/*
 * Copyright (C) Ascensio System SIA 2012-2019. All rights reserved
 *
 * https://www.onlyoffice.com/
 *
 * Version: 0.0.0 (build:0)
 */


/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {
function FileHandler() {

    this.get = function ( file ) {
        if ( AscCommon.AscBrowser.isAppleDevices ) {
            //this approach replaces tab, iframe approach do nothing
            var downloadWindow = window.open( file, "_parent", "", false );
            window.focus();
        }
        else {
			//делаем как docs.google.com, решение с form submit в схеме с socket вызывало ошибку 405 (Method Not Allowed)
            var frmWindow = getIFrameWindow( file );
//            frmWindow.focus();
        }
    }
    var getIFrameWindow = function ( file ) {
        var ifr = document.getElementById( "fileFrame" );
        if ( null != ifr )
            document.body.removeChild( ifr );
        createFrame( file );
        var wnd = window.frames["fileFrame"];
        return wnd;
    }
    var createFrame = function ( file ) {
        var frame = document.createElement( "iframe" );
		frame.src = file;
        frame.name = "fileFrame";
        frame.id = "fileFrame";

        frame.style.width = "0px";
        frame.style.height = "0px";
        frame.style.border = "0px";
        frame.style.display = "none";
		
		document.body.appendChild( frame );
    }
}
function getFile( filePath ) {
    var fh = new FileHandler();
    fh.get( filePath );
}

    //--------------------------------------------------------export----------------------------------------------------
    window['AscCommon'] = window['AscCommon'] || {};
    window['AscCommon'].getFile = getFile;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(/**
* @param {Window} window
* @param {undefined} undefined
*/
function(window, undefined) {
// Import
var CellValueType = AscCommon.CellValueType;

var c_oAscNumFormatType = Asc.c_oAscNumFormatType;

var gc_sFormatDecimalPoint = ".";
var gc_sFormatThousandSeparator = ",";

var numFormat_Text = 0;
var numFormat_TextPlaceholder = 1;
var numFormat_Bracket = 2;
var numFormat_Digit = 3;
var numFormat_DigitNoDisp = 4;
var numFormat_DigitSpace = 5;
var numFormat_DecimalPoint = 6;
var numFormat_DecimalFrac = 7;
var numFormat_Thousand = 8;
var numFormat_Scientific = 9;
var numFormat_Repeat = 10;
var numFormat_Skip = 11;
var numFormat_Year = 12;
var numFormat_Month = 13;
var numFormat_Minute = 14;
var numFormat_Hour = 15;
var numFormat_Day = 16;
var numFormat_Second = 17;
var numFormat_Milliseconds = 18;
var numFormat_AmPm = 19;
var numFormat_DateSeparator = 20;
var numFormat_TimeSeparator = 21;
var numFormat_DecimalPointText = 22;
//Вспомогательные типы, которые заменятюся в _prepareFormat
var numFormat_MonthMinute = 101;
var numFormat_Percent = 102;
var numFormat_General = 103;

var FormatStates = {Decimal: 1, Frac: 2, Scientific: 3, Slash: 4, SlashFrac: 5};
var SignType = {Negative: 1, Null:2, Positive: 3};

var gc_nMaxDigCount = 15;//Максимальное число знаков точности
var gc_nMaxDigCountView = 11;//Максимальное число знаков в ячейке
var gc_nMaxMantissa = Math.pow(10, gc_nMaxDigCount);
var gc_aTimeFormats = ['[$-F400]h:mm:ss AM/PM', 'h:mm;@', 'h:mm AM/PM;@', 'h:mm:ss;@', 'h:mm:ss AM/PM;@', 'mm:ss.0;@',
	'[h]:mm:ss;@'];
var gc_aFractionFormats = ['# ?/?', '# ??/??', '# ???/???', '# ?/2', '# ?/4', '# ?/8', '# ??/16', '# ?/10', '# ??/100'];

var NumComporationOperators =
{
	equal: 1,
	greater: 2,
	less: 3,
	greaterorequal: 4,
	lessorequal: 5,
	notequal: 6
};

function getNumberParts(x)
{
    var sig = SignType.Null;
    if (!isFinite(x))
        x = 0;
	if(x > 0)
		sig = SignType.Positive;
	else if(x < 0)
	{
		sig = SignType.Negative;
		x = Math.abs(x);
	}
    var exp = - gc_nMaxDigCount;
	var man = 0;
	if(SignType.Null != sig)
	{
		exp = Math.floor( Math.log(x) * Math.LOG10E ) - gc_nMaxDigCount + 1;
		//хотелось бы поставить здесь floor, чтобы не округлялось число 0.9999999999999999, но обнаружились проблемы с числом 0.999999999999999
		//после умножения оно превращается в 999999999999998.9
		man = Math.round(x / Math.pow(10, exp));
		if(man >= gc_nMaxMantissa)
		{
			exp++;
			man/=10;
		}
	}
    return {mantissa: man, exponent: exp, sign: sig};//для 0,123 exponent == - gc_nMaxDigCount
}

	function compareNumbers(val1, val2) {
		var res = 0;
		var parts1 = getNumberParts(val1);
		var parts2 = getNumberParts(val2);
		if (parts1.sign === parts2.sign) {
			if (parts1.exponent === parts2.exponent) {
				res = parts1.mantissa - parts2.mantissa;
			} else {
				res = parts1.exponent - parts2.exponent;
			}
			if (SignType.Negative === parts1.sign) {
				res = -res;
			}
		} else {
			res = parts1.sign - parts2.sign;
		}
		return res;
	}

    function isNumber(n) {
        return !isNaN(parseFloat(n)) && isFinite(n);
    }
	function round10(value, exp1, exp2) {
		//todo use Math.round10
		// Shift
		value = value.toString().split('e');
		value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp1) : exp1)));
		// Shift back
		value = value.toString().split('e');
		return +(value[0] + 'e' + (value[1] ? (+value[1] - exp2) : -exp2));
	}

function FormatObj(type, val)
{
    this.type = type;
    this.val = val;//что здесь лежит определяется типом
}
function FormatObjScientific(val, format, sign)
{
    this.type = numFormat_Scientific;
    this.val = val;//E или e
    this.format = format;//array формата
    this.sign = sign;
}
function FormatObjDecimalFrac(aLeft, aRight)
{
    this.type = numFormat_DecimalFrac;
    this.aLeft = aLeft;//array формата левой части
    this.aRight = aRight;//array формата правой части
    this.bNumRight = false;
	this.numerator = 0;
	this.denominator = 0;
}
function FormatObjDateVal(type, nCount, bElapsed)
{
    this.type = type;
    this.val = nCount;//Количество знаков подряд
    this.bElapsed = bElapsed;//true == [hhh]; в квадратных скобках
}
function FormatObjBracket(sData)
{
    this.type = numFormat_Bracket;
    this.val = sData;
    this.parse = function(data)
    {
        var length = data.length;
        if(length > 0)
        {
            var first = data[0];
            if("$" == first)
            {
                var aParams = data.substring(1).split('-');
				if (aParams[0].length > 0) {
					this.CurrencyString = aParams[0];
				} if(aParams.length > 1 && aParams[1].length > 0) {
					this.Lid = aParams[1];
				}
            }
			else if("=" == first || ">" == first || "<" == first)
			{
				var nIndex = 1;
				var sOperator = first;
				if(length > 1 && (">" == first || "<" == first))
				{
					var second = data[1];
					if("=" == second || (">" == second && "<" == first))
					{
						sOperator += second;
						nIndex = 2;
					}
				}
				switch(sOperator)
				{
					case "=": this.operator = NumComporationOperators.equal;break;
					case ">": this.operator = NumComporationOperators.greater;break;
					case "<": this.operator = NumComporationOperators.less;break;
					case ">=": this.operator = NumComporationOperators.greaterorequal;break;
					case "<=": this.operator = NumComporationOperators.lessorequal;break;
					case "<>": this.operator = NumComporationOperators.notequal;break;
				}
				this.operatorValue = parseInt(data.substring(nIndex));
			}
            else
            {
				var sLowerColor = data.toLowerCase();
                //todo Color1-56
                if("black" == sLowerColor)
                    this.color = 0x000000;
                else if("blue" == sLowerColor)
                    this.color = 0x0000ff;
                else if("cyan" == sLowerColor)
                    this.color = 0x00ffff;
                else if("green" == sLowerColor)
                    this.color = 0x00ff00;
                else if("magenta" == sLowerColor)
                    this.color = 0xff00ff;
                else if("red" == sLowerColor)
                    this.color = 0xff0000;
                else if("white" == sLowerColor)
                    this.color = 0xffffff;
                else if("yellow" == sLowerColor)
                    this.color = 0xffff00;
                else if("y" == first || "m" == first || "d" == first || "h" == first || "s" == first ||
                    "Y" == first || "M" == first || "D" == first || "H" == first || "S" == first)
                {
                    var bSame = true;
                    var nCount = 1;
                    for(var i = 1; i < length; ++i)
                    {
                        if(first != data[i])
                        {
                            bSame = false;
                            break;
                        }
                        nCount++;
                    }
                    if(true == bSame)
                    {
                        switch(first)
                        {
                            case "Y":
                            case "y": this.dataObj = new FormatObjDateVal(numFormat_Year, nCount, true);break;
                            case "M":
                            case "m": this.dataObj = new FormatObjDateVal(numFormat_MonthMinute, nCount, true);break;
                            case "D":
                            case "d": this.dataObj = new FormatObjDateVal(numFormat_Day, nCount, true);break;
                            case "H":
                            case "h": this.dataObj = new FormatObjDateVal(numFormat_Hour, nCount, true);break;
                            case "S":
                            case "s": this.dataObj = new FormatObjDateVal(numFormat_Second, nCount, true);break;
                        }
                    }
                }
            }
        }
    };
    this.parse(sData);
}
function NumFormat(bAddMinusIfNes)
{
    //Stream чтения формата
    this.formatString = "";
    this.length = this.formatString.length;
    this.index = 0;
    this.EOF = -1;
    
    //Формат
    this.aRawFormat = [];
    this.aDecFormat = [];
    this.aFracFormat = [];
    this.bDateTime = false;
	this.bDate = false;
	this.bTime = false;//флаг, чтобы отличить формат даты с временем, от простой даты
	this.bDay = false;//чтобы отличать когда надо использовать MonthGenitiveNames
    this.nPercent = 0;
    this.bScientific = false;
    this.bThousandSep = false;
    this.nThousandScale = 0;
    this.bTextFormat = false;
    this.bTimePeriod = false;
    this.bMillisec = false;
    this.bSlash = false;
    this.bWhole = false;
	this.bCurrency = false;
	this.bRepeat = false;
    this.Color = -1;
	this.ComporationOperator = null;
	this.LCID = null;
    
	this.bGeneralChart = false;//если в формате только один текст(например в chart "Основной")
    this.bAddMinusIfNes = bAddMinusIfNes;//когда не задано форматирование для отрицательных чисел иногда надо вставлять минус
}
NumFormat.prototype =
{
    _getChar : function()
    {
        if(this.index < this.length)
        {
            return this.formatString[this.index];
        }
        return this.EOF;
    },
    _readChar : function()
    {
        var curChar = this._getChar();
        if(this.index < this.length)
            this.index++;
        return curChar;
    },
    _skip : function(val)
    {
        var nNewIndex = this.index + val;
        if(nNewIndex >= 0)
            this.index = nNewIndex;
    },
    _addToFormat : function(type, val)
    {
        var oFormatObj = new FormatObj(type, val);
        this.aRawFormat.push(oFormatObj);
    },
    _addToFormat2 : function(oFormatObj)
    {
        this.aRawFormat.push(oFormatObj);
    },
    _ReadText : function()
    {
        var sText = "";
        while(true)
        {
            var next = this._readChar();
            if(this.EOF == next || "\"" == next)
                break;
            else
            {
                sText += next;
            }
        }
        this._addToFormat(numFormat_Text, sText);
    },
    _GetText : function(len)
    {
        return this.formatString.substr(this.index, len);
    },
    _ReadChar : function()
    {
        var next = this._readChar();
        if(this.EOF != next)
            this._addToFormat(numFormat_Text, next);
    },
    _ReadBracket : function()
    {
        var sBracket = "";
        while(true)
        {
            var next = this._readChar();
            if(this.EOF == next || "]" == next)
                break;
            else
            {
                sBracket += next;
            }
        }
		var oFormatObjBracket = new FormatObjBracket(sBracket);
		if(null != oFormatObjBracket.operator)
			this.ComporationOperator = oFormatObjBracket;
        this._addToFormat2(oFormatObjBracket);
    },
    _ReadAmPm : function(next)
    {
        var sAm = next;
        var sPm  = "";
        var bAm = true;
        while(true)
        {
            next = this._readChar();
            if(this.EOF == next)
                break;
            else if("/" == next)
            {
                bAm = false;
            }
            else if("A" == next || "a" == next || "P" == next || "p" == next || "M" == next || "m" == next)
            {
                if(true == bAm)
                    sAm += next;
                else
                    sPm += next;
            }
            else
            {
                this._skip(-1);
                break;
            }
        }
        if("" != sAm && "" != sPm)
        {
            this._addToFormat2(new FormatObj(numFormat_AmPm));
            this.bTimePeriod = true;
            this.bDateTime = true;
        }
    },
    _parseFormat : function(format)
    {
        var sGeneral = AscCommon.g_cGeneralFormat.toLowerCase();
        var sGeneralFirst = sGeneral[0];
        this.bGeneralChart = true;
        while(true)
        {
            var next = this._readChar();
            var bNoFormat = false;
            if(this.EOF == next)
                break;
            else if("[" == next)
                this._ReadBracket();
            else if("\"" == next)
                this._ReadText();
            else if("\\" == next)
                this._ReadChar();
            else if("%" == next)
            {
                this._addToFormat(numFormat_Percent);
            }
            else if("$" == next || "+" == next || "-" == next || "(" == next || ")" == next || " " == next)
            {
                this._addToFormat(numFormat_Text, next);
            }
			else if(":" == next)
            {
                this._addToFormat(numFormat_TimeSeparator);
            }
            else if(0 <= next && next <= 9)
            {
                //не 0 может быть только в дробях
                this._addToFormat(numFormat_Digit, next - 0);
            }
            else if("#" == next)
            {
                this._addToFormat(numFormat_DigitNoDisp);
            }
            else if("?" == next)
            {
                this._addToFormat(numFormat_DigitSpace);
            }
            else if (gc_sFormatDecimalPoint == next)
            {
                this._addToFormat(numFormat_DecimalPoint);
            }
            else if("/" == next)
            {
                this._addToFormat2(new FormatObjDecimalFrac([], []));
            }
            else if (gc_sFormatThousandSeparator == next)
            {
                this._addToFormat(numFormat_Thousand, 1);
            }
            else if("E" == next || "e" == next)
            {
                var nextnext = this._readChar();
                if(this.EOF != nextnext && "+" == nextnext || "-" == nextnext)
                {
                    var sign = ("+" == nextnext) ? SignType.Positive : SignType.Negative;
                    this._addToFormat2(new FormatObjScientific(next, "", sign));
                }
            }
            else if("*" == next)
            {
                var nextnext = this._readChar();
                if(this.EOF != nextnext)
                    this._addToFormat(numFormat_Repeat, nextnext);
            }
            else if("_" == next)
            {
                var nextnext = this._readChar();
                if(this.EOF != nextnext)
                    this._addToFormat(numFormat_Skip, nextnext);
            }
            else if("@" == next)
            {
                this._addToFormat(numFormat_TextPlaceholder);
            }
            else if("Y" == next || "y" == next)
            {
                this._addToFormat2(new FormatObjDateVal(numFormat_Year, 1, false));
            }
            else if("M" == next || "m" == next)
            {
                this._addToFormat2(new FormatObjDateVal(numFormat_MonthMinute, 1, false));
            }
            else if("D" == next || "d" == next)
            {
                this._addToFormat2(new FormatObjDateVal(numFormat_Day, 1, false));
            }
            else if("H" == next || "h" == next)
            {
                this._addToFormat2(new FormatObjDateVal(numFormat_Hour, 1, false));
            }
            else if("S" == next || "s" == next)
            {
                this._addToFormat2(new FormatObjDateVal(numFormat_Second, 1, false));
            }
            else if ("A" == next || "a" == next) {
                this._ReadAmPm(next);
            }
            else {
                if (sGeneralFirst === next.toLowerCase() &&
                    sGeneral === (next + this._GetText(sGeneral.length - 1)).toLowerCase()) {
                    this._addToFormat(numFormat_General);
                    this._skip(sGeneral.length - 1);
                } else {
                    bNoFormat = true;
                    this._addToFormat(numFormat_Text, next);
                }
            }
            if (!bNoFormat)
                this.bGeneralChart = false;
        }
        return true;
    },
    _getDateTimeBracket : function(val)
    {
        var res = null;
        var length = val.length;
        if(length > 0)
        {
            var first = val[0];
            if("y" == first || "m" == first || "d" == first || "h" == first || "s" == first)
            {
                var bSame = true;
                var nCount = 1;
                for(var i = 1; i < length; ++i)
                {
                    if(first != val[i])
                    {
                        bSame = false;
                        break;
                    }
                    nCount++;
                }
                if(true == bSame)
                {
                    switch(first)
                    {
                        case "y": res = new FormatObjDateVal(numFormat_Year, nCount, true);break;
                        case "m": res = new FormatObjDateVal(numFormat_MonthMinute, nCount, true);break;
                        case "d": res = new FormatObjDateVal(numFormat_Day, nCount, true);break;
                        case "h": res = new FormatObjDateVal(numFormat_Hour, nCount, true);break;
                        case "s": res = new FormatObjDateVal(numFormat_Second, nCount, true);break;
                    }
                }
            }
        }
        return res;
    },
    _prepareFormat : function()
    {
        //Color
		for(var i = 0, length = this.aRawFormat.length; i < length; ++i)
        {
            var oCurItem = this.aRawFormat[i];
            if(numFormat_Bracket == oCurItem.type && null != oCurItem.color)
                this.Color = oCurItem.color;
        }
        this.bRepeat = false;
        var nFormatLength = this.aRawFormat.length;

        //Группируем несколько элемнтов подряд в один спецсимвол
        for(var i = 0; i < nFormatLength; ++i)
        {
            var item = this.aRawFormat[i];
            if(numFormat_Repeat == item.type)
            {
                //Оставляем только последний numFormat_Repeat
                if(false == this.bRepeat)
                    this.bRepeat = true;
                else
                {
                    this.aRawFormat.splice(i, 1);
                    nFormatLength--;
                }
            }
            else if(numFormat_Bracket == item.type)
            {
                //Разруливаем [hhh]
                var oNewObj = item.dataObj;
                if(null != oNewObj)
                {
                    this.aRawFormat.splice(i, 1, oNewObj);
                    this.bDateTime = true;
                    if(numFormat_Hour == oNewObj.type || numFormat_Minute == oNewObj.type || numFormat_Second == oNewObj.type || numFormat_Milliseconds == oNewObj.type)
                        this.bTime = true;
                    else if (numFormat_Year == oNewObj.type || numFormat_Month == oNewObj.type || numFormat_Day == oNewObj.type) {
                        this.bDate = true;
                        if (numFormat_Day == oNewObj.type)
                            this.bDay = true;
                    }
                }
            }
            else if(numFormat_Year == item.type || numFormat_MonthMinute == item.type || numFormat_Day == item.type || numFormat_Hour == item.type || numFormat_Second == item.type || numFormat_Thousand == item.type)
            {
                //Собираем в одно целое последовательности hhh
                var nStartType = item.type;
                var nEndIndex = i;
                for(var j = i + 1; j < nFormatLength; ++j)
                {
                    if(nStartType == this.aRawFormat[j].type)
                        nEndIndex = j;
                    else
                        break;
                }
                if(i != nEndIndex)
                {
                    item.val = nEndIndex - i + 1;
                    var nDelCount = item.val - 1;
                    this.aRawFormat.splice(i + 1, nDelCount);
                    nFormatLength -= nDelCount;
                }
                if(numFormat_Thousand != item.type)
                {
                    this.bDateTime = true;
                    if(numFormat_Hour == item.type || numFormat_Minute == item.type || numFormat_Second == item.type || numFormat_Milliseconds == item.type)
                        this.bTime = true;
                    else if (numFormat_Year == item.type || numFormat_Month == item.type || numFormat_Day == item.type) {
                        this.bDate = true;
                        if (numFormat_Day == item.type)
                            this.bDay = true;
                    }
                }
            }
            else if(numFormat_Scientific == item.type)
            {
                var bAsText = false;
                if(true == this.bScientific)
                {
                    bAsText = true;
                }
                else
                {
                    var aDigitArray = [];
                    for(var j = i + 1; j < nFormatLength; ++j)
                    {
                        var nextItem = this.aRawFormat[j];
                        if(numFormat_Digit == nextItem.type || numFormat_DigitNoDisp == nextItem.type || numFormat_DigitSpace == nextItem.type)
                            aDigitArray.push(nextItem);
                    }
                    if(aDigitArray.length > 0)
                    {
                        item.format = aDigitArray;
                        this.bScientific = true;
                    }
                    else
                        bAsText = true;
                }
                if(false != bAsText)
                {
                    //заменяем на текст
                    item.type = numFormat_Text;
                    item.val = item.val + "+";
                }
            }
            else if(numFormat_DecimalFrac == item.type)
            {
                var bValid = false;
                //собираем правую и левую часть дроби
                var nLeft = i;
                for(var j = i - 1; j >= 0; --j)
                {
                    var subitem = this.aRawFormat[j];
                    if(numFormat_Digit == subitem.type || numFormat_DigitNoDisp == subitem.type || numFormat_DigitSpace == subitem.type)
                        nLeft = j;
                    else
                        break;
                }
                var nRight = i;
                if(nLeft < i)
                {
                    for(var j = i + 1; j < nFormatLength; ++j)
                    {
                        var subitem = this.aRawFormat[j];
                        if(numFormat_Digit == subitem.type || numFormat_DigitNoDisp == subitem.type || numFormat_DigitSpace == subitem.type)
                            nRight = j;
                        else
                            break;
                    }
                    if(nRight > i)
                    {
                        bValid = true;
                        item.aRight = this.aRawFormat.splice(i + 1, nRight - i);
                        item.aLeft = this.aRawFormat.splice(nLeft, i - nLeft);
                        nFormatLength -= nRight - nLeft;
                        i -= i - nLeft;
                        this.bSlash = true;

                        var flag = (item.aRight.length > 0) && (item.aRight[0].type == numFormat_Digit) && (item.aRight[0].val > 0);
                        if(flag)
                        {
                            var rPart = 0;
                            for(var j = 0; j< item.aRight.length; j++)
                            {
                                if(item.aRight[j].type == numFormat_Digit)
                                    rPart = rPart*10 + item.aRight[j].val;
                                else
                                {
                                    bValid = false;
                                    this.bSlash = false;
                                    break;
                                }
                            }
                            if(bValid == true)
                            {
                                item.aRight = [];
                                item.aRight.push(new FormatObj(numFormat_Digit, rPart));
                                item.bNumRight = true;
                            }
                        }
                    }

                }

                if(false == bValid)
                {
                    item.type = numFormat_DateSeparator;
                }
            }
        }
        
        var nReadState = FormatStates.Decimal;
        var bDecimal = true;
        nFormatLength = this.aRawFormat.length;
        //Разруливаем конфликтные ситуации, выставляем значения свойств
        for(var i = 0; i < nFormatLength; ++i)
        {
            var item = this.aRawFormat[i];
            if(numFormat_DecimalPoint == item.type)
            {
                //миллисекунды
                //Если после DecimalPoint идут numFormat_Digit, и есть формат для даты времени, то это миллисекунды
                if(this.bDateTime)
                {
                    var nStartIndex = i;
                    var nEndIndex = nStartIndex;
                    for(var j = i + 1; j < nFormatLength; ++j)
                    {
                        var subItem = this.aRawFormat[j];
                        if(numFormat_Digit == subItem.type)
                            nEndIndex = j;
                        else
                            break;
                    }
                    if(nStartIndex < nEndIndex)
                    {
                        var nDigCount = nEndIndex - nStartIndex;
                        var oNewItem = new FormatObjDateVal(numFormat_Milliseconds, nDigCount, false);
                        var nDelCount = nDigCount;
                        oNewItem.format = this.aRawFormat.splice(i + 1, nDelCount, oNewItem);
                        nFormatLength -= (nDigCount - 1);
                        i++;
                        this.bMillisec = true;

                    }
                    //преобразуем в текст все последующие
                    item.type = numFormat_DecimalPointText;
                    item.val = null;
                }
                else if(FormatStates.Decimal == nReadState)
                    nReadState = FormatStates.Frac;
            }
            else if(numFormat_MonthMinute == item.type)
            {
                //Разрешаем конфликты numFormat_MonthMinute
                var bRightCond = false;
                //ищем вперед первый элемент с типом datetime 
                for(var j = i + 1; j < nFormatLength; ++j)
                {
                    var subItem = this.aRawFormat[j];
                    if(numFormat_Year == subItem.type || numFormat_Month == subItem.type || numFormat_Day == subItem.type || numFormat_MonthMinute == subItem.type ||
                    numFormat_Hour == subItem.type || numFormat_Minute == subItem.type || numFormat_Second == subItem.type || numFormat_Milliseconds == subItem.type)
                    {
                        if(numFormat_Second == subItem.type)
                            bRightCond = true;
                        break;
                    }
                }
                var bLeftCond = false;
                if(false == bRightCond)
                {
                    //ищем назад первый элемент с типом hh или ss
                    var bFindSec = false;//чтобы разрулить случай mm:ss:mm должно быть Минуты:Секунды:Месяцы
                    for(var j = i - 1; j >= 0; --j)
                    {
                        var subItem = this.aRawFormat[j];
                        
                        if(numFormat_Hour == subItem.type)
                        {
                            bLeftCond = true;
                            break;
                        }
                        else if(numFormat_Second == subItem.type)
                        {
                            //продолжаем смотреть дальше, пока не встретиться следующий date time обьект
                            bFindSec = true;
                        }
                        else if(numFormat_Minute == subItem.type || numFormat_Month == subItem.type || numFormat_MonthMinute == subItem.type)
                        {
                            if(true == bFindSec && numFormat_Minute == subItem.type)
                                bFindSec = false;
                            break;
                        }
                        else if(numFormat_Year == subItem.type || numFormat_Day == subItem.type || numFormat_Hour == subItem.type || numFormat_Second == subItem.type || numFormat_Milliseconds == subItem.type)
                        {
                            if(true == bFindSec)
                                break;
                        }
                    }
                    if(true == bFindSec)
                        bLeftCond = true;
                }
                
                if( true == bLeftCond || true == bRightCond)
				{
                    item.type = numFormat_Minute;
					this.bTime = true;
				}
                else
				{
                    item.type = numFormat_Month;
					this.bDate = true;
				}
            }
            else if(numFormat_Percent == item.type)
            {
                this.nPercent++;
                //заменяем на текст
                item.type = numFormat_Text;
                item.val = "%";
            }
            else if(numFormat_Thousand == item.type)
            {
                if(FormatStates.Decimal == nReadState)
                {
                    var bStartCondition = false;
                    if(i > 0)
                    {
                        var prevItem = this.aRawFormat[i - 1];
                        if(numFormat_Digit == prevItem.type || numFormat_DigitNoDisp == prevItem.type || numFormat_DigitSpace == prevItem.type)
                        {
                            bStartCondition = true;
                        }
                    }
                    var bEndCondition = false;
                    if(i+1 < nFormatLength)
                    {
                        var nextItem = this.aRawFormat[i+1];
                        if(numFormat_Digit == nextItem.type || numFormat_DigitNoDisp == nextItem.type || numFormat_DigitSpace == nextItem.type)
                            bEndCondition = true;
                    }

                    if(true == bStartCondition && true == bEndCondition)
                    {
                        this.bThousandSep = true;
                    }
                    else if(bEndCondition == true)
                    {
                        //преобразуем в текст
                        item.type = numFormat_Text;
                        item.val = gc_sFormatThousandSeparator;
                    }
                }
                //проверка на концевой nThousandScale
                var bStartCondition = false;
                if(i > 0)
                {
                    var prevItem = this.aRawFormat[i - 1];
                    if(numFormat_Digit == prevItem.type || numFormat_DigitNoDisp == prevItem.type || numFormat_DigitSpace == prevItem.type)
                    {
                        bStartCondition = true;
                    }
                }
                var bEndCondition = true;
                //в последующем тексте нет numFormat_Digit, numFormat_DigitNoDisp, numFormat_DigitSpace
                for(var j = i + 1; j < nFormatLength; ++j)
                {
                    var nextItem = this.aRawFormat[j];
                    if(numFormat_Digit == nextItem.type || numFormat_DigitNoDisp == nextItem.type || numFormat_DigitSpace == nextItem.type || numFormat_DecimalPoint == nextItem.type)
                    {
                        bEndCondition = false;
                        break;
                    }
                }
                if(true == bStartCondition && true == bEndCondition)
                    this.nThousandScale = item.val;

            }
            else if(numFormat_Digit == item.type || numFormat_DigitNoDisp == item.type || numFormat_DigitSpace == item.type)
            {
                if(FormatStates.Decimal == nReadState)
                {
                    this.aDecFormat.push(item);

                    if(this.bSlash === true)
                        this.bWhole = true;
                }
                else if(FormatStates.Frac == nReadState)
                    this.aFracFormat.push(item);

            }
            else if(numFormat_Scientific == item.type)
                nReadState = FormatStates.Scientific;
            else if(numFormat_TextPlaceholder == item.type)
            {
                this.bTextFormat = true;
            }
        }
        return true;
    },
	_calsScientific : function(nDecLen, nRealExp)
	{
		var nKoef = 0;
		if(true == this.bThousandSep)
			nKoef = 4;
		if(nDecLen > nKoef)
			nKoef = nDecLen;
		if(nRealExp > 0 && nKoef > 0)
		{
			var nTemp = nRealExp % nKoef;
			if(0 == nTemp)
				nTemp = nKoef;
			nKoef = nTemp;
		}
		return nKoef;
	},
	_parseNumber : function(number, aDecFormat, nFracLen, nValType)
    {
        var res = {bDigit: false, dec: 0, frac: 0, fraction: 0, exponent: 0, exponentFrac: 0, scientific: 0, sign: SignType.Positive, date: {}};
        if(CellValueType.String != nValType)
            res.bDigit = (number == number - 0);
        if(res.bDigit)
        {
			var numberAbs = Math.abs(number);
			res.fraction = numberAbs - Math.floor(numberAbs);
			//Округляем
			var parts = getNumberParts(number);
			res.sign = parts.sign;
			var nRealExp = gc_nMaxDigCount + parts.exponent;//nRealExp == 0, при 0,123
			if(SignType.Null != parts.sign)
			{
				if(true == this.bScientific)
				{
					var nKoef = this._calsScientific(aDecFormat.length, nRealExp);
					res.scientific = nRealExp - nKoef;
					nRealExp = nKoef;
				}
				else
				{
					//Percent
					for(var i = 0; i < this.nPercent; ++i)
						nRealExp += 2;
					//Thousands separator
					for(var i = 0; i < this.nThousandScale; ++i)
						nRealExp -= 3;		
				}
				//округляем после операций которые могут изменить nRealExp
				if(false == this.bSlash)
				{
					var nOldRealExp = nRealExp;
					parts = getNumberParts(round10(parts.mantissa, nFracLen + nRealExp - gc_nMaxDigCount, nFracLen));
					if(SignType.Null != parts.sign)
					{
						nRealExp = gc_nMaxDigCount + parts.exponent;
						if(nOldRealExp != nRealExp && true == this.bScientific)
						{
							var nKoef = this._calsScientific(aDecFormat.length, nRealExp);
							res.scientific += nRealExp - nOldRealExp;
							nRealExp = nKoef;
						}
					}
				}
				res.exponent = nRealExp;
				res.exponentFrac = nRealExp;
				if(nRealExp > 0 && nRealExp < gc_nMaxDigCount)
				{
					var sNumber = parts.mantissa.toString();
					var nExponentFrac = 0;
					for(var i = nRealExp, length = sNumber.length; i < length; ++i)
					{
						if("0" == sNumber[i])
							nExponentFrac++;
						else
							break;
					}
					if(nRealExp + nExponentFrac < sNumber.length)
						res.exponentFrac = - nExponentFrac;
				}
				if(SignType.Null != parts.sign)
				{
					if(nRealExp <= 0)
					{
						if(this.bSlash == true)
						{
							res.dec = 0;
							res.frac = parts.mantissa;
						}
						else
						{
							if(nFracLen > 0)
							{
								res.dec = 0;
								res.frac = 0;
								if(nFracLen + nRealExp > 0)
								{
									var sTemp = parts.mantissa.toString();
									res.frac = sTemp.substring(0, nFracLen + nRealExp) - 0;
								}
							}
							else
							{
								res.dec = 0;
								res.frac = 0;
							}
						}
					}
					else if(nRealExp >= gc_nMaxDigCount)
					{
						res.dec = parts.mantissa;
						res.frac = 0;
					}
					else
					{
						var sTemp = parts.mantissa.toString();
						if(this.bSlash == true)
						{
							res.dec = sTemp.substring(0, nRealExp) - 0;
							if(nRealExp < sTemp.length)
								res.frac = sTemp.substring(nRealExp) - 0;
							else
								res.frac = 0;
						}
						else
						{
							if(nFracLen > 0 )
							{
								res.dec = sTemp.substring(0, nRealExp) - 0;
								res.frac = 0;
								var nStart = nRealExp;
								var nEnd = nRealExp + nFracLen;
								if(nStart < sTemp.length)
									res.frac = sTemp.substring(nStart, nEnd) - 0;
							}
							else
							{
								res.dec = sTemp.substring(0, nRealExp) - 0;
								res.frac = 0;
							}
						}
					}
				}
				if(0 == res.frac && 0 == res.dec)
					res.sign = SignType.Null;
			}
            //После округления может получиться ноль,
            //но не стала перестаскивать проверку на знак сюда, т.к. для округления нужно неотриц число

            if(this.bDateTime === true)
				res.date = this.parseDate(number);
        }
        return res;
    },
	parseDate : function(number)
	{
        var d = {val: 0, coeff: 1}, h = {val: 0, coeff: 24},
            min = {val: 0, coeff: 60}, s = {val: 0, coeff: 60}, ms = {val: 0, coeff: 1000};
        var tmp = +number;// '+' на всякий случай, если придет отриц число
        var ttimes = [d, h, min, s, ms];
        for(var i = 0; i < 4; i++)
        {
            var v = tmp*ttimes[i].coeff;
            ttimes[i].val = Math.floor(v);
            tmp = v - ttimes[i].val;
        }
        ms.val = Math.round(tmp*1000);
        for(i = 4; i > 0 && (ttimes[i].val === ttimes[i].coeff); i--)
        {
            ttimes[i].val = 0;
            ttimes[i-1].val++;
        }
        var stDate, day, month, year, dayWeek;
		if(AscCommon.bDate1904)
		{
			stDate = new Date(Date.UTC(1904,0,1,0,0,0));
			if(d.val)
				stDate.setUTCDate( stDate.getUTCDate() + d.val );
			day = stDate.getUTCDate();
			dayWeek = ( stDate.getUTCDay() > 0) ? stDate.getUTCDay() - 1 : 6;
			month = stDate.getUTCMonth();
			year = stDate.getUTCFullYear();
		}
		else
		{
			if(number === 60)
			{
				day = 29;
				month = 1;
				year = 1900;
				dayWeek = 3;
			}
			else if(number < 60)
			{
				stDate = new Date(Date.UTC(1899,11,31,0,0,0));
				if(d.val)
					stDate.setUTCDate( stDate.getUTCDate() + d.val );
				day = stDate.getUTCDate();
				dayWeek = ( stDate.getUTCDay() > 0) ? stDate.getUTCDay() - 1 : 6;
				month = stDate.getUTCMonth();
				year = stDate.getUTCFullYear();
			}
			else
			{
				stDate = new Date(Date.UTC(1899,11,30,0,0,0));
				if(d.val)
					stDate.setUTCDate( stDate.getUTCDate() + d.val );
				day = stDate.getUTCDate();
				dayWeek = stDate.getUTCDay();
				month = stDate.getUTCMonth();
				year = stDate.getUTCFullYear();
			}
		}
        return {d: day, month: month, year: year, dayWeek: dayWeek, hour: h.val, min: min.val, sec: s.val, ms: ms.val, countDay: d.val };
	},
	_FormatNumber: function (number, exponent, format, nReadState, cultureInfo, opt_forceNull)
	{
        var aRes = [];
        var nFormatLen = format.length;
        if(nFormatLen > 0)
        {
            if(FormatStates.Frac != nReadState && FormatStates.SlashFrac != nReadState)
            {
				var sNumber = number + "";
				var nNumberLen = sNumber.length;
				//для бага Bug 14325 - В загруженной таблице число с 30 знаками после разделителя отображается неправильно.
				//например число "1.23456789123456e+23" и формат "0.000000000000000000000000000000"
				if(exponent > nNumberLen)
				{
					for(var i = 0; i < exponent - nNumberLen; ++i)
						sNumber += "0";
					nNumberLen = sNumber.length;
				}
                var bIsNUll = false;
                if("0" == sNumber && !opt_forceNull)
                    bIsNUll = true;
                //выравниваем длину
                if(nNumberLen > nFormatLen)
                {
                    if(false == bIsNUll)
                    {
                        var nSplitIndex = nNumberLen - nFormatLen + 1;
                        aRes.push(new FormatObj(numFormat_Text, sNumber.slice(0, nSplitIndex)));
                        sNumber = sNumber.substring(nSplitIndex);
                        format.shift();
                    }
                }
                else if(nNumberLen < nFormatLen)
                {
                    //просто копируем, здесь будут только нули и пропуски
                    for(var i = 0, length = nFormatLen - nNumberLen; i < length; ++i)
                    {
                        var item = format.shift();
                        aRes.push(new FormatObj(item.type));
                    }
                }
                //просто заполняем текстом
                for(var i = 0, length = sNumber.length; i < length; ++i)
                {
                    var sCurNumber = sNumber[i];
					var numFormat = numFormat_Text;
                    var item = format.shift();
                    if(true == bIsNUll && null != item && FormatStates.Scientific != nReadState)
					{
						if(numFormat_DigitNoDisp == item.type)
							sCurNumber = "";
						else if(numFormat_DigitSpace == item.type)
						{
							numFormat = numFormat_DigitSpace;
							sCurNumber = null;
						}
					}
                    aRes.push(new FormatObj(numFormat, sCurNumber));
                }
                
                //Вставляем разделители 
                if(true == this.bThousandSep && FormatStates.Slash != nReadState)
                {
					var sThousandSep = cultureInfo.NumberGroupSeparator;
					var aGroupSize = cultureInfo.NumberGroupSizes;
					var nCurGroupIndex = 0;
					var nCurGroupSize = 0;
					if (nCurGroupIndex < aGroupSize.length)
					    nCurGroupSize = aGroupSize[nCurGroupIndex++];
					else
					    nCurGroupSize = 0;
                    var nIndex = 0;
                    for(var i = aRes.length - 1; i >= 0; --i)
                    {
                        var item = aRes[i];
                        if(numFormat_Text == item.type)
                        {
                            var aNewText = [];
                            var nTextLength = item.val.length;
                            for(var j = nTextLength - 1; j >= 0; --j)
                            {
                                if (nCurGroupSize == nIndex)
                                {
                                    aNewText.push(sThousandSep);
                                    nTextLength++;
                                }
                                aNewText.push(item.val[j]);
                                if(0 != j)
                                {
                                    nIndex++;
                                    if (nCurGroupSize + 1 == nIndex) {
                                        nIndex = 1;
                                        if (nCurGroupIndex < aGroupSize.length)
                                            nCurGroupSize = aGroupSize[nCurGroupIndex++];
                                    }
                                }
                            }
                            if(nTextLength > 1)
                                aNewText.reverse();
                            item.val = aNewText.join("");
                        }
                        else if(numFormat_DigitNoDisp != item.type)
                        {
                            //не добавляем пробел только перед numFormat_DigitNoDisp
                            if (nCurGroupSize == nIndex)
                            {
                                item.val = sThousandSep;
                                aRes[i] = item;
                            }
                        }
                        nIndex++;
                        if (nCurGroupSize + 1 == nIndex) {
                            nIndex = 1;
                            if (nCurGroupIndex < aGroupSize.length)
                                nCurGroupSize = aGroupSize[nCurGroupIndex++];
                        }
                    }
                }
            }
            else
            {
				var val = number;
				var exp = exponent;
                //Считаем количество нулей в начале
                var nStartNulls = 0;
				if(exp < 0)
					nStartNulls = Math.abs(exp);
                var sNumber = val.toString();
                var nNumberLen = sNumber.length;
				//удаляем 0 на конце
				var nLastNoNull = nNumberLen;
                for(var i = nNumberLen - 1; i >= 0; --i)
                {
					if ("0" != sNumber[i])
						break;
					nLastNoNull = i;
				}
				if (nLastNoNull < nNumberLen && (FormatStates.SlashFrac != nReadState || 0 == nLastNoNull)) {
					sNumber = sNumber.substring(0, nLastNoNull);
					nNumberLen = sNumber.length;
				}
                //заполняем первые нули
                for(var i = 0; i < nStartNulls; ++i)
                    aRes.push(new FormatObj(numFormat_Text, "0"));
                //просто заполняем текстом
                for(var i = 0, length = nNumberLen; i < length; ++i)
                    aRes.push(new FormatObj(numFormat_Text, sNumber[i]));
                //просто копируем, здесь будут только нули и пропуски
                for(var i = nNumberLen + nStartNulls; i < nFormatLen; ++i)
                {
                    var item = format[i];
                    aRes.push(new FormatObj(item.type));
                }
            }
        }
        return aRes;
    },
    _AddDigItem : function(res, oCurText, item)
    {
        if(numFormat_Text == item.type)
            oCurText.text += item.val;
        else if(numFormat_Digit == item.type)
        {
            //text.val может заполниться в Thousand
            oCurText.text += "0";
            if(null != item.val)
                oCurText.text += item.val;
        }
        else if(numFormat_DigitNoDisp == item.type)
        {
            oCurText.text += "";
            if(null != item.val)
                oCurText.text += item.val;
        }
        else if(numFormat_DigitSpace == item.type)
        {
            var oNewFont = new AscCommonExcel.Font();
			oNewFont.skip = true;
            this._CommitText(res, oCurText, "0", oNewFont);
            if(null != item.val)
                oCurText.text += item.val;
        }
    },
    _ZeroPad: function(n)
    {
        return (n < 10) ? "0" + n : n;
    },
    _CommitText: function(res, oCurText, textVal, format)
    {
        if(null != oCurText && oCurText.text.length > 0)
        {
            this._CommitText(res, null, oCurText.text, null);
            oCurText.text = "";
        }
        if(null != textVal && textVal.length > 0)
        {
            var length = res.length;
            var prev = null;
            if(length > 0)
                prev = res[length - 1];
            if(-1 != this.Color)
            {
                if(null == format)
                    format = new AscCommonExcel.Font();
                format.c = new AscCommonExcel.RgbColor(this.Color);
            }
            if(null != prev && ((null == prev.format && null == format) || (null != prev.format && null != format && format.isEqual(prev.format))))
            {
                prev.text += textVal;
            }
            else
            {
                if(null == format)
                    prev = {text: textVal};
                else
                    prev = {text: textVal, format: format};
                res.push(prev);
            }
        }
    },
    setFormat: function(format, cultureInfo) {
		if (null == cultureInfo) {
            cultureInfo = g_oDefaultCultureInfo;
        }
        this.formatString = format;
        this.length = this.formatString.length;
        //string -> tokens
        this.valid = this._parseFormat();
        if (true == this.valid) {
            //prepare tokens
            this.valid = this._prepareFormat();
            if (this.valid) {
                //additional prepare
                var aCurrencySymbols = ["$", "€", "£", "¥", "р.", cultureInfo.CurrencySymbol];
                var sText = "";
                for (var i = 0, length = this.aRawFormat.length; i < length; ++i) {
                    var item = this.aRawFormat[i];
                    if (numFormat_Text == item.type) {
                        sText += item.val;
                    } else if (numFormat_Bracket == item.type) {
                        if (null != item.CurrencyString) {
							this.bCurrency = true;
                            sText += item.CurrencyString;
                        }
						if (null != item.Lid) {
							//Excel sometimes add 0x10000(0x442 and 0x10442)
							this.LCID = parseInt(item.Lid, 16) & 0xFFFF;
						}
                    }
                    else if (numFormat_DecimalPoint == item.type) {
                        sText += gc_sFormatDecimalPoint;
                    } else if (numFormat_DecimalPointText == item.type) {
                        sText += gc_sFormatDecimalPoint;
                    }
                }
                if ("" != sText) {
                    for (var i = 0, length = aCurrencySymbols.length; i < length; ++i) {
                        if (-1 != sText.indexOf(aCurrencySymbols[i])) {
                            this.bCurrency = true;
                            break;
                        }
                    }
                }
                    }
                }
        return this.valid;
    },
    isInvalidDateValue : function(number)
    {
        return (number == number - 0) && ((number < 0 && !AscCommon.bDate1904) || number > 2958465.9999884);
    },
    _applyGeneralFormat: function(number, nValType, dDigitsCount, bChart, cultureInfo){
        var res = null;
        //todo fIsFitMeasurer and decrease dDigitsCount by other format tokens
        var sGeneral = DecodeGeneralFormat(number, nValType, dDigitsCount);
        if (null != sGeneral) {
            var numFormat = oNumFormatCache.get(sGeneral);
            if (null != numFormat) {
                res = numFormat.format(number, nValType, dDigitsCount, bChart, cultureInfo, true);
            }
        }
        if(!res){
            res = [{text: number.toString()}];
        }
        if (-1 != this.Color) {
            for (var i = 0; i < res.length; ++i) {
                var elem = res[i];
                if (null == elem.format) {
                    elem.format = new AscCommonExcel.Font();
                }
                elem.format.c = new AscCommonExcel.RgbColor(this.Color);
            }
        }
        return res;
    },
	_formatDecimalFrac: function(oParsedNumber) {
		var forceNull = false;
		for (var i = 0; i < this.aRawFormat.length; ++i) {
			var item = this.aRawFormat[i];
			if (numFormat_DecimalFrac == item.type) {
				var frac = oParsedNumber.fraction;
				var numerator = 0;
				var denominator = 0;
				if (item.bNumRight === true) {
					//todo max denominator - 99999
					denominator = item.aRight[0].val;
					numerator = Math.round(denominator * frac);
				} else if (frac > 0) {
					//Continued fraction
					//7 - excel max denominator length
					var denominatorLen = Math.min(7, item.aRight.length);
					var denominatorBound = Math.pow(10, denominatorLen);
					var an = Math.floor(frac);
					var xn1 = frac - an;
					var pn1 = an;
					var qn1 = 1;
					var pn2 = 1;
					var qn2 = 0;
					do {
						an = Math.floor(1 / xn1);
						xn1 = 1 / xn1 - an;
						var pn = an * pn1 + pn2;
						var qn = an * qn1 + qn2;
						pn2 = pn1;
						pn1 = pn;
						qn2 = qn1;
						qn1 = qn;
					} while (qn < denominatorBound);
					numerator = pn2;
					denominator = qn2;
				}
				if (numerator <= 0) {
					numerator = 0;
					if (this.bWhole === false) {
						if (denominator <= 0) {
							denominator = 1;
						}
					} else {
						denominator = 0;
					}
				}
				if (this.bWhole === false) {
					numerator += denominator * oParsedNumber.dec;
				} else if (numerator === denominator && 0 !== numerator) {
					oParsedNumber.dec++;
					numerator = 0;
					denominator = 0;
				}
				if (0 === numerator && 0 === denominator) {
					forceNull = true;
				}
				item.numerator = numerator;
				item.denominator = denominator;
			}
		}
		return forceNull;
	},
    format: function (number, nValType, dDigitsCount, cultureInfo, bChart)
    {
        if (null == cultureInfo)
            cultureInfo = g_oDefaultCultureInfo;
        var cultureInfoLCID = cultureInfo;
        if (null != this.LCID) {
            cultureInfoLCID = g_aCultureInfos[this.LCID] || cultureInfo;
        }
        if(null == nValType)
            nValType = CellValueType.Number;
        var res = [];
        var oCurText = {text: ""};
        if(true == this.valid)
        {
            if(true === this.bDateTime)
            {
                if(this.isInvalidDateValue(number))
                {
                    var oNewFont = new AscCommonExcel.Font();
					oNewFont.repeat = true;
                    this._CommitText(res, null, "#", oNewFont);
                    return res;
                }
            }
            var oParsedNumber = this._parseNumber(number, this.aDecFormat, this.aFracFormat.length, nValType);
            if (true == this.isGeneral() || (true == oParsedNumber.bDigit && true == this.bTextFormat) || (false == oParsedNumber.bDigit && false == this.bTextFormat) || (bChart && this.bGeneralChart))
            {
                return this._applyGeneralFormat(number, nValType, dDigitsCount, bChart, cultureInfo);
            }
			var forceNull = false;
			if (this.bSlash) {
				forceNull = this._formatDecimalFrac(oParsedNumber);
			}
            var aDec = [];
            var aFrac = [];
            var aScientific = [];
            if(true == oParsedNumber.bDigit)
            {
                aDec = this._FormatNumber(oParsedNumber.dec, oParsedNumber.exponent, this.aDecFormat.concat(), FormatStates.Decimal, cultureInfo, forceNull);
                aFrac = this._FormatNumber(oParsedNumber.frac, oParsedNumber.exponentFrac, this.aFracFormat.concat(), FormatStates.Frac, cultureInfo);
            }
            if(true == this.bAddMinusIfNes && SignType.Negative == oParsedNumber.sign)//&& oParsedNumber.dec > 0)
            {
                //todo разобраться с минусами
                //Добавляем в самое начало знак минус
                oCurText.text += "-";
            }
            var bNoDecFormat = false;
            if((null == aDec || 0 == aDec.length) && 0 != oParsedNumber.dec)
            {
                //случай ".00"
                bNoDecFormat = true;
            }
            
            var nReadState = FormatStates.Decimal;
            var nFormatLength = this.aRawFormat.length;    
            for(var i = 0; i < nFormatLength; ++i)
            {
                var item = this.aRawFormat[i];
                if(numFormat_Bracket == item.type)
                {
                    if(null != item.CurrencyString)
                        oCurText.text += item.CurrencyString;
                }
                else if(numFormat_DecimalPoint == item.type)
                {
                    if(bNoDecFormat && null != oParsedNumber.dec && FormatStates.Decimal == nReadState)
                    {
                        oCurText.text += oParsedNumber.dec;
                    }
					oCurText.text += cultureInfo.NumberDecimalSeparator;
                    nReadState = FormatStates.Frac;
                }
                else if (numFormat_DecimalPointText == item.type) {
                    oCurText.text += cultureInfo.NumberDecimalSeparator;
                }
                else if(numFormat_Digit == item.type || numFormat_DigitNoDisp == item.type || numFormat_DigitSpace == item.type)
                {
                    var text = null;
                    if(nReadState == FormatStates.Decimal)
                        text = aDec.shift();
                    else if(nReadState == FormatStates.Frac)
                        text = aFrac.shift();
                    else if(nReadState == FormatStates.Scientific)
                        text = aScientific.shift();
                    if(null != text)
                    {
                        this._AddDigItem(res, oCurText, text);
                    }
                }
                else if(numFormat_Text == item.type)
                {
                    oCurText.text += item.val;
                }
                else if(numFormat_TextPlaceholder == item.type)
                {
                    oCurText.text += number;
                }
                else if(numFormat_Scientific == item.type)
                {
                    if(null != item.format)
                    {
                        oCurText.text += item.val;

                        if(oParsedNumber.scientific < 0)
                            oCurText.text += "-";
                        else if(item.sign == SignType.Positive)
                            oCurText.text += "+";

                        
                        aScientific = this._FormatNumber(Math.abs(oParsedNumber.scientific), 0, item.format.concat(), FormatStates.Scientific, cultureInfo);
                        nReadState = FormatStates.Scientific;
                    }
                }
                else if(numFormat_DecimalFrac == item.type)
                {
                    var curForceNull = this.bWhole === false;
					var aLeft = this._FormatNumber(item.numerator, 0, item.aLeft.concat(), FormatStates.Slash, cultureInfo, curForceNull);
					for (var j = 0, length = aLeft.length; j < length; ++j) {
						var subitem = aLeft[j];
						if (subitem) {
							this._AddDigItem(res, oCurText, subitem);
						}
					}
					if ((item.numerator > 0 && item.denominator > 0) || curForceNull) {
						oCurText.text += "/";
					} else {
						var oNewFont = new AscCommonExcel.Font();
						oNewFont.skip = true;
						this._CommitText(res, oCurText, "/", oNewFont);
					}
					if (item.bNumRight === true) {
						var rightVal = item.aRight[0].val;
						if (rightVal) {
							if (item.denominator > 0) {
								oCurText.text += rightVal;
							} else {
								for (var rightIdx = 0; rightIdx < rightVal.toString().length; ++rightIdx) {
									var oNewFont = new AscCommonExcel.Font();
									oNewFont.skip = true;
									this._CommitText(res, oCurText, "0", oNewFont);
								}
							}
						}
					} else {
						var aRight = this._FormatNumber(item.denominator, 0, item.aRight.concat(), FormatStates.SlashFrac, cultureInfo);
						for (var j = 0, length = aRight.length; j < length; ++j) {
							var subitem = aRight[j];
							if (subitem) {
								this._AddDigItem(res, oCurText, subitem);
							}
						}
					}
                }
                else if(numFormat_Repeat == item.type)
                {
                    var oNewFont = new AscCommonExcel.Font();
					oNewFont.repeat = true;
                    this._CommitText(res, oCurText, item.val, oNewFont);
                }
                else if(numFormat_Skip == item.type)
                {
                    var oNewFont = new AscCommonExcel.Font();
					oNewFont.skip = true;
                    this._CommitText(res, oCurText, item.val, oNewFont);
                }
				else if(numFormat_DateSeparator == item.type)
                {
                    oCurText.text += cultureInfo.DateSeparator;
				}
				else if(numFormat_TimeSeparator == item.type)
                {
                    oCurText.text += cultureInfo.TimeSeparator;
				}
                else if(numFormat_Year == item.type)
                {
                  if (item.val > 0) {
                    if (item.val <= 2) {
                      oCurText.text += (oParsedNumber.date.year+'').substring(2);
                    } else {
                      oCurText.text += oParsedNumber.date.year;
                    }
                  }
                }
                else if(numFormat_Month == item.type)
                {
                    var m = oParsedNumber.date.month;
                    if(item.val == 1)
                        oCurText.text += m + 1;
                    else if(item.val == 2)
                        oCurText.text += this._ZeroPad(m + 1);
                    else if (item.val == 3) {
                        if (this.bDay && cultureInfoLCID.AbbreviatedMonthGenitiveNames.length > 0)
                            oCurText.text += cultureInfoLCID.AbbreviatedMonthGenitiveNames[m];
                        else
                            oCurText.text += cultureInfoLCID.AbbreviatedMonthNames[m];
                    }
                    else if (item.val == 5) {
                        var sMonthName = cultureInfoLCID.MonthNames[m];
                        if (sMonthName.length > 0)
                            oCurText.text += sMonthName[0];
                    }
                    else if (item.val > 0){
                        if (this.bDay && cultureInfoLCID.MonthGenitiveNames.length > 0)
                            oCurText.text += cultureInfoLCID.MonthGenitiveNames[m];
                        else
                            oCurText.text += cultureInfoLCID.MonthNames[m];
                    }
                }
                else if(numFormat_Day == item.type)
                {
                    if(item.val == 1)
                        oCurText.text += oParsedNumber.date.d;
                    else if(item.val == 2)
                        oCurText.text += this._ZeroPad(oParsedNumber.date.d);
                    else if(item.val == 3)
                        oCurText.text += cultureInfoLCID.AbbreviatedDayNames[oParsedNumber.date.dayWeek];
                    else if(item.val > 0)
                        oCurText.text += cultureInfoLCID.DayNames[oParsedNumber.date.dayWeek];
                    
                }
                else if(numFormat_Hour == item.type)
                {
                    var h = oParsedNumber.date.hour;
                    if(item.bElapsed === true)
                        h = oParsedNumber.date.countDay*24 + oParsedNumber.date.hour;
                    if(this.bTimePeriod === true)
                        h = h%12||12;

                    if(item.val == 1)
                        oCurText.text += h;
                    else if(item.val > 0)
                        oCurText.text += this._ZeroPad(h);
                }
                else if(numFormat_Minute == item.type)
                {
                    var min = oParsedNumber.date.min;
                    if(item.bElapsed === true)
                        min = oParsedNumber.date.countDay*24*60 + oParsedNumber.date.hour*60 + oParsedNumber.date.min;
                    if(item.val == 1)
                        oCurText.text += min;
                    else if(item.val > 0)
                        oCurText.text += this._ZeroPad(min);
                }
                else if(numFormat_Second == item.type)
                {
                    var s = oParsedNumber.date.sec;
                    if(this.bMillisec === false)
                        s = oParsedNumber.date.sec + Math.round(oParsedNumber.date.ms/1000);
                    if(item.bElapsed === true)
                        s = oParsedNumber.date.countDay*24*60*60 + oParsedNumber.date.hour*60*60 + oParsedNumber.date.min*60 + s;

                    if(item.val == 1)
                        oCurText.text += s;
                    else if(item.val > 0)
                        oCurText.text += this._ZeroPad(s);
                }
                else if (numFormat_AmPm == item.type) {
                    if (cultureInfoLCID.AMDesignator.length > 0 && cultureInfoLCID.PMDesignator.length > 0)
                        oCurText.text += (oParsedNumber.date.hour < 12) ? cultureInfoLCID.AMDesignator : cultureInfoLCID.PMDesignator;
                    else
                        oCurText.text += (oParsedNumber.date.hour < 12) ? "AM" : "PM";
                }
                else if (numFormat_Milliseconds == item.type) {
                    var nMsFormatLength = item.format.length;
                    var dMs = oParsedNumber.date.ms;
                    //Округляем
                    if (nMsFormatLength < 3) {
                        var dTemp = dMs / Math.pow(10, 3 - nMsFormatLength);
                        dTemp = Math.round(dTemp);
                        dMs = dTemp * Math.pow(10, 3 - nMsFormatLength);
                    }
                    var nExponent = 0;
                    if(0 == dMs)
                        nExponent = -1;
                    else if (dMs < 10)
                        nExponent = -2;
                    else if (dMs < 100)
                        nExponent = -1;
                    var aMilSec = this._FormatNumber(dMs, nExponent, item.format.concat(), FormatStates.Frac, cultureInfo);
                    for (var k = 0; k < aMilSec.length; k++)
                        this._AddDigItem(res, oCurText, aMilSec[k]);
                }
                else if (numFormat_General == item.type) {
                    this._CommitText(res, oCurText, null, null);
                    //todo minus sign
                    res = res.concat(this._applyGeneralFormat(Math.abs(number), nValType, dDigitsCount, bChart, cultureInfo));
                }
            }
            this._CommitText(res, oCurText, null, null);
			if(0 == res.length)
                res = [{text: ""}];
        }
        else
        {
            if(0 == res.length)
                res = [{text: number.toString()}];
        }
		//длина результирующей строки не должна быть длиннее c_oAscMaxColumnWidth
		var nLen = 0;
		for(var i = 0; i < res.length; ++i){
			var elem = res[i];
			if(elem.text)
				nLen += elem.text.length;
		}
		if(nLen > Asc.c_oAscMaxColumnWidth){
			var oNewFont = new AscCommonExcel.Font();
			oNewFont.repeat = true;
			res = [{text: "#", format: oNewFont}];
		}
        return res;
    },
    toString : function(output, nShift)
    {
        var bRes = true;
        if(this.bDateTime || this.bSlash || this.bTextFormat || (nShift < 0 && 0 == this.aFracFormat.length))
            return false;
        var nDecLength = this.aDecFormat.length;
        var nDecIndex = 0;
        var nFracLength = this.aFracFormat.length;
        var nFracIndex = 0;
        var nNewFracLength = nFracLength + nShift;
        if(nNewFracLength < 0)
            nNewFracLength = 0;
        var nReadState = FormatStates.Decimal;
        var res = "";
        var fFormatToString = function(aFormat)
        {
            var res = "";
            for(var i = 0, length = aFormat.length; i < length; ++i)
            {
                var item = aFormat[i];
                if(numFormat_Digit == item.type)
                {
                    if(null != item.val)
                        res += item.val;
                    else
                        res += "0";
                }
                else if(numFormat_DigitNoDisp == item.type)
                    res += "#";
                else if(numFormat_DigitSpace == item.type)
                    res += "?";
            }
            return res;
        };
        //Color
        if(null != this.Color)
        {
            switch(this.Color)
            {
            case 0x000000: res += "[Black]";break;
            case 0x0000ff: res += "[Blue]";break;
            case 0x00ffff: res += "[Cyan]";break;
            case 0x00ff00: res += "[Green]";break;
            case 0xff00ff: res += "[Magenta]";break;
            case 0xff0000: res += "[Red]";break;
            case 0xffffff: res += "[White]";break;
            case 0xffff00: res += "[Yellow]";break;
            }
        }
		//Comporation operator
        if(null != this.ComporationOperator)
        {
			switch(this.ComporationOperator.operator)
			{
				case NumComporationOperators.equal: res += "[=" + this.ComporationOperator.operatorValue +"]";break;
				case NumComporationOperators.greater: res += "[>" + this.ComporationOperator.operatorValue +"]";break;
				case NumComporationOperators.less: res += "[<" + this.ComporationOperator.operatorValue +"]";break;
				case NumComporationOperators.greaterorequal: res += "[>=" + this.ComporationOperator.operatorValue +"]";break;
				case NumComporationOperators.lessorequal: res += "[<=" + this.ComporationOperator.operatorValue +"]";break;
				case NumComporationOperators.notequal: res += "[<>" + this.ComporationOperator.operatorValue +"]";break;
			}
		}
        //ThousandSep
        var bAddThousandSep = this.bThousandSep;
        var nThousandScale = this.nThousandScale;
            
        var nFormatLength = this.aRawFormat.length;    
        for(var i = 0; i < nFormatLength; ++i)
        {
            var item = this.aRawFormat[i];
            if(numFormat_Bracket == item.type)
            {
                if(null != item.CurrencyString || null != item.Lid)
                {
                    res += "[$";
                    if(null != item.CurrencyString)
                        res += item.CurrencyString;
					if (null != item.Lid) {
						res += "-";
						res += item.Lid;
					}
                    res += "]";
                }
            }
            else if(numFormat_DecimalPoint == item.type)
            {
                nReadState = FormatStates.Frac;
                if(0 != nNewFracLength && 0 != nShift)
                    res += gc_sFormatDecimalPoint;
            }
            else if (numFormat_DecimalPointText == item.type) {
                res += gc_sFormatDecimalPoint;
            }
            else if(numFormat_Thousand == item.type)
            {
                for(var j = 0; j < item.val; ++j)
                    res += gc_sFormatThousandSeparator;
            }
            else if(numFormat_Digit == item.type || numFormat_DigitNoDisp == item.type || numFormat_DigitSpace == item.type)
            {
                if(FormatStates.Decimal == nReadState)
                    nDecIndex++;
                else
                    nFracIndex++;
                if(nReadState == FormatStates.Frac && nFracIndex > nNewFracLength)
                    ;
                else
                {
                    var sCurSimbol;
                    if(numFormat_Digit == item.type)
                        sCurSimbol = "0";
                    else if(numFormat_DigitNoDisp == item.type)
                        sCurSimbol = "#";
                    else if(numFormat_DigitSpace == item.type)
                        sCurSimbol = "?";
                    res += sCurSimbol;
                    if(nReadState == FormatStates.Frac && nFracIndex == nFracLength)
                    {
                        for(var j = 0; j < nShift; ++j)
                            res += sCurSimbol;
                    }
                }
                if(0 == nFracLength && nShift > 0 && FormatStates.Decimal == nReadState && nDecIndex == nDecLength)
                {
                    res += gc_sFormatDecimalPoint;
                    for(var j = 0; j < nShift; ++j)
                        res += "0";
                }
            }
            else if(numFormat_Text == item.type)
            {
                if("%" == item.val)
                    res += item.val;
                else
                    res += "\"" + item.val + "\"";
            }
            else if(numFormat_TextPlaceholder == item.type)
                res += "@";
            else if(numFormat_Scientific == item.type)
            {
                nReadState = FormatStates.Scientific;
                res += item.val;
                if(item.sign == SignType.Positive)
                    res += "+";
                else
                    res += "-";
            }
            else if(numFormat_DecimalFrac == item.type)
            {
                res += fFormatToString(item.aLeft);
                res += "/";
                res += fFormatToString(item.aRight);
            }
            else if(numFormat_Repeat == item.type)
                res += "*" + item.val;
            else if(numFormat_Skip == item.type)
                res += "_" + item.val;
			else if(numFormat_DateSeparator == item.type)
                res += "/";
			else if(numFormat_TimeSeparator == item.type)
                res += ":";
            else if(numFormat_Year == item.type)
            {
                for(var j = 0; j < item.val; ++j)
                    res += "y";
            }
            else if(numFormat_Month == item.type)
            {
                for(var j = 0; j < item.val; ++j)
                    res += "m";
            }
            else if(numFormat_Day == item.type)
            {
                for(var j = 0; j < item.val; ++j)
                    res += "d";
            }
            else if(numFormat_Hour == item.type)
            {
                for(var j = 0; j < item.val; ++j)
                    res += "h";
            }
            else if(numFormat_Minute == item.type)
            {
                for(var j = 0; j < item.val; ++j)
                    res += "m";
            }
            else if(numFormat_Second == item.type)
            {
                for(var j = 0; j < item.val; ++j)
                    res += "s";
            }
            else if(numFormat_AmPm == item.type)
                res += "AM/PM";
            else if(numFormat_Milliseconds == item.type)
                res += fFormatToString(item.format);
        }
        output.format = res;
        return true;
    },
	getFormatCellsInfo: function() {
		var info = new Asc.asc_CFormatCellsInfo();
		info.asc_setDecimalPlaces(this.aFracFormat.length);
		info.asc_setSeparator(this.bThousandSep);
		info.asc_setSymbol(this.LCID);
		return info;
	},
	isGeneral: function() {
		return 1 == this.aRawFormat.length && numFormat_General == this.aRawFormat[0].type;
	}
};
function NumFormatCache()
{
    this.oNumFormats = {};
}
NumFormatCache.prototype =
{
	cleanCache : function(){
		this.oNumFormats = {};
	},
    get : function(format)
    {
        var res = this.oNumFormats[format];
        if(null == res)
        {
            res = new CellFormat(format);
            this.oNumFormats[format] = res;
        }
        return res;
    },
    set : function(format)
    {
        var res = new CellFormat(format);
        this.oNumFormats[format] = res;
    }
};
//кеш структур по строке формата
var oNumFormatCache = new NumFormatCache();

function CellFormat(format)
{
    this.sFormat = format;
    this.oPositiveFormat = null;
    this.oNegativeFormat = null;
    this.oNullFormat = null;
    this.oTextFormat = null;
	this.aComporationFormats = null;
    var aFormats = format.split(";");
	var aParsedFormats = [];
	for(var i = 0; i < aFormats.length; ++i)
	{
    var sNewFormat = aFormats[i];
    //если sNewFormat заканчивается на нечетное число '\', значит ';' был экранирован и это текст
    while(true){
      var formatTail = sNewFormat.match(/\\+$/g);
      if (formatTail && formatTail.length > 0 && 1 === formatTail[0].length % 2 && i + 1 < aFormats.length) {
        sNewFormat += ';';
        sNewFormat += aFormats[++i];
      } else {
        break;
      }
    }
		var oNewFormat = new NumFormat(false);
		oNewFormat.setFormat(sNewFormat);
		aParsedFormats.push(oNewFormat);
	}
  var nFormatsLength = aParsedFormats.length;
	var bComporationOperator = false;
	if(nFormatsLength > 0)
	{
		var oFirstFormat = aParsedFormats[0];
		if(null != oFirstFormat.ComporationOperator)
		{
			bComporationOperator = true;
			//проверяем можно ли привести к стандартному формату
			//todo сохранять измененный формат в файл
			if(3 == nFormatsLength)
			{
				var oPositive = null;
				var oNegative = null;
				var oNull = null;
				for(var i = 0; i < nFormatsLength; ++i)
				{
					var oCurFormat = aParsedFormats[i];
					if(null == oCurFormat.ComporationOperator)
					{
						if(null == oPositive)
							oPositive = oCurFormat;
						else if(null == oNegative)
							oNegative = oCurFormat;
						else if(null == oNull)
							oNull = oCurFormat;
					}
					else
					{
						var oComporationOperator = oCurFormat.ComporationOperator;
						if(0 == oComporationOperator.operatorValue)
						{
							switch(oComporationOperator.operator)
							{
								case NumComporationOperators.greater: oPositive = oCurFormat;break;
								case NumComporationOperators.less: oNegative = oCurFormat;break;
								case NumComporationOperators.equal: oNull = oCurFormat;break;
							}
						}
						else
						{
							//невозможно привести
							oPositive = oNegative = oNull = null;
							break;
						}
					}
				}
			}
			this.oTextFormat = new NumFormat(false);
			this.oTextFormat.setFormat("@");
			if(null == oPositive || null == oNegative || null == oNull)
			{
				//по результатам опытов, если оператор сравнения проходит через 0, то надо добавлять знак минус в зависимости от значения
				//пример [<100] надо добавлять знак, [<-100] знак добавлять не надо
				for(var i = 0, length = aParsedFormats.length; i < length; ++i)
				{
					var oCurFormat = aParsedFormats[i];
					if(null == oCurFormat.ComporationOperator)
						oCurFormat.bAddMinusIfNes = true;
					else
					{
						var oComporationOperator = oCurFormat.ComporationOperator;
						if(0 < oComporationOperator.operatorValue && (oComporationOperator.operator == NumComporationOperators.less || oComporationOperator.operator == NumComporationOperators.lessorequal))
							oCurFormat.bAddMinusIfNes = true;
						else if(0 > oComporationOperator.operatorValue && (oComporationOperator.operator == NumComporationOperators.greater || oComporationOperator.operator == NumComporationOperators.greaterorequal))
							oCurFormat.bAddMinusIfNes = true;
					}
				}
				this.aComporationFormats = aParsedFormats;
			}
			else
			{
				this.oPositiveFormat = oPositive;
				this.oNegativeFormat = oNegative;
				this.oNullFormat = oNull;
			}
		}
	}
	if(false == bComporationOperator)
	{
		if(4 <= nFormatsLength)
		{
			this.oPositiveFormat = aParsedFormats[0];
			this.oNegativeFormat = aParsedFormats[1];
			this.oNullFormat = aParsedFormats[2];
			this.oTextFormat = aParsedFormats[3];
			//for ';;;' format, if 4 formats exist fourth always used for text
			this.oTextFormat.bTextFormat = true;
		}
		else if(3 == nFormatsLength)
		{
			this.oPositiveFormat = aParsedFormats[0];
			this.oNegativeFormat = aParsedFormats[1];
			this.oNullFormat = aParsedFormats[2];
			this.oTextFormat = this.oPositiveFormat;
			if (this.oNullFormat.bTextFormat) {
			    this.oTextFormat = this.oNullFormat;
			    this.oNullFormat = this.oPositiveFormat;
			}
		}
		else if(2 == nFormatsLength)
		{
			this.oPositiveFormat = aParsedFormats[0];
			this.oNegativeFormat = aParsedFormats[1];
			this.oNullFormat = this.oPositiveFormat;
			this.oTextFormat = this.oPositiveFormat;
			if (this.oNegativeFormat.bTextFormat) {
			    this.oTextFormat = this.oNegativeFormat;
			    this.oNegativeFormat = this.oPositiveFormat;
			}
		}
		else
		{
			this.oPositiveFormat = aParsedFormats[0];
			this.oPositiveFormat.bAddMinusIfNes = true;
			this.oNegativeFormat = this.oPositiveFormat;
			this.oNullFormat = this.oPositiveFormat;
			this.oTextFormat = this.oPositiveFormat;
		}
	}
    this.formatCache = {};
}
CellFormat.prototype =
{
	isTextFormat : function()
	{
		if(null != this.oPositiveFormat)
			return this.oPositiveFormat.bTextFormat;
		else if(null != this.aComporationFormats && this.aComporationFormats.length > 0)
			return this.aComporationFormats[0].bTextFormat;
		return false;
	},
	isGeneralFormat : function()
	{
		if(null != this.oPositiveFormat)
			return this.oPositiveFormat.isGeneral();
		else if(null != this.aComporationFormats && this.aComporationFormats.length > 0)
			return this.aComporationFormats[0].isGeneral();
		return false;
	},
	isDateTimeFormat : function()
	{
		if(null != this.oPositiveFormat)
			return this.oPositiveFormat.bDateTime;
		else if(null != this.aComporationFormats && this.aComporationFormats.length > 0)
			return this.aComporationFormats[0].bDateTime;
		return false;
	},
	getTextFormat: function () {
	    var oRes = null;
	    if (null == this.aComporationFormats) {
	        if (null != this.oTextFormat && this.oTextFormat.bTextFormat)
	            oRes = this.oTextFormat;
	    } else {
	        for (var i = 0, length = this.aComporationFormats.length; i < length ; ++i) {
	            var oCurFormat = this.aComporationFormats[i];
	            if (null == oCurFormat.ComporationOperator && oCurFormat.bTextFormat) {
	                oRes = oCurFormat;
	                break;
	            }
	        }
	    }
	    return oRes;
	},
	getFormatByValue : function(dNumber)
	{
		var oRes = null;
		if(null == this.aComporationFormats)
		{
			if(dNumber > 0 && null != this.oPositiveFormat)
				oRes = this.oPositiveFormat;
			else if(dNumber < 0 && null != this.oNegativeFormat)
				oRes = this.oNegativeFormat;
			else if(null != this.oNullFormat)
				oRes = this.oNullFormat;
		}
		else
		{
			//ищем совпадение
			var nLength = this.aComporationFormats.length;
			var oDefaultComporationFormat = null;
			for(var i = 0, length = nLength; i < length ; ++i)
			{
				var oCurFormat = this.aComporationFormats[i];
				if(null != oCurFormat.ComporationOperator)
				{
					var bOperationResult = false;
					var oOperationValue = oCurFormat.ComporationOperator.operatorValue;
					switch(oCurFormat.ComporationOperator.operator)
					{
						case NumComporationOperators.equal: bOperationResult = (dNumber == oOperationValue);break;
						case NumComporationOperators.greater: bOperationResult = (dNumber > oOperationValue);break;
						case NumComporationOperators.less: bOperationResult = (dNumber < oOperationValue);break;
						case NumComporationOperators.greaterorequal: bOperationResult = (dNumber >= oOperationValue);break;
						case NumComporationOperators.lessorequal: bOperationResult = (dNumber <= oOperationValue);break;
						case NumComporationOperators.notequal: bOperationResult = (dNumber != oOperationValue);break;
					}
					if(true == bOperationResult)
						oRes = oCurFormat;
				}
				else if(null == oDefaultComporationFormat)
					oDefaultComporationFormat = oCurFormat;
			}
			if(null == oRes && null != oDefaultComporationFormat)
				oRes = oDefaultComporationFormat;
		}
		return oRes;
	},
    format : function(number, nValType, dDigitsCount, bChart, cultureInfo, opt_withoutCache)
    {
        var res = null;
        if (null == bChart)
            bChart = false;
        var lcid = cultureInfo ? cultureInfo.LCID : 0;
        var cacheKey, cacheVal;
        if (!opt_withoutCache) {
            cacheKey = number + '-' + nValType + '-' + dDigitsCount + '-' + lcid;
            cacheVal = this.formatCache[cacheKey];
            if(null != cacheVal)
            {
                if (bChart)
                    res = cacheVal.chart;
                else
                    res = cacheVal.nochart;
                if (null != res)
                    return res;
            }
        }
        res = [{text: number.toString()}];
        var dNumber = number - 0;
        var oFormat = null;
		if(CellValueType.String != nValType && number == dNumber)
		{
			oFormat = this.getFormatByValue(dNumber);
			if(null != oFormat)
			    res = oFormat.format(number, nValType, dDigitsCount, cultureInfo, bChart);
			else if(null != this.aComporationFormats)
			{
			    var oNewFont = new AscCommonExcel.Font();
				oNewFont.repeat = true;
				res = [{text: "#", format: oNewFont}];
			}
		}
		else
		{
			//text
		    if (null != this.oTextFormat) {
		        oFormat = this.oTextFormat;
		        res = oFormat.format(number, nValType, dDigitsCount, cultureInfo, bChart);
		    }
		}
        if (!opt_withoutCache) {
            if (null == cacheVal) {
                cacheVal = {chart: null, nochart: null};
                this.formatCache[cacheKey] = cacheVal;
            }
            if (null != oFormat && oFormat.bGeneralChart) {
                if (bChart)
                    cacheVal.chart = res;
                else
                    cacheVal.nochart = res;
            }
            else {
                cacheVal.chart = res;
                cacheVal.nochart = res;
            }
        }
        return res;
    },
    shiftFormat : function(output, nShift)
    {
        var bRes = false;
        var bCurRes = true;
		if(null == this.aComporationFormats)
		{
			bCurRes = this.oPositiveFormat.toString(output, nShift);
			if(false == bCurRes)
				output.format = this.oPositiveFormat.formatString;
			bRes |= bCurRes;
			if(null != this.oNegativeFormat && this.oPositiveFormat != this.oNegativeFormat)
			{
				var oTempOutput = {};
				bCurRes = this.oNegativeFormat.toString(oTempOutput, nShift);
				if(false == bCurRes)
					output.format += ";" + this.oNegativeFormat.formatString;
				else
					output.format += ";" + oTempOutput.format;
				bRes |= bCurRes;
			}
			if(null != this.oNullFormat && this.oPositiveFormat != this.oNullFormat)
			{
				var oTempOutput = {};
				bCurRes = this.oNullFormat.toString(oTempOutput, nShift);
				if(false == bCurRes)
					output.format += ";" + this.oNullFormat.formatString;
				else
					output.format += ";" + oTempOutput.format;
				bRes |= bCurRes;
			}
			if(null != this.oTextFormat && this.oPositiveFormat != this.oTextFormat)
			{
				var oTempOutput = {};
				bCurRes = this.oTextFormat.toString(oTempOutput, nShift);
				if(false == bCurRes)
					output.format += ";" + this.oTextFormat.formatString;
				else
					output.format += ";" + oTempOutput.format;
				bRes |= bCurRes;
			}
		}
		else
		{
			var length = this.aComporationFormats.length;
			output.format = "";
			for(var i = 0; i < length; ++i)
			{
				var oTempOutput = {};
				var oCurFormat = this.aComporationFormats[i];
				var bCurRes = oCurFormat.toString(oTempOutput, nShift);
				if(0 != i)
					output.format += ";";
				if(false == bCurRes)
					output.format += oCurFormat.formatString;
				else
					output.format += oTempOutput.format;
				bRes |= bCurRes;
			}
		}
        return bRes;
    },
	formatToMathInfo : function(number, nValType, dDigitsCount)
	{
		return this._formatToText(number, nValType, dDigitsCount, false);
	},
	formatToChart : function(number, dDigitsCount, cultureInfo)
	{
		return this._formatToText(number, CellValueType.Number, dDigitsCount || gc_nMaxDigCount, true, cultureInfo);
	},
	_formatToText : function(number, nValType, dDigitsCount, bChart, cultureInfo)
	{
		var result = "";
		var arrFormat = this.format(number, nValType, dDigitsCount, bChart, cultureInfo);
		for (var i = 0, item; i < arrFormat.length; ++i) {
			item = arrFormat[i];
			if (item.format) {
				if (item.format.repeat)
					continue;
				if (item.format.skip) {
					result += " ";
					continue;
				}
			}
			if (item.text)
				result += item.text;
		}
		return result;
	},
	getType: function() {
		return this.getTypeInfo().type;
	},
	getTypeInfo: function() {
		var info;
		if (null != this.oPositiveFormat) {
			info = this.oPositiveFormat.getFormatCellsInfo();
			info.asc_setType(this._getType(this.oPositiveFormat));
		} else if (null != this.aComporationFormats && this.aComporationFormats.length > 0) {
			info = this.aComporationFormats[0].getFormatCellsInfo();
			info.asc_setType(this._getType(this.aComporationFormats[0]));
		} else {
			info = new Asc.asc_CFormatCellsInfo();
			info.asc_setType(c_oAscNumFormatType.General);
			info.asc_setDecimalPlaces(0);
			info.asc_setSeparator(false);
			info.asc_setSymbol(null);
		}
		return info;
	},
	_getType: function(format) {
		var nType = c_oAscNumFormatType.Custom;
		if (format.isGeneral()) {
			nType = c_oAscNumFormatType.General;
		}
		else if (format.bDateTime) {
			if (format.bDate) {
				nType = c_oAscNumFormatType.Date;
			} else {
				nType = c_oAscNumFormatType.Time;
			}
		}
		else if (format.bCurrency) {
			if (format.bRepeat) {
				nType = c_oAscNumFormatType.Accounting;
			} else {
				nType = c_oAscNumFormatType.Currency;
			}
		} else {
			var info = format.getFormatCellsInfo();
			var types = [c_oAscNumFormatType.Text, c_oAscNumFormatType.Percent, c_oAscNumFormatType.Scientific,
				c_oAscNumFormatType.Number, c_oAscNumFormatType.Fraction];
			for (var i = 0; i < types.length; ++i) {
				var type = types[i];
				info.asc_setType(type);
				var formats = getFormatCells(info);
				if (-1 != formats.indexOf(this.sFormat)) {
					nType = type;
					break;
				}
			}

		}
		return nType;
	}
};
var oDecodeGeneralFormatCache = {};
function DecodeGeneralFormat(val, nValType, dDigitsCount)
{
    var cacheVal = oDecodeGeneralFormatCache[val];
    if(null != cacheVal)
    {
        cacheVal = cacheVal[nValType];
        if(null != cacheVal)
        {
            cacheVal = cacheVal[dDigitsCount];
            if(null != cacheVal)
                return cacheVal;
        }
    }
    var res = DecodeGeneralFormat_Raw(val, nValType, dDigitsCount);
    var cacheVal = oDecodeGeneralFormatCache[val];
    if(null == cacheVal)
    {
        cacheVal = {};
        oDecodeGeneralFormatCache[val] = cacheVal;
    }
    var cacheType = cacheVal[nValType];
    if(null == cacheType)
    {
        cacheType = {};
        cacheVal[nValType] = cacheType;
    }
    cacheType[dDigitsCount] = res;
    return res;
}
function DecodeGeneralFormat_Raw(val, nValType, dDigitsCount)
{
    if(CellValueType.String == nValType)
        return "@";
    var number = val - 0;
    if(number != val)
        return "@";
    if(0 == number)
        return "0";
    var nDigitsCount;
    if(null == dDigitsCount || dDigitsCount > gc_nMaxDigCountView)
        nDigitsCount = gc_nMaxDigCountView;
    else
        nDigitsCount = parseInt(dDigitsCount);//пока не подключена измерялся не используем нецелые метрики
    if(number < 0)
    {
        //todo возможно нужно nDigitsCount--
        //nDigitsCount--;//на знак '-'
        number = -number;
    }
    if(nDigitsCount < 1)
        return "0";//можно возвращать любой числовой формат, все равно при nDigitsCount < 1 он учитываться не будет
	var bContinue = true;
	var parts = getNumberParts(number);
	while(bContinue)
	{
		bContinue = false;
		var nRealExp = gc_nMaxDigCount + parts.exponent;//nRealExp == 0, при 0,123
		var nRealExpAbs = Math.abs(nRealExp);
		var nExpMinDigitsCount;//число знаков в формате 'E+00'
		if(nRealExpAbs < 100)
			nExpMinDigitsCount = 4;
		else
			nExpMinDigitsCount = 2 + nRealExpAbs.toString().length;
		
		var suffix = "";
		if (nRealExp > 0)
		{
			if(nRealExp > nDigitsCount)
			{
				if(nDigitsCount >= nExpMinDigitsCount + 1)//1 на еще один символ перед E (*E+00)
				{
					suffix = "E+";
					for(var i = 2; i < nExpMinDigitsCount; ++i)
						suffix += "0";
					nDigitsCount -= nExpMinDigitsCount;
				}
				else
					return "0";//можно возвращать любой числовой формат, все равно будут решетки
			}
		}
		else
		{
			var nVarian1 = nDigitsCount - 2 + nRealExp;//без E+00, 2 на знаки "0."
			var nVarian2 = nDigitsCount - nExpMinDigitsCount;// с E+00
			if(nVarian2 > 2)
				nVarian2--;//на знак '.'
			else if(nVarian2 > 0)
				nVarian2 = 1;
			if(nVarian1 <= 0 && nVarian2 <= 0)
				return "0";
			if(nVarian1 < nVarian2)
			{
				//если в nVarian1 число помещается полностью, то применяем nVarian1
				var bUseVarian1 = false;
				if(nVarian1 > 0 && 0 == (parts.mantissa % Math.pow(10, gc_nMaxDigCount - nVarian1)))
					bUseVarian1 = true;
				if(false == bUseVarian1)
				{
					if(nDigitsCount >= nExpMinDigitsCount + 1)
					{
						suffix = "E+";
						for(var i = 2; i < nExpMinDigitsCount; ++i)
							suffix += "0";
						nDigitsCount -= nExpMinDigitsCount;
					}
					else
						return "0";//можно возвращать любой числовой формат, все равно будут решетки
				}
			}
		}
		var dec_num_digits = nRealExp;
		if(suffix)
			dec_num_digits = 1;
		//округляем мантиссу, чтобы правильно обрабатывать ситуацию 0,999, когда nDigitsCount = 4
		var nRoundDigCount = 0;
		if(dec_num_digits <= 0)
		{
			//2 на знаки '0.'
			var nTemp = nDigitsCount + dec_num_digits - 2;
			if(nTemp > 0)
				nRoundDigCount = nTemp;
		}
		else if(dec_num_digits < gc_nMaxDigCount)
		{
			if(dec_num_digits <= nDigitsCount)
			{
				//1 на знаки '.'
				if(dec_num_digits + 1 < nDigitsCount)
					nRoundDigCount = nDigitsCount - 1;
				else
					nRoundDigCount = dec_num_digits;
			}
		}
		if(nRoundDigCount > 0)
		{
			var nTemp = Math.pow(10, gc_nMaxDigCount - nRoundDigCount);
			number = Math.round(parts.mantissa / nTemp) * nTemp * Math.pow(10, parts.exponent);
			
			var oNewParts = getNumberParts(number);
			//если в результате округления изменилось число разрядов, надо начинать заново
			if(oNewParts.exponent != parts.exponent)
				bContinue = true;
			else
				bContinue = false;
			parts = oNewParts;
		}
	}
	
    var frac_num_digits;
    if(dec_num_digits > 0)
        frac_num_digits = nDigitsCount - 1 - dec_num_digits;//1 на знак '.'
    else
        frac_num_digits = nDigitsCount - 2 + dec_num_digits;//2 на знаки '0.' 
        
    //считаем необходимое число знаков после запятой
    if(frac_num_digits > 0)
    {
		var sTempNumber = parts.mantissa.toString();
		var sTempNumber;
		if(dec_num_digits > 0)
			sTempNumber = sTempNumber.substring(dec_num_digits, dec_num_digits + frac_num_digits);
		else
			sTempNumber = sTempNumber.substring(0, frac_num_digits);
        var nTempNumberLength = sTempNumber.length;
        var nreal_frac_num_digits = frac_num_digits;
        for(var i = frac_num_digits - 1; i >= 0; --i)
        {
            if("0" == sTempNumber[i])
                nreal_frac_num_digits--;
            else
                break;
        }
        frac_num_digits = nreal_frac_num_digits;
		if(dec_num_digits < 0)
			frac_num_digits += (-dec_num_digits);
    }
    if(frac_num_digits <= 0)
        return "0" + suffix;

    //собираем формат
    var number_format_string = "0" + gc_sFormatDecimalPoint;
    for(var i = 0; i < frac_num_digits; ++i)
        number_format_string += "0";
    number_format_string += suffix;
    return number_format_string;
}
function GeneralEditFormatCache()
{
    this.oCache = {};
}
GeneralEditFormatCache.prototype =
{
	cleanCache : function(){
		this.oCache = {};
	},
    format: function (number, cultureInfo)
    {
        if (null == cultureInfo)
            cultureInfo = g_oDefaultCultureInfo;
        //преобразуем число так чтобы в строке было только 15 значящих цифр.
        var value = this.oCache[number];
        if(null == value)
        {
			if(0 == number)
				value = "0";
			else
			{
				var sRes = "";
				var parts = getNumberParts(number);
				var nRealExp = gc_nMaxDigCount + parts.exponent;//nRealExp == 0, при 0,123
				if(parts.exponent >= 0)//nRealExp >= -gc_nMaxDigCount
				{
					if(nRealExp <= 21)
					{
						sRes = parts.mantissa.toString();
						for(var i = 0; i < parts.exponent; ++i)
							sRes += "0";
					}
					else
					{
					    sRes = this._removeTileZeros(parts.mantissa.toString(), cultureInfo);
						if(sRes.length > 1)
						{
							var temp = sRes.substring(0, 1);
							temp += cultureInfo.NumberDecimalSeparator;
							temp += sRes.substring(1);
							sRes = temp;
						}
						sRes += "E+" + (nRealExp - 1);
					}
				}
				else
				{
					if(nRealExp > 0)
					{
						sRes = parts.mantissa.toString();
						if(sRes.length > nRealExp)
						{
							var temp = sRes.substring(0, nRealExp);
							temp += cultureInfo.NumberDecimalSeparator;
							temp += sRes.substring(nRealExp);
							sRes = temp;
						}
						sRes = this._removeTileZeros(sRes, cultureInfo);
					}
					else
					{
						if(nRealExp >= -18)
						{
							sRes = "0";
							sRes += cultureInfo.NumberDecimalSeparator;
							for(var i = 0; i < -nRealExp; ++i)
								sRes += "0";
							var sTemp = parts.mantissa.toString();
							sTemp = sTemp.substring(0, 19 + nRealExp);
							sRes += this._removeTileZeros(sTemp, cultureInfo);
						}
						else
						{
							sRes = parts.mantissa.toString();
							if(sRes.length > 1)
							{
								var temp = sRes.substring(0, 1);
								temp += cultureInfo.NumberDecimalSeparator;
								temp += sRes.substring(1);
								temp = this._removeTileZeros(temp, cultureInfo);
								sRes = temp;
							}
							sRes += "E-" + (1 - nRealExp);
						}
					}
				}
				if( SignType.Negative == parts.sign)
					value = "-" + sRes;
				else
					value = sRes;
			}
            this.oCache[number] = value;
        }
        return value;
    },
    _removeTileZeros: function (val, cultureInfo)
    {
		var res = val;
		var nLength = val.length;
		var nLastNoZero = nLength - 1;
		for(var i = val.length - 1; i >= 0; --i)
		{
			nLastNoZero = i;
			if("0" != val[i])
				break;
		}
		if(nLastNoZero != nLength - 1)
		{
		    if (cultureInfo.NumberDecimalSeparator == res[nLastNoZero])
				res = res.substring(0, nLastNoZero);
			else
				res = res.substring(0, nLastNoZero + 1);
		}
		return res;
	}
};
var oGeneralEditFormatCache = new GeneralEditFormatCache();

function FormatParser()
{
    this.aCurrencyRegexp = {};
    this.aThouthandRegexp = {};
	this.days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
	this.daysLeap = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
	this.bFormatMonthFirst = true;
}
FormatParser.prototype =
{
    isLocaleNumber: function (val, cultureInfo) {
        if (null == cultureInfo)
            cultureInfo = g_oDefaultCultureInfo;
        //javascript decimal separator is '.'
        if ("." != cultureInfo.NumberDecimalSeparator) {
            val = val.replace(".", "q");//заменяем на символ с которым не распознается, как в Excel
            val = val.replace(cultureInfo.NumberDecimalSeparator, ".");
        }
        //parseNum исключаем запись числа в 16-ричной форме из числа.
        return AscCommonExcel.parseNum(val) && Asc.isNumberInfinity(val);
    },
    parseLocaleNumber: function (val, cultureInfo) {
        if (null == cultureInfo)
            cultureInfo = g_oDefaultCultureInfo;
        //javascript decimal separator is '.'
        if ("." != cultureInfo.NumberDecimalSeparator) {
            val = val.replace(".", "q");//заменяем на символ с которым не распознается, как в Excel
            val = val.replace(cultureInfo.NumberDecimalSeparator, ".");
        }
        return val - 0;
    },
    parse: function (value, cultureInfo)
    {
        if (null == cultureInfo)
            cultureInfo = g_oDefaultCultureInfo;
        var res = null;
        var bError = false;
        //replace Non-breaking space(0xA0) with White-space(0x20)
        if (" " == cultureInfo.NumberGroupSeparator)
            value = value.replace(new RegExp(String.fromCharCode(0xA0), "g"));
        var rx_thouthand = this.aThouthandRegexp[cultureInfo.LCID];
        if (null == rx_thouthand) {
            rx_thouthand = new RegExp("^(([ \\+\\-%\\$€£¥\\(]|" + escapeRegExp(cultureInfo.CurrencySymbol) + ")*)((\\d+" + escapeRegExp(cultureInfo.NumberGroupSeparator) + "\\d+)*\\d*" + escapeRegExp(cultureInfo.NumberDecimalSeparator) + "?\\d*)(([ %\\)]|р.|" + escapeRegExp(cultureInfo.CurrencySymbol) + ")*)$");
            this.aThouthandRegexp[cultureInfo.LCID] = rx_thouthand;
        }
        var match = value.match(rx_thouthand);
        if (null != match) {
            var sBefore = match[1];
            var sVal = match[3];
            var sAfter = match[5];
			var oChartCount = {};
			if(null != sBefore)
			    this._parseStringLetters(sBefore, cultureInfo.CurrencySymbol, true, oChartCount);
			if(null != sAfter)
			    this._parseStringLetters(sAfter, cultureInfo.CurrencySymbol, false, oChartCount);
			var bMinus = false;
			var bPercent = false;
			var sCurrency = null;
			var oCurrencyElem = null;
			var nBracket = 0;
			for(var sChar in oChartCount){
				var elem = oChartCount[sChar];
				if(" " == sChar)
					continue;
				else if("+" == sChar){
					if(elem.all > 1)
						bError = true;
				}
				else if("-" == sChar){
					if(elem.all > 1)
						bError = true;
					else
						bMinus = true;
				}
				else if("-" == sChar){
					if(elem.all > 1)
						bError = true;
					else
						bMinus = true;
				}
				else if("(" == sChar){
					if(1 == elem.all && 1 == elem.before)
						nBracket++;
					else
						bError = true;
				}
				else if(")" == sChar){
					if(1 == elem.all && 1 == elem.after)
						nBracket++;
					else
						bError = true;
				}
				else if("%" == sChar){
					if(1 == elem.all)
						bPercent = true;
					else
						bError = true;
				}
				else{
					if(null == sCurrency && 1 == elem.all){
						sCurrency = sChar;
						oCurrencyElem = elem;
					}
					else
						bError = true;
				}
			}
			if (nBracket > 0) {
			    if (2 == nBracket)
			        bMinus = true;
			    else
			        bError = true;
			}
			var CurrencyNegativePattern = cultureInfo.CurrencyNegativePattern;
			if(null != sCurrency){
			    if (sCurrency == cultureInfo.CurrencySymbol) {
			        var nPattern = cultureInfo.CurrencyNegativePattern;
			        if (0 == nPattern || 1 == nPattern || 2 == nPattern || 3 == nPattern || 9 == nPattern || 11 == nPattern || 12 == nPattern || 14 == nPattern) {
			            if (1 != oCurrencyElem.before)
			                bError = true;
			        }
			        else if (1 != oCurrencyElem.after)
			            bError = true;
			    }
			    else if(-1 != "$€£¥".indexOf(sCurrency)){
			        if (1 == oCurrencyElem.before) {
			            CurrencyNegativePattern = 0;
			        }
                    else
						bError = true;
				}
				else if(-1 != "р.".indexOf(sCurrency)){
				    if (1 == oCurrencyElem.after) {
				        CurrencyNegativePattern = 5;
				    }
                    else
						bError = true;
				}
				else
				    bError = true;
			}
			if(!bError){
				var oVal = this._parseThouthand(sVal, cultureInfo);
				if (oVal) {
					res = {format: null, value: null, bDateTime: false, bDate: false, bTime: false, bPercent: false, bCurrency: false};
					var dVal = oVal.number;
					if (bMinus)
						dVal = -dVal;
					var sFracFormat = "";
					if (parseInt(dVal) != dVal)
						sFracFormat = gc_sFormatDecimalPoint + "00";
					var sFormat = null;
					if (bPercent) {
						res.bPercent = true;
						dVal /= 100;
						sFormat = "0" + sFracFormat + "%";
					}
					else if (sCurrency) {
						res.bCurrency = true;
					    var sNumberFormat = "#" + gc_sFormatThousandSeparator + "##0" + sFracFormat;
					    var sCurrencyFormat;
					    if(sCurrency.length > 1)
					        sCurrencyFormat = "\"" + sCurrency + "\"";
					    else
					        sCurrencyFormat = "\\" + sCurrency;
					    var sPositivePattern;
					    var sNegativePattern;
					    switch (CurrencyNegativePattern) {
					        case 0:
					            sPositivePattern = sCurrencyFormat + sNumberFormat + "_)";
					            sNegativePattern = "[Red](" + sCurrencyFormat + sNumberFormat + ")";
					            break;
					        case 1:
					            sPositivePattern = sCurrencyFormat + sNumberFormat;
					            sNegativePattern = "[Red]-" + sCurrencyFormat + sNumberFormat;
					            break;
					        case 2:
					            sPositivePattern = sCurrencyFormat + sNumberFormat;
					            sNegativePattern = "[Red]" + sCurrencyFormat + "-" + sNumberFormat;
					            break;
					        case 3:
					            sPositivePattern = sCurrencyFormat + sNumberFormat + "_-";
					            sNegativePattern = "[Red]" + sCurrencyFormat + sNumberFormat + "-";
					            break;
					        case 4:
					            sPositivePattern = sNumberFormat + sCurrencyFormat + "_)";
					            sNegativePattern = "[Red](" + sNumberFormat + sCurrencyFormat + ")";
					            break;
					        case 5:
					            sPositivePattern = sNumberFormat + sCurrencyFormat;
					            sNegativePattern = "[Red]-" + sNumberFormat + sCurrencyFormat;
					            break;
					        case 6:
					            sPositivePattern = sNumberFormat + "-" + sCurrencyFormat;
					            sNegativePattern = "[Red]" + sNumberFormat + "-" + sCurrencyFormat;
					            break;
					        case 7:
					            sPositivePattern = sNumberFormat + sCurrencyFormat + "_-";
					            sNegativePattern = "[Red]" + sNumberFormat + sCurrencyFormat + "-";
					            break;
					        case 8:
					            sPositivePattern = sNumberFormat + " " + sCurrencyFormat;
					            sNegativePattern = "[Red]-" + sNumberFormat + " " + sCurrencyFormat;
					            break;
					        case 9:
					            sPositivePattern = sCurrencyFormat + " " + sNumberFormat;
					            sNegativePattern = "[Red]-" + sCurrencyFormat + " " + sNumberFormat;
					            break;
					        case 10:
					            sPositivePattern = sNumberFormat + " " + sCurrencyFormat + "_-";
					            sNegativePattern = "[Red]" + sNumberFormat + " " + sCurrencyFormat + "-";
					            break;
					        case 11:
					            sPositivePattern = sCurrencyFormat + " " + sNumberFormat + "_-";
					            sNegativePattern = "[Red]" + sCurrencyFormat + " " + sNumberFormat + "-";
					            break;
					        case 12:
					            sPositivePattern = sCurrencyFormat + " " + sNumberFormat;
					            sNegativePattern = "[Red]" + sCurrencyFormat + " -" + sNumberFormat;
					            break;
					        case 13:
					            sPositivePattern = sNumberFormat + " " + sCurrencyFormat;
					            sNegativePattern = "[Red]" + sNumberFormat + "- " + sCurrencyFormat;
					            break;
					        case 14:
					            sPositivePattern = sCurrencyFormat + " " + sNumberFormat + "_)";
					            sNegativePattern = "[Red](" + sCurrencyFormat + " " + sNumberFormat + ")";
					            break;
					        case 15:
					            sPositivePattern = sNumberFormat + " " + sCurrencyFormat + "_)";
					            sNegativePattern = "[Red](" + sNumberFormat + " " + sCurrencyFormat + ")";
					            break;
					    }
					    sFormat = sPositivePattern + ";" + sNegativePattern;
					}
					else if (oVal.thouthand) {
						sFormat = "#" + gc_sFormatThousandSeparator + "##0" + sFracFormat;
					}
					else
						sFormat = AscCommon.g_cGeneralFormat;
					res.format = sFormat;
					res.value = dVal;
				}
			}
        }
        if (null == res && !bError)
            res = this.parseDate(value, cultureInfo);
        return res;
    },
    _parseStringLetters: function (sVal, currencySymbol, bBefore, oRes) {
        //отдельно обрабатываем 'р.' и currencySymbol потому что они могут быть не односимвольными
        var aTemp = ["р.", currencySymbol];
        for (var i = 0, length = aTemp.length; i < length; i++){
            var sChar = aTemp[i];
            var nIndex = -1;
            var nCount = 0;
            while(-1 != (nIndex = sVal.indexOf(sChar, nIndex + 1)))
                nCount++;
            if(nCount > 0)
            {
                sVal = sVal.replace(new RegExp(escapeRegExp(sChar), "g"), "");
                var elem = oRes[sChar];
                if(!elem){
                    elem = {before: 0, after: 0, all: 0};
                    oRes[sChar] = elem;
                }
                if(bBefore)
                    elem.before += nCount;
                else
                    elem.after += nCount;
                elem.all += nCount;
            }
        }
		for(var i = 0, length = sVal.length; i < length; i++){
			var sChar = sVal[i];
			var elem = oRes[sChar];
			if(!elem){
				elem = {before: 0, after: 0, all: 0};
				oRes[sChar] = elem;
			}
			if(bBefore)
				elem.before++;
			else
				elem.after++;
			elem.all++;
		}
	},
    _parseThouthand: function (val, cultureInfo)
    {
        var oRes = null;
        var bThouthand = false;
        //reverse
        var sReverseVal = "";
        for (var i = val.length - 1; i >= 0; --i)
            sReverseVal += val[i];
        var nGroupSizeIndex = 0;
        var nGroupSize = cultureInfo.NumberGroupSizes[nGroupSizeIndex];
        var nPrevIndex = 0;
        var nIndex = -1;
        var bError = false;
        while (-1 != (nIndex = sReverseVal.indexOf(cultureInfo.NumberGroupSeparator, nIndex + 1))) {
            var nCurLength = nIndex - nPrevIndex;
            if (nCurLength < nGroupSize) {
                bError = true;
                break;
            }
            if (nGroupSizeIndex < cultureInfo.NumberGroupSizes.length - 1) {
                nGroupSizeIndex++;
                nGroupSize = cultureInfo.NumberGroupSizes[nGroupSizeIndex];
            }
            nPrevIndex = nIndex + 1;
        }
        if (!bError) {
            if (0 != nPrevIndex) {
                //чтобы не распознавалось 0,001
                if (nPrevIndex < val.length && parseInt(val.substr(0, val.length - nPrevIndex)) > 0) {
                    val = val.replace(new RegExp(escapeRegExp(cultureInfo.NumberGroupSeparator), "g"), '');
                    bThouthand = true;
                }
            }
			if (g_oFormatParser.isLocaleNumber(val, cultureInfo)) {
				var dNumber = g_oFormatParser.parseLocaleNumber(val, cultureInfo);
				oRes = { number: dNumber, thouthand: bThouthand };
			}
        }
		return oRes;
	},
    _parseDateFromArray: function (match, oDataTypes, cultureInfo)
	{
        var res = null;
        var bError = false;
        //в первый проход разделяем date и time с помощью delimiter
        for (var i = 0, length = match.length; i < length; i++) {
            var elem = match[i];
            if (elem.type == oDataTypes.delimiter) {
                bError = true;
                if(i - 1 >= 0 && i + 1 < length){
                    var prev = match[i - 1];
                    var next = match[i + 1];
                    if(prev.type != oDataTypes.delimiter && next.type != oDataTypes.delimite){
                        if (cultureInfo.TimeSeparator == elem.val || (":" == elem.val && cultureInfo.DateSeparator != elem.val)) {
                            if(false == prev.date && false == next.date){
                                bError = false;
                                prev.time = true;
                                next.time = true;
                            }
                        }
                        else{
                            if(false == prev.time && false == next.time){
                                bError = false;
                                prev.date = true;
                                next.date = true;
                            }
                        }
                    }
                }
                else if (i - 1 >= 0 && i + 1 == length) {
                    //случай "10:"
                    var prev = match[i - 1];
                    if (prev.type != oDataTypes.delimiter) {
                        if (cultureInfo.TimeSeparator == elem.val || (":" == elem.val && cultureInfo.DateSeparator != elem.val)) {
                            if (false == prev.date) {
                                bError = false;
                                prev.time = true;
                            }
                        }
                    }
                }
                if(bError)
                    break;
            }
        }
        if(!bError){
            //разделяем date и time с помощью Am/Pm и имена месяцев
            for (var i = 0, length = match.length; i < length; i++) {
                var elem = match[i];
                if (elem.type == oDataTypes.letter){
                    var valLower = elem.val.toLowerCase();
                    if (elem.am || elem.pm) {
                        if (i - 1 >= 0) {
                            var prev = match[i - 1];
                            if (oDataTypes.digit == prev.type && false == prev.date) {
                                prev.time = true;
                            }
                        }
                        //AmPm должна быть последней записью
                        if (i + 1 != length) {
                            bError = true;
                        }
                    }
                    else if (null != elem.month) {
                        if (i - 1 >= 0) {
                            var prev = match[i - 1];
                            if (oDataTypes.digit == prev.type && false == prev.time)
                                prev.date = true;
                        }
                        if (i + 1 < length) {
                            var next = match[i + 1];
                            if (oDataTypes.digit == next.type && false == next.time)
                                next.date = true;
                        }
                    }
                    else
                        bError = true;
                }
                if(bError)
                    break;
            }
        }
        if(!bError){
            var aDate = [];
            var nMonthIndex = null;
            var sMonthFormat = null;
            var aTime = [];
            var am = false;
            var pm = false;
            for (var i = 0, length = match.length; i < length; i++) {
                var elem = match[i];
                if (elem.date) {
                    if (elem.type == oDataTypes.digit)
                        aDate.push(elem.val);
                    else if (elem.type == oDataTypes.letter && null != elem.month) {
                        nMonthIndex = aDate.length;
                        sMonthFormat = elem.month.format;
                        aDate.push(elem.month.val);
                    }
                    else
                        bError = true;
                }
                else if (elem.time) {
                    if (elem.type == oDataTypes.digit)
                        aTime.push(elem.val);
                    else if (elem.type == oDataTypes.letter && (elem.am || elem.pm)) {
                        am = elem.am;
                        pm = elem.pm;
                    }
                    else
                        bError = true;
                }
                else if (oDataTypes.digit == elem.type)
                    bError = true;//случай "1-2-3 10"
            }
            var nDateLength = aDate.length;
            if (nDateLength > 0 && !(2 <= nDateLength && nDateLength <= 3 && (null == nMonthIndex || (3 == nDateLength && 1 == nMonthIndex) || 2 == nDateLength)))
                bError = true;
            var nTimeLength = aTime.length;
            if (nTimeLength > 3)
                bError = true;
            if(!bError){
                res = { d: null, m: null, y: null, h: null, min: null, s: null, am: am, pm: pm, sDateFormat: null };
                if (nDateLength > 0) {
                    var nIndexD = Math.max(cultureInfo.ShortDatePattern.indexOf("0"), cultureInfo.ShortDatePattern.indexOf("1"));
                    var nIndexM = Math.max(cultureInfo.ShortDatePattern.indexOf("2"), cultureInfo.ShortDatePattern.indexOf("3"));
                    var nIndexY = Math.max(cultureInfo.ShortDatePattern.indexOf("4"), cultureInfo.ShortDatePattern.indexOf("5"));
                    if (null != nMonthIndex) {
                        if (2 == nDateLength) {
                            res.d = aDate[nDateLength - 1 - nMonthIndex];
                            res.m = aDate[nMonthIndex];
                            //приоритет у формата d-mmm, но если он не подходит пробуем сделать mmm-yy
                            if (this.isValidDate((new Date()).getFullYear(), res.m - 1, res.d))
                                res.sDateFormat = "d-mmm";
                            else {
                                //не в классическом случае(!= dd/mm/yyyy) меняем местами d и m перед тем как пробовать y
                                if (!isDMY(cultureInfo) && this.isValidDate((new Date()).getFullYear(), res.d - 1, res.m)) {
                                    res.sDateFormat = "d-mmm";
                                    var temp = res.d;
                                    res.d = res.m;
                                    res.m = temp;
                                }
                                else {
                                    //если текстовый месяц стоит вторым, то первый параметр может быть только днем
                                    if (0 == nMonthIndex) {
                                        res.sDateFormat = "mmm-yy";
                                        res.d = null;
                                        res.m = aDate[0];
                                        res.y = aDate[1];
                                    }
                                    else
                                        bError = true;
                                }
                            }
                        }
                        else {
                            res.sDateFormat = "d-mmm-yy";
                            res.d = aDate[0];
                            res.m = aDate[1];
                            res.y = aDate[2];
                        }
                    }
                    else {
                        //смотрим порядок в default формат
                        if (2 == nDateLength) {
                            //в приоритете d и m
                            if (nIndexD < nIndexM) {
                                res.d = aDate[0];
                                res.m = aDate[1];
                            }
                            else {
                                res.m = aDate[0];
                                res.d = aDate[1];
                            }
                            if (this.isValidDate((new Date()).getFullYear(), res.m - 1, res.d))
                                res.sDateFormat = "d-mmm";
                            else{
                                //в обратной записи(== yyyy/mm/dd) меняем местами d и m перед тем как пробовать y
                                if (isYMD(cultureInfo) && this.isValidDate((new Date()).getFullYear(), res.d - 1, res.m)) {
                                    res.sDateFormat = "d-mmm";
                                    var temp = res.d;
                                    res.d = res.m;
                                    res.m = temp;
                                }
                                else{
                                    res.sDateFormat = "mmm-yy";
                                    res.d = null;
                                    if (nIndexM < nIndexY) {
                                        res.m = aDate[0];
                                        res.y = aDate[1];
                                    }
                                    else {
                                        res.y = aDate[0];
                                        res.m = aDate[1];
                                    }
                                }
                            }
                        }
                        else {
                            for (var i = 0, length = cultureInfo.ShortDatePattern.length; i < length; i++)
                            {
                                var nIndex = cultureInfo.ShortDatePattern[i] - 0;
                                var val = aDate[i];
                                if (0 == nIndex || 1 == nIndex) {
                                    res.d = val;
                                } else if (2 == nIndex || 3 == nIndex) {
                                    res.m = val;
                                } else if (4 == nIndex || 5 == nIndex) {
                                    res.y = val;
                                }
                            }
                            res.sDateFormat = getShortDateFormat(cultureInfo);
                        }
                    }
                    if(null != res.y)
                    {
                        if(res.y < 30)
                            res.y = 2000 + res.y;
                        else if(res.y < 100)
                            res.y = 1900 + res.y;
                    }
                }
                if(nTimeLength > 0){
                    res.h = aTime[0];
                    if(nTimeLength > 1)
                        res.min = aTime[1];
                    if(nTimeLength > 2)
                        res.s = aTime[2];
                }
                if(bError)
                    res = null;
            }
        }
		return res;
    },
    strcmp: function (s1, s2, index1, length, index2) {
        if (null == index2)
            index2 = 0;
        var bRes = true;
        for (var i = 0; i < length; ++i) {
            if (s1[index1 + i] != s2[index2 + i]) {
                bRes = false;
                break;
            }
        }
        return bRes;
    },
	parseDate: function (value, cultureInfo)
	{
		var res = null;
		var match = [];
		var sCurValue = null;
		var oCurDataType = null;
		var oPrevType = null;
		var bAmPm = false;
		var bMonth = false;
		var bError = false;
		var oDataTypes = {letter: {id: 0, min: 2, max: 9}, digit: {id: 1, min: 1, max: 4}, delimiter: {id: 2, min: 1, max: 1}, space: {id: 3, min: null, max: null}};
		var valueLower = value.toLowerCase();
		for(var i = 0, length = value.length; i < length; i++)
		{
		    var sChar = value[i];
		    var oDataType = null;
		    if("0" <= sChar && sChar <= "9")
		        oDataType = oDataTypes.digit;
		    else if(" " == sChar)
		        oDataType = oDataTypes.space;
		    else if ("/" == sChar || "-" == sChar || ":" == sChar || cultureInfo.DateSeparator == sChar || cultureInfo.TimeSeparator == sChar)
		        oDataType = oDataTypes.delimiter;
		    else
		        oDataType = oDataTypes.letter;
			    
		    if(null != oDataType)
		    {
		        if(null == oCurDataType)
		            sCurValue = sChar;
		        else
		        {
		            if(oCurDataType == oDataType)
		            {
		                if(null == oCurDataType.max || sCurValue.length < oCurDataType.max)
		                    sCurValue += sChar;
		                else
		                    bError = true;
		            }
		            else
		            {
		                if (null == oCurDataType.min || sCurValue.length >= oCurDataType.min) {
		                    if (oDataTypes.space != oCurDataType) {
		                        var oNewElem = { val: sCurValue, type: oCurDataType, month: null, am: false, pm: false, date: false, time: false };
		                        if (oDataTypes.digit == oCurDataType)
		                            oNewElem.val = oNewElem.val - 0;
		                        match.push(oNewElem);
		                    }
		                    sCurValue = sChar;
		                    oPrevType = oCurDataType;
		                }
		                else
		                    bError = true;
		            }
		        }
		        oCurDataType = oDataType;
		    }
		    else
		        bError = true;
		    if(oDataTypes.letter == oDataType){
		        var oNewElem = { val: sCurValue, type: oCurDataType, month: null, am: false, pm: false, date: false, time: false };
		        var bAm = false;
		        var bPm = false;
		        if (!bAmPm && ((bAm = this.strcmp(valueLower, "am", i, 2)) || (bPm = this.strcmp(valueLower, "pm", i, 2)))) {
		            bAmPm = true;
		            oNewElem.am = bAm;
		            oNewElem.pm = bPm;
		            oNewElem.time = true;
		            match.push(oNewElem);
		            i += 2 - 1;
		            if (oPrevType != oDataTypes.space)
		                bError = true;
		        }
		        else if (!bMonth) {
		            bMonth = true;
		            var aArraysToCheck = [{ arr: cultureInfo.AbbreviatedMonthNames, format: "mmm" }, { arr: cultureInfo.MonthNames, format: "mmmm" }];
		            var bFound = false;
		            for (var index in aArraysToCheck) {
		                var aArrayTemp = aArraysToCheck[index];
		                for (var j = 0, length2 = aArrayTemp.arr.length; j < length2; j++) {
		                    var sCmpVal = aArrayTemp.arr[j].toLowerCase();
		                    var sCmpValCrop = sCmpVal.replace(/\./g, "");
		                    var bCrop = false;
		                    if (this.strcmp(valueLower, sCmpVal, i, sCmpVal.length) || (bCrop = (sCmpVal != sCmpValCrop && this.strcmp(valueLower, sCmpValCrop, i, sCmpValCrop.length)))) {
		                        bFound = true;
		                        oNewElem.month = { val: j + 1, format: aArrayTemp.format };
		                        oNewElem.date = true;
		                        if (bCrop)
		                            i += sCmpValCrop.length - 1;
		                        else
		                            i += sCmpVal.length - 1;
		                        break;
		                    }
		                }
		                if (bFound)
		                    break;
		            }
		            //ничего кроме имени месяца больше быть не может
		            if (bFound)
		                match.push(oNewElem);
		            else
		                bError = true;
		        }
		        else
		            bError = true;
		        oCurDataType = null;
		        sCurValue = null;
		    }
			if (bError)
			{
				match = null;
				break;
			}
		}
		if (null != match && null != sCurValue) {
		    if (oDataTypes.space != oCurDataType) {
		        var oNewElem = { val: sCurValue, type: oCurDataType, month: null, am: false, pm: false, date: false, time: false };
		        if (oDataTypes.digit == oCurDataType)
		            oNewElem.val = oNewElem.val - 0;
		        match.push(oNewElem);
		    }
		}
		if(null != match && match.length > 0)
		{
		    var oParsedDate = this._parseDateFromArray(match, oDataTypes, cultureInfo);
			if(null != oParsedDate)
			{
				var d = oParsedDate.d;
				var m = oParsedDate.m;
				var y = oParsedDate.y;
				var h = oParsedDate.h;
				var min = oParsedDate.min;
				var s = oParsedDate.s;
				var am = oParsedDate.am;
				var pm = oParsedDate.pm;
				var sDateFormat = oParsedDate.sDateFormat;
				
				var bDate = false;
				var bTime = false;
				var nDay;
				var nMounth;
				var nYear;
				if(AscCommon.bDate1904)
				{
					nDay = 1;
					nMounth = 0;
					nYear = 1904;
				}
				else
				{
					nDay = 31;
					nMounth = 11;
					nYear = 1899;
				}
				var nHour = 0;
				var nMinute = 0;
				var nSecond = 0;
				var dValue = 0;
				var bValidDate = true;
				if(null != m && (null != d || null != y))
				{
					bDate = true;
					var oNowDate;
					if(null != d)
						nDay = d - 0;
					else
						nDay = 1;
					nMounth = m - 1;
					if(null != y)
						nYear = y - 0;
					else
                    {
                        oNowDate = new Date();
						nYear = oNowDate.getFullYear();
                    }
					
					//проверяем дату на валидность
					bValidDate = this.isValidDate(nYear, nMounth, nDay);
				}
				if(null != h)
				{
					bTime = true;
					nHour = h - 0;
					if (am || pm)
					{
						if(nHour <= 23)
						{
							//переводим 24
							nHour = nHour % 12;
							if(pm)
								nHour += 12;
						}
						else
							bValidDate = false;
					}
					if(null != min)
					{
						nMinute = min - 0;
						if(nMinute > 59)
							bValidDate = false;
					}
					if(null != s)
					{
						nSecond = s - 0;
						if(nSecond > 59)
							bValidDate = false;
					}
				}
				if(true == bValidDate && (true == bDate || true == bTime))
				{
					if(AscCommon.bDate1904)
						dValue = (Date.UTC(nYear,nMounth,nDay,nHour,nMinute,nSecond) - Date.UTC(1904,0,1,0,0,0)) / (86400 * 1000);
					else
					{
						if(1900 < nYear || (1900 == nYear && 1 < nMounth ))
							dValue = (Date.UTC(nYear,nMounth,nDay,nHour,nMinute,nSecond) - Date.UTC(1899,11,30,0,0,0)) / (86400 * 1000);
						else if(1900 == nYear && 1 == nMounth && 29 == nDay)
							dValue = 60;
						else
							dValue = (Date.UTC(nYear,nMounth,nDay,nHour,nMinute,nSecond) - Date.UTC(1899,11,31,0,0,0)) / (86400 * 1000);
					}
					if(dValue >= 0)
					{
						var sFormat;
						if(true == bDate && true == bTime)
						{
							sFormat = sDateFormat + " h:mm:ss";
							if (am || pm)
								sFormat += " AM/PM";
						}
						else if(true == bDate)
							sFormat = sDateFormat;
						else
						{
							if(dValue > 1)
								sFormat = "[h]:mm:ss";
							else if (am || pm)
								sFormat = "h:mm:ss AM/PM";
							else
								sFormat = "h:mm:ss";
						}
						res = {format: sFormat, value: dValue, bDateTime: true, bDate: bDate, bTime: bTime, bPercent: false, bCurrency: false};
					}
				}
            }
        }
		return res;
	},
	isValidDate : function(nYear, nMounth, nDay)
	{
		if(nYear < 1900 && !(1899 === nYear && 11 == nMounth && 31 == nDay))
			return false;
		else
		{
			if(nMounth < 0 || nMounth > 11)
				return false;
			else if(this.isValidDay(nYear, nMounth, nDay))
				return true;
			else if(1900 == nYear && 1 == nMounth && 29 == nDay)
				return true;
		}
		return false;
	},
	isValidDay : function(nYear, nMounth, nDay){
		if(this.isLeapYear(nYear))
		{
			if(nDay <= 0 || nDay > this.daysLeap[nMounth])
				return false;
		}
		else
		{
			if(nDay <= 0 || nDay > this.days[nMounth])
				return false;
		}
		return true;
	},
	isLeapYear : function(year)
	{
		return (0 == (year % 4)) && (0 != (year % 100) || 0 == (year % 400))
	}
};
var g_oFormatParser = new FormatParser();
function escapeRegExp(string) {
    return string.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}
function setCurrentCultureInfo(val) {
    var cultureInfoNew = g_aCultureInfos[val];
    if (!cultureInfoNew || AscCommon.g_oDefaultCultureInfo === cultureInfoNew) {
        return false;
    }
    AscCommon.g_oDefaultCultureInfo = g_oDefaultCultureInfo = cultureInfoNew;
    return true;
}
	function checkCultureInfoFontPicker() {
		var ci = g_oDefaultCultureInfo;
		AscFonts.FontPickerByCharacter.getFontsByString(ci.CurrencySymbol);
		AscFonts.FontPickerByCharacter.getFontsByString(ci.NumberDecimalSeparator);
		AscFonts.FontPickerByCharacter.getFontsByString(ci.NumberGroupSeparator);
		AscFonts.FontPickerByCharacter.getFontsByString(ci.AMDesignator);
		AscFonts.FontPickerByCharacter.getFontsByString(ci.PMDesignator);
		AscFonts.FontPickerByCharacter.getFontsByString(ci.DateSeparator);
		AscFonts.FontPickerByCharacter.getFontsByString(ci.TimeSeparator);
		var arrays = [ci.DayNames, ci.AbbreviatedDayNames, ci.MonthNames, ci.AbbreviatedMonthNames,
			ci.MonthGenitiveNames, ci.AbbreviatedMonthGenitiveNames
		];
		arrays.forEach(function(arr){
			arr.forEach(function(text) {
				AscFonts.FontPickerByCharacter.getFontsByString(text);
			});
		});
	}

	function isDMY(cultureInfo) {
		//day month year
		var res = true;
		for (var i = 0; i < cultureInfo.ShortDatePattern.length - 1; ++i) {
			if (cultureInfo.ShortDatePattern.charCodeAt(i) > cultureInfo.ShortDatePattern.charCodeAt(i + 1)) {
				return false;
			}
		}
		return true;
	}
	function isYMD(cultureInfo) {
		//year month day
		var res = true;
		for (var i = 0; i < cultureInfo.ShortDatePattern.length - 1; ++i) {
			if (cultureInfo.ShortDatePattern.charCodeAt(i) < cultureInfo.ShortDatePattern.charCodeAt(i + 1)) {
				return false;
			}
		}
		return true;
	}
	function getShortDateMonthFormat(bDate, bYear, opt_cultureInfo) {
		var cultureInfo = opt_cultureInfo ? opt_cultureInfo : AscCommon.g_oDefaultCultureInfo;
		var separator;
		if ('/' == AscCommon.g_oDefaultCultureInfo.DateSeparator) {
			separator = '-';
		} else {
			separator = '/';
		}
		var sRes = '';
		if (bDate) {
			if (-1 != cultureInfo.ShortDatePattern.indexOf('1')) {
				sRes += 'dd';
			} else {
				sRes += 'd';
			}
			sRes += separator;
		}
		sRes += 'mmm';
		if (bYear) {
			sRes += separator;
			sRes += 'yy';
		}
		return sRes;
	}
	function getShortDateFormat(opt_cultureInfo) {
		var cultureInfo = opt_cultureInfo ? opt_cultureInfo : AscCommon.g_oDefaultCultureInfo;
		var dateElems = [];
		for (var i = 0; i < cultureInfo.ShortDatePattern.length; ++i) {
			switch (cultureInfo.ShortDatePattern[i]) {
				case '0':
					dateElems.push('d');
					break;
				case '1':
					dateElems.push('dd');
					break;
				case '2':
					dateElems.push('m');
					break;
				case '3':
					dateElems.push('mm');
					break;
				case '4':
					dateElems.push('yy');
					break;
				case '5':
					dateElems.push('yyyy');
					break;
			}
		}
		return dateElems.join('/');
	}

	function getShortDateFormat2(day, month, year, opt_cultureInfo) {
		var cultureInfo = opt_cultureInfo ? opt_cultureInfo : AscCommon.g_oDefaultCultureInfo;
		var dateElems = [];
		for (var i = 0; i < cultureInfo.ShortDatePattern.length; ++i) {
			switch (cultureInfo.ShortDatePattern[i]) {
				case '0':
				case '1':
					if (day > 0) {
						dateElems.push('d'.repeat(day));
					}
					break;
				case '2':
				case '3':
					if (month > 0) {
						dateElems.push('m'.repeat(month));
					}
					break;
				case '4':
				case '5':
					if (year > 0) {
						dateElems.push('y'.repeat(year));
					}
					break;
			}
		}
		return dateElems.join('/');
	}

	function getNumberFormatSimple(opt_separate, opt_fraction) {
		var numberFormat = opt_separate ? '#,##0' : '0';
		if (opt_fraction > 0) {
			numberFormat += '.' + '0'.repeat(opt_fraction);
		}
		return numberFormat;
	}

	function getNumberFormat(opt_cultureInfo, opt_separate, opt_fraction, opt_red) {
		var cultureInfo = opt_cultureInfo ? opt_cultureInfo : AscCommon.g_oDefaultCultureInfo;
		var numberFormat = getNumberFormatSimple(opt_separate, opt_fraction);
		var red = opt_red ? '[Red]' : '';

		var positiveFormat;
		var negativeFormat;
		switch (cultureInfo.CurrencyNegativePattern) {
			case 0:
			case 4:
			case 14:
			case 15:
				positiveFormat = numberFormat + '_)';
				negativeFormat = '\\(' + numberFormat + '\\)';
				break;
			default:
				positiveFormat = numberFormat + '_ ';
				negativeFormat = '\\-' + numberFormat + '\\ ';
				break;
		}
		return positiveFormat + ';' + red + negativeFormat;
	}

	function getLocaleFormat(opt_cultureInfo, opt_currency) {
		var cultureInfo = opt_cultureInfo ? opt_cultureInfo : AscCommon.g_oDefaultCultureInfo;
		var symbol = opt_currency ? cultureInfo.CurrencySymbol : '';
		return '[$' + symbol + '-' + cultureInfo.LCID.toString(16).toUpperCase() + ']';
	}

	function getCurrencyFormatSimple(opt_cultureInfo, opt_fraction, opt_currency, opt_currencyLocale, opt_red) {
		var cultureInfo = opt_cultureInfo ? opt_cultureInfo : AscCommon.g_oDefaultCultureInfo;
		var numberFormat = getNumberFormatSimple(true, opt_fraction);
		var signCurrencyFormat;
		var signCurrencyFormatEnd;
		var signCurrencyFormatSpace;
		if (opt_currency) {
			if (opt_currencyLocale) {
				signCurrencyFormat = getLocaleFormat(cultureInfo, true);
			} else {
				signCurrencyFormat = '"' + cultureInfo.CurrencySymbol + '"';
			}
			signCurrencyFormatEnd = signCurrencyFormat;
			signCurrencyFormatSpace = signCurrencyFormat + '\\ ';
		} else {
			signCurrencyFormatEnd = signCurrencyFormat = signCurrencyFormatSpace = '';
			for (var i = 0; i < cultureInfo.CurrencySymbol.length; ++i) {
				signCurrencyFormatEnd += '_' + cultureInfo.CurrencySymbol[i];
			}
		}
		var red = opt_red ? '[Red]' : '';

		var prefixs = ['_ ', '_-', '_(', '_)'];
		var postfix = '';
		var positiveFormat;
		var negativeFormat;
		switch (cultureInfo.CurrencyNegativePattern) {
			case 0:
				postfix = prefixs[3];
				negativeFormat = '\\(' + signCurrencyFormat + numberFormat + '\\)';
				break;
			case 1:
				negativeFormat = '\\-' + signCurrencyFormat + numberFormat;
				break;
			case 2:
				negativeFormat = signCurrencyFormatSpace + '\\-' + numberFormat;
				break;
			case 3:
				postfix = prefixs[1];
				negativeFormat = signCurrencyFormatSpace + numberFormat + '\\-';
				break;
			case 4:
				postfix = prefixs[3];
				negativeFormat = '\\(' + numberFormat + signCurrencyFormatEnd + '\\)';
				break;
			case 5:
				negativeFormat = '\\-' + numberFormat + signCurrencyFormatEnd;
				break;
			case 6:
				negativeFormat = numberFormat + '\\-' + signCurrencyFormatEnd;
				break;
			case 7:
				postfix = prefixs[1];
				negativeFormat = numberFormat + signCurrencyFormatEnd + '\\-';
				break;
			case 8:
				negativeFormat = '\\-' + numberFormat + '\\ ' + signCurrencyFormatEnd;
				break;
			case 9:
				negativeFormat = '\\-' + signCurrencyFormatSpace + numberFormat;
				break;
			case 10:
				postfix = prefixs[1];
				negativeFormat = numberFormat + '\\ ' + signCurrencyFormatEnd + '\\-';
				break;
			case 11:
				postfix = prefixs[1];
				negativeFormat = signCurrencyFormatSpace + numberFormat + '\\-';
				break;
			case 12:
				negativeFormat = signCurrencyFormatSpace + '\\-' + numberFormat;
				break;
			case 13:
				negativeFormat = numberFormat + '\\-\\ ' + signCurrencyFormatEnd;
				break;
			case 14:
				postfix = prefixs[3];
				negativeFormat = '(' + signCurrencyFormat + numberFormat + '\\)';
				break;
			case 15:
				postfix = prefixs[3];
				negativeFormat = '\\(' + numberFormat + signCurrencyFormatEnd + '\\)';
				break;
		}
		switch (cultureInfo.CurrencyPositivePattern) {
			case 0:
				positiveFormat = signCurrencyFormat + numberFormat;
				break;
			case 1:
				positiveFormat = numberFormat + signCurrencyFormatEnd;
				break;
			case 2:
				positiveFormat = signCurrencyFormatSpace + numberFormat;
				break;
			case 3:
				positiveFormat = numberFormat + '\\ ' + signCurrencyFormatEnd;
				break;
		}
		positiveFormat = positiveFormat + postfix;
		return positiveFormat + ';' + red + negativeFormat;
	}

	function getCurrencyFormatSimple2(opt_cultureInfo, opt_fraction, opt_currency, opt_negative) {
		var cultureInfo = opt_cultureInfo ? opt_cultureInfo : AscCommon.g_oDefaultCultureInfo;
		var numberFormat = getNumberFormatSimple(true, opt_fraction);
		var signCurrencyFormat;
		var signCurrencyFormatEnd;
		var signCurrencyFormatSpace;
		if (opt_currency) {
			signCurrencyFormat = signCurrencyFormatEnd = getLocaleFormat(cultureInfo, true);
			signCurrencyFormatSpace = signCurrencyFormat + '\\ ';
		} else {
			signCurrencyFormatEnd = signCurrencyFormat = signCurrencyFormatSpace = '';
			for (var i = 0; i < cultureInfo.CurrencySymbol.length; ++i) {
				signCurrencyFormatEnd += '_' + cultureInfo.CurrencySymbol[i];
			}
		}
		var positiveFormat;
		switch (cultureInfo.CurrencyNegativePattern) {
			case 0:
			case 1:
			case 14:
				positiveFormat = signCurrencyFormat + numberFormat;
				break;
			case 2:
			case 3:
			case 9:
			case 10:
			case 11:
			case 12:
				positiveFormat = signCurrencyFormatSpace + numberFormat;
				break;
			case 4:
			case 5:
			case 6:
			case 7:
			case 15:
				positiveFormat = numberFormat + signCurrencyFormatEnd;
				break;
			case 8:
			case 13:
				positiveFormat = numberFormat + '\\ ' + signCurrencyFormatEnd;
				break;
		}
		return opt_negative ? positiveFormat + ';[Red]' + positiveFormat : positiveFormat;
	}

	function getCurrencyFormat(opt_cultureInfo, opt_fraction, opt_currency, opt_currencyLocale) {
		var cultureInfo = opt_cultureInfo ? opt_cultureInfo : AscCommon.g_oDefaultCultureInfo;
		var numberFormat = getNumberFormatSimple(true, opt_fraction);
		var nullSignFormat = '* "-"';
		if (opt_fraction) {
			nullSignFormat += '?'.repeat(opt_fraction);
		}
		var signCurrencyFormat;
		var signCurrencyFormatEnd;
		var signCurrencyFormatSpace;
		if (opt_currency) {
			if (opt_currencyLocale) {
				signCurrencyFormat = getLocaleFormat(cultureInfo, true);
			} else {
				signCurrencyFormat = '"' + cultureInfo.CurrencySymbol + '"';
			}
			signCurrencyFormatEnd = signCurrencyFormat;
			signCurrencyFormatSpace = signCurrencyFormat + '\\ ';
		} else {
			signCurrencyFormatEnd = signCurrencyFormat = signCurrencyFormatSpace = '';
			for (var i = 0; i < cultureInfo.CurrencySymbol.length; ++i) {
				signCurrencyFormatEnd += '_' + cultureInfo.CurrencySymbol[i];
			}
		}

		var prefixs = ['_ ', '_-', '_(', '_)'];
		var prefix = prefixs[0];
		var postfix = prefixs[0];
		var positiveNumberFormat = '* ' + numberFormat;
		var positiveFormat;
		var negativeFormat;
		var nullFormat;
		switch (cultureInfo.CurrencyNegativePattern) {
			case 0:
				prefix = prefixs[2];
				postfix = prefixs[3];
				negativeFormat = prefix + signCurrencyFormat + '* \\(' + numberFormat + '\\)';
				break;
			case 1:
				prefix = postfix = prefixs[1];
				negativeFormat = '\\-' + signCurrencyFormat + '* ' + numberFormat + postfix;
				break;
			case 2:
				negativeFormat = prefix + signCurrencyFormatSpace + '* \\-' + numberFormat + postfix;
				break;
			case 3:
				prefix = postfix = prefixs[1];
				negativeFormat = prefix + signCurrencyFormatSpace + '* ' + numberFormat + '\\-';
				break;
			case 4:
				prefix = prefixs[2];
				postfix = prefixs[3];
				negativeFormat = prefix + '* \\(' + numberFormat + '\\)' + signCurrencyFormatEnd + postfix;
				break;
			case 5:
				prefix = postfix = prefixs[1];
				negativeFormat = '\\-* ' + numberFormat + signCurrencyFormatEnd + postfix;
				break;
			case 6:
				negativeFormat = prefix + '* ' + numberFormat + '\\-' + signCurrencyFormatEnd + postfix;
				break;
			case 7:
				negativeFormat = prefix + '* ' + numberFormat + signCurrencyFormatEnd + '\\-';
				break;
			case 8:
				prefix = postfix = prefixs[1];
				negativeFormat = '\\-* ' + numberFormat + '\\ ' + signCurrencyFormatEnd + postfix;
				break;
			case 9:
				prefix = postfix = prefixs[1];
				negativeFormat = '\\-' + signCurrencyFormatSpace + '* ' + numberFormat + postfix;
				break;
			case 10:
				negativeFormat = prefix + '* ' + numberFormat + '\\ ' + signCurrencyFormatEnd + '\\-';
				break;
			case 11:
				negativeFormat = prefix + signCurrencyFormatSpace + '* ' + numberFormat + '\\-';
				break;
			case 12:
				negativeFormat = prefix + signCurrencyFormatSpace + '* \\-' + numberFormat + postfix;
				break;
			case 13:
				negativeFormat = prefix + '* ' + numberFormat + '\\-\\ ' + signCurrencyFormatEnd + postfix;
				break;
			case 14:
				prefix = prefixs[2];
				postfix = prefixs[3];
				negativeFormat = prefix + signCurrencyFormatSpace + '* \\(' + numberFormat + '\\)';
				break;
			case 15:
				prefix = prefixs[2];
				postfix = prefixs[3];
				negativeFormat = prefix + '* \\(' + numberFormat + '\\)\\ ' + signCurrencyFormatEnd + postfix;
				break;
		}
		switch (cultureInfo.CurrencyPositivePattern) {
			case 0:
				positiveFormat = signCurrencyFormat + positiveNumberFormat;
				nullFormat = signCurrencyFormat + nullSignFormat;
				break;
			case 1:
				positiveFormat = positiveNumberFormat + signCurrencyFormatEnd;
				nullFormat = nullSignFormat + signCurrencyFormatEnd;
				break;
			case 2:
				positiveFormat = signCurrencyFormatSpace + positiveNumberFormat;
				nullFormat = signCurrencyFormatSpace + nullSignFormat;
				break;
			case 3:
				positiveFormat = positiveNumberFormat + '\\ ' + signCurrencyFormatEnd;
				nullFormat = nullSignFormat + '\\ ' + signCurrencyFormatEnd;
				break;
		}
		positiveFormat = prefix + positiveFormat + postfix;
		nullFormat = prefix + nullFormat + postfix;
		var textFormat = prefix + '@' + postfix;
		return positiveFormat + ';' + negativeFormat + ';' + nullFormat + ';' + textFormat;
	}

	function getFormatCells(info) {
		var res = [];
		if (info) {
			var format;
			var i;
			var cultureInfo = g_aCultureInfos[info.symbol];
			var currency = !!cultureInfo;
			if (Asc.c_oAscNumFormatType.General === info.type) {
				res.push(AscCommon.g_cGeneralFormat);
			} else if (Asc.c_oAscNumFormatType.Number === info.type) {
				var numberFormat = getNumberFormatSimple(info.separator, info.decimalPlaces);
				res.push(numberFormat);
				res.push(numberFormat + ';[Red]' + numberFormat);
				res.push(getNumberFormat(cultureInfo, info.separator, info.decimalPlaces, false));
				res.push(getNumberFormat(cultureInfo, info.separator, info.decimalPlaces, true));
			} else if (Asc.c_oAscNumFormatType.Currency === info.type) {
				res.push(getCurrencyFormatSimple2(cultureInfo, info.decimalPlaces, currency, false));
				res.push(getCurrencyFormatSimple2(cultureInfo, info.decimalPlaces, currency, true));
				res.push(getCurrencyFormatSimple(cultureInfo, info.decimalPlaces, currency, currency, false));
				res.push(getCurrencyFormatSimple(cultureInfo, info.decimalPlaces, currency, currency, true));
			} else if (Asc.c_oAscNumFormatType.Accounting === info.type) {
				res.push(getCurrencyFormat(cultureInfo, info.decimalPlaces, currency, currency));
			} else if (Asc.c_oAscNumFormatType.Date === info.type) {
				//todo locale dependence
				if (info.symbol == g_oDefaultCultureInfo.LCID) {
					res.push(getShortDateFormat(cultureInfo));
					res.push('[$-F800]dddd, mmmm dd, yyyy');
				}
				res.push(getShortDateFormat2(1, 1, 0, cultureInfo) + ';@');
				res.push(getShortDateFormat2(1, 1, 2, cultureInfo) + ';@');
				res.push(getShortDateFormat2(2, 2, 2, cultureInfo) + ';@');
				res.push(getShortDateFormat2(1, 1, 4, cultureInfo) + ';@');
				res.push(getShortDateFormat2(1, 1, 2, cultureInfo) + ' h:mm;@');
				res.push('[$-409]' + getShortDateFormat2(1, 1, 2, cultureInfo) + ' h:mm AM/PM;@');
				var locale = getLocaleFormat(cultureInfo, false);
				res.push(locale + 'mmmmm;@');
				res.push(locale + 'mmmm d, yyyy;@');
				var separators = ['-', '/', ' '];
				for (i = 0; i < separators.length; ++i) {
					var separator = separators[i];
					res.push(locale + 'd' + separator + 'mmm;@');
					res.push(locale + 'd' + separator + 'mmm' + separator + 'yy;@');
					res.push(locale + 'dd' + separator + 'mmm' + separator + 'yy;@');
					res.push(locale + 'mmm' + separator + 'yy;@');
					res.push(locale + 'mmmm' + separator + 'yy;@');
					res.push(locale + 'mmmmm' + separator + 'yy;@');
					res.push(locale + 'yy' + separator + 'mmm;@');
					res.push(locale + 'd' + separator + 'mmm' + separator + 'yyyy;@');
					res.push(locale + 'yyyy' + separator + 'mmm' + separator + 'd;@');
					res.push(locale + 'yy' + separator + 'mmm' + separator + 'd;@');
				}
				res.push('yy/m/d;@');
				res.push('yy/mm/dd;@');
				res.push('yyyy/m/d;@');
			} else if (Asc.c_oAscNumFormatType.Time === info.type) {
				res = gc_aTimeFormats;
			} else if (Asc.c_oAscNumFormatType.Percent === info.type) {
				format = '0';
				if (info.decimalPlaces > 0) {
					format += '.' + '0'.repeat(info.decimalPlaces);
				}
				format += '%';
				res.push(format);
			} else if (Asc.c_oAscNumFormatType.Fraction === info.type) {
				res = gc_aFractionFormats;
			} else if (Asc.c_oAscNumFormatType.Scientific === info.type) {
				format = '0.' + '0'.repeat(info.decimalPlaces) + 'E+00';
				res.push(format);
			} else if (Asc.c_oAscNumFormatType.Text === info.type) {
				res.push('@');
			} else if (Asc.c_oAscNumFormatType.Custom === info.type) {
				for (i = 0; i <= 4; ++i) {
					res.push(AscCommonExcel.aStandartNumFormats[i]);
				}
				res.push(getCurrencyFormatSimple(null, 0, false, false, false));
				res.push(getCurrencyFormatSimple(null, 0, false, false, true));
				res.push(getCurrencyFormatSimple(null, 2, false, false, false));
				res.push(getCurrencyFormatSimple(null, 2, false, false, true));
				res.push(getCurrencyFormatSimple(null, 0, true, false, false));
				res.push(getCurrencyFormatSimple(null, 0, true, false, true));
				res.push(getCurrencyFormatSimple(null, 2, true, false, false));
				res.push(getCurrencyFormatSimple(null, 2, true, false, true));
				for (i = 9; i <= 13; ++i) {
					res.push(AscCommonExcel.aStandartNumFormats[i]);
				}
				res.push(getShortDateFormat(null));
				res.push(getShortDateMonthFormat(true, true, null));
				res.push(getShortDateMonthFormat(true, false, null));
				res.push(getShortDateMonthFormat(false, true, null));
				for (i = 18; i <= 21; ++i) {
					res.push(AscCommonExcel.aStandartNumFormats[i]);
				}
				res.push(getShortDateFormat(null) + " h:mm");
				for (i = 45; i <= 49; ++i) {
					res.push(AscCommonExcel.aStandartNumFormats[i]);
				}
				res.push(AscCommon.getCurrencyFormat(null, 0, true, false));
				res.push(AscCommon.getCurrencyFormat(null, 0, false, false));
				res.push(AscCommon.getCurrencyFormat(null, 2, true, false));
				res.push(AscCommon.getCurrencyFormat(null, 2, false, false));
				//todo add all used in workbook formats
			} else {
				res.push(AscCommon.g_cGeneralFormat);
				res.push('0.00');
				res.push('0.00E+00');
				res.push(getCurrencyFormat(cultureInfo, 2, currency, true));
				res.push(getCurrencyFormatSimple2(cultureInfo, 2, currency, false));
				res.push(getShortDateFormat(cultureInfo));
				//todo F400
				res.push('[$-F400]h:mm:ss AM/PM');
				res.push('0.00%');
				res.push('# ?/?');
				res.push('@');
			}
		}
		return res;
	}
	function getFormatByStandardId(id) {
		var res = null;
		if (15 <= id && id <= 17) {
			switch (id) {
				case 15:
					res = AscCommon.getShortDateMonthFormat(true, true, null);
					break;
				case 16:
					res = AscCommon.getShortDateMonthFormat(true, false, null);
					break;
				case 17:
					res = AscCommon.getShortDateMonthFormat(false, true, null);
					break;
			}
		} else {
			//todo currencyLocale true/false?
			var currencyLocale = true;
			switch (id) {
				case 5:
					res = AscCommon.getCurrencyFormatSimple(null, 0, true, currencyLocale, false);
					break;
				case 6:
					res = AscCommon.getCurrencyFormatSimple(null, 0, true, currencyLocale, true);
					break;
				case 7:
					res = AscCommon.getCurrencyFormatSimple(null, 2, true, currencyLocale, false);
					break;
				case 8:
					res = AscCommon.getCurrencyFormatSimple(null, 2, true, currencyLocale, true);
					break;
				case 14:
					res = AscCommon.getShortDateFormat(null);
					break;
				case 22:
					res = AscCommon.getShortDateFormat(null) + " h:mm";
					break;
				case 27:
				case 28:
				case 29:
				case 30:
				case 31:
				case 36:
					res = AscCommon.getShortDateFormat(null);
					break;
				case 37:
					res = AscCommon.getCurrencyFormatSimple(null, 0, false, currencyLocale, false);
					break;
				case 38:
					res = AscCommon.getCurrencyFormatSimple(null, 0, false, currencyLocale, true);
					break;
				case 39:
					res = AscCommon.getCurrencyFormatSimple(null, 2, false, currencyLocale, false);
					break;
				case 40:
					res = AscCommon.getCurrencyFormatSimple(null, 2, false, currencyLocale, true);
					break;
				case 41:
					res = AscCommon.getCurrencyFormat(null, 0, false, currencyLocale);
					break;
				case 42:
					res = AscCommon.getCurrencyFormat(null, 0, true, currencyLocale);
					break;
				case 43:
					res = AscCommon.getCurrencyFormat(null, 2, false, currencyLocale);
					break;
				case 44:
					res = AscCommon.getCurrencyFormat(null, 2, true, currencyLocale);
					break;
                default:
                    res = AscCommonExcel.aStandartNumFormats[id];
                    break;
			}
		}
		return res;
	}

var g_aCultureInfos = {
	4: {LCID: 4, Name: "zh-Hans", CurrencyPositivePattern: 0, CurrencyNegativePattern: 2, CurrencySymbol: "¥", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"], AbbreviatedDayNames: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"], MonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月", ""], AbbreviatedMonthNames: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "上午", PMDesignator: "下午", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "520"},
	5: {LCID: 5, Name: "cs", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "Kč", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["neděle", "pondělí", "úterý", "středa", "čtvrtek", "pátek", "sobota"], AbbreviatedDayNames: ["ne", "po", "út", "st", "čt", "pá", "so"], MonthNames: ["leden", "únor", "březen", "duben", "květen", "červen", "červenec", "srpen", "září", "říjen", "listopad", "prosinec", ""], AbbreviatedMonthNames: ["led", "úno", "bře", "dub", "kvě", "čvn", "čvc", "srp", "zář", "říj", "lis", "pro", ""], MonthGenitiveNames: ["ledna", "února", "března", "dubna", "května", "června", "července", "srpna", "září", "října", "listopadu", "prosince", ""], AbbreviatedMonthGenitiveNames: [], AMDesignator: "dop.", PMDesignator: "odp.", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	7: {LCID: 7, Name: "de", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"], AbbreviatedDayNames: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"], MonthNames: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "", PMDesignator: "", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	8: {LCID: 8, Name: "el", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο"], AbbreviatedDayNames: ["Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ"], MonthNames: ["Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος", ""], AbbreviatedMonthNames: ["Ιαν", "Φεβ", "Μαρ", "Απρ", "Μαϊ", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ", ""], MonthGenitiveNames: ["Ιανουαρίου", "Φεβρουαρίου", "Μαρτίου", "Απριλίου", "Μαΐου", "Ιουνίου", "Ιουλίου", "Αυγούστου", "Σεπτεμβρίου", "Οκτωβρίου", "Νοεμβρίου", "Δεκεμβρίου", ""], AbbreviatedMonthGenitiveNames: [], AMDesignator: "πμ", PMDesignator: "μμ", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	9: {LCID: 9, Name: "en", CurrencyPositivePattern: 0, CurrencyNegativePattern: 0, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "205"},
	10: {LCID: 10, Name: "es", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["do.", "lu.", "ma.", "mi.", "ju.", "vi.", "sá."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "", PMDesignator: "", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	11: {LCID: 11, Name: "fi", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai"], AbbreviatedDayNames: ["su", "ma", "ti", "ke", "to", "pe", "la"], MonthNames: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu", ""], AbbreviatedMonthNames: ["tammi", "helmi", "maalis", "huhti", "touko", "kesä", "heinä", "elo", "syys", "loka", "marras", "joulu", ""], MonthGenitiveNames: ["tammikuuta", "helmikuuta", "maaliskuuta", "huhtikuuta", "toukokuuta", "kesäkuuta", "heinäkuuta", "elokuuta", "syyskuuta", "lokakuuta", "marraskuuta", "joulukuuta", ""], AbbreviatedMonthGenitiveNames: ["tammik.", "helmik.", "maalisk.", "huhtik.", "toukok.", "kesäk.", "heinäk.", "elok.", "syysk.", "lokak.", "marrask.", "jouluk.", ""], AMDesignator: "ap.", PMDesignator: "ip.", DateSeparator: ".", TimeSeparator: ".", ShortDatePattern: "025"},
	12: {LCID: 12, Name: "fr", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], AbbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], MonthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre", ""], AbbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "", PMDesignator: "", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	16: {LCID: 16, Name: "it", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["domenica", "lunedì", "martedì", "mercoledì", "giovedì", "venerdì", "sabato"], AbbreviatedDayNames: ["dom", "lun", "mar", "mer", "gio", "ven", "sab"], MonthNames: ["gennaio", "febbraio", "marzo", "aprile", "maggio", "giugno", "luglio", "agosto", "settembre", "ottobre", "novembre", "dicembre", ""], AbbreviatedMonthNames: ["gen", "feb", "mar", "apr", "mag", "giu", "lug", "ago", "set", "ott", "nov", "dic", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "", PMDesignator: "", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	17: {LCID: 17, Name: "ja", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "¥", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"], AbbreviatedDayNames: ["日", "月", "火", "水", "木", "金", "土"], MonthNames: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月", ""], AbbreviatedMonthNames: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "午前", PMDesignator: "午後", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "531"},
	18: {LCID: 18, Name: "ko", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "₩", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"], AbbreviatedDayNames: ["일", "월", "화", "수", "목", "금", "토"], MonthNames: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월", ""], AbbreviatedMonthNames: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "오전", PMDesignator: "오후", DateSeparator: "-", TimeSeparator: ":", ShortDatePattern: "531"},
	21: {LCID: 21, Name: "pl", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "zł", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["niedziela", "poniedziałek", "wtorek", "środa", "czwartek", "piątek", "sobota"], AbbreviatedDayNames: ["niedz.", "pon.", "wt.", "śr.", "czw.", "pt.", "sob."], MonthNames: ["styczeń", "luty", "marzec", "kwiecień", "maj", "czerwiec", "lipiec", "sierpień", "wrzesień", "październik", "listopad", "grudzień", ""], AbbreviatedMonthNames: ["sty", "lut", "mar", "kwi", "maj", "cze", "lip", "sie", "wrz", "paź", "lis", "gru", ""], MonthGenitiveNames: ["stycznia", "lutego", "marca", "kwietnia", "maja", "czerwca", "lipca", "sierpnia", "września", "października", "listopada", "grudnia", ""], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	22: {LCID: 22, Name: "pt", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "R$", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["domingo", "segunda-feira", "terça-feira", "quarta-feira", "quinta-feira", "sexta-feira", "sábado"], AbbreviatedDayNames: ["dom", "seg", "ter", "qua", "qui", "sex", "sáb"], MonthNames: ["janeiro", "fevereiro", "março", "abril", "maio", "junho", "julho", "agosto", "setembro", "outubro", "novembro", "dezembro", ""], AbbreviatedMonthNames: ["jan", "fev", "mar", "abr", "mai", "jun", "jul", "ago", "set", "out", "nov", "dez", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "", PMDesignator: "", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	25: {LCID: 25, Name: "ru", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "₽", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["воскресенье", "понедельник", "вторник", "среда", "четверг", "пятница", "суббота"], AbbreviatedDayNames: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"], MonthNames: ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь", ""], AbbreviatedMonthNames: ["янв", "фев", "мар", "апр", "май", "июн", "июл", "авг", "сен", "окт", "ноя", "дек", ""], MonthGenitiveNames: ["января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря", ""], AbbreviatedMonthGenitiveNames: ["янв", "фев", "мар", "апр", "мая", "июн", "июл", "авг", "сен", "окт", "ноя", "дек", ""], AMDesignator: "", PMDesignator: "", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	31: {LCID: 31, Name: "tr", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "₺", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi"], AbbreviatedDayNames: ["Paz", "Pzt", "Sal", "Çar", "Per", "Cum", "Cmt"], MonthNames: ["Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık", ""], AbbreviatedMonthNames: ["Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "ÖÖ", PMDesignator: "ÖS", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "035"},
	34: {LCID: 34, Name: "uk", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "₴", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["неділя", "понеділок", "вівторок", "середа", "четвер", "п'ятниця", "субота"], AbbreviatedDayNames: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"], MonthNames: ["січень", "лютий", "березень", "квітень", "травень", "червень", "липень", "серпень", "вересень", "жовтень", "листопад", "грудень", ""], AbbreviatedMonthNames: ["Січ", "Лют", "Бер", "Кві", "Тра", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Гру", ""], MonthGenitiveNames: ["січня", "лютого", "березня", "квітня", "травня", "червня", "липня", "серпня", "вересня", "жовтня", "листопада", "грудня", ""], AbbreviatedMonthGenitiveNames: ["січ", "лют", "бер", "кві", "тра", "чер", "лип", "сер", "вер", "жов", "лис", "гру", ""], AMDesignator: "", PMDesignator: "", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	36: {LCID: 36, Name: "sl", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["nedelja", "ponedeljek", "torek", "sreda", "četrtek", "petek", "sobota"], AbbreviatedDayNames: ["ned.", "pon.", "tor.", "sre.", "čet.", "pet.", "sob."], MonthNames: ["januar", "februar", "marec", "april", "maj", "junij", "julij", "avgust", "september", "oktober", "november", "december", ""], AbbreviatedMonthNames: ["jan.", "feb.", "mar.", "apr.", "maj", "jun.", "jul.", "avg.", "sep.", "okt.", "nov.", "dec.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "dop.", PMDesignator: "pop.", DateSeparator: ". ", TimeSeparator: ":", ShortDatePattern: "035"},
	38: {LCID: 38, Name: "lv", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["svētdiena", "pirmdiena", "otrdiena", "trešdiena", "ceturtdiena", "piektdiena", "sestdiena"], AbbreviatedDayNames: ["svētd.", "pirmd.", "otrd.", "trešd.", "ceturtd.", "piektd.", "sestd."], MonthNames: ["janvāris", "februāris", "marts", "aprīlis", "maijs", "jūnijs", "jūlijs", "augusts", "septembris", "oktobris", "novembris", "decembris", ""], AbbreviatedMonthNames: ["janv.", "febr.", "marts", "apr.", "maijs", "jūn.", "jūl.", "aug.", "sept.", "okt.", "nov.", "dec.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "priekšp.", PMDesignator: "pēcp.", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	42: {LCID: 42, Name: "vi", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "₫", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["Chủ Nhật", "Thứ Hai", "Thứ Ba", "Thứ Tư", "Thứ Năm", "Thứ Sáu", "Thứ Bảy"], AbbreviatedDayNames: ["CN", "T2", "T3", "T4", "T5", "T6", "T7"], MonthNames: ["Tháng Giêng", "Tháng Hai", "Tháng Ba", "Tháng Tư", "Tháng Năm", "Tháng Sáu", "Tháng Bảy", "Tháng Tám", "Tháng Chín", "Tháng Mười", "Tháng Mười Một", "Tháng Mười Hai", ""], AbbreviatedMonthNames: ["Thg1", "Thg2", "Thg3", "Thg4", "Thg5", "Thg6", "Thg7", "Thg8", "Thg9", "Thg10", "Thg11", "Thg12", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "SA", PMDesignator: "CH", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	44: {LCID: 44, Name: "az", CurrencyPositivePattern: 2, CurrencyNegativePattern: 9, CurrencySymbol: "₼", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["bazar", "bazar ertəsi", "çərşənbə axşamı", "çərşənbə", "cümə axşamı", "cümə", "şənbə"], AbbreviatedDayNames: ["B.", "B.E.", "Ç.A.", "Ç.", "C.A.", "C.", "Ş."], MonthNames: ["Yanvar", "Fevral", "Mart", "Aprel", "May", "İyun", "İyul", "Avqust", "Sentyabr", "Oktyabr", "Noyabr", "Dekabr", ""], AbbreviatedMonthNames: ["yan", "fev", "mar", "apr", "may", "iyn", "iyl", "avq", "sen", "okt", "noy", "dek", ""], MonthGenitiveNames: ["yanvar", "fevral", "mart", "aprel", "may", "iyun", "iyul", "avqust", "sentyabr", "oktyabr", "noyabr", "dekabr", ""], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	1028: {LCID: 1028, Name: "zh-TW", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "NT$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"], AbbreviatedDayNames: ["週日", "週一", "週二", "週三", "週四", "週五", "週六"], MonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月", ""], AbbreviatedMonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "上午", PMDesignator: "下午", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "520"},
	1029: {LCID: 1029, Name: "cs-CZ", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "Kč", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["neděle", "pondělí", "úterý", "středa", "čtvrtek", "pátek", "sobota"], AbbreviatedDayNames: ["ne", "po", "út", "st", "čt", "pá", "so"], MonthNames: ["leden", "únor", "březen", "duben", "květen", "červen", "červenec", "srpen", "září", "říjen", "listopad", "prosinec", ""], AbbreviatedMonthNames: ["led", "úno", "bře", "dub", "kvě", "čvn", "čvc", "srp", "zář", "říj", "lis", "pro", ""], MonthGenitiveNames: ["ledna", "února", "března", "dubna", "května", "června", "července", "srpna", "září", "října", "listopadu", "prosince", ""], AbbreviatedMonthGenitiveNames: [], AMDesignator: "dop.", PMDesignator: "odp.", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	1031: {LCID: 1031, Name: "de-DE", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"], AbbreviatedDayNames: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"], MonthNames: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "", PMDesignator: "", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	1032: {LCID: 1032, Name: "el-GR", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο"], AbbreviatedDayNames: ["Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ"], MonthNames: ["Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος", ""], AbbreviatedMonthNames: ["Ιαν", "Φεβ", "Μαρ", "Απρ", "Μαϊ", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ", ""], MonthGenitiveNames: ["Ιανουαρίου", "Φεβρουαρίου", "Μαρτίου", "Απριλίου", "Μαΐου", "Ιουνίου", "Ιουλίου", "Αυγούστου", "Σεπτεμβρίου", "Οκτωβρίου", "Νοεμβρίου", "Δεκεμβρίου", ""], AbbreviatedMonthGenitiveNames: [], AMDesignator: "πμ", PMDesignator: "μμ", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	1033: {LCID: 1033, Name: "en-US", CurrencyPositivePattern: 0, CurrencyNegativePattern: 0, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "205"},
	1035: {LCID: 1035, Name: "fi-FI", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai"], AbbreviatedDayNames: ["su", "ma", "ti", "ke", "to", "pe", "la"], MonthNames: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu", ""], AbbreviatedMonthNames: ["tammi", "helmi", "maalis", "huhti", "touko", "kesä", "heinä", "elo", "syys", "loka", "marras", "joulu", ""], MonthGenitiveNames: ["tammikuuta", "helmikuuta", "maaliskuuta", "huhtikuuta", "toukokuuta", "kesäkuuta", "heinäkuuta", "elokuuta", "syyskuuta", "lokakuuta", "marraskuuta", "joulukuuta", ""], AbbreviatedMonthGenitiveNames: ["tammik.", "helmik.", "maalisk.", "huhtik.", "toukok.", "kesäk.", "heinäk.", "elok.", "syysk.", "lokak.", "marrask.", "jouluk.", ""], AMDesignator: "ap.", PMDesignator: "ip.", DateSeparator: ".", TimeSeparator: ".", ShortDatePattern: "025"},
	1036: {LCID: 1036, Name: "fr-FR", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], AbbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], MonthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre", ""], AbbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "", PMDesignator: "", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	1040: {LCID: 1040, Name: "it-IT", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["domenica", "lunedì", "martedì", "mercoledì", "giovedì", "venerdì", "sabato"], AbbreviatedDayNames: ["dom", "lun", "mar", "mer", "gio", "ven", "sab"], MonthNames: ["gennaio", "febbraio", "marzo", "aprile", "maggio", "giugno", "luglio", "agosto", "settembre", "ottobre", "novembre", "dicembre", ""], AbbreviatedMonthNames: ["gen", "feb", "mar", "apr", "mag", "giu", "lug", "ago", "set", "ott", "nov", "dic", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "", PMDesignator: "", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	1041: {LCID: 1041, Name: "ja-JP", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "¥", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"], AbbreviatedDayNames: ["日", "月", "火", "水", "木", "金", "土"], MonthNames: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月", ""], AbbreviatedMonthNames: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "午前", PMDesignator: "午後", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "531"},
	1042: {LCID: 1042, Name: "ko-KR", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "₩", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"], AbbreviatedDayNames: ["일", "월", "화", "수", "목", "금", "토"], MonthNames: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월", ""], AbbreviatedMonthNames: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "오전", PMDesignator: "오후", DateSeparator: "-", TimeSeparator: ":", ShortDatePattern: "531"},
	1043: {LCID: 1043, Name: "nl-NL", CurrencyPositivePattern: 2, CurrencyNegativePattern: 12, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"], AbbreviatedDayNames: ["zo", "ma", "di", "wo", "do", "vr", "za"], MonthNames: ["januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december", ""], AbbreviatedMonthNames: ["jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "", PMDesignator: "", DateSeparator: "-", TimeSeparator: ":", ShortDatePattern: "025"},
	1045: {LCID: 1045, Name: "pl-PL", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "zł", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["niedziela", "poniedziałek", "wtorek", "środa", "czwartek", "piątek", "sobota"], AbbreviatedDayNames: ["niedz.", "pon.", "wt.", "śr.", "czw.", "pt.", "sob."], MonthNames: ["styczeń", "luty", "marzec", "kwiecień", "maj", "czerwiec", "lipiec", "sierpień", "wrzesień", "październik", "listopad", "grudzień", ""], AbbreviatedMonthNames: ["sty", "lut", "mar", "kwi", "maj", "cze", "lip", "sie", "wrz", "paź", "lis", "gru", ""], MonthGenitiveNames: ["stycznia", "lutego", "marca", "kwietnia", "maja", "czerwca", "lipca", "sierpnia", "września", "października", "listopada", "grudnia", ""], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	1046: {LCID: 1046, Name: "pt-BR", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "R$", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["domingo", "segunda-feira", "terça-feira", "quarta-feira", "quinta-feira", "sexta-feira", "sábado"], AbbreviatedDayNames: ["dom", "seg", "ter", "qua", "qui", "sex", "sáb"], MonthNames: ["janeiro", "fevereiro", "março", "abril", "maio", "junho", "julho", "agosto", "setembro", "outubro", "novembro", "dezembro", ""], AbbreviatedMonthNames: ["jan", "fev", "mar", "abr", "mai", "jun", "jul", "ago", "set", "out", "nov", "dez", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "", PMDesignator: "", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	1049: {LCID: 1049, Name: "ru-RU", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "₽", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["воскресенье", "понедельник", "вторник", "среда", "четверг", "пятница", "суббота"], AbbreviatedDayNames: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"], MonthNames: ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь", ""], AbbreviatedMonthNames: ["янв", "фев", "мар", "апр", "май", "июн", "июл", "авг", "сен", "окт", "ноя", "дек", ""], MonthGenitiveNames: ["января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря", ""], AbbreviatedMonthGenitiveNames: ["янв", "фев", "мар", "апр", "мая", "июн", "июл", "авг", "сен", "окт", "ноя", "дек", ""], AMDesignator: "", PMDesignator: "", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	1051: {LCID: 1051, Name: "sk-SK", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["nedeľa", "pondelok", "utorok", "streda", "štvrtok", "piatok", "sobota"], AbbreviatedDayNames: ["ne", "po", "ut", "st", "št", "pi", "so"], MonthNames: ["január", "február", "marec", "apríl", "máj", "jún", "júl", "august", "september", "október", "november", "december", ""], AbbreviatedMonthNames: ["jan", "feb", "mar", "apr", "máj", "jún", "júl", "aug", "sep", "okt", "nov", "dec", ""], MonthGenitiveNames: ["januára", "februára", "marca", "apríla", "mája", "júna", "júla", "augusta", "septembra", "októbra", "novembra", "decembra", ""], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: ". ", TimeSeparator: ":", ShortDatePattern: "025"},
	1055: {LCID: 1055, Name: "tr-TR", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "₺", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi"], AbbreviatedDayNames: ["Paz", "Pzt", "Sal", "Çar", "Per", "Cum", "Cmt"], MonthNames: ["Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık", ""], AbbreviatedMonthNames: ["Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "ÖÖ", PMDesignator: "ÖS", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "035"},
	1058: {LCID: 1058, Name: "uk-UA", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "₴", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["неділя", "понеділок", "вівторок", "середа", "четвер", "п'ятниця", "субота"], AbbreviatedDayNames: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"], MonthNames: ["січень", "лютий", "березень", "квітень", "травень", "червень", "липень", "серпень", "вересень", "жовтень", "листопад", "грудень", ""], AbbreviatedMonthNames: ["Січ", "Лют", "Бер", "Кві", "Тра", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Гру", ""], MonthGenitiveNames: ["січня", "лютого", "березня", "квітня", "травня", "червня", "липня", "серпня", "вересня", "жовтня", "листопада", "грудня", ""], AbbreviatedMonthGenitiveNames: ["січ", "лют", "бер", "кві", "тра", "чер", "лип", "сер", "вер", "жов", "лис", "гру", ""], AMDesignator: "", PMDesignator: "", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	1060: {LCID: 1060, Name: "sl-SI", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["nedelja", "ponedeljek", "torek", "sreda", "četrtek", "petek", "sobota"], AbbreviatedDayNames: ["ned.", "pon.", "tor.", "sre.", "čet.", "pet.", "sob."], MonthNames: ["januar", "februar", "marec", "april", "maj", "junij", "julij", "avgust", "september", "oktober", "november", "december", ""], AbbreviatedMonthNames: ["jan.", "feb.", "mar.", "apr.", "maj", "jun.", "jul.", "avg.", "sep.", "okt.", "nov.", "dec.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "dop.", PMDesignator: "pop.", DateSeparator: ". ", TimeSeparator: ":", ShortDatePattern: "035"},
	1062: {LCID: 1062, Name: "lv-LV", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["svētdiena", "pirmdiena", "otrdiena", "trešdiena", "ceturtdiena", "piektdiena", "sestdiena"], AbbreviatedDayNames: ["svētd.", "pirmd.", "otrd.", "trešd.", "ceturtd.", "piektd.", "sestd."], MonthNames: ["janvāris", "februāris", "marts", "aprīlis", "maijs", "jūnijs", "jūlijs", "augusts", "septembris", "oktobris", "novembris", "decembris", ""], AbbreviatedMonthNames: ["janv.", "febr.", "marts", "apr.", "maijs", "jūn.", "jūl.", "aug.", "sept.", "okt.", "nov.", "dec.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "priekšp.", PMDesignator: "pēcp.", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	1066: {LCID: 1066, Name: "vi-VN", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "₫", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["Chủ Nhật", "Thứ Hai", "Thứ Ba", "Thứ Tư", "Thứ Năm", "Thứ Sáu", "Thứ Bảy"], AbbreviatedDayNames: ["CN", "T2", "T3", "T4", "T5", "T6", "T7"], MonthNames: ["Tháng Giêng", "Tháng Hai", "Tháng Ba", "Tháng Tư", "Tháng Năm", "Tháng Sáu", "Tháng Bảy", "Tháng Tám", "Tháng Chín", "Tháng Mười", "Tháng Mười Một", "Tháng Mười Hai", ""], AbbreviatedMonthNames: ["Thg1", "Thg2", "Thg3", "Thg4", "Thg5", "Thg6", "Thg7", "Thg8", "Thg9", "Thg10", "Thg11", "Thg12", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "SA", PMDesignator: "CH", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	1068: {LCID: 1068, Name: "az-Latn-AZ", CurrencyPositivePattern: 2, CurrencyNegativePattern: 9, CurrencySymbol: "₼", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["bazar", "bazar ertəsi", "çərşənbə axşamı", "çərşənbə", "cümə axşamı", "cümə", "şənbə"], AbbreviatedDayNames: ["B.", "B.E.", "Ç.A.", "Ç.", "C.A.", "C.", "Ş."], MonthNames: ["Yanvar", "Fevral", "Mart", "Aprel", "May", "İyun", "İyul", "Avqust", "Sentyabr", "Oktyabr", "Noyabr", "Dekabr", ""], AbbreviatedMonthNames: ["yan", "fev", "mar", "apr", "may", "iyn", "iyl", "avq", "sen", "okt", "noy", "dek", ""], MonthGenitiveNames: ["yanvar", "fevral", "mart", "aprel", "may", "iyun", "iyul", "avqust", "sentyabr", "oktyabr", "noyabr", "dekabr", ""], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	2052: {LCID: 2052, Name: "zh-CN", CurrencyPositivePattern: 0, CurrencyNegativePattern: 2, CurrencySymbol: "¥", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"], AbbreviatedDayNames: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"], MonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月", ""], AbbreviatedMonthNames: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "上午", PMDesignator: "下午", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "520"},
	2055: {LCID: 2055, Name: "de-CH", CurrencyPositivePattern: 2, CurrencyNegativePattern: 2, CurrencySymbol: "CHF", NumberDecimalSeparator: ".", NumberGroupSeparator: "’", NumberGroupSizes: [3], DayNames: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"], AbbreviatedDayNames: ["So.", "Mo.", "Di.", "Mi.", "Do.", "Fr.", "Sa."], MonthNames: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: ["Jan.", "Feb.", "März", "Apr.", "Mai", "Juni", "Juli", "Aug.", "Sep.", "Okt.", "Nov.", "Dez.", ""], AMDesignator: "vorm.", PMDesignator: "nachm.", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	2057: {LCID: 2057, Name: "en-GB", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "£", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	2058: {LCID: 2058, Name: "es-MX", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	2060: {LCID: 2060, Name: "fr-BE", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], AbbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], MonthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre", ""], AbbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "", PMDesignator: "", DateSeparator: "-", TimeSeparator: ":", ShortDatePattern: "134"},
	2064: {LCID: 2064, Name: "it-CH", CurrencyPositivePattern: 2, CurrencyNegativePattern: 2, CurrencySymbol: "CHF", NumberDecimalSeparator: ".", NumberGroupSeparator: "’", NumberGroupSizes: [3], DayNames: ["domenica", "lunedì", "martedì", "mercoledì", "giovedì", "venerdì", "sabato"], AbbreviatedDayNames: ["dom", "lun", "mar", "mer", "gio", "ven", "sab"], MonthNames: ["gennaio", "febbraio", "marzo", "aprile", "maggio", "giugno", "luglio", "agosto", "settembre", "ottobre", "novembre", "dicembre", ""], AbbreviatedMonthNames: ["gen", "feb", "mar", "apr", "mag", "giu", "lug", "ago", "set", "ott", "nov", "dic", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	2070: {LCID: 2070, Name: "pt-PT", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["domingo", "segunda-feira", "terça-feira", "quarta-feira", "quinta-feira", "sexta-feira", "sábado"], AbbreviatedDayNames: ["dom", "seg", "ter", "qua", "qui", "sex", "sáb"], MonthNames: ["janeiro", "fevereiro", "março", "abril", "maio", "junho", "julho", "agosto", "setembro", "outubro", "novembro", "dezembro", ""], AbbreviatedMonthNames: ["jan", "fev", "mar", "abr", "mai", "jun", "jul", "ago", "set", "out", "nov", "dez", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "", PMDesignator: "", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	2073: {LCID: 2073, Name: "ru-MD", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "L", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["воскресенье", "понедельник", "вторник", "среда", "четверг", "пятница", "суббота"], AbbreviatedDayNames: ["вс", "пн", "вт", "ср", "чт", "пт", "сб"], MonthNames: ["январь", "февраль", "март", "апрель", "май", "июнь", "июль", "август", "сентябрь", "октябрь", "ноябрь", "декабрь", ""], AbbreviatedMonthNames: ["янв.", "февр.", "март", "апр.", "май", "июнь", "июль", "авг.", "сент.", "окт.", "нояб.", "дек.", ""], MonthGenitiveNames: ["января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря", ""], AbbreviatedMonthGenitiveNames: ["янв.", "февр.", "мар.", "апр.", "мая", "июн.", "июл.", "авг.", "сент.", "окт.", "нояб.", "дек.", ""], AMDesignator: "ДП", PMDesignator: "ПП", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	2092: {LCID: 2092, Name: "az-Cyrl-AZ", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "₼", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["базар", "базар ертәси", "чәршәнбә ахшамы", "чәршәнбә", "ҹүмә ахшамы", "ҹүмә", "шәнбә"], AbbreviatedDayNames: ["Б", "Бе", "Ча", "Ч", "Ҹа", "Ҹ", "Ш"], MonthNames: ["jанвар", "феврал", "март", "апрел", "мај", "ијун", "ијул", "август", "сентјабр", "октјабр", "нојабр", "декабр", ""], AbbreviatedMonthNames: ["Јан", "Фев", "Мар", "Апр", "Мај", "Ијун", "Ијул", "Авг", "Сен", "Окт", "Ноя", "Дек", ""], MonthGenitiveNames: ["јанвар", "феврал", "март", "апрел", "мај", "ијун", "ијул", "август", "сентјабр", "октјабр", "нојабр", "декабр", ""], AbbreviatedMonthGenitiveNames: ["Јан", "Фев", "Мар", "Апр", "мая", "ијун", "ијул", "Авг", "Сен", "Окт", "Ноя", "Дек", ""], AMDesignator: "", PMDesignator: "", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	3076: {LCID: 3076, Name: "zh-HK", CurrencyPositivePattern: 0, CurrencyNegativePattern: 0, CurrencySymbol: "HK$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"], AbbreviatedDayNames: ["週日", "週一", "週二", "週三", "週四", "週五", "週六"], MonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月", ""], AbbreviatedMonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "上午", PMDesignator: "下午", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	3079: {LCID: 3079, Name: "de-AT", CurrencyPositivePattern: 2, CurrencyNegativePattern: 9, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"], AbbreviatedDayNames: ["So.", "Mo.", "Di.", "Mi.", "Do.", "Fr.", "Sa."], MonthNames: ["Jänner", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember", ""], AbbreviatedMonthNames: ["Jän", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: ["Jän.", "Feb.", "März", "Apr.", "Mai", "Juni", "Juli", "Aug.", "Sep.", "Okt.", "Nov.", "Dez.", ""], AMDesignator: "vorm.", PMDesignator: "nachm.", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	3081: {LCID: 3081, Name: "en-AU", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "035"},
	3082: {LCID: 3082, Name: "es-ES", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["do.", "lu.", "ma.", "mi.", "ju.", "vi.", "sá."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "", PMDesignator: "", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	3084: {LCID: 3084, Name: "fr-CA", CurrencyPositivePattern: 3, CurrencyNegativePattern: 15, CurrencySymbol: "$", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], AbbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], MonthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre", ""], AbbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "", PMDesignator: "", DateSeparator: "-", TimeSeparator: ":", ShortDatePattern: "531"},
	4100: {LCID: 4100, Name: "zh-SG", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"], AbbreviatedDayNames: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"], MonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月", ""], AbbreviatedMonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "上午", PMDesignator: "下午", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	4103: {LCID: 4103, Name: "de-LU", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"], AbbreviatedDayNames: ["So.", "Mo.", "Di.", "Mi.", "Do.", "Fr.", "Sa."], MonthNames: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: ["Jan.", "Feb.", "März", "Apr.", "Mai", "Juni", "Juli", "Aug.", "Sep.", "Okt.", "Nov.", "Dez.", ""], AMDesignator: "vorm.", PMDesignator: "nachm.", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	4105: {LCID: 4105, Name: "en-CA", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "-", TimeSeparator: ":", ShortDatePattern: "531"},
	4106: {LCID: 4106, Name: "es-GT", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "Q", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "035"},
	4108: {LCID: 4108, Name: "fr-CH", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "CHF", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], AbbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], MonthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre", ""], AbbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	5124: {LCID: 5124, Name: "zh-MO", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "MOP", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"], AbbreviatedDayNames: ["週日", "週一", "週二", "週三", "週四", "週五", "週六"], MonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月", ""], AbbreviatedMonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "上午", PMDesignator: "下午", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	5127: {LCID: 5127, Name: "de-LI", CurrencyPositivePattern: 2, CurrencyNegativePattern: 9, CurrencySymbol: "CHF", NumberDecimalSeparator: ".", NumberGroupSeparator: "’", NumberGroupSizes: [3], DayNames: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"], AbbreviatedDayNames: ["So.", "Mo.", "Di.", "Mi.", "Do.", "Fr.", "Sa."], MonthNames: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: ["Jan.", "Feb.", "März", "Apr.", "Mai", "Juni", "Juli", "Aug.", "Sep.", "Okt.", "Nov.", "Dez.", ""], AMDesignator: "vorm.", PMDesignator: "nachm.", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	5129: {LCID: 5129, Name: "en-NZ", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "035"},
	5130: {LCID: 5130, Name: "es-CR", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "₡", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	5132: {LCID: 5132, Name: "fr-LU", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], AbbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], MonthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre", ""], AbbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	6153: {LCID: 6153, Name: "en-IE", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "€", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	6154: {LCID: 6154, Name: "es-PA", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "B/.", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "315"},
	6156: {LCID: 6156, Name: "fr-MC", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], AbbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], MonthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre", ""], AbbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	7177: {LCID: 7177, Name: "en-ZA", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "R", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "531"},
	7178: {LCID: 7178, Name: "es-DO", CurrencyPositivePattern: 0, CurrencyNegativePattern: 0, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	7180: {LCID: 7180, Name: "fr-029", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "EC$", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], AbbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], MonthNames: ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre", ""], AbbreviatedMonthNames: ["Janv.", "Févr.", "Mars", "Avr.", "Mai", "Juin", "Juil.", "Août", "Sept.", "Oct.", "Nov.", "Déc.", ""], MonthGenitiveNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre", ""], AbbreviatedMonthGenitiveNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", ""], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	8201: {LCID: 8201, Name: "en-JM", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	8202: {LCID: 8202, Name: "es-VE", CurrencyPositivePattern: 0, CurrencyNegativePattern: 2, CurrencySymbol: "Bs.", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sept.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	8204: {LCID: 8204, Name: "fr-RE", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "€", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], AbbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], MonthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre", ""], AbbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	9225: {LCID: 9225, Name: "en-029", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "EC$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	9226: {LCID: 9226, Name: "es-CO", CurrencyPositivePattern: 2, CurrencyNegativePattern: 9, CurrencySymbol: "$", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sept.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "035"},
	9228: {LCID: 9228, Name: "fr-CD", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "FC", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], AbbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], MonthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre", ""], AbbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	10249: {LCID: 10249, Name: "en-BZ", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	10250: {LCID: 10250, Name: "es-PE", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "S/", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Setiembre", "Octubre", "Noviembre", "Diciembre", ""], AbbreviatedMonthNames: ["Ene.", "Feb.", "Mar.", "Abr.", "May.", "Jun.", "Jul.", "Ago.", "Set.", "Oct.", "Nov.", "Dic.", ""], MonthGenitiveNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "setiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthGenitiveNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "set.", "oct.", "nov.", "dic.", ""], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "035"},
	10252: {LCID: 10252, Name: "fr-SN", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "CFA", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], AbbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], MonthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre", ""], AbbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	11273: {LCID: 11273, Name: "en-TT", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	11274: {LCID: 11274, Name: "es-AR", CurrencyPositivePattern: 2, CurrencyNegativePattern: 9, CurrencySymbol: "$", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	11276: {LCID: 11276, Name: "fr-CM", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "FCFA", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], AbbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], MonthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre", ""], AbbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "mat.", PMDesignator: "soir", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	12297: {LCID: 12297, Name: "en-ZW", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "US$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	12298: {LCID: 12298, Name: "es-EC", CurrencyPositivePattern: 0, CurrencyNegativePattern: 2, CurrencySymbol: "$", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	12300: {LCID: 12300, Name: "fr-CI", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "CFA", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], AbbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], MonthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre", ""], AbbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	13321: {LCID: 13321, Name: "en-PH", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "₱", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	13322: {LCID: 13322, Name: "es-CL", CurrencyPositivePattern: 0, CurrencyNegativePattern: 2, CurrencySymbol: "$", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sept.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "-", TimeSeparator: ":", ShortDatePattern: "135"},
	13324: {LCID: 13324, Name: "fr-ML", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "CFA", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], AbbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], MonthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre", ""], AbbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	14345: {LCID: 14345, Name: "en-ID", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "Rp", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	14346: {LCID: 14346, Name: "es-UY", CurrencyPositivePattern: 2, CurrencyNegativePattern: 9, CurrencySymbol: "$", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Setiembre", "Octubre", "Noviembre", "Diciembre", ""], AbbreviatedMonthNames: ["Ene.", "Feb.", "Mar.", "Abr.", "May.", "Jun.", "Jul.", "Ago.", "Set.", "Oct.", "Nov.", "Dic.", ""], MonthGenitiveNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "setiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthGenitiveNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "set.", "oct.", "nov.", "dic.", ""], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	14348: {LCID: 14348, Name: "fr-MA", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "DH", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], AbbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], MonthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre", ""], AbbreviatedMonthNames: ["jan.", "fév.", "mar.", "avr.", "mai", "jui.", "juil.", "août", "sept.", "oct.", "nov.", "déc.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	15369: {LCID: 15369, Name: "en-HK", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	15370: {LCID: 15370, Name: "es-PY", CurrencyPositivePattern: 2, CurrencyNegativePattern: 12, CurrencySymbol: "₲", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sept.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	15372: {LCID: 15372, Name: "fr-HT", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "G", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], AbbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], MonthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre", ""], AbbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "135"},
	16393: {LCID: 16393, Name: "en-IN", CurrencyPositivePattern: 2, CurrencyNegativePattern: 12, CurrencySymbol: "₹", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3, 2], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "-", TimeSeparator: ":", ShortDatePattern: "135"},
	16394: {LCID: 16394, Name: "es-BO", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "Bs", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	17417: {LCID: 17417, Name: "en-MY", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "RM", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	17418: {LCID: 17418, Name: "es-SV", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	18441: {LCID: 18441, Name: "en-SG", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	18442: {LCID: 18442, Name: "es-HN", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "L", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	19466: {LCID: 19466, Name: "es-NI", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "C$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	20490: {LCID: 20490, Name: "es-PR", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "a. m.", PMDesignator: "p. m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "315"},
	21514: {LCID: 21514, Name: "es-US", CurrencyPositivePattern: 0, CurrencyNegativePattern: 0, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "205"},
	22538: {LCID: 22538, Name: "es-419", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "XDR", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "a.m.", PMDesignator: "p.m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	23562: {LCID: 23562, Name: "es-CU", CurrencyPositivePattern: 0, CurrencyNegativePattern: 1, CurrencySymbol: "$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"], AbbreviatedDayNames: ["dom.", "lun.", "mar.", "mié.", "jue.", "vie.", "sáb."], MonthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre", ""], AbbreviatedMonthNames: ["ene.", "feb.", "mar.", "abr.", "may.", "jun.", "jul.", "ago.", "sep.", "oct.", "nov.", "dic.", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "a.m.", PMDesignator: "p.m.", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
	29740: {LCID: 29740, Name: "az-Cyrl", CurrencyPositivePattern: 3, CurrencyNegativePattern: 8, CurrencySymbol: "₼", NumberDecimalSeparator: ",", NumberGroupSeparator: " ", NumberGroupSizes: [3], DayNames: ["базар", "базар ертәси", "чәршәнбә ахшамы", "чәршәнбә", "ҹүмә ахшамы", "ҹүмә", "шәнбә"], AbbreviatedDayNames: ["Б", "Бе", "Ча", "Ч", "Ҹа", "Ҹ", "Ш"], MonthNames: ["jанвар", "феврал", "март", "апрел", "мај", "ијун", "ијул", "август", "сентјабр", "октјабр", "нојабр", "декабр", ""], AbbreviatedMonthNames: ["Јан", "Фев", "Мар", "Апр", "Мај", "Ијун", "Ијул", "Авг", "Сен", "Окт", "Ноя", "Дек", ""], MonthGenitiveNames: ["јанвар", "феврал", "март", "апрел", "мај", "ијун", "ијул", "август", "сентјабр", "октјабр", "нојабр", "декабр", ""], AbbreviatedMonthGenitiveNames: ["Јан", "Фев", "Мар", "Апр", "мая", "ијун", "ијул", "Авг", "Сен", "Окт", "Ноя", "Дек", ""], AMDesignator: "", PMDesignator: "", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	30724: {LCID: 30724, Name: "zh", CurrencyPositivePattern: 0, CurrencyNegativePattern: 2, CurrencySymbol: "¥", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"], AbbreviatedDayNames: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"], MonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月", ""], AbbreviatedMonthNames: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "上午", PMDesignator: "下午", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "520"},
	30764: {LCID: 30764, Name: "az-Latn", CurrencyPositivePattern: 2, CurrencyNegativePattern: 9, CurrencySymbol: "₼", NumberDecimalSeparator: ",", NumberGroupSeparator: ".", NumberGroupSizes: [3], DayNames: ["bazar", "bazar ertəsi", "çərşənbə axşamı", "çərşənbə", "cümə axşamı", "cümə", "şənbə"], AbbreviatedDayNames: ["B.", "B.E.", "Ç.A.", "Ç.", "C.A.", "C.", "Ş."], MonthNames: ["Yanvar", "Fevral", "Mart", "Aprel", "May", "İyun", "İyul", "Avqust", "Sentyabr", "Oktyabr", "Noyabr", "Dekabr", ""], AbbreviatedMonthNames: ["yan", "fev", "mar", "apr", "may", "iyn", "iyl", "avq", "sen", "okt", "noy", "dek", ""], MonthGenitiveNames: ["yanvar", "fevral", "mart", "aprel", "may", "iyun", "iyul", "avqust", "sentyabr", "oktyabr", "noyabr", "dekabr", ""], AbbreviatedMonthGenitiveNames: [], AMDesignator: "AM", PMDesignator: "PM", DateSeparator: ".", TimeSeparator: ":", ShortDatePattern: "135"},
	31748: {LCID: 31748, Name: "zh-Hant", CurrencyPositivePattern: 0, CurrencyNegativePattern: 0, CurrencySymbol: "HK$", NumberDecimalSeparator: ".", NumberGroupSeparator: ",", NumberGroupSizes: [3], DayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"], AbbreviatedDayNames: ["週日", "週一", "週二", "週三", "週四", "週五", "週六"], MonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月", ""], AbbreviatedMonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月", ""], MonthGenitiveNames: [], AbbreviatedMonthGenitiveNames: [], AMDesignator: "上午", PMDesignator: "下午", DateSeparator: "/", TimeSeparator: ":", ShortDatePattern: "025"},
};
var g_oDefaultCultureInfo = g_aCultureInfos[1033];//en-US//1033//fr-FR//1036//basq//1069//ru-Ru//1049//hindi//1081

    //---------------------------------------------------------export---------------------------------------------------
    window['AscCommon'] = window['AscCommon'] || {};
    window['AscCommon'].isNumber = isNumber;
    window["AscCommon"].NumFormat = NumFormat;
    window["AscCommon"].CellFormat = CellFormat;
    window["AscCommon"].DecodeGeneralFormat = DecodeGeneralFormat;
    window["AscCommon"].setCurrentCultureInfo = setCurrentCultureInfo;
	window["AscCommon"].checkCultureInfoFontPicker = checkCultureInfoFontPicker;
	window['AscCommon'].getShortDateFormat = getShortDateFormat;
	window['AscCommon'].getShortDateFormat2 = getShortDateFormat2;
	window['AscCommon'].getShortDateMonthFormat = getShortDateMonthFormat;
	window['AscCommon'].getNumberFormatSimple = getNumberFormatSimple;
	window['AscCommon'].getNumberFormat = getNumberFormat;
	window['AscCommon'].getLocaleFormat = getLocaleFormat;
	window['AscCommon'].getCurrencyFormatSimple = getCurrencyFormatSimple;
	window['AscCommon'].getCurrencyFormatSimple2 = getCurrencyFormatSimple2;
	window['AscCommon'].getCurrencyFormat = getCurrencyFormat;
	window['AscCommon'].getFormatCells = getFormatCells;
	window['AscCommon'].getFormatByStandardId = getFormatByStandardId;
	window['AscCommon'].compareNumbers = compareNumbers;

    window["AscCommon"].gc_nMaxDigCount = gc_nMaxDigCount;
    window["AscCommon"].gc_nMaxDigCountView = gc_nMaxDigCountView;
    window["AscCommon"].oNumFormatCache = oNumFormatCache;
    window["AscCommon"].oGeneralEditFormatCache = oGeneralEditFormatCache;
    window["AscCommon"].g_oFormatParser = g_oFormatParser;
    window["AscCommon"].g_aCultureInfos = g_aCultureInfos;
    window["AscCommon"].g_oDefaultCultureInfo = g_oDefaultCultureInfo;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

// Import
var c_oSerConstants = AscCommon.c_oSerConstants;

var c_oAscTickMark = Asc.c_oAscTickMark;
var c_oAscTickLabelsPos = Asc.c_oAscTickLabelsPos;
var c_oAscChartDataLabelsPos = Asc.c_oAscChartDataLabelsPos;
var c_oAscValAxUnits = Asc.c_oAscValAxUnits;
var c_oAscChartLegendShowSettings = Asc.c_oAscChartLegendShowSettings;

//Generated code

var st_pagesetuporientationDEFAULT = 0;
var st_pagesetuporientationPORTRAIT = 1;
var st_pagesetuporientationLANDSCAPE = 2;

var st_dispblanksasSPAN = 0;
var st_dispblanksasGAP = 1;
var st_dispblanksasZERO = 2;

var st_legendposB = 0;
var st_legendposTR = 1;
var st_legendposL = 2;
var st_legendposR = 3;
var st_legendposT = 4;

var st_layouttargetINNER = 0;
var st_layouttargetOUTER = 1;

var st_layoutmodeEDGE = 0;
var st_layoutmodeFACTOR = 1;

var st_orientationMAXMIN = 0;
var st_orientationMINMAX = 1;

var st_axposB = 0;
var st_axposL = 1;
var st_axposR = 2;
var st_axposT = 3;

var st_tickmarkCROSS = 0;
var st_tickmarkIN = 1;
var st_tickmarkNONE = 2;
var st_tickmarkOUT = 3;

var st_ticklblposHIGH = 0;
var st_ticklblposLOW = 1;
var st_ticklblposNEXTTO = 2;
var st_ticklblposNONE = 3;

var st_crossesAUTOZERO = 0;
var st_crossesMAX = 1;
var st_crossesMIN = 2;

var st_timeunitDAYS = 0;
var st_timeunitMONTHS = 1;
var st_timeunitYEARS = 2;

var st_lblalgnCTR = 0;
var st_lblalgnL = 1;
var st_lblalgnR = 2;

var st_builtinunitHUNDREDS = 0;
var st_builtinunitTHOUSANDS = 1;
var st_builtinunitTENTHOUSANDS = 2;
var st_builtinunitHUNDREDTHOUSANDS = 3;
var st_builtinunitMILLIONS = 4;
var st_builtinunitTENMILLIONS = 5;
var st_builtinunitHUNDREDMILLIONS = 6;
var st_builtinunitBILLIONS = 7;
var st_builtinunitTRILLIONS = 8;

var st_crossbetweenBETWEEN = 0;
var st_crossbetweenMIDCAT = 1;

var st_sizerepresentsAREA = 0;
var st_sizerepresentsW = 1;

var st_markerstyleCIRCLE = 0;
var st_markerstyleDASH = 1;
var st_markerstyleDIAMOND = 2;
var st_markerstyleDOT = 3;
var st_markerstyleNONE = 4;
var st_markerstylePICTURE = 5;
var st_markerstylePLUS = 6;
var st_markerstyleSQUARE = 7;
var st_markerstyleSTAR = 8;
var st_markerstyleTRIANGLE = 9;
var st_markerstyleX = 10;
var st_markerstyleAUTO = 11;

var st_pictureformatSTRETCH = 0;
var st_pictureformatSTACK = 1;
var st_pictureformatSTACKSCALE = 2;

var st_dlblposBESTFIT = 0;
var st_dlblposB = 1;
var st_dlblposCTR = 2;
var st_dlblposINBASE = 3;
var st_dlblposINEND = 4;
var st_dlblposL = 5;
var st_dlblposOUTEND = 6;
var st_dlblposR = 7;
var st_dlblposT = 8;

var st_trendlinetypeEXP = 0;
var st_trendlinetypeLINEAR = 1;
var st_trendlinetypeLOG = 2;
var st_trendlinetypeMOVINGAVG = 3;
var st_trendlinetypePOLY = 4;
var st_trendlinetypePOWER = 5;

var st_errdirX = 0;
var st_errdirY = 1;

var st_errbartypeBOTH = 0;
var st_errbartypeMINUS = 1;
var st_errbartypePLUS = 2;

var st_errvaltypeCUST = 0;
var st_errvaltypeFIXEDVAL = 1;
var st_errvaltypePERCENTAGE = 2;
var st_errvaltypeSTDDEV = 3;
var st_errvaltypeSTDERR = 4;

var st_splittypeAUTO = 0;
var st_splittypeCUST = 1;
var st_splittypePERCENT = 2;
var st_splittypePOS = 3;
var st_splittypeVAL = 4;

var st_ofpietypePIE = 0;
var st_ofpietypeBAR = 1;

var st_bardirBAR = 0;
var st_bardirCOL = 1;

var st_bargroupingPERCENTSTACKED = 0;
var st_bargroupingCLUSTERED = 1;
var st_bargroupingSTANDARD = 2;
var st_bargroupingSTACKED = 3;

var st_shapeCONE = 0;
var st_shapeCONETOMAX = 1;
var st_shapeBOX = 2;
var st_shapeCYLINDER = 3;
var st_shapePYRAMID = 4;
var st_shapePYRAMIDTOMAX = 5;

var st_scatterstyleNONE = 0;
var st_scatterstyleLINE = 1;
var st_scatterstyleLINEMARKER = 2;
var st_scatterstyleMARKER = 3;
var st_scatterstyleSMOOTH = 4;
var st_scatterstyleSMOOTHMARKER = 5;

var st_radarstyleSTANDARD = 0;
var st_radarstyleMARKER = 1;
var st_radarstyleFILLED = 2;

var st_groupingPERCENTSTACKED = 0;
var st_groupingSTANDARD = 1;
var st_groupingSTACKED = 2;

var c_oserct_extlstEXT = 0;

var c_oserct_chartspaceDATE1904 = 0;
var c_oserct_chartspaceLANG = 1;
var c_oserct_chartspaceROUNDEDCORNERS = 2;
var c_oserct_chartspaceALTERNATECONTENT = 3;
var c_oserct_chartspaceSTYLE = 4;
var c_oserct_chartspaceCLRMAPOVR = 5;
var c_oserct_chartspacePIVOTSOURCE = 6;
var c_oserct_chartspacePROTECTION = 7;
var c_oserct_chartspaceCHART = 8;
var c_oserct_chartspaceSPPR = 9;
var c_oserct_chartspaceTXPR = 10;
var c_oserct_chartspaceEXTERNALDATA = 11;
var c_oserct_chartspacePRINTSETTINGS = 12;
var c_oserct_chartspaceUSERSHAPES = 13;
var c_oserct_chartspaceEXTLST = 14;
var c_oserct_chartspaceTHEMEOVERRIDE = 15;

var c_oserct_booleanVAL = 0;

var c_oserct_relidID = 0;

var c_oserct_pagesetupPAPERSIZE = 0;
var c_oserct_pagesetupPAPERHEIGHT = 1;
var c_oserct_pagesetupPAPERWIDTH = 2;
var c_oserct_pagesetupFIRSTPAGENUMBER = 3;
var c_oserct_pagesetupORIENTATION = 4;
var c_oserct_pagesetupBLACKANDWHITE = 5;
var c_oserct_pagesetupDRAFT = 6;
var c_oserct_pagesetupUSEFIRSTPAGENUMBER = 7;
var c_oserct_pagesetupHORIZONTALDPI = 8;
var c_oserct_pagesetupVERTICALDPI = 9;
var c_oserct_pagesetupCOPIES = 10;

var c_oserct_pagemarginsL = 0;
var c_oserct_pagemarginsR = 1;
var c_oserct_pagemarginsT = 2;
var c_oserct_pagemarginsB = 3;
var c_oserct_pagemarginsHEADER = 4;
var c_oserct_pagemarginsFOOTER = 5;

var c_oserct_headerfooterODDHEADER = 0;
var c_oserct_headerfooterODDFOOTER = 1;
var c_oserct_headerfooterEVENHEADER = 2;
var c_oserct_headerfooterEVENFOOTER = 3;
var c_oserct_headerfooterFIRSTHEADER = 4;
var c_oserct_headerfooterFIRSTFOOTER = 5;
var c_oserct_headerfooterALIGNWITHMARGINS = 6;
var c_oserct_headerfooterDIFFERENTODDEVEN = 7;
var c_oserct_headerfooterDIFFERENTFIRST = 8;

var c_oserct_printsettingsHEADERFOOTER = 0;
var c_oserct_printsettingsPAGEMARGINS = 1;
var c_oserct_printsettingsPAGESETUP = 2;

var c_oserct_externaldataAUTOUPDATE = 0;
var c_oserct_externaldataID = 1;

var c_oserct_dispblanksasVAL = 0;

var c_oserct_legendentryIDX = 0;
var c_oserct_legendentryDELETE = 1;
var c_oserct_legendentryTXPR = 2;
var c_oserct_legendentryEXTLST = 3;

var c_oserct_unsignedintVAL = 0;

var c_oserct_extensionANY = 0;
var c_oserct_extensionURI = 1;

var c_oserct_legendposVAL = 0;

var c_oserct_legendLEGENDPOS = 0;
var c_oserct_legendLEGENDENTRY = 1;
var c_oserct_legendLAYOUT = 2;
var c_oserct_legendOVERLAY = 3;
var c_oserct_legendSPPR = 4;
var c_oserct_legendTXPR = 5;
var c_oserct_legendEXTLST = 6;

var c_oserct_layoutMANUALLAYOUT = 0;
var c_oserct_layoutEXTLST = 1;

var c_oserct_manuallayoutLAYOUTTARGET = 0;
var c_oserct_manuallayoutXMODE = 1;
var c_oserct_manuallayoutYMODE = 2;
var c_oserct_manuallayoutWMODE = 3;
var c_oserct_manuallayoutHMODE = 4;
var c_oserct_manuallayoutX = 5;
var c_oserct_manuallayoutY = 6;
var c_oserct_manuallayoutW = 7;
var c_oserct_manuallayoutH = 8;
var c_oserct_manuallayoutEXTLST = 9;

var c_oserct_layouttargetVAL = 0;

var c_oserct_layoutmodeVAL = 0;

var c_oserct_doubleVAL = 0;

var c_oserct_dtableSHOWHORZBORDER = 0;
var c_oserct_dtableSHOWVERTBORDER = 1;
var c_oserct_dtableSHOWOUTLINE = 2;
var c_oserct_dtableSHOWKEYS = 3;
var c_oserct_dtableSPPR = 4;
var c_oserct_dtableTXPR = 5;
var c_oserct_dtableEXTLST = 6;

var c_oserct_seraxAXID = 0;
var c_oserct_seraxSCALING = 1;
var c_oserct_seraxDELETE = 2;
var c_oserct_seraxAXPOS = 3;
var c_oserct_seraxMAJORGRIDLINES = 4;
var c_oserct_seraxMINORGRIDLINES = 5;
var c_oserct_seraxTITLE = 6;
var c_oserct_seraxNUMFMT = 7;
var c_oserct_seraxMAJORTICKMARK = 8;
var c_oserct_seraxMINORTICKMARK = 9;
var c_oserct_seraxTICKLBLPOS = 10;
var c_oserct_seraxSPPR = 11;
var c_oserct_seraxTXPR = 12;
var c_oserct_seraxCROSSAX = 13;
var c_oserct_seraxCROSSES = 14;
var c_oserct_seraxCROSSESAT = 15;
var c_oserct_seraxTICKLBLSKIP = 16;
var c_oserct_seraxTICKMARKSKIP = 17;
var c_oserct_seraxEXTLST = 18;

var c_oserct_scalingLOGBASE = 0;
var c_oserct_scalingORIENTATION = 1;
var c_oserct_scalingMAX = 2;
var c_oserct_scalingMIN = 3;
var c_oserct_scalingEXTLST = 4;

var c_oserct_logbaseVAL = 0;

var c_oserct_orientationVAL = 0;

var c_oserct_axposVAL = 0;

var c_oserct_chartlinesSPPR = 0;

var c_oserct_titleTX = 0;
var c_oserct_titleLAYOUT = 1;
var c_oserct_titleOVERLAY = 2;
var c_oserct_titleSPPR = 3;
var c_oserct_titleTXPR = 4;
var c_oserct_titleEXTLST = 5;

var c_oserct_txRICH = 0;
var c_oserct_txSTRREF = 1;

var c_oserct_strrefF = 0;
var c_oserct_strrefSTRCACHE = 1;
var c_oserct_strrefEXTLST = 2;

var c_oserct_strdataPTCOUNT = 0;
var c_oserct_strdataPT = 1;
var c_oserct_strdataEXTLST = 2;

var c_oserct_strvalV = 0;
var c_oserct_strvalIDX = 1;

var c_oserct_numfmtFORMATCODE = 0;
var c_oserct_numfmtSOURCELINKED = 1;

var c_oserct_tickmarkVAL = 0;

var c_oserct_ticklblposVAL = 0;

var c_oserct_crossesVAL = 0;

var c_oserct_skipVAL = 0;

var c_oserct_timeunitVAL = 0;

var c_oserct_dateaxAXID = 0;
var c_oserct_dateaxSCALING = 1;
var c_oserct_dateaxDELETE = 2;
var c_oserct_dateaxAXPOS = 3;
var c_oserct_dateaxMAJORGRIDLINES = 4;
var c_oserct_dateaxMINORGRIDLINES = 5;
var c_oserct_dateaxTITLE = 6;
var c_oserct_dateaxNUMFMT = 7;
var c_oserct_dateaxMAJORTICKMARK = 8;
var c_oserct_dateaxMINORTICKMARK = 9;
var c_oserct_dateaxTICKLBLPOS = 10;
var c_oserct_dateaxSPPR = 11;
var c_oserct_dateaxTXPR = 12;
var c_oserct_dateaxCROSSAX = 13;
var c_oserct_dateaxCROSSES = 14;
var c_oserct_dateaxCROSSESAT = 15;
var c_oserct_dateaxAUTO = 16;
var c_oserct_dateaxLBLOFFSET = 17;
var c_oserct_dateaxBASETIMEUNIT = 18;
var c_oserct_dateaxMAJORUNIT = 19;
var c_oserct_dateaxMAJORTIMEUNIT = 20;
var c_oserct_dateaxMINORUNIT = 21;
var c_oserct_dateaxMINORTIMEUNIT = 22;
var c_oserct_dateaxEXTLST = 23;

var c_oserct_lbloffsetVAL = 0;

var c_oserct_axisunitVAL = 0;

var c_oserct_lblalgnVAL = 0;

var c_oserct_cataxAXID = 0;
var c_oserct_cataxSCALING = 1;
var c_oserct_cataxDELETE = 2;
var c_oserct_cataxAXPOS = 3;
var c_oserct_cataxMAJORGRIDLINES = 4;
var c_oserct_cataxMINORGRIDLINES = 5;
var c_oserct_cataxTITLE = 6;
var c_oserct_cataxNUMFMT = 7;
var c_oserct_cataxMAJORTICKMARK = 8;
var c_oserct_cataxMINORTICKMARK = 9;
var c_oserct_cataxTICKLBLPOS = 10;
var c_oserct_cataxSPPR = 11;
var c_oserct_cataxTXPR = 12;
var c_oserct_cataxCROSSAX = 13;
var c_oserct_cataxCROSSES = 14;
var c_oserct_cataxCROSSESAT = 15;
var c_oserct_cataxAUTO = 16;
var c_oserct_cataxLBLALGN = 17;
var c_oserct_cataxLBLOFFSET = 18;
var c_oserct_cataxTICKLBLSKIP = 19;
var c_oserct_cataxTICKMARKSKIP = 20;
var c_oserct_cataxNOMULTILVLLBL = 21;
var c_oserct_cataxEXTLST = 22;

var c_oserct_dispunitslblLAYOUT = 0;
var c_oserct_dispunitslblTX = 1;
var c_oserct_dispunitslblSPPR = 2;
var c_oserct_dispunitslblTXPR = 3;

var c_oserct_builtinunitVAL = 0;

var c_oserct_dispunitsBUILTINUNIT = 0;
var c_oserct_dispunitsCUSTUNIT = 1;
var c_oserct_dispunitsDISPUNITSLBL = 2;
var c_oserct_dispunitsEXTLST = 3;

var c_oserct_crossbetweenVAL = 0;

var c_oserct_valaxAXID = 0;
var c_oserct_valaxSCALING = 1;
var c_oserct_valaxDELETE = 2;
var c_oserct_valaxAXPOS = 3;
var c_oserct_valaxMAJORGRIDLINES = 4;
var c_oserct_valaxMINORGRIDLINES = 5;
var c_oserct_valaxTITLE = 6;
var c_oserct_valaxNUMFMT = 7;
var c_oserct_valaxMAJORTICKMARK = 8;
var c_oserct_valaxMINORTICKMARK = 9;
var c_oserct_valaxTICKLBLPOS = 10;
var c_oserct_valaxSPPR = 11;
var c_oserct_valaxTXPR = 12;
var c_oserct_valaxCROSSAX = 13;
var c_oserct_valaxCROSSES = 14;
var c_oserct_valaxCROSSESAT = 15;
var c_oserct_valaxCROSSBETWEEN = 16;
var c_oserct_valaxMAJORUNIT = 17;
var c_oserct_valaxMINORUNIT = 18;
var c_oserct_valaxDISPUNITS = 19;
var c_oserct_valaxEXTLST = 20;

var c_oserct_sizerepresentsVAL = 0;

var c_oserct_bubblescaleVAL = 0;

var c_oserct_bubbleserIDX = 0;
var c_oserct_bubbleserORDER = 1;
var c_oserct_bubbleserTX = 2;
var c_oserct_bubbleserSPPR = 3;
var c_oserct_bubbleserINVERTIFNEGATIVE = 4;
var c_oserct_bubbleserDPT = 5;
var c_oserct_bubbleserDLBLS = 6;
var c_oserct_bubbleserTRENDLINE = 7;
var c_oserct_bubbleserERRBARS = 8;
var c_oserct_bubbleserXVAL = 9;
var c_oserct_bubbleserYVAL = 10;
var c_oserct_bubbleserBUBBLESIZE = 11;
var c_oserct_bubbleserBUBBLE3D = 12;
var c_oserct_bubbleserEXTLST = 13;

var c_oserct_sertxSTRREF = 0;
var c_oserct_sertxV = 1;

var c_oserct_dptIDX = 0;
var c_oserct_dptINVERTIFNEGATIVE = 1;
var c_oserct_dptMARKER = 2;
var c_oserct_dptBUBBLE3D = 3;
var c_oserct_dptEXPLOSION = 4;
var c_oserct_dptSPPR = 5;
var c_oserct_dptPICTUREOPTIONS = 6;
var c_oserct_dptEXTLST = 7;

var c_oserct_markerSYMBOL = 0;
var c_oserct_markerSIZE = 1;
var c_oserct_markerSPPR = 2;
var c_oserct_markerEXTLST = 3;

var c_oserct_markerstyleVAL = 0;

var c_oserct_markersizeVAL = 0;

var c_oserct_pictureoptionsAPPLYTOFRONT = 0;
var c_oserct_pictureoptionsAPPLYTOSIDES = 1;
var c_oserct_pictureoptionsAPPLYTOEND = 2;
var c_oserct_pictureoptionsPICTUREFORMAT = 3;
var c_oserct_pictureoptionsPICTURESTACKUNIT = 4;

var c_oserct_pictureformatVAL = 0;

var c_oserct_picturestackunitVAL = 0;

var c_oserct_dlblsDLBL = 0;
var c_oserct_dlblsITEMS = 1;
var c_oserct_dlblsDLBLPOS = 2;
var c_oserct_dlblsDELETE = 3;
var c_oserct_dlblsLEADERLINES = 4;
var c_oserct_dlblsNUMFMT = 5;
var c_oserct_dlblsSEPARATOR = 6;
var c_oserct_dlblsSHOWBUBBLESIZE = 7;
var c_oserct_dlblsSHOWCATNAME = 8;
var c_oserct_dlblsSHOWLEADERLINES = 9;
var c_oserct_dlblsSHOWLEGENDKEY = 10;
var c_oserct_dlblsSHOWPERCENT = 11;
var c_oserct_dlblsSHOWSERNAME = 12;
var c_oserct_dlblsSHOWVAL = 13;
var c_oserct_dlblsSPPR = 14;
var c_oserct_dlblsTXPR = 15;
var c_oserct_dlblsEXTLST = 16;

var c_oserct_dlblIDX = 0;
var c_oserct_dlblITEMS = 1;
var c_oserct_dlblDLBLPOS = 2;
var c_oserct_dlblDELETE = 3;
var c_oserct_dlblLAYOUT = 4;
var c_oserct_dlblNUMFMT = 5;
var c_oserct_dlblSEPARATOR = 6;
var c_oserct_dlblSHOWBUBBLESIZE = 7;
var c_oserct_dlblSHOWCATNAME = 8;
var c_oserct_dlblSHOWLEGENDKEY = 9;
var c_oserct_dlblSHOWPERCENT = 10;
var c_oserct_dlblSHOWSERNAME = 11;
var c_oserct_dlblSHOWVAL = 12;
var c_oserct_dlblSPPR = 13;
var c_oserct_dlblTX = 14;
var c_oserct_dlblTXPR = 15;
var c_oserct_dlblEXTLST = 16;

var c_oserct_dlblposVAL = 0;

var c_oserct_trendlineNAME = 0;
var c_oserct_trendlineSPPR = 1;
var c_oserct_trendlineTRENDLINETYPE = 2;
var c_oserct_trendlineORDER = 3;
var c_oserct_trendlinePERIOD = 4;
var c_oserct_trendlineFORWARD = 5;
var c_oserct_trendlineBACKWARD = 6;
var c_oserct_trendlineINTERCEPT = 7;
var c_oserct_trendlineDISPRSQR = 8;
var c_oserct_trendlineDISPEQ = 9;
var c_oserct_trendlineTRENDLINELBL = 10;
var c_oserct_trendlineEXTLST = 11;

var c_oserct_trendlinetypeVAL = 0;

var c_oserct_orderVAL = 0;

var c_oserct_periodVAL = 0;

var c_oserct_trendlinelblLAYOUT = 0;
var c_oserct_trendlinelblTX = 1;
var c_oserct_trendlinelblNUMFMT = 2;
var c_oserct_trendlinelblSPPR = 3;
var c_oserct_trendlinelblTXPR = 4;
var c_oserct_trendlinelblEXTLST = 5;

var c_oserct_errbarsERRDIR = 0;
var c_oserct_errbarsERRBARTYPE = 1;
var c_oserct_errbarsERRVALTYPE = 2;
var c_oserct_errbarsNOENDCAP = 3;
var c_oserct_errbarsPLUS = 4;
var c_oserct_errbarsMINUS = 5;
var c_oserct_errbarsVAL = 6;
var c_oserct_errbarsSPPR = 7;
var c_oserct_errbarsEXTLST = 8;

var c_oserct_errdirVAL = 0;

var c_oserct_errbartypeVAL = 0;

var c_oserct_errvaltypeVAL = 0;

var c_oserct_numdatasourceNUMLIT = 0;
var c_oserct_numdatasourceNUMREF = 1;

var c_oserct_numdataFORMATCODE = 0;
var c_oserct_numdataPTCOUNT = 1;
var c_oserct_numdataPT = 2;
var c_oserct_numdataEXTLST = 3;

var c_oserct_numvalV = 0;
var c_oserct_numvalIDX = 1;
var c_oserct_numvalFORMATCODE = 2;

var c_oserct_numrefF = 0;
var c_oserct_numrefNUMCACHE = 1;
var c_oserct_numrefEXTLST = 2;

var c_oserct_axdatasourceMULTILVLSTRREF = 0;
var c_oserct_axdatasourceNUMLIT = 1;
var c_oserct_axdatasourceNUMREF = 2;
var c_oserct_axdatasourceSTRLIT = 3;
var c_oserct_axdatasourceSTRREF = 4;

var c_oserct_multilvlstrrefF = 0;
var c_oserct_multilvlstrrefMULTILVLSTRCACHE = 1;
var c_oserct_multilvlstrrefEXTLST = 2;

var c_oserct_lvlPT = 0;

var c_oserct_multilvlstrdataPTCOUNT = 0;
var c_oserct_multilvlstrdataLVL = 1;
var c_oserct_multilvlstrdataEXTLST = 2;

var c_oserct_bubblechartVARYCOLORS = 0;
var c_oserct_bubblechartSER = 1;
var c_oserct_bubblechartDLBLS = 2;
var c_oserct_bubblechartBUBBLE3D = 3;
var c_oserct_bubblechartBUBBLESCALE = 4;
var c_oserct_bubblechartSHOWNEGBUBBLES = 5;
var c_oserct_bubblechartSIZEREPRESENTS = 6;
var c_oserct_bubblechartAXID = 7;
var c_oserct_bubblechartEXTLST = 8;

var c_oserct_bandfmtsBANDFMT = 0;

var c_oserct_surface3dchartWIREFRAME = 0;
var c_oserct_surface3dchartSER = 1;
var c_oserct_surface3dchartBANDFMTS = 2;
var c_oserct_surface3dchartAXID = 3;
var c_oserct_surface3dchartEXTLST = 4;

var c_oserct_surfaceserIDX = 0;
var c_oserct_surfaceserORDER = 1;
var c_oserct_surfaceserTX = 2;
var c_oserct_surfaceserSPPR = 3;
var c_oserct_surfaceserCAT = 4;
var c_oserct_surfaceserVAL = 5;
var c_oserct_surfaceserEXTLST = 6;

var c_oserct_bandfmtIDX = 0;
var c_oserct_bandfmtSPPR = 1;

var c_oserct_surfacechartWIREFRAME = 0;
var c_oserct_surfacechartSER = 1;
var c_oserct_surfacechartBANDFMTS = 2;
var c_oserct_surfacechartAXID = 3;
var c_oserct_surfacechartEXTLST = 4;

var c_oserct_secondpiesizeVAL = 0;

var c_oserct_splittypeVAL = 0;

var c_oserct_ofpietypeVAL = 0;

var c_oserct_custsplitSECONDPIEPT = 0;

var c_oserct_ofpiechartOFPIETYPE = 0;
var c_oserct_ofpiechartVARYCOLORS = 1;
var c_oserct_ofpiechartSER = 2;
var c_oserct_ofpiechartDLBLS = 3;
var c_oserct_ofpiechartGAPWIDTH = 4;
var c_oserct_ofpiechartSPLITTYPE = 5;
var c_oserct_ofpiechartSPLITPOS = 6;
var c_oserct_ofpiechartCUSTSPLIT = 7;
var c_oserct_ofpiechartSECONDPIESIZE = 8;
var c_oserct_ofpiechartSERLINES = 9;
var c_oserct_ofpiechartEXTLST = 10;

var c_oserct_pieserIDX = 0;
var c_oserct_pieserORDER = 1;
var c_oserct_pieserTX = 2;
var c_oserct_pieserSPPR = 3;
var c_oserct_pieserEXPLOSION = 4;
var c_oserct_pieserDPT = 5;
var c_oserct_pieserDLBLS = 6;
var c_oserct_pieserCAT = 7;
var c_oserct_pieserVAL = 8;
var c_oserct_pieserEXTLST = 9;

var c_oserct_gapamountVAL = 0;

var c_oserct_bar3dchartBARDIR = 0;
var c_oserct_bar3dchartGROUPING = 1;
var c_oserct_bar3dchartVARYCOLORS = 2;
var c_oserct_bar3dchartSER = 3;
var c_oserct_bar3dchartDLBLS = 4;
var c_oserct_bar3dchartGAPWIDTH = 5;
var c_oserct_bar3dchartGAPDEPTH = 6;
var c_oserct_bar3dchartSHAPE = 7;
var c_oserct_bar3dchartAXID = 8;
var c_oserct_bar3dchartEXTLST = 9;

var c_oserct_bardirVAL = 0;

var c_oserct_bargroupingVAL = 0;

var c_oserct_barserIDX = 0;
var c_oserct_barserORDER = 1;
var c_oserct_barserTX = 2;
var c_oserct_barserSPPR = 3;
var c_oserct_barserINVERTIFNEGATIVE = 4;
var c_oserct_barserPICTUREOPTIONS = 5;
var c_oserct_barserDPT = 6;
var c_oserct_barserDLBLS = 7;
var c_oserct_barserTRENDLINE = 8;
var c_oserct_barserERRBARS = 9;
var c_oserct_barserCAT = 10;
var c_oserct_barserVAL = 11;
var c_oserct_barserSHAPE = 12;
var c_oserct_barserEXTLST = 13;

var c_oserct_shapeVAL = 0;

var c_oserct_overlapVAL = 0;

var c_oserct_barchartBARDIR = 0;
var c_oserct_barchartGROUPING = 1;
var c_oserct_barchartVARYCOLORS = 2;
var c_oserct_barchartSER = 3;
var c_oserct_barchartDLBLS = 4;
var c_oserct_barchartGAPWIDTH = 5;
var c_oserct_barchartOVERLAP = 6;
var c_oserct_barchartSERLINES = 7;
var c_oserct_barchartAXID = 8;
var c_oserct_barchartEXTLST = 9;

var c_oserct_holesizeVAL = 0;

var c_oserct_doughnutchartVARYCOLORS = 0;
var c_oserct_doughnutchartSER = 1;
var c_oserct_doughnutchartDLBLS = 2;
var c_oserct_doughnutchartFIRSTSLICEANG = 3;
var c_oserct_doughnutchartHOLESIZE = 4;
var c_oserct_doughnutchartEXTLST = 5;

var c_oserct_firstsliceangVAL = 0;

var c_oserct_pie3dchartVARYCOLORS = 0;
var c_oserct_pie3dchartSER = 1;
var c_oserct_pie3dchartDLBLS = 2;
var c_oserct_pie3dchartEXTLST = 3;

var c_oserct_piechartVARYCOLORS = 0;
var c_oserct_piechartSER = 1;
var c_oserct_piechartDLBLS = 2;
var c_oserct_piechartFIRSTSLICEANG = 3;
var c_oserct_piechartEXTLST = 4;

var c_oserct_scatterserIDX = 0;
var c_oserct_scatterserORDER = 1;
var c_oserct_scatterserTX = 2;
var c_oserct_scatterserSPPR = 3;
var c_oserct_scatterserMARKER = 4;
var c_oserct_scatterserDPT = 5;
var c_oserct_scatterserDLBLS = 6;
var c_oserct_scatterserTRENDLINE = 7;
var c_oserct_scatterserERRBARS = 8;
var c_oserct_scatterserXVAL = 9;
var c_oserct_scatterserYVAL = 10;
var c_oserct_scatterserSMOOTH = 11;
var c_oserct_scatterserEXTLST = 12;

var c_oserct_scatterstyleVAL = 0;

var c_oserct_scatterchartSCATTERSTYLE = 0;
var c_oserct_scatterchartVARYCOLORS = 1;
var c_oserct_scatterchartSER = 2;
var c_oserct_scatterchartDLBLS = 3;
var c_oserct_scatterchartAXID = 4;
var c_oserct_scatterchartEXTLST = 5;

var c_oserct_radarserIDX = 0;
var c_oserct_radarserORDER = 1;
var c_oserct_radarserTX = 2;
var c_oserct_radarserSPPR = 3;
var c_oserct_radarserMARKER = 4;
var c_oserct_radarserDPT = 5;
var c_oserct_radarserDLBLS = 6;
var c_oserct_radarserCAT = 7;
var c_oserct_radarserVAL = 8;
var c_oserct_radarserEXTLST = 9;

var c_oserct_radarstyleVAL = 0;

var c_oserct_radarchartRADARSTYLE = 0;
var c_oserct_radarchartVARYCOLORS = 1;
var c_oserct_radarchartSER = 2;
var c_oserct_radarchartDLBLS = 3;
var c_oserct_radarchartAXID = 4;
var c_oserct_radarchartEXTLST = 5;

var c_oserct_stockchartSER = 0;
var c_oserct_stockchartDLBLS = 1;
var c_oserct_stockchartDROPLINES = 2;
var c_oserct_stockchartHILOWLINES = 3;
var c_oserct_stockchartUPDOWNBARS = 4;
var c_oserct_stockchartAXID = 5;
var c_oserct_stockchartEXTLST = 6;

var c_oserct_lineserIDX = 0;
var c_oserct_lineserORDER = 1;
var c_oserct_lineserTX = 2;
var c_oserct_lineserSPPR = 3;
var c_oserct_lineserMARKER = 4;
var c_oserct_lineserDPT = 5;
var c_oserct_lineserDLBLS = 6;
var c_oserct_lineserTRENDLINE = 7;
var c_oserct_lineserERRBARS = 8;
var c_oserct_lineserCAT = 9;
var c_oserct_lineserVAL = 10;
var c_oserct_lineserSMOOTH = 11;
var c_oserct_lineserEXTLST = 12;

var c_oserct_updownbarsGAPWIDTH = 0;
var c_oserct_updownbarsUPBARS = 1;
var c_oserct_updownbarsDOWNBARS = 2;
var c_oserct_updownbarsEXTLST = 3;

var c_oserct_updownbarSPPR = 0;

var c_oserct_line3dchartGROUPING = 0;
var c_oserct_line3dchartVARYCOLORS = 1;
var c_oserct_line3dchartSER = 2;
var c_oserct_line3dchartDLBLS = 3;
var c_oserct_line3dchartDROPLINES = 4;
var c_oserct_line3dchartGAPDEPTH = 5;
var c_oserct_line3dchartAXID = 6;
var c_oserct_line3dchartEXTLST = 7;

var c_oserct_groupingVAL = 0;

var c_oserct_linechartGROUPING = 0;
var c_oserct_linechartVARYCOLORS = 1;
var c_oserct_linechartSER = 2;
var c_oserct_linechartDLBLS = 3;
var c_oserct_linechartDROPLINES = 4;
var c_oserct_linechartHILOWLINES = 5;
var c_oserct_linechartUPDOWNBARS = 6;
var c_oserct_linechartMARKER = 7;
var c_oserct_linechartSMOOTH = 8;
var c_oserct_linechartAXID = 9;
var c_oserct_linechartEXTLST = 10;

var c_oserct_area3dchartGROUPING = 0;
var c_oserct_area3dchartVARYCOLORS = 1;
var c_oserct_area3dchartSER = 2;
var c_oserct_area3dchartDLBLS = 3;
var c_oserct_area3dchartDROPLINES = 4;
var c_oserct_area3dchartGAPDEPTH = 5;
var c_oserct_area3dchartAXID = 6;
var c_oserct_area3dchartEXTLST = 7;

var c_oserct_areaserIDX = 0;
var c_oserct_areaserORDER = 1;
var c_oserct_areaserTX = 2;
var c_oserct_areaserSPPR = 3;
var c_oserct_areaserPICTUREOPTIONS = 4;
var c_oserct_areaserDPT = 5;
var c_oserct_areaserDLBLS = 6;
var c_oserct_areaserTRENDLINE = 7;
var c_oserct_areaserERRBARS = 8;
var c_oserct_areaserCAT = 9;
var c_oserct_areaserVAL = 10;
var c_oserct_areaserEXTLST = 11;

var c_oserct_areachartGROUPING = 0;
var c_oserct_areachartVARYCOLORS = 1;
var c_oserct_areachartSER = 2;
var c_oserct_areachartDLBLS = 3;
var c_oserct_areachartDROPLINES = 4;
var c_oserct_areachartAXID = 5;
var c_oserct_areachartEXTLST = 6;

var c_oserct_plotareaLAYOUT = 0;
var c_oserct_plotareaITEMS = 1;
var c_oserct_plotareaAREA3DCHART = 2;
var c_oserct_plotareaAREACHART = 3;
var c_oserct_plotareaBAR3DCHART = 4;
var c_oserct_plotareaBARCHART = 5;
var c_oserct_plotareaBUBBLECHART = 6;
var c_oserct_plotareaDOUGHNUTCHART = 7;
var c_oserct_plotareaLINE3DCHART = 8;
var c_oserct_plotareaLINECHART = 9;
var c_oserct_plotareaOFPIECHART = 10;
var c_oserct_plotareaPIE3DCHART = 11;
var c_oserct_plotareaPIECHART = 12;
var c_oserct_plotareaRADARCHART = 13;
var c_oserct_plotareaSCATTERCHART = 14;
var c_oserct_plotareaSTOCKCHART = 15;
var c_oserct_plotareaSURFACE3DCHART = 16;
var c_oserct_plotareaSURFACECHART = 17;
var c_oserct_plotareaITEMS1 = 18;
var c_oserct_plotareaCATAX = 19;
var c_oserct_plotareaDATEAX = 20;
var c_oserct_plotareaSERAX = 21;
var c_oserct_plotareaVALAX = 22;
var c_oserct_plotareaDTABLE = 23;
var c_oserct_plotareaSPPR = 24;
var c_oserct_plotareaEXTLST = 25;

var c_oserct_thicknessVAL = 0;

var c_oserct_surfaceTHICKNESS = 0;
var c_oserct_surfaceSPPR = 1;
var c_oserct_surfacePICTUREOPTIONS = 2;
var c_oserct_surfaceEXTLST = 3;

var c_oserct_perspectiveVAL = 0;

var c_oserct_depthpercentVAL = 0;

var c_oserct_rotyVAL = 0;

var c_oserct_hpercentVAL = 0;

var c_oserct_rotxVAL = 0;

var c_oserct_view3dROTX = 0;
var c_oserct_view3dHPERCENT = 1;
var c_oserct_view3dROTY = 2;
var c_oserct_view3dDEPTHPERCENT = 3;
var c_oserct_view3dRANGAX = 4;
var c_oserct_view3dPERSPECTIVE = 5;
var c_oserct_view3dEXTLST = 6;

var c_oserct_pivotfmtIDX = 0;
var c_oserct_pivotfmtSPPR = 1;
var c_oserct_pivotfmtTXPR = 2;
var c_oserct_pivotfmtMARKER = 3;
var c_oserct_pivotfmtDLBL = 4;
var c_oserct_pivotfmtEXTLST = 5;

var c_oserct_pivotfmtsPIVOTFMT = 0;

var c_oserct_chartTITLE = 0;
var c_oserct_chartAUTOTITLEDELETED = 1;
var c_oserct_chartPIVOTFMTS = 2;
var c_oserct_chartVIEW3D = 3;
var c_oserct_chartFLOOR = 4;
var c_oserct_chartSIDEWALL = 5;
var c_oserct_chartBACKWALL = 6;
var c_oserct_chartPLOTAREA = 7;
var c_oserct_chartLEGEND = 8;
var c_oserct_chartPLOTVISONLY = 9;
var c_oserct_chartDISPBLANKSAS = 10;
var c_oserct_chartSHOWDLBLSOVERMAX = 11;
var c_oserct_chartEXTLST = 12;

var c_oserct_protectionCHARTOBJECT = 0;
var c_oserct_protectionDATA = 1;
var c_oserct_protectionFORMATTING = 2;
var c_oserct_protectionSELECTION = 3;
var c_oserct_protectionUSERINTERFACE = 4;

var c_oserct_pivotsourceNAME = 0;
var c_oserct_pivotsourceFMTID = 1;
var c_oserct_pivotsourceEXTLST = 2;

var c_oserct_style1VAL = 0;

var c_oserct_styleVAL = 0;

var c_oserct_textlanguageidVAL = 0;

var c_oseralternatecontentCHOICE = 0;
var c_oseralternatecontentFALLBACK = 1;

var c_oseralternatecontentchoiceSTYLE = 0;
var c_oseralternatecontentchoiceREQUIRES = 1;

var c_oseralternatecontentfallbackSTYLE = 0;

var SIZE_REPRESENTS_AREA = 0;
var SIZE_REPRESENTS_W = 1;

var ERR_BAR_TYPE_BOTH = 0;
var ERR_BAR_TYPE_MINUS = 1;
var ERR_BAR_TYPE_PLUS = 2;

var ERR_DIR_X = 0;
var ERR_DIR_Y = 1;

var ERR_VAL_TYPE_CUST = 0;
var ERR_VAL_TYPE_FIXED_VAL = 1;
var ERR_VAL_TYPE_PERCENTAGE = 2;
var ERR_VAL_TYPE_STD_DEV = 3;
var ERR_VAL_TYPE_STD_ERR = 4;

var LAYOUT_TARGET_INNER = 0;
var LAYOUT_TARGET_OUTER = 1;

var LAYOUT_MODE_EDGE = 0;
var LAYOUT_MODE_FACTOR = 1;

var OF_PIE_TYPE_BAR = 0;
var OF_PIE_TYPE_PIE = 1;

var SPLIT_TYPE_AUTO = 0;
var SPLIT_TYPE_CUST = 1;
var SPLIT_TYPE_PERCENT = 2;
var SPLIT_TYPE_POS = 3;
var SPLIT_TYPE_VAL = 4;

var PICTURE_FORMAT_STACK = 0;
var PICTURE_FORMAT_STACK_SCALE = 1;
var PICTURE_FORMAT_STACK_STRETCH = 2;

var RADAR_STYLE_STANDARD = 0;
var RADAR_STYLE_MARKER = 1;
var RADAR_STYLE_FILLED = 2;

var TRENDLINE_TYPE_EXP = 0;
var TRENDLINE_TYPE_LINEAR = 1;
var TRENDLINE_TYPE_LOG = 2;
var TRENDLINE_TYPE_MOVING_AVG = 3;
var TRENDLINE_TYPE_POLY = 4;
var TRENDLINE_TYPE_POWER = 5;

function BinaryChartWriter(memory) {
    this.memory = memory;
    this.bs = new AscCommon.BinaryCommonWriter(this.memory);
}
BinaryChartWriter.prototype.WriteCT_extLst = function (oVal) {
    var oThis = this;
    if (null != oVal.m_ext) {
        for (var i = 0, length = oVal.m_ext.length; i < length; ++i) {
            var oCurVal = oVal.m_ext[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_extlstEXT, function () {
                    oThis.WriteCT_Extension(oCurVal);
                });
            }
        }
    }
}
BinaryChartWriter.prototype.WriteCT_ChartSpace = function (oVal) {
    var oThis = this;
    if (null != oVal.date1904) {
        this.bs.WriteItem(c_oserct_chartspaceDATE1904, function () {
            oThis.WriteCT_Boolean(oVal.date1904);
        });
    }
    if (null != oVal.lang) {
        this.bs.WriteItem(c_oserct_chartspaceLANG, function () {
            oThis.WriteCT_TextLanguageID(oVal.lang);
        });
    }
    if (null != oVal.roundedCorners) {
        this.bs.WriteItem(c_oserct_chartspaceROUNDEDCORNERS, function () {
            oThis.WriteCT_Boolean(oVal.roundedCorners);
        });
    }
    if (null != oVal.style) {
        this.bs.WriteItem(c_oserct_chartspaceALTERNATECONTENT, function () {
            oThis.bs.WriteItem(c_oseralternatecontentCHOICE, function () {
                oThis.bs.WriteItem(c_oseralternatecontentchoiceREQUIRES, function () {
                    oThis.memory.WriteString3("c14");
                });
                oThis.bs.WriteItem(c_oseralternatecontentchoiceSTYLE, function () {
                    oThis.WriteCT_Style(100 + oVal.style);
                });
            });
            oThis.bs.WriteItem(c_oseralternatecontentFALLBACK, function () {
                oThis.bs.WriteItem(c_oseralternatecontentfallbackSTYLE, function () {
                    oThis.WriteCT_Style1(oVal.style);
                });
            });
        });
    }
    var oCurVal = oVal.clrMapOvr;
    if (null != oCurVal) {
       this.bs.WriteItem(c_oserct_chartspaceCLRMAPOVR, function () {
            oThis.WriteClrMapOverride(oCurVal);
       });
    }
    if (null != oVal.pivotSource) {
        this.bs.WriteItem(c_oserct_chartspacePIVOTSOURCE, function () {
            oThis.WriteCT_PivotSource(oVal.pivotSource);
        });
    }
    if (null != oVal.protection) {
        this.bs.WriteItem(c_oserct_chartspacePROTECTION, function () {
            oThis.WriteCT_Protection(oVal.protection);
        });
    }
    if (null != oVal.chart) {
        this.bs.WriteItem(c_oserct_chartspaceCHART, function () {
            oThis.WriteCT_Chart(oVal.chart);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_chartspaceSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.txPr) {
        this.bs.WriteItem(c_oserct_chartspaceTXPR, function () {
            oThis.WriteTxPr(oVal.txPr);
        });
    }
    //var oCurVal = oVal.m_externalData;
    //if (null != oCurVal) {
    //    this.bs.WriteItem(c_oserct_chartspaceEXTERNALDATA, function () {
    //        oThis.WriteCT_ExternalData(oCurVal);
    //    });
    //}
    if (null != oVal.printSettings) {
        this.bs.WriteItem(c_oserct_chartspacePRINTSETTINGS, function () {
            oThis.WriteCT_PrintSettings(oVal.printSettings);
        });
    }
    //var oCurVal = oVal.m_userShapes;
    //if (null != oCurVal) {
    //    this.bs.WriteItem(c_oserct_chartspaceUSERSHAPES, function () {
    //        oThis.WriteCT_RelId(oCurVal);
    //    });
    //}
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_chartspaceEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
    if (null != oVal.themeOverride)
	    this.bs.WriteItem(c_oserct_chartspaceTHEMEOVERRIDE, function () { AscCommon.pptx_content_writer.WriteTheme(oThis.memory, oVal.themeOverride); });
}
BinaryChartWriter.prototype.WriteSpPr = function (oVal) {
  AscCommon.pptx_content_writer.WriteSpPr(this.memory, oVal);
}
BinaryChartWriter.prototype.WriteClrMapOverride = function (oVal) {
  AscCommon.pptx_content_writer.WriteClrMapOverride(this.memory, oVal);
}
BinaryChartWriter.prototype.WriteTxPr = function (oVal) {
  AscCommon.pptx_content_writer.WriteTextBody(this.memory, oVal);
}
BinaryChartWriter.prototype.percentToString = function (val, bInteger, bSign) {
    var sRes;
    if (bInteger)
        sRes = parseInt(val).toString();
    else
        sRes = val.toString();
    if (bSign)
        sRes += "%";
    return sRes;
}
BinaryChartWriter.prototype.metricToString = function (val, bInteger) {
    var sRes;
    if (bInteger)
        sRes = parseInt(val).toString();
    else
        sRes = val.toString();
    sRes += "mm";
    return sRes;
}
BinaryChartWriter.prototype.WriteCT_Boolean = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_booleanVAL, function () {
            oThis.memory.WriteBool(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_RelId = function (oVal) {
    var oThis = this;
    var oCurVal = oVal.m_id;
    if (null != oCurVal) {
        this.bs.WriteItem(c_oserct_relidID, function () {
            //todo
            oThis.memory.WriteString3(oCurVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_PageSetup = function (oVal) {
    var oThis = this;
    if (null != oVal.paperSize) {
        this.bs.WriteItem(c_oserct_pagesetupPAPERSIZE, function () {
            oThis.memory.WriteLong(oVal.paperSize);
        });
    }
    if (null != oVal.paperHeight) {
        this.bs.WriteItem(c_oserct_pagesetupPAPERHEIGHT, function () {
            oThis.memory.WriteString3(oThis.metricToString(oVal.paperHeight, false));
        });
    }
    if (null != oVal.paperWidth) {
        this.bs.WriteItem(c_oserct_pagesetupPAPERWIDTH, function () {
            oThis.memory.WriteString3(oThis.metricToString(oVal.paperWidth, false));
        });
    }
    if (null != oVal.firstPageNumber) {
        this.bs.WriteItem(c_oserct_pagesetupFIRSTPAGENUMBER, function () {
            oThis.memory.WriteLong(oVal.firstPageNumber);
        });
    }
    if (null != oVal.orientation) {
        var nVal = null;
        switch (oVal.orientation) {
            case AscFormat.PAGE_SETUP_ORIENTATION_DEFAULT: nVal = st_pagesetuporientationDEFAULT; break;
            case AscFormat.PAGE_SETUP_ORIENTATION_PORTRAIT: nVal = st_pagesetuporientationPORTRAIT; break;
            case AscFormat.PAGE_SETUP_ORIENTATION_LANDSCAPE: nVal = st_pagesetuporientationLANDSCAPE; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_pagesetupORIENTATION, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
    if (null != oVal.blackAndWhite) {
        this.bs.WriteItem(c_oserct_pagesetupBLACKANDWHITE, function () {
            oThis.memory.WriteBool(oVal.blackAndWhite);
        });
    }
    if (null != oVal.draft) {
        this.bs.WriteItem(c_oserct_pagesetupDRAFT, function () {
            oThis.memory.WriteBool(oVal.draft);
        });
    }
    if (null != oVal.useFirstPageNumb) {
        this.bs.WriteItem(c_oserct_pagesetupUSEFIRSTPAGENUMBER, function () {
            oThis.memory.WriteBool(oVal.useFirstPageNumb);
        });
    }
    if (null != oVal.horizontalDpi) {
        this.bs.WriteItem(c_oserct_pagesetupHORIZONTALDPI, function () {
            oThis.memory.WriteLong(oVal.horizontalDpi);
        });
    }
    if (null != oVal.verticalDpi) {
        this.bs.WriteItem(c_oserct_pagesetupVERTICALDPI, function () {
            oThis.memory.WriteLong(oVal.verticalDpi);
        });
    }
    if (null != oVal.copies) {
        this.bs.WriteItem(c_oserct_pagesetupCOPIES, function () {
            oThis.memory.WriteLong(oVal.copies);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_PageMargins = function (oVal) {
    var oThis = this;
    if (null != oVal.l) {
        this.bs.WriteItem(c_oserct_pagemarginsL, function () {
            oThis.memory.WriteDouble2(oVal.l);
        });
    }
    if (null != oVal.r) {
        this.bs.WriteItem(c_oserct_pagemarginsR, function () {
            oThis.memory.WriteDouble2(oVal.r);
        });
    }
    if (null != oVal.t) {
        this.bs.WriteItem(c_oserct_pagemarginsT, function () {
            oThis.memory.WriteDouble2(oVal.t);
        });
    }
    if (null != oVal.b) {
        this.bs.WriteItem(c_oserct_pagemarginsB, function () {
            oThis.memory.WriteDouble2(oVal.b);
        });
    }
    if (null != oVal.header) {
        this.bs.WriteItem(c_oserct_pagemarginsHEADER, function () {
            oThis.memory.WriteDouble2(oVal.header);
        });
    }
    if (null != oVal.footer) {
        this.bs.WriteItem(c_oserct_pagemarginsFOOTER, function () {
            oThis.memory.WriteDouble2(oVal.footer);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_HeaderFooter = function (oVal) {
    var oThis = this;
    if (null != oVal.oddHeader) {
        this.bs.WriteItem(c_oserct_headerfooterODDHEADER, function () {
            oThis.memory.WriteString3(oVal.oddHeader);
        });
    }
    if (null != oVal.oddFooter) {
        this.bs.WriteItem(c_oserct_headerfooterODDFOOTER, function () {
            oThis.memory.WriteString3(oVal.oddFooter);
        });
    }
    if (null != oVal.evenHeader) {
        this.bs.WriteItem(c_oserct_headerfooterEVENHEADER, function () {
            oThis.memory.WriteString3(oVal.evenHeader);
        });
    }
    if (null != oVal.evenFooter) {
        this.bs.WriteItem(c_oserct_headerfooterEVENFOOTER, function () {
            oThis.memory.WriteString3(oVal.evenFooter);
        });
    }
    if (null != oVal.firstHeader) {
        this.bs.WriteItem(c_oserct_headerfooterFIRSTHEADER, function () {
            oThis.memory.WriteString3(oVal.firstHeader);
        });
    }
    if (null != oVal.firstFooter) {
        this.bs.WriteItem(c_oserct_headerfooterFIRSTFOOTER, function () {
            oThis.memory.WriteString3(oVal.firstFooter);
        });
    }
    if (null != oVal.alignWithMargins) {
        this.bs.WriteItem(c_oserct_headerfooterALIGNWITHMARGINS, function () {
            oThis.memory.WriteBool(oVal.alignWithMargins);
        });
    }
    if (null != oVal.differentOddEven) {
        this.bs.WriteItem(c_oserct_headerfooterDIFFERENTODDEVEN, function () {
            oThis.memory.WriteBool(oVal.differentOddEven);
        });
    }
    if (null != oVal.differentFirst) {
        this.bs.WriteItem(c_oserct_headerfooterDIFFERENTFIRST, function () {
            oThis.memory.WriteBool(oVal.differentFirst);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_PrintSettings = function (oVal) {
    var oThis = this;
    if (null != oVal.headerFooter) {
        this.bs.WriteItem(c_oserct_printsettingsHEADERFOOTER, function () {
            oThis.WriteCT_HeaderFooter(oVal.headerFooter);
        });
    }
    if (null != oVal.pageMargins) {
        this.bs.WriteItem(c_oserct_printsettingsPAGEMARGINS, function () {
            oThis.WriteCT_PageMargins(oVal.pageMargins);
        });
    }
    if (null != oVal.pageSetup) {
        this.bs.WriteItem(c_oserct_printsettingsPAGESETUP, function () {
            oThis.WriteCT_PageSetup(oVal.pageSetup);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_ExternalData = function (oVal) {
    var oThis = this;
    var oCurVal = oVal.m_autoUpdate;
    if (null != oCurVal) {
        this.bs.WriteItem(c_oserct_externaldataAUTOUPDATE, function () {
            oThis.WriteCT_Boolean(oCurVal);
        });
    }
    var oCurVal = oVal.m_id;
    if (null != oCurVal) {
        this.bs.WriteItem(c_oserct_externaldataID, function () {
            //todo
            oThis.memory.WriteString3(oCurVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_DispBlanksAs = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case AscFormat.DISP_BLANKS_AS_SPAN: nVal = st_dispblanksasSPAN; break;
            case AscFormat.DISP_BLANKS_AS_GAP: nVal = st_dispblanksasGAP; break;
            case AscFormat.DISP_BLANKS_AS_ZERO: nVal = st_dispblanksasZERO; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_dispblanksasVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_LegendEntry = function (oVal) {
    var oThis = this;
    if (null != oVal.idx) {
        this.bs.WriteItem(c_oserct_legendentryIDX, function () {
            oThis.WriteCT_UnsignedInt(oVal.idx);
        });
    }
    if (null != oVal.bDelete) {
        this.bs.WriteItem(c_oserct_legendentryDELETE, function () {
            oThis.WriteCT_Boolean(oVal.bDelete);
        });
    }
    if (null != oVal.txPr) {
        this.bs.WriteItem(c_oserct_legendentryTXPR, function () {
            oThis.WriteTxPr(oVal.txPr);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_legendentryEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_UnsignedInt = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_unsignedintVAL, function () {
            oThis.memory.WriteLong(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_Extension = function (oVal) {
    var oThis = this;
    var oCurVal = oVal.m_Any;
    if (null != oCurVal) {
        this.bs.WriteItem(c_oserct_extensionANY, function () {
            oThis.memory.WriteString3(oCurVal);
        });
    }
    var oCurVal = oVal.m_uri;
    if (null != oCurVal) {
        this.bs.WriteItem(c_oserct_extensionURI, function () {
            oThis.memory.WriteString3(oCurVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_LegendPos = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case c_oAscChartLegendShowSettings.bottom: nVal = st_legendposB; break;
            case c_oAscChartLegendShowSettings.topRight: nVal = st_legendposTR; break;
            case c_oAscChartLegendShowSettings.left:
            case c_oAscChartLegendShowSettings.leftOverlay:
              nVal = st_legendposL; break;
            case c_oAscChartLegendShowSettings.right:
            case c_oAscChartLegendShowSettings.rightOverlay:
              nVal = st_legendposR; break;
            case c_oAscChartLegendShowSettings.top: nVal = st_legendposT; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_legendposVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_Legend = function (oVal) {
    var oThis = this;
    if (null != oVal.legendPos) {
        this.bs.WriteItem(c_oserct_legendLEGENDPOS, function () {
            oThis.WriteCT_LegendPos(oVal.legendPos);
        });
    }
    if (null != oVal.legendEntryes) {
        for (var i = 0, length = oVal.legendEntryes.length; i < length; ++i) {
            var oCurVal = oVal.legendEntryes[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_legendLEGENDENTRY, function () {
                    oThis.WriteCT_LegendEntry(oCurVal);
                });
            }
        }
    }
    this.bs.WriteItem(c_oserct_legendLAYOUT, function () {
        oThis.WriteCT_Layout(oVal);
    });
    if (null != oVal.overlay) {
        this.bs.WriteItem(c_oserct_legendOVERLAY, function () {
            oThis.WriteCT_Boolean(oVal.overlay);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_legendSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.txPr) {
        this.bs.WriteItem(c_oserct_legendTXPR, function () {
            oThis.WriteTxPr(oVal.txPr);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_legendEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_Layout = function (oVal) {
    var oThis = this;
    if (null != oVal.layout) {
        this.bs.WriteItem(c_oserct_layoutMANUALLAYOUT, function () {
            oThis.WriteCT_ManualLayout(oVal.layout);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_layoutEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_ManualLayout = function (oVal) {
    var oThis = this;
    if (null != oVal.layoutTarget) {
        this.bs.WriteItem(c_oserct_manuallayoutLAYOUTTARGET, function () {
            oThis.WriteCT_LayoutTarget(oVal.layoutTarget);
        });
    }
    if (null != oVal.xMode) {
        this.bs.WriteItem(c_oserct_manuallayoutXMODE, function () {
            oThis.WriteCT_LayoutMode(oVal.xMode);
        });
    }
    if (null != oVal.yMode) {
        this.bs.WriteItem(c_oserct_manuallayoutYMODE, function () {
            oThis.WriteCT_LayoutMode(oVal.yMode);
        });
    }
    if (null != oVal.wMode) {
        this.bs.WriteItem(c_oserct_manuallayoutWMODE, function () {
            oThis.WriteCT_LayoutMode(oVal.wMode);
        });
    }
    if (null != oVal.hMode) {
        this.bs.WriteItem(c_oserct_manuallayoutHMODE, function () {
            oThis.WriteCT_LayoutMode(oVal.hMode);
        });
    }
    if (null != oVal.x) {
        this.bs.WriteItem(c_oserct_manuallayoutX, function () {
            oThis.WriteCT_Double(oVal.x);
        });
    }
    if (null != oVal.y) {
        this.bs.WriteItem(c_oserct_manuallayoutY, function () {
            oThis.WriteCT_Double(oVal.y);
        });
    }
    if (null != oVal.w) {
        this.bs.WriteItem(c_oserct_manuallayoutW, function () {
            oThis.WriteCT_Double(oVal.w);
        });
    }
    if (null != oVal.h) {
        this.bs.WriteItem(c_oserct_manuallayoutH, function () {
            oThis.WriteCT_Double(oVal.h);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_manuallayoutEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_LayoutTarget = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case LAYOUT_TARGET_INNER: nVal = st_layouttargetINNER; break;
            case LAYOUT_TARGET_OUTER: nVal = st_layouttargetOUTER; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_layouttargetVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_LayoutMode = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case LAYOUT_MODE_EDGE: nVal = st_layoutmodeEDGE; break;
            case LAYOUT_MODE_FACTOR: nVal = st_layoutmodeFACTOR; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_layoutmodeVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_Double = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_doubleVAL, function () {
            oThis.memory.WriteDouble2(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_DTable = function (oVal) {
    var oThis = this;
    if (null != oVal.showHorzBorder) {
        this.bs.WriteItem(c_oserct_dtableSHOWHORZBORDER, function () {
            oThis.WriteCT_Boolean(oVal.showHorzBorder);
        });
    }
    if (null != oVal.showVertBorder) {
        this.bs.WriteItem(c_oserct_dtableSHOWVERTBORDER, function () {
            oThis.WriteCT_Boolean(oVal.showVertBorder);
        });
    }
    if (null != oVal.showOutline) {
        this.bs.WriteItem(c_oserct_dtableSHOWOUTLINE, function () {
            oThis.WriteCT_Boolean(oVal.showOutline);
        });
    }
    if (null != oVal.showKeys) {
        this.bs.WriteItem(c_oserct_dtableSHOWKEYS, function () {
            oThis.WriteCT_Boolean(oVal.showKeys);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_dtableSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.txPr) {
        this.bs.WriteItem(c_oserct_dtableTXPR, function () {
            oThis.WriteTxPr(oVal.txPr);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_dtableEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_SerAx = function (oVal) {
    var oThis = this;
    if (null != oVal.axId) {
        this.bs.WriteItem(c_oserct_seraxAXID, function () {
            oThis.WriteCT_UnsignedInt(oVal.axId);
        });
    }
    if (null != oVal.scaling) {
        this.bs.WriteItem(c_oserct_seraxSCALING, function () {
            oThis.WriteCT_Scaling(oVal.scaling);
        });
    }
    if (null != oVal.bDelete) {
        this.bs.WriteItem(c_oserct_seraxDELETE, function () {
            oThis.WriteCT_Boolean(oVal.bDelete);
        });
    }
    if (null != oVal.axPos) {
        this.bs.WriteItem(c_oserct_seraxAXPOS, function () {
            oThis.WriteCT_AxPos(oVal.axPos);
        });
    }
    if (null != oVal.majorGridlines) {
        this.bs.WriteItem(c_oserct_seraxMAJORGRIDLINES, function () {
            oThis.WriteCT_ChartLines(oVal.majorGridlines);
        });
    }
    if (null != oVal.minorGridlines) {
        this.bs.WriteItem(c_oserct_seraxMINORGRIDLINES, function () {
            oThis.WriteCT_ChartLines(oVal.minorGridlines);
        });
    }
   if (null != oVal.title) {
   this.bs.WriteItem(c_oserct_seraxTITLE, function () {
    oThis.WriteCT_Title(oVal.title);
    });
   }
    if (null != oVal.numFmt) {
        this.bs.WriteItem(c_oserct_seraxNUMFMT, function () {
            oThis.WriteCT_NumFmt(oVal.numFmt);
        });
    }
    if (null != oVal.majorTickMark) {
        this.bs.WriteItem(c_oserct_seraxMAJORTICKMARK, function () {
            oThis.WriteCT_TickMark(oVal.majorTickMark);
        });
    }
    if (null != oVal.minorTickMark) {
        this.bs.WriteItem(c_oserct_seraxMINORTICKMARK, function () {
            oThis.WriteCT_TickMark(oVal.minorTickMark);
        });
    }
    if (null != oVal.tickLblPos) {
        this.bs.WriteItem(c_oserct_seraxTICKLBLPOS, function () {
            oThis.WriteCT_TickLblPos(oVal.tickLblPos);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_seraxSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.txPr) {
        this.bs.WriteItem(c_oserct_seraxTXPR, function () {
            oThis.WriteTxPr(oVal.txPr);
        });
    }
    if (null != oVal.crossAx) {
        this.bs.WriteItem(c_oserct_seraxCROSSAX, function () {
            oThis.WriteCT_UnsignedInt(oVal.crossAx.axId);
        });
    }
    if (null != oVal.crosses) {
        this.bs.WriteItem(c_oserct_seraxCROSSES, function () {
            oThis.WriteCT_Crosses(oVal.crosses);
        });
    }
    if (null != oVal.crossesAt) {
        this.bs.WriteItem(c_oserct_seraxCROSSESAT, function () {
            oThis.WriteCT_Double(oVal.crossesAt);
        });
    }
    if (null != oVal.tickLblSkip) {
        this.bs.WriteItem(c_oserct_seraxTICKLBLSKIP, function () {
            oThis.WriteCT_Skip(oVal.tickLblSkip);
        });
    }
    if (null != oVal.tickMarkSkip) {
        this.bs.WriteItem(c_oserct_seraxTICKMARKSKIP, function () {
            oThis.WriteCT_Skip(oVal.tickMarkSkip);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_seraxEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_Scaling = function (oVal) {
    var oThis = this;
    if (null != oVal.logBase) {
        this.bs.WriteItem(c_oserct_scalingLOGBASE, function () {
            oThis.WriteCT_LogBase(oVal.logBase);
        });
    }
    if (null != oVal.orientation) {
        this.bs.WriteItem(c_oserct_scalingORIENTATION, function () {
            oThis.WriteCT_Orientation(oVal.orientation);
        });
    }
    if (null != oVal.max) {
        this.bs.WriteItem(c_oserct_scalingMAX, function () {
            oThis.WriteCT_Double(oVal.max);
        });
    }
    if (null != oVal.min) {
        this.bs.WriteItem(c_oserct_scalingMIN, function () {
            oThis.WriteCT_Double(oVal.min);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_scalingEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_LogBase = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_logbaseVAL, function () {
            oThis.memory.WriteDouble2(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_Orientation = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case AscFormat.ORIENTATION_MAX_MIN: nVal = st_orientationMAXMIN; break;
            case AscFormat.ORIENTATION_MIN_MAX: nVal = st_orientationMINMAX; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_orientationVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_AxPos = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case AscFormat.AX_POS_B: nVal = st_axposB; break;
            case AscFormat.AX_POS_L: nVal = st_axposL; break;
            case AscFormat.AX_POS_R: nVal = st_axposR; break;
            case AscFormat.AX_POS_T: nVal = st_axposT; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_axposVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_ChartLines = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_chartlinesSPPR, function () {
            oThis.WriteSpPr(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_Title = function (oVal) {
    var oThis = this;
    if (null != oVal.tx) {
        this.bs.WriteItem(c_oserct_titleTX, function () {
            oThis.WriteCT_Tx(oVal.tx);
        });
    }
    this.bs.WriteItem(c_oserct_titleLAYOUT, function () {
        oThis.WriteCT_Layout(oVal);
    });
    if (null != oVal.overlay) {
        this.bs.WriteItem(c_oserct_titleOVERLAY, function () {
            oThis.WriteCT_Boolean(oVal.overlay);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_titleSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.txPr) {
        this.bs.WriteItem(c_oserct_titleTXPR, function () {
            oThis.WriteTxPr(oVal.txPr);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_titleEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_Tx = function (oVal) {
    var oThis = this;
    if (null != oVal.rich) {
        this.bs.WriteItem(c_oserct_txRICH, function () {
            oThis.WriteTxPr(oVal.rich);
        });
    }
    if (null != oVal.strRef) {
        this.bs.WriteItem(c_oserct_txSTRREF, function () {
            oThis.WriteCT_StrRef(oVal.strRef);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_StrRef = function (oVal) {
    var oThis = this;
    if (null != oVal.f) {
        this.bs.WriteItem(c_oserct_strrefF, function () {
            oThis.memory.WriteString3(oVal.f);
        });
    }
    if (null != oVal.strCache) {
        this.bs.WriteItem(c_oserct_strrefSTRCACHE, function () {
            oThis.WriteCT_StrData(oVal.strCache);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_strrefEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_StrData = function (oVal) {
    var oThis = this;
    if (null != oVal.ptCount) {
        this.bs.WriteItem(c_oserct_strdataPTCOUNT, function () {
            oThis.WriteCT_UnsignedInt(oVal.ptCount);
        });
    }
    if (null != oVal.pts) {
        for (var i = 0, length = oVal.pts.length; i < length; ++i) {
            var oCurVal = oVal.pts[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_strdataPT, function () {
                    oThis.WriteCT_StrVal(oCurVal);
                });
            }
        }
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_strdataEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_StrVal = function (oVal) {
    var oThis = this;
    if (null != oVal.val) {
        this.bs.WriteItem(c_oserct_strvalV, function () {
            oThis.memory.WriteString3(oVal.val);
        });
    }
    if (null != oVal.idx) {
        this.bs.WriteItem(c_oserct_strvalIDX, function () {
            oThis.memory.WriteLong(oVal.idx);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_NumFmt = function (oVal) {
    var oThis = this;
    if (null != oVal.formatCode) {
        this.bs.WriteItem(c_oserct_numfmtFORMATCODE, function () {
            oThis.memory.WriteString3(oVal.formatCode);
        });
    }
    if (null != oVal.sourceLinked) {
        this.bs.WriteItem(c_oserct_numfmtSOURCELINKED, function () {
            oThis.memory.WriteBool(oVal.sourceLinked);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_TickMark = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case c_oAscTickMark.TICK_MARK_CROSS: nVal = st_tickmarkCROSS; break;
            case c_oAscTickMark.TICK_MARK_IN: nVal = st_tickmarkIN; break;
            case c_oAscTickMark.TICK_MARK_NONE: nVal = st_tickmarkNONE; break;
            case c_oAscTickMark.TICK_MARK_OUT: nVal = st_tickmarkOUT; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_tickmarkVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_TickLblPos = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case c_oAscTickLabelsPos.TICK_LABEL_POSITION_HIGH: nVal = st_ticklblposHIGH; break;
            case c_oAscTickLabelsPos.TICK_LABEL_POSITION_LOW: nVal = st_ticklblposLOW; break;
            case c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO: nVal = st_ticklblposNEXTTO; break;
            case c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE: nVal = st_ticklblposNONE; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_ticklblposVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_Crosses = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case AscFormat.CROSSES_AUTO_ZERO: nVal = st_crossesAUTOZERO; break;
            case AscFormat.CROSSES_MAX: nVal = st_crossesMAX; break;
            case AscFormat.CROSSES_MIN: nVal = st_crossesMIN; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_crossesVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_Skip = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_skipVAL, function () {
            oThis.memory.WriteLong(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_TimeUnit = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case AscFormat.TIME_UNIT_DAYS: nVal = st_timeunitDAYS; break;
            case AscFormat.TIME_UNIT_MONTHS: nVal = st_timeunitMONTHS; break;
            case AscFormat.TIME_UNIT_YEARS: nVal = st_timeunitYEARS; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_timeunitVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_DateAx = function (oVal) {
    var oThis = this;
    if (null != oVal.axId) {
        this.bs.WriteItem(c_oserct_dateaxAXID, function () {
            oThis.WriteCT_UnsignedInt(oVal.axId);
        });
    }
    if (null != oVal.scaling) {
        this.bs.WriteItem(c_oserct_dateaxSCALING, function () {
            oThis.WriteCT_Scaling(oVal.scaling);
        });
    }
    if (null != oVal.bDelete) {
        this.bs.WriteItem(c_oserct_dateaxDELETE, function () {
            oThis.WriteCT_Boolean(oVal.bDelete);
        });
    }
    if (null != oVal.axPos) {
        this.bs.WriteItem(c_oserct_dateaxAXPOS, function () {
            oThis.WriteCT_AxPos(oVal.axPos);
        });
    }
    if (null != oVal.majorGridlines) {
        this.bs.WriteItem(c_oserct_dateaxMAJORGRIDLINES, function () {
            oThis.WriteCT_ChartLines(oVal.majorGridlines);
        });
    }
    if (null != oVal.minorGridlines) {
        this.bs.WriteItem(c_oserct_dateaxMINORGRIDLINES, function () {
            oThis.WriteCT_ChartLines(oVal.minorGridlines);
        });
    }
   if (null != oVal.title) {
    this.bs.WriteItem(c_oserct_dateaxTITLE, function () {
        oThis.WriteCT_Title(oVal.title);
        });
   }
    if (null != oVal.numFmt) {
        this.bs.WriteItem(c_oserct_dateaxNUMFMT, function () {
            oThis.WriteCT_NumFmt(oVal.numFmt);
        });
    }
    if (null != oVal.majorTickMark) {
        this.bs.WriteItem(c_oserct_dateaxMAJORTICKMARK, function () {
            oThis.WriteCT_TickMark(oVal.majorTickMark);
        });
    }
    if (null != oVal.minorTickMark) {
        this.bs.WriteItem(c_oserct_dateaxMINORTICKMARK, function () {
            oThis.WriteCT_TickMark(oVal.minorTickMark);
        });
    }
    if (null != oVal.tickLblPos) {
        this.bs.WriteItem(c_oserct_dateaxTICKLBLPOS, function () {
            oThis.WriteCT_TickLblPos(oVal.tickLblPos);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_dateaxSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.txPr) {
        this.bs.WriteItem(c_oserct_dateaxTXPR, function () {
            oThis.WriteTxPr(oVal.txPr);
        });
    }
    if (null != oVal.crossAx) {
        this.bs.WriteItem(c_oserct_dateaxCROSSAX, function () {
            oThis.WriteCT_UnsignedInt(oVal.crossAx.axId);
        });
    }
    if (null != oVal.crosses) {
        this.bs.WriteItem(c_oserct_dateaxCROSSES, function () {
            oThis.WriteCT_Crosses(oVal.crosses);
        });
    }
    if (null != oVal.crossesAt) {
        this.bs.WriteItem(c_oserct_dateaxCROSSESAT, function () {
            oThis.WriteCT_Double(oVal.crossesAt);
        });
    }
    if (null != oVal.auto) {
        this.bs.WriteItem(c_oserct_dateaxAUTO, function () {
            oThis.WriteCT_Boolean(oVal.auto);
        });
    }
    if (null != oVal.lblOffset) {
        this.bs.WriteItem(c_oserct_dateaxLBLOFFSET, function () {
            oThis.WriteCT_LblOffset(oVal.lblOffset);
        });
    }
    if (null != oVal.baseTimeUnit) {
        this.bs.WriteItem(c_oserct_dateaxBASETIMEUNIT, function () {
            oThis.WriteCT_TimeUnit(oVal.baseTimeUnit);
        });
    }
    if (null != oVal.majorUnit) {
        this.bs.WriteItem(c_oserct_dateaxMAJORUNIT, function () {
            oThis.WriteCT_AxisUnit(oVal.majorUnit);
        });
    }
    if (null != oVal.majorTimeUnit) {
        this.bs.WriteItem(c_oserct_dateaxMAJORTIMEUNIT, function () {
            oThis.WriteCT_TimeUnit(oVal.majorTimeUnit);
        });
    }
    if (null != oVal.minorUnit) {
        this.bs.WriteItem(c_oserct_dateaxMINORUNIT, function () {
            oThis.WriteCT_AxisUnit(oVal.minorUnit);
        });
    }
    if (null != oVal.minorTimeUnit) {
        this.bs.WriteItem(c_oserct_dateaxMINORTIMEUNIT, function () {
            oThis.WriteCT_TimeUnit(oVal.minorTimeUnit);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_dateaxEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_LblOffset = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_lbloffsetVAL, function () {
            oThis.memory.WriteString3(oThis.percentToString(oVal, true, false));
        });
    }
}
BinaryChartWriter.prototype.WriteCT_AxisUnit = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_axisunitVAL, function () {
            oThis.memory.WriteDouble2(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_LblAlgn = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case AscFormat.LBL_ALG_CTR: nVal = st_lblalgnCTR; break;
            case AscFormat.LBL_ALG_L: nVal = st_lblalgnL; break;
            case AscFormat.LBL_ALG_R: nVal = st_lblalgnR; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_lblalgnVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_CatAx = function (oVal) {
    //todo ax
    var oThis = this;
    if (null != oVal.axId) {
        this.bs.WriteItem(c_oserct_cataxAXID, function () {
            oThis.WriteCT_UnsignedInt(oVal.axId);
        });
    }
    if (null != oVal.scaling) {
        this.bs.WriteItem(c_oserct_cataxSCALING, function () {
            oThis.WriteCT_Scaling(oVal.scaling);
        });
    }
    if (null != oVal.bDelete) {
        this.bs.WriteItem(c_oserct_cataxDELETE, function () {
            oThis.WriteCT_Boolean(oVal.bDelete);
        });
    }
    if (null != oVal.axPos) {
        this.bs.WriteItem(c_oserct_cataxAXPOS, function () {
            oThis.WriteCT_AxPos(oVal.axPos);
        });
    }
    if (null != oVal.majorGridlines) {
        this.bs.WriteItem(c_oserct_cataxMAJORGRIDLINES, function () {
            oThis.WriteCT_ChartLines(oVal.majorGridlines);
        });
    }
    if (null != oVal.minorGridlines) {
        this.bs.WriteItem(c_oserct_cataxMINORGRIDLINES, function () {
            oThis.WriteCT_ChartLines(oVal.minorGridlines);
        });
    }
     if (null != oVal.title) {
     this.bs.WriteItem(c_oserct_cataxTITLE, function () {
     oThis.WriteCT_Title(oVal.title);
     });
     }
    if (null != oVal.numFmt) {
        this.bs.WriteItem(c_oserct_cataxNUMFMT, function () {
            oThis.WriteCT_NumFmt(oVal.numFmt);
        });
    }
    if (null != oVal.majorTickMark) {
        this.bs.WriteItem(c_oserct_cataxMAJORTICKMARK, function () {
            oThis.WriteCT_TickMark(oVal.majorTickMark);
        });
    }
    if (null != oVal.minorTickMark) {
        this.bs.WriteItem(c_oserct_cataxMINORTICKMARK, function () {
            oThis.WriteCT_TickMark(oVal.minorTickMark);
        });
    }
    if (null != oVal.tickLblPos) {
        this.bs.WriteItem(c_oserct_cataxTICKLBLPOS, function () {
            oThis.WriteCT_TickLblPos(oVal.tickLblPos);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_cataxSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.txPr) {
        this.bs.WriteItem(c_oserct_cataxTXPR, function () {
            oThis.WriteTxPr(oVal.txPr);
        });
    }
    if (null != oVal.crossAx) {
        this.bs.WriteItem(c_oserct_cataxCROSSAX, function () {
            oThis.WriteCT_UnsignedInt(oVal.crossAx.axId);
        });
    }
    if (null != oVal.crosses) {
        this.bs.WriteItem(c_oserct_cataxCROSSES, function () {
            oThis.WriteCT_Crosses(oVal.crosses);
        });
    }
    if (null != oVal.crossesAt) {
        this.bs.WriteItem(c_oserct_cataxCROSSESAT, function () {
            oThis.WriteCT_Double(oVal.crossesAt);
        });
    }
    if (null != oVal.auto) {
        this.bs.WriteItem(c_oserct_cataxAUTO, function () {
            oThis.WriteCT_Boolean(oVal.auto);
        });
    }
    if (null != oVal.lblAlgn) {
        this.bs.WriteItem(c_oserct_cataxLBLALGN, function () {
            oThis.WriteCT_LblAlgn(oVal.lblAlgn);
        });
    }
    if (null != oVal.lblOffset) {
        this.bs.WriteItem(c_oserct_cataxLBLOFFSET, function () {
            oThis.WriteCT_LblOffset(oVal.lblOffset);
        });
    }
    if (null != oVal.tickLblSkip) {
        this.bs.WriteItem(c_oserct_cataxTICKLBLSKIP, function () {
            oThis.WriteCT_Skip(oVal.tickLblSkip);
        });
    }
    if (null != oVal.tickMarkSkip) {
        this.bs.WriteItem(c_oserct_cataxTICKMARKSKIP, function () {
            oThis.WriteCT_Skip(oVal.tickMarkSkip);
        });
    }
    if (null != oVal.noMultiLvlLbl) {
        this.bs.WriteItem(c_oserct_cataxNOMULTILVLLBL, function () {
            oThis.WriteCT_Boolean(oVal.noMultiLvlLbl);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_cataxEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_DispUnitsLbl = function (oVal) {
    var oThis = this;
    this.bs.WriteItem(c_oserct_dispunitslblLAYOUT, function () {
        oThis.WriteCT_Layout(oVal);
    });
    if (null != oVal.tx) {
        this.bs.WriteItem(c_oserct_dispunitslblTX, function () {
            oThis.WriteCT_Tx(oVal.tx);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_dispunitslblSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.txPr) {
        this.bs.WriteItem(c_oserct_dispunitslblTXPR, function () {
            oThis.WriteTxPr(oVal.txPr);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_BuiltInUnit = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case c_oAscValAxUnits.HUNDREDS: nVal = st_builtinunitHUNDREDS; break;
            case c_oAscValAxUnits.THOUSANDS: nVal = st_builtinunitTHOUSANDS; break;
            case c_oAscValAxUnits.TEN_THOUSANDS: nVal = st_builtinunitTENTHOUSANDS; break;
            case c_oAscValAxUnits.HUNDRED_THOUSANDS: nVal = st_builtinunitHUNDREDTHOUSANDS; break;
            case c_oAscValAxUnits.MILLIONS: nVal = st_builtinunitMILLIONS; break;
            case c_oAscValAxUnits.TEN_MILLIONS: nVal = st_builtinunitTENMILLIONS; break;
            case c_oAscValAxUnits.HUNDRED_MILLIONS: nVal = st_builtinunitHUNDREDMILLIONS; break;
            case c_oAscValAxUnits.BILLIONS: nVal = st_builtinunitBILLIONS; break;
            case c_oAscValAxUnits.TRILLIONS: nVal = st_builtinunitTRILLIONS; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_builtinunitVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_DispUnits = function (oVal) {
    var oThis = this;
    if (null != oVal.builtInUnit) {
        this.bs.WriteItem(c_oserct_dispunitsBUILTINUNIT, function () {
            oThis.WriteCT_BuiltInUnit(oVal.builtInUnit);
        });
    }
    if (null != oVal.custUnit) {
        this.bs.WriteItem(c_oserct_dispunitsCUSTUNIT, function () {
            oThis.WriteCT_Double(oVal.custUnit);
        });
    }
    if (null != oVal.dispUnitsLbl) {
        this.bs.WriteItem(c_oserct_dispunitsDISPUNITSLBL, function () {
            oThis.WriteCT_DispUnitsLbl(oVal.dispUnitsLbl);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_dispunitsEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_CrossBetween = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case AscFormat.CROSS_BETWEEN_BETWEEN: nVal = st_crossbetweenBETWEEN; break;
            case AscFormat.CROSS_BETWEEN_MID_CAT: nVal = st_crossbetweenMIDCAT; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_crossbetweenVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_ValAx = function (oVal) {
    //todo ax
    var oThis = this;
    if (null != oVal.axId) {
        this.bs.WriteItem(c_oserct_valaxAXID, function () {
            oThis.WriteCT_UnsignedInt(oVal.axId);
        });
    }
    if (null != oVal.scaling) {
        this.bs.WriteItem(c_oserct_valaxSCALING, function () {
            oThis.WriteCT_Scaling(oVal.scaling);
        });
    }
    if (null != oVal.bDelete) {
        this.bs.WriteItem(c_oserct_valaxDELETE, function () {
            oThis.WriteCT_Boolean(oVal.bDelete);
        });
    }
    if (null != oVal.axPos) {
        this.bs.WriteItem(c_oserct_valaxAXPOS, function () {
            oThis.WriteCT_AxPos(oVal.axPos);
        });
    }
    if (null != oVal.majorGridlines) {
        this.bs.WriteItem(c_oserct_valaxMAJORGRIDLINES, function () {
            oThis.WriteCT_ChartLines(oVal.majorGridlines);
        });
    }
    if (null != oVal.minorGridlines) {
        this.bs.WriteItem(c_oserct_valaxMINORGRIDLINES, function () {
            oThis.WriteCT_ChartLines(oVal.minorGridlines);
        });
    }
     if (null != oVal.title) {
     this.bs.WriteItem(c_oserct_valaxTITLE, function () {
     oThis.WriteCT_Title(oVal.title);
     });
     }
    if (null != oVal.numFmt) {
        this.bs.WriteItem(c_oserct_valaxNUMFMT, function () {
            oThis.WriteCT_NumFmt(oVal.numFmt);
        });
    }
    if (null != oVal.majorTickMark) {
        this.bs.WriteItem(c_oserct_valaxMAJORTICKMARK, function () {
            oThis.WriteCT_TickMark(oVal.majorTickMark);
        });
    }
    if (null != oVal.minorTickMark) {
        this.bs.WriteItem(c_oserct_valaxMINORTICKMARK, function () {
            oThis.WriteCT_TickMark(oVal.minorTickMark);
        });
    }
    if (null != oVal.tickLblPos) {
        this.bs.WriteItem(c_oserct_valaxTICKLBLPOS, function () {
            oThis.WriteCT_TickLblPos(oVal.tickLblPos);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_valaxSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.txPr) {
        this.bs.WriteItem(c_oserct_valaxTXPR, function () {
            oThis.WriteTxPr(oVal.txPr);
        });
    }
    if (null != oVal.crossAx) {
        this.bs.WriteItem(c_oserct_valaxCROSSAX, function () {
            oThis.WriteCT_UnsignedInt(oVal.crossAx.axId);
        });
    }
    if (null != oVal.crosses) {
        this.bs.WriteItem(c_oserct_valaxCROSSES, function () {
            oThis.WriteCT_Crosses(oVal.crosses);
        });
    }
    if (null != oVal.crossesAt) {
        this.bs.WriteItem(c_oserct_valaxCROSSESAT, function () {
            oThis.WriteCT_Double(oVal.crossesAt);
        });
    }
    if (null != oVal.crossBetween) {
        this.bs.WriteItem(c_oserct_valaxCROSSBETWEEN, function () {
            oThis.WriteCT_CrossBetween(oVal.crossBetween);
        });
    }
    if (null != oVal.majorUnit) {
        this.bs.WriteItem(c_oserct_valaxMAJORUNIT, function () {
            oThis.WriteCT_AxisUnit(oVal.majorUnit);
        });
    }
    if (null != oVal.minorUnit) {
        this.bs.WriteItem(c_oserct_valaxMINORUNIT, function () {
            oThis.WriteCT_AxisUnit(oVal.minorUnit);
        });
    }
    if (null != oVal.dispUnits) {
        this.bs.WriteItem(c_oserct_valaxDISPUNITS, function () {
            oThis.WriteCT_DispUnits(oVal.dispUnits);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_valaxEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_SizeRepresents = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case SIZE_REPRESENTS_AREA: nVal = st_sizerepresentsAREA; break;
            case SIZE_REPRESENTS_W: nVal = st_sizerepresentsW; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_sizerepresentsVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_BubbleScale = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_bubblescaleVAL, function () {
            oThis.memory.WriteString3(oThis.percentToString(oVal, true, false));
        });
    }
}
BinaryChartWriter.prototype.WriteCT_BubbleSer = function (oVal) {
    var oThis = this;
    if (null != oVal.idx) {
        this.bs.WriteItem(c_oserct_bubbleserIDX, function () {
            oThis.WriteCT_UnsignedInt(oVal.idx);
        });
    }
    if (null != oVal.order) {
        this.bs.WriteItem(c_oserct_bubbleserORDER, function () {
            oThis.WriteCT_UnsignedInt(oVal.order);
        });
    }
    if (null != oVal.tx) {
        this.bs.WriteItem(c_oserct_bubbleserTX, function () {
            oThis.WriteCT_SerTx(oVal.tx);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_bubbleserSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.invertIfNegative) {
        this.bs.WriteItem(c_oserct_bubbleserINVERTIFNEGATIVE, function () {
            oThis.WriteCT_Boolean(oVal.invertIfNegative);
        });
    }
    if (null != oVal.dPt) {
        for (var i = 0, length = oVal.dPt.length; i < length; ++i) {
            var oCurVal = oVal.dPt[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_bubbleserDPT, function () {
                    oThis.WriteCT_DPt(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_bubbleserDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    if (null != oVal.trendline) {
        this.bs.WriteItem(c_oserct_bubbleserTRENDLINE, function () {
            oThis.WriteCT_Trendline(oVal.trendline);
        });
    }
    //todo array
    if (null != oVal.errBars) {
        this.bs.WriteItem(c_oserct_bubbleserERRBARS, function () {
            oThis.WriteCT_ErrBars(oVal.errBars);
        });
    }
    if (null != oVal.xVal) {
        this.bs.WriteItem(c_oserct_bubbleserXVAL, function () {
            oThis.WriteCT_AxDataSource(oVal.xVal);
        });
    }
    if (null != oVal.yVal) {
        this.bs.WriteItem(c_oserct_bubbleserYVAL, function () {
            oThis.WriteCT_NumDataSource(oVal.yVal);
        });
    }
    if (null != oVal.bubbleSize) {
        this.bs.WriteItem(c_oserct_bubbleserBUBBLESIZE, function () {
            oThis.WriteCT_NumDataSource(oVal.bubbleSize);
        });
    }
    if (null != oVal.bubble3D) {
        this.bs.WriteItem(c_oserct_bubbleserBUBBLE3D, function () {
            oThis.WriteCT_Boolean(oVal.bubble3D);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_bubbleserEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_SerTx = function (oVal) {
    var oThis = this;
    if (null != oVal.strRef) {
        this.bs.WriteItem(c_oserct_sertxSTRREF, function () {
            oThis.WriteCT_StrRef(oVal.strRef);
        });
    }
    if (null != oVal.val) {
        this.bs.WriteItem(c_oserct_sertxV, function () {
            oThis.memory.WriteString3(oVal.val);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_DPt = function (oVal) {
    var oThis = this;
    if (null != oVal.idx) {
        this.bs.WriteItem(c_oserct_dptIDX, function () {
            oThis.WriteCT_UnsignedInt(oVal.idx);
        });
    }
    if (null != oVal.invertIfNegative) {
        this.bs.WriteItem(c_oserct_dptINVERTIFNEGATIVE, function () {
            oThis.WriteCT_Boolean(oVal.invertIfNegative);
        });
    }
    if (null != oVal.marker) {
        this.bs.WriteItem(c_oserct_dptMARKER, function () {
            oThis.WriteCT_Marker(oVal.marker);
        });
    }
    if (null != oVal.bubble3D) {
        this.bs.WriteItem(c_oserct_dptBUBBLE3D, function () {
            oThis.WriteCT_Boolean(oVal.bubble3D);
        });
    }
    if (null != oVal.explosion) {
        this.bs.WriteItem(c_oserct_dptEXPLOSION, function () {
            oThis.WriteCT_UnsignedInt(oVal.explosion);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_dptSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.pictureOptions) {
        this.bs.WriteItem(c_oserct_dptPICTUREOPTIONS, function () {
            oThis.WriteCT_PictureOptions(oVal.pictureOptions);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_dptEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_Marker = function (oVal) {
    var oThis = this;
    if (null != oVal.symbol) {
        this.bs.WriteItem(c_oserct_markerSYMBOL, function () {
            oThis.WriteCT_MarkerStyle(oVal.symbol);
        });
    }
    if (null != oVal.size) {
        this.bs.WriteItem(c_oserct_markerSIZE, function () {
            oThis.WriteCT_MarkerSize(oVal.size);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_markerSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_markerEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_MarkerStyle = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case AscFormat.SYMBOL_CIRCLE: nVal = st_markerstyleCIRCLE; break;
            case AscFormat.SYMBOL_DASH: nVal = st_markerstyleDASH; break;
            case AscFormat.SYMBOL_DIAMOND: nVal = st_markerstyleDIAMOND; break;
            case AscFormat.SYMBOL_DOT: nVal = st_markerstyleDOT; break;
            case AscFormat.SYMBOL_NONE: nVal = st_markerstyleNONE; break;
            case AscFormat.SYMBOL_PICTURE: nVal = st_markerstylePICTURE; break;
            case AscFormat.SYMBOL_PLUS: nVal = st_markerstylePLUS; break;
            case AscFormat.SYMBOL_SQUARE: nVal = st_markerstyleSQUARE; break;
            case AscFormat.SYMBOL_STAR: nVal = st_markerstyleSTAR; break;
            case AscFormat.SYMBOL_TRIANGLE: nVal = st_markerstyleTRIANGLE; break;
            case AscFormat.SYMBOL_X: nVal = st_markerstyleX; break;
            // case : nVal = st_markerstyleAUTO; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_markerstyleVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_MarkerSize = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_markersizeVAL, function () {
            oThis.memory.WriteByte(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_PictureOptions = function (oVal) {
    var oThis = this;
    if (null != oVal.applyToFront) {
        this.bs.WriteItem(c_oserct_pictureoptionsAPPLYTOFRONT, function () {
            oThis.WriteCT_Boolean(oVal.applyToFront);
        });
    }
    if (null != oVal.applyToSides) {
        this.bs.WriteItem(c_oserct_pictureoptionsAPPLYTOSIDES, function () {
            oThis.WriteCT_Boolean(oVal.applyToSides);
        });
    }
    if (null != oVal.applyToEnd) {
        this.bs.WriteItem(c_oserct_pictureoptionsAPPLYTOEND, function () {
            oThis.WriteCT_Boolean(oVal.applyToEnd);
        });
    }
    if (null != oVal.pictureFormat) {
        this.bs.WriteItem(c_oserct_pictureoptionsPICTUREFORMAT, function () {
            oThis.WriteCT_PictureFormat(oVal.pictureFormat);
        });
    }
    if (null != oVal.pictureStackUnit) {
        this.bs.WriteItem(c_oserct_pictureoptionsPICTURESTACKUNIT, function () {
            oThis.WriteCT_PictureStackUnit(oVal.pictureStackUnit);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_PictureFormat = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case PICTURE_FORMAT_STACK_STRETCH: nVal = st_pictureformatSTRETCH; break;
            case PICTURE_FORMAT_STACK: nVal = st_pictureformatSTACK; break;
            case PICTURE_FORMAT_STACK_SCALE: nVal = st_pictureformatSTACKSCALE; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_pictureformatVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_PictureStackUnit = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_picturestackunitVAL, function () {
            oThis.memory.WriteDouble2(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_DLbls = function (oVal) {
    var oThis = this;
    if (null != oVal.dLbl) {
        for (var i = 0, length = oVal.dLbl.length; i < length; ++i) {
            var oCurVal = oVal.dLbl[i];
            if (null != oCurVal && null != oCurVal.idx) {
                this.bs.WriteItem(c_oserct_dlblsDLBL, function () {
                    oThis.WriteCT_DLbl(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLblPos) {
        this.bs.WriteItem(c_oserct_dlblsDLBLPOS, function () {
            oThis.WriteCT_DLblPos(oVal.dLblPos);
        });
    }
    if (null != oVal.bDelete) {
        this.bs.WriteItem(c_oserct_dlblsDELETE, function () {
            oThis.WriteCT_Boolean(oVal.bDelete);
        });
    }
    if (null != oVal.leaderLines) {
        this.bs.WriteItem(c_oserct_dlblsLEADERLINES, function () {
            oThis.WriteCT_ChartLines(oVal.leaderLines);
        });
    }
    if (null != oVal.numFmt) {
        this.bs.WriteItem(c_oserct_dlblsNUMFMT, function () {
            oThis.WriteCT_NumFmt(oVal.numFmt);
        });
    }
    if (null != oVal.separator) {
        this.bs.WriteItem(c_oserct_dlblsSEPARATOR, function () {
            oThis.memory.WriteString3(oVal.separator);
        });
    }
    if (null != oVal.showBubbleSize) {
        this.bs.WriteItem(c_oserct_dlblsSHOWBUBBLESIZE, function () {
            oThis.WriteCT_Boolean(oVal.showBubbleSize);
        });
    }
    if (null != oVal.showCatName) {
        this.bs.WriteItem(c_oserct_dlblsSHOWCATNAME, function () {
            oThis.WriteCT_Boolean(oVal.showCatName);
        });
    }
    if (null != oVal.showLeaderLines) {
        this.bs.WriteItem(c_oserct_dlblsSHOWLEADERLINES, function () {
            oThis.WriteCT_Boolean(oVal.showLeaderLines);
        });
    }
    if (null != oVal.showLegendKey) {
        this.bs.WriteItem(c_oserct_dlblsSHOWLEGENDKEY, function () {
            oThis.WriteCT_Boolean(oVal.showLegendKey);
        });
    }
    if (null != oVal.showPercent) {
        this.bs.WriteItem(c_oserct_dlblsSHOWPERCENT, function () {
            oThis.WriteCT_Boolean(oVal.showPercent);
        });
    }
    if (null != oVal.showSerName) {
        this.bs.WriteItem(c_oserct_dlblsSHOWSERNAME, function () {
            oThis.WriteCT_Boolean(oVal.showSerName);
        });
    }
    if (null != oVal.showVal) {
        this.bs.WriteItem(c_oserct_dlblsSHOWVAL, function () {
            oThis.WriteCT_Boolean(oVal.showVal);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_dlblsSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.txPr) {
        this.bs.WriteItem(c_oserct_dlblsTXPR, function () {
            oThis.WriteTxPr(oVal.txPr);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_dlblsEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_DLbl = function (oVal) {
    var oThis = this;
    if (null != oVal.idx) {
        this.bs.WriteItem(c_oserct_dlblIDX, function () {
            oThis.WriteCT_UnsignedInt(oVal.idx);
        });
    }
    if (null != oVal.dLblPos) {
        this.bs.WriteItem(c_oserct_dlblDLBLPOS, function () {
            oThis.WriteCT_DLblPos(oVal.dLblPos);
        });
    }
    if (null != oVal.bDelete) {
        this.bs.WriteItem(c_oserct_dlblDELETE, function () {
            oThis.WriteCT_Boolean(oVal.bDelete);
        });
    }
    this.bs.WriteItem(c_oserct_dlblLAYOUT, function () {
        oThis.WriteCT_Layout(oVal);
    });
    if (null != oVal.numFmt) {
        this.bs.WriteItem(c_oserct_dlblNUMFMT, function () {
            oThis.WriteCT_NumFmt(oVal.numFmt);
        });
    }
    if (null != oVal.separator) {
        this.bs.WriteItem(c_oserct_dlblSEPARATOR, function () {
            oThis.memory.WriteString3(oVal.separator);
        });
    }
    if (null != oVal.showBubbleSize) {
        this.bs.WriteItem(c_oserct_dlblSHOWBUBBLESIZE, function () {
            oThis.WriteCT_Boolean(oVal.showBubbleSize);
        });
    }
    if (null != oVal.showCatName) {
        this.bs.WriteItem(c_oserct_dlblSHOWCATNAME, function () {
            oThis.WriteCT_Boolean(oVal.showCatName);
        });
    }
    if (null != oVal.showLegendKey) {
        this.bs.WriteItem(c_oserct_dlblSHOWLEGENDKEY, function () {
            oThis.WriteCT_Boolean(oVal.showLegendKey);
        });
    }
    if (null != oVal.showPercent) {
        this.bs.WriteItem(c_oserct_dlblSHOWPERCENT, function () {
            oThis.WriteCT_Boolean(oVal.showPercent);
        });
    }
    if (null != oVal.showSerName) {
        this.bs.WriteItem(c_oserct_dlblSHOWSERNAME, function () {
            oThis.WriteCT_Boolean(oVal.showSerName);
        });
    }
    if (null != oVal.showVal) {
        this.bs.WriteItem(c_oserct_dlblSHOWVAL, function () {
            oThis.WriteCT_Boolean(oVal.showVal);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_dlblSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.tx) {
        this.bs.WriteItem(c_oserct_dlblTX, function () {
            oThis.WriteCT_Tx(oVal.tx);
        });
    }
    if (null != oVal.txPr) {
        this.bs.WriteItem(c_oserct_dlblTXPR, function () {
            oThis.WriteTxPr(oVal.txPr);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_dlblEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_DLblPos = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case c_oAscChartDataLabelsPos.bestFit: nVal = st_dlblposBESTFIT; break;
            case c_oAscChartDataLabelsPos.b: nVal = st_dlblposB; break;
            case c_oAscChartDataLabelsPos.ctr: nVal = st_dlblposCTR; break;
            case c_oAscChartDataLabelsPos.inBase: nVal = st_dlblposINBASE; break;
            case c_oAscChartDataLabelsPos.inEnd: nVal = st_dlblposINEND; break;
            case c_oAscChartDataLabelsPos.l: nVal = st_dlblposL; break;
            case c_oAscChartDataLabelsPos.outEnd: nVal = st_dlblposOUTEND; break;
            case c_oAscChartDataLabelsPos.r: nVal = st_dlblposR; break;
            case c_oAscChartDataLabelsPos.t: nVal = st_dlblposT; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_dlblposVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_Trendline = function (oVal) {
    var oThis = this;
    if (null != oVal.name) {
        this.bs.WriteItem(c_oserct_trendlineNAME, function () {
            oThis.memory.WriteString3(oVal.name);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_trendlineSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.trendlineType) {
        this.bs.WriteItem(c_oserct_trendlineTRENDLINETYPE, function () {
            oThis.WriteCT_TrendlineType(oVal.trendlineType);
        });
    }
    if (null != oVal.order) {
        this.bs.WriteItem(c_oserct_trendlineORDER, function () {
            oThis.WriteCT_Order(oVal.order);
        });
    }
    if (null != oVal.period) {
        this.bs.WriteItem(c_oserct_trendlinePERIOD, function () {
            oThis.WriteCT_Period(oVal.period);
        });
    }
    if (null != oVal.forward) {
        this.bs.WriteItem(c_oserct_trendlineFORWARD, function () {
            oThis.WriteCT_Double(oVal.forward);
        });
    }
    if (null != oVal.backward) {
        this.bs.WriteItem(c_oserct_trendlineBACKWARD, function () {
            oThis.WriteCT_Double(oVal.backward);
        });
    }
    if (null != oVal.intercept) {
        this.bs.WriteItem(c_oserct_trendlineINTERCEPT, function () {
            oThis.WriteCT_Double(oVal.intercept);
        });
    }
    if (null != oVal.dispRSqr) {
        this.bs.WriteItem(c_oserct_trendlineDISPRSQR, function () {
            oThis.WriteCT_Boolean(oVal.dispRSqr);
        });
    }
    if (null != oVal.dispEq) {
        this.bs.WriteItem(c_oserct_trendlineDISPEQ, function () {
            oThis.WriteCT_Boolean(oVal.dispEq);
        });
    }
    if (null != oVal.trendlineLbl) {
        this.bs.WriteItem(c_oserct_trendlineTRENDLINELBL, function () {
            oThis.WriteCT_TrendlineLbl(oVal.trendlineLbl);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_trendlineEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_TrendlineType = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case TRENDLINE_TYPE_EXP: nVal = st_trendlinetypeEXP; break;
            case TRENDLINE_TYPE_LINEAR: nVal = st_trendlinetypeLINEAR; break;
            case TRENDLINE_TYPE_LOG: nVal = st_trendlinetypeLOG; break;
            case TRENDLINE_TYPE_MOVING_AVG: nVal = st_trendlinetypeMOVINGAVG; break;
            case TRENDLINE_TYPE_POLY: nVal = st_trendlinetypePOLY; break;
            case TRENDLINE_TYPE_POWER: nVal = st_trendlinetypePOWER; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_trendlinetypeVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_Order = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_orderVAL, function () {
            oThis.memory.WriteByte(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_Period = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_periodVAL, function () {
            oThis.memory.WriteLong(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_TrendlineLbl = function (oVal) {
    var oThis = this;
    this.bs.WriteItem(c_oserct_trendlinelblLAYOUT, function () {
        oThis.WriteCT_Layout(oVal);
    });
    if (null != oVal.tx) {
        this.bs.WriteItem(c_oserct_trendlinelblTX, function () {
            oThis.WriteCT_Tx(oVal.tx);
        });
    }
    if (null != oVal.numFmt) {
        this.bs.WriteItem(c_oserct_trendlinelblNUMFMT, function () {
            oThis.WriteCT_NumFmt(oVal.numFmt);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_trendlinelblSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.txPr) {
        this.bs.WriteItem(c_oserct_trendlinelblTXPR, function () {
            oThis.WriteTxPr(oVal.txPr);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_trendlinelblEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_ErrBars = function (oVal) {
    var oThis = this;
    if (null != oVal.errDir) {
        this.bs.WriteItem(c_oserct_errbarsERRDIR, function () {
            oThis.WriteCT_ErrDir(oVal.errDir);
        });
    }
    if (null != oVal.errBarType) {
        this.bs.WriteItem(c_oserct_errbarsERRBARTYPE, function () {
            oThis.WriteCT_ErrBarType(oVal.errBarType);
        });
    }
    if (null != oVal.errValType) {
        this.bs.WriteItem(c_oserct_errbarsERRVALTYPE, function () {
            oThis.WriteCT_ErrValType(oVal.errValType);
        });
    }
    if (null != oVal.noEndCap) {
        this.bs.WriteItem(c_oserct_errbarsNOENDCAP, function () {
            oThis.WriteCT_Boolean(oVal.noEndCap);
        });
    }
    if (null != oVal.plus) {
        this.bs.WriteItem(c_oserct_errbarsPLUS, function () {
            oThis.WriteCT_NumDataSource(oVal.plus);
        });
    }
    if (null != oVal.minus) {
        this.bs.WriteItem(c_oserct_errbarsMINUS, function () {
            oThis.WriteCT_NumDataSource(oVal.minus);
        });
    }
    if (null != oVal.val) {
        this.bs.WriteItem(c_oserct_errbarsVAL, function () {
            oThis.WriteCT_Double(oVal.val);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_errbarsSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_errbarsEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_ErrDir = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case ERR_DIR_X: nVal = st_errdirX; break;
            case ERR_DIR_Y: nVal = st_errdirY; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_errdirVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_ErrBarType = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case ERR_BAR_TYPE_BOTH: nVal = st_errbartypeBOTH; break;
            case ERR_BAR_TYPE_MINUS: nVal = st_errbartypeMINUS; break;
            case ERR_BAR_TYPE_PLUS: nVal = st_errbartypePLUS; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_errbartypeVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_ErrValType = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case ERR_VAL_TYPE_CUST: nVal = st_errvaltypeCUST; break;
            case ERR_VAL_TYPE_FIXED_VAL: nVal = st_errvaltypeFIXEDVAL; break;
            case ERR_VAL_TYPE_PERCENTAGE: nVal = st_errvaltypePERCENTAGE; break;
            case ERR_VAL_TYPE_STD_DEV: nVal = st_errvaltypeSTDDEV; break;
            case ERR_VAL_TYPE_STD_ERR: nVal = st_errvaltypeSTDERR; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_errvaltypeVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_NumDataSource = function (oVal) {
    var oThis = this;
    if (null != oVal.numLit) {
        this.bs.WriteItem(c_oserct_numdatasourceNUMLIT, function () {
            oThis.WriteCT_NumData(oVal.numLit);
        });
    }
    if (null != oVal.numRef) {
        this.bs.WriteItem(c_oserct_numdatasourceNUMREF, function () {
            oThis.WriteCT_NumRef(oVal.numRef);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_NumData = function (oVal) {
    var oThis = this;
    if (null != oVal.formatCode) {
        this.bs.WriteItem(c_oserct_numdataFORMATCODE, function () {
            oThis.memory.WriteString3(oVal.formatCode);
        });
    }
    if (null != oVal.ptCount) {
        this.bs.WriteItem(c_oserct_numdataPTCOUNT, function () {
            oThis.WriteCT_UnsignedInt(oVal.ptCount);
        });
    }
    if (null != oVal.pts) {
        for (var i = 0, length = oVal.pts.length; i < length; ++i) {
            var oCurVal = oVal.pts[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_numdataPT, function () {
                    oThis.WriteCT_NumVal(oCurVal);
                });
            }
        }
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_numdataEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_NumVal = function (oVal) {
    var oThis = this;
    if (null != oVal.val) {
        this.bs.WriteItem(c_oserct_numvalV, function () {
            oThis.memory.WriteString3(oVal.val);
        });
    }
    if (null != oVal.idx) {
        this.bs.WriteItem(c_oserct_numvalIDX, function () {
            oThis.memory.WriteLong(oVal.idx);
        });
    }
    if (null != oVal.formatCode) {
        this.bs.WriteItem(c_oserct_numvalFORMATCODE, function () {
            oThis.memory.WriteString3(oVal.formatCode);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_NumRef = function (oVal) {
    var oThis = this;
    if (null != oVal.f) {
        this.bs.WriteItem(c_oserct_numrefF, function () {
            oThis.memory.WriteString3(oVal.f);
        });
    }
    if (null != oVal.numCache) {
        this.bs.WriteItem(c_oserct_numrefNUMCACHE, function () {
            oThis.WriteCT_NumData(oVal.numCache);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_numrefEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_AxDataSource = function (oVal) {
    var oThis = this;
    if (null != oVal.multiLvlStrRef) {
        this.bs.WriteItem(c_oserct_axdatasourceMULTILVLSTRREF, function () {
            oThis.WriteCT_MultiLvlStrRef(oVal.multiLvlStrRef);
        });
    }
    if (null != oVal.numLit) {
        this.bs.WriteItem(c_oserct_axdatasourceNUMLIT, function () {
            oThis.WriteCT_NumData(oVal.numLit);
        });
    }
    if (null != oVal.numRef) {
        this.bs.WriteItem(c_oserct_axdatasourceNUMREF, function () {
            oThis.WriteCT_NumRef(oVal.numRef);
        });
    }
    if (null != oVal.strLit) {
        this.bs.WriteItem(c_oserct_axdatasourceSTRLIT, function () {
            oThis.WriteCT_StrData(oVal.strLit);
        });
    }
    if (null != oVal.strRef) {
        this.bs.WriteItem(c_oserct_axdatasourceSTRREF, function () {
            oThis.WriteCT_StrRef(oVal.strRef);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_MultiLvlStrRef = function (oVal) {
    var oThis = this;
    if (null != oVal.f) {
        this.bs.WriteItem(c_oserct_multilvlstrrefF, function () {
            oThis.memory.WriteString3(oVal.f);
        });
    }
    if (null != oVal.multiLvlStrCache) {
        this.bs.WriteItem(c_oserct_multilvlstrrefMULTILVLSTRCACHE, function () {
            oThis.WriteCT_MultiLvlStrData(oVal.multiLvlStrCache);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_multilvlstrrefEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_lvl = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        for (var i = 0, length = oVal.length; i < length; ++i) {
            var oCurVal = oVal[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_lvlPT, function () {
                    oThis.WriteCT_StrVal(oCurVal);
                });
            }
        }
    }
}
BinaryChartWriter.prototype.WriteCT_MultiLvlStrData = function (oVal) {
    var oThis = this;
    if (null != oVal.ptCount) {
        this.bs.WriteItem(c_oserct_multilvlstrdataPTCOUNT, function () {
            oThis.WriteCT_UnsignedInt(oVal.ptCount);
        });
    }
    //todo array
    if (null != oVal.lvl) {
        this.bs.WriteItem(c_oserct_multilvlstrdataLVL, function () {
            oThis.WriteCT_lvl(oVal.lvl);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_multilvlstrdataEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_BubbleChart = function (oVal) {
    var oThis = this;
    if (null != oVal.varyColors) {
        this.bs.WriteItem(c_oserct_bubblechartVARYCOLORS, function () {
            oThis.WriteCT_Boolean(oVal.varyColors);
        });
    }
    if (null != oVal.series) {
        for (var i = 0, length = oVal.series.length; i < length; ++i) {
            var oCurVal = oVal.series[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_bubblechartSER, function () {
                    oThis.WriteCT_BubbleSer(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_bubblechartDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    if (null != oVal.bubble3D) {
        this.bs.WriteItem(c_oserct_bubblechartBUBBLE3D, function () {
            oThis.WriteCT_Boolean(oVal.bubble3D);
        });
    }
    if (null != oVal.bubbleScale) {
        this.bs.WriteItem(c_oserct_bubblechartBUBBLESCALE, function () {
            oThis.WriteCT_BubbleScale(oVal.bubbleScale);
        });
    }
    if (null != oVal.showNegBubbles) {
        this.bs.WriteItem(c_oserct_bubblechartSHOWNEGBUBBLES, function () {
            oThis.WriteCT_Boolean(oVal.showNegBubbles);
        });
    }
    if (null != oVal.sizeRepresents) {
        this.bs.WriteItem(c_oserct_bubblechartSIZEREPRESENTS, function () {
            oThis.WriteCT_SizeRepresents(oVal.sizeRepresents);
        });
    }
    if (null != oVal.axId) {
        for (var i = 0, length = oVal.axId.length; i < length; ++i) {
            var oCurVal = oVal.axId[i];
            if (null != oCurVal && null != oCurVal.axId) {
                this.bs.WriteItem(c_oserct_bubblechartAXID, function () {
                    oThis.WriteCT_UnsignedInt(oCurVal.axId);
                });
            }
        }
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_bubblechartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_bandFmts = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        for (var i = 0, length = oVal.length; i < length; ++i) {
            var oCurVal = oVal[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_bandfmtsBANDFMT, function () {
                    oThis.WriteCT_BandFmt(oCurVal);
                });
            }
        }
    }
}
BinaryChartWriter.prototype.WriteCT_Surface3DChart = function (oVal) {
    var oThis = this;
    if (null != oVal.wireframe) {
        this.bs.WriteItem(c_oserct_surface3dchartWIREFRAME, function () {
            oThis.WriteCT_Boolean(oVal.wireframe);
        });
    }
    if (null != oVal.series) {
        for (var i = 0, length = oVal.series.length; i < length; ++i) {
            var oCurVal = oVal.series[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_surface3dchartSER, function () {
                    oThis.WriteCT_SurfaceSer(oCurVal);
                });
            }
        }
    }
    if (null != oVal.bandFmts && oVal.bandFmts.length > 0) {
        this.bs.WriteItem(c_oserct_surface3dchartBANDFMTS, function () {
            oThis.WriteCT_bandFmts(oVal.bandFmts);
        });
    }
    if (null != oVal.axId) {
        for (var i = 0, length = oVal.axId.length; i < length; ++i) {
            var oCurVal = oVal.axId[i];
            if (null != oCurVal && null != oCurVal.axId) {
                this.bs.WriteItem(c_oserct_surface3dchartAXID, function () {
                    oThis.WriteCT_UnsignedInt(oCurVal.axId);
                });
            }
        }
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_surface3dchartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_SurfaceSer = function (oVal) {
    var oThis = this;
    if (null != oVal.idx) {
        this.bs.WriteItem(c_oserct_surfaceserIDX, function () {
            oThis.WriteCT_UnsignedInt(oVal.idx);
        });
    }
    if (null != oVal.order) {
        this.bs.WriteItem(c_oserct_surfaceserORDER, function () {
            oThis.WriteCT_UnsignedInt(oVal.order);
        });
    }
    if (null != oVal.tx) {
        this.bs.WriteItem(c_oserct_surfaceserTX, function () {
            oThis.WriteCT_SerTx(oVal.tx);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_surfaceserSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.cat) {
        this.bs.WriteItem(c_oserct_surfaceserCAT, function () {
            oThis.WriteCT_AxDataSource(oVal.cat);
        });
    }
    if (null != oVal.val) {
        this.bs.WriteItem(c_oserct_surfaceserVAL, function () {
            oThis.WriteCT_NumDataSource(oVal.val);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_surfaceserEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_BandFmt = function (oVal) {
    var oThis = this;
    if (null != oVal.idx) {
        this.bs.WriteItem(c_oserct_bandfmtIDX, function () {
            oThis.WriteCT_UnsignedInt(oVal.idx);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_bandfmtSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_SurfaceChart = function (oVal) {
    var oThis = this;
    if (null != oVal.wireframe) {
        this.bs.WriteItem(c_oserct_surfacechartWIREFRAME, function () {
            oThis.WriteCT_Boolean(oVal.wireframe);
        });
    }
    if (null != oVal.series) {
        for (var i = 0, length = oVal.series.length; i < length; ++i) {
            var oCurVal = oVal.series[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_surfacechartSER, function () {
                    oThis.WriteCT_SurfaceSer(oCurVal);
                });
            }
        }
    }
    if (null != oVal.bandFmts && oVal.bandFmts.length > 0) {
        this.bs.WriteItem(c_oserct_surfacechartBANDFMTS, function () {
            oThis.WriteCT_bandFmts(oVal.bandFmts);
        });
    }
    if (null != oVal.axId) {
        for (var i = 0, length = oVal.axId.length; i < length; ++i) {
            var oCurVal = oVal.axId[i];
            if (null != oCurVal && null != oCurVal.axId) {
                this.bs.WriteItem(c_oserct_surfacechartAXID, function () {
                    oThis.WriteCT_UnsignedInt(oCurVal.axId);
                });
            }
        }
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_surfacechartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_SecondPieSize = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_secondpiesizeVAL, function () {
            oThis.memory.WriteString3(oThis.percentToString(oVal, true, false));
        });
    }
}
BinaryChartWriter.prototype.WriteCT_SplitType = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case SPLIT_TYPE_AUTO: nVal = st_splittypeAUTO; break;
            case SPLIT_TYPE_CUST: nVal = st_splittypeCUST; break;
            case SPLIT_TYPE_PERCENT: nVal = st_splittypePERCENT; break;
            case SPLIT_TYPE_POS: nVal = st_splittypePOS; break;
            case SPLIT_TYPE_VAL: nVal = st_splittypeVAL; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_splittypeVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_OfPieType = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case OF_PIE_TYPE_PIE: nVal = st_ofpietypePIE; break;
            case OF_PIE_TYPE_BAR: nVal = st_ofpietypeBAR; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_ofpietypeVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_custSplit = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        for (var i = 0, length = oVal.length; i < length; ++i) {
            var oCurVal = oVal[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_custsplitSECONDPIEPT, function () {
                    oThis.WriteCT_UnsignedInt(oCurVal);
                });
            }
        }
    }
}
BinaryChartWriter.prototype.WriteCT_OfPieChart = function (oVal) {
    var oThis = this;
    if (null != oVal.ofPieType) {
        this.bs.WriteItem(c_oserct_ofpiechartOFPIETYPE, function () {
            oThis.WriteCT_OfPieType(oVal.ofPieType);
        });
    }
    if (null != oVal.varyColors) {
        this.bs.WriteItem(c_oserct_ofpiechartVARYCOLORS, function () {
            oThis.WriteCT_Boolean(oVal.varyColors);
        });
    }
    if (null != oVal.series) {
        for (var i = 0, length = oVal.series.length; i < length; ++i) {
            var oCurVal = oVal.series[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_ofpiechartSER, function () {
                    oThis.WriteCT_PieSer(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_ofpiechartDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    if (null != oVal.gapWidth) {
        this.bs.WriteItem(c_oserct_ofpiechartGAPWIDTH, function () {
            oThis.WriteCT_GapAmount(oVal.gapWidth);
        });
    }
    if (null != oVal.splitType) {
        this.bs.WriteItem(c_oserct_ofpiechartSPLITTYPE, function () {
            oThis.WriteCT_SplitType(oVal.splitType);
        });
    }
    if (null != oVal.splitPos) {
        this.bs.WriteItem(c_oserct_ofpiechartSPLITPOS, function () {
            oThis.WriteCT_Double(oVal.splitPos);
        });
    }
    if (null != oVal.custSplit && oVal.custSplit.length > 0) {
        this.bs.WriteItem(c_oserct_ofpiechartCUSTSPLIT, function () {
            oThis.WriteCT_custSplit(oVal.custSplit);
        });
    }
    if (null != oVal.secondPieSize) {
        this.bs.WriteItem(c_oserct_ofpiechartSECONDPIESIZE, function () {
            oThis.WriteCT_SecondPieSize(oVal.secondPieSize);
        });
    }
    //todo array
    if (null != oVal.serLines) {
        this.bs.WriteItem(c_oserct_ofpiechartSERLINES, function () {
            oThis.WriteCT_ChartLines(oVal.serLines);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_ofpiechartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_PieSer = function (oVal) {
    var oThis = this;
    if (null != oVal.idx) {
        this.bs.WriteItem(c_oserct_pieserIDX, function () {
            oThis.WriteCT_UnsignedInt(oVal.idx);
        });
    }
    if (null != oVal.order) {
        this.bs.WriteItem(c_oserct_pieserORDER, function () {
            oThis.WriteCT_UnsignedInt(oVal.order);
        });
    }
    if (null != oVal.tx) {
        this.bs.WriteItem(c_oserct_pieserTX, function () {
            oThis.WriteCT_SerTx(oVal.tx);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_pieserSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.explosion) {
        this.bs.WriteItem(c_oserct_pieserEXPLOSION, function () {
            oThis.WriteCT_UnsignedInt(oVal.explosion);
        });
    }
    if (null != oVal.dPt) {
        for (var i = 0, length = oVal.dPt.length; i < length; ++i) {
            var oCurVal = oVal.dPt[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_pieserDPT, function () {
                    oThis.WriteCT_DPt(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_pieserDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    if (null != oVal.cat) {
        this.bs.WriteItem(c_oserct_pieserCAT, function () {
            oThis.WriteCT_AxDataSource(oVal.cat);
        });
    }
    if (null != oVal.val) {
        this.bs.WriteItem(c_oserct_pieserVAL, function () {
            oThis.WriteCT_NumDataSource(oVal.val);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_pieserEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_GapAmount = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_gapamountVAL, function () {
            oThis.memory.WriteString3(oThis.percentToString(oVal, true, false));
        });
    }
}
BinaryChartWriter.prototype.WriteCT_Bar3DChart = function (oVal) {
    var oThis = this;
    if (null != oVal.barDir) {
        this.bs.WriteItem(c_oserct_bar3dchartBARDIR, function () {
            oThis.WriteCT_BarDir(oVal.barDir);
        });
    }
    if (null != oVal.grouping) {
        this.bs.WriteItem(c_oserct_bar3dchartGROUPING, function () {
            oThis.WriteCT_BarGrouping(oVal.grouping);
        });
    }
    if (null != oVal.varyColors) {
        this.bs.WriteItem(c_oserct_bar3dchartVARYCOLORS, function () {
            oThis.WriteCT_Boolean(oVal.varyColors);
        });
    }
    if (null != oVal.series) {
        for (var i = 0, length = oVal.series.length; i < length; ++i) {
            var oCurVal = oVal.series[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_bar3dchartSER, function () {
                    oThis.WriteCT_BarSer(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_bar3dchartDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    if (null != oVal.gapWidth) {
        this.bs.WriteItem(c_oserct_bar3dchartGAPWIDTH, function () {
            oThis.WriteCT_GapAmount(oVal.gapWidth);
        });
    }
    if (null != oVal.gapDepth) {
        this.bs.WriteItem(c_oserct_bar3dchartGAPDEPTH, function () {
            oThis.WriteCT_GapAmount(oVal.gapDepth);
    });
    }
    if (null != oVal.shape) {
        this.bs.WriteItem(c_oserct_bar3dchartSHAPE, function () {
            oThis.WriteCT_Shape(oVal.shape);
        });
    }
    if (null != oVal.axId) {
        for (var i = 0, length = oVal.axId.length; i < length; ++i) {
            var oCurVal = oVal.axId[i];
            if (null != oCurVal && null != oCurVal.axId) {
                this.bs.WriteItem(c_oserct_bar3dchartAXID, function () {
                    oThis.WriteCT_UnsignedInt(oCurVal.axId);
                });
            }
        }
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_bar3dchartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_BarDir = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case AscFormat.BAR_DIR_BAR: nVal = st_bardirBAR; break;
            case AscFormat.BAR_DIR_COL: nVal = st_bardirCOL; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_bardirVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_BarGrouping = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case AscFormat.BAR_GROUPING_PERCENT_STACKED: nVal = st_bargroupingPERCENTSTACKED; break;
            case AscFormat.BAR_GROUPING_CLUSTERED: nVal = st_bargroupingCLUSTERED; break;
            case AscFormat.BAR_GROUPING_STANDARD: nVal = st_bargroupingSTANDARD; break;
            case AscFormat.BAR_GROUPING_STACKED: nVal = st_bargroupingSTACKED; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_bargroupingVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_BarSer = function (oVal) {
    var oThis = this;
    if (null != oVal.idx) {
        this.bs.WriteItem(c_oserct_barserIDX, function () {
            oThis.WriteCT_UnsignedInt(oVal.idx);
        });
    }
    if (null != oVal.order) {
        this.bs.WriteItem(c_oserct_barserORDER, function () {
            oThis.WriteCT_UnsignedInt(oVal.order);
        });
    }
    if (null != oVal.tx) {
        this.bs.WriteItem(c_oserct_barserTX, function () {
            oThis.WriteCT_SerTx(oVal.tx);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_barserSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.invertIfNegative) {
        this.bs.WriteItem(c_oserct_barserINVERTIFNEGATIVE, function () {
            oThis.WriteCT_Boolean(oVal.invertIfNegative);
        });
    }
    if (null != oVal.pictureOptions) {
        this.bs.WriteItem(c_oserct_barserPICTUREOPTIONS, function () {
            oThis.WriteCT_PictureOptions(oVal.pictureOptions);
        });
    }
    if (null != oVal.dPt) {
        for (var i = 0, length = oVal.dPt.length; i < length; ++i) {
            var oCurVal = oVal.dPt[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_barserDPT, function () {
                    oThis.WriteCT_DPt(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_barserDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    //todo array
    if (null != oVal.trendline) {
        this.bs.WriteItem(c_oserct_barserTRENDLINE, function () {
            oThis.WriteCT_Trendline(oVal.trendline);
        });
    }
    if (null != oVal.errBars) {
        this.bs.WriteItem(c_oserct_barserERRBARS, function () {
            oThis.WriteCT_ErrBars(oVal.errBars);
        });
    }
    if (null != oVal.cat) {
        this.bs.WriteItem(c_oserct_barserCAT, function () {
            oThis.WriteCT_AxDataSource(oVal.cat);
        });
    }
    if (null != oVal.val) {
        this.bs.WriteItem(c_oserct_barserVAL, function () {
            oThis.WriteCT_NumDataSource(oVal.val);
        });
    }
    if (null != oVal.shape) {
        this.bs.WriteItem(c_oserct_barserSHAPE, function () {
            oThis.WriteCT_Shape(oVal.shape);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_barserEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_Shape = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case AscFormat.BAR_SHAPE_CONE: nVal = st_shapeCONE; break;
            case AscFormat.BAR_SHAPE_CONETOMAX: nVal = st_shapeCONETOMAX; break;
            case AscFormat.BAR_SHAPE_BOX: nVal = st_shapeBOX; break;
            case AscFormat.BAR_SHAPE_CYLINDER: nVal = st_shapeCYLINDER; break;
            case AscFormat.BAR_SHAPE_PYRAMID: nVal = st_shapePYRAMID; break;
            case AscFormat.BAR_SHAPE_PYRAMIDTOMAX: nVal = st_shapePYRAMIDTOMAX; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_shapeVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_Overlap = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_overlapVAL, function () {
            oThis.memory.WriteString3(oThis.percentToString(oVal, true, false));
        });
    }
}
BinaryChartWriter.prototype.WriteCT_BarChart = function (oVal) {
    var oThis = this;
    if (null != oVal.barDir) {
        this.bs.WriteItem(c_oserct_barchartBARDIR, function () {
            oThis.WriteCT_BarDir(oVal.barDir);
        });
    }
    if (null != oVal.grouping) {
        this.bs.WriteItem(c_oserct_barchartGROUPING, function () {
            oThis.WriteCT_BarGrouping(oVal.grouping);
        });
    }
    if (null != oVal.varyColors) {
        this.bs.WriteItem(c_oserct_barchartVARYCOLORS, function () {
            oThis.WriteCT_Boolean(oVal.varyColors);
        });
    }
    if (null != oVal.series) {
        for (var i = 0, length = oVal.series.length; i < length; ++i) {
            var oCurVal = oVal.series[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_barchartSER, function () {
                    oThis.WriteCT_BarSer(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_barchartDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    if (null != oVal.gapWidth) {
        this.bs.WriteItem(c_oserct_barchartGAPWIDTH, function () {
            oThis.WriteCT_GapAmount(oVal.gapWidth);
        });
    }
    if (null != oVal.overlap) {
        this.bs.WriteItem(c_oserct_barchartOVERLAP, function () {
            oThis.WriteCT_Overlap(oVal.overlap);
        });
    }
    //todo array
    if (null != oVal.serLines) {
        this.bs.WriteItem(c_oserct_barchartSERLINES, function () {
            oThis.WriteCT_ChartLines(oVal.serLines);
        });
    }
    if (null != oVal.axId) {
        for (var i = 0, length = oVal.axId.length; i < length; ++i) {
            var oCurVal = oVal.axId[i];
            if (null != oCurVal && null != oCurVal.axId) {
                this.bs.WriteItem(c_oserct_barchartAXID, function () {
                    oThis.WriteCT_UnsignedInt(oCurVal.axId);
                });
            }
        }
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_barchartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_HoleSize = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_holesizeVAL, function () {
            oThis.memory.WriteString3(oThis.percentToString(oVal, true, false));
        });
    }
}
BinaryChartWriter.prototype.WriteCT_DoughnutChart = function (oVal) {
    var oThis = this;
    if (null != oVal.varyColors) {
        this.bs.WriteItem(c_oserct_doughnutchartVARYCOLORS, function () {
            oThis.WriteCT_Boolean(oVal.varyColors);
        });
    }
    if (null != oVal.series) {
        for (var i = 0, length = oVal.series.length; i < length; ++i) {
            var oCurVal = oVal.series[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_doughnutchartSER, function () {
                    oThis.WriteCT_PieSer(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_doughnutchartDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    if (null != oVal.firstSliceAng) {
        this.bs.WriteItem(c_oserct_doughnutchartFIRSTSLICEANG, function () {
            oThis.WriteCT_FirstSliceAng(oVal.firstSliceAng);
        });
    }
    if (null != oVal.holeSize) {
        this.bs.WriteItem(c_oserct_doughnutchartHOLESIZE, function () {
            oThis.WriteCT_HoleSize(oVal.holeSize);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_doughnutchartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_FirstSliceAng = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_firstsliceangVAL, function () {
            oThis.memory.WriteLong(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_Pie3DChart = function (oVal) {
    var oThis = this;
    if (null != oVal.varyColors) {
        this.bs.WriteItem(c_oserct_pie3dchartVARYCOLORS, function () {
            oThis.WriteCT_Boolean(oVal.varyColors);
        });
    }
    if (null != oVal.series) {
        for (var i = 0, length = oVal.series.length; i < length; ++i) {
            var oCurVal = oVal.series[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_pie3dchartSER, function () {
                    oThis.WriteCT_PieSer(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_pie3dchartDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_pie3dchartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_PieChart = function (oVal) {
    var oThis = this;
    if (null != oVal.varyColors) {
        this.bs.WriteItem(c_oserct_piechartVARYCOLORS, function () {
            oThis.WriteCT_Boolean(oVal.varyColors);
        });
    }
    if (null != oVal.series) {
        for (var i = 0, length = oVal.series.length; i < length; ++i) {
            var oCurVal = oVal.series[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_piechartSER, function () {
                    oThis.WriteCT_PieSer(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_piechartDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    if (null != oVal.firstSliceAng) {
        this.bs.WriteItem(c_oserct_piechartFIRSTSLICEANG, function () {
            oThis.WriteCT_FirstSliceAng(oVal.firstSliceAng);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_piechartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_ScatterSer = function (oVal) {
    var oThis = this;
    if (null != oVal.idx) {
        this.bs.WriteItem(c_oserct_scatterserIDX, function () {
            oThis.WriteCT_UnsignedInt(oVal.idx);
        });
    }
    if (null != oVal.order) {
        this.bs.WriteItem(c_oserct_scatterserORDER, function () {
            oThis.WriteCT_UnsignedInt(oVal.order);
        });
    }
    if (null != oVal.tx) {
        this.bs.WriteItem(c_oserct_scatterserTX, function () {
            oThis.WriteCT_SerTx(oVal.tx);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_scatterserSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.marker) {
        this.bs.WriteItem(c_oserct_scatterserMARKER, function () {
            oThis.WriteCT_Marker(oVal.marker);
        });
    }
    if (null != oVal.dPt) {
        for (var i = 0, length = oVal.dPt.length; i < length; ++i) {
            var oCurVal = oVal.dPt[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_scatterserDPT, function () {
                    oThis.WriteCT_DPt(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_scatterserDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    //todo array
    if (null != oVal.trendline) {
        this.bs.WriteItem(c_oserct_scatterserTRENDLINE, function () {
            oThis.WriteCT_Trendline(oVal.trendline);
        });
    }
    //todo array
    if (null != oVal.errBars) {
        this.bs.WriteItem(c_oserct_scatterserERRBARS, function () {
            oThis.WriteCT_ErrBars(oVal.errBars);
        });
    }
    if (null != oVal.xVal) {
        this.bs.WriteItem(c_oserct_scatterserXVAL, function () {
            oThis.WriteCT_AxDataSource(oVal.xVal);
        });
    }
    if (null != oVal.yVal) {
        this.bs.WriteItem(c_oserct_scatterserYVAL, function () {
            oThis.WriteCT_NumDataSource(oVal.yVal);
        });
    }
    if (null != oVal.smooth) {
        this.bs.WriteItem(c_oserct_scatterserSMOOTH, function () {
            oThis.WriteCT_Boolean(oVal.smooth);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_scatterserEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_ScatterStyle = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case AscFormat.SCATTER_STYLE_NONE: nVal = st_scatterstyleNONE; break;
            case AscFormat.SCATTER_STYLE_LINE: nVal = st_scatterstyleLINE; break;
            case AscFormat.SCATTER_STYLE_LINE_MARKER: nVal = st_scatterstyleLINEMARKER; break;
            case AscFormat.SCATTER_STYLE_MARKER: nVal = st_scatterstyleMARKER; break;
            case AscFormat.SCATTER_STYLE_SMOOTH: nVal = st_scatterstyleSMOOTH; break;
            case AscFormat.SCATTER_STYLE_SMOOTH_MARKER: nVal = st_scatterstyleSMOOTHMARKER; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_scatterstyleVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_ScatterChart = function (oVal) {
    var oThis = this;
    if (null != oVal.scatterStyle) {
        this.bs.WriteItem(c_oserct_scatterchartSCATTERSTYLE, function () {
            oThis.WriteCT_ScatterStyle(oVal.scatterStyle);
        });
    }
    if (null != oVal.varyColors) {
        this.bs.WriteItem(c_oserct_scatterchartVARYCOLORS, function () {
            oThis.WriteCT_Boolean(oVal.varyColors);
        });
    }
    if (null != oVal.series) {
        for (var i = 0, length = oVal.series.length; i < length; ++i) {
            var oCurVal = oVal.series[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_scatterchartSER, function () {
                    oThis.WriteCT_ScatterSer(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_scatterchartDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    if (null != oVal.axId) {
        for (var i = 0, length = oVal.axId.length; i < length; ++i) {
            var oCurVal = oVal.axId[i];
            if (null != oCurVal && null != oCurVal.axId) {
                this.bs.WriteItem(c_oserct_scatterchartAXID, function () {
                    oThis.WriteCT_UnsignedInt(oCurVal.axId);
                });
            }
        }
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_scatterchartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_RadarSer = function (oVal) {
    var oThis = this;
    if (null != oVal.idx) {
        this.bs.WriteItem(c_oserct_radarserIDX, function () {
            oThis.WriteCT_UnsignedInt(oVal.idx);
        });
    }
    if (null != oVal.order) {
        this.bs.WriteItem(c_oserct_radarserORDER, function () {
            oThis.WriteCT_UnsignedInt(oVal.order);
        });
    }
    if (null != oVal.tx) {
        this.bs.WriteItem(c_oserct_radarserTX, function () {
            oThis.WriteCT_SerTx(oVal.tx);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_radarserSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.marker) {
        this.bs.WriteItem(c_oserct_radarserMARKER, function () {
            oThis.WriteCT_Marker(oVal.marker);
        });
    }
    if (null != oVal.dPt) {
        for (var i = 0, length = oVal.dPt.length; i < length; ++i) {
            var oCurVal = oVal.dPt[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_radarserDPT, function () {
                    oThis.WriteCT_DPt(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_radarserDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    if (null != oVal.cat) {
        this.bs.WriteItem(c_oserct_radarserCAT, function () {
            oThis.WriteCT_AxDataSource(oVal.cat);
        });
    }
    if (null != oVal.val) {
        this.bs.WriteItem(c_oserct_radarserVAL, function () {
            oThis.WriteCT_NumDataSource(oVal.val);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_radarserEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_RadarStyle = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case RADAR_STYLE_STANDARD: nVal = st_radarstyleSTANDARD; break;
            case RADAR_STYLE_MARKER: nVal = st_radarstyleMARKER; break;
            case RADAR_STYLE_FILLED: nVal = st_radarstyleFILLED; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_radarstyleVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_RadarChart = function (oVal) {
    var oThis = this;
    if (null != oVal.radarStyle) {
        this.bs.WriteItem(c_oserct_radarchartRADARSTYLE, function () {
            oThis.WriteCT_RadarStyle(oVal.radarStyle);
        });
    }
    if (null != oVal.varyColors) {
        this.bs.WriteItem(c_oserct_radarchartVARYCOLORS, function () {
            oThis.WriteCT_Boolean(oVal.varyColors);
        });
    }
    if (null != oVal.series) {
        for (var i = 0, length = oVal.series.length; i < length; ++i) {
            var oCurVal = oVal.series[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_radarchartSER, function () {
                    oThis.WriteCT_RadarSer(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_radarchartDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    if (null != oVal.axId) {
        for (var i = 0, length = oVal.axId.length; i < length; ++i) {
            var oCurVal = oVal.axId[i];
            if (null != oCurVal && null != oCurVal.axId) {
                this.bs.WriteItem(c_oserct_radarchartAXID, function () {
                    oThis.WriteCT_UnsignedInt(oCurVal.axId);
                });
            }
        }
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_radarchartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_StockChart = function (oVal) {
    var oThis = this;
    if (null != oVal.series) {
        for (var i = 0, length = oVal.series.length; i < length; ++i) {
            var oCurVal = oVal.series[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_stockchartSER, function () {
                    oThis.WriteCT_LineSer(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_stockchartDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    if (null != oVal.dropLines) {
        this.bs.WriteItem(c_oserct_stockchartDROPLINES, function () {
            oThis.WriteCT_ChartLines(oVal.dropLines);
        });
    }
    if (null != oVal.hiLowLines) {
        this.bs.WriteItem(c_oserct_stockchartHILOWLINES, function () {
            oThis.WriteCT_ChartLines(oVal.hiLowLines);
        });
    }
    if (null != oVal.upDownBars) {
        this.bs.WriteItem(c_oserct_stockchartUPDOWNBARS, function () {
            oThis.WriteCT_UpDownBars(oVal.upDownBars);
        });
    }
    if (null != oVal.axId) {
        for (var i = 0, length = oVal.axId.length; i < length; ++i) {
            var oCurVal = oVal.axId[i];
            if (null != oCurVal && null != oCurVal.axId) {
                this.bs.WriteItem(c_oserct_stockchartAXID, function () {
                    oThis.WriteCT_UnsignedInt(oCurVal.axId);
                });
            }
        }
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_stockchartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_LineSer = function (oVal) {
    var oThis = this;
    if (null != oVal.idx) {
        this.bs.WriteItem(c_oserct_lineserIDX, function () {
            oThis.WriteCT_UnsignedInt(oVal.idx);
        });
    }
    if (null != oVal.order) {
        this.bs.WriteItem(c_oserct_lineserORDER, function () {
            oThis.WriteCT_UnsignedInt(oVal.order);
        });
    }
    if (null != oVal.tx) {
        this.bs.WriteItem(c_oserct_lineserTX, function () {
            oThis.WriteCT_SerTx(oVal.tx);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_lineserSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.marker) {
        this.bs.WriteItem(c_oserct_lineserMARKER, function () {
            oThis.WriteCT_Marker(oVal.marker);
        });
    }
    if (null != oVal.dPt) {
        for (var i = 0, length = oVal.dPt.length; i < length; ++i) {
            var oCurVal = oVal.dPt[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_lineserDPT, function () {
                    oThis.WriteCT_DPt(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_lineserDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    //todo array
    if (null != oVal.trendline) {
        this.bs.WriteItem(c_oserct_lineserTRENDLINE, function () {
            oThis.WriteCT_Trendline(oVal.trendline);
        });
    }
    if (null != oVal.errBars) {
        this.bs.WriteItem(c_oserct_lineserERRBARS, function () {
            oThis.WriteCT_ErrBars(oVal.errBars);
        });
    }
    if (null != oVal.cat) {
        this.bs.WriteItem(c_oserct_lineserCAT, function () {
            oThis.WriteCT_AxDataSource(oVal.cat);
        });
    }
    if (null != oVal.val) {
        this.bs.WriteItem(c_oserct_lineserVAL, function () {
            oThis.WriteCT_NumDataSource(oVal.val);
        });
    }
    if (null != oVal.smooth) {
        this.bs.WriteItem(c_oserct_lineserSMOOTH, function () {
            oThis.WriteCT_Boolean(oVal.smooth);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_lineserEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_UpDownBars = function (oVal) {
    var oThis = this;
    if (null != oVal.gapWidth) {
        this.bs.WriteItem(c_oserct_updownbarsGAPWIDTH, function () {
            oThis.WriteCT_GapAmount(oVal.gapWidth);
        });
    }
    if (null != oVal.upBars) {
        this.bs.WriteItem(c_oserct_updownbarsUPBARS, function () {
            oThis.WriteCT_UpDownBar(oVal.upBars);
        });
    }
    if (null != oVal.downBars) {
        this.bs.WriteItem(c_oserct_updownbarsDOWNBARS, function () {
            oThis.WriteCT_UpDownBar(oVal.downBars);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_updownbarsEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_UpDownBar = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_updownbarSPPR, function () {
            oThis.WriteSpPr(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_Line3DChart = function (oVal) {
    var oThis = this;
    if (null != oVal.grouping) {
        this.bs.WriteItem(c_oserct_line3dchartGROUPING, function () {
            oThis.WriteCT_Grouping(oVal.grouping);
        });
    }
    if (null != oVal.varyColors) {
        this.bs.WriteItem(c_oserct_line3dchartVARYCOLORS, function () {
            oThis.WriteCT_Boolean(oVal.varyColors);
        });
    }
    if (null != oVal.series) {
        for (var i = 0, length = oVal.series.length; i < length; ++i) {
            var oCurVal = oVal.series[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_line3dchartSER, function () {
                    oThis.WriteCT_LineSer(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_line3dchartDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    if (null != oVal.dropLines) {
        this.bs.WriteItem(c_oserct_line3dchartDROPLINES, function () {
            oThis.WriteCT_ChartLines(oVal.dropLines);
        });
    }
    if (null != oVal.gapDepth) {
        this.bs.WriteItem(c_oserct_line3dchartGAPDEPTH, function () {
            oThis.WriteCT_GapAmount(oVal.gapDepth);
        });
    }
    if (null != oVal.axId) {
        for (var i = 0, length = oVal.axId.length; i < length; ++i) {
            var oCurVal = oVal.axId[i];
            if (null != oCurVal && null != oCurVal.axId) {
                this.bs.WriteItem(c_oserct_line3dchartAXID, function () {
                    oThis.WriteCT_UnsignedInt(oCurVal.axId);
                });
            }
        }
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_line3dchartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_Grouping = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        var nVal = null;
        switch (oVal) {
            case AscFormat.GROUPING_PERCENT_STACKED: nVal = st_groupingPERCENTSTACKED; break;
            case AscFormat.GROUPING_STANDARD: nVal = st_groupingSTANDARD; break;
            case AscFormat.GROUPING_STACKED: nVal = st_groupingSTACKED; break;
        }
        if (null != nVal) {
            this.bs.WriteItem(c_oserct_groupingVAL, function () {
                oThis.memory.WriteByte(nVal);
            });
        }
    }
}
BinaryChartWriter.prototype.WriteCT_LineChart = function (oVal) {
    var oThis = this;
    if (null != oVal.grouping) {
        this.bs.WriteItem(c_oserct_linechartGROUPING, function () {
            oThis.WriteCT_Grouping(oVal.grouping);
        });
    }
    if (null != oVal.varyColors) {
        this.bs.WriteItem(c_oserct_linechartVARYCOLORS, function () {
            oThis.WriteCT_Boolean(oVal.varyColors);
        });
    }
    if (null != oVal.series) {
        for (var i = 0, length = oVal.series.length; i < length; ++i) {
            var oCurVal = oVal.series[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_linechartSER, function () {
                    oThis.WriteCT_LineSer(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_linechartDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    if (null != oVal.dropLines) {
        this.bs.WriteItem(c_oserct_linechartDROPLINES, function () {
            oThis.WriteCT_ChartLines(oVal.dropLines);
        });
    }
    if (null != oVal.hiLowLines) {
        this.bs.WriteItem(c_oserct_linechartHILOWLINES, function () {
            oThis.WriteCT_ChartLines(oVal.hiLowLines);
        });
    }
    if (null != oVal.upDownBars) {
        this.bs.WriteItem(c_oserct_linechartUPDOWNBARS, function () {
            oThis.WriteCT_UpDownBars(oVal.upDownBars);
        });
    }
    if (null != oVal.marker) {
        this.bs.WriteItem(c_oserct_linechartMARKER, function () {
            oThis.WriteCT_Boolean(oVal.marker);
        });
    }
    if (null != oVal.smooth) {
        this.bs.WriteItem(c_oserct_linechartSMOOTH, function () {
            oThis.WriteCT_Boolean(oVal.smooth);
        });
    }
    if (null != oVal.axId) {
        for (var i = 0, length = oVal.axId.length; i < length; ++i) {
            var oCurVal = oVal.axId[i];
            if (null != oCurVal && null != oCurVal.axId) {
                this.bs.WriteItem(c_oserct_linechartAXID, function () {
                    oThis.WriteCT_UnsignedInt(oCurVal.axId);
                });
            }
        }
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_linechartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_Area3DChart = function (oVal) {
    var oThis = this;
    if (null != oVal.grouping) {
        this.bs.WriteItem(c_oserct_area3dchartGROUPING, function () {
            oThis.WriteCT_Grouping(oVal.grouping);
        });
    }
    if (null != oVal.varyColors) {
        this.bs.WriteItem(c_oserct_area3dchartVARYCOLORS, function () {
            oThis.WriteCT_Boolean(oVal.varyColors);
        });
    }
    if (null != oVal.series) {
        for (var i = 0, length = oVal.series.length; i < length; ++i) {
            var oCurVal = oVal.series[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_area3dchartSER, function () {
                    oThis.WriteCT_AreaSer(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_area3dchartDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    if (null != oVal.dropLines) {
        this.bs.WriteItem(c_oserct_area3dchartDROPLINES, function () {
            oThis.WriteCT_ChartLines(oVal.dropLines);
        });
    }
    // if (null != oCurVal.gapDepth) {
    // this.bs.WriteItem(c_oserct_area3dchartGAPDEPTH, function () {
    // oThis.WriteCT_GapAmount(oCurVal);
    // });
    // }
    if (null != oVal.axId) {
        for (var i = 0, length = oVal.axId.length; i < length; ++i) {
            var oCurVal = oVal.axId[i];
            if (null != oCurVal && null != oCurVal.axId) {
                this.bs.WriteItem(c_oserct_area3dchartAXID, function () {
                    oThis.WriteCT_UnsignedInt(oCurVal.axId);
                });
            }
        }
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_area3dchartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_AreaSer = function (oVal) {
    var oThis = this;
    if (null != oVal.idx) {
        this.bs.WriteItem(c_oserct_areaserIDX, function () {
            oThis.WriteCT_UnsignedInt(oVal.idx);
        });
    }
    if (null != oVal.order) {
        this.bs.WriteItem(c_oserct_areaserORDER, function () {
            oThis.WriteCT_UnsignedInt(oVal.order);
        });
    }
    if (null != oVal.tx) {
        this.bs.WriteItem(c_oserct_areaserTX, function () {
            oThis.WriteCT_SerTx(oVal.tx);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_areaserSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.pictureOptions) {
        this.bs.WriteItem(c_oserct_areaserPICTUREOPTIONS, function () {
            oThis.WriteCT_PictureOptions(oVal.pictureOptions);
        });
    }
    if (null != oVal.dPt) {
        for (var i = 0, length = oVal.dPt.length; i < length; ++i) {
            var oCurVal = oVal.dPt[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_areaserDPT, function () {
                    oThis.WriteCT_DPt(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_areaserDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    //todo array
    if (null != oVal.trendline) {
        this.bs.WriteItem(c_oserct_areaserTRENDLINE, function () {
            oThis.WriteCT_Trendline(oVal.trendline);
        });
    }
    //todo array
    if (null != oVal.errBars) {
        this.bs.WriteItem(c_oserct_areaserERRBARS, function () {
            oThis.WriteCT_ErrBars(oVal.errBars);
        });
    }
    if (null != oVal.cat) {
        this.bs.WriteItem(c_oserct_areaserCAT, function () {
            oThis.WriteCT_AxDataSource(oVal.cat);
        });
    }
    if (null != oVal.val) {
        this.bs.WriteItem(c_oserct_areaserVAL, function () {
            oThis.WriteCT_NumDataSource(oVal.val);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_areaserEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_AreaChart = function (oVal) {
    var oThis = this;
    if (null != oVal.grouping) {
        this.bs.WriteItem(c_oserct_areachartGROUPING, function () {
            oThis.WriteCT_Grouping(oVal.grouping);
        });
    }
    if (null != oVal.varyColors) {
        this.bs.WriteItem(c_oserct_areachartVARYCOLORS, function () {
            oThis.WriteCT_Boolean(oVal.varyColors);
        });
    }
    if (null != oVal.series) {
        for (var i = 0, length = oVal.series.length; i < length; ++i) {
            var oCurVal = oVal.series[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_areachartSER, function () {
                    oThis.WriteCT_AreaSer(oCurVal);
                });
            }
        }
    }
    if (null != oVal.dLbls) {
        this.bs.WriteItem(c_oserct_areachartDLBLS, function () {
            oThis.WriteCT_DLbls(oVal.dLbls);
        });
    }
    if (null != oVal.dropLines) {
        this.bs.WriteItem(c_oserct_areachartDROPLINES, function () {
            oThis.WriteCT_ChartLines(oVal.dropLines);
        });
    }
    if (null != oVal.axId) {
        for (var i = 0, length = oVal.axId.length; i < length; ++i) {
            var oCurVal = oVal.axId[i];
            if (null != oCurVal && null != oCurVal.axId) {
                this.bs.WriteItem(c_oserct_areachartAXID, function () {
                    oThis.WriteCT_UnsignedInt(oCurVal.axId);
                });
            }
        }
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_areachartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_PlotArea = function (oVal, oChart) {
    var oThis = this;
    this.bs.WriteItem(c_oserct_plotareaLAYOUT, function () {
        oThis.WriteCT_Layout(oVal);
    });
    for (var i = 0, length = oVal.charts.length; i < length; ++i) {
        var chart = oVal.charts[i];
        if (chart instanceof AscFormat.CAreaChart) {
            this.bs.WriteItem(c_oserct_plotareaAREACHART, function () {
                oThis.WriteCT_AreaChart(chart);
            });
        }
        // else if(chart instanceof CArea3DChart)
        // {
        // this.bs.WriteItem(c_oserct_plotareaAREA3DCHART, function () {
        // oThis.WriteCT_Area3DChart(chart);
        // });
        // }
        else if (chart instanceof AscFormat.CBarChart) {
            if(chart.b3D){
                this.bs.WriteItem(c_oserct_plotareaBAR3DCHART, function () {
                    oThis.WriteCT_Bar3DChart(chart);
                });
            }
            else{
                this.bs.WriteItem(c_oserct_plotareaBARCHART, function () {
                    oThis.WriteCT_BarChart(chart);
                });
            }
        }
        else if (chart instanceof AscFormat.CBubbleChart) {
            this.bs.WriteItem(c_oserct_plotareaBUBBLECHART, function () {
                oThis.WriteCT_BubbleChart(chart);
            });
        }
        else if (chart instanceof AscFormat.CDoughnutChart) {
            this.bs.WriteItem(c_oserct_plotareaDOUGHNUTCHART, function () {
                oThis.WriteCT_DoughnutChart(chart);
            });
        }
        else if (chart instanceof AscFormat.CLineChart) {
            if(!oChart.view3D) {
                this.bs.WriteItem(c_oserct_plotareaLINECHART, function () {
                    oThis.WriteCT_LineChart(chart);
                });
            }
            else {
                this.bs.WriteItem(c_oserct_plotareaLINE3DCHART, function () {
                oThis.WriteCT_Line3DChart(chart);
                });
            }
        }
        // else if(chart instanceof CLine3DChart)
        // {
        // this.bs.WriteItem(c_oserct_plotareaLINE3DCHART, function () {
        // oThis.WriteCT_Line3DChart(chart);
        // });
        // }
        else if (chart instanceof AscFormat.COfPieChart) {
            this.bs.WriteItem(c_oserct_plotareaOFPIECHART, function () {
                oThis.WriteCT_OfPieChart(chart);
            });
        }
        else if (chart instanceof AscFormat.CPieChart) {
            if(!oChart.view3D) {
                this.bs.WriteItem(c_oserct_plotareaPIECHART, function () {
                    oThis.WriteCT_PieChart(chart);
                });
            }
            else{
                this.bs.WriteItem(c_oserct_plotareaPIE3DCHART, function () {
                    oThis.WriteCT_Pie3DChart(chart);
                });
            }
        }
        // else if(chart instanceof CPie3DChart)
        // {
        // this.bs.WriteItem(c_oserct_plotareaPIE3DCHART, function () {
        // oThis.WriteCT_Pie3DChart(chart);
        // });
        // }
        else if (chart instanceof AscFormat.CRadarChart) {
            this.bs.WriteItem(c_oserct_plotareaRADARCHART, function () {
                oThis.WriteCT_RadarChart(chart);
            });
        }
        else if (chart instanceof AscFormat.CScatterChart) {
            this.bs.WriteItem(c_oserct_plotareaSCATTERCHART, function () {
                oThis.WriteCT_ScatterChart(chart);
            });
        }
        else if (chart instanceof AscFormat.CStockChart) {
            this.bs.WriteItem(c_oserct_plotareaSTOCKCHART, function () {
                oThis.WriteCT_StockChart(chart);
            });
        }
        else if (chart instanceof AscFormat.CSurfaceChart) {
            this.bs.WriteItem(c_oserct_plotareaSURFACECHART, function () {
                oThis.WriteCT_SurfaceChart(chart);
            });
        }
        // else if(chart instanceof CSurface3DChart)
        // {
        // this.bs.WriteItem(c_oserct_plotareaSURFACE3DCHART, function () {
        // oThis.WriteCT_Surface3DChart(chart);
        // });
        // }
    }
    for (var i = 0, length = oVal.axId.length; i < length; ++i) {
        var axis = oVal.axId[i];
        if (axis instanceof AscFormat.CCatAx) {
            this.bs.WriteItem(c_oserct_plotareaCATAX, function () {
                oThis.WriteCT_CatAx(axis);
            });
        }
        else if (axis instanceof AscFormat.CValAx) {
            this.bs.WriteItem(c_oserct_plotareaVALAX, function () {
                oThis.WriteCT_ValAx(axis);
            });
        }
        else if (axis instanceof AscFormat.CDateAx) {
            this.bs.WriteItem(c_oserct_plotareaDATEAX, function () {
                oThis.WriteCT_DateAx(axis);
            });
        }
        else if (axis instanceof AscFormat.CSerAx) {
            this.bs.WriteItem(c_oserct_plotareaSERAX, function () {
                oThis.WriteCT_SerAx(axis);
            });
        }
    }
    if (null != oVal.dTable) {
        this.bs.WriteItem(c_oserct_plotareaDTABLE, function () {
            oThis.WriteCT_DTable(oVal.dTable);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_plotareaSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_plotareaEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_Thickness = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_thicknessVAL, function () {
            oThis.memory.WriteString3(oThis.percentToString(oVal, true, false));
        });
    }
}
BinaryChartWriter.prototype.WriteCT_Surface = function (oVal) {
    var oThis = this;
    if (null != oVal.thickness) {
        this.bs.WriteItem(c_oserct_surfaceTHICKNESS, function () {
            oThis.WriteCT_Thickness(oVal.thickness);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_surfaceSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.pictureOptions) {
        this.bs.WriteItem(c_oserct_surfacePICTUREOPTIONS, function () {
            oThis.WriteCT_PictureOptions(oVal.pictureOptions);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_surfaceEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_Perspective = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_perspectiveVAL, function () {
            oThis.memory.WriteByte(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_DepthPercent = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_depthpercentVAL, function () {
            oThis.memory.WriteString3(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_RotY = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_rotyVAL, function () {
            oThis.memory.WriteLong(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_HPercent = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_hpercentVAL, function () {
            oThis.memory.WriteString3(oThis.percentToString(oVal, true, false));
        });
    }
}
BinaryChartWriter.prototype.WriteCT_RotX = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_rotxVAL, function () {
            oThis.memory.WriteSByte(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_View3D = function (oVal) {
    var oThis = this;
    if (null != oVal.rotX) {
        this.bs.WriteItem(c_oserct_view3dROTX, function () {
            oThis.WriteCT_RotX(oVal.rotX);
        });
    }
    if (null != oVal.hPercent) {
        this.bs.WriteItem(c_oserct_view3dHPERCENT, function () {
            oThis.WriteCT_HPercent(oVal.hPercent);
        });
    }
    if (null != oVal.rotY) {
        this.bs.WriteItem(c_oserct_view3dROTY, function () {
            oThis.WriteCT_RotY(oVal.rotY);
        });
    }
    if (null != oVal.depthPercent) {
        this.bs.WriteItem(c_oserct_view3dDEPTHPERCENT, function () {
            oThis.WriteCT_DepthPercent(oVal.depthPercent);
        });
    }
    if (null != oVal.rAngAx) {
        this.bs.WriteItem(c_oserct_view3dRANGAX, function () {
            oThis.WriteCT_Boolean(oVal.rAngAx);
        });
    }
    if (null != oVal.perspective) {
        this.bs.WriteItem(c_oserct_view3dPERSPECTIVE, function () {
            oThis.WriteCT_Perspective(oVal.perspective);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_view3dEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_PivotFmt = function (oVal) {
    var oThis = this;
    if (null != oVal.idx) {
        this.bs.WriteItem(c_oserct_pivotfmtIDX, function () {
            oThis.WriteCT_UnsignedInt(oVal.idx);
        });
    }
    if (null != oVal.spPr) {
        this.bs.WriteItem(c_oserct_pivotfmtSPPR, function () {
            oThis.WriteSpPr(oVal.spPr);
        });
    }
    if (null != oVal.txPr) {
        this.bs.WriteItem(c_oserct_pivotfmtTXPR, function () {
            oThis.WriteTxPr(oVal.txPr);
        });
    }
    if (null != oVal.marker) {
        this.bs.WriteItem(c_oserct_pivotfmtMARKER, function () {
            oThis.WriteCT_Marker(oVal.marker);
        });
    }
    if (null != oVal.dLbl && null != oVal.dLbl.idx) {
        this.bs.WriteItem(c_oserct_pivotfmtDLBL, function () {
            oThis.WriteCT_DLbl(oVal.dLbl);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_pivotfmtEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_pivotFmts = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        for (var i = 0, length = oVal.length; i < length; ++i) {
            var oCurVal = oVal[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oserct_pivotfmtsPIVOTFMT, function () {
                    oThis.WriteCT_PivotFmt(oCurVal);
                });
            }
        }
    }
}
BinaryChartWriter.prototype.WriteCT_Chart = function (oVal) {
    var oThis = this;

    if (null != oVal.title) {
        this.bs.WriteItem(c_oserct_chartTITLE, function () {
            oThis.WriteCT_Title(oVal.title);
        });
    }
    if (null != oVal.autoTitleDeleted) {
        this.bs.WriteItem(c_oserct_chartAUTOTITLEDELETED, function () {
            oThis.WriteCT_Boolean(oVal.autoTitleDeleted);
        });
    }
    if (null != oVal.pivotFmts && oVal.pivotFmts.length > 0) {
        this.bs.WriteItem(c_oserct_chartPIVOTFMTS, function () {
            oThis.WriteCT_pivotFmts(oVal.pivotFmts);
        });
    }
    if (null != oVal.view3D) {
        this.bs.WriteItem(c_oserct_chartVIEW3D, function () {
            oThis.WriteCT_View3D(oVal.view3D);
        });
    }
    if (null != oVal.floor) {
        this.bs.WriteItem(c_oserct_chartFLOOR, function () {
            oThis.WriteCT_Surface(oVal.floor);
        });
    }
    if (null != oVal.sideWall) {
        this.bs.WriteItem(c_oserct_chartSIDEWALL, function () {
            oThis.WriteCT_Surface(oVal.sideWall);
        });
    }
    if (null != oVal.backWall) {
        this.bs.WriteItem(c_oserct_chartBACKWALL, function () {
            oThis.WriteCT_Surface(oVal.backWall);
        });
    }
    if (null != oVal.plotArea) {
        this.bs.WriteItem(c_oserct_chartPLOTAREA, function () {
            oThis.WriteCT_PlotArea(oVal.plotArea, oVal);
        });
    }
    if (null != oVal.legend) {
        this.bs.WriteItem(c_oserct_chartLEGEND, function () {
            oThis.WriteCT_Legend(oVal.legend);
        });
    }
    if (null != oVal.plotVisOnly) {
        this.bs.WriteItem(c_oserct_chartPLOTVISONLY, function () {
            oThis.WriteCT_Boolean(oVal.plotVisOnly);
        });
    }
    if (null != oVal.dispBlanksAs) {
        this.bs.WriteItem(c_oserct_chartDISPBLANKSAS, function () {
            oThis.WriteCT_DispBlanksAs(oVal.dispBlanksAs);
        });
    }
    if (null != oVal.showDLblsOverMax) {
        this.bs.WriteItem(c_oserct_chartSHOWDLBLSOVERMAX, function () {
            oThis.WriteCT_Boolean(oVal.showDLblsOverMax);
        });
    }
    // var oCurVal = oVal.m_extLst;
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_chartEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
}
BinaryChartWriter.prototype.WriteCT_Protection = function (oVal) {
    var oThis = this;
    if (null != oVal.chartObject) {
        this.bs.WriteItem(c_oserct_protectionCHARTOBJECT, function () {
            oThis.WriteCT_Boolean(oVal.chartObject);
        });
    }
    if (null != oVal.data) {
        this.bs.WriteItem(c_oserct_protectionDATA, function () {
            oThis.WriteCT_Boolean(oVal.data);
        });
    }
    if (null != oVal.formatting) {
        this.bs.WriteItem(c_oserct_protectionFORMATTING, function () {
            oThis.WriteCT_Boolean(oVal.formatting);
        });
    }
    if (null != oVal.selection) {
        this.bs.WriteItem(c_oserct_protectionSELECTION, function () {
            oThis.WriteCT_Boolean(oVal.selection);
        });
    }
    if (null != oVal.userInterface) {
        this.bs.WriteItem(c_oserct_protectionUSERINTERFACE, function () {
            oThis.WriteCT_Boolean(oVal.userInterface);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_PivotSource = function (oVal) {
    var oThis = this;
    if (null != oVal.name) {
        this.bs.WriteItem(c_oserct_pivotsourceNAME, function () {
            oThis.memory.WriteString3(oVal.name);
        });
    }
    if (null != oVal.fmtId) {
        this.bs.WriteItem(c_oserct_pivotsourceFMTID, function () {
            oThis.WriteCT_UnsignedInt(oVal.fmtId);
        });
    }
    // if (null != oVal.m_extLst) {
    // for (var i = 0, length = oVal.m_extLst.length; i < length; ++i) {
    // var oCurVal = oVal.m_extLst[i];
    // if (null != oCurVal) {
    // this.bs.WriteItem(c_oserct_pivotsourceEXTLST, function () {
    // oThis.WriteCT_extLst(oCurVal);
    // });
    // }
    // }
    // }
}
BinaryChartWriter.prototype.WriteCT_Style1 = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_style1VAL, function () {
            oThis.memory.WriteByte(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_Style = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_styleVAL, function () {
            oThis.memory.WriteByte(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteCT_TextLanguageID = function (oVal) {
    var oThis = this;
    if (null != oVal) {
        this.bs.WriteItem(c_oserct_textlanguageidVAL, function () {
            oThis.memory.WriteString3(oVal);
        });
    }
}
BinaryChartWriter.prototype.WriteAlternateContent = function (oVal) {
    var oThis = this;
    if (null != oVal.m_Choice) {
        for (var i = 0, length = oVal.m_Choice.length; i < length; ++i) {
            var oCurVal = oVal.m_Choice[i];
            if (null != oCurVal) {
                this.bs.WriteItem(c_oseralternatecontentCHOICE, function () {
                    oThis.WriteAlternateContentChoice(oCurVal);
                });
            }
        }
    }
    var oCurVal = oVal.m_Fallback;
    if (null != oCurVal) {
        this.bs.WriteItem(c_oseralternatecontentFALLBACK, function () {
            oThis.WriteAlternateContentFallback(oCurVal);
        });
    }
}
BinaryChartWriter.prototype.WriteAlternateContentChoice = function (oVal) {
    var oThis = this;
    var oCurVal = oVal.m_style;
    if (null != oCurVal) {
        this.bs.WriteItem(c_oseralternatecontentchoiceSTYLE, function () {
            oThis.WriteCT_Style(oCurVal);
        });
    }
    var oCurVal = oVal.m_Requires;
    if (null != oCurVal) {
        this.bs.WriteItem(c_oseralternatecontentchoiceREQUIRES, function () {
            oThis.memory.WriteString3(oCurVal);
        });
    }
}
BinaryChartWriter.prototype.WriteAlternateContentFallback = function (oVal) {
    var oThis = this;
    var oCurVal = oVal.m_style;
    if (null != oCurVal) {
        this.bs.WriteItem(c_oseralternatecontentfallbackSTYLE, function () {
            oThis.WriteCT_Style1(oCurVal);
        });
    }
}
function BinaryChartReader(stream) {
    this.stream = stream;
    this.bcr = new AscCommon.Binary_CommonReader(this.stream);
}
BinaryChartReader.prototype.ReadCT_extLst = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_extlstEXT === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Extension(t, l, oNewVal);
        });
        if (null == val.m_ext)
            val.m_ext = [];
        val.m_ext.push(oNewVal);
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ExternalReadCT_ChartSpace = function (length, val, curWorksheet) {
    var res = c_oSerConstants.ReadOk;
    this.curWorksheet = curWorksheet;
    var oThis = this;
    this.curChart = val;
    res = this.bcr.Read1(length, function (t, l) {
        return oThis.ReadCT_ChartSpace(t, l, val);
    });
    if(val){
        if(null === val.date1904){
            val.setDate1904(false);
        }
        if(null === val.roundedCorners){
            val.setRoundedCorners(false);
        }
    }
    return res;
}
BinaryChartReader.prototype.ReadCT_ChartSpace = function (type, length, val, curWorksheet) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_chartspaceDATE1904 === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setDate1904(oNewVal.m_val);
        else
            val.setDate1904(true);
    }
    else if (c_oserct_chartspaceLANG === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TextLanguageID(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setLang(oNewVal.m_val);
    }
    else if (c_oserct_chartspaceROUNDEDCORNERS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setRoundedCorners(oNewVal.m_val);
    }
    else if (c_oserct_chartspaceALTERNATECONTENT === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadAlternateContent(t, l, oNewVal);
        });
        var nNewStyle = null;
        if (null != oNewVal.m_Choice && oNewVal.m_Choice.length > 0) {
            var choice = oNewVal.m_Choice[0];
            if (null != choice.m_style && null != choice.m_style.m_val)
                nNewStyle = choice.m_style.m_val - 100;
        }
        if (null == nNewStyle && null != oNewVal.m_Fallback && null != oNewVal.m_Fallback.m_style && null != oNewVal.m_Fallback.m_style.m_val)
            nNewStyle = oNewVal.m_Fallback.m_style.m_val;
        if (null != nNewStyle)
            val.setStyle(nNewStyle);
    }
    else if (c_oserct_chartspaceSTYLE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Style1(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setStyle(oNewVal.m_val);
    }
    else if (c_oserct_chartspaceCLRMAPOVR === type) {
        val.setClrMapOvr(this.ReadClrOverride(length));
    }
    else if (c_oserct_chartspacePIVOTSOURCE === type) {
        var oNewVal = new AscFormat.CPivotSource();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PivotSource(t, l, oNewVal);
        });
        val.setPivotSource(oNewVal);
    }
    else if (c_oserct_chartspacePROTECTION === type) {
        var oNewVal = new AscFormat.CProtection();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Protection(t, l, oNewVal);
        });
        val.setProtection(oNewVal);
    }
    else if (c_oserct_chartspaceCHART === type) {
        var oNewVal = new AscFormat.CChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Chart(t, l, oNewVal);
        });
        val.setChart(oNewVal);
        if(null === oNewVal.autoTitleDeleted){
            oNewVal.setAutoTitleDeleted(false);
        }
        if(null === oNewVal.showDLblsOverMax){
            oNewVal.setShowDLblsOverMax(false);
        }
    }
    else if (c_oserct_chartspaceSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
        val.spPr.setParent(val);
    }
    else if (c_oserct_chartspaceTXPR === type) {
        val.setTxPr(this.ReadTxPr(length));
        val.txPr.setParent(val);
    }
    //else if (c_oserct_chartspaceEXTERNALDATA === type) {
    //    var oNewVal;
    //    oNewVal = {};
    //    res = this.bcr.Read1(length, function (t, l) {
    //        return oThis.ReadCT_ExternalData(t, l, oNewVal);
    //    });
    //    val.m_externalData = oNewVal;
    //}
    else if (c_oserct_chartspacePRINTSETTINGS === type) {
        var oNewVal = new AscFormat.CPrintSettings();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PrintSettings(t, l, oNewVal);
        });
        val.setPrintSettings(oNewVal);
    }
    //else if (c_oserct_chartspaceUSERSHAPES === type) {
    //    var oNewVal;
    //    oNewVal = {};
    //    res = this.bcr.Read1(length, function (t, l) {
    //        return oThis.ReadCT_RelId(t, l, oNewVal);
    //    });
    //    val.m_userShapes = oNewVal;
    //}
    else if (c_oserct_chartspaceEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else if (c_oserct_chartspaceTHEMEOVERRIDE === type) {
        var theme = AscCommon.pptx_content_loader.ReadTheme(this, this.stream);
        if (null != theme)
            val.setThemeOverride(theme);
        res = c_oSerConstants.ReadUnknown;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadSpPr = function (length) {
    return AscCommon.pptx_content_loader.ReadShapeProperty(this.stream);
}

BinaryChartReader.prototype.ReadClrOverride = function(lenght)
{
    var loader = new AscCommon.BinaryPPTYLoader();

    loader.stream = new AscCommon.FileStream();
    loader.stream.obj    = this.stream.obj;
    loader.stream.data   = this.stream.data;
    loader.stream.size   = this.stream.size;

    loader.stream.pos    = this.stream.pos;
    loader.stream.cur    = this.stream.cur;
    var s = loader.stream;
    var _main_type = s.GetUChar(); // 0!!!

    var clr_map =  new AscFormat.ClrMap();
    loader.ReadClrMap(clr_map);

    this.stream.pos = s.pos;
    this.stream.cur = s.cur;
    return clr_map;

};

BinaryChartReader.prototype.ReadTxPr = function (length) {
    var cur = this.stream.cur;
    var ret = AscCommon.pptx_content_loader.ReadTextBody(null, this.stream, null, this.curWorksheet);
    this.stream.cur = cur + length;
    return ret;
}
BinaryChartReader.prototype.ParsePersent = function (val) {
    var nVal = parseFloat(val);
    if (!isNaN(nVal))
        return nVal;
    else
        return null;
}
BinaryChartReader.prototype.ParseMetric = function (val) {
    var nVal = parseFloat(val);
    var nRes = null;
    if (!isNaN(nVal)) {
        if (-1 != val.indexOf("mm"))
            nRes = nVal;
        else if (-1 != val.indexOf("cm"))
            nRes = nVal * 10;
        else if (-1 != val.indexOf("in"))
            nRes = nVal * 2.54 * 10;
        else if (-1 != val.indexOf("pt"))
            nRes = nVal * 2.54 * 10 / 72;
        else if (-1 != val.indexOf("pc") || -1 != val.indexOf("pi"))
            nRes = nVal * 12 * 2.54 * 10 / 72;
    }
    return nRes;
}
BinaryChartReader.prototype.ConvertSurfaceToLine = function (oSurface, aChartWithAxis) {
    var oLine = new AscFormat.CLineChart();
    oLine.setGrouping(AscFormat.GROUPING_STANDARD);
    oLine.setVaryColors(false);
    for (var i = 0, length = oSurface.series.length; i < length; ++i) {
        var surfaceSer = oSurface.series[i];
        var lineSer = new AscFormat.CLineSeries();
        if (null != surfaceSer.idx)
            lineSer.setIdx(surfaceSer.idx);
        if (null != surfaceSer.order)
            lineSer.setOrder(surfaceSer.order);
        if (null != surfaceSer.tx)
            lineSer.setTx(surfaceSer.tx);
        if (null != surfaceSer.spPr)
            lineSer.setSpPr(surfaceSer.spPr);
        if (null != surfaceSer.cat)
            lineSer.setCat(surfaceSer.cat);
        if (null != surfaceSer.val)
            lineSer.setVal(surfaceSer.val);
        var marker = new AscFormat.CMarker();
        marker.setSymbol(AscFormat.SYMBOL_NONE);
        lineSer.setMarker(marker);
        lineSer.setSmooth(false);
        oLine.addSer(lineSer);
    }
    var dLbls = new AscFormat.CDLbls();
    dLbls.setShowLegendKey(false);
    dLbls.setShowVal(false);
    dLbls.setShowCatName(false);
    dLbls.setShowSerName(false);
    dLbls.setShowPercent(false);
    dLbls.setShowBubbleSize(false);
    oLine.setDLbls(dLbls);
    oLine.setMarker(true);
    oLine.setSmooth(false);
    this.CorrectChartWithAxis(oSurface, oLine, aChartWithAxis);
    return oLine;
};
BinaryChartReader.prototype.ConvertSurfaceValAxToLineValAx = function (oSurfaceValAx) {
    oSurfaceValAx.setCrossBetween(AscFormat.CROSS_BETWEEN_BETWEEN);
    oSurfaceValAx.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
}
BinaryChartReader.prototype.ConvertRadarToLine = function (oRadar, aChartWithAxis) {
    var bMarkerNull = RADAR_STYLE_FILLED == oRadar.radarStyle;
    var oLine = new AscFormat.CLineChart();
    oLine.setGrouping(AscFormat.GROUPING_STANDARD);
    if (null != oRadar.varyColors)
        oLine.setVaryColors(oRadar.varyColors);
    if (null != oRadar.dLbls)
        oLine.setDLbls(oRadar.dLbls);
    for (var i = 0, length = oRadar.series.length; i < length; ++i) {
        var radarSer = oRadar.series[i];
        var lineSer = new AscFormat.CLineSeries();
        if (null != radarSer.idx)
            lineSer.setIdx(radarSer.idx);
        if (null != radarSer.order)
            lineSer.setOrder(radarSer.order);
        if (null != radarSer.tx)
            lineSer.setTx(radarSer.tx);
        if (null != radarSer.spPr)
            lineSer.setSpPr(radarSer.spPr);
        if (null != radarSer.marker)
            lineSer.setMarker(radarSer.marker);
        else if(bMarkerNull){
            var marker = new AscFormat.CMarker();
            marker.setSymbol(AscFormat.SYMBOL_NONE);
            lineSer.setMarker(marker);
        }
        
        for (var j = 0, length2 = radarSer.dPt.length; j < length2; ++j) {
            lineSer.addDPt(radarSer.dPt[j]);
        }
        if (null != radarSer.dLbls)
            lineSer.setDLbls(radarSer.dLbls);
        if (null != radarSer.cat)
            lineSer.setCat(radarSer.cat);
        if (null != radarSer.val)
            lineSer.setVal(radarSer.val);
        lineSer.setSmooth(false);
        oLine.addSer(lineSer);
    }
    oLine.setMarker(true);
    oLine.setSmooth(false);
    this.CorrectChartWithAxis(oRadar, oLine, aChartWithAxis);
    return oLine;
};
BinaryChartReader.prototype.ConvertBubbleToScatter = function (oBubble, aChartWithAxis) {
    var oScatter = new AscFormat.CScatterChart();
    oScatter.setScatterStyle(AscFormat.SCATTER_STYLE_LINE_MARKER);
    if (null != oBubble.varyColors)
        oScatter.setVaryColors(oBubble.varyColors);
    if (null != oBubble.dLbls)
        oScatter.setDLbls(oBubble.dLbls);
    for (var i = 0, length = oBubble.series.length; i < length; ++i) {
        var bubbleSer = oBubble.series[i];
        var scatterSer = new AscFormat.CScatterSeries();
        if (null != bubbleSer.idx)
            scatterSer.setIdx(bubbleSer.idx);
        if (null != bubbleSer.order)
            scatterSer.setOrder(bubbleSer.order);
        if (null != bubbleSer.tx)
            scatterSer.setTx(bubbleSer.tx);
        //if (null != bubbleSer.spPr)
        //    scatterSer.setSpPr(bubbleSer.spPr);
        for (var j = 0, length2 = bubbleSer.dPt.length; j < length2; ++j) {
            scatterSer.addDPt(bubbleSer.dPt[j]);
        }
        if (null != bubbleSer.dLbls)
            scatterSer.setDLbls(bubbleSer.dLbls);
        if (null != bubbleSer.trendline)
            scatterSer.setTrendline(bubbleSer.trendline);
        if (null != bubbleSer.errBars)
            scatterSer.setErrBars(bubbleSer.errBars);
        if (null != bubbleSer.xVal)
            scatterSer.setXVal(bubbleSer.xVal);
        if (null != bubbleSer.yVal)
            scatterSer.setYVal(bubbleSer.yVal);
        var spPr = new AscFormat.CSpPr();
        var ln = new AscFormat.CLn();
        ln.setW(28575);
        var uni_fill = new AscFormat.CUniFill();
        uni_fill.setFill(new AscFormat.CNoFill());
        ln.setFill(uni_fill);
        spPr.setLn(ln);
        scatterSer.setSpPr(spPr);
        scatterSer.setSmooth(false);
        oScatter.addSer(scatterSer);
    }
    this.CorrectChartWithAxis(oBubble, oScatter, aChartWithAxis);
    return oScatter;
};
BinaryChartReader.prototype.ConvertOfPieToPie = function (oOfPie, aChartWithAxis) {
    var oPie = new AscFormat.CPieChart();
    if (null != oOfPie.varyColors)
        oPie.setVaryColors(oOfPie.varyColors);
    if (null != oOfPie.dLbls)
        oPie.setDLbls(oOfPie.dLbls);
    for (var i = 0, length = oOfPie.series.length; i < length; ++i) {
        oPie.addSer(oOfPie.series[i]);
    }
    oPie.setFirstSliceAng(0);
    this.CorrectChartWithAxis(oOfPie, oPie, aChartWithAxis);
    return oPie;
};
BinaryChartReader.prototype.CorrectChartWithAxis = function (chartOld, chartNew, aChartWithAxis) {
    for (var i = 0, length = aChartWithAxis.length; i < length; ++i) {
        var item = aChartWithAxis[i];
        if (item.chart == chartOld)
            item.chart = chartNew;
    }
};
BinaryChartReader.prototype.ReadCT_Boolean = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_booleanVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetBool();
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ExternalReadCT_RelId = function (length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    res = this.bcr.Read1(length, function (t, l) {
        return oThis.ReadCT_RelId(t, l, val);
    });
    return res;
}
BinaryChartReader.prototype.ReadCT_RelId = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_relidID === type) {
        //todo
        var oNewVal;
        oNewVal = this.stream.GetString2LE(length);
        val.m_id = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_PageSetup = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_pagesetupPAPERSIZE === type) {
        val.setPaperSize(this.stream.GetULongLE());
    }
    else if (c_oserct_pagesetupPAPERHEIGHT === type) {
        var mm = this.ParseMetric(this.stream.GetString2LE(length));
        if (null != mm)
            val.setPaperHeight(mm);
    }
    else if (c_oserct_pagesetupPAPERWIDTH === type) {
        var mm = this.ParseMetric(this.stream.GetString2LE(length));
        if (null != mm)
            val.setPaperWidth(mm);
    }
    else if (c_oserct_pagesetupFIRSTPAGENUMBER === type) {
        val.setFirstPageNumber(this.stream.GetULongLE());
    }
    else if (c_oserct_pagesetupORIENTATION === type) {
        switch (this.stream.GetUChar()) {
            case st_pagesetuporientationDEFAULT: val.setOrientation(AscFormat.PAGE_SETUP_ORIENTATION_DEFAULT); break;
            case st_pagesetuporientationPORTRAIT: val.setOrientation(AscFormat.PAGE_SETUP_ORIENTATION_PORTRAIT); break;
            case st_pagesetuporientationLANDSCAPE: val.setOrientation(AscFormat.PAGE_SETUP_ORIENTATION_LANDSCAPE); break;
        }
    }
    else if (c_oserct_pagesetupBLACKANDWHITE === type) {
        val.setBlackAndWhite(this.stream.GetBool());
    }
    else if (c_oserct_pagesetupDRAFT === type) {
        val.setBlackAndWhite(this.stream.GetBool());
    }
    else if (c_oserct_pagesetupUSEFIRSTPAGENUMBER === type) {
        val.setUseFirstPageNumb(this.stream.GetBool());
    }
    else if (c_oserct_pagesetupHORIZONTALDPI === type) {
        val.setHorizontalDpi(this.stream.GetULongLE());
    }
    else if (c_oserct_pagesetupVERTICALDPI === type) {
        val.setVerticalDpi(this.stream.GetULongLE());
    }
    else if (c_oserct_pagesetupCOPIES === type) {
        val.setCopies(this.stream.GetULongLE());
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_PageMargins = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_pagemarginsL === type) {
        val.setL(this.stream.GetDoubleLE());
    }
    else if (c_oserct_pagemarginsR === type) {
        val.setR(this.stream.GetDoubleLE());
    }
    else if (c_oserct_pagemarginsT === type) {
        val.setT(this.stream.GetDoubleLE());
    }
    else if (c_oserct_pagemarginsB === type) {
        val.setB(this.stream.GetDoubleLE());
    }
    else if (c_oserct_pagemarginsHEADER === type) {
        val.setHeader(this.stream.GetDoubleLE());
    }
    else if (c_oserct_pagemarginsFOOTER === type) {
        val.setFooter(this.stream.GetDoubleLE());
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_HeaderFooter = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_headerfooterODDHEADER === type) {
        val.setOddHeader(this.stream.GetString2LE(length));
    }
    else if (c_oserct_headerfooterODDFOOTER === type) {
        val.setOddFooter(this.stream.GetString2LE(length));
    }
    else if (c_oserct_headerfooterEVENHEADER === type) {
        val.setEvenHeader(this.stream.GetString2LE(length));
    }
    else if (c_oserct_headerfooterEVENFOOTER === type) {
        val.setEvenFooter(this.stream.GetString2LE(length));
    }
    else if (c_oserct_headerfooterFIRSTHEADER === type) {
        val.setFirstHeader(this.stream.GetString2LE(length));
    }
    else if (c_oserct_headerfooterFIRSTFOOTER === type) {
        val.setFirstFooter(this.stream.GetString2LE(length));
    }
    else if (c_oserct_headerfooterALIGNWITHMARGINS === type) {
        val.setAlignWithMargins(this.stream.GetBool());
    }
    else if (c_oserct_headerfooterDIFFERENTODDEVEN === type) {
        val.setDifferentOddEven(this.stream.GetBool());
    }
    else if (c_oserct_headerfooterDIFFERENTFIRST === type) {
        val.setDifferentFirst(this.stream.GetBool());
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_PrintSettings = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_printsettingsHEADERFOOTER === type) {
        var oNewVal = new AscFormat.CHeaderFooterChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_HeaderFooter(t, l, oNewVal);
        });
        val.setHeaderFooter(oNewVal);
    }
    else if (c_oserct_printsettingsPAGEMARGINS === type) {
        var oNewVal = new AscFormat.CPageMarginsChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PageMargins(t, l, oNewVal);
        });
        val.setPageMargins(oNewVal);
    }
    else if (c_oserct_printsettingsPAGESETUP === type) {
        var oNewVal = new AscFormat.CPageSetup();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PageSetup(t, l, oNewVal);
        });
        val.setPageSetup(oNewVal);
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_ExternalData = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_externaldataAUTOUPDATE === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        val.m_autoUpdate = oNewVal;
    }
    else if (c_oserct_externaldataID === type) {
        //todo
        var oNewVal;
        oNewVal = this.stream.GetString2LE(length);
        val.m_id = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_DispBlanksAs = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_dispblanksasVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_dispblanksasSPAN: val.m_val = AscFormat.DISP_BLANKS_AS_SPAN; break;
            case st_dispblanksasGAP: val.m_val = AscFormat.DISP_BLANKS_AS_GAP; break;
            case st_dispblanksasZERO: val.m_val = AscFormat.DISP_BLANKS_AS_ZERO; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_LegendEntry = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_legendentryIDX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setIdx(oNewVal.m_val);
    }
    else if (c_oserct_legendentryDELETE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setDelete(oNewVal.m_val);
        else
            val.setDelete(true);
    }
    else if (c_oserct_legendentryTXPR === type) {
        val.setTxPr(this.ReadTxPr(length));
        val.txPr.setParent(val);
    }
    else if (c_oserct_legendentryEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_UnsignedInt = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_unsignedintVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetULongLE();
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Extension = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_extensionANY === type) {
        var oNewVal;
        oNewVal = this.stream.GetString2LE(length);
        val.m_Any = oNewVal;
    }
    else if (c_oserct_extensionURI === type) {
        var oNewVal;
        oNewVal = this.stream.GetString2LE(length);
        val.m_uri = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_LegendPos = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_legendposVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_legendposB: val.m_val = c_oAscChartLegendShowSettings.bottom; break;
            case st_legendposTR: val.m_val = c_oAscChartLegendShowSettings.topRight; break;
            case st_legendposL: val.m_val = c_oAscChartLegendShowSettings.left; break;
            case st_legendposR: val.m_val = c_oAscChartLegendShowSettings.right; break;
            case st_legendposT: val.m_val = c_oAscChartLegendShowSettings.top; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Legend = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_legendLEGENDPOS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_LegendPos(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setLegendPos(oNewVal.m_val);
    }
    else if (c_oserct_legendLEGENDENTRY === type) {
        var oNewVal = new AscFormat.CLegendEntry();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_LegendEntry(t, l, oNewVal);
        });
        val.addLegendEntry(oNewVal);
    }
    else if (c_oserct_legendLAYOUT === type) {
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Layout(t, l, val);
        });
    }
    else if (c_oserct_legendOVERLAY === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setOverlay(oNewVal.m_val);
    }
    else if (c_oserct_legendSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_legendTXPR === type) {
        val.setTxPr(this.ReadTxPr(length));
        val.txPr.setParent(val);
    }
    else if (c_oserct_legendEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Layout = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_layoutMANUALLAYOUT === type) {
        var oNewVal = new AscFormat.CLayout();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ManualLayout(t, l, oNewVal);
        });
        val.setLayout(oNewVal);
    }
    else if (c_oserct_layoutEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_ManualLayout = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_manuallayoutLAYOUTTARGET === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_LayoutTarget(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setLayoutTarget(oNewVal.m_val);
    }
    else if (c_oserct_manuallayoutXMODE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_LayoutMode(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setXMode(oNewVal.m_val);
    }
    else if (c_oserct_manuallayoutYMODE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_LayoutMode(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setYMode(oNewVal.m_val);
    }
    else if (c_oserct_manuallayoutWMODE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_LayoutMode(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setWMode(oNewVal.m_val);
    }
    else if (c_oserct_manuallayoutHMODE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_LayoutMode(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setHMode(oNewVal.m_val);
    }
    else if (c_oserct_manuallayoutX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Double(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setX(oNewVal.m_val);
    }
    else if (c_oserct_manuallayoutY === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Double(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setY(oNewVal.m_val);
    }
    else if (c_oserct_manuallayoutW === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Double(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setW(oNewVal.m_val);
    }
    else if (c_oserct_manuallayoutH === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Double(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setH(oNewVal.m_val);
    }
    else if (c_oserct_manuallayoutEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_LayoutTarget = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_layouttargetVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_layouttargetINNER: val.m_val = LAYOUT_TARGET_INNER; break;
            case st_layouttargetOUTER: val.m_val = LAYOUT_TARGET_OUTER; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_LayoutMode = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_layoutmodeVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_layoutmodeEDGE: val.m_val = LAYOUT_MODE_EDGE; break;
            case st_layoutmodeFACTOR: val.m_val = LAYOUT_MODE_FACTOR; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Double = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_doubleVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetDoubleLE();
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_DTable = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_dtableSHOWHORZBORDER === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowHorzBorder(oNewVal.m_val);
    }
    else if (c_oserct_dtableSHOWVERTBORDER === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowVertBorder(oNewVal.m_val);
    }
    else if (c_oserct_dtableSHOWOUTLINE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowOutline(oNewVal.m_val);
    }
    else if (c_oserct_dtableSHOWKEYS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowKeys(oNewVal.m_val);
    }
    else if (c_oserct_dtableSPPR === type) {
        val.setSpPr(this.ReadSpPr(length))
    }
    else if (c_oserct_dtableTXPR === type) {
        val.setTxPr(this.ReadTxPr(length));
        val.txPr.setParent(val);
    }
    else if (c_oserct_dtableEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_SerAx = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_seraxAXID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setAxId(oNewVal.m_val);
    }
    else if (c_oserct_seraxSCALING === type) {
        var oNewVal = new AscFormat.CScaling();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Scaling(t, l, oNewVal);
        });
        val.setScaling(oNewVal);
    }
    else if (c_oserct_seraxDELETE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setDelete(oNewVal.m_val);
        else
            val.setDelete(true);
    }
    else if (c_oserct_seraxAXPOS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AxPos(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setAxPos(oNewVal.m_val);
    }
    else if (c_oserct_seraxMAJORGRIDLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setMajorGridlines(oNewVal.spPr);
        else
            val.setMajorGridlines(new AscFormat.CSpPr());
    }
    else if (c_oserct_seraxMINORGRIDLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setMinorGridlines(oNewVal.spPr);
        else
            val.setMinorGridlines(new AscFormat.CSpPr());
    }
    else if (c_oserct_seraxTITLE === type) {
        var oNewVal = new AscFormat.CTitle();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Title(t, l, oNewVal);
        });
        if(!AscFormat.isRealBool(oNewVal.overlay))
        {
            oNewVal.setOverlay(false);
        }
        val.setTitle(oNewVal);
    }
    else if (c_oserct_seraxNUMFMT === type) {
        var oNewVal = new AscFormat.CNumFmt();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumFmt(t, l, oNewVal);
        });
        val.setNumFmt(oNewVal);
    }
    else if (c_oserct_seraxMAJORTICKMARK === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TickMark(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setMajorTickMark(oNewVal.m_val);
        else{
            val.setMajorTickMark(c_oAscTickMark.TICK_MARK_CROSS);
        }
    }
    else if (c_oserct_seraxMINORTICKMARK === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TickMark(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setMinorTickMark(oNewVal.m_val);
        else{
            val.setMajorTickMark(c_oAscTickMark.TICK_MARK_CROSS);
        }
    }
    else if (c_oserct_seraxTICKLBLPOS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TickLblPos(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setTickLblPos(oNewVal.m_val);
    }
    else if (c_oserct_seraxSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_seraxTXPR === type) {
        val.setTxPr(this.ReadTxPr(length));
        val.txPr.setParent(val);
    }
    else if (c_oserct_seraxCROSSAX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });

        if (null != oNewVal.m_val)
        {
            val.crossAxId = oNewVal.m_val;
        }
    }
    else if (c_oserct_seraxCROSSES === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Crosses(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setCrosses(oNewVal.m_val);
    }
    else if (c_oserct_seraxCROSSESAT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Double(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setCrossesAt(oNewVal.m_val);
    }
    else if (c_oserct_seraxTICKLBLSKIP === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Skip(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setTickLblSkip(oNewVal.m_val);
    }
    else if (c_oserct_seraxTICKMARKSKIP === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Skip(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setTickMarkSkip(oNewVal.m_val);
    }
    else if (c_oserct_seraxEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Scaling = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_scalingLOGBASE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_LogBase(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setLogBase(oNewVal.m_val);
    }
    else if (c_oserct_scalingORIENTATION === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Orientation(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setOrientation(oNewVal.m_val);
    }
    else if (c_oserct_scalingMAX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Double(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setMax(oNewVal.m_val);
    }
    else if (c_oserct_scalingMIN === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Double(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setMin(oNewVal.m_val);
    }
    else if (c_oserct_scalingEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_LogBase = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_logbaseVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetDoubleLE();
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Orientation = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_orientationVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_orientationMAXMIN: val.m_val = AscFormat.ORIENTATION_MAX_MIN; break;
            case st_orientationMINMAX: val.m_val = AscFormat.ORIENTATION_MIN_MAX; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_AxPos = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_axposVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_axposB: val.m_val = AscFormat.AX_POS_B; break;
            case st_axposL: val.m_val = AscFormat.AX_POS_L; break;
            case st_axposR: val.m_val = AscFormat.AX_POS_R; break;
            case st_axposT: val.m_val = AscFormat.AX_POS_T; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_ChartLines = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_chartlinesSPPR === type) {
        val.spPr = this.ReadSpPr(length);
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Title = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_titleTX === type) {
        var oNewVal = new AscFormat.CChartText();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Tx(t, l, oNewVal);
        });
        oNewVal.setChart(this.curChart);
        val.setTx(oNewVal);
    }
    else if (c_oserct_titleLAYOUT === type) {
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Layout(t, l, val);
        });
    }
    else if (c_oserct_titleOVERLAY === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setOverlay(oNewVal.m_val);
    }
    else if (c_oserct_titleSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_titleTXPR === type) {
        val.setTxPr(this.ReadTxPr(length));
        val.txPr.setParent(val);
    }
    else if (c_oserct_titleEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Tx = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_txRICH === type) {
        val.setRich(this.ReadTxPr(length));
        val.rich.setParent(val);
    }
    else if (c_oserct_txSTRREF === type) {
        var oNewVal = new AscFormat.CStrRef();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_StrRef(t, l, oNewVal);
        });
        val.setStrRef(oNewVal);
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_StrRef = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_strrefF === type) {
        val.setF(this.stream.GetString2LE(length));
    }
    else if (c_oserct_strrefSTRCACHE === type) {
        var oNewVal = new AscFormat.CStrCache();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_StrData(t, l, oNewVal);
        });
        val.setStrCache(oNewVal);
    }
    else if (c_oserct_strrefEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_StrData = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_strdataPTCOUNT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setPtCount(oNewVal.m_val);
    }
    else if (c_oserct_strdataPT === type) {
        var oNewVal = new AscFormat.CStringPoint();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_StrVal(t, l, oNewVal);
        });
        val.addPt(oNewVal);
    }
    else if (c_oserct_strdataEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_StrVal = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_strvalV === type) {
        val.setVal(this.stream.GetString2LE(length));
    }
    else if (c_oserct_strvalIDX === type) {
        val.setIdx(this.stream.GetULongLE());
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_NumFmt = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_numfmtFORMATCODE === type) {
        val.setFormatCode(this.stream.GetString2LE(length));
    }
    else if (c_oserct_numfmtSOURCELINKED === type) {
        val.setSourceLinked(this.stream.GetBool());
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_TickMark = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_tickmarkVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_tickmarkCROSS: val.m_val = c_oAscTickMark.TICK_MARK_CROSS; break;
            case st_tickmarkIN: val.m_val = c_oAscTickMark.TICK_MARK_IN; break;
            case st_tickmarkNONE: val.m_val = c_oAscTickMark.TICK_MARK_NONE; break;
            case st_tickmarkOUT: val.m_val = c_oAscTickMark.TICK_MARK_OUT; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_TickLblPos = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_ticklblposVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_ticklblposHIGH: val.m_val = c_oAscTickLabelsPos.TICK_LABEL_POSITION_HIGH; break;
            case st_ticklblposLOW: val.m_val = c_oAscTickLabelsPos.TICK_LABEL_POSITION_LOW; break;
            case st_ticklblposNEXTTO: val.m_val = c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO; break;
            case st_ticklblposNONE: val.m_val = c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Crosses = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_crossesVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_crossesAUTOZERO: val.m_val = AscFormat.CROSSES_AUTO_ZERO; break;
            case st_crossesMAX: val.m_val = AscFormat.CROSSES_MAX; break;
            case st_crossesMIN: val.m_val = AscFormat.CROSSES_MIN; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Skip = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_skipVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetULongLE();
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_TimeUnit = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_timeunitVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_timeunitDAYS: val.m_val = AscFormat.TIME_UNIT_DAYS; break;
            case st_timeunitMONTHS: val.m_val = AscFormat.TIME_UNIT_MONTHS; break;
            case st_timeunitYEARS: val.m_val = AscFormat.TIME_UNIT_YEARS; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_DateAx = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_dateaxAXID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setAxId(oNewVal.m_val);
    }
    else if (c_oserct_dateaxSCALING === type) {
        var oNewVal = new AscFormat.CScaling();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Scaling(t, l, oNewVal);
        });
        val.setScaling(oNewVal);
    }
    else if (c_oserct_dateaxDELETE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setDelete(oNewVal.m_val);
        else
            val.setDelete(true);
    }
    else if (c_oserct_dateaxAXPOS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AxPos(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setAxPos(oNewVal.m_val);
    }
    else if (c_oserct_dateaxMAJORGRIDLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setMajorGridlines(oNewVal.spPr);
        else
            val.setMajorGridlines(new AscFormat.CSpPr());
    }
    else if (c_oserct_dateaxMINORGRIDLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setMinorGridlines(oNewVal.spPr);
        else
            val.setMinorGridlines(new AscFormat.CSpPr());
    }
    else if (c_oserct_dateaxTITLE === type) {
        var oNewVal = new AscFormat.CTitle();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Title(t, l, oNewVal);
        });
        if(!AscFormat.isRealBool(oNewVal.overlay))
        {
            oNewVal.setOverlay(false);
        }
        val.setTitle(oNewVal);
    }
    else if (c_oserct_dateaxNUMFMT === type) {
        var oNewVal = new AscFormat.CNumFmt();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumFmt(t, l, oNewVal);
        });
        val.setNumFmt(oNewVal);
    }
    else if (c_oserct_dateaxMAJORTICKMARK === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TickMark(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setMajorTickMark(oNewVal.m_val);
        else{
            val.setMajorTickMark(c_oAscTickMark.TICK_MARK_CROSS);
        }
    }
    else if (c_oserct_dateaxMINORTICKMARK === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TickMark(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setMinorTickMark(oNewVal.m_val);
        else{
            val.setMajorTickMark(c_oAscTickMark.TICK_MARK_CROSS);
        }
    }
    else if (c_oserct_dateaxTICKLBLPOS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TickLblPos(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setTickLblPos(oNewVal.m_val);
    }
    else if (c_oserct_dateaxSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_dateaxTXPR === type) {
        val.setTxPr(this.ReadTxPr(length));
        val.txPr.setParent(val);
    }
    else if (c_oserct_dateaxCROSSAX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });

        if (null != oNewVal.m_val)
        {
            val.crossAxId = oNewVal.m_val;
        }
    }
    else if (c_oserct_dateaxCROSSES === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Crosses(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setCrosses(oNewVal.m_val);
    }
    else if (c_oserct_dateaxCROSSESAT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Double(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setCrossesAt(oNewVal.m_val);
    }
    else if (c_oserct_dateaxAUTO === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setAuto(oNewVal.m_val);
    }
    else if (c_oserct_dateaxLBLOFFSET === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_LblOffset(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setLblOffset(oNewVal.m_val);
    }
    else if (c_oserct_dateaxBASETIMEUNIT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TimeUnit(t, l, oNewVal);
        });
        // if (null != oNewVal.m_val) {
        // val.setMinorTimeUnit(oNewVal.m_val);
    }
    else if (c_oserct_dateaxMAJORUNIT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AxisUnit(t, l, oNewVal);
        });
        // if (null != oNewVal.m_val)
        // val.setMajorUnit(oNewVal.m_val);
    }
    else if (c_oserct_dateaxMAJORTIMEUNIT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TimeUnit(t, l, oNewVal);
        });
        // if (null != oNewVal.m_val) {
        // val.setMinorTimeUnit(oNewVal.m_val);
    }
    else if (c_oserct_dateaxMINORUNIT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AxisUnit(t, l, oNewVal);
        });
        // if (null != oNewVal.m_val)
        // val.setMinorUnit(oNewVal.m_val);
    }
    else if (c_oserct_dateaxMINORTIMEUNIT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TimeUnit(t, l, oNewVal);
        });
        // if (null != oNewVal.m_val)
        // val.setMinorTimeUnit(oNewVal.m_val);
    }
    else if (c_oserct_dateaxEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_LblOffset = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_lbloffsetVAL === type) {
        val.m_val = this.ParsePersent(this.stream.GetString2LE(length));
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_AxisUnit = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_axisunitVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetDoubleLE();
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_LblAlgn = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_lblalgnVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_lblalgnCTR: val.m_val = AscFormat.LBL_ALG_CTR; break;
            case st_lblalgnL: val.m_val = AscFormat.LBL_ALG_L; break;
            case st_lblalgnR: val.m_val = AscFormat.LBL_ALG_R; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_CatAx = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_cataxAXID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setAxId(oNewVal.m_val);
    }
    else if (c_oserct_cataxSCALING === type) {
        var oNewVal = new AscFormat.CScaling();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Scaling(t, l, oNewVal);
        });
        val.setScaling(oNewVal);
    }
    else if (c_oserct_cataxDELETE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setDelete(oNewVal.m_val);
        else
            val.setDelete(true);
    }
    else if (c_oserct_cataxAXPOS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AxPos(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setAxPos(oNewVal.m_val);
    }
    else if (c_oserct_cataxMAJORGRIDLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setMajorGridlines(oNewVal.spPr);
        else
            val.setMajorGridlines(new AscFormat.CSpPr());
    }
    else if (c_oserct_cataxMINORGRIDLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setMinorGridlines(oNewVal.spPr);
        else
            val.setMinorGridlines(new AscFormat.CSpPr());
    }
    else if (c_oserct_cataxTITLE === type) {
        var oNewVal = new AscFormat.CTitle();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Title(t, l, oNewVal);
        });
        if(!AscFormat.isRealBool(oNewVal.overlay))
        {
            oNewVal.setOverlay(true);
        }
        val.setTitle(oNewVal);
    }
    else if (c_oserct_cataxNUMFMT === type) {
        var oNewVal = new AscFormat.CNumFmt();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumFmt(t, l, oNewVal);
        });
        val.setNumFmt(oNewVal);
    }
    else if (c_oserct_cataxMAJORTICKMARK === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TickMark(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setMajorTickMark(oNewVal.m_val);
        else{
            val.setMajorTickMark(c_oAscTickMark.TICK_MARK_CROSS);
        }
    }
    else if (c_oserct_cataxMINORTICKMARK === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TickMark(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setMinorTickMark(oNewVal.m_val);
        else{
            val.setMajorTickMark(c_oAscTickMark.TICK_MARK_CROSS);
        }
    }
    else if (c_oserct_cataxTICKLBLPOS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TickLblPos(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setTickLblPos(oNewVal.m_val);
    }
    else if (c_oserct_cataxSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_cataxTXPR === type) {
        val.setTxPr(this.ReadTxPr(length));
        val.txPr.setParent(val);
    }
    else if (c_oserct_cataxCROSSAX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
        {
            val.crossAxId = oNewVal.m_val;
        }
    }
    else if (c_oserct_cataxCROSSES === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Crosses(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setCrosses(oNewVal.m_val);

    }
    else if (c_oserct_cataxCROSSESAT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Double(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setCrossesAt(oNewVal.m_val);
    }
    else if (c_oserct_cataxAUTO === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setAuto(oNewVal.m_val);
    }
    else if (c_oserct_cataxLBLALGN === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_LblAlgn(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setLblAlgn(oNewVal.m_val);
    }
    else if (c_oserct_cataxLBLOFFSET === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_LblOffset(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setLblOffset(oNewVal.m_val);
    }
    else if (c_oserct_cataxTICKLBLSKIP === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Skip(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setTickLblSkip(oNewVal.m_val);
    }
    else if (c_oserct_cataxTICKMARKSKIP === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Skip(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setTickMarkSkip(oNewVal.m_val);
    }
    else if (c_oserct_cataxNOMULTILVLLBL === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setNoMultiLvlLbl(oNewVal.m_val);
    }
    else if (c_oserct_cataxEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_DispUnitsLbl = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_dispunitslblLAYOUT === type) {
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Layout(t, l, val);
        });
    }
    else if (c_oserct_dispunitslblTX === type) {
        var oNewVal = new AscFormat.CChartText();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Tx(t, l, oNewVal);
        });
        val.setTx(oNewVal);
    }
    else if (c_oserct_dispunitslblSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_dispunitslblTXPR === type) {
        val.setTxPr(this.ReadTxPr(length));
        val.txPr.setParent(val);
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_BuiltInUnit = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_builtinunitVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_builtinunitHUNDREDS: val.m_val = c_oAscValAxUnits.HUNDREDS; break;
            case st_builtinunitTHOUSANDS: val.m_val = c_oAscValAxUnits.THOUSANDS; break;
            case st_builtinunitTENTHOUSANDS: val.m_val = c_oAscValAxUnits.TEN_THOUSANDS; break;
            case st_builtinunitHUNDREDTHOUSANDS: val.m_val = c_oAscValAxUnits.HUNDRED_THOUSANDS; break;
            case st_builtinunitMILLIONS: val.m_val = c_oAscValAxUnits.MILLIONS; break;
            case st_builtinunitTENMILLIONS: val.m_val = c_oAscValAxUnits.TEN_MILLIONS; break;
            case st_builtinunitHUNDREDMILLIONS: val.m_val = c_oAscValAxUnits.HUNDRED_MILLIONS; break;
            case st_builtinunitBILLIONS: val.m_val = c_oAscValAxUnits.BILLIONS; break;
            case st_builtinunitTRILLIONS: val.m_val = c_oAscValAxUnits.TRILLIONS; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_DispUnits = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_dispunitsBUILTINUNIT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_BuiltInUnit(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setBuiltInUnit(oNewVal.m_val);
    }
    else if (c_oserct_dispunitsCUSTUNIT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Double(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setCustUnit(oNewVal.m_val);
    }
    else if (c_oserct_dispunitsDISPUNITSLBL === type) {
        var oNewVal = new AscFormat.CDLbl();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DispUnitsLbl(t, l, oNewVal);
        });
        val.setDispUnitsLbl(oNewVal);
    }
    else if (c_oserct_dispunitsEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_CrossBetween = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_crossbetweenVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_crossbetweenBETWEEN: val.m_val = AscFormat.CROSS_BETWEEN_BETWEEN; break;
            case st_crossbetweenMIDCAT: val.m_val = AscFormat.CROSS_BETWEEN_MID_CAT; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_ValAx = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_valaxAXID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setAxId(oNewVal.m_val);
    }
    else if (c_oserct_valaxSCALING === type) {
        var oNewVal = new AscFormat.CScaling();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Scaling(t, l, oNewVal);
        });
        val.setScaling(oNewVal);
    }
    else if (c_oserct_valaxDELETE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setDelete(oNewVal.m_val);
        else
            val.setDelete(true);
    }
    else if (c_oserct_valaxAXPOS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AxPos(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setAxPos(oNewVal.m_val);
    }
    else if (c_oserct_valaxMAJORGRIDLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setMajorGridlines(oNewVal.spPr);
        else
            val.setMajorGridlines(new AscFormat.CSpPr());
    }
    else if (c_oserct_valaxMINORGRIDLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setMinorGridlines(oNewVal.spPr);
        else
            val.setMinorGridlines(new AscFormat.CSpPr());
    }
    else if (c_oserct_valaxTITLE === type) {
        var oNewVal = new AscFormat.CTitle();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Title(t, l, oNewVal);
        });
        if(!AscFormat.isRealBool(oNewVal.overlay))
        {
            oNewVal.setOverlay(true);
        }
        val.setTitle(oNewVal);
    }
    else if (c_oserct_valaxNUMFMT === type) {
        var oNewVal = new AscFormat.CNumFmt();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumFmt(t, l, oNewVal);
        });
        val.setNumFmt(oNewVal);
    }
    else if (c_oserct_valaxMAJORTICKMARK === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TickMark(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setMajorTickMark(oNewVal.m_val);
        else{
            val.setMajorTickMark(c_oAscTickMark.TICK_MARK_CROSS);
        }
    }
    else if (c_oserct_valaxMINORTICKMARK === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TickMark(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setMinorTickMark(oNewVal.m_val);
        else{
            val.setMajorTickMark(c_oAscTickMark.TICK_MARK_CROSS);
        }
    }
    else if (c_oserct_valaxTICKLBLPOS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TickLblPos(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setTickLblPos(oNewVal.m_val);
    }
    else if (c_oserct_valaxSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_valaxTXPR === type) {
        val.setTxPr(this.ReadTxPr(length));
        val.txPr.setParent(val);
    }
    else if (c_oserct_valaxCROSSAX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
        {
            val.crossAxId = oNewVal.m_val;
        }
    }
    else if (c_oserct_valaxCROSSES === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Crosses(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setCrosses(oNewVal.m_val);
        else
            val.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    }
    else if (c_oserct_valaxCROSSESAT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Double(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setCrossesAt(oNewVal.m_val);
    }
    else if (c_oserct_valaxCROSSBETWEEN === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_CrossBetween(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setCrossBetween(oNewVal.m_val);
    }
    else if (c_oserct_valaxMAJORUNIT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AxisUnit(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setMajorUnit(oNewVal.m_val);
    }
    else if (c_oserct_valaxMINORUNIT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AxisUnit(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setMinorUnit(oNewVal.m_val);
    }
    else if (c_oserct_valaxDISPUNITS === type) {
        var oNewVal = new AscFormat.CDispUnits();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DispUnits(t, l, oNewVal);
        });
        val.setDispUnits(oNewVal);
    }
    else if (c_oserct_valaxEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_SizeRepresents = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_sizerepresentsVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_sizerepresentsAREA: val.m_val = SIZE_REPRESENTS_AREA; break;
            case st_sizerepresentsW: val.m_val = SIZE_REPRESENTS_W; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_BubbleScale = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_bubblescaleVAL === type) {
        val.m_val = this.ParsePersent(this.stream.GetString2LE(length));
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_BubbleSer = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_bubbleserIDX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setIdx(oNewVal.m_val);
    }
    else if (c_oserct_bubbleserORDER === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setOrder(oNewVal.m_val);
    }
    else if (c_oserct_bubbleserTX === type) {
        var oNewVal = new AscFormat.CTx();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_SerTx(t, l, oNewVal);
        });
        val.setTx(oNewVal);
    }
    else if (c_oserct_bubbleserSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_bubbleserINVERTIFNEGATIVE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setInvertIfNegative(oNewVal.m_val);
    }
    else if (c_oserct_bubbleserDPT === type) {
        var oNewVal = new AscFormat.CDPt();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DPt(t, l, oNewVal);
        });
        val.addDPt(oNewVal);
    }
    else if (c_oserct_bubbleserDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_bubbleserTRENDLINE === type) {
        //todo array
        var oNewVal = new AscFormat.CTrendLine();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Trendline(t, l, oNewVal);
        });
        val.setTrendline(oNewVal);
    }
    else if (c_oserct_bubbleserERRBARS === type) {
        //todo array
        var oNewVal = new AscFormat.CErrBars();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ErrBars(t, l, oNewVal);
        });
        val.setErrBars(oNewVal);
    }
    else if (c_oserct_bubbleserXVAL === type) {
        var oNewVal = new AscFormat.CCat();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AxDataSource(t, l, oNewVal);
        });
        val.setXVal(oNewVal);
    }
    else if (c_oserct_bubbleserYVAL === type) {
        var oNewVal = new AscFormat.CYVal();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumDataSource(t, l, oNewVal);
        });
        val.setYVal(oNewVal);
    }
    else if (c_oserct_bubbleserBUBBLESIZE === type) {
        var oNewVal = new AscFormat.CYVal();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumDataSource(t, l, oNewVal);
        });
        val.setBubbleSize(oNewVal);
    }
    else if (c_oserct_bubbleserBUBBLE3D === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setBubble3D(oNewVal.m_val);
    }
    else if (c_oserct_bubbleserEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_SerTx = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_sertxSTRREF === type) {
        var oNewVal = new AscFormat.CStrRef();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_StrRef(t, l, oNewVal);
        });
        val.setStrRef(oNewVal);
    }
    else if (c_oserct_sertxV === type) {
        val.setVal(this.stream.GetString2LE(length));
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_DPt = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_dptIDX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setIdx(oNewVal.m_val);
    }
    else if (c_oserct_dptINVERTIFNEGATIVE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setInvertIfNegative(oNewVal.m_val);
    }
    else if (c_oserct_dptMARKER === type) {
        var oNewVal = new AscFormat.CMarker();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Marker(t, l, oNewVal);
        });
        val.setMarker(oNewVal);
    }
    else if (c_oserct_dptBUBBLE3D === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setBubble3D(oNewVal.m_val);
    }
    else if (c_oserct_dptEXPLOSION === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setExplosion(oNewVal.m_val);
    }
    else if (c_oserct_dptSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_dptPICTUREOPTIONS === type) {
        var oNewVal = new AscFormat.CPictureOptions();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PictureOptions(t, l, oNewVal);
        });
        val.setPictureOptions(oNewVal);
    }
    else if (c_oserct_dptEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Marker = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_markerSYMBOL === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_MarkerStyle(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setSymbol(oNewVal.m_val);
    }
    else if (c_oserct_markerSIZE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_MarkerSize(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setSize(oNewVal.m_val);
    }
    else if (c_oserct_markerSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_markerEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_MarkerStyle = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_markerstyleVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_markerstyleCIRCLE: val.m_val = AscFormat.SYMBOL_CIRCLE; break;
            case st_markerstyleDASH: val.m_val = AscFormat.SYMBOL_DASH; break;
            case st_markerstyleDIAMOND: val.m_val = AscFormat.SYMBOL_DIAMOND; break;
            case st_markerstyleDOT: val.m_val = AscFormat.SYMBOL_DOT; break;
            case st_markerstyleNONE: val.m_val = AscFormat.SYMBOL_NONE; break;
            case st_markerstylePICTURE: val.m_val = AscFormat.SYMBOL_PICTURE; break;
            case st_markerstylePLUS: val.m_val = AscFormat.SYMBOL_PLUS; break;
            case st_markerstyleSQUARE: val.m_val = AscFormat.SYMBOL_SQUARE; break;
            case st_markerstyleSTAR: val.m_val = AscFormat.SYMBOL_STAR; break;
            case st_markerstyleTRIANGLE: val.m_val = AscFormat.SYMBOL_TRIANGLE; break;
            case st_markerstyleX: val.m_val = AscFormat.SYMBOL_X; break;
            case st_markerstyleAUTO: break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_MarkerSize = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_markersizeVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetUChar();
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_PictureOptions = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_pictureoptionsAPPLYTOFRONT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setApplyToFront(oNewVal.m_val);
    }
    else if (c_oserct_pictureoptionsAPPLYTOSIDES === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setApplyToSides(oNewVal.m_val);
    }
    else if (c_oserct_pictureoptionsAPPLYTOEND === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setApplyToEnd(oNewVal.m_val);
    }
    else if (c_oserct_pictureoptionsPICTUREFORMAT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PictureFormat(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setPictureFormat(oNewVal.m_val);
    }
    else if (c_oserct_pictureoptionsPICTURESTACKUNIT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PictureStackUnit(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setPictureStackUnit(oNewVal.m_val);
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_PictureFormat = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_pictureformatVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_pictureformatSTRETCH: val.m_val = PICTURE_FORMAT_STACK_STRETCH; break;
            case st_pictureformatSTACK: val.m_val = PICTURE_FORMAT_STACK; break;
            case st_pictureformatSTACKSCALE: val.m_val = PICTURE_FORMAT_STACK_SCALE; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_PictureStackUnit = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_picturestackunitVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetDoubleLE();
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}

    BinaryChartReader.prototype.CorrectDlbls = function(oLbls){
        if(oLbls && oLbls.bDelete !== true){
            if(null === oLbls.showLegendKey){
                oLbls.setShowLegendKey(false);
            }
            if(null === oLbls.showVal){
                oLbls.setShowVal(false);
            }
            if(null === oLbls.showCatName){
                oLbls.setShowCatName(false);
            }
            if(null === oLbls.showSerName){
                oLbls.setShowSerName(false);
            }
            if(null === oLbls.showPercent){
                oLbls.setShowPercent(false);
            }
            if(null === oLbls.showBubbleSize){
                oLbls.setShowBubbleSize(false);
            }
            if(oLbls.setShowLeaderLines && null === oLbls.showLeaderLines){
                oLbls.setShowLeaderLines(false);
            }
        }
    }

BinaryChartReader.prototype.ReadCT_DLbls = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_dlblsDLBL === type) {
        var oNewVal = new AscFormat.CDLbl();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbl(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.addDLbl(oNewVal);
    }
    else if (c_oserct_dlblsDLBLPOS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLblPos(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setDLblPos(oNewVal.m_val);
    }
    else if (c_oserct_dlblsDELETE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setDelete(oNewVal.m_val);
        else
            val.setDelete(true);
    }
    else if (c_oserct_dlblsLEADERLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setLeaderLines(oNewVal.spPr);
        else
            val.setLeaderLines(new AscFormat.CSpPr());
    }
    else if (c_oserct_dlblsNUMFMT === type) {
        var oNewVal = new AscFormat.CNumFmt();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumFmt(t, l, oNewVal);
        });
        val.setNumFmt(oNewVal);
    }
    else if (c_oserct_dlblsSEPARATOR === type) {
        val.setSeparator(this.stream.GetString2LE(length));
    }
    else if (c_oserct_dlblsSHOWBUBBLESIZE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowBubbleSize(oNewVal.m_val);
        else
            val.setShowBubbleSize(true);
    }
    else if (c_oserct_dlblsSHOWCATNAME === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowCatName(oNewVal.m_val);
        else
            val.setShowCatName(true);
    }
    else if (c_oserct_dlblsSHOWLEADERLINES === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowLeaderLines(oNewVal.m_val);
        else
            val.setShowLeaderLines(true);
    }
    else if (c_oserct_dlblsSHOWLEGENDKEY === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowLegendKey(oNewVal.m_val);
        else
            val.setShowLegendKey(true);
    }
    else if (c_oserct_dlblsSHOWPERCENT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowPercent(oNewVal.m_val);
        else
            val.setShowPercent(true);
    }
    else if (c_oserct_dlblsSHOWSERNAME === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowSerName(oNewVal.m_val);
        else
            val.setShowSerName(true);
    }
    else if (c_oserct_dlblsSHOWVAL === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowVal(oNewVal.m_val);
        else
            val.setShowVal(true);
    }
    else if (c_oserct_dlblsSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_dlblsTXPR === type) {
        val.setTxPr(this.ReadTxPr(length));
        val.txPr.setParent(val);
    }
    else if (c_oserct_dlblsEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_DLbl = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_dlblIDX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setIdx(oNewVal.m_val);
    }
    else if (c_oserct_dlblDLBLPOS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLblPos(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setDLblPos(oNewVal.m_val);
    }
    else if (c_oserct_dlblDELETE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setDelete(oNewVal.m_val);
        else
            val.setDelete(true);
    }
    else if (c_oserct_dlblLAYOUT === type) {
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Layout(t, l, val);
        });
    }
    else if (c_oserct_dlblNUMFMT === type) {
        var oNewVal = new AscFormat.CNumFmt();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumFmt(t, l, oNewVal);
        });
        val.setNumFmt(oNewVal);
    }
    else if (c_oserct_dlblSEPARATOR === type) {
        val.setSeparator(this.stream.GetString2LE(length));
    }
    else if (c_oserct_dlblSHOWBUBBLESIZE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowBubbleSize(oNewVal.m_val);
        else
            val.setShowBubbleSize(true);
    }
    else if (c_oserct_dlblSHOWCATNAME === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowCatName(oNewVal.m_val);
        else
            val.setShowCatName(true);
    }
    else if (c_oserct_dlblSHOWLEGENDKEY === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowLegendKey(oNewVal.m_val);
        else
            val.setShowLegendKey(true);
    }
    else if (c_oserct_dlblSHOWPERCENT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowPercent(oNewVal.m_val);
        else
            val.setShowPercent(true);
    }
    else if (c_oserct_dlblSHOWSERNAME === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowSerName(oNewVal.m_val);
        else
            val.setShowSerName(true);
    }
    else if (c_oserct_dlblSHOWVAL === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowVal(oNewVal.m_val);
        else
            val.setShowVal(true);
    }
    else if (c_oserct_dlblSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_dlblTX === type) {
        var oNewVal = new AscFormat.CChartText();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Tx(t, l, oNewVal);
        });
        val.setTx(oNewVal);
    }
    else if (c_oserct_dlblTXPR === type) {
        val.setTxPr(this.ReadTxPr(length));
        val.txPr.setParent(val);
    }
    else if (c_oserct_dlblEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_DLblPos = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_dlblposVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_dlblposBESTFIT: val.m_val = c_oAscChartDataLabelsPos.bestFit; break;
            case st_dlblposB: val.m_val = c_oAscChartDataLabelsPos.b; break;
            case st_dlblposCTR: val.m_val = c_oAscChartDataLabelsPos.ctr; break;
            case st_dlblposINBASE: val.m_val = c_oAscChartDataLabelsPos.inBase; break;
            case st_dlblposINEND: val.m_val = c_oAscChartDataLabelsPos.inEnd; break;
            case st_dlblposL: val.m_val = c_oAscChartDataLabelsPos.l; break;
            case st_dlblposOUTEND: val.m_val = c_oAscChartDataLabelsPos.outEnd; break;
            case st_dlblposR: val.m_val = c_oAscChartDataLabelsPos.r; break;
            case st_dlblposT: val.m_val = c_oAscChartDataLabelsPos.t; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Trendline = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_trendlineNAME === type) {
        val.setName(this.stream.GetString2LE(length));
    }
    else if (c_oserct_trendlineSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_trendlineTRENDLINETYPE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TrendlineType(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setTrendlineType(oNewVal.m_val);
    }
    else if (c_oserct_trendlineORDER === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Order(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setOrder(oNewVal.m_val);
    }
    else if (c_oserct_trendlinePERIOD === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Period(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setPeriod(oNewVal.m_val);
    }
    else if (c_oserct_trendlineFORWARD === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Double(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setForward(oNewVal.m_val);
    }
    else if (c_oserct_trendlineBACKWARD === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Double(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setBackward(oNewVal.m_val);
    }
    else if (c_oserct_trendlineINTERCEPT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Double(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setIntercept(oNewVal.m_val);
    }
    else if (c_oserct_trendlineDISPRSQR === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setDispRSqr(oNewVal.m_val);
    }
    else if (c_oserct_trendlineDISPEQ === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setDispEq(oNewVal.m_val);
    }
    else if (c_oserct_trendlineTRENDLINELBL === type) {
        var oNewVal = new AscFormat.CDLbl();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_TrendlineLbl(t, l, oNewVal);
        });
        val.setTrendlineLbl(oNewVal);
    }
    else if (c_oserct_trendlineEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_TrendlineType = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_trendlinetypeVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_trendlinetypeEXP: val.m_val = TRENDLINE_TYPE_EXP; break;
            case st_trendlinetypeLINEAR: val.m_val = TRENDLINE_TYPE_LINEAR; break;
            case st_trendlinetypeLOG: val.m_val = TRENDLINE_TYPE_LOG; break;
            case st_trendlinetypeMOVINGAVG: val.m_val = TRENDLINE_TYPE_MOVING_AVG; break;
            case st_trendlinetypePOLY: val.m_val = TRENDLINE_TYPE_POLY; break;
            case st_trendlinetypePOWER: val.m_val = TRENDLINE_TYPE_POWER; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Order = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_orderVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetUChar();
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Period = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_periodVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetULongLE();
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_TrendlineLbl = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_trendlinelblLAYOUT === type) {
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Layout(t, l, val);
        });
    }
    else if (c_oserct_trendlinelblTX === type) {
        var oNewVal = new AscFormat.CChartText();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Tx(t, l, oNewVal);
        });
        val.setTx(oNewVal);
    }
    else if (c_oserct_trendlinelblNUMFMT === type) {
        var oNewVal = new AscFormat.CNumFmt();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumFmt(t, l, oNewVal);
        });
        val.setNumFmt(oNewVal);
    }
    else if (c_oserct_trendlinelblSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_trendlinelblTXPR === type) {
        val.setTxPr(this.ReadTxPr(length));
        val.txPr.setParent(val);
    }
    else if (c_oserct_trendlinelblEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_ErrBars = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_errbarsERRDIR === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ErrDir(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setErrDir(oNewVal.m_val);
    }
    else if (c_oserct_errbarsERRBARTYPE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ErrBarType(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setErrBarType(oNewVal.m_val);
    }
    else if (c_oserct_errbarsERRVALTYPE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ErrValType(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setErrValType(oNewVal.m_val);
    }
    else if (c_oserct_errbarsNOENDCAP === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setNoEndCap(oNewVal.m_val);
    }
    else if (c_oserct_errbarsPLUS === type) {
        var oNewVal = new AscFormat.CMinusPlus();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumDataSource(t, l, oNewVal);
        });
        val.setPlus(oNewVal);
    }
    else if (c_oserct_errbarsMINUS === type) {
        var oNewVal = new AscFormat.CMinusPlus();;
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumDataSource(t, l, oNewVal);
        });
        val.setMinus(oNewVal);
    }
    else if (c_oserct_errbarsVAL === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Double(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setVal(oNewVal.m_val);
    }
    else if (c_oserct_errbarsSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_errbarsEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_ErrDir = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_errdirVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_errdirX: val.m_val = ERR_DIR_X; break;
            case st_errdirY: val.m_val = ERR_DIR_Y; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_ErrBarType = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_errbartypeVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_errbartypeBOTH: val.m_val = ERR_BAR_TYPE_BOTH; break;
            case st_errbartypeMINUS: val.m_val = ERR_BAR_TYPE_MINUS; break;
            case st_errbartypePLUS: val.m_val = ERR_BAR_TYPE_PLUS; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_ErrValType = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_errvaltypeVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_errvaltypeCUST: val.m_val = ERR_VAL_TYPE_CUST; break;
            case st_errvaltypeFIXEDVAL: val.m_val = ERR_VAL_TYPE_FIXED_VAL; break;
            case st_errvaltypePERCENTAGE: val.m_val = ERR_VAL_TYPE_PERCENTAGE; break;
            case st_errvaltypeSTDDEV: val.m_val = ERR_VAL_TYPE_STD_DEV; break;
            case st_errvaltypeSTDERR: val.m_val = ERR_VAL_TYPE_STD_ERR; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_NumDataSource = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_numdatasourceNUMLIT === type) {
        var oNewVal = new AscFormat.CNumLit();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumData(t, l, oNewVal);
        });
        val.setNumLit(oNewVal);
    }
    else if (c_oserct_numdatasourceNUMREF === type) {
        var oNewVal = new AscFormat.CNumRef();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumRef(t, l, oNewVal);
        });
        val.setNumRef(oNewVal);
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_NumData = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_numdataFORMATCODE === type) {
        val.setFormatCode(this.stream.GetString2LE(length));
    }
    else if (c_oserct_numdataPTCOUNT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setPtCount(oNewVal.m_val);
    }
    else if (c_oserct_numdataPT === type) {
        var oNewVal = new AscFormat.CNumericPoint();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumVal(t, l, oNewVal);
        });
        val.addPt(oNewVal);
    }
    else if (c_oserct_numdataEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_NumVal = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_numvalV === type) {
        var nVal = parseFloat(this.stream.GetString2LE(length));
        if(isNaN(nVal))
            nVal = 0;
        val.setVal(nVal);
    }
    else if (c_oserct_numvalIDX === type) {
        val.setIdx(this.stream.GetULongLE());
    }
    else if (c_oserct_numvalFORMATCODE === type) {
        val.setFormatCode(this.stream.GetString2LE(length));
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_NumRef = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_numrefF === type) {
        val.setF(this.stream.GetString2LE(length));
    }
    else if (c_oserct_numrefNUMCACHE === type) {
        var oNewVal = new AscFormat.CNumLit();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumData(t, l, oNewVal);
        });
        val.setNumCache(oNewVal);
    }
    else if (c_oserct_numrefEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_AxDataSource = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_axdatasourceMULTILVLSTRREF === type) {
        var oNewVal = new AscFormat.CMultiLvlStrRef();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_MultiLvlStrRef(t, l, oNewVal);
        });
        val.setMultiLvlStrRef(oNewVal);
    }
    else if (c_oserct_axdatasourceNUMLIT === type) {
        var oNewVal = new AscFormat.CNumLit();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumData(t, l, oNewVal);
        });
        val.setNumLit(oNewVal);
    }
    else if (c_oserct_axdatasourceNUMREF === type) {
        var oNewVal = new AscFormat.CNumRef();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumRef(t, l, oNewVal);
        });
        val.setNumRef(oNewVal);
    }
    else if (c_oserct_axdatasourceSTRLIT === type) {
        var oNewVal = new AscFormat.CStrCache();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_StrData(t, l, oNewVal);
        });
        val.setStrLit(oNewVal);
    }
    else if (c_oserct_axdatasourceSTRREF === type) {
        var oNewVal = new AscFormat.CStrRef();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_StrRef(t, l, oNewVal);
        });
        val.setStrRef(oNewVal);
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_MultiLvlStrRef = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_multilvlstrrefF === type) {
        val.setF(this.stream.GetString2LE(length));
    }
    else if (c_oserct_multilvlstrrefMULTILVLSTRCACHE === type) {
        var oNewVal = new AscFormat.CMultiLvlStrCache();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_MultiLvlStrData(t, l, oNewVal);
        });
        val.setMultiLvlStrCache(oNewVal);
    }
    else if (c_oserct_multilvlstrrefEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_lvl = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_lvlPT === type) {
        var oNewVal = new AscFormat.CStringPoint();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_StrVal(t, l, oNewVal);
        });
        val.push(oNewVal);
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_MultiLvlStrData = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_multilvlstrdataPTCOUNT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setPtCount(oNewVal.m_val);
    }
    else if (c_oserct_multilvlstrdataLVL === type) {
        //todo array
        var oNewVal = [];
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_lvl(t, l, oNewVal);
        });
        for(var i = 0; i < oNewVal.length; ++i)
        {
            val.setLvl(oNewVal[i]);
        }
    }
    else if (c_oserct_multilvlstrdataEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_BubbleChart = function (type, length, val, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_bubblechartVARYCOLORS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setVaryColors(oNewVal.m_val);
    }
    else if (c_oserct_bubblechartSER === type) {
        var oNewVal = new AscFormat.CBubbleSeries();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_BubbleSer(t, l, oNewVal);
        });
        val.addSer(oNewVal);
    }
    else if (c_oserct_bubblechartDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_bubblechartBUBBLE3D === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setBubble3D(oNewVal.m_val);
    }
    else if (c_oserct_bubblechartBUBBLESCALE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_BubbleScale(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setBubbleScale(oNewVal.m_val);
    }
    else if (c_oserct_bubblechartSHOWNEGBUBBLES === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowNegBubbles(oNewVal.m_val);
    }
    else if (c_oserct_bubblechartSIZEREPRESENTS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_SizeRepresents(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setSizeRepresents(oNewVal.m_val);
    }
    else if (c_oserct_bubblechartAXID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            aChartWithAxis.push({ axisId: oNewVal.m_val, chart: val });
    }
    else if (c_oserct_bubblechartEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_bandFmts = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_bandfmtsBANDFMT === type) {
        var oNewVal = new AscFormat.CBandFmt();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_BandFmt(t, l, oNewVal);
        });
        val.addBandFmt(oNewVal);
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Surface3DChart = function (type, length, val, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_surface3dchartWIREFRAME === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setWireframe(oNewVal.m_val);
    }
    else if (c_oserct_surface3dchartSER === type) {
        var oNewVal = new AscFormat.CSurfaceSeries();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_SurfaceSer(t, l, oNewVal);
        });
        val.addSer(oNewVal);
    }
    else if (c_oserct_surface3dchartBANDFMTS === type) {
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_bandFmts(t, l, val);
        });
    }
    else if (c_oserct_surface3dchartAXID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            aChartWithAxis.push({ axisId: oNewVal.m_val, chart: val, surface: true });
    }
    else if (c_oserct_surface3dchartEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_SurfaceSer = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_surfaceserIDX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setIdx(oNewVal.m_val);
    }
    else if (c_oserct_surfaceserORDER === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setOrder(oNewVal.m_val);
    }
    else if (c_oserct_surfaceserTX === type) {
        var oNewVal = new AscFormat.CTx();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_SerTx(t, l, oNewVal);
        });
        val.setTx(oNewVal);
    }
    else if (c_oserct_surfaceserSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_surfaceserCAT === type) {
        var oNewVal = new AscFormat.CCat();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AxDataSource(t, l, oNewVal);
        });
        val.setCat(oNewVal);
    }
    else if (c_oserct_surfaceserVAL === type) {
        var oNewVal = new AscFormat.CYVal();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumDataSource(t, l, oNewVal);
        });
        val.setVal(oNewVal);
    }
    else if (c_oserct_surfaceserEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_BandFmt = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_bandfmtIDX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setIdx(oNewVal.m_val);
    }
    else if (c_oserct_bandfmtSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_SurfaceChart = function (type, length, val, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_surfacechartWIREFRAME === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setWireframe(oNewVal.m_val);
    }
    else if (c_oserct_surfacechartSER === type) {
        var oNewVal = new AscFormat.CSurfaceSeries();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_SurfaceSer(t, l, oNewVal);
        });
        val.addSer(oNewVal);
    }
    else if (c_oserct_surfacechartBANDFMTS === type) {
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_bandFmts(t, l, val);
        });
    }
    else if (c_oserct_surfacechartAXID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            aChartWithAxis.push({ axisId: oNewVal.m_val, chart: val, surface: true });
    }
    else if (c_oserct_surfacechartEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_SecondPieSize = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_secondpiesizeVAL === type) {
        val.m_val = this.ParsePersent(this.stream.GetString2LE(length));
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_SplitType = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_splittypeVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_splittypeAUTO: val.m_val = SPLIT_TYPE_AUTO; break;
            case st_splittypeCUST: val.m_val = SPLIT_TYPE_CUST; break;
            case st_splittypePERCENT: val.m_val = SPLIT_TYPE_PERCENT; break;
            case st_splittypePOS: val.m_val = SPLIT_TYPE_POS; break;
            case st_splittypeVAL: val.m_val = SPLIT_TYPE_VAL; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_OfPieType = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_ofpietypeVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_ofpietypePIE: val.m_val = OF_PIE_TYPE_PIE; break;
            case st_ofpietypeBAR: val.m_val = OF_PIE_TYPE_BAR; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_custSplit = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_custsplitSECONDPIEPT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.addCustSplit(oNewVal.m_val);
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_OfPieChart = function (type, length, val, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_ofpiechartOFPIETYPE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_OfPieType(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setOfPieType(oNewVal.m_val);
    }
    else if (c_oserct_ofpiechartVARYCOLORS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setVaryColors(oNewVal.m_val);
    }
    else if (c_oserct_ofpiechartSER === type) {
        var oNewVal = new AscFormat.CPieSeries();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PieSer(t, l, oNewVal);
        });
        val.addSer(oNewVal);
    }
    else if (c_oserct_ofpiechartDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_ofpiechartGAPWIDTH === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_GapAmount(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setGapWidth(oNewVal.m_val);
    }
    else if (c_oserct_ofpiechartSPLITTYPE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_SplitType(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setSplitType(oNewVal.m_val)
    }
    else if (c_oserct_ofpiechartSPLITPOS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Double(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setSplitPos(oNewVal.m_val);
    }
    else if (c_oserct_ofpiechartCUSTSPLIT === type) {
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_custSplit(t, l, val);
        });
    }
    else if (c_oserct_ofpiechartSECONDPIESIZE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_SecondPieSize(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setSecondPieSize(oNewVal.m_val);
    }
    else if (c_oserct_ofpiechartSERLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setSerLines(oNewVal.spPr);
        else
            val.setSerLines(new AscFormat.CSpPr());
    }
    else if (c_oserct_ofpiechartEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_PieSer = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_pieserIDX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setIdx(oNewVal.m_val);
    }
    else if (c_oserct_pieserORDER === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setOrder(oNewVal.m_val);
    }
    else if (c_oserct_pieserTX === type) {
        var oNewVal = new AscFormat.CTx();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_SerTx(t, l, oNewVal);
        });
        val.setTx(oNewVal);
    }
    else if (c_oserct_pieserSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_pieserEXPLOSION === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setExplosion(oNewVal.m_val);
    }
    else if (c_oserct_pieserDPT === type) {
        var oNewVal = new AscFormat.CDPt();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DPt(t, l, oNewVal);
        });
        val.addDPt(oNewVal);
    }
    else if (c_oserct_pieserDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_pieserCAT === type) {
        var oNewVal = new AscFormat.CCat();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AxDataSource(t, l, oNewVal);
        });
        val.setCat(oNewVal);
    }
    else if (c_oserct_pieserVAL === type) {
        var oNewVal = new AscFormat.CYVal();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumDataSource(t, l, oNewVal);
        });
        val.setVal(oNewVal);
    }
    else if (c_oserct_pieserEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_GapAmount = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_gapamountVAL === type) {
        val.m_val = this.ParsePersent(this.stream.GetString2LE(length));
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Bar3DChart = function (type, length, val, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_bar3dchartBARDIR === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_BarDir(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setBarDir(oNewVal.m_val);
    }
    else if (c_oserct_bar3dchartGROUPING === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_BarGrouping(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setGrouping(oNewVal.m_val);
    }
    else if (c_oserct_bar3dchartVARYCOLORS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setVaryColors(oNewVal.m_val);
    }
    else if (c_oserct_bar3dchartSER === type) {
        var oNewVal = new AscFormat.CBarSeries();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_BarSer(t, l, oNewVal);
        });
        val.addSer(oNewVal);
    }
    else if (c_oserct_bar3dchartDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_bar3dchartGAPWIDTH === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_GapAmount(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setGapWidth(oNewVal.m_val);
    }
    else if (c_oserct_bar3dchartGAPDEPTH === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_GapAmount(t, l, oNewVal);
        });
        if(null != oNewVal.m_val)
            val.setGapDepth(oNewVal.m_val);
    }
    else if (c_oserct_bar3dchartSHAPE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Shape(t, l, oNewVal);
        });
        if(null != oNewVal.m_val)
            val.setShape(oNewVal.m_val);
    }
    else if (c_oserct_bar3dchartAXID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            aChartWithAxis.push({ axisId: oNewVal.m_val, chart: val });
    }
    else if (c_oserct_bar3dchartEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_BarDir = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_bardirVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_bardirBAR: val.m_val = AscFormat.BAR_DIR_BAR; break;
            case st_bardirCOL: val.m_val = AscFormat.BAR_DIR_COL; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_BarGrouping = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_bargroupingVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_bargroupingPERCENTSTACKED: val.m_val = AscFormat.BAR_GROUPING_PERCENT_STACKED; break;
            case st_bargroupingCLUSTERED: val.m_val = AscFormat.BAR_GROUPING_CLUSTERED; break;
            case st_bargroupingSTANDARD: val.m_val = AscFormat.BAR_GROUPING_STANDARD; break;
            case st_bargroupingSTACKED: val.m_val = AscFormat.BAR_GROUPING_STACKED; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_BarSer = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_barserIDX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setIdx(oNewVal.m_val);
    }
    else if (c_oserct_barserORDER === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setOrder(oNewVal.m_val);
    }
    else if (c_oserct_barserTX === type) {
        var oNewVal = new AscFormat.CTx();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_SerTx(t, l, oNewVal);
        });
        val.setTx(oNewVal);
    }
    else if (c_oserct_barserSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_barserINVERTIFNEGATIVE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setInvertIfNegative(oNewVal.m_val);
    }
    else if (c_oserct_barserPICTUREOPTIONS === type) {
        var oNewVal = new AscFormat.CPictureOptions();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PictureOptions(t, l, oNewVal);
        });
        val.setPictureOptions(oNewVal);
    }
    else if (c_oserct_barserDPT === type) {
        var oNewVal = new AscFormat.CDPt();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DPt(t, l, oNewVal);
        });
        val.addDPt(oNewVal);
    }
    else if (c_oserct_barserDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_barserTRENDLINE === type) {
        //todo array
        var oNewVal = new AscFormat.CTrendLine();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Trendline(t, l, oNewVal);
        });
        val.setTrendline(oNewVal);
    }
    else if (c_oserct_barserERRBARS === type) {
        var oNewVal = new AscFormat.CErrBars();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ErrBars(t, l, oNewVal);
        });
        val.setErrBars(oNewVal);
    }
    else if (c_oserct_barserCAT === type) {
        var oNewVal = new AscFormat.CCat();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AxDataSource(t, l, oNewVal);
        });
        val.setCat(oNewVal);
    }
    else if (c_oserct_barserVAL === type) {
        var oNewVal = new AscFormat.CYVal();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumDataSource(t, l, oNewVal);
        });
        val.setVal(oNewVal);
    }
    else if (c_oserct_barserSHAPE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Shape(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShape(oNewVal.m_val);
    }
    else if (c_oserct_barserEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Shape = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_shapeVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_shapeCONE: val.m_val = AscFormat.BAR_SHAPE_CONE; break;
            case st_shapeCONETOMAX: val.m_val = AscFormat.BAR_SHAPE_CONETOMAX; break;
            case st_shapeBOX: val.m_val = AscFormat.BAR_SHAPE_BOX; break;
            case st_shapeCYLINDER: val.m_val = AscFormat.BAR_SHAPE_CYLINDER; break;
            case st_shapePYRAMID: val.m_val = AscFormat.BAR_SHAPE_PYRAMID; break;
            case st_shapePYRAMIDTOMAX: val.m_val = AscFormat.BAR_SHAPE_PYRAMIDTOMAX; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Overlap = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_overlapVAL === type) {
        val.m_val = this.ParsePersent(this.stream.GetString2LE(length));
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_BarChart = function (type, length, val, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_barchartBARDIR === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_BarDir(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setBarDir(oNewVal.m_val);
    }
    else if (c_oserct_barchartGROUPING === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_BarGrouping(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setGrouping(oNewVal.m_val);
    }
    else if (c_oserct_barchartVARYCOLORS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setVaryColors(oNewVal.m_val);
    }
    else if (c_oserct_barchartSER === type) {
        var oNewVal = new AscFormat.CBarSeries();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_BarSer(t, l, oNewVal);
        });
        val.addSer(oNewVal);
    }
    else if (c_oserct_barchartDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_barchartGAPWIDTH === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_GapAmount(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setGapWidth(oNewVal.m_val);
    }
    else if (c_oserct_barchartOVERLAP === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Overlap(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setOverlap(oNewVal.m_val);
    }
    else if (c_oserct_barchartSERLINES === type) {
        //todo array
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setSerLines(oNewVal.spPr);
        else
            val.setSerLines(new AscFormat.CSpPr());
    }
    else if (c_oserct_barchartAXID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            aChartWithAxis.push({ axisId: oNewVal.m_val, chart: val });
    }
    else if (c_oserct_barchartEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_HoleSize = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_holesizeVAL === type) {
        val.m_val = this.ParsePersent(this.stream.GetString2LE(length));
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_DoughnutChart = function (type, length, val, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_doughnutchartVARYCOLORS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setVaryColors(oNewVal.m_val);
    }
    else if (c_oserct_doughnutchartSER === type) {
        var oNewVal = new AscFormat.CPieSeries();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PieSer(t, l, oNewVal);
        });
        val.addSer(oNewVal);
    }
    else if (c_oserct_doughnutchartDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_doughnutchartFIRSTSLICEANG === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_FirstSliceAng(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setFirstSliceAng(oNewVal.m_val);
    }
    else if (c_oserct_doughnutchartHOLESIZE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_HoleSize(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setHoleSize(oNewVal.m_val);
    }
    else if (c_oserct_doughnutchartEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_FirstSliceAng = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_firstsliceangVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetULongLE();
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Pie3DChart = function (type, length, val, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_pie3dchartVARYCOLORS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setVaryColors(oNewVal.m_val);
    }
    else if (c_oserct_pie3dchartSER === type) {
        var oNewVal = new AscFormat.CPieSeries();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PieSer(t, l, oNewVal);
        });
        val.addSer(oNewVal);
    }
    else if (c_oserct_pie3dchartDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_pie3dchartEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_PieChart = function (type, length, val, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_piechartVARYCOLORS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setVaryColors(oNewVal.m_val);
    }
    else if (c_oserct_piechartSER === type) {
        var oNewVal = new AscFormat.CPieSeries();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PieSer(t, l, oNewVal);
        });
        val.addSer(oNewVal);
    }
    else if (c_oserct_piechartDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_piechartFIRSTSLICEANG === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_FirstSliceAng(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setFirstSliceAng(oNewVal.m_val);
    }
    else if (c_oserct_piechartEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_ScatterSer = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_scatterserIDX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setIdx(oNewVal.m_val);
    }
    else if (c_oserct_scatterserORDER === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setOrder(oNewVal.m_val);
    }
    else if (c_oserct_scatterserTX === type) {
        var oNewVal = new AscFormat.CTx();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_SerTx(t, l, oNewVal);
        });
        val.setTx(oNewVal);
    }
    else if (c_oserct_scatterserSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_scatterserMARKER === type) {
        var oNewVal = new AscFormat.CMarker();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Marker(t, l, oNewVal);
        });
        val.setMarker(oNewVal);
    }
    else if (c_oserct_scatterserDPT === type) {
        var oNewVal = new AscFormat.CDPt();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DPt(t, l, oNewVal);
        });
        val.addDPt(oNewVal);
    }
    else if (c_oserct_scatterserDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_scatterserTRENDLINE === type) {
        //todo array
        var oNewVal = new AscFormat.CTrendLine();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Trendline(t, l, oNewVal);
        });
        val.setTrendline(oNewVal);
    }
    else if (c_oserct_scatterserERRBARS === type) {
        //todo array
        var oNewVal = new AscFormat.CErrBars();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ErrBars(t, l, oNewVal);
        });
        val.setErrBars(oNewVal);
    }
    else if (c_oserct_scatterserXVAL === type) {
        var oNewVal = new AscFormat.CCat();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AxDataSource(t, l, oNewVal);
        });
        val.setXVal(oNewVal);
    }
    else if (c_oserct_scatterserYVAL === type) {
        var oNewVal = new AscFormat.CYVal();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumDataSource(t, l, oNewVal);
        });
        val.setYVal(oNewVal);
    }
    else if (c_oserct_scatterserSMOOTH === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val){
            val.setSmooth(oNewVal.m_val);
        }
        else{
            val.setSmooth(true);
        }
    }
    else if (c_oserct_scatterserEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_ScatterStyle = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_scatterstyleVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_scatterstyleNONE: val.m_val = AscFormat.SCATTER_STYLE_NONE; break;
            case st_scatterstyleLINE: val.m_val = AscFormat.SCATTER_STYLE_LINE; break;
            case st_scatterstyleLINEMARKER: val.m_val = AscFormat.SCATTER_STYLE_LINE_MARKER; break;
            case st_scatterstyleMARKER: val.m_val = AscFormat.SCATTER_STYLE_MARKER; break;
            case st_scatterstyleSMOOTH: val.m_val = AscFormat.SCATTER_STYLE_SMOOTH; break;
            case st_scatterstyleSMOOTHMARKER: val.m_val = AscFormat.SCATTER_STYLE_SMOOTH_MARKER; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_ScatterChart = function (type, length, val, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_scatterchartSCATTERSTYLE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ScatterStyle(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setScatterStyle(oNewVal.m_val);
    }
    else if (c_oserct_scatterchartVARYCOLORS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setVaryColors(oNewVal.m_val);
    }
    else if (c_oserct_scatterchartSER === type) {
        var oNewVal = new AscFormat.CScatterSeries();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ScatterSer(t, l, oNewVal);
        });
        val.addSer(oNewVal);
        if(oNewVal.smooth === null){
            oNewVal.setSmooth(false);
        }
    }
    else if (c_oserct_scatterchartDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_scatterchartAXID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            aChartWithAxis.push({ axisId: oNewVal.m_val, chart: val });
    }
    else if (c_oserct_scatterchartEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_RadarSer = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_radarserIDX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setIdx(oNewVal.m_val);
    }
    else if (c_oserct_radarserORDER === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setOrder(oNewVal.m_val);
    }
    else if (c_oserct_radarserTX === type) {
        var oNewVal = new AscFormat.CTx();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_SerTx(t, l, oNewVal);
        });
        val.setTx(oNewVal);
    }
    else if (c_oserct_radarserSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_radarserMARKER === type) {
        var oNewVal = new AscFormat.CMarker();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Marker(t, l, oNewVal);
        });
        val.setMarker(oNewVal);
    }
    else if (c_oserct_radarserDPT === type) {
        var oNewVal = new AscFormat.CDPt();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DPt(t, l, oNewVal);
        });
        val.addDPt(oNewVal);
    }
    else if (c_oserct_radarserDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_radarserCAT === type) {
        var oNewVal = new AscFormat.CCat();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AxDataSource(t, l, oNewVal);
        });
        val.setCat(oNewVal);
    }
    else if (c_oserct_radarserVAL === type) {
        var oNewVal = new AscFormat.CYVal();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumDataSource(t, l, oNewVal);
        });
        val.setVal(oNewVal);
    }
    else if (c_oserct_radarserEXTLST === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_RadarStyle = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_radarstyleVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_radarstyleSTANDARD: val.m_val = RADAR_STYLE_STANDARD; break;
            case st_radarstyleMARKER: val.m_val = RADAR_STYLE_MARKER; break;
            case st_radarstyleFILLED: val.m_val = RADAR_STYLE_FILLED; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_RadarChart = function (type, length, val, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_radarchartRADARSTYLE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_RadarStyle(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setRadarStyle(oNewVal.m_val);
    }
    else if (c_oserct_radarchartVARYCOLORS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setVaryColors(oNewVal.m_val);
    }
    else if (c_oserct_radarchartSER === type) {
        var oNewVal = new AscFormat.CRadarSeries();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_RadarSer(t, l, oNewVal);
        });
        val.addSer(oNewVal);
    }
    else if (c_oserct_radarchartDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_radarchartAXID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            aChartWithAxis.push({ axisId: oNewVal.m_val, chart: val });
    }
    else if (c_oserct_radarchartEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_StockChart = function (type, length, val, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_stockchartSER === type) {
        var oNewVal = new AscFormat.CLineSeries();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_LineSer(t, l, oNewVal);
        });
        val.addSer(oNewVal);
    }
    else if (c_oserct_stockchartDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_stockchartDROPLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setDropLines(oNewVal.spPr);
        else
            val.setDropLines(new AscFormat.CSpPr());
    }
    else if (c_oserct_stockchartHILOWLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setHiLowLines(oNewVal.spPr);
        else
            val.setHiLowLines(new AscFormat.CSpPr());
    }
    else if (c_oserct_stockchartUPDOWNBARS === type) {
        var oNewVal = new AscFormat.CUpDownBars();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UpDownBars(t, l, oNewVal);
        });
        val.setUpDownBars(oNewVal);
    }
    else if (c_oserct_stockchartAXID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            aChartWithAxis.push({ axisId: oNewVal.m_val, chart: val });
    }
    else if (c_oserct_stockchartEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_LineSer = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_lineserIDX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setIdx(oNewVal.m_val);
    }
    else if (c_oserct_lineserORDER === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setOrder(oNewVal.m_val);
    }
    else if (c_oserct_lineserTX === type) {
        var oNewVal = new AscFormat.CTx();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_SerTx(t, l, oNewVal);
        });
        val.setTx(oNewVal);
    }
    else if (c_oserct_lineserSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_lineserMARKER === type) {
        var oNewVal = new AscFormat.CMarker();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Marker(t, l, oNewVal);
        });
        val.setMarker(oNewVal);
    }
    else if (c_oserct_lineserDPT === type) {
        var oNewVal = new AscFormat.CDPt();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DPt(t, l, oNewVal);
        });
        val.addDPt(oNewVal);
    }
    else if (c_oserct_lineserDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_lineserTRENDLINE === type) {
        //todo array
        var oNewVal = new AscFormat.CTrendLine();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Trendline(t, l, oNewVal);
        });
        val.setTrendline(oNewVal);
    }
    else if (c_oserct_lineserERRBARS === type) {
        var oNewVal = new AscFormat.CErrBars();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ErrBars(t, l, oNewVal);
        });
        val.setErrBars(oNewVal);
    }
    else if (c_oserct_lineserCAT === type) {
        var oNewVal = new AscFormat.CCat();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AxDataSource(t, l, oNewVal);
        });
        val.setCat(oNewVal);
    }
    else if (c_oserct_lineserVAL === type) {
        var oNewVal = new AscFormat.CYVal();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumDataSource(t, l, oNewVal);
        });
        val.setVal(oNewVal);
    }
    else if (c_oserct_lineserSMOOTH === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val) {
            val.setSmooth(oNewVal.m_val);
        }
        else {
            val.setSmooth(true);
        }
    }
    else if (c_oserct_lineserEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_UpDownBars = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_updownbarsGAPWIDTH === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_GapAmount(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setGapWidth(oNewVal.m_val);
    }
    else if (c_oserct_updownbarsUPBARS === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UpDownBar(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setUpBars(oNewVal.spPr);
        else
            val.setUpBars(new AscFormat.CSpPr());
    }
    else if (c_oserct_updownbarsDOWNBARS === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UpDownBar(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setDownBars(oNewVal.spPr);
        else
            val.setDownBars(new AscFormat.CSpPr());
    }
    else if (c_oserct_updownbarsEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_UpDownBar = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_updownbarSPPR === type) {
        val.spPr = this.ReadSpPr(length);
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Line3DChart = function (type, length, val, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_line3dchartGROUPING === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Grouping(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setGrouping(oNewVal.m_val);
    }
    else if (c_oserct_line3dchartVARYCOLORS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setVaryColors(oNewVal.m_val);
    }
    else if (c_oserct_line3dchartSER === type) {
        var oNewVal = new AscFormat.CLineSeries();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_LineSer(t, l, oNewVal);
        });
        if(oNewVal.smooth === null){
            oNewVal.setSmooth(false);
        }
        val.addSer(oNewVal);
    }
    else if (c_oserct_line3dchartDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_line3dchartDROPLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setDropLines(oNewVal.spPr);
        else
            val.setDropLines(new AscFormat.CSpPr());
    }
    else if (c_oserct_line3dchartGAPDEPTH === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_GapAmount(t, l, oNewVal);
        });
        //val.m_gapDepth = oNewVal;
    }
    else if (c_oserct_line3dchartAXID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            aChartWithAxis.push({ axisId: oNewVal.m_val, chart: val });
    }
    else if (c_oserct_line3dchartEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Grouping = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_groupingVAL === type) {
        switch (this.stream.GetUChar()) {
            case st_groupingPERCENTSTACKED: val.m_val = AscFormat.GROUPING_PERCENT_STACKED; break;
            case st_groupingSTANDARD: val.m_val = AscFormat.GROUPING_STANDARD; break;
            case st_groupingSTACKED: val.m_val = AscFormat.GROUPING_STACKED; break;
        }
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_LineChart = function (type, length, val, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_linechartGROUPING === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Grouping(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setGrouping(oNewVal.m_val);
    }
    else if (c_oserct_linechartVARYCOLORS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setVaryColors(oNewVal.m_val);
    }
    else if (c_oserct_linechartSER === type) {
        var oNewVal = new AscFormat.CLineSeries();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_LineSer(t, l, oNewVal);
        });
        val.addSer(oNewVal);
        if(oNewVal.smooth === null){
            oNewVal.setSmooth(false);
        }
    }
    else if (c_oserct_linechartDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_linechartDROPLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setDropLines(oNewVal.spPr);
        else
            val.setDropLines(new AscFormat.CSpPr());
    }
    else if (c_oserct_linechartHILOWLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setHiLowLines(oNewVal.spPr);
        else
            val.setHiLowLines(new AscFormat.CSpPr());
    }
    else if (c_oserct_linechartUPDOWNBARS === type) {
        var oNewVal = new AscFormat.CUpDownBars();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UpDownBars(t, l, oNewVal);
        });
        val.setUpDownBars(oNewVal);
    }
    else if (c_oserct_linechartMARKER === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setMarker(oNewVal.m_val);
    }
    else if (c_oserct_linechartSMOOTH === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val){
            val.setSmooth(oNewVal.m_val);
        }
        else{
            val.setSmooth(true);
        }
    }
    else if (c_oserct_linechartAXID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            aChartWithAxis.push({ axisId: oNewVal.m_val, chart: val });
    }
    else if (c_oserct_linechartEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Area3DChart = function (type, length, val, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_area3dchartGROUPING === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Grouping(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setGrouping(oNewVal.m_val);
    }
    else if (c_oserct_area3dchartVARYCOLORS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setVaryColors(oNewVal.m_val);
    }
    else if (c_oserct_area3dchartSER === type) {
        var oNewVal = new AscFormat.CAreaSeries();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AreaSer(t, l, oNewVal);
        });
        val.addSer(oNewVal);
    }
    else if (c_oserct_area3dchartDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_area3dchartDROPLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setDropLines(oNewVal.spPr);
        else
            val.setDropLines(new AscFormat.CSpPr());
    }
    else if (c_oserct_area3dchartGAPDEPTH === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_GapAmount(t, l, oNewVal);
        });
        //val.m_gapDepth = oNewVal;
    }
    else if (c_oserct_area3dchartAXID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            aChartWithAxis.push({ axisId: oNewVal.m_val, chart: val });
    }
    else if (c_oserct_area3dchartEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_AreaSer = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_areaserIDX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setIdx(oNewVal.m_val);
    }
    else if (c_oserct_areaserORDER === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setOrder(oNewVal.m_val);
    }
    else if (c_oserct_areaserTX === type) {
        var oNewVal = new AscFormat.CTx();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_SerTx(t, l, oNewVal);
        });
        val.setTx(oNewVal);
    }
    else if (c_oserct_areaserSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_areaserPICTUREOPTIONS === type) {
        var oNewVal = new AscFormat.CPictureOptions();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PictureOptions(t, l, oNewVal);
        });
        val.setPictureOptions(oNewVal);
    }
    else if (c_oserct_areaserDPT === type) {
        var oNewVal = new AscFormat.CDPt();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DPt(t, l, oNewVal);
        });
        val.addDPt(oNewVal);
    }
    else if (c_oserct_areaserDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_areaserTRENDLINE === type) {
        //todo array
        var oNewVal = new AscFormat.CTrendLine();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Trendline(t, l, oNewVal);
        });
        val.setTrendline(oNewVal);
    }
    else if (c_oserct_areaserERRBARS === type) {
        //todo array
        var oNewVal = new AscFormat.CErrBars();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ErrBars(t, l, oNewVal);
        });
        val.setErrBars(oNewVal);
    }
    else if (c_oserct_areaserCAT === type) {
        var oNewVal = new AscFormat.CCat();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AxDataSource(t, l, oNewVal);
        });
        val.setCat(oNewVal);
    }
    else if (c_oserct_areaserVAL === type) {
        var oNewVal = new AscFormat.CYVal();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_NumDataSource(t, l, oNewVal);
        });
        val.setVal(oNewVal);
    }
    else if (c_oserct_areaserEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_AreaChart = function (type, length, val, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_areachartGROUPING === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Grouping(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setGrouping(oNewVal.m_val);
    }
    else if (c_oserct_areachartVARYCOLORS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setVaryColors(oNewVal.m_val);
    }
    else if (c_oserct_areachartSER === type) {
        var oNewVal = new AscFormat.CAreaSeries();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AreaSer(t, l, oNewVal);
        });
        val.addSer(oNewVal);
    }
    else if (c_oserct_areachartDLBLS === type) {
        var oNewVal = new AscFormat.CDLbls();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbls(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setDLbls(oNewVal);
    }
    else if (c_oserct_areachartDROPLINES === type) {
        var oNewVal = { spPr: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ChartLines(t, l, oNewVal);
        });
        if (null != oNewVal.spPr)
            val.setDropLines(oNewVal.spPr);
        else
            val.setDropLines(new AscFormat.CSpPr());
    }
    else if (c_oserct_areachartAXID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            aChartWithAxis.push({ axisId: oNewVal.m_val, chart: val });
    }
    else if (c_oserct_areachartEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_PlotArea = function (type, length, val, oIdToAxisMap, aChartWithAxis) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_plotareaLAYOUT === type) {
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Layout(t, l, val);
        });
    }
    else if (c_oserct_plotareaAREA3DCHART === type) {
        var oNewVal = new AscFormat.CAreaChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Area3DChart(t, l, oNewVal, aChartWithAxis);
        });
        val.addChart(oNewVal);
    }
    else if (c_oserct_plotareaAREACHART === type) {
        var oNewVal = new AscFormat.CAreaChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_AreaChart(t, l, oNewVal, aChartWithAxis);
        });
        val.addChart(oNewVal);
    }
    else if (c_oserct_plotareaBAR3DCHART === type) {
        var oNewVal = new AscFormat.CBarChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Bar3DChart(t, l, oNewVal, aChartWithAxis);
        });
        oNewVal.set3D(true);
        //3d->2d
        /*if (AscFormat.BAR_GROUPING_STANDARD == oNewVal.grouping)
            oNewVal.setGrouping(AscFormat.BAR_GROUPING_CLUSTERED);
        else if(AscFormat.BAR_GROUPING_CLUSTERED != oNewVal.grouping){
            oNewVal.setOverlap(100);
        }*/
        val.addChart(oNewVal);
    }
    else if (c_oserct_plotareaBARCHART === type) {
        var oNewVal = new AscFormat.CBarChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_BarChart(t, l, oNewVal, aChartWithAxis);
        });
        val.addChart(oNewVal);
    }
    else if (c_oserct_plotareaBUBBLECHART === type) {
        var oNewVal = new AscFormat.CBubbleChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_BubbleChart(t, l, oNewVal, aChartWithAxis);
        });
        //bubble -> scatter
        var scatter = this.ConvertBubbleToScatter(oNewVal, aChartWithAxis);
        val.addChart(scatter);
    }
    else if (c_oserct_plotareaDOUGHNUTCHART === type) {
        var oNewVal = new AscFormat.CDoughnutChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DoughnutChart(t, l, oNewVal, aChartWithAxis);
        });
        val.addChart(oNewVal);
    }
    else if (c_oserct_plotareaLINE3DCHART === type) {
        var oNewVal = new AscFormat.CLineChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Line3DChart(t, l, oNewVal, aChartWithAxis);
        });
        //3d->2d
        oNewVal.setMarker(true);
        oNewVal.setSmooth(false);
        for (var i = 0, length = oNewVal.series.length; i < length; ++i) {
            var seria = oNewVal.series[i];
            if (null == seria.marker) {
                var marker = new AscFormat.CMarker();
                marker.setSymbol(AscFormat.SYMBOL_NONE);
                seria.setMarker(marker);
            }
        }
        val.addChart(oNewVal);
    }
    else if (c_oserct_plotareaLINECHART === type) {
        var oNewVal = new AscFormat.CLineChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_LineChart(t, l, oNewVal, aChartWithAxis);
        });
        val.addChart(oNewVal);
        if(oNewVal.smooth === null){
            oNewVal.setSmooth(false);
        }
    }
    else if (c_oserct_plotareaOFPIECHART === type) {
        var oNewVal = new AscFormat.COfPieChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_OfPieChart(t, l, oNewVal, aChartWithAxis);
        });
        //ofPie -> pie
        var pie = this.ConvertOfPieToPie(oNewVal, aChartWithAxis);
        val.addChart(pie);
    }
    else if (c_oserct_plotareaPIE3DCHART === type) {
        var oNewVal = new AscFormat.CPieChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Pie3DChart(t, l, oNewVal, aChartWithAxis);
        });
        //3d->2d
        oNewVal.setFirstSliceAng(0);
        val.addChart(oNewVal);
    }
    else if (c_oserct_plotareaPIECHART === type) {
        var oNewVal = new AscFormat.CPieChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PieChart(t, l, oNewVal, aChartWithAxis);
        });
        val.addChart(oNewVal);
    }
    else if (c_oserct_plotareaRADARCHART === type) {
        var oNewVal = new AscFormat.CRadarChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_RadarChart(t, l, oNewVal, aChartWithAxis);
        });
        //radar -> line
        var line = this.ConvertRadarToLine(oNewVal, aChartWithAxis);
        val.addChart(line);
    }
    else if (c_oserct_plotareaSCATTERCHART === type) {
        var oNewVal = new AscFormat.CScatterChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ScatterChart(t, l, oNewVal, aChartWithAxis);
        });
        val.addChart(oNewVal);
    }
    else if (c_oserct_plotareaSTOCKCHART === type) {
        var oNewVal = new AscFormat.CStockChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_StockChart(t, l, oNewVal, aChartWithAxis);
        });
        val.addChart(oNewVal);
    }
    else if (c_oserct_plotareaSURFACE3DCHART === type) {
        var oNewVal = new AscFormat.CSurfaceChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Surface3DChart(t, l, oNewVal, aChartWithAxis);
        });
        //surface -> line
        //var line = this.ConvertSurfaceToLine(oNewVal, aChartWithAxis);
        val.addChart(oNewVal);
    }
    else if (c_oserct_plotareaSURFACECHART === type) {
        var oNewVal = new AscFormat.CSurfaceChart();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_SurfaceChart(t, l, oNewVal, aChartWithAxis);
        });
        //surface -> line
        //var line = this.ConvertSurfaceToLine(oNewVal, aChartWithAxis);
        val.addChart(oNewVal);
    }
    else if (c_oserct_plotareaCATAX === type) {
        var oNewVal = new AscFormat.CCatAx();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_CatAx(t, l, oNewVal);
        });
        if (null != oNewVal.axId)
            oIdToAxisMap[oNewVal.axId] = oNewVal;
        val.addAxis(oNewVal);

        if(oNewVal.majorTickMark === null){
            oNewVal.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
        }
        if(oNewVal.minorTickMark === null){
            oNewVal.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
        }
        if(oNewVal.crosses === null){
            oNewVal.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
        }
        if(oNewVal.noMultiLvlLbl === null){
            oNewVal.setNoMultiLvlLbl(false);
        }
        if(oNewVal.bDelete === null){
            oNewVal.setDelete(false);
        }
    }
    else if (c_oserct_plotareaDATEAX === type) {
        var oNewVal = new AscFormat.CDateAx();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DateAx(t, l, oNewVal);
        });
        if (null != oNewVal.axId)
            oIdToAxisMap[oNewVal.axId] = oNewVal;
        val.addAxis(oNewVal);

        if(oNewVal.majorTickMark === null){
            oNewVal.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
        }
        if(oNewVal.minorTickMark === null){
            oNewVal.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
        }
        if(oNewVal.crosses === null){
            oNewVal.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
        }
        if(oNewVal.bDelete === null){
            oNewVal.setDelete(false);
        }
    }
    else if (c_oserct_plotareaSERAX === type) {
        var oNewVal = new AscFormat.CSerAx();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_SerAx(t, l, oNewVal);
        });
        if (null != oNewVal.axId)
            oIdToAxisMap[oNewVal.axId] = oNewVal;
        val.addAxis(oNewVal);
        if(oNewVal.majorTickMark === null){
            oNewVal.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
        }
        if(oNewVal.minorTickMark === null){
            oNewVal.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
        }
        if(oNewVal.crosses === null){
            oNewVal.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
        }
        if(oNewVal.bDelete === null){
            oNewVal.setDelete(false);
        }

    }
    else if (c_oserct_plotareaVALAX === type) {
        var oNewVal = new AscFormat.CValAx();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_ValAx(t, l, oNewVal);
        });
        if (null != oNewVal.axId)
            oIdToAxisMap[oNewVal.axId] = oNewVal;
        val.addAxis(oNewVal);
        //if(!AscFormat.isRealNumber(oNewVal.crossBetween))
        //{
        //    oNewVal.setCrossBetween(AscFormat.CROSS_BETWEEN_BETWEEN);
        //}

        if(oNewVal.majorTickMark === null){
            oNewVal.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
        }
        if(oNewVal.minorTickMark === null){
            oNewVal.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
        }
        if(oNewVal.crosses === null){
            oNewVal.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
        }
        if(oNewVal.bDelete === null){
            oNewVal.setDelete(false);
        }
    }
    else if (c_oserct_plotareaDTABLE === type) {
        var oNewVal = new AscFormat.CDTable();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DTable(t, l, oNewVal);
        });
        val.setDTable(oNewVal);
    }
    else if (c_oserct_plotareaSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_plotareaEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Thickness = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_thicknessVAL === type) {
        val.m_val = this.ParsePersent(this.stream.GetString2LE(length));
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Surface = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_surfaceTHICKNESS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Thickness(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setThickness(oNewVal.m_val);
    }
    else if (c_oserct_surfaceSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_surfacePICTUREOPTIONS === type) {
        var oNewVal = new AscFormat.CPictureOptions();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PictureOptions(t, l, oNewVal);
        });
        val.setPictureOptions(oNewVal);
    }
    else if (c_oserct_surfaceEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Perspective = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_perspectiveVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetUChar();
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_DepthPercent = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_depthpercentVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetString2LE(length);
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_RotY = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_rotyVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetULongLE();
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_HPercent = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_hpercentVAL === type) {
        val.m_val = this.ParsePersent(this.stream.GetString2LE(length));
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_RotX = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_rotxVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetChar();
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_View3D = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_view3dROTX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_RotX(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setRotX(oNewVal.m_val);
    }
    else if (c_oserct_view3dHPERCENT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_HPercent(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setHPercent(oNewVal.m_val);
    }
    else if (c_oserct_view3dROTY === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_RotY(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setRotY(oNewVal.m_val);
    }
    else if (c_oserct_view3dDEPTHPERCENT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DepthPercent(t, l, oNewVal);
        });
        if (null != oNewVal.m_val){
            var nPercent = parseInt(oNewVal.m_val)
            if(AscFormat.isRealNumber(nPercent)){
                val.setDepthPercent(nPercent);
            }
        }
    }
    else if (c_oserct_view3dRANGAX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setRAngAx(oNewVal.m_val);
    }
    else if (c_oserct_view3dPERSPECTIVE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Perspective(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setPerspective(oNewVal.m_val);
    }
    else if (c_oserct_view3dEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_PivotFmt = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_pivotfmtIDX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setIdx(oNewVal.m_val);
    }
    else if (c_oserct_pivotfmtSPPR === type) {
        val.setSpPr(this.ReadSpPr(length));
    }
    else if (c_oserct_pivotfmtTXPR === type) {
        val.setTxPr(this.ReadTxPr(length));
        val.txPr.setParent(val);
    }
    else if (c_oserct_pivotfmtMARKER === type) {
        var oNewVal = new AscFormat.CMarker();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Marker(t, l, oNewVal);
        });
        val.setMarker(oNewVal);
    }
    else if (c_oserct_pivotfmtDLBL === type) {
        var oNewVal = new AscFormat.CDLbl();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DLbl(t, l, oNewVal);
        });
        oThis.CorrectDlbls(oNewVal);
        val.setLbl(oNewVal);
    }
    else if (c_oserct_pivotfmtEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_pivotFmts = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_pivotfmtsPIVOTFMT === type) {
        var oNewVal = new AscFormat.CPivotFmt();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PivotFmt(t, l, oNewVal);
        });
        val.setPivotFmts(oNewVal);
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Chart = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_chartTITLE === type) {
        var oNewVal = new AscFormat.CTitle();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Title(t, l, oNewVal);
        });
        if(!AscFormat.isRealBool(oNewVal.overlay))
        {
            oNewVal.setOverlay(false);
        }
        val.setTitle(oNewVal);
    }
    else if (c_oserct_chartAUTOTITLEDELETED === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setAutoTitleDeleted(oNewVal.m_val);
        else
            val.setAutoTitleDeleted(true);
    }
    else if (c_oserct_chartPIVOTFMTS === type) {
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_pivotFmts(t, l, val);
        });
    }
    else if (c_oserct_chartVIEW3D === type) {
        var oNewVal = new AscFormat.CView3d();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_View3D(t, l, oNewVal);
        });
        val.setView3D(oNewVal);
    }
    else if (c_oserct_chartFLOOR === type) {
        var oNewVal = new AscFormat.CChartWall();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Surface(t, l, oNewVal);
        });
        val.setFloor(oNewVal);
    }
    else if (c_oserct_chartSIDEWALL === type) {
        var oNewVal = new AscFormat.CChartWall();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Surface(t, l, oNewVal);
        });
        val.setSideWall(oNewVal);
    }
    else if (c_oserct_chartBACKWALL === type) {
        var oNewVal = new AscFormat.CChartWall();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Surface(t, l, oNewVal);
        });
        val.setBackWall(oNewVal);
    }
    else if (c_oserct_chartPLOTAREA === type) {
        var oNewVal = new AscFormat.CPlotArea();
        var oIdToAxisMap = {};
        var aChartWithAxis = [];
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_PlotArea(t, l, oNewVal, oIdToAxisMap, aChartWithAxis);
        });


        // выставляем axis в chart        
        // TODO: 1. Диаграмм может быть больше, но мы пока работаем только с одной
        // TODO: 2. Избавиться от oIdToAxisMap, aChartWithAxis, т.к. они здесь больше не нужны
      ///  var oZeroChart = oNewVal.charts[0];
      ///  if ( oZeroChart )
      ///  {
      ///      var len = oNewVal.axId.length
      ///      for ( var i = 0; i < len; i++ )
      ///          oZeroChart.addAxId(oNewVal.axId[i]);
      ///  }
        for(var nAxIndex = 0; nAxIndex < oNewVal.axId.length; ++nAxIndex)
        {
            var oCurAxis = oNewVal.axId[nAxIndex];
            oCurAxis.setCrossAx(oIdToAxisMap[oCurAxis.crossAxId]);
            delete oCurAxis.crossAxId;
        }
        for(var nChartIndex = 0; nChartIndex < aChartWithAxis.length; ++nChartIndex)
        {
            var oCurChartWithAxis = aChartWithAxis[nChartIndex];
            var axis = oIdToAxisMap[oCurChartWithAxis.axisId];
            oCurChartWithAxis.chart.addAxId(axis);
            if(axis && axis.getObjectType() === AscDFH.historyitem_type_ValAx && !AscFormat.isRealNumber(axis.crossBetween))
            {
                if(oCurChartWithAxis.chart.getObjectType() === AscDFH.historyitem_type_AreaChart)
                {
                    axis.setCrossBetween(AscFormat.CROSS_BETWEEN_MID_CAT);
                }
                else
                {
                    axis.setCrossBetween(AscFormat.CROSS_BETWEEN_BETWEEN);
                }
            }
        }
        val.setPlotArea(oNewVal);


        //check: does category axis exist
        for(var _i = oNewVal.charts.length - 1; _i > -1; --_i){
            var oChart = oNewVal.charts[_i];
            if(oChart)
            {
                if(oChart.getObjectType() !== AscDFH.historyitem_type_ScatterChart && oChart.getAxisByTypes)
                {
                    var axis_by_types = oChart.getAxisByTypes();
                    if(axis_by_types.valAx.length === 0 || axis_by_types.catAx.length === 0)
                    {
                        oNewVal.removeCharts(_i, _i);
                        if(oChart.axId){
                            oChart.axId.length = 0;
                            oChart = oChart.createDuplicate();
                            if(oChart.setParent){
                                oChart.setParent(oNewVal);
                            }
                        }
                        var sDefaultValAxFormatCode = null;
                        if(oChart && oChart.series[0]){
                            var aPoints = AscFormat.getPtsFromSeries(oChart.series[0]);
                            if(aPoints[0] && typeof aPoints[0].formatCode === "string" && aPoints[0].formatCode.length > 0){
                                sDefaultValAxFormatCode = aPoints[0].formatCode;
                            }
                        }
                        var need_num_fmt = sDefaultValAxFormatCode;
                        var axis_obj = AscFormat.CreateDefaultAxises(need_num_fmt ? need_num_fmt : "General");
                        var cat_ax = axis_obj.catAx;
                        var val_ax = axis_obj.valAx;
                        if(oChart.getObjectType() === AscDFH.historyitem_type_BarChart && oChart.barDir === AscFormat.BAR_DIR_BAR)
                        {
                            if(cat_ax.axPos !== AscFormat.AX_POS_L)
                            {
                                cat_ax.setAxPos(AscFormat.AX_POS_L);
                            }
                            if(val_ax.axPos !== AscFormat.AX_POS_B)
                            {
                                val_ax.setAxPos(AscFormat.AX_POS_B);
                            }
                        }
                        else
                        {
                            if(cat_ax.axPos !== AscFormat.AX_POS_B)
                            {
                                cat_ax.setAxPos(AscFormat.AX_POS_B);
                            }
                            if(val_ax.axPos !== AscFormat.AX_POS_L)
                            {
                                val_ax.setAxPos(AscFormat.AX_POS_L);
                            }
                        }

                        oNewVal.addChart(oChart);
                        oChart.addAxId(cat_ax);
                        oChart.addAxId(val_ax);
                        oNewVal.addAxis(cat_ax);
                        oNewVal.addAxis(val_ax);
                    }
                    else
                    {
                        if(oChart.getObjectType() === AscDFH.historyitem_type_BarChart && oChart.barDir === AscFormat.BAR_DIR_BAR)
                        {
                            for(var _c = 0; _c < axis_by_types.valAx.length; ++_c)
                            {
                                var val_ax = axis_by_types.valAx[_c];
                                if(val_ax.axPos !== AscFormat.AX_POS_B || val_ax.axPos !== AscFormat.AX_POS_T )
                                {
                                    val_ax.setAxPos(AscFormat.AX_POS_B);
                                }
                            }
                            for(var _c = 0; _c < axis_by_types.catAx.length; ++_c)
                            {
                                var cat_ax = axis_by_types.catAx[_c];
                                if(cat_ax.axPos !== AscFormat.AX_POS_L || cat_ax.axPos !== AscFormat.AX_POS_R )
                                {
                                    cat_ax.setAxPos(AscFormat.AX_POS_L);
                                }
                            }
                        }
                    }
                }
                if(oChart.setVaryColors && oChart.varyColors === null){
                    oChart.setVaryColors(false);
                }
                if(oChart.setSmooth && oChart.smooth === null){
                    oChart.setSmooth(false);
                }
                if(oChart.setGapWidth && oChart.gapWidth === null){
                    oChart.setGapWidth(150);
                }
                var oDlbls;
                if(oChart.setDLbls && oChart.dLbls === null){
                    oDlbls = new AscFormat.CDLbls();
                    oDlbls.setShowLegendKey(false);
                    oDlbls.setShowVal(false);
                    oDlbls.setShowCatName(false);
                    oDlbls.setShowSerName(false);
                    oDlbls.setShowPercent(false);
                    oDlbls.setShowBubbleSize(false);
                    oChart.setDLbls(oDlbls);
                }
                var aSeries = oChart.series;
            }
        }


    }
    else if (c_oserct_chartLEGEND === type) {
        var oNewVal = new AscFormat.CLegend();
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Legend(t, l, oNewVal);
        });
        oNewVal.updateLegendPos();
        val.setLegend(oNewVal);
    }
    else if (c_oserct_chartPLOTVISONLY === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setPlotVisOnly(oNewVal.m_val);
    }
    else if (c_oserct_chartDISPBLANKSAS === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_DispBlanksAs(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setDispBlanksAs(oNewVal.m_val);
    }
    else if (c_oserct_chartSHOWDLBLSOVERMAX === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setShowDLblsOverMax(oNewVal.m_val);
        else
            val.setShowDLblsOverMax(true);
    }
    else if (c_oserct_chartEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // val.m_extLst = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Protection = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_protectionCHARTOBJECT === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setChartObject(oNewVal.m_val);
    }
    else if (c_oserct_protectionDATA === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setData(oNewVal.m_val);
    }
    else if (c_oserct_protectionFORMATTING === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setFormatting(oNewVal.m_val);
    }
    else if (c_oserct_protectionSELECTION === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setSelection(oNewVal.m_val);
    }
    else if (c_oserct_protectionUSERINTERFACE === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Boolean(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setUserInterface(oNewVal.m_val);
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_PivotSource = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_pivotsourceNAME === type) {
        val.setName(this.stream.GetString2LE(length));
    }
    else if (c_oserct_pivotsourceFMTID === type) {
        var oNewVal = { m_val: null };
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_UnsignedInt(t, l, oNewVal);
        });
        if (null != oNewVal.m_val)
            val.setFmtId(oNewVal.m_val);
    }
    else if (c_oserct_pivotsourceEXTLST === type) {
        var oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_extLst(t, l, oNewVal);
        });
        // if (null == val.m_extLst)
        // val.m_extLst = [];
        // val.m_extLst.push(oNewVal);
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Style1 = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_style1VAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetUChar();
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_Style = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_styleVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetUChar();
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadCT_TextLanguageID = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oserct_textlanguageidVAL === type) {
        var oNewVal;
        oNewVal = this.stream.GetString2LE(length);
        val.m_val = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadAlternateContent = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oseralternatecontentCHOICE === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadAlternateContentChoice(t, l, oNewVal);
        });
        if (null == val.m_Choice)
            val.m_Choice = [];
        val.m_Choice.push(oNewVal);
    }
    else if (c_oseralternatecontentFALLBACK === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadAlternateContentFallback(t, l, oNewVal);
        });
        val.m_Fallback = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadAlternateContentChoice = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oseralternatecontentchoiceSTYLE === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Style(t, l, oNewVal);
        });
        val.m_style = oNewVal;
    }
    else if (c_oseralternatecontentchoiceREQUIRES === type) {
        var oNewVal;
        oNewVal = this.stream.GetString2LE(length);
        val.m_Requires = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}
BinaryChartReader.prototype.ReadAlternateContentFallback = function (type, length, val) {
    var res = c_oSerConstants.ReadOk;
    var oThis = this;
    if (c_oseralternatecontentfallbackSTYLE === type) {
        var oNewVal;
        oNewVal = {};
        res = this.bcr.Read1(length, function (t, l) {
            return oThis.ReadCT_Style1(t, l, oNewVal);
        });
        val.m_style = oNewVal;
    }
    else
        res = c_oSerConstants.ReadUnknown;
    return res;
}

  //----------------------------------------------------------export----------------------------------------------------
  window['AscCommon'] = window['AscCommon'] || {};
  window['AscCommon'].BinaryChartWriter = BinaryChartWriter;
  window['AscCommon'].BinaryChartReader = BinaryChartReader;

  window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].LAYOUT_MODE_EDGE = LAYOUT_MODE_EDGE;
    window['AscFormat'].LAYOUT_MODE_FACTOR = LAYOUT_MODE_FACTOR;

    window['AscFormat'].LAYOUT_TARGET_INNER = LAYOUT_TARGET_INNER;
    window['AscFormat'].LAYOUT_TARGET_OUTER = LAYOUT_TARGET_OUTER;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

	// https://bugreport.apple.com/web/?problemID=39173151
	var isSafariAppleDevices = (AscCommon.AscBrowser.isSafariMacOs && AscCommon.AscBrowser.isAppleDevices);

function _FT_Common()
{


	this.UintToInt = function(v){
        return (v>2147483647)?v-4294967296:v;
    }
    this.UShort_To_Short = function(v){
        return (v>32767)?v-65536:v;
    }
    this.IntToUInt = function(v){
        return (v<0)?v+4294967296:v;
    }
    this.Short_To_UShort = function(v){
        return (v<0)?v+65536:v;
    }
    this.memset = function(d,v,s)
    {
        for (var i=0;i<s;i++)
            d[i]=v;
    }
    this.memcpy = function(d,s,l)
    {
        for (var i=0;i<l;i++)
            d[i]=s[i];
    }
    this.memset_p = function(d,v,s)
    {
        var _d = d.data;
        var _e = d.pos+s;
        for (var i=d.pos;i<_e;i++)
            _d[i]=v;
    }
    this.memcpy_p = function(d,s,l)
    {
        var _d1=d.data;
        var _p1=d.pos;
        var _d2=s.data;
        var _p2=s.pos;
        for (var i=0;i<l;i++)
            _d1[_p1++]=_d2[_p2++];
    }
    this.memcpy_p2 = function(d,s,p,l)
    {
        var _d1=d.data;
        var _p1=d.pos;
        var _p2=p;
        for (var i=0;i<l;i++)
            _d1[_p1++]=s[_p2++];
    }
    this.realloc = function(memory, pointer, cur_count, new_count)
    {
        var ret = { block: null, err : 0, size : new_count};
        if (cur_count < 0 || new_count < 0)
        {
            /* may help catch/prevent nasty security issues */
            ret.err = 6;
        }
        else if (new_count == 0)
        {
            ret.block = null;
        }
        else if (cur_count == 0)
        {
            ret.block = memory.Alloc(new_count);
        }
        else
        {
            var block2 = memory.Alloc(new_count);
            FT_Common.memcpy_p(block2, pointer, cur_count);
            ret.block = block2;
        }
        return ret;
    }

    this.realloc_long = function(memory, pointer, cur_count, new_count)
    {
        var ret = { block: null, err : 0, size : new_count};
        if (cur_count < 0 || new_count < 0)
        {
            /* may help catch/prevent nasty security issues */
            ret.err = 6;
        }
        else if (new_count == 0)
        {
            ret.block = null;
        }
        else if (cur_count == 0)
        {
            ret.block = CreateIntArray(new_count);
        }
        else
        {
            var block2 = CreateIntArray(new_count);
            for (var i = 0; i < cur_count; i++)
                block2[i] = pointer[i];

            ret.block = block2;
        }
        return ret;
    }
}
var FT_Common = new _FT_Common();
/******************************************************************************/
//                                  SERVICES
/******************************************************************************/

/******************************************************************************/
// bdf
/******************************************************************************/
var FT_SERVICE_ID_BDF = "bdf";
function FT_Service_BDFRec(get_charset_id_,get_property_)
{
    this.get_charset_id = get_charset_id_;
    this.get_property = get_property_;
}
/******************************************************************************/
// cid
/******************************************************************************/
var FT_SERVICE_ID_CID = "CID";
function FT_Service_CIDRec(get_ros_, get_is_cid_, get_cid_from_glyph_index_)
{
    this.get_ros = get_ros_;
    this.get_is_cid = get_is_cid_;
    this.get_cid_from_glyph_index = get_cid_from_glyph_index_;
}
/******************************************************************************/
// glyph-dict
/******************************************************************************/
var FT_SERVICE_ID_GLYPH_DICT = "glyph-dict";
function FT_Service_GlyphDictRec(get_name_, name_index_)
{
    this.get_name = get_name_;
    this.name_index = name_index_;
}
/******************************************************************************/
// gxval
/******************************************************************************/
var FT_SERVICE_ID_GX_VALIDATE = "truetypegx-validate";
var FT_SERVICE_ID_CLASSICKERN_VALIDATE = "classickern-validate";

function FT_Service_GXvalidateRec(validate_)
{
    this.validate = validate_;
}
function FT_Service_CKERNvalidateRec(validate_)
{
    this.validate = validate_;
}
/******************************************************************************/
// kerning
/******************************************************************************/
var FT_SERVICE_ID_KERNING = "kerning";
function FT_Service_KerningRec(get_track_)
{
    this.get_track = get_track_;
}
/******************************************************************************/
// multi-masters
/******************************************************************************/
var FT_SERVICE_ID_MULTI_MASTERS = "multi-masters";
function FT_Service_MultiMastersRec(get_mm_, set_mm_design_, set_mm_blend_, get_mm_var_, set_var_design_)
{
    this.get_mm = get_mm_;
    this.set_mm_design = set_mm_design_;
    this.set_mm_blend = set_mm_blend_;
    this.get_mm_var = get_mm_var_;
    this.set_var_design = set_var_design_;
}
/******************************************************************************/
// opentype-validate
/******************************************************************************/
var FT_SERVICE_ID_OPENTYPE_VALIDATE = "opentype-validate";
function FT_Service_OTvalidateRec(validate_)
{
    this.validate = validate_;
}
/******************************************************************************/
// pfr-metrics
/******************************************************************************/
var FT_SERVICE_ID_PFR_METRICS = "pfr-metrics";
function FT_Service_PfrMetricsRec(get_metrics_,get_kerning_,get_advance_)
{
    this.get_metrics = get_metrics_;
    this.get_kerning = get_kerning_;
    this.get_advance = get_advance_;
}
/******************************************************************************/
// postscript-font-name
/******************************************************************************/
var FT_SERVICE_ID_POSTSCRIPT_FONT_NAME = "postscript-font-name";
function FT_Service_PsFontNameRec(get_ps_font_name_)
{
    this.get_ps_font_name = get_ps_font_name_;
}
/******************************************************************************/
// postscript-cmaps
/******************************************************************************/
var FT_SERVICE_ID_POSTSCRIPT_CMAPS = "postscript-cmaps";

function PS_UniMap()
{
    this.unicode;
    this.glyph_index;
}
function PS_UnicodesRec()
{
    this.cmap;
    this.num_maps;
    this.maps;
}
function FT_Service_PsCMapsRec(unicode_value_, unicodes_init_,unicodes_char_index_, unicodes_char_next_, macintosh_name_,
                                    adobe_std_strings_, adobe_std_encoding_, adobe_expert_encoding_)
{
    this.unicode_value = unicode_value_;

    this.unicodes_init = unicodes_init_;
    this.unicodes_char_index = unicodes_char_index_;
    this.unicodes_char_next = unicodes_char_next_;

    this.macintosh_name = macintosh_name_;
    this.adobe_std_strings = adobe_std_strings_;
    this.adobe_std_encoding = adobe_std_strings_;
    this.adobe_expert_encoding = adobe_expert_encoding_;
}
/******************************************************************************/
// postscript-info
/******************************************************************************/
var FT_SERVICE_ID_POSTSCRIPT_INFO = "postscript-info";
function FT_Service_PsInfoRec(get_font_info_, ps_get_font_extra_, has_glyph_names_,get_font_private_, get_font_value_)
{
    this.ps_get_font_info = get_font_info_;
    this.ps_get_font_extra = ps_get_font_extra_;
    this.ps_has_glyph_names = has_glyph_names_;
    this.ps_get_font_private = get_font_private_;
    this.ps_get_font_value = get_font_value_;
}
/******************************************************************************/
// sfnt-table
/******************************************************************************/
var FT_SERVICE_ID_SFNT_TABLE = "sfnt-table";
function FT_Service_SFNT_TableRec(load_, get_, info_)
{
    this.load_table = load_;
    this.get_table = get_;
    this.table_info = info_;
}
/******************************************************************************/
// tt-cmaps
/******************************************************************************/
var FT_SERVICE_ID_TT_CMAP = "tt-cmaps";
function TT_CMapInfo()
{
    this.language = 0;
    this.format = 0;
}
function FT_Service_TTCMapsRec(get_cmap_info_)
{
    this.get_cmap_info = get_cmap_info_;
}
/******************************************************************************/
// truetype-engine
/******************************************************************************/
var FT_SERVICE_ID_TRUETYPE_ENGINE = "truetype-engine";
function FT_Service_TrueTypeEngineRec(engine_type_)
{
    this.engine_type = engine_type_;
}
/******************************************************************************/
// tt-glyf
/******************************************************************************/
var FT_SERVICE_ID_TT_GLYF = "tt-glyf";
function FT_Service_TTGlyfRec(get_location_)
{
    this.get_location = get_location_;
}
/******************************************************************************/
// winfonts
/******************************************************************************/
var FT_SERVICE_ID_WINFNT = "winfonts";
function FT_Service_WinFntRec(get_header_)
{
    this.get_header = get_header_;
}
/******************************************************************************/
// xf86
/******************************************************************************/
var FT_SERVICE_ID_XF86_NAME  = "xf86-driver-name";
var FT_XF86_FORMAT_TRUETYPE  = "TrueType";
var FT_XF86_FORMAT_TYPE_1    = "Type 1";
var FT_XF86_FORMAT_BDF       = "BDF";
var FT_XF86_FORMAT_PCF       = "PCF";
var FT_XF86_FORMAT_TYPE_42   = "Type 42";
var FT_XF86_FORMAT_CID       = "CID Type 1";
var FT_XF86_FORMAT_CFF       = "CFF";
var FT_XF86_FORMAT_PFR       = "PFR";
var FT_XF86_FORMAT_WINFNT    = "Windows FNT";

/******************************************************************************/
function FT_ServiceDescRec(id,data)
{
    this.serv_id = id;
    this.serv_data = data;
}
function ft_service_list_lookup(service_descriptors,service_id)
{
    var c = service_descriptors.length;
    for (var i=0;i<c;i++)
    {
        if (service_descriptors[i].serv_id == service_id)
            return service_descriptors[i].serv_data;
    }
    return null;
}

function FT_FACE_FIND_SERVICE(face, id)
{
    var module = face.driver;
    if (module.clazz.get_interface)
        return module.clazz.get_interface(module, id);
    return null;
}
function FT_FACE_FIND_GLOBAL_SERVICE(face, name)
{
    return ft_module_get_service(face.driver, name);
}
function ft_module_get_service(module, name)
{
    var result = null;

    if (module != null)
    {
        if (null != module.clazz.get_interface)
            result = module.clazz.get_interface(module, name);
        if (null == result)
        {
            var modules = module.library.modules;
            var count = modules.length;
            for (var i = 0;i<count;i++)
            {
                if (modules[i].clazz.get_interface)
                {
                    result = modules[i].clazz.get_interface(modules[i], name);
                    if (null != result)
                        break;
                }
            }
        }
    }

    return result;
}

function FT_ServiceCache()
{
    this.service_POSTSCRIPT_FONT_NAME = null;
    this.service_MULTI_MASTERS = null;
    this.service_GLYPH_DICT = null;
    this.service_PFR_METRICS = null;
    this.service_WINFNT = null;
}
/******************************************************************************/
// stream
/******************************************************************************/
function FT_Frame_Field(v,s,o)
{
    this.value = v;
    this.size = s;
    this.offset = o;
}
function FT_Stream(data, size)
{
	this.obj = null;
	this.data = data;
	this.size = size;
	this.pos = 0;
	this.cur = 0;
}
FT_Stream.prototype =
{
    Seek : function(_pos)
    {
        if (_pos > this.size)
            return 85;
        this.pos = _pos;
        return 0;
    },
    Skip : function(_skip)
    {
        if (_skip < 0)
            return 85;
        return this.Seek(this.pos + _skip);
    },
    Read : function(pointer, count)
    {
        return this.ReadAt(this.pos, pointer, count);
    },
    ReadArray : function(count)
    {
        var read_bytes = this.size - this.pos;
        if (read_bytes > count)
            read_bytes = count;
        if (0 == read_bytes)
            return null;
        var a = new Array(read_bytes);
        for (var i = 0;i<count;i++)
            a[i] = this.data[this.pos+i];
        return a;
    },
    ReadAt : function(_pos, pointer, count)
    {
        if (_pos > this.size)
            return 85;
        var read_bytes = this.size - _pos;
        if (read_bytes > count)
            read_bytes = count;

        FT_Common.memcpy_p2(pointer,this.data,_pos,count);

        this.pos = _pos + read_bytes;

        if (read_bytes < count)
            return 85;

        return 0;
    },
    TryRead : function(pointer, count)
    {
        var read_bytes = 0;
        if (this.pos < this.size)
            return read_bytes;
        read_bytes = this.size - this.pos;
        if (read_bytes > count)
            read_bytes = count;

        FT_Common.memcpy_p2(pointer,this.data,this.pos,count);

        this.pos += read_bytes;
        return read_bytes;
    },

    // 1 bytes
    GetUChar : function()
    {
        if (this.cur >= this.size)
            return 0;
        return this.data[this.cur++];
    },
    GetChar : function()
    {
        if (this.cur >= this.size)
            return 0;
        var m = this.data[this.cur++];
        if (m > 127)
            m -= 256;
        return m;
    },
    GetString1 : function(len)
    {
        if (this.cur + len > this.size)
            return "";
        var t = "";
        for (var i = 0; i < len; i++)
            t += String.fromCharCode(this.data[this.cur + i]);
        this.cur += len;
        return t;
    },
    ReadString1 : function(len)
    {
        if (this.pos + len > this.size)
            return "";
        var t = "";
        for (var i = 0; i < len; i++)
            t += String.fromCharCode(this.data[this.pos + i]);
        this.pos += len;
        return t;
    },

    ReadUChar : function()
    {
        if (this.pos >= this.size)
        {
            FT_Error = 85;
            return 0;
        }
        FT_Error = 0;
        return this.data[this.pos++];
    },
    ReadChar : function()
    {
        if (this.pos >= this.size)
        {
            FT_Error = 85;
            return 0;
        }
        FT_Error = 0;
        var m = this.data[this.pos++];
        if (m > 127)
            m -= 256;
        return m;
    },

    // 2 byte
    GetUShort : function()
    {
        if (this.cur + 1 >= this.size)
            return 0;
        return (this.data[this.cur++] << 8 | this.data[this.cur++]);
    },
    GetShort : function()
    {
        return FT_Common.UShort_To_Short(this.GetUShort());
    },
    ReadUShort : function()
    {
        if (this.pos + 1 >= this.size)
        {
            FT_Error = 85;
            return 0;
        }
        FT_Error = 0;
        return (this.data[this.pos++] << 8 | this.data[this.pos++]);
    },
    ReadShort : function()
    {
        return FT_Common.UShort_To_Short(this.ReadUShort());
    },
    GetUShortLE : function()
    {
        if (this.cur + 1 >= this.size)
            return 0;
        return (this.data[this.cur++] | this.data[this.cur++] << 8);
    },
    GetShortLE : function()
    {
        return FT_Common.UShort_To_Short(this.GetUShortLE());
    },
    ReadUShortLE : function()
    {
        if (this.pos + 1 >= this.size)
        {
            FT_Error = 85;
            return 0;
        }
        FT_Error = 0;
        return (this.data[this.pos++] | this.data[this.pos++] << 8);
    },
    ReadShortLE : function()
    {
        return FT_Common.UShort_To_Short(this.ReadUShortLE());
    },

    // 4 byte
    GetULong : function()
    {
        if (this.cur + 3 >= this.size)
            return 0;
        //return (this.data[this.cur++] << 24 | this.data[this.cur++] << 16 | this.data[this.cur++] << 8 | this.data[this.cur++]);
        var s = (this.data[this.cur++] << 24 | this.data[this.cur++] << 16 | this.data[this.cur++] << 8 | this.data[this.cur++]);
        if (s < 0)
            s += 4294967296;
        return s;
    },
    GetLong : function()
    {
        // 32-битные числа - по умолчанию знаковые!!!
        //return FT_Common.UintToInt(this.GetULong());
        return (this.data[this.cur++] << 24 | this.data[this.cur++] << 16 | this.data[this.cur++] << 8 | this.data[this.cur++]);
    },
    ReadULong : function()
    {
        if (this.pos + 3 >= this.size)
        {
            FT_Error = 85;
            return 0;
        }
        FT_Error = 0;
        var s = (this.data[this.pos++] << 24 | this.data[this.pos++] << 16 | this.data[this.pos++] << 8 | this.data[this.pos++]);
        if (s < 0)
            s += 4294967296;
        return s;
    },
    ReadLong : function()
    {
        // 32-битные числа - по умолчанию знаковые!!!
        //return FT_Common.Uint_To_int(this.ReadULong());
        if (this.pos + 3 >= this.size)
        {
            FT_Error = 85;
            return 0;
        }
        FT_Error = 0;
        return (this.data[this.pos++] << 24 | this.data[this.pos++] << 16 | this.data[this.pos++] << 8 | this.data[this.pos++]);
    },

    GetULongLE : function()
    {
        if (this.cur + 3 >= this.size)
            return 0;
        return (this.data[this.cur++] | this.data[this.cur++] << 8 | this.data[this.cur++] << 16 | this.data[this.cur++] << 24);
    },
    GetLongLE : function()
    {
        return FT_Common.Uint_To_int(this.GetULongLE());
    },
    ReadULongLE : function()
    {
        if (this.pos + 3 >= this.size)
        {
            FT_Error = 85;
            return 0;
        }
        FT_Error = 0;
        return (this.data[this.pos++] | this.data[this.pos++] << 8 | this.data[this.pos++] << 16 | this.data[this.pos++] << 24);
    },
    ReadLongLE : function()
    {
        return FT_Common.Uint_To_int(this.ReadULongLE());
    },

    // 3 byte
    GetUOffset : function()
    {
        if (this.cur + 2 >= this.size)
            return 0;
        return (this.data[this.cur++] << 16 | this.data[this.cur++] << 8 | this.data[this.cur++]);
    },
    GetUOffsetLE : function()
    {
        if (this.cur + 2 >= this.size)
            return 0;
        return (this.data[this.cur++] | this.data[this.cur++] << 8 | this.data[this.cur++] << 16);
    },
    ReadUOffset : function()
    {
        if (this.pos + 2 >= this.size)
        {
            FT_Error = 85;
            return 0;
        }
        FT_Error = 0;
        return (this.data[this.pos++] << 16 | this.data[this.pos++] << 8 | this.data[this.pos++]);
    },
    ReadUOffsetLE : function()
    {
        if (this.pos + 2 >= this.size)
        {
            FT_Error = 85;
            return 0;
        }
        FT_Error = 0;
        return (this.data[this.pos++] | this.data[this.pos++] << 8 | this.data[this.pos++] << 16);
    },
    EnterFrame : function(count)
    {
        if (this.pos >= this.size || this.size - this.pos < count)
            return 85;

        this.cur = this.pos;
        this.pos += count;
        return 0;
    },
    ExtractFrame : function(count, pointer)
    {
        if (null == pointer)
            pointer = new CPointer();

        var err = this.EnterFrame(count);
        if (err != 0)
            return err;

        pointer.data = this.data;
        pointer.pos = this.cur;

        this.cur = 0;
        return err;
    },
    ReleaseFrame : function()
    {
    },
    ExitFrame : function()
    {
        this.cur = 0;
    },

    ReadFields : function(arrayFields, structure)
    {
        // arrayFields : array {value, size, offset}
        // structures : data pointer
        var error = 0;
        var cursor = this.cur;
        var frame_accessed = false;

        var data = null;
        var pos = 0;

        var ind = 0;
        do
        {
            var value;
            var sign_shift;

            switch (arrayFields[ind].value)
            {
                case 4:  /* access a new frame */
                    error = this.EnterFrame(arrayFields[ind].offset);
                    if (error != 0)
                    {
                        if (frame_accessed === true)
                            this.ExitFrame();
                        return error;
                    }

                    frame_accessed = true;
                    cursor = this.cur;
                    ind++;
                    continue;  /* loop! */

                case 24:  /* read a byte sequence */
                case 25:   /* skip some bytes      */
                {
                    var len = arrayFields[ind].size;
                    if ( cursor + len > this.size )
                    {
                        error = 85;
                        if (frame_accessed === true)
                            this.ExitFrame();
                        return error;
                    }

                    if ( arrayFields[ind] == 24 )
                    {
                        data = structure.data;
                        pos = structure.pos + arrayFields[ind].offset;

                        for (var i=0;i<len;i++)
                            data[i] = this.data[cursor+i];
                    }
                    cursor += len;
                    ind++;
                    continue;
                }

                case 8:
                case 9:  /* read a single byte */
                    value = this.data[cursor++];
                    sign_shift = 24;
                    break;

                case 13:
                case 12:  /* read a 2-byte big-endian short */
                    value = this.data[cursor++] << 8 | this.data[cursor++];
                    sign_shift = 16;
                    break;

                case 15:
                case 14:  /* read a 2-byte little-endian short */
                    value = this.data[cursor++] | this.data[cursor++] << 8;
                    sign_shift = 16;
                    break;

                case 17:
                case 16:  /* read a 4-byte big-endian long */
                    value = this.data[cursor++] << 24 | this.data[cursor++] << 16 | this.data[cursor++] << 8 | this.data[cursor++];
                    sign_shift = 0;
                    break;

                case 19:
                case 18:  /* read a 4-byte little-endian long */
                    value = this.data[cursor++] | this.data[cursor++] << 8 | this.data[cursor++] << 16 | this.data[cursor++] << 24;
                    sign_shift = 0;
                    break;

                case 21:
                case 20:  /* read a 3-byte big-endian long */
                    value = this.data[cursor++] << 16 | this.data[cursor++] << 8 | this.data[cursor++];
                    sign_shift = 8;
                    break;

                case 23:
                case 22:  /* read a 3-byte little-endian long */
                    value = this.data[cursor++] | this.data[cursor++] << 8 | this.data[cursor++] << 16;
                    sign_shift = 8;
                    break;

                default:
                    /* otherwise, exit the loop */
                    this.cur = cursor;
                    if (frame_accessed === true)
                        this.ExitFrame();
                    return error;
            }

            /* now, compute the signed value is necessary */
            if ( arrayFields[ind].value & 1 )
                value = (( value << sign_shift ) >>> sign_shift) & 0xFFFFFFFF;

            /* finally, store the value in the object */

            data = structure.data;
            pos = structure.pos + arrayFields[ind].offset;
            switch (arrayFields[ind])
            {
                case 1:
                    data[pos] = value & 0xFF;
                    break;

                case 2:
                    data[pos] = (value >>> 8)&0xFF;
                    data[pos+1] = value&0xFF;
                    break;

                case 4:
                    data[pos] = (value >>> 24)&0xFF;
                    data[pos+1] = (value >>> 16)&0xFF;
                    data[pos+2] = (value >>> 8)&0xFF;
                    data[pos+3] = value&0xFF;
                    break;

                default:
                    data[pos] = (value >>> 24)&0xFF;
                    data[pos+1] = (value >>> 16)&0xFF;
                    data[pos+2] = (value >>> 8)&0xFF;
                    data[pos+3] = value&0xFF;
            }

            /* go to next field */
            ind++;
        }
        while ( 1 );

        return error;
    },
    ReadFields2 : function(fields, structure)
    {
        // arrayFields : array {value, size, offset}
        // structures : data pointer
        var error = 0;
        var cursor = this.cur;
        var frame_accessed = false;

        var data = null;
        var pos = 0;

        var ind = 0;
        do
        {
            var value;
            var sign_shift;

            var fval = fields[ind];
            var fsize = fields[ind+1];
            var foffset = fields[ind+2];

            switch (fval)
            {
                case 4:  /* access a new frame */
                    error = this.EnterFrame(foffset);
                    if (error != 0)
                    {
                        if (frame_accessed === true)
                            this.ExitFrame();
                        return error;
                    }

                    frame_accessed = true;
                    cursor = this.cur;
                    ind+=3;
                    continue;  /* loop! */

                case 24:  /* read a byte sequence */
                case 25:   /* skip some bytes      */
                {
					var len = fields[ind].size;
                    if ( cursor + fsize > this.size )
                    {
                        error = 85;
                        if (frame_accessed === true)
                            this.ExitFrame();
                        return error;
                    }

                    if ( fval == 24 )
                    {
                        data = structure.data;
                        pos = structure.pos + fields[ind].offset;

                        for (var i=0;i<len;i++)
                            data[i] = this.data[cursor+i];
                    }
                    cursor += fsize;
                    ind++;
                    continue;
                }

                case 8:
                case 9:  /* read a single byte */
                    value = this.data[cursor++];
                    sign_shift = 24;
                    break;

                case 13:
                case 12:  /* read a 2-byte big-endian short */
                    value = this.data[cursor++] << 8 | this.data[cursor++];
                    sign_shift = 16;
                    break;

                case 15:
                case 14:  /* read a 2-byte little-endian short */
                    value = this.data[cursor++] | this.data[cursor++] << 8;
                    sign_shift = 16;
                    break;

                case 17:
                case 16:  /* read a 4-byte big-endian long */
                    value = this.data[cursor++] << 24 | this.data[cursor++] << 16 | this.data[cursor++] << 8 | this.data[cursor++];
                    sign_shift = 0;
                    break;

                case 19:
                case 18:  /* read a 4-byte little-endian long */
                    value = this.data[cursor++] | this.data[cursor++] << 8 | this.data[cursor++] << 16 | this.data[cursor++] << 24;
                    sign_shift = 0;
                    break;

                case 21:
                case 20:  /* read a 3-byte big-endian long */
                    value = this.data[cursor++] << 16 | this.data[cursor++] << 8 | this.data[cursor++];
                    sign_shift = 8;
                    break;

                case 23:
                case 22:  /* read a 3-byte little-endian long */
                    value = this.data[cursor++] | this.data[cursor++] << 8 | this.data[cursor++] << 16;
                    sign_shift = 8;
                    break;

                default:
                    /* otherwise, exit the loop */
                    this.cur = cursor;
                    if (frame_accessed === true)
                        this.ExitFrame();
                    return error;
            }

            /* now, compute the signed value is necessary */
            if (0 != (fval & 1))
                value = (( value << sign_shift ) >>> sign_shift) & 0xFFFFFFFF;

            /* finally, store the value in the object */

            data = structure.data;
            pos = structure.pos + fields[ind].offset;
            switch (fields[ind])
            {
                case 1:
                    data[pos] = value & 0xFF;
                    break;

                case 2:
                    data[pos] = (value >>> 8)&0xFF;
                    data[pos+1] = value&0xFF;
                    break;

                case 4:
                    data[pos] = (value >>> 24)&0xFF;
                    data[pos+1] = (value >>> 16)&0xFF;
                    data[pos+2] = (value >>> 8)&0xFF;
                    data[pos+3] = value&0xFF;
                    break;

                default:
                    data[pos] = (value >>> 24)&0xFF;
                    data[pos+1] = (value >>> 16)&0xFF;
                    data[pos+2] = (value >>> 8)&0xFF;
                    data[pos+3] = value&0xFF;
            }

            /* go to next field */
            ind+=3;
        }
        while ( 1 );

        return error;
    }
};
/******************************************************************************/
// memory
/******************************************************************************/
function CPointer()
{
    this.obj    = null;
    this.data   = null;
    this.pos    = 0;
}
function dublicate_pointer(p)
{
    if (null == p)
        return null;

    var d = new CPointer();
    d.data = p.data;
    d.pos = p.pos;
    return d;
}
function copy_pointer(p, size)
{
    var _p = g_memory.Alloc(size);
    for (var i = 0; i < size; i++)
        _p.data[i] = p.data[p.pos + i];
    return _p;
}

function FT_Memory()
{
    this.canvas = document.createElement('canvas');
    this.canvas.width = 1;
    this.canvas.height = 1;
    this.ctx    = this.canvas.getContext('2d');

    this.Alloc = function(size)
    {
        var p = new CPointer();
        p.obj = this.ctx.createImageData(1,parseInt((size + 3) / 4));
        p.data = p.obj.data;
        p.pos = 0;
        return p;
    }
    this.AllocHeap = function()
    {
        // TODO: нужно посмотреть, как эта память будет использоваться.
        // нужно ли здесь делать стек, либо все время от нуля делать??
    }
    this.CreateStream = function(size)
    {
        var _size = parseInt((size + 3) / 4);
        var obj = this.ctx.createImageData(1,_size);
        return new FT_Stream(obj.data,_size);
    }
}
var g_memory = new FT_Memory();

function FT_PEEK_CHAR(p)
{
    var r = p.data[p.pos];
    if (r > 127)
        return r-256;
    return r;
}
function FT_NEXT_CHAR(p)
{
    var r = p.data[p.pos++];
    if (r > 127)
        return r - 256;
    return r;
}
function FT_PEEK_BYTE(p)
{
    return p.data[p.pos];
}
function FT_NEXT_BYTE(p)
{
    var r = p.data[p.pos++];
    return r;
}
function FT_PEEK_SHORT(p)
{
    var r = (p.data[p.pos] << 8 | p.data[p.pos+1]);
    if (r > 32767)
        return r - 65536;
    return r;
}
function FT_PEEK_SHORT_LE(p)
{
    var r = (p.data[p.pos+1] << 8 | p.data[p.pos]);
    if (r > 32767)
        return r - 65536;
    return r;
}
function FT_NEXT_SHORT(p)
{
    var r = (p.data[p.pos++] << 8 | p.data[p.pos++]);
    if (r > 32767)
        return r - 65536;
    return r;
}
function FT_PEEK_USHORT(p)
{
    var r = (p.data[p.pos] << 8 | p.data[p.pos+1]);
    return r;
}
function FT_PEEK_USHORT_LE(p)
{
    var r = (p.data[p.pos + 1] << 8 | p.data[p.pos]);
    return r;
}
function FT_NEXT_USHORT(p)
{
    var r = (p.data[p.pos++] << 8 | p.data[p.pos++]);
    return r;
}
function FT_PEEK_UOFF3(p)
{
    var r = (p.data[p.pos] << 16 | p.data[p.pos+1] << 8 | p.data[p.pos+2]);
    return r;
}
function FT_NEXT_UOFF3(p)
{
    var r = (p.data[p.pos++] << 16 | p.data[p.pos++] << 8 | p.data[p.pos++]);
    return r;
}
function FT_PEEK_LONG(p)
{
    return (p.data[p.pos] << 24 | p.data[p.pos+1] << 16 | p.data[p.pos+2] << 8 | p.data[p.pos+3]);
}
function FT_NEXT_LONG(p)
{
    var r = (p.data[p.pos++] << 24 | p.data[p.pos++] << 16 | p.data[p.pos++] << 8 | p.data[p.pos++]);
    return r;
}
function FT_PEEK_ULONG(p)
{
    var r = (p.data[p.pos] << 24 | p.data[p.pos+1] << 16 | p.data[p.pos+2] << 8 | p.data[p.pos+3]);
    if (r<0)
        r+=4294967296;
    return r;
}
function FT_PEEK_ULONG_LE(p)
{
    var r = (p.data[p.pos+3] << 24 | p.data[p.pos+2] << 16 | p.data[p.pos+1] << 8 | p.data[p.pos]);
    if (r<0)
        r+=4294967296;
    return r;
}
function FT_NEXT_ULONG(p)
{
    var r = (p.data[p.pos++] << 24 | p.data[p.pos++] << 16 | p.data[p.pos++] << 8 | p.data[p.pos++]);
    if (r<0)
        r+=4294967296;
    return r;
}
function FT_PEEK_String1(p,len)
{
    var t = "";
    for (var i = 0; i < len; i++)
    {
        var r = p.data[p.pos + i];
        if (r == 0)
            return t;
        t += String.fromCharCode(r);
    }
    return t;
}
function FT_NEXT_String1(p,len)
{
    var t = "";
    for (var i = 0; i < len; i++)
        t += String.fromCharCode(p.data[p.pos + i]);
    p.pos+=len;
    return t;
}
function ft_memchr(p, v, size)
{
    for (var i=0;i<size;i++)
        if (p.data[p.pos+i] == v)
            return i;
    return -1;
}
function _strncmp(s1,s2,n)
{
    var m1 = s1.length;
    var m2 = s2.length;
    var l = n;
    if (m1 < l)
        l = m1;
    if (m2 < l)
        l = m2;

    for (var i=0;i<l;i++)
    {
        var c = s1.charCodeAt(i) - s2.charCodeAt(i);
        if (c != 0)
            return c;
    }
    return m1 - m2;
}

function _strcmp_data(s,p)
{
    var m = s.length;

    for (var i=0;i<m;i++)
    {
        var _c = p.data[p.pos + i];
        if (_c == 0)
            return 1;

        var c = s.charCodeAt(i) - _c;
        if (c != 0)
            return c;
    }

    if (p.data[p.pos + m] == 0)
        return 0;

    return -1;
}

function _strcmp(s1,s2)
{
    return (s1 == s2) ? 0 : 1;
}

function _strncmp_data(p,s,n)
{
    var m2 = s.length;
    var l = n;
    if (m2 < l)
        l = m2;

    var m1 = 0;
    for (var i=0;i<l;i++)
    {
        m1++;
        if (0 == p.data[p.pos + i])
        {
            m1 = i;
            break;
        }

        var c = p.data[p.pos + i] - s.charCodeAt(i);
        if (c != 0)
            return c;
    }
    return m1 - m2;
}
function _strncmp2(s1,s2,n,start1,start2)
{
    var m1 = s1.length - start1;
    var m2 = s2.length - start2;
    var l = n;
    if (m1 < l)
        l = m1;
    if (m2 < l)
        l = m2;

    for (var i=0;i<l;i++)
    {
        var c = s1.charCodeAt(i + start1) - s2.charCodeAt(i + start2);
        if (c != 0)
            return c;
    }
    return m1 - m2;
}
function _mem_strcpyn1(dst, src, size)
{
    var i = 0;
    var slen = src.length;
    while (size > 1 && i < slen)
    {
        dst.data[dst.pos + i] = src.charCodeAt(i);
        i++;
    }

    dst.data[dst.pos + i] = 0;  /* always zero-terminate */
    return i != slen;
}
/******************************************************************************/
// calc
/******************************************************************************/
function FT_LOAD_TARGET_MODE(x)
{
    return ((x >>> 16) & 15);
}
function FT_LOAD_TARGET(x)
{
    return ((x & 15) << 16);
}

function FT_PAD_FLOOR(x, n)
{
    return x & (~(n-1));
}
function FT_PAD_ROUND(x, n)
{
    return (x + (n >>> 1)) & (~(n-1));
}
function FT_PAD_CEIL(x, n)
{
    return (x + n - 1) & (~(n-1));
}

function FT_PIX_FLOOR(x)
{
    return x & ~63;
}
function FT_PIX_ROUND(x)
{
    return (x + 32) & ~63;
}
function FT_PIX_CEIL(x)
{
    return (x + 63) & ~63;
}

function FT_RoundFix(a)
{
    return (a >= 0) ? (a + 0x8000) & ~0xFFFF : -((-a + 0x8000) & ~0xFFFF);
}
function FT_CeilFix(a)
{
    return (a >= 0) ? (a + 0xFFFF) & ~0xFFFF : -((-a + 0xFFFF) & ~0xFFFF);
}
function FT_FloorFix(a)
{
    return (a >= 0) ?  a & ~0xFFFF : -((-a) & ~0xFFFF);
}

// int64 support
function _FT_MulDiv(a,b,c)
{
    var s = 1;
    var d = 0;

    if ( a < 0 ) { a = -a; s = -1; }
    if ( b < 0 ) { b = -b; s = -s; }
    if ( c < 0 ) { c = -c; s = -s; }

    d = (c > 0 ? parseInt((a * b + (c >>> 1)) / c) : 0x7FFFFFFF);
    return (s > 0) ? d : -d;
}
function _FT_MulFix(a,b)
{
    var s = 1;
    if (a < 0)
    {
        a = -a;
        s = -1;
    }
    if (b < 0)
    {
        b = -b;
        s = -s;
    }

    var c = ((a * b + 0x8000) >>> 16) & 0xFFFFFFFF;
    return ( s > 0 ) ? c : -c;
}
function _FT_DivFix(a,b)
{
    var q;
    var s = 1;
    if ( a < 0 ) { a = -a; s = -1; }
    if ( b < 0 ) { b = -b; s = -s; }

    if (b == 0)
        q = 0x7FFFFFFF;
    else
    {
        q = parseInt(((a * 65536) + (b >>> 1)) / b);
        if (q < 0)
            q += 4294967296;
    }

    return (s < 0 ? -q : q);
}

function Int64()
{
    this.lo = 0;
    this.hi = 0;
}
function ft_multo64(x, y, z)
{
    var lo1 = x & 0x0000FFFF;  var hi1 = x >>> 16;
    var lo2 = y & 0x0000FFFF;  var hi2 = y >>> 16;

    var lo = lo1 * lo2;
    var i1 = lo1 * hi2;
    var i2 = lo2 * hi1;
    var hi = hi1 * hi2;

    /* Check carry overflow of i1 + i2 */
    i1 += i2;
    if (i1 < i2)
        hi += (1 << 16);
    
    hi += (i1 >>> 16);
    i1  = (i1 << 16) & 0xFFFFFFFF;
    if (i1 < 0)
        i1 += 4294967296;

    /* Check carry overflow of i1 + lo */
    lo += i1;

    if (lo >= 4294967296)
        lo = FT_Common.IntToUInt(lo & 0xFFFFFFFF);

    if (lo < i1)
        hi++;

    z.lo = lo;
    z.hi = hi;
}
function ft_div64by32(hi, lo, y)
{
    var q = 0;
    var r = hi;

    if (r >= y)
        return 0x7FFFFFFF;

    var i = 32;
    do
    {
        r = (r << 1) & 0xFFFFFFFF;
        q = (q << 1) & 0xFFFFFFFF;

        r  |= (lo >>> 31);
        if (r < 0)
            r += 4294967296;

        if (r >= y)
        {
            r -= y;
            q |= 1;
        }

        if (q < 0)
            q += 4294967296;

        lo = (lo << 1) & 0xFFFFFFFF;
        if (lo < 0)
            lo += 4294967296;
    } while ( --i );

    return q;
}
function FT_Add64(x, y, z)
{
    var lo = x.lo + y.lo;
    var hi = x.hi + y.hi;
    if (lo < x.lo)
        hi++;

    z.lo = lo;
    z.hi = hi;
}
var temp1 = new Int64();
var temp2 = new Int64();
function FT_MulDiv(a, b, c)
{
    if (a > 2147483647 || b > 2147483647 || c > 2147483647)
        alert("error");

    if (a == 0 || b == c)
        return a;

    var s  = a; a = Math.abs(a);
    s ^= b; b = Math.abs(b);
    s ^= c; c = Math.abs(c);

    if (a <= 46340 && b <= 46340 && c <= 176095 && c > 0)
        a = ((a * b + (c >> 1)) / c) >> 0;
    else if (FT_Common.UintToInt(c) > 0)
    {
        ft_multo64(a >= 0 ? a : a + 4294967296, b >= 0 ? b : b + 4294967296, temp1);

        temp2.hi = 0;
        temp2.lo = (c >>> 1);
        FT_Add64(temp1, temp2, temp1);
        a = ft_div64by32(temp1.hi, temp1.lo, c);
    }
    else
        a = 0x7FFFFFFF;

    return (s < 0 ? -a : a);
}
function FT_MulFix(a, b)
{
    if (a > 2147483647 || b > 2147483647)
    {
		//alert("error");
		a &= 0xFFFFFFFF;
		b &= 0xFFFFFFFF;
	}

    if (a == 0 || b == 0x10000)
        return a;

    var s = a; a = Math.abs(a);
    s ^= b; b = Math.abs(b);

    var ua = a < 0 ? a + 4294967296 : a;
    var ub = b < 0 ? b + 4294967296 : b;

    if (ua <= 2048 && ub <= 1048576)
        ua = (ua * ub + 0x8000) >>> 16;
    else
    {
        var al = ua & 0xFFFF;

        ua = ((ua >>> 16) * ub) + (al * (ub >>> 16)) + ((al * (ub & 0xFFFF) + 0x8000) >>> 16);
    }
    var _l = FT_Common.UintToInt(ua);
    return (s < 0 ? -_l : _l);
}
function FT_DivFix(a, b)
{
    if (a > 2147483647 || b > 2147483647)
    {
        a = (a & 0xFFFFFFFF);
        b = (b & 0xFFFFFFFF);
    }
    
    var q = 0;

    var s = 1;
    if ( a < 0 ) { a = -a; s = -1; }
    if ( b < 0 ) { b = -b; s = -s; }

    if (b == 0)
    {
        q = 0x7FFFFFFF;
    }
    else if ((a >>> 16) == 0)
    {
        q = ((a * 65536 + (b >>> 1)) / b) >> 0;
        if (q < 0)
            q += 4294967296;
    }
    else
    {
        temp1.hi  = (a >>> 16);
        temp1.lo  = (a << 16) & 0xFFFFFFFF;
        if (temp1.lo < 0)
            temp1.lo += 4294967296;

        temp2.hi = 0;
        temp2.lo = (b >>> 1);

        if (temp2.lo < 0)
            temp2.lo += 4294967296;

        FT_Add64(temp1, temp2, temp1);
        q = ft_div64by32(temp1.hi, temp1.lo, b < 0 ? b + 4294967296 : b);
    }

    var _q = (q > 2147483647) ? q - 4294967296 : q;
    return (s < 0) ? -_q : _q;
}

function FT_Sqrt32(x)
{
    var val, root, newroot, mask;

    root = 0;
    mask = 0x40000000;
    val  = x;

    do
    {
        newroot = root + mask;
        if ( newroot <= val )
        {
            val -= newroot;
            root = newroot + mask;
        }

        root >>>= 1;
        mask >>>= 2;

    } while ( mask != 0 );

    return root;
}

function FT_Matrix_Multiply(a, b)
{
    var xx, xy, yx, yy;

    if ( !a || !b )
        return;

    xx = FT_MulFix(a.xx, b.xx) + FT_MulFix(a.xy, b.yx);
    xy = FT_MulFix(a.xx, b.xy) + FT_MulFix(a.xy, b.yy);
    yx = FT_MulFix(a.yx, b.xx) + FT_MulFix(a.yy, b.yx);
    yy = FT_MulFix(a.yx, b.xy) + FT_MulFix(a.yy, b.yy);

    b.xx = xx;  b.xy = xy;
    b.yx = yx;  b.yy = yy;
}

function FT_Matrix_Invert(matrix)
{
    var delta, xx, yy;

    if (!matrix)
        return 6;

    delta = FT_MulFix(matrix.xx, matrix.yy) - FT_MulFix(matrix.xy, matrix.yx);
    if ( !delta )
        return 6;

    matrix.xy = -FT_DivFix(matrix.xy, delta);
    matrix.yx = -FT_DivFix(matrix.yx, delta);

    xx = matrix.xx;
    yy = matrix.yy;

    matrix.xx = FT_DivFix(yy, delta);
    matrix.yy = FT_DivFix(xx, delta);

    return 0;
}

function FT_Matrix_Multiply_Scaled(a, b, scaling)
{
    var xx, xy, yx, yy;
    var val = 0x10000 * scaling;
    if ( !a || !b )
        return;

    xx = FT_MulDiv(a.xx, b.xx, val) + FT_MulDiv(a.xy, b.yx, val);
    xy = FT_MulDiv(a.xx, b.xy, val) + FT_MulDiv(a.xy, b.yy, val);
    yx = FT_MulDiv(a.yx, b.xx, val) + FT_MulDiv(a.yy, b.yx, val);
    yy = FT_MulDiv(a.yx, b.xy, val) + FT_MulDiv(a.yy, b.yy, val);

    b.xx = xx; b.xy = xy;
    b.yx = yx; b.yy = yy;
}

function FT_Vector_Transform_Scaled(vector, matrix, scaling)
{
    var xz, yz;
    var val = 0x10000 * scaling;
    if (!vector || !matrix)
        return;

    xz = FT_MulDiv(vector.x, matrix.xx, val) + FT_MulDiv(vector.y, matrix.xy, val);
    yz = FT_MulDiv(vector.x, matrix.yx, val) + FT_MulDiv(vector.y, matrix.yy, val);

    vector.x = xz;
    vector.y = yz;
}

function FT_SqrtFixed(x)
{
    var root, rem_hi, rem_lo, test_div;
    var count;

    root = 0;
    if (x > 0)
    {
        rem_hi = 0;
        rem_lo = x;
        count  = 24;
        do
        {
            rem_hi   = (rem_hi << 2) | (rem_lo >>> 30);
            rem_lo <<= 2;
            root   <<= 1;
            test_div = (root << 1) + 1;

            if (rem_hi >= test_div)
            {
                rem_hi -= test_div;
                root   += 1;
            }
        } while (--count);
    }

    return root;
}

function ft_corner_orientation(in_x, in_y, out_x, out_y)
{
    var result;
    if ( in_y == 0 )
    {
        if ( in_x >= 0 )
            result = out_y;
        else
            result = -out_y;
    }
    else if ( in_x == 0 )
    {
        if ( in_y >= 0 )
            result = -out_x;
        else
            result = out_x;
    }
    else if ( out_y == 0 )
    {
        if ( out_x >= 0 )
            result = in_y;
        else
            result = -in_y;
    }
    else if ( out_x == 0 )
    {
        if ( out_y >= 0 )
            result = -in_x;
        else
            result =  in_x;
    }
    else
    {
        var delta = in_x * out_y - in_y * out_x;

        if ( delta == 0 )
            result = 0;
        else
            result = 1 - 2 * ( delta < 0 );
    }

    return result;
}

function ft_corner_is_flat(in_x, in_y, out_x, out_y)
{
    var ax = in_x;
    var ay = in_y;

    var d_in, d_out, d_corner;

    if ( ax < 0 )
        ax = -ax;
    if ( ay < 0 )
        ay = -ay;
    d_in = ax + ay;

    ax = out_x;
    if ( ax < 0 )
        ax = -ax;
    ay = out_y;
    if ( ay < 0 )
        ay = -ay;
    d_out = ax + ay;

    ax = out_x + in_x;
    if ( ax < 0 )
        ax = -ax;
    ay = out_y + in_y;
    if ( ay < 0 )
        ay = -ay;
    d_corner = ax + ay;

    return (( d_in + d_out - d_corner ) < ( d_corner >>> 4 )) ? 1 : 0;
}
/******************************************************************************/
// glyph
/******************************************************************************/
// bitmap
function ft_bitmap_glyph_init(glyph, slot)
{
    var library = glyph.library;

    if (slot.format != 1651078259)
        return 18;

    glyph.left = slot.bitmap_left;
    glyph.top  = slot.bitmap_top;

    if ((slot.internal.flags & 1) != 0)
    {
        var d = glyph.bitmap;
        var s = slot.bitmap;

        d.rows = s.rows;
        d.width = s.width;
        d.pitch = s.pitch;
        d.buffer = dublicate_pointer(s.buffer);
        d.num_grays = s.num_grays;
        d.pixel_mode = s.pixel_mode;
        d.palette_mode = s.palette_mode;
        d.palette = s.palette;

        slot.internal.flags &= ~1;
    }
    else
    {
        FT_Bitmap_New(glyph.bitmap);
        return FT_Bitmap_Copy(library, slot.bitmap, glyph.bitmap);
    }
    return 0;
}
function ft_bitmap_glyph_copy(source, target)
{
    target.left = source.left;
    target.top  = source.top;
    return FT_Bitmap_Copy(source.library, source.bitmap, target.bitmap);
}
function ft_bitmap_glyph_done(bitmap_glyph)
{
    FT_Bitmap_Done(bitmap_glyph.library, bitmap_glyph.bitmap);
}
function ft_bitmap_glyph_bbox(glyph, cbox)
{
    cbox.xMin = glyph.left << 6;
    cbox.xMax = cbox.xMin + (glyph.bitmap.width << 6);
    cbox.yMax = glyph.top << 6;
    cbox.yMin = cbox.yMax - (glyph.bitmap.rows << 6);
}

// outline
function ft_outline_glyph_init(glyph, slot)
{
    var source = slot.outline;
    var target = glyph.outline;


    /* check format in glyph slot */
    if (slot.format != 1869968492)
        return 18;

    var error = FT_Outline_New(glyph.library, source.n_points, source.n_contours, glyph.outline);
    if (error != 0)
        return error;

    FT_Outline_Copy(source, target);
    return error;
}
function ft_outline_glyph_done(glyph)
{
    FT_Outline_Done(glyph.library, glyph.outline);
}
function ft_outline_glyph_copy(source, target)
{
    var library = source.library;
    var error = FT_Outline_New(library, source.outline.n_points, source.outline.n_contours, target.outline);
    if (error != 0)
        FT_Outline_Copy(source.outline, target.outline);

    return error;
}
function ft_outline_glyph_transform(glyph, matrix, delta)
{
    if (matrix != null)
        FT_Outline_Transform(glyph.outline, matrix);

    if (delta != null)
        FT_Outline_Translate(glyph.outline, delta.x, delta.y);
}
function ft_outline_glyph_bbox(glyph, bbox)
{
    FT_Outline_Get_CBox(glyph.outline, bbox);
}
function ft_outline_glyph_prepare(glyph, slot)
{
    slot.format         = 1869968492;

    var d = slot.outline;
    var s = glyph.outline;

    d.n_contours = s.n_contours;
    d.n_points = s.n_points;
    d.points = s.points;
    d.tags = s.tags;
    d.contours = s.contours;
    d.flags = s.flags;

    slot.outline.flags &= ~1;
    return 0;
}

function _ft_bitmap_glyph_class()
{
    this.glyph_size = 0; // glyph_type
    this.glyph_format = 1651078259;
    this.glyph_init = ft_bitmap_glyph_init;
    this.glyph_done = ft_bitmap_glyph_done;
    this.glyph_copy = ft_bitmap_glyph_copy;
    this.glyph_transform = null;
    this.glyph_bbox = ft_bitmap_glyph_bbox;
    this.glyph_prepare = null;
}
var ft_bitmap_glyph_class = new _ft_bitmap_glyph_class();
function _ft_outline_glyph_class()
{
    this.glyph_size = 1; // glyph_type
    this.glyph_format = 1869968492;
    this.glyph_init = ft_outline_glyph_init;
    this.glyph_done = ft_outline_glyph_done;
    this.glyph_copy = ft_outline_glyph_copy;
    this.glyph_transform = ft_outline_glyph_transform;
    this.glyph_bbox = ft_outline_glyph_bbox;
    this.glyph_prepare = ft_outline_glyph_prepare;
}
var ft_outline_glyph_class = new _ft_outline_glyph_class();

function FT_GlyphRec()
{
    this.library = null;
    this.clazz = null;
    this.format = 0;
    this.advance = new FT_Vector();
}
function FT_BitmapGlyphRec()
{
    this.library = null;
    this.clazz = null;
    this.format = 0;
    this.advance = new FT_Vector();

    this.left = 0;
    this.top = 0;
    this.bitmap = new FT_Bitmap();
}
function FT_OutlineGlyphRec()
{
    this.library = null;
    this.clazz = null;
    this.format = 0;
    this.advance = new FT_Vector();

    this.outline = new FT_Outline();
}
function ft_new_glyph(library, clazz)
{
    var glyph = null;
    if (clazz.glyph_size == 0)
        glyph = new FT_BitmapGlyphRec();
    else
        glyph = new FT_OutlineGlyphRec();

    glyph.library = library;
    glyph.clazz = clazz;
    glyph.format = clazz.glyph_format;
    return glyph;
}
/******************************************************************************/
// glyphloader
/******************************************************************************/
function FT_CreateVectorArray(array, start, count)
{
    for (var i = start + count - 1; i >= start; i--)
        array[i] = new FT_Vector();
}
function FT_CreateArray(array, start, count)
{
    for (var i = start + count - 1; i >= start; i--)
        array[i] = 0;
}
function FT_CreateArraySubGlyphs(array, start, count)
{
    for (var i = start + count - 1; i >= start; i--)
        array[i] = new FT_SubGlyph();
}
function FT_OutlineCur()
{
    this.n_contours = 0;
    this.n_points = 0;

    this.points = 0;
    this.tags = 0;
    this.contours = 0;

    this.flags = 0;
}
function FT_SubGlyph()
{
    this.index = 0;
    this.flags = 0;
    this.arg1 = 0;
    this.arg2 = 0;
    this.transform = new FT_Matrix();
}
function FT_GlyphLoad()
{
    this.outline = new FT_Outline();
    this.extra_points = null;
    this.extra_points2 = 0;
    this.num_subglyphs = 0;
    this.subglyphs = null;
}
function FT_GlyphLoadCur()
{
    this.outline = new FT_OutlineCur();
    this.extra_points = 0;
    this.extra_points2 = 0;
    this.num_subglyphs = 0;
    this.subglyphs = 0;
}
function FT_GlyphLoader()
{
    this.memory = null;
    this.max_points = 0;
    this.max_contours = 0;
    this.max_subglyphs = 0;
    this.use_extra = 0;

    this.base = new FT_GlyphLoad();
    this.current = new FT_GlyphLoadCur();

    this.other = null;
}

function FT_GlyphLoader_New(memory)
{
    var loader = new FT_GlyphLoader();
    loader.memory = memory;
    return loader;
}
function FT_GlyphLoader_Rewind(loader)
{
    var base    = loader.base;
    var current = loader.current;

    base.outline.n_points   = 0;
    base.outline.n_contours = 0;
    base.num_subglyphs      = 0;

    var _cur = current.outline;
    _cur.n_contours = 0;
    _cur.n_points = 0;
    _cur.points = 0;
    _cur.tags = 0;
    _cur.contours = 0;
    _cur.flags = 0;

    current.extra_points = 0;
    current.extra_points2 = 0;
    current.num_subglyphs = 0;
    current.subglyphs = 0;

    current.extra_points  = 0;
    current.extra_points2 = base.extra_points2;
}
function FT_GlyphLoader_Reset(loader)
{
    var base = loader.base;

    base.outline.points = null;
    base.outline.tags = null;
    base.outline.contours = null;
    base.extra_points = null;
    base.extra_points2 = 0;
    base.subglyphs = null;

    loader.max_points    = 0;
    loader.max_contours  = 0;
    loader.max_subglyphs = 0;

    FT_GlyphLoader_Rewind(loader);
}
function FT_GlyphLoader_Done(loader)
{
    if (loader)
        FT_GlyphLoader_Reset(loader);
}
function FT_GlyphLoader_Adjust_Points(loader)
{
    var base    = loader.base.outline;
    var current = loader.current.outline;

    current.points   = base.n_points;
    current.tags     = base.n_points;
    current.contours = base.n_contours;

    if (loader.use_extra == 1)
    {
        loader.current.extra_points  = base.n_points;
        loader.current.extra_points2 = loader.base.extra_points2 + base.n_points;
    }
}
function FT_GlyphLoader_CreateExtra(loader)
{
    var c = 2*loader.max_points;
    loader.base.extra_points = new Array(c);
    FT_CreateVectorArray(loader.base.extra_points, 0, c);
    loader.use_extra = 1;
    loader.base.extra_points2 = loader.max_points;
    FT_GlyphLoader_Adjust_Points(loader);
    return 0;
}
function FT_GlyphLoader_Adjust_Subglyphs(loader)
{
    loader.current.subglyphs = loader.base.num_subglyphs;
}
function FT_GlyphLoader_CheckPoints(loader, n_points, n_contours)
{
    var base = loader.base.outline;
    var current = loader.current.outline;
    var adjust = 0;

    var new_max = base.n_points + current.n_points + n_points;
    var old_max = loader.max_points;

    if (new_max > old_max)
    {
        new_max = (new_max + 7) & ~7;

        if (new_max > 32767)
            return FT_Error.FT_Err_Array_Too_Large;

        if (null == base.points)
            base.points = new Array(new_max);
        if (null == base.tags)
            base.tags = new Array(new_max);

        FT_CreateVectorArray(base.points, old_max, new_max - old_max);
        FT_CreateArray(base.tags, old_max, new_max - old_max);

        if (1 == loader.use_extra)
        {
            if (null == loader.base.extra_points)
                loader.base.extra_points = new Array(2 * (new_max - old_max));
            FT_CreateVectorArray(loader.base.extra_points, old_max * 2, 2 * (new_max - old_max));
            loader.base.extra_points2 = new_max;
        }

        adjust = 1;
        loader.max_points = new_max;
    }

    /* check contours */
    old_max = loader.max_contours;
    new_max = base.n_contours + current.n_contours + n_contours;
    if (new_max > old_max)
    {
        new_max = (new_max + 4) & ~4;

        if (new_max > 32767)
            return 10;

        if (base.contours == null)
            base.contours = new Array(new_max);
        FT_CreateArray(base.contours, old_max, new_max - old_max);

        adjust = 1;
        loader.max_contours = new_max;
    }

    if (adjust == 1)
        FT_GlyphLoader_Adjust_Points(loader);

    return 0;
}
function FT_GlyphLoader_CheckSubGlyphs(loader, n_subs)
{
    var base    = loader.base;
    var current = loader.current;

    var new_max = base.num_subglyphs + current.num_subglyphs + n_subs;
    var old_max = loader.max_subglyphs;
    if (new_max > old_max)
    {
        new_max = (new_max + 2) & ~2;

        if (null == base.subglyphs)
            base.subglyphs = new Array(new_max);
        FT_CreateArraySubGlyphs(base.subglyphs, old_max, new_max - old_max);
        loader.max_subglyphs = new_max;
        FT_GlyphLoader_Adjust_Subglyphs(loader);
    }
    return 0;
}
function FT_GlyphLoader_Prepare(loader)
{
    var current = loader.current;

    current.outline.n_points   = 0;
    current.outline.n_contours = 0;
    current.num_subglyphs      = 0;

    FT_GlyphLoader_Adjust_Points(loader);
    FT_GlyphLoader_Adjust_Subglyphs(loader);
}
function FT_GlyphLoader_Add(loader)
{
    if ( !loader )
        return;

    var base    = loader.base;
    var current = loader.current;

    var n_curr_contours = current.outline.n_contours;
    var n_base_points   = base.outline.n_points;

    base.outline.n_points = base.outline.n_points + current.outline.n_points;
    base.outline.n_contours = base.outline.n_contours + current.outline.n_contours;

    base.num_subglyphs += current.num_subglyphs;

    var mass = base.outline.contours;
    var start = current.outline.contours;
    for (var n = 0; n < n_curr_contours; n++)
        mass[start+n] = mass[start+n] + n_base_points;

    FT_GlyphLoader_Prepare(loader);
}
function FT_GlyphLoader_CopyPoints(target, source)
{
    var num_points   = source.base.outline.n_points;
    var num_contours = source.base.outline.n_contours;


    var error = FT_GlyphLoader_CheckPoints(target, num_points, num_contours);
    if (error != 0)
    {
        var _out = target.base.outline;
        var _in = source.base.outline;

        var i=0;

        var out_p = _out.points;
        var in_p = _in.points;
        var out_t = _out.tags;
        var in_t = _in.tags;

        for (i=0;i<num_points;i++)
        {
            out_p[i].x = in_p[i].x;
            out_p[i].y = in_p[i].y;

            out_t[i] = in_t[i];
        }

        var out_c = _out.contours;
        var in_c = _in.contours;
        for (i=0;i<num_contours;i++)
            out_c[i] = in_c[i];

        if (1 == target.use_extra && 1 == source.use_extra)
        {
            var out_e = target.base.extra_points;
            var in_e = source.base.extra_points;
            var c = 2 * num_points;
            for (i=0;i<c;i++)
            {
                out_e[i].x = in_e[i].x;
                out_e[i].y = in_e[i].y;
            }
        }

        _out.n_points   = num_points;
        _out.n_contours = num_contours;

        FT_GlyphLoader_Adjust_Points(target);
    }

    return error;
}
function FT_GLYPHLOADER_CHECK_POINTS(_loader,_points,_contours)
{
    if (_points == 0 || (_loader.base.outline.n_points + _loader.current.outline.n_points + _points) <= _loader.max_points)
    {
        if (_contours == 0 || (_loader.base.outline.n_contours + _loader.current.outline.n_contours + _contours) <= _loader.max_contours)
            return 0;
    }
    return FT_GlyphLoader_CheckPoints(_loader,_points,_contours);
}
/******************************************************************************/
// ftmm
/******************************************************************************/
function FT_MM_Axis()
{
    this.name = null;
    this.minimum = 0;
    this.maximum = 0;
}
function FT_Var_Axis()
{
    this.name = null;

    this.minimum = 0;
    this.def = 0;
    this.maximum = 0;

    this.tag = 0;
    this.strid = 0;
}
function FT_Var_Named_Style()
{
    this.coords = null;
    this.strid = 0;
}
function FT_MM_Var()
{
    this.num_axis = 0;
    this.num_designs = 0;
    this.num_namedstyles = 0;
    this.axis = null;
    this.namedstyle = null;

    this.dublicate = function()
    {
        var res = new FT_MM_Var();
        res.num_axis = this.num_axis;
        res.num_designs = this.num_designs;
        res.num_namedstyles = this.num_namedstyles;

        var c = res.num_axis;
        if (c != 0)
        {
            res.axis = new Array(c);
            for (var i=0;i<c;i++)
            {
                res.axis[i] = new FT_Var_Axis();
                var _m = res.axis[i];
                var _s = this.axis[i];

                _m.name = _s.name;
                _m.minimum = _s.minimum;
                _m.def = _s.def;
                _m.maximum = _s.maximum;
                _m.tag = _s.tag;
                _m.strid = _s.strid;
            }
        }
        c = res.num_namedstyles;
        if (c != 0)
        {
            res.namedstyle = new Array(c);
            for (var i=0;i<c;i++)
            {
                res.namedstyle[i] = new FT_Var_Named_Style();
                var _m = res.namedstyle[i];
                var _s = this.namedstyle[i];

                _m.strid = _s.strid;
                if (null != _s.coords)
                    _m.coords = _s.coords.splice(0,0);
            }
        }
    }
}
function FT_Multi_Master()
{
    this.num_axis = 0;
    this.num_designs = 0;
    this.axis = new Array(4);

    for (var i = 0; i < 4; i++)
        this.axis[i] = new FT_MM_Axis();
}
/******************************************************************************/
// ftdriver
/******************************************************************************/
function FT_Driver_Class()
{
    this.flags = 0;
    this.name = "";
    this.version = 0;
    this.requires = 0;

    this.module_interface = null;

    this.init = null;
    this.done = null;
    this.get_interface = null;

    this.face_object_size = 0;
    this.size_object_size = 0;
    this.slot_object_size = 0;

    this.init_face = null;
    this.done_face = null;

    this.init_size = null;
    this.done_size = null;

    this.init_slot = null;
    this.done_slot = null;

    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    this.set_char_sizes = null;
    this.set_pixel_sizes = null;
    //#endif

    this.load_glyph = null;

    this.get_kerning = null;
    this.attach_file = null;
    this.get_advances = null;

    this.request_size = null;
    this.select_size = null;
}
//#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
function ft_stub_set_char_sizes(size, width, height, horz_res, vert_res)
{
    var driver = size.face.driver;
    if (driver.clazz.request_size != null)
    {
        var req = new FT_Size_RequestRec();
        req.type   = 0;
        req.width  = width;
        req.height = height;

        if (horz_res == 0)
            horz_res = vert_res;

        if (vert_res == 0)
            vert_res = horz_res;

        if (horz_res == 0)
            horz_res = vert_res = 72;

        req.horiResolution = horz_res;
        req.vertResolution = vert_res;

        return driver.clazz.request_size(size, req);
    }
    return 0;
}
function  ft_stub_set_pixel_sizes(size, width, height)
{
    var driver = size.face.driver;
    if (driver.clazz.request_size)
    {
        var req = new FT_Size_RequestRec();
        req.type           = 0;
        req.width          = width  << 6;
        req.height         = height << 6;
        req.horiResolution = 0;
        req.vertResolution = 0;
        return driver.clazz.request_size(size, req);
    }
    return 0;
}
//#endif
/******************************************************************************/
// ftvalid
/******************************************************************************/
function FT_ValidatorRec()
{
    this.base = new CPointer();
    this.limit = 0;
    this.level = 0
    this.error = 0
}
/******************************************************************************/
// pshints
/******************************************************************************/
/******************************************************************************/
// tttypes
/******************************************************************************/
function TTC_HeaderRec()
{
    this.tag = 0;
    this.version = 0;
    this.count = 0;
    this.offsets = null;
}
function SFNT_HeaderRec()
{
    this.format_tag = 0;
    this.num_tables = 0;
    this.search_range = 0;
    this.entry_selector = 0;
    this.range_shift = 0;

    this.offset = 0;  /* not in file */
}
function TT_Table()
{
    this.Tag = 0;
    this.CheckSum = 0;
    this.Offset = 0;
    this.Length = 0;
}
function TT_LongMetricsRec()
{
    this.advance = 0;
    this.bearing = 0;
}
function TT_NameEntryRec()
{
    this.platformID = 0;
    this.encodingID = 0;
    this.languageID = 0;
    this.nameID = 0;
    this.stringLength = 0;
    this.stringOffset = 0;
    this.string = null;
}
function TT_NameTableRec()
{
    this.format = 0;
    this.numNameRecords = 0;
    this.storageOffset = 0;
    this.names = null;
    this.stream = null;
}
function TT_GaspRange()
{
    this.maxPPEM = 0;
    this.gaspFlag = 0;
}
function TT_Gasp()
{
    this.version = 0;
    this.numRanges = 0;
    this.gaspRanges = null;
}
//#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
function TT_HdmxEntryRec()
{
    this.ppem = 0;
    this.max_width = 0;
    this.widths = null;
}
function TT_HdmxRec()
{
    this.version = 0;
    this.num_records = 0;
    this.records = null;
}
function TT_Kern0_PairRec()
{
    this.left = 0;
    this.right = 0;
    this.value = 0;
}
//#endif
function TT_SBit_MetricsRec()
{
    this.height = 0;
    this.width = 0;

    this.horiBearingX = 0;
    this.horiBearingY = 0;
    this.horiAdvance = 0;

    this.vertBearingX = 0;
    this.vertBearingY = 0;
    this.vertAdvance = 0;
}
function TT_SBit_Small_Metrics()
{
    this.height = 0;
    this.width = 0;

    this.bearingX = 0;
    this.bearingY = 0;
    this.advance = 0;
}
function TT_SBit_LineMetricsRec()
{
    this.ascender = 0;
    this.descender = 0;
    this.max_width = 0;
    this.caret_slope_numerator = 0;
    this.caret_slope_denominator = 0;
    this.caret_offset = 0;
    this.min_origin_SB = 0;
    this.min_advance_SB = 0;
    this.max_before_BL = 0;
    this.min_after_BL = 0;

    this.pad1 = 0;
    this.pad2 = 0;
}
function TT_SBit_RangeRec()
{
    this.first_glyph = 0;
    this.last_glyph = 0;

    this.index_format = 0;
    this.image_format = 0;
    this.image_offset = 0;

    this.image_size = 0;
    this.metrics = new TT_SBit_MetricsRec();
    this.num_glyphs = 0;

    this.glyph_offsets = null;
    this.glyph_codes = null;

    this.table_offset = 0;
}
function TT_SBit_StrikeRec()
{
    this.num_ranges = 0;
    this.sbit_ranges = null;
    this.ranges_offset = 0;

    this.color_ref = 0;

    this.hori = new TT_SBit_LineMetricsRec();
    this.vert = new TT_SBit_LineMetricsRec();

    this.start_glyph = 0;
    this.end_glyph = 0;

    this.x_ppem = 0;
    this.y_ppem = 0;

    this.bit_depth = 0;
    this.flags = 0;
}
function TT_SBit_ComponentRec()
{
    this.glyph_code = 0;
    this.x_offset = 0;
    this.y_offset = 0;
}
function TT_SBit_ScaleRec()
{
    this.hori = new TT_SBit_LineMetricsRec();
    this.vert = new TT_SBit_LineMetricsRec();

    this.x_ppem = 0;
    this.y_ppem = 0;

    this.x_ppem_substitute = 0;
    this.y_ppem_substitute = 0;
}
function TT_Post_20Rec()
{
    this.num_glyphs = 0;
    this.num_names = 0;
    this.glyph_indices = null;
    this.glyph_names = null;
}
function TT_Post_25Rec()
{
    this.num_glyphs = 0;
    this.offsets = null;
}
function TT_Post_NamesRec()
{
    this.loaded = false;
    this.format = null;
}
//#ifdef TT_CONFIG_OPTION_BDF
function TT_BDFRec()
{
    this.table = null;
    this.table_end = 0;
    this.strings = null;
    this.strings_size = 0;
    this.num_strikes = 0;
    this.loaded = 0;
}
//#endif
function TT_GlyphZoneRec()
{
    this.memory = null;
    this.max_points = 0;
    this.max_contours = 0;
    this.n_points = 0;    /* number of points in zone    */
    this.n_contours = 0;  /* number of contours          */

    this.org = null;         /* original point coordinates  */
    this.cur = null;         /* current point coordinates   */
    this.orus = null;        /* original (unscaled) point coordinates */

    this.tags = null;        /* current touch flags         */
    this.contours = null;    /* contour end points          */

    this._offset_org = 0;
    this._offset_cur = 0;
    this._offset_orus = 0;
    this._offset_tags = 0;
    this._offset_contours = 0;

    this.first_point = 0; /* offset of first (#0) point  */
}
TT_GlyphZoneRec.prototype =
{
    Clear : function()
    {
        this.memory = null;
        this.max_points = 0;
        this.max_contours = 0;
        this.n_points = 0;
        this.n_contours = 0;

        this.org = null;
        this.cur = null;
        this.orus = null;

        this.tags = null;
        this.contours = null;

        this._offset_org = 0;
        this._offset_cur = 0;
        this._offset_orus = 0;
        this._offset_tags = 0;
        this._offset_contours = 0;

        this.first_point = 0;
    },

    Copy : function(src)
    {
        this.memory = src.memory;
        this.max_points = src.max_points;
        this.max_contours = src.max_contours;
        this.n_points = src.n_points;
        this.n_contours = src.n_contours;

        this.org = src.org;
        this.cur = src.cur;
        this.orus = src.orus;

        this.tags = src.tags;
        this.contours = src.contours;

        this._offset_org = src._offset_org;
        this._offset_cur = src._offset_cur;
        this._offset_orus = src._offset_orus;
        this._offset_tags = src._offset_tags;
        this._offset_contours = src._offset_contours;

        this.first_point = src.first_point;
    }
}

function TT_LoaderRec()
{
    this.face = null;
    this.size = null;
    this.glyph = null;
    this.gloader = null;

    this.load_flags = 0;
    this.glyph_index = 0;

    this.stream = null;
    this.byte_len = 0;

    this.n_contours = 0;
    this.bbox = new FT_BBox();
    this.left_bearing = 0;
    this.advance = 0;
    this.linear = 0;
    this.linear_def = 0;
    this.preserve_pps = 0;
    this.pp1 = new FT_Vector();
    this.pp2 = new FT_Vector();

    this.glyf_offset = 0;

    this.base = new TT_GlyphZoneRec();
    this.zone = new TT_GlyphZoneRec();

    this.exec = null;
    this.instructions = null;
    this.ins_pos = 0;

    this.other = null;

    this.top_bearing = 0;
    this.vadvance = 0;
    this.pp3 = new FT_Vector();
    this.pp4 = new FT_Vector();

    this.cursor = 0;
    this.limit = 0;

    this.Clear = function()
    {
        this.load_flags = 0;
        this.glyph_index = 0;

        this.stream = null;
        this.byte_len = 0;

        this.n_contours = 0;
        this.bbox.xMin = 0;
        this.bbox.yMin = 0;
        this.bbox.xMax = 0;
        this.bbox.yMax = 0;
        this.left_bearing = 0;
        this.advance = 0;
        this.linear = 0;
        this.linear_def = 0;
        this.preserve_pps = 0;
        this.pp1.x = 0;
        this.pp1.y = 0;
        this.pp2.x = 0;
        this.pp2.y = 0;

        this.glyf_offset = 0;

        this.exec = null;
        this.instructions = null;
        this.ins_pos = 0;

        this.other = null;

        this.top_bearing = 0;
        this.vadvance = 0;
        this.pp3.x = 0;
        this.pp3.y = 0;
        this.pp4.x = 0;
        this.pp4.y = 0;

        this.cursor = 0;
        this.limit = 0;

        this.gloader = null;
    }
}
/******************************************************************************/
// tttables
/******************************************************************************/
function TT_Header()
{
    this.Table_Version = 0;
    this.Font_Revision = 0;

    this.CheckSum_Adjust = 0;
    this.Magic_Number = 0;

    this.Flags = 0;
    this.Units_Per_EM = 0;

    this.Created1 = 0;
    this.Created2 = 0;
    this.Modified1 = 0;
    this.Modified2 = 0;

    this.xMin = 0;
    this.yMin = 0;
    this.xMax = 0;
    this.yMax = 0;

    this.Mac_Style = 0;
    this.Lowest_Rec_PPEM = 0;

    this.Font_Direction = 0;
    this.Index_To_Loc_Format = 0;
    this.Glyph_Data_Format = 0;
}
function TT_HoriHeader()
{
    this.Version = 0;
    this.Ascender = 0;
    this.Descender = 0;
    this.Line_Gap = 0;

    this.advance_Width_Max = 0;

    this.min_Left_Side_Bearing = 0;
    this.min_Right_Side_Bearing = 0;
    this.xMax_Extent = 0;
    this.caret_Slope_Rise = 0;
    this.caret_Slope_Run = 0;
    this.caret_Offset = 0;

    this.Reserved1 = 0;
    this.Reserved2 = 0;
    this.Reserved3 = 0;
    this.Reserved4 = 0;

    this.metric_Data_Format = 0;
    this.number_Of_HMetrics = 0;

    this.long_metrics = null;
    this.short_metrics = null;
}
function TT_VertHeader()
{
    this.Version = 0;
    this.Ascender = 0;
    this.Descender = 0;
    this.Line_Gap = 0;

    this.advance_Height_Max = 0;

    this.min_Top_Side_Bearing = 0;
    this.min_Bottom_Side_Bearing = 0;
    this.yMax_Extent = 0;
    this.caret_Slope_Rise = 0;
    this.caret_Slope_Run = 0;
    this.caret_Offset = 0;

    this.Reserved1 = 0;
    this.Reserved2 = 0;
    this.Reserved3 = 0;
    this.Reserved4 = 0;

    this.metric_Data_Format = 0;
    this.number_Of_VMetrics = 0;

    this.long_metrics = null;
    this.short_metrics = null;
}
function TT_OS2()
{
    this.version = 0;
    this.xAvgCharWidth = 0;
    this.usWeightClass = 0;
    this.usWidthClass = 0;
    this.fsType = 0;
    this.ySubscriptXSize = 0;
    this.ySubscriptYSize = 0;
    this.ySubscriptXOffset = 0;
    this.ySubscriptYOffset = 0;
    this.ySuperscriptXSize = 0;
    this.ySuperscriptYSize = 0;
    this.ySuperscriptXOffset = 0;
    this.ySuperscriptYOffset = 0;
    this.yStrikeoutSize = 0;
    this.yStrikeoutPosition = 0;
    this.sFamilyClass = 0;

    this.panose = new Array(10);

    this.ulUnicodeRange1 = 0;        /* Bits 0-31   */
    this.ulUnicodeRange2 = 0;        /* Bits 32-63  */
    this.ulUnicodeRange3 = 0;        /* Bits 64-95  */
    this.ulUnicodeRange4 = 0;        /* Bits 96-127 */

    this.achVendID = new Array(4);

    this.fsSelection = 0;
    this.usFirstCharIndex = 0;
    this.usLastCharIndex = 0;
    this.sTypoAscender = 0;
    this.sTypoDescender = 0;
    this.sTypoLineGap = 0;
    this.usWinAscent = 0;
    this.usWinDescent = 0;

    /* only version 1 tables: */
    this.ulCodePageRange1 = 0;       /* Bits 0-31   */
    this.ulCodePageRange2 = 0;       /* Bits 32-63  */

    /* only version 2 tables: */
    this.sxHeight = 0;
    this.sCapHeight = 0;
    this.usDefaultChar = 0;
    this.usBreakChar = 0;
    this.usMaxContext = 0;
}
function TT_Postscript()
{
    this.FormatType = 0;
    this.italicAngle = 0;
    this.underlinePosition = 0;
    this.underlineThickness = 0;
    this.isFixedPitch = 0;
    this.minMemType42 = 0;
    this.maxMemType42 = 0;
    this.minMemType1 = 0;
    this.maxMemType1 = 0;
}
function TT_PCLT()
{
    this.Version = 0;
    this.FontNumber = 0;
    this.Pitch = 0;
    this.xHeight = 0;
    this.Style = 0;
    this.TypeFamily = 0;
    this.CapHeight = 0;
    this.SymbolSet = 0;
    this.TypeFace = "";
    this.CharacterComplement = "";
    this.FileName = "";
    this.StrokeWeight = 0;
    this.WidthType = 0;
    this.SerifStyle = 0;
    this.Reserved = 0;
}
function TT_MaxProfile()
{
    this.version = 0;
    this.numGlyphs = 0;
    this.maxPoints = 0;
    this.maxContours = 0;
    this.maxCompositePoints = 0;
    this.maxCompositeContours = 0;
    this.maxZones = 0;
    this.maxTwilightPoints = 0;
    this.maxStorage = 0;
    this.maxFunctionDefs = 0;
    this.maxInstructionDefs = 0;
    this.maxStackElements = 0;
    this.maxSizeOfInstructions = 0;
    this.maxComponentElements = 0;
    this.maxComponentDepth = 0;
}
function FT_Get_Sfnt_Table(face, tag)
{
    var table = null;
    if (face && ((face.face_flags & 8) != 0))
    {
        var service = FT_FACE_FIND_SERVICE( face, "sfnt-table");
        if (service != null)
            table = service.get_table(face, tag);
    }
    return table;
}
function FT_Load_Sfnt_Table(face, tag, offset, buffer, length)
{
    if (face == null || ((face.face_flags & 8) == 0))
        return 35;

    var service = FT_FACE_FIND_SERVICE(face, FT_SERVICE_ID_SFNT_TABLE);
    if (service == null)
        return 7;

    return service.load_table(face, tag, offset, buffer, length);
}
function FT_Sfnt_Table_Info(face, table_index, tag, length)
{
    if (face == null || ((face.face_flags & 8) == 0))
        return 35;

    var service = FT_FACE_FIND_SERVICE(face, FT_SERVICE_ID_SFNT_TABLE);
    if (service == null)
        return 7;

    return service.table_info(face, table_index, tag);
}
function FT_Get_CMap_Language_ID(charmap)
{
    if (charmap == null || charmap.face == null)
        return 0;

    var service = FT_FACE_FIND_SERVICE(charmap.face, FT_SERVICE_ID_TT_CMAP);
    if (service == null)
        return 0;
    var cmap_info = new TT_CMapInfo();
    if (0 != service.get_cmap_info( charmap, cmap_info))
        return 0;
    return cmap_info.language;
}
/******************************************************************************/
// ftimage
/******************************************************************************/
function FT_Vector()
{
    this.x = 0;
    this.y = 0;
}
function dublicate_vector(v)
{
    var _v = new FT_Vector();
    _v.x = v.x;
    _v.y = v.y;
    return _v;
}
function copy_vector(dst, src)
{
    dst.x = src.x;
    dst.y = src.y;
}
function FT_BBox()
{
    this.xMin = 0;
    this.yMin = 0;
    this.xMax = 0;
    this.yMax = 0;
}
function dublicate_bbox(v)
{
    var _v = new FT_BBox();
    _v.xMin = v.xMin;
    _v.yMin = v.yMin;
    _v.xMax = v.xMax;
    _v.yMax = v.yMax;
    return _v;
}
function FT_Bitmap()
{
    this.rows = 0;
    this.width = 0;
    this.pitch = 0;
    this.buffer = null;
    this.num_grays = 0;
    this.pixel_mode = 0;
    this.palette_mode = 0;
    this.palette = null;
}
function DoNullBitmap(im)
{
    im.rows = 0;
    im.width = 0;
    im.pitch = 0;
    im.buffer = null;
    im.num_grays = 0;
    im.pixel_mode = 0;
    im.palette_mode = 0;
    im.palette = null;
}
function FT_Outline()
{
    this.n_contours = 0;
    this.n_points = 0;

    this.points = null;
    this.tags = null;
    this.contours = null;

    this.flags = 0;
}
function EquatingOutline(d, s)
{
    d.n_contours = s.n_contours;
    d.n_points = s.n_points;
    d.points = s.points;
    d.tags = s.tags;
    d.contours = s.contours;
    d.flags = s.flags;
}
function FT_Span()
{
    this.x = 0;
    this.len = 0;
    this.coverage = 0;
}
function FT_Raster_Params()
{
    this.target = null;
    this.source = null;
    this.flags = 0;
    this.gray_spans = null;
    this.black_spans = null;
    this.bit_test = null;
    this.bit_set = null;
    this.user = null;
    this.clip_box = new FT_BBox();
}
/******************************************************************************/
// ftbitmap
/******************************************************************************/
function FT_Bitmap_New(bitmap)
{
    DoNullBitmap(bitmap);
}
function FT_Bitmap_Copy(library, source, target)
{
    var pitch  = source.pitch;
    if (source == target)
        return 0;

    if (source.buffer == null)
    {
        target.rows = source.rows;
        target.width = source.width;
        target.pitch = source.pitch;
        target.buffer = source.buffer;
        target.num_grays = source.num_grays;
        target.pixel_mode = source.pixel_mode;
        target.palette_mode = source.palette_mode;
        target.palette = source.palette;

        return 0;
    }

    if (pitch < 0)
        pitch = -pitch;
    var size = (pitch * source.rows);

    if (target.buffer != null)
    {
        var target_pitch = target.pitch;

        if (target_pitch < 0 )
            target_pitch = -target_pitch;
        var target_size = (target_pitch * target.rows);

        if (target_size != size)
        {
            target.buffer = null;
            target.buffer = g_memory.Alloc(size);//new Array(size);
        }
    }
    else
        target.buffer = g_memory.Alloc(size);//new Array(size);

    var s = source.buffer;
    var d = target.buffer;
    for (var i=0;i<size;i++)
        d[i]=s[i];

    return 0;
}
function FT_Bitmap_Done(library, bitmap)
{
    DoNullBitmap(bitmap);
    return 0;
}
/******************************************************************************/
// ftsnames
/******************************************************************************/
function FT_SfntName()
{
    this.platform_id = 0;
    this.encoding_id = 0;
    this.language_id = 0;
    this.name_id = 0;

    this.string = "";
    this.string_len = 0;
}
function FT_Get_Sfnt_Name_Count(face)
{
    return (face != null && (face.face_flags & 8) != 0) ? face.num_names : 0;
}
function FT_Get_Sfnt_Name(face, idx, aname)
{
    var error = 6;
    if (face != null && (face.face_flags & 8) != 0)
    {
        if (idx < face.num_names)
        {
            var entry = face.name_table.names[idx];

            if (entry.stringLength > 0 && entry.string == null)
            {
                var stream = face.stream;
                error = stream.Seek(entry.stringOffset);
                entry.string = stream.ReadString1(entry.stringLength);
                error = FT_Error;

                if (0 != error)
                {
                    entry.string = null;
                    entry.stringLength = 0;
                }
            }

            aname.platform_id = entry.platformID;
            aname.encoding_id = entry.encodingID;
            aname.language_id = entry.languageID;
            aname.name_id     = entry.nameID;
            aname.string      = entry.string;
            aname.string_len  = entry.stringLength;
        }
    }
    return 0;
}
/******************************************************************************/
// ftincrem
/******************************************************************************/
function FT_Incremental_MetricsRec()
{
    this.bearing_x = 0;
    this.bearing_y = 0;
    this.advance = 0;
    this.advance_v = 0;
}
function FT_Incremental_FuncsRec()
{
    this.get_glyph_data = null;
    this.free_glyph_data = null;
    this.get_glyph_metrics = null;
}
function FT_Incremental_Interface()
{
    this.funcs = null;
    this.object = null;
}
/******************************************************************************/
// fttypes
/******************************************************************************/
function FT_Matrix()
{
    this.xx = 0;
    this.xy = 0;
    this.yx = 0;
    this.yy = 0;
}
function dublicate_matrix(m)
{
    var _m = new FT_Matrix();
    _m.xx = m.xx;
    _m.xy = m.xy;
    _m.yx = m.yx;
    _m.yy = m.yy;
    return _m;
}
function FT_Data()
{
    this.pointer = null;
    this.length = 0;
}
function FT_Generic()
{
    this.data = null;
    this.finalizer = null;
}
function FT_Glyph_Metrics()
{
    this.width = 0;
    this.height = 0;

    this.horiBearingX = 0;
    this.horiBearingY = 0;
    this.horiAdvance = 0;

    this.vertBearingX = 0;
    this.vertBearingY = 0;
    this.vertAdvance = 0;

}
function FT_Bitmap_Size()
{
    this.height = 0;
    this.width = 0;

    this.size = 0;

    this.x_ppem = 0;
    this.y_ppem = 0;
}
function FT_CharMapRec()
{
    this.face = null;
    this.encoding = 0;
    this.platform_id = 0;
    this.encoding_id = 0;
}
function FT_Face()
{
    this.num_faces = 0;
    this.face_index = 0;

    this.face_flags = 0;
    this.style_flags = 0;

    this.num_glyphs = 0;

    this.family_name = "";
    this.style_name = "";

    this.num_fixed_sizes = 0;
    this.available_sizes = [];

    this.num_charmaps = 0;
    this.charmaps = [];

    this.generic = new FT_Generic();

    /*# The following member variables (down to `underline_thickness') */
    /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size    */
    /*# for bitmap fonts.                                              */
    this.bbox = new FT_BBox();

    this.units_per_EM = 0;
    this.ascender = 0;
    this.descender = 0;
    this.height = 0;

    this.max_advance_width = 0;
    this.max_advance_height = 0;

    this.underline_position = 0;
    this.underline_thickness = 0;

    this.glyph = null;
    this.size = null;
    this.charmap = null;

    /*@private begin */
    this.driver = null;
    this.memory = null;
    this.stream = null;

    this.sizes_list = [];

    this.autohint = [];
    this.extensions = null;

    this.internal = null;
    /*@private end */
}
function FT_Size_Metrics()
{
    this.x_ppem = 0;
    this.y_ppem = 0;

    this.x_scale = 0;
    this.y_scale = 0;

    this.ascender = 0;
    this.descender = 0;
    this.height = 0;
    this.max_advance = 0;
}
FT_Size_Metrics.prototype =
{
    Copy : function(src)
    {
        this.x_ppem = src.x_ppem;
        this.y_ppem = src.y_ppem;

        this.x_scale = src.x_scale;
        this.y_scale = src.y_scale;

        this.ascender = src.ascender;
        this.descender = src.descender;
        this.height = src.height;
        this.max_advance = src.max_advance;
    }
};

function FT_Size()
{
    this.face = null;
    this.generic = null;
    this.metrics = new FT_Size_Metrics();
    this.internal = null;
}
function FT_GlyphSlot()
{
    this.library = null;
    this.face = null;
    this.next = null;
    this.reserved = 0;       /* retained for binary compatibility */
    this.generic = null;

    this.metrics = new FT_Glyph_Metrics();
    this.linearHoriAdvance = 0;
    this.linearVertAdvance = 0;
    this.advance = new FT_Vector();

    this.format = 0;

    this.bitmap = new FT_Bitmap();
    this.bitmap_left = 0;
    this.bitmap_top = 0;

    this.outline = new FT_Outline();

    this.num_subglyphs = 0;
    this.subglyphs = [];

    this.control_data = null;
    this.control_len = 0;

    this.lsb_delta = 0;
    this.rsb_delta = 0;

    this.other = null;

    this.internal = null;

    this.base_root = null;
}
function FT_Open_Args()
{
    this.flags = null;
    this.memory_base = null;
    this.memory_size = null;
    this.pathname = "";
    this.stream = null;
    this.driver = null;
    this.num_params = 0;
    this.params = null;
}
function FT_Size_RequestRec()
{
    this.type = 0;
    this.width = 0;
    this.height = 0;
    this.horiResolution = 0;
    this.vertResolution = 0;
}
function FT_CMapRec()
{
    this.charmap = new FT_CharMapRec();
    this.clazz = null;

    this.type = 0;
}
function __FT_CMapRec(val)
{
    switch (val.type)
    {
        case 0:
            return val;
        case 1:
            return val.cmap;
        case 2:
        case 3:
        case 4:
        case 5:
            return val.cmap.cmap;
        default:
            break;
    }
    return val;
}
function __FT_TTCMapRec(val)
{
    switch (val.type)
    {
        case 0:
            return null;
        case 1:
            return val;
        case 2:
        case 3:
        case 4:
        case 5:
            return val.cmap;
        default:
            break;
    }
    return null;
}
function __FT_CharmapRec(val)
{
    switch (val.type)
    {
        case 0:
            return val.charmap;
        case 1:
            return val.cmap.charmap;
        case 2:
        case 3:
        case 4:
        case 5:
            return val.cmap.cmap.charmap;
        default:
            break;
    }
    return val.charmap;
}
function FT_CMap_ClassRec()
{
    this.size = 0;
    this.init = null;
    this.done = null;
    this.char_index = null;
    this.char_next = null;

    this.char_var_index = null;
    this.char_var_default = null;
    this.variant_list = null;
    this.charvariant_list = null;
    this.variantchar_list = null;
}
function create_cmap_class_rec(size_,init_,done_,char_index_,char_next_,var_index_,var_default_,
                               var_list_,char_var_list_, var_char_list_)
{
    var c = new FT_CMap_ClassRec();
    c.size = size_;
    c.init = init_;
    c.done = done_;
    c.char_index = char_index_;
    c.char_next = char_next_;

    c.char_var_index = var_index_;
    c.char_var_default = var_default_;
    c.variant_list = var_list_;
    c.charvariant_list = char_var_list_;
    c.variantchar_list = var_char_list_;
    return c;
}
function FT_Face_Internal()
{
    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    this.reserved1 = 0;
    this.reserved2 = 0;
    //#endif
    this.transform_matrix = new FT_Matrix();
    this.transform_delta = new FT_Vector();
    this.transform_flags = 0;

    this.services = new FT_ServiceCache();

    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
    this.incremental_interface = null;
    //#endif

    this.ignore_unpatented_hinter = false;
    this.refcount = 0;
}
function FT_Slot_Internal()
{
    this.loader = null;
    this.flags = 0;
    this.glyph_transformed = false;
    this.glyph_matrix = new FT_Matrix();
    this.glyph_delta = new FT_Vector();
    this.glyph_hints = null;
}
function FT_Module()
{
    this.clazz = null;      // FT_Module_Class
    this.library = null;    // FT_Library
    this.memory = null;     // FT_Memory
    this.generic = null;    // FT_Generic
}
function FT_Driver()
{
    this.root = new FT_Module();
    this.clazz = new FT_Driver_Class();
    this.faces_list = [];
    this.extensions = null;
    this.glyph_loader = null;
}
function FT_Module_Class()
{
    this.flags = 0;
    this.name = "";
    this.version = 0;
    this.requires = 0;

    this.module_interface = null;

    this.init = null;
    this.done = null;
    this.get_interface = null;
}
/******************************************************************************/
// outline
/******************************************************************************/
function FT_Outline_New(library, numPoints, numContours, anoutline)
{
    if (library == null)
        return 33;

    return FT_Outline_New_Internal(library.Memory, numPoints, numContours, anoutline);
}
function FT_Outline_New_Internal(memory, numPoints, numContours, anoutline)
{
    if (null == anoutline || null == memory)
        return 6;

    var _points = new Array(numPoints);
    for (var i = 0; i < numPoints; i++)
        _points[i] = new FT_Vector();

    var _tags = new Array(numPoints);
    for (var i = 0; i < numPoints; i++)
        _tags[i] = 0;
    var _contours = new Array(numContours);
    for (var i = 0; i < numContours; i++)
        _contours[i] = 0;

    anoutline.points = _points;
    anoutline.tags = _tags;
    anoutline.contours = _contours;

    anoutline.n_points    = numPoints & 0xFFFF;
    anoutline.n_contours  = numContours & 0xFFFF;
    anoutline.flags      |= 1;

    return 0;
}
function FT_Outline_Check(outline)
{
    if (outline != null)
    {
        var n_points   = outline.n_points;
        var n_contours = outline.n_contours;
        var end0, end;
        var n;

        if (n_points == 0 && n_contours == 0)
            return 0;

        if (n_points <= 0 || n_contours <= 0)
            return 6;

        end0 = end = -1;
        var _c = outline.contours;
        for (n = 0; n < n_contours; n++)
        {
            end = _c[n];
            if (end <= end0 || end >= n_points)
                return 6;
            end0 = end;
        }

        if ( end != n_points - 1 )
            return 6;

        return 0;
    }
    return 6;
}
function FT_Outline_Copy(source, target)
{
    if (null == source || null == target || source.n_points != target.n_points || source.n_contours != target.n_contours)
        return 6;

    if (source == target)
        return 0;

    var n_p = source.n_points;
    var s_p = source.points;
    var d_p = target.points;
    var s_t = source.tags;
    var t_t = target.tags;
    for (var i = 0; i < n_p; i++)
    {
        d_p[i].x = s_p[i].x;
        d_p[i].y = s_p[i].y;

        t_t[i] = s_t[i];
    }

    var n_c = source.n_contours;
    var s_c = source.contours;
    var t_c = target.contours;
    for (var i = 0; i < source.n_contours; i++)
    {
        t_c[i] = s_c[i];
    }

    var is_owner = target.flags & 1;
    target.flags = source.flags;

    target.flags &= ~1;
    target.flags |= is_owner;

    return 0;
}
function FT_Outline_Done_Internal(memory, outline)
{
    if (memory != null && outline != null)
    {
        if (outline.flags & 1)
        {
            outline.points = null;
            outline.tags = null;
            outline.contours = null;
        }

        outline.n_points = 0;
        outline.n_contours = 0;
        outline.flags = 0;

        return 0;
    }
    else
        return 6;
}
function FT_Outline_Done(library, outline)
{
    if (library == null)
        return 33;

    return FT_Outline_Done_Internal(library.memory, outline);
}
/******************************************************************************/
// obj
/******************************************************************************/
function find_unicode_charmap(face)
{
    if (null == face || null == face.charmaps)
        return 38;

    var count = Math.min(face.charmaps.length, face.num_charmaps);
    if (0 == count)
        return 38;

    var cur = count - 1;
    for ( ; cur >= 0; cur--)
    {
        var cmap = __FT_CharmapRec(face.charmaps[cur]);
        if (cmap.encoding == 1970170211)
        {
            if ((cmap.platform_id == 3 && cmap.encoding_id == 10) ||
                (cmap.platform_id == 0 && cmap.encoding_id == 4))
            {
                //#ifdef FT_MAX_CHARMAP_CACHEABLE
                if (cur > 15)
                {
                    continue;
                }
                //#endif
                face.charmap = face.charmaps[cur];
                return 0;
            }
        }
    }
    cur = count - 1;
    for ( ; cur >= 0; cur--)
    {
        var cmap = __FT_CharmapRec(face.charmaps[cur]);
        if (cmap.encoding == 1970170211)
        {
            //#ifdef FT_MAX_CHARMAP_CACHEABLE
            if (cur > 15)
            {
                continue;
            }
            //#endif
            face.charmap = face.charmaps[cur];
            return 0;
        }
    }
    return 38;
}
function ft_glyphslot_init(slot)
{
    var driver = slot.face.driver;
    slot.library = driver.library;
    slot.internal = new FT_Slot_Internal();

    var error = 0;
    if ((driver.flags & 512) == 0)
        slot.internal.loader = FT_GlyphLoader_New(driver.memory);

    if (driver.clazz.init_slot)
        error = driver.clazz.init_slot(slot);
    return error;
}
function ft_glyphslot_free_bitmap(slot)
{
    if (slot.internal != null && (slot.internal.flags & 1) != 0)
    {
        slot.bitmap.buffer = null;
        slot.internal.flags &= ~1;
    }
    else
    {
        slot.bitmap.buffer = null;
    }
}
function ft_glyphslot_set_bitmap(slot, buffer)
{
    ft_glyphslot_free_bitmap(slot);
    slot.bitmap.buffer = buffer;
}
function ft_glyphslot_alloc_bitmap(slot, size)
{
    if ((slot.internal.flags & 1) != 0)
        slot.bitmap.buffer = null;
    else
        slot.internal.flags |= 1;

    slot.bitmap.buffer = g_memory.Alloc(size);
    return 0;
}
function ft_glyphslot_clear(slot)
{
    ft_glyphslot_free_bitmap(slot);

    var metrics = slot.metrics;
    metrics.width = 0;
    metrics.height = 0;
    metrics.horiBearingX = 0;
    metrics.horiBearingY = 0;
    metrics.horiAdvance = 0;
    metrics.vertBearingX = 0;
    metrics.vertBearingY = 0;
    metrics.vertAdvance = 0;

    var outl = slot.outline;
    outl.n_contours = 0;
    outl.n_points = 0;
    outl.contours = null;
    outl.points = null;
    outl.tags = null;
    outl.flags = 0;

    slot.bitmap.width      = 0;
    slot.bitmap.rows       = 0;
    slot.bitmap.pitch      = 0;
    slot.bitmap.pixel_mode = 0;

    slot.bitmap_left   = 0;
    slot.bitmap_top    = 0;
    slot.num_subglyphs = 0;
    slot.subglyphs     = 0;
    slot.control_data  = 0;
    slot.control_len   = 0;
    slot.other         = 0;
    slot.format        = 0;

    slot.linearHoriAdvance = 0;
    slot.linearVertAdvance = 0;
    slot.lsb_delta         = 0;
    slot.rsb_delta         = 0;
}
function ft_glyphslot_done(slot)
{
    var clazz = slot.face.driver.clazz;
    if (clazz.done_slot != null)
        clazz.done_slot(slot);

    ft_glyphslot_free_bitmap(slot);
    slot.internal = null;
}
function ft_glyphslot_grid_fit_metrics(slot,  vertical)
{
    var metrics = slot.metrics;
    var right, bottom;

    if (1 ==  vertical)
    {
        metrics.horiBearingX = FT_PIX_FLOOR(metrics.horiBearingX);
        metrics.horiBearingY = FT_PIX_CEIL (metrics.horiBearingY);

        right  = FT_PIX_CEIL(metrics.vertBearingX + metrics.width);
        bottom = FT_PIX_CEIL(metrics.vertBearingY + metrics.height);

        metrics.vertBearingX = FT_PIX_FLOOR(metrics.vertBearingX);
        metrics.vertBearingY = FT_PIX_FLOOR(metrics.vertBearingY);

        metrics.width  = right - metrics.vertBearingX;
        metrics.height = bottom - metrics.vertBearingY;
    }
    else
    {
        metrics.vertBearingX = FT_PIX_FLOOR(metrics.vertBearingX);
        metrics.vertBearingY = FT_PIX_FLOOR(metrics.vertBearingY);

        right  = FT_PIX_CEIL (metrics.horiBearingX + metrics.width);
        bottom = FT_PIX_FLOOR(metrics.horiBearingY - metrics.height);

        metrics.horiBearingX = FT_PIX_FLOOR(metrics.horiBearingX);
        metrics.horiBearingY = FT_PIX_CEIL (metrics.horiBearingY);

        metrics.width  = right - metrics.horiBearingX;
        metrics.height = metrics.horiBearingY - bottom;
    }

    metrics.horiAdvance = FT_PIX_ROUND(metrics.horiAdvance);
    metrics.vertAdvance = FT_PIX_ROUND(metrics.vertAdvance);
}
function ft_synthesize_vertical_metrics(metrics, advance)
{
    var height = metrics.height;

    /* compensate for glyph with bbox above/below the baseline */
    if (metrics.horiBearingY < 0)
    {
        if (height < metrics.horiBearingY)
            height = metrics.horiBearingY;
    }
    else if (metrics.horiBearingY > 0)
        height -= metrics.horiBearingY;

    /* the factor 1.2 is a heuristical value */
    if (advance == 0)
        advance = parseInt(height * 12 / 10);

    metrics.vertBearingX = parseInt(metrics.horiBearingX - metrics.horiAdvance / 2);
    metrics.vertBearingY = parseInt((advance - height) / 2);
    metrics.vertAdvance  = advance;
}
var ft_standard_glyph_names = [".null","nonmarkingreturn","notequal","infinity","lessequal","greaterequal","partialdiff","summation","product","pi","integral",
"Omega","radical","approxequal","Delta","nonbreakingspace","lozenge","apple","franc","Gbreve","gbreve","Idotaccent","Scedilla",
"scedilla","Cacute","cacute","Ccaron","ccaron","dcroat",".notdef","space","exclam","quotedbl","numbersign","dollar","percent",
"ampersand","quoteright","parenleft","parenright","asterisk","plus","comma","hyphen","period","slash","zero","one","two","three",
"four","five","six","seven","eight","nine","colon","semicolon","less","equal","greater","question","at","A","B","C","D","E","F","G",
"H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","bracketleft","backslash","bracketright","asciicircum",
"underscore","quoteleft","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
"braceleft","bar","braceright","asciitilde","exclamdown","cent","sterling","fraction","yen","florin","section","currency",
"quotesingle","quotedblleft","guillemotleft","guilsinglleft","guilsinglright","fi","fl","endash","dagger","daggerdbl","periodcentered",
"paragraph","bullet","quotesinglbase","quotedblbase","quotedblright","guillemotright","ellipsis","perthousand","questiondown","grave",
"acute","circumflex","tilde","macron","breve","dotaccent","dieresis","ring","cedilla","hungarumlaut","ogonek","caron","emdash","AE",
"ordfeminine","Lslash","Oslash","OE","ordmasculine","ae","dotlessi","lslash","oslash","oe","germandbls","onesuperior","logicalnot",
"mu","trademark","Eth","onehalf","plusminus","Thorn","onequarter","divide","brokenbar","degree","thorn","threequarters","twosuperior",
"registered","minus","eth","multiply","threesuperior","copyright","Aacute","Acircumflex","Adieresis","Agrave","Aring","Atilde",
"Ccedilla","Eacute","Ecircumflex","Edieresis","Egrave","Iacute","Icircumflex","Idieresis","Igrave","Ntilde","Oacute","Ocircumflex",
"Odieresis","Ograve","Otilde","Scaron","Uacute","Ucircumflex","Udieresis","Ugrave","Yacute","Ydieresis","Zcaron","aacute",
"acircumflex","adieresis","agrave","aring","atilde","ccedilla","eacute","ecircumflex","edieresis","egrave","iacute","icircumflex",
"idieresis","igrave","ntilde","oacute","ocircumflex","odieresis","ograve","otilde","scaron","uacute","ucircumflex","udieresis",
"ugrave","yacute","ydieresis","zcaron","exclamsmall","Hungarumlautsmall","dollaroldstyle","dollarsuperior","ampersandsmall",
"Acutesmall","parenleftsuperior","parenrightsuperior","twodotenleader","onedotenleader","zerooldstyle","oneoldstyle","twooldstyle",
"threeoldstyle","fouroldstyle","fiveoldstyle","sixoldstyle","sevenoldstyle","eightoldstyle","nineoldstyle","commasuperior",
"threequartersemdash","periodsuperior","questionsmall","asuperior","bsuperior","centsuperior","dsuperior","esuperior","isuperior",
"lsuperior","msuperior","nsuperior","osuperior","rsuperior","ssuperior","tsuperior","ff","ffi","ffl","parenleftinferior",
"parenrightinferior","Circumflexsmall","hyphensuperior","Gravesmall","Asmall","Bsmall","Csmall","Dsmall","Esmall","Fsmall",
"Gsmall","Hsmall","Ismall","Jsmall","Ksmall","Lsmall","Msmall","Nsmall","Osmall","Psmall","Qsmall","Rsmall","Ssmall","Tsmall",
"Usmall","Vsmall","Wsmall","Xsmall","Ysmall","Zsmall","colonmonetary","onefitted","rupiah","Tildesmall","exclamdownsmall",
"centoldstyle","Lslashsmall","Scaronsmall","Zcaronsmall","Dieresissmall","Brevesmall","Caronsmall","Dotaccentsmall","Macronsmall",
"figuredash","hypheninferior","Ogoneksmall","Ringsmall","Cedillasmall","questiondownsmall","oneeighth","threeeighths","fiveeighths",
"seveneighths","onethird","twothirds","zerosuperior","foursuperior","fivesuperior","sixsuperior","sevensuperior","eightsuperior",
"ninesuperior","zeroinferior","oneinferior","twoinferior","threeinferior","fourinferior","fiveinferior","sixinferior","seveninferior",
"eightinferior","nineinferior","centinferior","dollarinferior","periodinferior","commainferior","Agravesmall","Aacutesmall",
"Acircumflexsmall","Atildesmall","Adieresissmall","Aringsmall","AEsmall","Ccedillasmall","Egravesmall","Eacutesmall",
"Ecircumflexsmall","Edieresissmall","Igravesmall","Iacutesmall","Icircumflexsmall","Idieresissmall","Ethsmall","Ntildesmall",
"Ogravesmall","Oacutesmall","Ocircumflexsmall","Otildesmall","Odieresissmall","OEsmall","Oslashsmall","Ugravesmall","Uacutesmall",
"Ucircumflexsmall","Udieresissmall","Yacutesmall","Thornsmall","Ydieresissmall","001.000","001.001","001.002","001.003","Black",
"Bold","Book","Light","Medium","Regular","Roman","Semibold"];

var ft_mac_names=[29,0,1,30,31,32,33,34,35,36,133,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,
66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,153,95,96,97,98,99,100,101,102,103,104,105,106,
107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,202,204,206,207,215,218,224,229,232,230,231,234,233,235,236,
239,237,238,240,243,241,242,244,245,248,246,247,249,251,254,252,253,141,190,126,127,131,145,144,178,194,199,182,154,160,2,167,170,3,
185,4,5,129,181,6,7,8,9,10,168,172,11,173,176,152,125,180,12,130,13,14,135,149,150,15,203,205,220,171,177,140,166,134,148,94,37,188,
16,256,227,128,132,136,137,138,139,142,143,146,147,151,201,208,200,209,210,211,212,213,214,216,217,17,219,222,223,225,174,155,156,
157,158,159,161,162,163,164,165,169,175,221,250,228,257,189,183,196,226,255,186,191,195,197,179,193,198,184,187,192,18,19,20,21,22,
23,24,25,26,27,28];

var ft_sid_names=[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,
69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,
109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,
142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,
175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,
241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,
274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,
307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,
340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,
373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,
406,407,408,409,410,411,412,413,414,415,416,417,418,419];

var t1_standard_encoding=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,
65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,
0,111,112,113,114,0,115,116,117,118,119,120,121,122,0,123,
0,124,125,126,127,128,129,130,131,0,132,133,0,134,135,136,
137,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,138,0,139,0,0,0,0,140,141,142,143,0,0,0,0,
0,144,0,0,0,145,0,0,146,147,148,149,0,0,0,0];

var t1_expert_encoding=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,229,230,0,231,232,233,234,235,236,237,238,13,14,15,99,
239,240,241,242,243,244,245,246,247,248,27,28,249,250,251,252,
0,253,254,255,256,257,0,0,0,258,0,0,259,260,261,262,
0,0,263,264,265,0,266,109,110,267,268,269,0,270,271,272,
273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,
289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,304,305,306,0,0,307,308,309,310,311,0,312,0,0,313,
0,0,314,315,0,0,316,317,318,0,0,0,158,155,163,319,
320,321,322,323,324,325,0,0,326,150,164,169,327,328,329,330,
331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,
347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,
363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378];

var ft_adobe_glyph_list=[0,52,0,106,2,167,3,63,4,220,6,125,9,143,10,23,
11,137,12,199,14,246,15,87,16,233,17,219,18,104,19,88,
22,110,23,32,23,71,24,77,27,156,29,73,31,247,32,107,
32,222,33,55,34,154,35,218,58,10,64,122,72,188,80,109,
88,104,93,61,98,168,106,91,114,111,115,237,122,180,127,255,
135,164,143,132,149,213,158,108,161,115,168,175,183,147,197,199,
202,25,204,166,208,209,209,81,215,26,65,143,0,65,0,140,
0,175,0,193,1,15,1,147,1,233,1,251,2,7,2,40,
2,57,2,82,2,91,2,128,2,136,2,154,69,131,0,198,
0,150,0,158,0,167,225,227,245,244,101,128,1,252,237,225,
227,242,239,110,128,1,226,243,237,225,236,108,128,247,230,225,
227,245,244,101,129,0,193,0,185,243,237,225,236,108,128,247,
225,226,242,229,246,101,134,1,2,0,213,0,221,0,232,0,
243,0,251,1,7,225,227,245,244,101,128,30,174,227,249,242,
233,236,236,233,99,128,4,208,228,239,244,226,229,236,239,119,
128,30,182,231,242,225,246,101,128,30,176,232,239,239,235,225,
226,239,246,101,128,30,178,244,233,236,228,101,128,30,180,99,
4,1,25,1,32,1,121,1,137,225,242,239,110,128,1,205,
233,242,99,2,1,40,1,45,236,101,128,36,182,245,237,230,
236,229,120,134,0,194,1,66,1,74,1,85,1,93,1,105,
1,113,225,227,245,244,101,128,30,164,228,239,244,226,229,236,
239,119,128,30,172,231,242,225,246,101,128,30,166,232,239,239,
235,225,226,239,246,101,128,30,168,243,237,225,236,108,128,247,
226,244,233,236,228,101,128,30,170,245,244,101,129,246,201,1,
129,243,237,225,236,108,128,247,180,249,242,233,236,236,233,99,
128,4,16,100,3,1,155,1,165,1,209,226,236,231,242,225,
246,101,128,2,0,233,229,242,229,243,233,115,131,0,196,1,
181,1,192,1,201,227,249,242,233,236,236,233,99,128,4,210,
237,225,227,242,239,110,128,1,222,243,237,225,236,108,128,247,
228,239,116,2,1,216,1,224,226,229,236,239,119,128,30,160,
237,225,227,242,239,110,128,1,224,231,242,225,246,101,129,0,
192,1,243,243,237,225,236,108,128,247,224,232,239,239,235,225,
226,239,246,101,128,30,162,105,2,2,13,2,25,229,227,249,
242,233,236,236,233,99,128,4,212,238,246,229,242,244,229,228,
226,242,229,246,101,128,2,2,236,240,232,97,129,3,145,2,
49,244,239,238,239,115,128,3,134,109,2,2,63,2,71,225,
227,242,239,110,128,1,0,239,238,239,243,240,225,227,101,128,
255,33,239,231,239,238,229,107,128,1,4,242,233,238,103,131,
0,197,2,104,2,112,2,120,225,227,245,244,101,128,1,250,
226,229,236,239,119,128,30,0,243,237,225,236,108,128,247,229,
243,237,225,236,108,128,247,97,244,233,236,228,101,129,0,195,
2,146,243,237,225,236,108,128,247,227,249,226,225,242,237,229,
238,233,225,110,128,5,49,66,137,0,66,2,189,2,198,2,
223,3,3,3,10,3,22,3,34,3,46,3,54,227,233,242,
227,236,101,128,36,183,228,239,116,2,2,206,2,215,225,227,
227,229,238,116,128,30,2,226,229,236,239,119,128,30,4,101,
3,2,231,2,242,2,254,227,249,242,233,236,236,233,99,128,
4,17,238,225,242,237,229,238,233,225,110,128,5,50,244,97,
128,3,146,232,239,239,107,128,1,129,236,233,238,229,226,229,
236,239,119,128,30,6,237,239,238,239,243,240,225,227,101,128,
255,34,242,229,246,229,243,237,225,236,108,128,246,244,243,237,
225,236,108,128,247,98,244,239,240,226,225,114,128,1,130,67,
137,0,67,3,85,3,127,3,193,3,210,3,224,4,171,4,
188,4,200,4,212,97,3,3,93,3,104,3,111,225,242,237,
229,238,233,225,110,128,5,62,227,245,244,101,128,1,6,242,
239,110,129,246,202,3,119,243,237,225,236,108,128,246,245,99,
3,3,135,3,142,3,171,225,242,239,110,128,1,12,229,228,
233,236,236,97,130,0,199,3,155,3,163,225,227,245,244,101,
128,30,8,243,237,225,236,108,128,247,231,233,242,99,2,3,
179,3,184,236,101,128,36,184,245,237,230,236,229,120,128,1,
8,228,239,116,129,1,10,3,201,225,227,227,229,238,116,128,
1,10,229,228,233,236,236,225,243,237,225,236,108,128,247,184,
104,4,3,234,3,246,4,161,4,165,225,225,242,237,229,238,
233,225,110,128,5,73,101,6,4,4,4,24,4,35,4,103,
4,115,4,136,225,226,235,232,225,243,233,225,238,227,249,242,
233,236,236,233,99,128,4,188,227,249,242,233,236,236,233,99,
128,4,39,100,2,4,41,4,85,229,243,227,229,238,228,229,
114,2,4,54,4,74,225,226,235,232,225,243,233,225,238,227,
249,242,233,236,236,233,99,128,4,190,227,249,242,233,236,236,
233,99,128,4,182,233,229,242,229,243,233,243,227,249,242,233,
236,236,233,99,128,4,244,232,225,242,237,229,238,233,225,110,
128,5,67,235,232,225,235,225,243,243,233,225,238,227,249,242,
233,236,236,233,99,128,4,203,246,229,242,244,233,227,225,236,
243,244,242,239,235,229,227,249,242,233,236,236,233,99,128,4,
184,105,128,3,167,239,239,107,128,1,135,233,242,227,245,237,
230,236,229,248,243,237,225,236,108,128,246,246,237,239,238,239,
243,240,225,227,101,128,255,35,239,225,242,237,229,238,233,225,
110,128,5,81,243,237,225,236,108,128,247,99,68,142,0,68,
4,252,5,10,5,36,5,96,5,121,5,166,5,173,5,231,
5,244,6,0,6,12,6,28,6,48,6,57,90,129,1,241,
5,2,227,225,242,239,110,128,1,196,97,2,5,16,5,27,
225,242,237,229,238,233,225,110,128,5,52,230,242,233,227,225,
110,128,1,137,99,4,5,46,5,53,5,62,5,89,225,242,
239,110,128,1,14,229,228,233,236,236,97,128,30,16,233,242,
99,2,5,70,5,75,236,101,128,36,185,245,237,230,236,229,
248,226,229,236,239,119,128,30,18,242,239,225,116,128,1,16,
228,239,116,2,5,104,5,113,225,227,227,229,238,116,128,30,
10,226,229,236,239,119,128,30,12,101,3,5,129,5,140,5,
150,227,249,242,233,236,236,233,99,128,4,20,233,227,239,240,
244,233,99,128,3,238,236,244,97,129,34,6,5,158,231,242,
229,229,107,128,3,148,232,239,239,107,128,1,138,105,2,5,
179,5,218,229,242,229,243,233,115,131,246,203,5,194,5,202,
5,210,193,227,245,244,101,128,246,204,199,242,225,246,101,128,
246,205,243,237,225,236,108,128,247,168,231,225,237,237,225,231,
242,229,229,107,128,3,220,234,229,227,249,242,233,236,236,233,
99,128,4,2,236,233,238,229,226,229,236,239,119,128,30,14,
237,239,238,239,243,240,225,227,101,128,255,36,239,244,225,227,
227,229,238,244,243,237,225,236,108,128,246,247,115,2,6,34,
6,41,236,225,243,104,128,1,16,237,225,236,108,128,247,100,
244,239,240,226,225,114,128,1,139,122,131,1,242,6,67,6,
75,6,112,227,225,242,239,110,128,1,197,101,2,6,81,6,
101,225,226,235,232,225,243,233,225,238,227,249,242,233,236,236,
233,99,128,4,224,227,249,242,233,236,236,233,99,128,4,5,
232,229,227,249,242,233,236,236,233,99,128,4,15,69,146,0,
69,6,165,6,183,6,191,7,89,7,153,7,165,7,183,7,
211,8,7,8,36,8,94,8,169,8,189,8,208,8,248,9,
44,9,109,9,115,225,227,245,244,101,129,0,201,6,175,243,
237,225,236,108,128,247,233,226,242,229,246,101,128,1,20,99,
5,6,203,6,210,6,224,6,236,7,79,225,242,239,110,128,
1,26,229,228,233,236,236,225,226,242,229,246,101,128,30,28,
232,225,242,237,229,238,233,225,110,128,5,53,233,242,99,2,
6,244,6,249,236,101,128,36,186,245,237,230,236,229,120,135,
0,202,7,16,7,24,7,32,7,43,7,51,7,63,7,71,
225,227,245,244,101,128,30,190,226,229,236,239,119,128,30,24,
228,239,244,226,229,236,239,119,128,30,198,231,242,225,246,101,
128,30,192,232,239,239,235,225,226,239,246,101,128,30,194,243,
237,225,236,108,128,247,234,244,233,236,228,101,128,30,196,249,
242,233,236,236,233,99,128,4,4,100,3,7,97,7,107,7,
127,226,236,231,242,225,246,101,128,2,4,233,229,242,229,243,
233,115,129,0,203,7,119,243,237,225,236,108,128,247,235,239,
116,130,1,22,7,136,7,145,225,227,227,229,238,116,128,1,
22,226,229,236,239,119,128,30,184,230,227,249,242,233,236,236,
233,99,128,4,36,231,242,225,246,101,129,0,200,7,175,243,
237,225,236,108,128,247,232,104,2,7,189,7,200,225,242,237,
229,238,233,225,110,128,5,55,239,239,235,225,226,239,246,101,
128,30,186,105,3,7,219,7,230,7,245,231,232,244,242,239,
237,225,110,128,33,103,238,246,229,242,244,229,228,226,242,229,
246,101,128,2,6,239,244,233,230,233,229,228,227,249,242,233,
236,236,233,99,128,4,100,108,2,8,13,8,24,227,249,242,
233,236,236,233,99,128,4,27,229,246,229,238,242,239,237,225,
110,128,33,106,109,3,8,44,8,72,8,83,225,227,242,239,
110,130,1,18,8,56,8,64,225,227,245,244,101,128,30,22,
231,242,225,246,101,128,30,20,227,249,242,233,236,236,233,99,
128,4,28,239,238,239,243,240,225,227,101,128,255,37,110,4,
8,104,8,115,8,135,8,154,227,249,242,233,236,236,233,99,
128,4,29,228,229,243,227,229,238,228,229,242,227,249,242,233,
236,236,233,99,128,4,162,103,129,1,74,8,141,232,229,227,
249,242,233,236,236,233,99,128,4,164,232,239,239,235,227,249,
242,233,236,236,233,99,128,4,199,111,2,8,175,8,183,231,
239,238,229,107,128,1,24,240,229,110,128,1,144,240,243,233,
236,239,110,129,3,149,8,200,244,239,238,239,115,128,3,136,
114,2,8,214,8,225,227,249,242,233,236,236,233,99,128,4,
32,229,246,229,242,243,229,100,129,1,142,8,237,227,249,242,
233,236,236,233,99,128,4,45,115,4,9,2,9,13,9,33,
9,37,227,249,242,233,236,236,233,99,128,4,33,228,229,243,
227,229,238,228,229,242,227,249,242,233,236,236,233,99,128,4,
170,104,128,1,169,237,225,236,108,128,247,101,116,3,9,52,
9,78,9,92,97,130,3,151,9,60,9,70,242,237,229,238,
233,225,110,128,5,56,244,239,238,239,115,128,3,137,104,129,
0,208,9,84,243,237,225,236,108,128,247,240,233,236,228,101,
129,30,188,9,101,226,229,236,239,119,128,30,26,245,242,111,
128,32,172,250,104,130,1,183,9,124,9,132,227,225,242,239,
110,128,1,238,242,229,246,229,242,243,229,100,128,1,184,70,
136,0,70,9,163,9,172,9,184,9,212,9,219,9,248,10,
4,10,15,227,233,242,227,236,101,128,36,187,228,239,244,225,
227,227,229,238,116,128,30,30,101,2,9,190,9,202,232,225,
242,237,229,238,233,225,110,128,5,86,233,227,239,240,244,233,
99,128,3,228,232,239,239,107,128,1,145,105,2,9,225,9,
238,244,225,227,249,242,233,236,236,233,99,128,4,114,246,229,
242,239,237,225,110,128,33,100,237,239,238,239,243,240,225,227,
101,128,255,38,239,245,242,242,239,237,225,110,128,33,99,243,
237,225,236,108,128,247,102,71,140,0,71,10,51,10,61,10,
107,10,115,10,176,10,193,10,205,11,39,11,52,11,65,11,
90,11,107,194,243,241,245,225,242,101,128,51,135,97,3,10,
69,10,76,10,94,227,245,244,101,128,1,244,237,237,97,129,
3,147,10,84,225,230,242,233,227,225,110,128,1,148,238,231,
233,225,227,239,240,244,233,99,128,3,234,226,242,229,246,101,
128,1,30,99,4,10,125,10,132,10,141,10,163,225,242,239,
110,128,1,230,229,228,233,236,236,97,128,1,34,233,242,99,
2,10,149,10,154,236,101,128,36,188,245,237,230,236,229,120,
128,1,28,239,237,237,225,225,227,227,229,238,116,128,1,34,
228,239,116,129,1,32,10,184,225,227,227,229,238,116,128,1,
32,229,227,249,242,233,236,236,233,99,128,4,19,104,3,10,
213,10,226,11,33,225,228,225,242,237,229,238,233,225,110,128,
5,66,101,3,10,234,10,255,11,16,237,233,228,228,236,229,
232,239,239,235,227,249,242,233,236,236,233,99,128,4,148,243,
244,242,239,235,229,227,249,242,233,236,236,233,99,128,4,146,
245,240,244,245,242,238,227,249,242,233,236,236,233,99,128,4,
144,239,239,107,128,1,147,233,237,225,242,237,229,238,233,225,
110,128,5,51,234,229,227,249,242,233,236,236,233,99,128,4,
3,109,2,11,71,11,79,225,227,242,239,110,128,30,32,239,
238,239,243,240,225,227,101,128,255,39,242,225,246,101,129,246,
206,11,99,243,237,225,236,108,128,247,96,115,2,11,113,11,
129,237,225,236,108,129,247,103,11,122,232,239,239,107,128,2,
155,244,242,239,235,101,128,1,228,72,140,0,72,11,165,11,
190,11,198,11,208,12,17,12,40,12,77,12,117,12,129,12,
157,12,165,12,189,177,184,53,3,11,175,11,180,11,185,179,
51,128,37,207,180,51,128,37,170,181,49,128,37,171,178,178,
176,183,51,128,37,161,208,243,241,245,225,242,101,128,51,203,
97,3,11,216,11,236,12,0,225,226,235,232,225,243,233,225,
238,227,249,242,233,236,236,233,99,128,4,168,228,229,243,227,
229,238,228,229,242,227,249,242,233,236,236,233,99,128,4,178,
242,228,243,233,231,238,227,249,242,233,236,236,233,99,128,4,
42,98,2,12,23,12,28,225,114,128,1,38,242,229,246,229,
226,229,236,239,119,128,30,42,99,2,12,46,12,55,229,228,
233,236,236,97,128,30,40,233,242,99,2,12,63,12,68,236,
101,128,36,189,245,237,230,236,229,120,128,1,36,100,2,12,
83,12,93,233,229,242,229,243,233,115,128,30,38,239,116,2,
12,100,12,109,225,227,227,229,238,116,128,30,34,226,229,236,
239,119,128,30,36,237,239,238,239,243,240,225,227,101,128,255,
40,111,2,12,135,12,146,225,242,237,229,238,233,225,110,128,
5,64,242,233,227,239,240,244,233,99,128,3,232,243,237,225,
236,108,128,247,104,245,238,231,225,242,245,237,236,225,245,116,
129,246,207,12,181,243,237,225,236,108,128,246,248,250,243,241,
245,225,242,101,128,51,144,73,146,0,73,12,239,12,251,12,
255,13,11,13,29,13,37,13,94,13,181,13,214,13,224,13,
242,13,254,14,48,14,86,14,99,14,166,14,187,14,205,193,
227,249,242,233,236,236,233,99,128,4,47,74,128,1,50,213,
227,249,242,233,236,236,233,99,128,4,46,225,227,245,244,101,
129,0,205,13,21,243,237,225,236,108,128,247,237,226,242,229,
246,101,128,1,44,99,3,13,45,13,52,13,84,225,242,239,
110,128,1,207,233,242,99,2,13,60,13,65,236,101,128,36,
190,245,237,230,236,229,120,129,0,206,13,76,243,237,225,236,
108,128,247,238,249,242,233,236,236,233,99,128,4,6,100,3,
13,102,13,112,13,155,226,236,231,242,225,246,101,128,2,8,
233,229,242,229,243,233,115,131,0,207,13,128,13,136,13,147,
225,227,245,244,101,128,30,46,227,249,242,233,236,236,233,99,
128,4,228,243,237,225,236,108,128,247,239,239,116,130,1,48,
13,164,13,173,225,227,227,229,238,116,128,1,48,226,229,236,
239,119,128,30,202,101,2,13,187,13,203,226,242,229,246,229,
227,249,242,233,236,236,233,99,128,4,214,227,249,242,233,236,
236,233,99,128,4,21,230,242,225,235,244,245,114,128,33,17,
231,242,225,246,101,129,0,204,13,234,243,237,225,236,108,128,
247,236,232,239,239,235,225,226,239,246,101,128,30,200,105,3,
14,6,14,17,14,32,227,249,242,233,236,236,233,99,128,4,
24,238,246,229,242,244,229,228,226,242,229,246,101,128,2,10,
243,232,239,242,244,227,249,242,233,236,236,233,99,128,4,25,
109,2,14,54,14,75,225,227,242,239,110,129,1,42,14,64,
227,249,242,233,236,236,233,99,128,4,226,239,238,239,243,240,
225,227,101,128,255,41,238,233,225,242,237,229,238,233,225,110,
128,5,59,111,3,14,107,14,118,14,126,227,249,242,233,236,
236,233,99,128,4,1,231,239,238,229,107,128,1,46,244,97,
131,3,153,14,137,14,147,14,158,225,230,242,233,227,225,110,
128,1,150,228,233,229,242,229,243,233,115,128,3,170,244,239,
238,239,115,128,3,138,115,2,14,172,14,179,237,225,236,108,
128,247,105,244,242,239,235,101,128,1,151,244,233,236,228,101,
129,1,40,14,197,226,229,236,239,119,128,30,44,250,232,233,
244,243,97,2,14,216,14,227,227,249,242,233,236,236,233,99,
128,4,116,228,226,236,231,242,225,246,229,227,249,242,233,236,
236,233,99,128,4,118,74,134,0,74,15,6,15,18,15,41,
15,53,15,67,15,79,225,225,242,237,229,238,233,225,110,128,
5,65,227,233,242,99,2,15,27,15,32,236,101,128,36,191,
245,237,230,236,229,120,128,1,52,229,227,249,242,233,236,236,
233,99,128,4,8,232,229,232,225,242,237,229,238,233,225,110,
128,5,75,237,239,238,239,243,240,225,227,101,128,255,42,243,
237,225,236,108,128,247,106,75,140,0,75,15,115,15,125,15,
135,16,18,16,65,16,76,16,106,16,143,16,156,16,168,16,
180,16,208,194,243,241,245,225,242,101,128,51,133,203,243,241,
245,225,242,101,128,51,205,97,7,15,151,15,169,15,191,15,
211,15,226,15,232,15,249,226,225,243,232,235,233,242,227,249,
242,233,236,236,233,99,128,4,160,99,2,15,175,15,181,245,
244,101,128,30,48,249,242,233,236,236,233,99,128,4,26,228,
229,243,227,229,238,228,229,242,227,249,242,233,236,236,233,99,
128,4,154,232,239,239,235,227,249,242,233,236,236,233,99,128,
4,195,240,240,97,128,3,154,243,244,242,239,235,229,227,249,
242,233,236,236,233,99,128,4,158,246,229,242,244,233,227,225,
236,243,244,242,239,235,229,227,249,242,233,236,236,233,99,128,
4,156,99,4,16,28,16,35,16,44,16,52,225,242,239,110,
128,1,232,229,228,233,236,236,97,128,1,54,233,242,227,236,
101,128,36,192,239,237,237,225,225,227,227,229,238,116,128,1,
54,228,239,244,226,229,236,239,119,128,30,50,101,2,16,82,
16,94,232,225,242,237,229,238,233,225,110,128,5,84,238,225,
242,237,229,238,233,225,110,128,5,63,104,3,16,114,16,126,
16,137,225,227,249,242,233,236,236,233,99,128,4,37,229,233,
227,239,240,244,233,99,128,3,230,239,239,107,128,1,152,234,
229,227,249,242,233,236,236,233,99,128,4,12,236,233,238,229,
226,229,236,239,119,128,30,52,237,239,238,239,243,240,225,227,
101,128,255,43,239,240,240,97,2,16,189,16,200,227,249,242,
233,236,236,233,99,128,4,128,231,242,229,229,107,128,3,222,
115,2,16,214,16,226,233,227,249,242,233,236,236,233,99,128,
4,110,237,225,236,108,128,247,107,76,138,0,76,17,1,17,
5,17,9,17,29,17,95,17,133,17,147,17,165,17,177,17,
189,74,128,1,199,76,128,246,191,97,2,17,15,17,22,227,
245,244,101,128,1,57,237,226,228,97,128,3,155,99,4,17,
39,17,46,17,55,17,82,225,242,239,110,128,1,61,229,228,
233,236,236,97,128,1,59,233,242,99,2,17,63,17,68,236,
101,128,36,193,245,237,230,236,229,248,226,229,236,239,119,128,
30,60,239,237,237,225,225,227,227,229,238,116,128,1,59,228,
239,116,130,1,63,17,105,17,114,225,227,227,229,238,116,128,
1,63,226,229,236,239,119,129,30,54,17,124,237,225,227,242,
239,110,128,30,56,233,247,238,225,242,237,229,238,233,225,110,
128,5,60,106,129,1,200,17,153,229,227,249,242,233,236,236,
233,99,128,4,9,236,233,238,229,226,229,236,239,119,128,30,
58,237,239,238,239,243,240,225,227,101,128,255,44,115,2,17,
195,17,212,236,225,243,104,129,1,65,17,204,243,237,225,236,
108,128,246,249,237,225,236,108,128,247,108,77,137,0,77,17,
241,17,251,18,24,18,33,18,58,18,71,18,83,18,91,18,
100,194,243,241,245,225,242,101,128,51,134,225,99,2,18,2,
18,18,242,239,110,129,246,208,18,10,243,237,225,236,108,128,
247,175,245,244,101,128,30,62,227,233,242,227,236,101,128,36,
194,228,239,116,2,18,41,18,50,225,227,227,229,238,116,128,
30,64,226,229,236,239,119,128,30,66,229,238,225,242,237,229,
238,233,225,110,128,5,68,237,239,238,239,243,240,225,227,101,
128,255,45,243,237,225,236,108,128,247,109,244,245,242,238,229,
100,128,1,156,117,128,3,156,78,141,0,78,18,134,18,138,
18,146,18,212,18,237,18,248,19,3,19,21,19,33,19,45,
19,58,19,66,19,84,74,128,1,202,225,227,245,244,101,128,
1,67,99,4,18,156,18,163,18,172,18,199,225,242,239,110,
128,1,71,229,228,233,236,236,97,128,1,69,233,242,99,2,
18,180,18,185,236,101,128,36,195,245,237,230,236,229,248,226,
229,236,239,119,128,30,74,239,237,237,225,225,227,227,229,238,
116,128,1,69,228,239,116,2,18,220,18,229,225,227,227,229,
238,116,128,30,68,226,229,236,239,119,128,30,70,232,239,239,
235,236,229,230,116,128,1,157,233,238,229,242,239,237,225,110,
128,33,104,106,129,1,203,19,9,229,227,249,242,233,236,236,
233,99,128,4,10,236,233,238,229,226,229,236,239,119,128,30,
72,237,239,238,239,243,240,225,227,101,128,255,46,239,247,225,
242,237,229,238,233,225,110,128,5,70,243,237,225,236,108,128,
247,110,244,233,236,228,101,129,0,209,19,76,243,237,225,236,
108,128,247,241,117,128,3,157,79,141,0,79,19,118,19,132,
19,150,19,203,20,78,20,152,20,187,21,48,21,69,21,213,
21,223,21,254,22,53,69,129,1,82,19,124,243,237,225,236,
108,128,246,250,225,227,245,244,101,129,0,211,19,142,243,237,
225,236,108,128,247,243,98,2,19,156,19,196,225,242,242,229,
100,2,19,166,19,177,227,249,242,233,236,236,233,99,128,4,
232,228,233,229,242,229,243,233,243,227,249,242,233,236,236,233,
99,128,4,234,242,229,246,101,128,1,78,99,4,19,213,19,
220,19,235,20,68,225,242,239,110,128,1,209,229,238,244,229,
242,229,228,244,233,236,228,101,128,1,159,233,242,99,2,19,
243,19,248,236,101,128,36,196,245,237,230,236,229,120,134,0,
212,20,13,20,21,20,32,20,40,20,52,20,60,225,227,245,
244,101,128,30,208,228,239,244,226,229,236,239,119,128,30,216,
231,242,225,246,101,128,30,210,232,239,239,235,225,226,239,246,
101,128,30,212,243,237,225,236,108,128,247,244,244,233,236,228,
101,128,30,214,249,242,233,236,236,233,99,128,4,30,100,3,
20,86,20,109,20,142,226,108,2,20,93,20,101,225,227,245,
244,101,128,1,80,231,242,225,246,101,128,2,12,233,229,242,
229,243,233,115,130,0,214,20,123,20,134,227,249,242,233,236,
236,233,99,128,4,230,243,237,225,236,108,128,247,246,239,244,
226,229,236,239,119,128,30,204,103,2,20,158,20,170,239,238,
229,235,243,237,225,236,108,128,246,251,242,225,246,101,129,0,
210,20,179,243,237,225,236,108,128,247,242,104,4,20,197,20,
208,20,212,21,34,225,242,237,229,238,233,225,110,128,5,85,
109,128,33,38,111,2,20,218,20,228,239,235,225,226,239,246,
101,128,30,206,242,110,133,1,160,20,243,20,251,21,6,21,
14,21,26,225,227,245,244,101,128,30,218,228,239,244,226,229,
236,239,119,128,30,226,231,242,225,246,101,128,30,220,232,239,
239,235,225,226,239,246,101,128,30,222,244,233,236,228,101,128,
30,224,245,238,231,225,242,245,237,236,225,245,116,128,1,80,
105,129,1,162,21,54,238,246,229,242,244,229,228,226,242,229,
246,101,128,2,14,109,4,21,79,21,107,21,184,21,202,225,
227,242,239,110,130,1,76,21,91,21,99,225,227,245,244,101,
128,30,82,231,242,225,246,101,128,30,80,229,231,97,132,33,
38,21,121,21,132,21,140,21,156,227,249,242,233,236,236,233,
99,128,4,96,231,242,229,229,107,128,3,169,242,239,245,238,
228,227,249,242,233,236,236,233,99,128,4,122,116,2,21,162,
21,177,233,244,236,239,227,249,242,233,236,236,233,99,128,4,
124,239,238,239,115,128,3,143,233,227,242,239,110,129,3,159,
21,194,244,239,238,239,115,128,3,140,239,238,239,243,240,225,
227,101,128,255,47,238,229,242,239,237,225,110,128,33,96,111,
2,21,229,21,248,231,239,238,229,107,129,1,234,21,239,237,
225,227,242,239,110,128,1,236,240,229,110,128,1,134,115,3,
22,6,22,33,22,40,236,225,243,104,130,0,216,22,17,22,
25,225,227,245,244,101,128,1,254,243,237,225,236,108,128,247,
248,237,225,236,108,128,247,111,244,242,239,235,229,225,227,245,
244,101,128,1,254,116,2,22,59,22,70,227,249,242,233,236,
236,233,99,128,4,126,233,236,228,101,131,0,213,22,83,22,
91,22,102,225,227,245,244,101,128,30,76,228,233,229,242,229,
243,233,115,128,30,78,243,237,225,236,108,128,247,245,80,136,
0,80,22,130,22,138,22,147,22,159,22,211,22,227,22,246,
23,2,225,227,245,244,101,128,30,84,227,233,242,227,236,101,
128,36,197,228,239,244,225,227,227,229,238,116,128,30,86,101,
3,22,167,22,178,22,190,227,249,242,233,236,236,233,99,128,
4,31,232,225,242,237,229,238,233,225,110,128,5,74,237,233,
228,228,236,229,232,239,239,235,227,249,242,233,236,236,233,99,
128,4,166,104,2,22,217,22,221,105,128,3,166,239,239,107,
128,1,164,105,129,3,160,22,233,247,242,225,242,237,229,238,
233,225,110,128,5,83,237,239,238,239,243,240,225,227,101,128,
255,48,115,2,23,8,23,25,105,129,3,168,23,14,227,249,
242,233,236,236,233,99,128,4,112,237,225,236,108,128,247,112,
81,131,0,81,23,42,23,51,23,63,227,233,242,227,236,101,
128,36,198,237,239,238,239,243,240,225,227,101,128,255,49,243,
237,225,236,108,128,247,113,82,138,0,82,23,95,23,119,23,
166,23,217,23,230,23,240,23,245,24,19,24,31,24,43,97,
2,23,101,23,112,225,242,237,229,238,233,225,110,128,5,76,
227,245,244,101,128,1,84,99,4,23,129,23,136,23,145,23,
153,225,242,239,110,128,1,88,229,228,233,236,236,97,128,1,
86,233,242,227,236,101,128,36,199,239,237,237,225,225,227,227,
229,238,116,128,1,86,100,2,23,172,23,182,226,236,231,242,
225,246,101,128,2,16,239,116,2,23,189,23,198,225,227,227,
229,238,116,128,30,88,226,229,236,239,119,129,30,90,23,208,
237,225,227,242,239,110,128,30,92,229,232,225,242,237,229,238,
233,225,110,128,5,80,230,242,225,235,244,245,114,128,33,28,
232,111,128,3,161,233,110,2,23,252,24,5,231,243,237,225,
236,108,128,246,252,246,229,242,244,229,228,226,242,229,246,101,
128,2,18,236,233,238,229,226,229,236,239,119,128,30,94,237,
239,238,239,243,240,225,227,101,128,255,50,243,237,225,236,108,
129,247,114,24,53,233,238,246,229,242,244,229,100,129,2,129,
24,66,243,245,240,229,242,233,239,114,128,2,182,83,139,0,
83,24,103,26,17,26,55,26,182,26,221,26,250,27,84,27,
105,27,117,27,135,27,143,70,6,24,117,24,209,24,241,25,
77,25,119,25,221,48,9,24,137,24,145,24,153,24,161,24,
169,24,177,24,185,24,193,24,201,177,176,176,176,48,128,37,
12,178,176,176,176,48,128,37,20,179,176,176,176,48,128,37,
16,180,176,176,176,48,128,37,24,181,176,176,176,48,128,37,
60,182,176,176,176,48,128,37,44,183,176,176,176,48,128,37,
52,184,176,176,176,48,128,37,28,185,176,176,176,48,128,37,
36,49,3,24,217,24,225,24,233,176,176,176,176,48,128,37,
0,177,176,176,176,48,128,37,2,185,176,176,176,48,128,37,
97,50,9,25,5,25,13,25,21,25,29,25,37,25,45,25,
53,25,61,25,69,176,176,176,176,48,128,37,98,177,176,176,
176,48,128,37,86,178,176,176,176,48,128,37,85,179,176,176,
176,48,128,37,99,180,176,176,176,48,128,37,81,181,176,176,
176,48,128,37,87,182,176,176,176,48,128,37,93,183,176,176,
176,48,128,37,92,184,176,176,176,48,128,37,91,51,4,25,
87,25,95,25,103,25,111,182,176,176,176,48,128,37,94,183,
176,176,176,48,128,37,95,184,176,176,176,48,128,37,90,185,
176,176,176,48,128,37,84,52,10,25,141,25,149,25,157,25,
165,25,173,25,181,25,189,25,197,25,205,25,213,176,176,176,
176,48,128,37,105,177,176,176,176,48,128,37,102,178,176,176,
176,48,128,37,96,179,176,176,176,48,128,37,80,180,176,176,
176,48,128,37,108,181,176,176,176,48,128,37,103,182,176,176,
176,48,128,37,104,183,176,176,176,48,128,37,100,184,176,176,
176,48,128,37,101,185,176,176,176,48,128,37,89,53,5,25,
233,25,241,25,249,26,1,26,9,176,176,176,176,48,128,37,
88,177,176,176,176,48,128,37,82,178,176,176,176,48,128,37,
83,179,176,176,176,48,128,37,107,180,176,176,176,48,128,37,
106,97,2,26,23,26,44,227,245,244,101,129,1,90,26,32,
228,239,244,225,227,227,229,238,116,128,30,100,237,240,233,231,
242,229,229,107,128,3,224,99,5,26,67,26,98,26,107,26,
147,26,169,225,242,239,110,130,1,96,26,78,26,90,228,239,
244,225,227,227,229,238,116,128,30,102,243,237,225,236,108,128,
246,253,229,228,233,236,236,97,128,1,94,232,247,97,130,1,
143,26,117,26,128,227,249,242,233,236,236,233,99,128,4,216,
228,233,229,242,229,243,233,243,227,249,242,233,236,236,233,99,
128,4,218,233,242,99,2,26,155,26,160,236,101,128,36,200,
245,237,230,236,229,120,128,1,92,239,237,237,225,225,227,227,
229,238,116,128,2,24,228,239,116,2,26,190,26,199,225,227,
227,229,238,116,128,30,96,226,229,236,239,119,129,30,98,26,
209,228,239,244,225,227,227,229,238,116,128,30,104,101,2,26,
227,26,239,232,225,242,237,229,238,233,225,110,128,5,77,246,
229,238,242,239,237,225,110,128,33,102,104,5,27,6,27,34,
27,48,27,59,27,72,97,2,27,12,27,23,225,242,237,229,
238,233,225,110,128,5,71,227,249,242,233,236,236,233,99,128,
4,40,227,232,225,227,249,242,233,236,236,233,99,128,4,41,
229,233,227,239,240,244,233,99,128,3,226,232,225,227,249,242,
233,236,236,233,99,128,4,186,233,237,225,227,239,240,244,233,
99,128,3,236,105,2,27,90,27,96,231,237,97,128,3,163,
248,242,239,237,225,110,128,33,101,237,239,238,239,243,240,225,
227,101,128,255,51,239,230,244,243,233,231,238,227,249,242,233,
236,236,233,99,128,4,44,243,237,225,236,108,128,247,115,244,
233,231,237,225,231,242,229,229,107,128,3,218,84,141,0,84,
27,186,27,191,27,197,28,7,28,32,28,96,28,147,28,177,
28,189,28,201,28,246,29,6,29,46,225,117,128,3,164,226,
225,114,128,1,102,99,4,27,207,27,214,27,223,27,250,225,
242,239,110,128,1,100,229,228,233,236,236,97,128,1,98,233,
242,99,2,27,231,27,236,236,101,128,36,201,245,237,230,236,
229,248,226,229,236,239,119,128,30,112,239,237,237,225,225,227,
227,229,238,116,128,1,98,228,239,116,2,28,15,28,24,225,
227,227,229,238,116,128,30,106,226,229,236,239,119,128,30,108,
101,4,28,42,28,53,28,73,28,82,227,249,242,233,236,236,
233,99,128,4,34,228,229,243,227,229,238,228,229,242,227,249,
242,233,236,236,233,99,128,4,172,238,242,239,237,225,110,128,
33,105,244,243,229,227,249,242,233,236,236,233,99,128,4,180,
104,3,28,104,28,110,28,136,229,244,97,128,3,152,111,2,
28,116,28,121,239,107,128,1,172,242,110,129,0,222,28,128,
243,237,225,236,108,128,247,254,242,229,229,242,239,237,225,110,
128,33,98,105,2,28,153,28,164,236,228,229,243,237,225,236,
108,128,246,254,247,238,225,242,237,229,238,233,225,110,128,5,
79,236,233,238,229,226,229,236,239,119,128,30,110,237,239,238,
239,243,240,225,227,101,128,255,52,111,2,28,207,28,218,225,
242,237,229,238,233,225,110,128,5,57,238,101,3,28,227,28,
234,28,240,230,233,246,101,128,1,188,243,233,120,128,1,132,
244,247,111,128,1,167,242,229,244,242,239,230,236,229,248,232,
239,239,107,128,1,174,115,3,29,14,29,26,29,39,229,227,
249,242,233,236,236,233,99,128,4,38,232,229,227,249,242,233,
236,236,233,99,128,4,11,237,225,236,108,128,247,116,119,2,
29,52,29,64,229,236,246,229,242,239,237,225,110,128,33,107,
239,242,239,237,225,110,128,33,97,85,142,0,85,29,105,29,
123,29,131,29,198,30,69,30,87,30,198,30,214,30,226,31,
21,31,30,31,142,31,149,31,219,225,227,245,244,101,129,0,
218,29,115,243,237,225,236,108,128,247,250,226,242,229,246,101,
128,1,108,99,3,29,139,29,146,29,188,225,242,239,110,128,
1,211,233,242,99,2,29,154,29,159,236,101,128,36,202,245,
237,230,236,229,120,130,0,219,29,172,29,180,226,229,236,239,
119,128,30,118,243,237,225,236,108,128,247,251,249,242,233,236,
236,233,99,128,4,35,100,3,29,206,29,229,30,59,226,108,
2,29,213,29,221,225,227,245,244,101,128,1,112,231,242,225,
246,101,128,2,20,233,229,242,229,243,233,115,134,0,220,29,
251,30,3,30,11,30,34,30,42,30,51,225,227,245,244,101,
128,1,215,226,229,236,239,119,128,30,114,99,2,30,17,30,
24,225,242,239,110,128,1,217,249,242,233,236,236,233,99,128,
4,240,231,242,225,246,101,128,1,219,237,225,227,242,239,110,
128,1,213,243,237,225,236,108,128,247,252,239,244,226,229,236,
239,119,128,30,228,231,242,225,246,101,129,0,217,30,79,243,
237,225,236,108,128,247,249,104,2,30,93,30,171,111,2,30,
99,30,109,239,235,225,226,239,246,101,128,30,230,242,110,133,
1,175,30,124,30,132,30,143,30,151,30,163,225,227,245,244,
101,128,30,232,228,239,244,226,229,236,239,119,128,30,240,231,
242,225,246,101,128,30,234,232,239,239,235,225,226,239,246,101,
128,30,236,244,233,236,228,101,128,30,238,245,238,231,225,242,
245,237,236,225,245,116,129,1,112,30,187,227,249,242,233,236,
236,233,99,128,4,242,233,238,246,229,242,244,229,228,226,242,
229,246,101,128,2,22,235,227,249,242,233,236,236,233,99,128,
4,120,109,2,30,232,31,10,225,227,242,239,110,130,1,106,
30,244,30,255,227,249,242,233,236,236,233,99,128,4,238,228,
233,229,242,229,243,233,115,128,30,122,239,238,239,243,240,225,
227,101,128,255,53,239,231,239,238,229,107,128,1,114,240,243,
233,236,239,110,133,3,165,31,49,31,53,31,90,31,121,31,
134,49,128,3,210,97,2,31,59,31,81,227,245,244,229,232,
239,239,235,243,249,237,226,239,236,231,242,229,229,107,128,3,
211,230,242,233,227,225,110,128,1,177,228,233,229,242,229,243,
233,115,129,3,171,31,103,232,239,239,235,243,249,237,226,239,
236,231,242,229,229,107,128,3,212,232,239,239,235,243,249,237,
226,239,108,128,3,210,244,239,238,239,115,128,3,142,242,233,
238,103,128,1,110,115,3,31,157,31,172,31,179,232,239,242,
244,227,249,242,233,236,236,233,99,128,4,14,237,225,236,108,
128,247,117,244,242,225,233,231,232,116,2,31,191,31,202,227,
249,242,233,236,236,233,99,128,4,174,243,244,242,239,235,229,
227,249,242,233,236,236,233,99,128,4,176,244,233,236,228,101,
130,1,104,31,231,31,239,225,227,245,244,101,128,30,120,226,
229,236,239,119,128,30,116,86,136,0,86,32,11,32,20,32,
31,32,60,32,67,32,79,32,91,32,99,227,233,242,227,236,
101,128,36,203,228,239,244,226,229,236,239,119,128,30,126,101,
2,32,37,32,48,227,249,242,233,236,236,233,99,128,4,18,
247,225,242,237,229,238,233,225,110,128,5,78,232,239,239,107,
128,1,178,237,239,238,239,243,240,225,227,101,128,255,54,239,
225,242,237,229,238,233,225,110,128,5,72,243,237,225,236,108,
128,247,118,244,233,236,228,101,128,30,124,87,134,0,87,32,
123,32,131,32,154,32,194,32,202,32,214,225,227,245,244,101,
128,30,130,227,233,242,99,2,32,140,32,145,236,101,128,36,
204,245,237,230,236,229,120,128,1,116,100,2,32,160,32,170,
233,229,242,229,243,233,115,128,30,132,239,116,2,32,177,32,
186,225,227,227,229,238,116,128,30,134,226,229,236,239,119,128,
30,136,231,242,225,246,101,128,30,128,237,239,238,239,243,240,
225,227,101,128,255,55,243,237,225,236,108,128,247,119,88,134,
0,88,32,238,32,247,33,18,33,31,33,35,33,47,227,233,
242,227,236,101,128,36,205,100,2,32,253,33,7,233,229,242,
229,243,233,115,128,30,140,239,244,225,227,227,229,238,116,128,
30,138,229,232,225,242,237,229,238,233,225,110,128,5,61,105,
128,3,158,237,239,238,239,243,240,225,227,101,128,255,56,243,
237,225,236,108,128,247,120,89,139,0,89,33,81,33,116,33,
139,33,189,33,228,33,236,33,253,34,40,34,52,34,60,34,
68,97,2,33,87,33,104,227,245,244,101,129,0,221,33,96,
243,237,225,236,108,128,247,253,244,227,249,242,233,236,236,233,
99,128,4,98,227,233,242,99,2,33,125,33,130,236,101,128,
36,206,245,237,230,236,229,120,128,1,118,100,2,33,145,33,
165,233,229,242,229,243,233,115,129,1,120,33,157,243,237,225,
236,108,128,247,255,239,116,2,33,172,33,181,225,227,227,229,
238,116,128,30,142,226,229,236,239,119,128,30,244,229,114,2,
33,196,33,208,233,227,249,242,233,236,236,233,99,128,4,43,
245,228,233,229,242,229,243,233,243,227,249,242,233,236,236,233,
99,128,4,248,231,242,225,246,101,128,30,242,232,239,239,107,
129,1,179,33,245,225,226,239,246,101,128,30,246,105,3,34,
5,34,16,34,27,225,242,237,229,238,233,225,110,128,5,69,
227,249,242,233,236,236,233,99,128,4,7,247,238,225,242,237,
229,238,233,225,110,128,5,82,237,239,238,239,243,240,225,227,
101,128,255,57,243,237,225,236,108,128,247,121,244,233,236,228,
101,128,30,248,245,115,2,34,75,34,113,226,233,103,2,34,
83,34,94,227,249,242,233,236,236,233,99,128,4,106,233,239,
244,233,230,233,229,228,227,249,242,233,236,236,233,99,128,4,
108,236,233,244,244,236,101,2,34,124,34,135,227,249,242,233,
236,236,233,99,128,4,102,233,239,244,233,230,233,229,228,227,
249,242,233,236,236,233,99,128,4,104,90,136,0,90,34,174,
34,198,34,243,35,14,35,81,35,173,35,185,35,197,97,2,
34,180,34,191,225,242,237,229,238,233,225,110,128,5,54,227,
245,244,101,128,1,121,99,2,34,204,34,221,225,242,239,110,
129,1,125,34,213,243,237,225,236,108,128,246,255,233,242,99,
2,34,229,34,234,236,101,128,36,207,245,237,230,236,229,120,
128,30,144,228,239,116,130,1,123,34,253,35,6,225,227,227,
229,238,116,128,1,123,226,229,236,239,119,128,30,146,101,3,
35,22,35,33,35,76,227,249,242,233,236,236,233,99,128,4,
23,100,2,35,39,35,58,229,243,227,229,238,228,229,242,227,
249,242,233,236,236,233,99,128,4,152,233,229,242,229,243,233,
243,227,249,242,233,236,236,233,99,128,4,222,244,97,128,3,
150,232,101,4,35,92,35,103,35,119,35,130,225,242,237,229,
238,233,225,110,128,5,58,226,242,229,246,229,227,249,242,233,
236,236,233,99,128,4,193,227,249,242,233,236,236,233,99,128,
4,22,100,2,35,136,35,155,229,243,227,229,238,228,229,242,
227,249,242,233,236,236,233,99,128,4,150,233,229,242,229,243,
233,243,227,249,242,233,236,236,233,99,128,4,220,236,233,238,
229,226,229,236,239,119,128,30,148,237,239,238,239,243,240,225,
227,101,128,255,58,115,2,35,203,35,210,237,225,236,108,128,
247,122,244,242,239,235,101,128,1,181,97,158,0,97,36,26,
38,154,39,4,39,68,39,132,39,196,40,4,40,68,40,126,
40,190,41,70,41,217,42,137,42,237,43,17,49,192,49,229,
50,0,50,225,51,7,52,96,52,168,53,123,53,132,54,5,
56,13,57,3,57,50,57,201,57,215,49,138,39,1,36,50,
36,114,36,154,36,218,37,26,37,90,37,154,37,218,38,26,
38,90,48,138,39,33,36,74,36,78,36,82,36,86,36,90,
36,94,36,98,36,102,36,106,36,110,48,128,39,94,49,128,
39,97,50,128,39,98,51,128,39,99,52,128,39,100,53,128,
39,16,54,128,39,101,55,128,39,102,56,128,39,103,57,128,
38,96,49,134,38,27,36,130,36,134,36,138,36,142,36,146,
36,150,48,128,38,101,49,128,38,102,50,128,38,99,55,128,
39,9,56,128,39,8,57,128,39,7,50,138,38,30,36,178,
36,182,36,186,36,190,36,194,36,198,36,202,36,206,36,210,
36,214,48,128,36,96,49,128,36,97,50,128,36,98,51,128,
36,99,52,128,36,100,53,128,36,101,54,128,36,102,55,128,
36,103,56,128,36,104,57,128,36,105,51,138,39,12,36,242,
36,246,36,250,36,254,37,2,37,6,37,10,37,14,37,18,
37,22,48,128,39,118,49,128,39,119,50,128,39,120,51,128,
39,121,52,128,39,122,53,128,39,123,54,128,39,124,55,128,
39,125,56,128,39,126,57,128,39,127,52,138,39,13,37,50,
37,54,37,58,37,62,37,66,37,70,37,74,37,78,37,82,
37,86,48,128,39,128,49,128,39,129,50,128,39,130,51,128,
39,131,52,128,39,132,53,128,39,133,54,128,39,134,55,128,
39,135,56,128,39,136,57,128,39,137,53,138,39,14,37,114,
37,118,37,122,37,126,37,130,37,134,37,138,37,142,37,146,
37,150,48,128,39,138,49,128,39,139,50,128,39,140,51,128,
39,141,52,128,39,142,53,128,39,143,54,128,39,144,55,128,
39,145,56,128,39,146,57,128,39,147,54,138,39,15,37,178,
37,182,37,186,37,190,37,194,37,198,37,202,37,206,37,210,
37,214,48,128,39,148,49,128,33,146,50,128,39,163,51,128,
33,148,52,128,33,149,53,128,39,153,54,128,39,155,55,128,
39,156,56,128,39,157,57,128,39,158,55,138,39,17,37,242,
37,246,37,250,37,254,38,2,38,6,38,10,38,14,38,18,
38,22,48,128,39,159,49,128,39,160,50,128,39,161,51,128,
39,162,52,128,39,164,53,128,39,165,54,128,39,166,55,128,
39,167,56,128,39,168,57,128,39,169,56,138,39,18,38,50,
38,54,38,58,38,62,38,66,38,70,38,74,38,78,38,82,
38,86,48,128,39,171,49,128,39,173,50,128,39,175,51,128,
39,178,52,128,39,179,53,128,39,181,54,128,39,184,55,128,
39,186,56,128,39,187,57,128,39,188,57,138,39,19,38,114,
38,118,38,122,38,126,38,130,38,134,38,138,38,142,38,146,
38,150,48,128,39,189,49,128,39,190,50,128,39,154,51,128,
39,170,52,128,39,182,53,128,39,185,54,128,39,152,55,128,
39,180,56,128,39,183,57,128,39,172,50,138,39,2,38,178,
38,224,38,228,38,232,38,236,38,240,38,244,38,248,38,252,
39,0,48,135,39,20,38,196,38,200,38,204,38,208,38,212,
38,216,38,220,48,128,39,174,49,128,39,177,50,128,39,3,
51,128,39,80,52,128,39,82,53,128,39,110,54,128,39,112,
49,128,39,21,50,128,39,22,51,128,39,23,52,128,39,24,
53,128,39,25,54,128,39,26,55,128,39,27,56,128,39,28,
57,128,39,34,51,138,39,4,39,28,39,32,39,36,39,40,
39,44,39,48,39,52,39,56,39,60,39,64,48,128,39,35,
49,128,39,36,50,128,39,37,51,128,39,38,52,128,39,39,
53,128,38,5,54,128,39,41,55,128,39,42,56,128,39,43,
57,128,39,44,52,138,38,14,39,92,39,96,39,100,39,104,
39,108,39,112,39,116,39,120,39,124,39,128,48,128,39,45,
49,128,39,46,50,128,39,47,51,128,39,48,52,128,39,49,
53,128,39,50,54,128,39,51,55,128,39,52,56,128,39,53,
57,128,39,54,53,138,39,6,39,156,39,160,39,164,39,168,
39,172,39,176,39,180,39,184,39,188,39,192,48,128,39,55,
49,128,39,56,50,128,39,57,51,128,39,58,52,128,39,59,
53,128,39,60,54,128,39,61,55,128,39,62,56,128,39,63,
57,128,39,64,54,138,39,29,39,220,39,224,39,228,39,232,
39,236,39,240,39,244,39,248,39,252,40,0,48,128,39,65,
49,128,39,66,50,128,39,67,51,128,39,68,52,128,39,69,
53,128,39,70,54,128,39,71,55,128,39,72,56,128,39,73,
57,128,39,74,55,138,39,30,40,28,40,32,40,36,40,40,
40,44,40,48,40,52,40,56,40,60,40,64,48,128,39,75,
49,128,37,207,50,128,39,77,51,128,37,160,52,128,39,79,
53,128,39,81,54,128,37,178,55,128,37,188,56,128,37,198,
57,128,39,86,56,137,39,31,40,90,40,94,40,98,40,102,
40,106,40,110,40,114,40,118,40,122,49,128,37,215,50,128,
39,88,51,128,39,89,52,128,39,90,53,128,39,111,54,128,
39,113,55,128,39,114,56,128,39,115,57,128,39,104,57,138,
39,32,40,150,40,154,40,158,40,162,40,166,40,170,40,174,
40,178,40,182,40,186,48,128,39,105,49,128,39,108,50,128,
39,109,51,128,39,106,52,128,39,107,53,128,39,116,54,128,
39,117,55,128,39,91,56,128,39,92,57,128,39,93,97,7,
40,206,40,216,40,223,40,230,40,255,41,15,41,26,226,229,
238,231,225,236,105,128,9,134,227,245,244,101,128,0,225,228,
229,246,97,128,9,6,231,117,2,40,237,40,246,234,225,242,
225,244,105,128,10,134,242,237,245,235,232,105,128,10,6,237,
225,244,242,225,231,245,242,237,245,235,232,105,128,10,62,242,
245,243,241,245,225,242,101,128,51,3,246,239,247,229,236,243,
233,231,110,3,41,42,41,52,41,59,226,229,238,231,225,236,
105,128,9,190,228,229,246,97,128,9,62,231,245,234,225,242,
225,244,105,128,10,190,98,4,41,80,41,121,41,130,41,140,
226,242,229,246,233,225,244,233,239,110,2,41,95,41,110,237,
225,242,235,225,242,237,229,238,233,225,110,128,5,95,243,233,
231,238,228,229,246,97,128,9,112,229,238,231,225,236,105,128,
9,133,239,240,239,237,239,230,111,128,49,26,242,229,246,101,
134,1,3,41,159,41,167,41,178,41,189,41,197,41,209,225,
227,245,244,101,128,30,175,227,249,242,233,236,236,233,99,128,
4,209,228,239,244,226,229,236,239,119,128,30,183,231,242,225,
246,101,128,30,177,232,239,239,235,225,226,239,246,101,128,30,
179,244,233,236,228,101,128,30,181,99,4,41,227,41,234,42,
57,42,127,225,242,239,110,128,1,206,233,242,99,2,41,242,
41,247,236,101,128,36,208,245,237,230,236,229,120,133,0,226,
42,10,42,18,42,29,42,37,42,49,225,227,245,244,101,128,
30,165,228,239,244,226,229,236,239,119,128,30,173,231,242,225,
246,101,128,30,167,232,239,239,235,225,226,239,246,101,128,30,
169,244,233,236,228,101,128,30,171,245,244,101,133,0,180,42,
73,42,84,42,101,42,108,42,117,226,229,236,239,247,227,237,
98,128,3,23,99,2,42,90,42,95,237,98,128,3,1,239,
237,98,128,3,1,228,229,246,97,128,9,84,236,239,247,237,
239,100,128,2,207,244,239,238,229,227,237,98,128,3,65,249,
242,233,236,236,233,99,128,4,48,100,5,42,149,42,159,42,
173,42,179,42,213,226,236,231,242,225,246,101,128,2,1,228,
225,235,231,245,242,237,245,235,232,105,128,10,113,229,246,97,
128,9,5,233,229,242,229,243,233,115,130,0,228,42,193,42,
204,227,249,242,233,236,236,233,99,128,4,211,237,225,227,242,
239,110,128,1,223,239,116,2,42,220,42,228,226,229,236,239,
119,128,30,161,237,225,227,242,239,110,128,1,225,101,131,0,
230,42,247,42,255,43,8,225,227,245,244,101,128,1,253,235,
239,242,229,225,110,128,49,80,237,225,227,242,239,110,128,1,
227,230,233,105,6,43,33,43,53,45,246,45,252,46,11,49,
111,48,2,43,39,43,46,176,178,176,56,128,32,21,184,185,
180,49,128,32,164,177,48,3,43,62,45,86,45,221,48,9,
43,82,43,102,43,164,43,226,44,32,44,94,44,156,44,218,
45,24,49,3,43,90,43,94,43,98,55,128,4,16,56,128,
4,17,57,128,4,18,50,10,43,124,43,128,43,132,43,136,
43,140,43,144,43,148,43,152,43,156,43,160,48,128,4,19,
49,128,4,20,50,128,4,21,51,128,4,1,52,128,4,22,
53,128,4,23,54,128,4,24,55,128,4,25,56,128,4,26,
57,128,4,27,51,10,43,186,43,190,43,194,43,198,43,202,
43,206,43,210,43,214,43,218,43,222,48,128,4,28,49,128,
4,29,50,128,4,30,51,128,4,31,52,128,4,32,53,128,
4,33,54,128,4,34,55,128,4,35,56,128,4,36,57,128,
4,37,52,10,43,248,43,252,44,0,44,4,44,8,44,12,
44,16,44,20,44,24,44,28,48,128,4,38,49,128,4,39,
50,128,4,40,51,128,4,41,52,128,4,42,53,128,4,43,
54,128,4,44,55,128,4,45,56,128,4,46,57,128,4,47,
53,10,44,54,44,58,44,62,44,66,44,70,44,74,44,78,
44,82,44,86,44,90,48,128,4,144,49,128,4,2,50,128,
4,3,51,128,4,4,52,128,4,5,53,128,4,6,54,128,
4,7,55,128,4,8,56,128,4,9,57,128,4,10,54,10,
44,116,44,120,44,124,44,128,44,132,44,136,44,140,44,144,
44,148,44,152,48,128,4,11,49,128,4,12,50,128,4,14,
51,128,246,196,52,128,246,197,53,128,4,48,54,128,4,49,
55,128,4,50,56,128,4,51,57,128,4,52,55,10,44,178,
44,182,44,186,44,190,44,194,44,198,44,202,44,206,44,210,
44,214,48,128,4,53,49,128,4,81,50,128,4,54,51,128,
4,55,52,128,4,56,53,128,4,57,54,128,4,58,55,128,
4,59,56,128,4,60,57,128,4,61,56,10,44,240,44,244,
44,248,44,252,45,0,45,4,45,8,45,12,45,16,45,20,
48,128,4,62,49,128,4,63,50,128,4,64,51,128,4,65,
52,128,4,66,53,128,4,67,54,128,4,68,55,128,4,69,
56,128,4,70,57,128,4,71,57,10,45,46,45,50,45,54,
45,58,45,62,45,66,45,70,45,74,45,78,45,82,48,128,
4,72,49,128,4,73,50,128,4,74,51,128,4,75,52,128,
4,76,53,128,4,77,54,128,4,78,55,128,4,79,56,128,
4,145,57,128,4,82,49,4,45,96,45,158,45,163,45,189,
48,10,45,118,45,122,45,126,45,130,45,134,45,138,45,142,
45,146,45,150,45,154,48,128,4,83,49,128,4,84,50,128,
4,85,51,128,4,86,52,128,4,87,53,128,4,88,54,128,
4,89,55,128,4,90,56,128,4,91,57,128,4,92,177,48,
128,4,94,52,4,45,173,45,177,45,181,45,185,53,128,4,
15,54,128,4,98,55,128,4,114,56,128,4,116,57,5,45,
201,45,205,45,209,45,213,45,217,50,128,246,198,51,128,4,
95,52,128,4,99,53,128,4,115,54,128,4,117,56,2,45,
227,45,241,51,2,45,233,45,237,49,128,246,199,50,128,246,
200,180,54,128,4,217,178,185,57,128,32,14,179,48,2,46,
3,46,7,48,128,32,15,49,128,32,13,181,55,7,46,28,
46,98,47,163,47,240,48,197,49,34,49,105,51,2,46,34,
46,48,56,2,46,40,46,44,49,128,6,106,56,128,6,12,
57,8,46,66,46,70,46,74,46,78,46,82,46,86,46,90,
46,94,50,128,6,96,51,128,6,97,52,128,6,98,53,128,
6,99,54,128,6,100,55,128,6,101,56,128,6,102,57,128,
6,103,52,7,46,114,46,146,46,208,47,14,47,46,47,102,
47,158,48,5,46,126,46,130,46,134,46,138,46,142,48,128,
6,104,49,128,6,105,51,128,6,27,55,128,6,31,57,128,
6,33,49,10,46,168,46,172,46,176,46,180,46,184,46,188,
46,192,46,196,46,200,46,204,48,128,6,34,49,128,6,35,
50,128,6,36,51,128,6,37,52,128,6,38,53,128,6,39,
54,128,6,40,55,128,6,41,56,128,6,42,57,128,6,43,
50,10,46,230,46,234,46,238,46,242,46,246,46,250,46,254,
47,2,47,6,47,10,48,128,6,44,49,128,6,45,50,128,
6,46,51,128,6,47,52,128,6,48,53,128,6,49,54,128,
6,50,55,128,6,51,56,128,6,52,57,128,6,53,51,5,
47,26,47,30,47,34,47,38,47,42,48,128,6,54,49,128,
6,55,50,128,6,56,51,128,6,57,52,128,6,58,52,9,
47,66,47,70,47,74,47,78,47,82,47,86,47,90,47,94,
47,98,48,128,6,64,49,128,6,65,50,128,6,66,51,128,
6,67,52,128,6,68,53,128,6,69,54,128,6,70,56,128,
6,72,57,128,6,73,53,9,47,122,47,126,47,130,47,134,
47,138,47,142,47,146,47,150,47,154,48,128,6,74,49,128,
6,75,50,128,6,76,51,128,6,77,52,128,6,78,53,128,
6,79,54,128,6,80,55,128,6,81,56,128,6,82,183,48,
128,6,71,53,3,47,171,47,203,47,235,48,5,47,183,47,
187,47,191,47,195,47,199,53,128,6,164,54,128,6,126,55,
128,6,134,56,128,6,152,57,128,6,175,49,5,47,215,47,
219,47,223,47,227,47,231,49,128,6,121,50,128,6,136,51,
128,6,145,52,128,6,186,57,128,6,210,179,52,128,6,213,
54,7,48,0,48,5,48,10,48,15,48,53,48,115,48,177,
179,54,128,32,170,180,53,128,5,190,181,56,128,5,195,54,
6,48,29,48,33,48,37,48,41,48,45,48,49,52,128,5,
208,53,128,5,209,54,128,5,210,55,128,5,211,56,128,5,
212,57,128,5,213,55,10,48,75,48,79,48,83,48,87,48,
91,48,95,48,99,48,103,48,107,48,111,48,128,5,214,49,
128,5,215,50,128,5,216,51,128,5,217,52,128,5,218,53,
128,5,219,54,128,5,220,55,128,5,221,56,128,5,222,57,
128,5,223,56,10,48,137,48,141,48,145,48,149,48,153,48,
157,48,161,48,165,48,169,48,173,48,128,5,224,49,128,5,
225,50,128,5,226,51,128,5,227,52,128,5,228,53,128,5,
229,54,128,5,230,55,128,5,231,56,128,5,232,57,128,5,
233,57,3,48,185,48,189,48,193,48,128,5,234,52,128,251,
42,53,128,251,43,55,4,48,207,48,221,48,241,48,246,48,
2,48,213,48,217,48,128,251,75,53,128,251,31,49,3,48,
229,48,233,48,237,54,128,5,240,55,128,5,241,56,128,5,
242,178,51,128,251,53,57,7,49,6,49,10,49,14,49,18,
49,22,49,26,49,30,51,128,5,180,52,128,5,181,53,128,
5,182,54,128,5,187,55,128,5,184,56,128,5,183,57,128,
5,176,56,3,49,42,49,86,49,91,48,7,49,58,49,62,
49,66,49,70,49,74,49,78,49,82,48,128,5,178,49,128,
5,177,50,128,5,179,51,128,5,194,52,128,5,193,54,128,
5,185,55,128,5,188,179,57,128,5,189,52,2,49,97,49,
101,49,128,5,191,50,128,5,192,185,178,57,128,2,188,54,
3,49,119,49,178,49,185,49,4,49,129,49,145,49,151,49,
172,50,2,49,135,49,140,180,56,128,33,5,184,57,128,33,
19,179,181,50,128,33,22,181,55,3,49,160,49,164,49,168,
51,128,32,44,52,128,32,45,53,128,32,46,182,182,52,128,
32,12,179,177,182,55,128,6,109,180,185,179,55,128,2,189,
103,2,49,198,49,205,242,225,246,101,128,0,224,117,2,49,
211,49,220,234,225,242,225,244,105,128,10,133,242,237,245,235,
232,105,128,10,5,104,2,49,235,49,245,233,242,225,231,225,
238,97,128,48,66,239,239,235,225,226,239,246,101,128,30,163,
105,7,50,16,50,41,50,48,50,60,50,85,50,101,50,181,
98,2,50,22,50,31,229,238,231,225,236,105,128,9,144,239,
240,239,237,239,230,111,128,49,30,228,229,246,97,128,9,16,
229,227,249,242,233,236,236,233,99,128,4,213,231,117,2,50,
67,50,76,234,225,242,225,244,105,128,10,144,242,237,245,235,
232,105,128,10,16,237,225,244,242,225,231,245,242,237,245,235,
232,105,128,10,72,110,5,50,113,50,122,50,136,50,152,50,
167,225,242,225,226,233,99,128,6,57,230,233,238,225,236,225,
242,225,226,233,99,128,254,202,233,238,233,244,233,225,236,225,
242,225,226,233,99,128,254,203,237,229,228,233,225,236,225,242,
225,226,233,99,128,254,204,246,229,242,244,229,228,226,242,229,
246,101,128,2,3,246,239,247,229,236,243,233,231,110,3,50,
197,50,207,50,214,226,229,238,231,225,236,105,128,9,200,228,
229,246,97,128,9,72,231,245,234,225,242,225,244,105,128,10,
200,107,2,50,231,50,255,225,244,225,235,225,238,97,129,48,
162,50,243,232,225,236,230,247,233,228,244,104,128,255,113,239,
242,229,225,110,128,49,79,108,3,51,15,52,71,52,80,101,
2,51,21,52,66,102,136,5,208,51,41,51,50,51,65,51,
79,51,168,51,182,52,37,52,51,225,242,225,226,233,99,128,
6,39,228,225,231,229,243,232,232,229,226,242,229,119,128,251,
48,230,233,238,225,236,225,242,225,226,233,99,128,254,142,104,
2,51,85,51,160,225,237,250,97,2,51,94,51,127,225,226,
239,246,101,2,51,104,51,113,225,242,225,226,233,99,128,6,
35,230,233,238,225,236,225,242,225,226,233,99,128,254,132,226,
229,236,239,119,2,51,137,51,146,225,242,225,226,233,99,128,
6,37,230,233,238,225,236,225,242,225,226,233,99,128,254,136,
229,226,242,229,119,128,5,208,236,225,237,229,228,232,229,226,
242,229,119,128,251,79,237,97,2,51,189,51,225,228,228,225,
225,226,239,246,101,2,51,202,51,211,225,242,225,226,233,99,
128,6,34,230,233,238,225,236,225,242,225,226,233,99,128,254,
130,235,243,245,242,97,4,51,239,51,248,52,6,52,22,225,
242,225,226,233,99,128,6,73,230,233,238,225,236,225,242,225,
226,233,99,128,254,240,233,238,233,244,233,225,236,225,242,225,
226,233,99,128,254,243,237,229,228,233,225,236,225,242,225,226,
233,99,128,254,244,240,225,244,225,232,232,229,226,242,229,119,
128,251,46,241,225,237,225,244,243,232,229,226,242,229,119,128,
251,47,240,104,128,33,53,236,229,241,245,225,108,128,34,76,
240,232,97,129,3,177,52,88,244,239,238,239,115,128,3,172,
109,4,52,106,52,114,52,125,52,159,225,227,242,239,110,128,
1,1,239,238,239,243,240,225,227,101,128,255,65,240,229,242,
243,225,238,100,130,0,38,52,139,52,151,237,239,238,239,243,
240,225,227,101,128,255,6,243,237,225,236,108,128,247,38,243,
241,245,225,242,101,128,51,194,110,4,52,178,52,189,53,55,
53,65,226,239,240,239,237,239,230,111,128,49,34,103,4,52,
199,52,210,52,224,53,47,226,239,240,239,237,239,230,111,128,
49,36,235,232,225,238,235,232,245,244,232,225,105,128,14,90,
236,101,131,34,32,52,235,53,32,53,39,226,242,225,227,235,
229,116,2,52,247,53,11,236,229,230,116,129,48,8,53,0,
246,229,242,244,233,227,225,108,128,254,63,242,233,231,232,116,
129,48,9,53,21,246,229,242,244,233,227,225,108,128,254,64,
236,229,230,116,128,35,41,242,233,231,232,116,128,35,42,243,
244,242,239,109,128,33,43,239,244,229,236,229,233,97,128,3,
135,117,2,53,71,53,83,228,225,244,244,225,228,229,246,97,
128,9,82,243,246,225,242,97,3,53,95,53,105,53,112,226,
229,238,231,225,236,105,128,9,130,228,229,246,97,128,9,2,
231,245,234,225,242,225,244,105,128,10,130,239,231,239,238,229,
107,128,1,5,112,3,53,140,53,164,53,194,97,2,53,146,
53,158,225,244,239,243,241,245,225,242,101,128,51,0,242,229,
110,128,36,156,239,243,244,242,239,240,232,101,2,53,177,53,
188,225,242,237,229,238,233,225,110,128,5,90,237,239,100,128,
2,188,112,2,53,200,53,205,236,101,128,248,255,242,111,2,
53,212,53,220,225,227,232,229,115,128,34,80,120,2,53,226,
53,246,229,241,245,225,108,129,34,72,53,236,239,242,233,237,
225,231,101,128,34,82,233,237,225,244,229,236,249,229,241,245,
225,108,128,34,69,114,4,54,15,54,42,54,46,54,91,225,
229,97,2,54,23,54,33,229,235,239,242,229,225,110,128,49,
142,235,239,242,229,225,110,128,49,141,99,128,35,18,105,2,
54,52,54,66,231,232,244,232,225,236,230,242,233,238,103,128,
30,154,238,103,130,0,229,54,75,54,83,225,227,245,244,101,
128,1,251,226,229,236,239,119,128,30,1,242,239,119,8,54,
111,54,118,54,247,55,57,55,107,55,162,55,185,56,4,226,
239,244,104,128,33,148,100,3,54,126,54,165,54,212,225,243,
104,4,54,138,54,145,54,152,54,160,228,239,247,110,128,33,
227,236,229,230,116,128,33,224,242,233,231,232,116,128,33,226,
245,112,128,33,225,226,108,5,54,178,54,185,54,192,54,199,
54,207,226,239,244,104,128,33,212,228,239,247,110,128,33,211,
236,229,230,116,128,33,208,242,233,231,232,116,128,33,210,245,
112,128,33,209,239,247,110,131,33,147,54,224,54,231,54,239,
236,229,230,116,128,33,153,242,233,231,232,116,128,33,152,247,
232,233,244,101,128,33,233,104,2,54,253,55,48,229,225,100,
4,55,9,55,19,55,29,55,40,228,239,247,238,237,239,100,
128,2,197,236,229,230,244,237,239,100,128,2,194,242,233,231,
232,244,237,239,100,128,2,195,245,240,237,239,100,128,2,196,
239,242,233,250,229,120,128,248,231,236,229,230,116,131,33,144,
55,70,55,87,55,99,228,226,108,129,33,208,55,78,243,244,
242,239,235,101,128,33,205,239,246,229,242,242,233,231,232,116,
128,33,198,247,232,233,244,101,128,33,230,242,233,231,232,116,
132,33,146,55,123,55,135,55,143,55,154,228,226,236,243,244,
242,239,235,101,128,33,207,232,229,225,246,121,128,39,158,239,
246,229,242,236,229,230,116,128,33,196,247,232,233,244,101,128,
33,232,244,225,98,2,55,170,55,177,236,229,230,116,128,33,
228,242,233,231,232,116,128,33,229,245,112,132,33,145,55,198,
55,226,55,244,55,252,100,2,55,204,55,216,110,129,33,149,
55,210,226,243,101,128,33,168,239,247,238,226,225,243,101,128,
33,168,236,229,230,116,129,33,150,55,235,239,230,228,239,247,
110,128,33,197,242,233,231,232,116,128,33,151,247,232,233,244,
101,128,33,231,246,229,242,244,229,120,128,248,230,115,5,56,
25,56,101,56,146,56,229,56,239,99,2,56,31,56,83,233,
105,2,56,38,56,61,227,233,242,227,245,109,129,0,94,56,
49,237,239,238,239,243,240,225,227,101,128,255,62,244,233,236,
228,101,129,0,126,56,71,237,239,238,239,243,240,225,227,101,
128,255,94,242,233,240,116,129,2,81,56,92,244,245,242,238,
229,100,128,2,82,237,225,236,108,2,56,110,56,121,232,233,
242,225,231,225,238,97,128,48,65,235,225,244,225,235,225,238,
97,129,48,161,56,134,232,225,236,230,247,233,228,244,104,128,
255,103,244,229,242,233,115,2,56,156,56,225,107,131,0,42,
56,166,56,194,56,217,97,2,56,172,56,186,236,244,239,238,
229,225,242,225,226,233,99,128,6,109,242,225,226,233,99,128,
6,109,109,2,56,200,56,206,225,244,104,128,34,23,239,238,
239,243,240,225,227,101,128,255,10,243,237,225,236,108,128,254,
97,109,128,32,66,245,240,229,242,233,239,114,128,246,233,249,
237,240,244,239,244,233,227,225,236,236,249,229,241,245,225,108,
128,34,67,116,132,0,64,57,15,57,22,57,34,57,42,233,
236,228,101,128,0,227,237,239,238,239,243,240,225,227,101,128,
255,32,243,237,225,236,108,128,254,107,245,242,238,229,100,128,
2,80,117,6,57,64,57,89,57,96,57,121,57,141,57,157,
98,2,57,70,57,79,229,238,231,225,236,105,128,9,148,239,
240,239,237,239,230,111,128,49,32,228,229,246,97,128,9,20,
231,117,2,57,103,57,112,234,225,242,225,244,105,128,10,148,
242,237,245,235,232,105,128,10,20,236,229,238,231,244,232,237,
225,242,235,226,229,238,231,225,236,105,128,9,215,237,225,244,
242,225,231,245,242,237,245,235,232,105,128,10,76,246,239,247,
229,236,243,233,231,110,3,57,173,57,183,57,190,226,229,238,
231,225,236,105,128,9,204,228,229,246,97,128,9,76,231,245,
234,225,242,225,244,105,128,10,204,246,225,231,242,225,232,225,
228,229,246,97,128,9,61,121,2,57,221,57,233,226,225,242,
237,229,238,233,225,110,128,5,97,233,110,130,5,226,57,242,
58,1,225,236,244,239,238,229,232,229,226,242,229,119,128,251,
32,232,229,226,242,229,119,128,5,226,98,144,0,98,58,46,
58,181,58,192,58,201,58,226,60,11,60,73,60,146,62,72,
62,84,62,127,62,135,62,145,64,15,64,39,64,48,97,7,
58,62,58,72,58,96,58,103,58,128,58,152,58,163,226,229,
238,231,225,236,105,128,9,172,227,235,243,236,225,243,104,129,
0,92,58,84,237,239,238,239,243,240,225,227,101,128,255,60,
228,229,246,97,128,9,44,231,117,2,58,110,58,119,234,225,
242,225,244,105,128,10,172,242,237,245,235,232,105,128,10,44,
104,2,58,134,58,144,233,242,225,231,225,238,97,128,48,112,
244,244,232,225,105,128,14,63,235,225,244,225,235,225,238,97,
128,48,208,114,129,0,124,58,169,237,239,238,239,243,240,225,
227,101,128,255,92,226,239,240,239,237,239,230,111,128,49,5,
227,233,242,227,236,101,128,36,209,228,239,116,2,58,209,58,
218,225,227,227,229,238,116,128,30,3,226,229,236,239,119,128,
30,5,101,6,58,240,59,5,59,28,59,170,59,181,59,193,
225,237,229,228,243,233,248,244,229,229,238,244,232,238,239,244,
229,115,128,38,108,99,2,59,11,59,18,225,245,243,101,128,
34,53,249,242,233,236,236,233,99,128,4,49,104,5,59,40,
59,49,59,63,59,93,59,152,225,242,225,226,233,99,128,6,
40,230,233,238,225,236,225,242,225,226,233,99,128,254,144,105,
2,59,69,59,84,238,233,244,233,225,236,225,242,225,226,233,
99,128,254,145,242,225,231,225,238,97,128,48,121,237,101,2,
59,100,59,113,228,233,225,236,225,242,225,226,233,99,128,254,
146,229,237,105,2,59,121,59,136,238,233,244,233,225,236,225,
242,225,226,233,99,128,252,159,243,239,236,225,244,229,228,225,
242,225,226,233,99,128,252,8,238,239,239,238,230,233,238,225,
236,225,242,225,226,233,99,128,252,109,235,225,244,225,235,225,
238,97,128,48,217,238,225,242,237,229,238,233,225,110,128,5,
98,116,132,5,209,59,205,59,225,59,245,59,254,97,129,3,
178,59,211,243,249,237,226,239,236,231,242,229,229,107,128,3,
208,228,225,231,229,243,104,129,251,49,59,236,232,229,226,242,
229,119,128,251,49,232,229,226,242,229,119,128,5,209,242,225,
230,229,232,229,226,242,229,119,128,251,76,104,2,60,17,60,
67,97,3,60,25,60,35,60,42,226,229,238,231,225,236,105,
128,9,173,228,229,246,97,128,9,45,231,117,2,60,49,60,
58,234,225,242,225,244,105,128,10,173,242,237,245,235,232,105,
128,10,45,239,239,107,128,2,83,105,5,60,85,60,96,60,
107,60,121,60,135,232,233,242,225,231,225,238,97,128,48,115,
235,225,244,225,235,225,238,97,128,48,211,236,225,226,233,225,
236,227,236,233,227,107,128,2,152,238,228,233,231,245,242,237,
245,235,232,105,128,10,2,242,245,243,241,245,225,242,101,128,
51,49,108,3,60,154,62,55,62,66,97,2,60,160,62,50,
227,107,6,60,175,60,184,60,221,61,114,61,169,61,221,227,
233,242,227,236,101,128,37,207,100,2,60,190,60,199,233,225,
237,239,238,100,128,37,198,239,247,238,240,239,233,238,244,233,
238,231,244,242,233,225,238,231,236,101,128,37,188,108,2,60,
227,61,74,101,2,60,233,61,13,230,244,240,239,233,238,244,
233,238,103,2,60,248,61,2,240,239,233,238,244,229,114,128,
37,196,244,242,233,225,238,231,236,101,128,37,192,238,244,233,
227,245,236,225,242,226,242,225,227,235,229,116,2,61,33,61,
53,236,229,230,116,129,48,16,61,42,246,229,242,244,233,227,
225,108,128,254,59,242,233,231,232,116,129,48,17,61,63,246,
229,242,244,233,227,225,108,128,254,60,239,247,229,114,2,61,
83,61,98,236,229,230,244,244,242,233,225,238,231,236,101,128,
37,227,242,233,231,232,244,244,242,233,225,238,231,236,101,128,
37,226,114,2,61,120,61,131,229,227,244,225,238,231,236,101,
128,37,172,233,231,232,244,240,239,233,238,244,233,238,103,2,
61,148,61,158,240,239,233,238,244,229,114,128,37,186,244,242,
233,225,238,231,236,101,128,37,182,115,3,61,177,61,207,61,
215,109,2,61,183,61,195,225,236,236,243,241,245,225,242,101,
128,37,170,233,236,233,238,231,230,225,227,101,128,38,59,241,
245,225,242,101,128,37,160,244,225,114,128,38,5,245,240,112,
2,61,229,62,11,229,114,2,61,236,61,251,236,229,230,244,
244,242,233,225,238,231,236,101,128,37,228,242,233,231,232,244,
244,242,233,225,238,231,236,101,128,37,229,239,233,238,244,233,
238,103,2,62,23,62,39,243,237,225,236,236,244,242,233,225,
238,231,236,101,128,37,180,244,242,233,225,238,231,236,101,128,
37,178,238,107,128,36,35,233,238,229,226,229,236,239,119,128,
30,7,239,227,107,128,37,136,237,239,238,239,243,240,225,227,
101,128,255,66,111,3,62,92,62,105,62,116,226,225,233,237,
225,233,244,232,225,105,128,14,26,232,233,242,225,231,225,238,
97,128,48,124,235,225,244,225,235,225,238,97,128,48,220,240,
225,242,229,110,128,36,157,241,243,241,245,225,242,101,128,51,
195,114,4,62,155,63,149,63,222,64,5,225,99,2,62,162,
63,56,101,3,62,170,62,175,62,243,229,120,128,248,244,236,
229,230,116,133,0,123,62,192,62,197,62,219,62,227,62,232,
226,116,128,248,243,109,2,62,203,62,208,233,100,128,248,242,
239,238,239,243,240,225,227,101,128,255,91,243,237,225,236,108,
128,254,91,244,112,128,248,241,246,229,242,244,233,227,225,108,
128,254,55,242,233,231,232,116,133,0,125,63,5,63,10,63,
32,63,40,63,45,226,116,128,248,254,109,2,63,16,63,21,
233,100,128,248,253,239,238,239,243,240,225,227,101,128,255,93,
243,237,225,236,108,128,254,92,244,112,128,248,252,246,229,242,
244,233,227,225,108,128,254,56,235,229,116,2,63,64,63,106,
236,229,230,116,132,0,91,63,79,63,84,63,89,63,101,226,
116,128,248,240,229,120,128,248,239,237,239,238,239,243,240,225,
227,101,128,255,59,244,112,128,248,238,242,233,231,232,116,132,
0,93,63,122,63,127,63,132,63,144,226,116,128,248,251,229,
120,128,248,250,237,239,238,239,243,240,225,227,101,128,255,61,
244,112,128,248,249,229,246,101,131,2,216,63,161,63,172,63,
178,226,229,236,239,247,227,237,98,128,3,46,227,237,98,128,
3,6,233,238,246,229,242,244,229,100,3,63,193,63,204,63,
210,226,229,236,239,247,227,237,98,128,3,47,227,237,98,128,
3,17,228,239,245,226,236,229,227,237,98,128,3,97,233,228,
231,101,2,63,231,63,242,226,229,236,239,247,227,237,98,128,
3,42,233,238,246,229,242,244,229,228,226,229,236,239,247,227,
237,98,128,3,58,239,235,229,238,226,225,114,128,0,166,115,
2,64,21,64,29,244,242,239,235,101,128,1,128,245,240,229,
242,233,239,114,128,246,234,244,239,240,226,225,114,128,1,131,
117,3,64,56,64,67,64,78,232,233,242,225,231,225,238,97,
128,48,118,235,225,244,225,235,225,238,97,128,48,214,236,108,
2,64,85,64,115,229,116,130,32,34,64,94,64,104,233,238,
246,229,242,243,101,128,37,216,239,240,229,242,225,244,239,114,
128,34,25,243,229,249,101,128,37,206,99,143,0,99,64,156,
65,105,65,116,65,180,65,211,66,48,67,215,68,199,69,43,
69,92,72,84,72,92,72,102,72,114,72,147,97,9,64,176,
64,187,64,197,64,204,64,211,64,236,64,246,65,42,65,51,
225,242,237,229,238,233,225,110,128,5,110,226,229,238,231,225,
236,105,128,9,154,227,245,244,101,128,1,7,228,229,246,97,
128,9,26,231,117,2,64,218,64,227,234,225,242,225,244,105,
128,10,154,242,237,245,235,232,105,128,10,26,236,243,241,245,
225,242,101,128,51,136,238,228,242,225,226,233,238,228,117,4,
65,8,65,18,65,24,65,31,226,229,238,231,225,236,105,128,
9,129,227,237,98,128,3,16,228,229,246,97,128,9,1,231,
245,234,225,242,225,244,105,128,10,129,240,243,236,239,227,107,
128,33,234,114,3,65,59,65,65,65,91,229,239,102,128,33,
5,239,110,130,2,199,65,74,65,85,226,229,236,239,247,227,
237,98,128,3,44,227,237,98,128,3,12,242,233,225,231,229,
242,229,244,245,242,110,128,33,181,226,239,240,239,237,239,230,
111,128,49,24,99,4,65,126,65,133,65,152,65,174,225,242,
239,110,128,1,13,229,228,233,236,236,97,129,0,231,65,144,
225,227,245,244,101,128,30,9,233,242,99,2,65,160,65,165,
236,101,128,36,210,245,237,230,236,229,120,128,1,9,245,242,
108,128,2,85,100,2,65,186,65,202,239,116,129,1,11,65,
193,225,227,227,229,238,116,128,1,11,243,241,245,225,242,101,
128,51,197,101,2,65,217,65,233,228,233,236,236,97,129,0,
184,65,227,227,237,98,128,3,39,238,116,132,0,162,65,246,
66,14,66,26,66,37,105,2,65,252,66,4,231,242,225,228,
101,128,33,3,238,230,229,242,233,239,114,128,246,223,237,239,
238,239,243,240,225,227,101,128,255,224,239,236,228,243,244,249,
236,101,128,247,162,243,245,240,229,242,233,239,114,128,246,224,
104,5,66,60,66,123,66,134,67,62,67,154,97,4,66,70,
66,81,66,91,66,98,225,242,237,229,238,233,225,110,128,5,
121,226,229,238,231,225,236,105,128,9,155,228,229,246,97,128,
9,27,231,117,2,66,105,66,114,234,225,242,225,244,105,128,
10,155,242,237,245,235,232,105,128,10,27,226,239,240,239,237,
239,230,111,128,49,20,101,6,66,148,66,168,66,192,67,4,
67,16,67,37,225,226,235,232,225,243,233,225,238,227,249,242,
233,236,236,233,99,128,4,189,99,2,66,174,66,182,235,237,
225,242,107,128,39,19,249,242,233,236,236,233,99,128,4,71,
100,2,66,198,66,242,229,243,227,229,238,228,229,114,2,66,
211,66,231,225,226,235,232,225,243,233,225,238,227,249,242,233,
236,236,233,99,128,4,191,227,249,242,233,236,236,233,99,128,
4,183,233,229,242,229,243,233,243,227,249,242,233,236,236,233,
99,128,4,245,232,225,242,237,229,238,233,225,110,128,5,115,
235,232,225,235,225,243,243,233,225,238,227,249,242,233,236,236,
233,99,128,4,204,246,229,242,244,233,227,225,236,243,244,242,
239,235,229,227,249,242,233,236,236,233,99,128,4,185,105,129,
3,199,67,68,229,245,227,104,4,67,81,67,116,67,131,67,
140,97,2,67,87,67,102,227,233,242,227,236,229,235,239,242,
229,225,110,128,50,119,240,225,242,229,238,235,239,242,229,225,
110,128,50,23,227,233,242,227,236,229,235,239,242,229,225,110,
128,50,105,235,239,242,229,225,110,128,49,74,240,225,242,229,
238,235,239,242,229,225,110,128,50,9,111,2,67,160,67,210,
227,104,3,67,169,67,191,67,201,225,110,2,67,176,67,184,
231,244,232,225,105,128,14,10,244,232,225,105,128,14,8,233,
238,231,244,232,225,105,128,14,9,239,229,244,232,225,105,128,
14,12,239,107,128,1,136,105,2,67,221,68,67,229,245,99,
5,67,235,68,14,68,29,68,38,68,52,97,2,67,241,68,
0,227,233,242,227,236,229,235,239,242,229,225,110,128,50,118,
240,225,242,229,238,235,239,242,229,225,110,128,50,22,227,233,
242,227,236,229,235,239,242,229,225,110,128,50,104,235,239,242,
229,225,110,128,49,72,240,225,242,229,238,235,239,242,229,225,
110,128,50,8,245,240,225,242,229,238,235,239,242,229,225,110,
128,50,28,242,99,2,68,74,68,169,236,101,132,37,203,68,
87,68,98,68,103,68,127,237,245,236,244,233,240,236,121,128,
34,151,239,116,128,34,153,112,2,68,109,68,115,236,245,115,
128,34,149,239,243,244,225,236,237,225,242,107,128,48,54,247,
233,244,104,2,68,136,68,152,236,229,230,244,232,225,236,230,
226,236,225,227,107,128,37,208,242,233,231,232,244,232,225,236,
230,226,236,225,227,107,128,37,209,245,237,230,236,229,120,130,
2,198,68,182,68,193,226,229,236,239,247,227,237,98,128,3,
45,227,237,98,128,3,2,108,3,68,207,68,213,69,11,229,
225,114,128,35,39,233,227,107,4,68,225,68,236,68,245,68,
255,225,236,246,229,239,236,225,114,128,1,194,228,229,238,244,
225,108,128,1,192,236,225,244,229,242,225,108,128,1,193,242,
229,244,242,239,230,236,229,120,128,1,195,245,98,129,38,99,
69,18,243,245,233,116,2,69,27,69,35,226,236,225,227,107,
128,38,99,247,232,233,244,101,128,38,103,109,3,69,51,69,
65,69,76,227,245,226,229,228,243,241,245,225,242,101,128,51,
164,239,238,239,243,240,225,227,101,128,255,67,243,241,245,225,
242,229,228,243,241,245,225,242,101,128,51,160,111,8,69,110,
69,121,69,208,70,150,71,179,71,210,72,61,72,70,225,242,
237,229,238,233,225,110,128,5,129,236,239,110,131,0,58,69,
133,69,158,69,177,237,239,110,2,69,141,69,149,229,244,225,
242,121,128,32,161,239,243,240,225,227,101,128,255,26,115,2,
69,164,69,170,233,231,110,128,32,161,237,225,236,108,128,254,
85,244,242,233,225,238,231,245,236,225,114,2,69,192,69,202,
232,225,236,230,237,239,100,128,2,209,237,239,100,128,2,208,
109,2,69,214,70,143,237,97,134,0,44,69,231,70,39,70,
50,70,62,70,92,70,115,97,3,69,239,70,9,70,17,226,
239,246,101,2,69,248,69,254,227,237,98,128,3,19,242,233,
231,232,244,227,237,98,128,3,21,227,227,229,238,116,128,246,
195,114,2,70,23,70,30,225,226,233,99,128,6,12,237,229,
238,233,225,110,128,5,93,233,238,230,229,242,233,239,114,128,
246,225,237,239,238,239,243,240,225,227,101,128,255,12,242,229,
246,229,242,243,229,100,2,70,75,70,86,225,226,239,246,229,
227,237,98,128,3,20,237,239,100,128,2,189,115,2,70,98,
70,105,237,225,236,108,128,254,80,245,240,229,242,233,239,114,
128,246,226,244,245,242,238,229,100,2,70,126,70,137,225,226,
239,246,229,227,237,98,128,3,18,237,239,100,128,2,187,240,
225,243,115,128,38,60,110,2,70,156,70,165,231,242,245,229,
238,116,128,34,69,116,2,70,171,70,185,239,245,242,233,238,
244,229,231,242,225,108,128,34,46,242,239,108,142,35,3,70,
219,70,225,70,240,70,255,71,43,71,88,71,102,71,107,71,
112,71,117,71,123,71,128,71,169,71,174,193,195,75,128,0,
6,66,2,70,231,70,236,197,76,128,0,7,83,128,0,8,
67,2,70,246,70,251,193,78,128,0,24,82,128,0,13,68,
3,71,7,71,33,71,38,67,4,71,17,71,21,71,25,71,
29,49,128,0,17,50,128,0,18,51,128,0,19,52,128,0,
20,197,76,128,0,127,204,69,128,0,16,69,5,71,55,71,
59,71,64,71,69,71,74,77,128,0,25,206,81,128,0,5,
207,84,128,0,4,211,67,128,0,27,84,2,71,80,71,84,
66,128,0,23,88,128,0,3,70,2,71,94,71,98,70,128,
0,12,83,128,0,28,199,83,128,0,29,200,84,128,0,9,
204,70,128,0,10,206,193,75,128,0,21,210,83,128,0,30,
83,5,71,140,71,144,71,154,71,159,71,164,73,128,0,15,
79,129,0,14,71,150,84,128,0,2,212,88,128,0,1,213,
66,128,0,26,217,78,128,0,22,213,83,128,0,31,214,84,
128,0,11,240,249,242,233,231,232,116,129,0,169,71,191,115,
2,71,197,71,203,225,238,115,128,248,233,229,242,233,102,128,
246,217,114,2,71,216,72,44,238,229,242,226,242,225,227,235,
229,116,2,71,231,72,9,236,229,230,116,130,48,12,71,242,
71,254,232,225,236,230,247,233,228,244,104,128,255,98,246,229,
242,244,233,227,225,108,128,254,65,242,233,231,232,116,130,48,
13,72,21,72,33,232,225,236,230,247,233,228,244,104,128,255,
99,246,229,242,244,233,227,225,108,128,254,66,240,239,242,225,
244,233,239,238,243,241,245,225,242,101,128,51,127,243,241,245,
225,242,101,128,51,199,246,229,242,235,231,243,241,245,225,242,
101,128,51,198,240,225,242,229,110,128,36,158,242,245,250,229,
233,242,111,128,32,162,243,244,242,229,244,227,232,229,100,128,
2,151,245,114,2,72,121,72,139,236,121,2,72,128,72,134,
225,238,100,128,34,207,239,114,128,34,206,242,229,238,227,121,
128,0,164,249,114,4,72,158,72,166,72,173,72,181,194,242,
229,246,101,128,246,209,198,236,229,120,128,246,210,226,242,229,
246,101,128,246,212,230,236,229,120,128,246,213,100,146,0,100,
72,228,74,110,75,134,75,194,76,114,77,68,77,130,78,59,
78,72,78,81,78,107,78,132,78,141,79,208,79,216,79,227,
79,247,80,19,97,11,72,252,73,7,73,17,73,89,73,152,
73,163,73,174,73,243,74,49,74,55,74,85,225,242,237,229,
238,233,225,110,128,5,100,226,229,238,231,225,236,105,128,9,
166,100,5,73,29,73,38,73,44,73,58,73,74,225,242,225,
226,233,99,128,6,54,229,246,97,128,9,38,230,233,238,225,
236,225,242,225,226,233,99,128,254,190,233,238,233,244,233,225,
236,225,242,225,226,233,99,128,254,191,237,229,228,233,225,236,
225,242,225,226,233,99,128,254,192,103,3,73,97,73,114,73,
128,229,243,104,129,5,188,73,105,232,229,226,242,229,119,128,
5,188,231,229,114,129,32,32,73,122,228,226,108,128,32,33,
117,2,73,134,73,143,234,225,242,225,244,105,128,10,166,242,
237,245,235,232,105,128,10,38,232,233,242,225,231,225,238,97,
128,48,96,235,225,244,225,235,225,238,97,128,48,192,108,3,
73,182,73,191,73,229,225,242,225,226,233,99,128,6,47,229,
116,130,5,211,73,200,73,220,228,225,231,229,243,104,129,251,
51,73,211,232,229,226,242,229,119,128,251,51,232,229,226,242,
229,119,128,5,211,230,233,238,225,236,225,242,225,226,233,99,
128,254,170,237,237,97,3,73,253,74,6,74,18,225,242,225,
226,233,99,128,6,79,236,239,247,225,242,225,226,233,99,128,
6,79,244,225,238,97,2,74,27,74,41,236,244,239,238,229,
225,242,225,226,233,99,128,6,76,242,225,226,233,99,128,6,
76,238,228,97,128,9,100,242,231,97,2,74,63,74,72,232,
229,226,242,229,119,128,5,167,236,229,230,244,232,229,226,242,
229,119,128,5,167,243,233,225,240,238,229,245,237,225,244,225,
227,249,242,233,236,236,233,227,227,237,98,128,4,133,98,3,
74,118,75,115,75,125,108,9,74,138,74,146,75,3,75,11,
75,27,75,38,75,56,75,70,75,81,199,242,225,246,101,128,
246,211,97,2,74,152,74,209,238,231,236,229,226,242,225,227,
235,229,116,2,74,168,74,188,236,229,230,116,129,48,10,74,
177,246,229,242,244,233,227,225,108,128,254,61,242,233,231,232,
116,129,48,11,74,198,246,229,242,244,233,227,225,108,128,254,
62,114,2,74,215,74,236,227,232,233,238,246,229,242,244,229,
228,226,229,236,239,247,227,237,98,128,3,43,242,239,119,2,
74,244,74,251,236,229,230,116,128,33,212,242,233,231,232,116,
128,33,210,228,225,238,228,97,128,9,101,231,242,225,246,101,
129,246,214,75,21,227,237,98,128,3,15,233,238,244,229,231,
242,225,108,128,34,44,236,239,247,236,233,238,101,129,32,23,
75,50,227,237,98,128,3,51,239,246,229,242,236,233,238,229,
227,237,98,128,3,63,240,242,233,237,229,237,239,100,128,2,
186,246,229,242,244,233,227,225,108,2,75,94,75,100,226,225,
114,128,32,22,236,233,238,229,225,226,239,246,229,227,237,98,
128,3,14,239,240,239,237,239,230,111,128,49,9,243,241,245,
225,242,101,128,51,200,99,4,75,144,75,151,75,160,75,187,
225,242,239,110,128,1,15,229,228,233,236,236,97,128,30,17,
233,242,99,2,75,168,75,173,236,101,128,36,211,245,237,230,
236,229,248,226,229,236,239,119,128,30,19,242,239,225,116,128,
1,17,100,4,75,204,76,29,76,39,76,90,97,4,75,214,
75,224,75,231,76,0,226,229,238,231,225,236,105,128,9,161,
228,229,246,97,128,9,33,231,117,2,75,238,75,247,234,225,
242,225,244,105,128,10,161,242,237,245,235,232,105,128,10,33,
108,2,76,6,76,15,225,242,225,226,233,99,128,6,136,230,
233,238,225,236,225,242,225,226,233,99,128,251,137,228,232,225,
228,229,246,97,128,9,92,232,97,3,76,48,76,58,76,65,
226,229,238,231,225,236,105,128,9,162,228,229,246,97,128,9,
34,231,117,2,76,72,76,81,234,225,242,225,244,105,128,10,
162,242,237,245,235,232,105,128,10,34,239,116,2,76,97,76,
106,225,227,227,229,238,116,128,30,11,226,229,236,239,119,128,
30,13,101,8,76,132,76,185,76,192,76,217,76,227,76,238,
77,27,77,63,99,2,76,138,76,175,233,237,225,236,243,229,
240,225,242,225,244,239,114,2,76,156,76,165,225,242,225,226,
233,99,128,6,107,240,229,242,243,233,225,110,128,6,107,249,
242,233,236,236,233,99,128,4,52,231,242,229,101,128,0,176,
232,105,2,76,199,76,208,232,229,226,242,229,119,128,5,173,
242,225,231,225,238,97,128,48,103,233,227,239,240,244,233,99,
128,3,239,235,225,244,225,235,225,238,97,128,48,199,108,2,
76,244,77,11,229,244,101,2,76,252,77,3,236,229,230,116,
128,35,43,242,233,231,232,116,128,35,38,244,97,129,3,180,
77,18,244,245,242,238,229,100,128,1,141,238,239,237,233,238,
225,244,239,242,237,233,238,245,243,239,238,229,238,245,237,229,
242,225,244,239,242,226,229,238,231,225,236,105,128,9,248,250,
104,128,2,164,104,2,77,74,77,124,97,3,77,82,77,92,
77,99,226,229,238,231,225,236,105,128,9,167,228,229,246,97,
128,9,39,231,117,2,77,106,77,115,234,225,242,225,244,105,
128,10,167,242,237,245,235,232,105,128,10,39,239,239,107,128,
2,87,105,6,77,144,77,193,77,253,78,8,78,19,78,29,
97,2,77,150,77,172,236,249,244,233,235,225,244,239,238,239,
115,129,3,133,77,166,227,237,98,128,3,68,237,239,238,100,
129,38,102,77,181,243,245,233,244,247,232,233,244,101,128,38,
98,229,242,229,243,233,115,133,0,168,77,212,77,220,77,231,
77,237,77,245,225,227,245,244,101,128,246,215,226,229,236,239,
247,227,237,98,128,3,36,227,237,98,128,3,8,231,242,225,
246,101,128,246,216,244,239,238,239,115,128,3,133,232,233,242,
225,231,225,238,97,128,48,98,235,225,244,225,235,225,238,97,
128,48,194,244,244,239,237,225,242,107,128,48,3,246,105,2,
78,36,78,47,228,101,129,0,247,78,43,115,128,34,35,243,
233,239,238,243,236,225,243,104,128,34,21,234,229,227,249,242,
233,236,236,233,99,128,4,82,235,243,232,225,228,101,128,37,
147,108,2,78,87,78,98,233,238,229,226,229,236,239,119,128,
30,15,243,241,245,225,242,101,128,51,151,109,2,78,113,78,
121,225,227,242,239,110,128,1,17,239,238,239,243,240,225,227,
101,128,255,68,238,226,236,239,227,107,128,37,132,111,10,78,
163,78,175,78,185,78,196,78,207,79,23,79,28,79,39,79,
154,79,180,227,232,225,228,225,244,232,225,105,128,14,14,228,
229,235,244,232,225,105,128,14,20,232,233,242,225,231,225,238,
97,128,48,105,235,225,244,225,235,225,238,97,128,48,201,236,
236,225,114,132,0,36,78,222,78,233,78,245,79,0,233,238,
230,229,242,233,239,114,128,246,227,237,239,238,239,243,240,225,
227,101,128,255,4,239,236,228,243,244,249,236,101,128,247,36,
115,2,79,6,79,13,237,225,236,108,128,254,105,245,240,229,
242,233,239,114,128,246,228,238,103,128,32,171,242,245,243,241,
245,225,242,101,128,51,38,116,6,79,53,79,70,79,92,79,
103,79,135,79,142,225,227,227,229,238,116,129,2,217,79,64,
227,237,98,128,3,7,226,229,236,239,247,99,2,79,81,79,
86,237,98,128,3,35,239,237,98,128,3,35,235,225,244,225,
235,225,238,97,128,48,251,236,229,243,115,2,79,112,79,116,
105,128,1,49,106,129,246,190,79,122,243,244,242,239,235,229,
232,239,239,107,128,2,132,237,225,244,104,128,34,197,244,229,
228,227,233,242,227,236,101,128,37,204,245,226,236,229,249,239,
228,240,225,244,225,104,129,251,31,79,171,232,229,226,242,229,
119,128,251,31,247,238,244,225,227,107,2,79,191,79,202,226,
229,236,239,247,227,237,98,128,3,30,237,239,100,128,2,213,
240,225,242,229,110,128,36,159,243,245,240,229,242,233,239,114,
128,246,235,116,2,79,233,79,239,225,233,108,128,2,86,239,
240,226,225,114,128,1,140,117,2,79,253,80,8,232,233,242,
225,231,225,238,97,128,48,101,235,225,244,225,235,225,238,97,
128,48,197,122,132,1,243,80,31,80,40,80,59,80,96,225,
236,244,239,238,101,128,2,163,99,2,80,46,80,53,225,242,
239,110,128,1,198,245,242,108,128,2,165,101,2,80,65,80,
85,225,226,235,232,225,243,233,225,238,227,249,242,233,236,236,
233,99,128,4,225,227,249,242,233,236,236,233,99,128,4,85,
232,229,227,249,242,233,236,236,233,99,128,4,95,101,151,0,
101,80,159,80,178,80,212,81,186,81,248,82,25,82,37,82,
60,82,113,83,225,84,27,84,129,84,245,85,124,85,199,85,
230,86,36,86,89,87,24,87,157,87,177,87,221,88,56,97,
2,80,165,80,172,227,245,244,101,128,0,233,242,244,104,128,
38,65,98,3,80,186,80,195,80,205,229,238,231,225,236,105,
128,9,143,239,240,239,237,239,230,111,128,49,28,242,229,246,
101,128,1,21,99,5,80,224,81,41,81,55,81,87,81,176,
97,2,80,230,81,35,238,228,242,97,3,80,241,80,248,81,
3,228,229,246,97,128,9,13,231,245,234,225,242,225,244,105,
128,10,141,246,239,247,229,236,243,233,231,110,2,81,17,81,
24,228,229,246,97,128,9,69,231,245,234,225,242,225,244,105,
128,10,197,242,239,110,128,1,27,229,228,233,236,236,225,226,
242,229,246,101,128,30,29,104,2,81,61,81,72,225,242,237,
229,238,233,225,110,128,5,101,249,233,247,238,225,242,237,229,
238,233,225,110,128,5,135,233,242,99,2,81,95,81,100,236,
101,128,36,212,245,237,230,236,229,120,134,0,234,81,121,81,
129,81,137,81,148,81,156,81,168,225,227,245,244,101,128,30,
191,226,229,236,239,119,128,30,25,228,239,244,226,229,236,239,
119,128,30,199,231,242,225,246,101,128,30,193,232,239,239,235,
225,226,239,246,101,128,30,195,244,233,236,228,101,128,30,197,
249,242,233,236,236,233,99,128,4,84,100,4,81,196,81,206,
81,212,81,222,226,236,231,242,225,246,101,128,2,5,229,246,
97,128,9,15,233,229,242,229,243,233,115,128,0,235,239,116,
130,1,23,81,231,81,240,225,227,227,229,238,116,128,1,23,
226,229,236,239,119,128,30,185,101,2,81,254,82,9,231,245,
242,237,245,235,232,105,128,10,15,237,225,244,242,225,231,245,
242,237,245,235,232,105,128,10,71,230,227,249,242,233,236,236,
233,99,128,4,68,103,2,82,43,82,50,242,225,246,101,128,
0,232,245,234,225,242,225,244,105,128,10,143,104,4,82,70,
82,81,82,92,82,102,225,242,237,229,238,233,225,110,128,5,
103,226,239,240,239,237,239,230,111,128,49,29,233,242,225,231,
225,238,97,128,48,72,239,239,235,225,226,239,246,101,128,30,
187,105,4,82,123,82,134,83,192,83,207,226,239,240,239,237,
239,230,111,128,49,31,231,232,116,142,0,56,82,168,82,177,
82,187,82,217,82,224,83,6,83,31,83,76,83,110,83,122,
83,133,83,166,83,174,83,185,225,242,225,226,233,99,128,6,
104,226,229,238,231,225,236,105,128,9,238,227,233,242,227,236,
101,129,36,103,82,198,233,238,246,229,242,243,229,243,225,238,
243,243,229,242,233,102,128,39,145,228,229,246,97,128,9,110,
229,229,110,2,82,232,82,241,227,233,242,227,236,101,128,36,
113,112,2,82,247,82,254,225,242,229,110,128,36,133,229,242,
233,239,100,128,36,153,231,117,2,83,13,83,22,234,225,242,
225,244,105,128,10,238,242,237,245,235,232,105,128,10,110,104,
2,83,37,83,63,97,2,83,43,83,54,227,235,225,242,225,
226,233,99,128,6,104,238,231,250,232,239,117,128,48,40,238,
239,244,229,226,229,225,237,229,100,128,38,107,105,2,83,82,
83,100,228,229,239,231,242,225,240,232,233,227,240,225,242,229,
110,128,50,39,238,230,229,242,233,239,114,128,32,136,237,239,
238,239,243,240,225,227,101,128,255,24,239,236,228,243,244,249,
236,101,128,247,56,112,2,83,139,83,146,225,242,229,110,128,
36,123,229,114,2,83,153,83,159,233,239,100,128,36,143,243,
233,225,110,128,6,248,242,239,237,225,110,128,33,119,243,245,
240,229,242,233,239,114,128,32,120,244,232,225,105,128,14,88,
238,246,229,242,244,229,228,226,242,229,246,101,128,2,7,239,
244,233,230,233,229,228,227,249,242,233,236,236,233,99,128,4,
101,107,2,83,231,83,255,225,244,225,235,225,238,97,129,48,
168,83,243,232,225,236,230,247,233,228,244,104,128,255,116,111,
2,84,5,84,20,238,235,225,242,231,245,242,237,245,235,232,
105,128,10,116,242,229,225,110,128,49,84,108,3,84,35,84,
46,84,107,227,249,242,233,236,236,233,99,128,4,59,101,2,
84,52,84,59,237,229,238,116,128,34,8,246,229,110,3,84,
69,84,78,84,99,227,233,242,227,236,101,128,36,106,112,2,
84,84,84,91,225,242,229,110,128,36,126,229,242,233,239,100,
128,36,146,242,239,237,225,110,128,33,122,236,233,240,243,233,
115,129,32,38,84,118,246,229,242,244,233,227,225,108,128,34,
238,109,5,84,141,84,169,84,180,84,200,84,211,225,227,242,
239,110,130,1,19,84,153,84,161,225,227,245,244,101,128,30,
23,231,242,225,246,101,128,30,21,227,249,242,233,236,236,233,
99,128,4,60,228,225,243,104,129,32,20,84,189,246,229,242,
244,233,227,225,108,128,254,49,239,238,239,243,240,225,227,101,
128,255,69,112,2,84,217,84,237,232,225,243,233,243,237,225,
242,235,225,242,237,229,238,233,225,110,128,5,91,244,249,243,
229,116,128,34,5,110,6,85,3,85,14,85,25,85,69,85,
101,85,116,226,239,240,239,237,239,230,111,128,49,35,227,249,
242,233,236,236,233,99,128,4,61,100,2,85,31,85,50,225,
243,104,129,32,19,85,39,246,229,242,244,233,227,225,108,128,
254,50,229,243,227,229,238,228,229,242,227,249,242,233,236,236,
233,99,128,4,163,103,130,1,75,85,77,85,88,226,239,240,
239,237,239,230,111,128,49,37,232,229,227,249,242,233,236,236,
233,99,128,4,165,232,239,239,235,227,249,242,233,236,236,233,
99,128,4,200,243,240,225,227,101,128,32,2,111,3,85,132,
85,140,85,149,231,239,238,229,107,128,1,25,235,239,242,229,
225,110,128,49,83,240,229,110,130,2,91,85,159,85,168,227,
236,239,243,229,100,128,2,154,242,229,246,229,242,243,229,100,
130,2,92,85,183,85,192,227,236,239,243,229,100,128,2,94,
232,239,239,107,128,2,93,112,2,85,205,85,212,225,242,229,
110,128,36,160,243,233,236,239,110,129,3,181,85,222,244,239,
238,239,115,128,3,173,241,117,2,85,237,86,25,225,108,130,
0,61,85,246,86,2,237,239,238,239,243,240,225,227,101,128,
255,29,115,2,86,8,86,15,237,225,236,108,128,254,102,245,
240,229,242,233,239,114,128,32,124,233,246,225,236,229,238,227,
101,128,34,97,114,3,86,44,86,55,86,66,226,239,240,239,
237,239,230,111,128,49,38,227,249,242,233,236,236,233,99,128,
4,64,229,246,229,242,243,229,100,129,2,88,86,78,227,249,
242,233,236,236,233,99,128,4,77,115,6,86,103,86,114,86,
134,86,215,87,4,87,14,227,249,242,233,236,236,233,99,128,
4,65,228,229,243,227,229,238,228,229,242,227,249,242,233,236,
236,233,99,128,4,171,104,132,2,131,86,146,86,153,86,184,
86,199,227,245,242,108,128,2,134,239,242,116,2,86,161,86,
168,228,229,246,97,128,9,14,246,239,247,229,236,243,233,231,
238,228,229,246,97,128,9,70,242,229,246,229,242,243,229,228,
236,239,239,112,128,1,170,243,241,245,225,244,242,229,246,229,
242,243,229,100,128,2,133,237,225,236,108,2,86,224,86,235,
232,233,242,225,231,225,238,97,128,48,71,235,225,244,225,235,
225,238,97,129,48,167,86,248,232,225,236,230,247,233,228,244,
104,128,255,106,244,233,237,225,244,229,100,128,33,46,245,240,
229,242,233,239,114,128,246,236,116,5,87,36,87,62,87,66,
87,83,87,149,97,130,3,183,87,44,87,54,242,237,229,238,
233,225,110,128,5,104,244,239,238,239,115,128,3,174,104,128,
0,240,233,236,228,101,129,30,189,87,75,226,229,236,239,119,
128,30,27,238,225,232,244,97,3,87,95,87,127,87,136,230,
239,245,235,104,2,87,105,87,114,232,229,226,242,229,119,128,
5,145,236,229,230,244,232,229,226,242,229,119,128,5,145,232,
229,226,242,229,119,128,5,145,236,229,230,244,232,229,226,242,
229,119,128,5,145,245,242,238,229,100,128,1,221,117,2,87,
163,87,172,235,239,242,229,225,110,128,49,97,242,111,128,32,
172,246,239,247,229,236,243,233,231,110,3,87,193,87,203,87,
210,226,229,238,231,225,236,105,128,9,199,228,229,246,97,128,
9,71,231,245,234,225,242,225,244,105,128,10,199,120,2,87,
227,88,44,227,236,225,109,132,0,33,87,242,87,253,88,24,
88,36,225,242,237,229,238,233,225,110,128,5,92,100,2,88,
3,88,8,226,108,128,32,60,239,247,110,129,0,161,88,16,
243,237,225,236,108,128,247,161,237,239,238,239,243,240,225,227,
101,128,255,1,243,237,225,236,108,128,247,33,233,243,244,229,
238,244,233,225,108,128,34,3,250,104,131,2,146,88,67,88,
86,88,97,99,2,88,73,88,80,225,242,239,110,128,1,239,
245,242,108,128,2,147,242,229,246,229,242,243,229,100,128,1,
185,244,225,233,108,128,1,186,102,140,0,102,88,132,88,214,
88,225,88,234,88,246,89,93,89,109,91,117,91,130,91,156,
93,33,93,41,97,4,88,142,88,149,88,160,88,171,228,229,
246,97,128,9,94,231,245,242,237,245,235,232,105,128,10,94,
232,242,229,238,232,229,233,116,128,33,9,244,232,97,3,88,
181,88,190,88,202,225,242,225,226,233,99,128,6,78,236,239,
247,225,242,225,226,233,99,128,6,78,244,225,238,225,242,225,
226,233,99,128,6,75,226,239,240,239,237,239,230,111,128,49,
8,227,233,242,227,236,101,128,36,213,228,239,244,225,227,227,
229,238,116,128,30,31,101,3,88,254,89,76,89,86,104,4,
89,8,89,31,89,45,89,61,225,114,2,89,15,89,22,225,
226,233,99,128,6,65,237,229,238,233,225,110,128,5,134,230,
233,238,225,236,225,242,225,226,233,99,128,254,210,233,238,233,
244,233,225,236,225,242,225,226,233,99,128,254,211,237,229,228,
233,225,236,225,242,225,226,233,99,128,254,212,233,227,239,240,
244,233,99,128,3,229,237,225,236,101,128,38,64,102,130,251,
0,89,101,89,105,105,128,251,3,108,128,251,4,105,136,251,
1,89,129,89,169,89,180,89,202,90,68,90,85,90,93,90,
106,230,244,229,229,110,2,89,139,89,148,227,233,242,227,236,
101,128,36,110,112,2,89,154,89,161,225,242,229,110,128,36,
130,229,242,233,239,100,128,36,150,231,245,242,229,228,225,243,
104,128,32,18,236,236,229,100,2,89,189,89,195,226,239,120,
128,37,160,242,229,227,116,128,37,172,238,225,108,5,89,216,
89,255,90,16,90,33,90,49,235,225,102,130,5,218,89,226,
89,246,228,225,231,229,243,104,129,251,58,89,237,232,229,226,
242,229,119,128,251,58,232,229,226,242,229,119,128,5,218,237,
229,109,129,5,221,90,7,232,229,226,242,229,119,128,5,221,
238,245,110,129,5,223,90,24,232,229,226,242,229,119,128,5,
223,240,101,129,5,227,90,40,232,229,226,242,229,119,128,5,
227,244,243,225,228,105,129,5,229,90,59,232,229,226,242,229,
119,128,5,229,242,243,244,244,239,238,229,227,232,233,238,229,
243,101,128,2,201,243,232,229,249,101,128,37,201,244,225,227,
249,242,233,236,236,233,99,128,4,115,246,101,142,0,53,90,
139,90,148,90,158,90,188,90,195,90,205,90,230,91,1,91,
35,91,47,91,58,91,91,91,99,91,110,225,242,225,226,233,
99,128,6,101,226,229,238,231,225,236,105,128,9,235,227,233,
242,227,236,101,129,36,100,90,169,233,238,246,229,242,243,229,
243,225,238,243,243,229,242,233,102,128,39,142,228,229,246,97,
128,9,107,229,233,231,232,244,232,115,128,33,93,231,117,2,
90,212,90,221,234,225,242,225,244,105,128,10,235,242,237,245,
235,232,105,128,10,107,232,97,2,90,237,90,248,227,235,225,
242,225,226,233,99,128,6,101,238,231,250,232,239,117,128,48,
37,105,2,91,7,91,25,228,229,239,231,242,225,240,232,233,
227,240,225,242,229,110,128,50,36,238,230,229,242,233,239,114,
128,32,133,237,239,238,239,243,240,225,227,101,128,255,21,239,
236,228,243,244,249,236,101,128,247,53,112,2,91,64,91,71,
225,242,229,110,128,36,120,229,114,2,91,78,91,84,233,239,
100,128,36,140,243,233,225,110,128,6,245,242,239,237,225,110,
128,33,116,243,245,240,229,242,233,239,114,128,32,117,244,232,
225,105,128,14,85,108,129,251,2,91,123,239,242,233,110,128,
1,146,109,2,91,136,91,147,239,238,239,243,240,225,227,101,
128,255,70,243,241,245,225,242,101,128,51,153,111,4,91,166,
91,188,91,200,91,207,230,97,2,91,173,91,181,238,244,232,
225,105,128,14,31,244,232,225,105,128,14,29,238,231,237,225,
238,244,232,225,105,128,14,79,242,225,236,108,128,34,0,245,
114,142,0,52,91,240,91,249,92,3,92,33,92,40,92,65,
92,92,92,126,92,138,92,157,92,168,92,201,92,209,92,220,
225,242,225,226,233,99,128,6,100,226,229,238,231,225,236,105,
128,9,234,227,233,242,227,236,101,129,36,99,92,14,233,238,
246,229,242,243,229,243,225,238,243,243,229,242,233,102,128,39,
141,228,229,246,97,128,9,106,231,117,2,92,47,92,56,234,
225,242,225,244,105,128,10,234,242,237,245,235,232,105,128,10,
106,232,97,2,92,72,92,83,227,235,225,242,225,226,233,99,
128,6,100,238,231,250,232,239,117,128,48,36,105,2,92,98,
92,116,228,229,239,231,242,225,240,232,233,227,240,225,242,229,
110,128,50,35,238,230,229,242,233,239,114,128,32,132,237,239,
238,239,243,240,225,227,101,128,255,20,238,245,237,229,242,225,
244,239,242,226,229,238,231,225,236,105,128,9,247,239,236,228,
243,244,249,236,101,128,247,52,112,2,92,174,92,181,225,242,
229,110,128,36,119,229,114,2,92,188,92,194,233,239,100,128,
36,139,243,233,225,110,128,6,244,242,239,237,225,110,128,33,
115,243,245,240,229,242,233,239,114,128,32,116,116,2,92,226,
93,8,229,229,110,2,92,234,92,243,227,233,242,227,236,101,
128,36,109,112,2,92,249,93,0,225,242,229,110,128,36,129,
229,242,233,239,100,128,36,149,104,2,93,14,93,19,225,105,
128,14,84,244,239,238,229,227,232,233,238,229,243,101,128,2,
203,240,225,242,229,110,128,36,161,242,97,2,93,48,93,56,
227,244,233,239,110,128,32,68,238,99,128,32,163,103,144,0,
103,93,97,94,43,94,66,94,127,94,144,95,65,96,58,96,
143,96,156,97,14,97,39,97,67,97,89,98,34,98,56,98,
158,97,9,93,117,93,127,93,134,93,141,93,205,93,230,93,
241,93,252,94,30,226,229,238,231,225,236,105,128,9,151,227,
245,244,101,128,1,245,228,229,246,97,128,9,23,102,4,93,
151,93,160,93,174,93,190,225,242,225,226,233,99,128,6,175,
230,233,238,225,236,225,242,225,226,233,99,128,251,147,233,238,
233,244,233,225,236,225,242,225,226,233,99,128,251,148,237,229,
228,233,225,236,225,242,225,226,233,99,128,251,149,231,117,2,
93,212,93,221,234,225,242,225,244,105,128,10,151,242,237,245,
235,232,105,128,10,23,232,233,242,225,231,225,238,97,128,48,
76,235,225,244,225,235,225,238,97,128,48,172,237,237,97,130,
3,179,94,6,94,19,236,225,244,233,238,243,237,225,236,108,
128,2,99,243,245,240,229,242,233,239,114,128,2,224,238,231,
233,225,227,239,240,244,233,99,128,3,235,98,2,94,49,94,
59,239,240,239,237,239,230,111,128,49,13,242,229,246,101,128,
1,31,99,4,94,76,94,83,94,92,94,114,225,242,239,110,
128,1,231,229,228,233,236,236,97,128,1,35,233,242,99,2,
94,100,94,105,236,101,128,36,214,245,237,230,236,229,120,128,
1,29,239,237,237,225,225,227,227,229,238,116,128,1,35,228,
239,116,129,1,33,94,135,225,227,227,229,238,116,128,1,33,
101,6,94,158,94,169,94,180,94,191,94,210,95,56,227,249,
242,233,236,236,233,99,128,4,51,232,233,242,225,231,225,238,
97,128,48,82,235,225,244,225,235,225,238,97,128,48,178,239,
237,229,244,242,233,227,225,236,236,249,229,241,245,225,108,128,
34,81,114,3,94,218,95,11,95,21,229,243,104,3,94,228,
94,243,94,252,225,227,227,229,238,244,232,229,226,242,229,119,
128,5,156,232,229,226,242,229,119,128,5,243,237,245,241,228,
225,237,232,229,226,242,229,119,128,5,157,237,225,238,228,226,
236,115,128,0,223,243,232,225,249,233,109,2,95,32,95,47,
225,227,227,229,238,244,232,229,226,242,229,119,128,5,158,232,
229,226,242,229,119,128,5,244,244,225,237,225,242,107,128,48,
19,104,5,95,77,95,210,96,17,96,42,96,48,97,4,95,
87,95,97,95,120,95,145,226,229,238,231,225,236,105,128,9,
152,100,2,95,103,95,114,225,242,237,229,238,233,225,110,128,
5,114,229,246,97,128,9,24,231,117,2,95,127,95,136,234,
225,242,225,244,105,128,10,152,242,237,245,235,232,105,128,10,
24,233,110,4,95,156,95,165,95,179,95,195,225,242,225,226,
233,99,128,6,58,230,233,238,225,236,225,242,225,226,233,99,
128,254,206,233,238,233,244,233,225,236,225,242,225,226,233,99,
128,254,207,237,229,228,233,225,236,225,242,225,226,233,99,128,
254,208,101,3,95,218,95,239,96,0,237,233,228,228,236,229,
232,239,239,235,227,249,242,233,236,236,233,99,128,4,149,243,
244,242,239,235,229,227,249,242,233,236,236,233,99,128,4,147,
245,240,244,245,242,238,227,249,242,233,236,236,233,99,128,4,
145,232,97,2,96,24,96,31,228,229,246,97,128,9,90,231,
245,242,237,245,235,232,105,128,10,90,239,239,107,128,2,96,
250,243,241,245,225,242,101,128,51,147,105,3,96,66,96,77,
96,88,232,233,242,225,231,225,238,97,128,48,78,235,225,244,
225,235,225,238,97,128,48,174,109,2,96,94,96,105,225,242,
237,229,238,233,225,110,128,5,99,229,108,130,5,210,96,114,
96,134,228,225,231,229,243,104,129,251,50,96,125,232,229,226,
242,229,119,128,251,50,232,229,226,242,229,119,128,5,210,234,
229,227,249,242,233,236,236,233,99,128,4,83,236,239,244,244,
225,108,2,96,167,96,184,233,238,246,229,242,244,229,228,243,
244,242,239,235,101,128,1,190,243,244,239,112,132,2,148,96,
199,96,210,96,216,96,248,233,238,246,229,242,244,229,100,128,
2,150,237,239,100,128,2,192,242,229,246,229,242,243,229,100,
130,2,149,96,231,96,237,237,239,100,128,2,193,243,245,240,
229,242,233,239,114,128,2,228,243,244,242,239,235,101,129,2,
161,97,3,242,229,246,229,242,243,229,100,128,2,162,109,2,
97,20,97,28,225,227,242,239,110,128,30,33,239,238,239,243,
240,225,227,101,128,255,71,111,2,97,45,97,56,232,233,242,
225,231,225,238,97,128,48,84,235,225,244,225,235,225,238,97,
128,48,180,240,97,2,97,74,97,80,242,229,110,128,36,162,
243,241,245,225,242,101,128,51,172,114,2,97,95,97,192,97,
2,97,101,97,109,228,233,229,238,116,128,34,7,246,101,134,
0,96,97,126,97,137,97,154,97,161,97,170,97,182,226,229,
236,239,247,227,237,98,128,3,22,99,2,97,143,97,148,237,
98,128,3,0,239,237,98,128,3,0,228,229,246,97,128,9,
83,236,239,247,237,239,100,128,2,206,237,239,238,239,243,240,
225,227,101,128,255,64,244,239,238,229,227,237,98,128,3,64,
229,225,244,229,114,132,0,62,97,208,97,227,97,239,98,26,
229,241,245,225,108,129,34,101,97,218,239,242,236,229,243,115,
128,34,219,237,239,238,239,243,240,225,227,101,128,255,30,111,
2,97,245,98,15,114,2,97,251,98,8,229,241,245,233,246,
225,236,229,238,116,128,34,115,236,229,243,115,128,34,119,246,
229,242,229,241,245,225,108,128,34,103,243,237,225,236,108,128,
254,101,115,2,98,40,98,48,227,242,233,240,116,128,2,97,
244,242,239,235,101,128,1,229,117,4,98,66,98,77,98,134,
98,145,232,233,242,225,231,225,238,97,128,48,80,233,108,2,
98,84,98,109,236,229,237,239,116,2,98,94,98,101,236,229,
230,116,128,0,171,242,233,231,232,116,128,0,187,243,233,238,
231,108,2,98,119,98,126,236,229,230,116,128,32,57,242,233,
231,232,116,128,32,58,235,225,244,225,235,225,238,97,128,48,
176,242,225,237,245,243,241,245,225,242,101,128,51,24,249,243,
241,245,225,242,101,128,51,201,104,144,0,104,98,204,101,90,
101,125,101,162,101,202,103,90,103,110,104,75,104,87,104,99,
105,167,105,175,105,186,105,195,106,19,106,23,97,13,98,232,
99,15,99,25,99,55,99,80,99,158,99,170,99,195,99,210,
99,239,99,252,100,54,100,63,97,2,98,238,99,1,226,235,
232,225,243,233,225,238,227,249,242,233,236,236,233,99,128,4,
169,236,244,239,238,229,225,242,225,226,233,99,128,6,193,226,
229,238,231,225,236,105,128,9,185,228,101,2,99,32,99,50,
243,227,229,238,228,229,242,227,249,242,233,236,236,233,99,128,
4,179,246,97,128,9,57,231,117,2,99,62,99,71,234,225,
242,225,244,105,128,10,185,242,237,245,235,232,105,128,10,57,
104,4,99,90,99,99,99,113,99,143,225,242,225,226,233,99,
128,6,45,230,233,238,225,236,225,242,225,226,233,99,128,254,
162,105,2,99,119,99,134,238,233,244,233,225,236,225,242,225,
226,233,99,128,254,163,242,225,231,225,238,97,128,48,111,237,
229,228,233,225,236,225,242,225,226,233,99,128,254,164,233,244,
245,243,241,245,225,242,101,128,51,42,235,225,244,225,235,225,
238,97,129,48,207,99,183,232,225,236,230,247,233,228,244,104,
128,255,138,236,225,238,244,231,245,242,237,245,235,232,105,128,
10,77,237,250,97,2,99,218,99,227,225,242,225,226,233,99,
128,6,33,236,239,247,225,242,225,226,233,99,128,6,33,238,
231,245,236,230,233,236,236,229,114,128,49,100,114,2,100,2,
100,18,228,243,233,231,238,227,249,242,233,236,236,233,99,128,
4,74,240,239,239,110,2,100,27,100,40,236,229,230,244,226,
225,242,226,245,112,128,33,188,242,233,231,232,244,226,225,242,
226,245,112,128,33,192,243,241,245,225,242,101,128,51,202,244,
225,102,3,100,73,100,165,101,0,240,225,244,225,104,134,5,
178,100,93,100,98,100,112,100,121,100,136,100,152,177,54,128,
5,178,50,2,100,104,100,108,51,128,5,178,102,128,5,178,
232,229,226,242,229,119,128,5,178,238,225,242,242,239,247,232,
229,226,242,229,119,128,5,178,241,245,225,242,244,229,242,232,
229,226,242,229,119,128,5,178,247,233,228,229,232,229,226,242,
229,119,128,5,178,241,225,237,225,244,115,135,5,179,100,188,
100,193,100,198,100,203,100,212,100,227,100,243,177,98,128,5,
179,178,56,128,5,179,179,52,128,5,179,232,229,226,242,229,
119,128,5,179,238,225,242,242,239,247,232,229,226,242,229,119,
128,5,179,241,245,225,242,244,229,242,232,229,226,242,229,119,
128,5,179,247,233,228,229,232,229,226,242,229,119,128,5,179,
243,229,231,239,108,135,5,177,101,22,101,27,101,32,101,37,
101,46,101,61,101,77,177,55,128,5,177,178,52,128,5,177,
179,48,128,5,177,232,229,226,242,229,119,128,5,177,238,225,
242,242,239,247,232,229,226,242,229,119,128,5,177,241,245,225,
242,244,229,242,232,229,226,242,229,119,128,5,177,247,233,228,
229,232,229,226,242,229,119,128,5,177,98,3,101,98,101,103,
101,113,225,114,128,1,39,239,240,239,237,239,230,111,128,49,
15,242,229,246,229,226,229,236,239,119,128,30,43,99,2,101,
131,101,140,229,228,233,236,236,97,128,30,41,233,242,99,2,
101,148,101,153,236,101,128,36,215,245,237,230,236,229,120,128,
1,37,100,2,101,168,101,178,233,229,242,229,243,233,115,128,
30,39,239,116,2,101,185,101,194,225,227,227,229,238,116,128,
30,35,226,229,236,239,119,128,30,37,101,136,5,212,101,222,
101,255,102,19,102,248,103,8,103,53,103,62,103,75,225,242,
116,129,38,101,101,230,243,245,233,116,2,101,239,101,247,226,
236,225,227,107,128,38,101,247,232,233,244,101,128,38,97,228,
225,231,229,243,104,129,251,52,102,10,232,229,226,242,229,119,
128,251,52,104,6,102,33,102,61,102,69,102,119,102,165,102,
214,97,2,102,39,102,53,236,244,239,238,229,225,242,225,226,
233,99,128,6,193,242,225,226,233,99,128,6,71,229,226,242,
229,119,128,5,212,230,233,238,225,236,97,2,102,80,102,111,
236,116,2,102,87,102,99,239,238,229,225,242,225,226,233,99,
128,251,167,244,247,239,225,242,225,226,233,99,128,254,234,242,
225,226,233,99,128,254,234,232,225,237,250,225,225,226,239,246,
101,2,102,134,102,148,230,233,238,225,236,225,242,225,226,233,
99,128,251,165,233,243,239,236,225,244,229,228,225,242,225,226,
233,99,128,251,164,105,2,102,171,102,205,238,233,244,233,225,
236,97,2,102,183,102,197,236,244,239,238,229,225,242,225,226,
233,99,128,251,168,242,225,226,233,99,128,254,235,242,225,231,
225,238,97,128,48,120,237,229,228,233,225,236,97,2,102,226,
102,240,236,244,239,238,229,225,242,225,226,233,99,128,251,169,
242,225,226,233,99,128,254,236,233,243,229,233,229,242,225,243,
241,245,225,242,101,128,51,123,107,2,103,14,103,38,225,244,
225,235,225,238,97,129,48,216,103,26,232,225,236,230,247,233,
228,244,104,128,255,141,245,244,225,225,242,245,243,241,245,225,
242,101,128,51,54,238,231,232,239,239,107,128,2,103,242,245,
244,245,243,241,245,225,242,101,128,51,57,116,129,5,215,103,
81,232,229,226,242,229,119,128,5,215,232,239,239,107,129,2,
102,103,99,243,245,240,229,242,233,239,114,128,2,177,105,4,
103,120,103,205,103,216,103,241,229,245,104,4,103,132,103,167,
103,182,103,191,97,2,103,138,103,153,227,233,242,227,236,229,
235,239,242,229,225,110,128,50,123,240,225,242,229,238,235,239,
242,229,225,110,128,50,27,227,233,242,227,236,229,235,239,242,
229,225,110,128,50,109,235,239,242,229,225,110,128,49,78,240,
225,242,229,238,235,239,242,229,225,110,128,50,13,232,233,242,
225,231,225,238,97,128,48,114,235,225,244,225,235,225,238,97,
129,48,210,103,229,232,225,236,230,247,233,228,244,104,128,255,
139,242,233,113,134,5,180,104,3,104,8,104,22,104,31,104,
46,104,62,177,52,128,5,180,50,2,104,14,104,18,49,128,
5,180,100,128,5,180,232,229,226,242,229,119,128,5,180,238,
225,242,242,239,247,232,229,226,242,229,119,128,5,180,241,245,
225,242,244,229,242,232,229,226,242,229,119,128,5,180,247,233,
228,229,232,229,226,242,229,119,128,5,180,236,233,238,229,226,
229,236,239,119,128,30,150,237,239,238,239,243,240,225,227,101,
128,255,72,111,9,104,119,104,130,104,154,104,179,105,11,105,
24,105,110,105,150,105,161,225,242,237,229,238,233,225,110,128,
5,112,232,105,2,104,137,104,145,240,244,232,225,105,128,14,
43,242,225,231,225,238,97,128,48,123,235,225,244,225,235,225,
238,97,129,48,219,104,167,232,225,236,230,247,233,228,244,104,
128,255,142,236,225,109,135,5,185,104,199,104,204,104,209,104,
214,104,223,104,238,104,254,177,57,128,5,185,178,54,128,5,
185,179,50,128,5,185,232,229,226,242,229,119,128,5,185,238,
225,242,242,239,247,232,229,226,242,229,119,128,5,185,241,245,
225,242,244,229,242,232,229,226,242,229,119,128,5,185,247,233,
228,229,232,229,226,242,229,119,128,5,185,238,239,235,232,245,
235,244,232,225,105,128,14,46,111,2,105,30,105,100,107,4,
105,40,105,52,105,58,105,80,225,226,239,246,229,227,239,237,
98,128,3,9,227,237,98,128,3,9,240,225,236,225,244,225,
236,233,250,229,228,226,229,236,239,247,227,237,98,128,3,33,
242,229,244,242,239,230,236,229,248,226,229,236,239,247,227,237,
98,128,3,34,238,243,241,245,225,242,101,128,51,66,114,2,
105,116,105,143,105,2,105,122,105,131,227,239,240,244,233,99,
128,3,233,250,239,238,244,225,236,226,225,114,128,32,21,238,
227,237,98,128,3,27,244,243,240,242,233,238,231,115,128,38,
104,245,243,101,128,35,2,240,225,242,229,110,128,36,163,243,
245,240,229,242,233,239,114,128,2,176,244,245,242,238,229,100,
128,2,101,117,4,105,205,105,216,105,229,105,254,232,233,242,
225,231,225,238,97,128,48,117,233,233,244,239,243,241,245,225,
242,101,128,51,51,235,225,244,225,235,225,238,97,129,48,213,
105,242,232,225,236,230,247,233,228,244,104,128,255,140,238,231,
225,242,245,237,236,225,245,116,129,2,221,106,13,227,237,98,
128,3,11,118,128,1,149,249,240,232,229,110,132,0,45,106,
39,106,50,106,62,106,85,233,238,230,229,242,233,239,114,128,
246,229,237,239,238,239,243,240,225,227,101,128,255,13,115,2,
106,68,106,75,237,225,236,108,128,254,99,245,240,229,242,233,
239,114,128,246,230,244,247,111,128,32,16,105,149,0,105,106,
137,106,160,106,194,106,241,110,123,110,243,111,24,111,51,111,
213,111,217,111,255,112,21,112,105,113,14,113,89,113,97,113,
110,113,197,113,254,114,26,114,70,225,99,2,106,144,106,150,
245,244,101,128,0,237,249,242,233,236,236,233,99,128,4,79,
98,3,106,168,106,177,106,187,229,238,231,225,236,105,128,9,
135,239,240,239,237,239,230,111,128,49,39,242,229,246,101,128,
1,45,99,3,106,202,106,209,106,231,225,242,239,110,128,1,
208,233,242,99,2,106,217,106,222,236,101,128,36,216,245,237,
230,236,229,120,128,0,238,249,242,233,236,236,233,99,128,4,
86,100,4,106,251,107,5,110,80,110,113,226,236,231,242,225,
246,101,128,2,9,101,2,107,11,110,75,239,231,242,225,240,
104,7,107,32,107,46,107,59,109,244,110,19,110,32,110,44,
229,225,242,244,232,227,233,242,227,236,101,128,50,143,230,233,
242,229,227,233,242,227,236,101,128,50,139,233,99,14,107,90,
107,106,107,205,108,3,108,69,108,98,108,114,108,171,108,220,
108,232,109,3,109,70,109,208,109,237,225,236,236,233,225,238,
227,229,240,225,242,229,110,128,50,63,99,4,107,116,107,127,
107,141,107,148,225,236,236,240,225,242,229,110,128,50,58,229,
238,244,242,229,227,233,242,227,236,101,128,50,165,236,239,243,
101,128,48,6,111,3,107,156,107,171,107,191,237,237,97,129,
48,1,107,164,236,229,230,116,128,255,100,238,231,242,225,244,
245,236,225,244,233,239,238,240,225,242,229,110,128,50,55,242,
242,229,227,244,227,233,242,227,236,101,128,50,163,101,3,107,
213,107,225,107,242,225,242,244,232,240,225,242,229,110,128,50,
47,238,244,229,242,240,242,233,243,229,240,225,242,229,110,128,
50,61,248,227,229,236,236,229,238,244,227,233,242,227,236,101,
128,50,157,102,2,108,9,108,24,229,243,244,233,246,225,236,
240,225,242,229,110,128,50,64,105,2,108,30,108,59,238,225,
238,227,233,225,108,2,108,42,108,51,227,233,242,227,236,101,
128,50,150,240,225,242,229,110,128,50,54,242,229,240,225,242,
229,110,128,50,43,104,2,108,75,108,86,225,246,229,240,225,
242,229,110,128,50,50,233,231,232,227,233,242,227,236,101,128,
50,164,233,244,229,242,225,244,233,239,238,237,225,242,107,128,
48,5,108,3,108,122,108,148,108,160,225,226,239,114,2,108,
131,108,140,227,233,242,227,236,101,128,50,152,240,225,242,229,
110,128,50,56,229,230,244,227,233,242,227,236,101,128,50,167,
239,247,227,233,242,227,236,101,128,50,166,109,2,108,177,108,
209,101,2,108,183,108,198,228,233,227,233,238,229,227,233,242,
227,236,101,128,50,169,244,225,236,240,225,242,229,110,128,50,
46,239,239,238,240,225,242,229,110,128,50,42,238,225,237,229,
240,225,242,229,110,128,50,52,112,2,108,238,108,246,229,242,
233,239,100,128,48,2,242,233,238,244,227,233,242,227,236,101,
128,50,158,114,2,109,9,109,57,101,3,109,17,109,28,109,
43,225,227,232,240,225,242,229,110,128,50,67,240,242,229,243,
229,238,244,240,225,242,229,110,128,50,57,243,239,245,242,227,
229,240,225,242,229,110,128,50,62,233,231,232,244,227,233,242,
227,236,101,128,50,168,115,5,109,82,109,111,109,125,109,150,
109,178,101,2,109,88,109,101,227,242,229,244,227,233,242,227,
236,101,128,50,153,236,230,240,225,242,229,110,128,50,66,239,
227,233,229,244,249,240,225,242,229,110,128,50,51,112,2,109,
131,109,137,225,227,101,128,48,0,229,227,233,225,236,240,225,
242,229,110,128,50,53,116,2,109,156,109,167,239,227,235,240,
225,242,229,110,128,50,49,245,228,249,240,225,242,229,110,128,
50,59,117,2,109,184,109,193,238,240,225,242,229,110,128,50,
48,240,229,242,246,233,243,229,240,225,242,229,110,128,50,60,
119,2,109,214,109,226,225,244,229,242,240,225,242,229,110,128,
50,44,239,239,228,240,225,242,229,110,128,50,45,250,229,242,
111,128,48,7,109,2,109,250,110,7,229,244,225,236,227,233,
242,227,236,101,128,50,142,239,239,238,227,233,242,227,236,101,
128,50,138,238,225,237,229,227,233,242,227,236,101,128,50,148,
243,245,238,227,233,242,227,236,101,128,50,144,119,2,110,50,
110,63,225,244,229,242,227,233,242,227,236,101,128,50,140,239,
239,228,227,233,242,227,236,101,128,50,141,246,97,128,9,7,
233,229,242,229,243,233,115,130,0,239,110,94,110,102,225,227,
245,244,101,128,30,47,227,249,242,233,236,236,233,99,128,4,
229,239,244,226,229,236,239,119,128,30,203,101,3,110,131,110,
147,110,158,226,242,229,246,229,227,249,242,233,236,236,233,99,
128,4,215,227,249,242,233,236,236,233,99,128,4,53,245,238,
103,4,110,170,110,205,110,220,110,229,97,2,110,176,110,191,
227,233,242,227,236,229,235,239,242,229,225,110,128,50,117,240,
225,242,229,238,235,239,242,229,225,110,128,50,21,227,233,242,
227,236,229,235,239,242,229,225,110,128,50,103,235,239,242,229,
225,110,128,49,71,240,225,242,229,238,235,239,242,229,225,110,
128,50,7,103,2,110,249,111,0,242,225,246,101,128,0,236,
117,2,111,6,111,15,234,225,242,225,244,105,128,10,135,242,
237,245,235,232,105,128,10,7,104,2,111,30,111,40,233,242,
225,231,225,238,97,128,48,68,239,239,235,225,226,239,246,101,
128,30,201,105,8,111,69,111,79,111,90,111,97,111,122,111,
138,111,153,111,169,226,229,238,231,225,236,105,128,9,136,227,
249,242,233,236,236,233,99,128,4,56,228,229,246,97,128,9,
8,231,117,2,111,104,111,113,234,225,242,225,244,105,128,10,
136,242,237,245,235,232,105,128,10,8,237,225,244,242,225,231,
245,242,237,245,235,232,105,128,10,64,238,246,229,242,244,229,
228,226,242,229,246,101,128,2,11,243,232,239,242,244,227,249,
242,233,236,236,233,99,128,4,57,246,239,247,229,236,243,233,
231,110,3,111,185,111,195,111,202,226,229,238,231,225,236,105,
128,9,192,228,229,246,97,128,9,64,231,245,234,225,242,225,
244,105,128,10,192,106,128,1,51,107,2,111,223,111,247,225,
244,225,235,225,238,97,129,48,164,111,235,232,225,236,230,247,
233,228,244,104,128,255,114,239,242,229,225,110,128,49,99,108,
2,112,5,112,10,228,101,128,2,220,245,249,232,229,226,242,
229,119,128,5,172,109,2,112,27,112,94,97,3,112,35,112,
55,112,80,227,242,239,110,129,1,43,112,44,227,249,242,233,
236,236,233,99,128,4,227,231,229,239,242,225,240,240,242,239,
248,233,237,225,244,229,236,249,229,241,245,225,108,128,34,83,
244,242,225,231,245,242,237,245,235,232,105,128,10,63,239,238,
239,243,240,225,227,101,128,255,73,110,5,112,117,112,127,112,
136,112,148,112,232,227,242,229,237,229,238,116,128,34,6,230,
233,238,233,244,121,128,34,30,233,225,242,237,229,238,233,225,
110,128,5,107,116,2,112,154,112,222,101,2,112,160,112,211,
231,242,225,108,131,34,43,112,173,112,191,112,196,98,2,112,
179,112,187,239,244,244,239,109,128,35,33,116,128,35,33,229,
120,128,248,245,116,2,112,202,112,207,239,112,128,35,32,112,
128,35,32,242,243,229,227,244,233,239,110,128,34,41,233,243,
241,245,225,242,101,128,51,5,118,3,112,240,112,249,113,2,
226,245,236,236,229,116,128,37,216,227,233,242,227,236,101,128,
37,217,243,237,233,236,229,230,225,227,101,128,38,59,111,3,
113,22,113,33,113,41,227,249,242,233,236,236,233,99,128,4,
81,231,239,238,229,107,128,1,47,244,97,131,3,185,113,52,
113,73,113,81,228,233,229,242,229,243,233,115,129,3,202,113,
65,244,239,238,239,115,128,3,144,236,225,244,233,110,128,2,
105,244,239,238,239,115,128,3,175,240,225,242,229,110,128,36,
164,242,233,231,245,242,237,245,235,232,105,128,10,114,115,4,
113,120,113,165,113,179,113,187,237,225,236,108,2,113,129,113,
140,232,233,242,225,231,225,238,97,128,48,67,235,225,244,225,
235,225,238,97,129,48,163,113,153,232,225,236,230,247,233,228,
244,104,128,255,104,243,232,225,242,226,229,238,231,225,236,105,
128,9,250,244,242,239,235,101,128,2,104,245,240,229,242,233,
239,114,128,246,237,116,2,113,203,113,237,229,242,225,244,233,
239,110,2,113,215,113,226,232,233,242,225,231,225,238,97,128,
48,157,235,225,244,225,235,225,238,97,128,48,253,233,236,228,
101,129,1,41,113,246,226,229,236,239,119,128,30,45,117,2,
114,4,114,15,226,239,240,239,237,239,230,111,128,49,41,227,
249,242,233,236,236,233,99,128,4,78,246,239,247,229,236,243,
233,231,110,3,114,42,114,52,114,59,226,229,238,231,225,236,
105,128,9,191,228,229,246,97,128,9,63,231,245,234,225,242,
225,244,105,128,10,191,250,232,233,244,243,97,2,114,81,114,
92,227,249,242,233,236,236,233,99,128,4,117,228,226,236,231,
242,225,246,229,227,249,242,233,236,236,233,99,128,4,119,106,
138,0,106,114,135,114,198,114,209,115,3,115,19,115,132,115,
201,115,206,115,218,115,226,97,4,114,145,114,156,114,166,114,
173,225,242,237,229,238,233,225,110,128,5,113,226,229,238,231,
225,236,105,128,9,156,228,229,246,97,128,9,28,231,117,2,
114,180,114,189,234,225,242,225,244,105,128,10,156,242,237,245,
235,232,105,128,10,28,226,239,240,239,237,239,230,111,128,49,
16,99,3,114,217,114,224,114,246,225,242,239,110,128,1,240,
233,242,99,2,114,232,114,237,236,101,128,36,217,245,237,230,
236,229,120,128,1,53,242,239,243,243,229,228,244,225,233,108,
128,2,157,228,239,244,236,229,243,243,243,244,242,239,235,101,
128,2,95,101,3,115,27,115,38,115,103,227,249,242,233,236,
236,233,99,128,4,88,229,109,4,115,49,115,58,115,72,115,
88,225,242,225,226,233,99,128,6,44,230,233,238,225,236,225,
242,225,226,233,99,128,254,158,233,238,233,244,233,225,236,225,
242,225,226,233,99,128,254,159,237,229,228,233,225,236,225,242,
225,226,233,99,128,254,160,104,2,115,109,115,118,225,242,225,
226,233,99,128,6,152,230,233,238,225,236,225,242,225,226,233,
99,128,251,139,104,2,115,138,115,188,97,3,115,146,115,156,
115,163,226,229,238,231,225,236,105,128,9,157,228,229,246,97,
128,9,29,231,117,2,115,170,115,179,234,225,242,225,244,105,
128,10,157,242,237,245,235,232,105,128,10,29,229,232,225,242,
237,229,238,233,225,110,128,5,123,233,115,128,48,4,237,239,
238,239,243,240,225,227,101,128,255,74,240,225,242,229,110,128,
36,165,243,245,240,229,242,233,239,114,128,2,178,107,146,0,
107,116,21,118,110,118,121,118,183,118,194,119,28,119,42,120,
150,121,90,121,103,121,129,121,178,122,60,122,82,122,95,122,
118,122,160,122,170,97,12,116,47,116,79,116,101,116,131,116,
245,117,14,117,44,117,69,117,175,117,189,118,56,118,85,98,
2,116,53,116,70,225,243,232,235,233,242,227,249,242,233,236,
236,233,99,128,4,161,229,238,231,225,236,105,128,9,149,99,
2,116,85,116,91,245,244,101,128,30,49,249,242,233,236,236,
233,99,128,4,58,228,101,2,116,108,116,126,243,227,229,238,
228,229,242,227,249,242,233,236,236,233,99,128,4,155,246,97,
128,9,21,102,135,5,219,116,149,116,158,116,178,116,192,116,
201,116,217,116,232,225,242,225,226,233,99,128,6,67,228,225,
231,229,243,104,129,251,59,116,169,232,229,226,242,229,119,128,
251,59,230,233,238,225,236,225,242,225,226,233,99,128,254,218,
232,229,226,242,229,119,128,5,219,233,238,233,244,233,225,236,
225,242,225,226,233,99,128,254,219,237,229,228,233,225,236,225,
242,225,226,233,99,128,254,220,242,225,230,229,232,229,226,242,
229,119,128,251,77,231,117,2,116,252,117,5,234,225,242,225,
244,105,128,10,149,242,237,245,235,232,105,128,10,21,104,2,
117,20,117,30,233,242,225,231,225,238,97,128,48,75,239,239,
235,227,249,242,233,236,236,233,99,128,4,196,235,225,244,225,
235,225,238,97,129,48,171,117,57,232,225,236,230,247,233,228,
244,104,128,255,118,112,2,117,75,117,96,240,97,129,3,186,
117,82,243,249,237,226,239,236,231,242,229,229,107,128,3,240,
249,229,239,245,110,3,117,108,117,122,117,156,237,233,229,245,
237,235,239,242,229,225,110,128,49,113,112,2,117,128,117,143,
232,233,229,245,240,232,235,239,242,229,225,110,128,49,132,233,
229,245,240,235,239,242,229,225,110,128,49,120,243,243,225,238,
231,240,233,229,245,240,235,239,242,229,225,110,128,49,121,242,
239,242,233,233,243,241,245,225,242,101,128,51,13,115,5,117,
201,117,245,118,4,118,12,118,40,232,233,228,225,225,245,244,
111,2,117,214,117,223,225,242,225,226,233,99,128,6,64,238,
239,243,233,228,229,226,229,225,242,233,238,231,225,242,225,226,
233,99,128,6,64,237,225,236,236,235,225,244,225,235,225,238,
97,128,48,245,241,245,225,242,101,128,51,132,242,97,2,118,
19,118,28,225,242,225,226,233,99,128,6,80,244,225,238,225,
242,225,226,233,99,128,6,77,244,242,239,235,229,227,249,242,
233,236,236,233,99,128,4,159,244,225,232,233,242,225,240,242,
239,236,239,238,231,237,225,242,235,232,225,236,230,247,233,228,
244,104,128,255,112,246,229,242,244,233,227,225,236,243,244,242,
239,235,229,227,249,242,233,236,236,233,99,128,4,157,226,239,
240,239,237,239,230,111,128,49,14,99,4,118,131,118,153,118,
162,118,170,97,2,118,137,118,147,236,243,241,245,225,242,101,
128,51,137,242,239,110,128,1,233,229,228,233,236,236,97,128,
1,55,233,242,227,236,101,128,36,218,239,237,237,225,225,227,
227,229,238,116,128,1,55,228,239,244,226,229,236,239,119,128,
30,51,101,4,118,204,118,231,119,0,119,12,104,2,118,210,
118,221,225,242,237,229,238,233,225,110,128,5,132,233,242,225,
231,225,238,97,128,48,81,235,225,244,225,235,225,238,97,129,
48,177,118,244,232,225,236,230,247,233,228,244,104,128,255,121,
238,225,242,237,229,238,233,225,110,128,5,111,243,237,225,236,
236,235,225,244,225,235,225,238,97,128,48,246,231,242,229,229,
238,236,225,238,228,233,99,128,1,56,104,6,119,56,119,185,
119,196,119,221,120,52,120,140,97,5,119,68,119,78,119,89,
119,96,119,121,226,229,238,231,225,236,105,128,9,150,227,249,
242,233,236,236,233,99,128,4,69,228,229,246,97,128,9,22,
231,117,2,119,103,119,112,234,225,242,225,244,105,128,10,150,
242,237,245,235,232,105,128,10,22,104,4,119,131,119,140,119,
154,119,170,225,242,225,226,233,99,128,6,46,230,233,238,225,
236,225,242,225,226,233,99,128,254,166,233,238,233,244,233,225,
236,225,242,225,226,233,99,128,254,167,237,229,228,233,225,236,
225,242,225,226,233,99,128,254,168,229,233,227,239,240,244,233,
99,128,3,231,232,97,2,119,203,119,210,228,229,246,97,128,
9,89,231,245,242,237,245,235,232,105,128,10,89,233,229,245,
235,104,4,119,235,120,14,120,29,120,38,97,2,119,241,120,
0,227,233,242,227,236,229,235,239,242,229,225,110,128,50,120,
240,225,242,229,238,235,239,242,229,225,110,128,50,24,227,233,
242,227,236,229,235,239,242,229,225,110,128,50,106,235,239,242,
229,225,110,128,49,75,240,225,242,229,238,235,239,242,229,225,
110,128,50,10,111,4,120,62,120,111,120,121,120,126,235,104,
4,120,73,120,82,120,91,120,101,225,233,244,232,225,105,128,
14,2,239,238,244,232,225,105,128,14,5,245,225,244,244,232,
225,105,128,14,3,247,225,233,244,232,225,105,128,14,4,237,
245,244,244,232,225,105,128,14,91,239,107,128,1,153,242,225,
235,232,225,238,231,244,232,225,105,128,14,6,250,243,241,245,
225,242,101,128,51,145,105,4,120,160,120,171,120,196,120,245,
232,233,242,225,231,225,238,97,128,48,77,235,225,244,225,235,
225,238,97,129,48,173,120,184,232,225,236,230,247,233,228,244,
104,128,255,119,242,111,3,120,205,120,220,120,236,231,245,242,
225,237,245,243,241,245,225,242,101,128,51,21,237,229,229,244,
239,242,245,243,241,245,225,242,101,128,51,22,243,241,245,225,
242,101,128,51,20,249,229,239,107,5,121,4,121,39,121,54,
121,63,121,77,97,2,121,10,121,25,227,233,242,227,236,229,
235,239,242,229,225,110,128,50,110,240,225,242,229,238,235,239,
242,229,225,110,128,50,14,227,233,242,227,236,229,235,239,242,
229,225,110,128,50,96,235,239,242,229,225,110,128,49,49,240,
225,242,229,238,235,239,242,229,225,110,128,50,0,243,233,239,
243,235,239,242,229,225,110,128,49,51,234,229,227,249,242,233,
236,236,233,99,128,4,92,108,2,121,109,121,120,233,238,229,
226,229,236,239,119,128,30,53,243,241,245,225,242,101,128,51,
152,109,3,121,137,121,151,121,162,227,245,226,229,228,243,241,
245,225,242,101,128,51,166,239,238,239,243,240,225,227,101,128,
255,75,243,241,245,225,242,229,228,243,241,245,225,242,101,128,
51,162,111,5,121,190,121,216,121,254,122,10,122,24,104,2,
121,196,121,206,233,242,225,231,225,238,97,128,48,83,237,243,
241,245,225,242,101,128,51,192,235,97,2,121,223,121,231,233,
244,232,225,105,128,14,1,244,225,235,225,238,97,129,48,179,
121,242,232,225,236,230,247,233,228,244,104,128,255,122,239,240,
239,243,241,245,225,242,101,128,51,30,240,240,225,227,249,242,
233,236,236,233,99,128,4,129,114,2,122,30,122,50,229,225,
238,243,244,225,238,228,225,242,228,243,249,237,226,239,108,128,
50,127,239,238,233,243,227,237,98,128,3,67,240,97,2,122,
67,122,73,242,229,110,128,36,166,243,241,245,225,242,101,128,
51,170,243,233,227,249,242,233,236,236,233,99,128,4,111,116,
2,122,101,122,110,243,241,245,225,242,101,128,51,207,245,242,
238,229,100,128,2,158,117,2,122,124,122,135,232,233,242,225,
231,225,238,97,128,48,79,235,225,244,225,235,225,238,97,129,
48,175,122,148,232,225,236,230,247,233,228,244,104,128,255,120,
246,243,241,245,225,242,101,128,51,184,247,243,241,245,225,242,
101,128,51,190,108,146,0,108,122,220,124,247,125,20,125,86,
125,124,126,20,126,29,126,45,126,69,126,87,126,205,126,246,
127,125,127,133,127,166,127,175,127,183,127,245,97,7,122,236,
122,246,122,253,123,4,123,29,123,45,124,235,226,229,238,231,
225,236,105,128,9,178,227,245,244,101,128,1,58,228,229,246,
97,128,9,50,231,117,2,123,11,123,20,234,225,242,225,244,
105,128,10,178,242,237,245,235,232,105,128,10,50,235,235,232,
225,238,231,249,225,239,244,232,225,105,128,14,69,109,10,123,
67,124,6,124,23,124,61,124,75,124,94,124,110,124,130,124,
150,124,173,97,2,123,73,123,254,236,229,102,4,123,85,123,
99,123,191,123,208,230,233,238,225,236,225,242,225,226,233,99,
128,254,252,232,225,237,250,97,2,123,109,123,150,225,226,239,
246,101,2,123,119,123,133,230,233,238,225,236,225,242,225,226,
233,99,128,254,248,233,243,239,236,225,244,229,228,225,242,225,
226,233,99,128,254,247,226,229,236,239,119,2,123,160,123,174,
230,233,238,225,236,225,242,225,226,233,99,128,254,250,233,243,
239,236,225,244,229,228,225,242,225,226,233,99,128,254,249,233,
243,239,236,225,244,229,228,225,242,225,226,233,99,128,254,251,
237,225,228,228,225,225,226,239,246,101,2,123,223,123,237,230,
233,238,225,236,225,242,225,226,233,99,128,254,246,233,243,239,
236,225,244,229,228,225,242,225,226,233,99,128,254,245,242,225,
226,233,99,128,6,68,226,228,97,129,3,187,124,14,243,244,
242,239,235,101,128,1,155,229,100,130,5,220,124,32,124,52,
228,225,231,229,243,104,129,251,60,124,43,232,229,226,242,229,
119,128,251,60,232,229,226,242,229,119,128,5,220,230,233,238,
225,236,225,242,225,226,233,99,128,254,222,232,225,232,233,238,
233,244,233,225,236,225,242,225,226,233,99,128,252,202,233,238,
233,244,233,225,236,225,242,225,226,233,99,128,254,223,234,229,
229,237,233,238,233,244,233,225,236,225,242,225,226,233,99,128,
252,201,235,232,225,232,233,238,233,244,233,225,236,225,242,225,
226,233,99,128,252,203,236,225,237,232,229,232,233,243,239,236,
225,244,229,228,225,242,225,226,233,99,128,253,242,237,101,2,
124,180,124,193,228,233,225,236,225,242,225,226,233,99,128,254,
224,229,109,2,124,200,124,219,232,225,232,233,238,233,244,233,
225,236,225,242,225,226,233,99,128,253,136,233,238,233,244,233,
225,236,225,242,225,226,233,99,128,252,204,242,231,229,227,233,
242,227,236,101,128,37,239,98,3,124,255,125,4,125,10,225,
114,128,1,154,229,236,116,128,2,108,239,240,239,237,239,230,
111,128,49,12,99,4,125,30,125,37,125,46,125,73,225,242,
239,110,128,1,62,229,228,233,236,236,97,128,1,60,233,242,
99,2,125,54,125,59,236,101,128,36,219,245,237,230,236,229,
248,226,229,236,239,119,128,30,61,239,237,237,225,225,227,227,
229,238,116,128,1,60,228,239,116,130,1,64,125,96,125,105,
225,227,227,229,238,116,128,1,64,226,229,236,239,119,129,30,
55,125,115,237,225,227,242,239,110,128,30,57,101,3,125,132,
125,170,126,15,230,116,2,125,139,125,155,225,238,231,236,229,
225,226,239,246,229,227,237,98,128,3,26,244,225,227,235,226,
229,236,239,247,227,237,98,128,3,24,243,115,132,0,60,125,
183,125,205,125,217,126,7,229,241,245,225,108,129,34,100,125,
193,239,242,231,242,229,225,244,229,114,128,34,218,237,239,238,
239,243,240,225,227,101,128,255,28,111,2,125,223,125,252,114,
2,125,229,125,242,229,241,245,233,246,225,236,229,238,116,128,
34,114,231,242,229,225,244,229,114,128,34,118,246,229,242,229,
241,245,225,108,128,34,102,243,237,225,236,108,128,254,100,250,
104,128,2,110,230,226,236,239,227,107,128,37,140,232,239,239,
235,242,229,244,242,239,230,236,229,120,128,2,109,105,2,126,
51,126,56,242,97,128,32,164,247,238,225,242,237,229,238,233,
225,110,128,5,108,106,129,1,201,126,75,229,227,249,242,233,
236,236,233,99,128,4,89,108,132,246,192,126,99,126,123,126,
134,126,143,97,2,126,105,126,112,228,229,246,97,128,9,51,
231,245,234,225,242,225,244,105,128,10,179,233,238,229,226,229,
236,239,119,128,30,59,236,225,228,229,246,97,128,9,52,246,
239,227,225,236,233,99,3,126,157,126,167,126,174,226,229,238,
231,225,236,105,128,9,225,228,229,246,97,128,9,97,246,239,
247,229,236,243,233,231,110,2,126,188,126,198,226,229,238,231,
225,236,105,128,9,227,228,229,246,97,128,9,99,109,3,126,
213,126,226,126,237,233,228,228,236,229,244,233,236,228,101,128,
2,107,239,238,239,243,240,225,227,101,128,255,76,243,241,245,
225,242,101,128,51,208,111,6,127,4,127,16,127,58,127,69,
127,75,127,117,227,232,245,236,225,244,232,225,105,128,14,44,
231,233,227,225,108,3,127,28,127,34,127,53,225,238,100,128,
34,39,238,239,116,129,0,172,127,42,242,229,246,229,242,243,
229,100,128,35,16,239,114,128,34,40,236,233,238,231,244,232,
225,105,128,14,37,238,231,115,128,1,127,247,236,233,238,101,
2,127,85,127,108,99,2,127,91,127,103,229,238,244,229,242,
236,233,238,101,128,254,78,237,98,128,3,50,228,225,243,232,
229,100,128,254,77,250,229,238,231,101,128,37,202,240,225,242,
229,110,128,36,167,115,3,127,141,127,148,127,156,236,225,243,
104,128,1,66,241,245,225,242,101,128,33,19,245,240,229,242,
233,239,114,128,246,238,244,243,232,225,228,101,128,37,145,245,
244,232,225,105,128,14,38,246,239,227,225,236,233,99,3,127,
197,127,207,127,214,226,229,238,231,225,236,105,128,9,140,228,
229,246,97,128,9,12,246,239,247,229,236,243,233,231,110,2,
127,228,127,238,226,229,238,231,225,236,105,128,9,226,228,229,
246,97,128,9,98,248,243,241,245,225,242,101,128,51,211,109,
144,0,109,128,35,130,144,130,169,130,196,130,221,132,18,132,
40,133,95,133,125,133,174,134,25,134,47,134,72,134,81,135,
108,135,136,97,12,128,61,128,71,128,135,128,142,128,167,128,
215,130,51,130,76,130,81,130,95,130,107,130,112,226,229,238,
231,225,236,105,128,9,174,99,2,128,77,128,129,242,239,110,
132,0,175,128,91,128,102,128,108,128,117,226,229,236,239,247,
227,237,98,128,3,49,227,237,98,128,3,4,236,239,247,237,
239,100,128,2,205,237,239,238,239,243,240,225,227,101,128,255,
227,245,244,101,128,30,63,228,229,246,97,128,9,46,231,117,
2,128,149,128,158,234,225,242,225,244,105,128,10,174,242,237,
245,235,232,105,128,10,46,104,2,128,173,128,205,225,240,225,
235,104,2,128,183,128,192,232,229,226,242,229,119,128,5,164,
236,229,230,244,232,229,226,242,229,119,128,5,164,233,242,225,
231,225,238,97,128,48,126,105,5,128,227,129,40,129,103,129,
133,130,39,227,232,225,244,244,225,247,97,3,128,242,129,17,
129,24,236,239,119,2,128,250,129,5,236,229,230,244,244,232,
225,105,128,248,149,242,233,231,232,244,244,232,225,105,128,248,
148,244,232,225,105,128,14,75,245,240,240,229,242,236,229,230,
244,244,232,225,105,128,248,147,229,107,3,129,49,129,80,129,
87,236,239,119,2,129,57,129,68,236,229,230,244,244,232,225,
105,128,248,140,242,233,231,232,244,244,232,225,105,128,248,139,
244,232,225,105,128,14,72,245,240,240,229,242,236,229,230,244,
244,232,225,105,128,248,138,232,225,238,225,235,225,116,2,129,
115,129,126,236,229,230,244,244,232,225,105,128,248,132,244,232,
225,105,128,14,49,116,3,129,141,129,169,129,232,225,233,235,
232,117,2,129,151,129,162,236,229,230,244,244,232,225,105,128,
248,137,244,232,225,105,128,14,71,232,111,3,129,178,129,209,
129,216,236,239,119,2,129,186,129,197,236,229,230,244,244,232,
225,105,128,248,143,242,233,231,232,244,244,232,225,105,128,248,
142,244,232,225,105,128,14,73,245,240,240,229,242,236,229,230,
244,244,232,225,105,128,248,141,242,105,3,129,241,130,16,130,
23,236,239,119,2,129,249,130,4,236,229,230,244,244,232,225,
105,128,248,146,242,233,231,232,244,244,232,225,105,128,248,145,
244,232,225,105,128,14,74,245,240,240,229,242,236,229,230,244,
244,232,225,105,128,248,144,249,225,237,239,235,244,232,225,105,
128,14,70,235,225,244,225,235,225,238,97,129,48,222,130,64,
232,225,236,230,247,233,228,244,104,128,255,143,236,101,128,38,
66,238,243,249,239,238,243,241,245,225,242,101,128,51,71,241,
225,230,232,229,226,242,229,119,128,5,190,242,115,128,38,66,
115,2,130,118,130,136,239,242,225,227,233,242,227,236,229,232,
229,226,242,229,119,128,5,175,241,245,225,242,101,128,51,131,
98,2,130,150,130,160,239,240,239,237,239,230,111,128,49,7,
243,241,245,225,242,101,128,51,212,99,2,130,175,130,183,233,
242,227,236,101,128,36,220,245,226,229,228,243,241,245,225,242,
101,128,51,165,228,239,116,2,130,204,130,213,225,227,227,229,
238,116,128,30,65,226,229,236,239,119,128,30,67,101,7,130,
237,131,108,131,119,131,134,131,159,131,196,131,208,101,2,130,
243,131,95,109,4,130,253,131,6,131,20,131,36,225,242,225,
226,233,99,128,6,69,230,233,238,225,236,225,242,225,226,233,
99,128,254,226,233,238,233,244,233,225,236,225,242,225,226,233,
99,128,254,227,237,101,2,131,43,131,56,228,233,225,236,225,
242,225,226,233,99,128,254,228,229,237,105,2,131,64,131,79,
238,233,244,233,225,236,225,242,225,226,233,99,128,252,209,243,
239,236,225,244,229,228,225,242,225,226,233,99,128,252,72,244,
239,242,245,243,241,245,225,242,101,128,51,77,232,233,242,225,
231,225,238,97,128,48,129,233,250,233,229,242,225,243,241,245,
225,242,101,128,51,126,235,225,244,225,235,225,238,97,129,48,
225,131,147,232,225,236,230,247,233,228,244,104,128,255,146,109,
130,5,222,131,167,131,187,228,225,231,229,243,104,129,251,62,
131,178,232,229,226,242,229,119,128,251,62,232,229,226,242,229,
119,128,5,222,238,225,242,237,229,238,233,225,110,128,5,116,
242,235,232,97,3,131,219,131,228,132,5,232,229,226,242,229,
119,128,5,165,235,229,230,245,236,97,2,131,239,131,248,232,
229,226,242,229,119,128,5,166,236,229,230,244,232,229,226,242,
229,119,128,5,166,236,229,230,244,232,229,226,242,229,119,128,
5,165,104,2,132,24,132,30,239,239,107,128,2,113,250,243,
241,245,225,242,101,128,51,146,105,6,132,54,132,91,132,228,
132,239,133,8,133,65,228,100,2,132,61,132,86,236,229,228,
239,244,235,225,244,225,235,225,238,225,232,225,236,230,247,233,
228,244,104,128,255,101,239,116,128,0,183,229,245,109,5,132,
105,132,140,132,155,132,164,132,215,97,2,132,111,132,126,227,
233,242,227,236,229,235,239,242,229,225,110,128,50,114,240,225,
242,229,238,235,239,242,229,225,110,128,50,18,227,233,242,227,
236,229,235,239,242,229,225,110,128,50,100,235,239,242,229,225,
110,128,49,65,112,2,132,170,132,202,97,2,132,176,132,190,
238,243,233,239,243,235,239,242,229,225,110,128,49,112,242,229,
238,235,239,242,229,225,110,128,50,4,233,229,245,240,235,239,
242,229,225,110,128,49,110,243,233,239,243,235,239,242,229,225,
110,128,49,111,232,233,242,225,231,225,238,97,128,48,127,235,
225,244,225,235,225,238,97,129,48,223,132,252,232,225,236,230,
247,233,228,244,104,128,255,144,238,117,2,133,15,133,60,115,
132,34,18,133,27,133,38,133,47,133,53,226,229,236,239,247,
227,237,98,128,3,32,227,233,242,227,236,101,128,34,150,237,
239,100,128,2,215,240,236,245,115,128,34,19,244,101,128,32,
50,242,105,2,133,72,133,86,226,225,225,242,245,243,241,245,
225,242,101,128,51,74,243,241,245,225,242,101,128,51,73,108,
2,133,101,133,116,239,238,231,236,229,231,244,245,242,238,229,
100,128,2,112,243,241,245,225,242,101,128,51,150,109,3,133,
133,133,147,133,158,227,245,226,229,228,243,241,245,225,242,101,
128,51,163,239,238,239,243,240,225,227,101,128,255,77,243,241,
245,225,242,229,228,243,241,245,225,242,101,128,51,159,111,5,
133,186,133,212,133,237,133,247,134,0,104,2,133,192,133,202,
233,242,225,231,225,238,97,128,48,130,237,243,241,245,225,242,
101,128,51,193,235,225,244,225,235,225,238,97,129,48,226,133,
225,232,225,236,230,247,233,228,244,104,128,255,147,236,243,241,
245,225,242,101,128,51,214,237,225,244,232,225,105,128,14,33,
246,229,242,243,243,241,245,225,242,101,129,51,167,134,15,228,
243,241,245,225,242,101,128,51,168,240,97,2,134,32,134,38,
242,229,110,128,36,168,243,241,245,225,242,101,128,51,171,115,
2,134,53,134,62,243,241,245,225,242,101,128,51,179,245,240,
229,242,233,239,114,128,246,239,244,245,242,238,229,100,128,2,
111,117,141,0,181,134,111,134,115,134,125,134,149,134,159,134,
181,134,192,134,217,134,240,134,250,135,24,135,88,135,98,49,
128,0,181,225,243,241,245,225,242,101,128,51,130,227,104,2,
134,132,134,142,231,242,229,225,244,229,114,128,34,107,236,229,
243,115,128,34,106,230,243,241,245,225,242,101,128,51,140,103,
2,134,165,134,172,242,229,229,107,128,3,188,243,241,245,225,
242,101,128,51,141,232,233,242,225,231,225,238,97,128,48,128,
235,225,244,225,235,225,238,97,129,48,224,134,205,232,225,236,
230,247,233,228,244,104,128,255,145,108,2,134,223,134,232,243,
241,245,225,242,101,128,51,149,244,233,240,236,121,128,0,215,
237,243,241,245,225,242,101,128,51,155,238,225,104,2,135,2,
135,11,232,229,226,242,229,119,128,5,163,236,229,230,244,232,
229,226,242,229,119,128,5,163,115,2,135,30,135,79,233,99,
3,135,39,135,56,135,67,225,236,238,239,244,101,129,38,106,
135,50,228,226,108,128,38,107,230,236,225,244,243,233,231,110,
128,38,109,243,232,225,242,240,243,233,231,110,128,38,111,243,
241,245,225,242,101,128,51,178,246,243,241,245,225,242,101,128,
51,182,247,243,241,245,225,242,101,128,51,188,118,2,135,114,
135,127,237,229,231,225,243,241,245,225,242,101,128,51,185,243,
241,245,225,242,101,128,51,183,119,2,135,142,135,155,237,229,
231,225,243,241,245,225,242,101,128,51,191,243,241,245,225,242,
101,128,51,189,110,150,0,110,135,212,136,90,136,114,136,180,
136,205,137,7,137,17,137,84,137,127,139,161,139,179,139,204,
139,235,140,5,140,70,142,52,142,60,142,85,142,93,143,61,
143,71,143,81,97,8,135,230,135,250,136,1,136,8,136,33,
136,44,136,69,136,81,98,2,135,236,135,245,229,238,231,225,
236,105,128,9,168,236,97,128,34,7,227,245,244,101,128,1,
68,228,229,246,97,128,9,40,231,117,2,136,15,136,24,234,
225,242,225,244,105,128,10,168,242,237,245,235,232,105,128,10,
40,232,233,242,225,231,225,238,97,128,48,106,235,225,244,225,
235,225,238,97,129,48,202,136,57,232,225,236,230,247,233,228,
244,104,128,255,133,240,239,243,244,242,239,240,232,101,128,1,
73,243,241,245,225,242,101,128,51,129,98,2,136,96,136,106,
239,240,239,237,239,230,111,128,49,11,243,240,225,227,101,128,
0,160,99,4,136,124,136,131,136,140,136,167,225,242,239,110,
128,1,72,229,228,233,236,236,97,128,1,70,233,242,99,2,
136,148,136,153,236,101,128,36,221,245,237,230,236,229,248,226,
229,236,239,119,128,30,75,239,237,237,225,225,227,227,229,238,
116,128,1,70,228,239,116,2,136,188,136,197,225,227,227,229,
238,116,128,30,69,226,229,236,239,119,128,30,71,101,3,136,
213,136,224,136,249,232,233,242,225,231,225,238,97,128,48,109,
235,225,244,225,235,225,238,97,129,48,205,136,237,232,225,236,
230,247,233,228,244,104,128,255,136,247,243,232,229,241,229,236,
243,233,231,110,128,32,170,230,243,241,245,225,242,101,128,51,
139,103,2,137,23,137,73,97,3,137,31,137,41,137,48,226,
229,238,231,225,236,105,128,9,153,228,229,246,97,128,9,25,
231,117,2,137,55,137,64,234,225,242,225,244,105,128,10,153,
242,237,245,235,232,105,128,10,25,239,238,231,245,244,232,225,
105,128,14,7,104,2,137,90,137,100,233,242,225,231,225,238,
97,128,48,147,239,239,107,2,137,108,137,115,236,229,230,116,
128,2,114,242,229,244,242,239,230,236,229,120,128,2,115,105,
4,137,137,138,50,138,61,138,119,229,245,110,7,137,155,137,
190,137,222,137,236,137,245,138,22,138,35,97,2,137,161,137,
176,227,233,242,227,236,229,235,239,242,229,225,110,128,50,111,
240,225,242,229,238,235,239,242,229,225,110,128,50,15,227,105,
2,137,197,137,209,229,245,227,235,239,242,229,225,110,128,49,
53,242,227,236,229,235,239,242,229,225,110,128,50,97,232,233,
229,245,232,235,239,242,229,225,110,128,49,54,235,239,242,229,
225,110,128,49,52,240,97,2,137,252,138,10,238,243,233,239,
243,235,239,242,229,225,110,128,49,104,242,229,238,235,239,242,
229,225,110,128,50,1,243,233,239,243,235,239,242,229,225,110,
128,49,103,244,233,235,229,245,244,235,239,242,229,225,110,128,
49,102,232,233,242,225,231,225,238,97,128,48,107,107,2,138,
67,138,91,225,244,225,235,225,238,97,129,48,203,138,79,232,
225,236,230,247,233,228,244,104,128,255,134,232,225,232,233,116,
2,138,101,138,112,236,229,230,244,244,232,225,105,128,248,153,
244,232,225,105,128,14,77,238,101,141,0,57,138,150,138,159,
138,169,138,199,138,206,138,231,139,2,139,36,139,48,139,59,
139,92,139,100,139,111,225,242,225,226,233,99,128,6,105,226,
229,238,231,225,236,105,128,9,239,227,233,242,227,236,101,129,
36,104,138,180,233,238,246,229,242,243,229,243,225,238,243,243,
229,242,233,102,128,39,146,228,229,246,97,128,9,111,231,117,
2,138,213,138,222,234,225,242,225,244,105,128,10,239,242,237,
245,235,232,105,128,10,111,232,97,2,138,238,138,249,227,235,
225,242,225,226,233,99,128,6,105,238,231,250,232,239,117,128,
48,41,105,2,139,8,139,26,228,229,239,231,242,225,240,232,
233,227,240,225,242,229,110,128,50,40,238,230,229,242,233,239,
114,128,32,137,237,239,238,239,243,240,225,227,101,128,255,25,
239,236,228,243,244,249,236,101,128,247,57,112,2,139,65,139,
72,225,242,229,110,128,36,124,229,114,2,139,79,139,85,233,
239,100,128,36,144,243,233,225,110,128,6,249,242,239,237,225,
110,128,33,120,243,245,240,229,242,233,239,114,128,32,121,116,
2,139,117,139,155,229,229,110,2,139,125,139,134,227,233,242,
227,236,101,128,36,114,112,2,139,140,139,147,225,242,229,110,
128,36,134,229,242,233,239,100,128,36,154,232,225,105,128,14,
89,106,129,1,204,139,167,229,227,249,242,233,236,236,233,99,
128,4,90,235,225,244,225,235,225,238,97,129,48,243,139,192,
232,225,236,230,247,233,228,244,104,128,255,157,108,2,139,210,
139,224,229,231,242,233,231,232,244,236,239,238,103,128,1,158,
233,238,229,226,229,236,239,119,128,30,73,109,2,139,241,139,
252,239,238,239,243,240,225,227,101,128,255,78,243,241,245,225,
242,101,128,51,154,110,2,140,11,140,61,97,3,140,19,140,
29,140,36,226,229,238,231,225,236,105,128,9,163,228,229,246,
97,128,9,35,231,117,2,140,43,140,52,234,225,242,225,244,
105,128,10,163,242,237,245,235,232,105,128,10,35,238,225,228,
229,246,97,128,9,41,111,6,140,84,140,95,140,120,140,161,
141,113,142,40,232,233,242,225,231,225,238,97,128,48,110,235,
225,244,225,235,225,238,97,129,48,206,140,108,232,225,236,230,
247,233,228,244,104,128,255,137,110,3,140,128,140,144,140,153,
226,242,229,225,235,233,238,231,243,240,225,227,101,128,0,160,
229,238,244,232,225,105,128,14,19,245,244,232,225,105,128,14,
25,239,110,7,140,178,140,187,140,201,140,235,140,251,141,36,
141,95,225,242,225,226,233,99,128,6,70,230,233,238,225,236,
225,242,225,226,233,99,128,254,230,231,232,245,238,238,97,2,
140,212,140,221,225,242,225,226,233,99,128,6,186,230,233,238,
225,236,225,242,225,226,233,99,128,251,159,233,238,233,244,233,
225,236,225,242,225,226,233,99,128,254,231,234,229,229,237,105,
2,141,5,141,20,238,233,244,233,225,236,225,242,225,226,233,
99,128,252,210,243,239,236,225,244,229,228,225,242,225,226,233,
99,128,252,75,237,101,2,141,43,141,56,228,233,225,236,225,
242,225,226,233,99,128,254,232,229,237,105,2,141,64,141,79,
238,233,244,233,225,236,225,242,225,226,233,99,128,252,213,243,
239,236,225,244,229,228,225,242,225,226,233,99,128,252,78,238,
239,239,238,230,233,238,225,236,225,242,225,226,233,99,128,252,
141,116,7,141,129,141,140,141,169,141,204,141,216,141,236,142,
6,227,239,238,244,225,233,238,115,128,34,12,101,2,141,146,
141,162,236,229,237,229,238,116,129,34,9,141,157,239,102,128,
34,9,241,245,225,108,128,34,96,231,242,229,225,244,229,114,
129,34,111,141,181,238,239,114,2,141,189,141,197,229,241,245,
225,108,128,34,113,236,229,243,115,128,34,121,233,228,229,238,
244,233,227,225,108,128,34,98,236,229,243,115,129,34,110,141,
225,238,239,242,229,241,245,225,108,128,34,112,112,2,141,242,
141,252,225,242,225,236,236,229,108,128,34,38,242,229,227,229,
228,229,115,128,34,128,243,117,3,142,15,142,22,142,31,226,
243,229,116,128,34,132,227,227,229,229,228,115,128,34,129,240,
229,242,243,229,116,128,34,133,247,225,242,237,229,238,233,225,
110,128,5,118,240,225,242,229,110,128,36,169,115,2,142,66,
142,75,243,241,245,225,242,101,128,51,177,245,240,229,242,233,
239,114,128,32,127,244,233,236,228,101,128,0,241,117,132,3,
189,142,105,142,116,142,197,143,24,232,233,242,225,231,225,238,
97,128,48,108,107,2,142,122,142,146,225,244,225,235,225,238,
97,129,48,204,142,134,232,225,236,230,247,233,228,244,104,128,
255,135,244,97,3,142,155,142,165,142,172,226,229,238,231,225,
236,105,128,9,188,228,229,246,97,128,9,60,231,117,2,142,
179,142,188,234,225,242,225,244,105,128,10,188,242,237,245,235,
232,105,128,10,60,109,2,142,203,142,237,226,229,242,243,233,
231,110,130,0,35,142,217,142,229,237,239,238,239,243,240,225,
227,101,128,255,3,243,237,225,236,108,128,254,95,229,114,2,
142,244,143,20,225,236,243,233,231,110,2,142,255,143,7,231,
242,229,229,107,128,3,116,236,239,247,229,242,231,242,229,229,
107,128,3,117,111,128,33,22,110,130,5,224,143,32,143,52,
228,225,231,229,243,104,129,251,64,143,43,232,229,226,242,229,
119,128,251,64,232,229,226,242,229,119,128,5,224,246,243,241,
245,225,242,101,128,51,181,247,243,241,245,225,242,101,128,51,
187,249,97,3,143,90,143,100,143,107,226,229,238,231,225,236,
105,128,9,158,228,229,246,97,128,9,30,231,117,2,143,114,
143,123,234,225,242,225,244,105,128,10,158,242,237,245,235,232,
105,128,10,30,111,147,0,111,143,174,143,196,144,18,144,188,
145,4,145,19,145,59,145,182,145,203,145,241,145,252,146,174,
148,8,148,72,148,105,148,151,149,24,149,71,149,83,97,2,
143,180,143,187,227,245,244,101,128,0,243,238,231,244,232,225,
105,128,14,45,98,4,143,206,143,248,144,1,144,11,225,242,
242,229,100,130,2,117,143,218,143,229,227,249,242,233,236,236,
233,99,128,4,233,228,233,229,242,229,243,233,243,227,249,242,
233,236,236,233,99,128,4,235,229,238,231,225,236,105,128,9,
147,239,240,239,237,239,230,111,128,49,27,242,229,246,101,128,
1,79,99,3,144,26,144,99,144,178,97,2,144,32,144,93,
238,228,242,97,3,144,43,144,50,144,61,228,229,246,97,128,
9,17,231,245,234,225,242,225,244,105,128,10,145,246,239,247,
229,236,243,233,231,110,2,144,75,144,82,228,229,246,97,128,
9,73,231,245,234,225,242,225,244,105,128,10,201,242,239,110,
128,1,210,233,242,99,2,144,107,144,112,236,101,128,36,222,
245,237,230,236,229,120,133,0,244,144,131,144,139,144,150,144,
158,144,170,225,227,245,244,101,128,30,209,228,239,244,226,229,
236,239,119,128,30,217,231,242,225,246,101,128,30,211,232,239,
239,235,225,226,239,246,101,128,30,213,244,233,236,228,101,128,
30,215,249,242,233,236,236,233,99,128,4,62,100,4,144,198,
144,221,144,227,144,250,226,108,2,144,205,144,213,225,227,245,
244,101,128,1,81,231,242,225,246,101,128,2,13,229,246,97,
128,9,19,233,229,242,229,243,233,115,129,0,246,144,239,227,
249,242,233,236,236,233,99,128,4,231,239,244,226,229,236,239,
119,128,30,205,101,129,1,83,145,10,235,239,242,229,225,110,
128,49,90,103,3,145,27,145,42,145,49,239,238,229,107,129,
2,219,145,36,227,237,98,128,3,40,242,225,246,101,128,0,
242,245,234,225,242,225,244,105,128,10,147,104,4,145,69,145,
80,145,90,145,168,225,242,237,229,238,233,225,110,128,5,133,
233,242,225,231,225,238,97,128,48,74,111,2,145,96,145,106,
239,235,225,226,239,246,101,128,30,207,242,110,133,1,161,145,
121,145,129,145,140,145,148,145,160,225,227,245,244,101,128,30,
219,228,239,244,226,229,236,239,119,128,30,227,231,242,225,246,
101,128,30,221,232,239,239,235,225,226,239,246,101,128,30,223,
244,233,236,228,101,128,30,225,245,238,231,225,242,245,237,236,
225,245,116,128,1,81,105,129,1,163,145,188,238,246,229,242,
244,229,228,226,242,229,246,101,128,2,15,107,2,145,209,145,
233,225,244,225,235,225,238,97,129,48,170,145,221,232,225,236,
230,247,233,228,244,104,128,255,117,239,242,229,225,110,128,49,
87,236,229,232,229,226,242,229,119,128,5,171,109,6,146,10,
146,38,146,45,146,134,146,145,146,163,225,227,242,239,110,130,
1,77,146,22,146,30,225,227,245,244,101,128,30,83,231,242,
225,246,101,128,30,81,228,229,246,97,128,9,80,229,231,97,
133,3,201,146,61,146,65,146,76,146,90,146,106,49,128,3,
214,227,249,242,233,236,236,233,99,128,4,97,236,225,244,233,
238,227,236,239,243,229,100,128,2,119,242,239,245,238,228,227,
249,242,233,236,236,233,99,128,4,123,116,2,146,112,146,127,
233,244,236,239,227,249,242,233,236,236,233,99,128,4,125,239,
238,239,115,128,3,206,231,245,234,225,242,225,244,105,128,10,
208,233,227,242,239,110,129,3,191,146,155,244,239,238,239,115,
128,3,204,239,238,239,243,240,225,227,101,128,255,79,238,101,
145,0,49,146,213,146,222,146,232,147,6,147,31,147,40,147,
49,147,74,147,108,147,142,147,154,147,173,147,184,147,217,147,
227,147,235,147,246,225,242,225,226,233,99,128,6,97,226,229,
238,231,225,236,105,128,9,231,227,233,242,227,236,101,129,36,
96,146,243,233,238,246,229,242,243,229,243,225,238,243,243,229,
242,233,102,128,39,138,100,2,147,12,147,18,229,246,97,128,
9,103,239,244,229,238,236,229,225,228,229,114,128,32,36,229,
233,231,232,244,104,128,33,91,230,233,244,244,229,100,128,246,
220,231,117,2,147,56,147,65,234,225,242,225,244,105,128,10,
231,242,237,245,235,232,105,128,10,103,232,97,3,147,83,147,
94,147,99,227,235,225,242,225,226,233,99,128,6,97,236,102,
128,0,189,238,231,250,232,239,117,128,48,33,105,2,147,114,
147,132,228,229,239,231,242,225,240,232,233,227,240,225,242,229,
110,128,50,32,238,230,229,242,233,239,114,128,32,129,237,239,
238,239,243,240,225,227,101,128,255,17,238,245,237,229,242,225,
244,239,242,226,229,238,231,225,236,105,128,9,244,239,236,228,
243,244,249,236,101,128,247,49,112,2,147,190,147,197,225,242,
229,110,128,36,116,229,114,2,147,204,147,210,233,239,100,128,
36,136,243,233,225,110,128,6,241,241,245,225,242,244,229,114,
128,0,188,242,239,237,225,110,128,33,112,243,245,240,229,242,
233,239,114,128,0,185,244,104,2,147,253,148,2,225,105,128,
14,81,233,242,100,128,33,83,111,3,148,16,148,50,148,66,
103,2,148,22,148,40,239,238,229,107,129,1,235,148,31,237,
225,227,242,239,110,128,1,237,245,242,237,245,235,232,105,128,
10,19,237,225,244,242,225,231,245,242,237,245,235,232,105,128,
10,75,240,229,110,128,2,84,112,3,148,80,148,87,148,98,
225,242,229,110,128,36,170,229,238,226,245,236,236,229,116,128,
37,230,244,233,239,110,128,35,37,114,2,148,111,148,140,100,
2,148,117,148,128,230,229,237,233,238,233,238,101,128,0,170,
237,225,243,227,245,236,233,238,101,128,0,186,244,232,239,231,
239,238,225,108,128,34,31,115,5,148,163,148,195,148,212,149,
1,149,14,232,239,242,116,2,148,172,148,179,228,229,246,97,
128,9,18,246,239,247,229,236,243,233,231,238,228,229,246,97,
128,9,74,236,225,243,104,129,0,248,148,204,225,227,245,244,
101,128,1,255,237,225,236,108,2,148,221,148,232,232,233,242,
225,231,225,238,97,128,48,73,235,225,244,225,235,225,238,97,
129,48,169,148,245,232,225,236,230,247,233,228,244,104,128,255,
107,244,242,239,235,229,225,227,245,244,101,128,1,255,245,240,
229,242,233,239,114,128,246,240,116,2,149,30,149,41,227,249,
242,233,236,236,233,99,128,4,127,233,236,228,101,130,0,245,
149,52,149,60,225,227,245,244,101,128,30,77,228,233,229,242,
229,243,233,115,128,30,79,245,226,239,240,239,237,239,230,111,
128,49,33,118,2,149,89,149,170,229,114,2,149,96,149,162,
236,233,238,101,131,32,62,149,109,149,132,149,155,99,2,149,
115,149,127,229,238,244,229,242,236,233,238,101,128,254,74,237,
98,128,3,5,100,2,149,138,149,146,225,243,232,229,100,128,
254,73,226,236,247,225,246,121,128,254,76,247,225,246,121,128,
254,75,243,227,239,242,101,128,0,175,239,247,229,236,243,233,
231,110,3,149,185,149,195,149,202,226,229,238,231,225,236,105,
128,9,203,228,229,246,97,128,9,75,231,245,234,225,242,225,
244,105,128,10,203,112,145,0,112,149,251,152,123,152,134,152,
143,152,155,154,80,154,90,155,82,156,101,156,191,156,217,157,
92,157,100,158,2,158,60,158,88,158,98,97,14,150,25,150,
57,150,67,150,74,150,81,150,129,150,140,150,154,150,165,150,
212,150,226,151,238,152,21,152,111,97,2,150,31,150,43,237,
240,243,243,241,245,225,242,101,128,51,128,243,229,238,244,239,
243,241,245,225,242,101,128,51,43,226,229,238,231,225,236,105,
128,9,170,227,245,244,101,128,30,85,228,229,246,97,128,9,
42,103,2,150,87,150,105,101,2,150,93,150,100,228,239,247,
110,128,33,223,245,112,128,33,222,117,2,150,111,150,120,234,
225,242,225,244,105,128,10,170,242,237,245,235,232,105,128,10,
42,232,233,242,225,231,225,238,97,128,48,113,233,249,225,238,
238,239,233,244,232,225,105,128,14,47,235,225,244,225,235,225,
238,97,128,48,209,108,2,150,171,150,196,225,244,225,236,233,
250,225,244,233,239,238,227,249,242,233,236,236,233,227,227,237,
98,128,4,132,239,227,232,235,225,227,249,242,233,236,236,233,
99,128,4,192,238,243,233,239,243,235,239,242,229,225,110,128,
49,127,114,3,150,234,150,255,151,227,97,2,150,240,150,248,
231,242,225,240,104,128,0,182,236,236,229,108,128,34,37,229,
110,2,151,6,151,116,236,229,230,116,136,0,40,151,29,151,
44,151,49,151,54,151,65,151,77,151,100,151,105,225,236,244,
239,238,229,225,242,225,226,233,99,128,253,62,226,116,128,248,
237,229,120,128,248,236,233,238,230,229,242,233,239,114,128,32,
141,237,239,238,239,243,240,225,227,101,128,255,8,115,2,151,
83,151,90,237,225,236,108,128,254,89,245,240,229,242,233,239,
114,128,32,125,244,112,128,248,235,246,229,242,244,233,227,225,
108,128,254,53,242,233,231,232,116,136,0,41,151,140,151,155,
151,160,151,165,151,176,151,188,151,211,151,216,225,236,244,239,
238,229,225,242,225,226,233,99,128,253,63,226,116,128,248,248,
229,120,128,248,247,233,238,230,229,242,233,239,114,128,32,142,
237,239,238,239,243,240,225,227,101,128,255,9,115,2,151,194,
151,201,237,225,236,108,128,254,90,245,240,229,242,233,239,114,
128,32,126,244,112,128,248,246,246,229,242,244,233,227,225,108,
128,254,54,244,233,225,236,228,233,230,102,128,34,2,115,3,
151,246,152,1,152,13,229,241,232,229,226,242,229,119,128,5,
192,232,244,225,232,229,226,242,229,119,128,5,153,241,245,225,
242,101,128,51,169,244,225,104,134,5,183,152,39,152,53,152,
58,152,67,152,82,152,98,49,2,152,45,152,49,49,128,5,
183,100,128,5,183,178,97,128,5,183,232,229,226,242,229,119,
128,5,183,238,225,242,242,239,247,232,229,226,242,229,119,128,
5,183,241,245,225,242,244,229,242,232,229,226,242,229,119,128,
5,183,247,233,228,229,232,229,226,242,229,119,128,5,183,250,
229,242,232,229,226,242,229,119,128,5,161,226,239,240,239,237,
239,230,111,128,49,6,227,233,242,227,236,101,128,36,223,228,
239,244,225,227,227,229,238,116,128,30,87,101,137,5,228,152,
177,152,188,152,208,152,220,152,240,153,86,153,97,153,118,154,
73,227,249,242,233,236,236,233,99,128,4,63,228,225,231,229,
243,104,129,251,68,152,199,232,229,226,242,229,119,128,251,68,
229,250,233,243,241,245,225,242,101,128,51,59,230,233,238,225,
236,228,225,231,229,243,232,232,229,226,242,229,119,128,251,67,
104,5,152,252,153,19,153,27,153,41,153,71,225,114,2,153,
3,153,10,225,226,233,99,128,6,126,237,229,238,233,225,110,
128,5,122,229,226,242,229,119,128,5,228,230,233,238,225,236,
225,242,225,226,233,99,128,251,87,105,2,153,47,153,62,238,
233,244,233,225,236,225,242,225,226,233,99,128,251,88,242,225,
231,225,238,97,128,48,122,237,229,228,233,225,236,225,242,225,
226,233,99,128,251,89,235,225,244,225,235,225,238,97,128,48,
218,237,233,228,228,236,229,232,239,239,235,227,249,242,233,236,
236,233,99,128,4,167,114,5,153,130,153,142,153,184,154,49,
154,62,225,230,229,232,229,226,242,229,119,128,251,78,227,229,
238,116,131,0,37,153,155,153,164,153,176,225,242,225,226,233,
99,128,6,106,237,239,238,239,243,240,225,227,101,128,255,5,
243,237,225,236,108,128,254,106,105,2,153,190,154,31,239,100,
134,0,46,153,207,153,218,153,229,153,241,153,252,154,8,225,
242,237,229,238,233,225,110,128,5,137,227,229,238,244,229,242,
229,100,128,0,183,232,225,236,230,247,233,228,244,104,128,255,
97,233,238,230,229,242,233,239,114,128,246,231,237,239,238,239,
243,240,225,227,101,128,255,14,115,2,154,14,154,21,237,225,
236,108,128,254,82,245,240,229,242,233,239,114,128,246,232,243,
240,239,237,229,238,233,231,242,229,229,235,227,237,98,128,3,
66,240,229,238,228,233,227,245,236,225,114,128,34,165,244,232,
239,245,243,225,238,100,128,32,48,243,229,244,97,128,32,167,
230,243,241,245,225,242,101,128,51,138,104,3,154,98,154,148,
155,29,97,3,154,106,154,116,154,123,226,229,238,231,225,236,
105,128,9,171,228,229,246,97,128,9,43,231,117,2,154,130,
154,139,234,225,242,225,244,105,128,10,171,242,237,245,235,232,
105,128,10,43,105,133,3,198,154,162,154,166,154,252,155,4,
155,15,49,128,3,213,229,245,240,104,4,154,179,154,214,154,
229,154,238,97,2,154,185,154,200,227,233,242,227,236,229,235,
239,242,229,225,110,128,50,122,240,225,242,229,238,235,239,242,
229,225,110,128,50,26,227,233,242,227,236,229,235,239,242,229,
225,110,128,50,108,235,239,242,229,225,110,128,49,77,240,225,
242,229,238,235,239,242,229,225,110,128,50,12,236,225,244,233,
110,128,2,120,238,244,232,245,244,232,225,105,128,14,58,243,
249,237,226,239,236,231,242,229,229,107,128,3,213,111,3,155,
37,155,42,155,68,239,107,128,1,165,240,104,2,155,49,155,
58,225,238,244,232,225,105,128,14,30,245,238,231,244,232,225,
105,128,14,28,243,225,237,240,232,225,239,244,232,225,105,128,
14,32,105,133,3,192,155,96,156,52,156,63,156,74,156,88,
229,245,112,6,155,112,155,147,155,179,155,207,155,221,156,17,
97,2,155,118,155,133,227,233,242,227,236,229,235,239,242,229,
225,110,128,50,115,240,225,242,229,238,235,239,242,229,225,110,
128,50,19,227,105,2,155,154,155,166,229,245,227,235,239,242,
229,225,110,128,49,118,242,227,236,229,235,239,242,229,225,110,
128,50,101,107,2,155,185,155,199,233,249,229,239,235,235,239,
242,229,225,110,128,49,114,239,242,229,225,110,128,49,66,240,
225,242,229,238,235,239,242,229,225,110,128,50,5,243,233,239,
115,2,155,230,156,2,107,2,155,236,155,250,233,249,229,239,
235,235,239,242,229,225,110,128,49,116,239,242,229,225,110,128,
49,68,244,233,235,229,245,244,235,239,242,229,225,110,128,49,
117,116,2,156,23,156,38,232,233,229,245,244,232,235,239,242,
229,225,110,128,49,119,233,235,229,245,244,235,239,242,229,225,
110,128,49,115,232,233,242,225,231,225,238,97,128,48,116,235,
225,244,225,235,225,238,97,128,48,212,243,249,237,226,239,236,
231,242,229,229,107,128,3,214,247,242,225,242,237,229,238,233,
225,110,128,5,131,236,245,115,132,0,43,156,115,156,126,156,
135,156,168,226,229,236,239,247,227,237,98,128,3,31,227,233,
242,227,236,101,128,34,149,109,2,156,141,156,148,233,238,245,
115,128,0,177,111,2,156,154,156,158,100,128,2,214,238,239,
243,240,225,227,101,128,255,11,115,2,156,174,156,181,237,225,
236,108,128,254,98,245,240,229,242,233,239,114,128,32,122,109,
2,156,197,156,208,239,238,239,243,240,225,227,101,128,255,80,
243,241,245,225,242,101,128,51,216,111,5,156,229,156,240,157,
51,157,62,157,72,232,233,242,225,231,225,238,97,128,48,125,
233,238,244,233,238,231,233,238,228,229,120,4,157,4,157,16,
157,28,157,41,228,239,247,238,247,232,233,244,101,128,38,31,
236,229,230,244,247,232,233,244,101,128,38,28,242,233,231,232,
244,247,232,233,244,101,128,38,30,245,240,247,232,233,244,101,
128,38,29,235,225,244,225,235,225,238,97,128,48,221,240,236,
225,244,232,225,105,128,14,27,243,244,225,236,237,225,242,107,
129,48,18,157,85,230,225,227,101,128,48,32,240,225,242,229,
110,128,36,171,114,3,157,108,157,134,157,159,101,2,157,114,
157,122,227,229,228,229,115,128,34,122,243,227,242,233,240,244,
233,239,110,128,33,30,233,237,101,2,157,142,157,148,237,239,
100,128,2,185,242,229,246,229,242,243,229,100,128,32,53,111,
4,157,169,157,176,157,186,157,199,228,245,227,116,128,34,15,
234,229,227,244,233,246,101,128,35,5,236,239,238,231,229,228,
235,225,238,97,128,48,252,112,2,157,205,157,242,101,2,157,
211,157,218,236,236,239,114,128,35,24,242,243,117,2,157,226,
157,233,226,243,229,116,128,34,130,240,229,242,243,229,116,128,
34,131,239,242,244,233,239,110,129,34,55,157,253,225,108,128,
34,29,115,2,158,8,158,51,105,130,3,200,158,16,158,27,
227,249,242,233,236,236,233,99,128,4,113,236,233,240,238,229,
245,237,225,244,225,227,249,242,233,236,236,233,227,227,237,98,
128,4,134,243,241,245,225,242,101,128,51,176,117,2,158,66,
158,77,232,233,242,225,231,225,238,97,128,48,119,235,225,244,
225,235,225,238,97,128,48,215,246,243,241,245,225,242,101,128,
51,180,247,243,241,245,225,242,101,128,51,186,113,136,0,113,
158,128,159,177,159,188,159,197,159,204,159,216,159,254,160,6,
97,4,158,138,158,161,158,225,159,160,100,2,158,144,158,150,
229,246,97,128,9,88,237,225,232,229,226,242,229,119,128,5,
168,102,4,158,171,158,180,158,194,158,210,225,242,225,226,233,
99,128,6,66,230,233,238,225,236,225,242,225,226,233,99,128,
254,214,233,238,233,244,233,225,236,225,242,225,226,233,99,128,
254,215,237,229,228,233,225,236,225,242,225,226,233,99,128,254,
216,237,225,244,115,136,5,184,158,248,159,12,159,26,159,31,
159,36,159,45,159,60,159,147,49,3,159,0,159,4,159,8,
48,128,5,184,97,128,5,184,99,128,5,184,50,2,159,18,
159,22,55,128,5,184,57,128,5,184,179,51,128,5,184,228,
101,128,5,184,232,229,226,242,229,119,128,5,184,238,225,242,
242,239,247,232,229,226,242,229,119,128,5,184,113,2,159,66,
159,132,225,244,225,110,4,159,79,159,88,159,103,159,119,232,
229,226,242,229,119,128,5,184,238,225,242,242,239,247,232,229,
226,242,229,119,128,5,184,241,245,225,242,244,229,242,232,229,
226,242,229,119,128,5,184,247,233,228,229,232,229,226,242,229,
119,128,5,184,245,225,242,244,229,242,232,229,226,242,229,119,
128,5,184,247,233,228,229,232,229,226,242,229,119,128,5,184,
242,238,229,249,240,225,242,225,232,229,226,242,229,119,128,5,
159,226,239,240,239,237,239,230,111,128,49,17,227,233,242,227,
236,101,128,36,224,232,239,239,107,128,2,160,237,239,238,239,
243,240,225,227,101,128,255,81,239,102,130,5,231,159,225,159,
245,228,225,231,229,243,104,129,251,71,159,236,232,229,226,242,
229,119,128,251,71,232,229,226,242,229,119,128,5,231,240,225,
242,229,110,128,36,172,117,4,160,16,160,28,160,117,160,204,
225,242,244,229,242,238,239,244,101,128,38,105,226,245,244,115,
135,5,187,160,49,160,54,160,59,160,64,160,73,160,88,160,
104,177,56,128,5,187,178,53,128,5,187,179,49,128,5,187,
232,229,226,242,229,119,128,5,187,238,225,242,242,239,247,232,
229,226,242,229,119,128,5,187,241,245,225,242,244,229,242,232,
229,226,242,229,119,128,5,187,247,233,228,229,232,229,226,242,
229,119,128,5,187,229,243,244,233,239,110,133,0,63,160,136,
160,159,160,176,160,184,160,196,225,114,2,160,143,160,150,225,
226,233,99,128,6,31,237,229,238,233,225,110,128,5,94,228,
239,247,110,129,0,191,160,168,243,237,225,236,108,128,247,191,
231,242,229,229,107,128,3,126,237,239,238,239,243,240,225,227,
101,128,255,31,243,237,225,236,108,128,247,63,239,244,101,4,
160,216,161,31,161,51,161,80,228,226,108,133,0,34,160,232,
160,239,160,246,161,2,161,23,226,225,243,101,128,32,30,236,
229,230,116,128,32,28,237,239,238,239,243,240,225,227,101,128,
255,2,240,242,233,237,101,129,48,30,161,12,242,229,246,229,
242,243,229,100,128,48,29,242,233,231,232,116,128,32,29,236,
229,230,116,129,32,24,161,40,242,229,246,229,242,243,229,100,
128,32,27,114,2,161,57,161,67,229,246,229,242,243,229,100,
128,32,27,233,231,232,116,129,32,25,161,76,110,128,1,73,
243,233,238,231,108,2,161,90,161,97,226,225,243,101,128,32,
26,101,129,0,39,161,103,237,239,238,239,243,240,225,227,101,
128,255,7,114,145,0,114,161,153,162,157,162,168,162,215,163,
10,164,27,164,51,164,146,166,180,166,217,166,229,167,27,167,
35,167,197,167,208,167,243,168,87,97,11,161,177,161,188,161,
198,161,205,162,14,162,30,162,55,162,66,162,91,162,114,162,
151,225,242,237,229,238,233,225,110,128,5,124,226,229,238,231,
225,236,105,128,9,176,227,245,244,101,128,1,85,100,4,161,
215,161,221,161,235,162,5,229,246,97,128,9,48,233,227,225,
108,129,34,26,161,230,229,120,128,248,229,239,246,229,242,243,
243,241,245,225,242,101,129,51,174,161,251,228,243,241,245,225,
242,101,128,51,175,243,241,245,225,242,101,128,51,173,230,101,
129,5,191,162,21,232,229,226,242,229,119,128,5,191,231,117,
2,162,37,162,46,234,225,242,225,244,105,128,10,176,242,237,
245,235,232,105,128,10,48,232,233,242,225,231,225,238,97,128,
48,137,235,225,244,225,235,225,238,97,129,48,233,162,79,232,
225,236,230,247,233,228,244,104,128,255,151,236,239,247,229,242,
228,233,225,231,239,238,225,236,226,229,238,231,225,236,105,128,
9,241,109,2,162,120,162,143,233,228,228,236,229,228,233,225,
231,239,238,225,236,226,229,238,231,225,236,105,128,9,240,243,
232,239,242,110,128,2,100,244,233,111,128,34,54,226,239,240,
239,237,239,230,111,128,49,22,99,4,162,178,162,185,162,194,
162,202,225,242,239,110,128,1,89,229,228,233,236,236,97,128,
1,87,233,242,227,236,101,128,36,225,239,237,237,225,225,227,
227,229,238,116,128,1,87,100,2,162,221,162,231,226,236,231,
242,225,246,101,128,2,17,239,116,2,162,238,162,247,225,227,
227,229,238,116,128,30,89,226,229,236,239,119,129,30,91,163,
1,237,225,227,242,239,110,128,30,93,101,6,163,24,163,69,
163,104,163,159,163,184,163,217,102,2,163,30,163,43,229,242,
229,238,227,229,237,225,242,107,128,32,59,236,229,248,243,117,
2,163,53,163,60,226,243,229,116,128,34,134,240,229,242,243,
229,116,128,34,135,231,233,243,244,229,114,2,163,80,163,85,
229,100,128,0,174,115,2,163,91,163,97,225,238,115,128,248,
232,229,242,233,102,128,246,218,104,3,163,112,163,135,163,149,
225,114,2,163,119,163,126,225,226,233,99,128,6,49,237,229,
238,233,225,110,128,5,128,230,233,238,225,236,225,242,225,226,
233,99,128,254,174,233,242,225,231,225,238,97,128,48,140,235,
225,244,225,235,225,238,97,129,48,236,163,172,232,225,236,230,
247,233,228,244,104,128,255,154,243,104,130,5,232,163,193,163,
208,228,225,231,229,243,232,232,229,226,242,229,119,128,251,72,
232,229,226,242,229,119,128,5,232,118,3,163,225,163,238,164,
14,229,242,243,229,228,244,233,236,228,101,128,34,61,233,97,
2,163,245,163,254,232,229,226,242,229,119,128,5,151,237,245,
231,242,225,243,232,232,229,226,242,229,119,128,5,151,236,239,
231,233,227,225,236,238,239,116,128,35,16,230,233,243,232,232,
239,239,107,129,2,126,164,40,242,229,246,229,242,243,229,100,
128,2,127,104,2,164,57,164,80,97,2,164,63,164,73,226,
229,238,231,225,236,105,128,9,221,228,229,246,97,128,9,93,
111,131,3,193,164,90,164,119,164,133,239,107,129,2,125,164,
97,244,245,242,238,229,100,129,2,123,164,108,243,245,240,229,
242,233,239,114,128,2,181,243,249,237,226,239,236,231,242,229,
229,107,128,3,241,244,233,227,232,239,239,235,237,239,100,128,
2,222,105,6,164,160,165,204,165,250,166,5,166,30,166,166,
229,245,108,9,164,182,164,217,164,232,164,246,165,36,165,50,
165,136,165,149,165,184,97,2,164,188,164,203,227,233,242,227,
236,229,235,239,242,229,225,110,128,50,113,240,225,242,229,238,
235,239,242,229,225,110,128,50,17,227,233,242,227,236,229,235,
239,242,229,225,110,128,50,99,232,233,229,245,232,235,239,242,
229,225,110,128,49,64,107,2,164,252,165,28,233,249,229,239,
107,2,165,6,165,15,235,239,242,229,225,110,128,49,58,243,
233,239,243,235,239,242,229,225,110,128,49,105,239,242,229,225,
110,128,49,57,237,233,229,245,237,235,239,242,229,225,110,128,
49,59,112,3,165,58,165,90,165,105,97,2,165,64,165,78,
238,243,233,239,243,235,239,242,229,225,110,128,49,108,242,229,
238,235,239,242,229,225,110,128,50,3,232,233,229,245,240,232,
235,239,242,229,225,110,128,49,63,233,229,245,112,2,165,114,
165,123,235,239,242,229,225,110,128,49,60,243,233,239,243,235,
239,242,229,225,110,128,49,107,243,233,239,243,235,239,242,229,
225,110,128,49,61,116,2,165,155,165,170,232,233,229,245,244,
232,235,239,242,229,225,110,128,49,62,233,235,229,245,244,235,
239,242,229,225,110,128,49,106,249,229,239,242,233,238,232,233,
229,245,232,235,239,242,229,225,110,128,49,109,231,232,116,2,
165,212,165,220,225,238,231,236,101,128,34,31,116,2,165,226,
165,240,225,227,235,226,229,236,239,247,227,237,98,128,3,25,
242,233,225,238,231,236,101,128,34,191,232,233,242,225,231,225,
238,97,128,48,138,235,225,244,225,235,225,238,97,129,48,234,
166,18,232,225,236,230,247,233,228,244,104,128,255,152,110,2,
166,36,166,152,103,131,2,218,166,46,166,57,166,63,226,229,
236,239,247,227,237,98,128,3,37,227,237,98,128,3,10,232,
225,236,102,2,166,72,166,118,236,229,230,116,131,2,191,166,
85,166,96,166,107,225,242,237,229,238,233,225,110,128,5,89,
226,229,236,239,247,227,237,98,128,3,28,227,229,238,244,229,
242,229,100,128,2,211,242,233,231,232,116,130,2,190,166,130,
166,141,226,229,236,239,247,227,237,98,128,3,57,227,229,238,
244,229,242,229,100,128,2,210,246,229,242,244,229,228,226,242,
229,246,101,128,2,19,244,244,239,242,245,243,241,245,225,242,
101,128,51,81,108,2,166,186,166,197,233,238,229,226,229,236,
239,119,128,30,95,239,238,231,236,229,103,129,2,124,166,208,
244,245,242,238,229,100,128,2,122,237,239,238,239,243,240,225,
227,101,128,255,82,111,3,166,237,166,248,167,17,232,233,242,
225,231,225,238,97,128,48,141,235,225,244,225,235,225,238,97,
129,48,237,167,5,232,225,236,230,247,233,228,244,104,128,255,
155,242,245,225,244,232,225,105,128,14,35,240,225,242,229,110,
128,36,173,114,3,167,43,167,79,167,109,97,3,167,51,167,
61,167,68,226,229,238,231,225,236,105,128,9,220,228,229,246,
97,128,9,49,231,245,242,237,245,235,232,105,128,10,92,229,
104,2,167,86,167,95,225,242,225,226,233,99,128,6,145,230,
233,238,225,236,225,242,225,226,233,99,128,251,141,246,239,227,
225,236,233,99,4,167,125,167,135,167,142,167,153,226,229,238,
231,225,236,105,128,9,224,228,229,246,97,128,9,96,231,245,
234,225,242,225,244,105,128,10,224,246,239,247,229,236,243,233,
231,110,3,167,169,167,179,167,186,226,229,238,231,225,236,105,
128,9,196,228,229,246,97,128,9,68,231,245,234,225,242,225,
244,105,128,10,196,243,245,240,229,242,233,239,114,128,246,241,
116,2,167,214,167,222,226,236,239,227,107,128,37,144,245,242,
238,229,100,129,2,121,167,232,243,245,240,229,242,233,239,114,
128,2,180,117,4,167,253,168,8,168,33,168,80,232,233,242,
225,231,225,238,97,128,48,139,235,225,244,225,235,225,238,97,
129,48,235,168,21,232,225,236,230,247,233,228,244,104,128,255,
153,112,2,168,39,168,74,229,101,2,168,46,168,60,237,225,
242,235,226,229,238,231,225,236,105,128,9,242,243,233,231,238,
226,229,238,231,225,236,105,128,9,243,233,225,104,128,246,221,
244,232,225,105,128,14,36,246,239,227,225,236,233,99,4,168,
103,168,113,168,120,168,131,226,229,238,231,225,236,105,128,9,
139,228,229,246,97,128,9,11,231,245,234,225,242,225,244,105,
128,10,139,246,239,247,229,236,243,233,231,110,3,168,147,168,
157,168,164,226,229,238,231,225,236,105,128,9,195,228,229,246,
97,128,9,67,231,245,234,225,242,225,244,105,128,10,195,115,
147,0,115,168,217,170,187,170,198,171,68,171,107,174,49,174,
60,176,203,179,85,179,131,179,158,180,93,180,160,181,193,181,
203,182,133,182,206,183,120,183,130,97,9,168,237,168,247,169,
12,169,84,169,109,169,120,169,145,169,177,169,217,226,229,238,
231,225,236,105,128,9,184,227,245,244,101,129,1,91,169,0,
228,239,244,225,227,227,229,238,116,128,30,101,100,5,169,24,
169,33,169,39,169,53,169,69,225,242,225,226,233,99,128,6,
53,229,246,97,128,9,56,230,233,238,225,236,225,242,225,226,
233,99,128,254,186,233,238,233,244,233,225,236,225,242,225,226,
233,99,128,254,187,237,229,228,233,225,236,225,242,225,226,233,
99,128,254,188,231,117,2,169,91,169,100,234,225,242,225,244,
105,128,10,184,242,237,245,235,232,105,128,10,56,232,233,242,
225,231,225,238,97,128,48,85,235,225,244,225,235,225,238,97,
129,48,181,169,133,232,225,236,230,247,233,228,244,104,128,255,
123,236,236,225,236,236,225,232,239,245,225,236,225,249,232,229,
247,225,243,225,236,236,225,237,225,242,225,226,233,99,128,253,
250,237,229,235,104,130,5,225,169,188,169,208,228,225,231,229,
243,104,129,251,65,169,199,232,229,226,242,229,119,128,251,65,
232,229,226,242,229,119,128,5,225,242,97,5,169,230,170,48,
170,56,170,106,170,114,97,5,169,242,169,250,170,2,170,33,
170,41,225,244,232,225,105,128,14,50,229,244,232,225,105,128,
14,65,233,237,225,233,109,2,170,12,170,23,225,236,225,233,
244,232,225,105,128,14,68,245,225,238,244,232,225,105,128,14,
67,237,244,232,225,105,128,14,51,244,232,225,105,128,14,48,
229,244,232,225,105,128,14,64,105,3,170,64,170,88,170,99,
105,2,170,70,170,81,236,229,230,244,244,232,225,105,128,248,
134,244,232,225,105,128,14,53,236,229,230,244,244,232,225,105,
128,248,133,244,232,225,105,128,14,52,239,244,232,225,105,128,
14,66,117,3,170,122,170,172,170,179,101,3,170,130,170,154,
170,165,101,2,170,136,170,147,236,229,230,244,244,232,225,105,
128,248,136,244,232,225,105,128,14,55,236,229,230,244,244,232,
225,105,128,248,135,244,232,225,105,128,14,54,244,232,225,105,
128,14,56,245,244,232,225,105,128,14,57,226,239,240,239,237,
239,230,111,128,49,25,99,5,170,210,170,231,170,240,171,33,
171,55,225,242,239,110,129,1,97,170,219,228,239,244,225,227,
227,229,238,116,128,30,103,229,228,233,236,236,97,128,1,95,
232,247,97,131,2,89,170,252,171,7,171,26,227,249,242,233,
236,236,233,99,128,4,217,228,233,229,242,229,243,233,243,227,
249,242,233,236,236,233,99,128,4,219,232,239,239,107,128,2,
90,233,242,99,2,171,41,171,46,236,101,128,36,226,245,237,
230,236,229,120,128,1,93,239,237,237,225,225,227,227,229,238,
116,128,2,25,228,239,116,2,171,76,171,85,225,227,227,229,
238,116,128,30,97,226,229,236,239,119,129,30,99,171,95,228,
239,244,225,227,227,229,238,116,128,30,105,101,9,171,127,171,
143,171,178,171,243,172,90,172,117,172,142,172,223,172,250,225,
231,245,236,236,226,229,236,239,247,227,237,98,128,3,60,99,
2,171,149,171,171,239,238,100,129,32,51,171,157,244,239,238,
229,227,232,233,238,229,243,101,128,2,202,244,233,239,110,128,
0,167,229,110,4,171,189,171,198,171,212,171,228,225,242,225,
226,233,99,128,6,51,230,233,238,225,236,225,242,225,226,233,
99,128,254,178,233,238,233,244,233,225,236,225,242,225,226,233,
99,128,254,179,237,229,228,233,225,236,225,242,225,226,233,99,
128,254,180,231,239,108,135,5,182,172,7,172,21,172,26,172,
35,172,50,172,66,172,77,49,2,172,13,172,17,51,128,5,
182,102,128,5,182,178,99,128,5,182,232,229,226,242,229,119,
128,5,182,238,225,242,242,239,247,232,229,226,242,229,119,128,
5,182,241,245,225,242,244,229,242,232,229,226,242,229,119,128,
5,182,244,225,232,229,226,242,229,119,128,5,146,247,233,228,
229,232,229,226,242,229,119,128,5,182,104,2,172,96,172,107,
225,242,237,229,238,233,225,110,128,5,125,233,242,225,231,225,
238,97,128,48,91,235,225,244,225,235,225,238,97,129,48,187,
172,130,232,225,236,230,247,233,228,244,104,128,255,126,237,105,
2,172,149,172,192,227,239,236,239,110,131,0,59,172,163,172,
172,172,184,225,242,225,226,233,99,128,6,27,237,239,238,239,
243,240,225,227,101,128,255,27,243,237,225,236,108,128,254,84,
246,239,233,227,229,228,237,225,242,235,235,225,238,97,129,48,
156,172,211,232,225,236,230,247,233,228,244,104,128,255,159,238,
116,2,172,230,172,240,233,243,241,245,225,242,101,128,51,34,
239,243,241,245,225,242,101,128,51,35,246,229,110,142,0,55,
173,28,173,37,173,47,173,77,173,84,173,94,173,119,173,146,
173,180,173,192,173,203,173,236,173,244,173,255,225,242,225,226,
233,99,128,6,103,226,229,238,231,225,236,105,128,9,237,227,
233,242,227,236,101,129,36,102,173,58,233,238,246,229,242,243,
229,243,225,238,243,243,229,242,233,102,128,39,144,228,229,246,
97,128,9,109,229,233,231,232,244,232,115,128,33,94,231,117,
2,173,101,173,110,234,225,242,225,244,105,128,10,237,242,237,
245,235,232,105,128,10,109,232,97,2,173,126,173,137,227,235,
225,242,225,226,233,99,128,6,103,238,231,250,232,239,117,128,
48,39,105,2,173,152,173,170,228,229,239,231,242,225,240,232,
233,227,240,225,242,229,110,128,50,38,238,230,229,242,233,239,
114,128,32,135,237,239,238,239,243,240,225,227,101,128,255,23,
239,236,228,243,244,249,236,101,128,247,55,112,2,173,209,173,
216,225,242,229,110,128,36,122,229,114,2,173,223,173,229,233,
239,100,128,36,142,243,233,225,110,128,6,247,242,239,237,225,
110,128,33,118,243,245,240,229,242,233,239,114,128,32,119,116,
2,174,5,174,43,229,229,110,2,174,13,174,22,227,233,242,
227,236,101,128,36,112,112,2,174,28,174,35,225,242,229,110,
128,36,132,229,242,233,239,100,128,36,152,232,225,105,128,14,
87,230,244,232,249,240,232,229,110,128,0,173,104,7,174,76,
175,50,175,61,175,75,176,20,176,33,176,197,97,6,174,90,
174,101,174,111,174,122,175,9,175,34,225,242,237,229,238,233,
225,110,128,5,119,226,229,238,231,225,236,105,128,9,182,227,
249,242,233,236,236,233,99,128,4,72,100,2,174,128,174,224,
228,97,4,174,139,174,148,174,179,174,193,225,242,225,226,233,
99,128,6,81,228,225,237,237,97,2,174,158,174,167,225,242,
225,226,233,99,128,252,97,244,225,238,225,242,225,226,233,99,
128,252,94,230,225,244,232,225,225,242,225,226,233,99,128,252,
96,235,225,243,242,97,2,174,203,174,212,225,242,225,226,233,
99,128,252,98,244,225,238,225,242,225,226,233,99,128,252,95,
101,132,37,146,174,236,174,243,174,251,175,4,228,225,242,107,
128,37,147,236,233,231,232,116,128,37,145,237,229,228,233,245,
109,128,37,146,246,97,128,9,54,231,117,2,175,16,175,25,
234,225,242,225,244,105,128,10,182,242,237,245,235,232,105,128,
10,54,236,243,232,229,236,229,244,232,229,226,242,229,119,128,
5,147,226,239,240,239,237,239,230,111,128,49,21,227,232,225,
227,249,242,233,236,236,233,99,128,4,73,101,4,175,85,175,
150,175,160,175,177,229,110,4,175,96,175,105,175,119,175,135,
225,242,225,226,233,99,128,6,52,230,233,238,225,236,225,242,
225,226,233,99,128,254,182,233,238,233,244,233,225,236,225,242,
225,226,233,99,128,254,183,237,229,228,233,225,236,225,242,225,
226,233,99,128,254,184,233,227,239,240,244,233,99,128,3,227,
241,229,108,129,32,170,175,168,232,229,226,242,229,119,128,32,
170,246,97,134,5,176,175,194,175,209,175,223,175,232,175,247,
176,7,49,2,175,200,175,205,177,53,128,5,176,53,128,5,
176,50,2,175,215,175,219,50,128,5,176,101,128,5,176,232,
229,226,242,229,119,128,5,176,238,225,242,242,239,247,232,229,
226,242,229,119,128,5,176,241,245,225,242,244,229,242,232,229,
226,242,229,119,128,5,176,247,233,228,229,232,229,226,242,229,
119,128,5,176,232,225,227,249,242,233,236,236,233,99,128,4,
187,105,2,176,39,176,50,237,225,227,239,240,244,233,99,128,
3,237,110,131,5,233,176,60,176,143,176,152,100,2,176,66,
176,132,225,231,229,243,104,130,251,73,176,78,176,87,232,229,
226,242,229,119,128,251,73,115,2,176,93,176,113,232,233,238,
228,239,116,129,251,44,176,104,232,229,226,242,229,119,128,251,
44,233,238,228,239,116,129,251,45,176,123,232,229,226,242,229,
119,128,251,45,239,244,232,229,226,242,229,119,128,5,193,232,
229,226,242,229,119,128,5,233,115,2,176,158,176,178,232,233,
238,228,239,116,129,251,42,176,169,232,229,226,242,229,119,128,
251,42,233,238,228,239,116,129,251,43,176,188,232,229,226,242,
229,119,128,251,43,239,239,107,128,2,130,105,8,176,221,177,
9,177,20,177,45,177,75,177,83,177,96,178,11,231,237,97,
131,3,195,176,233,176,237,176,245,49,128,3,194,230,233,238,
225,108,128,3,194,236,245,238,225,244,229,243,249,237,226,239,
236,231,242,229,229,107,128,3,242,232,233,242,225,231,225,238,
97,128,48,87,235,225,244,225,235,225,238,97,129,48,183,177,
33,232,225,236,230,247,233,228,244,104,128,255,124,236,245,113,
2,177,53,177,62,232,229,226,242,229,119,128,5,189,236,229,
230,244,232,229,226,242,229,119,128,5,189,237,233,236,225,114,
128,34,60,238,228,239,244,232,229,226,242,229,119,128,5,194,
239,115,6,177,111,177,146,177,178,177,206,177,220,177,252,97,
2,177,117,177,132,227,233,242,227,236,229,235,239,242,229,225,
110,128,50,116,240,225,242,229,238,235,239,242,229,225,110,128,
50,20,227,105,2,177,153,177,165,229,245,227,235,239,242,229,
225,110,128,49,126,242,227,236,229,235,239,242,229,225,110,128,
50,102,107,2,177,184,177,198,233,249,229,239,235,235,239,242,
229,225,110,128,49,122,239,242,229,225,110,128,49,69,238,233,
229,245,238,235,239,242,229,225,110,128,49,123,112,2,177,226,
177,239,225,242,229,238,235,239,242,229,225,110,128,50,6,233,
229,245,240,235,239,242,229,225,110,128,49,125,244,233,235,229,
245,244,235,239,242,229,225,110,128,49,124,120,141,0,54,178,
41,178,50,178,60,178,90,178,97,178,122,178,149,178,183,178,
195,178,206,178,239,178,247,179,2,225,242,225,226,233,99,128,
6,102,226,229,238,231,225,236,105,128,9,236,227,233,242,227,
236,101,129,36,101,178,71,233,238,246,229,242,243,229,243,225,
238,243,243,229,242,233,102,128,39,143,228,229,246,97,128,9,
108,231,117,2,178,104,178,113,234,225,242,225,244,105,128,10,
236,242,237,245,235,232,105,128,10,108,232,97,2,178,129,178,
140,227,235,225,242,225,226,233,99,128,6,102,238,231,250,232,
239,117,128,48,38,105,2,178,155,178,173,228,229,239,231,242,
225,240,232,233,227,240,225,242,229,110,128,50,37,238,230,229,
242,233,239,114,128,32,134,237,239,238,239,243,240,225,227,101,
128,255,22,239,236,228,243,244,249,236,101,128,247,54,112,2,
178,212,178,219,225,242,229,110,128,36,121,229,114,2,178,226,
178,232,233,239,100,128,36,141,243,233,225,110,128,6,246,242,
239,237,225,110,128,33,117,243,245,240,229,242,233,239,114,128,
32,118,116,2,179,8,179,79,229,229,110,2,179,16,179,58,
99,2,179,22,179,30,233,242,227,236,101,128,36,111,245,242,
242,229,238,227,249,228,229,238,239,237,233,238,225,244,239,242,
226,229,238,231,225,236,105,128,9,249,112,2,179,64,179,71,
225,242,229,110,128,36,131,229,242,233,239,100,128,36,151,232,
225,105,128,14,86,108,2,179,91,179,111,225,243,104,129,0,
47,179,99,237,239,238,239,243,240,225,227,101,128,255,15,239,
238,103,129,1,127,179,119,228,239,244,225,227,227,229,238,116,
128,30,155,109,2,179,137,179,147,233,236,229,230,225,227,101,
128,38,58,239,238,239,243,240,225,227,101,128,255,83,111,6,
179,172,179,222,179,233,180,2,180,47,180,58,102,2,179,178,
179,192,240,225,243,245,241,232,229,226,242,229,119,128,5,195,
116,2,179,198,179,207,232,249,240,232,229,110,128,0,173,243,
233,231,238,227,249,242,233,236,236,233,99,128,4,76,232,233,
242,225,231,225,238,97,128,48,93,235,225,244,225,235,225,238,
97,129,48,189,179,246,232,225,236,230,247,233,228,244,104,128,
255,127,236,233,228,245,115,2,180,12,180,29,236,239,238,231,
239,246,229,242,236,225,249,227,237,98,128,3,56,243,232,239,
242,244,239,246,229,242,236,225,249,227,237,98,128,3,55,242,
245,243,233,244,232,225,105,128,14,41,115,3,180,66,180,76,
180,84,225,236,225,244,232,225,105,128,14,40,239,244,232,225,
105,128,14,11,245,225,244,232,225,105,128,14,42,240,97,3,
180,102,180,122,180,154,227,101,129,0,32,180,109,232,225,227,
235,225,242,225,226,233,99,128,0,32,228,101,129,38,96,180,
129,243,245,233,116,2,180,138,180,146,226,236,225,227,107,128,
38,96,247,232,233,244,101,128,38,100,242,229,110,128,36,174,
241,245,225,242,101,11,180,188,180,199,180,213,180,238,180,255,
181,25,181,40,181,73,181,100,181,156,181,171,226,229,236,239,
247,227,237,98,128,3,59,99,2,180,205,180,209,99,128,51,
196,109,128,51,157,228,233,225,231,239,238,225,236,227,242,239,
243,243,232,225,244,227,232,230,233,236,108,128,37,169,232,239,
242,233,250,239,238,244,225,236,230,233,236,108,128,37,164,107,
2,181,5,181,9,103,128,51,143,109,129,51,158,181,15,227,
225,240,233,244,225,108,128,51,206,108,2,181,31,181,35,110,
128,51,209,239,103,128,51,210,109,4,181,50,181,54,181,59,
181,63,103,128,51,142,233,108,128,51,213,109,128,51,156,243,
241,245,225,242,229,100,128,51,161,239,242,244,232,239,231,239,
238,225,236,227,242,239,243,243,232,225,244,227,232,230,233,236,
108,128,37,166,245,240,240,229,114,2,181,110,181,133,236,229,
230,244,244,239,236,239,247,229,242,242,233,231,232,244,230,233,
236,108,128,37,167,242,233,231,232,244,244,239,236,239,247,229,
242,236,229,230,244,230,233,236,108,128,37,168,246,229,242,244,
233,227,225,236,230,233,236,108,128,37,165,247,232,233,244,229,
247,233,244,232,243,237,225,236,236,226,236,225,227,107,128,37,
163,242,243,241,245,225,242,101,128,51,219,115,2,181,209,182,
123,97,4,181,219,181,229,181,236,181,247,226,229,238,231,225,
236,105,128,9,183,228,229,246,97,128,9,55,231,245,234,225,
242,225,244,105,128,10,183,238,103,8,182,10,182,24,182,38,
182,52,182,67,182,81,182,95,182,108,227,233,229,245,227,235,
239,242,229,225,110,128,49,73,232,233,229,245,232,235,239,242,
229,225,110,128,49,133,233,229,245,238,231,235,239,242,229,225,
110,128,49,128,235,233,249,229,239,235,235,239,242,229,225,110,
128,49,50,238,233,229,245,238,235,239,242,229,225,110,128,49,
101,240,233,229,245,240,235,239,242,229,225,110,128,49,67,243,
233,239,243,235,239,242,229,225,110,128,49,70,244,233,235,229,
245,244,235,239,242,229,225,110,128,49,56,245,240,229,242,233,
239,114,128,246,242,116,2,182,139,182,162,229,242,236,233,238,
103,129,0,163,182,150,237,239,238,239,243,240,225,227,101,128,
255,225,242,239,235,101,2,182,171,182,188,236,239,238,231,239,
246,229,242,236,225,249,227,237,98,128,3,54,243,232,239,242,
244,239,246,229,242,236,225,249,227,237,98,128,3,53,117,7,
182,222,182,254,183,20,183,31,183,72,183,82,183,86,226,243,
229,116,130,34,130,182,233,182,244,238,239,244,229,241,245,225,
108,128,34,138,239,242,229,241,245,225,108,128,34,134,99,2,
183,4,183,12,227,229,229,228,115,128,34,123,232,244,232,225,
116,128,34,11,232,233,242,225,231,225,238,97,128,48,89,107,
2,183,37,183,61,225,244,225,235,225,238,97,129,48,185,183,
49,232,225,236,230,247,233,228,244,104,128,255,125,245,238,225,
242,225,226,233,99,128,6,82,237,237,225,244,233,239,110,128,
34,17,110,128,38,60,240,229,242,243,229,116,130,34,131,183,
99,183,110,238,239,244,229,241,245,225,108,128,34,139,239,242,
229,241,245,225,108,128,34,135,246,243,241,245,225,242,101,128,
51,220,249,239,245,247,225,229,242,225,243,241,245,225,242,101,
128,51,124,116,144,0,116,183,183,184,192,184,213,185,100,185,
140,187,188,191,70,192,145,192,157,192,169,193,202,193,227,194,
57,194,237,195,165,195,255,97,10,183,205,183,215,183,236,183,
243,184,12,184,90,184,107,184,132,184,146,184,150,226,229,238,
231,225,236,105,128,9,164,227,107,2,183,222,183,229,228,239,
247,110,128,34,164,236,229,230,116,128,34,163,228,229,246,97,
128,9,36,231,117,2,183,250,184,3,234,225,242,225,244,105,
128,10,164,242,237,245,235,232,105,128,10,36,104,4,184,22,
184,31,184,45,184,75,225,242,225,226,233,99,128,6,55,230,
233,238,225,236,225,242,225,226,233,99,128,254,194,105,2,184,
51,184,66,238,233,244,233,225,236,225,242,225,226,233,99,128,
254,195,242,225,231,225,238,97,128,48,95,237,229,228,233,225,
236,225,242,225,226,233,99,128,254,196,233,243,249,239,245,229,
242,225,243,241,245,225,242,101,128,51,125,235,225,244,225,235,
225,238,97,129,48,191,184,120,232,225,236,230,247,233,228,244,
104,128,255,128,244,247,229,229,236,225,242,225,226,233,99,128,
6,64,117,128,3,196,118,130,5,234,184,158,184,183,228,225,
231,229,115,129,251,74,184,168,104,129,251,74,184,174,232,229,
226,242,229,119,128,251,74,232,229,226,242,229,119,128,5,234,
98,2,184,198,184,203,225,114,128,1,103,239,240,239,237,239,
230,111,128,49,10,99,6,184,227,184,234,184,241,184,250,185,
60,185,87,225,242,239,110,128,1,101,227,245,242,108,128,2,
168,229,228,233,236,236,97,128,1,99,232,229,104,4,185,6,
185,15,185,29,185,45,225,242,225,226,233,99,128,6,134,230,
233,238,225,236,225,242,225,226,233,99,128,251,123,233,238,233,
244,233,225,236,225,242,225,226,233,99,128,251,124,237,229,228,
233,225,236,225,242,225,226,233,99,128,251,125,233,242,99,2,
185,68,185,73,236,101,128,36,227,245,237,230,236,229,248,226,
229,236,239,119,128,30,113,239,237,237,225,225,227,227,229,238,
116,128,1,99,100,2,185,106,185,116,233,229,242,229,243,233,
115,128,30,151,239,116,2,185,123,185,132,225,227,227,229,238,
116,128,30,107,226,229,236,239,119,128,30,109,101,9,185,160,
185,171,185,191,186,201,186,226,187,34,187,101,187,106,187,158,
227,249,242,233,236,236,233,99,128,4,66,228,229,243,227,229,
238,228,229,242,227,249,242,233,236,236,233,99,128,4,173,104,
7,185,207,185,216,185,230,186,14,186,44,186,85,186,183,225,
242,225,226,233,99,128,6,42,230,233,238,225,236,225,242,225,
226,233,99,128,254,150,232,225,232,105,2,185,239,185,254,238,
233,244,233,225,236,225,242,225,226,233,99,128,252,162,243,239,
236,225,244,229,228,225,242,225,226,233,99,128,252,12,105,2,
186,20,186,35,238,233,244,233,225,236,225,242,225,226,233,99,
128,254,151,242,225,231,225,238,97,128,48,102,234,229,229,237,
105,2,186,54,186,69,238,233,244,233,225,236,225,242,225,226,
233,99,128,252,161,243,239,236,225,244,229,228,225,242,225,226,
233,99,128,252,11,109,2,186,91,186,125,225,242,226,245,244,
97,2,186,102,186,111,225,242,225,226,233,99,128,6,41,230,
233,238,225,236,225,242,225,226,233,99,128,254,148,101,2,186,
131,186,144,228,233,225,236,225,242,225,226,233,99,128,254,152,
229,237,105,2,186,152,186,167,238,233,244,233,225,236,225,242,
225,226,233,99,128,252,164,243,239,236,225,244,229,228,225,242,
225,226,233,99,128,252,14,238,239,239,238,230,233,238,225,236,
225,242,225,226,233,99,128,252,115,235,225,244,225,235,225,238,
97,129,48,198,186,214,232,225,236,230,247,233,228,244,104,128,
255,131,108,2,186,232,186,251,229,240,232,239,238,101,129,33,
33,186,243,226,236,225,227,107,128,38,14,233,243,232,97,2,
187,4,187,19,231,229,228,239,236,225,232,229,226,242,229,119,
128,5,160,241,229,244,225,238,225,232,229,226,242,229,119,128,
5,169,110,4,187,44,187,53,187,72,187,93,227,233,242,227,
236,101,128,36,105,233,228,229,239,231,242,225,240,232,233,227,
240,225,242,229,110,128,50,41,112,2,187,78,187,85,225,242,
229,110,128,36,125,229,242,233,239,100,128,36,145,242,239,237,
225,110,128,33,121,243,104,128,2,167,116,131,5,216,187,116,
187,136,187,145,228,225,231,229,243,104,129,251,56,187,127,232,
229,226,242,229,119,128,251,56,232,229,226,242,229,119,128,5,
216,243,229,227,249,242,233,236,236,233,99,128,4,181,246,233,
114,2,187,166,187,175,232,229,226,242,229,119,128,5,155,236,
229,230,244,232,229,226,242,229,119,128,5,155,104,6,187,202,
188,98,188,220,189,96,190,3,191,60,97,5,187,214,187,224,
187,231,188,0,188,29,226,229,238,231,225,236,105,128,9,165,
228,229,246,97,128,9,37,231,117,2,187,238,187,247,234,225,
242,225,244,105,128,10,165,242,237,245,235,232,105,128,10,37,
108,2,188,6,188,15,225,242,225,226,233,99,128,6,48,230,
233,238,225,236,225,242,225,226,233,99,128,254,172,238,244,232,
225,235,232,225,116,3,188,44,188,75,188,82,236,239,119,2,
188,52,188,63,236,229,230,244,244,232,225,105,128,248,152,242,
233,231,232,244,244,232,225,105,128,248,151,244,232,225,105,128,
14,76,245,240,240,229,242,236,229,230,244,244,232,225,105,128,
248,150,101,3,188,106,188,170,188,193,104,4,188,116,188,125,
188,139,188,155,225,242,225,226,233,99,128,6,43,230,233,238,
225,236,225,242,225,226,233,99,128,254,154,233,238,233,244,233,
225,236,225,242,225,226,233,99,128,254,155,237,229,228,233,225,
236,225,242,225,226,233,99,128,254,156,242,101,2,188,177,188,
186,229,248,233,243,244,115,128,34,3,230,239,242,101,128,34,
52,244,97,130,3,184,188,202,188,206,49,128,3,209,243,249,
237,226,239,236,231,242,229,229,107,128,3,209,105,2,188,226,
189,56,229,245,244,104,4,188,239,189,18,189,33,189,42,97,
2,188,245,189,4,227,233,242,227,236,229,235,239,242,229,225,
110,128,50,121,240,225,242,229,238,235,239,242,229,225,110,128,
50,25,227,233,242,227,236,229,235,239,242,229,225,110,128,50,
107,235,239,242,229,225,110,128,49,76,240,225,242,229,238,235,
239,242,229,225,110,128,50,11,242,244,229,229,110,2,189,66,
189,75,227,233,242,227,236,101,128,36,108,112,2,189,81,189,
88,225,242,229,110,128,36,128,229,242,233,239,100,128,36,148,
111,6,189,110,189,127,189,132,189,146,189,151,189,204,238,225,
238,231,237,239,238,244,232,239,244,232,225,105,128,14,17,239,
107,128,1,173,240,232,245,244,232,225,239,244,232,225,105,128,
14,18,242,110,128,0,254,244,104,3,189,160,189,184,189,194,
97,2,189,166,189,176,232,225,238,244,232,225,105,128,14,23,
238,244,232,225,105,128,14,16,239,238,231,244,232,225,105,128,
14,24,245,238,231,244,232,225,105,128,14,22,245,243,225,238,
100,2,189,214,189,225,227,249,242,233,236,236,233,99,128,4,
130,243,243,229,240,225,242,225,244,239,114,2,189,240,189,249,
225,242,225,226,233,99,128,6,108,240,229,242,243,233,225,110,
128,6,108,242,229,101,144,0,51,190,41,190,50,190,60,190,
90,190,97,190,107,190,132,190,159,190,193,190,205,190,224,190,
235,191,12,191,34,191,42,191,53,225,242,225,226,233,99,128,
6,99,226,229,238,231,225,236,105,128,9,233,227,233,242,227,
236,101,129,36,98,190,71,233,238,246,229,242,243,229,243,225,
238,243,243,229,242,233,102,128,39,140,228,229,246,97,128,9,
105,229,233,231,232,244,232,115,128,33,92,231,117,2,190,114,
190,123,234,225,242,225,244,105,128,10,233,242,237,245,235,232,
105,128,10,105,232,97,2,190,139,190,150,227,235,225,242,225,
226,233,99,128,6,99,238,231,250,232,239,117,128,48,35,105,
2,190,165,190,183,228,229,239,231,242,225,240,232,233,227,240,
225,242,229,110,128,50,34,238,230,229,242,233,239,114,128,32,
131,237,239,238,239,243,240,225,227,101,128,255,19,238,245,237,
229,242,225,244,239,242,226,229,238,231,225,236,105,128,9,246,
239,236,228,243,244,249,236,101,128,247,51,112,2,190,241,190,
248,225,242,229,110,128,36,118,229,114,2,190,255,191,5,233,
239,100,128,36,138,243,233,225,110,128,6,243,241,245,225,242,
244,229,242,115,129,0,190,191,25,229,237,228,225,243,104,128,
246,222,242,239,237,225,110,128,33,114,243,245,240,229,242,233,
239,114,128,0,179,244,232,225,105,128,14,83,250,243,241,245,
225,242,101,128,51,148,105,7,191,86,191,97,191,212,192,54,
192,66,192,115,192,132,232,233,242,225,231,225,238,97,128,48,
97,107,2,191,103,191,127,225,244,225,235,225,238,97,129,48,
193,191,115,232,225,236,230,247,233,228,244,104,128,255,129,229,
245,116,4,191,139,191,174,191,189,191,198,97,2,191,145,191,
160,227,233,242,227,236,229,235,239,242,229,225,110,128,50,112,
240,225,242,229,238,235,239,242,229,225,110,128,50,16,227,233,
242,227,236,229,235,239,242,229,225,110,128,50,98,235,239,242,
229,225,110,128,49,55,240,225,242,229,238,235,239,242,229,225,
110,128,50,2,236,228,101,133,2,220,191,228,191,239,192,0,
192,12,192,40,226,229,236,239,247,227,237,98,128,3,48,99,
2,191,245,191,250,237,98,128,3,3,239,237,98,128,3,3,
228,239,245,226,236,229,227,237,98,128,3,96,111,2,192,18,
192,28,240,229,242,225,244,239,114,128,34,60,246,229,242,236,
225,249,227,237,98,128,3,52,246,229,242,244,233,227,225,236,
227,237,98,128,3,62,237,229,243,227,233,242,227,236,101,128,
34,151,112,2,192,72,192,102,229,232,97,2,192,80,192,89,
232,229,226,242,229,119,128,5,150,236,229,230,244,232,229,226,
242,229,119,128,5,150,240,233,231,245,242,237,245,235,232,105,
128,10,112,244,236,239,227,249,242,233,236,236,233,227,227,237,
98,128,4,131,247,238,225,242,237,229,238,233,225,110,128,5,
127,236,233,238,229,226,229,236,239,119,128,30,111,237,239,238,
239,243,240,225,227,101,128,255,84,111,7,192,185,192,196,192,
207,192,232,193,96,193,108,193,192,225,242,237,229,238,233,225,
110,128,5,105,232,233,242,225,231,225,238,97,128,48,104,235,
225,244,225,235,225,238,97,129,48,200,192,220,232,225,236,230,
247,233,228,244,104,128,255,132,110,3,192,240,193,82,193,87,
101,4,192,250,193,63,193,70,193,76,226,225,114,4,193,6,
193,35,193,45,193,54,229,248,244,242,97,2,193,16,193,26,
232,233,231,232,237,239,100,128,2,229,236,239,247,237,239,100,
128,2,233,232,233,231,232,237,239,100,128,2,230,236,239,247,
237,239,100,128,2,232,237,233,228,237,239,100,128,2,231,230,
233,246,101,128,1,189,243,233,120,128,1,133,244,247,111,128,
1,168,239,115,128,3,132,243,241,245,225,242,101,128,51,39,
240,225,244,225,235,244,232,225,105,128,14,15,242,244,239,233,
243,229,243,232,229,236,236,226,242,225,227,235,229,116,2,193,
131,193,161,236,229,230,116,130,48,20,193,142,193,150,243,237,
225,236,108,128,254,93,246,229,242,244,233,227,225,108,128,254,
57,242,233,231,232,116,130,48,21,193,173,193,181,243,237,225,
236,108,128,254,94,246,229,242,244,233,227,225,108,128,254,58,
244,225,239,244,232,225,105,128,14,21,240,97,2,193,209,193,
221,236,225,244,225,236,232,239,239,107,128,1,171,242,229,110,
128,36,175,114,3,193,235,194,10,194,25,225,228,229,237,225,
242,107,129,33,34,193,247,115,2,193,253,194,3,225,238,115,
128,248,234,229,242,233,102,128,246,219,229,244,242,239,230,236,
229,248,232,239,239,107,128,2,136,233,225,103,4,194,37,194,
42,194,47,194,52,228,110,128,37,188,236,102,128,37,196,242,
116,128,37,186,245,112,128,37,178,115,132,2,166,194,69,194,
108,194,214,194,227,225,228,105,130,5,230,194,79,194,99,228,
225,231,229,243,104,129,251,70,194,90,232,229,226,242,229,119,
128,251,70,232,229,226,242,229,119,128,5,230,101,2,194,114,
194,125,227,249,242,233,236,236,233,99,128,4,70,242,101,134,
5,181,194,142,194,156,194,161,194,170,194,185,194,201,49,2,
194,148,194,152,50,128,5,181,101,128,5,181,178,98,128,5,
181,232,229,226,242,229,119,128,5,181,238,225,242,242,239,247,
232,229,226,242,229,119,128,5,181,241,245,225,242,244,229,242,
232,229,226,242,229,119,128,5,181,247,233,228,229,232,229,226,
242,229,119,128,5,181,232,229,227,249,242,233,236,236,233,99,
128,4,91,245,240,229,242,233,239,114,128,246,243,116,4,194,
247,195,41,195,106,195,157,97,3,194,255,195,9,195,16,226,
229,238,231,225,236,105,128,9,159,228,229,246,97,128,9,31,
231,117,2,195,23,195,32,234,225,242,225,244,105,128,10,159,
242,237,245,235,232,105,128,10,31,229,104,4,195,52,195,61,
195,75,195,91,225,242,225,226,233,99,128,6,121,230,233,238,
225,236,225,242,225,226,233,99,128,251,103,233,238,233,244,233,
225,236,225,242,225,226,233,99,128,251,104,237,229,228,233,225,
236,225,242,225,226,233,99,128,251,105,232,97,3,195,115,195,
125,195,132,226,229,238,231,225,236,105,128,9,160,228,229,246,
97,128,9,32,231,117,2,195,139,195,148,234,225,242,225,244,
105,128,10,160,242,237,245,235,232,105,128,10,32,245,242,238,
229,100,128,2,135,117,3,195,173,195,184,195,209,232,233,242,
225,231,225,238,97,128,48,100,235,225,244,225,235,225,238,97,
129,48,196,195,197,232,225,236,230,247,233,228,244,104,128,255,
130,243,237,225,236,108,2,195,219,195,230,232,233,242,225,231,
225,238,97,128,48,99,235,225,244,225,235,225,238,97,129,48,
195,195,243,232,225,236,230,247,233,228,244,104,128,255,111,119,
2,196,5,196,110,101,2,196,11,196,59,236,246,101,3,196,
21,196,30,196,51,227,233,242,227,236,101,128,36,107,112,2,
196,36,196,43,225,242,229,110,128,36,127,229,242,233,239,100,
128,36,147,242,239,237,225,110,128,33,123,238,244,121,3,196,
69,196,78,196,89,227,233,242,227,236,101,128,36,115,232,225,
238,231,250,232,239,117,128,83,68,112,2,196,95,196,102,225,
242,229,110,128,36,135,229,242,233,239,100,128,36,155,111,142,
0,50,196,142,196,151,196,161,196,191,196,243,197,12,197,39,
197,73,197,85,197,104,197,115,197,148,197,156,197,180,225,242,
225,226,233,99,128,6,98,226,229,238,231,225,236,105,128,9,
232,227,233,242,227,236,101,129,36,97,196,172,233,238,246,229,
242,243,229,243,225,238,243,243,229,242,233,102,128,39,139,100,
2,196,197,196,203,229,246,97,128,9,104,239,116,2,196,210,
196,221,229,238,236,229,225,228,229,114,128,32,37,236,229,225,
228,229,114,129,32,37,196,232,246,229,242,244,233,227,225,108,
128,254,48,231,117,2,196,250,197,3,234,225,242,225,244,105,
128,10,232,242,237,245,235,232,105,128,10,104,232,97,2,197,
19,197,30,227,235,225,242,225,226,233,99,128,6,98,238,231,
250,232,239,117,128,48,34,105,2,197,45,197,63,228,229,239,
231,242,225,240,232,233,227,240,225,242,229,110,128,50,33,238,
230,229,242,233,239,114,128,32,130,237,239,238,239,243,240,225,
227,101,128,255,18,238,245,237,229,242,225,244,239,242,226,229,
238,231,225,236,105,128,9,245,239,236,228,243,244,249,236,101,
128,247,50,112,2,197,121,197,128,225,242,229,110,128,36,117,
229,114,2,197,135,197,141,233,239,100,128,36,137,243,233,225,
110,128,6,242,242,239,237,225,110,128,33,113,115,2,197,162,
197,170,244,242,239,235,101,128,1,187,245,240,229,242,233,239,
114,128,0,178,244,104,2,197,187,197,192,225,105,128,14,82,
233,242,228,115,128,33,84,117,145,0,117,197,237,197,245,198,
30,198,87,198,225,199,6,199,129,199,145,199,196,200,10,200,
91,200,100,200,219,200,243,201,95,201,123,201,237,225,227,245,
244,101,128,0,250,98,4,197,255,198,4,198,13,198,23,225,
114,128,2,137,229,238,231,225,236,105,128,9,137,239,240,239,
237,239,230,111,128,49,40,242,229,246,101,128,1,109,99,3,
198,38,198,45,198,77,225,242,239,110,128,1,212,233,242,99,
2,198,53,198,58,236,101,128,36,228,245,237,230,236,229,120,
129,0,251,198,69,226,229,236,239,119,128,30,119,249,242,233,
236,236,233,99,128,4,67,100,5,198,99,198,110,198,133,198,
139,198,215,225,244,244,225,228,229,246,97,128,9,81,226,108,
2,198,117,198,125,225,227,245,244,101,128,1,113,231,242,225,
246,101,128,2,21,229,246,97,128,9,9,233,229,242,229,243,
233,115,133,0,252,198,159,198,167,198,175,198,198,198,206,225,
227,245,244,101,128,1,216,226,229,236,239,119,128,30,115,99,
2,198,181,198,188,225,242,239,110,128,1,218,249,242,233,236,
236,233,99,128,4,241,231,242,225,246,101,128,1,220,237,225,
227,242,239,110,128,1,214,239,244,226,229,236,239,119,128,30,
229,103,2,198,231,198,238,242,225,246,101,128,0,249,117,2,
198,244,198,253,234,225,242,225,244,105,128,10,137,242,237,245,
235,232,105,128,10,9,104,3,199,14,199,24,199,102,233,242,
225,231,225,238,97,128,48,70,111,2,199,30,199,40,239,235,
225,226,239,246,101,128,30,231,242,110,133,1,176,199,55,199,
63,199,74,199,82,199,94,225,227,245,244,101,128,30,233,228,
239,244,226,229,236,239,119,128,30,241,231,242,225,246,101,128,
30,235,232,239,239,235,225,226,239,246,101,128,30,237,244,233,
236,228,101,128,30,239,245,238,231,225,242,245,237,236,225,245,
116,129,1,113,199,118,227,249,242,233,236,236,233,99,128,4,
243,233,238,246,229,242,244,229,228,226,242,229,246,101,128,2,
23,107,3,199,153,199,177,199,188,225,244,225,235,225,238,97,
129,48,166,199,165,232,225,236,230,247,233,228,244,104,128,255,
115,227,249,242,233,236,236,233,99,128,4,121,239,242,229,225,
110,128,49,92,109,2,199,202,199,255,97,2,199,208,199,241,
227,242,239,110,130,1,107,199,219,199,230,227,249,242,233,236,
236,233,99,128,4,239,228,233,229,242,229,243,233,115,128,30,
123,244,242,225,231,245,242,237,245,235,232,105,128,10,65,239,
238,239,243,240,225,227,101,128,255,85,110,2,200,16,200,71,
228,229,242,243,227,239,242,101,132,0,95,200,35,200,41,200,
53,200,64,228,226,108,128,32,23,237,239,238,239,243,240,225,
227,101,128,255,63,246,229,242,244,233,227,225,108,128,254,51,
247,225,246,121,128,254,79,105,2,200,77,200,82,239,110,128,
34,42,246,229,242,243,225,108,128,34,0,239,231,239,238,229,
107,128,1,115,112,5,200,112,200,119,200,127,200,142,200,193,
225,242,229,110,128,36,176,226,236,239,227,107,128,37,128,240,
229,242,228,239,244,232,229,226,242,229,119,128,5,196,243,233,
236,239,110,131,3,197,200,156,200,177,200,185,228,233,229,242,
229,243,233,115,129,3,203,200,169,244,239,238,239,115,128,3,
176,236,225,244,233,110,128,2,138,244,239,238,239,115,128,3,
205,244,225,227,107,2,200,202,200,213,226,229,236,239,247,227,
237,98,128,3,29,237,239,100,128,2,212,114,2,200,225,200,
237,225,231,245,242,237,245,235,232,105,128,10,115,233,238,103,
128,1,111,115,3,200,251,201,10,201,55,232,239,242,244,227,
249,242,233,236,236,233,99,128,4,94,237,225,236,108,2,201,
19,201,30,232,233,242,225,231,225,238,97,128,48,69,235,225,
244,225,235,225,238,97,129,48,165,201,43,232,225,236,230,247,
233,228,244,104,128,255,105,244,242,225,233,231,232,116,2,201,
67,201,78,227,249,242,233,236,236,233,99,128,4,175,243,244,
242,239,235,229,227,249,242,233,236,236,233,99,128,4,177,244,
233,236,228,101,130,1,105,201,107,201,115,225,227,245,244,101,
128,30,121,226,229,236,239,119,128,30,117,117,5,201,135,201,
145,201,152,201,177,201,193,226,229,238,231,225,236,105,128,9,
138,228,229,246,97,128,9,10,231,117,2,201,159,201,168,234,
225,242,225,244,105,128,10,138,242,237,245,235,232,105,128,10,
10,237,225,244,242,225,231,245,242,237,245,235,232,105,128,10,
66,246,239,247,229,236,243,233,231,110,3,201,209,201,219,201,
226,226,229,238,231,225,236,105,128,9,194,228,229,246,97,128,
9,66,231,245,234,225,242,225,244,105,128,10,194,246,239,247,
229,236,243,233,231,110,3,201,253,202,7,202,14,226,229,238,
231,225,236,105,128,9,193,228,229,246,97,128,9,65,231,245,
234,225,242,225,244,105,128,10,193,118,139,0,118,202,51,202,
199,202,208,202,219,203,148,203,155,203,253,204,9,204,109,204,
117,204,138,97,4,202,61,202,68,202,93,202,104,228,229,246,
97,128,9,53,231,117,2,202,75,202,84,234,225,242,225,244,
105,128,10,181,242,237,245,235,232,105,128,10,53,235,225,244,
225,235,225,238,97,128,48,247,118,132,5,213,202,116,202,143,
202,175,202,187,228,225,231,229,243,104,130,251,53,202,129,202,
134,182,53,128,251,53,232,229,226,242,229,119,128,251,53,104,
2,202,149,202,157,229,226,242,229,119,128,5,213,239,236,225,
109,129,251,75,202,166,232,229,226,242,229,119,128,251,75,246,
225,246,232,229,226,242,229,119,128,5,240,249,239,228,232,229,
226,242,229,119,128,5,241,227,233,242,227,236,101,128,36,229,
228,239,244,226,229,236,239,119,128,30,127,101,6,202,233,202,
244,203,52,203,63,203,69,203,136,227,249,242,233,236,236,233,
99,128,4,50,104,4,202,254,203,7,203,21,203,37,225,242,
225,226,233,99,128,6,164,230,233,238,225,236,225,242,225,226,
233,99,128,251,107,233,238,233,244,233,225,236,225,242,225,226,
233,99,128,251,108,237,229,228,233,225,236,225,242,225,226,233,
99,128,251,109,235,225,244,225,235,225,238,97,128,48,249,238,
245,115,128,38,64,242,244,233,227,225,108,2,203,80,203,86,
226,225,114,128,0,124,236,233,238,101,4,203,99,203,110,203,
121,203,130,225,226,239,246,229,227,237,98,128,3,13,226,229,
236,239,247,227,237,98,128,3,41,236,239,247,237,239,100,128,
2,204,237,239,100,128,2,200,247,225,242,237,229,238,233,225,
110,128,5,126,232,239,239,107,128,2,139,105,3,203,163,203,
174,203,213,235,225,244,225,235,225,238,97,128,48,248,242,225,
237,97,3,203,185,203,195,203,202,226,229,238,231,225,236,105,
128,9,205,228,229,246,97,128,9,77,231,245,234,225,242,225,
244,105,128,10,205,243,225,242,231,97,3,203,225,203,235,203,
242,226,229,238,231,225,236,105,128,9,131,228,229,246,97,128,
9,3,231,245,234,225,242,225,244,105,128,10,131,237,239,238,
239,243,240,225,227,101,128,255,86,111,3,204,17,204,28,204,
98,225,242,237,229,238,233,225,110,128,5,120,233,227,229,100,
2,204,37,204,73,233,244,229,242,225,244,233,239,110,2,204,
51,204,62,232,233,242,225,231,225,238,97,128,48,158,235,225,
244,225,235,225,238,97,128,48,254,237,225,242,235,235,225,238,
97,129,48,155,204,86,232,225,236,230,247,233,228,244,104,128,
255,158,235,225,244,225,235,225,238,97,128,48,250,240,225,242,
229,110,128,36,177,116,2,204,123,204,130,233,236,228,101,128,
30,125,245,242,238,229,100,128,2,140,117,2,204,144,204,155,
232,233,242,225,231,225,238,97,128,48,148,235,225,244,225,235,
225,238,97,128,48,244,119,143,0,119,204,200,205,177,205,187,
205,210,205,250,206,61,206,69,208,40,208,81,208,93,208,168,
208,176,208,183,208,194,208,203,97,8,204,218,204,225,204,235,
204,246,205,28,205,60,205,72,205,108,227,245,244,101,128,30,
131,229,235,239,242,229,225,110,128,49,89,232,233,242,225,231,
225,238,97,128,48,143,107,2,204,252,205,20,225,244,225,235,
225,238,97,129,48,239,205,8,232,225,236,230,247,233,228,244,
104,128,255,156,239,242,229,225,110,128,49,88,243,237,225,236,
108,2,205,38,205,49,232,233,242,225,231,225,238,97,128,48,
142,235,225,244,225,235,225,238,97,128,48,238,244,244,239,243,
241,245,225,242,101,128,51,87,118,2,205,78,205,86,229,228,
225,243,104,128,48,28,249,245,238,228,229,242,243,227,239,242,
229,246,229,242,244,233,227,225,108,128,254,52,119,3,205,116,
205,125,205,139,225,242,225,226,233,99,128,6,72,230,233,238,
225,236,225,242,225,226,233,99,128,254,238,232,225,237,250,225,
225,226,239,246,101,2,205,154,205,163,225,242,225,226,233,99,
128,6,36,230,233,238,225,236,225,242,225,226,233,99,128,254,
134,226,243,241,245,225,242,101,128,51,221,227,233,242,99,2,
205,196,205,201,236,101,128,36,230,245,237,230,236,229,120,128,
1,117,100,2,205,216,205,226,233,229,242,229,243,233,115,128,
30,133,239,116,2,205,233,205,242,225,227,227,229,238,116,128,
30,135,226,229,236,239,119,128,30,137,101,4,206,4,206,15,
206,27,206,51,232,233,242,225,231,225,238,97,128,48,145,233,
229,242,243,244,242,225,243,115,128,33,24,107,2,206,33,206,
43,225,244,225,235,225,238,97,128,48,241,239,242,229,225,110,
128,49,94,239,235,239,242,229,225,110,128,49,93,231,242,225,
246,101,128,30,129,232,233,244,101,8,206,90,206,99,206,183,
207,17,207,101,207,146,207,198,207,254,226,245,236,236,229,116,
128,37,230,99,2,206,105,206,125,233,242,227,236,101,129,37,
203,206,115,233,238,246,229,242,243,101,128,37,217,239,242,238,
229,242,226,242,225,227,235,229,116,2,206,142,206,162,236,229,
230,116,129,48,14,206,151,246,229,242,244,233,227,225,108,128,
254,67,242,233,231,232,116,129,48,15,206,172,246,229,242,244,
233,227,225,108,128,254,68,100,2,206,189,206,230,233,225,237,
239,238,100,129,37,199,206,200,227,239,238,244,225,233,238,233,
238,231,226,236,225,227,235,243,237,225,236,236,228,233,225,237,
239,238,100,128,37,200,239,247,238,240,239,233,238,244,233,238,
103,2,206,246,207,6,243,237,225,236,236,244,242,233,225,238,
231,236,101,128,37,191,244,242,233,225,238,231,236,101,128,37,
189,236,101,2,207,24,207,66,230,244,240,239,233,238,244,233,
238,103,2,207,39,207,55,243,237,225,236,236,244,242,233,225,
238,231,236,101,128,37,195,244,242,233,225,238,231,236,101,128,
37,193,238,244,233,227,245,236,225,242,226,242,225,227,235,229,
116,2,207,86,207,93,236,229,230,116,128,48,22,242,233,231,
232,116,128,48,23,242,233,231,232,244,240,239,233,238,244,233,
238,103,2,207,119,207,135,243,237,225,236,236,244,242,233,225,
238,231,236,101,128,37,185,244,242,233,225,238,231,236,101,128,
37,183,115,3,207,154,207,184,207,192,109,2,207,160,207,172,
225,236,236,243,241,245,225,242,101,128,37,171,233,236,233,238,
231,230,225,227,101,128,38,58,241,245,225,242,101,128,37,161,
244,225,114,128,38,6,116,2,207,204,207,215,229,236,229,240,
232,239,238,101,128,38,15,239,242,244,239,233,243,229,243,232,
229,236,236,226,242,225,227,235,229,116,2,207,239,207,246,236,
229,230,116,128,48,24,242,233,231,232,116,128,48,25,245,240,
240,239,233,238,244,233,238,103,2,208,13,208,29,243,237,225,
236,236,244,242,233,225,238,231,236,101,128,37,181,244,242,233,
225,238,231,236,101,128,37,179,105,2,208,46,208,57,232,233,
242,225,231,225,238,97,128,48,144,107,2,208,63,208,73,225,
244,225,235,225,238,97,128,48,240,239,242,229,225,110,128,49,
95,237,239,238,239,243,240,225,227,101,128,255,87,111,4,208,
103,208,114,208,139,208,157,232,233,242,225,231,225,238,97,128,
48,146,235,225,244,225,235,225,238,97,129,48,242,208,127,232,
225,236,230,247,233,228,244,104,128,255,102,110,129,32,169,208,
145,237,239,238,239,243,240,225,227,101,128,255,230,247,225,229,
238,244,232,225,105,128,14,39,240,225,242,229,110,128,36,178,
242,233,238,103,128,30,152,243,245,240,229,242,233,239,114,128,
2,183,244,245,242,238,229,100,128,2,141,249,238,110,128,1,
191,120,137,0,120,208,231,208,242,208,253,209,6,209,33,209,
46,209,50,209,62,209,70,225,226,239,246,229,227,237,98,128,
3,61,226,239,240,239,237,239,230,111,128,49,18,227,233,242,
227,236,101,128,36,231,100,2,209,12,209,22,233,229,242,229,
243,233,115,128,30,141,239,244,225,227,227,229,238,116,128,30,
139,229,232,225,242,237,229,238,233,225,110,128,5,109,105,128,
3,190,237,239,238,239,243,240,225,227,101,128,255,88,240,225,
242,229,110,128,36,179,243,245,240,229,242,233,239,114,128,2,
227,121,143,0,121,209,115,210,74,210,97,210,137,212,103,212,
111,212,128,212,192,212,204,213,201,213,241,213,253,214,8,214,
29,215,2,97,11,209,139,209,151,209,161,209,168,209,175,209,
185,209,210,209,221,210,3,210,16,210,62,225,228,239,243,241,
245,225,242,101,128,51,78,226,229,238,231,225,236,105,128,9,
175,227,245,244,101,128,0,253,228,229,246,97,128,9,47,229,
235,239,242,229,225,110,128,49,82,231,117,2,209,192,209,201,
234,225,242,225,244,105,128,10,175,242,237,245,235,232,105,128,
10,47,232,233,242,225,231,225,238,97,128,48,132,107,2,209,
227,209,251,225,244,225,235,225,238,97,129,48,228,209,239,232,
225,236,230,247,233,228,244,104,128,255,148,239,242,229,225,110,
128,49,81,237,225,235,235,225,238,244,232,225,105,128,14,78,
243,237,225,236,108,2,210,26,210,37,232,233,242,225,231,225,
238,97,128,48,131,235,225,244,225,235,225,238,97,129,48,227,
210,50,232,225,236,230,247,233,228,244,104,128,255,108,244,227,
249,242,233,236,236,233,99,128,4,99,227,233,242,99,2,210,
83,210,88,236,101,128,36,232,245,237,230,236,229,120,128,1,
119,100,2,210,103,210,113,233,229,242,229,243,233,115,128,0,
255,239,116,2,210,120,210,129,225,227,227,229,238,116,128,30,
143,226,229,236,239,119,128,30,245,101,7,210,153,211,161,211,
170,211,188,211,220,212,40,212,91,104,8,210,171,210,180,210,
214,210,228,211,45,211,61,211,120,211,138,225,242,225,226,233,
99,128,6,74,226,225,242,242,229,101,2,210,191,210,200,225,
242,225,226,233,99,128,6,210,230,233,238,225,236,225,242,225,
226,233,99,128,251,175,230,233,238,225,236,225,242,225,226,233,
99,128,254,242,232,225,237,250,225,225,226,239,246,101,4,210,
247,211,0,211,14,211,30,225,242,225,226,233,99,128,6,38,
230,233,238,225,236,225,242,225,226,233,99,128,254,138,233,238,
233,244,233,225,236,225,242,225,226,233,99,128,254,139,237,229,
228,233,225,236,225,242,225,226,233,99,128,254,140,233,238,233,
244,233,225,236,225,242,225,226,233,99,128,254,243,237,101,2,
211,68,211,81,228,233,225,236,225,242,225,226,233,99,128,254,
244,229,237,105,2,211,89,211,104,238,233,244,233,225,236,225,
242,225,226,233,99,128,252,221,243,239,236,225,244,229,228,225,
242,225,226,233,99,128,252,88,238,239,239,238,230,233,238,225,
236,225,242,225,226,233,99,128,252,148,244,232,242,229,229,228,
239,244,243,226,229,236,239,247,225,242,225,226,233,99,128,6,
209,235,239,242,229,225,110,128,49,86,110,129,0,165,211,176,
237,239,238,239,243,240,225,227,101,128,255,229,111,2,211,194,
211,203,235,239,242,229,225,110,128,49,85,242,233,238,232,233,
229,245,232,235,239,242,229,225,110,128,49,134,114,3,211,228,
212,8,212,20,225,232,226,229,238,249,239,237,111,2,211,242,
211,251,232,229,226,242,229,119,128,5,170,236,229,230,244,232,
229,226,242,229,119,128,5,170,233,227,249,242,233,236,236,233,
99,128,4,75,245,228,233,229,242,229,243,233,243,227,249,242,
233,236,236,233,99,128,4,249,243,233,229,245,238,103,3,212,
53,212,62,212,78,235,239,242,229,225,110,128,49,129,240,225,
238,243,233,239,243,235,239,242,229,225,110,128,49,131,243,233,
239,243,235,239,242,229,225,110,128,49,130,244,233,246,232,229,
226,242,229,119,128,5,154,231,242,225,246,101,128,30,243,232,
239,239,107,129,1,180,212,120,225,226,239,246,101,128,30,247,
105,5,212,140,212,151,212,162,212,171,212,179,225,242,237,229,
238,233,225,110,128,5,117,227,249,242,233,236,236,233,99,128,
4,87,235,239,242,229,225,110,128,49,98,238,249,225,238,103,
128,38,47,247,238,225,242,237,229,238,233,225,110,128,5,130,
237,239,238,239,243,240,225,227,101,128,255,89,111,7,212,220,
213,34,213,45,213,55,213,93,213,139,213,148,100,131,5,217,
212,230,212,250,213,3,228,225,231,229,243,104,129,251,57,212,
241,232,229,226,242,229,119,128,251,57,232,229,226,242,229,119,
128,5,217,249,239,100,2,213,11,213,20,232,229,226,242,229,
119,128,5,242,240,225,244,225,232,232,229,226,242,229,119,128,
251,31,232,233,242,225,231,225,238,97,128,48,136,233,235,239,
242,229,225,110,128,49,137,107,2,213,61,213,85,225,244,225,
235,225,238,97,129,48,232,213,73,232,225,236,230,247,233,228,
244,104,128,255,150,239,242,229,225,110,128,49,91,243,237,225,
236,108,2,213,103,213,114,232,233,242,225,231,225,238,97,128,
48,135,235,225,244,225,235,225,238,97,129,48,231,213,127,232,
225,236,230,247,233,228,244,104,128,255,110,244,231,242,229,229,
107,128,3,243,121,2,213,154,213,191,97,2,213,160,213,170,
229,235,239,242,229,225,110,128,49,136,107,2,213,176,213,184,
239,242,229,225,110,128,49,135,244,232,225,105,128,14,34,233,
238,231,244,232,225,105,128,14,13,112,2,213,207,213,214,225,
242,229,110,128,36,180,239,231,229,231,242,225,237,237,229,238,
105,129,3,122,213,230,231,242,229,229,235,227,237,98,128,3,
69,114,129,1,166,213,247,233,238,103,128,30,153,243,245,240,
229,242,233,239,114,128,2,184,116,2,214,14,214,21,233,236,
228,101,128,30,249,245,242,238,229,100,128,2,142,117,5,214,
41,214,52,214,62,214,100,214,232,232,233,242,225,231,225,238,
97,128,48,134,233,235,239,242,229,225,110,128,49,140,107,2,
214,68,214,92,225,244,225,235,225,238,97,129,48,230,214,80,
232,225,236,230,247,233,228,244,104,128,255,149,239,242,229,225,
110,128,49,96,115,3,214,108,214,146,214,187,226,233,103,2,
214,116,214,127,227,249,242,233,236,236,233,99,128,4,107,233,
239,244,233,230,233,229,228,227,249,242,233,236,236,233,99,128,
4,109,236,233,244,244,236,101,2,214,157,214,168,227,249,242,
233,236,236,233,99,128,4,103,233,239,244,233,230,233,229,228,
227,249,242,233,236,236,233,99,128,4,105,237,225,236,108,2,
214,196,214,207,232,233,242,225,231,225,238,97,128,48,133,235,
225,244,225,235,225,238,97,129,48,229,214,220,232,225,236,230,
247,233,228,244,104,128,255,109,249,101,2,214,239,214,248,235,
239,242,229,225,110,128,49,139,239,235,239,242,229,225,110,128,
49,138,249,97,2,215,9,215,19,226,229,238,231,225,236,105,
128,9,223,228,229,246,97,128,9,95,122,142,0,122,215,58,
216,66,216,77,216,120,216,147,217,182,218,34,218,76,218,88,
218,100,218,128,218,136,218,152,218,161,97,10,215,80,215,91,
215,98,215,105,215,116,215,194,215,224,215,235,216,15,216,27,
225,242,237,229,238,233,225,110,128,5,102,227,245,244,101,128,
1,122,228,229,246,97,128,9,91,231,245,242,237,245,235,232,
105,128,10,91,104,4,215,126,215,135,215,149,215,179,225,242,
225,226,233,99,128,6,56,230,233,238,225,236,225,242,225,226,
233,99,128,254,198,105,2,215,155,215,170,238,233,244,233,225,
236,225,242,225,226,233,99,128,254,199,242,225,231,225,238,97,
128,48,86,237,229,228,233,225,236,225,242,225,226,233,99,128,
254,200,233,110,2,215,201,215,210,225,242,225,226,233,99,128,
6,50,230,233,238,225,236,225,242,225,226,233,99,128,254,176,
235,225,244,225,235,225,238,97,128,48,182,241,229,102,2,215,
243,216,1,231,225,228,239,236,232,229,226,242,229,119,128,5,
149,241,225,244,225,238,232,229,226,242,229,119,128,5,148,242,
241,225,232,229,226,242,229,119,128,5,152,249,233,110,130,5,
214,216,37,216,57,228,225,231,229,243,104,129,251,54,216,48,
232,229,226,242,229,119,128,251,54,232,229,226,242,229,119,128,
5,214,226,239,240,239,237,239,230,111,128,49,23,99,3,216,
85,216,92,216,114,225,242,239,110,128,1,126,233,242,99,2,
216,100,216,105,236,101,128,36,233,245,237,230,236,229,120,128,
30,145,245,242,108,128,2,145,228,239,116,130,1,124,216,130,
216,139,225,227,227,229,238,116,128,1,124,226,229,236,239,119,
128,30,147,101,6,216,161,216,172,216,215,216,226,216,237,217,
177,227,249,242,233,236,236,233,99,128,4,55,100,2,216,178,
216,197,229,243,227,229,238,228,229,242,227,249,242,233,236,236,
233,99,128,4,153,233,229,242,229,243,233,243,227,249,242,233,
236,236,233,99,128,4,223,232,233,242,225,231,225,238,97,128,
48,92,235,225,244,225,235,225,238,97,128,48,188,242,111,140,
0,48,217,10,217,19,217,29,217,36,217,61,217,74,217,85,
217,97,217,108,217,118,217,129,217,136,225,242,225,226,233,99,
128,6,96,226,229,238,231,225,236,105,128,9,230,228,229,246,
97,128,9,102,231,117,2,217,43,217,52,234,225,242,225,244,
105,128,10,230,242,237,245,235,232,105,128,10,102,232,225,227,
235,225,242,225,226,233,99,128,6,96,233,238,230,229,242,233,
239,114,128,32,128,237,239,238,239,243,240,225,227,101,128,255,
16,239,236,228,243,244,249,236,101,128,247,48,240,229,242,243,
233,225,110,128,6,240,243,245,240,229,242,233,239,114,128,32,
112,244,232,225,105,128,14,80,247,233,228,244,104,3,217,148,
217,157,217,169,234,239,233,238,229,114,128,254,255,238,239,238,
234,239,233,238,229,114,128,32,12,243,240,225,227,101,128,32,
11,244,97,128,3,182,104,2,217,188,217,199,226,239,240,239,
237,239,230,111,128,49,19,101,4,217,209,217,220,217,236,217,
247,225,242,237,229,238,233,225,110,128,5,106,226,242,229,246,
229,227,249,242,233,236,236,233,99,128,4,194,227,249,242,233,
236,236,233,99,128,4,54,100,2,217,253,218,16,229,243,227,
229,238,228,229,242,227,249,242,233,236,236,233,99,128,4,151,
233,229,242,229,243,233,243,227,249,242,233,236,236,233,99,128,
4,221,105,3,218,42,218,53,218,64,232,233,242,225,231,225,
238,97,128,48,88,235,225,244,225,235,225,238,97,128,48,184,
238,239,242,232,229,226,242,229,119,128,5,174,236,233,238,229,
226,229,236,239,119,128,30,149,237,239,238,239,243,240,225,227,
101,128,255,90,111,2,218,106,218,117,232,233,242,225,231,225,
238,97,128,48,94,235,225,244,225,235,225,238,97,128,48,190,
240,225,242,229,110,128,36,181,242,229,244,242,239,230,236,229,
248,232,239,239,107,128,2,144,243,244,242,239,235,101,128,1,
182,117,2,218,167,218,178,232,233,242,225,231,225,238,97,128,
48,90,235,225,244,225,235,225,238,97,128,48,186];

function ft_get_adobe_glyph_index(_name,limit)
{
    var name = 0;
    var c = 0;
    var count, min, max;
    var p = 0;

    if (_name == null || _name == "" || 0 >= limit)
        return 0;

    c = _name.charCodeAt(name);
    name++;
    count = ft_adobe_glyph_list[1];
    p += 2;

    min = 0;
    max = count;

    var go_to_found = 0;
    var go_to_next = 0;
    while (min < max)
    {
        var mid = (min + max) >>> 1;
        var q = p + mid * 2;
        q = ((ft_adobe_glyph_list[q] << 8) | ft_adobe_glyph_list[q+1]);
        var c2 = ft_adobe_glyph_list[q] & 127;
        if (c2 == c)
        {
            p = q;
            go_to_found = 1;
            break;
        }
        if ( c2 < c )
            min = mid + 1;
        else
            max = mid;
    }
    if (0 == go_to_found)
        return 0;

    for (;;)
    {
        if (name >= limit)
        {
            if ((ft_adobe_glyph_list[p] & 128) == 0 && (ft_adobe_glyph_list[p+1] & 128) != 0)
                return ((ft_adobe_glyph_list[p+2] << 8) | ft_adobe_glyph_list[p+3]);
            return 0;
        }
        c = _name.charCodeAt(name++);
        if (ft_adobe_glyph_list[p] & 128)
        {
            p++;
            if (c != (ft_adobe_glyph_list[p] & 127))
                return 0;
            continue;
        }

        p++;
        count = ft_adobe_glyph_list[p] & 127;
        if (ft_adobe_glyph_list[p] & 128)
            p += 2;

        p++;
        for (; count > 0; count--, p += 2)
        {
            var offset = (ft_adobe_glyph_list[p] << 8) | ft_adobe_glyph_list[p+1];
            var q = offset;
            if (c == (ft_adobe_glyph_list[q] & 127))
            {
                p = q;
                go_to_next = 1;
                break;
            }
        }
        if (0 == go_to_next)
            return 0;
    }
    return 0;
}

function PS_UniMap()
{
    this.unicode = 0;
    this.glyph_index = 0;
}
function PS_UnicodesRec()
{
    this.cmap = null;
    this.num_maps = 0;
    this.maps = null;
}

function ps_unicode_value(glyph_name)
{
    var len = glyph_name.length;
    if (glyph_name.charCodeAt(0) == 117 && glyph_name.charCodeAt(1) == 110 && glyph_name.charCodeAt(2) == 105)
    {
        var count;
        var value = 0;
        var p = 3;

        for ( count = 4; count > 0; count--, p++ )
        {
            var c = 0;
            if (p < len)
                c = glyph_name.charCodeAt(p);
            if (c<0)
                c+=256;
            var d = c - 48;
            if (d < 0)
                d += 256;
            if (d >= 10)
            {
                d = c - 65;
                if (d < 0)
                    d += 256;
                if (d >= 6)
                    d = 16;
                else
                    d += 10;
            }

            if (d >= 16)
                break;

            value = (value << 4) + d;
        }

        if (count == 0)
        {
            if (p >= len)
                return value;
            if (glyph_name.charCodeAt(p) == 46)
                return (value | 0x7FFFFFFF);
        }
    }

    if (glyph_name.charCodeAt(0) == 117)
    {
        var count;
        var value = 0;
        var p     = 1;

        for (count = 6; count > 0; count--, p++)
        {
            var c = 0;
            if (p < len)
                c = glyph_name.charCodeAt(p);
            if (c<0)
                c+=256;
            var d = c - 48;
            if (d < 0)
                d += 256;
            if (d >= 10)
            {
                d = c - 65;
                if (d < 0)
                    d += 256;
                if (d >= 6)
                    d = 16;
                else
                    d += 10;
            }

            if (d >= 16)
                break;

            value = (value << 4) + d;
        }

        if (count <= 2)
        {
            if (p >= len)
                return value;
            if (glyph_name.charCodeAt(p) == 46)
                return (value | 0x7FFFFFFF);
      }
    }

    var p = 0;
    var dot = 0;

    for (; p<len; p++)
    {
        if (glyph_name.charCodeAt(p) == 46 && p > 0)
        {
            dot = p;
            break;
        }
    }

    if (dot == 0)
        return ft_get_adobe_glyph_index(glyph_name, p);
    else
        return ft_get_adobe_glyph_index(glyph_name, dot | 0x7FFFFFFF);
}

function compare_uni_maps(map1, map2)
{
    var unicode1 = map1.unicode & 0x7FFFFFFF;
    var unicode2 = map2.unicode & 0x7FFFFFFF;
    if (unicode1 == unicode2)
    {
        if (map1.unicode > map2.unicode)
            return 1;
        else if (map1.unicode < map2.unicode)
            return -1;
        else
            return 0;
    }
    else
    {
        if (unicode1 > unicode2)
            return 1;
        else if (unicode1 < unicode2)
            return -1;
        else
            return 0;
    }
}

function ft_qsort(mass, count, compare)
{
    var t;
    for (var i=0;i<count;i++)
    {
        for (var j=i+1;j<count;j++)
        {
            if (compare(mass[i],mass[j]) == 1)
            {
                t=mass[i];
                mass[i]=mass[j];
                mass[j]=t;
            }
        }
    }
}

var ft_extra_glyph_unicodes=[0x0394,0x03A9,0x2215,0x00AD,0x02C9,0x03BC,0x2219,0x00A0,0x021A,0x021B];
var ft_extra_glyph_names=["Delta","Omega","fraction","hyphen","macron","mu","periodcentered","space","Tcommaaccent","tcommaaccent"];

function ps_check_extra_glyph_name(gname,glyph,extra_glyphs,states)
{
    for (var n = 0; n < 10; n++)
    {
        if (ft_extra_glyph_names[n] == gname)
        {
            if ( states[n] == 0 )
            {
                states[n]     = 1;
                extra_glyphs[n] = glyph;
            }

            return;
        }
    }
}
function ps_check_extra_glyph_unicode(uni_char,states)
{
    for (var n = 0; n < 10; n++)
    {
        if (uni_char == ft_extra_glyph_unicodes[n])
        {
            states[n] = 2;
            return;
        }
    }
}

function ps_unicodes_init(memory,table,num_glyphs,get_glyph_name,free_glyph_name,glyph_data)
{
    var error = 0;

    var extra_glyph_list_states = [0,0,0,0,0,0,0,0,0,0];
    var extra_glyphs = [0,0,0,0,0,0,0,0,0,0];

    table.num_maps = 0;
    table.maps = new Array(num_glyphs + 10);
    for (var i = 0; i < (num_glyphs + 10); i++)
        table.maps[i] = new PS_UniMap();

    var n;
    var map = 0;
    var maps = table.maps;
    var uni_char;

    for ( n = 0; n < num_glyphs; n++)
    {
        var gname = get_glyph_name(glyph_data, n);
        if (gname != null)
        {
            ps_check_extra_glyph_name(gname, n, extra_glyphs, extra_glyph_list_states);

            if (n == 86)
            {
                var __nnn = 0;
                __nnn += 1;
                __nnn += 1;
                __nnn += 1;
            }

            uni_char = ps_unicode_value(gname);

            if ((uni_char & 0x7FFFFFFF) != 0)
            {
                ps_check_extra_glyph_unicode(uni_char, extra_glyph_list_states);
                maps[map].unicode = uni_char;
                maps[map].glyph_index = n;
                map++;
            }

            if (free_glyph_name)
                free_glyph_name(glyph_data, gname);
        }
    }

    for (n = 0; n < 10; n++)
    {
        if (extra_glyph_list_states[n] == 1)
        {
            maps[map].unicode = ft_extra_glyph_unicodes[n];
            maps[map].glyph_index = extra_glyphs[n];
            map++;
        }
    }

    var count = map;
    if ( count == 0 )
    {
        table.maps = null;
        if (!error)
            error = 163;
    }
    else
    {
        if (count < num_glyphs / 2)
        {
            table.maps[count-1] = new PS_UniMap();
            error = 0;
        }

        var del_count = num_glyphs + 10 - count;
        if (del_count > 10)
            maps.splice(count, del_count);
        maps.sort(compare_uni_maps);
        //ft_qsort(table.maps, count, compare_uni_maps);
    }

    table.num_maps = count;

    return error;
}

function ps_unicodes_char_index(table, unicode)
{
    var mid, result = -1;

    var maps = table.maps;
    var min = 0;
    var max = table.num_maps - 1;

    while (min <= max)
    {
        mid = min + ((max - min) >>> 1);

        if (maps[mid].unicode == unicode)
        {
            result = mid;
            break;
        }

        var base_glyph = maps[mid].unicode & 0x7FFFFFFF;
        if (base_glyph == unicode)
            result = mid;

        if (min == max)
            break;

        if (base_glyph < unicode)
            min = mid + 1;
        else
            max = mid - 1;
    }

    if (result != -1)
        return maps[result].glyph_index;
    return 0;
}

function ps_unicodes_char_next(table, unicode)
{
    var result = 0;
    var char_code = unicode + 1;

    var min = 0;
    var max = table.num_maps;
    var mid;
    var map;
    var base_glyph;

    while ( min < max )
    {
        mid = min + ((max - min) >>> 1);
        map = table.maps[mid];

        if (map.unicode == char_code)
        {
            result = map.glyph_index;
            return {unicode:char_code, result:result};
        }

        base_glyph = (map.unicode & 0x7FFFFFFF);

        if (base_glyph == char_code)
            result = map.glyph_index;

        if (base_glyph < char_code)
            min = mid + 1;
        else
            max = mid;
    }

    if (result != 0)
        return {unicode:char_code, result:result};

    char_code = 0;

    if (min < table.num_maps)
    {
        map       = table.maps[min];
        result    = map.glyph_index;
        char_code = (map.unicode & 0x7FFFFFFF);
    }

    return {unicode:char_code, result:result};
}

function ps_get_macintosh_name(name_index)
{
    if (name_index >= 258)
        name_index = 0;

    return ft_standard_glyph_names[ft_mac_names[name_index]];
}

function ps_get_standard_strings(sid)
{
    if (sid >= 391)
        return 0;

    return ft_standard_glyph_names[ft_sid_names[sid]];
}

function _pscmaps_interface()
{
    this.unicode_value = ps_unicode_value;
    this.unicodes_init = ps_unicodes_init;
    this.unicodes_char_index = ps_unicodes_char_index;
    this.unicodes_char_next = ps_unicodes_char_next;

    this.macintosh_name = ps_get_macintosh_name;
    this.adobe_std_strings = ps_get_standard_strings;
    this.adobe_std_encoding = t1_standard_encoding;
    this.adobe_expert_encoding = t1_expert_encoding;
}

var pscmaps_interface = new _pscmaps_interface();
function create_psnames_module(library)
{
    var psnames_mod = new FT_Module();
    psnames_mod.clazz = new FT_Module_Class();

    var clazz = psnames_mod.clazz;
    clazz.flags = 0;
    clazz.name = "psnames";
    clazz.version = 0x10000;
    clazz.requires = 0x20000;

    clazz.module_interface = pscmaps_interface;
    clazz.init = null;
    clazz.done = null;

    clazz.get_interface = function(module, name)
    {
        if (name == "postscript-cmaps")
            return pscmaps_interface;
        return null;
    }

    psnames_mod.library = library;
    psnames_mod.memory = library.Memory;
    psnames_mod.generic = null;

    return psnames_mod;
}
/******************************************************************************/
// t1tables
/******************************************************************************/
function _isdigit(x)
{
    if ((x >= 48) && (x <= 57))
        return 1;
    return 0;
}
function _isxdigit(x)
{
    if (((x >= 48) && (x <= 57)) ||
        ((x >= 97) && (x <= 102)) ||
        ((x >= 65) && (x <= 70)))
        return 1;
    return 0;
}

function PS_FontInfoRec()
{
    this.version        = "";
    this.notice         = "";
    this.full_name      = "";
    this.family_name    = "";
    this.weight         = "";
    this.italic_angle   = 0;
    this.is_fixed_pitch = 0;
    this.underline_position     = 0;
    this.underline_thickness    = 0;

    this.CreateDublicate = function()
    {
        var _ret = new PS_FontInfoRec();

        _ret.version = this.version;
        _ret.notice = this.notice;
        _ret.full_name = this.full_name;
        _ret.family_name = this.family_name;
        _ret.weight = this.weight;
        _ret.italic_angle = this.italic_angle;
        _ret.is_fixed_pitch = this.is_fixed_pitch;
        _ret.underline_position = this.underline_position;
        _ret.underline_thickness = this.underline_thickness;

        return _ret;
    }
}
function PS_PrivateRec()
{
    this.unique_id = 0;
    this.lenIV = 0;

    this.num_blue_values = 0;
    this.num_other_blues = 0;
    this.num_family_blues = 0;
    this.num_family_other_blues = 0;

    this.blue_values = [0,0,0,0,0,0,0,0,0,0,0,0,0,0];
    this.other_blues = [0,0,0,0,0,0,0,0,0,0];

    this.family_blues = [0,0,0,0,0,0,0,0,0,0,0,0,0,0];
    this.family_other_blues = [0,0,0,0,0,0,0,0,0,0];

    this.blue_scale = 0;
    this.blue_shift = 0;
    this.blue_fuzz = 0;

    this.standard_width = [0];
    this.standard_height = [0];

    this.num_snap_widths = 0;
    this.num_snap_heights = 0;
    this.force_bold = 0;
    this.round_stem_up = 0;

    this.snap_widths = [0,0,0,0,0,0,0,0,0,0,0,0,0];
    this.snap_heights = [0,0,0,0,0,0,0,0,0,0,0,0,0];

    this.expansion_factor = 0;

    this.language_group = 0;
    this.password = 0;

    this.min_feature = [0,0];

    this.clear = function()
    {
        this.unique_id = 0;
        this.lenIV = 0;

        this.num_blue_values = 0;
        this.num_other_blues = 0;
        this.num_family_blues = 0;
        this.num_family_other_blues = 0;

        for (var i = 0; i < 14; i++)
            this.blue_values[i] = 0;

        for (var i = 0; i < 10; i++)
            this.other_blues[i] = 0;

        for (var i = 0; i < 14; i++)
            this.family_blues[i] = 0;

        for (var i = 0; i < 10; i++)
            this.family_other_blues[i] = 0;

        this.blue_scale = 0;
        this.blue_shift = 0;
        this.blue_fuzz = 0;

        this.standard_width[0] = 0;
        this.standard_height[0] = 0;

        this.num_snap_widths = 0;
        this.num_snap_heights = 0;
        this.force_bold = 0;
        this.round_stem_up = 0;

        for (var i = 0; i < 13; i++)
            this.snap_widths[i] = 0;
        for (var i = 0; i < 13; i++)
            this.snap_heights[i] = 0;

        this.expansion_factor = 0;

        this.language_group = 0;
        this.password = 0;

        this.min_feature[0] = 0;
        this.min_feature[1] = 0;
    }
}

function PS_DesignMapRec()
{
    this.num_points = 0;
    this.design_points = null;
    this.blend_points = null;
}

function PS_BlendRec()
{
    this.num_designs = 0;
    this.num_axis = 0;

    this.axis_names = CreateNullArray(4);
    this.design_pos = CreateNullArray(16);
    this.design_map = new Array(4);
    for (var i = 0; i < 4; i++)
        this.design_map[i] = new PS_DesignMapRec();

    this.weight_vector = null;
    this.default_weight_vector = 0;

    this.font_infos = CreateNullArray(16 + 1);
    this.privates = CreateNullArray(16 + 1);

    this.blend_bitflags = 0;

    this.bboxes = CreateNullArray(16 + 1);

    this.default_design_vector = CreateUIntArray(16);
    this.num_default_design_vector = 0;
}

function CID_FaceDictRec()
{
    this.private_dict = new PS_PrivateRec();

    this.len_buildchar = 0;
    this.forcebold_threshold = 0;
    this.stroke_width = 0;
    this.expansion_factor = 0;

    this.paint_type = 0;
    this.font_type = 0;
    this.font_matrix = new FT_Matrix();
    this.font_offset = new FT_Vector();

    this.num_subrs = 0;
    this.subrmap_offset = 0;
    this.sd_bytes = 0;
}

function CID_FaceInfoRec()
{
    this.cid_font_name = "";
    this.cid_version = 0;
    this.cid_font_type = 0;

    this.registry = "";
    this.ordering = "";
    this.supplement = 0;

    this.font_info = new PS_FontInfoRec();
    this.font_bbox = new FT_BBox();
    this.uid_base = 0;

    this.num_xuid = 0;
    this.xuid = CreateUIntArray(16);

    this.cidmap_offset = 0;
    this.fd_bytes = 0;
    this.gd_bytes = 0;
    this.cid_count = 0;

    this.num_dicts = 0;
    this.font_dicts = null;

    this.data_offset = 0;
}

function FT_Has_PS_Glyph_Names(face)
{
    var result = 0;
    if (face != null)
    {
        var service = FT_FACE_FIND_SERVICE(face, FT_SERVICE_ID_POSTSCRIPT_INFO);

        if (service && service.ps_has_glyph_names)
            result = service.ps_has_glyph_names(face);
    }
    return result;
}
function FT_Get_PS_Font_Info(face, afont_info)
{
    var error = 6;
    if (face != null)
    {
        var service = FT_FACE_FIND_SERVICE(face, FT_SERVICE_ID_POSTSCRIPT_INFO);

        if (service && service.ps_get_font_info)
            error = service.ps_get_font_info(face, afont_info);
    }
    return error;
}
function FT_Get_PS_Font_Private(face, afont_private)
{
    var error = 6;
    if (face != null)
    {
        var service = FT_FACE_FIND_SERVICE(face, FT_SERVICE_ID_POSTSCRIPT_INFO);

        if (service && service.ps_get_font_private)
            error = service.ps_get_font_private(face, afont_private);
    }
    return error;
}
function FT_Get_PS_Font_Value(face, key, idx, value, value_len)
{
    var result  = 0;
    if (face != null)
    {
        var service = FT_FACE_FIND_SERVICE(face, FT_SERVICE_ID_POSTSCRIPT_INFO);

        if (service && service.ps_get_font_value)
            result = service.ps_get_font_value(face, key, idx, value, value_len);
    }
    return result;
}
/******************************************************************************/
// t1types
/******************************************************************************/
function T1_EncodingRec()
{
    this.num_chars  = 0;
    this.code_first = 0;
    this.code_last  = 0;

    this.char_index = null;
    this.char_name  = null;
}
function PS_FontExtraRec()
{
    this.fs_type = 0;

    this.CreateDublicate = function()
    {
        var _ret = new PS_FontExtraRec();
        _ret.fs_type = this.fs_type;
        return _ret;
    }
}
function T1_FontRec()
{
    this.font_info      = new PS_FontInfoRec();
    this.font_extra     = new PS_FontExtraRec();
    this.private_dict   = new PS_PrivateRec();
    this.font_name      = "";

    this.encoding_type  = 0;
    this.encoding       = new T1_EncodingRec();

    this.subrs_block        = null;
    this.charstrings_block  = null;
    this.glyph_names_block  = null;

    this.num_subrs = 0;
    this.subrs = null;
    this.subrs_len = null;

    this.num_glyphs = 0;
    this.glyph_names = null;
    this.charstrings = null;
    this.charstrings_len = null;

    this.paint_type = 0;
    this.font_type = 0;
    this.font_matrix = new FT_Matrix();
    this.font_offset = new FT_Vector();
    this.font_bbox = new FT_BBox();
    this.font_id = 0;

    this.stroke_width = 0;
}
function CID_SubrsRec()
{
    this.num_subrs = 0;
    this.code = null;
}

function AFM_TrackKernRec()
{
    this.degree     = 0;
    this.min_ptsize = 0;
    this.min_kern   = 0;
    this.max_ptsize = 0;
    this.max_kern   = 0;
}
function AFM_KernPairRec()
{
    this.index1 = 0;
    this.index2 = 0;
    this.x = 0;
    this.y = 0;
}
function AFM_FontInfoRec()
{
    this.IsCIDFont = 0;
    this.FontBBox = new FT_BBox();
    this.Ascender = 0;
    this.Descender = 0;
    this.TrackKerns = null;
    this.NumTrackKern = 0;
    this.KernPairs = null;
    this.NumKernPair = 0;
}



function T1_Face()
{
    this.num_faces = 0;
    this.face_index = 0;

    this.face_flags = 0;
    this.style_flags = 0;

    this.num_glyphs = 0;

    this.family_name = "";
    this.style_name = "";

    this.num_fixed_sizes = 0;
    this.available_sizes = [];

    this.num_charmaps = 0;
    this.charmaps = [];

    this.generic = new FT_Generic();

    /*# The following member variables (down to `underline_thickness') */
    /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size    */
    /*# for bitmap fonts.                                              */
    this.bbox = new FT_BBox();

    this.units_per_EM = 0;
    this.ascender = 0;
    this.descender = 0;
    this.height = 0;

    this.max_advance_width = 0;
    this.max_advance_height = 0;

    this.underline_position = 0;
    this.underline_thickness = 0;

    this.glyph = null;
    this.size = null;
    this.charmap = null;

    /*@private begin */
    this.driver = null;
    this.memory = null;
    this.stream = null;

    this.sizes_list = [];

    this.autohint = [];
    this.extensions = null;

    this.internal = null;
    /*@private end */

    this.type1 = new T1_FontRec();
    this.psnames = null;
    this.psaux = null;
    this.afm_data = null;

    this.charmaprecs = new Array(2);
    this.charmaprecs[0] = new FT_CharMapRec();
    this.charmaprecs[1] = new FT_CharMapRec();

    this.charmaps = new Array(2);
    this.charmaps[0] = null;
    this.charmaps[1] = null;

    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    this.unicode_map = null;
    //#endif

    /* support for Multiple Masters fonts */
    this.blend = null;

    /* undocumented, optional: indices of subroutines that express      */
    /* the NormalizeDesignVector and the ConvertDesignVector procedure, */
    /* respectively, as Type 2 charstrings; -1 if keywords not present  */
    this.ndv_idx = 0;
    this.cdv_idx = 0;

    /* undocumented, optional: has the same meaning as len_buildchar */
    /* for Type 2 fonts; manipulated by othersubrs 19, 24, and 25    */
    this.len_buildchar = 0;
    this.buildchar = null;

    /* since version 2.1 - interface to PostScript hinter */
    this.pshinter = null;
}

function CID_Face()
{
    this.num_faces = 0;
    this.face_index = 0;

    this.face_flags = 0;
    this.style_flags = 0;

    this.num_glyphs = 0;

    this.family_name = "";
    this.style_name = "";

    this.num_fixed_sizes = 0;
    this.available_sizes = [];

    this.num_charmaps = 0;
    this.charmaps = [];

    this.generic = new FT_Generic();

    /*# The following member variables (down to `underline_thickness') */
    /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size    */
    /*# for bitmap fonts.                                              */
    this.bbox = new FT_BBox();

    this.units_per_EM = 0;
    this.ascender = 0;
    this.descender = 0;
    this.height = 0;

    this.max_advance_width = 0;
    this.max_advance_height = 0;

    this.underline_position = 0;
    this.underline_thickness = 0;

    this.glyph = null;
    this.size = null;
    this.charmap = null;

    /*@private begin */
    this.driver = null;
    this.memory = null;
    this.stream = null;

    this.sizes_list = [];

    this.autohint = [];
    this.extensions = null;

    this.internal = null;
    /*@private end */

    this.psnames = null;
    this.psaux = null;
    this.cid = new CID_FaceInfoRec();
    this.font_extra = new PS_FontExtraRec();

    this.subrs = null;

    /* since version 2.1 - interface to PostScript hinter */
    this.pshinter = null;

    this.binary_data = new CPointer(); /* used if hex data has been converted */
    this.cid_stream = null;
}

/******************************************************************************/
function IS_PS_NEWLINE(ch)
{
    if (ch == 13 || ch == 10)
        return true;
    return false;
}
function IS_PS_SPACE(ch)
{
    switch (ch)
    {
        case 32:
        case 13:
        case 10:
        case 9:
        case 12:
        case 0:
            return true;
    }
    return false;
}
function IS_PS_SPECIAL(ch)
{
    switch (ch)
    {
        case 47:
        case 40:
        case 91:
        case 123:
        case 41:
        case 93:
        case 125:
        case 60:
        case 62:
        case 37:
            return true;
    }
    return false;
}
function IS_PS_DELIM(ch)
{
    switch (ch)
    {
        case 32:
        case 13:
        case 10:
        case 9:
        case 12:
        case 0:
        case 47:
        case 40:
        case 91:
        case 123:
        case 41:
        case 93:
        case 125:
        case 60:
        case 62:
        case 37:
            return true;
    }
    return false;
}
function IS_PS_DIGIT(ch)
{
    return (ch >= 48 && ch <= 57) ? true : false;
}
function IS_PS_XDIGIT(ch)
{
    return (IS_PS_DIGIT(ch) || (ch >= 65 && ch <= 70)
        || (ch >= 97 && ch <= 102)) ? true : false;
}
function IS_PS_BASE85(ch)
{
    return (ch >= 33 && ch <= 117) ? true : false;
}

function IS_PS_TOKEN(cur, limit, token, len)
{
    if (cur.data[cur.pos] == token.charCodeAt(0) && (((cur.pos + len) == limit) || ((cur.pos + len) < limit && IS_PS_DELIM(cur.data[cur.pos + len - 1]))) && _strncmp_data(cur, token, len - 1) == 0)
        return 1;
    return 0;
}

/******************************************************************************/
// psconv
/******************************************************************************/
var ft_char_table =
[
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
    -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
    25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
    -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
    25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1
];

function PS_Conv_Strtol(cursor, limit, base)
{
    var _data = cursor.data;
    var pos = cursor.pos;

    var num = 0;
    var sign = 0;

    if (pos == limit || base < 2 || base > 36)
        return 0;

    if (_data[pos] == 45 || _data[pos] == 43)
    {
        sign = (_data[pos] == 45) ? 1 : 0;

        pos++;
        if (pos == limit)
            return 0;
    }

    for (; pos < limit; pos++)
    {
        if (IS_PS_SPACE(_data[pos]) || _data[pos] >= 0x80)
            break;

        var c = ft_char_table[_data[pos] & 0x7f];

        if (c < 0 || c >= base)
            break;

        num = num * base + c;
    }

    if (sign == 1)
        num = -num;

    cursor.pos = pos;
    return num;
}
function PS_Conv_ToInt(cursor, limit)
{
    var num = PS_Conv_Strtol(cursor, limit, 10);
    var data = cursor.data;
    var pos = cursor.pos;

    if (pos < limit && data[pos] == 35)
    {
        cursor.pos = pos + 1;
        return PS_Conv_Strtol(cursor, limit, num);
    }
    return num;
}
function PS_Conv_ToFixed(cursor, limit, power_ten)
{
    var p = dublicate_pointer(cursor);
    var integral;
    var decimal = 0, divider = 1;
    var sign = 0;

    if (p.pos == limit)
        return 0;

    var _data = p.data;
    if (_data[p.pos] == 45 || _data[p.pos] == 43)
    {
        sign = (_data[p.pos] == 45) ? 1 : 0;

        p.pos++;
        if (p.pos == limit)
            return 0;
    }

    if (_data[p.pos] != 46)
        integral = PS_Conv_ToInt(p, limit) << 16;
    else
        integral = 0;

    /* read the decimal part */
    if (p.pos < limit && _data[p.pos] == 46)
    {
        p.pos++;
        for (; p.pos < limit; p.pos++)
        {
            if (IS_PS_SPACE(_data[p.pos]) || _data[p.pos] >= 0x80)
                break;

            var c = ft_char_table[_data[p.pos] & 0x7f];

            if (c < 0 || c >= 10)
                break;

            if (!integral && power_ten > 0)
            {
                power_ten--;
                decimal = decimal * 10 + c;
            }
            else
            {
                if (divider < 10000000)
                {
                    decimal = decimal * 10 + c;
                    divider *= 10;
                }
            }
        }
    }

    /* read exponent, if any */
    if (p.pos + 1 < limit && (_data[p.pos] == 101 || _data[p.pos] == 69))
    {
        p.pos++;
        power_ten += PS_Conv_ToInt(p, limit);
    }

    while (power_ten > 0)
    {
        integral *= 10;
        decimal  *= 10;
        power_ten--;
    }

    while (power_ten < 0)
    {
        integral /= 10;
        divider  *= 10;
        power_ten++;
    }

    if (decimal)
        integral += FT_DivFix(decimal, divider);

    if (sign)
        integral = -integral;

    cursor.pos = p.pos;

    return integral;
}

function PS_Conv_ASCIIHexDecode(cursor, limit, buffer, n)
{
    var r = 0;
    var w = buffer.pos;
    var pad = 0x01;
    
    n *= 2;

    var p  = dublicate_pointer(cursor);
    if (n > (limit - p.pos))
        n = (limit - p.pos);

    /* we try to process two nibbles at a time to be as fast as possible */
    var _data = p.data;
    for ( ; r < n; r++)
    {
        var c = _data[p.pos + r];

        if (IS_PS_SPACE(c))
            continue;

        if (c >= 0x80)
            break;

        c = ft_char_table[c & 0x7F];
        var _c = (c >= 0) ? c : c + 256;
        if (c >= 16)
            break;

        pad = (pad << 4) | c;
        if (pad & 0x100)
        {
            buffer.data[w++] = pad & 0xFF;
            pad = 0x01;
        }
    }

    if (pad != 0x01)
        buffer[w++] = ((pad << 4) & 0xFF);

    cursor.pos = p.pos + r;
    return w;
}

function PS_Conv_EexecDecode(cursor, limit, buffer, n, seed)
{
    var r;
    var s = seed;

    var _sd = cursor.data;
    var _sp = cursor.pos;

    if (n > (limit - _sp))
        n = (limit - _sp);

    var _dd = buffer.data;
    var _dp = buffer.pos;

    var v = 0;
    var b = 0;

    for (r = 0; r < n; r++, _sp++, _dp++)
    {
        v = _sd[_sp];
        b = (v ^ (s >> 8));

        s = ((v + s)*52845 + 22719) & 0xFFFF;
        _dd[_dp] = b & 0xFF;
    }

    cursor.pos = _sp;
    return { r : r, seed : s };
}
/******************************************************************************/
// afmparse
/******************************************************************************/
function AFM_ValueRec()
{
    this.type = 0;
    this.u;
}
function AFM_StreamRec()
{
    this.base = null;
    this.cursor = 0;
    this.limit = 0;

    this.status = 0;
}

function AFM_ParserRec()
{
	this.memory = null;
	this.stream = null;

	this.FontInfo = null;
	this.get_index = null;
	this.user_data = null;
}

function AFM_IS_NEWLINE(ch)
{
    if (ch == 13 || ch == 10)
        return true;
    return false;
}
function AFM_IS_EOF(ch)
{
    if (ch == -1  || ch == 0x1A)
        return true;
    return false;
}
function AFM_IS_SPACE(ch)
{
    if (ch == 32  || ch == 9)
        return true;
    return false;
}
function AFM_IS_SEP(ch)
{
    return (ch == 59) ? true : false;
}
function AFM_GETC(stream)
{
    return (stream.cursor < stream.limit) ? stream.base[stream.cursor++] : -1;
}

function afm_stream_skip_spaces(stream)
{
    var ch = 0;

    if (stream.status >= 1)
        return 59;

    while (true)
    {
        ch = AFM_GETC();
        if (!AFM_IS_SPACE(ch))
            break;
    }

    if (AFM_IS_NEWLINE(ch))
        stream.status = 2;
    else if (AFM_IS_SEP(ch))
        stream.status = 1;
    else if (AFM_IS_EOF(ch))
        stream.status = 3;

    return ch;
}
function afm_stream_read_one(stream)
{
    afm_stream_skip_spaces( stream );
    if (stream.status >= 1)
        return null;

    var str = new CPointer();
    str.data = stream.base;
    str.pos = stream.cursor - 1;
    var ch;

    while ( 1 )
    {
        ch = AFM_GETC();
        if (AFM_IS_SPACE(ch))
            break;
        else if (AFM_IS_NEWLINE(ch))
        {
            stream.status = 2;
            break;
        }
        else if (AFM_IS_SEP(ch))
        {
            stream.status = 1;
            break;
        }
        else if (AFM_IS_EOF(ch))
        {
            stream.status = 3;
            break;
        }
    }

    return str;
}
function afm_stream_read_string(stream)
{
    afm_stream_skip_spaces(stream);
    if (stream.status >= 2)
        return null;

    var str = new CPointer();
    str.data = stream.base;
    str.pos = stream.cursor - 1;
    var ch;

    /* scan to eol */
    while ( 1 )
    {
        ch = AFM_GETC();
        if (AFM_IS_NEWLINE(ch))
        {
            stream.status = 2;
            break;
        }
        else if (AFM_IS_EOF(ch))
        {
            stream.status = 3;
            break;
        }
    }

    return str;
}
var afm_key_table =
[
    "Ascender",
    "AxisLabel",
    "AxisType",
    "B",
    "BlendAxisTypes",
    "BlendDesignMap",
    "BlendDesignPositions",
    "C",
    "CC",
    "CH",
    "CapHeight",
    "CharWidth",
    "CharacterSet",
    "Characters",
    "Descender",
    "EncodingScheme",
    "EndAxis",
    "EndCharMetrics",
    "EndComposites",
    "EndDirection",
    "EndFontMetrics",
    "EndKernData",
    "EndKernPairs",
    "EndTrackKern",
    "EscChar",
    "FamilyName",
    "FontBBox",
    "FontName",
    "FullName",
    "IsBaseFont",
    "IsCIDFont",
    "IsFixedPitch",
    "IsFixedV",
    "ItalicAngle",
    "KP",
    "KPH",
    "KPX",
    "KPY",
    "L",
    "MappingScheme",
    "MetricsSets",
    "N",
    "Notice",
    "PCC",
    "StartAxis",
    "StartCharMetrics",
    "StartComposites",
    "StartDirection",
    "StartFontMetrics",
    "StartKernData",
    "StartKernPairs",
    "StartKernPairs0",
    "StartKernPairs1",
    "StartTrackKern",
    "StdHW",
    "StdVW",
    "TrackKern",
    "UnderlinePosition",
    "UnderlineThickness",
    "VV",
    "VVector",
    "Version",
    "W",
    "W0",
    "W0X",
    "W0Y",
    "W1",
    "W1X",
    "W1Y",
    "WX",
    "WY",
    "Weight",
    "WeightVector",
    "XHeight"
];

function afm_parser_read_vals(parser, vals, n)
{
    var stream = parser.stream;
    var str = null;

    if (n > 5)
        return 0;

    var i = 0;
    for (; i < n; i++)
    {
        var val = vals[i];

        if (val.type == 0)
            str = afm_stream_read_string(stream);
        else
            str = afm_stream_read_one(stream);

        if (str == null)
            break;

        var len = stream.cursor - str.pos - 1;

        switch (val.type)
        {
            case 0:
            case 1:
                val.u = "";
                for (var j = 0; j < len; j++)
                    val.u += String.fromCharCode(str.data[str.pos++]);
                break;

            case 2:
                val.u = PS_Conv_ToFixed(str, str.pos + len, 0);
                break;

            case 3:
                val.u = PS_Conv_ToInt(str, str.pos + len);
                break;

            case 4:
                val.u = (len == 4 && (0 == _strncmp(str, "true", 4)));
                break;

            case 5:
                if (parser.get_index != null)
                    val.u = parser.get_index(str, len, parser.user_data);
                else
                    val.u = 0;
                break;
        }
    }

    return i;
}

function afm_parser_next_key(parser, line)
{
    var stream = parser.stream;
    var key = null;

    if (line)
    {
        while ( 1 )
        {
            /* skip current line */
            if (stream.status < 2)
                afm_stream_read_string(stream);

            stream.status = 0;
            key = afm_stream_read_one(stream);

            /* skip empty line */
            if (key == null  && (stream.status < 3) && (stream.status >= 2))
                continue;

            break;
        }
    }
    else
    {
        while ( 1 )
        {
            /* skip current column */
            while (stream.status < 1)
                afm_stream_read_one(stream);

            stream.status = 0;
            key = afm_stream_read_one(stream);

            /* skip empty column */
            if (key == null  && (stream.status < 3) && (stream.status >= 1))
                continue;

            break;
        }
    }

    var ret_len;
    ret_len = (key != null) ? (stream.cursor - key.pos - 1) : 0;

    return { key : key, len: ret_len };
}

function afm_tokenize(key, len)
{
    var n = 0;
    for (; n < 74; n++)
    {
        if (afm_key_table[n].charCodeAt(0) == key.charCodeAt(0))
        {
            for (; n < 74; n++)
            {
                if (afm_key_table[n].charCodeAt(0) != key.charCodeAt(0))
                    return 75;

                if (_strncmp(afm_key_table[n], key, len) == 0)
                    return n;
            }
        }
    }
    return 75;
}

function afm_parser_init(parser, memory, base, limit)
{
    var stream = new AFM_StreamRec();

    stream.base = dublicate_pointer(base);
    stream.cursor = stream.base.pos;
    stream.limit  = limit;

    /* don't skip the first line during the first call */
    stream.status = 2;

    parser.memory    = memory;
    parser.stream    = stream;
    parser.FontInfo  = null;
    parser.get_index = null;

    return 0;
}

function afm_parser_done(parser)
{
    parser.stream = null;
}

function afm_parser_read_int(parser)
{
    var val = new AFM_ValueRec();
    val.type = 3;

    if (afm_parser_read_vals(parser, val, 1) == 1)
    {
        return { pint: val.u, err: 0 };
    }
    return { pint: 0, err: 160 };
}

function afm_parse_track_kern(parser)
{
    var fi = parser.FontInfo;
    var n = -1;

    var ret = afm_parser_read_int(parser);
    if (0 != ret.err)
        return 160;

    fi.NumTrackKern = ret.pint;
    if (fi.NumTrackKern != 0)
    {
        fi.TrackKerns = new Array(fi.NumTrackKern);
    }

    while (true)
    {
        var _key_len = afm_parser_next_key(parser, 1);
        if (_key_len.key == null)
            break;

        var shared_vals = new Array(5);
        shared_vals[0] = new AFM_ValueRec();
        shared_vals[1] = new AFM_ValueRec();
        shared_vals[2] = new AFM_ValueRec();
        shared_vals[3] = new AFM_ValueRec();
        shared_vals[4] = new AFM_ValueRec();

        switch (afm_tokenize(_key_len.key, _key_len.len))
        {
            case 56:
                n++;

                if (n >= fi.NumTrackKern)
                    return 160;

                var tk = fi.TrackKerns[n];

                shared_vals[0].type = 3;
                shared_vals[1].type = 2;
                shared_vals[2].type = 2;
                shared_vals[3].type = 2;
                shared_vals[4].type = 2;
                if (afm_parser_read_vals( parser, shared_vals, 5) != 5)
                    return 160;

                tk.degree     = shared_vals[0].u;
                tk.min_ptsize = shared_vals[1].u;
                tk.min_kern   = shared_vals[2].u;
                tk.max_ptsize = shared_vals[3].u;
                tk.max_kern   = shared_vals[4].u;

                /* is this correct? */
                if (tk.degree < 0 && tk.min_kern > 0)
                    tk.min_kern = -tk.min_kern;
                break;

            case 23:
            case 21:
            case 20:
                fi.NumTrackKern = n + 1;
                return 0;

            case 75:
                break;

            default:
                return 160;
        }
    }

    return 160;
}

function afm_compare_kern_pairs(kp1, kp2)
{
    var index1 = kp1.index1 << 16 | kp1.index2;
    var index2 = kp2.index1 << 16 | kp2.index2;

    if ( index1 > index2 )
        return 1;
    else if ( index1 < index2 )
        return -1;
    else
        return 0;
}

function afm_parse_kern_pairs(parser)
{
    var fi = parser.FontInfo;
    var kp = null;
    var n = -1;

    var _key_len = afm_parser_read_int(parser);
    if (null != _key_len.key)
        return 160;

    fi.NumKernPair = _key_len.len;
    if (fi.NumKernPair != 0)
    {
        fi.KernPairs = new Array(fi.NumKernPair);
        for (var i = 0; i < fi.NumKernPair; i++)
            fi.NumKernPair[i] = new AFM_KernPairRec();
    }

    while (true)
    {
        _key_len = afm_parser_next_key(parser, 1);
        if (null == _key_len.key)
            break;

        var token = afm_tokenize(_key_len.key, _key_len.len);
        switch (token)
        {
            case 34:
            case 36:
            case 37:
                var shared_vals = new Array(4);
                shared_vals[0] = new AFM_ValueRec();
                shared_vals[1] = new AFM_ValueRec();
                shared_vals[2] = new AFM_ValueRec();
                shared_vals[3] = new AFM_ValueRec();
                n++;

                if (n >= fi.NumKernPair)
                    return 160;

                kp = fi.KernPairs[n];

                shared_vals[0].type = 5;
                shared_vals[1].type = 5;
                shared_vals[2].type = 3;
                shared_vals[3].type = 3;
                var r = afm_parser_read_vals(parser, shared_vals, 4);
                if (r < 3)
                    return 160;

                kp.index1 = shared_vals[0].u;
                kp.index2 = shared_vals[1].u;
                if (token == 37)
                {
                    kp.x = 0;
                    kp.y = shared_vals[2].u;
                }
                else
                {
                    kp.x = shared_vals[2].u.i;
                    kp.y = (token == 34 && r == 4) ? shared_vals[3].u : 0;
                }
                break;

            case 22:
            case 21:
            case 20:
                fi.NumKernPair = n + 1;
                ft_qsort(fi.KernPairs, fi.NumKernPair, afm_compare_kern_pairs);
                return 0;

            case 75:
                break;

            default:
                return 160;
        }
    }

    return 160;
}

function afm_parse_kern_data(parser)
{
    while (true)
    {
        var _key_len = afm_parser_next_key(parser, 1);
        if (null != _key_len)
            break;

        switch (afm_tokenize(_key_len.key, _key_len.len))
        {
            case 53:
                var error = afm_parse_track_kern(parser);
                if (error != 0)
                    return error;
                break;

            case 50:
            case 51:
                var error = afm_parse_kern_pairs(parser);
                if (error != 0)
                    return error;
                break;

            case 21:
            case 20:
                return 0;

            case 75:
                break;

            default:
                return 160;
        }
    }
    
    return 160;
}

function afm_parser_skip_section(parser, n, end_section)
{
    while ( n-- > 0 )
    {
        var _key_len = afm_parser_next_key(parser, 1);
        if (_key_len.key != null)
            return 160;
    }

    while (true)
    {
        var _key_len = afm_parser_next_key(parser, 1);
        if (_key_len.key != null)
            break;

        var token = afm_tokenize(_key_len.key, _key_len.len);

        if (token == end_section || token == 20)
            return 0;
    }

    return 160;
}

function afm_parser_parse(parser)
{
    var fi = parser.FontInfo;
    var error = 160;
    var metrics_sets = 0;

    if (fi == null)
        return 6;

    var _key_len = afm_parser_next_key(parser, 1);
    if (null == _key_len.key || _key_len.len != 16 || _strncmp(_key_len.key, "StartFontMetrics", 16) != 0)
        return 2;

    while (true)
    {
        _key_len = afm_parser_next_key(parser, 1);
        if (null == _key_len)
            break;

        var shared_vals = new Array(4);
        shared_vals[0] = new AFM_ValueRec();
        shared_vals[1] = new AFM_ValueRec();
        shared_vals[2] = new AFM_ValueRec();
        shared_vals[3] = new AFM_ValueRec();

        var token = afm_tokenize(_key_len.key, _key_len.len);
        switch (token)
        {
            case 40:
                var ret = afm_parser_read_int(parser);
                if (ret.err != 0)
                {
                    fi.TrackKerns = null;
                    fi.NumTrackKern = 0;

                    fi.KernPairs = null;
                    fi.NumKernPair = 0;

                    fi.IsCIDFont = 0;

                    return error;
                }
                metrics_sets = ret.pint;
                if (metrics_sets != 0 && metrics_sets != 2)
                {
                    fi.TrackKerns = null;
                    fi.NumTrackKern = 0;

                    fi.KernPairs = null;
                    fi.NumKernPair = 0;

                    fi.IsCIDFont = 0;

                    return 7;
                }
                break;

            case 30:
                shared_vals[0].type = 4;
                if (afm_parser_read_vals(parser, shared_vals, 1) != 1)
                {
                    fi.TrackKerns = null;
                    fi.NumTrackKern = 0;

                    fi.KernPairs = null;
                    fi.NumKernPair = 0;

                    fi.IsCIDFont = 0;

                    return error;
                }

                fi.IsCIDFont = shared_vals[0].u;
                break;

            case 26:
                shared_vals[0].type = 2;
                shared_vals[1].type = 2;
                shared_vals[2].type = 2;
                shared_vals[3].type = 2;
                if (afm_parser_read_vals( parser, shared_vals, 4 ) != 4)
                {
                    fi.TrackKerns = null;
                    fi.NumTrackKern = 0;

                    fi.KernPairs = null;
                    fi.NumKernPair = 0;

                    fi.IsCIDFont = 0;

                    return error;
                }

                fi.FontBBox.xMin = shared_vals[0].u;
                fi.FontBBox.yMin = shared_vals[1].u;
                fi.FontBBox.xMax = shared_vals[2].u;
                fi.FontBBox.yMax = shared_vals[3].u;
                break;

            case 0:
                shared_vals[0].type = 2;
                if (afm_parser_read_vals(parser, shared_vals, 1) != 1)
                {
                    // fail
                    return error;
                }

                fi.Ascender = shared_vals[0].u;
                break;

            case 14:
                shared_vals[0].type = 2;
                if (afm_parser_read_vals( parser, shared_vals, 1 ) != 1)
                {
                    fi.TrackKerns = null;
                    fi.NumTrackKern = 0;

                    fi.KernPairs = null;
                    fi.NumKernPair = 0;

                    fi.IsCIDFont = 0;

                    return error;
                }

                fi.Descender = shared_vals[0].u;
                break;

            case 45:
                var ret = afm_parser_read_int(parser);
                if (ret.err != 0)
                {
                    fi.TrackKerns = null;
                    fi.NumTrackKern = 0;

                    fi.KernPairs = null;
                    fi.NumKernPair = 0;

                    fi.IsCIDFont = 0;

                    return error;
                }
                var n = ret.pint;
                error = afm_parser_skip_section(parser, n, 17);
                if (error != 0)
                    return error;
                break;

            case 49:
                error = afm_parse_kern_data(parser);
                if (error != 0)
                {
                    fi.TrackKerns = null;
                    fi.NumTrackKern = 0;

                    fi.KernPairs = null;
                    fi.NumKernPair = 0;

                    fi.IsCIDFont = 0;

                    return error;
                }
            /* fall through since we only support kern data */
            case 20:
                return 0;

            default:
                break;
        }
    }

    fi.TrackKerns = null;
    fi.NumTrackKern = 0;

    fi.KernPairs = null;
    fi.NumKernPair = 0;

    fi.IsCIDFont = 0;

    return error;
}

/******************************************************************************/
// t1cmap
/******************************************************************************/
function T1_CMapStdRec()
{
    this.cmap = new FT_CMapRec();

    this.code_to_sid = null;
    this.sid_to_string = null;

    this.num_glyphs = 0;
    this.glyph_names = null;

    this.type = 1;
}
function T1_CMapCustomRec()
{
    this.cmap = new FT_CMapRec();
    this.first = 0;
    this.count = 0;
    this.indices = null;

    this.type = 1;
}

// standart
function t1_cmap_std_init(cmap, is_expert)
{
    var face = __FT_CMapRec(cmap).charmap.face;
    var psnames = face.psnames;

    cmap.num_glyphs    = face.type1.num_glyphs;
    cmap.glyph_names   = face.type1.glyph_names;
    cmap.sid_to_string = psnames.adobe_std_strings;
    cmap.code_to_sid   = (is_expert == 1) ? psnames.adobe_expert_encoding : psnames.adobe_std_encoding;
}

function t1_cmap_std_done(cmap)
{
    cmap.num_glyphs    = 0;
    cmap.glyph_names   = null;
    cmap.sid_to_string = null;
    cmap.code_to_sid   = null;
}

function t1_cmap_std_char_index(cmap, char_code)
{
    var result = 0;

    if (char_code < 256)
    {
        /* convert character code to Adobe SID string */
        var code       = cmap.code_to_sid[char_code];
        var glyph_name = cmap.sid_to_string(code);

        /* look for the corresponding glyph name */
        for (var n = 0; n < cmap.num_glyphs; n++ )
        {
            var gname = cmap.glyph_names[n];

            if (gname != null && gname.charCodeAt(0) == glyph_name.charCodeAt(0) && gname == glyph_name)
            {
                result = n;
                break;
            }
        }
    }

    return result;
}

function t1_cmap_std_char_next(cmap, char_code)
{
    var result = 0;
    var pchar_code = char_code + 1;

    while (pchar_code < 256)
    {
        result = t1_cmap_std_char_index( cmap, pchar_code );
        if ( result != 0 )
            return {gindex:result,char_code:pchar_code};

        pchar_code++;
    }
    pchar_code = 0;
    return {gindex:result,char_code:pchar_code};
}

function t1_cmap_standard_init(cmap)
{
    t1_cmap_std_init(cmap, 0);
    return 0;
}

var t1_cmap_standard_class_rec = create_cmap_class_rec(0,t1_cmap_standard_init,t1_cmap_std_done,t1_cmap_std_char_index,t1_cmap_std_char_next,null,null,null,null,null);

// expert
function t1_cmap_expert_init(cmap)
{
    t1_cmap_std_init(cmap, 1);
    return 0;
}

var t1_cmap_expert_class_rec = create_cmap_class_rec(0,t1_cmap_expert_init,t1_cmap_std_done,t1_cmap_std_char_index,t1_cmap_std_char_next,null,null,null,null,null);

// custom
function t1_cmap_custom_init(cmap)
{
    var face = __FT_CMapRec(cmap).charmap.face;
    var encoding = face.type1.encoding;

    cmap.first   = encoding.code_first;
    cmap.count   = (encoding.code_last - cmap.first);

    if (0 > cmap.count)
        cmap.count = 0;

    cmap.indices = encoding.char_index;

    return 0;
}

function t1_cmap_custom_done(cmap)
{
    cmap.indices = null;
    cmap.first   = 0;
    cmap.count   = 0;
}

function t1_cmap_custom_char_index(cmap, char_code)
{
    if (char_code >= cmap.first && char_code < (cmap.first + cmap.count))
        return cmap.indices[char_code];
    return 0;
}

function t1_cmap_custom_char_next(cmap, _char_code)
{
    var result = 0;
    var char_code = _char_code;
    ++char_code;

    if (char_code < cmap.first)
        char_code = cmap.first;

    var last = cmap.first + cmap.count;
    for (; char_code < last; char_code++)
    {
        result = cmap.indices[char_code];
        if (result != 0)
            return {gindex:result,char_code:char_code};
    }

    return {gindex:result,char_code:0};
}

var t1_cmap_custom_class_rec = create_cmap_class_rec(0,t1_cmap_custom_init,t1_cmap_custom_done,t1_cmap_custom_char_index,t1_cmap_custom_char_next,null,null,null,null,null);

// unicode
function t1_get_glyph_name(face, idx)
{
    return face.type1.glyph_names[idx];
}

function t1_cmap_unicode_init(unicodes)
{
    var face = __FT_CMapRec(unicodes).charmap.face;
    var memory  = face.memory;
    var psnames = face.psnames;

    return psnames.unicodes_init(memory, unicodes, face.type1.num_glyphs, t1_get_glyph_name, null, face);
}

function t1_cmap_unicode_done(unicodes)
{
    unicodes.maps = null;
    unicodes.num_maps = 0;
}

function t1_cmap_unicode_char_index(unicodes, char_code)
{
    var face = __FT_CMapRec(unicodes).charmap.face;
    var psnames = face.psnames;

    return psnames.unicodes_char_index(unicodes, char_code);
}

function t1_cmap_unicode_char_next(unicodes, pchar_code)
{
    var face = __FT_CMapRec(unicodes).charmap.face;
    var psnames = face.psnames;

    return psnames.unicodes_char_next(unicodes, pchar_code);
}

var t1_cmap_unicode_class_rec = create_cmap_class_rec(0,t1_cmap_unicode_init,t1_cmap_unicode_done,t1_cmap_unicode_char_index,t1_cmap_unicode_char_next,null,null,null,null,null);

/******************************************************************************/
// psobj
/******************************************************************************/

function ps_table_new(table, count, memory)
{
    table.memory = memory;
    table.elements = new Array(count);

    for (var i = 0; i < count; i++)
        table.elements[i] = new CPointer();

    table.lengths = CreateIntArray(count);

    table.max_elems = count;
    table.init      = 0xDEADBEEF;
    table.num_elems = 0;
    table.block     = null;
    table.capacity  = 0;
    table.cursor    = 0;

    table.funcs = ps_table_funcs;
    return 0;
}

function shift_elements(table, old_base)
{
    var delta  = table.block.pos - old_base.pos;
    var els = table.elements;

    var limit = table.max_elems;
    for (var i = 0; i < limit; i++)
    {
        if (null != els[i])
        {
            els[i].data[els[i].pos] += delta;
        }
    }
}

function reallocate_t1_table(table, new_size)
{
    var memory = table.memory;
    var old_base = table.block;

    table.block = memory.Alloc(new_size);
    var dst = table.block.data;
    if (null != old_base)
    {
        var src = old_base.data;
        for (var i = 0; i < table.capacity; i++)
        {
            dst[i] = src[i];
        }
    }

    var _els = table.elements;
    var _elc = table.max_elems;
    for (var j = 0; j < _elc; j++)
        _els[j].data = dst;

    old_base = null;
    table.capacity = new_size;
    return 0;
}

function ps_table_add(table, idx, object, length)
{
    if (idx < 0 || idx >= table.max_elems)
        return 6;

    if (length < 0)
        return 6;

    /*
    table.elements[idx] = copy_pointer(object, length);
    table.lengths[idx] = length;
    table.cursor = idx + 1;
    */

    if (table.cursor + length > table.capacity)
    {
        var new_size = table.capacity;

        while (new_size < (table.cursor + length))
        {
            /* increase size by 25% and round up to the nearest multiple
             of 1024 */
            new_size += (new_size >> 2) + 1;
            new_size = parseInt((new_size + 1023) / 1024) * 1024;
        }

        reallocate_t1_table(table, new_size);
    }

    /* add the object to the base block and adjust offset */
    table.elements[idx].pos = table.cursor;
    table.lengths[idx] = length;

    var dd = table.block.data;
    var dp = table.cursor;
    var sd = object.data;
    var sp = object.pos;

    for (var i = 0; i < length; i++)
        dd[dp++] = sd[sp++];

    table.cursor += length;

    return 0;
}

function ps_table_done(table)
{
    if (null == table.block)
        return 0;

    reallocate_t1_table(table, table.cursor);
    return 0;
}

function ps_table_release(table)
{
    if (table.init == 0xDEADBEEF)
    {
        table.block = null;
        table.elements = null;
        table.lengths = null;
        table.init = 0;
    }
}

function skip_comment(cur, limit)
{
    while (cur.pos < limit)
    {
        if (IS_PS_NEWLINE(cur.data[cur.pos]))
            break;
        cur.pos++;
    }
}

function skip_spaces(cur, limit)
{
    while (cur.pos < limit)
    {
        if (!IS_PS_SPACE(cur.data[cur.pos]))
        {
            if (cur.data[cur.pos] == 37)
            {
                /* According to the PLRM, a comment is equal to a space. */
                skip_comment(cur, limit);
            }
            else
                break;
        }
        cur.pos++;
    }
}

function skip_literal_string(cur, limit)
{
    var embed = 0;
    var error = 3;

    while (cur.pos < limit)
    {
        var c = cur.data[cur.pos];
        cur.pos++;

        if (c == 92)
        {
            /* Red Book 3rd ed., section `Literal Text Strings', p. 29:     */
            /* A backslash can introduce three different types              */
            /* of escape sequences:                                         */
            /*   - a special escaped char like \r, \n, etc.                 */
            /*   - a one-, two-, or three-digit octal number                */
            /*   - none of the above in which case the backslash is ignored */

            if (cur.pos == limit)
                break;/* error (or to be ignored?) */

            switch (cur.data[cur.pos])
            {
            /* skip `special' escape */
            case 110:
            case 114:
            case 116:
            case 98:
            case 102:
            case 92:
            case 40:
            case 41:
                cur.pos++;
                break;

            default:
                /* skip octal escape or ignore backslash */
                for (var i = 0; i < 3 && cur.pos < limit; i++)
                {
                    if (48 > cur.data[cur.pos] || 55 < cur.data[cur.pos])
                        break;

                    cur.pos++;
                }
            }
        }
        else if (c == 40)
            embed++;
        else if (c == 41)
        {
            embed--;
            if (embed == 0)
            {
                error = 0;
                break;
            }
        }
    }
    return error;
}

function skip_string(cur, limit)
{
    while (cur.pos < limit)
    {
        /* All whitespace characters are ignored. */
        skip_spaces(cur, limit);
        if (cur.pos >= limit)
            break;

        if (!IS_PS_XDIGIT(cur.data[cur.pos]))
            break;
    }

    if (cur.pos < limit && cur.data[cur.pos] != 62)
    {
        return 3;
    }
    else
        cur.pos++;

    return 0;
}

function skip_procedure(cur, limit)
{
    var embed = 0;

    var error = 0;
    for (; cur.pos < limit && error == 0; cur.pos++)
    {
        switch (cur.data[cur.pos])
        {
        case 123:
            ++embed;
            break;

        case 125:
            --embed;
            if (embed == 0)
            {
                cur.pos++;
                return 0;
            }
            break;

        case 40:
            error = skip_literal_string(cur, limit);
            break;

        case 60:
            error = skip_string(cur, limit);
            break;

        case 37:
            skip_comment(cur, limit);
            break;
        }
    }

    if (embed != 0)
        error = 3;

    return error;
}

function ps_parser_skip_PS_token(parser)
{
    /* Note: PostScript allows any non-delimiting, non-whitespace        */
    /*       character in a name (PS Ref Manual, 3rd ed, p31).           */
    /*       PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */

    var cur = dublicate_pointer(parser.cursor);
    var limit = parser.limit;
    var error = 0;

    var cursor_pos = cur.pos;
    skip_spaces(cur, limit);             /* this also skips comments */
    if (cur.pos >= limit)
    {
        if (cur.pos == cursor_pos)
        {
            error = 3;
        }

        parser.error  = error;
        parser.cursor.pos = cur.pos;
        return;
    }

    /* self-delimiting, single-character tokens */
    if (cur.data[cur.pos] == 91 || cur.data[cur.pos] == 93)
    {
        cur.pos++;
        if (cur.pos == cursor_pos)
        {
            error = 3;
        }

        parser.error  = error;
        parser.cursor.pos = cur.pos;
        return;
    }

    /* skip balanced expressions (procedures and strings) */

    if (cur.data[cur.pos] == 123)                              /* {...} */
    {
        error = skip_procedure(cur, limit);
        if (cur.pos == cursor_pos)
        {
            error = 3;
        }

        parser.error  = error;
        parser.cursor.pos = cur.pos;
        return;
    }

    if (cur.data[cur.pos] == 40)                              /* (...) */
    {
        error = skip_literal_string(cur, limit);
        if (cur.pos == cursor_pos)
        {
            error = 3;
        }

        parser.error  = error;
        parser.cursor.pos = cur.pos;
        return;
    }

    if (cur.data[cur.pos] == 60)                              /* <...> */
    {
        if (cur.pos + 1 < limit && cur.data[cur.pos + 1] == 60)   /* << */
        {
            cur.pos += 2;
        }
        else
            error = skip_string(cur, limit);

        if (cur.pos == cursor_pos)
        {
            error = 3;
        }

        parser.error  = error;
        parser.cursor.pos = cur.pos;
        return;
    }

    if (cur.data[cur.pos] == 62)
    {
        cur.pos++;
        if (cur.pos >= limit || cur.data[cur.pos] != 62)             /* >> */
        {
            error = 3;

            parser.error  = error;
            parser.cursor.pos = cur.pos;
            return;
        }
        cur.pos++;
        if (cur.pos == cursor_pos)
        {
            error = 3;
        }

        parser.error  = error;
        parser.cursor.pos = cur.pos;
        return;
    }

    if (cur.data[cur.pos] == 47)
        cur.pos++;

    /* anything else */
    while (cur.pos < limit)
    {
        /* *cur might be invalid (e.g., ')' or '}'), but this   */
        /* is handled by the test `cur == parser->cursor' below */
        if (IS_PS_DELIM(cur.data[cur.pos]))
            break;

        cur.pos++;
    }

    //exit
    if (cur.pos == cursor_pos)
    {
        error = 3;
    }

    parser.error  = error;
    parser.cursor.pos = cur.pos;
}

function ps_parser_skip_spaces(parser)
{
    skip_spaces(parser.cursor, parser.limit);
}

function ps_parser_to_token(parser, token)
{
    var limit = parser.limit;
    var embed = 0;

    token.type  = 0;
    token.start = null;
    token.limit = 0;

    /* first of all, skip leading whitespace */
    ps_parser_skip_spaces(parser);
    var cur = dublicate_pointer(parser.cursor);

    if (cur.pos >= limit)
        return;

    switch (cur.data[cur.pos])
    {
        /************* check for literal string *****************/
    case 40:
        token.type  = 2;
        token.start = dublicate_pointer(cur);

        if (skip_literal_string(cur, limit) == 0)
            token.limit = cur.pos;
        break;

        /************* check for programs/array *****************/
    case 123:
        token.type  = 3;
        token.start = dublicate_pointer(cur);

        if (skip_procedure(cur, limit) == 0)
            token.limit = cur.pos;
        break;

        /************* check for table/array ********************/
        /* XXX: in theory we should also look for "<<"          */
        /*      since this is semantically equivalent to "[";   */
        /*      in practice it doesn't matter (?)               */
    case 91:
        token.type  = 3;
        embed        = 1;
        token.start  = dublicate_pointer(cur);
        cur.pos++;

        /* we need this to catch `[ ]' */
        parser.cursor.pos = cur.pos;
        ps_parser_skip_spaces(parser);
        cur.pos = parser.cursor.pos;

        while (cur.pos < limit && parser.error == 0)
        {
            /* XXX: this is wrong because it does not      */
            /*      skip comments, procedures, and strings */
            if (cur.data[cur.pos] == 91)
                embed++;
            else if (cur.data[cur.pos] == 93)
            {
                embed--;
                if ( embed <= 0 )
                {
                    cur.pos++;
                    token.limit = cur.pos;
                    break;
                }
            }

            parser.cursor.pos = cur.pos;
            ps_parser_skip_PS_token(parser);
            /* we need this to catch `[XXX ]' */
            ps_parser_skip_spaces(parser);
            cur.pos = parser.cursor.pos;
        }
        break;

        /* ************ otherwise, it is any token **************/
    default:
        token.start = dublicate_pointer(cur);
        token.type  = ((cur.data[cur.pos] == 47) ? 4 : 1);
        ps_parser_skip_PS_token(parser);
        cur.pos = parser.cursor.pos;
        if (!parser.error)
            token.limit = cur.pos;
    }

    if (token.limit == 0)
    {
        token.start = null;
        token.type  = 0;
    }

    parser.cursor.pos = cur.pos;
}

function ps_parser_to_token_array(parser, tokens, max_tokens)
{
    var master = new T1_TokenRec();
    var pnum_tokens = -1;
    /* this also handles leading whitespace */
    ps_parser_to_token(parser, master);

    if (master.type == 3)
    {
        var old_cursor = parser.cursor.pos;
        var old_limit  = parser.limit;
        var cur        = 0;

        /* don't include outermost delimiters */
        parser.cursor = dublicate_pointer(master.start);
        parser.cursor.pos += 1;
        parser.limit  = master.limit - 1;

        while (parser.cursor.pos < parser.limit)
        {
            var token = new T1_TokenRec();
            ps_parser_to_token(parser, token);
            if (token.type == 0)
                break;

            if (tokens != null && cur < max_tokens)
            {
                var _cur = tokens[cur];
                _cur.start = dublicate_pointer(token.start);
                _cur.limit = token.limit;
                _cur.type = token.type;
            }

            cur++;
        }

        pnum_tokens = cur;

        parser.cursor.pos = old_cursor;
        parser.limit  = old_limit;
    }

    return pnum_tokens;
}

function ps_tocoordarray(cur, limit, max_coords, coords)
{
    var count = 0;
    if (cur.pos >= limit)
        return count;

    /* check for the beginning of an array; otherwise, only one number */
    /* will be read                                                    */
    var c = cur.data[cur.pos];
    var ender = 0;

    if (c == 91)
        ender = 93;
    else if (c == 123)
        ender = 125;

    if (ender != 0)
        cur.pos++;

    /* now, read the coordinates */
    while ( cur < limit )
    {
        /* skip whitespace in front of data */
        skip_spaces(cur, limit);
        if (cur.pos >= limit)
            return count;

        if (cur.data[cur.pos] == ender)
        {
            cur.pos++;
            break;
        }

        var old_cur = cur.pos;

        if ( coords != null && count >= max_coords )
            break;

        /* call PS_Conv_ToFixed() even if coords == NULL */
        /* to properly parse number at `cur'             */
        var dummy = PS_Conv_ToFixed(cur, limit, 0) >> 16;
        if (null != coords)
            coords[count] = dummy;

        if (old_cur == cur.pos)
        {
            count = -1;
            return count;
        }
        else
            count++;

        if (ender == 0)
            break;
    }

    return count;
}

function ps_tofixedarray(cur, limit, max_values, values, power_ten)
{
    var count = 0;
    if (cur.pos >= limit)
        return count;

    /* Check for the beginning of an array.  Otherwise, only one number */
    /* will be read.                                                    */
    var c = cur.data[cur.pos];
    var ender = 0;

    if (c == 91)
        ender = 93;
    else if (c == 123)
        ender = 125;

    if (ender != 0)
        cur.pos++;

    /* now, read the values */
    while (cur.pos < limit)
    {
        /* skip whitespace in front of data */
        skip_spaces(cur, limit);
        if (cur.pos >= limit)
            return count;

        if (cur.data[cur.pos] == ender)
        {
            cur.pos++;
            break;
        }

        var old_cur = cur.pos;
        if (values != null && count >= max_values)
            break;

        /* call PS_Conv_ToFixed() even if coords == NULL */
        /* to properly parse number at `cur'             */
        var dummy = PS_Conv_ToFixed(cur, limit, power_ten);
        if (null != values)
            values[count] = dummy;

        if (old_cur == cur.pos)
        {
            count = -1;
            return count;
        }
        else
            count++;

        if (ender == 0)
            break;
    }

    return count;
}

function ps_tobool(cur, limit)
{
    var result = 0;
    var data = cur.data;
    var pos = cur.pos;

    /* return 1 if we find `true', 0 otherwise */
    if (cur.pos + 3 < limit &&
        data[pos] == 116 &&
        data[pos + 1] == 114 &&
        data[pos + 2] == 117 &&
        data[pos + 3] == 101)
    {
        result = 1;
        cur.pos += 5;
    }
    else if (cur.pos + 4 < limit &&
        data[pos] == 102 &&
        data[pos + 1] == 97 &&
        data[pos + 2] == 108 &&
        data[pos + 3] == 115 &&
        data[pos + 4] == 101)
    {
        result = 0;
        cur.pos   += 6;
    }

    return result;
}

function ps_parser_load_field(parser, field, objects, max_objects, pflags)
{
    var token = new T1_TokenRec();
    /* this also skips leading whitespace */
    ps_parser_to_token(parser, token);
    if (token.type == 0)
        return 3;

    var count = 1;
    var idx   = 0;
    var cur   = dublicate_pointer(token.start);
    var limit = token.limit;

    /* we must detect arrays in /FontBBox */
    if (field.type == 7)
    {
        var token2 = new T1_TokenRec();
        var old_cur   = dublicate_pointer(parser.cursor);
        var old_limit = parser.limit;

        /* don't include delimiters */
        parser.cursor = dublicate_pointer(token.start);
        parser.cursor.pos += 1;
        parser.limit  = token.limit - 1;

        ps_parser_to_token(parser, token2);
        parser.cursor = dublicate_pointer(old_cur);
        parser.limit  = old_limit;

        if (token2.type == 3)
        {
            /* if this is an array and we have no blend, an error occurs */
            if (max_objects == 0)
                return 3;

            count = max_objects;
            idx   = 1;

            /* don't include delimiters */
            cur.pos++;
            limit--;
        }
    }
    else if (token.type == 3)
    {
        /* if this is an array and we have no blend, an error occurs */
        if (max_objects == 0)
            return 3;

        count = max_objects;
        idx   = 1;

        /* don't include delimiters */
        cur.pos++;
        limit--;
    }

    for (; count > 0; count--, idx++)
    {
        var __obj = objects[idx];
        var val;
        skip_spaces(cur, limit);

        switch (field.type)
        {
            case 1:
                val = ps_tobool(cur, limit);
                fire_t1_field(__obj, val, field);
                break;

            case 3:
                val = PS_Conv_ToFixed(cur, limit, 0);
                fire_t1_field(__obj, val, field);
                break;

            case 4:
                val = PS_Conv_ToFixed(cur, limit, 3);
                fire_t1_field(__obj, val, field);
                break;

            case 2:
                val = PS_Conv_ToInt(cur, limit);
                fire_t1_field(__obj, val, field);
                break;

            case 5:
            case 6:
                var len = (limit - cur.pos);

                if (cur.pos >= limit)
                    break;

                /* we allow both a string or a name   */
                /* for cases like /FontName (foo) def */
                if (token.type == 4)
                {
                    /* don't include leading `/' */
                    len--;
                    cur.pos++;
                }
                else if (token.type == 2)
                {
                    /* don't include delimiting parentheses    */
                    /* XXX we don't handle <<...>> here        */
                    /* XXX should we convert octal escapes?    */
                    /*     if so, what encoding should we use? */
                    cur.pos++;
                    len -= 2;
                }
                else
                {
                    return 3;
                }

                /* for this to work (FT_String**)q must have been */
                /* initialized to NULL                            */
                var _s = "";
                for (var i = 0; i < len; i++)
                    _s += String.fromCharCode(cur.data[cur.pos + i]);

                fire_t1_field(__obj, _s, field);
                break;

            case 7:
                var temp = new Array(4);
                temp[0] = 0;
                temp[1] = 0;
                temp[2] = 0;
                temp[3] = 0;

                var result = ps_tofixedarray(cur, limit, 4, temp, 0);

                if ( result < 0 )
                {
                    return 3;
                }

                __obj.xMin = FT_RoundFix(temp[0]);
                __obj.yMin = FT_RoundFix(temp[1]);
                __obj.xMax = FT_RoundFix(temp[2]);
                __obj.yMax = FT_RoundFix(temp[3]);

                break;

            default:
                /* an error occurred */
                return 3;
        }
    }

    return 0;
}

function ps_parser_load_field_table(parser, field, objects, max_objects, pflags)
{
    var elements = new Array(32);
    for (var i = 0; i < 32; i++)
        elements[i] = new T1_TokenRec();

    var fieldrec = create_dublicate_t1_field(field);

    fieldrec.type = 2;
    if (field.type == 9 || field.type == 7)
        fieldrec.type = 3;

    var num_elements = ps_parser_to_token_array(parser, elements, 32);
    if (num_elements < 0)
        return 162;

    if (num_elements > field.array_max)
        num_elements = field.array_max;

    var old_cursor = dublicate_pointer(parser.cursor);
    var old_limit  = parser.limit;

    /* we store the elements count if necessary;           */
    /* we further assume that `count_offset' can't be zero */
    if (field.type != 7 && field.set_field_count != undefined)
    {
        fire_t1_field_count(objects[0], num_elements, field);
    }

    /* we now load each element, adjusting the field.offset on each one */
    var token = 0;
    for ( ; num_elements > 0; num_elements--, token++)
    {
        fieldrec.offset = token;
        parser.cursor = dublicate_pointer(elements[token].start);
        parser.limit  = elements[token].limit;
        ps_parser_load_field(parser, fieldrec, objects, max_objects, 0);
    }

    parser.cursor = dublicate_pointer(old_cursor);
    parser.limit  = old_limit;

    return 0;
}

function ps_parser_to_int(parser)
{
    ps_parser_skip_spaces(parser);
    return PS_Conv_ToInt(parser.cursor, parser.limit);
}

function ps_parser_to_bytes(parser, bytes, max_bytes, delimiters)
{
    ps_parser_skip_spaces(parser);
    var cur = dublicate_pointer(parser.cursor);
    
    if (cur.pos >= parser.limit)
        return 0;

    if (delimiters)
    {
        if (cur.data[cur.pos] != 60)
        {
            return {err: 3, num_bytes: 0};
        }

        cur.pos++;
    }

    var num_bytes = PS_Conv_ASCIIHexDecode(cur, parser.limit, bytes, max_bytes);

    if (delimiters)
    {
        if (cur.pos < parser.limit && cur.data[cur.pos] != 62)
        {
            return {err: 3, num_bytes: num_bytes};
        }

        cur.pos++;
    }

    parser.cursor.pos = cur.pos;
    return {err: 0, num_bytes: num_bytes};
}

function ps_parser_to_fixed(parser, power_ten)
{
    ps_parser_skip_spaces(parser);
    return PS_Conv_ToFixed(parser.cursor, parser.limit, power_ten);
}

function ps_parser_to_coord_array(parser, max_coords, coords)
{
    ps_parser_skip_spaces(parser);
    return PS_Conv_ToFixed(parser.cursor, parser.limit, max_coords, coords);
}

function ps_parser_to_fixed_array(parser, max_values, values, power_ten)
{
    ps_parser_skip_spaces(parser);
    return ps_tofixedarray(parser.cursor, parser.limit, max_values, values, power_ten);
}

function ps_parser_init(parser, base, limit, memory)
{
    parser.error  = 0;
    parser.base   = dublicate_pointer(base);
    parser.limit  = limit;
    parser.cursor = dublicate_pointer(base);
    parser.memory = memory;
    parser.funcs  = ps_parser_funcs;
}

function ps_parser_done(parser)
{
}

function t1_builder_init(builder, face, size, _glyph, hinting)
{
    var glyph = (null == _glyph) ? null : _glyph.root;

    builder.parse_state = 0;
    builder.load_points = 1;

    builder.face = face;
    builder.glyph = glyph;
    builder.memory = face.memory;

    if (glyph != null)
    {
        var loader = glyph.internal.loader;

        builder.loader  = loader;
        builder.base    = loader.base.outline;
        builder.current = loader.current.outline;
        FT_GlyphLoader_Rewind(loader);

        builder.hints_globals = size.internal;
        builder.hints_funcs   = null;

        if (hinting)
            builder.hints_funcs = glyph.internal.glyph_hints;
    }

    builder.pos_x = 0;
    builder.pos_y = 0;

    builder.left_bearing.x = 0;
    builder.left_bearing.y = 0;
    builder.advance.x      = 0;
    builder.advance.y      = 0;

    builder.funcs = t1_builder_funcs;
}

function t1_builder_done(builder)
{
    var glyph = builder.glyph;

    if (glyph != null)
        EquatingOutline(glyph.outline, builder.base);
}

function t1_builder_check_points(builder, count)
{
    return FT_GLYPHLOADER_CHECK_POINTS(builder.loader, count, 0);
}

function t1_builder_add_point(builder, x, y, flag)
{
    var outline = builder.current;
    var base = builder.base;

    if (builder.load_points)
    {
        var point = base.points[outline.points + outline.n_points];
        point.x = (FT_RoundFix(x) >> 16);
        point.y = (FT_RoundFix(y) >> 16);

        base.tags[outline.tags + outline.n_points] = flag ? 1 : 2;
    }
    outline.n_points++;
}

function t1_builder_add_point1(builder, x, y)
{
    var error = t1_builder_check_points(builder, 1);
    if ( !error )
        t1_builder_add_point(builder, x, y, 1);

    return error;
}

function t1_builder_add_contour(builder)
{
    var outline = builder.current;

    /* this might happen in invalid fonts */
    if (outline == null)
    {
        return 3;
    }

    if (builder.load_points == 0)
    {
        outline.n_contours++;
        return 0;
    }

    var error = FT_GLYPHLOADER_CHECK_POINTS(builder.loader, 0, 1);
    if (error == 0)
    {
        if (outline.n_contours > 0)
            builder.base.contours[outline.contours + outline.n_contours - 1] = (outline.n_points - 1);

        outline.n_contours++;
    }

    return error;
}

function t1_builder_start_point(builder, x, y)
{
    var error = 3;

    /* test whether we are building a new contour */
    if (builder.parse_state == 3)
        error = 0;
    else
    {
        builder.parse_state = 3;
        error = t1_builder_add_contour(builder);
        if ( !error )
            error = t1_builder_add_point1(builder, x, y);
    }

    return error;
}

function t1_builder_close_contour(builder)
{
    var outline = builder.current;

    if (outline == null)
        return;

    var base = builder.base;
    var first = (outline.n_contours <= 1) ? 0 : base.contours[outline.contours + outline.n_contours - 2] + 1;

    /* We must not include the last point in the path if it */
    /* is located on the first point.                       */
    if (outline.n_points > 1)
    {
        var p1 = base.points[outline.points + first];
        var p2 = base.points[outline.points + outline.n_points - 1];

        var control = base.tags[outline.tags + outline.n_points - 1];

        /* `delete' last point only if it coincides with the first */
        /* point and it is not a control point (which can happen). */
        if (p1.x == p2.x && p1.y == p2.y)
            if (control == 1)
                outline.n_points--;
    }

    if (outline.n_contours > 0)
    {
        /* Don't add contours only consisting of one point, i.e.,  */
        /* check whether the first and the last point is the same. */
        if (first == outline.n_points - 1)
        {
            outline.n_contours--;
            outline.n_points--;
        }
        else
            base.contours[outline.contours + outline.n_contours - 1] = (outline.n_points - 1);
    }
}

function t1_decrypt(buffer, length, seed)
{
    var mem = dublicate_pointer(buffer);
    PS_Conv_EexecDecode(mem, mem.pos + length, mem, length, seed);
}

/******************************************************************************/
// t1decode
/******************************************************************************/

var t1_args_count = [
    0, /* none */
    0, /* endchar */
    2, /* hsbw */
    5, /* seac */
    4, /* sbw */
    0, /* closepath */
    1, /* hlineto */
    1, /* hmoveto */
    4, /* hvcurveto */
    2, /* rlineto */
    2, /* rmoveto */
    6, /* rrcurveto */
    4, /* vhcurveto */
    1, /* vlineto */
    1, /* vmoveto */
    0, /* dotsection */
    2, /* hstem */
    6, /* hstem3 */
    2, /* vstem */
    6, /* vstem3 */
    2, /* div */
    -1, /* callothersubr */
    1, /* callsubr */
    0, /* pop */
    0, /* return */
    2, /* setcurrentpoint */
    2  /* opcode 15 (undocumented and obsolete) */
];

function t1_lookup_glyph_by_stdcharcode(decoder, charcode)
{
    /* check range of standard char code */
    if (charcode < 0 || charcode > 255)
        return -1;

    var glyph_name = decoder.psnames.adobe_std_strings(decoder.psnames.adobe_std_encoding[charcode]);

    for (var n = 0; n < decoder.num_glyphs; n++)
    {
        var name = decoder.glyph_names[n];

        if (name != null && name == glyph_name)
            return n;
    }

    return -1;
}

function t1operator_seac(decoder, asb, adx, ady, bchar, achar)
{
    var bchar_index, achar_index;

    if (decoder.seac)
        return 160;

    var error = 0;
    var face = decoder.builder.face;

    /* seac weirdness */
    adx += decoder.builder.left_bearing.x;

    /* `glyph_names' is set to 0 for CID fonts which do not */
    /* include an encoding.  How can we deal with these?    */
    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
    if (decoder.glyph_names == null && null == face.internal.incremental_interface)
        return 160;

    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
    if (face.internal.incremental_interface != null)
    {
        /* the caller must handle the font encoding also */
        bchar_index = bchar;
        achar_index = achar;
    }
    else// #endif
    {
        bchar_index = t1_lookup_glyph_by_stdcharcode(decoder, bchar);
        achar_index = t1_lookup_glyph_by_stdcharcode(decoder, achar);
    }

    if (bchar_index < 0 || achar_index < 0)
        return 160;

    /* if we are trying to load a composite glyph, do not load the */
    /* accent character and return the array of subglyphs.         */
    if (decoder.builder.no_recurse)
    {
        var glyph = decoder.builder.glyph;
        var loader = glyph.internal.loader;

        /* reallocate subglyph array if necessary */
        error = FT_GlyphLoader_CheckSubGlyphs(loader, 2);
        if (error != 0)
            return error;

        var subg = loader.current.subglyphs[0];

        /* subglyph 0 = base character */
        subg.index = bchar_index;
        subg.flags = 2 | 512;
        subg.arg1  = 0;
        subg.arg2  = 0;

        subg = loader.current.subglyphs[1];

        /* subglyph 1 = accent character */
        subg.index = achar_index;
        subg.flags = 2;
        subg.arg1  = FT_RoundFix(adx - asb) >> 16;
        subg.arg2  = FT_RoundFix(ady) >> 16;

        /* set up remaining glyph fields */
        glyph.num_subglyphs = 2;
        glyph.subglyphs     = loader.base.subglyphs;
        glyph.format        = 1668246896;

        loader.current.num_subglyphs = 2;
        return error;
    }

    /* First load `bchar' in builder */
    /* now load the unscaled outline */

    FT_GlyphLoader_Prepare(decoder.builder.loader);  /* prepare loader */

    /* the seac operator must not be nested */
    decoder.seac = 1;
    error = t1_decoder_parse_glyph(decoder, bchar_index);
    decoder.seac = 0;
    if (error != 0)
        return error;

    /* save the left bearing and width of the base character */
    /* as they will be erased by the next load.              */

    var left_bearing = dublicate_vector(decoder.builder.left_bearing);
    var advance      = dublicate_vector(decoder.builder.advance);

    decoder.builder.left_bearing.x = 0;
    decoder.builder.left_bearing.y = 0;

    decoder.builder.pos_x = adx - asb;
    decoder.builder.pos_y = ady;

    /* Now load `achar' on top of */
    /* the base outline           */

    /* the seac operator must not be nested */
    decoder.seac = 1;
    error = t1_decoder_parse_glyph(decoder, achar_index);
    decoder.seac = 0;
    if (error != 0)
        return error;

    /* restore the left side bearing and   */
    /* advance width of the base character */

    decoder.builder.left_bearing = left_bearing;
    decoder.builder.advance      = advance;

    decoder.builder.pos_x = 0;
    decoder.builder.pos_y = 0;

    return error;
}

function t1_decoder_parse_charstrings(decoder, charstring_base, charstring_len)
{
    var builder = decoder.builder;
    var x, y, orig_x, orig_y;
    var known_othersubr_result_cnt   = 0;
    var unknown_othersubr_result_cnt = 0;
    var large_int = 0;

    /* compute random seed from stack address of parameter */
    var seed = parseInt(Math.random() * 0xFFFF);
    if (seed == 0)
        seed = 0x7384;

    /* First of all, initialize the decoder */
    decoder.top  = 0;
    decoder.zone = 0;
    var zone  = 0;
    var zones = decoder.zones;

    builder.parse_state = 0;

    var hinter = builder.hints_funcs;

    /* a font that reads BuildCharArray without setting */
    /* its values first is buggy, but ...               */
    if (decoder.buildchar != null && decoder.len_buildchar > 0)
    {
        for (var i = 0; i < decoder.len_buildchar; i++)
        {
            decoder.buildchar[i] = 0;
        }
    }

    zones[zone].base = dublicate_pointer(charstring_base);
    zones[zone].limit  = charstring_base.pos + charstring_len;
    var limit = zones[zone].limit;

    zones[zone].cursor = 0;
    var ip = dublicate_pointer(zones[zone].base);

    var error = 0;

    x = orig_x = builder.pos_x;
    y = orig_y = builder.pos_y;

    /* begin hints recording session, if any */
    if (hinter != null)
        hinter.open(hinter.hints);

    large_int = 0;

    /* now, execute loop */
    while (ip.pos < limit)
    {
        var tops = decoder.stack;
        var top = decoder.top;
        var op = 0;
        var value = 0;

        /*********************************************************************/
        /*                                                                   */
        /* Decode operator or operand                                        */
        /*                                                                   */
        /*                                                                   */
        /* first of all, decompress operator or value */
        var _oper = ip.data[ip.pos];
        ip.pos++;
        switch (_oper)
        {
        case 1:
            op = 16;
            break;

        case 3:
            op = 18;
            break;
        case 4:
            op = 14;
            break;
        case 5:
            op = 9;
            break;
        case 6:
            op = 6;
            break;
        case 7:
            op = 13;
            break;
        case 8:
            op = 11;
            break;
        case 9:
            op = 5;
            break;
        case 10:
            op = 22;
            break;
        case 11:
            op = 24;
            break;

        case 13:
            op = 2;
            break;
        case 14:
            op = 1;
            break;

        case 15:          /* undocumented, obsolete operator */
            op = 26;
            break;

        case 21:
            op = 10;
            break;
        case 22:
            op = 7;
            break;

        case 30:
            op = 12;
            break;
        case 31:
            op = 8;
            break;

        case 12:
            if (ip.pos > limit)
                return 160;

            var _oper2 = ip.data[ip.pos];
            ip.pos++;
            switch (_oper2)
            {
            case 0:
                op = 15;
                break;
            case 1:
                op = 19;
                break;
            case 2:
                op = 17;
                break;
            case 6:
                op = 3;
                break;
            case 7:
                op = 4;
                break;
            case 12:
                op = 20;
                break;
            case 16:
                op = 21;
                break;
            case 17:
                op = 23;
                break;
            case 33:
                op = 25;
                break;

            default:
                return 160;
            }
            break;

        case 255:    /* four bytes integer */
            if (ip.pos + 4 > limit)
            {
                return 160;
            }

            value = ((ip.data[ip.pos] << 24) | (ip.data[ip.pos + 1] << 16) | (ip.data[ip.pos + 2] << 8) |  (ip.data[ip.pos + 3]));
            ip.pos += 4;

            /* According to the specification, values > 32000 or < -32000 must */
            /* be followed by a `div' operator to make the result be in the    */
            /* range [-32000;32000].  We expect that the second argument of    */
            /* `div' is not a large number.  Additionally, we don't handle     */
            /* stuff like `<large1> <large2> <num> div <num> div' or           */
            /* <large1> <large2> <num> div div'.  This is probably not allowed */
            /* anyway.                                                         */
            if (value > 32000 || value < -32000)
            {
                if (large_int)
                {
                }
                else
                    large_int = 1;
            }
            else
            {
                if (!large_int)
                    value <<= 16;
            }

            break;

        default:
            if (ip.data[ip.pos - 1] >= 32)
            {
                if (ip.data[ip.pos - 1] < 247)
                    value = ip.data[ip.pos - 1] - 139;
                else
                {
                    ip.pos++;
                    if (ip.pos > limit)
                    {
                        return 160;
                    }

                    if (ip.data[ip.pos - 2] < 251)
                        value =  ((ip.data[ip.pos - 2] - 247) << 8) + ip.data[ip.pos - 1] + 108;
                    else
                        value = -(((ip.data[ip.pos - 2] - 251) << 8) + ip.data[ip.pos - 1] + 108);
                }

                if (!large_int)
                    value <<= 16;
            }
            else
            {
                return 160;
            }
        }

        if (unknown_othersubr_result_cnt > 0)
        {
            switch (op)
            {
                case 22:
                case 24:
                case 0:
                case 23:
                    break;

                default:
                    /* all operands have been transferred by previous pops */
                    unknown_othersubr_result_cnt = 0;
                    break;
            }
        }

        if ( large_int && !(op == 0 || op == 20))
        {
            large_int = 0;
        }

        /*********************************************************************/
        /*                                                                   */
        /*  Push value on stack, or process operator                         */
        /*                                                                   */
        /*                                                                   */
        if (op == 0)
        {
            if (top >= 256)
            {
                return 160;
            }

            tops[top] = value;
            top++;
            decoder.top = top;
        }
        else if ( op == 21 )  /* callothersubr */
        {
            if (top < 2)
                return 130;

            top -= 2;

            var subr_no = (tops[top + 1] >> 16) & 0xFFFF;
            var arg_cnt = (tops[top] >> 16) & 0xFFFF;

            /***********************************************************/
            /*                                                         */
            /* remove all operands to callothersubr from the stack     */
            /*                                                         */
            /* for handled othersubrs, where we know the number of     */
            /* arguments, we increase the stack by the value of        */
            /* known_othersubr_result_cnt                              */
            /*                                                         */
            /* for unhandled othersubrs the following pops adjust the  */
            /* stack pointer as necessary                              */

            if (arg_cnt > top)
                return 130;

            top -= arg_cnt;

            known_othersubr_result_cnt   = 0;
            unknown_othersubr_result_cnt = 0;

            /* XXX TODO: The checks to `arg_count == <whatever>'       */
            /* might not be correct; an othersubr expects a certain    */
            /* number of operands on the PostScript stack (as opposed  */
            /* to the T1 stack) but it doesn't have to put them there  */
            /* by itself; previous othersubrs might have left the      */
            /* operands there if they were not followed by an          */
            /* appropriate number of pops                              */
            /*                                                         */
            /* On the other hand, Adobe Reader 7.0.8 for Linux doesn't */
            /* accept a font that contains charstrings like            */
            /*                                                         */
            /*     100 200 2 20 callothersubr                          */
            /*     300 1 20 callothersubr pop                          */
            /*                                                         */
            /* Perhaps this is the reason why BuildCharArray exists.   */

            switch (subr_no)
            {
                case 0:                     /* end flex feature */
                    if (arg_cnt != 3)
                        return 160;

                    if (decoder.flex_state == 0 || decoder.num_flex_vectors != 7)
                    {
                        return 160;
                    }

                    /* the two `results' are popped by the following setcurrentpoint */
                    tops[top] = x;
                    tops[top + 1] = y;
                    known_othersubr_result_cnt = 2;
                    break;

                case 1:                     /* start flex feature */
                    if (arg_cnt != 0)
                        return 160;

                    decoder.flex_state        = 1;
                    decoder.num_flex_vectors  = 0;

                    error = t1_builder_start_point(builder, x, y);
                    if (error != 0)
                        return error;

                    error = t1_builder_check_points(builder, 6);
                    if (error != 0)
                        return error;

                    break;

                case 2:                     /* add flex vectors */
                    if (arg_cnt != 0)
                        return 160;

                    if (decoder.flex_state == 0)
                    {
                        return 160;
                    }

                    /* note that we should not add a point for index 0; */
                    /* this will move our current position to the flex  */
                    /* point without adding any point to the outline    */
                    var idx = decoder.num_flex_vectors;
                    decoder.num_flex_vectors++;
                    if (idx > 0 && idx < 7)
                        t1_builder_add_point(builder, x, y, (idx == 3 || idx == 6) ? 1 : 0);

                    break;

                case 3:                     /* change hints */
                    if (arg_cnt != 1)
                        return 160;

                    known_othersubr_result_cnt = 1;

                    if (hinter)
                        hinter.reset(hinter.hints, builder.current.n_points);
                    break;

                case 12:
                case 13:
                    /* counter control hints, clear stack */
                    top = 0;
                    break;

                case 14:
                case 15:
                case 16:
                case 17:
                case 18:                    /* multiple masters */
                {
                    var blend = decoder.blend;

                    if ( !blend )
                    {
                        return 160;
                    }

                    var num_points = subr_no - 13;
                    if (subr_no == 18)
                        num_points++;
                    if (arg_cnt != (num_points * blend.num_designs))
                    {
                        return 160;
                    }

                    /* We want to compute                                    */
                    /*                                                       */
                    /*   a0*w0 + a1*w1 + ... + ak*wk                         */
                    /*                                                       */
                    /* but we only have a0, a1-a0, a2-a0, ..., ak-a0.        */
                    /*                                                       */
                    /* However, given that w0 + w1 + ... + wk == 1, we can   */
                    /* rewrite it easily as                                  */
                    /*                                                       */
                    /*   a0 + (a1-a0)*w1 + (a2-a0)*w2 + ... + (ak-a0)*wk     */
                    /*                                                       */
                    /* where k == num_designs-1.                             */
                    /*                                                       */
                    /* I guess that's why it's written in this `compact'     */
                    /* form.                                                 */
                    /*                                                       */
                    var delta  = top + num_points;
                    var values = top;
                    for (var nn = 0; nn < num_points; nn++)
                    {
                        var tmp = tops[values];

                        for (var mm = 1; mm < blend.num_designs; mm++)
                            tmp += FT_MulFix(tops[delta++], blend.weight_vector[mm]);

                        tops[values++] = tmp;
                    }

                    known_othersubr_result_cnt = num_points;
                    break;
                }

                case 19:
                    /* <idx> 1 19 callothersubr                             */
                    /* => replace elements starting from index cvi( <idx> ) */
                    /*    of BuildCharArray with WeightVector               */
                    var blend = decoder.blend;

                    if (arg_cnt != 1 || blend == null)
                        return 160;

                    var idx = (tops[top] >> 16) & 0xFFFF;

                    if (idx < 0 || (idx + blend.num_designs) > decoder.len_buildchar)
                        return 160;

                    for (var ii = 0; ii < blend.num_designs; ii++)
                        decoder.buildchar[idx + ii] = blend.weight_vector[ii];

                    break;

                case 20:
                    /* <arg1> <arg2> 2 20 callothersubr pop   */
                    /* ==> push <arg1> + <arg2> onto T1 stack */
                    if (arg_cnt != 2)
                        return 160;

                    tops[top] += tops[top + 1]; /* XXX (over|under)flow */

                    known_othersubr_result_cnt = 1;
                    break;

                case 21:
                    /* <arg1> <arg2> 2 21 callothersubr pop   */
                    /* ==> push <arg1> - <arg2> onto T1 stack */
                    if (arg_cnt != 2)
                        return 160;

                    tops[top] -= tops[top + 1]; /* XXX (over|under)flow */

                    known_othersubr_result_cnt = 1;
                    break;

                case 22:
                    /* <arg1> <arg2> 2 22 callothersubr pop   */
                    /* ==> push <arg1> * <arg2> onto T1 stack */
                    if (arg_cnt != 2)
                        return 160;

                    tops[top] = FT_MulFix(tops[top], tops[top + 1]);

                    known_othersubr_result_cnt = 1;
                    break;

                case 23:
                    /* <arg1> <arg2> 2 23 callothersubr pop   */
                    /* ==> push <arg1> / <arg2> onto T1 stack */
                    if (arg_cnt != 2 || tops[top + 1] == 0)
                        return 160;

                    tops[top] = FT_DivFix(tops[top], tops[top + 1]);

                    known_othersubr_result_cnt = 1;
                    break;

                case 24:
                    /* <val> <idx> 2 24 callothersubr               */
                    /* ==> set BuildCharArray[cvi( <idx> )] = <val> */
                    var blend = decoder.blend;

                    if (arg_cnt != 2 || blend == null)
                        return 160;

                    var idx = (tops[top + 1] >> 16) & 0xFFFF;

                    if (idx < 0 || idx >= decoder.len_buildchar)
                        return 160;

                    decoder.buildchar[idx] = tops[top];

                    break;

                case 25:
                    /* <idx> 1 25 callothersubr pop        */
                    /* ==> push BuildCharArray[cvi( idx )] */
                    /*     onto T1 stack                   */
                    var blend = decoder.blend;

                    if (arg_cnt != 1 || blend == null)
                        return 160;

                    idx = (tops[top] >> 16) & 0xFFFF;

                    if (idx < 0 || idx >= decoder.len_buildchar)
                        return 160;

                    tops[top] = decoder.buildchar[idx];

                    known_othersubr_result_cnt = 1;
                    break;

                case 27:
                    /* <res1> <res2> <val1> <val2> 4 27 callothersubr pop */
                    /* ==> push <res1> onto T1 stack if <val1> <= <val2>, */
                    /*     otherwise push <res2>                          */
                    if (arg_cnt != 4)
                        return 160;

                    if (tops[top + 2] > tops[top + 3])
                        tops[top] = tops[top + 1];

                    known_othersubr_result_cnt = 1;
                    break;

                case 28:
                    /* 0 28 callothersubr pop                               */
                    /* => push random value from interval [0, 1) onto stack */
                    if (arg_cnt != 0)
                        return 160;

                    var Rand = seed;
                    if (Rand >= 0x8000)
                        Rand++;

                    tops[top] = Rand;

                    seed = FT_MulFix(seed, 0x10000 - seed);
                    if (seed == 0)
                        seed += 0x2873;

                    known_othersubr_result_cnt = 1;
                    break;

                default:
                    if (arg_cnt >= 0 && subr_no >= 0)
                    {
                        unknown_othersubr_result_cnt = arg_cnt;
                        break;
                    }
                    /* fall through */

                    return 160;
            }

            top += known_othersubr_result_cnt;
            decoder.top = top;
        }
        else  /* general operator */
        {
            var num_args = t1_args_count[op];

            if (top < num_args)
                return 130;

            /* XXX Operators usually take their operands from the        */
            /*     bottom of the stack, i.e., the operands are           */
            /*     decoder->stack[0], ..., decoder->stack[num_args - 1]; */
            /*     only div, callsubr, and callothersubr are different.  */
            /*     In practice it doesn't matter (?).                    */

            top -= num_args;

            switch (op)
            {
                case 1:

                    t1_builder_close_contour(builder);

                    /* close hints recording session */
                    if (hinter != null)
                    {
                        if (hinter.close(hinter.hints, builder.current.n_points))
                            return 160;

                        /* apply hints to the loaded glyph outline now */
                        hinter.apply(hinter.hints, builder.current, builder.hints_globals, decoder.hint_mode);
                    }

                    /* add current outline to the glyph slot */
                    FT_GlyphLoader_Add(builder.loader);

                    /* the compiler should optimize away this empty loop but ... */
                    /* return now! */
                    return 0;

                case 2:
                    builder.parse_state = 1;

                    builder.left_bearing.x += tops[top];
                    builder.advance.x       = tops[top + 1];
                    builder.advance.y       = 0;

                    orig_x = x = builder.pos_x + tops[top];
                    orig_y = y = builder.pos_y;

                    /* the `metrics_only' indicates that we only want to compute */
                    /* the glyph's metrics (lsb + advance width), not load the   */
                    /* rest of it; so exit immediately                           */
                    if (builder.metrics_only)
                        return 0;

                    break;

                case 3:
                    return t1operator_seac(decoder, tops[top], tops[top + 1], tops[top + 2],
                        (tops[top + 3] >> 16) & 0xFFFF, (tops[top + 4] >> 16) & 0xFFFF);

                case 4:
                    builder.parse_state = 1;

                    builder.left_bearing.x += tops[top];
                    builder.left_bearing.y += tops[top + 1];
                    builder.advance.x       = tops[top + 2];
                    builder.advance.y       = tops[top + 3];

                    x = builder.pos_x + tops[top];
                    y = builder.pos_y + tops[top + 1];

                    /* the `metrics_only' indicates that we only want to compute */
                    /* the glyph's metrics (lsb + advance width), not load the   */
                    /* rest of it; so exit immediately                           */
                    if (builder.metrics_only)
                        return 0;

                    break;

                case 5:
                    /* if there is no path, `closepath' is a no-op */
                    if (builder.parse_state == 3 || builder.parse_state == 2)
                        t1_builder_close_contour(builder);

                    builder.parse_state = 1;
                    break;

                case 6:

                    error = t1_builder_start_point(builder, x, y);
                    if (error != 0)
                        return error;

                    x += tops[top];
                    error = t1_builder_add_point1(builder, x, y);
                    if (error != 0)
                        return error;

                    break;

                case 7:
                    x += tops[top];
                    if (decoder.flex_state == 0)
                    {
                        if (builder.parse_state == 0)
                            return 160;
                        builder.parse_state = 2;
                    }
                    break;

                case 8:

                    error = t1_builder_start_point(builder, x, y);
                    if (error != 0)
                        return error;
                    error = t1_builder_check_points(builder, 3);
                    if (error != 0)
                        return error;

                    x += tops[top];
                    t1_builder_add_point(builder, x, y, 0);
                    x += tops[top + 1];
                    y += tops[top + 2];
                    t1_builder_add_point(builder, x, y, 0);
                    y += tops[top + 3];
                    t1_builder_add_point(builder, x, y, 1);
                    break;

                case 9:
                    error = t1_builder_start_point(builder, x, y);
                    if (error != 0)
                        return error;

                    x += tops[top];
                    y += tops[top + 1];

                    error = t1_builder_add_point1(builder, x, y);
                    if (error != 0)
                        return error;

                    break;

                case 10:
                    x += tops[top];
                    y += tops[top + 1];
                    if (decoder.flex_state == 0)
                    {
                        if (builder.parse_state == 0)
                            return 160;
                        builder.parse_state = 2;
                    }
                    break;

                case 11:

                    error = t1_builder_start_point(builder, x, y);
                    if (error != 0)
                        return error;
                    error = t1_builder_check_points(builder, 3);
                    if (error != 0)
                        return error;

                    x += tops[top];
                    y += tops[top + 1];
                    t1_builder_add_point(builder, x, y, 0);

                    x += tops[top + 2];
                    y += tops[top + 3];
                    t1_builder_add_point(builder, x, y, 0);

                    x += tops[top + 4];
                    y += tops[top + 5];
                    t1_builder_add_point(builder, x, y, 1);
                    break;

                case 12:
                    error = t1_builder_start_point(builder, x, y);
                    if (error != 0)
                        return error;
                    error = t1_builder_check_points(builder, 3);
                    if (error != 0)
                        return error;

                    y += tops[top];
                    t1_builder_add_point(builder, x, y, 0);
                    x += tops[top + 1];
                    y += tops[top + 2];
                    t1_builder_add_point(builder, x, y, 0);
                    x += tops[top + 3];
                    t1_builder_add_point(builder, x, y, 1);
                    break;

                case 13:
                    error = t1_builder_start_point(builder, x, y);
                    if (error != 0)
                        return error;

                    y += tops[top];
                    error = t1_builder_add_point1(builder, x, y);
                    if (error != 0)
                        return error;
                    break;

                case 14:
                    y += tops[top];
                    if (decoder.flex_state == 0)
                    {
                        if (builder.parse_state == 0)
                            return 160;
                        builder.parse_state = 2;
                    }
                    break;

                case 20:
                    /* if `large_int' is set, we divide unscaled numbers; */
                    /* otherwise, we divide numbers in 16.16 format --    */
                    /* in both cases, it is the same operation            */
                    tops[top] = FT_DivFix(tops[top], tops[top + 1]);
                    ++top;

                    large_int = 0;
                    break;

                case 22:
                {
                    var idx = (tops[top] >> 16) & 0xFFFF;
                    if (idx < 0 || idx >= decoder.num_subrs)
                        return 160;

                    if (zone >= 16)
                        return 160;

                    zones[zone].cursor = dublicate_pointer(ip);  /* save current instruction pointer */
                    zone++;

                    /* The Type 1 driver stores subroutines without the seed bytes. */
                    /* The CID driver stores subroutines with seed bytes.  This     */
                    /* case is taken care of when decoder->subrs_len == 0.          */
                    zones[zone].base = dublicate_pointer(decoder.subrs[idx]);

                    if (decoder.subrs_len != 0)
                        zones[zone].limit = zones[zone].base.pos + decoder.subrs_len[idx];
                    else
                    {
                        /* We are using subroutines from a CID font.  We must adjust */
                        /* for the seed bytes.                                       */
                        zones[zone].base.pos  += (decoder.lenIV >= 0 ? decoder.lenIV : 0);
                        zones[zone].limit = decoder.subrs[idx + 1].pos;
                    }

                    zones[zone].cursor = dublicate_pointer(zones[zone].base);

                    if (zones[zone].base == null)
                        return 160;

                    decoder.zone = zone;
                    ip           = dublicate_pointer(zones[zone].base);
                    limit        = zones[zone].limit;
                    break;
                }

                case 23:

                    if (known_othersubr_result_cnt > 0)
                    {
                        known_othersubr_result_cnt--;
                        /* ignore, we pushed the operands ourselves */
                        break;
                    }

                    if (unknown_othersubr_result_cnt == 0)
                        return 160;

                    unknown_othersubr_result_cnt--;
                    top++;   /* `push' the operand to callothersubr onto the stack */
                    break;

                case 24:

                    if (zone <= 0)
                        return 160;

                    zone--;
                    ip           = dublicate_pointer(zones[zone].cursor);
                    limit        = zones[zone].limit;
                    decoder.zone = zone;
                    break;

                case 15:
                    break;

                case 16:
                    /* record horizontal hint */
                    if (hinter != null)
                    {
                        /* tops[0] += builder->left_bearing.y; */
                        hinter.stem(hinter.hints, 1, tops, top);
                    }
                    break;

                case 17:
                    /* record horizontal counter-controlled hints */
                    if (hinter != null)
                        hinter.stem3(hinter.hints, 1, tops, top);
                    break;

                case 18:
                    /* record vertical hint */
                    if (hinter != null)
                    {
                        tops[top] += orig_x;
                        hinter.stem(hinter.hints, 0, tops, top);
                    }
                    break;

                case 19:
                    /* record vertical counter-controlled hints */
                    if (hinter != null)
                    {
                        tops[top] += orig_x;
                        tops[top + 2] += orig_x;
                        tops[top + 4] += orig_x;
                        hinter.stem3(hinter.hints, 0, tops, top);
                    }
                    break;

                case 25:
                    /* From the T1 specification, section 6.4:                */
                    /*                                                        */
                    /*   The setcurrentpoint command is used only in          */
                    /*   conjunction with results from OtherSubrs procedures. */

                    /* known_othersubr_result_cnt != 0 is already handled     */
                    /* above.                                                 */

                    /* Note, however, that both Ghostscript and Adobe         */
                    /* Distiller handle this situation by silently ignoring   */
                    /* the inappropriate `setcurrentpoint' instruction.  So   */
                    /* we do the same.                                        */
                    x = tops[top];
                    y = tops[top + 1];
                    decoder.flex_state = 0;
                    break;

                case 26:
                    /* nothing to do except to pop the two arguments */
                    break;

                default:
                    return 160;
            }

            /* XXX Operators usually clear the operand stack;  */
            /*     only div, callsubr, callothersubr, pop, and */
            /*     return are different.                       */
            /*     In practice it doesn't matter (?).          */

            decoder.top = top;

        } /* general operator processing */

    } /* while ip < limit */

    return error;
}

function t1_decoder_parse_glyph(decoder, glyph)
{
    return decoder.parse_callback(decoder, glyph);
}

function t1_decoder_init(decoder, face, size, slot, glyph_names, blend, hinting, hint_mode, parse_callback)
{
    decoder.clear();

    var psnames = FT_FACE_FIND_GLOBAL_SERVICE(face, FT_SERVICE_ID_POSTSCRIPT_CMAPS);
    if (psnames == null)
        return 7;

    decoder.psnames = psnames;

    t1_builder_init(decoder.builder, face, size, slot, hinting);

    /* decoder->buildchar and decoder->len_buildchar have to be  */
    /* initialized by the caller since we cannot know the length */
    /* of the BuildCharArray                                     */
    decoder.num_glyphs     = face.num_glyphs;
    decoder.glyph_names    = glyph_names;
    decoder.hint_mode      = hint_mode;
    decoder.blend          = blend;
    decoder.parse_callback = parse_callback;

    decoder.funcs          = t1_decoder_funcs;

    return 0;
}

function t1_decoder_done(decoder)
{
    t1_builder_done(decoder.builder);
}


/******************************************************************************/
// psaux
/******************************************************************************/
function PS_Table_FuncsRec(_init, _done, _add, _release)
{
    this.init       = _init;
    this.done       = _done;
    this.add        = _add;
    this.release    = _release;
}

function PS_TableRec()
{
    this.block = null;
    this.cursor = 0;
    this.capacity = 0;
    this.init = 0;

    this.max_elems = 0;
    this.num_elems = 0;
    this.elements = null;
    this.lengths = null;

    this.memory = null;
    this.funcs = new PS_Table_FuncsRec(null, null, null, null);

    this.clear = function()
    {
        this.block = null;
        this.cursor = 0;
        this.capacity = 0;
        this.init = 0;

        this.max_elems = 0;
        this.num_elems = 0;
        this.elements = null;
        this.lengths = null;

        this.memory = null;
        this.funcs = new PS_Table_FuncsRec(null, null, null, null);
    }
}

function T1_TokenRec()
{
    this.start = new CPointer();
    this.limit = 0;
    this.type = 0;
}

function T1_FieldRec()
{
    this.ident = "";
    this.location = 0;
    this.type = 0;
    this.reader = null;
    this.offset = 0; // у нас это просто индекс члена класса. А не сдвиг в памяти
    this.size = 0;
    this.array_max = 0;

    this.count_offset = 0;
    this.dict = 0;

    this.set_field = null;
    this.set_field_count = null;
}

function create_dublicate_t1_field(_field)
{
    var ret = new T1_FieldRec();

    ret.ident = _field.ident;
    ret.location = _field.location;
    ret.type = _field.type;
    ret.reader = _field.reader;
    ret.offset = _field.offset; // у нас это просто индекс в МАССИВЕ (т.е. для не массива это поле не нужно)
    ret.size = _field.size;     // не пользуем (на будущее оставим)
    ret.array_max = _field.array_max;

    ret.count_offset = _field.count_offset;
    ret.dict = _field.dict;

    ret.set_field = _field.set_field;
    ret.set_field_count = _field.set_field_count;

    return ret;
}

function fire_t1_field(obj, val, f)
{
    f.set_field(obj, val, f);
}
function fire_t1_field_count(obj, val, f)
{
    f.set_field_count(obj, val, f);
}

function create_t1_field(_ident, _location, _type, _reader, _offset, _size, _array_max, _count_offset, _dict, func_set_field, func_set_field_count)
{
    var ret = new T1_FieldRec();
    ret.ident = _ident;
    ret.location = _location;
    ret.type = _type;
    ret.reader = _reader;
    ret.offset = _offset;
    ret.size = _size;
    ret.array_max = _array_max;
    ret.count_offset = _count_offset;
    ret.dict = _dict;

    ret.set_field = func_set_field;
    ret.set_field_count = func_set_field_count;

    return ret;
}
function create_t1_field2(_ident, _location, _type, func_set_field, func_set_field_count)
{
    var ret = new T1_FieldRec();
    ret.ident = _ident;
    ret.location = _location;
    ret.type = _type;

    ret.set_field = func_set_field;
    ret.set_field_count = func_set_field_count;

    return ret;
}
function create_t1_field4(_ident, _location, _type, _dict, func_set_field, func_set_field_count)
{
    var ret = new T1_FieldRec();
    ret.ident = _ident;
    ret.location = _location;
    ret.type = _type;
    ret.dict = _dict;

    ret.set_field = func_set_field;
    ret.set_field_count = func_set_field_count;

    return ret;
}
function create_t1_field3(_ident, _location, _type, _max, func_set_field, func_set_field_count)
{
    var ret = new T1_FieldRec();
    ret.ident = _ident;
    ret.location = _location;
    ret.type = _type;
    ret.array_max = _max;

    ret.set_field = func_set_field;
    ret.set_field_count = func_set_field_count;

    return ret;
}
function create_t1_field5(_ident, _location, _type, _max, _dict, func_set_field, func_set_field_count)
{
    var ret = new T1_FieldRec();
    ret.ident = _ident;
    ret.location = _location;
    ret.type = _type;
    ret.array_max = _max;
    ret.dict = _dict;

    ret.set_field = func_set_field;
    ret.set_field_count = func_set_field_count;

    return ret;
}

function PS_Parser_FuncsRec(_init,_done,_skip_spaces,_skip_PS_token,_to_int,_to_fixed,_to_bytes,_to_coord_array,_to_fixed_array,
                            _to_token,_to_token_array,_load_field,_load_field_table)
{
    this.init = _init;
    this.done = _done;

    this.skip_spaces    = _skip_spaces;
    this.skip_PS_token  = _skip_PS_token;

    this.to_int         = _to_int;
    this.to_fixed       = _to_fixed;
    this.to_bytes       = _to_bytes;
    this.to_coord_array = _to_coord_array;
    this.to_fixed_array = _to_fixed_array;
    this.to_token       = _to_token;
    this.to_token_array = _to_token_array;
    this.load_field     = _load_field;
    this.load_field_table = _load_field_table;
}

function T1_Builder_FuncsRec(_init,_done,_check_points,_add_point,_add_point1,_add_contour,_start_point,_close_contour)
{
    this.init = _init;
    this.done = _done;

    this.check_points   = _check_points;
    this.add_point      = _add_point;
    this.add_point1     = _add_point1;
    this.add_contour    = _add_contour;
    this.start_point    = _start_point;
    this.close_contour  = _close_contour;
}

function PS_ParserRec()
{
    this.cursor = 0;
    this.base = null;
    this.limit = 0;
    this.error = 0;
    this.memory = null;

    this.funcs = null;

    this.clear = function()
    {
        this.cursor = 0;
        this.base = null;
        this.limit = 0;
        this.error = 0;
        this.memory = null;

        this.funcs = null;
    }
}

function T1_BuilderRec()
{
    this.memory = null;
    this.face = null;
    this.glyph = null;
    this.loader = null;
    this.base = null;
    this.current = null;

    this.pos_x = 0;
    this.pos_y = 0;

    this.left_bearing = new FT_Vector();
    this.advance = new FT_Vector();

    this.bbox = new FT_BBox();
    this.parse_state = 0;
    this.load_points = 0;
    this.no_recurse = 0;

    this.metrics_only = 0;

    this.hints_funcs = null;
    this.hints_globals = null;

    this.funcs = null;

    this.clear = function()
    {
        this.memory = null;
        this.face = null;
        this.glyph = null;
        this.loader = null;
        this.base = null;
        this.current = null;

        this.pos_x = 0;
        this.pos_y = 0;

        this.left_bearing.x = 0;
        this.left_bearing.y = 0;
        this.advance.x = 0;
        this.advance.y = 0;

        this.bbox.xMin = 0;
        this.bbox.yMin = 0;
        this.bbox.xMax = 0;
        this.bbox.yMax = 0;

        this.parse_state = 0;
        this.load_points = 0;
        this.no_recurse = 0;

        this.metrics_only = 0;

        this.hints_funcs = null;
        this.hints_globals = null;

        this.funcs = null;
    }
}

function T1_Decoder_ZoneRec()
{
    this.cursor = 0;
    this.base = null;
    this.limit = 0;
}

function T1_Decoder_FuncsRec(_init, _done, _parse_charstrings)
{
    this.init = _init;
    this.done = _done;
    this.parse_charstrings = _parse_charstrings;
}

function T1_DecoderRec()
{
    this.builder = new T1_BuilderRec();

    this.stack = CreateIntArray(256);
    this.top = 0;

    this.zones = new Array(16 + 1);
    for (var i = 0; i <= 16; i++)
        this.zones[i] = new T1_Decoder_ZoneRec();

    this.zone = 0;

    this.psnames = null;
    this.num_glyphs = 0;
    this.glyph_names = null;

    this.lenIV = 0;
    this.num_subrs = 0;
    this.subrs = null;
    this.subrs_len = null;

    this.font_matrix = new FT_Matrix();
    this.font_offset = new FT_Vector();

    this.flex_state = 0;
    this.num_flex_vectors = 0;
    this.flex_vectors = new Array(7);
    for (var i = 0; i < 7; i++)
        this.flex_vectors[i] = new FT_Vector();

    this.blend = null;

    this.hint_mode = 0;

    this.parse_callback = null;
    this.funcs = null;

    this.buildchar = null;
    this.len_buildchar = 0;

    this.seac = 0;

    this.clear = function()
    {
        this.builder.clear();

        for (var i = 0; i < 256; i++)
            this.stack[i] = 0;

        this.top = 0;

        for (var i = 0; i <= 16; i++)
        {
            var _z = this.zones[i];
            _z.base = null;
            _z.cursor = 0;
            _z.limit = 0;
        }
        this.zone = 0;

        this.psnames = null;
        this.num_glyphs = 0;
        this.glyph_names = null;

        this.lenIV = 0;
        this.num_subrs = 0;
        this.subrs = null;
        this.subrs_len = null;

        this.font_matrix.xx = 0;
        this.font_matrix.xy = 0;
        this.font_matrix.yx = 0;
        this.font_matrix.yy = 0;

        this.font_offset.x = 0;
        this.font_offset.y = 0;

        this.flex_state = 0;
        this.num_flex_vectors = 0;
        for (var i = 0; i < 7; i++)
        {
            this.flex_vectors[i].x = 0;
            this.flex_vectors[i].y = 0;
        }

        this.blend = null;

        this.hint_mode = 0;

        this.parse_callback = null;
        this.funcs = null;

        this.buildchar = null;
        this.len_buildchar = 0;

        this.seac = 0;
    }
}

var ps_table_funcs = {
    init : ps_table_new,
    done : ps_table_done,
    add : ps_table_add,
    release : ps_table_release
};

var ps_parser_funcs = {
    init : ps_parser_init,
    done : ps_parser_done,
    skip_spaces : ps_parser_skip_spaces,
    skip_PS_token : ps_parser_skip_PS_token,
    to_int : ps_parser_to_int,
    to_fixed : ps_parser_to_fixed,
    to_bytes : ps_parser_to_bytes,
    to_coord_array : ps_parser_to_coord_array,
    to_fixed_array : ps_parser_to_fixed_array,
    to_token : ps_parser_to_token,
    to_token_array : ps_parser_to_token_array,
    load_field : ps_parser_load_field,
    load_field_table : ps_parser_load_field_table
};

var t1_builder_funcs = {
    init : t1_builder_init,
    done : t1_builder_done,
    check_points : t1_builder_check_points,
    add_point : t1_builder_add_point,
    add_point1 : t1_builder_add_point1,
    add_contour : t1_builder_add_contour,
    start_point : t1_builder_start_point,
    close_contour : t1_builder_close_contour
};

var t1_decoder_funcs = {
    init : t1_decoder_init,
    done : t1_decoder_done,
    parse_charstrings : t1_decoder_parse_charstrings
};

var afm_parser_funcs = {
    init : afm_parser_init,
    done : afm_parser_done,
    parse : afm_parser_parse
};

var t1_cmap_classes = {
    standard : t1_cmap_standard_class_rec,
    expert : t1_cmap_expert_class_rec,
    custom : t1_cmap_custom_class_rec,
    unicode : t1_cmap_unicode_class_rec
};

function PSAux_ServiceRec()
{
    this.ps_table_funcs = null;
    this.ps_parser_funcs = null;
    this.t1_builder_funcs = null;
    this.t1_decoder_funcs = null;

    this.t1_decrypt = null;

    this.t1_cmap_classes = null;

    this.afm_parser_funcs = null;
}

function create_psaux_interface(_table_funcs,_parser_funcs,_builder_funcs,_decoder_funcs,_decrypt,_cmap_classes,_afm_parser_funcs)
{
    var ret = new PSAux_ServiceRec();

    ret.ps_table_funcs = _table_funcs;
    ret.ps_parser_funcs = _parser_funcs;
    ret.t1_builder_funcs = _builder_funcs;
    ret.t1_decoder_funcs = _decoder_funcs;
    ret.t1_decrypt = _decrypt;
    ret.t1_cmap_classes = _cmap_classes;
    ret.afm_parser_funcs = _afm_parser_funcs;

    return ret;
}
var psaux_interface = create_psaux_interface(ps_table_funcs,ps_parser_funcs,t1_builder_funcs,t1_decoder_funcs, t1_decrypt, t1_cmap_classes, afm_parser_funcs);

function create_psaux_module(library)
{
    var psaux_mod = new FT_Module();
    psaux_mod.clazz = new FT_Module_Class();

    var clazz = psaux_mod.clazz;
    clazz.flags = 0;
    clazz.name = "psaux";
    clazz.version = 0x20000;
    clazz.requires = 0x20000;

    clazz.module_interface = psaux_interface;
    clazz.init = null;
    clazz.done = null;

    clazz.get_interface = null;

    psaux_mod.library = library;
    psaux_mod.memory = library.Memory;
    psaux_mod.generic = null;

    return psaux_mod;
}

/******************************************************************************/
// bdf
/******************************************************************************/
function BDF_PropertyRec()
{
    this.type;
    this.u;
}

function tt_face_free_bdf_props(face)
{
    var bdf = face.bdf;
    if (bdf.loaded == 1)
    {
        bdf.table = null;
        bdf.table_end = 0;
        bdf.strings = null;
        bdf.strings_size = 0;
    }
}

function tt_face_load_bdf_props(face, stream)
{
    var bdf = face.bdf;
    var error = 0;

    bdf.table = null;
    bdf.table_end = 0;
    bdf.strings = null;
    bdf.strings_size = 0;
    bdf.num_strikes = 0;
    bdf.loaded = 0;

    var length = tt_face_goto_table(face, 1111770656, stream);
    error = FT_Error;
    if (error != 0 || length < 8)
        return 8;

    bdf.table = new CPointer();
    error = stream.ExtractFrame(length, bdf.table);

    if (error != 0)
        return 8;

    bdf.table_end = length;

    var p = dublicate_pointer(bdf.table);
    var version = FT_NEXT_USHORT(p);
    var num_strikes = FT_NEXT_USHORT(p);
    var strings = FT_NEXT_ULONG (p);

    if (version != 0x0001 || strings < 8  || (strings - 8) / 4 < num_strikes || strings + 1 > length)
    {
        bdf.table = null;
        return 8;
    }

    bdf.num_strikes = num_strikes;
    bdf.strings = new CPointer();
    bdf.strings.data = bdf.table.data;
    bdf.strings.pos = bdf.table.pos + strings;
    bdf.strings_size = length - strings;

    var count = bdf.num_strikes;
    p.pos = bdf.table.pos + 8;
    var strike = p.pos + count * 4;

    for ( ; count > 0; count--)
    {
        p.pos+=2;
        var num_items = FT_PEEK_USHORT(p);

        strike += 10 * num_items;
        p.pos+=2;
    }

    if (strike > bdf.strings)
    {
        bdf.table = null;
        bdf.table_end = 0;
        bdf.strings = null;
        bdf.strings_size = 0;
        bdf.num_strikes = 0;
        bdf.loaded = 0;
        return 8;
    }

    bdf.loaded = 1;
    return error;
}

function tt_face_find_bdf_prop(face,property_name,aprop)
{
    var bdf = face.bdf;
    var size = face.size;
    var error = 0;

    aprop.type = 0;

    if (bdf.loaded == 0)
    {
        error = tt_face_load_bdf_props(face, face.stream);
        if (error != 0)
            return error;
    }

    var count = bdf.num_strikes;
    var p = dublicate_pointer(bdf.table);
    p.pos += 8;

    var strike = dublicate_pointer(p);
    strike.pos += 4 * count;

    error = 6;

    var property_len = property_name.length;
    if (size == null || property_len == 0)
        return error;

    var is_strike = 0;
    for ( ; count > 0; count-- )
    {
        var _ppem  = FT_NEXT_USHORT(p);
        var _count = FT_NEXT_USHORT(p);

        if (_ppem == size.metrics.y_ppem)
        {
            count = _count;
            is_strike = 1;
            break;
        }

        strike.pos += 10 * _count;
    }
    if (0 == is_strike)
        return error;

    p.pos = strike.pos;
    var point = dublicate_pointer(bdf.strings);
    for (; count > 0; count--)
    {
        p.pos+=4;
        var type = FT_PEEK_USHORT(p);
        p.pos-=4;

        if ((type & 0x10) != 0)
        {
            var name_offset = FT_PEEK_ULONG(p);
            p.pos+=6;
            var value = FT_PEEK_ULONG(p);
            p.pos-=6;

            point.pos = bdf.strings.pos + name_offset;
            if (name_offset < bdf.strings_size && property_len < bdf.strings_size - name_offset &&
                        property_name == FT_PEEK_String1(point,bdf.strings_size-name_offset))
            {
                switch ( type & 0x0F )
                {
                    case 0x00:
                    case 0x01:
                        point.pos = bdf.strings.pos + value;
                        if (value < bdf.strings_size && -1 != ft_memchr(point, 0, bdf.strings_size))
                        {
                            aprop.type = 1;
                            aprop.u = FT_PEEK_String1(point,bdf.strings_size);
                            return 0;
                        }
                        break;

                    case 0x02:
                        aprop.type = 2;
                        aprop.u = ((value > 2147483647) ? value-4294967296 : value);
                        return 0;
                    case 0x03:
                        aprop.type = 3;
                        aprop.u = ((value >= 0) ? value : value + 2147483647);
                        return 0;
                    default:
                        break;
                }
            }
        }
        p.pos += 10;
    }

    return error;
}

function sfnt_get_charset_id(face,acharset_encoding,acharset_registry)
{
    var encoding = new BDF_PropertyRec();
    var registry = new BDF_PropertyRec();

    FT_Error = tt_face_find_bdf_prop(face, "CHARSET_REGISTRY", registry);
    if (FT_Error == 0)
    {
        FT_Error = tt_face_find_bdf_prop(face, "CHARSET_ENCODING", encoding);
        if (FT_Error == 0)
        {
            if (registry.type == 1 && encoding.type == 1)
            {
                return {enc:encoding.u,reg:registry.u};
            }
            else
                FT_Error = 6;
        }
    }

    return {enc:"",reg:""};
}
/******************************************************************************/
// ttkern
/******************************************************************************/
function tt_face_load_kern(face, stream)
{
    var error = 0;
    var table_size = face.goto_table(face, 1801810542, stream);
    error = FT_Error;

    if (error != 0)
        return error;

    if (table_size < 4)
        return 142;

    face.kern_table = new CPointer();
    error = stream.ExtractFrame(table_size, face.kern_table);
    if (error != 0)
        return error;

    face.kern_table_size = table_size;
    stream.cur = face.kern_table.pos;
    var p_limit = stream.cur + table_size;

    stream.cur += 2; // skip version
    var num_tables = stream.GetUShort();

    if (num_tables > 32)
        num_tables = 32;

    var avail = 0;
    var ordered = 0;

    var nn = 0;
    for (; nn < num_tables; nn++)
    {
        var mask = 1 << nn;

        var p_next = stream.cur;

        if (stream.cur + 6 < p_limit)
            break;

        stream.cur += 2; // skip version
        var length = stream.GetUShort();
        var coverage = stream.GetUShort();

        if (length <= 6)
            break;

        p_next += length;

        if (p_next > p_limit)
            p_next = p_limit;

        if ((coverage & ~8) != 0x0001 || (stream.cur + 8) > p_limit)
        {
            stream.cur = p_next;
            continue;
        }

        var num_pairs = stream.GetUShort();
        stream.cur += 6;

        if ((p_next - stream.cur) < (6 * num_pairs))
            num_pairs = parseInt((p_next - stream.cur) / 6);

        avail |= mask;

        if (num_pairs > 0)
        {
            var count = 0;
            var old_pair = stream.GetULong();

            stream.cur += 2;

            for (count = num_pairs - 1; count > 0; count--)
            {
                var cur_pair = stream.GetULong();
                if (cur_pair <= old_pair)
                    break;

                stream.cur += 2;
                old_pair = cur_pair;
            }

            if (count == 0)
                ordered |= mask;
        }

        stream.cur = p_next;
    }

    face.num_kern_tables = nn;
    face.kern_avail_bits = avail;
    face.kern_order_bits = ordered;

    return error;
}
function tt_face_done_kern(face)
{
    face.kern_table = null;
    face.kern_table_size = 0;
    face.num_kern_tables = 0;
    face.kern_avail_bits = 0;
    face.kern_order_bits = 0;
}
function tt_face_get_kerning(face,left_glyph,right_glyph)
{
    var result = 0;
    var count, mask = 1;
    var p = dublicate_pointer(face.kern_table);
    if (null == p)
        return result;

    var p_limit = p.pos + face.kern_table_size;

    p.pos += 4;
    mask = 0x0001;

    for (count = face.num_kern_tables; count > 0 && p.pos + 6 <= p_limit; count--, mask <<= 1)
    {
        if (mask < 0)
            mask+=4294967296;
        var version  = FT_NEXT_USHORT( p );
        var length   = FT_NEXT_USHORT( p );
        var coverage = FT_NEXT_USHORT( p );
        var value = 0;

        var base = p.pos;
        var next = base + length;

        if (next > p_limit)
            next = p_limit;

        if ((face.kern_avail_bits & mask) == 0)
        {
            p.pos = next;
            continue;
        }

        if (p.pos + 8 > next)
        {
            p.pos = next;
            continue;
        }

        var num_pairs = FT_NEXT_USHORT( p );
        p.pos += 6;

        if (( next - p.pos) < 6 * num_pairs)
            num_pairs = parseInt((next - p.pos)/6);

        switch (coverage >>> 8)
        {
            case 0:
            {
                var key0 = (left_glyph<<16 | right_glyph)&0xFFFFFFFF;
                if (key0 < 0)
                    key0 += 4294967296;

                if ((face.kern_order_bits & mask) != 0)
                {
                    var min = 0;
                    var max = num_pairs;

                    var q = dublicate_pointer(p);
                    var is_found = 0;
                    while ( min < max )
                    {
                        var mid = (min + max) >>> 1;
                        q.pos = p.pos + 6 * mid;
                        var key = FT_NEXT_ULONG(q);

                        if (key == key0)
                        {
                            value = FT_PEEK_SHORT( q );
                            if ((coverage & 8) != 0)
                                result = value;
                            else
                                result += value;
                            p.pos = next;
                            is_found = 1;
                            break;
                        }
                        if (key < key0)
                            min = mid + 1;
                        else
                            max = mid;
                    }
                    if (1 == is_found)
                        continue;
                }
                else
                {
                    var is_found = 0;
                    for (var count2 = num_pairs; count2 > 0; count2--)
                    {
                        var key = FT_NEXT_ULONG(p);

                        if (key == key0)
                        {
                            value = FT_PEEK_SHORT(p);
                            if ((coverage & 8) != 0)
                                result = value;
                            else
                                result += value;
                            p.pos = next;
                            is_found = 1;
                            break;
                        }
                        p.pos += 2;
                    }
                    if (is_found == 1)
                        continue;
                }
            }
            break;
        default:
            break;
        }
        p.pos = next;
    }

    return result;
}
/******************************************************************************/
// ttload
/******************************************************************************/
function tt_face_lookup_table(face, tag)
{
    var count = face.num_tables;
    for (var i=0; i<count; i++)
    {
        var entry = face.dir_tables[i];
        if (entry.Tag == tag && entry.Length != 0)
            return entry;
    }
    return null;
}
function tt_face_goto_table(face, tag, stream)
{
    var length = 0;
    var table = tt_face_lookup_table(face, tag);
    if (table != null)
    {
        length = table.Length;
        FT_Error = stream.Seek(table.Offset);
        return table.Length;
    }
    FT_Error = 142;
    return 0;
}
function check_table_dir(sfnt, stream)
{
    var error = 0;
    var nn = 0;
    var valid_entries = 0;
    var has_head = 0;
    var has_sing = 0;
    var has_meta = 0;
    var offset = sfnt.offset + 12;

    error = stream.Seek(offset);
    if (0 != error)
        return error;

    var num_t = sfnt.num_tables;
    for (nn = 0; nn < num_t; nn++)
    {
        error = stream.EnterFrame(16);
        if (error != 0)
        {
            nn--;
            sfnt.num_tables = nn;
            break;
        }

        var Tag = stream.GetULong();
        var CheckSum = stream.GetULong();
        var Offset = stream.GetULong();
        var Length = stream.GetULong();

        stream.ExitFrame();

        if (Offset + Length > stream.size)
            continue;
        else
            valid_entries++;

        if (Tag == 1751474532 || Tag == 1651008868)
        {
            has_head = 1;
            if (Length < 0x36)
                return 142;

            error = stream.Seek(Offset + 12);
            if (error != 0)
                return error;

            var magic = stream.ReadULong();
            if (magic != 0x5F0F3CF5)
                return 142;

            error = stream.Seek(offset + (nn+1)*16);
            if (error != 0)
                return error;
        }
        else if (Tag == 1397313095)
            has_sing = 1;
        else if (Tag == 1296389185)
            has_meta = 1;
    }

    sfnt.num_tables = valid_entries;

    if (sfnt.num_tables == 0)
        return 2;

    if ((has_head == 1) || ((has_sing == 1) && (has_meta == 1)))
        return 0;
    else
        return 142;

    return error;
}
function tt_face_load_font_dir(face, stream)
{
    var sfnt = new SFNT_HeaderRec();
    var error = 0;

    sfnt.offset = stream.pos;
    sfnt.format_tag = stream.ReadULong();

    error = FT_Error;
    if (error != 0)
        return error;

    error = stream.EnterFrame(8);
    if (error != 0)
        return error;

    sfnt.num_tables = stream.GetUShort();
    sfnt.search_range = stream.GetUShort();
    sfnt.entry_selector = stream.GetUShort();
    sfnt.range_shift = stream.GetUShort();

    stream.ExitFrame();

    error = check_table_dir(sfnt, stream);
    if (0 != error)
        return error;

    face.num_tables = sfnt.num_tables;
    face.format_tag = sfnt.format_tag;

    face.dir_tables = new Array(face.num_tables);
    for (var dtNum = 0; dtNum < face.num_tables; dtNum++)
        face.dir_tables[dtNum] = new TT_Table();

    error = stream.Seek(sfnt.offset + 12);
    if (0 == error)
    {
        error = stream.EnterFrame(face.num_tables * 16);
    }
    if (0 != error)
        return error;

    var cur = 0;
    for (var nn = 0; nn < sfnt.num_tables; nn++ )
    {
        var entry = face.dir_tables[cur];
        entry.Tag      = stream.GetULong();
        entry.CheckSum = stream.GetULong();
        entry.Offset   = stream.GetLong();
        entry.Length   = stream.GetLong();

        /* ignore invalid tables */
        if (entry.Offset + entry.Length > stream.size)
            continue;
        cur++;
    }

    stream.ExitFrame();
    return error;
}
function tt_face_load_any(face,tag,offset,buffer,length)
{
    var error = 0;
    var table;
    var size;

    if (tag != 0)
    {
        table = tt_face_lookup_table(face, tag);
        if (null == table)
            return 142;

        offset += table.Offset;
        size = table.Length;
    }
    else
    {
        size = face.stream.size;
    }

    if (length == 0)
    {
        FT_Error = 0;
        return size;
    }

    if (null != length)
        size = length;

    error = face.stream.ReadAt(offset,buffer,size);
    FT_Error = error;
    return size;
}
function tt_face_load_generic_header(face, stream, tag)
{
    var error = 0;
    face.goto_table(face, tag, stream);
    error = FT_Error;
    if (error != 0)
        return error;

    error = stream.EnterFrame(54);
    if (error != 0)
        return error;

    var header = face.header;

    header.Table_Version = stream.GetULong();
    header.Font_Revision = stream.GetULong();
    header.CheckSum_Adjust = stream.GetLong();
    header.Magic_Number = stream.GetLong();
    header.Flags = stream.GetUShort();
    header.Units_Per_EM = stream.GetUShort();
    header.Created1 = stream.GetLong();
    header.Created2 = stream.GetLong();
    header.Modified1 = stream.GetLong();
    header.Modified2 = stream.GetLong();
    header.xMin = stream.GetShort();
    header.yMin = stream.GetShort();
    header.xMax = stream.GetShort();
    header.yMax = stream.GetShort();
    header.Mac_Style = stream.GetUShort();
    header.Lowest_Rec_PPEM = stream.GetUShort();
    header.Font_Direction = stream.GetShort();
    header.Index_To_Loc_Format = stream.GetShort();
    header.Glyph_Data_Format = stream.GetShort();

    stream.ExitFrame();

    return error;
}
function tt_face_load_head(face, stream)
{
    return tt_face_load_generic_header(face, stream, 1751474532);
}
function tt_face_load_bhed(face, stream)
{
    return tt_face_load_generic_header(face, stream, 1651008868);
}
function tt_face_load_maxp(face, stream)
{
    var error = 0;
    face.goto_table(face, 1835104368, stream);
    error = FT_Error;
    if (error != 0)
        return error;

    error = stream.EnterFrame(6);
    if (error != 0)
        return error;

    var maxProfile = face.max_profile;
    maxProfile.version = stream.GetLong();
    maxProfile.numGlyphs = stream.GetUShort();
    stream.ExitFrame();

    maxProfile.maxPoints             = 0;
    maxProfile.maxContours           = 0;
    maxProfile.maxCompositePoints    = 0;
    maxProfile.maxCompositeContours  = 0;
    maxProfile.maxZones              = 0;
    maxProfile.maxTwilightPoints     = 0;
    maxProfile.maxStorage            = 0;
    maxProfile.maxFunctionDefs       = 0;
    maxProfile.maxInstructionDefs    = 0;
    maxProfile.maxStackElements      = 0;
    maxProfile.maxSizeOfInstructions = 0;
    maxProfile.maxComponentElements  = 0;
    maxProfile.maxComponentDepth     = 0;

    if (maxProfile.version >= 0x10000)
    {
        error = stream.EnterFrame(26);
        if (error != 0)
            return error;

        maxProfile.maxPoints             = stream.GetUShort();
        maxProfile.maxContours           = stream.GetUShort();
        maxProfile.maxCompositePoints    = stream.GetUShort();
        maxProfile.maxCompositeContours  = stream.GetUShort();
        maxProfile.maxZones              = stream.GetUShort();
        maxProfile.maxTwilightPoints     = stream.GetUShort();
        maxProfile.maxStorage            = stream.GetUShort();
        maxProfile.maxFunctionDefs       = stream.GetUShort();
        maxProfile.maxInstructionDefs    = stream.GetUShort();
        maxProfile.maxStackElements      = stream.GetUShort();
        maxProfile.maxSizeOfInstructions = stream.GetUShort();
        maxProfile.maxComponentElements  = stream.GetUShort();
        maxProfile.maxComponentDepth     = stream.GetUShort();

        if (maxProfile.maxFunctionDefs < 64)
            maxProfile.maxFunctionDefs = 64;

        /* we add 4 phantom points later */
        if (maxProfile.maxTwilightPoints > (0xFFFF - 4))
            maxProfile.maxTwilightPoints = 0xFFFF - 4;

        /* we arbitrarily limit recursion to avoid stack exhaustion */
        if (maxProfile.maxComponentDepth > 100)
            maxProfile.maxComponentDepth = 100;

        stream.ExitFrame();
    }
    return error;
}
function tt_face_load_name(face, stream)
{
    var error = 0;
    var table_pos = 0;
    var table_len = 0;
    var storage_start = 0;
    var storage_limit = 0;
    var count = 0;

    table_len = face.goto_table(face, 1851878757, stream);
    error = FT_Error;
    if (error != 0)
        return error;

    var table = face.name_table;
    table.stream = stream;

    table_pos = stream.pos;

    error = stream.EnterFrame(6);
    if (error != 0)
        return error;

    table.format = stream.GetUShort();
    table.numNameRecords = stream.GetUShort();
    table.storageOffset = stream.GetUShort();

    stream.ExitFrame();

    storage_start = table_pos + 6 + 12*table.numNameRecords;
    storage_limit = table_pos + table_len;

    if (storage_start > storage_limit)
        return 145;

    /* Allocate the array of name records. */
    count = table.numNameRecords;
    table.numNameRecords = 0;

    table.names = new Array(count);

    error = stream.EnterFrame(count * 12);
    for (; count > 0; count--)
    {
        var entry = new TT_NameEntryRec();
        entry.platformID = stream.GetUShort();
        entry.encodingID = stream.GetUShort();
        entry.languageID = stream.GetUShort();
        entry.nameID = stream.GetUShort();
        entry.stringLength = stream.GetUShort();
        entry.stringOffset = stream.GetUShort();

        if (entry.stringLength == 0)
            continue;

        entry.stringOffset += (table_pos + table.storageOffset);
        if (entry.stringOffset < storage_start || (entry.stringOffset + entry.stringLength) > storage_limit)
            continue;

        table.names[table.numNameRecords] = entry;
        table.numNameRecords++;
    }

    stream.ExitFrame();

    /* everything went well, update face->num_names */
    face.num_names = table.numNameRecords;
    return error;
}
function tt_face_free_name(face)
{
    face.name_table.names = null;
    var table = face.num_table;
    table.names = null;
    table.numNameRecords = 0;
    table.format         = 0;
    table.storageOffset  = 0;
}
function tt_face_load_cmap(face, stream)
{
    face.cmap_size = face.goto_table(face, 1668112752, stream);
    if (FT_Error != 0)
        return FT_Error;

    face.cmap_table = new CPointer();
    var error = stream.ExtractFrame(face.cmap_size, face.cmap_table);
    if (error != 0)
    {
        face.cmap_size = 0;
        face.cmap_table = null;
    }
    return error;
}
function tt_face_load_os2(face, stream)
{
    var error = 0;

    var os2 = face.os2;

    face.goto_table(face, 1330851634, stream);
    if (error != 0)
        return error;

    error = stream.EnterFrame(78);
    if (error != 0)
        return error;

    os2.version = stream.GetUShort();
    os2.xAvgCharWidth = stream.GetShort();
    os2.usWeightClass = stream.GetUShort();
    os2.usWidthClass = stream.GetUShort();
    os2.fsType = stream.GetShort();
    os2.ySubscriptXSize = stream.GetShort();
    os2.ySubscriptYSize = stream.GetShort();
    os2.ySubscriptXOffset = stream.GetShort();
    os2.ySubscriptYOffset = stream.GetShort();
    os2.ySuperscriptXSize = stream.GetShort();
    os2.ySuperscriptYSize = stream.GetShort();
    os2.ySuperscriptXOffset = stream.GetShort();
    os2.ySuperscriptYOffset = stream.GetShort();
    os2.yStrikeoutSize = stream.GetShort();
    os2.yStrikeoutPosition = stream.GetShort();
    os2.sFamilyClass = stream.GetShort();

    os2.panose = new Array(10);
    os2.panose[0] = stream.GetUChar();
    os2.panose[1] = stream.GetUChar();
    os2.panose[2] = stream.GetUChar();
    os2.panose[3] = stream.GetUChar();
    os2.panose[4] = stream.GetUChar();
    os2.panose[5] = stream.GetUChar();
    os2.panose[6] = stream.GetUChar();
    os2.panose[7] = stream.GetUChar();
    os2.panose[8] = stream.GetUChar();
    os2.panose[9] = stream.GetUChar();

    os2.ulUnicodeRange1 = stream.GetULong();
    os2.ulUnicodeRange2 = stream.GetULong();
    os2.ulUnicodeRange3 = stream.GetULong();
    os2.ulUnicodeRange4 = stream.GetULong();

    os2.achVendID = new Array(4);
    os2.achVendID[0] = stream.GetUChar();
    os2.achVendID[1] = stream.GetUChar();
    os2.achVendID[2] = stream.GetUChar();
    os2.achVendID[3] = stream.GetUChar();

    os2.fsSelection = stream.GetUShort();
    os2.usFirstCharIndex = stream.GetUShort();
    os2.usLastCharIndex = stream.GetUShort();
    os2.sTypoAscender = stream.GetShort();
    os2.sTypoDescender = stream.GetShort();
    os2.sTypoLineGap = stream.GetShort();
    os2.usWinAscent = stream.GetUShort();
    os2.usWinDescent = stream.GetUShort();

    os2.ulCodePageRange1 = 0;
    os2.ulCodePageRange2 = 0;
    os2.sxHeight         = 0;
    os2.sCapHeight       = 0;
    os2.usDefaultChar    = 0;
    os2.usBreakChar      = 0;
    os2.usMaxContext     = 0;

    stream.ExitFrame();

    if (os2.version >= 0x0001)
    {
        error = stream.EnterFrame(8);
        if (error != 0)
            return error;

        os2.ulCodePageRange1 = stream.GetULong();
        os2.ulCodePageRange2 = stream.GetULong();

        if (os2.version >= 0x0002)
        {
            error = stream.EnterFrame(10);
            if (error != 0)
                return error;

            os2.sxHeight         = stream.GetShort();
            os2.sCapHeight       = stream.GetShort();
            os2.usDefaultChar    = stream.GetUShort();
            os2.usBreakChar      = stream.GetUShort();
            os2.usMaxContext     = stream.GetUShort();
        }
    }

    return error;
}
function tt_face_load_post(face, stream)
{
    var error = 0;

    face.goto_table(face, 1886352244, stream);
    error = FT_Error;
    if (error != 0)
        return error;

    error = stream.EnterFrame(32);
    if (error != 0)
        return error;

    var post = face.postscript;
    post.FormatType = stream.GetLong();
    post.italicAngle = stream.GetLong();
    post.underlinePosition = stream.GetShort();
    post.underlineThickness = stream.GetShort();
    post.isFixedPitch = stream.GetULong();
    post.minMemType42 = stream.GetULong();
    post.maxMemType42 = stream.GetULong();
    post.minMemType1 = stream.GetULong();
    post.maxMemType1 = stream.GetULong();

    stream.ExitFrame();

    return error;
}
function tt_face_load_pclt(face, stream)
{
    var error = 0;
    var pclt = face.pclt;

    /* optional table */
    face.goto_table(face, 1346587732, stream);
	error = FT_Error;
    if (error != 0)
        return error;

    error = stream.EnterFrame(54);
    if (error != 0)
        return error;

    pclt.Version = stream.GetULong();
    pclt.FontNumber = stream.GetULong();
    pclt.Pitch = stream.GetUShort();
    pclt.xHeight = stream.GetUShort();
    pclt.Style = stream.GetUShort();
    pclt.TypeFamily = stream.GetUShort();
    pclt.CapHeight = stream.GetUShort();
    pclt.SymbolSet = stream.GetUShort();
    pclt.TypeFace = stream.GetString1(16);
    pclt.CharacterComplement = stream.GetString1(8);
    pclt.FileName = stream.GetString1(6);
    pclt.StrokeWeight = stream.GetChar();
    pclt.WidthType = stream.GetChar();
    pclt.SerifStyle = stream.GetUChar();
    pclt.Reserved = stream.GetUChar();

    stream.ExitFrame();
    return error;
}
function tt_face_load_gasp(face, stream)
{
    var error = 0;
    face.goto_table(face, 1734439792, stream);
    error = FT_Error;
    if (error != 0)
        return error;

    error = stream.EnterFrame(4);
    if (error != 0)
        return error;

    face.gasp.version   = stream.GetUShort();
    face.gasp.numRanges = stream.GetUShort();

    stream.ExitFrame();

    if (face.gasp.version >= 2)
    {
        face.gasp.numRanges = 0;
        return 8;
    }

    var num_ranges = face.gasp.numRanges;
    face.gasp.gaspRanges = new Array(num_ranges);
    var ranges = face.gasp.gaspRanges;

    error = stream.EnterFrame(num_ranges * 4);
    if (error != 0)
        return error;

    for (var i = 0; i < num_ranges; i++)
    {
        ranges[i] = new TT_GaspRange();
        ranges[i].maxPPEM = stream.GetUShort();
        ranges[i].gaspFlag = stream.GetUShort();
    }

    stream.ExitFrame();
    return error;
}
/******************************************************************************/
// ttmtx
/******************************************************************************/
function tt_face_load_hmtx(face, stream, isvertical)
{
    var error = 0;

    var table_len = 0;
    var num_shorts = 0;
    var num_longs = 0;
    var num_shorts_checked = 0;

    var lm = null;

    if (isvertical == 1)
    {
        table_len = face.goto_table(face, 1986884728, stream);
        error = FT_Error;
        if (error != 0)
            return error;

        num_longs = face.vertical.number_Of_VMetrics;
        if (num_longs > (table_len / 4))
            num_longs = parseInt(table_len / 4);

        face.vertical.number_Of_VMetrics = 0;

        lm = face.vertical;
    }
    else
    {
        table_len = face.goto_table(face, 1752003704, stream);
        error = FT_Error;
        if (error != 0)
            return error;

        num_longs = face.horizontal.number_Of_HMetrics;
        if (num_longs > (table_len / 4))
            num_longs = parseInt(table_len / 4);

        face.horizontal.number_Of_HMetrics = 0;

        lm = face.horizontal;
    }

    /* never trust derived values */
    num_shorts         = face.max_profile.numGlyphs - num_longs;
    num_shorts_checked = parseInt((table_len - num_longs * 4) / 2);

    if (num_longs > 0)
        lm.long_metrics = new CreateIntArray(num_longs * 2);
    if (num_shorts > 0)
        lm.short_metrics = new Array(num_shorts);

    var longs  = lm.long_metrics;
    var shorts = lm.short_metrics;

    if (num_shorts < 0)
        num_shorts = 0;

    error = stream.EnterFrame(table_len);

    var _cur = 0;
    for (var i = 0; i < num_longs; i++)
    {
    	longs[_cur++] = stream.GetUShort();
		longs[_cur++] = stream.GetShort();
    }

    var count_s = Math.min(num_shorts, num_shorts_checked);
    for (var i = 0; i < count_s; i++)
    {
        shorts[i] = stream.GetShort();
    }

    if (num_shorts > num_shorts_checked && num_shorts_checked > 0)
    {
        var ind = shorts.length;
        var val = shorts[num_shorts_checked - 1];
        for (var i = ind; i < num_shorts; i++)
            shorts[i] = val;
    }

    stream.ExitFrame();

    if (isvertical)
        face.vertical.number_Of_VMetrics = num_longs;
    else
        face.horizontal.number_Of_HMetrics = num_longs;

    return error;
}
function tt_face_load_hhea(face, stream, isvertical)
{
    var error = 0;
    var header = null;
    if (1 == isvertical)
    {
        face.goto_table(face, 1986553185, stream);
        error = FT_Error;
        if (error != 0)
            return error;

        header = face.vertical;
    }
    else
    {
        face.goto_table(face, 1751672161, stream);
        error = FT_Error;
        if (error != 0)
            return error;

        header = face.horizontal;
    }

    error = stream.EnterFrame(36);
    if (error != 0)
        return error;

    if (0 == isvertical)
    {
        header.Version = stream.GetULong();
        header.Ascender = stream.GetShort();
        header.Descender = stream.GetShort();
        header.Line_Gap = stream.GetShort();

        header.advance_Width_Max = stream.GetUShort();

        header.min_Left_Side_Bearing = stream.GetShort();
        header.min_Right_Side_Bearing = stream.GetShort();
        header.xMax_Extent = stream.GetShort();
        header.caret_Slope_Rise = stream.GetShort();
        header.caret_Slope_Run = stream.GetShort();
        header.caret_Offset = stream.GetShort();

        header.Reserved1 = stream.GetShort();
        header.Reserved2 = stream.GetShort();
        header.Reserved3 = stream.GetShort();
        header.Reserved4 = stream.GetShort();

        header.metric_Data_Format = stream.GetShort();
        header.number_Of_HMetrics = stream.GetUShort();
    }
    else
    {
        header.Version = stream.GetULong();
        header.Ascender = stream.GetShort();
        header.Descender = stream.GetShort();
        header.Line_Gap = stream.GetShort();

        header.advance_Height_Max = stream.GetUShort();

        header.min_Top_Side_Bearing = stream.GetShort();
        header.min_Bottom_Side_Bearing = stream.GetShort();
        header.yMax_Extent = stream.GetShort();
        header.caret_Slope_Rise = stream.GetShort();
        header.caret_Slope_Run = stream.GetShort();
        header.caret_Offset = stream.GetShort();

        header.Reserved1 = stream.GetShort();
        header.Reserved2 = stream.GetShort();
        header.Reserved3 = stream.GetShort();
        header.Reserved4 = stream.GetShort();

        header.metric_Data_Format = stream.GetShort();
        header.number_Of_VMetrics = stream.GetUShort();
    }

    stream.ExitFrame();

    header.long_metrics  = null;
    header.short_metrics = null;

    return error;
}
function tt_face_get_metrics(face, vertical, gindex)
{
    var header = (vertical == 1) ? face.vertical : face.horizontal;

    var longs_m = null;
    var k = (vertical == 1) ? header.number_Of_VMetrics : header.number_Of_HMetrics;

    var v1 = 0;
    var v2 = 0;
    if (k == 0 || null == header.long_metrics || gindex >= face.max_profile.numGlyphs)
        return { bearing:0,advance:0 };

    if (gindex < k)
    {
    	var _ind = gindex << 1;
		v1 = header.long_metrics[_ind + 1];
		v2 = header.long_metrics[_ind];
    }
    else
    {
        v1 = header.short_metrics[gindex - k];
		v2 = header.long_metrics[(k - 1) << 1];
    }
    return { bearing:v1,advance:v2 };
}
/******************************************************************************/
// ttpost
/******************************************************************************/
function load_format_20(face, stream, post_limit)
{
    var error = 0;

    var num_glyphs = stream.ReadUShort();
    error = FT_Error;
    if (error != 0)
        return error;

    if (num_glyphs > face.max_profile.numGlyphs)
        return 3;

    error = stream.EnterFrame(num_glyphs*2);
    if (error != 0)
        return error;

    var glyph_indices = new Array(num_glyphs);
    for (var n=0;n<num_glyphs;n++)
        glyph_indices[n] = stream.GetUShort();
    stream.ExitFrame();

    var num_names = 0;
    for ( n = 0; n < num_glyphs; n++ )
    {
        var idx = glyph_indices[n];
        if (idx >= 258)
        {
            idx -= 257;
            if (idx > num_names)
                num_names = idx;
        }
    }

    var name_strings = new Array(num_names);
    var n=0;
    for (n = 0; n < num_names; n++)
    {
        var len = 0;
        if (stream.pos >= post_limit)
            break;
        else
        {
            len = stream.ReadUChar();
            error = FT_Error;
            if (error != 0)
                return error;
        }

        if (len > post_limit || stream.pos > post_limit - len)
        {
            len = Math.max(0, post_limit - stream.pos);
        }

        name_strings[n] = stream.ReadString1(len);
    }

    if (n < num_names)
    {
        for (; n < num_names; n++)
            name_strings[n] = "";
    }

    var table = face.postscript_names.names.format_20;
    table.num_glyphs    = num_glyphs;
    table.num_names     = num_names;
    table.glyph_indices = glyph_indices;
    table.glyph_names   = name_strings;

    return 0;
}
function load_format_25(face, stream, post_limit)
{
    var num_glyphs = stream.ReadUShort();
    var error = FT_Error;
    if (error != 0)
        return error;

    if (num_glyphs > face.max_profile.numGlyphs || num_glyphs > 258)
        return 3;

    var offset_table = g_memory.Alloc(num_glyphs);
    error = stream.Read(offset_table,num_glyphs);

    if (error != 0)
        return error;

    for (var n = 0; n < num_glyphs; n++ )
    {
        var idx = n + offset_table[n];
        if ( idx < 0 || idx > num_glyphs )
            return 3;
    }

    var table = face.postscript_names.names.format_25;
    table.num_glyphs = num_glyphs;
    table.offsets = offset_table;
    return 0;
}
function load_post_names(face)
{
    var stream = face.stream;
    var post_len = face.goto_table(face, 1886352244, stream);
    var error = FT_Error;
    if (error != 0)
        return error;

    var post_limit = stream.pos + post_len;
    var format = face.postscript.FormatType;

    error = stream.Skip(32);
    if (error != 0)
        return error;

    if (format == 0x00020000)
        error = load_format_20(face, stream, post_limit);
    else if (format == 0x00028000)
        error = load_format_25(face, stream, post_limit);
    else
        error = 3;

    face.postscript_names.loaded = 1;
    return error;
}
function tt_face_free_ps_names(face)
{
    var names = face.postscript_names;

    if (names.loaded == 1)
    {
        var format = face.postscript.FormatType;
        if (format == 0x00020000)
        {
            var table = names.names.format_20;

            table.glyph_indices = null;
            table.num_glyphs = 0;

            table.glyph_names = null;
            table.num_names = 0;
        }
        else if (format == 0x00028000)
        {
            var table = names.names.format_25;
            table.offsets = null;
            table.num_glyphs = 0;
        }
    }
    names.loaded = 0;
}
function tt_face_get_ps_name(face, idx)
{
    if (null == face)
    {
        FT_Error = 35;
        return "";
    }
    if (idx >= face.max_profile.numGlyphs)
    {
        FT_Error = 16;
        return "";
    }
    var psnames = face.psnames;
    if (null == psnames)
    {
        FT_Error = 7;
        return "";
    }

    FT_Error = 0;
    var names = face.postscript_names;
    var format = face.postscript.FormatType;

    var res = psnames.macintosh_name(0);
    if (format == 0x00010000)
    {
        if (idx < 258)
            res = psnames.macintosh_name(idx);
    }
    else if (format == 0x00020000)
    {
        var table = names.names.format_20;
        if (0 == names.loaded)
        {
            FT_Error = load_post_names(face);
            if (FT_Error != 0)
                return res;
        }

        if (idx < table.num_glyphs)
        {
            var name_index = table.glyph_indices[idx];

            if (name_index < 258)
                res = psnames.macintosh_name(name_index);
            else
                res = table.glyph_names[name_index - 258];
        }
    }
    else if (format == 0x00028000)
    {
        var table = names.names.format_25;
        if (0 == names.loaded)
        {
            FT_Error = load_post_names( face );
            if (FT_Error != 0)
                return res;
        }

        if (idx < table.num_glyphs)
        {
            idx += table.offsets[idx];
            res = psnames.macintosh_name(idx);
        }
    }
    return res;
}
/******************************************************************************/
// ttsbit
/******************************************************************************/
function blit_sbit(target, _source, line_bits, byte_padded, x_offset, y_offset, source_height)
{
    var line_incr = target.pitch;
    var line_buff = target.buffer;

    var source = dublicate_pointer(_source);

    if (line_incr < 0)
        line_buff -= line_incr * (target.rows - 1);

    line_buff.pos += (x_offset >> 3) + y_offset * line_incr;

    var acc    = 0;
    var loaded = 0;

    for (var height = source_height; height > 0; height--)
    {
        var cur = dublicate_pointer(line_buff);
        var count = line_bits;
        var shift = (x_offset & 7);
        var space = (8 - shift);

        if ( count >= 8 )
        {
            count -= 8;
            do
            {
                if (loaded < 8)
                {
                    acc |= (source.data[source.pos++] << ( 8 - loaded));
                    loaded += 8;
                }

                val = (0xFF & (acc >>> 8));
                if (shift != 0)
                {
                    cur.data[cur.pos] |= (0xFF & (val >>> shift));
                    cur.data[cur.pos+1] |= (0xFF & (val << space));
                }
                else
                    cur.data[cur.pos] |= val;

                cur.pos++;
                acc <<= 8;
                loaded -= 8;
                count  -= 8;
            } while (count >= 0);
            count += 8;
        }

        if (count > 0)
        {
            if (loaded < count)
            {
                acc |= ((source.data[source.pos++]) << (8 - loaded));
                loaded += 8;
            }

            var val = ((0xFF&(acc >>> 8)) & ~(0xFF >>> count));
            cur.data[cur.pos] |= (0xFF & (val >>> shift));

            if (count > space)
                cur.data[cur.pos+1] |= (0xFF & (val << space));

            acc <<= count;
            loaded -= count;
        }

        if ( byte_padded )
        {
            acc    = 0;
            loaded = 0;
        }
        line_buff.pos += line_incr;
    }
}
function Load_SBit_Const_Metrics(range, stream)
{
    range.image_size = stream.ReadULong();
    if (FT_Error != 0)
        return FT_Error;

    var error = stream.EnterFrame(8);
    if (0 == error)
    {
        var metrics = range.metrics;

        metrics.height = stream.GetUChar();
        metrics.width = stream.GetUChar();

        metrics.horiBearingX = stream.GetChar();
        metrics.horiBearingY = stream.GetChar();
        metrics.horiAdvance = stream.GetUChar();

        metrics.vertBearingX = stream.GetChar();
        metrics.vertBearingY = stream.GetChar();
        metrics.vertAdvance = stream.GetUChar();
    }
    stream.ExitFrame();
    return error;
}
function Load_SBit_Range_Codes(range, stream, load_offsets)
{
    var count = stream.ReadULong();
    if (FT_Error != 0)
        return FT_Error;

    range.num_glyphs = count;

    var size = 2 * count;
    if (load_offsets != 0)
    {
        range.glyph_offsets = new Array(count);
        size *= 2;
    }

    var error = stream.EnterFrame(size);
    if (0 != error)
        return error;

    range.glyph_codes = new Array(count);

    for (var n = 0; n < count; n++)
    {
        range.glyph_codes[n] = stream.GetUShort();

        if (load_offsets != 0)
            range.glyph_offsets[n] = range.image_offset + stream.GetUShort();
    }

    stream.ExitFrame();
    return error;
}
function Load_SBit_Range(range, stream)
{
    var error = 0;

    switch(range.index_format)
    {
    case 1:
    case 3:
        if (range.last_glyph < range.first_glyph)
            return 3;

        var num_glyphs = range.last_glyph - range.first_glyph + 1;
        range.num_glyphs = num_glyphs;
        num_glyphs++;

        var large = (range.index_format == 1) ? 1 : 0;
        var size_elem = large ? 4 : 2;

        error = stream.EnterFrame(num_glyphs*size_elem);
        if (error != 0)
            return error;
        range.glyph_offsets = new Array(num_glyphs);

        for (var n = 0; n < num_glyphs; n++)
            range.glyph_offsets[n] = (range.image_offset + ((large == 1) ? stream.GetULong() : stream.GetUShort()));
        stream.ExitFrame();
        break;

    case 2:
        error = Load_SBit_Const_Metrics(range, stream);
        break;
    case 4:
        error = Load_SBit_Range_Codes(range, stream, 1);
        break;
    case 5:
        error = Load_SBit_Const_Metrics(range, stream);
        if (error != 0)
            error = Load_SBit_Range_Codes(range, stream, 0);
        break;
    default:
        error = 3;
    }
    return error;
}

function tt_face_load_eblc(face, stream)
{
    var error = 0;

    face.num_sbit_strikes = 0;
    face.goto_table(face, 1161972803, stream);
    if (FT_Error != 0)
        face.goto_table(face, 1651273571, stream);
    error = FT_Error;
    if (error != 0)
        return error;

    var table_base = stream.pos;
    error = stream.EnterFrame(8);
    if (error != 0)
        return error;

    var version = stream.GetLong();
    var num_strikes = stream.GetULong();

    stream.ExitFrame();

    if (version != 0x00020000 || num_strikes >= 0x10000)
        return 3;

    face.sbit_strikes = new Array(num_strikes);
    face.num_sbit_strikes = num_strikes;
    
    for (var i = 0; i < num_strikes; i++)
        face.sbit_strikes[i] = new TT_SBit_StrikeRec();

    var strike_ind = 0;
    var count  = num_strikes;

    error = stream.EnterFrame(48*num_strikes);
    if (error != 0)
        return error;

    while ( count > 0 )
    {
        var strike = face.sbit_strikes[strike_ind];

        strike.ranges_offset = stream.GetULong();
        stream.cur += 4;
        strike.num_ranges = stream.GetULong();
        strike.color_ref = stream.GetULong();

        var h = strike.hori;
        var v = strike.vert;

        h.ascender = stream.GetChar();
        h.descender = stream.GetChar();
        h.max_width = stream.GetUChar();
        h.caret_slope_numerator = stream.GetChar();
        h.caret_slope_denominator = stream.GetChar();
        h.caret_offset = stream.GetChar();
        h.min_origin_SB = stream.GetChar();
        h.min_advance_SB = stream.GetChar();
        h.max_before_BL = stream.GetChar();
        h.min_after_BL = stream.GetChar();
        h.pads1 = stream.GetChar();
        h.pads2 = stream.GetChar();

        v.ascender = stream.GetChar();
        v.descender = stream.GetChar();
        v.max_width = stream.GetUChar();
        v.caret_slope_numerator = stream.GetChar();
        v.caret_slope_denominator = stream.GetChar();
        v.caret_offset = stream.GetChar();
        v.min_origin_SB = stream.GetChar();
        v.min_advance_SB = stream.GetChar();
        v.max_before_BL = stream.GetChar();
        v.min_after_BL = stream.GetChar();
        v.pads1 = stream.GetChar();
        v.pads2 = stream.GetChar();

        strike.start_glyph = stream.GetUShort();
        strike.end_glyph = stream.GetUShort();
        strike.x_ppem = stream.GetUChar();
        strike.y_ppem = stream.GetUChar();
        strike.bit_depth = stream.GetUChar();
        strike.flags = stream.GetChar();

        count--;
        strike_ind++;
    }
    
    stream.ExitFrame();
    strike_ind = 0;
    count  = num_strikes;

    while ( count > 0 )
    {
        var strike = face.sbit_strikes[strike_ind];
        var range;
        var count2 = strike.num_ranges;

        error = stream.Seek(table_base + strike.ranges_offset);
        if (0 != error)
            return error;

        error = stream.EnterFrame(strike.num_ranges * 8);
        if (0 != error)
            return error;

        strike.sbit_ranges = new Array(strike.num_ranges);
        var __count = strike.num_ranges;
        for (var i = 0; i < __count; i++)
            strike.sbit_ranges[i] = new TT_SBit_RangeRec();

        var range_ind = 0;
        while ( count2 > 0 )
        {
            range = strike.sbit_ranges[range_ind];
            range.first_glyph  = stream.GetUShort();
            range.last_glyph   = stream.GetUShort();
            range.table_offset = table_base + strike.ranges_offset + stream.GetULong();
            count2--;
            range_ind++;
        }

        stream.ExitFrame();

        count2 = strike.num_ranges;
        range_ind = 0;
        while (count2 > 0)
        {
            range = strike.sbit_ranges[range_ind];
            error = stream.Seek(range.table_offset);
            if (error != 0)
                return error;
            error = stream.EnterFrame(8);
            if (error != 0)
                return error;

            range.index_format = stream.GetUShort();
            range.image_format = stream.GetUShort();
            range.image_offset = stream.GetULong();

            stream.ExitFrame();

            error = Load_SBit_Range(range, stream);
            if (error != 0)
                return error;

            count2--;
            range_ind++;
        }

        count--;
        strike_ind++;
    }

    return error;
}
function tt_face_free_eblc(face)
{
    face.sbit_strikes = null;
    face.num_sbit_strikes = 0;
}
function tt_face_set_sbit_strike(face, req)
{
    return FT_Match_Size(face, req, 0);
}
function tt_face_load_strike_metrics(face, strike_index, metrics)
{
    if (strike_index >= face.num_sbit_strikes)
      return 6;

    var strike = face.sbit_strikes[strike_index];

    metrics.x_ppem = strike.x_ppem;
    metrics.y_ppem = strike.y_ppem;

    metrics.ascender  = strike.hori.ascender << 6;
    metrics.descender = strike.hori.descender << 6;

    metrics.max_advance = (strike.hori.min_origin_SB + strike.hori.max_width + strike.hori.min_advance_SB) << 6;

    metrics.height = metrics.ascender - metrics.descender;

    return 0;
}
function find_sbit_range(glyph_index, strike)
{
    FT_Error = 0;
    var range = null;
    var glyph_offset = 0;

    if (glyph_index < strike.start_glyph || glyph_index > strike.end_glyph)
    {
        FT_Error = 6;
    }

    var range_ind = 0;
    var range_limit = strike.num_ranges;

    for ( ; range_ind < range_limit; range_ind++)
    {
        range = strike.sbit_ranges[range_ind];
        if (glyph_index >= range.first_glyph && glyph_index <= range.last_glyph)
        {
            var delta = (glyph_index - range.first_glyph);

            switch (range.index_format)
            {
            case 1:
            case 3:
                glyph_offset = range.glyph_offsets[delta];
                break;
            case 2:
                glyph_offset = range.image_offset + range.image_size * delta;
                break;
            case 4:
            case 5:
                for (var n = 0; n < range.num_glyphs; n++)
                {
                    if (range.glyph_codes[n] == glyph_index)
                    {
                        if (range.index_format == 4)
                            glyph_offset = range.glyph_offsets[n];
                        else
                            glyph_offset = range.image_offset + n * range.image_size;
                        return {range:range,glyph_offset:glyph_offset};
                    }
                }
                break;
            default:
                break;
            }

            return {range:range,glyph_offset:glyph_offset};
        }
    }

    FT_Error = 6;
    return {range:range,glyph_offset:glyph_offset};
}
function tt_find_sbit_image(face, glyph_index, strike_index)
{
    FT_Error = 0;
    if (null == face.sbit_strikes || (face.num_sbit_strikes <= strike_index))
    {
        FT_Error = 6;
        return {strike:null,range:null,glyph_offset:0};
    }

    var strike = face.sbit_strikes[strike_index];
    var ret = find_sbit_range(glyph_index, strike);
    if (FT_Error != 0)
    {
        FT_Error = 6;
        return {strike:null,range:null,glyph_offset:0};
    }

    return {strike:strike,range:ret.range,glyph_offset:ret.glyph_offset};
}
function tt_load_sbit_metrics(stream, range, metrics)
{
    var error = 0;
    switch (range.image_format)
    {
    case 1:
    case 2:
    case 8:
        error = stream.EnterFrame(5);
        if (error != 0)
            return error;

        metrics.height       = stream.GetUChar();
        metrics.width        = stream.GetUChar();
        metrics.horiBearingX = stream.GetChar();
        metrics.horiBearingY = stream.GetChar();
        metrics.horiAdvance  = stream.GetUChar();

        metrics.vertBearingX = 0;
        metrics.vertBearingY = 0;
        metrics.vertAdvance  = 0;

        stream.ExitFrame();
        break;

    case 6:
    case 7:
    case 9:
        error = stream.EnterFrame(8);
        if (error != 0)
            return error;

        metrics.height       = stream.GetUChar();
        metrics.width        = stream.GetUChar();
        metrics.horiBearingX = stream.GetChar();
        metrics.horiBearingY = stream.GetChar();
        metrics.horiAdvance  = stream.GetUChar();

        metrics.vertBearingX = stream.GetChar();
        metrics.vertBearingY = stream.GetChar();
        metrics.vertAdvance  = stream.GetUChar();

        stream.ExitFrame();
        break;
    case 5:
    default:
        if (range.index_format == 2 || range.index_format == 5)
        {
            var s = range.metrics;
            metrics.height       = s.height;
            metrics.width        = s.width;
            metrics.horiBearingX = s.horiBearingX;
            metrics.horiBearingY = s.horiBearingY;
            metrics.horiAdvance  = s.horiAdvance;

            metrics.vertBearingX = s.vertBearingX;
            metrics.vertBearingY = s.vertBearingY;
            metrics.vertAdvance  = s.vertAdvance;
        }
        else
            return 3;
    }

    return error;
}
function crop_bitmap(map, metrics)
{
    var rows, count;
    var line_len;
    var line = new CPointer();
    line.data = map.buffer.data;
    var d = line.data;

    // 1
    line.pos = map.buffer.pos;
    rows = map.rows;
    line_len = map.pitch;

    var is_go_to = 0;
    for (count = 0; count < rows; count++)
    {
        for (var cur=0; cur < line_len; cur++)
        {
            if (d[line.pos+cur] != 0)
            {
                is_go_to = 1;
                break;
            }
        }
        if (1 == is_go_to)
            break;
        line.pos += line_len;
    }

    if (count >= rows)
    {
        map.width      = 0;
        map.rows       = 0;
        map.pitch      = 0;
        map.pixel_mode = 1;
    }

    if ( count > 0 )
    {
        line.pos = map.buffer.pos;
        var pos1 = line.pos;
        var pos2 = line.pos + count * line_len;

        var c = (rows - count)*line_len;

        for (var i=0;i<c;i++)
            d[pos1+i] = d[pos2+i];

        metrics.height       = (metrics.height - count)&0xFF;
        metrics.horiBearingY = (metrics.horiBearingY - count);
        metrics.vertBearingY = (metrics.vertBearingY - count);

        map.rows -= count;
        rows -= count;
    }

    //2
    is_go_to = 0;
    line.pos = (rows - 1) * line_len;

    for (count = 0; count < rows; count++)
    {
        for (var cur=0; cur < line_len; cur++)
        {
            if (d[line.pos+cur] != 0)
            {
                is_go_to = 1;
                break;
            }
        }
        if (is_go_to == 1)
            break;

        line.pos -= line_len;
    }

    if (count > 0)
    {
        metrics.height = (metrics.height - count);
        rows -= count;
        map.rows -= count;
    }

    // 3
    is_go_to = 0;
    do
    {
        line.pos = map.buffer.pos;
        var limit = line.pos + rows * line_len;

        for (; line.pos < limit; line.pos += line_len)
        {
            if ((d[line.pos] & 0x80) != 0)
            {
                is_go_to = 1;
                break;
            }
        }
        if (1 == is_go_to)
            break;

        line.pos = map.buffer.pos;
        limit = line.pos + rows * line_len;

        for (; line.pos < limit; line.pos += line_len)
        {
            var width = map.width;
            var cur = line.pos;
            var old = 0xFF & (d[cur] << 1);
            for (var n = 8; n < width; n += 8)
            {
                var val = d[cur+1];
                d[cur] = 0xFF & (old | (val >>> 7));
                old = 0xFF & (val << 1);
                cur++;
            }
            d[cur] = old;
        }

        map.width--;
        metrics.horiBearingX++;
        metrics.vertBearingX++;
        metrics.width--;

    } while (map.width > 0);

    // 4
    do
    {
        var right = map.width - 1;
        line.pos = (right >>> 3);
        var limit = line.pos + rows * line_len;
        var mask = 0xFF & (0x80 >>> (right & 7));

        for ( ; line.pos < limit; line.pos += line_len)
            if ((d[line.pos] & mask)!=0)
                return;

        map.width--;
        metrics.width--;

    } while ( map.width > 0 );
}
function Load_SBit_Single(map, x_offset, y_offset, pix_bits, image_format, metrics, stream)
{
    var error = 0;
    if (x_offset < 0 || x_offset + metrics.width > map.width || y_offset < 0 || y_offset + metrics.height > map.rows)
        return 6;

    var glyph_width = metrics.width;
    var glyph_height = metrics.height;
    var glyph_size;
    var line_bits = pix_bits * glyph_width;
    var pad_bytes = 0;

    switch ( image_format )
    {
        case 1:  /* byte-padded formats */
        case 6:
            var line_length;
            switch ( pix_bits )
            {
                case 1:
                    line_length = (glyph_width + 7) >>> 3;
                    break;
                case 2:
                    line_length = (glyph_width + 3) >>> 2;
                    break;
                case 4:
                    line_length = (glyph_width + 1) >>> 1;
                    break;
                default:
                    line_length = glyph_width;
            }

            glyph_size = glyph_height * line_length;
            pad_bytes  = 1;
            break;
      case 2:
      case 5:
      case 7:
            line_bits  = glyph_width * pix_bits;
            glyph_size = (glyph_height * line_bits + 7) >>> 3;
            break;
      default:
            return 3;
    }

    error = stream.EnterFrame(glyph_size);
    if (0 != error)
        return error;

    var s = new CPointer();
    s.data = stream.data;
    s.pos = stream.cur;
    blit_sbit(map, s, line_bits, pad_bytes, x_offset * pix_bits, y_offset, metrics.height);

    stream.ExitFrame();
    return error;
}
function Load_SBit_Image(strike, range, ebdt_pos, glyph_offset, slot, x_offset, y_offset, stream, metrics, depth)
{
    var map = slot.bitmap;
    var error = stream.Seek(ebdt_pos + glyph_offset);
    if (0 != error)
        return error;

    error = tt_load_sbit_metrics(stream, range, metrics);
    if (error != 0)
        return 0;

    if (depth == 0)
    {
        map.width = metrics.width;
        map.rows  = metrics.height;

        switch (strike.bit_depth)
        {
        case 1:
            map.pixel_mode = 1;
            map.pitch = (map.width + 7) >>> 3;
            break;
        case 2:
            map.pixel_mode = 3;
            map.pitch = (map.width + 3) >>> 2;
            break;
        case 4:
            map.pixel_mode = 4;
            map.pitch = (map.width + 1) >>> 1;
            break;
        case 8:
            map.pixel_mode = 2;
            map.pitch = map.width;
            break;
        default:
            return 3;
        }

        var size = map.rows * map.pitch;
        if (size == 0)
            return error;

        error = ft_glyphslot_alloc_bitmap(slot, size);
        if (error != 0)
            return error;
    }

    switch (range.image_format)
    {
        case 1:
        case 2:
        case 5:
        case 6:
        case 7:
            return Load_SBit_Single(map, x_offset, y_offset, strike.bit_depth, range.image_format, metrics, stream);

        case 8:
            error = stream.Skip(1);
            if (error != 0)
                return 83;
        case 9:
            break;

        default:
            return 3;
    }

    var num_components = stream.ReadUShort();
    FT_Error = error;
    if (error != 0)
        return error;

    error = stream.EnterFrame(4*num_components);
    if (error != 0)
        return error;

    var components = new Array(num_components);
    var count = num_components;
    var comp = 0;

    for (; count > 0; count--, comp++)
    {
        var _comp = components[comp];
        _comp.glyph_code = stream.GetUShort();
        _comp.x_offset   = stream.GetChar();
        _comp.y_offset   = stream.GetChar();
    }

    stream.ExitFrame();
    count = num_components;
    comp = 0;
    for ( ; count > 0; count--, comp++ )
    {
        var elem_metrics = new TT_SBit_MetricsRec();

        var _comp = components[comp];
        var elem = find_sbit_range(_comp.glyph_code, strike);
        error = FT_Error;
        if (error != 0)
        {
            components = null;
            return error;
        }

        error = Load_SBit_Image(strike, elem.range, ebdt_pos, elem.glyph_offset, slot, x_offset + _comp.x_offset,
                                 y_offset + _comp.y_offset, stream, elem_metrics, depth + 1);
        if (error != 0)
        {
            components = null;
            return error;
        }
    }

    return error;
}
function tt_face_load_sbit_image(face, strike_index, glyph_index, load_flags, stream, map, metrics)
{
    var elem = tt_find_sbit_image(face, glyph_index, strike_index);
    var error = FT_Error;
    if (error != 0)
        return error;

    face.goto_table(face, 1161970772, stream);
    error = FT_Error;
    if (error != 0)
    {
        face.goto_table(face, 1650745716, stream);
        error = FT_Error;
    }
    if (error != 0)
        return error;

    var ebdt_pos = stream.pos;
    var strike = elem.strike;

    error = Load_SBit_Image(strike, elem.range, ebdt_pos, elem.glyph_offset,
                             face.glyph, 0, 0, stream, metrics, 0);
    if (error != 0)
        return error;

    if (strike.flags & 1)
    {
        var advance = strike.hori.ascender - strike.hori.descender;

        metrics.vertBearingX = parseInt((-metrics.width / 2));
        metrics.vertBearingY = parseInt((advance - metrics.height)/2);
        metrics.vertAdvance  = parseInt(advance*12/10);
    }

    if (load_flags & 64)
        crop_bitmap(map, metrics);
    return error;
}
/******************************************************************************/
// ttcmap
/******************************************************************************/
function TT_CMapRec()
{
    this.cmap = new FT_CMapRec();
    this.data = null;
    this.flags = 0;

    this.type = 1;
}
function TT_CMap_ClassRec()
{
    this.clazz = new FT_CMap_ClassRec();
    this.format = 0;
    this.validate = null;
    this.get_cmap_info = null;
}
function TT_Validator()
{
    this.validator = new FT_ValidatorRec();
    this.num_glyphs = 0;
}
function tt_cmap_init(cmap, table)
{
    cmap.data = dublicate_pointer(table);
    return 0;
}
// cmap0 ----------------------------------------------------------------------------------
function tt_cmap0_char_index(cmap, char_code)
{
    var table = cmap.data;
    return char_code < 256 ? table.data[table.pos + 6 + char_code] : 0;
}
function tt_cmap0_char_next(cmap, char_code)
{
    var table = cmap.data;
    var pos_base = table.pos + 6;
    var charcode = char_code;
    var result = 0;
    var gindex = 0;

    var d = table.data;
    while (++charcode < 256)
    {
        gindex = d[pos_base + charcode];
        if (gindex != 0)
        {
            result = charcode;
            break;
        }
    }

    return {gindex:gindex,char_code:result};
}
function tt_cmap0_class_rec()
{
    this.clazz = create_cmap_class_rec(0,tt_cmap_init,null,tt_cmap0_char_index,tt_cmap0_char_next,null,null,null,null,null);
    this.format = 0;
    this.validate = function(table, valid)
    {
        var p = dublicate_pointer(table);
        p.pos += 2;
        var length = FT_NEXT_USHORT(p);

        if (length > valid.limit || length < 262)
            return 8;

        if (valid.level >= 1)
        {
            var idx;
            var d = p.data;
            var c = table.pos + 6;
            for (var n = 0; n < 256; n++)
            {
                idx = d[c++];
                if (idx >= valid.num_glyphs)
                    return 16;
            }
        }
        return 0;
    }
    this.get_cmap_info = function(cmap, cmap_info)
    {
		cmap_info.format   = 0;
    	if (isSafariAppleDevices)
    		return 0;

        var data = cmap.data;
        data.pos += 4;
        cmap_info.language = FT_PEEK_USHORT(data);
        data.pos -= 4;
        return 0;
    }
}
// cmap2 ----------------------------------------------------------------------------------
function tt_cmap2_get_subheader(table, char_code)
{
    if (char_code < 0x10000)
    {
        var char_lo = (char_code & 0xFF);
        var char_hi = (char_code >>> 8);
        var p = dublicate_pointer(table);
        p.pos += 6;

        var subs = table.pos + 518;
        var sub = subs;

        if (char_hi == 0)
        {
            sub = subs;
            p.pos += char_lo * 2;
            if (FT_PEEK_USHORT(p) != 0)
                return null;
        }
        else
        {
            p.pos += char_hi * 2;
            sub = subs + (FT_PEEK_USHORT(p) & ~7);
            if (sub == subs)
                return null;
        }
        var result = new CPointer();
        result.data = table.data;
        result.pos = sub;
        return result;
    }
    return null;
}
function tt_cmap2_char_index(cmap, char_code)
{
    var table = dublicate_pointer(cmap.data);
    var result = 0;
    var subheader = tt_cmap2_get_subheader(table, char_code);
    if (subheader != null)
    {
        var p = subheader;
        var idx = (char_code & 0xFF);

        var start  = FT_NEXT_USHORT(p);
        var count  = FT_NEXT_USHORT(p);
        var delta  = FT_NEXT_SHORT (p);
        var offset = FT_PEEK_USHORT(p);

        idx -= start;
        if ( idx < count && offset != 0 )
        {
            p.pos += offset + 2 * idx;
            idx = FT_PEEK_USHORT(p);
            if (idx != 0)
                result = (idx + delta) & 0xFFFF;
        }
    }
    return result;
}
function tt_cmap2_char_next(cmap, charcode_)
{
    var table = dublicate_pointer(cmap.data);
    var gindex = 0;
    var result = 0;
    var charcode = charcode_ + 1;
    var subheader = null;

    while (charcode < 0x10000)
    {
        subheader = tt_cmap2_get_subheader(table, charcode);
        if (subheader != null)
        {
            var p = subheader;
            var start   = FT_NEXT_USHORT(p);
            var count   = FT_NEXT_USHORT(p);
            var delta   = FT_NEXT_SHORT(p);
            var offset  = FT_PEEK_USHORT(p);
            var char_lo = (charcode & 0xFF);
            var pos, idx;

            if (offset == 0)
            {
                charcode = charcode & ~255 + 256;
                continue;
            }

            if (char_lo < start)
            {
                char_lo = start;
                pos = 0;
            }
            else
                pos = (char_lo - start);

            p.pos += offset + pos * 2;
            charcode = charcode & ~255 + char_lo;

            for ( ; pos < count; pos++, charcode++ )
            {
                idx = FT_NEXT_USHORT(p);

                if ( idx != 0 )
                {
                    gindex = (idx + delta) & 0xFFFF;
                    if ( gindex != 0 )
                    {
                        result = charcode;
                        return {gindex:gindex,char_code:result};
                    }
                }
            }
        }
        charcode = charcode & ~255 + 256;
    }
    return {gindex:gindex,char_code:result};
}
function tt_cmap2_class_rec()
{
    this.clazz = create_cmap_class_rec(0,tt_cmap_init,null,tt_cmap2_char_index,tt_cmap2_char_next,null,null,null,null,null);
    this.format = 2;
    this.validate = function(table, valid)
    {
        var p = dublicate_pointer(table);
        p.pos += 2;
        var length = FT_PEEK_USHORT(p);
        var n = 0;

        if (length > valid.limit || length < 6 + 512)
            return 8;

        p.pos = table.pos + 6;
        var max_subs = 0;
        for ( n = 0; n < 256; n++ )
        {
            var idx = FT_NEXT_USHORT(p);
            if (valid.level >= 2 && (idx & 7) != 0)
                return 8;

            idx >>>= 3;

            if (idx > max_subs)
                max_subs = idx;
        }

        var glyph_ids = p.pos + (max_subs + 1) * 8;
        if (glyph_ids > valid.limit)
            return 8;

        for (n = 0; n <= max_subs; n++)
        {
            var first_code = FT_NEXT_USHORT(p);
            var code_count = FT_NEXT_USHORT(p);
            var delta = FT_NEXT_SHORT(p);
            var offset = FT_NEXT_USHORT(p);

            if (code_count == 0)
                continue;

            if (valid.level >= 2)
            {
                if (first_code >= 256 || first_code + code_count > 256)
                    return 8;
            }

            if (offset != 0)
            {
                var ids = p.pos - 2 + offset;
                if (ids < glyph_ids || ids + code_count*2 > (table.pos+length))
                    return 9;

                if (valid.level >= 1)
                {
                    var limit = p.pos + code_count * 2;
                    var idx;
                    for (; p.pos < limit;)
                    {
                        idx = FT_NEXT_USHORT(p);
                        if ( idx != 0 )
                        {
                            idx = (idx + delta) & 0xFFFF;
                            if (idx >= valid.num_glyphs)
                                return 16;
                        }
                    }
                }
            }
        }
        return 0;
    }
    this.get_cmap_info = function(cmap, cmap_info)
    {
		cmap_info.format   = 2;
		if (isSafariAppleDevices)
			return 0;

        cmap.data.pos += 4;
        cmap_info.language = FT_PEEK_USHORT(cmap.data);
        cmap.data.pos -= 4;
        return 0;
    }
}
// cmap4 ----------------------------------------------------------------------------------
function TT_CMap4Rec()
{
    this.cmap = new TT_CMapRec();
    this.cur_charcode;
    this.cur_gindex;

    this.num_ranges;
    this.cur_range;
    this.cur_start;
    this.cur_end;
    this.cur_delta;
    this.cur_values;

    this.type = 2;
}
function tt_cmap4_init(cmap,table)
{
    var p = dublicate_pointer(table);
    p.pos += 6;
    cmap.cmap.data = dublicate_pointer(table);
    cmap.num_ranges = FT_PEEK_USHORT(p) >>> 1;
    cmap.cur_charcode = 0xFFFFFFFF;
    cmap.cur_gindex = 0;
    return 0;
}
function tt_cmap4_set_range(cmap, range_index)
{
    var table = cmap.cmap.data.pos;
    var p = dublicate_pointer(cmap.cmap.data);
    var num_ranges = cmap.num_ranges;

    while (range_index < num_ranges)
    {
        p.pos = table + 14 + range_index * 2;
        cmap.cur_end = FT_PEEK_USHORT(p);

        p.pos += 2 + num_ranges * 2;
        cmap.cur_start = FT_PEEK_USHORT(p);

        p.pos += num_ranges * 2;
        cmap.cur_delta = FT_PEEK_SHORT(p);

        p.pos += num_ranges * 2;
        var offset = FT_PEEK_USHORT(p);

        if (range_index >= num_ranges - 1 && cmap.cur_start == 0xFFFF && cmap.cur_end == 0xFFFF)
        {
            var face = cmap.cmap.cmap.charmap.face;
            var limit = face.cmap_table.pos + face.cmap_size;
            if (offset && p.pos + offset + 2 > limit)
            {
                cmap.cur_delta = 1;
                offset = 0;
            }
        }
        if (offset != 0xFFFF)
        {
            cmap.cur_values = null;
            if (offset != 0)
            {
                cmap.cur_values = dublicate_pointer(p);
                cmap.cur_values.pos += offset;
            }
            cmap.cur_range = range_index;
            return 0;
        }
        range_index++;
    }
    return -1;
}
function tt_cmap4_next(cmap)
{
    if (cmap.cur_charcode >= 0xFFFF)
    {
        cmap.cur_charcode = 0xFFFFFFFF;
        cmap.cur_gindex = 0;
        return;
    }

    var charcode = cmap.cur_charcode + 1;

    if (charcode < cmap.cur_start)
        charcode = cmap.cur_start;

    while(true)
    {
        var p = new CPointer();
        var values = cmap.cur_values;
        var end = cmap.cur_end;
        var delta = cmap.cur_delta;

        if ( charcode <= end )
        {
            if (values != null)
            {
                p.data = values.data;
                p.pos = values.pos;
                p.pos += 2*(charcode - cmap.cur_start);
                do
                {
                    var gindex = FT_NEXT_USHORT(p);
                    if (gindex != 0)
                    {
                        gindex = ((gindex + delta) & 0xFFFF);
                        if (gindex != 0)
                        {
                            cmap.cur_charcode = charcode;
                            cmap.cur_gindex   = gindex;
                            return;
                        }
                    }
                } while ( ++charcode <= end );
            }
            else
            {
                do
                {
                    var gindex = ((charcode + delta)&0xFFFF);
                    if (gindex != 0)
                    {
                        cmap.cur_charcode = charcode;
                        cmap.cur_gindex = gindex;
                        return;
                    }
                } while ( ++charcode <= end );
            }
        }

        if (tt_cmap4_set_range(cmap, cmap.cur_range + 1) < 0)
            break;

        if (charcode < cmap.cur_start)
            charcode = cmap.cur_start;
    }
    cmap.cur_charcode = 0xFFFFFFFF;
    cmap.cur_gindex = 0;
}
function tt_cmap4_char_map_linear(cmap, _charcode, next)
{
    var num_segs2, start, end, offset;
    var delta;
    var i, num_segs;
    var charcode = _charcode;
    var gindex = 0;
    var base = cmap.cmap.data.pos;
    var p = dublicate_pointer(cmap.cmap.data);
    p.pos += 6;

    num_segs2 = FT_PEEK_USHORT(p) & ~1;
    num_segs = num_segs2 >>> 1;

    if (num_segs == 0)
        return {gindex:0,char_code:_charcode};

    if (next != 0)
        charcode++;

    for (; charcode <= 0xFFFF; charcode++)
    {
        p.pos = base + 14;
        var q = dublicate_pointer(p);
        q.pos = base + 16 + num_segs2;

        for ( i = 0; i < num_segs; i++ )
        {
            end   = FT_NEXT_USHORT(p);
            start = FT_NEXT_USHORT(q);

            if ( charcode >= start && charcode <= end )
            {
                p.pos = q.pos - 2 + num_segs2;
                delta = FT_PEEK_SHORT(p);
                p.pos += num_segs2;
                offset = FT_PEEK_USHORT(p);

                if (i >= num_segs - 1 && start == 0xFFFF && end == 0xFFFF)
                {
                    var face = cmap.cmap.cmap.charmap.face;
                    var limit = face.cmap_table.pos + face.cmap_size;
                    if (offset != 0 && p.pos + offset + 2 > limit)
                    {
                        delta  = 1;
                        offset = 0;
                    }
                }

                if (offset == 0xFFFF)
                    continue;

                if (offset != 0)
                {
                    p.pos += offset + (charcode - start) * 2;
                    gindex = FT_PEEK_USHORT(p);
                    if (gindex != 0)
                        gindex = (gindex + delta) & 0xFFFF;
                }
                else
                    gindex = (charcode + delta) & 0xFFFF;

                break;
            }
        }

        if (next == 0 || gindex != 0)
            break;
    }

    if (next != 0 && gindex != 0)
        return {gindex:gindex,char_code:charcode};

    return {gindex:gindex,char_code:_charcode};
}
function tt_cmap4_char_map_binary(cmap, _charcode, next)
{
    var num_segs2, start, end, offset;
    var delta;
    var max, min, mid, num_segs;
    var __charcode = _charcode;
    var charcode = _charcode;
    var gindex = 0;
    var p = dublicate_pointer(cmap.cmap.data);
    var base = p.pos;

    p.pos += 6;
    num_segs2 = FT_PEEK_USHORT(p) & ~1;

    if (num_segs2 == 0)
        return {gindex:gindex,char_code:__charcode};

    num_segs = num_segs2 >>> 1;

    mid = num_segs;
    end = 0xFFFF;

    if (next != 0)
        charcode++;

    min = 0;
    max = num_segs;

    while (min < max)
    {
        mid = (min + max) >>> 1;
        p.pos = base + 14 + mid * 2;
        end = FT_PEEK_USHORT(p);
        p.pos += 2 + num_segs2;
        start = FT_PEEK_USHORT(p);

        if (charcode < start)
            max = mid;
        else if (charcode > end)
            min = mid + 1;
        else
        {
            p.pos += num_segs2;
            delta = FT_PEEK_SHORT(p);
            p.pos += num_segs2;
            offset = FT_PEEK_USHORT(p);

            if (mid >= num_segs - 1 && start == 0xFFFF && end == 0xFFFF)
            {
                var face = cmap.cmap.cmap.charmap.face;
                var limit = face.cmap_table.pos + face.cmap_size;
                if (offset && p.pos + offset + 2 > limit)
                {
                    delta  = 1;
                    offset = 0;
                }
            }

            if ((cmap.flags & 2) != 0)
            {
                var i;
                max = mid;
                if (offset == 0xFFFF)
                    mid = max + 1;

                for (i = max ; i > 0; i--)
                {
                    var old_p = p.pos;
                    p.pos = base + 14 + (i - 1) * 2;
                    var prev_end = FT_PEEK_USHORT(p);

                    if ( charcode > prev_end )
                    {
                        p.pos = old_p.pos;
                        break;
                    }

                    end = prev_end;
                    p.pos += 2 + num_segs2;
                    start = FT_PEEK_USHORT(p);
                    p.pos += num_segs2;
                    delta = FT_PEEK_SHORT(p);
                    p.pos += num_segs2;
                    offset = FT_PEEK_USHORT(p);

                    if (offset != 0xFFFF)
                        mid = i - 1;
                }

                if (mid == max + 1)
                {
                    if (i != max)
                    {
                        p.pos = base + 14 + max * 2;
                        end = FT_PEEK_USHORT(p);
                        p.pos += 2 + num_segs2;
                        start = FT_PEEK_USHORT(p);
                        p.pos += num_segs2;
                        delta = FT_PEEK_SHORT(p);
                        p.pos += num_segs2;
                        offset = FT_PEEK_USHORT(p);
                    }
                    mid = max;
                    for (i = max + 1; i < num_segs; i++)
                    {
                        p.pos = base + 14 + i * 2;
                        var next_end = FT_PEEK_USHORT(p);
                        p.pos += 2 + num_segs2;
                        var next_start = FT_PEEK_USHORT(p);

                        if (charcode < next_start)
                            break;

                        end = next_end;
                        start = next_start;
                        p.pos += num_segs2;
                        delta = FT_PEEK_SHORT(p);
                        p.pos += num_segs2;
                        offset = FT_PEEK_USHORT(p);

                        if (offset != 0xFFFF)
                            mid = i;
                    }
                    i--;

                    if (mid == max)
                    {
                        mid = i;
                        break;
                    }
                }

                if (mid != i)
                {
                    p.pos = base + 14 + mid * 2;
                    end = FT_PEEK_USHORT(p);
                    p.pos += 2 + num_segs2;
                    start = FT_PEEK_USHORT(p);
                    p.pos += num_segs2;
                    delta = FT_PEEK_SHORT(p);
                    p.pos += num_segs2;
                    offset = FT_PEEK_USHORT(p);
                }
            }
            else
            {
                if (offset == 0xFFFF)
                    break;
            }

            if (offset != 0)
            {
                p.pos += offset + (charcode - start) * 2;
                gindex = FT_PEEK_USHORT(p);
                if (gindex != 0)
                    gindex = (gindex + delta) & 0xFFFF;
            }
            else
                gindex = (charcode + delta) & 0xFFFF;

            break;
        }
    }

    if (next != 0)
    {
        if ( charcode > end )
        {
            mid++;
            if ( mid == num_segs )
                return {gindex:0,char_code:__charcode};
        }

        if (tt_cmap4_set_range(cmap, mid) != 0)
        {
            if (gindex != 0)
                __charcode = charcode;
        }
        else
        {
            cmap.cur_charcode = charcode;
            if (gindex != 0)
                cmap.cur_gindex = gindex;
            else
            {
                cmap.cur_charcode = charcode;
                tt_cmap4_next(cmap);
                gindex = cmap.cur_gindex;
            }

            if (gindex != 0)
                __charcode = cmap.cur_charcode;
        }
    }

    return {gindex:gindex,char_code:__charcode};
}
function tt_cmap4_char_index(cmap,char_code)
{
    if (char_code >= 0x10000)
        return 0;

    if ((cmap.cmap.flags & 1) != 0)
        return tt_cmap4_char_map_linear(cmap, char_code, 0).gindex;
    else
        return tt_cmap4_char_map_binary(cmap, char_code, 0).gindex;
}
function tt_cmap4_char_next(cmap,char_code)
{
    var gindex = 0;
    var _char_code = char_code;
    if (_char_code >= 0xFFFF)
        return {gindex:gindex,char_code:_char_code};

    if ((cmap.flags & 1) != 0)
    {
        var r = tt_cmap4_char_map_linear(cmap, char_code, 1);
        gindex = r.gindex;
        _char_code = r.char_code;
    }
    else
    {
        if (_char_code == cmap.cur_charcode)
        {
            tt_cmap4_next(cmap);
            gindex = cmap.cur_gindex;
            if (gindex)
                _char_code = cmap.cur_charcode;
        }
        else
        {
            var r = tt_cmap4_char_map_binary(cmap, char_code, 1);
            gindex = r.gindex;
            _char_code = r.char_code;
        }
    }
    return {gindex:gindex,char_code:_char_code};
}
function tt_cmap4_class_rec()
{
    this.clazz = create_cmap_class_rec(0,tt_cmap4_init,null,tt_cmap4_char_index,tt_cmap4_char_next,null,null,null,null,null);
    this.format = 4;
    this.validate = function(table, valid)
    {
        var p = dublicate_pointer(table);
        p.pos += 2;
        var length = FT_NEXT_USHORT(p);
        var error = 0;

        if (length < 16)
            return 8;

        if (table.pos + length > valid.limit)
        {
            if (valid.level >= 1)
                return 8;

            length = (valid.limit - table.pos);
        }

        p.pos = table.pos + 6;
        var num_segs = FT_NEXT_USHORT(p);

        if (valid.level >= 2)
        {
            if ((num_segs & 1) != 0)
                return 8;
        }

        num_segs >>>= 1;

        if (length < 16 + num_segs * 2 * 4)
            return 8;

        if (valid.level >= 2)
        {
            var search_range   = FT_NEXT_USHORT(p);
            var entry_selector = FT_NEXT_USHORT(p);
            var range_shift    = FT_NEXT_USHORT(p);

            if (((search_range | range_shift) & 1) != 0)
                return 8;

            search_range >>>= 1;
            range_shift >>>= 1;

            if (search_range > num_segs || search_range * 2 < num_segs || search_range + range_shift != num_segs                 ||
                                search_range != (1 << entry_selector))
                return 8;
        }

        var ends      = table.pos + 14;
        var starts    = table.pos + 16 + num_segs * 2;
        var deltas    = starts  + num_segs * 2;
        var offsets   = deltas  + num_segs * 2;
        var glyph_ids = offsets + num_segs * 2;

        if (valid.level >= 2)
        {
            p.pos = ends + (num_segs - 1) * 2;
            if (FT_PEEK_USHORT(p) != 0xFFFF)
                return 8;
        }

        var start, end, offset, n;
        var last_start = 0, last_end = 0;
        var delta;
        var p_start = new CPointer(); p_start.data = p.data; p_start.pos = starts;
        var p_end = new CPointer(); p_end.data = p.data; p_end.pos = ends;
        var p_delta = new CPointer(); p_delta.data = p.data; p_delta.pos = deltas;
        var p_offset = new CPointer(); p_offset.data = p.data; p_offset.pos = offsets;

        for ( n = 0; n < num_segs; n++ )
        {
            p.pos = p_offset.pos;
            start  = FT_NEXT_USHORT(p_start);
            end    = FT_NEXT_USHORT(p_end);
            delta  = FT_NEXT_SHORT(p_delta);
            offset = FT_NEXT_USHORT(p_offset);

            if (start > end)
                return 8;;

            if (start <= last_end && n > 0)
            {
                if (valid.level >= 1)
                    return 8;
                else
                {
                    if (last_start > start || last_end > end)
                        error |= 1;
                    else
                        error |= 2;
                }
            }

            if (offset && offset != 0xFFFF)
            {
                p.pos += offset;
                if (valid.level >= 1)
                {
                    if (p.pos < glyph_ids || p.pos + (end - start + 1) * 2 > table.pos + length)
                        return 8;
                }
                else if (n != num_segs - 1 || !(start == 0xFFFF && end == 0xFFFF))
                {
                    if (p.pos < glyph_ids || p.pos + (end - start + 1) * 2 > valid.limit)
                        return 8;
                }

                if (valid.level >= 1)
                {
                    var idx;
                    for (var i = start; i < end; i++ )
                    {
                        idx = FT_NEXT_USHORT(p);
                        if (idx != 0)
                        {
                            idx = (idx + delta) & 0xFFFF;
                            if (idx >= valid.num_glyphs)
                                return 16;
                        }
                    }
                }
            }
            else if (offset == 0xFFFF)
            {
              if (valid.level >= 2 || n != num_segs - 1 || !( start == 0xFFFF && end == 0xFFFF))
                return 8;
            }

            last_start = start;
            last_end   = end;
        }

        return error;
    }
    this.get_cmap_info = function(cmap, cmap_info)
    {
		cmap_info.format = 4;
		if (isSafariAppleDevices)
			return 0;

        var data = cmap.cmap.data;
        data.pos += 4;
        cmap_info.language = FT_PEEK_USHORT(data);
        data.pos -= 4;
        return 0;
    }
}
// cmap6 ----------------------------------------------------------------------------------
function tt_cmap6_char_index(cmap, char_code)
{
    var p = dublicate_pointer(cmap.data);
    p.pos += 6;
    var result = 0;
    var start = FT_NEXT_USHORT(p);
    var count = FT_NEXT_USHORT(p);
    var idx =  char_code - start;

    if ( idx < count )
    {
        p.pos += 2 * idx;
        result = FT_PEEK_USHORT(p);
    }
    return result;
}
function tt_cmap6_char_next(cmap, _char_code)
{
    var p = dublicate_pointer(cmap.data);
    p.pos += 6;
    var result    = 0;
    var char_code = _char_code + 1;
    var gindex = 0;

    var start = FT_NEXT_USHORT(p);
    var count = FT_NEXT_USHORT(p);

    if (char_code >= 0x10000)
        return {gindex:gindex,char_code:_char_code};

    if (char_code < start)
        char_code = start;

    var idx = char_code - start;
    p.pos += 2 * idx;
    for (; idx < count; idx++)
    {
        gindex = FT_NEXT_USHORT(p);
        if (gindex != 0)
        {
            result = char_code;
            break;
        }
        char_code++;
    }
    return {gindex:gindex,char_code:result};
}
function tt_cmap6_class_rec()
{
    this.clazz = create_cmap_class_rec(0,tt_cmap_init,null,tt_cmap6_char_index,tt_cmap6_char_next,null,null,null,null,null);
    this.format = 6;
    this.validate = function(table, valid)
    {
        var base = table.pos;
        var p = new CPointer();
        p.data = table.data;

        if (base + 10 > valid.limit)
            return 8;

        p.pos = base + 2;
        var length = FT_NEXT_USHORT(p);
        p.pos = base + 8;
        var count = FT_NEXT_USHORT(p);

        if (base + length > valid.limit || length < 10 + count * 2)
            return 8;

        if (valid.level >= 1)
        {
            var gindex;
            for (; count > 0; count--)
            {
                gindex = FT_NEXT_USHORT(p);
                if (gindex >= valid.num_glyphs)
                    return 16;
            }
        }
        return 0;
    }
    this.get_cmap_info = function(cmap, cmap_info)
    {
		cmap_info.format = 6;
		if (isSafariAppleDevices)
			return 0;

        var data = cmap.data;
        data.pos += 4;
        cmap_info.language = FT_PEEK_USHORT(data);
        data.pos -= 4;
        return 0;
    }
}
// cmap8 ----------------------------------------------------------------------------------
function tt_cmap8_char_index(cmap, char_code)
{
    var result = 0;
    var p = dublicate_pointer(cmap.cmap.data);
    p.pos += 8204;
    var num_groups = FT_NEXT_ULONG(p);
    var start, end, start_id;
    for (; num_groups > 0; num_groups--)
    {
        start    = FT_NEXT_ULONG(p);
        end      = FT_NEXT_ULONG(p);
        start_id = FT_NEXT_ULONG(p);

        if (char_code < start)
            break;

        if (char_code <= end)
        {
            result = (start_id + char_code - start);
            break;
        }
    }
    return result;
}
function tt_cmap8_char_next(cmap, _char_code)
{
    var result = 0;
    var char_code = _char_code + 1;
    var gindex = 0;
    var p = dublicate_pointer(cmap.cmap.data);
    p.pos += 8204;
    var num_groups = FT_NEXT_ULONG(p);
    var start, end, start_id;

    for ( ; num_groups > 0; num_groups-- )
    {
        start    = FT_NEXT_ULONG(p);
        end      = FT_NEXT_ULONG(p);
        start_id = FT_NEXT_ULONG(p);

        if (char_code < start)
            char_code = start;

        if (char_code <= end)
        {
            gindex = (char_code - start + start_id);
            if ( gindex != 0 )
            {
                result = char_code;
                break;
            }
        }
    }
    return {gindex:gindex,char_code:result};
}
function tt_cmap8_class_rec()
{
    this.clazz = create_cmap_class_rec(0,tt_cmap_init,null,tt_cmap8_char_index,tt_cmap8_char_next,null,null,null,null,null);
    this.format = 8;
    this.validate = function(table, valid)
    {
        var base = table.pos;
        var p = dublicate_pointer(table);
        p.pos += 4;

        if (base + 16 + 8192 > valid.limit)
            return 8;

        var length = FT_NEXT_ULONG(p);
        if (length > (valid.limit - base) || length < 8192 + 16)
            return 8;

        var is32 = base + 12;
        p.pos = is32 + 8192;
        var num_groups = FT_NEXT_ULONG(p);

        if (p.pos + num_groups * 12 > valid.limit)
            return 8;

        var n, start, end, start_id, count, last = 0;
        for ( n = 0; n < num_groups; n++ )
        {
            var hi, lo;
            start    = FT_NEXT_ULONG(p);
            end      = FT_NEXT_ULONG(p );
            start_id = FT_NEXT_ULONG(p);

            if (start > end)
                return 8;

            if (n > 0 && start <= last)
                return 8;

            if (valid.level >= 1)
            {
                if (start_id + end - start >= valid.num_glyphs)
                    return 16;

                count = (end - start + 1);
                if ((start & ~0xFFFF) != 0)
                {
                    for (; count > 0; count--, start++)
                    {
                        hi = (start >>> 16);
                        lo = (start & 0xFFFF);

                        if ((p.data[is32 + hi >>> 3] & (0x80 >>> (hi & 7))) == 0)
                            return 8;

                        if ((p.data[is32 + lo >>> 3] & (0x80 >>> (lo & 7))) == 0)
                            return 8;
                    }
                }
                else
                {
                    if ((end & ~0xFFFF) != 0)
                        return 8;

                    for ( ; count > 0; count--, start++ )
                    {
                        lo = (start & 0xFFFF);
                        if ((p.data[is32 + lo >>> 3] & (0x80 >>> (lo & 7))) != 0)
                            return 8;
                    }
                }
            }
            last = end;
        }

        return 0;
    }
    this.get_cmap_info = function(cmap, cmap_info)
    {
		cmap_info.format = 8;
		if (isSafariAppleDevices)
			return 0;

        var data = cmap.cmap.data;
        data.pos += 8;
        cmap_info.language = FT_PEEK_ULONG(data);
        data.pos -= 8;
        return 0;
    }
}
// cmap10 ---------------------------------------------------------------------------------
function tt_cmap10_char_index(cmap, char_code)
{
    var p = dublicate_pointer(cmap.cmap.data);
    p.pos += 12;
    var result = 0;
    var start = FT_NEXT_ULONG(p);
    var count = FT_NEXT_ULONG(p);
    var idx = (char_code - start);

    if (idx < count)
    {
        p.pos += 2 * idx;
        result = FT_PEEK_USHORT(p);
    }
    return result;
}
function tt_cmap10_char_next(cmap, _char_code)
{
    var p = dublicate_pointer(cmap.cmap.data);
    p.pos += 12;
    var char_code = _char_code + 1;
    var gindex = 0;
    var start = FT_NEXT_ULONG(p);
    var count = FT_NEXT_ULONG(p);

    if (char_code < start)
        char_code = start;

    var idx = char_code - start;
    p.pos += 2 * idx;

    for (; idx < count; idx++)
    {
        gindex = FT_NEXT_USHORT(p);
        if (gindex != 0)
            break;
        char_code++;
    }
    return {gindex:gindex,char_code:char_code};
}
function tt_cmap10_class_rec()
{
    this.clazz = create_cmap_class_rec(0,tt_cmap_init,null,tt_cmap10_char_index,tt_cmap10_char_next,null,null,null,null,null);
    this.format = 10;
    this.validate = function(table, valid)
    {
        var p = dublicate_pointer(table);
        var base = table.pos;
        p.pos += 4;

        if (base + 20 > valid.limit)
            return 8;

        var length = FT_NEXT_ULONG(p);
        p.pos = base + 16;
        var count = FT_NEXT_ULONG(p);

        if (length > (valid.limit - base) || length < 20 + count * 2)
            return 8;

        if (valid.level >= 1)
        {
            var gindex;
            for (; count > 0; count--)
            {
                gindex = FT_NEXT_USHORT(p);
                if (gindex >= valid.num_glyphs)
                    return 16;
            }
        }
        return 0;
    }
    this.get_cmap_info = function(cmap, cmap_info)
    {
		cmap_info.format = 10;
		if (isSafariAppleDevices)
			return 0;

        var data = cmap.cmap.data;
        data.pos += 8;
        cmap_info.language = FT_PEEK_ULONG(data);
        data.pos -= 8;
        return 0;
    }
}
// cmap12 ---------------------------------------------------------------------------------
function TT_CMap12Rec()
{
    this.cmap = new TT_CMapRec();
    this.valid;
    this.cur_charcode;
    this.cur_gindex;
    this.cur_group;
    this.num_groups;

    this.type = 3;
}
function tt_cmap12_init(cmap, table)
{
    cmap.cmap.data = dublicate_pointer(table);
    table.pos += 12;
    cmap.num_groups = FT_PEEK_ULONG(table);
    table.pos -= 12;
    cmap.valid = 0;
    return 0;
}
function tt_cmap12_next(cmap)
{
    if (cmap.cur_charcode >= 0xFFFFFFFF)
    {
        cmap.valid = 0;
        return;
    }

    var p = dublicate_pointer(cmap.cmap.data);
    var base = p.pos;
    var start, end, start_id;
    var gindex;

    var char_code = cmap.cur_charcode + 1;
    for (var n = cmap.cur_group; n < cmap.num_groups; n++)
    {
        p.pos = base + 16 + 12 * n;
        start    = FT_NEXT_ULONG(p);
        end      = FT_NEXT_ULONG(p);
        start_id = FT_PEEK_ULONG(p);

        if (char_code < start)
            char_code = start;

        for ( ; char_code <= end; char_code++ )
        {
            gindex = (start_id + char_code - start);
            if (gindex != 0)
            {
                cmap.cur_charcode = char_code;
                cmap.cur_gindex   = gindex;
                cmap.cur_group    = n;
                return;
            }
        }
    }
    cmap.valid = 0;
}
function tt_cmap12_char_map_binary(cmap, _char_code, next)
{
    var gindex = 0;
    var p = dublicate_pointer(cmap.cmap.data);
    var base = p.pos;
    p.pos += 12;
    var num_groups = FT_PEEK_ULONG(p);
    var char_code = _char_code;
    var __char_code = _char_code;
    var start, end, start_id;
    var max, min, mid;

    if (num_groups == 0)
        return {gindex:gindex,char_code:__char_code};

    mid = num_groups;
    end = 0xFFFFFFFF;

    if (next != 0)
        char_code++;

    min = 0;
    max = num_groups;

    while (min < max)
    {
        mid = (min + max) >>> 1;
        p.pos = base + 16 + 12 * mid;

        start = FT_NEXT_ULONG(p);
        end = FT_NEXT_ULONG(p);

        if (char_code < start)
            max = mid;
        else if (char_code > end)
            min = mid + 1;
        else
        {
            start_id = FT_PEEK_ULONG(p);
            gindex = (start_id + char_code - start);
            break;
        }
    }

    if (next != 0)
    {
        if (char_code > end)
        {
            mid++;
            if (mid == num_groups)
                return 0;
        }

        cmap.valid = 1;
        cmap.cur_charcode = char_code;
        cmap.cur_group = mid;

        if (gindex == 0)
        {
            tt_cmap12_next(cmap);

            if (cmap.valid == 1)
                gindex = cmap.cur_gindex;
        }
        else
            cmap.cur_gindex = gindex;

        if (gindex != 0)
            __char_code = cmap.cur_charcode;
    }

    return {gindex:gindex,char_code:__char_code};
}
function tt_cmap12_char_index(cmap, char_code)
{
    return tt_cmap12_char_map_binary(cmap, char_code, 0).gindex;
}
function tt_cmap12_char_next(cmap, _char_code)
{
    var gindex = 0;
    var __char_code = _char_code;

    if (cmap.cur_charcode >= 0xFFFFFFFF)
        return {gindex:gindex,char_code:__char_code};

    if (cmap.valid == 1 && cmap.cur_charcode == _char_code)
    {
        tt_cmap12_next(cmap);
        if (1 == cmap.valid)
        {
            gindex = cmap.cur_gindex;
            if (gindex != 0)
                __char_code = cmap.cur_charcode;
        }
        else
            gindex = 0;
    }
    else
        return tt_cmap12_char_map_binary(cmap, _char_code, 1);

    return {gindex:gindex,char_code:__char_code};
}
function tt_cmap12_class_rec()
{
    this.clazz = create_cmap_class_rec(0,tt_cmap12_init,null,tt_cmap12_char_index,tt_cmap12_char_next,null,null,null,null,null);
    this.format = 12;
    this.validate = function(table, valid)
    {
        var base = table.pos;
        var p = dublicate_pointer(table);
        if (p.pos + 16 > valid.limit)
            return 8;
        p.pos = base + 4;
        var length = FT_NEXT_ULONG(p);
        p.pos = base + 12;
        var num_groups = FT_NEXT_ULONG(p);
        if (length > (valid.limit - base) || length < 16 + 12 * num_groups)
            return 8;
        var n, start, end, start_id, last = 0;
        for (n = 0; n < num_groups; n++)
        {
            start    = FT_NEXT_ULONG(p);
            end      = FT_NEXT_ULONG(p);
            start_id = FT_NEXT_ULONG(p);

            if (start > end)
                return 8;
            if (n > 0 && start <= last)
                return 8;
            if (valid.level >= 1)
            {
                if (start_id + end - start >= valid.num_glyphs)
                    return 16;
            }
            last = end;
        }
        return 0;
    }
    this.get_cmap_info = function(cmap, cmap_info)
    {
		cmap_info.format = 12;
		if (isSafariAppleDevices)
			return 0;
		
        var data = cmap.cmap.data;
        data.pos += 8;
        cmap_info.language = FT_PEEK_ULONG(data);
        data.pos -= 8;
        return 0;
    }
}
// cmap13 ---------------------------------------------------------------------------------
function TT_CMap13Rec()
{
    this.cmap = new TT_CMapRec();
    this.valid;
    this.cur_charcode;
    this.cur_gindex;
    this.cur_group;
    this.num_groups;

    this.type = 4;
}
function tt_cmap13_init(cmap, table)
{
    cmap.cmap.data = dublicate_pointer(table);
    table.pos += 12;
    cmap.num_groups = FT_PEEK_ULONG(table);
    table.pos -= 12;
    cmap.valid = 0;
    return 0;
}
function tt_cmap13_next(cmap)
{
    if (cmap.cur_charcode >= 0xFFFFFFFF)
    {
        cmap.valid = 0;
        return;
    }

    var p = dublicate_pointer(cmap.cmap.data);
    var base = p.pos;
    var start, end, glyph_id, char_code;
    var gindex;

    char_code = cmap.cur_charcode + 1;
    for (var n = cmap.cur_group; n < cmap.num_groups; n++ )
    {
        p.pos = base + 16 + 12 * n;
        start = FT_NEXT_ULONG(p);
        end = FT_NEXT_ULONG(p);
        glyph_id = FT_PEEK_ULONG(p);

        if (char_code < start)
            char_code = start;

        if ( char_code <= end )
        {
            gindex = glyph_id;
            if (gindex != 0)
            {
                cmap.cur_charcode = char_code;
                cmap.cur_gindex = gindex;
                cmap.cur_group = n;
                return;
            }
        }
    }
    cmap.valid = 0;
}
function tt_cmap13_char_map_binary(cmap, _char_code, next)
{
    var gindex = 0;
    var p = dublicate_pointer(cmap.cmap.data);
    var base = p.pos;
    p.pos += 12;
    var num_groups = FT_PEEK_ULONG(p);
    var char_code = _char_code;
    var __char_code = _char_code;
    var start, end;
    var max, min, mid;

    if (num_groups == 0)
        return {gindex:gindex,char_code:__char_code};

    mid = num_groups;
    end = 0xFFFFFFFF;

    if (next != 0)
        char_code++;

        min = 0;
        max = num_groups;

    while (min < max)
    {
        mid = (min + max) >>> 1;
        p.pos = base + 16 + 12 * mid;

        start = FT_NEXT_ULONG(p);
        end   = FT_NEXT_ULONG(p);

        if (char_code < start)
            max = mid;
        else if (char_code > end)
            min = mid + 1;
        else
        {
            gindex = FT_PEEK_ULONG(p);
            break;
        }
    }

    if (next != 0)
    {
        if (char_code > end)
        {
            mid++;
            if (mid == num_groups)
                return 0;
        }

        cmap.valid        = 1;
        cmap.cur_charcode = char_code;
        cmap.cur_group    = mid;

        if (gindex == 0)
        {
            tt_cmap13_next( cmap );
            if (cmap.valid == 1)
                gindex = cmap.cur_gindex;
        }
        else
            cmap.cur_gindex = gindex;

        if (gindex != 0)
            __char_code = cmap.cur_charcode;
    }

    return {gindex:gindex,char_code:__char_code};
}
function tt_cmap13_char_index(cmap, char_code)
{
    return tt_cmap13_char_map_binary(cmap, char_code, 0).gindex;
}
function tt_cmap13_char_next(cmap, _char_code)
{
    if (cmap.cur_charcode >= 0xFFFFFFFF)
        return {gindex:0,char_code:_char_code};

    var gindex;
    var __char_code = _char_code;
    if (cmap.valid == 1 && cmap.cur_charcode == _char_code)
    {
        tt_cmap13_next(cmap);
        if (cmap.valid == 1)
        {
            gindex = cmap.cur_gindex;
            if (gindex != 0)
                __char_code = cmap.cur_charcode;
        }
        else
            gindex = 0;
    }
    else
        return tt_cmap13_char_map_binary( cmap, _char_code, 1 );

    return {gindex:gindex,char_code:__char_code};
}
function tt_cmap13_class_rec()
{
    this.clazz = create_cmap_class_rec(0,tt_cmap13_init,null,tt_cmap13_char_index,tt_cmap13_char_next,null,null,null,null,null);
    this.format = 13;
    this.validate = function(table, valid)
    {
        var p = dublicate_pointer(table);
        var base = p.pos;

        if (base + 16 > valid.limit)
            return 8;

        p.pos = base + 4;
        var length = FT_NEXT_ULONG(p);
        p.pos = base + 12;
        var num_groups = FT_NEXT_ULONG(p);

        if (length > (valid.limit - base) || length < 16 + 12 * num_groups)
            return 8;

        var start, end, glyph_id, last = 0;
        for (var n = 0; n < num_groups; n++)
        {
            start    = FT_NEXT_ULONG(p);
            end      = FT_NEXT_ULONG(p);
            glyph_id = FT_NEXT_ULONG(p);

            if (start > end)
                return 8;

            if (n > 0 && start <= last)
                return 8;

            if (valid.level >= 1)
            {
                if (glyph_id >= valid.num_glyphs)
                    return 16;
            }

            last = end;
        }
        return 0;
    }
    this.get_cmap_info = function(cmap, cmap_info)
    {
		cmap_info.format = 13;
		if (isSafariAppleDevices)
			return 0;

        var data = cmap.data;
        data.pos += 8;
        cmap_info.language = FT_PEEK_ULONG(data);
        data.pos -= 8;
        return 0;
    }
}
// cmap14 ---------------------------------------------------------------------------------
function TT_CMap14Rec()
{
    this.cmap = new TT_CMapRec();
    this.num_selectors;
    this.max_results;
    this.results = null;

    this.type = 5;
}
function tt_cmap14_done(cmap)
{
    cmap.results = null;
}
function tt_cmap14_ensure(cmap, num_results, memory)
{
    var old_max = cmap.max_results;
    if (num_results > cmap.max_results)
    {
        var c = num_results - old_max;
        for (;c>0;c--)
            cmap.results[old_max+c-1] = 0;
        cmap.max_results = num_results;
    }
    return 0;
}
function tt_cmap14_init(cmap, table)
{
    cmap.cmap.data = dublicate_pointer(table);
    table.pos += 6;
    cmap.num_selectors = FT_PEEK_ULONG(table);
    table.pos -= 6;
    cmap.max_results   = 0;
    cmap.results = null;
    return 0;
}
function tt_cmap14_char_index(cmap,char_code)
{
    return 0;
}
function tt_cmap14_char_next(cmap, _char_code)
{
    return {gindex:0,char_code:0};
}
function tt_cmap14_char_map_def_binary(base, char_code)
{
    var p = dublicate_pointer(base);
    var numRanges = FT_PEEK_ULONG(p);
    var min = 0;
    var max = numRanges;

    while (min < max)
    {
        var mid = (min + max) >>> 1;
        p.pos = base.pos + 4 + 4 * mid;
        var start = FT_NEXT_UOFF3(p);
        var cnt = FT_NEXT_BYTE(p);

        if (char_code < start)
            max = mid;
        else if (char_code > start+cnt)
            min = mid + 1;
        else
            return 1;
    }
    return 0;
}
function tt_cmap14_char_map_nondef_binary(base, char_code)
{
    var p = dublicate_pointer(base);
    var numMappings = FT_PEEK_ULONG(p);
    var min = 0;
    var max = numMappings;

    while (min < max)
    {
        var mid = (min + max) >>> 1;
        p.pos = base.pos + 4 + 5 * mid;
        var uni = FT_NEXT_UOFF3(p);

        if (char_code < uni)
            max = mid;
        else if (char_code > uni)
            min = mid + 1;
        else
            return FT_PEEK_USHORT(p);
    }
    return 0;
}
function tt_cmap14_find_variant(base, variantCode)
{
    var p = dublicate_pointer(base);
    var numVar = FT_PEEK_ULONG(p);
    var min = 0;
    var max = numVar;

    while (min < max)
    {
        var mid = (min + max) >>> 1;
        p.pos = base.pos + 4 + 11 * mid;
        var varSel = FT_NEXT_UOFF3(p);

        if (variantCode < varSel)
            max = mid;
        else if (variantCode > varSel)
            min = mid + 1;
        else
            return p;
    }
    return null;
}
function tt_cmap14_char_var_index(cmap, ucmap, charcode, variantSelector)
{
    var base = dublicate_pointer(cmap.cmap.data);
    base.pos += 6;
    var p = tt_cmap14_find_variant(base, variantSelector);
    if (null == p)
        return 0;

    var defOff = FT_NEXT_ULONG(p);
    var nondefOff = FT_PEEK_ULONG(p);

    base.pos = cmap.cmap.data.pos + defOff;
    if (defOff != 0 && 0 != tt_cmap14_char_map_def_binary(base, charcode))
    {
        return ucmap.cmap.clazz.char_index(ucmap.cmap, charcode);
    }

    base.pos = cmap.cmap.data.pos + nondefOff;
    if (nondefOff != 0)
        return tt_cmap14_char_map_nondef_binary(base, charcode);

    return 0;
}
function tt_cmap14_char_var_isdefault(cmap, charcode, variantSelector)
{
    var base = dublicate_pointer(cmap.cmap.data);
    var base_pos = base.pos;
    base += 6;
    var p = tt_cmap14_find_variant(base, variantSelector);
    if (null == p)
        return -1;

    var defOff    = FT_NEXT_ULONG(p);
    var nondefOff = FT_NEXT_ULONG(p);

    base.pos = base_pos + defOff;
    if (defOff != 0 && 0 != tt_cmap14_char_map_def_binary(base, charcode))
        return 1;

    base.pos = base_pos + nondefOff;
    if (nondefOff != 0 && tt_cmap14_char_map_nondef_binary(base, charcode) != 0)
        return 0;

    return -1;
}
function tt_cmap14_variants(cmap, memory)
{
    var count = cmap.num_selectors;
    var p = dublicate_pointer(cmap.cmap.data);
    p.pos += 10;

    if (0 != tt_cmap14_ensure(cmap, (count + 1), memory))
        return null;

    var result = cmap.results;
    var i = 0;
    for (; i < count; i++)
    {
        result[i] = FT_NEXT_UOFF3(p);
        p.pos += 8;
    }
    result[i] = 0;

    p.data = result;
    p.pos = 0;
    return p;
}
function tt_cmap14_char_variants(cmap, memory, charCode)
{
    var count = cmap.num_selectors;
    var p = dublicate_pointer(cmap.cmap.data);
    var base_pos = p.pos;
    p.pos += 10;
    
    if (0 != tt_cmap14_ensure(cmap, (count + 1), memory))
        return null;

    var p1 = dublicate_pointer(p);
    var p2 = dublicate_pointer(p);

    var results = cmap.results;
    var q = 0;
    for (; count > 0; --count)
    {
        var varSel    = FT_NEXT_UOFF3(p);
        var defOff    = FT_NEXT_ULONG(p);
        var nondefOff = FT_NEXT_ULONG(p);

        p1.pos = base_pos + defOff;
        p2.pos = base_pos + nondefOff;
        if ((defOff != 0 && 0 != tt_cmap14_char_map_def_binary(p1, charCode)) ||
           (nondefOff != 0 && 0 != tt_cmap14_char_map_nondef_binary(p2, charCode)))
        {
            results[q] = varSel;
            q++;
        }
    }
    results[q] = 0;
    p.data = results;
    p.pos = 0;
    return p;
}
function tt_cmap14_def_char_count(_p)
{
    var p = dublicate_pointer(_p);
    var numRanges = FT_NEXT_ULONG(p);
    var tot = 0;
    p.pos += 3;
    for (; numRanges > 0; numRanges--)
    {
        tot += 1 + p.data[p.pos];
        p.pos += 4;
    }
    return tot;
}
function tt_cmap14_get_def_chars(cmap, _p, memory)
{
    var p = dublicate_pointer(_p);
    var cnt = tt_cmap14_def_char_count(p);
    var numRanges = FT_NEXT_ULONG(p);

    if (0 != tt_cmap14_ensure(cmap, (cnt + 1), memory))
        return null;

    var results = cmap.results;
    var q = 0;
    for (; numRanges > 0; --numRanges)
    {
        var uni = FT_NEXT_UOFF3(p);
        cnt = FT_NEXT_BYTE(p) + 1;
        do
        {
            results[q] = uni;
            uni  += 1;
            q    += 1;
        } while (--cnt != 0);
    }
    results[q] = 0;
    p.data = results;
    p.pos = 0;
    return p;
}
function tt_cmap14_get_nondef_chars(cmap, _p, memory)
{
    var p = dublicate_pointer(_p);
    var numMappings = FT_NEXT_ULONG(p);

    if (0 != tt_cmap14_ensure(cmap, (numMappings + 1), memory))
        return null;

    var ret = cmap.results;
    var i = 0;
    for (; i < numMappings; i++)
    {
        ret[i] = FT_NEXT_UOFF3(p);
        p.pos += 2;
    }
    ret[i] = 0;
    p.data = ret;
    p.pos = 0;
    return p;
}
function tt_cmap14_variant_chars(cmap, memory, variantSelector)
{
    var base = dublicate_pointer(cmap.cmap.data);
    var base_pos = base.pos;
    base.pos += 6;
    var p = tt_cmap14_find_variant(base, variantSelector);
    if (null == p)
        return null;

    var defOff = FT_NEXT_ULONG(p);
    var nondefOff = FT_NEXT_ULONG(p);

    if (defOff == 0 && nondefOff == 0)
        return null;

    base.pos = base_pos + nondefOff;
    if (defOff == 0)
        return tt_cmap14_get_nondef_chars(cmap, base, memory);
    base.pos = base_pos + defOff;
    if (nondefOff == 0)
        return tt_cmap14_get_def_chars(cmap, base, memory);

    var numRanges;
    var numMappings;
    var duni;
    var dcnt;
    var nuni;
    var dp;
    var di, ni, k;

    var _cmap_data = cmap.cmap.data;
    p = dublicate_pointer(_cmap_data);
    p.pos += nondefOff;
    dp = dublicate_pointer(_cmap_data);
    dp.pos += defOff;

    numMappings = FT_NEXT_ULONG(p);
    dcnt        = tt_cmap14_def_char_count(dp);
    numRanges   = FT_NEXT_ULONG(dp);

    if (numMappings == 0)
    {
        var __pp = dublicate_pointer(_cmap_data);
        __pp += defOff;
        return tt_cmap14_get_def_chars(cmap, __pp, memory);
    }
    if (dcnt == 0)
    {
        var __pp = dublicate_pointer(_cmap_data);
        __pp += nondefOff;
        return tt_cmap14_get_nondef_chars(cmap, __pp, memory);
    }

    if (0 != tt_cmap14_ensure(cmap, (dcnt + numMappings + 1), memory))
        return null;

    var ret = cmap.results;
    duni = FT_NEXT_UOFF3(dp);
    dcnt = FT_NEXT_BYTE(dp);
    di = 1;
    nuni = FT_NEXT_UOFF3(p);
    p.pos += 2;
    ni = 1;
    i = 0;

    for ( ;; )
    {
        if (nuni > duni + dcnt)
        {
            for (k = 0; k <= dcnt; k++)
                ret[i++] = duni + k;

            ++di;

            if (di > numRanges)
                break;

            duni = FT_NEXT_UOFF3(dp);
            dcnt = FT_NEXT_BYTE(dp);
        }
        else
        {
            if (nuni < duni)
                ret[i++] = nuni;
            ++ni;
            if (ni > numMappings)
                break;

            nuni = FT_NEXT_UOFF3(p);
            p.pos += 2;
        }
    }

    if (ni <= numMappings)
    {
        ret[i++] = nuni;
        while (ni < numMappings)
        {
            ret[i++] = FT_NEXT_UOFF3(p);
            p.pos += 2;
            ++ni;
        }
    }
    else if (di <= numRanges)
    {
        for (k = 0; k <= dcnt; k++)
            ret[i++] = duni + k;

        while (di < numRanges)
        {
            duni = FT_NEXT_UOFF3(dp);
            dcnt = FT_NEXT_BYTE(dp);

            for (k = 0; k <= dcnt; k++)
                ret[i++] = duni + k;
            ++di;
        }
    }
    ret[i] = 0;
    p.data = ret;
    p.pos = 0;
    return p;
}
function tt_cmap14_class_rec()
{
    this.clazz = create_cmap_class_rec(0,tt_cmap14_init,tt_cmap14_done,tt_cmap14_char_index,tt_cmap14_char_next,
        tt_cmap14_char_var_index,tt_cmap14_char_var_isdefault,tt_cmap14_variants,
        tt_cmap14_char_variants,tt_cmap14_variant_chars);
    this.format = 14;
    this.validate = function(table, valid)
    {
        var p = dublicate_pointer(table);
        var defp = dublicate_pointer(table);
        var base = p.pos;
        p.pos += 2;
        var length        = FT_NEXT_ULONG(p);
        var num_selectors = FT_NEXT_ULONG(p);

        if (length > (valid.limit - base) || length < 10 + 11 * num_selectors)
            return 8;

        var n, lastVarSel = 1;
        for ( n = 0; n < num_selectors; n++ )
        {
            var varSel = FT_NEXT_UOFF3(p);
            var defOff = FT_NEXT_ULONG(p);
            var nondefOff = FT_NEXT_ULONG(p);

            if (defOff >= length || nondefOff >= length)
                return 8;

            if (varSel < lastVarSel)
                return 8;

            lastVarSel = varSel + 1;
            if (defOff != 0)
            {
                defp.pos = base + defOff;
                var numRanges = FT_NEXT_ULONG(defp);
                var lastBase  = 0;

                if (defp.pos + numRanges * 4 > valid.limit)
                    return 8;

                for (var i = 0; i < numRanges; ++i)
                {
                    var _base = FT_NEXT_UOFF3(defp);
                    var cnt  = FT_NEXT_BYTE(defp);

                    if (_base + cnt >= 0x110000)
                        return 8;

                    if (_base < lastBase)
                        return 8;

                    lastBase = _base + cnt + 1;
                }
            }

            if (nondefOff != 0)
            {
                defp.pos = base + nondefOff;
                var numMappings = FT_NEXT_ULONG(defp);
                var lastUni = 0;

                if (numMappings * 4 > (valid.limit - defp.pos))
                    return 8;

                for (var i = 0; i < numMappings; ++i)
                {
                    var uni = FT_NEXT_UOFF3(defp);
                    var gid = FT_NEXT_USHORT(defp);

                    if ( uni >= 0x110000)
                        return 8;
                    if (uni < lastUni)
                        return 8;
                    lastUni = uni + 1;
                    if (valid.level >= 1 && gid >= valid.num_glyphs)
                        return 16;
                }
            }
        }

        return 0;
    }
    this.get_cmap_info = function(cmap, cmap_info)
    {
        cmap_info.format = 14;
        cmap_info.language = 0xFFFFFFFF;
        return 0;
    }
}
// finally
function tt_face_build_cmaps(face)
{
    var table = dublicate_pointer(face.cmap_table);

    if (null == table)
        return 8;

    var limit = table.pos + face.cmap_size;
    var p = dublicate_pointer(table);

    if (p.data == null || p.pos + 4 > limit)
        return 8;

    if (FT_NEXT_USHORT(p) != 0)
        return 8;

    var num_cmaps = FT_NEXT_USHORT(p);
    //#ifdef FT_MAX_CHARMAP_CACHEABLE
    if (num_cmaps > 15)
    {
    }
    //#endif

    var pclazz = FT_TT_CMAP_CLASSES_GET;
    var pclazz_len = pclazz.length;
    var clazz;
    for (; num_cmaps > 0 && p.pos + 8 <= limit; num_cmaps--)
    {
        var charmap = new FT_CharMapRec();
        charmap.platform_id = FT_NEXT_USHORT(p);
        charmap.encoding_id = FT_NEXT_USHORT(p);
        charmap.face        = face;
        charmap.encoding    = 0;
        var offset          = FT_NEXT_ULONG(p);

        if (offset && offset <= face.cmap_size - 2)
        {
            var cmap = dublicate_pointer(table);
            cmap.pos += offset;
            var format = FT_PEEK_USHORT(cmap);
            for (var i = 0; i < pclazz_len; i++)
            {
                clazz = pclazz[i];
                if (clazz.format == format)
                {
                    var valid = new TT_Validator();
                    valid.base = cmap;
                    valid.limit = limit;
                    valid.level = 0;
                    valid.error = 0;
                    valid.num_glyphs = face.max_profile.numGlyphs;

                    var error = clazz.validate(cmap, valid);
                    if (error == 0)
                    {
                        var ttcmap = FT_CMap_New(clazz, cmap, charmap);
                        if (null != ttcmap)
                        {
                            ttcmap.flags = 0;
                        }
                    }
                    break;
                }
            }
        }
    }
    return 0;
}
function tt_get_cmap_info(cmap, cmap_info)
{
    var clazz = __FT_CMapRec(cmap).clazz;
    return clazz.get_cmap_info(cmap, cmap_info);
}
/******************************************************************************/
// driver
/******************************************************************************/
function tt_face_load_sfnt_header_stub(face,stream,face_index,header)
{
    return 7;
}
function tt_face_load_directory_stub(face,stream,header)
{
    return 7;
}
function tt_face_load_hdmx_stub(face,stream)
{
    return 7;
}
function tt_face_free_hdmx_stub(face)
{
}
function tt_face_set_sbit_strike_stub(face,x_ppem,y_ppem)
{
    var req = new FT_Size_RequestRec();
    req.type = 0;
    req.width = x_ppem;
    req.height = y_ppem;
    req.horiResolution = 0;
    req.vertResolution = 0;

    var strikeindex = 0x7FFFFFFF;
    return tt_face_set_sbit_strike(face, req, strikeindex);
}

function tt_face_load_sbit_stub(face,stream)
{
    return 7;
}
function tt_face_free_sbit_stub(face)
{
}

function tt_face_load_charmap_stub(face,cmap,input)
{
    return 7;
}
function tt_face_free_charmap_stub(face,cmap)
{
    return 0;
}

function get_sfnt_table(face, tag)
{
    var table = null;
    switch ( tag )
    {
    case 0:
        table = face.header;
        break;
    case 3:
        table = face.horizontal;
        break;
    case 4:
        table = (face.vertical_info == 1) ? face.vertical : null;
        break;
    case 2:
        table = (face.os2.version == 0xFFFF) ? null : face.os2;
        break;
    case 5:
        table = face.postscript;
        break;
    case 1:
        table = face.max_profile;
        break;
    case 6:
        table = (face.pclt.Version != 0) ? face.pclt : null;
        break;
    default:
        break;
    }
    return table;
}
function sfnt_table_info(face, idx, tag)
{
    if (tag != null)
        return {tag:0,offset:0,length:face.num_tables};

    if (idx >= face.num_tables)
        return null;
    var t = face.dir_tables[idx];
    return {tag:t.Tag,offset:t.Offset,length:t.Length};
}
function ft_mem_strcpyn(dst, src, size)
{
    var len = src.length;
    var ret = 1;
    if (len > size)
    {
        len = size;
        ret = 0;
    }
    var i=0;
    while (len > 1)
    {
        dst[dst.pos + i] = src.charCodeAt(i);
        i++;
        size--;
    }
    dst[dst.pos + i] = 0;
    return ret;
}
function sfnt_get_glyph_name(face, glyph_index, buffer, buffer_max)
{
    var gname = tt_face_get_ps_name(face, glyph_index);
    var error = FT_Error;
    if (error == 0)
        ft_mem_strcpyn(buffer, gname, buffer_max);
    return error;
}
function sfnt_get_name_index(face, glyph_name)
{
    var max_gid = 0xFFFFFFFF;
    if (face.num_glyphs < 0)
        return 0;
    else if (face.num_glyphs < 0xFFFFFFFF)
        max_gid = face.num_glyphs;
    for (var i = 0; i < max_gid; i++)
    {
        var gname = tt_face_get_ps_name(face, i);
        var error = FT_Error;
        if (error != 0)
            continue;

        if (glyph_name == gname)
            return i;
    }
    return 0;
}
function sfnt_get_ps_name(face)
{
    var n, found_win, found_apple;
    var result = "";

    if (face.postscript_name != "")
        return face.postscript_name;

    found_win   = -1;
    found_apple = -1;

    var num_faces = face.num_faces;
    for (n = 0; n < num_faces; n++)
    {
        var name = face.name_table.names[n];
        if (name.nameID == 6 && name.stringLength > 0)
        {
            if (name.platformID == 3 && name.encodingID == 1 && name.languageID == 0x409)
                found_win = n;

            if (name.platformID == 1 && name.encodingID == 0 && name.languageID == 0)
                found_apple = n;
        }
    }

    if (found_win != -1)
    {
        var stream = face.name_table.stream;
        var name = face.name_table.names[found_win];
        var len = parseInt(name.stringLength / 2);

        var error = stream.Seek(name.stringOffset);
        if (error == 0)
            error = stream.EnterFrame(name.stringLength);
        if (error != 0)
        {
            name.stringOffset = 0;
            name.stringLength = 0;
            face.postscript_name = "";
            return "";
        }
        var d = stream.data;
        var cur = stream.cur;
        for (; len > 0; len--, cur += 2)
        {
            if (d[cur] == 0 && d[cur+1] >= 32 && d[cur+1] < 128)
                result += String.fromCharCode(d[cur+1]);
        }
        stream.ExitFrame();
        face.postscript_name = result;
        return result;
    }

    if (found_apple != -1)
    {
        var stream = face.name_table.stream;
        var name = face.name_table.names[found_apple];
        var len = name.stringLength;

        var error = stream.Seek(name.stringOffset);
        if (error == 0)
        {
            result = stream.ReadString1(name.stringLength);
            error = FT_Error;
        }
        if (error != 0)
        {
            name.stringOffset = 0;
            name.stringLength = 0;
            face.postscript_name = "";
            return "";
        }

        face.postscript_name = result;
        return result;
    }

    face.postscript_name = result;
    return result;
}

var sfnt_service_glyph_dict = new FT_Service_GlyphDictRec(sfnt_get_glyph_name,sfnt_get_name_index);
var sfnt_service_ps_name = new FT_Service_PsFontNameRec(sfnt_get_ps_name);
var tt_service_get_cmap_info = new FT_Service_TTCMapsRec(tt_get_cmap_info);

var tt_cmap_classes = new Array(9);
tt_cmap_classes[0] = new tt_cmap0_class_rec();
tt_cmap_classes[1] = new tt_cmap2_class_rec();
tt_cmap_classes[2] = new tt_cmap4_class_rec();
tt_cmap_classes[3] = new tt_cmap6_class_rec();
tt_cmap_classes[4] = new tt_cmap8_class_rec();
tt_cmap_classes[5] = new tt_cmap10_class_rec();
tt_cmap_classes[6] = new tt_cmap12_class_rec();
tt_cmap_classes[7] = new tt_cmap13_class_rec();
tt_cmap_classes[8] = new tt_cmap14_class_rec();

var sfnt_service_sfnt_table = new FT_Service_SFNT_TableRec(tt_face_load_any,get_sfnt_table,sfnt_table_info);
var sfnt_service_bdf = new FT_Service_BDFRec(sfnt_get_charset_id,tt_face_find_bdf_prop);

var sfnt_services = new Array(5);
sfnt_services[0] = new FT_ServiceDescRec(FT_SERVICE_ID_SFNT_TABLE,sfnt_service_sfnt_table);
sfnt_services[1] = new FT_ServiceDescRec(FT_SERVICE_ID_POSTSCRIPT_FONT_NAME,sfnt_service_ps_name);
sfnt_services[2] = new FT_ServiceDescRec(FT_SERVICE_ID_GLYPH_DICT,sfnt_service_glyph_dict);
sfnt_services[3] = new FT_ServiceDescRec(FT_SERVICE_ID_BDF,sfnt_service_bdf);
sfnt_services[4] = new FT_ServiceDescRec(FT_SERVICE_ID_TT_CMAP,tt_service_get_cmap_info);

function tt_face_get_name(face, nameid)
{
    FT_Error = 0;
    var found_apple         = -1;
    var found_apple_roman   = -1;
    var found_apple_english = -1;
    var found_win           = -1;
    var found_unicode       = -1;

    var is_english = false;
    var convert = null;
    var rec = null;
    var num_names = face.num_names;
    var n = 0;
    for (; n < face.num_names; n++)
    {
        rec = face.name_table.names[n];
        if (rec.nameID == nameid && rec.stringLength > 0)
        {
            switch (rec.platformID)
            {
            case 0:
            case 2:
                found_unicode = n;
                break;

            case 1:
                if ( rec.languageID == 0)
                    found_apple_english = n;
                else if (rec.encodingID == 0)
                    found_apple_roman = n;
                break;

            case 3:
                if (found_win == -1 || (rec.languageID & 0x3FF) == 0x009)
                {
                    switch ( rec.encodingID )
                    {
                    case 0:
                    case 1:
                    case 10:
                        is_english = ((rec.languageID & 0x3FF) == 0x009) ? true : false;
                        found_win  = n;
                        break;

                    default:
                        break;
                    }
                }
                break;
            default:
                break;
            }
        }
    }

    found_apple = found_apple_roman;
    if (found_apple_english >= 0)
        found_apple = found_apple_english;

    if (found_win >= 0 && !(found_apple >= 0 && false === is_english))
    {
        rec = face.name_table.names[found_win];
        switch (rec.encodingID)
        {
        case 1:
        case 0:
            convert = tt_name_entry_ascii_from_utf16;
            break;

        case 10:
            convert = tt_name_entry_ascii_from_utf16;
            break;

        default:
            break;
        }
    }
    else if (found_apple >= 0)
    {
        rec     = face.name_table.names[found_apple];
        convert = tt_name_entry_ascii_from_other;
    }
    else if (found_unicode >= 0)
    {
        rec     = face.name_table.names[found_unicode];
        convert = tt_name_entry_ascii_from_utf16;
    }

    if (rec && convert)
    {
        if (rec.string == null)
        {
            var stream = face.name_table.stream;
            FT_Error = stream.Seek(rec.stringOffset);
            if (FT_Error == 0)
            {
                rec.string = stream.ReadArray(rec.stringLength);
            }
            if (FT_Error != 0 || null == rec.string)
                return "";
        }
        return convert(rec);
    }
    return "";
}
/* convert an Apple Roman or symbol name entry to ASCII */
function tt_name_entry_ascii_from_utf16(entry)
{
    var string = "";
    var p = entry.string;
    var len = parseInt(entry.stringLength / 2);
    if (len > p.length)
        len = p.length;

    var code = 0;
    for (var n = 0; n < len; n++)
    {
        code = p[2*n] << 8 | p[2*n+1];
        if (code < 32 || code > 127)
            code = 63;

        string += String.fromCharCode(code);
    }
    return string;
}

/* convert an Apple Roman or symbol name entry to ASCII */
function tt_name_entry_ascii_from_other(entry)
{
    var string = "";
    var p = entry.string;
    var len = entry.stringLength;
    if (len > p.length)
        len = p.length;

    var code = 0;
    for (var n = 0; n < len; n++)
    {
        code = p[n];
        if ( code < 32 || code > 127 )
            code = 63;

        string += String.fromCharCode(code);
    }
    return string;
}

function sfnt_init_face(stream, face, face_index)
{
    var error = 0;
    var library = face.driver.library;

    var sfnt = face.sfnt;
    if (null == sfnt)
    {
        sfnt = library.FT_Get_Module_Interface("sfnt");
        if (null == sfnt)
            return 3;

        face.sfnt = sfnt;
        face.goto_table = sfnt.goto_table;
    }

    face.psnames = FT_FACE_FIND_GLOBAL_SERVICE(face, "postscript-cmaps");

    error = sfnt_open_font(stream, face);
    if (error != 0)
        return error;

    if (face_index < 0)
        face_index = 0;

    if (face_index >= face.ttc_header.count)
        return 6;

    error = stream.Seek(face.ttc_header.offsets[face_index])
    if (error != 0)
        return error;

    /* check that we have a valid TrueType file */
    error = sfnt.load_font_dir(face, stream);
    if (error != 0)
        return error;

    face.num_faces = face.ttc_header.count;
    face.face_index = face_index;

    return error;
}
function sfnt_load_face(stream, face, face_index)
{
    var error = 0;
    var psnames_error = 0;

    var has_outline = false;
    var is_apple_sbit = false;
    var ignore_preferred_family = false;
    var ignore_preferred_subfamily = false;

    var sfnt = face.sfnt;

    if (face.internal.incremental_interface != null)
        has_outline = true;
    else if (null != tt_face_lookup_table(face, 1735162214))
        has_outline = true;
    else if (null != tt_face_lookup_table(face, 1128678944))
        has_outline = true;

    if (false === has_outline && sfnt.load_bhed != null)
    {
        error = sfnt.load_bhed(face, stream);
        is_apple_sbit = (error == 0) ? false : true;
    }

    if (false === is_apple_sbit)
    {
        error = sfnt.load_head(face, stream);
        if (error != 0)
            return error;
    }

    if (0 == face.header.Units_Per_EM)
        return 8;

    error = sfnt.load_maxp(face, stream);
    error = sfnt.load_cmap(face, stream);

    error = sfnt.load_name(face, stream);
    error = sfnt.load_post(face, stream);

    psnames_error = error;

    if (false === is_apple_sbit)
    {
        error = sfnt.load_hhea(face, stream, 0);
        if (error == 0)
        {
            error = sfnt.load_hmtx(face, stream, 0);
            if (error == 142)
            {
                error = 147;

                //#ifdef FT_CONFIG_OPTION_INCREMENTAL
                if (face.internal.incremental_interface &&
                    face.internal.incremental_interface.funcs.get_glyph_metrics)
                {
                    face.horizontal.number_Of_HMetrics = 0;
                    error = 0;
                }
                //#endif
            }
        }
        else if (error == 142)
        {
            if (face.format_tag == 1953658213)
            {
                has_outline = false;
                error       = 0;
            }
            else
            {
                error = 143;

                //#ifdef FT_CONFIG_OPTION_INCREMENTAL
                if (face.internal.incremental_interface &&
                    face.internal.incremental_interface.funcs.get_glyph_metrics)
                {
                    face.horizontal.number_Of_HMetrics = 0;
                    error = 0;
                }
                //#endif
            }
        }

        if (error != 0)
            return error;

        error = sfnt.load_hhea(face, stream, 1);
        if (error == 0)
        {
            error = sfnt.load_hmtx(face, stream, 1);
            if (error == 0)
                face.vertical_info = 1;
        }

        if (error != 0 && error != 142)
            return error;

        error = sfnt.load_os2(face, stream);
        if (error != 0)
        {
            /* we treat the table as missing if there are any errors */
            face.os2.version = 0xFFFF;
        }
    }

    if (sfnt.load_eblc)
    {
        error = sfnt.load_eblc(face, stream);
        if (error != 0)
        {
            if (error == 142)
                error = 0;
            else
                return error;
        }
    }

    error = sfnt.load_pclt(face, stream);
    if (error != 0)
    {
        if (error != 142)
            return error;

        face.pclt.Version = 0;
    }

    error = sfnt.load_gasp(face, stream);
    error = sfnt.load_kern(face, stream);

    face.num_glyphs = face.max_profile.numGlyphs;

    face.family_name = "";
    face.style_name = "";

    if (face.os2.version != 0xFFFF && (face.os2.fsSelection & 256) != 0)
    {
        /*
        if (false ==  ignore_preferred_family)
        {
            face.family_name = tt_face_get_name(face, 16);
            error = FT_Error;
            if (error != 0)
                return error;
        }
        */
        if ("" == face.family_name)
        {
            face.family_name = tt_face_get_name(face, 1);
            error = FT_Error;
            if (error != 0)
                return error;
        }

        /*
        if (false == ignore_preferred_subfamily)
        {
            face.style_name = tt_face_get_name(face, 17);
            error = FT_Error;
            if (error != 0)
                return error;
        }
        */
        if ("" == face.style_name)
        {
            face.style_name = tt_face_get_name(face, 2);
            error = FT_Error;
            if (error != 0)
                return error;
        }
    }
    else
    {
        face.family_name = tt_face_get_name(face, 21);
        error = FT_Error;
        if (error != 0)
            return error;

        /*
        if (face.family_name == "" && false == ignore_preferred_family)
        {
            face.family_name = tt_face_get_name(face, 16);
            error = FT_Error;
            if (error != 0)
                return error;
        }
        */
        if (face.family_name == "")
        {
            face.family_name = tt_face_get_name(face, 1);
            error = FT_Error;
            if (error != 0)
                return error;
        }

        face.style_name = tt_face_get_name(face, 22);
        error = FT_Error;
        if (error != 0)
            return error;

        /*
        if (face.style_name == "" && false == ignore_preferred_subfamily)
        {
            face.style_name = tt_face_get_name(face, 17);
            error = FT_Error;
            if (error != 0)
                return error;
        }
        */
        if (face.style_name == "")
        {
            face.style_name = tt_face_get_name(face, 2);
            error = FT_Error;
            if (error != 0)
                return error;
        }
    }

    // face_flags
    var flags = face.face_flags;
    if (has_outline === true)
        flags |= 1;

    flags |= (8 | 16);

    //#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
    if (psnames_error == 0 && face.postscript.FormatType != 0x00030000)
        flags |= 512;
    //#endif

    /* fixed width font? */
    if (face.postscript.isFixedPitch)
        flags |= 4;

    /* vertical information? */
    if (face.vertical_info)
        flags |= 32;

    /* kerning available ? */
    if (face.kern_avail_bits != 0)
        flags |= 64;

    //#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
    /* Don't bother to load the tables unless somebody asks for them. */
    /* No need to do work which will (probably) not be used.          */
    if (null != tt_face_lookup_table(face, 1735162214) &&
        null != tt_face_lookup_table(face, 1719034226) &&
        null != tt_face_lookup_table(face, 1735811442))
        flags |= 256;
    //#endif

    face.face_flags = flags;

    // Compute style flags.
    flags = 0;
    if (has_outline === true && face.os2.version != 0xFFFF)
    {
        if ((face.os2.fsSelection & 512) != 0)
            flags |= 1;
        else if ((face.os2.fsSelection & 1) != 0)
            flags |= 1;

        if ((face.os2.fsSelection & 32) != 0)
            flags |= 2;
    }
    else
    {
        if ((face.header.Mac_Style & 1) != 0)
            flags |= 2;

        if ((face.header.Mac_Style & 2) != 0)
            flags |= 1;
    }

    face.style_flags = flags;

    // TODO: ---
    tt_face_build_cmaps(face);

    for (var m = 0; m < face.num_charmaps; m++)
    {
        var charmap = __FT_CharmapRec(face.charmaps[m]);
        charmap.encoding = 0;
        charmap.encoding = sfnt_find_encoding(charmap.platform_id, charmap.encoding_id);
    }

    //#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
    var count = face.num_sbit_strikes;

    if (count > 0)
    {
        var em_size = face.header.Units_Per_EM;
        var avgwidth = face.os2.xAvgCharWidth;
        var metrics = new FT_Size_Metrics();

        if (em_size == 0 || face.os2.version == 0xFFFF)
        {
            avgwidth = 0;
            em_size = 1;
        }

        face.available_sizes = new Array(count);

        for (var i = 0; i < count; i++)
        {
            face.available_sizes[i] = new FT_Bitmap_Size();
            var bsize = face.available_sizes[i];

            error = sfnt.load_strike_metrics(face, i, metrics);
            if (error != 0)
                return error;

            bsize.height = (metrics.height >>> 6) & 0xFFFF;
            bsize.width = parseInt((avgwidth * metrics.x_ppem + parseInt(em_size / 2)) / em_size) & 0xFFFF;

            bsize.x_ppem = metrics.x_ppem << 6;
            bsize.y_ppem = metrics.y_ppem << 6;

            /* assume 72dpi */
            bsize.size   = metrics.y_ppem << 6;
        }

        face.face_flags |= 2;
        face.num_fixed_sizes = count;
    }

    //#endif TT_CONFIG_OPTION_EMBEDDED_BITMAPS

    /* a font with no bitmaps and no outlines is scalable; */
    /* it has only empty glyphs then                       */
    if (((face.face_flags & 2) == 0) &&
        ((face.face_flags & 1) == 0))
        face.face_flags |= 1;

    // Set up metrics
    if ((face.face_flags & 1) != 0)
    {
        face.bbox.xMin    = face.header.xMin;
        face.bbox.yMin    = face.header.yMin;
        face.bbox.xMax    = face.header.xMax;
        face.bbox.yMax    = face.header.yMax;
        face.units_per_EM = face.header.Units_Per_EM;

        face.ascender  = face.horizontal.Ascender;
        face.descender = face.horizontal.Descender;

        face.height = (face.ascender - face.descender + face.horizontal.Line_Gap);

        if (face.ascender == 0 && face.descender == 0)
        {
            if (face.os2.version != 0xFFFF)
            {
                if (face.os2.sTypoAscender || face.os2.sTypoDescender)
                {
                    face.ascender  = face.os2.sTypoAscender;
                    face.descender = face.os2.sTypoDescender;

                    face.height = (face.ascender - face.descender + face.os2.sTypoLineGap);
                }
                else
                {
                    face.ascender  = face.os2.usWinAscent;
                    face.descender = -face.os2.usWinDescent;

                    face.height = (face.ascender - face.descender);
                }
            }
        }

        face.max_advance_width  = face.horizontal.advance_Width_Max;
        face.max_advance_height = ((face.vertical_info != 0) ? face.vertical.advance_Height_Max : face.height);

        face.underline_position  = face.postscript.underlinePosition - parseInt(face.postscript.underlineThickness / 2);
        face.underline_thickness = face.postscript.underlineThickness;
    }
    return error;
}
function sfnt_done_face()
{
}

function sfnt_find_encoding(platform_id, encoding_id)
{
    switch (platform_id)
    {
        case 2:
        {
            return 1970170211;
        }
        case 0:
        {
            return 1970170211;
        }
        case 1:
        {
            if (0 == encoding_id)
                return 1634889070;
            break;
        }
        case 3:
        {
            if (0 == encoding_id)
                return 1937337698;
            if (10 == encoding_id)
                return 1970170211;
            if (1 == encoding_id)
                return 1970170211;
            if (2 == encoding_id)
                return 1936353651;
            if (3 == encoding_id)
                return 1734484000;
            if (4 == encoding_id)
                return 1651074869;
            if (5 == encoding_id)
                return 2002873971;
            if (6 == encoding_id)
                return 1785686113;
            break;
        }
        default:
            break;
    }
    return 0;
}

function sfnt_open_font(stream, face)
{
    var error = 0;

    face.ttc_header.tag     = 0;
    face.ttc_header.version = 0;
    face.ttc_header.count   = 0;

    var offset = stream.pos;
    var tag = stream.ReadULong();
    error = FT_Error;
    FT_Error = 0;

    if (error != 0)
      return error;

    if (tag != 0x00010000 && tag != 1953784678 && tag != 1330926671 &&
         tag != 1953658213 && tag != 1954115633 && tag != 0x00020000)
        return 2;

    face.ttc_header.tag = 1953784678;

    if (tag == 1953784678)
    {
        error = stream.EnterFrame(8);
        if (error != 0)
            return error;

        face.ttc_header.version = stream.GetLong();
        face.ttc_header.count = stream.GetLong();

        stream.ExitFrame();

        if (face.ttc_header.count == 0)
            return 8;

        var ul = FT_Common.IntToUInt(face.ttc_header.count);
        if (ul > (stream.size / (28 + 4)))
            return 10;

        face.ttc_header.offsets = new Array(ul);
        error = stream.EnterFrame(4*ul);

        if (error != 0)
            return error;

        for (var n = 0; n < ul; n++)
            face.ttc_header.offsets[n] = stream.GetULong();

        stream.ExitFrame();
    }
    else
    {
        face.ttc_header.version = 1 << 16;
        face.ttc_header.count = 1;

        face.ttc_header.offsets = new Array(1);
        face.ttc_header.offsets[0] = offset;
    }

    return error;
}

function _sfnt_interface()
{
    this.goto_table = tt_face_goto_table;

    this.init_face = sfnt_init_face;
    this.load_face = sfnt_load_face;
    this.done_face = sfnt_done_face;
    this.get_interface = sfnt_get_interface;
    
    this.load_any = tt_face_load_any;

    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    this.load_sfnt_header = tt_face_load_sfnt_header_stub;
    this.load_directory = tt_face_load_directory_stub;
    //#endif

    this.load_head = tt_face_load_head;
    this.load_hhea = tt_face_load_hhea;
    this.load_cmap = tt_face_load_cmap;
    this.load_maxp = tt_face_load_maxp;
    this.load_os2 = tt_face_load_os2;
    this.load_post = tt_face_load_post;

    this.load_name = tt_face_load_name;
    this.free_name = tt_face_free_name;

    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    this.load_hdmx_stub = tt_face_load_hdmx_stub;
    this.free_hdmx_stub = tt_face_free_hdmx_stub;
    //#endif

    this.load_kern = tt_face_load_kern;

    this.load_gasp = tt_face_load_gasp;
    this.load_pclt = tt_face_load_pclt;

    this.load_bhed = tt_face_load_bhed;

    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    this.set_sbit_strike_stub = tt_face_set_sbit_strike_stub;
    this.load_sbits_stub = tt_face_load_sbit_stub;

    this.find_sbit_image = tt_find_sbit_image;
    this.load_sbit_metrics = tt_load_sbit_metrics;
    //#endif

    this.load_sbit_image = tt_face_load_sbit_image;

    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    this.free_sbits_stub = tt_face_free_sbit_stub;
    //#endif

    this.get_psname = tt_face_get_ps_name;
    this.free_psnames = tt_face_free_ps_names;

    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    this.load_charmap_stub = tt_face_load_charmap_stub;
    this.free_charmap_stub = tt_face_free_charmap_stub;
    //#endif

    this.get_kerning = tt_face_get_kerning;

    this.load_font_dir = tt_face_load_font_dir;
    this.load_hmtx = tt_face_load_hmtx;

    this.load_eblc = tt_face_load_eblc;
    this.free_eblc = tt_face_free_eblc;

    this.set_sbit_strike = tt_face_set_sbit_strike;
    this.load_strike_metrics = tt_face_load_strike_metrics;

    this.get_metrics = tt_face_get_metrics;
}
var sfnt_interface = new _sfnt_interface();

/******************************************************************************/
// pic
/******************************************************************************/
var FT_SFNT_SERVICES_GET            = sfnt_services;
var FT_SFNT_SERVICE_GLYPH_DICT_GET  = sfnt_service_glyph_dict;
var FT_SFNT_SERVICE_PS_NAME_GET     = sfnt_service_ps_name;
var FT_TT_SERVICE_GET_CMAP_INFO_GET = tt_service_get_cmap_info;
var FT_TT_CMAP_CLASSES_GET          = tt_cmap_classes;
var FT_SFNT_SERVICE_SFNT_TABLE_GET  = sfnt_service_sfnt_table;
var FT_SFNT_SERVICE_BDF_GET         = sfnt_service_bdf;
var FT_SFNT_INTERFACE_GET           = sfnt_interface;

function sfnt_get_interface(module,name)
{
    return ft_service_list_lookup(FT_SFNT_SERVICES_GET, name);
}

function create_sfnt_module(library)
{
    var sfnt_mod = new FT_Module();
    sfnt_mod.clazz = new FT_Module_Class();

    var clazz = sfnt_mod.clazz;
    clazz.flags = 0;
    clazz.name = "sfnt";
    clazz.version = 0x10000;
    clazz.requires = 0x20000;

    clazz.module_interface = FT_SFNT_INTERFACE_GET;
    clazz.init = null;
    clazz.done = null;

    clazz.get_interface = sfnt_get_interface;

    sfnt_mod.library = library;
    sfnt_mod.memory = library.Memory;
    sfnt_mod.generic = null;

    return sfnt_mod;
}


function CRasterMemory()
{
    this.width = 0;
    this.height = 0;
    this.pitch = 0;

    this.m_oBuffer = null;
    this.CheckSize = function(w, h)
    {
        if (this.width < (w + 1) || this.height < (h + 1))
        {
            this.width = Math.max(this.width, w + 1);
            this.pitch = 4 * this.width;
            this.height = Math.max(this.height, h + 1);

            this.m_oBuffer = null;
            this.m_oBuffer = g_memory.ctx.createImageData(this.width, this.height);
        }
    }
}
var raster_memory = new CRasterMemory();

// outline ---
function _FT_Outline_Funcs_Gray()
{
    this.move_to = function(to, worker)
    {
        /* record current cell, if any */
        var err = gray_record_cell(worker);
        if (err == -100)
            return -100;

        /* start to a new position */
        var x = to.x << 2;
        var y = to.y << 2;

        err = gray_start_cell(worker, x >> 8, y >> 8);

        worker.x = x;
        worker.y = y;
        return err;
    }

    this.line_to = function(to, worker)
    {
        return gray_render_line(worker, to.x << 2, to.y << 2);
    }

    this.conic_to = function(control, to, worker)
    {
        return gray_render_conic(worker, control, to);
    }

    this.cubic_to = function(control1, control2, to, worker)
    {
        return gray_render_cubic(worker, control1, control2, to);
    }

    this.shift = 0;
    this.delta = 0;
}
var ft_outline_funcs_gray = new _FT_Outline_Funcs_Gray();

function FT_Outline_Decompose(outline, func_interface, user)
{
    if (!outline || !func_interface)
        return 6;

    var v_last      = new FT_Vector();
    var v_control   = new FT_Vector();
    var v_start     = new FT_Vector();

    var point;
    var limit;

    var tags = 0;
    var first = 0;
    var tag = 0;

    var shift = func_interface.shift;
    var delta = func_interface.delta;

    var error = 0;

    var count = outline.n_contours;
    var _c = outline.contours;
    var _p = outline.points;
    var _t = outline.tags;
    for (var n = 0; n < count; n++)
    {
        var last = _c[n];
        if (last < 0)
            return 20;
        limit = last;

        v_start.x = (_p[first].x << shift) - delta;
        v_start.y = (_p[first].y << shift) - delta;

        v_last.x = (_p[last].x << shift) - delta;
        v_last.y = (_p[last].y << shift) - delta;

        v_control.x = v_start.x;
        v_control.y = v_start.y;

        point = first;
        tags  = first;
        tag   = _t[tags] & 3;

        /* A contour cannot start with a cubic control point! */
        if (tag == 2)
            return 20;

        /* check first point to determine origin */
        if (tag == 0)
        {
            /* first point is conic control.  Yes, this happens. */
            if ((_t[last] & 3) == 1)
            {
                /* start at last point if it is on the curve */
                v_start.x = v_last.x;
                v_start.y = v_last.y;
                limit--;
            }
            else
            {
                /* if both first and last points are conic,         */
                /* start at their middle and record its position    */
                /* for closure                                      */
                v_start.x = parseInt((v_start.x + v_last.x) / 2);
                v_start.y = parseInt((v_start.y + v_last.y) / 2);

                v_last.x = v_start.x;
                v_last.y = v_start.y;
            }
            point--;
            tags--;
        }

        error = func_interface.move_to(v_start, user);
        if (error != 0)
            return error;

        var isClose = 0;
        while (point < limit)
        {
            point++;
            tags++;

            tag = _t[tags] & 3;
            switch ( tag )
            {
                case 1:  /* emit a single line_to */
                {
                    var vec = new FT_Vector();

                    vec.x = (_p[point].x << shift) - delta;
                    vec.y = (_p[point].y << shift) - delta;

                    error = func_interface.line_to(vec, user);
                    if (0 != error)
                        return error;
                    continue;
                }

                case 0:  /* consume conic arcs */
                    v_control.x = (_p[point].x << shift) - delta;
                    v_control.y = (_p[point].y << shift) - delta;

                    var isCont = 0;
                    while (true)
                    {
                        if (point < limit)
                        {
                            var vec = new FT_Vector();
                            var v_middle = new FT_Vector();

                            point++;
                            tags++;
                            tag = _t[tags] & 3;

                            vec.x = (_p[point].x << shift) - delta;
                            vec.y = (_p[point].y << shift) - delta;

                            if (tag == 1)
                            {
                                error = func_interface.conic_to(v_control, vec, user);
                                if (0 != error)
                                    return error;
                                isCont = 1;
                                break;
                            }

                            if (tag != 0)
                                return 20;

                            v_middle.x = parseInt((v_control.x + vec.x) / 2);
                            v_middle.y = parseInt((v_control.y + vec.y) / 2);

                            error = func_interface.conic_to(v_control, v_middle, user);
                            if (0 != error)
                                return error;

                            v_control.x = vec.x;
                            v_control.y = vec.y;

                            continue;
                        }
                        break;
                    }
                    if (1 == isCont/* && (point < limit)*/)
                        continue;

                    error = func_interface.conic_to(v_control, v_start, user);
                    isClose = 1;
                    break;

                default:  /* FT_CURVE_TAG_CUBIC */
                {
                    var vec1 = new FT_Vector();
                    var vec2 = new FT_Vector();

                    if ((point + 1 > limit) || (_t[tags+1]&3) != 2)
                        return 20;

                    point += 2;
                    tags  += 2;

                    vec1.x = (_p[point-2].x << shift) - delta;
                    vec1.y = (_p[point-2].y << shift) - delta;

                    vec2.x = (_p[point-1].x << shift) - delta;
                    vec2.y = (_p[point-1].y << shift) - delta;

                    if (point <= limit)
                    {
                        var vec = new FT_Vector();
                        vec.x = (_p[point].x << shift) - delta;
                        vec.y = (_p[point].y << shift) - delta;

                        error = func_interface.cubic_to(vec1, vec2, vec, user);
                        if (0 != error)
                            return error;
                        continue;
                    }

                    error = func_interface.cubic_to(vec1, vec2, v_start, user);
                    isClose = 1;
                    break;
                }
            }

            if (isClose == 1)
                break;
        }

        if (error != 0)
            return error;

        /* close the contour with a line segment */
        if (0 == isClose)
            error = func_interface.line_to(v_start, user);

        if (error != 0)
            return error;

        isClose = 0;
        first = last + 1;
    }
    return 0;
}

function FT_Outline_Get_Orientation(outline)
{
    if (outline == null || outline.n_points <= 0)
        return 0;

    /* We use the nonzero winding rule to find the orientation.       */
    /* Since glyph outlines behave much more `regular' than arbitrary */
    /* cubic or quadratic curves, this test deals with the polygon    */
    /* only which is spanned up by the control points.                */
    var points = outline.points;

	var v_cur;
    var first = 0;
    var area = 0;
    for (var c = 0; c < outline.n_contours; c++)
    {
        var last = outline.contours[c];
        var v_prev = points[last];

        for (var n = first; n <= last; n++)
        {
            v_cur = points[n];
            area += (v_cur.y - v_prev.y) * (v_cur.x + v_prev.x);
            v_prev = v_cur;
        }

        first = last + 1;
    }

    if (area > 0)
        return 1;
    else if ( area < 0 )
        return 0;
    return 2;
}

function FT_Outline_Get_Orientation_Cur(outline, base)
{
    if (outline == null || outline.n_points <= 0)
        return 0;

    /* We use the nonzero winding rule to find the orientation.       */
    /* Since glyph outlines behave much more `regular' than arbitrary */
    /* cubic or quadratic curves, this test deals with the polygon    */
    /* only which is spanned up by the control points.                */
    var points = base.points;
    var contours = base.contours;
    var _p_off = outline.points;
    var _c_off = outline.contours;

    var v_prev = new FT_Vector();
    var v_cur = new FT_Vector();

    var first = 0;
    var area = 0;
    for (var c = 0; c < outline.n_contours; c++)
    {
        var last = contours[_c_off + c];
        v_prev.x = points[_p_off + last].x;
        v_prev.y = points[_p_off + last].y;

        for (var n = first; n <= last; n++)
        {
            v_cur.x = points[_p_off + n].x;
            v_cur.y = points[_p_off + n].y;
            area += (v_cur.y - v_prev.y) * (v_cur.x + v_prev.x);
            v_prev.x = v_cur.x;
            v_prev.y = v_cur.y;
        }

        first = last + 1;
    }

    if (area > 0)
        return 1;
    else if ( area < 0 )
        return 0;
    return 2;
}

function ft_trig_prenorm(vec)
{
    var x = vec.x;
    var y = vec.y;

    var z = ((x >= 0) ? x : - x) | ((y >= 0) ? y : -y);
    var shift = 0;

    /* determine msb bit index in `shift' */
    if (z >= (1 << 16))
    {
        z >>= 16;
        shift += 16;
    }
    if (z >= (1 << 8))
    {
        z >>= 8;
        shift += 8;
    }
    if (z >= (1 << 4))
    {
        z >>= 4;
        shift += 4;
    }
    if (z >= (1 << 2))
    {
        z >>= 2;
        shift += 2;
    }
    if (z >= (1 << 1))
    {
        z >>= 1;
        shift += 1;
    }

    if (shift <= 29)
    {
        shift  = 29 - shift;
        vec.x = x << shift;
        vec.y = y << shift;
    }
    else
    {
        shift -= 29;
        vec.x = x >> shift;
        vec.y = y >> shift;
        shift = -shift;
    }

    return shift;
}

var ft_trig_arctan_table = [1740967, 919879, 466945, 234379, 117304, 58666, 29335, 14668, 7334,
    3667, 1833, 917, 458, 229, 115, 57, 29, 14, 7, 4, 2, 1, 0];

function ft_trig_pseudo_polarize(vec)
{
    var x = vec.x;
    var y = vec.y;

    var theta = 0;
    var xtemp = 0;

    /* Get the vector into [-PI/4,PI/4] sector */
    if ( y > x )
    {
        if ( y > -x )
        {
            theta =  5898240;
            xtemp =  y;
            y     = -x;
            x     =  xtemp;
        }
        else
        {
            theta =  y > 0 ? 11796480 : -11796480;
            x     = -x;
            y     = -y;
        }
    }
    else
    {
        if ( y < -x )
        {
            theta = -5898240;
            xtemp = -y;
            y     =  x;
            x     =  xtemp;
        }
        else
        {
            theta = 0;
        }
    }

    var arctanptr = 0;
    var i, b;

    /* Pseudorotations, with right shifts */
    for ( i = 1, b = 1; i < 23; b <<= 1, i++ )
    {
        if ( y > 0 )
        {
            xtemp  = x + ( ( y + b ) >> i );
            y      = y - ( ( x + b ) >> i );
            x      = xtemp;
            theta += ft_trig_arctan_table[arctanptr++];
        }
        else
        {
            xtemp  = x - ( ( y + b ) >> i );
            y      = y + ( ( x + b ) >> i );
            x      = xtemp;
            theta -= ft_trig_arctan_table[arctanptr++];
        }
    }

    /* round theta */
    if ( theta >= 0 )
        theta = FT_PAD_ROUND( theta, 32 );
    else
        theta = -FT_PAD_ROUND( -theta, 32 );

    vec.x = x;
    vec.y = theta;
}

function ft_trig_downscale(val)
{
    var s   = val;
    val = (val >= 0) ? val : -val;

    var v1 = val >>> 16;
    var v2 = FT_Common.Short_To_UShort(val & 0xFFFF);

    var k1 =  0xDBD9;   /* constant */
    var k2 = 0x5B16;   /* constant */

    var hi   = k1 * v1;
    var lo1  = k1 * v2 + k2 * v1;       /* can't overflow */

    var lo2  = ( k2 * v2 ) >>> 16;

    var lo3  = ( lo1 >= lo2 ) ? lo1 : lo2;
    lo1 += lo2;

    hi  += (lo1 >>> 16);
    if (lo1 < lo3)
        hi += 0x10000;

    var val  = FT_Common.UintToInt(hi);

    return (s >= 0) ? val : -val;
}

function FT_Vector_Length(vec)
{
    var v = new FT_Vector();
    v.x = vec.x;
    v.y = vec.y;

    /* handle trivial cases */
    if (v.x == 0)
    {
        return (v.y >= 0) ? v.y : -v.y;
    }
    else if (v.y == 0)
    {
        return (v.x >= 0) ? v.x : -v.x;
    }

    /* general case */
    var shift = ft_trig_prenorm(v);
    ft_trig_pseudo_polarize(v);

    v.x = ft_trig_downscale(v.x);

    if (shift > 0)
        return (v.x + (1 << (shift - 1))) >> shift;
    return v.x << -shift;
}

function FT_Outline_EmboldenXY(outline, xstrength, ystrength)
{
    if (outline == null)
        return 6;

    xstrength /= 2;
    ystrength /= 2;

    if (xstrength == 0 && ystrength == 0)
        return 0;

    var orientation = FT_Outline_Get_Orientation(outline);
    if (orientation == 2)
    {
        if (outline.n_contours != 0)
            return 6;
        else
            return 0;
    }

    var points = outline.points;
    var contours = outline.contours;

    var v_first = new FT_Vector();
    var v_prev  = new FT_Vector();
    var v_cur   = new FT_Vector();
    var v_next  = new FT_Vector();

    var first = 0;
    var last = 0;
    for (var c = 0; c < outline.n_contours; c++)
    {
        var _in = new FT_Vector();
        var out = new FT_Vector();
        var shift = new FT_Vector();

        last = contours[c];

        v_first.x = points[first].x;
        v_first.y = points[first].y;

        v_prev.x = points[last].x;
        v_prev.y = points[last].y;

        v_cur.x = v_first.x;
        v_cur.y = v_first.y;

        /* compute the incoming vector and its length */
        _in.x = v_cur.x - v_prev.x;
        _in.y = v_cur.y - v_prev.y;
        var l_in = FT_Vector_Length(_in);

        for (var n = first; n <= last; n++)
        {
            if (n < last)
                v_next = points[n + 1];
            else
                v_next = v_first;

            /* compute the outgoing vector and its length */
            out.x = v_next.x - v_cur.x;
            out.y = v_next.y - v_cur.y;
            var l_out = FT_Vector_Length(out);

            var d = l_in * l_out + _in.x * out.x + _in.y * out.y;

            /* shift only if turn is less then ~160 degrees */
            if (16 * d > l_in * l_out)
            {
                /* shift components are aligned along bisector        */
                /* and directed according to the outline orientation. */
                shift.x = l_out * _in.y + l_in * out.y;
                shift.y = l_out * _in.x + l_in * out.x;

                if (orientation == 0)
                    shift.x = -shift.x;
                else
                    shift.y = -shift.y;

                /* threshold strength to better handle collapsing segments */
                var l = Math.min(l_in, l_out);
                var q = out.x * _in.y - out.y * _in.x;
                if (orientation == 0)
                    q = -q;

                if (FT_MulDiv(xstrength, q, l) < d)
                    shift.x = FT_MulDiv(shift.x, xstrength, d);
                else
                    shift.x = FT_MulDiv(shift.x, l, q);

                if (FT_MulDiv(ystrength, q, l) < d)
                    shift.y = FT_MulDiv(shift.y, ystrength, d);
                else
                    shift.y = FT_MulDiv(shift.y, l, q);
            }
            else
                shift.x = shift.y = 0;

            points[n].x = v_cur.x + xstrength + shift.x;
            points[n].y = v_cur.y + ystrength + shift.y;

            _in    = out;
            l_in  = l_out;
            v_cur.x = v_next.x;
            v_cur.y = v_next.y;
        }

        first = last + 1;
    }

    return 0;
}

function FT_Outline_EmboldenXY_cur(outline, base, xstrength, ystrength)
{
    if (outline == null)
        return 6;

    xstrength /= 2;
    ystrength /= 2;

    if (xstrength == 0 && ystrength == 0)
        return 0;

    var orientation = FT_Outline_Get_Orientation_Cur(outline, base);
    if (orientation == 2)
    {
        if (outline.n_contours != 0)
            return 6;
        else
            return 0;
    }

    var points = base.points;
    var contours = base.contours;

    var _p_off = outline.points;
    var _c_off = outline.contours;

    var v_first = new FT_Vector();
    var v_prev  = new FT_Vector();
    var v_cur   = new FT_Vector();
    var v_next  = new FT_Vector();

    var first = 0;
    var last = 0;
    for (var c = 0; c < outline.n_contours; c++)
    {
        var _in = new FT_Vector();
        var out = new FT_Vector();
        var shift = new FT_Vector();

        last = contours[_c_off + c];

        v_first.x = points[_p_off + first].x;
        v_first.y = points[_p_off + first].y;

        v_prev.x = points[_p_off + last].x;
        v_prev.y = points[_p_off + last].y;

        v_cur.x = v_first.x;
        v_cur.y = v_first.y;

        /* compute the incoming vector and its length */
        _in.x = v_cur.x - v_prev.x;
        _in.y = v_cur.y - v_prev.y;
        var l_in = FT_Vector_Length(_in);

        for (var n = first; n <= last; n++)
        {
            if (n < last)
            {
                v_next.x = points[_p_off + n + 1].x;
                v_next.y = points[_p_off + n + 1].y;
            }
            else
            {
                v_next.x = v_first.x;
                v_next.y = v_first.y;
            }

            /* compute the outgoing vector and its length */
            out.x = v_next.x - v_cur.x;
            out.y = v_next.y - v_cur.y;
            var l_out = FT_Vector_Length(out);

            var d = l_in * l_out + _in.x * out.x + _in.y * out.y;

            /* shift only if turn is less then ~160 degrees */
            if (16 * d > l_in * l_out)
            {
                /* shift components are aligned along bisector        */
                /* and directed according to the outline orientation. */
                shift.x = l_out * _in.y + l_in * out.y;
                shift.y = l_out * _in.x + l_in * out.x;

                if (orientation == 0)
                    shift.x = -shift.x;
                else
                    shift.y = -shift.y;

                /* threshold strength to better handle collapsing segments */
                var l = Math.min(l_in, l_out);
                var q = out.x * _in.y - out.y * _in.x;
                if (orientation == 0)
                    q = -q;

                if (FT_MulDiv(xstrength, q, l) < d)
                    shift.x = FT_MulDiv(shift.x, xstrength, d);
                else
                    shift.x = FT_MulDiv(shift.x, l, q);

                if (FT_MulDiv(ystrength, q, l) < d)
                    shift.y = FT_MulDiv(shift.y, ystrength, d);
                else
                    shift.y = FT_MulDiv(shift.y, l, q);
            }
            else
                shift.x = shift.y = 0;

            points[_p_off + n].x = v_cur.x + xstrength + shift.x;
            points[_p_off + n].y = v_cur.y + ystrength + shift.y;

            _in    = out;
            l_in  = l_out;
            v_cur.x = v_next.x;
            v_cur.y = v_next.y;
        }

        first = last + 1;
    }

    return 0;
}


function FT_Outline_Embolden(outline, strength)
{
    return FT_Outline_EmboldenXY(outline, strength, strength);
}
//------------

function FT_Outline_Transform(outline, matrix)
{
    if ( !outline || !matrix )
        return;

    var vec = outline.points;
    var len = outline.n_points;

    for (var i=0; i < len; i++)
        FT_Vector_Transform(vec[i], matrix);
}

function FT_Vector_Transform(vector, matrix)
{
    if ( !vector || !matrix )
        return;

    var xz = FT_MulFix(vector.x, matrix.xx) + FT_MulFix(vector.y, matrix.xy);
    var yz = FT_MulFix(vector.x, matrix.yx) + FT_MulFix(vector.y, matrix.yy);

    vector.x = xz;
    vector.y = yz;
}

function FT_Outline_Translate(outline, xOffset, yOffset)
{
    if ( !outline )
        return;

    var vec = outline.points;
    var c = outline.n_points;

    for (var n=0;n<c;n++)
    {
        vec[n].x += xOffset;
        vec[n].y += yOffset;
    }
}

function FT_Outline_Get_CBox(outline, acbox)
{
    var xMin, yMin, xMax, yMax;

    if (outline != null && acbox != null)
    {
        if (outline.n_points == 0)
        {
            xMin = 0;
            yMin = 0;
            xMax = 0;
            yMax = 0;
        }
        else
        {
            var p = outline.points;
            var vec = p[0];
            var count = outline.n_points;

            xMin = xMax = vec.x;
            yMin = yMax = vec.y;

            for (var i = 1; i < count; i++)
            {
                var x = p[i].x;
                if ( x < xMin ) xMin = x;
                if ( x > xMax ) xMax = x;

                var y = p[i].y;
                if ( y < yMin ) yMin = y;
                if ( y > yMax ) yMax = y;
            }
        }
        acbox.xMin = xMin;
        acbox.xMax = xMax;
        acbox.yMin = yMin;
        acbox.yMax = yMax;
    }
}

function FT_Glyph_Class()
{
    this.glyph_size = 0;
    this.glyph_format = 0;
    this.glyph_init = null;
    this.glyph_done = null;
    this.glyph_copy = null;
    this.glyph_transform = null;
    this.glyph_bbox = null;
    this.glyph_prepare = null;
}

// для быстроты работы не пользуется эта структура.
// все ради всех браузеров, кроме ie9. в них типизированные массивы
// быстрее обычных (а тут скорость доступа - самое главное)
function TCell()
{
    this.x      = 0;
    this.cover  = 0;
    this.area   = 0;
    this.next   = 0;
}

function TRaster()
{
    this.worker = new TWorker();

    this.memory = null;

    this.cell_x     = CreateIntArray(1024);
    this.cell_cover = CreateIntArray(1024);
    this.cell_area  = CreateIntArray(1024);
    this.cell_next  = CreateIntArray(1024);

    this.buffer_size    = 0;
    this.band_size      = 0;
}

// - smooth -----------------------------------------------------------
// ------------ rasterizer --------------------------------------------
// пул памяти для растеризатора делаем Array int'ов. Почему не массив структур?
// 1) не выделять память под саму структуру (хотя кто знает как работает js)
// 2) самое главное - это возможность замены на типизированный массив!!!
// сам растеризатор ничего не знает о происхождении массива. За создание
// его отвечает функция CreateIntArray
function CreateIntArray(size)
{
    var arr = null;
    if (typeof(Int32Array) != 'undefined' && !window.opera)
        arr = new Int32Array(size);
    else
        arr = new Array(size);
    for (var i=0;i<size;i++)
        arr[i] = 0;
    return arr;
}
function CreateUIntArray(size)
{
    var arr = null;
    if (typeof(Uint32Array) != 'undefined' && !window.opera)
        arr = new Uint32Array(size);
    else
        arr = new Array(size);
    for (var i=0;i<size;i++)
        arr[i] = 0;
    return arr;
}
function CreateCharArray(size)
{
    var arr = null;
    if (typeof(Int8Array) != 'undefined' && !window.opera)
        arr = new Int8Array(size);
    else
        arr = new Array(size);
    for (var i=0;i<size;i++)
        arr[i] = 0;
    return arr;
}
function CreateNullArray(size)
{
    var arr = new Array(size);
    for (var i=0;i<size;i++)
        arr[i] = null;
    return arr;
}
function TWorker()
{
    this.ex = 0;
    this.ey = 0;

    this.min_ex = 0;
    this.max_ex = 0;
    this.min_ey = 0;
    this.max_ey = 0;

    this.count_ex = 0;
    this.count_ey = 0;

    this.area = 0;
    this.cover = 0;
    this.invalid = 0;

    this.max_cells = 0;
    this.num_cells = 0;

    this.cx = 0;
    this.cy = 0;
    this.x = 0;
    this.y = 0;

    this.last_ey = 0;

    this.bez_stack_x = CreateIntArray(97);
    this.bez_stack_y = CreateIntArray(97);
    this.lev_stack = CreateIntArray(32);

    this.outline = null;
    this.target = null;
    this.clip_box = new FT_BBox();

    this.gray_spans = new Array(32);
    for (var i=0;i<32;i++)
        this.gray_spans[i] = new FT_Span();

    this.num_gray_spans = 0;

    this.render_span = null;
    
    this.render_span_data = null;
    this.span_y = 0;

    this.band_size = 0;
    this.band_shoot = 0;

    this.cell_x     = null;
    this.cell_cover = null;
    this.cell_area  = null;
    this.cell_next  = null;
    this.buffer_size = 1024;

    this.ycells = CreateIntArray(this.buffer_size);
    this.ycount = 0;

    this.raster_memory = raster_memory;
}

function gray_init_cells(worker, raster)
{
    worker.cell_x     = raster.cell_x;
    worker.cell_cover = raster.cell_cover;
    worker.cell_area  = raster.cell_area;
    worker.cell_next  = raster.cell_next;
    worker.buffer_size = 1024;

    worker.max_cells   = 0;
    worker.num_cells   = 0;
    worker.area        = 0;
    worker.cover       = 0;
    worker.invalid     = 1;
}

function gray_compute_cbox(worker)
{
    var outline = worker.outline;
    var p = outline.points;
    var c = outline.n_points;

    if ( c <= 0 )
    {
        worker.min_ex = worker.max_ex = 0;
        worker.min_ey = worker.max_ey = 0;
        return;
    }

    worker.min_ex = worker.max_ex = p[0].x;
    worker.min_ey = worker.max_ey = p[0].y;

    for (var i = 1; i < c; i++)
    {
        var x = p[i].x;
        var y = p[i].y;

        if ( x < worker.min_ex ) worker.min_ex = x;
        if ( x > worker.max_ex ) worker.max_ex = x;
        if ( y < worker.min_ey ) worker.min_ey = y;
        if ( y > worker.max_ey ) worker.max_ey = y;
    }

    /* truncate the bounding box to integer pixels */
    worker.min_ex = worker.min_ex >> 6;
    worker.min_ey = worker.min_ey >> 6;
    worker.max_ex = ( worker.max_ex + 63 ) >> 6;
    worker.max_ey = ( worker.max_ey + 63 ) >> 6;
}

function TBand()
{
    this.min = 0;
    this.max = 0;
}

function gray_find_cell(ras)
{
    var x = ras.ex;

    if ( x > ras.count_ex )
        x = ras.count_ex;

    var pcell = ras.ey;
    var cell = ras.ycells[pcell];

    var bis_y = 1;
    for (;;)
    {
        if (cell == -1 || ras.cell_x[cell] > x)
            break;

        if (ras.cell_x[cell] == x)
            return cell;

        bis_y = 0;
        pcell = cell;
        cell = ras.cell_next[cell];
    }

    if (ras.num_cells >= ras.max_cells)
        return -1;

    var oldcell = cell;

    cell = ras.num_cells++;
    ras.cell_x[cell] = x;
    ras.cell_area[cell] = 0;
    ras.cell_cover[cell] = 0;
    ras.cell_next[cell] = oldcell;

    if (1 == bis_y)
        ras.ycells[pcell] = cell;
    else
        ras.cell_next[pcell] = cell;
    return cell;
}

function gray_record_cell(ras)
{
    if (0 == ras.invalid && ((ras.area | ras.cover) != 0))
    {
        var cell = gray_find_cell(ras);
        if (-1 == cell)
            return -100;

        ras.cell_area[cell] += ras.area;
        ras.cell_cover[cell] += ras.cover;
    }
    return 0;
}

function gray_set_cell(ras, ex, ey)
{
    ey -= ras.min_ey;

    if ( ex > ras.max_ex )
        ex = ras.max_ex;

    ex -= ras.min_ex;
    if ( ex < 0 )
        ex = -1;

    /* are we moving to a different cell ? */
    if ( ex != ras.ex || ey != ras.ey )
    {
        /* record the current one if it is valid */
        if (0 == ras.invalid)
        {
            var err = gray_record_cell(ras);
            if (err == -100)
                return -100;
        }

        ras.area  = 0;
        ras.cover = 0;
    }

    ras.ex      = ex;
    ras.ey      = ey;

    var _ey = ey >= 0 ? ey : ey + 4294967296;
    var _cy = ras.count_ey >= 0 ? ras.count_ey : ras.count_ey + 4294967296;

    ras.invalid = (_ey >= _cy || ex >= ras.count_ex) ? 1 : 0;
    return 0;
}

function gray_start_cell(ras, ex, ey)
{
    if (ex > ras.max_ex)
        ex = ras.max_ex;

    if (ex < ras.min_ex)
        ex = (ras.min_ex - 1);

    ras.area    = 0;
    ras.cover   = 0;
    ras.ex      = ex - ras.min_ex;
    ras.ey      = ey - ras.min_ey;
    ras.last_ey = ey << 8;
    ras.invalid = 0;

    return gray_set_cell(ras, ex, ey);
}

function gray_render_line(ras, to_x, to_y)
{
    var ey1, ey2, fy1, fy2, mod;
    var dx, dy, x, x2;
    var p, first;
    var delta, rem, lift, incr;

    ey1 = (ras.last_ey >> 8);
    ey2 = (to_y >> 8);     /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
    fy1 = (ras.y - ras.last_ey);
    fy2 = (to_y - (ey2 << 8));

    dx = to_x - ras.x;
    dy = to_y - ras.y;

    var min = ey1;
    var max = ey2;

    if (ey1 > ey2)
    {
        min = ey2;
        max = ey1;
    }
    if (min >= ras.max_ey || max < ras.min_ey)
    {
        ras.x       = to_x;
        ras.y       = to_y;
        ras.last_ey = ey2 << 8;
        return 0;
    }

    var err = 0;
    /* everything is on a single scanline */
    if (ey1 == ey2)
    {
        err = gray_render_scanline(ras, ey1, ras.x, fy1, to_x, fy2);
        if (err == -100)
            return -100;
        ras.x       = to_x;
        ras.y       = to_y;
        ras.last_ey = ey2 << 8;
        return 0;
    }

    /* vertical line - avoid calling gray_render_scanline */
    incr = 1;

    if (dx == 0)
    {
        var ex = ras.x >> 8;
        var two_fx = ((ras.x - (ex << 8)) << 1);
        var area;

        first = 256;
        if (dy < 0)
        {
            first = 0;
            incr  = -1;
        }

        delta      = (first - fy1);
        ras.area  += (two_fx * delta);
        ras.cover += delta;
        ey1       += incr;

        err = gray_set_cell(ras, ex, ey1);
        if (err == -100)
            return -100;

        delta = (first + first - 256);
        area  = two_fx * delta;
        while (ey1 != ey2)
        {
            ras.area  += area;
            ras.cover += delta;
            ey1       += incr;

            err = gray_set_cell(ras, ex, ey1);
            if (err == -100)
                return -100;
        }

        delta      = (fy2 - 256 + first);
        ras.area  += (two_fx * delta);
        ras.cover += delta;

        ras.x       = to_x;
        ras.y       = to_y;
        ras.last_ey = ey2 << 8;
        return 0;
    }

    /* ok, we have to render several scanlines */
    p     = (256 - fy1) * dx;
    first = 256;
    incr  = 1;

    if (dy < 0)
    {
        p     = fy1 * dx;
        first = 0;
        incr  = -1;
        dy    = -dy;
    }

    delta = parseInt(p / dy);
    mod   = (p % dy);
    if (mod < 0)
    {
        delta--;
        mod += dy;
    }

    x = ras.x + delta;
    err = gray_render_scanline(ras, ey1, ras.x, fy1, x, first);
    if (err == -100)
        return -100;

    ey1 += incr;
    err = gray_set_cell(ras, x >> 8, ey1);
    if (err == -100)
        return -100;

    if (ey1 != ey2)
    {
        p     = 256 * dx;
        lift  = parseInt(p / dy);
        rem   = (p % dy);
        if (rem < 0)
        {
            lift--;
            rem += dy;
        }
        mod -= dy;

        while (ey1 != ey2)
        {
            delta = lift;
            mod  += rem;
            if (mod >= 0)
            {
                mod -= dy;
                delta++;
            }

            x2 = x + delta;
            err = gray_render_scanline(ras, ey1, x, 256 - first, x2, first);
            if (err == -100)
                return -100;
            x = x2;

            ey1 += incr;
            err = gray_set_cell(ras, x >> 8, ey1);
            if (err == -100)
                return -100;
        }
    }

    err = gray_render_scanline(ras, ey1, x, 256 - first, to_x, fy2);
    if (err == -100)
        return -100;

    ras.x       = to_x;
    ras.y       = to_y;
    ras.last_ey = (ey2 << 8);
    return 0;
}

function gray_split_conic(bx,by,base)
{
    var a,b;
    bx[base+4] = bx[base+2];
    b = bx[base+1];
    a=bx[base+3] = parseInt((bx[base+2]+b)/2);
    b=bx[base+1] = parseInt((bx[base]+b)/2);
    bx[base+2] = parseInt((a+b)/2);

    by[base+4] = by[base+2];
    b = by[base+1];
    a=by[base+3] = parseInt((by[base+2]+b)/2);
    b=by[base+1] = parseInt((by[base]+b)/2);
    by[base+2] = parseInt((a+b)/2);
}

function gray_render_conic(ras, control, to)
{
    var dx, dy;
    var min, max, y;
    var top, level;
    var arc = 0;

    var arcx = ras.bez_stack_x;
    var arcy = ras.bez_stack_y;

    arcx[arc] = (to.x << 2);
    arcy[arc] = (to.y << 2);
    arcx[arc+1] = (control.x << 2);
    arcy[arc+1] = (control.y << 2);
    arcx[arc+2] = ras.x;
    arcy[arc+2] = ras.y;
    top = 0;

    dx = Math.abs(arcx[arc+2] + arcx[arc] - 2*arcx[arc+1]);
    dy = Math.abs(arcy[arc+2] + arcy[arc] - 2*arcy[arc+1]);
    if (dx < dy)
        dx = dy;

    if (dx < 64)
    {
        return gray_render_line(ras, arcx[arc], arcy[arc]);
    }

    /* short-cut the arc that crosses the current band */
    min = max = arcy[arc];

    y = arcy[arc+1];
    if (y < min) min = y;
    if (y > max) max = y;

    y = arcy[arc+2];
    if (y < min) min = y;
    if (y > max) max = y;

    if (((min >> 8) >= ras.max_ey) || ((max >> 8) < ras.min_ey))
    {
        return gray_render_line(ras, arcx[arc], arcy[arc]);
    }

    level = 0;
    do
    {
        dx >>= 2;
        level++;
    } while (dx > 64);

    var levels = ras.lev_stack;
    levels[0] = level;

    var err = 0;
    do
    {
        level = levels[top];
        if (level > 0)
        {
            gray_split_conic(arcx, arcy, arc);
            arc += 2;
            top++;
            levels[top] = levels[top - 1] = level - 1;
            continue;
        }

        err = gray_render_line(ras, arcx[arc], arcy[arc]);
        if (err == -100)
            return -100;
        top--;
        arc -= 2;

    }
    while (top >= 0);
    return 0;
}

function gray_split_cubic(bx,by,base)
{
    var a,b,c,d;
    bx[base+6] = bx[base+3];
    c = bx[base+1];
    d = bx[base+2];
    bx[base+1] = a = parseInt((bx[base]+c)/2);
    bx[base+5] = b = parseInt((bx[base+3]+d)/2);
    c = parseInt((c+d)/2);
    bx[base+2] = a = parseInt((a+c)/2);
    bx[base+4] = b = parseInt((b+c)/2);
    bx[base+3] = parseInt((a+b)/2);

    by[base+6] = by[base+3];
    c = by[base+1];
    d = by[base+2];
    by[base+1] = a = parseInt((by[base]+c)/2);
    by[base+5] = b = parseInt((by[base+3]+d)/2);
    c = parseInt((c+d)/2);
    by[base+2] = a = parseInt((a+c)/2);
    by[base+4] = b = parseInt((b+c)/2);
    by[base+3] = parseInt((a+b)/2);
}

function gray_render_cubic(ras, control1, control2, to)
{
    var min, max, y;

    var arcx = ras.bez_stack_x;
    var arcy = ras.bez_stack_y;
    arcx[0] = to.x << 2;
    arcy[0] = to.y << 2;
    arcx[1] = control2.x << 2;
    arcy[1] = control2.y << 2;
    arcx[2] = control1.x << 2;
    arcy[2] = control1.y << 2;
    arcx[3] = ras.x;
    arcy[3] = ras.y;

    var arc = 0;

    /* Short-cut the arc that crosses the current band. */
    min = max = arcy[0];

    y = arcy[arc+1];
    if (y<min)
        min = y;
    if (y>max)
        max = y;

    y = arcy[arc+2];
    if (y<min)
        min = y;
    if (y>max)
        max = y;

    y = arcy[arc+3];
    if (y<min)
        min = y;
    if (y>max)
        max = y;

    var err = 0;
    if ((min >> 8) >= ras.max_ey || (max >> 8) < ras.min_ey)
    {
        return gray_render_line(ras, arcx[arc], arcy[arc]);
    }

    for (;;)
    {
        var dx, dy, dx_, dy_;
        var dx1, dy1, dx2, dy2;
        var L, s, s_limit;

        dx = arcx[arc+3] - arcx[arc];
        dy = arcy[arc+3] - arcy[arc];

        dx_ = Math.abs(dx);
        dy_ = Math.abs(dy);

        L = ((dx_ > dy_) ? (236 * dx_ + 97 * dy_) : (97 * dx_ + 236 * dy_)) >>> 8;

        if ( L > 32767 )
        {
            gray_split_cubic(arcx,arcy,arc);
            arc += 3;
            continue;
        }

        s_limit = L * 42;

        dx1 = arcx[arc+1] - arcx[arc];
        dy1 = arcy[arc+1] - arcy[arc];
        s = Math.abs(dy*dx1 - dx*dy1);

        if (s>s_limit)
        {
            gray_split_cubic(arcx,arcy,arc);
            arc += 3;
            continue;
        }

        dx2 = arcx[arc+2] - arcx[arc];
        dy2 = arcy[arc+2] - arcy[arc];
        s = Math.abs(dy*dx2 - dx*dy2);

        if (s>s_limit)
        {
            gray_split_cubic(arcx,arcy,arc);
            arc += 3;
            continue;
        }

        if (((dy*dy1 + dx*dx1) < 0) || ((dy*dy2 + dx*dx2) < 0) ||
            ((dy*(arcy[arc+3]-arcy[arc+1]) + dx*(arcx[arc+3]-arcx[arc+1])) < 0) ||
            ((dy*(arcy[arc+3]-arcy[arc+2]) + dx*(arcx[arc+3]-arcx[arc+2])) < 0))
        {
            gray_split_cubic(arcx,arcy,arc);
            arc += 3;
            continue;
        }

        /* No reason to split. */
        err = gray_render_line(ras, arcx[arc], arcy[arc]);
        if (err == -100)
            return -100;

        if (arc == 0)
            return 0;

        arc -= 3;
    }
    return 0;
}

function gray_render_scanline(ras, ey, x1, y1, x2, y2)
{
    var ex1, ex2, fx1, fx2, delta, mod, lift, rem;
    var p, first, dx;
    var incr;

    dx = x2 - x1;

    ex1 = (x1 >> 8);
    ex2 = (x2 >> 8);
    fx1 = x1 - (ex1 << 8);
    fx2 = x2 - (ex2 << 8);

    /* trivial case.  Happens often */
    if (y1 == y2)
    {
        return gray_set_cell(ras, ex2, ey);
    }

    /* everything is located in a single cell.  That is easy! */
    if (ex1 == ex2)
    {
        delta = y2 - y1;
        ras.area  += ((fx1+fx2)*delta);
        ras.cover += delta;
        return 0;
    }

    /* ok, we'll have to render a run of adjacent cells on the same scanline */
    p = (256 - fx1)*(y2-y1);
    first = 256;
    incr  = 1;

    if (dx < 0)
    {
        p     = fx1*(y2-y1);
        first = 0;
        incr  = -1;
        dx    = -dx;
    }

    delta = parseInt(p/dx);
    mod   = p%dx;
    if (mod < 0)
    {
        delta--;
        mod += dx;
    }

    ras.area  += ((fx1+first)*delta);
    ras.cover += delta;

    ex1 += incr;
    var err = gray_set_cell(ras, ex1, ey);
    if (err == -100)
        return err;
    y1  += delta;

    if (ex1 != ex2)
    {
        p    = 256 * (y2 - y1 + delta);
        lift = parseInt(p/dx);
        rem  = (p%dx);
        if (rem < 0)
        {
            lift--;
            rem += dx;
        }

        mod -= dx;

        while (ex1 != ex2)
        {
            delta = lift;
            mod  += rem;
            if (mod >= 0)
            {
                mod -= dx;
                delta++;
            }

            ras.area  += (256*delta);
            ras.cover += delta;
            y1        += delta;
            ex1       += incr;
            err = gray_set_cell(ras, ex1, ey);
            if (err == -100)
                return err;
        }
    }

    delta      = y2 - y1;
    ras.area  += ((fx2 + 256 - first)*delta);
    ras.cover += delta;
    return 0;
}

function _gray_render_span(y, count, spans, span_start, worker)
{
    var map = worker.target;
    var pixels = map.buffer.data;
    var p = -y * map.pitch;
    if (map.pitch >= 0)
        p += ((map.rows-1)*map.pitch);

    var s = span_start;
    for (;count > 0;count--,s++)
    {
        var coverage = spans[s].coverage;

        if (coverage != 0)
        {
            var len = spans[s].len;
            var q = spans[s].x + p;
            for (;len>0;len--)
                pixels[q++] = coverage;
        }
    }
}
function gray_render_span(y, count, spans, span_start, worker)
{
    var map = worker.raster_memory;
    var pixels = map.m_oBuffer.data;
    var p = -y * map.pitch;
    if (worker.target.pitch >= 0)
        p += ((worker.target.rows-1)*map.pitch);

    p+=3;

    var s = span_start;
    for (;count > 0;count--,s++)
    {
        var coverage = spans[s].coverage;

        if (coverage != 0)
        {
            var len = spans[s].len;
            var q = (spans[s].x * 4) + p;
            for (;len>0;len--,q+=4)
                pixels[q] = coverage;
        }
    }
}

function gray_hline(ras, x, y, area, acount)
{
    var spans = ras.gray_spans;
    var span_i = 0;
    var span;

    var count;

    var coverage = (area >> 9);
    /* use range 0..256 */
    if (coverage < 0)
        coverage = -coverage;

    if ((ras.outline.flags & 2) != 0)
    {
        coverage &= 511;
        if (coverage > 256)
            coverage = 512 - coverage;
        else if (coverage == 256)
            coverage = 255;
    }
    else
    {
        if ( coverage >= 256 )
            coverage = 255;
    }

    y += ras.min_ey;
    x += ras.min_ex;

    if (x >= 32767)
        x = 32767;

    /* FT_Span.y is an integer, so limit our coordinates appropriately */
    if (y >= 2147483647)
        y = 2147483647;

    if (coverage != 0)
    {
        /* see whether we can add this span to the current list */
        count = ras.num_gray_spans;
        span_i  = count - 1;
        span = spans[span_i];
        if ((count > 0) && (ras.span_y == y) && ((span.x + span.len) == x) && (span.coverage == coverage))
        {
            span.len = (span.len + acount) & 0xFFFF;
            return;
        }

        if (ras.span_y != y || count >= 32)
        {
            if (ras.render_span && count > 0)
                ras.render_span(ras.span_y,count,ras.gray_spans,0,ras.render_span_data);

            ras.num_gray_spans = 0;
            ras.span_y = y;

            count = 0;
            span_i = 0;
            span = spans[0];
        }
        else
        {
            span_i++;
            span = spans[span_i];
        }

        /* add a gray span to the current list */
        span.x        = x;
        span.len      = acount & 0xFFFF;
        span.coverage = coverage & 0xFF;

        ras.num_gray_spans++;
    }
}

function gray_sweep(ras, target)
{
    if (ras.num_cells == 0)
        return;

    ras.num_gray_spans = 0;

    var _next = ras.cell_next;
    var _cover = ras.cell_cover;
    var _area = ras.cell_area;
    var _x = ras.cell_x;

    for (var yindex = 0; yindex < ras.ycount; yindex++)
    {
        var cell = ras.ycells[yindex];
        var cover = 0;
        var x = 0;

        for (; cell != -1; cell = _next[cell])
        {
            if (_x[cell] > x && cover != 0)
                gray_hline(ras, x, yindex, cover * 512, _x[cell] - x);

            cover += _cover[cell];
            var area = cover * 512 - _area[cell];

            if (area != 0 && _x[cell] >= 0)
                gray_hline(ras, _x[cell], yindex, area, 1);

            x = _x[cell] + 1;
        }

        if ( cover != 0 )
            gray_hline(ras, x, yindex, cover * 512, ras.count_ex - x);
    }

    if (ras.render_span && ras.num_gray_spans > 0)
        ras.render_span(ras.span_y, ras.num_gray_spans, ras.gray_spans, 0, ras.render_span_data);
}

function __grays_raster_render(raster, params)
{
    var outline = params.source;
    var target_map = params.target;

    if (raster == null)
        return 6;

    if (outline == null)
        return 20;

    /* return immediately if the outline is empty */
    if (outline.n_points == 0 || outline.n_contours <= 0)
        return 0;

    if (outline.contours == null || outline.points == null)
        return 20;

    if (outline.n_points != outline.contours[outline.n_contours - 1] + 1)
        return 20;

    var worker = raster.worker;

    /* if direct mode is not set, we must have a target bitmap */
    if (0 == (params.flags & 2))
    {
        if (target_map == null)
            return 6;

        /* nothing to do */
        if (0 == target_map.width || 0 == target_map.rows)
            return 0;

        if (null == target_map.buffer && null == worker.raster_memory)
            return 6;
    }

    /* this version does not support monochrome rendering */
    if (0 == (params.flags & 1))
        return 6;

    /* compute clipping box */
    if (0 == (params.flags & 2))
    {
        /* compute clip box from target pixmap */
        worker.clip_box.xMin = 0;
        worker.clip_box.yMin = 0;
        worker.clip_box.xMax = target_map.width;
        worker.clip_box.yMax = target_map.rows;
    }
    else if (params.flags & 4)
    {
        worker.clip_box.xMin = params.clip_box.xMin;
        worker.clip_box.yMin = params.clip_box.yMin;
        worker.clip_box.xMax = params.clip_box.xMax;
        worker.clip_box.yMax = params.clip_box.yMax;
    }
    else
    {
        worker.clip_box.xMin = -32768;
        worker.clip_box.yMin = -32768;
        worker.clip_box.xMax =  32767;
        worker.clip_box.yMax =  32767;
    }

    gray_init_cells(worker, raster);

    worker.outline        = outline;
    worker.num_cells      = 0;
    worker.invalid        = 1;
    worker.band_size      = raster.band_size;
    worker.num_gray_spans = 0;

    if (0 != (params.flags & 2))
    {
        worker.render_span      = params.gray_spans;
        worker.render_span_data = params.user;
    }
    else
    {
        worker.target           = target_map;
        worker.render_span      = gray_render_span;
        worker.render_span_data = worker;
    }

    if (worker.raster_memory != null)
        worker.raster_memory.CheckSize(target_map.width, target_map.rows);

    return __gray_convert_glyph(worker);
}
function __gray_convert_glyph(ras)
{
    var bands = m_bands;
    var band = 0;
    var n = 0;
    var num_bands = 0;
    var min = 0;
    var max = 0;
    var max_y = 0;
    var clip = null;

    gray_compute_cbox(ras);

    /* clip to target bitmap, exit if nothing to do */
    clip = ras.clip_box;

    if (ras.max_ex <= clip.xMin || ras.min_ex >= clip.xMax ||
        ras.max_ey <= clip.yMin || ras.min_ey >= clip.yMax )
        return 0;

    if (ras.min_ex < clip.xMin) ras.min_ex = clip.xMin;
    if (ras.min_ey < clip.yMin) ras.min_ey = clip.yMin;

    if (ras.max_ex > clip.xMax ) ras.max_ex = clip.xMax;
    if (ras.max_ey > clip.yMax ) ras.max_ey = clip.yMax;

    ras.count_ex = ras.max_ex - ras.min_ex;
    ras.count_ey = ras.max_ey - ras.min_ey;

    /* set up vertical bands */
    num_bands = parseInt((ras.max_ey - ras.min_ey) / ras.band_size);
    if (num_bands == 0)
        num_bands = 1;
    if (num_bands >= 39)
        num_bands = 39;

    ras.band_shoot = 0;

    min   = ras.min_ey;
    max_y = ras.max_ey;

    for (n = 0; n < num_bands; n++, min = max)
    {
        max = min + ras.band_size;
        if ((n == num_bands - 1) || (max > max_y))
            max = max_y;

        bands[0].min = min;
        bands[0].max = max;
        band = 0;

        while (band >= 0)
        {
            var isReduceBands = 0;

            var bottom, top, middle;
            var error = 0;
            var _band = bands[band];

            var cells_max;

            ras.ycount = _band.max - _band.min;
            if (ras.ycount >= ras.buffer_size)
                isReduceBands = 1;

            if (0 == isReduceBands)
            {
                ras.max_cells = ras.buffer_size;
                if (ras.max_cells < 2)
                {
                    // такого быть не может из-за лишнего килобайтика)
                    isReduceBands = 1;
                }

                if (0 == isReduceBands)
                {
                    for (var yindex = 0; yindex < ras.ycount; yindex++)
                        ras.ycells[yindex] = -1;

                    ras.num_cells = 0;
                    ras.invalid   = 1;
                    ras.min_ey    = _band.min;
                    ras.max_ey    = _band.max;
                    ras.count_ey  = _band.max - _band.min;

                    error = __gray_convert_glyph_inner(ras);

                    if (0 == error)
                    {
                        gray_sweep(ras, ras.target);
                        band--;
                        continue;
                    }
                    else if (error != 98)
                        return 1;
                }
            }

            /* render pool overflow; we will reduce the render band by half */
            bottom = _band.min;
            top    = _band.max;
            middle = bottom + ((top - bottom) >> 1);

            /* This is too complex for a single scanline; there must */
            /* be some problems.                                     */
            if (middle == bottom)
                return 1;

            if (bottom-top >= ras.band_size)
                ras.band_shoot++;


            bands[band+1].min = bottom;
            bands[band+1].max = middle;
            bands[band].min = middle;
            bands[band].max = top;

            band++;
        }
    }

    if (ras.band_shoot > 8 && ras.band_size > 16)
        ras.band_size = parseInt(ras.band_size / 2);

    return 0;
}

function __gray_convert_glyph_inner(ras)
{
    var error1 = FT_Outline_Decompose(ras.outline, ft_outline_funcs_gray, ras);

    if (-100 == error1)
        return 98;

    var error2 = gray_record_cell(ras);
    if (-100 == error2)
        return 98;

    return error1;
}

var m_bands = new Array(40);
for (var i = 0; i < 40; i++)
    m_bands[i] = new TBand();

function FT_Grays_Raster()
{
    // --------
    this.glyph_format = 1869968492;

    this.raster_new = function(memory, raster)
    {
        raster.memory = memory;
        return 0;
    }
    this.raster_reset = function(raster, pool_base, pool_size)
    {
        raster.buffer_size    = 1024;
        raster.band_size      = 117; // сделал как в си-шной либе, чтобы было удобно дебажиться.
        // а вообще - нужно так: (мы памяти выделяем больше на 1kb (под указатели ycells))
        //raster.band_size = 128;
    }
    this.raster_set_mode = null;
    this.raster_render = __grays_raster_render;
    this.raster_done = function()
    {
    }
}
// --------------------------------------------------------------------

function FT_Smooth_Renderer_Class()
{
    this.flags = 2;
    this.name = "smooth";
    this.version = 0x10000;
    this.requires = 0x20000;

    this.module_interface = null;

    this.init = ft_smooth_init;
    this.done = null;
    this.get_interface = null;

    this.glyph_format = 1869968492;

    this.render_glyph = ft_smooth_render;
    this.transform_glyph = ft_smooth_transform;
    this.get_glyph_cbox = ft_smooth_get_cbox;
    this.set_mode = ft_smooth_set_mode;

    this.raster_class = new FT_Grays_Raster();
}
function FT_Smooth_Renderer()
{
    this.clazz = new FT_Smooth_Renderer_Class();
    this.library = null;
    this.memory = null;
    this.generic = null;

    this.glyph_format = 0;
    this.glyph_class = new FT_Glyph_Class();
    this.raster = null;

    this.raster_render = null;
    this.render = null;
}

function create_renderer_smooth_module(library)
{
    var ren1_mod = new FT_Smooth_Renderer();
    ren1_mod.clazz = new FT_Smooth_Renderer_Class();
    ren1_mod.clazz.render_glyph = ft_smooth_render;

    ren1_mod.library = library;
    ren1_mod.memory = library.Memory;
    ren1_mod.generic = null;

    return ren1_mod;
}
function create_renderer_smooth_lcd_module(library)
{
    var ren1_mod = new FT_Smooth_Renderer();
    ren1_mod.clazz = new FT_Smooth_Renderer_Class();
    ren1_mod.clazz.render_glyph = ft_smooth_render_lcd;

    ren1_mod.library = library;
    ren1_mod.memory = library.Memory;
    ren1_mod.generic = null;

    return ren1_mod;
}
function create_renderer_smooth_lcd_v_module(library)
{
    var ren1_mod = new FT_Smooth_Renderer();
    ren1_mod.clazz = new FT_Smooth_Renderer_Class();
    ren1_mod.clazz.render_glyph = ft_smooth_render_lcd_v;

    ren1_mod.library = library;
    ren1_mod.memory = library.Memory;
    ren1_mod.generic = null;

    return ren1_mod;
}

function ft_smooth_init(render)
{
    render.clazz.raster_class.raster_reset(render.raster, render.library.raster_pool, render.library.raster_pool_size);
    return 0;
}

function ft_smooth_set_mode(render, mode_tag, data)
{
    return render.clazz.raster_class.raster_set_mode(render.raster, mode_tag, data);
}

function ft_smooth_transform(render, slot, matrix, delta)
{
    if (slot.format != render.glyph_format)
        return 6;

    if (matrix)
        FT_Outline_Transform(slot.outline, matrix);

    if (delta)
        FT_Outline_Translate(slot.outline, delta.x, delta.y);

    return 0;
}

function ft_smooth_get_cbox(render, slot, cbox)
{
    cbox.xMin = 0;
    cbox.yMin = 0;
    cbox.xMax = 0;
    cbox.yMax = 0;

    if (slot.format == render.glyph_format)
        FT_Outline_Get_CBox(slot.outline, cbox);
}

function ft_smooth_render(render, slot, mode, origin)
{
    if (mode == 1)
        mode = 0;

    return ft_smooth_render_generic(render, slot, mode, origin, 0);
}

function ft_smooth_render_lcd(render, slot, mode, origin)
{
    var error = ft_smooth_render_generic(render, slot, mode, origin, 3);
    if (error == 0)
        slot.bitmap.pixel_mode = 5;

    return error;
}

function ft_smooth_render_lcd_v(render, slot, mode, origin)
{
    var error = ft_smooth_render_generic(render, slot, mode, origin, 4);
    if (error == 0)
        slot.bitmap.pixel_mode = 6;

    return error;
}

function ft_smooth_render_generic(render, slot, mode, origin, required_mode)
{
    var error = 0;
    var outline = null;
    var cbox = new FT_BBox();
    var width, height, pitch;

    //#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
    var height_org, width_org;
    //#endif

    var hmul = (mode == 3) ? 1 : 0;
    var vmul = (mode == 4) ? 1 : 0;
    var x_shift, y_shift, x_left, y_top;

    var params = new FT_Raster_Params();

    /* check glyph image format */
    if (slot.format != render.glyph_format)
        return 6;

    /* check mode */
    if (mode != required_mode)
        return 19;

    outline = slot.outline;

    /* translate the outline to the new origin if needed */
    if (origin != null)
        FT_Outline_Translate(outline, origin.x, origin.y);

    /* compute the control box, and grid fit it */
    FT_Outline_Get_CBox(outline, cbox);

    cbox.xMin = (cbox.xMin & ~63);
    cbox.yMin = (cbox.yMin & ~63);
    cbox.xMax = ((cbox.xMax+63) & ~63);
    cbox.yMax = ((cbox.yMax+63) & ~63);

    if (cbox.xMin < 0 && cbox.xMax > 2147483647 + cbox.xMin)
    {
        if (outline && origin)
            FT_Outline_Translate(outline, -origin.x, -origin.y);
        return 98;
    }
    else
        width  = ((cbox.xMax - cbox.xMin) >>> 6);

    if ( cbox.yMin < 0 && cbox.yMax > 2147483647 + cbox.yMin )
    {
        if ( outline && origin )
            FT_Outline_Translate( outline, -origin.x, -origin.y );
        return 98;
    }
    else
        height = ((cbox.yMax - cbox.yMin) >>> 6);

    var bitmap = slot.bitmap;
    var memory = render.memory;

    //#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
    width_org  = width;
    height_org = height;
    //#endif

    /* release old bitmap buffer */
    if (slot.internal.flags & 1)
    {
        delete bitmap.buffer;
        slot.internal.flags &= ~1;
    }

    /* allocate new one */
    pitch = width;
    if (hmul == 1)
    {
        width = width * 3;
        pitch = (width + 3) & ~3;
    }

    if (vmul == 1)
        height *= 3;

    x_shift = cbox.xMin;
    y_shift = cbox.yMin;
    x_left  = cbox.xMin >> 6;
    y_top   = cbox.yMax >> 6;

    //#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
    /*
    if (slot.library.lcd_filter_func)
    {
        var extra = slot.library.lcd_extra;
        if (hmul == 1)
        {
            x_shift -= 64 * (extra >>> 1);
            width   += 3 * extra;
            pitch    = (width + 3) & ~3;
            x_left  -= (extra >>> 1);
        }
        if (vmul == 1)
        {
            y_shift -= 64 * (extra >>> 1);
            height  += 3 * extra;
            y_top   += (extra >>> 1);
        }
    }
    */
    //#endif

    if (width > 0x7FFF || height > 0x7FFF)
    {
        if (outline && origin)
            FT_Outline_Translate(outline, -origin.x, -origin.y);
        return 98;
    }

    bitmap.pixel_mode = 2;
    bitmap.num_grays  = 256;
    bitmap.width      = width;
    bitmap.rows       = height;
    bitmap.pitch      = pitch;

    if (bitmap.width > 1000 || bitmap.height > 1000)
        return 130;

    /* translate outline to render it into the bitmap */
    FT_Outline_Translate(outline, -x_shift, -y_shift);
    var memory = slot.library.Memory;

    //bitmap.buffer = memory.Alloc(pitch * height);

    slot.internal.flags |= 1;

    /* set up parameters */
    params.target = bitmap;
    params.source = outline;
    params.flags  = 1;

    //#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
    /*
    var points = outline.points;
    var count = outline.n_points;

    if (hmul == 1)
        for (var i = 0; i < count; i++)
            points[i].x = points[i].x * 3;

    if (vmul == 1)
        for (var i = 0; i < count; i++)
            points[i].y = points[i].y * 3;
    error = render.raster_render(render.raster, params);
    if (hmul == 1)
        for (var i = 0; i < count; i++)
            points[i].x = parseInt(points[i].x / 3);

    if (vmul == 1)
        for (var i = 0; i < count; i++)
            points[i].y = parseInt(points[i].y / 3);

    if (slot.library.lcd_filter_func)
        slot.library.lcd_filter_func(bitmap, mode, slot.library);
    */

    //#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
    error = render.raster_render(render.raster, params);
    if (hmul == 1)
    {
        var pixels = bitmap.buffer.data;
        var line = 0;
        for (var hh = height_org; hh > 0; hh--, line += pitch)
        {
            var end = line + width;
            for (var xx = width_org; xx > 0; xx--)
            {
                var pixel = pixels[line+xx-1];

                pixels[end-3] = pixel;
                pixels[end-2] = pixel;
                pixels[end-1] = pixel;
                end -= 3;
            }
        }
    }
    if (vmul == 1)
    {
        var pixels = bitmap.buffer.data;
        var read = (height - height_org) * pitch;
        var write = 0;
        var ii = 0;
        for (var hh = height_org; hh > 0; hh--)
        {
            for (ii=0;ii<pitch;ii++)
                pixels[write+ii] = pixels[read+ii];

            write += pitch;

            for (ii=0;ii<pitch;ii++)
                pixels[write+ii] = pixels[read+ii];

            write += pitch;

            for (ii=0;ii<pitch;ii++)
                pixels[write+ii] = pixels[read+ii];

            write += pitch;
            read  += pitch;
        }
    }
    //#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */

    FT_Outline_Translate(outline, x_shift, y_shift);

    if (x_left > 0x7FFFFFFF || y_top > 0x7FFFFFFF)
        return 23;

    if (error == 0)
    {
        slot.format      = 1651078259;
        slot.bitmap_left = x_left;
        slot.bitmap_top  = y_top;
    }

    if ( outline && origin )
        FT_Outline_Translate(outline, -origin.x, -origin.y);

    return error;
}
var TT_Round_Off             = 5;
var TT_Round_To_Half_Grid    = 0;
var TT_Round_To_Grid         = 1;
var TT_Round_To_Double_Grid  = 2;
var TT_Round_Up_To_Grid      = 4;
var TT_Round_Down_To_Grid    = 3;
var TT_Round_Super           = 6;
var TT_Round_Super_45        = 7;

function LibraryHintingParams()
{
    this.TT_USE_BYTECODE_INTERPRETER            = false;
    this.TT_CONFIG_OPTION_SUBPIXEL_HINTING      = false;
    this.TT_CONFIG_OPTION_UNPATENTED_HINTING    = false;

    this.TT_HINTER_FLAG = (this.TT_USE_BYTECODE_INTERPRETER) ? 1024 : 0;
    this.TT_CONFIG_OPTION_INTERPRETER_SWITCH    = false;
}

function TT_CallRec()
{
    this.Caller_Range   = 0;
    this.Caller_IP      = 0;
    this.Cur_Count      = 0;

    this.Def            = null;
}

function SPH_TweakRule()
{
    this.family = "";
    this.ppem = 0;
    this.style = "";
    this.glyph = 0;
}

function SPH_ScaleRule()
{
    this.family = "";
    this.ppem = 0;
    this.style = "";
    this.glyph = 0;
    this.scale = 0;
}

var MAX_NAME_SIZE       = 32;
var MAX_CLASS_MEMBERS   = 100;

function Font_Class()
{
    this.name = "";
    this.member = null;
}
function create_font_class(name, arr)
{
    var fc = new Font_Class();
    fc.name = name;
    fc.member = arr;
    return fc;
}

function FT_UnitVector()
{
    this.x = 0;
    this.y = 0;
}

function TT_GraphicsState()
{
    this.rp0 = 0;
    this.rp1 = 0;
    this.rp2 = 0;

    this.dualVector = new FT_UnitVector();
    this.projVector = new FT_UnitVector();
    this.freeVector = new FT_UnitVector();

    // #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
    this.both_x_axis = false;
    // #endif

    this.loop = 0;
    this.minimum_distance = 0;
    this.round_state = 0;

    this.auto_flip = false;
    this.control_value_cutin = 0;
    this.single_width_cutin = 0;
    this.single_width_value = 0;
    this.delta_base = 0;
    this.delta_shift = 0;

    this.instruct_control = 0;
    /* According to Greg Hitchcock from Microsoft, the `scan_control'     */
    /* variable as documented in the TrueType specification is a 32-bit   */
    /* integer; the high-word part holds the SCANTYPE value, the low-word */
    /* part the SCANCTRL value.  We separate it into two fields.          */
    this.scan_control = false;
    this.scan_type = 0;

    this.gep0 = 0;
    this.gep1 = 0;
    this.gep2 = 0;
}
TT_GraphicsState.prototype =
{
    default_tt : function()
    {
        this.rp0 = 0;
        this.rp1 = 0;
        this.rp2 = 0;

        this.dualVector.x = 0x4000; this.dualVector.y = 0;
        this.projVector.x = 0x4000; this.projVector.y = 0;
        this.freeVector.x = 0x4000; this.freeVector.y = 0;

        this.both_x_axis = true;

        this.loop = 1;
        this.minimum_distance = 64;
        this.round_state = 1;

        this.auto_flip = true;
        this.control_value_cutin = 68;
        this.single_width_cutin = 0;
        this.single_width_value = 0;
        this.delta_base = 9;
        this.delta_shift = 3;

        this.instruct_control = 0;
        /* According to Greg Hitchcock from Microsoft, the `scan_control'     */
        /* variable as documented in the TrueType specification is a 32-bit   */
        /* integer; the high-word part holds the SCANTYPE value, the low-word */
        /* part the SCANCTRL value.  We separate it into two fields.          */
        this.scan_control = false;
        this.scan_type = 0;

        this.gep0 = 1;
        this.gep1 = 1;
        this.gep2 = 1;
    },

    Copy : function(dst)
    {
        dst.rp0 = this.rp0;
        dst.rp1 = this.rp1;
        dst.rp2 = this.rp2;

        dst.dualVector.x = this.dualVector.x; dst.dualVector.y = this.dualVector.y;
        dst.projVector.x = this.projVector.x; dst.projVector.y = this.projVector.y;
        dst.freeVector.x = this.freeVector.x; dst.freeVector.y = this.freeVector.y;

        dst.both_x_axis = this.both_x_axis;

        dst.loop = this.loop;
        dst.minimum_distance = this.minimum_distance;
        dst.round_state = this.round_state;

        dst.auto_flip = this.auto_flip;
        dst.control_value_cutin = this.control_value_cutin;
        dst.single_width_cutin = this.single_width_cutin;
        dst.single_width_value = this.single_width_value;
        dst.delta_base = this.delta_base;
        dst.delta_shift = this.delta_shift;

        dst.instruct_control = this.instruct_control;
        /* According to Greg Hitchcock from Microsoft, the `scan_control'     */
        /* variable as documented in the TrueType specification is a 32-bit   */
        /* integer; the high-word part holds the SCANTYPE value, the low-word */
        /* part the SCANCTRL value.  We separate it into two fields.          */
        dst.scan_control = this.scan_control;
        dst.scan_type = this.scan_type;

        dst.gep0 = this.gep0;
        dst.gep1 = this.gep1;
        dst.gep2 = this.gep2;
    }
}

function TT_DefRecord()
{
    this.range = 0;             /* in which code range is it located?     */
    this.start = 0;             /* where does it start?                   */
    this.end   = 0;             /* where does it end?                     */
    this.opc   = 0;             /* function #, or instruction code        */
    this.active = false;        /* is it active?                          */
    this.inline_delta = false;  /* is function that defines inline delta? */
    this.sph_fdef_flags = 0;
}

function TT_CodeRange()
{
    this.base = null;
    this.size = 0;
}
function coderange_copy(d, s)
{
    d.base = dublicate_pointer(s.base);
    d.size = s.size;
}

function TT_ExecContextRec()
{
    this.face   = null;
    this.size   = null;
    this.memory = null;

    /* instructions state */
    this.error  = 0;      /* last execution error */
    this.top    = 0;        /* top of exec. stack   */

    this.stackSize  = 0;  /* size of exec. stack  */
    this.stack      = null;      /* current exec. stack  */

    this.args       = 0;
    this.new_top    = 0;    /* new top after exec.  */

    this.zp0 = new TT_GlyphZoneRec();
    this.zp1 = new TT_GlyphZoneRec();
    this.zp2 = new TT_GlyphZoneRec();
    this.pts = new TT_GlyphZoneRec();
    this.twilight = new TT_GlyphZoneRec();

    this.metrics = new FT_Size_Metrics();
    this.tt_metrics = new TT_Size_Metrics(); /* size metrics */

    this.GS = new TT_GraphicsState();         /* current graphics state */

    this.curRange = 0;  /* current code range number   */
    this.code = null;   /* current code range          */
    this.IP = 0;        /* current instruction pointer */
    this.codeSize = 0;  /* size of current range       */

    this.opcode = 0;    /* current opcode              */
    this.length = 0;    /* length of current opcode    */

    this.step_ins = false;  /* true if the interpreter must */
                            /* increment IP after ins. exec */
    this.cvtSize = 0;
    this.cvt = null;

    this.glyphSize = 0; /* glyph instructions buffer size */
    this.glyphIns = null;  /* glyph instructions buffer */

    this.numFDefs = 0;  /* number of function defs         */
    this.maxFDefs = 0;  /* maximum number of function defs */
    this.FDefs = null;     /* table of FDefs entries          */

    this.numIDefs = 0;  /* number of instruction defs */
    this.maxIDefs = 0;  /* maximum number of ins defs */
    this.IDefs = null;     /* table of IDefs entries     */

    this.maxFunc = 0;   /* maximum function index     */
    this.maxIns = 0;    /* maximum instruction index  */

    this.callTop = 0;    /* top of call stack during execution */
    this.callSize = 0;   /* size of call stack */
    this.callStack = null;  /* call stack */

    this.maxPoints = 0;    /* capacity of this context's `pts' */
    this.maxContours = 0;  /* record, expressed in points and  */
                                     /* contours.                        */

    /* table of valid code ranges */
    /* useful for the debugger   */
    this.codeRangeTable = new Array(3);
    for (var i = 0; i < 3; i++)
        this.codeRangeTable[i] = new TT_CodeRange();
    
    this.storeSize = 0;  /* size of current storage */
    this.storage = null;    /* storage area            */

    this.period = 0;     /* values used for the */
    this.phase = 0;      /* `SuperRounding'     */
    this.threshold = 0;

    //#if 0
    /* this seems to be unused */
    //FT_Int             cur_ppem;   /* ppem along the current proj vector */
    //#endif

    this.instruction_trap = false; /* If `True', the interpreter will */
                                         /* exit after each instruction     */

    this.default_GS = new TT_GraphicsState();       /* graphics state resulting from   */
                                                    /* the prep program                */
    this.is_composite = false;     /* true if the glyph is composite  */
    this.pedantic_hinting = false; /* true if pedantic interpretation */

    /* latest interpreter additions */
    this.F_dot_P = 0;           /* dot product of freedom and projection */
                                /* vectors                               */
    this.func_round = null;     /* current rounding function             */

    this.func_project = null;   /* current projection function */
    this.func_dualproj = null;  /* current dual proj. function */
    this.func_freeProj = null;  /* current freedom proj. func  */

    this.func_move = null;      /* current point move function */
    this.func_move_orig = null; /* move original position function */

    this.func_read_cvt = null;  /* read a cvt entry              */
    this.func_write_cvt = null; /* write a cvt entry (in pixels) */
    this.func_move_cvt = null;  /* incr a cvt entry (in pixels)  */

    this.grayscale = false;      /* are we hinting for grayscale? */

    // #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
    this.func_round_sphn = null;          /* subpixel rounding function */

    this.grayscale_hinting = false;       /* Using grayscale hinting?      */
    this.subpixel_hinting = false;        /* Using subpixel hinting?       */
    this.native_hinting = false;          /* Using native hinting?         */
    this.ignore_x_mode  = false;          /* Standard rendering mode for   */
                                          /* subpixel hinting.  On if gray */
                                          /* or subpixel hinting is on )   */
    this.compatibility_mode = false;      /* Additional exceptions to      */
                                          /* native TT rules for legacy    */
                                          /* fonts.  Implies               */
                                          /* ignore_x_mode.                */

    /* The following 4 aren't fully implemented but here for MS rasterizer */
    /* compatibility.                                                      */
    this.compatible_widths = false;     /* compatible widths?        */
    this.symmetrical_smoothing = false; /* symmetrical_smoothing?    */
    this.bgr = false;                   /* bgr instead of rgb?       */
    this.subpixel_positioned = false;   /* subpixel positioned       */
                                              /* (DirectWrite ClearType)?  */

    this.rasterizer_version = 0;    /* MS rasterizer version */

    this.iup_called = false;            /* IUP called for glyph?  */

    this.sph_tweak_flags = 0;       /* flags to control */
                                    /* hint tweaks      */

    this.sph_in_func_flags = 0;     /* flags to indicate if in   */
                                    /* special functions         */

    // #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
}

function Init_Context(exec, memory)
{
    exec.memory   = memory;
    exec.callSize = 32;

    exec.callStack = new Array(exec.callSize);
    for (var i = 0; i < exec.callSize; i++)
        exec.callStack[i] = new TT_CallRec();

    /* all values in the context are set to 0 already, but this is */
    /* here as a remainder                                         */
    exec.maxPoints   = 0;
    exec.maxContours = 0;

    exec.stackSize = 0;
    exec.glyphSize = 0;

    exec.stack     = null;
    exec.glyphIns  = null;

    exec.face = null;
    exec.size = null;

    return 0;
}

function TT_New_Context(driver)
{
    if (driver.context == null)
    {
        driver.context = new TT_ExecContextRec();

        /* initialize it; in case of error this deallocates `exec' too */
        var error = Init_Context(driver.context, driver.memory);
        if (error != 0)
            driver.context = null;
    }
    return driver.context;
}

function TT_Done_Context(exec)
{
    /* points zone */
    exec.maxPoints   = 0;
    exec.maxContours = 0;

    /* free stack */
    exec.stack      = null;
    exec.stackSize  = 0;

    /* free call stack */
    exec.callStack  = null;
    exec.callSize   = 0;
    exec.callTop    = 0;

    /* free glyph code range */
    exec.glyphIns   = null;
    exec.glyphSize  = 0;

    exec.size       = null;
    exec.face       = null;

    return 0;
}

function TT_Load_Context(exec, face, size)
{
    exec.face = face;
    var maxp = face.max_profile;
    exec.size = size;

    if (size != null)
    {
        exec.numFDefs   = size.num_function_defs;
        exec.maxFDefs   = size.max_function_defs;
        exec.numIDefs   = size.num_instruction_defs;
        exec.maxIDefs   = size.max_instruction_defs;
        exec.FDefs      = size.function_defs;
        exec.IDefs      = size.instruction_defs;
        exec.tt_metrics.Copy(size.ttmetrics);
        exec.metrics.Copy(size.metrics);

        exec.maxFunc    = size.max_func;
        exec.maxIns     = size.max_ins;

        for (var i = 0; i < 3; i++)
            coderange_copy(exec.codeRangeTable[i], size.codeRangeTable[i]);

        /* set graphics state */
        size.GS.Copy(exec.GS);

        exec.cvtSize = size.cvt_size;
        exec.cvt     = size.cvt;

        exec.storeSize = size.storage_size;
        exec.storage   = size.storage;

        exec.twilight.Copy(size.twilight);

        /* In case of multi-threading it can happen that the old size object */
        /* no longer exists, thus we must clear all glyph zone references.   */
        exec.zp0.Clear();
        exec.zp1.Clear();
        exec.zp2.Clear();
    }

    /* XXX: We reserve a little more elements on the stack to deal safely */
    /*      with broken fonts like arialbs, courbs, timesbs, etc.         */
    var ret = Update_MaxLONG(exec.memory, exec.stackSize, exec.stack, maxp.maxStackElements + 32);
    if (null != ret)
    {
        exec.stackSize = ret.size;
        exec.stack = ret.block;

        if (ret.err != 0)
            return ret.err;
    }
    
    ret = Update_MaxBYTE(exec.memory, exec.glyphSize, exec.glyphIns, maxp.maxSizeOfInstructions);
    if (ret != null)
    {
        exec.glyphSize = ret.size;
        exec.glyphIns = ret.block;

        if (ret.err != 0)
            return ret.err;
    }

    exec.pts.n_points   = 0;
    exec.pts.n_contours = 0;

    exec.zp1.Copy(exec.pts);
    exec.zp2.Copy(exec.pts);
    exec.zp0.Copy(exec.pts);

    exec.instruction_trap = false;

    return 0;
}

function Update_MaxBYTE(memory, size, buff, new_max)
{
    if (size >= new_max)
        return null;

    return FT_Common.realloc(memory, buff, size, new_max);
}
function Update_MaxLONG(memory, size, buff, new_max)
{
    if (size >= new_max)
        return null;

    return FT_Common.realloc_long(memory, buff, size, new_max);
}

function tt_size_ready_bytecode(size, pedantic)
{
    var error = 0;
    if (!size.bytecode_ready)
    {
        error = tt_size_init_bytecode(size, pedantic);
        if (error != 0)
            return error;
    }

    /* rescale CVT when needed */
    if (!size.cvt_ready)
    {
        var face = size.face;

        /* Scale the cvt values to the new ppem.          */
        /* We use by default the y ppem to scale the CVT. */
        for (var i = 0; i < size.cvt_size; i++)
            size.cvt[i] = FT_MulFix(face.cvt[i], size.ttmetrics.scale);

        /* all twilight points are originally zero */
        for (var i = 0; i < size.twilight.n_points; i++ )
        {
            size.twilight.org[size.twilight._offset_org + i].x = 0;
            size.twilight.org[size.twilight._offset_org + i].y = 0;
            size.twilight.cur[size.twilight._offset_cur + i].x = 0;
            size.twilight.cur[size.twilight._offset_cur + i].y = 0;
        }

        /* clear storage area */
        for (var i = 0; i < size.storage_size; i++)
            size.storage[i] = 0;

        size.GS.default_tt();

        error = tt_size_run_prep(size, pedantic);
        if (error != 0)
            size.cvt_ready = 1;
    }
    return error;
}

function tt_size_init_bytecode(size, pedantic)
{
    var maxp = size.face.max_profile;

    size.bytecode_ready = 1;
    size.cvt_ready      = 0;

    size.max_function_defs    = maxp.maxFunctionDefs;
    size.max_instruction_defs = maxp.maxInstructionDefs;

    size.num_function_defs    = 0;
    size.num_instruction_defs = 0;

    size.max_func = 0;
    size.max_ins  = 0;

    size.cvt_size     = size.face.cvt_size;
    size.storage_size = maxp.maxStorage;

    /* Set default metrics */
    var metrics = size.ttmetrics;
    metrics.rotated   = false;
    metrics.stretched = false;

      /* set default compensation (all 0) */
    for (var i = 0; i < 4; i++)
        metrics.compensations[i] = 0;

    /* allocate function defs, instruction defs, cvt, and storage area */
    size.function_defs = new Array(size.max_function_defs);
    for (var i = 0; i < size.max_function_defs; i++)
        size.function_defs[i] = new TT_DefRecord();

    size.instruction_defs = new Array(size.max_instruction_defs);
    for (var i = 0; i < size.max_instruction_defs; i++)
        size.instruction_defs[i] = new TT_DefRecord();

    size.cvt = new CreateIntArray(size.cvt_size);
    size.storage = new CreateIntArray(size.storage_size);

    /* reserve twilight zone */
    var n_twilight = maxp.maxTwilightPoints;

    /* there are 4 phantom points (do we need this?) */
    n_twilight += 4;

    var error = tt_glyphzone_new(size.face.memory, n_twilight, 0, size.twilight);
    if (error != 0)
    {
        tt_size_done_bytecode(size);
        return error;
    }

    size.twilight.n_points = n_twilight;

    size.GS.default_tt();
    size.face.interpreter = TT_RunIns;

    /* Fine, now run the font program! */
    error = tt_size_run_fpgm(size, pedantic);
    if (error != 0)
        tt_size_done_bytecode(size);

    return error;
}

function tt_size_run_fpgm(size, pedantic)
{
    var face = size.face;
    var exec = null;

    /* debugging instances have their own context */
    if (size.debug)
        exec = size.context;
    else
        exec = face.driver.context;

    if (exec == null)
        return 153;

    TT_Load_Context(exec, face, size);

    exec.callTop = 0;
    exec.top     = 0;

    exec.period    = 64;
    exec.phase     = 0;
    exec.threshold = 0;

    exec.instruction_trap = false;
    exec.F_dot_P          = 0x4000;

    exec.pedantic_hinting = pedantic;

    var metrics = exec.metrics;
    var tt_metrics = exec.tt_metrics;

    metrics.x_ppem   = 0;
    metrics.y_ppem   = 0;
    metrics.x_scale  = 0;
    metrics.y_scale  = 0;

    tt_metrics.ppem  = 0;
    tt_metrics.scale = 0;
    tt_metrics.ratio = 0x10000;

    /* allow font program execution */
    TT_Set_CodeRange(exec, 1, face.font_program, face.font_program_size);

    /* disable CVT and glyph programs coderange */
    TT_Clear_CodeRange(exec, 2);
    TT_Clear_CodeRange(exec, 3);

    var error = 0;
    if (face.font_program_size > 0)
    {
        error = TT_Goto_CodeRange(exec, 1, 0);
        if (error == 0)
            error = face.interpreter(exec);
    }
    else
        error = 0;

    if (error == 0)
        TT_Save_Context(exec, size);

    return error;
}

function TT_Clear_CodeRange(exec, range)
{
    exec.codeRangeTable[range - 1].base = null;
    exec.codeRangeTable[range - 1].size = 0;

    return 0;
}

function TT_Save_Context(exec, size)
{
    /* XXX: Will probably disappear soon with all the code range */
    /*      management, which is now rather obsolete.            */
    /*                                                           */
    size.num_function_defs    = exec.numFDefs;
    size.num_instruction_defs = exec.numIDefs;

    size.max_func = exec.maxFunc;
    size.max_ins  = exec.maxIns;

    for (var i = 0; i < 3; i++)
    {
        size.codeRangeTable[i].base = dublicate_pointer(exec.codeRangeTable[i].base);
        size.codeRangeTable[i].size = exec.codeRangeTable[i].size;
    }

    return 0;
}

function tt_size_done_bytecode(size)
{
    if (size.debug)
    {
        /* the debug context must be deleted by the debugger itself */
        size.context = null;
        size.debug   = false;
    }

    size.cvt = null;
    size.cvt_size = 0;

    /* free storage area */
    size.storage = null;
    size.storage_size = 0;

    /* twilight zone */
    tt_glyphzone_done(size.twilight);

    size.function_defs = null;
    size.instruction_defs = null;

    size.num_function_defs    = 0;
    size.max_function_defs    = 0;
    size.num_instruction_defs = 0;
    size.max_instruction_defs = 0;

    size.max_func = 0;
    size.max_ins  = 0;

    size.bytecode_ready = false;
    size.cvt_ready      = false;
}

function tt_glyphzone_done(zone)
{
    if (zone.memory != null)
    {
        zone.contours = null;
        zone.tags = null;
        zone.cur = null;
        zone.org = null;
        zone.orus = null;

        zone.max_points = zone.n_points   = 0;
        zone.max_contours = zone.n_contours = 0;
        zone.memory = null;
    }
}

function tt_glyphzone_new(memory, maxPoints, maxContours, zone)
{
    zone.Clear();
    zone.memory = memory;

    zone.org = new Array(maxPoints);
    FT_CreateVectorArray(zone.org, 0, maxPoints);

    zone.cur = new Array(maxPoints);
    FT_CreateVectorArray(zone.cur, 0, maxPoints);

    zone.orus = new Array(maxPoints);
    FT_CreateVectorArray(zone.orus, 0, maxPoints);

    zone.tags = CreateIntArray(maxPoints);
    zone.contours = CreateIntArray(maxContours);

    zone.max_points   = maxPoints;
    zone.max_contours = maxContours;
    return 0;
}

function TT_Set_CodeRange(exec, range, base, length)
{
    exec.codeRangeTable[range - 1].base = dublicate_pointer(base);
    exec.codeRangeTable[range - 1].size = length;

    return 0;
}

function TT_Goto_CodeRange(exec, range, IP)
{
    var coderange = exec.codeRangeTable[range - 1];

    /* NOTE: Because the last instruction of a program may be a CALL */
    /*       which will return to the first byte *after* the code    */
    /*       range, we test for IP <= Size instead of IP < Size.     */
    /*                                                               */
    exec.code     = dublicate_pointer(coderange.base);
    exec.codeSize = coderange.size;
    exec.IP       = IP;
    exec.curRange = range;

    return 0;
}

function TT_Run_Context(exec, debug)
{
    var error = TT_Goto_CodeRange(exec, 3, 0);
    if (error != 0)
        return error;

    exec.zp0.Copy(exec.pts);
    exec.zp1.Copy(exec.pts);
    exec.zp2.Copy(exec.pts);

    exec.GS.gep0 = 1;
    exec.GS.gep1 = 1;
    exec.GS.gep2 = 1;

    exec.GS.projVector.x = 0x4000;
    exec.GS.projVector.y = 0x0000;

    exec.GS.freeVector.x = exec.GS.projVector.x;
    exec.GS.freeVector.y = exec.GS.projVector.y;
    exec.GS.dualVector.x = exec.GS.projVector.x;
    exec.GS.dualVector.y = exec.GS.projVector.y;

    if (exec.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_UNPATENTED_HINTING)//#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
    {
        exec.GS.both_x_axis = true;
    }//#endif

    exec.GS.round_state = 1;
    exec.GS.loop        = 1;

    /* some glyphs leave something on the stack. so we clean it */
    /* before a new execution.                                  */
    exec.top     = 0;
    exec.callTop = 0;

    return exec.face.interpreter(exec);
}

//--------------------------------------------------------------//

var opcode_length =
[1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,

-1,-2, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,

1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
2, 3, 4, 5,  6, 7, 8, 9,  3, 5, 7, 9, 11,13,15,17,

1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1];

function Pop_Push_PACK(x, y)
{
    return ((x << 4) | y);
}
var Pop_Push_Count =
[
    /* opcodes are gathered in groups of 16 */
    /* please keep the spaces as they are   */

    /*  SVTCA  y  */  Pop_Push_PACK( 0, 0 ),
    /*  SVTCA  x  */  Pop_Push_PACK( 0, 0 ),
    /*  SPvTCA y  */  Pop_Push_PACK( 0, 0 ),
    /*  SPvTCA x  */  Pop_Push_PACK( 0, 0 ),
    /*  SFvTCA y  */  Pop_Push_PACK( 0, 0 ),
    /*  SFvTCA x  */  Pop_Push_PACK( 0, 0 ),
    /*  SPvTL //  */  Pop_Push_PACK( 2, 0 ),
    /*  SPvTL +   */  Pop_Push_PACK( 2, 0 ),
    /*  SFvTL //  */  Pop_Push_PACK( 2, 0 ),
    /*  SFvTL +   */  Pop_Push_PACK( 2, 0 ),
    /*  SPvFS     */  Pop_Push_PACK( 2, 0 ),
    /*  SFvFS     */  Pop_Push_PACK( 2, 0 ),
    /*  GPV       */  Pop_Push_PACK( 0, 2 ),
    /*  GFV       */  Pop_Push_PACK( 0, 2 ),
    /*  SFvTPv    */  Pop_Push_PACK( 0, 0 ),
    /*  ISECT     */  Pop_Push_PACK( 5, 0 ),

    /*  SRP0      */  Pop_Push_PACK( 1, 0 ),
    /*  SRP1      */  Pop_Push_PACK( 1, 0 ),
    /*  SRP2      */  Pop_Push_PACK( 1, 0 ),
    /*  SZP0      */  Pop_Push_PACK( 1, 0 ),
    /*  SZP1      */  Pop_Push_PACK( 1, 0 ),
    /*  SZP2      */  Pop_Push_PACK( 1, 0 ),
    /*  SZPS      */  Pop_Push_PACK( 1, 0 ),
    /*  SLOOP     */  Pop_Push_PACK( 1, 0 ),
    /*  RTG       */  Pop_Push_PACK( 0, 0 ),
    /*  RTHG      */  Pop_Push_PACK( 0, 0 ),
    /*  SMD       */  Pop_Push_PACK( 1, 0 ),
    /*  ELSE      */  Pop_Push_PACK( 0, 0 ),
    /*  JMPR      */  Pop_Push_PACK( 1, 0 ),
    /*  SCvTCi    */  Pop_Push_PACK( 1, 0 ),
    /*  SSwCi     */  Pop_Push_PACK( 1, 0 ),
    /*  SSW       */  Pop_Push_PACK( 1, 0 ),

    /*  DUP       */  Pop_Push_PACK( 1, 2 ),
    /*  POP       */  Pop_Push_PACK( 1, 0 ),
    /*  CLEAR     */  Pop_Push_PACK( 0, 0 ),
    /*  SWAP      */  Pop_Push_PACK( 2, 2 ),
    /*  DEPTH     */  Pop_Push_PACK( 0, 1 ),
    /*  CINDEX    */  Pop_Push_PACK( 1, 1 ),
    /*  MINDEX    */  Pop_Push_PACK( 1, 0 ),
    /*  AlignPTS  */  Pop_Push_PACK( 2, 0 ),
    /*  INS_$28   */  Pop_Push_PACK( 0, 0 ),
    /*  UTP       */  Pop_Push_PACK( 1, 0 ),
    /*  LOOPCALL  */  Pop_Push_PACK( 2, 0 ),
    /*  CALL      */  Pop_Push_PACK( 1, 0 ),
    /*  FDEF      */  Pop_Push_PACK( 1, 0 ),
    /*  ENDF      */  Pop_Push_PACK( 0, 0 ),
    /*  MDAP[0]   */  Pop_Push_PACK( 1, 0 ),
    /*  MDAP[1]   */  Pop_Push_PACK( 1, 0 ),

    /*  IUP[0]    */  Pop_Push_PACK( 0, 0 ),
    /*  IUP[1]    */  Pop_Push_PACK( 0, 0 ),
    /*  SHP[0]    */  Pop_Push_PACK( 0, 0 ),
    /*  SHP[1]    */  Pop_Push_PACK( 0, 0 ),
    /*  SHC[0]    */  Pop_Push_PACK( 1, 0 ),
    /*  SHC[1]    */  Pop_Push_PACK( 1, 0 ),
    /*  SHZ[0]    */  Pop_Push_PACK( 1, 0 ),
    /*  SHZ[1]    */  Pop_Push_PACK( 1, 0 ),
    /*  SHPIX     */  Pop_Push_PACK( 1, 0 ),
    /*  IP        */  Pop_Push_PACK( 0, 0 ),
    /*  MSIRP[0]  */  Pop_Push_PACK( 2, 0 ),
    /*  MSIRP[1]  */  Pop_Push_PACK( 2, 0 ),
    /*  AlignRP   */  Pop_Push_PACK( 0, 0 ),
    /*  RTDG      */  Pop_Push_PACK( 0, 0 ),
    /*  MIAP[0]   */  Pop_Push_PACK( 2, 0 ),
    /*  MIAP[1]   */  Pop_Push_PACK( 2, 0 ),

    /*  NPushB    */  Pop_Push_PACK( 0, 0 ),
    /*  NPushW    */  Pop_Push_PACK( 0, 0 ),
    /*  WS        */  Pop_Push_PACK( 2, 0 ),
    /*  RS        */  Pop_Push_PACK( 1, 1 ),
    /*  WCvtP     */  Pop_Push_PACK( 2, 0 ),
    /*  RCvt      */  Pop_Push_PACK( 1, 1 ),
    /*  GC[0]     */  Pop_Push_PACK( 1, 1 ),
    /*  GC[1]     */  Pop_Push_PACK( 1, 1 ),
    /*  SCFS      */  Pop_Push_PACK( 2, 0 ),
    /*  MD[0]     */  Pop_Push_PACK( 2, 1 ),
    /*  MD[1]     */  Pop_Push_PACK( 2, 1 ),
    /*  MPPEM     */  Pop_Push_PACK( 0, 1 ),
    /*  MPS       */  Pop_Push_PACK( 0, 1 ),
    /*  FlipON    */  Pop_Push_PACK( 0, 0 ),
    /*  FlipOFF   */  Pop_Push_PACK( 0, 0 ),
    /*  DEBUG     */  Pop_Push_PACK( 1, 0 ),

    /*  LT        */  Pop_Push_PACK( 2, 1 ),
    /*  LTEQ      */  Pop_Push_PACK( 2, 1 ),
    /*  GT        */  Pop_Push_PACK( 2, 1 ),
    /*  GTEQ      */  Pop_Push_PACK( 2, 1 ),
    /*  EQ        */  Pop_Push_PACK( 2, 1 ),
    /*  NEQ       */  Pop_Push_PACK( 2, 1 ),
    /*  ODD       */  Pop_Push_PACK( 1, 1 ),
    /*  EVEN      */  Pop_Push_PACK( 1, 1 ),
    /*  IF        */  Pop_Push_PACK( 1, 0 ),
    /*  EIF       */  Pop_Push_PACK( 0, 0 ),
    /*  AND       */  Pop_Push_PACK( 2, 1 ),
    /*  OR        */  Pop_Push_PACK( 2, 1 ),
    /*  NOT       */  Pop_Push_PACK( 1, 1 ),
    /*  DeltaP1   */  Pop_Push_PACK( 1, 0 ),
    /*  SDB       */  Pop_Push_PACK( 1, 0 ),
    /*  SDS       */  Pop_Push_PACK( 1, 0 ),

    /*  ADD       */  Pop_Push_PACK( 2, 1 ),
    /*  SUB       */  Pop_Push_PACK( 2, 1 ),
    /*  DIV       */  Pop_Push_PACK( 2, 1 ),
    /*  MUL       */  Pop_Push_PACK( 2, 1 ),
    /*  ABS       */  Pop_Push_PACK( 1, 1 ),
    /*  NEG       */  Pop_Push_PACK( 1, 1 ),
    /*  FLOOR     */  Pop_Push_PACK( 1, 1 ),
    /*  CEILING   */  Pop_Push_PACK( 1, 1 ),
    /*  ROUND[0]  */  Pop_Push_PACK( 1, 1 ),
    /*  ROUND[1]  */  Pop_Push_PACK( 1, 1 ),
    /*  ROUND[2]  */  Pop_Push_PACK( 1, 1 ),
    /*  ROUND[3]  */  Pop_Push_PACK( 1, 1 ),
    /*  NROUND[0] */  Pop_Push_PACK( 1, 1 ),
    /*  NROUND[1] */  Pop_Push_PACK( 1, 1 ),
    /*  NROUND[2] */  Pop_Push_PACK( 1, 1 ),
    /*  NROUND[3] */  Pop_Push_PACK( 1, 1 ),

    /*  WCvtF     */  Pop_Push_PACK( 2, 0 ),
    /*  DeltaP2   */  Pop_Push_PACK( 1, 0 ),
    /*  DeltaP3   */  Pop_Push_PACK( 1, 0 ),
    /*  DeltaCn[0] */ Pop_Push_PACK( 1, 0 ),
    /*  DeltaCn[1] */ Pop_Push_PACK( 1, 0 ),
    /*  DeltaCn[2] */ Pop_Push_PACK( 1, 0 ),
    /*  SROUND    */  Pop_Push_PACK( 1, 0 ),
    /*  S45Round  */  Pop_Push_PACK( 1, 0 ),
    /*  JROT      */  Pop_Push_PACK( 2, 0 ),
    /*  JROF      */  Pop_Push_PACK( 2, 0 ),
    /*  ROFF      */  Pop_Push_PACK( 0, 0 ),
    /*  INS_$7B   */  Pop_Push_PACK( 0, 0 ),
    /*  RUTG      */  Pop_Push_PACK( 0, 0 ),
    /*  RDTG      */  Pop_Push_PACK( 0, 0 ),
    /*  SANGW     */  Pop_Push_PACK( 1, 0 ),
    /*  AA        */  Pop_Push_PACK( 1, 0 ),

    /*  FlipPT    */  Pop_Push_PACK( 0, 0 ),
    /*  FlipRgON  */  Pop_Push_PACK( 2, 0 ),
    /*  FlipRgOFF */  Pop_Push_PACK( 2, 0 ),
    /*  INS_$83   */  Pop_Push_PACK( 0, 0 ),
    /*  INS_$84   */  Pop_Push_PACK( 0, 0 ),
    /*  ScanCTRL  */  Pop_Push_PACK( 1, 0 ),
    /*  SDPVTL[0] */  Pop_Push_PACK( 2, 0 ),
    /*  SDPVTL[1] */  Pop_Push_PACK( 2, 0 ),
    /*  GetINFO   */  Pop_Push_PACK( 1, 1 ),
    /*  IDEF      */  Pop_Push_PACK( 1, 0 ),
    /*  ROLL      */  Pop_Push_PACK( 3, 3 ),
    /*  MAX       */  Pop_Push_PACK( 2, 1 ),
    /*  MIN       */  Pop_Push_PACK( 2, 1 ),
    /*  ScanTYPE  */  Pop_Push_PACK( 1, 0 ),
    /*  InstCTRL  */  Pop_Push_PACK( 2, 0 ),
    /*  INS_$8F   */  Pop_Push_PACK( 0, 0 ),

    /*  INS_$90  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$91  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$92  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$93  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$94  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$95  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$96  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$97  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$98  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$99  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$9A  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$9B  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$9C  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$9D  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$9E  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$9F  */   Pop_Push_PACK( 0, 0 ),

    /*  INS_$A0  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$A1  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$A2  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$A3  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$A4  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$A5  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$A6  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$A7  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$A8  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$A9  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$AA  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$AB  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$AC  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$AD  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$AE  */   Pop_Push_PACK( 0, 0 ),
    /*  INS_$AF  */   Pop_Push_PACK( 0, 0 ),

    /*  PushB[0]  */  Pop_Push_PACK( 0, 1 ),
    /*  PushB[1]  */  Pop_Push_PACK( 0, 2 ),
    /*  PushB[2]  */  Pop_Push_PACK( 0, 3 ),
    /*  PushB[3]  */  Pop_Push_PACK( 0, 4 ),
    /*  PushB[4]  */  Pop_Push_PACK( 0, 5 ),
    /*  PushB[5]  */  Pop_Push_PACK( 0, 6 ),
    /*  PushB[6]  */  Pop_Push_PACK( 0, 7 ),
    /*  PushB[7]  */  Pop_Push_PACK( 0, 8 ),
    /*  PushW[0]  */  Pop_Push_PACK( 0, 1 ),
    /*  PushW[1]  */  Pop_Push_PACK( 0, 2 ),
    /*  PushW[2]  */  Pop_Push_PACK( 0, 3 ),
    /*  PushW[3]  */  Pop_Push_PACK( 0, 4 ),
    /*  PushW[4]  */  Pop_Push_PACK( 0, 5 ),
    /*  PushW[5]  */  Pop_Push_PACK( 0, 6 ),
    /*  PushW[6]  */  Pop_Push_PACK( 0, 7 ),
    /*  PushW[7]  */  Pop_Push_PACK( 0, 8 ),

    /*  MDRP[00]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[01]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[02]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[03]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[04]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[05]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[06]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[07]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[08]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[09]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[10]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[11]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[12]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[13]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[14]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[15]  */  Pop_Push_PACK( 1, 0 ),

    /*  MDRP[16]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[17]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[18]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[19]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[20]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[21]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[22]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[23]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[24]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[25]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[26]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[27]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[28]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[29]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[30]  */  Pop_Push_PACK( 1, 0 ),
    /*  MDRP[31]  */  Pop_Push_PACK( 1, 0 ),

    /*  MIRP[00]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[01]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[02]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[03]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[04]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[05]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[06]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[07]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[08]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[09]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[10]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[11]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[12]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[13]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[14]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[15]  */  Pop_Push_PACK( 2, 0 ),

    /*  MIRP[16]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[17]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[18]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[19]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[20]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[21]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[22]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[23]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[24]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[25]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[26]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[27]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[28]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[29]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[30]  */  Pop_Push_PACK( 2, 0 ),
    /*  MIRP[31]  */  Pop_Push_PACK( 2, 0 )
];

function GUESS_VECTOR(exc, v)
{
    // TODO: unpatented
}

function Ins_SxVTL(exc, aIdx1, aIdx2, aOpc, Vec)
{
    if ((aIdx1 >= exc.zp2.n_points) || (aIdx2 >= exc.zp1.n_points))
    {
        if (exc.pedantic_hinting)
            exc.error = 0x86;
        return 1;
    }

    var p1 = exc.zp1.cur[exc.zp1._offset_cur + aIdx2];
    var p2 = exc.zp2.cur[exc.zp2._offset_cur + aIdx1];

    var A = p1.x - p2.x;
    var B = p1.y - p2.y;

    /* If p1 == p2, SPVTL and SFVTL behave the same as */
    /* SPVTCA[X] and SFVTCA[X], respectively.          */
    /*                                                 */
    /* Confirmed by Greg Hitchcock.                    */

    if (A == 0 && B == 0)
    {
        A = 0x4000;
        aOpc = 0;
    }

    if ((aOpc & 1) != 0)
    {
        var C =  B;   /* counter clockwise rotation */
        B =  A;
        A = -C;
    }

    Normalize(exc, A, B, Vec);

    return 0;
}

function TT_VecLen(X, Y)
{
    if (X > 2147483647 || Y > 2147483647)
        alert("error");

    var v = new FT_Vector();
    v.x = X;
    v.y = Y;
    return FT_Vector_Length(v);
}

var FT_Hypot = TT_VecLen;

function FT_DivFix14(a, b)
{
    return FT_DivFix(a, b << 2);
}

function Normalize(exc, Vx, Vy, R)
{
    if (Vx > 2147483647 || Vy > 2147483647)
        alert("error");

    if (Math.abs(Vx) < 0x4000 && Math.abs(Vy) < 0x4000)
    {
        if (0 == Vx && 0 == Vy)
            return 0;

        Vx *= 0x4000;
        Vy *= 0x4000;
    }

    var W = FT_Hypot(Vx, Vy);

    R.x = FT_Common.UShort_To_Short(FT_DivFix14(Vx, W) & 0xFFFF);   /* Type conversion */
    R.y = FT_Common.UShort_To_Short(FT_DivFix14(Vy, W) & 0xFFFF);   /* Type conversion */

    return 0;
}

// ------
function Compute_Funcs(exc)
{
    // TODO: unpatented
    if (exc.GS.freeVector.x == 0x4000)
        exc.F_dot_P = exc.GS.projVector.x;
    else if (exc.GS.freeVector.y == 0x4000)
        exc.F_dot_P = exc.GS.projVector.y;
    else
        exc.F_dot_P = (exc.GS.projVector.x * exc.GS.freeVector.x + exc.GS.projVector.y * exc.GS.freeVector.y) >> 14;

    if (exc.GS.projVector.x == 0x4000)
        exc.func_project = Project_x;
    else if (exc.GS.projVector.y == 0x4000)
        exc.func_project = Project_y;
    else
        exc.func_project = Project;

    if (exc.GS.dualVector.x == 0x4000)
        exc.func_dualproj = Project_x;
    else if (exc.GS.dualVector.y == 0x4000)
        exc.func_dualproj = Project_y;
    else
        exc.func_dualproj = Dual_Project;

    exc.func_move      = Direct_Move;
    exc.func_move_orig = Direct_Move_Orig;

    if (exc.F_dot_P == 0x4000)
    {
        if ( exc.GS.freeVector.x == 0x4000 )
        {
            exc.func_move      = Direct_Move_X;
            exc.func_move_orig = Direct_Move_Orig_X;
        }
        else if ( exc.GS.freeVector.y == 0x4000 )
        {
            exc.func_move      = Direct_Move_Y;
            exc.func_move_orig = Direct_Move_Orig_Y;
        }
    }

    /* at small sizes, F_dot_P can become too small, resulting   */
    /* in overflows and `spikes' in a number of glyphs like `w'. */
    if (Math.abs(exc.F_dot_P) < 0x400)
        exc.F_dot_P = 0x4000;

    /* Disable cached aspect ratio */
    exc.tt_metrics.ratio = 0;
}

function Project(exc, dx, dy)
{
    if (dx > 2147483647 || dy > 2147483647)
        alert("error");

    return TT_DotFix14(dx, dy, exc.GS.projVector.x, exc.GS.projVector.y);
}
function Project_x(exc, dx, dy)
{
    if (dx > 2147483647 || dy > 2147483647)
        alert("error");

    return dx;
}
function Project_y(exc, dx, dy)
{
    if (dx > 2147483647 || dy > 2147483647)
        alert("error");

    return dy;
}
function Dual_Project(exc, dx, dy)
{
    if (dx > 2147483647 || dy > 2147483647)
        alert("error");
    
    return TT_DotFix14(dx, dy, exc.GS.dualVector.x, exc.GS.dualVector.y);
}

function Direct_Move(exc, zone, point, distance)
{
    if (point < 0 || point > 0xFFFF || distance > 2147483647)
        alert("error");

    var v = exc.GS.freeVector.x;
    if (v != 0)
    {
        if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)
        {
            if (!exc.ignore_x_mode || (exc.sph_tweak_flags & 1))
            {
                 zone.cur[zone._offset_cur + point].x += FT_MulDiv(distance, v, exc.F_dot_P);
            }
        }
        else
        {
            zone.cur[zone._offset_cur + point].x += FT_MulDiv(distance, v, exc.F_dot_P);
        }

        zone.tags[zone._offset_tags + point] |= 8;
    }

    v = exc.GS.freeVector.y;

    if (v != 0)
    {
        zone.cur[zone._offset_cur + point].y += FT_MulDiv(distance, v, exc.F_dot_P);
        zone.tags[zone._offset_tags + point] |= 16;
    }
}

function Direct_Move_Orig(exc, zone, point, distance)
{
    if (point < 0 || point > 0xFFFF || distance > 2147483647)
        alert("error");

    var v = exc.GS.freeVector.x;

    if (v != 0)
    {
        zone.org[zone._offset_org + point].x += FT_MulDiv(distance, v, exc.F_dot_P);
    }

    v = exc.GS.freeVector.y;

    if (v != 0)
    {
        zone.org[zone._offset_org + point].y += FT_MulDiv(distance, v, exc.F_dot_P);
    }
}

function Direct_Move_X(exc, zone, point, distance)
{
    if (point < 0 || point > 0xFFFF || distance > 2147483647)
        alert("error");

    if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)
    {
        if (!exc.ignore_x_mode)
        {
            zone.cur[zone._offset_cur + point].x += distance;
        }
        zone.tags[zone._offset_tags + point] |= 8;
    }
    else
    {
        zone.cur[zone._offset_cur + point].x += distance;
        zone.tags[zone._offset_tags + point] |= 8;
    }
}

function Direct_Move_Y(exc, zone, point, distance)
{
    if (point < 0 || point > 0xFFFF || distance > 2147483647)
        alert("error");

    zone.cur[zone._offset_cur + point].y += distance;
    zone.tags[zone._offset_tags + point] |= 16;
}

function Direct_Move_Orig_X(exc, zone, point, distance)
{
    if (point < 0 || point > 0xFFFF || distance > 2147483647)
        alert("error");

    zone.org[zone._offset_org + point].x += distance;
}

function Direct_Move_Orig_Y(exc, zone, point, distance)
{
    if (point < 0 || point > 0xFFFF || distance > 2147483647)
        alert("error");
    
    zone.org[zone._offset_org + point].y += distance;
}

// ------

// ------
function Compute_Round(exc, round_mode)
{
    switch (round_mode)
    {
    case TT_Round_Off:
        exc.func_round = Round_None;
        break;

    case TT_Round_To_Grid:
        exc.func_round = Round_To_Grid;
        break;

    case TT_Round_Up_To_Grid:
        exc.func_round = Round_Up_To_Grid;
        break;

    case TT_Round_Down_To_Grid:
        exc.func_round = Round_Down_To_Grid;
        break;

    case TT_Round_To_Half_Grid:
        exc.func_round = Round_To_Half_Grid;
        break;

    case TT_Round_To_Double_Grid:
        exc.func_round = Round_To_Double_Grid;
        break;

    case TT_Round_Super:
        exc.func_round = Round_Super;
        break;

    case TT_Round_Super_45:
        exc.func_round = Round_Super_45;
        break;
    }
}

function Round_None(exc, distance, compensation)
{
    if (distance > 2147483647 || compensation > 2147483647)
        alert("error");

    var val;
    if (distance >= 0)
    {
        val = distance + compensation;
        if (distance != 0 && val < 0)
            val = 0;
    }
    else
    {
        val = distance - compensation;
        if (val > 0)
            val = 0;
    }
    return val;
}

function Round_To_Grid(exc, distance, compensation)
{
    if (distance > 2147483647 || compensation > 2147483647)
        alert("error");

    var val;
    if (distance >= 0)
    {
        val = distance + compensation + 32;
        if (distance != 0 && val > 0)
            val &= ~63;
        else
            val = 0;
    }
    else
    {
        val = -FT_PIX_ROUND(compensation - distance);
        if (val > 0)
            val = 0;
    }

    return  val;
}

function Round_Up_To_Grid(exc, distance, compensation)
{
    if (distance > 2147483647 || compensation > 2147483647)
        alert("error");

    var val;
    if (distance >= 0)
    {
        val = distance + compensation + 63;
        if (distance != 0 && val > 0)
            val &= ~63;
        else
            val = 0;
    }
    else
    {
        val = -FT_PIX_CEIL(compensation - distance);
        if (val > 0)
            val = 0;
    }
    return val;
}

function Round_Down_To_Grid(exc, distance, compensation)
{
    if (distance > 2147483647 || compensation > 2147483647)
        alert("error");

    var val;
    if (distance >= 0)
    {
        val = distance + compensation;
        if (distance && val > 0)
            val &= ~63;
        else
            val = 0;
    }
    else
    {
        val = -((compensation - distance) & -64);
        if (val > 0)
            val = 0;
    }
    return val;
}

function Round_To_Half_Grid(exc, distance, compensation)
{
    if (distance > 2147483647 || compensation > 2147483647)
        alert("error");
    
    var val;
    if (distance >= 0)
    {
        val = FT_PIX_FLOOR(distance + compensation) + 32;
        if (distance != 0 && val < 0)
            val = 0;
    }
    else
    {
        val = -(FT_PIX_FLOOR(compensation - distance) + 32);
        if (val > 0)
            val = 0;
    }
    return val;
}

function Round_To_Double_Grid(exc, distance, compensation)
{
    if (distance > 2147483647 || compensation > 2147483647)
        alert("error");
    
    var val;
    if (distance >= 0)
    {
        val = distance + compensation + 16;
        if (distance != 0 && val > 0)
            val &= ~31;
        else
            val = 0;
    }
    else
    {
        val = -FT_PAD_ROUND(compensation - distance, 32);
        if (val > 0)
            val = 0;
    }

    return val;
}

function Round_Super(exc, distance, compensation)
{
    if (distance > 2147483647 || compensation > 2147483647)
        alert("error");
    
    var val;
    if (distance >= 0)
    {
        val = (distance - exc.phase + exc.threshold + compensation) & -exc.period;
        if (distance != 0 && val < 0)
            val = 0;
        val += exc.phase;
    }
    else
    {
        val = -((exc.threshold - exc.phase - distance + compensation) & -exc.period);
        if (val > 0)
            val = 0;
        val -= exc.phase;
    }
    return val;
}

function Round_Super_45(exc, distance, compensation)
{
    if (distance > 2147483647 || compensation > 2147483647)
        alert("error");
    
    var val;
    if (distance >= 0)
    {
        val = (((distance - exc.phase + exc.threshold + compensation) / exc.period) >> 0) * exc.period;
        if (distance != 0 && val < 0)
            val = 0;
        val += exc.phase;
    }
    else
    {
        val = -((((exc.threshold - exc.phase - distance + compensation) / exc.period) >> 0) * exc.period);
        if (val > 0)
            val = 0;
        val -= exc.phase;
    }
    return val;
}

function SetSuperRound(exc, GridPeriod, selector)
{
    switch ((selector & 0xC0))
    {
    case 0:
        exc.period = (GridPeriod / 2) >> 0;
        break;
    case 0x40:
        exc.period = GridPeriod;
        break;
    case 0x80:
        exc.period = GridPeriod * 2;
        break;
    /* This opcode is reserved, but... */
    case 0xC0:
        exc.period = GridPeriod;
        break;
    }

    switch ((selector & 0x30))
    {
    case 0:
        exc.phase = 0;
        break;
    case 0x10:
        exc.phase = exc.period >> 2;
        break;
    case 0x20:
        exc.phase = exc.period >> 1;
        break;
    case 0x30:
        exc.phase = (exc.period * 3) >> 2;
        break;
    }

    if ((selector & 0x0F) == 0)
        exc.threshold = exc.period - 1;
    else
        exc.threshold = (((selector & 0x0F) - 4) * exc.period) >> 3;

    exc.period    >>= 8;
    exc.phase     >>= 8;
    exc.threshold >>= 8;
}

// ------

function SkipCode(exc)
{
    exc.IP += exc.length;

    if (exc.IP < exc.codeSize)
    {
        exc.opcode = exc.code.data[exc.code.pos + exc.IP];

        exc.length = opcode_length[exc.opcode];
        if ( exc.length < 0 )
        {
            if ( exc.IP + 1 >= exc.codeSize )
            {
                exc.error = 131;
                return 1;
            }
            exc.length = 2 - exc.length * exc.code.data[exc.code.pos + exc.IP + 1];
        }

        if (exc.IP + exc.length <= exc.codeSize)
            return 0;
    }

    exc.error = 131;
    return 1;
}

function Ins_Goto_CodeRange(exc, aRange, aIP)
{
    if (aRange < 1 || aRange > 3)
    {
        exc.error = 132;
        return 1;
    }

    var range = exc.codeRangeTable[aRange - 1];

    if (range.base == null)     /* invalid coderange */
    {
        exc.error = 138;
        return 1;
    }

    /* NOTE: Because the last instruction of a program may be a CALL */
    /*       which will return to the first byte *after* the code    */
    /*       range, we test for aIP <= Size, instead of aIP < Size.  */

    if (aIP > range.size)
    {
        exc.error = 131;
        return 1;
    }

    exc.code     = dublicate_pointer(range.base);
    exc.codeSize = range.size;
    exc.IP       = aIP;
    exc.curRange = aRange;

    return 0;
}

function Compute_Point_Displacement(exc, x, y, zone, refp)
{
    var ret = {x: x, y: y, refp: refp, err: 0};
    var zp = null;
    var p;

    if (exc.opcode & 1)
    {
        zp = exc.zp0;
        p  = exc.GS.rp1;
    }
    else
    {
        zp = exc.zp1;
        p  = exc.GS.rp2;
    }

    if (p >= zp.n_points)
    {
        if (exc.pedantic_hinting )
            exc.error = 134;
        ret.refp = 0;
        ret.err = 1;
        return ret;
    }

    zone.Copy(zp);
    ret.refp = p;

    var v1 = zp.cur[zp._offset_cur + p];
    var v2 = zp.org[zp._offset_org + p];
    var d = exc.func_project(exc, v1.x - v2.x, v1.y - v2.y);

    // TODO : unpatended
    ret.x = FT_MulDiv(d, exc.GS.freeVector.x, exc.F_dot_P);
    ret.y = FT_MulDiv(d, exc.GS.freeVector.y, exc.F_dot_P);

    return ret;
}

function TT_MulFix14(a, b)
{
    a = FT_Common.UintToInt(a);
    b = FT_Common.UintToInt(b);

    var sign = a ^ b;

    if (a < 0)
        a = -a;
    if (b < 0)
        b = -b;

    var ah = ((a >>> 16) & 0xFFFF);
    var al = (a & 0xFFFF);

    var lo = FT_Common.IntToUInt((al * b) & 0xFFFFFFFF);
    var mid = FT_Common.IntToUInt((ah * b) & 0xFFFFFFFF);
    var hi = mid >>> 16;
    mid = FT_Common.IntToUInt((mid << 16) & 0xFFFFFFFF) + (1 << 13); /* rounding */
    lo += mid;

    lo = FT_Common.IntToUInt(lo & 0xFFFFFFFF);

    if (lo < mid)
        hi += 1;

    mid = FT_Common.IntToUInt(((lo >>> 14) | (hi << 18)) & 0xFFFFFFFF);

    //console.log("(" + a + ", " + b + "): " + (sign >= 0 ? mid : -mid));

    return sign >= 0 ? mid : -mid;
}

function TT_DotFix14(ax, ay, bx, by)
{
    ax = FT_Common.UintToInt(ax);
    ay = FT_Common.UintToInt(ay);
    bx = FT_Common.UintToInt(bx);
    by = FT_Common.UintToInt(by);

    /* compute ax*bx as 64-bit value */
    var _l = ((ax & 0xFFFF) * bx) & 0xFFFFFFFF;
    var l = FT_Common.IntToUInt(_l);
    var m = ((ax >> 16) * bx) & 0xFFFFFFFF;

    var lo1 = l + FT_Common.IntToUInt((m << 16) & 0xFFFFFFFF);
    lo1 = FT_Common.IntToUInt(lo1 & 0xFFFFFFFF);

    var hi1 = (m >> 16) + (_l >> 31) + ((lo1 < l) ? 1 : 0);

    /* compute ay*by as 64-bit value */
    _l = ((ay & 0xFFFF) * by) & 0xFFFFFFFF;
    l = FT_Common.IntToUInt(_l);
    m = ((ay >> 16) * by) & 0xFFFFFFFF;

    var lo2 = l + FT_Common.IntToUInt(m << 16);
    lo2 = FT_Common.IntToUInt(lo2 & 0xFFFFFFFF);

    var hi2 = (m >> 16) + (_l >> 31) + ((lo2 < l) ? 1 : 0);

    /* add them */
    var lo = lo1 + lo2;
    lo = FT_Common.IntToUInt(lo & 0xFFFFFFFF);

    var hi = hi1 + hi2 + ((lo < lo1) ? 1 : 0);

    /* divide the result by 2^14 with rounding */
    var s   = hi >> 31;
    l  = lo + FT_Common.IntToUInt(s);
    l = FT_Common.IntToUInt(l & 0xFFFFFFFF);

    hi += s + ((l < lo) ? 1 : 0);
    lo  = l;

    l   = lo + 0x2000;
    l = FT_Common.IntToUInt(l & 0xFFFFFFFF);
    
    hi += ((l < lo) ? 1 : 0);

    //console.log("(" + ax + ", " + ay + ", " + bx + ", " + by + "): " + (((hi << 18) | (l >> 14)) & 0xFFFFFFFF));

    return ((hi << 18) | (l >> 14)) & 0xFFFFFFFF;
}

function Move_Zp2_Point(exc, point, dx, dy, touch)
{
    // TODO: unpatented
    if (exc.GS.freeVector.x != 0)
    {
        exc.zp2.cur[exc.zp2._offset_cur + point].x += dx;
        if (touch)
            exc.zp2.tags[exc.zp2._offset_tags + point] |= 8;
    }

    if (exc.GS.freeVector.y != 0)
    {
        exc.zp2.cur[exc.zp2._offset_cur + point].y += dy;
        if (touch)
            exc.zp2.tags[exc.zp2._offset_tags + point] |= 16;
    }
}
////////////////////////////////////////////////////////
function Ins_SVTCA(exc, args, args_pos)
{
    var A = 0;
    var B = 0x4000;
    if ((exc.opcode & 1) == 1)
    {
        A = 0x4000;
        B = 0;
    }

    exc.GS.freeVector.x = A;
    exc.GS.projVector.x = A;
    exc.GS.dualVector.x = A;

    exc.GS.freeVector.y = B;
    exc.GS.projVector.y = B;
    exc.GS.dualVector.y = B;

    Compute_Funcs(exc);
}

function Ins_SPVTCA(exc, args, args_pos)
{
    var A = 0;
    var B = 0x4000;
    if ((exc.opcode & 1) == 1)
    {
        A = 0x4000;
        B = 0;
    }

    exc.GS.projVector.x = A;
    exc.GS.dualVector.x = A;

    exc.GS.projVector.y = B;
    exc.GS.dualVector.y = B;

    GUESS_VECTOR(exc, exc.GS.freeVector);

    Compute_Funcs(exc);
}

function Ins_SFVTCA(exc, args, args_pos)
{
    var A = 0;
    var B = 0x4000;
    if ((exc.opcode & 1) == 1)
    {
        A = 0x4000;
        B = 0;
    }

    exc.GS.freeVector.x = A;
    exc.GS.freeVector.y = B;

    GUESS_VECTOR(exc, exc.projVector);

    Compute_Funcs(exc);
}

function Ins_SPVTL(exc, args, args_pos)
{
    if (Ins_SxVTL(exc, 0xFFFF & args[args_pos + 1], 0xFFFF & args[args_pos], exc.opcode, exc.GS.projVector) == 0)
    {
        exc.GS.dualVector.x = exc.GS.projVector.x;
        exc.GS.dualVector.y = exc.GS.projVector.y;
        GUESS_VECTOR(exc, exc.GS.freeVector);
        Compute_Funcs(exc);
    }
}

function Ins_SFVTL(exc, args, args_pos)
{
    if (Ins_SxVTL(exc, 0xFFFF & args[args_pos + 1], 0xFFFF & args[args_pos], exc.opcode, exc.GS.freeVector) == 0)
    {
        GUESS_VECTOR(exc, exc.GS.projVector );
        Compute_Funcs(exc);
    }
}

function Ins_SPVFS(exc, args, args_pos)
{
    /* Only use low 16bits, then sign extend */
    var Y = FT_Common.UShort_To_Short(0xFFFF & args[args_pos + 1]);
    var X = FT_Common.UShort_To_Short(0xFFFF & args[args_pos]);

    Normalize(exc, X, Y, exc.GS.projVector);

    exc.GS.dualVector.x = exc.GS.projVector.x;
    exc.GS.dualVector.y = exc.GS.projVector.y;
    GUESS_VECTOR(exc, exc.GS.freeVector );
    Compute_Funcs(exc);
}

function Ins_SFVFS(exc, args, args_pos)
{
    /* Only use low 16bits, then sign extend */
    var Y = FT_Common.UShort_To_Short(0xFFFF & args[args_pos + 1]);
    var X = FT_Common.UShort_To_Short(0xFFFF & args[args_pos]);

    Normalize(exc, X, Y, exc.GS.freeVector);
    GUESS_VECTOR(exc, exc.GS.projVector );
    Compute_Funcs(exc);
}

function Ins_GPV(exc, args, args_pos)
{
    // TODO: unpatented
    args[args_pos] = exc.GS.projVector.x;
    args[args_pos + 1] = exc.GS.projVector.y;
}

function Ins_GFV(exc, args, args_pos)
{
    // TODO: unpatented
    args[args_pos] = exc.GS.freeVector.x;
    args[args_pos + 1] = exc.GS.freeVector.y;
}

function Ins_SFVTPV(exc, args, args_pos)
{
    GUESS_VECTOR(exc, exc.GS.projVector);
    exc.GS.freeVector.x = exc.GS.projVector.x;
    exc.GS.freeVector.y = exc.GS.projVector.y;
    Compute_Funcs(exc);
}

function Ins_ISECT(exc, args, args_pos)
{
    var point = 0xFFFF & args[args_pos];

    var a0 = 0xFFFF & args[args_pos + 1];
    var a1 = 0xFFFF & args[args_pos + 2];
    var b0 = 0xFFFF & args[args_pos + 3];
    var b1 = 0xFFFF & args[args_pos + 4];

    if ((b0 >= exc.zp0.n_points)  ||
        (b1 >= exc.zp0.n_points)  ||
        (a0 >= exc.zp1.n_points)  ||
        (a1 >= exc.zp1.n_points)  ||
        (point >= exc.zp2.n_points))
    {
        if (exc.pedantic_hinting)
            exc.error = 134;
        return;
    }

    /* Cramer's rule */

    var off0 = exc.zp0._offset_cur;
    var off1 = exc.zp1._offset_cur;
    var off2 = exc.zp2._offset_cur;

    var dbx = exc.zp0.cur[off0+b1].x - exc.zp0.cur[off0+b0].x;
    var dby = exc.zp0.cur[off0+b1].y - exc.zp0.cur[off0+b0].y;

    var dax = exc.zp1.cur[off1+a1].x - exc.zp1.cur[off1+a0].x;
    var day = exc.zp1.cur[off1+a1].y - exc.zp1.cur[off1+a0].y;

    var dx = exc.zp0.cur[off0+b0].x - exc.zp1.cur[off1+a0].x;
    var dy = exc.zp0.cur[off0+b0].y - exc.zp1.cur[off1+a0].y;

    exc.zp2.tags[exc.zp2._offset_tags + point] |= 24;

    var discriminant = FT_MulDiv(dax, -dby, 0x40) + FT_MulDiv(day, dbx, 0x40);
    var dotproduct   = FT_MulDiv(dax, dbx, 0x40) + FT_MulDiv(day, dby, 0x40);

    /* The discriminant above is actually a cross product of vectors     */
    /* da and db. Together with the dot product, they can be used as     */
    /* surrogates for sine and cosine of the angle between the vectors.  */
    /* Indeed,                                                           */
    /*       dotproduct   = |da||db|cos(angle)                           */
    /*       discriminant = |da||db|sin(angle)     .                     */
    /* We use these equations to reject grazing intersections by         */
    /* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */
    if (19 * Math.abs(discriminant) > Math.abs(dotproduct))
    {
        var val = FT_MulDiv(dx, -dby, 0x40) + FT_MulDiv(dy, dbx, 0x40);

        var __x = FT_MulDiv(val, dax, discriminant);
        var __y = FT_MulDiv(val, day, discriminant);

        exc.zp2.cur[off2 + point].x = exc.zp1.cur[off1 + a0].x + __x;
        exc.zp2.cur[off2 + point].y = exc.zp1.cur[off1 + a0].y + __y;
    }
    else
    {
        /* else, take the middle of the middles of A and B */
        exc.zp2.cur[off2 + point].x = (exc.zp1.cur[off1 + a0].x +
                               exc.zp1.cur[off1 + a1].x +
                               exc.zp0.cur[off0 + b0].x +
                               exc.zp0.cur[off0 + b1].x ) >> 2;
        exc.zp2.cur[off2 + point].y = (exc.zp1.cur[off1 + a0].y +
                               exc.zp1.cur[off1 + a1].y +
                               exc.zp0.cur[off0 + b0].y +
                               exc.zp0.cur[off0 + b1].y ) >> 2;
    }
}

function Ins_SRP0(exc, args, args_pos)
{
    exc.GS.rp0 = 0xFFFF & args[args_pos];
}

function Ins_SRP1(exc, args, args_pos)
{
    exc.GS.rp1 = 0xFFFF & args[args_pos];
}

function Ins_SRP2(exc, args, args_pos)
{
    exc.GS.rp2 = 0xFFFF & args[args_pos];
}

function Ins_SZP0(exc, args, args_pos)
{
    switch (args[args_pos])
    {
    case 0:
        exc.zp0.Copy(exc.twilight);
        break;

    case 1:
        exc.zp0.Copy(exc.pts);
        break;

    default:
        if (exc.pedantic_hinting)
            exc.error = 134;
        return;
    }

    exc.GS.gep0 = 0xFFFF & args[args_pos];
}

function Ins_SZP1(exc, args, args_pos)
{
    switch (args[args_pos])
    {
    case 0:
        exc.zp1.Copy(exc.twilight);
        break;

    case 1:
        exc.zp1.Copy(exc.pts);
        break;

    default:
        if (exc.pedantic_hinting)
            exc.error = 134;
        return;
    }

    exc.GS.gep1 = 0xFFFF & args[args_pos];
}

function Ins_SZP2(exc, args, args_pos)
{
    switch (args[args_pos])
    {
    case 0:
        exc.zp2.Copy(exc.twilight);
        break;

    case 1:
        exc.zp2.Copy(exc.pts);
        break;

    default:
        if (exc.pedantic_hinting)
            exc.error = 134;
        return;
    }

    exc.GS.gep2 = 0xFFFF & args[args_pos];
}

function Ins_SZPS(exc, args, args_pos)
{
    switch (args[args_pos])
    {
    case 0:
        exc.zp0.Copy(exc.twilight);
        break;

    case 1:
        exc.zp0.Copy(exc.pts);
        break;

    default:
        if (exc.pedantic_hinting)
            exc.error = 134;
        return;
    }

    exc.zp1.Copy(exc.zp0);
    exc.zp2.Copy(exc.zp0);

    exc.GS.gep0 = 0xFFFF & args[args_pos];
    exc.GS.gep1 = 0xFFFF & args[args_pos];
    exc.GS.gep2 = 0xFFFF & args[args_pos];
}

function Ins_SLOOP(exc, args, args_pos)
{
    if (args[args_pos] < 0)
        exc.error = 132;
    else
        exc.GS.loop = args[args_pos];
}

function Ins_RTG(exc, args, args_pos)
{
    exc.GS.round_state = TT_Round_To_Grid;
    exc.func_round = Round_To_Grid;
}

function Ins_RTHG(exc, args, args_pos)
{
    exc.GS.round_state = TT_Round_To_Half_Grid;
    exc.func_round = Round_To_Half_Grid;
}

function Ins_SMD(exc, args, args_pos)
{
    exc.GS.minimum_distance = args[args_pos];
}

function Ins_ELSE(exc, args, args_pos)
{
    var nIfs = 1;

    do
    {
        if (SkipCode(exc) == 1)
            return;

        switch (exc.opcode)
        {
        case 0x58:    /* IF */
            nIfs++;
            break;

        case 0x59:    /* EIF */
            nIfs--;
            break;
        }
    } while ( nIfs != 0 );
}

function Ins_JMPR(exc, args, args_pos)
{
    if (args[args_pos] == 0 && exc.args == 0)
        exc.error = 132;
    exc.IP += args[args_pos];
    if (exc.IP < 0 || (exc.callTop > 0 && exc.IP > exc.callStack[exc.callTop - 1].Def.end))
        exc.error = 132;
    exc.step_ins = 0;
}

function Ins_SCVTCI(exc, args, args_pos)
{
    exc.GS.control_value_cutin = args[args_pos];
}

function Ins_SSWCI(exc, args, args_pos)
{
    exc.GS.single_width_cutin = args[args_pos];
}

function Ins_SSW(exc, args, args_pos)
{
    exc.GS.single_width_value = FT_MulFix(args[args_pos], exc.tt_metrics.scale);
}

function Ins_DUP(exc, args, args_pos)
{
    args[args_pos + 1] = args[args_pos];
}

function Ins_POP(exc, args, args_pos)
{
}

function Ins_CLEAR(exc, args, args_pos)
{
    exc.new_top = 0;
}

function Ins_SWAP(exc, args, args_pos)
{
    var L = args[args_pos];
    args[args_pos] = args[args_pos + 1];
    args[args_pos + 1] = L;
}

function Ins_DEPTH(exc, args, args_pos)
{
    args[args_pos] = exc.top;
}

function Ins_CINDEX(exc, args, args_pos)
{
    var L = args[args_pos];

    if (L <= 0 || L > exc.args)
    {
        if (exc.pedantic_hinting)
            exc.error = 134;
        args[args_pos] = 0;
    }
    else
        args[args_pos] = exc.stack[exc.args - L];
}

function Ins_MINDEX(exc, args, args_pos)
{
    var L = args[args_pos];

    if (L <= 0 || L > exc.args)
    {
        if (exc.pedantic_hinting)
            exc.error = 134;
    }
    else
    {
        var K = exc.stack[exc.args - L];

        var _i1 = exc.args - L;
        var _i2 = exc.args - 1;
        for (var i = _i1; i < _i2; i++)
            exc.stack[i] = exc.stack[i + 1];

        exc.stack[exc.args - 1] = K;
    }
}

function Ins_ALIGNPTS(exc, args, args_pos)
{
    var p1 = 0xFFFF & args[args_pos];
    var p2 = 0xFFFF & args[args_pos + 1];

    if ((p1 >= exc.zp1.n_points) || (p2 >= exc.zp0.n_points))
    {
        if (exc.pedantic_hinting)
            exc.error = 134;
        return;
    }

    var v1 = exc.zp0.cur[exc.zp0._offset_cur + p2];
    var v2 = exc.zp1.cur[exc.zp1._offset_cur + p1];

    var distance = exc.func_project(exc, v1.x - v2.x, v1.y - v2.y) >> 1;

    exc.func_move(exc, exc.zp1, p1, distance);
    exc.func_move(exc, exc.zp0, p2, -distance);
}

function Ins_UNKNOWN(exc, args, args_pos)
{
    var defs = exc.IDefs;
    var limit = exc.numIDefs;

    for (var def = 0; def < limit; def++)
    {
        if (defs[def].opc == exc.opcode && defs[def].active)
        {
            if (exc.callTop >= exc.callSize)
            {
                exc.error = 130;
                return;
            }

            var call = exc.callStack[exc.callTop++];

            call.Caller_Range = exc.curRange;
            call.Caller_IP    = exc.IP + 1;
            call.Cur_Count    = 1;
            call.Def = defs[def];

            Ins_Goto_CodeRange(defs[def].range, defs[def].start);

            exc.step_ins = false;
            return;
        }
    }

    exc.error = 128;
}
function Ins_UTP(exc, args, args_pos)
{
    var point = 0xFFFF & args[args_pos];

    if (point >= exc.zp0.n_points)
    {
        if (exc.pedantic_hinting)
            exc.error = 134;
        return;
    }

    var mask = 0xFF;

    if (exc.GS.freeVector.x != 0)
        mask &= ~8;

    if (exc.GS.freeVector.y != 0)
        mask &= ~16;

    exc.zp0.tags[exc.zp0._offset_tags + point] &= mask;
}

function Ins_LOOPCALL(exc, args, args_pos)
{
    /* first of all, check the index */
    var F = args[args_pos + 1];
    if (F >= (exc.maxFunc + 1))
    {
        exc.error = 134;
        return;
    }

    /* Except for some old Apple fonts, all functions in a TrueType */
    /* font are defined in increasing order, starting from 0.  This */
    /* means that we normally have                                  */
    /*                                                              */
    /*    CUR.maxFunc+1 == CUR.numFDefs                             */
    /*    CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc             */
    /*                                                              */
    /* If this isn't true, we need to look up the function table.   */
    var defs = exc.FDefs;
    var def = F;
    if (exc.maxFunc + 1 != exc.numFDefs || defs[def].opc != F)
    {
        /* look up the FDefs table */
        def = 0;
        var limit = exc.numFDefs;

        while (def < limit && defs[def].opc != F)
            def++;

        if (def == limit)
        {
            exc.error = 134;
            return;
        }
    }

    /* check that the function is active */
    if (!defs[def].active)
    {
        exc.error = 134;
        return;
    }

    if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)
    {
        if (exc.ignore_x_mode && (defs[def].sph_fdef_flags & 8))
            return;

        exc.sph_in_func_flags = defs[def].sph_fdef_flags;
    }

    /* check stack */
    if (exc.callTop >= exc.callSize)
    {
        exc.error = 130;
        return;
    }

    if (args[args_pos] > 0)
    {
        var pCrec = exc.callStack[exc.callTop];

        pCrec.Caller_Range = exc.curRange;
        pCrec.Caller_IP    = exc.IP + 1;
        pCrec.Cur_Count    = args[args_pos];
        pCrec.Def          = defs[def];

        exc.callTop++;

        Ins_Goto_CodeRange(exc, defs[def].range, defs[def].start);
        exc.step_ins = false;
    }
}

function Ins_CALL(exc, args, args_pos)
{
    /* first of all, check the index */
    var F = FT_Common.IntToUInt(args[args_pos]);
    if (F >= (exc.maxFunc + 1))
    {
        exc.error = 134;
        return;
    }

    /* Except for some old Apple fonts, all functions in a TrueType */
    /* font are defined in increasing order, starting from 0.  This */
    /* means that we normally have                                  */
    /*                                                              */
    /*    CUR.maxFunc+1 == CUR.numFDefs                             */
    /*    CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc             */
    /*                                                              */
    /* If this isn't true, we need to look up the function table.   */

    var defs = exc.FDefs;
    var def = F;
    if ((exc.maxFunc + 1) != exc.numFDefs || defs[def].opc != F)
    {
        /* look up the FDefs table */
        def   = 0;
        var limit = exc.numFDefs;

        while (def < limit && defs[def].opc != F)
            def++;

        if (def == limit)
        {
            exc.error = 134;
            return;
        }
    }

    /* check that the function is active */
    if (!defs[def].active)
    {
        exc.error = 134;
        return;
    }

    if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)
    {
        if (exc.ignore_x_mode &&
            ((exc.iup_called && (exc.sph_tweak_flags & 1024)) ||
                defs[def].sph_fdef_flags & 8))
            return;

        exc.sph_in_func_flags = defs[def].sph_fdef_flags;
    }

    /* check the call stack */
    if (exc.callTop >= exc.callSize)
    {
        exc.error = 130;
        return;
    }

    var pCrec = exc.callStack[exc.callTop];

    pCrec.Caller_Range = exc.curRange;
    pCrec.Caller_IP    = exc.IP + 1;
    pCrec.Cur_Count    = 1;
    pCrec.Def = defs[def];

    exc.callTop++;

    Ins_Goto_CodeRange(exc, defs[def].range, defs[def].start);

    exc.step_ins = false;
}

function Ins_FDEF(exc, args, args_pos)
{
    var bIsSubpix = exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;

    var opcode_pattern = null;
    var opcode_patterns = null;
    var opcode_pointer = null;
    var opcode_size    = null;;
    if (bIsSubpix)
    {
        opcode_pattern = [
            /* #0 inline delta function 1 */
            [
                0x4B, /* PPEM    */
                0x53, /* GTEQ    */
                0x23, /* SWAP    */
                0x4B, /* PPEM    */
                0x51, /* LTEQ    */
                0x5A, /* AND     */
                0x58, /* IF      */
                0x38, /*   SHPIX */
                0x1B, /* ELSE    */
                0x21, /*   POP   */
                0x21, /*   POP   */
                0x59  /* EIF     */
            ],
            /* #1 inline delta function 2 */
            [
                0x4B, /* PPEM    */
                0x54, /* EQ      */
                0x58, /* IF      */
                0x38, /*   SHPIX */
                0x1B, /* ELSE    */
                0x21, /*   POP   */
                0x21, /*   POP   */
                0x59  /* EIF     */
            ],
            /* #2 diagonal stroke function */
            [
                0x20, /* DUP     */
                0x20, /* DUP     */
                0xB0, /* PUSHB_1 */
                /*   1     */
                0x60, /* ADD     */
                0x46, /* GC_cur  */
                0xB0, /* PUSHB_1 */
                /*   64    */
                0x23, /* SWAP    */
                0x42  /* WS      */
            ],
            /* #3 VacuFormRound function */
            [
                0x45, /* RCVT    */
                0x23, /* SWAP    */
                0x46, /* GC_cur  */
                0x60, /* ADD     */
                0x20, /* DUP     */
                0xB0  /* PUSHB_1 */
                /*   38    */
            ],
            /* #4 TTFautohint bytecode (old) */
            [
                0x20, /* DUP     */
                0x64, /* ABS     */
                0xB0, /* PUSHB_1 */
                /*   32    */
                0x60, /* ADD     */
                0x66, /* FLOOR   */
                0x23, /* SWAP    */
                0xB0  /* PUSHB_1 */
            ],
            /* #5 spacing function 1 */
            [
                0x01, /* SVTCA_x */
                0xB0, /* PUSHB_1 */
                /*   24    */
                0x43, /* RS      */
                0x58  /* IF      */
            ],
            /* #6 spacing function 2 */
            [
                0x01, /* SVTCA_x */
                0x18, /* RTG     */
                0xB0, /* PUSHB_1 */
                /*   24    */
                0x43, /* RS      */
                0x58  /* IF      */
            ],
            /* #7 TypeMan Talk DiagEndCtrl function */
            [
                0x01, /* SVTCA_x */
                0x20, /* DUP     */
                0xB0, /* PUSHB_1 */
                /*   3     */
                0x25, /* CINDEX  */
            ],
            /* #8 TypeMan Talk Align */
            [
                0x06, /* SPVTL   */
                0x7D, /* RDTG    */
            ]
        ];
        opcode_patterns = opcode_pattern.length;
        opcode_pointer = [  0, 0, 0, 0, 0, 0, 0, 0, 0 ];
        opcode_size    = [ 12, 8, 8, 6, 7, 4, 5, 4, 2 ];
    }

    /* some font programs are broken enough to redefine functions! */
    /* We will then parse the current table.                       */
    var defs = exc.FDefs;
    var rec = 0;
    var limit = exc.numFDefs;
    var n = args[args_pos];

    for ( ; rec < limit; rec++)
    {
        if (defs[rec].opc == n)
            break;
    }

    if (rec == limit)
    {
        /* check that there is enough room for new functions */
        if (exc.numFDefs >= exc.maxFDefs)
        {
            exc.error = 140;
            return;
        }
        exc.numFDefs++;
    }

    /* Although FDEF takes unsigned 32-bit integer,  */
    /* func # must be within unsigned 16-bit integer */
    if (n > 0xFFFF)
    {
        exc.error = 140;
        return;
    }

    defs[rec].range        = exc.curRange;
    defs[rec].opc          = 0xFFFF & n;
    defs[rec].start        = exc.IP + 1;
    defs[rec].active       = true;
    defs[rec].inline_delta = false;
    defs[rec].sph_fdef_flags = 0x0000;

    if (n > exc.maxFunc)
        exc.maxFunc = 0xFFFF & n;

    if (bIsSubpix)
    {
        /* We don't know for sure these are typeman functions, */
        /* however they are only active when RS 22 is called   */
        if (n >= 64 && n <= 66)
            defs[rec].sph_fdef_flags |= 128;
    }

    /* Now skip the whole function definition. */
    /* We don't allow nested IDEFS & FDEFs.    */

    while (SkipCode(exc) == 0)
    {
        if (bIsSubpix)//#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
        {
            for (var i = 0; i < opcode_patterns; i++)
            {
                if (opcode_pointer[i] < opcode_size[i] && exc.opcode == opcode_pattern[i][opcode_pointer[i]])
                {
                    opcode_pointer[i] += 1;

                    if (opcode_pointer[i] == opcode_size[i])
                    {
                        switch ( i )
                        {
                            case 0:
                                defs[rec].sph_fdef_flags        |= 1;
                                exc.face.sph_found_func_flags   |= 1;
                                break;

                            case 1:
                                defs[rec].sph_fdef_flags        |= 2;
                                exc.face.sph_found_func_flags   |= 2;
                                break;

                            case 2:
                                switch ( n )
                                {
                                    /* needs to be implemented still */
                                    case 58:
                                        defs[rec].sph_fdef_flags        |= 4;
                                        exc.face.sph_found_func_flags   |= 4;
                                }
                                break;

                            case 3:
                                switch ( n )
                                {
                                    case 0:
                                        defs[rec].sph_fdef_flags        |= 8;
                                        exc.face.sph_found_func_flags   |= 8;
                                }
                                break;

                            case 4:
                                /* probably not necessary to detect anymore */
                                defs[rec].sph_fdef_flags            |= 16;
                                exc.face.sph_found_func_flags       |= 16;
                                break;

                            case 5:
                                switch ( n )
                                {
                                    case 0:
                                    case 1:
                                    case 2:
                                    case 4:
                                    case 7:
                                    case 8:
                                        defs[rec].sph_fdef_flags        |= 32;
                                        exc.face.sph_found_func_flags   |= 32;
                                }
                                break;

                            case 6:
                                switch ( n )
                                {
                                    case 0:
                                    case 1:
                                    case 2:
                                    case 4:
                                    case 7:
                                    case 8:
                                        defs[rec].sph_fdef_flags        |= 64;
                                        exc.face.sph_found_func_flags   |= 64;
                                }
                                break;

                            case 7:
                                defs[rec].sph_fdef_flags        |= 256;
                                exc.face.sph_found_func_flags   |= 256;
                                break;

                            case 8:
                                //defs[rec].sph_fdef_flags        |= 256;
                                //exc.face.sph_found_func_flags   |= 256;
                                break;
                        }
                        opcode_pointer[i] = 0;
                    }
                }
                else
                    opcode_pointer[i] = 0;
            }

            /* Set sph_compatibility_mode only when deltas are detected */
            exc.face.sph_compatibility_mode = ((exc.face.sph_found_func_flags & 1) |
                                                (exc.face.sph_found_func_flags & 2));
        } //#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */

        switch (exc.opcode)
        {
        case 0x89:    /* IDEF */
        case 0x2C:    /* FDEF */
            exc.error = 137;
            return;
        case 0x2D:   /* ENDF */
            defs[rec].end = exc.IP;
            return;
        default:
            break;
        }
    }
}

function Ins_ENDF(exc, args, args_pos)
{
    var bIsSubpix = exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;
    if (bIsSubpix)
        exc.sph_in_func_flags = 0x0000;

    if (exc.callTop <= 0)     /* We encountered an ENDF without a call */
    {
        exc.error = 136;
        return;
    }

    exc.callTop--;
    var pRec = exc.callStack[exc.callTop];

    pRec.Cur_Count--;
    exc.step_ins = false;

    if (pRec.Cur_Count > 0)
    {
        exc.callTop++;
        exc.IP = pRec.Def.start;
    }
    else
    {
        /* Loop through the current function */
        Ins_Goto_CodeRange(exc, pRec.Caller_Range, pRec.Caller_IP);
    }

    /* Exit the current call frame.                      */

    /* NOTE: If the last instruction of a program is a   */
    /*       CALL or LOOPCALL, the return address is     */
    /*       always out of the code range.  This is a    */
    /*       valid address, and it is why we do not test */
    /*       the result of Ins_Goto_CodeRange() here!    */
}

function Ins_MDAP(exc, args, args_pos)
{
    var point = 0xFFFF & args[args_pos];

    if (point >= exc.zp0.n_points)
    {
        if (exc.pedantic_hinting)
            exc.error = 134;
        return;
    }

    var distance = 0;
    if ((exc.opcode & 1) != 0)
    {
        var cur_dist = exc.func_project(exc, exc.zp0.cur[exc.zp0._offset_cur + point].x, exc.zp0.cur[exc.zp0._offset_cur + point].y);
        var bIsSubpix = exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;

        if (bIsSubpix)
        {
            if (exc.ignore_x_mode && exc.GS.freeVector.x != 0)
            {
                distance = Round_None(exc, cur_dist, exc.tt_metrics.compensations[0]) - cur_dist;
            }
            else
            {
                distance = exc.func_round(exc, cur_dist, exc.tt_metrics.compensations[0]) - cur_dist;
            }
        }
        else
        {
            distance = exc.func_round(exc, cur_dist, exc.tt_metrics.compensations[0]) - cur_dist;
        }
    }

    exc.func_move(exc, exc.zp0, point, distance);

    exc.GS.rp0 = point;
    exc.GS.rp1 = point;
}

// --
function IUP_WorkerRec()
{
    this.orgs = null;   /* original and current coordinate */
    this.curs = null;   /* arrays                          */
    this.orus = null;

    this.off_orgs = 0;
    this.off_curs = 0;
    this.off_orus = 0;

    this.max_points = 0;
    this.is_offset_one = false;
}

function _iup_worker_shift(worker, p1, p2, p)
{
    if (!worker.is_offset_one)
    {
        var dx = worker.curs[worker.off_curs + p].x - worker.orgs[worker.off_orgs + p].x;
        if (dx != 0)
        {
            for (var i = p1; i < p; i++)
                worker.curs[worker.off_curs + i].x += dx;

            for (var i = p + 1; i <= p2; i++)
                worker.curs[worker.off_curs + i].x += dx;
        }
    }
    else
    {
        var dy = worker.curs[worker.off_curs + p].y - worker.orgs[worker.off_orgs + p].y;
        if (dy != 0)
        {
            for (var i = p1; i < p; i++)
                worker.curs[worker.off_curs + i].y += dy;

            for (var i = p + 1; i <= p2; i++)
                worker.curs[worker.off_curs + i].y += dy;
        }
    }
}

function _iup_worker_interpolate(worker, p1, p2, ref1, ref2)
{
    if (!worker.is_offset_one)
    {
        if (p1 > p2)
            return;

        if ((ref1 >= worker.max_points) || (ref2 >= worker.max_points))
            return;

        var orus1 = worker.orus[worker.off_orus + ref1].x;
        var orus2 = worker.orus[worker.off_orus + ref2].x;

        if (orus1 > orus2)
        {
            var tmp_o = orus1;
            orus1 = orus2;
            orus2 = tmp_o;

            var tmp_r = ref1;
            ref1  = ref2;
            ref2  = tmp_r;
        }

        var org1   = worker.orgs[worker.off_orgs + ref1].x;
        var org2   = worker.orgs[worker.off_orgs + ref2].x;
        var delta1 = worker.curs[worker.off_curs + ref1].x - org1;
        var delta2 = worker.curs[worker.off_curs + ref2].x - org2;

        if (orus1 == orus2)
        {
            /* simple shift of untouched points */
            for (var i = p1; i <= p2; i++)
            {
                var x = worker.orgs[worker.off_orgs + i].x;
                if ( x <= org1 )
                    x += delta1;
                else
                    x += delta2;

                worker.curs[worker.off_curs + i].x = x;
            }
        }
        else
        {
            var scale = 0;
            var scale_valid = 0;

            /* interpolation */
            for (var i = p1; i <= p2; i++)
            {
                var x = worker.orgs[worker.off_orgs + i].x;

                if ( x <= org1 )
                    x += delta1;
                else if ( x >= org2 )
                    x += delta2;
                else
                {
                    if ( !scale_valid )
                    {
                        scale_valid = 1;
                        scale = FT_DivFix(org2 + delta2 - (org1 + delta1), orus2 - orus1);
                    }

                    x = (org1 + delta1) + FT_MulFix(worker.orus[worker.off_orus + i].x - orus1, scale);
                }
                worker.curs[worker.off_curs + i].x = x;
            }
        }
    }
    else
    {
        if (p1 > p2)
            return;

        if ((ref1 >= worker.max_points) || (ref2 >= worker.max_points))
            return;

        var orus1 = worker.orus[worker.off_orus + ref1].y;
        var orus2 = worker.orus[worker.off_orus + ref2].y;

        if (orus1 > orus2)
        {
            var tmp_o = orus1;
            orus1 = orus2;
            orus2 = tmp_o;

            var tmp_r = ref1;
            ref1  = ref2;
            ref2  = tmp_r;
        }

        var org1   = worker.orgs[worker.off_orgs + ref1].y;
        var org2   = worker.orgs[worker.off_orgs + ref2].y;
        var delta1 = worker.curs[worker.off_curs + ref1].y - org1;
        var delta2 = worker.curs[worker.off_curs + ref2].y - org2;

        if (orus1 == orus2)
        {
            /* simple shift of untouched points */
            for (var i = p1; i <= p2; i++)
            {
                var y = worker.orgs[worker.off_orgs + i].y;
                if (y <= org1)
                    y += delta1;
                else
                    y += delta2;

                worker.curs[worker.off_curs + i].y = y;
            }
        }
        else
        {
            var scale = 0;
            var scale_valid = 0;

            /* interpolation */
            for (var i = p1; i <= p2; i++)
            {
                var y = worker.orgs[worker.off_orgs + i].y;

                if (y <= org1)
                    y += delta1;
                else if (y >= org2)
                    y += delta2;
                else
                {
                    if ( !scale_valid )
                    {
                        scale_valid = 1;
                        scale = FT_DivFix(org2 + delta2 - (org1 + delta1), orus2 - orus1);
                    }

                    y = (org1 + delta1) + FT_MulFix(worker.orus[worker.off_orus + i].y - orus1, scale);
                }
                worker.curs[worker.off_curs + i].y = y;
            }
        }
    }
}
// --

function Ins_IUP(exc, args, args_pos)
{
    var mask;

    /* ignore empty outlines */
    if (exc.pts.n_contours == 0)
        return;

    var V = new IUP_WorkerRec();
    if (exc.opcode & 1)
    {
        mask   = 8;
        V.orgs = exc.pts.org;
        V.curs = exc.pts.cur;
        V.orus = exc.pts.orus;

        V.off_orgs = exc.pts._offset_org;
        V.off_curs = exc.pts._offset_cur;
        V.off_orus = exc.pts._offset_orus;
    }
    else
    {
        mask = 16;

        V.orgs = exc.pts.org;
        V.curs = exc.pts.cur;
        V.orus = exc.pts.orus;

        V.off_orgs = exc.pts._offset_org;
        V.off_curs = exc.pts._offset_cur;
        V.off_orus = exc.pts._offset_orus;
        V.is_offset_one = true;
    }
    V.max_points = exc.pts.n_points;

    var contour = 0;
    var point   = 0;

    if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING) // #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
    {
        if (exc.ignore_x_mode)
        {
            exc.iup_called = 1;
            if (exc.sph_tweak_flags & 32768)
                return;
        }
    } //#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */

    do
    {
        var end_point   = exc.pts.contours[exc.pts._offset_contours + contour] - exc.pts.first_point;
        var first_point = point;

        if (end_point >= exc.pts.n_points)
            end_point = exc.pts.n_points - 1;

        while (point <= end_point && (exc.pts.tags[exc.pts._offset_tags + point] & mask) == 0)
            point++;

        if ( point <= end_point )
        {
            var first_touched = point;
            var cur_touched   = point;

            point++;

            while ( point <= end_point )
            {
                if ((exc.pts.tags[exc.pts._offset_tags + point] & mask) != 0)
                {
                    _iup_worker_interpolate(V, cur_touched + 1, point - 1, cur_touched, point);
                    cur_touched = point;
                }

                point++;
            }

            if (cur_touched == first_touched)
                _iup_worker_shift(V, first_point, end_point, cur_touched);
            else
            {
                _iup_worker_interpolate(V, 0xFFFF & (cur_touched + 1), end_point, cur_touched, first_touched);

                if (first_touched > 0)
                    _iup_worker_interpolate(V, first_point, first_touched - 1, cur_touched, first_touched);
            }
        }
        contour++;
    } while (contour < exc.pts.n_contours);
}

function Ins_SHP(exc, args, args_pos)
{
    if (exc.top < exc.GS.loop)
    {
        if (exc.pedantic_hinting)
            exc.error = 134;

        exc.GS.loop = 1;
        exc.new_top = exc.args;
    }

    var zp = new TT_GlyphZoneRec();

    var dx, dy, refp;
    var ret = Compute_Point_Displacement(exc, dx, dy, zp, refp);
    if (ret.err == 1)
        return;

    dx = ret.x;
    dy = ret.y;
    refp = ret.refp;
    while (exc.GS.loop > 0)
    {
        exc.args--;
        var point = 0xFFFF & exc.stack[exc.args];

        if (point >= exc.zp2.n_points)
        {
            if (exc.pedantic_hinting)
            {
                exc.error = 134;
                return;
            }
        }
        else
        {
            if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)
            {
                if (exc.ignore_x_mode)
                    Move_Zp2_Point(exc, point, 0, dy, true);
                else
                    Move_Zp2_Point(exc, point, dx, dy, true);
            }
            else
                Move_Zp2_Point(exc, point, dx, dy, true);
        }

        exc.GS.loop--;
    }

    exc.GS.loop = 1;
    exc.new_top = exc.args;
}

function Ins_SHC(exc, args, args_pos)
{
    var contour = 0xFFFF & args[args_pos];
    var bounds  = (exc.GS.gep2 == 0) ? 1 : exc.zp2.n_contours;

    if (contour >= bounds)
    {
        if (exc.pedantic_hinting)
            exc.error = 134;
        return;
    }

    var zp = new TT_GlyphZoneRec();

    var dx, dy, refp;
    var ret = Compute_Point_Displacement(exc, dx, dy, zp, refp);
    if (ret.err == 1)
        return;

    dx = ret.x;
    dy = ret.y;
    refp = ret.refp;

    var start, limit;
    if (contour == 0)
        start = 0;
    else
        start = 0xFFFF & (exc.zp2.contours[exc.zp2._offset_contours + contour - 1] + 1 - exc.zp2.first_point);

    /* we use the number of points if in the twilight zone */
    if (exc.GS.gep2 == 0)
        limit = exc.zp2.n_points;
    else
        limit = 0xFFFF & (exc.zp2.contours[exc.zp2._offset_contours + contour] - exc.zp2.first_point + 1);

    for (var i = start; i < limit; i++)
    {
        if ((zp.cur != exc.zp2.cur || zp._offset_cur != exc.zp2._offset_cur) || refp != i)
            Move_Zp2_Point(exc, i, dx, dy, true);
    }
}

function Ins_SHZ(exc, args, args_pos)
{
    if (args[args_pos] >= 2)
    {
        if (exc.pedantic_hinting)
            exc.error = 134;
        return;
    }

    var zp = new TT_GlyphZoneRec();

    var dx, dy, refp;
    var ret = Compute_Point_Displacement(exc, dx, dy, zp, refp);
    if (ret.err == 1)
        return;

    dx = ret.x;
    dy = ret.y;
    refp = ret.refp;

    /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points.     */
    /*      Twilight zone has no real contours, so use `n_points'. */
    /*      Normal zone's `n_points' includes phantoms, so must    */
    /*      use end of last contour.                               */
    var limit = 0;
    if (exc.GS.gep2 == 0)
        limit = 0xFFFF & exc.zp2.n_points;
    else if (exc.GS.gep2 == 1 && exc.zp2.n_contours > 0)
        limit = 0xFFFF & (exc.zp2.contours[exc.zp2._offset_contours + exc.zp2.n_contours - 1] + 1);

    /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
    for (var i = 0; i < limit; i++)
    {
        if ((zp.cur != exc.zp2.cur || zp._offset_cur != exc.zp2._offset_cur) || refp != i)
            Move_Zp2_Point(exc, i, dx, dy, false);
    }
}

function Ins_SHPIX(exc, args, args_pos)
{
    if (exc.top < (exc.GS.loop + 1))
    {
        if (exc.pedantic_hinting)
            exc.error = 134;

        exc.GS.loop = 1;
        exc.new_top = exc.args;
        return;
    }

    // TODO: unpatented
    var dx = TT_MulFix14(args[args_pos], exc.GS.freeVector.x);
    var dy = TT_MulFix14(args[args_pos], exc.GS.freeVector.y);

    while (exc.GS.loop > 0)
    {
        exc.args--;
        var point = 0xFFFF & exc.stack[exc.args];

        if (point >= exc.zp2.n_points)
        {
            if (exc.pedantic_hinting)
            {
                exc.error = 134;
                return;
            }
        }
        else
        {
            if (!exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)
            {
                Move_Zp2_Point(exc, point, dx, dy, true);
                exc.GS.loop -= 1;
                continue;
            }

            var B1, B2;
            if (exc.ignore_x_mode)
            {
                /* save point for later comparison */
                if (exc.GS.freeVector.y != 0)
                    B1 = exc.zp2.cur[exc.zp2._offset_cur + point].y;
                else
                    B1 = exc.zp2.cur[exc.zp2._offset_cur + point].x;

                if (!exc.face.sph_compatibility_mode && exc.GS.freeVector.y != 0)
                {
                    Move_Zp2_Point(exc, point, dx, dy, true);

                    /* save new point */
                    if (exc.GS.freeVector.y != 0)
                    {
                        B2 = exc.zp2.cur[exc.zp2._offset_cur + point].y;

                        /* reverse any disallowed moves */
                        if ((exc.sph_tweak_flags & 65536) &&
                            (B1 & 63) != 0 &&
                            (B2 & 63) != 0 &&
                            B1 != B2)
                            Move_Zp2_Point(exc, point, -dx, -dy, true);
                    }
                }
                else if (exc.face.sph_compatibility_mode)
                {
                    if (exc.sph_tweak_flags & 16384)
                    {
                        dx = FT_PIX_ROUND(B1 + dx) - B1;
                        dy = FT_PIX_ROUND(B1 + dy) - B1;
                    }

                    /* skip post-iup deltas */
                    if (exc.iup_called &&
                        ((exc.sph_in_func_flags & 1) ||
                        (exc.sph_in_func_flags & 2)))
                    {
                        exc.GS.loop -= 1;
                        continue;
                    }

                    if (!(exc.sph_tweak_flags & 4) &&
                        ((exc.is_composite && exc.GS.freeVector.y != 0) ||
                        (exc.zp2.tags[exc.zp2._offset_tags + point] & 16) ||
                        (exc.sph_tweak_flags & 32)))
                        Move_Zp2_Point(exc, point, 0, dy, true);

                    /* save new point */
                    if (exc.GS.freeVector.y != 0)
                    {
                        B2 = exc.zp2.cur[exc.zp2._offset_cur + point].y;

                        /* reverse any disallowed moves */
                        if ((B1 & 63) == 0 &&
                            (B2 & 63) != 0 &&
                            B1 != B2)
                            Move_Zp2_Point(exc, point, 0, -dy, true);
                    }
                }
                else if (exc.sph_in_func_flags & 256)
                    Move_Zp2_Point(exc, point, dx, dy, true);
            }
            else
                Move_Zp2_Point(exc, point, dx, dy, true);
        }
		exc.GS.loop--;
    }

    exc.GS.loop = 1;
    exc.new_top = exc.args;
}

function Ins_IP(exc, args, args_pos)
{
    if (exc.top < exc.GS.loop)
    {
        if (exc.pedantic_hinting)
            exc.error = 134;

        exc.GS.loop = 1;
        exc.new_top = exc.args;
        return;
    }

    /*
     * We need to deal in a special way with the twilight zone.
     * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0),
     * for every n.
     */
    var twilight = (exc.GS.gep0 == 0 || exc.GS.gep1 == 0 || exc.GS.gep2 == 0) ? 1 : 0;

    if (exc.GS.rp1 >= exc.zp0.n_points)
    {
        if (exc.pedantic_hinting)
            exc.error = 134;

        exc.GS.loop = 1;
        exc.new_top = exc.args;
        return;
    }

    var orus_base = null;
    var orus_base_off = 0;
    if (twilight)
    {
        orus_base = exc.zp0.org;
        orus_base_off = exc.zp0._offset_org + exc.GS.rp1;
    }
    else
    {
        orus_base = exc.zp0.orus;
        orus_base_off = exc.zp0._offset_orus + exc.GS.rp1;
    }

    var cur_base = exc.zp0.cur;
    var cur_base_off = exc.zp0._offset_cur + exc.GS.rp1;

    var old_range = 0;
    var cur_range = 0;

    /* XXX: There are some glyphs in some braindead but popular */
    /*      fonts out there (e.g. [aeu]grave in monotype.ttf)   */
    /*      calling IP[] with bad values of rp[12].             */
    /*      Do something sane when this odd thing happens.      */
    if ((exc.GS.rp1 >= exc.zp0.n_points) || (exc.GS.rp2 >= exc.zp1.n_points))
    {
        old_range = 0;
        cur_range = 0;
    }
    else
    {
        var v1, v2;
        if (twilight != 0)
        {
            v1 = exc.zp1.org[exc.zp1._offset_org + exc.GS.rp2];
            v2 = orus_base[orus_base_off];
            old_range = exc.func_dualproj(exc, v1.x - v2.x, v1.y - v2.y);
        }
        else if (exc.metrics.x_scale == exc.metrics.y_scale)
        {
            v1 = exc.zp1.orus[exc.zp1._offset_orus + exc.GS.rp2];
            v2 = orus_base[orus_base_off];
            old_range = exc.func_dualproj(exc, v1.x - v2.x, v1.y - v2.y);
        }
        else
        {
            v1 = exc.zp1.orus[exc.zp1._offset_orus + exc.GS.rp2];
            v2 = orus_base[orus_base_off];

            var _x = FT_MulFix(v1.x - v2.x, exc.metrics.x_scale);
            var _y = FT_MulFix(v1.y - v2.y, exc.metrics.y_scale);

            old_range = exc.func_dualproj(exc, _x, _y);
        }

        v1 = exc.zp1.cur[exc.zp1._offset_cur + exc.GS.rp2];
        v2 = cur_base[cur_base_off];

        cur_range = exc.func_project(exc, v1.x - v2.x, v1.y - v2.y);
    }

    for ( ; exc.GS.loop > 0; --exc.GS.loop )
    {
        var point = exc.stack[--exc.args];
        var org_dist, cur_dist, new_dist;

        /* check point bounds */
        if (point >= exc.zp2.n_points)
        {
            if (exc.pedantic_hinting)
            {
                exc.error = 134;
                return;
            }
            continue;
        }

        var v1, v2;
        if (twilight)
        {
            v1 = exc.zp2.org[exc.zp2._offset_org + point];
            v2 = orus_base[orus_base_off];
            org_dist = exc.func_dualproj(exc, v1.x - v2.x, v1.y - v2.y);
        }
        else if ( exc.metrics.x_scale == exc.metrics.y_scale )
        {
            v1 = exc.zp2.orus[exc.zp2._offset_orus + point];
            v2 = orus_base[orus_base_off];
            org_dist = exc.func_dualproj(exc, v1.x - v2.x, v1.y - v2.y);
        }
        else
        {
            v1 = exc.zp2.orus[exc.zp2._offset_orus + point];
            v2 = orus_base[orus_base_off];

            var _x = FT_MulFix(v1.x - v2.x, exc.metrics.x_scale);
            var _y = FT_MulFix(v1.y - v2.y, exc.metrics.y_scale);

            org_dist = exc.func_dualproj(exc, _x, _y);
        }

        v1 = exc.zp2.cur[exc.zp2._offset_cur + point];
        v2 = cur_base[cur_base_off];
        cur_dist = exc.func_project(exc, v1.x - v2.x, v1.y - v2.y);

        if (org_dist != 0)
        {
            if (old_range != 0)
                new_dist = FT_MulDiv(org_dist, cur_range, old_range);
            else
            {
                /* This is the same as what MS does for the invalid case:  */
                /*                                                         */
                /*   delta = (Original_Pt - Original_RP1) -                */
                /*           (Current_Pt - Current_RP1)                    */
                /*                                                         */
                /* In FreeType speak:                                      */
                /*                                                         */
                /*   new_dist = cur_dist -                                 */
                /*              org_dist - cur_dist;                       */

                new_dist = -org_dist;
            }
        }
        else
            new_dist = 0;

        exc.func_move(exc, exc.zp2, 0xFFFF & point, new_dist - cur_dist);
    }

    exc.GS.loop = 1;
    exc.new_top = exc.args;
}

function Ins_MSIRP(exc, args, args_pos)
{
    var control_value_cutin = 0;

    if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)
    {
        control_value_cutin = exc.GS.control_value_cutin;
        if (exc.ignore_x_mode && exc.GS.freeVector.x != 0 && ((exc.sph_tweak_flags & 256) == 0))
            control_value_cutin = 0;
    }

    var point = 0xFFFF & args[args_pos];

    if ((point >= exc.zp1.n_points) || (exc.GS.rp0 >= exc.zp0.n_points))
    {
        if (exc.pedantic_hinting)
            exc.error = 134;
        return;
    }

    /* UNDOCUMENTED!  The MS rasterizer does that with */
    /* twilight points (confirmed by Greg Hitchcock)   */
    if (exc.GS.gep1 == 0)
    {
        copy_vector(exc.zp1.org[exc.zp1._offset_org + point], exc.zp0.org[exc.zp0._offset_org + exc.GS.rp0]);
        exc.func_move_orig(exc, exc.zp1, point, args[args_pos + 1]);
        copy_vector(exc.zp1.cur[exc.zp1._offset_cur + point], exc.zp1.org[exc.zp1._offset_org + point]);
    }

    var v1 = exc.zp1.cur[exc.zp1._offset_cur + point];
    var v2 = exc.zp0.cur[exc.zp0._offset_cur + exc.GS.rp0];
    var distance = exc.func_project(exc, v1.x - v2.x, v1.y - v2.y);

    if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING) // #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
    {
        if (exc.ignore_x_mode && exc.GS.freeVector.x != 0 && (Math.abs(distance - args[args_pos + 1]) >= control_value_cutin))
            distance = args[args_pos + 1];
    } // #endif

    exc.func_move(exc, exc.zp1, point, args[args_pos + 1] - distance);

    exc.GS.rp1 = exc.GS.rp0;
    exc.GS.rp2 = point;

    if ((exc.opcode & 1 ) != 0)
        exc.GS.rp0 = point;
}

function Ins_ALIGNRP(exc, args, args_pos)
{
    if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)//#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
    {
        if (exc.ignore_x_mode && exc.iup_called && (exc.sph_tweak_flags & 512) != 0)
        {
            exc.error = 134;
            exc.GS.loop = 1;
            exc.new_top = exc.args;
            return;
        }
    } // #endif

    if (exc.top < exc.GS.loop || (exc.GS.rp0 >= exc.zp0.n_points))
    {
        if (exc.pedantic_hinting)
            exc.error = 134;

        exc.GS.loop = 1;
        exc.new_top = exc.args;
        return;
    }

    while (exc.GS.loop > 0)
    {
        exc.args--;
        var point = 0xFFFF & exc.stack[exc.args];

        if (point >= exc.zp1.n_points)
        {
            if (exc.pedantic_hinting)
            {
                exc.error = 134;
                return;
            }
        }
        else
        {
            var v1 = exc.zp1.cur[exc.zp1._offset_cur + point];
            var v2 = exc.zp0.cur[exc.zp0._offset_cur + exc.GS.rp0];
            var distance = exc.func_project(exc, v1.x - v2.x, v1.y - v2.y);

            exc.func_move(exc, exc.zp1, point, -distance);
        }
        exc.GS.loop--;
    }

    exc.GS.loop = 1;
    exc.new_top = exc.args;
}

function Ins_RTDG(exc, args, args_pos)
{
    exc.GS.round_state = TT_Round_To_Double_Grid;
    exc.func_round = Round_To_Double_Grid;
}

function Ins_MIAP(exc, args, args_pos)
{
    var control_value_cutin = exc.GS.control_value_cutin;
    var cvtEntry            = FT_Common.IntToUInt(args[args_pos + 1]);
    var point               = 0xFFFF & args[args_pos];

    var bIsSubpix = exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;
    if (bIsSubpix) // #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
    {
        if (exc.ignore_x_mode && exc.GS.freeVector.x != 0 && exc.GS.freeVector.y == 0 && (exc.sph_tweak_flags & 256) == 0)
            control_value_cutin = 0;
    } // #endif

    if ((point >= exc.zp0.n_points) || (cvtEntry >= exc.cvtSize))
    {
        if (exc.pedantic_hinting)
            exc.error = 134;

        exc.GS.rp0 = point;
        exc.GS.rp1 = point;
        return;
    }

    /* UNDOCUMENTED!                                                      */
    /*                                                                    */
    /* The behaviour of an MIAP instruction is quite different when used  */
    /* in the twilight zone.                                              */
    /*                                                                    */
    /* First, no control value cut-in test is performed as it would fail  */
    /* anyway.  Second, the original point, i.e. (org_x,org_y) of         */
    /* zp0.point, is set to the absolute, unrounded distance found in the */
    /* CVT.                                                               */
    /*                                                                    */
    /* This is used in the CVT programs of the Microsoft fonts Arial,     */
    /* Times, etc., in order to re-adjust some key font heights.  It      */
    /* allows the use of the IP instruction in the twilight zone, which   */
    /* otherwise would be invalid according to the specification.         */
    /*                                                                    */
    /* We implement it with a special sequence for the twilight zone.     */
    /* This is a bad hack, but it seems to work.                          */
    /*                                                                    */
    /* Confirmed by Greg Hitchcock.                                       */

    var distance = exc.func_read_cvt(exc, cvtEntry);

    if (exc.GS.gep0 == 0)   /* If in twilight zone */
    {
        if (!bIsSubpix)
        {
            exc.zp0.org[exc.zp0._offset_org + point].x = TT_MulFix14(distance, exc.GS.freeVector.x);
        }

        exc.zp0.org[exc.zp0._offset_org + point].y = TT_MulFix14(distance, exc.GS.freeVector.y),
        exc.zp0.cur[exc.zp0._offset_cur + point].x = exc.zp0.org[exc.zp0._offset_org + point].x;
        exc.zp0.cur[exc.zp0._offset_cur + point].y = exc.zp0.org[exc.zp0._offset_org + point].y;
    }

    if (bIsSubpix)
    {
        if (exc.ignore_x_mode && (exc.sph_tweak_flags & 128) != 0 && distance > 0 && exc.GS.freeVector.y != 0)
            distance = 0;
    }

    var v = exc.zp0.cur[exc.zp0._offset_cur + point];
    var org_dist = exc.func_project(exc, v.x, v.y);

    if ((exc.opcode & 1) != 0)   /* rounding and control cut-in flag */
    {
        if (Math.abs(distance - org_dist) > control_value_cutin)
            distance = org_dist;

        if (bIsSubpix)
        {
            if (exc.ignore_x_mode && exc.GS.freeVector.x != 0)
                distance = Round_None(exc, distance, exc.tt_metrics.compensations[0]);
            else
                distance = exc.func_round(exc, distance, exc.tt_metrics.compensations[0]);
        }
        else
        {
            distance = exc.func_round(exc, distance, exc.tt_metrics.compensations[0]);
        }
    }

    exc.func_move(exc, exc.zp0, point, distance - org_dist);
    
    exc.GS.rp0 = point;
    exc.GS.rp1 = point;
}

function Ins_NPUSHB(exc, args, args_pos)
{
    var L = exc.code.data[exc.code.pos + exc.IP + 1];

    if (L >= (exc.stackSize + 1 - exc.top))
    {
        exc.error = 130;
        return;
    }

    for (var K = 1; K <= L; K++)
        args[args_pos + K - 1] = exc.code.data[exc.code.pos + exc.IP + K + 1];

    exc.new_top += L;
}

// --
function GetShortIns(exc)
{
    /* Reading a byte stream so there is no endianess (DaveP) */
    exc.IP += 2;
    return FT_Common.UShort_To_Short((exc.code.data[exc.code.pos + exc.IP - 2] << 8) + exc.code.data[exc.code.pos + exc.IP - 1]);
}
// --

function Ins_NPUSHW(exc, args, args_pos)
{
    var L = exc.code.data[exc.code.pos + exc.IP + 1];

    if (L >=  (exc.stackSize + 1 - exc.top))
    {
        exc.error = 130;
        return;
    }

    exc.IP += 2;

    for (var K = 0; K < L; K++)
        args[args_pos + K] = GetShortIns(exc);

    exc.step_ins = false;
    exc.new_top += L;
}

function Ins_WS(exc, args, args_pos)
{
    var I = args[args_pos];
    if (I >= exc.storeSize)
    {
        if (exc.pedantic_hinting)
        {
            exc.error = 134;
            return;
        }
    }
    else
        exc.storage[I] = args[args_pos + 1];
}

function Ins_RS(exc, args, args_pos)
{
    if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)
    {
        var I = FT_Common.IntToUInt(args[args_pos]);
        if (I >= exc.storeSize)
        {
            if (exc.pedantic_hinting)
            {
                exc.error = 134;
                return;
            }
            else
                args[args_pos] = 0;
        }
        else
        {
            /* subpixel hinting - avoid Typeman Dstroke and */
            /* IStroke and Vacuform rounds                  */

            if (exc.ignore_x_mode &&
                ((I == 24) && (exc.face.sph_found_func_flags & (32 | 64))) ||
                ((I == 22) && (exc.sph_in_func_flags & 128)) ||
                ((I == 8) && (exc.face.sph_found_func_flags & 8) && exc.iup_called))
                args[args_pos] = 0;
            else
                args[args_pos] = exc.storage[I];
        }
    }
    else
    {
        var I = FT_Common.IntToUInt(args[args_pos]);

        if (I >= exc.storeSize)
        {
            if (exc.pedantic_hinting)
            {
                exc.error = 134;
                return;
            }
            else
                args[args_pos] = 0;
        }
        else
            args[args_pos] = exc.storage[I];
    }
}

function Ins_WCVTP(exc, args, args_pos)
{
    var I = args[args_pos];
    if (I >= exc.cvtSize)
    {
        if (exc.pedantic_hinting)
        {
            exc.error = 134;
            return;
        }
    }
    else
        exc.func_write_cvt(exc, I, args[args_pos + 1]);
}

function Ins_RCVT(exc, args, args_pos)
{
    var I = args[args_pos];
    if (I >= exc.cvtSize)
    {
        if (exc.pedantic_hinting)
        {
            exc.error = 134;
            return;
        }
        else
            args[args_pos] = 0;
    }
    else
       args[args_pos] = exc.func_read_cvt(exc, I);
}

function Ins_GC(exc, args, args_pos)
{
    var L = args[args_pos];
    var R = 0;
    if (L >= exc.zp2.n_points)
    {
        if (exc.pedantic_hinting)
            exc.error = 134;
    }
    else
    {
        if (exc.opcode & 1)
            R = exc.func_dualproj(exc, exc.zp2.org[exc.zp2._offset_org + L].x, exc.zp2.org[exc.zp2._offset_org + L].y);
        else
            R = exc.func_project(exc, exc.zp2.cur[exc.zp2._offset_cur + L].x, exc.zp2.cur[exc.zp2._offset_cur + L].y);
    }

    args[args_pos] = R;
}

function Ins_SCFS(exc, args, args_pos)
{
    var L = 0xFFFF & args[args_pos];

    if (L >= exc.zp2.n_points)
    {
        if (exc.pedantic_hinting)
            exc.error = 134;
        return;
    }

    var K = exc.func_project(exc, exc.zp2.cur[exc.zp2._offset_cur + L].x, exc.zp2.cur[exc.zp2._offset_cur + L].y);

    exc.func_move(exc, exc.zp2, L, args[args_pos + 1] - K);

    /* UNDOCUMENTED!  The MS rasterizer does that with */
    /* twilight points (confirmed by Greg Hitchcock)   */
    if (exc.GS.gep2 == 0)
    {
        exc.zp2.org[exc.zp2._offset_org + L].x = exc.zp2.cur[exc.zp2._offset_cur + L].x;
        exc.zp2.org[exc.zp2._offset_org + L].y = exc.zp2.cur[exc.zp2._offset_cur + L].y;
    }
}

function Ins_MD(exc, args, args_pos)
{
    var D = 0;
    var K = 0xFFFF & args[args_pos + 1];
    var L = 0xFFFF & args[args_pos];

    if ((L >= exc.zp0.n_points) || (K >= exc.zp1.n_points))
    {
        if (exc.pedantic_hinting)
            exc.error = 134;
        D = 0;
    }
    else
    {
        if (exc.opcode & 1)
        {
            var vec1 = exc.zp0.cur[exc.zp0._offset_cur + L];
            var vec2 = exc.zp1.cur[exc.zp1._offset_cur + K];

            D = exc.func_project(exc, vec1.x - vec2.x, vec1.y - vec2.y);
        }
        else
        {
            /* XXX: UNDOCUMENTED: twilight zone special case */
            if (exc.GS.gep0 == 0 || exc.GS.gep1 == 0)
            {
                var vec1 = exc.zp0.org[exc.zp0._offset_org + L];
                var vec2 = exc.zp1.org[exc.zp1._offset_org + K];

                D = exc.func_dualproj(exc, vec1.x - vec2.x, vec1.y - vec2.y);
            }
            else
            {
                var vec1 = exc.zp0.orus[exc.zp0._offset_orus + L];
                var vec2 = exc.zp1.orus[exc.zp1._offset_orus + K];

                if ( exc.metrics.x_scale == exc.metrics.y_scale )
                {
                    /* this should be faster */
                    D = exc.func_dualproj(exc, vec1.x - vec2.x, vec1.y - vec2.y);
                    D = FT_MulFix(D, exc.metrics.x_scale);
                }
                else
                {
                    var vec = new FT_Vector();
                    vec.x = FT_MulFix(vec1.x - vec2.x, exc.metrics.x_scale);
                    vec.y = FT_MulFix(vec1.y - vec2.y, exc.metrics.y_scale);

                    D = exc.func_dualproj(exc, vec.x, vec.y);
                }
            }
        }
    }

    if (exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)//#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
    {
        /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */
        if (exc.ignore_x_mode && Math.abs(D) == 64)
            D += 1;
    } //#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */

    args[args_pos] = D;
}

// --
function Current_Ppem(exc)
{
    return FT_MulFix(exc.tt_metrics.ppem, Current_Ratio(exc));
}

function Current_Ratio(exc)
{
    if (!exc.tt_metrics.ratio)
    {
        // TODO: unpatented
        if (exc.GS.projVector.y == 0)
            exc.tt_metrics.ratio = exc.tt_metrics.x_ratio;
        else if (exc.GS.projVector.x == 0)
            exc.tt_metrics.ratio = exc.tt_metrics.y_ratio;
        else
        {
            var x = TT_MulFix14(exc.tt_metrics.x_ratio, exc.GS.projVector.x);
            var y = TT_MulFix14(exc.tt_metrics.y_ratio, exc.GS.projVector.y);
            exc.tt_metrics.ratio = FT_Hypot(x, y);
        }
    }
    return exc.tt_metrics.ratio;
}

function FT_MulDiv_No_Round(a, b, c)
{
    var s = 1;
    if ( a < 0 ) { a = -a; s = -1; }
    if ( b < 0 ) { b = -b; s = -s; }
    if ( c < 0 ) { c = -c; s = -s; }

    var d = (c > 0 ? a * b / c : 0x7FFFFFFF);
    d = d >> 0;

    return ( s > 0 ) ? d : -d;
}
// --

function Ins_MPPEM(exc, args, args_pos)
{
    args[args_pos] = Current_Ppem(exc);
}

function Ins_MPS(exc, args, args_pos)
{
    args[args_pos] = Current_Ppem(exc);
}

function Ins_FLIPON(exc, args, args_pos)
{
    exc.GS.auto_flip = true;
}

function Ins_FLIPOFF(exc, args, args_pos)
{
    exc.GS.auto_flip = false;
}

function Ins_DEBUG(exc, args, args_pos)
{
    exc.error = 135;
}

function Ins_LT(exc, args, args_pos)
{
    args[args_pos] = (args[args_pos] < args[args_pos + 1]) ? 1 : 0;
}
function Ins_LTEQ(exc, args, args_pos)
{
    args[args_pos] = (args[args_pos] <= args[args_pos + 1]) ? 1 : 0;
}
function Ins_GT(exc, args, args_pos)
{
    args[args_pos] = (args[args_pos] > args[args_pos + 1]) ? 1 : 0;
}
function Ins_GTEQ(exc, args, args_pos)
{
    args[args_pos] = (args[args_pos] >= args[args_pos + 1]) ? 1 : 0;
}
function Ins_EQ(exc, args, args_pos)
{
    args[args_pos] = (args[args_pos] == args[args_pos + 1]) ? 1 : 0;
}
function Ins_NEQ(exc, args, args_pos)
{
    args[args_pos] = (args[args_pos] != args[args_pos + 1]) ? 1 : 0;
}
function Ins_ODD(exc, args, args_pos)
{
    args[args_pos] = ((exc.func_round(exc, args[args_pos], 0) & 127) == 64) ? 1 : 0;
}
function Ins_EVEN(exc, args, args_pos)
{
    args[args_pos] = ((exc.func_round(exc, args[args_pos], 0) & 127) == 0) ? 1 : 0;
}
function Ins_IF(exc, args, args_pos)
{
    if (args[args_pos] != 0)
        return;

    var nIfs = 1;
    var Out = 0;

    do
    {
        if (SkipCode(exc) == 1)
            return;

        switch ( exc.opcode )
        {
        case 0x58:      /* IF */
            nIfs++;
            break;
        case 0x1B:      /* ELSE */
            Out = (nIfs == 1) ? 1 : 0;
            break;
        case 0x59:      /* EIF */
            nIfs--;
            Out = (nIfs == 0) ? 1 : 0;
            break;
        }
    } while ( Out == 0 );
}
function Ins_EIF(exc, args, args_pos)
{
    // nothing
}
function Ins_AND(exc, args, args_pos)
{
    args[args_pos] = (args[args_pos] && args[args_pos + 1]) ? 1 : 0;
}
function Ins_OR(exc, args, args_pos)
{
    args[args_pos] = (args[args_pos] || args[args_pos + 1]) ? 1 : 0;
}
function Ins_NOT(exc, args, args_pos)
{
    args[args_pos] = (args[args_pos] != 0) ? 0 : 1;
}
function Ins_SDB(exc, args, args_pos)
{
    exc.GS.delta_base = FT_Common.UShort_To_Short(0xFFFF & args[args_pos]);
}
function Ins_SDS(exc, args, args_pos)
{
    exc.GS.delta_shift = FT_Common.UShort_To_Short(0xFFFF & args[args_pos]);
}

function Ins_ADD(exc, args, args_pos)
{
    args[args_pos] += args[args_pos + 1];
}
function Ins_SUB(exc, args, args_pos)
{
    args[args_pos] -= args[args_pos + 1];
}
function Ins_DIV(exc, args, args_pos)
{
    if (args[args_pos + 1] == 0)
        exc.error = 133;
    else
        args[args_pos] = FT_MulDiv_No_Round(args[args_pos], 64, args[args_pos + 1]);
}
function Ins_MUL(exc, args, args_pos)
{
    args[args_pos] = FT_MulDiv(args[args_pos], args[args_pos + 1], 64);
}
function Ins_ABS(exc, args, args_pos)
{
    args[args_pos] = Math.abs(args[args_pos]);
}
function Ins_NEG(exc, args, args_pos)
{
    args[args_pos] = -args[args_pos];
}
function Ins_FLOOR(exc, args, args_pos)
{
    args[args_pos] = FT_PIX_FLOOR(args[args_pos]);
}
function Ins_CEILING(exc, args, args_pos)
{
    args[args_pos] = FT_PIX_CEIL(args[args_pos]);
}
function Ins_ROUND(exc, args, args_pos)
{
    args[args_pos] = exc.func_round(exc, args[args_pos], exc.tt_metrics.compensations[exc.opcode - 0x68]);
}
function Ins_NROUND(exc, args, args_pos)
{
    args[args_pos] = Round_None(exc, args[args_pos], exc.tt_metrics.compensations[exc.opcode - 0x6C]);
}

function Ins_WCVTF(exc, args, args_pos)
{
    var I = args[args_pos];
    if (I >= exc.cvtSize)
    {
        if (exc.pedantic_hinting)
        {
            exc.error = 134;
            return;
        }
    }
    else
    {
        exc.cvt[I] = FT_MulFix(args[args_pos + 1], exc.tt_metrics.scale);
    }
}

function Ins_DELTAP(exc, args, args_pos)
{
    var A = 0;
    var C = 0;
    var B = 0;
    var B1 = 0;
    var B2 = 0;

    var bIsSubpix = exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;

    if (bIsSubpix)
    {
        if (exc.ignore_x_mode && exc.iup_called && (exc.sph_tweak_flags & 2048) != 0)
        {
            exc.new_top = exc.args;
            return;
        }
    }

    // TODO: unpatented

    var nump = args[args_pos];   /* some points theoretically may occur more
                                   than once, thus UShort isn't enough */
    if (nump < 0)
        nump += 4294967296;

    for (var k = 1; k <= nump; k++)
    {
        if (exc.args < 2)
        {
            if (exc.pedantic_hinting)
                exc.error = 129;
            exc.args = 0;
            exc.new_top = exc.args;
            return;
        }

        exc.args -= 2;

        A = 0xFFFF & exc.stack[exc.args + 1];
        B = exc.stack[exc.args];

        /* XXX: Because some popular fonts contain some invalid DeltaP */
        /*      instructions, we simply ignore them when the stacked   */
        /*      point reference is off limit, rather than returning an */
        /*      error.  As a delta instruction doesn't change a glyph  */
        /*      in great ways, this shouldn't be a problem.            */
        if (A < exc.zp0.n_points)
        {
            C = (B & 0xF0) >> 4;

            switch (exc.opcode)
            {
            case 0x5D:
                break;
            case 0x71:
                C += 16;
                break;
            case 0x72:
                C += 32;
                break;
            }

            C += exc.GS.delta_base;
            if (C < 0)
                C += 4294967296;

            if (Current_Ppem(exc) == C)
            {
                B = (B & 0xF) - 8;
                if (B >= 0)
                    B++;
                B = B * 64 / (1 << exc.GS.delta_shift);
                B = B >> 0;

                if (!bIsSubpix)
                {
                    exc.func_move(exc, exc.zp0, A, B);
                }
                else
                {
                    /*
                    *  Allow delta move if
                    *
                    *  - not using ignore_x_mode rendering
                    *  - glyph is specifically set to allow it
                    *  - glyph is composite and freedom vector is not subpixel vector
                    */
                    if (!exc.ignore_x_mode || (exc.sph_tweak_flags & 2) != 0 ||
                        (exc.is_composite && exc.GS.freeVector.y != 0))
                        exc.func_move(exc, exc.zp0, A, B);
                    else if (exc.ignore_x_mode) /* Otherwise apply subpixel hinting and compatibility mode rules */
                    {
                        if (exc.GS.freeVector.y != 0)
                            B1 = exc.zp0.cur[exc.zp0._offset_cur + A].y;
                        else
                            B1 = exc.zp0.cur[exc.zp0._offset_cur + A].x;

                        /*
                        // Standard Subpixel Hinting:  Allow y move
                        if (!exc.face.sph_compatibility_mode && exc.GS.freeVector.y != 0)
                            exc.func_move(exc, exc.zp0, A, B);
                        // Compatibility Mode: Allow x or y move if point touched in Y direction
                        else */if (exc.face.sph_compatibility_mode && (exc.sph_tweak_flags & 4) == 0)
                        {
                            /* save the y value of the point now; compare after move */
                            B1 = exc.zp0.cur[exc.zp0._offset_cur + A].y;

                            if ((exc.sph_tweak_flags & 16384) != 0)
                                B = FT_PIX_ROUND(B1 + B) - B1;

                            /*
                            *  Allow delta move if using compatibility_mode, IUP has not
                            *  been called, and point is touched on Y.
                            */
                            if (!exc.iup_called && (exc.zp0.tags[exc.zp0._offset_tags + A] & 16) != 0)
                                exc.func_move(exc, exc.zp0, A, B);
                        }

                        B2 = exc.zp0.cur[exc.zp0._offset_cur + A].y;

                        /* Reverse this move if it results in a disallowed move */
                        if (exc.GS.freeVector.y != 0 &&
                            ((exc.face.sph_compatibility_mode && (B1 & 63) == 0 && (B2 & 63) != 0 ) ||
                            ((exc.sph_tweak_flags & 524288) != 0 && (B1 & 63) != 0 && (B2 & 63) != 0)))
                            exc.func_move(exc, exc.zp0, A, -B);
                    }
                }

            }
        }
        else
        {
            if (exc.pedantic_hinting)
                exc.error = 134;
        }
    }

    exc.new_top = exc.args;
}

function Ins_DELTAC(exc, args, args_pos)
{
    // TODO: unpatented
    var nump = args[args_pos];

    for (var k = 1; k <= nump; k++)
    {
        if (exc.args < 2)
        {
            if (exc.pedantic_hinting)
                exc.error = 129;
            exc.args = 0;
            exc.new_top = exc.args;
            return;
        }

        exc.args -= 2;

        var A = FT_Common.IntToUInt(exc.stack[exc.args + 1]);
        var B = exc.stack[exc.args];
        var C = 0;

        if (A >= exc.cvtSize)
        {
            if (exc.pedantic_hinting)
            {
                exc.error = 134;
                return;
            }
        }
        else
        {
            C = (B & 0xF0) >> 4;

            switch (exc.opcode)
            {
            case 0x73:
                break;
            case 0x74:
                C += 16;
                break;
            case 0x75:
                C += 32;
                break;
            }

            C += exc.GS.delta_base;

            if (Current_Ppem(exc) == C)
            {
                B = (B & 0xF) - 8;
                if (B >= 0)
                    B++;
                B = B * 64 / (1 << exc.GS.delta_shift);
                B = B >> 0;

                exc.func_move_cvt(exc, A, B);
            }
        }
    }
    exc.new_top = exc.args;
}

function Ins_SROUND(exc, args, args_pos)
{
    SetSuperRound(exc, 0x4000, args[args_pos]);
    exc.GS.round_state = TT_Round_Super;
    exc.func_round = Round_Super;
}

function Ins_S45ROUND(exc, args, args_pos)
{
    SetSuperRound(exc, 0x2D41, args[args_pos]);
    exc.GS.round_state = TT_Round_Super_45;
    exc.func_round = Round_Super_45;
}

function Ins_JROT(exc, args, args_pos)
{
    if (args[args_pos + 1] != 0)
    {
        if (args[args_pos] == 0 && exc.args == 0)
            exc.error = 132;
        exc.IP += args[args_pos];
        if (exc.IP < 0 || (exc.callTop > 0 && exc.IP > exc.callStack[exc.callTop - 1].Def.end))
            exc.error = 132;
        exc.step_ins = false;
    }
}

function Ins_JROF(exc, args, args_pos)
{
    if (args[args_pos + 1] == 0)
    {
        if (args[args_pos] == 0 && exc.args == 0)
            exc.error = 132;
        exc.IP += args[args_pos];
        if (exc.IP < 0 || (exc.callTop > 0 && exc.IP > exc.callStack[exc.callTop - 1].Def.end))
            exc.error = 132;
        exc.step_ins = false;
    }
}

function Ins_ROFF(exc, args, args_pos)
{
    exc.GS.round_state = TT_Round_Off;
    exc.func_round = Round_None;
}

function Ins_RUTG(exc, args, args_pos)
{
    exc.GS.round_state = TT_Round_Up_To_Grid;
    exc.func_round = Round_Up_To_Grid;
}

function Ins_RDTG(exc, args, args_pos)
{
    exc.GS.round_state = TT_Round_Down_To_Grid;
    exc.func_round = Round_Down_To_Grid;
}

function Ins_SANGW(exc, args, args_pos)
{
    /* instruction not supported anymore */
}

function Ins_AA(exc, args, args_pos)
{
    /* intentionally no longer supported */
}

function Ins_FLIPPT(exc, args, args_pos)
{
    if (exc.top < exc.GS.loop)
    {
        if (exc.pedantic_hinting)
            exc.error = 129;

        exc.GS.loop = 1;
        exc.new_top = exc.args;
        return;
    }

    while (exc.GS.loop > 0)
    {
        exc.args--;
        var point = 0xFFFF & exc.stack[exc.args];

        if (point >= exc.pts.n_points)
        {
            if (exc.pedantic_hinting)
            {
                exc.error = 134;
                return;
            }
        }
        else
            exc.pts.tags[exc.pts._offset_tags + point] ^= 1;

        exc.GS.loop--;
    }

    exc.GS.loop = 1;
    exc.new_top = exc.args;
}

function Ins_FLIPRGON(exc, args, args_pos)
{
    var K = 0xFFFF & args[args_pos + 1];
    var L = 0xFFFF & args[args_pos];

    if ((K >= exc.pts.n_points) || (L >= exc.pts.n_points))
    {
        if (exc.pedantic_hinting)
            exc.error = 134;
        return;
    }

    for (var I = L; I <= K; I++)
        exc.pts.tags[exc.pts._offset_tags + I] |= 1;
}

function Ins_FLIPRGOFF(exc, args, args_pos)
{
    var K = 0xFFFF & args[args_pos + 1];
    var L = 0xFFFF & args[args_pos];

    if ((K >= exc.pts.n_points) || (L >= exc.pts.n_points))
    {
        if (exc.pedantic_hinting)
            exc.error = 134;
        return;
    }

    for (var I = L; I <= K; I++)
        exc.pts.tags[exc.pts._offset_tags + I] &= ~1;
}

function Ins_SCANCTRL(exc, args, args_pos)
{
    /* Get Threshold */
    var A = (args[args_pos] & 0xFF);

    if (A == 0xFF)
    {
        exc.GS.scan_control = true;
        return;
    }
    else if (A == 0)
    {
        exc.GS.scan_control = false;
        return;
    }

    if ((args[args_pos] & 0x100 ) != 0 && exc.tt_metrics.ppem <= A)
        exc.GS.scan_control = true;

    if ((args[args_pos] & 0x200 ) != 0 && exc.tt_metrics.rotated)
        exc.GS.scan_control = true;

    if ((args[args_pos] & 0x400 ) != 0 && exc.tt_metrics.stretched)
        exc.GS.scan_control = true;

    if ((args[args_pos] & 0x800 ) != 0 && exc.tt_metrics.ppem > A)
        exc.GS.scan_control = false;

    if ((args[args_pos] & 0x1000 ) != 0 && exc.tt_metrics.rotated)
        exc.GS.scan_control = false;

    if ((args[args_pos] & 0x2000 ) != 0 && exc.tt_metrics.stretched)
        exc.GS.scan_control = false;
}

function Ins_SDPVTL(exc, args, args_pos)
{
    var aOpc = exc.opcode;

    var p1 = 0xFFFF & args[args_pos + 1];
    var p2 = 0xFFFF & args[args_pos];

    if ((p2 >= exc.zp1.n_points) || (p1 >= exc.zp2.n_points))
    {
        if (exc.pedantic_hinting)
            exc.error = 134;
        return;
    }

    var v1 = exc.zp1.org[exc.zp1._offset_org + p2];
    var v2 = exc.zp2.org[exc.zp2._offset_org + p1];

    var A = v1.x - v2.x;
    var B = v1.y - v2.y;

    /* If v1 == v2, SDPVTL behaves the same as */
    /* SVTCA[X], respectively.                 */
    /*                                         */
    /* Confirmed by Greg Hitchcock.            */
    if ( A == 0 && B == 0 )
    {
        A    = 0x4000;
        aOpc = 0;
    }

    if ((aOpc & 1) != 0)
    {
        var C =  B;   /* counter clockwise rotation */
        B =  A;
        A = -C;
    }

    Normalize(exc, A, B, exc.GS.dualVector);

    v1 = exc.zp1.cur[exc.zp1._offset_cur + p2];
    v2 = exc.zp2.cur[exc.zp2._offset_cur + p1];

    A = v1.x - v2.x;
    B = v1.y - v2.y;

    if ( A == 0 && B == 0 )
    {
        A    = 0x4000;
        aOpc = 0;
    }

    if ((aOpc & 1) != 0)
    {
        var C =  B;   /* counter clockwise rotation */
        B =  A;
        A = -C;
    }

    Normalize(exc, A, B, exc.GS.projVector);

    GUESS_VECTOR(exc, exc.GS.freeVector);

    Compute_Funcs(exc);
}

function Ins_GETINFO(exc, args, args_pos)
{
    var K = 0;
    var bIsSubpix = exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;

    if (bIsSubpix)
    {
        /********************************/
        /* RASTERIZER VERSION           */
        /* Selector Bit:  0             */
        /* Return Bit(s): 0-7           */
        /*                              */
        if ((args[args_pos] & 1) != 0 && exc.ignore_x_mode)
        {
            K = exc.rasterizer_version;
        }
        else
        {
            if ((args[args_pos] & 1) != 0)
                K = 35;
        }
    }
    else
    {
        if ((args[args_pos] & 1) != 0)
            K = 35;
    }

    /********************************/
    /* GLYPH ROTATED                */
    /* Selector Bit:  1             */
    /* Return Bit(s): 8             */
    /*                              */
    if ((args[args_pos] & 2) != 0 && exc.tt_metrics.rotated)
        K |= 0x80;

    /********************************/
    /* GLYPH STRETCHED              */
    /* Selector Bit:  2             */
    /* Return Bit(s): 9             */
    /*                              */
    if ((args[args_pos] & 4) != 0 && exc.tt_metrics.stretched)
        K |= 1 << 8;

    /********************************/
    /* HINTING FOR GRAYSCALE        */
    /* Selector Bit:  5             */
    /* Return Bit(s): 12            */
    /*                              */
    if ((args[args_pos] & 32) != 0 && exc.grayscale)
        K |= 1 << 12;

    if (bIsSubpix) //#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
    {
        if (exc.ignore_x_mode && exc.rasterizer_version >= 35)
        {
            /********************************/
            /* HINTING FOR GRAYSCALE        */
            /* Selector Bit:  5             */
            /* Return Bit(s): 12            */
            /*                              */
            if ((args[args_pos] & 32) != 0 && exc.grayscale_hinting)
                K |= 1 << 12;

            if (exc.rasterizer_version >= 37)
            {
                /********************************/
                /* HINTING FOR SUBPIXEL         */
                /* Selector Bit:  6             */
                /* Return Bit(s): 13            */
                /*                              */
                if ((args[0] & 64) != 0 && exc.subpixel_hinting)
                    K |= 1 << 13;

                /********************************/
                /* COMPATIBLE WIDTHS ENABLED    */
                /* Selector Bit:  7             */
                /* Return Bit(s): 14            */
                /*                              */
                /* Functionality still needs to be added */
                if ((args[0] & 128) != 0 && exc.compatible_widths)
                    K |= 1 << 14;

                /********************************/
                /* SYMMETRICAL SMOOTHING        */
                /* Selector Bit:  8             */
                /* Return Bit(s): 15            */
                /*                              */
                /* Functionality still needs to be added */
                if ((args[0] & 256 ) != 0 && exc.symmetrical_smoothing)
                    K |= 1 << 15;

                /********************************/
                /* HINTING FOR BGR?             */
                /* Selector Bit:  9             */
                /* Return Bit(s): 16            */
                /*                              */
                /* Functionality still needs to be added */
                if ((args[0] & 512) != 0 && exc.bgr)
                    K |= 1 << 16;

                if (exc.rasterizer_version >= 38)
                {
                    /********************************/
                    /* SUBPIXEL POSITIONED?         */
                    /* Selector Bit:  10            */
                    /* Return Bit(s): 17            */
                    /*                              */
                    /* Functionality still needs to be added */
                    if ((args[0] & 1024) != 0 && exc.subpixel_positioned)
                        K |= 1 << 17;
                }
            }
        }
    }//#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
    args[args_pos] = K;
}

function Ins_IDEF(exc, args, args_pos)
{
    /*  First of all, look for the same function in our table */
    var defs = exc.IDefs;
    var _ind_def = 0;
    var limit = exc.numIDefs;
    var def = defs[_ind_def];

    for ( ; _ind_def < limit; _ind_def++)
    {
        def = defs[_ind_def];
        if (def.opc == args[args_pos])
            break;
    }

    if (_ind_def == limit)
    {
        /* check that there is enough room for a new instruction */
        if (exc.numIDefs >= exc.maxIDefs)
        {
            exc.error = 141;
            return;
        }
        exc.numIDefs++;
    }

    /* opcode must be unsigned 8-bit integer */
    if (0 > args[args_pos] || args[args_pos] > 0x00FF)
    {
        exc.error = 141;
        return;
    }

    def.opc    = 0xFF & args[args_pos];
    def.start  = exc.IP + 1;
    def.range  = exc.curRange;
    def.active = true;

    if (args[args_pos] > exc.maxIns)
        exc.maxIns = 0xFF & args[args_pos];

    /* Now skip the whole function definition. */
    /* We don't allow nested IDEFs & FDEFs.    */

    while (SkipCode(exc) == 0)
    {
        switch (exc.opcode)
        {
        case 0x89:   /* IDEF */
        case 0x2C:   /* FDEF */
            exc.error = 137;
            return;
      case 0x2D:   /* ENDF */
            return;
        }
    }
}

function Ins_ROLL(exc, args, args_pos)
{
    var A = args[args_pos + 2];
    var B = args[args_pos + 1];
    var C = args[args_pos];

    args[args_pos + 2] = C;
    args[args_pos + 1] = A;
    args[args_pos] = B;
}

function Ins_MAX(exc, args, args_pos)
{
    if (args[args_pos + 1] > args[args_pos])
        args[args_pos] = args[args_pos + 1];
}

function Ins_MIN(exc, args, args_pos)
{
    if (args[args_pos + 1] < args[args_pos])
        args[args_pos] = args[args_pos + 1];
}

function Ins_SCANTYPE(exc, args, args_pos)
{
    if (args[args_pos] >= 0)
        exc.GS.scan_type = args[args_pos];
}

function Ins_INSTCTRL(exc, args, args_pos)
{
    var K = args[args_pos + 1];
    var L = args[args_pos];

    if (K < 1 || K > 2)
    {
        if (exc.pedantic_hinting)
            exc.error = 134;
        return;
    }

    if (L != 0)
        L = K;

    exc.GS.instruct_control = ((((0xFF & exc.GS.instruct_control) & ~(K & 0xFF)) | (L & 0xFF)) != 0) ? 1 : 0;
}

function Ins_PUSHB(exc, args, args_pos)
{
    var L = 0xFFFF & (exc.opcode - 0xB0 + 1);

    if (L >= (exc.stackSize + 1 - exc.top))
    {
        exc.error = 130;
        return;
    }

    for (var K = 1; K <= L; K++)
        args[args_pos + K - 1] = exc.code.data[exc.code.pos + exc.IP + K];
}

function Ins_PUSHW(exc, args, args_pos)
{
    var L = 0xFFFF & (exc.opcode - 0xB8 + 1);

    if (L >= (exc.stackSize + 1 - exc.top))
    {
        exc.error = 130;
        return;
    }

    exc.IP++;

    for (var K = 0; K < L; K++)
        args[args_pos + K] = GetShortIns(exc);

    exc.step_ins = false;
}

function Ins_MDRP(exc, args, args_pos)
{
    var org_dist, distance;
    var minimum_distance = exc.GS.minimum_distance;

    var bIsSubpix = exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;

    if (bIsSubpix)
    {
        if (exc.ignore_x_mode && exc.GS.freeVector.x != 0 && (exc.sph_tweak_flags & 256) == 0)
            minimum_distance = 0;
    }

    var point = 0xFFFF & args[args_pos];

    if ((point >= exc.zp1.n_points) || (exc.GS.rp0 >= exc.zp0.n_points))
    {
        if (exc.pedantic_hinting)
            exc.error = 134;

        exc.GS.rp1 = exc.GS.rp0;
        exc.GS.rp2 = point;
        if ((exc.opcode & 16) != 0)
            exc.GS.rp0 = point;
        return;
    }

    /* XXX: Is there some undocumented feature while in the */
    /*      twilight zone?                                  */

    var v1, v2;
    /* XXX: UNDOCUMENTED: twilight zone special case */
    if (exc.GS.gep0 == 0 || exc.GS.gep1 == 0)
    {
        v1 = exc.zp1.org[exc.zp1._offset_org + point];
        v2 = exc.zp0.org[exc.zp0._offset_org + exc.GS.rp0];
        org_dist = exc.func_dualproj(exc, v1.x - v2.x, v1.y - v2.y);
    }
    else
    {
        v1 = exc.zp1.orus[exc.zp1._offset_orus + point];
        v2 = exc.zp0.orus[exc.zp0._offset_orus + exc.GS.rp0];

        if (exc.metrics.x_scale == exc.metrics.y_scale)
        {
            /* this should be faster */
            org_dist = exc.func_dualproj(exc, v1.x - v2.x, v1.y - v2.y);
            org_dist = FT_MulFix(org_dist, exc.metrics.x_scale);
        }
        else
        {
            var _x = FT_MulFix(v1.x - v2.x, exc.metrics.x_scale);
            var _y = FT_MulFix(v1.y - v2.y, exc.metrics.y_scale);
            org_dist = exc.func_dualproj(exc, _x, _y);
        }
    }

    /* single width cut-in test */
    if (Math.abs(org_dist - exc.GS.single_width_value) < exc.GS.single_width_cutin)
    {
        if (org_dist >= 0)
            org_dist = exc.GS.single_width_value;
        else
            org_dist = -exc.GS.single_width_value;
    }

    /* round flag */
    if ((exc.opcode & 4) != 0)
    {
        if (bIsSubpix)
        {
            if (exc.ignore_x_mode && exc.GS.freeVector.x != 0)
                distance = Round_None(exc, org_dist, exc.tt_metrics.compensations[exc.opcode & 3]);
            else
                distance = exc.func_round(exc, org_dist, exc.tt_metrics.compensations[exc.opcode & 3]);
        }
        else
        {
            distance = exc.func_round(exc, org_dist, exc.tt_metrics.compensations[exc.opcode & 3]);
        }
    }
    else
        distance = Round_None(exc, org_dist, exc.tt_metrics.compensations[exc.opcode & 3]);

    /* minimum distance flag */
    if ((exc.opcode & 8) != 0)
    {
        if (org_dist >= 0)
        {
            if (distance < minimum_distance)
                distance = minimum_distance;
        }
        else
        {
            if (distance > -minimum_distance)
                distance = -minimum_distance;
        }
    }

    /* now move the point */
    v1 = exc.zp1.cur[exc.zp1._offset_cur + point];
    v2 = exc.zp0.cur[exc.zp0._offset_cur + exc.GS.rp0];
    org_dist = exc.func_project(exc, v1.x - v2.x, v1.y - v2.y);
    
    exc.func_move(exc, exc.zp1, point, distance - org_dist);

    exc.GS.rp1 = exc.GS.rp0;
    exc.GS.rp2 = point;
    if ((exc.opcode & 16) != 0)
        exc.GS.rp0 = point;
}

function Ins_MIRP(exc, args, args_pos)
{
    var bIsSubpix = exc.face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;

    var minimum_distance    = exc.GS.minimum_distance;
    var control_value_cutin = exc.GS.control_value_cutin;
    var point               = 0xFFFF & args[args_pos];
    var cvtEntry            = FT_Common.IntToUInt(args[args_pos + 1] + 1);
    var distance = 0;

    if (bIsSubpix)
    {
        if (exc.ignore_x_mode && exc.GS.freeVector.x != 0 && (exc.sph_tweak_flags & 256) == 0)
            control_value_cutin = minimum_distance = 0;
    }

    /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
    if ((point >= exc.zp1.n_points) || (cvtEntry >= (exc.cvtSize + 1)) || (exc.GS.rp0 >= exc.zp0.n_points))
    {
        if (exc.pedantic_hinting)
            exc.error = 134;

        exc.GS.rp1 = exc.GS.rp0;
        if ((exc.opcode & 16) != 0)
            exc.GS.rp0 = point;
        exc.GS.rp2 = point;
        return;
    }

    var cvt_dist = 0;
    if (cvtEntry == 0)
        cvt_dist = 0;
    else
        cvt_dist = exc.func_read_cvt(exc, cvtEntry - 1);
        
    /* single width test */
    if (Math.abs(cvt_dist - exc.GS.single_width_value) < exc.GS.single_width_cutin)
    {
        if (cvt_dist >= 0)
            cvt_dist =  exc.GS.single_width_value;
        else
            cvt_dist = -exc.GS.single_width_value;
    }

    /* UNDOCUMENTED!  The MS rasterizer does that with */
    /* twilight points (confirmed by Greg Hitchcock)   */
    if (exc.GS.gep1 == 0)
    {
        var _v = exc.zp0.org[exc.zp0._offset_org + exc.GS.rp0];
        exc.zp1.org[exc.zp1._offset_org + point].x = _v.x + TT_MulFix14(cvt_dist, exc.GS.freeVector.x);
        exc.zp1.org[exc.zp1._offset_org + point].y = _v.y + TT_MulFix14(cvt_dist, exc.GS.freeVector.y);

        copy_vector(exc.zp1.cur[exc.zp1._offset_cur + point], exc.zp1.org[exc.zp1._offset_org + point]);
    }

    var v1 = exc.zp1.org[exc.zp1._offset_org + point];
    var v2 = exc.zp0.org[exc.zp0._offset_org + exc.GS.rp0];

    var org_dist = exc.func_dualproj(exc, v1.x - v2.x, v1.y - v2.y);

    v1 = exc.zp1.cur[exc.zp1._offset_cur + point];
    v2 = exc.zp0.cur[exc.zp0._offset_cur + exc.GS.rp0];

    var cur_dist = exc.func_project(exc, v1.x - v2.x, v1.y - v2.y);

    /* auto-flip test */
    if (exc.GS.auto_flip)
    {
        if ((org_dist ^ cvt_dist) < 0)
            cvt_dist = -cvt_dist;
    }

    if (bIsSubpix) //#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
    {
        if (exc.ignore_x_mode && exc.GS.freeVector.y != 0 && (exc.sph_tweak_flags & 262144) != 0)
        {
            if (cur_dist < -64)
                cvt_dist -= 16;
            else if (cur_dist > 64 && cur_dist < 84)
                cvt_dist += 32;
        }
    } //#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
    /* control value cut-in and round */
    if ((exc.opcode & 4) != 0)
    {
        /* XXX: UNDOCUMENTED!  Only perform cut-in test when both points */
        /*      refer to the same zone.                                  */
        if (exc.GS.gep0 == exc.GS.gep1)
        {
            /* XXX: According to Greg Hitchcock, the following wording is */
            /*      the right one:                                        */
            /*                                                            */
            /*        When the absolute difference between the value in   */
            /*        the table [CVT] and the measurement directly from   */
            /*        the outline is _greater_ than the cut_in value, the */
            /*        outline measurement is used.                        */
            /*                                                            */
            /*      This is from `instgly.doc'.  The description in       */
            /*      `ttinst2.doc', version 1.66, is thus incorrect since  */
            /*      it implies `>=' instead of `>'.                       */

            if (Math.abs(cvt_dist - org_dist) > control_value_cutin)
                cvt_dist = org_dist;
        }

        distance = exc.func_round(exc, cvt_dist, exc.tt_metrics.compensations[exc.opcode & 3]);
    }
    else
    {
        if (bIsSubpix)
        {
            /* do cvt cut-in always in MIRP for sph */
            if (exc.ignore_x_mode && exc.GS.gep0 == exc.GS.gep1)
            {
                if (Math.abs(cvt_dist - org_dist) > control_value_cutin)
                    cvt_dist = org_dist;
            }
        }
        distance = Round_None(exc, cvt_dist, exc.tt_metrics.compensations[exc.opcode & 3]);
    }

    /* minimum distance test */
    if ((exc.opcode & 8) != 0)
    {
        if (org_dist >= 0)
        {
            if (distance < minimum_distance)
                distance = minimum_distance;
        }
        else
        {
            if (distance > -minimum_distance)
                distance = -minimum_distance;
        }
    }

    if (!bIsSubpix)
    {
        exc.func_move(exc, exc.zp1, point, distance - cur_dist);
    }
    else
    {
        var B1 = exc.zp1.cur[exc.zp1._offset_cur + point].y;

        /* Round moves if necessary */
        if (exc.ignore_x_mode && exc.GS.freeVector.y != 0 && (exc.sph_tweak_flags & 16384) != 0)
            distance = FT_PIX_ROUND(B1 + distance - cur_dist) - B1 + cur_dist;

        if (exc.ignore_x_mode && exc.GS.freeVector.y != 0 && (exc.opcode & 16) == 0 && (exc.opcode & 8) == 0 && (exc.sph_tweak_flags & 8) != 0)
            distance += 64;

        exc.func_move(exc, exc.zp1, point, distance - cur_dist);

        var B2 = exc.zp1.cur[exc.zp1._offset_cur + point].y;

        var reverse_move = false;
        /* Reverse move if necessary */
        if (exc.ignore_x_mode)
        {
            if (exc.face.sph_compatibility_mode &&
                exc.GS.freeVector.y != 0 &&
                ( B1 & 63 ) == 0 &&
                ( B2 & 63 ) != 0)
                reverse_move = true;

            if ((exc.sph_tweak_flags & 65536) &&
                exc.GS.freeVector.y != 0 &&
                ( B2 & 63 ) != 0 &&
                ( B1 & 63 ) != 0)
                reverse_move = true;
        }

        if (reverse_move)
            exc.func_move(exc, exc.zp1, point, -(distance - cur_dist));
    }

    exc.GS.rp1 = exc.GS.rp0;
    if ((exc.opcode & 16) != 0)
        exc.GS.rp0 = point;
    exc.GS.rp2 = point;
}

var Instruct_Dispatch =
[
    /* Opcodes are gathered in groups of 16. */
    /* Please keep the spaces as they are.   */

    /*  SVTCA  y  */  Ins_SVTCA,
    /*  SVTCA  x  */  Ins_SVTCA,
    /*  SPvTCA y  */  Ins_SPVTCA,
    /*  SPvTCA x  */  Ins_SPVTCA,
    /*  SFvTCA y  */  Ins_SFVTCA,
    /*  SFvTCA x  */  Ins_SFVTCA,
    /*  SPvTL //  */  Ins_SPVTL,
    /*  SPvTL +   */  Ins_SPVTL,
    /*  SFvTL //  */  Ins_SFVTL,
    /*  SFvTL +   */  Ins_SFVTL,
    /*  SPvFS     */  Ins_SPVFS,
    /*  SFvFS     */  Ins_SFVFS,
    /*  GPV       */  Ins_GPV,
    /*  GFV       */  Ins_GFV,
    /*  SFvTPv    */  Ins_SFVTPV,
    /*  ISECT     */  Ins_ISECT,

    /*  SRP0      */  Ins_SRP0,
    /*  SRP1      */  Ins_SRP1,
    /*  SRP2      */  Ins_SRP2,
    /*  SZP0      */  Ins_SZP0,
    /*  SZP1      */  Ins_SZP1,
    /*  SZP2      */  Ins_SZP2,
    /*  SZPS      */  Ins_SZPS,
    /*  SLOOP     */  Ins_SLOOP,
    /*  RTG       */  Ins_RTG,
    /*  RTHG      */  Ins_RTHG,
    /*  SMD       */  Ins_SMD,
    /*  ELSE      */  Ins_ELSE,
    /*  JMPR      */  Ins_JMPR,
    /*  SCvTCi    */  Ins_SCVTCI,
    /*  SSwCi     */  Ins_SSWCI,
    /*  SSW       */  Ins_SSW,

    /*  DUP       */  Ins_DUP,
    /*  POP       */  Ins_POP,
    /*  CLEAR     */  Ins_CLEAR,
    /*  SWAP      */  Ins_SWAP,
    /*  DEPTH     */  Ins_DEPTH,
    /*  CINDEX    */  Ins_CINDEX,
    /*  MINDEX    */  Ins_MINDEX,
    /*  AlignPTS  */  Ins_ALIGNPTS,
    /*  INS_0x28  */  Ins_UNKNOWN,
    /*  UTP       */  Ins_UTP,
    /*  LOOPCALL  */  Ins_LOOPCALL,
    /*  CALL      */  Ins_CALL,
    /*  FDEF      */  Ins_FDEF,
    /*  ENDF      */  Ins_ENDF,
    /*  MDAP[0]   */  Ins_MDAP,
    /*  MDAP[1]   */  Ins_MDAP,

    /*  IUP[0]    */  Ins_IUP,
    /*  IUP[1]    */  Ins_IUP,
    /*  SHP[0]    */  Ins_SHP,
    /*  SHP[1]    */  Ins_SHP,
    /*  SHC[0]    */  Ins_SHC,
    /*  SHC[1]    */  Ins_SHC,
    /*  SHZ[0]    */  Ins_SHZ,
    /*  SHZ[1]    */  Ins_SHZ,
    /*  SHPIX     */  Ins_SHPIX,
    /*  IP        */  Ins_IP,
    /*  MSIRP[0]  */  Ins_MSIRP,
    /*  MSIRP[1]  */  Ins_MSIRP,
    /*  AlignRP   */  Ins_ALIGNRP,
    /*  RTDG      */  Ins_RTDG,
    /*  MIAP[0]   */  Ins_MIAP,
    /*  MIAP[1]   */  Ins_MIAP,

    /*  NPushB    */  Ins_NPUSHB,
    /*  NPushW    */  Ins_NPUSHW,
    /*  WS        */  Ins_WS,
    /*  RS        */  Ins_RS,
    /*  WCvtP     */  Ins_WCVTP,
    /*  RCvt      */  Ins_RCVT,
    /*  GC[0]     */  Ins_GC,
    /*  GC[1]     */  Ins_GC,
    /*  SCFS      */  Ins_SCFS,
    /*  MD[0]     */  Ins_MD,
    /*  MD[1]     */  Ins_MD,
    /*  MPPEM     */  Ins_MPPEM,
    /*  MPS       */  Ins_MPS,
    /*  FlipON    */  Ins_FLIPON,
    /*  FlipOFF   */  Ins_FLIPOFF,
    /*  DEBUG     */  Ins_DEBUG,

    /*  LT        */  Ins_LT,
    /*  LTEQ      */  Ins_LTEQ,
    /*  GT        */  Ins_GT,
    /*  GTEQ      */  Ins_GTEQ,
    /*  EQ        */  Ins_EQ,
    /*  NEQ       */  Ins_NEQ,
    /*  ODD       */  Ins_ODD,
    /*  EVEN      */  Ins_EVEN,
    /*  IF        */  Ins_IF,
    /*  EIF       */  Ins_EIF,
    /*  AND       */  Ins_AND,
    /*  OR        */  Ins_OR,
    /*  NOT       */  Ins_NOT,
    /*  DeltaP1   */  Ins_DELTAP,
    /*  SDB       */  Ins_SDB,
    /*  SDS       */  Ins_SDS,

    /*  ADD       */  Ins_ADD,
    /*  SUB       */  Ins_SUB,
    /*  DIV       */  Ins_DIV,
    /*  MUL       */  Ins_MUL,
    /*  ABS       */  Ins_ABS,
    /*  NEG       */  Ins_NEG,
    /*  FLOOR     */  Ins_FLOOR,
    /*  CEILING   */  Ins_CEILING,
    /*  ROUND[0]  */  Ins_ROUND,
    /*  ROUND[1]  */  Ins_ROUND,
    /*  ROUND[2]  */  Ins_ROUND,
    /*  ROUND[3]  */  Ins_ROUND,
    /*  NROUND[0] */  Ins_NROUND,
    /*  NROUND[1] */  Ins_NROUND,
    /*  NROUND[2] */  Ins_NROUND,
    /*  NROUND[3] */  Ins_NROUND,

    /*  WCvtF     */  Ins_WCVTF,
    /*  DeltaP2   */  Ins_DELTAP,
    /*  DeltaP3   */  Ins_DELTAP,
    /*  DeltaCn[0] */ Ins_DELTAC,
    /*  DeltaCn[1] */ Ins_DELTAC,
    /*  DeltaCn[2] */ Ins_DELTAC,
    /*  SROUND    */  Ins_SROUND,
    /*  S45Round  */  Ins_S45ROUND,
    /*  JROT      */  Ins_JROT,
    /*  JROF      */  Ins_JROF,
    /*  ROFF      */  Ins_ROFF,
    /*  INS_0x7B  */  Ins_UNKNOWN,
    /*  RUTG      */  Ins_RUTG,
    /*  RDTG      */  Ins_RDTG,
    /*  SANGW     */  Ins_SANGW,
    /*  AA        */  Ins_AA,

    /*  FlipPT    */  Ins_FLIPPT,
    /*  FlipRgON  */  Ins_FLIPRGON,
    /*  FlipRgOFF */  Ins_FLIPRGOFF,
    /*  INS_0x83  */  Ins_UNKNOWN,
    /*  INS_0x84  */  Ins_UNKNOWN,
    /*  ScanCTRL  */  Ins_SCANCTRL,
    /*  SDPVTL[0] */  Ins_SDPVTL,
    /*  SDPVTL[1] */  Ins_SDPVTL,
    /*  GetINFO   */  Ins_GETINFO,
    /*  IDEF      */  Ins_IDEF,
    /*  ROLL      */  Ins_ROLL,
    /*  MAX       */  Ins_MAX,
    /*  MIN       */  Ins_MIN,
    /*  ScanTYPE  */  Ins_SCANTYPE,
    /*  InstCTRL  */  Ins_INSTCTRL,
    /*  INS_0x8F  */  Ins_UNKNOWN,

    /*  INS_0x90  */   Ins_UNKNOWN,
    /*  INS_0x91  */   Ins_UNKNOWN,
    /*  INS_0x92  */   Ins_UNKNOWN,
    /*  INS_0x93  */   Ins_UNKNOWN,
    /*  INS_0x94  */   Ins_UNKNOWN,
    /*  INS_0x95  */   Ins_UNKNOWN,
    /*  INS_0x96  */   Ins_UNKNOWN,
    /*  INS_0x97  */   Ins_UNKNOWN,
    /*  INS_0x98  */   Ins_UNKNOWN,
    /*  INS_0x99  */   Ins_UNKNOWN,
    /*  INS_0x9A  */   Ins_UNKNOWN,
    /*  INS_0x9B  */   Ins_UNKNOWN,
    /*  INS_0x9C  */   Ins_UNKNOWN,
    /*  INS_0x9D  */   Ins_UNKNOWN,
    /*  INS_0x9E  */   Ins_UNKNOWN,
    /*  INS_0x9F  */   Ins_UNKNOWN,

    /*  INS_0xA0  */   Ins_UNKNOWN,
    /*  INS_0xA1  */   Ins_UNKNOWN,
    /*  INS_0xA2  */   Ins_UNKNOWN,
    /*  INS_0xA3  */   Ins_UNKNOWN,
    /*  INS_0xA4  */   Ins_UNKNOWN,
    /*  INS_0xA5  */   Ins_UNKNOWN,
    /*  INS_0xA6  */   Ins_UNKNOWN,
    /*  INS_0xA7  */   Ins_UNKNOWN,
    /*  INS_0xA8  */   Ins_UNKNOWN,
    /*  INS_0xA9  */   Ins_UNKNOWN,
    /*  INS_0xAA  */   Ins_UNKNOWN,
    /*  INS_0xAB  */   Ins_UNKNOWN,
    /*  INS_0xAC  */   Ins_UNKNOWN,
    /*  INS_0xAD  */   Ins_UNKNOWN,
    /*  INS_0xAE  */   Ins_UNKNOWN,
    /*  INS_0xAF  */   Ins_UNKNOWN,

    /*  PushB[0]  */  Ins_PUSHB,
    /*  PushB[1]  */  Ins_PUSHB,
    /*  PushB[2]  */  Ins_PUSHB,
    /*  PushB[3]  */  Ins_PUSHB,
    /*  PushB[4]  */  Ins_PUSHB,
    /*  PushB[5]  */  Ins_PUSHB,
    /*  PushB[6]  */  Ins_PUSHB,
    /*  PushB[7]  */  Ins_PUSHB,
    /*  PushW[0]  */  Ins_PUSHW,
    /*  PushW[1]  */  Ins_PUSHW,
    /*  PushW[2]  */  Ins_PUSHW,
    /*  PushW[3]  */  Ins_PUSHW,
    /*  PushW[4]  */  Ins_PUSHW,
    /*  PushW[5]  */  Ins_PUSHW,
    /*  PushW[6]  */  Ins_PUSHW,
    /*  PushW[7]  */  Ins_PUSHW,

    /*  MDRP[00]  */  Ins_MDRP,
    /*  MDRP[01]  */  Ins_MDRP,
    /*  MDRP[02]  */  Ins_MDRP,
    /*  MDRP[03]  */  Ins_MDRP,
    /*  MDRP[04]  */  Ins_MDRP,
    /*  MDRP[05]  */  Ins_MDRP,
    /*  MDRP[06]  */  Ins_MDRP,
    /*  MDRP[07]  */  Ins_MDRP,
    /*  MDRP[08]  */  Ins_MDRP,
    /*  MDRP[09]  */  Ins_MDRP,
    /*  MDRP[10]  */  Ins_MDRP,
    /*  MDRP[11]  */  Ins_MDRP,
    /*  MDRP[12]  */  Ins_MDRP,
    /*  MDRP[13]  */  Ins_MDRP,
    /*  MDRP[14]  */  Ins_MDRP,
    /*  MDRP[15]  */  Ins_MDRP,

    /*  MDRP[16]  */  Ins_MDRP,
    /*  MDRP[17]  */  Ins_MDRP,
    /*  MDRP[18]  */  Ins_MDRP,
    /*  MDRP[19]  */  Ins_MDRP,
    /*  MDRP[20]  */  Ins_MDRP,
    /*  MDRP[21]  */  Ins_MDRP,
    /*  MDRP[22]  */  Ins_MDRP,
    /*  MDRP[23]  */  Ins_MDRP,
    /*  MDRP[24]  */  Ins_MDRP,
    /*  MDRP[25]  */  Ins_MDRP,
    /*  MDRP[26]  */  Ins_MDRP,
    /*  MDRP[27]  */  Ins_MDRP,
    /*  MDRP[28]  */  Ins_MDRP,
    /*  MDRP[29]  */  Ins_MDRP,
    /*  MDRP[30]  */  Ins_MDRP,
    /*  MDRP[31]  */  Ins_MDRP,

    /*  MIRP[00]  */  Ins_MIRP,
    /*  MIRP[01]  */  Ins_MIRP,
    /*  MIRP[02]  */  Ins_MIRP,
    /*  MIRP[03]  */  Ins_MIRP,
    /*  MIRP[04]  */  Ins_MIRP,
    /*  MIRP[05]  */  Ins_MIRP,
    /*  MIRP[06]  */  Ins_MIRP,
    /*  MIRP[07]  */  Ins_MIRP,
    /*  MIRP[08]  */  Ins_MIRP,
    /*  MIRP[09]  */  Ins_MIRP,
    /*  MIRP[10]  */  Ins_MIRP,
    /*  MIRP[11]  */  Ins_MIRP,
    /*  MIRP[12]  */  Ins_MIRP,
    /*  MIRP[13]  */  Ins_MIRP,
    /*  MIRP[14]  */  Ins_MIRP,
    /*  MIRP[15]  */  Ins_MIRP,

    /*  MIRP[16]  */  Ins_MIRP,
    /*  MIRP[17]  */  Ins_MIRP,
    /*  MIRP[18]  */  Ins_MIRP,
    /*  MIRP[19]  */  Ins_MIRP,
    /*  MIRP[20]  */  Ins_MIRP,
    /*  MIRP[21]  */  Ins_MIRP,
    /*  MIRP[22]  */  Ins_MIRP,
    /*  MIRP[23]  */  Ins_MIRP,
    /*  MIRP[24]  */  Ins_MIRP,
    /*  MIRP[25]  */  Ins_MIRP,
    /*  MIRP[26]  */  Ins_MIRP,
    /*  MIRP[27]  */  Ins_MIRP,
    /*  MIRP[28]  */  Ins_MIRP,
    /*  MIRP[29]  */  Ins_MIRP,
    /*  MIRP[30]  */  Ins_MIRP,
    /*  MIRP[31]  */  Ins_MIRP
];

function TT_RunIns(exc)
{
    var ins_counter = 0;  /* executed instructions counter */

    var _tt_hints = exc.face.driver.library.tt_hint_props;
    if (_tt_hints.TT_CONFIG_OPTION_SUBPIXEL_HINTING) //#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
    {
        exc.iup_called = false;
    }//#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */

    var opcode_pattern = [
        [
            0x06, /* SPVTL   */
            0x7D, /* RDTG    */
        ]
    ];
    var opcode_pointer = [ 0 ];
    var opcode_size    = [ 1 ];

    /* set CVT functions */
    exc.tt_metrics.ratio = 0;
    if (exc.metrics.x_ppem != exc.metrics.y_ppem)
    {
        /* non-square pixels, use the stretched routines */
        exc.func_read_cvt  = Read_CVT_Stretched;
        exc.func_write_cvt = Write_CVT_Stretched;
        exc.func_move_cvt  = Move_CVT_Stretched;
    }
    else
    {
        /* square pixels, use normal routines */
        exc.func_read_cvt  = Read_CVT;
        exc.func_write_cvt = Write_CVT;
        exc.func_move_cvt  = Move_CVT;
    }

    Compute_Funcs(exc);
    Compute_Round(exc, exc.GS.round_state);

    do
    {
        exc.opcode = exc.code.data[exc.code.pos + exc.IP];

        exc.length = opcode_length[exc.opcode];
        if (exc.length < 0)
        {
            if (exc.IP + 1 >= exc.codeSize)
                return SetErrorAndReturn(exc, 131);

            exc.length = 2 - exc.length * exc.code.data[exc.code.pos + exc.IP + 1];
        }

        if (exc.IP + exc.length > exc.codeSize)
            return SetErrorAndReturn(exc, 131);

        /* First, let's check for empty stack and overflow */
        exc.args = exc.top - (Pop_Push_Count[exc.opcode] >> 4);

        /* `args' is the top of the stack once arguments have been popped. */
        /* One can also interpret it as the index of the last argument.    */
        if (exc.args < 0)
        {
            if (exc.pedantic_hinting)
            {
                exc.error = 129;
                return SetErrorAndReturn(exc);
            }

            /* push zeroes onto the stack */
            var __l = Pop_Push_Count[exc.opcode] >> 4;
            for (var i = 0; i < __l; i++)
                exc.stack[i] = 0;
            exc.args = 0;
        }

        exc.new_top = exc.args + (Pop_Push_Count[exc.opcode] & 15);

        /* `new_top' is the new top of the stack, after the instruction's */
        /* execution.  `top' will be set to `new_top' after the `switch'  */
        /* statement.                                                     */
        if (exc.new_top > exc.stackSize)
        {
            exc.error = 130;
            return SetErrorAndReturn(exc);
        }

        exc.step_ins = true;
        exc.error    = 0;

        if (_tt_hints.TT_CONFIG_OPTION_SUBPIXEL_HINTING) //#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
        {
            for (var i_patt = 0; i_patt < opcode_pattern.length; i_patt++)
            {
                if (opcode_pointer[i_patt] < opcode_size[i_patt] &&
                    exc.opcode == opcode_pattern[i_patt][opcode_pointer[i_patt]])
                {
                    opcode_pointer[i_patt] += 1;

                    if ( opcode_pointer[i_patt] == opcode_size[i_patt] )
                    {
                        switch ( i_patt )
                        {
                            case 0:
                                break;
                        }
                        opcode_pointer[i_patt] = 0;
                    }
                }
                else
                    opcode_pointer[i_patt] = 0;
            }
        }//#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */

        Instruct_Dispatch[exc.opcode](exc, exc.stack, exc.args);
 
        var bSuiteLabel = false;
        if (exc.error != 0)
        {
            switch (exc.error)
            {
                case 128: /* looking for redefined instructions */
                {
                    var defs  = exc.IDefs;
                    var limit = exc.numIDefs;

                    for (var def = 0; def < limit; def++)
                    {
                        var _def = defs[def];
                        if (def.active && exc.opcode == def.opc)
                        {
                            if (exc.callTop >= exc.callSize)
                            {
                                exc.error = 134;
                                return SetErrorAndReturn(exc);
                            }

                            var callrec = exc.callStack[exc.callTop];

                            callrec.Caller_Range = exc.curRange;
                            callrec.Caller_IP    = exc.IP + 1;
                            callrec.Cur_Count    = 1;
                            callrec.Def          = _def;

                            if (Ins_Goto_CodeRange(def.range, def.start) == 1)
                                return SetErrorAndReturn(exc);

                            bSuiteLabel = true;
                            break;
                        }
                    }
                }

                if (!bSuiteLabel)
                {
                    exc.error = 128;
                    return SetErrorAndReturn(exc);
                }

            default:
                if (!bSuiteLabel)
                    return SetErrorAndReturn(exc);
            }
        }

        if (!bSuiteLabel)
        {
            exc.top = exc.new_top;

            if (exc.step_ins)
                exc.IP += exc.length;

            /* increment instruction counter and check if we didn't */
            /* run this program for too long (e.g. infinite loops). */
            if (++ins_counter > 1000000)
                return 139;
        }

        if (exc.IP >= exc.codeSize)
        {
            if (exc.callTop > 0)
            {
                exc.error = 131;
                return SetErrorAndReturn(exc);
            }
            else
                return 0;
        }

    } while (!exc.instruction_trap);

    return 0;
}

function SetErrorAndReturn(exc, err)
{
    if (undefined !== err)
        exc.error = err;

    if (exc.error != 0 && !exc.instruction_trap)
    {
        exc.size.cvt_ready = false;
    }

    return exc.error;
}

function Read_CVT(exc, idx)
{
    return exc.cvt[idx];
}

function Read_CVT_Stretched(exc, idx)
{
    return FT_MulFix(exc.cvt[idx], Current_Ratio(exc));
}

function Write_CVT(exc, idx, value)
{
    exc.cvt[idx] = value;
}

function Write_CVT_Stretched(exc, idx, value)
{
    exc.cvt[idx] = FT_DivFix(value, Current_Ratio(exc));
}

function Move_CVT(exc, idx, value)
{
    exc.cvt[idx] += value;
}

function Move_CVT_Stretched(exc, idx, value)
{
    exc.cvt[idx] += FT_DivFix(value, Current_Ratio(exc));
}

/*********************************************************************/
/*********************************************************************/
/*********************************************************************/
/*********************************************************************/
/*********************************************************************/
/*********************************************************************/
function CSubpixHintingHacks()
{
    this.Correct_Init_Obj = function(_class)
    {
        for (var prop in _class)
        {
            if (!_class.hasOwnProperty(prop))
                continue;

            var _arr = _class[prop];
            var _obj = {};

            var _len = _arr.length;
            for (var i = 0; i < _len; i++)
                _obj[_arr[i]] = true;

            _class[prop] = _obj;
        }
    };

    this.FAMILY_CLASS_Rules =
    {
        "MS Legacy Fonts" : [
            "Aharoni",
            "Andale Mono",
            "Andalus",
            "Angsana New",
            "AngsanaUPC",
            "Arabic Transparent",
            "Arial Black",
            "Arial Narrow",
            "Arial Unicode MS",
            "Arial",
            "Batang",
            "Browallia New",
            "BrowalliaUPC",
            "Comic Sans MS",
            "Cordia New",
            "CordiaUPC",
            "Courier New",
            "DFKai-SB",
            "David Transparent",
            "David",
            "DilleniaUPC",
            "Estrangelo Edessa",
            "EucrosiaUPC",
            "FangSong_GB2312",
            "Fixed Miriam Transparent",
            "FrankRuehl",
            "Franklin Gothic Medium",
            "FreesiaUPC",
            "Garamond",
            "Gautami",
            "Georgia",
            "Gulim",
            "Impact",
            "IrisUPC",
            "JasmineUPC",
            "KaiTi_GB2312",
            "KodchiangUPC",
            "Latha",
            "Levenim MT",
            "LilyUPC",
            "Lucida Console",
            "Lucida Sans Unicode",
            "MS Gothic",
            "MS Mincho",
            "MV Boli",
            "Mangal",
            "Marlett",
            "Microsoft Sans Serif",
            "Mingliu",
            "Miriam Fixed",
            "Miriam Transparent",
            "Miriam",
            "Narkisim",
            "Palatino Linotype",
            "Raavi",
            "Rod Transparent",
            "Rod",
            "Shruti",
            "SimHei",
            "Simplified Arabic Fixed",
            "Simplified Arabic",
            "Simsun",
            "Sylfaen",
            "Symbol",
            "Tahoma",
            "Times New Roman",
            "Traditional Arabic",
            "Trebuchet MS",
            "Tunga",
            "Verdana",
            "Webdings",
            "Wingdings"
        ],
        "Core MS Legacy Fonts" : [
            "Arial Black",
            "Arial Narrow",
            "Arial Unicode MS",
            "Arial",
            "Comic Sans MS",
            "Courier New",
            "Garamond",
            "Georgia",
            "Impact",
            "Lucida Console",
            "Lucida Sans Unicode",
            "Microsoft Sans Serif",
            "Palatino Linotype",
            "Tahoma",
            "Times New Roman",
            "Trebuchet MS",
            "Verdana"
        ],
        "Apple Legacy Fonts" : [
            "Geneva",
            "Times",
            "Monaco",
            "Century",
            "Chalkboard",
            "Lobster",
            "Century Gothic",
            "Optima",
            "Lucida Grande",
            "Gill Sans",
            "Baskerville",
            "Helvetica",
            "Helvetica Neue"
        ],
        "Legacy Sans Fonts" : [
            "Andale Mono",
            "Arial Unicode MS",
            "Arial",
            "Century Gothic",
            "Comic Sans MS",
            "Franklin Gothic Medium",
            "Geneva",
            "Lucida Console",
            "Lucida Grande",
            "Lucida Sans Unicode",
            "Lucida Sans Typewriter",
            "Microsoft Sans Serif",
            "Monaco",
            "Tahoma",
            "Trebuchet MS",
            "Verdana"
        ],
        "Misc Legacy Fonts" : [
            "Dark Courier"
        ],
        "Verdana Clones" : [
            "DejaVu Sans",
            "Bitstream Vera Sans"
        ],
        "Verdana and Clones" : [
            "DejaVu Sans",
            "Bitstream Vera Sans",
            "Verdana"
        ]
    };

    this.Correct_Init_Obj(this.FAMILY_CLASS_Rules);

    this.STYLE_CLASS_Rules =
    {
        "Regular Class" : [
            "Regular",
            "Book",
            "Medium",
            "Roman",
            "Normal"
        ],
        "Regular/Italic Class" : [
            "Regular",
            "Book",
            "Medium",
            "Italic",
            "Oblique",
            "Roman",
            "Normal"
        ],
        "Bold/BoldItalic Class" : [
            "Bold",
            "Bold Italic",
            "Black"
        ],
        "Bold/Italic/BoldItalic Class" : [
            "Bold",
            "Bold Italic",
            "Black",
            "Italic",
            "Oblique"
        ],
        "Regular/Bold Class" : [
            "Regular",
            "Book",
            "Medium",
            "Normal",
            "Roman",
            "Bold",
            "Black"
        ]
    };

    this.Correct_Init_Obj(this.STYLE_CLASS_Rules);

    /***************************************************************/
    /***************************************************************/
    /***************************************************************/
    this._create_SPH_TweakRule = function(family, ppem, style, glyph)
    {
        var _ret = new SPH_TweakRule();
        _ret.family = family;
        _ret.ppem = ppem;
        _ret.style = style;
        _ret.glyph = glyph;
        return _ret;
    };
    this._create_SPH_ScaleRule = function(family, ppem, style, glyph, scale)
    {
        var _ret = new SPH_ScaleRule();
        _ret.family = family;
        _ret.ppem = ppem;
        _ret.style = style;
        _ret.glyph = glyph;
        _ret.scale = scale;
        return _ret;
    };

    /* Force special legacy fixes for fonts.                                 */
    this.COMPATIBILITY_MODE_Rules = [
        this._create_SPH_TweakRule("-", 0, "", 0)
    ];

    /* Don't do subpixel (ignore_x_mode) hinting; do normal hinting.         */
    this.PIXEL_HINTING_Rules = [
        /* these characters are almost always safe */
        this._create_SPH_TweakRule("Courier New", 12, "Italic", "z".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 11, "Italic", "z".charCodeAt(0))
    ];

    /* Subpixel hinting ignores SHPIX rules on X.  Force SHPIX for these.    */
    this.DO_SHPIX_Rules = [
        this._create_SPH_TweakRule("-", 0, "", 0)
    ];

    /* Skip Y moves that start with a point that is not on a Y pixel         */
    /* boundary and don't move that point to a Y pixel boundary.             */
    this.SKIP_NONPIXEL_Y_MOVES_Rules = [
        /* fix vwxyz thinness*/
        this._create_SPH_TweakRule("Consolas", 0, "", 0),
        /* Fix thin middle stems */
        this._create_SPH_TweakRule("Core MS Legacy Fonts", 0, "Regular", 0),
        /* Cyrillic small letter I */
        this._create_SPH_TweakRule("Legacy Sans Fonts", 0, "", 0),
        /* Fix artifacts with some Regular & Bold */
        this._create_SPH_TweakRule("Verdana Clones", 0, "", 0)
    ];

    this.SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions = [
        /* Fixes < and > */
        this._create_SPH_TweakRule("Courier New", 0, "Regular", 0)
    ];

    this.SKIP_NONPIXEL_Y_MOVES_DELTAP_Rules = [
        /* Maintain thickness of diagonal in 'N' */
        this._create_SPH_TweakRule("Times New Roman", 0, "Regular/Bold Class", "N".charCodeAt(0)),
        this._create_SPH_TweakRule("Georgia", 0, "Regular/Bold Class", "N".charCodeAt(0))
    ];

    /* Skip Y moves that move a point off a Y pixel boundary.                */
    this.SKIP_OFFPIXEL_Y_MOVES_Rules = [
        this._create_SPH_TweakRule("-", 0, "", 0)
    ];

    this.SKIP_OFFPIXEL_Y_MOVES_Rules_Exceptions = [
        this._create_SPH_TweakRule("-", 0, "", 0)
    ];

    /* Round moves that don't move a point to a Y pixel boundary.            */
    this.ROUND_NONPIXEL_Y_MOVES_Rules = [
        /* Droid font instructions don't snap Y to pixels */
        this._create_SPH_TweakRule("Droid Sans", 0, "Regular/Italic Class", 0),
        this._create_SPH_TweakRule("Droid Sans Mono", 0, "", 0)
    ];

    this.ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions = [
        this._create_SPH_TweakRule("-", 0, "", 0)
    ];

    /* Allow a Direct_Move along X freedom vector if matched.                */
    this.ALLOW_X_DMOVE_Rules = [
        /* Fixes vanishing diagonal in 4 */
        this._create_SPH_TweakRule("Verdana", 0, "Regular", "4".charCodeAt(0))
    ];

    this.RASTERIZER_35_Rules = [
        /* This seems to be the only way to make these look good */
        this._create_SPH_TweakRule("Times New Roman", 0, "Regular", "i".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 0, "Regular", "j".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 0, "Regular", "m".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 0, "Regular", "r".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 0, "Regular", "a".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 0, "Regular", "n".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 0, "Regular", "p".charCodeAt(0)),
        this._create_SPH_TweakRule("Times", 0, "", 0)
    ];

    /* Don't round to the subpixel grid.  Round to pixel grid.               */
    this.NORMAL_ROUND_Rules = [
        /* Fix serif thickness for certain ppems */
        /* Can probably be generalized somehow   */
        this._create_SPH_TweakRule("Courier New", 0, "", 0)
    ];

    /* Skip IUP instructions if matched.                                     */
    this.SKIP_IUP_Rules = [
        this._create_SPH_TweakRule("Arial", 13, "Regular", "a".charCodeAt(0))
    ];

    /* Skip MIAP Twilight hack if matched.                                   */
    this.MIAP_HACK_Rules = [
        this._create_SPH_TweakRule("Geneva", 12, "", 0)
    ];

    /* Skip DELTAP instructions if matched.                                  */
    this.ALWAYS_SKIP_DELTAP_Rules = [
        this._create_SPH_TweakRule("Georgia", 0, "Regular", "k".charCodeAt(0)),
        /* fix various problems with e in different versions */
        this._create_SPH_TweakRule("Trebuchet MS", 14, "Regular", "e".charCodeAt(0)),
        this._create_SPH_TweakRule("Trebuchet MS", 13, "Regular", "e".charCodeAt(0)),
        this._create_SPH_TweakRule("Trebuchet MS", 15, "Regular", "e".charCodeAt(0)),
        this._create_SPH_TweakRule("Trebuchet MS", 0, "Italic", "v".charCodeAt(0)),
        this._create_SPH_TweakRule("Trebuchet MS", 0, "Italic", "w".charCodeAt(0)),
        this._create_SPH_TweakRule("Trebuchet MS", 0, "Regular", "Y".charCodeAt(0)),
        this._create_SPH_TweakRule("Arial", 11, "Regular", "s".charCodeAt(0)),
        /* prevent problems with '3' and others */
        this._create_SPH_TweakRule("Verdana", 10, "Regular", 0),
        this._create_SPH_TweakRule("Verdana", 9, "Regular", 0),
        /* Cyrillic small letter short I */
        this._create_SPH_TweakRule("Legacy Sans Fonts", 0, "", 0x438),
        this._create_SPH_TweakRule("Legacy Sans Fonts", 0, "", 0x439),
        this._create_SPH_TweakRule("Arial", 10, "Regular", "6".charCodeAt(0)),
        this._create_SPH_TweakRule("Arial", 0, "Bold/BoldItalic Class", "a".charCodeAt(0)),
        /* Make horizontal stems consistent with the rest */
        this._create_SPH_TweakRule("Arial", 24, "Bold", "a".charCodeAt(0)),
        this._create_SPH_TweakRule("Arial", 25, "Bold", "a".charCodeAt(0)),
        this._create_SPH_TweakRule("Arial", 24, "Bold", "s".charCodeAt(0)),
        this._create_SPH_TweakRule("Arial", 25, "Bold", "s".charCodeAt(0)),
        this._create_SPH_TweakRule("Arial", 34, "Bold", "s".charCodeAt(0)),
        this._create_SPH_TweakRule("Arial", 35, "Bold", "s".charCodeAt(0)),
        this._create_SPH_TweakRule("Arial", 36, "Bold", "s".charCodeAt(0)),
        this._create_SPH_TweakRule("Arial", 25, "Regular", "s".charCodeAt(0)),
        this._create_SPH_TweakRule("Arial", 26, "Regular", "s".charCodeAt(0))
    ];

    /* Always do DELTAP instructions if matched.                             */
    this.ALWAYS_DO_DELTAP_Rules = [
        this._create_SPH_TweakRule("-", 0, "", 0)
    ];

    /* Don't allow ALIGNRP after IUP.                                        */
    this.NO_ALIGNRP_AFTER_IUP_Rules = [
        /* Prevent creation of dents in outline */
        this._create_SPH_TweakRule("-", 0, "", 0)
    ];

    /* Don't allow DELTAP after IUP.                                         */
    this.NO_DELTAP_AFTER_IUP_Rules = [
        this._create_SPH_TweakRule("-", 0, "", 0)
    ];

    /* Don't allow CALL after IUP.                                           */
    this.NO_CALL_AFTER_IUP_Rules = [
        /* Prevent creation of dents in outline */
        this._create_SPH_TweakRule("-", 0, "", 0)
    ];

    /* De-embolden these glyphs slightly.                                    */
    this.DEEMBOLDEN_Rules = [
        this._create_SPH_TweakRule("Courier New", 0, "Bold", "A".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 0, "Bold", "W".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 0, "Bold", "w".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 0, "Bold", "M".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 0, "Bold", "X".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 0, "Bold", "K".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 0, "Bold", "x".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 0, "Bold", "z".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 0, "Bold", "v".charCodeAt(0))
    ];

    /* Embolden these glyphs slightly.                                       */
    this.EMBOLDEN_Rules = [
        this._create_SPH_TweakRule("Courier New", 0, "Regular", 0),
        this._create_SPH_TweakRule("Courier New", 0, "Italic", 0)
    ];

    /* This is a CVT hack that makes thick horizontal stems on 2, 5, 7       */
    /* similar to Windows XP.                                                */
    this.TIMES_NEW_ROMAN_HACK_Rules = [
        this._create_SPH_TweakRule("Times New Roman", 16, "Italic", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 16, "Italic", "5".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 16, "Italic", "7".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 16, "Regular", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 16, "Regular", "5".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 16, "Regular", "7".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 17, "Italic", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 17, "Italic", "5".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 17, "Italic", "7".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 17, "Regular", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 17, "Regular", "5".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 17, "Regular", "7".charCodeAt(0))
    ];

    /* This fudges distance on 2 to get rid of the vanishing stem issue.     */
    /* A real solution to this is certainly welcome.                         */
    this.COURIER_NEW_2_HACK_Rules = [
        this._create_SPH_TweakRule("Courier New", 10, "Regular", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 11, "Regular", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 12, "Regular", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 13, "Regular", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 14, "Regular", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 15, "Regular", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 16, "Regular", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 17, "Regular", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 18, "Regular", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 19, "Regular", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 20, "Regular", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 21, "Regular", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 22, "Regular", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 23, "Regular", "2".charCodeAt(0)),
        this._create_SPH_TweakRule("Courier New", 24, "Regular", "2".charCodeAt(0))
    ];


    this.FORCE_NATURAL_WIDTHS = false;

    /* Use compatible widths with these glyphs.  Compatible widths is always */
    /* on when doing B/W TrueType instructing, but is used selectively here, */
    /* typically on glyphs with 3 or more vertical stems.                    */
    this.COMPATIBLE_WIDTHS_Rules = [
        this._create_SPH_TweakRule("Arial Unicode MS", 12, "Regular Class", "m".charCodeAt(0)),
        this._create_SPH_TweakRule("Arial Unicode MS", 14, "Regular Class", "m".charCodeAt(0)),
        /* Cyrillic small letter sha */
        this._create_SPH_TweakRule("Arial", 10, "Regular Class", 0x448),
        this._create_SPH_TweakRule("Arial", 11, "Regular Class", "m".charCodeAt(0)),
        this._create_SPH_TweakRule("Arial", 12, "Regular Class", "m".charCodeAt(0)),
        /* Cyrillic small letter sha */
        this._create_SPH_TweakRule("Arial", 12, "Regular Class", 0x448),
        this._create_SPH_TweakRule("Arial", 13, "Regular Class", 0x448),
        this._create_SPH_TweakRule("Arial", 14, "Regular Class", "m".charCodeAt(0)),
        /* Cyrillic small letter sha */
        this._create_SPH_TweakRule("Arial", 14, "Regular Class", 0x448),
        this._create_SPH_TweakRule("Arial", 15, "Regular Class", 0x448),
        this._create_SPH_TweakRule("Arial", 17, "Regular Class", "m".charCodeAt(0)),
        this._create_SPH_TweakRule("DejaVu Sans", 15, "Regular Class", 0),
        this._create_SPH_TweakRule("Microsoft Sans Serif", 11, "Regular Class", 0),
        this._create_SPH_TweakRule("Microsoft Sans Serif", 12, "Regular Class", 0),
        this._create_SPH_TweakRule("Segoe UI", 11, "Regular Class", 0),
        this._create_SPH_TweakRule("Monaco", 0, "Regular Class", 0),
        this._create_SPH_TweakRule("Segoe UI", 12, "Regular Class", "m".charCodeAt(0)),
        this._create_SPH_TweakRule("Segoe UI", 14, "Regular Class", "m".charCodeAt(0)),
        this._create_SPH_TweakRule("Tahoma", 11, "Regular Class", 0),
        this._create_SPH_TweakRule("Times New Roman", 16, "Regular Class", "c".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 16, "Regular Class", "m".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 16, "Regular Class", "o".charCodeAt(0)),
        this._create_SPH_TweakRule("Times New Roman", 16, "Regular Class", "w".charCodeAt(0)),
        this._create_SPH_TweakRule("Trebuchet MS", 11, "Regular Class", 0),
        this._create_SPH_TweakRule("Trebuchet MS", 12, "Regular Class", 0),
        this._create_SPH_TweakRule("Trebuchet MS", 14, "Regular Class", 0),
        this._create_SPH_TweakRule("Trebuchet MS", 15, "Regular Class", 0),
        this._create_SPH_TweakRule("Ubuntu", 12, "Regular Class", "m".charCodeAt(0)),
        /* Cyrillic small letter sha */
        this._create_SPH_TweakRule("Verdana", 10, "Regular Class", 0x448),
        this._create_SPH_TweakRule("Verdana", 11, "Regular Class", 0x448),
        this._create_SPH_TweakRule("Verdana and Clones", 12, "Regular Class", "i".charCodeAt(0)),
        this._create_SPH_TweakRule("Verdana and Clones", 12, "Regular Class", "j".charCodeAt(0)),
        this._create_SPH_TweakRule("Verdana and Clones", 12, "Regular Class", "l".charCodeAt(0)),
        this._create_SPH_TweakRule("Verdana and Clones", 12, "Regular Class", "m".charCodeAt(0)),
        this._create_SPH_TweakRule("Verdana and Clones", 13, "Regular Class", "i".charCodeAt(0)),
        this._create_SPH_TweakRule("Verdana and Clones", 13, "Regular Class", "j".charCodeAt(0)),
        this._create_SPH_TweakRule("Verdana and Clones", 13, "Regular Class", "l".charCodeAt(0)),
        this._create_SPH_TweakRule("Verdana and Clones", 14, "Regular Class", "m".charCodeAt(0))
    ];


    /* Scaling slightly in the x-direction prior to hinting results in       */
    /* more visually pleasing glyphs in certain cases.                       */
    /* This sometimes needs to be coordinated with compatible width rules.   */
    /* A value of 1000 corresponds to a scaled value of 1.0.                 */
    this.X_SCALING_Rules = [
        this._create_SPH_ScaleRule("DejaVu Sans", 12, "Regular Class", "m".charCodeAt(0), 950),
        this._create_SPH_ScaleRule("Verdana and Clones", 12, "Regular Class", "a".charCodeAt(0), 1100),
        this._create_SPH_ScaleRule("Verdana and Clones", 13, "Regular Class", "a".charCodeAt(0), 1050),
        this._create_SPH_ScaleRule("Arial", 11, "Regular Class", "m".charCodeAt(0), 975),
        this._create_SPH_ScaleRule("Arial", 12, "Regular Class", "m".charCodeAt(0), 1050),
        /* Cyrillic small letter el */
        this._create_SPH_ScaleRule("Arial", 13, "Regular Class", 0x43B, 950),
        this._create_SPH_ScaleRule("Arial", 13, "Regular Class", "o".charCodeAt(0), 950),
        this._create_SPH_ScaleRule("Arial", 13, "Regular Class", "e".charCodeAt(0), 950),
        this._create_SPH_ScaleRule("Arial", 14, "Regular Class", "m".charCodeAt(0), 950),
        /* Cyrillic small letter el */
        this._create_SPH_ScaleRule("Arial", 15, "Regular Class", 0x43B, 925),
        this._create_SPH_ScaleRule("Bitstream Vera Sans", 10, "Regular/Italic Class", 0, 1100),
        this._create_SPH_ScaleRule("Bitstream Vera Sans", 12, "Regular/Italic Class", 0, 1050),
        this._create_SPH_ScaleRule("Bitstream Vera Sans", 16, "Regular Class", 0, 1050),
        this._create_SPH_ScaleRule("Bitstream Vera Sans", 9, "Regular/Italic Class", 0, 1050),
        this._create_SPH_ScaleRule("DejaVu Sans", 12, "Regular Class", "l".charCodeAt(0), 975),
        this._create_SPH_ScaleRule("DejaVu Sans", 12, "Regular Class", "i".charCodeAt(0), 975),
        this._create_SPH_ScaleRule("DejaVu Sans", 12, "Regular Class", "j".charCodeAt(0), 975),
        this._create_SPH_ScaleRule("DejaVu Sans", 13, "Regular Class", "l".charCodeAt(0), 950),
        this._create_SPH_ScaleRule("DejaVu Sans", 13, "Regular Class", "i".charCodeAt(0), 950),
        this._create_SPH_ScaleRule("DejaVu Sans", 13, "Regular Class", "j".charCodeAt(0), 950),
        this._create_SPH_ScaleRule("DejaVu Sans", 10, "Regular/Italic Class", 0, 1100),
        this._create_SPH_ScaleRule("DejaVu Sans", 12, "Regular/Italic Class", 0, 1050),
        this._create_SPH_ScaleRule("Georgia", 10, "", 0, 1050),
        this._create_SPH_ScaleRule("Georgia", 11, "", 0, 1100),
        this._create_SPH_ScaleRule("Georgia", 12, "", 0, 1025),
        this._create_SPH_ScaleRule("Georgia", 13, "", 0, 1050),
        this._create_SPH_ScaleRule("Georgia", 16, "", 0, 1050),
        this._create_SPH_ScaleRule("Georgia", 17, "", 0, 1030),
        this._create_SPH_ScaleRule("Liberation Sans", 12, "Regular Class", "m".charCodeAt(0), 1100),
        this._create_SPH_ScaleRule("Lucida Grande", 11, "Regular Class", "m".charCodeAt(0), 1100),
        this._create_SPH_ScaleRule("Microsoft Sans Serif", 11, "Regular Class", "m".charCodeAt(0), 950),
        this._create_SPH_ScaleRule("Microsoft Sans Serif", 12, "Regular Class", "m".charCodeAt(0), 1050),
        this._create_SPH_ScaleRule("Segoe UI", 12, "Regular Class", "H".charCodeAt(0), 1050),
        this._create_SPH_ScaleRule("Segoe UI", 12, "Regular Class", "m".charCodeAt(0), 1050),
        this._create_SPH_ScaleRule("Segoe UI", 14, "Regular Class", "m".charCodeAt(0), 1050),
        this._create_SPH_ScaleRule("Tahoma", 11, "Regular Class", "i".charCodeAt(0), 975),
        this._create_SPH_ScaleRule("Tahoma", 11, "Regular Class", "l".charCodeAt(0), 975),
        this._create_SPH_ScaleRule("Tahoma", 11, "Regular Class", "j".charCodeAt(0), 900),
        this._create_SPH_ScaleRule("Tahoma", 11, "Regular Class", "m".charCodeAt(0), 918),
        this._create_SPH_ScaleRule("Verdana", 10, "Regular/Italic Class", 0, 1100),
        this._create_SPH_ScaleRule("Verdana", 12, "Regular Class", "m".charCodeAt(0), 975),
        this._create_SPH_ScaleRule("Verdana", 12, "Regular/Italic Class", 0, 1050),
        this._create_SPH_ScaleRule("Verdana", 13, "Regular/Italic Class", "i".charCodeAt(0), 950),
        this._create_SPH_ScaleRule("Verdana", 13, "Regular/Italic Class", "j".charCodeAt(0), 950),
        this._create_SPH_ScaleRule("Verdana", 13, "Regular/Italic Class", "l".charCodeAt(0), 950),
        this._create_SPH_ScaleRule("Verdana", 16, "Regular Class", 0, 1050),
        this._create_SPH_ScaleRule("Verdana", 9, "Regular/Italic Class", 0, 1050),
        this._create_SPH_ScaleRule("Times New Roman", 16, "Regular Class", "m".charCodeAt(0), 918),
        this._create_SPH_ScaleRule("Trebuchet MS", 11, "Regular Class", "m".charCodeAt(0), 800),
        this._create_SPH_ScaleRule("Trebuchet MS", 12, "Regular Class", "m".charCodeAt(0), 800)
    ];

    /*
    this.COMPATIBLE_WIDTHS_Rules = [
        this._create_SPH_TweakRule("-", 0, "", 0)
    ];

    this.X_SCALING_Rules = [
        this._create_SPH_ScaleRule("-", 0, "", 0, 1000)
    ];
    */

    this.TWEAK_RULES = function(_loader, _glyph_index, _rules, _flag)
    {
        var face = _loader.face;
        if (this.sph_test_tweak(face, face.family_name, _loader.size.metrics.x_ppem, face.style_name, _glyph_index, _rules, _rules.length))
            _loader.exec.sph_tweak_flags |= _flag;
    };
    this.TWEAK_RULES_EXCEPTIONS = function(_loader, _glyph_index, _rules, _flag)
    {
        var face = _loader.face;
        if (this.sph_test_tweak(face, face.family_name, _loader.size.metrics.x_ppem, face.style_name, _glyph_index, _rules, _rules.length))
            _loader.exec.sph_tweak_flags &= ~_flag;
    };

    this.is_member_of_family_class = function(detected_font_name, rule_font_name)
    {
        /* Does font name match rule family? */
        if (detected_font_name == rule_font_name)
            return true;

        /* Is font name a wildcard ""? */
        if (rule_font_name == "")
            return true;

        var _fcr = this.FAMILY_CLASS_Rules[rule_font_name];
        if (undefined !== _fcr)
        {
            if (undefined !== _fcr[detected_font_name])
                return true;
        }

        return false;
    };

    this.is_member_of_style_class = function(detected_font_style, rule_font_style)
    {
        /* Does font style match rule style? */
        if (detected_font_style == rule_font_style)
            return true;

        /* Is font style a wildcard ""? */
        if (rule_font_style == "")
            return true;

        /* Is font style contained in a class list? */
        var _scr = this.STYLE_CLASS_Rules[rule_font_style];
        if (undefined !== _scr)
        {
            if (undefined !== _scr[detected_font_style])
                return true;
        }

        return false;
    };

    this.sph_test_tweak = function(face, family, ppem, style, glyph_index, rule, num_rules)
    {
        /* rule checks may be able to be optimized further */
        for (var i = 0; i < num_rules; i++)
        {
            if (family != "" && this.is_member_of_family_class(family, rule[i].family))
            {
                if (rule[i].ppem == 0 || rule[i].ppem == ppem)
                {
                    if (style != "" && this.is_member_of_style_class(style, rule[i].style))
                    {
                        if (rule[i].glyph == 0 || FT_Get_Char_Index(face, rule[i].glyph) == glyph_index)
                            return true;
                    }
                }
            }
        }
        return false;
    };

    this.scale_test_tweak = function(face, family, ppem, style, glyph_index, rule, num_rules)
    {
        /* rule checks may be able to be optimized further */
        for (var i = 0; i < num_rules; i++)
        {
            if (family != "" && this.is_member_of_family_class(family, rule[i].family))
            {
                if (rule[i].ppem == 0 || rule[i].ppem == ppem)
                {
                    if (style != "" && this.is_member_of_style_class(style, rule[i].style))
                    {
                        if (rule[i].glyph == 0 || FT_Get_Char_Index(face, rule[i].glyph) == glyph_index)
                            return rule[i].scale;
                    }
                }
            }
        }
        return 1000;
    };

    this.sph_test_tweak_x_scaling = function(face, family, ppem, style, glyph_index)
    {
        return this.scale_test_tweak(face, family, ppem, style, glyph_index, this.X_SCALING_Rules, this.X_SCALING_Rules.length);
    };

    this.sph_set_tweaks = function(loader, glyph_index)
    {
        var face = loader.face;

        /* don't apply rules if style isn't set */
        if (face.style_name == "")
            return;

        this.TWEAK_RULES(loader, glyph_index, this.PIXEL_HINTING_Rules, 4096);

        if (loader.exec.sph_tweak_flags & 4096)
        {
            loader.exec.ignore_x_mode = false;
            return;
        }

        this.TWEAK_RULES(loader, glyph_index, this.ALLOW_X_DMOVE_Rules, 1);
        this.TWEAK_RULES(loader, glyph_index, this.ALWAYS_DO_DELTAP_Rules, 2);
        this.TWEAK_RULES(loader, glyph_index, this.ALWAYS_SKIP_DELTAP_Rules, 4);
        this.TWEAK_RULES(loader, glyph_index, this.DEEMBOLDEN_Rules, 16);
        this.TWEAK_RULES(loader, glyph_index, this.DO_SHPIX_Rules, 32);
        this.TWEAK_RULES(loader, glyph_index, this.EMBOLDEN_Rules, 64);
        this.TWEAK_RULES(loader, glyph_index, this.MIAP_HACK_Rules, 128);
        this.TWEAK_RULES(loader, glyph_index, this.NORMAL_ROUND_Rules, 256);
        this.TWEAK_RULES(loader, glyph_index, this.NO_ALIGNRP_AFTER_IUP_Rules, 512);
        this.TWEAK_RULES(loader, glyph_index, this.NO_CALL_AFTER_IUP_Rules, 1024);
        this.TWEAK_RULES(loader, glyph_index, this.NO_DELTAP_AFTER_IUP_Rules, 2048);
        this.TWEAK_RULES(loader, glyph_index, this.RASTERIZER_35_Rules, 8192);
        this.TWEAK_RULES(loader, glyph_index, this.SKIP_IUP_Rules, 32768);

        this.TWEAK_RULES(loader, glyph_index, this.SKIP_OFFPIXEL_Y_MOVES_Rules, 131072);
        this.TWEAK_RULES_EXCEPTIONS(loader, glyph_index, this.SKIP_OFFPIXEL_Y_MOVES_Rules_Exceptions, 131072);

        this.TWEAK_RULES(loader, glyph_index, this.SKIP_NONPIXEL_Y_MOVES_DELTAP_Rules, 524288);

        this.TWEAK_RULES(loader, glyph_index, this.SKIP_NONPIXEL_Y_MOVES_Rules, 65536);
        this.TWEAK_RULES_EXCEPTIONS(loader, glyph_index, this.SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions, 65536);

        this.TWEAK_RULES(loader, glyph_index, this.ROUND_NONPIXEL_Y_MOVES_Rules, 16384);
        this.TWEAK_RULES_EXCEPTIONS(loader, glyph_index, this.ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions, 16384);

        if (loader.exec.sph_tweak_flags & 8192)
        {
            if (loader.exec.rasterizer_version != 35)
            {
                loader.exec.rasterizer_version  = 35;
                loader.exec.size.cvt_ready      = false;

                tt_size_ready_bytecode(loader.exec.size, (loader.load_flags & 128) != 0);
            }
            else
                loader.exec.rasterizer_version  = 35;
        }
        else
        {
            if (loader.exec.rasterizer_version != 38)
            {
                loader.exec.rasterizer_version  = 38;
                loader.exec.size.cvt_ready      = false;

                tt_size_ready_bytecode(loader.exec.size, (loader.load_flags & 128) != 0);
            }
            else
                loader.exec.rasterizer_version = 38;
        }

        if ((loader.load_flags & 2) == 0)
        {
            this.TWEAK_RULES(loader, glyph_index, this.TIMES_NEW_ROMAN_HACK_Rules, 262144);
            this.TWEAK_RULES(loader, glyph_index, this.COURIER_NEW_2_HACK_Rules, 8);
        }

        if (this.sph_test_tweak(face, face.family_name, loader.size.metrics.x_ppem, face.style_name, glyph_index, this.COMPATIBILITY_MODE_Rules, this.COMPATIBILITY_MODE_Rules.length))
            loader.exec.face.sph_compatibility_mode = true;

        if (((loader.load_flags & 2) == 0) && !loader.exec.compatible_widths)
        {
            if (this.sph_test_tweak(face, face.family_name, loader.size.metrics.x_ppem, face.style_name, glyph_index, this.COMPATIBLE_WIDTHS_Rules, this.COMPATIBLE_WIDTHS_Rules.length))
                loader.exec.face.sph_compatibility_mode = true;
        }
    };
}

var global_SubpixHintingHacks = new CSubpixHintingHacks();
/******************************************************************************/
// classes
/******************************************************************************/
function TT_Size_Metrics()
{
    this.x_ratio = 0;
    this.y_ratio = 0;

    this.ppem   = 0;
    this.ratio  = 0;
    this.scale  = 0;

    this.compensations = new Array(4);

    this.valid = 0;

    this.rotated = 0;
    this.stretched = 0;
}
TT_Size_Metrics.prototype =
{
    Copy : function(src)
    {
        this.x_ratio = src.x_ratio;
        this.y_ratio = src.y_ratio;

        this.ppem   = src.ppem;
        this.ratio  = src.ratio;
        this.scale  = src.scale;

        this.compensations[0] = src.compensations[0];
        this.compensations[1] = src.compensations[1];
        this.compensations[2] = src.compensations[2];
        this.compensations[3] = src.compensations[3];

        this.valid = src.valid;

        this.rotated = src.rotated;
        this.stretched = src.stretched;
    }
};

function TT_DefRecord()
{
    this.range  = 0;        /* in which code range is it located?     */
    this.start  = 0;        /* where does it start?                   */
    this.end    = 0;          /* where does it end?                     */
    this.opc    = 0;          /* function #, or instruction code        */
    this.active = false;       /* is it active?                          */
    this.inline_delta = false; /* is function that defines inline delta? */
}

function TT_CodeRange()
{
    this.base = null;
    this.size = 0;
}

function TT_SizeRec()
{
    this.face = null;
    this.generic = null;
    this.metrics = new FT_Size_Metrics();
    this.internal = null;

    /* we have our own copy of metrics so that we can modify */
    /* it without affecting auto-hinting (when used)         */
    this._metrics = new FT_Size_Metrics();

    this.ttmetrics = new TT_Size_Metrics();

    this.strike_index = 0;
    //#ifdef TT_USE_BYTECODE_INTERPRETER
    this.num_function_defs = 0; /* number of function definitions */
    this.max_function_defs = 0;
    this.function_defs = null;     /* table of function definitions  */

    this.num_instruction_defs = 0;  /* number of ins. definitions */
    this.max_instruction_defs = 0;
    this.instruction_defs =  null;      /* table of ins. definitions  */

    this.max_func = 0;
    this.max_ins = 0;

    this.codeRangeTable = new Array(3);
    this.codeRangeTable[0] = new TT_CodeRange();
    this.codeRangeTable[1] = new TT_CodeRange();
    this.codeRangeTable[2] = new TT_CodeRange();

    this.GS = new TT_GraphicsState();

    this.cvt_size = 0;      /* the scaled control value table */
    this.cvt = null;

    this.storage_size = 0; /* The storage area is now part of */
    this.storage = null;      /* the instance                    */

    this.twilight = new TT_GlyphZoneRec();     /* The instance's twilight zone    */

    /* debugging variables */

    /* When using the debugger, we must keep the */
    /* execution context tied to the instance    */
    /* object rather than asking it on demand.   */
    this.debug = false;
    this.context = null;

    this.bytecode_ready = false;
    this.cvt_ready = false;
    this.ttfautohinted = false;
    //#endif
}
function TT_Face()
{
    this.num_faces = 0;
    this.face_index = 0;

    this.face_flags = 0;
    this.style_flags = 0;

    this.num_glyphs = 0;

    this.family_name = "";
    this.style_name = "";

    this.num_fixed_sizes = 0;
    this.available_sizes = null;

    this.num_charmaps = 0;
    this.charmaps = null;

    this.generic = new FT_Generic();

    /*# The following member variables (down to `underline_thickness') */
    /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size    */
    /*# for bitmap fonts.                                              */
    this.bbox = new FT_BBox();

    this.units_per_EM = 0;
    this.ascender = 0;
    this.descender = 0;
    this.height = null;

    this.max_advance_width = 0;
    this.max_advance_height = 0;

    this.underline_position = 0;
    this.underline_thickness = 0;

    this.glyph = null;
    this.size = null;
    this.charmap = null;

    /*@private begin */
    this.driver = null;
    this.memory = null;
    this.stream = null;

    this.sizes_list = [];

    this.autohint = [];
    this.extensions = null;

    this.internal = null;
    /*@private end */

    this.ttc_header = new TTC_HeaderRec();

    this.format_tag = 0;
    this.num_tables = 0;
    this.dir_tables = null;

    this.header = new TT_Header();
    this.horizontal = new TT_HoriHeader();

    this.max_profile = new TT_MaxProfile();
    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    this.max_components = 0;
    //#endif

    this.vertical_info = 0;
    this.vertical = new TT_VertHeader();

    this.num_names = 0;
    this.name_table = new TT_NameTableRec();

    this.os2 = new TT_OS2();
    this.postscript = new TT_Postscript();

    this.cmap_table = null;
    this.cmap_size = 0;

    this.sfnt = null;
    this.psnames = null;

    // horizontal device metrics
    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    this.hdmx = new TT_HdmxRec();
    //#endif

    // grid-fitting and scaling table
    this.gasp = new TT_Gasp(); // the `gasp' table

    // PCL 5 tabl
    this.pclt = new TT_PCLT();

    // embedded bitmaps support
    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    this.num_sbit_strikes = 0;
    this.sbit_strikes = null;
    //#endif

    this.num_sbit_scales = 0;
    this.sbit_scales = null;

    // postscript names table
    this.postscript_names = new TT_Post_NamesRec();

    // TrueType-specific fields (ignored by the OTF-Type2 driver)
    // the glyph locations
    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    this.num_locations_stub = 0;
    this.glyph_locations_stub = null;
    //#endif

    // the font program, if any
    this.font_program_size = 0;
    this.font_program = null;

    // the cvt program, if any
    this.cvt_program_size = 0;
    this.cvt_program = null;

    // the original, unscaled, control value table
    this.cvt_size = 0;
    this.cvt = null;

    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    // the format 0 kerning table, if any
    this.num_kern_pairs = 0;
    this.kern_table_index = 0;
    this.kern_pairs = [];
    //#endif

    // A pointer to the bytecode interpreter to use.  This is also
    // used to hook the debugger for the `ttdebug' utility.
    this.interpreter = null;

    //#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
    // Use unpatented hinting only.
    this.unpatented_hinting = false;
    //#endif

    // Other tables or fields. This is used by derivative formats like OpenType.
    this.extra = new FT_Generic();

    this.postscript_name = "";

    // since version 2.1.8, but was originally placed after
    // `glyph_locations_stub'
    this.glyf_len = 0;

    // since version 2.1.8, but was originally placed before `extra'
    //#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
    this.doblend = 0;
    this.blend = null;
    //#endif

    // since version 2.2

    this.horz_metrics = null;
    this.horz_metrics_size = 0;

    this.vert_metrics = null;
    this.vert_metrics_size = 0;

    this.num_locations = 0; // in broken TTF, gid > 0xFFFF
    this.glyph_locations = null;

    this.hdmx_table = null;
    this.hdmx_table_size = 0;
    this.hdmx_record_count = 0;
    this.hdmx_record_size = 0;
    this.hdmx_record_sizes = null;

    this.sbit_table = null;
    this.sbit_table_size = 0;
    this.sbit_num_strikes = 0;

    this.kern_table = null;
    this.kern_table_size = 0;
    this.num_kern_tables = 0;
    this.kern_avail_bits = 0;
    this.kern_order_bits = 0;

    //#ifdef TT_CONFIG_OPTION_BDF
    this.bdf = new TT_BDFRec();
    //#endif

    // since 2.3.0
    this.horz_metrics_offset = 0;
    this.vert_metrics_offset = 0;

    this.goto_table = null;
    this.access_glyph_frame = null;
    this.forget_glyph_frame = null;
    this.read_glyph_header = null;
    this.read_simple_glyph = null;
    this.read_composite_glyph = null;

    this.sph_found_func_flags = 0;  /* special functions found */
                                    /* for this face           */
    this.sph_compatibility_mode = false;
}
/******************************************************************************/
// gxvar
/******************************************************************************/
function GX_AVarCorrespondenceRec()
{
    this.fromCoord  = 0;
    this.toCoord    = 0;
}
function GX_AVarSegmentRec()
{
    this.pairCount = 0;
    this.correspondence = null;
}
function GX_BlendRec()
{
    this.num_axis = 0;
    this.normalizedcoords = null;

    this.mmvar = null;
    this.mmvar_len = 0;

    this.avar_checked = 0;
    this.avar_segment = null;

    this.tuplecount = 0;
    this.tuplecoords = null;

    this.gv_glyphcnt = 0;
    this.glyphoffsets = null;
}
function GX_GVar_Head()
{
    this.version = 0;
    this.axisCount = 0;
    this.globalCoordCount = 0;
    this.offsetToCoord = 0;
    this.glyphCount = 0;
    this.flags = 0;
    this.offsetToData = 0;
}
function GX_FVar_Head()
{
    this.version = 0;
    this.offsetToData = 0;
    this.countSizePairs = 0;
    this.axisCount = 0;
    this.axisSize = 0;
    this.instanceCount = 0;
    this.instanceSize = 0;
}
function GX_FVar_Axis()
{
    this.axisTag = 0;
    this.minValue = 0;
    this.defaultValue = 0;
    this.maxValue = 0;
    this.flags = 0;
    this.nameID = 0;
}
function ft_var_readpackedpoints(stream)
{
    var points = null;
    var point_cnt = 0;

    var n;
    var runcnt;
    var j;
    var first;
    point_cnt = n = stream.GetUChar();

    if (n == 0)
        return {points:points, point_cnt:point_cnt};

    if (n & 0x80)
        n = stream.GetUChar() | ((n & 0x7F) << 8);

    points = new Array(n);
    var i = 0;
    while (i < n)
    {
        runcnt = stream.GetUChar();
        if (runcnt & 0x80)
        {
            runcnt = runcnt & 0x7F;
            first  = points[i++] = stream.GetUShort();

            if (runcnt < 1 || i + runcnt >= n)
                return {points:points, point_cnt:point_cnt};

            /* first point not included in runcount */
            for (j = 0; j < runcnt; ++j)
            {
                first += stream.GetUShort();
                points[i++] = first & 0xFFFF;
            }
        }
        else
        {
            first = points[i++] = stream.GetUChar();

            if (runcnt < 1 || i + runcnt >= n)
                return {points:points, point_cnt:point_cnt};

            for (j = 0; j < runcnt; ++j)
            {
                first += stream.GetUChar();
                points[i++] = first & 0xFFFF;
            }
        }
    }

    return {points:points, point_cnt:point_cnt};
}
function ft_var_readpackeddeltas(stream, delta_cnt)
{
    var runcnt;
    var j;

    var deltas = new Array(delta_cnt);
    var i = 0;
    while (i < delta_cnt)
    {
        runcnt = stream.GetUChar();
        if ((runcnt & 128)!=0)
        {
            for (j = 0;j <= (runcnt & 63) && i < delta_cnt;j++)
                deltas[i++] = 0;
        }
        else if ((runcnt & 64)!=0)
        {
            for (j = 0;j <= (runcnt & 63) && i < delta_cnt;j++)
                deltas[i++] = stream.GetShort();
        }
        else
        {
            for (j = 0;j <= (runcnt & 63) && i < delta_cnt;j++)
                deltas[i++] = stream.GetChar();
        }

        if (j <= (runcnt & 63))
        {
            deltas = null;
            return null;
        }
    }
    return deltas;
}
function ft_var_load_avar(face)
{
    var stream = face.stream;
    var blend  = face.blend;
    var segment = null;
    var i, j;

    blend.avar_checked = 1;
    var table_len = face.goto_table(face, 1635148146, stream);
    var error = FT_Error;
    if (error != 0)
        return;

    error = stream.EnterFrame(table_len);
    if (error != 0)
        return;

    var version   = stream.GetLong();
    var axisCount = stream.GetLong();

    if (version != 0x00010000 || axisCount != blend.mmvar.num_axis)
    {
        stream.ExitFrame();
        return;
    }

    blend.avar_segment = new Array(axisCount);
    for (i=0;i<axisCount;i++)
        blend.avar_segment[i] = new GX_AVarSegmentRec();

    for (i = 0; i < axisCount; ++i)
    {
        segment = blend.avar_segment[i];
        segment.pairCount = stream.GetUShort();
        segment.correspondence = new Array(segment.pairCount);

        for (j = 0; j < segment.pairCount; ++j)
        {
            segment.correspondence[j].fromCoord = stream.GetShort() << 2;
            segment.correspondence[j].toCoord = stream.GetShort() << 2;
        }
    }
    stream.ExitFrame();
}
function ft_var_load_gvar(face)
{
    var stream = face.stream;
    var blend  = face.blend;
    var error = 0;
    var i, j;
    var gvar_head = new GX_GVar_Head();

    var table_len = face.goto_table(face, 1735811442, stream);
    error = FT_Error;
    if (error != 0)
        return error;

    var gvar_start = stream.pos;

    error = stream.EnterFrame(20);
    if (error != 0)
        return error;

    gvar_head.version = stream.GetLong();
    gvar_head.axisCount = stream.GetUShort();
    gvar_head.globalCoordCount = stream.GetUShort();
    gvar_head.offsetToCoord = stream.GetULong();
    gvar_head.glyphCount = stream.GetUShort();
    gvar_head.flags = stream.GetUShort();
    gvar_head.offsetToData = stream.GetULong();

    stream.ExitFrame();

    blend.tuplecount  = gvar_head.globalCoordCount;
    blend.gv_glyphcnt = gvar_head.glyphCount;
    var offsetToData = gvar_start + gvar_head.offsetToData;

    if (gvar_head.version != 0x00010000 || gvar_head.axisCount != blend.mmvar.num_axis)
        return 8;

    blend.glyphoffsets = new Array(blend.gv_glyphcnt + 1);
    if ((gvar_head.flags & 1) != 0)
    {
        error = stream.EnterFrame((blend.gv_glyphcnt + 1)*4);
        if (error != 0)
            return error;

        for (i = 0; i <= blend.gv_glyphcnt; ++i)
            blend.glyphoffsets[i] = offsetToData + stream.GetLong();

        stream.ExitFrame();
    }
    else
    {
        error = stream.EnterFrame((blend.gv_glyphcnt + 1)*2);
        if (error != 0)
            return error;

        for (i = 0; i <= blend.gv_glyphcnt; ++i)
            blend.glyphoffsets[i] = offsetToData + stream.GetUShort() * 2;

        stream.ExitFrame();
    }

    if (blend.tuplecount != 0)
    {
        blend.tuplecoords = new Array(gvar_head.axisCount * blend.tuplecount);
        error = stream.Seek(gvar_start + gvar_head.offsetToCoord);
        if (error != 0)
            return error;

        error = stream.EnterFrame(blend.tuplecount * gvar_head.axisCount * 2);

        for (i = 0; i < blend.tuplecount; i++)
        {
            for (j=0;j<gvar_head.axisCount;j++)
            {
                blend.tuplecoords[i * gvar_head.axisCount + j] = stream.GetShort() << 2;
            }
        }

        stream.ExitFrame();
    }
    return error;
}
function ft_var_apply_tuple(blend, tupleIndex, tuple_coords, im_start_coords, im_end_coords)
{
    var apply = 0x10000;
    var temp = 0;
    var i = 0;
    var c = blend.num_axis;
    var nn = blend.normalizedcoords;
    for (; i < c;i++)
    {
        if (tuple_coords[i] == 0)
            continue;
        else if (nn[i] == 0 || (nn[i] < 0 && tuple_coords[i] > 0) || (nn[i] > 0 && tuple_coords[i] < 0))
        {
            apply = 0;
            break;
        }
        else if (0 == (tupleIndex & 16384))
            apply = FT_MulDiv(apply, nn[i] > 0 ? nn[i] : -nn[i], 0x10000);

        else if (nn[i] <= im_start_coords[i] || nn[i] >= im_end_coords[i])
        {
            apply = 0;
            break;
        }
        else if (nn[i] < tuple_coords[i])
        {
            temp = FT_MulDiv(nn[i] - im_start_coords[i], 0x10000, tuple_coords[i] - im_start_coords[i]);
            apply = FT_MulDiv(apply, temp, 0x10000);
        }
        else
        {
            temp = FT_MulDiv(im_end_coords[i] - nn[i], 0x10000, im_end_coords[i] - tuple_coords[i]);
            apply = FT_MulDiv(apply, temp, 0x10000);
        }
    }
    return apply;
}
function TT_Get_MM_Var(face, bIsRet)
{
    var stream = face.stream;
    var table_len;
    FT_Error = 0;
    var fvar_start;
    var i, j;
    var mmvar = null;
    var fvar_head = new GX_FVar_Head();

    if (face.blend == null)
    {
        table_len = face.goto_table(face, 1735811442, stream);
        if (FT_Error != 0)
            return null;

        table_len = face.goto_table(face, 1719034226, stream);
        if (FT_Error != 0)
            return null;

        fvar_start = stream.pos;

        FT_Error = stream.EnterFrame(16);
        if (FT_Error != 0)
            return null;
        fvar_head.version = stream.GetULong();
        fvar_head.offsetToData = stream.GetUShort();
        fvar_head.countSizePairs = stream.GetUShort();
        fvar_head.axisCount = stream.GetUShort();
        fvar_head.axisSize = stream.GetUShort();
        fvar_head.instanceCount = stream.GetUShort();
        fvar_head.instanceSize = stream.GetUShort();
        stream.ExitFrame();


        if (fvar_head.version != 0x00010000 || fvar_head.countSizePairs != 2 || fvar_head.axisSize != 20 ||
                fvar_head.axisCount > 0x3FFE || fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount || fvar_head.instanceCount > 0x7EFF ||
            fvar_head.offsetToData + fvar_head.axisCount * 20 + fvar_head.instanceCount * fvar_head.instanceSize > table_len)
        {
            FT_Error = 8;
            return null;
        }

        face.blend = new GX_BlendRec();
        face.blend.mmvar_len = 0;
        mmvar = new FT_MM_Var();

        face.blend.mmvar = mmvar;

        mmvar.num_axis = fvar_head.axisCount;
        mmvar.num_designs = 0xFFFFFFFF;
        mmvar.num_namedstyles = fvar_head.instanceCount;
        mmvar.axis = new Array(mmvar.num_axis);
        mmvar.namedstyle = new Array(mmvar.num_namedstyles);

        FT_Error = stream.EnterFrame(fvar_start + fvar_head.offsetToData);
        if (FT_Error != 0)
            return null;

        var mass_a = mmvar.axis;
        var count_a = mmvar.num_axis;
        for (i = 0; i < count_a; i++)
        {
            mass_a[i] = new FT_Var_Axis();
            var a = mass_a[i];

            FT_Error = stream.EnterFrame(20);
            if (FT_Error != 0)
                return null;

            a.tag = stream.GetULong();
            a.minimum = stream.GetULong();
            a.def = stream.GetULong();
            a.maximum = stream.GetULong();
            stream.Skip(2);
            a.strid = stream.GetUShort();

            var tag = a.tag;
            a.name = "";
            a.name += String.fromCharCode((tag >>> 24) & 0xFF);
            a.name += String.fromCharCode((tag >>> 16) & 0xFF);
            a.name += String.fromCharCode((tag >>> 8) & 0xFF);
            a.name += String.fromCharCode(tag & 0xFF);

            stream.ExitFrame();
        }

        if (0 == bIsRet)
            return null;

        var mass_s = mmvar.namedstyle;
        var count_s = mmvar.num_namedstyles;
        for (i = 0;i < count_s;i++)
        {
            FT_Error = stream.EnterFrame(4 + 4 * count_a);
            if (FT_Error != 0)
                return null;

            mass_s[i] = new FT_Var_Named_Style();
            var s = mass_s[i];

            s.strid = stream.GetUShort();
            stream.Skip(2);

            s.coords = new Array(count_a);
            for (j = 0; j < count_a; j++)
                s.coords[j] = stream.GetULong();

            stream.ExitFrame();
        }
    }

    mmvar = null;
    mmvar = face.blend.mmvar.dublicate();

    mass_a = mmvar.axis;
    count_a = mmvar.num_axis;
    for (i = 0; i < count_a; i++)
    {
        var a = mass_a[i];

        if (a.tag == 2003265652)
            a.name = "Weight";
        else if (a.tag == 2003072104)
            a.name = "Width";
        else if (a.tag == 1869640570)
            a.name = "OpticalSize";
        else if (a.tag == 1936486004)
            a.name = "Slant";
    }

    return mmvar;
}
function TT_Set_MM_Blend(face, num_coords, coords)
{
    var error = 0;
    face.doblend = 0;

    if (face.blend == null)
    {
        TT_Get_MM_Var(face, 0);
        if (FT_Error != 0)
            return FT_Error;
    }
    var manageCvt = 0;

    var blend = face.blend;
    var mmvar = blend.mmvar;

    if (num_coords != mmvar.num_axis)
        return 6;

    for (var i = 0; i < num_coords; i++)
    {
        if (coords[i] < -0x00010000 || coords[i] > 0x00010000)
            return 6;
    }

    if (blend.glyphoffsets == null)
    {
        error = ft_var_load_gvar(face);
        if (error != 0)
            return error;
    }

    if (blend.normalizedcoords == null)
    {
        blend.normalizedcoords = new Array(num_coords);
        manageCvt = 1;
    }
    else
    {
        manageCvt = 0;
        for (var i = 0; i < num_coords; ++i)
        {
            if (blend.normalizedcoords[i] != coords[i])
            {
                manageCvt = 2;
                break;
            }
        }
    }

    blend.num_axis = num_coords;
    for (var i = 0;i < num_coords; i++)
        blend.normalizedcoords[i] = coords[i];
    face.doblend = 1;
    if (face.cvt != null)
    {
        switch (manageCvt)
        {
            case 2:
                tt_face_load_cvt(face, face.stream);
                break;

            case 1:
                tt_face_vary_cvt(face, face.stream);
                break;

            case 0:
                break;
        }
    }
    return error;
}
function TT_Set_Var_Design(face, num_coords, coords)
{
    var error = 0;
    var i, j;
    var a = null;
    var av = null;
    if (face.blend == null)
    {
        TT_Get_MM_Var(face, 0);
        if (FT_Error != 0)
            return FT_Error;
    }

    var blend = face.blend;
    var mmvar = blend.mmvar;

    if (num_coords != mmvar.num_axis)
        return 6;

    var _c = mmvar.num_axis;
    var normalized = new Array(_c);

    for (i = 0; i < _c; i++)
    {
        a = mmvar.axis[i];
        if (coords[i] > a.maximum || coords[i] < a.minimum)
            return 6;
        
        if (coords[i] < a.def)
        {
            normalized[i] = -FT_MulDiv(coords[i] - a.def, 0x10000, a.minimum - a.def);
        }
        else if (a.maximum == a.def)
            normalized[i] = 0;
        else
        {
            normalized[i] = FT_MulDiv(coords[i] - a.def, 0x10000, a.maximum - a.def);
        }
    }

    if (0 == blend.avar_checked)
        ft_var_load_avar(face);

    if (blend.avar_segment != null)
    {
        for (i = 0; i < _c; i++)
        {
            av = blend.avar_segment[i];
            var _coords = av.correspondence;
            for (j = 1; j < av.pairCount; j++)
            if (normalized[i] < _coords[j].fromCoord)
            {
                var mem = FT_MulDiv(normalized[i] - _coords[j - 1].fromCoord, 0x10000, _coords[j].fromCoord - _coords[j - 1].fromCoord);
                normalized[i] = FT_MulDiv(mem, _coords[j].toCoord - _coords[j - 1].toCoord, 0x10000) + _coords[j - 1].toCoord;
                break;
            }
        }
    }

    error = TT_Set_MM_Blend(face, num_coords, normalized);
    normalized = null;
    return error;
}
function tt_face_vary_cvt(face, stream)
{
    var error = 0;
    var here;
    var i, j;
    var blend = face.blend;
    var point_count;
    var localpoints;
    var deltas;

    if (blend == null)
        return 0;

    if (face.cvt == null)
        return 0;

    var table_len = face.goto_table(face, 1668702578, stream);
    error = FT_Error;
    if (error != 0)
        return 0;

    error = stream.EnterFrame(table_len);
    if (error != 0)
        return 0;

    var table_start = stream.cur;
    if (0x00010000 != stream.GetLong())
    {
        stream.ExitFrame();
        return 0;
    }

    var num_axis = blend.num_axis;
    var tuple_coords = new Array(num_axis);
    var im_start_coords = new Array(num_axis);
    var im_end_coords = new Array(num_axis);

    var tupleCount   = stream.GetUShort();
    var offsetToData = table_start + stream.GetUShort();

    for (i = 0; i < (tupleCount & 0xFFF); ++i)
    {
        var tupleDataSize = stream.GetUShort();
        var tupleIndex    = stream.GetUShort();

        if ((tupleIndex & 32768) != 0)
        {
            for (j = 0; j < num_axis; j++)
                tuple_coords[j] = stream.GetShort() << 2;
        }
        else
        {
            if ((tupleIndex & 16384) != 0)
            {
                stream.Skip(4 * num_axis);
            }
            offsetToData += tupleDataSize;
            continue;
        }
        if ((tupleIndex & 16384) != 0)
        {
            for (j = 0; j < num_axis; j++)
                im_start_coords[j] = stream.GetShort() << 2;
            for (j = 0; j < num_axis; j++)
                im_end_coords[j] = stream.GetShort() << 2;
        }

        var apply = ft_var_apply_tuple(blend, tupleIndex, tuple_coords, im_start_coords, im_end_coords);
        if (apply == 0 || 0 == (tupleIndex & 8192))
        {
            offsetToData += tupleDataSize;
            continue;
        }

        here = stream.cur;
        stream.cur = offsetToData;

        var __mem1 = ft_var_readpackedpoints(stream);
        localpoints = __mem1.points;
        point_count = __mem1.point_cnt;
        var cvt_size = face.cvt_size;
        deltas = ft_var_readpackeddeltas(stream, point_count == 0 ? cvt_size : point_count);
        if (deltas == null)
        {
        }
        else if (localpoints == null)
        {
            for (j = 0; j < cvt_size; j++)
                face.cvt[j] = (face.cvt[j] + FT_MulFix(deltas[j], apply)) & 0xFFFF;
        }
        else
        {
            for (j = 0; j < point_count; ++j)
            {
                var pindex = localpoints[j];
                face.cvt[pindex] = (face.cvt[pindex] + FT_MulFix(deltas[j], apply)) & 0xFFFF;
            }
        }

        localpoints = null;
        deltas = null;
        offsetToData += tupleDataSize;
        stream.cur = here;
    }

    stream.ExitFrame();

    tuple_coords = null;
    im_start_coords = null;
    im_end_coords = null;

    return error;
}
function TT_Vary_Get_Glyph_Deltas(face, glyph_index, n_points)
{
    var stream = face.stream;
    var blend  = face.blend;
    var error;
    var here;
    var i, j;
    var point_count, spoint_count = 0;
    var sharedpoints = null;
    var localpoints  = null;
    var points = null;
    var deltas_x = null, deltas_y = null;


    if (face.doblend == 0 || blend == null)
    {
        FT_Error = 6;
        return null;
    }

    var delta_xy = new Array(n_points);
    for (i=0;i<n_points;i++)
        delta_xy[i] = new FT_Vector();
    
    if (glyph_index >= blend.gv_glyphcnt || blend.glyphoffsets[glyph_index] == blend.glyphoffsets[glyph_index + 1])
        return 0;

    error = stream.Seek(blend.glyphoffsets[glyph_index]);
    if (error == 0)
        error = stream.EnterFrame(blend.glyphoffsets[glyph_index + 1] - blend.glyphoffsets[glyph_index]);

    if (error != 0)
    {
        delta_xy = null;
        FT_Error = error;
        return null;
    }

    var glyph_start = stream.cur;

    var num_axis = blend.num_axis;
    var tuple_coords = new Array(num_axis);
    var im_start_coords = new Array(num_axis);
    var im_end_coords = new Array(num_axis);

    var tupleCount   = stream.GetUShort();
    var offsetToData = glyph_start + stream.GetUShort();

    if ((tupleCount & 32768) != 0)
    {
        here = stream.cur;
        stream.cur = offsetToData;

        var __mem = ft_var_readpackedpoints(stream);
        sharedpoints = __mem.points;
        spoint_count = __mem.point_cnt;
        offsetToData = stream.cur;
        stream.cur = here;
    }

    for ( i = 0; i < ( tupleCount & 0x0FFF ); ++i )
    {
        var tupleDataSize = stream.GetUShort();
        var tupleIndex    = stream.GetUShort();

        if (0 != (tupleIndex & 32768))
        {
            for (j = 0; j < num_axis; j++)
                tuple_coords[j] = stream.GetShort() << 2;
        }
        else if (((tupleIndex & 4095) != 0) >= blend.tuplecount)
        {
            FT_Error = 8;
            tuple_coords = null;
            im_start_coords = null;
            im_end_coords = null;
            delta_xy = null;
            stream.ExitFrame();
            return null;
        }
        else
        {
            var _src = blend.tuplecoords;
            var _s_start = (tupleIndex & 0xFFF) * num_axis;
            for (j=0;j<num_axis;j++)
                tuple_coords[j] = _src[_s_start+j];
        }

        if (0 != (tupleIndex & 16384))
        {
            for (j = 0; j < num_axis; j++)
                im_start_coords[j] = stream.GetShort() << 2;
            for (j = 0; j < num_axis; j++)
                im_end_coords[j] = stream.GetShort() << 2;
        }

        var apply = ft_var_apply_tuple(blend, tupleIndex, tuple_coords, im_start_coords, im_end_coords);
        if (apply == 0)
        {
            offsetToData += tupleDataSize;
            continue;
        }

        here = stream.cur;
        if (0 != (tupleIndex & 8192))
        {
            stream.cur = offsetToData;
            var __mem = ft_var_readpackedpoints(stream);
            localpoints = __mem.points;
            point_count = __mem.point_cnt;
            points = localpoints;
        }
        else
        {
            points      = sharedpoints;
            point_count = spoint_count;
        }

        deltas_x = ft_var_readpackeddeltas(stream, point_count == 0 ? n_points : point_count);
        deltas_y = ft_var_readpackeddeltas(stream, point_count == 0 ? n_points : point_count);

        if (points == null || deltas_y == null || deltas_x == null)
        {
        }
        else if (points == null)
        {
            for (j = 0; j < n_points; j++)
            {
                delta_xy[j].x += FT_MulFix(deltas_x[j], apply);
                delta_xy[j].y += FT_MulFix(deltas_y[j], apply);
            }
        }
        else
        {
            for (j = 0; j < point_count; j++)
            {
                if (localpoints[j] >= n_points)
                    continue;

                delta_xy[localpoints[j]].x += FT_MulFix(deltas_x[j], apply);
                delta_xy[localpoints[j]].y += FT_MulFix(deltas_y[j], apply);
            }
        }

        localpoints = null;
        deltas_x = null;
        deltas_y = null;

        offsetToData += tupleDataSize;
        stream.cur = here;
    }

    tuple_coords = null;
    im_start_coords = null;
    im_end_coords = null;
    delta_xy = null;
    stream.ExitFrame();
    if (error != 0)
        delta_xy = null;

    FT_Error = error;
    return delta_xy;
}
function tt_done_blend(memory, blend)
{
}
/******************************************************************************/
// glyphloader
/******************************************************************************/
function load_sbit_image(size, glyph, glyph_index, load_flags)
{
    var metrics = new TT_SBit_MetricsRec();

    var face   = glyph.face;
    var stream = face.stream;
    var error = face.sfnt.load_sbit_image(face, size.strike_index, glyph_index, load_flags, stream, glyph.bitmap, metrics);
    if (error == 0)
    {
        glyph.outline.n_points   = 0;
        glyph.outline.n_contours = 0;

        glyph.metrics.width  = metrics.width  << 6;
        glyph.metrics.height = metrics.height << 6;

        glyph.metrics.horiBearingX = metrics.horiBearingX << 6;
        glyph.metrics.horiBearingY = metrics.horiBearingY << 6;
        glyph.metrics.horiAdvance  = metrics.horiAdvance  << 6;

        glyph.metrics.vertBearingX = metrics.vertBearingX << 6;
        glyph.metrics.vertBearingY = metrics.vertBearingY << 6;
        glyph.metrics.vertAdvance  = metrics.vertAdvance  << 6;

        glyph.format = 1651078259;

        if ((load_flags & 16) != 0)
        {
            glyph.bitmap_left = metrics.vertBearingX;
            glyph.bitmap_top  = metrics.vertBearingY;
        }
        else
        {
            glyph.bitmap_left = metrics.horiBearingX;
            glyph.bitmap_top  = metrics.horiBearingY;
        }
    }

    return error;
}
function TT_Get_HMetrics(face, idx)
{
    return face.sfnt.get_metrics(face, 0, idx);
}
function TT_Get_VMetrics(face, idx, yMax)
{
    if (face.vertical_info === 1)
        return face.sfnt.get_metrics(face, 1, idx);
    else if (face.os2.version != 0xFFFF)
        return {bearing : (face.os2.sTypoAscender - yMax), advance : (face.os2.sTypoAscender - face.os2.sTypoDescender)};
    else
        return {bearing : (face.horizontal.Ascender - yMax), advance : (face.horizontal.Ascender - face.horizontal.Descender)};

    return {bearing : 0, advance : face.units_per_EM};
}

function tt_get_metrics(loader, glyph_index)
{
    var face = loader.face;

    var h = TT_Get_HMetrics(face, glyph_index);
    var v = TT_Get_VMetrics(face, glyph_index, loader.bbox.yMax);

    loader.left_bearing = h.bearing;
    loader.advance      = h.advance;
    loader.top_bearing  = v.bearing;
    loader.vadvance     = v.advance;

    if (face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING) //#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
    {
        if (loader.exec != null)
            loader.exec.sph_tweak_flags = 0;

        /* this may not be the right place for this, but it works */
        if (loader.exec != null && loader.exec.ignore_x_mode)
            global_SubpixHintingHacks.sph_set_tweaks(loader, glyph_index);
    }//#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */

    if (loader.linear_def == 0)
    {
        loader.linear_def = 1;
        loader.linear = h.advance;
    }
}
function tt_get_metrics_incr_overrides(loader, glyph_index)
{
    var face = loader.face;

    var h = TT_Get_HMetrics(face, glyph_index);
    var v = TT_Get_VMetrics(face, glyph_index, 0);

    if (face.internal.incremental_interface && face.internal.incremental_interface.funcs.get_glyph_metrics)
    {
        var metrics = new FT_Incremental_MetricsRec();

        metrics.bearing_x = loader.left_bearing;
        metrics.bearing_y = 0;
        metrics.advance   = loader.advance;
        metrics.advance_v = 0;

        var error = face.internal.incremental_interface.funcs.get_glyph_metrics(face.internal.incremental_interface.object,
            glyph_index, false, metrics);
        if (error != 0)
            return 0;

        loader.left_bearing = metrics.bearing_x;
        loader.advance      = metrics.advance;
        loader.top_bearing  = v.tsb;
        loader.vadvance     = v.ah;

        if (0 == loader.linear_def)
        {
            loader.linear_def = 1;
            loader.linear = h.aw;
        }
    }
    return 0;
}
function translate_array(n, coords, delta_x, delta_y)
{
    if (delta_x != 0)
        for (var k = 0; k < n; k++)
            coords[k].x += delta_x;

    if (delta_y != 0)
        for (var k = 0; k < n; k++)
            coords[k].y += delta_y;
}
function translate_array_ex(n, coords, start_p, delta_x, delta_y)
{
    if (delta_x != 0)
        for (var k = 0; k < n; k++)
            coords[start_p + k].x += delta_x;

    if (delta_y != 0)
        for (var k = 0; k < n; k++)
            coords[start_p + k].y += delta_y;
}

function TT_Access_Glyph_Frame(loader, glyph_index, offset, byte_count)
{
    var error = 0;
    var stream = loader.stream;

    error = stream.Seek(offset);
    if (error == 0)
        error = stream.EnterFrame(byte_count);

    if (error != 0)
        return error;

    loader.cursor = stream.cur;
    loader.limit  = stream.size;

    return 0;
}

function TT_Forget_Glyph_Frame(loader)
{
    loader.stream.ExitFrame();
}

function TT_Load_Glyph_Header(loader)
{
    var stream = loader.stream;

    if (stream.cur + 10 > stream.size)
        return 20;

    loader.n_contours = stream.GetShort();
    loader.bbox.xMin = stream.GetShort();
    loader.bbox.yMin = stream.GetShort();
    loader.bbox.xMax = stream.GetShort();
    loader.bbox.yMax = stream.GetShort();

    loader.cursor += 10;

    return 0;
}

function TT_Load_Simple_Glyph(load)
{
    var error = 0;
    var p = new FT_Stream(load.stream.data, load.stream.size);
    p.cur = load.cursor;

    var gloader = load.gloader;
    var n_contours = load.n_contours;
    var face = load.face;
    var n_ins;
    var n_points;

    var c, count;
    var x;
    var prev_cont;
    var xy_size = 0;

    error = FT_GLYPHLOADER_CHECK_POINTS(gloader, 0, n_contours);
    if (error != 0)
        return error;

    if (null == gloader.base.outline.contours)
    {
        error = FT_GLYPHLOADER_CHECK_POINTS(gloader, 0, n_contours);
    }

    var conts = gloader.base.outline.contours;
    var cont = gloader.current.outline.contours;
    var cont_limit = cont + n_contours;

    if (n_contours >= 0xFFF || p.cur + (n_contours + 1) * 2 > load.limit)
        return 20;

    prev_cont = p.GetUShort();

    if (n_contours > 0)
        conts[cont] = prev_cont;

    for (cont++; cont < cont_limit; cont++)
    {
        conts[cont] = p.GetUShort();
        if (conts[cont] <= prev_cont)
            return 8;
        prev_cont = conts[cont];
    }

    n_points = 0;
    if (n_contours > 0)
    {
        n_points = conts[cont-1] + 1;
        if (n_points < 0)
            return 20;
    }

    /* note that we will add four phantom points later */
    error = FT_GLYPHLOADER_CHECK_POINTS(gloader, n_points + 4, 0);
    if (error != 0)
        return error;

    var outline = gloader.current.outline;
    for (cont = outline.contours + 1; cont < cont_limit; cont++)
        if (conts[cont-1] >= conts[cont])
            return 20;

    load.glyph.control_len  = 0;
    load.glyph.control_data = 0;

    if (p.cur + 2 > load.limit)
        return 20;

    n_ins = p.GetUShort();
    if (n_ins > face.max_profile.maxSizeOfInstructions)
        return 22;

    if ((load.limit - p.cur) < n_ins)
        return 22;

    //#ifdef TT_USE_BYTECODE_INTERPRETER
    if (face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER)
    {
        if ((load.load_flags & 2) == 0)
        {
            load.glyph.control_len  = n_ins;
            load.glyph.control_data = dublicate_pointer(load.exec.glyphIns);

			if (load.glyph.control_data != null)
			{
				var _dd = load.glyph.control_data.data;
				var _dc = load.glyph.control_data.pos;

				for (var j = 0; j < n_ins; j++)
					_dd[_dc + j] = p.data[p.cur + j];
			}
        }
    }

    p.cur += n_ins;

    var flags = gloader.base.outline.tags;
    var flag = outline.tags;
    var flag_limit = flag + n_points;

    var limit = load.limit;
    while (flag < flag_limit)
    {
        if (p.cur + 1 > limit)
            return 20;

        flags[flag++] = c = p.GetUChar();
        if ((c & 8)!=0)
        {
            if (p.cur + 1 > limit)
                return 20;

            count = p.GetUChar();
            if (flag + count > flag_limit)
                return 20;

            for (; count > 0; count--)
                flags[flag++] = c;
        }
    }

    var vecs = gloader.base.outline.points;
    var vec = outline.points;
    var vec_limit = vec + n_points;
    flag = outline.tags;
    x = 0;

    if (p.cur + xy_size > limit)
        return 20;

    for ( ; vec < vec_limit; vec++, flag++ )
    {
        var y = 0;
        var f = flags[flag];

        if ((f & 2)!=0)
        {
            if (p.cur + 1 > limit)
                return 20;

            y = p.GetUChar();
            if (( f & 16 ) == 0)
                y = -y;
        }
        else if (( f & 16 ) == 0)
        {
            if (p.cur + 2 > limit)
                return 20;

            y = p.GetShort();
        }

        x += y;
        vecs[vec].x = x;
        flags[flag]  = (f & ~( 2 | 16 )) & 0xFF;
    }

    vec = outline.points;
    flag = outline.tags;
    x = 0;

    for ( ; vec < vec_limit; vec++, flag++)
    {
        var y = 0;
        var f = flags[flag];

        if ((f & 4)!=0)
        {
            if (p.cur + 1 > limit)
                return 20;

            y = p.GetUChar();
            if ((f & 32) == 0)
                y = -y;
        }
        else if ((f & 32) == 0)
        {
            if (p.cur + 2 > limit)
                return 20;

            y = p.GetShort();
        }

        x += y;
        vecs[vec].y = x;
        flags[flag]  = (f & 1) & 0xFF;
    }

    outline.n_points   = n_points & 0xFFFF;
    outline.n_contours = n_contours & 0xFFFF;

    load.cursor = p.cur;
    return error;
}

function TT_Load_Composite_Glyph(loader)
{
    var error = 0;
    var s = new FT_Stream(loader.stream.data, loader.stream.size);
    s.cur = loader.cursor;
    var size_read = loader.limit - loader.cursor;
    var count_read = 0;

    var gloader = loader.gloader;
    var subglyph = null;
    var num_subglyphs = 0;

    do
    {
        var xx, xy, yy, yx;
        var count;

        error = FT_GlyphLoader_CheckSubGlyphs(gloader, num_subglyphs + 1);
        if (error != 0)
            return error;

        if (count_read + 4 > size_read)
            return 21;

        subglyph = gloader.base.subglyphs[gloader.current.subglyphs + num_subglyphs];

        subglyph.arg1 = subglyph.arg2 = 0;

        subglyph.flags = s.GetUShort();
        subglyph.index = s.GetUShort();

        count_read += 4;

        count = 2;
        if (subglyph.flags & 1)
            count += 2;
        if (subglyph.flags & 8)
            count += 2;
        else if (subglyph.flags & 64)
            count += 4;
        else if (subglyph.flags & 128)
            count += 8;

        if (count_read + count > size_read)
            return 21;

        if (subglyph.flags & 1)
        {
            subglyph.arg1 = s.GetShort();
            subglyph.arg2 = s.GetShort();
        }
        else
        {
            subglyph.arg1 = s.GetChar();
            subglyph.arg2 = s.GetChar();
        }

        xx = yy = 0x10000;
        xy = yx = 0;

        if (subglyph.flags & 8)
        {
            xx = s.GetShort() << 2;
            yy = xx;
        }
        else if (subglyph.flags & 64)
        {
            xx = s.GetShort() << 2;
            yy = s.GetShort() << 2;
        }
        else if (subglyph.flags & 128)
        {
            xx = s.GetShort() << 2;
            yx = s.GetShort() << 2;
            xy = s.GetShort() << 2;
            yy = s.GetShort() << 2;
        }

        subglyph.transform.xx = xx;
        subglyph.transform.xy = xy;
        subglyph.transform.yx = yx;
        subglyph.transform.yy = yy;

        num_subglyphs++;

        count_read += count;

    } while (subglyph.flags & 32);

    gloader.current.num_subglyphs = num_subglyphs;

    if (loader.face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER)
    {
        loader.ins_pos = loader.stream.pos + s.cur - loader.limit;
    }
    
    loader.cursor = s.cur;
    return error
}

function TT_Process_Simple_Glyph(loader)
{
    var gloader = loader.gloader;
    var error = 0;

    var outline  = gloader.current.outline;
    var base  = gloader.base.outline;
    var n_points = outline.n_points;

    var points = base.points;
    var p_s = outline.points;
    var s = p_s + n_points;
    var tags = base.tags;
    var t_s = outline.tags;
    var t = t_s + n_points;

    points[s    ].x = loader.pp1.x;
    points[s + 1].x = loader.pp2.x;
    points[s + 2].x = loader.pp3.x;
    points[s + 3].x = loader.pp4.x;
    points[s    ].y = loader.pp1.y;
    points[s + 1].y = loader.pp2.y;
    points[s + 2].y = loader.pp3.y;
    points[s + 3].y = loader.pp4.y;

    tags[t    ] = 0;
    tags[t + 1] = 0;
    tags[t + 2] = 0;
    tags[t + 3] = 0;

    n_points += 4;
    s += 4;

    //#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
    if (loader.face.doblend != 0)
    {
        var deltas = TT_Vary_Get_Glyph_Deltas(loader.face, loader.glyph_index, n_points);
        error = FT_Error;
        if (error != 0)
            return error;

        for (var i = 0; i < n_points; i++)
        {
            points[i + p_s].x += deltas[i].x;
            points[i + p_s].y += deltas[i].y;
        }

        deltas = null;
    }
    //#endif

    if ((loader.load_flags & 2) == 0)
    {
        tt_prepare_zone_cur(loader.zone, gloader, 0, 0);

        var _p_len = loader.zone.n_points + 4;

        var _orus = loader.zone.orus;
        var _cur = loader.zone.cur;
        for (var i = 0; i < _p_len; i++)
        {
            _orus[loader.zone._offset_orus + i].x = _cur[loader.zone._offset_cur + i].x;
            _orus[loader.zone._offset_orus + i].y = _cur[loader.zone._offset_cur + i].y;
        }
    }

    var _face = loader.face;
    if (_face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)
    {
        var x_scale_factor = 1000;
        var ppem = loader.size.metrics.x_ppem;
        if ((loader.load_flags & 2) == 0)
        {
            x_scale_factor = global_SubpixHintingHacks.sph_test_tweak_x_scaling(_face, _face.family_name, ppem, _face.style_name, loader.glyph_index);
        }

        if ((loader.load_flags & 1) == 0 || x_scale_factor != 1000)
        {
            var x_scale = FT_MulDiv(loader.size.metrics.x_scale, x_scale_factor, 1000);
            var y_scale = loader.size.metrics.y_scale;

            /* compensate for any scaling by de/emboldening; */
            /* the amount was determined via experimentation */
            if (x_scale_factor != 1000 && ppem > 11)
                FT_Outline_EmboldenXY(outline, FT_MulFix(1280 * ppem, 1000 - x_scale_factor), 0);

            for (var vec = 0 ; vec < n_points; vec++)
            {
                points[vec + p_s].x = FT_MulFix(points[vec + p_s].x, x_scale);
                points[vec + p_s].y = FT_MulFix(points[vec + p_s].y, y_scale);
            }

            loader.pp1.x = points[s - 4].x;
            loader.pp2.x = points[s - 3].x;
            loader.pp3.x = points[s - 2].x;
            loader.pp4.x = points[s - 1].x;
            loader.pp1.y = points[s - 4].y;
            loader.pp2.y = points[s - 3].y;
            loader.pp3.y = points[s - 2].y;
            loader.pp4.y = points[s - 1].y;
        }
    }
    else
    {
        if ((loader.load_flags & 1) == 0)
        {
            var x_scale = loader.size.metrics.x_scale;
            var y_scale = loader.size.metrics.y_scale;

            for (var vec = 0 ; vec < n_points; vec++)
            {
                points[vec + p_s].x = FT_MulFix(points[vec + p_s].x, x_scale);
                points[vec + p_s].y = FT_MulFix(points[vec + p_s].y, y_scale);
            }

            loader.pp1.x = points[s - 4].x;
            loader.pp2.x = points[s - 3].x;
            loader.pp3.x = points[s - 2].x;
            loader.pp4.x = points[s - 1].x;
            loader.pp1.y = points[s - 4].y;
            loader.pp2.y = points[s - 3].y;
            loader.pp3.y = points[s - 2].y;
            loader.pp4.y = points[s - 1].y;
        }
    }

    if ((loader.load_flags & 2) == 0)
    {
        loader.zone.n_points += 4;
        error = TT_Hint_Glyph(loader, false);
    }

    return error;
}

function TT_Process_Composite_Component(loader, subglyph, start_point, num_base_points)
{
    var gloader = loader.gloader;
    var base_vecs = gloader.base.outline.points;
    var base_vec = 0;
    var num_points = gloader.base.outline.n_points;
    var x, y;

    var have_scale = (0 == (subglyph.flags & (8 | 64 | 128))) ? 0 : 1;

    if (have_scale != 0)
    {
        for (var i = num_base_points; i < num_points; i++)
            FT_Vector_Transform(base_vecs[i], subglyph.transform);
    }

    if (0 == (subglyph.flags & 2))
    {
        var k = subglyph.arg1;
        var l = subglyph.arg2;
        k += start_point;
        l += num_base_points;
        if (k >= num_base_points || l >= num_points)
            return 21;

        var p1 = gloader.base.outline.points[k];
        var p2 = gloader.base.outline.points[l];

        x = p1.x - p2.x;
        y = p1.y - p2.y;
    }
    else
    {
        x = subglyph.arg1;
        y = subglyph.arg2;

        if (x == 0 && y == 0)
            return 0;

        if (have_scale != 0 && 0 != (subglyph.flags & 2048))
        {
            var mac_xscale = FT_SqrtFixed(FT_MulFix(subglyph.transform.xx, subglyph.transform.xx) +
                                            FT_MulFix(subglyph.transform.xy, subglyph.transform.xy));
            var mac_yscale = FT_SqrtFixed(FT_MulFix(subglyph.transform.yy, subglyph.transform.yy) +
                                            FT_MulFix(subglyph.transform.yx, subglyph.transform.yx));


            x = FT_MulFix(x, mac_xscale);
            y = FT_MulFix(y, mac_yscale);
        }

        if (0 == (loader.load_flags & 1))
        {
            var x_scale = loader.size.metrics.x_scale;
            var y_scale = loader.size.metrics.y_scale;

            x = FT_MulFix(x, x_scale);
            y = FT_MulFix(y, y_scale);

            if (subglyph.flags & 4)
            {
                x = FT_PIX_ROUND(x);
                y = FT_PIX_ROUND(y);
            }
        }
    }

    if (x != 0)
    {
        for (var j=num_base_points;j<num_points;j++)
            base_vecs[j].x += x;
    }
    if (y != 0)
    {
        for (var j=num_base_points;j<num_points;j++)
            base_vecs[j].y += y;
    }
    
    return 0;
}

function TT_Process_Composite_Glyph(loader, start_point, start_contour)
{
    var outline = loader.gloader.base.outline;

    /* make room for phantom points */
    var error = FT_GLYPHLOADER_CHECK_POINTS(loader.gloader, outline.n_points + 4, 0);
    if (error != 0)
        return error;

    var _points = outline.points;
    var _n_points = outline.n_points;
    var _tags = outline.tags;

    _points[_n_points].x = loader.pp1.x;
    _points[_n_points].y = loader.pp1.y;

    _points[_n_points + 1].x = loader.pp2.x;
    _points[_n_points + 1].y = loader.pp2.y;

    _points[_n_points + 2].x = loader.pp3.x;
    _points[_n_points + 2].y = loader.pp3.y;

    _points[_n_points + 3].x = loader.pp4.x;
    _points[_n_points + 3].y = loader.pp4.y;

    _tags[_n_points] = 0;
    _tags[_n_points + 1] = 0;
    _tags[_n_points + 2] = 0;
    _tags[_n_points + 3] = 0;

    if (loader.face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER) //#ifdef TT_USE_BYTECODE_INTERPRETER
    {
        /* TT_Load_Composite_Glyph only gives us the offset of instructions */
        /* so we read them here                                             */
        var stream = loader.stream;
        error = stream.Seek(loader.ins_pos);
        if (error != 0)
            return error;

        var n_ins = stream.ReadUShort();
        error = FT_Error;
        FT_Error = 0;
        if (error != 0)
            return error;

        /* check it */
        var max_ins = loader.face.max_profile.maxSizeOfInstructions;
        if (n_ins > max_ins)
        {
            /* acroread ignores this field, so we only do a rough safety check */
            if (n_ins > loader.byte_len)
                return 22;
        
            var ret = Update_MaxBYTE(loader.exec.memory, loader.exec.glyphSize, loader.exec.glyphIns, n_ins);
            if (ret != null)
            {
                loader.exec.glyphSize = ret.size;
                loader.exec.glyphIns = ret.block;
            }

            if ( error )
                return error;
        }
        else if (n_ins == 0)
            return 0;

        error = stream.Read(loader.exec.glyphIns, n_ins);
        if (error != 0)
            return error;

        loader.glyph.control_data = dublicate_pointer(loader.exec.glyphIns);
        loader.glyph.control_len = n_ins;
    }
    //#endif

    tt_prepare_zone(loader.zone, loader.gloader.base, start_point, start_contour);

    /* Some points are likely touched during execution of  */
    /* instructions on components.  So let's untouch them. */
    for (var i = start_point; i < loader.zone.n_points; i++)
        loader.zone.tags[i] &= ~24;

    loader.zone.n_points += 4;

    return TT_Hint_Glyph(loader, true);
}

function TT_Hint_Glyph(loader, is_composite)
{
    var zone = loader.zone;
    var n_ins = 0;

    var _tt_hints = loader.face.driver.library.tt_hint_props;
    if (_tt_hints.TT_USE_BYTECODE_INTERPRETER) //#ifdef TT_USE_BYTECODE_INTERPRETER
    {
        n_ins = loader.glyph.control_len;
    }
    //#endif

    var origin = zone.cur[zone._offset_cur + zone.n_points - 4].x;
    origin = FT_PIX_ROUND(origin) - origin;
    if (origin != 0)
        translate_array_ex(zone.n_points, zone.cur, zone._offset_cur, origin, 0);

    if (_tt_hints.TT_USE_BYTECODE_INTERPRETER) //#ifdef TT_USE_BYTECODE_INTERPRETER
    {
        /* save original point position in org */
        if (n_ins > 0)
        {
            var _arr_d = zone.org;
            var _arr_s = zone.cur;
            var _count = zone.n_points;
            var _d_s = zone._offset_org;
            var _s_s = zone._offset_cur;

            for (var i = 0; i < _count; i++)
            {
                _arr_d[i + _d_s].x = _arr_s[i + _s_s].x;
                _arr_d[i + _d_s].y = _arr_s[i + _s_s].y;
            }
        }

        /* Reset graphics state. */
        loader.size.GS.Copy(loader.exec.GS);

        /* XXX: UNDOCUMENTED! Hinting instructions of a composite glyph */
        /*      completely refer to the (already) hinted subglyphs.     */
        if (is_composite)
        {
            loader.exec.metrics.x_scale = 1 << 16;
            loader.exec.metrics.y_scale = 1 << 16;

            var _arr_d = zone.orus;
            var _arr_s = zone.cur;
            var _count = zone.n_points;
            var _d_s = zone._offset_orus;
            var _s_s = zone._offset_cur;

            for (var i = 0; i < _count; i++)
            {
                _arr_d[i + _d_s].x = _arr_s[i + _s_s].x;
                _arr_d[i + _d_s].y = _arr_s[i + _s_s].y;
            }
        }
        else
        {
            loader.exec.metrics.x_scale = loader.size.metrics.x_scale;
            loader.exec.metrics.y_scale = loader.size.metrics.y_scale;
        }
    }//#endif

    /* round pp2 and pp4 */
    zone.cur[zone._offset_cur + zone.n_points - 3].x = FT_PIX_ROUND(zone.cur[zone._offset_cur + zone.n_points - 3].x);
    zone.cur[zone._offset_cur + zone.n_points - 1].y = FT_PIX_ROUND(zone.cur[zone._offset_cur + zone.n_points - 1].y);

    //#ifdef TT_USE_BYTECODE_INTERPRETER
    if ( n_ins > 0 )
    {
        var base_outline = loader.gloader.base.outline;
        var current_outline = loader.gloader.current.outline;

        var error = TT_Set_CodeRange(loader.exec, 3, loader.exec.glyphIns, n_ins);
        if (error)
            return error;

        loader.exec.is_composite = is_composite;
        loader.exec.pts.Copy(zone);

        var debug = (!(loader.load_flags & 1) && loader.size.debug) ? true : false;

        error = TT_Run_Context(loader.exec, debug);
        if (error && loader.exec.pedantic_hinting)
            return error;

        /* store drop-out mode in bits 5-7; set bit 2 also as a marker */
        base_outline.tags[current_outline.tags] |= (loader.exec.GS.scan_type << 5) | 4;
    }
    //#endif

    /* save glyph phantom points */
    if (!loader.preserve_pps)
    {
        var _off = zone.n_points + zone._offset_cur;

        loader.pp1.x = zone.cur[_off - 4].x;
        loader.pp1.y = zone.cur[_off - 4].y;

        loader.pp2.x = zone.cur[_off - 3].x;
        loader.pp2.y = zone.cur[_off - 3].y;

        loader.pp3.x = zone.cur[_off - 2].x;
        loader.pp3.y = zone.cur[_off - 2].y;

        loader.pp4.x = zone.cur[_off - 1].x;
        loader.pp4.y = zone.cur[_off - 1].y;
    }

    if (_tt_hints.TT_CONFIG_OPTION_SUBPIXEL_HINTING) //#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
    {
        if (loader.exec.sph_tweak_flags & 16)
            FT_Outline_EmboldenXY(loader.gloader.current.outline, -24, 0);
        else if (loader.exec.sph_tweak_flags & 64)
            FT_Outline_EmboldenXY(loader.gloader.current.outline, 24, 0);
    }//#endif
    return 0;
}

function tt_prepare_zone(zone, load, start_point, start_contour)
{
    zone.n_points    = (load.outline.n_points - start_point) & 0xFFFF;
    zone.n_contours  = FT_Common.UShort_To_Short((load.outline.n_contours - start_contour) & 0xFFFF);

    zone.org = load.extra_points;
    zone._offset_org = start_point;

    zone.cur = load.outline.points;
    zone._offset_cur = start_point;

    zone.orus = load.extra_points;
    zone._offset_orus = load.extra_points2 + start_point;

    zone.tags = load.outline.tags;
    zone._offset_tags = start_point;

    zone.contours = load.outline.contours;
    zone._offset_contours = start_contour;

    zone.first_point = start_point;
}

function tt_prepare_zone_cur(zone, load, start_point, start_contour)
{
    var _base = load.base;
    var _cur = load.current;

    zone.n_points    = (_cur.outline.n_points - start_point) & 0xFFFF;
    zone.n_contours  = FT_Common.UShort_To_Short((_cur.outline.n_contours - start_contour) & 0xFFFF);

    zone.org = _base.extra_points;
    zone._offset_org = _cur.extra_points + start_point;

    zone.cur = _base.outline.points;
    zone._offset_cur = _cur.outline.points + start_point;

    zone.orus = _base.extra_points;
    zone._offset_orus = _cur.extra_points2 + start_point;

    zone.tags = _base.outline.tags;
    zone._offset_tags = _cur.outline.tags + start_point;

    zone.contours = _base.outline.contours;
    zone._offset_contours = _cur.outline.contours + start_contour;

    zone.first_point = start_point;
}

function tt_size_run_prep(size, pedantic)
{
    var face = size.face;
    var exec;
    var error = 0;

    /* debugging instances have their own context */
    if (size.debug)
        exec = size.context;
    else
        exec = face.driver.context;

    if (exec == null)
        return 153;

    TT_Load_Context(exec, face, size);

    exec.callTop = 0;
    exec.top     = 0;

    exec.instruction_trap = false;
    exec.pedantic_hinting = pedantic;

    TT_Set_CodeRange(exec, 2, face.cvt_program, face.cvt_program_size);
    TT_Clear_CodeRange(exec, 3);

    if (face.cvt_program_size > 0)
    {
        error = TT_Goto_CodeRange(exec, 2, 0);

        if (!error && !size.debug)
        {
            error = face.interpreter(exec);
        }
    }
    else
        error = 0;

    /* save as default graphics state */
    exec.GS.Copy(size.GS);

    // _DEBUG!
    /*
    var __arr = exec.stack;
    var __len = exec.stackSize;
    for (var __i = 0; __i < __len; ++__i)
        console.log("" + __i + ": " + __arr[__i]);
    */
    //

    TT_Save_Context(exec, size);
    return error;
}

function tt_loader_init(loader, size, glyph, load_flags, glyf_table_only)
{
    var face = glyph.face;
    var stream = face.stream;
    var pedantic = (0 == (load_flags & 128)) ? 0 : 1;

    loader.Clear();

    var bIsHint = face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER;
    var bIsSubpixHint = face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING;

    if (bIsHint)//#ifdef TT_USE_BYTECODE_INTERPRETER
    {/* load execution context */
        if ((load_flags & 2) == 0 && !glyf_table_only)
        {
            var grayscale = false;

            //#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
            var subpixel_hinting = false;
            var grayscale_hinting = false;
            //#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */

            if (!size.cvt_ready)
            {
                var error = tt_size_ready_bytecode(size, pedantic);
                if (error != 0)
                    return error;
            }

            /* query new execution context */
            var exec = size.debug ? size.context : face.driver.context;
            if (exec == null)
                return 153;

            if (bIsSubpixHint) // #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
            {
                subpixel_hinting = ((FT_LOAD_TARGET_MODE(load_flags) != 2) && true);

                if (subpixel_hinting)
                    grayscale = grayscale_hinting = false;
                else if (false)
                {
                    grayscale = grayscale_hinting = true;
                    subpixel_hinting = false;
                }

                if ((face.face_flags & 8192) != 0)
                    subpixel_hinting = grayscale_hinting = false;

                exec.ignore_x_mode = subpixel_hinting || grayscale_hinting;
                exec.rasterizer_version = 38;
                if (exec.sph_tweak_flags & 8192)
                    exec.rasterizer_version = 35;

                if (true)
                {
                    exec.compatible_widths     = false;
                    exec.symmetrical_smoothing = false;
                    exec.bgr                   = false;
                    exec.subpixel_positioned   = true;
                }
                else
                {
                    /*
                    exec.compatible_widths = (FT_LOAD_TARGET_MODE(load_flags) !=  FT_Common.TT_LOAD_COMPATIBLE_WIDTHS);
                    exec.symmetrical_smoothing = (FT_LOAD_TARGET_MODE(load_flags) != FT_Common.TT_LOAD_SYMMETRICAL_SMOOTHING);
                    exec.bgr = (FT_LOAD_TARGET_MODE(load_flags) != FT_Common.TT_LOAD_BGR);
                    exec.subpixel_positioned = (FT_LOAD_TARGET_MODE(load_flags) != FT_Common.TT_LOAD_SUBPIXEL_POSITIONED);
                    */
                }
            }/* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
            else
            {
                grayscale = (FT_LOAD_TARGET_MODE(load_flags) != 2);
            }/* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */

            TT_Load_Context(exec, face, size);

            if (bIsSubpixHint)//#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
            {
                /* a change from mono to subpixel rendering (and vice versa) */
                /* requires a re-execution of the CVT program                */
                if (subpixel_hinting != exec.subpixel_hinting)
                {
                    exec.subpixel_hinting = subpixel_hinting;

                    for (var i = 0; i < size.cvt_size; i++)
                        size.cvt[i] = FT_MulFix(face.cvt[i], size.ttmetrics.scale);

                    tt_size_run_prep(size, pedantic);
                }

                /* a change from mono to grayscale rendering (and vice versa) */
                /* requires a re-execution of the CVT program                 */
                if (grayscale != exec.grayscale_hinting)
                {
                    exec.grayscale_hinting = grayscale_hinting;

                    for (var i = 0; i < size.cvt_size; i++)
                        size.cvt[i] = FT_MulFix(face.cvt[i], size.ttmetrics.scale);
                    tt_size_run_prep( size, pedantic );
                }
            }/* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
            else
            {
                /* a change from mono to grayscale rendering (and vice versa) */
                /* requires a re-execution of the CVT program                 */
                if (grayscale != exec.grayscale)
                {
                    exec.grayscale = grayscale;

                    for (i = 0; i < size.cvt_size; i++)
                        size.cvt[i] = FT_MulFix(face.cvt[i], size.ttmetrics.scale);

                    tt_size_run_prep(size, pedantic);
                }
            }//#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */

            /* see whether the cvt program has disabled hinting */
            if (exec.GS.instruct_control & 1)
                load_flags |= 2;

            /* load default graphics state -- if needed */
            if (exec.GS.instruct_control & 2)
                exec.GS.default_tt();

            exec.pedantic_hinting = ((load_flags & 128) != 0) ? true : false;
            loader.exec = exec;
            loader.instructions = dublicate_pointer(exec.glyphIns);
        }
    }//#endif /* TT_USE_BYTECODE_INTERPRETER */

    if (face.internal.incremental_interface)
        loader.glyf_offset = 0;
    else
    {
        face.goto_table(face, 1735162214, stream);
        var error = FT_Error;
        FT_Error = 0;
        if (error == 142)
            loader.glyf_offset = 0;
        else if ( error )
            return error;
        else
            loader.glyf_offset = stream.pos;
    }

    if (0 == glyf_table_only)
    {
        var gloader = glyph.internal.loader;
        FT_GlyphLoader_Rewind(gloader);
        loader.gloader = gloader;
    }

    loader.load_flags = load_flags;

    loader.face = face;
    loader.size = size;
    loader.glyph = glyph;
    loader.stream = stream;

    return 0;
}

function tt_face_get_device_metrics(face, ppem, gindex)
{
    var _ret = null;
    var record_size = face.hdmx_record_size;

    for (var nn = 0; nn < face.hdmx_record_count; nn++ )
    {
        if ( face.hdmx_record_sizes[nn] == ppem )
        {
            gindex += 2;
            if (gindex < record_size)
            {
                _ret = dublicate_pointer(face.hdmx_table);
                _ret.pos += (8 + nn * record_size + gindex);
            }

            break;
        }
    }

    return _ret;
}

function compute_glyph_metrics(loader, glyph_index)
{
    var bbox = new FT_BBox();
    var face = loader.face;
    var y_scale = 0x10000;
    var glyph = loader.glyph;
    var size = loader.size;

    if ((loader.load_flags & 1) == 0)
        y_scale = size.metrics.y_scale;

    if (glyph.format != 1668246896)
        FT_Outline_Get_CBox(glyph.outline, bbox);
    else
    {
        bbox.xMin = loader.bbox.xMin;
        bbox.yMin = loader.bbox.yMin;
        bbox.xMax = loader.bbox.xMax;
        bbox.yMax = loader.bbox.yMax;
    }

    glyph.linearHoriAdvance = loader.linear;

    glyph.metrics.horiBearingX = bbox.xMin;
    glyph.metrics.horiBearingY = bbox.yMax;
    glyph.metrics.horiAdvance  = loader.pp2.x - loader.pp1.x;

    if (face.postscript.isFixedPitch == 0 && (loader.load_flags & 2) == 0)
    {
        var widthp = tt_face_get_device_metrics(face, loader.size.metrics.x_ppem, glyph_index);

        if (face.driver.library.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING)
        {
            var ignore_x_mode = (FT_LOAD_TARGET_MODE(loader.load_flags) != 2);

            if (null != widthp && ((ignore_x_mode && loader.exec.compatible_widths) || !ignore_x_mode || false))
                glyph.metrics.horiAdvance = widthp.data[widthp.pos] << 6;
        }
        else
        {
            if (null != widthp)
                glyph.metrics.horiAdvance = widthp.data[widthp.pos] << 6;
        }
    }

    glyph.metrics.width  = bbox.xMax - bbox.xMin;
    glyph.metrics.height = bbox.yMax - bbox.yMin;

    var top;
    var advance;

    if (face.vertical_info === 1 && face.vertical.number_Of_VMetrics > 0)
    {
        top = FT_DivFix(loader.pp3.y - bbox.yMax, y_scale);

        if (loader.pp3.y <= loader.pp4.y)
            advance = 0;
        else
            advance = FT_DivFix(loader.pp3.y - loader.pp4.y, y_scale);
    }
    else
    {
        var height = FT_DivFix(bbox.yMax - bbox.yMin, y_scale);
        if (face.os2.version != 0xFFFF)
            advance = face.os2.sTypoAscender - face.os2.sTypoDescender;
        else
            advance = face.horizontal.Ascender - face.horizontal.Descender;

        top = parseInt((advance - height)/2);
    }

    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
    var metrics = new FT_Incremental_MetricsRec();

    var incr = face.internal.incremental_interface;
    if (incr && incr.funcs.get_glyph_metrics)
    {
        metrics.bearing_x = 0;
        metrics.bearing_y = top;
        metrics.advance   = advance;

        var error = incr.funcs.get_glyph_metrics(incr.object, glyph_index, true, metrics);
        if (error != 0)
            return error;

        top     = metrics.bearing_y;
        advance = metrics.advance;
    }
    //#endif

    glyph.linearVertAdvance = advance;

    /* scale the metrics */
    if (0 == (loader.load_flags & 1))
    {
        top     = FT_MulFix(top, y_scale);
        advance = FT_MulFix(advance, y_scale);
    }

    glyph.metrics.vertBearingX = glyph.metrics.horiBearingX - parseInt(glyph.metrics.horiAdvance / 2);
    glyph.metrics.vertBearingY = top;
    glyph.metrics.vertAdvance  = advance;

    return 0;
}
function TT_Load_Glyph(size, glyph, glyph_index, load_flags)
{
    var loader = new TT_LoaderRec();
    var face = glyph.face;
    var error = 0;

    //#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
    if (size.strike_index != 0xFFFFFFFF && ((load_flags & 8) == 0))
    {
        error = load_sbit_image(size, glyph, glyph_index, load_flags);
        if (error == 0)
        {
            if ((face.face_flags & 1) != 0)
            {
                tt_loader_init(loader, size, glyph, load_flags, true);
                load_truetype_glyph(loader, glyph_index, 0, true);
                glyph.linearHoriAdvance = loader.linear;
                glyph.linearVertAdvance = loader.top_bearing + loader.bbox.yMax - loader.vadvance;
            }

            return 0;
        }
    }
    //#endif

    if ((0 == (load_flags & 1)) && (size.ttmetrics.valid == 0))
        return 36;

    if ((load_flags & 16384) != 0)
        return 6;

    error = tt_loader_init(loader, size, glyph, load_flags, false);
    if (error != 0)
        return error;

    glyph.format        = 1869968492;
    glyph.num_subglyphs = 0;
    glyph.outline.flags = 0;

    /* main loading loop */
    error = load_truetype_glyph(loader, glyph_index, 0, false);
    if (error == 0)
    {
        if (glyph.format == 1668246896)
        {
            glyph.num_subglyphs = loader.gloader.base.num_subglyphs;
            glyph.subglyphs     = loader.gloader.base.subglyphs;
        }
        else
        {
            EquatingOutline(glyph.outline, loader.gloader.base.outline);
            glyph.outline.flags &= ~512;

            if (loader.pp1.x != 0)
                FT_Outline_Translate(glyph.outline, -loader.pp1.x, 0);
        }

        if (face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER && ((load_flags & 2) == 0))
        {
            if (loader.exec.GS.scan_control)
            {
                /* convert scan conversion mode to FT_OUTLINE_XXX flags */
                switch (loader.exec.GS.scan_type)
                {
                case 0: /* simple drop-outs including stubs */
                    glyph.outline.flags |= 32;
                    break;
                case 1: /* simple drop-outs excluding stubs */
                    /* nothing; it's the default rendering mode */
                    break;
                case 4: /* smart drop-outs including stubs */
                    glyph.outline.flags |= (16 | 32);
                    break;
                case 5: /* smart drop-outs excluding stubs  */
                    glyph.outline.flags |= 16;
                    break;

                default: /* no drop-out control */
                    glyph.outline.flags |= 8;
                    break;
                }
            }
            else
                glyph.outline.flags |= 8;
        }
        compute_glyph_metrics(loader, glyph_index);
    }

    if ((0 == (load_flags & 1)) && size.metrics.y_ppem < 24)
        glyph.outline.flags |= 256;

    return error;
}

function load_truetype_glyph(loader, glyph_index, recurse_count, header_only)
{
    var error = 0;
    var x_scale, y_scale;
    var offset;
    var face = loader.face;
    var gloader = loader.gloader;
    var opened_frame = 0;

    var glyph_data;
    var glyph_data_loaded = 0;

    if (recurse_count > 1 && recurse_count > face.max_profile.maxComponentDepth )
        return 21;

    if (glyph_index >= face.num_glyphs)
        error = 16;

    loader.glyph_index = glyph_index;

    if ((loader.load_flags & 1) == 0)
    {
        x_scale = loader.size.metrics.x_scale;
        y_scale = loader.size.metrics.y_scale;
    }
    else
    {
        x_scale = 0x10000;
        y_scale = 0x10000;
    }

    tt_get_metrics(loader, glyph_index);

    if (face.internal.incremental_interface != null)
    {
        glyph_data = face.internal.incremental_interface.funcs.get_glyph_data(face.internal.incremental_interface.object, glyph_index);
        error = FT_Error;
        if (error != 0)
            return error;

        glyph_data_loaded = 1;
        offset = 0;
        loader.byte_len  = glyph_data.length;

        loader.stream = new FT_Stream(glyph_data.pointer, glyph_data.length);
    }
    else
    {
        var __mem = tt_face_get_location(face, glyph_index);
        offset = __mem.loc;
        loader.byte_len = __mem.size;
    }

    if (loader.byte_len > 0)
    {
        if (0 == loader.glyf_offset && null == face.internal.incremental_interface)
            return 8;

        error = face.access_glyph_frame(loader, glyph_index, loader.glyf_offset + offset, loader.byte_len);
        if (error != 0)
            return error;

        opened_frame = 1;

        error = face.read_glyph_header(loader);
        if (error != 0 || header_only)
            return error;
    }

    var subpixel_ = (loader.exec && loader.exec.subpixel_hinting) ? true : false;
    var grayscale_ = (loader.exec && loader.exec.grayscale_hinting) ? true : false;
    var use_aw_2_  = (subpixel_ && grayscale_);

    if (loader.byte_len == 0 || loader.n_contours == 0)
    {
        loader.bbox.xMin = 0;
        loader.bbox.xMax = 0;
        loader.bbox.yMin = 0;
        loader.bbox.yMax = 0;

        if (header_only == 1)
            return error;

        loader.pp1.x = loader.bbox.xMin - loader.left_bearing;
        loader.pp1.y = 0;
        loader.pp2.x = loader.pp1.x + loader.advance;
        loader.pp2.y = 0;
        loader.pp3.x = use_aw_2_ ? (loader.advance >> 0) : 0;
        loader.pp3.y = loader.top_bearing + loader.bbox.yMax;
        loader.pp4.x = use_aw_2_ ? (loader.advance >> 0) : 0;
        loader.pp4.y = loader.pp3.y - loader.vadvance;

        //#ifdef FT_CONFIG_OPTION_INCREMENTAL
        tt_get_metrics_incr_overrides(loader, glyph_index);
        //#endif

        //#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
        if (loader.face.doblend != 0)
        {
            var deltas = TT_Vary_Get_Glyph_Deltas(loader.face, glyph_index, 4);
            error = FT_Error;
            if (error != 0)
                return error;

            loader.pp1.x += deltas[0].x; loader.pp1.y += deltas[0].y;
            loader.pp2.x += deltas[1].x; loader.pp2.y += deltas[1].y;
            loader.pp3.x += deltas[2].x; loader.pp3.y += deltas[2].y;
            loader.pp4.x += deltas[3].x; loader.pp4.y += deltas[3].y;

            deltas = null;
        }
        //#endif

        if ((loader.load_flags & 1) == 0)
        {
            loader.pp1.x = FT_MulFix(loader.pp1.x, x_scale);
            loader.pp2.x = FT_MulFix(loader.pp2.x, x_scale);
            loader.pp3.y = FT_MulFix(loader.pp3.y, y_scale);
            loader.pp4.y = FT_MulFix(loader.pp4.y, y_scale);
        }

        error = 0;
        return error;
    }

    loader.pp1.x = loader.bbox.xMin - loader.left_bearing;
    loader.pp1.y = 0;
    loader.pp2.x = loader.pp1.x + loader.advance;
    loader.pp2.y = 0;
    loader.pp3.x = use_aw_2_ ? (loader.advance >> 0) : 0;
    loader.pp3.y = loader.top_bearing + loader.bbox.yMax;
    loader.pp4.x = use_aw_2_ ? (loader.advance >> 0) : 0;
    loader.pp4.y = loader.pp3.y - loader.vadvance;

    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
    tt_get_metrics_incr_overrides(loader, glyph_index);
    //#endif

    if (loader.n_contours > 0)
    {
        error = face.read_simple_glyph( loader );
        if (error != 0)
            return error;

        face.forget_glyph_frame(loader);
        opened_frame = 0;

        error = TT_Process_Simple_Glyph(loader);
        if (error != 0)
            return error;

        FT_GlyphLoader_Add(gloader);
    }
    else if (loader.n_contours == -1)
    {
        var start_point = gloader.base.outline.n_points;
        var start_contour = gloader.base.outline.n_contours;

        error = face.read_composite_glyph(loader);
        if (error != 0)
            return error;

        var ins_pos = loader.ins_pos;

        face.forget_glyph_frame( loader );
        opened_frame = 0;

        //#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT

        if (face.doblend != 0)
        {
            var deltas = TT_Vary_Get_Glyph_Deltas(face, glyph_index, gloader.current.num_subglyphs + 4);
            error = FT_Error;
            if (error != 0)
                return error;

            var subglyph = gloader.current.subglyphs[gloader.base.num_subglyphs];
            var limit = gloader.current.num_subglyphs;

            var i = 0;
            for (; i < limit; ++i, ++subglyph )
            {
                if (subglyph.flags & 2)
                {
                    subglyph.arg1 += (deltas[i].x & 0xFFFF);
                    subglyph.arg2 += (deltas[i].y & 0xFFFF);
                }
            }

            loader.pp1.x += deltas[i + 0].x; loader.pp1.y += deltas[i + 0].y;
            loader.pp2.x += deltas[i + 1].x; loader.pp2.y += deltas[i + 1].y;
            loader.pp3.x += deltas[i + 2].x; loader.pp3.y += deltas[i + 2].y;
            loader.pp4.x += deltas[i + 3].x; loader.pp4.y += deltas[i + 3].y;

            deltas = null;
        }
        //#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */

        if ((loader.load_flags & 1) == 0)
        {
            loader.pp1.x = FT_MulFix(loader.pp1.x, x_scale);
            loader.pp2.x = FT_MulFix(loader.pp2.x, x_scale);
            loader.pp3.y = FT_MulFix(loader.pp3.y, y_scale);
            loader.pp4.y = FT_MulFix(loader.pp4.y, y_scale);
        }

        if ((loader.load_flags & 1024) != 0)
        {
            FT_GlyphLoader_Add( gloader );
            loader.glyph.format = 1668246896;

            return error;
        }

        var n, num_base_points;
        var subglyph       = 0;

        var num_points     = start_point;
        var num_subglyphs  = gloader.current.num_subglyphs;
        var num_base_subgs = gloader.base.num_subglyphs;

        var old_stream = loader.stream;
        var old_byte_len = loader.byte_len;

        FT_GlyphLoader_Add(gloader);

        for ( n = 0; n < num_subglyphs; n++ )
        {
            var pp = new Array(4);
            subglyph = gloader.base.subglyphs[num_base_subgs + n];

            pp[0] = loader.pp1;
            pp[1] = loader.pp2;
            pp[2] = loader.pp3;
            pp[3] = loader.pp4;

            num_base_points = gloader.base.outline.n_points;

            error = load_truetype_glyph(loader, subglyph.index, recurse_count + 1, 0);
            if (error != 0)
                return error;

            subglyph = gloader.base.subglyphs[num_base_subgs + n];

            if (0 == (subglyph.flags & 0x0200))
            {
                loader.pp1 = pp[0];
                loader.pp2 = pp[1];
                loader.pp3 = pp[2];
                loader.pp4 = pp[3];
            }

            if (gloader.base.outline.n_points == num_base_points)
                continue;

            TT_Process_Composite_Component(loader, subglyph, start_point, num_base_points);
        }

        loader.stream   = old_stream;
        loader.byte_len = old_byte_len;

        loader.ins_pos = ins_pos;

        var bIsSubFlags = true;
        if (bIsSubFlags && face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER)
            bIsSubFlags = ((subglyph.flags & 256) != 0);

        if (((loader.load_flags & 2) == 0) && bIsSubFlags && num_points > start_point)
            TT_Process_Composite_Glyph(loader, start_point, start_contour);
    }
    else
        return 20;

    if (opened_frame == 1)
        face.forget_glyph_frame(loader);

    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
    if (glyph_data_loaded != 0)
    {
        face.internal.incremental_interface.funcs.free_glyph_data(face.internal.incremental_interface.object, glyph_data);
        glyph_data = null;
    }
    //#endif
    return error;
}
function TT_Init_Glyph_Loading(face)
{
    face.access_glyph_frame   = TT_Access_Glyph_Frame;
    face.read_glyph_header    = TT_Load_Glyph_Header;
    face.read_simple_glyph    = TT_Load_Simple_Glyph;
    face.read_composite_glyph = TT_Load_Composite_Glyph;
    face.forget_glyph_frame   = TT_Forget_Glyph_Frame;
}
/******************************************************************************/
// driver
/******************************************************************************/
var tt_service_truetype_engine = new FT_Service_TrueTypeEngineRec(0);
var tt_service_truetype_glyf = new FT_Service_TTGlyfRec(tt_face_get_location);
var tt_service_gx_multi_masters = new FT_Service_MultiMastersRec(null,null,TT_Set_MM_Blend,TT_Get_MM_Var,TT_Set_Var_Design);
var tt_services = new Array(4);
tt_services[0] = new FT_ServiceDescRec(FT_SERVICE_ID_XF86_NAME,FT_XF86_FORMAT_TRUETYPE);
tt_services[1] = new FT_ServiceDescRec(FT_SERVICE_ID_MULTI_MASTERS,tt_service_gx_multi_masters);
tt_services[2] = new FT_ServiceDescRec(FT_SERVICE_ID_TRUETYPE_ENGINE,tt_service_truetype_engine);
tt_services[3] = new FT_ServiceDescRec(FT_SERVICE_ID_TT_GLYF,tt_service_truetype_glyf);

var FT_TT_SERVICES_GET                  = tt_services;
var FT_TT_SERVICE_GX_MULTI_MASTERS_GET  = tt_service_gx_multi_masters;
var FT_TT_SERVICE_TRUETYPE_GLYF_GET     = tt_service_truetype_glyf;

function tt_check_trickyness_sfnt_ids(face)
{
    var checksum = 0;
    var i = 0;
    var j = 0;
    var k = 0;
    var num_matched_ids = new Array(13);
    for (var l = 0; l < 13; l++)
        num_matched_ids[l] = 0;

    var TRICK_SFNT_ID_cvt = 0;
    var TRICK_SFNT_ID_fpgm = 1;
    var TRICK_SFNT_ID_prep = 2;

    var has_cvt  = false;
    var has_fpgm = false;
    var has_prep = false;

    var sfnt_id = face.driver.sfnt_id;

    for (i = 0; i < face.num_tables; i++)
    {
        checksum = 0;
        switch(face.dir_tables[i].Tag)
        {
            case 1668707360:
                k = TRICK_SFNT_ID_cvt;
                has_cvt  = true;
                break;

            case 1718642541:
                k = TRICK_SFNT_ID_fpgm;
                has_fpgm = true;
                break;

            case 1886545264:
                k = TRICK_SFNT_ID_prep;
                has_prep = true;
                break;

            default:
                continue;
        }

        for ( j = 0; j < 13; j++ )
            if ( face.dir_tables[i].Length == sfnt_id[j][k].Length )
            {
                if (checksum != 0)
                    checksum = tt_get_sfnt_checksum(face, i);

                if (sfnt_id[j][k].CheckSum == checksum)
                    num_matched_ids[j]++;

                if (num_matched_ids[j] == 3)
                    return true;
            }
    }
    for (j = 0; j < 13; j++)
    {
        if ( !has_cvt  && !sfnt_id[j][TRICK_SFNT_ID_cvt].Length )
            num_matched_ids[j] ++;
        if ( !has_fpgm && !sfnt_id[j][TRICK_SFNT_ID_fpgm].Length )
            num_matched_ids[j] ++;
        if ( !has_prep && !sfnt_id[j][TRICK_SFNT_ID_prep].Length )
            num_matched_ids[j] ++;
        if (num_matched_ids[j] == 3)
            return true;
    }
    return false;
}
function tt_get_sfnt_checksum(face, i)
{
    if (!face.goto_table)
        return 0;

    var len = face.goto_table(face, face.dir_tables[i].Tag, face.stream);
        return 0;

    if (FT_Error != 0)
        return 0;

    return tt_synth_sfnt_checksum(face.stream, face.dir_tables[i].Length);
}
function tt_synth_sfnt_checksum(stream, length)
{
    var error = 0;
    var checksum = 0;
    var i = 0;

    var len = length;
    if (0 != stream.EnterFrame(len))
        return 0;

    for ( ; len > 3; len -= 4 )
        checksum += stream.GetULong();

    for ( i = 3; len > 0; len --,i--)
        checksum += (stream.GetUChar() << (i * 8));

    stream.ExitFrame();
    return checksum;
}
function tt_check_trickyness(face)
{
    if (!face)
        return false;

    if ((face.family_name != "") && (tt_check_trickyness_family(face.family_name) === true))
        return true;

    return tt_check_trickyness_sfnt_ids(face);
}
function tt_check_trickyness_family(name)
{
    if (name == "DFKaiSho-SB")
        return true;
    if (name == "DFKaiShu")
        return true;
    if (name == "DFKai-SB")
        return true;
    if (name == "HuaTianKaiTi?")
        return true;
    if (name == "HuaTianSongTi?")
        return true;
    if (name == "MingLiU")
        return true;
    if (name == "PMingLiU")
        return true;
    if (name == "MingLi43")
        return true;
    return false;
}
function tt_face_load_hdmx(face, stream)
{
    var error = 0;
    var version = 0;
    var nn = 0;
    var num_records = 0;
    var table_size = 0;
    var record_size = 0;

    table_size = face.goto_table(face, 1751412088, stream);
    if ( (FT_Error != 0) || table_size < 8 )
    {
		FT_Error = 0;
		return 0;
	}

    face.hdmx_table = new CPointer();
    error = stream.ExtractFrame(table_size, face.hdmx_table);
    if (error != 0)
        return error;

    var p = dublicate_pointer(face.hdmx_table);
    var end = p.pos + table_size;

    version     = FT_NEXT_USHORT(p);
    num_records = FT_NEXT_USHORT(p);
    record_size = FT_NEXT_ULONG(p);

    if (record_size >= 0xFFFF0000)
        record_size &= 0xFFFF;

    if (version != 0 || num_records > 255 || record_size > 0x10001)
    {
        error = 3;
        face.hdmx_table = null;
        face.hdmx_table_size = 0;
        stream.ReleaseFrame();
        return error;
    }

    if (0 != num_records)
        face.hdmx_record_sizes = new Array(num_records);

    for ( nn = 0; nn < num_records; nn++ )
    {
        if ( (p.pos + record_size) > end )
            break;

        face.hdmx_record_sizes[nn] = p.data[p.pos];
        p.pos += record_size;
    }

    face.hdmx_record_count = nn;
    face.hdmx_table_size   = table_size;
    face.hdmx_record_size  = record_size;

    return error;
}

function tt_face_load_loca(face, stream)
{
    var error = 0;
    var table_len = 0;
    var shift = 0;

    face.glyf_len = face.goto_table(face, 1735162214, stream);
    error = FT_Error;

    if ( error == 142)
        face.glyf_len = 0;
    else if (error != 0)
        return error;

    table_len = face.goto_table(face, 1819239265, stream);
    error = FT_Error;
    if (error != 0)
    {
        error = 144;
        return error;
    }

    if (face.header.Index_To_Loc_Format != 0)
    {
        shift = 2;
        if (table_len >= 0x40000)
        {
            error = 8;
            return error;
        }
        face.num_locations = table_len >>> shift;
    }
    else
    {
        shift = 1;

        if (table_len >= 0x20000)
        {
            error = 8;
            return error;
        }
        face.num_locations = table_len >>> shift;
    }

    if (face.num_locations != (face.num_glyphs + 1))
    {
        if (face.num_locations <= face.num_glyphs)
        {
            var new_loca_len = (face.num_glyphs + 1) << shift;

            var pos = stream.pos;
            var dist = 0x7FFFFFFF;

            var entry = 0;
            for (; entry < face.num_tables; entry++)
            {
                var diff = face.dir_tables[entry].Offset - pos;
                if (diff > 0 && diff < dist)
                    dist = diff;
            }

            if (entry == face.num_tables)
            {
                dist = stream.size - pos;
            }

            if (new_loca_len <= dist)
            {
                face.num_locations = face.num_glyphs + 1;
                table_len          = new_loca_len;
            }
        }
    }

    face.glyph_locations = new CPointer();
    error = stream.ExtractFrame(table_len, face.glyph_locations);
    return error;
}
function tt_face_get_location(face, gindex)
{
    var pos1 = 0;
    var pos2 = 0;
    var asize = 0;

    pos1 = pos2 = 0;
    var p = new CPointer();
    p.data = face.glyph_locations.data;
    var pos_s = face.glyph_locations.pos;
    var p_limit = 0;
    if (gindex < face.num_locations)
    {
        if (face.header.Index_To_Loc_Format != 0)
        {
            p.pos = pos_s + gindex * 4;
            p_limit = pos_s + face.num_locations * 4;

            pos1 = FT_NEXT_ULONG(p);
            pos2 = pos1;

            if (p.pos + 4 <= p_limit)
                pos2 = FT_NEXT_ULONG(p);
        }
        else
        {
            p.pos  = pos_s + gindex * 2;
            p_limit = pos_s + face.num_locations * 2;

            pos1 = FT_NEXT_USHORT(p);
            pos2 = pos1;

            if (p.pos + 2 <= p_limit)
                pos2 = FT_NEXT_USHORT(p);

            pos1 <<= 1;
            pos2 <<= 1;
        }
    }

    if (pos1 >= face.glyf_len)
        return {loc:0,size:0};

    if (pos2 >= face.glyf_len)
        pos2 = face.glyf_len;

    if (pos2 >= pos1)
        asize = pos2 - pos1;
    else
        asize = face.glyf_len - pos1;

    return {loc:pos1,size:asize};
}
function tt_face_load_cvt(face, stream)
{
    //#ifdef TT_USE_BYTECODE_INTERPRETER
    if (face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER || true)
    {
        var table_len = face.goto_table(face, 1668707360, stream);
        var error = FT_Error;
		FT_Error = 0;

        if (error != 0)
        {
            face.cvt_size = 0;
            face.cvt = null;
            return 0;
        }

        face.cvt_size = table_len / 2;
        face.cvt = CreateIntArray(face.cvt_size);

        error = stream.EnterFrame(table_len);
        if (error != 0)
            return error;

        for (var i = 0; i < face.cvt_size; i++)
            face.cvt[i] = stream.GetShort();
        
        //#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
        if (face.doblend)
            error = tt_face_vary_cvt(face, stream);
        //#endif

        return error;
    }
    //#endif
    return 0;
}
function tt_face_load_fpgm(face, stream)
{
    //#ifdef TT_USE_BYTECODE_INTERPRETER
    if (face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER || true)
    {
        /* The font program is optional */
        var table_len = face.goto_table(face, 1718642541, stream);
        var error = FT_Error;
		FT_Error = 0;
		
        if (error != 0)
        {
            face.font_program = null;
            face.font_program_size = 0;
            error = 0;
            return error;
        }
        else
        {
            face.font_program_size = table_len;
            face.font_program = new CPointer();
            return stream.ExtractFrame(table_len, face.font_program);
        }
    }
    //#endif
    return 0;
}
function tt_face_load_prep(face, stream)
{
    //#ifdef TT_USE_BYTECODE_INTERPRETER
    if (face.driver.library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER || true)
    {
        var table_len = face.goto_table(face, 1886545264, stream);
        var error = FT_Error;
		FT_Error = 0;
		
        if (error != 0)
        {
            face.cvt_program = null;
            face.cvt_program_size = 0;
            return 0;
        }
        else
        {
            face.cvt_program_size = table_len;
            face.cvt_program = new CPointer();
            return stream.ExtractFrame(table_len, face.cvt_program);
        }
    }
    //#endif
    return 0;
}
function tt_check_single_notdef(face)
{
    var result = false;

    var asize = 0;
    var i = 0;
    var glyph_index = 0;
    var count = 0;

    for( i = 0; i < face.num_locations; i++ )
    {
        asize = tt_face_get_location(face, i).size;
        if ( asize > 0 )
        {
            count += 1;
            if ( count > 1 )
                break;
            glyph_index = i;
        }
    }

    /* Only have a single outline. */
    if (count == 1)
    {
        if (glyph_index == 0)
            result = true;
        else
        {
            /* FIXME: Need to test glyphname == .notdef ? */
            FT_Error = 0;
            var buffer = g_memory.Alloc(10);
            buffer.pos = 0;

            FT_Get_Glyph_Name(face, glyph_index, buffer, 8);
            var buf = "";
            for (var i = 0; i < 10; i++)
            {
                buf += String.fromCharCode(buffer.data[i]);
            }

            if (FT_Error != 0 && buf[0] == '.' && (0 == _strncmp(buf,".notdef",8)))
                result = true;
        }
    }

    FT_Error = 0;
    return result;
}

function tt_driver_init(ttdriver)
{
    var _tt_hint_props = ttdriver.library.tt_hint_props;
    if (_tt_hint_props.TT_USE_BYTECODE_INTERPRETER || true)
    {
        if (!TT_New_Context(ttdriver))
            153;
    }
    return 0;
}
function tt_driver_done(ttdriver)
{
    var _tt_hint_props = ttdriver.library.tt_hint_props;
    if (_tt_hint_props.TT_USE_BYTECODE_INTERPRETER || true)
    {
        if (ttdriver.context != null)
        {
            TT_Done_Context(ttdriver.context);
            ttdriver.context = null;
        }
    }
}
function tt_get_interface(driver, tt_interface)
{
    var result = ft_service_list_lookup(FT_TT_SERVICES_GET, tt_interface);
    if (result != null)
        return result;

    if (driver == null)
        return null;

    var sfntd = driver.library.FT_Get_Module("sfnt");
    if (null != sfntd)
    {
        var sfnt = sfntd.clazz.module_interface;
        if (null != sfnt)
            return sfnt.get_interface(driver, tt_interface);
    }
    return null;
}
function tt_face_init(stream, face, face_index)
{
    var error = 0;
    var library = face.driver.library;
    var sfnt = library.FT_Get_Module_Interface("sfnt");

    error = stream.Seek(0);
    if (error != 0)
        return error;

    error = sfnt.init_face(stream, face, face_index);
    if (error != 0)
        return error;

    if (face.format_tag != 0x00010000 && face.format_tag != 0x00020000 && face.format_tag != 1953658213)
    {
        error = 2;
        return error;
    }

    if (library.tt_hint_props.TT_USE_BYTECODE_INTERPRETER || true)
        face.face_flags |= 2048;

    if ( face_index < 0 )
        return 0;

    error = sfnt.load_face(stream, face, face_index);
    if (error != 0)
        return error;

    if (tt_check_trickyness(face) === true)
        face.face_flags |= 8192;

    error = tt_face_load_hdmx(face, stream);
    if (error != 0)
        return error;

    if ((face.face_flags & 1) != 0)
    {
        //#ifdef FT_CONFIG_OPTION_INCREMENTAL
        if (null == face.internal.incremental_interface)
            error = tt_face_load_loca(face, stream);
        if (error == 0)
            error = tt_face_load_cvt(face, stream);
        if (error == 0)
            error = tt_face_load_fpgm(face, stream);
        if (error == 0)
            error = tt_face_load_prep(face, stream);

        /* Check the scalable flag based on `loca'. */
        if ((null == face.internal.incremental_interface) && (0 != face.num_fixed_sizes) && (face.glyph_locations != null) &&
            tt_check_single_notdef(face))
        {
            face.face_flags &= ~1;
        }
        //#endif
    }

    //#if defined( TT_CONFIG_OPTION_UNPATENTED_HINTING )
    // TODO:
    //#endif

    TT_Init_Glyph_Loading(face);
    return error;
}
function tt_face_done(face)
{
}
function tt_size_init()
{
    var size  = new TT_SizeRec();

    //#ifdef TT_USE_BYTECODE_INTERPRETER
    size.bytecode_ready = 0;
    size.cvt_ready      = 0;
    //#endif

    size.ttmetrics.valid = 0;
    size.strike_index = 0xFFFFFFFF;

    return size;
}
function tt_size_done(size)
{
    //#ifdef TT_USE_BYTECODE_INTERPRETER
    if (size.bytecode_ready)
        tt_size_done_bytecode(size);
    //#endif
    size.ttmetrics.valid = 0;
}
function tt_slot_init(slot)
{
    return FT_GlyphLoader_CreateExtra(slot.internal.loader);
}
function Load_Glyph(slot, size, glyph_index, load_flags)
{
    var face = slot.face;
    var error = 0;

    if (!slot)
        return 37;

    if (!size)
        return 36;

    if (!face)
        return 6;

    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
    if (glyph_index >= face.num_glyphs && (null == face.internal.incremental_interface))
        return 6;

    if ((load_flags & 2) != 0)
    {
        if ((face.face_flags & 8192) != 0)
            load_flags &= ~2;

        if ((load_flags & 32768) != 0)
            load_flags |= 2;
    }

    if ((load_flags & (1024 | 1)) != 0)
    {
        load_flags |= (8 | 1);

        if ((face.face_flags & 8192) == 0)
            load_flags |= 2;
    }

    error = TT_Load_Glyph(size, slot, glyph_index, load_flags);
    return error;
}
function tt_get_kerning(face, left_glyph, right_glyph, kerning)
{
    kerning.x = 0;
    kerning.y = 0;

    if (face.sfnt)
        kerning.x = face.sfnt.get_kerning(face, left_glyph, right_glyph);

    return 0;
}
function tt_get_advances(face, start, count, flags, advances)
{
    /* XXX: TODO: check for sbits */
    if ((face.face_flags & 16) != 0)
    {
        for (var nn = 0; nn < count; nn++)
        {
            /* since we don't need `tsb', we use zero for `yMax' parameter */
            var res = TT_Get_VMetrics(face, start + nn, 0);
            advances[nn] = res.ah;
        }
    }
    else
    {
        for (var nn = 0; nn < count; nn++)
        {
            var res = TT_Get_HMetrics(face, start);
            advances[nn] = res.aw;
        }
    }

    return 0;
}
function tt_size_request(size, req)
{
    var error = 0;

    //#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
    if ((size.face.face_flags & 2) != 0)
    {
        var sfnt = size.face.sfnt;
        var strike_index = sfnt.set_sbit_strike(size.face, req);

        error = FT_Error;
        FT_Error = 0;

        if (error != 0)
            size.strike_index = 0xFFFFFFFF;
    else
        return this.select_size(size, strike_index);
    }
    //#endif

    FT_Request_Metrics(size.face, req);

    if ((size.face.face_flags & 1) != 0)
    {
        error = tt_size_reset(size);

        var s = size._metrics;
        var d = size.metrics;

        d.x_ppem = s.x_ppem;
        d.y_ppem = s.y_ppem;

        d.x_scale = s.x_scale;
        d.y_scale = s.y_scale;

        d.ascender = s.ascender;
        d.descender = s.descender;
        d.height = s.height;
        d.max_advance = s.max_advance;
    }

    return error;
}
function tt_size_select(size, strike_index)
{
    var ttface = size.face;
    var error = 0;
    size.strike_index = strike_index;

    if ((ttface.face_flags & 1) != 0)
    {
        FT_Select_Metrics(ttface, strike_index);
        tt_size_reset(size);
    }
    else
    {
        var sfnt = ttface.sfnt;
        var metrics = size.metrics;

        error = sfnt.load_strike_metrics(ttface, strike_index, metrics);
        if (error != 0)
            size.strike_index = 0xFFFFFFFF;
    }
    return error;
}

function tt_size_reset(size)
{
    size.ttmetrics.valid = 0;
    var face = size.face;

    var d = size._metrics;
    var s = size.metrics;

    d.x_ppem = s.x_ppem;
    d.y_ppem = s.y_ppem;

    d.x_scale = s.x_scale;
    d.y_scale = s.y_scale;

    d.ascender = s.ascender;
    d.descender = s.descender;
    d.height = s.height;
    d.max_advance = s.max_advance;

    if (d.x_ppem < 1 || d.y_ppem < 1)
        return 151;

    if (face.header.Flags & 8)
    {
        d.x_scale = FT_DivFix(d.x_ppem << 6, face.units_per_EM);
        d.y_scale = FT_DivFix(d.y_ppem << 6, face.units_per_EM);

        d.ascender = FT_PIX_ROUND(FT_MulFix(face.ascender, d.y_scale));
        d.descender = FT_PIX_ROUND(FT_MulFix(face.descender, d.y_scale));
        d.height = FT_PIX_ROUND(FT_MulFix(face.height, d.y_scale));
        d.max_advance = FT_PIX_ROUND(FT_MulFix(face.max_advance_width, d.x_scale));
    }

    var tt = size.ttmetrics;
    /* compute new transformation */
    if (d.x_ppem >= d.y_ppem)
    {
        tt.scale   = d.x_scale;
        tt.ppem    = d.x_ppem;
        tt.x_ratio = 0x10000;
        tt.y_ratio = FT_MulDiv(d.y_ppem, 0x10000, d.x_ppem);
    }
    else
    {
        tt.scale   = d.y_scale;
        tt.ppem    = d.y_ppem;
        tt.x_ratio = FT_MulDiv(d.x_ppem, 0x10000, d.y_ppem);
        tt.y_ratio = 0x10000;
    }

    //#ifdef TT_USE_BYTECODE_INTERPRETER
    // TODO:
    //#endif

    size.ttmetrics.valid = 1;
    return 0;
}

function TT_Driver_Class()
{
    this.flags = 0x101;
    this.name = "truetype";
    this.version = 0x10000;
    this.requires = 0x20000;

    this.module_interface = null;

    this.init = tt_driver_init;
    this.done = tt_driver_done;
    this.get_interface = tt_get_interface;

    this.face_object_size = 0;
    this.size_object_size = 0;
    this.slot_object_size = 0;

    this.init_face = tt_face_init;
    this.done_face = tt_face_done;

    this.init_size = tt_size_init;
    this.done_size = tt_size_done;

    this.init_slot = tt_slot_init;
    this.done_slot = null;

    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    this.set_char_sizes = ft_stub_set_char_sizes;
    this.set_pixel_sizes = ft_stub_set_pixel_sizes;
    //#endif

    this.load_glyph = Load_Glyph;

    this.get_kerning = tt_get_kerning;
    this.attach_file = null;
    this.get_advances = tt_get_advances;

    this.request_size = tt_size_request;
    this.select_size = tt_size_select;
}

function tt_sfnt_id_rec(c,l)
{
    this.CheckSum = c;
    this.Length = l;
}

function TT_Driver()
{
    this.clazz = null;      // FT_Module_Class
    this.library = null;    // FT_Library
    this.memory = null;     // FT_Memory
    this.generic = null;    // FT_Generic

    this.clazz = new TT_Driver_Class();
    this.faces_list = [];
    this.extensions = null;
    this.glyph_loader = null;

    this.context = null;
    this.zone = new TT_GlyphZoneRec();
    this.extension_component = null;

    this.open_face = function(stream, face_index)
    {
        if (null == this.sfnt_id)
        {
            this.sfnt_id = new Array(13);
            this.sfnt_id[0] = new Array(3);
            this.sfnt_id[0][0] = new tt_sfnt_id_rec(0x05bcf058, 0x000002e4);
            this.sfnt_id[0][1] = new tt_sfnt_id_rec(0x28233bf1, 0x000087c4);
            this.sfnt_id[0][2] = new tt_sfnt_id_rec(0xa344a1ea, 0x000001e1);

            this.sfnt_id[1] = new Array(3);
            this.sfnt_id[1][0] = new tt_sfnt_id_rec(0x05bcf058, 0x000002e4);
            this.sfnt_id[1][1] = new tt_sfnt_id_rec(0x28233bf1, 0x000087c4);
            this.sfnt_id[1][2] = new tt_sfnt_id_rec(0xa344a1eb, 0x000001e1);

            this.sfnt_id[2] = new Array(3);
            this.sfnt_id[2][0] = new tt_sfnt_id_rec(0x11e5ead4, 0x00000350);
            this.sfnt_id[2][1] = new tt_sfnt_id_rec(0x5a30ca3b, 0x00009063);
            this.sfnt_id[2][2] = new tt_sfnt_id_rec(0x13a42602, 0x0000007e);

            this.sfnt_id[3] = new Array(3);
            this.sfnt_id[3][0] = new tt_sfnt_id_rec(0xfffbfffc, 0x00000008);
            this.sfnt_id[3][1] = new tt_sfnt_id_rec(0x9c9e48b8, 0x0000bea2);
            this.sfnt_id[3][2] = new tt_sfnt_id_rec(0x70020112, 0x00000008);

            this.sfnt_id[4] = new Array(3);
            this.sfnt_id[4][0] = new tt_sfnt_id_rec(0xfffbfffc, 0x00000008);
            this.sfnt_id[4][1] = new tt_sfnt_id_rec(0x0a5a0483, 0x00017c39);
            this.sfnt_id[4][2] = new tt_sfnt_id_rec(0x70020112, 0x00000008);

            this.sfnt_id[5] = new Array(3);
            this.sfnt_id[5][0] = new tt_sfnt_id_rec(0x00000000, 0x00000000);
            this.sfnt_id[5][1] = new tt_sfnt_id_rec(0x40c92555, 0x000000e5);
            this.sfnt_id[5][2] = new tt_sfnt_id_rec(0xa39b58e3, 0x0000117c);

            this.sfnt_id[6] = new Array(3);
            this.sfnt_id[6][0] = new tt_sfnt_id_rec(0x00000000, 0x00000000);
            this.sfnt_id[6][1] = new tt_sfnt_id_rec(0x33c41652, 0x000000e5);
            this.sfnt_id[6][2] = new tt_sfnt_id_rec(0x26d6c52a, 0x00000f6a);

            this.sfnt_id[7] = new Array(3);
            this.sfnt_id[7][0] = new tt_sfnt_id_rec(0x00000000, 0x00000000);
            this.sfnt_id[7][1] = new tt_sfnt_id_rec(0x6db1651d, 0x0000019d);
            this.sfnt_id[7][2] = new tt_sfnt_id_rec(0x6c6e4b03, 0x00002492);

            this.sfnt_id[8] = new Array(3);
            this.sfnt_id[8][0] = new tt_sfnt_id_rec(0x00000000, 0x00000000);
            this.sfnt_id[8][1] = new tt_sfnt_id_rec(0x40c92555, 0x000000e5);
            this.sfnt_id[8][2] = new tt_sfnt_id_rec(0xde51fad0, 0x0000117c);

            this.sfnt_id[9] = new Array(3);
            this.sfnt_id[9][0] = new tt_sfnt_id_rec(0x00000000, 0x00000000);
            this.sfnt_id[9][1] = new tt_sfnt_id_rec(0x85e47664, 0x000000e5);
            this.sfnt_id[9][2] = new tt_sfnt_id_rec(0xa6c62831, 0x00001caa);

            this.sfnt_id[10] = new Array(3);
            this.sfnt_id[10][0] = new tt_sfnt_id_rec(0x00000000, 0x00000000);
            this.sfnt_id[10][1] = new tt_sfnt_id_rec(0x2d891cfd, 0x0000019d);
            this.sfnt_id[10][2] = new tt_sfnt_id_rec(0xa0604633, 0x00001de8);

            this.sfnt_id[11] = new Array(3);
            this.sfnt_id[11][0] = new tt_sfnt_id_rec(0x00000000, 0x00000000);
            this.sfnt_id[11][1] = new tt_sfnt_id_rec(0x40aa774c, 0x000001cb);
            this.sfnt_id[11][2] = new tt_sfnt_id_rec(0x9b5caa96, 0x00001f9a);

            this.sfnt_id[12] = new Array(3);
            this.sfnt_id[12][0] = new tt_sfnt_id_rec(0x00000000, 0x00000000);
            this.sfnt_id[12][1] = new tt_sfnt_id_rec(0x0d3de9cb, 0x00000141);
            this.sfnt_id[12][2] = new tt_sfnt_id_rec(0xd4127766, 0x00002280);
        }

        FT_Error = 0;
        var face = new TT_Face();
        var internal = new FT_Face_Internal();

        face.driver = this;
        face.memory = this.memory;
        face.stream = stream;

        //#ifdef FT_CONFIG_OPTION_INCREMENTAL
        face.internal = internal;
        face.internal.incremental_interface = null;
        //#endif

        var err1 = this.clazz.init_face(stream, face, face_index);

        if (err1 != 0)
        {
            face = null;
            FT_Error = err1;
            return null;
        }

        var err2 = find_unicode_charmap(face);
        if (err2 != 0 && err2 != 38)
        {
            face = null;
            FT_Error = err2;
            return null;
        }

		FT_Error = 0;
        return face;
    }
}

function create_tt_driver(library)
{
    var driver = new TT_Driver();
    driver.library = library;
    driver.memory = library.Memory;

    driver.clazz = new TT_Driver_Class();
    return driver;
}
/******************************************************************************/
// cfftypes
/******************************************************************************/
function CFF_IndexRec()
{
    this.stream = null;
    this.start = 0;
    this.count = 0;
    this.off_size = 0;
    this.data_offset = 0;
    this.data_size = 0;

    this.offsets = null;
    this.bytes = null;

    this.clear = function()
    {
        this.stream = null;
        this.start = 0;
        this.count = 0;
        this.off_size = 0;
        this.data_offset = 0;
        this.data_size = 0;

        this.offsets = null;
        this.bytes = null;
    }
}

function CFF_EncodingRec()
{
    this.format = 0;
    this.offset = 0;

    this.count = 0;
    this.sids = CreateIntArray(256);
    this.codes = CreateIntArray(256);
}

function CFF_CharsetRec()
{
    this.format = 0;
    this.offset = 0;

    this.sids = null;
    this.cids = null;

    this.max_cid = 0;
    this.num_glyphs = 0;
}

function CFF_FontRecDictRec()
{
    this.version = 0;
    this.notice = 0;
    this.copyright = 0;
    this.full_name = 0;
    this.family_name = 0;
    this.weight = 0;
    this.is_fixed_pitch = 0;
    this.italic_angle = 0;
    this.underline_position = 0;
    this.underline_thickness = 0;
    this.paint_type = 0;
    this.charstring_type = 0;
    this.font_matrix = new FT_Matrix();
    this.has_font_matrix = 0;
    this.units_per_em = 0;
    this.font_offset = new FT_Vector();
    this.unique_id = 0;
    this.font_bbox = new FT_BBox();
    this.stroke_width = 0;
    this.charset_offset = 0;
    this.encoding_offset = 0;
    this.charstrings_offset = 0;
    this.private_offset = 0;
    this.private_size = 0;
    this.synthetic_base = 0;
    this.embedded_postscript = 0;

    this.cid_registry = 0;
    this.cid_ordering = 0;
    this.cid_supplement = 0;

    this.cid_font_version = 0;
    this.cid_font_revision = 0;
    this.cid_font_type = 0;
    this.cid_count = 0;
    this.cid_uid_base = 0;
    this.cid_fd_array_offset = 0;
    this.cid_fd_select_offset = 0;
    this.cid_font_name = 0;

    this.clear = function()
    {
        this.version = 0;
        this.notice = 0;
        this.copyright = 0;
        this.full_name = 0;
        this.family_name = 0;
        this.weight = 0;
        this.is_fixed_pitch = 0;
        this.italic_angle = 0;
        this.underline_position = 0;
        this.underline_thickness = 0;
        this.paint_type = 0;
        this.charstring_type = 0;

        this.font_matrix.xx = 0;
        this.font_matrix.xy = 0;
        this.font_matrix.yx = 0;
        this.font_matrix.yy = 0;

        this.has_font_matrix = 0;
        this.units_per_em = 0;

        this.font_offset.x = 0;
        this.font_offset.y = 0;

        this.unique_id = 0;

        this.font_bbox.xMin = 0;
        this.font_bbox.yMin = 0;
        this.font_bbox.xMax = 0;
        this.font_bbox.yMax = 0;

        this.stroke_width = 0;
        this.charset_offset = 0;
        this.encoding_offset = 0;
        this.charstrings_offset = 0;
        this.private_offset = 0;
        this.private_size = 0;
        this.synthetic_base = 0;
        this.embedded_postscript = 0;

        this.cid_registry = 0;
        this.cid_ordering = 0;
        this.cid_supplement = 0;

        this.cid_font_version = 0;
        this.cid_font_revision = 0;
        this.cid_font_type = 0;
        this.cid_count = 0;
        this.cid_uid_base = 0;
        this.cid_fd_array_offset = 0;
        this.cid_fd_select_offset = 0;
        this.cid_font_name = 0;
    }
}

function CFF_PrivateRec()
{
    this.num_blue_values = 0;
    this.num_other_blues = 0;
    this.num_family_blues = 0;
    this.num_family_other_blues = 0;

    this.blue_values = CreateIntArray(14);
    this.other_blues = CreateIntArray(10);
    this.family_blues = CreateIntArray(14);
    this.family_other_blues = CreateIntArray(10);

    this.blue_scale = 0;
    this.blue_shift = 0;
    this.blue_fuzz = 0;
    this.standard_width = 0;
    this.standard_height = 0;

    this.num_snap_widths = 0;
    this.num_snap_heights = 0;
    this.snap_widths = CreateIntArray(13);
    this.snap_heights = CreateIntArray(13);
    this.force_bold = 0;
    this.force_bold_threshold = 0;
    this.lenIV = 0;
    this.language_group = 0;
    this.expansion_factor = 0;
    this.initial_random_seed = 0;
    this.local_subrs_offset = 0;
    this.default_width = 0;
    this.nominal_width = 0;

    this.clear = function()
    {
        this.num_blue_values = 0;
        this.num_other_blues = 0;
        this.num_family_blues = 0;
        this.num_family_other_blues = 0;

        for (var i = 0; i < 14; i++)
            this.blue_values[i] = 0;
        for (var i = 0; i < 10; i++)
            this.other_blues[i] = 0;
        for (var i = 0; i < 14; i++)
            this.family_blues[i] = 0;
        for (var i = 0; i < 10; i++)
            this.family_other_blues[i] = 0;

        this.blue_scale = 0;
        this.blue_shift = 0;
        this.blue_fuzz = 0;
        this.standard_width = 0;
        this.standard_height = 0;

        this.num_snap_widths = 0;
        this.num_snap_heights = 0;

        for (var i = 0; i < 13; i++)
            this.snap_widths[i] = 0;
        for (var i = 0; i < 13; i++)
            this.snap_heights[i] = 0;

        this.force_bold = 0;
        this.force_bold_threshold = 0;
        this.lenIV = 0;
        this.language_group = 0;
        this.expansion_factor = 0;
        this.initial_random_seed = 0;
        this.local_subrs_offset = 0;
        this.default_width = 0;
        this.nominal_width = 0;
    }
}

function CFF_FDSelectRec()
{
    this.format = 0;
    this.range_count = 0;

    /* that's the table, taken from the file `as is' */
    this.data = null;
    this.data_size = 0;

    /* small cache for format 3 only */
    this.cache_first = 0;
    this.cache_count = 0;
    this.cache_fd = 0;
}

/* A SubFont packs a font dict and a private dict together.  They are */
/* needed to support CID-keyed CFF fonts.                             */
function CFF_SubFontRec()
{
    this.font_dict = new CFF_FontRecDictRec();
    this.private_dict = new CFF_PrivateRec();

    this.local_subrs_index = new CFF_IndexRec();
    this.local_subrs = []; /* array of pointers into Local Subrs INDEX data */
}

function CFF_FontRec()
{
    this.stream = null;
    this.memory = null;
    this.num_faces = 0;
    this.num_glyphs = 0;

    this.version_major = 0;
    this.version_minor = 0;
    this.header_size = 0;
    this.absolute_offsize = 0;


    this.name_index = new CFF_IndexRec();
    this.top_dict_index = new CFF_IndexRec();
    this.global_subrs_index = new CFF_IndexRec();

    this.encoding = new CFF_EncodingRec();
    this.charset = new CFF_CharsetRec();

    this.charstrings_index = new CFF_IndexRec();
    this.font_dict_index = new CFF_IndexRec();
    this.private_index = new CFF_IndexRec();
    this.local_subrs_index = new CFF_IndexRec();

    this.font_name = "";

    /* array of pointers into Global Subrs INDEX data */
    this.global_subrs = [];

    /* array of pointers into String INDEX data stored at string_pool */
    this.num_strings = 0;
    this.strings = null;
    this.string_pool = null;

    this.top_font = new CFF_SubFontRec();
    this.num_subfonts = 0;
    this.subfonts = new Array(256);
    for (var i = 0; i < 256; i++)
        this.subfonts[i] = null;

    this.fd_select = new CFF_FDSelectRec();

    /* interface to PostScript hinter */
    this.pshinter = null;

    /* interface to Postscript Names service */
    this.psnames = null;

    /* since version 2.3.0 */
    this.font_info = null;   /* font info dictionary */

    /* since version 2.3.6 */
    this.registry = "";
    this.ordering = "";
}

function CFF_ParserRec()
{
    this.library = null;
    this.start = null;
    this.limit = 0;
    this.cursor = null;

    this.stack = new Array(96 + 1);
    this.top = 0;

    this.object_code = 0;
    this.object = 0;

    this.clear = function()
    {
        this.library = null;
        this.start = null;
        this.limit = 0;
        this.cursor = null;

        for (var i = 0; i < (96 + 1); i++)
            this.stack[i] = 0;
        this.top = 0;

        this.object_code = 0;
        this.object = 0;
    }
}

function CFF_Field_Handler()
{
    this.kind = 0;
    this.code = 0;
    this.offset = 0;
    this.size = 0;
    this.reader = null;
    this.array_max = 0;
    this.count_offset = 0;

    this.set_field = null;
    this.set_field_count = null;
}

function create_cff_field(_kind, _code, _reader, _array_max, _set_field, _set_field_count)
{
    var ret = new CFF_Field_Handler();
    ret.kind = _kind;
    ret.code = _code;
    ret.offset = 0;
    ret.size = 0;
    ret.reader = _reader;
    ret.array_max = _array_max;
    ret.count_offset = 0;

    ret.set_field = _set_field;
    ret.set_field_count = _set_field_count;

    return ret;
}
/******************************************************************************/
// cffparse
/******************************************************************************/
function cff_parser_init(parser, code, object, library)
{
    parser.clear();
    
    parser.top = 0;
    parser.object_code = code;
    parser.object = object;
    parser.library = library;
}

function cff_parse_integer(start, limit)
{
    var p = dublicate_pointer(start);
    var v   = p.data[p.pos];
    p.pos++;
    var val = 0;

    if (v == 28)
    {
        if (p.pos + 2 > limit)
            return 0;

        val = FT_Common.UShort_To_Short((p.data[p.pos] << 8) | p.data[p.pos + 1]);
        p.pos += 2;
    }
    else if ( v == 29 )
    {
        if (p.pos + 4 > limit)
            return 0;

        val = (p.data[p.pos] << 24) | (p.data[p.pos + 1] << 16) | (p.data[p.pos + 2] << 8) | p.data[p.pos + 3];
        p.pos += 4;
    }
    else if (v < 247)
    {
        val = v - 139;
    }
    else if (v < 251)
    {
        if (p.pos + 1 > limit)
            return 0;

        val = (v - 247) * 256 + p.data[p.pos] + 108;
        p.pos++;
    }
    else
    {
        if (p + 1 > limit)
            return 0;

        val = -(v - 251) * 256 - p.data[p.pos] - 108;
        p.pos++;
    }
    return val;
}

var power_tens = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000];

function cff_parse_real(start, limit, power_ten, is_scaling)
{
    var scaling = 0;
    var result = 0;

    var p = dublicate_pointer(start);
    var nib = 0;
    var phase = 0;

    var sign = 0, exponent_sign = 0;

    var number   = 0;
    var exponent = 0;

    var exponent_add    = 0;
    var integer_length  = 0;
    var fraction_length = 0;

    /* First of all, read the integer part. */
    phase = 4;

    for (;;)
    {
        /* If we entered this iteration with phase == 4, we need to */
        /* read a new byte.  This also skips past the initial 0x1E. */
        if (phase)
        {
            p.pos++;

            /* Make sure we don't read past the end. */
            if (p.pos >= limit)
                return { res : result, scaling: scaling };
        }

        /* Get the nibble. */
        nib = (p.data[p.pos] >> phase) & 0xF;
        phase = 4 - phase;

        if (nib == 0xE)
            sign = 1;
        else if (nib > 9)
            break;
        else
        {
            /* Increase exponent if we can't add the digit. */
            if (number >= 0xCCCCCCC)
                exponent_add++;
            /* Skip leading zeros. */
            else if ( nib || number )
            {
                integer_length++;
                number = number * 10 + nib;
            }
        }
    }

    /* Read fraction part, if any. */
    if (nib == 0xa)
    {
        for (;;)
        {
            /* If we entered this iteration with phase == 4, we need */
            /* to read a new byte.                                   */
            if (phase)
            {
                p.pos++;

                /* Make sure we don't read past the end. */
                if (p.pos >= limit)
                    return { res : result, scaling: scaling };
            }

            /* Get the nibble. */
            nib   = (p.data[p.pos] >> phase) & 0xF;
            phase = 4 - phase;
            if (nib >= 10)
                break;

            /* Skip leading zeros if possible. */
            if (!nib && !number)
                exponent_add--;
            /* Only add digit if we don't overflow. */
            else if (number < 0xCCCCCCC && fraction_length < 9)
            {
                fraction_length++;
                number = number * 10 + nib;
            }
        }
    }

    /* Read exponent, if any. */
    if (nib == 12)
    {
        exponent_sign = 1;
        nib           = 11;
    }

    if (nib == 11)
    {
        for (;;)
        {
            /* If we entered this iteration with phase == 4, */
            /* we need to read a new byte.                   */
            if (phase)
            {
                p.pos++;

                /* Make sure we don't read past the end. */
                if (p.pos >= limit)
                    return { res : result, scaling: scaling };
            }

            /* Get the nibble. */
            nib   = (p.data[p.pos] >> phase) & 0xF;
            phase = 4 - phase;
            if (nib >= 10)
                break;

            exponent = exponent * 10 + nib;

            /* Arbitrarily limit exponent. */
            if (exponent > 1000)
                return { res : result, scaling: scaling };
        }

        if (exponent_sign)
            exponent = -exponent;
    }

    /* We don't check `power_ten' and `exponent_add'. */
    exponent += power_ten + exponent_add;

    if (is_scaling != 0)
    {
        /* Only use `fraction_length'. */
        fraction_length += integer_length;
        exponent        += integer_length;

        if (fraction_length <= 5)
        {
            if (number > 0x7FFF)
            {
                result  = FT_DivFix(number, 10);
                scaling = exponent - fraction_length + 1;
            }
            else
            {
                if (exponent > 0)
                {
                    /* Make `scaling' as small as possible. */
                    var new_fraction_length = Math.min(exponent, 5);
                    exponent -= new_fraction_length;
                    var shift = new_fraction_length - fraction_length;

                    number *= power_tens[shift];
                    if (number > 0x7FFF)
                    {
                        number /= 10;
                        exponent += 1;
                    }
                }
                else
                    exponent -= fraction_length;

                result = number << 16;
                scaling = exponent;
            }
        }
        else
        {
            if ((number / power_tens[fraction_length - 5]) > 0x7FFF)
            {
                result = FT_DivFix(number, power_tens[fraction_length - 4]);
                scaling = exponent - 4;
            }
            else
            {
                result = FT_DivFix(number, power_tens[fraction_length - 5]);
                scaling = exponent - 5;
            }
        }
    }
    else
    {
        integer_length  += exponent;
        fraction_length -= exponent;

        /* Check for overflow and underflow. */
        if (Math.abs(integer_length) > 5)
            return { res : result, scaling: scaling };

        /* Remove non-significant digits. */
        if (integer_length < 0)
        {
            number /= power_tens[-integer_length];
            fraction_length += integer_length;
        }

        /* this can only happen if exponent was non-zero */
        if (fraction_length == 10)
        {
            number /= 10;
            fraction_length -= 1;
        }

        /* Convert into 16.16 format. */
        if (fraction_length > 0)
        {
            if ((number / power_tens[fraction_length]) > 0x7FFF)
                return { res : result, scaling: scaling };

            result = FT_DivFix(number, power_tens[fraction_length]);
        }
        else
        {
            number *= power_tens[-fraction_length];

            if (number > 0x7FFF)
                return { res : result, scaling: scaling };

            result = number << 16;
        }
    }

    if (sign)
        result = -result;

    return { res : result, scaling: scaling };
}

function cff_parse_num(d, start)
{
    var _d0 = d[start];
    var _d1 = d[start + 1];
    if (_d0.data[_d0.pos] == 30)
        return cff_parse_real(_d0, _d1.pos, 0, false).res >> 16;
    return cff_parse_integer(_d0, _d1.pos);
}

function cff_parse_fixed(d, start)
{
    var _d0 = d[start];
    var _d1 = d[start + 1];
    if (_d0.data[_d0.pos] == 30)
        return cff_parse_real(_d0, _d1.pos, 0, false).res;
    return cff_parse_integer(_d0, _d1.pos) << 16;
}

function cff_parse_fixed_scaled(d, start, scaling)
{
    var _d0 = d[start];
    var _d1 = d[start + 1];
    if (_d0.data[_d0.pos] == 30)
        return cff_parse_real(_d0, _d1.pos, scaling, false).res;

    return (cff_parse_integer(_d0, _d1.pos) * power_tens[scaling]) << 16;
}

function cff_parse_fixed_dynamic(d, start)
{
    var _d0 = d[start];
    var _d1 = d[start + 1];
    if (_d0.data[_d0.pos] == 30)
        return cff_parse_real(_d0, _d1.pos, 0, true);

    var integer_length = 0;
    var number = cff_parse_integer(_d0, _d1.pos);

    var scaling = 0;
    if (number > 0x7FFF)
    {
        for (integer_length = 5; integer_length < 10; integer_length++)
            if (number < power_tens[integer_length])
                break;

        if ((number / power_tens[integer_length - 5]) > 0x7FFF)
        {
            scaling = integer_length - 4;
            var result = FT_DivFix(number, power_tens[integer_length - 4]);
            return { res : result, scaling: scaling };
        }
        else
        {
            scaling = integer_length - 5;
            var result = FT_DivFix(number, power_tens[integer_length - 5]);
            return { res : result, scaling: scaling };
        }
    }
    else
    {
        return { res : number << 16, scaling: 0 };
    }
}

function cff_parse_font_matrix(parser)
{
    var dict = parser.object;
    var matrix = dict.font_matrix;
    var offset = dict.font_offset;
    //FT_ULong*        upm    = &dict.units_per_em;
    var data = parser.stack;
    var start = 0;
    var error = 161;

    if (parser.top >= 6)
    {
        var scaling = 0;
        error = 0;

        dict.has_font_matrix = 1;
        /* We expect a well-formed font matrix, this is, the matrix elements */
        /* `xx' and `yy' are of approximately the same magnitude.  To avoid  */
        /* loss of precision, we use the magnitude of element `xx' to scale  */
        /* all other elements.  The scaling factor is then contained in the  */
        /* `units_per_em' value.                                             */

        var ret = cff_parse_fixed_dynamic(data, start++);
        scaling = ret.scaling;
        matrix.xx = ret.res;

        scaling = -scaling;
        if (scaling < 0 || scaling > 9)
        {
            /* Return default matrix in case of unlikely values. */
            matrix.xx = 0x10000;
            matrix.yx = 0;
            matrix.xy = 0;
            matrix.yy = 0x10000;
            offset.x  = 0;
            offset.y  = 0;
            dict.units_per_em = 1;

            return error;
        }

        matrix.yx = cff_parse_fixed_scaled(data, start++, scaling);
        matrix.xy = cff_parse_fixed_scaled(data, start++, scaling);
        matrix.yy = cff_parse_fixed_scaled(data, start++, scaling);
        offset.x  = cff_parse_fixed_scaled(data, start++, scaling);
        offset.y  = cff_parse_fixed_scaled(data, start, scaling);

        dict.units_per_em = power_tens[scaling];
    }

    return error;
}

function cff_parse_font_bbox(parser)
{
    var dict = parser.object;
    var bbox = dict.font_bbox;
    var data = parser.stack;

    if (parser.top >= 4)
    {
        var start = 0;

        bbox.xMin = FT_RoundFix(cff_parse_fixed(data, start++));
        bbox.yMin = FT_RoundFix(cff_parse_fixed(data, start++));
        bbox.xMax = FT_RoundFix(cff_parse_fixed(data, start++));
        bbox.yMax = FT_RoundFix(cff_parse_fixed(data, start));

        return 0;
    }
    return 161;
}

function cff_parse_private_dict(parser)
{
    var dict = parser.object;
    var data = parser.stack;

    if (parser.top >= 2)
    {
        dict.private_size   = cff_parse_num(data, 0);
        dict.private_offset = cff_parse_num(data, 1);

        return 0;
    }
    return 161;
}

function cff_parse_cid_ros(parser)
{
    var dict = parser.object;
    var data = parser.stack;

    if (parser.top >= 3)
    {
        dict.cid_registry = FT_Common.IntToUInt(cff_parse_num(data, 0));
        dict.cid_ordering = FT_Common.IntToUInt(cff_parse_num(data, 1));

        dict.cid_supplement = cff_parse_num(data, 2);
        return 0;
    }
    return 161;
}

function cff_parser_run(parser, start, limit)
{
    var p = dublicate_pointer(start);
    var error = 0;

    parser.top    = 0;
    parser.start  = start;
    parser.limit  = limit;
    parser.cursor = dublicate_pointer(start);

    var tops = parser.stack;
    while (p.pos < limit)
    {
        var v = p.data[p.pos];

        if (v >= 27 && v != 31)
        {
            /* it's a number; we will push its position on the stack */
            if (parser.top >= 96)
                return 6;

            tops[parser.top++] = dublicate_pointer(p);

            /* now, skip it */
            if (v == 30)
            {
                /* skip real number */
                p.pos++;
                for (;;)
                {
                    /* An unterminated floating point number at the */
                    /* end of a dictionary is invalid but harmless. */
                    if (p.pos >= limit)
                        return error;
                    v = p.data[p.pos] >> 4;
                    if (v == 15)
                        break;
                    v = p.data[p.pos] & 0xF;
                    if (v == 15)
                        break;
                    p.pos++;
                }
            }
            else if (v == 28)
                p.pos += 2;
            else if (v == 29)
                p.pos += 4;
            else if (v > 246)
                p.pos += 1;
        }
        else
        {
            /* This is not a number, hence it's an operator.  Compute its code */
            /* and look for it in our current list.                            */

            var num_args = parser.top;
            var code = v;

            tops[parser.top++] = dublicate_pointer(p);
            if (v == 12)
            {
                /* two byte operator */
                p.pos++;
                if (p.pos >= limit)
                    return 6;

                code = 0x100 | p.data[p.pos];
            }
            code = code | parser.object_code;

            var fields = cff_field_handlers;
            for (var field_ = 0; field_ < fields.length; field_++)
            {
                var field = fields[field_];
                if (field.code == FT_Common.UintToInt(code))
                {
                    /* we found our field's handler; read it */
                    var val;

                    /* check that we have enough arguments -- except for */
                    /* delta encoded arrays, which can be empty          */
                    if (field.kind != 6 && num_args < 1)
                        return 6;

                    switch (field.kind)
                    {
                        case 5:
                        case 4:
                        case 1:
                            val = cff_parse_num(parser.stack, 0);
                            fire_t1_field(parser.object, val, field);
                            break;

                        case 2:
                            val = cff_parse_fixed(parser.stack, 0);
                            fire_t1_field(parser.object, val, field);
                            break;

                        case 3:
                            val = cff_parse_fixed_scaled(parser.stack, 0, 3);
                            fire_t1_field(parser.object, val, field);
                            break;

                        case 6:
                            var data = parser.stack;
                            var _data_pos = 0;

                            if (num_args > field.array_max)
                                num_args = field.array_max;

                            fire_t1_field_count(parser.object, num_args, field);
                            val = 0;
                            field.offset = 0;
                            while (num_args > 0)
                            {
                                val += cff_parse_num(data, _data_pos++);
                                fire_t1_field(parser.object, val, field);
                                field.offset++;
                                num_args--;
                            }

                            break;

                        default:  /* callback */
                            error = field.reader(parser);
                            if ( error )
                                return error;
                    }

                    break;
                }
            }

            /* this is an unknown operator, or it is unsupported; */
            /* we will ignore it for now.                         */
            /* clear stack */
            parser.top = 0;
        }
        p.pos++;
    }

    return error;
}

/******************************************************************************/
// cfftoken
/******************************************************************************/
var cff_field_handlers = new Array(51);

// CFF_FontRecDictRec
cff_field_handlers[0] = create_cff_field(4, 0 | 4096, null, 0, function(obj, val, f) { obj.version = val }, undefined);
cff_field_handlers[1] = create_cff_field(4, 1 | 4096, null, 0, function(obj, val, f) { obj.notice = val }, undefined);
cff_field_handlers[2] = create_cff_field(4, 0x100 | 4096, null, 0, function(obj, val, f) { obj.copyright = val }, undefined);
cff_field_handlers[3] = create_cff_field(4, 2 | 4096, null, 0, function(obj, val, f) { obj.full_name = val }, undefined);
cff_field_handlers[4] = create_cff_field(4, 3 | 4096, null, 0, function(obj, val, f) { obj.family_name = val }, undefined);
cff_field_handlers[5] = create_cff_field(4, 4 | 4096, null, 0, function(obj, val, f) { obj.weight = val }, undefined);

cff_field_handlers[6] = create_cff_field(5, 0x101 | 4096, null, 0, function(obj, val, f) { obj.is_fixed_pitch = val }, undefined);

cff_field_handlers[7] = create_cff_field(2, 0x102 | 4096, null, 0, function(obj, val, f) { obj.italic_angle = val }, undefined);
cff_field_handlers[8] = create_cff_field(2, 0x103 | 4096, null, 0, function(obj, val, f) { obj.underline_position = val }, undefined);
cff_field_handlers[9] = create_cff_field(2, 0x104 | 4096, null, 0, function(obj, val, f) { obj.underline_thickness = val }, undefined);

cff_field_handlers[10] = create_cff_field(1, 0x105 | 4096, null, 0, function(obj, val, f) { obj.paint_type = val }, undefined);
cff_field_handlers[11] = create_cff_field(1, 0x106 | 4096, null, 0, function(obj, val, f) { obj.charstring_type = val }, undefined);

cff_field_handlers[12] = create_cff_field(7, 0x107 | 4096, cff_parse_font_matrix, 0, undefined, undefined);

cff_field_handlers[13] = create_cff_field(1, 13 | 4096, null, 0, function(obj, val, f) { obj.unique_id = val }, undefined);

cff_field_handlers[14] = create_cff_field(7, 5 | 4096, cff_parse_font_bbox, 0, undefined, undefined);

cff_field_handlers[15] = create_cff_field(1, 0x108 | 4096, null, 0, function(obj, val, f) { obj.stroke_width = val }, undefined);
cff_field_handlers[16] = create_cff_field(1, 15 | 4096, null, 0, function(obj, val, f) { obj.charset_offset = val }, undefined);
cff_field_handlers[17] = create_cff_field(1, 16 | 4096, null, 0, function(obj, val, f) { obj.encoding_offset = val }, undefined);
cff_field_handlers[18] = create_cff_field(1, 17 | 4096, null, 0, function(obj, val, f) { obj.charstrings_offset = val }, undefined);

cff_field_handlers[19] = create_cff_field(7, 18 | 4096, cff_parse_private_dict, 0, undefined, undefined);

cff_field_handlers[20] = create_cff_field(1, 0x114 | 4096, null, 0, function(obj, val, f) { obj.synthetic_base = val }, undefined);

cff_field_handlers[21] = create_cff_field(4, 0x115 | 4096, null, 0, function(obj, val, f) { obj.embedded_postscript = val }, undefined);

cff_field_handlers[22] = create_cff_field(7, 0x11E | 4096, cff_parse_cid_ros, 0, undefined, undefined);

cff_field_handlers[23] = create_cff_field(1, 0x11F | 4096, null, 0, function(obj, val, f) { obj.cid_font_version = val }, undefined);
cff_field_handlers[24] = create_cff_field(1, 0x120 | 4096, null, 0, function(obj, val, f) { obj.cid_font_revision = val }, undefined);
cff_field_handlers[25] = create_cff_field(1, 0x121 | 4096, null, 0, function(obj, val, f) { obj.cid_font_type = val }, undefined);
cff_field_handlers[26] = create_cff_field(1, 0x122 | 4096, null, 0, function(obj, val, f) { obj.cid_count = val }, undefined);
cff_field_handlers[27] = create_cff_field(1, 0x123 | 4096, null, 0, function(obj, val, f) { obj.cid_uid_base = val }, undefined);
cff_field_handlers[28] = create_cff_field(1, 0x124 | 4096, null, 0, function(obj, val, f) { obj.cid_fd_array_offset = val }, undefined);
cff_field_handlers[29] = create_cff_field(1, 0x125 | 4096, null, 0, function(obj, val, f) { obj.cid_fd_select_offset = val }, undefined);

cff_field_handlers[30] = create_cff_field(4, 0x126 | 4096, null, 0, function(obj, val, f) { obj.cid_font_name = val }, undefined);

// CFF_PrivateRec
cff_field_handlers[31] = create_cff_field(6, 6 | 8192, null, 14, function(obj, val, f) { obj.blue_values[f.offset] = val }, function(obj, val, f) { obj.num_blue_values = val });
cff_field_handlers[32] = create_cff_field(6, 7 | 8192, null, 10, function(obj, val, f) { obj.other_blues[f.offset] = val }, function(obj, val, f) { obj.num_other_blues = val });
cff_field_handlers[33] = create_cff_field(6, 8 | 8192, null, 14, function(obj, val, f) { obj.family_blues[f.offset] = val }, function(obj, val, f) { obj.num_family_blues = val });
cff_field_handlers[34] = create_cff_field(6, 9 | 8192, null, 10, function(obj, val, f) { obj.family_other_blues[f.offset] = val }, function(obj, val, f) { obj.num_family_other_blues = val });

cff_field_handlers[35] = create_cff_field(3, 0x109 | 8192, null, 0, function(obj, val, f) { obj.blue_scale = val }, undefined);

cff_field_handlers[36] = create_cff_field(1, 0x10A | 8192, null, 0, function(obj, val, f) { obj.blue_shift = val }, undefined);
cff_field_handlers[37] = create_cff_field(1, 0x10B | 8192, null, 0, function(obj, val, f) { obj.blue_fuzz = val }, undefined);
cff_field_handlers[38] = create_cff_field(1, 10 | 8192, null, 0, function(obj, val, f) { obj.standard_width = val }, undefined);
cff_field_handlers[39] = create_cff_field(1, 11 | 8192, null, 0, function(obj, val, f) { obj.standard_height = val }, undefined);

cff_field_handlers[40] = create_cff_field(6, 0x10C | 8192, null, 13, function(obj, val, f) { obj.snap_widths[f.offset] = val }, function(obj, val, f) { obj.num_snap_widths = val });
cff_field_handlers[41] = create_cff_field(6, 0x10D | 8192, null, 13, function(obj, val, f) { obj.snap_heights[f.offset] = val }, function(obj, val, f) { obj.num_snap_heights = val });

cff_field_handlers[42] = create_cff_field(5, 0x10E | 8192, null, 0, function(obj, val, f) { obj.force_bold = val }, undefined);
cff_field_handlers[43] = create_cff_field(2, 0x10F | 8192, null, 0, function(obj, val, f) { obj.force_bold_threshold = val }, undefined);

cff_field_handlers[44] = create_cff_field(1, 0x110 | 8192, null, 0, function(obj, val, f) { obj.lenIV = val }, undefined);
cff_field_handlers[45] = create_cff_field(1, 0x111 | 8192, null, 0, function(obj, val, f) { obj.language_group = val }, undefined);

cff_field_handlers[46] = create_cff_field(2, 0x112 | 8192, null, 0, function(obj, val, f) { obj.expansion_factor = val }, undefined);

cff_field_handlers[47] = create_cff_field(1, 0x113 | 8192, null, 0, function(obj, val, f) { obj.initial_random_seed = val }, undefined);
cff_field_handlers[48] = create_cff_field(1, 19 | 8192, null, 0, function(obj, val, f) { obj.local_subrs_offset = val }, undefined);
cff_field_handlers[49] = create_cff_field(1, 20 | 8192, null, 0, function(obj, val, f) { obj.default_width = val }, undefined);
cff_field_handlers[50] = create_cff_field(1, 21 | 8192, null, 0, function(obj, val, f) { obj.nominal_width = val }, undefined);

/******************************************************************************/
// cffload
/******************************************************************************/
var cff_isoadobe_charset =
[
    0,   1,   2,   3,   4,   5,   6,   7,
    8,   9,  10,  11,  12,  13,  14,  15,
    16,  17,  18,  19,  20,  21,  22,  23,
    24,  25,  26,  27,  28,  29,  30,  31,
    32,  33,  34,  35,  36,  37,  38,  39,
    40,  41,  42,  43,  44,  45,  46,  47,
    48,  49,  50,  51,  52,  53,  54,  55,
    56,  57,  58,  59,  60,  61,  62,  63,
    64,  65,  66,  67,  68,  69,  70,  71,
    72,  73,  74,  75,  76,  77,  78,  79,
    80,  81,  82,  83,  84,  85,  86,  87,
    88,  89,  90,  91,  92,  93,  94,  95,
    96,  97,  98,  99, 100, 101, 102, 103,
    104, 105, 106, 107, 108, 109, 110, 111,
    112, 113, 114, 115, 116, 117, 118, 119,
    120, 121, 122, 123, 124, 125, 126, 127,
    128, 129, 130, 131, 132, 133, 134, 135,
    136, 137, 138, 139, 140, 141, 142, 143,
    144, 145, 146, 147, 148, 149, 150, 151,
    152, 153, 154, 155, 156, 157, 158, 159,
    160, 161, 162, 163, 164, 165, 166, 167,
    168, 169, 170, 171, 172, 173, 174, 175,
    176, 177, 178, 179, 180, 181, 182, 183,
    184, 185, 186, 187, 188, 189, 190, 191,
    192, 193, 194, 195, 196, 197, 198, 199,
    200, 201, 202, 203, 204, 205, 206, 207,
    208, 209, 210, 211, 212, 213, 214, 215,
    216, 217, 218, 219, 220, 221, 222, 223,
    224, 225, 226, 227, 228
];

var cff_expert_charset =
[
    0,   1, 229, 230, 231, 232, 233, 234,
    235, 236, 237, 238,  13,  14,  15,  99,
    239, 240, 241, 242, 243, 244, 245, 246,
    247, 248,  27,  28, 249, 250, 251, 252,
    253, 254, 255, 256, 257, 258, 259, 260,
    261, 262, 263, 264, 265, 266, 109, 110,
    267, 268, 269, 270, 271, 272, 273, 274,
    275, 276, 277, 278, 279, 280, 281, 282,
    283, 284, 285, 286, 287, 288, 289, 290,
    291, 292, 293, 294, 295, 296, 297, 298,
    299, 300, 301, 302, 303, 304, 305, 306,
    307, 308, 309, 310, 311, 312, 313, 314,
    315, 316, 317, 318, 158, 155, 163, 319,
    320, 321, 322, 323, 324, 325, 326, 150,
    164, 169, 327, 328, 329, 330, 331, 332,
    333, 334, 335, 336, 337, 338, 339, 340,
    341, 342, 343, 344, 345, 346, 347, 348,
    349, 350, 351, 352, 353, 354, 355, 356,
    357, 358, 359, 360, 361, 362, 363, 364,
    365, 366, 367, 368, 369, 370, 371, 372,
    373, 374, 375, 376, 377, 378
];

var cff_expertsubset_charset =
[
    0,   1, 231, 232, 235, 236, 237, 238,
    13,  14,  15,  99, 239, 240, 241, 242,
    243, 244, 245, 246, 247, 248,  27,  28,
    249, 250, 251, 253, 254, 255, 256, 257,
    258, 259, 260, 261, 262, 263, 264, 265,
    266, 109, 110, 267, 268, 269, 270, 272,
    300, 301, 302, 305, 314, 315, 158, 155,
    163, 320, 321, 322, 323, 324, 325, 326,
    150, 164, 169, 327, 328, 329, 330, 331,
    332, 333, 334, 335, 336, 337, 338, 339,
    340, 341, 342, 343, 344, 345, 346
];

var cff_standard_encoding =
[
    0,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,
    1,   2,   3,   4,   5,   6,   7,   8,
    9,  10,  11,  12,  13,  14,  15,  16,
    17,  18,  19,  20,  21,  22,  23,  24,
    25,  26,  27,  28,  29,  30,  31,  32,
    33,  34,  35,  36,  37,  38,  39,  40,
    41,  42,  43,  44,  45,  46,  47,  48,
    49,  50,  51,  52,  53,  54,  55,  56,
    57,  58,  59,  60,  61,  62,  63,  64,
    65,  66,  67,  68,  69,  70,  71,  72,
    73,  74,  75,  76,  77,  78,  79,  80,
    81,  82,  83,  84,  85,  86,  87,  88,
    89,  90,  91,  92,  93,  94,  95,   0,
    0,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,
    0,  96,  97,  98,  99, 100, 101, 102,
    103, 104, 105, 106, 107, 108, 109, 110,
    0, 111, 112, 113, 114,   0, 115, 116,
    117, 118, 119, 120, 121, 122,   0, 123,
    0, 124, 125, 126, 127, 128, 129, 130,
    131,   0, 132, 133,   0, 134, 135, 136,
    137,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,
    0, 138,   0, 139,   0,   0,   0,   0,
    140, 141, 142, 143,   0,   0,   0,   0,
    0, 144,   0,   0,   0, 145,   0,   0,
    146, 147, 148, 149,   0,   0,   0,   0
];

var cff_expert_encoding =
[
    0,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,
    1, 229, 230,   0, 231, 232, 233, 234,
    235, 236, 237, 238,  13,  14,  15,  99,
    239, 240, 241, 242, 243, 244, 245, 246,
    247, 248,  27,  28, 249, 250, 251, 252,
    0, 253, 254, 255, 256, 257,   0,   0,
    0, 258,   0,   0, 259, 260, 261, 262,
    0,   0, 263, 264, 265,   0, 266, 109,
    110, 267, 268, 269,   0, 270, 271, 272,
    273, 274, 275, 276, 277, 278, 279, 280,
    281, 282, 283, 284, 285, 286, 287, 288,
    289, 290, 291, 292, 293, 294, 295, 296,
    297, 298, 299, 300, 301, 302, 303,   0,
    0,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,
    0, 304, 305, 306,   0,   0, 307, 308,
    309, 310, 311,   0, 312,   0,   0, 312,
    0,   0, 314, 315,   0,   0, 316, 317,
    318,   0,   0,   0, 158, 155, 163, 319,
    320, 321, 322, 323, 324, 325,   0,   0,
    326, 150, 164, 169, 327, 328, 329, 330,
    331, 332, 333, 334, 335, 336, 337, 338,
    339, 340, 341, 342, 343, 344, 345, 346,
    347, 348, 349, 350, 351, 352, 353, 354,
    355, 356, 357, 358, 359, 360, 361, 362,
    363, 364, 365, 366, 367, 368, 369, 370,
    371, 372, 373, 374, 375, 376, 377, 378
];

function cff_get_standard_encoding(charcode)
{
    return (charcode < 256 ? cff_standard_encoding[charcode] : 0);
}

function cff_index_read_offset(idx)
{
    var result = 0;
    var tmp = g_memory.Alloc(4);
    var error = idx.stream.Read(tmp, idx.off_size);

    if (error == 0)
    {
        for (var nn = 0; nn < idx.off_size; nn++)
            result = (result << 8) | tmp.data[nn];

        result = FT_Common.IntToUInt(result);
    }

    return { err : error, result: result };
}

function cff_index_init(idx, stream, load)
{
    idx.clear();
    idx.stream = stream;
    idx.start  = stream.pos;

    var count = stream.ReadUShort();
    var error = FT_Error;
    if (error != 0)
        return error;

    if (0 == count)
        return error;

    var offsize = stream.ReadUChar();
    if (error != 0)
        return error;

    if (offsize < 1 || offsize > 4)
        return 8;

    idx.count    = count;
    idx.off_size = offsize;
    var size = (count + 1) * offsize;

    idx.data_offset = idx.start + 3 + size;

    error = stream.Skip(size - offsize);
    if (error != 0)
        return error;

    var _err = cff_index_read_offset(idx);
    error = _err.err;
    size = _err.result;
    if (error != 0)
        return error;

    if (size == 0)
        return 8;

    idx.data_size = --size;

    if (load)
    {
        /* load the data */
        idx.bytes = new CPointer();
        error = stream.ExtractFrame(size, idx.bytes);
    }
    else
    {
        /* skip the data */
        error = stream.Skip(size);
    }

    return error;
}

function cff_index_done(idx)
{
    if (idx.stream != null)
    {
        idx.clear();
    }
}

function cff_index_load_offsets(idx)
{
    var error = 0;
    var stream = idx.stream;

    if (idx.count > 0 && idx.offsets == null)
    {
        var offsize = idx.off_size;
        var data_size = (idx.count + 1) * offsize;

        error = stream.Seek(idx.start + 3);
        if (error == 0)
            error = stream.EnterFrame(data_size);

        if (error != 0)
            return error;

        idx.offsets = CreateUIntArray(idx.count + 1);

        var poff = 0;
        var p = stream.cur;
        var p_end  = p + data_size;

        var _s = stream.data;
        var _d = idx.offsets;

        switch (offsize)
        {
            case 1:
                for (; p < p_end; p++, poff++)
                    _d[poff] = _s[p];
                break;

            case 2:
                for (; p < p_end; p += 2, poff++)
                    _d[poff] = (_s[p] << 8 | _s[p+1]);
                break;

            case 3:
                for (; p < p_end; p += 3, poff++)
                    _d[poff] = (_s[p] << 16 | _s[p+1] << 8 | _s[p+2]);
                break;

            default:
                for (; p < p_end; p += 4, poff++)
                {
                    var r = (_s[p] << 24 | _s[p+1] << 16 | _s[p+2] << 8 | _s[p+3]);
                    if (r<0)
                        r+=4294967296;
                    _d[poff] = r;
                }
        }

        stream.ExitFrame();
    }

    return error;
}

function cff_index_get_pointers(idx, table, pool, is_pool)
{
    var error = 0;

    if (idx.offsets == null)
    {
        error = cff_index_load_offsets(idx);
        if (error != 0)
            return { err: error, table: table, pool: pool };
    }

    if (idx.count > 0)
    {
        var t = new Array(idx.count + 1);
        var new_bytes = g_memory.Alloc(idx.data_size + idx.count);

        var extra = 0;
        var org_bytes = idx.bytes;

        /* at this point, `idx->offsets' can't be NULL */
        var cur_offset = idx.offsets[0] - 1;

        /* sanity check */
        if (cur_offset >= idx.data_size)
        {
            cur_offset = 0;
        }

        if (is_pool == 0)
        {
            t[0] = dublicate_pointer(org_bytes);
            t[0].pos += cur_offset;
        }
        else
        {
            t[0] = dublicate_pointer(new_bytes);
            t[0].pos += cur_offset;
        }

        for (var n = 1; n <= idx.count; n++)
        {
            var next_offset = idx.offsets[n] - 1;

            /* empty slot + two sanity checks for invalid offset tables */
            if (next_offset == 0 || next_offset < cur_offset || (next_offset >= idx.data_size && n < idx.count))
                next_offset = cur_offset;

            if (is_pool == 0)
            {
                t[n] = dublicate_pointer(org_bytes);
                t[n].pos += next_offset;
            }
            else
            {
                t[n] = dublicate_pointer(new_bytes);
                t[n].pos += next_offset + extra;

                if (next_offset != cur_offset)
                {
                    var _d = t[n - 1];
                    var _s = dublicate_pointer(org_bytes);
                    _s.pos += cur_offset;
                    var _l = t[n].pos - t[n-1].pos;

                    for (var i = 0; i < _l; i++)
                        _d.data[_d.pos + i] = _s.data[_s.pos + i];

                    t[n].data[t[n].pos] = 0;
                    t[n].pos += 1;
                    extra++;
                }
            }

            cur_offset = next_offset;
        }

        return { err: error, table: t, pool: new_bytes };
    }

    return { err: error, table: table, pool: pool };
}

function cff_index_access_element(idx, element)
{
    var error = 0;
    var pbytes = null;
    var pbyte_len = 0;

    if (idx && idx.count > element)
    {
        /* compute start and end offsets */
        var stream = idx.stream;
        var off1, off2 = 0;


        /* load offsets from file or the offset table */
        if (idx.offsets == null)
        {
            var pos = element * idx.off_size;

            error = stream.Seek(idx.start + 3 + pos);
            if (error != 0)
                return { err: error, bytes: pbytes, len: pbyte_len };

            var ret = cff_index_read_offset(idx);
            error = ret.err;
            off1 = ret.result;
            if (error != 0)
                return { err: error, bytes: pbytes, len: pbyte_len };

            if (off1 != 0)
            {
                do
                {
                    element++;
                    ret = cff_index_read_offset(idx);
                    error = ret.err;
                    off2 = ret.result;
                }
                while (off2 == 0 && element < idx.count);
            }
        }
        else   /* use offsets table */
        {
            off1 = idx.offsets[element];
            if (off1)
            {
                do
                {
                    element++;
                    off2 = idx.offsets[element];

                } while (off2 == 0 && element < idx.count);
            }
        }

        /* XXX: should check off2 does not exceed the end of this entry; */
        /*      at present, only truncate off2 at the end of this stream */
        if (off2 > stream.size + 1 || idx.data_offset > stream.size - off2 + 1)
        {
            off2 = stream.size - idx.data_offset + 1;
        }

        /* access element */
        if (off1 && off2 > off1)
        {
            pbyte_len = off2 - off1;

            if (idx.bytes != null)
            {
                /* this index was completely loaded in memory, that's easy */
                pbytes = dublicate_pointer(idx.bytes);
                pbytes.pos += (off1 - 1);
            }
            else
            {
                /* this index is still on disk/file, access it through a frame */
                error = stream.Seek(idx.data_offset + off1 - 1);
                if (error == 0)
                {
                    pbytes = new CPointer();
                    error = stream.ExtractFrame(off2 - off1, pbytes);
                }
            }
        }
        else
        {
            /* empty index element */
            pbytes = null;
            pbyte_len = 0;
        }
    }
    else
        error = 6;

    return { err: error, bytes: pbytes, len: pbyte_len };
}

function cff_index_forget_element(idx, pbytes)
{
    if (idx.bytes == null)
    {
        idx.stream.ReleaseFrame();
        pbytes = null;
    }
}

function cff_index_get_name(font, element)
{
    var idx = font.name_index;
    var ret = cff_index_access_element(idx, element);
    if (0 != ret.err)
        return null;

    var name = "";
    var _len = ret.len;
    var _d = ret.bytes;
    for (var i = 0; i < _len; i++)
        name += String.fromCharCode(_d.data[_d.pos + i]);

    cff_index_forget_element(idx, ret.bytes);
    return name;
}

function cff_index_get_string(font, element)
{
    return (element < font.num_strings) ? FT_PEEK_String1(font.strings[element], 1000) : null;
}

function cff_index_get_sid_string(font, sid)
{
    /* value 0xFFFFU indicates a missing dictionary entry */
    if (sid == 0xFFFF)
        return null;

    /* if it is not a standard string, return it */
    if (sid > 390)
        return cff_index_get_string(font, sid - 391);

    /* CID-keyed CFF fonts don't have glyph names */
    if (font.psnames == null)
        return null;

    /* this is a standard string */
    return font.psnames.adobe_std_strings(sid);
}

function CFF_Done_FD_Select(fdselect, stream)
{
    if (fdselect.data)
    {
        stream.ReleaseFrame();
        fdselect.data = null;
    }

    fdselect.data_size   = 0;
    fdselect.format      = 0;
    fdselect.range_count = 0;
}

function CFF_Load_FD_Select(fdselect, num_glyphs, stream, offset)
{
    var error = stream.Seek(offset);
    if (error != 0)
        return error;

    var format = stream.ReadUChar();
    error = FT_Error;
    if (error != 0)
        return error;

    fdselect.format      = format;
    fdselect.cache_count = 0;   /* clear cache */

    switch (format)
    {
        case 0:     /* format 0, that's simple */
            fdselect.data_size = num_glyphs;
            fdselect.data = new CPointer();
            error = stream.ExtractFrame(fdselect.data_size, fdselect.data);
            break;
        case 3:     /* format 3, a tad more complex */
            var num_ranges = stream.ReadUShort();
            error = FT_Error;
            if (error != 0)
                return error;

            fdselect.data_size = num_ranges * 3 + 2;
            fdselect.data = new CPointer();
            error = stream.ExtractFrame(fdselect.data_size, fdselect.data);
            break;

        default:    /* hmm... that's wrong */
            error = 3;
    }

    return error;
}

function cff_fd_select_get(fdselect, glyph_index)
{
    var fd = 0;
    switch (fdselect.format)
    {
        case 0:
            fd = fdselect.data.data[fdselect.data.pos + glyph_index];
            break;

        case 3:
            /* first, compare to cache */
            if ((glyph_index - fdselect.cache_first) < fdselect.cache_count)
            {
                fd = fdselect.cache_fd;
                break;
            }

            /* then, lookup the ranges array */
            var p = dublicate_pointer(fdselect.data);
            var p_limit = p.pos + fdselect.data_size;

            var first = FT_NEXT_USHORT(p);
            do
            {
                if (glyph_index < first)
                    break;

                var fd2 = p.data[p.pos];
                p.pos++;
                var limit = FT_NEXT_USHORT(p);

                if (glyph_index < limit)
                {
                    fd = fd2;

                    /* update cache */
                    fdselect.cache_first = first;
                    fdselect.cache_count = limit-first;
                    fdselect.cache_fd    = fd2;
                    break;
                }
                first = limit;

            } while ( p < p_limit );
            break;

        default:
            break;
    }

    return fd;
}

function cff_charset_compute_cids(charset, num_glyphs, memory)
{
    var error = 0;
    var max_cid = 0;

    if (charset.max_cid > 0)
        return error;

    for (var i = 0; i < num_glyphs; i++)
    {
        if (charset.sids[i] > max_cid)
            max_cid = charset.sids[i];
    }

    charset.cids = CreateUIntArray(max_cid + 1);

    /* When multiple GIDs map to the same CID, we choose the lowest */
    /* GID.  This is not described in any spec, but it matches the  */
    /* behaviour of recent Acroread versions.                       */
    for (var j = num_glyphs - 1; j >= 0 ; j--)
        charset.cids[charset.sids[j]] = j;

    charset.max_cid    = max_cid;
    charset.num_glyphs = num_glyphs;

    return error;
}

function cff_charset_cid_to_gindex(charset, cid)
{
    if (cid <= charset.max_cid)
        return charset.cids[cid];
    return 0;
}

function cff_charset_free_cids(charset, memory)
{
    charset.cids = null;
    charset.max_cid = 0;
}

function cff_charset_done(charset, stream)
{
    cff_charset_free_cids(charset, stream.memory);

    charset.sids = null;
    charset.format = 0;
    charset.offset = 0;
}

function cff_charset_load(charset, num_glyphs, stream, base_offset, offset, invert)
{
    var error = 0;
    var glyph_sid = 0;

    /* If the the offset is greater than 2, we have to parse the */
    /* charset table.                                            */
    if (offset > 2)
    {
        charset.offset = base_offset + offset;

        error = stream.Seek(charset.offset);
        if (error != 0)
        {
            charset.sids = null;
            charset.cids = null;
            charset.format = 0;
            charset.offset = 0;
            return error;
        }

        charset.format = stream.ReadUChar();
        error = FT_Error;
        if (error != 0)
        {
            charset.sids = null;
            charset.cids = null;
            charset.format = 0;
            charset.offset = 0;
            return error;
        }

        charset.sids = CreateUIntArray(num_glyphs);

        /* assign the .notdef glyph */
        charset.sids[0] = 0;

        switch (charset.format)
        {
            case 0:
                if (num_glyphs > 0)
                {
                    error = stream.EnterFrame((num_glyphs - 1) * 2);
                    if (error != 0)
                    {
                        charset.sids = null;
                        charset.cids = null;
                        charset.format = 0;
                        charset.offset = 0;
                        return error;
                    }

                    for (j = 1; j < num_glyphs; j++)
                        charset.sids[j] = stream.GetUShort();

                    stream.ExitFrame();
                }
                break;

            case 1:
            case 2:
                var nleft = 0;
                var j = 1;
                while (j < num_glyphs)
                {
                    glyph_sid = stream.ReadUShort();
                    error = FT_Error;
                    if (error != 0)
                    {
                        charset.sids = null;
                        charset.cids = null;
                        charset.format = 0;
                        charset.offset = 0;
                        return error;
                    }

                    if (charset.format == 2)
                    {
                        nleft = stream.ReadUShort();
                        error = FT_Error;
                        if (error != 0)
                        {
                            charset.sids = null;
                            charset.cids = null;
                            charset.format = 0;
                            charset.offset = 0;
                            return error;
                        }
                    }
                    else
                    {
                        nleft = stream.ReadUChar();
                        error = FT_Error;
                        if (error != 0)
                        {
                            charset.sids = null;
                            charset.cids = null;
                            charset.format = 0;
                            charset.offset = 0;
                            return error;
                        }
                    }

                    /* try to rescue some of the SIDs if `nleft' is too large */
                    if (glyph_sid > (0xFFFF - nleft))
                    {
                        nleft = (0xFFFF - glyph_sid);
                    }

                    /* Fill in the range of sids -- `nleft + 1' glyphs. */
                    for (i = 0; j < num_glyphs && i <= nleft; i++, j++, glyph_sid++)
                        charset.sids[j] = glyph_sid;
                }
                break;

            default:
                charset.sids = null;
                charset.cids = null;
                charset.format = 0;
                charset.offset = 0;
                return 3;
        }
    }
    else
    {
        /* Parse default tables corresponding to offset == 0, 1, or 2.  */
        /* CFF specification intimates the following:                   */
        /*                                                              */
        /* In order to use a predefined charset, the following must be  */
        /* true: The charset constructed for the glyphs in the font's   */
        /* charstrings dictionary must match the predefined charset in  */
        /* the first num_glyphs.                                        */
        charset.offset = offset;  /* record charset type */

        switch (offset)
        {
        case 0:
            if (num_glyphs > 229)
            {
                charset.sids = null;
                charset.cids = null;
                charset.format = 0;
                charset.offset = 0;
                return 3;
            }

            charset.sids = CreateUIntArray(num_glyphs);
            for (var k = 0; k < num_glyphs; k++)
                charset.sids[k] = cff_isoadobe_charset[k];

            break;

        case 1:
            if (num_glyphs > 166)
            {
                charset.sids = null;
                charset.cids = null;
                charset.format = 0;
                charset.offset = 0;
                return 3;
            }

            charset.sids = CreateUIntArray(num_glyphs);
            for (var k = 0; k < num_glyphs; k++)
                charset.sids[k] = cff_expert_charset[k];

            break;

        case 2:
            if (num_glyphs > 87)
            {
                charset.sids = null;
                charset.cids = null;
                charset.format = 0;
                charset.offset = 0;
                return 3;
            }

            charset.sids = CreateUIntArray(num_glyphs);
            for (var k = 0; k < num_glyphs; k++)
                charset.sids[k] = cff_expertsubset_charset[k];

            break;

        default:
            charset.sids = null;
            charset.cids = null;
            charset.format = 0;
            charset.offset = 0;
            return 3;
        }
    }

    /* we have to invert the `sids' array for subsetted CID-keyed fonts */
    if (invert)
        error = cff_charset_compute_cids(charset, num_glyphs, stream.memory);

    if (error != 0)
    {
        charset.sids = null;
        charset.cids = null;
        charset.format = 0;
        charset.offset = 0;
    }
    return error;
}

function cff_encoding_done(encoding)
{
    encoding.format = 0;
    encoding.offset = 0;
    encoding.count  = 0;
}

function cff_encoding_load(encoding, charset, num_glyphs, stream, base_offset, offset)
{
    var error = 0;
    var count = 0;
    var j = 0;
    var glyph_sid = 0;
    var glyph_code = 0;


    /* Check for charset->sids.  If we do not have this, we fail. */
    if (charset.sids == null)
        return 3;

    /* Zero out the code to gid/sid mappings. */
    for (j = 0; j < 256; j++)
    {
        encoding.sids[j] = 0;
        encoding.codes[j] = 0;
    }

    /* Note: The encoding table in a CFF font is indexed by glyph index;  */
    /* the first encoded glyph index is 1.  Hence, we read the character  */
    /* code (`glyph_code') at index j and make the assignment:            */
    /*                                                                    */
    /*    encoding->codes[glyph_code] = j + 1                             */
    /*                                                                    */
    /* We also make the assignment:                                       */
    /*                                                                    */
    /*    encoding->sids[glyph_code] = charset->sids[j + 1]               */
    /*                                                                    */
    /* This gives us both a code to GID and a code to SID mapping.        */
    if (offset > 1)
    {
        encoding.offset = base_offset + offset;

        error = stream.Seek(encoding.offset);
        if (error != 0)
            return error;
        encoding.format = stream.ReadUChar();
        error = FT_Error;
        if (error != 0)
            return error;
        count = stream.ReadUChar();
        error = FT_Error;
        if (error != 0)
            return error;

        switch (encoding.format & 0x7F)
        {
            case 0:
                encoding.count = count + 1;
                error = stream.EnterFrame(count);
                if (error != 0)
                    return error;

                var p = stream.cur;
                for (j = 1; j <= count; j++)
                {
                    glyph_code = stream.data[p];
                    p++;
                    /* Make sure j is not too big. */
                    if (j < num_glyphs)
                    {
                        /* Assign code to GID mapping. */
                        encoding.codes[glyph_code] = j;
                        /* Assign code to SID mapping. */
                        encoding.sids[glyph_code] = charset.sids[j];
                    }
                }
                stream.ExitFrame();
                break;

            case 1:
                var nleft = 0;
                var i = 1;
                encoding.count = 0;

                /* Parse the Format1 ranges. */
                for (j = 0;  j < count; j++, i += nleft)
                {
                    /* Read the first glyph code of the range. */
                    glyph_code = stream.ReadUChar();
                    error = FT_Error;
                    if (error != 0)
                        return error;

                    nleft = stream.ReadUChar();
                    error = FT_Error;
                    if (error != 0)
                        return error;
                    /* Read the number of codes in the range. */
                    /* Increment nleft, so we read `nleft + 1' codes/sids. */
                    nleft++;

                    /* compute max number of character codes */
                    if (nleft > encoding.count)
                        encoding.count = nleft;

                    /* Fill in the range of codes/sids. */
                    for (var k = i; k < nleft + i; k++, glyph_code++)
                    {
                        /* Make sure k is not too big. */
                        if (k < num_glyphs && glyph_code < 256)
                        {
                            /* Assign code to GID mapping. */
                            encoding.codes[glyph_code] = k;
                            /* Assign code to SID mapping. */
                            encoding.sids[glyph_code] = charset.sids[k];
                        }
                    }
                }

                /* simple check; one never knows what can be found in a font */
                if (encoding.count > 256)
                    encoding.count = 256;

                break;

            default:
                return 3;
        }

        /* Parse supplemental encodings, if any. */
        if (encoding.format & 0x80)
        {
            count = stream.ReadUChar();
            error = FT_Error;
            if (error != 0)
                return error;

            for (j = 0; j < count; j++)
            {
                /* Read supplemental glyph code. */
                glyph_code = stream.ReadUChar();
                error = FT_Error;
                if (error != 0)
                    return error;

                glyph_sid = stream.ReadUShort();
                error = FT_Error;
                if (error != 0)
                    return error;

                /* Assign code to SID mapping. */
                encoding.sids[glyph_code] = glyph_sid;

                /* First, look up GID which has been assigned to */
                /* SID glyph_sid.                                */
                for (var gindex = 0; gindex < num_glyphs; gindex++)
                {
                    if (charset.sids[gindex] == glyph_sid)
                    {
                        encoding.codes[glyph_code] = gindex;
                        break;
                    }
                }
            }
        }
    }
    else
    {
        /* We take into account the fact a CFF font can use a predefined */
        /* encoding without containing all of the glyphs encoded by this */
        /* encoding (see the note at the end of section 12 in the CFF    */
        /* specification).                                               */

        switch (offset)
        {
        case 0:
        case 1:
            var src = (offset == 0) ? cff_standard_encoding : cff_expert_encoding;
            for (var k = 0; k < 256; k++)
                encoding.sids[k] = src[k];

            encoding.count = 0;
            error = cff_charset_compute_cids(charset, num_glyphs, stream.memory);
            if (error != 0)
                return error;

            for (j = 0; j < 256; j++)
            {
                var sid = encoding.sids[j];
                var gid = 0;


                if (sid)
                    gid = cff_charset_cid_to_gindex(charset, sid);

                if ( gid != 0 )
                {
                    encoding.codes[j] = gid;
                    encoding.count    = j + 1;
                }
                else
                {
                    encoding.codes[j] = 0;
                    encoding.sids [j] = 0;
                }
            }
            break;

        default:
            return 3;
        }
    }

    return error;
}

function cff_subfont_load(font, idx, font_index, stream, base_offset, library)
{
    var error = 0;
    var parser = new CFF_ParserRec();
    var top = font.font_dict;
    var priv = font.private_dict;

    cff_parser_init(parser, 4096, font.font_dict, library);

    /* set defaults */
    top.clear();

    top.underline_position  = -100 << 16;
    top.underline_thickness = 50 << 16;
    top.charstring_type     = 2;
    top.font_matrix.xx      = 0x10000;
    top.font_matrix.yy      = 0x10000;
    top.cid_count           = 8720;

    /* we use the implementation specific SID value 0xFFFF to indicate */
    /* missing entries                                                 */
    top.version             = 0xFFFF;
    top.notice              = 0xFFFF;
    top.copyright           = 0xFFFF;
    top.full_name           = 0xFFFF;
    top.family_name         = 0xFFFF;
    top.weight              = 0xFFFF;
    top.embedded_postscript = 0xFFFF;

    top.cid_registry        = 0xFFFF;
    top.cid_ordering        = 0xFFFF;
    top.cid_font_name       = 0xFFFF;

    var ret = cff_index_access_element(idx, font_index);
    error = ret.err;
    var dict = ret.bytes;
    var dict_len = ret.len;

    if (error == 0)
    {
        error = cff_parser_run(parser, dict, dict.pos + dict_len);
    }

    cff_index_forget_element(idx, dict);

    if (error != 0)
        return error;

    /* if it is a CID font, we stop there */
    if (top.cid_registry != 0xFFFF)
        return error;

    /* parse the private dictionary, if any */
    if (top.private_offset != 0 && top.private_size != 0)
    {
        priv.clear();

        priv.blue_shift       = 7;
        priv.blue_fuzz        = 1;
        priv.lenIV            = -1;
        priv.expansion_factor = parseInt(0.06 * 0x10000);
        priv.blue_scale       = parseInt(0.039625 * 0x10000 * 1000);

        cff_parser_init(parser, 8192, priv, library);

        error = stream.Seek(base_offset + font.font_dict.private_offset);
        if (error != 0)
            return error;

        error = stream.EnterFrame(font.font_dict.private_size);
        if (error != 0)
            return error;

        var curs = new CPointer();
        curs.data = stream.data;
        curs.pos = stream.cur;
        error = cff_parser_run(parser, curs, curs.pos + font.font_dict.private_size);

        stream.ExitFrame();
        if (error != 0)
            return error;

        /* ensure that `num_blue_values' is even */
        priv.num_blue_values &= ~1;
    }

    /* read the local subrs, if any */
    if (priv.local_subrs_offset != 0)
    {
        error = stream.Seek(base_offset + top.private_offset + priv.local_subrs_offset);
        if (error != 0)
            return error;

        error = cff_index_init(font.local_subrs_index, stream, 1);
        if (error != 0)
            return error;

        ret = cff_index_get_pointers(font.local_subrs_index, font.local_subrs, null, 0);
        error = ret.err;
        font.local_subrs = ret.table;
        if (error != 0)
            return error;
    }

    return error;
}

function cff_subfont_done(memory, subfont)
{
    if (subfont != null)
    {
        cff_index_done(subfont.local_subrs_index);
        subfont.local_subrs = null;
    }
}

function cff_font_load(library, stream, face_index, font, pure_cff)
{
    var error = 0;
    var memory = stream.memory;
    var base_offset = stream.pos;
    var dict = font.top_font.font_dict;
    var string_index = new CFF_IndexRec();

    // TODO: font.clear();
    error = stream.EnterFrame(4);
    if (error != 0)
        return error;

    /* read CFF font header */
    font.version_major = stream.GetUChar();
    font.version_minor = stream.GetUChar();
    font.header_size = stream.GetUChar();
    font.absolute_offsize = stream.GetUChar();

    stream.ExitFrame();

    /* check format */
    if (font.version_major != 1 || font.header_size < 4 || font.absolute_offsize > 4)
        return 2;

    /* skip the rest of the header */
    error = stream.Skip(font.header_size - 4);
    if (error != 0)
        return error;

    /* read the name, top dict, string and global subrs index */
    error = cff_index_init(font.name_index, stream, 0);
    if (error == 0)
        error = cff_index_init(font.font_dict_index, stream, 0);
    if (error == 0)
        error = cff_index_init(string_index, stream, 1);
    if (error == 0)
        error = cff_index_init(font.global_subrs_index, stream, 1);

    if (error != 0)
        return error;

    var ret = cff_index_get_pointers(string_index, font.strings, font.string_pool, 1);
    error = ret.err;
    font.strings = ret.table;
    font.string_pool = ret.pool;

    font.num_strings = string_index.count;

    /* well, we don't really forget the `disabled' fonts... */
    font.num_faces = font.name_index.count;
    if (face_index >= font.num_faces)
    {
        error = 6;
    }

    /* in case of a font format check, simply exit now */
    if (face_index < 0)
        return error;

    /* now, parse the top-level font dictionary */
    error = cff_subfont_load(font.top_font, font.font_dict_index, face_index, stream, base_offset, library);
    if (error != 0)
        return error;

    error = stream.Seek(base_offset + dict.charstrings_offset);
    if (error != 0)
        return error;

    error = cff_index_init(font.charstrings_index, stream, 0);
    if (error != 0)
        return error;

    /* now, check for a CID font */
    if (dict.cid_registry != 0xFFFF)
    {
        var fd_index = new CFF_IndexRec();
        var sub = null;

        /* this is a CID-keyed font, we must now allocate a table of */
        /* sub-fonts, then load each of them separately              */
        error = stream.Seek(base_offset + dict.cid_fd_array_offset);
        if (error != 0)
            return error;

        error = cff_index_init(fd_index, stream, 0);
        if (error != 0)
            return error;

        if (fd_index.count > 256)
        {
            cff_index_done(fd_index);
        }
        else
        {
            var _is_break = 0;
            /* allocate & read each font dict independently */
            font.num_subfonts = fd_index.count;
            sub = new Array(fd_index.count);

            for (var idx = 0; idx < fd_index.count; idx++)
                sub[idx] = new CFF_SubFontRec();

            /* set up pointer table */
            for (var idx = 0; idx < fd_index.count; idx++)
                font.subfonts[idx] = sub[idx];

            /* now load each subfont independently */
            for (var idx = 0; idx < fd_index.count; idx++)
            {
                error = cff_subfont_load(font.subfonts[idx], fd_index, idx, stream, base_offset, library);
                if (error != 0)
                {
                    cff_index_done(fd_index);
                    _is_break = 1;
                }
            }

            /* now load the FD Select array */
            if (_is_break == 0)
            {
                error = CFF_Load_FD_Select(font.fd_select, font.charstrings_index.count, stream, base_offset + dict.cid_fd_select_offset);
            }

            cff_index_done(fd_index);

            if (error != 0)
                return error;
        }
    }
    else
        font.num_subfonts = 0;

    /* read the charstrings index now */
    if (dict.charstrings_offset == 0)
        return 3;


    font.num_glyphs = font.charstrings_index.count;

    ret = cff_index_get_pointers(font.global_subrs_index, font.global_subrs, null, 0);
    error = ret.err;
    font.global_subrs = ret.table;

    if (error != 0)
        return error;

    /* read the Charset and Encoding tables if available */
    if (font.num_glyphs > 0)
    {
        var invert = (dict.cid_registry != 0xFFFF && pure_cff) ? 1 : 0;

        error = cff_charset_load(font.charset, font.num_glyphs, stream, base_offset, dict.charset_offset, invert);
        if (error != 0)
            return error;

        /* CID-keyed CFFs don't have an encoding */
        if (dict.cid_registry == 0xFFFF)
        {
            error = cff_encoding_load(font.encoding, font.charset, font.num_glyphs, stream, base_offset, dict.encoding_offset);
            if (error != 0)
                return error;
        }
    }

    /* get the font name (/CIDFontName for CID-keyed fonts, */
    /* /FontName otherwise)                                 */
    font.font_name = cff_index_get_name(font, face_index);

    cff_index_done(string_index);
    return error;
}

function cff_font_done(font)
{
    var memory = font.memory;

    cff_index_done(font.global_subrs_index);
    cff_index_done(font.font_dict_index );
    cff_index_done(font.name_index);
    cff_index_done(font.charstrings_index);

    /* release font dictionaries, but only if working with */
    /* a CID keyed CFF font                                */
    if (font.num_subfonts > 0)
    {
        for (var idx = 0; idx < font.num_subfonts; idx++)
            cff_subfont_done(memory, font.subfonts[idx]);

        /* the subfonts array has been allocated as a single block */
        font.subfonts[0] = null;
    }

    cff_encoding_done(font.encoding);
    cff_charset_done(font.charset, font.stream);

    cff_subfont_done(memory, font.top_font);

    CFF_Done_FD_Select(font.fd_select, font.stream);

    font.font_info = null;

    font.strings = null;
    font.string_pool = null;
}

/******************************************************************************/
// cffcmaps
/******************************************************************************/
function CFF_CMapStdRec()
{
    this.cmap = new FT_CMapRec();
    this.gids = null;

    this.type = 1;
}

function cff_cmap_encoding_init(cmap)
{
    cmap.gids = __FT_CMapRec(cmap).charmap.face.extra.data.encoding.codes;
    return 0;
}

function cff_cmap_encoding_done(cmap)
{
    cmap.gids = null;
}

function cff_cmap_encoding_char_index(cmap, char_code)
{
    if (char_code < 256)
        return cmap.gids[char_code];

    return 0;
}

function cff_cmap_encoding_char_next(cmap, pchar_code)
{
    var char_code = pchar_code;
    var ret = {gindex: 0, char_code: 0};

    if (char_code < 255)
    {
        var code = char_code + 1;

        for (;;)
        {
            if (code >= 256)
                break;

            ret.gindex = cmap.gids[code];
            if (ret.gindex != 0)
            {
                ret.char_code = code;
                break;
            }
            code++;
        }
    }
    return ret;
}

var cff_cmap_encoding_class_rec = create_cmap_class_rec(101,cff_cmap_encoding_init,cff_cmap_encoding_done,cff_cmap_encoding_char_index,cff_cmap_encoding_char_next,null,null,null,null,null);

function cff_sid_to_glyph_name(face, idx)
{
    var cff = face.extra.data;
    var sid = cff.charset.sids[idx];

    return cff_index_get_sid_string(cff, sid);
}

function cff_cmap_unicode_init(unicodes)
{
    var face = __FT_CharmapRec(unicodes).face;
    var cff = face.extra.data;
    var charset = cff.charset;
    var psnames = cff.psnames;

    /* can't build Unicode map for CID-keyed font */
    /* because we don't know glyph names.         */
    if (charset.sids == null)
        return 163;

    return psnames.unicodes_init(face.memory, unicodes, cff.num_glyphs, cff_sid_to_glyph_name, null, face);
}

function cff_cmap_unicode_done(unicodes)
{
    unicodes.maps = null;
    unicodes.num_maps = 0;
}

function cff_cmap_unicode_char_index(unicodes, char_code)
{
    var face = __FT_CharmapRec(unicodes).face;
    var psnames = face.extra.data.psnames;

    return psnames.unicodes_char_index(unicodes, char_code);
}

function cff_cmap_unicode_char_next(unicodes, pchar_code)
{
    var face = __FT_CharmapRec(unicodes).face;
    var psnames = face.extra.data.psnames;

    return psnames.unicodes_char_next(unicodes, pchar_code);
}

var cff_cmap_unicode_class_rec = create_cmap_class_rec(102,cff_cmap_unicode_init,cff_cmap_unicode_done,cff_cmap_unicode_char_index,cff_cmap_unicode_char_next,null,null,null,null,null);

/******************************************************************************/
// cffobjs
/******************************************************************************/

function CFF_SizeRec()
{
    this.face = null;
    this.generic = null;
    this.metrics = new FT_Size_Metrics();
    this.internal = null;
    
    this.strike_index = 0;    /* 0xFFFFFFFF to indicate invalid */
}

function CFF_GlyphSlotRec()
{
    this.root = new FT_GlyphSlot();

    this.hint = 0;
    this.scaled = 0;

    this.x_scale = 0;
    this.y_scale = 0;
}

function CFF_InternalRec()
{
    this.topfont = null;
    this.subfonts = new Array(256);
}

function CFF_Transform()
{
    this.xx = 0;
    this.xy = 0;
    this.yx = 0;
    this.yy = 0;

    this.ox = 0;
    this.oy = 0;
}

function cff_size_get_globals_funcs(size)
{
    var face = size.face;
    var font = face.extra.data;
    var pshinter = font.pshinter;

    var module = face.driver.library.FT_Get_Module("pshinter");
    return (module != null && pshinter != null && pshinter.get_globals_funcs != null) ? pshinter.get_globals_funcs(module) : null;
}

function cff_size_done(cffsize)
{
    var internal = cffsize.internal;
    if (internal != null)
    {
        var funcs = cff_size_get_globals_funcs(cffsize);
        if (funcs != null)
        {
            funcs.destroy(internal.topfont);

            for (var i = internal.topfont.num_subfonts; i > 0; i--)
                funcs.destroy(internal.subfonts[i - 1]);
        }
        /* `internal' is freed by destroy_size (in ftobjs.c) */
    }
}

function cff_make_private_dict(subfont, priv)
{
    var cpriv = subfont.private_dict;
    var n = 0;
    priv.clear();

    var count = priv.num_blue_values = cpriv.num_blue_values;
    for (n = 0; n < count; n++)
        priv.blue_values[n] = cpriv.blue_values[n];

    count = priv.num_other_blues = cpriv.num_other_blues;
    for (n = 0; n < count; n++)
        priv.other_blues[n] = cpriv.other_blues[n];

    count = priv.num_family_blues = cpriv.num_family_blues;
    for (n = 0; n < count; n++)
        priv.family_blues[n] = cpriv.family_blues[n];

    count = priv.num_family_other_blues = cpriv.num_family_other_blues;
    for (n = 0; n < count; n++)
        priv.family_other_blues[n] = cpriv.family_other_blues[n];

    priv.blue_scale = cpriv.blue_scale;
    priv.blue_shift = cpriv.blue_shift;
    priv.blue_fuzz  = cpriv.blue_fuzz;

    priv.standard_width[0]  = cpriv.standard_width;
    priv.standard_height[0] = cpriv.standard_height;

    count = priv.num_snap_widths = cpriv.num_snap_widths;
    for (n = 0; n < count; n++)
        priv.snap_widths[n] = cpriv.snap_widths[n];

    count = priv.num_snap_heights = cpriv.num_snap_heights;
    for (n = 0; n < count; n++)
        priv.snap_heights[n] = cpriv.snap_heights[n];

    priv.force_bold     = cpriv.force_bold;
    priv.language_group = cpriv.language_group;
    priv.lenIV          = cpriv.lenIV;
}

function cff_size_init()
{
    var size = new CFF_SizeRec();
    var funcs = null;//cff_size_get_globals_funcs(size);

    if (funcs != null)
    {
        // TODO: global funcs...
    }

    FT_Error = 0;
    size.strike_index = 0xFFFFFFFF;
    return size;
}

function cff_size_select(size, strike_index)
{
    size.strike_index = strike_index;
    FT_Select_Metrics(size.face, strike_index);

    var funcs = cff_size_get_globals_funcs(size);

    if (funcs != null)
    {
        // TODO: global funcs...
    }

    return 0;
}

function cff_size_request(size, req)
{
    var face = size.face;
    if (0 != (face.face_flags & 2))
    {
        var sfnt = face.sfnt;
        
        var strike_index = sfnt.set_sbit_strike(face, req);
        if (FT_Error != 0)
            size.strike_index = 0xFFFFFFFF;
        else
            return cff_size_select(size, strike_index);
    }

    FT_Request_Metrics(size.face, req);

    var funcs = cff_size_get_globals_funcs(size);
    if (funcs != null)
    {
        // TODO: global funcs...
    }
    return 0;
}

function cff_slot_done(slot)
{
    slot.internal.glyph_hints = null;
}

function cff_slot_init(slot)
{
    var face     = slot.face;
    var font     = face.extra.data;
    var pshinter = font.pshinter;

    if (pshinter != null)
    {
        var module = face.driver.library.FT_Get_Module("pshinter");
        if (module != null)
        {
            slot.internal.glyph_hints = pshinter.get_t2_funcs(module);
        }
    }
    return 0;
}

function cff_strcpy(memory, source)
{
    var result = source;
    return result;
}

function remove_subset_prefix(name)
{
    var idx = 0;
    var length = name.length + 1;
    var continue_search = 1;

    while (continue_search)
    {
        if (length >= 7 && name.charCodeAt(6) == 43)
        {
            for (idx = 0; idx < 6; idx++)
            {
                /* ASCII uppercase letters */
                var c = name.charCodeAt(idx);
                if (!(65 <= c && c <= 90))
                    continue_search = 0;
            }

            if (continue_search)
            {
                name = name.substring(7);
                length -= 7;
            }
        }
        else
            continue_search = 0;
    }

    return name;
}

function remove_style(family_name, style_name)
{
    var family_name_length = family_name.length;
    var style_name_length  = style_name.length;

    if (family_name_length > style_name_length)
    {
        var idx = 0;
        for (idx = 1; idx <= style_name_length; idx++)
        {
            if (family_name.charCodeAt(family_name_length - idx) != style_name.charCodeAt(style_name_length - idx))
                break;
        }

        if (idx > style_name_length)
        {
            /* family_name ends with style_name; remove it */
            idx = family_name_length - style_name_length - 1;

            /* also remove special characters     */
            /* between real family name and style */
            while (idx > 0)
            {
                var c = family_name.charCodeAt(idx);
                if (c == 45 || c == 32 || c == 95 || c == 43)
                    break;
                
                --idx;
            }

            if (idx > 0)
                family_name = family_name.substring(0, idx);
        }
    }

    return family_name;
}

function cff_face_init(stream, face, face_index, num_params, params)
{
    var pure_cff = 1;
    var sfnt_format = 0;
    var flags = 0;
    var library = face.driver.library;

    var sfnt = library.FT_Get_Module_Interface("sfnt");
    if (sfnt == null)
        return 2;

    var psnames = FT_FACE_FIND_GLOBAL_SERVICE(face, FT_SERVICE_ID_POSTSCRIPT_CMAPS);
    var pshinter = library.FT_Get_Module_Interface("pshinter");

    /* create input stream from resource */
    var error = stream.Seek(0);
    if (error != 0)
        return error;

    /* check whether we have a valid OpenType file */
    error = sfnt.init_face(stream, face, face_index, num_params, params);
    if (error == 0)
    {
        if (face.format_tag != 1330926671)
            return 2;

        /* if we are performing a simple font format check, exit immediately */
        if (face_index < 0)
            return 0;

        /* UNDOCUMENTED!  A CFF in an SFNT can have only a single font. */
        if (face_index > 0)
            return 6;

        sfnt_format = 1;

        /* now, the font can be either an OpenType/CFF font, or an SVG CEF */
        /* font; in the latter case it doesn't have a `head' table         */
        face.goto_table(face, 1751474532, stream);
        error = FT_Error;
        if (error == 0)
        {
            pure_cff = 0;

            /* load font directory */
            error = sfnt.load_face(stream, face, 0);
            if (error != 0)
                return error;
        }
        else
        {
            /* load the `cmap' table explicitly */
            error = sfnt.load_cmap(face, stream);
            if (error != 0)
                return error;

            /* XXX: we don't load the GPOS table, as OpenType Layout     */
            /* support will be added later to a layout library on top of */
            /* FreeType 2                                                */
        }

        /* now load the CFF part of the file */
        face.goto_table(face, 1128678944, stream);
        error = FT_Error;
        if (error != 0)
            return error;
    }
    else
    {
        /* rewind to start of file; we are going to load a pure-CFF font */
        error = stream.Seek(0);
        if (error != 0)
            return error;
    }

    /* now load and parse the CFF table in the file */
    var cff = new CFF_FontRec();
    face.extra.data = cff;
    
    error = cff_font_load(library, stream, face_index, cff, pure_cff);
    if (error != 0)
        return error;

    cff.pshinter = pshinter;
    cff.psnames  = psnames;

    face.face_index = face_index;

    /* Complement the root flags with some interesting information. */
    /* Note that this is only necessary for pure CFF and CEF fonts; */
    /* SFNT based fonts use the `name' table instead.               */
    face.num_glyphs = cff.num_glyphs;
    var dict = cff.top_font.font_dict;

    /* we need the `PSNames' module for CFF and CEF formats */
    /* which aren't CID-keyed                               */
    if (dict.cid_registry == 0xFFFF && psnames == null)
        return 2;

    if (dict.has_font_matrix == 0)
        dict.units_per_em = pure_cff ? 1000 : face.units_per_EM;

    /* Normalize the font matrix so that `matrix->xx' is 1; the */
    /* scaling is done with `units_per_em' then (at this point, */
    /* it already contains the scaling factor, but without      */
    /* normalization of the matrix).                            */
    /*                                                          */
    /* Note that the offsets must be expressed in integer font  */
    /* units.                                                   */
    var matrix = dict.font_matrix;
    var offset = dict.font_offset;
    var temp = Math.abs(matrix.yy);

    if (temp != 0x10000)
    {
        dict.units_per_em = FT_DivFix(dict.units_per_em, temp);

        matrix.xx = FT_DivFix(matrix.xx, temp);
        matrix.yx = FT_DivFix(matrix.yx, temp);
        matrix.xy = FT_DivFix(matrix.xy, temp);
        matrix.yy = FT_DivFix(matrix.yy, temp);
        offset.x  = FT_DivFix(offset.x,  temp);
        offset.y  = FT_DivFix(offset.y,  temp);
    }

    offset.x >>= 16;
    offset.y >>= 16;

    for (var i = cff.num_subfonts; i > 0; i--)
    {
        var sub = cff.subfonts[i - 1].font_dict;
        var top = cff.top_font.font_dict;

        if (sub.has_font_matrix == 1)
        {
            var scaling = 0;
            /* if we have a top-level matrix, */
            /* concatenate the subfont matrix */

            if (top.has_font_matrix == 1)
            {
                if (top.units_per_em > 1 && sub.units_per_em > 1)
                    scaling = Math.min(top.units_per_em, sub.units_per_em);
                else
                    scaling = 1;

                FT_Matrix_Multiply_Scaled(top.font_matrix, sub.font_matrix, scaling);
                FT_Vector_Transform_Scaled(sub.font_offset, top.font_matrix, scaling);

                sub.units_per_em = FT_MulDiv(sub.units_per_em, top.units_per_em, scaling);
            }
        }
        else
        {
            sub.font_matrix = top.font_matrix;
            sub.font_offset = top.font_offset;

            sub.units_per_em = top.units_per_em;
        }

        matrix = sub.font_matrix;
        offset = sub.font_offset;
        temp = Math.abs(matrix.yy);

        if (temp != 0x10000)
        {
            sub.units_per_em = FT_DivFix(sub.units_per_em, temp);

            matrix.xx = FT_DivFix(matrix.xx, temp);
            matrix.yx = FT_DivFix(matrix.yx, temp);
            matrix.xy = FT_DivFix(matrix.xy, temp);
            matrix.yy = FT_DivFix(matrix.yy, temp);
            offset.x  = FT_DivFix(offset.x,  temp);
            offset.y  = FT_DivFix(offset.y,  temp);
        }

        offset.x >>= 16;
        offset.y >>= 16;
    }

    if (pure_cff == 1)
    {
        var style_name = null;

        /* set up num_faces */
        face.num_faces = cff.num_faces;

        /* compute number of glyphs */
        if (dict.cid_registry != 0xFFFF)
            face.num_glyphs = cff.charset.max_cid + 1;
        else
            face.num_glyphs = cff.charstrings_index.count;

        /* set global bbox, as well as EM size */
        face.bbox.xMin = dict.font_bbox.xMin >> 16;
        face.bbox.yMin = dict.font_bbox.yMin >> 16;
        /* no `U' suffix here to 0xFFFF! */
        face.bbox.xMax = (dict.font_bbox.xMax + 0xFFFF) >> 16;
        face.bbox.yMax = (dict.font_bbox.yMax + 0xFFFF) >> 16;

        face.units_per_EM = dict.units_per_em & 0xFFFF;

        face.ascender  = face.bbox.yMax;
        face.descender = face.bbox.yMin;

        face.height = ((face.units_per_EM * 12) / 10);
        if (face.height < (face.ascender - face.descender))
            face.height = (face.ascender - face.descender);

        face.underline_position = (dict.underline_position >> 16);
        face.underline_thickness = (dict.underline_thickness >> 16);

        /* retrieve font family & style name */
        face.family_name = cff_index_get_name(cff, face_index);
        if (face.family_name != null)
        {
            var full = cff_index_get_sid_string(cff, dict.full_name);
            var fullp = 0;
            var family = face.family_name;
            var family_name = null;

            face.family_name = remove_subset_prefix(face.family_name);

            if (dict.family_name != 0)
            {
                family_name = cff_index_get_sid_string(cff, dict.family_name);
                if (family_name != null)
                    family = family_name;
            }

            var familyp = 0;
            var full_len = (full == null) ? 0 : full.length;
            var family_len = family.length;

            /* We try to extract the style name from the full name.   */
            /* We need to ignore spaces and dashes during the search. */
            if (full != null && family != null)
            {
                while (fullp < full_len)
                {
                    var _c1 = full.charCodeAt(fullp);
                    var _c2 = 0;
                    if (familyp < family_len)
                        _c2 = family.charCodeAt(familyp);

                    /* skip common characters at the start of both strings */
                    if (_c1 == _c2)
                    {
                        familyp++;
                        fullp++;
                        continue;
                    }

                    if (_c1 == 32 || _c1 == 45)
                    {
                        fullp++;
                        continue;
                    }

                    if (_c2 == 32 || _c2 == 45)
                    {
                        familyp++;
                        continue;
                    }

                    if (familyp >= family_len && fullp < full_len)
                    {
                        /* The full name begins with the same characters as the  */
                        /* family name, with spaces and dashes removed.  In this */
                        /* case, the remaining string in `fullp' will be used as */
                        /* the style name.                                       */
                        style_name = full.substring(fullp);

                        /* remove the style part from the family name (if present) */
                        face.family_name = remove_style(face.family_name, style_name);
                    }
                    break;
                }
            }
        }
        else
        {
            var cid_font_name = cff_index_get_sid_string(cff, dict.cid_font_name);
            /* do we have a `/FontName' for a CID-keyed font? */
            if (cid_font_name != null)
                face.family_name = cff_strcpy(face.memory, cid_font_name);
        }

        if (style_name != null)
            face.style_name = style_name;
        else /* assume "Regular" style if we don't know better */
            face.style_name = "Regular";

        /*******************************************************************/
        /*                                                                 */
        /* Compute face flags.                                             */
        /*                                                                 */
        flags = (1 | 16 | 2048);

        if (sfnt_format != 0)
            flags |= 8;

        /* fixed width font? */
        if (dict.is_fixed_pitch != 0)
            flags |= 4;

        /* XXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */

        face.face_flags = flags;
        /*******************************************************************/
        /*                                                                 */
        /* Compute style flags.                                            */
        /*                                                                 */
        flags = 0;

        if (dict.italic_angle != 0)
            flags |= 1;

        var weight = cff_index_get_sid_string(cff, dict.weight);
        if (weight != null)
            if (weight == "Bold" || weight == "Black")
                flags |= 2;

        /* double check */
        if (0 == (flags & 2) && face.style_name != null)
            if (!_strncmp(face.style_name, "Bold", 4) || !_strncmp(face.style_name, "Black", 5))
                flags |= 2;

        face.style_flags = flags;
    }


    //#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES
    /* CID-keyed CFF fonts don't have glyph names -- the SFNT loader */
    /* has unset this flag because of the 3.0 `post' table.          */
    if (dict.cid_registry == 0xFFFF)
        face.face_flags |= 512;
    //#endif

    if (dict.cid_registry != 0xFFFF && pure_cff == 1)
        face.face_flags |= 4096;


    /*******************************************************************/
    /*                                                                 */
    /* Compute char maps.                                              */
    /*                                                                 */

    /* Try to synthesize a Unicode charmap if there is none available */
    /* already.  If an OpenType font contains a Unicode "cmap", we    */
    /* will use it, whatever be in the CFF part of the file.          */
    var cmaprec = new FT_CharMapRec();
    var cmap = null;
    var nn = 0;
    var encoding = cff.encoding;

    var is_skip_unicode = 0;
    for (nn = 0; nn < face.num_charmaps; nn++)
    {
        cmap = face.charmaps[nn];

        /* Windows Unicode? */
        if (cmap.platform_id == 3 && cmap.encoding_id == 1)
            is_skip_unicode = 1;

        /* Apple Unicode platform id? */
        if (cmap.platform_id == 0)
            is_skip_unicode = 1; /* Apple Unicode */
    }

    if (0 == is_skip_unicode)
    {
        /* since CID-keyed fonts don't contain glyph names, we can't */
        /* construct a cmap                                          */
        if (pure_cff == 1 && cff.top_font.font_dict.cid_registry != 0xFFFF)
            return error;

        //#ifdef FT_MAX_CHARMAP_CACHEABLE
        if (nn + 1 > 15)
            return error;
        //#endif

        /* we didn't find a Unicode charmap -- synthesize one */
        cmaprec.face        = face;
        cmaprec.platform_id = 3;
        cmaprec.encoding_id = 1;
        cmaprec.encoding    = 1970170211;

        nn = face.num_charmaps;

        FT_CMap_New(FT_CFF_CMAP_UNICODE_CLASS_REC_GET, null, cmaprec);
        error = FT_Error;
        if (error && 163 != error)
            return error;
        error = 0;

        /* if no Unicode charmap was previously selected, select this one */
        if (face.charmap == null && nn != face.num_charmaps)
            face.charmap = face.charmaps[nn];
    }

    //#ifdef FT_MAX_CHARMAP_CACHEABLE
    if (nn > 15)
        return error;
    //#endif

    if (encoding.count > 0)
    {
        var clazz = null;

        cmaprec.face = face;
        cmaprec.platform_id = 7;  /* Adobe platform id */

        if (encoding.offset == 0)
        {
            cmaprec.encoding_id = 0;
            cmaprec.encoding    = 1094995778;
            clazz               = FT_CFF_CMAP_ENCODING_CLASS_REC_GET;
        }
        else if (encoding.offset == 1)
        {
            cmaprec.encoding_id = 1;
            cmaprec.encoding    = 1094992453;
            clazz               = FT_CFF_CMAP_ENCODING_CLASS_REC_GET;
        }
        else
        {
            cmaprec.encoding_id = 2;
            cmaprec.encoding    = 1094992451;
            clazz               = FT_CFF_CMAP_ENCODING_CLASS_REC_GET;
        }

        FT_CMap_New(clazz, null, cmaprec);
        error = FT_Error;
    }

    return error;
}

function cff_face_done(face)
{
    if (face == null)
        return;

    var sfnt = face.sfnt;

    if (sfnt != null)
        sfnt.done_face(face);

    var cff = face.extra.data;
    if (cff != null)
    {
        cff_font_done(cff);
        face.extra.data = null;
    }
}

function cff_driver_init(module)
{
    return 0;
}

function cff_driver_done(module)
{
}

/******************************************************************************/
// cffgload
/******************************************************************************/

var cff_argument_counts =
[
    0,  /* unknown */

    2 | 128 | 64, /* rmoveto */
    1 | 128 | 64,
    1 | 128 | 64,

    0 | 32, /* rlineto */
    0 | 32,
    0 | 32,

    0 | 32, /* rrcurveto */
    0 | 32,
    0 | 32,
    0 | 32,
    0 | 32,
    0 | 32,
    0 | 32,

    13, /* flex */
    7,
    9,
    11,

    0 | 128, /* endchar */

    2 | 128, /* hstem */
    2 | 128,
    2 | 128,
    2 | 128,

    0 | 128, /* hintmask */
    0 | 128, /* cntrmask */
    0, /* dotsection */

    1, /* abs */
    2,
    2,
    2,
    1,
    0,
    2,
    1,

    1, /* blend */

    1, /* drop */
    2,
    1,
    2,
    1,

    2, /* put */
    1,
    4,
    3,

    2, /* and */
    2,
    1,
    2,
    4,

    1, /* callsubr */
    1,
    0,

    2, /* hsbw */
    0,
    0,
    0,
    5, /* seac */
    4, /* sbw */
    2  /* setcurrentpoint */
];

function CFF_Builder()
{
    this.memory = null;
    this.face = null;
    this.glyph = null;
    this.loader = null;
    this.base = null;
    this.current = null;

    this.pos_x = 0;
    this.pos_y = 0;

    this.left_bearing = new FT_Vector();
    this.advance = new FT_Vector();

    this.bbox = new FT_BBox();
    this.path_begun = 0;
    this.load_points = 0;
    this.no_recurse = 0;

    this.metrics_only = 0;

    this.hints_funcs = null;
    this.hints_globals = null;

    this.clear = function()
    {
        this.memory = null;
        this.face = null;
        this.glyph = null;
        this.loader = null;
        this.base = null;
        this.current = null;

        this.pos_x = 0;
        this.pos_y = 0;

        this.left_bearing.x = 0;
        this.left_bearing.y = 0;

        this.advance.x = 0;
        this.advance.y = 0;

        this.bbox.xMin = 0;
        this.bbox.yMin = 0;
        this.bbox.xMax = 0;
        this.bbox.yMax = 0;

        this.path_begun = 0;
        this.load_points = 0;
        this.no_recurse = 0;

        this.metrics_only = 0;

        this.hints_funcs = null;
        this.hints_globals = null;
    }
}

function CFF_Decoder_Zone()
{
    this.base = null;
    this.limit = 0;
    this.cursor = 0;
}

function CFF_Decoder()
{
    this.builder = new CFF_Builder();
    this.cff = null;

    this.stack = CreateIntArray(48 + 1);
    this.top = 0;

    this.zones = new Array(32 + 1);
    for (var i = 0; i < (32 + 1); i++)
        this.zones[i] = new CFF_Decoder_Zone();

    this.zone = 0;

    this.flex_state = 0;
    this.num_flex_vectors = 0;

    this.flex_vectors = new Array(7);
    for (var i = 0; i < 7; i++)
        this.flex_vectors[i] = new FT_Vector();

    this.glyph_width = 0;
    this.nominal_width = 0;

    this.read_width = 0;
    this.width_only = 0;
    this.num_hints = 0;
    this.buildchar = CreateIntArray(32);

    this.num_locals = 0;
    this.num_globals = 0;

    this.locals_bias = 0;
    this.globals_bias = 0;

    this.locals = null;
    this.globals = null;

    this.glyph_names = null;   /* for pure CFF fonts only  */
    this.num_glyphs = 0;    /* number of glyphs in font */

    this.hint_mode = 0;

    this.seac = 0;

    this.clear = function()
    {
        this.builder.clear();
        this.cff = null;

        this.stack = CreateIntArray(48 + 1);
        for (var i = 0; i < (48 + 1); i++)
            this.stack[i] = 0;
        this.top = 0;

        for (var i = 0; i < (32 + 1); i++)
        {
            var p = this.zones[i];
            p.base = null;
            p.cursor = 0;
            p.limit = 0;
        }

        this.zone = 0;

        this.flex_state = 0;
        this.num_flex_vectors = 0;

        for (var i = 0; i < 7; i++)
        {
            this.flex_vectors[i].x = 0;
            this.flex_vectors[i].y = 0;
        }

        this.glyph_width = 0;
        this.nominal_width = 0;

        this.read_width = 0;
        this.width_only = 0;
        this.num_hints = 0;

        for (var i = 0; i < 32; i++)
            this.buildchar[i] = 0;

        this.num_locals = 0;
        this.num_globals = 0;

        this.locals_bias = 0;
        this.globals_bias = 0;

        this.locals = null;
        this.globals = null;

        this.glyph_names = null;   /* for pure CFF fonts only  */
        this.num_glyphs = 0;    /* number of glyphs in font */

        this.hint_mode = 0;

        this.seac = 0;
    }
}

function cff_builder_init(builder, face, size, glyph, hinting)
{
    builder.path_begun  = 0;
    builder.load_points = 1;

    builder.face   = face;
    builder.glyph  = glyph;
    builder.memory = face.memory;

    if (glyph != null)
    {
        var loader = glyph.internal.loader;

        builder.loader = loader;
        builder.base = loader.base.outline;
        builder.current = loader.current.outline;
        FT_GlyphLoader_Rewind(loader);

        builder.hints_globals = null;
        builder.hints_funcs = null;

        if (hinting && size != null)
        {
            var internal = size.internal;

            builder.hints_globals = internal.topfont;
            builder.hints_funcs = glyph.internal.glyph_hints;
        }
    }

    builder.pos_x = 0;
    builder.pos_y = 0;

    builder.left_bearing.x = 0;
    builder.left_bearing.y = 0;
    builder.advance.x      = 0;
    builder.advance.y      = 0;
}

function cff_builder_done(builder)
{
    var glyph = builder.glyph;
    if (glyph != null)
        EquatingOutline(glyph.outline, builder.base);
}

function cff_compute_bias(in_charstring_type, num_subrs)
{
    if (in_charstring_type == 1)
        return 0;
    else if (num_subrs < 1240)
        return 107;
    else if (num_subrs < 33900)
        return 1131;

    return 32768;
}

function cff_decoder_init(decoder, face, size, slot, hinting, hint_mode)
{
    var cff = face.extra.data;
    /* clear everything */
    decoder.clear();

    /* initialize builder */
    cff_builder_init(decoder.builder, face, size, slot, hinting);

    /* initialize Type2 decoder */
    decoder.cff = cff;
    decoder.num_globals = cff.global_subrs_index.count;
    decoder.globals = cff.global_subrs;
    decoder.globals_bias = cff_compute_bias(cff.top_font.font_dict.charstring_type, decoder.num_globals);

    decoder.hint_mode    = hint_mode;
}

function cff_decoder_prepare(decoder, size, glyph_index)
{
    var builder = decoder.builder;
    var cff = builder.face.extra.data;
    var sub = cff.top_font;

    /* manage CID fonts */
    if (cff.num_subfonts != 0)
    {
        var fd_index = cff_fd_select_get(cff.fd_select, glyph_index);

        if (fd_index >= cff.num_subfonts)
            return 3;

        sub = cff.subfonts[fd_index];

        if (builder.hints_funcs != null && size != null)
        {
            var internal = size.internal;

            /* for CFFs without subfonts, this value has already been set */
            builder.hints_globals = internal.subfonts[fd_index];
        }
    }

    decoder.num_locals = sub.local_subrs_index.count;
    decoder.locals = sub.local_subrs;
    decoder.locals_bias = cff_compute_bias(decoder.cff.top_font.font_dict.charstring_type, decoder.num_locals);

    decoder.glyph_width   = sub.private_dict.default_width;
    decoder.nominal_width = sub.private_dict.nominal_width;

    return 0;
}

function _cff_check_points(builder, count)
{
    return FT_GLYPHLOADER_CHECK_POINTS(builder.loader, count, 0);
}

function cff_builder_add_point(builder, x, y, flag)
{
    var base = builder.base;
    var outline = builder.current;

    if (builder.load_points = 1)
    {
        var point = base.points[outline.points + outline.n_points];
        var control = base.tags[outline.tags + outline.n_points];

        point.x = x >> 16;
        point.y = y >> 16;
        base.tags[outline.tags + outline.n_points] = ((flag != 0) ? 1 : 2);
    }

    outline.n_points++;
}

function cff_builder_add_point1(builder, x, y)
{
    var error = _cff_check_points(builder, 1);
    if (error == 0)
        cff_builder_add_point(builder, x, y, 1);

    return error;
}

function cff_builder_add_contour(builder)
{
    if (builder.load_points == 0)
    {
        builder.current.n_contours++;
        return 0;
    }

    var base = builder.base;
    var outline = builder.current;
    var error = FT_GLYPHLOADER_CHECK_POINTS(builder.loader, 0, 1);
    if (error == 0)
    {
        if (outline.n_contours > 0)
            base.contours[outline.contours + outline.n_contours - 1] = (outline.n_points - 1);

        outline.n_contours++;
    }

    return error;
}

function cff_builder_start_point(builder, x, y)
{
    var error = 0;
    if (builder.path_begun == 0)
    {
        builder.path_begun = 1;
        error = cff_builder_add_contour(builder);
        if (error == 0)
            error = cff_builder_add_point1(builder, x, y);
    }
    return error;
}

function cff_builder_close_contour(builder)
{
    var base = builder.base;
    var outline = builder.current;

    if (outline == null)
        return;

    var first = (outline.n_contours <= 1) ? 0 : base.contours[outline.contours + outline.n_contours - 2] + 1;

    /* We must not include the last point in the path if it */
    /* is located on the first point.                       */
    if (outline.n_points > 1)
    {
        var p1 = base.points[outline.points + first];
        var p2 = base.points[outline.points + outline.n_points - 1];
        var control = base.tags[outline.tags + outline.n_points - 1];

        /* `delete' last point only if it coincides with the first    */
        /* point and if it is not a control point (which can happen). */
        if (p1.x == p2.x && p1.y == p2.y)
            if (control == 1)
                outline.n_points--;
    }

    if (outline.n_contours > 0)
    {
        /* Don't add contours only consisting of one point, i.e., */
        /* check whether begin point and last point are the same. */
        if (first == outline.n_points - 1)
        {
            outline.n_contours--;
            outline.n_points--;
        }
        else
            base.contours[outline.contours + outline.n_contours - 1] = (outline.n_points - 1);
    }
}

function cff_lookup_glyph_by_stdcharcode(cff, charcode)
{
    /* CID-keyed fonts don't have glyph names */
    if (null == cff.charset.sids)
        return -1;

    /* check range of standard char code */
    if (charcode < 0 || charcode > 255)
        return -1;

    /* Get code to SID mapping from `cff_standard_encoding'. */
    var glyph_sid = cff_get_standard_encoding(charcode);

    for (var n = 0; n < cff.num_glyphs; n++)
    {
        if (cff.charset.sids[n] == glyph_sid)
            return n;
    }

    return -1;
}

function cff_get_glyph_data(face, glyph_index)
{
    var cff = face.extra.data;
    return cff_index_access_element(cff.charstrings_index, glyph_index);
}

function cff_free_glyph_data(face, pointer, length)
{
    var cff = face.extra.data;
    cff_index_forget_element(cff.charstrings_index, pointer);
}

function cff_operator_seac(decoder, asb, adx, ady, bchar, achar)
{
    var builder = decoder.builder;
    var bchar_index, achar_index;
    var face = builder.face;

    if (decoder.seac != 0)
        return 160;

    adx += decoder.builder.left_bearing.x;
    ady += decoder.builder.left_bearing.y;

    //#ifdef FT_CONFIG_OPTION_INCREMENTAL
    /* Incremental fonts don't necessarily have valid charsets.        */
    /* They use the character code, not the glyph index, in this case. */
    if (face.internal.incremental_interface != null)
    {
        bchar_index = bchar;
        achar_index = achar;
    }
    else //#endif /* FT_CONFIG_OPTION_INCREMENTAL */
    {
        var cff = face.extra.data;
        bchar_index = cff_lookup_glyph_by_stdcharcode(cff, bchar);
        achar_index = cff_lookup_glyph_by_stdcharcode(cff, achar);
    }

    if (bchar_index < 0 || achar_index < 0)
        return 160;

    /* If we are trying to load a composite glyph, do not load the */
    /* accent character and return the array of subglyphs.         */
    if (builder.no_recurse != 0)
    {
        var glyph  = builder.glyph;
        var loader = glyph.internal.loader;

        /* reallocate subglyph array if necessary */
        error = FT_GlyphLoader_CheckSubGlyphs(loader, 2);
        if (error != 0)
            return error;

        var subg = loader.base.subglyphs[loader.current.subglyphs];

        /* subglyph 0 = base character */
        subg.index = bchar_index;
        subg.flags = 2 | 512;
        subg.arg1  = 0;
        subg.arg2  = 0;

        subg = loader.base.subglyphs[loader.current.subglyphs + 1];

        /* subglyph 1 = accent character */
        subg.index = achar_index;
        subg.flags = 2;
        subg.arg1 = (adx >> 16);
        subg.arg2 = (ady >> 16);

        /* set up remaining glyph fields */
        glyph.num_subglyphs = 2;
        glyph.subglyphs     = loader.base.subglyphs;
        glyph.format = 1668246896;

        loader.current.num_subglyphs = 2;
    }

    FT_GlyphLoader_Prepare(builder.loader);

    /* First load `bchar' in builder */
    var ret = cff_get_glyph_data(face, bchar_index);
    var error = ret.err;
    var charstring = ret.bytes;
    var charstring_len = ret.len;
    if (error == 0)
    {
        /* the seac operator must not be nested */
        decoder.seac = 1;
        error = cff_decoder_parse_charstrings(decoder, charstring, charstring_len);
        decoder.seac = 0;

        cff_free_glyph_data(face, charstring, charstring_len);

        if (error != 0)
            return error;
    }

    /* Save the left bearing, advance and glyph width of the base */
    /* character as they will be erased by the next load.         */

    var left_bearing = dublicate_vector(builder.left_bearing);
    var advance = dublicate_vector(builder.advance);
    var glyph_width = decoder.glyph_width;

    builder.left_bearing.x = 0;
    builder.left_bearing.y = 0;

    builder.pos_x = adx - asb;
    builder.pos_y = ady;

    /* Now load `achar' on top of the base outline. */
    ret = cff_get_glyph_data(face, achar_index);
    error = ret.err;
    charstring = ret.bytes;
    charstring_len = ret.len;
    if (error == 0)
    {
        /* the seac operator must not be nested */
        decoder.seac = 1;
        error = cff_decoder_parse_charstrings(decoder, charstring, charstring_len);
        decoder.seac = 0;

        cff_free_glyph_data(face, charstring, charstring_len);

        if (error != 0)
            return error;
    }

    /* Restore the left side bearing, advance and glyph width */
    /* of the base character.                                 */
    builder.left_bearing.x = left_bearing.x;
    builder.left_bearing.y = left_bearing.y;
    builder.advance.x = advance.x;
    builder.advance.y = advance.y;

    decoder.glyph_width  = glyph_width;

    builder.pos_x = 0;
    builder.pos_y = 0;

    return error;
}

function cff_decoder_parse_charstrings(decoder, charstring_base, charstring_len)
{
    var builder = decoder.builder;
    var charstring_type = decoder.cff.top_font.font_dict.charstring_type;

    /* set default width */
    decoder.num_hints  = 0;
    decoder.read_width = 1;

    /* compute random seed from stack address of parameter */
    var seed = parseInt(Math.random() * 0xFFFF);
    if (seed == 0)
        seed = 0x7384;

    /* initialize the decoder */
    decoder.top = 0;
    decoder.zone = 0;

    var zones = decoder.zones;
    var zone = 0;

    var tops = decoder.stack;
    var stack = decoder.top;

    var hinter = builder.hints_funcs;

    builder.path_begun = 0;

    zones[zone].base = dublicate_pointer(charstring_base);
    var limit = zones[zone].limit = charstring_base.pos + charstring_len;
    zones[zone].cursor = 0;
    var ip = dublicate_pointer(charstring_base);

    var error = 0;

    var x = builder.pos_x;
    var y = builder.pos_y;

    /* begin hints recording session, if any */
    if (hinter != null)
        hinter.open(hinter.hints);

    /* now execute loop */
    while (ip.pos < limit)
    {
        var op = 0;
        /********************************************************************/
        /*                                                                  */
        /* Decode operator or operand                                       */
        /*                                                                  */
        var v = ip.data[ip.pos];
        ip.pos++;
        if (v >= 32 || v == 28)
        {
            var shift = 16;
            var val = 0;

            /* this is an operand, push it on the stack */
            if (v == 28)
            {
                if (ip.pos + 1 >= limit)
                    return 3;
                val = ((ip.data[ip.pos] << 8) | ip.data[ip.pos + 1]);
                if (val > 32767)
                    val = val - 65536;
                ip.pos += 2;
            }
            else if (v < 247)
                val = v - 139;
            else if (v < 251)
            {
                if (ip.pos >= limit)
                    return 3;
                val = (v - 247) * 256 + ip.data[ip.pos] + 108;
                ip.pos++;
            }
            else if (v < 255)
            {
                if (ip.pos >= limit)
                    return 3;
                val = -(v - 251) * 256 - ip.data[ip.pos] - 108;
                ip.pos++;
            }
            else
            {
                if (ip.pos + 3 >= limit)
                    return 3;
                val = (ip.data[ip.pos] << 24 )| (ip.data[ip.pos + 1] << 16) | (ip.data[ip.pos + 2] << 8) | ip.data[ip.pos + 3];
                ip.pos += 4;
                if (charstring_type == 2)
                    shift = 0;
            }
            if (decoder.top >= 48)
                return 130;

            val <<= shift;
            tops[decoder.top] = val;
            decoder.top++;
        }
        else
        {
            /* The specification says that normally arguments are to be taken */
            /* from the bottom of the stack.  However, this seems not to be   */
            /* correct, at least for Acroread 7.0.8 on GNU/Linux: It pops the */
            /* arguments similar to a PS interpreter.                         */
            var args = decoder.top;
            var num_args = args;

            /* find operator */
            op = 0;

            switch (v)
            {
                case 1:
                    op = 19;
                    break;
                case 3:
                    op = 20;
                    break;
                case 4:
                    op = 3;
                    break;
                case 5:
                    op = 4;
                    break;
                case 6:
                    op = 5;
                    break;
                case 7:
                    op = 6;
                    break;
                case 8:
                    op = 7;
                    break;
                case 9:
                    op = 53;
                    break;
                case 10:
                    op = 49;
                    break;
                case 11:
                    op = 51;
                    break;
                case 12:
                {
                    if (ip.pos >= limit)
                        return 3;
                    v = ip.data[ip.pos];
                    ip.pos++;
                    switch (v)
                    {
                        case 0:
                            op = 25;
                            break;
                        case 1: /* this is actually the Type1 vstem3 operator */
                            op = 20;
                            break;
                        case 2: /* this is actually the Type1 hstem3 operator */
                            op = 19;
                            break;
                        case 3:
                            op = 44;
                            break;
                        case 4:
                            op = 45;
                            break;
                        case 5:
                            op = 46;
                            break;
                        case 6:
                            op = 56;
                            break;
                        case 7:
                            op = 57;
                            break;
                        case 8:
                            op = 42;
                            break;
                        case 9:
                            op = 26;
                            break;
                        case 10:
                            op = 27;
                            break;
                        case 11:
                            op = 28;
                            break;
                        case 12:
                            op = 29;
                            break;
                        case 13:
                            op = 43;
                            break;
                        case 14:
                            op = 30;
                            break;
                        case 15:
                            op = 47;
                            break;
                        case 16:
                            op = 54;
                            break;
                        case 17:
                            op = 55;
                            break;
                        case 18:
                            op = 35;
                            break;
                        case 20:
                            op = 40;
                            break;
                        case 21:
                            op = 41;
                            break;
                        case 22:
                            op = 48;
                            break;
                        case 23:
                            op = 31;
                            break;
                        case 24:
                            op = 32;
                            break;
                        case 26:
                            op = 33;
                            break;
                        case 27:
                            op = 39;
                            break;
                        case 28:
                            op = 36;
                            break;
                        case 29:
                            op = 37;
                            break;
                        case 30:
                            op = 38;
                            break;
                        case 33:
                            op = 58;
                            break;
                        case 34:
                            op = 15;
                            break;
                        case 35:
                            op = 14;
                            break;
                        case 36:
                            op = 16;
                            break;
                        case 37:
                            op = 17;
                            break;
                        default:
                            break;
                    }
                    break;
                }
                case 13:
                    op = 52;
                    break;
                case 14:
                    op = 18;
                    break;
                case 16:
                    op = 34;
                    break;
                case 18:
                    op = 21;
                    break;
                case 19:
                    op = 23;
                    break;
                case 20:
                    op = 24;
                    break;
                case 21:
                    op = 1;
                    break;
                case 22:
                    op = 2;
                    break;
                case 23:
                    op = 22;
                    break;
                case 24:
                    op = 10;
                    break;
                case 25:
                    op = 11;
                    break;
                case 26:
                    op = 13;
                    break;
                case 27:
                    op = 8;
                    break;
                case 29:
                    op = 50;
                    break;
                case 30:
                    op = 12;
                    break;
                case 31:
                    op = 9;
                    break;
                default:
                    break;
            }

            if (op == 0)
                continue;

            /* check arguments */
            var req_args = cff_argument_counts[op];
            if ((req_args & 128) != 0)
            {
                if (num_args > 0 && decoder.read_width != 0)
                {
                    /* If `nominal_width' is non-zero, the number is really a      */
                    /* difference against `nominal_width'.  Else, the number here  */
                    /* is truly a width, not a difference against `nominal_width'. */
                    /* If the font does not set `nominal_width', then              */
                    /* `nominal_width' defaults to zero, and so we can set         */
                    /* `glyph_width' to `nominal_width' plus number on the stack   */
                    /* -- for either case.                                         */
                    var set_width_ok = 0;
                    switch (op)
                    {
                        case 2:
                        case 3:
                            set_width_ok = num_args & 2;
                            break;

                        case 19:
                        case 20:
                        case 21:
                        case 22:
                        case 1:
                        case 23:
                        case 24:
                            set_width_ok = num_args & 1;
                            break;

                        case 18:
                            /* If there is a width specified for endchar, we either have */
                            /* 1 argument or 5 arguments.  We like to argue.             */
                            set_width_ok = ((num_args == 5) || (num_args == 1)) ? 1 : 0;
                            break;

                        default:
                            FT_Common.set_width_ok = 0;
                            break;
                    }

                    if (set_width_ok != 0)
                    {
                        decoder.glyph_width = decoder.nominal_width + (tops[stack] >> 16);

                        if (decoder.width_only != 0)
                        {
                            /* we only want the advance width; stop here */
                            break;
                        }

                        /* Consumed an argument. */
                        num_args--;
                    }
                }

                decoder.read_width = 0;
                req_args = 0;
            }

            req_args &= 0x000F;
            if (num_args < req_args)
                return 129;
            args     -= req_args;
            num_args -= req_args;

            /* At this point, `args' points to the first argument of the  */
            /* operand in case `req_args' isn't zero.  Otherwise, we have */
            /* to adjust `args' manually.                                 */

            /* Note that we only pop arguments from the stack which we    */
            /* really need and can digest so that we can continue in case */
            /* of superfluous stack elements.                             */

            switch (op)
            {
                case 19:
                case 20:
                case 21:
                case 22:
                    /* the number of arguments is always even here */
                    if (hinter != null)
                        hinter.stems(hinter.hints, (op == 19 || op == 21) ? 1 : 0, num_args / 2, tops[args - (num_args & ~1)]);

                    decoder.num_hints += num_args / 2;
                    args = stack;
                    break;

                case 23:
                case 24:
                    /* implement vstem when needed --                        */
                    /* the specification doesn't say it, but this also works */
                    /* with the 'cntrmask' operator                          */
                    /*                                                       */
                    if (num_args > 0)
                    {
                        if (hinter != null)
                            hinter.stems(hinter.hints, 0, num_args / 2, tops[args - (num_args & ~1)]);

                        decoder.num_hints += num_args / 2;
                    }

                    /* In a valid charstring there must be at least one byte */
                    /* after `hintmask' or `cntrmask' (e.g., for a `return'  */
                    /* instruction).  Additionally, there must be space for  */
                    /* `num_hints' bits.                                     */
                    if ((ip.pos + ((decoder.num_hints + 7) >> 3)) >= limit)
                        return 3;

                    if (hinter != null)
                    {
                        if (op == 23)
                            hinter.hintmask(hinter.hints, builder.current.n_points, decoder.num_hints, ip);
                        else
                            hinter.counter(hinter.hints, decoder.num_hints, ip);
                    }

                    ip.pos += (decoder.num_hints + 7 ) >> 3;
                    args = stack;
                    break;

                case 1:
                    cff_builder_close_contour(builder);
                    builder.path_begun = 0;
                    x += tops[args - 2];
                    y += tops[args - 1];
                    args = stack;
                    break;

                case 3:
                    cff_builder_close_contour(builder);
                    builder.path_begun = 0;
                    y += tops[args - 1];
                    args = stack;
                    break;

                case 2:
                    cff_builder_close_contour(builder);
                    builder.path_begun = 0;
                    x += tops[args - 1];
                    args = stack;
                    break;

                case 4:
                    if (cff_builder_start_point(builder, x, y) != 0 || _cff_check_points(builder, parseInt(num_args / 2)) != 0)
                        return error;

                    if (num_args < 2)
                        return 129;

                    args -= num_args & ~1;
                    while (args < decoder.top)
                    {
                        x += tops[args];
                        y += tops[args + 1];
                        cff_builder_add_point(builder, x, y, 1);
                        args += 2;
                    }
                    args = stack;
                    break;

                case 5:
                case 6:
                {
                    var phase = (op == 5) ? 1 : 0;

                    if (num_args < 0)
                        return 129;

                    /* there exist subsetted fonts (found in PDFs) */
                    /* which call `hlineto' without arguments      */
                    if (num_args == 0)
                        break;

                    if (cff_builder_start_point(builder, x, y) != 0 || _cff_check_points(builder, num_args))
                        return error;

                    args = stack;
                    while (args < decoder.top)
                    {
                        if (phase == 1)
                            x += tops[args];
                        else
                            y += tops[args];

                        if (cff_builder_add_point1(builder, x, y) != 0)
                            return error;

                        args++;
                        phase ^= 1;
                    }
                    args = stack;
                    break;
                }

                case 7:
                {
                    if (num_args < 6)
                        return 129;

                    var nargs = num_args - num_args % 6;

                    if (cff_builder_start_point(builder, x, y) != 0 || _cff_check_points(builder, parseInt(nargs / 2)))
                        return error;

                    args -= nargs;
                    while (args < decoder.top)
                    {
                        x += tops[args];
                        y += tops[args + 1];
                        cff_builder_add_point(builder, x, y, 0);
                        x += tops[args + 2];
                        y += tops[args + 3];
                        cff_builder_add_point(builder, x, y, 0);
                        x += tops[args + 4];
                        y += tops[args + 5];
                        cff_builder_add_point(builder, x, y, 1);
                        args += 6;
                    }
                    args = stack;
                    break;
                }

                case 13:
                {
                    if (num_args < 4)
                        return 129;

                    /* if num_args isn't of the form 4n or 4n+1, */
                    /* we reduce it to 4n+1                      */
                    var nargs = num_args - num_args % 4;
                    if ((num_args - nargs) > 0)
                        nargs += 1;

                    if (cff_builder_start_point(builder, x, y) != 0)
                        return error;

                    args -= nargs;
                    if ((nargs & 1) != 0)
                    {
                        x += tops[args];
                        args++;
                        nargs--;
                    }

                    if (_cff_check_points(builder, 3 * parseInt(nargs / 4)))
                        return error;

                    while (args < decoder.top)
                    {
                        y += tops[args];
                        cff_builder_add_point(builder, x, y, 0);
                        x += tops[args + 1];
                        y += tops[args + 2];
                        cff_builder_add_point(builder, x, y, 0);
                        y += tops[args + 3];
                        cff_builder_add_point(builder, x, y, 1);
                        args += 4;
                    }
                    args = stack;
                    break;
                }

                case 8:
                {
                    if (num_args < 4)
                        return 129;

                    /* if num_args isn't of the form 4n or 4n+1, */
                    /* we reduce it to 4n+1                      */
                    var nargs = num_args - num_args % 4;
                    if ((num_args - nargs) > 0)
                        nargs += 1;

                    if (cff_builder_start_point(builder, x, y) != 0)
                        return error;

                    args -= nargs;
                    if ((nargs & 1) != 0)
                    {
                        y += tops[args];
                        args++;
                        nargs--;
                    }

                    if (_cff_check_points(builder, 3 * parseInt(nargs / 4)))
                        return error;

                    while (args < decoder.top)
                    {
                        x += tops[args];
                        cff_builder_add_point(builder, x, y, 0);
                        x += tops[args + 1];
                        y += tops[args + 2];
                        cff_builder_add_point(builder, x, y, 0);
                        x += tops[args + 3];
                        cff_builder_add_point(builder, x, y, 1);
                        args += 4;
                    }
                    args = stack;
                    break;
                }

                case 12:
                case 9:
                {
                    if (cff_builder_start_point(builder, x, y) != 0)
                        return error;

                    if (num_args < 4)
                        return 129;

                    /* if num_args isn't of the form 8n, 8n+1, 8n+4, or 8n+5, */
                    /* we reduce it to the largest one which fits             */
                    var nargs = num_args - num_args % 4;
                    if ((num_args - nargs) > 0)
                        nargs += 1;

                    args -= nargs;
                    if (_cff_check_points(builder, parseInt(nargs / 4) * 3))
                        return 129;

                    var phase = (op == 9) ? 1 : 0;

                    while (nargs >= 4)
                    {
                        nargs -= 4;
                        if (phase == 1)
                        {
                            x += tops[args];
                            cff_builder_add_point(builder, x, y, 0);
                            x += tops[args + 1];
                            y += tops[args + 2];
                            cff_builder_add_point(builder, x, y, 0);
                            y += tops[args + 3];
                            if (nargs == 1)
                                x += tops[args + 4];
                            cff_builder_add_point(builder, x, y, 1);
                        }
                        else
                        {
                            y += tops[args];
                            cff_builder_add_point(builder, x, y, 0);
                            x += tops[args + 1];
                            y += tops[args + 2];
                            cff_builder_add_point(builder, x, y, 0);
                            x += tops[args + 3];
                            if (nargs == 1)
                                y += tops[args + 4];
                            cff_builder_add_point(builder, x, y, 1);
                        }
                        args  += 4;
                        phase ^= 1;
                    }
                    args = stack;
                    break;
                }

                case 11:
                {
                    if (num_args < 8)
                        return 129;

                    var nargs = num_args & ~1;
                    var num_lines = parseInt((nargs - 6) / 2);

                    if (cff_builder_start_point(builder, x, y) || _cff_check_points(builder, num_lines + 3))
                        return error;

                    args -= nargs;

                    /* first, add the line segments */
                    while (num_lines > 0)
                    {
                        x += tops[args];
                        y += tops[args + 1];
                        cff_builder_add_point(builder, x, y, 1);
                        args += 2;
                        num_lines--;
                    }

                    /* then the curve */
                    x += tops[args];
                    y += tops[args + 1];
                    cff_builder_add_point(builder, x, y, 0);
                    x += tops[args + 2];
                    y += tops[args + 3];
                    cff_builder_add_point(builder, x, y, 0);
                    x += tops[args + 4];
                    y += tops[args + 5];
                    cff_builder_add_point(builder, x, y, 1);
                    args = stack;
                    break;
                }

                case 10:
                {
                    if ( num_args < 8 )
                        return 129;

                    var nargs  = num_args - 2;
                    nargs      = nargs - nargs % 6 + 2;
                    var num_curves = parseInt((nargs - 2) / 6);

                    if (cff_builder_start_point(builder, x, y) != 0 || _cff_check_points(builder, num_curves * 3 + 2))
                        return error;

                    args -= nargs;

                    /* first, add the curves */
                    while (num_curves > 0)
                    {
                        x += tops[args];
                        y += tops[args + 1];
                        cff_builder_add_point(builder, x, y, 0);
                        x += tops[args + 2];
                        y += tops[args + 3];
                        cff_builder_add_point(builder, x, y, 0);
                        x += tops[args + 4];
                        y += tops[args + 5];
                        cff_builder_add_point(builder, x, y, 1);
                        args += 6;
                        num_curves--;
                    }

                    /* then the final line */
                    x += tops[args];
                    y += tops[args + 1];
                    cff_builder_add_point(builder, x, y, 1);
                    args = stack;

                    break;
                }

                case 16:
                {
                    /* adding five more points: 4 control points, 1 on-curve point */
                    /* -- make sure we have enough space for the start point if it */
                    /* needs to be added                                           */
                    if (cff_builder_start_point(builder, x, y) != 0 || _cff_check_points(builder, 6))
                        return error;

                    /* record the starting point's y position for later use */
                    var start_y = y;

                    /* first control point */
                    x += tops[args];
                    y += tops[args + 1];
                    cff_builder_add_point(builder, x, y, 0);

                    /* second control point */
                    x += tops[args + 2];
                    y += tops[args + 3];
                    cff_builder_add_point(builder, x, y, 0);

                    /* join point; on curve, with y-value the same as the last */
                    /* control point's y-value                                 */
                    x += tops[args + 4];
                    cff_builder_add_point(builder, x, y, 1);

                    /* third control point, with y-value the same as the join */
                    /* point's y-value                                        */
                    x += tops[args + 5];
                    cff_builder_add_point(builder, x, y, 0);

                    /* fourth control point */
                    x += tops[args + 6];
                    y += tops[args + 7];
                    cff_builder_add_point(builder, x, y, 0);

                    /* ending point, with y-value the same as the start   */
                    x += tops[args + 8];
                    y  = start_y;
                    cff_builder_add_point(builder, x, y, 1);

                    args = stack;
                    break;
                }

                case 15:
                {
                    /* adding six more points; 4 control points, 2 on-curve points */
                    if (cff_builder_start_point(builder, x, y) != 0 || _cff_check_points(builder, 6))
                        return error;

                    /* record the starting point's y-position for later use */
                    var start_y = y;

                    /* first control point */
                    x += tops[args];
                    cff_builder_add_point(builder, x, y, 0);

                    /* second control point */
                    x += tops[args + 1];
                    y += tops[args + 2];
                    cff_builder_add_point(builder, x, y, 0);

                    /* join point; on curve, with y-value the same as the last */
                    /* control point's y-value                                 */
                    x += tops[args + 3];
                    cff_builder_add_point(builder, x, y, 1);

                    /* third control point, with y-value the same as the join */
                    /* point's y-value                                        */
                    x += tops[args + 4];
                    cff_builder_add_point(builder, x, y, 0);

                    /* fourth control point */
                    x += tops[args + 5];
                    y  = start_y;
                    cff_builder_add_point(builder, x, y, 0);

                    /* ending point, with y-value the same as the start point's */
                    /* y-value -- we don't add this point, though               */
                    x += tops[args + 6];
                    cff_builder_add_point(builder, x, y, 1);

                    args = stack;
                    break;
                }

                case 17:
                {
                    /* alter use                    */
                    var dx = 0, dy = 0;   /* used in horizontal/vertical  */

                    /* adding six more points; 4 control points, 2 on-curve points */
                    if (cff_builder_start_point(builder, x, y) != 0 || _cff_check_points(builder, 6) != 0)
                        return error;

                    /* record the starting point's x, y position for later use */
                    var start_x = x;
                    var start_y = y;

                    /* XXX: figure out whether this is supposed to be a horizontal */
                    /*      or vertical flex; the Type 2 specification is vague... */

                    var temp = args;
                    var count = 0;

                    /* grab up to the last argument */
                    for (count = 5; count > 0; count--)
                    {
                        dx += tops[temp];
                        dy += tops[temp + 1];
                        temp += 2;
                    }

                    if (dx < 0)
                        dx = -dx;
                    if (dy < 0)
                        dy = -dy;

                    /* strange test, but here it is... */
                    var horizontal = (dx > dy) ? 1 : 0;

                    for (count = 5; count > 0; count--)
                    {
                        x += tops[args];
                        y += tops[args + 1];
                        cff_builder_add_point(builder, x, y, (count == 3) ? 1 : 0);
                        args += 2;
                    }

                    /* is last operand an x- or y-delta? */
                    if (horizontal == 1)
                    {
                        x += tops[args];
                        y  = start_y;
                    }
                    else
                    {
                        x  = start_x;
                        y += tops[args];
                    }

                    cff_builder_add_point(builder, x, y, 1);

                    args = stack;
                    break;
                }

                case 14:
                {
                    if (cff_builder_start_point(builder, x, y) != 0 || _cff_check_points(builder, 6))
                        return error;

                    for (var count = 6; count > 0; count--)
                    {
                        x += tops[args];
                        y += tops[args + 1];
                        cff_builder_add_point(builder, x, y, (count == 4 || count == 1) ? 1 : 0);
                        args += 2;
                    }

                    args = stack;
                    break;
                }

                case 56:
                    error = cff_operator_seac(decoder, tops[args], tops[args + 1], tops[args + 2], (tops[args + 3] >> 16), (tops[args + 4] >> 16));

                    /* add current outline to the glyph slot */
                    FT_GlyphLoader_Add(builder.loader);
                    return error;

                case 18:
                    /* We are going to emulate the seac operator. */
                    if (num_args >= 4)
                    {
                        /* Save glyph width so that the subglyphs don't overwrite it. */
                        var glyph_width = decoder.glyph_width;

                        error = cff_operator_seac(decoder, 0, tops[args - 4], tops[args - 3], (tops[args - 2] >> 16), (tops[args - 1] >> 16));
                        decoder.glyph_width = glyph_width;
                    }
                    else
                    {
                        cff_builder_close_contour(builder);

                        /* close hints recording session */
                        if (hinter != null)
                        {
                            if (hinter.close(hinter.hints, builder.current.n_points))
                                return 3;

                            /* apply hints to the loaded glyph outline now */
                            hinter.apply(hinter.hints, builder.current, builder.hints_globals, decoder.hint_mode);
                        }

                        /* add current outline to the glyph slot */
                        FT_GlyphLoader_Add(builder.loader);
                    }

                    /* return now! */
                    return error;

                case 26:
                    if (tops[args] < 0)
                        tops[args] = -tops[args];
                    args++;
                    break;

                case 27:
                    tops[args] += tops[args + 1];
                    args++;
                    break;

                case 28:
                    tops[args] -= tops[args + 1];
                    args++;
                    break;

                case 29:
                    tops[args] = FT_DivFix(tops[args], tops[args + 1]);
                    args++;
                    break;

                case 30:
                    tops[args] = -tops[args];
                    args++;
                    break;

                case 31:
                {
                    var Rand = seed;
                    if (Rand >= 0x8000)
                        Rand++;

                    tops[args] = Rand;
                    seed = FT_MulFix(seed, 0x10000 - seed);
                    if (seed == 0)
                        seed += 0x2873;
                    args++;

                    break;
                }

                case 32:
                    tops[args] = FT_MulFix( args[0], args[1] );
                    args++;
                    break;

                case 33:
                    if (tops[args] > 0)
                    {
                        var count = 9;
                        var root = tops[args];
                        var new_root = 0;
                        for (;;)
                        {
                            new_root = (root + FT_DivFix(tops[args], root) + 1) >> 1;
                            if (new_root == root || count <= 0)
                                break;
                            root = new_root;
                        }
                        tops[args] = new_root;
                    }
                    else
                        tops[args] = 0;
                    args++;
                    break;

                case 35:
                    /* nothing */
                    break;

                case 36:
                {
                    var tmp = tops[args];
                    tops[args] = tops[args + 1];
                    tops[args + 1] = tmp;
                    args += 2;

                    break;
                }

                case 37:
                {
                    var idx = (tops[args] >> 16);

                    if (idx < 0)
                        idx = 0;
                    else if (idx > num_args - 2)
                        idx = num_args - 2;
                    tops[args] = tops[args-(idx + 1)];
                    args++;

                    break;
                }

                case 38:
                {
                    var count = (tops[args] >> 16);
                    var idx = (tops[args + 1] >> 16);

                    if (count <= 0)
                        count = 1;

                    args -= count;
                    if (args < stack)
                        return 129;

                    if (idx >= 0)
                    {
                        while (idx > 0)
                        {
                            var tmp = tops[args + count - 1];
                            for (var i = count - 2; i >= 0; i--)
                                tops[args + i + 1] = tops[args + i];
                            tops[args] = tmp;
                            idx--;
                        }
                    }
                    else
                    {
                        while (idx < 0)
                        {
                            var tmp = tops[args];
                            for (var i = 0; i < count - 1; i++)
                                tops[args + i] = tops[args + i + 1];
                            tops[args + count - 1] = tmp;
                            idx++;
                        }
                    }
                    args += count;

                    break;
                }

                case 39:
                    tops[args + 1] = tops[args];
                    args += 2;
                    break;

                case 40:
                {
                    var val = tops[args];
                    var idx = (tops[args + 1] >> 16);

                    if (idx >= 0 && idx < 32)
                        decoder.buildchar[idx] = val;

                    break;
                }

                case 41:
                {
                    var idx = (tops[args] >> 16);
                    var val = 0;

                    if (idx >= 0 && idx < 32)
                        val = decoder.buildchar[idx];

                    tops[args] = val;
                    args++;

                    break;
                }

                case 42:
                    return 7;

                case 43:
                    return 7;

                case 25:
                    /* this operator is deprecated and ignored by the parser */
                    break;

                case 53:
                    /* this is an invalid Type 2 operator; however, there        */
                    /* exist fonts which are incorrectly converted from probably */
                    /* Type 1 to CFF, and some parsers seem to accept it         */
                    args = stack;
                    break;

                case 52:
                    /* this is an invalid Type 2 operator; however, there        */
                    /* exist fonts which are incorrectly converted from probably */
                    /* Type 1 to CFF, and some parsers seem to accept it         */
                    decoder.glyph_width = decoder.nominal_width + (tops[args + 1] >> 16);

                    decoder.builder.left_bearing.x = tops[args];
                    decoder.builder.left_bearing.y = 0;

                    x = decoder.builder.pos_x + tops[args];
                    y = decoder.builder.pos_y;
                    args = stack;
                    break;

                case 57:
                    /* this is an invalid Type 2 operator; however, there        */
                    /* exist fonts which are incorrectly converted from probably */
                    /* Type 1 to CFF, and some parsers seem to accept it         */
                    decoder.glyph_width = decoder.nominal_width + (tops[args + 2] >> 16);

                    decoder.builder.left_bearing.x = tops[args];
                    decoder.builder.left_bearing.y = tops[args + 1];

                    x = decoder.builder.pos_x + tops[args];
                    y = decoder.builder.pos_y + tops[args + 1];
                    args = stack;
                    break;

                case 58:
                    /* this is an invalid Type 2 operator; however, there        */
                    /* exist fonts which are incorrectly converted from probably */
                    /* Type 1 to CFF, and some parsers seem to accept it         */
                    x = decoder.builder.pos_x + tops[args];
                    y = decoder.builder.pos_y + tops[args + 1];
                    args = stack;
                    break;

                case 54:
                    /* this is an invalid Type 2 operator; however, there        */
                    /* exist fonts which are incorrectly converted from probably */
                    /* Type 1 to CFF, and some parsers seem to accept it         */

                    /* subsequent `pop' operands should add the arguments,       */
                    /* this is the implementation described for `unknown' other  */
                    /* subroutines in the Type1 spec.                            */
                    /*                                                           */
                    /* XXX Fix return arguments (see discussion below).          */
                    args -= 2 + (tops[args - 2] >> 16);
                    if (args < stack)
                        return 129;
                    break;

                case 55:
                    /* this is an invalid Type 2 operator; however, there        */
                    /* exist fonts which are incorrectly converted from probably */
                    /* Type 1 to CFF, and some parsers seem to accept it         */

                    /* XXX Increasing `args' is wrong: After a certain number of */
                    /* `pop's we get a stack overflow.  Reason for doing it is   */
                    /* code like this (actually found in a CFF font):            */
                    /*                                                           */
                    /*   17 1 3 callothersubr                                    */
                    /*   pop                                                     */
                    /*   callsubr                                                */
                    /*                                                           */
                    /* Since we handle `callothersubr' as a no-op, and           */
                    /* `callsubr' needs at least one argument, `pop' can't be a  */
                    /* no-op too as it basically should be.                      */
                    /*                                                           */
                    /* The right solution would be to provide real support for   */
                    /* `callothersubr' as done in `t1decode.c', however, given   */
                    /* the fact that CFF fonts with `pop' are invalid, it is     */
                    /* questionable whether it is worth the time.                */
                    args++;
                    break;

                case 44:
                {
                    var cond = (tops[args] != 0 && tops[args + 1] != 0) ? 1 : 0;

                    tops[args] = (cond == 1) ? 0x10000 : 0;
                    args++;

                    break;
                }
                case 45:
                {
                    var cond = (tops[args] != 0 || tops[args + 1]) ? 1 : 0;

                    tops[args] = (cond == 1) ? 0x10000 : 0;
                    args++;

                    break;
                }

                case 47:
                {
                    tops[args] = (tops[args] == 0) ? 0x10000 : 0;
                    args++;

                    break;
                }

                case 48:
                {
                    if (tops[args + 2] > tops[args + 3])
                        tops[args] = tops[args + 1];
                    args++;

                    break;
                }

                case 49:
                {
                    var idx = ((tops[args] >> 16) + decoder.locals_bias);

                    if (idx >= decoder.num_locals)
                        return 3;

                    if (zone >= 32)
                        return 3;

                    zones[zone].cursor = ip.pos - zones[zone].base.pos;  /* save current instruction pointer */

                    zone++;
                    zones[zone].base = dublicate_pointer(decoder.locals[idx]);
                    zones[zone].limit = (decoder.locals[idx + 1] != null) ? decoder.locals[idx + 1].pos : zones[zone].base.pos;
                    zones[zone].cursor = 0;

                    if (zones[zone].base == null || zones[zone].limit == zones[zone].base.pos)
                        return 3;

                    decoder.zone = zone;
                    ip = dublicate_pointer(zones[zone].base);
                    limit = zones[zone].limit;

                    break;
                }

                case 50:
                {
                    var idx = ((tops[args] >> 16) + decoder.globals_bias);

                    if (idx >= decoder.num_globals)
                        return 3;

                    if (zone >= 32)
                        return 3;

                    zones[zone].cursor = ip.pos - zones[zone].base.pos;  /* save current instruction pointer */

                    zone++;
                    zones[zone].base = dublicate_pointer(decoder.globals[idx]);
                    zones[zone].limit = (decoder.globals[idx + 1] != null) ? decoder.globals[idx + 1].pos : zones[zone].base.pos;
                    zones[zone].cursor = 0;

                    if (zones[zone].base == null || zones[zone].limit == zones[zone].base.pos)
                        return 3;

                    decoder.zone = zone;
                    ip = dublicate_pointer(zones[zone].base);
                    limit = zones[zone].limit;

                    break;
                }

                case 51:
                    if (decoder.zone <= 0)
                        return 3;

                    decoder.zone--;
                    zone  = decoder.zone;
                    ip = dublicate_pointer(zones[zone].base);
                    ip.pos += zones[zone].cursor;
                    limit = zones[zone].limit;
                    break;

                default:
                    return 7;
            }

            decoder.top = args;

            if (decoder.top >= 48)
                return 130;

        } /* general operator processing */

    } /* while ip < limit */

    return error;
}

function cff_slot_load(glyph, size, glyph_index, load_flags)
{
    var face = glyph.face;
    var cff  = face.extra.data;

    var font_matrix = null;
    var font_offset = null;

    var hinting = 0;
    var force_scaling = 0;

    /* in a CID-keyed font, consider `glyph_index' as a CID and map */
    /* it immediately to the real glyph_index -- if it isn't a      */
    /* subsetted font, glyph_indices and CIDs are identical, though */
    if (cff.top_font.font_dict.cid_registry != 0xFFFF && cff.charset.cids != null)
    {
        /* don't handle CID 0 (.notdef) which is directly mapped to GID 0 */
        if (glyph_index != 0)
        {
            glyph_index = cff_charset_cid_to_gindex(cff.charset, glyph_index);
            if (glyph_index == 0)
                return 6;
        }
    }
    else if (glyph_index >= cff.num_glyphs)
        return 6;

    if ((load_flags & 1024) != 0)
        load_flags |= (1 | 2);

    glyph.x_scale = 0x10000;
    glyph.y_scale = 0x10000;
    if (size != 0)
    {
        glyph.x_scale = size.metrics.x_scale;
        glyph.y_scale = size.metrics.y_scale;
    }

    var error = 0;

    //#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS

    /* try to load embedded bitmap if any              */
    /*                                                 */
    /* XXX: The convention should be emphasized in     */
    /*      the documents because it can be confusing. */
    if (size != null)
    {
        var cff_face = size.face;
        var sfnt = cff_face.sfnt;
        var stream = cff_face.stream;

        if (size.strike_index != 0xFFFFFFFF && sfnt.load_eblc != null && (load_flags & 8) == 0)
        {
            var metrics = new TT_SBit_MetricsRec();

            error = sfnt.load_sbit_image(face, size.strike_index, glyph_index, load_flags, stream, glyph.bitmap, metrics);

            if (error == 0)
            {
                glyph.outline.n_points   = 0;
                glyph.outline.n_contours = 0;

                glyph.metrics.width  = metrics.width << 6;
                glyph.metrics.height = metrics.height << 6;

                glyph.metrics.horiBearingX = metrics.horiBearingX << 6;
                glyph.metrics.horiBearingY = metrics.horiBearingY << 6;
                glyph.metrics.horiAdvance  = metrics.horiAdvance  << 6;

                glyph.metrics.vertBearingX = metrics.vertBearingX << 6;
                glyph.metrics.vertBearingY = metrics.vertBearingY << 6;
                glyph.metrics.vertAdvance  = metrics.vertAdvance  << 6;

                glyph.format = 1651078259;

                if (load_flags & 16)
                {
                    glyph.bitmap_left = metrics.vertBearingX;
                    glyph.bitmap_top  = metrics.vertBearingY;
                }
                else
                {
                    glyph.bitmap_left = metrics.horiBearingX;
                    glyph.bitmap_top  = metrics.horiBearingY;
                }
                return error;
            }
        }
    }

    //#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */

    /* return immediately if we only want the embedded bitmaps */
    if ((load_flags & 16384) != 0)
        return 6;

    /* if we have a CID subfont, use its matrix (which has already */
    /* been multiplied with the root matrix)                       */

    /* this scaling is only relevant if the PS hinter isn't active */
    if (cff.num_subfonts > 0)
    {
        var fd_index = cff_fd_select_get(cff.fd_select, glyph_index);

        if (fd_index >= cff.num_subfonts)
            fd_index = (cff.num_subfonts - 1);

        var top_upm = cff.top_font.font_dict.units_per_em;
        var sub_upm = cff.subfonts[fd_index].font_dict.units_per_em;

        font_matrix = dublicate_matrix(cff.subfonts[fd_index].font_dict.font_matrix);
        font_offset = dublicate_vector(cff.subfonts[fd_index].font_dict.font_offset);

        if (top_upm != sub_upm)
        {
            glyph.x_scale = FT_MulDiv(glyph.x_scale, top_upm, sub_upm);
            glyph.y_scale = FT_MulDiv(glyph.y_scale, top_upm, sub_upm);

            force_scaling = 1;
        }
    }
    else
    {
        font_matrix = dublicate_matrix(cff.top_font.font_dict.font_matrix);
        font_offset = dublicate_vector(cff.top_font.font_dict.font_offset);
    }

    glyph.outline.n_points   = 0;
    glyph.outline.n_contours = 0;

    hinting = ((load_flags & 1) == 0 && (load_flags & 2) == 0) ? 1 : 0;

    glyph.format = 1869968492;  /* by default */

    var decoder = new CFF_Decoder();
    cff_decoder_init(decoder, face, size, glyph, hinting, FT_LOAD_TARGET_MODE(load_flags));

    if ((load_flags & 256) != 0)
        decoder.width_only = 1;

    decoder.builder.no_recurse = ((load_flags & 1024) != 0) ? 1 : 0;

    /* now load the unscaled outline */
    var ret = cff_get_glyph_data(face, glyph_index);
    error = ret.err;
    var charstring = ret.bytes;
    var charstring_len = ret.len;

    if (error == 0)
    {
        error = cff_decoder_prepare(decoder, size, glyph_index);
        if (error == 0)
        {
            error = cff_decoder_parse_charstrings(decoder, charstring, charstring_len);
            cff_free_glyph_data(face, charstring, charstring_len);
            charstring = null;

            if (error == 0)
            {
                //#ifdef FT_CONFIG_OPTION_INCREMENTAL
                /* Control data and length may not be available for incremental */
                /* fonts.                                                       */
                if (face.internal.incremental_interface != null)
                {
                    glyph.control_data = null;
                    glyph.control_len = 0;
                }
                else //#endif /* FT_CONFIG_OPTION_INCREMENTAL */
                {
                    var csindex = cff.charstrings_index;

                    if (csindex.offsets != null)
                    {
                        glyph.control_data = dublicate_pointer(csindex.bytes);
                        glyph.control_data.pos += csindex.offsets[glyph_index] - 1;
                        glyph.control_len = charstring_len;
                    }

                }
                cff_builder_done(decoder.builder);
            }
        }
    }
    /* XXX: anything to do for broken glyph entry? */

    //#ifdef FT_CONFIG_OPTION_INCREMENTAL

    /* Incremental fonts can optionally override the metrics. */
    if (error == 0 && face.internal.incremental_interface != null && face.internal.incremental_interface.funcs.get_glyph_metrics != null)
    {
        var metrics = new FT_Incremental_MetricsRec();

        metrics.bearing_x = decoder.builder.left_bearing.x;
        metrics.bearing_y = 0;
        metrics.advance   = decoder.builder.advance.x;
        metrics.advance_v = decoder.builder.advance.y;

        error = face.internal.incremental_interface.funcs.get_glyph_metrics(face.internal.incremental_interface.object, glyph_index, 0, metrics);

        decoder.builder.left_bearing.x = metrics.bearing_x;
        decoder.builder.advance.x      = metrics.advance;
        decoder.builder.advance.y      = metrics.advance_v;
    }

    //#endif /* FT_CONFIG_OPTION_INCREMENTAL */

    if (error == 0)
    {
        /* Now, set the metrics -- this is rather simple, as   */
        /* the left side bearing is the xMin, and the top side */
        /* bearing the yMax.                                   */

        /* For composite glyphs, return only left side bearing and */
        /* advance width.                                          */
        if ((load_flags & 1024) != 0)
        {
            var internal = glyph.internal;

            glyph.metrics.horiBearingX = decoder.builder.left_bearing.x;
            glyph.metrics.horiAdvance  = decoder.glyph_width;
            internal.glyph_matrix           = dublicate_matrix(font_matrix);
            internal.glyph_delta            = dublicate_matrix(font_offset);
            internal.glyph_transformed      = 1;
        }
        else
        {
            var cbox = new FT_BBox();
            var metrics = glyph.metrics;
            var advance = new FT_Vector();
            var has_vertical_info = 0;

            /* copy the _unscaled_ advance width */
            metrics.horiAdvance = decoder.glyph_width;
            glyph.linearHoriAdvance = decoder.glyph_width;
            glyph.internal.glyph_transformed = 0;

            has_vertical_info = (face.vertical_info && face.vertical.number_Of_VMetrics > 0 && face.vertical.long_metrics) ? 1 : 0;

            /* get the vertical metrics from the vtmx table if we have one */
            if (has_vertical_info == 1)
            {
                var _ret = face.sfnt.get_metrics(face, 1, glyph_index);
                metrics.vertBearingY = _ret.bearing;
                metrics.vertAdvance  = _ret.advance;
            }
            else
            {
                /* make up vertical ones */
                if (face.os2.version != 0xFFFF)
                    metrics.vertAdvance = (face.os2.sTypoAscender - face.os2.sTypoDescender);
                else
                    metrics.vertAdvance = (face.horizontal.Ascender - face.horizontal.Descender);
            }

            glyph.linearVertAdvance = metrics.vertAdvance;

            glyph.format = 1869968492;

            glyph.outline.flags = 0;
            if (size != null && size.metrics.y_ppem < 24)
                glyph.outline.flags |= 256;

            glyph.outline.flags |= 4;

            if (!(font_matrix.xx == 0x10000 && font_matrix.yy == 0x10000 && font_matrix.xy == 0 && font_matrix.yx == 0))
                FT_Outline_Transform(glyph.outline, font_matrix);

            if (!(font_offset.x == 0 && font_offset.y == 0))
                FT_Outline_Translate(glyph.outline, font_offset.x, font_offset.y);

            advance.x = metrics.horiAdvance;
            advance.y = 0;
            FT_Vector_Transform(advance, font_matrix);
            metrics.horiAdvance = advance.x + font_offset.x;

            advance.x = 0;
            advance.y = metrics.vertAdvance;
            FT_Vector_Transform(advance, font_matrix);
            metrics.vertAdvance = advance.y + font_offset.y;

            if ((load_flags & 1) == 0 || force_scaling == 1)
            {
                /* scale the outline and the metrics */
                var cur = glyph.outline;
                var vecs = cur.points;
                var _vec = 0;
                var x_scale = glyph.x_scale;
                var y_scale = glyph.y_scale;

                /* First of all, scale the points */
                if (hinting == 0 || decoder.builder.hints_funcs == null)
                    for (var n = cur.n_points; n > 0; n--, _vec++)
                    {
                        vecs[_vec].x = FT_MulFix(vecs[_vec].x, x_scale);
                        vecs[_vec].y = FT_MulFix(vecs[_vec].y, y_scale);
                    }

                /* Then scale the metrics */
                metrics.horiAdvance = FT_MulFix(metrics.horiAdvance, x_scale);
                metrics.vertAdvance = FT_MulFix(metrics.vertAdvance, y_scale);
            }

            /* compute the other metrics */
            FT_Outline_Get_CBox(glyph.outline, cbox);

            metrics.width = cbox.xMax - cbox.xMin;
            metrics.height = cbox.yMax - cbox.yMin;

            metrics.horiBearingX = cbox.xMin;
            metrics.horiBearingY = cbox.yMax;

            if (has_vertical_info == 1)
                metrics.vertBearingX = metrics.horiBearingX - parseInt(metrics.horiAdvance / 2);
            else
            {
                if ((load_flags & 16) != 0)
                    ft_synthesize_vertical_metrics(metrics, metrics.vertAdvance);
            }
        }
    }

    return error;
}

/******************************************************************************/
// driver
/******************************************************************************/
function cff_get_kerning(face, left_glyph, right_glyph, kerning)
{
    var sfnt = face.sfnt;

    kerning.x = 0;
    kerning.y = 0;

    if (sfnt != null)
        kerning.x = sfnt.get_kerning(face, left_glyph, right_glyph);

    return 0;
}

function cff_Load_Glyph(slot, cffsize, glyph_index, load_flags)
{
    var size = cffsize;
    if (slot == null)
        return 37;

    /* check whether we want a scaled outline or bitmap */
    if (size == null)
        load_flags |= 1 | 2;

    /* reset the size object if necessary */
    if (load_flags & 1)
        size = null;

    if (size != null)
    {
        /* these two objects must have the same parent */
        if (cffsize.face != slot.face)
            return 35;
    }

    /* now load the glyph outline if necessary */
    var error = cff_slot_load(slot, size, glyph_index, load_flags);

    /* force drop-out mode to 2 - irrelevant now */
    /* slot->outline.dropout_mode = 2; */
    return error;
}

function cff_get_advances(face, start, count, flags, advances)
{
    var slot = face.glyph;
    var error = 0;
    flags |= 256;

    for (var nn = 0; nn < count; nn++)
    {
        error = cff_Load_Glyph(slot, face.size, start + nn, flags);
        if (error )
            break;

        advances[nn] = (flags & 16) ? slot.linearVertAdvance : slot.linearHoriAdvance;
    }

    return error;
}

function cff_get_glyph_name(face, glyph_index, buffer, buffer_max)
{
    var font = face.extra.data;

    if (font.psnames == null)
        return 2;

    /* first, locate the sid in the charset table */
    var sid = font.charset.sids[glyph_index];

    /* now, lookup the name itself */
    var gname = cff_index_get_sid_string(font, sid);

    if (gname != null)
        _mem_strcpyn1(buffer, gname, buffer_max);
        
    return 0;
}

function cff_get_name_index(face, glyph_name)
{
    var cff = face.extra.data;
    var charset = cff.charset;

    var psnames = FT_FACE_FIND_GLOBAL_SERVICE(face, FT_SERVICE_ID_POSTSCRIPT_CMAPS);
    if (psnames == null)
        return 0;

    var sid = 0;
    var name = "";
    for (var i = 0; i < cff.num_glyphs; i++)
    {
        sid = charset.sids[i];

        if (sid > 390)
            name = cff_index_get_string(cff, sid - 391);
        else
            name = psnames.adobe_std_strings(sid);

        if (name == null || name == "")
            continue;

        if (glyph_name == name)
            return i;
    }
    return 0;
}

var cff_service_glyph_dict = new FT_Service_GlyphDictRec(cff_get_glyph_name, cff_get_name_index);

function cff_ps_has_glyph_names(face)
{
    return ((face.face_flags & 512) > 0) ? 1 : 0;
}

function cff_ps_get_font_info(face)
{
    var cff = face.extra.data;
    var font_info = null;
    if (cff != null && cff.font_info == null)
    {
        var dict = cff.top_font.font_dict;
        font_info = new PS_FontInfoRec();

        font_info.version = cff_index_get_sid_string(cff, dict.version);
        font_info.notice = cff_index_get_sid_string(cff, dict.notice);
        font_info.full_name = cff_index_get_sid_string(cff, dict.full_name);
        font_info.family_name = cff_index_get_sid_string(cff, dict.family_name);
        font_info.weight = cff_index_get_sid_string(cff, dict.weight);

        font_info.italic_angle        = dict.italic_angle;
        font_info.is_fixed_pitch      = dict.is_fixed_pitch;
        font_info.underline_position  = dict.underline_position;
        font_info.underline_thickness = dict.underline_thickness;

        cff.font_info = font_info;
    }
    return { err : 0, font_info : font_info };
}

var cff_service_ps_info = new FT_Service_PsInfoRec(cff_ps_get_font_info, null, cff_ps_has_glyph_names, null, null);

function cff_get_ps_name(face)
{
    return face.extra.data.font_name;
}

var cff_service_ps_name = new FT_Service_PsFontNameRec(cff_get_ps_name);

function cff_get_cmap_info(charmap, cmap_info)
{
    var cmap = charmap.cmap;
    var library = __FT_CMapRec(cmap).charmap.face.driver.library;

    cmap_info.language = 0;
    cmap_info.format = 0;

    var error = 0;
    if (cmap.clazz != FT_CFF_CMAP_ENCODING_CLASS_REC_GET && cmap.clazz != FT_CFF_CMAP_UNICODE_CLASS_REC_GET)
    {
        var sfnt = library.FT_Get_Module("sfnt");
        var service = ft_module_get_service(sfnt, FT_SERVICE_ID_TT_CMAP);

        if (service != null && service.get_cmap_info != null)
            error = service.get_cmap_info(charmap, cmap_info);
    }
    return error;
}

var cff_service_get_cmap_info = new FT_Service_TTCMapsRec(cff_get_cmap_info);

function cff_get_ros(face, registry, ordering, supplement)
{
    var ret = {err : 0, registry : "", ordering : "", supplement : 0};
    var cff = face.extra.data;

    if (cff != null)
    {
        var dict = cff.top_font.font_dict;

        if (dict.cid_registry == 0xFFFF)
        {
            ret.err = 6;
            return ret;
        }

        if (cff.registry == null)
            cff.registry = cff_index_get_sid_string(cff, dict.cid_registry);
        ret.registry = cff.registry;

        if (cff.ordering == null)
            cff.ordering = cff_index_get_sid_string(cff, dict.cid_ordering);
        ret.ordering = cff.ordering;

        /*
         * XXX: According to Adobe TechNote #5176, the supplement in CFF
         *      can be a real number. We truncate it to fit public API
         *      since freetype-2.3.6.
         */
        ret.supplement = dict.cid_supplement;
    }

    return ret;
}

function cff_get_is_cid(face)
{
    var ret = {err : 0, is_cid : 0};
    var cff = face.extra.data;

    if (cff != null)
    {
        var dict = cff.top_font.font_dict;

        if (dict.cid_registry != 0xFFFF)
            ret.is_cid = 1;
    }

    return ret;
}

function cff_get_cid_from_glyph_index(face, glyph_index)
{
    var ret = { err : 0, cid : 0};
    var cff = face.extra.data;

    if (cff != null)
    {
        var dict = cff.top_font.font_dict;

        if (dict.cid_registry == 0xFFFF || glyph_index > cff.num_glyphs)
        {
            ret.err = 6;
            return ret;
        }

        ret.cid = cff.charset.sids[glyph_index];
    }
    return ret;
}

var cff_service_cid_info = new FT_Service_CIDRec(cff_get_ros, cff_get_is_cid, cff_get_cid_from_glyph_index);

var FT_CFF_SERVICE_PS_INFO_GET         = cff_service_ps_info;
var FT_CFF_SERVICE_GLYPH_DICT_GET      = cff_service_glyph_dict;
var FT_CFF_SERVICE_PS_NAME_GET         = cff_service_ps_name;
var FT_CFF_SERVICE_GET_CMAP_INFO_GET   = cff_service_get_cmap_info;
var FT_CFF_SERVICE_CID_INFO_GET        = cff_service_cid_info;
var FT_CFF_CMAP_ENCODING_CLASS_REC_GET = cff_cmap_encoding_class_rec;
var FT_CFF_CMAP_UNICODE_CLASS_REC_GET  = cff_cmap_unicode_class_rec;
var FT_CFF_FIELD_HANDLERS_GET          = cff_field_handlers;

var cff_services = new Array(6);
cff_services[0] = new FT_ServiceDescRec(FT_SERVICE_ID_XF86_NAME,FT_XF86_FORMAT_CFF);
cff_services[1] = new FT_ServiceDescRec(FT_SERVICE_ID_POSTSCRIPT_INFO,FT_CFF_SERVICE_PS_INFO_GET);
cff_services[2] = new FT_ServiceDescRec(FT_SERVICE_ID_POSTSCRIPT_FONT_NAME,FT_CFF_SERVICE_PS_NAME_GET);
cff_services[3] = new FT_ServiceDescRec(FT_SERVICE_ID_GLYPH_DICT,FT_CFF_SERVICE_GLYPH_DICT_GET);
cff_services[4] = new FT_ServiceDescRec(FT_SERVICE_ID_TT_CMAP,FT_CFF_SERVICE_GET_CMAP_INFO_GET);
cff_services[5] = new FT_ServiceDescRec(FT_SERVICE_ID_CID,FT_CFF_SERVICE_CID_INFO_GET);

var FT_CFF_SERVICES_GET = cff_services;

function cff_get_interface(driver, module_interface)
{
    var result = ft_service_list_lookup(FT_CFF_SERVICES_GET, module_interface);
    if (result != null)
        return result;

    if (driver == null)
        return null;

    /* we pass our request to the `sfnt' module */
    var sfnt = driver.library.FT_Get_Module("sfnt");
    if (sfnt == null)
        return null;

    return sfnt.clazz.get_interface(sfnt, module_interface);
}

function CFF_Driver_Class()
{
    this.flags = 0x501;
    this.name = "cff";
    this.version = 0x10000;
    this.requires = 0x20000;

    this.module_interface = null;

    this.init = cff_driver_init;
    this.done = cff_driver_done;
    this.get_interface = cff_get_interface;

    this.face_object_size = 0;
    this.size_object_size = 0;
    this.slot_object_size = 0;

    this.init_face = cff_face_init;
    this.done_face = cff_face_done;

    this.init_size = cff_size_init;
    this.done_size = cff_size_done;

    this.init_slot = cff_slot_init;
    this.done_slot = cff_slot_done;

    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    this.set_char_sizes = ft_stub_set_char_sizes;
    this.set_pixel_sizes = ft_stub_set_pixel_sizes;
    //#endif

    this.load_glyph = cff_Load_Glyph;

    this.get_kerning = cff_get_kerning;
    this.attach_file = null;
    this.get_advances = cff_get_advances;

    this.request_size = cff_size_request;
    this.select_size = cff_size_select;
}

function CFF_Driver()
{
    this.clazz = null;      // FT_Module_Class
    this.library = null;    // FT_Library
    this.memory = null;     // FT_Memory
    this.generic = null;    // FT_Generic

    this.clazz = new CFF_Driver_Class();
    this.faces_list = [];
    this.extensions = null;
    this.glyph_loader = null;

    this.extension_component = null;

    this.open_face = function(stream, face_index)
    {
        FT_Error = 0;
        var face = new TT_Face();
        var internal = new FT_Face_Internal();

        face.driver = this;
        face.memory = this.memory;
        face.stream = stream;

        //#ifdef FT_CONFIG_OPTION_INCREMENTAL
        face.internal = internal;
        face.internal.incremental_interface = null;
        //#endif

        var err1 = this.clazz.init_face(stream, face, face_index);

        if (err1 != 0)
        {
            face = null;
            FT_Error = err1;
            return null;
        }

        var err2 = find_unicode_charmap(face);
        if (err2 != 0 && err2 != 38)
        {
            face = null;
            FT_Error = err2;
            return null;
        }

		FT_Error = 0;
        return face;
    }
}

function create_cff_driver(library)
{
    var driver = new CFF_Driver();
    driver.library = library;
    driver.memory = library.Memory;

    return driver;
}
/******************************************************************************/
// afm
/******************************************************************************/
function T1_Done_Metrics(memory, fi)
{
    fi.KernPairs = null;
    fi.NumKernPair = 0;

    fi.TrackKerns = null;
    fi.NumTrackKern = 0;
}

function t1_get_index(name, len, user_data)
{
    var type1 = user_data;

    /* PS string/name length must be < 16-bit */
    if (len > 0xFFFF)
        return 0;

    for (var n = 0; n < type1.num_glyphs; n++)
    {
        var gname = type1.glyph_names[n];

        if (gname == name)
            return n;
    }

    return 0;
}

function compare_kern_pairs(a, b)
{
    var index1 = (a.index1 << 16) | a.index2;
    var index2 = (b.index2 << 16) | b.index2;

    if (index1 > index2)
        return 1;
    else if (index1 < index2)
        return -1;
    else
        return 0;
}

function T1_Read_PFM(t1_face, stream, fi)
{
    var error = 0;
    var start = new CPointer();
    start.data = stream.data;
    start.pos = stream.cur;

    var limit = stream.limit;
    var p = dublicate_pointer(start);

    /* Figure out how long the width table is.          */
    /* This info is a little-endian short at offset 99. */
    p.pos = start.pos + 99;
    if (p.pos + 2 > limit)
        return 3;

    var width_table_length = FT_PEEK_USHORT_LE(p);

    p.pos += 18 + width_table_length;
    if (p.pos + 0x12 > limit || FT_PEEK_USHORT_LE(p) < 0x12)
        return error;

    /* Kerning offset is 14 bytes from start of extensions table. */
    p.pos += 14;
    p.pos = start.pos + FT_PEEK_ULONG_LE(p);

    if (p.pos == start.pos)
        return error;

    if (p.pos + 2 > limit)
        return 2;

    fi.NumKernPair = FT_PEEK_USHORT_LE(p);
    p.pos += 2;
    if (p.pos + 4 * fi.NumKernPair > limit)
        return 3;

    /* Actually, kerning pairs are simply optional! */
    if (fi.NumKernPair == 0)
        return error;

    fi.KernPairs = new Array(fi.NumKernPair);
    for (var i = 0; i < fi.KernPairs; i++)
    {
        fi.KernPairs[i] = new AFM_KernPairRec();
    }

    /* now, read each kern pair */
    var kp = 0;
    limit = p.pos + 4 * fi.NumKernPair;

    /* PFM kerning data are stored by encoding rather than glyph index, */
    /* so find the PostScript charmap of this font and install it       */
    /* temporarily.  If we find no PostScript charmap, then just use    */
    /* the default and hope it is the right one.                        */
    var oldcharmap = t1_face.charmap;
    var charmap = null;

    for (var n = 0; n < t1_face.num_charmaps; n++)
    {
        charmap = t1_face.charmaps[n];
        /* check against PostScript pseudo platform */
        if (__FT_CharmapRec(charmap).platform_id == 7)
        {
            error = FT_Set_Charmap(t1_face, charmap);
            if (error)
            {
                fi.KernPairs = null;
                return error;
            }
            break;
        }
    }

    /* Kerning info is stored as:             */
    /*                                        */
    /*   encoding of first glyph (1 byte)     */
    /*   encoding of second glyph (1 byte)    */
    /*   offset (little-endian short)         */
    for (; p.pos < limit; p.pos += 4)
    {
        var _t = fi.KernPairs[kp];

        _t.index1 = FT_Get_Char_Index(t1_face, p.data[p.pos]);
        _t.index2 = FT_Get_Char_Index(t1_face, p.data[p.data + 1]);

        p.pos += 2;
        _t.x = FT_PEEK_SHORT_LE(p);
        p.pos -= 2;
        _t.y = 0;

        kp++;
    }

    if (oldcharmap != null)
        error = FT_Set_Charmap(t1_face, oldcharmap);

    if (error != 0)
    {
        fi.KernPairs = null;
        return error;
    }

    /* now, sort the kern pairs according to their glyph indices */
    ft_qsort(fi.KernPairs, fi.NumKernPair, compare_kern_pairs);

    return error;
}

function T1_Read_Metrics(t1_face, stream)
{
    var parser = new AFM_ParserRec();

    var fi = new AFM_FontInfoRec();
    var t1_font = t1_face.type1;

    var error = stream.EnterFrame(stream.size);
    
    fi.FontBBox = dublicate_bbox(t1_font.font_bbox);
    fi.Ascender  = t1_font.font_bbox.yMax;
    fi.Descender = t1_font.font_bbox.yMin;

    var psaux = t1_face.psaux;
    if (psaux != null && psaux.afm_parser_funcs != null)
    {
        var cur = new CPointer();
        cur.pos = stream.cur;
        cur.data = stream.data;
        error = psaux.afm_parser_funcs.init(parser, g_memory, cur, stream.size);

        if (error == 0)
        {
            parser.FontInfo  = fi;
            parser.get_index = t1_get_index;
            parser.user_data = t1_face.type1;

            error = psaux.afm_parser_funcs.parse(parser);
            psaux.afm_parser_funcs.done(parser);
        }
    }

    if (error == 2)
    {
        var start = new CPointer();
        start.pos = stream.cur;
        start.data = stream.data;

        /* MS Windows allows versions up to 0x3FF without complaining */
        if (stream.size > 6 && start.data[start.pos + 1] < 4)
        {
            start.pos += 2;
            if (FT_PEEK_ULONG_LE(start) == stream.size)
            {
                error = T1_Read_PFM(t1_face, stream, fi);
            }
        }
    }

    if (error == 0)
    {
        t1_font.font_bbox = dublicate_bbox(fi.FontBBox);

        t1_face.bbox.xMin = fi.FontBBox.xMin >> 16;
        t1_face.bbox.yMin = fi.FontBBox.yMin >> 16;
        /* no `U' suffix here to 0xFFFF! */
        t1_face.bbox.xMax = (fi.FontBBox.xMax + 0xFFFF) >> 16;
        t1_face.bbox.yMax = (fi.FontBBox.yMax + 0xFFFF) >> 16;

        /* no `U' suffix here to 0x8000! */
        t1_face.ascender  = ((fi.Ascender  + 0x8000) >> 16);
        t1_face.descender = ((fi.Descender + 0x8000) >> 16);

        if (fi.NumKernPair == 0)
        {
            t1_face.face_flags |= 64;
            t1_face.afm_data = fi;
            fi = null;
        }
    }

    stream.ExitFrame();

    if (fi != null)
    {
        T1_Done_Metrics(g_memory, fi);
        fi = null;
    }
    return error;
}

function T1_Get_Kerning(fi, glyph1, glyph2)
{
    var kerning = new FT_Vector();
    var min = 0;
    var mid = 0;
    var max = fi.NumKernPair - 1;
    var idx = (glyph1 << 16) | glyph2;

    /* simple binary search */
    var pairs = fi.KernPairs;

    while (min <= max)
    {
        mid  = min + (max - min) / 2;
        var midi = (pairs[mid].index1) << 16 | pairs[mid].index2;

        if (midi == idx)
        {
            kerning.x = mid.x;
            kerning.y = mid.y;

            return kerning;
        }

        if (midi < idx)
            min = mid + 1;
        else
            max = mid - 1;
    }

    kerning.x = 0;
    kerning.y = 0;

    return kerning;
}

function T1_Get_Track_Kerning(face, ptsize, degree, kerning)
{
    var fi = face.afm_data;
    var ret = { err: 6, kerning: kerning };

    if (fi == null)
    {
        ret.err = 6;
        return ret;
    }

    var count = fi.NumTrackKern;
    for (var i = 0; i < count; i++)
    {
        var tk = fi.TrackKerns[i];

        if (tk.degree != degree)
            continue;

        if (ptsize < tk.min_ptsize)
        {
            ret.kerning = tk.min_kern;
        }
        else if (ptsize > tk.max_ptsize)
        {
            ret.kerning = tk.max_kern;
        }
        else
        {
            ret.kerning = FT_MulDiv(ptsize - tk.min_ptsize, tk.max_kern - tk.min_kern, tk.max_ptsize - tk.min_ptsize) + tk.min_kern;
        }
    }

    return ret;
}

/******************************************************************************/
// gload
/******************************************************************************/
function T1_Parse_Glyph_And_Get_Char_String(decoder, glyph_index, char_string)
{
    var face = decoder.builder.face;
    var type1 = face.type1;
    var error = 0;

    decoder.font_matrix = dublicate_matrix(type1.font_matrix);
    decoder.font_offset = dublicate_vector(type1.font_offset);

    char_string.pointer = dublicate_pointer(type1.charstrings[glyph_index]);
    char_string.length  = type1.charstrings_len[glyph_index];

    if (error == 0)
        error = decoder.funcs.parse_charstrings(decoder, char_string.pointer, char_string.length);

    return error;
}

function T1_Parse_Glyph(decoder, glyph_index)
{
    var glyph_data = new FT_Data();
    var error = T1_Parse_Glyph_And_Get_Char_String(decoder, glyph_index, glyph_data);
    return error;
}

function T1_Compute_Max_Advance(face)
{
    var ret = { err : 0, max_advance : 0 };

    var type1 = face.type1;
    var psaux = face.psaux;

    /* initialize load decoder */
    var decoder = new T1_DecoderRec();
    
    ret.err = psaux.t1_decoder_funcs.init(decoder, face, null, null, type1.glyph_names, face.blend, 0, 0, T1_Parse_Glyph);
    if (ret.err != 0)
        return ret;

        decoder.builder.metrics_only = 1;
    decoder.builder.load_points  = 0;

    decoder.num_subrs     = type1.num_subrs;
    decoder.subrs         = type1.subrs;
    decoder.subrs_len     = type1.subrs_len;

    decoder.buildchar     = face.buildchar;
    decoder.len_buildchar = face.len_buildchar;

    /* for each glyph, parse the glyph charstring and extract */
    /* the advance width                                      */
    var _count = type1.num_glyphs;
    for (var glyph_index = 0; glyph_index < _count; glyph_index++)
    {
        if (glyph_index == 342)
        {
            var tt = 0;
            tt += 5;
            tt -= 89;
            tt += 8;
        }

        /* now get load the unscaled outline */
        ret.err = T1_Parse_Glyph(decoder, glyph_index);
        if (glyph_index == 0 || decoder.builder.advance.x > ret.max_advance)
            ret.max_advance = decoder.builder.advance.x;
    }

    psaux.t1_decoder_funcs.done(decoder);
    ret.err = 0;
    return ret;
}

function T1_Get_Advances(face, first, count, load_flags, advances)
{
    if (load_flags & 16)
    {
        for ( nn = 0; nn < count; nn++ )
            advances[nn] = 0;

        return 0;
    }

    var decoder = new T1_DecoderRec();
    var psaux = face.psaux;
    var type1 = face.type1;

    var error = psaux.t1_decoder_funcs.init(decoder, face, null, null, type1.glyph_names, face.blend, 0, 0, T1_Parse_Glyph);
    if (error != 0)
        return error;

    decoder.builder.metrics_only = 1;
    decoder.builder.load_points  = 0;

    decoder.num_subrs = type1.num_subrs;
    decoder.subrs     = type1.subrs;
    decoder.subrs_len = type1.subrs_len;

    decoder.buildchar     = face.buildchar;
    decoder.len_buildchar = face.len_buildchar;

    for (var nn = 0; nn < count; nn++)
    {
        error = T1_Parse_Glyph(decoder, first + nn);
        if (error == 0)
            advances[nn] = FT_RoundFix(decoder.builder.advance.x) >> 16;
        else
            advances[nn] = 0;
    }

    return 0;
}

function T1_Load_Glyph(_glyph, size, glyph_index, load_flags)
{
    var glyph = _glyph.base_root;

    var decoder = new T1_DecoderRec();
    var face = _glyph.face;
    var type1 = face.type1;
    var psaux = face.psaux;
    var decoder_funcs = psaux.t1_decoder_funcs;

    var glyph_data = new FT_Data();
    var must_finish_decoder = 0;

    if (glyph_index >= face.num_glyphs)
        return 6;

    if (load_flags & 1024)
        load_flags |= (1 | 2);

    if (size != null)
    {
        glyph.x_scale = size.metrics.x_scale;
        glyph.y_scale = size.metrics.y_scale;
    }
    else
    {
        glyph.x_scale = 0x10000;
        glyph.y_scale = 0x10000;
    }

    _glyph.outline.n_points   = 0;
    _glyph.outline.n_contours = 0;

    var hinting = ((load_flags & 1) == 0 && (load_flags & 2) == 0);
    _glyph.format = 1869968492;

    var error = decoder_funcs.init(decoder, face, size, glyph, type1.glyph_names, face.blend, hinting, FT_LOAD_TARGET_MODE(load_flags), T1_Parse_Glyph);
    if (error != 0)
        return error;

    must_finish_decoder = 1;

    decoder.builder.no_recurse = ((load_flags & 1024) != 0) ? 1 : 0;

    decoder.num_subrs     = type1.num_subrs;
    decoder.subrs         = type1.subrs;
    decoder.subrs_len     = type1.subrs_len;

    decoder.buildchar     = face.buildchar;
    decoder.len_buildchar = face.len_buildchar;

    /* now load the unscaled outline */
    error = T1_Parse_Glyph_And_Get_Char_String(decoder, glyph_index, glyph_data);
    if (error != 0)
    {
        decoder_funcs.done(decoder);
        return error;
    }

    var font_matrix = dublicate_matrix(decoder.font_matrix);
    var font_offset = dublicate_vector(decoder.font_offset);

    /* save new glyph tables */
    decoder_funcs.done(decoder);
    
    must_finish_decoder = 0;

    /* now, set the metrics -- this is rather simple, as   */
    /* the left side bearing is the xMin, and the top side */
    /* bearing the yMax                                    */
    if (error == 0)
    {
        glyph.root.outline.flags &= 1;
        glyph.root.outline.flags |= 4;

        /* for composite glyphs, return only left side bearing and */
        /* advance width                                           */
        if ((load_flags & 1024) != 0)
        {
            var internal = glyph.root.internal;

            glyph.root.metrics.horiBearingX = FT_RoundFix(decoder.builder.left_bearing.x) >> 16;
            glyph.root.metrics.horiAdvance = FT_RoundFix(decoder.builder.advance.x);

            internal.glyph_matrix      = dublicate_matrix(font_matrix);
            internal.glyph_delta       = dublicate_vector(font_offset);
            internal.glyph_transformed = 1;
        }
        else
        {
            var cbox = new FT_BBox();
            var metrics = glyph.root.metrics;
            var advance = new FT_Vector();

            /* copy the _unscaled_ advance width */
            metrics.horiAdvance = FT_RoundFix(decoder.builder.advance.x) >> 16;
            glyph.root.linearHoriAdvance = FT_RoundFix(decoder.builder.advance.x) >> 16;
            glyph.root.internal.glyph_transformed = 0;

            if ((load_flags & 16) != 0)
            {
                /* make up vertical ones */
                metrics.vertAdvance = (face.type1.font_bbox.yMax - face.type1.font_bbox.yMin) >> 16;
                glyph.root.linearVertAdvance = metrics.vertAdvance;
            }
            else
            {
                metrics.vertAdvance = FT_RoundFix(decoder.builder.advance.y) >> 16;
                glyph.root.linearVertAdvance = FT_RoundFix(decoder.builder.advance.y) >> 16;
            }

            glyph.root.format = 1869968492;

            if (size != null && size.metrics.y_ppem < 24)
                glyph.root.outline.flags |= 256;

            /* apply the font matrix, if any */
            if (font_matrix.xx != 0x10000 || font_matrix.yy != font_matrix.xx || font_matrix.xy != 0 || font_matrix.yx != 0)
                FT_Outline_Transform(glyph.root.outline, font_matrix);

            if (font_offset.x || font_offset.y)
                FT_Outline_Translate(glyph.root.outline, font_offset.x, font_offset.y);

            advance.x = metrics.horiAdvance;
            advance.y = 0;
            FT_Vector_Transform(advance, font_matrix);
            metrics.horiAdvance = advance.x + font_offset.x;
            advance.x = 0;
            advance.y = metrics.vertAdvance;
            FT_Vector_Transform(advance, font_matrix);
            metrics.vertAdvance = advance.y + font_offset.y;

            if ((load_flags & 1) == 0)
            {
                /* scale the outline and the metrics */
                var cur_p_c = decoder.builder.base.n_points;
                var points = decoder.builder.base.points;
                var vec = 0;
                var x_scale = glyph.x_scale;
                var y_scale = glyph.y_scale;


                /* First of all, scale the points, if we are not hinting */
                if (hinting == 0 || decoder.builder.hints_funcs == null)
                {
                    for (var n = cur_p_c; n > 0; n--, vec++)
                    {
                        points[vec].x = FT_MulFix(points[vec].x, x_scale);
                        points[vec].y = FT_MulFix(points[vec].y, y_scale);
                    }
                }

                /* Then scale the metrics */
                metrics.horiAdvance = FT_MulFix(metrics.horiAdvance, x_scale);
                metrics.vertAdvance = FT_MulFix(metrics.vertAdvance, y_scale);
            }

            /* compute the other metrics */
            FT_Outline_Get_CBox(glyph.root.outline, cbox);

            metrics.width  = cbox.xMax - cbox.xMin;
            metrics.height = cbox.yMax - cbox.yMin;

            metrics.horiBearingX = cbox.xMin;
            metrics.horiBearingY = cbox.yMax;

            if ((load_flags & 16) != 0)
            {
                /* make up vertical ones */
                ft_synthesize_vertical_metrics(metrics, metrics.vertAdvance);
            }
        }

        /* Set control data to the glyph charstrings.  Note that this is */
        /* _not_ zero-terminated.                                        */
        glyph.root.control_data = dublicate_pointer(glyph_data.pointer);
        glyph.root.control_len  = glyph_data.length;
    }

    return error;
}

/******************************************************************************/
// parse
/******************************************************************************/
function T1_ParserRec()
{
    this.root = new PS_ParserRec();
    this.stream = null;

    this.base_dict = null;
    this.base_len = 0;

    this.private_dict = null;
    this.private_len = 0;

    this.in_pfb = 0;
    this.in_memory = 0;
    this.single_block = 0;

    this.clear = function()
    {
        this.root.clear();
        this.stream = null;

        this.base_dict = null;
        this.base_len = 0;

        this.private_dict = null;
        this.private_len = 0;

        this.in_pfb = 0;
        this.in_memory = 0;
        this.single_block = 0;
    }
}

function read_pfb_tag(stream)
{
    var ret = { tag: 0, size: 0, err: 0 };

    var tag = stream.ReadUShort();
    ret.err = FT_Error;
    if (ret.err == 0)
    {
        if (tag == 0x8001 || tag == 0x8002)
        {
            var size = stream.ReadULongLE();
            ret.err = FT_Error;
            if (ret.err == 0)
                ret.size = size;
        }
        ret.tag = tag;
    }
    return ret;
}

function check_type1_format(stream, header_string, header_length)
{
    var error = stream.Seek(0);
    if (error != 0)
        return error;


    var ret = read_pfb_tag(stream);
    if (ret.err != 0)
        return ret.err;

    /* We assume that the first segment in a PFB is always encoded as   */
    /* text.  This might be wrong (and the specification doesn't insist */
    /* on that), but we have never seen a counterexample.               */
    if (ret.tag != 0x8001 && 0 != stream.Seek(0))
        return error;

    error = stream.EnterFrame(header_length);
    if (error == 0)
    {
        for (var i = 0; i < header_length; i++)
        {
            if (header_string.charCodeAt(i) != stream.data[stream.cur + i])
                return 2;
        }

        stream.ExitFrame();
    }
    return error;
}

function T1_New_Parser(parser, stream, memory, psaux)
{
    psaux.ps_parser_funcs.init(parser.root, null, 0, memory);

    parser.stream       = stream;
    parser.base_len     = 0;
    parser.base_dict    = null;
    parser.private_len  = 0;
    parser.private_dict = null;
    parser.in_pfb       = 0;
    parser.in_memory    = 0;
    parser.single_block = 0;

    /* check the header format */
    var error = check_type1_format(stream, "%!PS-AdobeFont", 14);
    if (error != 0)
    {
        if (error != 2)
            return error;

        error = check_type1_format(stream, "%!FontType", 10);
        if (error != 0)
            return error;
    }

    error = stream.Seek(0);
    if (error != 0)
        return error;

    var ret = read_pfb_tag(stream);
    if (ret.err != 0)
        return ret.err;

    var size = ret.size;

    if (ret.tag != 0x8001)
    {
        /* assume that this is a PFA file for now; an error will */
        /* be produced later when more things are checked        */
        error = stream.Seek(0);
        if (error != 0)
            return error;
        size = stream.size;
    }
    else
        parser.in_pfb = 1;

    /* now, try to load `size' bytes of the `base' dictionary we */
    /* found previously                                          */
    /* if it is a memory-based resource, set up pointers */
    parser.base_dict = new CPointer();
    parser.base_dict.data = stream.data;
    parser.base_dict.pos = stream.pos;
    parser.base_len = size;
    parser.in_memory = 1;

    error = stream.Skip(size);
    if (error != 0)
        return error;

    parser.root.base   = dublicate_pointer(parser.base_dict);
    parser.root.cursor = dublicate_pointer(parser.root.base);
    parser.root.limit  = parser.root.base.pos + parser.base_len;

    return error;
}

function T1_Finalize_Parser(parser)
{
    parser.private_dict = null;
    parser.base_dict = null;

    parser.root.funcs.done(parser.root);
}

function T1_Get_Private_Dict(parser, psaux)
{
    var stream = parser.stream;
    var memory = parser.root.memory;

    var error = 0;
    var size = 0;

    if (parser.in_pfb == 1)
    {
        /* in the case of the PFB format, the private dictionary can be  */
        /* made of several segments.  We thus first read the number of   */
        /* segments to compute the total size of the private dictionary  */
        /* then re-read them into memory.                                */
        var start_pos = stream.pos;
        parser.private_len = 0;
        for (;;)
        {
            var ret = read_pfb_tag(stream);
            if (ret.err != 0)
                return ret.err;

            if (ret.tag != 0x8002)
                break;

            parser.private_len += ret.size;

            error = stream.Skip(ret.size);
        }

        /* Check that we have a private dictionary there */
        /* and allocate private dictionary buffer        */
        if (parser.private_len == 0)
            return 3;

        error = stream.Seek(start_pos);
        if (error != 0)
            return error;

        parser.private_dict = memory.Alloc(parser.private_len);
        parser.private_len = 0;
        var p = dublicate_pointer(parser.private_dict);
        for (;;)
        {
            var ret = read_pfb_tag(stream);
            if (ret.err != 0 || ret.tag != 0x8002)
            {
                error = 0;
                break;
            }

            p.pos = parser.private_len;
            error = stream.Read(p, ret.size);

            if (error != 0)
                return error;

            parser.private_len += ret.size;
        }
    }
    else
    {
        /* We have already `loaded' the whole PFA font file into memory; */
        /* if this is a memory resource, allocate a new block to hold    */
        /* the private dict.  Otherwise, simply overwrite into the base  */
        /* dictionary block in the heap.                                 */

        /* first of all, look at the `eexec' keyword */
        var cur = dublicate_pointer(parser.base_dict);
        var limit = cur.pos + parser.base_len;
        var c = 0;

        var _go_to_found = 0;

        while (true)
        {
            for (;;)
            {
                c = cur.data[cur.pos];
                if (c == 101 && cur.pos + 9 < limit)  /* 9 = 5 letters for `eexec' + */
                {
                    if (cur.data[cur.pos + 1] == 101 && cur.data[cur.pos + 2] == 120 &&
                        cur.data[cur.pos + 3] == 101 && cur.data[cur.pos + 4] == 99)
                        break;
                }
                cur.pos++;
                if (cur.pos >= limit)
                    return 3;
            }

            /* check whether `eexec' was real -- it could be in a comment */
            /* or string (as e.g. in u003043t.gsf from ghostscript)       */
            parser.root.cursor = dublicate_pointer(parser.base_dict);
            parser.root.limit  = cur.pos + 9;

            cur = dublicate_pointer(parser.root.cursor);

            limit = parser.root.limit;

            while (cur.pos < limit)
            {
                if (cur.data[cur.pos] == 101 && _strncmp_data(cur, "eexec", 5) == 0)
                {
                    _go_to_found = 1;
                    break;
                }

                parser.root.funcs.skip_PS_token(parser.root);
                if (parser.root.error != 0)
                    break;
                parser.root.funcs.skip_spaces(parser.root);
                cur.pos = parser.root.cursor.pos;
            }

            if (_go_to_found == 1)
                break;

            /* we haven't found the correct `eexec'; go back and continue */
            /* searching                                                  */
            cur.pos   = limit;
            limit = parser.base_dict.pos + parser.base_len;
        }

        /* now determine where to write the _encrypted_ binary private  */
        /* dictionary.  We overwrite the base dictionary for disk-based */
        /* resources and allocate a new block otherwise                 */
        parser.root.limit = parser.base_dict.pos + parser.base_len;

        parser.root.funcs.skip_PS_token(parser.root);
        cur.pos = parser.root.cursor.pos;

        /* according to the Type1 spec, the first cipher byte must not be  */
        /* an ASCII whitespace character code (blank, tab, carriage return */
        /* or line feed).  We have seen Type 1 fonts with two line feed    */
        /* characters...  So skip now all whitespace character codes.      */
        while (cur.pos < limit  && (cur.data[cur.pos] == 32 || cur.data[cur.pos] == 9 || cur.data[cur.pos] == 13 || cur.data[cur.pos] == 10))
            cur.pos++;
        if (cur.pos >= limit)
            return 3;

        size = parser.base_len - (cur.pos - parser.base_dict.pos);

        if (parser.in_memory == 1)
        {
            /* note that we allocate one more byte to put a terminating `0' */
            parser.private_dict = memory.Alloc(size + 1);
            parser.private_len = size;
        }
        else
        {
            parser.single_block = 1;
            parser.private_dict = dublicate_pointer(parser.base_dict);
            parser.private_len  = size;
            parser.base_dict    = null;
            parser.base_len     = 0;
        }

        /* now determine whether the private dictionary is encoded in binary */
        /* or hexadecimal ASCII format -- decode it accordingly              */

        /* we need to access the next 4 bytes (after the final \r following */
        /* the `eexec' keyword); if they all are hexadecimal digits, then   */
        /* we have a case of ASCII storage                                  */

        if (_isxdigit(cur[0]) && _isxdigit(cur[1]) && _isxdigit(cur[2]) && _isxdigit(cur[3]))
        {
            /* ASCII hexadecimal encoding */
            parser.root.cursor = cur.pos;
            var ret = psaux.ps_parser_funcs.to_bytes(parser.root, parser.private_dict, parser.private_len, 0);
            parser.private_len = ret.num_bytes;

            /* put a safeguard */
            parser.private_dict[ret.num_bytes] = 0;
        }
        else
        {
            var mem = memory.Alloc(size);
            for (var i = 0; i < size; i++)
                mem.data[i] = cur.data[cur.pos + i];

            var _p = parser.private_dict.data;
            var _n = parser.private_dict.pos;
            for (var i = 0; i < size; i++)
                _p[_n + i] = mem.data[i];

            mem = null;
        }

    }

    /* we now decrypt the encoded binary private dictionary */
    var _mem = dublicate_pointer(parser.private_dict);
    psaux.t1_decrypt(_mem, parser.private_len, 55665);

    /* replace the four random bytes at the beginning with whitespace */
    var _d = parser.private_dict.data;
    _d[0] = 32;
    _d[1] = 32;
    _d[2] = 32;
    _d[3] = 32;

    parser.root.base   = dublicate_pointer(parser.private_dict);
    parser.root.cursor = dublicate_pointer(parser.private_dict);
    parser.root.limit  = parser.private_dict.pos + parser.private_len;

    return error;
}

/******************************************************************************/
// objs
/******************************************************************************/
var T1_SizeRec = FT_Size;

function T1_GlyphSlotRec()
{
    this.root = new FT_GlyphSlot();
    this.root.base_root = this;

    this.hint = 0;
    this.scaled = 0;

    this.max_points = 0;
    this.max_contours = 0;

    this.x_scale = 0;
    this.y_scale = 0;
}

function T1_Size_Get_Globals_Funcs(size)
{
    return null;

    var pshinter = size.face.pshinter;
    var module = size.face.driver.library.FT_Get_Module("pshinter");
    if (module != null && pshinter != null && pshinter.get_globals_funcs != null)
        return pshinter.get_globals_funcs(module);
    return null;
}

function T1_Size_Done(size)
{
    if (size.internal != null)
    {
        var funcs = T1_Size_Get_Globals_Funcs(size);
        if (funcs != null)
            funcs.destroy(size.internal);

        size.internal = null;
    }
}

function T1_Size_Init()
{
    var size  = new FT_Size();
    var funcs = T1_Size_Get_Globals_Funcs(size);

    if (funcs != null)
    {
        // TODO: (hints)
    }

    return size;
}

function T1_Size_Request(size, req)
{
    var funcs = T1_Size_Get_Globals_Funcs(size);
    FT_Request_Metrics(size.face, req);

    if (funcs != null)
        funcs.set_scale(size.internal, size.metrics.x_scale, size.metrics.y_scale, 0, 0);

    return 0;
}

function T1_GlyphSlot_Done(slot)
{
    slot.internal.glyph_hints = null;
}

function T1_GlyphSlot_Init(slot)
{
    var face = slot.face;
    var pshinter = face.pshinter;

    if (pshinter != null)
    {
        var module = face.driver.library.FT_Get_Module("pshinter");
        if (module != null)
        {
            var funcs = pshinter.get_t1_funcs(module);
            slot.internal.glyph_hints = funcs;
        }
    }
    return 0;
}

function T1_Face_Done(face)
{
    if (face == null)
        return;

    var memory = face.memory;
    var type1 = face.type1;

    //#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
    /* release multiple masters information */
    if (face.buildchar != null)
    {
        face.buildchar = null;
        face.len_buildchar = 0;
    }

    T1_Done_Blend(face);
    face.blend = 0;
    //#endif

    /* release font info strings */
    var info = type1.font_info;

    info.version = null;
    info.notice = null;
    info.full_name = null;
    info.family_name = null;
    info.weight = null;

    /* release top dictionary */
    type1.charstrings_len = null;
    type1.charstrings = null;
    type1.glyph_names = null;

    type1.subrs = null;
    type1.subrs_len = null;

    type1.subrs_block = null;
    type1.charstrings_block = null;
    type1.glyph_names_block = null;

    type1.encoding.char_index = null;
    type1.encoding.char_name = null;
    type1.font_name = null;

    //#ifndef T1_CONFIG_OPTION_NO_AFM
    /* release afm data if present */
    if (face.afm_data != null)
    {
        T1_Done_Metrics(memory, face.afm_data);
        face.afm_data = null;
    }
    //#endif

    face.family_name = "";
    face.style_name  = "";
}

function T1_Face_Init(stream, face, face_index, num_params, params)
{
    var type1 = face.type1;
    var info = type1.font_info;

    face.num_faces = 1;

    var psnames = FT_FACE_FIND_GLOBAL_SERVICE(face, FT_SERVICE_ID_POSTSCRIPT_CMAPS);
    face.psnames = psnames;

    var psaux = face.driver.library.FT_Get_Module_Interface("psaux");
    face.psaux = psaux;

    face.pshinter = face.driver.library.FT_Get_Module_Interface("pshinter");

    /* open the tokenizer; this will also check the font format */
    var error = T1_Open_Face(face);
    if (error != 0)
        return error;

    /* if we just wanted to check the format, leave successfully now */
    if (face_index < 0)
        return error;

    /* check the face index */
    if (face_index > 0)
        return 6;

    /* now load the font program into the face object */
    /* initialize the face object fields */
    /* set up root face fields */
    face.num_glyphs = type1.num_glyphs;
    face.face_index = 0;

    face.face_flags = 1 | 16 | 512 | 2048;

    if (info.is_fixed_pitch == 1)
        face.face_flags |= 4;

    if (face.blend != null)
        face.face_flags |= 256;

    /* XXX: TODO -- add kerning with .afm support */
    /* The following code to extract the family and the style is very   */
    /* simplistic and might get some things wrong.  For a full-featured */
    /* algorithm you might have a look at the whitepaper given at       */
    /*                                                                  */
    /*   http://blogs.msdn.com/text/archive/2007/04/23/wpf-font-selection-model.aspx */

    /* get style name -- be careful, some broken fonts only */
    /* have a `/FontName' dictionary entry!                 */
    face.family_name = info.family_name;
    face.style_name = null;

    if (face.family_name != null)
    {
        var full = 0;
        var family = 0;

        var full_len = info.full_name.length;
        var family_len = face.family_name.length;

        if (full < full_len)
        {
            var the_same = 1;
            while (full < full_len)
            {
                var _1 = info.full_name.charCodeAt(full);
                var _2 = (family < family_len) ? face.family_name.charCodeAt(family) : 0;

                if (_1 == _2)
                {
                    family++;
                    full++;
                }
                else
                {
                    if (_1 == 32 || _1 == 45)
                        full++;
                    else if (_2 == 32 || _2 == 45)
                        family++;
                    else
                    {
                        the_same = 0;

                        if (family == family_len)
                            face.style_name = full;
                        break;
                    }
                }
            }

            if (the_same == 1)
                face.style_name = "Regular";
        }
    }
    else
    {
        /* do we have a `/FontName'? */
        if (type1.font_name != null)
            face.family_name = type1.font_name;
    }

    if (face.style_name != null)
    {
        if (info.weight != null)
            face.style_name = info.weight;
        else
            face.style_name = "Regular";
    }

    /* compute style flags */
    face.style_flags = 0;
    if (info.italic_angle != 0)
        face.style_flags |= 1;
    if (info.weight != null)
    {
        if (info.weight == "Bold" || info.weight == "Black")
            face.style_flags |= 2;
    }

    /* no embedded bitmap support */
    face.num_fixed_sizes = 0;
    face.available_sizes = 0;

    face.bbox.xMin = type1.font_bbox.xMin >> 16;
    face.bbox.yMin = type1.font_bbox.yMin >> 16;
    /* no `U' suffix here to 0xFFFF! */
    face.bbox.xMax = (type1.font_bbox.xMax + 0xFFFF) >> 16;
    face.bbox.yMax = (type1.font_bbox.yMax + 0xFFFF) >> 16;

    /* Set units_per_EM if we didn't set it in parse_font_matrix. */
    if (face.units_per_EM == 0)
        face.units_per_EM = 1000;

    face.ascender  = face.bbox.yMax;
    face.descender = face.bbox.yMin;

    face.height = parseInt((face.units_per_EM * 12) / 10);
    if (face.height < (face.ascender - face.descender))
        face.height = (face.ascender - face.descender);

    /* now compute the maximum advance width */
    face.max_advance_width = (face.bbox.xMax);

    var ret = T1_Compute_Max_Advance(face);

    /* in case of error, keep the standard width */
    if (ret.err == 0)
        face.max_advance_width = FT_RoundFix(ret.max_advance) >> 16;
    else
        error = 0;   /* clear error */

    face.max_advance_height = face.height;

    face.underline_position  = info.underline_position;
    face.underline_thickness = info.underline_thickness;

    if (psnames != null && psaux != null)
    {
        var cmap_classes = psaux.t1_cmap_classes;
        var charmap = new FT_CharMapRec();

        charmap.face = face;

        /* first of all, try to synthesize a Unicode charmap */
        charmap.platform_id = 3;
        charmap.encoding_id = 1;
        charmap.encoding    = 1970170211;

        var __cmap = FT_CMap_New(cmap_classes.unicode, null, charmap);
        __cmap = null;
        error = FT_Error;
        FT_Error = 0;
        if (error != 0 && 163 != error)
            return error;
        error = 0;

        /* now, generate an Adobe Standard encoding when appropriate */
        charmap.platform_id = 7;
        var clazz = null;

        switch (type1.encoding_type)
        {
            case 2:
                charmap.encoding    = 1094995778;
                charmap.encoding_id = 0;
                clazz               = cmap_classes.standard;
                break;

            case 4:
                charmap.encoding    = 1094992453;
                charmap.encoding_id = 1;
                clazz               = cmap_classes.expert;
                break;

            case 1:
                charmap.encoding    = 1094992451;
                charmap.encoding_id = 2;
                clazz               = cmap_classes.custom;
                break;

            case 3:
                charmap.encoding    = 1818326065;
                charmap.encoding_id = 3;
                clazz               = cmap_classes.unicode;
                break;

            default:
                break;
        }

        if (clazz != null)
        {
            __cmap = FT_CMap_New(clazz, null, charmap);
            error = FT_Error;
            __cmap = null;
        }
    }

    return error;
}

function T1_Driver_Init(driver)
{
    return 0;
}

function T1_Driver_Done(driver)
{
}

/******************************************************************************/
// load
/******************************************************************************/

function T1_Loader()
{
    this.parser = new T1_ParserRec();

    this.num_chars = 0;
    this.encoding_table = new PS_TableRec();
    /* encoding character names         */

    this.num_glyphs = 0;
    this.glyph_names = new PS_TableRec();
    this.charstrings = new PS_TableRec();
    this.swap_table = new PS_TableRec();

    this.num_subrs = 0;
    this.subrs = new PS_TableRec();
    this.fontdata = 0;

    this.keywords_encountered = 0;

    this.clear = function()
    {
        this.parser.clear();

        this.num_chars = 0;
        this.encoding_table.clear();
        /* encoding character names         */

        this.num_glyphs = 0;
        this.glyph_names.clear();
        this.charstrings.clear();
        this.swap_table.clear();

        this.num_subrs = 0;
        this.subrs.clear();
        this.fontdata = 0;

        this.keywords_encountered = 0;
    }
}

function t1_allocate_blend(face, num_designs, num_axis)
{
    var blend = face.blend;
    if (blend == null)
    {
        blend = new PS_BlendRec();
        blend.num_default_design_vector = 0;
        face.blend = blend;
    }

    /* allocate design data if needed */
    if (num_designs > 0)
    {
        if (blend.num_designs == 0)
        {
            blend.font_infos[0] = face.type1.font_info;
            blend.privates[0] = face.type1.private_dict;
            blend.bboxes[0] = face.type1.font_bbox;

            for (var i = 1; i <= num_designs; i++)
            {
                blend.font_infos[i] = new PS_FontInfoRec();
                blend.privates[i] = new PS_PrivateRec();
                blend.bboxes[i] = new FT_BBox();
            }

            blend.weight_vector = CreateIntArray(num_designs * 2);
            blend.default_weight_vector = num_designs;

            blend.num_designs = num_designs;
        }
        else if (blend.num_designs != num_designs)
            return 3;
    }

    /* allocate axis data if needed */
    if (num_axis > 0)
    {
        if (blend.num_axis != 0 && blend.num_axis != num_axis)
            return 3;

        blend.num_axis = num_axis;
    }

    /* allocate the blend design pos table if needed */
    num_designs = blend.num_designs;
    num_axis    = blend.num_axis;
    if (num_designs && num_axis && blend.design_pos[0] == null)
    {
        for (var i = 0; i < num_designs; i++)
            blend.design_pos[i] = CreateIntArray(num_axis);
    }
    return 0;
}

function T1_Get_Multi_Master(face, master)
{
    var blend = face.blend;
    if (null == blend)
        return 6;

    master.num_axis = blend.num_axis;
    master.num_designs = blend.num_designs;

    for (var n = 0; n < blend.num_axis; n++)
    {
        var axis = master.axis[n];
        var map = blend.design_map[n];

        axis.name = blend.axis_names[n];
        axis.minimum = map.design_points[0];
        axis.maximum = map.design_points[map.num_points - 1];
    }
    return 0;
}

function mm_axis_unmap(axismap, ncv)
{
    if (ncv <= axismap.blend_points[0])
        return (axismap.design_points[0] << 16);

    for (var j = 1; j < axismap.num_points; j++)
    {
        if (ncv <= axismap.blend_points[j])
        {
            var t = FT_MulDiv(ncv - axismap.blend_points[j - 1], 0x10000, axismap.blend_points[j] - axismap.blend_points[j - 1]);
            return (axismap.design_points[j - 1] << 16) + FT_MulDiv(t, axismap.design_points[j] - axismap.design_points[j - 1], 1);
        }
    }

    return (axismap.design_points[axismap.num_points - 1] << 16);
}

function mm_weights_unmap(weights, w_s, axiscoords, a_s, axis_count)
{
    if (axis_count == 1)
        axiscoords[a_s] = weights[w_s + 1];
    else if (axis_count == 2)
    {
        axiscoords[a_s] = weights[w_s + 3] + weights[w_s + 1];
        axiscoords[a_s + 1] = weights[w_s + 3] + weights[w_s + 2];
    }
    else if (axis_count == 3)
    {
        axiscoords[a_s] = weights[w_s + 7] + weights[w_s + 5] + weights[w_s + 3] + weights[w_s + 1];
        axiscoords[a_s + 1] = weights[w_s + 7] + weights[w_s + 6] + weights[w_s + 3] + weights[w_s + 2];
        axiscoords[a_s + 2] = weights[w_s + 7] + weights[w_s + 6] + weights[w_s + 5] + weights[w_s + 4];
    }
    else
    {
        axiscoords[a_s] = weights[w_s + 15] + weights[w_s + 13] + weights[w_s + 11] + weights[w_s + 9] + weights[w_s + 7] + weights[w_s + 5] + weights[w_s + 3] + weights[w_s + 1];
        axiscoords[a_s + 1] = weights[w_s + 15] + weights[w_s + 14] + weights[w_s + 11] + weights[w_s + 10] + weights[w_s + 7] + weights[w_s + 6] + weights[w_s + 3] + weights[w_s + 2];
        axiscoords[a_s + 2] = weights[w_s + 15] + weights[w_s + 14] + weights[w_s + 13] + weights[w_s + 12] + weights[w_s + 7] + weights[w_s + 6] + weights[w_s + 5] + weights[w_s + 4];
        axiscoords[a_s + 3] = weights[w_s + 15] + weights[w_s + 14] + weights[w_s + 13] + weights[w_s + 12] + weights[w_s + 11] + weights[w_s + 10] + weights[w_s + 9] + weights[w_s + 8];
    }
}

function T1_Get_MM_Var(face)
{
    var mmvar = new FT_MM_Var();
    var mmaster = new FT_Multi_Master();
    var axiscoords = CreateIntArray(4);
    var blend = face.blend;

    var error = T1_Get_Multi_Master(face, mmaster);
    if (error != 0)
        return { err: error, mm : null };

    var _num_axis = mmaster.num_axis;
    mmvar.axis = new Array(_num_axis);
    for (var i = 0; i < _num_axis; i++)
        mmvar.axis[i] = new FT_Var_Axis();

    mmvar.num_axis = mmaster.num_axis;
    mmvar.num_designs = mmaster.num_designs;
    mmvar.num_namedstyles = 0xFFFFFFFF;                /* Does not apply */
    /* Point to axes after MM_Var struct */
    mmvar.namedstyle = null;

    for (var i = 0 ; i < _num_axis; i++)
    {
        var _axis = mmvar.axis[i];

        _axis.name = mmaster.axis[i].name;
        _axis.minimum = (mmaster.axis[i].minimum << 16);
        _axis.maximum = (mmaster.axis[i].maximum << 16);
        _axis.def = parseInt((_axis.minimum + _axis.maximum) / 2);
        /* Does not apply.  But this value is in range */
        _axis.strid = 0xFFFFFFFF;
        _axis.tag = 0xFFFFFFFF;

        if (_axis.name == "Weight")
            _axis.tag = 2003265652;//FT_MAKE_TAG("w", "g", "h", "t");
        else if (_axis.name == "Width")
            _axis.tag = 2003072104;//FT_MAKE_TAG("w", "d", "t", "h");
        else if (_axis.name == "OpticalSize")
            _axis.tag = 1869640570;//FT_MAKE_TAG("o", "p", "s", "z");
    }

    if (blend.num_designs == (1 << blend.num_axis))
    {
        mm_weights_unmap(blend.default_weight_vector, 0, axiscoords, 0, blend.num_axis);

        for (var i = 0; i < _num_axis; i++)
            mmvar.axis[i].def = mm_axis_unmap(blend.design_map[i], axiscoords[i]);
    }

    return { err : 0, mm : mmvar };
}

function T1_Set_MM_Blend(face, num_coords, coords)
{
    var blend = face.blend;
    if (blend != null)
        return 6;

    if (blend != null && blend.num_axis == num_coords)
    {
        for (var n = 0; n < blend.num_designs; n++)
        {
            var result = 0x10000;  /* 1.0 fixed */

            for (var m = 0; m < blend.num_axis; m++)
            {
                var factor = coords[m];
                if (factor < 0)
                    factor = 0;
                if (factor > 0x10000)
                    factor = 0x10000;
                if (( n & (1 << m)) == 0)
                    factor = 0x10000 - factor;

                result = FT_MulFix(result, factor);
            }
            blend.weight_vector[n] = result;
        }
    }

    return 0;
}

function T1_Set_MM_Design(face, num_coords, coords)
{
    var blend = face.blend;
    if (null == blend || blend.num_axis != num_coords)
        return 6;

    /* compute the blend coordinates through the blend design map */
    var final_blends = CreateIntArray(16);

    for (var n = 0; n < blend.num_axis; n++)
    {
        var design = coords[n];
        var the_blend = 0;
        var map = blend.design_map[n];
        var designs = map.design_points;
        var blends = map.blend_points;
        var before = -1, after = -1;

        var is_go_to_found = 0;
        for (var p = 0; p < map.num_points; p++)
        {
            var p_design = designs[p];

            /* exact match? */
            if (design == p_design)
            {
                the_blend = blends[p];
                is_go_to_found = 1;
                break;
            }

            if (design < p_design)
            {
                after = p;
                break;
            }

            before = p;
        }

        if (0 == is_go_to_found)
        {
            /* now interpolate if necessary */
            if (before < 0)
                the_blend = blends[0];
            else if ( after < 0 )
                the_blend = blends[map.num_points - 1];
            else
                the_blend = FT_MulDiv(design - designs[before], blends[after] - blends[before], designs[after] - designs[before]);
        }

        final_blends[n] = the_blend;
    }

    var error = T1_Set_MM_Blend(face, num_coords, final_blends);
    return error;
}

function T1_Set_Var_Design(face, num_coords, coords)
{
    var lcoords = CreateIntArray(4);          /* maximum axis count is 4 */

    if (num_coords <= 4 && num_coords > 0)
    {
        for (var i = 0; i < num_coords; i++)
            lcoords[i] = FT_RoundFix(coords[i]) >> 16;
        var error = T1_Set_MM_Design(face, num_coords, lcoords);
        return error;
    }
    return 6;
}

function T1_Done_Blend(face)
{
    face.blend = null;
}

function t1_parse_blend_axis_types(face, loader)
{
    var axis_tokens = new Array(4);
    for (var i = 0; i < 4; i++)
        axis_tokens[i] = new T1_TokenRec();

    /* take an array of objects */
    var num_axis = loader.parser.root.funcs.to_token_array(loader.parser.root, axis_tokens, 4);
    if (num_axis < 0)
    {
        loader.parser.root.error = 162;
        return;
    }
    if (num_axis == 0 || num_axis > 4)
    {
        loader.parser.root.error = 3;
        return;
    }

    /* allocate blend if necessary */
    var error = t1_allocate_blend(face, 0, num_axis);
    if (error != 0)
    {
        loader.parser.root.error = error;
        return;
    }

    var blend = face.blend;
    
    /* each token is an immediate containing the name of the axis */
    for (var n = 0; n < num_axis; n++)
    {
        var token = axis_tokens[n];
        
        /* skip first slash, if any */
        if (token.start.data[token.start.pos] == 47)
            token.start.pos++;

        var len = token.limit - token.start.pos;
        if (len == 0)
        {
            loader.parser.root.error = 3;
            return;
        }

        blend.axis_names[n] = "";
        for (var i = 0; i < len; i++)
        {
            blend.axis_names[n] += String.fromCharCode(token.start.data[token.start.pos + n]);
        }
    }

    loader.parser.root.error = error;
}

function t1_parse_blend_design_positions(face, loader)
{
    var design_tokens = new Array(16);
    for (var i = 0; i < 16; i++)
        design_tokens[i] = new T1_TokenRec();

    var parser = loader.parser;

    /* get the array of design tokens -- compute number of designs */
    var num_designs = parser.root.funcs.to_token_array(parser.root, design_tokens, 16);
    if (num_designs < 0)
    {
        parser.root.error = 162;
        return;
    }
    if (num_designs == 0 || num_designs > 16)
    {
        loader.parser.root.error = 3;
        return;
    }

    var old_cursor = parser.root.cursor;
    var old_limit = parser.root.limit;

    var blend = face.blend;
    var num_axis = 0;  /* make compiler happy */

    var error = 0;
    for (var n = 0; n < num_designs; n++)
    {
        /* read axis/coordinates tokens */
        var token = design_tokens[n];
        parser.root.cursor = token.start.pos;
        parser.root.limit = token.limit;

        var axis_tokens = new Array(4);
        for (var i = 0; i < 4; i++)
            axis_tokens[i] = new T1_TokenRec();
        
        var n_axis = parser.root.funcs.to_token_array(parser.root, axis_tokens, 4);

        if (n == 0)
        {
            if (n_axis <= 0 || n_axis > 4)
            {
                loader.parser.root.error = 3;
                return;
            }

            num_axis = n_axis;
            error = t1_allocate_blend( face, num_designs, num_axis );
            if (error != 0)
            {
                loader.parser.root.error = error;
                return;
            }
            blend = face.blend;
        }
        else if (n_axis != num_axis)
        {
            loader.parser.root.error = 3;
            return;
        }

        /* now read each axis token into the design position */
        for (var axis = 0; axis < n_axis; axis++)
        {
            var token2 = axis_tokens[axis];

            parser.root.cursor = token2.start.pos;
            parser.root.limit  = token2.limit;
            blend.design_pos[n][axis] = parser.root.funcs.to_fixed(parser, 0);
        }
    }

    parser.root.cursor = old_cursor;
    parser.root.limit  = old_limit;

    parser.root.error = error;
}

function t1_parse_blend_design_map(face, loader)
{
    var parser = loader.parser;

    var axis_tokens = new Array(4);
    for (var i = 0; i < 4; i++)
        axis_tokens[i] = new T1_TokenRec();

    var num_axis = parser.root.funcs.to_token_array(parser.root, axis_tokens, 4);

    if (num_axis < 0)
    {
        parser.root.error = 162;
        return;
    }
    if (num_axis == 0 || num_axis > 4)
    {
        parser.root.error = 3;
        return;
    }

    var old_cursor = parser.root.cursor;
    var old_limit = parser.root.limit;

    var error = t1_allocate_blend(face, 0, num_axis);
    if (error != 0)
    {
        parser.root.error = error;
        return;
    }
    var blend = face.blend;

    /* now read each axis design map */
    for (var n = 0; n < num_axis; n++)
    {
        var map = blend.design_map[n];

        var point_tokens = new Array(20);
        for (var i = 0; i < 20; i++)
            point_tokens[i] = new T1_TokenRec();

        var axis_token = axis_tokens[n];

        parser.root.cursor = axis_token.start.pos;
        parser.root.limit  = axis_token.limit;

        var num_points = parser.root.funcs.to_token_array(parser.root, point_tokens, 20);

        if (num_points <= 0 || num_points > 20)
        {
            parser.root.error = 3;
            return;
        }

        /* allocate design map data */
        map.design_points = CreateIntArray(num_points);
        map.blend_points = CreateIntArray(num_points);
        map.num_points = num_points;

        for (var p = 0; p < num_points; p++)
        {
            var point_token = point_tokens[p];

            /* don't include delimiting brackets */
            parser.root.cursor = point_token.start.pos + 1;
            parser.root.limit = point_token.limit - 1;

            map.design_points[p] = parser.root.funcs.to_int(parser.root);
            map.blend_points [p] = parser.root.funcs.to_fixed(parser.root, 0);
        }
    }

    parser.root.cursor = old_cursor;
    parser.root.limit  = old_limit;

    parser.root.error = error;
}

function t1_parse_weight_vector(face, loader)
{
    var design_tokens = new Array(16);
    for (var i = 0; i < 16; i++)
        design_tokens[i] = new T1_TokenRec();

    var parser = loader.parser;
    var blend = face.blend;
    var num_designs = parser.root.funcs.to_token_array(parser.root, design_tokens, 16);
    if (num_designs < 0)
    {
        parser.root.error = 162;
        return;
    }
    if (num_designs == 0 || num_designs > 16)
    {
        parser.root.error = 3;
        return;
    }

    var error = 0;
    if (blend == null || blend.num_designs == 0)
    {
        error = t1_allocate_blend(face, num_designs, 0 );
        if (error != 0)
        {
            parser.root.error = error;
            return;
        }
        blend = face.blend;
    }
    else if (blend.num_designs != num_designs)
    {
        parser.root.error = 3;
        return;
    }

    var old_cursor = parser.root.cursor;
    var old_limit = parser.root.limit;

    for (var n = 0; n < num_designs; n++)
    {
        var token = design_tokens[n];
        parser.root.cursor = token.start.pos;
        parser.root.limit = token.limit;

        var _temp = parser.root.funcs.to_fixed(parser.root, 0);
        blend.weight_vector[n] = _temp;
        blend.weight_vector[blend.default_weight_vector + n] = _temp;
    }

    parser.root.cursor = old_cursor;
    parser.root.limit  = old_limit;

    parser.root.error = error;
}

function t1_parse_buildchar(face, loader)
{
    face.len_buildchar = loader.parser.funcs.to_fixed_array(loader.parser.root, 0, null, 0);
}

function t1_load_keyword(face, loader, field)
{
    var blend = face.blend;
    if (blend != null && blend.num_designs == 0)
        blend = null;

    /* if the keyword has a dedicated callback, call it */
    if (field.type == 10)
    {
        field.reader(face, loader);
        return loader.parser.root.error;
    }

    var max_objects = 0;
    var arr = null;

    /* now, the keyword is either a simple field, or a table of fields; */
    /* we are now going to take care of it                              */
    switch (field.location)
    {
        case 3:
            if (blend != null)
            {
                arr = blend.font_infos;
                max_objects = blend.num_designs;
            }
            else
            {
                arr = new Array(1);
                arr[0] = face.type1.font_info;
                max_objects  = 0;
            }
            break;

        case 2:
            arr = new Array(1);
            arr[0] = face.type1.font_extra;
            max_objects  = 0;
            break;

        case 4:
            if (blend != null)
            {
                arr = blend.privates;
                max_objects = blend.num_designs;
            }
            else
            {
                arr = new Array(1);
                arr[0] = face.type1.private_dict;
                max_objects = 0;
            }
            break;

        case 5:
            if (blend != null)
            {
                arr = blend.bboxes;
                max_objects = blend.num_designs;
            }
            else
            {
                arr = new Array(1);
                arr[0] = face.type1.font_bbox;
                max_objects = 0;
            }
            break;

        case 6:
            arr = new Array(1);
            arr[0] = loader;
            max_objects  = 0;
            break;

        case 7:
            arr = new Array(1);
            arr[0] = face;
            max_objects  = 0;
            break;

        case 8:
            arr = new Array(1);
            arr[0] = loader;
            max_objects  = 0;
            break;

        default:
            arr = new Array(1);
            arr[0] = face.type1;
            max_objects  = 0;
    }

    if (field.type == 8 || field.type == 9)
        return loader.parser.root.funcs.load_field_table(loader.parser.root, field, arr, max_objects, 0);

    return loader.parser.root.funcs.load_field(loader.parser.root, field, arr, max_objects, 0);
}

function t1_parse_private(face, loader)
{
    loader.keywords_encountered |= 1;
}

function _t1_read_binary_data(parser)
{
    var ret = { size: 0, base: null, err: 0 };

    var limit = parser.root.limit;

    /* the binary data has one of the following formats */
    /*                                                  */
    /*   `size' [white*] RD white ....... ND            */
    /*   `size' [white*] -| white ....... |-            */
    /*                                                  */

    parser.root.funcs.skip_spaces(parser.root);
    var cur = dublicate_pointer(parser.root.cursor);

    if (cur.pos < limit && (cur.data[cur.pos] >= 48) && (cur.data[cur.pos] <= 57))
    {
        var s = parser.root.funcs.to_int(parser.root);
        parser.root.funcs.skip_PS_token(parser.root);

        /* there is only one whitespace char after the */
        /* `RD' or `-|' token                          */
        ret.base = dublicate_pointer(parser.root.cursor);
        ret.base.pos += 1;

        if (s >= 0 && s < (limit - ret.base.pos))
        {
            parser.root.cursor.pos += (s + 1);
            ret.size = s;
            ret.err = (parser.root.error == 0) ? 1 : 0;
            return ret;
        }
    }

    parser.root.error = 3;
    return ret;
}

function t1_parse_font_matrix(face, loader)
{
    var parser = loader.parser;
    var matrix = face.type1.font_matrix;
    var offset = face.type1.font_offset;

    var temp = CreateIntArray(6);

    var result = parser.root.funcs.to_fixed_array(parser.root, 6, temp, 3);

    if (result < 0)
    {
        parser.root.error = 3;
        return;
    }

    var temp_scale = Math.abs(temp[3]);

    if (temp_scale == 0)
    {
        parser.root.error = 3;
        return;
    }

    /* Set Units per EM based on FontMatrix values.  We set the value to */
    /* 1000 / temp_scale, because temp_scale was already multiplied by   */
    /* 1000 (in t1_tofixed, from psobjs.c).                              */
    face.units_per_EM = (FT_DivFix(1000 * 0x10000, temp_scale) >> 16);

    /* we need to scale the values by 1.0/temp_scale */
    if (temp_scale != 0x10000)
    {
        temp[0] = FT_DivFix(temp[0], temp_scale);
        temp[1] = FT_DivFix(temp[1], temp_scale);
        temp[2] = FT_DivFix(temp[2], temp_scale);
        temp[4] = FT_DivFix(temp[4], temp_scale);
        temp[5] = FT_DivFix(temp[5], temp_scale);
        temp[3] = temp[3] < 0 ? -0x10000 : 0x10000;
    }

    matrix.xx = temp[0];
    matrix.yx = temp[1];
    matrix.xy = temp[2];
    matrix.yy = temp[3];

    /* note that the offsets must be expressed in integer font units */
    offset.x = temp[4] >> 16;
    offset.y = temp[5] >> 16;
}

function t1_parse_encoding(face, loader)
{
    var parser = loader.parser;
    var limit = parser.root.limit;

    var memory = parser.root.memory;

    var psaux = face.psaux;

    parser.root.funcs.skip_spaces(parser.root);
    var cur = dublicate_pointer(parser.root.cursor);
    if (cur.pos >= limit)
    {
        parser.root.error = 3;
        return;
    }

    /* if we have a number or `[', the encoding is an array, */
    /* and we must load it now                               */
    var _cur_v = cur.data[cur.pos];
    if ((_cur_v >= 48 && _cur_v <= 57) || _cur_v == 91)
    {
        var encode = face.type1.encoding;
        var count, n;
        var char_table = loader.encoding_table;
        var only_immediates = 0;

        /* read the number of entries in the encoding; should be 256 */
        if (_cur_v == 91)
        {
            count = 256;
            only_immediates = 1;
            parser.root.cursor.pos++;
        }
        else
            count = parser.root.funcs.to_int(parser.root);

        parser.root.funcs.skip_spaces(parser.root);
        if (parser.root.cursor.pos >= limit)
            return;

        /* we use a T1_Table to store our charnames */
        loader.num_chars = encode.num_chars = count;

        encode.char_index = CreateUIntArray(count);
        encode.char_name = CreateNullArray(count);
        var error = psaux.ps_table_funcs.init(char_table, count, memory);
        if (error != 0)
        {
            parser.root.error = error;
            return;
        }

        /* We need to `zero' out encoding_table.elements */
        for (n = 0; n < count; n++)
        {
            var notdef_name = memory.Alloc(8);
            notdef_name.data[0] = 46;
            notdef_name.data[1] = 110;
            notdef_name.data[2] = 111;
            notdef_name.data[3] = 116;
            notdef_name.data[4] = 100;
            notdef_name.data[5] = 101;
            notdef_name.data[6] = 102;
            notdef_name.data[7] = 0;

            char_table.funcs.add(char_table, n, notdef_name, 8)
        }

        /* Now we need to read records of the form                */
        /*                                                        */
        /*   ... charcode /charname ...                           */
        /*                                                        */
        /* for each entry in our table.                           */
        /*                                                        */
        /* We simply look for a number followed by an immediate   */
        /* name.  Note that this ignores correctly the sequence   */
        /* that is often seen in type1 fonts:                     */
        /*                                                        */
        /*   0 1 255 { 1 index exch /.notdef put } for dup        */
        /*                                                        */
        /* used to clean the encoding array before anything else. */
        /*                                                        */
        /* Alternatively, if the array is directly given as       */
        /*                                                        */
        /*   /Encoding [ ... ]                                    */
        /*                                                        */
        /* we only read immediates.                               */

        n = 0;
        parser.root.funcs.skip_spaces(parser.root);

        while (parser.root.cursor.pos < limit)
        {
            cur.pos = parser.root.cursor.pos;

            /* we stop when we encounter a `def' or `]' */
            if (cur.data[cur.pos] == 100 && cur.pos + 3 < limit)
            {
                if (cur.data[cur.pos + 1] == 101 && cur.data[cur.pos + 2] == 102 && IS_PS_DELIM(cur.data[cur.pos + 3]))
                {
                    cur.pos += 3;
                    break;
                }
            }
            if (cur.data[cur.pos] == 93)
            {
                cur.pos++;
                break;
            }

            /* check whether we've found an entry */
            if (((cur.data[cur.pos] >= 48) && (cur.data[cur.pos] <= 57)) || (only_immediates == 1))
            {
                var charcode = 0;

                if (only_immediates == 1)
                    charcode = n;
                else
                {
                    charcode = parser.root.funcs.to_int(parser.root);
                    parser.root.funcs.skip_spaces(parser.root);
                }

                cur.pos = parser.root.cursor.pos;

                if (cur.data[cur.pos] == 47 && (cur.pos + 2) < limit && (n < count))
                {
                    cur.pos++;
                    parser.root.cursor.pos = cur.pos;
                    parser.root.funcs.skip_PS_token(parser.root);
                    if (parser.root.error != 0)
                        return;

                    var len = parser.root.cursor.pos - cur.pos;

                    parser.root.error = char_table.funcs.add(char_table, charcode, cur, len + 1);
                    if (parser.root.error != 0)
                        return;
                    char_table.elements[charcode][len] = 0;

                    n++;
                }
                else if (only_immediates == 1)
                {
                    /* Since the current position is not updated for           */
                    /* immediates-only mode we would get an infinite loop if   */
                    /* we don't do anything here.                              */
                    /*                                                         */
                    /* This encoding array is not valid according to the type1 */
                    /* specification (it might be an encoding for a CID type1  */
                    /* font, however), so we conclude that this font is NOT a  */
                    /* type1 font.                                             */
                    parser.root.error = 2;
                    return;
                }
            }
            else
            {
                parser.root.funcs.skip_PS_token(parser.root);
                if (parser.root.error != 0)
                    return;
            }

            parser.root.funcs.skip_spaces(parser.root);
        }

        face.type1.encoding_type = 1;
        parser.root.cursor.pos = cur.pos;
    }
    else
    {
        if (cur.pos + 17 < limit && _strncmp_data(cur, "StandardEncoding", 16) == 0)
            face.type1.encoding_type = 2;
        else if (cur + 15 < limit && _strncmp_data(cur, "ExpertEncoding", 14) == 0)
            face.type1.encoding_type = 4;
        else if (cur + 18 < limit && _strncmp_data(cur, "ISOLatin1Encoding", 17) == 0)
            face.type1.encoding_type = 3;
        else
            parser.root.error = 162;
    }
}

function t1_parse_subrs(face, loader)
{
    var parser = loader.parser;
    var table = loader.subrs;
    var memory = parser.root.memory;

    var psaux = face.psaux;
    parser.root.funcs.skip_spaces(parser.root);

    /* test for empty array */
    if (parser.root.cursor.pos < parser.root.limit && parser.root.cursor.data[parser.root.cursor.pos] == 91)
    {
        parser.root.funcs.skip_PS_token(parser.root);
        parser.root.funcs.skip_spaces(parser.root);

        if (parser.root.cursor.pos >= parser.root.limit || parser.root.cursor.data[parser.root.cursor.pos] != 93)
        parser.root.error = 3;
        return;
    }

    var num_subrs = parser.root.funcs.to_int(parser.root);

    /* position the parser right before the `dup' of the first subr */
    parser.root.funcs.skip_PS_token(parser.root);
    if (parser.root.error != 0)
        return;

    parser.root.funcs.skip_spaces(parser.root);

    var error = 0;
    /* initialize subrs array -- with synthetic fonts it is possible */
    /* we get here twice                                             */
    if (loader.num_subrs == 0)
    {
        error = psaux.ps_table_funcs.init(table, num_subrs, memory);
        if (error != 0)
        {
            parser.root.error = 0;
            return;
        }
    }

    /* the format is simple:   */
    /*                         */
    /*   `index' + binary data */
    /*                         */
    for (;;)
    {
        /* If the next token isn't `dup' we are done. */
        if (_strncmp_data(parser.root.cursor, "dup", 3) != 0)
            break;

        parser.root.funcs.skip_PS_token(parser.root);

        var idx = parser.root.funcs.to_int(parser.root);

        var ret = _t1_read_binary_data(parser);

        var size = ret.size;
        var base = ret.base;
        if (0 == ret.err)
            return;

        /* The binary string is followed by one token, e.g. `NP' */
        /* (bound to `noaccess put') or by two separate tokens:  */
        /* `noaccess' & `put'.  We position the parser right     */
        /* before the next `dup', if any.                        */
        parser.root.funcs.skip_PS_token(parser.root);
        if (parser.root.error != 0)
            return;

        parser.root.funcs.skip_spaces(parser.root);

        if (_strncmp_data(parser.root.cursor, "put", 3) == 0)
        {
            parser.root.funcs.skip_PS_token(parser.root);
            parser.root.funcs.skip_spaces(parser.root);
        }

        /* with synthetic fonts it is possible we get here twice */
        if (loader.num_subrs != 0)
            continue;

        /* some fonts use a value of -1 for lenIV to indicate that */
        /* the charstrings are unencoded                           */
        /*                                                         */
        /* thanks to Tom Kacvinsky for pointing this out           */
        /*                                                         */
        if (face.type1.private_dict.lenIV >= 0)
        {
            /* some fonts define empty subr records -- this is not totally */
            /* compliant to the specification (which says they should at   */
            /* least contain a `return'), but we support them anyway       */
            if (size < face.type1.private_dict.lenIV)
            {
                parser.root.error = 3;
                return;
            }

            /* t1_decrypt() shouldn't write to base -- make temporary copy */
            var temp = memory.Alloc(size);
            for (var i = 0; i < size; i++)
            {
                temp.data[i] = base.data[base.pos + i];
            }

            psaux.t1_decrypt(temp, size, 4330);
            size -= face.type1.private_dict.lenIV;

            temp.pos += face.type1.private_dict.lenIV;
            error = table.funcs.add(table, idx, temp, size);

            temp = null;
        }
        else
            error = table.funcs.add(table, idx, base, size);

        if (error != 0)
        {
            parser.root.error = error;
        }
    }

    if (loader.num_subrs == 0)
        loader.num_subrs = num_subrs;
}

function t1_parse_charstrings(face, loader)
{
    var parser = loader.parser;
    var code_table = loader.charstrings;
    var name_table = loader.glyph_names;
    var swap_table = loader.swap_table;
    var memory = parser.root.memory;

    var psaux = face.psaux;

    var limit = parser.root.limit;
    var n = 0;
    var notdef_index = 0;
    var notdef_found = 0;

    var num_glyphs = parser.root.funcs.to_int(parser.root);
    /* some fonts like Optima-Oblique not only define the /CharStrings */
    /* array but access it also                                        */
    if (num_glyphs == 0 || parser.root.error != 0)
        return;

    /* initialize tables, leaving space for addition of .notdef, */
    /* if necessary, and a few other glyphs to handle buggy      */
    /* fonts which have more glyphs than specified.              */

    /* for some non-standard fonts like `Optima' which provides  */
    /* different outlines depending on the resolution it is      */
    /* possible to get here twice                                */

    var root = parser.root;

    var error = 0;
    if (loader.num_glyphs == 0)
    {
        error = psaux.ps_table_funcs.init(code_table, num_glyphs + 1 + 5, memory);
        if (error != 0)
        {
            root.error = error;
            return;
        }

        error = psaux.ps_table_funcs.init(name_table, num_glyphs + 1 + 5, memory);
        if (error != 0)
        {
            root.error = error;
            return;
        }

        /* Initialize table for swapping index notdef_index and */
        /* index 0 names and codes (if necessary).              */
        error = psaux.ps_table_funcs.init(swap_table, 4, memory);
        if (error != 0)
        {
            root.error = error;
            return error;
        }
    }

    n = 0;

    for (;;)
    {
        /* the format is simple:        */
        /*   `/glyphname' + binary data */

        root.funcs.skip_spaces(root);

        var cur = dublicate_pointer(root.cursor);
        if (cur.pos >= limit)
            break;

        /* we stop when we find a `def' or `end' keyword */
        if (cur.pos + 3 < limit && IS_PS_DELIM(cur.data[cur.pos + 3]))
        {
            if (cur.data[cur.pos] == 100 && cur.data[cur.pos + 1] == 101 && cur.data[cur.pos + 2] == 102)
            {
                /* There are fonts which have this: */
                /*                                  */
                /*   /CharStrings 118 dict def      */
                /*   Private begin                  */
                /*   CharStrings begin              */
                /*   ...                            */
                /*                                  */
                /* To catch this we ignore `def' if */
                /* no charstring has actually been  */
                /* seen.                            */
                if (n != 0)
                    break;
            }

            if (cur.data[cur.pos] == 101 && cur.data[cur.pos + 1] == 110 && cur.data[cur.pos + 2] == 100)
                break;
        }

        root.funcs.skip_PS_token(root);
        if (root.error != 0)
            return;

        if (cur.data[cur.pos] == 47)
        {
            if (cur.pos + 1 >= limit)
            {
                root.error = 3;
                return;
            }

            cur.pos++;                              /* skip `/' */
            var len = root.cursor.pos - cur.pos;

            var ret = _t1_read_binary_data(parser);

            if (ret.err == 0)
                return;

            var size = ret.size;
            var base = ret.base;

            /* for some non-standard fonts like `Optima' which provides */
            /* different outlines depending on the resolution it is     */
            /* possible to get here twice                               */
            if (loader.num_glyphs != 0)
                continue;

            error = name_table.funcs.add(name_table, n, cur, len + 1);
            if (error != 0)
            {
                root.error = error;
                return;
            }

            /* add a trailing zero to the name table */
            name_table.elements[n].data[name_table.elements[n].pos + len] = 0;

            /* record index of /.notdef */
            if (cur.data[cur.pos] == 46 && _strcmp_data(".notdef", name_table.elements[n]) == 0)
            {
                notdef_index = n;
                notdef_found = 1;
            }

            if (face.type1.private_dict.lenIV >= 0 && (n < (num_glyphs + 5)))
            {
                if (size <= face.type1.private_dict.lenIV)
                {
                    root.error = 3;
                    return;
                }

                /* t1_decrypt() shouldn't write to base -- make temporary copy */
                var temp = memory.Alloc(size);

                for (var i = 0; i < size; i++)
                    temp.data[i] = base.data[base.pos + i];


                psaux.t1_decrypt(temp, size, 4330);
                size -= face.type1.private_dict.lenIV;

                temp.pos += face.type1.private_dict.lenIV;
                error = code_table.funcs.add(code_table, n, temp, size);

                temp = null;
            }
            else
                error = code_table.funcs.add(code_table, n, base, size);

            if (error != 0)
            {
                root.error = error;
                return;
            }

            n++;
        }
    }

    loader.num_glyphs = n;

    /* if /.notdef is found but does not occupy index 0, do our magic. */
    if (notdef_found != 0 && _strcmp_data(".notdef", name_table.elements[0]))
    {
        /* Swap glyph in index 0 with /.notdef glyph.  First, add index 0  */
        /* name and code entries to swap_table.  Then place notdef_index   */
        /* name and code entries into swap_table.  Then swap name and code */
        /* entries at indices notdef_index and 0 using values stored in    */
        /* swap_table.                                                     */

        /* Index 0 name */
        error = swap_table.funcs.add(swap_table, 0, name_table.elements[0], name_table.lengths[0]);
        if (error != 0)
        {
            root.error = error;
            return;
        }

        /* Index 0 code */
        error = swap_table.funcs.add(swap_table, 1, code_table.elements[0], code_table.lengths[0]);
        if (error != 0)
        {
            root.error = error;
            return;
        }

        /* Index notdef_index name */
        error = swap_table.funcs.add(swap_table, 2, name_table.elements[notdef_index], name_table.lengths[notdef_index]);
        if (error != 0)
        {
            root.error = error;
            return;
        }

        /* Index notdef_index code */
        error = swap_table.funcs.add(swap_table, 3, code_table.elements[notdef_index], code_table.lengths[notdef_index]);
        if (error != 0)
        {
            root.error = error;
            return;
        }

        error = name_table.funcs.add(name_table, notdef_index, swap_table.elements[0], swap_table.lengths[0]);
        if (error != 0)
        {
            root.error = error;
            return;
        }

        error = code_table.funcs.add(code_table, notdef_index, swap_table.elements[1], swap_table.lengths[1]);
        if (error != 0)
        {
            root.error = error;
            return;
        }

        error = name_table.funcs.add(name_table, 0, swap_table.elements[2], swap_table.lengths[2]);
        if (error != 0)
        {
            root.error = error;
            return;
        }

        error = code_table.funcs.add(code_table, 0, swap_table.elements[3], swap_table.lengths[3]);
        if (error != 0)
        {
            root.error = error;
            return;
        }
    }
    else if (notdef_found == 0)
    {
        /* notdef_index is already 0, or /.notdef is undefined in   */
        /* charstrings dictionary.  Worry about /.notdef undefined. */
        /* We take index 0 and add it to the end of the table(s)    */
        /* and add our own /.notdef glyph to index 0.               */

        /* 0 333 hsbw endchar */
        var notdef_glyph = memory.Alloc(5);
        notdef_glyph.data[0] = 0x8B;
        notdef_glyph.data[1] = 0xF7;
        notdef_glyph.data[2] = 0xE1;
        notdef_glyph.data[3] = 0x0D;
        notdef_glyph.data[4] = 0x0E;

        var notdef_name = memory.Alloc(8);
        notdef_name.data[0] = 46;
        notdef_name.data[1] = 110;
        notdef_name.data[2] = 111;
        notdef_name.data[3] = 116;
        notdef_name.data[4] = 100;
        notdef_name.data[5] = 101;
        notdef_name.data[6] = 102;
        notdef_name.data[7] = 0;

        error = swap_table.funcs.add(swap_table, 0, name_table.elements[0], name_table.lengths[0]);
        if (error != 0)
        {
            root.error = error;
            return;
        }

        error = swap_table.funcs.add(swap_table, 1, code_table.elements[0], code_table.lengths[0]);
        if (error != 0)
        {
            root.error = error;
            return;
        }

        error = name_table.funcs.add(name_table, 0, notdef_name, 8);
        if (error != 0)
        {
            root.error = error;
            return;
        }

        error = code_table.funcs.add(code_table, 0, notdef_glyph, 5);
        if (error != 0)
        {
            root.error = error;
            return;
        }

        error = name_table.funcs.add(name_table, n, swap_table.elements[0], swap_table.lengths[0]);
        if (error != 0)
        {
            root.error = error;
            return;
        }

        error = code_table.funcs.add(code_table, n, swap_table.elements[1], swap_table.lengths[1]);
        if (error != 0)
        {
            root.error = error;
            return;
        }

        /* we added a glyph. */
        loader.num_glyphs += 1;
    }
}

function _t1_parse_dict(face, loader, base, size)
{
    var parser = loader.parser;
    var have_integer = 0;

    parser.root.cursor = dublicate_pointer(base);
    parser.root.limit  = base.pos + size;
    parser.root.error  = 0;

    var limit = parser.root.limit;

    parser.root.funcs.skip_spaces(parser.root);

    var start_binary = dublicate_pointer(parser.root.cursor);
    
    while (parser.root.cursor.pos < limit)
    {
        var cur = dublicate_pointer(parser.root.cursor);

        /* look for `eexec' */
        if (IS_PS_TOKEN(cur, limit, "eexec", 6) == 1)
            break;

        /* look for `closefile' which ends the eexec section */
        else if (IS_PS_TOKEN(cur, limit, "closefile", 10) == 1)
            break;

        /* in a synthetic font the base font starts after a           */
        /* `FontDictionary' token that is placed after a Private dict */
        else if (IS_PS_TOKEN(cur, limit, "FontDirectory", 14) == 1)
        {
            if (loader.keywords_encountered & 1)
                loader.keywords_encountered |= 2;
            parser.root.cursor.pos += 13;
        }
        /* check whether we have an integer */
        else if (cur.data[cur.pos] >= 48 && cur.data[cur.pos] <= 57)
        {
            start_binary.pos = cur.pos;
            parser.root.funcs.skip_PS_token(parser.root);
            if (parser.root.error != 0)
                return parser.root.error;
            have_integer = 1;
        }

        /* in valid Type 1 fonts we don't see `RD' or `-|' directly */
        /* since those tokens are handled by parse_subrs and        */
        /* parse_charstrings                                        */
        else if (cur.data[cur.pos] == 82 && ((cur.pos + 6) < limit) && cur.data[cur.pos + 1] == 68 && have_integer == 1)
        {
            parser.root.cursor.pos = start_binary.pos;

            var ret = _t1_read_binary_data(parser);
            if (0 == ret.err)
                return 3;
            have_integer = 0;
        }
        else if (cur.data[cur.pos] == 45 && ((cur.pos + 6) < limit) && cur.data[cur.pos + 1] == 124 &&  have_integer == 1)
        {
            var ret = _t1_read_binary_data(parser);
            if (0 == ret.err)
                return 3;
            have_integer = 0;
        }

        /* look for immediates */
        else if (cur.data[cur.pos] == 47 && ((cur.pos + 2) < limit))
        {
            cur.pos++;

            parser.root.cursor.pos = cur.pos;
            parser.root.funcs.skip_PS_token(parser.root);
            if (parser.root.error != 0)
                return parser.root.error;

            var len = parser.root.cursor.pos - cur.pos;

            if (len > 0 && len < 22 && parser.root.cursor.pos < limit)
            {
                /* now compare the immediate name to the keyword table */
                for (var _i = 0; _i < t1_keywords.length; _i++)
                {
                    var keyword = t1_keywords[_i];
                    var name = keyword.ident;
                    if (name == null)
                        break;

                    if (cur.data[cur.pos] == name.charCodeAt(0) && len == name.length && _strncmp_data(cur, name, len) == 0)
                    {
                        var dict = ((loader.keywords_encountered & 1) != 0) ? 2 : 1;

                        if ((dict & keyword.dict) == 0)
                        {
                            break;
                        }

                        if (((loader.keywords_encountered & 2) == 0) || (name == "CharStrings"))
                        {
                            parser.root.error = t1_load_keyword(face, loader, keyword);
                            if (parser.root.error != 0)
                            {
                                if (parser.root.error == 162)
                                    parser.root.error = 0;
                                else
                                    return parser.root.error;
                            }
                        }
                        break;
                    }
                }
            }

            have_integer = 0;
        }
        else
        {
            parser.root.funcs.skip_PS_token(parser.root);
            if (parser.root.error != 0)
                return parser.root.error;
            have_integer = 0;
        }

        parser.root.funcs.skip_spaces(parser.root);
    }

    return parser.root.error;
}

function t1_init_loader(loader, face)
{
    loader.clear();

    loader.num_glyphs = 0;
    loader.num_chars  = 0;

    /* initialize the tables -- simply set their `init' field to 0 */
    loader.encoding_table.init  = 0;
    loader.charstrings.init     = 0;
    loader.glyph_names.init     = 0;
    loader.subrs.init           = 0;
    loader.swap_table.init      = 0;
    loader.fontdata             = 0;
    loader.keywords_encountered = 0;
}

function t1_done_loader(loader)
{
    var parser = loader.parser;

    /* finalize tables */
    if (loader.encoding_table.funcs.release != null)
        loader.encoding_table.funcs.release(loader.encoding_table);

    if (loader.charstrings.funcs.release != null)
        loader.charstrings.funcs.release(loader.charstrings);

    if (loader.glyph_names.funcs.release != null)
        loader.glyph_names.funcs.release(loader.glyph_names);

    if (loader.swap_table.funcs.release != null)
        loader.swap_table.funcs.release(loader.swap_table);

    if (loader.subrs.funcs.release != null)
        loader.subrs.funcs.release(loader.subrs);

    /* finalize parser */
    T1_Finalize_Parser(parser);
}

function T1_Open_Face(face)
{
    var loader = new T1_Loader();
    var type1 = face.type1;
    var priv = type1.private_dict;

    var psaux = face.psaux;

    t1_init_loader(loader, face);

    /* default values */
    face.ndv_idx          = -1;
    face.cdv_idx          = -1;
    face.len_buildchar    = 0;

    priv.blue_shift       = 7;
    priv.blue_fuzz        = 1;
    priv.lenIV            = 4;
    priv.expansion_factor = parseInt(0.06 * 0x10000);
    priv.blue_scale       = parseInt(0.039625 * 0x10000 * 1000);

    var parser = loader.parser;
    var error = T1_New_Parser(parser, face.stream, face.memory, psaux);
    if (error != 0)
    {
        t1_done_loader(loader);
        return error;
    }

    error = _t1_parse_dict(face, loader, parser.base_dict, parser.base_len);
    if (error != 0)
    {
        t1_done_loader(loader);
        return error;
    }

    error = T1_Get_Private_Dict(parser, psaux);
    if (error != 0)
    {
        t1_done_loader(loader);
        return error;
    }

    error = _t1_parse_dict(face, loader, parser.private_dict, parser.private_len);
    if (error != 0)
    {
        t1_done_loader(loader);
        return error;
    }

    /* ensure even-ness of `num_blue_values' */
    priv.num_blue_values &= 0xFFFFFFFE;

    //#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT

    if (face.blend != null && face.blend.num_default_design_vector != 0 && face.blend.num_default_design_vector != face.blend.num_axis)
    {
        face.blend.num_default_design_vector = 0;
    }

    /* the following can happen for MM instances; we then treat the */
    /* font as a normal PS font                                     */
    if (face.blend != null && (face.blend.num_designs == 0 || face.blend.num_axis == 0))
        T1_Done_Blend(face);

    /* another safety check */
    if (face.blend != null)
    {
        for (var i = 0; i < face.blend.num_axis; i++)
        {
            if (face.blend.design_map[i].num_points == 0)
            {
                T1_Done_Blend(face);
                break;
            }
        }
    }

    if (face.blend != null)
    {
        if (face.len_buildchar > 0)
        {
            face.buildchar = CreateIntArray(face.len_buildchar);
        }
    }
    else
    {
        face.len_buildchar = 0;
    }

    //#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */

    /* now, propagate the subrs, charstrings, and glyphnames tables */
    /* to the Type1 data                                            */
    type1.num_glyphs = loader.num_glyphs;

    if (loader.subrs.init != null)
    {
        loader.subrs.init = null;
        type1.num_subrs   = loader.num_subrs;
        type1.subrs_block = loader.subrs.block;
        type1.subrs       = loader.subrs.elements;
        type1.subrs_len   = loader.subrs.lengths;
    }

    if (loader.charstrings.init == 0)
    {
        error = 3;
    }

    loader.charstrings.init  = 0;
    type1.charstrings_block = loader.charstrings.block;
    type1.charstrings       = loader.charstrings.elements;
    type1.charstrings_len   = loader.charstrings.lengths;

    /* we copy the glyph names `block' and `elements' fields; */
    /* the `lengths' field must be released later             */
    type1.glyph_names_block = loader.glyph_names.block;
    type1.glyph_names = loader.glyph_names.elements;

    for (var ii = 0; ii < type1.num_glyphs; ii++)
    {
        var s = "";
        var p = type1.glyph_names[ii];
        var indC = 0;
        while (true)
        {
            var _c = p.data[p.pos + indC];
            indC++;

            if (_c == 0)
                break;

            s += String.fromCharCode(_c);
        }
        type1.glyph_names[ii] = s;
    }

    loader.glyph_names.block = 0;
    loader.glyph_names.elements = 0;

    /* we must now build type1.encoding when we have a custom array */
    if (type1.encoding_type == 1)
    {
        /* OK, we do the following: for each element in the encoding  */
        /* table, look up the index of the glyph having the same name */
        /* the index is then stored in type1.encoding.char_index, and */
        /* the name to type1.encoding.char_name                       */

        var min_char = 0;
        var max_char = 0;

        var charcode = 0;
        for ( ; charcode < loader.encoding_table.max_elems; charcode++)
        {
            type1.encoding.char_index[charcode] = 0;
            type1.encoding.char_name[charcode] = ".notdef";

            var char_name = loader.encoding_table.elements[charcode];
            if (char_name != null)
            {
                for (var idx = 0; idx < type1.num_glyphs; idx++)
                {
                    var glyph_name = type1.glyph_names[idx];
                    if (_strncmp_data(char_name, glyph_name, glyph_name.length) == 0)
                    {
                        type1.encoding.char_index[charcode] = idx;
                        type1.encoding.char_name[charcode] = glyph_name;

                        /* Change min/max encoded char only if glyph name is */
                        /* not /.notdef                                      */
                        if (".notdef" != glyph_name)
                        {
                            if (charcode < min_char)
                                min_char = charcode;
                            if (charcode >= max_char)
                                max_char = charcode + 1;
                        }
                        break;
                    }
                }
            }
        }

        type1.encoding.code_first = min_char;
        type1.encoding.code_last  = max_char;
        type1.encoding.num_chars  = loader.num_chars;
    }

    t1_done_loader(loader);
    return error;
}

/******************************************************************************/
// tokens
/******************************************************************************/
var t1_keywords = new Array(45);
// PS_FontInfoRec
t1_keywords[0] = create_t1_field4("version", 3, 5, 1, function(obj, val, f) { obj.version = val}, undefined);
t1_keywords[1] = create_t1_field4("Notice", 3, 5, 1, function(obj, val, f) { obj.notice = val}, undefined);
t1_keywords[2] = create_t1_field4("FullName", 3, 5, 1, function(obj, val, f) { obj.full_name = val}, undefined);
t1_keywords[3] = create_t1_field4("FamilyName", 3, 5, 1, function(obj, val, f) { obj.family_name = val}, undefined);
t1_keywords[4] = create_t1_field4("Weight", 3, 5, 1, function(obj, val, f) { obj.weight = val}, undefined);
t1_keywords[5] = create_t1_field4("ItalicAngle", 3, 2, 1, function(obj, val, f) { obj.italic_angle = val}, undefined);
t1_keywords[6] = create_t1_field4("isFixedPitch", 3, 1, 1, function(obj, val, f) { obj.is_fixed_pitch = val}, undefined);
t1_keywords[7] = create_t1_field4("UnderlinePosition", 3, 2, 1, function(obj, val, f) { obj.underline_position = val}, undefined);
t1_keywords[8] = create_t1_field4("UnderlineThickness", 3, 2, 1, function(obj, val, f) { obj.underline_thickness = val}, undefined);

// PS_FontExtraRec
t1_keywords[9] = create_t1_field4("FSType", 2, 2, 1, function(obj, val, f) { obj.fs_type = val}, undefined);

// PS_PrivateRec
t1_keywords[10] = create_t1_field4("UniqueID", 4, 2, 1 | 2, function(obj, val, f) { obj.unique_id = val}, undefined);
t1_keywords[11] = create_t1_field4("lenIV", 4, 2, 2, function(obj, val, f) { obj.lenIV = val}, undefined);
t1_keywords[12] = create_t1_field4("LanguageGroup", 4, 2, 2, function(obj, val, f) { obj.language_group = val}, undefined);
t1_keywords[13] = create_t1_field4("password", 4, 2, 2, function(obj, val, f) { obj.password = val}, undefined);

t1_keywords[14] = create_t1_field4("BlueScale", 4, 4, 2, function(obj, val, f) { obj.blue_scale = val}, undefined);
t1_keywords[15] = create_t1_field4("BlueShift", 4, 2, 2, function(obj, val, f) { obj.blue_shift = val}, undefined);
t1_keywords[16] = create_t1_field4("BlueFuzz", 4, 2, 2, function(obj, val, f) { obj.blue_fuzz = val}, undefined);

t1_keywords[17] = create_t1_field5("BlueValues", 4, 8, 14, 2, function(obj, val, f) { obj.blue_values[f.offset] = val}, function(obj, val, f) { obj.num_blue_values = val});
t1_keywords[18] = create_t1_field5("OtherBlues", 4, 8, 10, 2, function(obj, val, f) { obj.other_blues[f.offset] = val}, function(obj, val, f) { obj.num_other_blues = val});
t1_keywords[19] = create_t1_field5("FamilyBlues", 4, 8, 14, 2, function(obj, val, f) { obj.family_blues[f.offset] = val}, function(obj, val, f) { obj.num_family_blues = val});
t1_keywords[20] = create_t1_field5("FamilyOtherBlues", 4, 8, 10, 2, function(obj, val, f) { obj.family_other_blues[f.offset] = val}, function(obj, val, f) { obj.num_family_other_blues = val});

t1_keywords[21] = create_t1_field5("StdHW", 4, 8, 1, 2, function(obj, val, f) { obj.standard_width[0] = val}, undefined);
t1_keywords[22] = create_t1_field5("StdVW", 4, 8, 1, 2, function(obj, val, f) { obj.standard_height[0] = val}, undefined);
t1_keywords[23] = create_t1_field5("MinFeature", 4, 8, 2, 2, function(obj, val, f) { obj.min_feature[f.offset] = val}, undefined);

t1_keywords[24] = create_t1_field5("StemSnapH", 4, 8, 12, 2, function(obj, val, f) { obj.snap_widths[f.offset] = val}, function(obj, val, f) { obj.num_snap_widths = val});
t1_keywords[25] = create_t1_field5("StemSnapV", 4, 8, 12, 2, function(obj, val, f) { obj.snap_heights[f.offset] = val}, function(obj, val, f) { obj.num_snap_heights = val});

t1_keywords[26] = create_t1_field4("ForceBold", 4, 1, 2, function(obj, val, f) { obj.force_bold = val}, undefined);

// T1_FontRec
t1_keywords[27] = create_t1_field4("FontName", 1, 6, 1, function(obj, val, f) { obj.font_name = val}, undefined);
t1_keywords[28] = create_t1_field4("PaintType", 1, 2, 1, function(obj, val, f) { obj.paint_type = val}, undefined);
t1_keywords[29] = create_t1_field4("FontType", 1, 2, 1, function(obj, val, f) { obj.font_type = val}, undefined);
t1_keywords[30] = create_t1_field4("StrokeWidth", 1, 3, 1, function(obj, val, f) { obj.stroke_width = val}, undefined);

// FT_BBox
t1_keywords[31] = create_t1_field4("FontBBox", 5, 7, 1, undefined, undefined);

// T1_FaceRec
t1_keywords[32] = create_t1_field4("NDV", 7, 2, 2, function(obj, val, f) { obj.ndv_idx = val}, undefined);
t1_keywords[33] = create_t1_field4("CDV", 7, 3, 2, function(obj, val, f) { obj.cdv_idx = val}, undefined);

// PS_BlendRec
t1_keywords[34] = create_t1_field5("CDV", 8, 3, 16, 1, function(obj, val, f) { obj.default_design_vector[f.offset] = val}, function(obj, val, f) { obj.num_default_design_vector = val});

// callbacks
t1_keywords[35] = create_t1_field("FontMatrix", 8, 10, t1_parse_font_matrix, 0, -1, 0, 0, 1, undefined, undefined);
t1_keywords[36] = create_t1_field("Encoding", 8, 10, t1_parse_encoding, 0, -1, 0, 0, 1, undefined, undefined);
t1_keywords[37] = create_t1_field("Subrs", 8, 10, t1_parse_subrs, 0, -1, 0, 0, 2, undefined, undefined);
t1_keywords[38] = create_t1_field("CharStrings", 8, 10, t1_parse_charstrings, 0, -1, 0, 0, 2, undefined, undefined);
t1_keywords[39] = create_t1_field("Private", 8, 10, t1_parse_private, 0, -1, 0, 0, 1, undefined, undefined);

t1_keywords[40] = create_t1_field("BlendDesignPositions", 8, 10, t1_parse_blend_design_positions, 0, -1, 0, 0, 1, undefined, undefined);
t1_keywords[41] = create_t1_field("BlendDesignMap", 8, 10, t1_parse_blend_design_map, 0, -1, 0, 0, 1, undefined, undefined);
t1_keywords[42] = create_t1_field("BlendAxisTypes", 8, 10, t1_parse_blend_axis_types, 0, -1, 0, 0, 1, undefined, undefined);
t1_keywords[43] = create_t1_field("WeightVector", 8, 10, t1_parse_weight_vector, 0, -1, 0, 0, 1, undefined, undefined);
t1_keywords[44] = create_t1_field("BuildCharArray", 8, 10, t1_parse_buildchar, 0, -1, 0, 0, 2, undefined, undefined);

/******************************************************************************/
// driver
/******************************************************************************/

function t1_get_glyph_name(face, glyph_index, buffer, buffer_max)
{
    return face.type1.glyph_names[glyph_index];
    //_mem_strcpyn1(buffer, face.type1.glyph_names[glyph_index], buffer_max);
    //return 0;
}

function t1_get_name_index(face, glyph_name)
{
    var _count = face.type1.num_glyphs;
    for (var i = 0; i < _count; i++)
    {
        if (face.type1.glyph_names[i] == glyph_name)
            return i;
    }
    return 0;
}

var t1_service_glyph_dict = new FT_Service_GlyphDictRec(t1_get_glyph_name, t1_get_name_index);

function t1_get_ps_name(face)
{
    return face.type1.font_name;
}
var t1_service_ps_name = new FT_Service_PsFontNameRec(t1_get_ps_name);

var t1_service_multi_masters = new FT_Service_MultiMastersRec(T1_Get_Multi_Master, T1_Set_MM_Design, T1_Set_MM_Blend, T1_Get_MM_Var, T1_Set_Var_Design);

function t1_ps_get_font_info(face)
{
    FT_Error = 0;
    return face.type1.font_info.CreateDublicate();
}
function t1_ps_get_font_extra(face)
{
    FT_Error = 0;
    return face.type1.font_extra.CreateDublicate();
}
function t1_ps_has_glyph_names(face)
{
    return 1;
}
function t1_ps_get_font_private(face)
{
    FT_Error = 0;
    return face.type1.private_dict;
}

function t1_ps_get_font_value(face, key, idx)
{
    var retval = -1;
    var value = null;
    var type1 = face.type1;

    switch (key)
    {
        case 0:
            value = type1.font_type;
            break;

        case 1:
            switch (idx)
            {
                case 0:
                    value = type1.font_matrix.xx;
                    break;
                case 1:
                    value = type1.font_matrix.xy;
                    break;
                case 2:
                    value = type1.font_matrix.yx;
                    break;
                case 3:
                    value = type1.font_matrix.yy;
                    break;
            }
            break;

        case 2:
            switch (idx)
            {
                case 0:
                    value = type1.font_bbox.xMin;
                    break;
                case 1:
                    value = type1.font_bbox.yMin;
                    break;
                case 2:
                    value = type1.font_bbox.xMax;
                    break;
                case 3:
                    value = type1.font_bbox.yMax;
                    break;
            }
            break;

        case 3:
            value = type1.paint_type;
            break;

        case 4:
            value = type1.font_name;
            break;

        case 5:
            value = type1.private_dict.unique_id;
            break;

        case 6:
            value = type1.num_glyphs;
            break;

        case 7:
            if (idx < type1.num_glyphs)
            {
                value = type1.glyph_names[idx];
            }
            break;

        case 8:
            if (idx < type1.num_glyphs)
            {
                value = type1.charstrings[idx];
            }
            break;

        case 9:
            value = type1.encoding_type;
            break;

        case 10:
            if (type1.encoding_type == 1 && idx < type1.encoding.num_chars)
            {
                value = type1.encoding.char_name[idx];
            }
            break;

        case 11:
            value = type1.num_subrs;
            break;

        case 12:
            if (idx < type1.num_subrs)
            {
                value = type1.subrs[idx];
            }
            break;

        case 13:
            value = type1.private_dict.standard_width[0];
            break;

        case 14:
            value = type1.private_dict.standard_height[0];
            break;

        case 15:
            value = type1.private_dict.num_blue_values;
            break;

        case 16:
            if (idx < type1.private_dict.num_blue_values)
            {
                value = type1.private_dict.blue_values[idx];
            }
            break;

        case 24:
            value = type1.private_dict.blue_scale;
            break;

        case 17:
            value = type1.private_dict.blue_fuzz;
            break;

        case 25:
            value = type1.private_dict.blue_shift;
            break;

        case 18:
            value = type1.private_dict.num_other_blues;
            break;

        case 19:
            if (idx < type1.private_dict.num_other_blues)
            {
                value = type1.private_dict.other_blues[idx];
            }
            break;

        case 20:
            value = type1.private_dict.num_family_blues;
            break;

        case 21:
            if (idx < type1.private_dict.num_family_blues)
            {
                value = type1.private_dict.family_blues[idx];
            }
            break;

        case 22:
            value = type1.private_dict.num_family_other_blues;
            break;

        case 23:
            if (idx < type1.private_dict.num_family_other_blues)
            {
                value = type1.private_dict.family_other_blues[idx];
            }
            break;

        case 26:
            value = type1.private_dict.num_snap_widths;
            break;

        case 27:
            if (idx < type1.private_dict.num_snap_widths)
            {
                value = type1.private_dict.snap_widths[idx];
            }
            break;

        case 28:
            value = type1.private_dict.num_snap_heights;
            break;

        case 29:
            if (idx < type1.private_dict.num_snap_heights)
            {
                value = type1.private_dict.snap_heights[idx];
            }
            break;

        case 31:
            value = type1.private_dict.round_stem_up;
            break;

        case 30:
            value = type1.private_dict.force_bold;
            break;

        case 32:
            value = type1.private_dict.min_feature[idx];
            break;

        case 33:
            value = type1.private_dict.lenIV;
            break;

        case 34:
            value = type1.private_dict.password;
            break;

        case 35:
            value= type1.private_dict.language_group;
            break;

        case 41:
            value = type1.font_info.is_fixed_pitch;
            break;

        case 42:
            value = type1.font_info.underline_position;
            break;

        case 43:
            value = type1.font_info.underline_thickness;
            break;

        case 44:
            value = type1.font_extra.fs_type;
            break;

        case 36:
            value = type1.font_info.version;
            break;

        case 37:
            value = type1.font_info.notice;
            break;

        case 38:
            value = type1.font_info.full_name;
            break;

        case 39:
            value = type1.font_info.family_name;
            break;

        case 40:
            value = type1.font_info.weight;
            break;

        case 45:
            value = type1.font_info.italic_angle;
            break;

        default:
            break;
    }

    return retval;
}

var t1_service_ps_info = new FT_Service_PsInfoRec(t1_ps_get_font_info, t1_ps_get_font_extra, t1_ps_has_glyph_names, t1_ps_get_font_private, t1_ps_get_font_value);
var t1_service_kerning = new FT_Service_KerningRec(T1_Get_Track_Kerning);

var t1_services = new Array(6);
t1_services[0] = new FT_ServiceDescRec(FT_SERVICE_ID_POSTSCRIPT_FONT_NAME,t1_service_ps_name);
t1_services[1] = new FT_ServiceDescRec(FT_SERVICE_ID_GLYPH_DICT,t1_service_glyph_dict);
t1_services[2] = new FT_ServiceDescRec(FT_SERVICE_ID_XF86_NAME,FT_XF86_FORMAT_TYPE_1);
t1_services[3] = new FT_ServiceDescRec(FT_SERVICE_ID_POSTSCRIPT_INFO,t1_service_ps_info);
t1_services[4] = new FT_ServiceDescRec(FT_SERVICE_ID_KERNING,t1_service_kerning);
t1_services[5] = new FT_ServiceDescRec(FT_SERVICE_ID_MULTI_MASTERS,t1_service_multi_masters);

function Get_Interface(driver, t1_interface)
{
    return ft_service_list_lookup(t1_services, t1_interface);
}

function Get_Kerning(face, left_glyph, right_glyph, kerning)
{
    kerning.x = 0;
    kerning.y = 0;

    if (face.afm_data != null)
        T1_Get_Kerning(face.afm_data, left_glyph, right_glyph, kerning);

    return 0;
}

function T1_Driver_Class()
{
    this.flags = 0x501;
    this.name = "type1";
    this.version = 0x10000;
    this.requires = 0x20000;

    this.module_interface = null;

    this.init = T1_Driver_Init;
    this.done = T1_Driver_Done;
    this.get_interface = Get_Interface;

    this.face_object_size = 0;
    this.size_object_size = 0;
    this.slot_object_size = 0;

    this.init_face = T1_Face_Init;
    this.done_face = T1_Face_Done;

    this.init_size = T1_Size_Init;
    this.done_size = T1_Size_Done;

    this.init_slot = T1_GlyphSlot_Init;
    this.done_slot = T1_GlyphSlot_Done;

    //#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    this.set_char_sizes = ft_stub_set_char_sizes;
    this.set_pixel_sizes = ft_stub_set_pixel_sizes;
    //#endif

    this.load_glyph = T1_Load_Glyph;

    this.get_kerning = Get_Kerning;
    this.attach_file = T1_Read_Metrics;
    this.get_advances = T1_Get_Advances;

    this.request_size = T1_Size_Request;
    this.select_size = null;
}

function T1_Driver()
{
    this.clazz = null;      // FT_Module_Class
    this.library = null;    // FT_Library
    this.memory = null;     // FT_Memory
    this.generic = null;    // FT_Generic

    this.clazz = new T1_Driver_Class();
    this.faces_list = [];
    this.extensions = null;
    this.glyph_loader = null;

    this.open_face = function(stream, face_index)
    {
        FT_Error = 0;
        var face = new T1_Face();
        var internal = new FT_Face_Internal();

        face.driver = this;
        face.memory = this.memory;
        face.stream = stream;

        //#ifdef FT_CONFIG_OPTION_INCREMENTAL
        face.internal = internal;
        face.internal.incremental_interface = null;
        //#endif

        var err1 = this.clazz.init_face(stream, face, face_index);

        if (err1 != 0)
        {
            face = null;
            FT_Error = err1;
            return null;
        }

        var err2 = find_unicode_charmap(face);
        if (err2 != 0 && err2 != 38)
        {
            face = null;
            FT_Error = err2;
            return null;
        }

		FT_Error = 0;
        return face;
    }
}

function create_t1_driver(library)
{
    var driver = new T1_Driver();
    driver.library = library;
    driver.memory = library.Memory;

    driver.clazz = new T1_Driver_Class();
    return driver;
}
var FT_Error = 0;
function FT_Library()
{
    this.Memory = null;
    this.generic = new FT_Generic();
    this.version_major = 2;
    this.version_minor = 4;
    this.version_patch = 8;

    this.modules = [];
    this.renderers = [];
    this.cur_renderer = null;
    this.auto_hinter = null;

    this.raster_pool_size = 16384;
    this.raster_pool = null;

    this.m_bUseCIDs = true;

    this.tt_hint_props = new LibraryHintingParams();

    // #ifdef subpixel
    //FT_LcdFilter             lcd_filter;
    //FT_Int                   lcd_extra;        /* number of extra pixels */
    //FT_Byte                  lcd_weights[7];   /* filter weights, if any */
    //FT_Bitmap_LcdFilterFunc  lcd_filter_func;  /* filtering callback     */
    // #endif

    //#ifdef FT_CONFIG_OPTION_PIC
    //FT_PIC_Container   pic_container;
    //#endif

    this.Init = function()
    {
        this.Memory = new FT_Memory();
        //this.raster_pool = this.Memory.Alloc(this.raster_pool_size);
        // теперь пул для каждого рендерера свой
        // и он хранится непосредственно в рендерере.
        // если не создавать постоянно рендереры - то смысл такой же. У нас так и есть.
        this.FT_Add_Default_Modules();
    }
    this.FT_Add_Module = function(module)
    {
        var clazz = module.clazz;
        if (clazz == null)
            return 6;

        var version_control = (this.version_major << 16 | this.version_minor);
        if (clazz.requires > version_control)
            return 4;

        var mod_count = this.modules.length;
        for (var i = 0; i < mod_count; i++)
        {
            var _module = this.modules[i];
            if (_module.clazz.name == clazz.name)
            {
                if (clazz.version < _module.clazz.version)
                    return 5;
                this.modules.splice(i,1);
                break;
            }
        }

        var error = 0;
        if ((clazz.flags & 2) != 0)
        {
            error = this.ft_add_renderer(module);
            if (0 != error)
            {
                //delete module;
                return error;
            }
        }
        if ((clazz.flags & 4) != 0)
        {
            this.auto_hinter = module;
        }
        if ((clazz.flags & 1) != 0)
        {
            if (0 == (clazz.flags & 512))
            {
                module.glyph_loader = new FT_GlyphLoader();
            }
        }

        if (null != clazz.init)
            clazz.init(module);

        this.modules[mod_count] = module;
        return error;
    }
    this.FT_Add_Default_Modules = function()
    {
        // drivers
        var driver_tt = create_tt_driver(this);
        var driver_cff = create_cff_driver(this);
        var driver_t1 = create_t1_driver(this);
        //var driver_cid = create_cid_driver(this);
        this.FT_Add_Module(driver_tt);
        this.FT_Add_Module(driver_cff);
        this.FT_Add_Module(driver_t1);
        //this.FT_Add_Module(driver_cid);

        // modules
        var mod_ps_names = create_psnames_module(this);
        var mod_psaux = create_psaux_module(this);
        var mod_sfnt = create_sfnt_module(this);
        this.FT_Add_Module(mod_ps_names);
        this.FT_Add_Module(mod_psaux);
        this.FT_Add_Module(mod_sfnt);

        // autohinter
        this.auto_hinter = null;

        // renderers
        var mod_rend1 = create_renderer_smooth_module(this);
        this.FT_Add_Module(mod_rend1);
    }
    this.ft_add_renderer = function(module)
    {
        var error = 0;
        var clazz = module.clazz;

        module.glyph_format = clazz.glyph_format;

        if ((clazz.glyph_format == 1869968492) && (clazz.raster_class.raster_new))
        {
            module.raster = new TRaster();
            error = clazz.raster_class.raster_new(this.Memory, module.raster);

            if (error != 0)
                return error;

            module.raster_render = clazz.raster_class.raster_render;
            module.render = clazz.render_glyph;
        }

        this.renderers[this.renderers.length] = module;

        this.ft_set_current_renderer();
        return error;
    }
    this.ft_set_current_renderer = function()
    {
        this.cur_renderer = null;
        var count_r = this.renderers.length;
        for (var i = 0; i < count_r; i++)
        {
            if (this.renderers[i].glyph_format == 1869968492)
            {
                this.cur_renderer = this.renderers[i];
                return;
            }
        }
    }
    this.FT_Open_Face = function(args, face_index)
    {
        var face = null;
        var external_stream = (args.stream && (args.flags & 0x02) != 0) ? true : false;
        if (external_stream === true)
        {
            var stream = args.stream;

            // пробегаем по всем драйверам - и ищем первый, который сможет открыть
            var dr_len = this.modules.length;
            for (var i = 0; i < dr_len; i++)
            {
                if (0 == (this.modules[i].clazz.flags & 1))
                    continue;

                var driver = this.modules[i];
                face = driver.open_face(stream, face_index);

                if (0 != FT_Error)
                {
                    //#ifdef FT_CONFIG_OPTION_MAC_FONTS
                    if (driver.clazz.name == "truetype" && ((FT_Error & 0xFF) == 142))
                    {
                        face = this.open_face_PS_from_sfnt_stream(stream, face_index);
                        if (FT_Error != 0)
                            return null;
                    }
                    //#endif
                }
                else
                {
                    break;
                }

                if ((FT_Error & 0xFF) != 2)
                {
                    if (((FT_Error & 0xFF) == 85) ||
                        ((FT_Error & 0xFF) == 81))
                    {
                        //#ifdef FT_CONFIG_OPTION_MAC_FONTS
                        face = this.load_mac_face(stream, face_index);
                        if (FT_Error == 0)
                            return face;
                        FT_Error = 2;
                        face = null;
                        return face;
                        //#endif
                    }
                }
            }

            if (null == face)
                return face;

            face.face_flags |= (1 << 10);
            face.driver.faces_list[face.driver.faces_list.length] = face;

            if (face_index >= 0)
            {
                var slot = FT_New_GlyphSlot(face);
                slot = null;
                if (FT_Error != 0)
                {
                    face = null;
                    return null;
                }

                /* finally, allocate a size object for the face */
                {
                    var size = FT_New_Size(face);
                    if (FT_Error != 0)
                    {
                        face = null;
                        return null;
                    }

                    face.size = size;
                }
            }

            /* some checks */

            if ((face.face_flags & 1) != 0)
            {
                if (face.height < 0)
                    face.height = -face.height;

                if ((face.face_flags & (1 << 5)) == 0)
                    face.max_advance_height = face.height;
            }

            if ((face.face_flags & (1 << 1)) != 0)
            {
                var _num = face.num_fixed_sizes;
                for (var i = 0; i < _num; i++)
                {
                    var bsize = face.available_sizes[i];

                    if (bsize.height < 0)
                        bsize.height = -bsize.height;
                    if (bsize.x_ppem < 0)
                        bsize.x_ppem = -bsize.x_ppem;
                    if (bsize.y_ppem < 0)
                        bsize.y_ppem = -bsize.y_ppem;
                }
            }

            /* initialize internal face data */
            {
                var internal = face.internal;

                internal.transform_matrix.xx = 0x10000;
                internal.transform_matrix.xy = 0;
                internal.transform_matrix.yx = 0;
                internal.transform_matrix.yy = 0x10000;

                internal.transform_delta.x = 0;
                internal.transform_delta.y = 0;
            }

            FT_Error = 0;
            return face;
        }
        // пока открываем только из уже созданного стрима
        FT_Error = 6;
        return null;
    }

    this.open_face_PS_from_sfnt_stream = function(stream, face_index)
    {
    }
    this.load_mac_face = function(stream, face_index)
    {
    }

    this.FT_Get_Module_Interface = function(name)
    {
        var module = this.FT_Get_Module(name);
        return (null != module) ? module.clazz.module_interface : null;
    }
    this.FT_Get_Module = function(name)
    {
        var count = this.modules.length;
        for (var i = 0; i < count; i++)
        {
            if (this.modules[i].clazz.name == name)
                return this.modules[i];
        }
        return null;
    }
}

// API
function FT_Select_Size(face, strike_index)
{
    if (!face || (face.face_flags & 2) == 0)
        return 35;

    if (strike_index < 0 || strike_index >= face.num_fixed_sizes)
        return 6;

    var clazz = face.driver.clazz;
    if (clazz.select_size)
    {
        return clazz.select_size(face.size, strike_index);
    }

    FT_Select_Metrics(face, strike_index);
    return 0;
}

function FT_Select_Metrics(face, strike_index)
{
    var metrics = face.size.metrics;
    var bsize   = face.available_sizes[strike_index];

    metrics.x_ppem = (FT_Common.IntToUInt(bsize.x_ppem + 32) >>> 6) & 0xFFFF;
    metrics.y_ppem = (FT_Common.IntToUInt(bsize.y_ppem + 32) >>> 6) & 0xFFFF;

    if ((face.face_flags & 1) != 0)
    {
        metrics.x_scale = FT_DivFix(bsize.x_ppem, face.units_per_EM);
        metrics.y_scale = FT_DivFix(bsize.y_ppem, face.units_per_EM);

        ft_recompute_scaled_metrics(face, metrics);
    }
    else
    {
        metrics.x_scale     = 1 << 16;
        metrics.y_scale     = 1 << 16;
        metrics.ascender    = bsize.y_ppem;
        metrics.descender   = 0;
        metrics.height      = bsize.height << 6;
        metrics.max_advance = bsize.x_ppem;
    }
}

function ft_recompute_scaled_metrics(face, metrics)
{
    metrics.ascender    = FT_PIX_CEIL(FT_MulFix(face.ascender, metrics.y_scale));
    metrics.descender   = FT_PIX_FLOOR(FT_MulFix(face.descender, metrics.y_scale));
    metrics.height      = FT_PIX_ROUND(FT_MulFix(face.height, metrics.y_scale));
    metrics.max_advance = FT_PIX_ROUND(FT_MulFix(face.max_advance_width, metrics.x_scale));
}

function FT_Request_Size(face, req)
{
    var strike_index = 0;

    if (!face)
        return 35;

    if (!req || req.width < 0 || req.height < 0 || req.type >= 5)
        return 6;

    var clazz = face.driver.clazz;

    if (clazz.request_size)
    {
        return clazz.request_size(face.size, req);
    }

    if (((face.face_flags & 1) == 0) && ((face.face_flags & 2) != 0))
    {
        FT_Error = 0;
        strike_index = FT_Match_Size(face, req, 0);
        var error = FT_Error;
        FT_Error = 0;
        if (error != 0)
            return error;

        return FT_Select_Size(face, strike_index);
    }

    FT_Request_Metrics(face, req);
    return 0;
}

function FT_Request_Metrics(face, req)
{
    var metrics = face.size.metrics;

    if ((face.face_flags & 1) != 0)
    {
        var w = 0, h = 0, scaled_w = 0, scaled_h = 0;

        switch (req.type)
        {
            case 0:
                w = h = face.units_per_EM;
                break;

            case 1:
                w = h = face.ascender - face.descender;
                break;

            case 2:
                w = face.bbox.xMax - face.bbox.xMin;
                h = face.bbox.yMax - face.bbox.yMin;
                break;

            case 3:
                w = face.max_advance_width;
                h = face.ascender - face.descender;
                break;

            case 4:
                metrics.x_scale = req.width;
                metrics.y_scale = req.height;
                if (metrics.x_scale == 0)
                    metrics.x_scale = metrics.y_scale;
                else if (metrics.y_scale == 0)
                    metrics.y_scale = metrics.x_scale;

                scaled_w = FT_MulFix(face.units_per_EM, metrics.x_scale);
                scaled_h = FT_MulFix(face.units_per_EM, metrics.y_scale);

                metrics.x_ppem = (FT_Common.IntToUInt(scaled_w + 32) >>> 6) & 0xFFFF;
                metrics.y_ppem = (FT_Common.IntToUInt(scaled_h + 32) >>> 6) & 0xFFFF;

                ft_recompute_scaled_metrics( face, metrics );
                return;

            case 5:
                break;
        }

        /* to be on the safe side */
        if (w < 0)
            w = -w;

        if (h < 0)
            h = -h;

        scaled_w = FT_REQUEST_WIDTH(req);
        scaled_h = FT_REQUEST_HEIGHT(req);

        if (req.width != 0)
        {
            metrics.x_scale = FT_DivFix(scaled_w, w);

            if (req.height != 0)
            {
                metrics.y_scale = FT_DivFix(scaled_h, h);

                if (req.type == 3)
                {
                    if (metrics.y_scale > metrics.x_scale)
                        metrics.y_scale = metrics.x_scale;
                    else
                        metrics.x_scale = metrics.y_scale;
                }
            }
            else
            {
                metrics.y_scale = metrics.x_scale;
                scaled_h = FT_MulDiv(scaled_w, h, w);
            }
        }
        else
        {
            metrics.x_scale = metrics.y_scale = FT_DivFix(scaled_h, h);
            scaled_w = FT_MulDiv(scaled_h, w, h);
        }

        if (req.type != 0)
        {
            scaled_w = FT_MulFix(face.units_per_EM, metrics.x_scale);
            scaled_h = FT_MulFix(face.units_per_EM, metrics.y_scale);
        }

        metrics.x_ppem = (FT_Common.IntToUInt(scaled_w + 32) >>> 6) & 0xFFFF;
        metrics.y_ppem = (FT_Common.IntToUInt(scaled_h + 32) >>> 6) & 0xFFFF;

        ft_recompute_scaled_metrics(face, metrics);
    }
    else
    {
        metrics.x_ppem = 0;
        metrics.y_ppem = 0;

        metrics.ascender = 0;
        metrics.descender = 0;
        metrics.height = 0;
        metrics.max_advance = 0;

        metrics.x_scale = 1 << 16;
        metrics.y_scale = 1 << 16;
    }
}

function FT_REQUEST_WIDTH(req)
{
    return (req.horiResolution != 0) ? parseInt((req.width * req.horiResolution + 36) / 72) : req.width;
}

function FT_REQUEST_HEIGHT(req)
{
    return (req.vertResolution != 0) ? parseInt((req.height * req.vertResolution + 36) / 72) : req.height;
}

function FT_Match_Size(face, req, ignore_width)
{
    if ((face.face_flags & 2) == 0)
    {
        FT_Error = 35;
        return 0;
    }

    if (req.type != 0)
    {
        FT_Error = 7;
        return 0;
    }

    var w = FT_REQUEST_WIDTH(req);
    var h = FT_REQUEST_HEIGHT(req);

    if (req.width != 0 && req.height == 0)
        h = w;
    else if (req.width == 0 && req.height != 0)
        w = h;

    w = FT_PIX_ROUND(w);
    h = FT_PIX_ROUND(h);

    var num_fs = face.num_fixed_sizes;
    for (var i = 0; i < num_fs; i++)
    {
        var bsize = face.available_sizes[i];

        if (h != FT_PIX_ROUND(bsize.y_ppem))
            continue;

        if (w == FT_PIX_ROUND(bsize.x_ppem) || (ignore_width != 0))
        {
            FT_Error = 0;
            return i;
        }
    }

    FT_Error = 23;
    return 0;
}

function FT_Set_Char_Size(face, char_width, char_height, horz_resolution, vert_resolution)
{
    var req = new FT_Size_RequestRec();

    if (0 == char_width)
        char_width = char_height;
    else if (0 == char_height)
        char_height = char_width;

    if (0 == horz_resolution)
        horz_resolution = vert_resolution;
    else if (0 == vert_resolution)
        vert_resolution = horz_resolution;

    if (char_width < 64)
        char_width = 64;
    if (char_height < 64)
        char_height = 64;

    if (0 == horz_resolution)
        horz_resolution = vert_resolution = 72;

    req.type           = 0;
    req.width          = char_width;
    req.height         = char_height;
    req.horiResolution = horz_resolution;
    req.vertResolution = vert_resolution;

    return FT_Request_Size(face, req);
}

function FT_Set_Pixel_Sizes(face, pixel_width, pixel_height)
{
    var req = new FT_Size_RequestRec();

    if (pixel_width == 0)
        pixel_width = pixel_height;
    else if (pixel_height == 0)
        pixel_height = pixel_width;

    if (pixel_width < 1)
        pixel_width = 1;
    if (pixel_height < 1)
        pixel_height = 1;

    /* use `>=' to avoid potential compiler warning on 16bit platforms */
    if (pixel_width >= 0xFFFF)
        pixel_width = 0xFFFF;
    if (pixel_height >= 0xFFFF)
        pixel_height = 0xFFFF;

    req.type           = 0;
    req.width          = pixel_width << 6;
    req.height         = pixel_height << 6;
    req.horiResolution = 0;
    req.vertResolution = 0;

    return FT_Request_Size(face, req);
}

function FT_Get_First_Char(face)
{
    var result = {gindex:0,char_code:0};
    if (face && face.charmap && face.num_glyphs != 0)
    {
        result.gindex = FT_Get_Char_Index(face, 0);
        if (result.gindex == 0 || result.gindex >= face.num_glyphs)
            result = FT_Get_Next_Char(face, 0);
    }
    return result;
}

function FT_Get_Next_Char(face, charcode)
{
    var result = {gindex:0,char_code:0};
    if (face && face.charmap && face.num_glyphs != 0)
    {
        var code = charcode;
        var cmap = face.charmap;
        var _cmap = __FT_CMapRec(cmap);

        do
        {
            var _clazz = _cmap.clazz.clazz;
            if (undefined == _clazz)
                _clazz = _cmap.clazz;

            result = _clazz.char_next(cmap, code);
            code = result.char_code;
        } while (result.gindex >= face.num_glyphs);

        result.char_code = (result.gindex == 0) ? 0 : code;
    }
    return result;
}

function FT_Get_Char_Index(face, charcode)
{
    var result = 0;
    if (face && face.charmap)
    {
        var _clazz = __FT_CMapRec(face.charmap).clazz;
        if (undefined != _clazz.clazz)
            _clazz = _clazz.clazz;

        result = _clazz.char_index(face.charmap, charcode);
    }
    return result;
}

function FT_Get_Charmap_Index(charmap)
{
    if (!charmap || !charmap.face)
        return -1;

    var i = 0;
    for (; i < charmap.face.num_charmaps; i++)
        if (charmap.face.charmaps[i] == charmap)
            break;

    //#ifdef FT_MAX_CHARMAP_CACHEABLE
    if (i > 15)
        return -i;
    //#endif
    return i;
}

function FT_Set_Charmap(face, cmap)
{
    if (!face)
        return 35;

    var len = face.num_charmaps;
    if (0 == len)
        return 38;

	if (FT_Get_CMap_Format(cmap) == 14)
		return 6;

    for (var i = 0; i < len; i++)
    {
        if (face.charmaps[i] == cmap)
        {
            //#ifdef FT_MAX_CHARMAP_CACHEABLE
            if (i > 15)
                continue;
            //#endif
            face.charmap = face.charmaps[i];
            return 0;
        }
    }
    return 6;
}

function FT_Get_CMap_Format(cmap)
{
    var charmap = __FT_CharmapRec(cmap);
    if (!charmap || !charmap.face)
        return -1;

    var service = FT_FACE_FIND_SERVICE(charmap.face, "tt-cmaps");

    if (service == null)
        return -1;

    var cmap_info = new TT_CMapInfo();
    if (0 != service.get_cmap_info(cmap, cmap_info))
        return -1;
    
    return cmap_info.format;
}


function FT_Glyph_Get_CBox(glyph, bbox_mode, acbox)
{
    acbox.xMin = acbox.yMin = acbox.xMax = acbox.yMax = 0;

    if (!glyph || !glyph.clazz)
        return;

    var clazz = glyph.clazz;
    if (!clazz.glyph_bbox)
        return;

    clazz.glyph_bbox(glyph, acbox);

    if (bbox_mode == 1 || bbox_mode == 3)
    {
        acbox.xMin = FT_PIX_FLOOR(acbox.xMin);
        acbox.yMin = FT_PIX_FLOOR(acbox.yMin);
        acbox.xMax = FT_PIX_CEIL(acbox.xMax);
        acbox.yMax = FT_PIX_CEIL(acbox.yMax);
    }

    if (bbox_mode == 2 || bbox_mode == 3)
    {
        acbox.xMin >>= 6;
        acbox.yMin >>= 6;
        acbox.xMax >>= 6;
        acbox.yMax >>= 6;
    }
}

function FT_Get_Glyph(slot)
{
    FT_Error = 0;
    var clazz = null;

    if (!slot)
        return 37;

    if (slot.format == 1651078259)
        clazz = ft_bitmap_glyph_class;
    else if (slot.format == 1869968492)
        clazz = ft_outline_glyph_class;
    else
    {
        var render = FT_Lookup_Renderer(slot.library, slot.format);
        if (render)
            clazz = render.glyph_class;
    }

    if (!clazz)
    {
        FT_Error = 18;
        return null;
    }

    var glyph = ft_new_glyph(slot.library, clazz);
    if (FT_Error != 0)
        return null;

    glyph.advance.x = slot.advance.x << 10;
    glyph.advance.y = slot.advance.y << 10;

    FT_Error = clazz.glyph_init(glyph, slot);

    if (FT_Error != 0)
    {
        FT_Done_Glyph(glyph);
        glyph = null;
    }
    else
        return glyph;

    return null;
}

function FT_Done_Glyph(glyph)
{
    return 0;
}

function FT_Get_Name_Index(face, glyph_name)
{
    if (face && ((face.face_flags & 512) != 0))
    {
        var service = face.internal.services.service_GLYPH_DICT;
        if (null != service)
            service = FT_FACE_FIND_SERVICE(face, "glyph-dict");

        if (service && service.name_index)
            return service.name_index(face, glyph_name);
    }
    return 0;
}
function FT_Get_Glyph_Name(face, glyph_index, buffer, buffer_max)
{
    if (face && (glyph_index <= face.num_glyphs) && ((face.face_flags & 512) != 0))
    {
        var service = face.internal.services.service_GLYPH_DICT;
        if (null != service)
            service = FT_FACE_FIND_SERVICE(face, "glyph-dict");

        if (service && service.get_name)
            return service.get_name(face, glyph_index, buffer, buffer_max);
    }
    return 0;
}

function FT_Get_X11_Font_Format(face)
{
    if (face)
        return FT_FACE_FIND_SERVICE(face, "xf86-driver-name");
    return null;
}

function FT_Lookup_Renderer(library, format)
{
    var r = library.renderers;
    var c = r.length;

    for (var i = 0; i < c; i++)
    {
        if (r[i].glyph_format == format)
            return r[i];
    }

    return null;
}

function FT_Set_Renderer(library, renderer)
{
    if (!library)
        return 33;

    if (!renderer)
        return 6;

    if (renderer.glyph_format == 1869968492)
        library.cur_renderer = renderer;

    return 0;
}

function ft_lookup_glyph_renderer(slot)
{
    var library = slot.library;
    var res = library.cur_renderer;

    if (!res || (res.glyph_format != slot.format))
        res = FT_Lookup_Renderer(library, slot.format);

    return res;
}

function ft_set_current_renderer(library)
{
    library.cur_renderer = FT_Lookup_Renderer(library, 1869968492);
}



function FT_Load_Glyph(face, glyph_index, load_flags)
{
    if (!face || !face.size || !face.glyph)
        return 35;

    var slot = face.glyph;
    ft_glyphslot_clear(slot);

    var driver  = face.driver;
    var library = driver.library;
    var hinter  = library.auto_hinter;
    var autohint = false;

    /* resolve load flags dependencies */
    if (load_flags & 1024)
        load_flags |= (1 | 2048);

    if (load_flags & 1)
    {
        load_flags |= (2 | 8);
        load_flags &= ~4;
    }

    // if (hinter && ...){}
    // TODO:

    if (true === autohint)
    {
        // TODO:
    }
    else
    {
        var error = driver.clazz.load_glyph(slot, face.size, glyph_index, load_flags);
        if (error != 0)
            return error;

        if (slot.format == 1869968492)
        {
            /* check that the loaded outline is correct */
            error = FT_Outline_Check(slot.outline);
            if (error != 0)
                return error;

            //#ifdef GRID_FIT_METRICS
            if (0 == (load_flags & 2))
                ft_glyphslot_grid_fit_metrics( slot, ((load_flags & 16) != 0) ? true : false);
            //#endif
        }
    }

    /* compute the advance */
    if (0 != (load_flags & 16))
    {
        slot.advance.x = 0;
        slot.advance.y = slot.metrics.vertAdvance;
    }
    else
    {
        slot.advance.x = slot.metrics.horiAdvance;
        slot.advance.y = 0;
    }

    /* compute the linear advance in 16.16 pixels */
    if ((load_flags & 8192) == 0 && (0 != (face.face_flags & 1)))
    {
        var metrics = face.size.metrics;

        /* it's tricky! */
        slot.linearHoriAdvance = FT_MulDiv(slot.linearHoriAdvance, metrics.x_scale, 64);
        slot.linearVertAdvance = FT_MulDiv(slot.linearVertAdvance, metrics.y_scale, 64);
    }

    if ((load_flags & 2048) == 0)
    {
        var internal = face.internal;

        /* now, transform the glyph image if needed */
        if (internal.transform_flags != 0)
        {
            /* get renderer */
            var renderer = ft_lookup_glyph_renderer(slot);
            if (renderer != null)
                error = renderer.clazz.transform_glyph(renderer, slot, internal.transform_matrix, internal.transform_delta);
            else if (slot.format == 1869968492)
            {
                /* apply `standard' transformation if no renderer is available */
                if ((internal.transform_flags & 1) != 0)
                    FT_Outline_Transform(slot.outline, internal.transform_matrix);

                if ((internal.transform_flags & 2) != 0)
                    FT_Outline_Translate(slot.outline, internal.transform_delta.x, internal.transform_delta.y);
            }

            /* transform advance */
            FT_Vector_Transform(slot.advance, internal.transform_matrix);
        }
    }

    /* do we need to render the image now? */
    if ((error == 0) && (slot.format != 1651078259) && (slot.format != 1668246896) && ((load_flags & 4) != 0))
    {
        var mode = FT_LOAD_TARGET_MODE(load_flags);

        if (mode == 0 && (load_flags & 4096))
            mode = 2;

        error = FT_Render_Glyph(slot, mode);
    }
    return error;
}

function FT_Load_Char(face, char_code, load_flags)
{
    var glyph_index = 0;

    if ( !face )
        return 35;

    glyph_index = char_code;
    if (face.charmap)
        glyph_index = FT_Get_Char_Index(face, char_code);

    return FT_Load_Glyph(face, glyph_index, load_flags);
}

function FT_Set_Transform(face, matrix, delta)
{
    if (!face)
        return;

    var internal = face.internal;
    internal.transform_flags = 0;

    var m = internal.transform_matrix;
    if (!matrix)
    {
        m.xx = 0x10000;
        m.xy = 0;
        m.yx = 0;
        m.yy = 0x10000;
    }
    else
    {
        m.xx = matrix.xx;
        m.xy = matrix.xy;
        m.yx = matrix.yx;
        m.yy = matrix.yy;
    }

    /* set transform_flags bit flag 0 if `matrix' isn't the identity */
    if ((m.xy | m.yx) != 0 || m.xx != 0x10000 || m.yy != 0x10000)
        internal.transform_flags |= 1;

    var d = internal.transform_delta;
    if (!delta)
    {
        d.x = 0;
        d.y = 0;
    }
    else
    {
        d.x = delta.x;
        d.y = delta.y;
    }

    /* set transform_flags bit flag 1 if `delta' isn't the null vector */
    if ((d.x | d.y) != 0)
        internal.transform_flags |= 2;
}

function FT_Render_Glyph(slot, render_mode)
{
    if (!slot || !slot.face)
        return 6;

    var library = slot.library;
    return FT_Render_Glyph_Internal(library, slot, render_mode);
}

function FT_Render_Glyph_Internal(library, slot, render_mode)
{
    var error = 0;
    var renderer = null;
    var update = false;

    /* if it is already a bitmap, no need to do anything */
    switch (slot.format)
    {
        case 1651078259:   /* already a bitmap, don't do anything */
            break;

        default:
        {
            /* small shortcut for the very common case */
            if (slot.format == 1869968492)
            {
                renderer = library.cur_renderer;
            }
            else
            {
                renderer = FT_Lookup_Renderer(library, slot.format);
            }

            error = 7;
            while (renderer != null)
            {
                error = renderer.render(renderer, slot, render_mode, null);
                if ((error == 0) || ((error & 0xFF) != 19))
                    break;

                renderer = FT_Lookup_Renderer(library, slot.format);
                update   = true;
            }
            if (error == 0 && update && renderer)
                FT_Set_Renderer(library, renderer);
        }
    }

    return error;
}

function FT_Get_Kerning(face, left_glyph, right_glyph, kern_mode, akerning)
{
    var error = 0;

    if (!face)
        return 35;

    if (!akerning)
        return 6;

    var driver = face.driver;

    akerning.x = 0;
    akerning.y = 0;

    if (driver.clazz.get_kerning)
    {
        error = driver.clazz.get_kerning(face, left_glyph, right_glyph, akerning);
        if (error == 0)
        {
            if (kern_mode != 2)
            {
                akerning.x = FT_MulFix(akerning.x, face.size.metrics.x_scale);
                akerning.y = FT_MulFix(akerning.y, face.size.metrics.y_scale);

                if (kern_mode != 1)
                {
                    if (face.size.metrics.x_ppem < 25)
                        akerning.x = FT_MulDiv(akerning.x, face.size.metrics.x_ppem, 25);
                    if (face.size.metrics.y_ppem < 25)
                        akerning.y = FT_MulDiv(akerning.y, face.size.metrics.y_ppem, 25);

                    akerning.x = FT_PIX_ROUND(akerning.x);
                    akerning.y = FT_PIX_ROUND(akerning.y);
                }
            }
        }
    }

    return error;
}

function FT_New_GlyphSlot(face)
{
    if (!face || !face.driver)
        return 6;

    var slot = null;
    var _slot = null;

    if (face.driver.clazz.name == "type1")
    {
        _slot = new T1_GlyphSlotRec();
        slot = _slot.root;
    }
    else
    {
        _slot = new FT_GlyphSlot();
        slot = _slot;
    }

    slot.face = face;
    FT_Error = ft_glyphslot_init(slot);
    if (FT_Error != 0)
    {
        ft_glyphslot_done(slot);
        return null;
    }

    slot.next  = face.glyph;
    face.glyph = slot;
    return slot;
}

function FT_GlyphLoader_New(memory)
{
    var loader = new FT_GlyphLoader();
    loader.memory = memory;
    return loader;
}

function ft_glyphslot_done(slot)
{
    return 0;
}

function FT_New_Size(face)
{
    if (!face)
        return 35;

    if (!face.driver)
        return 34;

    var size = null;
    var clazz  = face.driver.clazz;
    
    FT_Error = 0;
    if (clazz.init_size)
    {
        size = clazz.init_size();
    }
    size.face = face;

    if (FT_Error == 0)
    {
        face.sizes_list[face.sizes_list.length] = size;
        return size;
    }

    return null;
}
function FT_CMap_New(clazz, init_data, charmap)
{
    FT_Error = 0;
    
    if (clazz == null || charmap == null || charmap.face == null)
    {
        FT_Error = 6;
        return null;
    }

    var _clazz = clazz.clazz;
    var face = charmap.face;
    var cmap = null;

    if (undefined != clazz.format)
    {
        switch (clazz.format)
        {
            case 4:
                cmap = new TT_CMap4Rec();
                break;
            case 12:
                cmap = new TT_CMap12Rec();
                break;
            case 13:
                cmap = new TT_CMap13Rec();
                break;
            case 14:
                cmap = new TT_CMap14Rec();
                break;
            default:
                cmap = new TT_CMapRec();
                break;
        }
    }
    else
    {
        switch (clazz.size)
        {
            case 101:
            case 102:
                cmap = new CFF_CMapStdRec();
                break;
            default:
                cmap = new TT_CMapRec();
        }
    }

    var cmap_ = __FT_CMapRec(cmap);
    if (undefined == _clazz)
        _clazz = clazz;

    if (null != cmap)
    {
        var charmap_= cmap_.charmap;
        charmap_.face = charmap.face;
        charmap_.encoding = charmap.encoding;
        charmap_.platform_id = charmap.platform_id;
        charmap_.encoding_id = charmap.encoding_id;

        cmap_.clazz = clazz;
        if (clazz.init != 0)
        {
            var error = _clazz.init(cmap, init_data);
            if (error != 0)
            {
                FT_Error = error;
                cmap = null;
                cmap_ = null;
                return null;
            }
        }
        if (null == face.charmaps)
            face.charmaps = new Array(1);
        face.charmaps[face.num_charmaps++] = cmap;
    }

    return cmap;
}

  //--------------------------------------------------------export----------------------------------------------------
  window['AscFonts'] = window['AscFonts'] || {};
  window['AscFonts'].FT_Common = FT_Common;
  window['AscFonts'].FT_Stream = FT_Stream;
  window['AscFonts'].g_memory = g_memory;
  window['AscFonts'].FT_Get_Sfnt_Table = FT_Get_Sfnt_Table;
  window['AscFonts'].FT_BBox = FT_BBox;
  window['AscFonts'].FT_Matrix = FT_Matrix;
  window['AscFonts'].FT_Open_Args = FT_Open_Args;
  window['AscFonts'].__FT_CharmapRec = __FT_CharmapRec;
  window['AscFonts'].FT_Outline_Decompose = FT_Outline_Decompose;
  window['AscFonts'].FT_Library = FT_Library;
  window['AscFonts'].FT_Set_Char_Size = FT_Set_Char_Size;
  window['AscFonts'].FT_Get_Char_Index = FT_Get_Char_Index;
  window['AscFonts'].FT_Set_Charmap = FT_Set_Charmap;
  window['AscFonts'].FT_Glyph_Get_CBox = FT_Glyph_Get_CBox;
  window['AscFonts'].FT_Get_Glyph = FT_Get_Glyph;
  window['AscFonts'].FT_Done_Glyph = FT_Done_Glyph;
  window['AscFonts'].FT_Load_Glyph = FT_Load_Glyph;
  window['AscFonts'].FT_Set_Transform = FT_Set_Transform;
  window['AscFonts'].FT_Render_Glyph = FT_Render_Glyph;
  window['AscFonts'].raster_memory = raster_memory;
  window['AscFonts'].FT_Get_Charmap_Index = FT_Get_Charmap_Index;
  window['AscFonts'].FT_Vector = FT_Vector;
  window['AscFonts'].FT_Get_Kerning = FT_Get_Kerning;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

// Import
var FT_Common = AscFonts.FT_Common;
var FT_Stream = AscFonts.FT_Stream;
var g_memory = AscFonts.g_memory;

    var FontStyle =
    {
        FontStyleRegular:    0,
        FontStyleBold:       1,
        FontStyleItalic:     2,
        FontStyleBoldItalic: 3,
        FontStyleUnderline:  4,
        FontStyleStrikeout:  8
    };

var charA = "A".charCodeAt(0);
var charZ = "Z".charCodeAt(0);
var chara = "a".charCodeAt(0);
var charz = "z".charCodeAt(0);
var char0 = "0".charCodeAt(0);
var char9 = "9".charCodeAt(0);
var charp = "+".charCodeAt(0);
var chars = "/".charCodeAt(0);

function DecodeBase64Char(ch)
{
    if (ch >= charA && ch <= charZ)
        return ch - charA + 0;
    if (ch >= chara && ch <= charz)
        return ch - chara + 26;
    if (ch >= char0 && ch <= char9)
        return ch - char0 + 52;
    if (ch == charp)
        return 62;
    if (ch == chars)
        return 63;
    return -1;
}

var b64_decode = [];
(function(){
    var i;
    for (i = charA; i <= charZ; i++)
        b64_decode[i] = i - charA + 0;
    for (i = chara; i <= charz; i++)
        b64_decode[i] = i - chara + 26;
    for (i = char0; i <= char9; i++)
        b64_decode[i] = i - char0 + 52;
})();
b64_decode[charp] = 62;
b64_decode[chars] = 63;

function CreateFontData2(szSrc, dstLen)
{
    var srcLen = szSrc.length;
    var nWritten = 0;

    if (dstLen === undefined)
        dstLen = srcLen;

    var pointer = g_memory.Alloc(dstLen);
    var stream = new FT_Stream(pointer.data, dstLen);
    stream.obj = pointer.obj;

    var dstPx = stream.data;
    var index = 0;

    if (window.chrome)
    {
        while (index < srcLen)
        {
            var dwCurr = 0;
            var i;
            var nBits = 0;
            for (i=0; i<4; i++)
            {
                if (index >= srcLen)
                    break;
                var nCh = DecodeBase64Char(szSrc.charCodeAt(index++));
                if (nCh == -1)
                {
                    i--;
                    continue;
                }
                dwCurr <<= 6;
                dwCurr |= nCh;
                nBits += 6;
            }

            dwCurr <<= 24-nBits;
            for (i=0; i<nBits/8; i++)
            {
                dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
                dwCurr <<= 8;
            }
        }
    }
    else
    {
        var p = b64_decode;
        while (index < srcLen)
        {
            var dwCurr = 0;
            var i;
            var nBits = 0;
            for (i=0; i<4; i++)
            {
                if (index >= srcLen)
                    break;
                var nCh = p[szSrc.charCodeAt(index++)];
                if (nCh == undefined)
                {
                    i--;
                    continue;
                }
                dwCurr <<= 6;
                dwCurr |= nCh;
                nBits += 6;
            }

            dwCurr <<= 24-nBits;
            for (i=0; i<nBits/8; i++)
            {
                dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
                dwCurr <<= 8;
            }
        }
    }

    return stream;
}

function CreateFontData3(szSrc)
{
    var srcLen = szSrc.length;
    var nWritten = 0;

    var pointer = g_memory.Alloc(srcLen);
    var stream = new FT_Stream(pointer.data, srcLen);
    stream.obj = pointer.obj;

    var dstPx = stream.data;
    var index = 0;

    while (index < srcLen)
    {
        dstPx[index] = (szSrc.charCodeAt(index) & 0xFF);
        index++;
    }

    return stream;
}

function CreateFontData4(szSrc)
{
    var srcLen = szSrc.length;
    var nWritten = 0;

    var index = 0;
    var dst_len = "";
    while (true)
    {
        var _c = szSrc.charCodeAt(index);
        if (_c == ";".charCodeAt(0))
            break;

        dst_len += String.fromCharCode(_c);
        index++;
    }

    index++;
    var dstLen = parseInt(dst_len);

    var pointer = g_memory.Alloc(dstLen);
    var stream = new FT_Stream(pointer.data, dstLen);
    stream.obj = pointer.obj;

    var dstPx = stream.data;

    if (window.chrome)
    {
        while (index < srcLen)
        {
            var dwCurr = 0;
            var i;
            var nBits = 0;
            for (i=0; i<4; i++)
            {
                if (index >= srcLen)
                    break;
                var nCh = DecodeBase64Char(szSrc.charCodeAt(index++));
                if (nCh == -1)
                {
                    i--;
                    continue;
                }
                dwCurr <<= 6;
                dwCurr |= nCh;
                nBits += 6;
            }

            dwCurr <<= 24-nBits;
            for (i=0; i<nBits/8; i++)
            {
                dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
                dwCurr <<= 8;
            }
        }
    }
    else
    {
        var p = b64_decode;
        while (index < srcLen)
        {
            var dwCurr = 0;
            var i;
            var nBits = 0;
            for (i=0; i<4; i++)
            {
                if (index >= srcLen)
                    break;
                var nCh = p[szSrc.charCodeAt(index++)];
                if (nCh == undefined)
                {
                    i--;
                    continue;
                }
                dwCurr <<= 6;
                dwCurr |= nCh;
                nBits += 6;
            }

            dwCurr <<= 24-nBits;
            for (i=0; i<nBits/8; i++)
            {
                dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
                dwCurr <<= 8;
            }
        }
    }

    return stream;
}

//----------------- FONT_MAP ----------------------------------------
var FD_UNKNOWN_CHARSET = 3;

function FD_FontInfo()
{
    this.Name       = "";
    this.IndexR     = -1;
    this.IndexI     = -1;
    this.IndexB     = -1;
    this.IndexBI    = -1;
}

function FD_FontDictionary()
{
    this.FONTS_DICT_ASCII_NAMES_COUNT = 0;
    this.FD_Ascii_Names = [];

    this.FD_Ascii_Names_Offsets = null;
    if (typeof(Int32Array) != 'undefined' && !window.opera)
        this.FD_Ascii_Names_Offsets = new Int32Array(256);
    else
        this.FD_Ascii_Names_Offsets = new Array(256);

    for (var i = 0; i < 256; i++)
        this.FD_Ascii_Names_Offsets[i] = -1;

    this.FONTS_DICT_UNICODE_NAMES_COUNT = 0;
    this.FD_Unicode_Names = [];

    this.FONTS_DICT_ASCII_FONTS_COUNT = 0;
    this.FD_Ascii_Files = [];

    // шрифты в массиве this.FD_Ascii_Font_Like_Names - в порядке важности.
    this.FD_Ascii_Font_Like_Names = [
        ["Cambria Math", "Asana Math", "XITS Math", "Latin Modern"],
        ["OpenSymbol"],
        ["Arial", "Liberation Sans", "Helvetica", "Nimbus Sans L"],
        ["Times New Roman", "Liberation Serif"],
        ["Courier New", "Liberation Mono"],
        ["Segoe", "Segoe UI"],
        ["Cambria", "Caladea"]
    ];
    this.FD_Ascii_Font_Like_Main = {
        "Cambria Math"  : 0,
        "Asana Math"    : 0,
        "XITS Math"     : 0,
        "Latin Modern"  : 0,

        "Symbol"        : 1,
        "Wingdings"     : 1,

        "Arial"             : 2,
        "Liberation Sans"   : 2,
        "Helvetica"         : 2,
        "Nimbus Sans L"     : 2,

        "Times New Roman"   : 3,
        "Liberation Serif"  : 3,

        "Courier New"       : 4,
        "Liberation Mono"   : 4,

        "Segoe"             : 5,
        "Segoe UI"          : 5,

        "Cambria"           : 6,
        "Caladea"           : 6
    };

    this.ChangeGlyphsMap = {
        "Symbol" : { Name : "OpenSymbol", IsSymbolSrc : true, MapSrc : [0xB7, 0xA8], MapDst : [0xE12C, 0xE442] },
        "Wingdings" : { Name : "OpenSymbol", IsSymbolSrc : true, MapSrc : [0x76, 0xD8, 0xA7, 0xFC, 0x71], MapDst : [0xE441, 0xE25F, 0xE46F, 0xE330, 0x2751] }
    };
	
	this.MainUnicodeRanges = {
		"48" : 3000,
		"49" : 3000,
		"50" : 3000,
		
		"55" : 3000,
		"59" : 3000,
		
		"28" : 3000,
		
		"13" : 3000,
		"63" : 3000,
		"67" : 3000
	};
}

FD_FontDictionary.prototype =
{
    Init : function()
    {
        var _base64_data = " ";
        var _ft_stream = CreateFontData2(_base64_data);
        var _file_stream = new AscCommon.FileStream(_ft_stream.data, _ft_stream.size);
        var i = 0;

        this.FONTS_DICT_ASCII_NAMES_COUNT = _file_stream.GetLong();
        for (i = 0; i < this.FONTS_DICT_ASCII_NAMES_COUNT; i++)
        {
            var _nameInfo = new FD_FontInfo();
            var _name_len = _file_stream.GetLong();
            _nameInfo.Name = _file_stream.GetString1(_name_len);
            _nameInfo.IndexR = _file_stream.GetLong();
            _nameInfo.IndexI = _file_stream.GetLong();
            _nameInfo.IndexB = _file_stream.GetLong();
            _nameInfo.IndexBI = _file_stream.GetLong();
            this.FD_Ascii_Names.push(_nameInfo);
        }

        for (i = 0; i < 256; i++)
        {
            this.FD_Ascii_Names_Offsets[i] = _file_stream.GetLong();
        }

        this.FONTS_DICT_UNICODE_NAMES_COUNT = _file_stream.GetLong();
        for (i = 0; i < this.FONTS_DICT_UNICODE_NAMES_COUNT; i++)
        {
            var _nameInfo = new FD_FontInfo();
            _nameInfo.Name = this.GetString16(_file_stream);
            _nameInfo.IndexR = _file_stream.GetLong();
            _nameInfo.IndexI = _file_stream.GetLong();
            _nameInfo.IndexB = _file_stream.GetLong();
            _nameInfo.IndexBI = _file_stream.GetLong();
            this.FD_Unicode_Names.push(_nameInfo);
        }

        this.FONTS_DICT_ASCII_FONTS_COUNT = _file_stream.GetLong();
        for (i = 0; i < this.FONTS_DICT_ASCII_FONTS_COUNT; i++)
        {
            var _nameInfo = new CFontSelect();
            _nameInfo.fromStream(_file_stream, false);
            this.FD_Ascii_Files.push(_nameInfo);
        }
    },

    GetString16 : function(_file_stream)
    {
        var _len = _file_stream.GetLong();
        var _ret = this.GetUTF16_fromUTF8(_file_stream.data, _file_stream.cur, _len);
        _file_stream.cur += _len;
        return _ret;
    },

    GetUTF16_fromUnicodeChar : function(code)
    {
        if (code < 0x10000)
            return String.fromCharCode(code);
        else
        {
            code -= 0x10000;
            return String.fromCharCode(0xD800 | ((code >> 10) & 0x03FF)) + String.fromCharCode(0xDC00 | (code & 0x03FF));
        }
    },

    GetUTF16_fromUTF8 : function(pBuffer, start, count)
    {
        var _res = "";

        var lIndex = start;
        var end = start + count;
        var val = 0;
        while (lIndex < end)
        {
            var byteMain = pBuffer[lIndex];
            if (0x00 == (byteMain & 0x80))
            {
                // 1 byte
                _res += this.GetUTF16_fromUnicodeChar(byteMain);
                ++lIndex;
            }
            else if (0x00 == (byteMain & 0x20))
            {
                // 2 byte
                val = (((byteMain & 0x1F) << 6) |
                    (pBuffer[lIndex + 1] & 0x3F));
                _res += this.GetUTF16_fromUnicodeChar(val);
                lIndex += 2;
            }
            else if (0x00 == (byteMain & 0x10))
            {
                // 3 byte
                val = (((byteMain & 0x0F) << 12) |
                    ((pBuffer[lIndex + 1] & 0x3F) << 6) |
                    (pBuffer[lIndex + 2] & 0x3F));

                _res += this.GetUTF16_fromUnicodeChar(val);
                lIndex += 3;
            }
            else if (0x00 == (byteMain & 0x08))
            {
                // 4 byte
                val = (((byteMain & 0x07) << 18) |
                    ((pBuffer[lIndex + 1] & 0x3F) << 12) |
                    ((pBuffer[lIndex + 2] & 0x3F) << 6) |
                    (pBuffer[lIndex + 3] & 0x3F));

                _res += this.GetUTF16_fromUnicodeChar(val);
                lIndex += 4;
            }
            else if (0x00 == (byteMain & 0x04))
            {
                // 5 byte
                val = (((byteMain & 0x03) << 24) |
                    ((pBuffer[lIndex + 1] & 0x3F) << 18) |
                    ((pBuffer[lIndex + 2] & 0x3F) << 12) |
                    ((pBuffer[lIndex + 3] & 0x3F) << 6) |
                    (pBuffer[lIndex + 4] & 0x3F));

                _res += this.GetUTF16_fromUnicodeChar(val);
                lIndex += 5;
            }
            else
            {
                // 6 byte
                val = (((byteMain & 0x01) << 30) |
                    ((pBuffer[lIndex + 1] & 0x3F) << 24) |
                    ((pBuffer[lIndex + 2] & 0x3F) << 18) |
                    ((pBuffer[lIndex + 3] & 0x3F) << 12) |
                    ((pBuffer[lIndex + 4] & 0x3F) << 6) |
                    (pBuffer[lIndex + 5] & 0x3F));

                _res += this.GetUTF16_fromUnicodeChar(val);
                lIndex += 5;
            }
        }

        return _res;
    },

    CorrectParamsFromDictionary : function(oFormat)
    {
        if (undefined == oFormat.wsName)
            return false;

        var nNameLen = oFormat.wsName.length;
        if (nNameLen == 0)
            return false;

        var bIsAscii = true;
        var i = 0;
        for (i = 0; i < nNameLen; ++i)
        {
            var _char_code = oFormat.wsName.charCodeAt(i);
            if (_char_code > 255 || _char_code < 0)
            {
                bIsAscii = false;
                break;
            }
        }

        var pFont = null;

        if (bIsAscii)
        {
            var nStartIndex = this.FD_Ascii_Names_Offsets[oFormat.wsName.charCodeAt(0)];

            if (-1 != nStartIndex)
            {
                var nIndex = -1;
                for (i = nStartIndex; i < this.FONTS_DICT_ASCII_NAMES_COUNT; i++)
                {
                    if (this.FD_Ascii_Names[i].Name == oFormat.wsName)
                    {
                        nIndex = i;
                        break;
                    }
                }

                if (nIndex != -1)
                {
                    var pRec = this.FD_Ascii_Names[nIndex];
                    var nFontIndex = -1;

                    var nStyle = 0;
                    if (oFormat.bItalic === true)
                        nStyle |= 1;
                    if (oFormat.bBold === true)
                        nStyle |= 2;

                    switch (nStyle)
                    {
                        case 1:
                        {
                            if (pRec.IndexI != -1)
                                nFontIndex = pRec.IndexI;
                            else if (pRec.IndexBI != -1)
                                nFontIndex = pRec.IndexBI;
                            else if (pRec.IndexR != -1)
                                nFontIndex = pRec.IndexR;
                            else
                                nFontIndex = pRec.IndexB;
                            break;
                        }
                        case 2:
                        {
                            if (pRec.IndexB != -1)
                                nFontIndex = pRec.IndexB;
                            else if (pRec.IndexBI != -1)
                                nFontIndex = pRec.IndexBI;
                            else if (pRec.IndexR != -1)
                                nFontIndex = pRec.IndexR;
                            else
                                nFontIndex = pRec.IndexI;
                            break;
                        }
                        case 3:
                        {
                            if (pRec.IndexBI != -1)
                                nFontIndex = pRec.IndexBI;
                            else if (pRec.IndexB != -1)
                                nFontIndex = pRec.IndexB;
                            else if (pRec.IndexI != -1)
                                nFontIndex = pRec.IndexI;
                            else
                                nFontIndex = pRec.IndexR;
                            break;
                        }
                        case 0:
                        default:
                        {
                            if (pRec.IndexR != -1)
                                nFontIndex = pRec.IndexR;
                            else if (pRec.IndexI != -1)
                                nFontIndex = pRec.IndexI;
                            else if (pRec.IndexB != -1)
                                nFontIndex = pRec.IndexB;
                            else
                                nFontIndex = pRec.IndexBI;
                            break;
                        }
                    }

                    if (nFontIndex != -1)
                        pFont = this.FD_Ascii_Files[nFontIndex];
                }
            }
        }
        else
        {
            var nIndex = -1;
            for (i = 0; i < this.FONTS_DICT_UNICODE_NAMES_COUNT; i++)
            {
                if (this.FD_Unicode_Names[i].Name == oFormat.wsName)
                {
                    nIndex = i;
                    break;
                }
            }

            if (nIndex != -1)
            {
                var pRec = this.FD_Unicode_Names[nIndex];
                var nFontIndex = -1;

                var nStyle = 0;
                if (oFormat.bItalic === true)
                    nStyle |= 1;
                if (oFormat.bBold === true)
                    nStyle |= 2;

                switch (nStyle)
                {
                    case 1:
                    {
                        if (pRec.IndexI != -1)
                            nFontIndex = pRec.IndexI;
                        else if (pRec.IndexBI != -1)
                            nFontIndex = pRec.IndexBI;
                        else if (pRec.IndexR != -1)
                            nFontIndex = pRec.IndexR;
                        else
                            nFontIndex = pRec.IndexB;
                        break;
                    }
                    case 2:
                    {
                        if (pRec.IndexB != -1)
                            nFontIndex = pRec.IndexB;
                        else if (pRec.IndexBI != -1)
                            nFontIndex = pRec.IndexBI;
                        else if (pRec.IndexR != -1)
                            nFontIndex = pRec.IndexR;
                        else
                            nFontIndex = pRec.IndexI;
                        break;
                    }
                    case 3:
                    {
                        if (pRec.IndexBI != -1)
                            nFontIndex = pRec.IndexBI;
                        else if (pRec.IndexB != -1)
                            nFontIndex = pRec.IndexB;
                        else if (pRec.IndexI != -1)
                            nFontIndex = pRec.IndexI;
                        else
                            nFontIndex = pRec.IndexR;
                        break;
                    }
                    case 0:
                    default:
                    {
                        if (pRec.IndexR != -1)
                            nFontIndex = pRec.IndexR;
                        else if (pRec.IndexI != -1)
                            nFontIndex = pRec.IndexI;
                        else if (pRec.IndexB != -1)
                            nFontIndex = pRec.IndexB;
                        else
                            nFontIndex = pRec.IndexBI;
                        break;
                    }
                }

                if (nFontIndex != -1)
                    pFont = this.FD_Ascii_Files[nFontIndex];
            }
        }

        if (null == pFont)
            return false;

        oFormat.wsName = pFont.m_wsFontName;

        // fixed
        oFormat.bFixedWidth = (pFont.m_bIsFixed == 1 ? true : false);

        // panose
        oFormat.pPanose = pFont.m_aPanose;

        // ranges
        oFormat.ulRange1 = pFont.m_ulUnicodeRange1;
        oFormat.ulRange2 = pFont.m_ulUnicodeRange2;
        oFormat.ulRange3 = pFont.m_ulUnicodeRange3;
        oFormat.ulRange4 = pFont.m_ulUnicodeRange4;
        oFormat.ulCodeRange1 = pFont.m_ulCodePageRange1;
        oFormat.ulCodeRange2 = pFont.m_ulCodePageRange2;

        oFormat.usWeight = pFont.m_usWeigth;
        oFormat.usWidth = pFont.m_usWidth;

        oFormat.shAvgCharWidth  = pFont.m_shAvgCharWidth;
        oFormat.shAscent        = pFont.m_shAscent;
        oFormat.shDescent       = pFont.m_shDescent;
        oFormat.shXHeight       = pFont.m_shXHeight;
        oFormat.shCapHeight     = pFont.m_shCapHeight;

        return true;
    },

    GetFontIndex : function(oSelect, oList, DefaultIndex, isName0)
    {
        this.CorrectParamsFromDictionary(oSelect);

        var nMinIndex   = 0; // Номер шрифта в списке с минимальным весом
        var nMinPenalty = 0; // Минимальный вес

        var nDefPenalty = 2147483647;

        var nFontsCount = oList.length;
        for ( var nIndex = 0; nIndex < nFontsCount; nIndex++ )
        {
            var nCurPenalty = oList[nIndex].GetPenalty(oSelect, isName0, this.MainUnicodeRanges);

            if ( 0 == nIndex )
            {
                nMinIndex   = 0;
                nMinPenalty = nCurPenalty;
            }
            else if ( nCurPenalty < nMinPenalty )
            {
                nMinIndex   = nIndex;
                nMinPenalty = nCurPenalty;
            }

            if ( undefined != DefaultIndex && nIndex == DefaultIndex )
            {
                nDefPenalty = nCurPenalty;
            }

            // Нашелся шрифт, удовлетворяющий всем параметрам, дальше искать нет смысла
            if ( 0 == nCurPenalty )
                break;
        }

        if ( undefined != DefaultIndex && nDefPenalty == nMinPenalty )
            nMinIndex = DefaultIndex;

		if (undefined == DefaultIndex)
			return nMinIndex;
			
        return oList[nMinIndex];
    },

    CheckLikeFonts : function(sFontName, sReqName)
    {
        var _index = this.FD_Ascii_Font_Like_Main[sReqName];
        if (undefined === _index)
            return false;

        var _arr = this.FD_Ascii_Font_Like_Names[_index];
        var _len = _arr.length;
        for (var i = 0; i < _len; i++)
        {
            // здесь точное равенство!
            if (_arr[i] == sFontName)
                return true;
        }
        return false;
    }
};

//-------------------------------------------------------------------

function CFontSelectFormat()
{
    this.wsName         = undefined;
    this.wsAltName      = undefined;

    this.wsFamilyClass  = undefined;
    this.sFamilyClass   = undefined;

    this.bBold          = undefined;
    this.bItalic        = undefined;

    this.bFixedWidth    = undefined;

    this.pPanose        = undefined;

    this.ulRange1       = undefined;
    this.ulRange2       = undefined;
    this.ulRange3       = undefined;
    this.ulRange4       = undefined;
    this.ulCodeRange1   = undefined;
    this.ulCodeRange2   = undefined;

    this.usWeight       = undefined;
    this.usWidth        = undefined;

    this.nFontFormat    = undefined;
    this.unCharset      = undefined;

    this.shAvgCharWidth = undefined;
    this.shAscent       = undefined;
    this.shDescent      = undefined;
    this.shLineGap      = undefined;
    this.shXHeight      = undefined;
    this.shCapHeight    = undefined;
}

// класс для подбора шрифтов
function CFontSelect()
{
    this.m_wsFontName   = "";

    this.m_wsFontPath   = "";
    this.m_lIndex       = 0;

    this.m_bBold    = false;
    this.m_bItalic  = false;
    this.m_bIsFixed = false;

    this.m_aPanose  = null;

    if (typeof(Int8Array) != 'undefined' && !window.opera)
    {
        this.m_aPanose = new Int8Array(10);
    }
    else
    {
        this.m_aPanose = new Array(10);
    }
    this.m_ulUnicodeRange1 = 0;
    this.m_ulUnicodeRange2 = 0;
    this.m_ulUnicodeRange3 = 0;
    this.m_ulUnicodeRange4 = 0;

    this.m_ulCodePageRange1 = 0;
    this.m_ulCodePageRange2 = 0;

    this.m_usWeigth = 0;
    this.m_usWidth  = 0;

    this.m_sFamilyClass = 0;
    this.m_eFontFormat  = 0;

    this.m_shAvgCharWidth   = 0;
    this.m_shAscent         = 0;
    this.m_shDescent        = 0;
    this.m_shLineGap        = 0;
    this.m_shXHeight        = 0;
    this.m_shCapHeight      = 0;
}
CFontSelect.prototype =
{
    fromStream : function(fs, bIsDictionary)
    {
        // name
        var _len = fs.GetLong();

        if (bIsDictionary === false)
            this.m_wsFontName = fs.GetString1(_len);
        else
            this.m_wsFontName = fs.GetString(_len >> 1);

        if (bIsDictionary !== false)
        {
            _len = fs.GetLong();
            this.m_wsFontPath = fs.GetString(_len >> 1);

            if (undefined === window["AscDesktopEditor"])
            {
                // удаляем все, кроме имени файла
                var _found1 = this.m_wsFontPath.lastIndexOf("/");
                var _found2 = this.m_wsFontPath.lastIndexOf("\\");
                var _found = Math.max(_found1, _found2);

                if (0 <= _found)
                    this.m_wsFontPath = this.m_wsFontPath.substring(_found + 1);
            }
            else
            {
                this.m_wsFontPath = this.m_wsFontPath.replace(/\\\\/g, "\\");
                this.m_wsFontPath = this.m_wsFontPath.replace(/\\/g, "/");
            }
        }

        this.m_lIndex = fs.GetLong();

        this.m_bItalic  = (1 == fs.GetLong());
        this.m_bBold    = (1 == fs.GetLong());
        this.m_bIsFixed = (1 == fs.GetLong());

        var _panose_len = 10;
        if (bIsDictionary !== false)
            _panose_len = fs.GetLong(); // 10

        for (var i = 0; i < _panose_len; i++)
            this.m_aPanose[i] = fs.GetUChar();

        this.m_ulUnicodeRange1 = fs.GetULong();
        this.m_ulUnicodeRange2 = fs.GetULong();
        this.m_ulUnicodeRange3 = fs.GetULong();
        this.m_ulUnicodeRange4 = fs.GetULong();

        this.m_ulCodePageRange1 = fs.GetULong();
        this.m_ulCodePageRange2 = fs.GetULong();

        this.m_usWeigth = fs.GetUShort();
        this.m_usWidth  = fs.GetUShort();

        this.m_sFamilyClass = FT_Common.UShort_To_Short(fs.GetUShort());
        this.m_eFontFormat  = FT_Common.UShort_To_Short(fs.GetUShort());

        this.m_shAvgCharWidth   = FT_Common.UShort_To_Short(fs.GetUShort());
        this.m_shAscent         = FT_Common.UShort_To_Short(fs.GetUShort());
        this.m_shDescent        = FT_Common.UShort_To_Short(fs.GetUShort());
        this.m_shLineGap        = FT_Common.UShort_To_Short(fs.GetUShort());
        this.m_shXHeight        = FT_Common.UShort_To_Short(fs.GetUShort());
        this.m_shCapHeight      = FT_Common.UShort_To_Short(fs.GetUShort());
    },

    GetStyle : function()
    {
        if (this.m_bBold && this.m_bItalic)
            return 3;
        else if (this.Bold)
            return 1;
        else if (this.m_bItalic)
            return 2;
        else
            return 0;
    },

    GetPenalty : function(oSelect, isName0, _main_ranges)
    {
        var nCurPenalty = 0;

        if (undefined !== oSelect.pPanose)
        {
            nCurPenalty += this.GetPanosePenalty(oSelect.pPanose);
        }

        if (true)
        {
            if (undefined !== oSelect.ulRange1 &&
                undefined !== oSelect.ulRange2 &&
                undefined !== oSelect.ulRange3 &&
                undefined !== oSelect.ulRange4 &&
                undefined !== oSelect.ulCodeRange1 &&
                undefined !== oSelect.ulCodeRange2)
            {
                nCurPenalty += this.GetSigPenalty(oSelect, nCurPenalty >= 1000 ? 50 : 10, 10, _main_ranges);
            }
        }

        var unCharset = FD_UNKNOWN_CHARSET;
        if (undefined !== oSelect.unCharset)
            unCharset = oSelect.unCharset;

        if (undefined !== oSelect.bFixedWidth)
            nCurPenalty += this.GetFixedPitchPenalty(oSelect.bFixedWidth);

        var nNamePenalty = 0;
        if (oSelect.wsName !== undefined && oSelect.wsAltName !== undefined)
        {
            nNamePenalty += Math.min(this.GetFaceNamePenalty(oSelect.wsName), this.GetFaceNamePenalty(oSelect.wsAltName));
        }
        else if (oSelect.wsName !== undefined)
            nNamePenalty += this.GetFaceNamePenalty(oSelect.wsName);
        else if (oSelect.wsAltName !== undefined)
            nNamePenalty += this.GetFaceNamePenalty(oSelect.wsAltName);

        if (true === isName0 && 0 == nNamePenalty)
            return 0;

        nCurPenalty += nNamePenalty;

        if (undefined != oSelect.usWidth)
            nCurPenalty += this.GetWidthPenalty(oSelect.usWidth);

        if (undefined !== oSelect.usWeight)
            nCurPenalty += this.GetWeightPenalty(oSelect.usWeight);

        if (undefined !== oSelect.bBold)
            nCurPenalty += this.GetBoldPenalty(oSelect.bBold);

        if (undefined !== oSelect.bItalic)
            nCurPenalty += this.GetItalicPenalty(oSelect.bItalic);

        if (undefined !== oSelect.wsFamilyClass)
            nCurPenalty += this.GetFamilyUnlikelyPenalty(oSelect.wsFamilyClass);
        else if (undefined !== oSelect.sFamilyClass)
            nCurPenalty += this.GetFamilyUnlikelyPenalty1(oSelect.sFamilyClass);

        nCurPenalty += this.GetCharsetPenalty(unCharset);

        if (undefined !== oSelect.shAvgCharWidth)
            nCurPenalty += this.GetAvgWidthPenalty(oSelect.shAvgCharWidth);

        if (undefined !== oSelect.shAscent)
            nCurPenalty += this.GetAscentPenalty(oSelect.shAscent);

        if (undefined !== oSelect.shDescent)
            nCurPenalty += this.GetDescentPenalty(oSelect.shDescent);

        if (undefined !== oSelect.shLineGap)
            nCurPenalty += this.GetLineGapPenalty(oSelect.shLineGap);

        if (undefined !== oSelect.shXHeight)
            nCurPenalty += this.GetXHeightPenalty(oSelect.shXHeight);

        if (undefined !== oSelect.shCapHeight)
            nCurPenalty += this.GetCapHeightPenalty(oSelect.shCapHeight);

        return nCurPenalty;
    },

    // penalty detect functions
    GetPanosePenalty : function(pReqPanose)
    {
        var nPenalty = 0;
        for (var nIndex = 0; nIndex < 10; nIndex++)
        {
            if (this.m_aPanose[nIndex] != pReqPanose[nIndex] && 0 != pReqPanose[nIndex])
            {
                var nKoef = Math.abs(this.m_aPanose[nIndex] - pReqPanose[nIndex]);
                switch(nIndex)
                {
                    case 0: nPenalty += 1000 * nKoef; break;
                    case 1: nPenalty += 100  * nKoef; break;
                    case 2: nPenalty += 100  * nKoef; break;
                    case 3: nPenalty += 100  * nKoef; break;
                    case 4: nPenalty += 100  * nKoef; break;
                    case 5: nPenalty += 100  * nKoef; break;
                    case 6: nPenalty += 100  * nKoef; break;
                    case 7: nPenalty += 100  * nKoef; break;
                    case 8: nPenalty += 100  * nKoef; break;
                    case 9: nPenalty += 100  * nKoef; break;
                }
            }
        }

        return nPenalty;
    },

    GetSigPenalty : function(format, dRangeWeight, dRangeWeightSuferflouous, _main_ranges)
    {
        var dPenalty = 0;

        // Для начала просматриваем сколько вообще различных пространств надо.
        // Исходя из их общего количества, находим вес 1 пропущеного пространства.
        var arrCandidate = ((typeof(Int8Array) != 'undefined' && !window.opera)) ? new Uint8Array(192) : new Array(192);
        var arrRequest = ((typeof(Int8Array) != 'undefined' && !window.opera)) ? new Uint8Array(192) : new Array(192);

        for (var i = 0; i < 192; i++)
        {
            arrCandidate[i] = 0;
            arrRequest[i] = 0;
        }

        var nRangesCount = 0; // Количество необходимых пространств
        var nAddCount    = 0; // количество дополнительных(ненужных) пространств у кандидата

        var ulCandRanges = [this.m_ulUnicodeRange1, this.m_ulUnicodeRange2, this.m_ulUnicodeRange3, this.m_ulUnicodeRange4,
            this.m_ulCodePageRange1, this.m_ulCodePageRange2];
        var ulReqRanges = [format.ulRange1, format.ulRange2, format.ulRange3, format.ulRange4,
            format.ulCodeRange1, format.ulCodeRange2];

        var nIndex = 0;
        for (var nIndex = 0; nIndex < 6; nIndex++)
        {
            for (var nBitCount = 0, nBit = 1; nBitCount < 32; nBitCount++, nBit *= 2)
            {
                var bReqAdd = false;

                if ( (ulReqRanges[nIndex] & nBit) != 0 )
                {
                    arrRequest[ nIndex * 32 + nBitCount ] = 1;
                    nRangesCount++;
                    bReqAdd = true;
                }

                if ( (ulCandRanges[nIndex] & nBit) != 0 )
                {
                    arrCandidate[ nIndex * 32 + nBitCount ] = 1;
                    if ( !bReqAdd )
                        nAddCount++;
                }
            }
        }

        if ( 0 == nRangesCount )
            return 0;

        //double dRangeWeight = 1;//1000.0 / nRangesCount;
		
        for (nIndex = 0; nIndex < 192; nIndex++)
        {
            if (1 == arrRequest[nIndex] && 0 == arrCandidate[nIndex])
            {
				if (undefined !== _main_ranges && undefined !== _main_ranges["" + nIndex])
					dPenalty += Math.max(_main_ranges["" + nIndex], dRangeWeight);
				else
					dPenalty += dRangeWeight;
			}
            else if (dRangeWeightSuferflouous != 0 && 0 == arrRequest[nIndex] && 1 == arrCandidate[nIndex])
                dPenalty += dRangeWeightSuferflouous;
        }

        return dPenalty;
    },

    GetFixedPitchPenalty : function(bReqFixed)
    {
        var nPenalty = 0;

        // Если запрашивается моноширинный, а кандидат не моноширинный, то вес 15000
        // Если запрашивается не моноширинный, а кандидат моноширинный, то вес 350
        if ( bReqFixed && !this.m_bIsFixed )
            nPenalty = 15000;
        if ( !bReqFixed && this.m_bIsFixed )
            nPenalty = 350;

        return nPenalty;
    },

    GetFaceNamePenalty : function(sReqName)
    {
        // На MSDN написано, что если имена не совпадают, то вес 10000.
        // Мы будем сравнивать сколько совпало символов у запрашиваемого
        // имени и с именем кандидата, без учета решистра, пробелов, запятых
        // и тире.

        /*
         TODO:
         sCandName.Remove(' '); sReqName.Remove(' ');
         sCandName.Remove(','); sReqName.Remove(',');
         sCandName.Remove('-'); sReqName.Remove('-');

         sCandName.MakeLower(); sReqName.MakeLower();
         */

        if ( 0 == sReqName.length )
            return 0;

        if ( 0 == this.m_wsFontName.length )
            return 10000;

        if ( sReqName == this.m_wsFontName )
            return 0;

        if (-1 != sReqName.indexOf(this.m_wsFontName) || -1 != this.m_wsFontName.indexOf(sReqName))
        {
			if (g_fontApplication.g_fontDictionary.CheckLikeFonts(this.m_wsFontName, sReqName))
				return 700;
			return 1000;
		}

        if (g_fontApplication.g_fontDictionary.CheckLikeFonts(this.m_wsFontName, sReqName))
            return 1000;

        return this.CheckEqualFonts2(sReqName, this.m_wsFontName);
    },

    GetWidthPenalty : function(usReqWidth)
    {
        // Penalty * width difference (Penalty = 50)
        return Math.abs(this.m_usWidth - usReqWidth) * 50;
    },

    GetWeightPenalty : function(usReqWeight)
    {
        // Penalty * ( weight difference / 10 )  (Penalty = 3)
        return (3 * ( Math.abs(this.m_usWeigth - usReqWeight) / 10));
    },

    GetItalicPenalty : function(bReqItalic)
    {
        // Penalty = 4
        if ( this.m_bItalic != bReqItalic )
            return 4;
        return 0;
    },

    GetBoldPenalty : function(bReqBold)
    {
        // SmallPenalty
        // Penalty = 1
        if ( this.m_bBold != bReqBold )
            return 1;
        return 0;
    },

    GetFamilyUnlikelyPenalty1 : function(nReqFamilyClass)
    {
        // Requested a roman/modern/swiss family, but the candidate is
        // decorative/script. Or requested decorative/script, and the
        // candidate is roman/modern/swiss. Penalty = 50.

        var nReqClassID  = nReqFamilyClass  >> 8;
        var nCandClassID = this.m_sFamilyClass >> 8;

        if ( 0 == nReqClassID ) // Unknown
            return 0;

        if ( 0 == nCandClassID ) // Unknown
            return 50;

        if ( ( nReqClassID <= 8 && nCandClassID > 8 ) || ( nReqClassID > 8 && nCandClassID <= 8 ) )
            return 50;

        return 0;
    },

    GetFamilyUnlikelyPenalty : function(sReqFamilyClass)
    {
        // Requested a roman/modern/swiss family, but the candidate is
        // decorative/script. Or requested decorative/script, and the
        // candidate is roman/modern/swiss. Penalty = 50.

        var nCandClassID = this.m_sFamilyClass >> 8;

        //sReqFamilyClass.MakeLower(); TODO:
        if ("any" == sReqFamilyClass || "unknown" == sReqFamilyClass)
            return 0;
        else if (0 == nCandClassID)
            return 50;
        else if ((("swiss" == sReqFamilyClass || "roman" == sReqFamilyClass || "modern" == sReqFamilyClass) && nCandClassID > 8) ||
                    (("decorative" == sReqFamilyClass || "script" == sReqFamilyClass) && nCandClassID <= 8))
            return 50;

        return 0;
    },

    GetCharsetPenalty : function(unReqCharset)
    {
        // Penalty = 65000 (это самый весомый параметр)
        if ( FD_UNKNOWN_CHARSET == unReqCharset )
            return 0;

        var _ret = this.GetCodePageByCharset(unReqCharset);

        var nMult = 1 << _ret.ulBit;
        if (nMult < 0)
            nMult += 4294967296;

        var ulCandRanges = [this.m_ulUnicodeRange1, this.m_ulUnicodeRange2, this.m_ulUnicodeRange3, this.m_ulUnicodeRange4,
            this.m_ulCodePageRange1, this.m_ulCodePageRange2];

        if ( (ulCandRanges[_ret.unLongIndex] & nMult) == 0 )
            return 65000;

        return 0;
    },

    GetAvgWidthPenalty : function(shReqWidth)
    {
        if ( 0 == this.m_shAvgCharWidth && 0 != shReqWidth )
            return 4000;

        return Math.abs( this.m_shAvgCharWidth - shReqWidth ) * 4;
    },

    GetAscentPenalty : function(shReqAscent)
    {
        if ( 0 == this.m_shAscent && 0 != shReqAscent )
            return 100;

        return (Math.abs( this.m_shAscent - shReqAscent ) / 10) >> 0;
    },

    GetDescentPenalty : function(shReqDescent)
    {
        if ( 0 == this.m_shDescent && 0 != shReqDescent )
            return 100;

        return (Math.abs( this.m_shDescent - shReqDescent ) / 10) >> 0;
    },

    GetLineGapPenalty : function(shReqLineGap)
    {
        if ( 0 == this.m_shLineGap && 0 != shReqLineGap )
            return 100;

        return (Math.abs( this.m_shLineGap - shReqLineGap ) / 10) >> 0;
    },

    GetXHeightPenalty : function(shReqXHeight)
    {
        if ( 0 == this.shXHeight && 0 != shReqXHeight )
            return 50;

        return (Math.abs( this.m_shXHeight - shReqXHeight ) / 20) >> 0;
    },

    GetCapHeightPenalty : function(shReqCapHeight)
    {
        if ( 0 == this.m_shCapHeight && 0 != shReqCapHeight )
            return 50;

        return (Math.abs( this.m_shCapHeight - shReqCapHeight ) / 20) >> 0;
    },

    // common
    GetCodePageByCharset : function(unCharset)
    {
        var ret = { ulBit : 0, unLongIndex : 4 };
        // Соответсвие CodePage -> ulCodePageRange1 : http://www.microsoft.com/Typography/otspec/os2.htm#cpr

        if ( unCharset == 1 )
            unCharset = this.GetDefaultCharset();

        if (true)
        {
            switch( unCharset )
            {
                case 0x00: ret.ulBit =  0; break;
                case 0xEE: ret.ulBit =  1; break;
                case 0xCC: ret.ulBit =  2; break;
                case 0xA1: ret.ulBit =  3; break;
                case 0xA2: ret.ulBit =  4; break;
                case 0xB1: ret.ulBit =  5; break;
                case 0xB2: ret.ulBit =  6; break;
                case 0xBA: ret.ulBit =  7; break;
                case 0xA3: ret.ulBit =  8; break;
                case 0xDE: ret.ulBit = 16; break;
                case 0x80: ret.ulBit = 17; break;
                case 0x86: ret.ulBit = 18; break;
                case 0x81: ret.ulBit = 19; break;
                case 0x88: ret.ulBit = 20; break;
                case 0x82: ret.ulBit = 21; break;
                case 0x4D: ret.ulBit = 29; break;
                case 0x02: ret.ulBit = 31; break;
                case 0xFF: ret.ulBit = 30; break;
                default:   ret.ulBit =  0; break;
            }
        }
    },

    GetDefaultCharset : function(bUseDefCharset)
    {
        if ( !bUseDefCharset )
            return FD_UNKNOWN_CHARSET;

        return 0;
    },

    CheckEqualFonts2 : function(name1, name2)
    {
        var _res1 = name1.toLowerCase();
        var _res2 = name2.toLowerCase();

        if (_res1 == _res2)
            return 1500;

        if (_res1.replace(/[\s-]/g, '') == _res2.replace(/[\s-]/g, ''))
            return 3000;

        return 10000;
    },

    Serialize : function()
    {
        var _obj = {};

		_obj["m_wsFontName"] = this.m_wsFontName;

		_obj["m_wsFontPath"] = this.m_wsFontPath;
		_obj["m_lIndex"] = this.m_lIndex;

		_obj["m_bBold"] = this.m_bBold;
		_obj["m_bItalic"] = this.m_bItalic;
		_obj["m_bIsFixed"] = this.m_bIsFixed;

		_obj["m_aPanose"] = new Array(10);
		for (var i = 0; i < 10; i++)
        {
			_obj["m_aPanose"][i] = this.m_aPanose[i];
        }

		_obj["m_ulUnicodeRange1"] = this.m_ulUnicodeRange1;
		_obj["m_ulUnicodeRange2"] = this.m_ulUnicodeRange2;
		_obj["m_ulUnicodeRange3"] = this.m_ulUnicodeRange3;
		_obj["m_ulUnicodeRange4"] = this.m_ulUnicodeRange4;

		_obj["m_ulCodePageRange1"] = this.m_ulCodePageRange1;
		_obj["m_ulCodePageRange2"] = this.m_ulCodePageRange2;

		_obj["m_usWeigth"] = this.m_usWeigth;
		_obj["m_usWidth"] = this.m_usWidth;

		_obj["m_sFamilyClass"] = this.m_sFamilyClass;
		_obj["m_eFontFormat"] = this.m_eFontFormat;

		_obj["m_shAvgCharWidth"] = this.m_shAvgCharWidth;
		_obj["m_shAscent"] = this.m_shAscent;
		_obj["m_shDescent"] = this.m_shDescent;
		_obj["m_shLineGap"] = this.m_shLineGap;
		_obj["m_shXHeight"] = this.m_shXHeight;
		_obj["m_shCapHeight"] = this.m_shCapHeight;

		return _obj;
    }
};

function CLanguageFontSelect()
{
    this.Type   = 0;
    this.Ranges = [];
    this.CodePage1Mask = 0;
    this.CodePage2Mask = 0;
    this.DefaultFont = "Arial";

    this.FullSupportPages = false;
}

CLanguageFontSelect.prototype =
{
    checkChar : function(_code)
    {
        var _len = this.Ranges.length;
        for (var i = 0; i < _len; i += 2)
        {
            if (_code >= this.Ranges[i] && _code <= this.Ranges[i + 1])
                return true;
        }
        return false;
    }
};

var LanguagesFontSelectTypes =
{
    Unknown     : -1,
    Arabic      : 1,
    Korean      : 2,
    Japan       : 3,
    Chinese     : 4,

    EastAsiaStart   : 2,
    EastAsiaEnd     : 4
};

function CFontSelectList()
{
    this.List = [];
    this.ListMap = {};

    this.Languages = [];

    this.m_pRanges = null;
    this.m_pRangesNums = null;

    this.IsInit = false;
    this.CurrentLoadedObj = null;
}

function memset(p, start, val, count)
{
    var _data = p.data;
    for (var i = 0; i < count; i++)
        _data[i + start] = val;
}

CFontSelectList.prototype =
{
    SerializeList : function()
    {
        var _list = [];
        var _len = this.List.length;
        for (var k = 0; k < _len; k++)
            _list.push(this.List[k].Serialize());
        return _list;
    },

    Init : function()
    {
        if (true == this.IsInit)
            return;

        this.IsInit = true;

		if (window["g_fonts_selection_bin"] != "")
		{
			// read from stream
			var _ft_stream = CreateFontData2(window["g_fonts_selection_bin"]);
			var _file_stream = new AscCommon.FileStream(_ft_stream.data, _ft_stream.size);

			var count = _file_stream.GetLong();
			for (var i = 0; i < count; i++)
			{
				var _fs = new CFontSelect();
				_fs.fromStream(_file_stream);
				
				// корректируем плохие популярные шрифты
				if (_fs.m_wsFontName == "Droid Sans Fallback")
				{	
					if ((_fs.m_ulCodePageRange1 & (1 << 19)) == (1 << 19))
						_fs.m_ulCodePageRange1 -= (1 << 19);
				}
						
				this.List.push(_fs);
				this.ListMap[_fs.m_wsFontPath] = this.List.length - 1;
			}
		}

        // add languages
        // 1) arabic
        var _arabic_lang = new CLanguageFontSelect();
        _arabic_lang.Type = LanguagesFontSelectTypes.Arabic;
        _arabic_lang.Ranges.push(0x0600);
        _arabic_lang.Ranges.push(0x06FF);
        _arabic_lang.Ranges.push(0x0750);
        _arabic_lang.Ranges.push(0x077F);
        _arabic_lang.Ranges.push(0x08A0);
        _arabic_lang.Ranges.push(0x08FF);
        _arabic_lang.Ranges.push(0xFB50);
        _arabic_lang.Ranges.push(0xFDFF);
        _arabic_lang.Ranges.push(0xFE70);
        _arabic_lang.Ranges.push(0xFEFF);
        _arabic_lang.CodePage1Mask = (1 << 6);
        _arabic_lang.CodePage2Mask = (1 << 19) | (1 << 29);
        _arabic_lang.DefaultFont = "Tahoma";
        this.Languages.push(_arabic_lang);

        // 2) korean
        var _korean_lang = new CLanguageFontSelect();
        _korean_lang.Type = LanguagesFontSelectTypes.Korean;
        _korean_lang.Ranges.push(0x1100);
        _korean_lang.Ranges.push(0x11FF);
        _korean_lang.Ranges.push(0x3130);
        _korean_lang.Ranges.push(0x318F);
        _korean_lang.Ranges.push(0xAC00);
        _korean_lang.Ranges.push(0xD7AF);
        _korean_lang.Ranges.push(0xFF00);
        _korean_lang.Ranges.push(0xFFEF);
        _korean_lang.CodePage1Mask = (1 << 19);
        _korean_lang.CodePage2Mask = 0;
        _korean_lang.DefaultFont = "Batang";
        this.Languages.push(_korean_lang);

        // 3) japan
        var _japan_lang = new CLanguageFontSelect();
        _japan_lang.Type = LanguagesFontSelectTypes.Japan;
        _japan_lang.Ranges.push(0x4E00);
        _japan_lang.Ranges.push(0x9FBF);

        /*
         _japan_lang.Ranges.push(0x3000);// punctuation
         _japan_lang.Ranges.push(0x303F);
         _japan_lang.Ranges.push(0x3040);// Hiragana
         _japan_lang.Ranges.push(0x309F);
         _japan_lang.Ranges.push(0x30A0);// Katakana
         _japan_lang.Ranges.push(0x30FF);
         */
        _japan_lang.Ranges.push(0x3000);
        _japan_lang.Ranges.push(0x30FF);
        _japan_lang.Ranges.push(0xFF00);
        _japan_lang.Ranges.push(0xFFEF);

        _japan_lang.CodePage1Mask = (1 << 17) | (1 << 30);
        _japan_lang.CodePage2Mask = 0;
        _japan_lang.DefaultFont = "MS Mincho";
        _japan_lang.FullSupportPages = true;
        this.Languages.push(_japan_lang);

        // 4) chinese http://stackoverflow.com/questions/1366068/whats-the-complete-range-for-chinese-characters-in-unicode
        var _chinese_lang = new CLanguageFontSelect();
        _chinese_lang.Type = LanguagesFontSelectTypes.Chinese;
        _chinese_lang.Ranges.push(0x4E00);
        _chinese_lang.Ranges.push(0x9FFF);
        _chinese_lang.Ranges.push(0x3400);
        _chinese_lang.Ranges.push(0x4DFF);
        _chinese_lang.Ranges.push(0x20000);
        _chinese_lang.Ranges.push(0x2A6DF);
        _chinese_lang.Ranges.push(0xF900);
        _chinese_lang.Ranges.push(0xFAFF);
        _chinese_lang.Ranges.push(0x2F800);
        _chinese_lang.Ranges.push(0x2FA1F);
        _chinese_lang.Ranges.push(0xFF00);
        _chinese_lang.Ranges.push(0xFFEF);
        _chinese_lang.CodePage1Mask = (1 << 18) | (1 << 20);
        _chinese_lang.CodePage2Mask = 0;
        _chinese_lang.DefaultFont = "SimSun";
        this.Languages.push(_chinese_lang);

        // debug!!!
        /*
         var _symbols = " `~><.,:;?!/\\|[](){}$€%#@&\'\"=+-*^_1234567890";
         console.log("start dump multisymbols -----------------------------");
         for (var i = 0; i < _symbols.length; i++)
         console.log("" + _symbols.charCodeAt(i));
         console.log("end dump multisymbols -------------------------------");
         */

        /*
         var _array_results = [];
         var _count_fonts = this.List.length;
         for (var i = 0; i < _count_fonts; i++)
         {
         var f = this.List[i];

         console.log(f.m_wsFontPath + "_" + f.m_lIndex + " codepage1: " + f.m_ulCodePageRange1 + ", codepage2: " + f.m_ulCodePageRange2);
         }
         */
		 
		// добавляем ASCW3
		var _fs = new CFontSelect();
		_fs.m_wsFontName = "ASCW3";
		this.List.push(_fs);

        delete window["g_fonts_selection_bin"];
    },

    isEnglishChar : function(_code)
    {
        if (97 <= _code && _code <= 122)
            return true;
        if (65 <= _code && _code <= 90)
            return true;
        return false;
    },

    isMultiLanguageSymbol : function(_code)
    {
        // здесь те символы, которые не влияют на язык

        switch (_code)
        {
            case 32:
            case 96:
            case 126:
            case 62:
            case 60:
            case 46:
            case 44:
            case 58:
            case 59:
            case 63:
            case 33:
            case 47:
            case 92:
            case 124:
            case 91:
            case 93:
            case 40:
            case 41:
            case 123:
            case 125:
            case 36:
            case 37:
            case 35:
            case 64:
            case 38:
            case 39:
            case 34:
            case 61:
            case 43:
            case 45:
            case 42:
            case 94:
            case 95:
            case 49:
            case 50:
            case 51:
            case 52:
            case 53:
            case 54:
            case 55:
            case 56:
            case 57:
            case 48:
                return true;
            default:
            {
                if (_code >= 0x2000 && _code <= 0x206F) // general punctuation
                    return true;

                if (_code >= 0x20A0 && _code <= 0x20CF) // Currency Symbols
                    return true;

                break;
            }
        }
        return false;
    },

    checkText : function(text)
    {
        var _text_len = text.length;
        if (_text_len == 0)
            return LanguagesFontSelectTypes.Unknown;

        var _array_detect_languages = [];
        var _detect_languages_length = this.Languages.length;

        for (var _lang = 0; _lang < _detect_languages_length; _lang++)
        {
            var _language = this.Languages[_lang];

            var _is_support = true;
            var _no_multi_symbols = 0;
            var _percent_by_english = 0;
            for (var i = 0; i < _text_len; i++)
            {
                var _code = text.charCodeAt(i);
                if (!this.isMultiLanguageSymbol(_code))
                {
                    _no_multi_symbols++;
                    if (!_language.checkChar(_code))
                    {
                        if (this.isEnglishChar(_code))
                            _percent_by_english--;
                        else
                        {
                            _is_support = false;
                            break;
                        }
                    }
                    else
                    {
                        _percent_by_english++;
                    }
                }
            }

            if (0 == _no_multi_symbols)
                return LanguagesFontSelectTypes.Unknown;

            if (_is_support && (_percent_by_english > 0))
            {
                _array_detect_languages.push(_language.Type);
            }
        }

        var _len = _array_detect_languages.length;
        if (0 == _len)
            return LanguagesFontSelectTypes.Unknown;

        return _array_detect_languages[_len - 1];
    },

    checkPasteText : function(textPr, langId)
    {
        var _ret_obj = { is_async : false, name : "", fontSlot : fontslot_ASCII };

        if (!textPr.RFonts)
            return _ret_obj;

        var _lang = null;
        for (var i = 0; i < this.Languages.length; i++)
        {
            _lang = this.Languages[i];
            if (_lang.Type == langId)
            {
                break;
            }
        }
        if (null == _lang)
        {
            // такого быть не должно
            return _ret_obj;
        }

        _ret_obj.fontSlot = fontslot_ASCII;

        if (langId >= LanguagesFontSelectTypes.EastAsiaStart && langId <= LanguagesFontSelectTypes.EastAsiaEnd)
            _ret_obj.fontSlot = fontslot_EastAsia;

        if (langId == LanguagesFontSelectTypes.Arabic)
        {
            if (textPr.CS || textPr.RTL)
                _ret_obj.fontSlot = fontslot_CS;
        }

        var _fontFamily = undefined;
        var bold    = undefined;
        var italic  = undefined;
        switch (_ret_obj.fontSlot)
        {
            case fontslot_ASCII:
            {
                _fontFamily = textPr.RFonts.Ascii;
                bold    = textPr.Bold;
                italic  = textPr.Italic;
                break;
            }
            case fontslot_HAnsi:
            {
                _fontFamily = textPr.RFonts.HAnsi;
                bold    = textPr.Bold;
                italic  = textPr.Italic;
                break;
            }
            case fontslot_CS:
            {
                _fontFamily = textPr.RFonts.CS;
                bold    = textPr.BoldCS;
                italic  = textPr.ItalicCS;
                break;
            }
            case fontslot_EastAsia:
            {
                _fontFamily = textPr.RFonts.EastAsia;
                bold    = textPr.Bold;
                italic  = textPr.Italic;
                break;
            }
            default:
                break;
        }

        if (undefined == _fontFamily)
            return _ret_obj;

        var oFontStyle = FontStyle.FontStyleRegular;
        if (!italic && bold)
            oFontStyle = FontStyle.FontStyleBold;
        else if (italic && !bold)
            oFontStyle = FontStyle.FontStyleItalic;
        else if (italic && bold)
            oFontStyle = FontStyle.FontStyleBoldItalic;

        var _info = g_fontApplication.GetFontInfo(_fontFamily.Name, oFontStyle);

        var _id = _info.GetFontID(AscCommon.g_font_loader, oFontStyle);
        var _select = this.List[this.ListMap[_id.id]];

        if (0 != _lang.CodePage1Mask)
        {
            if (!_lang.FullSupportPages)
            {
                if (0 == (_lang.CodePage1Mask & _select.m_ulCodePageRange1))
                    _ret_obj.is_async = true;
            }
            else
            {
                if (_lang.CodePage1Mask != (_lang.CodePage1Mask & _select.m_ulCodePageRange1))
                    _ret_obj.is_async = true;
            }
        }
        if (0 != _lang.CodePage2Mask)
        {
            if (!_lang.FullSupportPages)
            {
                if (0 == (_lang.CodePage2Mask & _select.m_ulCodePageRange2))
                    _ret_obj.is_async = true;
            }
            else
            {
                if (_lang.CodePage2Mask != (_lang.CodePage2Mask & _select.m_ulCodePageRange2))
                    _ret_obj.is_async = true;
            }
        }

        if (!_ret_obj.is_async)
            return _ret_obj;

        _ret_obj.name = this.selectNeedFont(_lang, oFontStyle);
        if (_ret_obj.name == "")
            _ret_obj.is_async = false;

        return _ret_obj;
    },

    getSetupRFonts : function(obj)
    {
        var _rfonts = new CRFonts();
        switch (obj.fontSlot)
        {
            case fontslot_EastAsia:
            {
                _rfonts.EastAsia = { Name : obj.name, Index : -1 };
                break;
            }
            case fontslot_CS:
            {
                _rfonts.CS = { Name : obj.name, Index : -1 };
                break;
            }
            case fontslot_HAnsi:
            {
                _rfonts.HAnsi = { Name : obj.name, Index : -1 };
                break;
            }
            case fontslot_ASCII:
            default:
            {
                _rfonts.Ascii = { Name : obj.name, Index : -1 };
                break;
            }
        }
        return _rfonts;
    },

    selectNeedFont : function(_lang, _style)
    {
        var _error = 0x01000000;
        var _name = "";

        var _len = AscFonts.g_font_infos.length;
        for (var i = 0; i < _len; i++)
        {
            var _info = AscFonts.g_font_infos[i];
            var _id = _info.GetFontID(AscCommon.g_font_loader, _style);
            var _select = this.List[this.ListMap[_id.id]];

            if (!_select)
                continue;

            var _bIsNeed = false;
            if (0 != _lang.CodePage1Mask)
            {
                if (!_lang.FullSupportPages)
                {
                    if (0 == (_lang.CodePage1Mask & _select.m_ulCodePageRange1))
                        _bIsNeed = true;
                }
                else
                {
                    if (_lang.CodePage1Mask != (_lang.CodePage1Mask & _select.m_ulCodePageRange1))
                        _bIsNeed = true;
                }
            }
            if (0 != _lang.CodePage2Mask)
            {
                if (!_lang.FullSupportPages)
                {
                    if (0 == (_lang.CodePage2Mask & _select.m_ulCodePageRange2))
                        _bIsNeed = true;
                }
                else
                {
                    if (_lang.CodePage2Mask != (_lang.CodePage2Mask & _select.m_ulCodePageRange2))
                        _bIsNeed = true;
                }
            }

            if (!_bIsNeed)
            {
                var _tmp_error = 0;
                if (_id.file.Status != 0)
                    _tmp_error += 0x00010000;
                if (_info.Name != _lang.DefaultFont)
                    _tmp_error += 0x00000100;

                if (_tmp_error < _error)
                {
                    _error = _tmp_error;
                    _name = _info.Name;
                }
            }
        }

        if (_name == "")
        {
            _name = g_fontApplication.GetFontInfoName(_lang.DefaultFont);
        }

        return _name;
    },

    checkText2 : function(text)
    {
        var r1 = 0;
        var r2 = 0;
        var r3 = 0;
        var r4 = 0;
        var codePage1 = 0;
        var codePage2 = 0;

        var len = text.length;
        for (var i = 0; i < len; i++)
        {
            var _code = text.charCodeAt(i);

            var lRangeNum	= this.m_pRangesNums.data[_code];
            var lRange		= this.m_pRanges.data[_code];

            if (0xFF != lRangeNum)
            {
                if ((i == 0) && ((lRangeNum == 1) && (lRange == 28)))
                {
                    codePage1 = 0x80000000;
                }
                else if (((lRangeNum == 2) && (lRange == 3)) || ((lRangeNum == 1) && (lRange == 31)) || ((lRangeNum == 0) && (lRange == 13)))
                {
                    // arabic!
                    r1 |= (1 << 13);
                    r2 |= (1 << 31);
                    r3 |= (1 << 3);
                }
                else
                {
                    if (0 == lRangeNum)
                        r1 |= 1 << lRange;
                    else if (1 == lRangeNum)
                        r2 |= 1 << lRange;
                    else if (2 == lRangeNum)
                        r3 |= 1 << lRange;
                    else
                        r4 |= 1 << lRange;
                }
            }
        }

        var _array_results = [];
        var _count_fonts = this.List.length;
        for (var i = 0; i < _count_fonts; i++)
        {
            var f = this.List[i];

            if (((f.m_ulUnicodeRange1 & r1) == r1) &&
                ((f.m_ulUnicodeRange2 & r2) == r2) &&
                ((f.m_ulUnicodeRange3 & r3) == r3) &&
                ((f.m_ulUnicodeRange4 & r4) == r4) &&
                ((f.m_ulCodePageRange1 & codePage1) == codePage1) &&
                ((f.m_ulCodePageRange2 & codePage2) == codePage2))
            {
                _array_results.push(f.m_wsFontPath);
            }
        }

        //console.log(_array_results);
    },

    initRanges : function()
    {
        // пока не используем
        /*

         // пока только 2 байта
         this.m_pRanges      = g_memory.Alloc(0xFFFF);
         this.m_pRangesNums  = g_memory.Alloc(0xFFFF);

         memset(this.m_pRanges, 0, 0xFF, 0xFFFF);
         memset(this.m_pRangesNums, 0, 0xFF, 0xFFFF);

         // теперь просто по порядку заполняем все рэнджи
         var nStart = 0;
         var nCount = 0;

         // rangeNum 0
         // case 00: sUCRName = "Basic Latin"; break; /: U+0020-U+007E :/
         nStart = 0x0020;
         nCount = 0x007E - nStart + 1;
         memset(this.m_pRanges, nStart, 0, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 01: sUCRName = "Latin-1 Supplement"; break; /: U+0080-U+00FF :/
         nStart = 0x0080;
         nCount = 0x00FF - nStart + 1;
         memset(this.m_pRanges, nStart, 1, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 02: sUCRName = "Latin Extended-A"; break; /: U+0100-U+017F :/
         nStart = 0x0100;
         nCount = 0x017F - nStart + 1;
         memset(this.m_pRanges, nStart, 2, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 03: sUCRName = "Latin Extended-B"; break; /: U+0180-U+024F :/
         nStart = 0x0180;
         nCount = 0x024F - nStart + 1;
         memset(this.m_pRanges, nStart, 3, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 04: sUCRName = "IPA Extensions"; break; /: U+0250-U+02AF :/ /: U+1D00-U+1D7F :/ /: U+1D80-U+1DBF :/
         nStart = 0x0250;
         nCount = 0x02AF - nStart + 1;
         memset(this.m_pRanges, nStart, 4, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         nStart = 0x1D00;
         nCount = 0x1D7F - nStart + 1;
         memset(this.m_pRanges, nStart, 4, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         nStart = 0x1D80;
         nCount = 0x1DBF - nStart + 1;
         memset(this.m_pRanges, nStart, 4, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 05: sUCRName = "Spacing Modifier Letters"; break; /: U+02B0-U+02FF :/ /: U+A700-U+A71F :/
         nStart = 0x02B0;
         nCount = 0x02FF - nStart + 1;
         memset(this.m_pRanges, nStart, 5, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         nStart = 0xA700;
         nCount = 0xA71F - nStart + 1;
         memset(this.m_pRanges, nStart, 5, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 06: sUCRName = "Combining Diacritical Marks"; break; /: U+0300-U+036F :/ /: U+1DC0-U+1DFF :/
         nStart = 0x0300;
         nCount = 0x036F - nStart + 1;
         memset(this.m_pRanges, nStart, 6, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         nStart = 0x1DC0;
         nCount = 0x1DFF - nStart + 1;
         memset(this.m_pRanges, nStart, 6, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 07: sUCRName = "Greek and Coptic"; break; /: U+0370-U+03FF :/
         nStart = 0x0370;
         nCount = 0x03FF - nStart + 1;
         memset(this.m_pRanges, nStart, 7, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 08: sUCRName = "Coptic"; break; /: U+2C80-U+2CFF :/
         nStart = 0x2C80;
         nCount = 0x2CFF - nStart + 1;
         memset(this.m_pRanges, nStart, 8, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 09: sUCRName = "Cyrillic"; break; /: U+0400-U+04FF :/ /: U+0500-U+052F :/ /: U+2DE0-U+2DFF :/ /: U+A640-U+A69F :/
         nStart = 0x0400;
         nCount = 0x04FF - nStart + 1;
         memset(this.m_pRanges, nStart, 9, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         nStart = 0x0500;
         nCount = 0x052F - nStart + 1;
         memset(this.m_pRanges, nStart, 9, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         nStart = 0x2DE0;
         nCount = 0x2DFF - nStart + 1;
         memset(this.m_pRanges, nStart, 9, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         nStart = 0xA640;
         nCount = 0xA69F - nStart + 1;
         memset(this.m_pRanges, nStart, 9, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 10: sUCRName = "Armenian"; break; /: U+0530-U+058F :/
         nStart = 0x0530;
         nCount = 0x058F - nStart + 1;
         memset(this.m_pRanges, nStart, 10, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 11: sUCRName = "Hebrew"; break; /: U+0590-U+05FF :/
         nStart = 0x0590;
         nCount = 0x05FF - nStart + 1;
         memset(this.m_pRanges, nStart, 11, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 12: sUCRName = "Vai"; break; /: U+A500-U+A63F :/
         nStart = 0xA500;
         nCount = 0xA63F - nStart + 1;
         memset(this.m_pRanges, nStart, 12, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 13: sUCRName = "Arabic"; break; /: U+0600-U+06FF :/ /: U+0750-U+077F :/
         nStart = 0x0600;
         nCount = 0x06FF - nStart + 1;
         memset(this.m_pRanges, nStart, 13, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         nStart = 0x0750;
         nCount = 0x077F - nStart + 1;
         memset(this.m_pRanges, nStart, 13, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 14: sUCRName = "NKo"; break; /: U+07C0-U+07FF :/
         nStart = 0x07C0;
         nCount = 0x07FF - nStart + 1;
         memset(this.m_pRanges, nStart, 14, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 15: sUCRName = "Devanagari"; break; /: U+0900-U+097F :/
         nStart = 0x0900;
         nCount = 0x097F - nStart + 1;
         memset(this.m_pRanges, nStart, 15, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 16: sUCRName = "Bengali"; break; /: U+0980-U+09FF :/
         nStart = 0x0980;
         nCount = 0x09FF - nStart + 1;
         memset(this.m_pRanges, nStart, 16, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 17: sUCRName = "Gurmukhi"; break; /: U+0A00-U+0A7F :/
         nStart = 0x0A00;
         nCount = 0x0A7F - nStart + 1;
         memset(this.m_pRanges, nStart, 17, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 18: sUCRName = "Gujarati"; break; /: U+0A80-U+0AFF :/
         nStart = 0x0A80;
         nCount = 0x0AFF - nStart + 1;
         memset(this.m_pRanges, nStart, 18, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 19: sUCRName = "Oriya"; break; /: U+0B00-U+0B7F :/
         nStart = 0x0B00;
         nCount = 0x0B7F - nStart + 1;
         memset(this.m_pRanges, nStart, 19, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 20: sUCRName = "Tamil"; break; /: U+0B80-U+0BFF :/
         nStart = 0x0B80;
         nCount = 0x0BFF - nStart + 1;
         memset(this.m_pRanges, nStart, 20, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 21: sUCRName = "Telugu"; break; /: U+0C00-U+0C7F :/
         nStart = 0x0C00;
         nCount = 0x0C7F - nStart + 1;
         memset(this.m_pRanges, nStart, 21, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 22: sUCRName = "Kannada"; break; /: U+0C80-U+0CFF :/
         nStart = 0x0C80;
         nCount = 0x0CFF - nStart + 1;
         memset(this.m_pRanges, nStart, 22, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 23: sUCRName = "Malayalam"; break; /: U+0D00-U+0D7F :/
         nStart = 0x0D00;
         nCount = 0x0D7F - nStart + 1;
         memset(this.m_pRanges, nStart, 23, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 24: sUCRName = "Thai"; break; /: U+0E00-U+0E7F :/
         nStart = 0x0E00;
         nCount = 0x0E7F - nStart + 1;
         memset(this.m_pRanges, nStart, 24, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 25: sUCRName = "Lao"; break; /: U+0E80-U+0EFF :/
         nStart = 0x0E80;
         nCount = 0x0EFF - nStart + 1;
         memset(this.m_pRanges, nStart, 25, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 26: sUCRName = "Georgian"; break; /: U+10A0-U+10FF :/ /: U+2D00-U+2D2F :/
         nStart = 0x10A0;
         nCount = 0x10FF - nStart + 1;
         memset(this.m_pRanges, nStart, 26, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         nStart = 0x2D00;
         nCount = 0x2D2F - nStart + 1;
         memset(this.m_pRanges, nStart, 26, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 27: sUCRName = "Balinese"; break; /: U+1B00-U+1B7F :/
         nStart = 0x1B00;
         nCount = 0x1B7F - nStart + 1;
         memset(this.m_pRanges, nStart, 27, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 28: sUCRName = "Hangul Jamo"; break; /: U+1100-U+11FF :/
         nStart = 0x1100;
         nCount = 0x11FF - nStart + 1;
         memset(this.m_pRanges, nStart, 28, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 29: sUCRName = "Latin Extended Additional"; break; /: U+1E00-U+1EFF :/ /: U+2C60-U+2C7F :/ /: U+A720-U+A7FF :/
         nStart = 0x1E00;
         nCount = 0x1EFF - nStart + 1;
         memset(this.m_pRanges, nStart, 29, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         nStart = 0x2C60;
         nCount = 0x2C7F - nStart + 1;
         memset(this.m_pRanges, nStart, 29, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         nStart = 0xA720;
         nCount = 0xA7FF - nStart + 1;
         memset(this.m_pRanges, nStart, 29, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 30: sUCRName = "Greek Extended"; break; /: U+1F00-U+1FFF :/
         nStart = 0x1F00;
         nCount = 0x1FFF - nStart + 1;
         memset(this.m_pRanges, nStart, 30, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         //case 31: sUCRName = "General Punctuation"; break; /: U+2000-U+206F :/ /: U+2E00-U+2E7F :/
         nStart = 0x2000;
         nCount = 0x206F - nStart + 1;
         memset(this.m_pRanges, nStart, 31, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         nStart = 0x2E00;
         nCount = 0x2E7F - nStart + 1;
         memset(this.m_pRanges, nStart, 31, nCount);
         memset(this.m_pRangesNums, nStart, 0, nCount);

         // rangeNum 1
         //case 00: sUCRName = "Superscripts And Subscripts"; break; /: U+2070-U+209F :/
         nStart = 0x2070;
         nCount = 0x209F - nStart + 1;
         memset(this.m_pRanges, nStart, 0, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 01: sUCRName = "Currency Symbols"; break; /: U+20A0-U+20CF :/
         nStart = 0x20A0;
         nCount = 0x20CF - nStart + 1;
         memset(this.m_pRanges, nStart, 1, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 02: sUCRName = "Combining Diacritical Marks For Symbols"; break; /: U+20D0-U+20FF :/
         nStart = 0x20D0;
         nCount = 0x20FF - nStart + 1;
         memset(this.m_pRanges, nStart, 2, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 03: sUCRName = "Letterlike Symbols"; break; /: U+2100-U+214F :/
         nStart = 0x2100;
         nCount = 0x214F - nStart + 1;
         memset(this.m_pRanges, nStart, 3, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 04: sUCRName = "Number Forms"; break; /: U+2150-U+218F :/
         nStart = 0x2150;
         nCount = 0x218F - nStart + 1;
         memset(this.m_pRanges, nStart, 4, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 05: sUCRName = "Arrows"; break; /: U+2190-U+21FF :/ /: U+27F0-U+27FF :/ /: U+2900-U+297F :/ /: U+2B00-U+2BFF :/
         nStart = 0x2190;
         nCount = 0x21FF - nStart + 1;
         memset(this.m_pRanges, nStart, 5, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         nStart = 0x27F0;
         nCount = 0x27FF - nStart + 1;
         memset(this.m_pRanges, nStart, 5, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         nStart = 0x2900;
         nCount = 0x297F - nStart + 1;
         memset(this.m_pRanges, nStart, 5, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         nStart = 0x2B00;
         nCount = 0x2BFF - nStart + 1;
         memset(this.m_pRanges, nStart, 5, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 06: sUCRName = "Mathematical Operators"; break; /: U+2200-U+22FF :/ /: U+2A00-U+2AFF :/ /: U+27C0-U+27EF :/ /: U+2980-U+29FF :/
         nStart = 0x2200;
         nCount = 0x22FF - nStart + 1;
         memset(this.m_pRanges, nStart, 6, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         nStart = 0x2A00;
         nCount = 0x2AFF - nStart + 1;
         memset(this.m_pRanges, nStart, 6, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         nStart = 0x27C0;
         nCount = 0x27EF - nStart + 1;
         memset(this.m_pRanges, nStart, 6, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         nStart = 0x2980;
         nCount = 0x29FF - nStart + 1;
         memset(this.m_pRanges, nStart, 6, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 07: sUCRName = "Miscellaneous Technical"; break; /: U+2300-U+23FF :/
         nStart = 0x2300;
         nCount = 0x23FF - nStart + 1;
         memset(this.m_pRanges, nStart, 7, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 08: sUCRName = "Control Pictures"; break; /: U+2400-U+243F :/
         nStart = 0x2400;
         nCount = 0x243F - nStart + 1;
         memset(this.m_pRanges, nStart, 8, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 09: sUCRName = "Optical Character Recognition"; break; /: U+2440-U+245F :/
         nStart = 0x2440;
         nCount = 0x245F - nStart + 1;
         memset(this.m_pRanges, nStart, 9, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 10: sUCRName = "Enclosed Alphanumerics"; break; /: U+2460-U+24FF :/
         nStart = 0x2460;
         nCount = 0x24FF - nStart + 1;
         memset(this.m_pRanges, nStart, 10, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 11: sUCRName = "Box Drawing"; break; /: U+2500-U+257F :/
         nStart = 0x2500;
         nCount = 0x257F - nStart + 1;
         memset(this.m_pRanges, nStart, 11, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 12: sUCRName = "Block Elements"; break; /: U+2580-U+259F :/
         nStart = 0x2580;
         nCount = 0x259F - nStart + 1;
         memset(this.m_pRanges, nStart, 12, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 13: sUCRName = "Geometric Shapes"; break; /: U+25A0-U+25FF :/
         nStart = 0x25A0;
         nCount = 0x25FF - nStart + 1;
         memset(this.m_pRanges, nStart, 13, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 14: sUCRName = "Miscellaneous Symbols"; break; /: U+2600-U+26FF :/
         nStart = 0x2600;
         nCount = 0x26FF - nStart + 1;
         memset(this.m_pRanges, nStart, 14, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 15: sUCRName = "Dingbats"; break; /: U+2700-U+27BF :/
         nStart = 0x2700;
         nCount = 0x27BF - nStart + 1;
         memset(this.m_pRanges, nStart, 15, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 16: sUCRName = "CJK Symbols and Punctuation"; break; /: U+3000-U+303F :/
         nStart = 0x3000;
         nCount = 0x303F - nStart + 1;
         memset(this.m_pRanges, nStart, 16, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 17: sUCRName = "Hiragana"; break;  /: U+3040-U+309F :/
         nStart = 0x3040;
         nCount = 0x309F - nStart + 1;
         memset(this.m_pRanges, nStart, 17, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 18: sUCRName = "Katakana"; break; /: U+30A0-U+30FF :/ /: U+31F0-U+31FF :/
         nStart = 0x30A0;
         nCount = 0x30FF - nStart + 1;
         memset(this.m_pRanges, nStart, 18, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         nStart = 0x31F0;
         nCount = 0x31FF - nStart + 1;
         memset(this.m_pRanges, nStart, 18, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 19: sUCRName = "Bopomofo"; break; /: U+3100-U+312F :/ /: U+31A0-U+31BF :/
         nStart = 0x3100;
         nCount = 0x312F - nStart + 1;
         memset(this.m_pRanges, nStart, 19, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         nStart = 0x31A0;
         nCount = 0x31BF - nStart + 1;
         memset(this.m_pRanges, nStart, 19, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 20: sUCRName = "Hangul Compatibility Jamo"; break; /: U+3130-U+318F :/
         nStart = 0x3130;
         nCount = 0x318F - nStart + 1;
         memset(this.m_pRanges, nStart, 20, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 21: sUCRName = "Phags-pa"; break; /: U+A840-U+A87F :/
         nStart = 0xA840;
         nCount = 0xA87F - nStart + 1;
         memset(this.m_pRanges, nStart, 21, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 22: sUCRName = "Enclosed CJK Letters and Months"; break; /: U+3200-U+32FF :/
         nStart = 0x3200;
         nCount = 0x32FF - nStart + 1;
         memset(this.m_pRanges, nStart, 22, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 23: sUCRName = "CJK Compatibility"; break; /: U+3300-U+33FF :/
         nStart = 0x3300;
         nCount = 0x33FF - nStart + 1;
         memset(this.m_pRanges, nStart, 23, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 24: sUCRName = "Hangul Syllables"; break; /: U+AC00-U+D7AF :/
         nStart = 0xAC00;
         nCount = 0xD7AF - nStart + 1;
         memset(this.m_pRanges, nStart, 24, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 25: sUCRName = "Non-Plane 0"; break; /: U+D800-U+DB7F :/ /: U+DB80-U+DBFF :/ /: U+DC00-U+DFFF :/ // Не юникодные символы
         nStart = 0xD800;
         nCount = 0xDB7F - nStart + 1;
         memset(this.m_pRanges, nStart, 25, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         nStart = 0xDB80;
         nCount = 0xDBFF - nStart + 1;
         memset(this.m_pRanges, nStart, 25, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         nStart = 0xDC00;
         nCount = 0xDFFF - nStart + 1;
         memset(this.m_pRanges, nStart, 25, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 26: sUCRName = "Phoenician"; break; /:U+10900-U+1091F:/

         //case 27: sUCRName = "CJK Unified Ideographs"; break; /: U+4E00-U+9FFF :/ /: U+2E80-U+2EFF :/ /: U+2F00-U+2FDF :/ /: U+2FF0-U+2FFF :/ /: U+3400-U+4DB5 :/ /:U+20000-U+2A6D6:/ /: U+3190-U+319F :/
         nStart = 0x4E00;
         nCount = 0x9FFF - nStart + 1;
         memset(this.m_pRanges, nStart, 27, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         nStart = 0x2E80;
         nCount = 0x2EFF - nStart + 1;
         memset(this.m_pRanges, nStart, 27, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         nStart = 0x2F00;
         nCount = 0x2FDF - nStart + 1;
         memset(this.m_pRanges, nStart, 27, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         nStart = 0x2FF0;
         nCount = 0x2FFF - nStart + 1;
         memset(this.m_pRanges, nStart, 27, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         nStart = 0x3400;
         nCount = 0x4DB5 - nStart + 1;
         memset(this.m_pRanges, nStart, 27, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         nStart = 0x3190;
         nCount = 0x319F - nStart + 1;
         memset(this.m_pRanges, nStart, 27, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 28: sUCRName = "Private Use Area (plane 0)"; break; /: U+E000-U+F8FF :/ // Не юникодные символы
         nStart = 0xE000;
         nCount = 0xF8FF - nStart + 1;
         memset(this.m_pRanges, nStart, 28, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 29: sUCRName = "CJK Strokes"; break; /: U+31C0-U+31EF :/ /: U+F900-U+FAFF :/ /:U+2F800-U+2FA1F:/
         nStart = 0x31C0;
         nCount = 0x31EF - nStart + 1;
         memset(this.m_pRanges, nStart, 29, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         nStart = 0xF900;
         nCount = 0xFAFF - nStart + 1;
         memset(this.m_pRanges, nStart, 29, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 30: sUCRName = "Alphabetic Presentation Forms"; break; /: U+FB00-U+FB4F :/
         nStart = 0xFB00;
         nCount = 0xFB4F - nStart + 1;
         memset(this.m_pRanges, nStart, 30, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         //case 31: sUCRName = "Arabic Presentation Forms-A"; break; /: U+FB50-U+FDFF :/
         nStart = 0xFB50;
         nCount = 0xFDFF - nStart + 1;
         memset(this.m_pRanges, nStart, 31, nCount);
         memset(this.m_pRangesNums, nStart, 1, nCount);

         // rangeNum 2
         //case 00: sUCRName = "Combining Half Marks"; break; /: U+FE20-U+FE2F :/
         nStart = 0xFE20;
         nCount = 0xFE2F - nStart + 1;
         memset(this.m_pRanges, nStart, 0, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 01: sUCRName = "Vertical forms"; break; /: U+FE10-U+FE1F :/ /: U+FE30-U+FE4F :/
         nStart = 0xFE10;
         nCount = 0xFE1F - nStart + 1;
         memset(this.m_pRanges, nStart, 1, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         nStart = 0xFE30;
         nCount = 0xFE4F - nStart + 1;
         memset(this.m_pRanges, nStart, 1, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 02: sUCRName = "Small Form Variants"; break; /: U+FE50-U+FE6F :/
         nStart = 0xFE50;
         nCount = 0xFE6F - nStart + 1;
         memset(this.m_pRanges, nStart, 2, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 03: sUCRName = "Arabic Presentation Forms-B"; break; /: U+FE70-U+FEFE :/
         nStart = 0xFE70;
         nCount = 0xFEFE - nStart + 1;
         memset(this.m_pRanges, nStart, 3, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 04: sUCRName = "Halfwidth and Fullwidth Forms"; break; /: U+FF00-U+FFEF :/
         nStart = 0xFF00;
         nCount = 0xFFEF - nStart + 1;
         memset(this.m_pRanges, nStart, 4, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 05: sUCRName = "Specials"; break; /: U+FFF0-U+FFFF :/
         nStart = 0xFFF0;
         nCount = 0xFFFF - nStart + 1;
         memset(this.m_pRanges, nStart, 5, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 06: sUCRName = "Tibetan"; break; /: U+0F00-U+0FFF :/
         nStart = 0x0F00;
         nCount = 0x0FFF - nStart + 1;
         memset(this.m_pRanges, nStart, 6, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 07: sUCRName = "Syriac"; break; /: U+0700-U+074F :/
         nStart = 0x0700;
         nCount = 0x074F - nStart + 1;
         memset(this.m_pRanges, nStart, 7, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 08: sUCRName = "Thaana"; break; /: U+0780-U+07BF :/
         nStart = 0x0780;
         nCount = 0x07BF - nStart + 1;
         memset(this.m_pRanges, nStart, 8, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 09: sUCRName = "Sinhala"; break; /: U+0D80-U+0DFF :/
         nStart = 0x0D80;
         nCount = 0x0DFF - nStart + 1;
         memset(this.m_pRanges, nStart, 9, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 10: sUCRName = "Myanmar"; break; /: U+1000-U+109F :/
         nStart = 0x1000;
         nCount = 0x109F - nStart + 1;
         memset(this.m_pRanges, nStart, 10, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 11: sUCRName = "Ethiopic"; break; /: U+1200-U+137F :/ /: U+1380-U+139F :/ /: U+2D80-U+2DDF :/
         nStart = 0x1200;
         nCount = 0x137F - nStart + 1;
         memset(this.m_pRanges, nStart, 11, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         nStart = 0x1380;
         nCount = 0x139F - nStart + 1;
         memset(this.m_pRanges, nStart, 11, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         nStart = 0x2D80;
         nCount = 0x2DDF - nStart + 1;
         memset(this.m_pRanges, nStart, 11, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 12: sUCRName = "Cherokee"; break; /: U+13A0-U+13FF :/
         nStart = 0x13A0;
         nCount = 0x13FF - nStart + 1;
         memset(this.m_pRanges, nStart, 12, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 13: sUCRName = "Unified Canadian Aboriginal Syllabics"; break; /: U+1400-U+167F :/
         nStart = 0x1400;
         nCount = 0x167F - nStart + 1;
         memset(this.m_pRanges, nStart, 13, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 14: sUCRName = "Ogham"; break; /: U+1680-U+169F :/
         nStart = 0x1680;
         nCount = 0x169F - nStart + 1;
         memset(this.m_pRanges, nStart, 14, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 15: sUCRName = "Runic"; break; /: U+16A0-U+16FF :/
         nStart = 0x16A0;
         nCount = 0x16FF - nStart + 1;
         memset(this.m_pRanges, nStart, 15, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 16: sUCRName = "Khmer"; break; /: U+1780-U+17FF :/ /: U+19E0-U+19FF :/
         nStart = 0x1780;
         nCount = 0x17FF - nStart + 1;
         memset(this.m_pRanges, nStart, 16, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         nStart = 0x19E0;
         nCount = 0x19FF - nStart + 1;
         memset(this.m_pRanges, nStart, 16, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 17: sUCRName = "Mongolian"; break; /: U+1800-U+18AF :/
         nStart = 0x1800;
         nCount = 0x18AF - nStart + 1;
         memset(this.m_pRanges, nStart, 17, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 18: sUCRName = "Braille Patterns"; break; /: U+2800-U+28FF :/
         nStart = 0x2800;
         nCount = 0x28FF - nStart + 1;
         memset(this.m_pRanges, nStart, 18, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 19: sUCRName = "Yi Syllables"; break; /: U+A000-U+A48F :/ /: U+A490-U+A4CF :/
         nStart = 0xA000;
         nCount = 0xA48F - nStart + 1;
         memset(this.m_pRanges, nStart, 19, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         nStart = 0xA490;
         nCount = 0xA4CF - nStart + 1;
         memset(this.m_pRanges, nStart, 19, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 20: sUCRName = "Tagalog"; break; /: U+1700-U+171F :/ /: U+1720-U+173F :/ /: U+1740-U+175F :/ /: U+1760-U+177F :/
         nStart = 0x1700;
         nCount = 0x171F - nStart + 1;
         memset(this.m_pRanges, nStart, 20, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         nStart = 0x1720;
         nCount = 0x173F - nStart + 1;
         memset(this.m_pRanges, nStart, 20, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         nStart = 0x1740;
         nCount = 0x175F - nStart + 1;
         memset(this.m_pRanges, nStart, 20, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         nStart = 0x1760;
         nCount = 0x177F - nStart + 1;
         memset(this.m_pRanges, nStart, 20, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 21: sUCRName = "Old Italic"; break; /:U+10300-U+1032F:/
         //case 22: sUCRName = "Gothic"; break; /:U+10330-U+1034F:/
         //case 23: sUCRName = "Deseret"; break; /:U+10400-U+1044F:/
         //case 24: sUCRName = "Byzantine Musical Symbols"; break; /:U+1D000-U+1D0FF:/ /:U+1D100-U+1D1FF:/ /:U+1D200-U+1D24F:/
         //case 25: sUCRName = "Mathematical Alphanumeric Symbols"; break; /:U+1D400-U+1D7FF:/
         //case 26: sUCRName = "Private Use (plane 15)"; break; /:U+F0000-U+FFFFD:/ /:U+100000-U+10FFFD:/ // Не юникодные символы

         //case 27: sUCRName = "Variation Selectors"; break; /: U+FE00-U+FE0F :/ /:U+E0100-U+E01EF:/
         nStart = 0xFE00;
         nCount = 0xFE0F - nStart + 1;
         memset(this.m_pRanges, nStart, 27, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 28: sUCRName = "Tags"; break; /:U+E0000-U+E007F:/
         //case 29: sUCRName = "Limbu"; break; /: U+1900-U+194F :/
         nStart = 0x1900;
         nCount = 0x194F - nStart + 1;
         memset(this.m_pRanges, nStart, 29, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 30: sUCRName = "Tai Le"; break; /: U+1950-U+197F :/
         nStart = 0x1950;
         nCount = 0x197F - nStart + 1;
         memset(this.m_pRanges, nStart, 30, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         //case 31: sUCRName = "New Tai Lue"; break; /: U+1980-U+19DF :/
         nStart = 0x1980;
         nCount = 0x19DF - nStart + 1;
         memset(this.m_pRanges, nStart, 31, nCount);
         memset(this.m_pRangesNums, nStart, 2, nCount);

         // rangeNum 3
         //case 00: sUCRName = "Buginese"; break; /: U+1A00-U+1A1F :/
         nStart = 0x1A00;
         nCount = 0x1A1F - nStart + 1;
         memset(this.m_pRanges, nStart, 0, nCount);
         memset(this.m_pRangesNums, nStart, 3, nCount);

         //case 01: sUCRName = "Glagolitic"; break; /: U+2C00-U+2C5F :/
         nStart = 0x2C00;
         nCount = 0x2C5F - nStart + 1;
         memset(this.m_pRanges, nStart, 1, nCount);
         memset(this.m_pRangesNums, nStart, 3, nCount);

         //case 02: sUCRName = "Tifinagh"; break; /: U+2D30-U+2D7F :/
         nStart = 0x2D30;
         nCount = 0x2D7F - nStart + 1;
         memset(this.m_pRanges, nStart, 2, nCount);
         memset(this.m_pRangesNums, nStart, 3, nCount);

         //case 03: sUCRName = "Yijing Hexagram Symbols"; break; /: U+4DC0-U+4DFF :/
         nStart = 0x4DC0;
         nCount = 0x4DFF - nStart + 1;
         memset(this.m_pRanges, nStart, 3, nCount);
         memset(this.m_pRangesNums, nStart, 3, nCount);

         //case 04: sUCRName = "Syloti Nagri"; break; /: U+A800-U+A82F :/
         nStart = 0xA800;
         nCount = 0xA82F - nStart + 1;
         memset(this.m_pRanges, nStart, 4, nCount);
         memset(this.m_pRangesNums, nStart, 3, nCount);

         //case 05: sUCRName = "Linear B Syllabary"; break; /:U+10000-U+1007F:/ /:U+10080-U+100FF:/ /:U+10100-U+1013F:/
         //case 06: sUCRName = "Ancient Greek Numbers"; break; /:U+10140-U+1018F:/
         //case 07: sUCRName = "Ugaritic"; break; /:U+10380-U+1039F:/
         //case 08: sUCRName = "Old Persian"; break; /:U+103A0-U+103DF:/
         //case 09: sUCRName = "Shavian"; break; /:U+10450-U+1047F:/
         //case 10: sUCRName = "Osmanya"; break; /:U+10480-U+104AF:/
         //case 11: sUCRName = "Cypriot Syllabary"; break; /:U+10800-U+1083F:/
         //case 12: sUCRName = "Kharoshthi"; break; /:U+10A00-U+10A5F:/
         //case 13: sUCRName = "Tai Xuan Jing Symbols"; break; /:U+1D300-U+1D35F:/
         //case 14: sUCRName = "Cuneiform"; break; /:U+12000-U+123FF:/ /:U+12400-U+1247F:/
         //case 15: sUCRName = "Counting Rod Numerals"; break; /:U+1D360-U+1D37F:/

         //case 16: sUCRName = "Sundanese"; break; /: U+1B80-U+1BBF :/
         nStart = 0x1B80;
         nCount = 0x1BBF - nStart + 1;
         memset(this.m_pRanges, nStart, 16, nCount);
         memset(this.m_pRangesNums, nStart, 3, nCount);

         //case 17: sUCRName = "Lepcha"; break; /: U+1C00-U+1C4F :/
         nStart = 0x1C00;
         nCount = 0x1C4F - nStart + 1;
         memset(this.m_pRanges, nStart, 17, nCount);
         memset(this.m_pRangesNums, nStart, 3, nCount);

         //case 18: sUCRName = "Ol Chiki"; break; /: U+1C50-U+1C7F :/
         nStart = 0x1C50;
         nCount = 0x1C7F - nStart + 1;
         memset(this.m_pRanges, nStart, 18, nCount);
         memset(this.m_pRangesNums, nStart, 3, nCount);

         //case 19: sUCRName = "Saurashtra"; break; /: U+A880-U+A8DF :/
         nStart = 0xA880;
         nCount = 0xA8DF - nStart + 1;
         memset(this.m_pRanges, nStart, 19, nCount);
         memset(this.m_pRangesNums, nStart, 3, nCount);

         //case 20: sUCRName = "Kayah Li"; break; /: U+A900-U+A92F :/
         nStart = 0xA900;
         nCount = 0xA92F - nStart + 1;
         memset(this.m_pRanges, nStart, 20, nCount);
         memset(this.m_pRangesNums, nStart, 3, nCount);

         //case 21: sUCRName = "Rejang"; break; /: U+A930-U+A95F :/
         nStart = 0xA930;
         nCount = 0xA95F - nStart + 1;
         memset(this.m_pRanges, nStart, 21, nCount);
         memset(this.m_pRangesNums, nStart, 3, nCount);

         //case 22: sUCRName = "Cham"; break; /: U+AA00-U+AA5F :/
         nStart = 0xAA00;
         nCount = 0xAA5F - nStart + 1;
         memset(this.m_pRanges, nStart, 22, nCount);
         memset(this.m_pRangesNums, nStart, 3, nCount);

         //case 23: sUCRName = "Ancient Symbols"; break; /:U+10190-U+101CF:/
         //case 24: sUCRName = "Phaistos Disc"; break; /:U+101D0-U+101FF:/
         //case 25: sUCRName = "Carian"; break; /:U+102A0-U+102DF:/ /:U+10280-U+1029F:/ /:U+10920-U+1093F:/
         //case 26: sUCRName = "Domino Tiles"; break; /:U+1F030-U+1F09F:/ /:U+1F000-U+1F02F:/
         //case 27: sUCRName = "Reserved for process-internal usage"; break;
         //case 28: sUCRName = "Reserved for process-internal usage"; break;
         //case 29: sUCRName = "Reserved for process-internal usage"; break;
         //case 30: sUCRName = "Reserved for process-internal usage"; break;
         //case 31: sUCRName = "Reserved for process-internal usage"; break;

         */
    }
};

function CApplicationFonts()
{
    this.FontPickerMap = {};

    this.g_fontDictionary = new FD_FontDictionary();
    this.g_fontSelections = new CFontSelectList();
    this.DefaultIndex = 0;

    this.Init = function()
    {
        this.g_fontDictionary.Init();
        this.g_fontSelections.Init();

        var oSelect = new CFontSelectFormat();
        oSelect.wsName = "Arial";

        this.DefaultIndex = this.g_fontDictionary.GetFontIndex(oSelect, this.g_fontSelections.List, undefined);
    };

    this.LoadFont = function(name, font_loader, fontManager, fEmSize, lStyle, dHorDpi, dVerDpi, transform, objDst)
    {
        var _font = this.GetFontFileWeb(name, lStyle);
        var font_name_index = AscFonts.g_map_font_index[_font.m_wsFontName];
        if (undefined !== objDst)
        {
            objDst.Name = _font.m_wsFontName;
            objDst.Replace = this.CheckReplaceGlyphsMap(name, objDst);
        }

        // используем стиль, пришедший извне, а не стиль _font
        // так как подвираем вез стиля в Web версии
        return AscFonts.g_font_infos[font_name_index].LoadFont(AscCommon.g_font_loader, fontManager, fEmSize, /*_font.GetStyle()*/lStyle, dHorDpi, dVerDpi, transform);
    };

    this.CheckReplaceGlyphsMap = function(name, objDst)
    {
        var _replaceInfo = this.g_fontDictionary.ChangeGlyphsMap[name];
        if (!_replaceInfo)
            return null;
        if (_replaceInfo.Name != objDst.Name)
            return null;
        return _replaceInfo;
    };

    this.GetReplaceGlyph = function(src, objDst)
    {
        // TODO: must be faster!!!
        var _arr = objDst.MapSrc;
        var _arrLen = _arr.length;

        for (var i = 0; i < _arrLen; i++)
        {
            if (_arr[i] == src)
                return objDst.MapDst[i];

            if (objDst.IsSymbolSrc && (src == (0xF000 + _arr[i])))
            {
                return objDst.MapDst[i];
            }
        }
    };

    this.GetFontFile = function(name, lStyle)
    {
        if (lStyle === undefined)
            lStyle = 0;

        var _key = "s" + lStyle + "_";
        _key += name;

        if (undefined !== this.FontPickerMap[_key])
        {
            return this.FontPickerMap[_key];
        }
        else
        {
            var oSelect = new CFontSelectFormat();
            oSelect.wsName = name;
            oSelect.bItalic = false;
            oSelect.bBold = false;

            var _font = this.GetFontIndex(oSelect);
            this.FontPickerMap[_key] = _font;
            return _font;
        }
    };

    this.GetFontFileWeb = function(name, lStyle)
    {
        // здесь не учитываем стиль. Иначе будет проблемой загрузка шрифтов,
        if (undefined !== this.FontPickerMap[name])
        {
            return this.FontPickerMap[name];
        }
        else
        {
            var oSelect = new CFontSelectFormat();
            oSelect.wsName = name;

            var _font = this.GetFontIndex(oSelect, true);
            this.FontPickerMap[name] = _font;
            return _font;
        }
    };

    this.GetFontInfo = function(name, lStyle, objDst)
    {
        var _font = this.GetFontFileWeb(name, lStyle);
        var font_name_index = AscFonts.g_map_font_index[_font.m_wsFontName];

        if (undefined !== objDst)
        {
            objDst.Name = _font.m_wsFontName;
            objDst.Replace = this.CheckReplaceGlyphsMap(name, objDst);
        }

        return AscFonts.g_font_infos[font_name_index];
    };
    this.GetFontInfoName = function(name, objDst)
    {
        var _font = this.GetFontFileWeb(name);

        if (undefined !== objDst)
        {
            objDst.Name = _font.m_wsFontName;
            objDst.Replace = this.CheckReplaceGlyphsMap(name, objDst);
        }

        return _font.m_wsFontName;
    };

    this.GetFontIndex = function(oSelect, isName0)
    {
        return this.g_fontDictionary.GetFontIndex(oSelect, this.g_fontSelections.List, this.DefaultIndex, isName0);
    };

    this.GetFontNameDictionary = function(sFontFamily, bDontReturnDef)
    {
        var sFontname;
        var nIndex = sFontFamily.indexOf(",");
        if(-1 != nIndex)
            sFontname = sFontFamily.substring(0, nIndex);
        else
            sFontname = sFontFamily;
        //trim { }, {'}, {"}
        sFontname = sFontname.replace(/^[\s'"]+|[\s'"]+$/g, '');
        if (0 == sFontname.length)
        {
            if (true === bDontReturnDef)
                sFontname = "Arial";
        }
        else
        {
            var sFontnameLower = sFontname.toLowerCase();
            if("serif" == sFontnameLower)
                sFontname = "Times New Roman";
            else if("sans-serif" == sFontnameLower)
                sFontname = "Arial";
            else if("cursive" == sFontnameLower)
                sFontname = "Comic Sans MS";
            else if("fantasy" == sFontnameLower)
                sFontname = "Impact";
            else if("monospace" == sFontnameLower)
                sFontname = "Courier New";
            else
            {
                var oSelect = new CFontSelectFormat();
                oSelect.wsName = sFontname;
                this.g_fontDictionary.CorrectParamsFromDictionary(oSelect);

                if (null != oSelect.pPanose)
                    return oSelect.wsName;
                else
                {
                    return this.GetFontInfoName(sFontname);
                }
            }
        }
        return sFontname;
    };
}

var g_fontApplication = new CApplicationFonts();

    //------------------------------------------------------export------------------------------------------------------
    window['AscFonts'] = window['AscFonts'] || {};
    window['AscFonts'].FontStyle = FontStyle;
    window['AscFonts'].DecodeBase64Char = DecodeBase64Char;
    window['AscFonts'].b64_decode = b64_decode;
    window['AscFonts'].CreateFontData2 = CreateFontData2;
    window['AscFonts'].CreateFontData3 = CreateFontData3;
    window['AscFonts'].CreateFontData4 = CreateFontData4;
    window['AscFonts'].LanguagesFontSelectTypes = LanguagesFontSelectTypes;

    window['AscFonts'].g_fontApplication = g_fontApplication;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined) {

    function CRasterHeapLineFree()
    {
        this.Y      = 0;
        this.Height = 0;
    }

    function CRasterDataInfo()
    {
        this.Chunk = null;
        this.Line = null;
        this.Index = 0;
    }

    function CRasterHeapLine()
    {
        this.Y = 0;
        this.Height = 0;
        this.Count = 0;
        this.CountBusy = 0;
        this.Images = null;
        this.Index = 0;
    }
    CRasterHeapLine.prototype =
    {
        CreatePlaces : function(width, height, widthLine)
        {
            this.Height = height;
            this.Count = (widthLine / width) >> 0;

            var _size = this.Count;
            var arr = null;
            if (typeof(Int8Array) != 'undefined' && !window.opera)
                arr = new Int8Array(_size);
            else
                arr = new Array(_size);

            for (var i=0;i<_size;i++)
                arr[i] = 0;

            this.Images = arr;
        },

        Alloc : function()
        {
            if (this.Count == this.CountBusy)
                return -1;

            var arr = this.Images;
            if (arr[this.CountBusy] == 0)
            {
                arr[this.CountBusy] = 1;
                this.CountBusy += 1;
                return this.CountBusy - 1;
            }

            var _len = this.Count;
            for (var i = 0; i < _len; i++)
            {
                if (arr[i] == 0)
                {
                    arr[i] = 1;
                    this.CountBusy += 1;
                    return i;
                }
            }
            return -1;
        },

        Free : function(index)
        {
            if (this.Images[index] == 1)
            {
                this.Images[index] = 0;
                this.CountBusy -= 1;
            }
            return this.CountBusy;
        }
    };

    function CRasterHeapChuck()
    {
        this.CanvasImage    = null;
        this.CanvasCtx      = null;

        this.Width  = 0;
        this.Height = 0;

        this.LinesFree = [];
        this.LinesBusy = [];

        this.CurLine = null;

        this.FindOnlyEqualHeight = false;
    }
    CRasterHeapChuck.prototype =
    {
        Create : function(width, height)
        {
            this.Width  = width;
            this.Height = height;

            this.CanvasImage = document.createElement('canvas');
            this.CanvasImage.width  = width;
            this.CanvasImage.height = height;

            this.CanvasCtx = this.CanvasImage.getContext('2d');
            this.CanvasCtx.globalCompositeOperation = "source-atop";

            var _freeLine = new CRasterHeapLineFree();
            _freeLine.Y         = 0;
            _freeLine.Height    = this.Height;
            this.LinesFree[0]   = _freeLine;
        },

        Clear : function()
        {
            this.LinesBusy.splice(0, this.LinesBusy.length);
            this.LinesFree.splice(0, this.LinesFree.length);

            var _freeLine = new CRasterHeapLineFree();
            _freeLine.Y         = 0;
            _freeLine.Height    = this.Height;
            this.LinesFree[0]   = _freeLine;
        },

        Alloc : function(width, height)
        {
            var _need_height = Math.max(width, height);
            var _busy_len = this.LinesBusy.length;
            for (var i = 0; i < _busy_len; i++)
            {
                var _line = this.LinesBusy[i];
                if (_line.Height >= _need_height)
                {
                    var _index = _line.Alloc();
                    if (-1 != _index)
                    {
                        var _ret = new CRasterDataInfo();
                        _ret.Chunk = this;
                        _ret.Line = _line;
                        _ret.Index = _index;
                        return _ret;
                    }
                }
            }

            // линию не нашли. Начинаем искать из свободной памяти
            // ищем 3/2 от нужного размера. и параллельно 1
            var _need_height1 = (3 * _need_height) >> 1;
            if (this.FindOnlyEqualHeight)
                _need_height1 = _need_height;

            var _free_len = this.LinesFree.length;
            var _index_found_koef1 = -1;
            for (var i = 0; i < _free_len; i++)
            {
                var _line = this.LinesFree[i];
                if (_line.Height >= _need_height1)
                {
                    // нашли
                    var _new_line = new CRasterHeapLine();
                    _new_line.CreatePlaces(_need_height1, _need_height1, this.Width);
                    _new_line.Y = _line.Y;
                    _new_line.Index = this.LinesBusy.length;
                    this.LinesBusy.push(_new_line);

                    _line.Y += _need_height1;
                    _line.Height -= _need_height1;

                    if (_line.Height == 0)
                        this.LinesFree.splice(i, 1);

                    var _ret = new CRasterDataInfo();
                    _ret.Chunk = this;
                    _ret.Line = _new_line;
                    _ret.Index = _new_line.Alloc();
                    return _ret;
                }
                else if (_line.Height >= _need_height && -1 == _index_found_koef1)
                {
                    _index_found_koef1 = i;
                }
            }

            // 3/2 не нашли. если нашли для 1, то выделяем там
            if (-1 != _index_found_koef1)
            {
                var _line = this.LinesFree[_index_found_koef1];

                var _new_line = new CRasterHeapLine();
                _new_line.CreatePlaces(_need_height, _need_height, this.Width);
                _new_line.Y = _line.Y;
                _new_line.Index = this.LinesBusy.length;
                this.LinesBusy.push(_new_line);

                _line.Y += _need_height;
                _line.Height -= _need_height;

                if (_line.Height == 0)
                    this.LinesFree.splice(i, 1);

                var _ret = new CRasterDataInfo();
                _ret.Chunk = this;
                _ret.Line = _new_line;
                _ret.Index = _new_line.Alloc();
                return _ret;
            }

            // не нашли.
            return null;
        },

        Free : function(obj)
        {
            var _refs = obj.Line.Free(obj.Index);
            if (_refs == 0)
            {
                // нужно удалить линию и перебить всем оставшимся индексы

                var _line = obj.Line;
                this.LinesBusy.splice(_line.Index, 1);

                var _lines_busy = this.LinesBusy;
                var _busy_len = _lines_busy.length;
                for (var i = _line.Index; i < _busy_len; i++)
                    _lines_busy[i].Index = i;

                // теперь нужно поправить linesfree
                var y1 = _line.Y;
                var y2 = _line.Y + _line.Height;
                var _lines_free = this.LinesFree;
                var _free_len = _lines_free.length;

                var _ind_prev = -1;
                var _ind_next = -1;
                for (var i = 0; i < _free_len; i++)
                {
                    var _line_f = _lines_free[i];
                    if (-1 == _ind_prev)
                    {
                        if (y1 == (_line_f.Y + _line_f.Height))
                            _ind_prev = i;
                    }
                    else if (-1 == _ind_next)
                    {
                        if (y2 == _line_f.Y)
                            _ind_next = i;
                    }
                    else
                    {
                        break;
                    }
                }

                // нашли прилегаюую свободную память. теперь нужно их склеить, или создать новую
                if (-1 != _ind_prev && -1 != _ind_next)
                {
                    _lines_free[_ind_prev].Height += (_line.Height + _lines_free[_ind_next].Height);
                    _lines_free.splice(_ind_next, 1);
                }
                else if (-1 != _ind_prev)
                {
                    _lines_free[_ind_prev].Height += _line.Height;
                }
                else if (-1 != _ind_next)
                {
                    _lines_free[_ind_next].Y -= _line.Height;
                    _lines_free[_ind_next].Height += _line.Height;
                }
                else
                {
                    var _new_line = new CRasterHeapLineFree();
                    _new_line.Y = _line.Y;
                    _new_line.Height = _line.Height;
                    _lines_free.push(_new_line);
                }
                _line = null;
            }
        }
    };

    function CRasterHeapTotal(_size)
    {
        this.ChunkHeapSize = (undefined === _size) ? 3000 : _size; // 4 * 3000 * 3000 = 36Mb
        this.Chunks = [];
    }
    CRasterHeapTotal.prototype =
    {
        Clear : function()
        {
            var _len = this.Chunks.length;
            for (var i = 0; i < _len; i++)
            {
                this.Chunks[i].Clear();
            }

            // теперь наверное удалим и память лишнюю
            if (_len > 1)
                this.Chunks.splice(1, _len - 1);
        },

        Alloc : function(width, height)
        {
            var _len = this.Chunks.length;
            for (var i = 0; i < _len; i++)
            {
                var _ret = this.Chunks[i].Alloc(width, height);
                if (null != _ret)
                    return _ret;
            }
            this.HeapAlloc(this.ChunkHeapSize, this.ChunkHeapSize);
            return this.Chunks[_len].Alloc(width, height);
        },

        HeapAlloc : function(width, height)
        {
            var _chunk = new CRasterHeapChuck();
            _chunk.Create(width, height);
            this.Chunks[this.Chunks.length] = _chunk;
        },

        CreateFirstChuck : function(_w, _h)
        {
            if (0 == this.Chunks.length)
            {
                this.Chunks[0] = new CRasterHeapChuck();
                this.Chunks[0].Create((undefined == _w) ? this.ChunkHeapSize : _w, (undefined == _h) ? this.ChunkHeapSize : _h);
            }
        }
    };

    window['AscFonts'] = window['AscFonts'] || {};
    window['AscFonts'].CRasterHeapTotal = CRasterHeapTotal;

})(window, undefined);
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined) {

    function CGlyphRect()
    {
        this.fX = 0;
        this.fY = 0;
        this.fWidth = 0;
        this.fHeight = 0;
    }

    function CGlyphBounds()
    {
        this.fLeft = 0;
        this.fTop = 0;
        this.fRight = 0;
        this.fBottom = 0;
    }
    CGlyphBounds.prototype =
    {
        checkPoint : function(x, y)
        {
            if (x < this.fLeft)
                this.fLeft = x;
            if (x > this.fRight)
                this.fRight = x;
            if (y < this.fTop)
                this.fTop = y;
            if (y > this.fBottom)
                this.fBottom = y;
        }
    };

    function CGlyph()
    {
        this.lUnicode = 0; // Юникод
        this.fX = 0;       // Позиция глифа
        this.fY = 0;       // на BaseLine

        this.fLeft = 0;    //
        this.fTop = 0;     // BBox
        this.fRight = 0;   //
        this.fBottom = 0;  //

        this.oMetrics = null;

        this.eState = AscFonts.EGlyphState.glyphstateNormal;

        this.bBitmap = false;
        this.oBitmap = null;

        this.Clear = function()
        {
            this.bBitmap = false;
            this.eState = AscFonts.EGlyphState.glyphstateNormal;
        };
    }

    function CGlyphString()
    {
        this.m_fX = 0;
        this.m_fY = 0;

        this.m_fEndX = 0;
        this.m_fEndY = 0;

        this.m_nGlyphIndex   = -1;
        this.m_nGlyphsCount  = 0;
        this.m_pGlyphsBuffer = new Array(100);

        this.m_arrCTM = [];
        this.m_dIDet = 1;

        this.m_fTransX = 0;
        this.m_fTransY = 0;

        this.GetFirstGlyph = function()
        {
            if (!this.m_pGlyphsBuffer[0])
                this.m_pGlyphsBuffer[0] = new CGlyph();
            return this.m_pGlyphsBuffer[0];
        };

        this.SetString = function(wsString, fX, fY)
        {
            this.m_fX = fX + this.m_fTransX;
            this.m_fY = fY + this.m_fTransY;

            this.m_nGlyphsCount = wsString.length;
            this.m_nGlyphIndex  = 0;

            for (var nIndex = 0; nIndex < this.m_nGlyphsCount; ++nIndex)
            {
                if (undefined == this.m_pGlyphsBuffer[nIndex])
                    this.m_pGlyphsBuffer[nIndex] = new CGlyph();
                else
                    this.m_pGlyphsBuffer[nIndex].Clear();

                this.m_pGlyphsBuffer[nIndex].lUnicode = wsString.charCodeAt(nIndex);
            }
        };

        this.SetStringGID = function(gid, fX, fY)
        {
            this.m_fX = fX + this.m_fTransX;
            this.m_fY = fY + this.m_fTransY;

            this.m_nGlyphsCount = 1;
            this.m_nGlyphIndex  = 0;

            if (undefined == this.m_pGlyphsBuffer[0])
                this.m_pGlyphsBuffer[0] = new CGlyph();
            else
                this.m_pGlyphsBuffer[0].Clear();

            this.m_pGlyphsBuffer[0].lUnicode = gid;
        };

        this.GetLength = function()
        {
            return this.m_nGlyphsCount;
        };

        this.GetAt = function(nIndex)
        {
            if (this.m_nGlyphsCount <= 0)
                return null;

            var nCurIndex = (nIndex < 0) ? 0 : nIndex;
            if (nCurIndex >= this.m_nGlyphsCount)
                nCurIndex = this.m_nGlyphsCount - 1;

            return this.m_pGlyphsBuffer[nCurIndex];
        };

        this.SetStartPoint = function(nIndex, fX, fY)
        {
            if (this.m_nGlyphsCount <= 0)
                return;

            var nCurIndex = (nIndex < 0) ? 0 : nIndex;
            if (nCurIndex >= this.m_nGlyphsCount)
                nCurIndex = this.m_nGlyphsCount - 1;

            this.m_pGlyphsBuffer[nCurIndex].fX = fX;
            this.m_pGlyphsBuffer[nCurIndex].fY = fY;
        };

        this.SetState = function(nIndex, eState)
        {
            if (this.m_nGlyphsCount <= 0)
                return;

            var nCurIndex = (nIndex < 0) ? 0 : nIndex;
            if (nCurIndex >= this.m_nGlyphsCount)
                nCurIndex = this.m_nGlyphsCount - 1;

            this.m_pGlyphsBuffer[nCurIndex].eState = eState;
        };

        this.SetBBox = function (nIndex, fLeft, fTop, fRight, fBottom)
        {
            if (this.m_nGlyphsCount <= 0)
                return;

            var nCurIndex = (nIndex < 0) ? 0 : nIndex;
            if (nCurIndex >= this.m_nGlyphsCount)
                nCurIndex = this.m_nGlyphsCount - 1;

            var _g = this.m_pGlyphsBuffer[nCurIndex];
            _g.fLeft   = fLeft;
            _g.fTop    = fTop;
            _g.fRight  = fRight;
            _g.fBottom = fBottom;
        };

        this.SetMetrics = function (nIndex, fWidth, fHeight, fHoriAdvance, fHoriBearingX, fHoriBearingY, fVertAdvance, fVertBearingX, fVertBearingY)
        {
            if (this.m_nGlyphsCount <= 0)
                return;

            var nCurIndex = (nIndex < 0) ? 0 : nIndex;
            if (nCurIndex >= this.m_nGlyphsCount)
                nCurIndex = this.m_nGlyphsCount - 1;

            var _g = this.m_pGlyphsBuffer[nCurIndex];
            _g.oMetrics.fHeight       = fHeight;
            _g.oMetrics.fHoriAdvance  = fHoriAdvance;
            _g.oMetrics.fHoriBearingX = fHoriBearingX;
            _g.oMetrics.fHoriBearingY = fHoriBearingY;
            _g.oMetrics.fVertAdvance  = fVertAdvance;
            _g.oMetrics.fVertBearingX = fVertBearingX;
            _g.oMetrics.fVertBearingY = fVertBearingY;
            _g.oMetrics.fWidth        = fWidth;
        };

        this.ResetCTM = function()
        {
            var m = this.m_arrCTM;
            m[0] = 1;
            m[1] = 0;
            m[2] = 0;
            m[3] = 1;
            m[4] = 0;
            m[5] = 0;

            this.m_dIDet      = 1;
        };

        this.GetBBox = function(nIndex, nType)
        {
            var oPoint = new CGlyphBounds();
            if (typeof nIndex == "undefined")
                nIndex = -1;
            if (typeof nType == "undefined")
                nType = 0;

            var nCurIndex = 0;
            if (nIndex < 0)
            {
                if (this.m_nGlyphsCount <= 0 || this.m_nGlyphIndex < 1 || this.m_nGlyphIndex > this.m_nGlyphsCount)
                    return oPoint;

                nCurIndex = this.m_nGlyphIndex - 1;
            }
            else
            {
                if (this.m_nGlyphsCount <= 0)
                    return oPoint;

                nCurIndex = (nIndex < 0) ? 0 : nIndex;
                if (nCurIndex >= this.m_nGlyphsCount)
                    nCurIndex = this.m_nGlyphsCount - 1;
            }

            var _g = this.m_pGlyphsBuffer[nCurIndex];
            var m = this.m_arrCTM;

            var fBottom = -_g.fBottom;
            var fRight  =  _g.fRight;
            var fLeft   =  _g.fLeft;
            var fTop    = -_g.fTop;


            if (0 == nType && !(1 == m[0] && 0 == m[1] && 0 == m[2] && 1 == m[3] && 0 == m[4] && 0 == m[5]))
            {
                // Применяем глобальную матрицу преобразования и пересчитываем BBox
                var arrfX =[fLeft, fLeft, fRight, fRight];
                var arrfY = [fTop, fBottom, fBottom, fTop];

                var fMinX = (arrfX[0] * m[0] + arrfY[0] * m[2]);
                var fMinY = (arrfX[0] * m[1] + arrfY[0] * m[3]);
                var fMaxX = fMinX;
                var fMaxY = fMinY;

                for (var nIndex = 1; nIndex < 4; ++nIndex)
                {
                    var fX = (arrfX[nIndex] * m[0] + arrfY[nIndex] * m[2]);
                    var fY = (arrfX[nIndex] * m[1] + arrfY[nIndex] * m[3]);

                    fMaxX = Math.max(fMaxX, fX);
                    fMinX = Math.min(fMinX, fX);

                    fMaxY = Math.max(fMaxY, fY);
                    fMinY = Math.min(fMinY, fY);
                }

                fLeft   = fMinX;
                fRight  = fMaxX;
                fTop    = fMinY;
                fBottom = fMaxY;
            }

            oPoint.fLeft   = fLeft   + _g.fX + this.m_fX;
            oPoint.fRight  = fRight  + _g.fX + this.m_fX;
            oPoint.fTop    = fTop    + _g.fY + this.m_fY;
            oPoint.fBottom = fBottom + _g.fY + this.m_fY;

            return oPoint;
        };

        this.GetBBox2 = function()
        {
            var oPoint = new CGlyphBounds();
            if (this.m_nGlyphsCount <= 0)
                return oPoint;

            var fBottom = 0;
            var fRight  = 0;
            var fLeft   = 0;
            var fTop    = 0;

            for (var nIndex = 0; nIndex < this.m_nGlyphsCount; ++nIndex)
            {
                fBottom = Math.max(fBottom, -this.m_pGlyphsBuffer[nIndex].fBottom);
                fTop    = Math.min(fTop, -this.m_pGlyphsBuffer[nIndex].fTop);
            }

            var m = this.m_arrCTM;
            if (!(1 == m[0] && 0 == m[1] && 0 == m[2] && 1 == m[3] && 0 == m[4] && 0 == m[5]))
            {
                // Применяем глобальную матрицу преобразования и пересчитываем BBox
                var arrfX = [fLeft, fLeft, fRight, fRight];
                var arrfY = [fTop, fBottom, fBottom, fTop];

                var fMinX = (arrfX[0] * m[0] + arrfY[0] * m[2]);
                var fMinY = (arrfX[0] * m[1] + arrfY[0] * m[3]);
                var fMaxX = fMinX;
                var fMaxY = fMinY;

                for (var nIndex = 1; nIndex < 4; ++nIndex)
                {
                    var fX = (arrfX[nIndex] * m[0] + arrfY[nIndex] * m[2]);
                    var fY = (arrfX[nIndex] * m[1] + arrfY[nIndex] * m[3]);

                    fMaxX = Math.max (fMaxX, fX);
                    fMinX = Math.min (fMinX, fX);

                    fMaxY = Math.max (fMaxY, fY);
                    fMinY = Math.min (fMinY, fY);
                }

                fLeft   = fMinX;
                fRight  = fMaxX;
                fTop    = fMinY;
                fBottom = fMaxY;
            }

            fLeft   += this.m_fX;
            fRight  += this.m_fX;
            fTop    += this.m_fY;
            fBottom += this.m_fY;

            oPoint.fLeft  = Math.min (fLeft, Math.min (this.m_fX, this.m_fEndX));
            oPoint.fRight = Math.max (fRight, Math.max (this.m_fX, this.m_fEndX));
            oPoint.fTop   = Math.min (fTop, Math.min (this.m_fY, this.m_fEndY));
            oPoint.fBottom = Math.max (fBottom, Math.max (this.m_fY, this.m_fEndY));

            return oPoint;
        };

        this.GetNext = function()
        {
            if (this.m_nGlyphIndex >= this.m_nGlyphsCount || this.m_nGlyphIndex < 0)
                return undefined;

            return this.m_pGlyphsBuffer[this.m_nGlyphIndex++];
        };

        this.SetTrans = function(fX, fY)
        {
            var m = this.m_arrCTM;
            this.m_fTransX = this.m_dIDet * (fX * m[3] - m[2] * fY);
            this.m_fTransY = this.m_dIDet * (fY * m[0] - m[1] * fX);
        };

        this.SetCTM = function(fA, fB, fC, fD, fE , fF)
        {
            var m = this.m_arrCTM;
            m[0] = fA;
            m[1] = fB;
            m[2] = fC;
            m[3] = fD;
            m[4] = fE;
            m[5] = fF;

            var dDet = fA * fD - fB * fC;

            if (dDet < 0.001 && dDet >= 0)
                dDet =  0.001;
            else if (dDet > - 0.001 && dDet < 0)
                dDet = -0.001;

            this.m_dIDet = 1 / dDet;
        };
    }

    window['AscFonts'] = window['AscFonts'] || {};
    window['AscFonts'].CGlyphRect = CGlyphRect;
    window['AscFonts'].CGlyphBounds = CGlyphBounds;
    window['AscFonts'].CGlyphString = CGlyphString;

})(window, undefined);
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function (window, undefined)
{
	/**
	 * @param {_start} start range value
	 * @param {_end} end range value
	 * @param {_name} not used range name
	 */
	function CSymbolRange(_start, _end, _name)
	{
		this.Start = _start;
		this.End = _end;
		this.Name = _name;
	}

	function CFontByCharacter()
	{
		this.Ranges = [];
		this.UsedRanges = [];
		this.LastRange = null;

		this.FontsByRange = {};
		this.FontsByRangeCount = 0;
		this.ExtendFontsByRangeCount = 0;

		this.IsUseNoSquaresMode = true;

		this.CallbackObj = { _this : null, _callback : null };
	}

	CFontByCharacter.prototype =
	{
		init : function(infos)
		{
			var fonts = window["__fonts_ranges"];
			if (!fonts)
				return;

            var index = 0;
			var count = fonts.length / 3;
			for (var i = 0; i < count; i++)
			{
				if (!infos[fonts[index + 2]])
				{
					this.Ranges.splice(0, this.Ranges.length);
					return;
				}
				this.Ranges.push(new CSymbolRange(fonts[index], fonts[index + 1], infos[fonts[index + 2]][0]));
				index += 3;
			}

			fonts = null;
			delete window["__fonts_ranges"];
		},

        getRangeBySymbol : function(_char, _array)
		{
			// search range by symbol
			var _start = 0;
			var _end = _array.length - 1;

			var _center = 0;
			var _range = null;

			if (_start > _end)
				return null;

			while (_start < _end)
			{
				_center = (_start + _end) >> 1;
				_range = _array[_center];

				if (_range.Start > _char)
					_end = _center - 1;
				else if (_range.End < _char)
					_start = _center + 1;
				else
					return _array[_center];
			}

			if (_start > _end)
				return null;

			_range = _array[_start];
			if (_range.Start > _char || _range.End < _char)
				return null;

			return _array[_start];
		},

		getFontBySymbol : function(_char)
		{
			if (!this.IsUseNoSquaresMode)
				return "";

			if (undefined === _char || 0 == _char)
				return "";

			if (this.LastRange)
			{
				if (this.LastRange.Start <= _char && _char <= this.LastRange.End)
					return this.LastRange.Name;
			}

			// ищем среди уже найденных
			var _range = this.getRangeBySymbol(_char, this.UsedRanges);
			if (_range != null)
			{
				this.LastRange = _range;
                return _range.Name;
            }

			_range = this.getRangeBySymbol(_char, this.Ranges);
			if (!_range)
				return "";

            this.UsedRanges.push(_range);
            this.LastRange = _range;

            if (!this.FontsByRange[_range.Name])
			{
				this.FontsByRange[_range.Name] = _range.Name;
                this.FontsByRangeCount++;
            }

            return _range.Name;
		},

		getFontsByString : function(_text)
		{
            if (!this.IsUseNoSquaresMode)
                return false;

            if (!_text)
            	return false;

			var oldCount = this.FontsByRangeCount;
            for (var i = _text.getUnicodeIterator(); i.check(); i.next())
            {
                AscFonts.FontPickerByCharacter.getFontBySymbol(i.value());
            }
            return (this.FontsByRangeCount != oldCount);
		},

        getFontsByString2 : function(_array)
        {
            if (!this.IsUseNoSquaresMode)
                return false;

			if (!_array)
				return false;

            var oldCount = this.FontsByRangeCount;
            for (var i = 0; i < _array.length; ++i)
            {
                AscFonts.FontPickerByCharacter.getFontBySymbol(_array[i]);
            }
            return (this.FontsByRangeCount != oldCount);
        },

		isExtendFonts : function()
		{
			return this.ExtendFontsByRangeCount != this.FontsByRangeCount;
		},

		extendFonts : function(fonts, isNoRealExtend)
		{
            if (this.ExtendFontsByRangeCount == this.FontsByRangeCount)
            	return;

            var isFound;
            for (var i in this.FontsByRange)
			{
				isFound = false;
				for (var j in fonts)
				{
					if (fonts[j].name == this.FontsByRange[i])
					{
						isFound = true;
						break;
					}
				}

				if (!isFound)
					fonts[fonts.length] = new AscFonts.CFont(this.FontsByRange[i], 0, "", 0, null);
			}

			if (true !== isNoRealExtend)
				this.ExtendFontsByRangeCount = this.FontsByRangeCount;
		},

		checkTextLight : function(text, isCodes)
		{
			if (isCodes !== true)
			{
				if (!this.getFontsByString(text))
					return false;
			}
			else
			{
				if (!this.getFontsByString2(text))
					return false;
			}

			var fonts = [];
			this.extendFonts(fonts, true);

			if (false === AscCommon.g_font_loader.CheckFontsNeedLoading(fonts))
				return false;

			return true;
		},

		loadFonts : function(_this, _callback)
		{
			var fonts = [];
			this.extendFonts(fonts);

			this.CallbackObj._this = _this;
			this.CallbackObj._callback = _callback;

			var _editor = window["Asc"]["editor"] ? window["Asc"]["editor"] : window.editor;
			_editor.asyncMethodCallback = function() {

				var _t = AscFonts.FontPickerByCharacter.CallbackObj;
				_t._callback.call(_t._this);

				_t._this = null;
				_t._callback = null;

			};

			AscCommon.g_font_loader.LoadDocumentFonts2(fonts);
			return true;
		},

		checkText : function(text, _this, _callback, isCodes, isOnlyAsync, isCheckSymbols)
		{
			if (isCheckSymbols !== false)
			{
				if (isCodes !== true)
				{
					if (!this.getFontsByString(text))
					{
						if (!isOnlyAsync)
							_callback.call(_this);
						return false;
					}
				}
				else
				{
					if (!this.getFontsByString2(text))
					{
						if (!isOnlyAsync)
							_callback.call(_this);
						return false;
					}
				}
			}

			var fonts = [];
			this.extendFonts(fonts);

			if (false === AscCommon.g_font_loader.CheckFontsNeedLoading(fonts))
			{
				if (!isOnlyAsync)
					_callback.call(_this);
				return false;
			}

			this.CallbackObj._this = _this;
			this.CallbackObj._callback = _callback;

			var _editor = window["Asc"]["editor"] ? window["Asc"]["editor"] : window.editor;
			_editor.asyncMethodCallback = function() {

				var _t = AscFonts.FontPickerByCharacter.CallbackObj;
				_t._callback.call(_t._this);

				_t._this = null;
				_t._callback = null;

			};

			AscCommon.g_font_loader.LoadDocumentFonts2(fonts);
			return true;
		}
	};

    window['AscFonts'] = window['AscFonts'] || {};
    window['AscFonts'].IsCheckSymbols = false;
    window['AscFonts'].FontPickerByCharacter = new CFontByCharacter();

})(window);
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function (window, undefined)
{
    var FT_Set_Charmap = AscFonts.FT_Set_Charmap;
    var FT_Get_Char_Index = AscFonts.FT_Get_Char_Index;
    var __FT_CharmapRec = AscFonts.__FT_CharmapRec;

    var raster_memory = AscFonts.raster_memory;

	var FONT_ITALIC_ANGLE 	= 0.3090169943749;
	var FT_ENCODING_UNICODE = 1970170211;
	var FT_ENCODING_NONE 	= 0;
	var FT_ENCODING_MS_SYMBOL 	= 1937337698;
	var FT_ENCODING_APPLE_ROMAN = 1634889070;
	var REND_MODE 			= 0;

	var EGlyphState =
	{
		glyphstateNormal : 0,	// символ отрисовался в нужном шрифте
		glyphstateDefault : 1, // символ отрисовался в дефолтовом шрифте
		glyphstateMiss : 2  	// символ не отрисовался
	};

	function get_raster_bounds(data, width, height, stride)
	{
		var ret = {dist_l: 0, dist_t: 0, dist_r: 0, dist_b: 0};

		// left
		var bIsBreak = false;
		for (var i = 0; i < width; i++)
		{
			var _ind = i * 4 + 3;
			for (var j = 0; j < height; j++, _ind += stride)
			{
				if (data[_ind] != 0)
				{
					bIsBreak = true;
					break;
				}
			}
			if (bIsBreak)
				break;

			ret.dist_l++;
		}

		// right
		bIsBreak = false;
		for (var i = width - 1; i >= 0; i--)
		{
			var _ind = i * 4 + 3;
			for (var j = 0; j < height; j++, _ind += stride)
			{
				if (data[_ind] != 0)
				{
					bIsBreak = true;
					break;
				}
			}
			if (bIsBreak)
				break;

			ret.dist_r++;
		}

		// top
		var bIsBreak = false;
		for (var j = 0; j < height; j++)
		{
			var _ind = j * stride + 3;
			for (var i = 0; i < width; i++, _ind += 4)
			{
				if (data[_ind] != 0)
				{
					bIsBreak = true;
					break;
				}
			}
			if (bIsBreak)
				break;

			ret.dist_t++;
		}

		// bottom
		var bIsBreak = false;
		for (var j = height - 1; j >= 0; j--)
		{
			var _ind = j * stride + 3;
			for (var i = 0; i < width; i++, _ind += 4)
			{
				if (data[_ind] != 0)
				{
					bIsBreak = true;
					break;
				}
			}
			if (bIsBreak)
				break;

			ret.dist_b++;
		}

		// clear
		if (null != raster_memory.m_oBuffer)
		{
			var nIndexDst = 3;
			var nPitch = 4 * (raster_memory.width - width);
			var dst = raster_memory.m_oBuffer.data;
			for (var j = 0; j < height; j++)
			{
				for (var i = 0; i < width; i++)
				{
					dst[nIndexDst] = 0;
					nIndexDst += 4;
				}
				nIndexDst += nPitch;
			}
		}

		return ret;
	}

	function CGlyphData()
	{
		this.m_oCanvas = null;
		this.m_oContext = null;
		this.R = 0;
		this.G = 0;
		this.B = 0;

		this.RasterData = null;

		this.TempImage = null;
	}

	CGlyphData.prototype =
	{
		// not used (old devices)
		checkColorAppleDevices : function(r, g, b, w, h)
		{
            if ((r == this.R) && (g == this.G) && (b == this.B))
                return;

            this.R = r;
            this.G = g;
            this.B = b;

            // full repaint
            this.TempImage = document.createElement("canvas");
            this.TempImage.width = w;
            this.TempImage.height = h;
            var ctxD = this.TempImage.getContext("2d");
            var pixDst = null;

            if (this.m_oCanvas != null)
            {
                pixDst = this.m_oContext.getImageData(0, 0, w, h);
                var dataPx = pixDst.data;

                var cur = 0;
                var cnt = w * h;
                for (var i = 0; i < cnt; i++)
                {
                    dataPx[cur++] = r;
                    dataPx[cur++] = g;
                    dataPx[cur++] = b;
                    cur++;
                }
            }
            else
            {
                var _raster = this.RasterData;
                var _x = _raster.Line.Height * _raster.Index;
                var _y = _raster.Line.Y;

                pixDst = _raster.Chunk.CanvasCtx.getImageData(_x, _y, w, h);
                var dataPx = pixDst.data;

                var cur = 0;
                var cnt = w * h;
                for (var i = 0; i < cnt; i++)
                {
                    dataPx[cur++] = r;
                    dataPx[cur++] = g;
                    dataPx[cur++] = b;
                    cur++;
                }
            }

            ctxD.putImageData(pixDst, 0, 0, 0, 0, w, h);
		},

		checkColorMozillaLinux : function(r, g, b, w, h)
		{
            if ((r == this.R) && (g == this.G) && (b == this.B))
                return;

            this.R = r;
            this.G = g;
            this.B = b;

            if (this.m_oCanvas != null)
            {
                this.m_oContext.fillStyle = (this.R == 0xFF && this.G == 0xFF && this.B == 0xFF) ? "rgb(255,255,254)" : "rgb(" + this.R + "," + this.G + "," + this.B + ")";
                this.m_oContext.fillRect(0, 0, w, h);
            }
            else
            {
                var _raster = this.RasterData;
                _raster.Chunk.CanvasCtx.fillStyle = (this.R == 0xFF && this.G == 0xFF && this.B == 0xFF) ? "rgb(255,255,254)" : "rgb(" + this.R + "," + this.G + "," + this.B + ")";
                var _x = _raster.Line.Height * _raster.Index;
                var _y = _raster.Line.Y;
                this.RasterData.Chunk.CanvasCtx.fillRect(_x, _y, w, h);
            }
		},

		checkColorNormal : function(r, g, b, w, h)
		{
            if ((r == this.R) && (g == this.G) && (b == this.B))
                return;

            this.R = r;
            this.G = g;
            this.B = b;

            if (this.m_oCanvas != null)
            {
                this.m_oContext.fillStyle = "rgb(" + this.R + "," + this.G + "," + this.B + ")";
                this.m_oContext.fillRect(0, 0, w, h);
            }
            else
            {
                var _raster = this.RasterData;
                _raster.Chunk.CanvasCtx.fillStyle = "rgb(" + this.R + "," + this.G + "," + this.B + ")";
                var _x = _raster.Line.Height * _raster.Index;
                var _y = _raster.Line.Y;
                this.RasterData.Chunk.CanvasCtx.fillRect(_x, _y, w, h);
            }
		},

		checkColor : undefined,

		init: function (width, height)
		{
			if (width == 0 || height == 0)
				return;

			this.m_oCanvas = document.createElement('canvas');

			this.m_oCanvas.width = (width == 0) ? 1 : width;
			this.m_oCanvas.height = (height == 0) ? 1 : height;

			this.m_oContext = this.m_oCanvas.getContext('2d');
			this.m_oContext.globalCompositeOperation = "source-in";
		}
	};

    CGlyphData.prototype.checkColor = (AscCommon.AscBrowser.isMozilla && AscCommon.AscBrowser.isLinuxOS) ? CGlyphData.prototype.checkColorMozillaLinux : CGlyphData.prototype.checkColorNormal;

	function CGlyphBitmap()
	{
		this.nX = 0;            // Сдвиг по X начальной точки для рисования символа
		this.nY = 0;            // Сдвиг по Y начальной точки для рисования символа
		this.nWidth = 0;        // Ширина символа
		this.nHeight = 0;       // Высота символа

		this.oGlyphData = new CGlyphData();
	}

	CGlyphBitmap.prototype =
	{
		fromAlphaMask: function (font_manager)
		{
			var bIsCanvas = false;
			var _chunk_size = (font_manager.RasterMemory == null) ? 0 : font_manager.RasterMemory.ChunkHeapSize;
			if (Math.max(this.nWidth, this.nHeight) > (_chunk_size / 10))
				bIsCanvas = true;

			var _x = 0;
			var _y = 0;
			var ctx = null;

			if (bIsCanvas)
			{
				this.oGlyphData.init(this.nWidth, this.nHeight);
				ctx = this.oGlyphData.m_oContext;
			}
			else
			{
				this.oGlyphData.RasterData = font_manager.RasterMemory.Alloc(this.nWidth, this.nHeight);
				ctx = this.oGlyphData.RasterData.Chunk.CanvasCtx;
				_x = this.oGlyphData.RasterData.Line.Height * this.oGlyphData.RasterData.Index;
				_y = this.oGlyphData.RasterData.Line.Y;
			}

			if (true)
			{
                if (this.nWidth > 0 && this.nHeight > 0)
                	ctx.putImageData(raster_memory.m_oBuffer, _x, _y, 0, 0, this.nWidth, this.nHeight);
			}
			else
			{
				var gamma = 1.1;

				var nIndexDst = 3;
				var nPitch = 4 * (raster_memory.width - this.nWidth);
				var dst = raster_memory.m_oBuffer.data;
				for (var j = 0; j < this.nHeight; j++)
				{
					for (var i = 0; i < this.nWidth; i++)
					{
						dst[nIndexDst] = Math.min((dst[nIndexDst] * gamma) >> 0, 255);
						nIndexDst += 4;
					}
					nIndexDst += nPitch;
				}

				if (this.nWidth > 0 && this.nHeight > 0)
					ctx.putImageData(raster_memory.m_oBuffer, _x, _y, 0, 0, this.nWidth, this.nHeight);
			}

			if (null != raster_memory.m_oBuffer)
			{
				var nIndexDst = 3;
				var nPitch = 4 * (raster_memory.width - this.nWidth);
				var dst = raster_memory.m_oBuffer.data;
				for (var j = 0; j < this.nHeight; j++)
				{
					for (var i = 0; i < this.nWidth; i++)
					{
						dst[nIndexDst] = 0;
						nIndexDst += 4;
					}
					nIndexDst += nPitch;
				}
			}
		},

		draw: function (context2D, x, y)
		{
			var nW = this.nWidth;
			var nH = this.nHeight;
			if (null != this.oGlyphData.TempImage)
			{
				context2D.drawImage(this.oGlyphData.TempImage, 0, 0, nW, nH, x, y, nW, nH);
				this.oGlyphData.TempImage = null;
			}
			else if (null != this.oGlyphData.m_oCanvas)
			{
				// своя память
				context2D.drawImage(this.oGlyphData.m_oCanvas, 0, 0, nW, nH, x, y, nW, nH);
			}
			else
			{
				var _raster = this.oGlyphData.RasterData;
				var _x = _raster.Line.Height * _raster.Index;
				var _y = _raster.Line.Y;
				context2D.drawImage(_raster.Chunk.CanvasImage, _x, _y, nW, nH, x, y, nW, nH);
			}
		},

		drawCrop: function (context2D, x, y, w, h, cx)
		{
			if (null != this.oGlyphData.TempImage)
			{
				context2D.drawImage(this.oGlyphData.TempImage, cx, 0, w, h, x, y, w, h);
				this.oGlyphData.TempImage = null;
			}
			else if (null != this.oGlyphData.m_oCanvas)
			{
				// своя память
				context2D.drawImage(this.oGlyphData.m_oCanvas, cx, 0, w, h, x, y, w, h);
			}
			else
			{
				var _raster = this.oGlyphData.RasterData;
				var _x = _raster.Line.Height * _raster.Index;
				var _y = _raster.Line.Y;
				context2D.drawImage(_raster.Chunk.CanvasImage, _x + cx, _y, w, h, x, y, w, h);
			}
		},

		drawCropInRect: function (context2D, x, y, clipRect)
		{
			var _x = x;
			var _y = y;
			var _r = x + this.nWidth;
			var _b = y + this.nHeight;

			var _dstX = 0;
			var _dstY = 0;
			var _dstW = this.nWidth;
			var _dstH = this.nHeight;

			if (_x < clipRect.l)
			{
				_dstX = clipRect.l - _x;
				_x += _dstX;
				_dstW -= _dstX;
			}
			if (_y < clipRect.t)
			{
				_dstY = clipRect.t - _y;
				_y += _dstY;
				_dstH -= _dstY;
			}
			if (_r > clipRect.r)
			{
				_dstW -= (_r - clipRect.r);
			}
			if (_b > clipRect.b)
			{
				_dstH -= (_b - clipRect.b);
			}

			if (_dstW <= 0 || _dstH <= 0)
				return;

			if (null != this.oGlyphData.TempImage)
			{
				context2D.drawImage(this.oGlyphData.TempImage, _dstX, _dstY, _dstW, _dstH, _x, _y, _dstW, _dstH);
				this.oGlyphData.TempImage = null;
			}
			else if (null != this.oGlyphData.m_oCanvas)
			{
				// своя память
				context2D.drawImage(this.oGlyphData.m_oCanvas, _dstX, _dstY, _dstW, _dstH, _x, _y, _dstW, _dstH);
			}
			else
			{
				var _raster = this.oGlyphData.RasterData;
				var __x = _raster.Line.Height * _raster.Index;
				var __y = _raster.Line.Y;
				context2D.drawImage(_raster.Chunk.CanvasImage, __x + _dstX, __y + _dstY, _dstW, _dstH, _x, _y, _dstW, _dstH);
			}
		},

		Free: function ()
		{
			if (null != this.oGlyphData.RasterData)
			{
				this.oGlyphData.RasterData.Chunk.Free(this.oGlyphData.RasterData);
			}
		}
	};

	function CBBox()
	{
		this.fMinX = 0;
		this.fMaxX = 0;
		this.fMinY = 0;
		this.fMaxY = 0;

		this.rasterDistances = null;
	}

	function CMetrics()
	{
		this.fWidth = 0;
		this.fHeight = 0;

		this.fHoriBearingX = 0;
		this.fHoriBearingY = 0;
		this.fHoriAdvance = 0;

		this.fVertBearingX = 0;
		this.fVertBearingY = 0;
		this.fVertAdvance = 0;
	}

	function CFontCacheSizes()
	{
		this.ushUnicode; // Значение символа в юникоде
		this.eState;     // Есть ли символ в шрифте/стандартном шрифте
		this.nCMapIndex; // Номер таблицы 'cmap', в которой был найден данный символ

		this.ushGID;

		this.fAdvanceX;

		this.oBBox = new CBBox();
		this.oMetrics = new CMetrics();

		this.bBitmap = false;
		this.oBitmap = null;
	}

	function CCMapIndex()
	{
		this.index = 0;
	}

	function CGlyphVectorPainter()
	{
		// сдвиг
		this.X = 0;
		this.Y = 0;

		// scale
		this.KoefX = 25.4 / 72;
		this.KoefY = 25.4 / 72;

		this.NeedClosed = false;

		this.shift = 0;
		this.delta = 0;

		this.CurX = 0;
		this.CurY = 0;
	}

	CGlyphVectorPainter.prototype =
	{
		start: function ()
		{

		},

		move_to: function (to, worker)
		{
			if (this.NeedClosed)
			{
				worker._z();
				this.NeedClosed = false;
			}

			this.CurX = this.X + this.KoefX * (to.x / 64.0);
			this.CurY = this.Y - this.KoefY * (to.y / 64.0);

			worker._m(this.CurX, this.CurY);

			return 0;
		},

		line_to: function (to, worker)
		{
			this.CurX = this.X + this.KoefX * (to.x / 64.0);
			this.CurY = this.Y - this.KoefY * (to.y / 64.0);

			worker._l(this.CurX, this.CurY);

			this.NeedClosed = true;
			return 0;
		},

		conic_to: function (control, to, worker)
		{
			var dX0 = this.CurX;
			var dY0 = this.CurY;

			var dXc = this.X + this.KoefX * (control.x / 64.0);
			var dYc = this.Y - this.KoefY * (control.y / 64.0);
			var dX3 = this.X + this.KoefX * (to.x / 64.0);
			var dY3 = this.Y - this.KoefY * (to.y / 64.0);

			// Строим кривую Безье второго порядка, с помощью кривой Безье третего порядка. Если p0, pC, p3 -
			// начальная, контрольная и конечная точки, соответственно, для кривой Безье второго порядка. Тогда
			// для этой же кривой, рассматриваемой как кривая Безье третьего порядка, точки p0, p1, p2, p3 будут
			// начальной, две контрольные, конечная точки. Где p1 и p2 рассчитываются по следующим формулам:
			//     p1 = (1/3) * (p0 + 2pС)
			//     p2 = (1/3) * (2pС + p3)

			var dX1 = (1.0 / 3.0) * (dX0 + 2 * dXc);
			var dY1 = (1.0 / 3.0) * (dY0 + 2 * dYc);
			var dX2 = (1.0 / 3.0) * (2 * dXc + dX3);
			var dY2 = (1.0 / 3.0) * (2 * dYc + dY3);

			worker._c(dX1, dY1, dX2, dY2, dX3, dY3);

			this.CurX = dX3;
			this.CurY = dY3;

			this.NeedClosed = true;
			return 0;
		},

		cubic_to: function (control1, control2, to, worker)
		{
			this.CurX = this.X + this.KoefX * (to.x / 64.0);
			this.CurY = this.Y - this.KoefY * (to.y / 64.0);

			worker._c(
				this.X + this.KoefX * (control1.x / 64.0),
				this.Y - this.KoefY * (control1.y / 64.0),
				this.X + this.KoefX * (control2.x / 64.0),
				this.Y - this.KoefY * (control2.y / 64.0),
				this.CurX,
				this.CurY);

			this.NeedClosed = true;
			return 0;
		},

		end: function (worker)
		{
			if (this.NeedClosed)
			{
				worker._z();
				this.NeedClosed = false;
			}
		}
	};

    function CFontFile(fileName, faceIndex)
	{
        this.m_sFileName = fileName;
        this.m_lFaceIndex = faceIndex;

		this.m_arrdFontMatrix = ("undefined" == typeof Float64Array) ? new Array(6) : new Float64Array(6);
		this.m_arrdTextMatrix = ("undefined" == typeof Float64Array) ? new Array(6) : new Float64Array(6);

		this.m_bAntiAliasing = true;
		this.m_bUseKerning = false;

		this.m_fSize = 1.0;       // Размер шрифта
		this.m_unHorDpi = 0;      // Горизонтальное разрешение
		this.m_unVerDpi = 0;      // Вертикальное разрешение

		this.m_bNeedDoItalic = false;
		this.m_bNeedDoBold = false;

		this.m_fCharSpacing = 0.0;

		this.m_oBox = new AscFonts.CGlyphBounds(); // Glyph box

		this.m_nError = 0;
		this.m_pFace = null;

		this.m_dUnitsKoef = 1.0;
		this.m_nDefaultChar = -1;
		this.m_nSymbolic = -1;
		this.m_dTextScale = 0;

		this.m_bStringGID = false;

        this.m_oTransform = new AscFonts.FT_Matrix();

		this.m_nNum_charmaps = 0;

		this.m_lAscender = 0;
		this.m_lDescender = 0;
		this.m_lLineHeight = 0;
		this.m_lUnits_Per_Em = 0;

		this.m_arrCacheSizes = [];
		this.m_arrCacheSizesGid = [];

		this.m_oFontManager = null;
		this.HintsSupport = true;
		this.HintsSubpixelSupport = true;

        this.m_bIsTransform = true; // !IsIdentity matrix transform

		this.Picker = new CFontLoaderBySymbol();

		this.FT_Load_Glyph_Wrapper = function(pFace, unGID, _LOAD_MODE)
		{
			var err = AscFonts.FT_Load_Glyph(pFace, unGID, _LOAD_MODE);
			if (0 != err && this.HintsSupport)
			{
				var err2 = AscFonts.FT_Load_Glyph(pFace, unGID, 40970);
				if (err2 != 0)
					return err;
				this.HintsSupport = false;
				return err2;
			}
			return err;
		};

		this.LoadDefaultCharAndSymbolicCmapIndex = function()
		{
			this.m_nDefaultChar = -1;
			this.m_nSymbolic = -1;

			var pTable = AscFonts.FT_Get_Sfnt_Table(this.m_pFace, 2);
			if (null == pTable)
				return;

			this.m_nDefaultChar = pTable.usDefaultChar;

			// version
			if (0xFFFF == pTable.version)
				return;

			var ulCodePageRange1 = pTable.ulCodePageRange1;
			var ulCodePageRange2 = pTable.ulCodePageRange2;
			if (!(ulCodePageRange1 & 0x80000000) && !(ulCodePageRange1 == 0 && ulCodePageRange2 == 0))
				return;

			var charMapArray = this.m_pFace.charmaps;
			for (var nIndex = 0; nIndex < this.m_nNum_charmaps; ++nIndex)
			{
				var pCharMap = AscFonts.__FT_CharmapRec(charMapArray[nIndex]);

				var nPlatformId = pCharMap.platform_id;
				var nEncodingId = pCharMap.encoding_id;
				// Symbol
				if (0 == nEncodingId && 3 == nPlatformId)
				{
					this.m_nSymbolic = nIndex;
					return;
				}
			}
		};

		this.ResetFontMatrix = function()
		{
			var m = this.m_arrdFontMatrix;
			if (this.m_bNeedDoItalic)
			{
				m[0] = 1;
				m[1] = 0;
				m[2] = FONT_ITALIC_ANGLE;
				m[3] = 1;
				m[4] = 0;
				m[5] = 0;
			}
			else
			{
				m[0] = 1;
				m[1] = 0;
				m[2] = 0;
				m[3] = 1;
				m[4] = 0;
				m[5] = 0;
			}

			this.UpdateMatrix();
		};

		this.ResetTextMatrix = function()
		{
			var m = this.m_arrdTextMatrix;
			m[0] = 1;
			m[1] = 0;
			m[2] = 0;
			m[3] = 1;
			m[4] = 0;
			m[5] = 0;

			this.CheckTextMatrix();
		};

		this.CheckTextMatrix = function()
		{
			this.m_bIsTransform = true;
			var m = this.m_arrdTextMatrix;
			if ((m[0] == 1) && (m[1] == 0) && (m[2] == 0) && (m[3] == 1))
			{
				this.m_bIsTransform = false;
				this.UpdateMatrix();
			}
		};

		this.CheckBBox = function()
		{
            if (this.m_lUnits_Per_Em == 0)
                this.m_lUnits_Per_Em = this.m_pFace.units_per_EM = 2048;

            this.m_dTextScale = 1;
            //this.m_dTextScale = Math.sqrt(this.m_arrdTextMatrix[2] * this.m_arrdTextMatrix[2] + this.m_arrdTextMatrix[3] * this.m_arrdTextMatrix[3]);

            var bbox = this.m_pFace.bbox;
            var xMin = bbox.xMin;
            var yMin = bbox.yMin;
            var xMax = bbox.xMax;
            var yMax = bbox.yMax;

            var dDiv = xMax > 20000 ? 65536 : 1;
            var dScale = this.fSize / (dDiv * this.m_lUnits_Per_Em);

            var m = this.m_arrdFontMatrix;
            this.m_oBox.checkPoint(((m[0] * xMin + m[2] * yMin) * dScale) >> 0, ((m[1] * xMin + m[3] * yMin) * dScale) >> 0);
            this.m_oBox.checkPoint(((m[0] * xMin + m[2] * yMax) * dScale) >> 0, ((m[1] * xMin + m[3] * yMax) * dScale) >> 0);
            this.m_oBox.checkPoint(((m[0] * xMax + m[2] * yMin) * dScale) >> 0, ((m[1] * xMax + m[3] * yMin) * dScale) >> 0);
            this.m_oBox.checkPoint(((m[0] * xMax + m[2] * yMax) * dScale) >> 0, ((m[1] * xMax + m[3] * yMax) * dScale) >> 0);

            // This is a kludge: some buggy PDF generators embed fonts with  zero bounding boxes.
            if (this.m_oBox.fLeft == this.m_oBox.fRight)
			{
				this.m_oBox.fLeft = 0;
				this.m_oBox.fRight = this.m_fSize >> 0;
			}
            if (this.m_oBox.fTop == this.m_oBox.fBottom)
            {
                this.m_oBox.fTop = 0;
                this.m_oBox.fBottom = (1.2 * this.m_fSize) >> 0;
            }
		};

		this.UpdateMatrix = function()
		{
			var m = this.m_arrdFontMatrix;
			var t = this.m_arrdTextMatrix;
			var fm = this.m_oTransform;

			fm.xx = ((m[0] * t[0] + m[1] * t[2]) * 65536) >> 0;
			fm.yx = ((m[0] * t[1] + m[1] * t[3]) * 65536) >> 0;
			fm.xy = ((m[2] * t[0] + m[3] * t[2]) * 65536) >> 0;
			fm.yy = ((m[2] * t[1] + m[3] * t[3]) * 65536) >> 0;

			AscFonts.FT_Set_Transform(this.m_pFace, fm, 0);
		};

		this.SetSizeAndDpi = function (dSize, unHorDpi, unVerDpi)
		{
			var dpiX = (unHorDpi + 0.5) >> 0;
			var dpiY = (unVerDpi + 0.5) >> 0;

			var dOldSize = this.m_fSize;
			var dNewSize = dSize;
			var dKoef = dNewSize / dOldSize;
			var isResize = (dKoef > 1.001 || dKoef < 0.999) ? true : false;

			if (isResize || dpiX != this.m_unHorDpi || dpiY != this.m_unVerDpi)
			{
				this.m_unHorDpi = dpiX;
				this.m_unVerDpi = dpiY;

				if (isResize)
				{
					this.m_fSize = dNewSize;
					this.UpdateMatrix();
					this.CheckBBox();
				}

				this.m_dUnitsKoef = this.m_unHorDpi / 72.0 * this.m_fSize;

				// Выставляем размер шрифта (dSize) и DPI
				this.m_nError = AscFonts.FT_Set_Char_Size(this.m_pFace, 0, (dNewSize * 64) >> 0, dpiX, dpiY);
				this.ClearCache();
			}
		};

		this.ClearCache = function()
		{
			this.Destroy();
			this.ClearCacheNoAttack();

			if (this.Picker)
				this.Picker.ClearCache();
		};

		this.ClearCacheNoAttack = function()
		{
			this.m_arrCacheSizes = [];
			this.m_arrCacheSizesGid = [];

			if (this.Picker)
				this.Picker.ClearCacheNoAttack();
		};

		this.Destroy = function()
		{
			if (this.m_oFontManager != null && this.m_oFontManager.RasterMemory != null)
			{
				var _arr = this.m_arrCacheSizes;
				for (var i in _arr)
				{
					if (_arr[i].oBitmap != null)
						_arr[i].oBitmap.Free();
				}
				_arr = this.m_arrCacheSizesGid;
				for (var i in _arr)
				{
					if (_arr[i].oBitmap != null)
						_arr[i].oBitmap.Free();
				}
			}
		};

		this.SetTextMatrix = function(fA, fB, fC, fD, fE, fF)
		{
			var m = this.m_arrdTextMatrix;

			var b1 = (m[0] == fA && m[1] == -fB && m[2] == -fC && m[3] == fD);
			if (b1 && m[4] == fE && m[5] == fF)
				return false;

			m[0] = fA;
			m[1] = -fB;
			m[2] = -fC;
			m[3] = fD;
			m[4] = fE;
			m[5] = fF;

			if (!b1)
			{
				this.ClearCache();
			}
			this.CheckTextMatrix();
			return true;
		};

		this.SetFontMatrix = function(fA, fB, fC, fD, fE, fF)
		{
			var m = this.m_arrdFontMatrix;
			if (this.m_bNeedDoItalic)
			{
				m[0] = fA;
				m[1] = fB;
				m[2] = fC + fA * FONT_ITALIC_ANGLE;
				m[3] = fD + fB * FONT_ITALIC_ANGLE;
				m[4] = fE;
				m[5] = fF;
			}
			else
			{
				m[0] = fA;
				m[1] = fB;
				m[2] = fC;
				m[3] = fD;
				m[4] = fE;
				m[5] = fF;
			}

			this.ClearCache();
		};

		this.GetGIDByUnicode = function(glyph)
		{
            var nCMapIndex = new CCMapIndex();
            var unGID = this.SetCMapForCharCode(glyph, nCMapIndex);
            if (unGID > 0)
            	return unGID;

            if (-1 != this.m_nSymbolic && glyph < 0xF000)
                unGID = this.SetCMapForCharCode(glyph + 0xF000, nCMapIndex);

            return unGID;
		};

		this.CacheGlyph = function(glyph_index_or_unicode, isRaster, isRasterDistances, workerVector, workerVectorX, workerVectorY, isFromPicker)
		{
            var oSizes = new CFontCacheSizes();
            oSizes.ushUnicode = glyph_index_or_unicode;

            var nCMapIndex = new CCMapIndex();
            var unGID = this.SetCMapForCharCode(glyph_index_or_unicode, nCMapIndex);

            if (unGID <= 0 && !this.m_bStringGID)
			{
				if (-1 != this.m_nSymbolic && glyph_index_or_unicode < 0xF000)
					unGID = this.SetCMapForCharCode(glyph_index_or_unicode + 0xF000, nCMapIndex);
			}

			if (unGID <= 0)
			{
                if (isFromPicker === true)
                	return null;

				if (!this.m_bStringGID && this.Picker)
				{
					// пробуем подобрать нужный шрифт
					var oSizesCheck = this.Picker.LoadSymbol(this, glyph_index_or_unicode, isRaster, isRasterDistances, workerVector, workerVectorX, workerVectorY);
					if (oSizesCheck)
						return oSizesCheck;
				}

				if (this.m_nDefaultChar >= 0)
				{
					unGID = this.m_nDefaultChar;
					oSizes.eState = EGlyphState.glyphstateDefault;
				}
				else
				{
					oSizes.eState = EGlyphState.glyphstateMiss;
                    oSizes.ushGID = -1;
                    oSizes.fAdvanceX = (this.m_pFace.size.metrics.max_advance >> 6) / 2.0;
                    return oSizes;
				}
			}
			else
			{
				oSizes.eState = EGlyphState.glyphstateNormal;
			}

            oSizes.ushGID = unGID;
            oSizes.nCMapIndex = nCMapIndex.index;

            if (0 != this.FT_Load_Glyph_Wrapper(this.m_pFace, unGID, this.GetCharLoadMode()))
                return oSizes;

            var pFaceGlyph = this.m_pFace.glyph;
            var pGlyph = AscFonts.FT_Get_Glyph(this.m_pFace.glyph);
            if (null == pGlyph)
                return oSizes;

            if (undefined !== workerVector)
			{
                var _painter = new CGlyphVectorPainter();
                _painter.KoefX = 25.4 / this.m_unHorDpi;
                _painter.KoefY = 25.4 / this.m_unVerDpi;

                if (workerVectorX !== undefined)
                    _painter.X = workerVectorX;
                if (workerVectorY !== undefined)
                    _painter.Y = workerVectorY;

                _painter.start(workerVector);
                AscFonts.FT_Outline_Decompose(pGlyph.outline, _painter, workerVector);
                _painter.end(workerVector);
                return oSizes;
			}

            var oBBox = new AscFonts.FT_BBox();
            AscFonts.FT_Glyph_Get_CBox(pGlyph, 1, oBBox);
            AscFonts.FT_Done_Glyph(pGlyph);
            pGlyph = null;

            oSizes.fAdvanceX = (pFaceGlyph.linearHoriAdvance * this.m_dUnitsKoef / this.m_lUnits_Per_Em);
            if (this.m_bNeedDoBold && this.m_oFontManager.IsAdvanceNeedBoldFonts)
                oSizes.fAdvanceX += 1;

            oSizes.oBBox.fMinX = (oBBox.xMin >> 6);
            oSizes.oBBox.fMaxX = (oBBox.xMax >> 6);
            oSizes.oBBox.fMinY = (oBBox.yMin >> 6);
            oSizes.oBBox.fMaxY = (oBBox.yMax >> 6);

            var dstM = oSizes.oMetrics;
            var srcM = pFaceGlyph.metrics;

            dstM.fWidth = (srcM.width >> 6);
            dstM.fHeight = (srcM.height >> 6);
            dstM.fHoriBearingX = (srcM.horiBearingX >> 6);
            dstM.fHoriBearingY = (srcM.horiBearingY >> 6);
            dstM.fHoriAdvance = (srcM.horiAdvance >> 6);
            dstM.fVertBearingX = (srcM.vertBearingX >> 6);
            dstM.fVertBearingY = (srcM.vertBearingY >> 6);
            dstM.fVertAdvance = (srcM.vertAdvance >> 6);

            if (isFromPicker && (0 == dstM.fHoriAdvance && 0 == srcM.width))
            	return null;

            if (!isRaster)
            {
            	if (isRasterDistances)
				{
                    if (0 == AscFonts.FT_Render_Glyph(pFaceGlyph, REND_MODE))
                    {
                        oSizes.oBBox.rasterDistances = get_raster_bounds(raster_memory.m_oBuffer.data, pFaceGlyph.bitmap.width, pFaceGlyph.bitmap.rows, raster_memory.pitch);
                    }
				}
                return oSizes;
            }

            oSizes.bBitmap = true;
            if (AscFonts.FT_Render_Glyph(pFaceGlyph, REND_MODE))
                return oSizes;

            if (0 == pFaceGlyph.bitmap.pitch)
            	return oSizes;

			oSizes.oBitmap = new CGlyphBitmap();
			oSizes.oBitmap.nX = pFaceGlyph.bitmap_left;
			oSizes.oBitmap.nY = pFaceGlyph.bitmap_top;
			oSizes.oBitmap.nWidth = pFaceGlyph.bitmap.width;
			oSizes.oBitmap.nHeight = pFaceGlyph.bitmap.rows;

			var isDisableNeedBold = (this.m_pFace.os2 && (this.m_pFace.os2.version != 0xFFFF) && (this.m_pFace.os2.usWeightClass >= 800)) ? true : false;

			if (this.m_bNeedDoBold && this.m_bAntiAliasing && !isDisableNeedBold)
			{
                oSizes.oBitmap.nWidth++;

				var _width_im = oSizes.oBitmap.nWidth;
				var _height = oSizes.oBitmap.nHeight;

				var nY, nX;
				var pDstBuffer;

				var _input = raster_memory.m_oBuffer.data;
				for (nY = 0, pDstBuffer = 0; nY < _height; ++nY, pDstBuffer += (raster_memory.pitch))
				{
					for (nX = _width_im - 1; nX >= 0; --nX)
					{
						if (0 != nX) // иначе ничего не делаем
						{
							var _pos_x = pDstBuffer + nX * 4 + 3;

							if (_width_im - 1 == nX)
							{
								// последний - просто копируем
								_input[_pos_x] = _input[_pos_x - 4];
							}
							else
							{
								// сдвигаем все вправо
								_input[_pos_x] = Math.min(255, _input[_pos_x - 4] + _input[_pos_x]);
							}
						}
					}
				}
			}

			oSizes.oBitmap.fromAlphaMask(this.m_oFontManager);
			return oSizes;
		};

		this.GetString = function(pString)
		{
			if (pString.GetLength() <= 0)
				return true;

			var unPrevGID = 0;
			var fPenX = 0, fPenY = 0;

			// Сначала мы все рассчитываем исходя только из матрицы шрифта FontMatrix
			if (this.m_bIsTransform)
                this.UpdateMatrix();

			var _cache_array = (this.m_bStringGID === false) ? this.m_arrCacheSizes : this.m_arrCacheSizesGid;

			for (var nIndex = 0; nIndex < pString.GetLength(); ++nIndex)
			{
				var pCurGlyph = pString.GetAt(nIndex);
				var ushUnicode = pCurGlyph.lUnicode;

				var charSymbolObj = _cache_array[ushUnicode];
				if (undefined == charSymbolObj)
				{
					_cache_array[ushUnicode] = this.CacheGlyph(ushUnicode, false);
                    charSymbolObj = _cache_array[ushUnicode];
                }

				var unGID = charSymbolObj.ushGID;
				var eState = charSymbolObj.eState;

				if (EGlyphState.glyphstateMiss == eState)
				{
					pString.SetStartPoint(nIndex, fPenX, fPenY);
					pString.SetBBox(nIndex, 0, 0, 0, 0);
					pString.SetState(nIndex, EGlyphState.glyphstateMiss);

					fPenX += charSymbolObj.fAdvanceX + this.m_fCharSpacing;
					unPrevGID = 0;

					continue;
				}
				else if (EGlyphState.glyphstateDefault == eState)
				{
					pString.SetState(nIndex, EGlyphState.glyphstateDefault);
					// kerning face!!!
				}
				else // if ( glyphstateNormal == eState )
				{
					pString.SetState(nIndex, EGlyphState.glyphstateNormal);
                    // kerning face!!!
				}

				/*
				if (0 != this.m_nNum_charmaps)
				{
					var nCharmap = pFace.charmap;
					var nCurCMapIndex = AscFonts.FT_Get_Charmap_Index(nCharmap);
					if (nCurCMapIndex != _cmap_index)
					{
						_cmap_index = Math.max(0, _cmap_index);
						nCharmap = pFace.charmaps[_cmap_index];
						AscFonts.FT_Set_Charmap(pFace, nCharmap);
					}
				}
				*/

				if (this.m_bUseKerning && unPrevGID && (nIndex > 0 && pString.GetAt(nIndex).eState == pString.GetAt(nIndex - 1).eState))
				{
					fPenX += this.GetKerning(unPrevGID, unGID);
				}

				var fX = pString.m_fX + fPenX;
				var fY = pString.m_fY + fPenY;

				// Начальную точку рассчитываем сразу исходя из глобальной матрицы
				var fXX = (pString.m_arrCTM[4] + fX * pString.m_arrCTM[0] + fY * pString.m_arrCTM[2] - pString.m_fX);
				var fYY = (pString.m_arrCTM[5] + fX * pString.m_arrCTM[1] + fY * pString.m_arrCTM[3] - pString.m_fY);

				pString.SetStartPoint(nIndex, fXX, fYY);

				var _metrics = charSymbolObj.oMetrics;
				pString.SetMetrics(nIndex, _metrics.fWidth, _metrics.fHeight, _metrics.fHoriAdvance, _metrics.fHoriBearingX, _metrics.fHoriBearingY, _metrics.fVertAdvance, _metrics.fVertBearingX, _metrics.fVertBearingY);
				pString.SetBBox(nIndex, charSymbolObj.oBBox.fMinX, charSymbolObj.oBBox.fMaxY, charSymbolObj.oBBox.fMaxX, charSymbolObj.oBBox.fMinY);
				fPenX += charSymbolObj.fAdvanceX + this.m_fCharSpacing;

				if (this.m_bNeedDoBold && this.m_oFontManager.IsAdvanceNeedBoldFonts)
				{
					// Когда текст делаем жирным сами, то мы увеличиваем расстояние на 1 пиксель в ширину (независимо от DPI и размера текста всегда 1 пиксель)
					fPenX += 1;
				}

				unPrevGID = unGID;
			}

			pString.m_fEndX = fPenX + pString.m_fX;
			pString.m_fEndY = fPenY + pString.m_fY;
		};

		this.GetString2 = function(pString)
		{
			if (pString.GetLength() <= 0)
				return true;

            if (this.m_bIsTransform)
                this.UpdateMatrix();

			var unPrevGID = 0;
			var fPenX = 0, fPenY = 0;

			var _cache_array = (this.m_bStringGID === false) ? this.m_arrCacheSizes : this.m_arrCacheSizesGid;

			for (var nIndex = 0; nIndex < pString.GetLength(); ++nIndex)
			{
				var pCurGlyph = pString.GetAt(nIndex);
				var ushUnicode = pCurGlyph.lUnicode;

				var charSymbolObj = _cache_array[ushUnicode];
                if (undefined == charSymbolObj || null == charSymbolObj.oBitmap)
                {
                    _cache_array[ushUnicode] = this.CacheGlyph(ushUnicode, true);
                    charSymbolObj = _cache_array[ushUnicode];
                }

				var nCMapIndex = charSymbolObj.nCMapIndex;
				var unGID = charSymbolObj.ushGID;
				var eState = charSymbolObj.eState;

				if (EGlyphState.glyphstateMiss == eState)
				{
					pString.SetStartPoint(nIndex, fPenX, fPenY);
					pString.SetBBox(nIndex, 0, 0, 0, 0);
					pString.SetState(nIndex, EGlyphState.glyphstateMiss);

					fPenX += charSymbolObj.fAdvanceX + this.m_fCharSpacing;
					unPrevGID = 0;

					continue;
				}
				else if (EGlyphState.glyphstateDefault == eState)
				{
					pString.SetState(nIndex, EGlyphState.glyphstateDefault);
                    // kerning face!!!
				}
				else
				{
					pString.SetState(nIndex, EGlyphState.glyphstateNormal);
                    // kerning face!!!
				}

				/*
				if (0 != this.m_nNum_charmaps)
				{
					var nCharmap = pFace.charmap;
					var nCurCMapIndex = AscFonts.FT_Get_Charmap_Index(nCharmap);
					if (nCurCMapIndex != nCMapIndex)
					{
						nCMapIndex = Math.max(0, nCMapIndex);
						nCharmap = this.m_pFace.charmaps[nCMapIndex];
						AscFonts.FT_Set_Charmap(this.m_pFace, nCharmap);
					}
				}
				*/

				if (this.m_bUseKerning && unPrevGID && (nIndex > 0 && pString.GetAt(nIndex).eState == pString.GetAt(nIndex - 1).eState))
				{
					fPenX += this.GetKerning(unPrevGID, unGID);
				}

				var fX = pString.m_fX + fPenX;
				var fY = pString.m_fY + fPenY;

				// Начальную точку рассчитываем сразу исходя из глобальной матрицы
				var fXX = (pString.m_arrCTM[4] + fX * pString.m_arrCTM[0] + fY * pString.m_arrCTM[2] - pString.m_fX);
				var fYY = (pString.m_arrCTM[5] + fX * pString.m_arrCTM[1] + fY * pString.m_arrCTM[3] - pString.m_fY);

				pString.SetStartPoint(nIndex, fXX, fYY);

                pCurGlyph.oMetrics = charSymbolObj.oMetrics;
				pString.SetBBox(nIndex, charSymbolObj.oBBox.fMinX, charSymbolObj.oBBox.fMaxY, charSymbolObj.oBBox.fMaxX, charSymbolObj.oBBox.fMinY);
				fPenX += charSymbolObj.fAdvanceX + this.m_fCharSpacing;

				if (this.m_bNeedDoBold && this.m_oFontManager.IsAdvanceNeedBoldFonts)
				{
					// Когда текст делаем жирным сами, то мы увеличиваем расстояние на 1 пиксель в ширину (независимо от DPI и размера текста всегда 1 пиксель)
					fPenX += 1;
				}

				pCurGlyph.bBitmap = charSymbolObj.bBitmap;
				pCurGlyph.oBitmap = charSymbolObj.oBitmap;

				unPrevGID = unGID;
			}

			pString.m_fEndX = fPenX + pString.m_fX;
			pString.m_fEndY = fPenY + pString.m_fY;
		};

		this.GetString2C = function(pString)
		{
			// Сначала мы все рассчитываем исходя только из матрицы шрифта FontMatrix
            if (this.m_bIsTransform)
                this.UpdateMatrix();

			var pCurGlyph = pString.m_pGlyphsBuffer[0];
			var ushUnicode = pCurGlyph.lUnicode;

			var _cache_array = (this.m_bStringGID === false) ? this.m_arrCacheSizes : this.m_arrCacheSizesGid;

            var charSymbolObj = _cache_array[ushUnicode];
            if (undefined == charSymbolObj || (null == charSymbolObj.oBitmap && charSymbolObj.bBitmap === false))
            {
                _cache_array[ushUnicode] = this.CacheGlyph(ushUnicode, true);
                charSymbolObj = _cache_array[ushUnicode];
            }

            if (!charSymbolObj)
            	return;

			var eState = charSymbolObj.eState;
			pCurGlyph.eState = charSymbolObj.eState;
			if (EGlyphState.glyphstateMiss == eState)
			{
				pCurGlyph.fX = 0;
				pCurGlyph.fY = 0;

				pCurGlyph.fLeft = 0;
				pCurGlyph.fTop = 0;
				pCurGlyph.fRight = 0;
				pCurGlyph.fBottom = 0;
				return;
			}

			// кернинга нету пока.
            var fX = pString.m_fX;
            var fY = pString.m_fY;
            var _m = pString.m_arrCTM;

            // Начальную точку рассчитываем сразу исходя из глобальной матрицы
            pCurGlyph.fX = (_m[4] + fX * _m[0] + fY * _m[2] - pString.m_fX);
            pCurGlyph.fY = (_m[5] + fX * _m[1] + fY * _m[3] - pString.m_fY);

			//pString.SetMetrics(nIndex, charSymbolObj.oMetrics.fWidth, charSymbolObj.oMetrics.fHeight, charSymbolObj.oMetrics.fHoriAdvance, charSymbolObj.oMetrics.fHoriBearingX, charSymbolObj.oMetrics.fHoriBearingY, charSymbolObj.oMetrics.fVertAdvance, charSymbolObj.oMetrics.fVertBearingX, charSymbolObj.oMetrics.fVertBearingY);
			pCurGlyph.oMetrics = charSymbolObj.oMetrics;

			/*
			pCurGlyph.fLeft   = charSymbolObj.oBBox.fMinX;
			pCurGlyph.fTop    = charSymbolObj.oBBox.fMaxY;
			pCurGlyph.fRight  = charSymbolObj.oBBox.fMaxX;
			pCurGlyph.fBottom = charSymbolObj.oBBox.fMinY;
			*/

			pCurGlyph.bBitmap = charSymbolObj.bBitmap;
			pCurGlyph.oBitmap = charSymbolObj.oBitmap;

            pString.m_fEndX = charSymbolObj.fAdvanceX + this.m_fCharSpacing + pString.m_fX;
            pString.m_fEndY = pString.m_fY;

            if (this.m_bNeedDoBold && this.m_oFontManager.IsAdvanceNeedBoldFonts)
            {
                // Когда текст делаем жирным сами, то мы увеличиваем расстояние на 1 пиксель в ширину (независимо от DPI и размера текста всегда 1 пиксель)
                pString.m_fEndX += this.m_unHorDpi / 72;
            }
		};

		this.GetChar = function(lUnicode, is_raster_distances)
		{
			var Result = undefined;
			var ushUnicode = lUnicode;

			// Сначала мы все рассчитываем исходя только из матрицы шрифта FontMatrix
            if (this.m_bIsTransform)
                this.UpdateMatrix();

			var _cache_array = (this.m_bStringGID === false) ? this.m_arrCacheSizes : this.m_arrCacheSizesGid;

            var charSymbolObj = _cache_array[ushUnicode];
            if (undefined == charSymbolObj)
            {
                _cache_array[ushUnicode] = this.CacheGlyph(ushUnicode, false, is_raster_distances);
                charSymbolObj = _cache_array[ushUnicode];
            }

            return charSymbolObj;
		};

		this.GetCharPath = function(lUnicode, worker, x, y)
		{
			var pFace = this.m_pFace;
			var pCurentGliph = pFace.glyph;

			var Result;
			var ushUnicode = lUnicode;

			// Сначала мы все рассчитываем исходя только из матрицы шрифта FontMatrix
            if (this.m_bIsTransform)
                this.UpdateMatrix();

            // no really cashe
            this.CacheGlyph(ushUnicode, false, false, worker, x, y);
		};

        this.GetStringPath = function(string, worker)
        {
            var _len = string.GetLength();
            if (_len <= 0)
                return true;

            for (var nIndex = 0; nIndex < _len; ++nIndex)
            {
                var _glyph = string.m_pGlyphsBuffer[nIndex];
                var _x = string.m_fX + 25.4 * _glyph.fX / this.m_unHorDpi;
                var _y = string.m_fY + 25.4 * _glyph.fY / this.m_unVerDpi;

                worker._s();
                this.GetCharPath(_glyph.lUnicode, worker, _x, _y);
                worker.df();
                worker._e();
            }
        };

        this.SetCMapForCharCode = function(lUnicode, pnCMapIndex)
        {
            if (this.m_bStringGID || !this.m_pFace || 0 == this.m_nNum_charmaps)
                return lUnicode;

            var nCharIndex = 0;

            var charMapArray = this.m_pFace.charmaps;
            for (var nIndex = 0; nIndex < this.m_nNum_charmaps; ++nIndex)
            {
                var pCMap = charMapArray[nIndex];
                var pCharMap = __FT_CharmapRec(pCMap);

                if (0 != FT_Set_Charmap(this.m_pFace, pCMap))
                    continue;

                var pEncoding = pCharMap.encoding;

                if (FT_ENCODING_UNICODE == pEncoding)
                {
                    if ((nCharIndex = FT_Get_Char_Index(this.m_pFace, lUnicode)) != 0)
                    {
                        pnCMapIndex.index = nIndex;
                        return nCharIndex;
                    }
                }
                else if (FT_ENCODING_NONE == pEncoding || FT_ENCODING_MS_SYMBOL == pEncoding || FT_ENCODING_APPLE_ROMAN == pEncoding)
                {
                    /*
                     var res_code = FT_Get_First_Char(this.m_pFace);
                     while (res_code.gindex != 0)
                     {
                     res_code = FT_Get_Next_Char(this.m_pFace, res_code.char_code);
                     if (res_code.char_code == lUnicode)
                     {
                     nCharIndex = res_code.gindex;
                     pnCMapIndex.index = nIndex;
                     break;
                     }
                     }
                     */

                    nCharIndex = FT_Get_Char_Index(this.m_pFace, lUnicode);
                    if (0 != nCharIndex)
                        pnCMapIndex.index = nIndex;
                }
            }

            return nCharIndex;
        };

		this.GetCharLoadMode = function()
        {
            return (this.HintsSupport && this.HintsSubpixelSupport) ? this.m_oFontManager.LOAD_MODE : 40970;
        };

        this.GetKerning = function(unPrevGID, unGID)
        {
            var pDelta = new AscFonts.FT_Vector();
            AscFonts.FT_Get_Kerning(this.m_pFace, unPrevGID, unGID, 0, pDelta);
            return (pDelta.x >> 6);
        };

        this.SetStringGID = function(bGID)
        {
            if (this.m_bStringGID == bGID)
                return;

            this.m_bStringGID = bGID;
        };

        this.GetStringGID = function()
        {
            return this.m_bStringGID;
        };

        this.SetCharSpacing = function(fCharSpacing)
        {
            this.m_fCharSpacing = fCharSpacing;
        };

        this.GetCharSpacing = function()
        {
            return this.m_fCharSpacing;
        };

        this.GetStyleName = function()
        {
            return this.m_pFace.style_name;
        };

        this.UpdateStyles = function(bBold, bItalic)
        {
            var sStyle = this.GetStyleName();

            // Смотрим какой стиль у исходного шрифта
            var bSrcBold = (-1 != sStyle.indexOf("Bold"));
            var bSrcItalic = (-1 != sStyle.indexOf("Italic"));

            this.SetNeedBold(bBold && !bSrcBold);
            this.SetNeedItalic(bItalic && !bSrcItalic);
        };

        this.IsBold = function()
        {
        	if (this.m_bNeedDoBold)
        		return true;

        	return (-1 != this.m_pFace.style_name.indexOf("Bold")) ? true : false;
        };

        this.IsItalic = function()
        {
            if (this.m_bNeedDoItalic)
                return true;

            return (-1 != this.m_pFace.style_name.indexOf("Italic")) ? true : false;
        };

        this.SetNeedItalic = function(value)
        {
            if (this.m_bNeedDoItalic != value)
            {
                this.ClearCache();
                this.m_bNeedDoItalic = value;
                this.ResetFontMatrix();
            }
        };

        this.SetNeedBold = function(value)
        {
            if (this.m_bNeedDoBold != value)
            {
                this.ClearCache();
                this.m_bNeedDoBold = value;
            }
        };

        this.IsSuccess = function()
        {
            return (0 == this.m_nError);
        };

        this.GetAscender = function()
        {
            return this.m_lAscender;
        };

        this.GetDescender = function()
        {
            return this.m_lDescender;
        };

        this.GetHeight = function()
        {
            return this.m_lLineHeight;
        };

        this.Units_Per_Em = function()
        {
            return this.m_lUnits_Per_Em;
        };

        this.CheckHintsSupport = function()
        {
            this.HintsSupport = true;

            if (!this.m_pFace || !this.m_pFace.driver || !this.m_pFace.driver.clazz)
                return;

            if (this.m_pFace.driver.clazz.name != "truetype")
            {
                this.HintsSupport = false;
                return;
            }

            if (this.m_pFace.family_name == "MS Mincho" ||
                this.m_pFace.family_name == "Castellar")
            {
                this.HintsSupport = false;
            }
            else if (this.m_pFace.family_name == "Microsoft JhengHei UI Light" ||
                this.m_pFace.family_name == "Kalinga")
            {
                this.HintsSubpixelSupport = false;
            }
        };
	}

	function CFontLoaderBySymbol()
	{
		this.FontFiles = {};

		this.LoadSymbol = function(pFontFile, symbol, isRaster, isRasterDistances, workerVector, workerVectorX, workerVectorY, isFromPicker)
		{
			var fontManager = pFontFile.m_oFontManager;

			var name = AscFonts.FontPickerByCharacter.getFontBySymbol(symbol);
			if (undefined === name || name == "")
				return null;

			var _fontFilePick = this.FontFiles[name];
			if (!_fontFilePick)
			{
                var _font_info = AscFonts.g_font_infos[AscFonts.g_map_font_index[name]];
                var _style = AscFonts.FontStyle.FontStyleRegular;
                if (pFontFile.IsBold())
                	_style |= AscFonts.FontStyle.FontStyleBold;
                if (pFontFile.IsItalic())
                    _style |= AscFonts.FontStyle.FontStyleItalic;

                _fontFilePick = _font_info.LoadFont(AscCommon.g_font_loader, fontManager, pFontFile.m_fSize, _style, pFontFile.m_unHorDpi, pFontFile.m_unVerDpi, undefined, true);

                if (!_fontFilePick)
                	return null;

                _fontFilePick.CheckHintsSupport();
                this.FontFiles[name] = _fontFilePick;
			}

			if (!_fontFilePick)
				return null;

            _fontFilePick.SetSizeAndDpi(pFontFile.m_fSize, pFontFile.m_unHorDpi, pFontFile.m_unVerDpi);

            var s = pFontFile.m_arrdTextMatrix;
            var d = _fontFilePick.m_arrdTextMatrix;

            d[0] = s[0];
            d[1] = s[1];
            d[2] = s[2];
            d[3] = s[3];
            d[4] = s[4];
            d[5] = s[5];

            _fontFilePick.UpdateMatrix();
            return _fontFilePick.CacheGlyph(symbol, isRaster, isRasterDistances, workerVector, workerVectorX, workerVectorY, true);
		};

		this.ClearCache = function()
		{
			for (var font in this.FontFiles)
				this.FontFiles[font].ClearCache();
		};

		this.ClearCacheNoAttack = function()
		{
            for (var font in this.FontFiles)
                this.FontFiles[font].ClearCacheNoAttack();
		};
	}

	window['AscFonts'] = window['AscFonts'] || {};
	window['AscFonts'].EGlyphState = EGlyphState;
	window['AscFonts'].CFontFile = CFontFile;
})(window);
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined) {

    function CFontFilesCache()
    {
        this.m_oLibrary = null;
        this.m_lMaxSize = 1000;
        this.m_lCurrentSize = 0;
        this.Fonts = {};

        this.LoadFontFile = function(stream_index, name, faceindex, fontManager)
        {
            var args = new AscFonts.FT_Open_Args();
            args.flags = 0x02;
            args.stream = AscFonts.g_fonts_streams[stream_index];

            var face = this.m_oLibrary.FT_Open_Face(args, faceindex);
            if (null == face)
                return null;

            var font = new AscFonts.CFontFile(name, faceindex);

            font.m_lUnits_Per_Em = face.units_per_EM;
            font.m_lAscender = face.ascender;
            font.m_lDescender = face.descender;
            font.m_lLineHeight = face.height;

            if (fontManager.IsUseWinOS2Params && face.os2 && face.os2.version != 0xFFFF)
            {
                var _os2 = face.os2;
                if (this.IsCellMode)
                {
                    /*
                    // что-то типо этого в экселе... пока выключаем
                    var _addidive = (0.15 * font.m_lLineHeight) >> 0;
                    font.m_lAscender += ((_addidive + 1) >> 1);
                    font.m_lDescender -= (_addidive >> 1);
                    font.m_lLineHeight += _addidive;
                    */

                    var _winAscent = face.os2.usWinAscent;
                    var _winDescent = -face.os2.usWinDescent;

                    // experimantal: for cjk fonts lineheight *= 1.3
                    if ((face.os2.ulUnicodeRange2 & 0x2DF00000) != 0)
                    {
                        var _addidive = (0.3 * (_winAscent - _winDescent)) >> 0;
                        _winAscent += ((_addidive + 1) >> 1);
                        _winDescent -= (_addidive >> 1);
                    }

                    // TODO:
                    // https://www.microsoft.com/typography/otspec/recom.htm - hhea, not typo!!!
                    if (font.m_lLineHeight < (_winAscent - _winDescent))
                    {
                        font.m_lAscender = _winAscent;
                        font.m_lDescender = _winDescent;
                        font.m_lLineHeight = _winAscent - _winDescent;
                    }
                }
                else
                {
                    var bIsUseTypeAttack = ((_os2.fsSelection & 128) == 128) ? true : false;
                    if (bIsUseTypeAttack)
                    {
                        font.m_lAscender  = face.os2.sTypoAscender;
                        font.m_lDescender = face.os2.sTypoDescender;

                        font.m_lLineHeight = (face.os2.sTypoAscender - face.os2.sTypoDescender + face.os2.sTypoLineGap);
                    }
                    else if (false)
                    {
                        font.m_lAscender  = face.os2.usWinAscent;
                        font.m_lDescender = -face.os2.usWinDescent;

                        font.m_lLineHeight = (face.os2.usWinAscent + face.os2.usWinDescent);
                    }
                }
            }

            font.m_nNum_charmaps = face.num_charmaps;

            font.m_pFace = face;
            font.LoadDefaultCharAndSymbolicCmapIndex();
            font.m_nError = AscFonts.FT_Set_Char_Size(face, 0, font.m_fSize * 64, 0, 0);

            if (!font.IsSuccess())
            {
                font = null;
                face = null;
                return null;
            }

            font.ResetTextMatrix();
            font.ResetFontMatrix();

            if (true === font.m_bUseKerning)
            {
                font.m_bUseKerning = ((face.face_flags & 64) != 0 ? true : false);
            }

            return font;
        };

        this.LockFont = function(stream_index, fontName, faceIndex, fontSize, _ext, fontManager)
        {
            var key = fontName + faceIndex + fontSize;
            if (undefined !== _ext)
                key += _ext;
            var pFontFile = this.Fonts[key];
            if (pFontFile)
                return pFontFile;

            pFontFile = this.Fonts[key] = this.LoadFontFile(stream_index, fontName, faceIndex, fontManager);
            return pFontFile;
        };
    }

    function CDefaultFont()
    {
        this.m_oLibrary = null;
        this.m_arrDefaultFont = new Array(4);

        this.SetDefaultFont = function(sFamilyName)
        {
            var fontInfo = g_fontApplication.GetFontInfo(sFamilyName);
            var font = null;

            var _defaultIndex = fontInfo.indexR;
            if (-1 == _defaultIndex)
                _defaultIndex = fontInfo.indexI;
            if (-1 == _defaultIndex)
                _defaultIndex = fontInfo.indexB;
            if (-1 == _defaultIndex)
                _defaultIndex = fontInfo.indexBI;

            var _indexR = fontInfo.indexR != -1 ? fontInfo.indexR : _defaultIndex;
            var _indexI = fontInfo.indexI != -1 ? fontInfo.indexI : _defaultIndex;
            var _indexB = fontInfo.indexB != -1 ? fontInfo.indexB : _defaultIndex;
            var _indexBI = fontInfo.indexBI != -1 ? fontInfo.indexBI : _defaultIndex;

            var fontInfos = AscFonts.g_font_infos;
            font = fontInfos[_indexR];
            this.m_arrDefaultFont[0] = this.m_oLibrary.LoadFont(font.stream_index, font.id, fontInfo.faceIndexR);
            this.m_arrDefaultFont[0].UpdateStyles(false, false);

            font = fontInfos[_indexB];
            this.m_arrDefaultFont[1] = this.m_oLibrary.LoadFont(font.stream_index, font.id, fontInfo.faceIndexB);
            this.m_arrDefaultFont[1].UpdateStyles(true, false);

            font = fontInfos[_indexI];
            this.m_arrDefaultFont[2] = this.m_oLibrary.LoadFont(font.stream_index, font.id, fontInfo.faceIndexI);
            this.m_arrDefaultFont[2].UpdateStyles(false, true);

            font = fontInfos[_indexBI];
            this.m_arrDefaultFont[3] = this.m_oLibrary.LoadFont(font.stream_index, font.id, fontInfo.faceIndexBI);
            this.m_arrDefaultFont[3].UpdateStyles(true, true);
        };

        this.GetDefaultFont = function(bBold, bItalic)
        {
            var nIndex = (bBold ? 1 : 0) + (bItalic ? 2 : 0);
            return this.m_arrDefaultFont[nIndex];
        };
    }

    // params: { mode: "cell" };
    function CFontManager(params)
    {
        this.m_oLibrary = null;

        this.m_pFont = null;
        this.m_oGlyphString = new AscFonts.CGlyphString();

        this.error = 0;

        this.fontName = undefined;

        this.m_bUseDefaultFont = false;
        this.m_fCharSpacing = 0.0;
        this.m_bStringGID = false;

        this.m_oFontsCache = null;
        this.m_oDefaultFont = new CDefaultFont();

        this.m_lUnits_Per_Em = 0;
        this.m_lAscender = 0;
        this.m_lDescender = 0;
        this.m_lLineHeight = 0;

        this.RasterMemory = null;

        this.LOAD_MODE = 40970;

        this.IsCellMode = (params && params.mode == "cell") ? true : false;
        this.IsAdvanceNeedBoldFonts = this.IsCellMode;
        this.IsUseWinOS2Params = true;

        this.AfterLoad = function()
        {
            if (null == this.m_pFont)
            {
                this.m_lUnits_Per_Em = 0;
                this.m_lAscender = 0;
                this.m_lDescender = 0;
                this.m_lLineHeight = 0;
            }
            else
            {
                var f = this.m_pFont;
                this.m_lUnits_Per_Em = f.m_lUnits_Per_Em;
                this.m_lAscender = f.m_lAscender;
                this.m_lDescender = f.m_lDescender;
                this.m_lLineHeight = f.m_lLineHeight;

                f.CheckHintsSupport();
            }
        };

        this.Initialize = function(is_init_raster_memory)
        {
            this.m_oLibrary = new AscFonts.FT_Library();
            this.m_oLibrary.Init();

            this.m_oFontsCache = new CFontFilesCache();
            this.m_oFontsCache.m_oFontManager = this;
            this.m_oFontsCache.m_oLibrary = this.m_oLibrary;

            if (is_init_raster_memory === true)
            {
                if (AscCommon.AscBrowser.isIE && !AscCommon.AscBrowser.isArm)
                {
                    this.RasterMemory = new AscFonts.CRasterHeapTotal();
                    this.RasterMemory.CreateFirstChuck();
                }
            }
        };

        this.ClearFontsRasterCache = function()
        {
            for (var i in this.m_oFontsCache.Fonts)
            {
                if (this.m_oFontsCache.Fonts[i])
                    this.m_oFontsCache.Fonts[i].ClearCache();
            }
            //this.m_oFontsCache.Fonts = [];
            this.ClearRasterMemory();
        };

        this.ClearRasterMemory = function()
        {
            // быстрая очистка всей памяти (убирание всех дыр)
            if (null == this.RasterMemory || null == this.m_oFontsCache)
                return;

            var _fonts = this.m_oFontsCache.Fonts;
            for (var i in _fonts)
            {
                if (_fonts[i] !== undefined && _fonts[i] != null)
                    _fonts[i].ClearCacheNoAttack();
            }

            this.RasterMemory.Clear();
        };

        this.SetDefaultFont = function(name)
        {
            this.m_oDefaultFont.m_oLibrary = this.m_oLibrary;
            this.m_oDefaultFont.SetDefaultFont(name);
        };

        this.UpdateSize = function(dOldSize, dDpi, dNewDpi)
        {
            if (0 == dNewDpi)
                dNewDpi = 72.0;
            if (0 == dDpi)
                dDpi = 72.0;

            return dOldSize * dDpi / dNewDpi;
        };

        this.LoadString = function(wsBuffer, fX, fY)
        {
            if (!this.m_pFont)
                return false;

            this.m_oGlyphString.SetString(wsBuffer, fX, fY);
            this.m_pFont.GetString(this.m_oGlyphString);

            return true;
        };

        this.LoadString2 = function(wsBuffer, fX, fY)
        {
            if (!this.m_pFont)
                return false;

            this.m_oGlyphString.SetString(wsBuffer, fX, fY);
            this.m_pFont.GetString2(this.m_oGlyphString);

            return true;
        };

        this.LoadString3 = function(gid, fX, fY)
        {
            if (!this.m_pFont)
                return false;

            this.SetStringGID(true);
            this.m_oGlyphString.SetStringGID (gid, fX, fY);
            this.m_pFont.GetString2(this.m_oGlyphString);
            this.SetStringGID(false);

            return true;
        };

        this.LoadString3C = function(gid, fX, fY)
        {
            if (!this.m_pFont)
                return false;

            this.SetStringGID(true);

            // это SetString
            var string = this.m_oGlyphString;

            string.m_fX = fX + string.m_fTransX;
            string.m_fY = fY + string.m_fTransY;

            string.m_nGlyphsCount = 1;
            string.m_nGlyphIndex  = 0;

            var _g = string.GetFirstGlyph();
            _g.bBitmap = false;
            _g.oBitmap = null;
            _g.eState = AscFonts.EGlyphState.glyphstateNormal;
            _g.lUnicode = gid;

            this.m_pFont.GetString2C(string);

            this.SetStringGID(false);
            return true;
        };

        this.LoadString2C = function(wsBuffer, fX, fY)
        {
            if (!this.m_pFont)
                return false;

            // это SetString
            var string = this.m_oGlyphString;

            string.m_fX = fX + string.m_fTransX;
            string.m_fY = fY + string.m_fTransY;

            string.m_nGlyphsCount = 1;
            string.m_nGlyphIndex  = 0;

            var _g = string.GetFirstGlyph();
            _g.bBitmap = false;
            _g.oBitmap = null;
            _g.eState = AscFonts.EGlyphState.glyphstateNormal;
            _g.lUnicode = wsBuffer.charCodeAt(0);

            this.m_pFont.GetString2C(string);
            return string.m_fEndX;
        };

        this.LoadString4C = function(lUnicode, fX, fY)
        {
            if (!this.m_pFont)
                return false;

            // это SetString
            var string = this.m_oGlyphString;

            string.m_fX = fX + string.m_fTransX;
            string.m_fY = fY + string.m_fTransY;

            string.m_nGlyphsCount = 1;
            string.m_nGlyphIndex  = 0;

            var _g = string.GetFirstGlyph();
            _g.bBitmap = false;
            _g.oBitmap = null;
            _g.eState = AscFonts.EGlyphState.glyphstateNormal;
            _g.lUnicode = lUnicode;

            this.m_pFont.GetString2C(string);
            return string.m_fEndX;
        };

        this.LoadStringPathCode = function(code, isGid, fX, fY, worker)
        {
            if (!this.m_pFont)
                return false;

            this.SetStringGID(isGid);

            // это SetString
            var string = this.m_oGlyphString;

            string.m_fX = fX + string.m_fTransX;
            string.m_fY = fY + string.m_fTransY;

            string.m_nGlyphsCount = 1;
            string.m_nGlyphIndex  = 0;

            var _g = string.GetFirstGlyph();
            _g.bBitmap = false;
            _g.oBitmap = null;
            _g.eState = AscFonts.EGlyphState.glyphstateNormal;
            _g.lUnicode = code;

            this.m_pFont.GetStringPath(string, worker);

            this.SetStringGID(false);

            return true;
        };

        this.LoadChar = function(lUnicode)
        {
            if (!this.m_pFont)
                return false;

            return this.m_pFont.GetChar2(lUnicode);
        };

        this.MeasureChar = function(lUnicode, is_raster_distances)
        {
            if (!this.m_pFont)
                return;

            return this.m_pFont.GetChar(lUnicode, is_raster_distances);
        };

        this.GetKerning = function(unPrevGID, unGID)
        {
            if (!this.m_pFont)
                return;

            return this.m_pFont.GetKerning(unPrevGID, unGID);
        };

        this.MeasureString = function()
        {
            var oPoint = new AscFonts.CGlyphRect();
            var len = this.m_oGlyphString.GetLength();
            if (len <= 0)
                return oPoint;

            var fTop = 0xFFFF, fBottom = -0xFFFF, fLeft = 0xFFFF, fRight = -0xFFFF;
            for (var nIndex = 0; nIndex < len; ++nIndex)
            {
                var oSizeTmp = this.m_oGlyphString.GetBBox (nIndex);

                if (fBottom < oSizeTmp.fBottom)
                    fBottom = oSizeTmp.fBottom;

                if (fTop > oSizeTmp.fTop)
                    fTop = oSizeTmp.fTop;

                if (fLeft > oSizeTmp.fLeft)
                    fLeft = oSizeTmp.fLeft;

                if (fRight < oSizeTmp.fRight)
                    fRight = oSizeTmp.fRight;
            }

            oPoint.fX = fLeft;
            oPoint.fY = fTop;

            oPoint.fWidth  = Math.abs((fRight - fLeft));
            oPoint.fHeight = Math.abs((fTop - fBottom));

            return oPoint;
        };

        this.MeasureString2 = function()
        {
            var oPoint = new AscFonts.CGlyphRect();

            if (this.m_oGlyphString.GetLength() <= 0)
                return oPoint;

            var fTop = 0xFFFF, fBottom = -0xFFFF, fLeft = 0xFFFF, fRight = -0xFFFF;

            var oSizeTmp = this.m_oGlyphString.GetBBox2();

            oPoint.fX = oSizeTmp.fLeft;
            oPoint.fY = oSizeTmp.fTop;

            oPoint.fWidth  = Math.abs((oSizeTmp.fRight - oSizeTmp.fLeft));
            oPoint.fHeight = Math.abs((oSizeTmp.fTop - oSizeTmp.fBottom));

            return oPoint;
        };

        this.GetNextChar2 = function()
        {
            return this.m_oGlyphString.GetNext();
        };

        this.IsSuccess = function()
        {
            return (0 == this.error);
        };

        this.SetTextMatrix = function(fA, fB, fC, fD, fE, fF)
        {
            if (!this.m_pFont)
                return false;

            if (this.m_pFont.SetTextMatrix (fA, fB, fC, fD, 0, 0))
                this.m_oGlyphString.SetCTM(fA, fB, fC, fD, 0, 0);
            this.m_oGlyphString.SetTrans(fE, fF);

            return true;
        };

        this.SetTextMatrix2 = function(fA, fB, fC, fD, fE, fF)
        {
            if (!this.m_pFont)
                return false;

            this.m_pFont.SetTextMatrix (fA, fB, fC, fD, 0, 0);
            this.m_oGlyphString.SetCTM(fA, fB, fC, fD, 0, 0);
            this.m_oGlyphString.SetTrans(fE, fF);

            return true;
        };

        this.SetStringGID = function(bStringGID)
        {
            this.m_bStringGID = bStringGID;

            if (!this.m_pFont)
                return;

            this.m_pFont.SetStringGID(this.m_bStringGID);
        };

        this.SetHintsProps = function(bIsHinting, bIsSubpixHinting)
        {
            if (undefined === AscCommon.g_fontManager.m_oLibrary.tt_hint_props)
                return;

            if (bIsHinting && bIsSubpixHinting)
            {
                this.m_oLibrary.tt_hint_props.TT_USE_BYTECODE_INTERPRETER = true;
                this.m_oLibrary.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING = true;

                this.LOAD_MODE = 40968;
            }
            else if (bIsHinting)
            {
                this.m_oLibrary.tt_hint_props.TT_USE_BYTECODE_INTERPRETER = true;
                this.m_oLibrary.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING = false;

                this.LOAD_MODE = 40968;
            }
            else
            {
                this.m_oLibrary.tt_hint_props.TT_USE_BYTECODE_INTERPRETER = true;
                this.m_oLibrary.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING = false;

                this.LOAD_MODE = 40970;
            }
        };

        this.SetAdvanceNeedBoldFonts = function(value)
        {
            this.IsAdvanceNeedBoldFonts = value;
        };

        this.LoadFont = function(fontFile, faceIndex, size, isBold, isItalic, needBold, needItalic, isNoSetupToManager)
        {
            var _ext = "";
            if (needBold)
                _ext += "nbold";
            if (needItalic)
                _ext += "nitalic";

            var pFontFile = this.m_oFontsCache.LockFont(fontFile.stream_index, fontFile.Id, faceIndex, size, _ext, this);

            if (!pFontFile)
                pFontFile = this.m_oDefaultFont.GetDefaultFont(isBold, isItalic);

            if (!pFontFile)
                return null;

            pFontFile.m_oFontManager = this;

            pFontFile.SetNeedBold(needBold);
            pFontFile.SetNeedItalic(needItalic);

            pFontFile.SetStringGID(this.m_bStringGID);
            pFontFile.SetCharSpacing(this.m_fCharSpacing);

            if (isNoSetupToManager !== true)
            {
				this.m_pFont = pFontFile;
				this.m_oGlyphString.ResetCTM();
                this.AfterLoad();
            }

            return pFontFile;
        };
    }

    window['AscFonts'].CFontManager = CFontManager;
    window['AscFonts'].CFontFilesCache = CFontFilesCache;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var g_memory = AscFonts.g_memory;

var fontslot_ASCII    = 0x00;
var fontslot_EastAsia = 0x01;
var fontslot_CS       = 0x02;
var fontslot_HAnsi    = 0x03;

var fonthint_Default  = 0x00;
var fonthint_CS       = 0x01;
var fonthint_EastAsia = 0x02;

var lcid_unknown = 0x0000; // Unknown
var lcid_ar = 0x0001; // Arabic
var lcid_bg = 0x0002; // Bulgarian
var lcid_ca = 0x0003; // Catalan
var lcid_zhHans = 0x0004; // Chinese, Han (Simplified variant)
var lcid_cs = 0x0005; // Czech
var lcid_da = 0x0006; // Danish
var lcid_de = 0x0007; // German
var lcid_el = 0x0008; // Modern Greek (1453-)
var lcid_en = 0x0009; // English
var lcid_es = 0x000a; // Spanish
var lcid_fi = 0x000b; // Finnish
var lcid_fr = 0x000c; // French
var lcid_he = 0x000d; // Hebrew
var lcid_hu = 0x000e; // Hungarian
var lcid_is = 0x000f; // Icelandic
var lcid_it = 0x0010; // Italian
var lcid_ja = 0x0011; // Japanese
var lcid_ko = 0x0012; // Korean
var lcid_nl = 0x0013; // Dutch
var lcid_no = 0x0014; // Norwegian
var lcid_pl = 0x0015; // Polish
var lcid_pt = 0x0016; // Portuguese
var lcid_rm = 0x0017; // Romansh
var lcid_ro = 0x0018; // Romanian
var lcid_ru = 0x0019; // Russian
var lcid_hr = 0x001a; // Croatian
var lcid_sk = 0x001b; // Slovak
var lcid_sq = 0x001c; // Albanian
var lcid_sv = 0x001d; // Swedish
var lcid_th = 0x001e; // Thai
var lcid_tr = 0x001f; // Turkish
var lcid_ur = 0x0020; // Urdu
var lcid_id = 0x0021; // Indonesian
var lcid_uk = 0x0022; // Ukrainian
var lcid_be = 0x0023; // Belarusian
var lcid_sl = 0x0024; // Slovenian
var lcid_et = 0x0025; // Estonian
var lcid_lv = 0x0026; // Latvian
var lcid_lt = 0x0027; // Lithuanian
var lcid_tg = 0x0028; // Tajik
var lcid_fa = 0x0029; // Persian
var lcid_vi = 0x002a; // Vietnamese
var lcid_hy = 0x002b; // Armenian
var lcid_az = 0x002c; // Azerbaijani
var lcid_eu = 0x002d; // Basque
var lcid_hsb = 0x002e; // Upper Sorbian
var lcid_mk = 0x002f; // Macedonian
var lcid_tn = 0x0032; // Tswana
var lcid_xh = 0x0034; // Xhosa
var lcid_zu = 0x0035; // Zulu
var lcid_af = 0x0036; // Afrikaans
var lcid_ka = 0x0037; // Georgian
var lcid_fo = 0x0038; // Faroese
var lcid_hi = 0x0039; // Hindi
var lcid_mt = 0x003a; // Maltese
var lcid_se = 0x003b; // Northern Sami
var lcid_ga = 0x003c; // Irish
var lcid_ms = 0x003e; // Malay (macrolanguage)
var lcid_kk = 0x003f; // Kazakh
var lcid_ky = 0x0040; // Kirghiz
var lcid_sw = 0x0041; // Swahili (macrolanguage)
var lcid_tk = 0x0042; // Turkmen
var lcid_uz = 0x0043; // Uzbek
var lcid_tt = 0x0044; // Tatar
var lcid_bn = 0x0045; // Bengali
var lcid_pa = 0x0046; // Panjabi
var lcid_gu = 0x0047; // Gujarati
var lcid_or = 0x0048; // Oriya
var lcid_ta = 0x0049; // Tamil
var lcid_te = 0x004a; // Telugu
var lcid_kn = 0x004b; // Kannada
var lcid_ml = 0x004c; // Malayalam
var lcid_as = 0x004d; // Assamese
var lcid_mr = 0x004e; // Marathi
var lcid_sa = 0x004f; // Sanskrit
var lcid_mn = 0x0050; // Mongolian
var lcid_bo = 0x0051; // Tibetan
var lcid_cy = 0x0052; // Welsh
var lcid_km = 0x0053; // Central Khmer
var lcid_lo = 0x0054; // Lao
var lcid_gl = 0x0056; // Galician
var lcid_kok = 0x0057; // Konkani (macrolanguage)
var lcid_syr = 0x005a; // Syriac
var lcid_si = 0x005b; // Sinhala
var lcid_iu = 0x005d; // Inuktitut
var lcid_am = 0x005e; // Amharic
var lcid_tzm = 0x005f; // Central Atlas Tamazight
var lcid_ne = 0x0061; // Nepali
var lcid_fy = 0x0062; // Western Frisian
var lcid_ps = 0x0063; // Pushto
var lcid_fil = 0x0064; // Filipino
var lcid_dv = 0x0065; // Dhivehi
var lcid_ha = 0x0068; // Hausa
var lcid_yo = 0x006a; // Yoruba
var lcid_quz = 0x006b; // Cusco Quechua
var lcid_nso = 0x006c; // Pedi
var lcid_ba = 0x006d; // Bashkir
var lcid_lb = 0x006e; // Luxembourgish
var lcid_kl = 0x006f; // Kalaallisut
var lcid_ig = 0x0070; // Igbo
var lcid_ii = 0x0078; // Sichuan Yi
var lcid_arn = 0x007a; // Mapudungun
var lcid_moh = 0x007c; // Mohawk
var lcid_br = 0x007e; // Breton
var lcid_ug = 0x0080; // Uighur
var lcid_mi = 0x0081; // Maori
var lcid_oc = 0x0082; // Occitan (post 1500)
var lcid_co = 0x0083; // Corsican
var lcid_gsw = 0x0084; // Swiss German
var lcid_sah = 0x0085; // Yakut
var lcid_qut = 0x0086; //
var lcid_rw = 0x0087; // Kinyarwanda
var lcid_wo = 0x0088; // Wolof
var lcid_prs = 0x008c; // Dari
var lcid_gd = 0x0091; // Scottish Gaelic
var lcid_arSA = 0x0401; // Arabic, Saudi Arabia
var lcid_bgBG = 0x0402; // Bulgarian, Bulgaria
var lcid_caES = 0x0403; // Catalan, Spain
var lcid_zhTW = 0x0404; // Chinese, Taiwan, Province of China
var lcid_csCZ = 0x0405; // Czech, Czech Republic
var lcid_daDK = 0x0406; // Danish, Denmark
var lcid_deDE = 0x0407; // German, Germany
var lcid_elGR = 0x0408; // Modern Greek (1453-), Greece
var lcid_enUS = 0x0409; // English, United States
var lcid_esES_tradnl = 0x040a; // Spanish
var lcid_fiFI = 0x040b; // Finnish, Finland
var lcid_frFR = 0x040c; // French, France
var lcid_heIL = 0x040d; // Hebrew, Israel
var lcid_huHU = 0x040e; // Hungarian, Hungary
var lcid_isIS = 0x040f; // Icelandic, Iceland
var lcid_itIT = 0x0410; // Italian, Italy
var lcid_jaJP = 0x0411; // Japanese, Japan
var lcid_koKR = 0x0412; // Korean, Republic of Korea
var lcid_nlNL = 0x0413; // Dutch, Netherlands
var lcid_nbNO = 0x0414; // Norwegian Bokmal, Norway
var lcid_plPL = 0x0415; // Polish, Poland
var lcid_ptBR = 0x0416; // Portuguese, Brazil
var lcid_rmCH = 0x0417; // Romansh, Switzerland
var lcid_roRO = 0x0418; // Romanian, Romania
var lcid_ruRU = 0x0419; // Russian, Russian Federation
var lcid_hrHR = 0x041a; // Croatian, Croatia
var lcid_skSK = 0x041b; // Slovak, Slovakia
var lcid_sqAL = 0x041c; // Albanian, Albania
var lcid_svSE = 0x041d; // Swedish, Sweden
var lcid_thTH = 0x041e; // Thai, Thailand
var lcid_trTR = 0x041f; // Turkish, Turkey
var lcid_urPK = 0x0420; // Urdu, Pakistan
var lcid_idID = 0x0421; // Indonesian, Indonesia
var lcid_ukUA = 0x0422; // Ukrainian, Ukraine
var lcid_beBY = 0x0423; // Belarusian, Belarus
var lcid_slSI = 0x0424; // Slovenian, Slovenia
var lcid_etEE = 0x0425; // Estonian, Estonia
var lcid_lvLV = 0x0426; // Latvian, Latvia
var lcid_ltLT = 0x0427; // Lithuanian, Lithuania
var lcid_tgCyrlTJ = 0x0428; // Tajik, Cyrillic, Tajikistan
var lcid_faIR = 0x0429; // Persian, Islamic Republic of Iran
var lcid_viVN = 0x042a; // Vietnamese, Viet Nam
var lcid_hyAM = 0x042b; // Armenian, Armenia
var lcid_azLatnAZ = 0x042c; // Azerbaijani, Latin, Azerbaijan
var lcid_euES = 0x042d; // Basque, Spain
var lcid_wenDE = 0x042e; // Sorbian languages, Germany
var lcid_mkMK = 0x042f; // Macedonian, The Former Yugoslav Republic of Macedonia
var lcid_stZA = 0x0430; // Southern Sotho, South Africa
var lcid_tsZA = 0x0431; // Tsonga, South Africa
var lcid_tnZA = 0x0432; // Tswana, South Africa
var lcid_venZA = 0x0433; // South Africa
var lcid_xhZA = 0x0434; // Xhosa, South Africa
var lcid_zuZA = 0x0435; // Zulu, South Africa
var lcid_afZA = 0x0436; // Afrikaans, South Africa
var lcid_kaGE = 0x0437; // Georgian, Georgia
var lcid_foFO = 0x0438; // Faroese, Faroe Islands
var lcid_hiIN = 0x0439; // Hindi, India
var lcid_mtMT = 0x043a; // Maltese, Malta
var lcid_seNO = 0x043b; // Northern Sami, Norway
var lcid_msMY = 0x043e; // Malay (macrolanguage), Malaysia
var lcid_kkKZ = 0x043f; // Kazakh, Kazakhstan
var lcid_kyKG = 0x0440; // Kirghiz, Kyrgyzstan
var lcid_swKE = 0x0441; // Swahili (macrolanguage), Kenya
var lcid_tkTM = 0x0442; // Turkmen, Turkmenistan
var lcid_uzLatnUZ = 0x0443; // Uzbek, Latin, Uzbekistan
var lcid_ttRU = 0x0444; // Tatar, Russian Federation
var lcid_bnIN = 0x0445; // Bengali, India
var lcid_paIN = 0x0446; // Panjabi, India
var lcid_guIN = 0x0447; // Gujarati, India
var lcid_orIN = 0x0448; // Oriya, India
var lcid_taIN = 0x0449; // Tamil, India
var lcid_teIN = 0x044a; // Telugu, India
var lcid_knIN = 0x044b; // Kannada, India
var lcid_mlIN = 0x044c; // Malayalam, India
var lcid_asIN = 0x044d; // Assamese, India
var lcid_mrIN = 0x044e; // Marathi, India
var lcid_saIN = 0x044f; // Sanskrit, India
var lcid_mnMN = 0x0450; // Mongolian, Mongolia
var lcid_boCN = 0x0451; // Tibetan, China
var lcid_cyGB = 0x0452; // Welsh, United Kingdom
var lcid_kmKH = 0x0453; // Central Khmer, Cambodia
var lcid_loLA = 0x0454; // Lao, Lao People's Democratic Republic
var lcid_myMM = 0x0455; // Burmese, Myanmar
var lcid_glES = 0x0456; // Galician, Spain
var lcid_kokIN = 0x0457; // Konkani (macrolanguage), India
var lcid_mni = 0x0458; // Manipuri
var lcid_sdIN = 0x0459; // Sindhi, India
var lcid_syrSY = 0x045a; // Syriac, Syrian Arab Republic
var lcid_siLK = 0x045b; // Sinhala, Sri Lanka
var lcid_chrUS = 0x045c; // Cherokee, United States
var lcid_iuCansCA = 0x045d; // Inuktitut, Unified Canadian Aboriginal Syllabics, Canada
var lcid_amET = 0x045e; // Amharic, Ethiopia
var lcid_tmz = 0x045f; // Tamanaku
var lcid_neNP = 0x0461; // Nepali, Nepal
var lcid_fyNL = 0x0462; // Western Frisian, Netherlands
var lcid_psAF = 0x0463; // Pushto, Afghanistan
var lcid_filPH = 0x0464; // Filipino, Philippines
var lcid_dvMV = 0x0465; // Dhivehi, Maldives
var lcid_binNG = 0x0466; // Bini, Nigeria
var lcid_fuvNG = 0x0467; // Nigerian Fulfulde, Nigeria
var lcid_haLatnNG = 0x0468; // Hausa, Latin, Nigeria
var lcid_ibbNG = 0x0469; // Ibibio, Nigeria
var lcid_yoNG = 0x046a; // Yoruba, Nigeria
var lcid_quzBO = 0x046b; // Cusco Quechua, Bolivia
var lcid_nsoZA = 0x046c; // Pedi, South Africa
var lcid_baRU = 0x046d; // Bashkir, Russian Federation
var lcid_lbLU = 0x046e; // Luxembourgish, Luxembourg
var lcid_klGL = 0x046f; // Kalaallisut, Greenland
var lcid_igNG = 0x0470; // Igbo, Nigeria
var lcid_krNG = 0x0471; // Kanuri, Nigeria
var lcid_gazET = 0x0472; // West Central Oromo, Ethiopia
var lcid_tiER = 0x0473; // Tigrinya, Eritrea
var lcid_gnPY = 0x0474; // Guarani, Paraguay
var lcid_hawUS = 0x0475; // Hawaiian, United States
var lcid_soSO = 0x0477; // Somali, Somalia
var lcid_iiCN = 0x0478; // Sichuan Yi, China
var lcid_papAN = 0x0479; // Papiamento, Netherlands Antilles
var lcid_arnCL = 0x047a; // Mapudungun, Chile
var lcid_mohCA = 0x047c; // Mohawk, Canada
var lcid_brFR = 0x047e; // Breton, France
var lcid_ugCN = 0x0480; // Uighur, China
var lcid_miNZ = 0x0481; // Maori, New Zealand
var lcid_ocFR = 0x0482; // Occitan (post 1500), France
var lcid_coFR = 0x0483; // Corsican, France
var lcid_gswFR = 0x0484; // Swiss German, France
var lcid_sahRU = 0x0485; // Yakut, Russian Federation
var lcid_qutGT = 0x0486; // Guatemala
var lcid_rwRW = 0x0487; // Kinyarwanda, Rwanda
var lcid_woSN = 0x0488; // Wolof, Senegal
var lcid_prsAF = 0x048c; // Dari, Afghanistan
var lcid_pltMG = 0x048d; // Plateau Malagasy, Madagascar
var lcid_gdGB = 0x0491; // Scottish Gaelic, United Kingdom
var lcid_arIQ = 0x0801; // Arabic, Iraq
var lcid_zhCN = 0x0804; // Chinese, China
var lcid_deCH = 0x0807; // German, Switzerland
var lcid_enGB = 0x0809; // English, United Kingdom
var lcid_esMX = 0x080a; // Spanish, Mexico
var lcid_frBE = 0x080c; // French, Belgium
var lcid_itCH = 0x0810; // Italian, Switzerland
var lcid_nlBE = 0x0813; // Dutch, Belgium
var lcid_nnNO = 0x0814; // Norwegian Nynorsk, Norway
var lcid_ptPT = 0x0816; // Portuguese, Portugal
var lcid_roMO = 0x0818; // Romanian, Macao
var lcid_ruMO = 0x0819; // Russian, Macao
var lcid_srLatnCS = 0x081a; // Serbian, Latin, Serbia and Montenegro
var lcid_svFI = 0x081d; // Swedish, Finland
var lcid_urIN = 0x0820; // Urdu, India
var lcid_azCyrlAZ = 0x082c; // Azerbaijani, Cyrillic, Azerbaijan
var lcid_dsbDE = 0x082e; // Lower Sorbian, Germany
var lcid_seSE = 0x083b; // Northern Sami, Sweden
var lcid_gaIE = 0x083c; // Irish, Ireland
var lcid_msBN = 0x083e; // Malay (macrolanguage), Brunei Darussalam
var lcid_uzCyrlUZ = 0x0843; // Uzbek, Cyrillic, Uzbekistan
var lcid_bnBD = 0x0845; // Bengali, Bangladesh
var lcid_paPK = 0x0846; // Panjabi, Pakistan
var lcid_mnMongCN = 0x0850; // Mongolian, Mongolian, China
var lcid_boBT = 0x0851; // Tibetan, Bhutan
var lcid_sdPK = 0x0859; // Sindhi, Pakistan
var lcid_iuLatnCA = 0x085d; // Inuktitut, Latin, Canada
var lcid_tzmLatnDZ = 0x085f; // Central Atlas Tamazight, Latin, Algeria
var lcid_neIN = 0x0861; // Nepali, India
var lcid_quzEC = 0x086b; // Cusco Quechua, Ecuador
var lcid_tiET = 0x0873; // Tigrinya, Ethiopia
var lcid_arEG = 0x0c01; // Arabic, Egypt
var lcid_zhHK = 0x0c04; // Chinese, Hong Kong
var lcid_deAT = 0x0c07; // German, Austria
var lcid_enAU = 0x0c09; // English, Australia
var lcid_esES = 0x0c0a; // Spanish, Spain
var lcid_frCA = 0x0c0c; // French, Canada
var lcid_srCyrlCS = 0x0c1a; // Serbian, Cyrillic, Serbia and Montenegro
var lcid_seFI = 0x0c3b; // Northern Sami, Finland
var lcid_tmzMA = 0x0c5f; // Tamanaku, Morocco
var lcid_quzPE = 0x0c6b; // Cusco Quechua, Peru
var lcid_arLY = 0x1001; // Arabic, Libyan Arab Jamahiriya
var lcid_zhSG = 0x1004; // Chinese, Singapore
var lcid_deLU = 0x1007; // German, Luxembourg
var lcid_enCA = 0x1009; // English, Canada
var lcid_esGT = 0x100a; // Spanish, Guatemala
var lcid_frCH = 0x100c; // French, Switzerland
var lcid_hrBA = 0x101a; // Croatian, Bosnia and Herzegovina
var lcid_smjNO = 0x103b; // Lule Sami, Norway
var lcid_arDZ = 0x1401; // Arabic, Algeria
var lcid_zhMO = 0x1404; // Chinese, Macao
var lcid_deLI = 0x1407; // German, Liechtenstein
var lcid_enNZ = 0x1409; // English, New Zealand
var lcid_esCR = 0x140a; // Spanish, Costa Rica
var lcid_frLU = 0x140c; // French, Luxembourg
var lcid_bsLatnBA = 0x141a; // Bosnian, Latin, Bosnia and Herzegovina
var lcid_smjSE = 0x143b; // Lule Sami, Sweden
var lcid_arMA = 0x1801; // Arabic, Morocco
var lcid_enIE = 0x1809; // English, Ireland
var lcid_esPA = 0x180a; // Spanish, Panama
var lcid_frMC = 0x180c; // French, Monaco
var lcid_srLatnBA = 0x181a; // Serbian, Latin, Bosnia and Herzegovina
var lcid_smaNO = 0x183b; // Southern Sami, Norway
var lcid_arTN = 0x1c01; // Arabic, Tunisia
var lcid_enZA = 0x1c09; // English, South Africa
var lcid_esDO = 0x1c0a; // Spanish, Dominican Republic
var lcid_frWest = 0x1c0c; // French
var lcid_srCyrlBA = 0x1c1a; // Serbian, Cyrillic, Bosnia and Herzegovina
var lcid_smaSE = 0x1c3b; // Southern Sami, Sweden
var lcid_arOM = 0x2001; // Arabic, Oman
var lcid_enJM = 0x2009; // English, Jamaica
var lcid_esVE = 0x200a; // Spanish, Venezuela
var lcid_frRE = 0x200c; // French, Reunion
var lcid_bsCyrlBA = 0x201a; // Bosnian, Cyrillic, Bosnia and Herzegovina
var lcid_smsFI = 0x203b; // Skolt Sami, Finland
var lcid_arYE = 0x2401; // Arabic, Yemen
var lcid_enCB = 0x2409; // English
var lcid_esCO = 0x240a; // Spanish, Colombia
var lcid_frCG = 0x240c; // French, Congo
var lcid_srLatnRS = 0x241a; // Serbian, Latin, Serbia
var lcid_smnFI = 0x243b; // Inari Sami, Finland
var lcid_arSY = 0x2801; // Arabic, Syrian Arab Republic
var lcid_enBZ = 0x2809; // English, Belize
var lcid_esPE = 0x280a; // Spanish, Peru
var lcid_frSN = 0x280c; // French, Senegal
var lcid_srCyrlRS = 0x281a; // Serbian, Cyrillic, Serbia
var lcid_arJO = 0x2c01; // Arabic, Jordan
var lcid_enTT = 0x2c09; // English, Trinidad and Tobago
var lcid_esAR = 0x2c0a; // Spanish, Argentina
var lcid_frCM = 0x2c0c; // French, Cameroon
var lcid_srLatnME = 0x2c1a; // Serbian, Latin, Montenegro
var lcid_arLB = 0x3001; // Arabic, Lebanon
var lcid_enZW = 0x3009; // English, Zimbabwe
var lcid_esEC = 0x300a; // Spanish, Ecuador
var lcid_frCI = 0x300c; // French, Cote d'Ivoire
var lcid_srCyrlME = 0x301a; // Serbian, Cyrillic, Montenegro
var lcid_arKW = 0x3401; // Arabic, Kuwait
var lcid_enPH = 0x3409; // English, Philippines
var lcid_esCL = 0x340a; // Spanish, Chile
var lcid_frML = 0x340c; // French, Mali
var lcid_arAE = 0x3801; // Arabic, United Arab Emirates
var lcid_enID = 0x3809; // English, Indonesia
var lcid_esUY = 0x380a; // Spanish, Uruguay
var lcid_frMA = 0x380c; // French, Morocco
var lcid_arBH = 0x3c01; // Arabic, Bahrain
var lcid_enHK = 0x3c09; // English, Hong Kong
var lcid_esPY = 0x3c0a; // Spanish, Paraguay
var lcid_frHT = 0x3c0c; // French, Haiti
var lcid_arQA = 0x4001; // Arabic, Qatar
var lcid_enIN = 0x4009; // English, India
var lcid_esBO = 0x400a; // Spanish, Bolivia
var lcid_enMY = 0x4409; // English, Malaysia
var lcid_esSV = 0x440a; // Spanish, El Salvador
var lcid_enSG = 0x4809; // English, Singapore
var lcid_esHN = 0x480a; // Spanish, Honduras
var lcid_esNI = 0x4c0a; // Spanish, Nicaragua
var lcid_esPR = 0x500a; // Spanish, Puerto Rico
var lcid_esUS = 0x540a; // Spanish, United States
var lcid_bsCyrl = 0x641a; // Bosnian, Cyrillic
var lcid_bsLatn = 0x681a; // Bosnian, Latin
var lcid_srCyrl = 0x6c1a; // Serbian, Cyrillic
var lcid_srLatn = 0x701a; // Serbian, Latin
var lcid_smn = 0x703b; // Inari Sami
var lcid_azCyrl = 0x742c; // Azerbaijani, Cyrillic
var lcid_sms = 0x743b; // Skolt Sami
var lcid_zh = 0x7804; // Chinese
var lcid_nn = 0x7814; // Norwegian Nynorsk
var lcid_bs = 0x781a; // Bosnian
var lcid_azLatn = 0x782c; // Azerbaijani, Latin
var lcid_sma = 0x783b; // Southern Sami
var lcid_uzCyrl = 0x7843; // Uzbek, Cyrillic
var lcid_mnCyrl = 0x7850; // Mongolian, Cyrillic
var lcid_iuCans = 0x785d; // Inuktitut, Unified Canadian Aboriginal Syllabics
var lcid_zhHant = 0x7c04; // Chinese, Han (Traditional variant)
var lcid_nb = 0x7c14; // Norwegian Bokmal
var lcid_sr = 0x7c1a; // Serbian
var lcid_tgCyrl = 0x7c28; // Tajik, Cyrillic
var lcid_dsb = 0x7c2e; // Lower Sorbian
var lcid_smj = 0x7c3b; // Lule Sami
var lcid_uzLatn = 0x7c43; // Uzbek, Latin
var lcid_mnMong = 0x7c50; // Mongolian, Mongolian
var lcid_iuLatn = 0x7c5d; // Inuktitut, Latin
var lcid_tzmLatn = 0x7c5f; // Central Atlas Tamazight, Latin
var lcid_haLatn = 0x7c68; // Hausa, Latin

var g_aLcidNameIdArray = [
 "ar", 0x0001 ,
 "bg", 0x0002 ,
 "ca", 0x0003 ,
 "zh-Hans", 0x0004 ,
 "cs", 0x0005 ,
 "da", 0x0006 ,
 "de", 0x0007 ,
 "el", 0x0008 ,
 "en", 0x0009 ,
 "es", 0x000a ,
 "fi", 0x000b ,
 "fr", 0x000c ,
 "he", 0x000d ,
 "hu", 0x000e ,
 "is", 0x000f ,
 "it", 0x0010 ,
 "ja", 0x0011 ,
 "ko", 0x0012 ,
 "nl", 0x0013 ,
 "no", 0x0014 ,
 "pl", 0x0015 ,
 "pt", 0x0016 ,
 "rm", 0x0017 ,
 "ro", 0x0018 ,
 "ru", 0x0019 ,
 "hr", 0x001a ,
 "sk", 0x001b ,
 "sq", 0x001c ,
 "sv", 0x001d ,
 "th", 0x001e ,
 "tr", 0x001f ,
 "ur", 0x0020 ,
 "id", 0x0021 ,
 "uk", 0x0022 ,
 "be", 0x0023 ,
 "sl", 0x0024 ,
 "et", 0x0025 ,
 "lv", 0x0026 ,
 "lt", 0x0027 ,
 "tg", 0x0028 ,
 "fa", 0x0029 ,
 "vi", 0x002a ,
 "hy", 0x002b ,
 "az", 0x002c ,
 "eu", 0x002d ,
 "hsb", 0x002e ,
 "mk", 0x002f ,
 "tn", 0x0032 ,
 "xh", 0x0034 ,
 "zu", 0x0035 ,
 "af", 0x0036 ,
 "ka", 0x0037 ,
 "fo", 0x0038 ,
 "hi", 0x0039 ,
 "mt", 0x003a ,
 "se", 0x003b ,
 "ga", 0x003c ,
 "ms", 0x003e ,
 "kk", 0x003f ,
 "ky", 0x0040 ,
 "sw", 0x0041 ,
 "tk", 0x0042 ,
 "uz", 0x0043 ,
 "tt", 0x0044 ,
 "bn", 0x0045 ,
 "pa", 0x0046 ,
 "gu", 0x0047 ,
 "or", 0x0048 ,
 "ta", 0x0049 ,
 "te", 0x004a ,
 "kn", 0x004b ,
 "ml", 0x004c ,
 "as", 0x004d ,
 "mr", 0x004e ,
 "sa", 0x004f ,
 "mn", 0x0050 ,
 "bo", 0x0051 ,
 "cy", 0x0052 ,
 "km", 0x0053 ,
 "lo", 0x0054 ,
 "gl", 0x0056 ,
 "kok", 0x0057 ,
 "syr", 0x005a ,
 "si", 0x005b ,
 "iu", 0x005d ,
 "am", 0x005e ,
 "tzm", 0x005f ,
 "ne", 0x0061 ,
 "fy", 0x0062 ,
 "ps", 0x0063 ,
 "fil", 0x0064 ,
 "dv", 0x0065 ,
 "ha", 0x0068 ,
 "yo", 0x006a ,
 "quz", 0x006b ,
 "nso", 0x006c ,
 "ba", 0x006d ,
 "lb", 0x006e ,
 "kl", 0x006f ,
 "ig", 0x0070 ,
 "ii", 0x0078 ,
 "arn", 0x007a ,
 "moh", 0x007c ,
 "br", 0x007e ,
 "ug", 0x0080 ,
 "mi", 0x0081 ,
 "oc", 0x0082 ,
 "co", 0x0083 ,
 "gsw", 0x0084 ,
 "sah", 0x0085 ,
 "qut", 0x0086 ,
 "rw", 0x0087 ,
 "wo", 0x0088 ,
 "prs", 0x008c ,
 "gd", 0x0091 ,
 "ar-SA", 0x0401 ,
 "bg-BG", 0x0402 ,
 "ca-ES", 0x0403 ,
 "zh-TW", 0x0404 ,
 "cs-CZ", 0x0405 ,
 "da-DK", 0x0406 ,
 "de-DE", 0x0407 ,
 "el-GR", 0x0408 ,
 "en-US", 0x0409 ,
 "es-ES_tradnl", 0x040a ,
 "fi-FI", 0x040b ,
 "fr-FR", 0x040c ,
 "he-IL", 0x040d ,
 "hu-HU", 0x040e ,
 "is-IS", 0x040f ,
 "it-IT", 0x0410 ,
 "ja-JP", 0x0411 ,
 "ko-KR", 0x0412 ,
 "nl-NL", 0x0413 ,
 "nb-NO", 0x0414 ,
 "pl-PL", 0x0415 ,
 "pt-BR", 0x0416 ,
 "rm-CH", 0x0417 ,
 "ro-RO", 0x0418 ,
 "ru-RU", 0x0419 ,
 "hr-HR", 0x041a ,
 "sk-SK", 0x041b ,
 "sq-AL", 0x041c ,
 "sv-SE", 0x041d ,
 "th-TH", 0x041e ,
 "tr-TR", 0x041f ,
 "ur-PK", 0x0420 ,
 "id-ID", 0x0421 ,
 "uk-UA", 0x0422 ,
 "be-BY", 0x0423 ,
 "sl-SI", 0x0424 ,
 "et-EE", 0x0425 ,
 "lv-LV", 0x0426 ,
 "lt-LT", 0x0427 ,
 "tg-Cyrl-TJ", 0x0428 ,
 "fa-IR", 0x0429 ,
 "vi-VN", 0x042a ,
 "hy-AM", 0x042b ,
 "az-Latn-AZ", 0x042c ,
 "eu-ES", 0x042d ,
 "wen-DE", 0x042e ,
 "mk-MK", 0x042f ,
 "st-ZA", 0x0430 ,
 "ts-ZA", 0x0431 ,
 "tn-ZA", 0x0432 ,
 "ven-ZA", 0x0433 ,
 "xh-ZA", 0x0434 ,
 "zu-ZA", 0x0435 ,
 "af-ZA", 0x0436 ,
 "ka-GE", 0x0437 ,
 "fo-FO", 0x0438 ,
 "hi-IN", 0x0439 ,
 "mt-MT", 0x043a ,
 "se-NO", 0x043b ,
 "ms-MY", 0x043e ,
 "kk-KZ", 0x043f ,
 "ky-KG", 0x0440 ,
 "sw-KE", 0x0441 ,
 "tk-TM", 0x0442 ,
 "uz-Latn-UZ", 0x0443 ,
 "tt-RU", 0x0444 ,
 "bn-IN", 0x0445 ,
 "pa-IN", 0x0446 ,
 "gu-IN", 0x0447 ,
 "or-IN", 0x0448 ,
 "ta-IN", 0x0449 ,
 "te-IN", 0x044a ,
 "kn-IN", 0x044b ,
 "ml-IN", 0x044c ,
 "as-IN", 0x044d ,
 "mr-IN", 0x044e ,
 "sa-IN", 0x044f ,
 "mn-MN", 0x0450 ,
 "bo-CN", 0x0451 ,
 "cy-GB", 0x0452 ,
 "km-KH", 0x0453 ,
 "lo-LA", 0x0454 ,
 "my-MM", 0x0455 ,
 "gl-ES", 0x0456 ,
 "kok-IN", 0x0457 ,
 "mni", 0x0458 ,
 "sd-IN", 0x0459 ,
 "syr-SY", 0x045a ,
 "si-LK", 0x045b ,
 "chr-US", 0x045c ,
 "iu-Cans-CA", 0x045d ,
 "am-ET", 0x045e ,
 "tmz", 0x045f ,
 "ne-NP", 0x0461 ,
 "fy-NL", 0x0462 ,
 "ps-AF", 0x0463 ,
 "fil-PH", 0x0464 ,
 "dv-MV", 0x0465 ,
 "bin-NG", 0x0466 ,
 "fuv-NG", 0x0467 ,
 "ha-Latn-NG", 0x0468 ,
 "ibb-NG", 0x0469 ,
 "yo-NG", 0x046a ,
 "quz-BO", 0x046b ,
 "nso-ZA", 0x046c ,
 "ba-RU", 0x046d ,
 "lb-LU", 0x046e ,
 "kl-GL", 0x046f ,
 "ig-NG", 0x0470 ,
 "kr-NG", 0x0471 ,
 "gaz-ET", 0x0472 ,
 "ti-ER", 0x0473 ,
 "gn-PY", 0x0474 ,
 "haw-US", 0x0475 ,
 "so-SO", 0x0477 ,
 "ii-CN", 0x0478 ,
 "pap-AN", 0x0479 ,
 "arn-CL", 0x047a ,
 "moh-CA", 0x047c ,
 "br-FR", 0x047e ,
 "ug-CN", 0x0480 ,
 "mi-NZ", 0x0481 ,
 "oc-FR", 0x0482 ,
 "co-FR", 0x0483 ,
 "gsw-FR", 0x0484 ,
 "sah-RU", 0x0485 ,
 "qut-GT", 0x0486 ,
 "rw-RW", 0x0487 ,
 "wo-SN", 0x0488 ,
 "prs-AF", 0x048c ,
 "plt-MG", 0x048d ,
 "gd-GB", 0x0491 ,
 "ar-IQ", 0x0801 ,
 "zh-CN", 0x0804 ,
 "de-CH", 0x0807 ,
 "en-GB", 0x0809 ,
 "es-MX", 0x080a ,
 "fr-BE", 0x080c ,
 "it-CH", 0x0810 ,
 "nl-BE", 0x0813 ,
 "nn-NO", 0x0814 ,
 "pt-PT", 0x0816 ,
 "ro-MO", 0x0818 ,
 "ru-MO", 0x0819 ,
 "sr-Latn-CS", 0x081a ,
 "sv-FI", 0x081d ,
 "ur-IN", 0x0820 ,
 "az-Cyrl-AZ", 0x082c ,
 "dsb-DE", 0x082e ,
 "se-SE", 0x083b ,
 "ga-IE", 0x083c ,
 "ms-BN", 0x083e ,
 "uz-Cyrl-UZ", 0x0843 ,
 "bn-BD", 0x0845 ,
 "pa-PK", 0x0846 ,
 "mn-Mong-CN", 0x0850 ,
 "bo-BT", 0x0851 ,
 "sd-PK", 0x0859 ,
 "iu-Latn-CA", 0x085d ,
 "tzm-Latn-DZ", 0x085f ,
 "ne-IN", 0x0861 ,
 "quz-EC", 0x086b ,
 "ti-ET", 0x0873 ,
 "ar-EG", 0x0c01 ,
 "zh-HK", 0x0c04 ,
 "de-AT", 0x0c07 ,
 "en-AU", 0x0c09 ,
 "es-ES", 0x0c0a ,
 "fr-CA", 0x0c0c ,
 "sr-Cyrl-CS", 0x0c1a ,
 "se-FI", 0x0c3b ,
 "tmz-MA", 0x0c5f ,
 "quz-PE", 0x0c6b ,
 "ar-LY", 0x1001 ,
 "zh-SG", 0x1004 ,
 "de-LU", 0x1007 ,
 "en-CA", 0x1009 ,
 "es-GT", 0x100a ,
 "fr-CH", 0x100c ,
 "hr-BA", 0x101a ,
 "smj-NO", 0x103b ,
 "ar-DZ", 0x1401 ,
 "zh-MO", 0x1404 ,
 "de-LI", 0x1407 ,
 "en-NZ", 0x1409 ,
 "es-CR", 0x140a ,
 "fr-LU", 0x140c ,
 "bs-Latn-BA", 0x141a ,
 "smj-SE", 0x143b ,
 "ar-MA", 0x1801 ,
 "en-IE", 0x1809 ,
 "es-PA", 0x180a ,
 "fr-MC", 0x180c ,
 "sr-Latn-BA", 0x181a ,
 "sma-NO", 0x183b ,
 "ar-TN", 0x1c01 ,
 "en-ZA", 0x1c09 ,
 "es-DO", 0x1c0a ,
 "fr-West", 0x1c0c ,
 "sr-Cyrl-BA", 0x1c1a ,
 "sma-SE", 0x1c3b ,
 "ar-OM", 0x2001 ,
 "en-JM", 0x2009 ,
 "es-VE", 0x200a ,
 "fr-RE", 0x200c ,
 "bs-Cyrl-BA", 0x201a ,
 "sms-FI", 0x203b ,
 "ar-YE", 0x2401 ,
 "en-CB", 0x2409 ,
 "es-CO", 0x240a ,
 "fr-CG", 0x240c ,
 "sr-Latn-RS", 0x241a ,
 "smn-FI", 0x243b ,
 "ar-SY", 0x2801 ,
 "en-BZ", 0x2809 ,
 "es-PE", 0x280a ,
 "fr-SN", 0x280c ,
 "sr-Cyrl-RS", 0x281a ,
 "ar-JO", 0x2c01 ,
 "en-TT", 0x2c09 ,
 "es-AR", 0x2c0a ,
 "fr-CM", 0x2c0c ,
 "sr-Latn-ME", 0x2c1a ,
 "ar-LB", 0x3001 ,
 "en-ZW", 0x3009 ,
 "es-EC", 0x300a ,
 "fr-CI", 0x300c ,
 "sr-Cyrl-ME", 0x301a ,
 "ar-KW", 0x3401 ,
 "en-PH", 0x3409 ,
 "es-CL", 0x340a ,
 "fr-ML", 0x340c ,
 "ar-AE", 0x3801 ,
 "en-ID", 0x3809 ,
 "es-UY", 0x380a ,
 "fr-MA", 0x380c ,
 "ar-BH", 0x3c01 ,
 "en-HK", 0x3c09 ,
 "es-PY", 0x3c0a ,
 "fr-HT", 0x3c0c ,
 "ar-QA", 0x4001 ,
 "en-IN", 0x4009 ,
 "es-BO", 0x400a ,
 "en-MY", 0x4409 ,
 "es-SV", 0x440a ,
 "en-SG", 0x4809 ,
 "es-HN", 0x480a ,
 "es-NI", 0x4c0a ,
 "es-PR", 0x500a ,
 "es-US", 0x540a ,
 "bs-Cyrl", 0x641a ,
 "bs-Latn", 0x681a ,
 "sr-Cyrl", 0x6c1a ,
 "sr-Latn", 0x701a ,
 "smn", 0x703b ,
 "az-Cyrl", 0x742c ,
 "sms", 0x743b ,
 "zh", 0x7804 ,
 "nn", 0x7814 ,
 "bs", 0x781a ,
 "az-Latn", 0x782c ,
 "sma", 0x783b ,
 "uz-Cyrl", 0x7843 ,
 "mn-Cyrl", 0x7850 ,
 "iu-Cans", 0x785d ,
 "zh-Hant", 0x7c04 ,
 "nb", 0x7c14 ,
 "sr", 0x7c1a ,
 "tg-Cyrl", 0x7c28 ,
 "dsb", 0x7c2e ,
 "smj", 0x7c3b ,
 "uz-Latn", 0x7c43 ,
 "mn-Mong", 0x7c50 ,
 "iu-Latn", 0x7c5d ,
 "tzm-Latn", 0x7c5f ,
 "ha-Latn", 0x7c68 ];
var g_oLcidNameToIdMap = {};
var g_oLcidIdToNameMap = {};

(function(document){
	for(var i = 0, length = g_aLcidNameIdArray.length; i + 1< length; i+=2)
	{
		var name = g_aLcidNameIdArray[i];
		var id = g_aLcidNameIdArray[i + 1];
		g_oLcidNameToIdMap[name] = id;
		g_oLcidIdToNameMap[id] = name;
	}
    function CDetectFontUse()
    {
        this.DetectData     = null;

        this.TableChunkLen  = 65536;
        this.TableChunks    = 4;

        this.TableChunkMain     = 0;
        this.TableChunkHintEA   = this.TableChunkLen;
        this.TableChunkHintZH   = 2 * this.TableChunkLen;
        this.TableChunkHintEACS = 3 * this.TableChunkLen;

        this.Init = function()
        {
            this.DetectData = g_memory.Alloc(this.TableChunkLen * this.TableChunks);
            var _data = this.DetectData.data;
            var i, j;

            // ********************** 1st table *********************** //
            j = 0;
            for (i = 0x0000; i <= 0x007F; i++)
            {
                _data[i + j] = fontslot_ASCII;
            }
            for (i = 0x00A0; i <= 0x04FF; i++)
            {
                _data[i + j] = fontslot_HAnsi;
            }
            for (i = 0x0590; i <= 0x07BF; i++)
            {
                _data[i + j] = fontslot_ASCII;
            }
            for (i = 0x1100; i <= 0x11FF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x1E00; i <= 0x1EFF; i++)
            {
                _data[i + j] = fontslot_HAnsi;
            }
            for (i = 0x1F00; i <= 0x27BF; i++)
            {
                _data[i + j] = fontslot_HAnsi;
            }
            for (i = 0x2E80; i <= 0x319F; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x3200; i <= 0x4D8F; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x4E00; i <= 0x9FAF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xA000; i <= 0xA4CF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xAC00; i <= 0xD7AF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xD800; i <= 0xDFFF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xE000; i <= 0xF8FF; i++)
            {
                _data[i + j] = fontslot_HAnsi;
            }
            for (i = 0xF900; i <= 0xFAFF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xFB00; i <= 0xFB1C; i++)
            {
                _data[i + j] = fontslot_HAnsi;
            }
            for (i = 0xFB1D; i <= 0xFDFF; i++)
            {
                _data[i + j] = fontslot_ASCII;
            }
            for (i = 0xFE30; i <= 0xFE6F; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xFE70; i <= 0xFEFE; i++)
            {
                _data[i + j] = fontslot_ASCII;
            }
            for (i = 0xFF00; i <= 0xFFEF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }

            // ********************** 2nd table *********************** //
            j = this.TableChunkHintEA;
            for (i = 0x0000; i <= 0x007F; i++)
            {
                _data[i + j] = fontslot_ASCII;
            }
            for (i = 0x00A0; i <= 0x04FF; i++)
            {
                _data[i + j] = fontslot_HAnsi;
            }
            _data[0xA1 + j] = fontslot_EastAsia;
            _data[0xA4 + j] = fontslot_EastAsia;
            _data[0xA7 + j] = fontslot_EastAsia;
            _data[0xA8 + j] = fontslot_EastAsia;
            _data[0xAA + j] = fontslot_EastAsia;
            _data[0xAD + j] = fontslot_EastAsia;
            _data[0xAF + j] = fontslot_EastAsia;
            _data[0xB0 + j] = fontslot_EastAsia;
            _data[0xB1 + j] = fontslot_EastAsia;
            _data[0xB2 + j] = fontslot_EastAsia;
            _data[0xB3 + j] = fontslot_EastAsia;
            _data[0xB4 + j] = fontslot_EastAsia;
            _data[0xB6 + j] = fontslot_EastAsia;
            _data[0xB7 + j] = fontslot_EastAsia;
            _data[0xB8 + j] = fontslot_EastAsia;
            _data[0xB9 + j] = fontslot_EastAsia;
            _data[0xBA + j] = fontslot_EastAsia;
            _data[0xBC + j] = fontslot_EastAsia;
            _data[0xBD + j] = fontslot_EastAsia;
            _data[0xBE + j] = fontslot_EastAsia;
            _data[0xBF + j] = fontslot_EastAsia;
            _data[0xD7 + j] = fontslot_EastAsia;
            _data[0xF7 + j] = fontslot_EastAsia;

            for (i = 0x02B0; i <= 0x04FF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x0590; i <= 0x07BF; i++)
            {
                _data[i + j] = fontslot_ASCII;
            }
            for (i = 0x1100; i <= 0x11FF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x1E00; i <= 0x1EFF; i++)
            {
                _data[i + j] = fontslot_HAnsi;
            }
            for (i = 0x1F00; i <= 0x1FFF; i++)
            {
                _data[i + j] = fontslot_HAnsi;
            }
            for (i = 0x2000; i <= 0x27BF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x2E80; i <= 0x319F; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x3200; i <= 0x4D8F; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x4E00; i <= 0x9FAF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xA000; i <= 0xA4CF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xAC00; i <= 0xD7AF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xD800; i <= 0xDFFF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xE000; i <= 0xF8FF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xF900; i <= 0xFAFF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xFB00; i <= 0xFB1C; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xFB1D; i <= 0xFDFF; i++)
            {
                _data[i + j] = fontslot_ASCII;
            }
            for (i = 0xFE30; i <= 0xFE6F; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xFE70; i <= 0xFEFE; i++)
            {
                _data[i + j] = fontslot_ASCII;
            }
            for (i = 0xFF00; i <= 0xFFEF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }

            // ********************** 3rd table *********************** //
            j = this.TableChunkHintZH;
            for (i = 0x0000; i <= 0x007F; i++)
            {
                _data[i + j] = fontslot_ASCII;
            }
            for (i = 0x00A0; i <= 0x00FF; i++)
            {
                _data[i + j] = fontslot_HAnsi;
            }
            _data[0xA1 + j] = fontslot_EastAsia;
            _data[0xA4 + j] = fontslot_EastAsia;
            _data[0xA7 + j] = fontslot_EastAsia;
            _data[0xA8 + j] = fontslot_EastAsia;
            _data[0xAA + j] = fontslot_EastAsia;
            _data[0xAD + j] = fontslot_EastAsia;
            _data[0xAF + j] = fontslot_EastAsia;
            _data[0xB0 + j] = fontslot_EastAsia;
            _data[0xB1 + j] = fontslot_EastAsia;
            _data[0xB2 + j] = fontslot_EastAsia;
            _data[0xB3 + j] = fontslot_EastAsia;
            _data[0xB4 + j] = fontslot_EastAsia;
            _data[0xB6 + j] = fontslot_EastAsia;
            _data[0xB7 + j] = fontslot_EastAsia;
            _data[0xB8 + j] = fontslot_EastAsia;
            _data[0xB9 + j] = fontslot_EastAsia;
            _data[0xBA + j] = fontslot_EastAsia;
            _data[0xBC + j] = fontslot_EastAsia;
            _data[0xBD + j] = fontslot_EastAsia;
            _data[0xBE + j] = fontslot_EastAsia;
            _data[0xBF + j] = fontslot_EastAsia;
            _data[0xD7 + j] = fontslot_EastAsia;
            _data[0xF7 + j] = fontslot_EastAsia;

            _data[0xE0 + j] = fontslot_EastAsia;
            _data[0xE1 + j] = fontslot_EastAsia;
            _data[0xE8 + j] = fontslot_EastAsia;
            _data[0xE9 + j] = fontslot_EastAsia;
            _data[0xEA + j] = fontslot_EastAsia;
            _data[0xEC + j] = fontslot_EastAsia;
            _data[0xED + j] = fontslot_EastAsia;
            _data[0xF2 + j] = fontslot_EastAsia;
            _data[0xF3 + j] = fontslot_EastAsia;
            _data[0xF9 + j] = fontslot_EastAsia;
            _data[0xFA + j] = fontslot_EastAsia;
            _data[0xFC + j] = fontslot_EastAsia;

            for (i = 0x0100; i <= 0x02AF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x02B0; i <= 0x04FF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x0590; i <= 0x07BF; i++)
            {
                _data[i + j] = fontslot_ASCII;
            }
            for (i = 0x1100; i <= 0x11FF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x1E00; i <= 0x1EFF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x1F00; i <= 0x1FFF; i++)
            {
                _data[i + j] = fontslot_HAnsi;
            }
            for (i = 0x2000; i <= 0x27BF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x2E80; i <= 0x319F; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x3200; i <= 0x4D8F; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x4E00; i <= 0x9FAF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xA000; i <= 0xA4CF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xAC00; i <= 0xD7AF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xD800; i <= 0xDFFF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xE000; i <= 0xF8FF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xF900; i <= 0xFAFF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xFB00; i <= 0xFB1C; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xFB1D; i <= 0xFDFF; i++)
            {
                _data[i + j] = fontslot_ASCII;
            }
            for (i = 0xFE30; i <= 0xFE6F; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xFE70; i <= 0xFEFE; i++)
            {
                _data[i + j] = fontslot_ASCII;
            }
            for (i = 0xFF00; i <= 0xFFEF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }

            // ********************** 4rd table *********************** //
            j = this.TableChunkHintEACS;
            for (i = 0x0000; i <= 0x007F; i++)
            {
                _data[i + j] = fontslot_ASCII;
            }
            for (i = 0x00A0; i <= 0x00FF; i++)
            {
                _data[i + j] = fontslot_HAnsi;
            }
            _data[0xA1 + j] = fontslot_EastAsia;
            _data[0xA4 + j] = fontslot_EastAsia;
            _data[0xA7 + j] = fontslot_EastAsia;
            _data[0xA8 + j] = fontslot_EastAsia;
            _data[0xAA + j] = fontslot_EastAsia;
            _data[0xAD + j] = fontslot_EastAsia;
            _data[0xAF + j] = fontslot_EastAsia;
            _data[0xB0 + j] = fontslot_EastAsia;
            _data[0xB1 + j] = fontslot_EastAsia;
            _data[0xB2 + j] = fontslot_EastAsia;
            _data[0xB3 + j] = fontslot_EastAsia;
            _data[0xB4 + j] = fontslot_EastAsia;
            _data[0xB6 + j] = fontslot_EastAsia;
            _data[0xB7 + j] = fontslot_EastAsia;
            _data[0xB8 + j] = fontslot_EastAsia;
            _data[0xB9 + j] = fontslot_EastAsia;
            _data[0xBA + j] = fontslot_EastAsia;
            _data[0xBC + j] = fontslot_EastAsia;
            _data[0xBD + j] = fontslot_EastAsia;
            _data[0xBE + j] = fontslot_EastAsia;
            _data[0xBF + j] = fontslot_EastAsia;
            _data[0xD7 + j] = fontslot_EastAsia;
            _data[0xF7 + j] = fontslot_EastAsia;

            for (i = 0x0100; i <= 0x02AF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x02B0; i <= 0x04FF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x0590; i <= 0x07BF; i++)
            {
                _data[i + j] = fontslot_ASCII;
            }
            for (i = 0x1100; i <= 0x11FF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x1E00; i <= 0x1EFF; i++)
            {
                _data[i + j] = fontslot_HAnsi;
            }
            for (i = 0x1F00; i <= 0x1FFF; i++)
            {
                _data[i + j] = fontslot_HAnsi;
            }
            for (i = 0x2000; i <= 0x27BF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x2E80; i <= 0x319F; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x3200; i <= 0x4D8F; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0x4E00; i <= 0x9FAF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xA000; i <= 0xA4CF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xAC00; i <= 0xD7AF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xD800; i <= 0xDFFF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xE000; i <= 0xF8FF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xF900; i <= 0xFAFF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xFB00; i <= 0xFB1C; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xFB1D; i <= 0xFDFF; i++)
            {
                _data[i + j] = fontslot_ASCII;
            }
            for (i = 0xFE30; i <= 0xFE6F; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
            for (i = 0xFE70; i <= 0xFEFE; i++)
            {
                _data[i + j] = fontslot_ASCII;
            }
            for (i = 0xFF00; i <= 0xFFEF; i++)
            {
                _data[i + j] = fontslot_EastAsia;
            }
        }

        this.Get_FontClass = function(nUnicode, nHint, nEastAsia_lcid, bCS, bRTL)
        {
            var _glyph_slot = fontslot_ASCII;
			if (nUnicode > 0xFFFF)
			{
				if ((nUnicode >= 0x20000 && nUnicode <= 0x2A6DF) ||
					(nUnicode >= 0x2F800 && nUnicode <= 0x2FA1F))
				{
					_glyph_slot = fontslot_EastAsia;
				}
				else if (nUnicode >= 0x1D400 && nUnicode <= 0x1D7FF)
				{
					_glyph_slot = fontslot_ASCII;
				}
				else
				{
					_glyph_slot = fontslot_HAnsi;
				}
			}			
            else if (nHint != fonthint_EastAsia)
            {
                _glyph_slot = this.DetectData.data[nUnicode];
            }
            else
            {
                if (nEastAsia_lcid == lcid_zh)
                    _glyph_slot = this.DetectData.data[this.TableChunkHintZH + nUnicode];
                else
                    _glyph_slot = this.DetectData.data[this.TableChunkHintEA + nUnicode];

                if (_glyph_slot == fontslot_EastAsia)
                    return _glyph_slot;
            }

            if (bCS || bRTL)
                return fontslot_CS;

            return _glyph_slot;
        }
    }

    window.CDetectFontUse = CDetectFontUse;
	window.CDetectFontUse;
})(window.document);

var g_font_detector = new window.CDetectFontUse();
g_font_detector.Init();
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined)
{

	// Import
	var g_fontApplication = AscFonts.g_fontApplication;

	function CGrRFonts()
	{
		this.Ascii    = {Name : "Empty", Index : -1};
		this.EastAsia = {Name : "Empty", Index : -1};
		this.HAnsi    = {Name : "Empty", Index : -1};
		this.CS       = {Name : "Empty", Index : -1};
	}

	CGrRFonts.prototype =
	{
		checkFromTheme : function(fontScheme, rFonts)
		{
			this.Ascii.Name    = fontScheme.checkFont(rFonts.Ascii.Name);
			this.EastAsia.Name = fontScheme.checkFont(rFonts.EastAsia.Name);
			this.HAnsi.Name    = fontScheme.checkFont(rFonts.HAnsi.Name);
			this.CS.Name       = fontScheme.checkFont(rFonts.CS.Name);

			this.Ascii.Index    = -1;
			this.EastAsia.Index = -1;
			this.HAnsi.Index    = -1;
			this.CS.Index       = -1;
		}
	};

	var gr_state_pen       = 0;
	var gr_state_brush     = 1;
	var gr_state_pen_brush = 2;
	var gr_state_state     = 3;
	var gr_state_all       = 4;

	function CFontSetup()
	{
		this.Name   = "";
		this.Index  = -1;
		this.Size   = 12;
		this.Bold   = false;
		this.Italic = false;

		this.SetUpName  = "";
		this.SetUpIndex = -1;
		this.SetUpSize  = 12;
		this.SetUpStyle = -1;

		this.SetUpMatrix = new CMatrix();
	}

	CFontSetup.prototype =
	{
		Clear : function()
		{
			this.Name   = "";
			this.Index  = -1;
			this.Size   = 12;
			this.Bold   = false;
			this.Italic = false;

			this.SetUpName  = "";
			this.SetUpIndex = -1;
			this.SetUpSize  = 12;
			this.SetUpStyle = -1;

			this.SetUpMatrix = new CMatrix();
		}
	};

	function CGrState_Pen()
	{
		this.Type = gr_state_pen;
		this.Pen  = null;
	}

	CGrState_Pen.prototype =
	{
		Init : function(_pen)
		{
			if (_pen !== undefined)
				this.Pen = _pen.CreateDublicate();
		}
	};

	function CGrState_Brush()
	{
		this.Type  = gr_state_brush;
		this.Brush = null;
	}

	CGrState_Brush.prototype =
	{
		Init : function(_brush)
		{
			if (undefined !== _brush)
				this.Brush = _brush.CreateDublicate();
		}
	};

	function CGrState_PenBrush()
	{
		this.Type  = gr_state_pen_brush;
		this.Pen   = null;
		this.Brush = null;
	}

	CGrState_PenBrush.prototype =
	{
		Init : function(_pen, _brush)
		{
			if (undefined !== _pen && undefined !== _brush)
			{
				this.Pen   = _pen.CreateDublicate();
				this.Brush = _brush.CreateDublicate();
			}
		}
	};

	function CHist_Clip()
	{
		this.Path          = null;   // clipPath
		this.Rect          = null;   // clipRect. clipRect - is a simple clipPath.
		this.IsIntegerGrid = false;
		this.Transform     = new CMatrix();
	}

	CHist_Clip.prototype =
	{
		Init : function(path, rect, isIntegerGrid, transform)
		{
			this.Path = path;

			if (rect !== undefined)
			{
				this.Rect   = new _rect();
				this.Rect.x = rect.x;
				this.Rect.y = rect.y;
				this.Rect.w = rect.w;
				this.Rect.h = rect.h;
			}

			if (undefined !== isIntegerGrid)
				this.IsIntegerGrid = isIntegerGrid;

			if (undefined !== transform)
				this.Transform = transform.CreateDublicate();
		},

		ToRenderer : function(renderer)
		{
			if (this.Rect != null)
			{
				var r = this.Rect;
				renderer.StartClipPath();
				renderer.rect(r.x, r.y, r.w, r.h);
				renderer.EndClipPath();
			}
			else
			{
				// TODO: пока не используется
			}
		}
	};

	function CGrState_State()
	{
		this.Type = gr_state_state;

		this.Transform     = null;
		this.IsIntegerGrid = false;
		this.Clips         = null;
	}

	CGrState_State.prototype =
	{
		Init : function(_transform, _isIntegerGrid, _clips)
		{
			if (undefined !== _transform)
				this.Transform = _transform.CreateDublicate();

			if (undefined !== _isIntegerGrid)
				this.IsIntegerGrid = _isIntegerGrid;

			if (undefined !== _clips)
				this.Clips = _clips;
		},

		ApplyClips : function(renderer)
		{
			var _len = this.Clips.length;
			for (var i = 0; i < _len; i++)
			{
				this.Clips[i].ToRenderer(renderer);
			}
		}
	};

	function CGrState()
	{
		this.Parent = null;
		this.States = [];

		this.Clips = [];
	}

	CGrState.prototype =
	{
		SavePen : function()
		{
			if (null == this.Parent)
				return;

			var _state = new CGrState_Pen();
			_state.Init(this.Parent.m_oPen);
			this.States.push(_state);
		},

		SaveBrush : function()
		{
			if (null == this.Parent)
				return;

			var _state = new CGrState_Brush();
			_state.Init(this.Parent.m_oBrush);
			this.States.push(_state);
		},

		SavePenBrush : function()
		{
			if (null == this.Parent)
				return;

			var _state = new CGrState_PenBrush();
			_state.Init(this.Parent.m_oPen, this.Parent.m_oBrush);
			this.States.push(_state);
		},

		RestorePen : function()
		{
			var _ind = this.States.length - 1;
			if (null == this.Parent || -1 == _ind)
				return;

			var _state = this.States[_ind];
			if (_state.Type == gr_state_pen)
			{
				this.States.splice(_ind, 1);
				var _c = _state.Pen.Color;
				this.Parent.p_color(_c.R, _c.G, _c.B, _c.A);
			}
		},

		RestoreBrush : function()
		{
			var _ind = this.States.length - 1;
			if (null == this.Parent || -1 == _ind)
				return;

			var _state = this.States[_ind];
			if (_state.Type == gr_state_brush)
			{
				this.States.splice(_ind, 1);
				var _c = _state.Brush.Color1;
				this.Parent.b_color1(_c.R, _c.G, _c.B, _c.A);
			}
		},

		RestorePenBrush : function()
		{
			var _ind = this.States.length - 1;
			if (null == this.Parent || -1 == _ind)
				return;

			var _state = this.States[_ind];
			if (_state.Type == gr_state_pen_brush)
			{
				this.States.splice(_ind, 1);
				var _cb = _state.Brush.Color1;
				var _cp = _state.Pen.Color;
				this.Parent.b_color1(_cb.R, _cb.G, _cb.B, _cb.A);
				this.Parent.p_color(_cp.R, _cp.G, _cp.B, _cp.A);
			}
		},

		SaveGrState : function()
		{
			if (null == this.Parent)
				return;

			var _state = new CGrState_State();
			_state.Init(this.Parent.m_oTransform, !!this.Parent.m_bIntegerGrid, this.Clips);
			this.States.push(_state);
			this.Clips = [];
		},

		RestoreGrState : function()
		{
			var _ind = this.States.length - 1;
			if (null == this.Parent || -1 == _ind)
				return;

			var _state = this.States[_ind];
			if (_state.Type == gr_state_state)
			{
				if (this.Clips.length > 0)
				{
					// значит клипы были, и их нужно обновить
					this.Parent.RemoveClip();

					for (var i = 0; i <= _ind; i++)
					{
						var _s = this.States[i];

						if (_s.Type == gr_state_state)
						{
							var _c = _s.Clips;
							var _l = _c.length;

							for (var j = 0; j < _l; j++)
							{
								this.Parent.transform3(_c[j].Transform);
								this.Parent.SetIntegerGrid(_c[j].IsIntegerGrid);

								var _r = _c[j].Rect;
								//this.Parent.AddClipRect(_r.x, _r.y, _r.w, _r.h);

								this.Parent.StartClipPath();

								this.Parent._s();
								this.Parent._m(_r.x, _r.y);
								this.Parent._l(_r.x + _r.w, _r.y);
								this.Parent._l(_r.x + _r.w, _r.y + _r.h);
								this.Parent._l(_r.x, _r.y + _r.h);
								this.Parent._l(_r.x, _r.y);

								this.Parent.EndClipPath();
							}
						}
					}
				}

				this.Clips = _state.Clips;
				this.States.splice(_ind, 1);

				this.Parent.transform3(_state.Transform);
				this.Parent.SetIntegerGrid(_state.IsIntegerGrid);
			}
		},

		Save : function()
		{
			this.SavePen();
			this.SaveBrush();
			this.SaveGrState();
		},

		Restore : function()
		{
			this.RestoreGrState();
			this.RestoreBrush();
			this.RestorePen();
		},

		StartClipPath : function()
		{
			// реализовать, как понадобится
		},

		EndClipPath : function()
		{
			// реализовать, как понадобится
		},

		AddClipRect : function(_r)
		{
			var _histClip           = new CHist_Clip();
			_histClip.Transform     = this.Parent.m_oTransform.CreateDublicate();
			_histClip.IsIntegerGrid = !!this.Parent.m_bIntegerGrid;
			_histClip.Rect          = new _rect();
			_histClip.Rect.x        = _r.x;
			_histClip.Rect.y        = _r.y;
			_histClip.Rect.w        = _r.w;
			_histClip.Rect.h        = _r.h;

			this.Clips.push(_histClip);

			this.Parent.StartClipPath();

			this.Parent._s();
			this.Parent._m(_r.x, _r.y);
			this.Parent._l(_r.x + _r.w, _r.y);
			this.Parent._l(_r.x + _r.w, _r.y + _r.h);
			this.Parent._l(_r.x, _r.y + _r.h);
			this.Parent._l(_r.x, _r.y);

			this.Parent.EndClipPath();

			//this.Parent._e();
		}
	};

	var g_stringBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	var g_arrayBase64  = [];
	for (var index64 = 0; index64 < g_stringBase64.length; index64++)
	{
		g_arrayBase64.push(g_stringBase64.charAt(index64));
	}

	function Base64Encode(srcData, nSrcLen, nOffset)
	{
		if ("undefined" === typeof(nOffset))
			nOffset = 0;

		var nWritten = 0;
		var nLen1    = (((nSrcLen / 3) >> 0) * 4);
		var nLen2    = (nLen1 / 76) >> 0;
		var nLen3    = 19;
		var srcInd   = 0;
		var dstStr   = [];

		var _s = "";
		for (var i = 0; i <= nLen2; i++)
		{
			if (i == nLen2)
				nLen3 = ((nLen1 % 76) / 4) >> 0;

			for (var j = 0; j < nLen3; j++)
			{
				var dwCurr = 0;
				for (var n = 0; n < 3; n++)
				{
					dwCurr |= srcData[srcInd++ + nOffset];
					dwCurr <<= 8;
				}

				_s = "";
				for (var k = 0; k < 4; k++)
				{
					var b = (dwCurr >>> 26) & 0xFF;
					_s += g_arrayBase64[b];
					dwCurr <<= 6;
					dwCurr &= 0xFFFFFFFF;
				}
				dstStr.push(_s);
			}
		}
		nLen2 = (nSrcLen % 3 != 0) ? (nSrcLen % 3 + 1) : 0;
		if (nLen2)
		{
			var dwCurr = 0;
			for (var n = 0; n < 3; n++)
			{
				if (n < (nSrcLen % 3))
					dwCurr |= srcData[srcInd++ + nOffset];
				dwCurr <<= 8;
			}

			_s = "";
			for (var k = 0; k < nLen2; k++)
			{
				var b = (dwCurr >>> 26) & 0xFF;
				_s += g_arrayBase64[b];
				dwCurr <<= 6;
			}

			nLen3 = (nLen2 != 0) ? 4 - nLen2 : 0;
			for (var j = 0; j < nLen3; j++)
			{
				_s += '=';
			}
			dstStr.push(_s);
		}

		return dstStr.join("");
	}

	function CMemory(bIsNoInit)
	{
		this.Init = function()
		{
			var _canvas = document.createElement('canvas');
			var _ctx    = _canvas.getContext('2d');
			this.len    = 1024 * 1024 * 5;
			this.ImData = _ctx.createImageData(this.len / 4, 1);
			this.data   = this.ImData.data;
			this.pos    = 0;
		}

		this.ImData = null;
		this.data   = null;
		this.len    = 0;
		this.pos    = 0;

		if (true !== bIsNoInit)
			this.Init();

		this.Copy = function(oMemory, nPos, nLen)
		{
			for (var Index = 0; Index < nLen; Index++)
			{
				this.CheckSize(1);
				this.data[this.pos++] = oMemory.data[Index + nPos];
			}
		};

		this.CheckSize          = function(count)
		{
			if (this.pos + count >= this.len)
			{
				var _canvas = document.createElement('canvas');
				var _ctx    = _canvas.getContext('2d');

				var oldImData = this.ImData;
				var oldData   = this.data;
				var oldPos    = this.pos;

				this.len = Math.max(this.len * 2, this.pos + ((3 * count / 2) >> 0));

				this.ImData = _ctx.createImageData(this.len / 4, 1);
				this.data   = this.ImData.data;
				var newData = this.data;

				for (var i = 0; i < this.pos; i++)
					newData[i] = oldData[i];
			}
		}
		this.GetBase64Memory    = function()
		{
			return Base64Encode(this.data, this.pos, 0);
		}
		this.GetBase64Memory2   = function(nPos, nLen)
		{
			return Base64Encode(this.data, nLen, nPos);
		}
		this.GetData   = function(nPos, nLen)
		{
			var _canvas = document.createElement('canvas');
			var _ctx    = _canvas.getContext('2d');

			var len = this.GetCurPosition();

			//todo ImData.data.length multiple of 4
			var ImData = _ctx.createImageData(Math.ceil(len / 4), 1);
			var res = ImData.data;

			for (var i = 0; i < len; i++)
				res[i] = this.data[i];
			return res;
		}
		this.GetCurPosition     = function()
		{
			return this.pos;
		}
		this.Seek               = function(nPos)
		{
			this.pos = nPos;
		}
		this.Skip               = function(nDif)
		{
			this.pos += nDif;
		}
		this.WriteBool          = function(val)
		{
			this.CheckSize(1);
			if (false == val)
				this.data[this.pos++] = 0;
			else
				this.data[this.pos++] = 1;
		}
		this.WriteByte          = function(val)
		{
			this.CheckSize(1);
			this.data[this.pos++] = val;
		}
		this.WriteSByte         = function(val)
		{
			this.CheckSize(1);
			if (val < 0)
				val += 256;
			this.data[this.pos++] = val;
		}
		this.WriteLong          = function(val)
		{
			this.CheckSize(4);
			this.data[this.pos++] = (val) & 0xFF;
			this.data[this.pos++] = (val >>> 8) & 0xFF;
			this.data[this.pos++] = (val >>> 16) & 0xFF;
			this.data[this.pos++] = (val >>> 24) & 0xFF;
		}
		this.WriteDouble        = function(val)
		{
			this.CheckSize(4);
			var lval              = ((val * 100000) >> 0) & 0xFFFFFFFF; // спасаем пять знаков после запятой.
			this.data[this.pos++] = (lval) & 0xFF;
			this.data[this.pos++] = (lval >>> 8) & 0xFF;
			this.data[this.pos++] = (lval >>> 16) & 0xFF;
			this.data[this.pos++] = (lval >>> 24) & 0xFF;
		}
		var tempHelp = new ArrayBuffer(8);
		var tempHelpUnit = new Uint8Array(tempHelp);
		var tempHelpFloat = new Float64Array(tempHelp);
		this.WriteDouble2       = function(val)
		{
			this.CheckSize(8);
			tempHelpFloat[0] = val;
			this.data[this.pos++] = tempHelpUnit[0];
			this.data[this.pos++] = tempHelpUnit[1];
			this.data[this.pos++] = tempHelpUnit[2];
			this.data[this.pos++] = tempHelpUnit[3];
			this.data[this.pos++] = tempHelpUnit[4];
			this.data[this.pos++] = tempHelpUnit[5];
			this.data[this.pos++] = tempHelpUnit[6];
			this.data[this.pos++] = tempHelpUnit[7];
		}
		this._doubleEncodeLE754 = function(v)
		{
			//код взят из jspack.js на основе стандарта Little-endian N-bit IEEE 754 floating point
			var s, e, m, i, d, c, mLen, eLen, eBias, eMax;
			var el = {len : 8, mLen : 52, rt : 0};
			mLen = el.mLen, eLen = el.len * 8 - el.mLen - 1, eMax = (1 << eLen) - 1, eBias = eMax >> 1;

			s = v < 0 ? 1 : 0;
			v = Math.abs(v);
			if (isNaN(v) || (v == Infinity))
			{
				m = isNaN(v) ? 1 : 0;
				e = eMax;
			}
			else
			{
				e = Math.floor(Math.log(v) / Math.LN2);            // Calculate log2 of the value
				if (v * (c = Math.pow(2, -e)) < 1)
				{
					e--;
					c *= 2;
				}        // Math.log() isn't 100% reliable

				// Round by adding 1/2 the significand's LSD
				if (e + eBias >= 1)
				{
					v += el.rt / c;
				}            // Normalized:  mLen significand digits
				else
				{
					v += el.rt * Math.pow(2, 1 - eBias);
				}         // Denormalized:  <= mLen significand digits
				if (v * c >= 2)
				{
					e++;
					c /= 2;
				}                // Rounding can increment the exponent

				if (e + eBias >= eMax)
				{
					// Overflow
					m = 0;
					e = eMax;
				}
				else if (e + eBias >= 1)
				{
					// Normalized - term order matters, as Math.pow(2, 52-e) and v*Math.pow(2, 52) can overflow
					m = (v * c - 1) * Math.pow(2, mLen);
					e = e + eBias;
				}
				else
				{
					// Denormalized - also catches the '0' case, somewhat by chance
					m = v * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
					e = 0;
				}
			}
			var a = new Array(8);
			for (i = 0, d = 1; mLen >= 8; a[i] = m & 0xff, i += d, m /= 256, mLen -= 8);
			for (e = (e << mLen) | m, eLen += mLen; eLen > 0; a[i] = e & 0xff, i += d, e /= 256, eLen -= 8);
			a[i - d] |= s * 128;
			return a;
		}
        this.WriteStringBySymbol = function(code)
        {
        	if (code < 0xFFFF)
			{
				this.CheckSize(4);
                this.data[this.pos++] = 1;
                this.data[this.pos++] = 0;
                this.data[this.pos++] = code & 0xFF;
                this.data[this.pos++] = (code >>> 8) & 0xFF;
			}
			else
			{
                this.CheckSize(6);
                this.data[this.pos++] = 2;
                this.data[this.pos++] = 0;

                var codePt = code - 0x10000;
                var c1 = 0xD800 | (codePt >> 10);
                var c2 = 0xDC00 | (codePt & 0x3FF);
                this.data[this.pos++] = c1 & 0xFF;
                this.data[this.pos++] = (c1 >>> 8) & 0xFF;
                this.data[this.pos++] = c2 & 0xFF;
                this.data[this.pos++] = (c2 >>> 8) & 0xFF;
			}
        }
		this.WriteString        = function(text)
		{
			if ("string" != typeof text)
				text = text + "";

			var count = text.length & 0xFFFF;
			this.CheckSize(2 * count + 2);
			this.data[this.pos++] = count & 0xFF;
			this.data[this.pos++] = (count >>> 8) & 0xFF;
			for (var i = 0; i < count; i++)
			{
				var c                 = text.charCodeAt(i) & 0xFFFF;
				this.data[this.pos++] = c & 0xFF;
				this.data[this.pos++] = (c >>> 8) & 0xFF;
			}
		}
		this.WriteString2       = function(text)
		{
			if ("string" != typeof text)
				text = text + "";

			var count      = text.length & 0x7FFFFFFF;
			var countWrite = 2 * count;
			this.WriteLong(countWrite);
			this.CheckSize(countWrite);
			for (var i = 0; i < count; i++)
			{
				var c                 = text.charCodeAt(i) & 0xFFFF;
				this.data[this.pos++] = c & 0xFF;
				this.data[this.pos++] = (c >>> 8) & 0xFF;
			}
		}
		this.WriteString3       = function(text)
		{
			if ("string" != typeof text)
				text = text + "";

			var count      = text.length & 0x7FFFFFFF;
			var countWrite = 2 * count;
			this.CheckSize(countWrite);
			for (var i = 0; i < count; i++)
			{
				var c                 = text.charCodeAt(i) & 0xFFFF;
				this.data[this.pos++] = c & 0xFF;
				this.data[this.pos++] = (c >>> 8) & 0xFF;
			}
		}
		this.ClearNoAttack      = function()
		{
			this.pos = 0;
		}

		this.WriteLongAt = function(_pos, val)
		{
			this.data[_pos++] = (val) & 0xFF;
			this.data[_pos++] = (val >>> 8) & 0xFF;
			this.data[_pos++] = (val >>> 16) & 0xFF;
			this.data[_pos++] = (val >>> 24) & 0xFF;
		}

		this.WriteBuffer = function(data, _pos, count)
		{
			this.CheckSize(count);
			for (var i = 0; i < count; i++)
			{
				this.data[this.pos++] = data[_pos + i];
			}
		}

		this.WriteUtf8Char = function(code)
		{
			this.CheckSize(1);
			if (code < 0x80) {
				this.data[this.pos++] = code;
			}
			else if (code < 0x0800) {
				this.data[this.pos++] = (0xC0 | (code >> 6));
				this.data[this.pos++] = (0x80 | (code & 0x3F));
			}
			else if (code < 0x10000) {
				this.data[this.pos++] = (0xE0 | (code >> 12));
				this.data[this.pos++] = (0x80 | ((code >> 6) & 0x3F));
				this.data[this.pos++] = (0x80 | (code & 0x3F));
			}
			else if (code < 0x1FFFFF) {
				this.data[this.pos++] = (0xF0 | (code >> 18));
				this.data[this.pos++] = (0x80 | ((code >> 12) & 0x3F));
				this.data[this.pos++] = (0x80 | ((code >> 6) & 0x3F));
				this.data[this.pos++] = (0x80 | (code & 0x3F));
			}
			else if (code < 0x3FFFFFF) {
				this.data[this.pos++] = (0xF8 | (code >> 24));
				this.data[this.pos++] = (0x80 | ((code >> 18) & 0x3F));
				this.data[this.pos++] = (0x80 | ((code >> 12) & 0x3F));
				this.data[this.pos++] = (0x80 | ((code >> 6) & 0x3F));
				this.data[this.pos++] = (0x80 | (code & 0x3F));
			}
			else if (code < 0x7FFFFFFF) {
				this.data[this.pos++] = (0xFC | (code >> 30));
				this.data[this.pos++] = (0x80 | ((code >> 24) & 0x3F));
				this.data[this.pos++] = (0x80 | ((code >> 18) & 0x3F));
				this.data[this.pos++] = (0x80 | ((code >> 12) & 0x3F));
				this.data[this.pos++] = (0x80 | ((code >> 6) & 0x3F));
				this.data[this.pos++] = (0x80 | (code & 0x3F));
			}
		};

		this.WriteXmlString = function(val)
		{
			var pCur = 0;
			var pEnd = val.length;
			while (pCur < pEnd)
			{
				var code = val.charCodeAt(pCur++);
				if (code >= 0xD800 && code <= 0xDFFF && pCur < pEnd)
				{
					code = 0x10000 + (((code & 0x3FF) << 10) | (0x03FF & val.charCodeAt(pCur++)));
				}
				this.WriteUtf8Char(code);
			}
		};
		this.WriteXmlStringEncode = function(val)
		{
			var pCur = 0;
			var pEnd = val.length;
			while (pCur < pEnd)
			{
				var code = val.charCodeAt(pCur++);
				if (code >= 0xD800 && code <= 0xDFFF && pCur < pEnd)
				{
					code = 0x10000 + (((code & 0x3FF) << 10) | (0x03FF & val.charCodeAt(pCur++)));
				}
				switch (code)
				{
					case 0x26:
						//&
						this.WriteUtf8Char(0x26);
						this.WriteUtf8Char(0x61);
						this.WriteUtf8Char(0x6d);
						this.WriteUtf8Char(0x70);
						this.WriteUtf8Char(0x3b);
						break;
					case 0x27:
						//'
						this.WriteUtf8Char(0x26);
						this.WriteUtf8Char(0x61);
						this.WriteUtf8Char(0x70);
						this.WriteUtf8Char(0x6f);
						this.WriteUtf8Char(0x73);
						this.WriteUtf8Char(0x3b);
						break;
					case 0x3c:
						//<
						this.WriteUtf8Char(0x26);
						this.WriteUtf8Char(0x6c);
						this.WriteUtf8Char(0x74);
						this.WriteUtf8Char(0x3b);
						break;
					case 0x3e:
						//>
						this.WriteUtf8Char(0x26);
						this.WriteUtf8Char(0x67);
						this.WriteUtf8Char(0x74);
						this.WriteUtf8Char(0x3b);
						break;
					case 0x22:
						//"
						this.WriteUtf8Char(0x26);
						this.WriteUtf8Char(0x71);
						this.WriteUtf8Char(0x75);
						this.WriteUtf8Char(0x6f);
						this.WriteUtf8Char(0x74);
						this.WriteUtf8Char(0x3b);
						break;
					default:
						this.WriteUtf8Char(code);
						break;
				}
			}
		};
		this.WriteXmlBool = function(val)
		{
			this.WriteXmlString(val ? '1' : '0');
		};
		this.WriteXmlNumber = function(val)
		{
			this.WriteXmlString(val.toString());
		};
		this.WriteXmlNodeStart = function(name, isClose)
		{
			this.WriteUtf8Char(0x3c);
			this.WriteXmlString(name);
			if(isClose)
			{
				this.WriteUtf8Char(0x3e);
			}
		};
		this.WriteXmlNodeEnd = function(name, isEmpty, isEnd)
		{
			if (isEmpty)
			{
				if (isEnd)
					this.WriteUtf8Char(0x2f);
				this.WriteUtf8Char(0x3e);
			}
			else
			{
				this.WriteUtf8Char(0x3c);
				this.WriteUtf8Char(0x2f);
				this.WriteXmlString(name);
				this.WriteUtf8Char(0x3e);
			}
		};
		this.WriteXmlAttributesEnd = function(name)
		{
			this.WriteUtf8Char(0x3e);
		};
		this.WriteXmlAttributeString = function(name, val)
		{
			this.WriteUtf8Char(0x20);
			this.WriteXmlString(name);
			this.WriteUtf8Char(0x3d);
			this.WriteUtf8Char(0x22);
			this.WriteXmlString(val);
			this.WriteUtf8Char(0x22);
		};
		this.WriteXmlAttributeStringEncode = function(name, val)
		{
			this.WriteUtf8Char(0x20);
			this.WriteXmlString(name);
			this.WriteUtf8Char(0x3d);
			this.WriteUtf8Char(0x22);
			this.WriteXmlStringEncode(val);
			this.WriteUtf8Char(0x22);
		};
		this.WriteXmlAttributeBool = function(name, val)
		{
			this.WriteXmlAttributeString(name, val ? '1' : '0');
		};
		this.WriteXmlAttributeNumber = function(name, val)
		{
			this.WriteXmlAttributeString(name, val.toString());
		};
	}

	function CCommandsType()
	{
		this.ctPenXML              = 0;
		this.ctPenColor            = 1;
		this.ctPenAlpha            = 2;
		this.ctPenSize             = 3;
		this.ctPenDashStyle        = 4;
		this.ctPenLineStartCap     = 5;
		this.ctPenLineEndCap       = 6;
		this.ctPenLineJoin         = 7;
		this.ctPenDashPatern       = 8;
		this.ctPenDashPatternCount = 9;
		this.ctPenDashOffset       = 10;
		this.ctPenAlign            = 11;
		this.ctPenMiterLimit       = 12;

		// brush
		this.ctBrushXML             = 20;
		this.ctBrushType            = 21;
		this.ctBrushColor1          = 22;
		this.ctBrushColor2          = 23;
		this.ctBrushAlpha1          = 24;
		this.ctBrushAlpha2          = 25;
		this.ctBrushTexturePath     = 26;
		this.ctBrushTextureAlpha    = 27;
		this.ctBrushTextureMode     = 28;
		this.ctBrushRectable        = 29;
		this.ctBrushRectableEnabled = 30;
		this.ctBrushGradient        = 31;

		// font
		this.ctFontXML       = 40;
		this.ctFontName      = 41;
		this.ctFontSize      = 42;
		this.ctFontStyle     = 43;
		this.ctFontPath      = 44;
		this.ctFontGID       = 45;
		this.ctFontCharSpace = 46;

		// shadow
		this.ctShadowXML       = 50;
		this.ctShadowVisible   = 51;
		this.ctShadowDistanceX = 52;
		this.ctShadowDistanceY = 53;
		this.ctShadowBlurSize  = 54;
		this.ctShadowColor     = 55;
		this.ctShadowAlpha     = 56;

		// edge
		this.ctEdgeXML      = 70;
		this.ctEdgeVisible  = 71;
		this.ctEdgeDistance = 72;
		this.ctEdgeColor    = 73;
		this.ctEdgeAlpha    = 74;

		// text
		this.ctDrawText        = 80;
		this.ctDrawTextEx      = 81;
		this.ctDrawTextCode    = 82;
		this.ctDrawTextCodeGid = 83;

		// pathcommands
		this.ctPathCommandMoveTo          = 91;
		this.ctPathCommandLineTo          = 92;
		this.ctPathCommandLinesTo         = 93;
		this.ctPathCommandCurveTo         = 94;
		this.ctPathCommandCurvesTo        = 95;
		this.ctPathCommandArcTo           = 96;
		this.ctPathCommandClose           = 97;
		this.ctPathCommandEnd             = 98;
		this.ctDrawPath                   = 99;
		this.ctPathCommandStart           = 100;
		this.ctPathCommandGetCurrentPoint = 101;
		this.ctPathCommandText            = 102;
		this.ctPathCommandTextEx          = 103;

		// image
		this.ctDrawImage         = 110;
		this.ctDrawImageFromFile = 111;

		this.ctSetParams = 120;

		this.ctBeginCommand = 121;
		this.ctEndCommand   = 122;

		this.ctSetTransform   = 130;
		this.ctResetTransform = 131;

		this.ctClipMode = 140;

		this.ctCommandLong1   = 150;
		this.ctCommandDouble1 = 151;
		this.ctCommandString1 = 152;
		this.ctCommandLong2   = 153;
		this.ctCommandDouble2 = 154;
		this.ctCommandString2 = 155;

		this.ctPageWidth  = 200;
		this.ctPageHeight = 201;

		this.ctPageStart = 202;
		this.ctPageEnd   = 203;

		this.ctError = 255;
	}

	var CommandType = new CCommandsType();

	var MetaBrushType = {
		Solid    : 0,
		Gradient : 1,
		Texture  : 2
	};

	// 0 - dash
	// 1 - dashDot
	// 2 - dot
	// 3 - lgDash
	// 4 - lgDashDot
	// 5 - lgDashDotDot
	// 6 - solid
	// 7 - sysDash
	// 8 - sysDashDot
	// 9 - sysDashDotDot
	// 10- sysDot

	var DashPatternPresets = [
		[4, 3],
		[4, 3, 1, 3],
		[1, 3],
		[8, 3],
		[8, 3, 1, 3],
		[8, 3, 1, 3, 1, 3],
		undefined,
		[3, 1],
		[3, 1, 1, 1],
		[3, 1, 1, 1, 1, 1],
		[1, 1]
	];

	function CMetafileFontPicker(manager)
	{
		this.Manager = manager; 	// в идеале - кэш измерятеля. тогда ни один шрифт не будет загружен заново
		if (!this.Manager)
		{
			this.Manager = new AscFonts.CFontManager();
			this.Manager.Initialize(false)
		}

		this.FontsInCache = {};
		this.LastPickFont = null;
		this.LastPickFontNameOrigin = "";
		this.LastPickFontName = "";
		this.Metafile = null; 												// класс, которому будет подменяться шрифт

		this.SetFont = function(setFont)
		{
			var name = setFont.FontFamily.Name;
			var size = setFont.FontSize;

            var style = 0;
            if (setFont.Italic == true)
                style += 2;
            if (setFont.Bold == true)
                style += 1;

            var name_check = name + "_" + style;
			if (this.FontsInCache[name_check])
			{
				this.LastPickFont = this.FontsInCache[name_check];
			}
			else
			{
				var font = g_fontApplication.GetFontFileWeb(name, style);
                var font_name_index = AscFonts.g_map_font_index[font.m_wsFontName];
                var fontId = AscFonts.g_font_infos[font_name_index].GetFontID(AscCommon.g_font_loader, style);
                var test_id = fontId.id + fontId.faceIndex + size;

                var cache = this.Manager.m_oFontsCache;
                this.LastPickFont = cache.Fonts[test_id];
                if (!this.LastPickFont)
                	this.LastPickFont = cache.Fonts[test_id + "nbold"];
                if (!this.LastPickFont)
                    this.LastPickFont = cache.Fonts[test_id + "nitalic"];
                if (!this.LastPickFont)
                    this.LastPickFont = cache.Fonts[test_id + "nboldnitalic"];

                if (!this.LastPickFont)
				{
					// такого при правильном кэше быть не должно
					this.LastPickFont = cache.LockFont(fontId.file.stream_index, fontId.id, fontId.faceIndex, size, "", this.Manager);
				}

				this.FontsInCache[name_check] = this.LastPickFont;
			}

            this.LastPickFontNameOrigin = name;
			this.LastPickFontName = name;
			this.Metafile.SetFont(setFont, true);
		};

		this.FillTextCode = function(glyph)
		{
			if (this.LastPickFont.GetGIDByUnicode(glyph))
			{
				if (this.LastPickFontName != this.LastPickFontNameOrigin)
				{
                    this.LastPickFontName = this.LastPickFontNameOrigin;
					this.Metafile.SetFontName(this.LastPickFontName);
				}
			}
			else
			{
                var name = AscFonts.FontPickerByCharacter.getFontBySymbol(glyph);
                if (name != this.LastPickFontName)
				{
					this.LastPickFontName = name;
                    this.Metafile.SetFontName(this.LastPickFontName);
                }
			}
		};
	}


	function CMetafile(width, height)
	{
		this.Width  = width;
		this.Height = height;

		this.m_oPen   = new CPen();
		this.m_oBrush = new CBrush();

		this.m_oFont =
		{
			Name     : "",
			FontSize : -1,
			Style    : -1
		};

		// чтобы выставилось в первый раз
		this.m_oPen.Color.R    = -1;
		this.m_oBrush.Color1.R = -1;
		this.m_oBrush.Color2.R = -1;

		this.m_oTransform    = new CMatrix();
		this.m_arrayCommands = [];

		this.Memory               = null;
		this.VectorMemoryForPrint = null;

		this.BrushType = MetaBrushType.Solid;

		// RFonts
		this.m_oTextPr  = null;
		this.m_oGrFonts = new CGrRFonts();

		// просто чтобы не создавать каждый раз
		this.m_oFontSlotFont    = new CFontSetup();
		this.LastFontOriginInfo = {Name : "", Replace : null};
		this.m_oFontTmp = { FontFamily : { Name : "arial" }, Bold : false, Italic : false };

		this.StartOffset = 0;

		this.m_bIsPenDash = false;

		this.FontPicker = null;
	}

	CMetafile.prototype =
	{
		// pen methods
		p_color  : function(r, g, b, a)
		{
			if (this.m_oPen.Color.R != r || this.m_oPen.Color.G != g || this.m_oPen.Color.B != b)
			{
				this.m_oPen.Color.R = r;
				this.m_oPen.Color.G = g;
				this.m_oPen.Color.B = b;

				var value = b << 16 | g << 8 | r;
				this.Memory.WriteByte(CommandType.ctPenColor);
				this.Memory.WriteLong(value);
			}
			if (this.m_oPen.Color.A != a)
			{
				this.m_oPen.Color.A = a;
				this.Memory.WriteByte(CommandType.ctPenAlpha);
				this.Memory.WriteByte(a);
			}
		},
		p_width  : function(w)
		{
			var val = w / 1000;
			if (this.m_oPen.Size != val)
			{
				this.m_oPen.Size = val;
				this.Memory.WriteByte(CommandType.ctPenSize);
				this.Memory.WriteDouble(val);
			}
		},
		p_dash : function(params)
		{
			var bIsDash = (params && (params.length > 0)) ? true : false;

			if (false == this.m_bIsPenDash && bIsDash == this.m_bIsPenDash)
				return;
			this.m_bIsPenDash = bIsDash;

			if (!this.m_bIsPenDash)
			{
				this.Memory.WriteByte(CommandType.ctPenDashStyle);
				this.Memory.WriteByte(0);
			}
			else
			{
				this.Memory.WriteByte(CommandType.ctPenDashStyle);
				this.Memory.WriteByte(5);

				this.Memory.WriteLong(params.length);
				for (var i = 0; i < params.length; i++)
				{
					this.Memory.WriteDouble(params[i]);
				}
			}
		},
		// brush methods
		b_color1 : function(r, g, b, a)
		{
			if (this.BrushType != MetaBrushType.Solid)
			{
				this.Memory.WriteByte(CommandType.ctBrushType);
				this.Memory.WriteLong(1000);
				this.BrushType = MetaBrushType.Solid;
			}

			if (this.m_oBrush.Color1.R != r || this.m_oBrush.Color1.G != g || this.m_oBrush.Color1.B != b)
			{
				this.m_oBrush.Color1.R = r;
				this.m_oBrush.Color1.G = g;
				this.m_oBrush.Color1.B = b;

				var value = b << 16 | g << 8 | r;
				this.Memory.WriteByte(CommandType.ctBrushColor1);
				this.Memory.WriteLong(value);
			}
			if (this.m_oBrush.Color1.A != a)
			{
				this.m_oBrush.Color1.A = a;
				this.Memory.WriteByte(CommandType.ctBrushAlpha1);
				this.Memory.WriteByte(a);
			}
		},
		b_color2 : function(r, g, b, a)
		{
			if (this.m_oBrush.Color2.R != r || this.m_oBrush.Color2.G != g || this.m_oBrush.Color2.B != b)
			{
				this.m_oBrush.Color2.R = r;
				this.m_oBrush.Color2.G = g;
				this.m_oBrush.Color2.B = b;

				var value = b << 16 | g << 8 | r;
				this.Memory.WriteByte(CommandType.ctBrushColor2);
				this.Memory.WriteLong(value);
			}
			if (this.m_oBrush.Color2.A != a)
			{
				this.m_oBrush.Color2.A = a;
				this.Memory.WriteByte(CommandType.ctBrushAlpha2);
				this.Memory.WriteByte(a);
			}
		},

		put_brushTexture : function(src, mode)
		{
			var isLocalUse = true;
			if (window["AscDesktopEditor"] && window["AscDesktopEditor"]["IsLocalFile"] && window["AscDesktopEditor"]["IsFilePrinting"])
				isLocalUse = ((!window["AscDesktopEditor"]["IsLocalFile"]()) && window["AscDesktopEditor"]["IsFilePrinting"]()) ? false : true;

            if (window["AscDesktopEditor"] && !isLocalUse)
            {
                if ((undefined !== window["AscDesktopEditor"]["CryptoMode"]) && (0 < window["AscDesktopEditor"]["CryptoMode"]))
                    isLocalUse = true;
            }

			if (this.BrushType != MetaBrushType.Texture)
			{
				this.Memory.WriteByte(CommandType.ctBrushType);
				this.Memory.WriteLong(3008);
				this.BrushType = MetaBrushType.Texture;
			}

			this.m_oBrush.Color1.R = -1;
			this.m_oBrush.Color1.G = -1;
			this.m_oBrush.Color1.B = -1;
			this.m_oBrush.Color1.A = -1;
			this.Memory.WriteByte(CommandType.ctBrushTexturePath);

			var _src = src;

			var srcLocal = AscCommon.g_oDocumentUrls.getLocal(_src);
			if (srcLocal && isLocalUse)
			{
				_src = srcLocal;
			}

			this.Memory.WriteString(_src);
			this.Memory.WriteByte(CommandType.ctBrushTextureMode);
			this.Memory.WriteByte(mode);
		},

		put_BrushTextureAlpha : function(alpha)
		{
			var write = alpha;
			if (null == alpha || undefined == alpha)
				write = 255;

			this.Memory.WriteByte(CommandType.ctBrushTextureAlpha);
			this.Memory.WriteByte(write);
		},

		put_BrushGradient : function(gradFill, points, transparent)
		{
			this.BrushType = MetaBrushType.Gradient;

			this.Memory.WriteByte(CommandType.ctBrushGradient);

			this.Memory.WriteByte(AscCommon.g_nodeAttributeStart);

			if (gradFill.path != null && (gradFill.lin == null || gradFill.lin == undefined))
			{
				this.Memory.WriteByte(1);
				this.Memory.WriteByte(gradFill.path);

				this.Memory.WriteDouble(points.x0);
				this.Memory.WriteDouble(points.y0);
				this.Memory.WriteDouble(points.x1);
				this.Memory.WriteDouble(points.y1);
				this.Memory.WriteDouble(points.r0);
				this.Memory.WriteDouble(points.r1);
			}
			else
			{
				this.Memory.WriteByte(0);
				if (null == gradFill.lin)
				{
					this.Memory.WriteLong(90 * 60000);
					this.Memory.WriteBool(false);
				}
				else
				{
					this.Memory.WriteLong(gradFill.lin.angle);
					this.Memory.WriteBool(gradFill.lin.scale);
				}

				this.Memory.WriteDouble(points.x0);
				this.Memory.WriteDouble(points.y0);
				this.Memory.WriteDouble(points.x1);
				this.Memory.WriteDouble(points.y1);
			}

			var _colors = gradFill.colors;
			this.Memory.WriteByte(2);
			this.Memory.WriteLong(_colors.length);

			for (var i = 0; i < _colors.length; i++)
			{
				this.Memory.WriteLong(_colors[i].pos);

				this.Memory.WriteByte(_colors[i].color.RGBA.R);
				this.Memory.WriteByte(_colors[i].color.RGBA.G);
				this.Memory.WriteByte(_colors[i].color.RGBA.B);

				if (null == transparent)
					this.Memory.WriteByte(_colors[i].color.RGBA.A);
				else
					this.Memory.WriteByte(transparent);
			}

			this.Memory.WriteByte(AscCommon.g_nodeAttributeEnd);
		},

		transform                 : function(sx, shy, shx, sy, tx, ty)
		{
			if (this.m_oTransform.sx != sx || this.m_oTransform.shx != shx || this.m_oTransform.shy != shy ||
				this.m_oTransform.sy != sy || this.m_oTransform.tx != tx || this.m_oTransform.ty != ty)
			{
				this.m_oTransform.sx  = sx;
				this.m_oTransform.shx = shx;
				this.m_oTransform.shy = shy;
				this.m_oTransform.sy  = sy;
				this.m_oTransform.tx  = tx;
				this.m_oTransform.ty  = ty;

				this.Memory.WriteByte(CommandType.ctSetTransform);
				this.Memory.WriteDouble(sx);
				this.Memory.WriteDouble(shy);
				this.Memory.WriteDouble(shx);
				this.Memory.WriteDouble(sy);
				this.Memory.WriteDouble(tx);
				this.Memory.WriteDouble(ty);
			}
		},
		// path commands
		_s                        : function()
		{
			if (this.VectorMemoryForPrint != null)
				this.VectorMemoryForPrint.ClearNoAttack();

			var _memory = (null == this.VectorMemoryForPrint) ? this.Memory : this.VectorMemoryForPrint;
			_memory.WriteByte(CommandType.ctPathCommandStart);
		},
		_e                        : function()
		{
			// тут всегда напрямую в Memory
			this.Memory.WriteByte(CommandType.ctPathCommandEnd);
		},
		_z                        : function()
		{
			var _memory = (null == this.VectorMemoryForPrint) ? this.Memory : this.VectorMemoryForPrint;
			_memory.WriteByte(CommandType.ctPathCommandClose);
		},
		_m                        : function(x, y)
		{
			var _memory = (null == this.VectorMemoryForPrint) ? this.Memory : this.VectorMemoryForPrint;
			_memory.WriteByte(CommandType.ctPathCommandMoveTo);
			_memory.WriteDouble(x);
			_memory.WriteDouble(y);
		},
		_l                        : function(x, y)
		{
			var _memory = (null == this.VectorMemoryForPrint) ? this.Memory : this.VectorMemoryForPrint;
			_memory.WriteByte(CommandType.ctPathCommandLineTo);
			_memory.WriteDouble(x);
			_memory.WriteDouble(y);
		},
		_c                        : function(x1, y1, x2, y2, x3, y3)
		{
			var _memory = (null == this.VectorMemoryForPrint) ? this.Memory : this.VectorMemoryForPrint;
			_memory.WriteByte(CommandType.ctPathCommandCurveTo);
			_memory.WriteDouble(x1);
			_memory.WriteDouble(y1);
			_memory.WriteDouble(x2);
			_memory.WriteDouble(y2);
			_memory.WriteDouble(x3);
			_memory.WriteDouble(y3);
		},
		_c2                       : function(x1, y1, x2, y2)
		{
			var _memory = (null == this.VectorMemoryForPrint) ? this.Memory : this.VectorMemoryForPrint;
			_memory.WriteByte(CommandType.ctPathCommandCurveTo);
			_memory.WriteDouble(x1);
			_memory.WriteDouble(y1);
			_memory.WriteDouble(x1);
			_memory.WriteDouble(y1);
			_memory.WriteDouble(x2);
			_memory.WriteDouble(y2);
		},
		ds                        : function()
		{
			if (null == this.VectorMemoryForPrint)
			{
				this.Memory.WriteByte(CommandType.ctDrawPath);
				this.Memory.WriteLong(1);
			}
			else
			{
				this.Memory.Copy(this.VectorMemoryForPrint, 0, this.VectorMemoryForPrint.pos);
				this.Memory.WriteByte(CommandType.ctDrawPath);
				this.Memory.WriteLong(1);
			}
		},
		df                        : function()
		{
			if (null == this.VectorMemoryForPrint)
			{
				this.Memory.WriteByte(CommandType.ctDrawPath);
				this.Memory.WriteLong(256);
			}
			else
			{
				this.Memory.Copy(this.VectorMemoryForPrint, 0, this.VectorMemoryForPrint.pos);
				this.Memory.WriteByte(CommandType.ctDrawPath);
				this.Memory.WriteLong(256);
			}
		},
		WriteVectorMemoryForPrint : function()
		{
			if (null != this.VectorMemoryForPrint)
			{
				this.Memory.Copy(this.VectorMemoryForPrint, 0, this.VectorMemoryForPrint.pos);
			}
		},
		drawpath                  : function(type)
		{
			if (null == this.VectorMemoryForPrint)
			{
				this.Memory.WriteByte(CommandType.ctDrawPath);
				this.Memory.WriteLong(type);
			}
			else
			{
				this.Memory.Copy(this.VectorMemoryForPrint, 0, this.VectorMemoryForPrint.pos);
				this.Memory.WriteByte(CommandType.ctDrawPath);
				this.Memory.WriteLong(type);
			}
		},

		// canvas state
		save    : function()
		{
		},
		restore : function()
		{
		},
		clip    : function()
		{
		},

		// images
		drawImage : function(img, x, y, w, h, isUseOriginUrl)
		{
			var isLocalUse = true;
			if (window["AscDesktopEditor"] && window["AscDesktopEditor"]["IsLocalFile"] && window["AscDesktopEditor"]["IsFilePrinting"])
				isLocalUse = ((!window["AscDesktopEditor"]["IsLocalFile"]()) && window["AscDesktopEditor"]["IsFilePrinting"]()) ? false : true;

			if (window["AscDesktopEditor"] && !isLocalUse)
			{
				if ((undefined !== window["AscDesktopEditor"]["CryptoMode"]) && (0 < window["AscDesktopEditor"]["CryptoMode"]))
					isLocalUse = true;
			}

			if (!window.editor)
			{
				// excel
				this.Memory.WriteByte(CommandType.ctDrawImageFromFile);

				var imgLocal = AscCommon.g_oDocumentUrls.getLocal(img);
				if (imgLocal && isLocalUse && (true !== isUseOriginUrl))
				{
					this.Memory.WriteString2(imgLocal);
				}
				else
				{
					this.Memory.WriteString2(img);
				}

				this.Memory.WriteDouble(x);
				this.Memory.WriteDouble(y);
				this.Memory.WriteDouble(w);
				this.Memory.WriteDouble(h);
				return;
			}

			var _src = "";
			if (!window["NATIVE_EDITOR_ENJINE"] && (true !== isUseOriginUrl))
			{
				var _img = window.editor.ImageLoader.map_image_index[img];
				if (_img == undefined || _img.Image == null)
					return;

				_src = _img.src;
			}
			else
			{
				_src = img;
			}

			var srcLocal = AscCommon.g_oDocumentUrls.getLocal(_src);
			if (srcLocal && isLocalUse)
			{
				_src = srcLocal;
			}

			this.Memory.WriteByte(CommandType.ctDrawImageFromFile);
			this.Memory.WriteString2(_src);
			this.Memory.WriteDouble(x);
			this.Memory.WriteDouble(y);
			this.Memory.WriteDouble(w);
			this.Memory.WriteDouble(h);
		},

		SetFontName : function(name)
		{
            var fontinfo = g_fontApplication.GetFontInfo(name, 0, this.LastFontOriginInfo);
            if (this.m_oFont.Name != fontinfo.Name)
            {
                this.m_oFont.Name = fontinfo.Name;
                this.Memory.WriteByte(CommandType.ctFontName);
                this.Memory.WriteString(this.m_oFont.Name);
            }
		},

		SetFont      : function(font, isFromPicker)
		{
			if (this.FontPicker && !isFromPicker)
				return this.FontPicker.SetFont(font);

			if (null == font)
				return;

			var style = 0;
			if (font.Italic == true)
				style += 2;
			if (font.Bold == true)
				style += 1;

			var fontinfo = g_fontApplication.GetFontInfo(font.FontFamily.Name, style, this.LastFontOriginInfo);
			//style        = fontinfo.GetBaseStyle(style);

			if (this.m_oFont.Name != fontinfo.Name)
			{
				this.m_oFont.Name = fontinfo.Name;
				this.Memory.WriteByte(CommandType.ctFontName);
				this.Memory.WriteString(this.m_oFont.Name);
			}
			if (this.m_oFont.FontSize != font.FontSize)
			{
				this.m_oFont.FontSize = font.FontSize;
				this.Memory.WriteByte(CommandType.ctFontSize);
				this.Memory.WriteDouble(this.m_oFont.FontSize);
			}
			if (this.m_oFont.Style != style)
			{
				this.m_oFont.Style = style;
				this.Memory.WriteByte(CommandType.ctFontStyle);
				this.Memory.WriteLong(style);
			}
		},
		FillText     : function(x, y, text)
		{
			if (null != this.LastFontOriginInfo.Replace && 1 == text.length)
				return this.FillTextCode(x, y, text.charCodeAt(0));

			this.Memory.WriteByte(CommandType.ctDrawText);

			this.Memory.WriteString(text);
			this.Memory.WriteDouble(x);
			this.Memory.WriteDouble(y);
		},
		FillTextCode : function(x, y, code)
		{
			var _code = code;
            if (null != this.LastFontOriginInfo.Replace)
				_code = g_fontApplication.GetReplaceGlyph(_code, this.LastFontOriginInfo.Replace);

			if (this.FontPicker)
				this.FontPicker.FillTextCode(_code);

            this.Memory.WriteByte(CommandType.ctDrawText);
			this.Memory.WriteStringBySymbol(_code);
            this.Memory.WriteDouble(x);
            this.Memory.WriteDouble(y);
		},
		tg           : function(gid, x, y)
		{
			if (window["native"] !== undefined)
			{
				// TODO:
				return;
			}

			var _old_pos = this.Memory.pos;

			g_fontApplication.LoadFont(this.m_oFont.Name, AscCommon.g_font_loader, AscCommon.g_oTextMeasurer.m_oManager, this.m_oFont.FontSize, Math.max(this.m_oFont.Style, 0), 72, 72);
			AscCommon.g_oTextMeasurer.m_oManager.LoadStringPathCode(gid, true, x, y, this);

			// start (1) + draw(1) + typedraw(4) + end(1) = 7!
			if ((this.Memory.pos - _old_pos) < 8)
				this.Memory.pos = _old_pos;

			/*
			 this.Memory.WriteByte(CommandType.ctDrawTextCodeGid);
			 this.Memory.WriteLong(gid);
			 this.Memory.WriteDouble(x);
			 this.Memory.WriteDouble(y);
			 */
		},
		charspace    : function(space)
		{
		},

		beginCommand : function(command)
		{
			this.Memory.WriteByte(CommandType.ctBeginCommand);
			this.Memory.WriteLong(command);
		},
		endCommand   : function(command)
		{
			if (32 == command)
			{
				if (null == this.VectorMemoryForPrint)
				{
					this.Memory.WriteByte(CommandType.ctEndCommand);
					this.Memory.WriteLong(command);
				}
				else
				{
					this.Memory.Copy(this.VectorMemoryForPrint, 0, this.VectorMemoryForPrint.pos);
					this.Memory.WriteByte(CommandType.ctEndCommand);
					this.Memory.WriteLong(command);
				}
				return;
			}
			this.Memory.WriteByte(CommandType.ctEndCommand);
			this.Memory.WriteLong(command);
		},

		put_PenLineJoin          : function(_join)
		{
			this.Memory.WriteByte(CommandType.ctPenLineJoin);
			this.Memory.WriteByte(_join & 0xFF);
		},
		put_TextureBounds        : function(x, y, w, h)
		{
			this.Memory.WriteByte(CommandType.ctBrushRectable);
			this.Memory.WriteDouble(x);
			this.Memory.WriteDouble(y);
			this.Memory.WriteDouble(w);
			this.Memory.WriteDouble(h);
		},
		put_TextureBoundsEnabled : function(bIsEnabled)
		{
			this.Memory.WriteByte(CommandType.ctBrushRectableEnabled);
			this.Memory.WriteBool(bIsEnabled);
		},

		SetFontSlot : function(slot, fontSizeKoef)
		{
			var _rfonts   = this.m_oGrFonts;
			var _lastFont = this.m_oFontSlotFont;

			switch (slot)
			{
				case fontslot_ASCII:
				{
					_lastFont.Name   = _rfonts.Ascii.Name;
					_lastFont.Size   = this.m_oTextPr.FontSize;
					_lastFont.Bold   = this.m_oTextPr.Bold;
					_lastFont.Italic = this.m_oTextPr.Italic;

					break;
				}
				case fontslot_CS:
				{
					_lastFont.Name   = _rfonts.CS.Name;
					_lastFont.Size   = this.m_oTextPr.FontSizeCS;
					_lastFont.Bold   = this.m_oTextPr.BoldCS;
					_lastFont.Italic = this.m_oTextPr.ItalicCS;

					break;
				}
				case fontslot_EastAsia:
				{
					_lastFont.Name   = _rfonts.EastAsia.Name;
					_lastFont.Size   = this.m_oTextPr.FontSize;
					_lastFont.Bold   = this.m_oTextPr.Bold;
					_lastFont.Italic = this.m_oTextPr.Italic;

					break;
				}
				case fontslot_HAnsi:
				default:
				{
					_lastFont.Name   = _rfonts.HAnsi.Name;
					_lastFont.Size   = this.m_oTextPr.FontSize;
					_lastFont.Bold   = this.m_oTextPr.Bold;
					_lastFont.Italic = this.m_oTextPr.Italic;

					break;
				}
			}

			if (undefined !== fontSizeKoef)
				_lastFont.Size *= fontSizeKoef;

            this.m_oFontTmp.FontFamily.Name = _lastFont.Name;
            this.m_oFontTmp.Bold = _lastFont.Bold;
            this.m_oFontTmp.Italic = _lastFont.Italic;
            this.m_oFontTmp.FontSize = _lastFont.Size;
            this.SetFont(this.m_oFontTmp);
		}
	};

	function CDocumentRenderer()
	{
		this.m_arrayPages         = [];
		this.m_lPagesCount        = 0;
		//this.DocumentInfo = "";
		this.Memory               = new CMemory();
		this.VectorMemoryForPrint = null;

		this.ClipManager            = new CClipManager();
		this.ClipManager.BaseObject = this;

		this.RENDERER_PDF_FLAG = true;
		this.ArrayPoints       = null;

		this.GrState        = new CGrState();
		this.GrState.Parent = this;

		this.m_oPen       = null;
		this.m_oBrush     = null;
		this.m_oTransform = null;

		this._restoreDumpedVectors = null;

		this.m_oBaseTransform = null;

		this.UseOriginImageUrl = false;

        this.FontPicker = null;
	}

	CDocumentRenderer.prototype =
	{
		InitPicker : function(_manager)
		{
			this.FontPicker = new CMetafileFontPicker(_manager);
		},

		SetBaseTransform : function(_matrix)
		{
			this.m_oBaseTransform = _matrix;
		},
		BeginPage        : function(width, height)
		{
			this.m_arrayPages[this.m_arrayPages.length]                    = new CMetafile(width, height);
			this.m_lPagesCount                                             = this.m_arrayPages.length;
			this.m_arrayPages[this.m_lPagesCount - 1].Memory               = this.Memory;
			this.m_arrayPages[this.m_lPagesCount - 1].StartOffset          = this.Memory.pos;
			this.m_arrayPages[this.m_lPagesCount - 1].VectorMemoryForPrint = this.VectorMemoryForPrint;
            this.m_arrayPages[this.m_lPagesCount - 1].FontPicker		   = this.FontPicker;

            if (this.FontPicker)
            	this.m_arrayPages[this.m_lPagesCount - 1].FontPicker.Metafile  = this.m_arrayPages[this.m_lPagesCount - 1];

			this.Memory.WriteByte(CommandType.ctPageStart);

			this.Memory.WriteByte(CommandType.ctPageWidth);
			this.Memory.WriteDouble(width);
			this.Memory.WriteByte(CommandType.ctPageHeight);
			this.Memory.WriteDouble(height);

			var _page         = this.m_arrayPages[this.m_lPagesCount - 1];
			this.m_oPen       = _page.m_oPen;
			this.m_oBrush     = _page.m_oBrush;
			this.m_oTransform = _page.m_oTransform;
		},
		EndPage          : function()
		{
			this.Memory.WriteByte(CommandType.ctPageEnd);
		},

		p_color    : function(r, g, b, a)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].p_color(r, g, b, a);
		},
		p_width    : function(w)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].p_width(w);
		},
		p_dash : function(params)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].p_dash(params);
		},
		// brush methods
		b_color1   : function(r, g, b, a)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].b_color1(r, g, b, a);
		},
		b_color2   : function(r, g, b, a)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].b_color2(r, g, b, a);
		},
		transform  : function(sx, shy, shx, sy, tx, ty)
		{
			if (0 != this.m_lPagesCount)
			{
				if (null == this.m_oBaseTransform)
					this.m_arrayPages[this.m_lPagesCount - 1].transform(sx, shy, shx, sy, tx, ty);
				else
				{
					var _transform = new CMatrix();
					_transform.sx  = sx;
					_transform.shy = shy;
					_transform.shx = shx;
					_transform.sy  = sy;
					_transform.tx  = tx;
					_transform.ty  = ty;
					AscCommon.global_MatrixTransformer.MultiplyAppend(_transform, this.m_oBaseTransform);
					this.m_arrayPages[this.m_lPagesCount - 1].transform(_transform.sx, _transform.shy, _transform.shx, _transform.sy, _transform.tx, _transform.ty);
				}
			}
		},
		transform3 : function(m)
		{
			this.transform(m.sx, m.shy, m.shx, m.sy, m.tx, m.ty);
		},
		reset      : function()
		{
			this.transform(1, 0, 0, 1, 0, 0);
		},
		// path commands
		_s         : function()
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1]._s();
		},
		_e         : function()
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1]._e();
		},
		_z         : function()
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1]._z();
		},
		_m         : function(x, y)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1]._m(x, y);

			if (this.ArrayPoints != null)
				this.ArrayPoints[this.ArrayPoints.length] = {x : x, y : y};
		},
		_l         : function(x, y)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1]._l(x, y);

			if (this.ArrayPoints != null)
				this.ArrayPoints[this.ArrayPoints.length] = {x : x, y : y};
		},
		_c         : function(x1, y1, x2, y2, x3, y3)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1]._c(x1, y1, x2, y2, x3, y3);

			if (this.ArrayPoints != null)
			{
				this.ArrayPoints[this.ArrayPoints.length] = {x : x1, y : y1};
				this.ArrayPoints[this.ArrayPoints.length] = {x : x2, y : y2};
				this.ArrayPoints[this.ArrayPoints.length] = {x : x3, y : y3};
			}
		},
		_c2        : function(x1, y1, x2, y2)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1]._c2(x1, y1, x2, y2);

			if (this.ArrayPoints != null)
			{
				this.ArrayPoints[this.ArrayPoints.length] = {x : x1, y : y1};
				this.ArrayPoints[this.ArrayPoints.length] = {x : x2, y : y2};
			}
		},
		ds         : function()
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].ds();
		},
		df         : function()
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].df();
		},
		drawpath   : function(type)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].drawpath(type);
		},

		// canvas state
		save    : function()
		{
		},
		restore : function()
		{
		},
		clip    : function()
		{
		},

		// images
		drawImage : function(img, x, y, w, h, alpha, srcRect)
		{
			if (img == null || img == undefined || img == "")
				return;

			if (0 != this.m_lPagesCount)
			{
				if (!srcRect)
					this.m_arrayPages[this.m_lPagesCount - 1].drawImage(img, x, y, w, h, this.UseOriginImageUrl);
				else
				{
					/*
					 if (!window.editor)
					 {
					 this.m_arrayPages[this.m_lPagesCount - 1].drawImage(img,x,y,w,h);
					 return;
					 }
					 */

					var _img = undefined;
					if (window.editor)
						_img = window.editor.ImageLoader.map_image_index[img];
					else if (window["Asc"]["editor"])
						_img = window["Asc"]["editor"].ImageLoader.map_image_index[img];

					var w0 = 0;
					var h0 = 0;
					if (_img != undefined && _img.Image != null)
					{
						w0 = _img.Image.width;
						h0 = _img.Image.height;
					}

					if (w0 == 0 || h0 == 0)
					{
						this.m_arrayPages[this.m_lPagesCount - 1].drawImage(img, x, y, w, h);
						return;
					}

					var bIsClip = false;
					if (srcRect.l > 0 || srcRect.t > 0 || srcRect.r < 100 || srcRect.b < 100)
						bIsClip = true;

					if (bIsClip)
					{
						this.SaveGrState();
						this.AddClipRect(x, y, w, h);
					}

					var __w   = w;
					var __h   = h;
					var _delW = Math.max(0, -srcRect.l) + Math.max(0, srcRect.r - 100) + 100;
					var _delH = Math.max(0, -srcRect.t) + Math.max(0, srcRect.b - 100) + 100;

					if (srcRect.l < 0)
					{
						var _off = ((-srcRect.l / _delW) * __w);
						x += _off;
						w -= _off;
					}
					if (srcRect.t < 0)
					{
						var _off = ((-srcRect.t / _delH) * __h);
						y += _off;
						h -= _off;
					}
					if (srcRect.r > 100)
					{
						var _off = ((srcRect.r - 100) / _delW) * __w;
						w -= _off;
					}
					if (srcRect.b > 100)
					{
						var _off = ((srcRect.b - 100) / _delH) * __h;
						h -= _off;
					}

					var _wk = 100;
					if (srcRect.l > 0)
						_wk -= srcRect.l;
					if (srcRect.r < 100)
						_wk -= (100 - srcRect.r);
					_wk = 100 / _wk;

					var _hk = 100;
					if (srcRect.t > 0)
						_hk -= srcRect.t;
					if (srcRect.b < 100)
						_hk -= (100 - srcRect.b);
					_hk = 100 / _hk;

					var _r = x + w;
					var _b = y + h;

					if (srcRect.l > 0)
					{
						x -= ((srcRect.l * _wk * w) / 100);
					}
					if (srcRect.t > 0)
					{
						y -= ((srcRect.t * _hk * h) / 100);
					}
					if (srcRect.r < 100)
					{
						_r += (((100 - srcRect.r) * _wk * w) / 100);
					}
					if (srcRect.b < 100)
					{
						_b += (((100 - srcRect.b) * _hk * h) / 100);
					}

					this.m_arrayPages[this.m_lPagesCount - 1].drawImage(img, x, y, _r - x, _b - y);

					if (bIsClip)
					{
						this.RestoreGrState();
					}
				}
			}
		},

		SetFont                  : function(font)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].SetFont(font);
		},
		FillText                 : function(x, y, text, cropX, cropW)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].FillText(x, y, text);
		},
		FillTextCode             : function(x, y, text, cropX, cropW)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].FillTextCode(x, y, text);
		},
		tg                       : function(gid, x, y)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].tg(gid, x, y);
		},
		FillText2                : function(x, y, text)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].FillText(x, y, text);
		},
		charspace                : function(space)
		{
		},
		SetIntegerGrid           : function(param)
		{
		},
		GetIntegerGrid           : function()
		{
		},
		GetFont                  : function()
		{
			if (0 != this.m_lPagesCount)
				return this.m_arrayPages[this.m_lPagesCount - 1].m_oFont;
			return null;
		},
		put_GlobalAlpha          : function(enable, alpha)
		{
		},
		Start_GlobalAlpha        : function()
		{
		},
		End_GlobalAlpha          : function()
		{
		},
		DrawHeaderEdit           : function(yPos)
		{
		},
		DrawFooterEdit           : function(yPos)
		{
		},
		drawCollaborativeChanges : function(x, y, w, h)
		{
		},
		drawSearchResult         : function(x, y, w, h)
		{
		},

		DrawEmptyTableLine : function(x1, y1, x2, y2)
		{
			// эта функция не для печати или сохранения вообще
		},
		DrawLockParagraph  : function(lock_type, x, y1, y2)
		{
			// эта функция не для печати или сохранения вообще
		},

		DrawLockObjectRect : function(lock_type, x, y, w, h)
		{
			// эта функция не для печати или сохранения вообще
		},

		DrawSpellingLine : function(y0, x0, x1, w)
		{
		},

		// smart methods for horizontal / vertical lines
		drawHorLine  : function(align, y, x, r, penW)
		{
			this.p_width(1000 * penW);
			this._s();

			var _y = y;
			switch (align)
			{
				case 0:
				{
					_y = y + penW / 2;
					break;
				}
				case 1:
				{
					break;
				}
				case 2:
				{
					_y = y - penW / 2;
				}
			}
			this._m(x, y);
			this._l(r, y);

			this.ds();

			this._e();
		},
		drawHorLine2 : function(align, y, x, r, penW)
		{
			this.p_width(1000 * penW);

			var _y = y;
			switch (align)
			{
				case 0:
				{
					_y = y + penW / 2;
					break;
				}
				case 1:
				{
					break;
				}
				case 2:
				{
					_y = y - penW / 2;
					break;
				}
			}

			this._s();
			this._m(x, (_y - penW));
			this._l(r, (_y - penW));
			this.ds();

			this._s();
			this._m(x, (_y + penW));
			this._l(r, (_y + penW));
			this.ds();

			this._e();
		},

		drawVerLine : function(align, x, y, b, penW)
		{
			this.p_width(1000 * penW);
			this._s();

			var _x = x;
			switch (align)
			{
				case 0:
				{
					_x = x + penW / 2;
					break;
				}
				case 1:
				{
					break;
				}
				case 2:
				{
					_x = x - penW / 2;
				}
			}
			this._m(_x, y);
			this._l(_x, b);

			this.ds();
		},

		// мега крутые функции для таблиц
		drawHorLineExt : function(align, y, x, r, penW, leftMW, rightMW)
		{
			this.drawHorLine(align, y, x + leftMW, r + rightMW, penW);
		},

		rect : function(x, y, w, h)
		{
			var _x = x;
			var _y = y;
			var _r = (x + w);
			var _b = (y + h);

			this._s();
			this._m(_x, _y);
			this._l(_r, _y);
			this._l(_r, _b);
			this._l(_x, _b);
			this._l(_x, _y);
		},

		TableRect : function(x, y, w, h)
		{
			this.rect(x, y, w, h);
			this.df();
		},

		put_PenLineJoin          : function(_join)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].put_PenLineJoin(_join);
		},
		put_TextureBounds        : function(x, y, w, h)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].put_TextureBounds(x, y, w, h);
		},
		put_TextureBoundsEnabled : function(val)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].put_TextureBoundsEnabled(val);
		},
		put_brushTexture         : function(src, mode)
		{
			if (src == null || src == undefined)
				src = "";

			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].put_brushTexture(src, mode);
		},
		put_BrushTextureAlpha    : function(alpha)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].put_BrushTextureAlpha(alpha);
		},
		put_BrushGradient        : function(gradFill, points, transparent)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].put_BrushGradient(gradFill, points, transparent);
		},

		// функции клиппирования
		AddClipRect    : function(x, y, w, h)
		{
			/*
			 this.b_color1(0, 0, 0, 255);
			 this.rect(x, y, w, h);
			 this.df();
			 return;
			 */

			var __rect = new _rect();
			__rect.x   = x;
			__rect.y   = y;
			__rect.w   = w;
			__rect.h   = h;
			this.GrState.AddClipRect(__rect);
			//this.ClipManager.AddRect(x, y, w, h);
		},
		RemoveClipRect : function()
		{
			//this.ClipManager.RemoveRect();
		},

		SetClip    : function(r)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].beginCommand(32);

			this.rect(r.x, r.y, r.w, r.h);

			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].endCommand(32);

			//this._s();
		},
		RemoveClip : function()
		{
			if (0 != this.m_lPagesCount)
			{
				this.m_arrayPages[this.m_lPagesCount - 1].beginCommand(64);
				this.m_arrayPages[this.m_lPagesCount - 1].endCommand(64);
			}
		},

		GetTransform : function()
		{
			if (0 != this.m_lPagesCount)
			{
				return this.m_arrayPages[this.m_lPagesCount - 1].m_oTransform;
			}
			return null;
		},
		GetLineWidth : function()
		{
			if (0 != this.m_lPagesCount)
			{
				return this.m_arrayPages[this.m_lPagesCount - 1].m_oPen.Size;
			}
			return 0;
		},
		GetPen       : function()
		{
			if (0 != this.m_lPagesCount)
			{
				return this.m_arrayPages[this.m_lPagesCount - 1].m_oPen;
			}
			return 0;
		},
		GetBrush     : function()
		{
			if (0 != this.m_lPagesCount)
			{
				return this.m_arrayPages[this.m_lPagesCount - 1].m_oBrush;
			}
			return 0;
		},

		drawFlowAnchor : function(x, y)
		{
		},

		SavePen    : function()
		{
			this.GrState.SavePen();
		},
		RestorePen : function()
		{
			this.GrState.RestorePen();
		},

		SaveBrush    : function()
		{
			this.GrState.SaveBrush();
		},
		RestoreBrush : function()
		{
			this.GrState.RestoreBrush();
		},

		SavePenBrush    : function()
		{
			this.GrState.SavePenBrush();
		},
		RestorePenBrush : function()
		{
			this.GrState.RestorePenBrush();
		},

		SaveGrState    : function()
		{
			this.GrState.SaveGrState();
		},
		RestoreGrState : function()
		{
			var _t                = this.m_oBaseTransform;
			this.m_oBaseTransform = null;
			this.GrState.RestoreGrState();
			this.m_oBaseTransform = _t;
		},

		StartClipPath : function()
		{
			this.private_removeVectors();

			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].beginCommand(32);
		},

		EndClipPath : function()
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].endCommand(32);

			this.private_restoreVectors();
		},

		SetTextPr : function(textPr, theme)
		{
			if (0 != this.m_lPagesCount)
			{
				var _page = this.m_arrayPages[this.m_lPagesCount - 1];

				_page.m_oTextPr = textPr;
				if (theme)
					_page.m_oGrFonts.checkFromTheme(theme.themeElements.fontScheme, _page.m_oTextPr.RFonts);
				else
					_page.m_oGrFonts = _page.m_oTextPr.RFonts;
			}
		},

		SetFontSlot : function(slot, fontSizeKoef)
		{
			if (0 != this.m_lPagesCount)
				this.m_arrayPages[this.m_lPagesCount - 1].SetFontSlot(slot, fontSizeKoef);
		},

		GetTextPr : function()
		{
			if (0 != this.m_lPagesCount)
				return this.m_arrayPages[this.m_lPagesCount - 1].m_oTextPr;
			return null;
		},

		DrawPresentationComment : function(type, x, y, w, h)
		{

		},

		private_removeVectors : function()
		{
			this._restoreDumpedVectors = this.VectorMemoryForPrint;

			if (this._restoreDumpedVectors != null)
			{
				this.VectorMemoryForPrint = null;
				if (0 != this.m_lPagesCount)
					this.m_arrayPages[this.m_lPagesCount - 1].VectorMemoryForPrint = null;
			}
		},

		private_restoreVectors : function()
		{
			if (null != this._restoreDumpedVectors)
			{
				this.VectorMemoryForPrint = this._restoreDumpedVectors;
				if (0 != this.m_lPagesCount)
					this.m_arrayPages[this.m_lPagesCount - 1].VectorMemoryForPrint = this._restoreDumpedVectors;
			}
			this._restoreDumpedVectors = null;
		}
	};

	var MATRIX_ORDER_PREPEND = 0;
	var MATRIX_ORDER_APPEND  = 1;

	function deg2rad(deg)
	{
		return deg * Math.PI / 180.0;
	}

	function rad2deg(rad)
	{
		return rad * 180.0 / Math.PI;
	}

	function CMatrix()
	{
		this.sx  = 1.0;
		this.shx = 0.0;
		this.shy = 0.0;
		this.sy  = 1.0;
		this.tx  = 0.0;
		this.ty  = 0.0;
	}

	CMatrix.prototype =
	{
		Reset           : function()
		{
			this.sx  = 1.0;
			this.shx = 0.0;
			this.shy = 0.0;
			this.sy  = 1.0;
			this.tx  = 0.0;
			this.ty  = 0.0;
		},
		// трансформ
		Multiply        : function(matrix, order)
		{
			if (MATRIX_ORDER_PREPEND == order)
			{
				var m = new CMatrix();
				m.sx  = matrix.sx;
				m.shx = matrix.shx;
				m.shy = matrix.shy;
				m.sy  = matrix.sy;
				m.tx  = matrix.tx;
				m.ty  = matrix.ty;
				m.Multiply(this, MATRIX_ORDER_APPEND);
				this.sx  = m.sx;
				this.shx = m.shx;
				this.shy = m.shy;
				this.sy  = m.sy;
				this.tx  = m.tx;
				this.ty  = m.ty;
			}
			else
			{
				var t0   = this.sx * matrix.sx + this.shy * matrix.shx;
				var t2   = this.shx * matrix.sx + this.sy * matrix.shx;
				var t4   = this.tx * matrix.sx + this.ty * matrix.shx + matrix.tx;
				this.shy = this.sx * matrix.shy + this.shy * matrix.sy;
				this.sy  = this.shx * matrix.shy + this.sy * matrix.sy;
				this.ty  = this.tx * matrix.shy + this.ty * matrix.sy + matrix.ty;
				this.sx  = t0;
				this.shx = t2;
				this.tx  = t4;
			}
			return this;
		},
		// а теперь частные случаи трансформа (для удобного пользования)
		Translate       : function(x, y, order)
		{
			var m = new CMatrix();
			m.tx  = x;
			m.ty  = y;
			this.Multiply(m, order);
		},
		Scale           : function(x, y, order)
		{
			var m = new CMatrix();
			m.sx  = x;
			m.sy  = y;
			this.Multiply(m, order);
		},
		Rotate          : function(a, order)
		{
			var m   = new CMatrix();
			var rad = deg2rad(a);
			m.sx    = Math.cos(rad);
			m.shx   = Math.sin(rad);
			m.shy   = -Math.sin(rad);
			m.sy    = Math.cos(rad);
			this.Multiply(m, order);
		},
		RotateAt        : function(a, x, y, order)
		{
			this.Translate(-x, -y, order);
			this.Rotate(a, order);
			this.Translate(x, y, order);
		},
		// determinant
		Determinant     : function()
		{
			return this.sx * this.sy - this.shy * this.shx;
		},
		// invert
		Invert          : function()
		{
			var det = this.Determinant();
			if (0.0001 > Math.abs(det))
				return;
			var d = 1 / det;

			var t0   = this.sy * d;
			this.sy  = this.sx * d;
			this.shy = -this.shy * d;
			this.shx = -this.shx * d;

			var t4  = -this.tx * t0 - this.ty * this.shx;
			this.ty = -this.tx * this.shy - this.ty * this.sy;

			this.sx = t0;
			this.tx = t4;
			return this;
		},
		// transform point
		TransformPointX : function(x, y)
		{
			return x * this.sx + y * this.shx + this.tx;
		},
		TransformPointY : function(x, y)
		{
			return x * this.shy + y * this.sy + this.ty;
		},
		// calculate rotate angle
		GetRotation     : function()
		{
			var x1  = 0.0;
			var y1  = 0.0;
			var x2  = 1.0;
			var y2  = 0.0;
			var _x1 = this.TransformPointX(x1, y1);
			var _y1 = this.TransformPointY(x1, y1);
			var _x2 = this.TransformPointX(x2, y2);
			var _y2 = this.TransformPointY(x2, y2);

			var _y = _y2 - _y1;
			var _x = _x2 - _x1;

			if (Math.abs(_y) < 0.001)
			{
				if (_x > 0)
					return 0;
				else
					return 180;
			}
			if (Math.abs(_x) < 0.001)
			{
				if (_y > 0)
					return 90;
				else
					return 270;
			}

			var a = Math.atan2(_y, _x);
			a     = rad2deg(a);
			if (a < 0)
				a += 360;
			return a;
		},
		// сделать дубликата
		CreateDublicate : function()
		{
			var m = new CMatrix();
			m.sx  = this.sx;
			m.shx = this.shx;
			m.shy = this.shy;
			m.sy  = this.sy;
			m.tx  = this.tx;
			m.ty  = this.ty;
			return m;
		},

		IsIdentity  : function()
		{
			if (this.sx == 1.0 &&
				this.shx == 0.0 &&
				this.shy == 0.0 &&
				this.sy == 1.0 &&
				this.tx == 0.0 &&
				this.ty == 0.0)
			{
				return true;
			}
			return false;
		},
		IsIdentity2 : function()
		{
			if (this.sx == 1.0 &&
				this.shx == 0.0 &&
				this.shy == 0.0 &&
				this.sy == 1.0)
			{
				return true;
			}
			return false;
		},

		GetScaleValue : function()
		{
			var x1 = this.TransformPointX(0, 0);
			var y1 = this.TransformPointY(0, 0);
			var x2 = this.TransformPointX(1, 1);
			var y2 = this.TransformPointY(1, 1);
			return Math.sqrt(((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))/2);
		}
	};

	function GradientGetAngleNoRotate(_angle, _transform)
	{
		var x1 = 0.0;
		var y1 = 0.0;
		var x2 = 1.0;
		var y2 = 0.0;

		var _matrixRotate = new CMatrix();
		_matrixRotate.Rotate(-_angle / 60000);

		var _x11 = _matrixRotate.TransformPointX(x1, y1);
		var _y11 = _matrixRotate.TransformPointY(x1, y1);
		var _x22 = _matrixRotate.TransformPointX(x2, y2);
		var _y22 = _matrixRotate.TransformPointY(x2, y2);

		_matrixRotate = global_MatrixTransformer.Invert(_transform);

		var _x1 = _matrixRotate.TransformPointX(_x11, _y11);
		var _y1 = _matrixRotate.TransformPointY(_x11, _y11);
		var _x2 = _matrixRotate.TransformPointX(_x22, _y22);
		var _y2 = _matrixRotate.TransformPointY(_x22, _y22);

		var _y = _y2 - _y1;
		var _x = _x2 - _x1;

		var a = 0;
		if (Math.abs(_y) < 0.001)
		{
			if (_x > 0)
				a = 0;
			else
				a = 180;
		}
		else if (Math.abs(_x) < 0.001)
		{
			if (_y > 0)
				a = 90;
			else
				a = 270;
		}
		else
		{
			a = Math.atan2(_y, _x);
			a = rad2deg(a);
		}

		if (a < 0)
			a += 360;

		//console.log(a);
		return a * 60000;
	};

	var CMatrixL = CMatrix;

	function CGlobalMatrixTransformer()
	{
		this.TranslateAppend = function(m, _tx, _ty)
		{
			m.tx += _tx;
			m.ty += _ty;
		}
		this.ScaleAppend     = function(m, _sx, _sy)
		{
			m.sx *= _sx;
			m.shx *= _sx;
			m.shy *= _sy;
			m.sy *= _sy;
			m.tx *= _sx;
			m.ty *= _sy;
		}
		this.RotateRadAppend = function(m, _rad)
		{
			var _sx  = Math.cos(_rad);
			var _shx = Math.sin(_rad);
			var _shy = -Math.sin(_rad);
			var _sy  = Math.cos(_rad);

			var t0 = m.sx * _sx + m.shy * _shx;
			var t2 = m.shx * _sx + m.sy * _shx;
			var t4 = m.tx * _sx + m.ty * _shx;
			m.shy  = m.sx * _shy + m.shy * _sy;
			m.sy   = m.shx * _shy + m.sy * _sy;
			m.ty   = m.tx * _shy + m.ty * _sy;
			m.sx   = t0;
			m.shx  = t2;
			m.tx   = t4;
		}

		this.MultiplyAppend = function(m1, m2)
		{
			var t0 = m1.sx * m2.sx + m1.shy * m2.shx;
			var t2 = m1.shx * m2.sx + m1.sy * m2.shx;
			var t4 = m1.tx * m2.sx + m1.ty * m2.shx + m2.tx;
			m1.shy = m1.sx * m2.shy + m1.shy * m2.sy;
			m1.sy  = m1.shx * m2.shy + m1.sy * m2.sy;
			m1.ty  = m1.tx * m2.shy + m1.ty * m2.sy + m2.ty;
			m1.sx  = t0;
			m1.shx = t2;
			m1.tx  = t4;
		}

		this.Invert = function(m)
		{
			var newM = m.CreateDublicate();
			var det  = newM.sx * newM.sy - newM.shy * newM.shx;
			if (0.0001 > Math.abs(det))
				return newM;

			var d = 1 / det;

			var t0   = newM.sy * d;
			newM.sy  = newM.sx * d;
			newM.shy = -newM.shy * d;
			newM.shx = -newM.shx * d;

			var t4  = -newM.tx * t0 - newM.ty * newM.shx;
			newM.ty = -newM.tx * newM.shy - newM.ty * newM.sy;

			newM.sx = t0;
			newM.tx = t4;
			return newM;
		}

		this.MultiplyAppendInvert = function(m1, m2)
		{
			var m = this.Invert(m2);
			this.MultiplyAppend(m1, m);
		}

		this.MultiplyPrepend = function(m1, m2)
		{
			var m = new CMatrixL();
			m.sx  = m2.sx;
			m.shx = m2.shx;
			m.shy = m2.shy;
			m.sy  = m2.sy;
			m.tx  = m2.tx;
			m.ty  = m2.ty;
			this.MultiplyAppend(m, m1);
			m1.sx  = m.sx;
			m1.shx = m.shx;
			m1.shy = m.shy;
			m1.sy  = m.sy;
			m1.tx  = m.tx;
			m1.ty  = m.ty;
		}

		this.CreateDublicateM = function(matrix)
		{
			var m = new CMatrixL();
			m.sx  = matrix.sx;
			m.shx = matrix.shx;
			m.shy = matrix.shy;
			m.sy  = matrix.sy;
			m.tx  = matrix.tx;
			m.ty  = matrix.ty;
		}

		this.IsIdentity  = function(m)
		{
			if (m.sx == 1.0 &&
				m.shx == 0.0 &&
				m.shy == 0.0 &&
				m.sy == 1.0 &&
				m.tx == 0.0 &&
				m.ty == 0.0)
			{
				return true;
			}
			return false;
		}
		this.IsIdentity2 = function(m)
		{
			if (m.sx == 1.0 &&
				m.shx == 0.0 &&
				m.shy == 0.0 &&
				m.sy == 1.0)
			{
				return true;
			}
			return false;
		}
	}

	function CClipManager()
	{
		this.clipRects  = [];
		this.curRect    = new _rect();
		this.BaseObject = null;

		this.AddRect    = function(x, y, w, h)
		{
			var _count = this.clipRects.length;
			if (0 == _count)
			{
				this.curRect.x = x;
				this.curRect.y = y;
				this.curRect.w = w;
				this.curRect.h = h;

				var _r                 = new _rect();
				_r.x                   = x;
				_r.y                   = y;
				_r.w                   = w;
				_r.h                   = h;
				this.clipRects[_count] = _r;

				this.BaseObject.SetClip(this.curRect);
			}
			else
			{
				this.BaseObject.RemoveClip();
				var _r = new _rect();
				_r.x   = x;
				_r.y   = y;
				_r.w   = w;
				_r.h   = h;

				this.clipRects[_count] = _r;
				this.curRect           = this.IntersectRect(this.curRect, _r);
				this.BaseObject.SetClip(this.curRect);
			}
		}
		this.RemoveRect = function()
		{
			var _count = this.clipRects.length;
			if (0 != _count)
			{
				this.clipRects.splice(_count - 1, 1);
				--_count;

				this.BaseObject.RemoveClip();

				if (0 != _count)
				{
					this.curRect.x = this.clipRects[0].x;
					this.curRect.y = this.clipRects[0].y;
					this.curRect.w = this.clipRects[0].w;
					this.curRect.h = this.clipRects[0].h;

					for (var i = 1; i < _count; i++)
						this.curRect = this.IntersectRect(this.curRect, this.clipRects[i]);

					this.BaseObject.SetClip(this.curRect);
				}
			}
		}

		this.IntersectRect = function(r1, r2)
		{
			var res = new _rect();
			res.x   = Math.max(r1.x, r2.x);
			res.y   = Math.max(r1.y, r2.y);
			res.w   = Math.min(r1.x + r1.w, r2.x + r2.w) - res.x;
			res.h   = Math.min(r1.y + r1.h, r2.y + r2.h) - res.y;

			if (0 > res.w)
				res.w = 0;
			if (0 > res.h)
				res.h = 0;

			return res;
		}
	}

	function CPen()
	{
		this.Color    = {R : 255, G : 255, B : 255, A : 255};
		this.Style    = 0;
		this.LineCap  = 0;
		this.LineJoin = 0;

		this.LineWidth = 1;
	}

	function CBrush()
	{
		this.Color1 = {R : 255, G : 255, B : 255, A : 255};
		this.Color2 = {R : 255, G : 255, B : 255, A : 255};
		this.Type   = 0;
	}

	function CTableMarkup(Table)
	{
		this.Internal =
		{
			RowIndex  : 0,
			CellIndex : 0,
			PageNum   : 0
		};
		this.Table    = Table;
		this.X        = 0; // Смещение таблицы от начала страницы до первой колонки

		this.Cols    = []; // массив ширин колонок
		this.Margins = []; // массив левых и правых маргинов

		this.Rows = []; // массив позиций, высот строк(для данной страницы)
		// Rows = [ { Y : , H :  }, ... ]

		this.CurCol = 0; // текущая колонка
		this.CurRow = 0; // текущая строка

		this.TransformX = 0;
		this.TransformY = 0;
	}

	CTableMarkup.prototype =
	{
		CreateDublicate : function()
		{
			var obj = new CTableMarkup(this.Table);

			obj.Internal = {RowIndex : this.Internal.RowIndex, CellIndex : this.Internal.CellIndex, PageNum : this.Internal.PageNum};
			obj.X        = this.X;

			var len = this.Cols.length;
			for (var i = 0; i < len; i++)
				obj.Cols[i] = this.Cols[i];

			len = this.Margins.length;
			for (var i = 0; i < len; i++)
				obj.Margins[i] = {Left : this.Margins[i].Left, Right : this.Margins[i].Right};

			len = this.Rows.length;
			for (var i = 0; i < len; i++)
				obj.Rows[i] = {Y : this.Rows[i].Y, H : this.Rows[i].H};

			obj.CurRow = this.CurRow;
			obj.CurCol = this.CurCol;

			return obj;
		},

		CorrectFrom : function()
		{
			this.X += this.TransformX;

			var _len = this.Rows.length;
			for (var i = 0; i < _len; i++)
			{
				this.Rows[i].Y += this.TransformY;
			}
		},

		CorrectTo : function()
		{
			this.X -= this.TransformX;

			var _len = this.Rows.length;
			for (var i = 0; i < _len; i++)
			{
				this.Rows[i].Y -= this.TransformY;
			}
		},

		Get_X : function()
		{
			return this.X;
		},

		Get_Y : function()
		{
			var _Y = 0;
			if (this.Rows.length > 0)
			{
				_Y = this.Rows[0].Y;
			}
			return _Y;
		}
	};

	function CTableOutline(Table, PageNum, X, Y, W, H)
	{
		this.Table   = Table;
		this.PageNum = PageNum;

		this.X = X;
		this.Y = Y;

		this.W = W;
		this.H = H;
	}

	var g_fontManager = new AscFonts.CFontManager();
	g_fontManager.Initialize(true);

	function SetHintsProps(bIsHinting, bIsSubpixHinting)
	{
		if (undefined === g_fontManager.m_oLibrary.tt_hint_props)
			return;

		if (bIsHinting && bIsSubpixHinting)
		{
			g_fontManager.m_oLibrary.tt_hint_props.TT_USE_BYTECODE_INTERPRETER       = true;
			g_fontManager.m_oLibrary.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING = true;

			g_fontManager.LOAD_MODE = 40968;
		}
		else if (bIsHinting)
		{
			g_fontManager.m_oLibrary.tt_hint_props.TT_USE_BYTECODE_INTERPRETER       = true;
			g_fontManager.m_oLibrary.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING = false;

			g_fontManager.LOAD_MODE = 40968;
		}
		else
		{
			g_fontManager.m_oLibrary.tt_hint_props.TT_USE_BYTECODE_INTERPRETER       = true;
			g_fontManager.m_oLibrary.tt_hint_props.TT_CONFIG_OPTION_SUBPIXEL_HINTING = false;

			g_fontManager.LOAD_MODE = 40970;
		}
	}

	SetHintsProps(true, true);

	var g_dDpiX = 96.0;
	var g_dDpiY = 96.0;

	var g_dKoef_mm_to_pix = g_dDpiX / 25.4;
	var g_dKoef_pix_to_mm = 25.4 / g_dDpiX;

	function _rect()
	{
		this.x = 0;
		this.y = 0;
		this.w = 0;
		this.h = 0;
	}

	//--------------------------------------------------------export----------------------------------------------------
	window['AscCommon']                          = window['AscCommon'] || {};
	window['AscCommon'].CGrRFonts                = CGrRFonts;
	window['AscCommon'].CFontSetup               = CFontSetup;
	window['AscCommon'].CGrState                 = CGrState;
	window['AscCommon'].Base64Encode             = Base64Encode;
	window['AscCommon'].CMemory                  = CMemory;
	window['AscCommon'].CDocumentRenderer        = CDocumentRenderer;
	window['AscCommon'].MATRIX_ORDER_PREPEND     = MATRIX_ORDER_PREPEND;
	window['AscCommon'].MATRIX_ORDER_APPEND      = MATRIX_ORDER_APPEND;
	window['AscCommon'].deg2rad                  = deg2rad;
	window['AscCommon'].rad2deg                  = rad2deg;
	window['AscCommon'].CMatrix                  = CMatrix;
	window['AscCommon'].CMatrixL                 = CMatrixL;
	window['AscCommon'].CGlobalMatrixTransformer = CGlobalMatrixTransformer;
	window['AscCommon'].CClipManager             = CClipManager;
	window['AscCommon'].CPen                     = CPen;
	window['AscCommon'].CBrush                   = CBrush;
	window['AscCommon'].CTableMarkup             = CTableMarkup;
	window['AscCommon'].CTableOutline            = CTableOutline;
	window['AscCommon'].SetHintsProps            = SetHintsProps;
	window['AscCommon']._rect                    = _rect;

	window['AscCommon'].global_MatrixTransformer = new CGlobalMatrixTransformer();
	window['AscCommon'].g_fontManager            = g_fontManager;
	window['AscCommon'].g_dDpiX                  = g_dDpiX;
	window['AscCommon'].g_dKoef_mm_to_pix        = g_dKoef_mm_to_pix;
	window['AscCommon'].g_dKoef_pix_to_mm        = g_dKoef_pix_to_mm;
	window['AscCommon'].GradientGetAngleNoRotate = GradientGetAngleNoRotate;

	window['AscCommon'].DashPatternPresets 		 = DashPatternPresets;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){
    function CTextMeasurer()
    {
        this.m_oManager = new AscFonts.CFontManager();

        this.m_oFont = null;

        // RFonts
        this.m_oTextPr = null;
        this.m_oGrFonts = new AscCommon.CGrRFonts();
        this.m_oLastFont = new AscCommon.CFontSetup();

        this.LastFontOriginInfo = {Name : "", Replace : null};
    }

    CTextMeasurer.prototype =
    {
        Init : function()
        {
            this.m_oManager.Initialize();
        },

        SetStringGid : function(bGID)
        {
            this.m_oManager.SetStringGID(bGID);
        },

        SetFont : function(font)
        {
            if (!font)
                return;

            this.m_oFont = font;

            var bItalic = true === font.Italic;
            var bBold   = true === font.Bold;

            var oFontStyle = FontStyle.FontStyleRegular;
            if ( !bItalic && bBold )
                oFontStyle = FontStyle.FontStyleBold;
            else if ( bItalic && !bBold )
                oFontStyle = FontStyle.FontStyleItalic;
            else if ( bItalic && bBold )
                oFontStyle = FontStyle.FontStyleBoldItalic;

            var _lastSetUp = this.m_oLastFont;
            if (_lastSetUp.SetUpName != font.FontFamily.Name || _lastSetUp.SetUpSize != font.FontSize || _lastSetUp.SetUpStyle != oFontStyle)
            {
                _lastSetUp.SetUpName = font.FontFamily.Name;
                _lastSetUp.SetUpSize = font.FontSize;
                _lastSetUp.SetUpStyle = oFontStyle;

                g_fontApplication.LoadFont(_lastSetUp.SetUpName, AscCommon.g_font_loader, this.m_oManager, _lastSetUp.SetUpSize, _lastSetUp.SetUpStyle, 72, 72, undefined, this.LastFontOriginInfo);
            }
        },

        SetFontInternal : function(_name, _size, _style)
        {
            var _lastSetUp = this.m_oLastFont;
            if (_lastSetUp.SetUpName != _name || _lastSetUp.SetUpSize != _size || _lastSetUp.SetUpStyle != _style)
            {
                _lastSetUp.SetUpName = _name;
                _lastSetUp.SetUpSize = _size;
                _lastSetUp.SetUpStyle = _style;

                g_fontApplication.LoadFont(_lastSetUp.SetUpName, AscCommon.g_font_loader, this.m_oManager, _lastSetUp.SetUpSize, _lastSetUp.SetUpStyle, 72, 72, undefined, this.LastFontOriginInfo);
            }
        },

        SetTextPr : function(textPr, theme)
        {
            this.m_oTextPr = textPr;
            if (theme)
                this.m_oGrFonts.checkFromTheme(theme.themeElements.fontScheme, this.m_oTextPr.RFonts);
            else
                this.m_oGrFonts = this.m_oTextPr.RFonts;
        },

        SetFontSlot : function(slot, fontSizeKoef)
        {
            var _rfonts = this.m_oGrFonts;
            var _lastFont = this.m_oLastFont;

            switch (slot)
            {
                case fontslot_ASCII:
                {
                    _lastFont.Name   = _rfonts.Ascii.Name;
                    _lastFont.Index  = _rfonts.Ascii.Index;

                    _lastFont.Size = this.m_oTextPr.FontSize;
                    _lastFont.Bold = this.m_oTextPr.Bold;
                    _lastFont.Italic = this.m_oTextPr.Italic;

                    break;
                }
                case fontslot_CS:
                {
                    _lastFont.Name   = _rfonts.CS.Name;
                    _lastFont.Index  = _rfonts.CS.Index;

                    _lastFont.Size = this.m_oTextPr.FontSizeCS;
                    _lastFont.Bold = this.m_oTextPr.BoldCS;
                    _lastFont.Italic = this.m_oTextPr.ItalicCS;

                    break;
                }
                case fontslot_EastAsia:
                {
                    _lastFont.Name   = _rfonts.EastAsia.Name;
                    _lastFont.Index  = _rfonts.EastAsia.Index;

                    _lastFont.Size = this.m_oTextPr.FontSize;
                    _lastFont.Bold = this.m_oTextPr.Bold;
                    _lastFont.Italic = this.m_oTextPr.Italic;

                    break;
                }
                case fontslot_HAnsi:
                default:
                {
                    _lastFont.Name   = _rfonts.HAnsi.Name;
                    _lastFont.Index  = _rfonts.HAnsi.Index;

                    _lastFont.Size = this.m_oTextPr.FontSize;
                    _lastFont.Bold = this.m_oTextPr.Bold;
                    _lastFont.Italic = this.m_oTextPr.Italic;

                    break;
                }
            }

            if (undefined !== fontSizeKoef)
                _lastFont.Size *= fontSizeKoef;

            var _style = 0;
            if (_lastFont.Italic)
                _style += 2;
            if (_lastFont.Bold)
                _style += 1;

            if (_lastFont.Name != _lastFont.SetUpName || _lastFont.Size != _lastFont.SetUpSize || _style != _lastFont.SetUpStyle)
            {
                _lastFont.SetUpName = _lastFont.Name;
                _lastFont.SetUpSize = _lastFont.Size;
                _lastFont.SetUpStyle = _style;

                g_fontApplication.LoadFont(_lastFont.SetUpName, AscCommon.g_font_loader, this.m_oManager, _lastFont.SetUpSize, _lastFont.SetUpStyle, 72, 72, undefined, this.LastFontOriginInfo);
            }
        },

        GetTextPr : function()
        {
            return this.m_oTextPr;
        },

        GetFont : function()
        {
            return this.m_oFont;
        },

        Measure : function(text)
        {
            var Width  = 0;
            var Height = 0;

            var _code = text.charCodeAt(0);
            if (null != this.LastFontOriginInfo.Replace)
                _code = g_fontApplication.GetReplaceGlyph(_code, this.LastFontOriginInfo.Replace);

            var Temp = this.m_oManager.MeasureChar( _code );

            Width  = Temp.fAdvanceX * 25.4 / 72;
            Height = 0;//Temp.fHeight;

            return { Width : Width, Height : Height };
        },
        Measure2 : function(text)
        {
            var Width  = 0;

            var _code = text.charCodeAt(0);
            if (null != this.LastFontOriginInfo.Replace)
                _code = g_fontApplication.GetReplaceGlyph(_code, this.LastFontOriginInfo.Replace);

            var Temp = this.m_oManager.MeasureChar( _code, true );

            Width  = Temp.fAdvanceX * 25.4 / 72;

            if (Temp.oBBox.rasterDistances == null)
            {
                return {
                    Width  : Width,
                    Ascent : (Temp.oBBox.fMaxY * 25.4 / 72),
                    Height : ((Temp.oBBox.fMaxY - Temp.oBBox.fMinY) * 25.4 / 72),
                    WidthG : ((Temp.oBBox.fMaxX - Temp.oBBox.fMinX) * 25.4 / 72),
                    rasterOffsetX: 0,
                    rasterOffsetY: 0
                };
            }

            return {
                Width  : Width,
                Ascent : (Temp.oBBox.fMaxY * 25.4 / 72),
                Height : ((Temp.oBBox.fMaxY - Temp.oBBox.fMinY) * 25.4 / 72),
                WidthG : ((Temp.oBBox.fMaxX - Temp.oBBox.fMinX) * 25.4 / 72),
                rasterOffsetX: Temp.oBBox.rasterDistances.dist_l * 25.4 / 72,
                rasterOffsetY: Temp.oBBox.rasterDistances.dist_t * 25.4 / 72
            };
        },

        MeasureCode : function(lUnicode)
        {
            var Width  = 0;
            var Height = 0;

            if (null != this.LastFontOriginInfo.Replace)
                lUnicode = g_fontApplication.GetReplaceGlyph(lUnicode, this.LastFontOriginInfo.Replace);

            var Temp = this.m_oManager.MeasureChar( lUnicode );

            Width  = Temp.fAdvanceX * 25.4 / 72;
            Height = ((Temp.oBBox.fMaxY - Temp.oBBox.fMinY) * 25.4 / 72);

            return { Width : Width, Height : Height, Ascent : (Temp.oBBox.fMaxY * 25.4 / 72) };
        },
        Measure2Code : function(lUnicode)
        {
            var Width  = 0;

            if (null != this.LastFontOriginInfo.Replace)
                lUnicode = g_fontApplication.GetReplaceGlyph(lUnicode, this.LastFontOriginInfo.Replace);

            var Temp = this.m_oManager.MeasureChar( lUnicode, true );

            Width  = Temp.fAdvanceX * 25.4 / 72;

            if (Temp.oBBox.rasterDistances == null)
            {
                return {
                    Width  : Width,
                    Ascent : (Temp.oBBox.fMaxY * 25.4 / 72),
                    Height : ((Temp.oBBox.fMaxY - Temp.oBBox.fMinY) * 25.4 / 72),
                    WidthG : ((Temp.oBBox.fMaxX - Temp.oBBox.fMinX) * 25.4 / 72),
                    rasterOffsetX: 0,
                    rasterOffsetY: 0
                };
            }

            return {
                Width  : Width,
                Ascent : (Temp.oBBox.fMaxY * 25.4 / 72),
                Height : ((Temp.oBBox.fMaxY - Temp.oBBox.fMinY) * 25.4 / 72),
                WidthG : ((Temp.oBBox.fMaxX - Temp.oBBox.fMinX) * 25.4 / 72),
                rasterOffsetX: (Temp.oBBox.rasterDistances.dist_l + Temp.oBBox.fMinX) * 25.4 / 72,
                rasterOffsetY: Temp.oBBox.rasterDistances.dist_t * 25.4 / 72
            };
        },

        GetAscender : function()
        {
            var UnitsPerEm = this.m_oManager.m_lUnits_Per_Em;
            var Ascender   = this.m_oManager.m_lAscender;

            return Ascender * this.m_oLastFont.SetUpSize / UnitsPerEm * g_dKoef_pt_to_mm;
        },
        GetDescender : function()
        {
            var UnitsPerEm = this.m_oManager.m_lUnits_Per_Em;
            var Descender  = this.m_oManager.m_lDescender;

            return Descender * this.m_oLastFont.SetUpSize / UnitsPerEm * g_dKoef_pt_to_mm;
        },
        GetHeight : function()
        {
            var UnitsPerEm = this.m_oManager.m_lUnits_Per_Em;
            var Height     = this.m_oManager.m_lLineHeight;

            return Height * this.m_oLastFont.SetUpSize / UnitsPerEm * g_dKoef_pt_to_mm;
        }
    };
    var g_oTextMeasurer = new CTextMeasurer();
    g_oTextMeasurer.Init();

    //--------------------------------------------------------export----------------------------------------------------
    window['AscCommon'] = window['AscCommon'] || {};
    window['AscCommon'].CTextMeasurer = CTextMeasurer;
    window['AscCommon'].g_oTextMeasurer = g_oTextMeasurer;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined)
{
	AscCommon.isTouch 			= false;
	AscCommon.isTouchMove 		= false;
	AscCommon.TouchStartTime 	= -1;
	// Import
	var AscBrowser               = AscCommon.AscBrowser;

	// константы для мыши
	var g_mouse_event_type_down  = 0;
	var g_mouse_event_type_move  = 1;
	var g_mouse_event_type_up    = 2;
	var g_mouse_event_type_wheel = 3;

	var g_mouse_button_left   = 0;
	var g_mouse_button_center = 1;
	var g_mouse_button_right  = 2;

	var MouseUpLock = {
		MouseUpLockedSend : false
	};

	AscCommon.stopEvent = function(e)
	{
		if (!e)
			return;
		if (e.preventDefault)
			e.preventDefault();
		if (e.stopPropagation)
			e.stopPropagation();
	};

	function CMouseEventHandler()
	{
		this.X = 0;                            // позиция курсора X
		this.Y = 0;                            // позиция курсора Y

		this.Button = g_mouse_button_left;          // кнопка мыши
		this.Type   = g_mouse_event_type_move;      // тип евента

		this.AltKey   = false;                        // нажата ли кнопка alt
		this.CtrlKey  = false;                        // нажата ли кнопка ctrl
		this.ShiftKey = false;                        // нажата ли кнопка shift

		this.Sender = null;                         // от какого html элемента пришел евент

		this.LastClickTime = -1;                       // время последнего mousedown
		this.ClickCount    = 0;                        // количество кликов

		this.WheelDelta = 0;

		// координаты мышки при предыдущем mousedown (для mousemove)
		this.IsPressed = false;                        // была ли зажата кнопка
		this.LastX     = 0;
		this.LastY     = 0;

		this.KoefPixToMM = 1;

		this.IsLocked      = false;
		this.IsLockedEvent = false;

		this.buttonObject = null;

		this.AscHitToHandlesEpsilon = 0;

		this.LockMouse   = function()
		{
			if (!this.IsLocked)
			{
				this.IsLocked = true;

				if (window.captureEvents)
					window.captureEvents(Event.MOUSEDOWN | Event.MOUSEUP);

				if (window.g_asc_plugins)
					window.g_asc_plugins.disablePointerEvents();

				/*
				 var parent = window;
				 while (true)
				 {
				 if (!parent)
				 break;

				 if (parent.captureEvents)
				 parent.captureEvents(Event.MOUSEDOWN | Event.MOUSEUP);

				 if (parent == parent.parent)
				 break;

				 parent = parent.parent;
				 }
				 */

				return true;
			}
			return false;
		};
		this.UnLockMouse = function()
		{
			if (this.IsLocked)
			{
				this.IsLocked = false;

				if (window.releaseEvents)
					window.releaseEvents(Event.MOUSEMOVE);

				if (window.g_asc_plugins)
					window.g_asc_plugins.enablePointerEvents();

				/*
				 var parent = window;
				 while (true)
				 {
				 if (!parent)
				 break;

				 if (parent.releaseEvents)
				 parent.releaseEvents(Event.MOUSEMOVE);

				 if (parent == parent.parent)
				 break;

				 parent = parent.parent;
				 }
				 */

				return true;
			}
			return false;
		};
	}

	function CKeyboardEvent()
	{
		this.AltKey   = false;                        // нажата ли кнопка alt
		this.CtrlKey  = false;                        // нажата ли кнопка ctrl
		this.ShiftKey = false;                        // нажата ли кнопка shift
		this.AltGr    = false;

		this.Sender = null;                         // от какого html элемента пришел евент

		this.CharCode = 0;
		this.KeyCode  = 0;
	}

	CKeyboardEvent.prototype.Up = function()
	{
		this.AltKey   = false;
		this.CtrlKey  = false;
		this.ShiftKey = false;
		this.AltGr    = false;
	};

	var global_mouseEvent    = new CMouseEventHandler();
	var global_keyboardEvent = new CKeyboardEvent();

	function check_KeyboardEvent(e)
	{
		global_keyboardEvent.AltKey = e.altKey;
		global_keyboardEvent.AltGr = AscCommon.getAltGr(e);
		global_keyboardEvent.CtrlKey = !global_keyboardEvent.AltGr && (e.metaKey || e.ctrlKey);

		global_keyboardEvent.ShiftKey = e.shiftKey;

		global_keyboardEvent.Sender = (e.srcElement) ? e.srcElement : e.target;

		global_keyboardEvent.CharCode = e.charCode;
		global_keyboardEvent.KeyCode  = e.keyCode;
		global_keyboardEvent.Which    = e.which;
	}

	function check_KeyboardEvent2(e)
	{
		global_keyboardEvent.AltKey = e.altKey;

		if (e.metaKey !== undefined)
			global_keyboardEvent.CtrlKey = e.ctrlKey || e.metaKey;
		else
			global_keyboardEvent.CtrlKey = e.ctrlKey;

		global_keyboardEvent.ShiftKey = e.shiftKey;

		global_keyboardEvent.AltGr = (global_keyboardEvent.CtrlKey && global_keyboardEvent.AltKey) ? true : false;

		if (global_keyboardEvent.CtrlKey && global_keyboardEvent.AltKey)
			global_keyboardEvent.CtrlKey = false;
	}

	function check_MouseMoveEvent(e)
	{
		// если мышь залочена, то евент придет от окна.
		if (e.IsLocked && !e.IsLockedEvent)
			return;

		if (e.pageX || e.pageY)
		{
			global_mouseEvent.X = e.pageX;
			global_mouseEvent.Y = e.pageY;
		}
		else if (e.clientX || e.clientY)
		{
			global_mouseEvent.X = e.clientX;
			global_mouseEvent.Y = e.clientY;
		}

		global_mouseEvent.X = (global_mouseEvent.X * AscBrowser.zoom) >> 0;
		global_mouseEvent.Y = (global_mouseEvent.Y * AscBrowser.zoom) >> 0;

		global_mouseEvent.AltKey   = e.altKey;
		global_mouseEvent.ShiftKey = e.shiftKey;
		global_mouseEvent.CtrlKey  = e.ctrlKey || e.metaKey;

		global_mouseEvent.Type = g_mouse_event_type_move;

		if (!global_mouseEvent.IsLocked)
		{
			global_mouseEvent.Sender = (e.srcElement) ? e.srcElement : e.target;
		}

		var _eps = 3 * global_mouseEvent.KoefPixToMM;
		if ((Math.abs(global_mouseEvent.X - global_mouseEvent.LastX) > _eps) || (Math.abs(global_mouseEvent.Y - global_mouseEvent.LastY) > _eps))
		{
			global_mouseEvent.LastClickTime = -1;
			global_mouseEvent.ClickCount    = 0;
		}
	}

	function CreateMouseUpEventObject(x, y)
	{
		var e   = {};
		e.PageX = x;
		e.PageY = y;

		e.altKey   = global_mouseEvent.AltKey;
		e.shiftKey = global_mouseEvent.ShiftKey;
		e.ctrlKey  = global_mouseEvent.CtrlKey;

		e.srcElement = global_mouseEvent.Sender;
		e.button     = 0;
		return e;
	}

	function check_MouseUpEvent(e)
	{
		if (e.pageX || e.pageY)
		{
			global_mouseEvent.X = e.pageX;
			global_mouseEvent.Y = e.pageY;
		}
		else if (e.clientX || e.clientY)
		{
			global_mouseEvent.X = e.clientX;
			global_mouseEvent.Y = e.clientY;
		}

		global_mouseEvent.X = (global_mouseEvent.X * AscBrowser.zoom) >> 0;
		global_mouseEvent.Y = (global_mouseEvent.Y * AscBrowser.zoom) >> 0;

		global_mouseEvent.AltKey   = e.altKey;
		global_mouseEvent.ShiftKey = e.shiftKey;
		global_mouseEvent.CtrlKey  = e.ctrlKey || e.metaKey;

		global_keyboardEvent.AltKey   = global_mouseEvent.AltKey;
		global_keyboardEvent.ShiftKey = global_mouseEvent.ShiftKey;
		global_keyboardEvent.CtrlKey  = global_mouseEvent.CtrlKey;

		global_mouseEvent.Type   = g_mouse_event_type_up;
		global_mouseEvent.Button = (e.button !== undefined) ? e.button : 0;

		var lockedElement = null;

		var newSender = (e.srcElement) ? e.srcElement : e.target;
		if (!newSender)
		    newSender = { id : "emulation_oo_id" };

		if (global_mouseEvent.Sender && global_mouseEvent.Sender.id == newSender.id)
		{
			lockedElement = global_mouseEvent.Sender;
		}

		if (global_mouseEvent.IsLocked == true && global_mouseEvent.Sender != newSender && false === MouseUpLock.MouseUpLockedSend)
		{
			Window_OnMouseUp(e);
		}
		MouseUpLock.MouseUpLockedSend = true;
		global_mouseEvent.Sender      = newSender;

		global_mouseEvent.UnLockMouse();

		global_mouseEvent.IsPressed = false;

		return lockedElement;
	}

	function check_MouseDownEvent(e, isClicks)
	{
		if (e.pageX || e.pageY)
		{
			global_mouseEvent.X = e.pageX;
			global_mouseEvent.Y = e.pageY;
		}
		else if (e.clientX || e.clientY)
		{
			global_mouseEvent.X = e.clientX;
			global_mouseEvent.Y = e.clientY;
		}

		global_mouseEvent.X = (global_mouseEvent.X * AscBrowser.zoom) >> 0;
		global_mouseEvent.Y = (global_mouseEvent.Y * AscBrowser.zoom) >> 0;

		var _eps = 3 * global_mouseEvent.KoefPixToMM;
		if ((Math.abs(global_mouseEvent.X - global_mouseEvent.LastX) > _eps) || (Math.abs(global_mouseEvent.Y - global_mouseEvent.LastY) > _eps))
		{
			// not only move!!! (touch - fast click in different places)
			global_mouseEvent.LastClickTime = -1;
			global_mouseEvent.ClickCount    = 0;
		}

		global_mouseEvent.LastX = global_mouseEvent.X;
		global_mouseEvent.LastY = global_mouseEvent.Y;

		global_mouseEvent.AltKey   = e.altKey;
		global_mouseEvent.ShiftKey = e.shiftKey;
		global_mouseEvent.CtrlKey  = e.ctrlKey || e.metaKey;

		global_keyboardEvent.AltKey   = global_mouseEvent.AltKey;
		global_keyboardEvent.ShiftKey = global_mouseEvent.ShiftKey;
		global_keyboardEvent.CtrlKey  = global_mouseEvent.CtrlKey;

		global_mouseEvent.Type   = g_mouse_event_type_down;
		global_mouseEvent.Button = (e.button !== undefined) ? e.button : 0;
		if (global_mouseEvent.Button == -1)
			global_mouseEvent.Button = 0;

		if (!global_mouseEvent.IsLocked || !global_mouseEvent.Sender)
			global_mouseEvent.Sender = (e.srcElement) ? e.srcElement : e.target;

		if (isClicks)
		{
			var CurTime = new Date().getTime();
			if (0 == global_mouseEvent.ClickCount)
			{
				global_mouseEvent.ClickCount    = 1;
				global_mouseEvent.LastClickTime = CurTime;
			}
			else
			{
				if (500 > CurTime - global_mouseEvent.LastClickTime)
				{
					global_mouseEvent.LastClickTime = CurTime;
					global_mouseEvent.ClickCount++;
				}
				else
				{
					global_mouseEvent.ClickCount    = 1;
					global_mouseEvent.LastClickTime = CurTime;
				}
			}
		}
		else
		{
			global_mouseEvent.LastClickTime = -1;
			global_mouseEvent.ClickCount    = 1;
		}

		MouseUpLock.MouseUpLockedSend = false;
	}

	function check_MouseDownEvent2(x, y)
	{
		global_mouseEvent.X = x;
		global_mouseEvent.Y = y;

		global_mouseEvent.LastX = global_mouseEvent.X;
		global_mouseEvent.LastY = global_mouseEvent.Y;

		global_mouseEvent.Type = g_mouse_event_type_down;

		global_mouseEvent.Sender = editor.WordControl.m_oEditor.HtmlElement;

		global_mouseEvent.LastClickTime = -1;
		global_mouseEvent.ClickCount    = 1;

		MouseUpLock.MouseUpLockedSend = false;
	}

	function global_OnMouseWheel(e)
	{
		global_mouseEvent.AltKey   = e.altKey;
		global_mouseEvent.ShiftKey = e.shiftKey;
		global_mouseEvent.CtrlKey  = e.ctrlKey || e.metaKey;

		if (undefined != e.wheelDelta)
			global_mouseEvent.WheelDelta = (e.wheelDelta > 0) ? -45 : 45;
		else
			global_mouseEvent.WheelDelta = (e.detail > 0) ? 45 : -45;

		global_mouseEvent.type = g_mouse_event_type_wheel;

		global_mouseEvent.Sender = (e.srcElement) ? e.srcElement : e.target;

		global_mouseEvent.LastClickTime = -1;
		global_mouseEvent.ClickCount    = 0;
	}

	function InitCaptureEvents()
	{
		window.onmousemove = function(event)
		{
			return Window_OnMouseMove(event)
		};
		window.onmouseup   = function(event)
		{
			return Window_OnMouseUp(event)
		};
		/*
		 var parent = window;
		 while (true)
		 {
		 if (!parent)
		 return;

		 parent.onmousemove  = function(event){return Window_OnMouseMove(event)};
		 parent.onmouseup    = function(event){return Window_OnMouseUp(event)};

		 if (parent == parent.parent)
		 return;

		 parent = parent.parent;
		 }
		 */
	}

	function Window_OnMouseMove(e)
	{
		if (!global_mouseEvent.IsLocked)
			return;

		if ((undefined != global_mouseEvent.Sender) && (null != global_mouseEvent.Sender) &&
			(undefined != global_mouseEvent.Sender.onmousemove) && (null != global_mouseEvent.Sender.onmousemove))
		{
			global_mouseEvent.IsLockedEvent = true;
			global_mouseEvent.Sender.onmousemove(e);
			global_mouseEvent.IsLockedEvent = false;
		}
	}

	function Window_OnMouseUp(e)
	{
		if (false === MouseUpLock.MouseUpLockedSend)
		{
			MouseUpLock.MouseUpLockedSend = true;
			if (global_mouseEvent.IsLocked)
			{
				if ((undefined != global_mouseEvent.Sender) && (null != global_mouseEvent.Sender) &&
					(undefined != global_mouseEvent.Sender.onmouseup) && (null != global_mouseEvent.Sender.onmouseup))
				{
					global_mouseEvent.Sender.onmouseup(e, true);

					if (global_mouseEvent.IsLocked) // не все хотят пользоваться локами
						global_mouseEvent.UnLockMouse();
				}
			}
		}

		if (window.g_asc_plugins)
		    window.g_asc_plugins.onExternalMouseUp();
	}

	InitCaptureEvents();

	function button_eventHandlers(disable_pos, norm_pos, over_pos, down_pos, control, click_func_delegate)
	{
		this.state_normal = norm_pos;
		this.state_over   = over_pos;
		this.state_down   = down_pos;

		this.Click_func = click_func_delegate;
		this.Control    = control;
		this.IsPressed  = false;

		var oThis = this;

		this.Control.HtmlElement.onmouseover = function(e)
		{
			check_MouseMoveEvent(e);

			if (global_mouseEvent.IsLocked)
			{
				if (global_mouseEvent.Sender.id != oThis.Control.HtmlElement.id)
				{
					// это не залоченная кнопка
					return;
				}
				// залоченная кнопка
				oThis.Control.HtmlElement.style.backgroundPosition = oThis.state_down;
				return;
			}
			oThis.Control.HtmlElement.style.backgroundPosition = oThis.state_over;
		}
		this.Control.HtmlElement.onmouseout  = function(e)
		{
			check_MouseMoveEvent(e);

			if (global_mouseEvent.IsLocked)
			{
				if (global_mouseEvent.Sender.id != oThis.Control.HtmlElement.id)
				{
					// это не залоченная кнопка
					return;
				}
				// залоченная кнопка
				oThis.Control.HtmlElement.style.backgroundPosition = oThis.state_over;
				return;
			}
			oThis.Control.HtmlElement.style.backgroundPosition = oThis.state_normal;
		}
		this.Control.HtmlElement.onmousedown = function(e)
		{
			check_MouseDownEvent(e);
			global_mouseEvent.LockMouse();
			global_mouseEvent.buttonObject = oThis;

			AscCommon.stopEvent(e);

			if (global_mouseEvent.IsLocked)
			{
				if (global_mouseEvent.Sender.id != oThis.Control.HtmlElement.id)
				{
					// это не залоченная кнопка
					return;
				}
				// залоченная кнопка
				oThis.Control.HtmlElement.style.backgroundPosition = oThis.state_down;
				return;
			}
			oThis.Control.HtmlElement.style.backgroundPosition = oThis.state_down;
		}
		this.Control.HtmlElement.onmouseup   = function(e)
		{
			var lockedElement = check_MouseUpEvent(e);

			if (e.preventDefault)
				e.preventDefault();
			else
				e.returnValue = false;

			if (null != lockedElement && global_mouseEvent.buttonObject != null)
			{
				oThis.Click_func();
			}

			if (null != lockedElement)
			{
				oThis.Control.HtmlElement.style.backgroundPosition = oThis.state_over;
			}
			else
			{
				if (null != global_mouseEvent.buttonObject)
					global_mouseEvent.buttonObject.Control.HtmlElement.style.backgroundPosition = global_mouseEvent.buttonObject.state_normal;

				if ((global_mouseEvent.buttonObject == null) || (oThis.Control.HtmlElement.id != global_mouseEvent.buttonObject.Control.HtmlElement.id))
					oThis.Control.HtmlElement.style.backgroundPosition = oThis.state_over;
			}
			global_mouseEvent.buttonObject = null;
		}

		// теперь touch
		this.Control.HtmlElement.ontouchstart = function(e)
		{
			oThis.Control.HtmlElement.onmousedown(e.touches[0]);
			return false;
		}
		this.Control.HtmlElement.ontouchend   = function(e)
		{
			var lockedElement = check_MouseUpEvent(e.changedTouches[0]);

			if (null != lockedElement)
			{
				oThis.Click_func();
				oThis.Control.HtmlElement.style.backgroundPosition = oThis.state_normal;
			}
			else
			{
				if (null != global_mouseEvent.buttonObject)
					global_mouseEvent.buttonObject.Control.HtmlElement.style.backgroundPosition = global_mouseEvent.buttonObject.state_normal;

				if (oThis.Control.HtmlElement.id != global_mouseEvent.buttonObject.Control.HtmlElement.id)
					oThis.Control.HtmlElement.style.backgroundPosition = oThis.state_normal;
			}
			global_mouseEvent.buttonObject = null;
			return false;
		}
	}

	function emulateKeyDown(_code, _element)
	{
		var oEvent = document.createEvent('KeyboardEvent');

		// Chromium Hack
		Object.defineProperty(oEvent, 'keyCode', {
			get : function()
			{
				return this.keyCodeVal;
			}
		});
		Object.defineProperty(oEvent, 'which', {
			get : function()
			{
				return this.keyCodeVal;
			}
		});
		Object.defineProperty(oEvent, 'shiftKey', {
			get : function()
			{
				return false;
			}
		});
		Object.defineProperty(oEvent, 'altKey', {
			get : function()
			{
				return false;
			}
		});
		Object.defineProperty(oEvent, 'metaKey', {
			get : function()
			{
				return false;
			}
		});
		Object.defineProperty(oEvent, 'ctrlKey', {
			get : function()
			{
				return false;
			}
		});

		if (AscCommon.AscBrowser.isIE)
		{
			oEvent.preventDefault = function () {
				Object.defineProperty(this, "defaultPrevented", {get: function () {return true;}});
			};
		}

		if (oEvent.initKeyboardEvent)
		{
			oEvent.initKeyboardEvent("keydown", true, true, window, false, false, false, false, _code, _code);
		}
		else
		{
			oEvent.initKeyEvent("keydown", true, true, window, false, false, false, false, _code, 0);
		}

		oEvent.keyCodeVal = _code;

		_element.dispatchEvent(oEvent);
		return oEvent.defaultPrevented;
	}

	//--------------------------------------------------------export----------------------------------------------------
	window['AscCommon']                          = window['AscCommon'] || {};
	window['AscCommon'].g_mouse_event_type_down  = g_mouse_event_type_down;
	window['AscCommon'].g_mouse_event_type_move  = g_mouse_event_type_move;
	window['AscCommon'].g_mouse_event_type_up    = g_mouse_event_type_up;
	window['AscCommon'].g_mouse_button_left      = g_mouse_button_left;
	window['AscCommon'].g_mouse_button_center    = g_mouse_button_center;
	window['AscCommon'].g_mouse_button_right     = g_mouse_button_right;
	window['AscCommon'].MouseUpLock              = MouseUpLock;
	window['AscCommon'].CMouseEventHandler       = CMouseEventHandler;
	window['AscCommon'].CKeyboardEvent           = CKeyboardEvent;
	window['AscCommon'].global_mouseEvent        = global_mouseEvent;
	window['AscCommon'].global_keyboardEvent     = global_keyboardEvent;
	window['AscCommon'].check_KeyboardEvent      = check_KeyboardEvent;
	window['AscCommon'].check_KeyboardEvent2     = check_KeyboardEvent2;
	window['AscCommon'].check_MouseMoveEvent     = check_MouseMoveEvent;
	window['AscCommon'].CreateMouseUpEventObject = CreateMouseUpEventObject;
	window['AscCommon'].check_MouseUpEvent       = check_MouseUpEvent;
	window['AscCommon'].check_MouseDownEvent     = check_MouseDownEvent;
	window['AscCommon'].Window_OnMouseUp         = Window_OnMouseUp;
	window['AscCommon'].button_eventHandlers     = button_eventHandlers;
	window['AscCommon'].emulateKeyDown 			 = emulateKeyDown;

})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function (window, undefined) {

function CHistory(Document)
{
    this.Index      = -1;
    this.SavedIndex = null;        // Номер точки отката, на которой произошло последнее сохранение
    this.ForceSave  = false;       // Нужно сохранение, случается, когда у нас точка SavedIndex смещается из-за объединения точек, и мы делаем Undo
    this.RecIndex   = -1;          // Номер точки, на которой произошел последний пересчет
    this.Points     = [];          // Точки истории, в каждой хранится массив с изменениями после текущей точки
    this.Document   = Document;
    this.Api                  = null;
    this.CollaborativeEditing = null;
    this.CanNotAddChanges = false; // флаг для отслеживания ошибок добавления изменений без точки:Create_NewPoint->Add->Save_Changes->Add
	this.CollectChanges   = false;

	this.RecalculateData =
	{
		Inline       : {
			Pos     : -1,
			PageNum : 0
		},
		Flow         : [],
		HdrFtr       : [],
		Drawings     : {
			All       : false,
			Map       : {},
			ThemeInfo : null
		},
		Tables       : [],
		NumPr        : [],
		NotesEnd     : false,
		NotesEndPage : 0,
		Update       : true
	};

	this.TurnOffHistory = 0;
    this.MinorChanges   = false; // Данный параметр нужен, чтобы определить влияют ли добавленные изменения на пересчет

    this.BinaryWriter = new AscCommon.CMemory();

    this.FileCheckSum = 0;
    this.FileSize     = 0;

    // Параметры для специального сохранения для локальной версии редактора
    this.UserSaveMode   = false;
    this.UserSavedIndex = null;  // Номер точки, на которой произошло последнее сохранение пользователем (не автосохранение)

	this.StoredData = [];
}

CHistory.prototype =
{
    Set_LogicDocument : function(LogicDocument)
    {
        if (!LogicDocument)
            return;

        this.Document             = LogicDocument;
        this.Api                  = LogicDocument.Get_Api();
        this.CollaborativeEditing = LogicDocument.Get_CollaborativeEditing();
    },

    Is_UserSaveMode : function()
    {
        return this.UserSaveMode;
    },

    Update_FileDescription : function(oStream)
    {
        var pData = oStream.data;
        var nSize = oStream.size;

        this.FileCheckSum = g_oCRC32.Calculate_ByByteArray(pData, nSize);
        this.FileSize     = nSize;
    },

	Update_PointInfoItem : function(PointIndex, StartPoint, LastPoint, SumIndex, DeletedIndex)
	{
		var Point = this.Points[PointIndex];
		if (Point)
		{
			// Проверяем первое изменение. Если оно уже нужного типа, тогда мы его удаляем. Добавляем специфическое
			// первое изменение с описанием.
			var Class = AscCommon.g_oTableId;

			if (Point.Items.length > 0)
			{
				var FirstItem = Point.Items[0];
				if (FirstItem.Class === Class && AscDFH.historyitem_TableId_Description === FirstItem.Data.Type)
					Point.Items.splice(0, 1);
			}

			var Data = new AscCommon.CChangesTableIdDescription(Class,
				this.FileCheckSum,
				this.FileSize,
				Point.Description,
				Point.Items.length,
				PointIndex,
				StartPoint,
				LastPoint,
				SumIndex,
				DeletedIndex
			);

			var Binary_Pos = this.BinaryWriter.GetCurPosition();
			this.BinaryWriter.WriteString2(Class.Get_Id());
			this.BinaryWriter.WriteLong(Data.Type);
			Data.WriteToBinary(this.BinaryWriter);

			var Binary_Len = this.BinaryWriter.GetCurPosition() - Binary_Pos;

			var Item = {
				Class  : Class,
				Data   : Data,
				Binary : {
					Pos : Binary_Pos,
					Len : Binary_Len
				},

				NeedRecalc : false
			};

			Point.Items.splice(0, 0, Item);
		}
	},

    Is_Clear : function()
    {
        if ( this.Points.length <= 0 )
            return true;

        return false;
    },

    Clear : function()
    {
        this.Index          = -1;
        this.SavedIndex     = null;
        this.ForceSave      = false;
        this.UserSavedIndex = null;
        this.Points.length  = 0;
		this.TurnOffHistory = 0;
        this.private_ClearRecalcData();
    },

    Can_Undo : function()
    {
        if ( this.Index >= 0 )
            return true;

        return false;
    },

    Can_Redo : function()
    {
        if ( this.Points.length > 0 && this.Index < this.Points.length - 1 )
            return true;

        return false;
    },

    UndoLastPoint : function(nBottomIndex)
    {
        var oPoint = this.Points[this.Index];
        if(oPoint)
        {
            var aItems = oPoint.Items;
            var _bottomIndex;
            if(AscFormat.isRealNumber(nBottomIndex))
            {
                _bottomIndex = nBottomIndex - 1;
            }
            else
            {
                _bottomIndex = -1;
            }
            for (var i = aItems.length - 1; i > _bottomIndex; i--)
            {
                var oItem = aItems[i];
                oItem.Data.Undo();
            }
            oPoint.Items.length = _bottomIndex + 1;
            this.Document.SetSelectionState( oPoint.State );
        }
    },

    Undo : function(Options)
    {
        this.CheckUnionLastPoints();

        // Проверяем можно ли сделать Undo
        if (true !== this.Can_Undo())
            return null;

        // Запоминаем самое последнее состояние документа для Redo
        if ( this.Index === this.Points.length - 1 )
            this.LastState = this.Document.GetSelectionState();
        
        this.Document.RemoveSelection(true);

        this.private_ClearRecalcData();

        var Point = null;
        if (undefined !== Options && null !== Options && true === Options.All)
        {
            while (this.Index >= 0)
            {
                Point = this.Points[this.Index--];

                // Откатываем все действия в обратном порядке (относительно их выполенения)
                for (var Index = Point.Items.length - 1; Index >= 0; Index--)
                {
                    var Item = Point.Items[Index];

					if (Item.Data)
					{
						Item.Data.Undo();
						Item.Data.RefreshRecalcData();
					}
                    this.private_UpdateContentChangesOnUndo(Item);
                }
            }
        }
        else
        {
            Point = this.Points[this.Index--];

            // Откатываем все действия в обратном порядке (относительно их выполенения)
            for (var Index = Point.Items.length - 1; Index >= 0; Index--)
            {
                var Item = Point.Items[Index];
				if (Item.Data)
				{
					Item.Data.Undo();
					Item.Data.RefreshRecalcData();
				}
				this.private_UpdateContentChangesOnUndo(Item);
            }
        }

		this.private_PostProcessingRecalcData();

        if (null != Point)
            this.Document.SetSelectionState( Point.State );
		
		if(!window['AscCommon'].g_specialPasteHelper.pasteStart)
		{
			window['AscCommon'].g_specialPasteHelper.SpecialPasteButton_Hide();
		}
		
        return this.RecalculateData;
    },

    Redo : function()
    {
        // Проверяем можно ли сделать Redo
        if ( true != this.Can_Redo() )
            return null;

        this.Document.RemoveSelection(true);
        
        var Point = this.Points[++this.Index];

        this.private_ClearRecalcData();

        // Выполняем все действия в прямом порядке
        for ( var Index = 0; Index < Point.Items.length; Index++ )
        {
            var Item = Point.Items[Index];

			if (Item.Data)
			{
				Item.Data.Redo();
				Item.Data.RefreshRecalcData();
			}
			this.private_UpdateContentChangesOnRedo(Item);
        }

        this.private_PostProcessingRecalcData();

        // Восстанавливаем состояние на следующую точку
        var State = null;
        if ( this.Index === this.Points.length - 1 )
            State = this.LastState;
        else
            State = this.Points[this.Index + 1].State;

        this.Document.SetSelectionState( State );
		
		if(!window['AscCommon'].g_specialPasteHelper.pasteStart)
		{
			window['AscCommon'].g_specialPasteHelper.SpecialPasteButton_Hide();
		}
		
        return this.RecalculateData;
    },

    Create_NewPoint : function(Description)
    {
		if ( 0 !== this.TurnOffHistory )
			return;

		if (this.Document && this.Document.OnCreateNewHistoryPoint)
			this.Document.OnCreateNewHistoryPoint();

        this.CanNotAddChanges = false;
		this.CollectChanges   = false;

		if (null !== this.SavedIndex && this.Index < this.SavedIndex)
            this.Set_SavedIndex(this.Index);

        this.Clear_Additional();

        this.CheckUnionLastPoints();
        
        var State = this.Document.GetSelectionState();
        var Items = [];
        var Time  = new Date().getTime();

        // Создаем новую точку
        this.Points[++this.Index] =
        {
            State      : State, // Текущее состояние документа (курсор, селект)
            Items      : Items, // Массив изменений, начиная с текущего момента
            Time       : Time,  // Текущее время
            Additional : {},    // Дополнительная информация
            Description: Description
        };

        // Удаляем ненужные точки
        this.Points.length = this.Index + 1;
		
		if(!window['AscCommon'].g_specialPasteHelper.pasteStart)
		{
			window['AscCommon'].g_specialPasteHelper.SpecialPasteButton_Hide();
		}
    },

	/**
	 * Специальная функция, для создания точки, чтобы отловить все изменения, которые происходят. После использования
	 * данная точка ДОЛЖНА быть удалена через функцию Remove_LastPoint.
	 */
	CreateNewPointForCollectChanges : function()
	{
		this.Points[++this.Index] = {
			State       : null,
			Items       : [],
			Time        : null,
			Additional  : {},
			Description : -1
		};

		this.Points.length  = this.Index + 1;
		this.CollectChanges = true;
	},
    
    Remove_LastPoint : function()
    {
		this.CollectChanges = false;
        this.Index--;
        this.Points.length = this.Index + 1;
    },

    Is_LastPointEmpty : function()
    {
        if (!this.Points[this.Index] || this.Points[this.Index].Items.length <= 0)
            return true;

        return false;
    },

    Is_LastPointNeedRecalc : function()
    {
        if (!this.Points[this.Index])
            return false;

        var RecalcData = this.Get_RecalcData();
        if (RecalcData.Flow.length > 0 || RecalcData.HdrFtr.length > 0 || -1 !== RecalcData.Inline.Pos || true === RecalcData.Drawings.All)
            return true;

        for(var Key in RecalcData.Drawings.Map)
        {
            if(null != AscCommon.g_oTableId.Get_ById(Key))
            {
                return true;
            }
        }

        return false;
    },

    Clear_Redo : function()
    {
        // Удаляем ненужные точки
        this.Points.length = this.Index + 1;
    },

    // Регистрируем новое изменение:
    // Class - объект, в котором оно произошло
    // Data  - сами изменения
	Add : function(_Class, Data)
	{
		if (0 !== this.TurnOffHistory || this.Index < 0)
			return;

		this._CheckCanNotAddChanges();

		// Заглушка на случай, если у нас во время создания одной точки в истории, после нескольких изменений идет
		// пересчет, потом снова добавляются изменения и снова запускается пересчет и т.д.
		if (this.RecIndex >= this.Index)
			this.RecIndex = this.Index - 1;

		var Binary_Pos = this.BinaryWriter.GetCurPosition();

		var Class;
		if (_Class) {
            Class = _Class.GetClass();
            Data = _Class;

            this.BinaryWriter.WriteString2(Class.Get_Id());
            this.BinaryWriter.WriteLong(_Class.Type);
            _Class.WriteToBinary(this.BinaryWriter);
        }

        if (Class && Class.SetIsRecalculated)
        	Class.SetIsRecalculated(false);

		var Binary_Len = this.BinaryWriter.GetCurPosition() - Binary_Pos;
		var Item       = {
			Class  : Class,
			Data   : Data,
			Binary : {
				Pos : Binary_Pos,
				Len : Binary_Len
			},

			NeedRecalc : !this.MinorChanges
		};

		this.Points[this.Index].Items.push(Item);

		if (!this.CollaborativeEditing)
			return;

		if (_Class)
		{
			if (_Class.IsContentChange())
			{
				var bAdd  = _Class.IsAdd();
				var Count = _Class.GetItemsCount();

				var ContentChanges = new AscCommon.CContentChangesElement(bAdd == true ? AscCommon.contentchanges_Add : AscCommon.contentchanges_Remove, Data.Pos, Count, Item);
				Class.Add_ContentChanges(ContentChanges);
				this.CollaborativeEditing.Add_NewDC(Class);

				if (true === bAdd)
					this.CollaborativeEditing.Update_DocumentPositionsOnAdd(Class, Data.Pos);
				else
					this.CollaborativeEditing.Update_DocumentPositionsOnRemove(Class, Data.Pos, Count);
			}
		    if(_Class.IsPosExtChange()){
                this.CollaborativeEditing.AddPosExtChanges(Item, _Class);
            }
		}
	},

    RecalcData_Add : function(Data)
    {
        if (true !== this.RecalculateData.Update)
            return;

        if ( "undefined" === typeof(Data) || null === Data )
            return;

        switch ( Data.Type )
        {
            case AscDFH.historyitem_recalctype_Flow:
            {
                var bNew = true;
                for ( var Index = 0; Index < this.RecalculateData.Flow.length; Index++ )
                {
                    if ( this.RecalculateData.Flow[Index] === Data.Data )
                    {
                        bNew = false;
                        break;
                    }
                }

                if ( true === bNew )
                    this.RecalculateData.Flow.push( Data.Data );

                break;
            }

            case AscDFH.historyitem_recalctype_HdrFtr:
            {
                if ( null === Data.Data )
                    break;

                var bNew = true;
                for ( var Index = 0; Index < this.RecalculateData.HdrFtr.length; Index++ )
                {
                    if ( this.RecalculateData.HdrFtr[Index] === Data.Data )
                    {
                        bNew = false;
                        break;
                    }
                }

                if ( true === bNew )
                    this.RecalculateData.HdrFtr.push( Data.Data );

                break
            }

            case AscDFH.historyitem_recalctype_Inline:
            {
                if ( (Data.Data.Pos < this.RecalculateData.Inline.Pos) || (Data.Data.Pos === this.RecalculateData.Inline.Pos && Data.Data.PageNum < this.RecalculateData.Inline.PageNum) || this.RecalculateData.Inline.Pos < 0 )
                {
                    this.RecalculateData.Inline.Pos     = Data.Data.Pos;
                    this.RecalculateData.Inline.PageNum = Data.Data.PageNum;
                }

                break;
            }
            case AscDFH.historyitem_recalctype_Drawing:
            {
                if(!this.RecalculateData.Drawings.All)
                {
                    if(Data.All)
                    {
                        this.RecalculateData.Drawings.All = true;
                    }
                    else
                    {
                        if(Data.Theme)
                        {
                            this.RecalculateData.Drawings.ThemeInfo =
                            {
                                Theme: true,
                                ArrInd: Data.ArrInd
                            }
                        }
                        else if(Data.ColorScheme)
                        {
                            this.RecalculateData.Drawings.ThemeInfo =
                            {
                                ColorScheme: true,
                                ArrInd: Data.ArrInd
                            }
                        }
                        else
                        {
                            this.RecalculateData.Drawings.Map[Data.Object.Get_Id()] = Data.Object;
                        }
                    }
                }
                break;
            }

			case AscDFH.historyitem_recalctype_NotesEnd:
			{
				this.RecalculateData.NotesEnd     = true;
				this.RecalculateData.NotesEndPage = Data.PageNum;
				break;
			}
        }
    },

	AddChangedStyleToRecalculateData : function(sId, oStyle)
	{
		if (!this.RecalculateData.ChangedStyles)
			this.RecalculateData.ChangedStyles = {};

		if (this.RecalculateData.ChangedStyles[sId] === oStyle)
			return false;

		this.RecalculateData.ChangedStyles[sId] = oStyle;
		return true;
	},

	AddChangedNumberingToRecalculateData : function(NumId, Lvl, oNum)
	{
		if (!this.RecalculateData.ChangedNums)
			this.RecalculateData.ChangedNums = {};

		if (!this.RecalculateData.ChangedNums[NumId])
			this.RecalculateData.ChangedNums[NumId] = {};

		if (this.RecalculateData.ChangedNums[NumId][Lvl] === oNum)
			return false;

		this.RecalculateData.ChangedNums[NumId][Lvl] = oNum;
		return true;
	},

    Add_RecalcNumPr : function(NumPr)
    {
        if (undefined !== NumPr && null !== NumPr && undefined !== NumPr.NumId)
            this.RecalculateData.NumPr[NumPr.NumId] = true;
    },

    Add_RecalcTableGrid : function(TableId)
    {
        this.RecalculateData.Tables[TableId] = true;
    },

    OnEnd_GetRecalcData : function()
    {
        // Пересчитываем таблицы
        for (var TableId in this.RecalculateData.Tables)
        {
            var Table = AscCommon.g_oTableId.Get_ById(TableId);
            if (null !== Table && Table.Is_UseInDocument())
            {
                if (true === Table.Check_ChangedTableGrid())
                {
                    Table.Refresh_RecalcData2(0, 0);
                }
            }
        }

        // Делаем это, чтобы пересчитались ячейки таблиц, в которых есть заданная нумерация. Но нам не нужно менять
        // начальную точку пересчета здесь, т.к. начальная точка уже рассчитана правильно.
        this.RecalculateData.Update = false;
        for (var NumId in this.RecalculateData.NumPr)
        {
            var NumPr = new CNumPr();
            NumPr.NumId = NumId;
            for (var Lvl = 0; Lvl < 9; ++Lvl)
            {
                NumPr.Lvl = Lvl;
                var AllParagraphs = this.Document.GetAllParagraphsByNumbering(NumPr);
                var Count = AllParagraphs.length;
                for (var Index = 0; Index < Count; ++Index)
                {
                    var Para = AllParagraphs[Index];
                    Para.Refresh_RecalcData2(0);
                }
            }
        }
        this.RecalculateData.NumPr = [];
        this.RecalculateData.Update = true;
    },

	CheckUnionLastPoints : function()
    {
        // Не объединяем точки в истории, когда отключается пересчет.
        // TODO: Неправильно изменяется RecalcIndex
        if (true !== this.Document.Is_OnRecalculate())
            return false;

        // Не объединяем точки истории, если на предыдущей точке произошло сохранение
        if (this.Points.length < 2
            || (true !== this.Is_UserSaveMode() && null !== this.SavedIndex && this.SavedIndex >= this.Points.length - 2)
            || (true === this.Is_UserSaveMode() && null !== this.UserSavedIndex && this.UserSavedIndex >= this.Points.length - 2))
            return false;

        var Point1 = this.Points[this.Points.length - 2];
        var Point2 = this.Points[this.Points.length - 1];

        // Не объединяем слова больше 63 элементов
        if (Point1.Items.length > 63 && AscDFH.historydescription_Document_AddLetterUnion === Point1.Description)
            return false;

        var StartIndex1 = 0;
        var StartIndex2 = 0;
        if (Point1.Items.length > 0 && Point1.Items[0].Data && AscDFH.historyitem_TableId_Description === Point1.Items[0].Data.Type)
            StartIndex1 = 1;

        if (Point2.Items.length > 0 && Point2.Items[0].Data && AscDFH.historyitem_TableId_Description === Point2.Items[0].Data.Type)
            StartIndex2 = 1;

        var NewDescription;
        if ((AscDFH.historydescription_Document_CompositeInput === Point1.Description || AscDFH.historydescription_Document_CompositeInputReplace === Point1.Description)
            && AscDFH.historydescription_Document_CompositeInputReplace === Point2.Description)
        {
            // Ничего не делаем. Эта ветка означает, что эти две точки можно объединить
            NewDescription = AscDFH.historydescription_Document_CompositeInput;
        }
        else
        {
            var PrevItem = null;
            var Class    = null;
            for (var Index = StartIndex1; Index < Point1.Items.length; Index++)
            {
                var Item = Point1.Items[Index];

                if (null === Class)
                    Class = Item.Class;
                else if (Class != Item.Class || "undefined" === typeof(Class.Check_HistoryUninon) || false === Class.Check_HistoryUninon(PrevItem.Data, Item.Data))
                    return;

                PrevItem = Item;
            }

            for (var Index = StartIndex2; Index < Point2.Items.length; Index++)
            {
                var Item = Point2.Items[Index];

                if (Class != Item.Class || "undefined" === typeof(Class.Check_HistoryUninon) || false === Class.Check_HistoryUninon(PrevItem.Data, Item.Data))
                    return;

                PrevItem = Item;
            }

            NewDescription = AscDFH.historydescription_Document_AddLetterUnion;
        }

        if (0 !== StartIndex1)
            Point1.Items.splice(0, 1);

        if (0 !== StartIndex2)
            Point2.Items.splice(0, 1);

        var NewPoint =
        {
            State      : Point1.State,
            Items      : Point1.Items.concat(Point2.Items),
            Time       : Point1.Time,
            Additional : {},
            Description: NewDescription
        };

		if (null !== this.SavedIndex && this.SavedIndex >= this.Points.length - 2)
            this.Set_SavedIndex(this.Points.length - 3);

        this.Points.splice( this.Points.length - 2, 2, NewPoint );
        if ( this.Index >= this.Points.length )
        {
            var DiffIndex = -this.Index + (this.Points.length - 1);
            this.Index    += DiffIndex;
            this.RecIndex  = Math.max( -1, this.RecIndex + DiffIndex);
        }

        return true;
	},

    CanRemoveLastPoint : function()
    {
        if (this.Points.length <= 0
            || (true !== this.Is_UserSaveMode() && null !== this.SavedIndex && this.SavedIndex >= this.Points.length - 1)
            || (true === this.Is_UserSaveMode() && null !== this.UserSavedIndex && this.UserSavedIndex >= this.Points.length - 1))
            return false;

        return true;
    },

    TurnOff : function()
    {
		this.TurnOffHistory++;
    },

    TurnOn : function()
    {
		this.TurnOffHistory--;
		if(this.TurnOffHistory < 0)
			this.TurnOffHistory = 0;
    },

	/** @returns {boolean} */
    Is_On : function()
    {
		return (0 === this.TurnOffHistory);
    },

	Reset_SavedIndex : function(IsUserSave)
	{
		this.SavedIndex = (null === this.SavedIndex && -1 === this.Index ? null : this.Index);
		if (true === this.Is_UserSaveMode())
		{
			if (true === IsUserSave)
			{
				this.UserSavedIndex = this.Index;
				this.ForceSave      = false;
			}
		}
		else
		{
			this.ForceSave = false;
		}
	},

    Set_SavedIndex : function(Index)
    {
      this.SavedIndex = Index;
      if (true === this.Is_UserSaveMode()) {
        if (null !== this.UserSavedIndex && this.UserSavedIndex > this.SavedIndex) {
          this.UserSavedIndex = Index;
          this.ForceSave = true;
        }
      } else {
        this.ForceSave = true;
      }
    },

	Have_Changes : function(IsNotUserSave)
	{
		if (!this.Document || this.Document.IsViewModeInReview())
			return false;

		var checkIndex = (this.Is_UserSaveMode() && !IsNotUserSave) ? this.UserSavedIndex : this.SavedIndex;
		if (-1 === this.Index && null === checkIndex && false === this.ForceSave)
			return false;

		if (this.Index != checkIndex || true === this.ForceSave)
			return true;

		return false;
	},

    Get_RecalcData : function(RecalcData, arrChanges)
    {
        if (RecalcData)
        {
            this.RecalculateData = RecalcData;
        }
        else if (arrChanges)
		{
			this.private_ClearRecalcData();
			for (var nIndex = 0, nCount = arrChanges.length; nIndex < nCount; ++nIndex)
			{
				var oChange = arrChanges[nIndex];
				oChange.RefreshRecalcData();
			}
			this.private_PostProcessingRecalcData();
		}
        else
        {
            if (this.Index >= 0)
            {
                this.private_ClearRecalcData();

                for (var Pos = this.RecIndex + 1; Pos <= this.Index; Pos++)
                {
                    // Считываем изменения, начиная с последней точки, и смотрим что надо пересчитать.
                    var Point = this.Points[Pos];

                    // Выполняем все действия в прямом порядке
                    for (var Index = 0; Index < Point.Items.length; Index++)
                    {
                        var Item = Point.Items[Index];

                        if (true === Item.NeedRecalc)
                            Item.Class.Refresh_RecalcData(Item.Data);
                    }
                }

                this.private_PostProcessingRecalcData();
            }
        }

        this.OnEnd_GetRecalcData();
        return this.RecalculateData;
    },

    Reset_RecalcIndex : function()
    {
        this.RecIndex = this.Index;
    },

    Is_SimpleChanges : function()
    {
        var Count, Items;
        if (this.Index - this.RecIndex !== 1 && this.RecIndex >= -1)
        {
            Items = [];
            Count = 0;
            for (var PointIndex = this.RecIndex + 1; PointIndex <= this.Index; PointIndex++)
            {
                Items = Items.concat(this.Points[PointIndex].Items);
                Count += this.Points[PointIndex].Items.length;
            }
        }
        else if (this.Index >= 0)
        {
            // Считываем изменения, начиная с последней точки, и смотрим что надо пересчитать.
            var Point = this.Points[this.Index];

            Count = Point.Items.length;
            Items = Point.Items;
        }
        else
            return [];
        

        if (Items.length > 0)
        {
            var Class = Items[0].Class;
            // Смотрим, чтобы класс, в котором произошли все изменения был один и тот же
            for (var Index = 1; Index < Count; Index++)
            {
                var Item = Items[Index];

                if (Class !== Item.Class)
                    return [];
            }

            if (Class instanceof ParaRun && Class.Is_SimpleChanges(Items))
                return [Items[0]];
        }

        return [];
    },

    Set_Additional_ExtendDocumentToPos : function()
    {
        if ( this.Index >= 0 )
        {
            this.Points[this.Index].Additional.ExtendDocumentToPos = true;
        }
    },

    Is_ExtendDocumentToPos : function()
    {
        if ( undefined === this.Points[this.Index] || undefined === this.Points[this.Index].Additional || undefined === this.Points[this.Index].Additional.ExtendDocumentToPos )
            return false;

        return true;
    },

    Clear_Additional : function()
    {
        if ( this.Index >= 0 )
        {
            this.Points[this.Index].Additional = {};
        }

        if (this.Api && true === this.Api.isMarkerFormat)
            this.Api.sync_MarkerFormatCallback(false);
    },

    Get_EditingTime : function(dTime)
    {
        var Count = this.Points.length;

        var TimeLine = [];
        for ( var Index = 0; Index < Count; Index++ )
        {
            var PointTime = this.Points[Index].Time;
            TimeLine.push( { t0 : PointTime - dTime, t1 : PointTime } );
        }

        Count = TimeLine.length;
        for ( var Index = 1; Index < Count; Index++ )
        {
            var CurrEl = TimeLine[Index];
            var PrevEl = TimeLine[Index - 1];
            if ( CurrEl.t0 <= PrevEl.t1 )
            {
                PrevEl.t1 = CurrEl.t1;
                TimeLine.splice( Index, 1 );
                Index--;
                Count--;
            }
        }

        Count = TimeLine.length;
        var OverallTime = 0;
        for ( var Index = 0; Index < Count; Index++ )
        {
            OverallTime += TimeLine[Index].t1 - TimeLine[Index].t0;
        }

        return OverallTime;
    },

    Get_DocumentPositionBinary : function()
    {
        var PosInfo = this.Document.Get_DocumentPositionInfoForCollaborative();
        if (!PosInfo)
            return null;
        var BinaryPos = this.BinaryWriter.GetCurPosition();
        this.BinaryWriter.WriteString2(PosInfo.Class.Get_Id());
        this.BinaryWriter.WriteLong(PosInfo.Position);
        var BinaryLen = this.BinaryWriter.GetCurPosition() - BinaryPos;
        return  (BinaryLen + ";" + this.BinaryWriter.GetBase64Memory2(BinaryPos, BinaryLen));
    },

    _CheckCanNotAddChanges : function() {
        try {
            if (this.CanNotAddChanges && this.Api && !this.CollectChanges) {
                var tmpErr = new Error();
                if (tmpErr.stack) {
                    this.Api.CoAuthoringApi.sendChangesError(tmpErr.stack);
                }
            }
        } catch (e) {
        }
    }
};
CHistory.prototype.private_UpdateContentChangesOnUndo = function(Item)
{
	if (this.private_IsContentChange(Item.Class, Item.Data))
	{
		Item.Class.m_oContentChanges.RemoveByHistoryItem(Item);
	}
};
CHistory.prototype.private_UpdateContentChangesOnRedo = function(Item)
{
	if (this.private_IsContentChange(Item.Class, Item.Data))
	{
		var bAdd  = this.private_IsAddContentChange(Item.Class, Item.Data);
		var Count = this.private_GetItemsCountInContentChange(Item.Class, Item.Data);

		var ContentChanges = new AscCommon.CContentChangesElement(( bAdd == true ? AscCommon.contentchanges_Add : AscCommon.contentchanges_Remove ), Item.Data.Pos, Count, Item);
		Item.Class.Add_ContentChanges(ContentChanges);
		this.CollaborativeEditing.Add_NewDC(Item.Class);
	}
};
CHistory.prototype.private_IsContentChange = function(Class, Data)
{
	var bPresentation = !(typeof CPresentation === "undefined");
	var bSlide = !(typeof Slide === "undefined");
	if ( ( Class instanceof CDocument        && ( AscDFH.historyitem_Document_AddItem        === Data.Type || AscDFH.historyitem_Document_RemoveItem        === Data.Type ) ) ||
		(((Class instanceof CDocumentContent || Class instanceof AscFormat.CDrawingDocContent)) && ( AscDFH.historyitem_DocumentContent_AddItem === Data.Type || AscDFH.historyitem_DocumentContent_RemoveItem === Data.Type ) ) ||
		( Class instanceof CTable           && ( AscDFH.historyitem_Table_AddRow            === Data.Type || AscDFH.historyitem_Table_RemoveRow            === Data.Type ) ) ||
		( Class instanceof CTableRow        && ( AscDFH.historyitem_TableRow_AddCell        === Data.Type || AscDFH.historyitem_TableRow_RemoveCell        === Data.Type ) ) ||
		( Class instanceof Paragraph        && ( AscDFH.historyitem_Paragraph_AddItem       === Data.Type || AscDFH.historyitem_Paragraph_RemoveItem       === Data.Type ) ) ||
		( Class instanceof ParaHyperlink    && ( AscDFH.historyitem_Hyperlink_AddItem       === Data.Type || AscDFH.historyitem_Hyperlink_RemoveItem       === Data.Type ) ) ||
		( Class instanceof ParaRun          && ( AscDFH.historyitem_ParaRun_AddItem         === Data.Type || AscDFH.historyitem_ParaRun_RemoveItem         === Data.Type ) ) ||
		( bPresentation && Class instanceof CPresentation && (AscDFH.historyitem_Presentation_AddSlide === Data.Type || AscDFH.historyitem_Presentation_RemoveSlide === Data.Type)) ||
		( bSlide && Class instanceof Slide && (AscDFH.historyitem_SlideAddToSpTree === Data.Type || AscDFH.historyitem_SlideRemoveFromSpTree === Data.Type))
	)
		return true;

	return false;
};
CHistory.prototype.private_IsAddContentChange = function(Class, Data)
{
	var bPresentation = !(typeof CPresentation === "undefined");
	var bSlide = !(typeof Slide === "undefined");
	return ( ( Class instanceof CDocument        && AscDFH.historyitem_Document_AddItem        === Data.Type ) ||
		( ((Class instanceof CDocumentContent || Class instanceof AscFormat.CDrawingDocContent)) && AscDFH.historyitem_DocumentContent_AddItem === Data.Type ) ||
		( Class instanceof CTable           && AscDFH.historyitem_Table_AddRow            === Data.Type ) ||
		( Class instanceof CTableRow        && AscDFH.historyitem_TableRow_AddCell        === Data.Type ) ||
		( Class instanceof Paragraph        && AscDFH.historyitem_Paragraph_AddItem       === Data.Type ) ||
		( Class instanceof ParaHyperlink    && AscDFH.historyitem_Hyperlink_AddItem       === Data.Type ) ||
		( Class instanceof ParaRun          && AscDFH.historyitem_ParaRun_AddItem         === Data.Type ) ||
		( bPresentation && Class instanceof CPresentation && (AscDFH.historyitem_Presentation_AddSlide === Data.Type )) ||
		( bSlide && Class instanceof Slide && (AscDFH.historyitem_SlideAddToSpTree === Data.Type))
	) ? true : false;
};
CHistory.prototype.private_GetItemsCountInContentChange = function(Class, Data)
{
	if ( ( Class instanceof Paragraph ) ||  ( Class instanceof ParaHyperlink) || ( Class instanceof ParaRun ) ||
		( Class instanceof CDocument        && AscDFH.historyitem_Document_RemoveItem        === Data.Type ) ||
		( ((Class instanceof CDocumentContent || Class instanceof AscFormat.CDrawingDocContent)) && AscDFH.historyitem_DocumentContent_RemoveItem === Data.Type ) )
		return Data.Items.length;

	return 1;
};
CHistory.prototype.GetAllParagraphsForRecalcData = function(Props)
{
	if (!this.RecalculateData.AllParagraphs)
	{
		if (this.Document)
			this.RecalculateData.AllParagraphs = this.Document.GetAllParagraphs({All : true});
		else
			this.RecalculateData.AllParagraphs = [];
	}

	var arrParagraphs = [];
	if (!Props || true === Props.All)
	{
		return this.RecalculateData.AllParagraphs;
	}
	else if (true === Props.Style)
	{
		var arrStylesId = Props.StylesId;
		for (var nParaIndex = 0, nParasCount = this.RecalculateData.AllParagraphs.length; nParaIndex < nParasCount; ++nParaIndex)
		{
			var oPara = this.RecalculateData.AllParagraphs[nParaIndex];
			for (var nStyleIndex = 0, nStylesCount = arrStylesId.length; nStyleIndex < nStylesCount; ++nStyleIndex)
			{
				if (oPara.Pr.PStyle === arrStylesId[nStyleIndex])
				{
					arrParagraphs.push(oPara);
					break;
				}
			}
		}
	}
	else if (true === Props.Numbering)
	{
		for (var nParaIndex = 0, nParasCount = this.RecalculateData.AllParagraphs.length; nParaIndex < nParasCount; ++nParaIndex)
		{
			var oPara = this.RecalculateData.AllParagraphs[nParaIndex];

			var NumPr  = Props.NumPr;
			var _NumPr = oPara.GetNumPr();

			if (undefined != _NumPr && _NumPr.NumId === NumPr.NumId && (_NumPr.Lvl === NumPr.Lvl || undefined === NumPr.Lvl))
				arrParagraphs.push(oPara);
		}
	}
	return arrParagraphs;
};
CHistory.prototype.GetRecalculateIndex = function()
{
	return this.RecIndex;
};
CHistory.prototype.SetRecalculateIndex = function(nIndex)
{
	this.RecIndex = Math.min(this.Index, nIndex);
};
CHistory.prototype.SaveRedoPoints = function()
{
	var arrData = [];
	this.StoredData.push(arrData);
	for (var nIndex = this.Index + 1, nCount = this.Points.length; nIndex < nCount; ++nIndex)
	{
		arrData.push(this.Points[nIndex]);
	}
};
CHistory.prototype.PopRedoPoints = function()
{
	if (this.StoredData.length <= 0)
		return;

	var arrPoints = this.StoredData[this.StoredData.length - 1];
	this.Points.length = this.Index + 1;
	for (var nIndex = 0, nCount = arrPoints.length; nIndex < nCount; ++nIndex)
	{
		this.Points[this.Index + nIndex + 1] = arrPoints[nIndex];
	}

	this.StoredData.length = this.StoredData.length - 1;
};
CHistory.prototype.RemoveLastPoint = function()
{
	this.Remove_LastPoint();
};
CHistory.prototype.IsParagraphSimpleChanges = function()
{
	var Count, Items;
	if (this.Index - this.RecIndex !== 1 && this.RecIndex >= -1)
	{
		Items = [];
		Count = 0;
		for (var PointIndex = this.RecIndex + 1; PointIndex <= this.Index; PointIndex++)
		{
			Items = Items.concat(this.Points[PointIndex].Items);
			Count += this.Points[PointIndex].Items.length;
		}
	}
	else if (this.Index >= 0)
	{
		// Считываем изменения, начиная с последней точки, и смотрим что надо пересчитать.
		var Point = this.Points[this.Index];

		Count = Point.Items.length;
		Items = Point.Items;
	}
	else
		return null;


	if (Items.length > 0)
	{
		// Смотрим, чтобы параграф, в котором происходили все изменения был один и тот же. Если есть изменение,
		// которое не возвращает параграф, значит возвращаем null.

		var Para = null;
		for (var Index = 0; Index < Count; Index++)
		{
			var Class = Items[Index].Class;

			if (Class instanceof Paragraph)
			{
				if (null === Para)
					Para = Class;
				else if (Para !== Class)
					return null;
			}
			else if (Class instanceof AscCommon.CTableId || Class instanceof AscCommon.CComments)
			{
				continue;
			}
			else if (Class.GetParagraph)
			{
				if (null === Para)
					Para = Class.GetParagraph();
				else if (Para !== Class.GetParagraph())
					return null;
			}
			else
				return null;
		}

		// Все изменения сделаны в одном параграфе, нам осталось проверить, что каждое из этих изменений
		// влияет только на данный параграф.
		for (var Index = 0; Index < Count; Index++)
		{
			var Item  = Items[Index];
			var Class = Item.Class;

			if (Class instanceof AscCommon.CTableId || Class instanceof AscCommon.CComments)
				continue;

			if (!Class.IsParagraphSimpleChanges || !Class.IsParagraphSimpleChanges(Item))
				return null;
		}

		return Para;
	}

	return null;
};
CHistory.prototype.private_ClearRecalcData = function()
{
	// NumPr здесь не обнуляем
	var NumPr            = this.RecalculateData.NumPr;
	this.RecalculateData = {
		Inline   : {
			Pos     : -1,
			PageNum : 0
		},
		Flow     : [],
		HdrFtr   : [],
		Drawings : {
			All       : false,
			Map       : {},
			ThemeInfo : null
		},

		Tables        : [],
		NumPr         : NumPr,
		NotesEnd      : false,
		NotesEndPage  : 0,
		Update        : true,
		ChangedStyles : {},
		ChangedNums   : {},
		AllParagraphs : null
	};
};
/**
 * Обработка изменений после Undo/Redo всех изменений
 */
CHistory.prototype.private_PostProcessingRecalcData = function()
{
	for (var sId in this.RecalculateData.ChangedStyles)
	{
		var oStyle = this.RecalculateData.ChangedStyles[sId];
		oStyle.RecalculateRelatedParagraphs();
	}
};
	/**
	 * Получаем сколько изменений в истории уже сохранено на сервере на данный момент с учетом текущей точки в истории
	 * @returns {number}
	 */
	CHistory.prototype.GetDeleteIndex = function()
	{
		if (null === this.SavedIndex)
			return null;

		var nSum = 0;
		for (var nPointIndex = 0, nLastPoint = Math.min(this.SavedIndex, this.Index); nPointIndex <= nLastPoint; ++nPointIndex)
		{
			nSum += this.Points[nPointIndex].Items.length;
		}

		return nSum;
	};
	/**
	 * Удаляем изменения из истории, которые сохранены на сервере. Это происходит при подключении второго пользователя
	 */
	CHistory.prototype.RemovePointsByDeleteIndex = function()
	{
		var nDeleteIndex = this.GetDeleteIndex();
		if (null === nDeleteIndex)
			return;

		while (nDeleteIndex > 0 && this.Points.length > 0)
		{
			nDeleteIndex -= this.Points[0].Items.length;

			this.Points.splice(0, 1);

			if (this.Index >= 0)
				this.Index--;

			if (this.RecIndex >= 0)
				this.RecIndex--;
		}

		this.SavedIndex = null;
	};

function CRC32()
{
    this.m_aTable = [];
    this.private_InitTable();
}
CRC32.prototype.private_InitTable = function()
{
    var CRC_POLY = 0xEDB88320;
    var nChar;
    for(var nIndex = 0; nIndex < 256; nIndex++)
    {
        nChar = nIndex;
        for(var nCounter = 0; nCounter < 8; nCounter++)
        {
            nChar = ((nChar & 1) ? ((nChar >>> 1) ^ CRC_POLY) : (nChar >>> 1));
        }
        this.m_aTable[nIndex] = nChar;
    }
};
CRC32.prototype.Calculate_ByString = function(sStr, nSize)
{
    var CRC_MASK = 0xD202EF8D;
    var nCRC = 0 ^ (-1);

    for (var nIndex = 0; nIndex < nSize; nIndex++)
    {
        nCRC = this.m_aTable[(nCRC ^ sStr.charCodeAt(nIndex)) & 0xFF] ^ (nCRC >>> 8);
        nCRC ^= CRC_MASK;
    }

    return (nCRC ^ (-1)) >>> 0;
};
CRC32.prototype.Calculate_ByByteArray = function(aArray, nSize)
{
    var CRC_MASK = 0xD202EF8D;
    var nCRC = 0 ^ (-1);

    for (var nIndex = 0; nIndex < nSize; nIndex++)
    {
        nCRC = (nCRC >>> 8) ^ this.m_aTable[(nCRC ^ aArray[nIndex]) & 0xFF];
        nCRC ^= CRC_MASK;
    }

    return (nCRC ^ (-1)) >>> 0;
};

var g_oCRC32 = new CRC32();

    //----------------------------------------------------------export--------------------------------------------------
    window['AscCommon'] = window['AscCommon'] || {};
    window['AscCommon'].CHistory = CHistory;
    window['AscCommon'].History = new CHistory();
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

	var CAscColorScheme = AscCommon.CAscColorScheme;
	var CColor = AscCommon.CColor;

var g_oAutoShapesGroups = [
    "Basic shapes",
    "Figured arrows",
    "Math",
    "Charts",
    "Stars & Ribbons",
    "Callouts",
    "Buttons",
    "Rectangles",
    "Lines"
];

var g_oAutoShapesTypes = [];
g_oAutoShapesTypes[0] = [];//Basic Shapes
g_oAutoShapesTypes[0][0] =  { 'Type' : "textRect", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKxJREFUeNpi/P//PwM1ARMDlcHgN5AFxmBkZOwh1xBgPJRgGAgFJWSY14PXy6BYh8a8E4xPlpeRAdD7pkDKAYg/A/FpkKFAMV8slm8GihM2EAh8gYrrgIqbQAZCxTaTFctAQ5ygdBMynxIvg7x6AOjCfVDDQPx9IFdjUbuZAU8k9CDz0TGO5ALWh6yOdgkbKQx9SdC/maCBoKQwOPMyLBuhJ1RSAePIK2ABAgwAvo1VrBjQ0e0AAAAASUVORK5CYII="};
g_oAutoShapesTypes[0][1] =  { 'Type' : "rect", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAGJJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj41sMpBiB+D8azYAmxoAkDgefPn2KQTEQqiiGTIctwebl/yMvlhkpMOc/tV3IOIJzCtXTIXpOWUxkrKNnRbhjGEfLQ4oBQIABADiTFcrCIC0JAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[0][2] =  { 'Type' : "ellipse", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAR1JREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj40MWFwBiVyDWAmIZIOYA4h9A/ASIrwPxbiB+D1P86dMnTAORgC8QBwHxfSDeBcT3gPglEEsAsSLUIi8gXgfEm3C6EAqSgNgQiPuB+BKa3AsoPg7EekCcCsTCQDwfVxiaALE5EDdgMQwdgOQbgdgCiE1xGegF9cJbIsP/DVS9Jy4DFYD4BImRegKqD2eyYSHRQFYg/ofLwAfQcCQFGAPxI1wGbgdifyAWIdIwYaj67bgMPA0NkwZossAH9KCxfByqD2eYzYPGXiEQPwTivUD8DIjvArESEEsBsQs0ItYC8WZ0mxhhxRda1hNEynry0MD/DbXkGjQHfcCW9RhHy0OKAUCAAQCYrz96ombzgAAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[0][3] =  { 'Type' : "triangle", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPVJREFUeNpi/P//PwM1ARMDlQELugAfHx8utfJA/BCbxKdPn0h2oSAQV4Lso5aXvYGYB0pTbCDIIDsgngTE9kDMTamBPkB8A4hPAfEDIHalxEAuIHYC4g1Q/iaogWzkGugFxI+B+B6Ufw2I30MtIdlALqhrNqKJg1zpiS3JETLQBeqaS2jiZ4H4LxDbkGIgKxB7QF2DDkCG7YBGFtEGgrz6B4hP4pA/CE1OFsQYyApNwFuhrsEGfgLxXmyuxGZgDFR8L4EUAPK2FBAHEzLQGYhnQr2MD3wG4g50V2KLelABWYLERgaMaOKM6JoZB30BS3UDAQIMAD+RLxKet7HDAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[0][4] =  { 'Type' : "rtTriangle", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAI1JREFUeNpi/P//PwM1ARMDlQHVDWRB5vDx8S0BUluAeAUphnz69AmvC32AOIKaXo4BYm9yDUU3EBblseQaim4gIxI7lhzv43IhsvdJMpSYZEOSocSmQ6IjipSETVSYkppTCLqUnKyHN0nhSzZkeZ9QsiE59lmwuHAJFgsYkfiMaHLeyIUJ48grYAECDADl/x5fvLBaLAAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[0][5] =  { 'Type' : "parallelogram", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAO9JREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj40OXUwPiWiQ+I5o8cuA//fTpUwWKgViAOxA/BOIaAo6qBuKThLzMD8TGQLyLgGHyQKwAxEcIGegMxB+A+BgBA32hhv3AZyAoGOyBeA8Q/8FjmBDUF3sIxbIBEPMA8T4CrvMC4jugCCFkoBsQHwTib3gM44b6YhehdCgBTS5bCLjOEYi/A/F5Qga6QxW9I5B2XYD4ALYwRjaQA4itgHgzAdeZQZPVfkJZzxKIHwHxPQIGegLxBSB+jzfrAYErEMsB8RKkrMWIhWZAUoMBGEfLQ4oBQIABAJksL7igo2spAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[0][6] =  { 'Type' : "trapezoid", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAASBJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj40MW5wXiKUDMBeWDApoRSf4bEOcC8SeYwKdPn1ANRAPmQHwRiPtwyBcBsRkQ7yHWyxZohoHUMSM5ACRnSWwYikMxG5TPjGQYK1SMDapGghgDrYH4MhD/gmpkQzOUByp3CYitiDEQFDazkFyH7F0WJG/PgqrFa6AK1FtMSKmAFc0w5KBgherBaSDIC2eA+B8QC6IZwopESwPxX6haa1wGgjQaA/FyKJ8VzRA2JDYsckBqjaCuxTBQDzmhYjGADSkI2JDUfYTqxTAQlK5OQdmKSAaxYgnH31A1DFA9FhhZDwh0gHgqlH2fhOy7BYinYzOQG4hXoeVZbAC5AGWE8n/ABUZeAQsQYAB1Yisi5lX9sAAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[0][7] =  { 'Type' : "diamond", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAARtJREFUeNrMlEsKwjAQhq267jVcCC5EQcTiUQRfqAs9jE983ERQ1FbBB4IX8Ay9QP0HfkEkaSN04cBHmnTyd5qZiRUEQSJOSyZittgF0+8H27Z1PkXQBXNwUjn4vm8cYQF0wBq0Qdk4Qo2YiAzBHTxBC1jA/VUwz8imFBPzOLY5uqaCOdADM3D9eieiqY9ID1GCIjYAS3DRRL/nvibnB51glmIrcIw4+w0IGKkkdqfKcp9f8wxLbstzrOkKewQqJqVBE78SGOsEH3zZMhAt028CbmGtd/sQdTRiDktnokqcqlMudG4oRCtclzY8/3I5nLlJNle5VuV8EZa4sNbzWLzyexme2yKs7aIE3+0lnVFnfbpRqbf+/sZ+CTAAcZs9d+tSdJIAAAAASUVORK5CYII="};
g_oAutoShapesTypes[0][8] =  { 'Type' : "pentagon", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAStJREFUeNpi/P//PwM1ARMDlQELjMHHx4dLjSQQVwExGxC3AfFDbIo+ffpElAvNgbgLiI8D8UEgbgdia6JciAVEArEfEM+AGgYCj4A4B4hVgHghsQZyAXERECsAcR0Q30aSOwLEz4C4EirfA8Rf8UWKLNSLQkBcgWYYDNwD4jIg5gTibiCWwWWgJRB3AvFjaCS8wRMc75Fc3wXVi2GgOxCfgxr6g4gU8guI+4H4GBB7YDPwPBCLkZH0JKEOwTAQFJPyUAXEAgEgVgXiQ9gM/ABNFhYkGGgPxA+gYYo1lo8jBzARAJTwT+BLNqAAViTS2zDvHsNn4AtowrUk0rvPoXrwljYniAxHM2gQEcx6p4A4GIjXADEjEP9HopEBSGwuumbGQV/AUt1AgAADABY4PZrII+JwAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[0][9] =  { 'Type' : "hexagon", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNpi/P//PwM1ARMDlcHgN5AFmcPHxwdjygNxNxD/hPIZgfg/EpsViMuA+CFI4NOnT3AzGJEjBcnAEqhhk3E4JB+I2aCWohiIzcsg15kA8Uo8PlsJVSNPTBiGAvFBIH6Fx8AXQHwIiCMIGSgHxAZAvIqI8F8NVSuPz8AwID4MxG+JMBDkgwNAHI7PQHMgfkdCKnkNxKb4DDwFxAIkGAhSexqfgaCwswdiQSIM4wdiZyBegc9AUEK9AA1LQiAYiC8C8SNCyQYUe3ZALILHMJAPnLClVWwGglx5HuoCXCAI6rqHePMyWlj2ALEtWh6GsdmBuBSbRsaRV8ACBBgAHzQ1/dI3wFUAAAAASUVORK5CYII="};
g_oAutoShapesTypes[0][10] =  { 'Type' : "heptagon", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATRJREFUeNpi/P//PwM1ARMDlQELjMHHx4cu5wDEKUAM8gIjkvgCIN6DrPDTp0+YBqIBdyCOBuI+ID6HJG4FxKlA/BeI9+N1IRLwAOIoIJ6JZhgIHIMGUxrU5QcIGegDxOFAPBeIj+Jw/REoDXLpPyA+hMtAOyCOAOLF2GzGYigTNIz/IVmCYiDIGyuBeCea5sVIkRKDJA5y2Q8gzkM2ED3ZbMbimlioQdgS7Cl0cRYik9cSNNchA0ZyEvZ/YuXQDXQkxhVIwABdDtnL04E4E4jZgXgHmkZs3gVZngTNOVgNBKU7XqjmP+jZCw04AXEiEG9AV4ceKTughsVB09c+PIatwpYqsMUyzMYEqOHIOcEFiOOBeCmWYIEENqw8xFLawMIIPXKWoBuGXNowDvoCluoGAgQYAPhpR6oCmQSgAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[0][11] =  { 'Type' : "octagon", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATZJREFUeNpi/P//PwM1ARMDlQELjMHHx4cu5wDEyWhijEC8AIj3IAt++vQJ00A04AHEUUDcD8TnkMStgDgNiP8B8T68LkQC7kAcDcTT0QwDgWNQV6ZDDT1AyEAfIA4H4nlQzdjAUSgNM/QQLgPtgDgCiBcB8X4CYQ8ylBmIU4D4L5IlKAaCwmYVEO9C07wEiP9DvRqDJA5y2Xcgzkc2ED3ZbMLiGpBhiThcepqcdAhy2XxqJuwfQJwJdSkDDh/gNNAJiwZ2aBLCBvShPsAay9OhLmEF4p1I4rE4DIPlpAW4DATFFA80Jv+iZy804AjESUC8Hl0desLeCTUsHk/2coTGOiiJbSYm68FsTADi30B8GEnOBWrZErRgQSQJWHmIpbRxgnoLPSYxDEMubRgHfQFLdQMBAgwAYrxI9g9PFlEAAAAASUVORK5CYII="};

g_oAutoShapesTypes[0][12] =  { 'Type' : "decagon", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAUJJREFUeNrMlLtKA1EQhnMkWMm+Sh4gIK4IWqQWkY0SL2gaHyVt0kVcG22EkGbFG2IsbHyXrUyRrP/AvzCOZzcStnDg4wwnZ//MOXNxWZbVqrSVWsVWz50gCOxvG+CYvuMq17kEj/pgmqa/BY3tgH3QA59qvwlOKPxUGqGybYoNjJjYhOsZmIOXRYItsAuG4L0g+gmf4JSir0WC62APXIHnBW//xoTKG89U5D8E5R9vwb3auwYRiFVyIvoS2Re40IK2bEbKj5U/BV1PpB9MkLcOnTnctocLzC1T2G6ZTpFowgKhVdD3RNwoKxupu3N+nHAvUtf3ddIRS8wrKJlao4iUwkPJzUKK3dk2tIWdUOyAq68eN0EH3IDxX1ovj6xDUd0JW+CQ9Zl4s5fPQ8+0CdW0yVSCYiump4379wO2csFvAQYAcA9LTdDU7PQAAAAASUVORK5CYII="};

g_oAutoShapesTypes[0][13] =  { 'Type' : "dodecagon", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATdJREFUeNpi/P//PwM1ARMDlQELjMHHx4cu5wjESUDMCOX/h7IXAPEeZIWfPn3CNBANuANxFBD3A/E5JHErIE4D4n9AvA+vC9EMiwHi6WiGgcAxqCvToYYeIGSgDxCHA/FcqGZs4CiUhrn0EC4D7YA4AogXYbMZi6GgCE0B4r9IlqDEMsjGlUC8C0lsMRK9BIgLkOQOA/EUIM7E5UJQLG5G4i+BioFALJIYMjiNpAbDhYxoimPQxJZAxdABIy4D8WUZXIYRzCmOBAxF97I+vmQzA4gzgJgdiHcgeZsBh+scoDlpAS4DQVHPA9X8Bz17YfFJIhBvQFeHnrB3QtNVPJTej8OwJGgS20JM1oPZmAg1FDknuEAtW4oULKhRDisPcZQ2yUixz4gUOTtwlTaMg76ApbqBAAEGAMs+TMehgXoxAAAAAElFTkSuQmCC"};

g_oAutoShapesTypes[0][14] =  { 'Type' : "pie", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAR5JREFUeNpi/P//PwM1ARMDlQELjMHHx4cupwTE7kCsBcSCQByDz6BPnz7hdCHIklAgLgbit0A8lSwXQgEHENcA8TsgLgPir2R7GQqygPgNEE+gRqRoA7EyEM/Cou4/OQZ6A/E+IP6GRR0jOQaCYvUE1ZINEPAA8Ssc6kBeXoLHnH9AHIdu4H88XovFYxgojU7C5uUfQCxKhi9FgPgzNgNvAbE5GQZaAPFNbAbuBWJnIOYiwTBQfrUF4t3YDDwHxPeBOJWECM0E4itAfA1XaTMDiKWAuACIufEYBpIrAWJe9IzACCsPkUobbmgWVIIm9IvQ8IXlJl1o0IBcNhMamfDSBpuByFnRFVp8wcL1C9SgPUB8A1vxxTjoS2yAAAMAsic+vBCozAkAAAAASUVORK5CYII="};
g_oAutoShapesTypes[0][15] =  { 'Type' : "chord", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAThJREFUeNpi/P//PwM1ARMDlQELjMHHx4cupw3EsUC8BIivEDLo06dPOF3IBcQFQJwLxHOBOBNqOFleBhlWDxUvBuLbQDwRiLOAWJ8cA0EanwNxHxB/hYrdAuIJQJwGxIakGAjyliIQz8ai7jbU0FQgNiHWQG8g3ofkMmyG9gNxChCbEmOgMhCfIOAjkKG9QJwExBaEDOQG4ldEhPttaBjHA7ENtRI2zNAYdEORDfwOxGIkGtoLNdQOm4EgBeZkuPQkEFthM3A3ELtAw5JYAMqvlkC8GZuB54H4PjRZEFsOgDLCVSjGGinTgVgKmpe58BjGA8QlUHomsgQjrDxEKm24oDYrQxP6BWhYwXKTLhA7QV0FMuwHcmmDzUAY0IGGKcgQDqjYNyC+DMR7gPgGtuKLcdCX2AABBgCNUEhbXzjZUQAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[0][16] =  { 'Type' : "teardrop", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAASJJREFUeNpi/P//PwM1ARMDlQELjMHHx4cupwbEnkCsD8QSSOIgLzFCaQYo+8enT5+CUAxEAmxAnA3EtkC8BYj7gfgaEP/F47B1GC6EAk4gboXamgnEL8n2MhTkAPEXIK6jOAyBQBWIjYA4lVqx7A/EO6EuJBUwYjNQF4iPUuhLFAOFgPgRmb78j81AEPsnmUH3F5uBb4FYjgzDFIH4DTYDLwGxAxkGWkL1Yhi4BZrVeEgwDKTWC4i3YTPwBhBfAOJiEgysAuJDQPwQV2nTD43tRiDmxmOQLFQtKMnMRkmQsPIQqbSBFQ6gsNkOxMeA+CbUIlBa1YaG9UYgXgrTBCxtcBqInBU9oIZIA/FXIL4HxLeAeD8Q30dWjGHgoC2xAQIMAJN5P+qYRUE2AAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[0][17] =  { 'Type' : "frame", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAI1JREFUeNrMlGEKgCAMhbfwtye009kJvcDLoH60Hka6ooFMJ8zvsTkFIJ42ibOFYxNjzNVpXSBeTExsvJQynxLuljrBlgshu2QkhDRRyUbK/JSMFQVvVVk78sC7bZQlHCH7hhAjibwlN9sGHYTwbpvmT9ksm8HAHgJTE4jk5EV4NxjEDAV2Fv39xF4FGAD1iijRvhIHcwAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[0][18] =  { 'Type' : "halfFrame", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKZJREFUeNpi/P//PwM1ARMDlQHVDWSBMfj4+EDUEiAGhQEjHj2wMEJWk/Dp06c/KAYiKY4l0jEGQJwBxDOA+A+GC9FsXYzmAmyuAoFuIL6I1ctYDI4hIrj+EIoUUtLQH2JimZEMg6nmQgZSXMgw6F3ISG0X/qemC+2gNCu1CodoIG4A4t+UGsiClO3ukOtlRlgBCy1tWHDlAEIAWNqgGjhoC1iAAAMA7JAmoxpKfRYAAAAASUVORK5CYII="};
g_oAutoShapesTypes[0][19] =  { 'Type' : "corner", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIJJREFUeNpi/P//PwM1ARMDlQHVDWRB5vDx8c0FUuxADAoHRqgwjB2Dy5BPnz5hNxCqGZvGxeR6mZHaYYgryhmp7cL/1HYhw6AJQwZKw5CFSHVPgLgdh8EyyEmNhcgwrMBj2RJqZ73/dC0cGKlaOAABG1KY/Cdg0X9s4owjr4AFCDAAecAY1MOuwU0AAAAASUVORK5CYII="};
g_oAutoShapesTypes[0][20] =  { 'Type' : "diagStripe", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAARlJREFUeNrM1M9KAlEUx3GvtJ4Haa0hGuLSjRjSKoQEoxL/PICPoVGI0SYEIQoiMGrRIjBQA5+iF5gXGL8DR5DxzDAzuujAZxi4ww/O3HuPcRwnsc9KJvZcB+sXy7KCvjtEF1o7xrbt6lZgQGVwiT5mnrVj5KO0nJOwgRLmrtXwrrasVAHnPmFZ1HGLZZjAIs5wg7kSdoE7/PpuykaVcOoTlpGweywCd1mqgrKELZSwawzxE+Ycuq2cyG56w9K4wgOmYQ92Az3lvxyhhUd8R7kpRglLS9gIX1GvnvcWpNDGGJ9x7rJRwp4wiTscnI2wDl7wtuu0ccOaeBU7ja8/ObQfeI47vsx6wMr4ch921BDG13bgv53YKwEGAKylPza045nMAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[0][21] =  { 'Type' : "plus", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAI5JREFUeNrMVNEOgCAIlOZbm19IX2df6Nbz9aIbOVhmtHUvOsBTDoQABE8swRmxbVJKvS/XlYQNwsYyuJRyJTSwGfZ9JmX6l4ZVM+q00rBWf4uHlKfXkAcecSjaZi1lepEpfaahFyG8CUmrstawPNjY0AjZqpwB9vwpmCkKZi6LN4fy0x6l3w9Yd8JTgAEAq5sa1Cv6QPgAAAAASUVORK5CYII="};
g_oAutoShapesTypes[0][22] =  { 'Type' : "plaque", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKdJREFUeNpi/P//PwM1ARMDlQHVDWSBMfj4+JDFl0BpUHgwYqFhcrEwDZ8+fUI1EAuIIeCYJcR6OZsEH8bj9DKaNxcTEVSLoF52RfY+C4nehIE/QLwLihmQHUCtWGYc9Onw/9DJKbTLekhpEZYOdxHQ64aU9eCxzAgrvpDyMij1uyDnUzxZbzcQL0TOy9i8vBDZRgJgISEv4ytxkJMHTgsZB32JDRBgADisKdf1YvotAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[0][23] =  { 'Type' : "can", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQ9JREFUeNpi/P//PwM1ARMDlQELNkE+Pj4QJQbEvkCsBcQiQMwNlX4CxA+BeC8QX/r06ROKXkZsXgYaqAukCoH4AhDfA+I7QPwAiBWAWB5K2wDxEqCBO4kxcDaQ6gXiG3h8B/JBK9DAVGLCkB+IWQkEF8iVfESFIRD8BuJyIN4HxEeB+D0Q/wRiCSh2AmINqDqiDASFwwwgdgdiI6ghjED8CCoPCoqZQNxNrIEgzUegmK7pkGXADGQk0sD/xBrIRu28TKwLGYk18D+1vQyyWY+AYRpElzbQkqQamg6PQQsIUG4RBGI1aMFgBcQHMFyCo3CAuQCUxVSheRsk+BGIP0Fzyh4gvktU8TWoSmyAAAMAuihDxOeqLuYAAAAASUVORK5CYII="};
g_oAutoShapesTypes[0][24] =  { 'Type' : "cube", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAO5JREFUeNpi/P//PwM1ARMDlQELjMHHx4dN7g+xBn369AnVQDTgAsTxQMyIQ/4/VA4WXrEYLkQCPkAcDMRLgXgHHkeBLI1GNwM9DEOAOByIFxMwzAPqg4XovmBCszEAiFcC8T4ChsUA8RIgPoAzUoAgAUpHQPF/JNuRwwxErwHinUhyWA38jxy4eADIZRtomQ5xhiEjkQb8p2tOYSLWZjw++Umpl38gsU2BmA2IhXDFMjGAA0p7QZPXfCB+R0kYgiy2gxq2CD0TkONlEEgG4hVAvAdfTvkPzcPIpQgjllwCotcC8TasMTboS2yAAAMAiLwzfFcyX98AAAAASUVORK5CYII="};
g_oAutoShapesTypes[0][25] =  { 'Type' : "bevel", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAMFJREFUeNpi/P//PwM1ARMDlQELjMHHx7cEygQ5mRGJzQDlI7MZ0NV++vQpBsVAqORjID4CxNuIdJAXEOsCsQ6GC6E2HQDiOCCOQnPBf1wuA4JFuAwEKdoFxLFQTAxYgqQHI1IYsYQRsYCRZrHMhOZlqhpIjlf/ozuGWi7EG4b/yTDo/6CN5f/EFA7/qVI4QA1KR8oB2LIZA5Ys6YLLQJACJSDeDc2fxBYOlrgMBAFpKHbDEQSMOPhwMcZBX2IDBBgAUnYvbh3TyxEAAAAASUVORK5CYII="};
g_oAutoShapesTypes[0][26] =  { 'Type' : "donut", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAbdJREFUeNrMlDtLA0EUhXfFyuiCIBZWoviKj5DKThDUQkQLQcTeJqA2USzUQkyvpAniH4hWWqoxlVqIT4wPRAsbRWxcMChC1nPhDIyb3a1SeOFjZ9i7Z+7cObOm4zhGKaPMKHGUq4FlWe53raAPdIIQkK18giuQAfd6sm3bfwW1kI8nQRvYJ3fMbQYREAeXYAN86R+bqoesUMSWwBtIsSLDZ9EpUAlWRFRV6BacBT9glR82gTHQAgogB9Lgme/nuWhSCeqH0g7qwTrnQ2AaHHIh2eYRmGFvJZKgC4SLDgUxCLIgT/FesAA+tJx3cAES4BVcgz3m3rgrbATHHI+ALZeYCtniJhjm/IwFFG05xMOQaACnAXY7YY7BSqu8BE2fsV+onIKerwtK72o5fgTRALEIcyTqxNdegg+gm+MdMC5u8hAT702Abc6j+q3RBTO0QwVPL8vT7AE1oJoLLvP25Jjbz7mnseM09pp2n0f5lMRbGvuJ7+fAt+T73RTZziJ4ocHzPj2UvBhPNxF09ZR9YvTlAThnfw3eCPHcANuSYoVGkKCKDvY0zF4pU4vQrt/vy/z3f+xfAQYA5jSFXYrK0roAAAAASUVORK5CYII="};

g_oAutoShapesTypes[0][27] =  { 'Type' : "noSmoking", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdtJREFUeNrM1E9IVFEUx/F54Wq0twmEllqpNUEkhGBQoL5VmAshol2Ki5j8AxW40kUILZth8D+0Vdy1jCKEqEVR/p3+MAQG0h93Q9QEyfg98Htwe/OmNrPowgcu7905c8699zyvXC4najkOJWo86sKJ7/vRd60IcBoNevYdG3iC9+7iYrH4Z0Bn1GMIJ/FY3mltC87glgIvouT+2Av3UBlasAl8xSx+VKnM1g0r87v4FWYYDXgbv3FfPzyBK2jDPvJYwie9H9c25MKA7qGk0IR559mu9nIBd/Aco+jR+5y2IBV3ypfwVGWmVI7Ns7iGI3iGSfTqsCy7R7gYF/AYXmjehwzO4hVmlFmLgizjsta+UfCKgEl8c4LfwwDOYV3ljeA4XmqNjS84HBfQc+Z2UjvK0oJ2YBvTuInmyNrYTvmJRs0/arMLCnodnTplK39M72wctXsdF/CDMrHxEFftNulSZxX0vDrkBla0tt3tGjegtVO39nILq5jCBezhAQadcgu64IG6qaL1XqNLbZdRlpZ1v57ZXr2N7Flaf57/V+t91gWv1noNKttXFaVqrRden7RKs4u+pkxtnNKlD3Tqc+HH4W8B3VYMFCSpUi3jTecLVPH58v77L/aBAAMAF3yN8vwfkx0AAAAASUVORK5CYII="};
g_oAutoShapesTypes[0][28] =  { 'Type' : "blockArc", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAASdJREFUeNrs1LFKQlEcx/FrBYLGfYbQEqGM3kCIphxq6w3alIiCplqaG2oInISGwB5BqkmnGiqKmgMjmroY2lDX74HfgeNVocGp+sMHjvee87//c84fY2EYeqOMMW/E8QcTTtiB7/vRd1ksIYeknrVwiws8upODIOhN6EQC60p4jhqeMI4MFrCJO5Tx6S6O2bZRhSbZHl5xjPaQnZl5JUxiHx1bYTThFr5xoIXTWFO1X3jAKZ71fgcfOLIJ3UuZxZQqM1FAEXV9aFvjDZ2tiUPMa23fGS7jUts0Exaxi3dnzhtutM2mKjZnnMd9tMIZNDRewVkkmefcdBWr+n2NuUF9mFAFJlKaOCyukNb4RZczsG0qP+xfc5NxnNhu6Wub/z+HX5ywK8AAkzxHW63u4mAAAAAASUVORK5CYII="};
g_oAutoShapesTypes[0][29] =  { 'Type' : "foldedCorner", 'Image' :"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAI1JREFUeNpi/P//PwM1ARMDlQHVDWRB5vDx8S3BogY5TBjR+DCxmE+fPmEaCFUcS6KjllDby//xGcg4GCKFEZ+B/weDl6nuQga6Rsp/quYUEly4GJdaJgqSSgwQ9wLxbyDmwuVCUrxsBsTZQLwSiL/BbUIuD7EUDv9xeA2maTUQbwIxYIUD48grYAECDAB6VSL4lX9gFQAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[0][30] =  { 'Type' : "smileyFace", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAZ9JREFUeNrMlD0ohVEYx98rg4+6EiH5WHwkkjJISpLIZlEKi0EyGRSjGYOBMBnIZjCJXLFJyUDEIJHhWuR2fUVdv6P/W8fpvqQMTv069zzPc//nvM95nhNKJBLeX44U749Hqv8jHA67vmJog0oohBDcwjlE4NoOjsVin3PI/2RHsAtaYQ8O4Eb2ImiAZtiB9Z8E02AMnmBOcya8wru1YQYMyjcJb76gm8MBiUxpNuPREfPkm5GvL+hSqqEWZrXuhWXosWJc2yLUQ0kywU7l5Vlrk8N+XYwXYDOxu3aMLVgOh5CldUSn2bZijG3Fspkc7uvrvpaNnFdQCg+wKuzh2vJVPllBhW1uOf6LOn50dVIcZwHc/UIwCnlwn0zwUjfmqTuWVMjuyFYl+LGNcJZMcEu3la72MrkahxbIUb6bYAI2dIHp8kd8EbdTRmWf1lwG3VChXjYbrcGF/CPwAgtBrZehE8RVtNGA3OXCkE44YbdessfBlM8wVMEmHFknMrmtg3Y4hnn1+Y+vjRk10CHhNNnMn0+10cm3z9e/fbE/BBgAYOGAEI/qCqQAAAAASUVORK5CYII="};
g_oAutoShapesTypes[0][31] =  { 'Type' : "heart", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAXZJREFUeNrM1EsoRFEYwPG5kne3bESRjdfOxloeWdlIIQt2bGbF0kKRJaIUdpJkM9nZSLOQwmaK8ipRssb1LI/rf+o7dV3fzE3Nwle/ZppzzjfnnPt91/F9P5bNyIllObKeMNd+cV3XfLShA5W4xylW8STTitCPBlTgAbvY8DzvZ0KiET1YxzEe0YIJTCEfYzjEOPLQhEHcYC+csBXb8o82dmQnfSjEEdZk7FXG69BsEwbvsArXyrUkUCvXsKKMX8rYryOb+3lTFpidbMHU14cy/oISLeG7bP9EWZSEk+bBlgU3EjyyuexOlCqLvvCp/F4slZHUEm7K9of/UHZxOVlCS/iMOdRIKUTFgMydlqRqp1xhRo7RnSGZ+cN2zOI2qvXOsIgu9CqdNSTdtCRz9dYLxYE8hLjU54KU1QiqsYx9baFjX1/Sy+GoxyjupNaMeaTCE20vR71tzjEpbVcgDyCVaUHUDm2Umym4SDfB7tD592/sbwEGAEJwWOV72omDAAAAAElFTkSuQmCC"};

g_oAutoShapesTypes[0][32] =  { 'Type' : "lightningBolt", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAWFJREFUeNrM1E0oRFEUwPF5GqTGwwLJggU1C9n6SpSy0oidLC2UhaIsZOGjzNJeFoqVfGykLJRJ0ww2NmgisSBZqecjZfH8b52pOy8f775m4dRvFvNup3vPPfdYruuG8hkFoTxHWP3Ytv3T9ygyfyVxHCc34TfRjhiqsIaE0Q616EYfLGzjAgt4x6lJwhpMSU13cKStWcakOpmf42cv5RFpRFDhWXOJPUyg1uSWN7GITsyjWvt2gkI0m7bNLaZxLcl7UIo5PHtK4bsPP7ElZYjKf6t4RRyNQRq7FfWy0xepr7rtFGYwhko/bZMN1XcfGEYXVnCHDRShF1c4MHl6x9JKGanhCEpQJskTQd6y2uU6ztGBceyjTnbp+8h6qERNWMIN3rCLQSSl4Y2mzZm8HtXYs+jHIZ4w5F1sqXn4y7TRowEtaEO5vPUB1bdMm4cgCb1jbRTFuCdhPCfhv57YXwIMAEu2VgZ5MSPnAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[0][33] =  { 'Type' : "sun", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAARBJREFUeNpi/P//PwM1ARMDlQHVDWQBEXx8fPjULAHiGFySnz59IsmFS6D0YmJdyAiKFCQXLgDi30BcBsTvsagXBeJmIOYA4gRsLmRB0/ADiCdADQsG4kAghiWDjUC8BognAXEhsS4EueA1EIcAsT8Qx6J5H2ToaiAWhPmAkAtfQw1xxxIRMdCw5ATiRcQkG1jAu+OJVZBlbvgiigktNhmQwowYsASXgSAXMcLClYAh/5HUxeDzMkxyPTabkby5C0093oQtAcRrgXgnljAC8XdDaSG8WQ8JNEDT2WKoZYuRgmA3NHZ1oOkwmRgDOaCKQTllIRSj+yCflKyHLRb/44oAcgqHGHwRgNOFg7qABQgwAO1VSMa/d/eoAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[0][34] =  { 'Type' : "moon", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATlJREFUeNpi/P//PwM1ARMDlQELMoePjw9dXg6InYFYHYiloWJPgHjzp0+fjpHqQn8gbgRiSSC+AsTJQHwbiGWA2IwoF0IBGxCXArEwEPcB8WWoeCYQSwHxdCA+RoqBcUDMA8SVQPwTKhYGxIZQFz8lJVKUgNgOiCcjGQZylQ8QLyFkGDYDHaFefIYk5gI16BA5yUYHiK+hiYG8eprcdCgExC/RxASJ8SouA0HZhhFNDMT/S66BH4BYDE3sPRYxog28CsTaWMQ0yTVwD9RAKSSx3dDIkiDHwPtAfASIs6E5BgQeAPFRIM6DRhDJpc0CIP4GxF1ArIUk9gWIW4DYFJ+BjMjlIVppEwAtIG4C8SMg3gDEFUCsCJIEljaxxOZlGAAZcA5afBkAsRc0WT0H4utEuXBQltgAAQYAtFtCh0VqS+gAAAAASUVORK5CYII="};
g_oAutoShapesTypes[0][35] =  { 'Type' : "cloud", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAVdJREFUeNrk1D8ohVEYx/H76vrTVa+E6bqRzCZFJoMsUoz+lGI1UDYZTAYpyqRMTEqm21XKJIUMBmWRgYEoekUhXt9Tz3Cc97mut97Nqc/tnve8/e6555zneGEYppJsZamEW+KBafPh+36xsRY84v63kCAIfgYqrRPjeEIDCrjACLIwC3+FbZxFZui0JoxhDneowQK6sIlz1KEd01jDoRtYgVG04VP6rzJWjkqs41Se3QjzDwa0wGEJmpL+IJ7l+wMmiizNgSxNZJc7sGE93/njptbLLCNrmI55Oqoxg1rsajPcx1CMwBfMYw+tWuAWPrAYc6Z55LRAsyFHqLLGMlhyAppLVZvd+ZLjkRGzSml2o8/q98tZVQ/2NU6wDA/HaJSAvLxjyrAXPfLOJVbtQM9cX04t56wfMGU3KdUSyplcwZsEvru1rAVqLSvrfFvqcvD+3wX7LcAAg5tQ7i0qW5IAAAAASUVORK5CYII="};
g_oAutoShapesTypes[0][36] =  { 'Type' : "arc", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAMVJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj45sDpDiAGBSov4H4FRB/BuLHQHwMiO/gMuTTp09wNiMsUoAGIqsRBGJRIJYAYh0gNgbiN0A8A4jvk2MgOgC5PASIXYB4DRBvwWUgC5FB8wOIlwDxOSDOA2J+IF5KjUi5BsQNQGwEdTFVYvkFEHcAsR0QW1Er2bwG4klAHAXEbNRKh6Bk9ASITaiZsM8AsQE1DXwAxHLUNBCUm4SpaeB3aKLHzCmj5SHZACDAAExzMDRjtJ19AAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[0][37] =  { 'Type' : "bracePair", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAOJJREFUeNpi/P//PwM1ARMDlQELjMHHx4csLgTEZkAcDeXHQuklQAzy0lIgPg/EL2EaPn36hGogGlCCGlYHxPeRxGOAWByIe4H4HbKBhLycD8RNQPwcixzIoEYgzsXrZTTACMS3ccj9hsox0iVS6GIgKCY7iNDbDlWLMwwXQ8NlGRBfIcLAq0A8BykpxaIbiJzWHhFhqDYQJ0OTEl4vgxSUE+HCCiRHEIwUxkEdyzCgCsQcWMS5oXIkJWxQjNcDsSQWOQWo3BJSst5OKN0EdUkMUgqA0TuwBv6gL2CpbiBAgAEAVCYs6XklXh0AAAAASUVORK5CYII="};
g_oAutoShapesTypes[0][38] =  { 'Type' : "leftBracket", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAHdJREFUeNpi/P//PwM1ARMDlQELPkk+Pj4Q5QDEyVAhxk+fPsWQbSAQeAAxyIBaIL5PDS9HA3ETED+nipeh4BY1I4WR2rH8n9oGMg54OqS7gSM0DNWAmINaBi6G5mMpamW9nUD8E4gbkcRi8Qb6oC9gqW4gQIABACLNFMDAy/5VAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[0][39] =  { 'Type' : "rightBracket", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAHhJREFUeNpi/P//PwM1ARMDlQELIQV8fHyLgRQjEIO8Mg+I93/69Il8A4EgFkorAnETELMB8U5qePk51MBYaoXhDyC+TfdIGTVwYAz8T20DGQdXXkYC3EAsRU0DFYC4AogXU2rgYqSwmwsqbfAG8KAvYKluIECAAQAzrBXjwlCO7AAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[0][40] =  { 'Type' : "leftBrace", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAH5JREFUeNpi/P//PwM1ARMDlcHgN5AFnyQfHx+MuRCIuYC499OnTyfINhAKAoBYAojdqeVlUSBmpGYY/odiqhgoD8RuQLyXWgbOBuLXQNxFLQPdoPQUaobhBSBWo3bC/k9NA18BMSs1DdwIxI+AeDUQWxBSzDhafA0+AwECDADARBdOQgegyAAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[0][41] =  { 'Type' : "rightBrace", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAH5JREFUeNpi/P//PwM1ARMDlcHgN5CFkAI+Pj4LIFUExN+BOB4k9unTJ4pceAKIw4BYEogDqOllUHIQpXYY/qemgfuA2A2I5allYCcQvwLi2dQycAqUdqOWgWpAfIHascxITQNBhr2mhoHmQLwaiJ8B8QaCto4WX4PPQIAAAwCBBBgikPMdYwAAAABJRU5ErkJggg=="};


g_oAutoShapesTypes[1] = [];//figured arrows
g_oAutoShapesTypes[1][0] =  { 'Type' : "rightArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPJJREFUeNpi/P//PwM1ARMDlQELjMHHx4dLDQ8QzwDidVCMAT59+kSyC/8BsR8QB1HLyz+BeDIQ+xIylBgDQbHGCMRngbifkEtZkNiLoRrRDYO5EAQuAXEXEJdC+evwGQjSlEKEi68BcSsQl0MdsJYayeYOEHcAsSu695mweI9YcBeanLxxeZmRRAOtgDgSiHdTw4UgwzKB+BgQr8DlQg4gXoIlufxHizAbIE4H4m1AvBxfLMfiyXoToGxbIE6FenM5oXSIL2GDgD0QJwPxASBeRGnWY4V6+SAQz6M064HCkRmIjwDxXIKKB30BS3UDAQIMACLUMzq9j0bhAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[1][1] =  { 'Type' : "leftArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAANxJREFUeNpi/P//PwM1ARMDlQELjMHHx4dLTQQQewNxLC4Fnz59ItqFIMPcgZiRGl4GGeYBxP1A/J9kL+NwWTcQXyXFhSw4DHMG4i4gvg4VA7lwCRKbEYnNgBy+LFgMcwDiDiC+iyQei8dRi3G5EGZYGxA/okY6BCWNaWQYxojLwG1AnAzE1lRJ2ECwHIhZgTgNGtjHiDTjP75YXgT1QjqUfwxLwDPiMgxXslkIDQpkQ0GGxFCSsOdDDU3D5RJSDQSBuVBDM0gxkFDhMBuIj5KS9RgHfQFLdQMBAgwAxccr9mKxR40AAAAASUVORK5CYII="};
g_oAutoShapesTypes[1][2] =  { 'Type' : "upArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAOJJREFUeNpi/P//PwM1ARMDlQELjMHHx4dLTQQQewPxViBegU3Bp0+fiHZhNBDbAHE3ENtDDSfby3FA7AbEy4D4EhB3ArEjIUNxGRgPxE5APBOIj0HFHkANdcVnKDYDk6AuQTYMBu4BcRfU5RHEGJgKDSuQYcdxOOImEPcAsQc2Q5nQDANFwDQ8hsHANSCegM1QRljCBiabJUjiIEFGII7BYthiZP0gtcBkE4uRDrFoXoLHhbHkJBtceZKR3HTISO28/J9EcbILB/p6mQWP3F9oEmFES0p4vcw46AtYqhsIEGAAMwAyM982hWwAAAAASUVORK5CYII="};
g_oAutoShapesTypes[1][3] =  { 'Type' : "downArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAOJJREFUeNpi/P//PwM1ARMDlQELjMHHx4cutxBqISOSGMw7scgKP336hGkgFsAMxDFYxJeQ6+X/9ArD/9Q2kJFcAxkHhZeRY3kxka5ihMb0fyT1MdgMPA7E5kA8C4iP4jEQplkPiIuAeCcuF04D4t9AnAa1/RgeQzWAuBBq2HJcBoLAbCidBqWxGaoGxCVAvAvdMFw5BWToHxyGKgNxKRDvxWYYvqw3H4j/AXEmkqGyQFwGxPtwGUYoL4MKh79AHAnEn4E4A4gP4jOMkIEMSMmjHIi3EjIMnKYGfQFLdQMBAgwAMK4xGOPRVkEAAAAASUVORK5CYII="};
g_oAutoShapesTypes[1][4] =  { 'Type' : "leftRightArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATlJREFUeNrMlD8vBEEYxncF5QaVuG8hQkLHV9A4h5BTCb2K0jdQadx2hEaPHHKFRkJLR6VZieYuWb9JHslkzE52ky28yS87mfeZZ+fPOxPneR7VGUNRzVG74fBvI0kSN7cIW9By+lM4gWu7M8uy4AwnoVmQy/WTRtklj8Ie3AdWdgc7MFLGcEXCVLPxRSpNs3APFTOwBIfQh9gyjq2vyR3DAbzAo89wAtpwAa/qawWWbTSXsA1v8OkueRc+4KpClRjtu/bzzx5OQQ8GFQwHGtPwGd7AMoxVMBzXmFuf4Tl8qZjLxqbGnPkOpa8bsA/z8OCccGS1zWEtwDQcaay3bEwJdGEVnmWw5mg65qZK05UuWNgdfTesmbmx7miDht8Szgb2bg5OpS31fJlSeCrIxcr1vMl//2L/CDAAGotHmb91GeAAAAAASUVORK5CYII="};
g_oAutoShapesTypes[1][5] =  { 'Type' : "upDownArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAVZJREFUeNrM1L9Kw1AUx/FE/ANSszk6uApSHBxUFH0AQagIRcWhLvoAvoE4C6JL8Q/WQdAn6KyDSCefQAcHByFUoUWJ38AvEK733ioU9MAHSu/NyUlyzg2TJAm6GT1Bl6M3+xFFkW19AMuYxSOO8GpuiuP4RxWOYw9zuEKIXRR9FYbZO8xVWMA6ZnCPKppaW0QJdVziw6zQTDiNVVVzrIRmjGALnzjEsyvhjh7zFmd49zxZH1Ywj1MS3tgS1vRfogpbqBiJCvowgfake9skrHz7ysSaceG+o7q25UYdv3IirrVfN3YorrU/mBSiZjxWy3FNP85zHyXdt2lL2MAE7tSDb5ZkTTV92jZljWTVNymT2NDdL9STZoxiW316gBffpKQxqLsvqOqT3IGwpPGra747jl4+xtRvQ7jGFIbV2A+u08aXMBuxkt7Vk2Y39h1f4b8/sb8EGACXm3Y44qGohAAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[1][6] =  { 'Type' : "quadArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATJJREFUeNrMlMFKAlEUhh3RdNM8j9CiXLSUsloIUUpoIvgy7iNxYZSNSESrSrf1EK1bRJtxFQTjN3AGDtNcvcosuvBxx8udw/n/8ztOEASZNFc2k/JKvWAuenBd13SnChcwgeukC77vW3d4DqcwhANoW3eYsFpQhle4hSIcwQe8mF5yoikbJBfgBo5hLPvakvVLPxDlKp6vms2Uu9CALa0itkdWnYnHRg87sA9TkelIV7pDT52HFlRgLgn44+GI7VkGMLeI3DbsQhMPD5M6HErewos7Cb56sbOpKJqZJD9AHupwCZ9yrgudqOcnKdZblkNPovJlIflKe7csNqH0X+WTnrae/mTdj0MJ7uBdfs+kSGXTv94b9CWX37AHA3jctGC47kVqXbI5WmWs8++/2AsBBgC2PUqU0f0+tgAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[1][7] =  { 'Type' : "leftRightUpArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAS9JREFUeNpi/P//PwM1ARMDlQELjMHHx4dLjTEQFwPxbyDuB+IL2BR9+vSJKBeaAXEREM8E4m6owcbketkaiPOBeAoQHwTiK0A8CWqBOakG2gFxFpSdjSSeD9VTCLUQdxiigUNQDAKLkcRBSSKSmrHMSG6ysSTCEEtiDTQF4hw0b2IDOVC1eA00AOICqDgPFhf+R9ObD9WD1UA9IC6Hprk/QDwDGiH/0by/GIpBamZB9ejBFcDyMjCnLAFSC4B4D4kR5QLEicCcEo3uQpCNzGRkX2ZotsRIh+1AXAfEQkDshRR2/6FsbJGzDYh9gLgZm5dBlC4QV0ENAHnhLx5XLYPKgxxyGVfhcBmIO6Hif/F48y/Uxd1QPQy4XIhcypwiEHagNHgavfhiHPQlNkCAAQB56k3cGux8WQAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[1][8] =  { 'Type' : "bentArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAORJREFUeNpi/P//PwM1ARMDlQHVDWRB5vDx8RGrzxaIDyMLfPr0iSIX5gCxJTW9zAzEhUBshtfLUCAGxMlArAoKBSD+h8PiWUCcD8QTgfgULgPlgbgZiA8C8QIgfk7Apd+h3u8D4gvYDIwB4kNAPJdIrwsCMQcQs+FyoSYQT4OyrYE4AaoJBBiBGDkXzADiWCCejM/LnED8HspOgHr7KBaXrQXiVKhPDhOKFGTvHMUh9xuIVwLxLkLJhtiMvQmI15OaDhnxyC0bFIXDf2oYyEikl4krbaBgDZY0RzRgHPQlNkCAAQDBgSnpHlmAAgAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[1][9] =  { 'Type' : "uturnArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATpJREFUeNrk1DFLw0AchvGmiohCRnHp6Kq7IkIXV0EEwUXoqg4qrjq6iLaCIIIdCoWOfgK1UISKSzcdBJcOIghZWlGJz8EbCGnTC5Ktf/jRy1369nqXnOP7fibNymZSrtQDR8MXrusGzUmsYA7TmEAbDdygGw3yPK83UDWLbbyiijf157CEM1ygZZ0hNYV9lHEbGftUiPnBXRzg3Ra4ikeFjWEN8xp7QE2hdWzg1LYpedyrvYkZlMS01zV2h4Uku2yuX9RexBGe5RDLGmvrc9wW6EtchcecJJvSwVekz+xsQff+qq+re68xoiVp2B7sYAZmTS81u/PQeEl9J0FYvxk6MeHmC9/YwRU+sIUimoP+8qBq6jHZw4/CnmxraCsTcKx2ojclbkfD1Up8OCikorX810HpDN8B+yfAAIr4SDocULDSAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[1][10] =  { 'Type' : "leftUpArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAO5JREFUeNpi/P//PwM1ARMDlQELjMHHx0esHj0ofQlZ8NOnT6gGEgmMgbgYiP8AcR8QX6DEy2ZAXATEM4G4C8o2JtdAGyDOA+IpQHwQiK8A8WSooWakGmgHxJlQtdlI4iALGKGGWmNECh5wCIpBYAmaXBQpXtYlYBEjKekQlDQqKUqHWAxjpIaBIG9WAfEaIPaHhtl/qOH/STXQAIgrgHgt1MA1BPT+JzYMiU2bjIRcCMpGbdDw+wrEEUjeJegyuC2w4gupcACFYxnUskhiIwNWOGDz3mVoXv1NRuGB1YUwoAHEN0h1IeOgL7EBAgwABxY3P95MS0wAAAAASUVORK5CYII="};
g_oAutoShapesTypes[1][11] =  { 'Type' : "bentUpArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKpJREFUeNpi/P//PwM1ARMDlQHVDWSBMfj4+IhRrwelLyELfvr0CdNAIoAREJcC8S8gngDE5ynxshkQFwHxTCDuBuJCIDYm10AbIM4H4qlAfACIrwDxZKgFZqQaaAfEGUDMCMTZSOL5ULFiqIVEh+EhKAaBJWhyUYM6Hf6ntoGMBBM2ECyGKvyPpuE/PgPwGQjSFDN48zJa0viPFlZEl3GMI688pLqBAAEGAHWoHwOONhXMAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[1][12] =  { 'Type' : "curvedRightArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATpJREFUeNrM1LFLwkEUwHF/KhIRv70/IDchaiwkJ1uChkAwlailraWh/6GohgaDiKghGmpwEKKk2lptbHKvpR9tar++D15wHIbeTwcffBDv9HHv7t55YRjGRhnx2IgjaQ/4vm8PTWAR85jR71JWOQiC/gmtWEYGaTRwhxaqA6/QiByKuMQx2sZcyjWhlFbGKZpYwxymnfdQYw81JHCEd1zjDZ0oCSXRFFZwhefIp6xjIo8DLXmoe9jps4BklIvdxT12kDXGz7AVZQ9llXJrL/S05YRfdG8X8IlblxXuY1Xnd/GBdZ2r6NxSrz969uNgtF5Oy7vBqyb9C0m2SetVXDrlSUucRQHb+DauVdu19SQe9dp84RCTKGEDJ64l2yH9e64vjXRNvddr4/Ie/ujngyT770fe2L/YvwIMAK6nR5IgILrvAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[1][13] =  { 'Type' : "curvedLeftArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAUJJREFUeNpi/P//PwM1ARMDlQELNkE+Pj4QtQTK/QnEt4H4DBAfAeIfMHWfPn0izkAoAGnMBGJFIDYC4nAofQmId5DkQihgB+LfQHwLitcCsT0QxwHxLyDeR6qBjEjefg7E54B4MxB/B+JkIH4MDQpUTdhiGRqGyJbqAbETEKsD8WIgFgJiX2AYJpPiQhj4A3UdCNsBcQIQ7wZiZlK9jA0cAuKPQFyMK8kxEZGsWLCELSO5CRsURnOQ+CAv50GTzV9SvRwMxFbQsDKCGqYDxAuAmB+apIh2oSMQBwBxPJQfCcSvkcIuEIh7SHFhIhDPhbJjoLQoNGGHAvF8IL5Bigt/oVnGA8T90HS4EFcuwedCUERkA/EeaG4B5Y6DQLwB6nUGUg08Ac0NoFzxH2r4L0rLw23QHMFArGE48/KgKrEBAgwA29xIVqtGOtUAAAAASUVORK5CYII="};
g_oAutoShapesTypes[1][14] =  { 'Type' : "curvedUpArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATxJREFUeNrs1M8qRVEUx/Fz/clEp26SF1AGiriKmEikmwdgoIiUKxNewMDcxIhSZKIkBl5AZKDEhIE8wx0cf5I/Hd9Vv6PtnE0Gd6BY9anT3ueuu9beq5OL4zioZFQFFY4/mLAmeQjD8Ke/GcQ43rCPQ1uMouhzQmIDdbBrf8a0J9kYiljHAxbQgK1MhYpJvCq5G7WYRQElPGp9DmtKupI+w2o0+o6DeEGH3rfq6rW+qo46fZdyg24936E5VeUUlrV3r31LNqMzzSS8xIgqu8CA5wxt/wx5LOEcT1+NzRFu0YsDtKvNJPrRij30qaPN7+bQbu1arbVgF/NoQxcmsI0ejOLEuZyPyCUfB2cOhzUeO2jCkL2HYxs3zaFNwambKJlDX8JArS66f4yyKrIqr9KVZRL+f21+T8J3AQYAPiFKAsF0mB8AAAAASUVORK5CYII="};
g_oAutoShapesTypes[1][15] =  { 'Type' : "curvedDownArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATRJREFUeNrs1M8rBGEcx/EZsdkwf8S2OdiDHOTmpJwcrNOW9rilOIj8Fbi4kMivu4t1QcnBRSRJDv4CiZqQtIz3U5/Znp52xmUPW3zr1TzzzPSd7/M838aPoshrZrR5TY7WT9geD4IgsOf7MW/d+3jGO3Zw5yYKwzCxwlHMYg9HiE/tBreYw9CvFSrGUMQqOjGMRWQwhWU8YhpZnKYl7EIBu1rSEjZVmaf5GSzgWx+7wFvSoZgXcjjDOK5xbj031dxjApfIo5x2ygM4RE3jkwZbVMUgXpSsT1vTcMm9WqKJHjw4yTbQoSK68aptWlcXTLoVfuHJuq9Z44y2wLxTUTJPh2PiKumUt3T9cOY/sYKSOmBNSU0LHWO73rDxz8Fp7LQY0fJMtfs4sBvb///b/IGEPwIMALziR3CVg1ekAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[1][16] =  { 'Type' : "stripedRightArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQdJREFUeNpi/P//PwM1ARMDlQELjMHHx4dPHTcQzwTidVCMAT59+kSyC/8BcQAQB1HDy4xA/BuIJwGxHz5DSQ3DM0A8AYh9cRnKgsReAsQxQLwYiGOhNCOS/E8ofQGIe4G4CMpfh8tAdPALiJNxyF0B4g4gLoVauhabl0lNkLeAuBOIXZG9z4QjAogFd4B4FhB7YfMyI5pLiXGxDRCHAfEefF4m1oUgw9KA+DgQr8DnQhjggMb8fyyRZAfEKUC8HYiXo4QXrHAgkPV4gHgi1ECQYalAvBuIF6FnPRYSIgBkswMQJwHxPmTDyM0pbFAXHgTi+dTIeqAwPgLEc/EqGvQFLNUNBAgwAKEmOjXb91BaAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[1][17] =  { 'Type' : "notchedRightArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAARhJREFUeNpi/P//PwM1ARMDlQELjMHHx4dP3RIgXgfFGODTp08ku/AfEPsDcRC1vPwLiCcBsS8hQ4kxkBWIGYH4LBD3A7EfEAcTDENoOKFHOSOU/gGlLwFxFxCXQtVihCkjLNkAI8UESGUD8Sog3k7A1SpAXA5Vtw5XpJwB4k4gDoRGAD5wB4g7gNgDPUzRw/AGEO+AKpIlYOhdIJ4GxN64whAENIDYB4inA/FjAgZaAXEkevAgu1AaiAuAeB4QnyDCsAwgPgzEa3BFymK02P2PFMs/gTgZyrYF4lQg3gKNQJScguzlWDwumotm2DaYYfjSISFgD3UlKMxWEJOw8QE2qGHb8BlGavG1nZBhKJEyaAtYqhsIEGAAeDhDGfrPOf4AAAAASUVORK5CYII="};
g_oAutoShapesTypes[1][18] =  { 'Type' : "homePlate", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKtJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj41sCZcIClRFJ3X80/kQgPo1s0KdPn1ANhIIYIhxhAMS5QMwGxEep4eULQDwdiJOA2IZaYXgGamgKEDtQK1JAhk4F4gQgdsFmIDkpHBQxe4A4DpuBjGQYaALEjkA8iRouBBmWAQ3LM5S6EGRYJhDPQDaM3EjBaRh6wgZ5eQkWA/5jcf0EbIaBvTlafA0+AwECDADcmSPoGVCwUgAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[1][19] =  { 'Type' : "chevron", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQlJREFUeNpi/P//PwM1ARMDlcHgN5AFXYCPj28JkAIFLCMWehIQn0LX8+nTJ9wGQjWlA/FCID6EJK4PxLlAzArER4l2IdQFP4A4H6p5L1T8IhDPAOIsqGuPkBKGl4C4F4jDgdgdSfwMEE8D4hQgdiA1Uq4BcRcQBwKxD5qhU4E4AYhdSI3lO0C8GmogG5L4aSDeA8RxQCxJioE6QBwNxBuA+BeSuAkQOwHxPCB+TihSkA0rAOJlUNcgGwaKmEVAfICYWEY2bCkQ70czLBOI5+JKOtgM1IYmmQVoSQNm2GwgPoHLW4zopQ00pzAg5Q4GJP5EaCzjzCnYDAS5+g8p+RevgaPlIckAIMAAy7BEdQf3HY0AAAAASUVORK5CYII="};
g_oAutoShapesTypes[1][20] =  { 'Type' : "rightArrowCallout", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAMNJREFUeNpi/P//PwM1ARMDlQHVDWSBMfj4+JYAKWT/M0L56HQsNoM+ffqEaiAUxBJwwGJaehnkI1Nqh2EiEHNTYiAjEhsUno+AOBiXgcQmyMVQ74IMnwvEdkCsghHLaLbjAjFYxNYBcRwQ15HrQnSwDYjFsHmZkUwD3YD4DTYv/ycyqSAn8kIgDgXiDnLDEDmngAxPAeIjQHyXWulQFojXUCth/4cmoa9YCwciw5CRUL5nwRLoDEgBTzJgHPQlNkCAAQDOEiorysvIOgAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[1][21] =  { 'Type' : "downArrowCallout", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAORJREFUeNpi/P//PwM1ARMDlQELjMHHx7cESOFyLiMeM35++vQpGcNAIPgBxCkkOogHiCfQ1MvUMJARl4GMZBr4H5eB/weDC//jC8P/lLqOWmGIPWEDATsQL0Fz8S8gTkZKczPQfANyxE9cBsZgSbQT0Sz4iWQByenwPwnZD6sLsXnrJ5oFyMGC1bXoLvwCxI1A/BSK25DkvgJxARBfAeIPQDwLa7TDykNgaYPuck8g9gPiA0C8CoidgDgEiI8A8RqoBWAALG0IGggDokAcD8QaQPwCiOcB8T10RVgNHLQlNkCAAQAViD0/3AQyCwAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[1][22] =  { 'Type' : "leftArrowCallout", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAMhJREFUeNpi/P//PwM1ARMDlQHVDWSBMfj4+HCpWQzEjFD2fxxshk+fPsWgGIgHgDTFEFCzGJ+XTYF4CRL/P5GWYjWQC4jj0AxhJMLA/7gMDAHi52TEBVYXqgCxPRDPhvKXQPF/UlyIHCkgr64F4tdAHEsNF4oC8TZqJuw3QOxOpjlYvbwQiMuA+CwQT0BLvDHkePkOEB8F4hSoQTFkhCVGslkDxLK4vEOOgV/R8i7JCRtbXj4BxWRlPRYifbKYWBczDvoSGyDAAGoXK2EaUxTdAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[1][23] =  { 'Type' : "upArrowCallout", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAOxJREFUeNpi/P//PwM1ARMDlQELjMHHx4dNXhyIE4BYHYhfAfEcIL6DrujTp08EXcgMxEFA3ALET4E4C4j3A3EZECcDMRcuFzLCwhDJhVpAnAjEv4F4NhDfR1IvBMRJQKwExEuB+Ci6C9EN5AHiGVA5kMQvqItgctORDIfLIRvIgubiL0Acg2TABDT5n0CcQs1YZiQ6loFgMZKm/1D6B5p6NiBeghQkMDUp2AxEDi9sABQcsWhiGMGC7GVyswwjtXPKf1wGMlLbhf/JdN1/anuZkZpeZqRf8QUE7DgS938CrvuJtbQZtCU2QIABAN6bOsjC9WPGAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[1][24] =  { 'Type' : "leftRightArrowCallout", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAANdJREFUeNpi/P//PwM1ARMDlQELjMHHx4cutwSND/IKIxIdgyz56dMnVAOxAJDGWBxyi6ntZUa6hSETHu8wEqF/CSEDTYH4H1IYEgIgtVa4DNQH4nyo2GICLvwPVQNSmwXVC/EWLGEDk80CILUWiDeTGGxeQBwGTDYJ6C78CcTvyIiHL1C9GC4EObsEX+JFizhkdd1AF15EdyFIYC40oGOJSIcwyyZD9WKN5QNIYv+JTOAnCaXDGBLSYQwpOeU/tYsvRoqKLzyJlxHNxYz4XM846EtsgAADAAV0OpbwxfV8AAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[1][25] =  { 'Type' : "quadArrowCallout", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAR5JREFUeNrMVEEKwjAQbEVEEPouEQW9KGo9efJBHj1oIhUPelIP+gRfUzwIInWCU1hDWqx6cGFoEpbNZma2fpIk3i+j5P04yukiCIKsnAbQB3xgB0SupDiOXwtmRBNoAyPuFWA4Wn3y5BnQA/bibMtLNFDLfbIjxqKrDdcdICwqihZfTe7S8HmmxGW5HQ7JURp2N6FVyFzQBdauDg3xdfKk33CIJhUtFn3ekBobtlFCzaKhYZvQ7vCbkbm7ODyQm6XgKktRRf4Uc04uDiN6bsikvI595hicgXmWyhFHTRKfWJNiF56+HAhR8tSUdpHCVYHru7NsRq9iWUiLrifApcgsj+nJgWXsI7u8FJ1lj8a9AQvuT1IAp1p//8d+CDAA/dNNeDNMnqcAAAAASUVORK5CYII="};
g_oAutoShapesTypes[1][26] =  { 'Type' : "circularArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATlJREFUeNpi/P//PwM1ARMDlcHgN5AFmcPHxwdjcgFxABAbALEElP8MiI8C8UYg/oFu0KdPnzANhAI9IM4D4rtAvAyIHwIxKObkgNgOiCcC8VQgvkTQhUAgBsSlQDwfiPehyX2AGgKysAiIy4D4FaEwDAbik1DDWIE4BoinQV0UDRUDGXoQyicYKc5AfAjKTgBiFSCeBMSTgVgViCOgciA11sTG8i0oDQqvBiC+AcUgtjtU7imU5iAl2TASSCGMxLjwO1KSwJYnYWI/0NTijGVstjoAcTLU8v9ohi+Dik+GplEMF4IULYZiGDgAxDOg7ElI4pOg6vthhoFdhFzaIOUUbMAciHOBeDYQvwbiCqjLThPKKbgAKH3+AeISIP4NxBOA+BxGTJHgQuSsyYCe9WAuZBx5BSxAgAEAge1QGI/UrLEAAAAASUVORK5CYII="};


g_oAutoShapesTypes[2] = [];//Math
g_oAutoShapesTypes[2][0] =  { 'Type' : "mathPlus", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIZJREFUeNrklEEOgCAMBKnx3BfC6+SF/cAqiYeGUBCt8WATDkAzYdkFAhA8awnO5Q5c9YSZWz35GPpeUt0gItMnTC2Qh2TyAOJNUzBlymlAD0INk8patIAYXH40UmBKphvRQ09yqU3BUUnKCqL3TeBQktHz7Vt2zyE9yaFV+SqQ/vfB7gIMAH7EHoje1ggXAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[2][1] =  { 'Type' : "mathMinus", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAE9JREFUeNpi/P//PwM1ARMDlcGogSPBQBZkDh8f3xI0eVAiZcTCRlHz6dOnWKwGQjXFkuioJfi8zEhVL2OzEc27BIOAcTQvjxo4CAwECDAAkpISzEheW/IAAAAASUVORK5CYII="};
g_oAutoShapesTypes[2][2] =  { 'Type' : "mathMultiply", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAS1JREFUeNpi/P//PwM1ARMDlcHgN5AFmcPHxwdjxgPxYyDeh0VPHBD/BuLlIM6nT59wGwgFYUDsCsT/oT7Yg2aYE1TuLxCvwutCIPCE4hgofzEQMwPxTqgYyLAsqAtnAPEvIN6Az0ABNLFYIF4CxMZArAHEGUD8DYh5gJiNmEgBhcs2qMtgAOQyLajLYIZNB+KN6K7DFcu4DGWAGgby6lYgXkNKsgEZegfN0C9Qw64B8QpS02EkEKtCw5AbzaWgsAwixcAIIPaGRgAMLEFLOgHQ5EXQQJBhPlDDviCF2SM078dBLQ0jZOBfKP0PyTBQbqkC4u1oLv0JxN8JJezVQPwDiKdB5fYD8Xyo3DJoDlkCdf1mKCaY9TZDbVYE4rlYYp8ByUAMwDjyCliAAAMAEhVJZUUpwTcAAAAASUVORK5CYII="};
g_oAutoShapesTypes[2][3] =  { 'Type' : "mathDivide", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJJJREFUeNpi/P//PwM1ARMDlcHgN5AFmcPHx4dNTToQ+wPxRiCeiS756dMnkl3oBcWe1PLyTiDeBqUJAkbkZIPDy3gBupdZ0OSXQGmQLYw4zIDJwegYfAaCFMWS4MDFhMKQkUQfM+JNNlAXLsHjPQZCQUL1SCEm2YAS9lYoTZV0CErU3tRM2DvITtij5SFZACDAAHwrKVKkJoeZAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[2][4] =  { 'Type' : "mathEqual", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAHxJREFUeNpi/P//PwM1ARMDlcGogZQDFmQOHx/fYiDFCOXCoh+Zz4iFZvj06VMMVgOhIIZERy3B52VGqnoZChbjUY/iVSgbJWcwIucUYBiS5SpgGOJ04WIc3v+Px5Uo4Y7Ny7EkOnAx3SNlCba0RigtYo2U0cJhcBgIEGAAKIUicWs8SPwAAAAASUVORK5CYII="};
g_oAutoShapesTypes[2][5] =  { 'Type' : "mathNotEqual", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAUVJREFUeNrM1M8rBGEcx/EZrbVJkxzJ2WXl4ERxcaHk6LRysdmEi4sbLsJJkkJxsP4EVxdHpbTtxUU5yEmZvSjq8X7qo7ZtfqynOfjWq3mmmXnmeZ7v93l8Y4yXZXR4GUeu+SYIgna+6cYhPvGNHmyEYdhwHeEynrCOF7UbrlOeRBFnmMAwzmOnTFRTOuzCgQZS1vfHWIjr0EYpprMtfOAe23jQWlZdsjyDAZxiGv1qJ2dZcQUfRlcbBeyiD4v40jp6ei+2w1LED/fwjEfs4w4nbdVhRFJyKokLzNtSxTjG9NxvHUhSUoawgyMMYk7TriUNojUpv+uRxypuVbhratciBmDSkmL/2Il3XGJJ9yN61pys1DW0BTqKTU3V7oQp1WDd5bTpRQU3eMWK2nWn00YbP6/pzeIN13/Z7P6/P2Az7/BHgAEAg7hCrKWemhIAAAAASUVORK5CYII="};


g_oAutoShapesTypes[3] = [];//Charts
g_oAutoShapesTypes[3][0] =  { 'Type' : "flowChartProcess", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAGRJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj41sCpEAByogkj85nwCX36dOnGBQDoSCWTIctGfRh+H/kJRtGbAb+H/SRwkhtF/6nataDunAxEvs/Es2Ahc2Ahc/AOFoeUgwAAgwANnoWy2DLy7cAAAAASUVORK5CYII="};
g_oAutoShapesTypes[3][1] =  { 'Type' : "flowChartAlternateProcess", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAM1JREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj44MxU4DYAcoGBTAjmh6YGIg+AsQzQYKfPn1CNRAKUoHYAIgrgfgxAcfIQNUlA/FcbF5OB2IdIG4kwjAQeAJVawD1FYaBNkDcBMSvSAgykNoGpCBCMRAULm/JiIe3uGKZkhT+H5cLB3fCBjlbmAwzBJF9h2zgQWgyECfBMDFoLB/AZuAcIL4MxHVALEuEYTJQtZegeiERASu+kLIeKIHb4shq6JF3AGYYLOsxjpaHFAOAAAMA+x8uqNzuaL8AAAAASUVORK5CYII="};
g_oAutoShapesTypes[3][2] =  { 'Type' : "flowChartDecision", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAARJJREFUeNpi/P//PwM1ARMDlcGogZQDFhiDj48PlxpHII6BWj4diE9hU/Tp0ydUA7EANSBOAGJ2qEGsUIN9gXgpEN/A60IkIATEEUBsAMTrgXgXEP+Fyp0GYi8gLgHiO0C8HIgfImtmhCVsoJdBhgcBsRMQHwfi1UD8DYfreYE4EohtgfgEEM8Hevkbugs7gVgMiOcB8X4CYf8ZiGcB8WMgjgJieSAuw+ZCNyAOAOLbQLwSiB/hMFAWGixyQLwKiA/DIgXZQJhibqihjtAYXQ51EbJXLYF4OxBvAuIfyLGMzUDkyAkFYhMg3gIV8wPiy0C8AohfYEs2+AyEARkgLoemw5lAfAlfOmQcLb4Gn4EAAQYATMZPrADb/lgAAAAASUVORK5CYII="};
g_oAutoShapesTypes[3][3] =  { 'Type' : "flowChartInputOutput", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPJJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj40OXUwXieigbFNCMeOgnnz59qkAxEAvwAOL7QFxLwFHVQHySkJdBzjUG4t0EDJMHYgUgPkzIQBcg/gjExwgY6AfER4D4Jz4DQcFgB8R7gPgPHsOEoL7YQyiWDYCYF4j3EnCdJxDfBuKnhAx0BeIDQPwNj2FcQGwPxLsIpUMJIFYD4q0EXOcExD+A+DwhA92B+AIQvyOQdl2gvviDz0AOILYE4s0EXGcGxPxAvJ9Q1gMZ9hiI7xEw0Avqi/d4sx40MmSBeDGUz4gk9x+NvwSXbYyj5SHFACDAAFJ5MLnz4LRIAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[3][4] =  { 'Type' : "flowChartPredefinedProcess", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIpJREFUeNrkVG0KwCAI7Y397oTrdOuEXcAVJCxp4sIfgz0I7YOH6VMQUfDEFpzxfcKdnRhjvp23xOJhL/0GlFKOgbBfprrObi3gt3n2ZQhrASw5fKMj0ghpIUK1yitEsjhusoEXoSmH5F1lLERIXrKBlkN4yAY8D0Uva7qc9XKovZwGwv/Mw0uAAQDFeyYk82o5YAAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[3][5] =  { 'Type' : "flowChartInternalStorage", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIhJREFUeNrkVFsKwCAMM2PfnnA7XT2hF+gcOJBiXd3KfhYQKcSQvgQzB08swRnugmsbxBipXKjhVQuMBHLOmypYcRJSObvBUBo6FCQSDtvuQcSqIKpDeupQNsVUtw5fFYRGfDs2VoewpsxeKbs7nAV/vsuYfA/LplBNJd3MaLdx+N9/6C54CDAA2wgdusu3e9wAAAAASUVORK5CYII="};
g_oAutoShapesTypes[3][6] =  { 'Type' : "flowChartDocument", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAANdJREFUeNpi/P//PwM1ARMDlQELjMHHx7cESIGcy4hEowN0eTj96dOnWBQDoZKxZDpsCTYvM1Lg0//YDKQkdhipHSn/qe1lRpolG5p6mYEaXmah0CAtIJbFmlOgwBqIjxIwhBuIfYHYCYj/APFTID6GzcA1QJwBxDxAvBOHYQ5AHAJlLwPiAzjzMhBsAOIPQBwDxHpAvB+I7wKxFBCrArEd1HW7gXgLEP/AGpiw4gtYOMDEBIE4DIjNgJgdiH8D8R0gPg215Dc2g4CFA6qBg7Y8HPwGAgQYAJMWMDrcTODBAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[3][7] =  { 'Type' : "flowChartMultidocument", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAANNJREFUeNpi/P//PwM1ARMDlQHVDWSBMfj4+NDllmBRDwofRiQaDj59+hSDYiAOzbFEOmwJhguxSP5HY8MAugtjsHqZQpf9x2bgEnwKsbguBkmeEZcLY4h02WJ0gyhNNoy0Sof/qW0gI3p6ZSHGGzhctoRQsgEp4gTi72iaQVkoEIidgJgHqu4fEIfhzXpQF3YB8XIgPg/EekBsBsSWQPwMiOcC8VWopcw4wwBWfAHzshiQCgdiLSAGsb8A8UMgXgfEFwiFATAvoxo4cspDqhsIEGAA764zGxxK3mUAAAAASUVORK5CYII="};
g_oAutoShapesTypes[3][8] =  { 'Type' : "flowChartTerminator", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJlJREFUeNpi/P//PwM1ARMDlcGogZQDFhiDj48PxgwB4gAc6kFJghGJ3gLEK0ASnz59QjUQCryA2A2IY4h00AKowcuxeTkIiD2BOI0EHyYAsTsQR2AzMBCIc8kINpChrtgM3ArEC8kwcB4Q78RmIChwNwHxYhINAzlkFUYsQ8FaKL0ES8zC2MhgPRCvQxZgHC0cRg0kHQAEGAC/uh4SLAXcDAAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[3][9] =  { 'Type' : "flowChartPreparation", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj40MWNwDiKiD+BcSwQGaE0iA+BxC3AfF5mIZPnz6hGogE3IE4EoinAPEhHA6xA+J8IF4OxDuxuhAKbIA4FojrgPgeHp+BLHoMxE1A/BWIj2ALQ2EgzgDiaQQMg4H7QDwdiNOhejEMrIR64RgJcQBSuwwa3hgGygDxQzIi9hFUL4aBz4FYlgwDpYH4CTYDJwFxEhBbkWCYNRCnQVMEhoGgQN4OxFlArESEYYpQtdugerHmlEXQxFoPTUK4gC0QNwLxBageOGCElTZoOcUF6hVYTkHOJQzQnDIbiHeh5xTG0eJr8BkIEGAAU5g5pV5OFcQAAAAASUVORK5CYII="};
g_oAutoShapesTypes[3][10] =  { 'Type' : "flowChartManualInput", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALBJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj4yNFHy8QGwCxLRCrADHrp0+fYlEMJAC4gFgfiDWBWBuIFYD4HRDfAuIlQJyM4UIcBmhBsTzUgNtAvA2IrwDxSyT1idgMNEYyBOSC90B8A4cB6IARm4FFQHwGasAlIH5DUaQAASiF95MZuf+pnWwYsRlISR7E6kLGweRCBmq7kAFXwl6MZvB/NAux8VEcwjhaHlIMAAIMABY0JL85G87NAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[3][11] =  { 'Type' : "flowChartManualOperation", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAM5JREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj41sMteAfEDNChf9D2bCAZkQSg8mD9Xz69CkWxUAg+A3ES4B4H4mOcgLiGGxevgPExmT40hiqF8PAw0CsRoaBalC9GAZeAGIhIBYnwTBxqJ4L2Az8DMQPgFiHBAN1oHo+40o2V4HYiAQDjaB6cKbD60CsSoKBqlA9OA28SEI4wsLvIj4DvwHxQyLDUQeq9huhrHcNiA2IMNAAqhZ71kMzMAmaa/Blve9APA9dM+NoeUgxAAgwADztL3+YYwZvAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[3][12] =  { 'Type' : "flowChartConnector", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAOJJREFUeNpi/P//PwM1ARMDlcHgN5AFlwQjIyNIzgmILYFYBir8BIiPA/E+YNj/waoPW6QADRMEUsVAfBNqwBOolAzUAnUg7gXqfY+hGWQgMoa6ugWI/dHlkNT4A3ErSC2GHBbFbkAci8swJHWxILXo4tgixRLqTULgOFQtwVhWAOIHRBj4AKqWaskGFNZ/iDEQq81YgAxS7OM1EGvYEBvW2AzcB8QawLTojyfRg+Q0oWpJStg3gPgoED+DSkkBsTXUsB5sCZsRV/EFzXrOUAOkoMLPoBbsJSnrjZaHJAGAAAMAXnqVHzpkxZcAAAAASUVORK5CYII="};
g_oAutoShapesTypes[3][13] =  { 'Type' : "flowChartOffpageConnector", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKdJREFUeNpi/P//PwM1ARMDlcEINJAFXYCPj28JlAmLLUYsbBDN8OnTpxiCBkJBDBGOWTJ8IoXYlP5/wFzISIswTAFiLhxy3ECci8tibAaWALEEEPcCsQ2anCVUnA+qDtN76KUNMGHDmI5AHA3Ej4B4AxC7A7EGEC8F4n3QhE2SgSAgCMTFQKwAxOeBeC4Qf4BJkmMgCHAAsTIQX0WXIMrA4V98AQQYABgvLZyQTKa8AAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[3][14] =  { 'Type' : "flowChartPunchedCard", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAI1JREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj40MWVwPiWiibkQhz/n/69CkWxUAkYArEWUA8AYjPEumwJbi8bALEmUA8hQTDwC7EZqA21LCpJBqGEizIBlYC8TQyDMPpQgYyDaNJsmGktoH/6eLC/9TOeoxUzXpQFy5B4zMiuZwRR9ihiDOOlocUA4AAAwC7Ix0HHHqu4QAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[3][15] =  { 'Type' : "flowChartPunchedTape", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQtJREFUeNpi/P//PwM1ARMDlQHVDWSBMfj4+AiplQBibyBWAWJZqNgLIH4ExKs/ffr0HN2F1XgMEwfiWiD+DMRzgTgBiGOAeBJUrArDhUCgATV0MxC/B+LHUFdpAXEAEG8F4m1oFoFcNx+InbEZyAjEV4E4FIhFgJgXiF8D8RsgngfEF/D44D82A0GCG6B4cCYbxsGUDhmxGfh/UHqZhQQXmgGxCzQ5yQDxb2hOOYbLQHwuTIAm8C1ADMpiD6AGg7JgEC4DQbkjF4gPAvE7IH4CxApArAfExkBcCcRfkNS/g2JQZqiBuwpWHgILB24g5QXE+kAsBBKCagBlr1VQGicAFg6oBo6cAhYgwADdGz02aKj1UwAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[3][16] =  { 'Type' : "flowChartSummingJunction", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAZ5JREFUeNrMlMsrhUEYxg+5bo6OkpNEkVyWiEiUy47/QNnJYcFC2dhZyYbIbWHjD7BhYyMWLmFFpOSaKCXOhlw6fqPnqzHOF4uz8Nav7zIzT/O+7zOTFIvFAomM5ECCI+GCKd5LMBh0x5qhDoogHV7gHDZhzZ0cjUa/nkleDS3BHOiGXNiAC3iAbCiGBriDebj/TbAQhuEGRuE5TlaZMAT5MAKXtqBdw1TohzNNLvcpUwXkwSEMQJpfU1o1OAYLEIEqR6wGemEOJrW+1U/QNGAb3lX4BS2u1HitajsN+/AB6/r/s8tEASxZ31t69mlhkyXmxTF0+Ama9ycnRSNaCm2w4ogFNN/UPkO2+paySTXkLDC7aoRViVY741nw5om5gqb9JdZ3C3QpzUX5LuKIGidc+TVlV7tJ0ynplNiexndgBnrU7WTN37UFbWN7lnmUwacsMTuqtNMT+XXQpB3P2K8woUkmjSMfYx/oOJbBuGoYd4fev7D8F9IlcKqzG9ZZNmma7czC7V8uBy/aoV7+9G7ha5l++dfb5t9esJ8CDACjlncwTb309gAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[3][17] =  { 'Type' : "flowChartOr", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAVpJREFUeNrMlE0rBlEUx58rG5tZkCQLFNnJ0nvxOXhKig3FlgU2drKwkp5Sz0Y+g428LZWSlPKWshA1JSWM36kzdbvP3OmqWTj1q5lzzvzvPWfOvSZJklKRVlcq2AoXrE8foihyY/0wBK3QAs/wBIdwbifGcZy7Q/l4HSbgESrq31XRWViBxpCS22AVbmEB9uFKY5ewB4vwCmvQnCco5c9rOTvwZcWM9fwBW3ANc3mC49JKqAb2v6L9HfYJyg840x2EmOQdwahPsANu/jglkt9uO0x6UhibqqdnqSWOP33/YWzKNXOIfcO2lu2aLDaZ4R9w/XbJ99DlKc14/JJ/5xM8hRFoCOxfk+Yf+wQP4B2mAgWn4UU3kikoPdyEPphx+uuef4l3an725aD2AMv6wYZeBBf6R3ugV+dOzvgSvNU02xobNzYGg9CtC3/q3MkiJ77bxvz7G/tXgAEAfNRRrsipRBwAAAAASUVORK5CYII="};
g_oAutoShapesTypes[3][18] =  { 'Type' : "flowChartCollate", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQpJREFUeNpi/P//PwM1ARMDlQHVDWTBJsjHx9cCpOShXEY0aVAYPfr06VM10QYCAScQLwLi3VjkfIHYgVQvzwTiGJBj0cRFgDgMiKeSauAtID4NxHFo4rlAvAeI75ETKfOA2BCIdaB8R6gLV5Aby9+AeDkQpwIxPxDHA/F0IP5JSbIBee8zEHcC8SkgvkKNdHgdiEWBeBe1ErY6EL8BYldqGOgCxAJAXA7EpkgRRJaBXEAcAcSzgPgDEC8E4kwgZifXwEQgvogUEQeB+Dk0YZNsoBoQm0OzH3oOcgJiRVINTAPixUD8EU38NRCvAeIskkobIPgBzXbx0NIFVurA2I9wGcg46EtsgAADAANRM6sreNPHAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[3][19] =  { 'Type' : "flowChartSort", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNpi/P//PwM1ARMDlQHVDWTBJcHHx4fMNQPiYiDOAuK3MMFPnz6R7UIfIH4PxKHU8LILEAsAcQXUpbqUGMgNxBFAPBuIPwDxAiDOAGJ2cg1MAOILQHwZyj8ExM+BOIwcA1WB2ByIF6GJzwBiZyBWJNXAdCBeDIpMNPE3QLwaGuPEJxsgEAXiOChmxCL/l1QDQeltOxDvxiLnC8QOpHp5OhDHAjE/FpeDImUaqQbeBuLTUC8jgxwg3gPEd8lJNvOA2AApMYO8KQzEK8hNh1+BeDkQp0BzCyhdzgTin5RkPZD3PgNxBzQILlOj+NoMxIJAvJKQQsZBX2IDBBgAxNEw3jhcw70AAAAASUVORK5CYII="};
g_oAutoShapesTypes[3][20] =  { 'Type' : "flowChartExtract", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQVJREFUeNpi/P//PwM1ARMDlQHVDWRB5vDx8WFTUwTERlD2XSCuR1fw6dMnol0oDsQGQDwBiCcBsTIQq1DiZQ8gvg7EZ4D4FJTtTa6B3EBsC8SbkcR2Qr0vSo6BTkD8DoivIImBXPoGiL1INZAZiJ2BeAcWuT1Ql3ORYqAl1NADWOT2AvFvqA+INhAUGfuB+B8WuV9QORf0ZIfLQC0gloRGAC6wC4gFgNiYGANBrjsKxF/xGPgBiE9iixx0A6WBWB+ItxGRy7YCsRIQ6+EzMAqILwLxCyIMfARNUgH4DARlre0klAUgV8riLByA4DgQVwExIx5DYAUoI5R9BFmSceQVsAABBgAkyzF3CceGmgAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[3][21] =  { 'Type' : "flowChartMerge", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQlJREFUeNpi/P//PwM1ARMDlQHVDWRB5vDx8cUBKVckIUYgRg8TRiQ2SG7fp0+f5mM1EAisgLgNiK8T6SBtIM4H4vm4vHwHiD1J8KEPED/FF4bLgVgfiMWJMEwGiHWAeD0+A0G2XYTaTAj4AfFDIL5EKJZ3QMOSC49hAkBsBsTbiEk214D4ORB74DHQBYg/AvEpYtPhLiB2BGJmHEkNZOBuIP5DrIHHgPgfENtjkXOAGrqPlJwCsnkPDm+DktVhIP5GatYDuUAQmjRgwASIxaARR3Je/grER6DJAwbcgfgsEL8kt3DYCcQaUJeZQtlbiC4csIAXQHwBiAugBcE9aPbECRhHXgELEGAAPoo1PLy45aEAAAAASUVORK5CYII="};
g_oAutoShapesTypes[3][22] =  { 'Type' : "flowChartOnlineStorage", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPBJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj44Mx5YA4BYiV0NSCApsRiQ0DILGNnz59Wo1iIBSADCkB4q1AXEeE71qB+AYQr8ZwIZSdDsSbgXg7Eb6zBmJeIF6GKwxdoM7fTmRw2QDxDiD+jctAByBeQ0L4KwDxWXyxLAnEt0mITHYgfo7PwP9osYcP/IfqZcFn4EsgViHSwL9A/AXqK5wGHgRiPxLC8BYQm+EzcBc0XLyJNBCk3hGIuXAZ+AeIZwOxPxB7EmHgNagrE5AFGWHFF1LWkwfiDCCWRcty6FkPWWwLMOutQDFwtDwkGwAEGAD1wTTsCB3towAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[3][23] =  { 'Type' : "flowChartDelay", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAONJREFUeNpi/P//PwM1ARMDlQHVDWSBMfj4+MKBlC+UCwoHRjT6PRA/A+ITQHwA3aBPnz6hGgg1LAaP5UpALATEoUDsDcQTgPgpJV6+B8RngLgciE8BcT0QS1MrDFdDvV2M5ksUA0lNP6uAmB2IHagVy3+A+BgQm+IykJEMQ0HhqkjNdPgRiLmQw5FSA3mA+CfU+xRHCgioA/FDaoUhEzRCjlEr2QRB9RyiRqT4AbEnNPv9wlo4EAEUgFgYiMOA+C8Q12HLy8gGbgPiJUheZ0RjM0ANOA7EW5BjFhkwDvoSGyDAAMYLMkC6e+HXAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[3][24] =  { 'Type' : "flowChartMagneticTape", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATpJREFUeNpi/P//PwM1ARMDlQELjMHHx4cu5wLE1kCsgiR2G4iPAfEedMWfPn1CNRAJiABxOhDLAPERIN4CxB+AWACINYA4BIgtgHgmEL9G18wIC0OoC0WBuAWILwHxPCD+jsVCdiBOBGJjIK6CGQpzIXoYpkMNm4rDMBD4CcQzgPg8EGfgixQHIJYD4vlEhv98aLA44DIQFAEngfgbkQZ+h4axNS4DFYD4Fomp5A4Qy+MykBOIv5Bo4EeoPhZsBoK8wEeigfxA/AOI/2Az8AEQK5NooApUH1YvH4UmWG4iDQN51Raac7AaeABqWzKRBiZC1e8nJqdchuYUbEkIlEPygJgZiEGaGUE0MKfEYjMQZijIdlUgvgjEO6DJAx9YjM9A5IRuD8RaUD7cNWg0A1YXDtoCluoGAgQYAHM7V+eWmXSVAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[3][25] =  { 'Type' : "flowChartMagneticDisk", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATpJREFUeNrs1DFLAmEcx3GfLDSTi5aQUJIIhDAbojdQS0ODW6tDYS+g9xJES2O0OQlNTQWRQ9CoKS1dOsRFBGVc3yf+B0/nGZzc4NAfPjwHz/njef7PcyrXdWNR1kQs4hr/wEnvwbIsPUxhHavII66nhG72C97whRbucYtPx3F+cpR3KAQWGQ7wjhs8oosHCUhhAfNIo4AVmTsm8M4feMJwhouQu9xBmcC9oB6mQoYlZLXxgR5KlbGNSzSkZ8/G/AwyWEJJtq3MHDNQT1TlUDZQkX4ljXd0f3rSZxvnuMbRsBV+4EqEKTfqe6iCAvsjhk0P+1L09ncD2vBX5XD4a6nGPVxk2MccamhK4199IbNYxiaK8rWccg9tf6D3gzVsISun7DVdyahb84Q26ujoFwY+vf//w5HrW4ABAJmuVHmPJ85VAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[3][26] =  { 'Type' : "flowChartMagneticDrum", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAU5JREFUeNrMlLtKBEEQRbddwRcOKAgKvlADEQQjwWwx3n/YyC/wJ0w2FAxMDMwNBQMDQQVBEMVMFJE18zHo+tqxvQ13oShq6Ak2sODQU7dn7kx315Tz3pc6GV2lDke3FpIkCcMY2OALHac8r8P4AbbAeZhI0zTfkLEGjsC20HrAJtgHDd6zDpqxJS/wC3eVvgI+wR44pulykT2sgEMuS8YiOAUt5hfUoobT4NrQJ8CVyG/BZBHDfvBk6MPgQeQNalHDPvBs6L1Kb/KgooZl8GNovyATWnuPB2KGmfHmjDVYVroXdZpr+JWjhy9MRD5Is7eY4bdeBuMdjIp8iHUZ3cNXlo6lz4h8ilrU8AasGvo9mBP5LLgrYngA5sG40kOxL7Gs2n/OZRHDR3aRmtJPeGBVEg7lTD/sdINl+xoBdZ6iM0roBexY7cv9+479J8AAgX5MCGQVKM8AAAAASUVORK5CYII="};
g_oAutoShapesTypes[3][27] =  { 'Type' : "flowChartDisplay", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAUhJREFUeNpi/P//PwM1ARMDlQELjMHHx4csrgPEFUCM7HxGJPZFIJ4LxO9gAp8+fUI1EA1EAvE+IJ6HJs4MxOpAbAbEDUA8C4ivEPKyHRCLAvFqLHJ/gfgaEC8A4j4gzgRiK3wGsgJxMBBvB+LPBILrARBPBeJ4IObBZaAXVGwzkXEAcu0dIHbDZiAoVnyAeA0Q/yEhYg8BsQE2AwOB+C0QHyQxpdwCYnlsBjriiAhC4CM09jEMvATEmmQYyIgrlndAXclNooHCyGHOhBZjj4HYk0QDQb66hyvZbIcmAXYSDLQF4pO4DDwLxF+Q0xUBYA7EkkB8AJeBoLDYBTWQhYBhekCcAs3PPzFKGyQAss0PiB2AeA+anAoQCwGxPRArAvE0aMmDiHJYAYtWfIUCsT+U/R+aNP4jJZGb0MLhK3rxxTjoS2yAAAMAmrFC0jI7B90AAAAASUVORK5CYII="};


g_oAutoShapesTypes[4] = [];//Stars & Ribbons
g_oAutoShapesTypes[4][0] =  { 'Type' : "irregularSeal1", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAXNJREFUeNrM1D8oRVEcwPF3/UteXQZKlEGkEJMwkEEUk2JAt4wKg1BkMinKiJIi/4oYWGRhUrIZMBhksCjqpuhR1/fU79ZxuM99vTf41af3bufec3/nd37nWp7nRVIZaZEUR4b/x7btMPfnYB5D5oDruqEyLDeuu9W7k1nyGJr9RaAl9JIDIh19yEM1ztCaTIZqfARNyMUBLGxiA+uoD8qwFx3atXrwDR+YRiFe4cj4EnZxETThDl7Qhlk8aWMxPGjXizjC6V9LPpa3zqAmoAx1+ESj1PVbWP5JMfqwChNYwFXAxLUYxCP26MPboF0ulTpd4+aXcUfKomqssoliAJPmhNnokZtVFMiGmLGPBqzhMl4N36UVHG0no9Ii43LsVjGKFfQjM5E+zMKy1LBClqgyvscw8tGVyIQxyWQOz9J36ncLUzhHJ4rD7LKKEq332qXxt3Gi3VOGShz6X5t4Z1lvZHWGi4zJVNyJnxn+2y/2lwADAMjoVL55G3YOAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[4][1] =  { 'Type' : "irregularSeal2", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAY1JREFUeNrM1E0oRFEYxvGZYSE0+U5sEGWBUtZKCUslZSFZyYZRkoUs2CgrFjTZia2yoaSkCIUFKyOllGRhZBofoa7/qedmGvfO3MUsvPXrfp177nvOe+7xW5bly2QEfBmObPskGAyma5uPOYw4PYzFYp4zrNaxA4XI0XUd+tDrmKFL5GIaYbTp3hiqlLGJZS9z2IJaZWRiGHkYRQP2MY44Tr1kWIAQXvCEKX3kDbO4xQoO8OUlw0N8Yh5rOj/CB65RoWTuUOKWYQ+64U+4Z4a37fDBUrUbxLeqH0nO8EKNFtGPSZy7jOAMC7BUsIjTkG800SFV8B6PKVZAVPPbmLCU/szhszoOqwipwhSnGK2YcauymZtybGlYqcIMdx2XeHDq0Ky5Ca23dmTpheRYVdVNNGPHrcqmIEs6lmFIHXaq+qaTXU2T+Vu69KweV04dRsWnBR1Qxk04xrv+W/PBV2wouxovf4q9FiuV9Ymu9zCQ0C6uOfx90d5gk7avIu0um/o70oa9ffn//Y79I8AAwt5Z7lHxxw0AAAAASUVORK5CYII="};
g_oAutoShapesTypes[4][2] =  { 'Type' : "star4", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATFJREFUeNrM1D1Lw1AUxvHGN2iGiIKDg64ORUVBEXwZXAQFCZV+lX4Ah26CH0LBzV3wDVFstYrFqXYu4lIbVESE+L/wBCRUbckdvPAjIUlPzzk5N04YhimbqytleVkP2BOdeJ730zO92EIe760eCIKgowxnMIhZWyXPo44FGwH7MY49jGEgacBF0yLcoKZs23spseViDiu41bUifP3mBM9/BezDlLLK4AkX2Nd9cz6KZWzgHqe4xmcUxIl2CmNT4DCCJnZw+Utlq8gpoQfGZrNVQHOYwBKm8aqgh3jEMNZVhau+HqHyfQ7jPayIq7kzpQ1hG2uYxAGO0ejkpbyp8Wlk1V+T9S7Ok4zNmf7U1xa8SjqHLyir3BI+bGw9U3q3RsTKXjbzdodqOwGdf//F/hJgAGE6SFGCW24cAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[4][3] =  { 'Type' : "star5", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATlJREFUeNrklL1KA0EUhbP+E3GJVgbfID6FdgmKKWx9g9hoE7SwSVYttLKLAcFSn8BOH8D4F6xTiGkksKCgGNZv4AxI2DUbsp0DH3fu3ZnDzpy76wRBkEpyjKQSHokLjtmJ67pRa3KwA8dwG7bA9/2B3nBWMZPEkUdhHa6hCBPDCi7BO9TgDZaHERyHNbhQfgmrMBXLFMYpTIKj3DbovWJTYrUQnQ07cWxj4/I8YduYBifQ6WNUyWyDI1xuhx3ZFPegCxVYjBAz9Sp8aX37rzv8AA/uYBcWep5nVW/AodbHMuVbd/aiPK34qnp3EJfTape68oIMKyiv6/l0XEHTGo9y3JPQmaKn+gOsxBXMq50O4Am24ErxGfb1xeQlHtmHdszAHJSh9atuXD2HG9jU3s/ezc7/+8H+CDAAM85EJbUVaJgAAAAASUVORK5CYII="};
g_oAutoShapesTypes[4][4] =  { 'Type' : "star6", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAUZJREFUeNpi/P//PwM1ARMDlQELjMHHx4dLjRoQV0AtbwXi29gUffr0iSgXsgJxOhDvBuJ9QJwFxOyUeDkWiP8A8VogXgHE/4A4jlwDtYHYDohnAPEvKAaxbYDYkGAYAsFiKM0IxLCo3wrE95HUgMJvOxAXI4n9h+qJQTfwDBCrA3ElEH/E4/IVUAwC/EDcDsQ3sXl5NhD/AOJoElJJFFTPbGwGfgPiaUBsAcQqRBgGUmMJ1fMNV6SwQ8PjNxEG/kbSgzWWeaBpDhSWD4kwEKTmLFQPDzYDk6G2zSchDOdD9SRjSzYmUO9OQ0oOW5FiFAYigNgHLdmYYjMwFk0jKFGnAPEpIL4HFVMFYg8g7gLiS6TmlENAfByI06B5mhXK3ovLMGLy8nyoQcFAHAmN2RWUFA6gRDsJiF2R8jXeJMU46EtsgAADANbwRS3ErJwQAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[4][5] =  { 'Type' : "star7", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAWNJREFUeNrM1M8rBGEcx/FdNovDuDmSROSgpDg4OftRIlHODi7y80ooDg5KuXCx/4H25EApB4kDp5UWBwkpppST8Z76PLXN7jxmswdPvdqdZ57nO8/zfX7EPc+LlbKUxUpcEuaP4zhhbSqxgXLM4atQI9d1I49wSr8VmP3rlAfRjnWNshUjtg5xsyia8jLazDt8K9iF6rown9sf11gyU04EPnCCKiyEDOAMwznPK7i0TfkUdWiKkNtatODcFtBfwUd0RwjYg0882QL2owYHEQIewV+AobCA9RjHFj4iBHxX21E0Fgo4gze8FnEw7vGsvnkBd/Gir04iaQmU1Gpva9p7eUdP+8nXgEXc4FjvqrUnzbHr0Kbfx+FvJ+UOGfTq2d9Cm2Jy1YmrYDDb0ctoj41hVVvDz9WaVrVZ+Qu/bQIlq2M1gBTSqu/DhPpliw14ix085NSnledp5Tj8cvi3N/aPAAMA7PFQGkny12EAAAAASUVORK5CYII="};
g_oAutoShapesTypes[4][6] =  { 'Type' : "star8", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQpJREFUeNpi/P//PwM1ARMDlQHVDWSBMfj4+LDJ6wFxDpQ9BYgvYVP06dMnTAOxAF8gDgXiHii/FIhXAvEWfC5khEUKkgsXg8SBGCSRDsTfoOLcQDwNKZhAamKIcSFcIRr4CsTxSPwl9I0UKIiAepUBh0uQXf4XiIOBeC0uF4IM8wTiWCwWx2CxCOT9QCD2wmWgDxB34vDJYhzi7UAchcvArUBcgUXTfxyuBoFKIF6Ny8DlQLwdS+wxQsUY0cTnQ9PkRnyRAjLUG0v4YQOsQLyCmsnmPzHJBj2p/AHiBCTxRVBH/Ccl6yGDAGjSWAz1+jYgXkVu4QACG0Dqoa5cRahgQHHhoC1gAQIMAF1oP9L/kdqeAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[4][7] =  { 'Type' : "star10", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAZRJREFUeNrM1M0rRFEYx/G5zCAvE7JSbLCzs6BYKQshJQvEyoKU+EesJBuljKSsbEQJCwm7KbKY2ViIJC9T5GUY31O/qeO4d5qFhac+3XPfnjnnmedcL5PJhP4yCkJ/HOHsIBqN5npuAPc4CHoglUr9TOhEO26RQBv6dP0RZ2hEDQ4DZ+jEKCpgCpzGCsowg4iVPK+E5lo55lCqRPu696Wlm9pP6Nl0roQl6NT4GjfO/S0dzZIL0YVdfPglNLUa13hPMzGxqhLE4KkMkzjBCPqxiLjbNhd4V7JljWPWfU+JzfEZ89hWGRJ+ffiENXSjSdfGNCO/qNeSN/AS1NgRJfBLknGOnvWO704xnT2MTSSdpYasembPL3U+qHd//SnN+vUeFGHd6sns8u3oRQfeUIdzN+GR/rkWTGMHDwH1q8KQZrhr96Lbh584xSsa1Ni1mm1YzXwl2fZK57P1TMJZNaypWbHq3WrVPaXWymsvL+FOMzENP6XECzjWTqnM+flyIm6NTYJq9dqxriWDPmPev/9ifwswANgKX8uFKzufAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[4][8] =  { 'Type' : "star12", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQFJREFUeNrMVDEOwjAMbCrmPoQvdIa9Yk2+wyuYSFbUnc7wBB7SBxAS5EjWxUkBdcCSFStpz+ezE+W9b9a0tlnZVgfcpKDrOjyzwQ3FLrgW4rfN85wDCqYIdAoehT4EH34p2ZF7YrindQCW7hsNtRDjnjgeKo1N0JBn9Ew/ySyTxQcNjQSIjeANsPTzI/gRz3lTsOQ704YzNgS8BZa3moYRoAfNvMCWJ+mxOS0IPRa6l80e7V1xH0se4IMnlOiAwK7WZQtnn3Y53hQtMTTkilZbAHMsmV4qOc3gCQAaSJDGqDrYpbImun4ju8vFx6FdeBxiaWdifalduYzh3z6wLwEGAIqwWOpgjbDBAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[4][9] =  { 'Type' : "star16", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPVJREFUeNrMVDsOwyAMhahzbtQeoB3N0NN1bBcYmwPkSLmAC5WpnhxDMmQoEgof++H3HsEzszuyDe7gdqqDcRz1Xsw9bIy/bVmWNaDRvCRPMr9roL2Uo3QWgJt8AwAmidmtIVZCjTVv0qouZw2jBLEBYLGosnDWMFiAlQpBIs6Tqvi3j6ZoyjOcHqHaKEAabO5pWJLOQDWATh7MQh0v2pxBGdFyjw1NS+xbr2vKpALYMAJjr3tcdob4zqiuHuizKdSiTACWOmAEMtDWxS6BT6OaaKx1L3br8k6iVZKKuPc4bD1fJfEh2r56v9yqwr99YA8H/AgwAMcoV0vQHfYzAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[4][10] =  { 'Type' : "star24", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPpJREFUeNrMVL0SwiAMhp5zH8RH0N3VDo7kRXwXF2F06NzdF+oLIHjhLk1Dqh6D3OUKFML3E7AxRtOydaZx25VO3/f8n08B2A8pnDD/bvM8rxMKzWKiKUXW5ZJi+IWyxzCI6oSIzjiOeJD/RkNKySlza1rF5aShR5pRSCCxsERDJyEE8gVC/UqMoaY4CS2n/CQbS+J9BWXA9VUN84IDO9ELY6rjkZvTsQUjQRgEI4BoV0oKNMqDgChUKJeS+shlq5UGo2k1lx1JFhQzgO3ZLOwbqcfAvkY5bEG5VrwTajXi9TPa49BtPA6Zzh3Hj43bs0T4tw9s84QvAQYAAGROgQfrZZYAAAAASUVORK5CYII="};
g_oAutoShapesTypes[4][11] =  { 'Type' : "star32", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAARlJREFUeNrMVDFuwzAMlI0goz9UIFu8xgE6UlnSZzVL5DXo3uzufzy1k0IXZ+DKSI4ReCiBg2WYoo68s4oYo1sySrdwrMZFVVX2W1B4rFuFJNa/0ff9fcFEFNj8ifdXxe6ZlgMKRTDZ4tmAcaSc2TMUMHTUthBzn21rVFlnGJAcTaFUtJQ3zNCnClohDopa8aM4UpGr4szCsSi25Q5JDpuEmAgO2xDLLmsbGrLQ6cMIvinnXfFGecOeF7ZRaYT4IIbeiHOiYo4sJVMq742ZB3zhfY3DAhGop1Qehz4qPVflQkXJtuyp3XaimJAfZY6xT+bP4We0Psy1nPoFHXxXQ7AGzLKXQ/ngcvBk4suDuf5l+G8v2MUL3gQYANnXX46tFyDRAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[4][12] =  { 'Type' : "ribbon2", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAANdJREFUeNpi/P//PwM1ARMDlcEINJAFxuDj40OXawBiZSx6GIH4DlQeDj59+oRqIBYAMiwWh9wSgi4EAgcgToa6gBgAMhSW5uYB8X50A1OBeBYQH4TyFxMwMAZK20P17kePlE6ohCVSWOECMJdZQvX0YovlS0A8EYiziPAuzLIsqJ7z1Eo2//FFiikQFwDxJCTFS9A0ogfDFCDOh+o5he7CAqiCk1gCPhaK/yOJMUANmQo1FMOFS4E4G4pBGq9DXXgRSc1VaOzfQUuLs+GBO1p8DT4DAQIMAM+FMJ6vG8+xAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[4][13] =  { 'Type' : "ribbon", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPpJREFUeNpi/P//PwM1ARMDlcEINJAFxuDj4/MCUlFQLiimrgOxFhBfBOJuqHgFEGsD8Q0g1oCKMQLxnE+fPh1AMRBq2CQgPgXlLwbiGCBegqQGZFgsVCwGKmYJxNlAfADdyyDDcoDYFMlmmGFLoBgmBktrZkCcBcQTMbwMddkUIC4A4mioplgcQQWzKA/qkNO4IuUPku34wH8kX/zHFcu6QFwMxDOQFOMCMLnpQJwPxHrYvAyKwTlAfISEVAJSywrE5dBgQjFwNhAnA3ESAdcxIKUCmGtnY3PhAVjUowU8LhCLN2FjAXexGPof6qLrOAN3tPgafAYCBBgAylk0sWsBQkIAAAAASUVORK5CYII="};
g_oAutoShapesTypes[4][14] =  { 'Type' : "ellipseRibbon2", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAVJJREFUeNrslEErRFEUx+dJYfOyUMpmViwsRSzsFJFQLAcrIVsbH0DZWSpRat5WJAqLWWEhLHwAdsr2NUrE8zt1rs5c782UZmHhX79m7nn3/s+55973giRJcvVUQ67O+vuGje5PGIb+syYYhz7o0NgT3MEJvNjJcRxXGqZoBbrgEC40NghT0AnrVStMkSxahbKJncINbNTcMtqENgh0/OaZOb1CM0Q6dvdu1jeUJp5DUce7GUWUNdki5GFA+/zjlMVgGHq9zGmSZ+/QCiM2uTW8ghIsaeZaatcqb+E+61Bku/0wZ3o5A2NalRzIlsZlTgtcVrvYo5okMgknYQ0OoMdseV97OZRl2A3TsA2PGtvTSp/hWC97Udc9wI6uy6cZLsMRXJsqCt7hiPkCfJq+n8HE9wT3+eLVi3RxYH6dCqbHgXcLZPzBqzdfYfj/Pfy1vgQYADPcTKNRnye6AAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[4][15] =  { 'Type' : "ellipseRibbon", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAUVJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj41uCR10MlIapgQU8I5T9/9OnT3HoLvwExKuhmkH4B5RGjjUQOw2IfwFxLFR+GxCfxublaUAcAMSmSLYvgdLIYCYS2xqIvYF4EzYDrwDxOiDOAGJ5qFgClBYBYl8g/g51GQNUTTJU30OMMISC7VAb46D8P0C8EYi7oPyzSGrDgJgNiPdgjRQoiAZiVqhXq6Fiq6EYHSwGYlUgtgHiM9i8bAXEzkA8A4jvYwk7dPACiGcBsQkQ62AzMAnq5dNEJjmQTz4A8Q6oXgwvs0PDzxvK/4nDIB5o2M1HS5MYBsaiaZwB1fwFTZwNmg6T8eYULOAWEPdCk9IRaJiCwjkIiO/h0sQIK76AWQ9djgOI/YDYCIhlgPgfED8D4gvQhPwNWTEw66EaOFoekg0AAgwAlRNJHjM7j10AAAAASUVORK5CYII="};
g_oAutoShapesTypes[4][16] =  { 'Type' : "verticalScroll", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAMFJREFUeNpi/P//PwM1ARMDlQELjMHHxwdjWgNxMtQykPNZoTQIMELZjEhidz59+tSIYSAUsEEN2wbEO4B4OhAnAPEfPI5ajM/L/5FcRmzgMmL1MhT8hor5ArE/EL8E4gVIljFiccB1fAbCQCoQMwPxDxzyS4A4Bm+koNn6G4oHPtkwEQrkQenC/wPh5f90cyFysgkFYj9qRooDEJcQ6UJGYgzkAOLPlLoQ2csXgHgWUtbCln9h/Os4nT7oS2yAAAMAisQtI0KWLfgAAAAASUVORK5CYII="};
g_oAutoShapesTypes[4][17] =  { 'Type' : "horizontalScroll", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAANlJREFUeNpi/P//PwM1ARMDlQHVDWSBMfj4+EjV6w/E9kAsBsTrP336tJYSF3IAcSAQtwNxBhC7YLgQCCyAOAGIQbHECxUDsRmR1CDzQex+KP0Pm4HJQHweiNmAWBOI04lwKUgtD9RgjEgBsacB8QogZgdiViIM/AXFf7C5ECSxGOqlu0D8m6JYhrooBYi5gbib4mQDddlPIr1KVML+T6uc8p9aBjKSaeh/XGH4H8lgDqQY/49Eo1sM03cDm4HI4Ac0xqlW2jBSI9m8BeIl6F4gFTAO+hIbIMAAVoEuTAOYrAYAAAAASUVORK5CYII="};
g_oAutoShapesTypes[4][18] =  { 'Type' : "wave", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAS1JREFUeNrk1L9Lw0AYxvGeFkVqI4iCo0txcLEd3DoIolBwc3ETZ2d3ERfBRfB/6I+xHWzp4CjiLCJdlFIVFwnqIIX0e/AEakwo2ujiCx8SDvIcb7j3jOd5iThrJBFzxR6Y9F8cx7GPFNaRxQzSuMclauhGBbmu+zmQymMbHZyhrfUMVrCMEzwGsuzGOzgKBtqwMuqBD+5wjk0coIQLzKmbHMa/tKyqR3RkWy2ihQ1tbusa+ziMChxUVzKJCTxr3YQFfudAvsqvHRsvLNAMEfjxJ5PS/w/tMRgbalJUe1jEqDZ4QRWNnwQanbdjTcm7Du0WlnCKt5CM6f5OjX99McurPJohH0xhF7Oa51utz2NBI1lhlhvBwEHdFLCm2bX1gBtt8uRfDub/XbA9AQYAlmpGpyVP7AgAAAAASUVORK5CYII="};
g_oAutoShapesTypes[4][19] =  { 'Type' : "doubleWave", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAShJREFUeNrk1L9LgkEcx3FPW0J9sP+goaHJwcVBQlqFnINaAsFBXNpbWkJEoUVqaMqh/gGHhlqCCBojagiiwUEc4qrBIa/3xfeB80eThwR94cU9Dwefe+557vsoY0zEZ0Ujnst74EJ4EQRBhSGLGDQO8SjTKdSxiE808eQGaa1/RhW+QwJPGaxLVJFBH12kZdzDDnK4R0cWWyPwYDywzbDtLJpEAau4wYUzZ0PKWMGX3SmBpZEtU+Of+x3nv7yqN9Sc+xPfH8VMC1S+j80sJ1zN5WCrv9Qpxnegmmg9WaWBJbxKe+mwM7GLZfRwjOdpT+gG2hP/gSsU0cIDbrGFIc6wjn3cyX3K3anbegkJDGtDxPEiIQOZy2NT2tPWNa13NBL4f36w3wIMAGN5TkpIrl84AAAAAElFTkSuQmCC"};


g_oAutoShapesTypes[5] = [];//Callouts
g_oAutoShapesTypes[5][0] =  { 'Type' : "wedgeRectCallout", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKhJREFUeNpi/P//PwM1ARMDlQHVDWRB5vDx8S0GUoxAjC0cYOLo8oyfPn2KwWogVHEMiY5aQm0v/6e2gYz4DPw/6F1I9XTIOOhzyn+q5hSol2EJdQ4QH0CS8wLiKKTcQpSBsFziAMSJQPwDiE8AsRsQRwBxFxBfIsWFMAByGRfUUJCB0VCXXyLVy8hgGxCLAzGowDgCxLuoEcvzoeE1k+hUPuhLbIAAAwDbmyJ0Rwi5jAAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[5][1] =  { 'Type' : "wedgeRoundRectCallout", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPBJREFUeNpi/P//PwM1ARMDlQHVDWRB5vDx8bEBqTAgtgJiXiBmRJKGhQ0jlP0BiE8C8cpPnz79xmogEIQDsTIQTwLiGwQcowHEkUAcAsTLcXnZmkjDGKBqJgKxLb4w5AbidyQEGUgtH7Uj5T8+AxnJMJARn4H/B33C/gbEoiToB6n9jM/Ao0CcBsRCRBgmBFV7GiVAkQsHYE5hBVIxQGwGzSn/gHgaEJ8AYjcgjkWKiO9AfB6I5wFzyg9cBqK7whOI/YE4A4gXAfESIN6FrghoIAOurIcOtgOxBNSgw9gMIyeW50PpmUQlypFXwAIEGAA0/zh6Hf/ZQAAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[5][2] =  { 'Type' : "wedgeEllipseCallout", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAT1JREFUeNpi/P//PwM1ARMDlQHVDWSBMfj4+JDFhYDYC4g1gFgeKsYIxI+A+CoQbwfid8gaPn36hGogEggFYl8gPgfEG6GGvARicSCWA2JrIJ4AxFuAeBW6ZkZYpEBdmAl10SwgvofHZ0pAnA7ED4B4OrILkcMQZLMmELcQMIwBKt8MxFpQfVgjxRuI1wPxFyLD/ws0SLxxGSgLxBdJjNQrQCwDxKy4kg2pyegvlP6PzYCnQGxAooH6QPwMiP9gM3ArEAeAIpxIwwSBOBCIt+Hy4mEgvg7EtUCsSsAwkHwNNJEfwpcOQSAMGnPxaIaoALEYENtCk8tW5ISNL6eAFDlA2S5AHIvkk8dQVy2A5h7ceRkN/ANibqgrFwLxHkpKG1Ca4gLimVBv7SGrtEECv6Hpah0UkwQYB32JDRBgAKsRSH+XxJZDAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[5][3] =  { 'Type' : "cloudCallout", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAW9JREFUeNrM1EsoBVEcx/GZ61Ueg7DBTSl7ycbKgqVSVuJuxFLJBjtZISXKSnYeG7mrWzbKRopYWFjfKN0UyZTyyvie+o/mjv+U4S5MfWrOnJnfnDn/Ocf2PM8q5JGwCnwU+yeO44T7OjGEN9QgjRyG0Sj3ZLGHC9d18wNDRwvGMCchtZjHM3ZwiTp0YBLrOA4HliCFdrxL+0n6iqS9gTO5Zvqu8Yh+LdB83gcmpD0AV87vMBrxNUcY0YrShe1AO/3DOtTLKL/NYdyKV2AK1djXQg4xGCPQzOEsDtCmBe7iFUsxR5pBUgs0lT1BWeBaJZZDAa1KqB01b2YdlqJc5mhaebgbfYG2Ob/VimLJf3WOFXnrKZrloYzc84Be9MgArrD2NVR/cwgtvaQEmhc0YBxV0nePVbxI2yxNy196WuAMFpRPbZIfP6dVxg9MROxAW8r1m6iwvOoERmgKsPjbbUsbodkANv+6H9r/fsf+FGAA3KRZye1QzHcAAAAASUVORK5CYII="};
g_oAutoShapesTypes[5][4] =  { 'Type' : "borderCallout1", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIBJREFUeNpi/P//PwM1ARMDlcEINJAFxuDj48OlZgkaHxaLjMiCnz59ikExEA8AGRBLQM0SUrzMSKSlRBv4nxRLCRm4mEgXEhXLi4kIO9yxjCWQY6iVDhejGfafEhdicxkjVPw/WnhiTY+MsNIGmLDJ9iY0YaMaOFraDB4DAQIMAFUMHmzdjHIIAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[5][5] =  { 'Type' : "borderCallout2", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAHhJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj48OlZgmUBgU2IxKNLMbw6dOnGBQD8QCQplgCapYMwTBEcz4scTJSw0D0MFtMZDhjNRDkuhg0MWJcyYgrDP/js51ULy/GkTwYkZMFIYtYiPBaDCkuZBwtbUaAgQABBgDUbhnS9VX6yQAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[5][6] =  { 'Type' : "borderCallout3", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJVJREFUeNrMVNsJwCAMNNJvJ9TR+qUTukCqYECsr7QKHohC8PSSSwARxUpIsRgXHZRStbgLK0qAbCeQNPDe6xdhB2YQt1sljwhnKgbVHKZ8cYj6RUnQvfzMqJCDXwFXsmReZknGhhxbeTD3JLYI4YMH97eeLCocrXP/IQSaNkUvu4aNqgi9PCQsh4NhEx47D88nfAQYAIa4KWRjBVrLAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[5][7] =  { 'Type' : "accentCallout1", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKdJREFUeNpi/P//PwM1ARMDlQHVDWSBMfj4+HCpWQ3EoUBcAMQTcNGfPn0CK2aEhSERBuID+UADJ6K4kAggAsToMcgIxG+AeCI5YcgOxJxomAMqV4ARhni8CwMcUBchA5iLJxDjQvSw48CBiXIhsmH/kbyM7jJGdBdiM3AVmstgms7hi2VYxDBhcVkYDk0FeGh4LCOnQ2LSG06AkbBHTuEwaiDlACDAAEF/LfAI8fTxAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[5][8] =  { 'Type' : "accentCallout2", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALlJREFUeNrslMENgzAMRQ2qBFxy6WywRhmFrlF2YRJOWcAYZFduiFMQubVf+gqWos+LHSgQEXKqhMzKHniTB+ectedF7sg9eYisD/LTe79tLqSHicCR3H4B6ylw+CA8oPsKoGrkembS0z1syDW7UTXw8cEiHI3AigGEDNmgCWOByEMIX1AHRwYVKAPaBaYGUCm6UCZh6rOZUlOW0DKg64wW6MbH1jehvodH7pup3cX+nZ/DP/C6FgEGACReMlbp1qrBAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[5][9] =  { 'Type' : "accentCallout3", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAMdJREFUeNrklEsKAyEMhs0gfYFuejZ7jfEonqMepifpxgPUKiQgksyjlW4aCBEnfP4xGSHnrEbapAbbcKCqJZMbYziPGGeMnovEgPYOrbXcmbG4W9HlU0qhLvSOYq7C/rN42HOHVMIZ/dKsT6SQkjVTXgUAAzziPjQ5L/wWJGC1G3OIQjUgqPcE1UICZ4dOXWuiQlgAPpa6TNBph0IvxLlV2M/hlpljrczhb/5lh12NnwK5sXHduLhvgT34jt3fBIb/e2DfAgwA1p1AUUnDUUQAAAAASUVORK5CYII="};
g_oAutoShapesTypes[5][10] =  { 'Type' : "callout1", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIlJREFUeNpi/P//PwM1ARMDlcEINJABFCkgzMvLiwuXQukyNLoUmYaZwwiLZT4+PkrcVfrp06duYr1cRoSablLCsIsUSwkZuIRIF3YRY+BiII6hlgtBhsXCApxSFy5BMgwlwPHFMi4DYd7EprgMjUYWh1uKnA4Xo7mMJABMh6gGjpY2g8dAgAADAJsgMkA3Q1sKAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[5][11] =  { 'Type' : "callout2", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJBJREFUeNpi/P//PwM1ARMDlcEINJABFCkgzMvLiwuXEqDLQDTMHEZYLPPx8VHirrJPnz51EevlUiLUdJESht3EuBDGwOblxSBxUPBC6UvILsAFgF4G0yxY5ECGxJAahjBL0b28BIthZZSE4X98iomJOCY018XiUVyGh+7GFimLcRhIFIBFCuNo8TX4DAQIMABRcDj3mTmg7AAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[5][12] =  { 'Type' : "callout3", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKhJREFUeNrkVMkNgCAQBOMXKtQyoAhowR90ZCc0gOwDsxJBQHxJMuHM7M7AQr33ZGSbyOA2nJCAZABj7A4i00s8jxwAGj3knPfmJJxzulayrCDULR6qCsJLUCzZgqWwFu0N2GtIg+RzPCd7a4eHEgfFkn2nh2q0hyJHSAuHRZKxROu6dClLz0PEl/JpLUN2JmB7Q5grPdPyjLDkp1q2KPs2wv98sIcAAwCa8UpfySXDwwAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[5][13] =  { 'Type' : "accentBorderCallout1", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAM9JREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj48OlZjEQxwJxPRCrIomDAp8Ryr796dOnRhQD8QCYJhUgTkIThxk6l1wvM6LRMJf+x/AyDqCMpJgRzWUMWAzH60KQYbV4XMqIzVAmPIbVAfEEJMX/sdDorsXqZVBMVgNxJxBfQ5P7jyX8GPGFoQYQlwNxFxbDGLHw0cMXxUCQYWVQl91AcwUIXAfieThcdx1uC6xwACbsBUCqFZRIyckhwISNYaAikLpPbpbDMHC0+Bo8BgIEGAD96zeIQ42yCwAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[5][14] =  { 'Type' : "accentBorderCallout2", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKJJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj48OlZgkQxwBxPRCrADEjFjW3P3361IhiIBEAZFgsHktJ9jIjtcPwP0lhCAW8QLwQiP8C8U+oIf+JcOF/XAbqQw1LBOIv6OFDqpdBrisG4plIhpHsZWQDzaGuO0GGQYzYvJwFxDNwuA4EbgDxYqjm/2j0dVxheByLQbC010pU2hotbUaAgQABBgBKUiUTmgvKNQAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[5][15] =  { 'Type' : "accentBorderCallout3", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALhJREFUeNpi/P//PwM1ARMDlQHVDWSBMfj4+LDJLwHiGCCuB2JVJHFYODEC8e1Pnz41YhhIAKhCDcYGFlPby4ykGPgfjSY+DKHhRZQriDWQAUs4LSbVhUzkhBOOYMEw8D8eg/4TaxkLAVfADLoBDeP/WNRdxxeG6CAWSreSE4b/qZ2XjwHxXCDuRstmpKVyWPGFlJczgdgEiL8B8SRQXiVkCDAv4zUQ2WArIP4AxLkkGzhyCliAAAMAh+cvMqm4dUEAAAAASUVORK5CYII="};



g_oAutoShapesTypes[6] = [];//buttons
g_oAutoShapesTypes[6][0] =  { 'Type' : "actionButtonBackPrevious", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAO1JREFUeNpi/P//PwM1ARMDlQELjMHHx7cEygQ5mRGJRheDARS5T58+xaAYCAUxZDpsMTYv/6d2GDISoZ4XiCOAeA6lkQJS5w3EvaDgxiLPiBEpeLxsDMRRQPwWiJuB+DEQmxKMZSxAFohjgVgUiJcD8Sk8wfMfm4HoiqqAeAcQbwXiP+RECjYvs+HQ95+cSAGFlwIQ9wCxJck5BYuXnwFxNxDrAHECELsBMSg33cWilqRYvgLE5VADQfQFfEHAQmTC/gvE24H4IBC7E5sOiQHfgHg9FNO0+PqPy4VL0BRhK7L+4wsexkFfYgMEGAD0qzLU9YI2qgAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[6][1] =  { 'Type' : "actionButtonForwardNext", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPBJREFUeNpi/P//PwM1ARMDlQELjMHHx7cESIGcywgVgrGRxRiwqAEBxk+fPsWgGAgFsWQ6bAk2L/+ndhgie4sLiOcCcQgQc1MjUhihcqJA3A/EnkDMTFKkYAF/gXg6ECsDMSjAnYF4GRCfozTZ3AXiRiDeDMQJQFwJxFLEGPifQAQdBOISIL4DxOVocv8JRQq+IGLDEp6MhMIQm+H20Fh/CMRtuFzIgsfLML4aEMdDfTMTiK/gcwALAe/lA7EGEK8D4t2UJpt/QPwIiGcB8XeSCwc08A2Ik6mZ9UgF/3G5cDGRBmMr0iCuGvQlNkCAAQBfLDHssD1CBwAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[6][2] =  { 'Type' : "actionButtonBeginning", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAANlJREFUeNpi/P//PwM1ARMDlQELjMHHx7cYSDEC8X8ozQBlM+Dhw8GnT59iUAwEgp9AnEKmwxbTzMt0NXAJFjFOIE5C9iI+AwmlH10g7gBiHiyRwogRy1jAfyRXRQGxIdRlJ3G4HsNARhxqOoH4LhCXA/FXApYTFSnM0CT1n5jgwWcgzMWlUHY7EBsTnVOw2ArjfwPi6VDDQDFsiid4iHIhDJyFupaJXC/HYBEDuXYaEMcSYyAjmZmDGVkvKQkbF+BA1suCJrEYR1j+xxPGyMUdA+OgL7EBAgwAzCUr18e53ukAAAAASUVORK5CYII="};
g_oAutoShapesTypes[6][3] =  { 'Type' : "actionButtonEnd", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAOBJREFUeNpi/P//PwM1ARMDlQELjMHHx7cEysTmZEY0cRifEcr//enTp0QUA4HgBxCnkOmwOdi8zEKBT9mpbSDWSEEPu8VAnADEbFj0zcYSxhgGMqIp+gPEgkDcDsTauAwgJdn8BeJ+IF4DxDlQ17LjUPuflHR4HIgrgZgfiBtxqGEkJgyRwS9oELAQUstERLgYA3EXNAhqic4pWGwFWZANxGrQhHuBmEjBl/bYoK6qAOLvBBz2H5uB6LbG4jEghW6lDbUMZMQVKUuQiqX/aMUWI46wY4SWVBBFg77EBggwAMU5LnE7blb4AAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[6][4] =  { 'Type' : "actionButtonHome", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAANJJREFUeNpi/P//PwM1ARMDlQELjMHHx7cYSDHiUYvsFUYkMTD706dPMSgGAsEPIE4l02FLaO9lPN7VAuJ8KDsd2TVAEIPPQFyGFQBxGpQ/E8mgxaTGsjbUZTORxKYiRQ4jtghjwhGLMG/OAuKzSOKXgDgWiHNxxDpOL1dCFRVgSyJYHEAwDBmxBTiupEJMLCPbvhjNlbHEJhsGHIYju3YJNfLyf0LhRowL/yN59T9SmmNEYpMUKbEk5rj/1M7LWNMhOxGBjpxLsHqZcdCX2AABBgDk2C8NAZy3LwAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[6][5] =  { 'Type' : "actionButtonInformation", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAARVJREFUeNrMlLEOAUEQhm9Fo3CJVqLQSbS8AImEV3AVOs+j1CAqrQgRapHo1ITQ4hrl+icZyVq77sgVNvmSvd3J5J+d/0ZIKZ0oV8yJeMWfG9d1ByHiqRxhuvB933tJyMv7UdjAVLKMtGRLKSlQAkX+XoMFuIRJqK88qIIxmPNZGjTBBGyDEkpNWRl0wF15I3rjPWiBE7iGVVgDU06mN4vOZhwz1MXYfFgAB6WDRF+533HM2/vHLE2RBiuJDz9FoMINyOgeU/ZZsDKJsb0hdbYOjgazJ0AF9L5RSD5bgjbIgSST4zO6u33rQ/LZme3T4DMqs2swtgiT8Kl0xAQNjUjHl1VhXwmQFruoI0xqsY74+4n9EGAAJeBAHwSxw+kAAAAASUVORK5CYII="};
g_oAutoShapesTypes[6][6] =  { 'Type' : "actionButtonReturn", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPZJREFUeNpi/P//PwM1ARMDlQELjMHHx7cYSDEiyf2H8pG9wIgkhwI+ffoUi2IgFMSQ6bDF2LzMOBBhqIlDnJEcAx2AuBqIrYl1Ib70YwzEgUCcDMRxQKyLJv8fXxhyQQMZhGcDMTcQZwBxPhD/BOJCIC4FYjFCXkZ24U+oISCFX6GGzYEaPgnqyleEvMyIJa39JzJIMBM2kgZkjRxAvAQq9hOLJRiWsWBx4Tcg7gXidiCORZLnBOJ+IO7Dl2xYcHjpOhDPRMoBIA1/gbgViG8R62X0nHINzYX4wH9S0yEhwEj74gsKluBwLSMeb6LIMQ76EhsgwACa1Tc8JRY6LQAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[6][7] =  { 'Type' : "actionButtonMovie", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJ1JREFUeNrMVFEOwBAMVfHthHU6TugC3SSW0JXJkHg/VJW+PgpEpFZCq8Uwz8Ra6+8BCh8JtirWKjvGiNWB2YE/E/PbKK86EPaLUhQ5IXRi0j6X6+Z4rJHSzkCh8C5f5luUWxkqFgTM75h/KENOqwwOI6KQQBcaiuKIKNB5tNC5tElZAs68Qzqy2+iBGk79lMCof7Wzl1hwfMe+BBgAaokpMT1Ged0AAAAASUVORK5CYII="};
g_oAutoShapesTypes[6][8] =  { 'Type' : "actionButtonDocument", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALZJREFUeNpi/P//PwM1ARMDlQELjMHHxzcVSDEC8X8kmgHKRgbYxH9++vSpEMVAIPgFxIVkOqyf9l7GAqaieQvk1SVAfJxYA9HDCsTPQuJPA2J/qPgxYmL5P47AR+ZXALEfENtQI9kwQl3JC8RRWOQIhiE6QPc+Vt8wEXARVXPKf3LkmAjEMrGuZyQmlkkB/4mNlGlomhgJWY4vYWeRmKRo72V2aP5lwOI1QknoF9ypg77EBggwACwyJ9doZCJOAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[6][9] =  { 'Type' : "actionButtonSound", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKtJREFUeNrMVDEOgCAMtMbEjYe2i77ESR/KqEPFAVMbQAQGLyGUQI621xaYuWuJvmuMwRvGmNVt4Ba/7BI+vN1aOz8IHQ63pkLHltYhQwnhFrFl6A9C/kCGNSp7Av8hZqmssAobi8omAIokXpYXpQghYuscU26ncCDsrbhTFDCharXKKPImz1XDgVRKKIcQMkg/tV7NYOSQKKOqMRCPU2V03e23q7+f2KcAAwBcGS2U4a5E9wAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[6][10] =  { 'Type' :"actionButtonHelp", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPNJREFUeNpi/P//PwM1ARMDlQELjMHHxzcVSDGiycOcz4iFjaz216dPnwpQDAQJAnEhmQ7rJ9XLvEDMQ5KXcQBTIA6BGgby4mcgXgPEp9HUMWJzIXr4KQNxAhAzA/EuIF4PxL+hYkrEuBA9/ShBw3U1EJ+Ein0C4nggNgfie9j04vPybihGVmsC1fyCGBcyEgjrXCBWhYbffmLCEF+WCYcadh6IF1Ijp+hCY3g+EP/DIv+f2GQDA1uB+AcQ/yElHeILw0Co/GlSCgdCxc5/UnMKPhcWkVN8/adq8QUE7EA8Da1o+k+gSIPxf8O9OehLbIAAAwDkizbWtj8OXwAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[6][11] =  { 'Type' : "actionButtonBlank", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAHtJREFUeNpi/P//PwM1ARMDlQELjMHHxzcNSMGcywil/0PZ/5HEGNDkQODnp0+fClEMBIJfQFxApsMmYPMyJYH5H5uBjNSOlP+DMpZp6mVKACNdYplh0EcK1cNwUMXyf5rlFOTShh2IpyJ5n1DRhRxMP+HhNuhLbIAAAwB0WRy1vQn8sAAAAABJRU5ErkJggg=="};


g_oAutoShapesTypes[7] = [];//rectangles
g_oAutoShapesTypes[7][0] =  { 'Type' : "rect", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAGJJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj41sMpBiB+D8azYAmxoAkDgefPn2KQTEQqiiGTIctwebl/yMvlhkpMOc/tV3IOIJzCtXTIXpOWUxkrKNnRbhjGEfLQ4oBQIABADiTFcrCIC0JAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[7][1] =  { 'Type' : "roundRect", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALBJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj4wNRRUBshEUdKKAZ0dgw+jIQd3769AnVQCAoBWJFII6Biv8h4Bh+IP4IxAuAOA6IF6F7WR+Is6DsP0T47iOUTgBiK2xhCPICLxnBJgDE3NgMBIXHZzIM/IArlv9TO9kwUmAOI10S9v9Bn/VOAfFCMswAJewL8MCEFV/QrJcPxKZYshu2LAcTuwTE3bCsxzhaHlIMAAIMAHJ9KbmAfHgtAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[7][2] =  { 'Type' : "snip1Rect", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIxJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj41sMpBjR5GEBzAhlMyKJNwHxbZjCT58+oRoIBTFEOsQIiCuBeDoQn8blZUYSfHYOiKcAcRYQm1ArDGGGZgCxDrUi5SzU2+XUjOWztEg2jNQ28P+gzylYvfyfqlkPastiLIn8P46sx4jNIYyj5SHFACDAAAPPHdMyuhBXAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[7][3] =  { 'Type' : "snip2SameRect", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKpJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj40MWNwHiAigbOZAZkcSagPg2TOLTp0+oBqIZlg7EHUB8BYdDQGoqgXg6EJ/G52WQwkwgnoXHMBA4A8TToGpNcBkIksgA4rnothIwFKRHG5uBoDDrAeJjJMQByNAZUO9jGAgK6BtkROwZ5IhjwhKD5ABGuiRsSjL1EPIyek5ZguYFRhx8BlxBxThaHlIMAAIMAJQrJhZw0gUwAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[7][4] =  { 'Type' : "snip2DiagRect", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKlJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj41sCpEAByoimBpsYCDQC8W0Y59OnT6gGQkEskQ4xBuIqIJ4GxKep4eWzQDwFiLOA2ASXgf/JNDQDiHWoFSkgQ6cDcQU1Y/ksLZLNf2wGgpKGMpkGMmIzcAIQ16DHGiUuPAPEU4E4G4iNqJX1kA3VIsfLLFgkz0CTQhWSVxjRvMaIlCX/I3uZcbQ8pBgABBgAcw0lYSSYIcgAAAAASUVORK5CYII="};
g_oAutoShapesTypes[7][5] =  { 'Type' : "snipRoundRect", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALBJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj42MDUqFAbAXiAjEjEMMCmBFK/0cSbwLi2zD9nz59QjUQCCKAWBmIJwHxTQIOMQbiSiCeDsSnsboQ6rIKIP5AhM/OAvFUIM6GuvYMtjDkIdIwZEOnAHEGEOtQK1LOQb1dTs1YPosUaSgGUpJl/mMzkHEwJWxGahv4n9phyIgtYYMEl6Blt/9oNLqrGNEdwzhaHlIMAAIMAM4tJpUJ2v6YAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[7][6] =  { 'Type' : "round1Rect", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAHpJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj41sCZYIClRFJDTIfnf0JiI8B8apPnz79RjEQCmJIdJA6EEcDcSQQL0L3MjnRfROI+4HYhpph+B6IubAZyDjok83/0ZxCsYGMVM16ULAERwQxIokx4sieEMnR8pBiABBgAHroHEDa8+g7AAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[7][7] =  { 'Type' : "round2SameRect", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKBJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj4+MAUslArAPEvDjUgwKcEUqDwBcgvgzE8z59+vQDxUAgiAdiRSDuBuJ7RDpIFojzgDgWiGeje9kciKeTYBgIPAbiSUBsgS0M2YD4LhnBBjKUndqR8h+bgZSkcEZsBjJS24UM1Hbhf2q7kJEaLmRBk1iCy2a0HMKIlGtQ1DGOFl+Dz0CAAAMAJN8hXHUuIicAAAAASUVORK5CYII="};
g_oAutoShapesTypes[7][8] =  { 'Type' : "round2DiagRect", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJJJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj4wNRKkCcAsTSQMwIxP+hNAOUjQxQ5D99+hSDYiAQaABxGhAvB+LTJDpsMYYLoYbNAeJrZPiUEVsYipFpGM5I+U/tWGYcTMnmP7UNZBzUOUUSiL9Qy0BxIM4A4uPYEvZ/pBSPK9sxoqkHuewUEC+DB+ZoeUgxAAgwANDdHerbkfGMAAAAAElFTkSuQmCC"};


g_oAutoShapesTypes[8] = [];//lines
g_oAutoShapesTypes[8][0] =  { 'Type' : "line", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAHpJREFUeNpi/P//PwM1ARMDlQHVDWRB5vDx8S0AUgmkGvLp0yecLgQZtoTaXo6hxFBcYUi2ofgiBWToYmrHciypLiUm2ZDkUmLTIcili6idsOOIMZTUnAIydCG1s148PpeSm5dBLp1H7cIhCZuhlJY2GIYyjrwCFiDAAO/CFyGEoNlsAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[8][1] =  { 'Type' : "lineWithArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAINJREFUeNpi/P//PwM1ARMDlQHVDWRB5vDx8S0AUgmkGvLp0yecLgQZtpjaXo4F4iXUDsMYcg3FFykx5HifUCyT7H1ikg3IpYuonQ7jiDWUlIQNMnQhtXNKPCGXkpP10L2/jRp5GWToXGoXDsnYDGUh0zCQN0EFKSOUhgPGkVfAAgQYABb8GY12UkSXAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[8][2] =  { 'Type' : "lineWithTwoArrows", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAItJREFUeNpi/P//PwM1ARMDlQHVDWRB5vDx8W0DUqAwYIQKeRFjyKdPn7AbCDXsPRDHUMvLjFDDFlM7DGPJNRTdQC80Q5dQO5ZJ9j4xyQbk0kXUTodxxBpKSsIGGbqQ2jklnpBLycl66N7fRo28DDJ0LrULh2Qgnoe3cCABwAoRBiQakndHXgELEGAA9hEcIIzFYToAAAAASUVORK5CYII="};
g_oAutoShapesTypes[8][3] =  { 'Type' : "bentConnector5", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAFpJREFUeNpi/P//PwM1ARMDlcHgN5AFxuDj41sCZYIClRFJDSyQY/EZ9OnTJ1QDgSAGj/ol1Pby/5EXy4yD3oX/R71MOOsR4eUlWCxhRKLBOY1xtDykGAAEGADcnhMnEoJMwgAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[8][4] =  { 'Type' : "bentConnector5WithArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJFJREFUeNpi/P//PwM1ARMDlQHVDWSBMfj4+JYAKZD/GaE0A5TNAOXH4jPo06dPqAYCQQwe9YuHTxgSayAjtQ38PxqGMCBHbRcuA+J4rDmFTGADxEeA+CcQrwB7BVbaALMeAxE5hRFLjEsCMQcw69mQ4kJ8+fgQEE+hlpcPA3EfEK+nloEFQHwWJTkM+hIbIMAAKWIf3RSIaJQAAAAASUVORK5CYII="};
g_oAutoShapesTypes[8][5] =  { 'Type' : "bentConnector5WithTwoArrows", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALBJREFUeNpi/P//PwM1ARMDlQELjMHHxwei4oE4FYhtSDXo06dPGC6MAOIUcgxDBoywMAS6cDeQugvEPFA5WOAyQukYYlzIgiQ2F4izgNgOi/olJIchEKwA4p9AfAiHoWTF8npKDKNJshkwA/9T20DGIevlw9DsijUdkgNsgfgINP2uQM96+DQuQcuK/5HCFcSWBGY9F1JciC8fg3LWNGp5GWRYPzSHoZY2gzanAAQYALHXLQuS40RaAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[8][6] =  { 'Type' : "curvedConnector3", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAK5JREFUeNpi/P//PwM1ARMDlcHgN5AFlwQfH98CIMUJxKBAfg7Eq4H4GEz+06dPpBkIBAlIbH0gzgDiX0B8hhpevgjEM4E4ippheAWIpahpoBgQ/yA7UtCAMxBHAPFiahjoAcT+QDwLiC9Qw8vhUJedBuLflBrIBcTMQHybWjnlGxB/B2JNama9pUAcB8TmxBjIiKv4AmY9ZK41NCzFYPqAWS+cJANHy0OiAUCAAQBD5CTZKVFPsQAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[8][7] =  { 'Type' : "curvedConnector3WithArrow", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAANpJREFUeNpi/P//PwM1ARMDlQHVDWRBF+Dj41sApDiAmBEq9AyIVwPxMWwGfPr0Cb+BQJCAxtcH4gwg/gXEZ6jh5YtAPAOIo6gZhleBWJKaBopBvUx6pGABzkAcDsSLqGGgBxD7A/FsIL5ADS+DXLYYiE8D8W9KDeQGYmYgvk2tnPIViL8DsQYWucNAHE9OGC6BagR59wSSuC3U0J9AvAJZAyN6aQPMeuiG2gBxEBBLIWVHkKYPQKwMzHqupCabI1CMDg4B8TRy0iEDjjDsA+L16BKMI6+ABQgwAFuyMA13JDJxAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[8][8] =  { 'Type' : "curvedConnector3WithTwoArrows", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAP5JREFUeNpi/P//PwM1ARMDlQELMoePjw9ExQNxChDbEmvIp0+fcLowglTD0AEjchgCXbgbJAbEb6D0fyj9DIjXAPFRQi5kQZObC8RZUJciA30gTgfin0B8hpRIWQHE/UB8CE38IhDPBOIocmJ5PRDbYRG/CsRS1Ew2YkD8g6Rkgwc4AXEkEC+ihoGeQOwLxLOgYUmxl8OAeAkQnwbiX5QayA3EzEB8i1p5+SsQfwdiTSxyh6HZlOQwBHk3Doh/A/EJJHFbqKE/oekXa9bDZag1NCwloNmRAZolhUF8YNZzJTXZHMWRj0EunEpOOsQGQNmzD5qzsJc2g7LEBggwAJiCPeRPs1YEAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[8][9] =  { 'Type' : "spline", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQpJREFUeNpi/P//PwM1ARMDlQHVDWSBMfj4+LDJcwLxbyD+Q8igT58+oRqIBuSBuACI1aH8C0A8B4jvkeNlJSDuAOIjQBwFxGlA/AOIm4FYgFQD2YG4GognAvFaIP4AxE+AuAmIvwBxIKkGRgPxTSA+gUXtRiB2hoYrUQbyALEvEO/GoXY/EPMCsRqxBjoB8XsgvoxD7Xcgvg7EVsQa6AHEqwgkkdNAbEqsgUJAfIpAmB8HYmFo8BA0MALqLXzgGRA/BmIfYmP5OxG5az0Q+0OTGFXy8l4gfgrExdgMZYQVXzjyMi4ACsc6IJYE4ndAzA3My7GUGAgDykAsA8SvgQZeQzFw5BSwAAEGAFsZPGhsWG4rAAAAAElFTkSuQmCC"};
g_oAutoShapesTypes[8][10] =  { 'Type' : "polyline1", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAS9JREFUeNpi/P//PwM1ARMDlQHVDWRBF+Dj40PmbgXiICD+iU3zp0+fSHKhJBD/wGUYOV4uBOIdSHxRINYg2ctQEAfEHEA8H8r3A+JoqIsZgTgXiD8S60JeIA4A4mYg/gPEukAcCcTFQBwPxG+B2JwULwsB8W8gfgc1HGTQXCB+ApUHufAfKV5+CsTPgHgG1MC9QLwHKucJtfAELgMZ0XMKNNmwA7EyEH8G4sdQKXto2GUC8WtcyQZXpICSyjUkPigc84A4GMpnx5WcWIhIWmxAnA81rA6adF4AcRk00kjOetpQjZxAbAzE6dBEL0FuXn4DxCJA/B2I/0LDlZGUdIgOQJGyGIjXQMNuHRAvgxpMVhiCwEZoUomBen0TNYqvl9AErgTN18Slw0FXwAIEGAD740IjvBOiNQAAAABJRU5ErkJggg=="};
g_oAutoShapesTypes[8][11] =  { 'Type' : "polyline2", 'Image' : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALhJREFUeNpi/P//PwM1ARMDlcHgN5AFmcPHxwdjSgBxMRBLYtEDCnRGII6BCXz69Am7gVCgAsRFQLwNiLdgkV8MxJuIciEQmABxNlQDLsOOAPEqYsMwH4h3APF6HOpB3l1NSqSAwmYlHvUg+ViiI4UIsBGI/YF4CZIYyDdryTVwDRQj65+PbCCl6fAPNBiomrD/U9tAvC4ktegBpctr+GL5ElQRIw5LGNHUXwTiBSjOHS0PKQYAAQYANtIlJHng+9gAAAAASUVORK5CYII="};


var g_oStandartColors = [
    {R: 0xC0, G: 0x00, B: 0x00},
    {R: 0xFF, G: 0x00, B: 0x00},
    {R: 0xFF, G: 0xC0, B: 0x00},
    {R: 0xFF, G: 0xFF, B: 0x00},
    {R: 0x92, G: 0xD0, B: 0x50},
    {R: 0x00, G: 0xB0, B: 0x50},
    {R: 0x00, G: 0xB0, B: 0xF0},
    {R: 0x00, G: 0x70, B: 0xC0},
    {R: 0x00, G: 0x20, B: 0x60},
    {R: 0x70, G: 0x30, B: 0xA0}
];

var g_oThemeColorsDefaultModsWord = [
    [
        { name : "wordShade", val : 0xF2 },
        { name : "wordShade", val : 0xD9 },
        { name : "wordShade", val : 0xBF },
        { name : "wordShade", val : 0xA6 },
        { name : "wordShade", val : 0x80 }
    ],
    [
        { name : "wordShade", val : 0xE6 },
        { name : "wordShade", val : 0xBF },
        { name : "wordShade", val : 0x80 },
        { name : "wordShade", val : 0x40 },
        { name : "wordShade", val : 0x1A }
    ],
    [
        { name : "wordTint", val : 0x33 },
        { name : "wordTint", val : 0x66 },
        { name : "wordTint", val : 0x99 },
        { name : "wordShade", val : 0xBF },
        { name : "wordShade", val : 0x80 }
    ],
    [
        { name : "wordTint", val : 0x1A },
        { name : "wordTint", val : 0x40 },
        { name : "wordTint", val : 0x80 },
        { name : "wordTint", val : 0xBF },
        { name : "wordTint", val : 0xE6 }
    ],
    [
        { name : "wordTint", val : 0x80 },
        { name : "wordTint", val : 0xA6 },
        { name : "wordTint", val : 0xBF },
        { name : "wordTint", val : 0xD9 },
        { name : "wordTint", val : 0xF2 }
    ]
];

var g_oThemeColorsDefaultModsPowerPoint = [
    [
        { lumMod : 95000, lumOff : -1 },
        { lumMod : 85000, lumOff : -1 },
        { lumMod : 75000, lumOff : -1 },
        { lumMod : 65000, lumOff : -1 },
        { lumMod : 50000, lumOff : -1 }
    ],
    [
        { lumMod : 90000, lumOff : -1 },
        { lumMod : 75000, lumOff : -1 },
        { lumMod : 50000, lumOff : -1 },
        { lumMod : 25000, lumOff : -1 },
        { lumMod : 10000, lumOff : -1 }
    ],
    [
        { lumMod : 20000, lumOff : 80000 },
        { lumMod : 40000, lumOff : 60000 },
        { lumMod : 60000, lumOff : 40000 },
        { lumMod : 75000, lumOff : -1 },
        { lumMod : 50000, lumOff : -1 }
    ],
    [
        { lumMod : 10000, lumOff : 90000 },
        { lumMod : 25000, lumOff : 75000 },
        { lumMod : 50000, lumOff : 50000 },
        { lumMod : 75000, lumOff : 25000 },
        { lumMod : 90000, lumOff : 10000 }
    ],
    [
        { lumMod : 50000, lumOff : 50000 },
        { lumMod : 65000, lumOff : 35000 },
        { lumMod : 75000, lumOff : 25000 },
        { lumMod : 85000, lumOff : 15000 },
        { lumMod : 90000, lumOff : 5000 }
    ]
];

/* 0..4 */
function GetDefaultColorModsIndex(r, g, b)
{
    var L = (Math.max(r, Math.max(g, b)) + Math.min(r, Math.min(g, b))) / 2;
    L /= 255;
    if (L == 1)
        return 0;
    if (L >= 0.8)
        return 1;
    if (L >= 0.2)
        return 2;
    if (L > 0)
        return 3;
    return 4;
}

/* 0 - ppt, 1 - word, 2 - excel */
function GetDefaultMods(r, g, b, pos, editor_id)
{
    if (pos < 1 || pos > 5)
        return [];

    var index = GetDefaultColorModsIndex(r, g, b);
    var _obj, _mods = [], _mod;

    if (editor_id == 0)
    {
        _obj = g_oThemeColorsDefaultModsPowerPoint[index][pos - 1];

        if (_obj.lumMod !== -1)
        {
            _mod = new AscFormat.CColorMod();
            _mod["name"] = "lumMod";
            _mod["val"] = _obj.lumMod;
            _mods.push(_mod);
        }
        if (_obj.lumOff !== -1)
        {
            _mod = new AscFormat.CColorMod();
            _mod.name = "lumOff";
            _mod.val = _obj.lumOff;
            _mods.push(_mod);
        }

        return _mods;
    }
    if (editor_id == 1)
    {
        _obj = g_oThemeColorsDefaultModsWord[index][pos - 1];

        _mod = new AscFormat.CColorMod();
        _mod.name = _obj.name;
        _mod.val = _obj.val /** 100000 / 255) >> 0*/;
        _mods.push(_mod);

        return _mods;
    }
    // TODO: excel
    return [];
}

	var g_oUserColorScheme = [];
	var elem;
	elem = new CAscColorScheme();
	elem.name = 'Office';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(31, 73, 125));
	elem.colors.push(new CColor(238, 236, 225));
	elem.colors.push(new CColor(79, 129, 189));
	elem.colors.push(new CColor(192, 80, 77));
	elem.colors.push(new CColor(155, 187, 89));
	elem.colors.push(new CColor(128, 100, 162));
	elem.colors.push(new CColor(75, 172, 198));
	elem.colors.push(new CColor(247, 150, 70));
	elem.colors.push(new CColor(0, 0, 255));
	elem.colors.push(new CColor(128, 0, 128));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Grayscale';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(248, 248, 248));
	elem.colors.push(new CColor(221, 221, 221));
	elem.colors.push(new CColor(178, 178, 178));
	elem.colors.push(new CColor(150, 150, 150));
	elem.colors.push(new CColor(128, 128, 128));
	elem.colors.push(new CColor(95, 95, 95));
	elem.colors.push(new CColor(77, 77, 77));
	elem.colors.push(new CColor(95, 95, 95));
	elem.colors.push(new CColor(145, 145, 145));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Apex';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(105, 103, 109));
	elem.colors.push(new CColor(201, 194, 209));
	elem.colors.push(new CColor(206, 185, 102));
	elem.colors.push(new CColor(156, 176, 132));
	elem.colors.push(new CColor(107, 177, 201));
	elem.colors.push(new CColor(101, 133, 207));
	elem.colors.push(new CColor(126, 107, 201));
	elem.colors.push(new CColor(163, 121, 187));
	elem.colors.push(new CColor(65, 0, 130));
	elem.colors.push(new CColor(147, 41, 104));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Aspect';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(50, 50, 50));
	elem.colors.push(new CColor(227, 222, 209));
	elem.colors.push(new CColor(240, 127, 9));
	elem.colors.push(new CColor(159, 41, 54));
	elem.colors.push(new CColor(27, 88, 124));
	elem.colors.push(new CColor(78, 133, 66));
	elem.colors.push(new CColor(96, 72, 120));
	elem.colors.push(new CColor(193, 152, 89));
	elem.colors.push(new CColor(107, 159, 37));
	elem.colors.push(new CColor(178, 107, 2));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Civic';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(100, 107, 134));
	elem.colors.push(new CColor(197, 209, 215));
	elem.colors.push(new CColor(209, 99, 73));
	elem.colors.push(new CColor(204, 180, 0));
	elem.colors.push(new CColor(140, 173, 174));
	elem.colors.push(new CColor(140, 123, 112));
	elem.colors.push(new CColor(143, 176, 140));
	elem.colors.push(new CColor(209, 144, 73));
	elem.colors.push(new CColor(0, 163, 214));
	elem.colors.push(new CColor(105, 79, 7));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Concourse';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(70, 70, 70));
	elem.colors.push(new CColor(222, 245, 250));
	elem.colors.push(new CColor(45, 162, 191));
	elem.colors.push(new CColor(218, 31, 40));
	elem.colors.push(new CColor(235, 100, 27));
	elem.colors.push(new CColor(57, 99, 157));
	elem.colors.push(new CColor(71, 75, 120));
	elem.colors.push(new CColor(125, 60, 74));
	elem.colors.push(new CColor(255, 129, 25));
	elem.colors.push(new CColor(68, 185, 232));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Equity';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(105, 100, 100));
	elem.colors.push(new CColor(233, 229, 220));
	elem.colors.push(new CColor(211, 72, 23));
	elem.colors.push(new CColor(155, 45, 31));
	elem.colors.push(new CColor(162, 142, 106));
	elem.colors.push(new CColor(149, 98, 81));
	elem.colors.push(new CColor(145, 132, 133));
	elem.colors.push(new CColor(133, 93, 93));
	elem.colors.push(new CColor(204, 153, 0));
	elem.colors.push(new CColor(150, 169, 169));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Flow';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(4, 97, 123));
	elem.colors.push(new CColor(219, 245, 249));
	elem.colors.push(new CColor(15, 111, 198));
	elem.colors.push(new CColor(0, 157, 217));
	elem.colors.push(new CColor(11, 208, 217));
	elem.colors.push(new CColor(16, 207, 155));
	elem.colors.push(new CColor(124, 202, 98));
	elem.colors.push(new CColor(165, 194, 73));
	elem.colors.push(new CColor(244, 145, 0));
	elem.colors.push(new CColor(133, 223, 208));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Foundry';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(103, 106, 85));
	elem.colors.push(new CColor(234, 235, 222));
	elem.colors.push(new CColor(114, 163, 118));
	elem.colors.push(new CColor(176, 204, 176));
	elem.colors.push(new CColor(168, 205, 215));
	elem.colors.push(new CColor(192, 190, 175));
	elem.colors.push(new CColor(206, 197, 151));
	elem.colors.push(new CColor(232, 183, 183));
	elem.colors.push(new CColor(219, 83, 83));
	elem.colors.push(new CColor(144, 54, 56));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Median';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(119, 95, 85));
	elem.colors.push(new CColor(235, 221, 195));
	elem.colors.push(new CColor(148, 182, 210));
	elem.colors.push(new CColor(221, 128, 71));
	elem.colors.push(new CColor(165, 171, 129));
	elem.colors.push(new CColor(216, 178, 92));
	elem.colors.push(new CColor(123, 167, 157));
	elem.colors.push(new CColor(150, 140, 140));
	elem.colors.push(new CColor(247, 182, 21));
	elem.colors.push(new CColor(112, 68, 4));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Metro';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(78, 91, 111));
	elem.colors.push(new CColor(214, 236, 255));
	elem.colors.push(new CColor(127, 209, 59));
	elem.colors.push(new CColor(234, 21, 122));
	elem.colors.push(new CColor(254, 184, 10));
	elem.colors.push(new CColor(0, 173, 220));
	elem.colors.push(new CColor(115, 138, 200));
	elem.colors.push(new CColor(26, 179, 159));
	elem.colors.push(new CColor(235, 136, 3));
	elem.colors.push(new CColor(95, 119, 145));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Module';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(90, 99, 120));
	elem.colors.push(new CColor(212, 212, 214));
	elem.colors.push(new CColor(240, 173, 0));
	elem.colors.push(new CColor(96, 181, 204));
	elem.colors.push(new CColor(230, 108, 125));
	elem.colors.push(new CColor(107, 183, 109));
	elem.colors.push(new CColor(232, 134, 81));
	elem.colors.push(new CColor(198, 72, 71));
	elem.colors.push(new CColor(22, 139, 186));
	elem.colors.push(new CColor(104, 0, 0));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Opulent';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(177, 63, 154));
	elem.colors.push(new CColor(244, 231, 237));
	elem.colors.push(new CColor(184, 61, 104));
	elem.colors.push(new CColor(172, 102, 187));
	elem.colors.push(new CColor(222, 108, 54));
	elem.colors.push(new CColor(249, 182, 57));
	elem.colors.push(new CColor(207, 109, 164));
	elem.colors.push(new CColor(250, 141, 61));
	elem.colors.push(new CColor(255, 222, 102));
	elem.colors.push(new CColor(212, 144, 197));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Oriel';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(87, 95, 109));
	elem.colors.push(new CColor(255, 243, 157));
	elem.colors.push(new CColor(254, 134, 55));
	elem.colors.push(new CColor(117, 152, 217));
	elem.colors.push(new CColor(179, 44, 22));
	elem.colors.push(new CColor(245, 205, 45));
	elem.colors.push(new CColor(174, 186, 213));
	elem.colors.push(new CColor(119, 124, 132));
	elem.colors.push(new CColor(210, 97, 28));
	elem.colors.push(new CColor(59, 67, 91));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Origin';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(70, 70, 83));
	elem.colors.push(new CColor(221, 233, 236));
	elem.colors.push(new CColor(114, 124, 163));
	elem.colors.push(new CColor(159, 184, 205));
	elem.colors.push(new CColor(210, 218, 122));
	elem.colors.push(new CColor(250, 218, 122));
	elem.colors.push(new CColor(184, 132, 114));
	elem.colors.push(new CColor(142, 115, 106));
	elem.colors.push(new CColor(178, 146, 202));
	elem.colors.push(new CColor(107, 86, 128));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Paper';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(68, 77, 38));
	elem.colors.push(new CColor(254, 250, 201));
	elem.colors.push(new CColor(165, 181, 146));
	elem.colors.push(new CColor(243, 164, 71));
	elem.colors.push(new CColor(231, 188, 41));
	elem.colors.push(new CColor(208, 146, 167));
	elem.colors.push(new CColor(156, 133, 192));
	elem.colors.push(new CColor(128, 158, 194));
	elem.colors.push(new CColor(142, 88, 182));
	elem.colors.push(new CColor(127, 111, 111));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Solstice';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(79, 39, 28));
	elem.colors.push(new CColor(231, 222, 201));
	elem.colors.push(new CColor(56, 145, 167));
	elem.colors.push(new CColor(254, 184, 10));
	elem.colors.push(new CColor(195, 45, 46));
	elem.colors.push(new CColor(132, 170, 51));
	elem.colors.push(new CColor(150, 67, 5));
	elem.colors.push(new CColor(71, 90, 141));
	elem.colors.push(new CColor(141, 199, 101));
	elem.colors.push(new CColor(170, 138, 20));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Technic';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(59, 59, 59));
	elem.colors.push(new CColor(212, 210, 208));
	elem.colors.push(new CColor(110, 160, 176));
	elem.colors.push(new CColor(204, 175, 10));
	elem.colors.push(new CColor(141, 137, 164));
	elem.colors.push(new CColor(116, 133, 96));
	elem.colors.push(new CColor(158, 146, 115));
	elem.colors.push(new CColor(126, 132, 141));
	elem.colors.push(new CColor(0, 200, 195));
	elem.colors.push(new CColor(161, 22, 224));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Trek';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(78, 59, 48));
	elem.colors.push(new CColor(251, 238, 201));
	elem.colors.push(new CColor(240, 162, 46));
	elem.colors.push(new CColor(165, 100, 78));
	elem.colors.push(new CColor(181, 139, 128));
	elem.colors.push(new CColor(195, 152, 109));
	elem.colors.push(new CColor(161, 149, 116));
	elem.colors.push(new CColor(193, 117, 41));
	elem.colors.push(new CColor(173, 31, 31));
	elem.colors.push(new CColor(255, 196, 47));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Urban';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(66, 68, 86));
	elem.colors.push(new CColor(222, 222, 222));
	elem.colors.push(new CColor(83, 84, 138));
	elem.colors.push(new CColor(67, 128, 134));
	elem.colors.push(new CColor(160, 77, 163));
	elem.colors.push(new CColor(196, 101, 45));
	elem.colors.push(new CColor(139, 93, 61));
	elem.colors.push(new CColor(92, 146, 181));
	elem.colors.push(new CColor(103, 175, 189));
	elem.colors.push(new CColor(194, 168, 116));
	g_oUserColorScheme.push(elem);
	elem = new CAscColorScheme();
	elem.name = 'Verve';
	elem.colors.push(new CColor(0, 0, 0));
	elem.colors.push(new CColor(255, 255, 255));
	elem.colors.push(new CColor(102, 102, 102));
	elem.colors.push(new CColor(210, 210, 210));
	elem.colors.push(new CColor(255, 56, 140));
	elem.colors.push(new CColor(228, 0, 89));
	elem.colors.push(new CColor(156, 0, 127));
	elem.colors.push(new CColor(104, 0, 127));
	elem.colors.push(new CColor(0, 91, 211));
	elem.colors.push(new CColor(0, 52, 158));
	elem.colors.push(new CColor(23, 187, 253));
	elem.colors.push(new CColor(255, 121, 194));
	g_oUserColorScheme.push(elem);

var g_oUserTexturePresets = [
    "data:image/png;base64, ",
    "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAClNJREFUeNpkmdmO3DYQRbVQUm9jGEbgR7/5//8myS84BuzJTHerN0m5xcO+Fhw9CGyKLNZya2PXp39/LMvSNM3tdtN7nufz+bzZbF5eXk6nU9/3mhy222qev3371nXddrdJKV3z07atvtZ1rWXj6fz29rbf7w+Hw/F4FB0NqqoathsRvFwuWqmNWqyBNm764efPn4/HQ5M6Syu1XXQ00DvWaZuoaOl2u9UicanBIz8aa4GW8oaPOT/6pLfmNRjHUVINwyC+oatJDaZpen19Fc3dbmc6DCRVnx+t0UGa0VtjPiWN0BYU9Q3pJbEGoqiz7/e7xlogLVbVop+aRE9aACGxlb9WUoze+soxWqk1IqgBZ+ktCvdrrMdKWimB+SQd6x1speeDAkRUu6rnY/n0jsVdC4tajJSoUOYTBY052+OuWuCVee3VEdooRqVdrKRJbOWNCaERRWP0Lyr6LDk0YA/S6Oeh28OHSHMAcBFgoKBHUjEOW9cV+kCFKFh6Sk1wo5VgDmBgd2aSFa79OhKFawVmZV5rREszgFcUYYuxPgnysIhSUbw2pr5DJQimRwPp6XIecS8dpxnAyqNDE7CFelj8etXZ6B89wXT4jkQchuvtAk8ADhNItnDSbAU8FJ8CwkiOc+gnawwPe6h4xXtEOSwFjwIHDgiK9Y1POm/IT5h1HOXMIqHYgWrxEgzU73b3MR74QDFztZi/Lj8aS+X77Q7sogvwClJDI49LHCBl6oPY0gd8Z7zEjDaIuliRqowYEQWC+on+NRi6Xgve39/F5YcPHySGfmrc9RE1AAn2wg5NeFHADp+D12A9BVSKETVCpfAemg9LBgjwZ/abdRTMRhBGHNFewItrR4BYKvwAvBoY06M4O1+JSgWyS51YDUQwP4Dd7beY3OAFJbg6NrIXh8MHujqFTauQaF4vvw5GsHV8Xr8BjwSJMci1TxGQkMkclwMyPIsJsvR6g63wuCZ8AtRP+SkL6gakgzAmw7ip5SDEthtyXCJE8ZtQBvTMK2ETDemrPANeCTmcp41aQxCRQNPTXeK8qvj8OvlohlTBdiKLgSGMpHVAB2cEpOvtV9LgjPDGzWbJJiORsZiQ3dahA7mh9Q3a2tTZFMQCUD+eT+t4ZvuUJEGUIg6xCKxcruUA/cTnwzqrnIo1WSwlDf0AESRkYySffsB2NhbyMzY3K7fQfJVAA0KDVmTaNluWkqdwk8jtmT/SlGakyDUQ7QSgAplhAkngiZiHw6ItC8PPpEiD28uJqKI4r2Crbje77dCHGsbzRawPmx4wQUuGxShTNT3mKUMhG6sNH9dMfQtJ0tDbOe63q87vNhHTpYnb5Q5BYXu/OUz3OCu0RfZwacUAPVlKw9POaIfHVwAKC4A2KXl+TCYLZeKOs9b0fOR8Yno75HDqkoZoy/GEEBvFtLKTLmaRHCCFEYfX9Qxchmz1DE94iWFOnq3/9+DRic/IR60I9bWHogCWKVUDEYxC/UiV4byGjoFUvRT4e9KmQNmuclHQ+XgKvZCbHVSwkam4+nP0b9rGD+JCF73CE9U2T1OVMsG6L3vrEsnsB+wik5ZUb+k5A17xOBfvJdl1vTsF8M5hpB1kWKtkmWZnw3WLcb9ebDgfQdAObZGMkcyVIfByODGKy0nPGG2wr5OxKaCDNu91lDL8jQQmiQtBKhUoJ5BIUBa8qCZQJhsgUaqr6Y4+IlQ+keRC2VEbggLcYbe3L685U9WKEzgPPsWeoyGjbKUDwXyKZMHBstCEaEFE1xx1KV00ryx0GUd1dppRFAi+o2qvlII0UOyJtkx+3rTd0N9Opz///ktW/vr16y+oPCaFAZlYcSx2ycGXiK4iVFK16y0CRmkNsnBIGbko1zNxfF2pNEVV4g9Nh8R1gwwomBIvep63CNGCitgCc5HO6/r93ze0q5pRJ2oNwCiBsHs+KN85UdqKiJzDhCNIWK2J7oqC/VkhxaMeygGWIEkKr5dZmv7y5YvYWjJNsogYjXIo20EDSniaADESkIe0o9k9P0OuHajl6RcYL/UC8AET7Lp04UgDLhyiWmBCk9+/f5dI+Mrjdicaiya1PD09hVb4EVWyPhO0YBEPdZP4C9FdS2Xh8poe3wGaCG5f0VuWRXJZv30+l8foLsjdbHYdEWkLZ8SIdXQhmdjPnbnmakbbBAXwG4xOJR6WwJPtK9PsDntr+vPnz1SwoqBy0nUUkBJxsVi20wA6Yfkm4ng8ur9b5wAleKpC9qMqQqFI3fLDeYjET6TFxDKT2Ora5DIEkFDnRD0rtiQQJSicshMusQiyuuolnNK/iyGuHmQd5T7o4NpgK9qy6QGwqGocHW0BUYOtctUz5wpvnh5N3Y/Xy+16+fjxY98Fo+qWPv3xiVbsei+9Zd9FeOurTn26+pwh/xRy9TO8NYsekfAZ9/HoaODmxdWvLKPGNa4zbtfb445XPS4T0aBum9N4jDiFW2lz9PIp4agAUFC1ZVGn3rtNqc/c/GALTtUu6Y8aiUoEwIE2IEuK+y3uu5EpBRKAIAhF5T+OkNNApqGBxppuQKyVKCOfPFF2g3SKJcDnNgv/xY6ESZcVvqFYcmoJOs59bqz18/X1Vfr0LY/rSa05vR85lX7fly109OQD4qRDhjHq+jHQ3XeGLPy5YoiOBoVbRFmBtLh/OWzy456M2IaS3aO6QiRqG7ncCTjy4ZIuy367NnJfVKAmbSknQFGs4KL4F1ksivHsO1zLWOdA2FHevR4A4IYHlyQDYhCIr4Mi3v3bZUSi9Hb96fAY6TO1AJZLEcj5ZoELIF8j4hOuUqSt6JRyK0vQR69OJNR8hDfXcL6nCNkUNqmWuNgQLUkpE+y3B8xM78p1Lc6IE1hJTGoLnHGSvFjz0rrTMKWsFpRioSrZdt0nskD1UrmkRFxCAy7GpTxqN0rocwjleJkkCT9QqbPMipzRT9TV+TIqJg3bTfSJS0E6MBBNbaEfodJXcfasKBe18lWTjUi94QLSdbf7xHX+CQFS5x6aPlsDLuUQd90AalLVqZscl8vwgec2qycskJIgVBov5wEz4TsSly7rex8yDzFPY0KoK3q7Vb42GSBLeHOiBLiIug5ypUUAub749wMVPAtoO8/jBECbIMkFJKEVYRwXuHr0bcz6On19n+vL6a6NXjWw7DbfISQGVdENOnCd2DatLYWjiKHw/+cB7gRLhJyK8wIS3+q654GO7/e4dE3rSzpbMHxzevge0D6MFvESQgD1E38cuRdyKwtW3Ak6IhDDHWbJp8QgeU+katyV7OHL0lzuLb/dpj4dqpztSx9RAJrGg0NlWD/fha7bfy0jBvni05FC88fz6eXlJVnhvhsu0OmSge+MS5fsv9f40yYKoWkS6tf9PkaJlH8622msNlKntoNIJz1qvmD3/cc//v8NIPs6nijqf7DIiRpIz/rK/1t2OmnXRem6Ymmb5P+2pCF6r8iPuTx010osDKma7AdrhbsqWqd6JsG1b37t5+CJDgc1ODuVWDgtLodQTKlZqpLvwRYbo0nOlP8TYAD8wdiTL7IMZAAAAABJRU5ErkJggg==",
    "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABs9JREFUeNp8mVlW3EoQRB90gYdfL8X735bBYOCFdMUlSLVdHzoldQ05Rg598/Pnz8vl8vr6+vb2xuTl5SWTtdbrPvL95ubm9vb2v31kkgU888oWnhn5ko1PT0/39/d5fvv27fn5OV9yCOvzzLK7uztOyzxHZTHb8z0r2bIGWSEik6y+2QdkZXBQ1kONr7kpz8fHR1bmYyaw9+fPH3jgC3QwcrdkuT4jJ2xk3e6Ds8Yk4+Z98F0S/egcRpnkjhAamnLO3T48EyLWPqCGNUhRFS3p7QFn0pFny0C+VUqeYdHFSCJkIVTOR4mo5cw5a2R1eX0PfvvvfUiZi5n0l9gHKoBjJBTb+vXrl1t6hGi4Ql1qEOPZlBieMkNsUMNHxaZ5ypaq9/X3799KMcbOxeiRNZ7Depkf0mIspaKBM886VemvfdB4RUg4Ab4J9yGRE3hFidpAuxrzGECYWW9/Ga81WqFD185zq8ahteHRSlTXOUsLQaiEy48fP7JfS8wkxEYjaAF3zdIwDa8Ql1fgTSeIkI4TL5f8CvKxWDRhAQAEdnz58iUTPZHJ5qoxVfeoDrhsZcMHktMUMEoGJqzS4VDfPI94QxaErBz19etXDswrW5b6HrD59vfRBtdG2Qy03ntovg8PD1gIxpcnikJ1q/28z2qP+6T1XULNhijKgog/R6uOTARJTRuFoMTszRMCspfFq4Ndh478jBEwB5oNZwMSNURIBCAwRGMiAIRmMDtIBLF0L8R2eHVf0KtFPN27Iy50QJA2Grrv9yFZQKBQiVEiyxHiPiLviDMdTbn49fOQrI5ReQbN1SkcIxgl5GJ+CjM8X94HP+G2R8jUWqUdW4FRFHdofS11jYT0R9bHrVCTqhGlIFGfaKxqbNs8EQjhxahkWgJDG+yuFTCDvhYbuIxQsybzfAfVWn2IClkiGJ64oTCZ85/3sRSgsGSgULBGD0GByxA4LCXfGpHgaoLgAKKgGw/ImnwEh49QPfAzi6ILMpM8IZpXsdtD2ZUTdVUoZhAkWCa4mHh2HqU5boRidPo/2s2XcD/I4oLv378jcBEcG4giOCGvUQ0KRZwNwgarM0SDpZjBOsdgs2GdwOAqUmjC6qgzLSNYRshtk+9E2WONFpxz6LEv0DtMw5UWtgW5Ar0yICZinczxmM65BziNGNqELjyO1fAB1pFeOiQX4jrp6O3ah7DnynZhEYFdMNlVxjJ9U4wDQlrC2GwnysgGoapE4U3lQhaWrslezShZGTR60Hh3PvJzLOD1nNF3FBd4tUXwJYSKVa1lZNwhznRIPk3LNiVyiiIFMhCMybsJxdXUu5cN1s9ZvKls5yM6FrF1I2s4YGdwPBv6rbGuejhbNLKRnHngubhqwzjyFy1ppDcAbFsVV3boYCW2ZYSReqHknDziKKa4Bm9jzDJF6W1xn73s+0gWtIOudUe1eH526txMdp03LPjIIIb6e6kyaJNSilpkdwmMOeYFktUe3dS42JM3OE3sQx6HZ+4mT4wTc7mPnZYSVx27cxVvNfk2jxi72kUIWYswpF6AokSMy+XOgsxyVDRqBXUi2R+tZoXA4VVNaENxvifyRG4Rw+17CcS9W6FmFEcvto1GgaQALBVTbJkk2nuyq2OvyrhnopEFlBtL5oSi4TVnIq4OQucoDKGpd6ksePZk230HJ+eyfXjlUMFYP9Q3orjkjjaHKlYKhstD9efaY9iBlP1bWjrUSA0IlJ3YdBHKRqsBc8zVjtPjXAkOjBnh0qNH6qYhd4Vs/NFFqBg+zHTQNGxoqLUNrtO30ZeTDlKg0UkYPstPndJsZA2/lb+rKat0nFsP7ZINmCPGe767IuY4INJi/mFbV235LLBzh8PviLyVbg09SmqLP7PZlh9916OyU99gj70Ay1zjLp5li6BFS3e5mxGBriAziJjaxBBOpn+Op3rJMsES5e2bdZraVmVCayuBydWg1B0e/J82JHK1RLVcpf75FKrNWOTY5OLcQelG5oDf7kGeG9iSayZtDgfQb/kW9Yk0QUekBRAb/4fW/tHpO5tjF1R2pjpr4i7iz/EvhtGRT3REPKVrtc6tz8mjDfCRbLUNWN4MTBlSh+7lBQ3oAxFGm2mEnZEANtZgD5h55xo2CuwLWahtUbyRzVYYJn/GPdM9X+VSoTYmncnVtugYEp6hm3Mi9Y0HWjn6y/hnQS1Y3tgL7VZ7d3tGSCVR6XaGerS2s2fG+UcDXBwC+OmzWSPYeDGp72qCi8Ob5Pp/GJOjZFgLKAexMOLHx8eu/xT5tv5voRSd4ozW+Ajf/kArzq4L3gCufvoHYAdbQedpH7SW3WvX+X8BBgAdQTe+hA31AQAAAABJRU5ErkJggg==",
    "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABlZJREFUeNp0mclS3EAQRDGIzeH//0pOEIHN7tK88SMjW9aBEN2t6lqzlvnx9PT0/v7++fl5eXn59fX18fFxcXFxdXU1KxfxfJ0etnif89u2zcp8MhTm5ce/x094yfUhy+fz71CYb9/e3mb95uYGBob+/Ltx/RzydHFTdIeVj9MzHw43Q2vWZ1E6PJCav4ficT1b19fXrM+/8wl62e9QDuj6nrS43vuQDFpuybqyzYukVB4PqkLO2cJivJ+1NYxzH6dhS2NJlMtG55enRxGh7oqk0oIaJE28qoB7d7ZKiCQnrfQtVO27RMul/JdrPJPGReWjJ2yKaiG4sYddVm2n6HCGmxMckEjlHQq2sosP6QkwAFv39/ffbBlic5pDmKY4g4kMpdVMK2fyVLtnxZzk5OTw8PLycmYLVlJbumrFvLvzIAZqHwpQzwOGSLEFNe6dvwMNuKzocHb52ZZNNrgV5uCYMAYaWMEtttMzRMELYxbXmS1IcQBJ5thQ48DQnHsz2uZ9GN24WOsgSsIVJsOmHmZXaFAeAgJqBlphIdcPo0k/7f7nz58tb5KWnOlJsuWthWfFKBKqpxTGCK3rtPtuhP9huk5tukiwSbcziFJofMCL0wh4pLCuwnju7u7GxJsfJCClQdPl15WEtBQdaoJTsa5jZQjz1e/fv3cYQh+H+SHDJ6mX3KZYtoQYrh//TZflwzlDDFVgzvvg1th9O8z8Klm5S4VcKbYBE0LMSi2tCShSOOiRGnECc0+O6l9cTYYEiML99Rk/xYs5j/Iyz1SW9DoPc9fQ2QFC9oUZ/s1KgfTC9abqq9PDrSK1KQ8snPWJdvRNVAK8oAnohdZ5ma2hvEeizqixtIiFoWWTCoAQfCPr0Kpaj5U18WW8Y1yLHLPLlk6A07GhYuWj6qqUwSs9AxHLPd1LwMuqs+L6uLBJ3yyFzb+vr69aENNwhvX6PONDD6vClXXRkQjdqt4oCDAA/ezXr18U78OHDovF18SldaDASSENJ1avCHkuWVcwLIBN/5j14cYt1YbvV7WelDWZ7Ylqzkj/Zsu7E2ZQAxoy1JVeN+f8xNfwmohQFrBcEXSyIs84sOPYDtsSuEmtiG34WWZW0AHgQAeHVXLW2cRp3ihAArPbmp5M48aU3dG8DNZRshmh8zIiopIEZG6aLdGEk6o8oZiSbiQcxX/D6ersXJNeJWdrAs3FTBsV3Yl/GVKuIOQOuVmPZ41btVtyUKjIIpFYReLab1XJoMty6ajt9vZ2h/vM7Wu5Ut2YCKmGoGizXwW7lUxmUnF1hUxS9RnlK5hTydlzmllTWybNHCvo3U4DCgsz0tdSb3eytUQsgM7Kovqf5LWA5rDlTBgCgXNSwnNGadM72VtChlJlrgL9rHwSX9BcVWCJdln7p59MGO7MZNzlgEWAyICCAyFRZ69aTTWnnEq1aqigdY+qx8dHpiVs47zkExCLBn/sbf9TvVqW5+UMcAZuZSNOM0jih/KUZfSxpPxNmWz37Jh5l5Usfg4dKGsEeS3H8jDV7JoJSBWbKq3hnbVirmc/vvpclVMco01d12nBK+QFto2KoO6mqaeGLlQzyx4mq6ojDi2u2FWX5uxjs7RNxMKrKnPpsJVk0kA18lSLBY05eMoGTvfYsu+u3Fxjywz4FclKi1q/hjbK4I0EGeNJW86txPV94sK+Q3FztFfl3ue/p/RBoNVMRqgbgrCV1jxrS1SsqV8Oxo1w284qlX7+/JljpnW2mDOczNmV387MPTw8iBECVc0814QqWmbX4AAsZ4s0+zUtqpmgerKj2Q4HMt9cL2PttfNOv0mvz1KskmONhvUzXs7J5zBDr+NrX7KEqjit6iPnLtXtJYbXoGt3oeQjxz3+uFB/c4i//jDhoMCbUlt5F6Gny2oBktLG9tqTrQxVwKuekqpG+fZqJUl95crz8/PetiRg5ukc9CQJY6LK3+yS8z1bj3zAhRrf2zttq6OUk/2vqC+5axJmaAs9ZZAsG6so331LWlUqTalfhUAaZf3hIxNI9tlZgJStzUv5Iw293VlpjoTv7u78ldB2mWzPxfOZDE07MAeYR8w6/eNsvZweB/fclAUqs7UEatz8+vQMtfOYa06PeuBmVrNjzp85+DGxMFpEHaDH+Sghh0vucHZiVUi5V3UYwnP+rwADAN6ZnhHCe04NAAAAAElFTkSuQmCC",
    "data:image/png;base64, ",
    "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAB8JJREFUeNpkmdlWIzEMREkwO/n/T+QRDvvOlPuGm5rGDxzj9iJLpZLkbG5ubrbb7c/Svr+/8/f4+Pjo6Cj9r6+vy8vL9/f3DH5+fqb/8fGRwUx4eXkZY5ydneXfo6Wlc3Fxka1eX18zLV/Tz+DJyUn6WZ45n0vLqs1mk8kPDw85JV+zfyZnMF9PT0/ZfCAELRvlW+ZlWcbTyV/kzmH8i+g5L50IkR3Oz885NTvkb+Zn8HhpP79ts7R8YofcNv1MyGAOzebbpWWHjIy3tzd6HI/sm9/GLbM4n9LP1wyiVJZwmXQcz3U5DN1wbSYgJapFQ3zCPmnodUqXS3MtjmF3DlBDXItl7KU0LM9eWYis6AlI9B04BcVrekTPuJfZaweVqj0AoRzYHnG9KF+RjIspFihkz4zHuPf394jFfUAIsjKNDelrpfH09BSVZH2mcqHIEdlbiEzwchkBTJkfAGQwk8EHquJiLNS+LEdu9ME+ET1znp+fMSUyzQknS0OHLNaCaBFUYQWUh9eIVs5Gc2NpYjHnteHwCaRHu0iGNOkowIjHZSWuJPYBLDdDZ6okM6EJUIVYyE1HFKsknQOxshBFsj8KQz6gPG+YXpaFKjggdkHq7BuCyUg+7XY7TJm/d3d3WXl9fY16MicTkFgIZpMQBxIgjQbKrRAL9np8fAx7ob9MgxamwtEzqmYlCgccURJkxr+gKoNMRhnbahhUUmhXsLEh83GXvYa2WyA7YYfsHMOQ7Id6MCjLQIPEQ+NKhgphh1c2R3gZ6VSQETxwhak8proj89KiT5lX8sTiiKVnIERzrHsaxOQ8HSti4R/omAYYYt/xlzMap5q1R7CUsGUCd5DtpHXpTYFwSbXuiTLo1M7qeP0FyKPVle1pUjlz9GI9GqsxrSMVYsVpgKz2laWn0MYBL6RW6YAPbqavAQVNL8LU64EYf4MVVKwiubxGQE8Beow7IX91deUCRDGmkiDka5TERlmDKxBQVRKglMRFtyyK3JiMCyS6GAr1fZlvQCqYA7wjL04XO6LCDvhwqexM+BMlHSRyAbhav8NpyIsyng6XZB/YbjoCHoHCTIDSeV+a5oDZWyyVD/fqpHoP481YOimO2dgyjrHzIKp8VzPdI5pGYVADCuP4hjDqwbP+YqsZTvti02yF6+iVuuQAHNKg9gr7t5NGemimAyWHYb5YhL7BTrz3NcS7/qED0tljyy0aGQpHgNMihjnBHkFVWAtk9tYxQBVwJW2KWxi1pu5b4VgQJyCXdxcTKSabmgIRooJe2abUcAbWFtoYhQVluIGPYGxzbSCVkzqHZIJEqjq5tImQ4bVDQourNHbQutF9oo1Q3RmfiIm76vxmEEY31M4neUt7KQqgMbY06rv0IJvKnqRYBx4HRpmRepA0y8QmBoWE0HaYkLSMtWROCEdqoLcieraSLMCJqOAmJlvp5/Q50pGyqQjx+6JwRKIC0nAk9JsdE+NQ2CplcAQgmnSo6VanScDo6N0E4+x9SF+grTch08xAloua7EpmDXYxzmRBaeLKNZxz4CEdoam8MyG9IbqBYBkUKIReaazh3H0zRIToAgRFZP8JeYvMroylHGaTS+l98DJmZWFDhxqGpwDZyJ073UUvqAMtqqahyVQ4hqM2lPfEDVIyLa5KUaRzmCxwpUaSF+hXCU0sliioDnSqObhHjuwUhYKWNwyQBIfBIOZ6RA+zia476Pj6YGzgCLBrmBkrLjYj0BBCGD1RpekEPpyEBbQjDdezVuMr6kwAVUrSYLG7Lx1ub29TrJHrwZzEUYnYAsY4Su4hGjg4HBHuIAXSTKCHrxGCbAUMmE8jMbxlBToMkJ19q0zLB+iAkBBnQVDfUQjY/ZLTmaBUblIunozxhvn9C5nZn+zAMkgSW1BrkDTjDWSI+IFwAXkGbJM79IGtj/5vLRDXw/TDQAEXeFICTowbxKz4BlW73krGi7brGDy6rBISqkMtcue5P6xozFmVoJpSZ45YPss0Xzunhfj50yRnJfYJUuI8PPpYHBtwyP54cTCt8MUHkMquKMBxBWqArrRCBWseseL9rTdbhWqxT61BZPDVoFnngNNfo/jiunpO8rFDy7T0ijGrHuORMrW2TYagmaiQwlrH9ulWdYJxlnAGxNt5uWzX/G7RkDJiz8Lm+f0MhI1IgKjgOB5tEXMynoVhrKyKiwSwIR4e6JHYVDZLqEAViDfO/AvjANy0Wc5Yl5r/exvTVGTVGc3xey0/HZAG+jTfkadNgTqNUQCDZ1hOGYjf6RiCN1CMvorVtmAJW1uBEal0OqvWLgZ9mSLl1FaTIMx6jabm0KvcyIClHZHDdNQnRfG64p3OHQAoeiUP4GWAXH5Ybq/SVEFgiGhOgtNXL9Odolgh8pORwd4kUZY2blqSzMDTrwZeurlEJPme069wjANb9eePHc04HW18fPN1yBdUasGtaZOvD7CiFRKnIlA/o/UzhPm45ORvC50B/H28lI0tWEDk6NoG5FrUUzvwGtavmPb7VRcn8oGq43cnJp7FtU+XRinG0WGcrRABervdjuKE7DSLM5IJ8Fs/Q3AzEimfuPglEdPgYpkQSstfQgUVWIgNDSEHM/lpTe3uH5J8tmtAYHiSdAsyXzJUQKtNsDeWu5po4He9JFGjzn8CDADdTKgo2oIe5AAAAABJRU5ErkJggg==",
    "data:image/png;base64, ",
    "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAC4lJREFUeNpM2UlyHMcVgGE00JgnUgBJUKTEE3jpM3jtpbe+gve6jvcO38J7e6eQEKYoieKIGSAA/9UflOEKsqMq8+Wbx8Ts3//4bmtr6+rq6mTx3N3d9bm0tLS5ubm3t7eysnJ6evrx48fz8/O1tbX9/f22NjY2gr+9vb25ubm4uFhfX2/r/v6+levr6+Xl5T6/fPkSqrb6ffToUZ+z2ezy8rKDoe0z/BY7GExHOhiV9+/f9zkPdbiitLu7++nTp7dv30IX+bY6s7q6Gt75fN6ZDx8+PH36dOX3J1ytBxnY48ePoxGqiLXVYnh6iZUEC2BgS5I4iFYA94unz061ReYA5u0lJaCWXr16FUTMtRei+Gsx/XUygGgkDR30myTb29vh7UjAcRlnYWtlcNzZ2AoY+bBlk1QVGIT99knZHT86OuplHsbU0BvNh6KTT548+eGHH8KL0vricfjNmzc0EcaU0XpnaSjOerldPEyJS7IlAEttLh4WTx0d2dnZaQtbGaTf+fR/Pg9pOoxqoHT7/Pnz1nvHK08KOGMFnC4TuvV85W7xHBwc0FOE6a/f4HsJTzqOs2gH32e/cZZ4SISZs/YZ9332Mo+hCMR49HhiPk431EDQIJmSJvoNL4egqp7erfewbEbsYGI4GKMYGsruN55SR1thI+c8e3EUkdKTSlNVlg00lXACvoyqJ3QdYXpqJn2o2wogVj5//gxzqmLr1lMBRodU14tHfLDbcrbsw0bfeXEifv/99yEKo2PkjrkRa/HRep+Q8k7+MFs8ke9IWi96ko33CN7IdZyC6ca6lRBOhmZvGh7hnQOFq5XM12esy1sxHQEyZB1aaTEy6eD4+LjFQikkiZS3wSkztUJPIe9XYgqyI1EhWMgf2BKi7CIDSTDyaqyELujURg1nZ2cW44m3ClXxy5oBS6fBlOe4cCsMHdWYYIq1xYN0nLT+9ddfx+WcjZhAKMkFkedABBWnAjPsyS3pt9VnhHcXT+uhlkEYPTtSXvDyX4vcTqzEJTftCU8qn0IyXPB2OH65USvkG9jDKxILdaYJGI2whyTssR5M3LfFyTpLbEhg4FIDgPxiRaXKZ+acvzolOBPiavGkyZEY5YWRhVOJAsIVOhKvKbhTilgK67P3SAbTJ5wxFC1op3BbXh7hmS6VE5E0D6mc1pLM0W+H+WMHuJGkPAroN998w6YR7rjaIoO0q/T2BCyhx5MAXF08wWBL7uUVAij4fONBdQnE0/sFLRTomQXVuGjEikzYWYGpMIyt3vUj+Bi1n6ikFRk98THIidCJnFQhiYlEdaYwVi6zV2fIJ2ZZFnYew2n6Tfft5gBOZdDsu7V4WuQk4exsW5FTbcWTborXzg8PDys7tKVtIvrIKAktWFrvhQv3K/2kHkYXyOGVFRUZ3p1IIklV1m+dnZ4WLOdnZ5cXF1E5PDhQY/jxFDitdrJjfDPmWlENaELRHaHEUQIYzhuXqUed1jhwmnbJQxLYtH6KrK1UKNjLwCl58lcxHJawx41MKKeP7O+8F7kgREOv1BBSfoNdaJmbtOl+pFnW1zVIxa0n2FQ8trcnO+gPiQIiLDyXvWQmIip/ujmomalFngcbHfDRrJYMvWRT8PrNPjkuErBJQ1NWkzmlAOyHtzP8jAIiKQUEwJkyIu/pUSiD4aDScsDkbMvBUdOY8tPHj+2WPDE6ug/Vdp6/y5M8iebpVmDCxbc0gIGxjmTIHGRT3Qg53Ei91yOlp9ajzYk9o73RM05ZvvoapQ6Iu9G6KG2cPbZwoyUcZVSxUhaxKCakKyr/9ddfhVQwaZq/hjO6HYlKwNxOuGTXSVschdcnUKgVkFgmdw+7qLUc0S+f0y1FbwQseGmlX6b86quvkFAx+40V1UZf3osMMMn/1z//Md0vzdq78S8XT691DxHIxLUAyl+0tR9hyScqEanQsDWa6eHvI+ICGwLXtCSwnuLs/LwAmf3e6d4vmg79agLM/vPP71ImO2p9HtDtPeL+RkoDp4LK1rDElg5sNPKaZrm3x+xqGqB+Rnz9+jXVgucAZdrw//TTT3Npsw/uyfZabxMzcY3LXErTLGCTnmuPdCr4NYwcWRSnZl7YE69pTlqXdXvhEqjP0TYtGSWG90gEvWRBKacns6ahfCLamkHVekzhXqBiFOMGMeKgNEb31CFj0bcKNuWPNhR8gsock/m3b9OTWwb2Ciwla9slwCGGFKNnHKOH3jqwsGkFYmiIEdo4Uz/adQ8Suw/jqwKeA3V4gEYpFCKUaeiZWK0HHEC44lvLwAFoq5URrVpwuc0wGP4OjjZdH6qSOjVlQf2NXpQaCXR6cqYE6TqoOlEaIQEzBNaD72zadQkADzK6BlVlDI/GssEHKhL4s2fPGgfnpjl5crQixuuYoMv8SaGIQOkx7FnTHY5+UJNkMaq5hIBloz47G73g05OUZjxher+U3UuSz/7197/xAFVMkpTQI9bwCYWJQ5WIS8E8EtXFIjWHXXD89ttvSmdb3377rUZIbyM/j3sKB10BjT55IifDRqYkph7JltJMEkuGEoxo75gC2qLyzJTMF5kAWjGcyQJxxqviRteQ8tR1ehodkdFo7qJCalZoSYnXFy9eBP3jjz+qIQ/F/9MnswDpxXbHgymNjUKkMHBWBykbl26sEiBItXKYaMoR7h3c9LklM5mF1MgQ0pcvXzKu9FOblnHDXko0HaRdF3cMpCcLTHk2u+rG1EEuyC/5QzxQyrt376aMb6/vzo87GTla/JNDMEbJnVYjvASm/Y2GGlKZMo+Ec9xaSW/syCta4Zqy9Bj7ol5nMRnRDaXLAu8mFsIZquKmA72bWl3pBpAJ4j5WmDKSBXUYtH7i1z2ZmmPe0juJMMqW6uQUDdl8SDzmKpIZU6P0/1Nk52PFRKA8KK5pvvdemhHa5XzKl86x46oQJiQwrmnEbTeYdhN+SgXm6eA4QWRisTOuvuUtdpQDA5MUdEj0UaYxa4SqrZ9//jl9F9rRUKfpsi0i9W5O7MmnlTgNC17no+XQp7veaFE3osjEawCS4biyUpE6NWZ2iS2FhbfU9ebNm5GT5Qv+7hJgZ/8RFb54sRP356dnmvXN7Y3Jqf7ypz+kAwOduFB6k0Zsh1pJGY2yIZaPj4sX2Ui/NcbJpJJmXfbxM/Ani4uayc8up2yyt7sn49zeLToIl58YV8IUqTTXYgoLL8fXX1R8xoWlexSxJgVgOpGOjo46e3x8rFsf7ZqrB4wGPKWJpWlwnd1PHUdheHL2eWoXyklRdWEnUXXYNDIGt/EHCyle1AwY1zhSqGZGT9v7q1evGuZpd4L5cnN7f7c2X1nQerh9XVtdU14jTeuTy5shiTuu2iQwDX+7agtnTyCLbErfPbkOparc7phzSvlZxzH6toW5pwE9PGefp9BbXdwr8NQpwjiaTkhJN7pIUS6JeIbKpT4ynL6K0NFwaZund/Dw8DBufvnll829qXiv5G9rD8Pg5fWUY/d3H7kE0H9f314/3Iku3HfOeY1scpVKrAUQZUJv/G1nSK9P4viJYbaW8yQn3jb+oCI50d+7t+9d7B69fBm2D+/eu4MoEh8m743FU9SY4GIrAu4wxx0wh4uzqmG7AnbcjkBSNESv1iACBXkrVY67lRnfGtky3whDMeHSm4StULb0Pj+/uly+mbS3tbuzsjbF9uXN9cX7d/e39bLTbeLS3Wx5aeW/r4831lZ2d7efPn/WaFPPsru1O/0Z5sPbWodnRwenJx/v7pfmG3vLGzVQm7PVteuL04vzk+svt4KgbFufub+9PQ0p1ah3b/P6hM89i4Tp9m2+ka0vzy+miyT3BZKWTK07vZw6z9X1ta3N9WnIub55ur6aLdav7h/+rOKatEA+PW0WOtlY32kYZc1pQrq6vMp1LpYOnjwVQ+Py3Dy96Hmmv6aUfmdLN4XI/v7UcaTsFPY/AQYAVM4VTMddBr0AAAAASUVORK5CYII=",
    "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABfRJREFUeNp8mWt66zgMQ28a9bH/jc1GZgNt0mbgwDnFgM7VD3+OIlF8ghR9uvz7z5/7uN1uPDXWWl9fXz8/P3o5n8+3+zidTnrq58vLi16+v7/11Ltmrtfrz2No2ctj6F0zWimap/swKU/qRfRNjY3b6SLHBgjBn98ZntQWuNcQdQkgzvTOdi/WSbfHgJqf7+/v8GqaqGN7mjtYsUpSbaVIrUclYsXK8PGWytx4Rv+mnlJCZDMDXiyCXr+YZYMoIrfPSHL+eXoML9NT5PJsxOOZijQdS5KWgcJmxLnTDCE6mrCUXqlJSwxnqBnWPVns+kVGNOvWKIb23mWfYA/bOKyczB5q25ktvdiaJlrqZCBhGnEesRtRA69MD/XxtceBiUbP9zGlKg3xFwtE1mGuNY50aO4ub+6mN2gPhgMaNHm5XHDnjO30kgojnAlF6vn29uboM9yYJn68jB92WK+AJ0uTyk8SDM1Y5RwMcFjrGMvEzevr66v+Sm7wM52yR2K6rbkpWfkJTiY4iRYMAYmId2hKgIoIS7P8ilIoChwntBjZUWSeBKwk0wU9yQeAkrFP+K884BmhdF5HECSceQq3kE3zBpTEOUxcAIs6tsCaxgK7E/QZoDxZLHcdCjaJaMi3KjwLhtYEwETzYvqQXPpQuXAhiP/Si+C0BOCsLcbTUQA0NHGYtnOeqiEBPf1yqhAffZZ5N7am3Noghzg0is4Wbk1L+Rhvga3yoXqWz2X0bIgjtIWQJdCsNKwzqJMyTh0pib0eOkakHAGuyTQpGWT0Iu4wRLswhNY33JrWJV5IBWl1xChZfTzIB01xlhWAXa3skJHr5LYmEIC2CISVD7Pe9LyJT5mOJoSmy17vYyX0pWIqEjlbWilx/ZczmJWRrG8WWSuzng1qOyR/CUC/dXqlCA4mIWapU/VqVr0z7BmZTKv+ycjbmM5aL4kiN8ZKv6myDKgDitNvprFApVn82PFX2cjPpFvVTrozeb1KyGSo3lFPomMSdGWxCvspl70N4TKAy7Hm9SbdvG5TFNlluEzYe701Xbsymrlx6HLVMd8Ug+bG4KQSD54APztG3Vky9hFpixLhSgFjaijRH5/jPbewPi9kCb+QlZlcNB9GtN+XAxUPwKsMBPPumsb9O6BURBf8zovxfue5l6yLiKu6AM2XnrMKLdyqVI2vVJnptkDW/lPO5dRb11EnjamSKWXpP22aoTorDpyh/MFjFZD+3msfKFyKZL5g00FdRR++RU1L4qNsL+Ddw8g+lAdj48O+SP3MEOGikSUhWcReQfEDi5DCPTa+S/mwkrW5JZ7JtbKHsQBn4DDaHvAH/sGWJxF10VWqJOgKgmujmSM+Ku6yp5WoRnPApi9koUOWufXsWzUAUZdSAAINgZaVRuqkagEJWlPa8r8Cd+6Pa9bUpgtAZGGIKYutGYnpDLNeyKI5L6GcvuoyVLDLZZD5KpqfdbN4Cs1Zn42diickvLpjU1cJ8gYNgkrJz+4/zxpSVAOst3fjPKn4Tf7UVsEgzNXFtW6UdAxnFZlFItAKLtTtKKX9/PzcfauylQ9zCp/ziS6W7M8oIaupOat+qSr7uRlYDrWVykwNgXsZRMDPvuVuDuc435LLTdENgVzOWp7gzbu2bB3306oDmP1PIgsn4xJRSDvvpbmSjneGVNY/W73FOjdecJfy6xxW2PT9SjseeYWZKX8WQnugpO3A8SwgK9VkTKUm6oBqdM80lTIk0gp+N+fLuiq/fGTaSZ5IZ1noWR6KlgzVrM8yANPtZtW0CK7UQSXpeV2eg3ti+fJh0ZZXhFpjn1uGzfxskT27ui0dHkPZSFMYXXLPnpXtDJF0ylUVD73y/LqRhIqb7OQcwikrsxNWrfUqGzcjVluWegY4rW4v3YRyYeEWGJZtVbros0atCMXxt8t++alTmPLrx8eHqJC/+IB4uV594P/y9x32Zmuv+p1iPTsROkWUKY/p/+59+Wwo1JdOmm/XOzcmbfVYMZz98lBt3tSNW/mZk6KUIP28D60UNPDh7j8BBgBq3suL4cOj2gAAAABJRU5ErkJggg==",
    "data:image/png;base64, ",
    "data:image/png;base64, "
];


var g_oPresetTxWarpGroups =
[
    "No Transform",
    "Follow Path",
    "Warp"
];


var g_PresetTxWarpTypes =
    [
        [
            {'Type': "textNoShape", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAADCUlEQVRoge3WPUjjbADA8SCoNdWoUCtauoi2YFWQYuvgooO46SIoqODoIC7qIIJuVkV0qIgdBId2UWslRRCtiIg6CA4dMnUrQpEKIfixmP87vbmTE3zf68HljvwhQ/J8kF/gKRX4SxJ+9wv8qiyI2bIgZsuCmC0LYrYsiNmyIGbLgpitn4YoioIg/Jrv4PV6kWW5oD0syB8HOT09pbe3l6qqKjweD6urq8A3yPLyMk6nk/r6enZ2dox1l5eXdHR0YLPZaGpqIhaLGWOJRAKPx4MoikxOTtLY2GhArq6u8Pv9VFRU0NPTQyaTKRySzWaRJImjoyOen585OTmhpKSE+/t7AzI6OsrT0xNnZ2eIosjt7S2Pj49IksT6+jqapnF+fo7T6SSXy5HJZCgtLSUWi6GqKouLiwiCgCzL5HI5KisriUajqKpKKBSira0NXdcLg3yW1+slkUigKApFRUWoqmqMjY+PMzU1xe7uLs3NzZ+uX1tbo6ury7h/f3+nrq4OWZbZ3t6mu7v7w3yXy8Xd3V3hkM3NTQKBAA6HA1EUEQSBw8NDFEWhpqbmw9yFhQUGBwdZWVmhr6/v0/1mZmYYGhr68KyzsxNZlpmfn0cQhB+u/f39wiAHBwc4HA4uLi54fX0FwO12E4/HURSF4uJiXl5ejPljY2NMT08TjUZpaWn5dM+NjQ2CwaBxr+s6brcbWZYJh8P09/d/+dL/GxIKhfD7/ei6jq7rhMNhBEEgFosZZ2RiYoJ8Ps/x8TF2u510Ok0+n6e6upqtrS00TeP6+hqXy0U6nSabzWK324lEIqiqytLSknFG/j2Te3t7aJpGMplEkiSy2WxhkIeHB1pbW5EkCVEUGRkZYWBggLm5ORRFoba2ltnZWcrLy/F4PMTjcWPtzc0NwWAQURRpaGggEokYY6lUCp/Ph81mY3h4mEAgYPxqpVIp2tvbKSsrw+fzkUwmv0R8Cfm+t7e3/zr1t2T91zJbFsRsWRCzZUHMlgUxWxbEbFkQs2VBzJYFMVsWxGxZELP110D+AaZ5qZil4yhUAAAAAElFTkSuQmCC"}
        ],
        [
            {'Type': "textPlain", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAHVklEQVRoge2ZMWhT3xfHz/CGNzzhDRmipvUNKWYIGCFDhiBBImToEG2GN0QI2CFDhg4BM2RQBItTwSAdCmaoUqFDBUGLBTNkqKCQIWqGCKlUiJChYsQgD/3+hnJu3333paZ/f/L//f+/XrjQvHfeufdz77nnnnNK+D9p9N+ewN/V/r0gjUYDRIRGo/G3T6bVav3Huv9RIL+j+xjkGOQP6T4GOQb5Q7qPQY5B/pBuX5DhcIhyuQzbtrG9vT12sG63i1wuh62trbEDNJtNFAoFNJvNsZO3bRudTmcsiOM4qFQqyOfz6Pf7k4E4joNoNAoiAhHBMAzpY/dgyWTSV4bbixcvcPbsWRARpqenFZjBYADTNEFEiMfjY0GKxaKYTyqVmgxkdXVVfMS9UqkoIEtLS5LMwsKCojybzUoyhUJBel8ul6X3N27cUEB6vR40TZPk/HZXAUmn0wqIaZoKSCqVGisDAO/fv8f09LQkc+bMGXz+/FnIhMNh6X0ikVBA7ty5o8ynVCodDrK3tyfok8mkNFCn05FAdF0HEUkyrVZL6FpbWxPP4/G4ItNut6X3mqaJsd0gbL6maQo9gUDgcJDt7W0QEWZnZwHsnxeeKB9oBnGbE5vQ8vKy0MVmw2a5sLAgybAJZ7NZAEC1WhV6GcRxHOi6Dk3T0Ov14DgOYrEYiAjdbnc8SL1eBxFhY2NDPFteXgYRoV6vKyC8uhsbG8qWz87OgojQ6/UA7Nu6G54nzmN1u10FhBOtXC4n9K6srICIsLq6Oh6ED9ve3p54xsoWFxclkHA4LGRGoxEMw0A6nRbPLMtCIpGQBgsGg7BtGwBg2zZM08RoNBLv2VsyCC/s2tqakOEFqVar40FKpZJif6PRSHgUN8jc3Jwkl8lkcO7cuQPFPp4snU4L95lMJpFMJqX37GYZ5Pbt24qXchwHU1NTuHr16niQQqGAWCwGb/MD8U5yfn4euq4DAPr9PogIKysrkkyhUIBlWQD2d2x+fl56X6vVJJBisQhN06RdA4B4PK7stuK11tfXJwKp1WqSDJslcOCR3GcNABYXF8VhN01T6OTGDoBBbNsW4O7m93yiWMsP5MmTJ5IMO4XBYDBRzOT1cm7d/N2lS5d8LeTatWs4ffr00UA6nY4vyObmpiR3//59EBF2dnawvr4OIsLr1699de7u7kqekFuz2ZRAotGob0jCrnxikI2NDQSDQV8Q72rzBdjr9YS3Ydfrbex5vCD8nHVbloVIJIJ6vS51vrd+CdJqtUS44I6D3CDjouJ2uy1258OHD78FEgqFlPDE3b99+zYepN1uK0GaH0i73Za+29zcFK6Sz8u4kPvt27cgIjx69Eh6/vHjRwmErWFc//Lly3gQ706MMy2v2bhN7lemxbe493Y+6o64m/SLb3Hu0WhUKD8KyN27d0FE+PTpky/IpKYVCAQOBfn69as/iDvHyGQyGA6H+0ITgLCnajQawrR2d3d/C+TkyZPI5/O+OrxNudmJ9hMgx3EOhHxA3rx5Iyl68OCBcLm/Mq2dnR0QEe7duyc9f/funQQyNTWFK1euHB0kk8nAMAy8evVKEtJ1XQHxZmnuyfPf3lCbQw1eeQ5EuXn/rWBZ1tjU9lCQWCyGeDyuCk1wj3B43ev1RFjvlanVakilUkogys2rO5FI4MKFC0cHsSxLJFXcBoPBRCCVSgVEhNFohOfPn4OI8PjxY0nm5s2bOHHiBL5//w5d15WUdWtrS9KdSqV8F7ZerysxoQSi67pSIGBX6QXxuk7btkX0y5mm9zCXSiWEQiEAwMzMDC5fviy954uUQQqFAgzDUECy2aySbgiQnz9/wjRNBeThw4cgIpTLZQnEaxbxeByRSATAwS56k59cLidk3PLcvFWU69evg0iuBfC3h4bxlmUpyQ7n3t4d4VybWyAQQCaTEb8Nw1Bk3EFgNpuFruuSd+QYikE4P3FH2sPhEJqmKUdAAjl//ry0Sj9+/MDFixdBdJBIMUggEBCT8Eu2YrEYDMMQnooPON8LvPrs/ThddoOw0ygWi0Lvs2fPQKSWhCQQrlVxjMS27lbmLj7wgeP7x31uvM/4sl1aWpImyRPi324QzjQNwxCXcz6fB5Gayyg5OxHBtm00m01RegkGg+LsMIhhGAiFQiI3IDqofbknbpomqtWqKI3yHcWT1DRN1Aq8IMBBvBWLxcT8vGMpIHwXuHs8HkcqlRL2zyBcOOPuTT2bzaYSRZ86dQqDwUDI8EJx599uEPdCuWNAbx4vgXA26O61Wg25XE6knAzC9wZ3v9qvd6LeuMldlGMz84K4TZm7t2ihgABy4TkSicBxHBQKBQSDQUlxq9USZVNN05RwBDjI44n2S6xPnz6V3vf7fUkHn0k3iOM4mJubE3pmZmbw8uXLX4N0Oh3EYjFYliXskP93AexXWhqNBkajEVZXV2EYBm7duqUo5knw4XRX9N2tXq/DNE3UajWMRiM0Gg2pQMjjh8NhhMNhpTIzFuR/tR2D/NPaX3VXb+SoHLzSAAAAAElFTkSuQmCC"},
            {'Type': "textStop", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGlklEQVRoge2aMYgaTRTHX7GBDdliCVsYELKBDWxhYSFBiAQLC4srUqSwkMTiCguLLSwsDBEsLnABiy0MSDDcESyEWFhYXCHB4goJFldYXGHAIoWFhYEttvh/xTHz7eyodya5+0K+e7CF63925zdv5r03o4S/xOi/7sDvsluQP81uQf402xlkOp2i2+1eR18AAN1uF9PpdOd2O4NYloVarbbzi65qtVoNlmXt3G5nENM0rx3ENM2d292CXJfdguza4BbkivbHgvT7feRyOXQ6Hfi+f6n+xkGWyyVs24Zt21gul2u1Hz9+hK7rICIQEd6+fStpPM9DMpmEbdtYLBY3D+I4Du/gOg95ngfDMLiGiKBpGr5//y7oDg4O+PelUulmQcrlsjDS0WhU0r1//16AYNfh4aGgi8fj/DvDMFCtVn8fiO/7KJfLME0TuVxOAkkmk1IHR6ORoAtqkskkVFUFESGbzXLN+fm59Jx0Oi2BTKdTZLNZOI6zcZ1JIKvVColEQnh4u90WQBRFga7rGAwGyGQy0kj7vs87Xq/XAQC9Xg9EBFVV4XkeAKDVaoGIkEgkMBgMEIlEoCiKAOJ5HqLRKO9LKpVaCyOBvH79WhqlV69eCSBEhGq1KnQw6LnJZAIigq7rWK1W/H4sFgMRYTKZAABKpRKICL1eDwDQaDRARAIIgw1ezWZzO8hisYCqqjBNE8PhEKPRCJqmIR6PSyCsM57nSZrj42MQEYrFovAyFiBYx1OpFDRN4x6az+cSSC6XAxHBdV2MRiPYto1IJMLbrAXpdrsgIsxmM36vWCxCVVUBRNd14SGpVEq4V6vVQETSvqXT6fBOAUAkEkEikRA00WhUALEsS9AMh0MQEU5OTjaDlMtlxGIxQcBcGwRJJpOCplAogIiwWCyEz+fn54JuNBqBiFAuly9eHpqSAITF7nkeiAiVSkXQ2LaNUqm0GaTVakk5od1uSyCFQkHQMA8wT2azWRCRtChnsxnS6TROT0/5NAp3qFAocJDZbAYiwmAwEDSO40gDfmkeWQcShnVdVwjBsVgMkUhk63NZQAg/K5gQx+MxiAhfvnyRNI8ePboayHw+R7PZ5KFvGwiDHQ6HAICHDx/i8ePHW0HYXN8GwjS9Xg+DwQDtdhv1eh3pdBqKomwHGQwGQrZlVxCk0WisBen3+1wTdv0mkIODA+lZYZBN10aQyWQCRVEEMfscBAnH8aOjIxARjo6OAAD379/HkydPtoJ8/vxZiGDMPnz4wCMgC+Phy7ZtaZ0KICxmRyIR5PN5DAaDtVErmOnZKAYrgHv37uHp06dbQcJtgveZR5gmkUjAcRx0u10eGcMmgMRiMdi2LSSbdYv9MhBWM/0qyKdPn4Swvs0EEFVVpXC4DiQ8tcKdunPnDlKp1C+DME0wQQMXpX84kQog8XgcjuNIja4atVin7t69KyXNnwE5OTkBEeH09FTQZLNZqfwRQPb395HJZARBpVLZGYTN623GItK6CBjOI51Oh3/PajtWr60FcV0XmqYJpUUqlZJAwl5jIMfHxwAAXdc3bo5YNbwpj7iuy9uy7B8cfdd1oSiKUFVLILPZDIqiIBaLYbFY8CLyshKl2WwKCdE0zY0gmqahXq/zuisM4jiO0FbTNBiGgel0ivF4DFVVpVkjgQD/7hG2JcRwRGK1Fivtnz17Bl3X8ePHD0H37ds3EBFevnzJ66iwd7PZrADCZkTwGo/Hl4OsViuh8d7enhA5TNOEYRhCm/39fRARP1hgReN8Phd0Z2dnvJpllW0+nxc0YW8eHh4KEOFKeCMIg2k0Gmi1Wnzkzs7O+IvCITGRSAh7FubV8J6h3+8LC/zBgwdC4vz69StUVRX2NqvVCpZlCeX/lUGCtlgspDoqWFp4ngdVVWHbNm/DRjEcker1uhCF4vG4sHBZFRFeX57nSd7dGYS9gL3cNE1YlgXLsuD7Pg8Iz58/53q2jw9ufwHwacrWUrFY5GHb933E43EYhnFz51r5fB5EFyca7BAuOPrL5ZLPabZHYQVpcNowDxiGwdfl3t7ezYBUq1U0m01omiYswnD2ZVsBXddRqVT4lAx6bjqdCs9QVRWu60pl0rWAABfnVixSEdHa3/xYSA5f7969E3TBvc+LFy+k05FrBQHEvUt4UQMXp4jhvc22s19FUfja+Rn7pd/Ze70eisXixmPM4EE3EeHNmzeSxvd9VCoVoZ76GbvWPwysViueHDOZjFQf/U77//7z4U+1vwbkH7Yb7XF6Z9O8AAAAAElFTkSuQmCC"},
            {'Type': "textTriangle", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGRklEQVRoge2ZMWjbXBDHb1CLKIJq8KDBgwYPHjx48ODBgwZRPGjwIIqhHlzqwUOGDBrczZAhBQ+mBDo0FNOm1AUPGlLwkIKHDBkyGKrBFFNMcai7afBgiob/N4T3qifJadwmbfjIgaCR753u9967e3evhP+J0L924KrkFuSmyS3ITZNbkJsmtyA3TW5BbprcggRBcJV+/LHN3wLpdrsYjUaX0vV9H0dHR5fSHY1G6Ha7v+PS5iCnp6cgokuD2LYNSZJwfHz8S93RaAQiwunp6aZubQ7CPnYZkPF4DCICESGTyVyp7ahcK0itVuMgRITDw8Mrsx2VawVJpVICiGVZV2Y7KtcGcnJyAiJCuVzGYrGArutQFOVKbCfJH4O4rgvLsjCZTAS9brcr6O3s7ICI4Hke1xmPx7AsC71e79+CTCYTKIqSGMzNZhOqqvK/J5MJiAgHBwf8XT6f59tuOBz+OxDDMIQYCDtQKpVQLpeFsaqqotVqCXbYUygU/g3IwcGB4AgRod1uc71UKoVmsymMLZVKqNVqAIBOpxMbv7+///dBKpUKJEnC0dERHMfhgQ2cn+Z3797Fs2fPhLGPHj2CaZoAfqbmVquF4XAISZJgmubfB5Flma+A7/tQFIXHyefPn0FEePfunTB2e3sbuVwOAFAsFqGqKnzfBwDs7u5CkqTrA5nP50IxF97b0+mUvy+XyyA6N8dSb9Sh2WyGk5MTAICu66hUKsJ3kmLtj0GCIEC9XgcRwTRNDsNA2MwyYdsrCAIcHh6CiC6sryRJguM4wrtCoRADmU6nqFQqaDQaWCwWm4GcnZ3hyZMnQiAypxiIbdvCGHZuzGYzvH//HkSET58+JX7U930QEfb29oT3zWYzBhJO0YVCAcvl8vIg1Wo1MaOEQcIZCgB6vR4Hef36dWzrhWU2m4GI+EEYnQwGwrZo+IlO4FoQ5qhhGJjP59w4c5z9PhgMhHGu6/KT++XLlyAinJ2dbQTCtiQDYSm6UqnA8zzYtg0iwng8/jWIYRjI5XJ8CZfLZSJINCDD79nqzOfzjUCithuNhuB4EATI5/NCkkgEmU6nIKJYR7cpyPPnz0FE+PbtWyII+04UhJUxzLZhGNA0TdDp9XqQJImn7USQwWAARVFivXMSSLRIDIO8ePECRISvX78mgqxbEfaegei6jkKhIOisVivIsox+v78exHEclEolQWF7ezsRZDabCXosRsJbK6rzOyDZbDaWdg3DQL1eXw8ym82wWq0AnMcGO0cuA8Kc9zyP/zvae7PDdRMQIoIkSbBtm9ur1+vIZrPrQZhMp1PkcjkQETRNSwSJOhlehfDqhKXT6SCfz/NzJJrCoyDpdDqWfovFIkzThK7rF4N4nsd7jFwux43/KthZml4ul/j48SOICG/fvhV0nj59ivv37+PHjx+JIJ7nxVakVCqh0Whwn8LPWpDVaoVMJsMrWZaCk0CGw6FgaGtrC5IkAfh5exK9o6rX63wmdV1HtVoVfo9OkmEYvM9frVZwXRfVapVDrQXp9/sgImxtbQmZKwkkur9N0+T79vv377h37x4eP34s6Dx48ADFYhHAeV0VzUisx2EgpmnCMAxEZbVaCZ1mDMSyLGiaxgMeABaLRSII6/SYaJom3JKk02mkUilhQhRF4f2IbdtCKwz8zJAMJCmo14kAks1mY7UMKxuiIOE0zWqiMNzDhw9BRHjz5g0A4NWrV4IOKz/CsRatflncRdPv/v5+7I5MAGFpLiyWZSWChDMX6/bCxtmtSSqVwu7uLk+lLLaOj49BRLz1Dd9KRotGVrAyyWQyF2etqMJ4POZdG+u/wx2iruu8kJNlWSixP3z4EMsyqqriy5cvAM73OQvaSqXC03wYJAgCyLKMdDrNt/tgMAARXXwgMqdqtRparRZkWYamaUKhxkBYf82epEKOZcB1OtEr1WKxGNturKXIZDKo1WocPpr+BZDhcBibxX6/D9u2eUcYzlphvaT2lO1xIsKdO3fguq7we7TfYDbDthaLBVRVFfSi10wxEADY29uDpmnIZrM8xbqui52dHQDnp2+73Ybv+3AcB7Isx1pWJkEQ8FnsdDqJOu12G4qiwHEc+L6PdrsdK3+GwyGKxSIURUG1Wk3sEm//6+2myf8G5D/6xG5E+ZdB9wAAAABJRU5ErkJggg=="},
            {'Type': "textTriangleInverted", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGJUlEQVRoge2aLWzbWhTHD7jAwJMMAgIMAqwpICAgoGAgwGCaAgICBgICqikgoCCTAgoqGQQMBGRaQEA1MFVaQEFBwTRZWkDAJhkEWFNAtAUERFonGUSTwf+B6tyXaztputZv7+3tSAaxfY/P757r83Edwm8i9KsNuC/5/4K4rgsiguu6927MXXT/AfkDkpLuPyD/CZDxeAzXdTGfz+/1YTfJLt1XV1cYjUaYTqeJY2MgR0dHICIQETRNw/Hx8d4Pu6ts0z2ZTGCaJogIQgiMRqPYWAXkw4cPEmLzePXq1S8DCcMQlmUp9miahtVqtR2k1+uBiOA4DjzPw+HhIYgIpmkmPqzdbiOfz+Py8vKnjX/37h2KxSI6nU4iCNtUq9Xgui6q1SqICC9evNgO0m63YRgGwjCU52q1GogIvu8rICcnJ3KGdF3Hcrm8NcRqtYJhGFIPG70JYlkWLMuSNgVBAF3XUSqVtoMAwMXFhfKbDT8/P1d+Z7NZxd3RGWIZDocolUpoNpvKBAHXE7epg3UyyNXVFYgI/X5fGVetVpHL5XaDRGW9XoOI0O12FRB+8MHBAYgIhUIhEWIXLK/9UqmkTAyDXFxcKKuBpdVqQQhxOxAAcilFQVzXRRiGKJfLICIlNH779k1C8vHw4UN8//4dADCdTkFEKJfLCMMQnufFQBzHQSaTUWxxXReFQgFEqunKryAI0G630Ww20e/34Xke5vN5IsjmGj07O4stgcvLy8QIOJlMAACnp6cgIpydnckxtm0rII1GQ3ra931UKhWpp1gsbgfZzCHRIwrSarXkuPV6DV3XcXh4KM/x+hdCoNVqoVgsKsur0+lA13Ws1+vYGAaxbRvFYhHNZhNCCKnPcRxlXAyEXbYPyHA4VBQVi0U8evRI/ubZGwwGAK7DLBFJ2Gq1GptV9iyD8JLlo1Qq4ePHj0gSBUQIAcuysFwuMR6P0e120Wg0EkGiCbFWqyn5JpPJwDAMZeYMw8Djx4+lkbVaTdER1Z3L5WQCdBxHRj3f9xXvx0BM00Sj0YjT7gFyfHwsX8AwDEFEqNfryj22bSOfz0sjO52Ocp1f+E0Qy7Ji9VWlUtkNYts2KpXKXiBR5fzyhmEoA0Q0/jcaDQmXy+VwenqqXOdxmyBRr4VhCF3XlSARA0kKd9tAopUxg8znc3lPtLgbj8dyeWiathdIuVxW7mHd0UpCAZlOp7HqcrFY3Bok+tImCRHtBRJNtPV6PRYkYiDAdQjOZDKyuhwMBokgnucp4zgq+b6PN2/egIjw6dOnRAguPW4C4ag1m80A/J3pe73ezSBBEMA0TZimKWP9Pi/75vlN7yQJGxwF8X1f0d1sNkFEsG0bg8EA2WxWKSB3ggDA+fn5jXlkFwh78evXr4kgs9ksESSqu9/vKzYIIba2DFtrrdFoBNM0Yds2CoWCDJX8sF1GcLF4W4/wBDLIYrGQGZ3ouk/aJnsVjZVKReYXNjhayfJyusvS6na7MW/3+30UCoXE9+LWIM+ePcOTJ08UkGjiZOM9z8Pr169BRPjy5ctOkOgMcxXxM230XiC+78s6arOx2hTuGOfzOd6+fQsiwufPnxP1rVYrEBHa7bZynmu91EAAxFpdIYRSwPFsBkEg7+GwyRIEgcxRQgg8ffpUXmMvpQ7CwkaWy2U0m0153rIsaJoGAHj//r3Se7C8fPkSDx48wI8fP5DL5RSvdrvdf8YjLKvVCpZlwXEc6RV+PzjjbgvRJycnskLm7nE4HMLzPOi6jk6ng2w2i8VikT4IACyXS5m8Ng8uCPlatLA7OjqS1S8nu2j3GO3PUwVh2Ww9o+FUCCE3LFjq9bosAkejkTL24ODgLqbcDWQ2m0HTNNn8bO7+5fN55R0CgFKpJL0WBIHc0xJCbN3T3Vfu/A1xMBhACBHrPSqViuwGWXRdVxJbr9eDpmk3Jrt9JLWPobxrycLd33g8Vu6LbiL8rKQGwvUWG847NEEQpPK81EA4cjUaDSyXSxiGEduvvU9J9Ts774Lwduiu6vWukirI8+fPlRD7Mxl7X0kVZDKZKJtraUrqf+GoVqsQQsTqrvuW1EGCIJDfVtKU/++fav6t8tuA/AWoTnSAo15MFQAAAABJRU5ErkJggg=="},
            {'Type': "textChevron", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGUklEQVRoge2ZMWgiTRiGv2K522ILiy2Es9jCwsLCwkKOLSyusNjCwsLCwiLFFRYW4ZIihWCRgxQeyBE4Cw9SyJHCIkUKD4QzIJyFcB4nnBwWFhYWwm2xB1u8fxG+YWd3TWL+5BL+Py8I2cnM7DzOzPe9MxL+I6KHHsBd6QnksekJ5LHpCeSx6VYg4/EY8/n8jocCzOdzjMfjW7XdGmQ4HIKI0O/3b/XCq9Tv90FEGAwGW7fdGoRfdp8gt+n73kFc18VsNruXvr26VxDXdWGaJhRFQbPZvNO+/bpXkEajASICEUFRlGtn5tGCxONxAUJEKBQKd9a3X/8aZDQaodVqwXVdqd5gMAARoVQqYblcIh6PQ1VVOI4j6riui06nI6LUg4GMx2NomiYG7NXBwQGICJPJBABwenoaGGShUBCzdXp6+nAgyWRSWjo8aACwLAvpdFo8O44DVVVxeHgIAJhOp1LbWCz2MCDejcyfer0u6um6jkqlIrXNZDJi5sLa8yz+VZBUKoVoNIrFYoFarQYiQi6XAwCsVis8e/YM7969k9qWy2W8evUKAFAsFkFEqNVqWCwWiEajIjjcKchyuUQul0M8HpcsA4MQEVqtFoDLTavrOqLRKABgNpuBiNDr9aQ+j4+PUSwWAQCmaULXdREkOp2O6NcPcnR0hEKhgOl0uh3IdDpFNBoVHUejURFtGERVVdi2LdpYlgWiy+56vd61nskwDFiWJZ4dxxGBwwvSbrelcWyCCYA4jiNB8IddKYNks1mp3f7+PogIy+USnz59AhHh27dvG0F0XcfBwYFUls/nAyD+XBSPx28GcnJyAiKCpmkoFAriW+p0OhKIfyPzNzefz/Hx40cQEX79+rURhIjQbrelst3dXQlkPB4LANM0xVjOz8+vB8lkMlAUBWdnZxJYrVaTQPzeiUEmk4n4e7FYhEKsVqtQEG7HIM1mU8pRg8EAqqqGOgQJZD6fizDIWq/XoSD+jexNeK1WS8xOmPg9fhB/HqlUKoG9Vi6XoSiK5BACILy2v3z5Isr+/PkDVVUDIP7I4i1///49iAg/fvzYCsR/aLMsC5qmSfaH3zMajTaD1Ot1aJoWeHHYjAyHw1CQ2WyGDx8+gIjw9evXrUC4nEFevnyJZDIp1fn9+zdevHiBRqOxGaRSqSCVSkkVbNsOBfEvG84D8/k8sNZZvV5PWPmbgBiGEYiOAJBOpwPeTgLpdrvodrvi2XVd5HK5G4F4NzjnEU6YrFqtJpJm2GErDCQWiwWiVLlcDszUxsxu27ZIcmEg/kMSb3Dg0tqHhehSqYRIJCIGyX1uAonFYlL45QDz+vVrGIZxPYht2zBNU5zswkD8y2Z/f1/sL8dxoCgKDMOQoks8HhffZCKRCICGzYg/MZumCcuyrgfhczZDcFi9DiSfz8M0TfHMFn9nZwfL5VL0w8Yym80G1r+/b8MwYBgGIpFIAIhnfyPI4eGhqMiRIQyEMz0rkUigWq2K5729vdCXv337FsBlYNF1Xerj7OxMAslmsygWi1iv16jVagGgjSBe4+ZNimEgR0dH4v+8JE5OTkTZ58+fA55N0zQRkjnKeW8W6/V6AMQ7a36gjSAcbdhqXwWSz+fF/9kw+p1po9EQe8y/+Rl+d3dXlHFwYZBSqRQaftfrtXSIC4C8efMGz58/x8XFhSj7+fMniAh7e3sSiKIoGI/H4ty+yZXato3hcIhOpxO4oEilUtA0DZPJBJPJREAzSLVaRSwWC+3XLwkkm80GEiLPkn9GiC7PJGFL8aby7kfvh0HYIXz//n07kGQyGXCWbNz8IN5zgqZpWC6XW4Os12voui764bzht/HsxFnNZjOQkCUQXddRLpelCtw5l3ttPC8xvxPeRt1uVywp/2Z3XReqqgbsSCqVujqPcMJhsRuNRCLiWOq1KL1e71Y/Afg1Go1wfn4eSIjA5flIVVWsVisAwGKxgKIogS0ggXDycV0Xtm0jnU4jnU4jm80ikUgAuLxYuM0tx03V7/cl+8MHO9M0MZvNsLOzEx5ZvQ+ZTAZEhEwmI5ZUu92WrnH+tjbdIfgNpwRSrValyslkEq7r3moj36WOj4+lcXmXGksC8YbWq65eHkLem0l/MgRCvFar1UK5XH5UEKzpdBo44rL+3z9PP0Y9gTw2/QP9cVZ6Icas7AAAAABJRU5ErkJggg=="},
            {'Type': "textChevronInverted", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGFUlEQVRoge2aLWzbTBjHH2kGAQaWFmAQYE0BAwXWFGBQYBAQEGDgSQaVFhAQEBAQTQEFkQYCCgI6qWAfAZUaaQUD0VRgEFBVgdZUEJBJkRZpBplkEBBg8H9BdVef7TRLmr6btj7Sgbj38fx8z5fvSvhLhH63AruSR5A/TR5B/jT5d0HCMHwIPe4tG4MMh0OYponZbLZzZWazGUzTxHA43HjsViBEtNViDzn3I8gjyAPNnQDxfR+2bcOyLIxGo50utk7umns8HqNcLqPRaKRGzgTIy5cvQUQgIjx79gzv37//5cXuK6vmZpGS6fX69evEWAFkPB7zzqxJkoTpdPpbQcrlsqBTJpPBYrFYDXJycgIiwvPnz1Gr1SDLMogIjUbjt4FMJhP+Qk3T5Dqdnp6uBmm1WiAi7hue5yGTySCTyXC7/L9Bms0miAj9fh/A7cuu1+urQSqVChRFETo0Gg0QEcbjsbCY67ool8soFouYTCZbK+/7PizLgm3bcF03AZLL5aDrOv8dhiFkWYZhGKtBfN9HpVIROrDJP3/+LIBYlsVtVtf1rWswwzD4PAcHBwJIEAQgInS7XWGMaZrQNG01SJqwyY6OjgSQeBsMBhtDnJ6eps7FQL58+ZJqxpVKBU+fPt0MBACICO12OwFSKpXgOA6ICOVyeWOQ/f19EBEcxxF2mCne7XYF/2TC/GYnIIqiYD6fA7gJj5IkJSriIAjQbDah6zry+bywa7PZDEQE0zQRhiGCIICqqgJItVpNmJDrutB1fT1IEATo9Xro9Xq4uLjA+fl5KohlWXzMYDBIhMSfP38m4n8+n8f3798BAP1+P2GScR+xbZs79XA45DvI2kqQ5XIJTdNS7TYO8ubNGz4uDEMoioJms8mfrbJ/FjRarRay2axgNt1uVwAxTRP5fD4BwCxiJUiv10tdPA0k7tyGYQh+wnxHURS0223uAyz+l8vlRAi9uLgQQKIRLQrQbrcRBMFqkFKpJAzK5XL8bcRB4pGkVqtBVVX+O27vQRAgk8mgVCpxJWu1mjDH5eWlMCZqHasAUkGYE7mui+VyedspBeTy8lKYiJkFACwWi9RIViwWkc/nuZLx/DCdTgWQXC63FiAVRFVV7O/vJzulgEQLSeDWLH3fx/X1dcKPAKBer+P8/BwAkM1m0ev17gTRNC2RoIGb0onltVQQIkK1Wr0XyHQ65VEs7kfRipWI1oLkcrnU/PTq1Su8ePFiNYimaXAcZysQ5qjj8RhnZ2cgIlxdXSXmAm6rhV/ZEdM0E+P39vYSgAJIoVBAoVBInXyds0eff/jwAUSEr1+/poKwOdeBGIaRSIjz+TzxaZEAcRwHsiwLsZ3lg3Ug0cr17du3ICJ8+/ZtI5DRaJRIiPHdZ/qwsj4V5Pj4OLFAsVhMBWGJjQnzkeFwKPjLJiDxMr7T6SSqX13XIUnS3XmEferKsozj42NenKWBnJycpIKMRiN8/PgRRMTLkVUgnU5HeM5eJANha8myjHfv3qFarYKI0iNr/EG0CmVNlmVuk2zyaDkCAEdHR3wXPn36xB0/TXzfBxHh8PBQeF6v1wWQHz9+8MTK2pMnT3B2drYe5Pr6Gtlslg+sVqswTZPHcwbCEhsTVvAtFgvex/M8oY/nefwFSJIkFJ7AbUkS9b944RkfsxIEuDGxg4MDHB4eIgxDOI7Dw2D0eySq6N7eHi/kVgWETqcDWZYB3ITWXC7H/8bK+vi46XTKd8VxHKHiWAsSl1arxcMgU1JVVZ5z2DMG63keiIhncSbNZpPvJKvrXNflayiKkvoClsslfN+/U8dfPjJlCzKlWXVrWRYv7pjNh2GITCbDAwQT27Y5LItImqbxMMv8c5sTmo3PftkdBsvk0RY9Yi0UCrBtWxiraRqveNmuRVu/39/67uVeV29sV6JmxaRWq0FRFG7T7KAtmsiix6DbfPNH5V4gQRDAsizoup4ItewgjSnOoKO2PplMYBgGisXiWh9YJw92GTqfzyFJElRV5bYfr+N2KQ96q8ucmLV4WbNLeVAQz/MgSVKqD+1aHvyefTAYoFKpJK4Bdi3/7j8M/Kny14D8BzlJUi1rfoTAAAAAAElFTkSuQmCC"},
            {'Type': "textRingInside", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGcklEQVRoge2aL4ziThTH5y5NDlHRXFZUcEkFAoHoJYjmgkCsQCBOICoQFRUVKxArEBVNyAWBQCAqEBWICnIhOQTiBOIEAoFAIBAVKyoQiArEiO9PbDphKHSB2z+/XPabTLK0DDOfmTfvvb4uwT8i8tYTeC69g6RpNptBURTc3NyAEALHcV5iGE4vAjKdTkEIYe0d5AK9g6TpnwaZz+e4u7tDLpeDoihQFAWFQgG2bWO9Xv/1mK8CIooi+1uSJJTLZZTLZebVCCEolUoYj8dXj3k2SBRFGAwGME0ThmHANE2EYXgWCCEEsixjNBpht9ux71FKMR6PcXt7C0IIBEFAr9d7GZDdbodOpwNJkhKTy+fzZ4HIsozVapU6TrfbhSAIIITg/v7+eUGCIEA+n2fmoapqAubYrhyC2LZ91mTa7TbrMxgMngdkuVxClmUoigLP89h1y7K4SQZB8CTIubZPKWULJ8syttvt34GEYQhZllGr1TibBh5N4FKQyWRy9oRs22b9ms3m9SCUUmiahkajkbjebDaZHV8C0u12z57QaDRi/QqFwvUgrutC0zRQStm19XoNVVWRyWRQLBYvBikUCtzvpWkymXB9oyji7odhePS3EiDFYhHL5ZJ9Hg6HEEURhUIBy+USzWbzYhBCCHRdT0zqmFqtFtdvPp+ze67rghACTdMS54cDWa1WzKVSStFoNEAIgWVZ7KyUy2VuoH3oUyCx61YUBaPR6CRQ7GDifoIgcN/99u3bSXPlQHq9HnOVpmlCFEX4vs/ub7dbZDIZbpKj0ehJkMlkglarxfoKggBN02BZFhzHgW3b+P79O5cBxCu/r/37lUrlNEi9XsdisUCr1YIkSYkgVqvVEiZTKpUSNhsEATqdDjzPg+d5LNYEQYB2u41KpZKY9GFTVZUzKwDIZrMghODm5gamaZ4GMU0T8/kcoijiz58/3BcbjQYEQYDv+8jlchBFEbquw3Xdi/x9LEopZrMZfN9Hu92GZVm4v79Hp9OB7/tHD3SlUgEhBNVqFQ8PD6dBfN+Hruuc/VFKYVkWRFHE79+/ATyu7GF8eQ3d3d2BEALTNBMZc+Kwq6rKPkdRhFqtBlmWEzv0FhqPxyCEoF6vJ9IeDsR1XZZ9brdblEolZLPZJxO+1xKlFNlsFsViEdVqlbvHgcQrH4Yh8vk88vn8yVT9reQ4Dmq1Gvr9PnedAyGE4PPnz/jy5QtKpdJZAey1tV6vEYZh+mGPXd/Hjx/x8+fPV53guep2u2i32xgOh9z1BIggCPj06RMEQUhs31trt9tBlmXk8/lEQYMD+fDhA379+oUwDKHrOgghMAzj4jix2WxgGAZrx6L/Nep0OiCEYDqdolarcfc4kK9fv3KDuq4LQRCQzWYvKgwEQfDs5aAoiiBJEssFUyP7jx8/oCgK56nm8zkURWHJ4znp+EuADAYDFItFdshbrdZpENu24TgOVFXlPFYcU+Jk7Slvdi3Iw8PD0ceCGGQ/m0g97PV6HWEYQtM0aJrG7UwURQxGVdXU+PIUSBAE8DwPuq5D0zS243HLZDKo1+vYbDapY5wEsW0b/X6fBcTDsxFFEXK5HCsFndqZYyCUUvR6PVZcOKcdpur7St0R3/dZ6A/DkGWb8U4Bj2dm/6nvHJByucwWQJIkWJaF4XDIrep6vYbjOAmY/cAXe9PZbIZ6vX4aJAxDSJLEVppSCsdxIAgCMpkMGo0GwjDk6lvHKoOHIHF8ajabT7ry+Kk0btPpFMDjy6N4YQkh6TsS/9BhZrlcLtmPCILAVR2LxeJZIJ1OJxUgVpzhxm02m3H1rlNjJkA2mw0kSUoQA49mZRgG97h7+Fx9DCTN1g+1Wq24vrFJx4XBUql0dFePFuhc14UoilgsFkcH2y+ixauWBnLo89M0HA65s3WuTpZMbduGLMvwPI8LgtvtNuEuDzPRQ5BLsoL9M7Jf+LgaBAAMwwAhBLlcDoZhoNlscuWa2A0f6hDk3ErjarViZnvJbjwJQimF53msenHYJEk6utqHIKfc9L622y2rYsqyfDLCXwUSa7fbYTQaQdd1FAoFKIqCarV6crBjXittV+L38jHENY/WL/Lq7RhIbC79fh/T6RTT6RSu67K0J/Zu175PfBUQx3ESpdZ99317e8tKTdfqRUA2mw10XWcvPWM3vlgsWPXR8zz4vp+aGF6i93+q+b/pnwH5D1bN/dl0+RwMAAAAAElFTkSuQmCC"},
            {'Type': "textRingOutside", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGbklEQVRoge2aL8zaThjHTzRLRUUFAsEWkjUZgmQVJEO8ooJkCESXIF6B6BJEBQKBQCCavIIsr0AgEIgKxCsQZOrNhqhAIEiGQCAQFYh3CQJRUVHx/YmlF65XoLx/tl+WPcklUHq9+9w99/wrBH+JkD89geeSfyCnZLvdIpvNIpVKgRACy7JeYhhGXgTEdV0QQmj7B3KB/AM5JX81yGq1gmma1AAQQqAoCur1OqbTKYIgeNKYvwUknU7Tz7IsQ9M0aJqGTCZDr+fzecxms0ePeRHIbrfDbDaD4zh4eHhIDBLC2LYN3/eZe6fTKarVKr2v1Wq9DEgQBBgOh7i6umImJooiBoNBIhBJkjCfz0+OY9s2JEkCIQTNZvN5QVarFRRF4Vb3sMWtYBSk0Wgkmoxt27TP7e3t84DsdjsoigJFUWDbNlzXhe/7uL295VTmHMhwOEw8oVKpRHd8vV4/DSQIAmiahuvr61hrElWz6IBRkMlkknhCg8GA9qvX608DMU0T5XKZg5hMJtA0jVOvxWJxEqTT6SSe0Hw+p/1SqRSdw2q1gmEYsG07Gchms0Emk4HnefTabDaDqqr04ObzeeYgR4GjIKqqMs87Jcvlkum72WwAALVajV7r9/vnQZrNJkajEQDA8zw0Gg16Fvr9PjzPg2EY9KHlcpl7aJz5rVQqnOmNk36/z/RzHAfArx3RdR2EELx+/Ro/fvw4DuJ5HkqlEoBfO5PL5SCKIrrdLp2E7/vUwYmiyKlVHIgsyyCEIJPJwLbto7uzXq+Ry+WOqu3DwwNyuRxUVeXCHgZkMBig0+nAdV2k02nkcjnuILdarbPWKAoynU7R7XYhiiIIIRAEAcViEaZpwrIsdDod6LpOgQ8XYL/fM88OFzTqaxgQ0zQxGo2gqiqq1Sq3cuPxmA5yymnt93t0u13Ytg3btmkU4Louut0uyuUydX7HmiRJ1Nr5vs+dw/DsxILoug5d11GpVLiO/X4fgiCAEIJut3sUIqkEQYDFYoH7+3vYto2bmxs0m000Gg30ej0uBDIMg9md6E4xIIVCAYqiMDcFQUAPvCRJGI/HT4Z4jJimCUVRqKpHVZ4BSafTmE6n9LvneahUKtSELpfL3zDleJnNZiCEUGMUWtZQGJAPHz7Qz67rQlVVCIKAVquVyHS+tFQqFYiiCM/zuFiMAXn79i2+ffuGfr8PWZahKMrZqPV3ymq1giAIuLu7Q7vdZn5jQD5+/Mh441M5x58SwzCQz+c5786AfP78GYQQvHr1Ct+/f/+tE0wqy+US0+mU0xQG5NOnT3jz5g3evXsHQRBiY5o/Lff39xiPx1itVsx1BsQwDARBwMRT19fX2O12Fw22Xq9hGAZtl4Tx56RSqUBRlNMhiqIojDcP009Zli9KjhzHeZFy0Ha7pQFotVplfmNA4pKZ9XpNQ3hN0+C67tkBXwokTLrq9TqXl3AOMS6O8n2f5gOyLJ9VlceA+L6P7XZ78p6w2lKr1bg4kFOtcrlMz0bUCTabzURZ3zmQ9XqNwWAAXddRKBSYol2Y+1iWxcV7YYhfKBS4KIMBKZVKcF0Xo9EIkiTRWlT4wCAIUCwW6YB3d3eJQYIgQK/XQzabPRn1HrZarcY89zBi1nX9OMjNzQ2d3Hw+p6qmqiomkwlXRclkMolANE2jZSVZlmGaJiaTCaNKYUk1Gsof7sphxfLLly/HQTabDbMK+/0elmXRhCeVSqFQKDCDxZnmKEiYTLXbbS78jsph1ZEQwqhQWL2RJImLOricvVgscvq33+/R6/W4MhAhJNaKxYEkNd+HRTpCCAO+WCxQKpVijQ0HMp/Pkc/njzrBTqdzMYhhGIkgon2z2WzifrF1rWaziaurq1hzaFnWxSDHalFxclhFiTq9i0E8z4OqqkilUkwFfb/fMzWtpCBhSSeJhP5KEITYCs1FIMAvBxVaEUmSkM1mYwsGz7kji8WC1gUurciffa2wXC5Rr9epCQ1LOmGLVjPiQKL+IE52ux0NhaKVzmcBicrPnz/x/v17OsmvX79y98RZrVNhzWKxoG+visXioxK6R716a7fbdIJxKhAHEjrGyWQCx3HgOA6GwyFKpRJVp0aj8eh3iY9+h+i6LobDIarVKreCUZB2u8050rCJooharfak94dPAjklYWKl6zo0TaMO1nEcWJZF22AwOOvpk8q/P9X83+SvAfkPv2b7OakXefQAAAAASUVORK5CYII="},
            {'Type': "textArchUpPour", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAECklEQVRoge2YIXDqShRAr4iIiEAgIiIqIiIqEIgnIhCICmRFRUUEAlGBQCAimEFEIBAIBKICUYFAVCAQERUIBKICEYFAICIqEBUR54sOO+W39ENL52fe5DjYze6eZe+9G4S/BPm/F3AuMpG0kYmcwmq1+vU5fk1kOp3iui4igoig6zrlcpmnp6dfme9XRKbTKZqmUS6XeX5+BuDp6YlisYiu6+q7c/JtkSRJGI/HtFot2u323vHxPA9d19lsNnvPzOdzCoUCnU4HgDiOGQwG1Go1Hh8fSZLku8s5TmQwGOwtarlcYts2FxcXuK6LpmkYhqGOjed55HK5L8dcrVYYhoGmabiui+M45PN5ZrOZ6rPZbAiC4Dwig8EAEaFYLLLdbonjGNM06XQ6agdnsxm6rlMoFACo1+tomsZ2uz04bqlUQtO0vZjpdDqYpsl6vSaOYy4vLxERWq3Wz0Wm0ymGYSAiuK5LEASUy+UP/XzfR0RYr9fMZjNEhOFwuNen0+nQ6/XYbreICI1G48M419fX+L6vEkU+n2cymfxcBOD5+RnHcVQGajabn/YREcIwBKBarWIYBpPJhCiK6Ha7aJrGaDRisVggIszn84MbIiI4jkMURccs8fhg32w2XF1dqWP278CMoggRYbFYAG/JIAgCLMtCRLAsi/F4DMB6vUZEPiwySRIKhQIiQrlcJo7jY5d3WtZKkoRqtYqIcHNzw8vLi2prNBqYpnl05ikUCtRqtU/HrtVqJ2ewb6Xf3TGxLAvf96nVaui6rnb8GBaLBblcjkqlQr1e5/LyEk3T6Pf731nSf4vc399TKpVotVp7WWgymZDL5XAchyAIjj7L74miiCAIcBxHxRPAdrtlOBzieR6+73+oRyeLPDw8qMDbnfOHhwfVvlwuubm54fX19WSJHbsjtVwuldz7xCIimKap2k8WSZIE27YJgoDVaoXruuTzeRXs0+n0R5X4qzk1TePi4oJ2u00cx1QqFVWjThYZj8c4jqM+27ZNGIa0221ERKXSczIajdS44/EY27aBt6uMZVkf6tJ7Dop0u108zwNQBWyXDovF4t5V4lzc3d1RKpWAt18nn8+rdO77PvV6/eCzB0UajYa6GsxmM0zTVG2e5325O98lCAIlAnB7e6sumM1mU23sZxwU8X0fx3HYbDaEYahEdkVrV8HPSRRFGIahArvb7XJ9fc1yuVQxc4iDIrtrxC7YRQTP87i6usK27bMH+o56vY6u6/T7fUajEblcDl3XMQzjyzfNL9NvGIYqFnq9HoZh8OfPn197y9sxGAxoNpuEYYiu67iu++m97D3Znw9pIxNJG5lI2shE0kYmkjYykbSRiaSNTCRtZCJpIxNJG5lI2shE0sZfI/IPnK/mbji+lKgAAAAASUVORK5CYII="},
            {'Type': "textArchDownPour", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAE80lEQVRoge2YL2zyThjHH3HJi6ioQJxAICoqKioqumRiAoFAICpegahAIBCIiQnEEsTEBAKBQExMTEwgEIiJiQkEogKBQFQgKhAVFc1y4vsK0gsH7G9YfvwWvgnm+nD3fO6eP9cSfonov3bgUDqBHJtOIMemE8ix6QRybDqBHJtOIMemE8ix6QRybDqBHJtOIMemE8ix6feCPD8/w3VdFItFVCoVjEYj+Ww8HqPVailjh1YYhuh2uyiXy3AcB4VCAXd3dwCAer3+5toKSBiGYIyBiJTf/f09AGA0GqFQKICIUC6XkabpwQDSNEW9XgdjDJxzXFxcwHVdEBFGoxGSJJH+dLvd90Fubm5ARLi4uEAQBBgOh9A0DbquI45jaff4+AgiQrvdPhhIp9PZcTLzZzqdAgB6vR4YY2CMKf7sgFxfX4OI8Pz8LMf6/f7eXdB1HbZt7zgUBAGEEG86LIRAEAQ747VaDYVCQRnzPA+5XE45+VarBSLC4+Pj2yDZDry8vCgLm6apnEocx/LkNjUYDFCr1T4E+fv3L/r9vjJ+d3cHxhgWi4W003Ud5XJZsRuPx0q47wVZLpdgjKHZbCpGo9EIRATP8/D09ATHcaBpGiaTiVy03W7D87x3ITZhPM/D1dWVtBdCwHVdmKaJ5XIpw7fX6yn/7Xa7O1GzAwKsj5gxppxKmqaoVqsy2RzHkXGbJAnK5fKnIbZhKpUKkiQBsN5Izjl0XYdpmsjlckouJEkCwzBQKBR2Cs0OSJIk8DxPOlypVKBpGogIuq6j1+tJh8MwhG3bKJVKCILgS1VMCIH5fA7XdWFZlgyp+XwOy7JARMjn82i32xiPx+j3+ygWiyAiWY7fBcnk+75SghuNBlarlXw+nU7BOQcRyZJtmuanYbLSmv2Xcy6jIEkSWYq3W0G9Xt978ntBJpMJcrkciAi2bctcyJQlJucc3W4X8/kcvV4PRIThcKjYZlUqCx8AGA6HICJcXV1hsVhgMBjAMAwwxpQkjqIInU4Hvu/D9/2duT8EieMY+Xwenuft7HC73ZYNcdM5YF2SO52OsiFZOBSLRcznc7kRRITlciltkyRBqVSSgF/JtzdBgHWZ23Q0SRJUKhVZvfYtlMvlZJWJogiccziOg5ubGxiGAc454jiWINsSQihrbG/Ut0A2tVwuYdu2zIN9C8xmM6VReZ4HwzCk7WKxAGMM19fXmEwmIKK9jTGrTEQEy7IQRdFhQF5eXpDP52WyDQaDvXZZyEVRJPvRtu3DwwOiKEKapmCM4fLycu9cg8FArsc538nRb4FMp1NomiarzHYjAta7yDmHZVkA1ledP3/+yJzYJ8dxoOu6UgkzBUEgC42maUpP+zZIBpPdPvfdPJvNplLfTdOEaZrvzpntuu/7bz6L41g23o/0pRerUqkExhgeHh4ghMBqtUKj0QARwTAMCCHw+voKXddxdnb24Xzn5+cgIrRaLQghIISQN+7sdD+rL4FEUSTfRzZ/m81stVrtvVBmqlarYIwBWBeI7NawPV8Yhj8Hkjl6e3sL27Zxfn6OWq2m9IM0TaFpGjRN2+lBQghZODKFYQjf92EYBizLQqvV+jLEt0A+o1qtpoRMpuzlqVqtHnzNHwGZzWayFxiGAc/z5EWQc47ZbHbwNX/sK0ocx2g2m3BdVyZvo9H4dIP7qn7v56D/q34NyD9R1OIfzRsxNwAAAABJRU5ErkJggg=="},
            {'Type': "textCirclePour", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAF10lEQVRoge2aL5CqXhTHbyAQCAQCwUAgGAwGg4FAIBgIBIPBQDAQDAbCCxt2hmAwGAwvEAwbDAYDYYOBQNhAMGwgEAyGDQaDwUD4vuBwfzIqqCvzfu/N+87szO5c7p8P99xzzj0swV8i8rsX8Cz9A8mTaZqQZRmSJIHneZimWcY0GZUComkaCCH0x7KsMqbJqBQQ27YzIK+vr2VMk1EpIG9vbxmQwWCA5XIJ13UxHA7heR7W6/VT5ywF5PPzMwNCCAHHcdA0DaZpot1uQ5Zl8DwPx3FwOBy+PWcpIEmSgGVZCtFsNi/uwGq1gqIokGUZ7+/v35rzYZA4juH7Pna73cX2RqNBQebzee5Yg8GAmuCjuhskjmPouk4XKcvyRZher0ef+fnzZ+G4pmmCEALHce5dEoA7QTzPA8dxZ/bf7/fPnp1MJrRdUZTCscMwBCEELMsijuN7lgXgDpD5fA6GYdDtdjGfz1Gv1+lCL02+XC5pO8Mw6HQ62O/3V8d/f3+nz08mk3JAVqsVOI7DdDoFAGy3W4iiCFEU6eS6rmf6bDYb8DwPSZIQBAFUVQXHcbAsC57nZcxxs9lkztQjZ6UQ5HA4oFKpZIJaq9XCjx8/sFgsMiZm23buWw/DEJZlQRAEer7q9fqZuS4Wi+eDDIfDjI1Pp1M0m00kSYKvry8QQiAIAgRBwGw2u2nSJEmwXC4xGAxQqVQyJmrb9t0QhSC73Q48z8P3fQBHkxIEAZ+fnwCOEVwURSRJkrsTRVqv1wjDEF9fXw+PkQviui6azSb9u9PpZExM13WMRqOHJ89TFEWYTqf0pRUpF0TXdQyHQwDHt8ayLLbbLYCjA+B5/mpA/I5SD5ma3MvLS2GfXBCWZfH29gYAeH19zXgmwzBKyWrjOM5A3OqSr4Ls93sQQtDr9QAcPVW68CAIwLJsKbvhOA5dvCAIkCQJhBDwPJ97hq6CpB6pVqsBOOZOlmUhjmPUajUK+Gyl6c94PEaSJACOToVhGIzH46v9ck2L4zh0u10AoG8m3fbVavXE5f+narV6MaUxTfMs6J4qF2QymdC3cJoElnkHZxjm4tnzfR8cx13tVxgQUy8VRRFkWUar1fpWzCjStbR/u92CEELN7axf0cCLxQKKosD3fcxms4cy03tECLkaOwghV6/IuSCnudR8PofruqhUKnSXylDuYgnBZrO53JY36GlZx3EcTKdTEEJgGMa3F3xJ6/X6KkgcxxBF8WrfXJDUUzUaDei6jt1uB8MwQAihKf0zlYIEQXDWNplM0Ol0rvbNBVFVFYZhIIoi8DxPD5plWRBF8emHPo7jizfK/X4PWZbhuu7VvoUgaZ5TrVbpPeFwOKBarT49RUmDsCzLtEQUhiEajQZEUcwtG+WCWJZFY8Z4PIaqqrTt4+MDLMs+PTCKopgpDaVX6ryoDhSAfHx8oF6vAzjugiiK8DyPthuGgXq9ftW3P6IwDOnvQRCAEIJ2u104R2EcqdVq9PDNZjNUKhWaLK5WKxBCaKr/qJIkwXq9Pjtzo9Ho5vtOIchoNMq42263C03T6BtSFKUwM72kIAjQ7/dRr9dp/sYwDCzLemiHb0pRTg/24XCAoih0u9PC2i0HP4oi2LZN7+mSJF0sPpRWDoqiCIIgUBPabrc0tlSrVeppTrXf7yFJEiRJgu/76HQ6NJjO5/PMDq7XazrOo0npzQW6KIogiiJarRYWiwWWyyV4nqeTVyqVzPNp5TA1GU3Tcj2c7/v0+UfO3F0l0yiKoKrq2TWUEHIWdU9Lpq1Wq9Du02BYesn0VL7vZ0qmqqqeeZx+v39zNR4AXl5ebi40XFJpX3VPdy4vtQCOwTYtlT4ak0oDScui6b3/UvodRRE0TQPP84WwRSoFJL3Nnf7wPI92uw3btmGaJmq1GhiGQa/X+1aFMVUpIJ7nnX2e9jwPjuOg3+/DdV2EYfiUb4epSgEZjUYZkD/2Hwba7fbfAWKaZuYj0B8L8jv0D+T/pl82gOGZr7UaJQAAAABJRU5ErkJggg=="},
            {'Type': "textButtonPour", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAIH0lEQVRoge1aLXTqShcdMSIiAoEYgUBERCAiIhARCAQiIgKBqIhAIBAIBCKCtRARCERERUREBaIiAoFAREQgEAhERAQiIgJRgUBE7CdYma+5/BRub9f31lt3q7YDM7NnztnnZ0rwHwH5f2/gT+EvkX8b/hJ5Bvv9/sfX+DEiq9UKmqaBEAJCCARBQLPZRBiGP7LejxBZrVaglKLZbGK32wEAwjCEqqoQBIH/7U/it4lkWQbf9zEejzGZTArmY5omBEFAmqaF72w2GyiKgul0CgA4HA5wXRe9Xg+LxQJZlv3udh4j4rpuYVNRFEGSJFSrVWiaBkopRFHkZmOaJkql0t059/s9RFEEpRSapkGWZZTLZazXa/6ZNE1h2/afIeK6LgghUFUVx+MRh8MBjDFMp1N+guv1GoIgQFEUAMBgMAClFMfj8ea8jUYDlNKCz0ynUzDGkCQJDocDarUaCCEYj8ffJ7JarSCKIggh0DQNtm2j2WxefM6yLBBCkCQJ1us1CCF4e3srfGY6ncJxHByPRxBCMBwOL+Zpt9uwLIsLRblcxnK5/D4RANjtdpBlmSvQaDS6+hlCCIIgAAB0u12Ioojlcok4jjGbzUApxfv7O7bbLQgh2Gw2Nw+EEAJZlhHH8SNbfNzZ0zRFq9XiZvarY8ZxDEIIttstgLMY2LaNSqUCQggqlQp83wcAJEkCQsjFJrMsg6IoIISg2WzicDg8ur3nVCvLMnS7XRBC0Ol08PHxwceGwyEYYw8rj6Io6PV6V+fu9XpPK9hvyW9uJpVKBZZlodfrQRAEfuKPYLvdolQqQdd1DAYD1Go1UErx+vr6O1v6mojneWg0GhiPxwUVWi6XKJVKkGUZtm0/bMufEccxbNuGLMvcnwDgeDzi7e0NpmnCsqyLePQ0kfl8zh0vt/P5fM7HoyhCp9PB6XR6mkSO3KSiKOLkPgsLIQSMMT7+NJEsyyBJEmzbxn6/h6ZpKJfL3NlXq9W3IvG9NSmlqFarmEwmOBwO0HWdx6inifi+D1mW+e+SJCEIAkwmExBCuJTew36/5yr2CN7f3/m8vu9DkiQA51SmUqlcxKWHiMxmM5imCQA8gOVyqKpqIZW4hSAI4Hnew0T6/T4ajQaA8+2Uy2V+EJZlYTAYPE9kOBzy1GC9XoMxxsdM07x7OjmeJWLbNicCAC8vLzzBHI1G/GCv4SYRy7IgyzLSNEUQBJxIHrTyCP4rfN9Hv9/n3xuNRhgOh1zxwjCEbdtX/SuOY4iiyB17Npuh3W4jiiLuM08TydOI3NkJITBNE61WC5IkXd3Ifr+Hqqp4eXnBcDhEEAQQRRGapsGyLO7MhmHAdd2r6w4GAwiCgNfXV7y/v6NUKkEQBIiieLfSvCu/QRBwX3AcB6Iool6v36zygiDg8mwYBoIg4FG61WohDEM4joPT6YR+v39zXdd1MRqNEAQBBEGApmlX87KbRHJNr9VqPEpHUfRUxD6dTvA8D7quIwgCzGYzAGe/8jzvpknewnq9Rrvd5qrpOM5VJSwQyWuPXF632y2CIAAh5K5i5EjTFIwxNJtNfiO5s5umCdd1n6rZXdcFpZTvabPZQNd1VKvViyBcINLv98EYg+u6UBQF7XYbWZbB8zwIgvCl5LquyzfebrcRBAHPnXRdL9zIVzXGbrcDpRSj0QhpmnL57/f7IIRgsVjcJ5JLXBiGEASBq0232y1kq9cwnU6xWq0QxzEajQaCIMBgMMDxeOQ3NJlMcDwe7/oIcJb/er0O4Cw85XIZwNl0JUniJnuViG3bBa2WZZmry3K5LMSSa1itVlBVFfV6nd+IqqpQFIU7OWMMiqJcnOivUBSF367jONB1nY+pqnqRJReIRFEExhi3P8/zeI6TV4BfJW++72Oz2SAMQ6Rpiu12i9lsxudcr9cXp3kNlFJORNO0glwzxrBarW4TAc5NgXyhLMsgyzIcx8FgMCiUsj+NPAAmSQJKKU+PHMcpHHaOCyJRFKFcLmM6nWKz2aDX63HVqNVqhQniOH66JP0VaZqi0+lcBLu8E1Ov1/Hy8gLgfy2kaxH+akDMHf1zTdDtdgulbZ5/NRqNb9cjmqaBMVa47VzK8zpI0zQIggBZlgv7uEtksVhwAoqiXETV+XzOG2v3eleP4ng88kbf52Q0iiLejCCEoNVqXSVxk0iSJBAEAZPJpJBTZVnGfYUxhsVicXPiZ5BlGVdFQggsyyqMx3H85Tp3C6vPyGMBIQSlUolXjKVS6csC6x583wdjjCeXeTPQMIynbvuhLkqSJPyKdV0vOHde1X0VF26RoJTCcRx+8x8fH9B1nYvLI42Hh4iEYchrdUmSrp5Sv99HpVK56vRZlmG/318dUxSFK9JnnE4n3oBgjD1UjX5JZLlcglIKQRBuphWe5xW6jMA5gLZaLW4qhBBUq1WeNOadyVsVZC6/lNI/1/vNs1hVVa+Oj8fjQrDMza3ZbPJuS5Ik3Ad2ux2iKLrq2DkMw4DjOBcR/FtEgLOzM8Yu0ou8w0EIQZqmvApkjF2YYf4skf+cd9t/9YPZbAbG2M/1fqMoQqVSgWEY8DwPr6+v/A0jNzvf93lZ/BWGwyF36vl8jvl8DsMwHmrIfYsIcI64o9EIpVKJF2CmafLTz/3l1uPMZrPBeDzmJmcYBp8r7yUnSfLstr73GPrx8XFx/XnTol6vXzQocrO79jaSJMnPvyE+i9xkDMNAGIbY7/d4e3vj7yvXHoq+ix97Zw/DEJ1OB4qiQBRFSJKETqfzY2XA33/h+LfhP0PkH0zLHKRhYhw0AAAAAElFTkSuQmCC"},
            {'Type': "textCurveUp", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGIklEQVRoge2ZL2zbThTHHzCINIMAA6sKMCgICLCmAmsyMAgICDCItEwKMMimgIKAgIKCSAHRNGkDAQUBkdZJAQMFAwUDAZYWYBCQSQEFAQaeZhBgaQbR9P2B6O7ni5P82v5a/byf+iRL8fndn8/du/feXQj/E6H/egAPJU8gWZMnkKzJE0jW5Akka5JZkPV6fSf9TIKsVis4jnOnOpkE6Xa7sCzrTnWeQB5TDoFEUbSzPJMgnU5nJ8h4PIYkSeh2u6lvmQRxHCe12ZfLJWRZBhEhl8shDEPh+x8DUq1WQUT8uby8FL7/ESBhGEKSJKiqimKxCCJCq9US6mQSpFKpCCDD4RCSJMHzPIRhiHw+j0qlItTJJIhlWTg/P+fv5XIZtm3z91qthlKpJNTJFIjneYjjGJZlCZ4pl8thPB7z9263C03ThLqZAfnw4QOICI7jwDRNDjKfz0FEgpcajUYgEoeeCRDP87g3kiQJsixzkM+fP6NQKAj6DwrSarVQq9XuW10Q0zQF10pEuLi4AACcn58L+4OVPRhIPp9/EBBmOrVaDev1GsfHxyAijEYjAIBt29yDxXGMZrPJYZNyL5A4jnf68kMynU5hWRZKpRIWiwUv73Q6kGWZ51BsrzAQ5sEWiwV0XRdW7V+DLJdLENHOnGeXfPr0CUdHR3wAr1694t+KxSJOT0/5+/X1tQBSKpWg6zpPT1iKMhwOD4PEcYzJZILJZIL5fL5zYJPJBESUamyXsACWnMlcLocoihAEAYgIX79+5fo3NzcgInz58gUAoGmaUFfTNEyn01Q/Aojv+1BVVah4cnLCG2UyHo/5AGazGWzbhmmaGAwGqQ6YTff7fazXa1iWBSLCcrnk7axWK67PVnsymQDYxBA2FsdxbpfG93o9EBHq9Tq63S4ajQYkSYIkSXBdl+sl7Ti55MkBAEAQBJAkCfV6nZddXl5yvX6/n4rQ2yBEBEVRcHV1tRNgJ4jneahWq4ICm7Vms8nLzs7OQESQZRmlUgn9fp+70OSg3717ByLCzc0NL5tMJtB1HUEQoNlspvpLgvi+L+yX5DjvlWsVCgXhoOM4DogIxWKRm0UYhpBlGbqucz3TNGEYhtBWGIaI4xjAJodKTlASZDabYbVagYjw8eNHQeft27d4/vz5YZAoigSbBTYbLgnC7Hx7uS3LQi6X4++yLKPX6213IbS77fkYyHK55L+3V6TVaqFcLu8HGQwG3NYVRYFhGHxwyYrFYhGapqXunthKAcC3b98E77Mt6/V6p+ebzWYcBNjskW0nYhhGaiUFkOPjY0iSBNM0eYRNegwm+6K64zhQFAXA5gxBRPj+/ftOkH2zzVz7crnE79+/8ezZM7x+/Zp///HjB1RVxfv37/eDqKoqBCeuRIROpwNgY3rMne4CYel1u93G0dERfv36dScQ5tVYtqsoiuDZrq6u+B7aC9JoNFJn5TAMhSjOAtb2AIDNuZpt9nK5nDoz3AaEhQAmhmFwE42iCKVSCbIsp9oTQEajEQqFghB02AwwO2VLf319nWpM0zTufi3LQrFYTOmEYQjf9/mEbF8i2LYtgLB9J8syFEUBEaHRaBwGiaIIpmnCNE34vo/FYsEjPZu5ZEDbrps0OcMw8OLFi1SHL1++RKVS2ZuvFQoFAYTFseSzbVYpEDZj7KYi+bB8iAW55NET+DvZYy7ZsiyYppnqUNM0tNttnkEnnYbrujwXYxLHsZA2JQPuQRBgk1oMBgP0ej1Mp1NhBbrdrrD5mdi2LVycmaYJVVUFHRapmctVFAX5fJ7HrWq1ClmWU3vLdV3ouo7T09O9fzf8Y2QPggD5fJ6vQKvVQi6Xg6IofACu60KSJMF26/V66qzNNjJLWdilm2VZ/PfJyclBJ7FPbpWiRFEE3/cBbGa+Wq1C0zRuJmzpPc/jdfr9PoiIu/PFYgFZloWUhZkpe1RVxdnZ2eOBJMXzPIzHY54Bs6fdbgt6zLuxM4QkSalIvlqthLPKxcUF5vN56l73UUCSMhwOYdv2zuAIAG/evBFgG40Gfv78Kei4rgvLsva2cVt51OugIAjgOA5UVYXjOPea6dtKJu61HkKeQLImfwHqm4TSvLEUqwAAAABJRU5ErkJggg=="},
            {'Type': "textCurveDown", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGEklEQVRoge2ZLWzbXhfGDzAIMDAwMCi4wCDAICCaCgIMDAIizZMCAgwMAqIpYCCTAgIyDQQEBARUWkBBQEBBYTVVWsBAQUFAQEGBQTUFBBhEU4DB8wfVufWNk36ufbu9fSST+F77/K7PPR83hH9E9L824E/pDeS16Q3ktekN5LXpDeS16UEgSZI8lx1P1oNAarUaFovFc9nyJD0IxHVddLvd57LlSfp3QZIkwXK53Dr4rwKpVCrQNA29Xi8z2HVdtFqtFzHsoVJAzs/PQUTyOj4+VgYHQYAwDF/UwPtKATk4OFBADMNQ3CwMw78DpN1ug4gQhiFM0wQRYTgcyvthGML3/Rc38j5SQIIggG3bAICLiwuYpolSqSTvh2EI13Vf1sJ7SgGp1WqK63S7XRAR4jgGcP3F/gqQq6srxZWiKAIR4ezsDMA1mOu6WK1WmM1mL2vpHdqaR9IyTROHh4cArkFs20atVgMRvapQfGdmL5VKMgl2u13oug5N02RkOzk5eXYj76M7QVzXRbvdBgAMh0MlPBMR9vf3/4ghtVoNtVrt0fPvBcIB4PDwEEQEy7KwXq8RhiGICOfn5482gOX7Poge3x4pM1erFTzPg2VZqFar6Ha7EEJkQNjV4jiGruuZJBnHMQaDAUaj0b17mFarBSJ6dM+jgIzH44zrcIJMg6RLl2azCcuylIcGQSDn5vN5RFF0pyG9Xg9EdK+xd4JUq9VbQY6Pj0FEmM/ncs50OgUR4fLyEgCwXC4z84vF4p0rPZlMQET4+fPn1vtRFGE6ncpUcCtIoVAAEUEIAcuyoOs6TNOUIGx0etVWqxU0TZMhmmFN08RgMIDneSAiDAYD5cX9fh9CCPi+j9lsJp99dHSkjFutVgiCQImUpVIJ6/V6N4gQIpO504XiNhAAKBaLaDQaAICvX7+CiCTYer2G4zjY29uTX4Wfw1cul5NfZBO4UqmAiOD7PrrdLvb390FEmTZDAdE0LdM4hWGIcrl8K0i6BuOyJu1+R0dHSs6p1+vS5fr9PhzHga7rICIZ6tPzOp2O/C1JEti2jUKhsBvEMAwcHBzsNJL7lU2QdrsNIYQCkv70SZLAMAx8+vQJwLUL67qOq6srANfu4ziOsh/53YZhZNyo2WxC1/XdII7joN/vKwOq1aoE4dprE2QwGMgcwCCb6nQ6sqQRQmRW9OTkBESkuLZpmkqSjKII7XZbthg7QT58+ICPHz8qAzzPw7t37xSQzQTIYTmKInz58gVEhN+/f2dgWEKIrVnctm3k8/kb44hQqVQwHA7huq7cU+VyOVO0KiCNRgOe5ykDHMeRD2eQ6XS6E4Q3+21KJ9m02JXSIHxx4mUAbi22gvR6PRiGgdVqBeAmJ7D/LxYLEBHG4/FOEE6qtx3kCSEyCwZch+T0/iIi2LaN0WgkbQKuXblSqewGYSOazSaAm9aXQfjhm+V7GuTHjx8gInz//n0nSKFQUDpPFucg3oOO46BYLGbGMdxOkDiOkcvlZELjz7oJsrkaaZDLy0sQEb59+7YTpNlsKi7E4vDOrhsEAXK5nOJGZ2dn0DQtc/aWcWauaPnibJ8G0XVdCYmbdZKu60rsZ3FuGY1GW92PQSaTCYCbU516vY4kSXBxcQHLslCv1zPPzoAsFgvk83kQERzHwenpqdK3c6mQLhy5SOQxjuNs7e2FEKjX65jP54rBLHYtzu7r9RpCCHk0xTal98tOEIYZj8dYLpfSVTjkCiFgmiY8z0OSJIjjGIZhYG9vT85vtVrQNC3zQsuyZLTSdT3jolzKp7P76ekpbNuGZVloNBpbIXaCpBXHMTzPk6snhJD1T7lclrVP2ih2Ea63gJvQzSWQ7/vQNE1Wu7wgmqYhCIK7zHo4CIsLPiGEPIRI76V0EccliWmach/wavOCzGYz6TLNZhP5fB6macL3/UcdOT24t1wul5jP50oTZhhGZuN2Oh1Z2RaLRRBRxt0Yjq9Op4PJZPKo1vlJ/yH2+314nrf1JOXXr194//69Yujnz5+VMUmSoNfrwXXdTLH6UD3rn6FRFKHRaMhNvlnF/kn9f/6r+5r1z4D8B1TcfmbMVYbLAAAAAElFTkSuQmCC"},
            {'Type': "textCanUp", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGrklEQVRoge2aIYgbTRTHX2HFUkJZSsTSroiIWGjEiYoToUREpCWFiIhAIyKuNCIi4sSJowRORFRERJyICPRExFEiUnqFiEBPRJyIiDgREeiJiBURC13KUv6fON50Z3aTXu7r9Tv63YOFJPtm5v3mzbx5b+4If4nQf23A75I7kNsmG4GcnJzAtm2MRqMbMgcYjUawbRuTyWSjdhuBdLtdENGNg1xnjDuQm5I7kE2U70A2kDuQTZSvA+J5HgaDATzPu5L+HwdxXRfVahU7OztwHCdSf7FYwDRNEBFM08R8Pg/pOI6DSqWCUqkEx3H+PEi5XAYRgYiQTqcj9dPptNAhImQymZBONpsV74vF4u8F8X0f/X4fZ2dnkSBHR0fQNE0ycjAYSLr9fl96z8/Hjx+FDhvNj6Zp6PV6K0Gm0ylc170aiOu6yGQyICLouo7ZbBYCKRQKIQPL5bLUD3vMMAw0Gg0kEgkQEfb29kI6wSefz0eC7O7ugohg2zaWy+WvQWq1mtRxoVAIgei6jng8jtPTU7x79w5EhHg8LvXDhrNBPPupVEroWJYl4MbjMUzTFJ4OgkwmE8mmRqOxHsT3fcRiMamRruvCnQxCRGg2m6JdMpkEEQnvOY4DIsLW1pY0WDKZhKZpko5pmvB9HwDQbrdF/0GQarUq2RSPx0WbSJDxeAwigmVZwsVEJPYKg2iahsViIdodHByAiNDv9wEAw+EQRIT9/X1pMPb2xcUFBoNBaKktl0vouh4CYc+lUinxWV16Ekiz2YRpmsLISqUiGcggweUB/NzY7KVOpwMiwvv37yW9VqsljAgGjqBsb29Lhs5mMzG5rutiPp8jHo9LKyIEks/nJQWOIN1uVwIpFotSJ+fn5yAi7OzsAAAajQaICNPpVNIbjUao1WpwHAeHh4eSt1l4GTEIT1JwX9RqNWnvhkDS6bTUMW9QFUSdDQAgIlQqFcmYdcKwajgNeg2ACCbBpTQYDEJnkjRaIpGQUgl2qwrC31WQUqkEAHj16hU0TcP3799Xguzt7UXC8t5hw3lfBe1yXRdPnz5dDaK+nM/nkuHs5g8fPoQMePToEV68eAEAKBaLePDgwUoIAHjz5g3u378f+v3z588SSKlUgq7rIb21IKq7OPqoHok6dROJhGifz+dhmuZakHK5DMMwQr+rKUomk0EikQjprd0jx8fH4vP5+blI+DYFWTV4UFbp8OEXBInFYuh0OtJ+WrtHoiCuA5LNZvH48eO1INlsNhKEl3MQhO0wDAMHBwfwPC8UOUMgwdT7uiDPnz/Hw4cP14JUKpVQWhMFombQfI6pGXcIJJfLiQb1en0jEA6/L1++hK7r+PHjx0oQjkaqqEvr2bNnkVm0GsmknjjcEhFqtdrKqPXp06eQAYZh4PXr1wB+ZrWqLBYLtNtteJ6Ht2/f4t69e/j27Zuk8+XLl9DS2t7eRq/Xk5aZ2r/0jXOmQqEA3/dDIOwRtfbwfR9EhN3dXQAQnlQrx+ABywefeiCqUatcLiOZTErvbdteD1IsFmFZlsj3V4EcHh5KnUynUymN4AkZDoeS3tHRkfid+xqPx5LO8fGxBFKpVEJBwXXd9Xskk8lISdzZ2VkkiJrV8uDclr+3Wi1JjwGn06k4wdVJ2d/fl0Dq9bpI/YNycXGxGiSZTEqu5sF+lTTy4Dy77CHe/CwcSJbLpZiker0u6agVIudkUVXhShD1kOF1rILEYjGpsLFtWyrAPM+DruvQdV2UBI7jIBaLwbIsoaNpGizLEn35vi9CP4PwcgzW+huD8AyqIESEXq8H4Gcak8vloPZFdFmDz2YzlEolKdUHgK2trch6J6oeUZeperUkgWSzWfHZ8zxR9rbbbWkgXddhmiaazSYMwwARodPpSB1z+q0+wTSIo1ssFkO1WhV9qWeVYRih5Vyr1VaDBD3CMx2MRgwSPDSJLktfNdQ6jiPKVn4sy5IOsdPT0xAoh9YgSDqdlsprvltYCRK8LOBciIhQrVYlkOASiNrULKpXeAkFhUtbfjiyBUE4mLAdJycn688RTdMwHo9F+sD3Ufl8XgKZz+coFotiBoMXEap0u12USqVICODytOcLhVwuF3nTGLwOyuVyME0zlKdJIMGZ4YiTSqVEETObzTAcDuH7PnzfF3fA/1Y8z8NoNILneeKzOjlqemLb9mqQYNbL6cZkMrnyTfpNyng8lq5p16bxT548AdFl7f3169c/auhVpNPpiADC4Z9FAmm1WigUCiv/THAbxHGc0BUS8H/9z4fbLHcgt03+GpB/APnJiyIuPGi/AAAAAElFTkSuQmCC"},
            {'Type': "textCanDown", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGkUlEQVRoge2ZLYwaWxTHTxPETTuCJjRB7DaTZgUCgUCQFjECQROaILbpCsSIbVKBQKxYgSBZsWkQKxCbhmQRK1bQBIFAbFLEiArEpkGsQCAQIxCIESMQ/yeaczv3zgxveW/b1/TtScZwz3DO73LP14Xwhwj91w7clzyA/G7yAPK7yQPI7yZbgTiOg1wuh5ubm5/lD6bTKXK5HL5+/brVe1uBjMdjEBHG4/FWRn6FjQeQnyUPIL/CyK+w8WeCrNdrdDoddLtdeJ53b0a2kU021us1er0eut1uaE0BOT09BRGBiFAsFrFcLu9s5L5kk41yuSz9Gw6HypoCUiqVpCIRIZ/P39nIfUmcjW63q/i2v7+vrCsgpmkqykSE6+vrSCOu66LRaKDf7/9r5weDAer1OlzXjQRZr9fY29tT/MrlcptBDg8P0ev1kEwmQUSoVCqRILlcTn5pr9eLdNDzPFiWBSEE9vf3sVqtQjr9fl9+TzabxfX1dQiEPzMMA81mE7lcDqZpbgaZz+cAgMlkAiJCKpUKgRwdHSm7k06n4ft+yEnbthU927aVdd/3kUqlFJ0PHz6EQOr1OogIV1dXClgsSLFYVBar1SqISAY9g6TT6dAR1H+VxWKBRCIR0ru9vZU6l5eXoXUGC4Lk83mk02ms12v5mRAiHkTPBJ1OB0QkO1EGISJkMhk4jiNhS6WS8u7x8bFyZBiq3W5LHc5C5XIZw+EQ2WxWvhMEMQwD9Xpd+f6NMRIkDjrOux0E4SBfrVYQQsAwDOX9QqGgvMtZJwicTCaRSCTguq7cSB1kOp2CiHB5ean4ZllWPIguHCc6SCqVUpzmWOA5ZT6f4+nTp3j58qUM8NVqhWw2ixcvXgD4fvSi0ihnTgbhZDCbzRS9g4ODu4PM5/NIEP0YnZ+fK7+S4zggIjQaDUWPgVerFQaDAYgIZ2dnik6tVlNAWq1WKLABbK4jdwXRHWTHT05OAAAXFxcgInz69EnR+/jxI4gIjuOg1+uBiDAajRQd7i4YhDMky3K5lBsSCzIYDFCpVGDbNmq1GnZ2diJB9F5nuVwq6fXk5AREhMlkouj1+31Uq1W4risTCcdHUCcIYts2TNPEYrFAs9mU9W0jSLCXiUqtDKIHHgAFhPN+VG1hiTsyemW3bRuJRCKUyvf29uJBoupDFIiepgEglUrJc1ur1fDo0aONIEdHRzAMI/Q5H1MGsSwr5I9hGHAcJx5Ef4HbEB3ky5cvIQd2d3dRLpcBAG/fvsWTJ09iIQDg/fv32N3dDX3+7du3jSCWZSlFNRak3W7DcRy4rhsb7PpuAN/TJuf2N2/e4NmzZxtBDg4OQv0S8CPBMEixWIQQArVaLdJuJIheLeNAotr4IIhlWZFOBsWyrNA5jwKxLCvUOrEvsSB6tfynIKVSCc+fP/9bkCjY2WwWAonSq1ar8SB6oeMv3Rbk9evXStccJeVyOdJB3YZlWUin0yG9QqEQD6JXy7heKwoklUopMfL48eONILZtRzqo2+BKvxWIfrS4+uogFxcXoS82DAPv3r0D8D2Qo4xza+L7fmR1BoDRaKSANBoNEBGm06nUWS6Xm+uIvshDjg7CrUjQQR6KgB8FUb+J4RrR6/Vkm69PjWdnZwpIu90OFeHhcLi5+zVNU/Y+vu/LAqmDsMMsOiBXbb1Fubq6kk7qsw7L4eGhAsKtfXC6tG07NG0qIIVCAdlsFsvlUhmMdBD9doWd4lGUHT4/P1f0eLdns5nsfjudjqKTz+cVENd1QURIJBIYj8cYjUYQQuD4+DgehHeSH+5vTk9PFRC92eOY4HmE5xi9S65UKiAirNdr3N7egohQq9Xkuuu60mYwobx69SrUdXz+/DkehB3gx7ZteXOhgzAcz+ZCCNlbeZ6HRCKBnZ0dOYD5vg/DMJDJZKS9ZDIJIYTcFI4HHUS/7NAHuxBIcHfT6TQWiwVM05TnkUGy2SyEEGi327If04OPR10+OjxnBGdv/oUKhQJarRaEELJND4K4rgvDMCRIq9XS3Q6DeJ6HTqcjr4Xy+bx0kkGC8cOPftabzaZcC178BTtnTu/BhzdSr1X9fh+ZTCYUG7EgujiOI7MRg9zc3EAIIY0nk8lQGuX2Jvgkk0klJfNx43UhRGiwuqts9beC7/sYDofwPE+58I66HQd+FDN+gldBLJzh+Jd2XReDwSDy34B7A9FlNBopd8O6eJ4nW5FGoxEKUJbJZBKa3beV/+f/7L+z/DEgfwGqM5x9rUdafgAAAABJRU5ErkJggg=="},
            {'Type': "textWave1", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGdElEQVRoge2aL4waSxzHf2LFihUrVqxYgUAgEAjECcQKBAKBuLQIBAKBQCAqSHqCBIFAIBAIkq4gKWlIeoKkNLleaEMbBIKkTXpi0yAqVpxYgUCs+FaQme7sn3vl3d27e+/dL7mE3Z2d+X1mfvOd38we4T9i9NAO3JX9f0GazSZqtdp9+HIrOxrENE0kEon78OVW9gTy2OwJ5LHZE8hjsycQALAsC61WC67r3rljx1osiGVZyOfzmM/nwn0GMp1OQUQgImSzWez3+ztxaLFYYLPZHP1eJMjFxQV3UtM0OI7Dn5mmCcMwkEwmeRkiwnA4/Pve+x0igmmax78XvOE4DnRdj3XSNE1+X9d1pNNpPip3YXcG0ul0QESQZRmyLIOIUK/X+XMGIkkSbNuG53nI5/MgInz79u12FLhDkFwuh1wuB9d1eYgVCgX+nIGUy2V+j5Xr9XpCXb1eD4qioFqtwvO8fw7EdV1IkiT0rKZpQsUMxLIsoSJd11GtVvn1er2GJEk8DP3P7h1kOp0ik8kIBRKJRCTI1dWVUK5UKgnz5OXLl8I8UxQF79+/vzXIYrGAbds3g3S7XVQqlT8CCdrZ2RkUReHXJycnICKUSiWUy2UQUajuY0Ha7TaICIZhhORe8KhWq6HdbgsFDMMIgWiaFmqErStMqlVVRSKR4A0Wi0Woqiq847ouGo0GOp0OLxcHMh6PhRGeTqfxIIVCAaPRiF8zBQuCRKUoi8UCRITtdovdbhcagfl8DiLCarUS6mKOMUGJAtnv99A0TQBpNpvxIO12G9vtFgAwm834ZD0GZLlc4urqCkSEfr8vOCPLMle25XIpOEZEmM1mkSCj0QhEhFwuh9lsBkVRkM/n40GY2bYNRVF4A8eALBYL/vvi4kIoc3Jywnuy1WoJCysblSiQTCYDVVVxfX0N4HAAEvQhBOJ5HjKZDIgIxWIxcrLfBDIej3F5eQkiwuXlpVDm+fPnePbsGYdiMu55HhqNRmTHbbfbUChNp1NBWCJBut0uVwbHcY4GsSyL//bPB+ZAt9sFcBCDVCrFn7muy6PA395kMgERYb1eh9q6ESSVSkGWZZ6BRoFEqVYUCJtvQYsSA+CgmkGQZrMJWZaFzMC27ZtBNpsNiIj3WhwIEfF4DYKMx2N8+PABRITv379HgkSJAfB7Uvvby2azoYSUSXEsyGg0QjKZFOhlWY4ECYbN+fk5n+yr1SoUDn778uULiAivX78W7n/8+DEEIkkSTk9P+fVgMOBqGgvSaDSESeU4TqRqBUcN+K1Cm80GX79+BRHh06dPkSBxqrbf70PtsezbdV1Uq1UuCLlcLh7ENE0hGbQsKxYkmJP5Q+7Hjx8gIrx79y4ShK0XQVUDDiLA2mMdmc1mhQUxlUoJm70QSCqVwmKx4NcsR/Kri381Xi6XAA4xL0kSdF0HAFxfX4OIMJlMIkFY2s/e95t/TjLp9f+l0+kQRAgkkUjwyvf7PVRVhSzLgkqxra6maVAUBf1+H9lsFkQkxLKu6+h0OpEgbA75Oy0KZL1eCxCVSgW73S6yTgGEiPhhQ7fbhaqqPC6ZSrF1pF6vh3prPB7zuorFYkhee70elssl7+m/AmFzKZvNCmX3+31ofxMCaTQamM/nkCQJzWaTJ45spM7OzlAul2HbtrBx0nVdSK1brRbS6bTQWK1Wg6ZpfB05Pz+/EYQtB4PBQCizWq2EcA+BGIbBHZNlGY7jwLZt/Pz5M9QgcFh1WfgFFYil9f6jnUKhwB2I2mUGQdjIBbcWk8kklI8JICzHIqLY+A6a53mRceu6LmRZ5iHAst9iscgdDjoIiOuW67pcfv3WbrdDX80EkGazCSJCPp//48OCm4ypXr1eR6lU4qELHBSyVCoJ5T3Pi1xHgil7oVAIZQUCiOM46Pf7scpwrL158yYkCG/fvgUAVCoVJJNJoTxTKT8IC102/3a7HRRFCUn3vX7V9TwPp6enHMIwDP6s3++DSDwLGwwGIRA2kkwRWYoS7Ox7/zzteR4KhQJ0XRd6ka0lLNSA34utH2Q4HIKIoKoqKpUKJEkSztmYPeh3dsMwIEkShsMhPyEJgnz+/DkUnq9evQrV9aAgL168EByUJEnItZix3SRLFqOE6EFBXNcVksGorTVwyOWSySQymUzsmvbg/8KxXC6haRoSiQS2220kyJ/Yg4MEbbVa3d2Hnn+jPYE8NvsFyIFK1JCsNRQAAAAASUVORK5CYII="},
            {'Type': "textWave2", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGNUlEQVRoge2ZL2wiTxTHnxiBWIFYsWIFAsElCERFBQJRwSWIFQgEAoFAVCAQiIq9XHIIckEgEOSCQFQgEBUVXI5cSI5cEHs5BJcgViAQFRUIxIrvTzQz3WF22/Jroff7pS/ZpJ2dnXmfmfdvBsL/ROi1FXgpeQM5lFiWhWq1uvd3fx0IESGTyez/3QF0eZa8gRxAl2fJG8gBdHmWvIEcQJdnyX8WZLvdol6vo9PpADgiiOM4mE6ne08UJplMBkQEIsJwOAwF6ff7GAwGoePsDZLJZBCLxfb9LFC63a6AICKkUqlAkEajIfr0+/3AsV4VhCsej8ehaZpQ1g+y2WwQjUbFO03TsFqtlLGOAjIcDlGv13F7eyvalssliAinp6fYbDZwXReRSEQB+fLli7RrRIRPnz4dH6TT6QgF0um0aG+32yAiXF1dibZKpaKAFItFEBHOz8+xXq+RSCSkcY4CMpvN8O7dOwHCGMPXr18BAOVyGYZhwPM80b/f7ysg3PzW6zUAYDQagTEm7W4gyGw2w2g0ehGQWq0GIkI0GhVm02g0hIK5XE7qP5/PFRDGGBKJhPjf8zzoui7tpAKyXC7BGAMRhR5ungrieR4Mw4BhGFgsFhiNRiAilMtlAIBpmqjVasp3fpCbmxsQESzLkvoUi0W0Wq1wkM+fP0tOVa1WlS3cBWk0GqjVamLruXDFu92uaIvH4zg7OxMK+99x0TRNgDiOAyJCpVKR+jSbTWWhJZByuaxEiF6vFwpSKpVEv5OTE6nfx48fwRjDzc2NaLMsC+12G9vtNjQnxGIxATIej0FEyGaz0kINh0PFLCWQTCaDZDIJ13VhWZaI8X6H5CB8Ev/jt1vLspToslgsAACu64KIMB6PnwTC/azdbot2v98oILlcDvV6HcCdjfOIMZlMFBAOahiGmKxUKol+8XhcMQku3Kn3AeFPuVzGfD5X/FQCWSwWkinx2oevBAfhEahUKsHzPFxeXord46JpmuKQXLiC/gUKAuHAsVhMgkmn09B1PRwEgGRGm81GJCM/CM8JfruNx+NgjN0PTITr6+sHQR7bEW6C7XYb4/FYWAh/HgQJGphHGj9IPp+X+vFAsVqtsF6vQUSh+eghEH/4vb29BRHBtm0AdwvrDzB7g/gTFAfxmxtwX8kul0v8+fMHRIQfP348CHJ5eSm1c8X98+1aBABUq9XHQfzhMgiEO/m3b9+kfldXVyAifP/+HT9//gQR4ffv34Egk8kkMI/w3OOfT9M0JSECkAKLAjIej8EYg2maKJVKsG0b0Wg0cEf8vsS/5X7B/3ZdV+rjui663a4wvd2VbjabCkg2m4VhGArI7vyPJsTdgXnU2hWufK/XCwWxbVuEzUgkglQqJb1Pp9PKfB8+fAARYTabKXOGgpycnDwJJKjWCgKZz+dSn3K5LJJkMpkEY0z0mU6ngfNxc/OHcsdxRHINBInFYkgkEjg/P0cul0M2m5Vqn6eAjMfj0KhkWRYKhQKA+7NHKpVCt9uFYRjQNA2GYSgnxN3d6/V6StUggTDGFAcMilqPgXBn3r0sME1TVA6DwUDZ+Xw+r8wH3Js8161QKDycEHVdV1ZxX5DpdCoS2cXFhXjPHZwnSc/zEI/HpUOX4zgoFAoib3DhVXAkEoFlWWCM4fT0NBwkmUz+a5Dr62vh4Dwf+MNmo9EAYwybzUa0TSYT6LqOaDT64FUPcFcH7tZcoSBnZ2dK2W6apgJimqYyUavVAhGJ84thGGKVF4sFdF0PPGs/VX79+oX3798LkN0jgATCcwcXz/MCoxYRYbvdYvdbf9GYz+cVH9jN5PvKarWCZVnIZrPK/BLIxcWFdEDiThsE4jiONFAqlZLqL14R82f3ouGlRQLp9Xoguru6BIKvZziI3wS5czebTdHmd2ZN0wJL9oOB8Jit67qoqcJA/PZer9cD88ZisYBt28ruHUKUorFQKCgm4T9W+i+dW60WOp0OGGMHN53HRAFZrVbirrVYLKJSqUjJJ5PJQNd1cUrkT9DVzjEl8DyyXC4xGAzgeR5s2wYRifKe5xF/VNI0TbkOOrY8erCaTCYwTVP8JsJBXNeFaZqIRqOhR9pjyqv/0PNS8uo/vb2UvIH8bfIP/BpHp/Ltbr0AAAAASUVORK5CYII="},
            {'Type': "textDoubleWave1", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAG8klEQVRoge2aP4gaSxzHf8UWW1xhYbEJW+zBFhYWQiRYXMBiIRYWQgxYWFhIkGBhwEKIhWBxhAtYmOQCV1zAQpIjXHEBIRewMHCFhYWFxRYWFhYWhizBwEK+r7g3k53Z1Xd37x4vee9+MMXNzvzm95k/v/n9xiP8R4T+bQOuS25AfjX5/4IMBgNUq1WsVqtrN2Y6ncJxnCv1vTRIv98HEWE6nV5pwE1yeHgIXddh2/al+/5yIESEfr9/6b43IDcgG+QGBP91kPF4jEQiAU3TsL+/L3z7bUAcx4FpmiAiXsbjMf9+VZCgi24ymUDTNEQiEczn8+sFef78uQBBRHj8+PGVQVzXxc7ODjRN81106XSaj1EoFK4XJBaL+UAUReEhyWVB9vf3uZ5SqcTrZ7MZFEURxmi329cDMpvNQETY2dnBYrFAv9+HqqogIkwmEwFkPB4jGo1C13X+LUju37/Pjb1z5w6+ffsGANxob8nlctcDwpbWa1itVgMRodfrCSDFYpEbEIvF4LquT/lkMgERQdM0PvtMdz6f56tk2zZ0XYemaYEgq9UK9XodpmlC0zQMBoPNII1GA9FoVGhwcnICIuLei4FsbW0Js3l8fOxT3mw2oSgKRqMRKpUKiAgnJycAANM0oaoq5vM5AKDT6XBdMsijR4+Ese7du4cvX76sBymVSsjlckID27ZBRGg0GgIIEUFVVYRCIRAR8vm8DySRSHB9g8EARIRWq3U+8J9bmInjOHzVvCDe8bxFXhUBJJ/Po1arCQ2m0+lakH6/D9u2EQ6Hoaqq4GKXyyWICIeHh9xQIkKtVuM6vYcfACzL8oGwOrns7e2tB0kmk74G60Di8ThvU6/XQUTodru87uzszOfdcrkcHMfh35rNpjBWoVAQQLyrVCqV4DgOdxKFQmE9yO7urs8DsQMrg5TLZd5mNBr5lL98+RK3b9/Gjx8/IMvR0ZGwWvKEMBB2Pg3D4O7fdV2YpolkMrkeJGhAXdcDQdrtttBW0zSYpsn/LpfLPsfBhHlHGaTVagkg7O/d3V2hXaVSEcZaCzKZTHwXowxyenoq9EmlUiAiPnMPHz5EJpPZCCJ7J7m+XC4Htut0OtB1fTPIYrFAJBLxHS4ZRFbO3CuLy+LxuLD9rgKSzWaFyWHCbNgI0mg0BIB4PB4IMhwOhX4sFGFGbG9v4+nTp4EgBwcHFwJJJpMIh8O+/n8J4rouPxOhUAitVmut15JjLWYE23LePrK8fv0aRIQPHz4I9e/evRNADMPwnQUA6Ha7m0GYkbquYzabAVjvfmWQXq/HD/D3799BRHjx4kUgyJs3b0BEePv2rVD//v17H0gsFoNt25hOpzg7O0OlUuHx31qQdrsNVVUxGo14nQzCXK0ckn/8+BFEhFevXp0rDvBKTNZ5LXlr3bp1K/AyZGW5XAaDlMtlWJYlKF8HIt83nz9/BhHh2bNnHKTT6Qhter0eer0evx/+CoRt86CSzWaFvgKIZVk+nz0cDi+0tVh9o9GA67qBhkajUeRyOYzH48D7QQYxDCMQolgs+qJtASQWi/kGZ7N3GZCvX78Grsj29jaePHnC4y45QA0CiUajyGQySCaTKBaLgSG8D8QwDJ53MGH5iAwiK/SCAMFnxLsK4XAYsVhsI8jdu3fx4MGDQMM3goRCIZ9vj0ajgSBHR0dCOxY/ecN0b1DIzhqDsywLqqoKW2Rvb893j8gxFRM5shBAiH4mPgBwfHy89maXYy3ZE4XDYVSrVZ8u5hFZgOjdAdVqVQBJpVK+VQPOc5uNIYrX4Pl8zr2Goig8d2AglUpFUNRsNgUjIpEI0uk0/16v1xEKhfjf7Ox5EzIWrzEdhULBZzCbNBnQd0YURUEul+OZXyaTgWEYPERnIIlEQlDE4iIWa1mWJRhhmqYQRK5WK2xtbUFRFPT7fe4dvSBshbz3BZsU+ZoQQORgkeXb3r3KQBRFwWKxEPoqisL3fKlU4luJ3frydmQPEHJhIHLYwySTyWxOrNhzjHwu8vk8IpGIABIKhXBwcADg5yXpXW52cA3D4DPvBQd+5vGssAcNBsJWSc4kdV3fnOqyYExVVcF1np6e8r3MQCzL4u46mUyCSMwaP336JBgp3xlBk8f0eFNdovPnJPmB0OuUfCDAuXfZ9IrovS/kLSErZ+9UsnfyiuM4SKVSiEajvlQA+Hm7FwoFDIdDnvCxoHYtyEWk0+lgOp3yKJSIEA6HfQkQ217FYvFCeofDITRNE0DYgfeWoBT6b/3OzrJC73nyiuu66Ha7ga+Q62S5XApnybZt4Y2YiHw/dQB/E8RxHGQyGWSz2X/kd3cmLHcnIkQikcCxfov/fHBdF/V6Hel0mj+xyvJbgFxEbkB+NfkDUJRbE8hV/lcAAAAASUVORK5CYII="},
            {'Type': "textWave4", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGqElEQVRoge2aL4gbTxTHn1gRyhYiAo1YkULEihQWGhERsZSIlEZEBBpRaMSJiIiIg0acOIiIOHEiIuJEChERJyKOEpFCoEd74igRV4gIZcWJiIgTK1ak8P2JH2+6M7N717T98fvR3z0Ykd2ZN/OZffP+DCH8IUL/9gJ+l9yD/Nfk/w0SBAGCIPjda0EQBDg4OMDFxcXOY3cG8TwP2WwWnuftPNldMhwOQUSYz+c7j90ZZD6fg4juQW6TexDcg9yD3Cp/PIjv+6hWq8jn81gul5FjfwnE932USiVks1msVqufWnxY4kDq9TqICEQE27Yjg/EvgTSbTTFBqVTS+gZBgPF4DN/3fxrk6upKzMFtPB7/PpDFYoFEIiGUG4aBm5sbqe/h4SGICOVy+adB2u22BhKl76dBeJHhNhqNRL8gCJBMJsW7k5OTSH3L5RK2bSOXy6Hf72sg2WwWRIRutwvP82DbNkzTxHa7vR2k3+/Dtm1ks1m0Wi1cXl5Ggriui3Q6jdVqhb29PRARarWa6Pf+/XsJslQq4du3b5Ku7XYLx3FEn3w+L4EEQQAiguM4YuGj0UhYRCzI5eWltstEhPPzcw3EMAwMBgMAwHq9hmEYSKfTot/x8TGICLlcDul0GkSkbQqbktoYZLFYgIhwdHQkxvi+j0QigclkEg8SZS7sKVQQIsL19bV4XigUQETinPBX8jxPMsewFItFEBFM04RhGBrIeDzWNhIAKpUKjo+P40F48qjGi+ZF5fN5SVGr1ZJ2/fnz53j69Kl4/+zZM7x48UL8vr6+FhDL5VLsfhik0+mAiDSv1+l00G6340FqtRpM04TneQiCAIPBQCifzWYSyKtXryRFbEq8iEwmg0qlIt4fHBwgkUiIGMAHe39/X/QplUqSjkajgWQyCVWGw6F0HjUQ13WlyYHvX4nPA4N0u11NOREJ2yUitFot8f7s7Ew6pKw3fGjZ1TJIpVJBJpPRQObzuWYREkij0ZB2CAAmk4lk3wyiBiV+PhwOBUj4THieByLC6ekpAMBxHFiWJenodrsSiOu6yOfzmE6nGA6HAno+n2uAEshms5FiAQCsVqtIEDWN4Of85cJQYrKQBzIMQ8sG1IDIziDcHMdBr9e7HSRKvn79CiJCp9P5IRAGjgLJ5/PS+2azeSvIkydPYp3Po0ePdgNhk1C/yNXV1c4gqs5wfIgCefz4cSzIw4cPdwNRTYvd5JcvX6R+Hz58ABGh3+/fCcI61fcqiGVZsCwL7XYbh4eHwosxzA+BbLdbzGYz2LYd+UXUeiTqsMeBqH3jQDKZDOr1utTH933h8WJBgiDA3t4eMpkMTNOUPuVdIOxe2StZlhULMp1OIz1fFIjrupE6+MxGgpycnMTa5F0gUYtQ0wiWt2/fgojw7t076fnp6ammo1AoROpQRYvsUXnWj4CokT2Xy2m5VRx03PNCoRAZEO8ECfvtVCqF/f19UaGpIGppy9Ui52Su62rBdVeQSqUiJaIsm83mdpBMJgPLsjCbzUROFOd+1UW4rotUKiV+v379Gi9fvrwVhPO3OBDenOl0KvUbj8fCO0aCpFIp9Ho9qUMciFoPpFIpVKtV8bvX68FxHE1XeMGqM+AklUGOjo6kYMzS6XS0ZFICISItRYkDCdv/+fm5lkhOJhOYpinpyuVyGAwG4lCrIFwPMQjneclkEuv1WvQrFou3pyiWZWkmwwFQBQm7RfbrYRNYLpcgIukeKp1Oo1ar4ePHjyAivHnzRpqLTYnXcHNzIwou13WxWCxEqau6ZQnEcRzNt7PPV0GI/i6i5vM5DMOAaZrafVMikRBJJNff7XYbm80GRKSVDGo9En6mtkajEQ9SKpW0Q9Tr9WJBTNMUV0JqoQUA5XJZLJbHcX5lmqZU4282G7H7YZDwfOGm3spo9Yjq+8vlciQIXyhwUz0Q8L0KvLi4QKPRkKI51/i86HA1qpo3j+VmGIZ0ZjSQTqcjeZrVaiV2iVNuBgnX91G3jADw6dMnaQEPHjzA58+fAXyvBguFAiaTCZLJpNgcFYQ3pVwuw3VdkQbFgrAZ9Xo9rFYrESATiYQwHQZZLBbI5XKoVCra7oRFvbdiYY8UbhwAo0DuEgmE0+tw40vqYrEoQFKpVGR0jRJ2FrxBLOpNpGEYGI1Gkfe6O4MA8g6yS3VdV9TX6/VaSxnukmq1Ctu2tXF8hRTlhXYVDWQ2m4lzwVcuzWbzlyeKEt/3Ua/XUa/Xf/jGPk4iC6uzszMMBoN/5E8B/5T8v//C8V+UPwbkL8E2YCkA6wuRAAAAAElFTkSuQmCC"},
            {'Type': "textInflate", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAG/UlEQVRoge2ZP4gazRvHH8hClmBhIWQLAxtYjisMHESChZAtLC5gYSEh5O+SWFgYMHAEIRIWLA7OBIsrDpLCQrgrhFhYHESCxQUsUlgIucLCgBAJV1hssZAtvm9xzLw7O2tO8yb5vfzee2Dh3Hl2Zj7PzDx/5gj/J0L/6wn8KjkH+bfJfxek2+2i0+n8jrkAADqdDg4PD1f+bmUQXddh2/bKAy0rtm1D1/WVvzsH+V1yDrLqB+cgS8o5yKof/GdB+v0+LMtCv99fSv+PgziOg1QqhVgshqOjo1Ddd+/eIR6Pg4igKAr29/clnU+fPiEejyOZTMJxnD8PsrW1BSICEUHTNLiuK+lubGxwHSJCIpGA53m83fM8GIbB223b/rUg0+kUpmlCURRsb29LIJVKBdFoVJhkq9US9D58+IALFy4IOkSEXq/HdXq9ntAWj8dDQebzOUzTRCqVwmQyWQ5kPB4jFovxzlVVFT7WdR3pdFqaYC6XE/qpVCq8LZlMQlEUEBEajQbXKRQKUj+maUogxWJRWP35fH42yLNnz6TOd3Z2BBBFUaCqKprNJt9i0WhU6IfB1mo1AEC9XpeA2bba2tpCq9XisH6Q+XwOVVWF+bA+F4LMZjOoqgpN09BoNJDL5UBEKBaLAggR4dGjRwCAb9++4fr16yAiDIdDrheJRKCqKree67pQVZVP8suXL7h06RKuXbuGr1+/AgAeP34sGaXVavHzVa/XEYvFQs+kANJut0FE3As5joNoNIp0Oi2BdLtd/o5tI/ZuNBqBiHDnzh1hMNM0oaoqAODo6AhEhFKpxNs7nY60IpZlQVEUbqSDgwMQEQaDwWKQarUKwzAEhWw2K3TMQBzH4e+63S6ICHt7e8Jv/3nwA5+cnKDZbIKI0G63ebvjOBJIMplEIpHgvz3P4ztmIcj9+/clK1qWJYFomiboTCYTEBGq1SoA8En6PRQA7O7ugogwGo1g2zaICMfHx4JOIpGQxnvy5Imgc/fuXdy7d28xSLvdltxo0B3quo5MJoOgEBEsy+LfEBHG47Gg0+12USwWMZ/PuZM4OTkRdHK5HB/Pdd3Qwx22c84MiGEgbMJ+0TSNvy+VSiAiIfgFxbIsEMnDl8tlPh5b6WazKejs7e1JLnohiOd5aDab0HVdAnn69Kmkv7a2xl3rgwcPcPHiRXz//n0hSCaTkVw2IBqOOQTmRGazGcbjMSqVCiKRyI9BHMdBvV7nhzp4+BYljYlEAqZpAji1dnCgoIQFPgCo1Wr8fb/f50E5GNuCqyn8cl03NGovA2KaJnfTuVwOly9f/ikQtgv8IIuehSDMj7PHMAxpwB+BML1bt24hHo//Y5BgLsaCZTablXJAyf2yKNpsNuF5XuhhPwtk0ST9kk6nl16RYrGIdru9MGGUQFjw8XubnwHJZDK4cuXKD0GWWZHDw0MQEd6/f//DviSQq1ev4uXLl4LC8+fPlwLxe7fNzU0paAbl5s2bWFtbk97v7Oxwb8ZWxB/9AWA4HEqxRQCJRCJ4+/atoFAqlZYGWV9fB3Bq7TDX6pdFK+LfAYPBAESEN2/eCDq1Wg3JZHIxSDKZRKVSERT8kZZN2J8N+98z95vP50ODneu6PEczTTPURftBptMprxz9ks/npfpHGM2yLNy+fVtQuHHjhuCBdF2XOgFOVzOfz/N+wkCGwyEikQh6vd5CnUKhIBhOURRks1lBR9M0nteFgtRqNSHXPz4+Do0jwWWdzWZCrvXixQsQET5//izosax4f3+fZ8LBfCyVSgnjra+vIxaLcQfEXHLwwiM0jpRKJYzHY2Sz2VCQ4P5n3oVtAVYNBgdjWXG/30ej0QARSf8LicViwnhsDrZtYzQacbCgCCAs1/cHIEVRhL3MUhe/JVl6zjJnZpCg46jVavxbVvnt7u7ydnYm/CCvXr2SgmKYs5E2KbMae8rlsrCXGUi9Xpesxqq24XAolcgAeOk8n8/x8eNHEBEePnzI21+/fi2VupPJhNfyrG2pywfg1MKGYaDRaHBfPp1OOUgkEoFhGHBdF9PplA/EPBKr9DRNE4Krpml8kp7nQVVVKIqC6XQKz/OQTCalFQH+vkWJRCILLwPPrEeYdZm1dV3H5uYmv7phNyEbGxvCd4lEQghmbLv5PR6buGEYyGQy/O8giOd5ODg4kKrJlUDYJFgnuq5je3tbWG52peMXdmcVjUZRrVb5XZm/1mZnxv8ES+tlZeUr03w+j2azyVeFPaPRSIIPS739tx+sAmRPOp2GbduhceqXgwCnSz0YDPiqhA3suq50rRpmaZZxM1ccdoe8jPwUCJN2u41yuRzqRYC/4wl7grU3cOoYKpWKdOmxqvwjkLPE8zwUCgVEo1HpDP1q+a0gf1LOQf5t8hcNB5MLDmokwwAAAABJRU5ErkJggg=="},
            {'Type': "textDeflate", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGmklEQVRoge2ZMYgaWxSGTzHFkExgCgsLiykstrCYYgsLiymEbLGETZBgwEKICxYSLCy2kCBIshALSQxIYmEgEAkWBrYMi4WFhYXFFhYWEoRsMRBDJkTIhPyvkHvfXO9o9L19L8t7e2BgnXvuzPnuPefcc2YJ/xGh323ARckVyGWTK5DLJlcgl022Bul0OpjP5/+ELQCA+XyOTqez9bytQQzDQKlU2vpFm0qpVIJhGFvPuwL5p+QKZNsJVyAbyoWCtFotlMtlzGYzaex3gTiOg2KxiFar5TtPAnn9+jWICEQEwzAwHA6F8d8B4rou4vE4t6vf70vzJBDLsvgEIsLt27eFcQbiui7a7TbOzs7+tvGj0QitVguu6/qCNJtNwaZEIrEeZDweCxPY5d0VBpLJZPh4vV5faWSz2UQmk0GtVoPrur7j7DmFQsEXJBaLCfZomiZVFwLIyckJiAi7u7uoVCowDANEhEqlIoAkk0npwefn55KRiURCWkkvzGQygaIofFxVVWSzWQFkOp3ydzBIIsJgMFgNUq1WQUQYj8cAgG63CyJCNpsVQFRVBRHBNE3oug4iQiaTER7c6XR8d/fk5ITr5PN5EBF0XUc0GuUwXpBWqwUiwuPHj4UdfP78+WqQQqEgbWs4HEY8HhdAiAgHBwd8VVVVha7rwjwWnPl8HtPpFMViUZgHAMFgEKqqYjKZAAAODg54kmFSLBahaRrPoPP5HIFAAPl8fjVIOp3G/v6+oJBIJIQHMxBv5mArywLftm0oioJIJCK4kmEYCAQCAIDhcCjtdr/fl0Du3r0Ly7IEm/b393Hv3r3VIPF4HOl0WlDIZDISiKZpgg6LrUajAeBPtzo+Phb0jo6OQESwbZu7SLvdFnQ0TRPeFwqFJLfNZrOIRqOrQabTKbrdrqCwnEUMw5AeYtu2sLqVSsU333c6HcTjcUynU5RKJSEemcRiMeF9RIRyubzWJgnET/xAlncNWPh7KpUCsFgxIvJNt0yYO/rdZ+/7+PEjiAgvX74UdJ4+fYpQKLQ5yHg8hmmaEshyoLH7zJeTySSuX7+OHz9+rHx2Op3m8eIV78JNJhMp0wF/Zq6NQBqNBjRNk4JvVYlimiZM0wQA3Lp1C8FgcCUEsIhHv5rKC8ISws7ODizLQjKZRCaT4dltLYjjONKBtwyy7LPAorRhet6/V8lyLDBpNBr8/unpqe9ZxK5v376tBmFB6D21N9mRWCzGk8CdO3d+uSOrYJvNJr///v37tSBeEX45jsNPaiJCKpVCsVjcCMQbI/fv38e1a9fWxkgqlfIFqdfr/D6rLAzDEEqZX4Kw84CdyIB/1loFwrJWoVDwzUjj8RjZbBaTyQT5fB6Kokg63vf1ej0QEbrdLhzHwWAwQK1WQzqdRjgcXg3y8OFDEBEePHiAr1+/AlgcYr/KWq7rQlVVnpYfPXoEIsLp6amg9/btWxAR3rx5g3K5DCKC4zgrQc7OzkBEePfunQS8LAJIMpmUSmQ/11ouYwaDAYgI1WoVANBut4XfTJjxw+GQp9BeryfoeF3uw4cPICK8evVqOxDLsoSiDljk+2WQSCQi6LCqmfUtjuNAURTs7u4KeqZpQlEUOI7D/X8ZNhKJ8Pe5rgsiQq1W2w7ENE3J/5fzvWEYuHHjBjf6y5cvuHnzJsLhMD5//sz1WDNUKpXgOA6Oj49BRHw3XdeFpmn87AGA2WwmpXtd15HL5QSbbNteD2IYhrRCoVDIt/plhVy9XgcRIZlMCvOW21N2eYtEdl6xFc/lchJILBaTqt9qtbq+jFdVFc1mUyD3OxBZYxUKhXzbYQD4/v07Dg8PBYjDw0N8+vSJ67CynYgQCAR8D+B8Pi+VMrlcTup/OMjPnz+haRqePHnCB1+8eME7OC9IOp0WDFyOKyaz2QzVahV7e3soFotShgIWvYX3WcsnfqPRkJKCZVlSnAo7EgwGBX+0LIuvPjPCMAw0m03eAcbjcd9+fVOxbRumaYKIEI1GpSzJ6i2W2ufzOVRVxd7e3moQwzCws7MD13V5r8y+loxGIwALn+12u3BdF/1+f22pvqm4roter4f5fI52u41YLCaMRyIR3peww3a52SK/CSxN6rrO6x3WcF2E4dsKy3je69mzZ4KOAJJKpQTlo6Mj2Lb9l/6DdJFyfn4u1VrsgwUT389BLMD/ju9ftLCgJyLpoAV8enZd16EoCv+QcJmkXC7DNE0er16RStTRaHQh33P/bfn//nv6ssoVyGWTPwDWyFxNUfRp2wAAAABJRU5ErkJggg=="},
            {'Type': "textInflateBottom", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGOElEQVRoge2ZL4gbTxTHX2ELKxa6YsWKFRERESsiIlZcISJixYmIiIiIFSlE3EHFFSKuEIiIWHEihYiIFREVFRERKyIiIk4EGkpECiciVkScCCXQUFZ8f+KY6c7+ud61vf6O9h4shJ03s+8zM+/PTAh/idD/bcDvkn8XZDabgYhweXn52425vLwEEWE2m92770+DbDabe3/sR7LZbJ5A7g3ied6Dg3ied+++TyAPARIEwZ8H2e129/7YXeS3gkwmEziOg/F4nGgbDocgerj0kwWy2Wzgui5Wq1V6v/iL9+/fg4j4Y1kWwjDk7Z1Oh4MEQYDJZCK0/4z4vo8gCDhIp9MR2sfjMRRFARFBkiTM5/PbQbbbLe8QfaIzxEA2mw1UVQUR4ejoKBUmDEOcnJxA13U0m81UnWq1CiKCruvYbrcJkDAMkc/nBXsMw8DhcMgGYdumXq/D930cHx/zVYmDNJtNYfDJZJIwstVqCTrtdlto//Dhg9D++vXrBAjzyWKxiH6/j1KplJprBJBWqwVFUbgjh2EI0zShqmoCRJZlwQjbtoWBP378CMMwBB1d1/H582euU6lUhHY2ZhSkWq1ClmVst1sAwHq9hiRJiUkRQBzHEWYfAHq9HogI19fXAgjbcsvlEpqmCToA4LouN85xHK4zGo0AANfX1yAiKIqC6XQq+GYUJJfLodlsCjaVy2UUi8VskDAME8Wg7/tC3jg/PwcRoVwuc512uw0igu/7/B3blmwLjMdjEBFqtZow7snJCe/D/OX8/BwAsNvtQEQYDoeCTe12G7lcLhskTeK1leM4iQCwWq1ARLi4uODvVFXF0dGRMJZhGCiVSgC+r9hyueTtzGccxwEATKdTEFEi5LquK2z3XwJZr9dcJwxDSJKEVqsFALi6ukp1bsdxoOs6/y1JkhDJWD8GklZFLBYLvtq3giwWC5ydncFxHDQaDe6wURBN0xLApmny7cZmMp7YOp0OZFnm45immRhHVdUEyHq9Rq/XQ6FQEIJDJshqtYIkSYk8EgdJM6BWq/FtMxgMUg9f6/WaRx/btrm/xCckDhJ/JElK9BVA4rkh+jAD6vW64OhMHMfhDhhNmllSLpe5wfH3jUYDANDtdgUbFEVBq9UStnUqSKlUgiRJ6Ha78DwP8/mcz270Q9Vq9VaQN2/egIh42ZEmxWIxFSQ6UWxCcrkcXNflk5kmAoimaYnB2fJGQdIMYM4LAKenp3j27Bm+fPmS+eFcLpc5Thxkv98LOkEQoNfrZYOoqoputysosIR4FxCm9+rVK7x48SITArgJxT8CeffuHYgInz59EnTevn2Lly9fZoNYloWzszNBgSXAH4HUajW+Is1mMxHn43KXFRmNRql1VbVaTfRNOHt8/9fr9TuBlMtl7iOnp6d4/vw5vn37ditIvD6Lg7AcNhgMeHsYhlBVFf1+PxvEdV1omiY4FcsjTCzLQqVSSRhQKpUSzn7bKdKyrETmZyCs3mNH3+jkslInHrkEEFb/2LaNw+HAw190m+RyudQ8YhgGNywr/LLEFgQBKpVKol4CxJUFbvxWlmUsl0vs93uYppnaTwD5+vUrbNtO5JA4SDyzs+KOJSkGcnV1JeixifJ9nweH+KqpqioYygpJRVF4BR2t6VJBgJtry+gpkYFFQYgIi8WCv2MlCQsUrCCcTqfC2CyUr1YrDhutmNl1UBRkMpn88HSYCsJgbNvGaDTiRrKZYyDRMM0iG6ut5vN5ZvnNxmLnj2hheXFxkQABvh8JdF1PzeqZIFFhkYOV0pqmwTAM5PN5bLdb7HY7fnZnOvv9HkTEq2EmlmVBURQA4OdzRVH4OIVCAbIs8wqZSRiGmM1mtwaPO93reJ7HjWRlNltmtm/z+bzQp1gsQpZl7ifL5RKSJOH4+FjQISI+OUSERqORqGzvIvfuYZomhsMhdF0X9m68ImAFqGma8DyPl+DR+M+2UvRMPxgMUCgUHh4EuIlS/X5fcMD4srMtGS+/o5HscDgIFxSu6/70DeYvXRl2Oh3Yti0cV6NiWZYAEvcZ4Ca31Gq1xIreVx70r7f1es2jXLlcfrD7YuAP/IcYhmEiMT6E/Lt/hj5WeQJ5bPIE8tjkCeSxyRPIY5O/BuQ/soiLzOgZW3AAAAAASUVORK5CYII="},
            {'Type': "textDeflateBottom", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAG7klEQVRoge1aIYzizhd+oqKiyVZUVFRUIBArEBUVKyoQJLcCQXJsgqhAIBBcQi4IRBPEiRUIBILkKsgFgUCsQCAQXEIu5IJAIFYgEOSCQFRUIL6/IDPLUNiF++3ebX6//5c02UxnOvPNzHvve48l/EtAf3sBr4X/LpHhcAgiwmQyefXFLBYLEBF6vd7FYy8m4vs+iAiLxeLiyV5CEAQgIvi+f/HYi4m0Wi0Qvd2NlGUZnuddPO7iFXmeB13XL57oXJim+WeIFItFmKZ58UTn4vr6Gq7rXjzuYiK5XA62bZ/d//HxEb1eD6vV6qz+juMgl8tduqzLiTiOg9vb27P6VioVSJIEIgIRoV6vvzjGdV04jnPpsi4nYts28vk8giBANpuFYRio1WqRfs1mkxPQNI3/3el0hH6VSgVEBMdxsNlsUC6XcX19/fZEmDHmcjm+OCLCcDjkfcIwhKqqUBSFt7fbbSiKglgshu12C+ApJrHHdV14ngfDMF6PSBiGmEwmCMNQaNd1Ha7rQpIkaJoGRVFARMK9rtfrICJ8+fJFGOt5HogI/X4fAFAoFEBEUBQFmqZBkiSUy+Wj7n2z2SAIgsuIzOdzxGIxfuTCACKoqgrbthEEAabTKSRJQjwe533u7u5wdXWFnz9/CmN//PgBIsLnz58B7DyUJEkYDocIggC2bUNVVRCRsIGTyQSqqkLTtJOKIkIkDEOYpikc+WAwAACsViveNp1O+RjLsoRdjMfjJz3bcDjkY03TFDZgOp3y7+8rh2Qyydv3+z9LpNFoCCSICJVKBQAwm81AREgmk8IYZi8A8OvXL1xdXeHjx49HJ9yHYRhIp9NCWyqVAhFhPp8DAJbLZWQ9Dw8PLxOxbRtEhFgsBsMwuBECT8Z5ePdd1+VEvn//DiLCp0+fXiSy/20GZl/7ToKIIMsy937H4oxAJAgCSJIEy7IQBAFXo2yyh4cHEBHG4/FJIp1OB0R0lsw4RoRdr3a7DeDJPTcaDWw2G5imCU3TnicyGo0EmwB297hYLAJ4Ur7Mfe4TkWUZAPDt2zcQEUql0otEVFU9KkdkWUaj0eDfliSJz8lE6+Pj42ki7XYbsiwLC90XcY1G46iPT6VSSCQSAJ5O7ZRe6vf7WC6XAHZGfHNzE+kTj8f5nMlkUjBw5nD2NztCpFarwbIsocM+Ec/zIobO+mQyGQBPdhSLxY4SyWQykGUZ0+kU5XL5qJJOpVIol8sAdpLoMARYloVms3maSLFYRDabjSySJTqu66JQKAjvWTJUrVYB7LwM01eH3mWz2fA4MZ/PuSEfBrpCocBP9BiRXC7HPelRIq7r8p1gEyuKwomk0+mIEbMT2D/q29tbHrGbzSZmsxlGoxEcx+EeKAxD7s4Pr4nnedwtHyNSrVb5DThKpFqtCrvIJASbyHGcCJFyuRyxm/F4LAjFw4ed3na7FZwJQ61W44t3XReqqnJZA+wM/tAETmqtfr8fEYSJRCJCJBaLCafIsFwukclkBJWgqio8zxPkx/39PQzDEByM7/s8eWOufT9+7b9/lshiseAijogwGo0ARNNQ5qFms9mp/XgR6/UasiwL8t73faiqCuBJaLKnUCig1+udRySdTnMXuq97FEXhRLbbLW5ubiIS43eQz+eRSCT4qbAgCOzyGk3TIMuyoLdeJMKCoq7rmM/nICIsl0us12sQEVKpFICdPUmSFAlMv4PZbAZJkrhHZCJxvV6j1+shFothMBjwlIGIIEnS80TYKfi+z70K8FQ8IyIkEgl+zK8Flocwfcduwng85qphMBgIJ3OSSBiGQhbHXCuwywn272oikYgkXf8EQRDwDWLPZDLhG7herwHs7JLZ7kki4/FYqPR1u10eeYfDIc8fTNN8k0rjarXi3zdNk7tcRVGE/Kfb7T5PpNlsQtd1bnT39/fcqDqdDs8Kn0s5/ymCIMBms4Ft23xDbduOFC0OKzICkVKpJEgU13W5ZvJ9/+wy0Gsgm83yuFEsFiOS5BACkVQqxeUzsAt2TJ22Wq2zi2yvgdVqhVarxed+yc0LRCzL4iV95m7Z1TrMQf4kptMpD5AAjjoZgYhpmlyO9Ho9KIrypnXec7HdbqGqKjf40WgU+Q1FIGIYBieSz+eRSqV+q3z5Fti3mXa7zRM5BoEIE4jb7RaapqFer/Nqxt+G7/vQdR1hGKJUKglXDThCpNvtwvd9WJb1V+3iECzFzeVy0HU9Uh8WiMiyDMuyoCjK0cL038bd3R2P+h8+fBDeRYz9WKXvvWA/R8rn88I7gUg8HhcU7nsEW+OzkZ0p369fv/7RxV2Cfr8PWZYjN0YgUq/XhQTnvWKz2UTaIjL+LQXhW+K/+y8c7xX/J/Le8K8h8j/0YgHdBTXJtgAAAABJRU5ErkJggg=="},
            {'Type': "textInflateTop", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGIklEQVRoge2ZLYwaWxTHjxgxbUYgEKRBjECMoAlNEIgVCMSmISkCgUCMQIygCUkRiGkyCWkQiE2DQDTpCMQKkpIGsaJpEJsGUYGoQKxAIEi7YtKMqBjxf4Kc++Yyw+7y3ts+3sue5Brumbn3d+6552Mg/E+E/u0N/FPyAHJs8gBybPIAcmzyAHJs8gBybPIAcmxyMMh4PMZkMrmPvQAAzs/PMR6PD37uYBAiguM4By90V3EcB0SHO8rBTyiKcu8giqIc/NzBILqu3zuIrusHP/eXQNrt9sEL3VVardbvAzFN8+CF7iqmaR4vyGazubPuUYJ4nodcLgciQj6fx/X19a3P/DaQTCYD0zQRBAHK5TKICJ1OJ1aX53lUq9WITqvVAhGhXC4jCAKYpgnDMO4fpFgswjRNvHv3TtrkbhL7/PkzHj16JOkQEb58+SJ0Pn36JM0NBgOYpolisfh7QMrlMgqFgrSJfD4v6XU6HRARdF1Hv99HNpsFEeHs7Ex6V/gduVwO5XL5nwUZj8fIZrOoVCoIgkBaPJ1Og4hwcnKCTqcDRVFARNIdYNDFYgEAmM/nwoWA7f1hAMdxUCqVQERIJpMRkPl8jkqlgn6/fxjI2dmZZKk4KyYSCfi+D2B7QYkI0+kUAPDr1y+oqorT01PpvZlMRvj/dDoFEaFSqQAAgiBAKpUCEUkgnuchkUiIvezLYRGQjx8/Rvz6xYsXYv709BREhGazKVmMiNDtdgEA3759AxGh1+tJ77YsC4lEAgDQ7XZBRJjNZmKe3TFsgF6vF9kPn/KNILVaDUSERqOBwWAATdOgaZpwr13rA9sTUBRFWHc2m4GIIlVyt9sVdVSj0YCiKOJUAeDy8hJEJIV3wzBEZGTQer1+M8hms4GiKJK1OTyuVisJZLlcSi/K5XIoFAoAANd1Y3Wurq6wXq8BANVqFblcTprfbDYSyPX1NYgIpVJJ2o+iKPA8bz/IdDqNKPGmwiBx1Wm9XheJjN2Bn4kTDuO7omma+J3v0WAwEPPr9RqKokgeEQHp9XrIZrOSArtJGCQu85qmiVQqBQB48+YNiAg/fvzYC8KJdVfClQMb8evXr5JOPp+PVOASSK1WE37OwknrNpBGoyEaotevX4OI8PPnz70gyWQStm3fCMInu1vaWJYlwngsyK6sVitx2ThSWJYVCxLu7O7S5e3rNHVdF3fUtm0QEebzuZTL4nqWvauNRiMpfnOYdBwHmUzmXkH4dw4snLeq1Spc1401ZmQ13/dRrVbFCzhrh0FuOxHOEd+/f/9bIPV6PZJDwuNGkLAVdF3HcDg8GOTt27e3Rq27noimaTg5OYGmaXcHWSwWQqnZbML3fRG1zs/PxYbjwq/jOCJr74ZslsvLS7iuiyAIoKpqLEj440Y4sARBgMVigeFwKIX6WBC+XMPhUPzGIK7rAgD6/T6ISMrIgBwEJpNJbNgcDAYgIqzXa+lSSxsiEsXhy5cv8eTJk4hOnEggxWIxcpF3Qdjau/VOoVAQBSGXGmGDANtTU1VVrLVb5XKNxmsd8o1L0spkMqjVapLCxcVFLMhoNJL0OKoA21Lk8ePHePXqlaRTr9fx7NkzANuclUwmpXlu1ngtziNXV1eS3ng8xsXFxX4QRVHQaDQkhWazGQsSTpzL5VJyCWBb7O3WUolEQlS27MbhTXJS5bU+fPgAIsL79++l9zx//hxPnz7dD5JOp6VOLwgCJJPJWBBFUcTXEYYN1z8cOrkCHo1GUqnP96jVagHYFoyqqkprcfMVNhrr7VYgEkihUICqqmKDfLHDkYRBNE2DYRiwbTu2Q+SwraqqCKPhAMCVrqqqsG1brB0GAbbuHjaSZVmR04+A8HGnUink83nRrRmGAcuyAGz9k3uCcEwPl9rAtgTnjfFIp9OSDre3PCqVSqSP4QvPxmP43fpLAlkul8K6fBLz+Vx8bAD+jGLsKjzi/mpot9uSzm6A4DKdB592uGv0fV+0wDziPj9FYpvrukilUjAMQ3zimUwmom9frVZwHAee56HdbkNV1b19tO/7KJVKN+rYtg1N09But+F5HhzHiSTS2Wwmsnuz2ZQKyL0g/1V5ADk2+QMXuYmGRHEj9gAAAABJRU5ErkJggg=="},
            {'Type': "textDeflateTop", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGcklEQVRoge1YLYziWhQ+ouIKRAWioqICUdFsKhBkg0AgECMQCLJBVCBWzCYjRiAQ3SBWIEawCWIEAoFYgRiBQJAsAjECgUCwSQUCgahAVCC+JybnTi8FdnZ35r15781JbsJtD/ee797z850S/iNC/7QBzyVvQF6bvAF5bfIG5LXJG5DXJm9AXpu8AXlt8v8Dsl6vX9KOo7JcLp+s+2Qgvu9jMBj8lkG/I6PRCI1G48n6CSCj0eiowd1uF7lc7s+s+wUpFArodruJ58PhEPf394nnCpDdbgchBIgI/X5fUez1erAs65nNPS2O46DX6ynPJpMJiAi2bSf0FSDj8RhEBCJCOp1GGIby3Wg0AtHflxvS6TRGo5HyzHVdad9isVDeKZbd3NxIRSLC5eWlfLdcLkFE2G63L2h+zDAiTCYTOR8MBoptt7e3qn588vHjRxARKpUKNE1DKpVCFEUAgCAIQEQIguDFQfBeq9VKPiuXy9A0DbZtJw45AcTzPOl/nU4HRIThcAgA2O/3IKKjgfbccn9/rxxaFEUQQsD3fURRBMMwUKlUTgMpFouo1WpynslklDkR4e7u7gUhPAgH9X6/B/CQqVKplJxXKhXk83nlP4kYaTabct5qtZQMYZpmIpO8hAwGA5imKef1el050GazmcigiTQUD7DpdAoiknFiWRZ8339uuxPS6XQUQ13XVWpbr9dTgAI/qexRFClxkc/n0Ww2Ua1W8eXLl+e0Hfv9Hr7vo16vw/d9FAoFAA+1TdM0JfB7vV6iFPy0MKTTaXkanudB13WZAq+urp4NSLVaVWoYA5lOp9B1XdH9LSCWZaHdbgN4ABLP5UQk3/2JfP36NbHuhw8fAADtdluCYmk2m78OpFAoyLjwfR9EhHw+j9lsBtu2oev6HxXJ3W4HXddh2zbG4zEKhYJy257nyUDfbDYol8sS7Fkg3W4XlmXJIYTA9fW1AoRry3q9hhDirIvNZjMMBgMMh8OjtLzT6UAIIdsEpkmtVgvAQ0loNpvodruKW58FslqtoGla4po9zwPw6JtxnuP7PoQQ2O12ysLT6VThRjz4UFgymYxyEEyFOM3bti2J7OE4CaTdbh/9AwO5u7sDESlN1nq9TrDl9XqNVCol/2+aJtLptJxziuf14gfD9ITXi6/Do1AoKGUiASQezJqmIZ/Pw3EclMtlecrH+FZcBwAajQaICIZhSCOjKMLFxYXi/9VqFZlMRlmLgUwmE4RhqAAoFouYTqc4JgoQDrRWqyUD+Pr6WmaNU8Tx6uoKQgg5Z5fiWGKZz+cgIlxcXAB4cJtDV+M9ptMpFouF1J/NZkcBHAWSzWbhuq6i4Pu+fMZudNgLdLtdha3quq4w57i0Wi2EYYjdbgciQqfTOQokCAIJ/ClEVQFiWZaMhziQOF0gokTDM5vNFEJJRMhms2c3ZoZ7uFacFjF5PIyHzWajVPoEECGEQhoZiKZpis5hU7PdbpXiSER4//79WSC3t7eJngMA+v2+dFO+ke/fvys6nz9/Ps+1iCjx5YJrB1PoU8SRiORzziznhNc9jLdWqyU9gG9kPB4rOtVqNRECChDDMFCtVhWFy8tLZcNcLpdoag6BvHv37qeudQqI53lwHAfAo5sdxpHrujJhHAViWVbik08ul1M2LJVKiWvl7pGBlEolGIZxFMBsNkMYhrIDPQRi27a8zdVqBSLCp0+f5PsfP35A1/Xzra5t24oB2+1WVlUOOK41cd/mNMlAuPc/rPasNxgMJEuYz+fyPWes+GkzD2PhjxA3NzengdRqNbkR8FAfDqsxu1q9Xpf/6/f7ypcNNvLYtzFmBvw73nGyu8UzZzablXphGMJxnMQBJIDwdWuaJv9gGIaSqXgzIYTM71wA41Vc13Ul4Pf7PVzXlafLGYmDNggCSUfimZMPl/ckokR/kgDCi8dHo9GA4ziSVrTbbei6DsuyoGkaTNOUgOPCN+d5HkajkaTf8RswDANEBMuykEqlYBgGTNNU3IZvOz7i/ftRIMAjTWGyF4YhyuUyisUiAODbt2/SoPjih99pwzBEJpNRdBzHkWkcePQAHu12G5qmKWCjKJLfsvhWDmvPUSDz+Ryu68I0TUnQxuOxPKUgCGRQe54HIQTq9bpiIMtyuUSxWIQQAqVSCZvNJqFTr9ehaRpqtZrs2w/9f7FYIJPJwDCMRNydBPJvlTcgr03+AiRA3AD+jIkcAAAAAElFTkSuQmCC"},
            {'Type': "textDeflateInflate", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAIWUlEQVRogeWaIYziWhSGr6ioQHQTkkUgmg0CUVFRgUCQzYhmM2IEAjGiAoFAVCCaDYIEMWJEBdnMJiMqViAQbEKyCAQCMQKBQIxgk2bTZCsQTRaBqPifIOe+3rYzb+Zldvdl30kqaG9v73fvPafn/IXhDzH2uwfwUvb/BVkul2CMYbvdvvhgttstGGNYLpfPvvfZIIvFAowx+L7/7If9k/m+/+tAPM/76SCe5z373n8NEgQBjscjVqsV7u/vc9seDgeMx2N0u12MRiNEUZTbZrVa4XA4/ByQu7s7eJ6H8XiMOI4zIKvVCoqigDEGxhja7bbQzvd9lEolKIqCer0OSZKgKArCMORtbNuGJElgjEGWZd53GiQIAkwmE8zn86eDBEGAarXKB8gYw/n5eQZEURS4rovtdgvHcYQBHI9H6LqOWq2G/X7PwWRZhm3bAIDpdArGGPr9PrbbLVzX5ROTBElPmKZpuSsrgNAAJElCt9uF4zgcarfbAQCGwyEYY3AcR+jIMAzoug4AWK/XYIxhsVgIbW5ubvh9pmlC0zTh+tXVFRhjuLq6AgDEcYxyuYxisYjRaIR+v49CoYCLi4vHQebzORhjuLu74+cmk4kQSQaDQa6zDwYDSJIEAPj48SMYY/j69WvmgWSlUomvDtl+vwdjDIPBAADw6dMnMMYwnU55m/F4LExsLojjOHxWyXa7XQZEUZTMwAgQAPr9Phhjgs8kLY5jMMYwHA4z18rlMgdJTk7SqtVq5l4BZLFYYLVa8d/L5RKGYWRAVFXNdG7bNkqlEgDAdd3cVfN9H+v1GsfjEZVKJbMiAFCv1zlIt9tFoVDAcDjEer3mE2NZFs7Ozh4GIbu7u0Oj0QBjDOVyWQDpdru5IPV6nXc+m83AGIPrukKby8tLMMaw3+/RarVQr9cz/SQBO52OEHQURUGr1YJpmpkxZEBub2/5TcPhkA+K9qRlWZBlGYfDgd9Dzp3cy7quQ1EUjMdj7HY7uK4LWZa5o5I/JkNqFEWQZRmWZQE4Ob8sy1gsFhgMBnx3MMZQLBYfBtntdpAkCWdnZzzej0YjYZtYlgXGGJrNJnzfx3Q6RalUQrPZFDr2fZ+vKh2mafJwTH0VCgVMp1P4vo92uw3GGAchx06mLJvNBv1+//EVsW0bqqrieDzyc7S8SZBKpSLEdsuyHnTsKIqwWq0QBEHm2uFwgG3bkGUZjDEUCgWUy2UOQitEPvOYCSCGYaDb7fLfYRjyh1C222w24TgOgiDAcrl8kZwrDEMsl0vsdjv0ej0OApwmTtd1YaJms1lmYgSQQqHAOzkcDjBNk2+l0WjEz/9sS+6IIAigKAosy8LxeEQcx9A0LfOaEECKxSIURcH19TU0TYNpmgCQeUP/aptOpzwnS27npAkg5+fngmP+itl/qm02G+i6ziNqeksLIL7vo9PpwPO8B533d9t2u82d4GfXI+v1WnhfvLSNRiMhu3iqPRuk0WjkZp8vZf+2/2eDNJtNNBqNZz/oqdZoNDKO/BR7NohlWT8VxDCMPwNEVdX/JshsNoNt208OEL8FZDKZoFarYTAY5IZrKrDooBKWLI5j2LYNTdMwmUx+PYiu61yoo+P6+lpo9/nzZ7x69Upo8/r1a2w2G96GRAs6ZrPZy4MEQQDP8/hMJUFUVeUihaZpXM5JSj1URHU6HYRhCNu2BeAgCHjaoWkaJEmCrutQVTUjbOz3eyyXS6H/J4F4niek6f1+n1+j2py0LeBUNTLGMB6PebtisQhN0/iWi+MYxWKR529UwFG2vV6vOVgybQ/DkCs5VKg9CYQqt3SJSQMikGQhFUURJElCp9MB8Lf0mZwAAGi1WryupyIqmW7QKiZBLi4uhLFIkoT1ev04CIkCqqryYp86p5sJJK0G1mo1rlNtNptMGQucdK12uw3g9OJLp+IkPRHI4XCALMswDINLqpVKBYZhPA5Cq5HUjMip07pWWu/t9Xool8sAgC9fvvzjp4dqtZpx6vv7+1xdK+mnq9VKmNhckMFgkFH/0lJ/Ur9K30vnaQDfvn17EERRlMzWAyCAUJ9piVTTtMd1rfF4nHGmm5ubJ4GQSLHf77mulafRAqctnBey0yCdTidXDCRJ6EGQpC0WC0EFoSqR9Nm0Jb+bPARL9tjng3K5zM+3Wi0u/ZimCcdxMJ/P0e12Ua1WHwcJw1AAoNBHndOA00bhNIoifPjwAYwxfP/+PReEJNO0gJcGSctJyYP8MRfkeDzygZdKJbiuy7XfNEh62+T5SLoc3e/3XFhQFCVX5kk+6/z8HLquYz6fw3VdtNttGIaBQqGQmUzhF+1t27b5QNPbgEDSUYvSDeDvD6bJdAQ4+Zssy4iiCKqqotfrCdfDMBSeRVlEnqUjogBSr9cze4/eCZTwEUg6m03qsXRPeus4jsOlzkajgVqtJlyn8J8ESUujD1lGDkrHdopatA0IJKmkH49HQRMDTt8/0pGFvmIBJ0eWZVnQsCjVIRDaIel3xuXlZaYcFkDevHmDd+/e8d8/fvzA27dvwRjD+/fvBZBkkkgPTEYhyggoH6PtRu8O6ofeByTEJV+A5J/JSYuiCIqiPB5+G40GJEmC53mIoojXE7Is84yUvv2pqopSqcTV+XT2S+mGLMswTZMPkrKG/X7P72u324KenBStKbu+urrCZrPh2tvNzc3DIBRtkke/30ej0eAfRGlmk1lwcmaTdnZ2JrS5vLwUrvd6PeE69ZkEWSwWGZUxmVXnggCnqk5RFJTLZf7mvb295RHm/v4elmUhDEO0221Bl02b7/toNpt8VdLCWhzH/NOCbdsIwxCWZWUi4u3tLSqVCv++kleX/H//VPNftT8G5C+JKlIcDg8DmAAAAABJRU5ErkJggg=="},
            {'Type': "textDeflateInflateDeflate", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAI8klEQVRoge2ZL5DiyhbGW0REREREICIiIiIQEQgEAhExAoEYgUBEIBAIBAKBoAqBiEBEjKC2EAgEW4WIQEREIKjaCARbNYK6FYFAREREICK+K6a6H53A7J83e/fV3XeqRkwS0ufX6XP6O6cJ/iVGfrcDH2V/LkgQBCCE4HA4fLgz9N1BEPzwb38aJIqiHx7sW3Y4HH4PSBRFWK/XCMMQWZYVno3jGJ7nYTabIQgCXK/XwjOvr6/YbDZ4fX1FFEUfB5KmKUajESzLgqZpqNfrcF23ANLpdCCKIiqVCgRBgK7r3HLzfR+SJMEwDAyHQ9TrdUiShNfXVwDA5XKBYRgQBIG9o91uF0CiKEK73UalUkGtVsN0Or07aRxIHMcwDAOmacJxHLiuC8uyQAjBbrcDACwWCxBCUKlUcD6f2e90XUelUgEAJEkCQRAwHA65wVqtFrrdLgCgXq9DURTEcczAarUaB3I+nyHLMgzDwGg0guu60HUd9Xq98HU5EMdxIIoiLpcLu3Y+n0EIwWKx4EDm8zn3osFgAEII4jjG58+fQQjBly9fCjMHAFmWQRRF2LbNXafvpmP1ej3IssxgKbAoipjNZo9BjscjWx5pmmK73aLb7d4FuYUFANd1QQjB+XzGfD5/NyEkSQJCCKbTKXc9jmNuLMuyoKoqHMfBZrPB8XjE9XpFs9mEYRiPQYC3zNFsNiGKIlRVxXA4vAsShiH3u1qtBkmSAABhGIIQgs1mwz0zHA5RqVSQZRnK5TJqtdo3QRRFYY4TQiAIAmRZhiiKj0H2+z0EQUCj0cB+v2dg90D6/T6At2VCr90mhU6nA1mW0el0sF6vMR6PubhZr9cQBAGLxYIF72g04sbq9/sQRRFpmgJ4WyVhGMJ1XRZrd0FqtRrq9XphFgkhcByHAzFNE7quQ9M0qKrKBr81z/PQ6/Vg2za63S48z+Pur9dr9g7TNNms03e9vr5CEARugujkUri7ILIss8+dJAmGwyFM00SpVEK73QYA7HY7DIdDZFmGIAgKS+xn7Hg8sn1mPB6zDAm8JSBBENDv93E6nRAEAURRxNPT02OQXq8HQgg0TYMsy2i320jTFMfjsTAD/6RtNhtUKhUQQkAIgSRJhUTCgVwuF0ynU8xms18iQf5bo18knzGBn5Ao+/0ejUbjQxzL2+VyQaPR4JbW99oPg9Bg/xVGtda9xPEt+z/Ir7DfBnI6neC67sMUnKYpptMpbNuG67p3ZXwQBJjNZjifz8iy7GNBjscjptMpOp0OJpMJJ9ooiO/7EASBpcTJZFKAKJfL7D5VzLcS3HEcdk8QBHiedxfE8zwMBgOMRqOHlWkBhO7kVM8QQqDrOnOAgiiKgqenJziOA03TQAhhsgZ4kxeEELTbbXiexyQ6dTJJEsiyDF3X4TgOms0mJEkqgEwmExBCUCqVoCgKCCEF5VsAWa/XIIRguVwiyzJWZNEvcAtiWRaDOx6PbPelpigK9wWu1yskSWI7MgWlhVaWZaz2oSBUsjebTfYe+hW32+1jkOVyWSiG8gFIQfLK1rIsJq1pDZOfuW63y/agarVaUL+bzYYbazabcUUdNdM0Ua1WH4NQy7IMp9MJvu+zmftWPTIej5m03u12dx24NVVVMRqNuGvX65Ubq9PpQJIkBEGAIAiw2WywWCzw9PTESoa7IJfLBc1mkwvQ/Lp9lH5fXl5ACEGapvj06RMIIfj69etdCJqdxuNx4Z4kSWysvC80Kei6/r5opA2C8XiMzWaDw+GA0+n0XSD0ehRFGI/H71aIdOnlMx0AaJrGxmo0GtA0Db7v43A4cNkzb5xHt3Kdmu/73wVCswvwn6/z119/PRxYEITC0gJwt2bPW7vdLug9zqN+vw9d17mNi0r7PAjNNtQGgwEblO4Hp9OJe2a322EwGCBJEhiGUZi0fKODBvtte2i73d7tdHIg5/MZ1WqVBSJtPNwDyTcOdF1nmSRfHlOjCSHLMjQaDaiqyt2njuf3mlKphNFoxHpp92KrsEayLIPjOKjVaqhWq9hut1BVlTm+WCxYA4B+ldVqBUIIXl5eOLDbsjnLMui6zlLudDrlfhNFEUqlUmECPM9jG6FhGNym+y7IPZvP5wzEdV1omgbbtiEIAsrlMgRBQKlUQpIk7DfUUdu2sd1uWQai+8/lckGpVIIgCDBNE6Io4vn5+Z8TjVEUwfM8JEnCnNN1vRAzWZYxWUL/np+fuWf2+z2TN81mE3EcY7Va3a0APxwkb+/V8mma4uXlhanfez1bAO+m1e+1P/egh7ZRf4UlSYJut1sQhN9jP11Y/Youy4dViLcBTLuJk8mEi4PfAeL7PpP4tFzIx1vhWIGKOd/3MRwOIcsyTNMsFFb7/R6TyYTpskeBnGXZu9C73Q6TyQSTyYQdIt2C0E6jbdvwfZ/VR7SFexfkeDxymxqdjdv8T0EkSYJlWej3+1AUBaZpcg7THpUkSSiVSpBlGc/Pz1xDulqtQlEU9Pt9WJbFKlIKEoYhBEHAcrnkfKpWq9B1/TEItSiKEIYhgiBgVeN7EuV6vaJarcKyLPa/qqqo1+tME8VxDE3T0Gq1ALxJdFVVOV1H300dt22bKYggCLBcLjGdTtkm/BAkDEOoqsptYqZpfpdopIc7SZKwwiovJ5IkwfV6ZSdWt6UxvX8rEm/7vYqiwDAM1Ot1tFotDAaDxyDVapXpf7pJpWnKla1UfdLzw/xsRlHEoPKw1KjKzR/f0bFuQcrlcuH3dEIegtB1fGu0jqaKkwZk/qyDHuTcwuZr9vV6jV6vhyzLoKoqms0md5/GIwWxbRuEEByPR/bM9XqFruswTfMxSKvVgiiKmM/nOBwOmM/nkGWZK4IoSKlUQhAESNMU6/Wak9dZlrGDG8/zcL1esdvtIMsyg3Ndlx1qXi4XrFYr6LrOgURRBFEUYZomPM+D53loNBp3mx+FeqTf70NVVda6CcMQnU6HVWRU6M3ncxZP9MDyNgXHcYxOpwNFUSAIwt0z8vl8zuJAVVXMZjNomsbF1uFwYOeThBCUy2WsVivk7c/VWv+r9q8B+Rs10Wlx1IHHdwAAAABJRU5ErkJggg=="},
            {'Type': "textFadeRight", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAFs0lEQVRoge2aL2zbThTHHzAwMAgwMDAwCAiIJoOAgAIDg4IAA0vbpABrKgiwtICCggBLAQUFAQMB1RZQUE0BBgWVNmAwTQXZVBCQaQEBAQEFBgUBlvb9genu58s5XdulW/T75UkH6r7787m79973qhL+I0Z/ewGbsh3IttkOZNvswSDj8Rjdbhdpmj7Feh5tDwZJkgREhCRJnmA5j7cdyA7kiWwHsgN5ItsqkCRJYNs2JpPJg/sWghwdHUFRFFQqFVxdXUmTPSXIY8eWQC4vL0FEvCmKgul0WjjZZDJBt9vFbDb7nfUXjv1Qk0BevnwpgBARXr9+LU12eXmJcrkMIoJlWRuRLBsDub29haqqEoiqqsiyTJis2WwKPmEYSoOPRiMYhgFVVXF4ePjnQEajEYgIlUoF4/EYg8GAg7EAZJNpmiaAaJqG5XLJx8qyjJ8Ya8fHx8LkaZqi1WrB8zxMJpPNgQwGAxARzs/P+bd2u82vUh6EiBAEAebzOWq1muADAOfn59xP13V+sre3t9zHcRxhI87OztaCzGYzoe+dIFEUgYiwWCz4N7bwN2/eSCAsyC8uLkBE6Ha7vF8QBCAi9Pt9AECn0wER4ezsDADw6dMnDuC6LhRFgWVZEshkMoFhGHwjwjDk13wtSBiG0HVdcEjTFESEKIoEkHq9Lvjpug7P8/jPlmWhUqnwSVn8tVotAD9TPBHh4uICgJgt8yCWZUFRFBwcHKDZbEJRFPi+fzdIEASwbVt2KgBhC2K2v78P0zQBAMvlsjABuK7LN8B1XVSrVWmMPMjHjx+F2wD8e2XjOF4PkqYphsPhvUB6vZ7gw2IJ+HkdiAinp6eCz9HREYezLEvajF6vJ4CEYYhSqSQkEdZ3b29vPcg6KwLJBzYA9Pt9Hl/smtyVfUqlkgS6mrVc10WtVpP6BkEAwzAeBsKCchXkw4cPgt/bt29BRPj+/Ts//i9fvhSOmWUZiAiDwUD4zk6SgVSrVaiqyuNktb7dCyRNU0RRxOvFKsjnz58F//fv34OI8PXrV7x79w5EhG/fvhWOPZvNCkHYdwZimiaICKZpolarodFooNVqIYoiqW8hyHA45LmftVWQvP7Kf0+ShNej+Xz+WyDPnj3D8+fPC8dYNQnk6upKOsIikFWhWASyTkyuA1m9Wo7jwHEcqb/jOL8Odtu2BYDDw8N7gbCiOJ1OOci6dwUDWZUsLN0ykCAIoKoqbm5uuM/19fWv0y9zYvKd5e8ikOvra2Gg/CkMh8NCnziO0Wg0eLC3223h98fHxwIIG8fzPEynU8RxDNM0US6Xpc0RQE5OTjhEvp4Ugaym1nxcrPPpdDpcOZTLZan47u3tCf2yLOPyhDXTNAtPWgBh0jxfSe8LwnYz77M6ju/7vC74vi+cWl7D5ceez+fwfR++76PX60nFsRDEcRxJoa4DYeKP2YsXL1AqlQAAi8UCRISDgwPBxzAMNJtNAOBKl1V4TdPged5mZLxt21I2uLm5uZdEsW0b+/v7/OdyuQzDMPimrGqk5XIpvFc0TcN4PEan0xGC+1EglmVJypKlxLtEY5qmUFUVnU6Hf2My3vM89Ho9aJomPb5GoxFs20a9Xsd4PH7w4teCqKoqXYfT09NCEMuyuERnYi+fEvMPK9by75VNGwf58eMHSqUSXr16JTiwBMBSZT4o+/0+f/goiiJciSzLUK1WuW+tVlsbqBsFAX5erfzjKMsyrrWY/GYgq3+kcF1XGnyxWCAMQ0RR9KQQEkilUhHkMStIiqIgCAIBhD2CWFuttH/aBBDXdYUrY1kWdF1HvV7nO85A4jjmEPls9bdMAGGvvHxrt9toNBpcFiRJAl3XsVgsEMfxnUXqT5oAwopUXm9Np1MEQcBBlstl4V8x/rYJIPP5XAhiFuDr3hXbZJKMPzk5gaIocF13K67Mfe3/+w8D22o7kG2zfwDRbvJQmsnd7AAAAABJRU5ErkJggg=="},
            {'Type': "textFadeLeft", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGIklEQVRoge2YP2gTbxjHn+EVMmSIeMNBg97QIUiGUDIECfaQDC0KHhgkYpEDO2TIkEE0Q4aDDA4dOmQIWiVCBcEOHTJ0yJAhYAfBKB1uCJKh4A2FFjzwlBu+v6G813vvTf/YX22r9IEb8v558n7e93mfPy/hHxE66wWclFyAnDe5ADlvcq5AdnZ20Gg0YNv2b889VyC9Xg9EhF6v99tzL0D+hFyA4ALkz8gFCI4BYts2MpnMsf7sMDkMZGdnZ9+5vw3yf3btuLodx0E6nQYRYXFxcezcMwdxHAfPnz+Hbdv76jYMA0QEIgJjDMPhUNJzKiC2bcN1XanddV1omgYiQjKZRLfblXRvbGwEEPyr1WqnC+K6LmZmZkBEiMfjWF9fF/prtZqwwEqlIumu1+sSSDKZPFmQ4XAI0zRhWRa2trakscViUViApmlBn+/7UBRF6I/H4xJIKpUK7kav10MikQARYTQaHQ3EdV30ej1pAgdZXV0VFlIsFoVxg8Eg6Eun04jFYiAi9Pt9AMDa2hqICLlcDpubm5ibmwvGcxDP80BEyGQygd5qtQoiwsrKysEgrutifn4+2B0iQqlUkkDS6TQYYygUCsEiwzvJzcayLADA8vIyiAj1eh0A0Gg0QERYW1sDsHvpGWOCHr4ZYU/F27iesSCe5yGfz4OIYBgGKpVKsOvcvjlIeFdWVlakS5jL5aBpGjzPA7BnSvzkDMOAqqrCYvh94iCvX78GEaHb7QZjfv78iYmJCTx69Gh/kNXVVenY+v0+iAgLCwsCSD6fFxSlUinkcjkAwPb2NhKJBCqVijDm3r17uHHjRgA6MzMj9HOz4SBPnjwBEUkeL5vNBv81FqTVaknKAQgmwkH4by7lchmMMQC77paIsLS0JIyxLCswCU3TUK1Whf5WqyWAmKYpOAgupVJJaj/Ua3GbjIKEjzu8CMdx0Ol0DnXRiqJIoFHXfvfuXUxNTUlzHz9+jImJiYNBBoMBqtUqdF0XvFIUhHsfLu12O3CLb9++BRHh06dPYyE8z0MsFsOLFy+E9vX1dQFE13Xoui7N5ya4LwjfSe7TC4UCLMsaCxJ1y9yd9vt9vHz5EkQ0NpUAgG/fvoGI8ObNG6H9y5cvAkgul4OqqjBNE+VyGZZlwbIs6Lp+MEgmk4GiKFIEPgpI2CyWlpZARNjc3BwLMhqNQERot9tj2znI9evXpage/n78+DEeJB6PY25uTlDuOM5YkKj98zgxHA7x6tUrEBG+fv06FmQ4HIKIsLy8fCDI1atXDwT5/v37eJB8Po/JyUlBOTe3KEin0xHGhe/I+/fvQUT4/PnzWJCjnkgymTwQJCzSHWGMoVgswrZtdLtdqKoaJHRhkGhdwCO553lHSiyPAqJpGnRdR7vdhmVZmJ+fx507d5DNZqVgKnmt8OKJCKlUCpqmwTRNASSc/wC7F1NRFAB7QTSaDzWbzUAPY0yKRdzkOMjU1JSUw+27MeMaHcdBq9XC4uIiPM9DsVgMIjkHYYwFCx0MBmCMBYscjUa4fPkynj17Juh9+vQprly5gl+/fkHTNKmuiJ7k9PQ0Zmdnjw8SlcFgIN0R0zTBGEO5XA6Ko/AJZLNZKQYYhhHcwXQ6DcMwhP5oIL19+zZu3rx5ciBh2draQr1ex3A4DGoDng3zBBHYC1qDwQDAbtKYSCQCuEKhgFQqJeheWFiQUpSoCZ8YSFhs20Yul0OhUJCCH78nmUwGHz9+DCo9nmtx5xAuyEzTFEAqlQpisRh83xd012o1ydn80Xethw8fSi6T1x88E+BZte/7gYlykGazCSLChw8fBL2zs7O4du3a6YFsbGwIBVrYTFzXRSwWg6qqsG07SDrDIDz3irppRVGQzWZPDwTYMz9d16WUpVQqCacVrRBHoxEuXbqEBw8eBHO4yd6/f/90QQ6ScLXJi7VoIFVVFYyxILfjSWy0ljnzt9/w49u7d+8kEP4ooWkaGo1G8D4QNbczB/F9H81mE51OB47jQFVVAYSX39HPcRxBz5mDRMX3fSEebW9v49atWwLE9PS0NO/cgYwTnsxykGgOB/wlIMAujGEYQdyJyl8DcphcgJw3+WdA/gNJA/iefPxbBwAAAABJRU5ErkJggg=="},
            {'Type': "textFadeUp", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAIE0lEQVRoge2ZL4zizBvHJ5eKiooKLmnuEE0OsWIFuSDIBVGxuSAQCMQm10sQ5IJAkAsCgeCCQCAqECsQTQ6BQCDIhksQFSSHQCBIDrECsQJBLhUVzaXi+woyz3WW5Zbdt/v+/uR9kiZLZzrTz3Tmeb7Pswz/J8b+0y8Qlf0LcsxWqxWGw+HR9vF4jMViEfW00YMMh0Msl8uj7ZvNBldXV1FPGz1Io9GA7/t/7FOv16OeNnqQarX6YJ9KpRL1tNGDlMvlSPo81iIF2e12qNVqD/ZrtVq4ubmJcupoQabTKfr9/oP9RqMRRqNRlFNHC2JZFubz+YP9VqsVGo1GlFNHC2KaJjzPe7BfEAS4vLyMcupoQXK53Ml9s9lslFNHBxIEAfL5/Mn9C4UCXNeNavq/B9LtdjEYDAAAy+USlUoFlmVhu91Sn81mg2azSb93ux0sy0K73cZsNgOwPzPhPk+xJ4OMRiMwxlAsFgEAtm2jXq9DkiR0u13qV6vVwBgjdzscDiFJEtrtNizLAgC0220wxmhR/jEQ3/eh67oAUq1WkcvlwBgTInc8HgdjDO12GwDQbDbBGEMul0OpVBJA4vH4g/ImUhDLssAYE0AuLi6gaRoYY+SRfvz4AUmShHulUoleOp1OAwB6vR6Nx7/Ss4P4vg9N05BMJoXV1zQNkiRBVVUYhgHg9/ZLJBJIJBIAgMvLS8RiMSiKAkVREAQBhsOh0C8IgucH6ff7yGQyAIBMJgPLsnB7ewvGGGq1GizLIpBOpwPDMLDZbMAYg+d5MAwDjUYDnU4HjDGsVivMZjMwxhAEAVKp1JOi/qNB0uk0HMchEMdxMB6PwRjDer1Gv98nkHK5TGdD0zQsl0sYhgHbtgl+MBgQKAA4jkML9Wwgq9UKyWSSfmuaBtd10W636b7jOASSyWQwnU4B7APgZDKBYRjCQtRqNQRBAMYYxZV0Oo3VavV8IJVKhbI713Vp3xcKBUqWwiC6rlNMKZfLsG1bAOl0OqQGdF2nzNK27UfnLCeD8EO+2+0AAJPJBIVCAQBwdnaGyWRyACJJEj3farXQbDYFkPV6jVgsBmDv9fjZ4O79Ma74UV8kfAibzSYsy4LneZAkicQiB9lut9B1nfoPh0PM53OYpkkgAKCqKna7HSqVCp0nYP/1bdt+HpCwGYaB2WyGxWKBVCpF9x3HgWmaWCwWFCfCViwWhQiey+UwHo/R7XbpCwPAbDa79/lj9iSQ9XoNRVHgeR663a6Quvb7fRSLRWGL3QXp9Xr0m7tix3FwdnYm9I3H4ycf+keDzOdzCojAfguEtdXV1RVti/tkfa1WEwTiaDTC5eUlXNcFYwy2bdOVyWROTsBOBvE8D5VKhaQE9yrpdJpULLA/O81mE71ej+RL2JrNplBp2Ww2OD8/BwC8ffuWxufXu3fv8OvXr2hAgiBAJpMRJuDVRL7FuJVKJYK5D6TT6RzcV1UVvu/j48ePByCMMXz79i0akGq1SoPGYjEwxrDZbLBerymWcCsUCuj1eqjX6/fGAh5LwpZKpbBYLEi23L1O2V4PgqxWK1KwZ2dnGI/H5PuHw+FBVphKpTAYDFAsFu9Nlsbj8QG8aZro9Xq4vr6+F+QUyfIgSD6fB2MMhmHAdV1YlkWHuNFoHJQ/NU2D4zhHQRaLhRAogd/nxvd9yLL8pCL3H0Fubm4gSRJKpRJJ63w+j1arRX+H61i+75N4PAbCxeLt7S3dCytqwzCEwBgJSKVSQSKRIKkQBAFUVSUhGI/HhTrWzc0Nib9cLncAwsdhjAnRfTabQVVVACAZExmI7/tQVVX4X8d8Pqe8gvv98MpOp1M6P4ZhHIAkk0mKQ2H5sd1uyYE4jgNZlk+qj50EYts2YrGYINwajYYg13kOwa3T6ZBcMQyDcnJuuq5ToLtbtWeMYTQaIQgCKIqC8Xh8MPZ6vX48SDqdPnCf5+fn9HKWZSEejwvt+XyecvNsNnsQL3RdR7/fx6dPn/D+/Xuh7fXr1/jy5QuNE9ZdwN6z/cl73QvCPUtY3F1fX+PFixckR0zTFNQtsA9s/KAWi0VcXFwI7bIsw3EctNttyLIs5Oa6rpMr7/f7kCSJUgZgv3A8xz8Z5OrqivYsN9M0wRij5CeRSAggq9WKtgewdxRhEcjPgeM4VJQIOwpd1ym+eJ4HWZbR6XSofTqdCvOfBPLhwwe8efOGNM5kMoGmaYjH4/j58yc8zwNjDIqi0DO8EMczQl6/4s6AFxjm8zk5inDElmWZHAmwVwg8lQZ+n8mwQH0QRFEUOrRhncX3KH8pvkKe50FVVeEL9Pt9YeK7oMlkEpqmwfd9Kj4wxkiATiYTMMYoReAFjmP/7ToA4QFLVVVKkrjG4p6m2+2SbMlmswQanoTDKoqCWq1GdSxu9XodjDGkUil6XpZlYcUTiQQYY8jn87i4uBAKfQ+C8E8YvkzTRCwWoz1bLpcP1PDdPX97e4tXr14J7eGMb71eHzyfzWaFxeh2uwd97nq7oyB8S/BLURQsl0uhyJxKpVCr1WhfM8aEMhE3wzCEse7qsnC7LMtotVpC2hwEAc7Pz4UxjkX9A5DFYkEPSZKEyWRCX4mvuKIoGAwGwle5G8AA4OvXr9T+8uVLfP/+XWhfLpe0RTOZDIbDobD9gL3b51uMMYbPnz+fBuK6LjKZDDRNo5fbbrdwHAe+78P3fTiOA9d1MRqN6Awcs2q1CkmSjuYUvV4PqqpiPB7DdV2aJ2zz+Zzqwo9yv/+L9i/If5v9BWGRdKF0A6I0AAAAAElFTkSuQmCC"},
            {'Type': "textFadeDown", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAHrUlEQVRogeWaIYziWhfHr0A0mwoEogKBqECMGFHBJogKNotAVCAQJFuBQCCaLNkdQbJNECMqEBUIRMUIJovoJgg2O4JkyYZMEBWIiooKNukkiCZTgaj4P0E4u53ZN99Mh9335b2TVEwP515+veee8+9lGP4lxv7pL3As+++CXF9fgzGGjx8/Hv3LfP78GYwxXF9fPzk21YpwHAfDMNKEPmimaYLjuFSxqUAkSYKqqqkmfMg0TYMkSaliU4G0Wq3UEz5klUoFrVYrVWwqENM0wfN8qgkfsnw+D9M0U8WmAlksFmCMYbPZpJr0VxaGIRhjWCwWqeJTgRwmvbq6SjXpr+zq6gqMMYRhmCo+dR8RRRGDwSBt+D0bDocQRTF1fGoQRVHQbrdTT3zXOp0OFEVJHZ8aRNd1lEql1BPftWq1Cl3XU8enBrFtG7lcLvXEdy2Xy8G27dTxjwKxLAuNRgOO49A9z/PAGEMQBLAsC+fn57+MdRwHnU4Hvu/f8xmGAcuyEEURGGPwPI98URRB07S/HffJINvtFplMBowx8DyfmCybzWI+n0MQBDDGcHFxkYi9ubnBq1evwBjDmzdvEr7xeAzGGI2RzWYTfkVRwBhDJpM5DshyuQRjjK5arUa+crmMXq9HPlEUEccx+afTKfkymQy22y35CoUC+TRNQ7lcJp9t24k5f7WaTwZZrVaJQRljmM/nAIButwtZlhO+n3vL27dvE75Pnz4B+NFQD9fp6Sk6nQ4A4Pb2Fq9fv074gyB4PkgQBJQCpVIJjDE0m00AwGQyobQ7pFe326XY09NTWinGGMmPbrcLxhiKxSKNPRqNAPxYjWKxCJ7nj5dawL6i9Ho9AHvByPM84jiG67pgjCGXyyGKIsiynBCT+Xwe9XodcRwjl8tB0zQA+5SUJAlxHNMDWK1WAPZ7o1gsIooiNBoNnJ6eHg+kVqvRkw6CABzHUXrxPE+TXVxcIJPJYLfb7QdnDJZlAQAajQZJf57naQUOqbnb7bDdbsFxHKWnqqq0+kcBOT8/T2zyRqNBKyRJEmRZBrAvmZlMBo7jUEq6rktjqKoKz/OQyWQQRREAoNls4uTkBAAwGo0Sm75erz9aDT8KxHGcRPObTCbU1TudDoEAQKlUwng8hu/7YOzH8JZlQVVVTKfThCJQVRX1eh3APq2GwyH5RFFM9K5ngwCAIAhUBqMoAsdxiKIIpmkm8ljTNPR6Pfi+j3w+fw9kMBhQhQL2aWsYBqIoQjabJfUbhiHtxaOC+L6faIalUgmLxQLL5RKFQoHuj0YjqKoK3/cT9yeTCWzbRqfTSaRLuVzGdDrFbDZDtVql+7PZLJHORwO5a2dnZxgMBoiiKPG2uFwuUalU4Pv+L0VltVrFbDajvwuFArbbLTRNSxxodLtdKgiPsdQgg8EAjUYDAFAsFqlpBUGAk5MT+L6f2DsHE0WRCsChLAP7nrNer+lzJycnT3oDTf2GKAgCBEEAsK8uy+WS/Pl8/m9XJJfLUXl2XRfVahVhGILjOFiWBcuyMBwOH90/ngWiqirJB8/z0O/3E4JRFEWEYZjYIz+DHMy2bXS7XVxeXt6TQR8+fPi9IHEcJyYcj8eYTqeJlyJZlu9tdgDYbDaJJ20YBi4uLvD+/ft7IF++fPm9IIf+cNBImqZhs9kkOrCqqveqGQCs1+tEJWq321iv16ThDtfPZfu3gex2O5rQNE3qxJVKhT7T7XYxn8+pYx9sPp8nTigrlQqCICC9dbjevXv3+0GA/R4QBAFxHJP4+/lJH/bM3VMR27ZJ2gD7FHQc59F66iFLBdJsNqk7t9ttOI4DTdOoYR6qz93KY1kW9Qrf99FqtWCa5lGOlVKBWJZFR0GWZcE0TViWhclkAgC0+WVZJokRxzHOz89JDdu2jcFggFarlfp08dkg2+2W5ITrumg2m3Ach6T+YrGArutoNBqkzzqdDnRdJ4ne7/cxn88hSRIp4T8OAuw36qGxSZKE3W5HcL7vo91uo9VqEUilUoGu6/QeoygKwjCkYhHH8b3Diz8C0u/36enWajUEQUBfyvd9qKoKXdcpbWq1GlqtFikASZLgui7JnKurq0Qh+GMgruvSbxlnZ2ewbRvNZhPr9ZpAhsMhCURFUUgVe54HRVFg2zadWzWbzYS6/mMgwL587nY7jEYjUq/D4ZBAptMpRqMRdrsdarUagViWhV6vB8MwYNs2wjBM9KE/DmIYBsbjMebzOUqlEmazGW1wVVWpLLuui3a7TSDNZhOTyQStVgur1QqmaT5Jsh8dZLPZQFEU+L4PjuPw/ft38DwP13WhqipVt/F4TO/sq9UKuVwOnuehXC7D87yjVK5n/85+eFXleR6LxQL5fB6yLJMU4TgOpVIJk8kEqqpCkiQ6HhUEAbIs0zHRc+zZIIdj0WKxSE+dMUYgL1++BGMM3759I1+tVsPt7S1evHiBbDaLr1+//vMgwF57iaKIs7Mz6LqOYrFIIPV6HYwxRFEEVVUhCAJ0XScV/Zwfd362o4BYloVCoYB+v4/Ly0soikKl2TAMUsG6rqNWq8E0TQJ57HHP/7KjgBzUbxAEuLm5wWKxICHoOA7pskNfCcMQm80mcU78XPvv/lPN/6v9a0D+Aj2lePye0dmuAAAAAElFTkSuQmCC"},
            {'Type': "textSlantUp", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAE8UlEQVRoge2YL3DqShTGj1gRERGxIgIRgUBUVFREIBCICAQCgahAVFREVFQgKphBICoqKiIrIioQFRWIiAgEAoGoiEAgEBERKyIQiO+KO9nHkvTPu49C3p1+M53pbs9u97d7zp6zIfwlolMv4FD6ASmbfkDKph+Qsql0IMvlEqvV6l+PKxXIfD4HYwxhGL5rE8dxYX+pQMIwBBEVgkwmE5imCSJCo9HAZrNR/v6/ABmPx2CMgYjkj+d5ik3pQeI4hmEY6Ha7EEJgNptB0zScn58rY0sP0u12cXZ2hu12K/va7TYqlYoyttQgaZqCMQbf9xU713VBpC69FCCe5+Hq6gqPj48KyHg8BhFhuVwCANbrNXq9HhhjYIwpc5wcpNfrKUG8C+K6LjjnEELg7u4OmqaBiNBsNjGfz5V5TgrieR6ICP1+H77vQ9d1BcRxHJimKa/dWq2GyWRSONdJQarVKm5ubmT77u5OATk/PwcRgXMOz/NkwIdhiF6vp8x1FJA0TTEejxV3mE6n0HUdQgjZFwSBAlKpVFCv15GmqTJfo9FQNgA4AkgYhtI1dhd5dXUFx3EU2+VyqdhYloVms6nYxHEMxhim06nS/0cgz8/PeHt7+9RusVhA13WYpolarQYiQrfbBfDbbe7v7xX71WqlgDQaDViWpeSQXq+XyyF/BPJRPbQv27Zh2zaSJMF2u8XZ2RkajQYAgHOOp6enD0GyG200GiFNU5k/Hh4ejgeyWCzAGEMURbIvCAJsNhtsNhsQUQ5kNpspc08mk9zVnJ3owUGEEAiCIPeGuL6+RqfTKZwj2/n9jP309FRYohARDMPAcDhU3OxgIFEUyUDWdV0JQE3TchVqpvV6DSLC4+Oj0p+50v5pv/cGOQhIEASoVqvgnMMwDBCRPIEkST51P8YYXNdVFptl7q/E38FAOp0ObNtGmqYQQsCyLFn/zOdzEFHO3dI0le6UbYIQAmmaot1uo91ugzGGxWJxPBAiUv5hlpVXqxVeXl4KQQaDAUzTBPCP71cqFXDOoes6lsulLBAPCrLdbhEEgbLgDGQ/mWWBOp/P5e/7IM1mU457e3uTtdV+fB0UZDKZgHMudz/bqQxkNBrl7IkI0+lUguwubrvdQtd1JcCjKILv+1iv1/8J4l2Q4XCYeyNnSWg32ItAVquVtNnN3P1+H5qmKbXVIZUDyQq3TqeDJElkkhoMBgrIbDZTxmWnIIRAFEUgIliWhTAMMRgMcmDfCpKVEZ1OR0k8RSD7/j8ajcA5l+1Wq6WcqOM47yazg4Nk1+ZucMdxXAiyXzQ6joPLy0vZjqIItm2jVqt9mJEPJQXk4eEBlmXJdhzHsmrdB9lNWkII6LqOl5eXb13sR1JAXl9f5U4HQaCU3/sgu7eP67qwLCv39e+YKry1PM8DYwz1eh1CiEIQ0zTx+vqK4XBYWAAeWzkQ3/dlcGblRxHI7vX8Xml9TCkgSZJA13Xl1squ0uyNnIH4vg/HcXKJ8VRSQEajEQzDUJJWv98HEcmvFmEYolqtIkmS4670Eykg9Xod7XZbtoUQMAwDnHPYti37ThnU70kB4Zyj1WoB+F1y1+t1uK6Ly8tL3N7enmSBX1UORNM03N/f4+LiApZlIU3Tb09mh5ACsltWWJalfDgouxSQKIrQarVwc3PzpXdymXTyr/GH0g9I2fTXgPwCxRmiuVvgWoIAAAAASUVORK5CYII="},
            {'Type': "textCascadeUp", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGAUlEQVRoge2ZP2jbThTHH1SDKYJ68CBaQz0ImsGUDqJ48KDBgwcPoXgIJYMpomQINIMLHjwEPKSgQYMppmQwtIOHUDIEmsGDBxfaYooHUULxoMGDBw8eNGgQ9Nsh3P18OiVx2sRx++sDD5HevbvPu3t/TiH8JUI3vYCrkn8gqyYrBeJ5Hur1Ok5OTi49dqVAer0eiAi9Xu/SY/+/ILPZDIeHh5hMJpee7CJZKsjvTHadtv8IkPF4jM3NTRARkskk+v2+NHblQYIgwNraGoiI/1RVxXQ6FcbeOIjrutje3ka73Y61Xa1WQUSwbRue52FnZwdEhL29PcHOjYKcnJwgmUxyT1cqFcF2GIZQVRWVSkUYl8lkkM1mhWfXDuK6Lra2tmBZlpTpisUiiAipVAqKonAgZvvo6AhEhIODA2Hcs2fPcP/+/eWBRD3+6NEj4R0RoVAowPd9uK4LVVUF2/V6HUSE2WzGx43HY6yvr4NIXPpvgfi+D8dx0G63Y3WfPHkiBCkR4f379wAAx3FARBgOh1w/erTK5TJ0XUcQBOh0OjBNk++coihXB8JSIhFhf39f0BsMBiAi6LqOfr+Pvb09EBF2dnb4IqPnvN1uCyCmaSKZTPKdIiJomoZarQbP8xYDCcMQ/X5fOtcMpNlsCp7WNE04AuxYzAduOp2GaZoAAMMwYFnWmU4CAF3Xuf1cLodOp4MwDGPXGwvS7/eRTqdBREgkEsL2s8ny+TyICJlMhm/3u3fvuF6hUIBhGILdjY0N5PN5AKeZp9lsCu89zxNAMpkMDMOA67qC3sHBATY3N88HCYIAqVRK8PZ8kDIQIsL6+jrCMOS7s7W1xfVUVeXHiMlgMEAQBAAARVGk2IoDKRaL0SVC13XJtgSyv78vBSgRca/Mg7BnYRgilUpx4Nlshlu3buHNmzfSIpiziOhCENM0kcvlBJ3hcAgiktoUCcQ0TRARisUi6vU6D7Tj42MBZH6XAKBUKvGUGF1QVNj7KMhoNJKylqIoGI/HAE4dViqVkE6nJZsCyGQyARHxgATAj43jOAJItNqy4J5Op/jy5QuICF+/fr0USDTYWYouFArodru8fkRjSwJhlfTo6Ejy0u7urjCZbduCIZY6Pc/Dhw8fQET4/v37uSDRBbFjzUAmk4lQ8YkIGxsbsTYFENu2QUTwfV9UigGZh50HcV1XgDoPpF6vC88ty5KOpOM4SCQS0DQNjUZjsfT78uVLPHjwQFK6c+eOBBI9/2w3e70e92wUZDQa8V1QFEXISGEYQtO0WNtRx14IUqlUeJ4XlGJ2JDrZ/PPXr1+DiPDt2zdB59WrV7h37x5+/PiBtbU1qKrKF9lqtc4EWUSkrBWt5MzTUZCot7vdLn/OduTz58+CzosXL/D48WMA4O2NaZqoVqtQFAW1Wg2qqkoF8JdAohAs/V4EMh8XnU5HSNlMTNNEqVQSwOdbnMlk8ssfNc4E2d3dFSZaFGQ2m3GdRqPB3wdBgEQiIWQqlk41Tfulj3IXgrDrJJskDiRaWVnGA/7LSoVCgb9vNBqSA8IwxPHx8ZV8WpJAWEzMe2qRYK9UKtB1nf/N+jXHcdBqtaAoilBor1okENY6q6qKwWBwqhQDcnh4KIwzDEPoSJ8/fy71a51OZzkgHz9+BBHh7t27ePv2LX9++/ZtCWT+rPu+D1VVeRsDnF4FFqnI1wLSarViW4e4Hdne3pbGReOm2WzCNE3p0811iABSLpeRSCSESjoej2NBNE2D7/vwfR/ZbBaapp3ZPixDBBDTNKXK/unTp1gQlpUMwwARoVarLW/VMSKAPHz4EE+fPhUUWD1hNzIGEr1FntUgLksEkGQyKX0QyOVyQkzMxwiDWEYMXCQCSPTCNJ1OpazDQEajESzLWgkIIAKSTqeFK2y1WoWqqsjlcvzuzL5nLdJaL1MEkGw2CyJCq9WCbdtQFAWWZaFcLiOVSt3UGhcSAYQ1cfO/4XAI27alSr5qIoCwy/6yqvFVigAyGo34/SOfz69cHJwnUtPY7XZh2/YfBQGs2P/Zf0f+gaya/DUgPwHndw+ryzSioAAAAABJRU5ErkJggg=="},
            {'Type': "textCascadeDown", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAFzUlEQVRoge2ZLWzbXBSGDzAwsCYDgwBrsiaDgACDgIKAAINKG4imgIAAgwBPCoimgoCASNWUSQUBAQEBBpHWSQUFlTZQENBJAZFWEBBpkWYQEBBgYFBg8H6g373LtZ203dK/aa9kqXHvz3l8zz3nXJvwl4ge24Bd6R/IU9OdQWazGVqtFnzfvwdzfl93BhmNRiAijEajezDn9/UP5D5AlsslTk9PEQTBnfs+KZA/GTsBcnJyAkmSQESwLAtnZ2c7m+wm7QxkNptxiPXr5ORkJ5PdpJ2BHB0dgYhwfHyMIAjQaDRARFBVFVdXV4nJPM9DvV7HYrF4WiCe5yGbzQoNOp0OiAgXFxfCZK7r8hXTNA3z+fz3Cf7XTvcIe/JMl5eXICJ0u11hMiKCJEnQNA1EBMdxEoNHUYR+v49er5cY995B0owhIrTbbWEySZIwmUwQhiFs24YkSYlsXyqVOHQul0MYhg8H4nkeXNdFu92G53nwPC8VpFwu8z7xVQOuo188aNTr9YQB/X4f3W4XYRjuDqTX6yUmZ1ccpN/vCwPlcjkBrlKpgIjw5s0bNJtNKIoCWZYFF2P7j4hQrVZ3B5LP5/nTdhyHX2kg8clqtRoymQz/rSgKdF3n7jQYDEBEPC8FQQBVVYWHxVY/DWSxWGx1TQFElmXYtp1slAIyHo+FNmw1getSI+5KV1dXkGUZBwcHAIDhcMj3mmEYICIUi8VUEBYhVVXF5eXlzSCmaaJSqdwKJL6x2dP0fR/n5+c8H63Ltm2USiUAQL1eBxFhMBggiiK+8nGQs7MzYdVM00QURdtByuVyIo8EQXArkNPTU37/+PgYRIRv374Jbd69e4d8Pg8AKBaL0HWdGzWfz1NBbNveWmmkgjBj1hsyl7lpj8Qzfhqs7/vcJU3T5KvDtLe3J4y9Wq248bVajf8/3i8Bwp6UJElotVro9XqQZRlEhGazKRj89etXoR9zgdFoxDf2tlNkJpPB4eGhcI+5GwNhIZwZHoYhstksZFlOuFcCZLlcwrIs/iRkWYaqqjxzbwq/66vA/t5Wg7EotS62+gzkw4cPICJ8/vyZt/n48aNQMm0EYeSe56HZbML3fezv76NarQogtVot1Qjf9/Hp0ycQEX78+JEKwVwmDsKCBAOp1WogIuGgtVgsUvve6mDlui7fpAxEURRhApYAoyjibvb9+/fU8XzfTzUmvv9ev36NV69eJfpns1m8f//+7iBRFGE4HAqTGYbBA0AYhtA0DbqupxoUF4tQcRAGyPrlcjlYlpXov7+/j2KxeHeQdU2nU6iqyssL13V5NGk0GoJBDD6uTe4RBzEMIzVBO44DwzD+DAS4Dgir1Qq6rgvx/fz8nLfJZDIcjGkwGPAkeVsQVq8Nh0Nep7muuxsQptlshkwmI6wGU6lU4vuK6eDggJcxiqKg0+lsBYk/KEVR4LouyuUyd+OdgADXmT8tX3S7XRARJpMJv2fbNjfAMAy0Wq2tIC9fvtxYjb948WK3IJu0XC4hyzL29vYQhiH/XSgUAFxX2utlPwBMJpOEa1mWJeS19etBQIBfmdo0Te4mzAVLpVKirovnkUKhwIvY8XgMx3GEtzwPBuL7Pt9D7GJlOHO91WrF27N7DKRYLCbC7Gq1QqfT2e1mv43WA8L6Cwp2PO71evxetVoVQMrlMnfFm/Qg30eCIEg9EOm6zl9KrJ8YGYjrujBN81ZzPOqHHvYC0LIsFAqFxHmk2+1ClmX8/PnzxrEeFWQ+nwubV1EUAYSVOvFK9/DwENPpVLj36J/e2u02B2HHXQYSP50y5fN5aJom3Ht0EODahRqNBqbTaaLY1HVdOBKHYQhZlpHL5YQxngQIUxiGcBxHAGFlzdHREYBfr5XiyfRJgaRpNptx16tUKnwfxcubJw8CAG/fvk2UJ1++fBHaPAuQ8XjMV4KVPHE9CxAAuLi4gKZpUBQlEY6BZwTCtOn977MD2aR/IE9Nfw3If9N0EwglGDDbAAAAAElFTkSuQmCC"}
        ],
        [
            {'Type': "textArchUp", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAADYElEQVRoge2YoZeqQBSHjfsHGDYYCAYCYQLBQDAYCBsMGzYQDASCkWAg2AwGosEwwWAkGAwGAsFAIBAIBgLBYCBMmDDh98I7yzmsuuuuso/zDl/ycB3v/YB7Z44t/Ce0/nUBj+JXRDjnOB6Pleb4FRHf99Hv9yvN8Wsiw+Gw0hyViqxWKwyHQ8znc4xGoypTVSdyOBygKAo8z4Msy5hOp2ffYYwhjuOH5LtLhDEGXdfR6/Vg23YpRiktinccB67rluJhGOL5+RmKosAwjHvKAHCnCKUULy8vAADXdZHneSm2XC6Lz5TS0lpN0xDHMYQQUBQFp9PpnlLuE/E8D5PJ5GIsjmOMx2MAwHw+h+/7RSwIAjw9PcEwDERRBFmWL4qcTies12swxr6s5S4RzjkIIeCcAwD2+33pqQwGA+R5Dk3TEEVRcX25XMLzPLiui263ezbRkiQBpRSyLKPX60FRFAghHiOSZRn2+/3Z9eVyWfTHdDotFbzZbNBut0EIQZqmxXXHcRCGIRhjSJKkJA/8HdetVqvoqzAMv6zvqkgQBDBNE4wxRFGEdrsNVVWhaVqpKACwbRtvb28ghOBwOJRil+7ker0GIQSapmG73ZZix+MRqqqWhsUtXBXhnMO2bciyDMuyih9NkgSapp0dOcIwxG63uzlxEARnN+RdIgiCm3/nnS9frTAMQQhBr9cr7m4URRgMBt9O9hnvo/wnEsCNPSKEwHQ6xevra/EkDMNAlmU/SnqJ8XiMJEl+vP5bUyuKIvT7fZimCV3XKz/RUkqLqfVxw/3It8evEAKu65am06PhnMOyLMxmM6RpijzPoSjKpzmvijDG4Pv+TZvRo3jvQV3XS69ZlmWQJAme511de1FECAFZlqGqKmRZxmg0+nET3kqe53AcB0IIdDod7HY7bLdbzGYzdDodGIaBzWZzdf1FkSAIQAgB8HeTM00T4/EYkiRhsVhUIkIphW3bSJIEs9kMkiTBsizsdrvi5PAZF0WyLEO320WaplgsFsUeYlnWxd39EXDOsVqtQCm9aSf/yNUe8X0fm80GaZqCEILJZAJVVStt8nu4aWpxzpGm6d1H7Spp/g6qG41I3WhE6kYjUjcakbrRiNSNRqRuNCJ1oxGpG41I3WhE6kYjUjcakbrxBw0K0kIhG+liAAAAAElFTkSuQmCC"},
            {'Type': "textArchDown", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAADnUlEQVRoge2YIXTqPBiGEROICQQCgUBETERUIioQiAoEAhGBQFQgEJMIRM+pQFQgKhAIxASiImJiAlFRgZhAICoqKiYqKhAViIj3ip31p3+BAWN3vTt9FHxJz/meNPmStIBfQuGnE7gVuUjWyEWyRi6SNXKRrJGLZI1cJGvkIlkjF8kauUjWyEWyRi6SNXKRrPE7RYQQ4JyDcx7/Hg6HCMPwp/I7m4RIu92GoihQFAW9Xg9hGGIymaDRaPxUfmeTEKlWq9hut9jtdqjValiv1wiCAHd3dz+VHxzHgRDi034JEVVVYRgGhBCYzWaQJAmSJMEwjG9L9BRRFIEQgnK5DFVVwTnHbrc72De1Rur1OgqFAiilMAwDQRD8laQP0el0YJomXNcF5xyMMRSLRXQ6Hdi2neibENntdlAUJdXp/5imibe3t1vnnaLX6+H5+TkRe3x8RLfbBaUUg8Egjl9Ufn3fR7vdhmVZt8l0D8/zwDlPxMIwhCzLWCwWcUzXdYzHY4RhiHK5jO12C+BMESEETNNEpVLBcrm8Yfr/MZ1O0e/3U/HtdgvGGAghqNfrKJVK8H0fQghUKpW436cirutClmUwxmBZFiRJSr3uWxBFEZrNJgzDwGq1SrWHYYjVaoUoirBcLtFutzEcDuP2oyJCCBiGgVqthtfX1zg+GAxSU+BWLBYLFAqFk2s0iiIwxqDreiJ+VGSxWIAQgul0Gsd83wel9GgJ/CphGGK9XqPRaGC9Xl/07MmppWkadF2HEAKWZYFSevC1f8Z8Pr+ojPu+D0IIHMc5+5mTIp7n4eHhAcViEZTSxBT7QNd13N/fo9VqHd2BdV2H67qJWBRF8XHo0Oi7rnuRzFlV69hojkYj9Ho9AEC/30/N7SAIYFkWZrNZqm00GsE0TaxWK1BKj8q0Wq1zUrz+GO84Diil8VvgnCdGXQgBSik6nQ4qlUpiLwDeN7vNZgPHcSDLMlRVvTYVAF8QYYxhMpkcbX96eoKmaQDeR3+/aADv669araLVasG2bXiel5p+l3C1SLPZjDfHj1PyPt1uN55Otm3HUh9wziHLcvxf0zTM5/Nr07leZDqdghCC0WgEQkhqNBuNRlwcXl5eDu7akiRhMBhgNpuBEHJxyd3nS1fd5XIJTdPgeV6qTVGUeF2Mx2MwxlJ9giBAv98HY+yqsr7Pt93ZbdtGqVSCqqqo1Wrffsv81o8Pm80mPvJ/Zdqcw+/8ivIv8wdL3arN8Q1vAgAAAABJRU5ErkJggg=="},
            {'Type': "textCircle", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAF3klEQVRoge2Zr5eqTBjH9w+44QaDwWDYQCAQCBsIhA0GAoFAMBAIBgLBQDB4joFgIBgMBgKBYCAYDAQDwWAgbCAQDAaCgTCBQPi+YY+cZZFdf/HePffcb2NGZp7P8Dwzzzw+4S/R05824FFqDCRNU4Rh2NTwFTUGEoYheJ5vaviKGgNJkgQcxzU1fEUPB0mSBIqiwDRNdLvdSj8hBI7jII7jh877cBBVVWGaJiaTSQUkz3OwLAtFUcAwDKIoeti8d4Hs9/tKG8dxRXun0yn1ua6L4XAIAFitVhiPx5X3gyBAu90Gx3FIkuRiW24CIYSApmmIoghZlpHnedGnqmrhNrIsl97TNA2tVgs8z0MQBMxms1K/oiigKAqbzQau64IQ0izIZrOBqqoAUFm11WqFyWRSGPaxv9/vY7/fIwgCjEajyhdVFAXPz89Yr9dX23QTSBRFpa01yzJkWVY88zwP27bR7XZLxhqGgfV6jSAI4DhOaUzf9yHLMgghpS98qW6OkcFggOVyCQCwbRue5xV9h8MBmqZhuVyW3CNNU7y8vEAQhEo7z/NXudJn3QxCCAHP85jP5xiPx5jP5zcboaoqdrvd2b40TS8a4yxImqbF6vi+j3a7DZqmK8bmeQ7LsiDL8sUTftZut4NlWaU2Qgg0TQNFUWi321itVreBLJdLdLtduK4LSZKw3W6RJAl0Xa/sUo9WnucQBKFwW9/3IUnSt3PWulYcx+j3+/j9+3dpxVzXhWmaDzK7KsMwCggAsCwLrVYLm83my/e+jZFT8jcejwt3YxjmPmvPaL/fI8sytFotEEIQhiFUVYWiKBelMxcHu+/74HkeHMeh3+/fZfQ5nVzWdV202230er2rrgFX71qO49wc2F+J4zjoug5d1791IwClcwv4QTfELMu+PEfyPIfv+xgOh6AoqhKnZ0G22y0YhgHP8xgOh1iv13cdVrfqeDzCtm3Isozn52f8+vWrNgc7CyKKIjzPw36/B8MwmEwmaLfbGI1GjRt/0mw2K1Kak+Ge51US0ZPOggiCgNVqBUJIsUPVpd3/l47HIwzDgCAIZ/vPgsRxjF6vhyzLIMsyNE0Dz/OVRK9JBUGAwWAASZIgSRIEQcBkMqm9o1wU7EmS/JEYuUY/Zte6V/9AmtZ6vYaiKJAkCbIsYzQawXGc2tP+S5Dj8Yj5fA7DMKBpWuny1ISOx+PZ9jRNEQQBZrMZFosF4jhGq9UqZRi1IJZlgaIoLBYLvL29IYoi0DSNOI7hOE4jO9h0Oq0UJC5VLUir1So9v729odPpQNO0Rmu6juNAVVV4nnfVvacWhGVZTCYTTKdT9Pt9DIfDh1cH65TnOWzbxuvrK0zTrHW5j6oF2e126Ha7GI/HFw3UhE5ALy8vUFUVh8Oh9re1IISQSqp8UpqmjcBtNpvar+55HtI0hWEY2G63lf6rtt84jiHLMkRRBEVRFxUFrhEhBJIkfbk7bjabszXji0GCIADLssUgs9msUv24VaecTtd1RFEEjuNgGMZjgv3zRAzDFFXDU1X9miLzOX02NAxDKIqCTqeDXq+H19fXi134IpDD4VBU1gkhUBQFi8Wi9BtN0y6a8PM752LC932YpgnP80BRVG3x7qMudi1RFMGyLBiGqRxaruvCtm0AKIrbwDt0HMfI8xxhGCLLstICnGLus/b7PSRJAvC+e3Y6nW/j8apgD8OwUnjIsgy9Xg95nuN4PGIwGBR9u92uADz9L3Iy8CRFUeD7fqmNEAJd14vnw+HwrYvdnTRallWs8mKxKK3cer0uQE4Ap4r7RyNZlr27enk3CEVRxXnDcVzp7LFtuwARRRHAez71eXvVdf2uIjjwIJDhcAhZlituY5pmAULTNID3g+3zxpAkCTqdzl31srtBDocDptMpdF2vZMSLxQKWZSGKIjw9PRUQLMtWxhmNRkUc3aJGL1ZRFKHb7YKmaSyXS9A0jfF4fPbkTtP0rlJs4zfEunzt0fqxV91r9Q/kp+mvAfkPWgnC5oYbWPkAAAAASUVORK5CYII="},
            {'Type': "textButton", 'Image': "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAGYUlEQVRoge2ZIYziTBvHR4yoQPSSCgSiAlGBqFhBLoiKJoeo2FwQTW4vQZAsYgWiYgWCBMElCMSKExUVCAQCwSWIFc2lAlGBOIGoaHIkV1GBGFFR8X/Fhn5w20LZ5bu998v3TyqmfTozv/aZmWeeIfgfEXnrDlxKFweJ4xjj8RiNRgOapsEwDPi+f+lmnuniIIZhoFqtwrZtbDYb3NzcoFarIY7jSzd1oIuCbDYbEELw48eP5F4cx9hut6n2URSh3+9DlmU0m008Pj4m91VVTcp59F8BcV03l71hGCiVSlgul3BdF9VqFZZlwTAMUEpz1wOcCeK6LizLwnK5zLRRFAWdTicpz2YzSJKU6lqUUliWlZSDIIAoiqCUYjgcntO1bJA4jg9cZPf16vU6KKXo9/up763Xa4iiiFqtBl3XIcsyHMdJb5yQg48SxzEEQUC9Xj8L4ihIp9NBoVCA4ziYTCZoNBrJM8uyQCnFZrNJfTeOYziOc9I1FEXBeDxOyoPBAMViEWEYnsuRDRIEAarVKgqFAmRZxmq1OnguSdKBW7xE6/Ua5XIZrVYLuq6DEHLWAN/X0THCGEOj0QAhBL1e7+CZLMtYLBYvanRfURTBcRwoioL7+/sX13NysMdxDMMwwPM8TNME8ORal14bwjB8VX25Z62HhwdQSiHLMrrdLhhjL270XHmed3K2PGv6nc/nuLu7e3XHztFoNAKlFKVSCYIgZLrfSRDLsp5dnue9qFOMMUyn05N2QRDAcRx4ngdCCFRVxWg0AmMMtVoNs9nsfJDdQN+/fp/B8mq73YLn+ZN2q9UKg8EAlmVB0zRst1tIkoQoimDbNjRNOw3ied7B+kAIyYyVfhdjDKvVClEUpa4xvu9DFEUAT1PvsRgsDEMsFotk/er1euj3+8mCexRkPp+DUgpKKTRNw2KxyA0ym80giiKur69RrVZTG/N9HzzPo9lsQtd1CIKQOoXbto1ms4k4jnF1dYXVaoXtdotisYharZa68h+AyLIM0zSh6zoURQGlFISQg0uW5VQQQRCSfcd0Os0E2Y+OB4MBWq1WJgjw5CGlUgntdhudTgfVajV1f5OA+L6fkDYajWTKI4ScDBk2mw1KpVJSDsPw6B/ZybKspMNZIMDTWua6LqIoyuxDArL/sizL2G63yRc85VpxHIPn+WRtWS6XqSC/D/bZbIbr6+uTIHmUgLiuC0mSkq8ZRRFms1nuMXJzc4NWqwXbtqEoytuBAE/R6Gazga7rqFQq4HkeHz9+zFURYwz9fh+dTgePj4+pIGEYwjCMpOw4ThL27Gu9Xqfezw2yi3XCMMRwODzYj5xSu91GEAQAgMlk8qI9xWt0sa3ufD6HoiioVCqo1+sJ1J/S//Naf5sI8DRQz8lY/I0ijDFIkoRKpfLWfXmViOM4KBaLRzct/waR3QKWpiAIMBqN/kju9rUiQRCgWCwm4QVjDKZpQlVVUEohSRJs237bXuYQAYBWqwVJkqCqKjiOOwjj/xat12u0Wi10u93s6Jcxhk6nA03TMg3fUjuv0TQNpVIJhBAoioLJZJJExP+KdaTb7eLr168A/nP+IssyeJ5PAtq/HiSOY6iqmhqBH2zJz6l0uVxC1/XX9+4MqaqKQqFwMuGRG2Q6nYLn+VzpnEvK8zxUKhUIgnC07Vwgw+EQHMf9cYidGGO4ubkBIQTNZjPVzY6CxHGMu7s7UErfDGJfDw8P4DguNS7MBGGMQdO0JF0piiJEUcTV1RU0TTtr03VJZe1zMkF2Odfdn6jVahgOh/B9H77vZ1ZoGMbZkXQYhjBNE4PB4MUZ+aOutT9TKIqCbrd7tLIoisBx3Fm5Ydd1Icsy7u/vUS6XX3xckXvW0nUdnz59Omozn88hCELm8zAMsd1u0ev1oCgKdF1HvV5PIgnP88Bx3LNDpTzKDXJ7e4v3798ftWm326npHeAJYpdZN00Ttm2jUqk8y7Z0u11QSs9OlOcGWa1WqNVqR21EUcRgMMh8znHcQTpolzfbj+2iKEKpVDo4fM2js1b2Y777/ft3EELw7du3TJtyuXzgNlEUoVAoPDu82WX0z9HFYq0vX77g3bt3+PnzZ6bNhw8f8Pnz54N7t7e3kGUZv379elX7FwNRFCUzU79Ts9l8ZrNcLjEej199sHoxEMbYyWnXNE202+1LNXmgfwDJIwE2xeerMAAAAABJRU5ErkJggg=="}
        ]
    ];


    var g_oChartPresets = {};
    g_oChartPresets[Asc.c_oAscChartTypeSettings.areaNormal] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,2,0,0,0,0,0,0,0,0],[2,[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],[[3,null,[3,12,1,["lumMod",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,true,false,[3,null,[3,12,1,["lumMod",85000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,12,1,["lumMod",75000]]],null,[1,null],[0,2,2],[0,2,2],0,0,1,9575]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,12,2,["lumMod",75000],["alpha",36000]]],[100000,[3,8,3,["lumMod",95000],["lumOff",5000],["alpha",42000]]]],10,[1,null],0,0,0,0,1,9525]],0,3,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[0,true],0,0,2,[0,[3,0,1,["lumMod",75000]]],[100000,[3,0,0]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,2,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,3,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[5,null,22,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,2,0,0,0,0,0,0,0,0],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,19050]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,12,2,["lumMod",75000],["alpha",36000]]],[100000,[3,8,3,["lumMod",95000],["lumOff",5000],["alpha",42000]]]],null,[1,null],0,0,0,0,1,9525]],0,3,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[3,216.75,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,2,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,null,null,null,2,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,2,0,0,0,0,0,0,0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[5,null,20,[3,8,2,["lumMod",15000],["lumOff",85000]],[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,2,0,0,0,0,0,0,0,0],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,137.7,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,12700]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,2,0,0,0,0,0,0,0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,true],[[3,188.7,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[10,true,false,[3,null,[3,0,1,["lumMod",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],null,null,false,false,false,false,false,false,true],null,null,null,2,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,12700]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,2,0,0,0,0,0,0,0,0]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.areaStacked] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,1,0,0,0,0,0,0,0,0],[2,[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],[[3,null,[3,12,1,["lumMod",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,true,false,[3,null,[3,12,1,["lumMod",85000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,12,1,["lumMod",75000]]],null,[1,null],[0,2,2],[0,2,2],0,0,1,9575]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,12,2,["lumMod",75000],["alpha",36000]]],[100000,[3,8,3,["lumMod",95000],["lumOff",5000],["alpha",42000]]]],10,[1,null],0,0,0,0,1,9525]],0,3,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[0,true],0,0,2,[0,[3,0,1,["lumMod",75000]]],[100000,[3,0,0]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,1,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,3,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[5,null,22,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,1,0,0,0,0,0,0,0,0],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,19050]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,12,2,["lumMod",75000],["alpha",36000]]],[100000,[3,8,3,["lumMod",95000],["lumOff",5000],["alpha",42000]]]],null,[1,null],0,0,0,0,1,9525]],0,3,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[3,216.75,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,1,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,null,null,null,1,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,1,0,0,0,0,0,0,0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[5,null,20,[3,8,2,["lumMod",15000],["lumOff",85000]],[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,1,0,0,0,0,0,0,0,0],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,137.7,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,12700]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,1,0,0,0,0,0,0,0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,true],[[3,188.7,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[10,true,false,[3,null,[3,0,1,["lumMod",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],null,null,false,false,false,false,false,false,true],null,null,null,1,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,12700]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,1,0,0,0,0,0,0,0,0]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.areaStackedPer] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,0,0,0,0,0,0,0,0,0],[2,[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],[[3,null,[3,12,1,["lumMod",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,true,false,[3,null,[3,12,1,["lumMod",85000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,12,1,["lumMod",75000]]],null,[1,null],[0,2,2],[0,2,2],0,0,1,9575]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,12,2,["lumMod",75000],["alpha",36000]]],[100000,[3,8,3,["lumMod",95000],["lumOff",5000],["alpha",42000]]]],10,[1,null],0,0,0,0,1,9525]],0,3,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[0,true],0,0,2,[0,[3,0,1,["lumMod",75000]]],[100000,[3,0,0]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,0,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,3,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[5,null,22,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,0,0,0,0,0,0,0,0,0],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,19050]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,12,2,["lumMod",75000],["alpha",36000]]],[100000,[3,8,3,["lumMod",95000],["lumOff",5000],["alpha",42000]]]],null,[1,null],0,0,0,0,1,9525]],0,3,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[3,216.75,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,0,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,null,null,null,0,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,0,0,0,0,0,0,0,0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[5,null,20,[3,8,2,["lumMod",15000],["lumOff",85000]],[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,0,0,0,0,0,0,0,0,0],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,137.7,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,12700]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,0,0,0,0,0,0,0,0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,true],[[3,188.7,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[10,true,false,[3,null,[3,0,1,["lumMod",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],null,null,false,false,false,false,false,false,true],null,null,null,0,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,12700]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,0,0,0,0,0,0,0,0,0]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.barNormal] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,219,-27,null,0],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[8,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,0,0,2,2,true],[0,0,7,null,false,false,null,false,false,false,true],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[8,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-5400000,1,0,true,0,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],7,null,false,false,false,false,false,false,true],444,-90,null,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[5,null,24,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,164,-22,null,0],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[0,0,[0,[[4,null,[5400000,false],0,0,2,[0,[3,12,2,["lumMod",75000],["alpha",36000]]],[100000,[3,8,3,["lumMod",95000],["lumOff",5000],["alpha",42000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,true],[0,0,5,null,false,false,null,false,false,false,true],[[3,216.75,[3,0,0]],[[3,127.5,[3,12,0]],null,[1,null],0,0,0,0,1,9525]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],5,null,false,false,false,false,false,false,true],65,null,null,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,100,-24,null,0],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,100,-24,null,0],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[5,null,20,[3,8,2,["lumMod",15000],["lumOff",85000]],[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,267,-43,null,0],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,137.7,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,12700]],0,0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,100,-24,null,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,15,2,["lumMod",25000],["lumOff",75000]]],[100000,[3,15,2,["lumMod",5000],["lumOff",95000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],4,[0,[3,0,0]],[51000,[3,0,1,["alpha",75000]]],[75000,[3,0,2,["lumMod",60000],["lumOff",40000]]],[100000,[3,0,3,["lumMod",20000],["lumOff",80000],["alpha",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,355,-70,null,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[2,null],[[3,null,[3,0,0]],null,[3,800000],0,0,0,0,1,25400]],0,164,-35,null,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,199,null,null,0],[2,[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,true,false,[3,null,[3,12,1,["lumMod",85000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",75000],["lumOff",25000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",75000],["lumOff",25000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[2,null],[[3,null,[3,0,0]],null,[3,800000],0,0,0,0,1,9525]],0,315,-40,null,0],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,15875]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,178.5,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,80,25,null,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,12700]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,100,-24,null,0]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.barStacked] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,2],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[8,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,0,0,2,2,true],[0,0,3,null,false,false,null,false,false,false,true],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[9,false,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],3,null,false,false,false,false,false,false,true],79,100,null,2],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[0,null],0,0,null,null,null,null]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[5,null,24,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,2],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[0,0,[0,[[4,null,[5400000,false],0,0,2,[0,[3,12,2,["lumMod",75000],["alpha",36000]]],[100000,[3,8,3,["lumMod",95000],["lumOff",5000],["alpha",42000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,true],[0,0,3,null,false,false,null,false,false,false,true],[[3,216.75,[3,0,0]],[[3,127.5,[3,12,0]],null,[1,null],0,0,0,0,1,9525]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],3,null,false,false,false,false,false,false,true],150,100,null,2],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,150,100,null,2],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,2],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[5,null,20,[3,8,2,["lumMod",15000],["lumOff",85000]],[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,2],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,137.7,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,12700]],0,0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,2],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],[0,2,2],[0,2,2],0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,15,2,["lumMod",5000],["lumOff",95000]]],[100000,[3,15,2,["lumMod",15000],["lumOff",85000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,178.5,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,50,100,null,2],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,2],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,12700]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,2]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.barStackedPer] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,1],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[8,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,0,0,2,2,true],[0,0,3,null,false,false,null,false,false,false,true],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[9,false,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],3,null,false,false,false,false,false,false,true],79,100,null,1],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[0,null],0,0,null,null,null,null]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[5,null,24,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,1],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[0,0,[0,[[4,null,[5400000,false],0,0,2,[0,[3,12,2,["lumMod",75000],["alpha",36000]]],[100000,[3,8,3,["lumMod",95000],["lumOff",5000],["alpha",42000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,true],[0,0,3,null,false,false,null,false,false,false,true],[[3,216.75,[3,0,0]],[[3,127.5,[3,12,0]],null,[1,null],0,0,0,0,1,9525]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],3,null,false,false,false,false,false,false,true],150,100,null,1],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,150,100,null,1],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,1],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[5,null,20,[3,8,2,["lumMod",15000],["lumOff",85000]],[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,1],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,137.7,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,12700]],0,0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,1],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],[0,2,2],[0,2,2],0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,15,2,["lumMod",5000],["lumOff",95000]]],[100000,[3,15,2,["lumMod",15000],["lumOff",85000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,178.5,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,50,100,null,1],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,1],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,12700]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,1]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.barNormal3d] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,0,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[5,null,20,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[3,null,[3,0,0]],null,[0,null],0,0,null,null,null,null]],0,160,null,0,0,[100,null,null,false,10,0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[3,null,[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,216.75,[3,0,0]],[[3,null,[3,0,1,["lumMod",75000]]],null,[1,null],0,0,0,0,1,9525]],0,65,null,null,0,[60,null,100,false,0,0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[3,null,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,150,null,null,0,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,0,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],[[3,null,[3,8,1,["tint",75000]]],null,[1,null],0,0,0,0,1,6350]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,false,false,[3,null,[3,12,0]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[0,0,0,0,3,2,true],[0,0,null,null,false,false,null,false,false,false,true],[[3,224.4,[3,0,0]],[[3,null,[3,0,1,["lumMod",50000]]],null,[0,null],0,0,null,null,null,null]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[3,76.5,[3,0,0]],[[3,127.5,[3,12,0]],null,[1,null],0,0,null,null,null,null]],null,null,false,false,false,false,false,false,true],84,null,53,0,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[3,68.85,[3,7,1,["lumMod",75000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,76.5,[3,0,0]],[[3,null,[3,0,1,["lumMod",75000]]],null,[0,null],0,0,null,null,null,null]],0,150,null,null,0,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[3,68.85,[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,0,2,[50000,[3,0,0]],[100000,[3,0,1,["alpha",0]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,0,0,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,0,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,0,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.barStacked3d] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,2,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[0,null],0,0,null,null,null,null]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[5,null,20,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[3,null,[3,0,0]],null,[0,null],0,0,null,null,null,null]],0,150,null,null,2,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,19050]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[8,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,0,0,2,2,true],[0,0,null,null,false,false,null,false,false,false,true],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[8,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],null,null,false,false,false,false,false,false,true],79,null,null,2,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,150,null,null,2,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,2,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,2,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,2,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.barStackedPer3d] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,1,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[0,null],0,0,null,null,null,null]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[5,null,20,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[3,null,[3,0,0]],null,[0,null],0,0,null,null,null,null]],0,150,null,null,1,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,19050]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[8,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,0,0,2,2,true],[0,0,null,null,false,false,null,false,false,false,true],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[8,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],null,null,false,false,false,false,false,false,true],79,null,null,1,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,150,null,null,1,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,1,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,1,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,1,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.barNormal3dPerspective] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,3,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[5,null,20,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[3,null,[3,0,0]],null,[0,null],0,0,null,null,null,null]],0,160,null,0,3,[100,null,null,false,10,0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[3,null,[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,216.75,[3,0,0]],[[3,null,[3,0,1,["lumMod",75000]]],null,[1,null],0,0,0,0,1,9525]],0,65,null,null,3,[60,null,100,false,0,0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[3,null,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,150,null,null,3,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,3,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],[[3,null,[3,8,1,["tint",75000]]],null,[1,null],0,0,0,0,1,6350]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,false,false,[3,null,[3,12,0]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[0,0,0,0,3,2,true],[0,0,null,null,false,false,null,false,false,false,true],[[3,224.4,[3,0,0]],[[3,null,[3,0,1,["lumMod",50000]]],null,[0,null],0,0,null,null,null,null]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[3,76.5,[3,0,0]],[[3,127.5,[3,12,0]],null,[1,null],0,0,null,null,null,null]],null,null,false,false,false,false,false,false,true],84,null,53,3,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[3,68.85,[3,7,1,["lumMod",75000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,76.5,[3,0,0]],[[3,null,[3,0,1,["lumMod",75000]]],null,[0,null],0,0,null,null,null,null]],0,150,null,null,3,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[3,68.85,[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],[0,2,2],[0,2,2],0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,0,2,[50000,[3,0,0]],[100000,[3,0,1,["alpha",0]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,0,3,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,3,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,3,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0]]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.lineNormal] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,28575]],0,null,null,null,2,0,0,0,0,0,[null,0,4]],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[0,0,[0,[[4,null,[5400000,false],0,0,2,[0,[3,12,2,["lumMod",75000],["alpha",36000]]],[100000,[3,8,3,["lumMod",95000],["lumOff",5000],["alpha",42000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,true],[0,0,3,null,false,false,null,false,false,false,true],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,31750]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],3,null,false,false,false,false,false,false,true],null,null,null,2,0,0,0,0,[null,0,null],[17,[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[4,null,[5400000,false],0,0,2,[0,[3,12,0]],[100000,[3,12,1,["lumMod",95000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,0,1,1,22225]],0,null,null,null,2,0,0,0,0,0,[null,0,4]],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,31750]],0,null,null,null,2,0,0,0,0,0,[null,0,4]],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[5,null,20,[3,8,2,["lumMod",15000],["lumOff",85000]],[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,137.7,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,130.05,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,137.7,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,22225]],0,null,null,null,2,0,0,0,0,0,[null,0,4]],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,34925]],0,null,null,null,2,0,0,0,0,0,[null,0,4]],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14.5,false,false,[4,null,[5400000,false],0,0,2,[0,[3,8,2,["lumMod",50000],["lumOff",50000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[10,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[0,0,0,0,2,2,true],[0,0,3,null,false,false,null,false,false,false,true],[0,[[3,null,[3,0,2,["shade",95000],["satMod",105000]]],null,[1,null],0,0,0,1,1,19050]],[[9,true,false,[3,null,[3,0,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],3,null,false,false,false,false,false,false,true],null,null,null,2,0,0,0,0,[null,0,null],[17,[[3,null,[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,38100]],0,null,null,null,2,0,0,0,0,0,[null,0,4]],[2,[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,true,false,[3,null,[3,12,1,["lumMod",85000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",75000],["lumOff",25000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",75000],["lumOff",25000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[0,null],0,0,null,1,null,22225]],0,null,null,null,2,0,0,0,0,0,[null,0,4]],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[8,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,22225]],0,null,null,null,2,0,0,0,0,[null,0,null],[6,[[3,null,[3,0,0]],[[3,null,[3,0,0]],null,[1,null],0,0,null,null,null,9525]],2]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,28575]],0,null,null,null,2,0,0,0,0,[null,0,null],[5,[[3,null,[3,0,0]],[[3,null,[3,0,0]],null,[0,null],0,0,null,null,null,9525]],0]]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.lineStacked] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,28575]],0,null,null,null,1,0,0,0,0,0,[null,0,4],0,0],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false,null,0],[0,0,[0,[[4,null,[5400000,false],0,0,2,[0,[3,12,2,["lumMod",75000],["alpha",36000]]],[100000,[3,8,3,["lumMod",95000],["lumOff",5000],["alpha",42000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,true,0,0],[0,0,3,null,false,false,null,false,false,false,true],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,31750]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],3,null,false,false,false,false,false,false,true],null,null,null,1,0,0,0,0,[null,0,null],[17,[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[4,null,[5400000,false],0,0,2,[0,[3,12,0]],[100000,[3,12,1,["lumMod",95000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false,null,0],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,0,1,1,22225]],0,null,null,null,1,0,0,0,0,0,[null,0,4],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,31750]],0,null,null,null,1,0,0,0,0,0,[null,0,4],0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[5,null,20,[3,8,2,["lumMod",15000],["lumOff",85000]],[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,137.7,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,130.05,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false,null,0],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,137.7,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,22225]],0,null,null,null,1,0,0,0,0,0,[null,0,4],0,0],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false,null,0],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,34925]],0,null,null,null,1,0,0,0,0,0,[null,0,4],0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14.5,false,false,[4,null,[5400000,false],0,0,2,[0,[3,8,2,["lumMod",50000],["lumOff",50000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[10,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false,null,0],[0,0,0,0,2,2,true,0,0],[0,0,3,null,false,false,null,false,false,false,true],[0,[[3,null,[3,0,2,["shade",95000],["satMod",105000]]],null,[1,null],0,0,0,1,1,19050]],[[9,true,false,[3,null,[3,0,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],3,null,false,false,false,false,false,false,true],null,null,null,1,0,0,0,0,[null,0,null],[17,[[3,null,[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,38100]],0,null,null,null,1,0,0,0,0,0,[null,0,4],0,0],[2,[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,true,false,[3,null,[3,12,1,["lumMod",85000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",75000],["lumOff",25000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,null,0],[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",75000],["lumOff",25000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[0,null],0,0,null,1,null,22225]],0,null,null,null,1,0,0,0,0,0,[null,0,4],0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[8,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,22225]],0,null,null,null,1,0,0,0,0,[null,0,null],[6,[[3,null,[3,0,0]],[[3,null,[3,0,0]],null,[1,null],0,0,null,null,null,9525]],2],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,28575]],0,null,null,null,1,0,0,0,0,[null,0,null],[5,[[3,null,[3,0,0]],[[3,null,[3,0,0]],null,[0,null],0,0,null,null,null,9525]],0],0,0]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.lineStackedPer] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,28575]],0,null,null,null,0,0,0,0,0,0,[null,0,4]],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[0,0,[0,[[4,null,[5400000,false],0,0,2,[0,[3,12,2,["lumMod",75000],["alpha",36000]]],[100000,[3,8,3,["lumMod",95000],["lumOff",5000],["alpha",42000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,true],[0,0,3,null,false,false,null,false,false,false,true],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,31750]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],3,null,false,false,false,false,false,false,true],null,null,null,0,0,0,0,0,[null,0,null],[17,[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[4,null,[5400000,false],0,0,2,[0,[3,12,0]],[100000,[3,12,1,["lumMod",95000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,0,1,1,22225]],0,null,null,null,0,0,0,0,0,0,[null,0,4]],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,31750]],0,null,null,null,0,0,0,0,0,0,[null,0,4]],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[5,null,20,[3,8,2,["lumMod",15000],["lumOff",85000]],[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,137.7,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,130.05,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,137.7,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,22225]],0,null,null,null,0,0,0,0,0,0,[null,0,4]],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,34925]],0,null,null,null,0,0,0,0,0,0,[null,0,4]],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14.5,false,false,[4,null,[5400000,false],0,0,2,[0,[3,8,2,["lumMod",50000],["lumOff",50000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[10,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[0,0,0,0,2,2,true],[0,0,3,null,false,false,null,false,false,false,true],[0,[[3,null,[3,0,2,["shade",95000],["satMod",105000]]],null,[1,null],0,0,0,1,1,19050]],[[9,true,false,[3,null,[3,0,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],3,null,false,false,false,false,false,false,true],null,null,null,0,0,0,0,0,[null,0,null],[17,[[3,null,[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,38100]],0,null,null,null,0,0,0,0,0,0,[null,0,4]],[2,[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,true,false,[3,null,[3,12,1,["lumMod",85000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",75000],["lumOff",25000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",75000],["lumOff",25000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[0,null],0,0,null,1,null,22225]],0,null,null,null,0,0,0,0,0,0,[null,0,4]],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[8,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,22225]],0,null,null,null,0,0,0,0,0,[null,0,null],[6,[[3,null,[3,0,0]],[[3,null,[3,0,0]],null,[1,null],0,0,null,null,null,9525]],2]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[0,[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,28575]],0,null,null,null,0,0,0,0,0,[null,0,null],[5,[[3,null,[3,0,0]],[[3,null,[3,0,0]],null,[0,null],0,0,null,null,null,9525]],0]]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.line3d] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,2,[null,null,null,false,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[null,0,null],[null,0,4]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[2,null],null,[1,null],0,0,0,0,1,25400]],0,null,null,null,2,[null,null,null,false,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[null,0,null],[null,0,4]],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,25400]],0,null,null,null,2,[null,null,null,false,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[null,0,null],[null,0,4]]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.hBarNormal] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,182,null,null,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[5,null,25,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,227,-48,null,0,0,0,0,0,0,0],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,12,2,["lumMod",75000],["alpha",36000]]],[100000,[3,8,3,["lumMod",95000],["lumOff",5000],["alpha",42000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,5,null,false,false,null,false,false,false,true],[[3,216.75,[3,0,0]],[[3,127.5,[3,12,0]],null,[1,null],0,0,0,0,1,9525]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],5,null,false,false,false,false,false,false,true],65,null,null,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,100,null,null,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,100,null,null,0,0,0,0,0,0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[5,null,20,[3,8,2,["lumMod",15000],["lumOff",85000]],[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,3,2,false],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,247,null,null,0,0,0,0,0,0,0],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,137.7,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,12700]],0,0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,115,-20,null,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],[0,2,2],[0,2,2],0,0,1,19050]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,15,2,["lumMod",15000],["lumOff",85000]]],[99000,[3,15,2,["lumMod",25000],["lumOff",75000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[10800000,true],0,[],4,[0,[3,0,0]],[51000,[3,0,1,["alpha",75000]]],[75000,[3,0,2,["lumMod",60000],["lumOff",40000]]],[100000,[3,0,3,["lumMod",20000],["lumOff",80000],["alpha",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,326,-58,null,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,3,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[0,null],0,0,null,null,null,9525]],0,0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[2,null],[[3,null,[3,0,0]],null,[3,800000],0,0,0,0,1,25400]],0,227,-48,null,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,269,null,null,0,0,0,0,0,0,0],[2,[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,true,false,[3,null,[3,12,1,["lumMod",85000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[10800000,false],0,0,2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",75000],["lumOff",25000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[10800000,false],0,0,2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",75000],["lumOff",25000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[2,null],[[3,null,[3,0,0]],null,[3,800000],0,0,0,0,1,9525]],0,182,-50,null,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,12700]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,115,-20,null,0,0,0,0,0,0,0]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.hBarStacked] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,2,0,0,0,0,0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[8,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,0,0,2,2,true],[0,0,3,null,false,false,null,false,false,false,true],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[9,false,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],3,null,false,false,false,false,false,false,true],79,100,null,2,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[0,null],0,0,null,null,null,null]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[5,null,24,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,2,0,0,0,0,0,0],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[0,0,[0,[[4,null,[5400000,false],0,0,2,[0,[3,12,2,["lumMod",75000],["alpha",36000]]],[100000,[3,8,3,["lumMod",95000],["lumOff",5000],["alpha",42000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,true],[0,0,3,null,false,false,null,false,false,false,true],[[3,216.75,[3,0,0]],[[3,127.5,[3,12,0]],null,[1,null],0,0,0,0,1,9525]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],3,null,false,false,false,false,false,false,true],150,100,null,2,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,150,100,null,2,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,2,0,0,0,0,0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[5,null,20,[3,8,2,["lumMod",15000],["lumOff",85000]],[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,2,0,0,0,0,0,0],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,137.7,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,12700]],0,0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,2,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],[0,2,2],[0,2,2],0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,15,2,["lumMod",5000],["lumOff",95000]]],[100000,[3,15,2,["lumMod",15000],["lumOff",85000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,178.5,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,50,100,null,2,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,2,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,12700]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,2,0,0,0,0,0,0]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.hBarStackedPer] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,1,0,0,0,0,0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[8,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,0,0,2,2,true],[0,0,3,null,false,false,null,false,false,false,true],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[9,false,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],3,null,false,false,false,false,false,false,true],79,100,null,1,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[0,null],0,0,null,null,null,null]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[5,null,24,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,1,0,0,0,0,0,0],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[0,0,[0,[[4,null,[5400000,false],0,0,2,[0,[3,12,2,["lumMod",75000],["alpha",36000]]],[100000,[3,8,3,["lumMod",95000],["lumOff",5000],["alpha",42000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,true],[0,0,3,null,false,false,null,false,false,false,true],[[3,216.75,[3,0,0]],[[3,127.5,[3,12,0]],null,[1,null],0,0,0,0,1,9525]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],3,null,false,false,false,false,false,false,true],150,100,null,1,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,150,100,null,1,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,1,0,0,0,0,0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[5,null,20,[3,8,2,["lumMod",15000],["lumOff",85000]],[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,1,0,0,0,0,0,0],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,137.7,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,12700]],0,0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,1,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],[0,2,2],[0,2,2],0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,15,2,["lumMod",5000],["lumOff",95000]]],[100000,[3,15,2,["lumMod",15000],["lumOff",85000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,178.5,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,50,100,null,1,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,1,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,12700]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,100,null,1,0,0,0,0,0,0]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.hBarNormal3d] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,0,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[5,null,20,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[3,null,[3,0,0]],null,[0,null],0,0,null,null,null,null]],0,160,null,0,0,[100,null,null,false,10,0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[3,null,[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,216.75,[3,0,0]],[[3,null,[3,0,1,["lumMod",75000]]],null,[1,null],0,0,0,0,1,9525]],0,65,null,null,0,[60,null,100,false,0,0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[3,null,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,150,null,null,0,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,0,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],[[3,null,[3,8,1,["tint",75000]]],null,[1,null],0,0,0,0,1,6350]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,false,false,[3,null,[3,12,0]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[0,0,0,0,3,2,true],[0,0,null,null,false,false,null,false,false,false,true],[[3,224.4,[3,0,0]],[[3,null,[3,0,1,["lumMod",50000]]],null,[0,null],0,0,null,null,null,null]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[3,76.5,[3,0,0]],[[3,127.5,[3,12,0]],null,[1,null],0,0,null,null,null,null]],null,null,false,false,false,false,false,false,true],84,null,53,0,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[3,68.85,[3,7,1,["lumMod",75000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,76.5,[3,0,0]],[[3,null,[3,0,1,["lumMod",75000]]],null,[0,null],0,0,null,null,null,null]],0,150,null,null,0,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[3,68.85,[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[10800000,true],0,[],2,[50000,[3,0,0]],[100000,[3,0,1,["alpha",0]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,0,0,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,0,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,0,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.hBarStacked3d] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,2,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[0,null],0,0,null,null,null,null]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[5,null,20,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[3,null,[3,0,0]],null,[0,null],0,0,null,null,null,null]],0,150,null,null,2,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,19050]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[8,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,0,0,2,2,true],[0,0,null,null,false,false,null,false,false,false,true],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[8,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],null,null,false,false,false,false,false,false,true],79,null,null,2,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,150,null,null,2,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,2,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,2,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,2,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.hBarStackedPer3d] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,1,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,19050]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[0,null],0,0,null,null,null,null]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[5,null,20,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[3,null,[3,0,0]],null,[0,null],0,0,null,null,null,null]],0,150,null,null,1,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,19050]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[8,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,0,0,2,2,true],[0,0,null,null,false,false,null,false,false,false,true],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[8,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],null,null,false,false,false,false,false,false,true],79,null,null,1,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,150,null,null,1,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,2,2,false],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,1,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,1,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false],[0,0,null,null,false,false,null,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,150,null,null,1,[100,null,null,true,15,20],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.stock] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[null,0,4],[0,[[3,null,[3,15,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,9525]],[[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],[[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,null],0,0,0,0,1,9525]],150,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,null],0,0,0,0,1,9525]]]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,19050]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[0,null],0,0,null,null,null,null]],0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[null,0,4],[0,[[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,null],0,0,0,0,1,15875]],[[[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],[[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,null],0,0,0,0,1,9525]],150,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[0,null],0,0,null,null,null,9525]]]],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,19050]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[4,null,[5400000,false],0,0,2,[0,[3,12,2,["lumMod",75000],["alpha",36000]]],[100000,[3,8,3,["lumMod",95000],["lumOff",5000],["alpha",42000]]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[null,0,4],[0,[[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,null],0,0,0,0,1,15875]],[[[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],[[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,null],0,0,0,0,1,9525]],150,[[3,null,[3,12,0]],[[3,null,[3,12,1,["lumMod",85000]]],null,[1,null],0,0,0,0,1,9525]]]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[null,0,4],[0,[[3,null,[3,15,2,["lumMod",75000],["lumOff",25000]]],null,[0,null],0,0,null,null,null,9525]],[[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],[[3,null,[3,15,2,["lumMod",75000],["lumOff",25000]]],null,[0,null],0,0,null,null,null,9525]],150,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[0,null],0,0,null,null,null,9525]]]],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[null,0,4],[0,[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[0,null],0,0,null,null,null,9525]],[[[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],[[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[0,null],0,0,null,null,null,9525]],150,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[0,null],0,0,null,null,null,9525]]]],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[5,null,20,[3,8,2,["lumMod",15000],["lumOff",85000]],[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[null,0,4],[0,[[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],null,[1,null],0,0,0,0,1,12700]],[[[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],[[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[0,null],0,0,null,null,null,9525]],150,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[0,null],0,0,null,null,null,9525]]]],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,137.7,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,12700]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[null,0,4],[0,[[3,null,[3,12,0]],null,[1,null],0,0,0,0,1,9525]],[[[4,null,0,[],0,2,[0,[3,8,2,["lumMod",75000],["lumOff",25000]]],[100000,[3,8,2,["lumMod",95000],["lumOff",5000]]]],[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[0,null],0,0,null,null,null,9525]],150,[[4,null,0,[],0,2,[0,[3,12,0]],[100000,[3,12,1,["lumMod",85000]]]],[[3,null,[3,12,0]],null,[1,null],0,0,0,0,1,9525]]]],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9575]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[null,0,4],[0,[[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,null],0,0,0,2,1,25400]],[[[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],[[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[0,null],0,0,null,null,null,9525]],150,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[0,null],0,0,null,null,null,9525]]]],[2,[[3,null,[3,0,0]],[[3,null,[3,0,0]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[15,true,false,[3,null,[3,12,0]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[8,false,false,[3,null,[3,12,0]],true,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,12,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[null,0,4],[0,[[3,null,[3,12,0]],null,[1,null],0,0,0,0,1,15875]],[[[5,null,20,[3,12,0],[3,0,0]],[[3,127.5,[3,12,0]],null,[1,null],0,0,0,0,1,9525]],150,[[5,null,20,[3,0,0],[3,12,0]],[[3,127.5,[3,12,1,["lumMod",85000]]],null,[1,null],0,0,0,0,1,9525]]]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",35000],["lumOff",65000]]],null,[1,null],0,0,0,0,1,9525]],0,0,3,2,false,null,0],[[9,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[null,0,4],[0,[[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,null],0,0,0,0,1,25400]],[[[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],[[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[0,null],0,0,null,null,null,28575]],150,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[0,null],0,0,null,null,null,28575]]]],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,12700]],0,0,3,2,false,null,0],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,0,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[null,0,4],[0,[[3,null,[3,15,2,["lumMod",75000],["lumOff",25000]]],null,[1,null],0,0,0,0,1,9525]],[[[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],[[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[0,null],0,0,null,null,null,9525]],150,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[0,null],0,0,null,null,null,9525]]]]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.pie] = [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[3,null,[3,0,0]],[[3,null,[3,12,0]],null,[0,null],0,0,null,null,null,19050]],0,null,null,null,null,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[5,null,22,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[3,null,[3,12,0]],null,[0,null],0,0,null,null,null,19050]],0,null,null,null,null,0,0,0,0,0,0,0,0],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],3],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,3,null,false,false,true,false,true,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[10,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[5,null,36,[3,8,2,["lumMod",75000],["lumOff",25000]],[3,8,2,["lumMod",65000],["lumOff",35000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],3,null,false,false,true,false,true,false,false],null,null,null,null,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,null,null,null,null,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,null,0,0,0,0,0,0,0,0],[2,[[5,null,8,[3,12,0],[3,8,2,["lumMod",10000],["lumOff",90000]]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[3,127.5,[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],3],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[4,null,[5400000,false],0,0,2,[0,[3,0,0]],[100000,[3,0,2,["lumMod",60000],["lumOff",40000]]]],[[3,null,[3,12,0]],null,[0,null],0,0,null,null,null,19050]],0,null,null,null,null,0,0,0,0,0,0,0,0],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,null,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,5,null,false,false,true,false,true,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],5,null,false,false,true,false,true,false,false],null,null,null,null,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],0,[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,7,null,false,true,true,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[10,true,false,[3,null,[3,0,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],7,null,false,true,null,false,false,false,false],null,null,null,null,0,0,0,0,0,0,0,0],[2,[[3,null,[3,0,0]],[[3,null,[3,0,0]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[15,true,false,[3,null,[3,12,0]],true,[1,true,0,1,null,true,1,1]],0,[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,5,null,false,true,true,false,true,false,false],[[3,null,[3,12,0]],[[3,null,[3,0,0]],null,[0,null],0,0,null,null,null,19050]],[[9,true,false,[3,null,[3,0,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],5,null,false,true,true,false,true,false,false],null,null,null,null,0,0,0,0,0,0,0,0],[2,[[5,null,8,[3,12,1,["lumMod",95000]],[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[3,198.9,[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,5,null,false,false,true,false,true,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],5,null,false,false,true,false,true,false,false],null,null,null,null,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,null,0,0,0,0,0,0,0,0]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.doughnut] =  [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[3,null,[3,0,0]],[[3,null,[3,12,0]],null,[0,null],0,0,null,null,null,19050]],0,null,null,null,null,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[5,null,22,[3,0,0],[3,0,2,["lumMod",20000],["lumOff",80000]]],[[3,null,[3,12,0]],null,[0,null],0,0,null,null,null,19050]],0,null,null,null,null,0,0,0,0,0,0,0,0],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],3],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,true,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[10,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[5,null,36,[3,8,2,["lumMod",75000],["lumOff",25000]],[3,8,2,["lumMod",65000],["lumOff",35000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],null,null,false,false,true,false,true,false,false],null,null,null,null,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0,null,null,null,null,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,null,0,0,0,0,0,0,0,0],[2,[[5,null,8,[3,12,0],[3,8,2,["lumMod",10000],["lumOff",90000]]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[3,127.5,[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],3],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[4,null,[5400000,false],0,0,2,[0,[3,0,0]],[100000,[3,0,2,["lumMod",60000],["lumOff",40000]]]],[[3,null,[3,12,0]],null,[0,null],0,0,null,null,null,19050]],0,null,null,null,null,0,0,0,0,0,0,0,0],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,null,0,0,0,0,0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],2],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,true,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],null,null,false,false,true,false,true,false,false],null,null,null,null,0,0,0,0,0,0,0,0],[2,[[3,null,[3,0,0]],[[3,null,[3,0,0]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[15,true,false,[3,null,[3,12,0]],true,[1,true,0,1,null,true,1,1]],0,[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,true,true,false,true,false,false],[[3,null,[3,12,0]],[[3,null,[3,0,0]],null,[0,null],0,0,null,null,null,19050]],[[9,true,false,[3,null,[3,0,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],null,null,false,true,true,false,true,false,false],null,null,null,null,0,0,0,0,0,0,0,0],[2,[[5,null,8,[3,12,1,["lumMod",95000]],[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[3,198.9,[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,true,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],null,null,false,false,true,false,true,false,false],null,null,null,null,0,0,0,0,0,0,0,0]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.pie3d] =  [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[3,null,[3,0,0]],[[3,null,[3,12,0]],null,[0,null],0,0,null,null,null,25400]],0,null,null,null,null,[100,null,null,true,30,0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],0,[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,5,null,false,true,true,false,false,false,false],[[3,229.5,[3,0,0]],[[3,null,[3,0,1,["lumMod",75000]]],null,[0,null],0,0,null,null,null,19050]],[[10,false,false,[3,null,[3,0,0]],null,[1,true,0,1,0,true,0,1]],[[3,229.5,[3,12,0]],[[3,null,[3,0,0]],null,[1,null],0,0,0,0,1,12700]],5,null,false,true,null,false,false,false,false],null,null,null,null,[100,null,null,true,50,0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0,0,0],[2,[[4,null,0,[],[],3,[0,[3,12,0]],[39000,[3,12,0]],[100000,[3,12,1,["lumMod",75000]]]],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],null,[1,true,0,1,null,true,1,1]],[[3,99.45,[3,12,1,["lumMod",95000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],3],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,3,null,false,false,true,false,true,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[10,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[5,null,36,[3,8,2,["lumMod",75000],["lumOff",25000]],[3,8,2,["lumMod",65000],["lumOff",35000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],3,null,false,false,true,false,true,false,false],null,null,null,null,[100,null,null,true,50,0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,null,[100,null,null,true,30,0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,null,[100,null,null,true,30,0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0,0,0],[2,[[5,null,8,[3,12,0],[3,8,2,["lumMod",10000],["lumOff",90000]]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[3,127.5,[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],3],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[4,null,[5400000,false],0,0,2,[0,[3,0,0]],[100000,[3,0,2,["lumMod",60000],["lumOff",40000]]]],[[3,null,[3,12,0]],null,[0,null],0,0,null,null,null,50800]],0,null,null,null,null,[100,null,null,true,30,0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0,0,0],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,12,1,["lumMod",85000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,null,[100,null,null,true,30,0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],0,[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,7,null,false,true,true,false,false,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[10,true,false,[3,null,[3,0,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],7,null,false,true,null,false,false,false,false],null,null,null,null,[100,null,null,true,30,0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0,0,0],[2,[[5,null,8,[3,12,1,["lumMod",95000]],[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[18,true,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[3,198.9,[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,5,null,false,false,true,false,true,false,false],[[3,null,[3,0,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],[[9,true,false,[3,null,[3,12,0]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],5,null,false,false,true,false,true,false,false],null,null,null,null,[100,null,null,true,50,0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0,0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],4],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,0,[0,0,null,null,false,false,true,false,false,false,false],[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,null,null,null,null,[100,100,null,true,30,0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],[[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0,0,0]];
    g_oChartPresets[Asc.c_oAscChartTypeSettings.scatter] =  [[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],0,[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[5,[[3,null,[3,0,0]],[[3,null,[3,0,0]],null,[0,null],0,0,null,null,null,9525]],0],0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],true,[1,true,0,1,null,true,1,1]],0,[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[6,[[3,null,[3,0,0]],[[3,null,[3,0,0]],null,[1,null],0,0,null,null,null,9525]],2],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,16,0]],null,[1,true,0,1,null,true,1,1]],0,[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,[[9,false,false,[3,null,[3,16,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,16,2,["lumMod",40000],["lumOff",60000]]],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,16,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[5,[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[3,null,[3,0,0]],null,[1,null],0,0,null,null,null,9525]],0],0,0],[2,[[3,null,[3,6,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[20,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,0,1,null,true,1,1]],0,[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,15,2,["lumMod",5000],["lumOff",95000]]],null,[1,null],0,0,0,0,1,9525]],2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,0,0,0,25400]],0,null,null,null,null,0,0,0,0,0,[6,[[2,null],[[3,178.5,[3,0,1,["lumMod",75000]]],null,[1,null],0,0,0,0,0,34925]],0],0,0],[2,[[4,null,0,[],[],2,[43000,[3,12,0]],[100000,[3,12,1,["lumMod",95000]]]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,false,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,0,1,null,true,1,1]],0,[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,[[9,false,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[0,null],0,0,null,null,null,25400]],0,null,null,null,null,0,0,0,0,0,[4,[[3,null,[3,0,0]],[[3,null,[3,0,0]],null,[1,null],0,0,0,0,1,9525]],0],0,0],[2,[[3,null,[3,8,2,["lumMod",75000],["lumOff",25000]]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,true,false,[3,null,[3,12,1,["lumMod",85000]]],false,[1,true,0,1,null,true,1,1]],0,[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,12,1,["lumMod",50000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,191.25,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[0,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[3,[[3,null,[3,0,2,["lumMod",60000],["lumOff",40000]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0],0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[14,false,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],0,[[4,null,[5400000,false],0,0,2,[0,[3,12,1,["alpha",0]]],[100000,[3,12,1,["lumMod",95000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,8,2,["lumMod",25000],["lumOff",75000]]],null,[1,null],0,0,null,1,null,9525]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],10,[1,null],0,0,0,0,1,25400]],0,null,null,null,null,0,0,0,0,0,[5,[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["lumMod",110000],["satMod",105000],["tint",67000]]],[50000,[3,0,3,["lumMod",105000],["satMod",103000],["tint",73000]]],[100000,[3,0,3,["lumMod",105000],["satMod",109000],["tint",81000]]]],[[3,null,[3,0,1,["shade",95000]]],null,[1,null],0,0,0,0,1,9525]],0],0,0],[2,[[3,null,[3,0,0]],[[3,null,[3,0,0]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[15,true,false,[3,null,[3,12,0]],true,[1,true,0,1,null,true,1,1]],0,[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,[[9,false,false,[3,null,[3,12,0]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[0,[[3,63.75,[3,12,0]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[6,[[3,null,[3,0,0]],[[3,null,[3,12,0]],null,[1,null],0,0,null,null,null,22225]],0],0,0],[2,[[4,null,0,[],[],2,[0,[3,8,2,["lumMod",65000],["lumOff",35000]]],[100000,[3,8,2,["lumMod",85000],["lumOff",15000]]]],[[2,null],null,[0,null],0,0,null,null,null,null]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,12,1,["lumMod",95000]]],null,[1,true,0,1,null,true,1,1]],0,[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,[[9,false,false,[3,null,[3,12,1,["lumMod",75000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,12,1,["lumMod",50000]]],null,[0,null],0,0,0,0,1,9525]],[0,[[3,25.5,[3,12,1,["lumMod",95000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[6,[[4,null,[5400000,false],0,[],3,[0,[3,0,3,["satMod",103000],["lumMod",102000],["tint",94000]]],[50000,[3,0,3,["satMod",110000],["lumMod",100000],["shade",100000]]],[100000,[3,0,3,["lumMod",99000],["satMod",120000],["shade",78000]]]],[[3,null,[3,0,0]],null,[1,null],0,0,null,1,null,9525]],0],0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],false,[1,true,0,1,null,true,1,1]],0,[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,[[9,false,false,[3,null,[3,15,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,null,[3,15,2,["lumMod",25000],["lumOff",75000]]],null,[0,null],0,0,null,null,null,null]],[0,[[3,null,[3,15,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[6,[[3,null,[3,12,0]],[[3,153,[3,0,0]],null,[0,null],0,0,null,null,null,38100]],0],0,0],[2,[[3,null,[3,12,0]],[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[null,null,null,0,null,[null,null,null,null,null,null,null,null]],[[2,null],[[2,null],null,[0,null],0,0,null,null,null,null]],[16,true,false,[3,null,[3,8,2,["lumMod",50000],["lumOff",50000]]],false,[1,true,0,1,null,true,1,1]],0,[[5,null,20,[3,8,2,["lumMod",15000],["lumOff",85000]],[3,12,0]],[[2,null],null,[0,null],0,0,null,null,null,null]],0,0,[[9,false,false,[3,null,[3,8,2,["lumMod",65000],["lumOff",35000]]],null,[1,true,-60000000,1,null,true,1,1]],[[2,null],[[3,137.7,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],[0,[[3,null,[3,8,2,["lumMod",15000],["lumOff",85000]]],null,[1,null],0,0,0,0,1,9525]],0,2,2,false,1,0],[0,0,null,null,false,false,null,false,false,false,false],[0,[[2,null],null,[1,null],0,0,null,1,null,25400]],0,null,null,null,null,0,0,0,0,0,[6,[[3,null,[3,12,0]],[[3,null,[3,0,0]],null,[1,null],0,0,null,null,null,15875]],2],0,0]];

    //----------------------------------------------------------export----------------------------------------------------
  window['AscCommon'] = window['AscCommon'] || {};
  window['AscCommon'].g_oAutoShapesGroups = g_oAutoShapesGroups;
  window['AscCommon'].g_oAutoShapesTypes = g_oAutoShapesTypes;
  window['AscCommon'].g_oStandartColors = g_oStandartColors;
  window['AscCommon'].GetDefaultColorModsIndex = GetDefaultColorModsIndex;
  window['AscCommon'].GetDefaultMods = GetDefaultMods;
  window['AscCommon'].g_oUserColorScheme = g_oUserColorScheme;
  window['AscCommon'].g_oUserTexturePresets = g_oUserTexturePresets;
  window['AscCommon'].g_oPresetTxWarpGroups = g_oPresetTxWarpGroups;
  window['AscCommon'].g_PresetTxWarpTypes = g_PresetTxWarpTypes;
  window['AscCommon'].g_oChartPresets = g_oChartPresets;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

// Import
var g_memory = AscFonts.g_memory;
var DecodeBase64Char = AscFonts.DecodeBase64Char;
var b64_decode = AscFonts.b64_decode;
    
var g_nodeAttributeEnd = AscCommon.g_nodeAttributeEnd;

var c_oAscShdClear = Asc.c_oAscShdClear;
var c_oAscColor = Asc.c_oAscColor;
var c_oAscFill = Asc.c_oAscFill;

var c_dScalePPTXSizes = 36000;
function IsHiddenObj(object)
{
    if (!object)
        return false;
    var _uniProps = object.nvSpPr;
    if (!_uniProps)
        _uniProps = object.nvPicPr;
    if (!_uniProps)
        _uniProps = object.nvGrpSpPr;

    if (!_uniProps)
        return false;

    if (_uniProps.cNvPr && _uniProps.cNvPr.isHidden)
        return true;

    return false;
}

function CBuilderImages(blip_fill, full_url, image_shape, sp_pr, ln, text_pr, para_text_pr, run, paragraph)
{
    this.Url = full_url;
    this.BlipFill = blip_fill;
    this.ImageShape = image_shape;
    this.SpPr = sp_pr;
    this.Ln = ln;

    this.TextPr     = text_pr;
    this.ParaTextPr = para_text_pr;
    this.Run        = run;
    this.Paragraph  = paragraph;
    this.AdditionalUrls = [];//для wmf, ole
}
CBuilderImages.prototype =
{
    SetUrl : function(url)
    {
        if(url !== "error")
        {
            var oCopyFill, oCopyBlipFill, oCopyLn;
            if(!this.Ln && this.SpPr && this.SpPr.Fill)
            {
                oCopyFill = this.SpPr.Fill.createDuplicate();
                if(oCopyFill.fill && oCopyFill.fill.type === c_oAscFill.FILL_TYPE_BLIP)
                {
                    oCopyFill.fill.setRasterImageId(url);
                    this.SpPr.setFill(oCopyFill);
                }
            }
            if(this.Ln && this.SpPr && this.SpPr === this.Ln && this.Ln.Fill && this.Ln.Fill.fill && this.Ln.Fill.fill.type === c_oAscFill.FILL_TYPE_BLIP)
            {
                oCopyLn = this.Ln.createDuplicate();
                oCopyLn.Fill.fill.setRasterImageId(url);
                this.SpPr.setLn(oCopyLn);
            }
            if(this.ImageShape && this.ImageShape.blipFill)
            {
                oCopyBlipFill = this.ImageShape.blipFill.createDuplicate();
                oCopyBlipFill.setRasterImageId(url);
                this.ImageShape.setBlipFill(oCopyBlipFill);
            }
            if(this.TextPr && !this.Ln)
            {
                if(this.Paragraph)
                {
                    var oPr = this.Paragraph.Pr;
                    if(oPr.DefaultRunPr && oPr.DefaultRunPr.Unifill && oPr.DefaultRunPr.Unifill.fill && oPr.DefaultRunPr.Unifill.fill.type === c_oAscFill.FILL_TYPE_BLIP)
                    {
                        var Pr = this.Paragraph.Pr.Copy();
                        Pr.DefaultRunPr.Unifill.fill.setRasterImageId(url);
                        this.Paragraph.Set_Pr(Pr);
                    }
                }
                else if(this.ParaTextPr || this.Run)
                {
                    if(this.ParaTextPr && this.ParaTextPr.Value && this.ParaTextPr.Value.Unifill && this.ParaTextPr.Value.Unifill.fill && this.ParaTextPr.Value.Unifill.fill.type === c_oAscFill.FILL_TYPE_BLIP)
                    {
                        oCopyFill = this.ParaTextPr.Value.Unifill.createDuplicate();
                        oCopyFill.fill.setRasterImageId(url);
                        this.ParaTextPr.Set_Unifill(oCopyFill);
                    }
                    if(this.Run && this.Run.Pr && this.Run.Pr.Unifill && this.Run.Pr.Unifill.fill && this.Run.Pr.Unifill.fill.type === c_oAscFill.FILL_TYPE_BLIP)
                    {
                        oCopyFill = this.Run.Pr.Unifill.createDuplicate();
                        oCopyFill.fill.setRasterImageId(url);
                        this.Run.Set_Unifill(oCopyFill);
                    }
                }
            }
            this.BlipFill.RasterImageId = url;
        }
    }
};

function BinaryPPTYLoader()
{
    this.stream = null;
    this.presentation = null;

    this.TempGroupObject = null;
    this.TempMainObject = null;

    this.IsThemeLoader = false;
    this.Api = null;

    this.map_table_styles = {};
    this.NextTableStyleId = 0;

    this.ImageMapChecker = null;

    this.IsUseFullUrl = false;
	this.insertDocumentUrlsData = null;
    this.RebuildImages = [];

    this.textBodyTextFit = [];
    this.aSlideLayouts = [];
    this.aThemes = [];
	this.DocReadResult = null;

	this.arr_connectors = [];
	this.map_shapes_by_id = {};



	this.ClearConnectorsMaps = function(){
        this.arr_connectors.length = 0;
        this.map_shapes_by_id = {};
    };

	this.AssignConnectorsId = function () {
	    var oPr = null;
        for(var i = 0; i < this.arr_connectors.length; ++i){
            oPr = this.arr_connectors[i].nvSpPr.nvUniSpPr;
            if(AscFormat.isRealNumber(oPr.stCnxId)){
                if(AscCommon.isRealObject(this.map_shapes_by_id[oPr.stCnxId])){
                    oPr.stCnxId = this.map_shapes_by_id[oPr.stCnxId].Id;
                }
                else{
                    oPr.stCnxId = null;
                    oPr.stCnxIdx = null;
                }
            }
            if(AscFormat.isRealNumber(oPr.endCnxId)){
                if(AscCommon.isRealObject(this.map_shapes_by_id[oPr.endCnxId])){
                    oPr.endCnxId = this.map_shapes_by_id[oPr.endCnxId].Id;
                }
                else{
                    oPr.endCnxId = null;
                    oPr.endCnxIdx = null;
                }
            }
            this.arr_connectors[i].nvSpPr.setUniSpPr(oPr.copy());
        }
        this.ClearConnectorsMaps();
    };

    this.Start_UseFullUrl = function(insertDocumentUrlsData)
    {
        this.IsUseFullUrl = true;
		this.insertDocumentUrlsData = insertDocumentUrlsData;
    };

    this.End_UseFullUrl = function()
    {
        var _result = this.RebuildImages;

        this.IsUseFullUrl = false;
        this.RebuildImages = [];

        return _result;
    };

    this.Check_TextFit = function()
    {
        for(var i = 0; i < this.textBodyTextFit.length; ++i)
        {
            this.textBodyTextFit[i].checkTextFit();
        }
        this.textBodyTextFit.length = 0;
    };

    this.Load = function(base64_ppty, presentation)
    {
        this.presentation = presentation;
        this.ImageMapChecker = {};

		var isBase64 = typeof base64_ppty === 'string';
		var srcLen = isBase64 ? base64_ppty.length : base64_ppty.length;
        var nWritten = 0;

        var index = 0;
        var read_main_prop = "";
        while (true)
        {
            var _c = isBase64 ? base64_ppty.charCodeAt(index) : base64_ppty[index];
            if (_c == ";".charCodeAt(0))
                break;

            read_main_prop += String.fromCharCode(_c);
            index++;
        }
        index++;

        if ("PPTY" != read_main_prop)
            return false;

        read_main_prop = "";
        while (true)
        {
            var _c = isBase64 ? base64_ppty.charCodeAt(index) : base64_ppty[index];
            if (_c == ";".charCodeAt(0))
                break;

            read_main_prop += String.fromCharCode(_c);
            index++;
        }
        index++;

        var _version_num_str = read_main_prop.substring(1);
		var version = 1;
		if(_version_num_str.length > 0)
        {
            version = _version_num_str - 0;
        }
        read_main_prop = "";
        while (true)
        {
            var _c = isBase64 ? base64_ppty.charCodeAt(index) : base64_ppty[index];
            if (_c == ";".charCodeAt(0))
                break;

            read_main_prop += String.fromCharCode(_c);
            index++;
        }
        index++;

		if (Asc.c_nVersionNoBase64 !== version) {
			var dstLen_str = read_main_prop;

			var dstLen = parseInt(dstLen_str);

			var pointer = g_memory.Alloc(dstLen);
			this.stream = new AscCommon.FileStream(pointer.data, dstLen);
			this.stream.obj = pointer.obj;

			var dstPx = this.stream.data;

			if (window.chrome)
			{
				while (index < srcLen)
				{
					var dwCurr = 0;
					var i;
					var nBits = 0;
					for (i=0; i<4; i++)
					{
						if (index >= srcLen)
							break;
						var nCh = DecodeBase64Char(isBase64 ? base64_ppty.charCodeAt(index++) : base64_ppty[index++]);
						if (nCh == -1)
						{
							i--;
							continue;
						}
						dwCurr <<= 6;
						dwCurr |= nCh;
						nBits += 6;
					}

					dwCurr <<= 24-nBits;
					for (i=0; i<nBits/8; i++)
					{
						dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
						dwCurr <<= 8;
					}
				}
			}
			else
			{
				var p = b64_decode;
				while (index < srcLen)
				{
					var dwCurr = 0;
					var i;
					var nBits = 0;
					for (i=0; i<4; i++)
					{
						if (index >= srcLen)
							break;
						var nCh = p[isBase64 ? base64_ppty.charCodeAt(index++) : base64_ppty[index++]];
						if (nCh == undefined)
						{
							i--;
							continue;
						}
						dwCurr <<= 6;
						dwCurr |= nCh;
						nBits += 6;
					}

					dwCurr <<= 24-nBits;
					for (i=0; i<nBits/8; i++)
					{
						dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
						dwCurr <<= 8;
					}
				}
			}
		} else {
			this.stream = new AscCommon.FileStream();
			this.stream.obj    = null;
			this.stream.data   = base64_ppty;
			this.stream.size   = base64_ppty.length;
			//skip header
			this.stream.EnterFrame(index);
			this.stream.Seek2(index);
		}
		
        this.presentation.ImageMap = {};
        this.presentation.Fonts = [];

        if (presentation.globalTableStyles)
            this.NextTableStyleId = this.presentation.globalTableStyles.length;

        this.LoadDocument();

        AscFormat.checkPlaceholdersText();

        this.ImageMapChecker = null;
    }

    this.LoadDocument = function()
    {
        // чтение формата ppty
        var _main_tables = {};
        var s = this.stream;
        var err = 0;

        err = s.EnterFrame(5 * 30);
        if (err != 0)
            return err;

        for (var i = 0; i < 30; i++)
        {
            var _type = s.GetUChar();
            if (0 == _type)
                break;

            _main_tables["" + _type] = s.GetULong();
        }

        if (undefined != _main_tables["255"])
        {
            // signature
            s.Seek2(_main_tables["255"]);
            var _sign = s.GetString1(4);
            var _ver = s.GetULong();
        }

        if (!this.IsThemeLoader)
        {
            if (undefined != _main_tables["1"])
            {
                // app
                s.Seek2(_main_tables["1"]);

                this.presentation.App = new CApp();
                this.presentation.App.fromStream(s);
            }

            if (undefined != _main_tables["2"])
            {
                // core
                s.Seek2(_main_tables["2"]);

                this.presentation.Core = new CCore();
                this.presentation.Core.fromStream(s);
            }
        }

        if (undefined != _main_tables["3"])
        {
            // core
            s.Seek2(_main_tables["3"]);

            this.presentation.pres = new CPres();
            var pres = this.presentation.pres;

            pres.fromStream(s, this);

            this.presentation.defaultTextStyle = pres.defaultTextStyle;
            this.presentation.Width = pres.SldSz.cx / c_dScalePPTXSizes;
            this.presentation.Height = pres.SldSz.cy / c_dScalePPTXSizes;
        }

        if (!this.IsThemeLoader)
        {
            if (undefined != _main_tables["4"])
            {
                // view props
                s.Seek2(_main_tables["4"]);
                this.presentation.ViewProps = this.ReadViewProps();
            }

            if (undefined != _main_tables["5"])
            {
                // vmldrawing
                s.Seek2(_main_tables["5"]);
                this.presentation.VmlDrawing = this.ReadVmlDrawing();
            }

            if (undefined != _main_tables["6"])
            {
                // tablestyles
                s.Seek2(_main_tables["6"]);
                this.presentation.TableStyles = this.ReadTableStyles();
            }
            if (undefined != _main_tables["7"])
            {
                // presprops
                s.Seek2(_main_tables["7"]);
                this.ReadPresProps(this.presentation);
            }
        }

        this.aThemes.length = 0;
        if (undefined != _main_tables["20"])
        {
            // themes
            s.Seek2(_main_tables["20"]);

            var _themes_count = s.GetULong();
            for (var i = 0; i < _themes_count; i++)
                this.aThemes[i] = this.ReadTheme();
        }

        if (undefined != _main_tables["22"])
        {
            // slide masters
            s.Seek2(_main_tables["22"]);

            var _sm_count = s.GetULong();
            for (var i = 0; i < _sm_count; i++)
            {
                this.presentation.slideMasters[i] = this.ReadSlideMaster();
                this.presentation.slideMasters[i].setSlideSize(this.presentation.Width, this.presentation.Height);
            }
        }

        this.aSlideLayouts.length = 0;
        if (undefined != _main_tables["23"])
        {
            // slide masters
            s.Seek2(_main_tables["23"]);

            var _sl_count = s.GetULong();
            for (var i = 0; i < _sl_count; i++)
            {
                this.aSlideLayouts[i] = this.ReadSlideLayout();
                this.aSlideLayouts[i].setSlideSize(this.presentation.Width, this.presentation.Height);
            }
        }

        if (!this.IsThemeLoader)
        {
            if (undefined != _main_tables["24"])
            {
                // slides
                s.Seek2(_main_tables["24"]);

                var _s_count = s.GetULong();
                var bOldVal;
                if(this.Api)
                {
                    bOldVal = this.Api.bNoSendComments;
                    this.Api.bNoSendComments = true;
                }
                for (var i = 0; i < _s_count; i++)
                {
                    this.presentation.insertSlide(i, this.ReadSlide(i)) ;
                    this.presentation.Slides[i].setSlideSize(this.presentation.Width, this.presentation.Height);
                }
                if(this.Api)
                {
                    this.Api.bNoSendComments = bOldVal;
                }
            }

            if (undefined != _main_tables["25"])
            {
                // slides
                s.Seek2(_main_tables["25"]);

                var _nm_count = s.GetULong();
                for (var i = 0; i < _nm_count; i++){
                    this.presentation.notesMasters[i] = this.ReadNoteMaster();
                    this.presentation.notesMasters[i].setTheme(this.aThemes[0]);//TODO: убрать после того как будут сделаны рельсы
                }
            }

            if (undefined != _main_tables["26"])
            {
                // slides
                s.Seek2(_main_tables["26"]);

                var _n_count = s.GetULong();
                for (var i = 0; i < _n_count; i++)
                    this.presentation.notes[i] = this.ReadNote();
            }
        }

        // теперь нужно прочитать используемые в презентации шрифты и картинки
        if (null == this.ImageMapChecker)
        {
            if (undefined != _main_tables["42"])
            {
                s.Seek2(_main_tables["42"]);

                var _type = s.GetUChar();
                var _len = s.GetULong();

                s.Skip2(1); // strat attr

                var _cur_ind = 0;

                while (true)
                {
                    var _at = s.GetUChar();
                    if (_at == g_nodeAttributeEnd)
                        break;

                    var image_id = s.GetString2();
                    if (this.IsThemeLoader)
                    {
                        image_id = "theme" + (this.Api.ThemeLoader.CurrentLoadThemeIndex + 1) + "/media/" + image_id;
                    }

                    this.presentation.ImageMap[_cur_ind++] = image_id;
                }
            }
        }
        else
        {
            var _cur_ind = 0;
            for (var k in this.ImageMapChecker)
            {
                if (this.IsThemeLoader)
                {
                    image_id = "theme" + (this.Api.ThemeLoader.CurrentLoadThemeIndex + 1) + "/media/" + k;
                }

                this.presentation.ImageMap[_cur_ind++] = k;
            }
        }

        if (undefined != _main_tables["43"])
        {
            s.Seek2(_main_tables["43"]);

            var _type = s.GetUChar();
            var _len = s.GetULong();

            s.Skip2(1); // strat attr

            var _cur_ind = 0;

            while (true)
            {
                var _at = s.GetUChar();
                if (_at == g_nodeAttributeEnd)
                    break;

                var f_name = s.GetString2();

                this.presentation.Fonts[this.presentation.Fonts.length] = new AscFonts.CFont(f_name, 0, "", 0, 0x0F);
            }
        }

        // все загружено, осталось расставить связи и загрузить картинки тем и шаблонов
        if (undefined != _main_tables["41"])
        {
            s.Seek2(_main_tables["41"]);

            s.Skip2(5); // type + len

            var _count = s.GetULong();

            for (var i = 0; i < _count; i++)
            {
                var _master_type = s.GetUChar(); // must be 0
                this.ReadMasterInfo(i);
            }
        }

        if (!this.IsThemeLoader)
        {
            if (undefined != _main_tables["40"])
            {
                s.Seek2(_main_tables["40"]);

                s.Skip2(6); // type + len + start attr

                var _slideNum = 0;
                while (true)
                {
                    var _at = s.GetUChar();
                    if (_at == g_nodeAttributeEnd)
                        break;

                    var indexL = s.GetULong();
                    this.presentation.Slides[_slideNum].setLayout(this.aSlideLayouts[indexL]);
                    this.presentation.Slides[_slideNum].Master = this.aSlideLayouts[indexL].Master;
                    _slideNum++;
                }
            }
			if (undefined != _main_tables["45"])
			{
				s.Seek2(_main_tables["45"]);
				s.Skip2(6); // type + len + start attr

				var _slideNum = 0;
				while (true)
				{
					var _at = s.GetUChar();
					if (_at == g_nodeAttributeEnd)
						break;

					var indexL = s.GetLong();
					this.presentation.Slides[_slideNum].setNotes(this.presentation.notes[indexL]);
                    ++_slideNum;
				}
			}
			if (undefined != _main_tables["46"])
			{
				s.Seek2(_main_tables["46"]);
				s.Skip2(6); // type + len + start attr

				var _noteNum = 0;
				while (true)
				{
					var _at = s.GetUChar();
					if (_at == g_nodeAttributeEnd)
						break;

					var indexL = s.GetLong();
                    this.presentation.notes[_noteNum].setNotesMaster(this.presentation.notesMasters[indexL]);
					_noteNum++;
				}
			}
			if (undefined != _main_tables["47"])
			{
				s.Seek2(_main_tables["47"]);
				s.Skip2(6); // type + len + start attr

				var _noteMasterNum = 0;
				while (true)
				{
					var _at = s.GetUChar();
					if (_at == g_nodeAttributeEnd)
						break;

					var indexL = s.GetLong();
					var notesMaster = this.presentation.notesMasters[_noteMasterNum];
					var notesMasterTheme = this.aThemes[indexL];
					if (notesMaster && notesMasterTheme) {
						notesMaster.setTheme(notesMasterTheme);
					}
					_noteMasterNum++;
				}
			}
        }

        if (this.Api != null && !this.IsThemeLoader)
        {
            if (this.aThemes.length == 0)
            {
                this.aThemes[0] = AscFormat.GenerateDefaultTheme(this.presentation);
            }
            if (this.presentation.slideMasters.length == 0)
            {
                this.presentation.slideMasters[0] = AscFormat.GenerateDefaultMasterSlide(this.aThemes[0]);
                this.aSlideLayouts[0] = this.presentation.slideMasters[0].sldLayoutLst[0];
            }
            if(this.presentation.slideMasters[0].sldLayoutLst.length === 0)
            {
                this.presentation.slideMasters[0].sldLayoutLst[0] = AscFormat.GenerateDefaultSlideLayout(this.presentation.slideMasters[0]);
                this.aSlideLayouts[0] = this.presentation.slideMasters[0].sldLayoutLst[0];
            }

            if(this.presentation.notesMasters.length === 0)
            {
                this.presentation.notesMasters[0] = AscCommonSlide.CreateNotesMaster();
                var oNotesTheme = this.aThemes[0].createDuplicate();
                oNotesTheme.presentation = this.presentation;
                this.aThemes.push(oNotesTheme);
                this.presentation.notesMasters[0].setTheme(oNotesTheme);
            }
            if (this.presentation.Slides.length == 0)
            {
                //this.presentation.Slides[0] = AscFormat.GenerateDefaultSlide(this.aSlideLayouts[0]);
            }
            var _slides = this.presentation.Slides;
            var _slide;
            for(var i = 0; i < _slides.length; ++i)
            {
                _slide = _slides[i];
                if(!_slide.notes){
                    _slide.setNotes(AscCommonSlide.CreateNotes());
                    _slide.notes.setSlide(_slide);
                    _slide.notes.setNotesMaster(this.presentation.notesMasters[0]);
                }
            }
            //var _editor = this.Api;
            //_editor.sync_InitEditorThemes(_editor.ThemeLoader.Themes.EditorThemes, _editor.ThemeLoader.Themes.DocumentThemes);
        }
        else if (this.Api != null && this.IsThemeLoader)
        {
            var theme_loader = this.Api.ThemeLoader;
            var _info = theme_loader.themes_info_editor[theme_loader.CurrentLoadThemeIndex];
            _info.ImageMap = this.presentation.ImageMap;
            _info.FontMap = this.presentation.Fonts;
        }
    }

    this.ReadMasterInfo = function(indexMaster)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        var master = this.presentation.slideMasters[indexMaster];

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    var indexTh = s.GetULong();
                    master.setTheme(this.aThemes[indexTh]);
                    master.ThemeIndex = -indexTh - 1;
                    break;
                }
                case 1:
                {
                    s.GetString2A();
                    break;
                }
                default:
                    break;
            }
        }

        var _lay_count = s.GetULong();
        for (var i = 0; i < _lay_count; i++)
        {
            s.Skip2(6); // type + len

            while (true)
            {
                var _at = s.GetUChar();
                if (_at == g_nodeAttributeEnd)
                    break;

                switch (_at)
                {
                    case 0:
                    {
                        var indexL = s.GetULong();
                        master.addToSldLayoutLstToPos(master.sldLayoutLst.length, this.aSlideLayouts[indexL]);
                        this.aSlideLayouts[indexL].setMaster( master);
                        break;
                    }
                    case 1:
                    {
                        s.GetString2A();
                        break;
                    }
                    default:
                        break;
                }
            }
        }

        s.Seek2(_end_rec);

        if (this.Api != null && this.IsThemeLoader)
        {
            var theme_loader = this.Api.ThemeLoader;

            var theme_load_info = new CThemeLoadInfo();
            theme_load_info.Master = master;
            theme_load_info.Theme = master.Theme;

            var _lay_cnt = master.sldLayoutLst.length;
            for (var i = 0; i < _lay_cnt; i++)
                theme_load_info.Layouts[i] = master.sldLayoutLst[i];

            theme_loader.themes_info_editor[theme_loader.CurrentLoadThemeIndex] = theme_load_info;
        }
    }

    this.ReadViewProps = function()
    {
        return null;
    }
    this.ReadVmlDrawing = function()
    {
        return null;
    }
    this.ReadPresProps = function(presentation)
    {
        var s = this.stream;

        var _type = s.GetUChar();

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    s.SkipRecord();
                    break;
                }
                case 1:
                {
                    presentation.showPr = this.ReadShowPr();
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
    }
    this.ReadShowPr = function()
    {
        var showPr = new CShowPr();
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    showPr.loop = s.GetBool();
                    break;
                }
                case 1:
                {
                    showPr.showAnimation = s.GetBool();
                    break;
                }
                case 2:
                {
                    showPr.showNarration = s.GetBool();
                    break;
                }
                case 3:
                {
                    showPr.useTimings = s.GetBool();
                    break;
                }
                default:
                    break;
            }
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    //todo browseShowScrollbar
                    showPr.browse = true;
                    s.SkipRecord();
                    break;
                }
                case 1:
                {
                    this.ReadShowPrCustShow(showPr);
                    break;
                }
                case 2:
                {
                    this.ReadShowPrKiosk(showPr);
                    break;
                }
                case 3:
                {
                    showPr.penClr = this.ReadUniColor();
                    break;
                }
                case 4:
                {
                    showPr.present = true;
                    s.SkipRecord();
                    break;
                }
                case 5:
                {
                    if (!showPr.show){
                        showPr.show = {showAll: null, range: null, custShow: null};
                    }
                    showPr.show.showAll = true;
                    s.SkipRecord();
                    break;
                }
                case 6:
                {
                    this.ReadShowPrSldRg(showPr);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return showPr;
    }
    this.ReadShowPrCustShow = function(showPr)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    if (!showPr.show){
                        showPr.show = {showAll: null, range: null, custShow: null};
                    }
                    showPr.show.custShow = s.GetLong();
                    break;
                }
                default:
                    break;
            }
        }

        s.Seek2(_end_rec);
    }
    this.ReadShowPrKiosk = function(showPr)
    {
        showPr.kiosk = {restart: null};
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    showPr.kiosk.restart = s.GetLong();
                    break;
                }
                default:
                    break;
            }
        }

        s.Seek2(_end_rec);
    }
    this.ReadShowPrSldRg = function(showPr)
    {
        if (!showPr.show){
            showPr.show = {showAll: null, range: null, custShow: null};
        }
        showPr.show.range = {start: null, end: null};
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    showPr.show.range.start = s.GetLong();
                    break;
                }
                case 1:
                {
                    showPr.show.range.end = s.GetLong();
                    break;
                }
                default:
                    break;
            }
        }

        s.Seek2(_end_rec);
    }
    this.ReadTableStyles = function()
    {
        //var _styles = this.presentation.globalTableStyles;
        var s = this.stream;

        var _type = s.GetUChar();

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        s.Skip2(1); // start attributes

        var _old_default = this.presentation.DefaultTableStyleId;
        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    var _def = s.GetString2();
                    this.presentation.DefaultTableStyleId = _def;
                    break;
                }
                default:
                    break;
            }
        }

        var _type = s.GetUChar(); // 0!!!
        s.Skip2(4); // len


        while (s.cur < _end_rec)
        {
            s.Skip2(1);
            this.ReadTableStyle();
        }

        if(!this.presentation.globalTableStyles.Style[this.presentation.DefaultTableStyleId])
        {
            this.presentation.DefaultTableStyleId = _old_default;
        }
        s.Seek2(_end_rec);
    }

    this.ReadTableStyle = function(bNotAddStyle)
    {
        var s = this.stream;

        var _style = new CStyle("", null, null, styletype_Table);

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    var _id = s.GetString2();
                   // _style.Id = _id;
					if(AscCommon.isRealObject(this.presentation.TableStylesIdMap) && !bNotAddStyle)
						this.presentation.TableStylesIdMap[_style.Id] = true;
                    this.map_table_styles[_id] = _style;
                    break;
                }
                case 1:
                {
                    _style.Name = s.GetString2();
                    break;
                }
                default:
                    break;
            }
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    var _end_rec2 = s.cur + s.GetLong() + 4;

                    while (s.cur < _end_rec2)
                    {
                        var _at2 = s.GetUChar();
                        switch (_at2)
                        {
                            case 0:
                            {
                                var _end_rec3 = s.cur + s.GetLong() + 4;
                                while (s.cur < _end_rec3)
                                {
                                    var _at3 = s.GetUChar();
                                    switch (_at3)
                                    {
                                        case 0:
                                        {
                                            var _unifill = this.ReadUniFill();
                                            if (_unifill && _unifill.fill !== undefined && _unifill.fill != null)
                                            {
                                                if (undefined === _style.TablePr.Shd || null == _style.TablePr.Shd)
                                                {
                                                    _style.TablePr.Shd = new CDocumentShd();
                                                    _style.TablePr.Shd.Value = c_oAscShdClear;
                                                }
                                                _style.TablePr.Shd.Unifill = _unifill;
                                            }
                                        }
                                        default:
                                        {
                                            s.SkipRecord();
                                            break;
                                        }
                                    }
                                }
                                break;
                            }
                            case 1:
                            {
                                if (undefined === _style.TablePr.Shd || null == _style.TablePr.Shd)
                                {
                                    _style.TablePr.Shd = new CDocumentShd();
                                    _style.TablePr.Shd.Value = c_oAscShdClear;
                                }
                                _style.TablePr.Shd.FillRef = this.ReadStyleRef();
                                break;
                            }
                            default:
                            {
                                s.SkipRecord();
                                break;
                            }
                        }
                    }

                    s.Seek2(_end_rec2);
                    break;
                }
                case 1:
                {
                    _style.TableWholeTable = this.ReadTableStylePart();
                    break;
                }
                case 2:
                {
                    _style.TableBand1Horz = this.ReadTableStylePart();
                    break;
                }
                case 3:
                {
                    _style.TableBand2Horz = this.ReadTableStylePart();
                    break;
                }
                case 4:
                {
                    _style.TableBand1Vert = this.ReadTableStylePart();
                    break;
                }
                case 5:
                {
                    _style.TableBand2Vert = this.ReadTableStylePart();
                    break;
                }
                case 6:
                {
                    _style.TableLastCol = this.ReadTableStylePart();
                    break;
                }
                case 7:
                {
                    _style.TableFirstCol = this.ReadTableStylePart();
                    break;
                }
                case 8:
                {
                    _style.TableFirstRow = this.ReadTableStylePart();
                    break;
                }
                case 9:
                {
                    _style.TableLastRow = this.ReadTableStylePart();
                    break;
                }
                case 10:
                {
                    _style.TableBRCell = this.ReadTableStylePart();
                    break;
                }
                case 11:
                {
                    _style.TableBLCell = this.ReadTableStylePart();
                    break;
                }
                case 12:
                {
                    _style.TableTRCell = this.ReadTableStylePart();
                    break;
                }
                case 13:
                {
                    _style.TableTLCell = this.ReadTableStylePart();
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);

        if(_style.TableWholeTable.TablePr.TableBorders.InsideH)
        {
            _style.TablePr.TableBorders.InsideH = _style.TableWholeTable.TablePr.TableBorders.InsideH;
            delete _style.TableWholeTable.TablePr.TableBorders.InsideH;
        }
        if(_style.TableWholeTable.TablePr.TableBorders.InsideV)
        {
            _style.TablePr.TableBorders.InsideV = _style.TableWholeTable.TablePr.TableBorders.InsideV;
            delete _style.TableWholeTable.TablePr.TableBorders.InsideV;
        }
        if(_style.TableWholeTable.TableCellPr.TableCellBorders.Top)
        {
            _style.TablePr.TableBorders.Top = _style.TableWholeTable.TableCellPr.TableCellBorders.Top;
            delete _style.TableWholeTable.TableCellPr.TableCellBorders.Top;
        }
        if(_style.TableWholeTable.TableCellPr.TableCellBorders.Bottom)
        {
            _style.TablePr.TableBorders.Bottom = _style.TableWholeTable.TableCellPr.TableCellBorders.Bottom;
            delete _style.TableWholeTable.TableCellPr.TableCellBorders.Bottom;
        }
        if(_style.TableWholeTable.TableCellPr.TableCellBorders.Left)
        {
            _style.TablePr.TableBorders.Left = _style.TableWholeTable.TableCellPr.TableCellBorders.Left;
            delete _style.TableWholeTable.TableCellPr.TableCellBorders.Left;
        }
        if(_style.TableWholeTable.TableCellPr.TableCellBorders.Right)
        {
            _style.TablePr.TableBorders.Right = _style.TableWholeTable.TableCellPr.TableCellBorders.Right;
            delete _style.TableWholeTable.TableCellPr.TableCellBorders.Right;
        }
		if(bNotAddStyle)
		{
			return _style;
		}
		else
		{
			if(this.presentation.globalTableStyles)
				this.presentation.globalTableStyles.Add(_style);
		}
    };

    this.ReadTableStylePart = function()
    {
        var s = this.stream;

        var _part = new CTableStylePr();

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    var _end_rec2 = s.cur + s.GetLong() + 4;

                    s.Skip2(1); // start attributes

                    var _i, _b;
                    while (true)
                    {
                        var _at2 = s.GetUChar();
                        if (_at2 == g_nodeAttributeEnd)
                            break;

                        switch (_at2)
                        {
                            case 0:
                            {
                                _i = s.GetUChar();
                                break;
                            }
                            case 1:
                            {
                                _b = s.GetUChar();
                                break;
                            }
                            default:
                                break;
                        }
                    }

                    if(_i === 0)
                    {
                        _part.TextPr.Italic = true;
                    }
                    else if(_i === 1)
                    {
                        _part.TextPr.Italic = false;
                    }

                    if(_b === 0)
                    {
                        _part.TextPr.Bold = true;
                    }
                    else if(_b === 1)
                    {
                        _part.TextPr.Bold = false;
                    }

                    while (s.cur < _end_rec2)
                    {
                        var _at3 = s.GetUChar();
                        switch (_at3)
                        {
                            case 0:
                            {
                                _part.TextPr.FontRef = this.ReadFontRef();
                                break;
                            }
                            case 1:
                            {
                                var _Unicolor = this.ReadUniColor();
                                if(_Unicolor && _Unicolor.color)
                                {
                                    _part.TextPr.Unifill = new AscFormat.CUniFill();
                                    _part.TextPr.Unifill.fill = new AscFormat.CSolidFill();
                                    _part.TextPr.Unifill.fill.color = _Unicolor;
                                }
                                break;
                            }
                            default:
                            {
                                s.SkipRecord();
                                break;
                            }
                        }
                    }

                    s.Seek2(_end_rec2);
                    break;
                }
                case 1:
                {
                    var _end_rec2 = s.cur + s.GetLong() + 4;

                    while (s.cur < _end_rec2)
                    {
                        var _at2 = s.GetUChar();
                        switch (_at2)
                        {
                            case 0:
                            {
                                this.ReadTcBdr(_part);
                                break;
                            }
                            case 1:
                            {
                                if (undefined === _part.TableCellPr.Shd || null == _part.TableCellPr.Shd)
                                {
                                    _part.TableCellPr.Shd = new CDocumentShd();
                                    _part.TableCellPr.Shd.Value = c_oAscShdClear;
                                }
                                _part.TableCellPr.Shd.FillRef = this.ReadStyleRef();
                                break;
                            }
                            case 2:
                            {
                                var _end_rec3 = s.cur + s.GetLong() + 4;
                                while (s.cur < _end_rec3)
                                {
                                    var _at3 = s.GetUChar();
                                    switch (_at3)
                                    {
                                        case 0:
                                        {
                                            var _unifill = this.ReadUniFill();
                                            if (_unifill && _unifill.fill !== undefined && _unifill.fill != null)
                                            {
                                                if (undefined === _part.TableCellPr.Shd || null == _part.TableCellPr.Shd)
                                                {
                                                    _part.TableCellPr.Shd = new CDocumentShd();
                                                    _part.TableCellPr.Shd.Value = c_oAscShdClear;
                                                }
                                                _part.TableCellPr.Shd.Unifill = _unifill;
                                            }
                                            break;
                                        }
                                        default:
                                        {
                                            s.SkipRecord();
                                            break;
                                        }
                                    }
                                }
                                break;
                            }
                            case 3:
                            {
                                s.SkipRecord();
                                break;
                            }
                            default:
                            {
                                s.SkipRecord();
                                break;
                            }
                        }
                    }

                    s.Seek2(_end_rec2);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return _part;
    }

    this.ReadTcBdr = function(_part)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    _part.TableCellPr.TableCellBorders.Left = new CDocumentBorder();
                    this.ReadTableBorderLineStyle(_part.TableCellPr.TableCellBorders.Left);
                    break;
                }
                case 1:
                {
                    _part.TableCellPr.TableCellBorders.Right = new CDocumentBorder();
                    this.ReadTableBorderLineStyle(_part.TableCellPr.TableCellBorders.Right);
                    break;
                }
                case 2:
                {
                    _part.TableCellPr.TableCellBorders.Top = new CDocumentBorder();
                    this.ReadTableBorderLineStyle(_part.TableCellPr.TableCellBorders.Top);
                    break;
                }
                case 3:
                {
                    _part.TableCellPr.TableCellBorders.Bottom = new CDocumentBorder();
                    this.ReadTableBorderLineStyle(_part.TableCellPr.TableCellBorders.Bottom);
                    break;
                }
                case 4:
                {
                    _part.TablePr.TableBorders.InsideH = new CDocumentBorder();
                    this.ReadTableBorderLineStyle(_part.TablePr.TableBorders.InsideH);
                    break;
                }
                case 5:
                {
                    _part.TablePr.TableBorders.InsideV = new CDocumentBorder();
                    this.ReadTableBorderLineStyle(_part.TablePr.TableBorders.InsideV);
                    break;
                }
                case 6:
                case 7:
                {
                    s.SkipRecord();
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return _part;
    }

    this.ReadTableBorderLineStyle = function(_border)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    var ln = this.ReadLn();
                    _border.Unifill = ln.Fill;
                    _border.Size = (ln.w == null) ? 12700 : ((ln.w) >> 0);
                    _border.Size /= 36000;
                    _border.Value = border_Single;
                    break;
                }
                case 1:
                {
                    _border.LineRef = this.ReadStyleRef();
                    _border.Value = border_Single;
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
    }

    // UNICOLOR ---------------------------------

    this.ReadUniColor = function()
    {
        var s = this.stream;
        var _len = s.GetULong();
        var read_start = s.cur;
        var read_end = read_start + _len;

        var uni_color = new AscFormat.CUniColor();

        if (s.cur < read_end)
        {
            var _type = s.GetUChar();

            var _e = s.cur + s.GetULong() + 4;

            switch (_type)
            {
                case c_oAscColor.COLOR_TYPE_PRST:
                {
                    s.Skip2(2);
                    uni_color.setColor(new AscFormat.CPrstColor());
                    uni_color.color.setId(s.GetString2());
                    s.Skip2(1);

                    if (s.cur < _e)
                    {
                        if (0 == s.GetUChar())
                        {
                            uni_color.setMods(this.ReadColorMods());
                        }
                    }

                    break;
                }
                case c_oAscColor.COLOR_TYPE_SCHEME:
                {
                    s.Skip2(2);
                    uni_color.setColor(new AscFormat.CSchemeColor());
                    uni_color.color.setId(s.GetUChar());
                    s.Skip2(1);

                    if (s.cur < _e)
                    {
                        if (0 == s.GetUChar())
                        {
                            uni_color.setMods(this.ReadColorMods());
                        }
                    }

                    break;
                }
                case c_oAscColor.COLOR_TYPE_SRGB:
                {
                    var r, g, b;
                    s.Skip2(1);
                    uni_color.setColor(new AscFormat.CRGBColor());
                    s.Skip2(1);
                    r = s.GetUChar();
                    s.Skip2(1);
                    g = s.GetUChar();
                    s.Skip2(1);
                    b = s.GetUChar();
                    s.Skip2(1);
                    uni_color.color.setColor(r, g, b);
                    if (s.cur < _e)
                    {
                        if (0 == s.GetUChar())
                        {
                            uni_color.setMods(this.ReadColorMods());
                        }
                    }

                    break;
                }
                case c_oAscColor.COLOR_TYPE_SYS:
                {
                    s.Skip2(1);
                    uni_color.setColor(new AscFormat.CSysColor());

                    while (true)
                    {
                        var _at = s.GetUChar();
                        if (_at == g_nodeAttributeEnd)
                            break;

                        switch (_at)
                        {
                            case 0:
                            {
                                uni_color.color.setId(s.GetString2());
                                break;
                            }
                            case 1:
                            {
                                uni_color.color.setR(s.GetUChar());
                                break;
                            }
                            case 2:
                            {
                                uni_color.color.setG(s.GetUChar());
                                break;
                            }
                            case 3:
                            {
                                uni_color.color.setB(s.GetUChar());
                                break;
                            }
                            default:
                                break;
                        }
                    }

                    if (s.cur < _e)
                    {
                        if (0 == s.GetUChar())
                        {
                            uni_color.setMods(this.ReadColorMods());
                        }
                    }

                    break;
                }
            }
        }

        if(!uni_color.color){
            return null;
        }

        s.Seek2(read_end);
        return uni_color;
    }

    this.ReadColorMods = function()
    {
        var ret = new AscFormat.CColorModifiers();
        var _mods = this.ReadColorModifiers();
        for(var i = 0; i < _mods.length; ++i)
            ret.addMod(_mods[i]);
        return ret;
    };

    this.ReadColorModifiers = function()
    {
        var s = this.stream;
        var _start = s.cur;
        var _end = _start + s.GetULong() + 4;

        var _ret = null;

        var _count = s.GetULong();
        for (var i = 0; i < _count; i++)
        {
            if (s.cur > _end)
                break;

            s.Skip2(1);

            var _s1 = s.cur;
            var _e1 = _s1 + s.GetULong() + 4;

            if (_s1 < _e1)
            {
                s.Skip2(1);

                if (null == _ret)
                    _ret = [];

                var _mod = new AscFormat.CColorMod();
                _ret[_ret.length] = _mod;

                while (true)
                {
                    var _type = s.GetUChar();

                    if (0 == _type)
                    {
                        _mod.setName(s.GetString2());
                        var _find = _mod.name.indexOf(":");
                        if (_find >= 0 && _find < (_mod.name.length - 1))
                            _mod.setName(_mod.name.substring(_find + 1));
                    }
                    else if (1 == _type)
                        _mod.setVal(s.GetLong());
                    else if (g_nodeAttributeEnd == _type)
                        break;
                    else
                        break;
                }
            }

            s.Seek2(_e1);
        }

        s.Seek2(_end);
        return _ret;
    }

    // ------------------------------------------

    // UNIFILL ----------------------------------

    this.ReadRect = function(bIsMain)
    {
        var _ret = {};

        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    _ret.l = s.GetPercentage();
                    break;
                }
                case 1:
                {
                    _ret.t = s.GetPercentage();
                    break;
                }
                case 2:
                {
                    _ret.r = s.GetPercentage();
                    break;
                }
                case 3:
                {
                    _ret.b = s.GetPercentage();
                    break;
                }
                default:
                    break;
            }
        }

        s.Seek2(_end_rec);

        if (null == _ret.l && null == _ret.t && null == _ret.r && null == _ret.b)
            return null;

        if (_ret.l == null)
            _ret.l = 0;
        if (_ret.t == null)
            _ret.t = 0;
        if (_ret.r == null)
            _ret.r = 0;
        if (_ret.b == null)
            _ret.b = 0;

        if (!bIsMain)
        {
            var _absW = Math.abs(_ret.l) + Math.abs(_ret.r) + 100;
            var _absH = Math.abs(_ret.t) + Math.abs(_ret.b) + 100;

            _ret.l = -100 * _ret.l / _absW;
            _ret.t = -100 * _ret.t / _absH;
            _ret.r = -100 * _ret.r / _absW;
            _ret.b = -100 * _ret.b / _absH;
        }

        _ret.r = 100 - _ret.r;
        _ret.b = 100 - _ret.b;

        if (_ret.l > _ret.r)
        {
            var tmp = _ret.l;
            _ret.l = _ret.r;
            _ret.r = tmp;
        }
        if (_ret.t > _ret.b)
        {
            var tmp = _ret.t;
            _ret.t = _ret.b;
            _ret.b = tmp;
        }
        var ret = new AscFormat.CSrcRect();
        ret.setLTRB(_ret.l, _ret.t, _ret.r, _ret.b);
        return ret;
    }

    this.ReadGradLin = function()
    {
        var _lin = new AscFormat.GradLin();
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    _lin.setAngle(s.GetLong());
                    break;
                }
                case 1:
                {
                    _lin.setScale(s.GetBool());
                }
                default:
                    break;
            }
        }

        s.Seek2(_end_rec);
        return _lin;
    }

    this.ReadGradPath = function()
    {
        var _path = new AscFormat.GradPath();
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    _path.setPath(s.GetUChar());
                    break;
                }
                default:
                    break;
            }
        }

        s.Seek2(_end_rec);
        return _path;
    }

    this.ReadUniFill = function(oSpPr, oImageShape, oLn)
    {
        var s = this.stream;
        var read_start = s.cur;
        var read_end = read_start + s.GetULong() + 4;

        var uni_fill = new AscFormat.CUniFill();

        if (s.cur < read_end)
        {
            var _type = s.GetUChar();
            var _e = s.cur + s.GetULong() + 4;

            switch (_type)
            {
                case c_oAscFill.FILL_TYPE_BLIP:
                {
                    s.Skip2(1);

                    uni_fill.setFill(new AscFormat.CBlipFill());

                    while (true)
                    {
                        var _at = s.GetUChar();
                        if (_at == g_nodeAttributeEnd)
                            break;

                        switch (_at)
                        {
                            case 0:
                                s.Skip2(4); // dpi
                                break;
                            case 1:
                                s.Skip2(1); // rotWithShape
                                break;
                            default:
                                break;
                        }
                    }

                    while (s.cur < _e)
                    {
                        var rec = s.GetUChar();

                        switch (rec)
                        {
                            case 0:
                            {
                                var _s2 = s.cur;
                                var _e2 = _s2 + s.GetLong() + 4;

                                s.Skip2(1);

                                while (true)
                                {
                                    var _at = s.GetUChar();
                                    if (g_nodeAttributeEnd == _at)
                                        break;

                                    if (_at == 0)
                                        s.Skip2(1);
                                }

                                while (s.cur < _e2)
                                {
                                    var _t = s.GetUChar();

                                    switch (_t)
                                    {
                                        case 0:
                                        case 1:
                                        {
                                            // id. embed / link
                                            s.Skip2(4);
                                            break;
                                        }
                                        case 10:
                                        case 11:
                                        {
                                            // id. embed / link
                                            s.GetString2();
                                            break;
                                        }
                                        case 2:
                                        {
                                            s.Skip2(4);
                                            var count_effects = s.GetLong();
                                            for (var _eff = 0; _eff < count_effects; ++_eff)
                                            {
                                                s.Skip2(1); // type
                                                var __rec_len = s.GetLong();
                                                if (0 == __rec_len)
                                                    continue;

                                                var recE = s.GetUChar();

                                                if (recE == 21)
                                                {
                                                    // alpha!!!
                                                    var _e22 = s.cur + s.GetLong() + 4;

                                                    s.Skip2(1); // startattr

                                                    while (true)
                                                    {
                                                        var _at222 = s.GetUChar();
                                                        if (g_nodeAttributeEnd == _at222)
                                                            break;

                                                        if (_at222 == 0)
                                                        {
                                                            uni_fill.setTransparent(255 * s.GetLong() / 100000);
                                                        }
                                                    }

                                                    s.Seek2(_e22);
                                                }
                                                else
                                                {
                                                    s.SkipRecord();
                                                }
                                            }
                                            break;
                                        }
                                        case 3:
                                        {
                                            s.Skip2(6); // len + start attributes + type

                                            var sReadPath = s.GetString2();
											if (this.IsUseFullUrl && this.insertDocumentUrlsData && this.insertDocumentUrlsData.imageMap) {
												var sReadPathNew = this.insertDocumentUrlsData.imageMap[AscCommon.g_oDocumentUrls.mediaPrefix + sReadPath];
												if(sReadPathNew){
													sReadPath = sReadPathNew;
												}
											}
                                            uni_fill.fill.setRasterImageId(sReadPath);

                                            // TEST version ---------------
                                            var _s = sReadPath;
                                            var indS = _s.lastIndexOf("emf");
                                            if (indS == -1)
                                                indS = _s.lastIndexOf("wmf");

                                            if (indS != -1 && (indS == (_s.length - 3)))
                                            {
                                                _s = _s.substring(0, indS);
                                                _s += "svg";
                                                sReadPath = _s;
                                                uni_fill.fill.setRasterImageId(_s);
                                            }
                                            // ----------------------------

                                            if (this.IsThemeLoader)
                                            {
                                                sReadPath = "theme" + (this.Api.ThemeLoader.CurrentLoadThemeIndex + 1) + "/media/" + sReadPath;
                                                uni_fill.fill.setRasterImageId(sReadPath);
                                            }

                                            if (this.ImageMapChecker != null)
                                                this.ImageMapChecker[sReadPath] = true;

                                            if (this.IsUseFullUrl)
                                                this.RebuildImages.push(new CBuilderImages(uni_fill.fill, sReadPath, oImageShape, oSpPr, oLn));

                                            s.Skip2(1); // end attribute
                                            break;
                                        }
                                        default:
                                        {
                                            s.SkipRecord();
                                            break;
                                        }
                                    }
                                }

                                s.Seek2(_e2);
                                break;
                            }
                            case 1:
                            {
                                uni_fill.fill.setSrcRect(this.ReadRect(true));
                                break;
                            }
                            case 2:
                            {
                                var oBlipTile = new AscFormat.CBlipFillTile();


                                var s = this.stream;

                                var _rec_start = s.cur;
                                var _end_rec = _rec_start + s.GetLong() + 4;

                                s.Skip2(1); // start attributes

                                while (true)
                                {
                                    var _at = s.GetUChar();
                                    if (_at == g_nodeAttributeEnd)
                                break;

                                    switch (_at)
                                    {
                                        case 0:
                                        {
                                            oBlipTile.sx = s.GetLong();
                                            break;
                            }
                                        case 1:
                                        {
                                            oBlipTile.sy = s.GetLong();
                                            break;
                                        }
                                        case 2:
                                        {
                                            oBlipTile.tx = s.GetLong();
                                            break;
                                        }
                            case 3:
                            {
                                            oBlipTile.ty = s.GetLong();
                                            break;
                                        }
                                        case 4:
                                        {
                                            oBlipTile.algn = s.GetUChar();
                                            break;
                                        }
                                        case 5:
                                        {
                                            oBlipTile.flip = s.GetUChar();
                                            break;
                                        }
                                        default:
                                        {
                                            break;
                                        }
                                    }
                                }
                                s.Seek2(_end_rec);
                                uni_fill.fill.setTile(oBlipTile);
                                break;
                            }
                            case 3:
                            {
                                var _e2 = s.cur + s.GetLong() + 4;

                                while (s.cur < _e2)
                                {
                                    var _t = s.GetUChar();

                                    switch (_t)
                                    {
                                        case 0:
                                        {
                                            var _srcRect = this.ReadRect(false);
                                            if (_srcRect != null)
                                                uni_fill.fill.setSrcRect(_srcRect);
                                            break;
                                        }
                                        default:
                                        {
                                            s.SkipRecord();
                                            break;
                                        }
                                    }
                                }

                                s.Seek2(_e2);
                                break;
                            }
                            case 101:
                            {
                              var oBuilderImages = this.RebuildImages[this.RebuildImages.length - 1];
                              if (this.IsUseFullUrl && oBuilderImages) {
                                s.Skip2(4);
                                var urlsCount = s.GetUChar();
                                for (var i = 0; i < urlsCount; ++i) {
                                  oBuilderImages.AdditionalUrls.push(s.GetString2());
                                }
                              } else {
                                s.SkipRecord();
                              }
                              break;
                            }
                            default:
                            {
                                // пока никаких настроек градиента нет
                                var _len = s.GetULong();
                                s.Skip2(_len);
                            }
                        }
                    }

                    break;
                }
                case c_oAscFill.FILL_TYPE_GRAD:
                {
                    s.Skip2(1);

                    uni_fill.setFill(new AscFormat.CGradFill());

                    while (true)
                    {
                        var _at = s.GetUChar();
                        if (_at == g_nodeAttributeEnd)
                            break;

                        switch (_at)
                        {
                            case 0:
                                s.Skip2(1);
                                break;
                            case 1:
                                uni_fill.fill.rotateWithShape = s.GetBool();
                                break;
                            default:
                                break;
                        }
                    }

                    while (s.cur < _e)
                    {
                        var rec = s.GetUChar();

                        switch (rec)
                        {
                            case 0:
                            {
                                var _s1 = s.cur;
                                var _e1 = _s1 + s.GetULong() + 4;

                                var _count = s.GetULong();
                                var colors_ = [];
                                for (var i = 0; i < _count; i++)
                                {
                                    if (s.cur >= _e1)
                                        break;

                                    s.Skip2(1); // type
                                    s.Skip2(4); // len

                                    var _gs = new AscFormat.CGs();

                                    s.Skip2(1); // start attr
                                    s.Skip2(1); // pos type
                                    _gs.pos = s.GetLong();
                                    s.Skip2(1); // end attr

                                    s.Skip2(1);
                                    _gs.color = this.ReadUniColor();

                                    colors_[colors_.length] = _gs;
                                }

                                s.Seek2(_e1);
                                colors_.sort(function(a,b){return a.pos- b.pos;});

                                for(var z = 0; z < colors_.length; ++z)
                                {
                                    uni_fill.fill.addColor(colors_[z]);
                                }
                                break;
                            }
                            case 1:
                            {
                                uni_fill.fill.setLin(this.ReadGradLin());
                                break;
                            }
                            case 2:
                            {
                                uni_fill.fill.setPath(this.ReadGradPath());
                                break;
                            }
                            case 3:
                            {
                                s.SkipRecord();
                                break;
                            }
                            default:
                            {
                                // пока никаких настроек градиента нет
                                var _len = s.GetULong();
                                s.Skip2(_len);
                            }
                        }


                    }
                    if (null != uni_fill.fill.lin && null != uni_fill.fill.path)
                    {
                        // ms office не открывает такие файлы.
                        uni_fill.fill.setPath(null);
                    }

                    if(uni_fill.fill.colors.length < 2)
                    {
                        if(uni_fill.fill.colors.length === 1)
                        {
                            var oUniColor = uni_fill.fill.colors[0].color;
                            uni_fill.fill = new AscFormat.CSolidFill();
                            uni_fill.fill.color = oUniColor;
                        }
                        else
                        {
                            uni_fill.fill = new AscFormat.CSolidFill();
                            uni_fill.fill.color =  AscFormat.CreateUniColorRGB(0, 0, 0);
                        }
                    }

                    break;
                }
                case c_oAscFill.FILL_TYPE_PATT:
                {
                    uni_fill.setFill(new AscFormat.CPattFill());

                    s.Skip2(1);
                    while (true)
                    {
                        var _atPF = s.GetUChar();
                        if (_atPF == g_nodeAttributeEnd)
                            break;

                        switch (_atPF)
                        {
                            case 0:
                            {
                                uni_fill.fill.setFType(s.GetUChar());
                                break;
                            }
                            default:
                                break;
                        }
                    }

                    while (s.cur < _e)
                    {
                        var rec = s.GetUChar();

                        switch (rec)
                        {
                            case 0:
                            {
                                uni_fill.fill.setFgColor(this.ReadUniColor());
                                break;
                            }
                            case 1:
                            {
                                uni_fill.fill.setBgColor(this.ReadUniColor());
                                break;
                            }
                            default:
                            {
                                // пока никаких настроек градиента нет
                                s.SkipRecord();
                            }
                        }
                    }

                    break;
                }
                case c_oAscFill.FILL_TYPE_SOLID:
                {
                    s.Skip2(1); // type + len

                    uni_fill.setFill(new AscFormat.CSolidFill());
                    uni_fill.fill.setColor(this.ReadUniColor());

//                    uni_fill.fill.color.Mods = new AscFormat.CColorModifiers();
                    if(uni_fill.fill
                        && uni_fill.fill.color
                        && uni_fill.fill.color.Mods
                        && uni_fill.fill.color.Mods.Mods)
                    {
                        var mods = uni_fill.fill.color.Mods.Mods;
                        var _len = mods.length;
                        for (var i = 0; i < _len; i++)
                        {
                            if (mods[i].name == "alpha")
                            {
                                uni_fill.setTransparent(255 * mods[i].val / 100000);
                                uni_fill.fill.color.Mods.removeMod(i);
                                break;
                            }
                        }
                    }
                    else
                    {
                        if(uni_fill.fill.color){
                            uni_fill.fill.color.setMods(new AscFormat.CColorModifiers());
                        }

                    }
                    break;
                }
                case c_oAscFill.FILL_TYPE_NOFILL:
                {
                    uni_fill.setFill(new AscFormat.CNoFill());
                    break;
                }
                case c_oAscFill.FILL_TYPE_GRP:
                {
                    uni_fill.setFill(new AscFormat.CGrpFill());
                    break;
                }
            }
        }

        s.Seek2(read_end);
        if(!uni_fill.fill){
            return null;
        }
        return uni_fill;
    }

    // ------------------------------------------

    // COLOR SCHEME -----------------------------

    this.ReadExtraColorScheme = function()
    {
        var extra = new AscFormat.ExtraClrScheme();

        var s = this.stream;
        var _e = s.cur + s.GetULong() + 4;

        while (s.cur < _e)
        {
            var _rec = s.GetUChar();

            switch (_rec)
            {
                case 0:
                {
                    extra.setClrScheme(new AscFormat.ClrScheme());
                    this.ReadClrScheme(extra.clrScheme);
                    break;
                }
                case 1:
                {
                    extra.setClrMap(new AscFormat.ClrMap());
                    this.ReadClrMap(extra.clrMap);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_e);
        return extra;
    }

    this.ReadClrScheme = function(clrscheme)
    {
        var s = this.stream;
        var _e = s.cur + s.GetULong() + 4;

        s.Skip2(1); // start attribute

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            if (0 == _at)
                clrscheme.setName(s.GetString2());
        }

        while (s.cur < _e)
        {
            var _rec = s.GetUChar();

            clrscheme.addColor(_rec,this.ReadUniColor());
        }

        s.Seek2(_e);
    }

    this.ReadClrMap = function(clrmap)
    {
        var s = this.stream;
        var _e = s.cur + s.GetULong() + 4;

        s.Skip2(1); // start sttribute

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            clrmap.setClr(_at, s.GetUChar());
        }

        s.Seek2(_e);
    }

    this.ReadClrOverride = function()
    {
        var s = this.stream;
        var _e = s.cur + s.GetULong() + 4;

        var clr_map = null;
        if (s.cur < _e)
        {
            clr_map = new AscFormat.ClrMap();
            s.Skip2(1); // "0"-rectype
            this.ReadClrMap(clr_map);
        }

        s.Seek2(_e);
        return clr_map;
    }

    // ------------------------------------------

    // LINE PROPERTIES --------------------------

    this.ReadLn = function(spPr)
    {
        var ln = new AscFormat.CLn();

        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;


        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    ln.setAlgn(s.GetUChar());
                    break;
                }
                case 1:
                {
                    ln.setCap(s.GetUChar());
                    break;
                }
                case 2:
                {
                    ln.setCmpd(s.GetUChar());
                    break;
                }
                case 3:
                {
                    ln.setW(s.GetLong());
                    break;
                }
                default:
                    break;
            }
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    // themeElements
                    ln.setFill(this.ReadUniFill(spPr, null, ln));
                    break;
                }
                case 1:
                {
                    ln.setPrstDash(this.ReadLineDash());
                    break;
                }
                case 2:
                {
                    ln.setJoin(this.ReadLineJoin());
                    break;
                }
                case 3:
                {
                    ln.setHeadEnd(this.ReadLineEnd());
                    break;
                }
                case 4:
                {
                    ln.setTailEnd(this.ReadLineEnd());
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return ln;
    }

    this.ReadLineEnd = function()
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        var endL = new AscFormat.EndArrow();

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    endL.setType(s.GetUChar());
                    break;
                }
                case 1:
                {
                    endL.setW(s.GetUChar());
                    break;
                }
                case 2:
                {
                    endL.setLen(s.GetUChar());
                    break;
                }
                default:
                    break;
            }
        }

        s.Seek2(_end_rec);
        return endL;
    }

    this.ReadLineDash = function()
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        var _dash = 6; // solid

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    _dash = s.GetUChar();
                    break;
                }
                default:
                    break;
            }
        }

        s.Seek2(_end_rec);
        return _dash;
    }

    this.ReadLineJoin = function()
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        var join = new AscFormat.LineJoin();

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    join.setType(s.GetLong());
                    break;
                }
                case 1:
                {
                    join.setLimit(s.GetLong());
                    break;
                }
                default:
                    break;
            }
        }

        s.Seek2(_end_rec);
        return join;
    }

    // ------------------------------------------

    // SLIDE MASTER -----------------------------

    this.ReadSlideMaster = function()
    {
        var master = new MasterSlide(this.presentation, null);
        this.TempMainObject = master;

        var s = this.stream;

        s.Skip2(1); // type
        var end = s.cur + s.GetULong() + 4;

        s.Skip2(1); // attribute start
        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    master.preserve = s.GetBool();
                    break;
                }
                default:
                    break;
            }
        }

        while (s.cur < end)
        {
            var _rec = s.GetUChar();

            switch (_rec)
            {
                case 0:
                {
                    var cSld = new AscFormat.CSld();
                    this.ReadCSld(cSld);
                    for(var i = 0; i < cSld.spTree.length; ++i)
                    {
                        master.shapeAdd(i, cSld.spTree[i]);
                    }
                    if(cSld.Bg)
                    {
                        master.changeBackground(cSld.Bg);
                    }
                    master.setCSldName(cSld.name);
                    break;
                }
                case 1:
                {
                    var clrMap = new AscFormat.ClrMap();
                    this.ReadClrMap(clrMap);
                    master.setClMapOverride(clrMap);
                    break;
                }
                case 2:
                case 3:
                case 4:
                {
                    var _len = s.GetULong();
                    s.Skip2(_len);
                    break;
                }
                case 5:
                {
                    master.hf = this.ReadHF();
                    break;
                }
                case 6:
                {
                    master.setTxStyles(this.ReadTxStyles());
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(end);
        this.TempMainObject = null;
        return master;
    }

    this.ReadTxStyles = function()
    {
        var txStyles = new AscFormat.CTextStyles();

        var s = this.stream;
        var end = s.cur + s.GetULong() + 4;

        while (s.cur < end)
        {
            var _rec = s.GetUChar();

            switch (_rec)
            {
                case 0:
                {
                    txStyles.titleStyle = this.ReadTextListStyle();
                    break;
                }
                case 1:
                {
                    txStyles.bodyStyle = this.ReadTextListStyle();
                    break;
                }
                case 2:
                {
                    txStyles.otherStyle = this.ReadTextListStyle();
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(end);
        return txStyles;
    }

    // ------------------------------------------

    // SLIDE LAYOUT -----------------------------

    this.ReadSlideLayout = function()
    {
        var layout = new SlideLayout(null);
        this.TempMainObject = layout;

        var s = this.stream;

        s.Skip2(1); // type
        var end = s.cur + s.GetULong() + 4;

        s.Skip2(1); // attribute start
        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    layout.setMatchingName(s.GetString2());
                    break;
                }
                case 1:
                {
                    layout.preserve = s.GetBool();
                    break;
                }
                case 2:
                {
                    layout.setShowPhAnim(s.GetBool());
                    break;
                }
                case 3:
                {
                    layout.setShowMasterSp(s.GetBool());
                    break;
                }
                case 4:
                {
                    layout.userDrawn = s.GetBool();
                    break;
                }
                case 5:
                {
                    layout.setType(s.GetUChar());
                    break;
                }
                default:
                    break;
            }
        }

        while (s.cur < end)
        {
            var _rec = s.GetUChar();

            switch (_rec)
            {
                case 0:
                {
                    var cSld = new AscFormat.CSld();
                    this.ReadCSld(cSld);
                    for(var i = 0; i < cSld.spTree.length; ++i)
                    {
                        layout.shapeAdd(i, cSld.spTree[i]);
                    }
                    if(cSld.Bg)
                    {
                        layout.changeBackground(cSld.Bg);
                    }
                    layout.setCSldName(cSld.name);
                    break;
                }
                case 1:
                {
                    layout.setClMapOverride(this.ReadClrOverride());
                    break;
                }
                case 4:
                {
                    layout.hf = this.ReadHF();
                    break;
                }
                default:
                {
                    var _len = s.GetULong();
                    s.Skip2(_len);
                    break;
                }
            }
        }

        s.Seek2(end);
        this.TempMainObject = null;
        return layout;
    }

    // ------------------------------------------

    // SLIDE ------------------------------------

    this.ReadSlide = function(sldIndex)
    {
        var slide = new Slide(this.presentation, null, sldIndex);
        this.TempMainObject = slide;

        slide.maxId = -1;
        var s = this.stream;
        s.Skip2(1); // type
        var end = s.cur + s.GetULong() + 4;

        s.Skip2(1); // attribute start
        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            if (0 == _at)
                slide.setShow(s.GetBool());
            else if (1 == _at)
                slide.setShowPhAnim(s.GetBool());
            else if (2 == _at)
                slide.setShowMasterSp(s.GetBool());
        }

        while (s.cur < end)
        {
            var _rec = s.GetUChar();

            switch (_rec)
            {
                case 0:
                {
                    var cSld = new AscFormat.CSld();
                    this.ReadCSld(cSld);
                    for(var i = 0; i < cSld.spTree.length; ++i)
                    {
                        slide.shapeAdd(i, cSld.spTree[i]);
                    }
                    if(cSld.Bg)
                    {
                        slide.changeBackground(cSld.Bg);
                    }
                    slide.setCSldName(cSld.name);
                    break;
                }
                case 1:
                {
                    slide.setClMapOverride(this.ReadClrOverride());
                    break;
                }
                case 2:
                {
                    var _timing = this.ReadTransition();
                    slide.applyTiming(_timing);
                    break;
                }
                case 4:
                {
                    this.ReadComments(slide.writecomments);
                    break;
                }
                default:
                {
                    var _len = s.GetULong();
                    s.Skip2(_len);
                    break;
                }
            }
        }

        slide.Load_Comments(this.presentation.CommentAuthors);

        s.Seek2(end);
        this.TempMainObject = null;
        return slide;
    }

    this.ReadComments = function(writecomments)
    {
        var s = this.stream;
        var end2 = s.cur + s.GetLong() + 4;
        while (s.cur < end2)
        {
            var _rec2 = s.GetUChar();
            switch (_rec2)
            {
                case 0:
                {
                    s.Skip2(4); // len
                    var lCount = s.GetULong();

                    for (var i = 0; i < lCount; i++)
                    {
                        s.Skip2(1);

                        var _comment = new CWriteCommentData();

                        var _end_rec3 = s.cur + s.GetLong() + 4;

                        s.Skip2(1); // start attributes
                        while (true)
                        {
                            var _at3 = s.GetUChar();
                            if (_at3 == g_nodeAttributeEnd)
                                break;

                            switch (_at3)
                            {
                                case 0:
                                    _comment.WriteAuthorId = s.GetLong();
                                    break;
                                case 1:
                                    _comment.WriteTime = s.GetString2();
                                    break;
                                case 2:
                                    _comment.WriteCommentId = s.GetLong();
                                    break;
                                case 3:
                                    _comment.x = s.GetLong();
                                    break;
                                case 4:
                                    _comment.y = s.GetLong();
                                    break;
                                case 5:
                                    _comment.WriteText = s.GetString2();
                                    break;
                                case 6:
                                    _comment.WriteParentAuthorId = s.GetLong();
                                    break;
                                case 7:
                                    _comment.WriteParentCommentId = s.GetLong();
                                    break;
                                case 8:
                                    _comment.AdditionalData = s.GetString2();
                                    break;
                                default:
                                    break;
                            }
                        }

                        s.Seek2(_end_rec3);

                        _comment.Calculate2();
                        writecomments.push(_comment);
                    }

                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(end2);
    }

    this.ReadTransition = function()
    {
        var _timing = new CAscSlideTiming();
        _timing.setDefaultParams();

        var s = this.stream;
        var end = s.cur + s.GetULong() + 4;

        if (s.cur == end)
            return _timing;

        s.Skip2(1); // attribute start
        var _presentDuration = false;
        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            if (0 == _at)
            {
                _timing.SlideAdvanceOnMouseClick = s.GetBool();
            }
            else if (1 == _at)
            {
                _timing.SlideAdvanceAfter = true;
                _timing.SlideAdvanceDuration = s.GetULong();
            }
            else if (2 == _at)
            {
                _timing.TransitionDuration = s.GetULong();
                _presentDuration = true;
            }
            else if (3 == _at)
            {
                var _spd = s.GetUChar();
                if (!_presentDuration)
                {
                    _timing.TransitionDuration = 250;
                    if (_spd == 1)
                        _timing.TransitionDuration = 500;
                    else if (_spd == 2)
                        _timing.TransitionDuration = 750;
                }
            }
        }

        while (s.cur < end)
        {
            var _rec = s.GetUChar();

            switch (_rec)
            {
                case 0:
                {
                    var _type = "";
                    var _paramNames = [];
                    var _paramValues = [];

                    var _end_rec2 = s.cur + s.GetULong() + 4;

                    s.Skip2(1); // start attributes
                    while (true)
                    {
                        var _at2 = s.GetUChar();
                        if (_at2 == g_nodeAttributeEnd)
                            break;

                        switch (_at2)
                        {
                            case 0:
                            {
                                _type = s.GetString2();
                                break;
                            }
                            case 1:
                            {
                                _paramNames.push(s.GetString2());
                                break;
                            }
                            case 2:
                            {
                                _paramValues.push(s.GetString2());
                                break;
                            }
                            default:
                                break;
                        }
                    }

                    if (_paramNames.length == _paramValues.length && _type != "")
                    {
                        var _len = _paramNames.length;
                        // тут все поддерживаемые переходы
                        if ("p:fade" == _type)
                        {
                            _timing.TransitionType = c_oAscSlideTransitionTypes.Fade;
                            _timing.TransitionOption = c_oAscSlideTransitionParams.Fade_Smoothly;

                            if (1 == _len && _paramNames[0] == "thruBlk" && _paramValues[0] == "1")
                            {
                                _timing.TransitionOption = c_oAscSlideTransitionParams.Fade_Through_Black;
                            }
                        }
                        else if ("p:push" == _type)
                        {
                            _timing.TransitionType = c_oAscSlideTransitionTypes.Push;
                            _timing.TransitionOption = c_oAscSlideTransitionParams.Param_Bottom;

                            if (1 == _len && _paramNames[0] == "dir")
                            {
                                if ("l" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_Right;
                                if ("r" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_Left;
                                if ("d" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_Top;
                            }
                        }
                        else if ("p:wipe" == _type)
                        {
                            _timing.TransitionType = c_oAscSlideTransitionTypes.Wipe;
                            _timing.TransitionOption = c_oAscSlideTransitionParams.Param_Right;

                            if (1 == _len && _paramNames[0] == "dir")
                            {
                                if ("u" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_Bottom;
                                if ("r" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_Left;
                                if ("d" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_Top;
                            }
                        }
                        else if ("p:strips" == _type)
                        {
                            _timing.TransitionType = c_oAscSlideTransitionTypes.Wipe;
                            _timing.TransitionOption = c_oAscSlideTransitionParams.Param_TopRight;

                            if (1 == _len && _paramNames[0] == "dir")
                            {
                                if ("rd" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_TopLeft;
                                if ("ru" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_BottomLeft;
                                if ("lu" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_BottomRight;
                            }
                        }
                        else if ("p:cover" == _type)
                        {
                            _timing.TransitionType = c_oAscSlideTransitionTypes.Cover;
                            _timing.TransitionOption = c_oAscSlideTransitionParams.Param_Right;

                            if (1 == _len && _paramNames[0] == "dir")
                            {
                                if ("u" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_Bottom;
                                if ("r" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_Left;
                                if ("d" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_Top;
                                if ("rd" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_TopLeft;
                                if ("ru" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_BottomLeft;
                                if ("lu" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_BottomRight;
                                if ("ld" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_TopRight;
                            }
                        }
                        else if ("p:pull" == _type)
                        {
                            _timing.TransitionType = c_oAscSlideTransitionTypes.UnCover;
                            _timing.TransitionOption = c_oAscSlideTransitionParams.Param_Right;

                            if (1 == _len && _paramNames[0] == "dir")
                            {
                                if ("u" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_Bottom;
                                if ("r" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_Left;
                                if ("d" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_Top;
                                if ("rd" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_TopLeft;
                                if ("ru" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_BottomLeft;
                                if ("lu" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_BottomRight;
                                if ("ld" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Param_TopRight;
                            }
                        }
                        else if ("p:split" == _type)
                        {
                            _timing.TransitionType = c_oAscSlideTransitionTypes.Split;

                            var _is_vert = true;
                            var _is_out = true;

                            for (var i = 0; i < _len; i++)
                            {
                                if (_paramNames[i] == "orient")
                                {
                                    _is_vert = (_paramValues[i] == "vert") ? true : false;
                                }
                                else if (_paramNames[i] == "dir")
                                {
                                    _is_out = (_paramValues[i] == "out") ? true : false;
                                }
                            }

                            if (_is_vert)
                            {
                                if (_is_out)
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Split_VerticalOut;
                                else
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Split_VerticalIn;
                            }
                            else
                            {
                                if (_is_out)
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Split_HorizontalOut;
                                else
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Split_HorizontalIn;
                            }
                        }
                        else if ("p:wheel" == _type)
                        {
                            _timing.TransitionType = c_oAscSlideTransitionTypes.Clock;
                            _timing.TransitionOption = c_oAscSlideTransitionParams.Clock_Clockwise;
                        }
                        else if ("p14:wheelReverse" == _type)
                        {
                            _timing.TransitionType = c_oAscSlideTransitionTypes.Clock;
                            _timing.TransitionOption = c_oAscSlideTransitionParams.Clock_Counterclockwise;
                        }
                        else if ("p:wedge" == _type)
                        {
                            _timing.TransitionType = c_oAscSlideTransitionTypes.Clock;
                            _timing.TransitionOption = c_oAscSlideTransitionParams.Clock_Wedge;
                        }
                        else if ("p14:warp" == _type)
                        {
                            _timing.TransitionType = c_oAscSlideTransitionTypes.Zoom;
                            _timing.TransitionOption = c_oAscSlideTransitionParams.Zoom_Out;

                            if (1 == _len && _paramNames[0] == "dir")
                            {
                                if ("in" == _paramValues[0])
                                    _timing.TransitionOption = c_oAscSlideTransitionParams.Zoom_In;
                            }
                        }
                        else if ("p:newsflash" == _type)
                        {
                            _timing.TransitionType = c_oAscSlideTransitionTypes.Zoom;
                            _timing.TransitionOption = c_oAscSlideTransitionParams.Zoom_AndRotate;
                        }
                        else if ("p:none" != _type)
                        {
                            _timing.TransitionType = c_oAscSlideTransitionTypes.Fade;
                            _timing.TransitionOption = c_oAscSlideTransitionParams.Fade_Smoothly;
                        }
                    }

                    s.Seek2(_end_rec2);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(end);
        return _timing;
    }

    this.ReadHF = function()
    {
        var hf = new AscFormat.HF();

        var s = this.stream;
        var _e = s.cur + s.GetULong() + 4;

        s.Skip2(1); // attribute start
        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            if (0 == _at)
                hf.setDt(s.GetBool());
            else if (1 == _at)
                hf.setFtr(s.GetBool());
            else if (2 == _at)
                hf.setHdr(s.GetBool());
            else if (3 == _at)
                hf.setSldNum(s.GetBool());
        }

        s.Seek2(_e);
        return hf;
    }

    // ------------------------------------------

    this.ReadNoteMaster = function()
    {

        var oNotesMaster = new AscCommonSlide.CNotesMaster();
        this.TempMainObject = oNotesMaster;
        this.stream.Skip2(1); // type
        var end = this.stream.cur + this.stream.GetLong() + 4;
        while(this.stream.cur < end){
            var at = this.stream.GetUChar();
            switch (at)
            {
                case 0:
                {
                    var cSld = new AscFormat.CSld();
                    this.ReadCSld(cSld);
                    for(var i = 0; i < cSld.spTree.length; ++i){
                        oNotesMaster.addToSpTreeToPos(i, cSld.spTree[i]);
                    }
                    if(cSld.Bg)
                    {
                        oNotesMaster.changeBackground(cSld.Bg);
                    }
                    oNotesMaster.setCSldName(cSld.name);
                    break;
                }
                case 1:
                {
                    this.ReadClrMap(oNotesMaster.clrMap);
                    break;
                }
                case 2:
                {
                    oNotesMaster.setHF(this.ReadHF());
                    break;
                }
                case 3:
                {

                    oNotesMaster.setNotesStyle(this.ReadTextListStyle());
                    break;
                }
                default:
                {
                    this.stream.SkipRecord();
                    break;
                }
            }
        }

        this.stream.Seek2(end);
        this.TempMainObject = null;
        return oNotesMaster;
    }

    this.ReadNote = function()
    {
        var oNotes = new AscCommonSlide.CNotes();
        this.TempMainObject = oNotes;
        var _s = this.stream;
        _s.Skip2(1); // type
        var _end = _s.cur + _s.GetLong() + 4;

        _s.Skip2(1); // attribute start
        while (true)
        {
            var _at = _s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            if (0 == _at)
                oNotes.setShowMasterPhAnim(_s.GetBool());
            else if (1 == _at)
                oNotes.setShowMasterSp(_s.GetBool());
        }

        while (_s.cur < _end)
        {
            var _rec = _s.GetUChar();

            switch (_rec)
            {
                case 0:
                {
                    var cSld = new AscFormat.CSld();
                    this.ReadCSld(cSld);
                    for(var i = 0; i < cSld.spTree.length; ++i){
                        oNotes.addToSpTreeToPos(i, cSld.spTree[i]);
                    }
                    if(cSld.Bg)
                    {
                        oNotes.changeBackground(cSld.Bg);
                    }
                    oNotes.setCSldName(cSld.name);
                    break;
                }
                case 1:
                {
                    oNotes.setClMapOverride(this.ReadClrOverride());
                    break;
                }
                default:
                {
                    _s.SkipRecord();
                    break;
                }
            }
        }
        this.TempMainObject = null;
        _s.Seek2(_end);
        return oNotes;
    }

    this.ReadCSld = function(csld)
    {
        var s = this.stream;
        var _end_rec = s.cur + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            if (0 == _at)
                csld.name = s.GetString2();
            else
                break;
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    // themeElements
                    csld.Bg = this.ReadBg();
                    break;
                }
                case 1:
                {
                    // SHAPES
                    this.ClearConnectorsMaps();
                    csld.spTree = this.ReadGroupShapeMain();
                    this.AssignConnectorsId();
                    break;
                }
                default:
                {
                    s.Seek2(_end_rec);
                    return;
                }
            }
        }

        s.Seek2(_end_rec);
    }

    this.ReadBg = function()
    {
        var bg = new AscFormat.CBg();

        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            if (0 == _at)
                bg.bwMode = s.GetUChar();
            else
                break;
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    // themeElements
                    bg.bgPr = this.ReadBgPr();
                    break;
                }
                case 1:
                {
                    bg.bgRef = this.ReadStyleRef();
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return bg;
    }

    this.ReadBgPr = function()
    {
        var bgpr = new AscFormat.CBgPr();

        var s = this.stream;
        var _end_rec = s.cur + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            if (0 == _at)
                bgpr.shadeToTitle = s.GetBool();
            else
                break;
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    // themeElements
                    bgpr.Fill = this.ReadUniFill();
                    break;
                }
                case 1:
                {
                    var _len = s.GetULong();
                    s.Skip2(_len);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return bgpr;
    }

    this.ReadStyleRef = function()
    {
        var ref = new AscFormat.StyleRef();

        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            if (0 == _at)
                ref.setIdx(s.GetLong());
            else
                break;
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    // themeElements
                    ref.setColor(this.ReadUniColor());
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return ref;
    }

    this.ReadFontRef = function()
    {
        var ref = new AscFormat.FontRef();

        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            if (0 == _at)
                ref.setIdx(s.GetUChar());
            else
                break;
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    // themeElements
                    ref.setColor(this.ReadUniColor());
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return ref;
    }

    // THEME ------------------------------------

    this.ReadTheme = function()
    {
        var theme = new AscFormat.CTheme();
        theme.presentation = this.presentation;

        var s = this.stream;
        var type = s.GetUChar();

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;


        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            if (0 == _at)
                theme.setName(s.GetString2());
            else if (1 == _at)
                theme.setIsThemeOverride(s.GetBool());
            else
                break;
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    // themeElements
                    var themeElements = new AscFormat.ThemeElements();
                    this.ReadThemeElements(themeElements);
                    theme.setFontScheme(themeElements.fontScheme);
                    theme.setFormatScheme(themeElements.fmtScheme);
                    theme.changeColorScheme(themeElements.clrScheme);

                    break;
                }
                case 1:
                {
                    theme.setSpDef(this.ReadDefaultShapeProperties());
                    break;
                }
                case 2:
                {
                    theme.setLnDef(this.ReadDefaultShapeProperties());
                    break;
                }
                case 3:
                {
                    theme.setTxDef(this.ReadDefaultShapeProperties());
                    break;
                }
                case 4:
                {
                    s.Skip2(4); // len
                    var _len = s.GetULong();
                    for (var i = 0; i < _len; i++)
                    {
                        s.Skip2(1); // type
                        theme.extraClrSchemeLst[i] = this.ReadExtraColorScheme();
                    }
                }
            }
        }

        s.Seek2(_end_rec);
        return theme;
    }

    this.ReadThemeElements = function(thelems)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    this.ReadClrScheme(thelems.clrScheme);
                    break;
                }
                case 1:
                {
                    this.ReadFontScheme(thelems.fontScheme);
                    break;
                }
                case 2:
                {
                    this.ReadFmtScheme(thelems.fmtScheme);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
    }

    this.ReadFontScheme = function(fontscheme)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            if (0 == _at)
                fontscheme.setName(s.GetString2());
            else
                break;
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    this.ReadFontCollection(fontscheme.majorFont);
                    break;
                }
                case 1:
                {
                    this.ReadFontCollection(fontscheme.minorFont);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
    }

    this.ReadFontCollection = function(fontcolls)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    fontcolls.setLatin(this.ReadTextFontTypeface());
                    break;
                }
                case 1:
                {
                    fontcolls.setEA(this.ReadTextFontTypeface());
                    break;
                }
                case 2:
                {
                    fontcolls.setCS(this.ReadTextFontTypeface());
                    break;
                }
                case 3:
                {
                    var _len = s.GetULong();
                    s.Skip2(_len);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
    }

    this.ReadTextFontTypeface = function()
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        var charset = "";
        var panose = "";
        var pitchFamily = "";
        var typeface = "";

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    charset = s.GetString2();
                    break;
                }
                case 1:
                {
                    panose = s.GetString2();
                    break;
                }
                case 2:
                {
                    pitchFamily = s.GetString2();
                    break;
                }
                case 3:
                {
					typeface = s.GetString2();
                    break;
                }
                default:
                    break;
            }
        }

        s.Seek2(_end_rec);

        return typeface;
    }

    this.ReadFmtScheme = function(fmt)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            if (0 == _at)
                fmt.setName(s.GetString2());
            else
                break;
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    s.Skip2(4); // len
                    var _c = s.GetULong();

                    for (var i = 0; i < _c; i++)
                    {
                        s.Skip2(1); // type
                        fmt.fillStyleLst[i] = this.ReadUniFill();
                    }

                    break;
                }
                case 1:
                {
                    s.Skip2(4); // len
                    var _c = s.GetULong();

                    for (var i = 0; i < _c; i++)
                    {
                        s.Skip2(1); // type1
                        fmt.lnStyleLst[i] = this.ReadLn();
                    }
                    break;
                }
                case 2:
                {
                    var _len = s.GetULong();
                    s.Skip2(_len);
                    break;
                }
                case 3:
                {
                    s.Skip2(4); // len
                    var _c = s.GetULong();

                    for (var i = 0; i < _c; i++)
                    {
                        s.Skip2(1); // type
                        fmt.bgFillStyleLst[i] = this.ReadUniFill();
                    }
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
    }

    this.ReadDefaultShapeProperties = function()
    {
        var def = new AscFormat.DefaultShapeDefinition();

        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    this.ReadSpPr(def.spPr);
                    break;
                }
                case 1:
                {
                    var _len = s.GetULong();
                    s.Skip2(_len);

                    // bodyPr
                    break;
                }
                case 2:
                {
                    var _len = s.GetULong();
                    s.Skip2(_len);

                    // textstyles
                    break;
                }
                case 3:
                {
                    def.style = this.ReadShapeStyle();
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return def;
    }

    this.ReadSpPr = function(spPr)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            if (0 == _at)
                spPr.setBwMode(s.GetUChar());
            else
                break;
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    spPr.setXfrm(this.ReadXfrm());
                    spPr.xfrm.setParent(spPr);
                    break;
                }
                case 1:
                {
                    var oGeometry = this.ReadGeometry(spPr.xfrm);
                    if(oGeometry && oGeometry.pathLst.length > 0)
                        spPr.setGeometry(oGeometry);
                    break;
                }
                case 2:
                {
                    spPr.setFill(this.ReadUniFill(spPr, null, null));
                    break;
                }
                case 3:
                {
                    spPr.setLn(this.ReadLn(spPr));
                    break;
                }
                case 4:
                {
                    var _len = s.GetULong();
                    s.Skip2(_len);
                    break;
                }
                case 5:
                {
                    var _len = s.GetULong();
                    s.Skip2(_len);
                    break;
                }
                case 6:
                {
                    var _len = s.GetULong();
                    s.Skip2(_len);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
    }

    this.ReadGrSpPr = function(spPr)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            if (0 == _at)
                spPr.setBwMode(s.GetUChar());
            else
                break;
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    spPr.setXfrm(this.ReadXfrm());
                    spPr.xfrm.setParent(spPr);
                    break;
                }
                case 1:
                {
                    spPr.setFill(this.ReadUniFill(spPr, null, null));
                    break;
                }
                case 2:
                {
                    var _len = s.GetULong();
                    s.Skip2(_len);
                    break;
                }
                case 3:
                {
                    var _len = s.GetULong();
                    s.Skip2(_len);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
    }

    this.ReadXfrm = function()
    {
        var ret = new AscFormat.CXfrm();

        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    ret.setOffX(s.GetLong() / c_dScalePPTXSizes);
                    break;
                }
                case 1:
                {
                    ret.setOffY(s.GetLong() / c_dScalePPTXSizes);
                    break;
                }
                case 2:
                {
                    ret.setExtX(s.GetLong() / c_dScalePPTXSizes);
                    break;
                }
                case 3:
                {
                    ret.setExtY(s.GetLong() / c_dScalePPTXSizes);
                    break;
                }
                case 4:
                {
                    ret.setChOffX(s.GetLong() / c_dScalePPTXSizes);
                    break;
                }
                case 5:
                {
                    ret.setChOffY(s.GetLong() / c_dScalePPTXSizes);
                    break;
                }
                case 6:
                {
                    ret.setChExtX(s.GetLong() / c_dScalePPTXSizes);
                    break;
                }
                case 7:
                {
                    ret.setChExtY(s.GetLong() / c_dScalePPTXSizes);
                    break;
                }
                case 8:
                {
                    ret.setFlipH(s.GetBool());
                    break;
                }
                case 9:
                {
                    ret.setFlipV(s.GetBool());
                    break;
                }
                case 10:
                {
                    ret.setRot((s.GetLong()/60000)*Math.PI/180);
                    break;
                }
                default:
                    break;
            }
        }

        s.Seek2(_end_rec);
        return ret;
    }

	this.ReadSignatureLine = function()
	{
		var ret = new AscFormat.CSignatureLine();

		var s = this.stream;

		var _rec_start = s.cur;
		var _end_rec = _rec_start + s.GetULong() + 4;

		s.Skip2(1); // start attributes

		while (true)
		{
			var _at = s.GetUChar();
			if (_at == g_nodeAttributeEnd)
				break;
			switch (_at)
			{
				case 0:
				{
					s.GetString2();
					break;
				}
				case 1:
				{
					s.GetBool();
					break;
				}
				case 2:
				{
					s.GetUChar();
					break;
				}
				case 3:
				{
					ret.id = s.GetString2();
					break;
				}
				case 4:
				{
					s.GetBool();
					break;
				}
				case 5:
				{
					s.GetString2();
					break;
				}
				case 6:
				{
					s.GetBool();
					break;
				}
				case 7:
				{
					s.GetString2();
					break;
				}
				case 8:
				{
					s.GetBool();
					break;
				}
				case 9:
				{
					s.GetString2();
					break;
				}
				case 10:
				{
					ret.signer = s.GetString2();
					break;
				}
				case 11:
				{
					ret.signer2 = s.GetString2();
					break;
				}
				case 12:
				{
					ret.email = s.GetString2();
					break;
				}
				default:
					break;
			}
		}

		s.Seek2(_end_rec);
		return ret;
	}

    this.ReadShapeStyle = function()
    {
        var def = new AscFormat.CShapeStyle();

        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    def.setLnRef(this.ReadStyleRef());
                    break;
                }
                case 1:
                {
                    def.setFillRef(this.ReadStyleRef());
                    break;
                }
                case 2:
                {
                    def.setEffectRef(this.ReadStyleRef());
                    break;
                }
                case 3:
                {
                    def.setFontRef(this.ReadFontRef());
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return def;
    }

    this.ReadOleInfo = function(ole)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetLong() + 4;

        s.Skip2(1); // start attributes
        var dxaOrig = 0;
        var dyaOrig = 0;
        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    ole.setApplicationId(s.GetString2());
                    break;
                }
                case 1:
                {
                    ole.setData(s.GetString2());
                    break;
                }
                case 2:
                {
                    dxaOrig = s.GetULong();
                    break;
                }
                case 3:
                {
                    dyaOrig = s.GetULong();
                    break;
                }
                case 4:
                {
                    s.GetUChar();
                    break;
                }
                case 5:
                {
                    s.GetUChar();
                    break;
                }
                case 6:
                {
                    s.GetUChar();
                    break;
                }
                case 7:
                {
                    ole.setObjectFile(s.GetString2());
                    break;
                }
                default:
                {
                    break;
                }
            }
        }
        var oleType = null;
        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 1:
                {
                    s.GetLong();//length
                    oleType = s.GetUChar();
                    break;
                }
                case 2:
                {

                    switch(oleType)
                    {
                        case 1:
                        {
                            ole.setObjectFile("maskFile.docx");
                            s.SkipRecord();
                            break;
                        }
                        case 2:
                        {
                            ole.setObjectFile("maskFile.xlsx");
                            s.SkipRecord();
                            break;
                        }
                        case 4:
                        {
                            s.GetLong();//length

                            var type2 = s.GetUChar();
                            s.SkipRecord();
                            break;
                        }
                        default:
                        {
                            s.SkipRecord();
                            break;
                        }
                    }
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }


        if (dxaOrig > 0 && dyaOrig > 0) {
			var ratio = 4 / 3 / 20;//twips to px
			ole.setPixSizes(ratio * dxaOrig, ratio * dyaOrig);
		}
        s.Seek2(_end_rec);
    }

    this.ReadGeometry = function(_xfrm)
    {
        var geom = null;

        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        if (s.cur < _end_rec)
        {
            var _t = s.GetUChar();

            if (1 == _t)
            {
                // preset shape

                var _len = s.GetULong();
                var _s = s.cur;
                var _e = _s + _len;

                s.Skip2(1); // start attributes

                while (true)
                {
                    var _at = s.GetUChar();
                    if (_at == g_nodeAttributeEnd)
                        break;

                    if (0 == _at)
                    {
                        var tmpStr = s.GetString2();
                        geom = AscFormat.CreateGeometry(tmpStr);
                        geom.isLine = tmpStr == "line";
                        geom.setPreset(tmpStr);
                    }

                    else
                        break;
                }

                while (s.cur < _e)
                {
                    var _at = s.GetUChar();
                    switch (_at)
                    {
                        case 0:
                        {
                            this.ReadGeomAdj(geom);
                            break;
                        }
                        default:
                        {
                            s.SkipRecord();
                            break;
                        }
                    }
                }
            }
            else if (2 == _t)
            {
                var _len = s.GetULong();
                var _s = s.cur;
                var _e = _s + _len;

                geom = AscFormat.CreateGeometry("");
                geom.preset = null;
                while (s.cur < _e)
                {
                    var _at = s.GetUChar();
                    switch (_at)
                    {
                        case 0:
                        {
                            this.ReadGeomAdj(geom);
                            break;
                        }
                        case 1:
                        {
                            this.ReadGeomGd(geom);
                            break;
                        }
                        case 2:
                        {
                            this.ReadGeomAh(geom);
                            break;
                        }
                        case 3:
                        {
                            this.ReadGeomCxn(geom);
                            break;
                        }
                        case 4:
                        {
                            this.ReadGeomPathLst(geom, _xfrm);
                            break;
                        }
                        case 5:
                        {
                            this.ReadGeomRect(geom);
                            break;
                        }
                        default:
                        {
                            s.SkipRecord();
                            break;
                        }
                    }
                }
            }
        }

        s.Seek2(_end_rec);
        return geom;
    }

    this.ReadGeomAdj = function(geom)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        var _c = s.GetULong();

        for (var i = 0; i < _c; i++)
        {
            s.Skip2(6); // type + len + start attributes

            var arr = [];
            var cp = 0;

            while (true)
            {
                var _at = s.GetUChar();
                if (_at == g_nodeAttributeEnd)
                    break;

                if (cp == 1)
                    arr[cp] = s.GetLong();
                else
                    arr[cp] = s.GetString2();
                cp++;
            }

            if (arr.length >= 3)
                geom.AddAdj(arr[0], arr[1], arr[2]);
        }

        s.Seek2(_end_rec);
    }

    this.ReadGeomGd = function(geom)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        var _c = s.GetULong();

        for (var i = 0; i < _c; i++)
        {
            s.Skip2(6); // type + len + start attributes

            var arr = [];
            var cp = 0;

            while (true)
            {
                var _at = s.GetUChar();
                if (_at == g_nodeAttributeEnd)
                    break;

                if (cp == 1)
                    arr[cp] = s.GetLong();
                else
                    arr[cp] = s.GetString2();
                cp++;
            }

            geom.AddGuide(arr[0], arr[1], arr[2], arr[3], arr[4]);
        }

        s.Seek2(_end_rec);
    }

    this.ReadGeomAh = function(geom)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        var _c = s.GetULong();

        for (var i = 0; i < _c; i++)
        {
            var _type1 = s.GetUChar();
            s.Skip2(4); // len
            var _type = s.GetUChar();
            s.Skip2(5); // len + start attributes

            var arr = [];
            while (true)
            {
                var _at = s.GetUChar();
                if (_at == g_nodeAttributeEnd)
                    break;

                arr[_at] = s.GetString2();
            }

            if (1 == _type)
                geom.AddHandlePolar(arr[2], arr[6], arr[4], arr[3], arr[7], arr[5], arr[0], arr[1]);
            else
                geom.AddHandleXY(arr[2], arr[6], arr[4], arr[3], arr[7], arr[5], arr[0], arr[1]);
        }

        s.Seek2(_end_rec);
    }

    this.ReadGeomCxn = function(geom)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        var _c = s.GetULong();

        for (var i = 0; i < _c; i++)
        {
            var _type = s.GetUChar();
            s.Skip2(5); // len + start attributes

            var arr = [];
            while (true)
            {
                var _at = s.GetUChar();
                if (_at == g_nodeAttributeEnd)
                    break;

                arr[_at] = s.GetString2();
            }

            geom.AddCnx(arr[2], arr[0], arr[1]);
        }

        s.Seek2(_end_rec);
    }

    this.ReadGeomRect = function(geom)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        var arr = [];
        arr[0] = "l";
        arr[1] = "t";
        arr[2] = "r";
        arr[3] = "b";
        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            arr[_at] = s.GetString2();
        }

        geom.AddRect(arr[0], arr[1], arr[2], arr[3]);

        s.Seek2(_end_rec);
    }

    this.ReadGeomPathLst = function(geom, _xfrm)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        var _c = s.GetULong();

        for (var i = 0; i < _c; i++)
        {
            var _type = s.GetUChar();
            var _len = s.GetULong();

            var _s = s.cur;
            var _e = _s + _len;
            s.Skip2(1); // start attributes

            var extrusionOk = false;
            var fill = 5;
            var stroke = true;
            var w = undefined;
            var h = undefined;

            while (true)
            {
                var _at = s.GetUChar();
                if (_at == g_nodeAttributeEnd)
                    break;

                switch (_at)
                {
                    case 0:
                    {
                        extrusionOk = s.GetBool();
                        break;
                    }
                    case 1:
                    {
                        fill = s.GetUChar();
                        break;
                    }
                    case 2:
                    {
                        h = s.GetLong();
                        break;
                    }
                    case 3:
                    {
                        stroke = s.GetBool();
                        break;
                    }
                    case 4:
                    {
                        w = s.GetLong();
                        break;
                    }
                    default:
                        break;
                }
            }

            geom.AddPathCommand(0, extrusionOk, (fill == 4) ? "none" : "norm", stroke, w, h);
            var isKoords = false;

            while (s.cur < _e)
            {
                var _at = s.GetUChar();
                switch (_at)
                {
                    case 0:
                    {
                        s.Skip2(4); // len

                        var _cc = s.GetULong();

                        for (var j = 0; j < _cc; j++)
                        {
                            s.Skip2(5); // type + len
                            isKoords |= this.ReadUniPath2D(geom);
                        }

                        break;
                    }
                    default:
                    {
                        s.SkipRecord();
                        break;
                    }
                }
            }

            s.Seek2(_e);
        }

        var _path = geom.pathLst[geom.pathLst.length - 1];
        if (isKoords && undefined === _path.pathW && undefined === _path.pathH)
        {
            _path.pathW = _xfrm.extX * c_dScalePPTXSizes;
            _path.pathH = _xfrm.extY * c_dScalePPTXSizes;

            if(_path.pathW != undefined)
            {
                _path.divPW = 100/_path.pathW;
                _path.divPH = 100/_path.pathH;
            }
        }

        s.Seek2(_end_rec);
    }

    this.ReadUniPath2D = function(geom)
    {
        var s = this.stream;

        var _type = s.GetUChar();
        var _len = s.GetULong();

        var _s = s.cur;
        var _e = _s + _len;

        if (3 == _type)
        {
            geom.AddPathCommand(6);
            s.Seek2(_e);
            return;
        }

        s.Skip2(1);

        var isKoord = false;

        var arr = [];
        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            arr[_at] = s.GetString2();

            if (!isKoord && !isNaN(parseInt(arr[_at])))
                isKoord = true;
        }

        switch (_type)
        {
            case 1:
            {
                geom.AddPathCommand(1, arr[0], arr[1]);
                break;
            }
            case 2:
            {
                geom.AddPathCommand(2, arr[0], arr[1]);
                break;
            }
            case 3:
            {
                geom.AddPathCommand(6);
                break;
            }
            case 4:
            {
                geom.AddPathCommand(5, arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]);
                break;
            }
            case 5:
            {
                geom.AddPathCommand(3, arr[0], arr[1], arr[2], arr[3]);
                break;
            }
            case 6:
            {
                geom.AddPathCommand(4, arr[0], arr[1], arr[2], arr[3]);
                break;
            }
            default:
            {
                s.SkipRecord();
                break;
            }
        }

        s.Seek2(_e);

        return isKoord;
    }

    // ------------------------------------------

    this.ReadGraphicObject = function()
    {
        var s = this.stream;
        var _type = s.GetUChar();
        var _object = null;

        switch (_type)
        {
            case 1:
            {
                _object = this.ReadShape();
                break;
            }
            case 2://pic
            case 6://ole
            case 7://video
            case 8://audio
            {
                _object = this.ReadPic(_type);
                break;
            }
            case 3:
            {
                _object = this.ReadCxn();
                break;
            }
            case 4:
            {
                _object = this.ReadGroupShape();
                break;
            }
            case 5:
            {
                _object = this.ReadGrFrame();
                break;
            }
            default:
            {
                s.SkipRecord();
                break;
            }
        }

        return _object;
    }

    // SHAPE PROPERTIES -------------------------

    this.ReadShape = function()
    {
        var s = this.stream;

        var shape = new AscFormat.CShape(this.TempMainObject);
        if (null != this.TempGroupObject)
            shape.Container = this.TempGroupObject;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;
        shape.setBDeleted(false);
        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    shape.attrUseBgFill = s.GetBool();
                    break;
                }
                default:
                    break;
            }
        }

        var txXfrm = null;
        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    var pr = this.ReadNvUniProp(shape);
                    shape.setNvSpPr(pr);
                    if(AscFormat.isRealNumber(pr.locks))
                    {
                        shape.setLocks(pr.locks);
                    }
                    break;
                }
                case 1:
                {
                    var sp_pr = new AscFormat.CSpPr();
                    this.ReadSpPr(sp_pr);
                    shape.setSpPr(sp_pr);
                    sp_pr.setParent(shape);
                    break;
                }
                case 2:
                {
                    shape.setStyle(this.ReadShapeStyle());
                    break;
                }
                case 3:
                {
                    shape.setTxBody(this.ReadTextBody(shape));
                    shape.txBody.setParent(shape);
                    break;
                }
				case 6:
				{
                    txXfrm = this.ReadXfrm();
					break;
				}
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }
        if(txXfrm && AscFormat.isRealNumber(txXfrm.rot) && shape.txBody){
            var oCopyBodyPr;
            var rot2 = txXfrm.rot;
            while(rot2 < 0){
                rot2 += 2*Math.PI;
            }
            var nSquare = ((2.0*rot2/Math.PI + 0.5) >> 0);
            while (nSquare < 0){
                nSquare += 4;
            }
            switch (nSquare){
                case 0:
                {
                    oCopyBodyPr = shape.txBody.bodyPr ? shape.txBody.bodyPr.createDuplicate() : new AscFormat.CBodyPr();
                    oCopyBodyPr.rot = (rot2/AscFormat.cToRad + 0.5) >> 0;
                    shape.txBody.setBodyPr(oCopyBodyPr);
                    break;
                }
                case 1:
                {
                    oCopyBodyPr = shape.txBody.bodyPr ? shape.txBody.bodyPr.createDuplicate() : new AscFormat.CBodyPr();
                    oCopyBodyPr.vert = AscFormat.nVertTTvert;
                    shape.txBody.setBodyPr(oCopyBodyPr);
                    break;
                }
                case 2:
                {
                    oCopyBodyPr = shape.txBody.bodyPr ? shape.txBody.bodyPr.createDuplicate() : new AscFormat.CBodyPr();
                    oCopyBodyPr.rot = (rot2/AscFormat.cToRad + 0.5) >> 0;
                    shape.txBody.setBodyPr(oCopyBodyPr);
                    break;
                }
                case 3:
                {
                    oCopyBodyPr = shape.txBody.bodyPr ? shape.txBody.bodyPr.createDuplicate() : new AscFormat.CBodyPr();
                    oCopyBodyPr.vert = AscFormat.nVertTTvert270;
                    shape.txBody.setBodyPr(oCopyBodyPr);
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return shape;
    };

    this.CheckGroupXfrm = function(oGroup){
        if(!oGroup || !oGroup.spPr){
            return;
        }
        if(!oGroup.spPr.xfrm && oGroup.spTree.length > 0){
            var oXfrm = new AscFormat.CXfrm();
            oXfrm.setOffX(0);
            oXfrm.setOffY(0);
            oXfrm.setChOffX(0);
            oXfrm.setChOffY(0);
            oXfrm.setExtX(50);
            oXfrm.setExtY(50);
            oXfrm.setChExtX(50);
            oXfrm.setChExtY(50);
            oGroup.spPr.setXfrm(oXfrm);
            oGroup.updateCoordinatesAfterInternalResize();
            oGroup.spPr.xfrm.setParent(oGroup.spPr);
        }
    };

    this.ReadGroupShape = function()
    {
        var s = this.stream;

        var shape = new AscFormat.CGroupShape();
        shape.setBDeleted(false);
        this.TempGroupObject = shape;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    var pr = this.ReadNvUniProp(shape);
                    shape.setNvSpPr(pr);
                    if(AscFormat.isRealNumber(pr.locks))
                    {
                        shape.setLocks(pr.locks);
                    }
                    break;
                }
                case 1:
                {
                    var spPr = new AscFormat.CSpPr();
                    this.ReadGrSpPr(spPr);
                    shape.setSpPr(spPr);
                    spPr.setParent(shape);
                    break;
                }
                case 2:
                {
                    s.Skip2(4); // len
                    var _c = s.GetULong();
                    for (var i = 0; i < _c; i++)
                    {
                        s.Skip2(1);
                        var __len = s.GetULong();
                        if (__len == 0)
                            continue;

                        var _type = s.GetUChar();

                        var _object = null;

                        switch (_type)
                        {
                            case 1:
                            {
                                _object = this.ReadShape();
                                if (!IsHiddenObj(_object) && _object.spPr && _object.spPr.xfrm)
                                {
                                    shape.addToSpTree(shape.spTree.length,_object);
                                    shape.spTree[shape.spTree.length-1].setGroup(shape);
                                }
                                break;
                            }
                            case 6:
                            case 2:
                            case 7:
                            case 8:
                            {
                                _object = this.ReadPic(_type);
                                if (!IsHiddenObj(_object) && _object.spPr && _object.spPr.xfrm)
                                {
                                    shape.addToSpTree(shape.spTree.length,_object);
                                    shape.spTree[shape.spTree.length-1].setGroup(shape);
                                }
                                break;
                            }
                            case 3:
                            {
                                _object = this.ReadCxn();
                                if (!IsHiddenObj(_object) && _object.spPr && _object.spPr.xfrm)
                                {
                                    shape.addToSpTree(shape.spTree.length,_object);
                                    shape.spTree[shape.spTree.length-1].setGroup(shape);
                                }
                                break;
                            }
                            case 4:
                            {
                                _object = this.ReadGroupShape();
                                if (!IsHiddenObj(_object) && _object.spPr && _object.spPr.xfrm && _object.spTree.length > 0)
                                {
                                    shape.addToSpTree(shape.spTree.length,_object);
                                    shape.spTree[shape.spTree.length-1].setGroup(shape);
                                    this.TempGroupObject = shape;
                                }
                                break;
                            }
                            case 5:
                            {
                                var _ret = null;
                                if ("undefined" != typeof(AscFormat.CGraphicFrame))
                                    _ret = this.ReadGrFrame();
                                else
                                    _ret = this.ReadChartDataInGroup(shape);
                                if (null != _ret)
                                {
                                    shape.addToSpTree(shape.spTree.length, _ret);
                                    shape.spTree[shape.spTree.length-1].setGroup(shape);
                                }
                                break;
                            }
                            default:
                            {
                                s.SkipRecord();
                                break;
                            }
                        }
                    }
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }
        this.CheckGroupXfrm(shape);
        s.Seek2(_end_rec);
        this.TempGroupObject = null;
        return shape;
    }

    this.ReadGroupShapeMain = function()
    {
        var s = this.stream;

        var shapes = [];

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        s.Skip2(5); // type SPTREE + len

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    var _len = s.GetULong();
                    s.Skip2(_len);
                    break;
                }
                case 1:
                {
                    var _len = s.GetULong();
                    s.Skip2(_len);
                    break;
                }
                case 2:
                {
                    s.Skip2(4); // len
                    var _c = s.GetULong();
                    for (var i = 0; i < _c; i++)
                    {
                        s.Skip2(1);
                        var __len = s.GetULong();
                        if (__len == 0)
                            continue;

                        var _type = s.GetUChar();

                        switch (_type)
                        {
                            case 1:
                            {
                                var _object = this.ReadShape();
                                if (!IsHiddenObj(_object))
                                {
                                    shapes[shapes.length] = _object;
                                    _object.setParent2(this.TempMainObject);
                                }
                                break;
                            }
                            case 6:
                            case 2:
                            case 7:
                            case 8:
                            {
                                var _object = this.ReadPic(_type);
                                if (!IsHiddenObj(_object))
                                {
                                    shapes[shapes.length] = _object;
                                    _object.setParent2(this.TempMainObject);
                                }
                                break;
                            }
                            case 3:
                            {
                                var _object = this.ReadCxn();
                                if (!IsHiddenObj(_object))
                                {
                                    shapes[shapes.length] = _object;
                                    _object.setParent2(this.TempMainObject);
                                }
                                break;
                            }
                            case 4:
                            {
                                var _object = this.ReadGroupShape();
                                if (!IsHiddenObj(_object))
                                {
                                    shapes[shapes.length] = _object;
                                    _object.setParent2(this.TempMainObject);
                                }
                                break;
                            }
                            case 5:
                            {
                                var _ret = this.ReadGrFrame();
                                if (null != _ret)
                                {
                                    shapes[shapes.length] = _ret;
                                    _ret.setParent2(this.TempMainObject);
                                }
                                break;
                            }
                            default:
                            {
                                s.SkipRecord();
                                break;
                            }
                        }
                    }
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return shapes;
    }


    this.ReadPic = function(type)
    {
        var s = this.stream;

        var isOle = (type === 6);
        var pic = isOle ? new AscFormat.COleObject(this.TempMainObject) : new AscFormat.CImageShape(this.TempMainObject);

        pic.setBDeleted(false);

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        var sMaskFileName;
        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    var pr = this.ReadNvUniProp(pic);
                    pic.setNvSpPr(pr);
                    if(AscFormat.isRealNumber(pr.locks)){
                        pic.setLocks(pr.locks);
                    }
                    break;
                }
                case 1:
                {
                    pic.setBlipFill(this.ReadUniFill(null, pic, null).fill);
                    break;
                }
                case 2:
                {

                    var spPr = new AscFormat.CSpPr();
                    spPr.setParent(pic);
                    this.ReadSpPr(spPr);
                    pic.setSpPr(spPr);
                    break;
                }
                case 3:
                {
                    pic.setStyle(this.ReadShapeStyle());
                    break;
                }
                case 4:
                {
                    if(isOle) {
                        this.ReadOleInfo(pic);
                        if(pic.m_sObjectFile === "maskFile.docx"
                            ||  pic.m_sObjectFile === "maskFile.xlsx"){
                            var oParent = pic.parent;
                            pic = AscFormat.CImageShape.prototype.copy.call(pic);
                            if(oParent){
                                pic.setParent(oParent);
                            }
                        }
                    } else {
                        s.SkipRecord();
                    }
                    break;
                }
                case 5:
                {
                    if(type === 7 || type === 8){//video or audio
                        s.GetLong();
                        s.GetUChar();//start attributes

                        while(true)
                        {
                            var _at2 = s.GetUChar();
                            if (_at2 == g_nodeAttributeEnd)
                                break;
                            switch (_at2) {
                                case 0:
                                {
                                    sMaskFileName = s.GetString2();
                                    break;
                                }
                                case 1:
                                {
                                    s.GetBool();
                                    break;
                                }
                                default:
                                {
                                    break;
                                }
                            }
                        }

                    }
                    else{
                        s.SkipRecord();
                    }
                    break;
                }
                default:
                {
                    this.stream.SkipRecord();
                    break;
                }
            }
        }

        if(type === 7 || type === 8){//video or audio
            if(typeof sMaskFileName === "string" && sMaskFileName.length > 0 &&
                pic.nvPicPr && pic.nvPicPr.nvPr && pic.nvPicPr.nvPr.unimedia){
                var oUniMedia = new AscFormat.UniMedia();
                oUniMedia.type = type;
                oUniMedia.media = sMaskFileName;
                pic.nvPicPr.nvPr.setUniMedia(oUniMedia);
            }
        }
        s.Seek2(_end_rec);
        return pic;
    }
    this.ReadCxn = function()
    {
        var s = this.stream;

        var shape = new AscFormat.CConnectionShape();
        shape.setBDeleted(false);

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    var pr = this.ReadNvUniProp(shape);
                    shape.setNvSpPr(pr);
                    if(AscFormat.isRealNumber(pr.locks)){
                        shape.setLocks(pr.locks);
                    }
                    break;
                }
                case 1:
                {
                    var spPr = new AscFormat.CSpPr();
                    spPr.setParent(shape);
                    this.ReadSpPr(spPr);
                    shape.setSpPr(spPr);

                    break;
                }
                case 2:
                {
                    shape.setStyle(this.ReadShapeStyle());
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }
        this.arr_connectors.push(shape);
        s.Seek2(_end_rec);
        return shape;
    }

    this.ReadChartDataInGroup = function(group)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        this.TempGroupObject = group;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    var spid = s.GetString2();
                    break;
                }
                default:
                    break;
            }
        }

        var _nvGraphicFramePr = null;
        var _xfrm = null;
        var _chart = null;
        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    _nvGraphicFramePr = this.ReadNvUniProp(AscFormat.ExecuteNoHistory(function () {
                        return new AscFormat.CGraphicFrame();
                    }, this, []));
                    break;
                }
                case 1:
                {
                    _xfrm = this.ReadXfrm();
                    break;
                }
                case 2:
                {
                    s.SkipRecord();
                    break;
                }
                case 3:
                {
                    var _length = s.GetLong();
                    var _pos = s.cur;

                    var _stream = new AscCommon.FT_Stream2();
                    _stream.data = s.data;
                    _stream.pos = s.pos;
                    _stream.cur = s.cur;
                    _stream.size = s.size;

                    _chart = new AscFormat.CChartSpace();
                    _chart.setBDeleted(false);
                    var oBinaryChartReader = new AscCommon.BinaryChartReader(_stream);
                    oBinaryChartReader.ExternalReadCT_ChartSpace(_length, _chart, this.presentation);
                    _chart.setBDeleted(false);
                    if(AscCommon.isRealObject(_nvGraphicFramePr) && AscFormat.isRealNumber(_nvGraphicFramePr.locks))
                    {
                        _chart.setLocks(_nvGraphicFramePr.locks);
                    }
                    if(_xfrm)
                    {
                        if(!_chart.spPr)
                        {
                            _chart.setSpPr(new AscFormat.CSpPr());
                            _chart.spPr.setParent(_chart);
                        }

                        _chart.spPr.setXfrm(_xfrm);
                        _xfrm.setParent(_chart.spPr);
                    }

                    s.Seek2(_pos + _length);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);

        this.TempGroupObject = null;
        if (_chart == null)
            return null;

        return _chart;
    }

    this.ReadGrFrame = function()
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        var _graphic_frame = new AscFormat.CGraphicFrame();
        _graphic_frame.setParent2(this.TempMainObject);
        this.TempGroupObject = _graphic_frame;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    var spid = s.GetString2();
                    break;
                }
                default:
                    break;
            }
        }

        var _nvGraphicFramePr = null;
        var _xfrm = null;
        var _table = null;
        var _chart = null;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    _nvGraphicFramePr = this.ReadNvUniProp(_graphic_frame);
                    break;
                }
                case 1:
                {
                    _xfrm = this.ReadXfrm();
                    break;
                }
                case 2:
                {
                    _table = this.ReadTable(_xfrm, _graphic_frame);
                    break;
                }
                case 3:
                {
                    var _length = s.GetLong();
                    var _pos = s.cur;

                    if(typeof AscFormat.CChartSpace !== "undefined" && _length)
                    {
                        var _stream = new AscCommon.FT_Stream2();
                        _stream.data = s.data;
                        _stream.pos = s.pos;
                        _stream.cur = s.cur;
                        _stream.size = s.size;
                        _chart = new AscFormat.CChartSpace();
                        _chart.setBDeleted(false);
                        AscCommon.pptx_content_loader.ImageMapChecker = this.ImageMapChecker;
                        AscCommon.pptx_content_loader.Reader.ImageMapChecker = this.ImageMapChecker;
                        var oBinaryChartReader = new AscCommon.BinaryChartReader(_stream);
                        oBinaryChartReader.ExternalReadCT_ChartSpace(_length, _chart, this.presentation);

                    }

                    s.Seek2(_pos + _length);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);

        this.TempGroupObject = null;
        if (_table == null && _chart == null)
            return null;

        if (_table != null)
        {
            if(!_graphic_frame.spPr)
            {
                _graphic_frame.setSpPr(new AscFormat.CSpPr());
                _graphic_frame.spPr.setParent(_graphic_frame);
            }
            if(!_xfrm){
                _xfrm = new AscFormat.CXfrm();
                _xfrm.setOffX(0);
                _xfrm.setOffY(0);
                _xfrm.setExtX(0);
                _xfrm.setExtY(0);
            }
            _graphic_frame.spPr.setXfrm(_xfrm);
            _xfrm.setParent(_graphic_frame.spPr);
            _graphic_frame.setSpPr(_graphic_frame.spPr);
            _graphic_frame.setNvSpPr(_nvGraphicFramePr);
            if(AscCommon.isRealObject(_nvGraphicFramePr) && AscFormat.isRealNumber(_nvGraphicFramePr.locks))
            {
                _graphic_frame.setLocks(_nvGraphicFramePr.locks);
            }
            _graphic_frame.setGraphicObject(_table);
            _graphic_frame.setBDeleted(false);
        }
        else if (_chart != null)
        {
            if(!_chart.spPr)
            {
                _chart.setSpPr(new AscFormat.CSpPr());
                _chart.spPr.setParent(_chart);
            }
            if(!_xfrm){
                _xfrm = new AscFormat.CXfrm();
                _xfrm.setOffX(0);
                _xfrm.setOffY(0);
                _xfrm.setExtX(0);
                _xfrm.setExtY(0);
            }
            if(AscCommon.isRealObject(_nvGraphicFramePr) )
            {
                _chart.setNvSpPr(_nvGraphicFramePr);
                if(AscFormat.isRealNumber(_nvGraphicFramePr.locks)){
                    _chart.setLocks(_nvGraphicFramePr.locks);
                }
            }
            this.map_shapes_by_id[_nvGraphicFramePr.cNvPr.id] = _chart;
            _chart.spPr.setXfrm(_xfrm);
            _xfrm.setParent(_chart.spPr);
            return _chart;
        }

        return _graphic_frame;
    }

    this.ReadNvUniProp = function(drawing)
    {
        var prop = new AscFormat.UniNvPr();

        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    this.ReadCNvPr(prop.cNvPr);
                    if(AscCommon.isRealObject(drawing))
                    {
                        this.map_shapes_by_id[prop.cNvPr.id] = drawing;
                    }
                    break;
                }
                case 1:
                {

                    var end = s.cur + s.GetULong() + 4;
                    var locks = 0;
                    if(AscCommon.isRealObject(drawing))
                    {
                        var drawingType = drawing.getObjectType();
                        switch(drawingType)
                        {
                            case AscDFH.historyitem_type_Shape:
                            {
                                s.Skip2(1); // attribute start
                                while (true)
                                {
                                    var _at2 = s.GetUChar();
                                    if (_at2 == g_nodeAttributeEnd)
                                        break;

                                    var value;
                                    switch(_at2)
                                    {
                                        case 1 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noAdjustHandles | (value ? AscFormat.LOCKS_MASKS.noAdjustHandles << 1 : 0));
                                            break;
                                        }
                                        case 2 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noChangeArrowheads | (value ? AscFormat.LOCKS_MASKS.noChangeArrowheads << 1 : 0));
                                            break;
                                        }
                                        case 3 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noChangeAspect | (value ? AscFormat.LOCKS_MASKS.noChangeAspect << 1 : 0));
                                            break;
                                        }
                                        case 4 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noChangeShapeType | (value ? AscFormat.LOCKS_MASKS.noChangeShapeType << 1 : 0));
                                            break;
                                        }
                                        case 5 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noEditPoints | (value ? AscFormat.LOCKS_MASKS.noEditPoints << 1 : 0));
                                            break;
                                        }
                                        case 6 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noGrp | (value ? AscFormat.LOCKS_MASKS.noGrp << 1 : 0));
                                            break;
                                        }
                                        case 7 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noMove | (value ? AscFormat.LOCKS_MASKS.noMove << 1 : 0));
                                            break;
                                        }
                                        case 8 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noResize | (value ? AscFormat.LOCKS_MASKS.noResize << 1 : 0));
                                            break;
                                        }
                                        case 9 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noRot | (value ? AscFormat.LOCKS_MASKS.noRot << 1 : 0));
                                            break;
                                        }
                                        case 10:{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noSelect | (value ? AscFormat.LOCKS_MASKS.noSelect << 1 : 0));
                                            break;
                                        }
                                        case 11:{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noTextEdit | (value ? AscFormat.LOCKS_MASKS.noTextEdit << 1 : 0));
                                            break;
                                        }
                                    }
                                }
                                prop.locks = locks;
                                break;
                            }
                            case AscDFH.historyitem_type_GroupShape:
                            {
                                s.Skip2(1); // attribute start
                                while (true)
                                {
                                    var _at2 = s.GetUChar();
                                    if (_at2 == g_nodeAttributeEnd)
                                        break;

                                    var value;
                                    switch(_at2)
                                    {
                                        case 0:
                                        {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noChangeAspect | (value ? AscFormat.LOCKS_MASKS.noChangeAspect << 1 : 0));
                                            break;
                                        }
                                        case 1:
                                        {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noGrp | (value ? AscFormat.LOCKS_MASKS.noGrp << 1 : 0));
                                            break;
                                        }
                                        case 2:
                                        {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noMove | (value ? AscFormat.LOCKS_MASKS.noMove << 1 : 0));
                                            break;
                                        }
                                        case 3:
                                        {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noResize | (value ? AscFormat.LOCKS_MASKS.noResize << 1 : 0));
                                            break;
                                        }
                                        case 4:
                                        {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noRot | (value ? AscFormat.LOCKS_MASKS.noRot << 1 : 0));
                                            break;
                                        }
                                        case 5:
                                        {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noSelect | (value ? AscFormat.LOCKS_MASKS.noSelect << 1 : 0));
                                            break;
                                        }
                                        case 6:
                                        {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noUngrp | (value ? AscFormat.LOCKS_MASKS.noUngrp << 1 : 0));
                                            break;
                                        }
                                    }
                                }
                                prop.locks = locks;
                                break;
                            }
                            case AscDFH.historyitem_type_ImageShape:
                            {
                                s.Skip2(1); // attribute start
                                while (true)
                                {
                                    var _at2 = s.GetUChar();
                                    if (_at2 == g_nodeAttributeEnd)
                                        break;

                                    var value;
                                    switch(_at2)
                                    {
                                        case 0 :{
                                            value = s.GetBool();
                                            break;
                                        }
                                        case 1 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noAdjustHandles | (value ? AscFormat.LOCKS_MASKS.noAdjustHandles << 1 : 0));
                                            break;
                                            }
                                        case 2 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noChangeArrowheads | (value ? AscFormat.LOCKS_MASKS.noChangeArrowheads << 1 : 0));
                                            break;
                                            }
                                        case 3 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noChangeAspect | (value ? AscFormat.LOCKS_MASKS.noChangeAspect << 1 : 0));
                                            break;
                                            }
                                        case 4 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noChangeShapeType | (value ? AscFormat.LOCKS_MASKS.noChangeShapeType << 1 : 0));
                                            break;
                                            }
                                        case 5 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noCrop | (value ? AscFormat.LOCKS_MASKS.noCrop << 1 : 0));
                                            break;
                                            }
                                        case 6 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noEditPoints | (value ? AscFormat.LOCKS_MASKS.noEditPoints << 1 : 0));
                                            break;
                                            }
                                        case 7 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noGrp | (value ? AscFormat.LOCKS_MASKS.noGrp << 1 : 0));
                                            break;
                                            }
                                        case 8 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noMove | (value ? AscFormat.LOCKS_MASKS.noMove << 1 : 0));
                                            break;
                                            }
                                        case 9 :{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noResize | (value ? AscFormat.LOCKS_MASKS.noResize << 1 : 0));
                                            break;
                                            }
                                        case 10:{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noRot | (value ? AscFormat.LOCKS_MASKS.noRot << 1 : 0));
                                            break;
                                            }
                                        case 11:{
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noSelect | (value ? AscFormat.LOCKS_MASKS.noSelect << 1 : 0));
                                            break;
                                            }
                                    }
                                }
                                prop.locks = locks;
                                break;
                            }
                            case AscDFH.historyitem_type_GraphicFrame:
                            case AscDFH.historyitem_type_ChartSpace:
                            {
                                s.Skip2(1); // attribute start
                                while (true)
                                {
                                    var _at2 = s.GetUChar();
                                    if (_at2 == g_nodeAttributeEnd)
                                        break;

                                    var value;
                                    switch(_at2)
                                    {
                                        case 0: {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noChangeAspect | (value ? AscFormat.LOCKS_MASKS.noChangeAspect << 1 : 0));
                                            break;
                                        }
                                        case 1: {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noDrilldown | (value ? AscFormat.LOCKS_MASKS.noDrilldown << 1 : 0));
                                            break;
                                        }
                                        case 2: {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noGrp | (value ? AscFormat.LOCKS_MASKS.noGrp << 1 : 0));
                                            break;
                                        }
                                        case 3: {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noMove | (value ? AscFormat.LOCKS_MASKS.noMove << 1 : 0));
                                            break;
                                        }
                                        case 4: {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noResize | (value ? AscFormat.LOCKS_MASKS.noResize << 1 : 0));
                                            break;
                                        }
                                        case 5: {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noSelect | (value ? AscFormat.LOCKS_MASKS.noSelect << 1 : 0));
                                            break;
                                        }
                                    }
                                }
                                prop.locks = locks;
                                break;
                            }
                            case AscDFH.historyitem_type_Cnx:{

                                s.Skip2(1); // attribute start
                                while (true)
                                {
                                    var _at2 = s.GetUChar();
                                    if (_at2 == g_nodeAttributeEnd)
                                        break;

                                    var value;
                                    switch(_at2)
                                    {
                                        case 0: {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noAdjustHandles | (value ? AscFormat.LOCKS_MASKS.noAdjustHandles << 1 : 0));
                                            break;
                                        }
                                        case 1: {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noChangeArrowheads | (value ? AscFormat.LOCKS_MASKS.noChangeArrowheads << 1 : 0));
                                            break;
                                        }
                                        case 2: {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noChangeAspect | (value ? AscFormat.LOCKS_MASKS.noChangeAspect << 1 : 0));
                                            break;
                                        }
                                        case 3: {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noChangeShapeType | (value ? AscFormat.LOCKS_MASKS.noChangeShapeType << 1 : 0));
                                            break;
                                        }
                                        case 4: {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noEditPoints | (value ? AscFormat.LOCKS_MASKS.noEditPoints << 1 : 0));
                                            break;
                                        }
                                        case 5: {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noGrp | (value ? AscFormat.LOCKS_MASKS.noGrp << 1 : 0));
                                            break;
                                        }
                                        case 6: {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noMove | (value ? AscFormat.LOCKS_MASKS.noMove << 1 : 0));
                                            break;
                                        }
                                        case 7: {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noResize | (value ? AscFormat.LOCKS_MASKS.noResize << 1 : 0));
                                            break;
                                        }
                                        case 8: {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noRot | (value ? AscFormat.LOCKS_MASKS.noRot << 1 : 0));
                                            break;
                                        }
                                        case 9: {
                                            value = s.GetBool();
                                            locks |= (AscFormat.LOCKS_MASKS.noSelect | (value ? AscFormat.LOCKS_MASKS.noSelect << 1 : 0));
                                            break;
                                        }
                                        case 10:{
                                            prop.nvUniSpPr.stCnxId = s.GetULong();
                                            break;
                                        }
                                        case 11:{
                                            prop.nvUniSpPr.stCnxIdx = s.GetULong();
                                            break;
                                        }
                                        case 12:{
                                            prop.nvUniSpPr.endCnxId = s.GetULong();
                                            break;
                                        }
                                        case 13:{
                                            prop.nvUniSpPr.endCnxIdx = s.GetULong();
                                            break;
                                        }
                                    }
                                }
                                prop.locks = locks;
                                prop.setUniSpPr(prop.nvUniSpPr.copy());
                                break;
                            }
                        }
                    }
                    s.Seek2(end);
                    break;
                }
                case 2:
                {
                    this.ReadNvPr(prop.nvPr);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return prop;
    }

    this.ReadCNvPr = function(cNvPr)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    cNvPr.id = s.GetLong();
                    if(this.TempMainObject && cNvPr.id > this.TempMainObject.maxId)
                    {
                        this.TempMainObject.maxId = cNvPr.id;
                    }
                    break;
                }
                case 1:
                {
                    cNvPr.name = s.GetString2();
                    break;
                }
                case 2:
                {
                    cNvPr.isHidden = (1 == s.GetUChar()) ? true : false;
                    break;
                }
                case 3:
                {
                    cNvPr.title = s.GetString2();
                    break;
                }
                case 4:
                {
                    cNvPr.descr = s.GetString2();
                    break;
                }
                default:{
                    break;
                }
            }
        }

        while(s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch(_at){
                case 0:{
                    cNvPr.setHlinkClick(this.ReadHyperlink());
                    break;
                }
                case 1:{
                    cNvPr.setHlinkHover(this.ReadHyperlink());
                    break;
                }
                default:{
                    this.stream.SkipRecord();
                    break;
                }
            }
        }
        s.Seek2(_end_rec);
    }

    this.ReadTable = function(_xfrm, _graphic_frame)
    {
        if (_xfrm == null)
        {
            this.stream.SkipRecord();
            return null;
        }

        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        var cols = null;
        var rows = null;
        var _return_to_rows = 0;
        var props = null;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    props = this.ReadTablePr();
                    break;
                }
                case 1:
                {
                    s.Skip2(4);
                    var _len = s.GetULong();
                    cols = new Array(_len);
                    for (var i = 0; i < _len; i++)
                    {
                        s.Skip2(7); // type, len + startAttr + 0 (attrType)
                        cols[i] = s.GetULong() / 36000;
                        s.Skip2(1); // endAttr
                    }
                    break;
                }
                case 2:
                {
                    var _end_rec2 = s.cur + s.GetULong() + 4;
                    rows = s.GetULong();
                    _return_to_rows = s.cur;
                    s.Seek2(_end_rec2);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        var _table = new CTable(this.presentation.DrawingDocument, _graphic_frame, true, rows, cols.length, cols, true);
        _table.Reset(0, 0, _xfrm.extX, 100000, 0, 0, 1);
        if (null != props)
        {
            var style;
            if(this.map_table_styles[props.style])
            {
                _table.Set_TableStyle(this.map_table_styles[props.style].Id);
            }
            _table.Set_Pr(props.props);
            _table.Set_TableLook(props.look);
        }
        _table.SetTableLayout(tbllayout_Fixed);

        s.Seek2(_return_to_rows);

        for (var i = 0; i < rows; i++)
        {
            s.Skip2(1); // 0!
            this.ReadTableRow(_table.Content[i]);
        }

        s.Seek2(_end_rec);

        return _table;
    }

    this.ReadTableRow = function(row)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        s.Skip2(1); // start attributes

		var fMaxTopMargin = 0, fMaxBottomMargin = 0, fMaxTopBorder = 0, fMaxBottomBorder = 0;
		
		var fRowHeight = 5;
        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
					fRowHeight = s.GetULong() / 36000;
                   
                    break;
                }
                default:
                    break;
            }
        }

        s.Skip2(5); // type + len
        var _count = s.GetULong();
        _count = Math.min(_count, row.Content.length);
		for (var i = 0; i < _count; i++)
		{
			s.Skip2(1);
			var bIsNoHMerge = this.ReadCell(row.Content[i]);
			if (bIsNoHMerge === false)
			{
				row.Remove_Cell(i);
				i--;
				_count--;
			}
			var _gridCol = 1;
			if ("number" == typeof (row.Content[i].Pr.GridSpan))
			{
				_gridCol = row.Content[i].Pr.GridSpan;
			}

			if (_gridCol > (_count - i))
			{
				_gridCol = _count - i;
				row.Content[i].Pr.GridSpan = _gridCol;
				if (1 == row.Content[i].Pr.GridSpan)
					row.Content[i].Pr.GridSpan = undefined;
			}

			_gridCol--;
			while (_gridCol > 0)
			{
				i++;
				if (i >= _count)
					break;

				s.Skip2(1);
				this.ReadCell(row.Content[i]);

				// удаляем
				row.Remove_Cell(i);
				i--;
				_count--;

				--_gridCol;
			}
		}

		if(this.presentation && Array.isArray(this.presentation.Slides)){
            var bLoadVal = AscCommon.g_oIdCounter.m_bLoad;
            var bRead = AscCommon.g_oIdCounter.m_bRead;
            AscCommon.g_oIdCounter.m_bLoad = false;
            AscCommon.g_oIdCounter.m_bRead = false;
            for(i = 0;  i < row.Content.length; ++i){
                var oCell = row.Content[i];
                var oMargins = oCell.GetMargins();
                if(oMargins.Bottom.W > fMaxBottomMargin){
                    fMaxBottomMargin = oMargins.Bottom.W;
                }
                if(oMargins.Top.W > fMaxTopMargin){
                    fMaxTopMargin = oMargins.Top.W;
                }
                var oBorders = oCell.Get_Borders();
                if(oBorders.Top.Size > fMaxTopBorder){
                    fMaxTopBorder = oBorders.Top.Size;
                }
                if(oBorders.Bottom.Size > fMaxBottomBorder){
                    fMaxBottomBorder = oBorders.Bottom.Size;
                }
            }
            AscCommon.g_oIdCounter.m_bLoad = bLoadVal;
            AscCommon.g_oIdCounter.m_bRead = bRead;
            row.Set_Height(Math.max(1, fRowHeight - fMaxTopMargin - fMaxBottomMargin - fMaxTopBorder/2 - fMaxBottomBorder/2), Asc.linerule_AtLeast);
        }
        s.Seek2(_end_rec);
    }

    this.ReadCell = function(cell)
    {
        // cell.Content.Content.splice(0, cell.Content.Content.length);
        cell.Content.Internal_Content_RemoveAll();
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    var _id = s.GetString2();
                    break;
                }
                case 1:
                {
                    var rowSpan = s.GetULong();
                    if (1 < rowSpan)
                    {
                        cell.SetVMerge(vmerge_Restart);
                    }
                    break;
                }
                case 2:
                {
                    cell.Set_GridSpan(s.GetULong());
                    break;
                }
                case 3:
                {
                    var bIsHMerge = s.GetBool();
                    if (bIsHMerge)
                    {
                        s.Seek2(_end_rec);
                        return false;
                    }
                    break;
                }
                case 4:
                {
                    var bIsVMerge = s.GetBool();
                    if (bIsVMerge && cell.Pr.VMerge != vmerge_Restart)
                    {
                        cell.SetVMerge(vmerge_Continue);
                    }
                    break;
                }
                default:
                    break;
            }
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    var props = new CTableCellPr();
                    this.ReadCellProps(props);
                    props.Merge(cell.Pr);
                    cell.Set_Pr(props);
                    break;
                }
                case 1:
                {
                    this.ReadTextBody2(cell.Content);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return true;
    }

    this.ReadCellProps = function(props)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        //props.TableCellMar = {};
        //props.TableCellMar.Top    = new CTableMeasurement(tblwidth_Mm, 1.27);
        //props.TableCellMar.Left   = new CTableMeasurement(tblwidth_Mm, 2.54);
        //props.TableCellMar.Bottom = new CTableMeasurement(tblwidth_Mm, 1.27);
        //props.TableCellMar.Right  = new CTableMeasurement(tblwidth_Mm, 2.54);

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    if(props.TableCellMar == null)
                        props.TableCellMar = {};
                    props.TableCellMar.Left   = new CTableMeasurement(tblwidth_Mm, s.GetULong() / 36000);
                    //props.TableCellMar.Left.W = s.GetULong() / 36000;
                    break;
                }
                case 1:
                {
                    if(props.TableCellMar == null)
                        props.TableCellMar = {};
                    props.TableCellMar.Top = new CTableMeasurement(tblwidth_Mm, s.GetULong() / 36000);

                    //  props.TableCellMar.Top.W = s.GetULong() / 36000;
                    break;
                }
                case 2:
                {
                    if(props.TableCellMar == null)
                        props.TableCellMar = {};
                    props.TableCellMar.Right   = new CTableMeasurement(tblwidth_Mm, s.GetULong() / 36000);
                    // props.TableCellMar.Right.W = s.GetULong() / 36000;
                    break;
                }
                case 3:
                {
                    if(props.TableCellMar == null)
                        props.TableCellMar = {};
                    props.TableCellMar.Bottom   = new CTableMeasurement(tblwidth_Mm, s.GetULong() / 36000);

                    //props.TableCellMar.Bottom.W = s.GetULong() / 36000;
                    break;
                }
                case 4:
                {
                    s.Skip2(1);
                    break;
                }
                case 5:
                {
                    var nVert = s.GetUChar();
                    switch (nVert)
                    {
                        case 0: props.TextDirection = Asc.c_oAscCellTextDirection.TBRL; break;
                        case 1: props.TextDirection = Asc.c_oAscCellTextDirection.LRTB;/*_T("horz"); */break;
                        case 2: props.TextDirection = Asc.c_oAscCellTextDirection.TBRL; break;
                        case 3: props.TextDirection = Asc.c_oAscCellTextDirection.TBRL; break;
                        case 4: props.TextDirection = Asc.c_oAscCellTextDirection.BTLR; break;
                        case 5: props.TextDirection = Asc.c_oAscCellTextDirection.BTLR; break;
                        case 6: props.TextDirection = Asc.c_oAscCellTextDirection.TBRL; break;
                        default:
                            props.TextDirection = LRTB;
                            break;
                    }
                    break;
                }
                case 6:
                {
                    var nVertAlign = s.GetUChar();
                    switch (nVertAlign)
                    {
                        case 0://bottom
                        {
                            props.VAlign = vertalignjc_Bottom;
                            break;
                        }
                        case 1://ctr
                        case 2://dist
                        case 3: //just
                        {
                            props.VAlign = vertalignjc_Center;
                            break;
                        }
                        case 4://top
                        {
                            props.VAlign = vertalignjc_Top;
                            break;
                        }
                    }
                    //s.Skip2(1);
                    break;
                }
                case 7:
                {
                    s.Skip2(1);
                    break;
                }
                default:
                    break;
            }
        }


        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    if(!props.TableCellBorders)
                    {
                        props.TableCellBorders = {};
                    }
                    props.TableCellBorders.Left = this.ReadTableBorderLn();
                    break;
                }
                case 1:
                {
                    if(!props.TableCellBorders)
                    {
                        props.TableCellBorders = {};
                    }
                    props.TableCellBorders.Top = this.ReadTableBorderLn();
                    break;
                }
                case 2:
                {
                    if(!props.TableCellBorders)
                    {
                        props.TableCellBorders = {};
                    }
                    props.TableCellBorders.Right = this.ReadTableBorderLn();
                    break;
                }
                case 3:
                {
                    if(!props.TableCellBorders)
                    {
                        props.TableCellBorders = {};
                    }
                    props.TableCellBorders.Bottom = this.ReadTableBorderLn();
                    break;
                }
                case 4:
                {
                    s.SkipRecord();
                    break;
                }
                case 5:
                {
                    s.SkipRecord();
                    break;
                }
                case 6:
                {
                    var _unifill = this.ReadUniFill();

                    if (_unifill && _unifill.fill !== undefined && _unifill.fill != null)
                    {
                        props.Shd = new CDocumentShd();
                        props.Shd.Value = c_oAscShdClear;
                        props.Shd.Unifill = _unifill;
                    }
                    break;
                }
                case 7:
                {
                    s.SkipRecord();
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
    }

    this.ReadTableBorderLn = function()
    {
        var ln = this.ReadLn();

        var border = new CDocumentBorder();
        if(ln.Fill)
        {
            border.Unifill = ln.Fill;
        }
        border.Size = (ln.w == null) ? 12700 : ((ln.w) >> 0);
        border.Size /= 36000;

        border.Value = border_Single;

        return border;
    }

    this.ReadTablePr = function()
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        var obj = {};
        obj.props = new CTablePr();
        obj.look = new CTableLook(false, false, false, false, false, false);
        obj.style = -1;

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                   //var ind = this.map_table_styles[s.GetString2()];
                   //if (undefined !== ind)
                    obj.style = s.GetString2();
                    break;
                }
                case 1:
                {
                    s.Skip2(1);// rtl
                    break;
                }
                case 2:
                {
                    obj.look.m_bFirst_Row = s.GetBool();
                    break;
                }
                case 3:
                {
                    obj.look.m_bFirst_Col = s.GetBool();
                    break;
                }
                case 4:
                {
                    obj.look.m_bLast_Row = s.GetBool();
                    break;
                }
                case 5:
                {
                    obj.look.m_bLast_Col = s.GetBool();
                    break;
                }
                case 6:
                {
                    obj.look.m_bBand_Hor = s.GetBool();
                    break;
                }
                case 7:
                {
                    obj.look.m_bBand_Ver = s.GetBool();
                    break;
                }
                default:
                    break;
            }
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    var _unifill = this.ReadUniFill();
                    if (_unifill && _unifill.fill !== undefined && _unifill.fill != null)
                    {
                        obj.props.Shd = new CDocumentShd();
                        obj.props.Shd.Value = c_oAscShdClear;
                        obj.props.Shd.Unifill = _unifill;
                    }
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return obj;
    }

    this.ReadNvPr = function(nvPr)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    nvPr.setIsPhoto(s.GetBool());
                    break;
                }
                case 1:
                {
                    nvPr.setUserDrawn(s.GetBool());
                    break;
                }
                default:
                    break;
            }
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    nvPr.setPh(this.ReadPH());
                    break;
                }
                case 1:
                {
                    nvPr.setUniMedia(new AscFormat.UniMedia());
                    var _len = s.GetULong();
                    s.Skip2(_len);
                    break;
                }
                default:
                {
                    var _len = s.GetULong();
                    s.Skip2(_len);
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
    }

    this.ReadPH = function()
    {
        var ph = new AscFormat.Ph();
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    ph.setHasCustomPrompt(s.GetBool());
                    break;
                }
                case 1:
                {
                    ph.setIdx(s.GetString2());
                    break;
                }
                case 2:
                {
                    ph.setOrient(s.GetUChar());
                    break;
                }
                case 3:
                {
                    ph.setSz(s.GetUChar());
                    break;
                }
                case 4:
                {
                    ph.setType(s.GetUChar());
                    break;
                }
                default:
                    break;
            }
        }

        s.Seek2(_end_rec);
        return ph;
    }

    // ------------------------------------------

    // TEXT PROPERTIES --------------------------

    this.ReadRunProperties = function()
    {
        var rPr = new CTextPr();

        var s = this.stream;
        var _end_rec = s.cur + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    var altLang = s.GetString2();
                    break;
                }
                case 1:
                {
                    rPr.Bold = s.GetBool();
                    break;
                }
                case 2:
                {
                    var baseline = s.GetLong();

                    if (baseline < 0)
                        rPr.VertAlign = AscCommon.vertalign_SubScript;
                    else if (baseline > 0)
                        rPr.VertAlign = AscCommon.vertalign_SuperScript;

                    break;
                }
                case 3:
                {
                    var bmk = s.GetString2();
                    break;
                }
                case 4:
                {
                    var _cap = s.GetUChar();
                    if (_cap == 0)
                    {
                        rPr.Caps = true;
                        rPr.SmallCaps = false;
                    }
                    else if (_cap == 1)
                    {
                        rPr.Caps = false;
                        rPr.SmallCaps = true;
                    }
                    else if (_cap == 2)
                    {
                        rPr.SmallCaps = false;
                        rPr.Caps = false;
                    }
                    break;
                }
                case 5:
                {
                    s.Skip2(1); // dirty
                    break;
                }
                case 6:
                {
                    s.Skip2(1); // error
                    break;
                }
                case 7:
                {
                    rPr.Italic = s.GetBool();
                    break;
                }
                case 8:
                {
                    s.Skip2(4); // kern
                    break;
                }
                case 9:
                {
                    s.Skip2(1); // kumimoji
                    break;
                }
                case 10:
                {
                    var lang = s.GetString2();
                    var nLcid = g_oLcidNameToIdMap[lang];
                    if(nLcid)
                        rPr.Lang.Val = nLcid;
                    break;
                }
                case 11:
                {
                    s.Skip2(1); // noproof
                    break;
                }
                case 12:
                {
                    s.Skip2(1); // normalizeH
                    break;
                }
                case 13:
                {
                    s.Skip2(1); // smtClean
                    break;
                }
                case 14:
                {
                    s.Skip2(4); // smtId
                    break;
                }
                case 15:
                {
                    //s.Skip2(4); // spc
                    rPr.Spacing = s.GetLong() * 25.4 / 7200;
                    break;
                }
                case 16:
                {
                    var _strike = s.GetUChar();
                    if (0 == _strike)
                    {
                        rPr.Strikeout = false;
                        rPr.DStrikeout = true;
                    }
                    else if (2 == _strike)
                    {
                        rPr.Strikeout = true;
                        rPr.DStrikeout = false;
                    }
                    else
                    {
                        rPr.Strikeout = false;
                        rPr.DStrikeout = false;
                    }
                    break;
                }
                case 17:
                {
                    var _size = s.GetLong() / 100;
                    _size = ((_size * 2) + 0.5) >> 0;
                    _size /= 2;
                    rPr.FontSize = _size;
                    break;
                }
                case 18:
                {
                    rPr.Underline = (s.GetUChar() != 12);
                    break;
                }
                default:
                    break;
            }
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    rPr.TextOutline = this.ReadLn();
                    break;
                }
                case 1:
                {
                    var oUniFill = this.ReadUniFill();
                    if(oUniFill && oUniFill.fill){
                        rPr.Unifill = oUniFill;
                    }
                    break;
                }
                case 2:
                {
                    s.SkipRecord();
                    break;
                }
                case 3:
                {
                    //latin
                    rPr.RFonts.Ascii = { Name: this.ReadTextFontTypeface(), Index : -1 };
                    rPr.RFonts.HAnsi = { Name: rPr.RFonts.Ascii.Name, Index : -1 };
                    break;
                }
                case 4:
                {
                    //ea
                    rPr.RFonts.EastAsia = { Name: this.ReadTextFontTypeface(), Index : -1 };
                    break;
                }
                case 5:
                {
                    //cs
                    rPr.RFonts.CS = { Name: this.ReadTextFontTypeface(), Index : -1 };
                    break;
                }
                case 6:
                {
                    //sym

                    s.SkipRecord();
                    //rPr.RFonts.HAnsi = { Name: this.ReadTextFontTypeface(), Index : -1 };
                    break;
                }
                case 7:
                {
                    rPr.hlink = this.ReadHyperlink();
                    if (null == rPr.hlink)
                        delete rPr.hlink;
                    break;
                }
                case 8:
                {
                    s.SkipRecord();
                    break;
                }
                default:
                {
                    s.SkipRecord();
                }
            }
        }

        s.Seek2(_end_rec);
        //checkTextPr(rPr);
        return rPr;
    }

    this.ReadHyperlink = function()
    {
        var hyper = new AscFormat.CT_Hyperlink();
        var s = this.stream;
        var _end_rec = s.cur + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    hyper.id = s.GetString2();
                    break;
                }
                case 1:
                {
                    hyper.invalidUrl = s.GetString2();
                    break;
                }
                case 2:
                {
                    hyper.action = s.GetString2();
                    break;
                }
                case 3:
                {
                    hyper.tgtFrame = s.GetString2();
                    break;
                }
                case 4:
                {
                    hyper.tooltip = s.GetString2();
                    break;
                }
                case 5:
                {
                    hyper.history = s.GetBool();
                    break;
                }
                case 6:
                {
                    hyper.highlightClick = s.GetBool();
                    break;
                }
                case 7:
                {
                    hyper.endSnd = s.GetBool();
                    break;
                }
                default:
                    break;
            }
        }

        s.Seek2(_end_rec);

        // correct hyperlink
        if (hyper.action != null && hyper.action != "")
        {
            if (hyper.action == "ppaction://hlinkshowjump?jump=firstslide")
                hyper.id = "ppaction://hlinkshowjump?jump=firstslide";
            else if (hyper.action == "ppaction://hlinkshowjump?jump=lastslide")
                hyper.id = "ppaction://hlinkshowjump?jump=lastslide";
            else if (hyper.action == "ppaction://hlinkshowjump?jump=nextslide")
                hyper.id = "ppaction://hlinkshowjump?jump=nextslide";
            else if (hyper.action == "ppaction://hlinkshowjump?jump=previousslide")
                hyper.id = "ppaction://hlinkshowjump?jump=previousslide";
            else if (hyper.action == "ppaction://hlinksldjump")
            {
                if (hyper.id != null && hyper.id.indexOf("slide") == 0)
                {
                    var _url = hyper.id.substring(5);
                    var _indexXml = _url.indexOf(".");
                    if (-1 != _indexXml)
                        _url = _url.substring(0, _indexXml);

                    var _slideNum = parseInt(_url);
                    if (isNaN(_slideNum))
                        _slideNum = 1;

                    --_slideNum;

                    hyper.id = hyper.action + "slide" + _slideNum;
                }
                else
                {
                    hyper.id = null;
                }
            }
            else
            {
                hyper.id = null;
            }
        }

        if (hyper.id == null)
            return null;

        return hyper;
    }

    this.CorrectBodyPr = function(bodyPr)
    {

        //TODO: сделать через методы
        var s = this.stream;
        var _end_rec = s.cur + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    bodyPr.flatTx = s.GetLong();
                    break;
                }
                case 1:
                {
                    bodyPr.anchor = s.GetUChar();
                    break;
                }
                case 2:
                {
                    bodyPr.anchorCtr = s.GetBool();
                    break;
                }
                case 3:
                {
                    bodyPr.bIns = s.GetLong()/36000;
                    break;
                }
                case 4:
                {
                    bodyPr.compatLnSpc = s.GetBool();
                    break;
                }
                case 5:
                {
                    bodyPr.forceAA = s.GetBool();
                    break;
                }
                case 6:
                {
                    bodyPr.fromWordArt = s.GetBool();
                    break;
                }
                case 7:
                {
                    bodyPr.horzOverflow = s.GetUChar();
                    break;
                }
                case 8:
                {
                    bodyPr.lIns = s.GetLong()/36000;
                    break;
                }
                case 9:
                {
                    bodyPr.numCol = s.GetLong();
                    break;
                }
                case 10:
                {
                    bodyPr.rIns = s.GetLong()/36000;
                    break;
                }
                case 11:
                {
                    bodyPr.rot = s.GetLong();
                    break;
                }
                case 12:
                {
                    bodyPr.rtlCol = s.GetBool();
                    break;
                }
                case 13:
                {
                    bodyPr.spcCol = s.GetLong()/36000;
                    break;
                }
                case 14:
                {
                    bodyPr.spcFirstLastPara = s.GetBool();
                    break;
                }
                case 15:
                {
                    bodyPr.tIns = s.GetLong()/36000;
                    break;
                }
                case 16:
                {
                    bodyPr.upright = s.GetBool();
                    break;
                }
                case 17:
                {
                    bodyPr.vert = s.GetUChar();
                    if(bodyPr.vert === AscFormat.nVertTTwordArtVert)
                        bodyPr.vert = AscFormat.nVertTTvert;
                    break;
                }
                case 18:
                {
                    bodyPr.vertOverflow = s.GetUChar();
                    break;
                }
                case 19:
                {
                    bodyPr.wrap = s.GetUChar();
                    break;
                }
                default:
                    break;
            }
        }

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0://prstTxWarp
                {
                    var _end_rec3 = s.cur + s.GetULong() + 4;
                    s.Skip2(1);// start attributes
                    while(true)
                    {
                        var _at2 = s.GetUChar();
                        if (_at2 == g_nodeAttributeEnd)
                            break;
                        switch (_at2) {
                            case 0:
                            {
                                var sPrst = s.GetUChar();
                                bodyPr.prstTxWarp = AscFormat.ExecuteNoHistory(function () {
                                    return AscFormat.CreatePrstTxWarpGeometry(AscFormat.getPrstByNumber(sPrst));
                                }, this, []);
                                break;
                            }
                        }
                    }
                    while (s.cur < _end_rec3)
                    {
                       var _at = s.GetUChar();
                       switch (_at)
                       {
                           case 0:
                           {
                               this.ReadGeomAdj(bodyPr.prstTxWarp );
                               break;
                           }
                           default:
                           {
                               s.SkipRecord();
                               break;
                           }
                       }
                    }
                    s.Seek2(_end_rec3);
                    break;
                }
                case 1:
                {
                    var _end_rec2 = s.cur + s.GetULong() + 4;

                    s.Skip2(1); // start attributes

                    var txFit = new AscFormat.CTextFit();
                    txFit.type = -1;

                    while (true)
                    {
                        var _at2 = s.GetUChar();
                        if (_at2 == g_nodeAttributeEnd)
                            break;

                        switch (_at2)
                        {
                            case 0:
                            {
                                txFit.type = s.GetLong() - 1;
                                break;
                            }
                            case 1:
                            {
                                txFit.fontScale = s.GetLong();
                                break;
                            }
                            case 2:
                            {
                                txFit.lnSpcReduction = s.GetLong();
                                break;
                            }
                            default:
                                break;
                        }
                    }
                    if (txFit.type != -1)
                    {
                        bodyPr.textFit = txFit;
                    }

                    s.Seek2(_end_rec2);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                }
            }
        }
        s.Seek2(_end_rec);
    }

    this.ReadBodyPr = function()
    {
        var bodyPr = new AscFormat.CBodyPr();
        this.CorrectBodyPr(bodyPr);
        return bodyPr;
    }

    this.ReadTextParagraphPr = function(par)
    {

        var para_pr = new CParaPr();
        var s = this.stream;
        var _end_rec = s.cur + s.GetULong() + 4;

        s.Skip2(1); // start attributes

        while (true)
        {
            var _at = s.GetUChar();
            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0:
                {
                    var _align = s.GetUChar();
                    switch (_align)
                    {
                        case 0: { para_pr.Jc = AscCommon.align_Center; break; }
                        case 1: { para_pr.Jc = AscCommon.align_Justify; break; }
                        case 2: { para_pr.Jc = AscCommon.align_Justify; break; }
                        case 3: { para_pr.Jc = AscCommon.align_Justify; break; }
                        case 4: { para_pr.Jc = AscCommon.align_Left; break; }
                        case 5: { para_pr.Jc = AscCommon.align_Right; break; }
                        case 6: { para_pr.Jc = AscCommon.align_Justify; break; }
                        default:
                            para_pr.Jc = AscCommon.align_Center;
                            break;
                    }
                    break;
                }
                case 1:
                {
                    para_pr.DefaultTab = s.GetLong()/36000;
                    break;
                }
                case 2:
                {
                    s.Skip2(1); // eaLnBrk
                    break;
                }
                case 3:
                {
                    s.Skip2(1); // font align
                    break;
                }
                case 4:
                {
                    s.Skip2(1); // hangingPunct
                    break;
                }
                case 5:
                {
                    para_pr.Ind.FirstLine = s.GetLong()/36000;
                    break;
                }
                case 6:
                {
                    s.Skip2(1); // latinLnBrk
                    break;
                }
                case 7:
                {
                    para_pr.Lvl = s.GetLong();
                    break;
                }
                case 8:
                {
                    para_pr.Ind.Left = s.GetLong()/36000;
                    break;
                }
                case 9:
                {
                    para_pr.Ind.Right = s.GetLong()/36000;
                    break;
                }
                case 10:
                {
                    s.Skip2(1); // rtl
                    break;
                }
                default:
                    break;
            }
        }

        var bullet = new AscFormat.CBullet();
        var b_bullet = false;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    s.Skip2(5); // len start attr

                    var Pts = null;
                    var Pct = null;
                    while (true)
                    {
                        var _at = s.GetUChar();
                        if (_at == g_nodeAttributeEnd)
                            break;

                        switch (_at)
                        {
                            case 0:
                            {
                                Pct = s.GetLong();
                                para_pr.Spacing.Line = Pct/100000;
                                para_pr.Spacing.LineRule = Asc.linerule_Auto;
                                break;
                            }
                            case 1:
                            {
                                Pts = s.GetLong();
                                para_pr.Spacing.Line = Pts*0.00352777778;
                                para_pr.Spacing.LineRule = Asc.linerule_Exact;
                                break;
                            }
                            default:
                                break;
                        }
                    }


                    // lnSpc
                    // TODO:
                    break;
                }
                case 1:
                {
                    s.Skip2(5); // len + start attr

                    var Pts = null;
                    var Pct = null;
                    while (true)
                    {
                        var _at = s.GetUChar();
                        if (_at == g_nodeAttributeEnd)
                            break;

                        switch (_at)
                        {
                            case 0:
                            {
                                Pct = s.GetLong();
                                para_pr.Spacing.After = 0;
                                para_pr.Spacing.AfterPct = Pct;
                                break;
                            }
                            case 1:
                            {
                                Pts = s.GetLong();
                                para_pr.Spacing.After = Pts*0.00352777778;
                                break;
                            }
                            default:
                                break;
                        }
                    }
                    // spcAft
                    // TODO:
                    break;
                }
                case 2:
                {
                    s.Skip2(5); // len + start attr

                    var Pts = null;
                    var Pct = null;
                    while (true)
                    {
                        var _at = s.GetUChar();
                        if (_at == g_nodeAttributeEnd)
                            break;

                        switch (_at)
                        {
                            case 0:
                            {
                                Pct = s.GetLong();
                                para_pr.Spacing.Before = 0;
                                para_pr.Spacing.BeforePct = Pct;
                                break;
                            }
                            case 1:
                            {
                                Pts = s.GetLong();
                                para_pr.Spacing.Before = Pts*0.00352777778;
                                break;
                            }
                            default:
                                break;
                        }
                    }

                    // spcBef
                    // TODO:
                    break;
                }
                case 3:
                {

                    var cur_pos = s.cur;
                    var _len = s.GetULong();
                    if (0 != _len)
                    {
                        b_bullet = true;
                        bullet.bulletColor = new AscFormat.CBulletColor();
                        bullet.bulletColor.type = s.GetUChar();

                        if (bullet.bulletColor.type == AscFormat.BULLET_TYPE_COLOR_CLRTX)
                        {
                            s.SkipRecord();
                        }
                        else
                        {
                            var _l = s.GetULong();
                            if (0 !== _l) {
                                s.Skip2(1);
                                bullet.bulletColor.UniColor = this.ReadUniColor();
                            }
                        }
                    }
                    s.Seek2(cur_pos + _len + 4);
                    break;
                }
                case 4:
                {
                    var cur_pos = s.cur;
                    var _len = s.GetULong();
                    if (0 != _len)
                    {
                        b_bullet = true;
                        bullet.bulletSize = new AscFormat.CBulletSize();

                        bullet.bulletSize.type = s.GetUChar();

                        if (bullet.bulletSize.type == AscFormat.BULLET_TYPE_SIZE_TX)
                        {
                            s.SkipRecord();
                        }
                        else
                        {
                            var _l = s.GetULong();
                            s.Skip2(2); // start attributes + type
                            bullet.bulletSize.val = s.GetLong();
                            s.Skip2(1); // end attributes
                        }
                    }
                    s.Seek2(cur_pos + _len + 4);
                    break;
                }
                case 5:
                {

                    var cur_pos = s.cur;
                    var _len = s.GetULong();
                    if (0 != _len)
                    {
                        b_bullet = true;
                        bullet.bulletTypeface = new AscFormat.CBulletTypeface();
                        bullet.bulletTypeface.type = s.GetUChar();

                        if (bullet.bulletTypeface.type == AscFormat.BULLET_TYPE_TYPEFACE_BUFONT)
                        {
                            bullet.bulletTypeface.typeface = this.ReadTextFontTypeface();
                        }
                        else
                        {
                            s.SkipRecord();
                        }
                    }
                    s.Seek2(cur_pos + _len + 4);
                    break;
                }
                case 6:
                {

                    var cur_pos = s.cur;
                    var _len = s.GetULong();
                    if (0 != _len)
                    {
                        b_bullet = true;
                        bullet.bulletType = new AscFormat.CBulletType();
                        bullet.bulletType.type = s.GetUChar();

                        if (bullet.bulletType.type == AscFormat.BULLET_TYPE_BULLET_NONE)
                        {
                            s.SkipRecord();
                        }
                        else if (bullet.bulletType.type == AscFormat.BULLET_TYPE_BULLET_BLIP)
                        {
                            s.SkipRecord();
                        }
                        else if (bullet.bulletType.type == AscFormat.BULLET_TYPE_BULLET_AUTONUM)
                        {
                            s.Skip2(5); // len + type + start attr

                            while (true)
                            {
                                var _at = s.GetUChar();
                                if (_at == g_nodeAttributeEnd)
                                    break;

                                switch (_at)
                                {
                                    case 0:
                                    {
                                        bullet.bulletType.AutoNumType = s.GetUChar();
                                        break;
                                    }
                                    case 1:
                                    {
                                        bullet.bulletType.startAt = s.GetLong();
                                        break;
                                    }
                                    default:
                                        break;
                                }
                            }
                        }
                        else if (bullet.bulletType.type == AscFormat.BULLET_TYPE_BULLET_CHAR)
                        {
                            s.Skip2(6);
                            bullet.bulletType.Char = s.GetString2();
                            AscFonts.FontPickerByCharacter.getFontsByString(bullet.bulletType.Char);
                            s.Skip2(1);
                        }
                    }
                    s.Seek2(cur_pos + _len + 4);
                    break;
                }
                case 7:
                {
                    s.Skip2(4);
                    var _c = s.GetULong();

                    if (0 != _c)
                    {
                        para_pr.Tabs = new CParaTabs();
                        var _value, _pos;
                        for (var i = 0; i < _c; i++)
                        {
                            s.Skip2(6); // type, len, start attr
                            _value = null;
                            _pos = null;
                            while (true)
                            {
                                var _at = s.GetUChar();
                                if (_at == g_nodeAttributeEnd)
                                    break;

                                switch (_at)
                                {
                                    case 0:
                                    {
                                        _value = s.GetUChar();

                                        if (_value == 0)
                                            _value = tab_Center;
                                        else if (_value == 3)
                                            _value = tab_Right;
                                        else
                                            _value = tab_Left;

                                        break;
                                    }
                                    case 1:
                                    {
                                        _pos = s.GetLong() / 36000;
                                        break;
                                    }
                                    default:
                                        break;
                                }
                            }
                            para_pr.Tabs.Add(new CParaTab(_value, _pos))
                        }
                    }
                    break;
                }
                case 8:
                {
                    var OldBlipCount = 0;

                    if (this.IsUseFullUrl && par)
                        OldBlipCount = this.RebuildImages.length;

                    var r_pr = this.ReadRunProperties();
                    if(r_pr)
                    {
                        para_pr.DefaultRunPr = new CTextPr();

                        if(r_pr.Unifill && !r_pr.Unifill.fill)
                        {
                            r_pr.Unifill = undefined;
                        }
                        para_pr.DefaultRunPr.Set_FromObject(r_pr);


                        if (this.IsUseFullUrl && par)
                        {

                            if(this.RebuildImages.length > OldBlipCount)
                            {
                                for(var _t = OldBlipCount; _t < this.RebuildImages.length; ++_t)
                                {
                                    var oTextPr = new CTextPr();
                                    oTextPr.Set_FromObject(r_pr);
                                    this.RebuildImages[_t].TextPr = oTextPr;
                                    this.RebuildImages[_t].Paragraph = par;
                                }
                            }

                        }

                    }
                    break;
                }
                default:
                {
                    s.SkipRecord();
                }
            }
        }

        if(b_bullet)
            para_pr.Bullet = bullet;
        // пока записи не поддерживаем
        s.Seek2(_end_rec);
        return para_pr;
    }

    this.ReadTextListStyle = function()
    {
        var styles = new AscFormat.TextListStyle();
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            styles.levels[_at] = this.ReadTextParagraphPr();
        }

        s.Seek2(_end_rec);
        return styles;
    }

    this.ReadTextBody = function(shape)
    {
        var txbody;

        if(shape)
        {
            if(shape.txBody)
            {
                txbody = shape.txBody;
            }
            else
            {
                txbody = new AscFormat.CTextBody();
                txbody.setParent(shape);
            }
        }
        else
        {
            txbody = new AscFormat.CTextBody();
        }
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    txbody.setBodyPr(this.ReadBodyPr());
                    if(txbody.bodyPr && txbody.bodyPr.textFit)
                    {
                        this.textBodyTextFit.push(txbody);
                    }
                    break;
                }
                case 1:
                {
                    txbody.setLstStyle(this.ReadTextListStyle());
                    break;
                }
                case 2:
                {
                    s.Skip2(4);
                    var _c = s.GetULong();
                    txbody.setContent(new AscFormat.CDrawingDocContent(txbody, this.presentation ? this.presentation.DrawingDocument : null, 0, 0, 0, 0, 0, 0, true));
                    if(_c>0)
                    {
                        txbody.content.Internal_Content_RemoveAll();
                    }
                    var _last_field_type = false;
                    for (var i = 0; i < _c; i++)
                    {
                        s.Skip2(1); // type
                        var _paragraph = this.ReadParagraph(txbody.content);
                        _paragraph.Correct_Content();
                        txbody.content.Internal_Content_Add(txbody.content.Content.length, _paragraph);
                        if(_paragraph.f_type != undefined || _paragraph.f_text != undefined || _paragraph.f_id != undefined)
                        {
                            _last_field_type = true;
                        }
                    }
                    if(shape && (this.TempMainObject && typeof Slide !== "undefined" && this.TempMainObject instanceof  Slide && shape.isPlaceholder && shape.isPlaceholder() && (shape.getPlaceholderType() === AscFormat.phType_sldNum || shape.getPlaceholderType() === AscFormat.phType_dt)) && _last_field_type)
                    {
                        var str_field = txbody.getFieldText(_last_field_type, this.TempMainObject, (this.presentation && this.presentation.pres && AscFormat.isRealNumber(this.presentation.pres.attrFirstSlideNum)) ? this.presentation.pres.attrFirstSlideNum : 1);
                        if(str_field.length > 0)
                        {
                            txbody.content.Internal_Content_RemoveAll();
                            txbody.content.Internal_Content_Add(txbody.content.Content.length,  new Paragraph(txbody.content.DrawingDocument, txbody.content, true));
                            AscFormat.AddToContentFromString(txbody.content, str_field);

                            if(_paragraph.f_runPr || _paragraph.f_paraPr)
                            {
                                txbody.content.Set_ApplyToAll(true);
                                if(_paragraph.f_runPr)
                                {
                                    var _value_text_pr = new CTextPr();
                                    if(_paragraph.f_runPr.Unifill && !_paragraph.f_runPr.Unifill.fill)
                                    {
                                        _paragraph.f_runPr.Unifill = undefined;
                                    }
                                    _value_text_pr.Set_FromObject(_paragraph.f_runPr);
                                    txbody.content.AddToParagraph( new ParaTextPr(_value_text_pr), false );
                                    delete _paragraph.f_runPr;
                                }
                                if(_paragraph.f_paraPr)
                                {
                                    txbody.content.Content[0].Set_Pr(_paragraph.f_paraPr);
                                    delete _paragraph.f_paraPr;
                                }
                                txbody.content.Set_ApplyToAll(false);
                            }
                        }

                    }
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return txbody;
    }

    this.ReadTextBodyTxPr = function(shape)
    {
        var txbody;

        if(shape.txPr)
            txbody = shape.txPr;
        else
        {
            shape.txPr = new AscFormat.CTextBody();
            txbody = shape.txPr;
        }
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    shape.setBodyPr(this.ReadBodyPr());
                    break;
                }
                case 1:
                {
                    txbody.setLstStyle(this.ReadTextListStyle());
                    break;
                }
                case 2:
                {
                    s.Skip2(4);
                    var _c = s.GetULong();
                    /*if(History != null)
                     {
                     History.TurnOff();
                     }*/
                    if(!txbody.content)
                        txbody.content = new AscFormat.CDrawingDocContent(shape, this.presentation ? this.presentation.DrawingDocument : null, 0, 0, 0, 0, 0, 0, true);
                    if(_c>0)
                    {
                        txbody.content.Internal_Content_RemoveAll();
                    }

                    var _last_field_type = false;
                    for (var i = 0; i < _c; i++)
                    {
                        s.Skip2(1); // type
                        var _paragraph = this.ReadParagraph(txbody.content);
                        _paragraph.Set_Parent(txbody.content);
                        txbody.content.Internal_Content_Add(txbody.content.Content.length, _paragraph);
                        if(_paragraph.f_type != undefined || _paragraph.f_text != undefined || _paragraph.f_id != undefined)
                        {
                            _last_field_type = true;
                        }
                    }

                    if(_last_field_type)
                    {
                       // var str_field = txbody.getFieldText(_last_field_type);
                       // if(str_field.length > 0)
                       // {
                       //     txbody.content.Internal_Content_RemoveAll();
                       //     AddToContentFromString(txbody.content, str_field);
                       // }
                    }
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
        return txbody;
    }

    this.ReadTextBody2 = function(content)
    {
        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;
        var oBodyPr;
        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    s.SkipRecord();
                    break;
                }
                case 1:
                {
                    s.SkipRecord();
                    break;
                }
                case 2:
                {
                    s.Skip2(4);
                    var _c = s.GetULong();
                    for (var i = 0; i < _c; i++)
                    {
                        s.Skip2(1); // type
                        var _paragraph = this.ReadParagraph(content);
                        content.Internal_Content_Add(content.Content.length, _paragraph);
                    }
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }

        s.Seek2(_end_rec);
    }

    this.ReadParagraph = function(DocumentContent)
    {
        var par = new Paragraph(DocumentContent.DrawingDocument, DocumentContent, true);

        var EndPos = 0;

        var s = this.stream;

        var _rec_start = s.cur;
        var _end_rec = _rec_start + s.GetULong() + 4;

        while (s.cur < _end_rec)
        {
            var _at = s.GetUChar();
            switch (_at)
            {
                case 0:
                {
                    par.Set_Pr(this.ReadTextParagraphPr(par));
                    break;
                }
                case 1:
                {
                    var OldImgCount = 0;
                    if(this.IsUseFullUrl)
                    {
                        OldImgCount = this.RebuildImages.length;
                    }
                    var endRunPr =  this.ReadRunProperties();
                    var _value_text_pr = new CTextPr();
                    if(endRunPr.Unifill && !endRunPr.Unifill.fill)
                    {
                        endRunPr.Unifill = undefined;
                    }
                    _value_text_pr.Set_FromObject(endRunPr);
                    par.TextPr.Apply_TextPr(_value_text_pr);//endRunProperties
                    var oTextPrEnd = new CTextPr();
                    oTextPrEnd.Set_FromObject(endRunPr);
                    par.Content[0].Set_Pr(oTextPrEnd);
                    if(this.IsUseFullUrl)
                    {
                        if(this.RebuildImages.length > OldImgCount)
                        {
                            for(var _t = OldImgCount; _t < this.RebuildImages.length; ++_t)
                            {
                                var _text_pr = new CTextPr();
                                _text_pr.Set_FromObject(endRunPr);
                                this.RebuildImages[_t].TextPr = _text_pr;
                                this.RebuildImages[_t].ParaTextPr = par.TextPr;
                                this.RebuildImages[_t].Run = par.Content[0];

                            }
                        }
                    }
                    break;
                }
                case 2:
                {
                    s.Skip2(4);

                    var _c = s.GetULong();
                    for (var i = 0; i < _c; i++)
                    {
                        s.Skip2(5); // type (0) + len
                        var _type = s.GetUChar();

                        switch (_type)
                        {
                            case AscFormat.PARRUN_TYPE_RUN:
                            {
                                var _end = s.cur + s.GetULong() + 4;

                                s.Skip2(1); // start attr

                                var _text = "";
                                while (true)
                                {
                                    var _at = s.GetUChar();
                                    if (_at == g_nodeAttributeEnd)
                                        break;

                                    if (0 == _at)
                                        _text = s.GetString2();
                                }

                                var OldImgCount = 0;
                                if(this.IsUseFullUrl)
                                {
                                    OldImgCount = this.RebuildImages.length;
                                }

                                var _run = null;
                                while (s.cur < _end)
                                {
                                    var _rec = s.GetUChar();

                                    if (0 == _rec)
                                        _run = this.ReadRunProperties();
                                    else
                                        s.SkipRecord();
                                }

                                s.Seek2(_end);


                                var new_run = new ParaRun(par, false), hyperlink = null;
                                if (null != _run)
                                {

                                    var text_pr = new CTextPr();
                                    if(_run.Unifill && !_run.Unifill.fill)
                                    {
                                        _run.Unifill = undefined;
                                    }
                                    if (_run.hlink !== undefined)
                                    {
                                        hyperlink = new ParaHyperlink();
                                        hyperlink.SetValue(_run.hlink.id);
                                        if (_run.hlink.tooltip) {
                                          hyperlink.SetToolTip(_run.hlink.tooltip);
                                        }
                                        // if(!_run.Unifill)
                                        // {
                                        //     _run.Unifill = AscFormat.CreateUniFillSchemeColorWidthTint(11, 0);
                                        // }
                                        _run.Underline = true;
                                    }
                                    text_pr.Set_FromObject(_run);
                                    new_run.Set_Pr(text_pr);
                                    if(this.IsUseFullUrl)
                                    {
                                        if(this.RebuildImages.length > OldImgCount)
                                        {
                                            for(var _t = OldImgCount; _t < this.RebuildImages.length; ++_t)
                                            {
                                                var _text_pr = new CTextPr();
                                                _text_pr.Set_FromObject(text_pr);
                                                this.RebuildImages[_t].TextPr = _text_pr;
                                                this.RebuildImages[_t].Run = new_run;

                                            }
                                        }
                                    }
                                }

                                new_run.AddText(_text);

                                if (hyperlink !== null)
                                {
                                    hyperlink.Add_ToContent(0, new_run, false);
                                    par.Internal_Content_Add(EndPos++, hyperlink);
                                }
                                else
                                {
                                    par.Internal_Content_Add(EndPos++, new_run);
                                }

                                break;
                            }
                            case AscFormat.PARRUN_TYPE_FLD:
                            {
                                var _end = s.cur + s.GetULong() + 4;

                                s.Skip2(1); // start attr

                                while (true)
                                {
                                    var _at = s.GetUChar();
                                    if (_at == g_nodeAttributeEnd)
                                        break;

                                    if (0 == _at)
                                        var f_id = s.GetString2();
                                    else if (1 == _at)
                                        var f_type = s.GetString2();
                                    else
                                        var f_text = s.GetString2();
                                }

                                var _rPr = null, _pPr = null;
                                while (s.cur < _end)
                                {
                                    var _at2 = s.GetUChar();
                                    switch (_at2)
                                    {
                                        case 0:
                                        {
                                            _rPr = this.ReadRunProperties();
                                            break;
                                        }
                                        case 1:
                                        {
                                            _pPr = this.ReadTextParagraphPr();
                                            break;
                                        }
                                        default:
                                        {
                                            s.SkipRecord();
                                            break;
                                        }
                                    }
                                }

                                par.f_id = f_id;
                                par.f_type = f_type;
                                par.f_text = f_text;
                                par.f_runPr = _rPr;
                                par.f_paraPr = _pPr;

                                s.Seek2(_end);
                                break;
                            }
                            case AscFormat.PARRUN_TYPE_BR:
                            {
                                var _end = s.cur + s.GetULong() + 4;

                                var _run = null;
                                while (s.cur < _end)
                                {
                                    var _rec = s.GetUChar();

                                    if (0 == _rec)
                                        _run = this.ReadRunProperties();
                                    else
                                        s.SkipRecord();
                                }

                                s.Seek2(_end);

                                var new_run = new ParaRun(par, false), hyperlink = null;
                                if (null != _run)
                                {
                                    if (_run.hlink !== undefined)
                                    {
                                        hyperlink = new ParaHyperlink();
                                        hyperlink.SetValue(_run.hlink.id);
                                        if (_run.hlink.tooltip) {
                                          hyperlink.SetToolTip(_run.hlink.tooltip);
                                        }
                                    }
                                    var text_pr = new CTextPr();
                                    if(_run.Unifill && !_run.Unifill.fill)
                                    {
                                        _run.Unifill = undefined;
                                    }
                                    text_pr.Set_FromObject(_run);
                                    new_run.Set_Pr(text_pr);
                                }
                                new_run.Add_ToContent( 0, new ParaNewLine(break_Line));
                                if (hyperlink !== null)
                                {
                                    hyperlink.Add_ToContent(0, new_run, false);
                                    par.Internal_Content_Add(EndPos++, hyperlink);
                                }
                                else
                                {
                                    par.Internal_Content_Add(EndPos++, new_run);
                                }
                                break;
                            }
							case AscFormat.PARRUN_TYPE_MATHPARA:
							case AscFormat.PARRUN_TYPE_MATH:
							{
								var _end = s.cur + s.GetULong() + 4;

								var _stream = new AscCommon.FT_Stream2();
								_stream.data = s.data;
								_stream.pos = s.pos;
								_stream.cur = s.cur;
								_stream.size = s.size;
								var parContentOld = par.Content.length;

								var oParStruct = new OpenParStruct(par, par);
                                oParStruct.cur.pos = par.Content.length - 1;
								if (!this.DocReadResult) {
									this.DocReadResult = new AscCommonWord.DocReadResult(null);
								}
								var boMathr = new Binary_oMathReader(_stream, this.DocReadResult, null);
								var nDocLength = _stream.GetULongLE();
								if (AscFormat.PARRUN_TYPE_MATHPARA == _type) {
									var props = {};
									boMathr.bcr.Read1(nDocLength, function(t, l){
										return boMathr.ReadMathOMathPara(t,l,oParStruct, props);
									});
								} else {
									var oMath = new ParaMath();
									oParStruct.addToContent(oMath);
									boMathr.bcr.Read1(nDocLength, function(t, l){
										return boMathr.ReadMathArg(t,l,oMath.Root,oParStruct);
									});
									oMath.Root.Correct_Content(true);
								}
								s.Seek2(_end);

								EndPos += par.Content.length - parContentOld;
								break;
							}
                            default:
                            {
                                s.SkipRecord();
                                break;
                            }
                        }
                    }
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }
        s.Seek2(_end_rec);
        return par;
    }

    // ------------------------------------------
}

function CApp()
{
    this.Template = null;
    this.TotalTime = null;
    this.Words = null;
    this.Application = null;
    this.PresentationFormat = null;
    this.Paragraphs = null;
    this.Slides = null;
    this.Notes = null;
    this.HiddenSlides = null;
    this.MMClips = null;
    this.ScaleCrop = null;
    this.HeadingPairs = [];
    this.TitlesOfParts = [];
    this.Company = null;
    this.LinksUpToDate = null;
    this.SharedDoc = null;
    this.HyperlinksChanged = null;
    this.AppVersion = null;

    this.fromStream = function(s)
    {
        var _type = s.GetUChar();
        var _len = s.GetULong();

        // attributes
        var _sa = s.GetUChar();

        while (true)
        {
            var _at = s.GetUChar();

            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0: { this.Template = s.GetString2(); break; }
                case 1: { this.Application = s.GetString2(); break; }
                case 2: { this.PresentationFormat = s.GetString2(); break; }
                case 3: { this.Company = s.GetString2(); break; }
                case 4: { this.AppVersion = s.GetString2(); break; }

                case 5: { this.TotalTime = s.GetLong(); break; }
                case 6: { this.Words = s.GetLong(); break; }
                case 7: { this.Paragraphs = s.GetLong(); break; }
                case 8: { this.Slides = s.GetLong(); break; }
                case 9: { this.Notes = s.GetLong(); break; }
                case 10: { this.HiddenSlides = s.GetLong(); break; }
                case 11: { this.MMClips = s.GetLong(); break; }

                case 12: { this.ScaleCrop = s.GetBool(); break; }
                case 13: { this.LinksUpToDate = s.GetBool(); break; }
                case 14: { this.SharedDoc = s.GetBool(); break; }
                case 15: { this.HyperlinksChanged = s.GetBool(); break; }
                default:
                    return;
            }
        }
    }
}

function CCore()
{
    this.title = null;
    this.creator = null;
    this.lastModifiedBy = null;
    this.revision = null;
    this.created = null;
    this.modified = null;

    this.fromStream = function(s)
    {
        var _type = s.GetUChar();
        var _len = s.GetULong();

        // attributes
        var _sa = s.GetUChar();

        while (true)
        {
            var _at = s.GetUChar();

            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0: { this.title = s.GetString2(); break; }
                case 1: { this.creator = s.GetString2(); break; }
                case 2: { this.lastModifiedBy = s.GetString2(); break; }
                case 3: { this.revision = s.GetString2(); break; }
                case 4: { this.created = s.GetString2(); break; }
                case 5: { this.modified = s.GetString2(); break; }
                default:
                    return;
            }
        }
    }
}

function CPres()
{
    this.defaultTextStyle = null;
    this.SldSz = null;
    this.NotesSz = null;

    this.attrAutoCompressPictures = null;
    this.attrBookmarkIdSeed = null;
    this.attrCompatMode = null;
    this.attrConformance = null;
    this.attrEmbedTrueTypeFonts = null;
    this.attrFirstSlideNum = null;
    this.attrRemovePersonalInfoOnSave = null;
    this.attrRtl = null;
    this.attrSaveSubsetFonts = null;
    this.attrServerZoom = null;
    this.attrShowSpecialPlsOnTitleSld = null;
    this.attrStrictFirstAndLastChars = null;

    this.fromStream = function(s, reader)
    {
        var _type = s.GetUChar();
        var _len = s.GetULong();
        var _start_pos = s.cur;
        var _end_pos = _len + _start_pos;

        // attributes
        var _sa = s.GetUChar();

        while (true)
        {
            var _at = s.GetUChar();

            if (_at == g_nodeAttributeEnd)
                break;

            switch (_at)
            {
                case 0: { this.attrAutoCompressPictures = s.GetBool(); break; }
                case 1: { this.attrBookmarkIdSeed = s.GetLong(); break; }
                case 2: { this.attrCompatMode = s.GetBool(); break; }
                case 3: { this.attrConformance = s.GetUChar(); break; }
                case 4: { this.attrEmbedTrueTypeFonts = s.GetBool(); break; }
                case 5: { this.attrFirstSlideNum = s.GetLong(); break; }
                case 6: { this.attrRemovePersonalInfoOnSave = s.GetBool(); break; }
                case 7: { this.attrRtl = s.GetBool(); break; }
                case 8: { this.attrSaveSubsetFonts = s.GetBool(); break; }
                case 9: { this.attrServerZoom = s.GetString2(); break; }
                case 10: { this.attrShowSpecialPlsOnTitleSld = s.GetBool(); break; }
                case 11: { this.attrStrictFirstAndLastChars = s.GetBool(); break; }
                default:
                    return;
            }
        }

        while (true)
        {
            if (s.cur >= _end_pos)
                break;

            _type = s.GetUChar();
            switch (_type)
            {
                case 0:
                {
                    this.defaultTextStyle = reader.ReadTextListStyle();
                    break;
                }
                case 1: { s.SkipRecord(); break; }
                case 2: { s.SkipRecord(); break; }
                case 3: { s.SkipRecord(); break; }
                case 4: { s.SkipRecord(); break; }
                case 5:
                {
                    this.SldSz = {};
                    s.Skip2(5); // len + start attributes

                    while (true)
                    {
                        var _at = s.GetUChar();

                        if (_at == g_nodeAttributeEnd)
                            break;

                        switch (_at)
                        {
                            case 0: { this.SldSz.cx = s.GetLong(); break; }
                            case 1: { this.SldSz.cy = s.GetLong(); break; }
                            case 2: { this.SldSz.type = s.GetUChar(); break; }
                            default:
                                return;
                        }
                    }

                    break;
                }
                case 6:
                {
                    var _end_rec2 = s.cur + s.GetULong() + 4;
                    while (s.cur < _end_rec2)
                    {
                        var _rec = s.GetUChar();

                        switch (_rec)
                        {
                            case 0:
                            {
                                s.Skip2(4); // len
                                var lCount = s.GetULong();

                                for (var i = 0; i < lCount; i++)
                                {
                                    s.Skip2(1);

                                    var _author = new CCommentAuthor();

                                    var _end_rec3 = s.cur + s.GetLong() + 4;
                                    s.Skip2(1); // start attributes

                                    while (true)
                                    {
                                        var _at2 = s.GetUChar();
                                        if (_at2 == g_nodeAttributeEnd)
                                            break;

                                        switch (_at2)
                                        {
                                            case 0:
                                                _author.Id = s.GetLong();
                                                break;
                                            case 1:
                                                _author.LastId = s.GetLong();
                                                break;
                                            case 2:
                                                var _clr_idx = s.GetLong();
                                                break;
                                            case 3:
                                                _author.Name = s.GetString2();
                                                break;
                                            case 4:
                                                _author.Initials = s.GetString2();
                                                break;
                                            default:
                                                break;
                                        }
                                    }

                                    s.Seek2(_end_rec3);

                                    reader.presentation.CommentAuthors[_author.Name] = _author;
                                }

                                break;
                            }
                            default:
                            {
                                s.SkipRecord();
                                break;
                            }
                        }
                    }

                    s.Seek2(_end_rec2);
                    break;
                }
				case 9:
				{
					var _length = s.GetULong();
					var _end_rec2 = s.cur + _length;

					reader.presentation.Api.macros.SetData(AscCommon.GetStringUtf8(s, _length));
					s.Seek2(_end_rec2);
					break;
				}
                case 10:
                {
                    reader.ReadComments(reader.presentation.writecomments);
                    break;
                }
                default:
                {
                    s.SkipRecord();
                    break;
                }
            }
        }
        if(reader.presentation.Load_Comments)
        {
            reader.presentation.Load_Comments(reader.presentation.CommentAuthors);
        }
        s.Seek2(_end_pos);
    }
}

    function CPPTXContentLoader()
    {
        this.Reader = new AscCommon.BinaryPPTYLoader();
        this.Writer = null;

        this.stream = null;
        this.TempMainObject = null;
        this.ParaDrawing = null;
        this.LogicDocument = null;
        this.BaseReader = null;

        this.ImageMapChecker = {};

        this.Start_UseFullUrl = function(insertDocumentUrlsData)
        {
            this.Reader.Start_UseFullUrl(insertDocumentUrlsData);
        }
        this.End_UseFullUrl = function()
        {
            return this.Reader.End_UseFullUrl();
        }

        this.ReadDrawing = function(reader, stream, logicDocument, paraDrawing)
        {
            if(reader){
                this.BaseReader = reader;
            }
            if (this.Reader == null)
                this.Reader = new AscCommon.BinaryPPTYLoader();

            if (null != paraDrawing)
            {
                this.ParaDrawing = paraDrawing;
                this.TempMainObject = null;
            }
            this.LogicDocument = logicDocument;

            this.Reader.ImageMapChecker = this.ImageMapChecker;

            if (null == this.stream)
            {
                this.stream = new AscCommon.FileStream();
                this.stream.obj    = stream.obj;
                this.stream.data   = stream.data;
                this.stream.size   = stream.size;
            }

            this.stream.pos    = stream.pos;
            this.stream.cur    = stream.cur;

            this.Reader.stream = this.stream;
            this.Reader.presentation = logicDocument;

            var GrObject = null;

            var s = this.stream;
            var _main_type = s.GetUChar(); // 0!!!

            var _rec_start = s.cur;
            var _end_rec = _rec_start + s.GetULong() + 4;
            if (s.cur < _end_rec){
                s.Skip2(5); // 1 + 4 byte - len

                var _type = s.GetUChar();
                switch (_type)
                {
                    case 1:
                    {
                        GrObject = this.ReadShape();
                        break;
                    }
                    case 6:
                    case 2:
                    case 7:
                    case 8:
                    {
                        GrObject = this.ReadPic(_type);
                        break;
                    }
                    case 3:
                    {
                        GrObject = this.ReadCxn();
                        break;
                    }
                    case 4:
                    {
                        GrObject = this.ReadGroupShape();
                        break;
                    }
                    case 5:
                    {
                        s.SkipRecord();
                        break;
                    }
                    default:
                    {
                        s.SkipRecord();
                        break;
                    }
                }
            }

            s.Seek2(_end_rec);
            stream.pos = s.pos;
            stream.cur = s.cur;

            return GrObject;
        }

        this.ReadGraphicObject = function(stream, presentation)
        {
            if (this.Reader == null)
                this.Reader = new AscCommon.BinaryPPTYLoader();

            if(presentation)
            {
                this.Reader.presentation = presentation;
            }
            var oLogicDocument = this.LogicDocument;
            this.LogicDocument = null;

            this.Reader.ImageMapChecker = this.ImageMapChecker;

            if (null == this.stream)
            {
                this.stream = new AscCommon.FileStream();
                this.stream.obj    = stream.obj;
                this.stream.data   = stream.data;
                this.stream.size   = stream.size;
            }

            this.stream.pos    = stream.pos;
            this.stream.cur    = stream.cur;

            this.Reader.stream = this.stream;

            var s = this.stream;
            var _main_type = s.GetUChar(); // 0!!!

            var _rec_start = s.cur;
            var _end_rec = _rec_start + s.GetULong() + 4;

            s.Skip2(5); // 1 + 4 byte - len

            var GrObject = this.Reader.ReadGraphicObject();

            s.Seek2(_end_rec);
            stream.pos = s.pos;
            stream.cur = s.cur;
            this.LogicDocument = oLogicDocument;
            return GrObject;
        }

        this.ReadTextBody = function(reader, stream, shape, presentation)
        {
            if(reader){
                this.BaseReader = reader;
            }
            if (this.Reader == null)
                this.Reader = new AscCommon.BinaryPPTYLoader();
            if(presentation)
                this.Reader.presentation = presentation;

            var oLogicDocument = this.LogicDocument;
            this.LogicDocument = null;

            this.Reader.ImageMapChecker = this.ImageMapChecker;

            if (null == this.stream)
            {
                this.stream = new AscCommon.FileStream();
                this.stream.obj    = stream.obj;
                this.stream.data   = stream.data;
                this.stream.size   = stream.size;
            }

            this.stream.pos    = stream.pos;
            this.stream.cur    = stream.cur;

            this.Reader.stream = this.stream;

            var s = this.stream;
            var _main_type = s.GetUChar(); // 0!!!

            var txBody = this.Reader.ReadTextBody(shape);

            stream.pos = s.pos;
            stream.cur = s.cur;
            this.LogicDocument = oLogicDocument;
            return txBody;
        }

        this.ReadTextBodyTxPr = function(reader, stream, shape)
        {
            if(reader){
                this.BaseReader = reader;
            }
            if (this.Reader == null)
                this.Reader = new AscCommon.BinaryPPTYLoader();

            var oLogicDocument = this.LogicDocument;
            this.LogicDocument = null;

            this.Reader.ImageMapChecker = this.ImageMapChecker;

            if (null == this.stream)
            {
                this.stream = new AscCommon.FileStream();
                this.stream.obj    = stream.obj;
                this.stream.data   = stream.data;
                this.stream.size   = stream.size;
            }

            this.stream.pos    = stream.pos;
            this.stream.cur    = stream.cur;

            this.Reader.stream = this.stream;

            var s = this.stream;
            var _main_type = s.GetUChar(); // 0!!!

            var txBody = this.Reader.ReadTextBodyTxPr(shape);

            stream.pos = s.pos;
            stream.cur = s.cur;
            this.LogicDocument = oLogicDocument;
            return txBody;
        }

        this.ReadShapeProperty = function(stream, type)
        {
            if (this.Reader == null)
                this.Reader = new AscCommon.BinaryPPTYLoader();

            var oLogicDocument = this.LogicDocument;
            this.LogicDocument = null;

            this.Reader.ImageMapChecker = this.ImageMapChecker;

            if (null == this.stream)
            {
                this.stream = new AscCommon.FileStream();
                this.stream.obj    = stream.obj;
                this.stream.data   = stream.data;
                this.stream.size   = stream.size;
            }

            this.stream.pos    = stream.pos;
            this.stream.cur    = stream.cur;

            this.Reader.stream = this.stream;

            var s = this.stream;
            var _main_type = s.GetUChar(); // 0!!!

            var oNewSpPr;
            if(0 == type){
                oNewSpPr = this.Reader.ReadLn()
            }
            else if(1 == type){
                oNewSpPr = this.Reader.ReadUniFill();
            }
            else{
                oNewSpPr = new AscFormat.CSpPr();
                this.Reader.ReadSpPr(oNewSpPr);
            }

            stream.pos = s.pos;
            stream.cur = s.cur;

            this.LogicDocument = oLogicDocument;
            return oNewSpPr;
        };
		
		this.ReadRunProperties = function(stream, type)
		{
			if (this.Reader == null)
				this.Reader = new AscCommon.BinaryPPTYLoader();

			var oLogicDocument = this.LogicDocument;
			this.LogicDocument = null;

			this.Reader.ImageMapChecker = this.ImageMapChecker;

			if (null == this.stream)
			{
				this.stream = new AscCommon.FileStream();
				this.stream.obj	= stream.obj;
				this.stream.data   = stream.data;
				this.stream.size   = stream.size;
			}

			this.stream.pos	= stream.pos;
			this.stream.cur	= stream.cur;

			this.Reader.stream = this.stream;

			var s = this.stream;
			var _main_type = s.GetUChar(); // 0!!!

			var oNewrPr = this.Reader.ReadRunProperties();

			stream.pos = s.pos;
			stream.cur = s.cur;

			this.LogicDocument = oLogicDocument;
			return oNewrPr;
		};

        this.ReadShape = function()
        {
            var s = this.stream;

            var shape = new AscFormat.CShape();
            shape.setWordShape(true);
            shape.setBDeleted(false);
            shape.setParent(this.TempMainObject == null ? this.ParaDrawing : null);
            var _rec_start = s.cur;
            var _end_rec = _rec_start + s.GetULong() + 4;

            s.Skip2(1); // start attributes

            while (true)
            {
                var _at = s.GetUChar();
                if (_at == AscCommon.g_nodeAttributeEnd)
                    break;

                switch (_at)
                {
                    case 0:
                    {
                        shape.attrUseBgFill = s.GetBool();
                        break;
                    }
                    default:
                        break;
                }
            }

            var oXFRM = null;
            while (s.cur < _end_rec)
            {
                var _at = s.GetUChar();
                switch (_at)
                {
                    case 0:
                    {
                        var pr = this.Reader.ReadNvUniProp(shape);
                        shape.setNvSpPr(pr);
                        if(AscFormat.isRealNumber(pr.locks))
                        {
                            shape.setLocks(pr.locks);
                        }
                        break;
                    }
                    case 1:
                    {
                        var spPr = new AscFormat.CSpPr();
                        this.ReadSpPr(spPr);
                        shape.setSpPr(spPr);
                        shape.spPr.setParent(shape);
                        break;
                    }
                    case 2:
                    {
                        shape.setStyle(this.Reader.ReadShapeStyle());
                        break;
                    }
                    case 3:
                    {
                        s.SkipRecord();
                        break;
                    }
                    case 4:
                    {
                        var oThis = this.BaseReader;

                        shape.setTextBoxContent(new CDocumentContent(shape, this.LogicDocument.DrawingDocument, 0, 0, 0, 0, false, false));

                        var _old_cont = shape.textBoxContent.Content[0];

                        shape.textBoxContent.Internal_Content_RemoveAll();

                        s.Skip2(4); // rec len

                        oThis.stream.pos = s.pos;
                        oThis.stream.cur = s.cur;

                        var oBinary_DocumentTableReader = new Binary_DocumentTableReader(shape.textBoxContent, oThis.oReadResult, oThis.openParams, oThis.stream, false, oThis.oComments);
                        var nDocLength = oThis.stream.GetULongLE();
                        var content_arr = [];
                        oThis.bcr.Read1(nDocLength, function(t,l){
                            return oBinary_DocumentTableReader.ReadDocumentContent(t,l, content_arr);
                        });
                        for(var i = 0, length = content_arr.length; i < length; ++i){
                            if(i == length - 1)
                                shape.textBoxContent.Internal_Content_Add(i, content_arr[i], true);
                            else
                                shape.textBoxContent.Internal_Content_Add(i, content_arr[i], false);
                        }

                        s.pos = oThis.stream.pos;
                        s.cur = oThis.stream.cur;

                        if (shape.textBoxContent.Content.length == 0)
                            shape.textBoxContent.Internal_Content_Add(0, _old_cont);

                        break;
                    }
                    case 5:
                    {
                        var bodyPr = new AscFormat.CBodyPr();
                        this.Reader.CorrectBodyPr(bodyPr);
                        shape.setBodyPr(bodyPr);
                        break;
                    }
                    case 6:
                    {
                        oXFRM = this.Reader.ReadXfrm();
                        break;
                    }
                    case 7:
                    {
                        shape.setSignature(this.Reader.ReadSignatureLine());
                        break;
                    }
                    default:
                    {
                        s.SkipRecord();
                        break;
                    }
                }
            }

            if(oXFRM)
            {
                var oRet = new AscFormat.CGroupShape();
                shape.setParent(null);
                oRet.setParent(this.TempMainObject == null ? this.ParaDrawing : null);
                oRet.setBDeleted(false);
                var oSpPr = new AscFormat.CSpPr();
                var oXfrm = new AscFormat.CXfrm();
                oXfrm.setOffX(shape.spPr.xfrm.offX);
                oXfrm.setOffY(shape.spPr.xfrm.offY);
                oXfrm.setExtX(shape.spPr.xfrm.extX);
                oXfrm.setExtY(shape.spPr.xfrm.extY);
                oXfrm.setChExtX(shape.spPr.xfrm.extX);
                oXfrm.setChExtY(shape.spPr.xfrm.extY);
                oXfrm.setChOffX(0);
                oXfrm.setChOffY(0);
                oSpPr.setXfrm(oXfrm);
                oXfrm.setParent(oSpPr);
                shape.spPr.xfrm.setOffX(0);
                shape.spPr.xfrm.setOffY(0);
                oRet.setSpPr(oSpPr);
                oSpPr.setParent(oRet);
                oRet.addToSpTree(0, shape);
                var oShape2 = new AscFormat.CShape();
                var oSpPr2 = new AscFormat.CSpPr();
                oShape2.setSpPr(oSpPr2);
                oSpPr2.setParent(oShape2);
                var oXfrm2 = oXFRM;
                oXfrm2.setParent(oSpPr2);
                oSpPr2.setXfrm(oXfrm2);
                oXfrm2.setOffX(oXfrm2.offX - oXfrm.offX);
                oXfrm2.setOffY(oXfrm2.offY - oXfrm.offY);
                oSpPr2.setFill(AscFormat.CreateNoFillUniFill());
                oSpPr2.setLn(AscFormat.CreateNoFillLine());
                oShape2.setTxBody(shape.txBody);
                shape.setTxBody(null);
                shape.setGroup(oRet);
                oShape2.setBDeleted(false);
                oShape2.setWordShape(true);
                if(shape.spPr.xfrm && AscFormat.isRealNumber(shape.spPr.xfrm.rot))
                {
                    oXfrm2.setRot((AscFormat.isRealNumber(oXfrm2.rot) ? oXfrm2.rot : 0) + shape.spPr.xfrm.rot);
                }
                if(oShape2.txBody)
                {
                    oShape2.txBody.setParent(oShape2);
                }
                if(shape.textBoxContent)
                {
                    oShape2.setTextBoxContent(shape.textBoxContent.Copy(oShape2, shape.textBoxContent.DrawingDocument));
                    shape.setTextBoxContent(null);
                }
                if(shape.bodyPr)
                {
                    oShape2.setBodyPr(shape.bodyPr);
                    shape.setBodyPr(null);
                }
                oRet.addToSpTree(1, oShape2);
                oShape2.setGroup(oRet);
                s.Seek2(_end_rec);
                return oRet;
            }
            s.Seek2(_end_rec);
            return shape;

        }
        this.ReadCxn = function()
        {
            var s = this.stream;

            var shape = new AscFormat.CConnectionShape( );
            shape.setWordShape(true);
            shape.setParent(this.TempMainObject == null ? this.ParaDrawing : null);
            var _rec_start = s.cur;
            var _end_rec = _rec_start + s.GetULong() + 4;

            while (s.cur < _end_rec)
            {
                var _at = s.GetUChar();
                switch (_at)
                {
                    case 0:
                    {
                        s.SkipRecord();
                        break;
                    }
                    case 1:
                    {
                        var spPr = new AscFormat.CSpPr();
                        this.ReadSpPr(spPr);
                        shape.setSpPr(spPr);
                        break;
                    }
                    case 2:
                    {
                        shape.setStyle(this.Reader.ReadShapeStyle());
                        break;
                    }
                    default:
                    {
                        s.SkipRecord();
                        break;
                    }
                }
            }

            s.Seek2(_end_rec);
            return shape;
        }
        this.ReadPic = function(type)
        {
            var s = this.stream;

            var isOle = (type === 6);
            var pic = isOle ? new AscFormat.COleObject() : new AscFormat.CImageShape();
            pic.setBDeleted(false);
            pic.setParent(this.TempMainObject == null ? this.ParaDrawing : null);

            var _rec_start = s.cur;
            var _end_rec = _rec_start + s.GetULong() + 4;

            var sMaskFileName = "";
            while (s.cur < _end_rec)
            {
                var _at = s.GetUChar();
                switch (_at)
                {
                    case 0:
                    {
                        var pr = this.Reader.ReadNvUniProp(pic);
                        pic.setNvSpPr(pr);
                        if(AscFormat.isRealNumber(pr.locks))
                        {
                            pic.setLocks(pr.locks);
                        }
                        break;
                    }
                    case 1:
                    {
                        var unifill = this.Reader.ReadUniFill(null, pic, null);
                        pic.setBlipFill(unifill.fill);//this.Reader.ReadUniFill();

                        //pic.spPr.Fill = new AscFormat.CUniFill();
                        //pic.spPr.Fill.fill = pic.blipFill;
                        //pic.brush = pic.spPr.Fill;

                        break;
                    }
                    case 2:
                    {
                        var spPr = new AscFormat.CSpPr();
                        this.ReadSpPr(spPr);
                        pic.setSpPr(spPr);
                        pic.spPr.setParent(pic);
                        break;
                    }
                    case 3:
                    {
                        pic.setStyle(this.Reader.ReadShapeStyle());
                        break;
                    }
                    case 4:
                    {
                        if(isOle) {
                            this.ReadOleInfo(pic);
                            if(pic.m_sObjectFile === "maskFile.docx"
                                ||  pic.m_sObjectFile === "maskFile.xlsx"){
                                var oParent = pic.parent;
                                pic = AscFormat.CImageShape.prototype.copy.call(pic);
                                if(oParent){
                                    pic.setParent(oParent);
                                }
                            }
                        } else {
                            s.SkipRecord();
                        }
                        break;
                    }
                    case 5:
                    {
                        if(type === 7 || type === 8){//video or audio
                            s.GetLong();
                            s.GetUChar();//start attributes
                            while(true){
                                var _at2 = s.GetUChar();
                                if (_at2 == g_nodeAttributeEnd)
                                    break;
                                switch (_at2) {
                                    case 0:
                                    {
                                        sMaskFileName = s.GetString2();
                                        break;
                                    }
                                }
                            }
                        }
                        else{
                            s.SkipRecord();
                        }
                        break;
                    }
                    default:
                    {
                        s.SkipRecord();
                        break;
                    }
                }
            }

            if(type === 7 || type === 8){//video or audio
                if(typeof sMaskFileName === "string" && sMaskFileName.length > 0 &&
                    pic.nvPicPr && pic.nvPicPr.nvPr && pic.nvPicPr.nvPr.unimedia){
                    var oUniMedia = new AscFormat.UniMedia();
                    oUniMedia.type = type;
                    oUniMedia.media = sMaskFileName;
                    pic.nvPicPr.nvPr.setUniMedia(oUniMedia);
                }
            }

            s.Seek2(_end_rec);
            return pic;
        }
        this.ReadOleInfo = function(ole)
        {
            var s = this.stream;

            var _rec_start = s.cur;
            var _end_rec = _rec_start + s.GetLong() + 4;

            s.Skip2(1); // start attributes
            var dxaOrig = 0;
            var dyaOrig = 0;
            while (true)
            {
                var _at = s.GetUChar();
                if (_at == g_nodeAttributeEnd)
                    break;

                switch (_at)
                {
                    case 0:
                    {
                        ole.setApplicationId(s.GetString2());
                        break;
                    }
                    case 1:
                    {
                        ole.setData(s.GetString2());
                        break;
                    }
                    case 2:
                    {
                        dxaOrig = s.GetULong();
                        break;
                    }
                    case 3:
                    {
                        dyaOrig = s.GetULong();
                        break;
                    }
                    case 4:
                    {
                        s.GetUChar();
                        break;
                    }
                    case 5:
                    {
                        s.GetUChar();
                        break;
                    }
                    case 6:
                    {
                        s.GetUChar();
                        break;
                    }
                    case 7:
                    {
                        ole.setObjectFile(s.GetString2());
                        break;
                    }
                    default:
                        break;
                }
            }




            var oleType = null;
            while (s.cur < _end_rec)
            {
                var _at = s.GetUChar();
                switch (_at)
                {
                    case 1:
                    {
                        s.GetLong();//length
                        oleType = s.GetUChar();
                        break;
                    }
                    case 2:
                    {

                        switch(oleType)
                        {
                            case 1:
                            {
                                ole.setObjectFile("maskFile.docx");
                                s.SkipRecord();
                                break;
                            }
                            case 2:
                            {
                                ole.setObjectFile("maskFile.xlsx");
                                s.SkipRecord();
                                break;
                            }
                            case 4:
                            {
                                s.GetLong();//length

                                var type2 = s.GetUChar();
                                if (c_oSer_OMathContentType.OMath === type2 && ole.parent && ole.parent.Parent)
                                {
                                    var length2 = s.GetLong();
                                    var _stream = new AscCommon.FT_Stream2();
                                    _stream.data = s.data;
                                    _stream.pos = s.pos;
                                    _stream.cur = s.cur;
                                    _stream.size = s.size;
                                    var boMathr = new Binary_oMathReader(_stream, this.DocReadResult, null);
                                    var oMathPara = new ParaMath();
                                    ole.parent.ParaMath = oMathPara;
                                    var par = ole.parent.Parent;
                                    var oParStruct = new OpenParStruct(par, par);
                                    oParStruct.cur.pos = par.Content.length - 1;
                                    if (!this.DocReadResult) {
                                        this.DocReadResult = new AscCommonWord.DocReadResult(null);
                                    }
                                    boMathr.bcr.Read1(length2, function(t, l){
                                        return boMathr.ReadMathArg(t,l,oMathPara.Root,oParStruct);
                                    });
                                    oMathPara.Root.Correct_Content(true);
                                }
                                else
                                {
                                    s.SkipRecord();
                                }
                                break;
                            }
                            default:
                            {
                                s.SkipRecord();
                                break;
                            }
                        }
                        break;
                    }
                    default:
                    {
                        s.SkipRecord();
                        break;
                    }
                }
            }




			if (dxaOrig > 0 && dyaOrig > 0) {
				var ratio = 4 / 3 / 20;//twips to px
				ole.setPixSizes(ratio * dxaOrig, ratio * dyaOrig);
			}
            s.Seek2(_end_rec);
        }
        this.ReadGroupShape = function()
        {
            var s = this.stream;

            var shape = new AscFormat.CGroupShape();

            shape.setBDeleted(false);
            shape.setParent(this.TempMainObject == null ? this.ParaDrawing : null);
            this.TempGroupObject = shape;

            var oldParaDrawing = this.ParaDrawing;
            this.ParaDrawing = null;

            var _rec_start = s.cur;
            var _end_rec = _rec_start + s.GetULong() + 4;

            while (s.cur < _end_rec)
            {
                var _at = s.GetUChar();
                switch (_at)
                {
                    case 0:
                    {
                        s.SkipRecord();
                        break;
                    }
                    case 1:
                    {
                        var spPr = new AscFormat.CSpPr();
                        this.Reader.ReadGrSpPr(spPr);
                        shape.setSpPr(spPr);
                        shape.spPr.setParent(shape);
                        break;
                    }
                    case 2:
                    {
                        s.Skip2(4); // len
                        var _c = s.GetULong();
                        for (var i = 0; i < _c; i++)
                        {
                            s.Skip2(1);
                            var __len = s.GetULong();
                            if (__len == 0)
                                continue;

                            var _type = s.GetUChar();

                            var sp;
                            switch (_type)
                            {
                                case 1:
                                {
                                    sp = this.ReadShape();
                                    if(sp.spPr && sp.spPr.xfrm){
                                        sp.setGroup(shape);
                                        shape.addToSpTree(shape.spTree.length, sp);
                                    }
                                    break;
                                }
                                case 6:
                                case 2:
                                case 7:
                                case 8:
                                {
                                    sp = this.ReadPic(_type);
                                    if(sp.spPr && sp.spPr.xfrm){
                                        sp.setGroup(shape);
                                        shape.addToSpTree(shape.spTree.length, sp);
                                    }
                                    break;
                                }
                                case 3:
                                {
                                    sp = this.ReadCxn();
                                    if(sp.spPr && sp.spPr.xfrm) {
                                        sp.setGroup(shape);
                                        shape.addToSpTree(shape.spTree.length, sp);
                                    }
                                    break;
                                }
                                case 4:
                                {
                                    sp = this.ReadGroupShape();
                                    if(sp && sp.spPr && sp.spPr.xfrm && sp.spTree.length > 0) {
                                        sp.setGroup(shape);
                                        shape.addToSpTree(shape.spTree.length, sp);
                                    }
                                    break;
                                }
                                case 5:
                                {
                                    var _chart = this.Reader.ReadChartDataInGroup(shape);
                                    if (null != _chart)
                                    {
                                        _chart.setGroup(shape);
                                        shape.addToSpTree(shape.spTree.length, _chart);
                                    }
                                    break;
                                }
                                default:
                                {
                                    s.SkipRecord();
                                    break;
                                }
                            }
                        }
                        break;
                    }
                    default:
                    {
                        s.SkipRecord();
                        break;
                    }
                }
            }

            if(oldParaDrawing && shape.spPr && !shape.spPr.xfrm){
                shape.bEmptyTransform = true;
            }
            if(!oldParaDrawing){
                this.Reader.CheckGroupXfrm(shape);
            }
            this.ParaDrawing = oldParaDrawing;
            s.Seek2(_end_rec);
            this.TempGroupObject = null;
            if(shape.spTree.length === 0){
                return null;
            }
            return shape;
        }

        this.ReadSpPr = function(spPr)
        {
            var s = this.stream;

            var _rec_start = s.cur;
            var _end_rec = _rec_start + s.GetULong() + 4;

            s.Skip2(1); // start attributes

            while (true)
            {
                var _at = s.GetUChar();
                if (_at == AscCommon.g_nodeAttributeEnd)
                    break;

                if (0 == _at)
                    spPr.bwMode = s.GetUChar();
                else
                    break;
            }

            while (s.cur < _end_rec)
            {
                var _at = s.GetUChar();
                switch (_at)
                {
                    case 0:
                    {
                        spPr.setXfrm(this.Reader.ReadXfrm());
                        spPr.xfrm.setParent(spPr);
                        //this.CorrectXfrm(spPr.xfrm);
                        break;
                    }
                    case 1:
                    {
                        var oGeometry = this.Reader.ReadGeometry(spPr.xfrm);
                        if(oGeometry && oGeometry.pathLst.length > 0)
                            spPr.setGeometry(oGeometry);
                        break;
                    }
                    case 2:
                    {
                        spPr.setFill(this.Reader.ReadUniFill(spPr, null, null));
                        break;
                    }
                    case 3:
                    {
                        spPr.setLn(this.Reader.ReadLn());
                        break;
                    }
                    case 4:
                    {
                        var _len = s.GetULong();
                        s.Skip2(_len);
                        break;
                    }
                    case 5:
                    {
                        var _len = s.GetULong();
                        s.Skip2(_len);
                        break;
                    }
                    case 6:
                    {
                        var _len = s.GetULong();
                        s.Skip2(_len);
                        break;
                    }
                    default:
                    {
                        s.SkipRecord();
                        break;
                    }
                }
            }

            s.Seek2(_end_rec);
        }

        this.CorrectXfrm = function(_xfrm)
        {
            if (!_xfrm)
                return;

            if (null == _xfrm.rot)
                return;

            var nInvertRotate = 0;
            if (true === _xfrm.flipH)
                nInvertRotate += 1;
            if (true === _xfrm.flipV)
                nInvertRotate += 1;

            var _rot = _xfrm.rot;
            var _del = 2 * Math.PI;

            if (nInvertRotate)
                _rot = -_rot;

            if (_rot >= _del)
            {
                var _intD = (_rot / _del) >> 0;
                _rot = _rot - _intD * _del;
            }
            else if (_rot < 0)
            {
                var _intD = (-_rot / _del) >> 0;
                _intD = 1 + _intD;
                _rot = _rot + _intD * _del;
            }

            _xfrm.rot = _rot;
        }

        this.ReadTheme = function(reader, stream)
        {
            if(reader)
            {
                this.BaseReader = reader;
            }
            if (this.Reader == null)
                this.Reader = new AscCommon.BinaryPPTYLoader();

            if (null == this.stream)
            {
                this.stream = new AscCommon.FileStream();
                this.stream.obj    = stream.obj;
                this.stream.data   = stream.data;
                this.stream.size   = stream.size;
            }

            this.stream.pos    = stream.pos;
            this.stream.cur    = stream.cur;

            this.Reader.stream = this.stream;
            this.Reader.ImageMapChecker = this.ImageMapChecker;
            return this.Reader.ReadTheme();
        }

        this.CheckImagesNeeds = function(logicDoc)
        {
            var index = 0;
            logicDoc.ImageMap = {};
            for (var i in this.ImageMapChecker)
            {
                logicDoc.ImageMap[index++] = i;
            }
        }

        this.Clear = function(bClearStreamOnly)
        {
            //вызывается пока только перед вставкой
            this.Reader.stream = null;
            this.stream = null;
            this.BaseReader = null;
            if(!bClearStreamOnly)
                this.ImageMapChecker = {};
        }
    }

    //----------------------------------------------------------export----------------------------------------------------
    window['AscCommon'] = window['AscCommon'] || {};
    window['AscCommon'].c_dScalePPTXSizes = c_dScalePPTXSizes;
    window['AscCommon'].CBuilderImages = CBuilderImages;
    window['AscCommon'].BinaryPPTYLoader = BinaryPPTYLoader;
    window['AscCommon'].IsHiddenObj = IsHiddenObj;
    window['AscCommon'].pptx_content_loader = new CPPTXContentLoader();
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

// Import
var c_dScalePPTXSizes = AscCommon.c_dScalePPTXSizes;
var g_nodeAttributeStart = AscCommon.g_nodeAttributeStart;
var g_nodeAttributeEnd = AscCommon.g_nodeAttributeEnd;

var c_oAscColor = Asc.c_oAscColor;
var c_oAscFill = Asc.c_oAscFill;

var c_oMainTables = {
    Main			: 255,
    App				: 1,
    Core			: 2,
    Presentation	: 3,
    ViewProps		: 4,
    VmlDrawing		: 5,
    TableStyles		: 6,
    PresProps		: 7,
	JsaProject		: 8,

    Themes			: 20,
    ThemeOverride	: 21,
    SlideMasters	: 22,
    SlideLayouts	: 23,
    Slides			: 24,
    NotesMasters	: 25,
    NotesSlides		: 26,

    HandoutMasters	: 30,

    SlideRels		: 40,
    ThemeRels		: 41,

    ImageMap		: 42,
    FontMap			: 43,
	SlideNotesRels	: 45,
	NotesRels		: 46,
	NotesMastersRels: 47
};

function CSeekTableEntry()
{
    this.Type       = 0;
    this.SeekPos    = 0;
}

function GUID()
{
    var S4 = function ()
    {
        var ret = (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
        ret = ret.toUpperCase();
        return ret;
    };

    return (
        S4() + S4() + "-" +
            S4() + "-" +
            S4() + "-" +
            S4() + "-" +
            S4() + S4() + S4()
        );
}

function CBinaryFileWriter()
{
    // temp members
    this.tableStylesGuides = {};

    // memory functions ----------
    this.Init = function()
    {
        var _canvas = document.createElement('canvas');
        var _ctx = _canvas.getContext('2d');
        this.len = 1024*1024*5;
        this.ImData = _ctx.createImageData(this.len / 4, 1);
        this.data = this.ImData.data;
        this.pos = 0;
    };

    this.IsWordWriter = false;
    this.ImData = null;
    this.data = null;
    this.len = 0;
    this.pos = 0;
    this.Init();

    this.UseContinueWriter = false;

    this.IsUseFullUrl = false;
    this.PresentationThemesOrigin = "";

    this.max_shape_id = 3;
    this.arr_map_shapes_id = {};

	this.DocSaveParams = null;
    var oThis = this;

    this.ClearIdMap = function(){
        this.max_shape_id = 3;
        this.arr_map_shapes_id = {};
    };

    this.Start_UseFullUrl = function()
    {
        this.IsUseFullUrl = true;
    };

    this.Start_UseDocumentOrigin = function(origin)
    {
        this.PresentationThemesOrigin = origin;
    };

    this.End_UseFullUrl = function()
    {
        this.IsUseFullUrl = false;
    };

    this.Copy = function(oMemory, nPos, nLen)
    {
        for ( var Index = 0; Index < nLen; Index++ )
        {
            this.CheckSize(1);
            this.data[this.pos++] = oMemory.data[Index + nPos];
        }
    };

    this.CheckSize = function(count)
    {
        if (this.pos + count >= this.len)
        {
            var _canvas = document.createElement('canvas');
            var _ctx = _canvas.getContext('2d');

            var oldImData = this.ImData;
            var oldData = this.data;
            var oldPos = this.pos;

            this.len = Math.max(this.len * 2, this.pos + ((3 * count / 2) >> 0));
			
            this.ImData = _ctx.createImageData(this.len / 4, 1);
            this.data = this.ImData.data;
            var newData = this.data;

            for (var i=0;i<this.pos;i++)
                newData[i]=oldData[i];
        }
    };
    this.GetBase64Memory = function()
    {
        return AscCommon.Base64Encode(this.data,this.pos, 0);
    };
    this.GetBase64Memory2 = function(nPos, nLen)
    {
        return AscCommon.Base64Encode(this.data, nLen, nPos);
    };
    this.GetCurPosition = function()
    {
        return this.pos;
    };
    this.Seek = function(nPos)
    {
        this.pos = nPos;
    };
    this.Skip = function(nDif)
    {
        this.pos += nDif;
    };
    this.WriteBool = function(val)
    {
        this.CheckSize(1);
        if(false == val)
            this.data[this.pos++] = 0;
        else
            this.data[this.pos++] = 1;
    };
    this.WriteUChar = function(val)
    {
        this.CheckSize(1);
        this.data[this.pos++] = val;
    };
    this.WriteUShort = function(val)
    {
        this.CheckSize(2);
        this.data[this.pos++] = (val)&0xFF;
        this.data[this.pos++] = (val >>> 8)&0xFF;
    };
    this.WriteULong = function(val)
    {
        this.CheckSize(4);
        this.data[this.pos++] = (val)&0xFF;
        this.data[this.pos++] = (val >>> 8)&0xFF;
        this.data[this.pos++] = (val >>> 16)&0xFF;
        this.data[this.pos++] = (val >>> 24)&0xFF;
    };
    this.WriteDouble = function(val)
    {
        this.WriteULong((val * 100000) >> 0);
    };
    this.WriteString = function(text)
    {
        var count = text.length & 0xFFFF;
        this.WriteULong(count);
        this.CheckSize(count);
        for (var i=0;i<count;i++)
        {
            var c = text.charCodeAt(i) & 0xFF;
            this.data[this.pos++] = c;
        }
    };
    this.WriteString2 = function(text)
    {
        var count = text.length & 0x7FFFFFFF;
        var countWrite = 2 * count;
        this.WriteULong(count);
        this.CheckSize(countWrite);
        for (var i=0;i<count;i++)
        {
            var c = text.charCodeAt(i) & 0xFFFF;
            this.data[this.pos++] = c&0xFF;
            this.data[this.pos++] = (c >>> 8)&0xFF;
        }
    };
    this.WriteBuffer = function(data, _pos, count)
    {
        this.CheckSize(count);
        for (var i = 0; i < count; i++)
        {
            this.data[this.pos++] = data[_pos+i];
        }
    }
    // ---------------------------

    this.m_arStack = [];
    this.m_lStackPosition = 0;
    this.m_arMainTables = [];

    this.StartRecord = function(lType)
    {
        this.m_arStack[this.m_lStackPosition] = this.pos + 5; // sizeof(BYTE) + sizeof(ULONG)
        this.m_lStackPosition++;
        this.WriteUChar(lType);
        this.WriteULong(0);
    };
    this.EndRecord = function()
    {
        this.m_lStackPosition--;

        var _seek = this.pos;
        this.pos = this.m_arStack[this.m_lStackPosition] - 4;
        this.WriteULong(_seek - this.m_arStack[this.m_lStackPosition]);
        this.pos = _seek;
    };

    this.StartMainRecord = function(lType)
    {
        var oEntry = new CSeekTableEntry();
        oEntry.Type = lType;
        oEntry.SeekPos = this.pos;
        this.m_arMainTables[this.m_arMainTables.length] = oEntry;
    };

    this.WriteReserved = function(lCount)
    {
        this.CheckSize(lCount);

        var _d = this.data;
        var _p = this.pos;
        var _e = this.pos + lCount;
        while (_p < _e)
            _d[_p++] = 0;

        this.pos += lCount;
    };

    this.WriteMainPart = function(startPos)
    {
        var _pos = this.pos;

        this.pos = startPos;
        var _count = this.m_arMainTables.length;

        for (var i = 0; i < _count; i++)
        {
            this.WriteUChar(this.m_arMainTables[i].Type);
            this.WriteULong(this.m_arMainTables[i].SeekPos);
        }

        this.pos = _pos;
    };

    this._WriteString1 = function(type, val)
    {
        this.WriteUChar(type);
        this.WriteString2(val);
    };
    this._WriteString2 = function(type, val)
    {
        if (val != null)
            this._WriteString1(type, val);
    };

    this._WriteUChar1 = function(type, val)
    {
        this.WriteUChar(type);
        this.WriteUChar(val);
    };
    this._WriteUChar2 = function(type, val)
    {
        if (val != null)
            this._WriteUChar1(type, val);
    };

    this._WriteBool1 = function(type, val)
    {
        this.WriteUChar(type);
        this.WriteBool(val);
    };
    this._WriteBool2 = function(type, val)
    {
        if (val != null)
            this._WriteBool1(type, val);
    };

    this._WriteInt1 = function(type, val)
    {
        this.WriteUChar(type);
        this.WriteULong(val);
    };
    this._WriteInt2 = function (type, val)
    {
        if (val != null)
            this._WriteInt1(type, val);
    };

    this._WriteInt3 = function (type, val, scale)
    {
        this._WriteInt1(type, val * scale);
    };

    this._WriteInt4 = function (type, val, scale)
    {
        if (val != null)
            this._WriteInt1(type, (val * scale) >> 0);
    };

    this._WriteDouble1 = function(type, val)
    {
        var _val = val * 10000;
        this._WriteInt1(type, _val);
    };
    this._WriteDouble2 = function(type, val)
    {
        if (val != null)
            this._WriteDouble1(type, val);
    };

    this._WriteLimit1 = this._WriteUChar1;
    this._WriteLimit2 = this._WriteUChar2;

    this.WriteRecord1 = function(type, val, func_write)
    {
        this.StartRecord(type);
        func_write(val);
        this.EndRecord();
    };
    this.WriteRecord2 = function(type, val, func_write)
    {
        if (null != val)
        {
            this.StartRecord(type);
            func_write(val);
            this.EndRecord();
        }
    };

    this.WriteRecord3 = function(type, val, func_write)
    {
        if (null != val)
        {
            var _start_pos = this.pos;

            this.StartRecord(type);
            func_write(val);
            this.EndRecord();

            if ((_start_pos + 5) == this.pos)
            {
                // удаляем запись из бинарника
                this.pos -= 5;

                return false;
            }

            return true;
        }

        return false;
    };

    this.WriteRecordArray = function(type, subtype, val_array, func_element_write)
    {
        this.StartRecord(type);

        var len = val_array.length;
        this.WriteULong(len);

        for (var i = 0; i < len; i++)
            this.WriteRecord1(subtype, val_array[i], func_element_write);

        this.EndRecord();
    };

    // font map
    this.font_map = {};
    this.image_map = {};

    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////

    this.WriteDocument2 = function(presentation)
    {
        this.font_map = {};
        this.image_map = {};

        var startPos = this.GetCurPosition();
        this.WriteReserved(5 * 30);

        // main
        this.StartMainRecord(c_oMainTables.Main);
        this.WriteULong(0x50505459);
        this.WriteULong(0);

        // App
		if (presentation.App)
			this.WriteApp(presentation.App);

        // Core
		if (presentation.Core)
			this.WriteCore(presentation.Core);

        // ViewProps
		if (presentation.ViewProps)
			this.WriteViewProps(presentation.ViewProps);
        
        // PresProps
		this.WritePresProps(presentation);
        
        // presentation
        this.WritePresentation(presentation);

        var _dst_themes = [];
        var _dst_masters = [];
        var _dst_layouts = [];
        var _dst_slides = [];
        var _dst_notes = [];
        var _dst_notesMasters = [];

        var _slides_rels = [];
        var _master_rels = [];

        var _slides = presentation.Slides;
        var _slide_count = _slides.length;

        for (var i = 0; i < _slide_count; i++)
        {
            _dst_slides[i] = _slides[i];
            if(_slides[i].notes && !_slides[i].notes.isEmptyBody())
            {
                _dst_notes.push(_slides[i].notes);
            }
            var _m = _slides[i].Layout.Master;

            var is_found = false;
            var _len_dst = _dst_masters.length;
            for (var j = 0; j < _len_dst; j++)
            {
                if (_dst_masters[j] == _m)
                {
                    is_found = true;
                    break;
                }
            }

            if (!is_found)
            {
                _dst_masters[_len_dst] = _m;

                var _m_rels = { ThemeIndex : 0, Layouts : [] };
                var _lay_c = _m.sldLayoutLst.length;

                var _ind_l = _dst_layouts.length;
                for (var k = 0; k < _lay_c; k++)
                {
                    _dst_layouts[_ind_l] = _m.sldLayoutLst[k];
                    _m_rels.Layouts[k] = _ind_l;
                    _ind_l++;
                }

                _master_rels[_len_dst] = _m_rels;
            }

            var _layoutsC = _dst_layouts.length;
            for (var ii = 0; ii < _layoutsC; ii++)
            {
                if (_dst_layouts[ii] == _dst_slides[i].Layout)
                {
                    _slides_rels[i] = ii;
                }
            }
        }


        for(var i = 0; i < _dst_notes.length; ++i)
        {
            for(var j = 0; j < _dst_notesMasters.length; ++j)
            {
                if(_dst_notesMasters[j] === _dst_notes[i].Master)
                {
                    break;
                }
            }
            if(j === _dst_notesMasters.length)
            {
                _dst_notesMasters.push(_dst_notes[i].Master);
            }
        }

        var _dst_masters_len = _dst_masters.length;
        if (0 == _dst_masters_len && presentation.slideMasters.length > 0)
        {
            var _m = presentation.slideMasters[0];

            _dst_masters[0] = _m;

            var _m_rels = { ThemeIndex : 0, Layouts : [] };
            var _lay_c = _m.sldLayoutLst.length;

            var _ind_l = _dst_layouts.length;
            for (var k = 0; k < _lay_c; k++)
            {
                _dst_layouts[_ind_l] = _m.sldLayoutLst[k];
                _m_rels.Layouts[k] = _ind_l;
                _ind_l++;
            }

            _master_rels[0] = _m_rels;
            _dst_masters_len = 1;
        }

        for (var i = 0; i < _dst_masters_len; i++)
        {
            var _t = _dst_masters[i].Theme;

            var is_found = false;
            var _len_dst = _dst_themes.length;
            for (var j = 0; j < _len_dst; j++)
            {
                if (_dst_themes[j] == _t)
                {
                    is_found = true;
                    break;
                }
            }

            if (!is_found)
            {
                _dst_themes[_len_dst] = _t;
                _master_rels[i].ThemeIndex = _len_dst;
            }
        }

        var i, j;
        for(i = 0; i < _dst_notesMasters.length; ++i){
            for(j = 0; j < _dst_themes.length; ++j){
                if(_dst_themes[j] === _dst_notesMasters[i].Theme){
                    break;
                }
            }
            if(j === _dst_themes.length){
                _dst_themes.push(_dst_notesMasters[i].Theme);
            }
        }

        //var _count_table_styles = presentation.globalTableStyles.length;
        //if (0 < _count_table_styles)
        //{

        var oTableStyleIdMap;
        if(presentation.GetTableStyleIdMap)
        {
            oTableStyleIdMap = {};
            presentation.GetTableStyleIdMap(oTableStyleIdMap);
        }
        else
        {
            oTableStyleIdMap = presentation.TableStylesIdMap;
        }
        for(var key in oTableStyleIdMap)
        {
            if(oTableStyleIdMap.hasOwnProperty(key))
            {
                this.tableStylesGuides[key] = "{" + GUID() + "}"
            }
        }


        this.StartMainRecord(c_oMainTables.TableStyles);
        this.StartRecord(c_oMainTables.SlideRels);
        this.WriteUChar(g_nodeAttributeStart);
        if(this.tableStylesGuides[presentation.DefaultTableStyleId])
        {
            this._WriteString1(0, this.tableStylesGuides[presentation.DefaultTableStyleId]);
        }
        else
        {
            for(key in this.tableStylesGuides)
            {
                if(this.tableStylesGuides.hasOwnProperty(key))
                {
                    this._WriteString1(0, this.tableStylesGuides[key]);
                    break;
                }
            }
        }
        this.WriteUChar(g_nodeAttributeEnd);

        this.StartRecord(0);
        for (key in this.tableStylesGuides)
        {
            if(this.tableStylesGuides.hasOwnProperty(key))
            {
                this.WriteTableStyle(key, AscCommon.g_oTableId.m_aPairs[key]);
            }
        }
        this.EndRecord();

        this.EndRecord();
        //}

        this.StartMainRecord(c_oMainTables.SlideRels);
        this.StartRecord(c_oMainTables.SlideRels);
        this.WriteUChar(g_nodeAttributeStart);
        for (var i = 0; i < _slide_count; i++)
        {
            this._WriteInt1(0, _slides_rels[i]);
        }
        this.WriteUChar(g_nodeAttributeEnd);
        this.EndRecord();

        this.StartMainRecord(c_oMainTables.SlideNotesRels);
        this.StartRecord(c_oMainTables.SlideNotesRels);
        this.WriteUChar(g_nodeAttributeStart);
        var _rels, slideNotes, i, j;
        var _notes = _dst_notes;
        var _notes_count = _notes.length;
        for(var  i = 0; i < _slide_count; ++i){
            slideNotes = presentation.Slides[i].notes;
            _rels = -1;
            if(slideNotes){
                for(j = 0; j < _notes_count; ++j){
                    if(_notes[j] === slideNotes){
                        _rels = j;
                        break;
                    }
                }
            }
            this._WriteInt1(0, _rels);
        }
        this.WriteUChar(g_nodeAttributeEnd);
        this.EndRecord();


        this.StartMainRecord(c_oMainTables.NotesMastersRels);
        this.StartRecord(c_oMainTables.NotesMastersRels);
        this.WriteUChar(g_nodeAttributeStart);
        var _notes_masters = _dst_notesMasters;
        var _notes_masters_count = _notes_masters.length;
        var _themes = _dst_themes;
        var _thems_count = _themes.length;
        var _theme;
        for(i = 0; i < _notes_masters_count; ++i){
            _theme = _notes_masters[i].Theme;
            _rels = -1;
            for(j = 0; j < _thems_count; ++j){
                if(_theme === _themes[j]){
                    _rels = j;
                    break;
                }
            }
            this._WriteInt1(0, _rels);
        }
        this.WriteUChar(g_nodeAttributeEnd);
        this.EndRecord();

        this.StartMainRecord(c_oMainTables.NotesRels);
        this.StartRecord(c_oMainTables.NotesRels);
        this.WriteUChar(g_nodeAttributeStart);
        var _notes_count = _notes.length;
        for(i = 0; i < _notes_count; ++i){
            slideNotes = _notes[i];
            _rels = -1;
            for(j = 0; j < _notes_masters_count; ++j){
                if(slideNotes.Master === _notes_masters[j]){
                    _rels = j;
                    break;
                }
            }
            this._WriteInt1(0, _rels);
        }
        this.WriteUChar(g_nodeAttributeEnd);
        this.EndRecord();




        this.StartMainRecord(c_oMainTables.ThemeRels);
        this.StartRecord(c_oMainTables.ThemeRels);
        var _master_count = _dst_masters.length;
        this.WriteULong(_master_count);
        for (var i = 0; i < _master_count; i++)
        {
            this.StartRecord(0);

            this.WriteUChar(g_nodeAttributeStart);

            this._WriteInt1(0, _master_rels[i].ThemeIndex);
            this.WriteUChar(1);
            this.WriteString(_dst_masters[i].ImageBase64);

            this.WriteUChar(g_nodeAttributeEnd);

            var _lay_c = _master_rels[i].Layouts.length;
            this.WriteULong(_lay_c);
            for (var j = 0; j < _lay_c; j++)
            {
                this.StartRecord(0);
                this.WriteUChar(g_nodeAttributeStart);
                var _indL = _master_rels[i].Layouts[j];
                this._WriteInt1(0, _indL);
                this.WriteUChar(1);
                this.WriteString(_dst_layouts[_indL].ImageBase64);
                this.WriteUChar(g_nodeAttributeEnd);
                this.EndRecord();
            }

            this.EndRecord();
        }
        this.EndRecord();


        var _count_arr = 0;

        _count_arr = _dst_themes.length;
        this.StartMainRecord(c_oMainTables.Themes);
        this.WriteULong(_count_arr);
        for (var i = 0; i < _count_arr; i++)
            this.WriteTheme(_dst_themes[i]);

        _count_arr = _dst_masters.length;
        this.StartMainRecord(c_oMainTables.SlideMasters);
        this.WriteULong(_count_arr);
        for (var i = 0; i < _count_arr; i++)
            this.WriteSlideMaster(_dst_masters[i]);

        _count_arr = _dst_layouts.length;
        this.StartMainRecord(c_oMainTables.SlideLayouts);
        this.WriteULong(_count_arr);
        for (var i = 0; i < _count_arr; i++)
            this.WriteSlideLayout(_dst_layouts[i]);

        _count_arr = _dst_slides.length;
        this.StartMainRecord(c_oMainTables.Slides);
        this.WriteULong(_count_arr);
        for (var i = 0; i < _count_arr; i++)
            this.WriteSlide(_dst_slides[i]);

        _count_arr = _dst_notes.length;
        this.StartMainRecord(c_oMainTables.NotesSlides);
        this.WriteULong(_count_arr);
        for (var i = 0; i < _count_arr; i++)
            this.WriteSlideNote(_dst_notes[i]);

        _count_arr = _dst_notesMasters.length;
        this.StartMainRecord(c_oMainTables.NotesMasters);
        this.WriteULong(_count_arr);
        for (var i = 0; i < _count_arr; i++)
            this.WriteNoteMaster(_dst_notesMasters[i]);

        // во время записи - нужно заодно генерить FontMap и ImagesMap
        this.StartMainRecord(c_oMainTables.FontMap);
        this.StartRecord(c_oMainTables.FontMap);
        this.WriteUChar(g_nodeAttributeStart);

        var _index_attr = 0;
        for (var i in this.font_map)
        {
            this.WriteUChar(_index_attr++);
            this.WriteString2(i);
        }

        this.WriteUChar(g_nodeAttributeEnd);
        this.EndRecord();

        this.StartMainRecord(c_oMainTables.ImageMap);
        this.StartRecord(c_oMainTables.ImageMap);
        this.WriteUChar(g_nodeAttributeStart);

        _index_attr = 0;
        for (var i in this.image_map)
        {
            this.WriteUChar(_index_attr++);
            this.WriteString2(i);
        }

        this.WriteUChar(g_nodeAttributeEnd);
        this.EndRecord();

        // теперь запишем информацию о главных таблицах
        this.WriteMainPart(startPos);
    }

    this.WriteDocument = function(presentation)
    {
        this.WriteDocument2(presentation);

        // и скинем все в base64
        var ret = "PPTY;v1;" + this.pos + ";";
        return ret + this.GetBase64Memory();
    }
	
	this.WriteDocument3 = function(presentation, base64) {
		var _memory = new AscCommon.CMemory(true);
		_memory.ImData = this.ImData;
		_memory.data = this.data;
		_memory.len = this.len;
		_memory.pos = this.pos;

		_memory.WriteXmlString("PPTY;v" + Asc.c_nVersionNoBase64 + ";0;");

		this.ImData = _memory.ImData;
		this.data = _memory.data;
		this.len = _memory.len;
		this.pos = _memory.pos;
		
		this.WriteDocument2(presentation);
		
		_memory.ImData = this.ImData;
		_memory.data = this.data;
		_memory.len = this.len;
		_memory.pos = this.pos;

		if (!base64)
		    return _memory.GetData();
		return _memory.GetBase64Memory();
	}
	this.WriteByMemory = function(callback) {
		var _memory = new AscCommon.CMemory(true);
		_memory.ImData = this.ImData;
		_memory.data = this.data;
		_memory.len = this.len;
		_memory.pos = this.pos;

		callback(_memory);

		this.ImData = _memory.ImData;
		this.data = _memory.data;
		this.len = _memory.len;
		this.pos = _memory.pos;
	};

    this.WriteApp = function(app)
    {
        this.StartMainRecord(c_oMainTables.App);
        this.StartRecord(c_oMainTables.App);

        this.WriteUChar(g_nodeAttributeStart);

        this._WriteString2(0, app.Template);
        this._WriteString2(1, app.Application);
        this._WriteString2(2, app.PresentationFormat);
        this._WriteString2(3, app.Company);
        this._WriteString2(4, app.AppVersion);

        this._WriteInt2(5, app.TotalTime);
        this._WriteInt2(6, app.Words);
        this._WriteInt2(7, app.Paragraphs);
        this._WriteInt2(8, app.Slides);
        this._WriteInt2(9, app.Notes);
        this._WriteInt2(10, app.HiddenSlides);
        this._WriteInt2(11, app.MMClips);

        this._WriteBool2(12, app.ScaleCrop);
        this._WriteBool2(13, app.LinksUpToDate);
        this._WriteBool2(14, app.SharedDoc);
        this._WriteBool2(15, app.HyperlinksChanged);

        this.WriteUChar(g_nodeAttributeEnd);

        this.EndRecord();
    }
    this.WriteCore = function(core)
    {
        this.StartMainRecord(c_oMainTables.Core);
        this.StartRecord(c_oMainTables.Core);

        this.WriteUChar(g_nodeAttributeStart);

        this._WriteString2(0, core.title);
        this._WriteString2(1, core.creator);
        this._WriteString2(2, core.lastModifiedBy);
        this._WriteString2(3, core.revision);
        this._WriteString2(4, core.created);
        this._WriteString2(5, core.modified);

        this.WriteUChar(g_nodeAttributeEnd);

        this.EndRecord();
    }
    this.WriteViewProps = function(viewprops)
    {
        this.StartMainRecord(c_oMainTables.ViewProps);
        this.StartRecord(c_oMainTables.ViewProps);
        this.EndRecord();
    }
    this.WritePresProps = function(presentation)
    {       
        this.StartMainRecord(c_oMainTables.PresProps);
        this.StartRecord(c_oMainTables.PresProps);
        
        //showPr
        var showPr = presentation.showPr;
        if (showPr) {
            this.StartRecord(1);
            this.WriteUChar(g_nodeAttributeStart);

            this._WriteBool2(0, showPr.loop);
            this._WriteBool2(1, showPr.showAnimation);
            this._WriteBool2(2, showPr.showNarration);
            this._WriteBool2(3, showPr.useTimings);

            this.WriteUChar(g_nodeAttributeEnd);
            
            if (showPr.browse) {
                this.StartRecord(0);
                //todo browseShowScrollbar
                this.EndRecord();
            }
            if (showPr.show && null != showPr.show.custShow) {
                this.StartRecord(1);
                this.WriteUChar(g_nodeAttributeStart);
                this._WriteInt2(0, showPr.show.custShow);
                this.WriteUChar(g_nodeAttributeEnd);
                this.EndRecord();
            }
            if (showPr.kiosk) {
                this.StartRecord(2);
                this.WriteUChar(g_nodeAttributeStart);
                this._WriteInt2(0, showPr.kiosk.restart);
                this.WriteUChar(g_nodeAttributeEnd);
                this.EndRecord();
            }
            this.WriteRecord1(3, showPr.penClr, this.WriteUniColor);
            if (showPr.present) {
                this.StartRecord(4);
                this.EndRecord();
            }
            if (showPr.show && null != showPr.show.showAll) {
                this.StartRecord(5);
                this.EndRecord();
            }
            if (showPr.show && showPr.show.range && null != showPr.show.range.start && null != showPr.show.range.end) {
                this.StartRecord(6);
                this.WriteUChar(g_nodeAttributeStart);
                this._WriteInt2(0, showPr.show.range.start);
                this._WriteInt2(1, showPr.show.range.end);
                this.WriteUChar(g_nodeAttributeEnd);
                this.EndRecord();
            }
            this.EndRecord();
        }
        this.EndRecord();
    }

    this.WritePresentation = function(presentation)
    {
        var pres = presentation.pres;

        this.StartMainRecord(c_oMainTables.Presentation);

        this.StartRecord(c_oMainTables.Presentation);

        this.WriteUChar(g_nodeAttributeStart);

        this._WriteBool2(0, pres.attrAutoCompressPictures);
        this._WriteInt2(1, pres.attrBookmarkIdSeed);
        this._WriteBool2(2, pres.attrCompatMode);
        this._WriteLimit2(3, pres.attrConformance);
        this._WriteBool2(4, pres.attrEmbedTrueTypeFonts);
        this._WriteInt2(5, pres.attrFirstSlideNum);
        this._WriteBool2(6, pres.attrRemovePersonalInfoOnSave);
        this._WriteBool2(7, pres.attrRtl);
        this._WriteBool2(8, pres.attrSaveSubsetFonts);
        this._WriteString2(9, pres.attrServerZoom);
        this._WriteBool2(10, pres.attrShowSpecialPlsOnTitleSld);
        this._WriteBool2(11, pres.attrStrictFirstAndLastChars);

        this.WriteUChar(g_nodeAttributeEnd);

        this.WriteRecord2(0, presentation.defaultTextStyle, this.WriteTextListStyle);

        // 5
        pres.SldSz.cx = (presentation.Width * c_dScalePPTXSizes) >> 0;
        pres.SldSz.cy = (presentation.Height * c_dScalePPTXSizes) >> 0;

        this.StartRecord(5);
        this.WriteUChar(g_nodeAttributeStart);

        this._WriteInt1(0, pres.SldSz.cx);
        this._WriteInt1(1, pres.SldSz.cy);
        this._WriteLimit2(2, pres.SldSz.type);

        this.WriteUChar(g_nodeAttributeEnd);
        this.EndRecord();

        // 3
        pres.NotesSz = {};
        pres.NotesSz.cx = (presentation.Height * c_dScalePPTXSizes) >> 0;
        pres.NotesSz.cy = (presentation.Width * c_dScalePPTXSizes) >> 0;

        this.StartRecord(3);
        this.WriteUChar(g_nodeAttributeStart);

        this._WriteInt1(0, pres.NotesSz.cx);
        this._WriteInt1(1, pres.NotesSz.cy);

        this.WriteUChar(g_nodeAttributeEnd);
        this.EndRecord();

        if (!this.IsUseFullUrl)
        {
            var _countAuthors = 0;
            for (var i in presentation.CommentAuthors)
                ++_countAuthors;

            if (_countAuthors > 0)
            {
                this.StartRecord(6);
                this.StartRecord(0);

                this.WriteULong(_countAuthors);

                for (var i in presentation.CommentAuthors)
                {
                    var _author = presentation.CommentAuthors[i];

                    this.StartRecord(0);

                    this.WriteUChar(g_nodeAttributeStart);

                    this._WriteInt1(0, _author.Id);
                    this._WriteInt1(1, _author.LastId);
                    this._WriteInt1(2, _author.Id - 1);
                    this._WriteString1(3, _author.Name);
                    this._WriteString1(4, _author.Initials);

                    this.WriteUChar(g_nodeAttributeEnd);

                    this.EndRecord();
                }

                this.EndRecord();
                this.EndRecord();
            }
        }
		var macros = presentation.Api.macros.GetData();
		if (macros) {
			this.StartRecord(9);
			this.WriteByMemory(function(_memory){
				_memory.WriteXmlString(macros);
			});
			this.EndRecord();
		}
        if (presentation.writecomments) {
            this.WriteComments(10, presentation.writecomments);
        }

        this.EndRecord();
    }

    this.WriteTheme = function(_theme)
    {
        this.StartRecord(c_oMainTables.Themes);

        this.WriteUChar(g_nodeAttributeStart);
        this._WriteString2(0, _theme.name);

        if (_theme.isThemeOverride)
            this._WriteBool1(1, true);

        this.WriteUChar(g_nodeAttributeEnd);

        this.WriteRecord1(0, _theme.themeElements, this.WriteThemeElements);
        this.WriteRecord2(1, _theme.spDef, this.WriteDefaultShapeDefinition);
        this.WriteRecord2(2, _theme.lnDef, this.WriteDefaultShapeDefinition);
        this.WriteRecord2(3, _theme.txDef, this.WriteDefaultShapeDefinition);

        this.WriteRecordArray(4, 0, _theme.extraClrSchemeLst, this.WriteExtraClrScheme);

        this.EndRecord();
    }

    this.WriteSlideMaster = function(_master)
    {
        this.StartRecord(c_oMainTables.SlideMasters);

        this.WriteUChar(g_nodeAttributeStart);
        this._WriteBool2(0, _master.preserve);
        this.WriteUChar(g_nodeAttributeEnd);

        this.WriteRecord1(0, _master.cSld, this.WriteCSld);
        this.WriteRecord1(1, _master.clrMap, this.WriteClrMap);
        this.WriteRecord2(5, _master.hf, this.WriteHF);
        this.WriteRecord2(6, _master.txStyles, this.WriteTxStyles);

        this.EndRecord();
    }

    this.WriteSlideLayout = function(_layout)
    {
        this.StartRecord(c_oMainTables.SlideLayouts);

        this.WriteUChar(g_nodeAttributeStart);
        this._WriteString2(0, _layout.matchingName);
        this._WriteBool2(1, _layout.preserve);
        this._WriteBool2(2, _layout.showMasterPhAnim);
        this._WriteBool2(3, _layout.showMasterSp);
        this._WriteBool2(4, _layout.userDrawn);
        this._WriteLimit2(5, _layout.type);
        this.WriteUChar(g_nodeAttributeEnd);

        this.WriteRecord1(0, _layout.cSld, this.WriteCSld);
        this.WriteRecord2(1, _layout.clrMap, this.WriteClrMapOvr);
        this.WriteRecord2(4, _layout.hf, this.WriteHF);

        this.EndRecord();
    }

    this.WriteSlide = function(_slide)
    {
        this.StartRecord(c_oMainTables.Slides);

        this.WriteUChar(g_nodeAttributeStart);
        this._WriteBool2(0, _slide.show);
        this._WriteBool2(1, _slide.showMasterPhAnim);
        this._WriteBool2(2, _slide.showMasterSp);
        this.WriteUChar(g_nodeAttributeEnd);

        this.WriteRecord1(0, _slide.cSld, this.WriteCSld);
        this.WriteRecord2(1, _slide.clrMap, this.WriteClrMapOvr);
        this.WriteRecord1(2, _slide.timing, this.WriteSlideTransition);
        this.WriteComments(4, _slide.writecomments);

        this.EndRecord();
    }
    this.WriteComments = function(type, comments)
    {
        var _countComments = 0;

       // if (!oThis.IsUseFullUrl)
        {
            for (var i in comments)
                ++_countComments;
        }

        if (_countComments > 0)
        {
            oThis.StartRecord(type);
            oThis.StartRecord(0);

            oThis.WriteULong(_countComments);

            for (var i in comments)
            {
                var _comment = comments[i];

                oThis.StartRecord(0);

                oThis.WriteUChar(g_nodeAttributeStart);

                oThis._WriteInt1(0, _comment.WriteAuthorId);
                oThis._WriteString1(1, _comment.WriteTime);
                oThis._WriteInt1(2, _comment.WriteCommentId);
                oThis._WriteInt1(3, (22.66*_comment.x) >> 0);
                oThis._WriteInt1(4, (22.66*_comment.y) >> 0);
                oThis._WriteString1(5, _comment.Data.m_sText);

                if (0 != _comment.WriteParentAuthorId)
                {
                    oThis._WriteInt1(6, _comment.WriteParentAuthorId);
                    oThis._WriteInt1(7, _comment.WriteParentCommentId);
                }

                oThis._WriteString1(8, _comment.AdditionalData);

                oThis.WriteUChar(g_nodeAttributeEnd);

                oThis.EndRecord();
            }

            oThis.EndRecord();
            oThis.EndRecord();
        }
    }

    this.WriteSlideTransition = function(_timing)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteBool1(0, _timing.SlideAdvanceOnMouseClick);

        if (_timing.SlideAdvanceAfter)
        {
            oThis._WriteInt1(1, _timing.SlideAdvanceDuration);

            if (_timing.TransitionType == c_oAscSlideTransitionTypes.None)
            {
                oThis._WriteInt1(2, 0);
            }
        }
        else if (_timing.TransitionType == c_oAscSlideTransitionTypes.None)
        {
            oThis._WriteInt1(2, 2000);
        }

        if (_timing.TransitionType != c_oAscSlideTransitionTypes.None)
        {
            oThis._WriteInt1(2, _timing.TransitionDuration);

            if (_timing.TransitionDuration < 250)
                oThis._WriteUChar1(3, 0);
            else if (_timing.TransitionDuration > 1000)
                oThis._WriteUChar1(3, 2);
            else
                oThis._WriteUChar1(3, 1);

            oThis.WriteUChar(g_nodeAttributeEnd);

            oThis.StartRecord(0);

            oThis.WriteUChar(g_nodeAttributeStart);

            switch (_timing.TransitionType)
            {
                case c_oAscSlideTransitionTypes.Fade:
                {
                    oThis._WriteString2(0, "p:fade");
                    switch (_timing.TransitionOption)
                    {
                        case c_oAscSlideTransitionParams.Fade_Smoothly:
                        {
                            oThis._WriteString2(1, "thruBlk");
                            oThis._WriteString2(2, "0");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Fade_Through_Black:
                        {
                            oThis._WriteString2(1, "thruBlk");
                            oThis._WriteString2(2, "1");
                            break;
                        }
                        default:
                            break;
                    }
                    break;
                }
                case c_oAscSlideTransitionTypes.Push:
                {
                    oThis._WriteString2(0, "p:push");
                    switch (_timing.TransitionOption)
                    {
                        case c_oAscSlideTransitionParams.Param_Left:
                        {
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "r");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_Right:
                        {
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "l");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_Top:
                        {
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "d");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_Bottom:
                        {
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "u");
                            break;
                        }
                        default:
                            break;
                    }
                    break;
                }
                case c_oAscSlideTransitionTypes.Wipe:
                {
                    switch (_timing.TransitionOption)
                    {
                        case c_oAscSlideTransitionParams.Param_Left:
                        {
                            oThis._WriteString2(0, "p:wipe");
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "r");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_Right:
                        {
                            oThis._WriteString2(0, "p:wipe");
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "l");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_Top:
                        {
                            oThis._WriteString2(0, "p:wipe");
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "d");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_Bottom:
                        {
                            oThis._WriteString2(0, "p:wipe");
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "u");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_TopLeft:
                        {
                            oThis._WriteString2(0, "p:strips");
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "rd");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_TopRight:
                        {
                            oThis._WriteString2(0, "p:strips");
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "ld");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_BottomLeft:
                        {
                            oThis._WriteString2(0, "p:strips");
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "ru");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_BottomRight:
                        {
                            oThis._WriteString2(0, "p:strips");
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "lu");
                            break;
                        }
                        default:
                            break;
                    }
                    break;
                }
                case c_oAscSlideTransitionTypes.Split:
                {
                    oThis._WriteString2(0, "p:split");
                    switch (_timing.TransitionOption)
                    {
                        case c_oAscSlideTransitionParams.Split_HorizontalIn:
                        {
                            oThis._WriteString2(1, "orient");
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "horz");
                            oThis._WriteString2(2, "in");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Split_HorizontalOut:
                        {
                            oThis._WriteString2(1, "orient");
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "horz");
                            oThis._WriteString2(2, "out");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Split_VerticalIn:
                        {
                            oThis._WriteString2(1, "orient");
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "vert");
                            oThis._WriteString2(2, "in");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Split_VerticalOut:
                        {
                            oThis._WriteString2(1, "orient");
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "vert");
                            oThis._WriteString2(2, "out");
                            break;
                        }
                        default:
                            break;
                    }
                    break;
                }
                case c_oAscSlideTransitionTypes.UnCover:
                case c_oAscSlideTransitionTypes.Cover:
                {
                    if (_timing.TransitionType == c_oAscSlideTransitionTypes.Cover)
                        oThis._WriteString2(0, "p:cover");
                    else
                        oThis._WriteString2(0, "p:pull");

                    switch (_timing.TransitionOption)
                    {
                        case c_oAscSlideTransitionParams.Param_Left:
                        {
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "r");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_Right:
                        {
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "l");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_Top:
                        {
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "d");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_Bottom:
                        {
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "u");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_TopLeft:
                        {
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "rd");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_TopRight:
                        {
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "ld");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_BottomLeft:
                        {
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "ru");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Param_BottomRight:
                        {
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "lu");
                            break;
                        }
                        default:
                            break;
                    }
                    break;
                }
                case c_oAscSlideTransitionTypes.Clock:
                {
                    switch (_timing.TransitionOption)
                    {
                        case c_oAscSlideTransitionParams.Clock_Clockwise:
                        {
                            oThis._WriteString2(0, "p:wheel");
                            oThis._WriteString2(1, "spokes");
                            oThis._WriteString2(2, "1");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Clock_Counterclockwise:
                        {
                            oThis._WriteString2(0, "p14:wheelReverse");
                            oThis._WriteString2(1, "spokes");
                            oThis._WriteString2(2, "1");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Clock_Wedge:
                        {
                            oThis._WriteString2(0, "p:wedge");
                            break;
                        }
                        default:
                            break;
                    }
                    break;
                }
                case c_oAscSlideTransitionTypes.Zoom:
                {
                    switch (_timing.TransitionOption)
                    {
                        case c_oAscSlideTransitionParams.Zoom_In:
                        {
                            oThis._WriteString2(0, "p14:warp");
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "in");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Zoom_Out:
                        {
                            oThis._WriteString2(0, "p14:warp");
                            oThis._WriteString2(1, "dir");
                            oThis._WriteString2(2, "out");
                            break;
                        }
                        case c_oAscSlideTransitionParams.Zoom_AndRotate:
                        {
                            oThis._WriteString2(0, "p:newsflash");
                            break;
                        }
                        default:
                            break;
                    }
                    break;
                }
                default:
                    break;
            }

            oThis.WriteUChar(g_nodeAttributeEnd);

            oThis.EndRecord();
        }
        else
        {
            oThis.WriteUChar(g_nodeAttributeEnd);
        }
    }

    this.WriteSlideNote = function(_note)
    {
        this.StartRecord(c_oMainTables.NotesSlides);

        this.WriteUChar(g_nodeAttributeStart);
        this._WriteBool2(0, _note.showMasterPhAnim);
        this._WriteBool2(1, _note.showMasterSp);
        this.WriteUChar(g_nodeAttributeEnd);

        this.WriteRecord1(0, _note.cSld, this.WriteCSld);
        this.WriteRecord2(1, _note.clrMap, this.WriteClrMapOvr);

        this.EndRecord();
    }

    this.WriteNoteMaster = function(_master)
    {
        this.StartRecord(c_oMainTables.NotesMasters);

        this.WriteRecord1(0, _master.cSld, this.WriteCSld);
        this.WriteRecord1(1, _master.clrMap, this.WriteClrMap);
        this.WriteRecord2(2, _master.hf, this.WriteHF);
        this.WriteRecord2(3, _master.txStyles, this.WriteTextListStyle);

        this.EndRecord();
    }

    //////////////////////////////common functions///////////////////////////
    this.WriteThemeElements = function(themeElements)
    {
        oThis.WriteRecord1(0, themeElements.clrScheme, oThis.WriteClrScheme);
        oThis.WriteRecord1(1, themeElements.fontScheme, oThis.WriteFontScheme);
        oThis.WriteRecord1(2, themeElements.fmtScheme, oThis.WriteFmtScheme);
    }
    this.WriteFontScheme = function(fontScheme)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteString1(0, fontScheme.name);
        oThis.WriteUChar(g_nodeAttributeEnd);

        oThis.WriteRecord1(0, fontScheme.majorFont, oThis.WriteFontCollection);
        oThis.WriteRecord1(1, fontScheme.minorFont, oThis.WriteFontCollection);
    }
    this.WriteFontCollection = function(coll)
    {
        oThis.WriteRecord1(0, { Name: coll.latin, Index : -1 }, oThis.WriteTextFontTypeface);
        oThis.WriteRecord1(1, { Name: coll.ea, Index : -1 }, oThis.WriteTextFontTypeface);
        oThis.WriteRecord1(2, { Name: coll.cs, Index : -1 }, oThis.WriteTextFontTypeface);
    }
    this.WriteFmtScheme = function(fmt)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteString1(0, fmt.name);
        oThis.WriteUChar(g_nodeAttributeEnd);

        oThis.WriteRecordArray(0, 0, fmt.fillStyleLst, oThis.WriteUniFill);
        oThis.WriteRecordArray(1, 0, fmt.lnStyleLst, oThis.WriteLn);
        oThis.WriteRecordArray(3, 0, fmt.bgFillStyleLst, oThis.WriteUniFill);
    }

    this.WriteDefaultShapeDefinition = function(shapeDef)
    {
        oThis.WriteRecord1(0, shapeDef.spPr, oThis.WriteSpPr);
        oThis.WriteRecord1(1, shapeDef.bodyPr, oThis.WriteBodyPr);
        oThis.WriteRecord1(2, shapeDef.lstStyle, oThis.WriteTextListStyle);
        oThis.WriteRecord2(3, shapeDef.style, oThis.WriteShapeStyle);
    }
    this.WriteExtraClrScheme = function(extraScheme)
    {
        oThis.WriteRecord1(0, extraScheme.clrScheme, oThis.WriteClrScheme);
        oThis.WriteRecord2(1, extraScheme.clrMap, oThis.WriteClrMap);
    }
    this.WriteCSld = function(cSld)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteString2(0, cSld.name);
        oThis.WriteUChar(g_nodeAttributeEnd);

        oThis.WriteRecord2(0, cSld.Bg, oThis.WriteBg);

        var spTree = cSld.spTree;
        var _len = spTree.length;

        oThis.StartRecord(1);

        oThis.StartRecord(4);

        var uniPr = AscFormat.ExecuteNoHistory(function(){return new AscFormat.UniNvPr();}, this, []);
        uniPr.cNvPr.id = 1;
        uniPr.cNvPr.name = "";

        var spPr = AscFormat.ExecuteNoHistory(function(){return new AscFormat.CSpPr();}, this, []);
        spPr.xfrm = AscFormat.ExecuteNoHistory(function(){return new AscFormat.CXfrm();}, this, []);
        spPr.xfrm.offX = 0;
        spPr.xfrm.offY = 0;
        spPr.xfrm.extX = 0;
        spPr.xfrm.extY = 0;
        spPr.xfrm.chOffX = 0;
        spPr.xfrm.chOffY = 0;
        spPr.xfrm.chExtX = 0;
        spPr.xfrm.chExtY = 0;
        spPr.WriteXfrm = spPr.xfrm;

        oThis.WriteRecord1(0, uniPr, oThis.WriteUniNvPr);
        oThis.WriteRecord1(1, spPr, oThis.WriteSpPr);

        if (0 != _len)
        {
            oThis.StartRecord(2);
            oThis.WriteULong(_len);

            oThis.ClearIdMap();
            for (var i = 0; i < _len; i++)
            {
                oThis.StartRecord(0);
				
				switch(spTree[i].getObjectType())
                {
                    case AscDFH.historyitem_type_Shape:
                    case AscDFH.historyitem_type_Cnx:
                    {
						oThis.WriteShape(spTree[i]);
                        break;
                    }
                    case AscDFH.historyitem_type_OleObject:
                    case AscDFH.historyitem_type_ImageShape:
                    {
                        oThis.WriteImage(spTree[i]);
                        break;
                    }
                    case AscDFH.historyitem_type_GroupShape:
                    {
                        oThis.WriteGroupShape(spTree[i]);
                        break;
                    }
                    case AscDFH.historyitem_type_ChartSpace:
                    {
                        oThis.WriteChart(spTree[i]);
                        break;
                    }
					default:
					{
						if (spTree[i] instanceof AscFormat.CGraphicFrame && spTree[i].graphicObject instanceof CTable)
						{
							oThis.WriteTable(spTree[i]);
						}
					}
                }

                oThis.EndRecord();
            }
            oThis.ClearIdMap();
            oThis.EndRecord();
        }

        oThis.EndRecord();

        oThis.EndRecord();
    }
    this.WriteClrMap = function(clrmap)
    {
        oThis.WriteUChar(g_nodeAttributeStart);

        var _len = clrmap.color_map.length;
        for (var i = 0; i < _len; ++i)
        {
            if (null != clrmap.color_map[i])
            {
                oThis.WriteUChar(i);
                oThis.WriteUChar(clrmap.color_map[i]);
            }
        }

        oThis.WriteUChar(g_nodeAttributeEnd);
    }
    this.WriteClrScheme = function(scheme)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteString1(0, scheme.name);
        oThis.WriteUChar(g_nodeAttributeEnd);

        var _len = scheme.colors.length;
        for (var i = 0; i < _len; i++)
        {
            if (null != scheme.colors[i])
            {
                oThis.WriteRecord1(i, scheme.colors[i], oThis.WriteUniColor);
            }
        }
    }
    this.WriteClrMapOvr = function(clrmapovr)
    {
        oThis.WriteRecord2(0, clrmapovr, oThis.WriteClrMap);
    }
    this.WriteHF = function(hf)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteBool2(0, hf.dt);
        oThis._WriteBool2(1, hf.ftr);
        oThis._WriteBool2(2, hf.hdr);
        oThis._WriteBool2(3, hf.sldNum);
        oThis.WriteUChar(g_nodeAttributeEnd);
    }
    this.WriteTxStyles = function(txStyles)
    {
        oThis.WriteRecord2(0, txStyles.titleStyle, oThis.WriteTextListStyle);
        oThis.WriteRecord2(1, txStyles.bodyStyle, oThis.WriteTextListStyle);
        oThis.WriteRecord2(2, txStyles.otherStyle, oThis.WriteTextListStyle);
    }
    this.WriteTextListStyle = function(styles)
    {
        var _levels = styles.levels;
        var _count = _levels.length;
        var _props_to_write;
        for (var i = 0; i < _count; ++i)
        {
            if(_levels[i])
            {
                _props_to_write = new AscFormat.CTextParagraphPr();
                _props_to_write.bullet = _levels[i].Bullet;
                _props_to_write.lvl = _levels[i].Lvl;
                _props_to_write.pPr = _levels[i];
                _props_to_write.rPr = _levels[i].DefaultRunPr;
            }
            else
            {
                _props_to_write = null;
            }
            oThis.WriteRecord2(i, _props_to_write, oThis.WriteTextParagraphPr);
        }
    }
    this.WriteTextParagraphPr = function(tPr)
    {
        oThis.WriteUChar(g_nodeAttributeStart);

        var pPr = tPr.pPr;
        if (undefined !== pPr && null != pPr)
        {
            switch (pPr.Jc)
            {
                case AscCommon.align_Left:
                    oThis._WriteUChar1(0, 4);
                    break;
                case AscCommon.align_Center:
                    oThis._WriteUChar1(0, 0);
                    break;
                case AscCommon.align_Right:
                    oThis._WriteUChar1(0, 5);
                    break;
                case AscCommon.align_Justify:
                    oThis._WriteUChar1(0, 2);
                    break;
                default:
                    break;
            }


            var defTab = pPr.DefaultTab;
            if (defTab !== undefined && defTab != null)
            {
                oThis._WriteInt1(1, defTab * 36000);
            }

            var ind = pPr.Ind;
            if (ind !== undefined && ind != null)
            {
                if (ind.FirstLine != null)
                {
                    oThis._WriteInt2(5, ind.FirstLine * 36000);
                }
                if (ind.Left != null)
                {
                    oThis._WriteInt1(8, ind.Left * 36000);
                }
                if (ind.Right != null)
                {
                    oThis._WriteInt1(9, ind.Right * 36000);
                }
            }
        }

        oThis._WriteInt2(7, tPr.lvl);

        oThis.WriteUChar(g_nodeAttributeEnd);

        if (undefined !== pPr && null != pPr)
        {
            var spacing = pPr.Spacing;
            if (spacing !== undefined && spacing != null)
            {
                var _value;
                switch (spacing.LineRule)
                {
                    case Asc.linerule_Auto:
                        oThis.StartRecord(0);
                        oThis.WriteUChar(g_nodeAttributeStart);
                        oThis._WriteInt1(0, (spacing.Line * 100000) >> 0);
                        oThis.WriteUChar(g_nodeAttributeEnd);
                        oThis.EndRecord();
                        break;
                    case Asc.linerule_Exact:
                        oThis.StartRecord(0);
                        oThis.WriteUChar(g_nodeAttributeStart);
                        _value = ((spacing.Line / 0.00352777778) >> 0);
                        if(_value < 0){
                            _value = 0;
                        }
                        if(_value > 158400){
                            _value = 158400;
                        }
                        oThis._WriteInt1(1, _value);
                        oThis.WriteUChar(g_nodeAttributeEnd);
                        oThis.EndRecord();
                        break;
                    default:
                        break;
                }

                if (spacing.After !== undefined && spacing.After !== null)
                {
                    oThis.StartRecord(1);
                    oThis.WriteUChar(g_nodeAttributeStart);
                    _value = ((spacing.After / 0.00352777778) >> 0);
                    if(_value < 0){
                        _value = 0;
                    }
                    if(_value > 158400){
                        _value = 158400;
                    }
                    oThis._WriteInt1(1, _value);
                    oThis.WriteUChar(g_nodeAttributeEnd);
                    oThis.EndRecord();
                }

                if (spacing.Before !== undefined && spacing.Before !== null)
                {
                    oThis.StartRecord(2);
                    oThis.WriteUChar(g_nodeAttributeStart);
                    _value = ((spacing.Before / 0.00352777778) >> 0);
                    if(_value < 0){
                        _value = 0;
                    }
                    if(_value > 158400){
                        _value = 158400;
                    }
                    oThis._WriteInt1(1, _value);
                    oThis.WriteUChar(g_nodeAttributeEnd);
                    oThis.EndRecord();
                }
            }
        }

        var bullet = tPr.bullet;

        if (undefined !== bullet && null != bullet)
        {
            if (bullet.bulletColor != null && bullet.bulletColor.type != AscFormat.BULLET_TYPE_COLOR_NONE)
            {
                oThis.StartRecord(3);

                if (bullet.bulletColor.type == AscFormat.BULLET_TYPE_COLOR_CLR)
                {
                    oThis.StartRecord(AscFormat.BULLET_TYPE_COLOR_CLR);
                    oThis.WriteRecord2(0, bullet.bulletColor.UniColor, oThis.WriteUniColor);
                    oThis.EndRecord();
                }
                else
                {
                    oThis.StartRecord(AscFormat.BULLET_TYPE_COLOR_CLRTX);
                    oThis.EndRecord();
                }

                oThis.EndRecord();
            }

            if (bullet.bulletSize != null && bullet.bulletSize.type != AscFormat.BULLET_TYPE_SIZE_NONE)
            {
                oThis.StartRecord(4);

                if (bullet.bulletSize.type == AscFormat.BULLET_TYPE_SIZE_PTS)
                {
                    oThis.StartRecord(AscFormat.BULLET_TYPE_SIZE_PTS);
                    oThis.WriteUChar(g_nodeAttributeStart);
                    oThis._WriteInt1(0, bullet.bulletSize.val);
                    oThis.WriteUChar(g_nodeAttributeEnd);
                    oThis.EndRecord();
                }
                else if (bullet.bulletSize.type == AscFormat.BULLET_TYPE_SIZE_PCT)
                {
                    oThis.StartRecord(AscFormat.BULLET_TYPE_SIZE_PCT);
                    oThis.WriteUChar(g_nodeAttributeStart);
                    oThis._WriteInt1(0, bullet.bulletSize.val);
                    oThis.WriteUChar(g_nodeAttributeEnd);
                    oThis.EndRecord();
                }
                else
                {
                    oThis.StartRecord(AscFormat.BULLET_TYPE_SIZE_TX);
                    oThis.EndRecord();
                }

                oThis.EndRecord();
            }

            if (bullet.bulletTypeface != null && bullet.bulletTypeface.type != null && bullet.bulletTypeface.type != AscFormat.BULLET_TYPE_TYPEFACE_NONE)
            {
                oThis.StartRecord(5);

                if (bullet.bulletTypeface.type == AscFormat.BULLET_TYPE_TYPEFACE_BUFONT)
                {
                    oThis.WriteRecord2(AscFormat.BULLET_TYPE_TYPEFACE_BUFONT, { Name: bullet.bulletTypeface.typeface, Index : -1}, oThis.WriteTextFontTypeface);
                }
                else
                {
                    oThis.StartRecord(AscFormat.BULLET_TYPE_TYPEFACE_TX);
                    oThis.EndRecord();
                }

                oThis.EndRecord();
            }

            if (bullet.bulletType != null && bullet.bulletType.type != null)
            {
                oThis.StartRecord(6);

                switch (bullet.bulletType.type)
                {
                    case AscFormat.BULLET_TYPE_BULLET_CHAR:
                    {
                        oThis.StartRecord(AscFormat.BULLET_TYPE_BULLET_CHAR);
                        oThis.WriteUChar(g_nodeAttributeStart);
                        oThis._WriteString1(0, bullet.bulletType.Char);
                        oThis.WriteUChar(g_nodeAttributeEnd);
                        oThis.EndRecord();
                        break;
                    }
                    case AscFormat.BULLET_TYPE_BULLET_BLIP:
                    {
                        // not support. char (*)
                        oThis.StartRecord(AscFormat.BULLET_TYPE_BULLET_CHAR);
                        oThis.WriteUChar(g_nodeAttributeStart);
                        oThis._WriteString1(0, "*");
                        oThis.WriteUChar(g_nodeAttributeEnd);
                        oThis.EndRecord();
                        break;
                    }
                    case AscFormat.BULLET_TYPE_BULLET_AUTONUM:
                    {
                        oThis.StartRecord(AscFormat.BULLET_TYPE_BULLET_AUTONUM);
                        oThis.WriteUChar(g_nodeAttributeStart);
                        oThis._WriteLimit1(0, bullet.bulletType.AutoNumType);
                        oThis._WriteInt2(1, bullet.bulletType.startAt);
                        oThis.WriteUChar(g_nodeAttributeEnd);
                        oThis.EndRecord();
                        break;
                    }
                    case AscFormat.BULLET_TYPE_BULLET_NONE:
                    {
                        oThis.StartRecord(AscFormat.BULLET_TYPE_BULLET_NONE);
                        oThis.EndRecord();
                        break;
                    }
                }

                oThis.EndRecord();
            }
        }

        if (pPr !== undefined && pPr != null && pPr.Tabs !== undefined && pPr.Tabs != null)
        {
            if (pPr.Tabs.Tabs != undefined &&  pPr.Tabs.Tabs!= null)
                oThis.WriteRecordArray(7, 0, pPr.Tabs.Tabs, oThis.WriteTab);
        }

        if (tPr !== undefined && tPr != null)
        {
            oThis.WriteRecord2(8, tPr.rPr, oThis.WriteRunProperties);
        }
    }

    this.WriteRunProperties = function(rPr, hlinkObj)
    {
        if (rPr == null || rPr === undefined)
            return;

        oThis.WriteUChar(g_nodeAttributeStart);

        oThis._WriteBool2(1, rPr.Bold);
        oThis._WriteBool2(7, rPr.Italic);

        var _cap = null;
        if (rPr.Caps === true)
            _cap = 0;
        else if (rPr.SmallCaps === true)
            _cap = 1;
        else if (rPr.Caps === false && rPr.SmallCaps === false)
            _cap = 2;

        if (null != _cap)
        {
            oThis._WriteUChar1(4, _cap);
        }

        oThis._WriteString2(10, g_oLcidIdToNameMap[rPr.Lang.Val]);

        var _strike = null;
        if (rPr.DStrikeout === true)
            _strike = 0;
        else if (rPr.Strikeout === true)
            _strike = 2;
        else if (rPr.DStrikeout === false && rPr.Strikeout === false)
            _strike = 1;

        if (undefined !== rPr.Spacing && null != rPr.Spacing)
        {
            oThis._WriteInt1(15, (rPr.Spacing * 7200 / 25.4) >> 0);
        }

        if (null != _strike)
        {
            oThis._WriteUChar1(16, _strike);
        }

        if (undefined !== rPr.Underline && null != rPr.Underline)
        {
            oThis._WriteUChar1(18, (rPr.Underline === true) ? 13 : 12);
        }

        if (undefined !== rPr.FontSize && null != rPr.FontSize)
        {
            oThis._WriteInt1(17, rPr.FontSize * 100);
        }

        if (AscCommon.vertalign_SubScript == rPr.VertAlign)
            oThis._WriteInt1(2, -25000);
        else if (AscCommon.vertalign_SuperScript == rPr.VertAlign)
            oThis._WriteInt1(2, 30000);

        oThis.WriteUChar(g_nodeAttributeEnd);

        if(rPr.TextOutline)
            oThis.WriteRecord1(0, rPr.TextOutline, oThis.WriteLn);

        if(rPr.Unifill)
            oThis.WriteRecord1(1, rPr.Unifill, oThis.WriteUniFill);

        if (rPr.RFonts)
        {
            if (rPr.RFonts.Ascii)
                oThis.WriteRecord2(3, rPr.RFonts.Ascii, oThis.WriteTextFontTypeface);
            if (rPr.RFonts.EastAsia)
                oThis.WriteRecord2(4, rPr.RFonts.EastAsia, oThis.WriteTextFontTypeface);
            if (rPr.RFonts.CS)
                oThis.WriteRecord2(5, rPr.RFonts.CS, oThis.WriteTextFontTypeface);
        }

        if (hlinkObj != null && hlinkObj !== undefined)
        {
            oThis.WriteRecord1(7, hlinkObj, oThis.WriteHyperlink);
        }
    }

    this.WriteHyperlink = function(hlink)
    {
        oThis.WriteUChar(g_nodeAttributeStart);

        var url = hlink.Value;
        var action = null;

        if (url == "ppaction://hlinkshowjump?jump=firstslide")
        {
            action = url;
            url = "";
        }
        else if (url == "ppaction://hlinkshowjump?jump=lastslide")
        {
            action = url;
            url = "";
        }
        else if (url == "ppaction://hlinkshowjump?jump=nextslide")
        {
            action = url;
            url = "";
        }
        else if (url == "ppaction://hlinkshowjump?jump=previousslide")
        {
            action = url;
            url = "";
        }
        else
        {
            var mask = "ppaction://hlinksldjumpslide";
            var indSlide = url.indexOf(mask);
            if (0 == indSlide)
            {
                var slideNum = parseInt(url.substring(mask.length));
                url = "slide" + (slideNum + 1) + ".xml";
                action = "ppaction://hlinksldjump";
            }
        }

        oThis._WriteString1(0, url);
        oThis._WriteString2(2, action);
        oThis._WriteString2(4, hlink.tooltip);

        oThis.WriteUChar(g_nodeAttributeEnd);
    }

    this.WriteTextFontTypeface = function(typeface)
    {
        oThis.WriteUChar(g_nodeAttributeStart);

        if (!typeface || typeface.Name == null)
        {
            oThis.font_map["Arial"] = true;
            oThis._WriteString1(3, "Arial");
            oThis.WriteUChar(g_nodeAttributeEnd);
            return;
        }

        if ((0 != typeface.Name.indexOf("+mj")) && (0 != typeface.Name.indexOf("+mn")))
            oThis.font_map[typeface.Name] = true;

        oThis._WriteString1(3, typeface.Name);

        oThis.WriteUChar(g_nodeAttributeEnd);
    }

    this.WriteTab = function(tab)
    {
        oThis.WriteUChar(g_nodeAttributeStart);

        var _algn = 2;
        if (tab.Value == tab_Center)
            _algn = 0;
        else if (tab.Value == tab_Right)
            _algn = 3;

        oThis._WriteLimit2(0, _algn);

        if (tab.Pos != undefined && tab.Pos != null)
        {
            oThis._WriteInt1(1, tab.Pos * 36000);
        }

        oThis.WriteUChar(g_nodeAttributeEnd);
    }

    this.WriteBodyPr = function(bodyPr)
    {
        if (undefined === bodyPr || null == bodyPr)
            return;

        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteInt2(0, bodyPr.flatTx);
        oThis._WriteLimit2(1, bodyPr.anchor);
        oThis._WriteBool2(2, bodyPr.anchorCtr);
        oThis._WriteInt4(3, bodyPr.bIns, 36000);
        oThis._WriteBool2(4, bodyPr.compatLnSpc);
        oThis._WriteBool2(5, bodyPr.forceAA);
        oThis._WriteBool2(6, bodyPr.fromWordArt);
        oThis._WriteLimit2(7, bodyPr.horzOverflow);
        oThis._WriteInt4(8, bodyPr.lIns, 36000);
        oThis._WriteInt2(9, bodyPr.numCol);
        oThis._WriteInt4(10, bodyPr.rIns, 36000);
        oThis._WriteInt2(11, bodyPr.rot);
        oThis._WriteBool2(12, bodyPr.rtlCol);
        oThis._WriteInt4(13, bodyPr.spcCol, 36000);
        oThis._WriteBool2(14, bodyPr.spcFirstLastPara);
        oThis._WriteInt4(15, bodyPr.tIns, 36000);
        oThis._WriteBool2(16, bodyPr.upright);
        oThis._WriteLimit2(17, bodyPr.vert);
        oThis._WriteLimit2(18, bodyPr.vertOverflow);
        oThis._WriteLimit2(19, bodyPr.wrap);

        oThis.WriteUChar(g_nodeAttributeEnd);

        oThis.WriteRecord2(0, bodyPr.prstTxWarp, oThis.WritePrstTxWarp);
        if(bodyPr.textFit)
        {
            oThis.WriteRecord1(1, bodyPr.textFit, oThis.WriteTextFit);
        }
    };


    this.WriteTextFit = function(oTextFit)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteInt1(0, oTextFit.type + 1);
        oThis._WriteInt2(1, oTextFit.fontScale);
        oThis._WriteInt2(2, oTextFit.lnSpcReduction);
        oThis.WriteUChar(g_nodeAttributeEnd);
    };

    // fill-stroke ---------------------------------------------------------------
    this.WriteUniColor = function(unicolor)
    {
        if (undefined === unicolor || null == unicolor || unicolor.color == null)
            return;

        var color = unicolor.color;
        switch (color.type)
        {
            case c_oAscColor.COLOR_TYPE_PRST:
            {
                oThis.StartRecord(c_oAscColor.COLOR_TYPE_PRST);

                oThis.WriteUChar(g_nodeAttributeStart);
                oThis._WriteString1(0, color.id);
                oThis.WriteUChar(g_nodeAttributeEnd);

                oThis.WriteMods(unicolor.Mods);

                oThis.EndRecord();
                break;
            }
            case c_oAscColor.COLOR_TYPE_SCHEME:
            {
                oThis.StartRecord(c_oAscColor.COLOR_TYPE_SCHEME);

                oThis.WriteUChar(g_nodeAttributeStart);
                oThis._WriteUChar1(0, color.id);
                oThis.WriteUChar(g_nodeAttributeEnd);

                oThis.WriteMods(unicolor.Mods);

                oThis.EndRecord();
                break;
            }
            case c_oAscColor.COLOR_TYPE_SRGB:
            {
                oThis.StartRecord(c_oAscColor.COLOR_TYPE_SRGB);

                oThis.WriteUChar(g_nodeAttributeStart);
                oThis._WriteUChar1(0, color.RGBA.R);
                oThis._WriteUChar1(1, color.RGBA.G);
                oThis._WriteUChar1(2, color.RGBA.B);
                oThis.WriteUChar(g_nodeAttributeEnd);

                oThis.WriteMods(unicolor.Mods);

                oThis.EndRecord();
                break;
            }
            case c_oAscColor.COLOR_TYPE_SYS:
            {
                oThis.StartRecord(c_oAscColor.COLOR_TYPE_SYS);

                oThis.WriteUChar(g_nodeAttributeStart);
                oThis._WriteString1(0, color.id);
                oThis._WriteUChar1(1, color.RGBA.R);
                oThis._WriteUChar1(2, color.RGBA.G);
                oThis._WriteUChar1(3, color.RGBA.B);
                oThis.WriteUChar(g_nodeAttributeEnd);

                oThis.WriteMods(unicolor.Mods);

                oThis.EndRecord();
                break;
            }
        }
    };

    this.WriteMods = function(mods)
    {
		if(!mods || !mods.Mods)
			return;
        var _count = mods.Mods.length;
        if (0 == _count)
            return;

        oThis.StartRecord(0);
        oThis.WriteULong(_count);

        for (var i = 0; i < _count; ++i)
        {
            oThis.StartRecord(1);

            oThis.WriteUChar(g_nodeAttributeStart);
            oThis._WriteString1(0, mods.Mods[i].name);
            oThis._WriteInt2(1, mods.Mods[i].val);
            oThis.WriteUChar(g_nodeAttributeEnd);

            oThis.EndRecord();
        }

        oThis.EndRecord();
    }

    this.CorrectUniColorAlpha = function(color, trans)
    {
        if(!color)
        {
            return;
        }
        // делаем прозрачность
        if(!color.Mods)
        {
            color.setMods(new AscFormat.CColorModifiers());
        }
        var mods = color.Mods.Mods;
        var _len = mods.length;

        if (trans != null)
        {
            var nIndex = -1;
            for (var i = 0; i < _len; i++)
            {
                if (mods[i].name == "alpha")
                {
                    nIndex = i;
                    break;
                }
            }
            if (-1 != nIndex)
            {
                --_len;
                mods.splice(nIndex, 1);
            }

            mods[_len] = new AscFormat.CColorMod();
            mods[_len].name = "alpha";
            mods[_len].val = (trans * 100000 / 255) >> 0;
        }
    }

    this.WriteUniFill = function(unifill)
    {
        if (undefined === unifill || null == unifill)
            return;

        var trans = ((unifill.transparent != null) && (unifill.transparent != 255)) ? unifill.transparent : null;
        var fill = unifill.fill;
        if (undefined === fill || null == fill)
            return;

        switch (fill.type)
        {
            case c_oAscFill.FILL_TYPE_NOFILL:
            {
                oThis.StartRecord(c_oAscFill.FILL_TYPE_NOFILL);
                oThis.EndRecord();
                break;
            }
            case c_oAscFill.FILL_TYPE_GRP:
            {
                oThis.StartRecord(c_oAscFill.FILL_TYPE_GRP);
                oThis.EndRecord();
                break;
            }
            case c_oAscFill.FILL_TYPE_GRAD:
            {
                oThis.StartRecord(c_oAscFill.FILL_TYPE_GRAD);

                oThis.WriteUChar(g_nodeAttributeStart);

                if (fill.rotateWithShape === false)
                {
                    oThis._WriteBool1(1, false);
                }

                oThis.WriteUChar(g_nodeAttributeEnd);

                oThis.StartRecord(0);

                var len = fill.colors.length;
                oThis.WriteULong(len);

                for (var i = 0; i < len; i++)
                {
                    oThis.StartRecord(0);

                    oThis.WriteUChar(g_nodeAttributeStart);
                    oThis._WriteInt1(0, fill.colors[i].pos);
                    oThis.WriteUChar(g_nodeAttributeEnd);

                    // делаем прозрачность
                    oThis.CorrectUniColorAlpha(fill.colors[i].color, trans);

                    oThis.WriteRecord1(0, fill.colors[i].color, oThis.WriteUniColor);

                    oThis.EndRecord();
                }
                oThis.EndRecord();

                if (fill.lin)
                {
                    oThis.StartRecord(1);
                    oThis.WriteUChar(g_nodeAttributeStart);
                    oThis._WriteInt1(0, fill.lin.angle);
                    oThis._WriteBool1(1, fill.lin.scale);
                    oThis.WriteUChar(g_nodeAttributeEnd);
                    oThis.EndRecord();
                }
                else if (fill.path)
                {
                    oThis.StartRecord(2);
                    oThis.WriteUChar(g_nodeAttributeStart);
                    oThis._WriteUChar1(0, fill.path.path);
                    oThis.WriteUChar(g_nodeAttributeEnd);
                    oThis.EndRecord();
                }

                oThis.EndRecord();
                break;
            }
            case c_oAscFill.FILL_TYPE_PATT:
            {
                oThis.StartRecord(c_oAscFill.FILL_TYPE_PATT);

                oThis.WriteUChar(g_nodeAttributeStart);
                oThis._WriteLimit2(0, fill.ftype);
                oThis.WriteUChar(g_nodeAttributeEnd);

                oThis.CorrectUniColorAlpha(fill.fgClr, trans);
                oThis.CorrectUniColorAlpha(fill.bgClr, trans);

                oThis.WriteRecord2(0, fill.fgClr, oThis.WriteUniColor);
                oThis.WriteRecord2(1, fill.bgClr, oThis.WriteUniColor);

                oThis.EndRecord();
                break;
            }
            case c_oAscFill.FILL_TYPE_BLIP:
            {
                oThis.StartRecord(c_oAscFill.FILL_TYPE_BLIP);

                oThis.WriteUChar(g_nodeAttributeStart);
                oThis.WriteUChar(g_nodeAttributeEnd);
				
                var _src = fill.RasterImageId;
				var imageLocal = AscCommon.g_oDocumentUrls.getImageLocal(_src);
                if(imageLocal)
                    _src = imageLocal;
                else
                    imageLocal = _src;

                oThis.image_map[_src] = true;

                if (window["IsEmbedImagesInInternalFormat"] === true)
                {
                    var _image = editor.ImageLoader.map_image_index[AscCommon.getFullImageSrc2(_src)];
                    if (undefined !== _image)
                    {
                        var imgNatural = _image.Image;

                        var _canvas = document.createElement("canvas");
                        _canvas.width = imgNatural.width;
                        _canvas.height = imgNatural.height;

                        _canvas.getContext("2d").drawImage(imgNatural, 0, 0, _canvas.width, _canvas.height);
                        _src = _canvas.toDataURL("image/png");
                    }
                }
                else if (oThis.IsUseFullUrl)
                {
                    if ((0 == _src.indexOf("theme")) && window.editor)
                    {
                        _src = oThis.PresentationThemesOrigin + _src;
                    }
                    else if (0 != _src.indexOf("http:") && 0 != _src.indexOf("data:") && 0 != _src.indexOf("https:") && 0 != _src.indexOf("ftp:") && 0 != _src.indexOf("file:")){
                        var imageUrl = AscCommon.g_oDocumentUrls.getImageUrl(_src);
						if(imageUrl){
							_src = imageUrl;
						}
					}
                }

                oThis.StartRecord(0);
                oThis.WriteUChar(g_nodeAttributeStart);
                oThis.WriteUChar(g_nodeAttributeEnd);

                if (null != trans)
                {
                    oThis.StartRecord(2);
                    oThis.WriteULong(1);
                    oThis.StartRecord(3);
                    oThis.StartRecord(21);
                    oThis.WriteUChar(g_nodeAttributeStart);
                    oThis._WriteInt1(0, (trans * 100000 / 255) >> 0);
                    oThis.WriteUChar(g_nodeAttributeEnd);
                    oThis.EndRecord();
                    oThis.EndRecord();
                    oThis.EndRecord();
                }

                oThis.StartRecord(3);
                oThis.WriteUChar(g_nodeAttributeStart);
                oThis._WriteString1(0, _src);
                oThis.WriteUChar(g_nodeAttributeEnd);
                oThis.EndRecord();

                oThis.EndRecord();

                if (fill.srcRect != null)
                {
                    oThis.StartRecord(1);
                    oThis.WriteUChar(g_nodeAttributeStart);

                    if (fill.srcRect.l != null)
                    {
                        var _num = (fill.srcRect.l * 1000) >> 0;
                        oThis._WriteString1(0, "" + _num);
                    }
                    if (fill.srcRect.t != null)
                    {
                        var _num = (fill.srcRect.t * 1000) >> 0;
                        oThis._WriteString1(1, "" + _num);
                    }
                    if (fill.srcRect.l != null)
                    {
                        var _num = ((100 - fill.srcRect.r) * 1000) >> 0;
                        oThis._WriteString1(2, "" + _num);
                    }
                    if (fill.srcRect.l != null)
                    {
                        var _num = ((100 - fill.srcRect.b) * 1000) >> 0;
                        oThis._WriteString1(3, "" + _num);
                    }

                    oThis.WriteUChar(g_nodeAttributeEnd);
                    oThis.EndRecord();
                }

                if (null != fill.tile)
                {
                    oThis.StartRecord(2);
                    oThis.WriteUChar(g_nodeAttributeStart);
                    oThis._WriteInt2(0, fill.tile.sx);
                    oThis._WriteInt2(1, fill.tile.sy);
                    oThis._WriteInt2(2, fill.tile.tx);
                    oThis._WriteInt2(3, fill.tile.ty);
                    oThis._WriteLimit2(4, fill.tile.algn);
                    oThis._WriteLimit2(5, fill.tile.flip);
                    oThis.WriteUChar(g_nodeAttributeEnd);
                    oThis.EndRecord();
                }
                else
                {
                    oThis.StartRecord(3);
                    oThis.EndRecord();
                }

                if (oThis.IsUseFullUrl) {
                  var displayN = oThis._isDisplayedImage(imageLocal);
                  if (0 != displayN) {
                      var additionalUrl = AscCommon.g_oDocumentUrls.getImageUrlsWithOtherExtention(imageLocal);
                    oThis.StartRecord(101);
                    oThis.WriteUChar(additionalUrl.length);
                    for (var i = 0; i < additionalUrl.length; ++i) {
                      oThis.WriteString2(additionalUrl[i]);
                    }
                    oThis.EndRecord();
                  }
                }

                oThis.EndRecord();
                break;
            }
            case c_oAscFill.FILL_TYPE_SOLID:
            {
                oThis.StartRecord(c_oAscFill.FILL_TYPE_SOLID);

                if(fill.color){
                    oThis.CorrectUniColorAlpha(fill.color, trans);
                    oThis.WriteRecord1(0, fill.color, oThis.WriteUniColor);
                }
                oThis.EndRecord();
                break;
            }
            default:
                break;
        }
    }
    this._isDisplayedImage = function (strName) {
      var res = 0;
      if (strName) {
        //шаблон display[N]image.ext
        var findStr = "display";
        var index = strName.indexOf(findStr);
        if (-1 != index) {
          if (index + findStr.length < strName.length) {
            var displayN = parseInt(strName[index + findStr.length]);
            if (!isNaN(displayN)) {
              var imageIndex = index + findStr.length + 1;
              if (imageIndex == strName.indexOf("image", imageIndex))
                res = displayN;
            }
          }
        }
      }
      return res;
    }
    this.WriteLn = function(ln)
    {
        if (undefined === ln || null == ln)
            return;

        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteLimit2(0, ln.algn);
        oThis._WriteLimit2(1, ln.cap);
        oThis._WriteLimit2(2, ln.cmpd);
        oThis._WriteInt2(3, ln.w);
        oThis.WriteUChar(g_nodeAttributeEnd);

        oThis.WriteRecord2(0, ln.Fill, oThis.WriteUniFill);
        oThis.WriteRecord2(1, ln.prstDash, oThis.WriteLineDash);
        oThis.WriteRecord1(2, ln.Join, oThis.WriteLineJoin);
        oThis.WriteRecord2(3, ln.headEnd, oThis.WriteLineEnd);
        oThis.WriteRecord2(4, ln.tailEnd, oThis.WriteLineEnd);
    }

    this.WriteLineJoin = function(join)
    {
        if (join == null || join === undefined)
        {
            oThis.WriteUChar(g_nodeAttributeStart);
            oThis._WriteInt1(0, 0);
            oThis.WriteUChar(g_nodeAttributeEnd);
            return;
        }

        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteInt1(0, (join.type != null && join.type !== undefined) ? join.type : 0);
        oThis._WriteInt2(1, join.limit);
        oThis.WriteUChar(g_nodeAttributeEnd);
    }

    this.WriteLineDash = function(dash)
    {
        if (dash == null || dash === undefined)
            return;

        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteLimit2(0, dash);
        oThis.WriteUChar(g_nodeAttributeEnd);
    }

    this.WriteLineEnd = function(end)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteLimit2(0, end.type);
        oThis._WriteLimit2(1, end.w);
        oThis._WriteLimit2(2, end.len);
        oThis.WriteUChar(g_nodeAttributeEnd);
    }
    // fill-stroke ---------------------------------------------------------------

    // text body write ----------------------------------------------------------

    this.WriteTxBody = function(txBody)
    {
        if(txBody.bodyPr)
        {
            oThis.WriteRecord2(0, txBody.bodyPr, oThis.WriteBodyPr);
        }
        if(txBody.lstStyle)
        {
            oThis.WriteRecord2(1, txBody.lstStyle, oThis.WriteTextListStyle);
        }
        var _content = txBody.content.Content;
        oThis.WriteRecordArray(2, 0, _content, oThis.WriteParagraph);
    };

    this.WriteParagraph = function(paragraph, startPos, endPos)
    {
        var tPr = new AscFormat.CTextParagraphPr();
        tPr.bullet = paragraph.Pr.Bullet;
        tPr.lvl = paragraph.Pr.Lvl;
        tPr.pPr = paragraph.Pr;
		tPr.rPr = paragraph.Pr.DefaultRunPr;
        if (tPr.rPr == null)
            tPr.rPr = new CTextPr();

        oThis.WriteRecord1(0, tPr, oThis.WriteTextParagraphPr);
        oThis.WriteRecord2(1, paragraph.TextPr.Value, oThis.WriteRunProperties);

        oThis.StartRecord(2);
        var _position = oThis.pos;
        oThis.WriteULong(0); // temp length
        var _count = 0;

        var _par_content = paragraph.Content;

        if(paragraph.f_id != undefined || paragraph.f_type != undefined || paragraph.f_text!= undefined)
        {
            oThis.StartRecord(0); // subtype
            oThis.WriteParagraphField(paragraph.f_id, paragraph.f_type, paragraph.f_text);
            oThis.EndRecord();

            _count++;
        }

        var _content_len = _par_content.length;
        for (var i = 0; i < _content_len; i++)
        {
            var _elem = _par_content[i];
            switch (_elem.Type)
            {
                case para_Run:
                {
                    var _run_len = _elem.Content.length;
                    var _run_text = "";
                    for (var j = 0; j < _run_len; j++)
                    {
                        switch (_elem.Content[j].Type)
                        {
                            case para_Text:
                            {
                                _run_text += AscCommon.encodeSurrogateChar(_elem.Content[j].Value);
                                break;
                            }
                            case para_Space :
                            {
                                _run_text += ' ';
                                break;
                            }
                            case para_Tab :
                            {
                                _run_text += '\t';
                                break;
                            }
                            case para_NewLine :
                            {
                                if("" != _run_text)
                                {
                                    oThis.StartRecord(0); // subtype
                                    oThis.WriteTextRun(_elem.Pr, _run_text, null);
                                    oThis.EndRecord();

                                    _count++;

                                    _run_text = "";
                                }
                                oThis.StartRecord(0); // subtype
                                oThis.WriteLineBreak(_elem.Pr, null);
                                oThis.EndRecord();

                                _count++;

                                break;
                            }
                        }
                    }

                    if ("" != _run_text)
                    {
                        oThis.StartRecord(0); // subtype
                        oThis.WriteTextRun(_elem.Pr, _run_text, null);
                        oThis.EndRecord();

                        _count++;
                    }
                    break;
                }
                case para_Hyperlink:
                {
                    var _hObj = { Value : _elem.GetValue(), tooltip: _elem.GetToolTip()};
                    var _content_len_h = _elem.Content.length;

                    for (var hi = 0; hi < _content_len_h; hi++)
                    {
                        var _elem_h = _elem.Content[hi];
                        switch (_elem_h.Type)
                        {
                            case para_Run:
                            {
                                var _run_len = _elem_h.Content.length;
                                var _run_text = "";
                                for (var j = 0; j < _run_len; j++)
                                {
                                    switch (_elem_h.Content[j].Type)
                                    {
                                        case para_Text:
                                        {
                                            _run_text += AscCommon.encodeSurrogateChar(_elem_h.Content[j].Value);
                                            break;
                                        }
                                        case para_Space :
                                        {
                                            _run_text += ' ';
                                            break;
                                        }
                                        case para_Tab :
                                        {
                                            _run_text += '\t';
                                            break;
                                        }
                                        case para_NewLine :
                                        {
                                            if("" != _run_text)
                                            {
                                                oThis.StartRecord(0); // subtype
                                                oThis.WriteTextRun(_elem_h.Pr, _run_text, _hObj);
                                                oThis.EndRecord();

                                                _count++;

                                                _run_text = "";
                                            }
                                            oThis.StartRecord(0); // subtype
                                            oThis.WriteLineBreak(_elem_h.Pr, _hObj);
                                            oThis.EndRecord();

                                            _count++;

                                            break;
                                        }
                                    }
                                }

                                if ("" != _run_text)
                                {
                                    oThis.StartRecord(0); // subtype
                                    oThis.WriteTextRun(_elem.Content[0].Pr, _run_text, _hObj);
                                    oThis.EndRecord();

                                    _count++;
                                }
                                break;
                            }
                            case para_Math:
                            {
                                if (null != _elem_h.Root)
                                {
                                    oThis.StartRecord(0); // subtype
                                    oThis.StartRecord(AscFormat.PARRUN_TYPE_MATHPARA);
                                    var _memory = new AscCommon.CMemory(true);
                                    _memory.ImData = oThis.ImData;
                                    _memory.data = oThis.data;
                                    _memory.len = oThis.len;
                                    _memory.pos = oThis.pos;
                                    oThis.UseContinueWriter = true;

                                    if (!oThis.DocSaveParams) {
                                        oThis.DocSaveParams = new AscCommonWord.DocSaveParams(false, false);
                                    }
                                    var boMaths = new Binary_oMathWriter(_memory, null, oThis.DocSaveParams);
                                    boMaths.bs.WriteItemWithLength(function(){boMaths.WriteOMathPara(_elem_h)});

                                    oThis.ImData = _memory.ImData;
                                    oThis.data = _memory.data;
                                    oThis.len = _memory.len;
                                    oThis.pos = _memory.pos;
                                    oThis.UseContinueWriter = false;

                                    _memory.ImData = null;
                                    _memory.data = null;

                                    oThis.EndRecord();
                                    oThis.EndRecord();
                                    _count++;
                                }
                            }
                            default:
                                break;
                        }
                    }

                    break;
                }
				case para_Math:
				{
					if (null != _elem.Root)
					{
						oThis.StartRecord(0); // subtype
						oThis.StartRecord(AscFormat.PARRUN_TYPE_MATHPARA);
						var _memory = new AscCommon.CMemory(true);
						_memory.ImData = oThis.ImData;
						_memory.data = oThis.data;
						_memory.len = oThis.len;
						_memory.pos = oThis.pos;
						oThis.UseContinueWriter = true;

						if (!oThis.DocSaveParams) {
							oThis.DocSaveParams = new AscCommonWord.DocSaveParams(false, false);
						}
						var boMaths = new Binary_oMathWriter(_memory, null, oThis.DocSaveParams);
						boMaths.bs.WriteItemWithLength(function(){boMaths.WriteOMathPara(_elem)});	

						oThis.ImData = _memory.ImData;
						oThis.data = _memory.data;
						oThis.len = _memory.len;
						oThis.pos = _memory.pos;
						oThis.UseContinueWriter = false;

						_memory.ImData = null;
						_memory.data = null;
						
						oThis.EndRecord();
						oThis.EndRecord();
						_count++;
					}
				}
                default:
                    break;
            }
        }

        var _new_pos = oThis.pos;
        oThis.pos = _position;
        oThis.WriteULong(_count);
        oThis.pos = _new_pos;

        oThis.EndRecord();
    };

    this.WriteParagraphField = function (id, type, text)
    {
        oThis.StartRecord(AscFormat.PARRUN_TYPE_FLD);

        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteString1(0, id);
        oThis._WriteString2(1, type);
        oThis._WriteString2(2, text);
        oThis.WriteUChar(g_nodeAttributeEnd);

        // rPr & pPr

        oThis.EndRecord();
    };

    this.WriteTextRun = function(runPr, text, hlinkObj)
    {
        oThis.StartRecord(AscFormat.PARRUN_TYPE_RUN);

        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteString2(0, text);
        oThis.WriteUChar(g_nodeAttributeEnd);

        if (runPr !== undefined && runPr != null)
        {
            oThis.StartRecord(0);
            oThis.WriteRunProperties(runPr, hlinkObj);
            oThis.EndRecord();
        }

        oThis.EndRecord();
    };
    this.WriteLineBreak = function(runPr, hlinkObj)
    {
        oThis.StartRecord(AscFormat.PARRUN_TYPE_BR);

        if (runPr !== undefined && runPr != null)
        {
            oThis.StartRecord(0);
            oThis.WriteRunProperties(runPr, hlinkObj);
            oThis.EndRecord();
        }

        oThis.EndRecord();
    };

    // text body write ----------------------------------------------------------

    // objects ------------------------------------------------------------------
    this.WriteShapeStyle = function(style)
    {
        oThis.WriteRecord1(0, style.lnRef, oThis.WriteStyleRef);
        oThis.WriteRecord1(1, style.fillRef, oThis.WriteStyleRef);
        oThis.WriteRecord1(2, style.effectRef, oThis.WriteStyleRef);
        oThis.WriteRecord1(3, style.fontRef, oThis.WriteFontRef);
    }

    this.WriteStyleRef = function(ref)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteInt2(0, ref.idx);
        oThis.WriteUChar(g_nodeAttributeEnd);

        oThis.WriteRecord1(0, ref.Color, oThis.WriteUniColor);
    }

    this.WriteFontRef = function(ref)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteUChar2(0, ref.idx);
        oThis.WriteUChar(g_nodeAttributeEnd);

        oThis.WriteRecord1(0, ref.Color, oThis.WriteUniColor);
    }

    this.WriteBg = function(bg)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteLimit2(0, bg.bwMode);
        oThis.WriteUChar(g_nodeAttributeEnd);

        oThis.WriteRecord2(0, bg.bgPr, oThis.WriteBgPr);
        oThis.WriteRecord2(1, bg.bgRef, oThis.WriteStyleRef);
    }
    this.WriteBgPr = function(bgPr)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteBool2(0, bgPr.shadeToTitle);
        oThis.WriteUChar(g_nodeAttributeEnd);

        oThis.WriteRecord1(0, bgPr.Fill, oThis.WriteUniFill);
    }

    this.WriteShape = function(shape)
    {
        if(shape.getObjectType() === AscDFH.historyitem_type_Cnx){
            oThis.StartRecord(3);
        }
        else{
            oThis.StartRecord(1);
            oThis.WriteUChar(g_nodeAttributeStart);
            oThis._WriteBool2(0, shape.attrUseBgFill);
            oThis.WriteUChar(g_nodeAttributeEnd);
        }



        shape.spPr.WriteXfrm = shape.spPr.xfrm;

        var tmpFill = shape.spPr.Fill;
        var isUseTmpFill = false;
        if (tmpFill !== undefined && tmpFill != null)
        {
            var trans = ((tmpFill.transparent != null) && (tmpFill.transparent != 255)) ? tmpFill.transparent : null;
            if (trans != null)
            {
                if (tmpFill.fill === undefined || tmpFill.fill == null)
                {
                    isUseTmpFill = true;
                    shape.spPr.Fill = shape.brush;
                }
            }
        }
        var nvSpPr;
        if(shape.nvSpPr)
        {
            nvSpPr = shape.nvSpPr;
        }
        else
        {
            nvSpPr = {};
        }
        nvSpPr.locks = shape.locks;
        nvSpPr.objectType = shape.getObjectType();
        if(nvSpPr.cNvPr){
            nvSpPr.cNvPr.shapeId = shape.Id;
        }
        oThis.WriteRecord2(0, nvSpPr, oThis.WriteUniNvPr);

        oThis.WriteRecord1(1, shape.spPr, oThis.WriteSpPr);
        oThis.WriteRecord2(2, shape.style, oThis.WriteShapeStyle);
        oThis.WriteRecord2(3, shape.txBody, oThis.WriteTxBody);

        if (isUseTmpFill)
        {
            shape.spPr.Fill = tmpFill;
        }

        shape.spPr.WriteXfrm = null;

        oThis.EndRecord();
    }

    this.WriteImage = function(image)
    {
        var isOle = AscDFH.historyitem_type_OleObject == image.getObjectType();
        if(isOle){
            oThis.StartRecord(6);
            //важно писать в начале
            oThis.WriteRecord1(4, image, oThis.WriteOleInfo);
        } else {
            var _type;
            var bMedia = false, _fileMask;
            if(image.nvPicPr && image.nvPicPr.nvPr && image.nvPicPr.nvPr.unimedia && image.nvPicPr.nvPr.unimedia.type !== null
                && typeof image.nvPicPr.nvPr.unimedia.media === "string" && image.nvPicPr.nvPr.unimedia.media.length > 0){
                _type = image.nvPicPr.nvPr.unimedia.type;
                _fileMask = image.nvPicPr.nvPr.unimedia.media;
                bMedia = true;
            }
            else{
                _type = 2;
            }
            oThis.StartRecord(_type);
            if(bMedia){
                oThis.WriteRecord1(5, null, function(){
                    oThis.WriteUChar(g_nodeAttributeStart);
                    oThis._WriteString1(0, _fileMask);
                    oThis.WriteUChar(g_nodeAttributeEnd);
                });
            }

        }


        var nvPicPr;
        if(image.nvPicPr)
        {
            nvPicPr = image.nvPicPr;
        }
        else
        {
            nvPicPr = {};
        }
        nvPicPr.locks = image.locks;
        nvPicPr.objectType = image.getObjectType();
        if(nvPicPr.cNvPr){
            nvPicPr.cNvPr.shapeId = image.Id;
        }

        oThis.WriteRecord1(0, nvPicPr, this.WriteUniNvPr);

        image.spPr.WriteXfrm = image.spPr.xfrm;

        var bSetGeometry = false;
        if (image.spPr.geometry === undefined || image.spPr.geometry == null)
        {
            // powerpoint!
            bSetGeometry = true;
            image.spPr.geometry = AscFormat.ExecuteNoHistory(function(){return AscFormat.CreateGeometry("rect");}, this, []);
        }

        var unifill = new AscFormat.CUniFill();
        unifill.fill = image.blipFill
        oThis.WriteRecord1(1, unifill, oThis.WriteUniFill);
        oThis.WriteRecord1(2, image.spPr, oThis.WriteSpPr);
        if(bSetGeometry){
            image.spPr.geometry = null;
        }
        oThis.WriteRecord2(3, image.style, oThis.WriteShapeStyle);

        image.spPr.WriteXfrm = null;

        oThis.EndRecord();
    }
    this.WriteOleInfo = function(ole)
    {
		var ratio = 20 * 3 / 4;//px to twips
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteString2(0, ole.m_sApplicationId);
        oThis._WriteString2(1, ole.m_sData);
        oThis._WriteInt2(2, ratio * ole.m_nPixWidth);
        oThis._WriteInt2(3, ratio * ole.m_nPixHeight);
        oThis._WriteUChar2(4, 0);
        oThis._WriteUChar2(5, 0);
        oThis._WriteString2(7, ole.m_sObjectFile);
        oThis.WriteUChar(g_nodeAttributeEnd);
    }
    this.WriteTable = function(grObj)
    {
        oThis.StartRecord(5);

        oThis.WriteUChar(g_nodeAttributeStart);
        oThis.WriteUChar(g_nodeAttributeEnd);


        var nvGraphicFramePr;
        if(grObj.nvGraphicFramePr)
        {
            nvGraphicFramePr = grObj.nvGraphicFramePr;
        }
        else
        {
            nvGraphicFramePr = {};
        }
        nvGraphicFramePr.locks = grObj.locks;
        nvGraphicFramePr.objectType = grObj.getObjectType();
        if(nvGraphicFramePr.cNvPr){
            nvGraphicFramePr.cNvPr.shapeId = grObj.Id;
        }

        oThis.WriteRecord1(0, nvGraphicFramePr, oThis.WriteUniNvPr);

        if (grObj.spPr.xfrm && grObj.spPr.xfrm.isNotNull())
            oThis.WriteRecord2(1, grObj.spPr.xfrm, oThis.WriteXfrm);

        oThis.WriteRecord2(2, grObj.graphicObject, oThis.WriteTable2);

        oThis.EndRecord();
    }

    this.WriteChart = function(grObj)
    {
        oThis.StartRecord(5);

        oThis.WriteUChar(g_nodeAttributeStart);
        oThis.WriteUChar(g_nodeAttributeEnd);
        var nvGraphicFramePr  = {};
        if(grObj.nvGraphicFramePr)
        {
            nvGraphicFramePr = grObj.nvGraphicFramePr;
        }
        else
        {
            nvGraphicFramePr = {};
        }

        nvGraphicFramePr.locks = grObj.locks;
        nvGraphicFramePr.objectType = grObj.getObjectType();
        if(nvGraphicFramePr.cNvPr){
            nvGraphicFramePr.cNvPr.shapeId = grObj.Id;
        }

        oThis.WriteRecord1(0, nvGraphicFramePr, oThis.WriteUniNvPr);

        if (grObj.spPr && grObj.spPr.xfrm && grObj.spPr.xfrm.isNotNull())
            oThis.WriteRecord2(1, grObj.spPr.xfrm, oThis.WriteXfrm);

        oThis.WriteRecord2(3, grObj, oThis.WriteChart2);

        oThis.EndRecord();
    }

    this.WriteChart2 = function(grObj)
    {
        var _memory = new AscCommon.CMemory(true);
        _memory.ImData = oThis.ImData;
        _memory.data = oThis.data;
        _memory.len = oThis.len;
        _memory.pos = oThis.pos;

        oThis.UseContinueWriter = true;

        var oBinaryChartWriter = new AscCommon.BinaryChartWriter(_memory);
        oBinaryChartWriter.WriteCT_ChartSpace(grObj);

        oThis.ImData = _memory.ImData;
        oThis.data = _memory.data;
        oThis.len = _memory.len;
        oThis.pos = _memory.pos;

        oThis.UseContinueWriter = false;

        _memory.ImData = null;
        _memory.data = null;
    }

    this.WriteTable2 = function(table)
    {
        var obj = {};
        obj.props = table.Pr;
        obj.look = table.TableLook;
        obj.style = table.TableStyle;

        oThis.WriteRecord1(0, obj, oThis.WriteTableProps);

        var grid = table.TableGrid;
        var _len = grid.length;

        oThis.StartRecord(1);
        oThis.WriteULong(_len);
        for (var i = 0; i < _len; i++)
        {
            oThis.StartRecord(0);
            oThis.WriteUChar(g_nodeAttributeStart);
            oThis._WriteInt1(0, (grid[i] * 36000) >> 0);
            oThis.WriteUChar(g_nodeAttributeEnd);
            oThis.EndRecord();
        }
        oThis.EndRecord();

        oThis.StartRecord(2);
        var rows_c = table.Content.length;
        oThis.WriteULong(rows_c);

        var _grid = oThis.GenerateTableWriteGrid(table);
        for (var i = 0; i < rows_c; i++)
        {
            oThis.StartRecord(0);
            oThis.WriteTableRow(table.Content[i], _grid.Rows[i]);
            oThis.EndRecord();
        }

        oThis.EndRecord();
    }

    this.GenerateTableWriteGrid = function(table)
    {
        var TableGrid = {};

        var _rows = table.Content;
        var _cols = table.TableGrid;

        var _cols_count = _cols.length;
        var _rows_count = _rows.length;

        TableGrid.Rows = new Array(_rows_count);

        for (var i = 0; i < _rows_count; i++)
        {
            TableGrid.Rows[i] = {};
            TableGrid.Rows[i].Cells = [];

            var _index = 0;
            var _cells_len = _rows[i].Content.length;
            for (var j = 0; j < _cells_len; j++)
            {
                var _cell = _rows[i].Content[j];

                var _cell_info = {};
                _cell_info.Cell = _cell;
                _cell_info.row_span = 1;
                _cell_info.grid_span = (_cell.Pr.GridSpan === undefined || _cell.Pr.GridSpan == null) ? 1 : _cell.Pr.GridSpan;
                _cell_info.hMerge = false;
                _cell_info.vMerge = false;
                _cell_info.isEmpty = false;

                if (_cell.Pr.VMerge == vmerge_Continue)
                    _cell_info.vMerge = true;

                TableGrid.Rows[i].Cells.push(_cell_info);
                if (_cell_info.grid_span > 1)
                {
                    for (var t = _cell_info.grid_span - 1; t > 0; t--)
                    {
                        var _cell_info_empty = {};
                        _cell_info_empty.isEmpty = true;
                        _cell_info_empty.vMerge = _cell_info.vMerge;

                        TableGrid.Rows[i].Cells.push(_cell_info_empty);
                    }
                }
            }
        }

        for (var i = 0; i < _cols_count; i++)
        {
            var _index = 0;
            while (_index < _rows_count)
            {
                var _count = 1;
                for (var j = _index + 1; j < _rows_count; j++)
                {
                    if (i >= TableGrid.Rows[j].Cells.length)
                        continue;

                    if (TableGrid.Rows[j].Cells[i].vMerge !== true)
                        break;

                    ++_count;
                }

                if (i < TableGrid.Rows[_index].Cells.length)
                    TableGrid.Rows[_index].Cells[i].row_span = _count;

                _index += _count;
            }
        }

        return TableGrid;
    }

    this.WriteEmptyTableCell = function(_info)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteBool1(3, true);

        if (true == _info.vMerge)
            oThis._WriteBool1(4, true);

        oThis.WriteUChar(g_nodeAttributeEnd);

        oThis.StartRecord(1);

        oThis.StartRecord(0);
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis.WriteUChar(g_nodeAttributeEnd);
        oThis.EndRecord();

        oThis.StartRecord(2); // paragrs
        oThis.WriteULong(1);  // count
        oThis.StartRecord(0); // par_type
        oThis.StartRecord(1); // endpr
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis.WriteUChar(g_nodeAttributeEnd);
        oThis.EndRecord();
        oThis.EndRecord();
        oThis.EndRecord();

        oThis.EndRecord();
    }

    this.WriteTableRow = function(row, row_info)
    {
        oThis.WriteUChar(g_nodeAttributeStart);

        if (row.Pr.Height !== undefined && row.Pr.Height != null){
			var fMaxTopMargin = 0, fMaxBottomMargin = 0, fMaxTopBorder = 0, fMaxBottomBorder = 0;
			for(i = 0;  i < row.Content.length; ++i){
				var oCell = row.Content[i];
				var oMargins = oCell.GetMargins();
				if(oMargins.Bottom.W > fMaxBottomMargin){
					fMaxBottomMargin = oMargins.Bottom.W;
				}
				if(oMargins.Top.W > fMaxTopMargin){
					fMaxTopMargin = oMargins.Top.W;
				}
				var oBorders = oCell.Get_Borders();
				if(oBorders.Top.Size > fMaxTopBorder){
					fMaxTopBorder = oBorders.Top.Size;
				}
				if(oBorders.Bottom.Size > fMaxBottomBorder){
					fMaxBottomBorder = oBorders.Bottom.Size;
				}
			}
            oThis._WriteInt1(0, ( (row.Pr.Height.Value + fMaxBottomMargin + fMaxTopMargin + fMaxTopBorder/2 + fMaxBottomBorder/2) * 36000) >> 0);
		}
        
        oThis.WriteUChar(g_nodeAttributeEnd);

        oThis.StartRecord(0);
        var _len = row_info.Cells.length;
        oThis.WriteULong(_len);

        for (var i = 0; i < _len; i++)
        {
            oThis.StartRecord(1);

            var _info = row_info.Cells[i];
            if (_info.isEmpty)
            {
                oThis.WriteEmptyTableCell(_info);
            }
            else
            {
                oThis.WriteUChar(g_nodeAttributeStart);

                if (_info.vMerge === false && _info.row_span > 1)
                {
                    oThis._WriteInt1(1, _info.row_span);
                }
                if (_info.hMerge === false && _info.grid_span > 1)
                {
                    oThis._WriteInt1(2, _info.grid_span);
                }
                if (_info.hMerge === true)
                {
                    oThis._WriteBool1(3, true);
                }
                if (_info.vMerge === true)
                {
                    oThis._WriteBool1(4, true);
                }

                oThis.WriteUChar(g_nodeAttributeEnd);

                oThis.WriteTableCell(_info.Cell);
            }

            oThis.EndRecord();
        }

        oThis.EndRecord();
    }

    this.WriteTableCell = function(cell)
    {
        oThis.StartRecord(0);

        oThis.WriteUChar(g_nodeAttributeStart);

        var _marg = cell.Pr.TableCellMar;
        var tableMar = cell.Row.Table.Pr.TableCellMar;

        if(_marg && _marg.Left && AscFormat.isRealNumber(_marg.Left.W))
        {
            oThis._WriteInt1(0, (_marg.Left.W * 36000) >> 0);
        }
        else if(tableMar && tableMar.Left && AscFormat.isRealNumber(tableMar.Left.W))
        {
            oThis._WriteInt1(0, (tableMar.Left.W * 36000) >> 0);
        }

        if(_marg && _marg.Top && AscFormat.isRealNumber(_marg.Top.W))
        {
            oThis._WriteInt1(1, (_marg.Top.W * 36000) >> 0);
        }
        else if(tableMar && tableMar.Top && AscFormat.isRealNumber(tableMar.Top.W))
        {
            oThis._WriteInt1(1, (tableMar.Top.W * 36000) >> 0);
        }

        if(_marg && _marg.Right && AscFormat.isRealNumber(_marg.Right.W))
        {
            oThis._WriteInt1(2, (_marg.Right.W * 36000) >> 0);
        }
        else if(tableMar && tableMar.Right && AscFormat.isRealNumber(tableMar.Right.W))
        {
            oThis._WriteInt1(2, (tableMar.Right.W * 36000) >> 0);
        }

        if(_marg && _marg.Bottom && AscFormat.isRealNumber(_marg.Bottom.W))
        {
            oThis._WriteInt1(3, (_marg.Bottom.W * 36000) >> 0);
        }
        else if(tableMar && tableMar.Bottom && AscFormat.isRealNumber(tableMar.Bottom.W))
        {
            oThis._WriteInt1(3, (tableMar.Bottom.W * 36000) >> 0);
        }


        if(AscFormat.isRealNumber(cell.Pr.TextDirection))
        {
            switch (cell.Pr.TextDirection)
            {
                case Asc.c_oAscCellTextDirection.LRTB:
                {

                    oThis._WriteUChar1(5, 1);
                    break;
                }
                case Asc.c_oAscCellTextDirection.TBRL:
                {

                    oThis._WriteUChar1(5, 0);
                    break;
                }
                case Asc.c_oAscCellTextDirection.BTLR:
                {

                    oThis._WriteUChar1(5, 4);
                    break;
                }
                default:
                {
                    oThis._WriteUChar1(5, 1);
                    break;
                }
            }
        }
        if(AscFormat.isRealNumber(cell.Pr.VAlign))
        {
            switch(cell.Pr.VAlign)
            {
                case vertalignjc_Bottom:
                {
                    oThis._WriteUChar1(6, 0);
                    break;
                }
                case vertalignjc_Center:
                {
                    oThis._WriteUChar1(6, 1);
                    break;
                }
                case vertalignjc_Top:
                {
                    oThis._WriteUChar1(6, 4);
                    break;
                }
            }
        }


        oThis.WriteUChar(g_nodeAttributeEnd);

        oThis.WriteRecord3(0, cell.Pr.TableCellBorders.Left, oThis.WriteTableCellBorder);
        oThis.WriteRecord3(1, cell.Pr.TableCellBorders.Top, oThis.WriteTableCellBorder);
        oThis.WriteRecord3(2, cell.Pr.TableCellBorders.Right, oThis.WriteTableCellBorder);
        oThis.WriteRecord3(3, cell.Pr.TableCellBorders.Bottom, oThis.WriteTableCellBorder);

        var shd = cell.Pr.Shd;
        if (shd !== undefined && shd != null)
        {
            oThis.WriteRecord2(6, shd.Unifill, oThis.WriteUniFill);
        }

        oThis.EndRecord();

        oThis.StartRecord(1);
        oThis.WriteRecordArray(2, 0, cell.Content.Content, oThis.WriteParagraph);
        oThis.EndRecord();
    }

    this.WriteTableProps = function(obj)
    {
        oThis.WriteUChar(g_nodeAttributeStart);

        if(oThis.tableStylesGuides.hasOwnProperty(obj.style))
        {
            oThis._WriteString1(0, oThis.tableStylesGuides[obj.style]);
        }
        oThis._WriteBool1(2, obj.look.m_bFirst_Row);
        oThis._WriteBool1(3, obj.look.m_bFirst_Col);
        oThis._WriteBool1(4, obj.look.m_bLast_Row);
        oThis._WriteBool1(5, obj.look.m_bLast_Col);
        oThis._WriteBool1(6, obj.look.m_bBand_Hor);
        oThis._WriteBool1(7, obj.look.m_bBand_Ver);

        oThis.WriteUChar(g_nodeAttributeEnd);

        var shd = obj.props.Shd;
        if (shd !== undefined && shd != null)
        {
            if (shd.Unifill !== undefined && shd.Unifill != null)
            {
                if (shd.Unifill.fill !== undefined && shd.Unifill.fill != null)
                {
                    oThis.WriteRecord1(0, shd.Unifill, oThis.WriteUniFill);
                }
            }
        }
    }

    this.WriteGroupShape = function(group)
    {
        oThis.StartRecord(4);

        group.spPr.WriteXfrm = group.spPr.xfrm;
        if(group.nvGrpSpPr)
        {
            var _old_ph = group.nvGrpSpPr.nvPr.ph;
            group.nvGrpSpPr.nvPr.ph = null;
            group.nvGrpSpPr.locks = group.locks;
            group.nvGrpSpPr.objectType = group.getObjectType();
            group.nvGrpSpPr.cNvPr.shapeId = group.Id;
            oThis.WriteRecord1(0, group.nvGrpSpPr, oThis.WriteUniNvPr);
            group.nvGrpSpPr.nvPr.ph = _old_ph;
        }
        oThis.WriteRecord1(1, group.spPr, oThis.WriteGrpSpPr);

        group.spPr.WriteXfrm = null;

        var spTree = group.spTree;
        var _len = spTree.length;
        if (0 != _len)
        {
            oThis.StartRecord(2);
            oThis.WriteULong(_len);

            for (var i = 0; i < _len; i++)
            {
                oThis.StartRecord(0);

				switch(spTree[i].getObjectType())
                {
                    case AscDFH.historyitem_type_Shape:
                    case AscDFH.historyitem_type_Cnx:
                    {
						oThis.WriteShape(spTree[i]);
                        break;
                    }
                    case AscDFH.historyitem_type_OleObject:
                    case AscDFH.historyitem_type_ImageShape:
                    {
                        oThis.WriteImage(spTree[i]);
                        break;
                    }
                    case AscDFH.historyitem_type_GroupShape:
                    {
                        oThis.WriteGroupShape(spTree[i]);
                        break;
                    }
                    case AscDFH.historyitem_type_ChartSpace:
                    {
                        oThis.WriteChart(spTree[i]);
                        break;
                    }
					default:
					{
						if (spTree[i] instanceof AscFormat.CGraphicFrame && spTree[i].graphicObject instanceof CTable)
						{
							oThis.WriteTable(spTree[i]);
						}
					}
                }
				
                oThis.EndRecord(0);
            }

            oThis.EndRecord();
        }

        oThis.EndRecord();
    }

    this.WriteGrpSpPr = function(grpSpPr)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteLimit2(0, grpSpPr.bwMode);
        oThis.WriteUChar(g_nodeAttributeEnd);

        if (grpSpPr.WriteXfrm && grpSpPr.WriteXfrm.isNotNull())
            oThis.WriteRecord2(0, grpSpPr.WriteXfrm, oThis.WriteXfrm);
        oThis.WriteRecord1(1, grpSpPr.Fill, oThis.WriteUniFill);
    }

    this.WriteSpPr = function(spPr)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteLimit2(0, spPr.bwMode);
        oThis.WriteUChar(g_nodeAttributeEnd);

        var _fill = spPr.Fill;
        var bIsExistFill = false;
        if (_fill !== undefined && _fill != null && _fill.fill !== undefined && _fill.fill != null)
            bIsExistFill = true;

        var bIsExistLn = false;
        if (spPr.ln !== undefined && spPr.ln != null)
        {
            _fill = spPr.ln.Fill;
            if (_fill !== undefined && _fill != null && _fill.fill !== undefined && _fill.fill != null)
                bIsExistLn = true;
        }

        if (spPr.xfrm && spPr.xfrm.isNotNull())
            oThis.WriteRecord2(0, spPr.xfrm, oThis.WriteXfrm);

        oThis.WriteRecord2(1, spPr.geometry, oThis.WriteGeometry);

        if (spPr.geometry === undefined || spPr.geometry == null)
        {
            if (bIsExistFill || bIsExistLn)
            {
                oThis.StartRecord(1);

                oThis.StartRecord(1);
                oThis.WriteUChar(g_nodeAttributeStart);
                oThis._WriteString1(0, "rect");
                oThis.WriteUChar(g_nodeAttributeEnd);
                oThis.EndRecord();

                oThis.EndRecord();
            }
        }

        oThis.WriteRecord1(2, spPr.Fill, oThis.WriteUniFill);
        oThis.WriteRecord2(3, spPr.ln, oThis.WriteLn);
    }

    this.WriteXfrm = function(xfrm)
    {
        if (oThis.IsWordWriter === true)
            return oThis.WriteXfrmRot(xfrm);

        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteInt4(0, xfrm.offX, c_dScalePPTXSizes);
        oThis._WriteInt4(1, xfrm.offY, c_dScalePPTXSizes);
        oThis._WriteInt4(2, xfrm.extX, c_dScalePPTXSizes);
        oThis._WriteInt4(3, xfrm.extY, c_dScalePPTXSizes);
        oThis._WriteInt4(4, xfrm.chOffX, c_dScalePPTXSizes);
        oThis._WriteInt4(5, xfrm.chOffY, c_dScalePPTXSizes);
        oThis._WriteInt4(6, xfrm.chExtX, c_dScalePPTXSizes);
        oThis._WriteInt4(7, xfrm.chExtY, c_dScalePPTXSizes);
        oThis._WriteBool2(8, xfrm.flipH);
        oThis._WriteBool2(9, xfrm.flipV);
        oThis._WriteInt4(10, xfrm.rot, 180 * 60000 / Math.PI);
        oThis.WriteUChar(g_nodeAttributeEnd);
    }

	this.WriteSignatureLine = function(oSignatureLine)
	{
		oThis.WriteUChar(g_nodeAttributeStart);
		oThis._WriteUChar2(2, 1);
		oThis._WriteString2(3, oSignatureLine.id);
		oThis._WriteBool2(4, true);
		oThis._WriteString2(5, "{00000000-0000-0000-0000-000000000000}");
		oThis._WriteString2(10, oSignatureLine.signer);
		oThis._WriteString2(11, oSignatureLine.signer2);
		oThis._WriteString2(12, oSignatureLine.email);
		oThis.WriteUChar(g_nodeAttributeEnd);
	}

    this.WriteXfrmRot = function(xfrm)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteInt4(0, xfrm.offX, c_dScalePPTXSizes);
        oThis._WriteInt4(1, xfrm.offY, c_dScalePPTXSizes);
        oThis._WriteInt4(2, xfrm.extX, c_dScalePPTXSizes);
        oThis._WriteInt4(3, xfrm.extY, c_dScalePPTXSizes);
        oThis._WriteInt4(4, xfrm.chOffX, c_dScalePPTXSizes);
        oThis._WriteInt4(5, xfrm.chOffY, c_dScalePPTXSizes);
        oThis._WriteInt4(6, xfrm.chExtX, c_dScalePPTXSizes);
        oThis._WriteInt4(7, xfrm.chExtY, c_dScalePPTXSizes);
        oThis._WriteBool2(8, xfrm.flipH);
        oThis._WriteBool2(9, xfrm.flipV);

        if (xfrm.rot != null)
        {
            var nCheckInvert = 0;
            if (true == xfrm.flipH)
                nCheckInvert += 1;
            if (true == xfrm.flipV)
                nCheckInvert += 1;

            var _rot = (xfrm.rot * 180 * 60000 / Math.PI) >> 0;
            var _n360 = 360 * 60000;

            if (_rot > _n360)
            {
                var _nDel = (_rot / _n360) >> 0;
                _rot = _rot - _nDel * _n360;
            }
            else if (_rot < 0)
            {
                var _nDel = (-_rot / _n360) >> 0;
                _nDel += 1;
                _rot = _rot + _nDel * _n360;
            }

            if (nCheckInvert == 1)
            {
                _rot = _n360 - _rot;
            }
            oThis._WriteInt1(10, _rot);
        }

        oThis.WriteUChar(g_nodeAttributeEnd);
    }

    this.WriteSpCNvPr = function (locks) {
        oThis.WriteUChar(g_nodeAttributeStart);
        if(locks & AscFormat.LOCKS_MASKS.noAdjustHandles)
            oThis._WriteBool2(1, !!(locks & AscFormat.LOCKS_MASKS.noAdjustHandles << 1));
        if(locks & AscFormat.LOCKS_MASKS.noChangeArrowheads)
            oThis._WriteBool2(2, !!(locks & (AscFormat.LOCKS_MASKS.noChangeArrowheads << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noChangeAspect)
            oThis._WriteBool2(3, !!(locks & (AscFormat.LOCKS_MASKS.noChangeAspect << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noChangeShapeType)
            oThis._WriteBool2(4, !!(locks & (AscFormat.LOCKS_MASKS.noChangeShapeType << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noEditPoints)
            oThis._WriteBool2(5, !!(locks & (AscFormat.LOCKS_MASKS.noEditPoints << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noGrp)
            oThis._WriteBool2(6, !!(locks & (AscFormat.LOCKS_MASKS.noGrp << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noMove)
            oThis._WriteBool2(7, !!(locks & (AscFormat.LOCKS_MASKS.noMove << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noResize)
            oThis._WriteBool2(8, !!(locks & (AscFormat.LOCKS_MASKS.noResize << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noRot)
            oThis._WriteBool2(9, !!(locks & (AscFormat.LOCKS_MASKS.noRot << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noSelect)
            oThis._WriteBool2(10, !!(locks & (AscFormat.LOCKS_MASKS.noSelect << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noTextEdit)
            oThis._WriteBool2(11, !!(locks & (AscFormat.LOCKS_MASKS.noTextEdit << 1)));
        oThis.WriteUChar(g_nodeAttributeEnd);
    };

    this.WritePicCNvPr = function (locks) {
        oThis.WriteUChar(g_nodeAttributeStart);
        if(locks & AscFormat.LOCKS_MASKS.noAdjustHandles)
            oThis._WriteBool2(1,  !!(locks & (AscFormat.LOCKS_MASKS.noAdjustHandles << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noChangeArrowheads)
            oThis._WriteBool2(2,  !!(locks & (AscFormat.LOCKS_MASKS.noChangeArrowheads << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noChangeAspect)
            oThis._WriteBool2(3,  !!(locks & (AscFormat.LOCKS_MASKS.noChangeAspect << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noChangeShapeType)
            oThis._WriteBool2(4,  !!(locks & (AscFormat.LOCKS_MASKS.noChangeShapeType << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noCrop)
            oThis._WriteBool2(5,  !!(locks & (AscFormat.LOCKS_MASKS.noCrop << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noEditPoints)
            oThis._WriteBool2(6,  !!(locks & (AscFormat.LOCKS_MASKS.noEditPoints << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noGrp)
            oThis._WriteBool2(7,  !!(locks & (AscFormat.LOCKS_MASKS.noGrp << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noMove)
            oThis._WriteBool2(8,  !!(locks & (AscFormat.LOCKS_MASKS.noMove << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noResize)
            oThis._WriteBool2(9,  !!(locks & (AscFormat.LOCKS_MASKS.noResize << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noRot)
            oThis._WriteBool2(10, !!(locks & (AscFormat.LOCKS_MASKS.noRot << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noSelect)
            oThis._WriteBool2(11, !!(locks & (AscFormat.LOCKS_MASKS.noSelect << 1)));
        oThis.WriteUChar(g_nodeAttributeEnd);
    };

    this.WriteGrpCNvPr = function(locks) {
        oThis.WriteUChar(g_nodeAttributeStart);
        if(locks & AscFormat.LOCKS_MASKS.noChangeAspect)
            oThis._WriteBool2(0, !!(locks & (AscFormat.LOCKS_MASKS.noChangeAspect << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noGrp)
            oThis._WriteBool2(1, !!(locks & (AscFormat.LOCKS_MASKS.noGrp << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noMove)
            oThis._WriteBool2(2, !!(locks & (AscFormat.LOCKS_MASKS.noMove << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noResize)
            oThis._WriteBool2(3, !!(locks & (AscFormat.LOCKS_MASKS.noResize << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noRot)
            oThis._WriteBool2(4, !!(locks & (AscFormat.LOCKS_MASKS.noRot << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noSelect)
            oThis._WriteBool2(5, !!(locks & (AscFormat.LOCKS_MASKS.noSelect << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noUngrp)
            oThis._WriteBool2(6, !!(locks & (AscFormat.LOCKS_MASKS.noUngrp << 1)));
        oThis.WriteUChar(g_nodeAttributeEnd);
    };
    this.WriteGrFrameCNvPr = function(locks) {
        oThis.WriteUChar(g_nodeAttributeStart);
        if(locks & AscFormat.LOCKS_MASKS.noChangeAspect)
            oThis._WriteBool2(0, !!(locks & (AscFormat.LOCKS_MASKS.noChangeAspect << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noDrilldown)
            oThis._WriteBool2(1, !!(locks & (AscFormat.LOCKS_MASKS.noDrilldown << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noGrp)
            oThis._WriteBool2(2, !!(locks & (AscFormat.LOCKS_MASKS.noGrp << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noMove)
            oThis._WriteBool2(3, !!(locks & (AscFormat.LOCKS_MASKS.noMove << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noResize)
            oThis._WriteBool2(4, !!(locks & (AscFormat.LOCKS_MASKS.noResize << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noSelect)
            oThis._WriteBool2(5, !!(locks & (AscFormat.LOCKS_MASKS.noSelect << 1)));
        oThis.WriteUChar(g_nodeAttributeEnd);
    };

    this.WriteCnxCNvPr = function(pr){
        var locks = pr.locks;
        oThis.WriteUChar(g_nodeAttributeStart);
        if(locks & AscFormat.LOCKS_MASKS.noAdjustHandles)
            oThis._WriteBool2(0, !!(locks & (AscFormat.LOCKS_MASKS.noAdjustHandles << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noChangeArrowheads)
            oThis._WriteBool2(1, !!(locks & (AscFormat.LOCKS_MASKS.noChangeArrowheads << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noChangeAspect)
            oThis._WriteBool2(2, !!(locks & (AscFormat.LOCKS_MASKS.noChangeAspect << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noChangeShapeType)
            oThis._WriteBool2(3, !!(locks & (AscFormat.LOCKS_MASKS.noChangeShapeType << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noEditPoints)
            oThis._WriteBool2(4, !!(locks & (AscFormat.LOCKS_MASKS.noEditPoints << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noGrp)
            oThis._WriteBool2(5, !!(locks & (AscFormat.LOCKS_MASKS.noGrp << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noMove)
            oThis._WriteBool2(6, !!(locks & (AscFormat.LOCKS_MASKS.noMove << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noResize)
            oThis._WriteBool2(7, !!(locks & (AscFormat.LOCKS_MASKS.noResize << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noRot)
            oThis._WriteBool2(8, !!(locks & (AscFormat.LOCKS_MASKS.noRot << 1)));
        if(locks & AscFormat.LOCKS_MASKS.noSelect)
            oThis._WriteBool2(9, !!(locks & (AscFormat.LOCKS_MASKS.noSelect << 1)));

        if(pr.stCnxId && AscFormat.isRealNumber(pr.stCnxIdx)){

            if(!AscFormat.isRealNumber(oThis.arr_map_shapes_id[pr.stCnxId])){
                oThis.arr_map_shapes_id[pr.stCnxId] = ++oThis.max_shape_id;
            }
            oThis._WriteInt2(10, oThis.arr_map_shapes_id[pr.stCnxId]);
            oThis._WriteInt2(11, pr.stCnxIdx);
        }
        if(pr.endCnxId && AscFormat.isRealNumber(pr.endCnxIdx)){
            if(!AscFormat.isRealNumber(oThis.arr_map_shapes_id[pr.endCnxId])){
                oThis.arr_map_shapes_id[pr.endCnxId] = ++oThis.max_shape_id;
            }
            oThis._WriteInt2(12, oThis.arr_map_shapes_id[pr.endCnxId]);
            oThis._WriteInt2(13, pr.endCnxIdx);

        }
        oThis.WriteUChar(g_nodeAttributeEnd);
    };

    this.WriteUniNvPr = function(nv)
    {
        oThis.WriteRecord2(0, nv.cNvPr, oThis.Write_cNvPr);
        if(AscFormat.isRealNumber(nv.locks) && (nv.locks !== 0 || nv.nvUniSpPr) && AscFormat.isRealNumber(nv.objectType))
        {
            switch(nv.objectType)
            {
                case AscDFH.historyitem_type_Shape:
                {
                    oThis.WriteRecord1(1, nv.locks, oThis.WriteSpCNvPr);
                    break;
                }
                case AscDFH.historyitem_type_ImageShape:
                {
                    oThis.WriteRecord1(1, nv.locks, oThis.WritePicCNvPr);
                    break;
                }
                case AscDFH.historyitem_type_GroupShape:
                {
                    oThis.WriteRecord1(1, nv.locks, oThis.WriteGrpCNvPr);
                    break;
                }
                case AscDFH.historyitem_type_GraphicFrame:
                case AscDFH.historyitem_type_ChartSpace:
                {
                    oThis.WriteRecord1(1, nv.locks, oThis.WriteGrFrameCNvPr);
                    break;
                }
                case AscDFH.historyitem_type_Cnx:
                {
                    nv.nvUniSpPr.locks = nv.locks;
                    oThis.WriteRecord1(1, nv.nvUniSpPr, oThis.WriteCnxCNvPr);
                    break;
                }
            }
        }
        nv.locks     = null;
        nv.objectType = null;
        oThis.WriteRecord2(2, nv.nvPr, oThis.Write_nvPr);
    };

    this.Write_cNvPr = function(cNvPr)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        if(cNvPr.shapeId){
            if(AscFormat.isRealNumber(oThis.arr_map_shapes_id[cNvPr.shapeId])){
                cNvPr.id = oThis.arr_map_shapes_id[cNvPr.shapeId];
            }
            else{
                oThis.arr_map_shapes_id[cNvPr.shapeId] = ++oThis.max_shape_id;
            }
            cNvPr.id = oThis.arr_map_shapes_id[cNvPr.shapeId];
        }
        oThis._WriteInt1(0, cNvPr.id);
        oThis._WriteString1(1, cNvPr.name);
		oThis._WriteBool1(2, cNvPr.isHidden);
		oThis._WriteString2(3, cNvPr.title);
		oThis._WriteString2(4, cNvPr.descr);
        oThis.WriteUChar(g_nodeAttributeEnd);
        oThis.WriteRecord2(0, cNvPr.hlinkClick, oThis.Write_Hyperlink2);
        oThis.WriteRecord2(1, cNvPr.hlinkHover, oThis.Write_Hyperlink2);
    }

    this.Write_Hyperlink2 = function(hyper)
    {
        oThis.WriteUChar(g_nodeAttributeStart);


        var id = hyper.id;
        var action = hyper.action;

        if (id === "ppaction://hlinkshowjump?jump=firstslide")
        {
            action = id;
            id = "";
        }
        else if (id === "ppaction://hlinkshowjump?jump=lastslide")
        {
            action = id;
            id = "";
        }
        else if (id === "ppaction://hlinkshowjump?jump=nextslide")
        {
            action = id;
            id = "";
        }
        else if (id === "ppaction://hlinkshowjump?jump=previousslide")
        {
            action = id;
            id = "";
        }
        else
        {
            if(typeof id === "string")
            {
                var mask = "ppaction://hlinksldjumpslide";
                var indSlide = id.indexOf(mask);
                if (0 === indSlide)
                {
                    var slideNum = parseInt(id.substring(mask.length));
                    id = "slide" + (slideNum + 1) + ".xml";
                    action = "ppaction://hlinksldjump";
                }
            }
        }

        oThis._WriteString2(0, id);
        oThis._WriteString2(1, hyper.invalidUrl);
        oThis._WriteString2(2, action);
        oThis._WriteString2(3, hyper.tgtFrame);
        oThis._WriteString2(4, hyper.tooltip);
        oThis._WriteBool2(5, hyper.history);
        oThis._WriteBool2(6, hyper.highlightClick);
        oThis._WriteBool2(7, hyper.endSnd);
        oThis.WriteUChar(g_nodeAttributeEnd);
    };

    this.Write_nvPr = function(nvPr)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteBool2(0, nvPr.isPhoto);
        oThis._WriteBool2(1, nvPr.userDrawn);
        oThis.WriteUChar(g_nodeAttributeEnd);

        oThis.WriteRecord2(0, nvPr.ph, oThis.Write_ph);
    }

    this.Write_ph = function(ph)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteBool2(0, ph.hasCustomPrompt);
        oThis._WriteString2(1, ph.idx);
        oThis._WriteLimit2(2, ph.orient);
        oThis._WriteLimit2(3, ph.sz);
        oThis._WriteLimit2(4, ph.type);
        oThis.WriteUChar(g_nodeAttributeEnd);
    }

    this.WriteGeometry = function(geom)
    {
        if (undefined === geom || null == geom)
            return;

        if (typeof geom.preset === "string" && geom.preset.length > 0)
        {
            oThis.StartRecord(1);

            oThis.WriteUChar(g_nodeAttributeStart);
            oThis._WriteString1(0, geom.preset);
            oThis.WriteUChar(g_nodeAttributeEnd);

            oThis.WriteAdj(geom.gdLst, geom.avLst, 0);

            oThis.EndRecord();
        }
        else
        {
            oThis.StartRecord(2);

            oThis.WriteAdj(geom.gdLst, geom.avLst, 0);
            oThis.WriteGuides(geom.gdLstInfo, 1);
            oThis.WriteAh(geom.ahXYLstInfo, geom.ahPolarLstInfo, 2);
            oThis.WriteCnx(geom.cnxLstInfo, 3);
            oThis.WritePathLst(geom.pathLst, 4);
            oThis.WriteRecord2(5, geom.rectS, oThis.WriteTextRect);

            oThis.EndRecord();
        }
    }

    this.WritePrstTxWarp = function(prstTxWarp)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteLimit1(0, AscFormat.getNumByTxPrst(prstTxWarp.preset));
        oThis.WriteUChar(g_nodeAttributeEnd);
        oThis.WriteAdj(prstTxWarp.gdLst, prstTxWarp.avLst, 0);
    }

    this.WriteAdj = function(gdLst, avLst, rec_num)
    {
        var _len = 0;
        for (var i in avLst)
            ++_len;

        if (0 == _len)
            return;

        oThis.StartRecord(rec_num);
        oThis.WriteULong(_len);

        for (var i in avLst)
        {
            oThis.StartRecord(1);

            oThis.WriteUChar(g_nodeAttributeStart);
            oThis._WriteString1(0, i);
            oThis._WriteInt1(1, 15);
            oThis._WriteString1(2, "" + (gdLst[i] >> 0));
            oThis.WriteUChar(g_nodeAttributeEnd);

            oThis.EndRecord();
        }

        oThis.EndRecord();
    }

    this.WriteGuides = function(gdLst, rec_num)
    {
        var _len = gdLst.length;

        if (0 == rec_num)
            return;

        this.StartRecord(rec_num);
        this.WriteULong(_len);

        for (var i = 0; i < _len; i++)
        {
            this.StartRecord(1);

            var _gd = gdLst[i];

            this.WriteUChar(g_nodeAttributeStart);
            this._WriteString1(0, _gd.name);
            this._WriteInt1(1, _gd.formula);

            this._WriteString2(2, _gd.x);
            this._WriteString2(3, _gd.y);
            this._WriteString2(4, _gd.z);

            this.WriteUChar(g_nodeAttributeEnd);

            this.EndRecord();
        }

        this.EndRecord();
    }

    this.WriteAh = function(ahLstXY, ahLstPolar, rec_num)
    {
        var _len = 0;
        for (var i in ahLstXY)
            ++_len;

        for (var i in ahLstPolar)
            ++_len;

        if (0 == rec_num)
            return;

        this.StartRecord(rec_num);
        this.WriteULong(_len);

        for (var i in ahLstXY)
        {
            this.StartRecord(1);

            var _ah = ahLstXY[i];

            this.StartRecord(2);
            this.WriteUChar(g_nodeAttributeStart);

            this._WriteString2(0, _ah.posX);
            this._WriteString2(1, _ah.posY);
            this._WriteString2(2, _ah.gdRefX);
            this._WriteString2(3, _ah.gdRefY);
            this._WriteString2(4, _ah.maxX);
            this._WriteString2(5, _ah.maxY);
            this._WriteString2(6, _ah.minX);
            this._WriteString2(7, _ah.minY);

            this.WriteUChar(g_nodeAttributeEnd);
            this.EndRecord();

            this.EndRecord();
        }

        for (var i in ahLstPolar)
        {
            this.StartRecord(1);

            var _ah = ahLstPolar[i];

            this.StartRecord(2);
            this.WriteUChar(g_nodeAttributeStart);

            this._WriteString2(0, _ah.posX);
            this._WriteString2(1, _ah.posY);
            this._WriteString2(2, _ah.gdRefAng);
            this._WriteString2(3, _ah.gdRefR);
            this._WriteString2(4, _ah.maxAng);
            this._WriteString2(5, _ah.maxR);
            this._WriteString2(6, _ah.minAng);
            this._WriteString2(7, _ah.minR);

            this.WriteUChar(g_nodeAttributeEnd);
            this.EndRecord();

            this.EndRecord();
        }

        this.EndRecord();
    }

    this.WriteCnx = function(cnxLst, rec_num)
    {
        var _len = 0;
        for (var i in cnxLst)
            ++_len;

        if (0 == rec_num)
            return;

        this.StartRecord(rec_num);
        this.WriteULong(_len);

        for (var i in cnxLst)
        {
            this.StartRecord(1);

            var _gd = cnxLst[i];

            this.WriteUChar(g_nodeAttributeStart);
            this._WriteString1(0, _gd.x);
            this._WriteString1(1, _gd.y);
            this._WriteString1(2, _gd.ang);
            this.WriteUChar(g_nodeAttributeEnd);

            this.EndRecord();
        }

        this.EndRecord();
    }

    this.WriteTextRect = function(rect)
    {
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteString2(0, rect.l);
        oThis._WriteString2(1, rect.t);
        oThis._WriteString2(2, rect.r);
        oThis._WriteString2(3, rect.b);
        oThis.WriteUChar(g_nodeAttributeEnd);
    }

    this.WritePathLst = function(pathLst, rec_num)
    {
        var _len = pathLst.length;
        if (0 == _len)
            return;

        this.StartRecord(rec_num);
        this.WriteULong(_len);

        for (var i = 0; i < _len; i++)
        {
            this.StartRecord(1);

            var _path = pathLst[i];

            this.WriteUChar(g_nodeAttributeStart);
            this._WriteBool2(0, _path.extrusionOk);
            if (_path.fill != null && _path.fill !== undefined)
            {
                this._WriteLimit1(1, (_path.fill == "none") ? 4 : 5);
            }
            this._WriteInt2(2, _path.pathH);
            this._WriteBool2(3, _path.stroke);
            this._WriteInt2(4, _path.pathW);
            this.WriteUChar(g_nodeAttributeEnd);

            var _comms = _path.ArrPathCommandInfo;
            var _count = _comms.length;
            if (0 != _count)
            {
                this.StartRecord(0);
                this.WriteULong(_count);

                for (var j = 0; j < _count; j++)
                {
                    this.StartRecord(0);

                    var cmd = _comms[j];

                    switch(cmd.id)
                    {
                        case AscFormat.moveTo:
                        {
                            this.StartRecord(1);
                            this.WriteUChar(g_nodeAttributeStart);
                            this._WriteString1(0, "" + cmd.X);
                            this._WriteString1(1, "" + cmd.Y);
                            this.WriteUChar(g_nodeAttributeEnd);
                            this.EndRecord();
                            break;
                        }
                        case AscFormat.lineTo:
                        {
                            this.StartRecord(2);
                            this.WriteUChar(g_nodeAttributeStart);
                            this._WriteString1(0, "" + cmd.X);
                            this._WriteString1(1, "" + cmd.Y);
                            this.WriteUChar(g_nodeAttributeEnd);
                            this.EndRecord();
                            break;
                        }
                        case AscFormat.bezier3:
                        {
                            this.StartRecord(6);
                            this.WriteUChar(g_nodeAttributeStart);
                            this._WriteString1(0, "" + cmd.X0);
                            this._WriteString1(1, "" + cmd.Y0);
                            this._WriteString1(2, "" + cmd.X1);
                            this._WriteString1(3, "" + cmd.Y1);
                            this.WriteUChar(g_nodeAttributeEnd);
                            this.EndRecord();
                            break;
                        }
                        case AscFormat.bezier4:
                        {
                            this.StartRecord(4);
                            this.WriteUChar(g_nodeAttributeStart);
                            this._WriteString1(0, "" + cmd.X0);
                            this._WriteString1(1, "" + cmd.Y0);
                            this._WriteString1(2, "" + cmd.X1);
                            this._WriteString1(3, "" + cmd.Y1);
                            this._WriteString1(4, "" + cmd.X2);
                            this._WriteString1(5, "" + cmd.Y2);
                            this.WriteUChar(g_nodeAttributeEnd);
                            this.EndRecord();
                            break;
                        }
                        case AscFormat.arcTo:
                        {
                            this.StartRecord(5);
                            this.WriteUChar(g_nodeAttributeStart);
                            this._WriteString1(0, "" + cmd.wR);
                            this._WriteString1(1, "" + cmd.hR);
                            this._WriteString1(2, "" + cmd.stAng);
                            this._WriteString1(3, "" + cmd.swAng);
                            this.WriteUChar(g_nodeAttributeEnd);
                            this.EndRecord();
                            break;
                        }
                        case AscFormat.close:
                        {
                            this.StartRecord(3);
                            this.EndRecord();
                            break;
                        }
                    }

                    this.EndRecord();
                }

                this.EndRecord();
            }

            this.EndRecord()
        }

        this.EndRecord();
    }

    // objects ------------------------------------------------------------------

    // tables -------------------------------------------------------------------
    this.WriteTableStyle = function(num, tableStyle)
    {
        oThis.StartRecord(1);
        oThis.WriteUChar(g_nodeAttributeStart);
        oThis._WriteString1(0, oThis.tableStylesGuides[num]);

        var __name = tableStyle.Name;
        __name = __name.replace(/&/g, "_");
        __name = __name.replace(/>/g, "_");
        __name = __name.replace(/</g, "_");
        __name = __name.replace(/"/g, "_");
        __name = __name.replace(/'/g, "_");
        oThis._WriteString2(1, __name);
        oThis.WriteUChar(g_nodeAttributeEnd);

        if (undefined !== tableStyle.TablePr.Shd && null != tableStyle.TablePr.Shd)
        {
            oThis.StartRecord(0);

            if (tableStyle.TablePr.Shd.Unifill != null && tableStyle.TablePr.Shd.Unifill !== undefined)
            {
                oThis.StartRecord(0);
                oThis.WriteRecord2(0, tableStyle.TablePr.Shd.Unifill, oThis.WriteUniFill);
                oThis.EndRecord();
            }
            if (tableStyle.TablePr.Shd.FillRef != null && tableStyle.TablePr.Shd.FillRef !== undefined)
            {
                oThis.WriteRecord2(1, tableStyle.TablePr.Shd.FillRef, oThis.WriteStyleRef);
            }

            oThis.EndRecord();
        }

        //oThis.WriteRecord2(1, tableStyle.TableWholeTable, oThis.WriteTableStylePart);
        if (tableStyle.TableWholeTable)
        {
            oThis.StartRecord(1);
            oThis.WriteTableStylePartWH(tableStyle.TableWholeTable, tableStyle.TablePr);
            oThis.EndRecord();
        }

        oThis.WriteRecord2(2, tableStyle.TableBand1Horz, oThis.WriteTableStylePart);
        oThis.WriteRecord2(3, tableStyle.TableBand2Horz, oThis.WriteTableStylePart);

        oThis.WriteRecord2(4, tableStyle.TableBand1Vert, oThis.WriteTableStylePart);
        oThis.WriteRecord2(5, tableStyle.TableBand2Vert, oThis.WriteTableStylePart);

        oThis.WriteRecord2(6, tableStyle.TableLastCol, oThis.WriteTableStylePart);
        oThis.WriteRecord2(7, tableStyle.TableFirstCol, oThis.WriteTableStylePart);
        oThis.WriteRecord2(8, tableStyle.TableFirstRow, oThis.WriteTableStylePart);
        oThis.WriteRecord2(9, tableStyle.TableLastRow, oThis.WriteTableStylePart);

        oThis.WriteRecord2(10, tableStyle.TableBRCell, oThis.WriteTableStylePart);
        oThis.WriteRecord2(11, tableStyle.TableBLCell, oThis.WriteTableStylePart);
        oThis.WriteRecord2(12, tableStyle.TableTRCell, oThis.WriteTableStylePart);
        oThis.WriteRecord2(13, tableStyle.TableTLCell, oThis.WriteTableStylePart);

        oThis.EndRecord();
    }

    this.WriteTableStylePart = function(_part)
    {
        var bIsFontRef = false;
        if (_part.TextPr.FontRef !== undefined && _part.TextPr.FontRef != null)
            bIsFontRef = true;

        var bIsFill = false;
        if (_part.TextPr.Unifill !== undefined && _part.TextPr.Unifill != null)
            bIsFill = true;

        if (bIsFontRef || bIsFill)
        {
            oThis.StartRecord(0);
            oThis.WriteUChar(g_nodeAttributeStart);
            if(AscFormat.isRealBool(_part.TextPr.Italic))
            {
                oThis._WriteLimit1(0, _part.TextPr.Italic === true ? 0 : 1);
            }
            if(AscFormat.isRealBool(_part.TextPr.Bold))
            {
                oThis._WriteLimit1(1, _part.TextPr.Bold === true ? 0 : 1);
            }
            oThis.WriteUChar(g_nodeAttributeEnd);

            oThis.WriteRecord2(0, _part.TextPr.FontRef, oThis.WriteFontRef);

            if (bIsFill && _part.TextPr.Unifill.fill !== undefined && _part.TextPr.Unifill.fill != null && _part.TextPr.Unifill.fill.type == c_oAscFill.FILL_TYPE_SOLID)
                oThis.WriteRecord2(1, _part.TextPr.Unifill.fill.color, oThis.WriteUniColor);

            oThis.EndRecord();
        }

        oThis.StartRecord(1);

        oThis.StartRecord(0);

        /*
        oThis.WriteTableCellBorderLineStyle2(0, _part.TableCellPr.TableCellBorders.Left);
        oThis.WriteTableCellBorderLineStyle2(1, _part.TableCellPr.TableCellBorders.Right);
        oThis.WriteTableCellBorderLineStyle2(2, _part.TableCellPr.TableCellBorders.Top);
        oThis.WriteTableCellBorderLineStyle2(3, _part.TableCellPr.TableCellBorders.Bottom);

        oThis.WriteTableCellBorderLineStyle2(4, _part.TableCellPr.TableCellBorders.InsideH);
        oThis.WriteTableCellBorderLineStyle2(5, _part.TableCellPr.TableCellBorders.InsideV);
        */

        oThis.WriteRecord3(0, _part.TableCellPr.TableCellBorders.Left, oThis.WriteTableCellBorderLineStyle);
        oThis.WriteRecord3(1, _part.TableCellPr.TableCellBorders.Right, oThis.WriteTableCellBorderLineStyle);
        oThis.WriteRecord3(2, _part.TableCellPr.TableCellBorders.Top, oThis.WriteTableCellBorderLineStyle);
        oThis.WriteRecord3(3, _part.TableCellPr.TableCellBorders.Bottom, oThis.WriteTableCellBorderLineStyle);

        oThis.WriteRecord3(4, _part.TableCellPr.TableCellBorders.InsideH, oThis.WriteTableCellBorderLineStyle);
        oThis.WriteRecord3(5, _part.TableCellPr.TableCellBorders.InsideV, oThis.WriteTableCellBorderLineStyle);


        oThis.EndRecord();

        var _Shd = _part.TableCellPr.Shd;
        if (undefined !== _Shd && null != _Shd)
        {
            oThis.WriteRecord2(1, _Shd.FillRef, oThis.WriteStyleRef);
            if (_Shd.Unifill !== undefined && _Shd.Unifill != null)
            {
                oThis.StartRecord(2);
                oThis.WriteRecord2(0, _Shd.Unifill, oThis.WriteUniFill);
                oThis.EndRecord();
            }
        }

        oThis.EndRecord();
    }

    this.WriteTableStylePartWH = function(_part, tablePr)
    {
        var bIsFontRef = false;
        if (_part.TextPr.FontRef !== undefined && _part.TextPr.FontRef != null)
            bIsFontRef = true;

        var bIsFill = false;
        if (_part.TextPr.Unifill !== undefined && _part.TextPr.Unifill != null)
            bIsFill = true;

        if (bIsFontRef || bIsFill)
        {
            oThis.StartRecord(0);
            oThis.WriteUChar(g_nodeAttributeStart);
            oThis.WriteUChar(g_nodeAttributeEnd);

            oThis.WriteRecord2(0, _part.TextPr.FontRef, oThis.WriteFontRef);

            if (bIsFill && _part.TextPr.Unifill.fill !== undefined && _part.TextPr.Unifill.fill != null && _part.TextPr.Unifill.fill.type == c_oAscFill.FILL_TYPE_SOLID)
                oThis.WriteRecord2(1, _part.TextPr.Unifill.fill.color, oThis.WriteUniColor);

            oThis.EndRecord();
        }

        oThis.StartRecord(1);

        oThis.StartRecord(0);

        var bIsRet = false;

        /*
        bIsRet = oThis.WriteRecord3(0, _part.TableCellPr.TableCellBorders.Left, oThis.WriteTableCellBorderLineStyle);
        if (!bIsRet)
            oThis.WriteRecord3(0, tablePr.TableBorders.Left, oThis.WriteTableCellBorderLineStyle);

        bIsRet = oThis.WriteRecord3(1, _part.TableCellPr.TableCellBorders.Right, oThis.WriteTableCellBorderLineStyle);
        if (!bIsRet)
            oThis.WriteRecord3(1, tablePr.TableBorders.Right, oThis.WriteTableCellBorderLineStyle);

        bIsRet = oThis.WriteRecord3(2, _part.TableCellPr.TableCellBorders.Top, oThis.WriteTableCellBorderLineStyle);
        if (!bIsRet)
            oThis.WriteRecord3(2, tablePr.TableBorders.Top, oThis.WriteTableCellBorderLineStyle);

        bIsRet = oThis.WriteRecord3(3, _part.TableCellPr.TableCellBorders.Bottom, oThis.WriteTableCellBorderLineStyle);
        if (!bIsRet)
            oThis.WriteRecord3(3, tablePr.TableBorders.Bottom, oThis.WriteTableCellBorderLineStyle);
        */

        bIsRet = oThis.WriteRecord3(0, tablePr.TableBorders.Left, oThis.WriteTableCellBorderLineStyle);
        if (!bIsRet)
            oThis.WriteTableCellBorderLineStyle2(0, tablePr.TableBorders.Left);

        bIsRet = oThis.WriteRecord3(1, tablePr.TableBorders.Right, oThis.WriteTableCellBorderLineStyle);
        if (!bIsRet)
            oThis.WriteTableCellBorderLineStyle2(1, tablePr.TableBorders.Right);

        bIsRet = oThis.WriteRecord3(2, tablePr.TableBorders.Top, oThis.WriteTableCellBorderLineStyle);
        if (!bIsRet)
            oThis.WriteTableCellBorderLineStyle2(2, tablePr.TableBorders.Top);

        bIsRet = oThis.WriteRecord3(3, tablePr.TableBorders.Bottom, oThis.WriteTableCellBorderLineStyle);
        if (!bIsRet)
            oThis.WriteTableCellBorderLineStyle2(3, tablePr.TableBorders.Bottom);

        /*
        oThis.WriteRecord3(4, _part.TablePr.TableBorders.InsideH, oThis.WriteTableCellBorderLineStyle);
        oThis.WriteRecord3(5, _part.TablePr.TableBorders.InsideV, oThis.WriteTableCellBorderLineStyle);
        */
        if(tablePr.TableBorders.InsideH)
        {
            oThis.WriteTableCellBorderLineStyle2(4, tablePr.TableBorders.InsideH);
        }
        if(tablePr.TableBorders.InsideV)
        {
            oThis.WriteTableCellBorderLineStyle2(5, tablePr.TableBorders.InsideV);
        }

        oThis.EndRecord();

        var _Shd = _part.TableCellPr.Shd;
        if (undefined !== _Shd && null != _Shd)
        {
            oThis.WriteRecord2(1, _Shd.FillRef, oThis.WriteStyleRef);
            if (_Shd.Unifill !== undefined && _Shd.Unifill != null)
            {
                oThis.StartRecord(2);
                oThis.WriteRecord2(0, _Shd.Unifill, oThis.WriteUniFill);
                oThis.EndRecord();
            }
        }

        oThis.EndRecord();

    }

    this.WriteTableCellBorder = function(_border)
    {
        if (_border.Value == border_None)
        {
            oThis.StartRecord(0);
            oThis.WriteUChar(g_nodeAttributeStart);
            oThis.WriteUChar(g_nodeAttributeEnd);

            var _unifill = new AscFormat.CUniFill();
            _unifill.fill = new AscFormat.CNoFill();
            oThis.WriteRecord2(0, _unifill, oThis.WriteUniFill);

            oThis.EndRecord();
            return;
        }

        var bIsFill = false;
        var bIsSize = false;
        if ((_border.Unifill !== undefined && _border.Unifill != null))
        {
            bIsFill = true;
        }
        if (_border.Size !== undefined && _border.Size != null)
        {
            bIsSize = true;
        }

        if (bIsFill || bIsSize)
        {
            oThis.StartRecord(0);
            oThis.WriteUChar(g_nodeAttributeStart);
            if (bIsSize)
            {
                oThis._WriteInt2(3, (_border.Size * 36000) >> 0);
            }
            oThis.WriteUChar(g_nodeAttributeEnd);

            // TODO: потом переделать по-нормальному
            //if (!_border.Unifill && _border.Color instanceof CDocumentColor)
            //{
            //    var _unifill = new AscFormat.CUniFill();
            //    _unifill.fill = new AscFormat.CSolidFill();
            //    _unifill.fill.color.color = new CRGBColor();
//
            //    _unifill.fill.color.color.RGBA.R = _border.Color.r;
            //    _unifill.fill.color.color.RGBA.G = _border.Color.g;
            //    _unifill.fill.color.color.RGBA.B = _border.Color.b;
//
            //    oThis.WriteRecord2(0, _unifill, oThis.WriteUniFill);
            //}

            oThis.WriteRecord2(0, _border.Unifill, oThis.WriteUniFill);

            oThis.EndRecord();
        }
    }

    this.WriteTableCellBorderLineStyle2 = function(rec_type, _border)
    {
        if (!_border)
        {
            oThis.StartRecord(rec_type);

            oThis.StartRecord(0);
            oThis.WriteUChar(g_nodeAttributeStart);
            oThis.WriteUChar(g_nodeAttributeEnd);

            var _unifill = new AscFormat.CUniFill();
            _unifill.fill = new AscFormat.CNoFill();
            oThis.WriteRecord2(0, _unifill, oThis.WriteUniFill);

            oThis.EndRecord();

            oThis.EndRecord();
            return;
        }
        else
        {
            oThis.WriteRecord3(rec_type, _border, oThis.WriteTableCellBorderLineStyle);
        }
    }

    this.WriteTableCellBorderLineStyle = function(_border)
    {
        if (_border.Value == border_None)
        {
            oThis.StartRecord(0);
            oThis.WriteUChar(g_nodeAttributeStart);
            oThis.WriteUChar(g_nodeAttributeEnd);

            var _unifill = new AscFormat.CUniFill();
            _unifill.fill = new AscFormat.CNoFill();
            oThis.WriteRecord2(0, _unifill, oThis.WriteUniFill);

            oThis.EndRecord();
            return;
        }

        var bIsFill = false;
        var bIsSize = false;
        var bIsLnRef = false;
        if ((_border.Unifill !== undefined && _border.Unifill != null))
        {
            bIsFill = true;
        }
        if (_border.Size !== undefined && _border.Size != null)
        {
            bIsSize = true;
        }

        if (bIsFill && bIsSize)
        {
            oThis.StartRecord(0);
            oThis.WriteUChar(g_nodeAttributeStart);
            if (bIsSize)
            {
                oThis._WriteInt2(3, (_border.Size * 36000) >> 0);
            }
            oThis.WriteUChar(g_nodeAttributeEnd);

            // TODO: потом переделать по-нормальному
            //if (!_border.Unifill && _border.Color instanceof CDocumentColor)
            //{
            //    var _unifill = new AscFormat.CUniFill();
            //    _unifill.fill = new AscFormat.CSolidFill();
            //    _unifill.fill.color.color = new CRGBColor();
//
            //    _unifill.fill.color.color.RGBA.R = _border.Color.r;
            //    _unifill.fill.color.color.RGBA.G = _border.Color.g;
            //    _unifill.fill.color.color.RGBA.B = _border.Color.b;
//
            //    oThis.WriteRecord2(0, _unifill, oThis.WriteUniFill);
            //}

            oThis.WriteRecord2(0, _border.Unifill, oThis.WriteUniFill);

            oThis.EndRecord();
        }

        oThis.WriteRecord2(1, _border.LineRef, oThis.WriteStyleRef);
    }
    // --------------------------------------------------------------------------
}

    function CPPTXContentWriter()
    {
        this.BinaryFileWriter = new AscCommon.CBinaryFileWriter();
        this.BinaryFileWriter.Init();
        //this.BinaryFileWriter.IsWordWriter = true;

        this.TreeDrawingIndex = 0;

        this.ShapeTextBoxContent = null;
        this.arrayStackStartsTextBoxContent = [];

        this.arrayStackStarts = [];

        this.Start_UseFullUrl = function()
        {
            this.BinaryFileWriter.Start_UseFullUrl();
        }
        this.Start_UseDocumentOrigin = function(origin)
        {
            this.BinaryFileWriter.Start_UseDocumentOrigin(origin);
        }
        this.End_UseFullUrl = function()
        {
            return this.BinaryFileWriter.End_UseFullUrl();
        }

        this._Start = function()
        {
            this.ShapeTextBoxContent = new AscCommon.CMemory();
            this.arrayStackStartsTextBoxContent = [];
            this.arrayStackStarts = [];
        }
        this._End = function()
        {
            this.ShapeTextBoxContent = null;
        }
        this.WriteTextBody = function(memory, textBody)
        {
            if (this.BinaryFileWriter.UseContinueWriter)
            {
                this.BinaryFileWriter.ImData = memory.ImData;
                this.BinaryFileWriter.data = memory.data;
                this.BinaryFileWriter.len = memory.len;
                this.BinaryFileWriter.pos = memory.pos;
            }
            else
            {
                this.TreeDrawingIndex++;
                this.arrayStackStarts.push(this.BinaryFileWriter.pos);
            }

            var _writer = this.BinaryFileWriter;
            _writer.StartRecord(0);
            _writer.WriteTxBody(textBody);
            _writer.EndRecord();

            if (this.BinaryFileWriter.UseContinueWriter)
            {
                memory.ImData = this.BinaryFileWriter.ImData;
                memory.data = this.BinaryFileWriter.data;
                memory.len = this.BinaryFileWriter.len;
                memory.pos = this.BinaryFileWriter.pos;
            }
            else
            {
                this.TreeDrawingIndex--;

                var oldPos = this.arrayStackStarts[this.arrayStackStarts.length - 1];
                memory.WriteBuffer(this.BinaryFileWriter.data, oldPos, this.BinaryFileWriter.pos - oldPos);
                this.BinaryFileWriter.pos = oldPos;

                this.arrayStackStarts.splice(this.arrayStackStarts.length - 1, 1);
            }
        }
        this.WriteClrMapOverride = function(memory, clrMapOverride)
        {
            if (this.BinaryFileWriter.UseContinueWriter)
            {
                this.BinaryFileWriter.ImData = memory.ImData;
                this.BinaryFileWriter.data = memory.data;
                this.BinaryFileWriter.len = memory.len;
                this.BinaryFileWriter.pos = memory.pos;
            }
            else
            {
                this.TreeDrawingIndex++;
                this.arrayStackStarts.push(this.BinaryFileWriter.pos);
            }

            var _writer = this.BinaryFileWriter;
            _writer.StartRecord(0);
            _writer.StartRecord(0);
            _writer.WriteClrMapOvr(clrMapOverride);
            _writer.EndRecord();
            _writer.EndRecord();

            if (this.BinaryFileWriter.UseContinueWriter)
            {
                memory.ImData = this.BinaryFileWriter.ImData;
                memory.data = this.BinaryFileWriter.data;
                memory.len = this.BinaryFileWriter.len;
                memory.pos = this.BinaryFileWriter.pos;
            }
            else
            {
                this.TreeDrawingIndex--;

                var oldPos = this.arrayStackStarts[this.arrayStackStarts.length - 1];
                memory.WriteBuffer(this.BinaryFileWriter.data, oldPos, this.BinaryFileWriter.pos - oldPos);
                this.BinaryFileWriter.pos = oldPos;

                this.arrayStackStarts.splice(this.arrayStackStarts.length - 1, 1);
            }
        }
        this.WriteSpPr = function(memory, spPr, type)
        {
            if (this.BinaryFileWriter.UseContinueWriter)
            {
                this.BinaryFileWriter.ImData = memory.ImData;
                this.BinaryFileWriter.data = memory.data;
                this.BinaryFileWriter.len = memory.len;
                this.BinaryFileWriter.pos = memory.pos;
            }
            else
            {
                this.TreeDrawingIndex++;
                this.arrayStackStarts.push(this.BinaryFileWriter.pos);
            }

            var _writer = this.BinaryFileWriter;
            _writer.StartRecord(0);
            if(0 == type)
                _writer.WriteLn(spPr);
            else if(1 == type)
                _writer.WriteUniFill(spPr);
            else
                _writer.WriteSpPr(spPr);
            _writer.EndRecord();

            if (this.BinaryFileWriter.UseContinueWriter)
            {
                memory.ImData = this.BinaryFileWriter.ImData;
                memory.data = this.BinaryFileWriter.data;
                memory.len = this.BinaryFileWriter.len;
                memory.pos = this.BinaryFileWriter.pos;
            }
            else
            {
                this.TreeDrawingIndex--;

                var oldPos = this.arrayStackStarts[this.arrayStackStarts.length - 1];
                memory.WriteBuffer(this.BinaryFileWriter.data, oldPos, this.BinaryFileWriter.pos - oldPos);
                this.BinaryFileWriter.pos = oldPos;

                this.arrayStackStarts.splice(this.arrayStackStarts.length - 1, 1);
            }
        }
		this.WriteRunProperties = function(memory, rPr)
		{
			if (this.BinaryFileWriter.UseContinueWriter)
			{
				this.BinaryFileWriter.ImData = memory.ImData;
				this.BinaryFileWriter.data = memory.data;
				this.BinaryFileWriter.len = memory.len;
				this.BinaryFileWriter.pos = memory.pos;
			}
			else
			{
				this.TreeDrawingIndex++;
				this.arrayStackStarts.push(this.BinaryFileWriter.pos);
			}

			var _writer = this.BinaryFileWriter;
			_writer.StartRecord(0);
			_writer.WriteRunProperties(rPr);
			_writer.EndRecord();

			if (this.BinaryFileWriter.UseContinueWriter)
			{
				memory.ImData = this.BinaryFileWriter.ImData;
				memory.data = this.BinaryFileWriter.data;
				memory.len = this.BinaryFileWriter.len;
				memory.pos = this.BinaryFileWriter.pos;
			}
			else
			{
				this.TreeDrawingIndex--;

				var oldPos = this.arrayStackStarts[this.arrayStackStarts.length - 1];
				memory.WriteBuffer(this.BinaryFileWriter.data, oldPos, this.BinaryFileWriter.pos - oldPos);
				this.BinaryFileWriter.pos = oldPos;

				this.arrayStackStarts.splice(this.arrayStackStarts.length - 1, 1);
			}
		}
        this.WriteDrawing = function(memory, grObject, Document, oMapCommentId, oNumIdMap, copyParams, saveParams)
        {
            this.TreeDrawingIndex++;

            this.arrayStackStarts.push(this.BinaryFileWriter.pos);

            this.BinaryFileWriter.StartRecord(0);
            this.BinaryFileWriter.StartRecord(1);
            switch(grObject.getObjectType())
            {
                case AscDFH.historyitem_type_Shape:
                case AscDFH.historyitem_type_Cnx:
                {
                    if(grObject.bWordShape)
                    {
                        this.WriteShape(grObject, Document, oMapCommentId, oNumIdMap, copyParams, saveParams);
                    }
                    else
                    {
                        this.WriteShape2(grObject, Document, oMapCommentId, oNumIdMap, copyParams, saveParams);
                    }
                    break;
                }
                case AscDFH.historyitem_type_OleObject:
                case AscDFH.historyitem_type_ImageShape:
                {
					if(grObject.bWordShape)
					{
						this.WriteImage(grObject);
					}
					else
					{
						this.WriteImage2(grObject);
					}
                    break;
                }
                case AscDFH.historyitem_type_GroupShape:
                {
                    this.WriteGroup(grObject, Document, oMapCommentId, oNumIdMap, copyParams, saveParams);
                    break;
                }
				case AscDFH.historyitem_type_ChartSpace:
				{
					this.BinaryFileWriter.WriteChart(grObject);
					break;
				}
            }
            this.BinaryFileWriter.EndRecord();
            this.BinaryFileWriter.EndRecord();

            this.TreeDrawingIndex--;

            var oldPos = this.arrayStackStarts[this.arrayStackStarts.length - 1];
            memory.WriteBuffer(this.BinaryFileWriter.data, oldPos, this.BinaryFileWriter.pos - oldPos);
            this.BinaryFileWriter.pos = oldPos;

            this.arrayStackStarts.splice(this.arrayStackStarts.length - 1, 1);
        }

        this.WriteShape2 = function(shape, Document, oMapCommentId, oNumIdMap, copyParams, saveParams)
        {
            var _writer = this.BinaryFileWriter;
            _writer.WriteShape(shape);
        }

        this.WriteShape = function(shape, Document, oMapCommentId, oNumIdMap, copyParams, saveParams)
        {
            var _writer = this.BinaryFileWriter;

            if(shape.getObjectType() === AscDFH.historyitem_type_Cnx){
                _writer.StartRecord(3);
            }
            else{
                _writer.StartRecord(1);
                _writer.WriteUChar(AscCommon.g_nodeAttributeStart);
                _writer._WriteBool2(0, shape.attrUseBgFill);
                _writer.WriteUChar(AscCommon.g_nodeAttributeEnd);
            }

            shape.spPr.WriteXfrm = shape.spPr.xfrm;

            var tmpFill = shape.spPr.Fill;
            var isUseTmpFill = false;
            if (tmpFill !== undefined && tmpFill != null)
            {
                var trans = ((tmpFill.transparent != null) && (tmpFill.transparent != 255)) ? tmpFill.transparent : null;
                if (trans != null)
                {
                    if (tmpFill.fill === undefined || tmpFill.fill == null)
                    {
                        isUseTmpFill = true;
                        shape.spPr.Fill = shape.brush;
                    }
                }
            }

            _writer.WriteRecord1(0, {locks: shape.locks, objectType: shape.getObjectType()}, _writer.WriteUniNvPr);
            _writer.WriteRecord1(1, shape.spPr, _writer.WriteSpPr);
            _writer.WriteRecord2(2, shape.style, _writer.WriteShapeStyle);
            //_writer.WriteRecord2(3, shape.txBody, _writer.WriteTxBody);

            if (shape.textBoxContent)
            {
                _writer.StartRecord(4);

                var memory = this.ShapeTextBoxContent;

                this.arrayStackStartsTextBoxContent.push(memory.pos);

                var bdtw = new BinaryDocumentTableWriter(memory, Document, oMapCommentId, oNumIdMap, copyParams, saveParams);
                var bcw = new AscCommon.BinaryCommonWriter(memory);
                bcw.WriteItemWithLength(function(){bdtw.WriteDocumentContent(shape.textBoxContent);});

                var oldPos = this.arrayStackStartsTextBoxContent[this.arrayStackStartsTextBoxContent.length - 1];
                _writer.WriteBuffer(memory.data, oldPos, memory.pos - oldPos);
                memory.pos = oldPos;
                this.arrayStackStartsTextBoxContent.splice(this.arrayStackStartsTextBoxContent.length - 1, 1);

                _writer.EndRecord();

                _writer.StartRecord(5);
                _writer.WriteBodyPr(shape.bodyPr);
                _writer.EndRecord();
            }
            _writer.WriteRecord2(7, shape.signatureLine, _writer.WriteSignatureLine);

            if (isUseTmpFill)
            {
                shape.spPr.Fill = tmpFill;
            }

            delete shape.spPr.WriteXfrm;

            _writer.EndRecord();
        }

		this.WriteImage2 = function(image)
		{
			var _writer = this.BinaryFileWriter;
			_writer.WriteImage(image);
		}
		
        this.WriteImage = function(image)
        {
            var _writer = this.BinaryFileWriter;

            var isOle = AscDFH.historyitem_type_OleObject == image.getObjectType();
            var _type, _fileMask;
            if(isOle){
                _writer.StartRecord(6);
                //важно писать в начале
                _writer.WriteRecord1(4, image, _writer.WriteOleInfo);
            } else {
                var _type;
                var bMedia = false;
                if(image.nvPicPr && image.nvPicPr.nvPr && image.nvPicPr.nvPr.unimedia && image.nvPicPr.nvPr.unimedia.type !== null
                && typeof image.nvPicPr.nvPr.unimedia.media === "string" && image.nvPicPr.nvPr.unimedia.media.length > 0){
                    _type = image.nvPicPr.nvPr.unimedia.type;
                    _fileMask = image.nvPicPr.nvPr.unimedia.media;
                    bMedia = true;
                }
                else{
                    _type = 2;
                }
                _writer.StartRecord(_type);
                if(bMedia){
                    _writer.WriteRecord1(5, null, function(){
                        _writer.WriteUChar(g_nodeAttributeStart);
                        _writer._WriteString2(0, _fileMask);
                        _writer.WriteUChar(g_nodeAttributeEnd);
                    });
                }
            }
            _writer.WriteRecord1(0, {locks: image.locks, objectType: image.getObjectType()}, _writer.WriteUniNvPr);

            image.spPr.WriteXfrm = image.spPr.xfrm;


            var _unifill = null;
            if (image.blipFill instanceof AscFormat.CUniFill)
            {
                _unifill = image.blipFill;
            }
            else
            {
                _unifill = new AscFormat.CUniFill();
                _unifill.fill = image.blipFill;
            }

            _writer.WriteRecord1(1, _unifill, _writer.WriteUniFill);
            _writer.WriteRecord1(2, image.spPr, _writer.WriteSpPr);
            _writer.WriteRecord2(3, image.style, _writer.WriteShapeStyle);

            delete image.spPr.WriteXfrm;

            _writer.EndRecord();
        }
        this.WriteOleInfo = function(ole)
        {
			var ratio = 20 * 3 / 4;//px to twips
            var _writer = this.BinaryFileWriter;
            _writer.WriteUChar(g_nodeAttributeStart);
            _writer._WriteString2(0, ole.m_sApplicationId);
            _writer._WriteString2(1, ole.m_sData);
			_writer._WriteInt2(2, ratio * ole.m_nPixWidth);
			_writer._WriteInt2(3, ratio * ole.m_nPixHeight);
            _writer._WriteUChar2(4, 0);
            _writer._WriteUChar2(5, 0);
			_writer._WriteString2(7, ole.m_sObjectFile);
            _writer.WriteUChar(g_nodeAttributeEnd);
        }

        this.WriteGroup = function(group, Document, oMapCommentId, oNumIdMap, copyParams, saveParams)
        {
            var _writer = this.BinaryFileWriter;

            _writer.StartRecord(4);

            group.spPr.WriteXfrm = group.spPr.xfrm;
            //if (group.spPr.WriteXfrm)
            //{
            //    group.spPr.WriteXfrm.chOffX = 0;
            //    group.spPr.WriteXfrm.chOffY = 0;
            //    group.spPr.WriteXfrm.chExtX = group.spPr.WriteXfrm.extX;
            //    group.spPr.WriteXfrm.chExtY = group.spPr.WriteXfrm.extY;
            //}

            //_writer.WriteRecord1(0, group.nvGrpSpPr, oThis.WriteUniNvPr);
            _writer.WriteRecord1(1, group.spPr, _writer.WriteGrpSpPr);

            delete group.spPr.WriteXfrm;

            var spTree = group.spTree;
            var _len = spTree.length;
            if (0 != _len)
            {
                _writer.StartRecord(2);
                _writer.WriteULong(_len);

                for (var i = 0; i < _len; i++)
                {
                    _writer.StartRecord(0);

                    var elem = spTree[i];
                    switch(elem.getObjectType())
                    {

                        case AscDFH.historyitem_type_Cnx:
                        case AscDFH.historyitem_type_Shape:
                        {
                            if(elem.bWordShape)
                            {
                                this.WriteShape(elem, Document, oMapCommentId, oNumIdMap, copyParams, saveParams);
                            }
                            else
                            {
                                this.WriteShape2(elem, Document, oMapCommentId, oNumIdMap, copyParams, saveParams);
                            }
                            break;
                        }
                        case AscDFH.historyitem_type_OleObject:
                        case AscDFH.historyitem_type_ImageShape:
                        {
							if(elem.bWordShape)
							{
								this.WriteImage(elem);
							}
							else
							{
								this.WriteImage2(elem);
							}
                            break;
                        }
                        case AscDFH.historyitem_type_GroupShape:
                        {
                            this.WriteGroup(elem, Document, oMapCommentId, oNumIdMap, copyParams, saveParams);
                            break;
                        }
                        case AscDFH.historyitem_type_ChartSpace:
                        {
                            this.BinaryFileWriter.WriteChart(elem);
                            break;
                        }
                    }

                    _writer.EndRecord(0);
                }

                _writer.EndRecord();
            }

            _writer.EndRecord();
        }

        this.WriteTheme = function(memory, theme)
        {
			if (this.BinaryFileWriter.UseContinueWriter)
			{
				this.BinaryFileWriter.ImData = memory.ImData;
				this.BinaryFileWriter.data = memory.data;
				this.BinaryFileWriter.len = memory.len;
				this.BinaryFileWriter.pos = memory.pos;
			}
			else
			{
				this.TreeDrawingIndex++;
				this.arrayStackStarts.push(this.BinaryFileWriter.pos);
			}

            this.BinaryFileWriter.WriteTheme(theme);

			if (this.BinaryFileWriter.UseContinueWriter)
			{
				memory.ImData = this.BinaryFileWriter.ImData;
				memory.data = this.BinaryFileWriter.data;
				memory.len = this.BinaryFileWriter.len;
				memory.pos = this.BinaryFileWriter.pos;
			}
			else
			{
				this.TreeDrawingIndex--;

				var oldPos = this.arrayStackStarts[this.arrayStackStarts.length - 1];
				memory.WriteBuffer(this.BinaryFileWriter.data, oldPos, this.BinaryFileWriter.pos - oldPos);
				this.BinaryFileWriter.pos = oldPos;

				this.arrayStackStarts.splice(this.arrayStackStarts.length - 1, 1);
			}
        }
    }

    //--------------------------------------------------------export----------------------------------------------------
    window['AscCommon'] = window['AscCommon'] || {};
    window['AscCommon'].GUID = GUID;
    window['AscCommon'].CBinaryFileWriter = CBinaryFileWriter;
    window['AscCommon'].pptx_content_writer = new CPPTXContentWriter();
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){
    // Import
    var global_mouseEvent = AscCommon.global_mouseEvent;
    
function HitInLine(context, px, py, x0, y0, x1, y1)
{
   /* var l = Math.min(x0, x1);
    var t = Math.min(y0, y1);
    var r = Math.max(x0, x1);
    var b = Math.max(y0, y1);
    if(px < l || px > r || py < t || py > b)
        return false;*/
    var tx, ty, dx, dy, d;
    tx=x1-x0;
    ty=y1-y0;

    d=1.5/Math.sqrt(tx*tx+ty*ty);

    if(typeof global_mouseEvent !== "undefined" && AscCommon.isRealObject(global_mouseEvent) && AscFormat.isRealNumber(global_mouseEvent.KoefPixToMM))
    {
        d *= global_mouseEvent.KoefPixToMM;
    }

    if (global_mouseEvent && global_mouseEvent.AscHitToHandlesEpsilon)
    {
        d = global_mouseEvent.AscHitToHandlesEpsilon/Math.sqrt(tx*tx+ty*ty);
    }

    dx=-ty*d;
    dy=tx*d;

    context.beginPath();
    context.moveTo(x0, y0);
    context.lineTo(x0+dx, y0+dy);
    context.lineTo(x1+dx, y1+dy);
    context.lineTo(x1-dx, y1-dy);
    context.lineTo(x0-dx, y0-dy);
    context.closePath();
    return context.isPointInPath(px, py);
}

function HitInBezier4(context, px, py, x0, y0, x1, y1, x2, y2, x3, y3)
{
    var l = Math.min(x0, x1, x2, x3);
    var t = Math.min(y0, y1, y2, y3);
    var r = Math.max(x0, x1, x2, x3);
    var b = Math.max(y0, y1, y2, y3);
    if(px < l || px > r || py < t || py > b)
        return false;
    var tx, ty, dx, dy, d;
    tx=x3-x0;
    ty=y3-y0;

    d=1.5/Math.sqrt(tx*tx+ty*ty);

    if(typeof global_mouseEvent !== "undefined" && AscCommon.isRealObject(global_mouseEvent) && AscFormat.isRealNumber(global_mouseEvent.KoefPixToMM))
    {
        d *= global_mouseEvent.KoefPixToMM;
    }

    if (global_mouseEvent && global_mouseEvent.AscHitToHandlesEpsilon)
    {
        d = global_mouseEvent.AscHitToHandlesEpsilon/Math.sqrt(tx*tx+ty*ty);
    }

    dx=-ty*d;
    dy=tx*d;

    context.beginPath();
    context.moveTo(x0, y0);
    context.lineTo(x0+dx, y0+dy);
    context.bezierCurveTo(x1+dx, y1+dy, x2+dx, y2+dy, x3+dx, y3+dy);
    context.lineTo(x3-dx, y3-dy);
    context.bezierCurveTo(x2-dx, y2-dy, x1-dx, y1-dy, x0-dx, y0-dy);
    context.closePath();
    return context.isPointInPath(px, py);
}

function HitInBezier3(context, px, py, x0, y0, x1, y1, x2, y2)
{
    var l = Math.min(x0, x1, x2);
    var t = Math.min(y0, y1, y2);
    var r = Math.max(x0, x1, x2);
    var b = Math.max(y0, y1, y2);
    if(px < l || px > r || py < t || py > b)
        return false;
    var tx, ty, dx, dy, d;
    tx=x2-x0;
    ty=y2-y0;

    d=1.5/Math.sqrt(tx*tx+ty*ty);

    if(typeof global_mouseEvent !== "undefined" && AscCommon.isRealObject(global_mouseEvent) && AscFormat.isRealNumber(global_mouseEvent.KoefPixToMM))
    {
        d *= global_mouseEvent.KoefPixToMM;
    }

    if (global_mouseEvent && global_mouseEvent.AscHitToHandlesEpsilon)
    {
        d = global_mouseEvent.AscHitToHandlesEpsilon/Math.sqrt(tx*tx+ty*ty);
    }

    dx=-ty*d;
    dy=tx*d;

    context.beginPath();
    context.moveTo(x0, y0);
    context.lineTo(x0+dx, y0+dy);
    context.quadraticCurveTo(x1+dx, y1+dy, x2+dx, y2+dy);
    context.lineTo(x2-dx, y2-dy);
    context.quadraticCurveTo(x1-dx, y1-dy, x0-dx, y0-dy);
    context.closePath();
    return context.isPointInPath(px, py);
}

    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].HitInLine = HitInLine;
    window['AscFormat'].HitInBezier4 = HitInBezier4;
    window['AscFormat'].HitInBezier3 = HitInBezier3;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){
    // Import
    var HitInBezier4 = AscFormat.HitInBezier4;
    
    // arcTo new version
    function Arc3(ctx, fX, fY, fWidth, fHeight, fStartAngle, fSweepAngle)
    {
        var sin1 = Math.sin(fStartAngle);
        var cos1 = Math.cos(fStartAngle);

        var __x = cos1 / fWidth;
        var __y = sin1 / fHeight;
        var l = 1 / Math.sqrt(__x * __x + __y * __y);

        var cx = fX - l * cos1;
        var cy = fY - l * sin1;

        Arc2(ctx, cx - fWidth, cy - fHeight, 2 * fWidth, 2 * fHeight, fStartAngle, fSweepAngle);
    }

    function Arc2(ctx, fX, fY, fWidth, fHeight, fStartAngle, fSweepAngle)
    {
        if (0 >= fWidth || 0 >= fHeight)
            return;

        fStartAngle = -fStartAngle;
        fSweepAngle = -fSweepAngle;

        if (false /*is path closed*/ )
        {
            var fStartX = fX + fWidth / 2.0 + fWidth / 2 * Math.cos( AngToEllPrm( fStartAngle, fWidth / 2, fHeight / 2 ) );
            var fStartY = fY + fHeight / 2.0 - fHeight / 2 * Math.sin( AngToEllPrm ( fStartAngle, fWidth / 2, fHeight / 2 ) );

            if ( fSweepAngle < (2 * Math.PI) )
            {
                ctx._m(fStartX, fStartY);
            }
        }

        var bClockDirection = false;
        var fEndAngle = (2 * Math.PI) -(fSweepAngle + fStartAngle);
        var fSrtAngle = (2 * Math.PI) - fStartAngle;
        if( fSweepAngle > 0 )
            bClockDirection = true;

        if(Math.abs(fSweepAngle) >= (2 * Math.PI))
        {
            Ellipse(ctx, fX + fWidth / 2, fY + fHeight / 2, fWidth / 2, fHeight / 2);
        }
        else
        {
            EllipseArc(ctx, fX + fWidth / 2, fY + fHeight / 2, fWidth / 2, fHeight / 2, fSrtAngle, fEndAngle, bClockDirection);
        }
    }

    function AngToEllPrm(fAngle, fXRad, fYRad)
    {
        return Math.atan2( Math.sin( fAngle ) / fYRad,  Math.cos( fAngle ) / fXRad );
    }

    function Ellipse(ctx, fX, fY, fXRad, fYRad)
    {
        ctx._m(fX - fXRad, fY);

        var c_fKappa = 0.552;
        ctx._c(fX - fXRad, fY + fYRad * c_fKappa, fX - fXRad * c_fKappa, fY + fYRad, fX, fY + fYRad);
        ctx._c(fX + fXRad * c_fKappa, fY + fYRad, fX + fXRad, fY + fYRad * c_fKappa, fX + fXRad, fY);
        ctx._c(fX + fXRad, fY - fYRad * c_fKappa, fX + fXRad * c_fKappa, fY - fYRad, fX, fY - fYRad);
        ctx._c(fX - fXRad * c_fKappa, fY - fYRad, fX - fXRad, fY - fYRad * c_fKappa, fX - fXRad, fY);
    }

    function EllipseArc(ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, bClockDirection)
    {
        while ( fAngle1 < 0 )
            fAngle1 += (2 * Math.PI);

        while ( fAngle1 > (2 * Math.PI) )
            fAngle1 -= (2 * Math.PI);

        while ( fAngle2 < 0 )
            fAngle2 += (2 * Math.PI);

        while ( fAngle2 >= (2 * Math.PI) )
            fAngle2 -= (2 * Math.PI);

        if ( !bClockDirection )
        {
            if ( fAngle1 <= fAngle2 )
                EllipseArc2(ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, false);
            else
            {
                EllipseArc2(ctx, fX, fY, fXRad, fYRad, fAngle1, 2 * Math.PI, false);
                EllipseArc2(ctx, fX, fY, fXRad, fYRad, 0, fAngle2, false);
            }
        }
        else
        {
            if ( fAngle1 >= fAngle2 )
                EllipseArc2(ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, true);
            else
            {
                EllipseArc2(ctx, fX, fY, fXRad, fYRad, fAngle1, 0, true);
                EllipseArc2(ctx, fX, fY, fXRad, fYRad, 2 * Math.PI, fAngle2, true);
            }
        }
    }

    function EllipseArc2(ctx, fX, fY, fXRad, fYRad, dAngle1, dAngle2, bClockDirection)
    {
        var nFirstPointQuard  = ((2 * dAngle1 / Math.PI) >> 0) + 1;
        var nSecondPointQuard = ((2 * dAngle2 / Math.PI) >> 0) + 1;
        nSecondPointQuard = Math.min( 4, Math.max( 1, nSecondPointQuard ) );
        nFirstPointQuard  = Math.min( 4, Math.max( 1, nFirstPointQuard ) );

        var fStartX = fX + fXRad * Math.cos( AngToEllPrm( dAngle1, fXRad, fYRad ) );
        var fStartY = fY + fYRad * Math.sin( AngToEllPrm( dAngle1, fXRad, fYRad ) );

        var EndPoint = {X: 0, Y: 0};
        //ctx._l(fStartX, fStartY);

        var fCurX = fStartX, fCurY = fStartY;
        var dStartAngle = dAngle1;
        var dEndAngle = 0;

        if ( !bClockDirection )
        {
            for( var nIndex = nFirstPointQuard; nIndex <= nSecondPointQuard; nIndex++ )
            {
                if ( nIndex == nSecondPointQuard )
                    dEndAngle = dAngle2;
                else
                    dEndAngle = nIndex * Math.PI / 2;
                if ( !( nIndex == nFirstPointQuard ) )
                    dStartAngle = (nIndex - 1 ) * Math.PI / 2;

                EndPoint = EllipseArc3(ctx, fX, fY, fXRad, fYRad, AngToEllPrm( dStartAngle, fXRad, fYRad ), AngToEllPrm( dEndAngle, fXRad, fYRad ), false);
            }
        }
        else
        {
            for( var nIndex = nFirstPointQuard; nIndex >= nSecondPointQuard; nIndex-- )
            {
                if ( nIndex == nFirstPointQuard )
                    dStartAngle = dAngle1;
                else
                    dStartAngle = nIndex * Math.PI / 2;
                if ( !( nIndex == nSecondPointQuard ) )
                    dEndAngle = (nIndex - 1 ) * Math.PI / 2;
                else
                    dEndAngle = dAngle2;

                EndPoint = EllipseArc3(ctx, fX, fY, fXRad, fYRad, AngToEllPrm( dStartAngle, fXRad, fYRad ), AngToEllPrm( dEndAngle, fXRad, fYRad ), false);
            }
        }
    }

    function EllipseArc3(ctx, fX, fY, fXRad, fYRad, dAngle1, dAngle2, bClockDirection)
    {
        var fAlpha = Math.sin( dAngle2 - dAngle1 ) * ( Math.sqrt( 4.0 + 3.0 * Math.tan( (dAngle2 - dAngle1) / 2.0 ) * Math.tan( (dAngle2 - dAngle1) / 2.0 ) ) - 1.0 ) / 3.0;

        var sin1 = Math.sin(dAngle1);
        var cos1 = Math.cos(dAngle1);
        var sin2 = Math.sin(dAngle2);
        var cos2 = Math.cos(dAngle2);

        var fX1 = fX + fXRad * cos1;
        var fY1 = fY + fYRad * sin1;

        var fX2 = fX + fXRad * cos2;
        var fY2 = fY + fYRad * sin2;

        var fCX1 = fX1 - fAlpha * fXRad * sin1;
        var fCY1 = fY1 + fAlpha * fYRad * cos1;

        var fCX2 = fX2 + fAlpha * fXRad * sin2;
        var fCY2 = fY2 - fAlpha * fYRad * cos2;

        if ( !bClockDirection )
        {
            ctx._c(fCX1, fCY1, fCX2, fCY2, fX2, fY2);
            return {X: fX2, Y: fY2};
        }
        else
        {
            ctx._c(fCX2, fCY2, fCX1, fCY1, fX1, fY1);
            return {X: fX1, Y: fY1};
        }
    }

    // ----------------------------------------------------------------------- //

    function _ArcToOnCanvas(context, start_x, start_y, width_r, height_r, start_ang, sweep_ang)
    {
        var _sin = Math.sin(start_ang);
        var _cos = Math.cos(start_ang);

        var _x = _cos / width_r;
        var _y = _sin / height_r;
        var _l = 1 / Math.sqrt(_x * _x + _y * _y);

        var _cx = start_x - _l * _cos;
        var _cy = start_y - _l * _sin;


        ArcTo2OnCanvas(context, _cx - width_r, _cy - height_r, 2 * width_r, 2 * height_r, start_ang, sweep_ang);
    }

    function ArcTo2OnCanvas(context, _l_c_x, _l_c_y, width,  height, start_ang, sweep_ang)
    {
        if (0 >= width || 0 >= height)
            return;

        start_ang = -start_ang;
        sweep_ang = -sweep_ang;

        var bClockDirection = false;
        var fEndAngle = (2 * Math.PI) - (sweep_ang + start_ang);
        var fSrtAngle = (2 * Math.PI) - start_ang;
        if (sweep_ang > 0)
        {
            bClockDirection = true;
        }

        if (Math.abs(sweep_ang) >= (2 * Math.PI))
        {
            EllipseOnCanvas(context, _l_c_x + width / 2, _l_c_y + height / 2, width / 2, height / 2);
        }
        else
        {
            EllipseArcOnCanvas(context, _l_c_x + width / 2, _l_c_y + height / 2, width / 2, height / 2, fSrtAngle, fEndAngle, bClockDirection);
        }
    }

    function EllipseOnCanvas(ctx, fX, fY, fXRad, fYRad)
    {
        ctx.moveTo(fX - fXRad, fY);
        var c_fKappa = 0.552;
        ctx.bezierCurveTo(fX - fXRad, fY + fYRad * c_fKappa, fX - fXRad * c_fKappa, fY + fYRad, fX, fY + fYRad);
        ctx.bezierCurveTo(fX + fXRad * c_fKappa, fY + fYRad, fX + fXRad, fY + fYRad * c_fKappa, fX + fXRad, fY);
        ctx.bezierCurveTo(fX + fXRad, fY - fYRad * c_fKappa, fX + fXRad * c_fKappa, fY - fYRad, fX, fY - fYRad);
        ctx.bezierCurveTo(fX - fXRad * c_fKappa, fY - fYRad, fX - fXRad, fY - fYRad * c_fKappa, fX - fXRad, fY);
    }


    function EllipseArcOnCanvas(ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, bClockDirection)
    {
        while ( fAngle1 < 0 )
            fAngle1 += (2 * Math.PI);

        while ( fAngle1 > (2 * Math.PI) )
            fAngle1 -= (2 * Math.PI);

        while ( fAngle2 < 0 )
            fAngle2 += (2 * Math.PI);

        while ( fAngle2 >= (2 * Math.PI) )
            fAngle2 -= (2 * Math.PI);

        if ( !bClockDirection )
        {
            if ( fAngle1 <= fAngle2 )
                EllipseArc2OnCanvas(ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, false);
            else
            {
                EllipseArc2OnCanvas(ctx, fX, fY, fXRad, fYRad, fAngle1, 2 * Math.PI, false);
                EllipseArc2OnCanvas(ctx, fX, fY, fXRad, fYRad, 0, fAngle2, false);
            }
        }
        else
        {
            if ( fAngle1 >= fAngle2 )
                EllipseArc2OnCanvas(ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, true);
            else
            {
                EllipseArc2OnCanvas(ctx, fX, fY, fXRad, fYRad, fAngle1, 0, true);
                EllipseArc2OnCanvas(ctx, fX, fY, fXRad, fYRad, 2 * Math.PI, fAngle2, true);
            }
        }
    }


    function EllipseArc2OnCanvas(ctx, fX, fY, fXRad, fYRad, dAngle1, dAngle2, bClockDirection)
    {
        var nFirstPointQuard  = ((2 * dAngle1 / Math.PI) >> 0) + 1;
        var nSecondPointQuard = ((2 * dAngle2 / Math.PI) >> 0) + 1;
        nSecondPointQuard = Math.min( 4, Math.max( 1, nSecondPointQuard ) );
        nFirstPointQuard  = Math.min( 4, Math.max( 1, nFirstPointQuard ) );

        var fStartX = fX + fXRad * Math.cos( AngToEllPrm( dAngle1, fXRad, fYRad ) );
        var fStartY = fY + fYRad * Math.sin( AngToEllPrm( dAngle1, fXRad, fYRad ) );

        var EndPoint = {X: 0, Y: 0};
        ctx.lineTo(fStartX, fStartY);

        var fCurX = fStartX, fCurY = fStartY;
        var dStartAngle = dAngle1;
        var dEndAngle = 0;

        if ( !bClockDirection )
        {
            for( var nIndex = nFirstPointQuard; nIndex <= nSecondPointQuard; nIndex++ )
            {
                if ( nIndex == nSecondPointQuard )
                    dEndAngle = dAngle2;
                else
                    dEndAngle = nIndex * Math.PI / 2;
                if ( !( nIndex == nFirstPointQuard ) )
                    dStartAngle = (nIndex - 1 ) * Math.PI / 2;

                EndPoint = EllipseArc3OnCanvas(ctx, fX, fY, fXRad, fYRad, AngToEllPrm( dStartAngle, fXRad, fYRad ), AngToEllPrm( dEndAngle, fXRad, fYRad ), false);
            }
        }
        else
        {
            for( var nIndex = nFirstPointQuard; nIndex >= nSecondPointQuard; nIndex-- )
            {
                if ( nIndex == nFirstPointQuard )
                    dStartAngle = dAngle1;
                else
                    dStartAngle = nIndex * Math.PI / 2;
                if ( !( nIndex == nSecondPointQuard ) )
                    dEndAngle = (nIndex - 1 ) * Math.PI / 2;
                else
                    dEndAngle = dAngle2;

                EndPoint = EllipseArc3OnCanvas(ctx, fX, fY, fXRad, fYRad, AngToEllPrm( dStartAngle, fXRad, fYRad ), AngToEllPrm( dEndAngle, fXRad, fYRad ), false);
            }
        }
    }

    function EllipseArc3OnCanvas(ctx, fX, fY, fXRad, fYRad, dAngle1, dAngle2, bClockDirection)
    {
        var fAlpha = Math.sin( dAngle2 - dAngle1 ) * ( Math.sqrt( 4.0 + 3.0 * Math.tan( (dAngle2 - dAngle1) / 2.0 ) * Math.tan( (dAngle2 - dAngle1) / 2.0 ) ) - 1.0 ) / 3.0;

        var sin1 = Math.sin(dAngle1);
        var cos1 = Math.cos(dAngle1);
        var sin2 = Math.sin(dAngle2);
        var cos2 = Math.cos(dAngle2);

        var fX1 = fX + fXRad * cos1;
        var fY1 = fY + fYRad * sin1;

        var fX2 = fX + fXRad * cos2;
        var fY2 = fY + fYRad * sin2;

        var fCX1 = fX1 - fAlpha * fXRad * sin1;
        var fCY1 = fY1 + fAlpha * fYRad * cos1;

        var fCX2 = fX2 + fAlpha * fXRad * sin2;
        var fCY2 = fY2 - fAlpha * fYRad * cos2;

        if ( !bClockDirection )
        {
            ctx.bezierCurveTo(fCX1, fCY1, fCX2, fCY2, fX2, fY2);
            return {X: fX2, Y: fY2};
        }
        else
        {
            ctx.bezierCurveTo(fCX2, fCY2, fCX1, fCY1, fX1, fY1);
            return {X: fX1, Y: fY1};
        }
    }

    function _HitToArc(context, px, py,    start_x, start_y, width_r, height_r, start_ang, sweep_ang)
    {
        var _sin = Math.sin(start_ang);
        var _cos = Math.cos(start_ang);

        var _x = _cos / width_r;
        var _y = _sin / height_r;
        var _l = 1 / Math.sqrt(_x * _x + _y * _y);

        var _cx = start_x - _l * _cos;
        var _cy = start_y - _l * _sin;


        return HitToArc2(px, py, context, _cx - width_r, _cy - height_r, 2 * width_r, 2 * height_r, start_ang, sweep_ang);
    }

    function HitToArc2(px, py, context, _l_c_x, _l_c_y, width,  height, start_ang, sweep_ang)
    {
        if (0 >= width || 0 >= height)
            return;

        start_ang = -start_ang;
        sweep_ang = -sweep_ang;

        var bClockDirection = false;
        var fEndAngle = (2 * Math.PI) - (sweep_ang + start_ang);
        var fSrtAngle = (2 * Math.PI) - start_ang;
        if (sweep_ang > 0)
        {
            bClockDirection = true;
        }

        if (Math.abs(sweep_ang) >= (2 * Math.PI))
        {
            return HitToEllipseOnCanvas(px, py, context, _l_c_x + width / 2, _l_c_y + height / 2, width / 2, height / 2);
        }
        else
        {
            return HitToEllipseArcOnCanvas(px, py, context, _l_c_x + width / 2, _l_c_y + height / 2, width / 2, height / 2, fSrtAngle, fEndAngle, bClockDirection);
        }
    }

    function HitToEllipseOnCanvas(px, py, ctx, fX, fY, fXRad, fYRad)
    {
        var c_fKappa = 0.552;
        return HitInBezier4(ctx, px, py, fX - fXRad, fY, fX - fXRad, fY + fYRad * c_fKappa, fX - fXRad * c_fKappa, fY + fYRad, fX, fY + fYRad) ||
            HitInBezier4(ctx, px, py, fX, fY + fYRad, fX + fXRad * c_fKappa, fY + fYRad, fX + fXRad, fY + fYRad * c_fKappa, fX + fXRad, fY)||
            HitInBezier4(ctx, px, py, fX + fXRad, fY, fX + fXRad, fY - fYRad * c_fKappa, fX + fXRad * c_fKappa, fY - fYRad, fX, fY - fYRad)||
            HitInBezier4(ctx, px, py, fX, fY - fYRad, fX - fXRad * c_fKappa, fY - fYRad, fX - fXRad, fY - fYRad * c_fKappa, fX - fXRad, fY);
    }


    function HitToEllipseArcOnCanvas(px, py, ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, bClockDirection)
    {
        while ( fAngle1 < 0 )
            fAngle1 += (2 * Math.PI);

        while ( fAngle1 > (2 * Math.PI) )
            fAngle1 -= (2 * Math.PI);

        while ( fAngle2 < 0 )
            fAngle2 += (2 * Math.PI);

        while ( fAngle2 >= (2 * Math.PI) )
            fAngle2 -= (2 * Math.PI);

        if ( !bClockDirection )
        {
            if ( fAngle1 <= fAngle2 )
                return HitToEllipseArc2OnCanvas(px, py,ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, false);
            else
            {
                return HitToEllipseArc2OnCanvas(px, py,ctx, fX, fY, fXRad, fYRad, fAngle1, 2 * Math.PI, false)|| HitToEllipseArc2OnCanvas(px, py,ctx, fX, fY, fXRad, fYRad, 0, fAngle2, false);
            }
        }
        else
        {
            if ( fAngle1 >= fAngle2 )
                return HitToEllipseArc2OnCanvas(px, py,ctx, fX, fY, fXRad, fYRad, fAngle1, fAngle2, true);
            else
            {
                return HitToEllipseArc2OnCanvas(px, py, ctx, fX, fY, fXRad, fYRad, fAngle1, 0, true) || HitToEllipseArc2OnCanvas(px, py,ctx, fX, fY, fXRad, fYRad, 2 * Math.PI, fAngle2, true);
            }
        }
    }


    function HitToEllipseArc2OnCanvas(px, py, ctx, fX, fY, fXRad, fYRad, dAngle1, dAngle2, bClockDirection)
    {
        var nFirstPointQuard  = ((2 * dAngle1 / Math.PI) >> 0) + 1;
        var nSecondPointQuard = ((2 * dAngle2 / Math.PI) >> 0) + 1;
        nSecondPointQuard = Math.min( 4, Math.max( 1, nSecondPointQuard ) );
        nFirstPointQuard  = Math.min( 4, Math.max( 1, nFirstPointQuard ) );

        var fStartX = fX + fXRad * Math.cos( AngToEllPrm( dAngle1, fXRad, fYRad ) );
        var fStartY = fY + fYRad * Math.sin( AngToEllPrm( dAngle1, fXRad, fYRad ) );

        var EndPoint = {X: fStartX, Y: fStartY, hit : false};
        var dStartAngle = dAngle1;
        var dEndAngle = 0;

        if ( !bClockDirection )
        {
            for( var nIndex = nFirstPointQuard; nIndex <= nSecondPointQuard; nIndex++ )
            {
                if ( nIndex == nSecondPointQuard )
                    dEndAngle = dAngle2;
                else
                    dEndAngle = nIndex * Math.PI / 2;
                if ( !( nIndex == nFirstPointQuard ) )
                    dStartAngle = (nIndex - 1 ) * Math.PI / 2;


                EndPoint = HitToEllipseArc3OnCanvas(px, py, EndPoint, ctx, fX, fY, fXRad, fYRad, AngToEllPrm( dStartAngle, fXRad, fYRad ), AngToEllPrm( dEndAngle, fXRad, fYRad ), false);
                if(EndPoint.hit)
                {
                    return true;
                }
            }
        }
        else
        {
            for( var nIndex = nFirstPointQuard; nIndex >= nSecondPointQuard; nIndex-- )
            {
                if ( nIndex == nFirstPointQuard )
                    dStartAngle = dAngle1;
                else
                    dStartAngle = nIndex * Math.PI / 2;
                if ( !( nIndex == nSecondPointQuard ) )
                    dEndAngle = (nIndex - 1 ) * Math.PI / 2;
                else
                    dEndAngle = dAngle2;

                EndPoint = HitToEllipseArc3OnCanvas(px, py, EndPoint, ctx, fX, fY, fXRad, fYRad, AngToEllPrm( dStartAngle, fXRad, fYRad ), AngToEllPrm( dEndAngle, fXRad, fYRad ), false);
                if(EndPoint.hit)
                {
                    return true;
                }
            }
        }
        return false;
    }

    function HitToEllipseArc3OnCanvas(px, py, EndPoint, ctx, fX, fY, fXRad, fYRad, dAngle1, dAngle2, bClockDirection)
    {
        var fAlpha = Math.sin( dAngle2 - dAngle1 ) * ( Math.sqrt( 4.0 + 3.0 * Math.tan( (dAngle2 - dAngle1) / 2.0 ) * Math.tan( (dAngle2 - dAngle1) / 2.0 ) ) - 1.0 ) / 3.0;

        var sin1 = Math.sin(dAngle1);
        var cos1 = Math.cos(dAngle1);
        var sin2 = Math.sin(dAngle2);
        var cos2 = Math.cos(dAngle2);

        var fX1 = fX + fXRad * cos1;
        var fY1 = fY + fYRad * sin1;

        var fX2 = fX + fXRad * cos2;
        var fY2 = fY + fYRad * sin2;

        var fCX1 = fX1 - fAlpha * fXRad * sin1;
        var fCY1 = fY1 + fAlpha * fYRad * cos1;

        var fCX2 = fX2 + fAlpha * fXRad * sin2;
        var fCY2 = fY2 - fAlpha * fYRad * cos2;

        if ( !bClockDirection )
        {
            return {X: fX2, Y: fY2, hit :  HitInBezier4(ctx, px, py,EndPoint.X, EndPoint.Y, fCX1, fCY1, fCX2, fCY2, fX2, fY2)};
        }
        else
        {
            return {X: fX1, Y: fY1, hit :  HitInBezier4(ctx, px, py,EndPoint.X, EndPoint.Y, fCX2, fCY2, fCX1, fCY1, fX1, fY1)};
        }
    }

    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].ArcToCurvers = Arc3;
    window['AscFormat'].HitToArc = _HitToArc;
    window['AscFormat'].ArcToOnCanvas = _ArcToOnCanvas;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

    function CShapeColor(r, g, b){
        this.r = r;
        this.g = g;
        this.b = b;



    }


    function dBoundColor(c) {
        return Math.min(255, Math.max(0, (c + 0.5) >> 0));
    }

    CShapeColor.prototype.getColorData = function (dBrightness)
    {
        if(AscFormat.fApproxEqual(dBrightness, 0.0))
        {
            return this;
        }

        var r, g, b;
        if(dBrightness >= 0.0)
        {
            return new CShapeColor(dBoundColor(this.r*(1.0 - dBrightness) + dBrightness*255.0),
                dBoundColor(this.g*(1.0 - dBrightness) + dBrightness*255.0),
                dBoundColor(this.b*(1.0 - dBrightness) + dBrightness*255.0)
            );
        }
        else
        {
            return new CShapeColor(dBoundColor(this.r*(1.0 + dBrightness)),
                dBoundColor(this.g*(1.0 + dBrightness)),
                dBoundColor(this.b*(1.0 + dBrightness))
            );
        }

    };


    CShapeColor.prototype.darken = function ()
    {
        return this.getColorData(-0.4);
    };

    CShapeColor.prototype.darkenLess = function ()
    {
        return this.getColorData(-0.2);
    };

    CShapeColor.prototype.lighten  = function () {
        return this.getColorData(0.4);
    };

    CShapeColor.prototype.lightenLess = function()
    {
        return this.getColorData(0.2);
    };

    CShapeColor.prototype.norm  = function(a){
        return this;
    };
    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].CShapeColor = CShapeColor;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {

// Import
var c_oAscSizeRelFromH = AscCommon.c_oAscSizeRelFromH;
var c_oAscSizeRelFromV = AscCommon.c_oAscSizeRelFromV;
var c_oAscLockTypes = AscCommon.c_oAscLockTypes;
var parserHelp = AscCommon.parserHelp;
var isRealObject = AscCommon.isRealObject;
    var History = AscCommon.History;

var c_oAscError = Asc.c_oAscError;
var c_oAscChartTitleShowSettings = Asc.c_oAscChartTitleShowSettings;
var c_oAscChartHorAxisLabelShowSettings = Asc.c_oAscChartHorAxisLabelShowSettings;
var c_oAscChartVertAxisLabelShowSettings = Asc.c_oAscChartVertAxisLabelShowSettings;
var c_oAscChartLegendShowSettings = Asc.c_oAscChartLegendShowSettings;
var c_oAscChartDataLabelsPos = Asc.c_oAscChartDataLabelsPos;
var c_oAscGridLinesSettings = Asc.c_oAscGridLinesSettings;
var c_oAscChartTypeSettings = Asc.c_oAscChartTypeSettings;
var c_oAscRelativeFromH = Asc.c_oAscRelativeFromH;
var c_oAscRelativeFromV = Asc.c_oAscRelativeFromV;
var c_oAscFill = Asc.c_oAscFill;


var HANDLE_EVENT_MODE_HANDLE = 0;
var HANDLE_EVENT_MODE_CURSOR = 1;

var DISTANCE_TO_TEXT_LEFTRIGHT = 3.2;

    var BAR_DIR_BAR = 0;
    var BAR_DIR_COL = 1;

    var BAR_GROUPING_CLUSTERED = 0;
    var BAR_GROUPING_PERCENT_STACKED = 1;
    var BAR_GROUPING_STACKED = 2;
    var BAR_GROUPING_STANDARD = 3;

    var GROUPING_PERCENT_STACKED = 0;
    var GROUPING_STACKED = 1;
    var GROUPING_STANDARD = 2;

    var SCATTER_STYLE_LINE = 0;
    var SCATTER_STYLE_LINE_MARKER = 1;
    var SCATTER_STYLE_MARKER = 2;
    var SCATTER_STYLE_NONE = 3;
    var SCATTER_STYLE_SMOOTH = 4;
    var SCATTER_STYLE_SMOOTH_MARKER = 5;

    var CARD_DIRECTION_N = 0;
    var CARD_DIRECTION_NE = 1;
    var CARD_DIRECTION_E = 2;
    var CARD_DIRECTION_SE = 3;
    var CARD_DIRECTION_S = 4;
    var CARD_DIRECTION_SW = 5;
    var CARD_DIRECTION_W = 6;
    var CARD_DIRECTION_NW = 7;

    var CURSOR_TYPES_BY_CARD_DIRECTION = [];
    CURSOR_TYPES_BY_CARD_DIRECTION[CARD_DIRECTION_N]  = "n-resize";
    CURSOR_TYPES_BY_CARD_DIRECTION[CARD_DIRECTION_NE] = "ne-resize";
    CURSOR_TYPES_BY_CARD_DIRECTION[CARD_DIRECTION_E]  = "e-resize";
    CURSOR_TYPES_BY_CARD_DIRECTION[CARD_DIRECTION_SE] = "se-resize";
    CURSOR_TYPES_BY_CARD_DIRECTION[CARD_DIRECTION_S]  = "s-resize";
    CURSOR_TYPES_BY_CARD_DIRECTION[CARD_DIRECTION_SW] = "sw-resize";
    CURSOR_TYPES_BY_CARD_DIRECTION[CARD_DIRECTION_W]  = "w-resize";
    CURSOR_TYPES_BY_CARD_DIRECTION[CARD_DIRECTION_NW] = "nw-resize";

    function fillImage(image, rasterImageId, x, y, extX, extY)
    {
        image.setSpPr(new AscFormat.CSpPr());
        image.spPr.setParent(image);
        image.spPr.setGeometry(AscFormat.CreateGeometry("rect"));
        image.spPr.setXfrm(new AscFormat.CXfrm());
        image.spPr.xfrm.setParent(image.spPr);
        image.spPr.xfrm.setOffX(x);
        image.spPr.xfrm.setOffY(y);
        image.spPr.xfrm.setExtX(extX);
        image.spPr.xfrm.setExtY(extY);

        var blip_fill = new AscFormat.CBlipFill();
        blip_fill.setRasterImageId(rasterImageId);
        blip_fill.setStretch(true);
        image.setBlipFill(blip_fill);
        image.setNvPicPr(new AscFormat.UniNvPr());
        image.setNoChangeAspect(true);
        image.setBDeleted(false);
    }

    function removeDPtsFromSeries(series)
    {
        if(Array.isArray(series.dPt))
        {
            for(var i = series.dPt.length - 1; i > -1; --i)
            {
                series.removeDPt(i);
            }
        }
    }

    function fApproxEqual(a, b, fDelta){
        if ( a === b ) {
            return true;
        }
        if(AscFormat.isRealNumber(fDelta)){
            return Math.abs( a - b ) < fDelta;
        }
        return Math.abs( a - b ) < 1e-15;
    }


	function fSolveQuadraticEquation(a, b, c){
		var oResult = {x1: null, x2: null, bError: true};
		var D = b*b - 4*a*c;
        if(D < 0){
            return oResult;
        }
		oResult.bError = false;
        oResult.x1 = (-b + Math.sqrt(D))/(2*a);
        oResult.x2 = (-b - Math.sqrt(D))/(2*a);
		return oResult;
	}

    function fCheckBoxIntersectionSegment(fX, fY, fWidth, fHeight, x1, y1, x2, y2){
        return fCheckSegementIntersection(fX, fY, fX + fWidth, fY, x1, y1, x2, y2) ||
            fCheckSegementIntersection(fX + fWidth, fY, fX + fWidth, fY + fHeight, x1, y1, x2, y2) ||
            fCheckSegementIntersection(fX + fWidth, fY + fHeight, fX, fY + fHeight, x1, y1, x2, y2) ||
            fCheckSegementIntersection(fX, fY + fHeight, fX, fY, x1, y1, x2, y2);

    }

    function fCheckSegementIntersection(x11, y11, x12, y12, x21, y21, x22, y22){
        //check bounding boxes intersection
        if(Math.max(x11, x12) < Math.min(x21, x22)){
            return false;
        }
        if(Math.min(x11, x12) > Math.max(x21, x22)){
            return false;
        }
        if(Math.max(y11, y12) < Math.min(y21, y22)){
            return false;
        }
        if(Math.min(y11, y12) > Math.max(y21, y22)){
            return false;
        }

        var oCoeffs = fResolve2LinearSystem(x12-x11, -(x22-x21), y12-y11, -(y22-y21), x21-x11, y21-y11);
        if(oCoeffs.bError){
            return false;
        }
        return (oCoeffs.x1 >= 0 && oCoeffs.x1 <= 1
            && oCoeffs.x2 >= 0 && oCoeffs.x2 <= 1);
    }


    function fResolve2LinearSystem(a11, a12, a21, a22, t1, t2){
        var oResult = {bError: true};
        var D = a11*a22 - a12*a21;
        if(fApproxEqual(D,  0)){
            return oResult;
        }
        oResult.bError = false;
        oResult.x1 = (t1*a22 - a12*t2)/D;
        oResult.x2 = (a11*t2 - t1*a21)/D;
        return oResult;
    }

    function checkParagraphDefFonts(map, par)
    {
        par && par.Pr && par.Pr.DefaultRunPr && checkRFonts(map, par.Pr.DefaultRunPr.RFonts);
    }
    function checkTxBodyDefFonts(map, txBody)
    {
        txBody && txBody.content && txBody.content.Content[0] && checkParagraphDefFonts(map, txBody.content.Content[0]);
    }

    function checkRFonts(map, rFonts)
    {
        if(rFonts)
        {
            if(rFonts.Ascii && typeof rFonts.Ascii.Name && rFonts.Ascii.Name.length > 0)
                map[rFonts.Ascii.Name] = true;
            if(rFonts.EastAsia && typeof rFonts.EastAsia.Name && rFonts.EastAsia.Name.length > 0)
                map[rFonts.EastAsia.Name] = true;
            if(rFonts.CS && typeof rFonts.CS.Name && rFonts.CS.Name.length > 0)
                map[rFonts.CS.Name] = true;
            if(rFonts.HAnsi && typeof rFonts.HAnsi.Name && rFonts.HAnsi.Name.length > 0)
                map[rFonts.HAnsi.Name] = true;
        }
    }

function CheckShapeBodyAutoFitReset(oShape, bNoResetRelSize)
{
    var oParaDrawing = AscFormat.getParaDrawing(oShape);
    if(oParaDrawing && !(bNoResetRelSize === true))
    {
        if(oParaDrawing.SizeRelH)
        {
            oParaDrawing.SetSizeRelH(undefined);
        }
        if(oParaDrawing.SizeRelV)
        {
            oParaDrawing.SetSizeRelV(undefined);
        }
    }
    if(oShape instanceof AscFormat.CShape)
    {
        var oPropsToSet = null;
        if(oShape.bWordShape)
        {
            if(!oShape.textBoxContent)
                return;
            if(oShape.bodyPr)
            {
                oPropsToSet = oShape.bodyPr.createDuplicate();
            }
            else
            {
                oPropsToSet = new AscFormat.CBodyPr();
            }
        }
        else
        {
            if(!oShape.txBody)
                return;
            if(oShape.txBody.bodyPr)
            {
                oPropsToSet = oShape.txBody.bodyPr.createDuplicate();
            }
            else
            {
                oPropsToSet = new AscFormat.CBodyPr();
            }
        }
        var oBodyPr = oShape.getBodyPr();
        if(oBodyPr.textFit && oBodyPr.textFit.type === AscFormat.text_fit_Auto)
        {
            if(!oPropsToSet.textFit)
            {
                oPropsToSet.textFit = new AscFormat.CTextFit();
            }
            oPropsToSet.textFit.type = AscFormat.text_fit_No;
        }
        if(oBodyPr.wrap === AscFormat.nTWTNone)
        {
            oPropsToSet.wrap = AscFormat.nTWTSquare;
        }
        if(oShape.bWordShape)
        {
           oShape.setBodyPr(oPropsToSet);
        }
        else
        {
            oShape.txBody.setBodyPr(oPropsToSet);
        }
    }
}

function CDistance(L, T, R, B)
{
    this.L = L;
    this.T = T;
    this.R = R;
    this.B = B;
}


function ConvertRelPositionHToRelSize(nRelPosition)
{
    switch(nRelPosition)
    {
        case c_oAscRelativeFromH.InsideMargin:
        {
            return c_oAscSizeRelFromH.sizerelfromhInsideMargin;
        }
        case c_oAscRelativeFromH.LeftMargin:
        {
            return c_oAscSizeRelFromH.sizerelfromhLeftMargin;
        }
        case c_oAscRelativeFromH.Margin:
        {
            return c_oAscSizeRelFromH.sizerelfromhMargin;
        }
        case c_oAscRelativeFromH.OutsideMargin:
        {
            return c_oAscSizeRelFromH.sizerelfromhOutsideMargin;
        }
        case c_oAscRelativeFromH.Page:
        {
            return c_oAscSizeRelFromH.sizerelfromhPage;
        }
        case c_oAscRelativeFromH.RightMargin:
        {
            return c_oAscSizeRelFromH.sizerelfromhRightMargin;
        }
        default:
        {
            return c_oAscSizeRelFromH.sizerelfromhPage;
        }
    }
}

function ConvertRelPositionVToRelSize(nRelPosition)
{
    switch(nRelPosition)
    {
        case c_oAscRelativeFromV.BottomMargin:
        {
            return c_oAscSizeRelFromV.sizerelfromvBottomMargin;
        }
        case c_oAscRelativeFromV.InsideMargin:
        {
            return c_oAscSizeRelFromV.sizerelfromvInsideMargin;
        }
        case c_oAscRelativeFromV.Margin:
        {
            return c_oAscSizeRelFromV.sizerelfromvMargin;
        }
        case c_oAscRelativeFromV.OutsideMargin:
        {
            return c_oAscSizeRelFromV.sizerelfromvOutsideMargin;
        }
        case c_oAscRelativeFromV.Page:
        {
            return c_oAscSizeRelFromV.sizerelfromvPage;
        }
        case c_oAscRelativeFromV.TopMargin:
        {
            return c_oAscSizeRelFromV.sizerelfromvTopMargin;
        }
        default:
        {
            return c_oAscSizeRelFromV.sizerelfromvMargin;
        }
    }
}

function ConvertRelSizeHToRelPosition(nRelSize)
{
    switch(nRelSize)
    {
        case c_oAscSizeRelFromH.sizerelfromhMargin:
        {
            return c_oAscRelativeFromH.Margin;
        }
        case c_oAscSizeRelFromH.sizerelfromhPage:
        {
            return c_oAscRelativeFromH.Page;
        }
        case c_oAscSizeRelFromH.sizerelfromhLeftMargin:
        {
            return c_oAscRelativeFromH.LeftMargin;
        }
        case c_oAscSizeRelFromH.sizerelfromhRightMargin:
        {
            return c_oAscRelativeFromH.RightMargin;
        }
        case c_oAscSizeRelFromH.sizerelfromhInsideMargin:
        {
            return c_oAscRelativeFromH.InsideMargin;
        }
        case c_oAscSizeRelFromH.sizerelfromhOutsideMargin:
        {
            return c_oAscRelativeFromH.OutsideMargin;
        }
        default:
        {
            return c_oAscRelativeFromH.Margin;
        }
    }
}


function ConvertRelSizeVToRelPosition(nRelSize)
{
    switch(nRelSize)
    {
        case c_oAscSizeRelFromV.sizerelfromvMargin:
        {
            return c_oAscRelativeFromV.Margin;
        }
        case c_oAscSizeRelFromV.sizerelfromvPage:
        {
            return c_oAscRelativeFromV.Page;
        }
        case c_oAscSizeRelFromV.sizerelfromvTopMargin:
        {
            return c_oAscRelativeFromV.TopMargin;
        }
        case c_oAscSizeRelFromV.sizerelfromvBottomMargin:
        {
            return c_oAscRelativeFromV.BottomMargin;
        }
        case c_oAscSizeRelFromV.sizerelfromvInsideMargin:
        {
            return c_oAscRelativeFromV.InsideMargin;
        }
        case c_oAscSizeRelFromV.sizerelfromvOutsideMargin:
        {
            return c_oAscRelativeFromV.OutsideMargin;
        }
        default:
        {
            return c_oAscRelativeFromV.Margin;
        }
    }
}

function checkObjectInArray(aObjects, oObject)
{
    var i;
    for(i = 0; i < aObjects.length; ++i)
    {
        if(aObjects[i] === oObject)
        {
            return;
        }
    }
    aObjects.push(oObject);
}
function getValOrDefault(val, defaultVal)
{

    if(val !== null && val !== undefined)
    {
        if(val > 558.7)
            return 0;
        return val;
    }
    return defaultVal;
}

function checkInternalSelection(selection)
{
    return !!(selection.groupSelection || selection.chartSelection || selection.textSelection);
}


function CheckStockChart(oDrawingObjects, oApi)
{
    var selectedObjectsByType = oDrawingObjects.getSelectedObjectsByTypes();
    if(selectedObjectsByType.charts[0])
    {
        var chartSpace = selectedObjectsByType.charts[0];
        if(chartSpace && chartSpace.chart && chartSpace.chart.plotArea && chartSpace.chart.plotArea.charts[0] && chartSpace.chart.plotArea.charts[0].getObjectType() !== AscDFH.historyitem_type_StockChart)
        {
            if(chartSpace.chart.plotArea.charts[0].series.length !== 4)
            {
                oApi.sendEvent("asc_onError", c_oAscError.ID.StockChartError, c_oAscError.Level.NoCritical);
                oApi.WordControl.m_oLogicDocument.Document_UpdateInterfaceState();
                return false;
            }
        }
    }
    return true;
}

function CheckLinePreset(preset)
{
    return CheckLinePresetForParagraphAdd(preset);
}

function CheckLinePresetForParagraphAdd(preset)
{
    return preset === "line" ||
    preset === "bentConnector2" ||
    preset === "bentConnector3" ||
    preset === "bentConnector4" ||
    preset === "bentConnector5" ||
    preset === "curvedConnector2" ||
    preset === "curvedConnector3" ||
    preset === "curvedConnector4" ||
    preset === "curvedConnector5" ||
    preset === "straightConnector1";

}

function CompareGroups(a, b)
{
    if(a.group == null && b.group == null)
        return 0;
    if(a.group == null)
        return 1;
    if(b.group == null)
        return -1;

    var count1 = 0;
    var cur_group = a.group;
    while(cur_group != null)
    {
        ++count1;
        cur_group = cur_group.group;
    }
    var count2 = 0;
    cur_group = b.group;
    while(cur_group != null)
    {
        ++count2;
        cur_group = cur_group.group;
    }
    return count1 - count2;
}

function CheckSpPrXfrm(object, bNoResetAutofit)
{
    if(!object.spPr)
    {
        object.setSpPr(new AscFormat.CSpPr());
        object.spPr.setParent(object);
    }
    if(!object.spPr.xfrm)
    {
        object.spPr.setXfrm(new AscFormat.CXfrm());
        object.spPr.xfrm.setParent(object.spPr);
        object.spPr.xfrm.setOffX(object.x);
        object.spPr.xfrm.setOffY(object.y);
        object.spPr.xfrm.setExtX(object.extX);
        object.spPr.xfrm.setExtY(object.extY);
        if(bNoResetAutofit !== true)
        {
            CheckShapeBodyAutoFitReset(object);
        }
    }
}


function CheckSpPrXfrm2(object)
{
    if(!object)
        return;
    if(!object.spPr)
    {
        object.spPr = new AscFormat.CSpPr();
        object.spPr.parent = object;
    }
    if(!object.spPr.xfrm)
    {
        object.spPr.xfrm = new AscFormat.CXfrm();
        object.spPr.xfrm.parent = object.spPr;
        object.spPr.xfrm.offX = 0;//object.x;
        object.spPr.xfrm.offY = 0;//object.y;
        object.spPr.xfrm.extX = object.extX;
        object.spPr.xfrm.extY = object.extY;
    }

}
    function CheckSpPrXfrm3(object)
    {
        if(object.recalcInfo && object.recalcInfo.recalculateTransform){
            return;
        }
        if(!object.spPr)
        {
            object.setSpPr(new AscFormat.CSpPr());
            object.spPr.setParent(object);
        }
        if(!object.spPr.xfrm) {
            object.spPr.setXfrm(new AscFormat.CXfrm());
            object.spPr.xfrm.setParent(object.spPr);
        }
        object.spPr.xfrm.setOffX(object.x);
        object.spPr.xfrm.setOffY(object.y);
        object.spPr.xfrm.setExtX(object.extX);
        object.spPr.xfrm.setExtY(object.extY);
    }

function getObjectsByTypesFromArr(arr, bGrouped)
{
    var ret = {shapes: [], images: [], groups: [], charts: [], tables: [], oleObjects: []};
    var selected_objects = arr;
    for(var i = 0;  i < selected_objects.length; ++i)
    {
        var drawing = selected_objects[i];
        var type = drawing.getObjectType();
        switch(type)
        {
            case AscDFH.historyitem_type_Shape:
            case AscDFH.historyitem_type_Cnx:
            {
                ret.shapes.push(drawing);
                break;
            }
            case AscDFH.historyitem_type_ImageShape:
            {
                ret.images.push(drawing);
                break;
            }
            case AscDFH.historyitem_type_OleObject:
            {
                ret.oleObjects.push(drawing);
                break;
            }
            case AscDFH.historyitem_type_GroupShape:
            {
                ret.groups.push(drawing);
                if(bGrouped)
                {
                    var by_types = getObjectsByTypesFromArr(drawing.spTree, true);
                    ret.shapes = ret.shapes.concat(by_types.shapes);
                    ret.images = ret.images.concat(by_types.images);
                    ret.charts = ret.charts.concat(by_types.charts);
                    ret.tables = ret.tables.concat(by_types.tables);
                    ret.oleObjects = ret.oleObjects.concat(by_types.oleObjects);
                }
                break;
            }
            case AscDFH.historyitem_type_ChartSpace:
            {
                ret.charts.push(drawing);
                break;
            }
            case AscDFH.historyitem_type_GraphicFrame:
            {
                ret.tables.push(drawing);
                break;
            }
        }
    }
    return ret;
}

function CreateBlipFillUniFillFromUrl(url)
{
    var ret = new AscFormat.CUniFill();
    ret.setFill(CreateBlipFillRasterImageId(url));
    return ret;
}

function CreateBlipFillRasterImageId(url)
{
    var oBlipFill = new AscFormat.CBlipFill();
    oBlipFill.setRasterImageId(url);
    return oBlipFill;
}

function getTargetTextObject(controller)
{
    if(controller.selection.textSelection)
    {
        return  controller.selection.textSelection;
    }
    else if(controller.selection.groupSelection )
    {
        if(controller.selection.groupSelection.selection.textSelection)
        {
            return controller.selection.groupSelection.selection.textSelection;
        }
        else if(controller.selection.groupSelection.selection.chartSelection && controller.selection.groupSelection.selection.chartSelection.selection.textSelection)
        {
            return controller.selection.groupSelection.selection.chartSelection.selection.textSelection;
        }
    }
    else if(controller.selection.chartSelection && controller.selection.chartSelection.selection.textSelection)
    {
        return controller.selection.chartSelection.selection.textSelection;
    }
    return null;
}


function isConnectorPreset(sPreset){
        if(typeof sPreset === "string" && sPreset.length > 0){
            if(sPreset === "flowChartOffpageConnector" || sPreset === "flowChartConnector"){
                return false;
            }
            return (sPreset.toLowerCase().indexOf("line") > -1 || sPreset.toLowerCase().indexOf("connector") > -1);
        }
        return false;
}

function DrawingObjectsController(drawingObjects)
{
    this.drawingObjects = drawingObjects;

    this.curState = new AscFormat.NullState(this);

    this.selectedObjects = [];
    this.drawingDocument = drawingObjects.drawingDocument;
    this.selection =
    {
        selectedObjects: [],
        groupSelection: null,
        chartSelection: null,
        textSelection: null
    };
    this.arrPreTrackObjects = [];
    this.arrTrackObjects = [];

    this.objectsForRecalculate = {};

    this.chartForProps = null;

    this.handleEventMode = HANDLE_EVENT_MODE_HANDLE;
}

function CanStartEditText(oController)
{
    var oSelector = oController.selection.groupSelection ? oController.selection.groupSelection : oController;
    if(oSelector.selectedObjects.length === 1 && oSelector.selectedObjects[0].getObjectType() === AscDFH.historyitem_type_Shape)
    {
        return true;
    }
    return false;
}

DrawingObjectsController.prototype =
{

    checkDrawingHyperlink: function(drawing, e, hit_in_text_rect, x, y, pageIndex){
        var oApi = this.getEditorApi();
        if(!oApi){
            return;
        }


        //
        // if( this.document || (this.drawingObjects.cSld && !(this.noNeedUpdateCursorType === true)) )
        // {
        //     var nPageIndex = pageIndex;
        //     if(this.drawingObjects.cSld && !( this.noNeedUpdateCursorType === true ) && AscFormat.isRealNumber(this.drawingObjects.num))
        //     {
        //         nPageIndex = this.drawingObjects.num;
        //     }
        //     content.UpdateCursorType(tx, ty, 0);
        //     ret.updated = true;
        // }
        // else if(this.drawingObjects)
        // {
        //     hit_paragraph = content.Internal_GetContentPosByXY(tx, ty, 0);
        //     par = content.Content[hit_paragraph];
        //     if(isRealObject(par))
        //     {
        //         check_hyperlink = par.CheckHyperlink(tx, ty, 0);
        //         if(isRealObject(check_hyperlink))
        //         {
        //             ret.hyperlink = check_hyperlink;
        //         }
        //     }
        // }


        var oNvPr;
        if(this.document || this.drawingObjects && this.drawingObjects.cSld){
            if(/*e.CtrlKey*/true){
                oNvPr = drawing.getNvProps();
                if(oNvPr && oNvPr.hlinkClick && oNvPr.hlinkClick.id !== null){
                    if(this.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
                        if(e.CtrlKey){
                            editor.sync_HyperlinkClickCallback(oNvPr.hlinkClick.id);
                            return true;
                        }
                    }
                    else{
                        var ret = {objectId: drawing.Get_Id(), cursorType: "move", bMarker: false};
                        if( !(this.noNeedUpdateCursorType === true))
                        {



                            var oDD = editor &&  editor.WordControl && editor.WordControl.m_oDrawingDocument;
                            if(oDD){
                                var MMData         = new AscCommon.CMouseMoveData();
                                var Coords         = oDD.ConvertCoordsToCursorWR(x, y, pageIndex, null);
                                MMData.X_abs       = Coords.X;
                                MMData.Y_abs       = Coords.Y;
                                MMData.Type      = AscCommon.c_oAscMouseMoveDataTypes.Hyperlink;
                                MMData.Hyperlink = new Asc.CHyperlinkProperty({Text: null, Value: oNvPr.hlinkClick.id, ToolTip: oNvPr.hlinkClick.tooltip, Class: null});
                                editor.sync_MouseMoveCallback(MMData);
                                if(hit_in_text_rect)
                                {
                                    ret.cursorType = "text";
                                    oDD.SetCursorType("text", MMData);
                                }
                                ret.updated = true;
                            }
                        }
                        return ret;
                    }
                }
            }
        }
        else if(this.drawingObjects && this.drawingObjects.getWorksheetModel){
            if(/*!drawing.selected*/ true){
                oNvPr = drawing.getNvProps();
                if(oNvPr && oNvPr.hlinkClick && oNvPr.hlinkClick.id !== null){

                    if(this.handleEventMode === HANDLE_EVENT_MODE_HANDLE) {
                        if(e.CtrlKey){
                            // var wsModel = this.drawingObjects.getWorksheetModel();
                            //
                            // var _link = oNvPr.hlinkClick.id;
                            // var newHyperlink = new AscCommonExcel.Hyperlink();
                            // if (_link.search('#') === 0) {
                            //     var sLink2 = _link.replace('#', '');
                            //     newHyperlink.setLocation(sLink2);
                            //     var aRanges = AscCommonExcel.getRangeByRef(sLink2, wsModel);
                            //     newHyperlink.Ref = aRanges[0];
                            // }
                            // else {
                            //     newHyperlink.Hyperlink = _link;
                            // }
                            // newHyperlink.Tooltip = oNvPr.hlinkClick.tooltip;
                            // var ascHyperlink = new Asc.asc_CHyperlink();
                            // ascHyperlink.hyperlinkModel = newHyperlink;
                            // oApi._asc_setWorksheetRange(ascHyperlink);
                            //newHyperlink.Ref.setHyperlink(newHyperlink);
                            // return AscCommonExcel.getRangeByRef(sFormula, this.worksheet);
                            // editor.sync_HyperlinkClickCallback(oNvPr.hlinkClick.id);
                            return true;
                        }
                        else{
                            return false;
                        }
                    }
                    else{

                        var _link = oNvPr.hlinkClick.id;
                        var sLink2;
                        if (_link.search('#') === 0) {
                            sLink2 = _link.replace('#', '');
                        }
                        else {
                            sLink2 = _link;
                        }
                        var oHyperlink = AscFormat.ExecuteNoHistory(function(){return new ParaHyperlink();}, this, []);
                        oHyperlink.Value = sLink2;
                        oHyperlink.Tooltip = oNvPr.hlinkClick.tooltip;
                        if(hit_in_text_rect){
                            return {objectId: drawing.Get_Id(), cursorType: "text", bMarker: false, hyperlink: oHyperlink};
                        }
                        else{
                            return {objectId: drawing.Get_Id(), cursorType: "move", bMarker: false, hyperlink: oHyperlink};
                        }
                    }
                }
            }
        }
        if(this.handleEventMode === HANDLE_EVENT_MODE_HANDLE) {
            return false;
        }
        else{
            return null;
        }
    },

    getAllSignatures: function(){
        var _ret = [];
        this.getAllSignatures2(_ret, this.getDrawingArray());
        return _ret;
    },

    getAllSignatures2: function(aRet, spTree){
        var aSp = [];
        for(var i = 0; i < spTree.length; ++i){
            if(spTree[i].getObjectType() === AscDFH.historyitem_type_GroupShape){
                aSp = aSp.concat(this.getAllSignatures2(aRet, spTree[i].spTree));
            }
            else if(spTree[i].signatureLine){
                aRet.push(spTree[i].signatureLine);
                aSp.push(spTree[i]);
            }
        }
        return aSp;
    },

    getDefaultText: function(){
        return  AscCommon.translateManager.getValue('Your text here');
    },

    getAllConnectors: function(aDrawings, allDrawings){
        var _ret = allDrawings;
        if(!_ret){
            _ret = [];
        }
        for(var i = 0; i < aDrawings.length; ++i){
            if(aDrawings[i].getObjectType() === AscDFH.historyitem_type_Cnx){
                _ret.push(aDrawings[i]);
            }
            else if(aDrawings[i].getObjectType() === AscDFH.historyitem_type_GroupShape){
                aDrawings[i].getAllConnectors(aDrawings[i].spTree, _ret);
            }
        }
        return _ret;
    },

    getAllShapes:  function(aDrawings, allDrawings){
        var _ret = allDrawings;
        if(!_ret){
            _ret = [];
        }
        for(var i = 0; i < aDrawings.length; ++i){
            if(aDrawings[i].getObjectType() === AscDFH.historyitem_type_Shape){
                _ret.push(aDrawings[i]);
            }
            else if(aDrawings[i].getObjectType() === AscDFH.historyitem_type_GroupShape){
                aDrawings[i].getAllShapes(aDrawings[i].spTree, _ret);
            }
        }
        return _ret;
    },

    getAllConnectorsByDrawings: function(aDrawings, result,  aConnectors, bInsideGroup){
        var _ret;
        if(Array.isArray(result)){
            _ret = result;
        }
        else{
            _ret = [];
        }
        var _aConnectors;
        if(Array.isArray(aConnectors)){
            _aConnectors = aConnectors;
        }
        else{
            _aConnectors = this.getAllConnectors(this.getDrawingArray(), []);
        }
        for(var i = 0; i < _aConnectors.length; ++i){
            for(var j = 0; j < aDrawings.length; ++j){
                if(aDrawings[j].getObjectType() === AscDFH.historyitem_type_GroupShape){
                    if(bInsideGroup){
                        this.getAllConnectorsByDrawings(aDrawings[j].spTree, _ret, _aConnectors, bInsideGroup);
                    }
                }
                else{
                    if(aDrawings[j].Get_Id() === _aConnectors[i].getStCxnId() || aDrawings[j].Get_Id() === _aConnectors[i].getEndCxnId()){
                        _ret.push(_aConnectors[i]);
                    }
                }
            }
        }
        return _ret;
    },

    getAllSingularDrawings: function(aDrawings, _ret){
        for(var i = 0; i < aDrawings.length; ++i){
            if(aDrawings[i].getObjectType() === AscDFH.historyitem_type_GroupShape){
                this.getAllSingularDrawings(aDrawings[i].spTree, _ret);
            }
            else{
                _ret.push(aDrawings[i]);
            }
        }
    },

    checkConnectorsPreTrack: function(){

        if(this.arrPreTrackObjects.length > 0 && this.arrPreTrackObjects[0].originalObject && this.arrPreTrackObjects[0].overlayObject){

            var aAllConnectors = this.getAllConnectors(this.getDrawingArray());
            var oPreTrack;
            var stId = null, endId = null, oBeginTrack = null, oEndTrack = null, oBeginShape = null, oEndShape = null;
            var aConnectionPreTracks = [];
            for(var i = 0; i < aAllConnectors.length; ++i){
                stId = aAllConnectors[i].getStCxnId();
                endId = aAllConnectors[i].getEndCxnId();
                oBeginTrack = null;
                oEndTrack = null;
                oBeginShape = null;
                oEndShape = null;

                if(stId !== null || endId !== null){
                    for(var j = 0; j < this.arrPreTrackObjects.length; ++j){
                        if(this.arrPreTrackObjects[j].originalObject === aAllConnectors[i]){
                            oEndTrack = null;
                            oBeginTrack = null;
                            break;
                        }
                        oPreTrack = this.arrPreTrackObjects[j].originalObject;
                        if(oPreTrack.Id === stId){
                            oBeginTrack = this.arrPreTrackObjects[j];
                        }
                        if(oPreTrack.Id === endId){
                            oEndTrack = this.arrPreTrackObjects[j];
                        }
                    }
                }
                if(oBeginTrack || oEndTrack){

                    if(oBeginTrack){
                        oBeginShape = oBeginTrack.originalObject;
                    }
                    else{
                        if(stId !== null){
                            oBeginShape = AscCommon.g_oTableId.Get_ById(stId);
                            if(oBeginShape && oBeginShape.bDeleted){
                                oBeginShape = null;
                            }
                        }
                    }
                    if(oEndTrack){
                        oEndShape = oEndTrack.originalObject;
                    }
                    else if(endId !== null){
                        oEndShape = AscCommon.g_oTableId.Get_ById(endId);
                        if(oEndShape && oEndShape.bDeleted){
                            oEndShape = null;
                        }
                    }
                    aConnectionPreTracks.push(new AscFormat.CConnectorTrack(aAllConnectors[i], oBeginTrack, oEndTrack, oBeginShape, oEndShape));
                }
            }
            for(i = 0; i < aConnectionPreTracks.length; ++i){
                this.arrPreTrackObjects.push(aConnectionPreTracks[i]);
            }
        }
    },

    //for mobile spreadsheet editor
    startEditTextCurrentShape: function()
    {
        if(!CanStartEditText(this))
        {
            return;
        }
        var oSelector = this.selection.groupSelection ? this.selection.groupSelection : this;
        var oShape = oSelector.selectedObjects[0];
        var oContent = oShape.getDocContent();
        if(oContent)
        {
            oSelector.resetInternalSelection();
            oSelector.selection.textSelection = oShape;
            oContent.MoveCursorToEndPos(false);
            this.updateSelectionState();
            this.updateOverlay();
        }
        else
        {
            var oThis = this;
            this.checkSelectedObjectsAndCallback(function(){
                oShape.createTextBody();
                var oContent = oShape.getDocContent();
                oSelector.resetInternalSelection();
                oSelector.selection.textSelection = oShape;
                oContent.MoveCursorToEndPos(false);
                oThis.updateSelectionState();
            }, [], false, AscDFH.historydescription_Spreadsheet_AddNewParagraph);
        }
    },

    canReceiveKeyPress: function()
    {
        return this.curState instanceof AscFormat.NullState;
    },

    handleAdjustmentHit: function(hit, selectedObject, group, pageIndex, bWord)
    {
        if(this.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
        {
            this.arrPreTrackObjects.length = 0;
            if(hit.adjPolarFlag === false)
            {
                this.arrPreTrackObjects.push(new AscFormat.XYAdjustmentTrack(selectedObject, hit.adjNum, hit.warp));
            }
            else
            {
                this.arrPreTrackObjects.push(new AscFormat.PolarAdjustmentTrack(selectedObject, hit.adjNum, hit.warp));
            }
            if(!isRealObject(group))
            {

                this.resetInternalSelection();
                this.changeCurrentState(new AscFormat.PreChangeAdjState(this, selectedObject));
            }
            else
            {
                group.resetInternalSelection();
                this.changeCurrentState(new AscFormat.PreChangeAdjInGroupState(this, group));
            }
            return true;
        }
        else
        {
            if(!isRealObject(group))
                return {objectId: selectedObject.Get_Id(), cursorType: "crosshair", bMarker: true};
            else
                return {objectId: selectedObject.Get_Id(), cursorType: "crosshair", bMarker: true};
        }
    },

    handleSlideComments: function(e, x, y, pageIndex)
    {
        if(this.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
        {
            return {result: null, selectedIndex: -1};
        }
        else
        {
            return {result: false, selectedIndex: -1};
        }
    },

    handleSignatureDblClick: function(sGuid, width, height){
        var oApi = editor || Asc['editor'];
        if(oApi){
            oApi.sendEvent("asc_onSignatureDblClick", sGuid, width, height);
        }
    },

    checkChartForProps: function(bStart)
    {
        if(bStart)
        {
            if(this.selectedObjects.length === 0){
                this.chartForProps = null;
                return;
            }
            this.chartForProps = this.getSelectionState();
            this.resetSelection();
            this.drawingObjects.getWorksheet().endEditChart();
            var oldIsStartAdd = window["Asc"]["editor"].isStartAddShape;
            window["Asc"]["editor"].isStartAddShape = true;
            this.updateOverlay();
            window["Asc"]["editor"].isStartAddShape = oldIsStartAdd;
        }
        else
        {
            if(this.chartForProps === null){
                return;
            }
            this.setSelectionState(this.chartForProps, this.chartForProps.length - 1);
            this.updateOverlay();
            this.drawingObjects.getWorksheet().setSelectionShape(true);
            this.chartForProps = null;
        }

    },

    resetInternalSelection: function(noResetContentSelect)
    {
        if(this.selection.groupSelection)
        {
            this.selection.groupSelection.resetSelection(this);
            this.selection.groupSelection = null;
        }
        if(this.selection.textSelection)
        {
            if(!(noResetContentSelect  === true))
            {
                if(this.selection.textSelection.getObjectType() === AscDFH.historyitem_type_GraphicFrame)
                {
                    if(this.selection.textSelection.graphicObject)
                    {
                        this.selection.textSelection.graphicObject.RemoveSelection();
                    }
                }
                else
                {
                    var content = this.selection.textSelection.getDocContent();
                    content && content.RemoveSelection();
                }
            }
            this.selection.textSelection = null;
        }
        if(this.selection.chartSelection)
        {
            this.selection.chartSelection.resetSelection(noResetContentSelect);
            this.selection.chartSelection = null;
        }
        if(this.selection.wrapPolygonSelection)
        {
            this.selection.wrapPolygonSelection = null;
        }
    },

    handleHandleHit: function(hit, selectedObject, group, pageIndex, bWord)
    {
        if(this.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
        {
            var selected_objects = group ? group.selectedObjects : this.selectedObjects;
            this.arrPreTrackObjects.length = 0;
            if(hit === 8)
            {
                if(selectedObject.canRotate())
                {
                    for(var i = 0; i < selected_objects.length; ++i)
                    {
                        if(selected_objects[i].canRotate())
                        {
                            this.arrPreTrackObjects.push(selected_objects[i].createRotateTrack());
                        }
                    }
                    if(!isRealObject(group))
                    {
                        this.resetInternalSelection();
                        this.updateOverlay();
                        this.changeCurrentState(new AscFormat.PreRotateState(this, selectedObject));
                    }
                    else
                    {
                        group.resetInternalSelection();
                        this.updateOverlay();
                        this.changeCurrentState(new AscFormat.PreRotateInGroupState(this, group, selectedObject));
                    }
                }
            }
            else
            {
                if(selectedObject.canResize())
                {
                    var card_direction = selectedObject.getCardDirectionByNum(hit);
                    for(var j = 0; j < selected_objects.length; ++j)
                    {
                        if(selected_objects[j].canResize())
                            this.arrPreTrackObjects.push(selected_objects[j].createResizeTrack(card_direction, selected_objects.length === 1 ? this : null));
                    }
                    if(!isRealObject(group))
                    {
                        this.resetInternalSelection();
                        this.updateOverlay();

                        this.changeCurrentState(new AscFormat.PreResizeState(this, selectedObject, card_direction));
                    }
                    else
                    {
                        group.resetInternalSelection();
                        this.updateOverlay();

                        this.changeCurrentState(new AscFormat.PreResizeInGroupState(this, group, selectedObject, card_direction));
                    }
                }
            }
            return true;
        }
        else
        {
            var card_direction = selectedObject.getCardDirectionByNum(hit);
            return {objectId: selectedObject.Get_Id(), cursorType: hit === 8 ? "crosshair" : CURSOR_TYPES_BY_CARD_DIRECTION[card_direction], bMarker: true};
        }
    },


    handleDblClickEmptyShape: function(oShape){
        this.checkSelectedObjectsAndCallback(function () {
            if(!oShape.getDocContent() && !CheckLinePresetForParagraphAdd(oShape.getPresetGeom())){
                if(!oShape.bWordShape){
                    oShape.createTextBody();
                }
                else{
                    oShape.createTextBoxContent();
                }
                this.recalculate();
                var oContent = oShape.getDocContent();
                oContent.Set_CurrentElement(0, true);
                this.updateSelectionState();
            }
        },[], false);
    },

    handleMoveHit: function(object, e, x, y, group, bInSelect, pageIndex, bWord)
    {
        var b_is_inline;
        if(isRealObject(group))
        {
            b_is_inline = group.parent && group.parent.Is_Inline && group.parent.Is_Inline();
        }
        else
        {
            b_is_inline = object.parent && object.parent.Is_Inline && object.parent.Is_Inline();
        }
        var b_is_selected_inline = this.selectedObjects.length === 1 && (this.selectedObjects[0].parent && this.selectedObjects[0].parent.Is_Inline && this.selectedObjects[0].parent.Is_Inline());
        if(this.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
        {
            var selector = group ? group : this;
            this.checkChartTextSelection();
            if(object.canMove())
            {
                this.arrPreTrackObjects.length = 0;
                var is_selected =  object.selected;
                var b_check_internal = checkInternalSelection(selector.selection);
                if(!(e.CtrlKey || e.ShiftKey) && !is_selected || b_is_inline || b_is_selected_inline)
                    selector.resetSelection();
                if(!e.CtrlKey || !object.selected){
                    selector.selectObject(object, pageIndex);
                }
                if(!is_selected || b_check_internal)
                    this.updateOverlay();
                this.checkSelectedObjectsForMove(group, pageIndex);
                if(!isRealObject(group))
                {
                    this.resetInternalSelection();
                    this.updateOverlay();
                    if(!b_is_inline)
                        this.changeCurrentState(new AscFormat.PreMoveState(this, x, y, e.ShiftKey, e.CtrlKey,  object, is_selected, /*true*/!bInSelect));
                    else
                    {
                        this.changeCurrentState(new AscFormat.PreMoveInlineObject(this, object, is_selected, !bInSelect, pageIndex, x, y));
                    }
                }
                else
                {
                    group.resetInternalSelection();
                    this.updateOverlay();
                    this.changeCurrentState(new AscFormat.PreMoveInGroupState(this, group, x, y, e.ShiftKey, e.CtrlKey, object,  is_selected));
                }
                if(e.ClickCount > 1 && !e.ShiftKey && !e.CtrlKey && ((this.selection.groupSelection && this.selection.groupSelection.selectedObjects.length === 1) || this.selectedObjects.length === 1))
                {
                    var drawing = this.selectedObjects[0].parent;

                    if (object.getObjectType() === AscDFH.historyitem_type_ChartSpace && this.handleChartDoubleClick)
                        this.handleChartDoubleClick(drawing, object, e, x, y, pageIndex);
                    if(object.getObjectType() === AscDFH.historyitem_type_Shape){
                        if(null !== object.signatureLine){
                            if(this.handleSignatureDblClick){
                                this.handleSignatureDblClick(object.signatureLine.id, object.extX, object.extY)
                            }
                        }
                        else if(this.handleDblClickEmptyShape){
                            if(!object.getDocContent()){
                                this.handleDblClickEmptyShape(object);
                            }
                        }
                    }
                    if (object.getObjectType() === AscDFH.historyitem_type_OleObject && this.handleOleObjectDoubleClick){
                        this.handleOleObjectDoubleClick(drawing, object, e, x, y, pageIndex);
                    }
                    else if (2 == e.ClickCount && drawing instanceof ParaDrawing && drawing.Is_MathEquation())
                        this.handleMathDrawingDoubleClick(drawing, e, x, y, pageIndex);
                }
            }
            return true;
        }
        else
        {
            return {objectId: object.Get_Id(), cursorType: "move", bMarker: bInSelect};
        }
    },

    recalculateCurPos: function(bUpdateX, bUpdateY)
	{
		var oTargetDocContent = this.getTargetDocContent(undefined, true);
		if (oTargetDocContent)
			return oTargetDocContent.RecalculateCurPos(bUpdateX, bUpdateY);

		return {X : 0, Y : 0, Height : 0, PageNum : 0, Internal : {Line : 0, Page : 0, Range : 0}, Transform : null};
	},

    startEditCurrentOleObject: function(){
        var oSelector = this.selection.groupSelection ? this.selection.groupSelection : this;
        var oThis = this;
        if(oSelector.selectedObjects.length === 1 && oSelector.selectedObjects[0].getObjectType() === AscDFH.historyitem_type_OleObject){
            var oleObject = oSelector.selectedObjects[0];
            this.checkSelectedObjectsAndFireCallback(function(){
                var pluginData = new Asc.CPluginData();
                pluginData.setAttribute("data", oleObject.m_sData);
                pluginData.setAttribute("guid", oleObject.m_sApplicationId);
                pluginData.setAttribute("width", oleObject.extX);
                pluginData.setAttribute("height", oleObject.extY);
                pluginData.setAttribute("widthPix", oleObject.m_nPixWidth);
                pluginData.setAttribute("heightPix", oleObject.m_nPixHeight);
                pluginData.setAttribute("objectId", oleObject.Id);

                if (window["Asc"]["editor"]) {
                    window["Asc"]["editor"].asc_pluginRun(oleObject.m_sApplicationId, 0, pluginData);
                }
                else {
                    if (editor){
                        editor.asc_pluginRun(oleObject.m_sApplicationId, 0, pluginData);
                    }
                }
            }, []);
        }
    },


    checkSelectedObjectsForMove: function(group, pageIndex)
    {
        var selected_object = group ? group.selectedObjects : this.selectedObjects;
        var b_check_page = AscFormat.isRealNumber(pageIndex);
        for(var i = 0; i < selected_object.length; ++i)
        {
            if(selected_object[i].canMove() && (!b_check_page || selected_object[i].selectStartPage === pageIndex))
            {
                this.arrPreTrackObjects.push(selected_object[i].createMoveTrack());
            }
        }
    },

    handleTextHit: function(object, e, x, y, group, pageIndex, bWord)
    {
        var content, invert_transform_text, tx, ty, hit_paragraph, par, check_hyperlink;
        if(this.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
        {
            var bNotes = (this.drawingObjects && this.drawingObjects.getObjectType && this.drawingObjects.getObjectType() === AscDFH.historyitem_type_Notes);
            if(e.CtrlKey && !this.document && !bNotes)
            {
                content = object.getDocContent();
                invert_transform_text = object.invertTransformText;
                if(content && invert_transform_text)
                {
                    tx = invert_transform_text.TransformPointX(x, y);
                    ty = invert_transform_text.TransformPointY(x, y);
                    hit_paragraph = content.Internal_GetContentPosByXY(tx, ty, 0);
                    par = content.Content[hit_paragraph];
                    if(isRealObject(par))
                    {
                        check_hyperlink = par.CheckHyperlink(tx, ty, 0);
                        if(!isRealObject(check_hyperlink))
                        {
                            return this.handleMoveHit(object, e, x, y, group, false, pageIndex, bWord);
                        }
                    }
                    else
                    {
                        return this.handleMoveHit(object, e, x, y, group, false, pageIndex, bWord);
                    }
                }
                else
                {
                    return this.handleMoveHit(object, e, x, y, group, false, pageIndex, bWord);
                }
            }
            if(!group)
            {
                if(this.selection.textSelection !== object)
                {
                    this.resetSelection(true);
                    this.selectObject(object,pageIndex);
                    this.selection.textSelection = object;
                }
            }
            else
            {
                if(this.selection.groupSelection !== group || group.selection.textSelection !== object)
                {
                    this.resetSelection(true);
                    group.selectObject(object,pageIndex);
                    this.selectObject(group, pageIndex);
                    this.selection.groupSelection = group;
                    group.selection.textSelection = object;
                }
            }


            object.selectionSetStart(e, x, y, pageIndex);

            this.changeCurrentState(new AscFormat.TextAddState(this, object, x, y));
            return true;
        }
        else
        {
            var ret = {objectId: object.Get_Id(), cursorType: "text"};
            content = object.getDocContent();
            invert_transform_text = object.invertTransformText;
            if(content && invert_transform_text)
            {
                tx = invert_transform_text.TransformPointX(x, y);
                ty = invert_transform_text.TransformPointY(x, y);
                if( this.document || (this.drawingObjects.cSld && !(this.noNeedUpdateCursorType === true)) )
                {
                    var nPageIndex = pageIndex;
                    if(this.drawingObjects.cSld && !( this.noNeedUpdateCursorType === true ) && AscFormat.isRealNumber(this.drawingObjects.num))
                    {
                        nPageIndex = this.drawingObjects.num;
                    }
                    content.UpdateCursorType(tx, ty, 0);
                    ret.updated = true;
                }
                else if(this.drawingObjects)
                {
                    hit_paragraph = content.Internal_GetContentPosByXY(tx, ty, 0);
                    par = content.Content[hit_paragraph];
                    if(isRealObject(par))
                    {
                        check_hyperlink = par.CheckHyperlink(tx, ty, 0);
                        if(isRealObject(check_hyperlink))
                        {
                            ret.hyperlink = check_hyperlink;
                        }
                    }
                }
            }
            return ret;
        }
    },


    handleRotateTrack: function(e, x, y)
    {
        var angle = this.curState.majorObject.getRotateAngle(x, y);
        this.rotateTrackObjects(angle, e);
        this.updateOverlay();
    },

    getSnapArrays: function()
    {
        var drawing_objects = this.getDrawingObjects();
        var snapX = [];
        var snapY = [];
        for(var i = 0; i < drawing_objects.length; ++i)
        {
            if(drawing_objects[i].getSnapArrays)
            {
                drawing_objects[i].getSnapArrays(snapX, snapY);
            }
        }
        return {snapX: snapX, snapY: snapY};
    },

    getLeftTopSelectedFromArray: function(aDrawings, pageIndex)
    {
        var i, dX, dY;
        for(i = aDrawings.length - 1; i > -1; --i)
        {
            if(aDrawings[i].selected && pageIndex === aDrawings[i].selectStartPage)
            {
                dX = aDrawings[i].transform.TransformPointX(aDrawings[i].extX/2, aDrawings[i].extY/2) - aDrawings[i].extX/2;
                dY = aDrawings[i].transform.TransformPointY(aDrawings[i].extX/2, aDrawings[i].extY/2) - aDrawings[i].extY/2;
                return {X: dX, Y: dY, bSelected: true, PageIndex: pageIndex};
            }
        }
        return {X: 0, Y: 0, bSelected: false, PageIndex: pageIndex};
    },

    getLeftTopSelectedObject: function(pageIndex)
    {
        return this.getLeftTopSelectedFromArray(this.getDrawingObjects(), pageIndex);
    },
	
	createWatermarkImage: function(sImageUrl)
	{
        return AscFormat.ExecuteNoHistory(function(){
            return this.createImage(sImageUrl, 0, 0, 110, 61.875);
        }, this, []);
    },


	IsSelectionUse: function(){
        var content = this.getTargetDocContent();
        if(content)
        {
            return content.IsTextSelectionUse();
        }
        else
        {
            return this.selectedObjects.length > 0;
        }
    },

    getFromTargetTextObjectContextMenuPosition: function(oTargetTextObject, pageIndex)
    {
        var oTransformText = oTargetTextObject.transformText;
        var oTargetObjectOrTable = this.getTargetDocContent(false, true);
        if(oTargetTextObject && oTargetObjectOrTable && oTargetObjectOrTable.GetCursorPosXY && oTransformText){
            var oPos = oTargetObjectOrTable.GetCursorPosXY();
            return {
                X: oTransformText.TransformPointX(oPos.X, oPos.Y),
                Y: oTransformText.TransformPointY(oPos.X, oPos.Y),
                PageIndex: pageIndex
            };
        }
        return {X: 0, Y: 0, PageIndex: pageIndex};
    },



    isPointInDrawingObjects3: function(x, y, nPageIndex, bSelected, bText)
    {
        var oOldState = this.curState;
        this.changeCurrentState(new AscFormat.NullState(this));
        var oResult, bRet = false;
        this.handleEventMode = HANDLE_EVENT_MODE_CURSOR;
        oResult = this.curState.onMouseDown(AscCommon.global_mouseEvent, x, y, 0);
        this.handleEventMode = HANDLE_EVENT_MODE_HANDLE;
        if(AscCommon.isRealObject(oResult)){
            if(oResult.cursorType !== "text"){
                var object = g_oTableId.Get_ById(oResult.objectId);
                if(AscCommon.isRealObject(object)
                    && ((bSelected && object.selected) ||  !bSelected) ){
                    bRet = true;
                }
                else
                {
                    return false;
                }
            }
            else{
                if(bText){
                    return true;
                }
            }
        }
        this.changeCurrentState(oOldState);
        return bRet;
    },


    isPointInDrawingObjects4: function(x, y, pageIndex){
        var oOldState = this.curState;
        this.changeCurrentState(new AscFormat.NullState(this));
        var oResult, nRet = 0;
        this.handleEventMode = HANDLE_EVENT_MODE_CURSOR;
        oResult = this.curState.onMouseDown(AscCommon.global_mouseEvent, x, y, 0);
        this.handleEventMode = HANDLE_EVENT_MODE_HANDLE;
        var object;
        if(AscCommon.isRealObject(oResult)){
            if(oResult.cursorType === "text"){
                nRet = 1;
            }
            else if(oResult.cursorType === "move"){
                object = g_oTableId.Get_ById(oResult.objectId);
                if(object && object.hitInBoundingRect && object.hitInBoundingRect(x, y)){
                    nRet = 3;
                }
                else{
                    nRet = 2;
                }
            }
            else{
                nRet = 3;
            }
        }
        this.changeCurrentState(oOldState);
        return nRet;
    },

	GetSelectionBounds: function()
    {
        var oTargetDocContent = this.getTargetDocContent(false, true);
        if(isRealObject(oTargetDocContent))
        {
            return oTargetDocContent.GetSelectionBounds();
        }
        return null;
    },


    CreateDocContent: function(){
        var oController = this;
        if(this.selection.groupSelection){
            oController = this.selection.groupSelection;
        }
        if(oController.selection.textSelection){
            return;
        }
        if(oController.selection.chartSelection){
           if(oController.selection.chartSelection.selection.textSelection){
               oController.selection.chartSelection.selection.textSelection.checkDocContent && oController.selection.chartSelection.selection.textSelection.checkDocContent();
               return;
           }
        }
        if(oController.selectedObjects.length === 1 ){
            if(oController.selectedObjects[0].getObjectType() === AscDFH.historyitem_type_Shape){
                var oShape = oController.selectedObjects[0];
                if(oShape.bWordShape){
                    if(!oShape.textBoxContent){
                        oShape.createTextBoxContent();
                    }
                }
                else{
                    if(!oShape.txBody){
                        oShape.createTextBody();
                    }
                }
                oController.selection.textSelection = oShape;
            }
            else{
                if(oController.selection.chartSelection && oController.selection.chartSelection.selection.title){
                    oController.selection.chartSelection.selection.textSelection = oController.selection.chartSelection.selection.title;
                    oController.selection.chartSelection.selection.textSelection.checkDocContent && oController.selection.chartSelection.selection.textSelection.checkDocContent();
                }
            }
        }
    },

    getContextMenuPosition: function(pageIndex)
    {
        var i, aDrawings, dX, dY, oTargetTextObject;
        if(this.selectedObjects.length > 0)
        {
            oTargetTextObject = getTargetTextObject(this);
            if(oTargetTextObject)
            {
                return this.getFromTargetTextObjectContextMenuPosition(oTargetTextObject, pageIndex);

            }
            else if(this.selection.groupSelection)
            {
                aDrawings = this.selection.groupSelection.arrGraphicObjects;
                for(i = aDrawings.length-1; i > -1; --i)
                {
                    if(aDrawings[i].selected)
                    {
                        dX = aDrawings[i].transform.TransformPointX(aDrawings[i].extX/2, aDrawings[i].extY/2) - aDrawings[i].extX/2;
                        dY = aDrawings[i].transform.TransformPointY(aDrawings[i].extX/2, aDrawings[i].extY/2) - aDrawings[i].extY/2;
                        return {X: dX, Y: dY, PageIndex: this.selection.groupSelection.selectStartPage};
                    }
                }
            }
            else
            {
                return this.getLeftTopSelectedObject(pageIndex);
            }
        }

        return {X: 0, Y: 0, PageIndex: pageIndex};
    },

    drawSelect: function(pageIndex, drawingDocument)
    {
		if (undefined !== drawingDocument.BeginDrawTracking)
            drawingDocument.BeginDrawTracking();
		
        var i;
        if(this.selection.textSelection)
        {
            if(this.selection.textSelection.selectStartPage === pageIndex)
            {
                drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.TEXT, this.selection.textSelection.getTransformMatrix(), 0, 0, this.selection.textSelection.extX, this.selection.textSelection.extY, AscFormat.CheckObjectLine(this.selection.textSelection), this.selection.textSelection.canRotate());
                if(this.selection.textSelection.drawAdjustments)
                    this.selection.textSelection.drawAdjustments(drawingDocument);
            }
        }
        else if(this.selection.groupSelection)
        {
            if(this.selection.groupSelection.selectStartPage === pageIndex)
            {
                drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.GROUP_PASSIVE, this.selection.groupSelection.getTransformMatrix(), 0, 0, this.selection.groupSelection.extX, this.selection.groupSelection.extY, false, this.selection.groupSelection.canRotate());
                if(this.selection.groupSelection.selection.textSelection)
                {
                    for(i = 0; i < this.selection.groupSelection.selectedObjects.length ; ++i)
                    {
                        drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.TEXT, this.selection.groupSelection.selectedObjects[i].transform, 0, 0, this.selection.groupSelection.selectedObjects[i].extX, this.selection.groupSelection.selectedObjects[i].extY, AscFormat.CheckObjectLine(this.selection.groupSelection.selectedObjects[i]), this.selection.groupSelection.selectedObjects[i].canRotate());
                    }
                }
                else if(this.selection.groupSelection.selection.chartSelection)
                {
                    this.selection.groupSelection.selection.chartSelection.drawSelect(drawingDocument, pageIndex);
                }
                else
                {
                    for(i = 0; i < this.selection.groupSelection.selectedObjects.length ; ++i)
                    {
                        drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.SHAPE, this.selection.groupSelection.selectedObjects[i].transform, 0, 0, this.selection.groupSelection.selectedObjects[i].extX, this.selection.groupSelection.selectedObjects[i].extY, AscFormat.CheckObjectLine(this.selection.groupSelection.selectedObjects[i]), this.selection.groupSelection.selectedObjects[i].canRotate());
                    }
                }

                if(this.selection.groupSelection.selectedObjects.length === 1 && this.selection.groupSelection.selectedObjects[0].drawAdjustments)
                {
                    this.selection.groupSelection.selectedObjects[0].drawAdjustments(drawingDocument);
                }
            }
        }
        else if(this.selection.chartSelection)
        {
            this.selection.chartSelection.drawSelect(drawingDocument, pageIndex);
        }
        else if(this.selection.wrapPolygonSelection)
        {
            if(this.selection.wrapPolygonSelection.selectStartPage === pageIndex)
                drawingDocument.AutoShapesTrack.DrawEditWrapPointsPolygon(this.selection.wrapPolygonSelection.parent.wrappingPolygon.calculatedPoints, new AscCommon.CMatrix());
        }
        else
        {
            for(i = 0; i < this.selectedObjects.length; ++i)
            {
                if(this.selectedObjects[i].selectStartPage === pageIndex)
                {
                    drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.SHAPE, this.selectedObjects[i].getTransformMatrix(), 0, 0, this.selectedObjects[i].extX, this.selectedObjects[i].extY, AscFormat.CheckObjectLine(this.selectedObjects[i]), this.selectedObjects[i].canRotate());
                }
            }
            if(this.selectedObjects.length === 1 && this.selectedObjects[0].drawAdjustments && this.selectedObjects[0].selectStartPage === pageIndex)
            {
                this.selectedObjects[0].drawAdjustments(drawingDocument);
            }
        }
        if(this.document)
        {
            if(this.selectedObjects.length === 1 && this.selectedObjects[0].parent && !this.selectedObjects[0].parent.Is_Inline())
            {
                var anchor_pos;
                if(this.arrTrackObjects.length === 1 && !(this.arrTrackObjects[0] instanceof TrackPointWrapPointWrapPolygon || this.arrTrackObjects[0] instanceof  TrackNewPointWrapPolygon))
                {
                    var page_index = AscFormat.isRealNumber(this.arrTrackObjects[0].pageIndex) ? this.arrTrackObjects[0].pageIndex : (AscFormat.isRealNumber(this.arrTrackObjects[0].selectStartPage) ? this.arrTrackObjects[0].selectStartPage : 0);
                    if(page_index === pageIndex)
                    {
                        var bounds = this.arrTrackObjects[0].getBounds();
                        var nearest_pos = this.document.Get_NearestPos(page_index, bounds.min_x, bounds.min_y, true, this.selectedObjects[0].parent);
                        nearest_pos.Page = page_index;
                        drawingDocument.AutoShapesTrack.drawFlowAnchor(nearest_pos.X, nearest_pos.Y);
                    }
                }
                else
                {
                    var page_index = this.selectedObjects[0].selectStartPage;
                    if(page_index === pageIndex)
                    {
                        var paragraph = this.selectedObjects[0].parent.Get_ParentParagraph();
                        anchor_pos = paragraph.Get_AnchorPos(this.selectedObjects[0].parent);
                        drawingDocument.AutoShapesTrack.drawFlowAnchor(anchor_pos.X, anchor_pos.Y);
                    }
                }
            }
        }
        if(this.selectionRect)
        {
            drawingDocument.DrawTrackSelectShapes(this.selectionRect.x, this.selectionRect.y, this.selectionRect.w, this.selectionRect.h);
        }


        if(this.connector){
            this.connector.drawConnectors(drawingDocument.AutoShapesTrack);
            this.connector = null;
        }


      
		if (undefined !== drawingDocument.EndDrawTracking)
			drawingDocument.EndDrawTracking();

		return;
    },

    selectObject: function(object, pageIndex)
    {
        object.select(this, pageIndex);
    },

    deselectObject: function(object)
    {
        for(var i = 0; i < this.selectedObjects.length; ++i)
        {
            if(this.selectedObjects[i] === object){
                object.selected = false;
                this.selectedObjects.splice(i, 1);
                return;
            }
        }
    },

    recalculate: function()
    {
        for(var key in this.objectsForRecalculate)
        {
            this.objectsForRecalculate[key].recalculate();
        }
        this.objectsForRecalculate = {};
    },

    addContentChanges: function(changes)
    {
        // this.contentChanges.Add(changes);
    },

    refreshContentChanges: function()
    {
        //this.contentChanges.Refresh();
        //this.contentChanges.Clear();
    },

    getAllFontNames: function()
    {
    },


    getNearestPos: function(x, y){
        var oTragetDocContent = this.getTargetDocContent(false, false);
        if(oTragetDocContent){
            var tx = x, ty = y;
            var oTransform = oTragetDocContent.Get_ParentTextTransform();
            if(oTransform){
                var oInvertTransform = AscCommon.global_MatrixTransformer.Invert(oTransform);
                tx = oInvertTransform.TransformPointX(x, y);
                ty = oInvertTransform.TransformPointY(x, y);
                return oTragetDocContent.Get_NearestPos(0, tx, ty, false);
            }
        }
        return null;
    },

    getNearestPos2: function(x, y){
        var oTragetDocContent = this.getTargetDocContent(false, false);
        if(oTragetDocContent){
            var tx = x, ty = y;
            var oTransform = oTragetDocContent.Get_ParentTextTransform();
            if(oTransform){
                var oInvertTransform = AscCommon.global_MatrixTransformer.Invert(oTransform);
                tx = oInvertTransform.TransformPointX(x, y);
                ty = oInvertTransform.TransformPointY(x, y);
                var oNearestPos = oTragetDocContent.Get_NearestPos(0, tx, ty, false);
                return oNearestPos;
            }
        }
        return null;
    },

    getTargetDocContent: function(bCheckChartTitle, bOrTable)
    {
        var text_object = getTargetTextObject(this);
        if(text_object)
        {
            if(bOrTable)
            {
                if(text_object.getObjectType() === AscDFH.historyitem_type_GraphicFrame)
                {
                    return text_object.graphicObject;
                }
            }
            if(bCheckChartTitle && text_object.checkDocContent)
            {
                text_object.checkDocContent();
            }
            return text_object.getDocContent();
        }
        return null;
    },

    addNewParagraph: function(bRecalculate)
    {
        this.applyTextFunction(CDocumentContent.prototype.AddNewParagraph, CTable.prototype.AddNewParagraph, [bRecalculate]);
    },


    paragraphClearFormatting: function(isClearParaPr, isClearTextPr)
    {
        this.applyDocContentFunction(AscFormat.CDrawingDocContent.prototype.ClearParagraphFormatting, [isClearParaPr, isClearTextPr], CTable.prototype.ClearParagraphFormatting);
    },

    applyDocContentFunction: function(f, args, tableFunction)
    {
        var oThis = this;
        function applyToArrayDrawings(arr)
        {
            var ret = false, ret2;
            for(var i = 0; i < arr.length; ++i)
            {
                if(arr[i].getObjectType() === AscDFH.historyitem_type_GroupShape)
                {
                    ret2 = applyToArrayDrawings(arr[i].arrGraphicObjects);
                    if(ret2)
                    {
                        ret = true;
                    }
                }
                else if(arr[i].getObjectType() === AscDFH.historyitem_type_GraphicFrame)
                {
                    arr[i].graphicObject.Set_ApplyToAll(true);
                    tableFunction.apply(arr[i].graphicObject, args);
                    arr[i].graphicObject.Set_ApplyToAll(false);
                    ret = true;
                }
                else if(arr[i].getObjectType() === AscDFH.historyitem_type_ChartSpace)
                {
                    if(f === CDocumentContent.prototype.AddToParagraph && args[0].Type === para_TextPr)
                    {
                        AscFormat.CheckObjectTextPr(arr[i], args[0].Value, oThis.getDrawingDocument());
                    }
                    if(f === CDocumentContent.prototype.IncreaseDecreaseFontSize)
                    {
                        arr[i].paragraphIncDecFontSize(args[0]);
                    }
                }
                else if(arr[i].getDocContent)
                {
                    var content = arr[i].getDocContent();
                    if(content)
                    {
                        content.Set_ApplyToAll(true);
                        f.apply(content, args);
                        content.Set_ApplyToAll(false);
                        ret = true;
                    }
                    else
                    {
                        if(arr[i].getObjectType() === AscDFH.historyitem_type_Shape)
                        {
                            if(arr[i].bWordShape)
                            {
                                arr[i].createTextBoxContent();
                            }
                            else
                            {
                                arr[i].createTextBody();
                            }
                            content = arr[i].getDocContent();
                            if(content)
                            {
                                content.Set_ApplyToAll(true);
                                f.apply(content, args);
                                content.Set_ApplyToAll(false);
                                ret = true;
                            }
                        }
                    }
                }

                if(arr[i].checkExtentsByDocContent)
                {
                    arr[i].checkExtentsByDocContent();
                }
            }
            return ret;
        }
        function applyToChartSelection(chart)
        {
            var content;
            if(chart.selection.textSelection)
            {
                chart.selection.textSelection.checkDocContent();
                content = chart.selection.textSelection.getDocContent();
                if(content)
                {
                    f.apply(content, args);
                }
            }
            else if(chart.selection.title)
            {
                content = chart.selection.title.getDocContent();
                if(content)
                {
                    content.Set_ApplyToAll(true);
                    f.apply(content, args);
                    content.Set_ApplyToAll(false);
                }
            }
        }
        if(this.selection.textSelection)
        {
            if(this.selection.textSelection.getObjectType() !== AscDFH.historyitem_type_GraphicFrame)
            {
                f.apply(this.selection.textSelection.getDocContent(), args);
                this.selection.textSelection.checkExtentsByDocContent();
            }
            else
            {
                tableFunction.apply(this.selection.textSelection.graphicObject, args);
            }
        }
        else if(this.selection.groupSelection)
        {
            if(this.selection.groupSelection.selection.textSelection)
            {
                if(this.selection.groupSelection.selection.textSelection.getObjectType() !== AscDFH.historyitem_type_GraphicFrame)
                {
                    f.apply(this.selection.groupSelection.selection.textSelection.getDocContent(), args);
                    this.selection.groupSelection.selection.textSelection.checkExtentsByDocContent();
                }
                else
                {
                    tableFunction.apply(this.selection.groupSelection.selection.textSelection.graphicObject, args);
                }
            }
            else if(this.selection.groupSelection.selection.chartSelection)
            {
                if(f === CDocumentContent.prototype.IncreaseDecreaseFontSize)
                {
                    this.selection.groupSelection.selection.chartSelection.paragraphIncDecFontSize(args[0]);
                }
                else
                {
                    applyToChartSelection(this.selection.groupSelection.selection.chartSelection);
                }

            }
            else
                applyToArrayDrawings(this.selection.groupSelection.selectedObjects);
        }
        else if(this.selection.chartSelection)
        {
            if(f === CDocumentContent.prototype.IncreaseDecreaseFontSize)
            {
                this.selection.chartSelection.paragraphIncDecFontSize(args[0]);
            }
            else
            {
                applyToChartSelection(this.selection.chartSelection);
            }
        }
        else
        {
            var ret = applyToArrayDrawings(this.selectedObjects);
           //if(!ret)
           //{
           //    if(f !== CDocumentContent.prototype.AddToParagraph && this.selectedObjects[0] && this.selectedObjects[0].parent && this.selectedObjects[0].parent.Is_Inline())
           //    {
           //        var parent_paragraph = this.selectedObjects[0].parent.Get_ParentParagraph();
           //        parent_paragraph
           //    }
           //}
        }
        if(this.document)
        {
            this.document.Recalculate();
        }
    },

    setParagraphSpacing: function(Spacing)
    {
        this.applyDocContentFunction(CDocumentContent.prototype.SetParagraphSpacing, [Spacing], CTable.prototype.SetParagraphSpacing);
    },

    setParagraphTabs: function(Tabs)
    {
        this.applyTextFunction(CDocumentContent.prototype.SetParagraphTabs, CTable.prototype.SetParagraphTabs, [Tabs]);
    },

    setParagraphNumbering: function(NumInfo)
    {
        this.applyDocContentFunction(CDocumentContent.prototype.SetParagraphNumbering, [NumInfo], CTable.prototype.SetParagraphNumbering);
    },

    setParagraphShd: function(Shd)
    {
        this.applyDocContentFunction(CDocumentContent.prototype.SetParagraphShd, [Shd], CTable.prototype.SetParagraphShd);
    },


    setParagraphStyle: function(Style)
    {
        this.applyDocContentFunction(CDocumentContent.prototype.SetParagraphStyle, [Style], CTable.prototype.SetParagraphStyle);
    },


    setParagraphContextualSpacing: function(Value)
    {
        this.applyDocContentFunction(CDocumentContent.prototype.SetParagraphContextualSpacing, [Value], CTable.prototype.SetParagraphContextualSpacing);
    },

    setParagraphPageBreakBefore: function(Value)
    {
        this.applyTextFunction(CDocumentContent.prototype.SetParagraphPageBreakBefore, CTable.prototype.SetParagraphPageBreakBefore, [Value]);
    },
    setParagraphKeepLines: function(Value)
    {
        this.applyTextFunction(CDocumentContent.prototype.SetParagraphKeepLines, CTable.prototype.SetParagraphKeepLines, [Value]);
    },

    setParagraphKeepNext: function(Value)
    {
        this.applyTextFunction(CDocumentContent.prototype.SetParagraphKeepNext, CTable.prototype.SetParagraphKeepNext, [Value]);
    },

    setParagraphWidowControl: function(Value)
    {
        this.applyTextFunction(CDocumentContent.prototype.SetParagraphWidowControl, CTable.prototype.SetParagraphWidowControl, [Value]);
    },

    setParagraphBorders: function(Value)
    {
        this.applyTextFunction(CDocumentContent.prototype.SetParagraphBorders, CTable.prototype.SetParagraphBorders, [Value]);
    },


    handleEnter: function(){
        var oSelector = this.selection.groupSelection ? this.selection.groupSelection : this;
        var aSelectedObjects2 = oSelector.selectedObjects;
        var nRet = 0;
        if(aSelectedObjects2.length === 1){
            var oSelectedObject = aSelectedObjects2[0];
            var nObjectType = oSelectedObject.getObjectType();
            var oContent;
            switch(nObjectType){
                case AscDFH.historyitem_type_Shape:{
                    oContent = oSelectedObject.getDocContent();
                    if(!oContent){
                        if(!CheckLinePresetForParagraphAdd(oSelectedObject.getPresetGeom())){
                            this.checkSelectedObjectsAndCallback(function () {
                                if(oSelectedObject.bWordShape){
                                    oSelectedObject.createTextBoxContent();
                                }
                                else {
                                    oSelectedObject.createTextBody();
                                }
                                oContent = oSelectedObject.getDocContent();
                                if(oContent){
                                    oContent.MoveCursorToStartPos();
                                    oSelector.selection.textSelection = oSelectedObject;
                                }
                                nRet |= 1;
                                nRet |= 2;
                            }, [], false, undefined, [], undefined);
                        }
                    }
                    else{
                        if(oContent.IsEmpty()){
                            oContent.MoveCursorToStartPos();
                        }
                        else{
                            oContent.SelectAll();
                        }
                        nRet |= 1;
                        if(oSelectedObject.isEmptyPlaceholder()){
                            nRet |= 2;
                        }
                        oSelector.selection.textSelection = oSelectedObject;
                    }
                    break;
                }
                case AscDFH.historyitem_type_ChartSpace:{
                    if(oSelector.selection.chartSelection === oSelectedObject){
                        if(oSelectedObject.selection.title){
                            oContent = oSelectedObject.selection.title.getDocContent();
                            if(oContent.IsEmpty()){
                                oContent.MoveCursorToStartPos();
                            }
                            else{
                                oContent.SelectAll();
                            }
                            nRet |= 1;
                            oSelectedObject.selection.textSelection = oSelectedObject.selection.title;
                        }
                    }
                    break;
                }
                case AscDFH.historyitem_type_GraphicFrame: {
                    var oTable = oSelectedObject.graphicObject;
                    if(oSelector.selection.textSelection === oSelectedObject){
                        var oTableSelection = oTable.Selection;
                        if(oTableSelection.Type === table_Selection_Cell){
                            this.checkSelectedObjectsAndCallback(function () {
                                oTable.Remove(-1);
                                oTable.RemoveSelection();
                                nRet |= 1;
                                nRet |= 2;
                            }, [], false, undefined, [], undefined);
                        }
                    }
                    else{
                        oTable.MoveCursorToStartPos(false);
                        var oCurCell = oTable.CurCell;
                        if(oCurCell && oCurCell.Content){
                            if(!oCurCell.Content.IsEmpty()){
                                oCurCell.Content.SelectAll();
                                oTable.Selection.Use          = true;
                                oTable.Selection.Type         = table_Selection_Text;
                                oTable.Selection.StartPos.Pos = {Row : oCurCell.Row.Index, Cell : oCurCell.Index};
                                oTable.Selection.EndPos.Pos   = {Row : oCurCell.Row.Index, Cell : oCurCell.Index};
                                oTable.Selection.CurRow       = oCurCell.Row.Index;
                            }
                            oSelector.selection.textSelection = oSelectedObject;
                            nRet |= 1;
                        }
                    }
                    break;
                }
            }
        }
        return nRet;
    },

    applyTextFunction: function(docContentFunction, tableFunction, args)
    {
        if(this.selection.textSelection)
        {
            this.selection.textSelection.applyTextFunction(docContentFunction, tableFunction, args);
        }
        else if(this.selection.groupSelection)
        {
            var oOldDoc = this.selection.groupSelection.document;
            this.selection.groupSelection.document = this.document;
            this.selection.groupSelection.applyTextFunction(docContentFunction, tableFunction, args);
            this.selection.groupSelection.document = oOldDoc;
        }
        else if(this.selection.chartSelection)
        {
            this.selection.chartSelection.applyTextFunction(docContentFunction, tableFunction, args);
            if(this.document)
            {
                this.document.Recalculate();
            }
        }
        else
        {
            if(docContentFunction === CDocumentContent.prototype.AddToParagraph && args[0].Type === para_TextPr || docContentFunction === CDocumentContent.prototype.PasteFormatting)
            {
                this.applyDocContentFunction(docContentFunction, args, tableFunction);
            }
            else if(this.selectedObjects.length === 1 && ((this.selectedObjects[0].getObjectType() === AscDFH.historyitem_type_Shape && !CheckLinePresetForParagraphAdd(this.selectedObjects[0].getPresetGeom())) || this.selectedObjects[0].getObjectType() === AscDFH.historyitem_type_GraphicFrame))
            {
                this.selection.textSelection = this.selectedObjects[0];
                if(this.selectedObjects[0].getObjectType() === AscDFH.historyitem_type_GraphicFrame)
                {
                    this.selectedObjects[0].graphicObject.MoveCursorToStartPos(false);
                    this.selectedObjects[0].applyTextFunction(docContentFunction, tableFunction, args);
                }
                else
                {
                    var oDocContent = this.selectedObjects[0].getDocContent();
                    if(oDocContent){
                        oDocContent.MoveCursorToEndPos(false);
                    }
                    this.selectedObjects[0].applyTextFunction(docContentFunction, tableFunction, args);
                    this.selection.textSelection.select(this, this.selection.textSelection.selectStartPage);
                }
            }
            else if(this.parent && this.parent.GoTo_Text)
            {
                this.parent.GoTo_Text();
                this.resetSelection();
                if(this.document && (docpostype_DrawingObjects !== this.document.Get_DocPosType() || isRealObject(getTargetTextObject(this.document.DrawingObjects))) && CDocumentContent.prototype.AddNewParagraph === docContentFunction)
                {
                    this.document.AddNewParagraph(args[0]);
                }
            }
            else if(this.selectedObjects.length > 0 && this.selectedObjects[0].parent && this.selectedObjects[0].parent.GoTo_Text)
            {
                this.selectedObjects[0].parent.GoTo_Text();
                this.resetSelection();
                if(this.document && (docpostype_DrawingObjects !== this.document.Get_DocPosType() || isRealObject(getTargetTextObject(this))) && CDocumentContent.prototype.AddNewParagraph === docContentFunction)
                {
                    this.document.AddNewParagraph(args[0]);
                }
            }
        }
    },

    paragraphAdd: function(paraItem, bRecalculate)
    {
        this.applyTextFunction(CDocumentContent.prototype.AddToParagraph, CTable.prototype.AddToParagraph, [paraItem, bRecalculate]);
    },


    setMathProps: function(oMathProps)
    {
        var oContent = this.getTargetDocContent(false);
            if(oContent){
                this.checkSelectedObjectsAndCallback(function(){
                    var oContent2 = this.getTargetDocContent(true);
                    if(oContent2){
                        var SelectedInfo = new CSelectedElementsInfo();
                        oContent2.GetSelectedElementsInfo(SelectedInfo);
                        if (null !== SelectedInfo.Get_Math()){
                            var ParaMath = SelectedInfo.Get_Math();
                            ParaMath.Set_MenuProps(oMathProps);
                        }
                    }
            }, [], false, AscDFH.historydescription_Spreadsheet_SetCellFontName);
        }
    },

    paragraphIncDecFontSize: function(bIncrease)
    {
        this.applyDocContentFunction(CDocumentContent.prototype.IncreaseDecreaseFontSize, [bIncrease], CTable.prototype.IncreaseDecreaseFontSize);
    },

    paragraphIncDecIndent: function(bIncrease)
    {
        this.applyDocContentFunction(CDocumentContent.prototype.IncreaseDecreaseIndent, [bIncrease], CTable.prototype.IncreaseDecreaseIndent);
    },
    setDefaultTabSize: function(TabSize)
    {
        this.applyDocContentFunction(CDocumentContent.prototype.SetParagraphDefaultTabSize, [TabSize], CTable.prototype.SetParagraphDefaultTabSize);
    },

    setParagraphAlign: function(align)
    {
        if(!this.document){
            var oContent = this.getTargetDocContent(true, false);
            if(oContent){
                var oInfo = new CSelectedElementsInfo();
                oContent.GetSelectedElementsInfo(oInfo);
                var Math         = oInfo.Get_Math();
                if (null !== Math && true !== Math.Is_Inline())
                {
                    Math.Set_Align(align);
                    return;
                }
            }
        }
        this.applyDocContentFunction(CDocumentContent.prototype.SetParagraphAlign, [align], CTable.prototype.SetParagraphAlign);
    },

    setParagraphIndent: function(indent)
    {
        var content = this.getTargetDocContent(true);
        if(content)
        {
            content.SetParagraphIndent(indent);
        }
        else if(this.document)
        {
            if(this.selectedObjects.length > 0)
            {
                var parent_paragraph = this.selectedObjects[0].parent.Get_ParentParagraph();
                if(parent_paragraph)
                {
                    parent_paragraph.Set_Ind(indent, true);
                    this.document.Recalculate();
                }
            }
        }
    },

    setCellFontName: function (fontName) {

        var oThis = this;
        var callBack = function()
        {
            oThis.paragraphAdd(new ParaTextPr({ FontFamily : { Name : fontName , Index : -1 } }));
        };
        this.checkSelectedObjectsAndCallback(callBack, [], false, AscDFH.historydescription_Spreadsheet_SetCellFontName);

    },

    setCellFontSize: function (fontSize) {

        var oThis = this;
        var callBack = function()
        {
            oThis.paragraphAdd(new ParaTextPr({ FontSize : fontSize}));
        };
        this.checkSelectedObjectsAndCallback(callBack, [], false, AscDFH.historydescription_Spreadsheet_SetCellFontSize);
    },

    setCellBold: function (isBold) {
        var oThis = this;
        var callBack = function()
        {
            oThis.paragraphAdd(new ParaTextPr({ Bold : isBold}));
        };
        this.checkSelectedObjectsAndCallback(callBack, [], false, AscDFH.historydescription_Spreadsheet_SetCellBold);

    },

    setCellItalic: function (isItalic) {
        var oThis = this;
        var callBack = function()
        {
            oThis.paragraphAdd(new ParaTextPr({ Italic : isItalic}));
        };
        this.checkSelectedObjectsAndCallback(callBack, [], false, AscDFH.historydescription_Spreadsheet_SetCellItalic);
    },

    setCellUnderline: function (isUnderline) {
        var oThis = this;
        var callBack = function()
        {
            oThis.paragraphAdd(new ParaTextPr({ Underline : isUnderline}));
        };
        this.checkSelectedObjectsAndCallback(callBack, [], false, AscDFH.historydescription_Spreadsheet_SetCellUnderline);
    },

    setCellStrikeout: function (isStrikeout) {
        var oThis = this;
        var callBack = function()
        {
            oThis.paragraphAdd(new ParaTextPr({ Strikeout : isStrikeout}));
        };
        this.checkSelectedObjectsAndCallback(callBack, [], false, AscDFH.historydescription_Spreadsheet_SetCellStrikeout);
    },

    setCellSubscript: function (isSubscript) {
        var oThis = this;
        var callBack = function()
        {
            oThis.paragraphAdd(new ParaTextPr({ VertAlign : isSubscript ? AscCommon.vertalign_SubScript : AscCommon.vertalign_Baseline}));
        };
        this.checkSelectedObjectsAndCallback(callBack, [], false, AscDFH.historydescription_Spreadsheet_SetCellSubscript);
    },

    setCellSuperscript: function (isSuperscript) {
        var oThis = this;
        var callBack = function()
        {
            oThis.paragraphAdd(new ParaTextPr({ VertAlign : isSuperscript ? AscCommon.vertalign_SubScript : AscCommon.vertalign_Baseline}));
        };
        this.checkSelectedObjectsAndCallback(callBack, [], false, AscDFH.historydescription_Spreadsheet_SetCellSuperscript);
    },

    setCellAlign: function (align) {
        this.checkSelectedObjectsAndCallback(this.setParagraphAlign, [align], false, AscDFH.historydescription_Spreadsheet_SetCellAlign);
    },

    setCellVertAlign: function (align) {

        var vert_align;
        switch (align)
        {
            case Asc.c_oAscVAlign.Bottom :
            {
                vert_align = 0;
                break;
            }
            case Asc.c_oAscVAlign.Center :
            {
                vert_align = 1;
                break;
            }
            case Asc.c_oAscVAlign.Dist:
            {
                vert_align = 1;
                break;
            }
            case Asc.c_oAscVAlign.Just :
            {
                vert_align = 1;
                break;
            }
            case Asc.c_oAscVAlign.Top :
            {
                vert_align = 4
            }
        }
        this.checkSelectedObjectsAndCallback(this.applyDrawingProps, [{verticalTextAlign: vert_align}], false, AscDFH.historydescription_Spreadsheet_SetCellVertAlign);
    },

    setCellTextWrap: function (isWrapped) {
        //TODO:this.checkSelectedObjectsAndCallback(this.setCellTextWrapCallBack, [isWrapped]);

    },

    setCellTextShrink: function (isShrinked) {
        //TODO:this.checkSelectedObjectsAndCallback(this.setCellTextShrinkCallBack, [isShrinked]);

    },

    setCellTextColor: function (color) {
        var oThis = this;
        var callBack = function()
        {
            var unifill = new AscFormat.CUniFill();
            unifill.setFill(new AscFormat.CSolidFill());
            unifill.fill.setColor(AscFormat.CorrectUniColor(color, null));
            oThis.paragraphAdd(new ParaTextPr({Unifill: unifill}));
        };
        this.checkSelectedObjectsAndCallback(callBack, [], false, AscDFH.historydescription_Spreadsheet_SetCellTextColor);
    },

    setCellBackgroundColor: function (color)
    {
        var fill = new Asc.asc_CShapeFill();
        if(color)
        {
            fill.type = c_oAscFill.FILL_TYPE_SOLID;
            fill.fill = new Asc.asc_CFillSolid();
            fill.fill.color = color;
        }
        else
        {
            fill.type = c_oAscFill.FILL_TYPE_NOFILL;
        }

        this.checkSelectedObjectsAndCallback(this.applyDrawingProps, [{fill: fill}], false, AscDFH.historydescription_Spreadsheet_SetCellBackgroundColor);
    },


    setCellAngle: function (angle) {

        switch (angle)
        {
            case 0 :
            {
                this.checkSelectedObjectsAndCallback(this.applyDrawingProps, [{vert: null}], false, AscDFH.historydescription_Spreadsheet_SetCellVertAlign);
                break;
            }
            case 90 :
            {
                this.checkSelectedObjectsAndCallback(this.applyDrawingProps, [{vert: AscFormat.nVertTTvert}], false, AscDFH.historydescription_Spreadsheet_SetCellVertAlign);
                break;
            }
            case 270:
            {
                this.checkSelectedObjectsAndCallback(this.applyDrawingProps, [{vert: AscFormat.nVertTTvert270}], false, AscDFH.historydescription_Spreadsheet_SetCellVertAlign);
                break;
            }
        }
    },

    setCellStyle: function (name) {
        //TODO:this.checkSelectedObjectsAndCallback(this.setCellStyleCallBack, [name]);
    },

    // Увеличение размера шрифта
    increaseFontSize: function () {
        this.checkSelectedObjectsAndCallback(this.paragraphIncDecFontSize, [true], false, AscDFH.historydescription_Spreadsheet_SetCellIncreaseFontSize);

    },

    // Уменьшение размера шрифта
    decreaseFontSize: function () {
        this.checkSelectedObjectsAndCallback(this.paragraphIncDecFontSize, [false], false, AscDFH.historydescription_Spreadsheet_SetCellDecreaseFontSize);

    },

    deleteSelectedObjects: function(){
        if(Asc["editor"] && Asc["editor"].isChartEditor && (!this.selection.chartSelection)){
            return;
        }
        var oThis = this;
        this.checkSelectedObjectsAndCallback(function(){
            oThis.resetInternalSelection();
            oThis.removeCallback(-1);
        }, [], false, AscDFH.historydescription_Spreadsheet_Remove);
    },


    hyperlinkCheck: function(bCheckEnd)
    {
        var content = this.getTargetDocContent();
        if(content)
            return content.IsCursorInHyperlink(bCheckEnd);
        return null;
    },

    hyperlinkCanAdd: function(bCheckInHyperlink)
    {
        var content = this.getTargetDocContent();
        if(content)
        {
            if(this.document && content.Parent && content.Parent instanceof  AscFormat.CTextBody)
                return false;
            return content.CanAddHyperlink(bCheckInHyperlink);
        }
        return false;
    },

    hyperlinkRemove: function()
    {
        var content = this.getTargetDocContent(true);
        if(content)
        {
            var Ret = content.RemoveHyperlink();
            var target_text_object = getTargetTextObject(this);
            if(target_text_object)
            {
                target_text_object.checkExtentsByDocContent && target_text_object.checkExtentsByDocContent();
            }
            return Ret;
        }
        return undefined;
    },

    hyperlinkModify: function( HyperProps )
    {
        var content = this.getTargetDocContent(true);
        if(content)
        {
            var Ret = content.ModifyHyperlink(HyperProps);
            var target_text_object = getTargetTextObject(this);
            if(target_text_object)
            {
                target_text_object.checkExtentsByDocContent && target_text_object.checkExtentsByDocContent();
            }
            return Ret;
        }
        return undefined;
    },

    hyperlinkAdd: function( HyperProps )
    {
        var content = this.getTargetDocContent(true), bCheckExtents = false;
        if(content)
        {
            if(!this.document)
            {
                if ( null != HyperProps.Text && "" != HyperProps.Text && true === content.IsSelectionUse() )
                {
                    this.removeCallback(-1, undefined, undefined, true);
                    bCheckExtents = true;
                }
            }
            var Ret = content.AddHyperlink(HyperProps);
            if(bCheckExtents)
            {
                var target_text_object = getTargetTextObject(this);
                if(target_text_object)
                {
                    target_text_object.checkExtentsByDocContent && target_text_object.checkExtentsByDocContent();
                }
            }
            return Ret;
        }
        return null;
    },


    insertHyperlink: function (options) {
        if(!this.getHyperlinkInfo())
        {
            this.checkSelectedObjectsAndCallback(this.hyperlinkAdd, [{Text: options.text, Value: options.hyperlinkModel.Hyperlink, ToolTip: options.hyperlinkModel.Tooltip}], false, AscDFH.historydescription_Spreadsheet_SetCellHyperlinkAdd);
        }
        else
        {
            this.checkSelectedObjectsAndCallback(this.hyperlinkModify, [{Text: options.text, Value: options.hyperlinkModel.Hyperlink, ToolTip: options.hyperlinkModel.Tooltip}], false, AscDFH.historydescription_Spreadsheet_SetCellHyperlinkModify);
        }
    },

    removeHyperlink: function () {
        this.checkSelectedObjectsAndCallback(this.hyperlinkRemove, [], false, AscDFH.historydescription_Spreadsheet_SetCellHyperlinkRemove);
    },

    canAddHyperlink: function() {
        return this.hyperlinkCanAdd();
    },

    getParagraphParaPr: function()
    {
        var target_text_object = getTargetTextObject(this);
        if(target_text_object)
        {
            if(target_text_object.getObjectType() === AscDFH.historyitem_type_GraphicFrame)
            {
                return target_text_object.graphicObject.GetCalculatedParaPr();
            }
            else
            {
                var content = this.getTargetDocContent();
                if(content)
                {
                    return content.GetCalculatedParaPr();
                }
            }
        }
        else
        {
            var result, cur_pr, selected_objects, i;
            var getPropsFromArr = function(arr)
            {
                var cur_pr, result_pr, content;
                for(var i = 0; i < arr.length; ++i)
                {
                    cur_pr = null;
                    if(arr[i].getObjectType() === AscDFH.historyitem_type_GroupShape)
                    {
                        cur_pr = getPropsFromArr(arr[i].arrGraphicObjects);
                    }
                    else
                    {
                        if(arr[i].getDocContent && arr[i].getObjectType() !== AscDFH.historyitem_type_ChartSpace)
                        {
                            content = arr[i].getDocContent();
                            if(content)
                            {
                                content.Set_ApplyToAll(true);
                                cur_pr = content.GetCalculatedParaPr();
                                content.Set_ApplyToAll(false);
                            }
                        }
                    }

                    if(cur_pr)
                    {
                        if(!result_pr)
                            result_pr = cur_pr;
                        else
                            result_pr.Compare(cur_pr);
                    }
                }
                return result_pr;
            };

            if(this.selection.groupSelection)
            {
                result = getPropsFromArr(this.selection.groupSelection.selectedObjects);
            }
            else
            {
                result = getPropsFromArr(this.selectedObjects);
            }
            return result;
        }
    },

    getTheme: function()
    {
        return window["Asc"]["editor"].wbModel.theme;
    },

    getParagraphTextPr: function()
    {
        var target_text_object = getTargetTextObject(this);
        if(target_text_object)
        {
            if(target_text_object.getObjectType() === AscDFH.historyitem_type_GraphicFrame)
            {
                return target_text_object.graphicObject.GetCalculatedTextPr();
            }
            else
            {
                var content = this.getTargetDocContent();
                if(content)
                {
                    return content.GetCalculatedTextPr();
                }
            }
        }
        else
        {
            var result, cur_pr, selected_objects, i;
            var getPropsFromArr = function(arr)
            {
                var cur_pr, result_pr, content;
                for(var i = 0; i < arr.length; ++i)
                {
                    cur_pr = null;
                    if(arr[i].getObjectType() === AscDFH.historyitem_type_GroupShape)
                    {
                        cur_pr = getPropsFromArr(arr[i].arrGraphicObjects);
                    }
                    else if(arr[i].getObjectType() === AscDFH.historyitem_type_ChartSpace)
                    {
                        cur_pr = arr[i].getParagraphTextPr();
                    }
                    else
                    {
                        if(arr[i].getDocContent)
                        {
                            content = arr[i].getDocContent();
                            if(content)
                            {
                                content.Set_ApplyToAll(true);
                                cur_pr = content.GetCalculatedTextPr();
                                content.Set_ApplyToAll(false);
                            }
                        }
                    }

                    if(cur_pr)
                    {
                        if(!result_pr)
                            result_pr = cur_pr;
                        else
                            result_pr.Compare(cur_pr);
                    }
                }
                return result_pr;
            };

            if(this.selection.groupSelection)
            {
                result = getPropsFromArr(this.selection.groupSelection.selectedObjects);
            }
            else if (this.selectedObjects
				&& 1 === this.selectedObjects.length
				&& this.selectedObjects[0].getObjectType() === AscDFH.historyitem_type_ImageShape
				&& this.selectedObjects[0].parent
				&& this.selectedObjects[0].parent.Parent
				&& this.selectedObjects[0].parent.Parent.GetCalculatedTextPr)
			{
				var oParaDrawing = this.selectedObjects[0].parent;
				var oParagraph   = oParaDrawing.Parent;
				oParagraph.Cursor_MoveTo_Drawing(oParaDrawing.Get_Id(), true);
				result = oParagraph.GetCalculatedTextPr();
			}
            else
            {
                result = getPropsFromArr(this.selectedObjects);
            }
            return result;
        }
    },


    getColorMap: function()
    {
        return AscFormat.G_O_DEFAULT_COLOR_MAP;
    },


    editChartDrawingObjects: function(chart)
    {

        if(this.chartForProps)
        {
            this.resetSelection();
            if(this.chartForProps.group)
            {
                var main_group = this.chartForProps.getMainGroup();
                this.selectObject(main_group, 0);
                this.selection.groupSelection = main_group;
                main_group.selectObject(this.chartForProps, 0);
            }
            else
            {
                this.selectObject(this.chartForProps);
            }
            this.chartForProps = null;

        }
        var objects_by_types = this.getSelectedObjectsByTypes();
        if(objects_by_types.charts.length === 1)
        {
            this.checkSelectedObjectsAndCallback(this.editChartCallback, [chart], false, AscDFH.historydescription_Spreadsheet_EditChart);
        }
    },

    getTextArtPreviewManager: function()
    {
        var api = this.getEditorApi();
        return api.textArtPreviewManager;
    },

    resetConnectors: function(aShapes){
        var aAllConnectors = this.getAllConnectors(this.getDrawingArray());
        for(var  i = 0; i < aAllConnectors.length; ++i){
            for(var j = 0; j < aShapes.length; ++j){
                aAllConnectors[i].resetShape(aShapes[j]);
            }
        }
    },

    getConnectorsForCheck: function(){
        var aSelectedObjects = this.selection.groupSelection ? this.selection.groupSelection.selectedObjects : this.selectedObjects;
        var aAllConnectors = this.getAllConnectorsByDrawings(aSelectedObjects, [],  undefined, true);
        var _ret = [];
        for(var i = 0;  i < aAllConnectors.length; ++i){
            if(!aAllConnectors[i].selected){
                _ret.push(aAllConnectors[i]);
            }
        }
        return _ret;
    },
    
    getConnectorsForCheck2: function(){
        var aConnectors = this.getConnectorsForCheck();
        var oGroupMaps = {};
        var _ret = [];
        for(var i = 0; i < aConnectors.length; ++i){
            var oGroup = aConnectors[i].getMainGroup();
            if(oGroup){
                oGroupMaps[oGroup.Id] = oGroup;
            }
            else{
                _ret.push(aConnectors[i]);
            }
        }
        for(i in oGroupMaps){
            if(oGroupMaps.hasOwnProperty(i)){
                _ret.push(oGroupMaps[i]);
            }
        }
        return _ret;
    },

    applyDrawingProps: function(props)
    {
        var objects_by_type = this.getSelectedObjectsByTypes(true);
        var i;
        if(AscFormat.isRealNumber(props.verticalTextAlign))
        {
            for(i = 0; i < objects_by_type.shapes.length; ++i)
            {
                objects_by_type.shapes[i].setVerticalAlign(props.verticalTextAlign);
            }
            for(i = 0; i < objects_by_type.groups.length; ++i)
            {
                objects_by_type.groups[i].setVerticalAlign(props.verticalTextAlign);
            }
            if(objects_by_type.tables.length == 1)
            {
                var props2 = new Asc.CTableProp();
                if(props.verticalTextAlign === AscFormat.VERTICAL_ANCHOR_TYPE_BOTTOM)
                {
                    props2.put_CellsVAlign(vertalignjc_Bottom);
                }
                else if(props.verticalTextAlign === AscFormat.VERTICAL_ANCHOR_TYPE_CENTER)
                {
                    props2.put_CellsVAlign(vertalignjc_Center);
                }
                else
                {
                    props2.put_CellsVAlign(vertalignjc_Top);
                }
                var target_text_object = getTargetTextObject(this);
                if(target_text_object === objects_by_type.tables[0])
                {
                    objects_by_type.tables[0].graphicObject.Set_Props(props2);
                }
                else
                {
                    objects_by_type.tables[0].graphicObject.SelectAll();
                    objects_by_type.tables[0].graphicObject.Set_Props(props2);
                    objects_by_type.tables[0].graphicObject.RemoveSelection();
                }
                editor.WordControl.m_oLogicDocument.Check_GraphicFrameRowHeight(objects_by_type.tables[0]);
            }
        }

        if(AscFormat.isRealNumber(props.columnNumber))
        {
            for(i = 0; i < objects_by_type.shapes.length; ++i)
            {
                objects_by_type.shapes[i].setColumnNumber(props.columnNumber);
                objects_by_type.shapes[i].recalculate();
                objects_by_type.shapes[i].checkExtentsByDocContent();
            }
            for(i = 0; i < objects_by_type.groups.length; ++i)
            {
                objects_by_type.groups[i].setColumnNumber(props.columnNumber);
                objects_by_type.groups[i].recalculate();
                objects_by_type.groups[i].checkExtentsByDocContent();
            }
        }

        if(AscFormat.isRealNumber(props.columnSpace))
        {
            for(i = 0; i < objects_by_type.shapes.length; ++i)
            {
                objects_by_type.shapes[i].setColumnSpace(props.columnSpace);
                objects_by_type.shapes[i].recalculate();
                objects_by_type.shapes[i].checkExtentsByDocContent();
            }
            for(i = 0; i < objects_by_type.groups.length; ++i)
            {
                objects_by_type.groups[i].setColumnSpace(props.columnSpace);
                objects_by_type.groups[i].recalculate();
                objects_by_type.groups[i].checkExtentsByDocContent();
            }
        }

        if(AscFormat.isRealNumber(props.vert))
        {
            for(i = 0; i < objects_by_type.shapes.length; ++i)
            {
                objects_by_type.shapes[i].setVert(props.vert);
            }
            for(i = 0; i < objects_by_type.groups.length; ++i)
            {
                objects_by_type.groups[i].setVert(props.vert);
            }
        }
        if(isRealObject(props.paddings))
        {
            for(i = 0; i < objects_by_type.shapes.length; ++i)
            {
                objects_by_type.shapes[i].setPaddings(props.paddings);
            }
            for(i = 0; i < objects_by_type.groups.length; ++i)
            {
                objects_by_type.groups[i].setPaddings(props.paddings);
            }
        }
        if(typeof(props.type) === "string")
        {
            var aShapes = [];
            for(i = 0; i < objects_by_type.shapes.length; ++i)
            {
                if(objects_by_type.shapes[i].getObjectType() === AscDFH.historyitem_type_Shape){
                    objects_by_type.shapes[i].changePresetGeom(props.type);
                    aShapes.push(objects_by_type.shapes[i]);
                }
            }
            for(i = 0; i < objects_by_type.groups.length; ++i)
            {
                objects_by_type.groups[i].changePresetGeom(props.type);
                objects_by_type.groups[i].getAllShapes(objects_by_type.groups[i].spTree, aShapes);
            }
            for(i = 0; i < objects_by_type.images.length; ++i)
            {
                objects_by_type.images[i].changePresetGeom(props.type);
                aShapes.push(objects_by_type.images[i]);
            }
            this.resetConnectors(aShapes);
        }
        if(isRealObject(props.stroke))
        {
            for(i = 0; i < objects_by_type.shapes.length; ++i)
            {
                objects_by_type.shapes[i].changeLine(props.stroke);
            }
            for(i = 0; i < objects_by_type.groups.length; ++i)
            {
                objects_by_type.groups[i].changeLine(props.stroke);
            }
            for(i = 0; i < objects_by_type.charts.length; ++i)
            {
                objects_by_type.charts[i].changeLine(props.stroke);
            }
            for(i = 0; i < objects_by_type.images.length; ++i)
            {
                objects_by_type.images[i].changeLine(props.stroke);
            }
        }
        if(isRealObject(props.fill))
        {
            for(i = 0; i < objects_by_type.shapes.length; ++i)
            {
                objects_by_type.shapes[i].changeFill(props.fill);
            }
            for(i = 0; i < objects_by_type.groups.length; ++i)
            {
                objects_by_type.groups[i].changeFill(props.fill);
            }
            for(i = 0; i < objects_by_type.charts.length; ++i)
            {
                objects_by_type.charts[i].changeFill(props.fill);
            }
        }

        for(i = 0; i < objects_by_type.shapes.length; ++i)
        {
            objects_by_type.shapes[i].setTitle(props.title);
        }
        for(i = 0; i < objects_by_type.groups.length; ++i)
        {
            objects_by_type.groups[i].setTitle(props.title);
        }
        for(i = 0; i < objects_by_type.charts.length; ++i)
        {
            objects_by_type.charts[i].setTitle(props.title);
        }

        for(i = 0; i < objects_by_type.images.length; ++i)
        {
            objects_by_type.images[i].setTitle(props.title);
        }

        for(i = 0; i < objects_by_type.shapes.length; ++i)
        {
            objects_by_type.shapes[i].setDescription(props.description);
        }
        for(i = 0; i < objects_by_type.groups.length; ++i)
        {
            objects_by_type.groups[i].setDescription(props.description);
        }
        for(i = 0; i < objects_by_type.charts.length; ++i)
        {
            objects_by_type.charts[i].setDescription(props.description);
        }

        for(i = 0; i < objects_by_type.images.length; ++i)
        {
            objects_by_type.images[i].setDescription(props.description);
        }

        if(typeof props.ImageUrl === "string" && props.ImageUrl.length > 0)
        {
            for(i = 0; i < objects_by_type.images.length; ++i)
            {
                objects_by_type.images[i].setBlipFill(CreateBlipFillRasterImageId(props.ImageUrl));
            }
        }
        if(props.ChartProperties)
        {
            for(i = 0; i < objects_by_type.charts.length; ++i)
            {
                this.applyPropsToChartSpace(props.ChartProperties, objects_by_type.charts[i]);
            }
        }

        var aGroups = [];
        var bCheckConnectors = false;
        var oApi = editor || Asc['editor'];
        var editorId = oApi.getEditorId();
        var bMoveFlag = true;
        if(AscFormat.isRealNumber(props.Width) || AscFormat.isRealNumber(props.Height))
        {
            for(i = 0; i < objects_by_type.shapes.length; ++i)
            {
                CheckSpPrXfrm(objects_by_type.shapes[i]);
                if(!props.SizeRelH && AscFormat.isRealNumber(props.Width))
                {
                    objects_by_type.shapes[i].spPr.xfrm.setExtX(props.Width);
                    if(objects_by_type.shapes[i].parent instanceof ParaDrawing)
                    {
                        objects_by_type.shapes[i].parent.SetSizeRelH({RelativeFrom: c_oAscSizeRelFromH.sizerelfromhPage, Percent: 0});
                    }
                }
                if(!props.SizeRelV && AscFormat.isRealNumber(props.Height))
                {
                    objects_by_type.shapes[i].spPr.xfrm.setExtY(props.Height);
                    if(objects_by_type.shapes[i].parent instanceof ParaDrawing)
                    {
                        objects_by_type.shapes[i].parent.SetSizeRelV({RelativeFrom: c_oAscSizeRelFromV.sizerelfromvPage, Percent: 0});
                    }
                }
                if(objects_by_type.shapes[i].parent instanceof ParaDrawing)
                {
                    var oDrawing =  objects_by_type.shapes[i].parent;
                    if (oDrawing.SizeRelH && !oDrawing.SizeRelV)
                    {
                        oDrawing.SetSizeRelV({RelativeFrom: c_oAscSizeRelFromV.sizerelfromvPage, Percent: 0});
                    }
                    if (oDrawing.SizeRelV && !oDrawing.SizeRelH)
                    {
                        oDrawing.SetSizeRelH({RelativeFrom: c_oAscSizeRelFromH.sizerelfromhPage, Percent: 0});
                    }
                }
                CheckShapeBodyAutoFitReset(objects_by_type.shapes[i], true);
                if(objects_by_type.shapes[i].group)
                {
                    checkObjectInArray(aGroups, objects_by_type.shapes[i].group.getMainGroup());
                }
                objects_by_type.shapes[i].checkDrawingBaseCoords();
            }
            if(!props.SizeRelH && !props.SizeRelV && AscFormat.isRealNumber(props.Width) && AscFormat.isRealNumber(props.Height))
            {
                for(i = 0; i < objects_by_type.images.length; ++i)
                {
                    CheckSpPrXfrm(objects_by_type.images[i]);
                    objects_by_type.images[i].spPr.xfrm.setExtX(props.Width);
                    objects_by_type.images[i].spPr.xfrm.setExtY(props.Height);
                    if(objects_by_type.images[i].group)
                    {
                        checkObjectInArray(aGroups, objects_by_type.images[i].group.getMainGroup());
                    }
                    objects_by_type.images[i].checkDrawingBaseCoords();
                }
                for(i = 0; i < objects_by_type.charts.length; ++i)
                {
                    CheckSpPrXfrm(objects_by_type.charts[i]);
                    objects_by_type.charts[i].spPr.xfrm.setExtX(props.Width);
                    objects_by_type.charts[i].spPr.xfrm.setExtY(props.Height);
                    if(objects_by_type.charts[i].group)
                    {
                        checkObjectInArray(aGroups, objects_by_type.charts[i].group.getMainGroup());
                    }
                    objects_by_type.charts[i].checkDrawingBaseCoords();
                }
                for(i = 0; i < objects_by_type.oleObjects.length; ++i)
                {
                    CheckSpPrXfrm(objects_by_type.oleObjects[i]);
                    objects_by_type.oleObjects[i].spPr.xfrm.setExtX(props.Width);
                    objects_by_type.oleObjects[i].spPr.xfrm.setExtY(props.Height);
                    if(objects_by_type.oleObjects[i].group)
                    {
                        checkObjectInArray(aGroups, objects_by_type.oleObjects[i].group.getMainGroup());
                    }

                    var api = window.editor || window["Asc"]["editor"];
                    if(api)
                    {
                        var pluginData = new Asc.CPluginData();
                        pluginData.setAttribute("data", objects_by_type.oleObjects[i].m_sData);
                        pluginData.setAttribute("guid", objects_by_type.oleObjects[i].m_sApplicationId);
                        pluginData.setAttribute("width", objects_by_type.oleObjects[i].spPr.xfrm.extX);
                        pluginData.setAttribute("height", objects_by_type.oleObjects[i].spPr.xfrm.extY);
                        pluginData.setAttribute("objectId", objects_by_type.oleObjects[i].Get_Id());
                        api.asc_pluginResize(pluginData);
                    }
                    objects_by_type.oleObjects[i].checkDrawingBaseCoords();
                }
            }

            if(editorId === AscCommon.c_oEditorId.Presentation || editorId === AscCommon.c_oEditorId.Spreadsheet){
                bCheckConnectors = true;
                bMoveFlag = false;
            }
        }

        if(AscFormat.isRealBool(props.lockAspect))
        {
            for(i = 0; i < objects_by_type.shapes.length; ++i)
            {
                objects_by_type.shapes[i].setNoChangeAspect(props.lockAspect ? true : undefined);
            }
            for(i = 0; i < objects_by_type.images.length; ++i)
            {
                objects_by_type.images[i].setNoChangeAspect(props.lockAspect ? true : undefined);
            }
            for(i = 0; i < objects_by_type.charts.length; ++i)
            {
                objects_by_type.charts[i].setNoChangeAspect(props.lockAspect ? true : undefined);
            }
        }
        if(isRealObject(props.Position) && AscFormat.isRealNumber(props.Position.X) && AscFormat.isRealNumber(props.Position.Y))
        {
            for(i = 0; i < objects_by_type.shapes.length; ++i)
            {
                CheckSpPrXfrm(objects_by_type.shapes[i]);
                objects_by_type.shapes[i].spPr.xfrm.setOffX(props.Position.X);
                objects_by_type.shapes[i].spPr.xfrm.setOffY(props.Position.Y);
                if(objects_by_type.shapes[i].group)
                {
                    checkObjectInArray(aGroups, objects_by_type.shapes[i].group.getMainGroup());
                }
                objects_by_type.shapes[i].checkDrawingBaseCoords();
            }
            for(i = 0; i < objects_by_type.images.length; ++i)
            {
                CheckSpPrXfrm(objects_by_type.images[i]);
                objects_by_type.images[i].spPr.xfrm.setOffX(props.Position.X);
                objects_by_type.images[i].spPr.xfrm.setOffY(props.Position.Y);
                if(objects_by_type.images[i].group)
                {
                    checkObjectInArray(aGroups, objects_by_type.images[i].group.getMainGroup());
                }
                objects_by_type.images[i].checkDrawingBaseCoords();
            }
            for(i = 0; i < objects_by_type.charts.length; ++i)
            {
                CheckSpPrXfrm(objects_by_type.charts[i]);
                objects_by_type.charts[i].spPr.xfrm.setOffX(props.Position.X);
                objects_by_type.charts[i].spPr.xfrm.setOffY(props.Position.Y);
                if(objects_by_type.charts[i].group)
                {
                    checkObjectInArray(aGroups, objects_by_type.charts[i].group.getMainGroup());
                }
                objects_by_type.charts[i].checkDrawingBaseCoords();
            }

            if(editorId === AscCommon.c_oEditorId.Presentation || editorId === AscCommon.c_oEditorId.Spreadsheet){
                bCheckConnectors = true;
            }
        }

        if(bCheckConnectors){
            var aConnectors = this.getConnectorsForCheck();
            for(i = 0; i < aConnectors.length; ++i){
                aConnectors[i].calculateTransform(bMoveFlag);
                var oGroup = aConnectors[i].getMainGroup();
                if(oGroup){
                    checkObjectInArray(aGroups, oGroup);
                }
            }
        }

        for(i = 0; i < aGroups.length; ++i)
        {
            aGroups[i].updateCoordinatesAfterInternalResize();
        }

        var bRecalcText = false;
        if(props.textArtProperties)
        {
            var  oAscTextArtProperties = props.textArtProperties;
            var oParaTextPr;
            var nStyle = oAscTextArtProperties.asc_getStyle();
            var bWord = (typeof CGraphicObjects !== "undefined" &&  (this instanceof CGraphicObjects));
            if(AscFormat.isRealNumber(nStyle))
            {
                var oPreviewManager = this.getTextArtPreviewManager();
                var oStyleTextPr = oPreviewManager.getStylesToApply()[nStyle].Copy();
                if(bWord)
                {
                    oParaTextPr = new ParaTextPr({TextFill: oStyleTextPr.TextFill, TextOutline: oStyleTextPr.TextOutline});
                }
                else
                {
                    oParaTextPr = new ParaTextPr({Unifill: oStyleTextPr.TextFill, TextOutline: oStyleTextPr.TextOutline});
                }
            }
            else
            {
                var oAscFill = oAscTextArtProperties.asc_getFill(), oAscStroke = oAscTextArtProperties.asc_getLine();
                if(oAscFill || oAscStroke)
                {
                    if(bWord)
                    {
                        oParaTextPr = new ParaTextPr({AscFill: oAscFill, AscLine: oAscStroke});
                    }
                    else
                    {
                        oParaTextPr = new ParaTextPr({AscUnifill: oAscFill, AscLine: oAscStroke});
                    }
                }
            }
            if(oParaTextPr)
            {
                bRecalcText = true;

                if(this.document && this.document.TurnOff_Recalculate)
                {
                    this.document.TurnOff_Recalculate();
                }

                this.paragraphAdd(oParaTextPr);

                if(this.document && this.document.TurnOn_Recalculate)
                {
                    this.document.TurnOn_Recalculate();
                }
            }
            var oPreset = oAscTextArtProperties.asc_getForm();
            if(typeof oPreset === "string")
            {
                for(i = 0; i < objects_by_type.shapes.length; ++i)
                {
                    objects_by_type.shapes[i].applyTextArtForm(oPreset);
                }
                for(i = 0; i < objects_by_type.groups.length; ++i)
                {
                    objects_by_type.groups[i].applyTextArtForm(oPreset);
                }
                this.resetTextSelection();
            }
        }
        var oApi = this.getEditorApi();
        if(oApi && oApi.noCreatePoint && !oApi.exucuteHistory)
        {
            for(i = 0; i < objects_by_type.shapes.length; ++i)
            {
                if(bRecalcText)
                {
                    objects_by_type.shapes[i].recalcText();
                    if(bWord)
                    {
                        objects_by_type.shapes[i].recalculateText();
                    }
                }
                objects_by_type.shapes[i].recalculate();
            }
            for(i = 0; i < objects_by_type.groups.length; ++i)
            {
                if(bRecalcText)
                {
                    objects_by_type.groups[i].recalcText();
                    if(bWord)
                    {
                        objects_by_type.shapes[i].recalculateText();
                    }
                }
                objects_by_type.groups[i].recalculate();
            }
        }
        return objects_by_type;
    },

    getSelectedObjectsByTypes: function(bGroupedObjects)
    {
        var selected_objects = this.selection.groupSelection ? this.selection.groupSelection.selectedObjects : this.selectedObjects;
        return getObjectsByTypesFromArr(selected_objects, bGroupedObjects);
    },

    editChartCallback: function(chartSettings)
    {
        var objects_by_types = this.getSelectedObjectsByTypes();
        if(objects_by_types.charts.length === 1)
        {
            var chart_space = objects_by_types.charts[0];
            this.applyPropsToChartSpace(chartSettings, chart_space);
        }
    },

    applyPropsToChartSpace: function(chartSettings, chartSpace)
    {
        var chart_space = chartSpace;
        var style_index = chartSettings.getStyle();
        var sRange = chartSettings.getRange();
        var b_clear_formatting = false;
        chartSpace.resetSelection(true);
        var oPr = this.getPropsFromChart(chart_space);
        if(oPr.isEqual(chartSettings)){


            var oChartType = chart_space && chart_space.chart && chart_space.chart.plotArea && chart_space.chart.plotArea.charts[0];
            if(!oChartType){
                return;
            }
            //подписи данных
            if(typeof oChartType.setDLbls === "function" && AscFormat.isRealNumber(chartSettings.getDataLabelsPos()) && chartSettings.getDataLabelsPos() !== c_oAscChartDataLabelsPos.none)
            {
                if(oChartType.dLbls && oChartType.dLbls.bDelete){
                    oChartType.dLbls.setDelete(false);
                }
                for(var i = 0; i < oChartType.series.length; ++i){
                    var oSerie = oChartType.series[i];
                    if(oSerie.dLbls){
                        if(oSerie.dLbls.bDelete){
                            oSerie.dLbls.setDelete(false);
                            for(var j = 0; j < oSerie.dLbls.dLbl.length; ++j){
                                if(oSerie.dLbls.dLbl[j].bDelete){
                                    oSerie.dLbls.dLbl[j].setDelete(false);
                                }
                            }
                        }
                    }
                }
            }

            return;
        }

        //for bug http://bugzilla.onlyoffice.com/show_bug.cgi?id=35570
        var type = chartSettings.getType();
        if(oPr.getType() === type){
            chartSettings.type = null;
            var testChartSettings = new Asc.asc_ChartSettings();
            if(testChartSettings.isEqual(chartSettings)){
                chartSettings.type = type;
                return;
            }
            chartSettings.type = type;
        }

        //Title Settings
        chart_space.setChart(chart_space.chart.createDuplicate());

        /*if(AscFormat.isRealNumber(style_index) && style_index > 0 && style_index < 49 && chart_space.style !== style_index)
        {
            if(!b_clear_formatting)
            {
                chart_space.clearFormatting();
            }
            chart_space.setStyle(style_index);
        }*/

        var chart = chart_space.chart;
        var plot_area = chart.plotArea;
        if(AscFormat.isRealNumber(style_index)){
            --style_index;
            var oCurChartSettings = oPr;
            var _cur_type = oCurChartSettings.type;
            if(AscCommon.g_oChartPresets[_cur_type] && AscCommon.g_oChartPresets[_cur_type][style_index]){

                plot_area.removeCharts(1, plot_area.charts.length - 1);
                AscFormat.ApplyPresetToChartSpace(chartSpace, AscCommon.g_oChartPresets[_cur_type][style_index], chartSettings.bCreate);
                return;
            }
        }


        chart_space.updateLinks();
        var oValAx = chart_space.chart.plotArea.valAx;
        var oCatAx = chart_space.chart.plotArea.catAx;
        chart_space.setStyle(chart_space.style);
        if(this.drawingObjects && this.drawingObjects.getWorksheet && typeof sRange === "string" && sRange.length > 0)
        {
            var ws_view = this.drawingObjects.getWorksheet();
            var parsed_formula = parserHelp.parse3DRef(sRange);
            if(parsed_formula)
            {

                var ws = ws_view.model.workbook.getWorksheetByName(parsed_formula.sheet);
                var new_bbox;
                var range_object = ws.getRange2(parsed_formula.range);
                if(range_object)
                {
                    new_bbox = range_object.bbox;
                }
                if(ws && new_bbox )
                {
                    var oCommonBBox = chart_space.getCommonBBox();
                    var b_equal_bbox = oCommonBBox && oCommonBBox.r1 === new_bbox.r1
                        && oCommonBBox.r2 === new_bbox.r2
                        && oCommonBBox.c1 === new_bbox.c1
                        && oCommonBBox.c2 === new_bbox.c2;
                    var b_equal_ws = chart_space.bbox && chart_space.bbox.worksheet === ws;
                    var b_equal_vert = chart_space.bbox && chartSettings.getInColumns() === !chart_space.bbox.seriesBBox.bVert;

                    var bLimit = (Math.abs(new_bbox.r2 - new_bbox.r1) > 4096 || Math.abs(new_bbox.c2 - new_bbox.c1) > 4096);
                    if(!(chart_space.bbox && chart_space.bbox.seriesBBox && b_equal_ws
                        && b_equal_bbox && b_equal_vert ) && !bLimit)
                    {
                        var catHeadersBBox, serHeadersBBox;
                        if(chart_space.bbox && b_equal_bbox && b_equal_ws && !b_equal_vert)
                        {
                            if(chart_space.bbox.catBBox)
                                serHeadersBBox = {r1: chart_space.bbox.catBBox.r1, r2: chart_space.bbox.catBBox.r2,
                                    c1: chart_space.bbox.catBBox.c1, c2: chart_space.bbox.catBBox.c2};
                            if(chart_space.bbox.serBBox)
                                catHeadersBBox = {r1: chart_space.bbox.serBBox.r1, r2: chart_space.bbox.serBBox.r2,
                                    c1: chart_space.bbox.serBBox.c1, c2: chart_space.bbox.serBBox.c2};
                        }
                        var chartSeries = AscFormat.getChartSeries(ws_view.model, chartSettings, catHeadersBBox, serHeadersBBox);
                        //chart_space.clearFormatting(true);
                        b_clear_formatting = true;
                        chart_space.rebuildSeriesFromAsc(chartSeries);
                        if(chart_space.pivotSource){
                            chart_space.setPivotSource(null);
                        }
                    }
                }
            }
        }


        var title_show_settings = chartSettings.getTitle();
        if(title_show_settings === c_oAscChartTitleShowSettings.none)
        {
            if(chart.title)
            {
                chart.setTitle(null);
            }
        }
        else if(title_show_settings === c_oAscChartTitleShowSettings.noOverlay
            || title_show_settings === c_oAscChartTitleShowSettings.overlay)
        {
            if(!chart.title)
            {
                chart.setTitle(new AscFormat.CTitle());
            }
            if(chart.title.overlay !== (title_show_settings === c_oAscChartTitleShowSettings.overlay))
            {
                chart.title.setOverlay(title_show_settings === c_oAscChartTitleShowSettings.overlay);
            }
        }
        //horAxisLabel


        //legend
        var legend_pos_settings =  chartSettings.getLegendPos();
        if(legend_pos_settings !== null)
        {
            if(legend_pos_settings === c_oAscChartLegendShowSettings.none)
            {
                if(chart.legend)
                {
                    chart.setLegend(null);
                }
            }
            else
            {
                if(!chart.legend)
                {
                    chart.setLegend(new AscFormat.CLegend());
                }
                if(chart.legend.legendPos !== legend_pos_settings && legend_pos_settings !== c_oAscChartLegendShowSettings.layout)
                    chart.legend.setLegendPos(legend_pos_settings);
                var b_overlay = c_oAscChartLegendShowSettings.leftOverlay === legend_pos_settings || legend_pos_settings === c_oAscChartLegendShowSettings.rightOverlay;
                if(chart.legend.overlay !== b_overlay)
                {
                    chart.legend.setOverlay(b_overlay);
                }
            }
        }


        var chart_type = plot_area.charts[0];
        plot_area.removeCharts(1, plot_area.charts.length - 1);
        //Data Labels
        var i;
        var need_groupping, need_num_fmt, need_bar_dir;
        var val_axis, new_chart_type, object_type, axis_obj ;
        var axis_by_types;
        var val_ax, cat_ax;
        object_type = chart_type.getObjectType();
        var sDefaultValAxFormatCode = null;
        if(chart_type && chart_type.series[0]){
            var aPoints = AscFormat.getPtsFromSeries(chart_type.series[0]);
            if(aPoints[0] && typeof aPoints[0].formatCode === "string" && aPoints[0].formatCode.length > 0){
                sDefaultValAxFormatCode = aPoints[0].formatCode;
            }
        }
        need_num_fmt = sDefaultValAxFormatCode;

        var checkSwapAxis = function(plotArea, chartType, newChartType)
        {
            if(chartType.getAxisByTypes )
            {
                var axis_by_types = chartType.getAxisByTypes(), cat_ax, val_ax;
                if(axis_by_types.catAx.length > 0 && axis_by_types.valAx.length > 0)
                {
                    cat_ax = axis_by_types.catAx[0];
                    val_ax = axis_by_types.valAx[0];
                }
            }
            if(!val_ax || !cat_ax)
            {
                var axis_obj = AscFormat.CreateDefaultAxises(need_num_fmt ? need_num_fmt : "General");
                cat_ax = axis_obj.catAx;
                val_ax = axis_obj.valAx;



                if(oValAx && oValAx instanceof AscFormat.CValAx){
                    oValAx.createDuplicate(val_ax);
                    val_ax.numFmt.setFormatCode(need_num_fmt);
                }
                if(oCatAx){
                    if(oCatAx.majorGridlines)
                    {
                        axis_obj.catAx.setMajorGridlines(oCatAx.majorGridlines.createDuplicate());
                    }
                    axis_obj.catAx.setMajorTickMark(oCatAx.majorTickMark);

                    if(oCatAx.minorGridlines)
                    {
                        axis_obj.catAx.setMinorGridlines(oCatAx.minorGridlines.createDuplicate());
                    }
                    axis_obj.catAx.setMinorTickMark(oCatAx.minorTickMark);

                    if(oCatAx.spPr)
                    {
                        axis_obj.catAx.setSpPr(oCatAx.spPr.createDuplicate());
                    }
                    axis_obj.catAx.setTickLblPos(oCatAx.tickLblPos);
                    if(oCatAx.title)
                    {
                        axis_obj.catAx.setTitle(oCatAx.title.createDuplicate());
                    }
                    if(oCatAx.txPr)
                    {
                        axis_obj.catAx.setTxPr(oCatAx.txPr.createDuplicate());
                    }
                }

            }
            if(cat_ax && val_ax)
            {
                if(newChartType.getObjectType() === AscDFH.historyitem_type_BarChart && newChartType.barDir === BAR_DIR_BAR)
                {
                    if(cat_ax.axPos !== AscFormat.AX_POS_L)
                    {
                        cat_ax.setAxPos(AscFormat.AX_POS_L);
                    }
                    if(val_ax.axPos !== AscFormat.AX_POS_B)
                    {
                        val_ax.setAxPos(AscFormat.AX_POS_B);
                    }
                }
                else
                {
                    if(cat_ax.axPos !== AscFormat.AX_POS_B)
                    {
                        cat_ax.setAxPos(AscFormat.AX_POS_B);
                    }
                    if(val_ax.axPos !== AscFormat.AX_POS_L)
                    {
                        val_ax.setAxPos(AscFormat.AX_POS_L);
                    }
                }
                newChartType.addAxId(cat_ax);
                newChartType.addAxId(val_ax);
                plotArea.addAxis(cat_ax);
                plotArea.addAxis(val_ax);
            }
        };

        var replaceChart = function(plotArea, chartType, newChartType)
        {
            plotArea.addChart(newChartType, 0);
            plotArea.removeCharts(1, plotArea.charts.length - 1);
            newChartType.setFromOtherChart(chartType);
            if(newChartType.getObjectType() !== AscDFH.historyitem_type_PieChart && newChartType.getObjectType() !== AscDFH.historyitem_type_DoughnutChart)
            {
                if(newChartType.setVaryColors && newChartType.varyColors === true)
                {
                    newChartType.setVaryColors(false);
                }
            }
        };

        switch(type)
        {
            case c_oAscChartTypeSettings.barNormal     :
            case c_oAscChartTypeSettings.barStacked    :
            case c_oAscChartTypeSettings.barStackedPer :
            case c_oAscChartTypeSettings.barNormal3d           :
            case c_oAscChartTypeSettings.barStacked3d          :
            case c_oAscChartTypeSettings.barStackedPer3d       :
            case c_oAscChartTypeSettings.barNormal3dPerspective:
            case c_oAscChartTypeSettings.hBarNormal    :
            case c_oAscChartTypeSettings.hBarStacked   :
            case c_oAscChartTypeSettings.hBarStackedPer:
            case c_oAscChartTypeSettings.hBarNormal3d:
            case c_oAscChartTypeSettings.hBarStacked3d:
            case c_oAscChartTypeSettings.hBarStackedPer3d:
            {
                if(type === c_oAscChartTypeSettings.barNormal || type === c_oAscChartTypeSettings.hBarNormal
                    || type === c_oAscChartTypeSettings.barNormal3d || type === c_oAscChartTypeSettings.hBarNormal3d )
                    need_groupping = BAR_GROUPING_CLUSTERED;
                else if(type === c_oAscChartTypeSettings.barStacked || type === c_oAscChartTypeSettings.hBarStacked
                    || type === c_oAscChartTypeSettings.barStacked3d || type === c_oAscChartTypeSettings.hBarStacked3d)
                    need_groupping = BAR_GROUPING_STACKED;
                else if(type === c_oAscChartTypeSettings.barNormal3dPerspective)
                    need_groupping = BAR_GROUPING_STANDARD;
                else
                    need_groupping = BAR_GROUPING_PERCENT_STACKED;

                var bNeed3D = type === c_oAscChartTypeSettings.barNormal3d || type === c_oAscChartTypeSettings.barStacked3d
                    || type === c_oAscChartTypeSettings.barStackedPer3d || type === c_oAscChartTypeSettings.barNormal3dPerspective
                    || type === c_oAscChartTypeSettings.hBarNormal3d || type === c_oAscChartTypeSettings.hBarStacked3d || type === c_oAscChartTypeSettings.hBarStackedPer3d;

                if( type === c_oAscChartTypeSettings.barNormal || type === c_oAscChartTypeSettings.barStacked
                    || type === c_oAscChartTypeSettings.barNormal3d || type === c_oAscChartTypeSettings.barStacked3d
                    || type === c_oAscChartTypeSettings.hBarNormal || type === c_oAscChartTypeSettings.hBarStacked
                    || type === c_oAscChartTypeSettings.hBarNormal3d || type === c_oAscChartTypeSettings.hBarStacked3d
                    || type === c_oAscChartTypeSettings.barNormal3dPerspective){
                    need_num_fmt = sDefaultValAxFormatCode;

                }
                else
                    need_num_fmt = "0%";

                if(type === c_oAscChartTypeSettings.barNormal || type === c_oAscChartTypeSettings.barStacked || type === c_oAscChartTypeSettings.barStackedPer
                    || type === c_oAscChartTypeSettings.barNormal3d || type === c_oAscChartTypeSettings.barStacked3d || type === c_oAscChartTypeSettings.barStackedPer3d  || type === c_oAscChartTypeSettings.barNormal3dPerspective)
                    need_bar_dir = BAR_DIR_COL;
                else
                    need_bar_dir = BAR_DIR_BAR;

                if(chart_type.getObjectType() === AscDFH.historyitem_type_BarChart)
                {
                    var bChangedGrouping = false;
                    var nOldGrouping = chart_type.grouping;
                    if(chart_type.grouping !== need_groupping)
                    {
                        chart_type.setGrouping(need_groupping);
                        bChangedGrouping = true;
                    }

                    if(!AscFormat.isRealNumber(chart_type.gapWidth))
                    {
                        chart_type.setGapWidth(150);
                    }
                    if(BAR_GROUPING_PERCENT_STACKED === need_groupping || BAR_GROUPING_STACKED === need_groupping)
                    {
                        if(!AscFormat.isRealNumber(chart_type.overlap) || nOldGrouping !== BAR_GROUPING_PERCENT_STACKED || nOldGrouping !== BAR_GROUPING_STACKED)
                        {
                            chart_type.setOverlap(100);
                        }
                    }
                    else
                    {
                        if(bChangedGrouping && chart_type.overlap !== null)
                        {
                            chart_type.setOverlap(null);
                        }
                    }

                    axis_by_types = chart_type.getAxisByTypes();
                    if(chart_type.barDir !== need_bar_dir)
                    {
                        val_axis = axis_by_types.valAx;
                        if(need_bar_dir === BAR_DIR_BAR)
                        {
                            for(i = 0; i < val_axis.length; ++i)
                                val_axis[i].setAxPos(AscFormat.AX_POS_B);

                            for(i = 0; i < axis_by_types.catAx.length; ++i)
                                axis_by_types.catAx[i].setAxPos(AscFormat.AX_POS_L);
                        }
                        else
                        {
                            for(i = 0; i < val_axis.length; ++i)
                                val_axis[i].setAxPos(AscFormat.AX_POS_L);

                            for(i = 0; i < axis_by_types.catAx.length; ++i)
                                axis_by_types.catAx[i].setAxPos(AscFormat.AX_POS_B);
                        }
                        chart_type.setBarDir(need_bar_dir);
                    }

                    if(bNeed3D)
                    {
                        if(!chart_type.b3D)
                        {
                            chart_type.set3D(true);
                        }
                        if(!chart.view3D)
                        {
                            chart.setView3D(new AscFormat.CView3d());
                        }

                        var oView3d = chart.view3D;
                        if(!AscFormat.isRealNumber(oView3d.rotX))
                        {
                            oView3d.setRotX(15);
                        }
                        if(!AscFormat.isRealNumber(oView3d.rotY))
                        {
                            oView3d.setRotY(20);
                        }
                        if(!AscFormat.isRealBool(oView3d.rAngAx))
                        {
                            oView3d.setRAngAx(true);
                        }
                        if(c_oAscChartTypeSettings.barNormal3dPerspective === type)
                        {
                            if(!AscFormat.isRealNumber(oView3d.depthPercent))
                            {
                                oView3d.setDepthPercent(100);
                            }
                        }
                        else
                        {
                            if(null !== oView3d.depthPercent)
                            {
                                oView3d.setDepthPercent(null);
                            }
                        }

                        chart.setDefaultWalls();
                    }
                    else
                    {
                        if(chart_type.b3D)
                        {
                            chart_type.set3D(false);
                        }
                        if(chart.view3D)
                        {
                            chart.setView3D(null);
                        }
                        if(chart.floor)
                        {
                            chart.setFloor(null);
                        }
                        if(chart.sideWall)
                        {
                            chart.setSideWall(null);
                        }
                        if(chart.backWall)
                        {
                            chart.setBackWall(null);
                        }
                    }
                    val_axis = axis_by_types.valAx;
                    for(i = 0; i < val_axis.length; ++i)
                    {
                        if(!val_axis[i].numFmt)
                        {
                            val_axis[i].setNumFmt(new AscFormat.CNumFmt());
                            val_axis[i].numFmt.setFormatCode(sDefaultValAxFormatCode ? sDefaultValAxFormatCode : "General");
                            val_axis[i].numFmt.setSourceLinked(true);
                        }
                        if(need_num_fmt && val_axis[i].numFmt.formatCode !== need_num_fmt)
                            val_axis[i].numFmt.setFormatCode(need_num_fmt);
                    }
                }
                else
                {
                    new_chart_type = new AscFormat.CBarChart();
                    replaceChart(plot_area, chart_type, new_chart_type);
                    new_chart_type.setBarDir(need_bar_dir);
                    checkSwapAxis(plot_area, chart_type, new_chart_type);
                    new_chart_type.setGrouping(need_groupping);
                    new_chart_type.setGapWidth(150);

                    if(BAR_GROUPING_PERCENT_STACKED === need_groupping || BAR_GROUPING_STACKED === need_groupping)
                        new_chart_type.setOverlap(100);

                    if(bNeed3D)
                    {
                        if(!chart.view3D){
                            chart.setView3D(AscFormat.CreateView3d(15, 20, true, c_oAscChartTypeSettings.barNormal3dPerspective === type ? 100 : undefined));
                            chart.setDefaultWalls();
                        }
                        if(!new_chart_type.b3D){
                            new_chart_type.set3D(true);
                        }

                    }
                    else
                    {
                        if(chart.view3D)
                        {
                            chart.setView3D(null);
                        }
                        if(chart.floor)
                        {
                            chart.setFloor(null);
                        }
                        if(chart.sideWall)
                        {
                            chart.setSideWall(null);
                        }
                        if(chart.backWall)
                        {
                            chart.setBackWall(null);
                        }
                    }

                    axis_by_types = new_chart_type.getAxisByTypes();
                    val_axis = axis_by_types.valAx;
                    for(i = 0; i < val_axis.length; ++i)
                    {
                        if(!val_axis[i].numFmt)
                        {
                            val_axis[i].setNumFmt(new AscFormat.CNumFmt());
                            val_axis[i].numFmt.setFormatCode(sDefaultValAxFormatCode ? sDefaultValAxFormatCode : "General");
                            val_axis[i].numFmt.setSourceLinked(true);
                        }
                        if(need_num_fmt && val_axis[i].numFmt.formatCode !== need_num_fmt)
                            val_axis[i].numFmt.setFormatCode(need_num_fmt);
                        if(need_bar_dir = BAR_DIR_BAR)
                            val_axis[i].setAxPos(AscFormat.AX_POS_B);
                    }
                    if(need_bar_dir = BAR_DIR_BAR)
                    {
                        for(i = 0; i < axis_by_types.catAx.length; ++i)
                            axis_by_types.catAx[i].setAxPos(AscFormat.AX_POS_L);
                    }
                }
                break;
            }
            case c_oAscChartTypeSettings.lineNormal           :
            case c_oAscChartTypeSettings.lineStacked          :
            case c_oAscChartTypeSettings.lineStackedPer      :
            case c_oAscChartTypeSettings.lineNormalMarker    :
            case c_oAscChartTypeSettings.lineStackedMarker   :
            case c_oAscChartTypeSettings.lineStackedPerMarker:
            case c_oAscChartTypeSettings.line3d:
            {
                if(type === c_oAscChartTypeSettings.lineNormal || type === c_oAscChartTypeSettings.lineNormalMarker || type === c_oAscChartTypeSettings.line3d)
                    need_groupping = GROUPING_STANDARD;
                else if(type === c_oAscChartTypeSettings.lineStacked || type === c_oAscChartTypeSettings.lineStackedMarker)
                    need_groupping = GROUPING_STACKED;
                else
                    need_groupping = GROUPING_PERCENT_STACKED;

                if(type === c_oAscChartTypeSettings.lineNormal || type === c_oAscChartTypeSettings.lineStacked  || type === c_oAscChartTypeSettings.line3d
                    || type === c_oAscChartTypeSettings.lineNormalMarker || type === c_oAscChartTypeSettings.lineStackedMarker)
                    need_num_fmt = sDefaultValAxFormatCode;
                else
                    need_num_fmt = "0%";

                var b_marker = chartSettings.getShowMarker();

                if(chart_type.getObjectType() === AscDFH.historyitem_type_LineChart)
                {
                    if(chart_type.grouping !== need_groupping)
                        chart_type.setGrouping(need_groupping);
                    val_axis = chart_type.getAxisByTypes().valAx;
                    for(i = 0; i < val_axis.length; ++i)
                    {
                        if(!val_axis[i].numFmt)
                        {
                            val_axis[i].setNumFmt(new AscFormat.CNumFmt());
                            val_axis[i].numFmt.setFormatCode(sDefaultValAxFormatCode ? sDefaultValAxFormatCode : "General");
                            val_axis[i].numFmt.setSourceLinked(true);
                        }
                        if(need_num_fmt && val_axis[i].numFmt.formatCode !== need_num_fmt)
                            val_axis[i].numFmt.setFormatCode(need_num_fmt);
                    }



                    if(type === c_oAscChartTypeSettings.line3d)
                    {

                        if(!chart.view3D)
                        {
                            chart.setView3D(new AscFormat.CView3d());
                        }

                        var oView3d = chart.view3D;
                        if(!AscFormat.isRealNumber(oView3d.rotX))
                        {
                            oView3d.setRotX(15);
                        }
                        if(!AscFormat.isRealNumber(oView3d.rotY))
                        {
                            oView3d.setRotY(20);
                        }
                        if(!AscFormat.isRealBool(oView3d.rAngAx))
                        {
                            oView3d.setRAngAx(true);
                        }
                        if(!AscFormat.isRealNumber(oView3d.depthPercent))
                        {
                            oView3d.setDepthPercent(100);
                        }
                        chart.setDefaultWalls();
                    }
                    else
                    {
                        if(chart.view3D)
                        {
                            chart.setView3D(null);
                            chartSettings.bLine = true;
                            new_chart_type = new AscFormat.CLineChart();
                            replaceChart(plot_area, chart_type, new_chart_type);
                            checkSwapAxis(plot_area, chart_type, new_chart_type);
                        }
                        if(chart.floor)
                        {
                            chart.setFloor(null);
                        }
                        if(chart.sideWall)
                        {
                            chart.setSideWall(null);
                        }
                        if(chart.backWall)
                        {
                            chart.setBackWall(null);
                        }
                    }

                   // if((AscFormat.isRealBool(chart_type.marker) && chart_type.marker) !== b_marker)
                   //     chart_type.setMarker(b_marker);
                }
                else
                {


                    new_chart_type = new AscFormat.CLineChart();
                    replaceChart(plot_area, chart_type, new_chart_type);
                    checkSwapAxis(plot_area, chart_type, new_chart_type);
                    val_axis = new_chart_type.getAxisByTypes().valAx;
                    for(i = 0; i < val_axis.length; ++i)
                    {
                        if(!val_axis[i].numFmt)
                        {
                            val_axis[i].setNumFmt(new AscFormat.CNumFmt());
                            val_axis[i].numFmt.setFormatCode(sDefaultValAxFormatCode ? sDefaultValAxFormatCode : "General");
                            val_axis[i].numFmt.setSourceLinked(true);
                        }
                        if(need_num_fmt && val_axis[i].numFmt.formatCode !== need_num_fmt)
                            val_axis[i].numFmt.setFormatCode(need_num_fmt);
                    }
                    if(type === c_oAscChartTypeSettings.line3d)
                    {
                        if(!chart.view3D){
                            chart.setView3D(AscFormat.CreateView3d(15, 20, true, 100));
                            chart.setDefaultWalls();
                        }
                    }
                    else
                    {
                        if(chart.view3D)
                        {
                            chart.setView3D(null);
                        }
                        if(chart.floor)
                        {
                            chart.setFloor(null);
                        }
                        if(chart.sideWall)
                        {
                            chart.setSideWall(null);
                        }
                        if(chart.backWall)
                        {
                            chart.setBackWall(null);
                        }
                    }
                    //new_chart_type.setMarker(b_marker);
                    new_chart_type.setGrouping(need_groupping);
                }
                break;
            }
            case c_oAscChartTypeSettings.pie:
            case c_oAscChartTypeSettings.pie3d:
            {
                if(chart_type.getObjectType() !== AscDFH.historyitem_type_PieChart)
                {
                    new_chart_type = new AscFormat.CPieChart();
                    replaceChart(plot_area, chart_type, new_chart_type);
                    new_chart_type.setVaryColors(true);
                    if(type === c_oAscChartTypeSettings.pie3d)
                    {
                        if(!chart.view3D){
                            chart.setView3D(AscFormat.CreateView3d(30, 0, true, 100));
                            chart.setDefaultWalls();
                        }
                        if(!chart.view3D.rAngAx){
                            chart.view3D.setRAngAx(true);
                        }
                        if(chart.view3D.rotX < 0){
                            chart.view3D.rotX = 30;
                        }
                    }
                    else
                    {
                        if(chart.view3D)
                        {
                            chart.setView3D(null);
                        }
                        if(chart.floor)
                        {
                            chart.setFloor(null);
                        }
                        if(chart.sideWall)
                        {
                            chart.setSideWall(null);
                        }
                        if(chart.backWall)
                        {
                            chart.setBackWall(null);
                        }
                    }
                }
                else
                {
                    if(type === c_oAscChartTypeSettings.pie3d)
                    {
                        if(!chart.view3D)
                        {
                            chart.setView3D(new AscFormat.CView3d());
                        }

                        var oView3d = chart.view3D;
                        if(!AscFormat.isRealNumber(oView3d.rotX))
                        {
                            oView3d.setRotX(30);
                        }
                        if(!AscFormat.isRealNumber(oView3d.rotY))
                        {
                            oView3d.setRotY(0);
                        }
                        if(!AscFormat.isRealBool(oView3d.rAngAx))
                        {
                            oView3d.setRAngAx(true);
                        }
                        if(!AscFormat.isRealNumber(oView3d.depthPercent))
                        {
                            oView3d.setDepthPercent(100);
                        }
                        chart.setDefaultWalls();
                    }
                    else
                    {
                        if(chart.view3D)
                        {
                            chart.setView3D(null);
                        }
                        if(chart.floor)
                        {
                            chart.setFloor(null);
                        }
                        if(chart.sideWall)
                        {
                            chart.setSideWall(null);
                        }
                        if(chart.backWall)
                        {
                            chart.setBackWall(null);
                        }
                    }
                }
                break;
            }
            case c_oAscChartTypeSettings.doughnut:
            {
                if(chart_type.getObjectType() !== AscDFH.historyitem_type_DoughnutChart)
                {
                    new_chart_type = new AscFormat.CDoughnutChart();
                    replaceChart(plot_area, chart_type, new_chart_type);
                    new_chart_type.setVaryColors(true);
                    new_chart_type.setHoleSize(50);
                }
                break;
            }
            case c_oAscChartTypeSettings.areaNormal:
            case c_oAscChartTypeSettings.areaStacked:
            case c_oAscChartTypeSettings.areaStackedPer:
            {

                if(type === c_oAscChartTypeSettings.areaNormal)
                    need_groupping = GROUPING_STANDARD;
                else if(type === c_oAscChartTypeSettings.areaStacked)
                    need_groupping = GROUPING_STACKED;
                else
                    need_groupping = GROUPING_PERCENT_STACKED;

                if(type === c_oAscChartTypeSettings.areaNormal || type === c_oAscChartTypeSettings.areaStacked)
                    need_num_fmt = sDefaultValAxFormatCode;
                else
                    need_num_fmt = "0%";

                if(chart_type.getObjectType() === AscDFH.historyitem_type_AreaChart)
                {
                    if(chart_type.grouping !== need_groupping)
                        chart_type.setGrouping(need_groupping);
                    val_axis = chart_type.getAxisByTypes().valAx;
                    for(i = 0; i < val_axis.length; ++i)
                    {
                        if(!val_axis[i].numFmt)
                        {
                            val_axis[i].setNumFmt(new AscFormat.CNumFmt());
                            val_axis[i].numFmt.setFormatCode(sDefaultValAxFormatCode ? sDefaultValAxFormatCode : "General");
                            val_axis[i].numFmt.setSourceLinked(true);
                        }
                        if(need_num_fmt && val_axis[i].numFmt.formatCode !== need_num_fmt)
                            val_axis[i].numFmt.setFormatCode(need_num_fmt);
                    }
                }
                else
                {
                    new_chart_type = new AscFormat.CAreaChart();
                    replaceChart(plot_area, chart_type, new_chart_type);
                    checkSwapAxis(plot_area, chart_type, new_chart_type);

                    val_axis = new_chart_type.getAxisByTypes().valAx;
                    for(i = 0; i < val_axis.length; ++i)
                    {
                        if(!val_axis[i].numFmt)
                        {
                            val_axis[i].setNumFmt(new AscFormat.CNumFmt());
                            val_axis[i].numFmt.setFormatCode(sDefaultValAxFormatCode ? sDefaultValAxFormatCode : "General");
                            val_axis[i].numFmt.setSourceLinked(true);
                        }
                        if(need_num_fmt && val_axis[i].numFmt.formatCode !== need_num_fmt)
                            val_axis[i].numFmt.setFormatCode(need_num_fmt);
                    }
                    new_chart_type.setGrouping(need_groupping);
                }
                chart_space.chart.setView3D(null);
                break;
            }
            case c_oAscChartTypeSettings.scatter:
            case c_oAscChartTypeSettings.scatterLine:
            case c_oAscChartTypeSettings.scatterSmooth:
            {
                if(chart_type.getObjectType() !== AscDFH.historyitem_type_ScatterChart)
                {
                    new_chart_type = new AscFormat.CScatterChart();
                    replaceChart(plot_area, chart_type, new_chart_type);
                    for(var j = 0; j < new_chart_type.series.length; ++j)
                    {
                        new_chart_type.series[j].setMarker(null);
                    }
                    new_chart_type.setScatterStyle(SCATTER_STYLE_MARKER);
                    axis_obj = AscFormat.CreateScatterAxis(); //cat - 0, val - 1
                    if(oValAx && oValAx instanceof AscFormat.CValAx){
                        oValAx.createDuplicate(axis_obj.valAx);
                        axis_obj.valAx.setAxPos(AscFormat.AX_POS_L);
                    }
                    if(oCatAx){
                        if(oCatAx.majorGridlines)
                        {
                            axis_obj.catAx.setMajorGridlines(oCatAx.majorGridlines.createDuplicate());
                        }
                        axis_obj.catAx.setMajorTickMark(oCatAx.majorTickMark);

                        if(oCatAx.minorGridlines)
                        {
                            axis_obj.catAx.setMinorGridlines(oCatAx.minorGridlines.createDuplicate());
                        }
                        axis_obj.catAx.setMinorTickMark(oCatAx.minorTickMark);

                        if(oCatAx.spPr)
                        {
                            axis_obj.catAx.setSpPr(oCatAx.spPr.createDuplicate());
                        }
                        axis_obj.catAx.setTickLblPos(oCatAx.tickLblPos);
                        if(oCatAx.title)
                        {
                            axis_obj.catAx.setTitle(oCatAx.title.createDuplicate());
                        }
                        if(oCatAx.txPr)
                        {
                            axis_obj.catAx.setTxPr(oCatAx.txPr.createDuplicate());
                        }
                    }
                    new_chart_type.addAxId(axis_obj.catAx);
                    new_chart_type.addAxId(axis_obj.valAx);
                    plot_area.addAxis(axis_obj.catAx);
                    plot_area.addAxis(axis_obj.valAx);
                }
                break;
            }
            case c_oAscChartTypeSettings.stock:
            {
                if(chart_type.getObjectType() !== AscDFH.historyitem_type_StockChart)
                {
                    new_chart_type = new AscFormat.CStockChart();
                    replaceChart(plot_area, chart_type, new_chart_type);
                    checkSwapAxis(plot_area, chart_type, new_chart_type);

                    new_chart_type.setHiLowLines(new AscFormat.CSpPr());
                    new_chart_type.setUpDownBars(new AscFormat.CUpDownBars());
                    new_chart_type.upDownBars.setGapWidth(150);
                    new_chart_type.upDownBars.setUpBars(new AscFormat.CSpPr());
                    new_chart_type.upDownBars.setDownBars(new AscFormat.CSpPr());
                    val_axis = new_chart_type.getAxisByTypes().valAx;
                    for(i = 0; i < val_axis.length; ++i)
                    {
                        if(!val_axis[i].numFmt)
                        {
                            val_axis[i].setNumFmt(new AscFormat.CNumFmt());
                            val_axis[i].numFmt.setSourceLinked(true);
                        }
                        if(val_axis[i].numFmt.formatCode !== "General")
                            val_axis[i].numFmt.setFormatCode("General");
                    }
                }
                break;
            }
        }


        var hor_axis = plot_area.getHorizontalAxis();
        var hor_axis_label_setting = chartSettings.getHorAxisLabel();
        if(hor_axis)
        {
            if(hor_axis_label_setting !== null)
            {
                switch (hor_axis_label_setting)
                {
                    case c_oAscChartHorAxisLabelShowSettings.none:
                    {
                        if(hor_axis.title)
                            hor_axis.setTitle(null);
                        break;
                    }
                    case c_oAscChartHorAxisLabelShowSettings.noOverlay:
                    {
                        var _text_body;
                        if(hor_axis.title && hor_axis.title.tx && hor_axis.title.tx.rich)
                        {
                            _text_body = hor_axis.title.tx.rich;
                        }
                        else
                        {
                            if(!hor_axis.title)
                            {
                                hor_axis.setTitle(new AscFormat.CTitle());
                            }
                            if(!hor_axis.title.txPr)
                            {
                                hor_axis.title.setTxPr(new AscFormat.CTextBody());
                            }
                            if(!hor_axis.title.txPr.bodyPr)
                            {
                                hor_axis.title.txPr.setBodyPr(new AscFormat.CBodyPr());
                            }
                            if(!hor_axis.title.txPr.content)
                            {
                                hor_axis.title.txPr.setContent(new AscFormat.CDrawingDocContent(hor_axis.title.txPr, chart_space.getDrawingDocument(), 0, 0, 100, 500, false, false, true));
                            }
                            _text_body = hor_axis.title.txPr;
                        }
                        if(hor_axis.title.overlay !== false)
                            hor_axis.title.setOverlay(false);

                        if(!_text_body.bodyPr || _text_body.bodyPr.isNotNull())
                        {
                            _text_body.setBodyPr(new AscFormat.CBodyPr());
                        }

                        break;
                    }
                }
            }
            hor_axis.setMenuProps(chartSettings.getHorAxisProps());
            if(AscFormat.isRealBool(chartSettings.getShowHorAxis())){
                hor_axis.setDelete(!chartSettings.getShowHorAxis());
            }
        }

        //vertAxis
        var vert_axis = plot_area.getVerticalAxis(); //TODO: запрашивать у chart_type
        var vert_axis_labels_settings = chartSettings.getVertAxisLabel();
        if(vert_axis)
        {
            if(vert_axis_labels_settings !== null)
            {
                switch (vert_axis_labels_settings)
                {
                    case c_oAscChartVertAxisLabelShowSettings.none:
                    {
                        if(vert_axis.title)
                        {
                            vert_axis.setTitle(null);
                        }
                        break;
                    }
                    case c_oAscChartVertAxisLabelShowSettings.vertical:
                    {
                        //TODO: пока СDocumentContent не поддерживает вертикальный текст, может быть будет когда-нибудь, хотя вряд ли.
                        break;
                    }
                    default:
                    {
                        if( vert_axis_labels_settings === c_oAscChartVertAxisLabelShowSettings.rotated
                            || vert_axis_labels_settings === c_oAscChartVertAxisLabelShowSettings.horizontal)
                        {
                            var _text_body;
                            if(vert_axis.title && vert_axis.title.tx && vert_axis.title.tx.rich)
                            {
                                _text_body = vert_axis.title.tx.rich;
                            }
                            else
                            {
                                if(!vert_axis.title)
                                {
                                    vert_axis.setTitle(new AscFormat.CTitle());
                                }
                                if(!vert_axis.title.txPr)
                                {
                                    vert_axis.title.setTxPr(new AscFormat.CTextBody());
                                }
                                _text_body =  vert_axis.title.txPr;
                            }
                            if(!_text_body.bodyPr)
                            {
                                _text_body.setBodyPr(new AscFormat.CBodyPr());
                            }
                            var _body_pr = _text_body.bodyPr.createDuplicate();
                            if(!_text_body.content)
                            {
                                _text_body.setContent(new AscFormat.CDrawingDocContent(_text_body, chart_space.getDrawingDocument(), 0, 0, 100, 500, false, false, true));
                            }
                            if(vert_axis_labels_settings === c_oAscChartVertAxisLabelShowSettings.rotated)
                            {
                                _body_pr.reset();
                            }
                            else
                            {
                                _body_pr.setVert(AscFormat.nVertTThorz);
                                _body_pr.setRot(0);
                            }
                            _text_body.setBodyPr(_body_pr);
                            if(vert_axis.title.overlay !== false)
                            {
                                vert_axis.title.setOverlay(false);
                            }
                        }
                    }
                }
            }
            vert_axis.setMenuProps(chartSettings.getVertAxisProps());
            if(AscFormat.isRealBool(chartSettings.getShowVerAxis())){
                vert_axis.setDelete(!chartSettings.getShowVerAxis());
            }
        }

        //gridLines
        //Hor GridLInes
        var setAxisGridLines = function(axis, gridLinesSettings)
        {
            if(axis)
            {
                switch(gridLinesSettings)
                {
                    case c_oAscGridLinesSettings.none:
                    {
                        if(axis.majorGridlines)
                            axis.setMajorGridlines(null);
                        if(axis.minorGridlines)
                            axis.setMinorGridlines(null);
                        break;
                    }
                    case c_oAscGridLinesSettings.major:
                    {
                        if(!axis.majorGridlines)
                            axis.setMajorGridlines(new AscFormat.CSpPr());
                        if(axis.minorGridlines)
                            axis.setMinorGridlines(null);
                        break;
                    }
                    case c_oAscGridLinesSettings.minor:
                    {
                        if(!axis.minorGridlines)
                            axis.setMinorGridlines(new AscFormat.CSpPr());
                        if(axis.majorGridlines)
                            axis.setMajorGridlines(null);
                        break;
                    }
                    case c_oAscGridLinesSettings.majorMinor:
                    {
                        if(!axis.minorGridlines)
                            axis.setMinorGridlines(new AscFormat.CSpPr());
                        if(!axis.majorGridlines)
                            axis.setMajorGridlines(new AscFormat.CSpPr());
                        break;
                    }
                }
            }
        };

        setAxisGridLines(plot_area.getVerticalAxis(), chartSettings.getHorGridLines());
        setAxisGridLines(plot_area.getHorizontalAxis(), chartSettings.getVertGridLines());

        for(var i = 0; i < plot_area.charts.length; ++i){
            chart_type = plot_area.charts[i];
            var data_labels_pos_setting = chartSettings.getDataLabelsPos();
            if(AscFormat.isRealNumber(data_labels_pos_setting)){
                if(data_labels_pos_setting === c_oAscChartDataLabelsPos.none){
                    if(chart_type.dLbls)
                        chart_type.setDLbls(null);
                    chart_type.removeDataLabels();
                }
                else{
                    var finish_dlbl_pos =  data_labels_pos_setting;
                    finish_dlbl_pos = this.checkDlblsPosition(chart, chart_type, finish_dlbl_pos);
                    if(chart_type.dLbls && chart_type.dLbls.dLblPos !== finish_dlbl_pos){
                        chart_type.dLbls.setDLblPos(finish_dlbl_pos);
                    }
                    for(var i = 0; i < chart_type.series.length; ++i){
                        if(chart_type.series[i].setDLbls){
                            if(!chart_type.series[i].dLbls){
                                var d_lbls = new AscFormat.CDLbls();
                                d_lbls.setShowVal(true);
                                chart_type.series[i].setDLbls(d_lbls);
                                chart_type.series[i].dLbls.setParent(chart_type);
                            }
                            if(chart_type.series[i].dLbls.dLblPos !== finish_dlbl_pos){
                                chart_type.series[i].dLbls.setDLblPos(finish_dlbl_pos);
                            }
                            for(var j = 0; j < chart_type.series[i].dLbls.dLbl.length; ++j){
                                if(chart_type.series[i].dLbls.dLbl[j].dLblPos !== finish_dlbl_pos){
                                    chart_type.series[i].dLbls.dLbl[j].setDLblPos(finish_dlbl_pos);
                                }
                            }
                        }
                    }
                }
            }
            else{
                if(chart_type.dLbls && AscFormat.isRealNumber(chart_type.dLbls.dLblPos)){
                    chart_type.dLbls.setDLblPos(this.checkDlblsPosition(chart, chart_type, chart_type.dLbls.dLblPos));
                }
                for(var i = 0; i < chart_type.series.length; ++i){
                    if(chart_type.series[i].dLbls){
                        if(AscFormat.isRealNumber(chart_type.series[i].dLbls.dLblPos)){
                            chart_type.series[i].dLbls.setDLblPos(this.checkDlblsPosition(chart, chart_type, chart_type.series[i].dLbls.dLblPos));
                        }
                        for(var j = 0; j < chart_type.series[i].dLbls.dLbl.length; ++j){
                            if(AscFormat.isRealNumber(chart_type.series[i].dLbls.dLbl[j].dLblPos)){
                                chart_type.series[i].dLbls.dLbl[j].setDLblPos(this.checkDlblsPosition(chart, chart_type, chart_type.series[i].dLbls.dLbl[j].dLblPos));
                            }
                        }
                    }
                }
            }
            //подписи данных
            if(typeof chart_type.setDLbls === "function" && AscFormat.isRealNumber(chartSettings.getDataLabelsPos()) && chartSettings.getDataLabelsPos() !== c_oAscChartDataLabelsPos.none)
            {
                if(AscFormat.isRealBool(chartSettings.showCatName) ||
                    AscFormat.isRealBool(chartSettings.showSerName) ||
                    AscFormat.isRealBool(chartSettings.showVal)){
                    var fCheckLbls = function(oLbl){
                        if(oLbl.setDelete && oLbl.bDelete){
                            oLbl.setDelete(false);
                        }
                        if(AscFormat.isRealBool(chartSettings.showCatName)){
                            oLbl.setShowCatName(chartSettings.showCatName);
                        }
                        if(AscFormat.isRealBool(chartSettings.showSerName)){
                            oLbl.setShowSerName(chartSettings.showSerName);
                        }
                        if(AscFormat.isRealBool(chartSettings.showVal)){
                            oLbl.setShowVal(chartSettings.showVal);
                        }
                        if(!AscFormat.isRealBool(oLbl.showLegendKey) || oLbl.showLegendKey === true)                {
                            oLbl.setShowLegendKey(false);
                        }
                        if(!AscFormat.isRealBool(oLbl.showPercent) || oLbl.showPercent === true){
                            oLbl.setShowPercent(false);
                        }
                        if(!AscFormat.isRealBool(oLbl.showBubbleSize) || oLbl.showBubbleSize === true){
                            oLbl.setShowBubbleSize(false);
                        }
                        if(typeof chartSettings.separator === "string" && chartSettings.separator.length > 0)
                            oLbl.setSeparator(chartSettings.separator);
                    };
                    for(var i = 0; i < chart_type.series.length; ++i){
                        var oSeries = chart_type.series[i];
                        if(oSeries.setDLbls){
                            if(!oSeries.dLbls){
                                oSeries.setDLbls(new AscFormat.CDLbls());
                                oSeries.dLbls.setParent(oSeries);
                            }
                        }
                        fCheckLbls(oSeries.dLbls);
                        for(var j = 0; j < oSeries.dLbls.dLbl.length; ++j){
                            fCheckLbls(oSeries.dLbls.dLbl[j]);
                        }
                    }
                }
            }

            if(chart_type.getObjectType() === AscDFH.historyitem_type_LineChart )
            {
                if(!AscFormat.isRealBool(chartSettings.showMarker) || AscFormat.CChartsDrawer.prototype._isSwitchCurrent3DChart(chartSpace))
                {
                    chartSettings.showMarker = false;
                }
                if(!AscFormat.isRealBool(chartSettings.bLine) || AscFormat.CChartsDrawer.prototype._isSwitchCurrent3DChart(chartSpace))
                {
                    chartSettings.bLine = true;
                }

                if(chartSettings.showMarker)
                {
                    if(!chart_type.marker)
                    {
                        chart_type.setMarker(true);
                    }
                    for(var j = 0; j < chart_type.series.length; ++j)
                    {
                        if(chart_type.series[j].marker && chart_type.series[j].marker.symbol === AscFormat.SYMBOL_NONE)
                        {
                            chart_type.series[j].setMarker(null);
                        }
                    }
                }
                else
                {
                    for(var j = 0; j < chart_type.series.length; ++j)
                    {
                        if(!chart_type.series[j].marker)
                        {
                            chart_type.series[j].setMarker(new AscFormat.CMarker());
                        }
                        if(chart_type.series[j].marker.symbol !== AscFormat.SYMBOL_NONE)
                        {
                            chart_type.series[j].marker.setSymbol(AscFormat.SYMBOL_NONE);
                        }
                    }
                }

                if(!chartSettings.bLine)
                {
                    for(var j = 0; j < chart_type.series.length; ++j)
                    {
                        removeDPtsFromSeries(chart_type.series[j]);
                        if(!chart_type.series[j].spPr)
                        {
                            chart_type.series[j].setSpPr(new AscFormat.CSpPr());
                        }

                        if(AscFormat.isRealBool(chart_type.series[j].smooth))
                        {
                            chart_type.series[j].setSmooth(null);
                        }
                        chart_type.series[j].spPr.setLn(AscFormat.CreateNoFillLine());
                    }
                }
                else
                {
                    for(var j = 0; j < chart_type.series.length; ++j)
                    {
                        removeDPtsFromSeries(chart_type.series[j]);
                        if(chart_type.series[j].smooth !== (chartSettings.smooth === true))
                        {
                            chart_type.series[j].setSmooth(chartSettings.smooth === true);
                        }
                        if(chart_type.series[j].spPr && chart_type.series[j].spPr.ln)
                        {
                            chart_type.series[j].spPr.setLn(null);
                        }
                    }
                }
                if(chart_type.smooth !== (chartSettings.smooth === true))
                {
                    chart_type.setSmooth(chartSettings.smooth === true);
                }
                for(var j = 0; j < chart_type.series.length; ++j)
                {
                    if(chart_type.series[j].smooth !== (chartSettings.smooth === true))
                    {
                        chart_type.series[j].setSmooth(chartSettings.smooth === true);
                    }
                }
            }
            if(chart_type.getObjectType() === AscDFH.historyitem_type_ScatterChart)
            {
                if(!AscFormat.isRealBool(chartSettings.showMarker))
                {
                    chartSettings.showMarker = true;
                }
                if(!AscFormat.isRealBool(chartSettings.bLine))
                {
                    chartSettings.bLine = false;
                }

                for(var i = 0; i < chart_type.series.length; ++i)
                {
                    if(chart_type.series[i].marker)
                    {
                        chart_type.series[i].setMarker(null);
                    }
                    if(AscFormat.isRealBool(chart_type.series[i].smooth))
                    {
                        chart_type.series[i].setSmooth(null);
                    }
                }
                var new_scatter_style;
                if(chartSettings.bLine)
                {
                    for(var j = 0; j < chart_type.series.length; ++j)
                    {
                        removeDPtsFromSeries(chart_type.series[j]);
                        if(chart_type.series[j].spPr && chart_type.series[j].spPr.ln)
                        {
                            chart_type.series[j].spPr.setLn(null);
                        }
                    }
                    if(chartSettings.smooth)
                    {
                        if(chartSettings.showMarker)
                        {
                            new_scatter_style = SCATTER_STYLE_SMOOTH_MARKER;
                            for(var j = 0; j < chart_type.series.length; ++j)
                            {
                                if(chart_type.series[j].marker)
                                {
                                    chart_type.series[j].setMarker(null);
                                }
                                chart_type.series[j].setSmooth(true);
                            }
                        }
                        else
                        {
                            new_scatter_style = SCATTER_STYLE_SMOOTH;
                            for(var j = 0; j < chart_type.series.length; ++j)
                            {
                                if(!chart_type.series[j].marker)
                                {
                                    chart_type.series[j].setMarker(new AscFormat.CMarker());
                                }
                                chart_type.series[j].marker.setSymbol(AscFormat.SYMBOL_NONE);
                                chart_type.series[j].setSmooth(true);
                            }
                        }
                    }
                    else
                    {
                        if(chartSettings.showMarker)
                        {
                            new_scatter_style = SCATTER_STYLE_LINE_MARKER;
                            for(var j = 0; j < chart_type.series.length; ++j)
                            {
                                if(chart_type.series[j].marker)
                                {
                                    chart_type.series[j].setMarker(null);
                                }
                                chart_type.series[j].setSmooth(false);
                            }
                        }
                        else
                        {
                            new_scatter_style = SCATTER_STYLE_LINE;
                            for(var j = 0; j < chart_type.series.length; ++j)
                            {
                                if(!chart_type.series[j].marker)
                                {
                                    chart_type.series[j].setMarker(new AscFormat.CMarker());
                                }
                                chart_type.series[j].marker.setSymbol(AscFormat.SYMBOL_NONE);
                                chart_type.series[j].setSmooth(false);
                            }
                        }
                    }
                }
                else
                {
                    for(var j = 0; j < chart_type.series.length; ++j)
                    {
                        removeDPtsFromSeries(chart_type.series[j]);
                        if(!chart_type.series[j].spPr)
                        {
                            chart_type.series[j].setSpPr(new AscFormat.CSpPr());
                        }
                        chart_type.series[j].spPr.setLn(AscFormat.CreateNoFillLine());
                    }
                    if(chartSettings.showMarker)
                    {
                        new_scatter_style = SCATTER_STYLE_MARKER;
                        for(var j = 0; j < chart_type.series.length; ++j)
                        {
                            if(chart_type.series[j].marker)
                            {
                                chart_type.series[j].setMarker(null);
                            }
                            chart_type.series[j].setSmooth(false);
                        }
                    }
                    else
                    {
                        new_scatter_style = SCATTER_STYLE_MARKER;
                        for(var j = 0; j < chart_type.series.length; ++j)
                        {
                            if(!chart_type.series[j].marker)
                            {
                                chart_type.series[j].setMarker(new AscFormat.CMarker());
                            }
                            chart_type.series[j].marker.setSymbol(AscFormat.SYMBOL_NONE);
                        }
                    }
                }
                chart_type.setScatterStyle(new_scatter_style);
            }
        }

    },

    checkDlblsPosition: function(chart, chart_type, position){
        var finish_dlbl_pos =  position;

        switch (chart_type.getObjectType())
        {
            case AscDFH.historyitem_type_BarChart:
            {
                if(BAR_GROUPING_CLUSTERED === chart_type.grouping)
                {
                    if(!(finish_dlbl_pos === c_oAscChartDataLabelsPos.ctr
                        || finish_dlbl_pos === c_oAscChartDataLabelsPos.inEnd
                        || finish_dlbl_pos === c_oAscChartDataLabelsPos.inBase
                        || finish_dlbl_pos === c_oAscChartDataLabelsPos.outEnd))
                    {
                        finish_dlbl_pos = c_oAscChartDataLabelsPos.ctr;
                    }
                }
                else
                {
                    if(!(finish_dlbl_pos === c_oAscChartDataLabelsPos.ctr
                        || finish_dlbl_pos === c_oAscChartDataLabelsPos.inEnd
                        || finish_dlbl_pos === c_oAscChartDataLabelsPos.inBase))
                    {
                        finish_dlbl_pos = c_oAscChartDataLabelsPos.ctr;
                    }
                }
                if(chart.view3D)
                {
                    finish_dlbl_pos = null;
                }
                break;
            }
            case AscDFH.historyitem_type_LineChart:
            case AscDFH.historyitem_type_ScatterChart:
            {
                if(!(finish_dlbl_pos === c_oAscChartDataLabelsPos.ctr
                    || finish_dlbl_pos === c_oAscChartDataLabelsPos.l
                    || finish_dlbl_pos === c_oAscChartDataLabelsPos.t
                    || finish_dlbl_pos === c_oAscChartDataLabelsPos.r
                    || finish_dlbl_pos === c_oAscChartDataLabelsPos.b))
                {
                    finish_dlbl_pos = c_oAscChartDataLabelsPos.ctr;
                }
                if(chart.view3D)
                {
                    finish_dlbl_pos = null;
                }
                break;
            }
            case AscDFH.historyitem_type_PieChart:
            {
                if(!(finish_dlbl_pos === c_oAscChartDataLabelsPos.ctr
                    || finish_dlbl_pos === c_oAscChartDataLabelsPos.inEnd
                    || finish_dlbl_pos === c_oAscChartDataLabelsPos.outEnd
                    || finish_dlbl_pos === c_oAscChartDataLabelsPos.bestFit))
                {
                    finish_dlbl_pos = c_oAscChartDataLabelsPos.ctr;
                }
                break;
            }
            case AscDFH.historyitem_type_AreaChart:
            case AscDFH.historyitem_type_DoughnutChart:
            case AscDFH.historyitem_type_StockChart:
            {
                finish_dlbl_pos = null;
                break;
            }
        }
        return finish_dlbl_pos;
    },

    getChartProps: function()
    {
        var objects_by_types = this.getSelectedObjectsByTypes();
        var ret = null;
        if(objects_by_types.charts.length === 1)
        {
            ret = this.getPropsFromChart(objects_by_types.charts[0]);
        }
        return ret;
    },

    getPropsFromChart: function(chart_space)
    {
        var chart = chart_space.chart, plot_area = chart_space.chart.plotArea;
        var ret = new Asc.asc_ChartSettings();
        var range_obj = chart_space.getRangeObjectStr();
        if(range_obj)
        {
            if(typeof range_obj.range === "string" && range_obj.range.length > 0)
            {
                ret.putRange(range_obj.range);
                ret.putInColumns(!range_obj.bVert);
            }
        }
        //ret.putStyle(AscFormat.isRealNumber(chart_space.style) ? chart_space.style : null);
        ret.putTitle(isRealObject(chart.title) ? (chart.title.overlay ? c_oAscChartTitleShowSettings.overlay : c_oAscChartTitleShowSettings.noOverlay) : c_oAscChartTitleShowSettings.none);
        var hor_axis = plot_area.getHorizontalAxis();
        var vert_axis = plot_area.getVerticalAxis();

        var calc_grid_lines = function(axis)
        {
            if(!axis || (!axis.majorGridlines && !axis.minorGridlines))
                return c_oAscGridLinesSettings.none;
            if(axis.majorGridlines && !axis.minorGridlines)
                return c_oAscGridLinesSettings.major;
            if(axis.minorGridlines && !axis.majorGridlines)
                return c_oAscGridLinesSettings.minor;
            return c_oAscGridLinesSettings.majorMinor;
        };

        var chart_type = plot_area.charts[0];
        var chart_type_object_type = chart_type.getObjectType();

        if(hor_axis)
        {
            ret.putShowHorAxis(!hor_axis.bDelete);
            ret.putHorAxisProps(hor_axis.getMenuProps());
        }
        else
        {
            if(vert_axis)
            {
                if(vert_axis.getObjectType() === AscDFH.historyitem_type_ValAx)
                {
                    ret.putShowHorAxis(false);
                    var _cat_ax_pr = new AscCommon.asc_CatAxisSettings();
                    _cat_ax_pr.setDefault();
                    ret.putHorAxisProps(_cat_ax_pr);
                }
                else
                {
                    ret.putShowHorAxis(false);
                    var _val_ax_pr = new AscCommon.asc_ValAxisSettings();
                    _val_ax_pr.setDefault();
                    ret.putHorAxisProps(_val_ax_pr);
                }
            }
        }
        ret.putHorGridLines(calc_grid_lines(vert_axis));

        if(vert_axis)
        {
            ret.putShowVerAxis(!vert_axis.bDelete);
            ret.putVertAxisProps(vert_axis.getMenuProps());
            if(chart_type.getObjectType() === AscDFH.historyitem_type_AreaChart && !AscFormat.isRealNumber(vert_axis.crossBetween))
            {
                if(ret.horAxisProps)
                {
                    ret.horAxisProps.putLabelsPosition(Asc.c_oAscLabelsPosition.byDivisions);
                }
            }
        }
        ret.putVertGridLines(calc_grid_lines(hor_axis));

        ret.putHorAxisLabel(hor_axis && hor_axis.title ? c_oAscChartHorAxisLabelShowSettings.noOverlay : c_oAscChartTitleShowSettings.none);
        var _label;
        if(vert_axis && vert_axis.title)
        {
            var tx_body;
            if(vert_axis.title.tx && vert_axis.title.tx.rich)
            {
                tx_body  =  vert_axis.title.tx.rich;
            }
            else if(vert_axis.title.txPr)
            {
                tx_body  =  vert_axis.title.txPr;
            }
            if(tx_body)
            {
                var oBodyPr = vert_axis.title.getBodyPr();
                if(oBodyPr && oBodyPr.vert === AscFormat.nVertTThorz)
                {
                    _label = c_oAscChartVertAxisLabelShowSettings.horizontal;
                }
                else
                {
                    _label = c_oAscChartVertAxisLabelShowSettings.rotated;
                }
            }
            else
            {
                _label = c_oAscChartVertAxisLabelShowSettings.none;
            }
        }
        else
        {
            _label = c_oAscChartVertAxisLabelShowSettings.none;
        }
        ret.putVertAxisLabel(_label);

        var data_labels = plot_area.charts[0].dLbls;
        var nDefaultDatalabelsPos = chart_type && chart_type.getDefaultDataLabelsPosition ? chart_type.getDefaultDataLabelsPosition() :  c_oAscChartDataLabelsPos.none;

        if(data_labels)
        {
            if(chart_type.series[0] && chart_type.series[0].dLbls){
                this.collectPropsFromDLbls(nDefaultDatalabelsPos, chart_type.series[0].dLbls, ret);
            }
            else{
                this.collectPropsFromDLbls(nDefaultDatalabelsPos, data_labels, ret);
            }
        }
        else
        {
            if(chart_type.series[0] && chart_type.series[0].dLbls){
                this.collectPropsFromDLbls(nDefaultDatalabelsPos, chart_type.series[0].dLbls, ret);
            }
            else{
                ret.putShowSerName(false);
                ret.putShowCatName(false);
                ret.putShowVal(false);
                ret.putSeparator("");
                ret.putDataLabelsPos(c_oAscChartDataLabelsPos.none);
            }
        }

        if(chart.legend)
        {
            ret.putLegendPos(AscFormat.isRealNumber(chart.legend.legendPos) ? chart.legend.legendPos : c_oAscChartLegendShowSettings.bottom);
        }
        else
        {
            ret.putLegendPos(c_oAscChartLegendShowSettings.none);
        }


        var calc_chart_type;
        if(chart_type_object_type === AscDFH.historyitem_type_PieChart)
        {
            if(!AscFormat.CChartsDrawer.prototype._isSwitchCurrent3DChart(chart_space))
            {
                calc_chart_type = c_oAscChartTypeSettings.pie;
            }
            else
            {
                calc_chart_type = c_oAscChartTypeSettings.pie3d;
            }
        }
        else if(chart_type_object_type === AscDFH.historyitem_type_DoughnutChart)
            calc_chart_type = c_oAscChartTypeSettings.doughnut;
        else if(chart_type_object_type === AscDFH.historyitem_type_StockChart)
            calc_chart_type = c_oAscChartTypeSettings.stock;
        else if(chart_type_object_type === AscDFH.historyitem_type_BarChart)
        {
            var b_hbar = chart_type.barDir === BAR_DIR_BAR;
            var bView3d = AscFormat.CChartsDrawer.prototype._isSwitchCurrent3DChart(chart_space);
            if(b_hbar)
            {
                switch(chart_type.grouping)
                {
                    case BAR_GROUPING_CLUSTERED:
                    {
                        calc_chart_type = bView3d ? c_oAscChartTypeSettings.hBarNormal3d : c_oAscChartTypeSettings.hBarNormal;
                        break;
                    }
                    case BAR_GROUPING_STACKED:
                    {
                        calc_chart_type = bView3d ? c_oAscChartTypeSettings.hBarStacked3d : c_oAscChartTypeSettings.hBarStacked;
                        break;
                    }
                    case BAR_GROUPING_PERCENT_STACKED:
                    {
                        calc_chart_type = bView3d ? c_oAscChartTypeSettings.hBarStackedPer3d : c_oAscChartTypeSettings.hBarStackedPer;
                        break;
                    }
                    default:
                    {
                        calc_chart_type = bView3d ? c_oAscChartTypeSettings.hBarNormal3d : c_oAscChartTypeSettings.hBarNormal;
                        break;
                    }
                }
            }
            else
            {
                switch(chart_type.grouping)
                {
                    case BAR_GROUPING_CLUSTERED:
                    {
                        calc_chart_type = bView3d ? c_oAscChartTypeSettings.barNormal3d : c_oAscChartTypeSettings.barNormal;
                        break;
                    }
                    case BAR_GROUPING_STACKED:
                    {
                        calc_chart_type = bView3d ? c_oAscChartTypeSettings.barStacked3d : c_oAscChartTypeSettings.barStacked;
                        break;
                    }
                    case BAR_GROUPING_PERCENT_STACKED:
                    {
                        calc_chart_type = bView3d ? c_oAscChartTypeSettings.barStackedPer3d : c_oAscChartTypeSettings.barStackedPer;
                        break;
                    }
                    default:
                    {
                        if(BAR_GROUPING_STANDARD && bView3d)
                        {
                            calc_chart_type = c_oAscChartTypeSettings.barNormal3dPerspective;
                        }
                        else
                        {
                            calc_chart_type = c_oAscChartTypeSettings.barNormal;
                        }
                        break;
                    }
                }
            }
        }
        else if(chart_type_object_type === AscDFH.historyitem_type_LineChart)
        {
            switch(chart_type.grouping)
            {
                case GROUPING_PERCENT_STACKED :
                {
                    calc_chart_type = c_oAscChartTypeSettings.lineStackedPer;
                    break;
                }
                case GROUPING_STACKED         :
                {
                    calc_chart_type = c_oAscChartTypeSettings.lineStacked;
                    break;
                }
                default        :
                {
                    if(!AscFormat.CChartsDrawer.prototype._isSwitchCurrent3DChart(chart_space))
                    {
                        calc_chart_type = c_oAscChartTypeSettings.lineNormal;
                    }
                    else
                    {
                        calc_chart_type = c_oAscChartTypeSettings.line3d;
                    }
                    break;
                }
            }
            var bShowMarker = false;
            if(chart_type.marker !== false)
            {
                for(var j = 0; j < chart_type.series.length; ++j)
                {
                    if(!chart_type.series[j].marker)
                    {
                        bShowMarker = true;
                        break;
                    }
                    if(chart_type.series[j].marker.symbol !== AscFormat.SYMBOL_NONE)
                    {
                        bShowMarker = true;
                        break;
                    }
                }
            }
            ret.putShowMarker(bShowMarker);
            var b_no_line = true;
            for(var i = 0; i < chart_type.series.length; ++i)
            {
                if(!(chart_type.series[i].spPr && chart_type.series[i].spPr.ln &&
                    chart_type.series[i].spPr.ln.Fill &&chart_type.series[i].spPr.ln.Fill.fill && chart_type.series[i].spPr.ln.Fill.fill.type === c_oAscFill.FILL_TYPE_NOFILL))
                {
                    b_no_line = false;
                    break;
                }
            }
            var b_smooth = true;
            for(var i = 0; i < chart_type.series.length; ++i)
            {
                if(chart_type.series[i].smooth === false)
                {
                    b_smooth = false;
                    break;
                }
            }
            if(!b_no_line)
            {
                ret.putLine(true);
                ret.putSmooth(b_smooth);
            }
            else
            {
                ret.putLine(false);
            }
        }
        else if(chart_type_object_type === AscDFH.historyitem_type_AreaChart)
        {
            switch(chart_type.grouping)
            {
                case GROUPING_PERCENT_STACKED :
                {
                    calc_chart_type = c_oAscChartTypeSettings.areaStackedPer;
                    break;
                }
                case GROUPING_STACKED         :
                {
                    calc_chart_type = c_oAscChartTypeSettings.areaStacked;
                    break;
                }
                default        :
                {
                    calc_chart_type = c_oAscChartTypeSettings.areaNormal;
                    break;
                }
            }
        }
        else if(chart_type_object_type === AscDFH.historyitem_type_ScatterChart)
        {
            calc_chart_type = c_oAscChartTypeSettings.scatter;
            switch(chart_type.scatterStyle)
            {
                case SCATTER_STYLE_LINE:
                {
                    ret.bLine = true;
                    ret.smooth = false;
                    ret.showMarker = false;
                    break;
                }
                case SCATTER_STYLE_LINE_MARKER:
                {
                    ret.bLine = true;
                    ret.smooth = false;
                    ret.showMarker = true;
                    break;
                }
                case SCATTER_STYLE_MARKER:
                {
                    ret.bLine = false;
                    ret.showMarker = false;
                    for(var j = 0; j < chart_type.series.length; ++j)
                    {
                        if(!(chart_type.series[j].marker && chart_type.series[j].marker.symbol === AscFormat.SYMBOL_NONE))
                        {
                            ret.showMarker = true;
                            break;
                        }
                    }
                    break;
                }
                case SCATTER_STYLE_NONE:
                {
                    ret.bLine = false;
                    ret.showMarker = false;
                    break;
                }
                case SCATTER_STYLE_SMOOTH:
                {
                    ret.bLine = true;
                    ret.smooth = true;
                    ret.showMarker = false;
                    break;
                }
                case SCATTER_STYLE_SMOOTH_MARKER:
                {
                    ret.bLine = true;
                    ret.smooth = true;
                    ret.showMarker = true;
                    break;
                }
            }
            if(ret.bLine)
            {
                for(var i = 0; i < chart_type.series.length; ++i)
                {
                    if(!(chart_type.series[i].spPr && chart_type.series[i].spPr.ln &&
                        chart_type.series[i].spPr.ln.Fill &&chart_type.series[i].spPr.ln.Fill.fill && chart_type.series[i].spPr.ln.Fill.fill.type === c_oAscFill.FILL_TYPE_NOFILL))
                    {
                        break;
                    }
                }
                if(i === chart_type.series.length)
                {
                    ret.bLine = false;
                }
                var b_smooth = ret.smooth;
                if(b_smooth)
                {
                    for(var i = 0; i < chart_type.series.length; ++i)
                    {
                        if(!chart_type.series[i].smooth)
                        {
                            b_smooth = false;
                            break;
                        }
                    }
                }
                ret.putSmooth(b_smooth);
            }
        }
        else if(chart_type_object_type === AscDFH.historyitem_type_SurfaceChart){
            var oView3D = chart_space.chart.view3D;
            if(chart_type.isWireframe()){
                if(oView3D && oView3D.rotX === 90 && oView3D.rotY === 0 && oView3D.rAngAx === false && oView3D.perspective === 0){
                    calc_chart_type = c_oAscChartTypeSettings.contourWireframe;
                }
                else{
                    calc_chart_type = c_oAscChartTypeSettings.surfaceWireframe;
                }
            }
            else{
                if(oView3D && oView3D.rotX === 90 && oView3D.rotY === 0 && oView3D.rAngAx === false && oView3D.perspective === 0){
                    calc_chart_type = c_oAscChartTypeSettings.contourNormal;
                }
                else{
                    calc_chart_type = c_oAscChartTypeSettings.surfaceNormal;
                }
            }
        }
        else
        {
            calc_chart_type = c_oAscChartTypeSettings.unknown;
        }
        ret.type = calc_chart_type;
        return ret;
    },

    collectPropsFromDLbls: function(nDefaultDatalabelsPos, data_labels, ret){
        ret.putShowSerName(data_labels.showSerName === true);
        ret.putShowCatName(data_labels.showCatName === true);
        ret.putShowVal(data_labels.showVal === true);
        ret.putSeparator(data_labels.separator);
        if(data_labels.showSerName || data_labels.showCatName || data_labels.showVal || data_labels.showPercent){
            ret.putDataLabelsPos(AscFormat.isRealNumber(data_labels.dLblPos) ? data_labels.dLblPos :  nDefaultDatalabelsPos);
        }
        else{
            ret.putDataLabelsPos(c_oAscChartDataLabelsPos.none);
        }
    },
	_getChartSpace: function (chartSeries, options, bUseCache) {
		switch (options.type) {
			case c_oAscChartTypeSettings.lineNormal:
			case c_oAscChartTypeSettings.lineNormalMarker:
				return AscFormat.CreateLineChart(chartSeries, GROUPING_STANDARD, bUseCache, options);
			case c_oAscChartTypeSettings.lineStacked:
			case c_oAscChartTypeSettings.lineStackedMarker:
				return AscFormat.CreateLineChart(chartSeries, GROUPING_STACKED, bUseCache, options);
			case c_oAscChartTypeSettings.lineStackedPer:
			case c_oAscChartTypeSettings.lineStackedPerMarker:
				return AscFormat.CreateLineChart(chartSeries, GROUPING_PERCENT_STACKED, bUseCache, options);
            case c_oAscChartTypeSettings.line3d:
                return AscFormat.CreateLineChart(chartSeries, GROUPING_STANDARD, bUseCache, options, true);
			case c_oAscChartTypeSettings.barNormal:
				return AscFormat.CreateBarChart(chartSeries, BAR_GROUPING_CLUSTERED, bUseCache, options);
			case c_oAscChartTypeSettings.barStacked:
				return AscFormat.CreateBarChart(chartSeries, BAR_GROUPING_STACKED, bUseCache, options);
			case c_oAscChartTypeSettings.barStackedPer:
				return AscFormat.CreateBarChart(chartSeries, BAR_GROUPING_PERCENT_STACKED, bUseCache, options);
            case c_oAscChartTypeSettings.barNormal3d:
                return AscFormat.CreateBarChart(chartSeries, BAR_GROUPING_CLUSTERED, bUseCache, options, true);
            case c_oAscChartTypeSettings.barStacked3d:
                return AscFormat.CreateBarChart(chartSeries, BAR_GROUPING_STACKED, bUseCache, options, true);
            case c_oAscChartTypeSettings.barStackedPer3d:
                return AscFormat.CreateBarChart(chartSeries, BAR_GROUPING_PERCENT_STACKED, bUseCache, options, true);
            case c_oAscChartTypeSettings.barNormal3dPerspective:
                return AscFormat.CreateBarChart(chartSeries, BAR_GROUPING_STANDARD, bUseCache, options, true, true);
			case c_oAscChartTypeSettings.hBarNormal:
				return AscFormat.CreateHBarChart(chartSeries, BAR_GROUPING_CLUSTERED, bUseCache, options);
			case c_oAscChartTypeSettings.hBarStacked:
				return AscFormat.CreateHBarChart(chartSeries, BAR_GROUPING_STACKED, bUseCache, options);
			case c_oAscChartTypeSettings.hBarStackedPer:
				return AscFormat.CreateHBarChart(chartSeries, BAR_GROUPING_PERCENT_STACKED, bUseCache, options);
            case c_oAscChartTypeSettings.hBarNormal3d:
                return AscFormat.CreateHBarChart(chartSeries, BAR_GROUPING_CLUSTERED, bUseCache, options, true);
            case c_oAscChartTypeSettings.hBarStacked3d:
                return AscFormat.CreateHBarChart(chartSeries, BAR_GROUPING_STACKED, bUseCache, options, true);
            case c_oAscChartTypeSettings.hBarStackedPer3d:
                return AscFormat.CreateHBarChart(chartSeries, BAR_GROUPING_PERCENT_STACKED, bUseCache, options, true);
			case c_oAscChartTypeSettings.areaNormal:
				return AscFormat.CreateAreaChart(chartSeries, GROUPING_STANDARD, bUseCache, options);
			case c_oAscChartTypeSettings.areaStacked:
				return AscFormat.CreateAreaChart(chartSeries, GROUPING_STACKED, bUseCache, options);
			case c_oAscChartTypeSettings.areaStackedPer:
				return AscFormat.CreateAreaChart(chartSeries, GROUPING_PERCENT_STACKED, bUseCache, options);
			case c_oAscChartTypeSettings.stock:
				return AscFormat.CreateStockChart(chartSeries, bUseCache, options);
			case c_oAscChartTypeSettings.doughnut:
				return AscFormat.CreatePieChart(chartSeries, true, bUseCache, options);
			case c_oAscChartTypeSettings.pie:
				return AscFormat.CreatePieChart(chartSeries, false, bUseCache, options);
            case c_oAscChartTypeSettings.pie3d:
                return AscFormat.CreatePieChart(chartSeries, false, bUseCache, options, true);
			case c_oAscChartTypeSettings.scatter:
			case c_oAscChartTypeSettings.scatterLine:
			case c_oAscChartTypeSettings.scatterLineMarker:
			case c_oAscChartTypeSettings.scatterMarker:
			case c_oAscChartTypeSettings.scatterNone:
			case c_oAscChartTypeSettings.scatterSmooth:
			case c_oAscChartTypeSettings.scatterSmoothMarker:
				return AscFormat.CreateScatterChart(chartSeries, bUseCache, options);
            case c_oAscChartTypeSettings.surfaceNormal:
                return AscFormat.CreateSurfaceChart(chartSeries, bUseCache, options, false, false);
            case c_oAscChartTypeSettings.surfaceWireframe:
                return AscFormat.CreateSurfaceChart(chartSeries, bUseCache, options, false, true);
            case c_oAscChartTypeSettings.contourNormal:
                return AscFormat.CreateSurfaceChart(chartSeries, bUseCache, options, true, false);
            case c_oAscChartTypeSettings.contourWireframe:
                return AscFormat.CreateSurfaceChart(chartSeries, bUseCache, options, true, true);
			// radar return CreateRadarChart(chartSeries);
		}

		return null;
	},

	getChartSpace: function(worksheet, options, bUseCache)
	{
		var chartSeries = AscFormat.getChartSeries(worksheet, options);
		return this._getChartSpace(chartSeries, options, bUseCache);
	},

    getChartSpace2: function(chart, options)
    {
        var ret = null;
        if(isRealObject(chart) && typeof chart["binary"] === "string" && chart["binary"].length > 0)
        {
            var asc_chart_binary = new Asc.asc_CChartBinary();
            asc_chart_binary.asc_setBinary(chart["binary"]);
            ret = asc_chart_binary.getChartSpace(editor.WordControl.m_oLogicDocument);
            if(ret.spPr && ret.spPr.xfrm)
            {
                ret.spPr.xfrm.setOffX(0);
                ret.spPr.xfrm.setOffY(0);
            }
            ret.setBDeleted(false);
        }
        else if(isRealObject(chart))
        {
            ret = DrawingObjectsController.prototype._getChartSpace.call(this, chart, options, true);
            ret.setBDeleted(false);
            ret.setStyle(2);
            ret.setSpPr(new AscFormat.CSpPr());
            ret.spPr.setParent(ret);
            ret.spPr.setXfrm(new AscFormat.CXfrm());
            ret.spPr.xfrm.setParent(ret.spPr);
            ret.spPr.xfrm.setOffX(0);
            ret.spPr.xfrm.setOffY(0);
            ret.spPr.xfrm.setExtX(152);
            ret.spPr.xfrm.setExtY(89);
        }
        return ret;
    },

	getSeriesDefault: function (type) {
		// Обновлены тестовые данные для новой диаграммы


        var series = [], seria, Cat;
        var  createItem = function(value) {
            return { numFormatStr: "General", isDateTimeFormat: false, val: value, isHidden: false };
        };
        var  createItem2 = function(value, formatCode) {
            return { numFormatStr: formatCode, isDateTimeFormat: false, val: value, isHidden: false };
        };
        if(type !== c_oAscChartTypeSettings.stock)
        {

            var bIsScatter = (c_oAscChartTypeSettings.scatter <= type && type <= c_oAscChartTypeSettings.scatterSmoothMarker);

            Cat = { Formula: "Sheet1!$A$2:$A$7", NumCache: [createItem("USA"), createItem("CHN"), createItem("RUS"), createItem("GBR"), createItem("GER"), createItem("JPN")] };
            seria = new AscFormat.asc_CChartSeria();
            seria.Val.Formula = "Sheet1!$B$2:$B$7";
            seria.Val.NumCache = [ createItem(46), createItem(38), createItem(24), createItem(29), createItem(11), createItem(7) ];
            seria.TxCache.Formula = "Sheet1!$B$1";
            seria.TxCache.Tx = "Gold";
            if (!bIsScatter)
                seria.Cat = Cat;
            else
                seria.xVal = Cat;
            series.push(seria);

            seria = new AscFormat.asc_CChartSeria();
            seria.Val.Formula = "Sheet1!$C$2:$C$7";
            seria.Val.NumCache = [ createItem(29), createItem(27), createItem(26), createItem(17), createItem(19), createItem(14) ];
            seria.TxCache.Formula = "Sheet1!$C$1";
            seria.TxCache.Tx = "Silver";
            if (!bIsScatter)
                seria.Cat = Cat;
            else
                seria.xVal = Cat;
            series.push(seria);

            seria = new AscFormat.asc_CChartSeria();
            seria.Val.Formula = "Sheet1!$D$2:$D$7";
            seria.Val.NumCache = [ createItem(29), createItem(23), createItem(32), createItem(19), createItem(14), createItem(17) ];
            seria.TxCache.Formula = "Sheet1!$D$1";
            seria.TxCache.Tx = "Bronze";
            if (!bIsScatter)
                seria.Cat = Cat;
            else
                seria.xVal = Cat;
            series.push(seria);

            return series;
        }
        else
        {
            Cat = { Formula: "Sheet1!$A$2:$A$6", NumCache: [createItem2(38719, "d\-mmm\-yy"), createItem2(38720, "d\-mmm\-yy"), createItem2(38721, "d\-mmm\-yy"), createItem2(38722, "d\-mmm\-yy"), createItem2(38723, "d\-mmm\-yy")], formatCode: "d\-mmm\-yy" };
            seria = new AscFormat.asc_CChartSeria();
            seria.Val.Formula = "Sheet1!$B$2:$B$6";
            seria.Val.NumCache = [ createItem(40), createItem(21), createItem(37), createItem(49), createItem(32)];
            seria.TxCache.Formula = "Sheet1!$B$1";
            seria.TxCache.Tx = "Open";
            seria.Cat = Cat;
            series.push(seria);

            seria = new AscFormat.asc_CChartSeria();
            seria.Val.Formula = "Sheet1!$C$2:$C$6";
            seria.Val.NumCache = [ createItem(57), createItem(54), createItem(52), createItem(59), createItem(34)];
            seria.TxCache.Formula = "Sheet1!$C$1";
            seria.TxCache.Tx = "High";
            seria.Cat = Cat;
            series.push(seria);

            seria = new AscFormat.asc_CChartSeria();
            seria.Val.Formula = "Sheet1!$D$2:$D$6";
            seria.Val.NumCache = [ createItem(10), createItem(14), createItem(14), createItem(12), createItem(6)];
            seria.TxCache.Formula = "Sheet1!$D$1";
            seria.TxCache.Tx = "Low";
            seria.Cat = Cat;
            series.push(seria);

            seria = new AscFormat.asc_CChartSeria();
            seria.Val.Formula = "Sheet1!$E$2:$E$6";
            seria.Val.NumCache = [ createItem(24), createItem(35), createItem(48), createItem(35), createItem(15)];
            seria.TxCache.Formula = "Sheet1!$E$1";
            seria.TxCache.Tx = "Close";
            seria.Cat = Cat;
            series.push(seria);

            return series;
        }

	},

    changeCurrentState: function(newState)
    {
        this.curState = newState;
    },

    updateSelectionState: function(bNoCheck)
    {
        var text_object, drawingDocument = this.drawingObjects.getDrawingDocument();
        if(this.selection.textSelection)
        {
            text_object = this.selection.textSelection;
        }
        else if(this.selection.groupSelection)
        {
            if(this.selection.groupSelection.selection.textSelection)
            {
                text_object = this.selection.groupSelection.selection.textSelection;
            }
            else if(this.selection.groupSelection.selection.chartSelection && this.selection.groupSelection.selection.chartSelection.selection.textSelection)
            {
                text_object = this.selection.groupSelection.selection.chartSelection.selection.textSelection;
            }
        }
        else if(this.selection.chartSelection && this.selection.chartSelection.selection.textSelection)
        {
            text_object = this.selection.chartSelection.selection.textSelection;
        }
        if(isRealObject(text_object))
        {
            text_object.updateSelectionState(drawingDocument);
        }
        else if(bNoCheck !== true)
        {
            drawingDocument.UpdateTargetTransform(null);
            drawingDocument.TargetEnd();
            drawingDocument.SelectEnabled(false);
            drawingDocument.SelectShow();
        }
    },

    remove: function(dir, bOnlyText, bRemoveOnlySelection)
    {
        if(Asc["editor"] && Asc["editor"].isChartEditor && (!this.selection.chartSelection))
        {
            return;
        }
        this.checkSelectedObjectsAndCallback(this.removeCallback, [dir, bOnlyText, bRemoveOnlySelection], false, AscDFH.historydescription_Spreadsheet_Remove);
    },

    removeCallback: function(dir, bOnlyText, bRemoveOnlySelection, bNoCheck)
    {
        var target_text_object = getTargetTextObject(this);
        if(target_text_object)
        {
            if(target_text_object.getObjectType() === AscDFH.historyitem_type_GraphicFrame)
            {
                target_text_object.graphicObject.Remove(dir, bOnlyText, bRemoveOnlySelection);
            }
            else
            {
                var content = this.getTargetDocContent(true);
                if(content)
                {
                    content.Remove(dir, true, bRemoveOnlySelection)
                }

                bNoCheck !== true && target_text_object.checkExtentsByDocContent && target_text_object.checkExtentsByDocContent();
            }
        }
        else if(this.selectedObjects.length > 0)
        {
            var worksheet = this.drawingObjects.getWorksheet();
            if(worksheet)
            {
                worksheet.endEditChart();
            }
            var aAllShapes = [];
            if(this.selection.groupSelection)
            {
                if(this.selection.groupSelection.selection.chartSelection)
                {
                    this.selection.groupSelection.selection.chartSelection.remove();
                }
                else
                {
                    this.resetConnectors(this.selection.groupSelection.selectedObjects);
                    var group_map = {}, group_arr = [], i, cur_group, sp, xc, yc, hc, vc, rel_xc, rel_yc, j;
                    for(i = 0; i < this.selection.groupSelection.selectedObjects.length; ++i)
                    {
                        this.selection.groupSelection.selectedObjects[i].group.removeFromSpTree(this.selection.groupSelection.selectedObjects[i].Get_Id());
                        group_map[this.selection.groupSelection.selectedObjects[i].group.Get_Id()+""] = this.selection.groupSelection.selectedObjects[i].group;
                        if(this.selection.groupSelection.selectedObjects[i].setBDeleted){
                            this.selection.groupSelection.selectedObjects[i].setBDeleted(true);
                        }
                    }
                    group_map[this.selection.groupSelection.Get_Id()+""] = this.selection.groupSelection;
                    for(var key in group_map)
                    {
                        if(group_map.hasOwnProperty(key))
                            group_arr.push(group_map[key]);
                    }
                    group_arr.sort(CompareGroups);
                    for(i = 0; i < group_arr.length; ++i)
                    {
                        cur_group = group_arr[i];
                        if(isRealObject(cur_group.group))
                        {
                            if(cur_group.spTree.length === 0)
                            {
                                cur_group.group.removeFromSpTree(cur_group.Get_Id());
                            }
                            else if(cur_group.spTree.length == 1)
                            {
                                sp = cur_group.spTree[0];
                                hc = sp.spPr.xfrm.extX/2;
                                vc = sp.spPr.xfrm.extY/2;
                                xc = sp.transform.TransformPointX(hc, vc);
                                yc = sp.transform.TransformPointY(hc, vc);
                                rel_xc = cur_group.group.invertTransform.TransformPointX(xc, yc);
                                rel_yc = cur_group.group.invertTransform.TransformPointY(xc, yc);
                                sp.spPr.xfrm.setOffX(rel_xc - hc);
                                sp.spPr.xfrm.setOffY(rel_yc - vc);
                                sp.spPr.xfrm.setRot(AscFormat.normalizeRotate(cur_group.rot + sp.rot));
                                sp.spPr.xfrm.setFlipH(cur_group.spPr.xfrm.flipH === true ? !(sp.spPr.xfrm.flipH === true) : sp.spPr.xfrm.flipH === true);
                                sp.spPr.xfrm.setFlipV(cur_group.spPr.xfrm.flipV === true ? !(sp.spPr.xfrm.flipV === true) : sp.spPr.xfrm.flipV === true);
                                sp.setGroup(cur_group.group);
                                for(j = 0; j < cur_group.group.spTree.length; ++j)
                                {
                                    if(cur_group.group.spTree[j] === cur_group)
                                    {
                                        cur_group.group.addToSpTree(j, sp);
                                        cur_group.group.removeFromSpTree(cur_group.Get_Id());
                                    }
                                }
                            }
                        }
                        else
                        {
                            if(cur_group.spTree.length === 0)
                            {
                                this.resetInternalSelection();
                                this.removeCallback();
                                return;
                            }
                            else if(cur_group.spTree.length === 1)
                            {
                                sp = cur_group.spTree[0];
                                sp.spPr.xfrm.setOffX(cur_group.spPr.xfrm.offX + sp.spPr.xfrm.offX);
                                sp.spPr.xfrm.setOffY(cur_group.spPr.xfrm.offY + sp.spPr.xfrm.offY);
                                sp.spPr.xfrm.setRot(AscFormat.normalizeRotate(cur_group.rot + sp.rot));
                                sp.spPr.xfrm.setFlipH(cur_group.spPr.xfrm.flipH === true ? !(sp.spPr.xfrm.flipH === true) : sp.spPr.xfrm.flipH === true);
                                sp.spPr.xfrm.setFlipV(cur_group.spPr.xfrm.flipV === true ? !(sp.spPr.xfrm.flipV === true) : sp.spPr.xfrm.flipV === true);
                                sp.setGroup(null);
                                sp.addToDrawingObjects();
                                sp.checkDrawingBaseCoords();
                                cur_group.deleteDrawingBase();
                                this.resetSelection();
                                this.selectObject(sp, cur_group.selectStartPage);
                            }
                            else
                            {
                                cur_group.updateCoordinatesAfterInternalResize();
                            }
                            this.resetInternalSelection();
                            this.recalculate();
                            return;
                        }
                    }
                    this.resetInternalSelection();
                }
            }
            else if(this.selection.chartSelection)
            {
                this.selection.chartSelection.remove();
            }
            else
            {
                this.resetConnectors(this.selectedObjects);
                for(var i = 0; i < this.selectedObjects.length; ++i)
                {
                    
                    this.selectedObjects[i].deleteDrawingBase(true);                    
                    if(this.selectedObjects[i].signatureLine){
                        var oApi = this.getEditorApi();
                        if(oApi){
                            oApi.sendEvent("asc_onRemoveSignature", this.selectedObjects[i].signatureLine.id);
                        }
                    }
                    if(this.selectedObjects[i].setBDeleted){
                        this.selectedObjects[i].setBDeleted(true);
                    }

                }
                this.resetSelection();
                this.recalculate();
            }
            this.updateOverlay();
        }
        else if(this.drawingObjects.slideComments)
        {
            this.drawingObjects.slideComments.removeSelectedComment();
        }
    },


    getAllObjectsOnPage: function(pageIndex, bHdrFtr)
    {
        return this.getDrawingArray();
    },

    selectNextObject: function(direction)
    {
        var selection_array = this.selectedObjects;
        if(selection_array.length > 0)
        {
            var i, graphic_page;
            if(direction > 0)
            {
                var selectNext = function (oThis, last_selected_object)
                {
                    var search_array = oThis.getAllObjectsOnPage(last_selected_object.selectStartPage,
                        last_selected_object.parent && last_selected_object.parent.DocumentContent && last_selected_object.parent.DocumentContent.IsHdrFtr(false));

                    if(search_array.length > 0)
                    {
                        for(var i = search_array.length-1; i > -1; --i)
                        {
                            if(search_array[i] === last_selected_object)
                                break;
                        }
                        if(i > -1)
                        {
                            oThis.resetSelection();
                            oThis.selectObject(search_array[i < search_array.length - 1 ? i+1 : 0], last_selected_object.selectStartPage);
                            return;
                        }
                        else
                        {
                            return;
                        }
                    }

                };

                if(this.selection.groupSelection)
                {
                    for(i = this.selection.groupSelection.arrGraphicObjects.length - 1; i > -1; --i)
                    {
                        if(this.selection.groupSelection.arrGraphicObjects[i].selected)
                            break;
                    }
                    if(i > -1)
                    {
                        if(i < this.selection.groupSelection.arrGraphicObjects.length-1)
                        {
                            this.selection.groupSelection.resetSelection();
                            this.selection.groupSelection.selectObject(this.selection.groupSelection.arrGraphicObjects[i+1], this.selection.groupSelection.selectStartPage);
                        }
                        else
                        {
                            selectNext(this, this.selection.groupSelection);
                        }
                    }
                }
                //else if(this.selection.chartSelection)
                //{}
                else
                {
                    var last_selected_object = this.selectedObjects[this.selectedObjects.length-1];
                    if(last_selected_object.getObjectType() === AscDFH.historyitem_type_GroupShape)
                    {
                        this.resetSelection();
                        this.selectObject(last_selected_object, last_selected_object.selectStartPage);
                        this.selection.groupSelection = last_selected_object;
                        last_selected_object.selectObject(last_selected_object.arrGraphicObjects[0], last_selected_object.selectStartPage);
                    }
                    //else if(last_selected_object.getObjectType() === AscDFH.historyitem_type_ChartSpace)
                    //{TODO}
                    else
                    {
                        selectNext(this, last_selected_object)
                    }
                }
            }
            else
            {
                var selectPrev = function (oThis, first_selected_object)
                {
                    var search_array = oThis.getAllObjectsOnPage(first_selected_object.selectStartPage,
                        first_selected_object.parent && first_selected_object.parent.DocumentContent && first_selected_object.parent.DocumentContent.IsHdrFtr(false));

                    if(search_array.length > 0)
                    {
                        for(var i = 0; i < search_array.length; ++i)
                        {
                            if(search_array[i] === first_selected_object)
                                break;
                        }
                        if(i < search_array.length)
                        {
                            oThis.resetSelection();
                            oThis.selectObject(search_array[i > 0 ? i-1 : search_array.length-1], first_selected_object.selectStartPage);
                            return;
                        }
                        else
                        {
                            return;
                        }
                    }
                }
                if(this.selection.groupSelection)
                {
                    for(i = 0; i < this.selection.groupSelection.arrGraphicObjects.length; ++i)
                    {
                        if(this.selection.groupSelection.arrGraphicObjects[i].selected)
                            break;
                    }
                    if(i < this.selection.groupSelection.arrGraphicObjects.length)
                    {
                        if(i > 0)
                        {
                            this.selection.groupSelection.resetSelection();
                            this.selection.groupSelection.selectObject(this.selection.groupSelection.arrGraphicObjects[i-1], this.selection.groupSelection.selectStartPage);
                        }
                        else
                        {
                            selectPrev(this, this.selection.groupSelection);
                        }
                    }
                    else
                    {

                        return;
                    }
                }
                //else if(this.selection.chartSelection)
                //{
                //
                //}
                else
                {
                    var first_selected_object = this.selectedObjects[0];
                    if(first_selected_object.getObjectType() === AscDFH.historyitem_type_GroupShape)
                    {
                        this.resetSelection();
                        this.selectObject(first_selected_object, first_selected_object.selectStartPage);
                        this.selection.groupSelection = first_selected_object;
                        first_selected_object.selectObject(first_selected_object.arrGraphicObjects[first_selected_object.arrGraphicObjects.length-1], first_selected_object.selectStartPage);
                    }
                    //else if(last_selected_object.getObjectType() === AscDFH.historyitem_type_ChartSpace)
                    //{TODO}
                    else
                    {
                        selectPrev(this, first_selected_object)
                    }
                }
            }
            this.updateOverlay();
            if(this.drawingObjects && this.drawingObjects.sendGraphicObjectProps){
                this.drawingObjects.sendGraphicObjectProps();
            }
            else if(this.document && this.document.Document_UpdateInterfaceState){
                this.document.Document_UpdateInterfaceState();
            }
        }
    },



    moveSelectedObjects: function(dx, dy)
    {
        if(!this.canEdit())
            return;

        var oldCurState = this.curState;
        this.checkSelectedObjectsForMove(this.selection.groupSelection ? this.selection.groupSelection : null);
        this.swapTrackObjects();
        var move_state;
        if(!this.selection.groupSelection)
            move_state = new AscFormat.MoveState(this, this.selectedObjects[0], 0, 0);
        else
            move_state = new AscFormat.MoveInGroupState(this, this.selection.groupSelection.selectedObjects[0], this.selection.groupSelection, 0, 0);

        for(var i = 0; i < this.arrTrackObjects.length; ++i)
            this.arrTrackObjects[i].track(dx, dy, this.arrTrackObjects[i].originalObject.selectStartPage);
        var nPageIndex  = (this.arrTrackObjects[0] && this.arrTrackObjects[0].originalObject && AscFormat.isRealNumber(this.arrTrackObjects[0].originalObject.selectStartPage)) ? this.arrTrackObjects[0].originalObject.selectStartPage : 0;
        move_state.onMouseUp({}, 0, 0, nPageIndex);
        this.curState = oldCurState;
    },

    cursorMoveToStartPos: function()
    {
        var content = this.getTargetDocContent(undefined, true);
        if(content)
        {
            content.MoveCursorToStartPos();
            this.updateSelectionState();
        }
    },

    cursorMoveToEndPos: function()
    {
        var content = this.getTargetDocContent(undefined, true);
        if(content)
        {
            content.MoveCursorToEndPos();
            this.updateSelectionState();
        }
    },

    getMoveDist: function(bWord){
        if(bWord){
            return this.convertPixToMM(1);
        }
        else{
            return this.convertPixToMM(5);
        }
    },

    cursorMoveLeft: function(AddToSelect/*Shift*/, Word/*Ctrl*/)
    {
        var target_text_object = getTargetTextObject(this);
        if(target_text_object)
        {
            if(target_text_object.getObjectType() === AscDFH.historyitem_type_GraphicFrame)
            {
                target_text_object.graphicObject.MoveCursorLeft(AddToSelect, Word);
            }
            else
            {
                var content = this.getTargetDocContent(undefined, true);
                if(content)
                {
                    content.MoveCursorLeft(AddToSelect, Word);
                }
            }
            this.updateSelectionState();
        }
        else
        {
            if(this.selectedObjects.length === 0)
                return;

            this.moveSelectedObjects(-this.getMoveDist(Word), 0);
        }
    },

    cursorMoveRight: function(AddToSelect, Word, bFromPaste)
    {
        var target_text_object = getTargetTextObject(this);
        if(target_text_object)
        {
            if(target_text_object.getObjectType() === AscDFH.historyitem_type_GraphicFrame)
            {
                target_text_object.graphicObject.MoveCursorRight(AddToSelect, Word, bFromPaste);
            }
            else
            {
                var content = this.getTargetDocContent(undefined, true);
                if(content)
                {
                    content.MoveCursorRight(AddToSelect, Word, bFromPaste);
                }
            }
            this.updateSelectionState();
        }
        else
        {
            if(this.selectedObjects.length === 0)
                return;
            this.moveSelectedObjects(this.getMoveDist(Word), 0);
        }
    },


    cursorMoveUp: function(AddToSelect, Word)
    {
        var target_text_object = getTargetTextObject(this);
        if(target_text_object)
        {
            if(target_text_object.getObjectType() === AscDFH.historyitem_type_GraphicFrame)
            {
                target_text_object.graphicObject.MoveCursorUp(AddToSelect);
            }
            else
            {
                var content = this.getTargetDocContent(undefined, true);
                if(content)
                {
                    content.MoveCursorUp(AddToSelect);
                }
            }
            this.updateSelectionState();
        }
        else
        {
            if(this.selectedObjects.length === 0)
                return;
            this.moveSelectedObjects(0, -this.getMoveDist(Word));
        }
    },

    cursorMoveDown: function(AddToSelect, Word)
    {
        var target_text_object = getTargetTextObject(this);
        if(target_text_object)
        {
            if(target_text_object.getObjectType() === AscDFH.historyitem_type_GraphicFrame)
            {
                target_text_object.graphicObject.MoveCursorDown(AddToSelect);
            }
            else
            {
                var content = this.getTargetDocContent(undefined, true);
                if(content)
                {
                    content.MoveCursorDown(AddToSelect);
                }
            }
            this.updateSelectionState();
        }
        else
        {
            if(this.selectedObjects.length === 0)
                return;
            this.moveSelectedObjects(0, this.getMoveDist(Word));
        }
    },

    cursorMoveEndOfLine: function(AddToSelect)
    {
        var content = this.getTargetDocContent(undefined, true);
        if(content)
        {
            content.MoveCursorToEndOfLine(AddToSelect);
            this.updateSelectionState();
        }
    },


    cursorMoveStartOfLine: function(AddToSelect)
    {

        var content = this.getTargetDocContent(undefined, true);
        if(content)
        {
            content.MoveCursorToStartOfLine(AddToSelect);
            this.updateSelectionState();
        }
    },

    cursorMoveAt: function( X, Y, AddToSelect )
    {
        var text_object;
        if(this.selection.textSelection)
        {
            text_object = this.selection.textSelection;
        }
        else if(this.selection.groupSelection && this.selection.groupSelection.selection.textSelection)
        {
            text_object = this.selection.groupSelection.selection.textSelection;
        }
        if(text_object && text_object.cursorMoveAt)
        {
            text_object.cursorMoveAt( X, Y, AddToSelect );
            this.updateSelectionState();
        }
    },

    resetTextSelection: function()
    {
        var oContent = this.getTargetDocContent();
        if(oContent)
        {
            oContent.RemoveSelection();
            var oTextSelection;
            if(this.selection.groupSelection)
            {
                oTextSelection = this.selection.groupSelection.selection.textSelection;
                this.selection.groupSelection.selection.textSelection = null;
            }

            if(this.selection.textSelection)
            {
                oTextSelection = this.selection.textSelection;
                this.selection.textSelection = null;
            }

            if(oTextSelection && oTextSelection.recalcInfo)
            {
                if(oTextSelection.recalcInfo.bRecalculatedTitle)
                {
                    oTextSelection.recalcInfo.recalcTitle = null;
                    oTextSelection.recalcInfo.bRecalculatedTitle = false;
                }
            }

            if(this.selection.chartSelection)
            {
                this.selection.chartSelection.selection.textSelection = null
            }

        }
    },

    selectAll: function()
    {
        var i;
        var target_text_object = getTargetTextObject(this);
        if(target_text_object)
        {
            if(target_text_object.getObjectType() === AscDFH.historyitem_type_GraphicFrame)
            {
                target_text_object.graphicObject.SelectAll();
            }
            else
            {
                var content = this.getTargetDocContent();
                if(content)
                {
                    content.SelectAll();
                }
            }
        }
        else if(!this.document)
        {
            if(this.selection.groupSelection)
            {
                if(!this.selection.groupSelection.selection.chartSelection)
                {
                    this.selection.groupSelection.resetSelection();
                    for(i = this.selection.groupSelection.arrGraphicObjects.length - 1; i > -1; --i)
                    {
                        this.selection.groupSelection.selectObject(this.selection.groupSelection.arrGraphicObjects[i], 0);
                    }
                }
            }
            else if(!this.selection.chartSelection)
            {
                this.resetSelection();
                var drawings = this.getDrawingObjects();
                for(i = drawings.length - 1; i > -1; --i)
                {
                    this.selectObject(drawings[i], 0);
                }
            }
        }
        else{
            this.resetSelection();
            this.document.Set_DocPosType(docpostype_Content);
            this.document.SelectAll();
        }
        this.updateSelectionState();
    },

    canEdit: function()
    {
        var oApi = this.getEditorApi();
        var _ret = true;
        if(oApi){
            _ret = oApi.canEdit();
        }
        return _ret;
    },

    onKeyDown: function(e)
    {
        var ctrlKey = e.metaKey || e.ctrlKey;
        var drawingObjectsController = this;
        var bRetValue = false;
        var state = drawingObjectsController.curState;
        var canEdit = drawingObjectsController.canEdit();
        var oApi = window["Asc"]["editor"];
        if ( e.keyCode == 8 && canEdit ) // BackSpace
        {
            var oTargetTextObject = getTargetTextObject(this);
            drawingObjectsController.remove(-1);
            bRetValue = true;
        }
        else if ( e.keyCode == 9 && canEdit ) // Tab
        {
            if(this.getTargetDocContent())
            {

                var oThis = this;
                var callBack = function()
                {
                    oThis.paragraphAdd(new ParaTab());
                };
                this.checkSelectedObjectsAndCallback(callBack, [], false, AscDFH.historydescription_Spreadsheet_AddTab, undefined, window["Asc"]["editor"].collaborativeEditing.getFast())
            }
            else
            {
                this.selectNextObject(!e.shiftKey ? 1 : -1);
            }
            bRetValue = true;
        }
        else if ( e.keyCode == 13 && canEdit ) // Enter
        {
            var target_doc_content = this.getTargetDocContent();
            if(target_doc_content)
            {
                var hyperlink = this.hyperlinkCheck(false);
                if(hyperlink && !e.shiftKey)
                {
                    window["Asc"]["editor"].wb.handlers.trigger("asc_onHyperlinkClick", hyperlink.GetValue());
                    hyperlink.SetVisited(true);
                    this.drawingObjects.showDrawingObjects(true);
                }
                else
                {
                    var oSelectedInfo = new CSelectedElementsInfo();
                    target_doc_content.GetSelectedElementsInfo(oSelectedInfo);
                    var oMath         = oSelectedInfo.Get_Math();
                    if (null !== oMath && oMath.Is_InInnerContent())
                    {
                        this.checkSelectedObjectsAndCallback(function()
                        {
                            oMath.Handle_AddNewLine();
                        }, [], false, AscDFH.historydescription_Spreadsheet_AddNewParagraph, undefined, window["Asc"]["editor"].collaborativeEditing.getFast());
                        this.recalculate();
                    }
                    else
                    {
                        this.checkSelectedObjectsAndCallback(this.addNewParagraph, [], false, AscDFH.historydescription_Spreadsheet_AddNewParagraph, undefined, window["Asc"]["editor"].collaborativeEditing.getFast());
                        this.recalculate();
                    }

                }
            }
            else{
                var nResult = this.handleEnter();
                if(nResult & 1){
                    this.updateSelectionState();
                    if(this.drawingObjects && this.drawingObjects.sendGraphicObjectProps){
                        this.drawingObjects.sendGraphicObjectProps();
                    }
                }
            }
            bRetValue = true;
        }
        else if ( e.keyCode == 27 ) // Esc
        {
            var content = this.getTargetDocContent();
            if(content)
            {
                content.RemoveSelection();
            }

            if(this.selection.textSelection)
            {
                this.selection.textSelection = null;
                drawingObjectsController.updateSelectionState();
            }
            else if(this.selection.groupSelection)
            {
                if(this.selection.groupSelection.selection.textSelection)
                {
                    this.selection.groupSelection.selection.textSelection = null;
                }
                else if(this.selection.groupSelection.selection.chartSelection)
                {
                    if(this.selection.groupSelection.selection.chartSelection.selection.textSelection)
                    {
                        this.selection.groupSelection.selection.chartSelection.selection.textSelection = null;
                    }
                    else
                    {
                        this.selection.groupSelection.selection.chartSelection.resetSelection();
                        this.selection.groupSelection.selection.chartSelection = null;
                    }
                }
                else
                {
                    this.selection.groupSelection.resetSelection();
                    this.selection.groupSelection = null;
                }
                drawingObjectsController.updateSelectionState();
            }
            else if(this.selection.chartSelection)
            {
                if(this.selection.chartSelection.selection.textSelection)
                {
                    this.selection.chartSelection.selection.textSelection = null;
                }
                else
                {
                    this.selection.chartSelection.resetSelection();
                    this.selection.chartSelection = null;
                }
                drawingObjectsController.updateSelectionState();
            }
            else
            {
                if(!this.checkEndAddShape())
                {
                    this.resetSelection();
                    var ws = drawingObjectsController.drawingObjects.getWorksheet();
                    var isChangeSelectionShape = ws._endSelectionShape();
                    if (isChangeSelectionShape) {
                        ws._drawSelection();
                        ws._updateSelectionNameAndInfo();
                    }
                }
            }
            bRetValue = true;
        }
        else if ( e.keyCode == 32 && canEdit ) // Space
        {
            if(!ctrlKey)
            {
                //if(this.selection.textSelection || this.selection.groupSelection && this.selection.groupSelection.selection.textSelection
                //    || this.selection.chartSelection && this.selection.chartSelection.selection.textSelection)
                //{

                var oThis = this;
                var callBack = function()
                {
                    oThis.paragraphAdd(new ParaSpace(1));
                };
                this.checkSelectedObjectsAndCallback(callBack, [], false, AscDFH.historydescription_Spreadsheet_AddSpace, undefined, window["Asc"]["editor"].collaborativeEditing.getFast());
                //}
               // else
               // {
               //     //TODO: this.selectNextObject(!e.shiftKey ? 1 : -1);
               // }
            }

            bRetValue = true;
        }
        else if ( e.keyCode == 33 ) // PgUp
        {
        }
        else if ( e.keyCode == 34 ) // PgDn
        {
        }
        else if ( e.keyCode == 35 ) // клавиша End
        {
            var content = this.getTargetDocContent();
            if(content)
            {
                if (ctrlKey) // Ctrl + End - переход в конец документа
                {
                    content.MoveCursorToEndPos();
                    drawingObjectsController.updateSelectionState();
                    drawingObjectsController.updateOverlay();
                    this.drawingObjects.sendGraphicObjectProps();

                }
                else // Переходим в конец строки
                {
                    content.MoveCursorToEndOfLine(e.shiftKey);
                    drawingObjectsController.updateSelectionState();
                    drawingObjectsController.updateOverlay();
                    this.drawingObjects.sendGraphicObjectProps();
                }
            }
            bRetValue = true;
        }
        else if ( e.keyCode == 36 ) // клавиша Home
        {
            var content = this.getTargetDocContent();
            if(content)
            {
                if (ctrlKey) // Ctrl + End - переход в конец документа
                {
                    content.MoveCursorToStartPos();
                    drawingObjectsController.updateSelectionState();
                    drawingObjectsController.updateOverlay();
                    this.drawingObjects.sendGraphicObjectProps();
                }
                else // Переходим в конец строки
                {
                    content.MoveCursorToStartOfLine(e.shiftKey);
                    drawingObjectsController.updateSelectionState();
                    drawingObjectsController.updateOverlay();
                    this.drawingObjects.sendGraphicObjectProps();
                }
            }
            bRetValue = true;
        }
        else if ( e.keyCode == 37 ) // Left Arrow
        {
            this.cursorMoveLeft(e.shiftKey,ctrlKey );

            drawingObjectsController.updateSelectionState();
            drawingObjectsController.updateOverlay();
            this.drawingObjects.sendGraphicObjectProps();
            bRetValue = true;
        }
        else if ( e.keyCode == 38 ) // Top Arrow
        {
            this.cursorMoveUp(e.shiftKey, ctrlKey);

            drawingObjectsController.updateSelectionState();
            drawingObjectsController.updateOverlay();
            this.drawingObjects.sendGraphicObjectProps();
            bRetValue = true;
        }
        else if ( e.keyCode == 39 ) // Right Arrow
        {
            this.cursorMoveRight(e.shiftKey,ctrlKey );

            drawingObjectsController.updateSelectionState();
            drawingObjectsController.updateOverlay();
            this.drawingObjects.sendGraphicObjectProps();
            bRetValue = true;
        }
        else if ( e.keyCode == 40 ) // Bottom Arrow
        {
            this.cursorMoveDown(e.shiftKey, ctrlKey);

            drawingObjectsController.updateSelectionState();
            drawingObjectsController.updateOverlay();
            this.drawingObjects.sendGraphicObjectProps();
            bRetValue = true;
        }
        else if ( e.keyCode == 45 ) // Insert
        {
            //TODO
        }
        else if ( e.keyCode == 46 && canEdit ) // Delete
        {
			if (!e.shiftKey)
			{
				var oTargetTextObject = getTargetTextObject(this);
				drawingObjectsController.remove(1);
				bRetValue = true;
			}
        }
        else if ( e.keyCode == 65 && true === ctrlKey ) // Ctrl + A - выделяем все
        {
            this.selectAll();
            this.drawingObjects.sendGraphicObjectProps();
            bRetValue = true;
        }
        else if ( e.keyCode == 66 && canEdit && true === ctrlKey ) // Ctrl + B - делаем текст жирным
        {
            var TextPr = drawingObjectsController.getParagraphTextPr();
            if ( isRealObject(TextPr))
            {
                this.setCellBold(TextPr.Bold === true ? false : true );
                bRetValue = true;
            }
        }
        else if ( e.keyCode == 67 && true === ctrlKey ) // Ctrl + C + ...
        {
            //TODO
        }
        else if ( e.keyCode == 69 && canEdit && true === ctrlKey ) // Ctrl + E - переключение прилегания параграфа между center и left
        {

            var ParaPr = drawingObjectsController.getParagraphParaPr();
            if ( isRealObject(ParaPr))
            {
                this.setCellAlign(ParaPr.Jc === AscCommon.align_Center ? AscCommon.align_Left : AscCommon.align_Center );
                bRetValue = true;
            }
        }
        else if ( e.keyCode == 73 && canEdit && true === ctrlKey ) // Ctrl + I - делаем текст наклонным
        {
            var TextPr = drawingObjectsController.getParagraphTextPr();
            if ( isRealObject(TextPr))
            {
                drawingObjectsController.setCellItalic(TextPr.Italic === true ? false : true );
                bRetValue = true;
            }
        }
        else if ( e.keyCode == 74 && canEdit && true === ctrlKey ) // Ctrl + J переключение прилегания параграфа между justify и left
        {
            var ParaPr = drawingObjectsController.getParagraphParaPr();
            if ( isRealObject(ParaPr))
            {
                drawingObjectsController.setCellAlign(ParaPr.Jc === AscCommon.align_Justify ? AscCommon.align_Left : AscCommon.align_Justify );
                bRetValue = true;
            }
        }
        else if ( e.keyCode == 75 && canEdit && true === ctrlKey ) // Ctrl + K - добавление гиперссылки
        {
            //TODO
            bRetValue = true;
        }
        else if ( e.keyCode == 76 && canEdit && true === ctrlKey ) // Ctrl + L + ...
        {

            var ParaPr = drawingObjectsController.getParagraphParaPr();
            if ( isRealObject(ParaPr))
            {
                drawingObjectsController.setCellAlign(ParaPr.Jc === AscCommon.align_Left ? AscCommon.align_Justify : AscCommon.align_Left);
                bRetValue = true;
            }

        }
        else if ( e.keyCode == 77 && canEdit && true === ctrlKey ) // Ctrl + M + ...
        {
            bRetValue = true;

        }
        else if ( e.keyCode == 80 && true === ctrlKey ) // Ctrl + P + ...
        {
            bRetValue = true;

        }
        else if ( e.keyCode == 82 && canEdit && true === ctrlKey ) // Ctrl + R - переключение прилегания параграфа между right и left
        {
            var ParaPr = drawingObjectsController.getParagraphParaPr();
            if ( isRealObject(ParaPr))
            {
                drawingObjectsController.setCellAlign(ParaPr.Jc === AscCommon.align_Right ? AscCommon.align_Left : AscCommon.align_Right);
                bRetValue = true;
            }
        }
        else if ( e.keyCode == 83 && canEdit && true === ctrlKey ) // Ctrl + S - save
        {
            bRetValue = false;
        }
        else if ( e.keyCode == 85 && canEdit && true === ctrlKey ) // Ctrl + U - делаем текст подчеркнутым
        {
            var TextPr = drawingObjectsController.getParagraphTextPr();
            if ( isRealObject(TextPr))
            {
                drawingObjectsController.setCellUnderline(TextPr.Underline === true ? false : true );
                bRetValue = true;
            }
        }
        else if ( e.keyCode == 86 && canEdit && true === ctrlKey ) // Ctrl + V - paste
        {

        }
        else if ( e.keyCode == 88 && canEdit && true === ctrlKey ) // Ctrl + X - cut
        {
            //не возвращаем true чтобы не было preventDefault
        }
        else if ( e.keyCode == 89 && canEdit && true === ctrlKey ) // Ctrl + Y - Redo
        {
        }
        else if ( e.keyCode == 90 && canEdit && true === ctrlKey ) // Ctrl + Z - Undo
        {
        }
        else if ( e.keyCode == 93 || 57351 == e.keyCode /*в Opera такой код*/ ) // контекстное меню
        {
            bRetValue = true;
        }
        else if ( e.keyCode == 121 && true === e.shiftKey ) // Shift + F10 - контекстное меню
        {
        }
        else if ( e.keyCode == 144 ) // Num Lock
        {
        }
        else if ( e.keyCode == 145 ) // Scroll Lock
        {
        }
        else if ( e.keyCode == 187 && canEdit && true === ctrlKey ) // Ctrl + Shift + +, Ctrl + = - superscript/subscript
        {
            var TextPr = drawingObjectsController.getParagraphTextPr();
            if ( isRealObject(TextPr))
            {
                if ( true === e.shiftKey )
                    drawingObjectsController.setCellSuperscript(TextPr.VertAlign === AscCommon.vertalign_SuperScript ? false : true );
                else
                    drawingObjectsController.setCellSubscript(TextPr.VertAlign === AscCommon.vertalign_SubScript ? false : true );
                bRetValue = true;
            }
        }
        else if ( e.keyCode == 188 && true === ctrlKey ) // Ctrl + ,
        {
            var TextPr = drawingObjectsController.getParagraphTextPr();
            if ( isRealObject(TextPr))
            {
                drawingObjectsController.setCellSuperscript(TextPr.VertAlign === AscCommon.vertalign_SuperScript ? false : true );
                bRetValue = true;
            }
        }
        else if ( e.keyCode == 189 && canEdit ) // Клавиша Num-
        {

            var Item = null;
            var oThis = this;
            var callBack = function()
            {
                var Item = null;
                if ( true === ctrlKey && true === e.shiftKey )
                {
                    Item = new ParaText(0x2013);
                    Item.SpaceAfter = false;
                }
                else if ( true === e.shiftKey )
                    Item = new ParaText("_".charCodeAt(0));
                else
                    Item = new ParaText("-".charCodeAt(0));
                oThis.paragraphAdd(Item);
            };
            this.checkSelectedObjectsAndCallback(callBack, [], false, AscDFH.historydescription_Spreadsheet_AddItem, undefined, window["Asc"]["editor"].collaborativeEditing.getFast());
            bRetValue = true;
        }
        else if ( e.keyCode == 190 && true === ctrlKey ) // Ctrl + .
        {
            var TextPr = drawingObjectsController.getParagraphTextPr();
            if ( isRealObject(TextPr))
            {
                drawingObjectsController.setCellSubscript(TextPr.VertAlign === AscCommon.vertalign_SubScript ? false : true );
                bRetValue = true;
            }
        }
        else if ( e.keyCode == 219 && canEdit && true === ctrlKey ) // Ctrl + [
        {
            drawingObjectsController.decreaseFontSize();
            bRetValue = true;
        }
        else if ( e.keyCode == 221 && canEdit && true === ctrlKey ) // Ctrl + ]
        {
            drawingObjectsController.increaseFontSize();
            bRetValue = true;
        }
        else if ( e.keyCode === 113 ) // F2
        {
            // ToDo обработать эту горячую клавишу. В автофигуры можно добавлять формулу
            bRetValue = true;
        }
        if(bRetValue)
            e.preventDefault();
        return bRetValue;
    },

    checkTrackDrawings: function(){
        return this.curState instanceof  AscFormat.StartAddNewShape
        || this.curState instanceof  AscFormat.SplineBezierState
        || this.curState instanceof  AscFormat.PolyLineAddState
        || this.curState instanceof  AscFormat.AddPolyLine2State
        || this.arrTrackObjects.length > 0 || this.arrPreTrackObjects.length > 0;
    },

    checkEndAddShape: function()
    {
        if(this.curState instanceof  AscFormat.StartAddNewShape
            || this.curState instanceof  AscFormat.SplineBezierState
            || this.curState instanceof  AscFormat.PolyLineAddState
            || this.curState instanceof  AscFormat.AddPolyLine2State
            || this.arrTrackObjects.length > 0)
        {
            this.changeCurrentState(new AscFormat.NullState(this));
            if( this.arrTrackObjects.length > 0)
            {
                this.clearTrackObjects();
                this.updateOverlay();
            }
            if(Asc["editor"])
            {
                Asc["editor"].asc_endAddShape();
                var ws = Asc["editor"].wb.getWorksheet();
                if(ws){
                    var ct = ws.getCursorTypeFromXY(ws.objectRender.lastX, ws.objectRender.lastY);
                    if(ct){
                        Asc["editor"].wb._onUpdateCursor(ct.cursor);
                    }
                }
            }
            return true;
        }
        return false;
    },

    /*onKeyPress: function(e)
     {
     this.curState.onKeyPress(e);
     return true;
     },*/

    resetSelectionState: function()
    {
        if(this.bNoResetSeclectionState === true)
            return;
        this.checkChartTextSelection();
        this.resetSelection();
        this.clearPreTrackObjects();
        this.clearTrackObjects();
        this.changeCurrentState(new AscFormat.NullState(this, this.drawingObjects));
        this.updateSelectionState();
        Asc["editor"] && Asc["editor"].asc_endAddShape();
    },

    resetSelectionState2: function()
    {
        var count = this.selectedObjects.length;
        while(count > 0)
        {
            this.selectedObjects[0].deselect(this);
            --count;
        }
        this.changeCurrentState(new AscFormat.NullState(this, this.drawingObjects));
    },

    getColorMapOverride: function()
    {
        return null;
    },

    Document_UpdateInterfaceState: function()
    {},

    getChartObject: function(type, w, h)
    {
        if(null != type)
        {
            return AscFormat.ExecuteNoHistory(function()
            {
                var options = new Asc.asc_ChartSettings();
                options.type = type;
                options.style = 1;
                options.putTitle(c_oAscChartTitleShowSettings.noOverlay);
                var chartSeries = {series: DrawingObjectsController.prototype.getSeriesDefault.call(this, type),
                    parsedHeaders: {bLeft: true, bTop: true}};
                var ret = this.getChartSpace2(chartSeries, options);
                if (!ret) {
                    chartSeries = {series: DrawingObjectsController.prototype.getSeriesDefault.call(this,
                        c_oAscChartTypeSettings.barNormal), parsedHeaders: {bLeft: true, bTop: true}};
                    ret = this.getChartSpace2(chartSeries, options);
                }
                if(type === c_oAscChartTypeSettings.scatter)
                {
                    var new_hor_axis_settings = new AscCommon.asc_ValAxisSettings();
                    new_hor_axis_settings.setDefault();
                    options.putHorAxisProps(new_hor_axis_settings);
                    var new_vert_axis_settings = new AscCommon.asc_ValAxisSettings();
                    new_vert_axis_settings.setDefault();
                    options.putVertAxisProps(new_vert_axis_settings);
                    options.putHorGridLines(c_oAscGridLinesSettings.major);
                    options.putVertGridLines(c_oAscGridLinesSettings.major);
                    options.putShowMarker(true);
                    options.putSmooth(null);
                    options.putLine(false);
                }
                options.type = null;
                options.bCreate = true;
                this.applyPropsToChartSpace(options, ret);
                options.bCreate = false;
                this.applyPropsToChartSpace(options, ret);
                ret.theme = this.getTheme();
                CheckSpPrXfrm(ret);
                ret.spPr.xfrm.setOffX(0);
                ret.spPr.xfrm.setOffY(0);
                if(AscFormat.isRealNumber(w) && w > 0.0){
                    var dAspect = w/ret.spPr.xfrm.extX;
                    if(dAspect < 1.0){
                        ret.spPr.xfrm.setExtX(w);
                        ret.spPr.xfrm.setExtY(ret.spPr.xfrm.extY*dAspect);
                    }
                }
                ret.theme = this.getTheme();
                ret.colorMapOverride = this.getColorMapOverride();
                return ret;
            }, this, []);
        }
        else
        {
            var by_types = getObjectsByTypesFromArr(this.selection.groupSelection ? this.selection.groupSelection.selectedObjects : this.selectedObjects, true);
            if(by_types.charts.length === 1)
            {
                by_types.charts[0].theme = this.getTheme();
                by_types.charts[0].colorMapOverride = this.getColorMapOverride();
                AscFormat.ExecuteNoHistory(function()
                {
                    CheckSpPrXfrm2(by_types.charts[0]);
                }, this, []);
                return by_types.charts[0];
            }
        }
        return null;
    },


    checkNeedResetChartSelection: function(e, x, y, pageIndex, bTextFlag)
    {
        var oTitle, oCursorInfo, oTargetTextObject = getTargetTextObject(this);
        if(oTargetTextObject instanceof AscFormat.CTitle)
        {
            oTitle = oTargetTextObject;
        }
        if(!oTitle)
            return true;

        this.handleEventMode = HANDLE_EVENT_MODE_CURSOR;
        oCursorInfo = this.curState.onMouseDown(e, x, y, pageIndex, bTextFlag);
        this.handleEventMode = HANDLE_EVENT_MODE_HANDLE;

        return !(isRealObject(oCursorInfo) && oTitle === oCursorInfo.title);
    },

    checkChartTextSelection: function(bNoRedraw)
    {
        if(this.bNoCheckChartTextSelection === true)
            return false;
        var chart_selection, bRet = false;
        var nPageNum1, nPageNum2;
        if(this.selection.chartSelection)
        {
            chart_selection = this.selection.chartSelection;
        }
        else if(this.selection.groupSelection && this.selection.groupSelection.selection.chartSelection)
        {
            chart_selection = this.selection.groupSelection.selection.chartSelection;
        }
        if(chart_selection && (chart_selection.selection.textSelection || chart_selection.selection.title))
        {
            var oTitle = chart_selection.selection.textSelection;
            if(!oTitle){
                oTitle = chart_selection.selection.title;
                nPageNum2 = this.drawingObjects.num;
            }
            var content = oTitle.getDocContent(), bDeleteTitle = false;
            if(content)
            {
                if(content.Is_Empty())
                {
                    if(chart_selection.selection.title && chart_selection.selection.title.parent)
                    {
                        History.Create_NewPoint(AscDFH.historydescription_CommonControllerCheckChartText);
                        chart_selection.selection.title.parent.setTitle(null);
                        bDeleteTitle = true;
                    }
                }
            }
            if(chart_selection.recalcInfo.bRecalculatedTitle || bDeleteTitle)
            {
                chart_selection.recalcInfo.recalcTitle = null;
                chart_selection.handleUpdateInternalChart();
                if(this.document)
                {
                    chart_selection.recalculate();
                    nPageNum1  = chart_selection.selectStartPage;
                }
                else if(this.drawingObjects.cSld)
                {
                    chart_selection.recalculate();
                    if(!(bNoRedraw === true))
                    {
                        nPageNum1 = this.drawingObjects.num;
                    }
                }
                else
                {
                    nPageNum1 = 0;
                    chart_selection.recalculate();
                }
                chart_selection.recalcInfo.bRecalculatedTitle = false;
            }
        }
        var oTargetTextObject = getTargetTextObject(this);
        var nSelectStartPage = 0, bNoNeedRecalc = false;
        if(oTargetTextObject)
        {
            nSelectStartPage = oTargetTextObject.selectStartPage;
        }
        if((!(oTargetTextObject instanceof AscFormat.CShape)) && this.document)
        {
            if(this.selectedObjects.length === 1 && this.selectedObjects[0].parent)
            {
                var oShape =  this.selectedObjects[0].parent.isShapeChild(true);
                if(oShape)
                {
                    oTargetTextObject = oShape;
                    nSelectStartPage = this.selectedObjects[0].selectStartPage;
                    bNoNeedRecalc = true;
                }
            }
        }
        if (oTargetTextObject) {

            var warpGeometry = oTargetTextObject.recalcInfo && oTargetTextObject.recalcInfo.warpGeometry;
            if(warpGeometry && warpGeometry.preset !== "textNoShape" || oTargetTextObject.worksheet)
            {
                if (oTargetTextObject.recalcInfo.bRecalculatedTitle)
                {
                    oTargetTextObject.recalcInfo.recalcTitle = null;
                    oTargetTextObject.recalcInfo.bRecalculatedTitle = false;
                    AscFormat.ExecuteNoHistory(function()
                    {
                        if(oTargetTextObject.bWordShape)
                        {
                            if(!bNoNeedRecalc)
                            {
                                oTargetTextObject.recalcInfo.oContentMetrics = oTargetTextObject.recalculateTxBoxContent();
                                oTargetTextObject.recalcInfo.recalculateTxBoxContent = false;
                                oTargetTextObject.recalcInfo.AllDrawings = [];
                                var oContent = oTargetTextObject.getDocContent();
                                if(oContent)
                                {
                                    oContent.GetAllDrawingObjects(oTargetTextObject.recalcInfo.AllDrawings);
                                }
                            }
                        }
                        else
                        {
                            oTargetTextObject.recalcInfo.oContentMetrics = oTargetTextObject.recalculateContent();
                            oTargetTextObject.recalcInfo.recalculateContent = false;
                        }
                    }, this, []);

                }
                if (this.document)
                {
                    nPageNum2 = nSelectStartPage;
                }
                else if (this.drawingObjects.cSld)
                {
                 //   if (!(bNoRedraw === true))
                    {
                        nPageNum2 = this.drawingObjects.num;
                    }
                }
                else
                {
                    nPageNum2 = 0;
                }
            }

        }

        if(AscFormat.isRealNumber(nPageNum1))
        {
            bRet = true;
            if(this.document)
            {
                this.document.DrawingDocument.OnRecalculatePage( nPageNum1, this.document.Pages[nPageNum1] );
                this.document.DrawingDocument.OnEndRecalculate( false, true );
            }
            else if(this.drawingObjects.cSld)
            {
                if(!(bNoRedraw === true))
                {
                    editor.WordControl.m_oDrawingDocument.OnRecalculatePage( nPageNum1, this.drawingObjects );
                    editor.WordControl.m_oDrawingDocument.OnEndRecalculate( false, true );
                }
            }
            else
            {
                this.drawingObjects.showDrawingObjects(true);
            }
        }
        if(AscFormat.isRealNumber(nPageNum2) && nPageNum2 !== nPageNum1)
        {

            bRet = true;
            if(this.document)
            {
                this.document.DrawingDocument.OnRecalculatePage( nPageNum2, this.document.Pages[nPageNum2] );
                this.document.DrawingDocument.OnEndRecalculate( false, true );
            }
            else if(this.drawingObjects.cSld)
            {
                if(!(bNoRedraw === true))
                {
                    editor.WordControl.m_oDrawingDocument.OnRecalculatePage( nPageNum2, this.drawingObjects );
                    editor.WordControl.m_oDrawingDocument.OnEndRecalculate( false, true );
                }
            }
            else
            {
                this.drawingObjects.showDrawingObjects(true);
            }
        }
        return bRet;
    },

    resetSelection: function(noResetContentSelect, bNoCheckChart)
    {
        if(bNoCheckChart !== true)
        {
            this.checkChartTextSelection();
        }
        this.resetInternalSelection(noResetContentSelect);
        for(var i = 0; i < this.selectedObjects.length; ++i)
        {
            this.selectedObjects[i].selected = false;
        }
        this.selectedObjects.length = 0;
        this.selection =
        {
            selectedObjects: [],
            groupSelection: null,
            chartSelection: null,
            textSelection: null
        };
    },

    clearPreTrackObjects: function()
    {
        this.arrPreTrackObjects.length = 0;
    },

    addPreTrackObject: function(preTrackObject)
    {
        this.arrPreTrackObjects.push(preTrackObject);
    },

    clearTrackObjects: function()
    {
        this.arrTrackObjects.length = 0;
    },

    addTrackObject: function(trackObject)
    {
        this.arrTrackObjects.push(trackObject);
    },

    swapTrackObjects: function()
    {
        this.checkConnectorsPreTrack();
        this.clearTrackObjects();
        for(var i = 0; i < this.arrPreTrackObjects.length; ++i)
            this.addTrackObject(this.arrPreTrackObjects[i]);
        this.clearPreTrackObjects();
    },

    rotateTrackObjects: function(angle, e)
    {
        for(var i = 0; i < this.arrTrackObjects.length; ++i)
            this.arrTrackObjects[i].track(angle, e);
    },

    trackResizeObjects: function(kd1, kd2, e, x, y)
    {
        for(var i = 0; i < this.arrTrackObjects.length; ++i)
            this.arrTrackObjects[i].track(kd1, kd2, e, x, y);
    },

    trackEnd: function()
    {
        var oOriginalObjects = [];
        for(var i = 0; i < this.arrTrackObjects.length; ++i){
            this.arrTrackObjects[i].trackEnd();
            if(this.arrTrackObjects[i].originalObject && !this.arrTrackObjects[i].processor3D){
                oOriginalObjects.push(this.arrTrackObjects[i].originalObject);
            }
        }
        var aAllConnectors = this.getAllConnectorsByDrawings(oOriginalObjects, [],  undefined, true);
        for(i = 0; i < aAllConnectors.length; ++i){
            aAllConnectors[i].calculateTransform();
        }
        this.drawingObjects.showDrawingObjects(true);
    },

    canGroup: function()
    {
        return this.getArrayForGrouping().length > 1;
    },

    getArrayForGrouping: function()
    {
        var graphic_objects = this.getDrawingObjects();
        var grouped_objects = [];
        for(var i = 0; i < graphic_objects.length; ++i)
        {
            var cur_graphic_object = graphic_objects[i];
            if(cur_graphic_object.selected && cur_graphic_object.canGroup())
            {
                grouped_objects.push(cur_graphic_object);
            }
        }
        return grouped_objects;
    },


    getBoundsForGroup: function(arrDrawings)
    {
        var bounds = arrDrawings[0].getBoundsInGroup();
        var max_x = bounds.r;
        var max_y = bounds.b;
        var min_x = bounds.l;
        var min_y = bounds.t;
        for(var i = 1; i < arrDrawings.length; ++i)
        {
            bounds = arrDrawings[i].getBoundsInGroup();
            if(max_x < bounds.r)
                max_x = bounds.r;
            if(max_y < bounds.b)
                max_y = bounds.b;
            if(min_x > bounds.l)
                min_x = bounds.l;
            if(min_y > bounds.t)
                min_y = bounds.t;
        }
        return new AscFormat.CGraphicBounds(min_x, min_y, max_x, max_y);
    },


    getGroup: function(arrDrawings)
    {
        if(!Array.isArray(arrDrawings))
            arrDrawings = this.getArrayForGrouping();
        if(arrDrawings.length < 2)
            return null;
        var bounds = this.getBoundsForGroup(arrDrawings);
        var max_x = bounds.r;
        var max_y = bounds.b;
        var min_x = bounds.l;
        var min_y = bounds.t;
        var group = new AscFormat.CGroupShape();
        group.setSpPr(new AscFormat.CSpPr());
        group.spPr.setParent(group);
        group.spPr.setXfrm(new AscFormat.CXfrm());
        var xfrm = group.spPr.xfrm;
        xfrm.setParent(group.spPr);
        xfrm.setOffX(min_x);
        xfrm.setOffY(min_y);
        xfrm.setExtX(max_x-min_x);
        xfrm.setExtY(max_y-min_y);
        xfrm.setChExtX(max_x-min_x);
        xfrm.setChExtY(max_y-min_y);
        xfrm.setChOffX(0);
        xfrm.setChOffY(0);
        for(var i = 0; i < arrDrawings.length; ++i)
        {
            CheckSpPrXfrm(arrDrawings[i]);
            arrDrawings[i].spPr.xfrm.setOffX(arrDrawings[i].x - min_x);
            arrDrawings[i].spPr.xfrm.setOffY(arrDrawings[i].y - min_y);
            arrDrawings[i].setGroup(group);
            group.addToSpTree(group.spTree.length, arrDrawings[i]);
        }
        group.setBDeleted(false);
        return group;
    },

    unGroup: function()
    {
        this.checkSelectedObjectsAndCallback(this.unGroupCallback, null, false, AscDFH.historydescription_CommonControllerUnGroup)
    },

    getSelectedObjectsBounds: function(isTextSelectionUse)
    {
        if((!this.getTargetDocContent() || true === isTextSelectionUse) && this.selectedObjects.length > 0)
        {
            var nPageIndex, aDrawings, oRes, aSelectedCopy, i;
            if(this.selection.groupSelection)
            {
                aDrawings = this.selection.groupSelection.selectedObjects;
                nPageIndex = this.selection.groupSelection.selectStartPage;

            }
            else
            {
                aSelectedCopy = [].concat(this.selectedObjects);
                aSelectedCopy.sort(function(a, b){return a.selectStartPage - b.selectStartPage});
                nPageIndex = aSelectedCopy[0].selectStartPage;
                aDrawings = [];
                for(i = 0; i < aSelectedCopy.length; ++i)
                {
                    if(nPageIndex === aSelectedCopy[i].selectStartPage)
                    {
                        aDrawings.push(aSelectedCopy[i]);
                    }
                    else
                    {
                        break;
                    }
                }
            }
            oRes = getAbsoluteRectBoundsArr(aDrawings);
            oRes.pageIndex = nPageIndex;
            return oRes;
        }
        return null;
    },

    unGroupCallback: function()
    {
        var ungroup_arr = this.canUnGroup(true), aGraphicObjects;
        if(ungroup_arr.length > 0)
        {
            this.resetSelection();
            var i, j,   cur_group, sp_tree, sp, nInsertPos;
            for(i = 0; i < ungroup_arr.length; ++i)
            {
                cur_group = ungroup_arr[i];
                cur_group.normalize();

                aGraphicObjects = this.getDrawingObjects();
                nInsertPos = undefined;
                for(j = 0; j < aGraphicObjects.length; ++j)
                {
                    if(aGraphicObjects[j] === cur_group)
                    {
                        nInsertPos = j;
                        break;
                    }
                }



                sp_tree = cur_group.spTree;
                var xc, yc;
                for(j = 0; j < sp_tree.length; ++j)
                {
                    sp = sp_tree[j];
                    sp.spPr.xfrm.setRot(AscFormat.normalizeRotate(sp.rot + cur_group.rot));
                    xc = sp.transform.TransformPointX(sp.extX/2.0, sp.extY/2.0);
                    yc = sp.transform.TransformPointY(sp.extX/2.0, sp.extY/2.0);
                    sp.spPr.xfrm.setOffX(xc - sp.extX/2.0);
                    sp.spPr.xfrm.setOffY(yc - sp.extY/2.0);
                    sp.spPr.xfrm.setFlipH(cur_group.spPr.xfrm.flipH === true ? !(sp.spPr.xfrm.flipH === true) : sp.spPr.xfrm.flipH === true);
                    sp.spPr.xfrm.setFlipV(cur_group.spPr.xfrm.flipV === true ? !(sp.spPr.xfrm.flipV === true) : sp.spPr.xfrm.flipV === true);
                    sp.setGroup(null);
                    if(sp.spPr.Fill && sp.spPr.Fill.fill && sp.spPr.Fill.fill.type === Asc.c_oAscFill.FILL_TYPE_GRP && cur_group.spPr && cur_group.spPr.Fill)
                    {
                        sp.spPr.setFill(cur_group.spPr.Fill.createDuplicate());
                    }
                    if(AscFormat.isRealNumber(nInsertPos)){
                        sp.addToDrawingObjects(nInsertPos + j);
                    }
                    else {
                        sp.addToDrawingObjects();
                    }
                    sp.checkDrawingBaseCoords();
                    this.selectObject(sp, 0);
                }
                cur_group.setBDeleted(true);
                cur_group.deleteDrawingBase();
            }
        }
    },

    canUnGroup: function(bRetArray)
    {
        var _arr_selected_objects = this.selectedObjects;
        var ret_array = [];
        for(var _index = 0; _index < _arr_selected_objects.length; ++_index)
        {
            if(_arr_selected_objects[_index].getObjectType() === AscDFH.historyitem_type_GroupShape
                && (!_arr_selected_objects[_index].parent || _arr_selected_objects[_index].parent && (!_arr_selected_objects[_index].parent.Is_Inline || !_arr_selected_objects[_index].parent.Is_Inline())))
            {
                if(!(bRetArray === true))
                    return true;
                ret_array.push(_arr_selected_objects[_index]);

            }
        }
        return bRetArray === true ? ret_array : false;
    },

    startTrackNewShape: function(presetGeom)
    {
        switch (presetGeom)
        {
            case "spline":
            {
                this.changeCurrentState(new AscFormat.SplineBezierState(this));
                break;
            }
            case "polyline1":
            {
                this.changeCurrentState(new AscFormat.PolyLineAddState(this));
                break;
            }
            case "polyline2":
            {
                this.changeCurrentState(new AscFormat.AddPolyLine2State(this));
                break;
            }
            default :
            {
                this.changeCurrentState(new AscFormat.StartAddNewShape(this, presetGeom));
                break;
            }
        }
    },


    getHyperlinkInfo: function()
    {
        var content = this.getTargetDocContent();
        if(content)
        {
            if ( ( true === content.Selection.Use && content.Selection.StartPos == content.Selection.EndPos) || false == content.Selection.Use )
            {
                var paragraph;
                if ( true == content.Selection.Use )
                    paragraph = content.Content[content.Selection.StartPos];
                else
                    paragraph = content.Content[content.CurPos.ContentPos];

                var HyperPos = -1;
                if ( true === paragraph.Selection.Use )
                {
                    var StartPos = paragraph.Selection.StartPos;
                    var EndPos   = paragraph.Selection.EndPos;
                    if ( StartPos > EndPos )
                    {
                        StartPos = paragraph.Selection.EndPos;
                        EndPos   = paragraph.Selection.StartPos;
                    }

                    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
                    {
                        var Element = paragraph.Content[CurPos];

                        if ( true !== Element.IsSelectionEmpty() && para_Hyperlink !== Element.Type )
                            break;
                        else if ( true !== Element.IsSelectionEmpty() && para_Hyperlink === Element.Type )
                        {
                            if ( -1 === HyperPos )
                                HyperPos = CurPos;
                            else
                                break;
                        }
                    }

                    if ( paragraph.Selection.StartPos === paragraph.Selection.EndPos && para_Hyperlink === paragraph.Content[paragraph.Selection.StartPos].Type )
                        HyperPos = paragraph.Selection.StartPos;
                }
                else
                {
                    if (para_Hyperlink === paragraph.Content[paragraph.CurPos.ContentPos].Type)
                        HyperPos = paragraph.CurPos.ContentPos;
                }
                if ( -1 !== HyperPos )
                {
                   return  paragraph.Content[HyperPos];
                }

            }
        }
        return null;
    },

    setSelectionState: function( state, stateIndex )
    {
        if(!Array.isArray(state)){
            return;
        }
        var _state_index = AscFormat.isRealNumber(stateIndex) ? stateIndex : state.length-1;
        var selection_state = state[_state_index];
        this.clearPreTrackObjects();
        this.clearTrackObjects();
        this.resetSelection();
        this.changeCurrentState(new AscFormat.NullState(this));
        if(selection_state.textObject && !selection_state.textObject.bDeleted)
        {
            this.selectObject(selection_state.textObject, selection_state.selectStartPage);
            this.selection.textSelection = selection_state.textObject;
            if(selection_state.textObject.getObjectType() === AscDFH.historyitem_type_GraphicFrame)
            {
                selection_state.textObject.graphicObject.SetSelectionState(selection_state.textSelection, selection_state.textSelection.length-1);
            }
            else
            {
                selection_state.textObject.getDocContent().SetSelectionState(selection_state.textSelection, selection_state.textSelection.length-1);
            }
        }
        else if(selection_state.groupObject && !selection_state.groupObject.bDeleted)
        {
            this.selectObject(selection_state.groupObject, selection_state.selectStartPage);
            this.selection.groupSelection = selection_state.groupObject;
            selection_state.groupObject.setSelectionState(selection_state.groupSelection);
        }
        else if(selection_state.chartObject && !selection_state.chartObject.bDeleted)
        {
            this.selectObject(selection_state.chartObject, selection_state.selectStartPage);
            this.selection.chartSelection = selection_state.chartObject;
            selection_state.chartObject.setSelectionState(selection_state.chartSelection);
        }
        else if(selection_state.wrapObject && !selection_state.wrapObject.bDeleted)
        {
            this.selectObject(selection_state.wrapObject, selection_state.selectStartPage);
            this.selection.wrapPolygonSelection = selection_state.wrapObject;
        }
        else
        {
            if(Array.isArray(selection_state.selection)){
                for(var i = 0; i < selection_state.selection.length; ++i)
                {
                    if(!selection_state.selection[i].object.bDeleted)
                    {
                        this.selectObject(selection_state.selection[i].object, selection_state.selection[i].pageIndex);
                    }
                }
            }
        }
    },


    getSelectionState: function()
    {
        var selection_state = {};
        if(this.selection.textSelection)
        {
            selection_state.focus = true;
            selection_state.textObject = this.selection.textSelection;
            selection_state.selectStartPage = this.selection.textSelection.selectStartPage;
            if(this.selection.textSelection.getObjectType() === AscDFH.historyitem_type_GraphicFrame)
            {
                selection_state.textSelection = this.selection.textSelection.graphicObject.GetSelectionState();
            }
            else
            {
                selection_state.textSelection = this.selection.textSelection.getDocContent().GetSelectionState();
            }
        }
        else if(this.selection.groupSelection)
        {
            selection_state.focus = true;
            selection_state.groupObject = this.selection.groupSelection;
            selection_state.selectStartPage = this.selection.groupSelection.selectStartPage;
            selection_state.groupSelection = this.selection.groupSelection.getSelectionState();
        }
        else if(this.selection.chartSelection)
        {
            selection_state.focus = true;
            selection_state.chartObject = this.selection.chartSelection;
            selection_state.selectStartPage = this.selection.chartSelection.selectStartPage;
            selection_state.chartSelection = this.selection.chartSelection.getSelectionState();
        }
        else if(this.selection.wrapPolygonSelection)
        {
            selection_state.focus = true;
            selection_state.wrapObject = this.selection.wrapPolygonSelection;
            selection_state.selectStartPage = this.selection.wrapPolygonSelection.selectStartPage;
        }
        else
        {
            selection_state.focus = this.selectedObjects.length > 0;
            selection_state.selection = [];
            for(var i = 0; i < this.selectedObjects.length; ++i)
            {
                selection_state.selection.push({object: this.selectedObjects[i], pageIndex: this.selectedObjects[i].selectStartPage});
            }
        }
        if(this.drawingObjects && this.drawingObjects.getWorksheet)
        {
            var worksheetView = this.drawingObjects.getWorksheet();
            if(worksheetView)
            {
                selection_state.worksheetId = worksheetView.model.getId();
            }
        }
        return [selection_state];
    },

    Save_DocumentStateBeforeLoadChanges: function(oState)
    {
        var oTargetDocContent = this.getTargetDocContent(undefined, true);
        if(oTargetDocContent)
        {
            oState.Pos      = oTargetDocContent.GetContentPosition(false, false, undefined);
            oState.StartPos = oTargetDocContent.GetContentPosition(true, true, undefined);
            oState.EndPos   = oTargetDocContent.GetContentPosition(true, false, undefined);
            oState.DrawingSelection = oTargetDocContent.Selection.Use;
        }
        oState.DrawingsSelectionState = this.getSelectionState()[0];
    },

    loadDocumentStateAfterLoadChanges: function(oSelectionState, PageIndex)
    {
        var bDocument = isRealObject(this.document), bNeedRecalculateCurPos = false;
        var nPageIndex = 0;
        if(AscFormat.isRealNumber(PageIndex)){
            nPageIndex = PageIndex;
        }
        else if(!bDocument)
        {
            if(this.drawingObjects.getObjectType && this.drawingObjects.getObjectType() === AscDFH.historyitem_type_Slide)
            {
                nPageIndex = 0;
            }
        }
        if(oSelectionState && oSelectionState.DrawingsSelectionState)
        {
            var oDrawingSelectionState = oSelectionState.DrawingsSelectionState;
            if(oDrawingSelectionState.textObject)
            {
                if(oDrawingSelectionState.textObject.Is_UseInDocument() && (!oDrawingSelectionState.textObject.group || oDrawingSelectionState.textObject.group === this))
                {
                    this.selectObject(oDrawingSelectionState.textObject, bDocument ? (oDrawingSelectionState.textObject.parent ? oDrawingSelectionState.textObject.parent.PageNum : nPageIndex) : nPageIndex);
                    var oDocContent;
                    if(oDrawingSelectionState.textObject instanceof AscFormat.CGraphicFrame){
                        oDocContent = oDrawingSelectionState.textObject.graphicObject;
                    }
                    else {
                        oDocContent = oDrawingSelectionState.textObject.getDocContent();
                    }

                    if(oDocContent){
                        if (true === oSelectionState.DrawingSelection)
                        {
                            oDocContent.SetContentPosition(oSelectionState.StartPos, 0, 0);
                            oDocContent.SetContentSelection(oSelectionState.StartPos, oSelectionState.EndPos, 0, 0, 0);
                        }
                        else
                        {
                            oDocContent.SetContentPosition(oSelectionState.Pos, 0, 0);
                            bNeedRecalculateCurPos = true;
                        }
                        this.selection.textSelection = oDrawingSelectionState.textObject;
                    }
                }
            }
            else if(oDrawingSelectionState.groupObject)
            {
                if(oDrawingSelectionState.groupObject.Is_UseInDocument() && !oDrawingSelectionState.groupObject.group)
                {
                    this.selectObject(oDrawingSelectionState.groupObject, bDocument ? (oDrawingSelectionState.groupObject.parent ? oDrawingSelectionState.groupObject.parent.PageNum : nPageIndex) : nPageIndex);
                    oDrawingSelectionState.groupObject.resetSelection(this);

                    var oState =
                    {
                        DrawingsSelectionState: oDrawingSelectionState.groupSelection,
                        Pos: oSelectionState.Pos,
                        StartPos: oSelectionState.StartPos,
                        EndPos: oSelectionState.EndPos,
                        DrawingSelection: oSelectionState.DrawingSelection
                    };
                    if(oDrawingSelectionState.groupObject.loadDocumentStateAfterLoadChanges(oState, nPageIndex))
                    {
                        this.selection.groupSelection = oDrawingSelectionState.groupObject;
                        if(!oSelectionState.DrawingSelection){
                            bNeedRecalculateCurPos = true;
                        }
                    }
                }
            }
            else if(oDrawingSelectionState.chartObject)
            {
                if(oDrawingSelectionState.chartObject.Is_UseInDocument())
                {
                    this.selectObject(oDrawingSelectionState.chartObject, bDocument ? (oDrawingSelectionState.chartObject.parent ? oDrawingSelectionState.chartObject.parent.PageNum : nPageIndex) : nPageIndex);
                    oDrawingSelectionState.chartObject.resetSelection();
                    if(oDrawingSelectionState.chartObject.loadDocumentStateAfterLoadChanges(oSelectionState))
                    {
                        this.selection.chartSelection = oDrawingSelectionState.chartObject;
                        if(!oSelectionState.DrawingSelection){
                            bNeedRecalculateCurPos = true;
                        }
                    }
                }
            }
            else if(oDrawingSelectionState.wrapObject)
            {
                if(oDrawingSelectionState.wrapObject.parent && oDrawingSelectionState.wrapObject.parent.Is_UseInDocument && oDrawingSelectionState.wrapObject.parent.Is_UseInDocument())
                {
                    this.selectObject(oDrawingSelectionState.wrapObject, oDrawingSelectionState.wrapObject.parent.PageNum);
                    if(oDrawingSelectionState.wrapObject.canChangeWrapPolygon && oDrawingSelectionState.wrapObject.canChangeWrapPolygon() && !oDrawingSelectionState.wrapObject.parent.Is_Inline())
                    {
                        this.selection.wrapPolygonSelection = oDrawingSelectionState.wrapObject;
                    }
                }
            }
            else
            {
                for(var i = 0; i < oDrawingSelectionState.selection.length; ++i)
                {
                    var oSp = oDrawingSelectionState.selection[i].object;
                    if(oSp.Is_UseInDocument() && !oSp.group)
                    {
                        this.selectObject(oSp, bDocument ? (oSp.parent ? oSp.parent.PageNum : nPageIndex) : nPageIndex);
                    }
                }
            }
        }

        if(this.document && bNeedRecalculateCurPos){
            this.document.NeedUpdateTarget = true;
            this.document.RecalculateCurPos();
        }
        return this.selectedObjects.length > 0;
    },


    drawTracks: function(overlay)
    {
        for(var i = 0; i < this.arrTrackObjects.length; ++i)
            this.arrTrackObjects[i].draw(overlay);
    },

    DrawOnOverlay: function(overlay)
    {
        this.drawTracks(overlay);
    },

    needUpdateOverlay: function()
    {
        return this.arrTrackObjects.length > 0;
    },

    drawSelection: function(drawingDocument)
    {
        DrawingObjectsController.prototype.drawSelect.call(this, 0, drawingDocument);
        //this.drawTextSelection();
    },

    getTargetTransform: function()
    {
        var oRet = null;
        if(this.selection.textSelection)
        {
            oRet =  this.selection.textSelection.transformText;
        }
        else if(this.selection.groupSelection )
        {
            if(this.selection.groupSelection.selection.textSelection)
                oRet = this.selection.groupSelection.selection.textSelection.transformText;
            else if(this.selection.groupSelection.selection.chartSelection && this.selection.groupSelection.selection.chartSelection.selection.textSelection)
            {
                oRet = this.selection.groupSelection.selection.chartSelection.selection.textSelection.transformText;
            }
        }
        else if(this.selection.chartSelection && this.selection.chartSelection.selection.textSelection)
        {
            oRet = this.selection.chartSelection.selection.textSelection.transformText;
        }
        if(oRet)
        {
            oRet = oRet.CreateDublicate();
            return oRet;
        }
        return new AscCommon.CMatrix();
    },

    drawTextSelection: function(num)
    {
        var content = this.getTargetDocContent(undefined, true);
        if(content)
        {
            this.drawingObjects.getDrawingDocument().UpdateTargetTransform(this.getTargetTransform());

            content.DrawSelectionOnPage(0);
        }
    },

    getSelectedObjects: function()
    {
        return this.selectedObjects;
    },

    getDrawingPropsFromArray: function(drawings)
    {
        var image_props, shape_props, chart_props, table_props = undefined, new_image_props, new_shape_props, new_chart_props, new_table_props, shape_chart_props, locked;
        var drawing;
        for(var i = 0; i < drawings.length; ++i)
        {
            drawing = drawings[i];
            locked = undefined;
            if(!drawing.group)
            {
                locked = drawing.lockType !== c_oAscLockTypes.kLockTypeNone && drawing.lockType !== c_oAscLockTypes.kLockTypeMine ;
                if(typeof editor !== "undefined" && isRealObject(editor) && editor.isPresentationEditor)
                {
                    if(drawing.Lock)
                    {
                        locked = drawing.Lock.Is_Locked();
                    }
                }
            }
            else
            {
                var oParentGroup = drawing.group.getMainGroup();
                if(oParentGroup)
                {
                    locked = oParentGroup.lockType !== c_oAscLockTypes.kLockTypeNone && oParentGroup.lockType !== c_oAscLockTypes.kLockTypeMine ;
                    if(typeof editor !== "undefined" && isRealObject(editor) && editor.isPresentationEditor)
                    {
                        if(oParentGroup.Lock)
                        {
                            locked = oParentGroup.Lock.Is_Locked();
                        }
                    }
                }
            }
            var lockAspect = drawing.getNoChangeAspect();
            switch(drawing.getObjectType())
            {
                case AscDFH.historyitem_type_Shape:
                case AscDFH.historyitem_type_Cnx:
                {

                    new_shape_props =
                    {
                        canFill: drawing.canFill(),
                        type: drawing.getPresetGeom(),
                        fill: drawing.getFill(),
                        stroke: drawing.getStroke(),
                        paddings: drawing.getPaddings(),
                        verticalTextAlign: drawing.getBodyPr().anchor,
                        vert: drawing.getBodyPr().vert,
                        w: drawing.extX,
                        h: drawing.extY ,
                        canChangeArrows: drawing.canChangeArrows(),
                        bFromChart: false,
                        locked: locked,
                        textArtProperties: drawing.getTextArtProperties(),
                        lockAspect: lockAspect,
                        title: drawing.getTitle(),
                        description: drawing.getDescription(),
                        columnNumber: drawing.getColumnNumber(),
                        columnSpace: drawing.getColumnSpace(),
                        signatureId: drawing.getSignatureLineGuid()
                    };
                    if(!shape_props)
                        shape_props = new_shape_props;
                    else
                    {
                        shape_props = AscFormat.CompareShapeProperties(shape_props, new_shape_props);
                    }
                    break;
                }
                case AscDFH.historyitem_type_ImageShape:
                {
                    new_image_props =
                    {
                        ImageUrl: drawing.getImageUrl(),
                        w: drawing.extX,
                        h: drawing.extY,
                        locked: locked,
                        x: drawing.x,
                        y: drawing.y,
                        lockAspect: lockAspect,
                        title: drawing.getTitle(),
                        description: drawing.getDescription()
                    };
                    if(!image_props)
                        image_props = new_image_props;
                    else
                    {
                        if(image_props.ImageUrl !== null && image_props.ImageUrl !== new_image_props.ImageUrl)
                            image_props.ImageUrl = null;
                        if(image_props.w != null && image_props.w !== new_image_props.w)
                            image_props.w = null;
                        if(image_props.h != null && image_props.h !== new_image_props.h)
                            image_props.h = null;
                        if(image_props.x != null && image_props.x !== new_image_props.x)
                            image_props.x = null;
                        if(image_props.y != null && image_props.y !== new_image_props.y)
                            image_props.y = null;

                        if(image_props.locked || new_image_props.locked)
                            image_props.locked = true;
                        if(image_props.lockAspect || new_image_props.lockAspect)
                            image_props.lockAspect = false;
                        if(image_props.title !== new_image_props.title)
                            image_props.title = undefined;
                        if(image_props.description !== new_image_props.description)
                            image_props.description = undefined;
                        
                    }


                    new_shape_props =
                    {
                        canFill: false,
                        type: drawing.getPresetGeom(),
                        fill: drawing.getFill(),
                        stroke: drawing.getStroke(),
                        paddings: null,
                        verticalTextAlign: null,
                        vert: null,
                        w: drawing.extX,
                        h: drawing.extY ,
                        canChangeArrows: drawing.canChangeArrows(),
                        bFromChart: false,
                        bFromImage: true,
                        locked: locked,
                        textArtProperties: null,
                        lockAspect: lockAspect,
                        title: drawing.getTitle(),
                        description: drawing.getDescription(),
                        columnNumber: null,
                        columnSpace: null,
                        signatureId: null
                    };
                    if(!shape_props)
                        shape_props = new_shape_props;
                    else
                    {
                        shape_props = AscFormat.CompareShapeProperties(shape_props, new_shape_props);
                    }
                    break;
                }
                case AscDFH.historyitem_type_OleObject:
                {
                    var pluginData = new Asc.CPluginData();
                    pluginData.setAttribute("data", drawing.m_sData);
                    pluginData.setAttribute("guid", drawing.m_sApplicationId);
                    pluginData.setAttribute("width", drawing.extX);
                    pluginData.setAttribute("height", drawing.extY);
                    pluginData.setAttribute("widthPix", drawing.m_nPixWidth);
                    pluginData.setAttribute("heightPix", drawing.m_nPixHeight);
                    pluginData.setAttribute("objectId", drawing.Id);
                    new_image_props =
                    {
                        ImageUrl: drawing.getImageUrl(),
                        w: drawing.extX,
                        h: drawing.extY,
                        locked: locked,
                        x: drawing.x,
                        y: drawing.y,
                        lockAspect: lockAspect,
                        pluginGuid: drawing.m_sApplicationId,
                        pluginData: pluginData,
                        oleWidth: drawing.m_fDefaultSizeX,
                        oleHeight: drawing.m_fDefaultSizeY,
                        title: drawing.getTitle(),
                        description: drawing.getDescription()
                    };
                    if(!image_props)
                        image_props = new_image_props;
                    else
                    {
                        image_props.ImageUrl = null;
                        if(image_props.w != null && image_props.w !== new_image_props.w)
                            image_props.w = null;
                        if(image_props.h != null && image_props.h !== new_image_props.h)
                            image_props.h = null;
                        if(image_props.x != null && image_props.x !== new_image_props.x)
                            image_props.x = null;
                        if(image_props.y != null && image_props.y !== new_image_props.y)
                            image_props.y = null;

                        if(image_props.locked || new_image_props.locked)
                            image_props.locked = true;
                        if(image_props.lockAspect || new_image_props.lockAspect)
                            image_props.lockAspect = false;
                        image_props.pluginGuid = null;
                        image_props.pluginData = undefined;
                        image_props.oleWidth = undefined;
                        image_props.oleHeight = undefined;
                        if(image_props.title !== new_image_props.title)
                            image_props.title = undefined;
                        if(image_props.description !== new_image_props.description)
                            image_props.description = undefined;
                    }
                    break;
                }
                case AscDFH.historyitem_type_ChartSpace:
                {
                    var type_subtype = drawing.getTypeSubType();
                    new_chart_props =
                    {
                        type: type_subtype.type,
                        subtype: type_subtype.subtype,
                        styleId: drawing.style,
                        w: drawing.extX,
                        h: drawing.extY,
                        locked: locked,
                        lockAspect: lockAspect,
                        title: drawing.getTitle(),
                        description: drawing.getDescription()
                    };
                    if(!chart_props)
                    {
                        chart_props = new_chart_props;
                        chart_props.chartProps = this.getPropsFromChart(drawing);
                        chart_props.severalCharts = false;
                        chart_props.severalChartStyles = false;
                        chart_props.severalChartTypes = false;
                    }
                    else
                    {
                        chart_props.chartProps = null;
                        chart_props.severalCharts = true;
                        if(!chart_props.severalChartStyles)
                        {
                            chart_props.severalChartStyles = (chart_props.styleId !== new_chart_props.styleId);
                        }
                        if(!chart_props.severalChartTypes)
                        {
                            chart_props.severalChartTypes = (chart_props.type !== new_chart_props.type);
                        }

                        if(chart_props.w != null && chart_props.w !== new_chart_props.w)
                            chart_props.w = null;
                        if(chart_props.h != null && chart_props.h !== new_chart_props.h)
                            chart_props.h = null;

                        if(chart_props.locked || new_chart_props.locked)
                            chart_props.locked = true;
                        if(!chart_props.lockAspect || !new_chart_props.lockAspect)
                            chart_props.locked = false;


                        if(chart_props.title !== new_chart_props.title)
                            chart_props.title = undefined;
                        if(chart_props.description !== new_chart_props.description)
                            chart_props.description = undefined;
                    }

                    new_shape_props =
                    {
                        canFill: true,
                        type: null,
                        fill: drawing.getFill(),
                        stroke: drawing.getStroke(),
                        paddings: null,
                        verticalTextAlign: null,
                        vert: null,
                        w: drawing.extX,
                        h: drawing.extY ,
                        canChangeArrows: false,
                        bFromChart: true,
                        locked: locked,
                        textArtProperties: null,
                        lockAspect: lockAspect,
                        title: drawing.getTitle(),
                        description: drawing.getDescription(),
                        signatureId: drawing.getSignatureLineGuid()
                    };
                    if(!shape_props)
                        shape_props = new_shape_props;
                    else
                    {
                        shape_props = AscFormat.CompareShapeProperties(shape_props, new_shape_props);
                    }

                    if(!shape_chart_props)
                    {
                        shape_chart_props = new_shape_props;
                    }
                    else
                    {
                        shape_chart_props = AscFormat.CompareShapeProperties(shape_chart_props, new_shape_props);
                    }
                    break;
                }
                case AscDFH.historyitem_type_GraphicFrame:
                {
                    if(table_props === undefined)
                    {
                        new_table_props = drawing.graphicObject.Get_Props();
                        table_props = new_table_props;
                        new_table_props.Locked = locked;
                        if(new_table_props.CellsBackground)
                        {
                            if(new_table_props.CellsBackground.Unifill && new_table_props.CellsBackground.Unifill.fill && new_table_props.CellsBackground.Unifill.fill.type !== c_oAscFill.FILL_TYPE_NONE)
                            {
                                new_table_props.CellsBackground.Unifill.check(drawing.Get_Theme(), drawing.Get_ColorMap());
                                var RGBA = new_table_props.CellsBackground.Unifill.getRGBAColor();
                                new_table_props.CellsBackground.Color = new CDocumentColor(RGBA.R, RGBA.G, RGBA.B, false);
                                new_table_props.CellsBackground.Value = Asc.c_oAscShdClear;
                            }
                            else
                            {
                                new_table_props.CellsBackground.Color = new CDocumentColor(0, 0, 0, false);
                                new_table_props.CellsBackground.Value = Asc.c_oAscShdNil;
                            }
                        }
                        if(new_table_props.CellBorders)
                        {
                            var checkBorder = function (border)
                            {
                                if(!border)
                                    return;
                                if(border.Unifill && border.Unifill.fill && border.Unifill.fill.type !== c_oAscFill.FILL_TYPE_NONE)
                                {
                                    border.Unifill.check(drawing.Get_Theme(), drawing.Get_ColorMap());
                                    var RGBA = border.Unifill.getRGBAColor();
                                    border.Color = new CDocumentColor(RGBA.R, RGBA.G, RGBA.B, false);
                                    border.Value = border_Single;
                                }
                                else
                                {
                                    border.Color = new CDocumentColor(0, 0, 0, false);
                                    border.Value = border_Single;
                                }
                            };
                            checkBorder(new_table_props.CellBorders.Top);
                            checkBorder(new_table_props.CellBorders.Bottom);
                            checkBorder(new_table_props.CellBorders.Right);
                            checkBorder(new_table_props.CellBorders.Left);
                        }
                        new_table_props.TableDescription = drawing.getDescription();
                        new_table_props.TableCaption = drawing.getTitle();
                    }
                    else
                    {
                        table_props = null;
                    }
                    break;
                }
                case AscDFH.historyitem_type_GroupShape:
                {
                    var group_drawing_props = this.getDrawingPropsFromArray(drawing.spTree);
                    if(group_drawing_props.shapeProps)
                    {
                        if(!shape_props)
                            shape_props = group_drawing_props.shapeProps;
                        else
                        {
                            shape_props = AscFormat.CompareShapeProperties(shape_props, group_drawing_props.shapeProps);
                        }
                    }

                    if(group_drawing_props.shapeChartProps)
                    {
                        if(!shape_chart_props)
                        {
                            shape_chart_props = group_drawing_props.shapeChartProps;
                        }
                        else
                        {
                            shape_chart_props = AscFormat.CompareShapeProperties(shape_chart_props, group_drawing_props.shapeChartProps);
                        }
                    }
                    if(group_drawing_props.imageProps)
                    {
                        if(!image_props)
                            image_props = group_drawing_props.imageProps;
                        else
                        {
                            if(image_props.ImageUrl !== null && image_props.ImageUrl !== group_drawing_props.imageProps.ImageUrl)
                                image_props.ImageUrl = null;

                            if(image_props.w != null && image_props.w !== group_drawing_props.imageProps.w)
                                image_props.w = null;
                            if(image_props.h != null && image_props.h !== group_drawing_props.imageProps.h)
                                image_props.h = null;
                            if(image_props.x != null && image_props.x !== group_drawing_props.imageProps.x)
                                image_props.x = null;
                            if(image_props.y != null && image_props.y !== group_drawing_props.imageProps.y)
                                image_props.y = null;

                            if(image_props.locked || group_drawing_props.imageProps.locked)
                                image_props.locked = true;
                            if(!image_props.lockAspect || !group_drawing_props.imageProps.lockAspect)
                                image_props.lockAspect = false;
                            if(image_props.title !== group_drawing_props.imageProps.title)
                                image_props.title = undefined;
                            if(image_props.description !== group_drawing_props.imageProps.description)
                                image_props.description = undefined;


                        }
                    }
                    if(group_drawing_props.chartProps)
                    {
                        if(!chart_props)
                        {
                            chart_props = group_drawing_props.chartProps;
                        }
                        else
                        {
                            chart_props.chartProps = null;
                            chart_props.severalCharts = true;
                            if(!chart_props.severalChartStyles)
                            {
                                chart_props.severalChartStyles = (chart_props.styleId !== group_drawing_props.chartProps.styleId);
                            }
                            if(!chart_props.severalChartTypes)
                            {
                                chart_props.severalChartTypes = (chart_props.type !== group_drawing_props.chartProps.type);
                            }
                            if(chart_props.w != null && chart_props.w !== group_drawing_props.chartProps.w)
                                chart_props.w = null;
                            if(chart_props.h != null && chart_props.h !== group_drawing_props.chartProps.h)
                                chart_props.h = null;



                            if(chart_props.title !== group_drawing_props.title)
                                chart_props.title = undefined;
                            if(chart_props.description !== group_drawing_props.chartProps.description)
                                chart_props.description = undefined;


                            if(chart_props.locked || group_drawing_props.chartProps.locked)
                                chart_props.locked = true;
                        }
                    }
                    if(group_drawing_props.tableProps)
                    {
                        if(!table_props)
                        {
                            table_props = group_drawing_props.tableProps;
                        }
                        else
                        {
                            table_props = null;
                        }
                    }
                    break;
                }
            }
        }
        if(shape_props && shape_props.textArtProperties)
        {
            var oTextArtProperties = shape_props.textArtProperties;
            var oTextPr = this.getParagraphTextPr();
            if(oTextPr)
            {
                if(oTextPr.TextFill)
                {
                    oTextArtProperties.Fill = oTextPr.TextFill;
                }
                else if(oTextPr.Unifill)
                {
                    oTextArtProperties.Fill = oTextPr.Unifill;
                }
                else if(oTextPr.Color)
                {
                    oTextArtProperties.Fill = AscFormat.CreateUnfilFromRGB(oTextPr.Color.r, oTextPr.Color.g, oTextPr.Color.b);
                }
                if(oTextPr.TextOutline){
                    oTextArtProperties.Line = oTextPr.TextOutline;
                }
                else{
                    oTextArtProperties.Line = AscFormat.CreateNoFillLine();
                }
                if(oTextArtProperties.Fill)
                {
                    oTextArtProperties.Fill.check(this.getTheme(), this.getColorMap());
                }
                if(oTextArtProperties.Line && oTextArtProperties.Line.Fill)
                {
                    oTextArtProperties.Line.Fill.check(this.getTheme(), this.getColorMap());
                }
            }
        }
        return {imageProps: image_props, shapeProps: shape_props, chartProps: chart_props, tableProps: table_props, shapeChartProps: shape_chart_props};
    },

    getDrawingProps: function()
    {
        if(this.selection.groupSelection)
        {
            return this.getDrawingPropsFromArray(this.selection.groupSelection.selectedObjects);
        }
        return this.getDrawingPropsFromArray(this.selectedObjects);
    },

    getEditorApi: function()
    {
        if(window["Asc"] && window["Asc"]["editor"])
        {
            return window["Asc"]["editor"];
        }
        else
        {
            return editor;
        }
    },

    getGraphicObjectProps: function()
    {
        var  props = this.getDrawingProps();

        var api = this.getEditorApi();
        var shape_props, image_props, chart_props;
        var ascSelectedObjects = [];

        var ret = [], i, bParaLocked = false;
        if(isRealObject(props.shapeChartProps))
        {
            shape_props = new Asc.asc_CImgProperty();
            shape_props.fromGroup = props.shapeChartProps.fromGroup;
            shape_props.ShapeProperties = new Asc.asc_CShapeProperty();
            shape_props.ShapeProperties.type =  props.shapeChartProps.type;
            shape_props.ShapeProperties.fill = props.shapeChartProps.fill;
            shape_props.ShapeProperties.stroke = props.shapeChartProps.stroke;
            shape_props.ShapeProperties.canChangeArrows = props.shapeChartProps.canChangeArrows;
            shape_props.ShapeProperties.bFromChart = props.shapeChartProps.bFromChart;
            shape_props.ShapeProperties.bFromImage = props.shapeChartProps.bFromImage;
            shape_props.ShapeProperties.lockAspect = props.shapeChartProps.lockAspect;

            if(props.shapeChartProps.paddings)
            {
                shape_props.ShapeProperties.paddings = new Asc.asc_CPaddings(props.shapeChartProps.paddings);
            }
            shape_props.verticalTextAlign = props.shapeChartProps.verticalTextAlign;
            shape_props.vert = props.shapeChartProps.vert;
            shape_props.ShapeProperties.canFill = props.shapeChartProps.canFill;
            shape_props.Width = props.shapeChartProps.w;
            shape_props.Height = props.shapeChartProps.h;
            var pr = shape_props.ShapeProperties;
            var oTextArtProperties;
            if (!isRealObject(props.shapeProps))
            {
                if (pr.fill != null && pr.fill.fill != null && pr.fill.fill.type == c_oAscFill.FILL_TYPE_BLIP)
                {
                    if(api)
                        this.drawingObjects.drawingDocument.InitGuiCanvasShape(api.shapeElementId);
                    this.drawingObjects.drawingDocument.LastDrawingUrl = null;
                    this.drawingObjects.drawingDocument.DrawImageTextureFillShape(pr.fill.fill.RasterImageId);
                }
                else
                {
                    if(api)
                        this.drawingObjects.drawingDocument.InitGuiCanvasShape(api.shapeElementId);
                    this.drawingObjects.drawingDocument.DrawImageTextureFillShape(null);
                }


                if(pr.textArtProperties)
                {
                    oTextArtProperties = pr.textArtProperties;
                    if(oTextArtProperties && oTextArtProperties.Fill && oTextArtProperties.Fill.fill  && oTextArtProperties.Fill.fill.type == c_oAscFill.FILL_TYPE_BLIP)
                    {
                        if(api)
                            this.drawingObjects.drawingDocument.InitGuiCanvasTextArt(api.textArtElementId);
                        this.drawingObjects.drawingDocument.LastDrawingUrlTextArt = null;
                        this.WordControl.m_oDrawingDocument.DrawImageTextureFillTextArt(oTextArtProperties.Fill.fill.RasterImageId);
                    }
                    else
                    {
                        this.WordControl.m_oDrawingDocument.DrawImageTextureFillTextArt(null);
                    }
                }

            }
            shape_props.ShapeProperties.fill = AscFormat.CreateAscFill(shape_props.ShapeProperties.fill);
            shape_props.ShapeProperties.stroke = AscFormat.CreateAscStroke(shape_props.ShapeProperties.stroke, shape_props.ShapeProperties.canChangeArrows === true);
            shape_props.ShapeProperties.stroke.canChangeArrows = shape_props.ShapeProperties.canChangeArrows === true;
            shape_props.Locked = props.shapeChartProps.locked === true;

            ret.push(shape_props);
        }
        if (isRealObject(props.shapeProps))
        {
            shape_props = new Asc.asc_CImgProperty();
            shape_props.fromGroup = CanStartEditText(this);
            shape_props.ShapeProperties = new Asc.asc_CShapeProperty();
            shape_props.ShapeProperties.type =  props.shapeProps.type;
            shape_props.ShapeProperties.fill = props.shapeProps.fill;
            shape_props.ShapeProperties.stroke = props.shapeProps.stroke;
            shape_props.ShapeProperties.canChangeArrows = props.shapeProps.canChangeArrows;
            shape_props.ShapeProperties.bFromChart = props.shapeProps.bFromChart;
            shape_props.ShapeProperties.bFromImage = props.shapeProps.bFromImage;
            shape_props.ShapeProperties.lockAspect = props.shapeProps.lockAspect;
            shape_props.ShapeProperties.description = props.shapeProps.description;
            shape_props.ShapeProperties.title = props.shapeProps.title;
            shape_props.description = props.shapeProps.description;
            shape_props.title = props.shapeProps.title;
            shape_props.ShapeProperties.textArtProperties = AscFormat.CreateAscTextArtProps(props.shapeProps.textArtProperties);
            shape_props.lockAspect = props.shapeProps.lockAspect;

            shape_props.ShapeProperties.columnNumber = props.shapeProps.columnNumber;
            shape_props.ShapeProperties.columnSpace = props.shapeProps.columnSpace;
            if(props.shapeProps.textArtProperties)
            {
                oTextArtProperties = props.shapeProps.textArtProperties;
                if(oTextArtProperties && oTextArtProperties.Fill && oTextArtProperties.Fill.fill  && oTextArtProperties.Fill.fill.type == c_oAscFill.FILL_TYPE_BLIP)
                {
                    if(api)
                        this.drawingObjects.drawingDocument.InitGuiCanvasTextArt(api.textArtElementId);
                    this.drawingObjects.drawingDocument.LastDrawingUrlTextArt = null;
                    this.drawingObjects.drawingDocument.DrawImageTextureFillTextArt(oTextArtProperties.Fill.fill.RasterImageId);
                }
                else
                {
                    this.drawingObjects.drawingDocument.DrawImageTextureFillTextArt(null);
                }
            }

            if(props.shapeProps.paddings)
            {
                shape_props.ShapeProperties.paddings = new Asc.asc_CPaddings(props.shapeProps.paddings);
            }
            shape_props.verticalTextAlign = props.shapeProps.verticalTextAlign;
            shape_props.vert = props.shapeProps.vert;
            shape_props.ShapeProperties.canFill = props.shapeProps.canFill;
            shape_props.Width = props.shapeProps.w;
            shape_props.Height = props.shapeProps.h;
            var pr = shape_props.ShapeProperties;
            if (pr.fill != null && pr.fill.fill != null && pr.fill.fill.type == c_oAscFill.FILL_TYPE_BLIP)
            {
                if(api)
                    this.drawingObjects.drawingDocument.InitGuiCanvasShape(api.shapeElementId);
                this.drawingObjects.drawingDocument.LastDrawingUrl = null;
                this.drawingObjects.drawingDocument.DrawImageTextureFillShape(pr.fill.fill.RasterImageId);
            }
            else
            {
                if(api)
                    this.drawingObjects.drawingDocument.InitGuiCanvasShape(api.shapeElementId);
                this.drawingObjects.drawingDocument.DrawImageTextureFillShape(null);
            }
            shape_props.ShapeProperties.fill = AscFormat.CreateAscFill(shape_props.ShapeProperties.fill);
            shape_props.ShapeProperties.stroke = AscFormat.CreateAscStroke(shape_props.ShapeProperties.stroke, shape_props.ShapeProperties.canChangeArrows === true);
            shape_props.ShapeProperties.stroke.canChangeArrows  = shape_props.ShapeProperties.canChangeArrows === true;
            shape_props.Locked = props.shapeProps.locked === true;

            if(!bParaLocked)
            {
                bParaLocked = shape_props.Locked;
            }
            ret.push(shape_props);
        }
        if (isRealObject(props.imageProps))
        {
            image_props = new Asc.asc_CImgProperty();
            image_props.Width = props.imageProps.w;
            image_props.Height = props.imageProps.h;
            image_props.ImageUrl = props.imageProps.ImageUrl;
            image_props.Locked = props.imageProps.locked === true;
            image_props.lockAspect = props.imageProps.lockAspect;


            image_props.pluginGuid = props.imageProps.pluginGuid;
            image_props.pluginData = props.imageProps.pluginData;

            image_props.oleWidth = props.imageProps.oleWidth;
            image_props.oleHeight = props.imageProps.oleHeight;

            image_props.description = props.imageProps.description;
            image_props.title = props.imageProps.title;

            if(!bParaLocked)
            {
                bParaLocked = image_props.Locked;
            }
            ret.push(image_props);
        }
        if (isRealObject(props.chartProps) && isRealObject(props.chartProps.chartProps))
        {
            chart_props = new Asc.asc_CImgProperty();
            chart_props.Width = props.chartProps.w;
            chart_props.Height = props.chartProps.h;
            chart_props.ChartProperties = props.chartProps.chartProps;
            chart_props.Locked = props.chartProps.locked === true;
            chart_props.lockAspect = props.chartProps.lockAspect;
            if(!bParaLocked)
            {
                bParaLocked = chart_props.Locked;
            }

            chart_props.description = props.chartProps.description;
            chart_props.title = props.chartProps.title;
            ret.push(chart_props);
        }
        for (i = 0; i < ret.length; i++)
        {
            ascSelectedObjects.push(new AscCommon.asc_CSelectedObject ( Asc.c_oAscTypeSelectElement.Image, new Asc.asc_CImgProperty(ret[i]) ));
        }

        // Текстовые свойства объекта
        var ParaPr = this.getParagraphParaPr();
        var TextPr = this.getParagraphTextPr();
        if ( ParaPr && TextPr ) {
            var theme = this.getTheme();
            if(theme && theme.themeElements && theme.themeElements.fontScheme)
            {
                if(TextPr.FontFamily)
                {
                    TextPr.FontFamily.Name =  theme.themeElements.fontScheme.checkFont(TextPr.FontFamily.Name);
                }
                if(TextPr.RFonts)
                {
                    if(TextPr.RFonts.Ascii)
                        TextPr.RFonts.Ascii.Name     = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.Ascii.Name);
                    if(TextPr.RFonts.EastAsia)
                        TextPr.RFonts.EastAsia.Name  = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.EastAsia.Name);
                    if(TextPr.RFonts.HAnsi)
                        TextPr.RFonts.HAnsi.Name     = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.HAnsi.Name);
                    if(TextPr.RFonts.CS)
                        TextPr.RFonts.CS.Name        = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.CS.Name);
                }
            }

            if(bParaLocked)
            {
                ParaPr.Locked = true;
            }
            this.prepareParagraphProperties(ParaPr, TextPr, ascSelectedObjects);
        }
        var oTargetDocContent = this.getTargetDocContent(false, false);
        if(oTargetDocContent)
        {
            if (( true === oTargetDocContent.Selection.Use && oTargetDocContent.Selection.StartPos == oTargetDocContent.Selection.EndPos && type_Paragraph == oTargetDocContent.Content[oTargetDocContent.Selection.StartPos].GetType() ) || ( false == oTargetDocContent.Selection.Use && type_Paragraph == oTargetDocContent.Content[oTargetDocContent.CurPos.ContentPos].GetType() ))
            {
                var oParagraph;
                if (true == oTargetDocContent.Selection.Use)
                    oParagraph = oTargetDocContent.Content[oTargetDocContent.Selection.StartPos];
                else
                    oParagraph = oTargetDocContent.Content[oTargetDocContent.CurPos.ContentPos];
                if ( true === oParagraph.Selection.Use )
                {
                    var StartPos = oParagraph.Selection.StartPos;
                    var EndPos   = oParagraph.Selection.EndPos;
                    if ( StartPos > EndPos )
                    {
                        StartPos = oParagraph.Selection.EndPos;
                        EndPos   = oParagraph.Selection.StartPos;
                    }

                    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
                    {
                        var Element = oParagraph.Content[CurPos];

                        if (true !== Element.IsSelectionEmpty() && (para_Math === Element.Type))
                        {
                            ascSelectedObjects.push(new AscCommon.asc_CSelectedObject(Asc.c_oAscTypeSelectElement.Math, Element.Get_MenuProps()));
                        }
                    }
                }
                else
                {
                    var CurType = oParagraph.Content[oParagraph.CurPos.ContentPos].Type;
                    if (para_Math === CurType)
                    {
                        ascSelectedObjects.push(new AscCommon.asc_CSelectedObject(Asc.c_oAscTypeSelectElement.Math, oParagraph.Content[oParagraph.CurPos.ContentPos].Get_MenuProps()));
                    }
                }
            }
        }

        return ascSelectedObjects;
    },

    prepareParagraphProperties: function(ParaPr, TextPr, ascSelectedObjects)
    {
        var _this = this;
        var trigger = this.drawingObjects.callTrigger;

        ParaPr.Subscript   = ( TextPr.VertAlign === AscCommon.vertalign_SubScript   ? true : false );
        ParaPr.Superscript = ( TextPr.VertAlign === AscCommon.vertalign_SuperScript ? true : false );
        ParaPr.Strikeout   = TextPr.Strikeout;
        ParaPr.DStrikeout  = TextPr.DStrikeout;
        ParaPr.AllCaps     = TextPr.Caps;
        ParaPr.SmallCaps   = TextPr.SmallCaps;
        ParaPr.TextSpacing = TextPr.Spacing;
        ParaPr.Position    = TextPr.Position;
        //-----------------------------------------------------------------------------

        if ( true === ParaPr.Spacing.AfterAutoSpacing )
            ParaPr.Spacing.After = spacing_Auto;
        else if ( undefined === ParaPr.Spacing.AfterAutoSpacing )
            ParaPr.Spacing.After = UnknownValue;

        if ( true === ParaPr.Spacing.BeforeAutoSpacing )
            ParaPr.Spacing.Before = spacing_Auto;
        else if ( undefined === ParaPr.Spacing.BeforeAutoSpacing )
            ParaPr.Spacing.Before = UnknownValue;

        if ( -1 === ParaPr.PStyle )
            ParaPr.StyleName = "";

        if ( null == ParaPr.NumPr || 0 === ParaPr.NumPr.NumId )
            ParaPr.ListType = {Type: -1, SubType : -1};

        // ParaPr.Spacing
        if ( true === ParaPr.Spacing.AfterAutoSpacing )
            ParaPr.Spacing.After = spacing_Auto;
        else if ( undefined === ParaPr.Spacing.AfterAutoSpacing )
            ParaPr.Spacing.After = UnknownValue;

        if ( true === ParaPr.Spacing.BeforeAutoSpacing )
            ParaPr.Spacing.Before = spacing_Auto;
        else if ( undefined === ParaPr.Spacing.BeforeAutoSpacing )
            ParaPr.Spacing.Before = UnknownValue;

        trigger("asc_onParaSpacingLine", new AscCommon.asc_CParagraphSpacing( ParaPr.Spacing ));

        // ParaPr.Jc
        trigger("asc_onPrAlign", ParaPr.Jc);

        ascSelectedObjects.push(new AscCommon.asc_CSelectedObject ( Asc.c_oAscTypeSelectElement.Paragraph, new Asc.asc_CParagraphProperty( ParaPr ) ));
    },


    createImage: function(rasterImageId, x, y, extX, extY)
    {
        var image = new AscFormat.CImageShape();
        AscFormat.fillImage(image, rasterImageId, x, y, extX, extY);
        return image;
    },

    createOleObject: function(data, sApplicationId, rasterImageId, x, y, extX, extY, nWidthPix, nHeightPix)
    {
        var oleObject = new AscFormat.COleObject();
        AscFormat.fillImage(oleObject, rasterImageId, x, y, extX, extY);
        oleObject.setData(data);
        oleObject.setApplicationId(sApplicationId);
        oleObject.setPixSizes(nWidthPix, nHeightPix);
        return oleObject;
    },

    createTextArt: function(nStyle, bWord, wsModel, sStartString)
    {
        var MainLogicDocument = (editor && editor.WordControl && editor.WordControl.m_oLogicDocument ? editor && editor.WordControl && editor.WordControl.m_oLogicDocument : null);
        var TrackRevisions = (MainLogicDocument ? MainLogicDocument.Is_TrackRevisions() : false);

        if (MainLogicDocument && true === TrackRevisions)
            MainLogicDocument.Set_TrackRevisions(false);

        var oShape = new AscFormat.CShape();
        oShape.setWordShape(bWord === true);
        oShape.setBDeleted(false);
        if(wsModel)
            oShape.setWorksheet(wsModel);
        var nFontSize;
        if(bWord)
        {
            nFontSize = 36;
            oShape.createTextBoxContent();
        }
        else
        {
            nFontSize = 54;
            oShape.createTextBody();
        }
        var bUseStartString = (typeof sStartString === "string");
		if(bUseStartString)
		{
			nFontSize = undefined;
		}
        var oSpPr = new AscFormat.CSpPr();
        var oXfrm = new AscFormat.CXfrm();
        oXfrm.setOffX(0);
        oXfrm.setOffY(0);
        oXfrm.setExtX(1828800/36000);
        oXfrm.setExtY(1828800/36000);
        oSpPr.setXfrm(oXfrm);
        oXfrm.setParent(oSpPr);
        oSpPr.setFill(AscFormat.CreateNoFillUniFill());
        oSpPr.setLn(AscFormat.CreateNoFillLine());
        oSpPr.setGeometry(AscFormat.CreateGeometry("rect"));
        oShape.setSpPr(oSpPr);
        oSpPr.setParent(oShape);
        var oContent = oShape.getDocContent();
        var sText, oSelectedContent, oNearestPos, sSelectedText;
        if(this.document)
        {
            sSelectedText = this.document.GetSelectedText(false, {});
            oSelectedContent = this.document.GetSelectedContent(true);
            oContent.Recalculate_Page(0, true);
            oContent.MoveCursorToStartPos(false);
            oNearestPos = oContent.Get_NearestPos(0, 0, 0, false, undefined);
            oNearestPos.Paragraph.Check_NearestPos( oNearestPos );
            if(typeof sSelectedText === "string" && sSelectedText.length > 0)
            {
                if(oSelectedContent && this.document.Can_InsertContent(oSelectedContent, oNearestPos))
                {
                    oSelectedContent.MoveDrawing = true;
                    if(oSelectedContent.Elements.length > 1 && oSelectedContent.Elements[oSelectedContent.Elements.length - 1].Element.GetType() === AscCommonWord.type_Paragraph
                    && oSelectedContent.Elements[oSelectedContent.Elements.length - 1].Element.IsEmpty()){
                        oSelectedContent.Elements.splice(oSelectedContent.Elements.length - 1, 1);
                    }
                    if(oSelectedContent.Elements.length > 0){
                        oSelectedContent.Elements[oSelectedContent.Elements.length - 1].SelectedAll = false;
                    }
                    oContent.Insert_Content(oSelectedContent, oNearestPos);
                    oContent.Selection.Start    = false;
                    oContent.Selection.Use      = false;
                    oContent.Selection.StartPos = 0;
                    oContent.Selection.EndPos   = 0;
                    oContent.Selection.Flag     = selectionflag_Common;
                    oContent.Set_DocPosType(docpostype_Content);
                    oContent.CurPos.ContentPos = 0;
                    oShape.bSelectedText = true;
                }
                else
                {
                    sText = this.getDefaultText();
                    AscFormat.AddToContentFromString(oContent, sText);
                    oShape.bSelectedText = false;
                }
            }
            else
            {
                sText = this.getDefaultText();
                AscFormat.AddToContentFromString(oContent, sText);
                oShape.bSelectedText = false;
            }
        }
        else if(this.drawingObjects.cSld)
        {
            oShape.setParent(this.drawingObjects);
            var oTargetDocContent = this.getTargetDocContent();
            if(oTargetDocContent && oTargetDocContent.Selection.Use && oTargetDocContent.GetSelectedText(false, {}).length > 0)
            {
                oSelectedContent = new CSelectedContent();
                oTargetDocContent.GetSelectedContent(oSelectedContent);
                oSelectedContent.MoveDrawing = true;
                if(oSelectedContent.Elements.length > 1 && oSelectedContent.Elements[oSelectedContent.Elements.length - 1].Element.GetType() === AscCommonWord.type_Paragraph
                    && oSelectedContent.Elements[oSelectedContent.Elements.length - 1].Element.IsEmpty()){
                    oSelectedContent.Elements.splice(oSelectedContent.Elements.length - 1, 1);
                }
                if(oSelectedContent.Elements.length > 0){
                    oSelectedContent.Elements[oSelectedContent.Elements.length - 1].SelectedAll = false;
                }

                oContent.Recalculate_Page(0, true);
                oContent.MoveCursorToStartPos(false);
                var paragraph = oContent.Content[oContent.CurPos.ContentPos];
                if (null != paragraph && type_Paragraph == paragraph.GetType())
                {
                    oNearestPos = { Paragraph: paragraph, ContentPos: paragraph.Get_ParaContentPos(false, false) };
                    paragraph.Check_NearestPos(oNearestPos);
                    oContent.Insert_Content(oSelectedContent, oNearestPos);
                    oShape.bSelectedText = false;
                }
                else
                {
                    sText = this.getDefaultText();
                    AscFormat.AddToContentFromString(oContent, sText);
                    oShape.bSelectedText = false;
                }
            }
            else
            {
                oShape.bSelectedText = false;
                sText = bUseStartString ? sStartString : this.getDefaultText();
                AscFormat.AddToContentFromString(oContent, sText);
            }
        }
        else
        {
            sText = bUseStartString ? sStartString : this.getDefaultText();
            AscFormat.AddToContentFromString(oContent, sText);
        }
        var oTextPr;
        if(!bUseStartString)
        {
            oTextPr = oShape.getTextArtPreviewManager().getStylesToApply()[nStyle].Copy();
            oTextPr.FontSize = nFontSize;
            oTextPr.RFonts.Ascii = undefined;
            if(!((typeof CGraphicObjects !== "undefined") && (this instanceof CGraphicObjects)))
            {
                oTextPr.Unifill = oTextPr.TextFill;
                oTextPr.TextFill = undefined;
            }
        }
        else
        {
            oTextPr = new CTextPr();
            oTextPr.FontSize = nFontSize;
            oTextPr.RFonts.Ascii = {Name: "Cambria Math", Index: -1};
            oTextPr.RFonts.HAnsi = {Name: "Cambria Math", Index: -1};
            oTextPr.RFonts.CS = {Name: "Cambria Math", Index: -1};
            oTextPr.RFonts.EastAsia = {Name: "Cambria Math", Index: -1};
        }
        oContent.Set_ApplyToAll(true);
        oContent.AddToParagraph(new ParaTextPr(oTextPr));
        oContent.SetParagraphAlign(AscCommon.align_Center);
        oContent.Set_ApplyToAll(false);
        var oBodyPr = oShape.getBodyPr().createDuplicate();
        oBodyPr.rot = 0;
        oBodyPr.spcFirstLastPara = false;
        oBodyPr.vertOverflow = AscFormat.nOTOwerflow;
        oBodyPr.horzOverflow = AscFormat.nOTOwerflow;
        oBodyPr.vert = AscFormat.nVertTThorz;
        oBodyPr.wrap = AscFormat.nTWTNone;
        oBodyPr.lIns = 2.54;
        oBodyPr.tIns = 1.27;
        oBodyPr.rIns = 2.54;
        oBodyPr.bIns = 1.27;
        oBodyPr.numCol = 1;
        oBodyPr.spcCol = 0;
        oBodyPr.rtlCol = 0;
        oBodyPr.fromWordArt = false;
        oBodyPr.anchor = 4;
        oBodyPr.anchorCtr = false;
        oBodyPr.forceAA = false;
        oBodyPr.compatLnSpc = true;
        oBodyPr.prstTxWarp = AscFormat.ExecuteNoHistory(function(){return AscFormat.CreatePrstTxWarpGeometry("textNoShape");}, this, []);
        oBodyPr.textFit = new AscFormat.CTextFit();
        oBodyPr.textFit.type = AscFormat.text_fit_Auto;
        if(bWord)
        {
            oShape.setBodyPr(oBodyPr);
        }
        else
        {
            oShape.txBody.setBodyPr(oBodyPr);
        }

        if (MainLogicDocument && true === TrackRevisions)
            MainLogicDocument.Set_TrackRevisions(true);

        return oShape;
    },

	GetSelectedText: function(bCleartText, oPr)
    {
        var content = this.getTargetDocContent();
        if(content)
        {
            return content.GetSelectedText(bCleartText, oPr);
        }
        else
        {
            return "";
        }
    },

    putPrLineSpacing: function(type, value)
    {
        this.checkSelectedObjectsAndCallback(this.setParagraphSpacing, [{ LineRule : type,  Line : value }], false, AscDFH.historydescription_Spreadsheet_PutPrLineSpacing);
        //TODO
    },


    putLineSpacingBeforeAfter: function(type, value)
    {
        var arg;
        switch (type)
        {
            case 0:
            {
                if ( spacing_Auto === value )
                    arg = { BeforeAutoSpacing : true };
                else
                    arg = { Before : value, BeforeAutoSpacing : false };

                break;
            }
            case 1:
            {
                if ( spacing_Auto === value )
                    arg = { AfterAutoSpacing : true };
                else
                    arg = { After : value, AfterAutoSpacing : false };

                break;
            }
        }
        if(arg)
        {
            this.checkSelectedObjectsAndCallback(this.setParagraphSpacing, [arg], false, AscDFH.historydescription_Spreadsheet_SetParagraphSpacing);
        }
    },


    setGraphicObjectProps: function(props)
    {
        if(typeof Asc.asc_CParagraphProperty !== "undefined" && !(props instanceof Asc.asc_CParagraphProperty))
        {
            if(props && props.ChartProperties && typeof props.ChartProperties.range === "string")
            {
                var editor = window["Asc"]["editor"];
                var check = parserHelp.checkDataRange(editor.wbModel, editor.wb, Asc.c_oAscSelectionDialogType.Chart, props.ChartProperties.range, true, !props.ChartProperties.inColumns, props.ChartProperties.type);
                if(check === c_oAscError.ID.StockChartError || check === c_oAscError.ID.DataRangeError
                    || check === c_oAscError.ID.MaxDataSeriesError)
                {
                    editor.wbModel.handlers.trigger("asc_onError", check, c_oAscError.Level.NoCritical);
                    this.drawingObjects.sendGraphicObjectProps();
                    return;
                }
            }

            var aAdditionalObjects = null;
            if(AscFormat.isRealNumber(props.Width) && AscFormat.isRealNumber(props.Height)){
                aAdditionalObjects = this.getConnectorsForCheck2();
            }

            this.checkSelectedObjectsAndCallback(this.setGraphicObjectPropsCallBack, [props], false, AscDFH.historydescription_Spreadsheet_SetGraphicObjectsProps, aAdditionalObjects);
            var oApplyProps = null;
            if(props)
            {
                if(props.ShapeProperties)
                {
                    oApplyProps = props.ShapeProperties;
                }
                else
                {
                    oApplyProps = props;
                }
            }
            if(oApplyProps &&  (oApplyProps.textArtProperties && typeof oApplyProps.textArtProperties.asc_getForm() === "string"  || oApplyProps.ChartProperties))
            {
                this.updateSelectionState();
            }
        }
        else
        {
            this.checkSelectedObjectsAndCallback(this.paraApplyCallback, [props], false, AscDFH.historydescription_Spreadsheet_ParaApply);
        }
    },

    checkSelectedObjectsAndCallback: function(callback, args, bNoSendProps, nHistoryPointType, aAdditionalObjects, bNoCheckLock)
    {
        var oApi = Asc.editor;
        if(oApi && oApi.collaborativeEditing && oApi.collaborativeEditing.getGlobalLock()){
            return;
        }
        var selection_state = this.getSelectionState();
        if(!(bNoCheckLock === true))
        {
            this.drawingObjects.objectLocker.reset();
            for(var i = 0; i < this.selectedObjects.length; ++i)
            {
                this.drawingObjects.objectLocker.addObjectId(this.selectedObjects[i].Get_Id());
            }
            if(aAdditionalObjects){
                for(var i = 0; i < aAdditionalObjects.length; ++i){
                    this.drawingObjects.objectLocker.addObjectId(aAdditionalObjects[i].Get_Id());
                }
            }
        }
        var _this = this;
        var callback2 = function(bLock, bSync)
        {
            if(bLock)
            {
                var nPointType = AscFormat.isRealNumber(nHistoryPointType) ? nHistoryPointType : AscDFH.historydescription_CommonControllerCheckSelected;
                History.Create_NewPoint(nPointType);
                if(bSync !== true)
                {
                    _this.setSelectionState(selection_state);
                    for(var i = 0; i < _this.selectedObjects.length; ++i)
                    {
                        _this.selectedObjects[i].lockType = c_oAscLockTypes.kLockTypeMine;
                    }
                    if(aAdditionalObjects){
                        for(var i = 0; i < aAdditionalObjects.length; ++i){
                            aAdditionalObjects[i].lockType = c_oAscLockTypes.kLockTypeMine;
                        }
                    }
                }
                callback.apply(_this, args);
                _this.startRecalculate();
                if(!(bNoSendProps === true))
                {
                    _this.drawingObjects.sendGraphicObjectProps();
                }
            }
        };
        if(!(bNoCheckLock === true))
        {
            return this.drawingObjects.objectLocker.checkObjects(callback2);
        }
        callback2(true, true);
        return true;
    },

    checkSelectedObjectsAndCallbackNoCheckLock: function(callback, args, bNoSendProps, nHistoryPointType)
    {
        var nPointType = AscFormat.isRealNumber(nHistoryPointType) ? nHistoryPointType : AscDFH.historydescription_CommonControllerCheckSelected;
        History.Create_NewPoint(nPointType);

        callback.apply(this, args);
        this.startRecalculate();
        if(!(bNoSendProps === true))
        {
            this.drawingObjects.sendGraphicObjectProps();
        }
    },

    checkSelectedObjectsAndCallback2: function(callback)
    {
        var selection_state = this.getSelectionState();
        this.drawingObjects.objectLocker.reset();
        for(var i = 0; i < this.selectedObjects.length; ++i)
        {
            this.drawingObjects.objectLocker.addObjectId(this.selectedObjects[i].Get_Id());
        }
        var _this = this;
        var callback2 = function(bLock)
        {
            if(bLock)
            {
                History.Create_NewPoint();
            }
            callback.apply(_this, [bLock]);
            if(bLock)
            {
                _this.startRecalculate();
                _this.drawingObjects.sendGraphicObjectProps();
            }

        };
        return this.drawingObjects.objectLocker.checkObjects(callback2);
    },

    setGraphicObjectPropsCallBack: function(props)
    {
        var apply_props;
        if(AscFormat.isRealNumber(props.Width) && AscFormat.isRealNumber(props.Height))
        {
            apply_props = props;
        }
        else
        {
            apply_props = props.ShapeProperties ? props.ShapeProperties : props;
        }
        var objects_by_types = this.applyDrawingProps(apply_props);
    },

    paraApplyCallback: function(Props)
    {
            if ( "undefined" != typeof(Props.ContextualSpacing) && null != Props.ContextualSpacing )
                this.setParagraphContextualSpacing( Props.ContextualSpacing );

            if ( "undefined" != typeof(Props.Ind) && null != Props.Ind )
                this.setParagraphIndent( Props.Ind );

            if ( "undefined" != typeof(Props.Jc) && null != Props.Jc )
                this.setParagraphAlign( Props.Jc );

            if ( "undefined" != typeof(Props.KeepLines) && null != Props.KeepLines )
                this.setParagraphKeepLines( Props.KeepLines );

            if ( undefined != Props.KeepNext && null != Props.KeepNext )
                this.setParagraphKeepNext( Props.KeepNext );

            if ( undefined != Props.WidowControl && null != Props.WidowControl )
                this.setParagraphWidowControl( Props.WidowControl );

            if ( "undefined" != typeof(Props.PageBreakBefore) && null != Props.PageBreakBefore )
                this.setParagraphPageBreakBefore( Props.PageBreakBefore );

            if ( "undefined" != typeof(Props.Spacing) && null != Props.Spacing )
                this.setParagraphSpacing( Props.Spacing );

            if ( "undefined" != typeof(Props.Shd) && null != Props.Shd )
                this.setParagraphShd( Props.Shd );

            if ( "undefined" != typeof(Props.Brd) && null != Props.Brd )
            {
                if(Props.Brd.Left && Props.Brd.Left.Color)
                {
                    Props.Brd.Left.Unifill = AscFormat.CreateUnifillFromAscColor(Props.Brd.Left.Color, 1);
                }
                if(Props.Brd.Top && Props.Brd.Top.Color)
                {
                    Props.Brd.Top.Unifill = AscFormat.CreateUnifillFromAscColor(Props.Brd.Top.Color, 1);
                }
                if(Props.Brd.Right && Props.Brd.Right.Color)
                {
                    Props.Brd.Right.Unifill = AscFormat.CreateUnifillFromAscColor(Props.Brd.Right.Color, 1);
                }
                if(Props.Brd.Bottom && Props.Brd.Bottom.Color)
                {
                    Props.Brd.Bottom.Unifill = AscFormat.CreateUnifillFromAscColor(Props.Brd.Bottom.Color, 1);
                }
                if(Props.Brd.InsideH && Props.Brd.InsideH.Color)
                {
                    Props.Brd.InsideH.Unifill = AscFormat.CreateUnifillFromAscColor(Props.Brd.InsideH.Color, 1);
                }
                if(Props.Brd.InsideV && Props.Brd.InsideV.Color)
                {
                    Props.Brd.InsideV.Unifill = AscFormat.CreateUnifillFromAscColor(Props.Brd.InsideV.Color, 1);
                }

                this.setParagraphBorders( Props.Brd );
            }

            if ( undefined != Props.Tabs )
            {
                var Tabs = new CParaTabs();
                Tabs.Set_FromObject( Props.Tabs.Tabs );
                this.setParagraphTabs( Tabs );
            }

            if ( undefined != Props.DefaultTab )
            {
                //AscCommonWord.Default_Tab_Stop = Props.DefaultTab;
                this.setDefaultTabSize( Props.DefaultTab );
            }


            // TODO: как только разъединят настройки параграфа и текста переделать тут
            var TextPr = new CTextPr();

            if ( true === Props.Subscript )
                TextPr.VertAlign = AscCommon.vertalign_SubScript;
            else if ( true === Props.Superscript )
                TextPr.VertAlign = AscCommon.vertalign_SuperScript;
            else if ( false === Props.Superscript || false === Props.Subscript )
                TextPr.VertAlign = AscCommon.vertalign_Baseline;

            if ( undefined != Props.Strikeout )
            {
                TextPr.Strikeout  = Props.Strikeout;
                TextPr.DStrikeout = false;
            }

            if ( undefined != Props.DStrikeout )
            {
                TextPr.DStrikeout = Props.DStrikeout;
                if ( true === TextPr.DStrikeout )
                    TextPr.Strikeout = false;
            }

            if ( undefined != Props.SmallCaps )
            {
                TextPr.SmallCaps = Props.SmallCaps;
                TextPr.AllCaps   = false;
            }

            if ( undefined != Props.AllCaps )
            {
                TextPr.Caps = Props.AllCaps;
                if ( true === TextPr.AllCaps )
                    TextPr.SmallCaps = false;
            }

            if ( undefined != Props.TextSpacing )
                TextPr.Spacing = Props.TextSpacing;

            if ( undefined != Props.Position )
                TextPr.Position = Props.Position;

            this.paragraphAdd( new ParaTextPr(TextPr) );
        this.startRecalculate();
    },

    // layers
    setGraphicObjectLayer: function(layerType)
    {
        if(this.selection.groupSelection)
        {
            this.checkSelectedObjectsAndCallback(this.setGraphicObjectLayerCallBack, [layerType], false, AscDFH.historydescription_Spreadsheet_GraphicObjectLayer);
        }
        else
        {
            this.checkSelectedObjectsAndCallback(this.setGraphicObjectLayerCallBack, [layerType], false, AscDFH.historydescription_Spreadsheet_GraphicObjectLayer);
        }
       // this.checkSelectedObjectsAndCallback(this.setGraphicObjectLayerCallBack, [layerType]);
        //oAscDrawingLayerType
    },

    setGraphicObjectAlign: function(alignType)
    {
        this.checkSelectedObjectsAndCallback(this.setGraphicObjectAlignCallBack, [alignType], false, AscDFH.historydescription_Spreadsheet_GraphicObjectLayer);
    },

    setGraphicObjectLayerCallBack: function(layerType)
    {
        switch (layerType)
        {
            case 0:
            {
                this.bringToFront();
                break;
            }
            case 1:
            {
                this.sendToBack();
                break;
            }
            case 2:
            {
                this.bringForward();
                break;
            }
            case 3:
            {
                this.bringBackward();
            }
        }
    },

    setGraphicObjectAlignCallBack: function(alignType)
    {
        switch (alignType)
        {
            case 0:
            {
                this.alignLeft(true);
                break;
            }
            case 1:
            {
                this.alignRight(true);
                break;
            }
            case 2:
            {
                this.alignBottom(true);
                break;
            }
            case 3:
            {
                this.alignTop(true);
                break;
            }
            case 4:
            {
                this.alignCenter(true);
                break;
            }
            case 5:
            {
                this.alignMiddle(true);
                break;
            }
        }
    },


    alignLeft : function(bSelected)
    {
        var selected_objects = this.selection.groupSelection ? this.selection.groupSelection.selectedObjects : this.selectedObjects, i, boundsObject, leftPos, arrBounds;
        if(selected_objects.length > 0)
        {
            boundsObject = getAbsoluteRectBoundsArr(selected_objects);
            arrBounds = boundsObject.arrBounds;
            if(bSelected && selected_objects.length > 1 )
            {
                leftPos = boundsObject.minX;
            }
            else
            {
                leftPos = 0;
            }
            this.checkSelectedObjectsForMove(this.selection.groupSelection ? this.selection.groupSelection : null);
            this.swapTrackObjects();
            var move_state;
            if(!this.selection.groupSelection)
                move_state = new AscFormat.MoveState(this, this.selectedObjects[0], 0, 0);
            else
                move_state = new AscFormat.MoveInGroupState(this, this.selection.groupSelection.selectedObjects[0], this.selection.groupSelection, 0, 0);

            for(i = 0; i < this.arrTrackObjects.length; ++i)
                this.arrTrackObjects[i].track(leftPos - arrBounds[i].minX, 0, this.arrTrackObjects[i].originalObject.selectStartPage);
            move_state.onMouseUp({}, 0, 0, 0);
        }
    },

    alignRight : function(bSelected)
    {
        var selected_objects = this.selection.groupSelection ? this.selection.groupSelection.selectedObjects : this.selectedObjects, i, boundsObject, rightPos, arrBounds;
        if(selected_objects.length > 0)
        {
            boundsObject = getAbsoluteRectBoundsArr(selected_objects);
            arrBounds = boundsObject.arrBounds;
            if(bSelected && selected_objects.length > 1 )
            {
                rightPos = boundsObject.maxX;
            }
            else
            {
                rightPos = this.drawingObjects.Width;
            }
            this.checkSelectedObjectsForMove(this.selection.groupSelection ? this.selection.groupSelection : null);
            this.swapTrackObjects();
            var move_state;
            if(!this.selection.groupSelection)
                move_state = new AscFormat.MoveState(this, this.selectedObjects[0], 0, 0);
            else
                move_state = new AscFormat.MoveInGroupState(this, this.selection.groupSelection.selectedObjects[0], this.selection.groupSelection, 0, 0);

            for(i = 0; i < this.arrTrackObjects.length; ++i)
                this.arrTrackObjects[i].track(rightPos - arrBounds[i].maxX, 0, this.arrTrackObjects[i].originalObject.selectStartPage);
            move_state.onMouseUp({}, 0, 0, 0);
        }
    },


    alignTop : function(bSelected)
    {
        var selected_objects = this.selection.groupSelection ? this.selection.groupSelection.selectedObjects : this.selectedObjects, i, boundsObject, topPos, arrBounds;
        if(selected_objects.length > 0)
        {
            boundsObject = getAbsoluteRectBoundsArr(selected_objects);
            arrBounds = boundsObject.arrBounds;
            if(bSelected && selected_objects.length > 1 )
            {
                topPos = boundsObject.minY;
            }
            else
            {
                topPos = 0;
            }
            this.checkSelectedObjectsForMove(this.selection.groupSelection ? this.selection.groupSelection : null);
            this.swapTrackObjects();
            var move_state;
            if(!this.selection.groupSelection)
                move_state = new AscFormat.MoveState(this, this.selectedObjects[0], 0, 0);
            else
                move_state = new AscFormat.MoveInGroupState(this, this.selection.groupSelection.selectedObjects[0], this.selection.groupSelection, 0, 0);

            for(i = 0; i < this.arrTrackObjects.length; ++i)
                this.arrTrackObjects[i].track(0, topPos - arrBounds[i].minY, this.arrTrackObjects[i].originalObject.selectStartPage);
            move_state.onMouseUp({}, 0, 0, 0);
        }
    },


    alignBottom : function(bSelected)
    {
        var selected_objects = this.selection.groupSelection ? this.selection.groupSelection.selectedObjects : this.selectedObjects, i, boundsObject, bottomPos, arrBounds;
        if(selected_objects.length > 0)
        {
            boundsObject = getAbsoluteRectBoundsArr(selected_objects);
            arrBounds = boundsObject.arrBounds;
            if(bSelected && selected_objects.length > 1 )
            {
                bottomPos = boundsObject.maxY;
            }
            else
            {
                bottomPos = this.drawingObjects.Height;
            }
            this.checkSelectedObjectsForMove(this.selection.groupSelection ? this.selection.groupSelection : null);
            this.swapTrackObjects();
            var move_state;
            if(!this.selection.groupSelection)
                move_state = new AscFormat.MoveState(this, this.selectedObjects[0], 0, 0);
            else
                move_state = new AscFormat.MoveInGroupState(this, this.selection.groupSelection.selectedObjects[0], this.selection.groupSelection, 0, 0);

            for(i = 0; i < this.arrTrackObjects.length; ++i)
                this.arrTrackObjects[i].track(0, bottomPos - arrBounds[i].maxY, this.arrTrackObjects[i].originalObject.selectStartPage);
            move_state.onMouseUp({}, 0, 0, 0);
        }
    },


    alignCenter : function(bSelected)
    {
        var selected_objects = this.selection.groupSelection ? this.selection.groupSelection.selectedObjects : this.selectedObjects, i, boundsObject, centerPos, arrBounds;
        if(selected_objects.length > 0)
        {
            boundsObject = getAbsoluteRectBoundsArr(selected_objects);
            arrBounds = boundsObject.arrBounds;
            if(bSelected && selected_objects.length > 1 )
            {
                centerPos = boundsObject.minX +(boundsObject.maxX - boundsObject.minX)/2;
            }
            else
            {
                centerPos = this.drawingObjects.Width/2;
            }
            this.checkSelectedObjectsForMove(this.selection.groupSelection ? this.selection.groupSelection : null);
            this.swapTrackObjects();
            var move_state;
            if(!this.selection.groupSelection)
                move_state = new AscFormat.MoveState(this, this.selectedObjects[0], 0, 0);
            else
                move_state = new AscFormat.MoveInGroupState(this, this.selection.groupSelection.selectedObjects[0], this.selection.groupSelection, 0, 0);

            for(i = 0; i < this.arrTrackObjects.length; ++i)
                this.arrTrackObjects[i].track(centerPos - (arrBounds[i].maxX - arrBounds[i].minX)/2 - arrBounds[i].minX, 0, this.arrTrackObjects[i].originalObject.selectStartPage);
            move_state.onMouseUp({}, 0, 0, 0);
        }
    },

    alignMiddle : function(bSelected)
    {
        var selected_objects = this.selection.groupSelection ? this.selection.groupSelection.selectedObjects : this.selectedObjects, i, boundsObject, middlePos, arrBounds;
        if(selected_objects.length > 0)
        {
            boundsObject = getAbsoluteRectBoundsArr(selected_objects);
            arrBounds = boundsObject.arrBounds;
            if(bSelected && selected_objects.length > 1 )
            {
                middlePos = boundsObject.minY +(boundsObject.maxY - boundsObject.minY)/2;
            }
            else
            {
                middlePos = this.drawingObjects.Height/2;
            }
            this.checkSelectedObjectsForMove(this.selection.groupSelection ? this.selection.groupSelection : null);
            this.swapTrackObjects();
            var move_state;
            if(!this.selection.groupSelection)
                move_state = new AscFormat.MoveState(this, this.selectedObjects[0], 0, 0);
            else
                move_state = new AscFormat.MoveInGroupState(this, this.selection.groupSelection.selectedObjects[0], this.selection.groupSelection, 0, 0);

            for(i = 0; i < this.arrTrackObjects.length; ++i)
                this.arrTrackObjects[i].track(0, middlePos - (arrBounds[i].maxY - arrBounds[i].minY)/2 - arrBounds[i].minY, this.arrTrackObjects[i].originalObject.selectStartPage);
            move_state.onMouseUp({}, 0, 0, 0);
        }
    },

    distributeHor : function(bSelected)
    {
        var selected_objects = this.selection.groupSelection ? this.selection.groupSelection.selectedObjects : this.selectedObjects, i, boundsObject, arrBounds, pos1, pos2, gap, sortObjects, lastPos;
        if(selected_objects.length > 0)
        {
            boundsObject = getAbsoluteRectBoundsArr(selected_objects);
            arrBounds = boundsObject.arrBounds;
            this.checkSelectedObjectsForMove(this.selection.groupSelection ? this.selection.groupSelection : null);
            this.swapTrackObjects();
            sortObjects = [];
            for(i = 0; i < selected_objects.length; ++i)
            {
                sortObjects.push({trackObject: this.arrTrackObjects[i], boundsObject: arrBounds[i]});
            }
            sortObjects.sort(function(obj1, obj2){return (obj1.boundsObject.maxX + obj1.boundsObject.minX)/2 - (obj2.boundsObject.maxX + obj2.boundsObject.minX)/2});
            if(bSelected && selected_objects.length > 2)
            {
                pos1 =  boundsObject.minX;
                pos2 = boundsObject.maxX;
                sortObjects.splice(0, 1)[0].trackObject.track(0, 0, 0);
                sortObjects.splice(sortObjects.length-1, 1)[0].trackObject.track(0, 0, 0);
            }
            else
            {
                pos1 = 0;
                pos2 = this.drawingObjects.Width;
            }
            var summ_width = 0;
            for(i = 0; i < sortObjects.length; ++i)
            {
                summ_width += (sortObjects[i].boundsObject.maxX - sortObjects[i].boundsObject.minX);
            }
            gap = (pos2 - pos1 - summ_width)/(sortObjects.length+1);
            var move_state;
            if(!this.selection.groupSelection)
                move_state = new AscFormat.MoveState(this, this.selectedObjects[0], 0, 0);
            else
                move_state = new AscFormat.MoveInGroupState(this, this.selection.groupSelection.selectedObjects[0], this.selection.groupSelection, 0, 0);

            lastPos = pos1;
            for(i = 0; i < sortObjects.length; ++i)
            {
                sortObjects[i].trackObject.track(lastPos + gap - sortObjects[i].boundsObject.minX, 0, this.arrTrackObjects[i].originalObject.selectStartPage);
                lastPos += (gap + sortObjects[i].boundsObject.maxX - sortObjects[i].boundsObject.minX);
            }
            move_state.onMouseUp({}, 0, 0, 0);
        }
    },
    distributeVer : function(bSelected)
    {
        var selected_objects = this.selection.groupSelection ? this.selection.groupSelection.selectedObjects : this.selectedObjects, i, boundsObject, arrBounds, pos1, pos2, gap, sortObjects, lastPos;
        if(selected_objects.length > 0)
        {
            boundsObject = getAbsoluteRectBoundsArr(selected_objects);
            arrBounds = boundsObject.arrBounds;
            this.checkSelectedObjectsForMove(this.selection.groupSelection ? this.selection.groupSelection : null);
            this.swapTrackObjects();
            sortObjects = [];
            for(i = 0; i < selected_objects.length; ++i)
            {
                sortObjects.push({trackObject: this.arrTrackObjects[i], boundsObject: arrBounds[i]});
            }
            sortObjects.sort(function(obj1, obj2){return (obj1.boundsObject.maxY + obj1.boundsObject.minY)/2 - (obj2.boundsObject.maxY + obj2.boundsObject.minY)/2});
            if(bSelected && selected_objects.length > 2)
            {
                pos1 =  boundsObject.minY;
                pos2 = boundsObject.maxY;
                sortObjects.splice(0, 1)[0].trackObject.track(0, 0, 0);
                sortObjects.splice(sortObjects.length-1, 1)[0].trackObject.track(0, 0, 0);
            }
            else
            {
                pos1 = 0;
                pos2 = this.drawingObjects.Height;
            }
            var summ_heigth = 0;
            for(i = 0; i < sortObjects.length; ++i)
            {
                summ_heigth += (sortObjects[i].boundsObject.maxY - sortObjects[i].boundsObject.minY);
            }
            gap = (pos2 - pos1 - summ_heigth)/(sortObjects.length+1);
            var move_state;
            if(!this.selection.groupSelection)
                move_state = new AscFormat.MoveState(this, this.selectedObjects[0], 0, 0);
            else
                move_state = new AscFormat.MoveInGroupState(this, this.selection.groupSelection.selectedObjects[0], this.selection.groupSelection, 0, 0);

            lastPos = pos1;
            for(i = 0; i < sortObjects.length; ++i)
            {
                sortObjects[i].trackObject.track(0, lastPos + gap - sortObjects[i].boundsObject.minY, this.arrTrackObjects[i].originalObject.selectStartPage);
                lastPos += (gap + sortObjects[i].boundsObject.maxY - sortObjects[i].boundsObject.minY);
            }
            move_state.onMouseUp({}, 0, 0, 0);
        }
    },


    bringToFront : function()
    {
        var sp_tree = this.getDrawingObjects();
        if(!(this.selection.groupSelection))
        {
            var selected = [];
            for(var i = 0; i < sp_tree.length; ++i)
            {
                if(sp_tree[i].selected)
                {
                    selected.push(sp_tree[i]);
                }
            }
            for(var i = sp_tree.length-1; i > -1 ; --i)
            {
                if(sp_tree[i].selected)
                {
                    sp_tree[i].deleteDrawingBase();
                }
            }
            for(i = 0; i < selected.length; ++i)
            {
                selected[i].addToDrawingObjects(sp_tree.length);
            }
        }
        else
        {
            this.selection.groupSelection.bringToFront();
        }
        this.drawingObjects.showDrawingObjects(true);
    },

    bringForward : function()
    {
        var sp_tree = this.getDrawingObjects();
        if(!(this.selection.groupSelection))
        {
            for(var i = sp_tree.length - 1;i > -1; --i)
            {
                var sp = sp_tree[i];
                if(sp.selected && i < sp_tree.length - 1 && !sp_tree[i+1].selected)
                {
                    sp.deleteDrawingBase();
                    sp.addToDrawingObjects(i+1);
                }
            }
        }
        else
        {
            this.selection.groupSelection.bringForward();
        }
        this.drawingObjects.showDrawingObjects(true);
    },

    sendToBack : function()
    {
        var sp_tree = this.getDrawingObjects();

        if(!(this.selection.groupSelection))
        {
            var  j = 0;
            for(var i = 0; i < sp_tree.length; ++i)
            {
                if(sp_tree[i].selected)
                {
                    var object = sp_tree[i];
                    object.deleteDrawingBase();
                    object.addToDrawingObjects(j);
                    ++j;
                }
            }
        }
        else
        {
            this.selection.groupSelection.sendToBack();
        }
        this.drawingObjects.showDrawingObjects(true);
    },


    bringBackward : function()
    {
        var sp_tree = this.getDrawingObjects();
        if(!(this.selection.groupSelection))
        {
            for(var i = 0;i < sp_tree.length; ++i)
            {
                var sp = sp_tree[i];
                if(sp.selected && i > 0 && !sp_tree[i-1].selected)
                {
                    sp.deleteDrawingBase();
                    sp.addToDrawingObjects(i-1);
                }
            }
        }
        else
        {
            this.selection.groupSelection.bringBackward();
        }
        this.drawingObjects.showDrawingObjects(true);
    }
};



function CBoundsController()
{
    this.min_x = 0xFFFF;
    this.min_y = 0xFFFF;
    this.max_x = -0xFFFF;
    this.max_y = -0xFFFF;

    this.Rects = [];
}

CBoundsController.prototype =
{
    ClearNoAttack : function()
    {
        this.min_x = 0xFFFF;
        this.min_y = 0xFFFF;
        this.max_x = -0xFFFF;
        this.max_y = -0xFFFF;

        if (0 != this.Rects.length)
            this.Rects.splice(0, this.Rects.length);
    },

    CheckPageRects : function(rects, ctx)
    {
        var _bIsUpdate = false;
        if (rects.length != this.Rects.length)
        {
            _bIsUpdate = true;
        }
        else
        {
            for (var i = 0; i < rects.length; i++)
            {
                var _1 = this.Rects[i];
                var _2 = rects[i];

                if (_1.x != _2.x || _1.y != _2.y || _1.w != _2.w || _1.h != _2.h)
                    _bIsUpdate = true;
            }
        }

        if (!_bIsUpdate)
            return;

        this.Clear(ctx);

        if (0 != this.Rects.length)
            this.Rects.splice(0, this.Rects.length);

        for (var i = 0; i < rects.length; i++)
        {
            var _r = rects[i];
            this.CheckRect(_r.x, _r.y, _r.w, _r.h);
            this.Rects.push(_r);
        }
    },

    Clear : function(ctx)
    {
        if (this.max_x != -0xFFFF && this.max_y != -0xFFFF)
        {
            ctx.fillRect(this.min_x - 5, this.min_y - 5, this.max_x - this.min_x + 10, this.max_y - this.min_y + 10);
        }
        this.min_x = 0xFFFF;
        this.min_y = 0xFFFF;
        this.max_x = -0xFFFF;
        this.max_y = -0xFFFF;
    },

    CheckPoint1 : function(x,y)
    {
        if (x < this.min_x)
            this.min_x = x;
        if (y < this.min_y)
            this.min_y = y;
    },
    CheckPoint2 : function(x,y)
    {
        if (x > this.max_x)
            this.max_x = x;
        if (y > this.max_y)
            this.max_y = y;
    },
    CheckPoint : function(x,y)
    {
        if (x < this.min_x)
            this.min_x = x;
        if (y < this.min_y)
            this.min_y = y;
        if (x > this.max_x)
            this.max_x = x;
        if (y > this.max_y)
            this.max_y = y;
    },
    CheckRect : function(x,y,w,h)
    {
        this.CheckPoint1(x,y);
        this.CheckPoint2(x + w,y + h);
    },

    fromBounds : function(_bounds)
    {
        this.min_x = _bounds.min_x;
        this.min_y = _bounds.min_y;
        this.max_x = _bounds.max_x;
        this.max_y = _bounds.max_y;
    }
};

function CSlideBoundsChecker()
{
    this.map_bounds_shape = {};
    this.map_bounds_shape["heart"] = true;

    this.IsSlideBoundsCheckerType = true;

    this.Bounds = new CBoundsController();

    this.m_oCurFont     = null;
    this.m_oTextPr      = null;

    this.m_oCoordTransform  = new AscCommon.CMatrixL();
    this.m_oTransform       = new AscCommon.CMatrixL();
    this.m_oFullTransform   = new AscCommon.CMatrixL();

    this.IsNoSupportTextDraw = true;

    this.LineWidth = null;
    this.AutoCheckLineWidth = false;
}

CSlideBoundsChecker.prototype =
{
    DrawLockParagraph: function()
    {},

    GetIntegerGrid: function()
    {
        return false;
    },

    AddSmartRect: function()
    {},

    drawCollaborativeChanges: function()
    {},

    drawSearchResult : function(x, y, w, h)
    {},

    IsShapeNeedBounds : function(preset)
    {
        if (preset === undefined || preset == null)
            return true;
        return (true === this.map_bounds_shape[preset]) ? false : true;
    },

    init : function(width_px, height_px, width_mm, height_mm)
    {
        this.m_lHeightPix   = height_px;
        this.m_lWidthPix    = width_px;
        this.m_dWidthMM     = width_mm;
        this.m_dHeightMM    = height_mm;
        this.m_dDpiX        = 25.4 * this.m_lWidthPix / this.m_dWidthMM;
        this.m_dDpiY        = 25.4 * this.m_lHeightPix / this.m_dHeightMM;

        this.m_oCoordTransform.sx   = this.m_dDpiX / 25.4;
        this.m_oCoordTransform.sy   = this.m_dDpiY / 25.4;

        this.Bounds.ClearNoAttack();
    },

    SetCurrentPage: function()
    {},

    EndDraw : function(){},
    put_GlobalAlpha : function(enable, alpha)
    {
    },
    Start_GlobalAlpha : function()
    {
    },
    End_GlobalAlpha : function()
    {
    },
    // pen methods
    p_color : function(r,g,b,a)
    {
    },
    p_width : function(w)
    {
    },
    p_dash : function(params)
    {
    },
    // brush methods
    b_color1 : function(r,g,b,a)
    {
    },
    b_color2 : function(r,g,b,a)
    {
    },

    SetIntegerGrid : function()
    {
    },

    transform : function(sx,shy,shx,sy,tx,ty)
    {
        this.m_oTransform.sx    = sx;
        this.m_oTransform.shx   = shx;
        this.m_oTransform.shy   = shy;
        this.m_oTransform.sy    = sy;
        this.m_oTransform.tx    = tx;
        this.m_oTransform.ty    = ty;

        this.CalculateFullTransform();
    },
    CalculateFullTransform : function()
    {
        this.m_oFullTransform.sx = this.m_oTransform.sx;
        this.m_oFullTransform.shx = this.m_oTransform.shx;
        this.m_oFullTransform.shy = this.m_oTransform.shy;
        this.m_oFullTransform.sy = this.m_oTransform.sy;
        this.m_oFullTransform.tx = this.m_oTransform.tx;
        this.m_oFullTransform.ty = this.m_oTransform.ty;
        AscCommon.global_MatrixTransformer.MultiplyAppend(this.m_oFullTransform, this.m_oCoordTransform);
    },
    // path commands
    _s : function()
    {
    },
    _e : function()
    {
    },
    _z : function()
    {
    },
    _m : function(x,y)
    {
        var _x = this.m_oFullTransform.TransformPointX(x,y);
        var _y = this.m_oFullTransform.TransformPointY(x,y);

        this.Bounds.CheckPoint(_x, _y);
    },
    _l : function(x,y)
    {
        var _x = this.m_oFullTransform.TransformPointX(x,y);
        var _y = this.m_oFullTransform.TransformPointY(x,y);

        this.Bounds.CheckPoint(_x, _y);
    },
    _c : function(x1,y1,x2,y2,x3,y3)
    {
        var _x1 = this.m_oFullTransform.TransformPointX(x1,y1);
        var _y1 = this.m_oFullTransform.TransformPointY(x1,y1);

        var _x2 = this.m_oFullTransform.TransformPointX(x2,y2);
        var _y2 = this.m_oFullTransform.TransformPointY(x2,y2);

        var _x3 = this.m_oFullTransform.TransformPointX(x3,y3);
        var _y3 = this.m_oFullTransform.TransformPointY(x3,y3);

        this.Bounds.CheckPoint(_x1, _y1);
        this.Bounds.CheckPoint(_x2, _y2);
        this.Bounds.CheckPoint(_x3, _y3);
    },
    _c2 : function(x1,y1,x2,y2)
    {
        var _x1 = this.m_oFullTransform.TransformPointX(x1,y1);
        var _y1 = this.m_oFullTransform.TransformPointY(x1,y1);

        var _x2 = this.m_oFullTransform.TransformPointX(x2,y2);
        var _y2 = this.m_oFullTransform.TransformPointY(x2,y2);

        this.Bounds.CheckPoint(_x1, _y1);
        this.Bounds.CheckPoint(_x2, _y2);
    },
    ds : function()
    {
    },
    df : function()
    {
    },

    // canvas state
    save : function()
    {
    },
    restore : function()
    {
    },
    clip : function()
    {
    },

    reset : function()
    {
        this.m_oTransform.Reset();
        this.CalculateFullTransform();
    },

    transform3 : function(m)
    {
        this.m_oTransform = m.CreateDublicate();
        this.CalculateFullTransform();
    },

    transform00 : function(m)
    {
        this.m_oTransform = m.CreateDublicate();
        this.m_oTransform.tx = 0;
        this.m_oTransform.ty = 0;
        this.CalculateFullTransform();
    },

    // images
    drawImage2 : function(img,x,y,w,h)
    {
        var _x1 = this.m_oFullTransform.TransformPointX(x,y);
        var _y1 = this.m_oFullTransform.TransformPointY(x,y);

        var _x2 = this.m_oFullTransform.TransformPointX(x+w,y);
        var _y2 = this.m_oFullTransform.TransformPointY(x+w,y);

        var _x3 = this.m_oFullTransform.TransformPointX(x+w,y+h);
        var _y3 = this.m_oFullTransform.TransformPointY(x+w,y+h);

        var _x4 = this.m_oFullTransform.TransformPointX(x,y+h);
        var _y4 = this.m_oFullTransform.TransformPointY(x,y+h);

        this.Bounds.CheckPoint(_x1, _y1);
        this.Bounds.CheckPoint(_x2, _y2);
        this.Bounds.CheckPoint(_x3, _y3);
        this.Bounds.CheckPoint(_x4, _y4);
    },
    drawImage : function(img,x,y,w,h)
    {
        return this.drawImage2(img, x, y, w, h);
    },

    // text
    font : function(font_id,font_size)
    {
        this.m_oFontManager.LoadFontFromFile(font_id, font_size, this.m_dDpiX, this.m_dDpiY);
    },
    GetFont : function()
    {
        return this.m_oCurFont;
    },
    SetFont : function(font)
    {
        this.m_oCurFont = font;
    },
    SetTextPr : function(textPr)
    {
        this.m_oTextPr = textPr;
    },
    SetFontSlot : function(slot, fontSizeKoef)
    {
    },
    GetTextPr : function()
    {
        return this.m_oTextPr;
    },
    FillText : function(x,y,text)
    {
        // убыстеренный вариант. здесь везде заточка на то, что приходит одна буква
        if (this.m_bIsBreak)
            return;

        // TODO: нужен другой метод отрисовки!!!
        var _x = this.m_oFullTransform.TransformPointX(x, y);
        var _y = this.m_oFullTransform.TransformPointY(x, y);
        this.Bounds.CheckRect(_x, _y, 1, 1);
    },
    FillTextCode : function(x, y, lUnicode)
    {
        // убыстеренный вариант. здесь везде заточка на то, что приходит одна буква
        if (this.m_bIsBreak)
            return;

        // TODO: нужен другой метод отрисовки!!!
        var _x = this.m_oFullTransform.TransformPointX(x, y);
        var _y = this.m_oFullTransform.TransformPointY(x, y);
        this.Bounds.CheckRect(_x, _y, 1, 1);
    },
    t : function(text,x,y)
    {
        if (this.m_bIsBreak)
            return;

        // TODO: нужен другой метод отрисовки!!!
        var _x = this.m_oFullTransform.TransformPointX(x, y);
        var _y = this.m_oFullTransform.TransformPointY(x, y);
        this.Bounds.CheckRect(_x, _y, 1, 1);
    },
    FillText2 : function(x,y,text,cropX,cropW)
    {
        // убыстеренный вариант. здесь везде заточка на то, что приходит одна буква
        if (this.m_bIsBreak)
            return;

        // TODO: нужен другой метод отрисовки!!!
        var _x = this.m_oFullTransform.TransformPointX(x, y);
        var _y = this.m_oFullTransform.TransformPointY(x, y);
        this.Bounds.CheckRect(_x, _y, 1, 1);
    },
    t2 : function(text,x,y,cropX,cropW)
    {
        if (this.m_bIsBreak)
            return;

        // TODO: нужен другой метод отрисовки!!!
        var _x = this.m_oFullTransform.TransformPointX(x, y);
        var _y = this.m_oFullTransform.TransformPointY(x, y);
        this.Bounds.CheckRect(_x, _y, 1, 1);
    },
    charspace : function(space)
    {
    },

    // private methods
    DrawHeaderEdit : function(yPos)
    {
    },
    DrawFooterEdit : function(yPos)
    {
    },

    DrawEmptyTableLine : function(x1,y1,x2,y2)
    {
    },

    DrawSpellingLine : function(y0, x0, x1, w)
    {
    },

    // smart methods for horizontal / vertical lines
    drawHorLine : function(align, y, x, r, penW)
    {
        var _x1 = this.m_oFullTransform.TransformPointX(x,y-penW);
        var _y1 = this.m_oFullTransform.TransformPointY(x,y-penW);

        var _x2 = this.m_oFullTransform.TransformPointX(x,y+penW);
        var _y2 = this.m_oFullTransform.TransformPointY(x,y+penW);

        var _x3 = this.m_oFullTransform.TransformPointX(r,y-penW);
        var _y3 = this.m_oFullTransform.TransformPointY(r,y-penW);

        var _x4 = this.m_oFullTransform.TransformPointX(r,y+penW);
        var _y4 = this.m_oFullTransform.TransformPointY(r,y+penW);

        this.Bounds.CheckPoint(_x1, _y1);
        this.Bounds.CheckPoint(_x2, _y2);
        this.Bounds.CheckPoint(_x3, _y3);
        this.Bounds.CheckPoint(_x4, _y4);
    },
    drawHorLine2 : function(align, y, x, r, penW)
    {
        return this.drawHorLine(align, y, x, r, penW);
    },
    drawVerLine : function(align, x, y, b, penW)
    {
        var _x1 = this.m_oFullTransform.TransformPointX(x-penW,y);
        var _y1 = this.m_oFullTransform.TransformPointY(x-penW,y);

        var _x2 = this.m_oFullTransform.TransformPointX(x+penW,y);
        var _y2 = this.m_oFullTransform.TransformPointY(x+penW,y);

        var _x3 = this.m_oFullTransform.TransformPointX(x-penW,b);
        var _y3 = this.m_oFullTransform.TransformPointY(x-penW,b);

        var _x4 = this.m_oFullTransform.TransformPointX(x+penW,b);
        var _y4 = this.m_oFullTransform.TransformPointY(x+penW,b);

        this.Bounds.CheckPoint(_x1, _y1);
        this.Bounds.CheckPoint(_x2, _y2);
        this.Bounds.CheckPoint(_x3, _y3);
        this.Bounds.CheckPoint(_x4, _y4);
    },

    // мега крутые функции для таблиц
    drawHorLineExt : function(align, y, x, r, penW, leftMW, rightMW)
    {
        this.drawHorLine(align, y, x + leftMW, r + rightMW);
    },

    rect : function(x,y,w,h)
    {
        var _x1 = this.m_oFullTransform.TransformPointX(x,y);
        var _y1 = this.m_oFullTransform.TransformPointY(x,y);

        var _x2 = this.m_oFullTransform.TransformPointX(x+w,y);
        var _y2 = this.m_oFullTransform.TransformPointY(x+w,y);

        var _x3 = this.m_oFullTransform.TransformPointX(x+w,y+h);
        var _y3 = this.m_oFullTransform.TransformPointY(x+w,y+h);

        var _x4 = this.m_oFullTransform.TransformPointX(x,y+h);
        var _y4 = this.m_oFullTransform.TransformPointY(x,y+h);

        this.Bounds.CheckPoint(_x1, _y1);
        this.Bounds.CheckPoint(_x2, _y2);
        this.Bounds.CheckPoint(_x3, _y3);
        this.Bounds.CheckPoint(_x4, _y4);
    },

    rect2 : function(x,y,w,h)
    {
        var _x1 = this.m_oFullTransform.TransformPointX(x,y);
        var _y1 = this.m_oFullTransform.TransformPointY(x,y);

        var _x2 = this.m_oFullTransform.TransformPointX(x+w,y);
        var _y2 = this.m_oFullTransform.TransformPointY(x+w,y);

        var _x3 = this.m_oFullTransform.TransformPointX(x+w,y-h);
        var _y3 = this.m_oFullTransform.TransformPointY(x+w,y-h);

        var _x4 = this.m_oFullTransform.TransformPointX(x,y-h);
        var _y4 = this.m_oFullTransform.TransformPointY(x,y-h);

        this.Bounds.CheckPoint(_x1, _y1);
        this.Bounds.CheckPoint(_x2, _y2);
        this.Bounds.CheckPoint(_x3, _y3);
        this.Bounds.CheckPoint(_x4, _y4);
    },

    TableRect : function(x,y,w,h)
    {
        this.rect(x, y, w, h);
    },

    // функции клиппирования
    AddClipRect : function(x, y, w, h)
    {
    },
    RemoveClipRect : function()
    {
    },

    SetClip : function(r)
    {
    },
    RemoveClip : function()
    {
    },

    SavePen : function()
    {
    },
    RestorePen : function()
    {
    },

    SaveBrush : function()
    {
    },
    RestoreBrush : function()
    {
    },

    SavePenBrush : function()
    {
    },
    RestorePenBrush : function()
    {
    },

    SaveGrState : function()
    {
    },
    RestoreGrState : function()
    {
    },

    StartClipPath : function()
    {
    },

    EndClipPath : function()
    {
    },

    CorrectBounds : function()
    {
        if (this.LineWidth != null)
        {
            var _correct = this.LineWidth / 2.0;

            this.Bounds.min_x -= _correct;
            this.Bounds.min_y -= _correct;
            this.Bounds.max_x += _correct;
            this.Bounds.max_y += _correct;
        }
    },

    CorrectBounds2 : function()
    {
        if (this.LineWidth != null)
        {
            var _correct = this.LineWidth * this.m_oCoordTransform.sx / 2;

            this.Bounds.min_x -= _correct;
            this.Bounds.min_y -= _correct;
            this.Bounds.max_x += _correct;
            this.Bounds.max_y += _correct;
        }
    },

    CheckLineWidth : function(shape)
    {
        if (!shape)
            return;
        var _ln = shape.pen;
        if (_ln != null && _ln.Fill != null && _ln.Fill.fill != null)
        {
            this.LineWidth = (_ln.w == null) ? 12700 : parseInt(_ln.w);
            this.LineWidth /= 36000.0;
        }
    },

    DrawLockObjectRect : function()
    {
    },

    DrawPresentationComment : function(type, x, y, w, h)
    {
        this.rect(x, y, w, h);
    }
};
//-----------------------------------------------------------------------------------
// ASC Classes
//-----------------------------------------------------------------------------------

function GetMinSnapDistanceXObject(pointX, arrGrObjects)
{
    var min_dx = null;
    var ret = null;
    for(var i = 0; i < arrGrObjects.length; ++i)
    {
        var cur_snap_arr_x = arrGrObjects[i].snapArrayX;
        var count = cur_snap_arr_x.length;
        for(var snap_index  = 0; snap_index < count; ++snap_index)
        {
            var dx = cur_snap_arr_x[snap_index] - pointX;
            if(min_dx === null)
            {
                ret = {dist: dx, pos: cur_snap_arr_x[snap_index]};
                min_dx = dx;
            }
            else
            {
                if(Math.abs(dx) < Math.abs(min_dx))
                {
                    min_dx = dx;
                    ret = {dist: dx, pos: cur_snap_arr_x[snap_index]};
                }
            }
        }
    }
    return ret;
}

function GetMinSnapDistanceYObject(pointY, arrGrObjects)
{
    var min_dy = null;
    var ret = null;
    for(var i = 0; i < arrGrObjects.length; ++i)
    {
        var cur_snap_arr_y = arrGrObjects[i].snapArrayY;
        var count = cur_snap_arr_y.length;
        for(var snap_index  = 0; snap_index < count; ++snap_index)
        {
            var dy = cur_snap_arr_y[snap_index] - pointY;
            if(min_dy === null)
            {
                min_dy = dy;
                ret = {dist: dy, pos: cur_snap_arr_y[snap_index]};
            }
            else
            {
                if(Math.abs(dy) < Math.abs(min_dy))
                {
                    min_dy = dy;
                    ret = {dist: dy, pos: cur_snap_arr_y[snap_index]};
                }
            }
        }
    }
    return ret;
}

function GetMinSnapDistanceXObjectByArrays(pointX, snapArrayX)
{
    var min_dx = null;
    var ret = null;
    var cur_snap_arr_x = snapArrayX;
    var count = cur_snap_arr_x.length;
    for(var snap_index  = 0; snap_index < count; ++snap_index)
    {
        var dx = cur_snap_arr_x[snap_index] - pointX;
        if(min_dx === null)
        {
            ret = {dist: dx, pos: cur_snap_arr_x[snap_index]};
            min_dx = dx;
        }
        else
        {
            if(Math.abs(dx) < Math.abs(min_dx))
            {
                min_dx = dx;
                ret = {dist: dx, pos: cur_snap_arr_x[snap_index]};
            }
        }
    }
    return ret;
}

function GetMinSnapDistanceYObjectByArrays(pointY, snapArrayY)
{
    var min_dy = null;
    var ret = null;
    var cur_snap_arr_y = snapArrayY;
    var count = cur_snap_arr_y.length;
    for(var snap_index  = 0; snap_index < count; ++snap_index)
    {
        var dy = cur_snap_arr_y[snap_index] - pointY;
        if(min_dy === null)
        {
            min_dy = dy;
            ret = {dist: dy, pos: cur_snap_arr_y[snap_index]};
        }
        else
        {
            if(Math.abs(dy) < Math.abs(min_dy))
            {
                min_dy = dy;
                ret = {dist: dy, pos: cur_snap_arr_y[snap_index]};
            }
        }
    }
    return ret;
}

function getAbsoluteRectBoundsObject(drawing)
{
    var transform = drawing.transform;
    var arrX = [], arrY = [];
    arrX.push(transform.TransformPointX(0, 0));
    arrX.push(transform.TransformPointX(drawing.extX, 0));
    arrX.push(transform.TransformPointX(drawing.extX, drawing.extY));
    arrX.push(transform.TransformPointX(0, drawing.extY));

    arrY.push(transform.TransformPointY(0, 0));
    arrY.push(transform.TransformPointY(drawing.extX, 0));
    arrY.push(transform.TransformPointY(drawing.extX, drawing.extY));
    arrY.push(transform.TransformPointY(0, drawing.extY));
    return {minX: Math.min.apply(Math, arrX), minY: Math.min.apply(Math, arrY), maxX: Math.max.apply(Math, arrX), maxY: Math.max.apply(Math, arrY)};
}

function getAbsoluteRectBoundsArr(aDrawings)
{
    var arrBounds = [], minX, minY, maxX, maxY, i, bounds;
    for(i = 0; i < aDrawings.length; ++i)
    {
        bounds = getAbsoluteRectBoundsObject(aDrawings[i]);
        arrBounds.push(bounds);
        if(i === 0)
        {
            minX = bounds.minX;
            minY = bounds.minY;
            maxX = bounds.maxX;
            maxY = bounds.maxY;
        }
        else
        {
            if(minX > bounds.minX)
            {
                minX = bounds.minX;
            }
            if(minY > bounds.minY)
            {
                minY = bounds.minY;
            }
            if(maxX < bounds.maxX)
            {
                maxX = bounds.maxX;
            }
            if(maxY < bounds.maxY)
            {
                maxY = bounds.maxY;
            }
        }
    }
    return {arrBounds: arrBounds, minX: minX, maxX: maxX, minY: minY, maxY: maxY};
}

function CalcLiterByLength(aAlphaBet, nLength)
{
    var modulo = nLength;
    var sResultLiter = '';
    while(modulo > 0)
    {
        sResultLiter = aAlphaBet[modulo%aAlphaBet.length] + sResultLiter;
        modulo = (modulo/aAlphaBet.length) >> 0;
    }
    return sResultLiter;
}




function CollectUniColor(oUniColor)
{
    if(!oUniColor || !oUniColor.color)
    {
        return 0;
    }
    var ret = [];
    var oColor = oUniColor.color;
    var oColorTypes = window['Asc'].c_oAscColor;
    ret.push(oColor.type);

    switch(oColor.type)
    {
        case oColorTypes.COLOR_TYPE_NONE:
        {
            break;
        }
        case oColorTypes.COLOR_TYPE_SRGB:
        {
            ret.push(((oColor.RGBA.R << 16) & 0xFF0000) + ((oColor.RGBA.G << 8) & 0xFF00) + oColor.RGBA.B);
            break;
        }
        case oColorTypes.COLOR_TYPE_PRST:
        case oColorTypes.COLOR_TYPE_SCHEME:
        case oColorTypes.COLOR_TYPE_SYS:
        {
            ret.push(oColor.id);
            break;
        }
    }
    if(!oUniColor.Mods)
    {
        ret.push(0);
    }
    else
    {
        var aMods = oUniColor.Mods.Mods;
        ret.push(aMods.length);
        for(var i = 0; i < aMods.length; ++ i)
        {
            ret.push([aMods[i].name, aMods[i].val]);
        }
    }
    return ret;
}


function CollectGs(oGs)
{
    if(!oGs)
    {
        return 0;
    }
    return [oGs.pos, CollectUniColor(oGs.color)];
}

function CreateGsFromParams(aParams, index, aBaseColors, bAccent1Background){
    if(!aParams){
        return null;
    }
    var oRet = new AscFormat.CGs();
    oRet.pos = aParams[0];
    oRet.color = CreateUniColorFromPreset(aParams[1], index, aBaseColors, bAccent1Background);
    return oRet;
}

function CollectSettingsUniFill(oUniFill)
{
    if(!oUniFill || !oUniFill.fill){
        return 0;
    }
    var ret = [];
    var oFill = oUniFill.fill;
    ret.push(oFill.type);
    ret.push(oUniFill.transparent);
    var oFillTypes = window['Asc'].c_oAscFill;
    switch(oFill.type)
    {
        case oFillTypes.FILL_TYPE_NONE:{
            break;
        }
        case oFillTypes.FILL_TYPE_BLIP:{
            ret.push(oFill.RasterImageId);
            break;
        }
        case oFillTypes.FILL_TYPE_NOFILL:{
            break;
        }
        case oFillTypes.FILL_TYPE_SOLID:{
            ret.push(CollectUniColor(oUniFill.fill.color));
            break;
        }
        case oFillTypes.FILL_TYPE_GRAD:{
            ret.push(oFill.lin ? [oFill.lin.angle, oFill.lin.scale] : 0);
            ret.push(oFill.path ? [] : 0);
            ret.push(oFill.rotateWithShape ? [] : 0);
            ret.push(oFill.colors.length);
            for(var i = 0; i < oFill.colors.length; ++i)
            {
                ret.push(CollectGs(oFill.colors[i]));
            }
            break;
        }
        case oFillTypes.FILL_TYPE_PATT:{
            ret.push(oFill.ftype);
            ret.push(CollectUniColor(oFill.fgClr));
            ret.push(CollectUniColor(oFill.bgClr));
            break;
        }
        case oFillTypes.FILL_TYPE_GRP:{
            break;
        }
    }
    return ret;
}


    function CreateUniColorFromPreset(aPreset, index, aBaseColors, bAccent1Background){
        if(!aPreset){
            return null;
        }
        var oRet = new AscFormat.CUniColor();
        var oColorTypes = window['Asc'].c_oAscColor;
        switch (aPreset[0]){
            case oColorTypes.COLOR_TYPE_NONE:
            {
                oRet.color =  new AscFormat.CRGBColor();
                break;
            }
            case oColorTypes.COLOR_TYPE_SRGB:
            {
                oRet.color =  new AscFormat.CRGBColor();
                oRet.color.RGBA.R = (aPreset[1] >> 16) & 0xFF;
                oRet.color.RGBA.G = (aPreset[1] >> 8) & 0xFF;
                oRet.color.RGBA.R = aPreset[1] & 0xFF;
                break;
            }
            case oColorTypes.COLOR_TYPE_PRST:
            {
                oRet.color = new AscFormat.CPrstColor();
                oRet.color.id = aPreset[1];
                break;
            }
            case oColorTypes.COLOR_TYPE_SCHEME:{
                oRet.color = new AscFormat.CSchemeColor();
                oRet.color.id = aPreset[1];
                if(AscFormat.isRealNumber(index) && Array.isArray(aBaseColors) && aBaseColors[index]){
                    if(aBaseColors[index].fill && aBaseColors[index].fill.color && aBaseColors[index].fill.color.color
                        && aBaseColors[index].fill.color.color.type === oColorTypes.COLOR_TYPE_SCHEME
                    &&  oRet.color.id === 0 && !bAccent1Background){
                        oRet.color.id = aBaseColors[index].fill.color.color.id;
                        if(aBaseColors[index].fill.color.Mods){
                            oRet.Mods = aBaseColors[index].fill.color.Mods.createDuplicate();
                        }
                    }
                }
                break;
            }
            case oColorTypes.COLOR_TYPE_SYS:
            {
                oRet.color = new AscFormat.CSysColor();
                oRet.color.id = aPreset[2];
                break;
            }
        }
        if(aPreset[2]){
            if(!oRet.Mods){
                oRet.Mods = new AscFormat.CColorModifiers();
            }
            for(var i = 0; i < aPreset[2]; ++i){
                var oMod = new AscFormat.CColorMod();
                oMod.name = aPreset[i + 3][0];
                oMod.val = aPreset[i + 3][1];
                oRet.Mods.Mods.push(oMod)
            }

        }
        return oRet;
    }


    function CreateUnifillFromPreset(aPreset, index, aBaseColors, bAccent1Background){
        var oRet = null;
        if(!aPreset){
            return oRet;
        }

        var oUnifill = new AscFormat.CUniFill();
        oUnifill.transparent = aPreset[1];
        var oFillTypes = window['Asc'].c_oAscFill;
        switch(aPreset[0]){
            case oFillTypes.FILL_TYPE_NONE:{
                oUnifill.fill = new AscFormat.CNoFill();
                break;
            }
            case oFillTypes.FILL_TYPE_BLIP:{
                oUnifill.fill =  new AscFormat.CBlipFill();
                oUnifill.fill.RasterImageId = aPreset[2];
                break;
            }
            case oFillTypes.FILL_TYPE_NOFILL:{
                oUnifill.fill = new AscFormat.CNoFill();
                break;
            }
            case oFillTypes.FILL_TYPE_SOLID:{
                oUnifill.fill =  new AscFormat.CSolidFill();
                oUnifill.fill.color = CreateUniColorFromPreset(aPreset[2], index, aBaseColors, bAccent1Background);
                break;
            }
            case oFillTypes.FILL_TYPE_GRAD:{
                oUnifill.fill = new AscFormat.CGradFill();
                if(aPreset[2]){
                    oUnifill.fill.lin = new AscFormat.GradLin();
                    oUnifill.fill.lin.angle = aPreset[2][0];
                    oUnifill.fill.lin.scale = aPreset[2][1];
                }
                if(Array.isArray(aPreset[3])){
                    oUnifill.fill.path = new AscFormat.GradPath();
                }
                if(Array.isArray(aPreset[4])){
                    oUnifill.fill.rotateWithShape = true;
                }
                for(var i = 0; i < aPreset[5]; ++i)
                {
                    oUnifill.fill.colors.push(CreateGsFromParams(aPreset[6+i], index, aBaseColors, bAccent1Background));
                }
                break;
            }
            case oFillTypes.FILL_TYPE_PATT:{
                oUnifill.fill = new AscFormat.CPattFill();
                oUnifill.fill.ftype = aPreset[2];
                oUnifill.fill.fgClr = CreateUniColorFromPreset(aPreset[3], index, aBaseColors, bAccent1Background);
                oUnifill.fill.bgClr = CreateUniColorFromPreset(aPreset[4], index, aBaseColors, bAccent1Background);
                break;
            }
            case oFillTypes.FILL_TYPE_GRP:{
                break;
            }
        }
        return oUnifill;
    }


function CollectSettingsLn(oLn)
{
    if(!oLn)
    {
        return 0;
    }
    var ret = [];
    ret.push(CollectSettingsUniFill(oLn.Fill));
    ret.push(oLn.prstDash);

    if(!oLn.Join)
    {
        ret.push(0);
    }
    else
    {
        ret.push([oLn.Join.type, oLn.Join.limit]);
    }

    if(oLn.headEnd)
    {
        ret.push([oLn.headEnd.type, oLn.headEnd.len, oLn.headEnd.w]);
    }
    else
    {
        ret.push(0);
    }

    if(oLn.tailEnd)
    {
        ret.push([oLn.tailEnd.type, oLn.tailEnd.len, oLn.tailEnd.w]);
    }
    else
    {
        ret.push(0);
    }
    ret.push(oLn.algn);
    ret.push(oLn.cap);
    ret.push(oLn.cmpd);
    ret.push(oLn.w);
    return ret;
}


function CollectSettingsSpPr(oSpPr)
{
    if(!oSpPr)
    {
        return 0;
    }
    return [CollectSettingsUniFill(oSpPr.Fill), CollectSettingsLn(oSpPr.ln)];

}

function CollectTextPr(oTxPr) {
    if(!oTxPr || !oTxPr.content || !oTxPr.content.Content[0].Pr || !oTxPr.content.Content[0].Pr.DefaultRunPr){
        return 0;
    }
    var oRet = [];
    var oTextPr = oTxPr.content.Content[0].Pr.DefaultRunPr;
    oRet.push(oTextPr.FontSize);
    oRet.push(oTextPr.Bold);
    oRet.push(oTextPr.Italic);
    oRet.push(CollectSettingsUniFill(oTextPr.Unifill));
    oRet.push(oTextPr.Caps);
    if(oTxPr.bodyPr){
        oRet.push([oTxPr.bodyPr.anchor, oTxPr.bodyPr.anchorCtr, oTxPr.bodyPr.rot, oTxPr.bodyPr.vert, oTxPr.bodyPr.horzOverflow, oTxPr.bodyPr.spcFirstLastPara, oTxPr.bodyPr.vertOverflow, oTxPr.bodyPr.wrap]);
    }
    else{
        oRet.push(0);
    }
    return oRet;
}

function CollectCatAxisPr(oAxis){
    var oRet = 0;
    if(!oAxis){
        return oRet;
    }
    oRet = [];
    oRet.push(CollectTextPr(oAxis.txPr));
    oRet.push(CollectSettingsSpPr(oAxis.spPr));
    oRet.push(CollectSettingsSpPr(oAxis.majorGridlines));
    oRet.push(CollectSettingsSpPr(oAxis.minorGridlines));
    oRet.push(oAxis.majorTickMark);
    oRet.push(oAxis.minorTickMark);
    oRet.push(oAxis.bDelete);
    oRet.push(oAxis.crossBetween);
    oRet.push(oAxis.crosses);
    return oRet;
}
function CollectValAxisPr(oAxis){
    var oRet = 0;
    if(!oAxis){
        return oRet;
    }
    oRet = [];
    oRet.push(CollectTextPr(oAxis.txPr));
    oRet.push(CollectSettingsSpPr(oAxis.spPr));
    oRet.push(CollectSettingsSpPr(oAxis.majorGridlines));
    oRet.push(CollectSettingsSpPr(oAxis.minorGridlines));
    oRet.push(oAxis.majorTickMark);
    oRet.push(oAxis.minorTickMark);
    oRet.push(oAxis.bDelete);
    oRet.push(oAxis.crossBetween);
    oRet.push(oAxis.crosses);
    return oRet;
}

function CollectLegendPr(oLegend){
    var oRet = 0;
    if(!oLegend){
        return oRet;
    }

    oRet = [];
    oRet.push(CollectTextPr(oLegend.txPr));
    oRet.push(CollectSettingsSpPr(oLegend.spPr));
    oRet.push(oLegend.legendPos);
    return oRet;
}


function CollectDLbls(oDlbls){
    var oRet = 0;
    if(!oDlbls){
        return oRet;
    }

    oRet = [];
    oRet.push(CollectTextPr(oDlbls.txPr));
    oRet.push(CollectSettingsSpPr(oDlbls.spPr));
    oRet.push(oDlbls.dLblPos);
    oRet.push(oDlbls.separator);
    oRet.push(oDlbls.showBubbleSize);
    oRet.push(oDlbls.showCatName);
    oRet.push(oDlbls.showLeaderLines);
    oRet.push(oDlbls.showLegendKey);
    oRet.push(oDlbls.showPercent);
    oRet.push(oDlbls.showSerName);
    oRet.push(oDlbls.showVal);
    return oRet;
}

function CollectMarker(oMarker){
    if(!oMarker){
        return 0;
    }
    return [oMarker.size, CollectSettingsSpPr(oMarker.spPr), oMarker.symbol];
}

function ApplyMarker(aPreset, oObject, index, aBaseColors){

    if(!oObject || !oObject.setMarker || (oObject instanceof AscFormat.CLineChart)){
        return;
    }
    if(!aPreset){
        oObject.setMarker(null);
        return;
    }
    if(!oObject.marker){
        oObject.setMarker(new AscFormat.CMarker());
    }
    oObject.marker.setSize(aPreset[0]);
    ApplySpPr(aPreset[1], oObject.marker, index, aBaseColors);
    oObject.marker.setSymbol(aPreset[2]);
    if(AscFormat.MARKER_SYMBOL_TYPE[0] === oObject.marker.symbol){
        oObject.marker.setSymbol(AscFormat.MARKER_SYMBOL_TYPE[index % 9]);
    }
}

function CollectSettingsFromChart(oChartSpace)
{
    var oRet = [];
    if(!oChartSpace){
        return oRet;
    }
    oRet.push(oChartSpace.style);
    oRet.push(CollectSettingsSpPr(oChartSpace.spPr));
    oRet.push(CollectTextPr(oChartSpace.txPr));
    if(oChartSpace.chart.title){
        oRet.push(CollectSettingsSpPr(oChartSpace.chart.title.spPr));
        oRet.push(CollectTextPr(oChartSpace.chart.title.txPr));
    }
    else{
        oRet.push(0);
        oRet.push(0);
    }
    oRet.push(CollectLegendPr(oChartSpace.chart.legend));
    if(oChartSpace.chart.plotArea){
        var oPlotArea = oChartSpace.chart.plotArea;
        oRet.push(CollectSettingsSpPr(oPlotArea.spPr));
        oRet.push(CollectTextPr(oPlotArea.txPr));
        var oValAxData = 0, oCatAxData = 0;
        for(var i = 0;  i < oPlotArea.axId.length; ++i){
            if(oPlotArea.axId[i].getObjectType() === AscDFH.historyitem_type_CatAx
            || oPlotArea.axId[i].getObjectType() === AscDFH.historyitem_type_DateAx
            || oPlotArea.axId[i].getObjectType() === AscDFH.historyitem_type_SerAx){
                oCatAxData = CollectCatAxisPr(oPlotArea.axId[i]);
            }
            if(oPlotArea.axId[i].getObjectType() === AscDFH.historyitem_type_ValAx ){
                oValAxData = CollectValAxisPr(oPlotArea.axId[i]);
            }

        }
        oRet.push(oCatAxData);
        oRet.push(oValAxData);
        var oChart = oPlotArea.charts[0];
        oRet.push(CollectDLbls(oChart.dLbls));
        if(oChart.getObjectType() === AscDFH.historyitem_type_PieChart || oChart.getObjectType() === AscDFH.historyitem_type_DoughnutChart){
            oRet.push(CollectSettingsSpPr(oChart.series[0] && oChart.series[0].dPt[0] && oChart.series[0].dPt[0].spPr));
        }
        else{
            oRet.push(CollectSettingsSpPr(oChart.series[0] && oChart.series[0].spPr));
        }

        if(oChart.getObjectType() === AscDFH.historyitem_type_PieChart || oChart.getObjectType() === AscDFH.historyitem_type_DoughnutChart){
            if(oChart.series[0] && oChart.series[0].dLbls && oChart.series[0].dLbls.dLbl[0]){
                oRet.push(CollectDLbls(oChart.series[0].dLbls && oChart.series[0].dLbls.dLbl[0] && oChart.series[0].dLbls.dLbl[0]));
            }
            else{
                oRet.push(CollectDLbls(oChart.series[0] && oChart.series[0].dLbls));
            }

        }
        else{
            oRet.push(CollectDLbls(oChart.series[0] && oChart.series[0].dLbls));
        }


        oRet.push(oChart.gapWidth);
        oRet.push(oChart.overlap);
        oRet.push(oChart.gapDepth);
        oRet.push(oChart.grouping);
        if(oChartSpace.chart.view3D){
            var oView3D = oChartSpace.chart.view3D;
            oRet.push([oView3D.depthPercent, oView3D.hPercent, oView3D.perspective, oView3D.rAngAx, oView3D.rotX, oView3D.rotY]);
        }
        else{
            oRet.push(0);
        }
    }
    else{
        oRet.push(0);
    }

    if(oChartSpace.chart.backWall){
        oRet.push([CollectSettingsSpPr(oChartSpace.chart.backWall.spPr), oChartSpace.chart.backWall.thickness]);
    }
    else{
        oRet.push(0);
    }

    if(oChartSpace.chart.floor){
        oRet.push([CollectSettingsSpPr(oChartSpace.chart.floor.spPr), oChartSpace.chart.floor.thickness]);
    }
    else{
        oRet.push(0);
    }

    if(oChartSpace.chart.sideWall){
        oRet.push([CollectSettingsSpPr(oChartSpace.chart.sideWall.spPr), oChartSpace.chart.sideWall.thickness]);
    }
    else{
        oRet.push(0);
    }
    oRet.push(CollectMarker(oChart.marker));
    oRet.push(CollectMarker(oChart.series[0] && oChart.series[0].marker));
    oRet.push(CollectSettingsSpPr(oChart.hiLowLines));
    if(oChart.upDownBars){
        oRet.push([CollectSettingsSpPr(oChart.upDownBars.downBars), oChart.upDownBars.gapWidth, CollectSettingsSpPr(oChart.upDownBars.upBars)]);
    }
    else{
        oRet.push(0);
    }
    return oRet;
}

function CreateLnFromPreset(aPreset, index, aBaseColors, bAccent1Background){
    var oRet = null;
    if(!aPreset){
        return oRet;
    }
    var oLn = new AscFormat.CLn();
    oLn.Fill = CreateUnifillFromPreset(aPreset[0], index, aBaseColors, bAccent1Background);
    oLn.prstDash = aPreset[1];
    if(aPreset[2]){
        oLn.Join = new AscFormat.LineJoin();
        oLn.Join.type = aPreset[2][0];
        oLn.Join.limit = aPreset[2][1];
    }
    if(aPreset[3]){
        oLn.headEnd = new AscFormat.EndArrow();
        oLn.headEnd.type = aPreset[3][0];
        oLn.headEnd.len = aPreset[3][1];
        oLn.headEnd.w = aPreset[3][2];
    }
    if(aPreset[4]){
        oLn.headEnd = new AscFormat.EndArrow();
        oLn.headEnd.type = aPreset[4][0];
        oLn.headEnd.len = aPreset[4][1];
        oLn.headEnd.w = aPreset[4][2];
    }
    oLn.algn = aPreset[5];
    oLn.cap = aPreset[6];
    oLn.cmpd = aPreset[7];
    oLn.w = aPreset[8];
    return oLn;
}

function ApplySpPr(aSpPrPr, oObject, index, aBaseColors, bAccent1Background){
    if(!aSpPrPr){
        if(oObject.spPr && oObject.spPr.xfrm){
            oObject.spPr.setFill(null);
            oObject.spPr.setLn(null);
            return
        }
        oObject.setSpPr(null);
        return;
    }
    if(!oObject.spPr){
        oObject.setSpPr(new AscFormat.CSpPr());
    }
    oObject.spPr.setParent(oObject);
    oObject.spPr.setFill(CreateUnifillFromPreset(aSpPrPr[0], index, aBaseColors, bAccent1Background));
    oObject.spPr.setLn(CreateLnFromPreset(aSpPrPr[1], index, aBaseColors, bAccent1Background));
}

function ApplyTxPr(aTextPr, oObject, oDrawingDocument, i, baseFills, bAccent1Background){
    if(!aTextPr){
        return;
    }
    if(!oObject.txPr){
        oObject.setTxPr(AscFormat.CreateTextBodyFromString("", oDrawingDocument, oObject));
    }
    var Pr = oObject.txPr.content.Content[0].Pr.Copy();
    if(!Pr.DefaultRunPr){
        Pr.DefaultRunPr = new CTextPr();
    }
    Pr.DefaultRunPr.FontSize = aTextPr[0];
    Pr.DefaultRunPr.Bold = aTextPr[1];
    Pr.DefaultRunPr.Italic = aTextPr[2];
    Pr.DefaultRunPr.Unifill = CreateUnifillFromPreset(aTextPr[3], i, baseFills, bAccent1Background);
    Pr.DefaultRunPr.Caps = aTextPr[4];
    oObject.txPr.content.Content[0].Set_Pr(Pr);
    if(aTextPr[5]){
        var oBodyPr = new AscFormat.CBodyPr();
        oBodyPr.anchor = aTextPr[5][0];
        oBodyPr.anchorCtr = aTextPr[5][1];
        oBodyPr.rot = aTextPr[5][2];
        oBodyPr.vert = aTextPr[5][3];
        oBodyPr.horzOverflow = aTextPr[5][4];
        oBodyPr.spcFirstLastPara = aTextPr[5][5];
        oBodyPr.vertOverflow = aTextPr[5][6];
        oBodyPr.wrap = aTextPr[5][7];
        oObject.txPr.setBodyPr(oBodyPr);
    }
}

function ApplyPropsToCatAxis(aPr, oAxis, oDrawingDocument, bCreate){
    if(!aPr){
        return;
    }
    ApplyTxPr(aPr[0], oAxis, oDrawingDocument);
    ApplySpPr(aPr[2], oAxis);
    if(oAxis.spPr){
        if(!bCreate || oAxis.majorGridlines){
            oAxis.setMajorGridlines(oAxis.spPr);
        }
        oAxis.setSpPr(null);
    }
    else{
        if(!bCreate){
            oAxis.setMajorGridlines(null);
        }
    }
    ApplySpPr(aPr[3], oAxis);
    if(oAxis.spPr){
        if(!bCreate || oAxis.minorGridlines){
            oAxis.setMinorGridlines(oAxis.spPr);
        }
        oAxis.setSpPr(null);
    }
    else{
        if(!bCreate){
            oAxis.setMinorGridlines(null);
        }
    }
    ApplySpPr(aPr[1], oAxis);

    if(!bCreate){
        oAxis.setMajorTickMark(aPr[4]);
        oAxis.setMinorTickMark(aPr[5]);
        oAxis.setDelete(aPr[6]);
        if(aPr.length > 7){
            oAxis.setCrossBetween && oAxis.setCrossBetween(aPr[7]);
            oAxis.setCrosses && oAxis.setCrosses(aPr[8]);
        }
    }
}
function ApplyPropsToValAxis(aPr, oAxis, oDrawingDocument, bCreate){
    if(!aPr){
        return;
    }
    ApplyTxPr(aPr[0], oAxis, oDrawingDocument);
    ApplySpPr(aPr[2], oAxis);
    if(oAxis.spPr){
        if(!bCreate || oAxis.majorGridlines){
            oAxis.setMajorGridlines(oAxis.spPr);
        }
        oAxis.setSpPr(null);
    }
    else{
        if(!bCreate){
            oAxis.setMajorGridlines(null);
        }
    }
    ApplySpPr(aPr[3], oAxis);
    if(oAxis.spPr){
        if(!bCreate || oAxis.minorGridlines){
            oAxis.setMinorGridlines(oAxis.spPr);
        }
        oAxis.setSpPr(null);
    }
    else {
        if(!bCreate){
            oAxis.setMinorGridlines(null);
        }
    }
    ApplySpPr(aPr[1], oAxis);
    if(!bCreate){
        oAxis.setMajorTickMark(aPr[4]);
        oAxis.setMinorTickMark(aPr[5]);
        oAxis.setDelete(aPr[6]);
        if(aPr.length > 7){
            oAxis.setCrossBetween && oAxis.setCrossBetween(aPr[7]);
            oAxis.setCrosses && oAxis.setCrosses(aPr[8]);
        }
    }
}

function ApplyLegendProps(aPr, oLegend, oDrawingDocument, bCreate){
    if(!aPr || !oLegend){
        return;
    }
    ApplyTxPr(aPr[0], oLegend, oDrawingDocument);
    ApplySpPr(aPr[1], oLegend);
    if(!bCreate){
        oLegend.setLegendPos(aPr[2]);
    }
    oLegend.setLayout(null);
}

function ApplyDLblsProps(aPr, oObj, oDrawingDocument, i, baseFills, bCreate){
    if(!aPr || !oObj){
        if(oObj){
            oObj.setDLbls(null);
        }
        return;
    }
    //if(!bCreate)
    {
        if(!oObj.dLbls){
            oObj.setDLbls(new AscFormat.CDLbls());
        }
    }
    if(oObj.dLbls){
        var lbls = oObj.dLbls;
        lbls.setParent(oObj);
        if(oObj.dLbls.bDelete){
            if(oObj.dLbls.setDelete){
                oObj.dLbls.setDelete(false);
            }
        }

        ApplyTxPr(aPr[0], lbls, oDrawingDocument, i, baseFills);
        ApplySpPr(aPr[1], lbls, i, baseFills);
        //if(!bCreate)
        {
            lbls.setDLblPos(aPr[2]);
            lbls.setSeparator(aPr[3]);
            lbls.setShowBubbleSize(aPr[4]);
            lbls.setShowCatName(aPr[5]);
            lbls.setShowLeaderLines(aPr[6]);
            lbls.setShowLegendKey(aPr[7]);
            lbls.setShowPercent(aPr[8]);
            lbls.setShowSerName(aPr[9]);
            lbls.setShowVal(aPr[10]);
        }
    }
}
function ApplyPresetToChartSpace(oChartSpace, aPreset, bCreate){
    var oDrawingDocument = oChartSpace.getDrawingDocument();
    oChartSpace.setStyle(aPreset[0]);
    ApplySpPr(aPreset[1], oChartSpace);
    ApplyTxPr(aPreset[2], oChartSpace, oDrawingDocument);
    var bAccent1Background = false;
    if(oChartSpace.spPr && oChartSpace.spPr.Fill && oChartSpace.spPr.Fill.fill && oChartSpace.spPr.Fill.fill.color && oChartSpace.spPr.Fill.fill.color.color
        && oChartSpace.spPr.Fill.fill.color.color.type === window['Asc'].c_oAscColor.COLOR_TYPE_SCHEME &&  oChartSpace.spPr.Fill.fill.color.color.id === 0){
        bAccent1Background = true;
    }
    if(bCreate && !oChartSpace.chart.title){
        oChartSpace.chart.setTitle(new AscFormat.CTitle());
        oChartSpace.chart.title.setOverlay(false);
    }
    if(oChartSpace.chart.title){
        ApplySpPr(aPreset[3], oChartSpace.chart.title);
        ApplyTxPr(aPreset[4], oChartSpace.chart.title, oDrawingDocument);
        if(oChartSpace.chart.title.layout){
            oChartSpace.chart.title.setLayout(null);
        }
    }


    var style = AscFormat.CHART_STYLE_MANAGER.getStyleByIndex(aPreset[0]);

    if(!aPreset[5] && !bCreate){
        oChartSpace.chart.setLegend(null);
    }
    else{
        if(!bCreate && aPreset[5]){
            // if(!oChartSpace.chart.legend){
            //     oChartSpace.chart.setLegend(new AscFormat.CLegend());
            // }
            oChartSpace.chart.legend && oChartSpace.chart.legend.setOverlay(false);
        }
    }
    ApplyLegendProps(aPreset[5], oChartSpace.chart.legend, oDrawingDocument, bCreate);

    var oPlotArea = oChartSpace.chart.plotArea;
    if(oPlotArea.layout){
        oPlotArea.setLayout(null);
    }
    ApplySpPr(aPreset[6], oPlotArea);
    ApplyTxPr(aPreset[7], oPlotArea, oDrawingDocument);
    var oAxisByTypes = oPlotArea.getAxisByTypes();
    for(var i = 0; i < oAxisByTypes.catAx.length; ++i){
        ApplyPropsToCatAxis(aPreset[8], oAxisByTypes.catAx[i], oDrawingDocument, bCreate);
    }
    for(i = 0; i < oAxisByTypes.valAx.length; ++i){
        ApplyPropsToValAxis(aPreset[9], oAxisByTypes.valAx[i], oDrawingDocument, bCreate);
    }

    var oChart = oPlotArea.charts[0], base_fills;
    var ser, lit = null, val = null;
    ApplyDLblsProps(aPreset[10], oChart, oDrawingDocument, undefined, undefined, bCreate);
    for(i = 0; i < oChart.series.length; ++i){
        lit = null;
        ser = oChart.series[i];
        val = ser.val || ser.yVal;
        var pts = AscFormat.getPtsFromSeries(ser);
        if(val){
            if(val.numRef && val.numRef.numCache)
            {
                lit = val.numRef.numCache;
            }
            else if(val.numLit)
            {
                lit = val.numLit;
            }
        }
        var ptCount;
        if(lit && AscFormat.isRealNumber(lit.ptCount)){
            ptCount = Math.max(lit.ptCount, AscFormat.getMaxIdx(pts));
        }
        else{
            ptCount = AscFormat.getMaxIdx(pts);
        }

        var oDPt;
        if(oChart.getObjectType() === AscDFH.historyitem_type_PieChart || oChart.getObjectType() === AscDFH.historyitem_type_DoughnutChart){
            base_fills = AscFormat.getArrayFillsFromBase(style.fill2, ptCount);
            for(j = 0; j < ptCount; ++j){
                oDPt = null;
                if(oChart.series[i].getDptByIdx){
                    oDPt = oChart.series[i].getDptByIdx(j);
                }
                if(!oDPt){
                    oDPt = new AscFormat.CDPt();
                    oDPt.setIdx(j);
                    oChart.series[i].addDPt(oDPt);
                }
                if(oDPt.bubble3D !== false){
                    oDPt.setBubble3D(false);
                }
                ApplySpPr(aPreset[11], oDPt, j, base_fills, bAccent1Background);

            }
            for (j = 0; j < oChart.series[i].dPt.length; ++j ){
                if(oChart.series[i].dPt[j].idx >= ptCount){
                    oChart.series[i].removeDPt(j);
                }
            }
        }
        else{
            for(var j = oChart.series[i].dPt.length - 1; j > -1; --j){
                oChart.series[i].removeDPt(j);
            }
            base_fills = AscFormat.getArrayFillsFromBase(style.fill2, oChart.series.length);
            ApplySpPr(aPreset[11], oChart.series[i], i, base_fills, bAccent1Background);
        }
        if(oChart.getObjectType() === AscDFH.historyitem_type_PieChart || oChart.getObjectType() === AscDFH.historyitem_type_DoughnutChart){
            ApplyDLblsProps(aPreset[12], oChart.series[i], oDrawingDocument, i, base_fills, true);
            if(oChart.series[i].dLbls){
                for(var j = 0; j < ptCount; ++j){
                    var oDLbl = oChart.series[i].dLbls.findDLblByIdx(j);
                    if(!oDLbl) {
                        oDLbl = new AscFormat.CDLbl();
                        oChart.series[i].dLbls.addDLbl(oDLbl);
                        oDLbl.setIdx(j);
                    }
                    ApplyTxPr(aPreset[12][0], oDLbl, oDrawingDocument, j, base_fills, bAccent1Background);
                    ApplySpPr(aPreset[12][1], oDLbl, j, base_fills, bAccent1Background);
                    oDLbl.setDLblPos(aPreset[12][2]);
                    oDLbl.setSeparator(aPreset[12][3]);
                    oDLbl.setShowBubbleSize(aPreset[12][4]);
                    oDLbl.setShowCatName(aPreset[12][5]);
                    oDLbl.setShowLegendKey(aPreset[12][7]);
                    oDLbl.setShowPercent(aPreset[12][8]);
                    oDLbl.setShowSerName(aPreset[12][9]);
                    oDLbl.setShowVal(aPreset[12][10]);
                }
            }
        }
        else{
            ApplyDLblsProps(aPreset[12], oChart.series[i], oDrawingDocument, i, base_fills, true);
        }
    }


    if(oChart.getObjectType() === AscDFH.historyitem_type_PieChart || oChart.getObjectType() === AscDFH.historyitem_type_DoughnutChart){
        oChart.setVaryColors(true);
    }
    else{
        if(oChart.setVaryColors){
            oChart.setVaryColors(false);
        }
    }

    if(oChart.setGapWidth){
        oChart.setGapWidth(aPreset[13]);
    }
    if(oChart.setOverlap){
        oChart.setOverlap(aPreset[14]);
    }
    if(oChart.setGapDepth){
        oChart.setGapDepth(aPreset[15]);
    }
    if(oChart.setGrouping){
        oChart.setGrouping(aPreset[16]);
    }

    if(aPreset[17]){
        if(!oChartSpace.chart.view3D){
            oChartSpace.chart.setView3D(new AscFormat.CView3d());
        }
        oChartSpace.chart.view3D.setDepthPercent(aPreset[17][0]);
        oChartSpace.chart.view3D.setHPercent(aPreset[17][1]);
        oChartSpace.chart.view3D.setPerspective(aPreset[17][2]);
        oChartSpace.chart.view3D.setRAngAx(aPreset[17][3]);
        oChartSpace.chart.view3D.setRotX(aPreset[17][4]);
        oChartSpace.chart.view3D.setRotY(aPreset[17][5]);
    }
    else{
        oChartSpace.chart.setView3D(null);
    }
    if(aPreset[18]){
        if(!oChartSpace.chart.backWall){
            oChartSpace.chart.setBackWall(new AscFormat.CChartWall());
        }
        ApplySpPr(aPreset[18][0], oChartSpace.chart.backWall);
        oChartSpace.chart.backWall.setThickness(aPreset[18][1]);
    }
    else{
        oChartSpace.chart.setBackWall(null);
    }

    if(aPreset[19]){
        if(!oChartSpace.chart.floor){
            oChartSpace.chart.setFloor(new AscFormat.CChartWall());
        }
        ApplySpPr(aPreset[19][0], oChartSpace.chart.floor);
        oChartSpace.chart.floor.setThickness(aPreset[19][1]);
    }
    else{
        oChartSpace.chart.setFloor(null);
    }

    if(aPreset[20]){
        if(!oChartSpace.chart.sideWall){
            oChartSpace.chart.setSideWall(new AscFormat.CChartWall());
        }
        ApplySpPr(aPreset[20][0], oChartSpace.chart.sideWall);
        oChartSpace.chart.sideWall.setThickness(aPreset[20][1]);
    }
    else{
        oChartSpace.chart.setSideWall(null);
    }
    ApplyMarker(aPreset[21], oChart);
    for(var i = 0; i < oChart.series.length; ++i){
        ApplyMarker(aPreset[22], oChart.series[i], i, base_fills, bCreate);
    }


    if(oChart.getObjectType() === AscDFH.historyitem_type_StockChart){
        var oSpPr = oChartSpace.spPr;
        if(oChart.hiLowLines){
            oChartSpace.spPr = oChart.hiLowLines;
            ApplySpPr(aPreset[23], oChartSpace);
        }
        else{
            oChartSpace.spPr = new AscFormat.CSpPr();
            ApplySpPr(aPreset[23], oChartSpace);
            oChart.setHiLowLines(oChartSpace.spPr);
        }

        if(!aPreset[24]){
            oChart.setUpDownBars(null);
        }
        else{
            if(!oChart.upDownBars){
                oChart.setUpDownBars(new AscFormat.CUpDownBars());
            }

            if(oChart.upDownBars.downBars){
                oChartSpace.spPr = oChart.upDownBars.downBars;
                ApplySpPr(aPreset[24][0], oChartSpace);
            }
            else{
                oChartSpace.spPr = new AscFormat.CSpPr();
                ApplySpPr(aPreset[24][0], oChartSpace);
                oChart.upDownBars.setDownBars(oChartSpace.spPr);
            }

            oChart.upDownBars.setGapWidth(aPreset[24][1]);

            if(oChart.upDownBars.upBars){
                oChartSpace.spPr = oChart.upDownBars.upBars;
                ApplySpPr(aPreset[24][2], oChartSpace);
            }
            else{
                oChartSpace.spPr = new AscFormat.CSpPr();
                ApplySpPr(aPreset[24][2], oChartSpace);
                oChart.upDownBars.setUpBars(oChartSpace.spPr);
            }
        }
        oChartSpace.spPr = oSpPr;
    }
}
    function CMathPainter(_api)
    {
        this.Api = _api;

        this.StartLoad = function ()
        {
            var loader = AscCommon.g_font_loader;
            var fontinfo = g_fontApplication.GetFontInfo("Cambria Math");
            if (undefined === fontinfo)
            {
                // нет Cambria Math - нет и формул
                return;
            }

            var isasync = loader.LoadFont(fontinfo, this.Api.asyncFontEndLoaded_MathDraw, this);

            if (false === isasync)
            {
                this.Generate();
            }
        };

        this.Generate2 = function ()
        {
            // GENERATE IMAGES & JSON
            var bTurnOnId = false;
            if (false === g_oTableId.m_bTurnOff)
            {
                g_oTableId.m_bTurnOff = true;
                bTurnOnId = true;
            }

            History.TurnOff();

            var _math = new AscCommon.CAscMathCategory();

            var _canvas = document.createElement('canvas');

            var _sizes =
                [
                    {w: 25, h: 25}, // Symbols
                    {w: 50, h: 50}, // Fraction
                    {w: 50, h: 50}, // Script
                    {w: 115, h: 55}, // Radical
                    {w: 60, h: 60}, // Integral
                    {w: 100, h: 75}, // LargeOperator
                    {w: 80, h: 75}, // Bracket, //{ w : 150, h : 75 }
                    {w: 100, h: 50}, // Function
                    {w: 100, h: 40}, // Accent
                    {w: 100, h: 60}, // LimitLog
                    {w: 60, h: 40}, // Operator
                    {w: 100, h: 70} // Matrix
                ];

            var _excluded_arr = [c_oAscMathType.Bracket_Custom_5];
            var _excluded_obj = {};
            for (var k = 0; k < _excluded_arr.length; k++)
            {
                _excluded_obj["" + _excluded_arr[k]] = true;
            }

            var _types = [];
            for (var _name in c_oAscMathType)
            {
                if (_excluded_obj["" + c_oAscMathType[_name]] !== undefined)
                    continue;

                _types.push(c_oAscMathType[_name]);
            }
            _types.sort(function (a, b)
            {
                return a - b;
            });

            var raster_koef = 1;

            // retina
            //raster_koef = 2;

            // CREATE image!!!
            var _total_image = new AscFonts.CRasterHeapTotal();
            _total_image.CreateFirstChuck(1500 * raster_koef, 5000 * raster_koef);

            _total_image.Chunks[0].FindOnlyEqualHeight = true;
            _total_image.Chunks[0].CanvasCtx.globalCompositeOperation = "source-over";

            var _types_len = _types.length;
            for (var t = 0; t < _types_len; t++)
            {
                var _type = _types[t];
                var _category1 = (_type >> 24) & 0xFF;
                var _category2 = (_type >> 16) & 0xFF;
                _type &= 0xFFFF;

                if (undefined == _math.Data[_category1])
                {
                    _math.Data[_category1] = new AscCommon.CAscMathCategory();
                    _math.Data[_category1].Id = _category1;

                    _math.Data[_category1].W = _sizes[_category1].w;
                    _math.Data[_category1].H = _sizes[_category1].h;
                }

                if (undefined == _math.Data[_category1].Data[_category2])
                {
                    _math.Data[_category1].Data[_category2] = new AscCommon.CAscMathCategory();
                    _math.Data[_category1].Data[_category2].Id = _category2;

                    _math.Data[_category1].Data[_category2].W = _sizes[_category1].w;
                    _math.Data[_category1].Data[_category2].H = _sizes[_category1].h;
                }

                var _menuType = new AscCommon.CAscMathType();
                _menuType.Id = _types[t];

                var _paraMath = new ParaMath();
                _paraMath.Root.Load_FromMenu(_menuType.Id);
                _paraMath.Root.Correct_Content(true);

                _paraMath.MathToImageConverter(false, _canvas, _sizes[_category1].w, _sizes[_category1].h, raster_koef);

                var _place = _total_image.Alloc(_canvas.width, _canvas.height);
                var _x = _place.Line.Height * _place.Index;
                var _y = _place.Line.Y;

                _menuType.X = _x;
                _menuType.Y = _y;

                _math.Data[_category1].Data[_category2].Data.push(_menuType);

                _total_image.Chunks[0].CanvasCtx.drawImage(_canvas, _x, _y);
            }

            var _total_w = _total_image.Chunks[0].CanvasImage.width;
            var _total_h = _total_image.Chunks[0].LinesFree[0].Y;

            var _total_canvas = document.createElement('canvas');
            _total_canvas.width = _total_w;
            _total_canvas.height = _total_h;
            _total_canvas.getContext('2d').drawImage(_total_image.Chunks[0].CanvasImage, 0, 0);

            var _url_total = _total_canvas.toDataURL("image/png");
            var _json_formulas = JSON.stringify(_math);

            _canvas = null;

            if (true === bTurnOnId)
                g_oTableId.m_bTurnOff = false;

            History.TurnOn();

            this.Api.sendMathTypesToMenu(_math);
        };

        this.Generate = function ()
        {
            var _math_json = JSON.parse('{"Id":0,"Data":[{"Id":0,"Data":[{"Id":0,"Data":[{"Id":0,"X":0,"Y":0},{"Id":1,"X":25,"Y":0},{"Id":2,"X":50,"Y":0},{"Id":3,"X":75,"Y":0},{"Id":4,"X":100,"Y":0},{"Id":5,"X":125,"Y":0},{"Id":6,"X":150,"Y":0},{"Id":7,"X":175,"Y":0},{"Id":8,"X":200,"Y":0},{"Id":9,"X":225,"Y":0},{"Id":10,"X":250,"Y":0},{"Id":11,"X":275,"Y":0},{"Id":12,"X":300,"Y":0},{"Id":13,"X":325,"Y":0},{"Id":14,"X":350,"Y":0},{"Id":15,"X":375,"Y":0},{"Id":16,"X":400,"Y":0},{"Id":17,"X":425,"Y":0},{"Id":18,"X":450,"Y":0},{"Id":19,"X":475,"Y":0},{"Id":20,"X":500,"Y":0},{"Id":21,"X":525,"Y":0},{"Id":22,"X":550,"Y":0},{"Id":23,"X":575,"Y":0},{"Id":24,"X":600,"Y":0},{"Id":25,"X":625,"Y":0},{"Id":26,"X":650,"Y":0},{"Id":27,"X":675,"Y":0},{"Id":28,"X":700,"Y":0},{"Id":29,"X":725,"Y":0},{"Id":30,"X":750,"Y":0},{"Id":31,"X":775,"Y":0},{"Id":32,"X":800,"Y":0},{"Id":33,"X":825,"Y":0},{"Id":34,"X":850,"Y":0},{"Id":35,"X":875,"Y":0},{"Id":36,"X":900,"Y":0},{"Id":37,"X":925,"Y":0},{"Id":38,"X":950,"Y":0},{"Id":39,"X":975,"Y":0},{"Id":40,"X":1000,"Y":0},{"Id":41,"X":1025,"Y":0},{"Id":42,"X":1050,"Y":0},{"Id":43,"X":1075,"Y":0},{"Id":44,"X":1100,"Y":0},{"Id":45,"X":1125,"Y":0},{"Id":46,"X":1150,"Y":0},{"Id":47,"X":1175,"Y":0},{"Id":48,"X":1200,"Y":0},{"Id":49,"X":1225,"Y":0},{"Id":50,"X":1250,"Y":0},{"Id":51,"X":1275,"Y":0},{"Id":52,"X":1300,"Y":0},{"Id":53,"X":1325,"Y":0},{"Id":54,"X":1350,"Y":0},{"Id":55,"X":1375,"Y":0}],"W":25,"H":25},{"Id":1,"Data":[{"Id":65536,"X":1400,"Y":0},{"Id":65537,"X":1425,"Y":0},{"Id":65538,"X":1450,"Y":0},{"Id":65539,"X":1475,"Y":0},{"Id":65540,"X":0,"Y":25},{"Id":65541,"X":25,"Y":25},{"Id":65542,"X":50,"Y":25},{"Id":65543,"X":75,"Y":25},{"Id":65544,"X":100,"Y":25},{"Id":65545,"X":125,"Y":25},{"Id":65546,"X":150,"Y":25},{"Id":65547,"X":175,"Y":25},{"Id":65548,"X":200,"Y":25},{"Id":65549,"X":225,"Y":25},{"Id":65550,"X":250,"Y":25},{"Id":65551,"X":275,"Y":25},{"Id":65552,"X":300,"Y":25},{"Id":65553,"X":325,"Y":25},{"Id":65554,"X":350,"Y":25},{"Id":65555,"X":375,"Y":25},{"Id":65556,"X":400,"Y":25},{"Id":65557,"X":425,"Y":25},{"Id":65558,"X":450,"Y":25},{"Id":65559,"X":475,"Y":25},{"Id":65560,"X":500,"Y":25},{"Id":65561,"X":525,"Y":25},{"Id":65562,"X":550,"Y":25},{"Id":65563,"X":575,"Y":25},{"Id":65564,"X":600,"Y":25},{"Id":65565,"X":625,"Y":25}],"W":25,"H":25},{"Id":2,"Data":[{"Id":131072,"X":650,"Y":25},{"Id":131073,"X":675,"Y":25},{"Id":131074,"X":700,"Y":25},{"Id":131075,"X":725,"Y":25},{"Id":131076,"X":750,"Y":25},{"Id":131077,"X":775,"Y":25},{"Id":131078,"X":800,"Y":25},{"Id":131079,"X":825,"Y":25},{"Id":131080,"X":850,"Y":25},{"Id":131081,"X":875,"Y":25},{"Id":131082,"X":900,"Y":25},{"Id":131083,"X":925,"Y":25},{"Id":131084,"X":950,"Y":25},{"Id":131085,"X":975,"Y":25},{"Id":131086,"X":1000,"Y":25},{"Id":131087,"X":1025,"Y":25},{"Id":131088,"X":1050,"Y":25},{"Id":131089,"X":1075,"Y":25},{"Id":131090,"X":1100,"Y":25},{"Id":131091,"X":1125,"Y":25},{"Id":131092,"X":1150,"Y":25},{"Id":131093,"X":1175,"Y":25},{"Id":131094,"X":1200,"Y":25},{"Id":131095,"X":1225,"Y":25}],"W":25,"H":25}],"W":25,"H":25},{"Id":1,"Data":[{"Id":0,"Data":[{"Id":16777216,"X":0,"Y":50},{"Id":16777217,"X":50,"Y":50},{"Id":16777218,"X":100,"Y":50},{"Id":16777219,"X":150,"Y":50}],"W":50,"H":50},{"Id":1,"Data":[{"Id":16842752,"X":200,"Y":50},{"Id":16842753,"X":250,"Y":50},{"Id":16842754,"X":300,"Y":50},{"Id":16842755,"X":350,"Y":50},{"Id":16842756,"X":400,"Y":50}],"W":50,"H":50}],"W":50,"H":50},{"Id":2,"Data":[{"Id":0,"Data":[{"Id":33554432,"X":450,"Y":50},{"Id":33554433,"X":500,"Y":50},{"Id":33554434,"X":550,"Y":50},{"Id":33554435,"X":600,"Y":50}],"W":50,"H":50},{"Id":1,"Data":[{"Id":33619968,"X":650,"Y":50},{"Id":33619969,"X":700,"Y":50},{"Id":33619970,"X":750,"Y":50},{"Id":33619971,"X":800,"Y":50}],"W":50,"H":50}],"W":50,"H":50},{"Id":3,"Data":[{"Id":0,"Data":[{"Id":50331648,"X":0,"Y":100},{"Id":50331649,"X":115,"Y":100},{"Id":50331650,"X":230,"Y":100},{"Id":50331651,"X":345,"Y":100}],"W":115,"H":55},{"Id":1,"Data":[{"Id":50397184,"X":460,"Y":100},{"Id":50397185,"X":575,"Y":100}],"W":115,"H":55}],"W":115,"H":55},{"Id":4,"Data":[{"Id":0,"Data":[{"Id":67108864,"X":690,"Y":100},{"Id":67108865,"X":805,"Y":100},{"Id":67108866,"X":920,"Y":100},{"Id":67108867,"X":1035,"Y":100},{"Id":67108868,"X":1150,"Y":100},{"Id":67108869,"X":1265,"Y":100},{"Id":67108870,"X":1380,"Y":100},{"Id":67108871,"X":0,"Y":215},{"Id":67108872,"X":60,"Y":215}],"W":60,"H":60},{"Id":1,"Data":[{"Id":67174400,"X":120,"Y":215},{"Id":67174401,"X":180,"Y":215},{"Id":67174402,"X":240,"Y":215},{"Id":67174403,"X":300,"Y":215},{"Id":67174404,"X":360,"Y":215},{"Id":67174405,"X":420,"Y":215},{"Id":67174406,"X":480,"Y":215},{"Id":67174407,"X":540,"Y":215},{"Id":67174408,"X":600,"Y":215}],"W":60,"H":60},{"Id":2,"Data":[{"Id":67239936,"X":660,"Y":215},{"Id":67239937,"X":720,"Y":215},{"Id":67239938,"X":780,"Y":215}],"W":60,"H":60}],"W":60,"H":60},{"Id":5,"Data":[{"Id":0,"Data":[{"Id":83886080,"X":0,"Y":275},{"Id":83886081,"X":100,"Y":275},{"Id":83886082,"X":200,"Y":275},{"Id":83886083,"X":300,"Y":275},{"Id":83886084,"X":400,"Y":275}],"W":100,"H":75},{"Id":1,"Data":[{"Id":83951616,"X":500,"Y":275},{"Id":83951617,"X":600,"Y":275},{"Id":83951618,"X":700,"Y":275},{"Id":83951619,"X":800,"Y":275},{"Id":83951620,"X":900,"Y":275},{"Id":83951621,"X":1000,"Y":275},{"Id":83951622,"X":1100,"Y":275},{"Id":83951623,"X":1200,"Y":275},{"Id":83951624,"X":1300,"Y":275},{"Id":83951625,"X":1400,"Y":275}],"W":100,"H":75},{"Id":2,"Data":[{"Id":84017152,"X":0,"Y":375},{"Id":84017153,"X":100,"Y":375},{"Id":84017154,"X":200,"Y":375},{"Id":84017155,"X":300,"Y":375},{"Id":84017156,"X":400,"Y":375},{"Id":84017157,"X":500,"Y":375},{"Id":84017158,"X":600,"Y":375},{"Id":84017159,"X":700,"Y":375},{"Id":84017160,"X":800,"Y":375},{"Id":84017161,"X":900,"Y":375}],"W":100,"H":75},{"Id":3,"Data":[{"Id":84082688,"X":1000,"Y":375},{"Id":84082689,"X":1100,"Y":375},{"Id":84082690,"X":1200,"Y":375},{"Id":84082691,"X":1300,"Y":375},{"Id":84082692,"X":1400,"Y":375},{"Id":84082693,"X":0,"Y":475},{"Id":84082694,"X":100,"Y":475},{"Id":84082695,"X":200,"Y":475},{"Id":84082696,"X":300,"Y":475},{"Id":84082697,"X":400,"Y":475}],"W":100,"H":75},{"Id":4,"Data":[{"Id":84148224,"X":500,"Y":475},{"Id":84148225,"X":600,"Y":475},{"Id":84148226,"X":700,"Y":475},{"Id":84148227,"X":800,"Y":475},{"Id":84148228,"X":900,"Y":475}],"W":100,"H":75}],"W":100,"H":75},{"Id":6,"Data":[{"Id":0,"Data":[{"Id":100663296,"X":1000,"Y":475},{"Id":100663297,"X":1100,"Y":475},{"Id":100663298,"X":1200,"Y":475},{"Id":100663299,"X":1300,"Y":475},{"Id":100663300,"X":1400,"Y":475},{"Id":100663301,"X":0,"Y":575},{"Id":100663302,"X":80,"Y":575},{"Id":100663303,"X":160,"Y":575},{"Id":100663304,"X":240,"Y":575},{"Id":100663305,"X":320,"Y":575},{"Id":100663306,"X":400,"Y":575},{"Id":100663307,"X":480,"Y":575}],"W":80,"H":75},{"Id":1,"Data":[{"Id":100728832,"X":560,"Y":575},{"Id":100728833,"X":640,"Y":575},{"Id":100728834,"X":720,"Y":575},{"Id":100728835,"X":800,"Y":575}],"W":80,"H":75},{"Id":2,"Data":[{"Id":100794368,"X":880,"Y":575},{"Id":100794369,"X":960,"Y":575},{"Id":100794370,"X":1040,"Y":575},{"Id":100794371,"X":1120,"Y":575},{"Id":100794372,"X":1200,"Y":575},{"Id":100794373,"X":1280,"Y":575},{"Id":100794374,"X":1360,"Y":575},{"Id":100794375,"X":0,"Y":655},{"Id":100794376,"X":80,"Y":655},{"Id":100794377,"X":160,"Y":655},{"Id":100794378,"X":240,"Y":655},{"Id":100794379,"X":320,"Y":655},{"Id":100794380,"X":400,"Y":655},{"Id":100794381,"X":480,"Y":655},{"Id":100794382,"X":560,"Y":655},{"Id":100794383,"X":640,"Y":655},{"Id":100794384,"X":720,"Y":655},{"Id":100794385,"X":800,"Y":655}],"W":80,"H":75},{"Id":3,"Data":[{"Id":100859904,"X":880,"Y":655},{"Id":100859905,"X":960,"Y":655},{"Id":100859906,"X":1040,"Y":655},{"Id":100859907,"X":1120,"Y":655}],"W":80,"H":75},{"Id":4,"Data":[{"Id":100925441,"X":1200,"Y":655},{"Id":100925442,"X":1280,"Y":655}],"W":80,"H":75}],"W":80,"H":75},{"Id":7,"Data":[{"Id":0,"Data":[{"Id":117440512,"X":0,"Y":735},{"Id":117440513,"X":100,"Y":735},{"Id":117440514,"X":200,"Y":735},{"Id":117440515,"X":300,"Y":735},{"Id":117440516,"X":400,"Y":735},{"Id":117440517,"X":500,"Y":735}],"W":100,"H":50},{"Id":1,"Data":[{"Id":117506048,"X":600,"Y":735},{"Id":117506049,"X":700,"Y":735},{"Id":117506050,"X":800,"Y":735},{"Id":117506051,"X":900,"Y":735},{"Id":117506052,"X":1000,"Y":735},{"Id":117506053,"X":1100,"Y":735}],"W":100,"H":50},{"Id":2,"Data":[{"Id":117571584,"X":1200,"Y":735},{"Id":117571585,"X":1300,"Y":735},{"Id":117571586,"X":1400,"Y":735},{"Id":117571587,"X":0,"Y":835},{"Id":117571588,"X":100,"Y":835},{"Id":117571589,"X":200,"Y":835}],"W":100,"H":50},{"Id":3,"Data":[{"Id":117637120,"X":300,"Y":835},{"Id":117637121,"X":400,"Y":835},{"Id":117637122,"X":500,"Y":835},{"Id":117637123,"X":600,"Y":835},{"Id":117637124,"X":700,"Y":835},{"Id":117637125,"X":800,"Y":835}],"W":100,"H":50},{"Id":4,"Data":[{"Id":117702656,"X":900,"Y":835},{"Id":117702657,"X":1000,"Y":835},{"Id":117702658,"X":1100,"Y":835}],"W":100,"H":50}],"W":100,"H":50},{"Id":8,"Data":[{"Id":0,"Data":[{"Id":134217728,"X":1200,"Y":835},{"Id":134217729,"X":1300,"Y":835},{"Id":134217730,"X":1400,"Y":835},{"Id":134217731,"X":0,"Y":935},{"Id":134217732,"X":100,"Y":935},{"Id":134217733,"X":200,"Y":935},{"Id":134217734,"X":300,"Y":935},{"Id":134217735,"X":400,"Y":935},{"Id":134217736,"X":500,"Y":935},{"Id":134217737,"X":600,"Y":935},{"Id":134217738,"X":700,"Y":935},{"Id":134217739,"X":800,"Y":935},{"Id":134217740,"X":900,"Y":935},{"Id":134217741,"X":1000,"Y":935},{"Id":134217742,"X":1100,"Y":935},{"Id":134217743,"X":1200,"Y":935},{"Id":134217744,"X":1300,"Y":935},{"Id":134217745,"X":1400,"Y":935},{"Id":134217746,"X":0,"Y":1035},{"Id":134217747,"X":100,"Y":1035}],"W":100,"H":40},{"Id":1,"Data":[{"Id":134283264,"X":200,"Y":1035},{"Id":134283265,"X":300,"Y":1035}],"W":100,"H":40},{"Id":2,"Data":[{"Id":134348800,"X":400,"Y":1035},{"Id":134348801,"X":500,"Y":1035}],"W":100,"H":40},{"Id":3,"Data":[{"Id":134414336,"X":600,"Y":1035},{"Id":134414337,"X":700,"Y":1035},{"Id":134414338,"X":800,"Y":1035}],"W":100,"H":40}],"W":100,"H":40},{"Id":9,"Data":[{"Id":0,"Data":[{"Id":150994944,"X":900,"Y":1035},{"Id":150994945,"X":1000,"Y":1035},{"Id":150994946,"X":1100,"Y":1035},{"Id":150994947,"X":1200,"Y":1035},{"Id":150994948,"X":1300,"Y":1035},{"Id":150994949,"X":1400,"Y":1035}],"W":100,"H":60},{"Id":1,"Data":[{"Id":151060480,"X":0,"Y":1135},{"Id":151060481,"X":100,"Y":1135}],"W":100,"H":60}],"W":100,"H":60},{"Id":10,"Data":[{"Id":0,"Data":[{"Id":167772160,"X":840,"Y":215},{"Id":167772161,"X":900,"Y":215},{"Id":167772162,"X":960,"Y":215},{"Id":167772163,"X":1020,"Y":215},{"Id":167772164,"X":1080,"Y":215},{"Id":167772165,"X":1140,"Y":215},{"Id":167772166,"X":1200,"Y":215}],"W":60,"H":40},{"Id":1,"Data":[{"Id":167837696,"X":1260,"Y":215},{"Id":167837697,"X":1320,"Y":215},{"Id":167837698,"X":1380,"Y":215},{"Id":167837699,"X":1440,"Y":215},{"Id":167837700,"X":1360,"Y":655},{"Id":167837701,"X":200,"Y":1135},{"Id":167837702,"X":300,"Y":1135},{"Id":167837703,"X":400,"Y":1135},{"Id":167837704,"X":500,"Y":1135},{"Id":167837705,"X":600,"Y":1135},{"Id":167837706,"X":700,"Y":1135},{"Id":167837707,"X":800,"Y":1135}],"W":60,"H":40},{"Id":2,"Data":[{"Id":167903232,"X":900,"Y":1135},{"Id":167903233,"X":1000,"Y":1135}],"W":60,"H":40}],"W":60,"H":40},{"Id":11,"Data":[{"Id":0,"Data":[{"Id":184549376,"X":1100,"Y":1135},{"Id":184549377,"X":1200,"Y":1135},{"Id":184549378,"X":1300,"Y":1135},{"Id":184549379,"X":1400,"Y":1135},{"Id":184549380,"X":0,"Y":1235},{"Id":184549381,"X":100,"Y":1235},{"Id":184549382,"X":200,"Y":1235},{"Id":184549383,"X":300,"Y":1235}],"W":100,"H":70},{"Id":1,"Data":[{"Id":184614912,"X":400,"Y":1235},{"Id":184614913,"X":500,"Y":1235},{"Id":184614914,"X":600,"Y":1235},{"Id":184614915,"X":700,"Y":1235}],"W":100,"H":70},{"Id":2,"Data":[{"Id":184680448,"X":800,"Y":1235},{"Id":184680449,"X":900,"Y":1235},{"Id":184680450,"X":1000,"Y":1235},{"Id":184680451,"X":1100,"Y":1235}],"W":100,"H":70},{"Id":3,"Data":[{"Id":184745984,"X":1200,"Y":1235},{"Id":184745985,"X":1300,"Y":1235},{"Id":184745986,"X":1400,"Y":1235},{"Id":184745987,"X":0,"Y":1335}],"W":100,"H":70},{"Id":4,"Data":[{"Id":184811520,"X":100,"Y":1335},{"Id":184811521,"X":200,"Y":1335}],"W":100,"H":70}],"W":100,"H":70}],"W":0,"H":0}');

            var _math = new AscCommon.CAscMathCategory();

            var _len1 = _math_json["Data"].length;
            for (var i1 = 0; i1 < _len1; i1++)
            {
                var _catJS1 = _math_json["Data"][i1];
                var _cat1 = new AscCommon.CAscMathCategory();

                _cat1.Id = _catJS1["Id"];
                _cat1.W = _catJS1["W"];
                _cat1.H = _catJS1["H"];

                var _len2 = _catJS1["Data"].length;
                for (var i2 = 0; i2 < _len2; i2++)
                {
                    var _catJS2 = _catJS1["Data"][i2];
                    var _cat2 = new AscCommon.CAscMathCategory();

                    _cat2.Id = _catJS2["Id"];
                    _cat2.W = _catJS2["W"];
                    _cat2.H = _catJS2["H"];

                    var _len3 = _catJS2["Data"].length;
                    for (var i3 = 0; i3 < _len3; i3++)
                    {
                        var _typeJS = _catJS2["Data"][i3];
                        var _type = new AscCommon.CAscMathType();

                        _type.Id = _typeJS["Id"];
                        _type.X = _typeJS["X"];
                        _type.Y = _typeJS["Y"];

                        _cat2.Data.push(_type);
                    }

                    _cat1.Data.push(_cat2);
                }

                _math.Data.push(_cat1);
            }

            this.Api.sendMathTypesToMenu(_math);
        }
    }


    function fCreateSignatureShape(sGuid, sSigner, sSigner2, sEmail, bWord, wsModel, Width, Height, sImgUrl){
        var oShape = new AscFormat.CShape();
        oShape.setWordShape(bWord === true);
        oShape.setBDeleted(false);
        if(wsModel)
            oShape.setWorksheet(wsModel);
        var oSpPr = new AscFormat.CSpPr();
        var oXfrm = new AscFormat.CXfrm();
        oXfrm.setOffX(0);
        oXfrm.setOffY(0);
        if(AscFormat.isRealNumber(Width) && AscFormat.isRealNumber(Height)){
            oXfrm.setExtX(Width);
			oXfrm.setExtY(Height);
        }
        else{
			oXfrm.setExtX(1828800/36000);
			oXfrm.setExtY(1828800/36000);
        }
        if(typeof sImgUrl === "string" && sImgUrl.length > 0){
            var oBlipFillUnifill = AscFormat.CreateBlipFillUniFillFromUrl(sImgUrl);
            oSpPr.setFill(oBlipFillUnifill);
        }
        else {
			oSpPr.setFill(AscFormat.CreateNoFillUniFill());
        }
        oSpPr.setXfrm(oXfrm);
        oXfrm.setParent(oSpPr);
        oSpPr.setLn(AscFormat.CreateNoFillLine());
        oSpPr.setGeometry(AscFormat.CreateGeometry("rect"));
        oShape.setSpPr(oSpPr);
        oSpPr.setParent(oShape);
        var oSignatureLine = new AscFormat.CSignatureLine();
        oSignatureLine.id = sGuid;
        oSignatureLine.signer = sSigner;
        oSignatureLine.signer2 = sSigner2;
        oSignatureLine.email = sEmail;
        oShape.setSignature(oSignatureLine);

        return oShape;
    }


    function fGetListTypeFromBullet(Bullet) {

        var ListType = {
            Type    : -1,
            SubType : -1
        };
        if (Bullet)
        {
            if (Bullet && Bullet.bulletType)
            {
                switch (Bullet.bulletType.type)
                {
                    case AscFormat.BULLET_TYPE_BULLET_CHAR:
                    {
                        ListType.Type    = 0;
                        ListType.SubType = undefined;
                        switch (Bullet.bulletType.Char)
                        {
                            case "•":
                            {
                                ListType.SubType = 1;
                                break;
                            }
                            case  "o":
                            {
                                ListType.SubType = 2;
                                break;
                            }
                            case  "§":
                            {
                                ListType.SubType = 3;
                                break;
                            }
                            case  String.fromCharCode(0x0076):
                            {
                                ListType.SubType = 4;
                                break;
                            }
                            case  String.fromCharCode(0x00D8):
                            {
                                ListType.SubType = 5;
                                break;
                            }
                            case  String.fromCharCode(0x00FC):
                            {
                                ListType.SubType = 6;
                                break;
                            }
                            case String.fromCharCode(119):
                            {
                                ListType.SubType = 7;
                                break;
                            }
                            case String.fromCharCode(0x2013):
                            {
                                ListType.SubType = 8;
                                break;
                            }
                        }
                        break;
                    }
                    case AscFormat.BULLET_TYPE_BULLET_BLIP:
                    {
                        ListType.Type    = 0;
                        ListType.SubType = undefined;
                        break;
                    }
                    case AscFormat.BULLET_TYPE_BULLET_AUTONUM:
                    {
                        ListType.Type    = 1;
                        ListType.SubType = undefined;
                        if (AscFormat.isRealNumber(Bullet.bulletType.AutoNumType))
                        {
                            var AutoNumType = AscCommonWord.g_NumberingArr[Bullet.bulletType.AutoNumType] - 99;
                            if (AutoNumType > 0 && AutoNumType < 9)
                            {
                                ListType.SubType = AutoNumType;
                            }
                        }
                        break;
                    }
                }
            }
        }
        return ListType;
    }


    function fGetFontByNumInfo(Type, SubType){
        if(SubType >= 0){
            if(Type === 0){
                switch(SubType)
                {
                    case 0:
                    case 1:
                    case 8:
                    {
                        return "Arial";
                    }
                    case 2:
                    {
                        return "Courier New";
                    }
                    case 3:
                    case 4:
                    case 5:
                    case 6:
                    case 7:
                    {
                        return "Wingdings";
                    }
                }
            }
        }
        return null;
    }

    function fGetPresentationBulletByNumInfo(NumInfo){
        var bullet = new AscFormat.CBullet();
        if(NumInfo.SubType < 0)
        {
            bullet.bulletType = new AscFormat.CBulletType();
            bullet.bulletType.type = AscFormat.BULLET_TYPE_BULLET_NONE;
        }
        else
        {
            switch (NumInfo.Type)
            {
                case 0 : /*bulletChar*/
                {
                    switch(NumInfo.SubType)
                    {
                        case 0:
                        case 1:
                        {
                            var bulletText = "•";
                            bullet.bulletTypeface = new AscFormat.CBulletTypeface();
                            bullet.bulletTypeface.type = AscFormat.BULLET_TYPE_TYPEFACE_BUFONT;
                            bullet.bulletTypeface.typeface = "Arial";
                            break;
                        }
                        case 2:
                        {
                            bulletText = "o";
                            bullet.bulletTypeface = new AscFormat.CBulletTypeface();
                            bullet.bulletTypeface.type = AscFormat.BULLET_TYPE_TYPEFACE_BUFONT;
                            bullet.bulletTypeface.typeface = "Courier New";
                            break;
                        }
                        case 3:
                        {
                            bulletText = "§";
                            bullet.bulletTypeface = new AscFormat.CBulletTypeface();
                            bullet.bulletTypeface.type = AscFormat.BULLET_TYPE_TYPEFACE_BUFONT;
                            bullet.bulletTypeface.typeface = "Wingdings";
                            break;
                        }
                        case 4:
                        {
                            bulletText = String.fromCharCode( 0x0076 );
                            bullet.bulletTypeface = new AscFormat.CBulletTypeface();
                            bullet.bulletTypeface.type = AscFormat.BULLET_TYPE_TYPEFACE_BUFONT;
                            bullet.bulletTypeface.typeface = "Wingdings";
                            break;
                        }
                        case 5:
                        {
                            bulletText = String.fromCharCode( 0x00D8 );
                            bullet.bulletTypeface = new AscFormat.CBulletTypeface();
                            bullet.bulletTypeface.type = AscFormat.BULLET_TYPE_TYPEFACE_BUFONT;
                            bullet.bulletTypeface.typeface = "Wingdings";
                            break;
                        }
                        case 6:
                        {
                            bulletText = String.fromCharCode( 0x00FC );
                            bullet.bulletTypeface = new AscFormat.CBulletTypeface();
                            bullet.bulletTypeface.type = AscFormat.BULLET_TYPE_TYPEFACE_BUFONT;
                            bullet.bulletTypeface.typeface = "Wingdings";
                            break;
                        }
                        case 7:
                        {

                            bulletText = String.fromCharCode(119);
                            bullet.bulletTypeface = new AscFormat.CBulletTypeface();
                            bullet.bulletTypeface.type = AscFormat.BULLET_TYPE_TYPEFACE_BUFONT;
                            bullet.bulletTypeface.typeface = "Wingdings";
                            break;
                        }
                        case 8:
                        {
                            bulletText = String.fromCharCode(0x2013);
                            bullet.bulletTypeface = new AscFormat.CBulletTypeface();
                            bullet.bulletTypeface.type = AscFormat.BULLET_TYPE_TYPEFACE_BUFONT;
                            bullet.bulletTypeface.typeface = "Arial";
                            break;
                        }
                    }
                    bullet.bulletType = new AscFormat.CBulletType();
                    bullet.bulletType.type = AscFormat.BULLET_TYPE_BULLET_CHAR;
                    bullet.bulletType.Char = bulletText;
                    break;
                }
                case 1 : /*autonum*/
                {
                    switch(NumInfo.SubType)
                    {
                        case 0 :
                        case 1 :
                        {
                            var numberingType = 12;//numbering_numfmt_arabicPeriod;
                            break;
                        }
                        case 2:
                        {
                            numberingType = 11;//numbering_numfmt_arabicParenR;
                            break;
                        }
                        case 3 :
                        {
                            numberingType = 34;//numbering_numfmt_romanUcPeriod;
                            break;
                        }
                        case 4 :
                        {
                            numberingType = 5;//numbering_numfmt_alphaUcPeriod;
                            break;
                        }
                        case 5 :
                        {
                            numberingType = 1;
                            break;
                        }
                        case 6 :
                        {
                            numberingType = 2;
                            break;
                        }
                        case 7 :
                        {
                            numberingType = 31;//numbering_numfmt_romanLcPeriod;
                            break;
                        }
                    }
                    bullet.bulletType = new AscFormat.CBulletType();
                    bullet.bulletType.type = AscFormat.BULLET_TYPE_BULLET_AUTONUM;
                    bullet.bulletType.AutoNumType = numberingType;
                    break;
                }
                default :
                {
                    break;
                }
            }
        }
        return bullet;
    }



    function fResetConnectorsIds(aCopyObjects, oIdMaps){
        for(var i = 0; i < aCopyObjects.length; ++i){
            var oDrawing = aCopyObjects[i].Drawing ? aCopyObjects[i].Drawing : aCopyObjects[i];
            if(oDrawing.getObjectType){
                if(oDrawing.getObjectType() === AscDFH.historyitem_type_Cnx){
                    var sStId = oDrawing.getStCxnId();
                    var sEndId = oDrawing.getEndCxnId();
                    var sStCnxId = null, sEndCnxId = null;
                    if(oIdMaps[sStId]){
                        sStCnxId = oIdMaps[sStId];
                    }
                    if(oIdMaps[sEndId]){
                        sEndCnxId = oIdMaps[sEndId];
                    }
                    if(sStId !==  sStCnxId || sEndCnxId !== sEndId){

                        var nvUniSpPr = oDrawing.nvSpPr.nvUniSpPr.copy();
                        if(!sStCnxId){
                            nvUniSpPr.stCnxIdx = null;
                            nvUniSpPr.stCnxId  = null;
                        }
                        else{
                            nvUniSpPr.stCnxId  = sStCnxId;
                        }
                        if(!sEndCnxId){
                            nvUniSpPr.endCnxIdx = null;
                            nvUniSpPr.endCnxId  = null;
                        }
                        else{
                            nvUniSpPr.endCnxId  = sEndCnxId;
                        }
                        oDrawing.nvSpPr.setUniSpPr(nvUniSpPr);
                    }
                }
                else if(oDrawing.getObjectType() === AscDFH.historyitem_type_GroupShape){
                    fResetConnectorsIds(oDrawing.spTree, oIdMaps);
                }
            }
        }
    }


    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].HANDLE_EVENT_MODE_HANDLE = HANDLE_EVENT_MODE_HANDLE;
    window['AscFormat'].HANDLE_EVENT_MODE_CURSOR = HANDLE_EVENT_MODE_CURSOR;
    window['AscFormat'].DISTANCE_TO_TEXT_LEFTRIGHT = DISTANCE_TO_TEXT_LEFTRIGHT;
    window['AscFormat'].BAR_DIR_BAR = BAR_DIR_BAR;
    window['AscFormat'].BAR_DIR_COL = BAR_DIR_COL;
    window['AscFormat'].BAR_GROUPING_CLUSTERED = BAR_GROUPING_CLUSTERED;
    window['AscFormat'].BAR_GROUPING_PERCENT_STACKED = BAR_GROUPING_PERCENT_STACKED;
    window['AscFormat'].BAR_GROUPING_STACKED = BAR_GROUPING_STACKED;
    window['AscFormat'].BAR_GROUPING_STANDARD = BAR_GROUPING_STANDARD;
    window['AscFormat'].GROUPING_PERCENT_STACKED = GROUPING_PERCENT_STACKED;
    window['AscFormat'].GROUPING_STACKED = GROUPING_STACKED;
    window['AscFormat'].GROUPING_STANDARD = GROUPING_STANDARD;
    window['AscFormat'].SCATTER_STYLE_LINE = SCATTER_STYLE_LINE;
    window['AscFormat'].SCATTER_STYLE_LINE_MARKER = SCATTER_STYLE_LINE_MARKER;
    window['AscFormat'].SCATTER_STYLE_MARKER = SCATTER_STYLE_MARKER;
    window['AscFormat'].SCATTER_STYLE_NONE = SCATTER_STYLE_NONE;
    window['AscFormat'].SCATTER_STYLE_SMOOTH = SCATTER_STYLE_SMOOTH;
    window['AscFormat'].SCATTER_STYLE_SMOOTH_MARKER = SCATTER_STYLE_SMOOTH_MARKER;
    window['AscFormat'].CARD_DIRECTION_N = CARD_DIRECTION_N;
    window['AscFormat'].CARD_DIRECTION_NE = CARD_DIRECTION_NE;
    window['AscFormat'].CARD_DIRECTION_E = CARD_DIRECTION_E;
    window['AscFormat'].CARD_DIRECTION_SE = CARD_DIRECTION_SE;
    window['AscFormat'].CARD_DIRECTION_S = CARD_DIRECTION_S;
    window['AscFormat'].CARD_DIRECTION_SW = CARD_DIRECTION_SW;
    window['AscFormat'].CARD_DIRECTION_W = CARD_DIRECTION_W;
    window['AscFormat'].CARD_DIRECTION_NW = CARD_DIRECTION_NW;


    window['AscFormat'].CURSOR_TYPES_BY_CARD_DIRECTION = CURSOR_TYPES_BY_CARD_DIRECTION;
    window['AscFormat'].removeDPtsFromSeries = removeDPtsFromSeries;
    window['AscFormat'].checkTxBodyDefFonts = checkTxBodyDefFonts;
    window['AscFormat'].CheckShapeBodyAutoFitReset = CheckShapeBodyAutoFitReset;
    window['AscFormat'].CDistance = CDistance;
    window['AscFormat'].ConvertRelPositionHToRelSize = ConvertRelPositionHToRelSize;
    window['AscFormat'].ConvertRelPositionVToRelSize = ConvertRelPositionVToRelSize;
    window['AscFormat'].ConvertRelSizeHToRelPosition = ConvertRelSizeHToRelPosition;
    window['AscFormat'].ConvertRelSizeVToRelPosition = ConvertRelSizeVToRelPosition;
    window['AscFormat'].checkObjectInArray = checkObjectInArray;
    window['AscFormat'].getValOrDefault = getValOrDefault;
    window['AscFormat'].CheckStockChart = CheckStockChart;
    window['AscFormat'].CheckLinePreset = CheckLinePreset;
    window['AscFormat'].CompareGroups = CompareGroups;
    window['AscFormat'].CheckSpPrXfrm = CheckSpPrXfrm;
    window['AscFormat'].CheckSpPrXfrm2 = CheckSpPrXfrm2;
    window['AscFormat'].CheckSpPrXfrm3 = CheckSpPrXfrm3;
    window['AscFormat'].getObjectsByTypesFromArr = getObjectsByTypesFromArr;
    window['AscFormat'].getTargetTextObject = getTargetTextObject;
    window['AscFormat'].DrawingObjectsController = DrawingObjectsController;
    window['AscFormat'].CBoundsController = CBoundsController;
    window['AscFormat'].CSlideBoundsChecker = CSlideBoundsChecker;
    window['AscFormat'].GetMinSnapDistanceXObject = GetMinSnapDistanceXObject;
    window['AscFormat'].GetMinSnapDistanceYObject = GetMinSnapDistanceYObject;
    window['AscFormat'].GetMinSnapDistanceXObjectByArrays = GetMinSnapDistanceXObjectByArrays;
    window['AscFormat'].GetMinSnapDistanceYObjectByArrays = GetMinSnapDistanceYObjectByArrays;
    window['AscFormat'].CalcLiterByLength = CalcLiterByLength;
    window['AscFormat'].fillImage = fillImage;
	window['AscFormat'].fSolveQuadraticEquation = fSolveQuadraticEquation;
	window['AscFormat'].fApproxEqual = fApproxEqual;
	window['AscFormat'].fCheckBoxIntersectionSegment = fCheckBoxIntersectionSegment;
	window['AscFormat'].CMathPainter = CMathPainter;
	window['AscFormat'].CollectSettingsFromChart = CollectSettingsFromChart;
	window['AscFormat'].ApplyPresetToChartSpace = ApplyPresetToChartSpace;
	window['AscFormat'].ApplySpPr = ApplySpPr;
	window['AscFormat'].ApplyDLblsProps = ApplyDLblsProps;
	window['AscFormat'].CollectDLbls = CollectDLbls;
	window['AscFormat'].CollectSettingsSpPr = CollectSettingsSpPr;
	window['AscFormat'].CheckLinePresetForParagraphAdd = CheckLinePresetForParagraphAdd;
	window['AscFormat'].isConnectorPreset = isConnectorPreset;
	window['AscFormat'].fCreateSignatureShape = fCreateSignatureShape;
	window['AscFormat'].CreateBlipFillUniFillFromUrl = CreateBlipFillUniFillFromUrl;
	window['AscFormat'].fGetListTypeFromBullet = fGetListTypeFromBullet;
	window['AscFormat'].fGetPresentationBulletByNumInfo = fGetPresentationBulletByNumInfo;
	window['AscFormat'].fGetFontByNumInfo = fGetFontByNumInfo;
	window['AscFormat'].CreateBlipFillRasterImageId = CreateBlipFillRasterImageId;
	window['AscFormat'].fResetConnectorsIds = fResetConnectorsIds;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */


(function(window, undefined){

// Import
var changestype_Drawing_Props = AscCommon.changestype_Drawing_Props;
var changestype_2_ElementsArray_and_Type = AscCommon.changestype_2_ElementsArray_and_Type;
    var History = AscCommon.History;

var HANDLE_EVENT_MODE_HANDLE = AscFormat.HANDLE_EVENT_MODE_HANDLE;
var HANDLE_EVENT_MODE_CURSOR = AscFormat.HANDLE_EVENT_MODE_CURSOR;

var MOVE_DELTA = 1/100000;
var SNAP_DISTANCE = 1.27;

function checkEmptyPlaceholderContent(content)
{
    if(!content || content.Parent && content.Parent.txWarpStruct && content.Parent.recalcInfo.warpGeometry && content.Parent.recalcInfo.warpGeometry.preset !== "textNoShape" )
        return content;
    return null;
}

function StartAddNewShape(drawingObjects, preset)
{
    this.drawingObjects = drawingObjects;
    this.preset = preset;

    this.bStart = false;
    this.bMoved = false;//отошли ли мы от начальной точки

    this.pageIndex = null;
    this.startX = null;
    this.startY = null;

}

StartAddNewShape.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {objectId: null, bMarker: true};

        if(this.bStart){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }

        this.pageIndex = pageIndex;
        this.startX = x;
        this.startY = y;
        this.drawingObjects.arrPreTrackObjects.length = 0;
        this.drawingObjects.arrPreTrackObjects.push(new AscFormat.NewShapeTrack(this.preset, x, y, this.drawingObjects.document.theme, null, null, null, pageIndex));
        this.bStart = true;
        this.drawingObjects.swapTrackObjects();
        return true;
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        if(this.bStart && e.IsLocked)
        {
            if(!this.bMoved && (Math.abs(this.startX - x) > MOVE_DELTA || Math.abs(this.startY - y) > MOVE_DELTA || this.pageIndex !== pageIndex))
                this.bMoved = true;
            var tx, ty;
            if(this.pageIndex !== pageIndex)
            {
                var t = this.drawingObjects.drawingDocument.ConvertCoordsToAnotherPage(x, y, pageIndex, this.pageIndex);
                tx = t.X;
                ty = t.Y;
            }
            else
            {
                tx = x;
                ty = y;
            }
            this.drawingObjects.arrTrackObjects[0].track(e, tx, ty);
            this.drawingObjects.updateOverlay();
        }
    },

    onMouseUp: function(e, x, y, pageIndex)
    {
        if(this.bStart)
        {
            if(!this.bMoved && this instanceof StartAddNewShape)
            {
                var ext_x, ext_y;
                if(typeof AscFormat.SHAPE_EXT[this.preset] === "number")
                {
                    ext_x = AscFormat.SHAPE_EXT[this.preset];
                }
                else
                {
                    ext_x = 25.4;
                }
                if(typeof AscFormat.SHAPE_ASPECTS[this.preset] === "number")
                {
                    var _aspect = AscFormat.SHAPE_ASPECTS[this.preset];
                    ext_y = ext_x/_aspect;
                }
                else
                {
                    ext_y = ext_x;
                }
                this.onMouseMove({IsLocked: true}, this.startX + ext_x, this.startY + ext_y, this.pageIndex);
            }
            History.Create_NewPoint(AscDFH.historydescription_Document_AddNewShape);
            var bounds = this.drawingObjects.arrTrackObjects[0].getBounds();
            var shape = this.drawingObjects.arrTrackObjects[0].getShape(true, this.drawingObjects.drawingDocument);
            var drawing = new ParaDrawing(shape.spPr.xfrm.extX, shape.spPr.xfrm.extY, shape, this.drawingObjects.drawingDocument, this.drawingObjects.document, null);
            var nearest_pos = this.drawingObjects.document.Get_NearestPos(this.pageIndex, bounds.min_x, bounds.min_y, true, drawing);
            if(nearest_pos && false === this.drawingObjects.document.Document_Is_SelectionLocked(AscCommon.changestype_None, {Type : AscCommon.changestype_2_Element_and_Type , Element : nearest_pos.Paragraph, CheckType : AscCommon.changestype_Paragraph_Content} ))
            {
                drawing.Set_DrawingType(drawing_Anchor);
                drawing.Set_GraphicObject(shape);
                shape.setParent(drawing);
                drawing.Set_WrappingType(WRAPPING_TYPE_NONE);
                drawing.Set_Distance( 3.2,  0,  3.2, 0 );
                nearest_pos.Paragraph.Check_NearestPos(nearest_pos);
                nearest_pos.Page = this.pageIndex;

                drawing.Set_XYForAdd(shape.x, shape.y, nearest_pos, this.pageIndex);
                drawing.Add_ToDocument(nearest_pos, false);
                this.drawingObjects.resetSelection();
                shape.select(this.drawingObjects, this.pageIndex);
                this.drawingObjects.document.Recalculate();
                if(this.preset === "textRect")
                {
                    this.drawingObjects.selection.textSelection = shape;
                    shape.selectionSetStart(e, x, y, pageIndex);
                    shape.selectionSetEnd(e, x, y, pageIndex);
                }
            }
            else
            {
                this.drawingObjects.document.Document_Undo();
            }
        }
        this.drawingObjects.clearTrackObjects();
        this.drawingObjects.updateOverlay();
        this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
        editor.sync_StartAddShapeCallback( false );
        editor.sync_EndAddShape();
    }
};


function NullState(drawingObjects)
{
    this.drawingObjects = drawingObjects;
    this.startTargetTextObject = null;
}

NullState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex, bTextFlag)
    {
        var ret;
        var selection = this.drawingObjects.selection;
        var b_no_handle_selected = false;

        this.startTargetTextObject = AscFormat.getTargetTextObject(this.drawingObjects);
        var start_target_doc_content, end_target_doc_content;
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
        {
            this.drawingObjects.setStartTrackPos(x, y, pageIndex);
            start_target_doc_content = checkEmptyPlaceholderContent(this.drawingObjects.getTargetDocContent());
        }

        if(selection.wrapPolygonSelection)
        {
            b_no_handle_selected = true;
            var  object_page_x, object_page_y;
            var coords = AscFormat.CheckCoordsNeedPage(x, y, pageIndex, selection.wrapPolygonSelection.selectStartPage, this.drawingObjects.drawingDocument);
            object_page_x = coords.x;
            object_page_y = coords.y;
            var hit_to_wrap_polygon = selection.wrapPolygonSelection.parent.hitToWrapPolygonPoint(object_page_x, object_page_y);
            var wrap_polygon = selection.wrapPolygonSelection.parent.wrappingPolygon;
            if(hit_to_wrap_polygon.hit)
            {
                if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                {
                    if(hit_to_wrap_polygon.hitType === WRAP_HIT_TYPE_POINT)
                    {
                        if(!e.CtrlKey)
                        {
                            this.drawingObjects.changeCurrentState(new PreChangeWrapContour(this.drawingObjects, selection.wrapPolygonSelection, hit_to_wrap_polygon.pointNum));
                        }
                        else
                        {
                            if(wrap_polygon.relativeArrPoints.length > 3)
                            {
                                if(false === this.drawingObjects.document.Document_Is_SelectionLocked(changestype_Drawing_Props, {Type : AscCommon.changestype_2_Element_and_Type , Element : selection.wrapPolygonSelection.parent.Get_ParentParagraph(), CheckType : AscCommon.changestype_Paragraph_Content}))
                                {
                                    History.Create_NewPoint(AscDFH.historydescription_Document_EditWrapPolygon);
                                    var new_rel_array = [].concat(wrap_polygon.relativeArrPoints);
                                    new_rel_array.splice(hit_to_wrap_polygon.pointNum, 1);
                                    wrap_polygon.setEdited(true);
                                    wrap_polygon.setArrRelPoints(new_rel_array);
                                    this.drawingObjects.document.Recalculate();
                                    this.drawingObjects.updateOverlay();
                                }
                            }
                        }
                        return true;
                    }
                    else
                    {
                        this.drawingObjects.changeCurrentState(new PreChangeWrapContourAddPoint(this.drawingObjects, selection.wrapPolygonSelection, hit_to_wrap_polygon.pointNum1, object_page_x, object_page_y));
                        return true;
                    }
                }
                else
                {
                    return {objectId: selection.wrapPolygonSelection.Get_Id(), cursorType: "default"};
                }
            }
        }
        else if(selection.groupSelection)
        {
            ret = AscFormat.handleSelectedObjects(this.drawingObjects, e, x, y, selection.groupSelection, pageIndex, true);
            if(ret)
            {
                if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                {
                    end_target_doc_content = checkEmptyPlaceholderContent(this.drawingObjects.getTargetDocContent());
                    if((start_target_doc_content || end_target_doc_content) && (start_target_doc_content !== end_target_doc_content))
                    {

                        this.drawingObjects.checkChartTextSelection(true);
                        this.drawingObjects.drawingDocument.OnRecalculatePage( pageIndex, this.drawingObjects.document.Pages[pageIndex] );
                        this.drawingObjects.drawingDocument.OnEndRecalculate( false, true );
                    }
                }
                return ret;
            }

            if(selection.groupSelection.selectStartPage === pageIndex){
                ret = AscFormat.handleFloatObjects(this.drawingObjects, selection.groupSelection.arrGraphicObjects, e, x, y, selection.groupSelection, pageIndex, true);
                if(ret)
                {
                    if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                    {
                        end_target_doc_content = checkEmptyPlaceholderContent(this.drawingObjects.getTargetDocContent());
                        if ((start_target_doc_content || end_target_doc_content) && (start_target_doc_content !== end_target_doc_content))
                        {

                            this.drawingObjects.checkChartTextSelection(true);
                            this.drawingObjects.drawingDocument.OnRecalculatePage(pageIndex, this.drawingObjects.document.Pages[pageIndex]);
                            this.drawingObjects.drawingDocument.OnEndRecalculate(false, true);
                        }
                    }
                    return ret;
                }
            }
        }
        else if(selection.chartSelection)
        {}


        if(!b_no_handle_selected)
        {
            ret = AscFormat.handleSelectedObjects(this.drawingObjects, e, x, y, null, pageIndex, true);
            if(ret)
            {
                if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                {
                    end_target_doc_content = checkEmptyPlaceholderContent(this.drawingObjects.getTargetDocContent());
                    if ((start_target_doc_content || end_target_doc_content) && (start_target_doc_content !== end_target_doc_content))
                    {

                        this.drawingObjects.checkChartTextSelection(true);
                        this.drawingObjects.drawingDocument.OnRecalculatePage(pageIndex, this.drawingObjects.document.Pages[pageIndex]);
                        this.drawingObjects.drawingDocument.OnEndRecalculate(false, true);
                    }
                }
                return ret;
            }
        }

        var drawing_page;
        if(this.drawingObjects.document.Get_DocPosType() !== docpostype_HdrFtr)
        {
            drawing_page = this.drawingObjects.graphicPages[pageIndex];
        }
        else
        {
            drawing_page = this.drawingObjects.getHdrFtrObjectsByPageIndex(pageIndex);
        }
        if(drawing_page)
        {
            ret = AscFormat.handleFloatObjects(this.drawingObjects, drawing_page.beforeTextObjects, e, x, y, null, pageIndex, true);
            if(ret)
            {
                if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                {
                    end_target_doc_content = checkEmptyPlaceholderContent(this.drawingObjects.getTargetDocContent());
                    if ((start_target_doc_content || end_target_doc_content) && (start_target_doc_content !== end_target_doc_content))
                    {
                        this.drawingObjects.checkChartTextSelection(true);
                        this.drawingObjects.drawingDocument.OnRecalculatePage(pageIndex, this.drawingObjects.document.Pages[pageIndex]);
                        this.drawingObjects.drawingDocument.OnEndRecalculate(false, true);
                    }
                }
                return ret;
            }

            var no_shape_child_array = [];
            for(var i = 0; i < drawing_page.inlineObjects.length; ++i)
            {
                if(!(drawing_page.inlineObjects[i].parent && drawing_page.inlineObjects[i].parent.isShapeChild()))
                    no_shape_child_array.push(drawing_page.inlineObjects[i]);
            }
            ret = AscFormat.handleInlineObjects(this.drawingObjects, no_shape_child_array, e, x, y, pageIndex, true);
            if(ret)
            {
                if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                {
                    end_target_doc_content = checkEmptyPlaceholderContent(this.drawingObjects.getTargetDocContent());
                    if ((start_target_doc_content || end_target_doc_content) && (start_target_doc_content !== end_target_doc_content))
                    {
                        this.drawingObjects.checkChartTextSelection(true);
                        this.drawingObjects.drawingDocument.OnRecalculatePage(pageIndex, this.drawingObjects.document.Pages[pageIndex]);
                        this.drawingObjects.drawingDocument.OnEndRecalculate(false, true);
                    }
                }
                return ret;
            }

            if(!bTextFlag)
            {
                ret = AscFormat.handleFloatObjects(this.drawingObjects, drawing_page.behindDocObjects, e, x, y, null, pageIndex, true);
                if(ret)
                {
                    if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                    {
                        end_target_doc_content = checkEmptyPlaceholderContent(this.drawingObjects.getTargetDocContent());
                        if ((start_target_doc_content || end_target_doc_content) && (start_target_doc_content !== end_target_doc_content)) {

                            this.drawingObjects.checkChartTextSelection(true);
                            this.drawingObjects.drawingDocument.OnRecalculatePage(pageIndex, this.drawingObjects.document.Pages[pageIndex]);
                            this.drawingObjects.drawingDocument.OnEndRecalculate(false, true);
                        }
                    }
                    return ret;
                }
            }
        }
        if(start_target_doc_content)
        {
            this.drawingObjects.checkChartTextSelection(true);
            this.drawingObjects.drawingDocument.OnRecalculatePage(pageIndex, this.drawingObjects.document.Pages[pageIndex]);
            this.drawingObjects.drawingDocument.OnEndRecalculate(false, true);
        }
        return null;

    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        var text_object = AscFormat.getTargetTextObject(this.drawingObjects);
        if(text_object && e.IsLocked)
        {
            text_object.selectionSetEnd(e, x, y, pageIndex);
        }
    },

    onMouseUp: function(e, x, y, pageIndex)
    {}
};


function PreChangeAdjState(drawingObjects, majorObject)
{
    this.drawingObjects = drawingObjects;
    this.majorObject = majorObject;
}

PreChangeAdjState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: "default", objectId: this.majorObject.Get_Id()};
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        this.drawingObjects.swapTrackObjects();
        this.drawingObjects.changeCurrentState(new ChangeAdjState(this.drawingObjects, this.majorObject));
        this.drawingObjects.OnMouseMove(e, x, y, pageIndex);
    },

    onMouseUp: function(e, x, y, pageIndex)
    {
        this.drawingObjects.clearPreTrackObjects();
        this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
    }
};

function PreMoveInlineObject(drawingObjects, majorObject, isSelected, bInside, nStartPage, dStartX, dStartY)
{
    this.drawingObjects = drawingObjects;
    this.majorObject = majorObject;
    this.majorObjectIsSelected = isSelected;
    this.bInside = bInside;
    this.nStartPage = nStartPage;
    this.dStartX = dStartX;
    this.dStartY = dStartY;
}

PreMoveInlineObject.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: "default", objectId: this.majorObject.Get_Id()};
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        if(!e.IsLocked)
        {
            this.onMouseUp(e, x, y, pageIndex);
            return;
        }
        if(this.nStartPage !== pageIndex || Math.abs(x - this.dStartX) > MOVE_DELTA || Math.abs(y - this.dStartY) > MOVE_DELTA)
        {
            this.drawingObjects.changeCurrentState(new MoveInlineObject(this.drawingObjects, this.majorObject));
            this.drawingObjects.OnMouseMove(e, x, y, pageIndex);
        }
    },

    onMouseUp: function(e, x,y,pageIndex)
    {
        return AscFormat.handleMouseUpPreMoveState(this.drawingObjects, e, x, y,pageIndex, true);
    }
};


function MoveInlineObject(drawingObjects, majorObject)
{
    this.drawingObjects = drawingObjects;
    this.majorObject = majorObject;
    this.InlinePos = null;
}

MoveInlineObject.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: "default", objectId: this.majorObject.Get_Id()};
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        if(!e.IsLocked)
        {
            this.onMouseUp(e, x, y, pageIndex);
            return;
        }
        this.InlinePos = this.drawingObjects.document.Get_NearestPos(pageIndex, x, y, false, this.majorObject.parent);
        this.InlinePos.Page = pageIndex;
        this.drawingObjects.updateOverlay();
    },

    onMouseUp: function(e, x,y,pageIndex)
    {
        var check_paragraphs = [];
        if(!e.CtrlKey)
        {
            var parent_paragraph = this.majorObject.parent.checkShapeChildAndGetTopParagraph();
            check_paragraphs.push(parent_paragraph);
            var new_check_paragraph = this.majorObject.parent.checkShapeChildAndGetTopParagraph(this.InlinePos.Paragraph);
            if(parent_paragraph !== new_check_paragraph)
                check_paragraphs.push(new_check_paragraph);
            if(false === this.drawingObjects.document.Document_Is_SelectionLocked(changestype_Drawing_Props, {Type : changestype_2_ElementsArray_and_Type , Elements : check_paragraphs, CheckType : AscCommon.changestype_Paragraph_Content}, true))
            {
                History.Create_NewPoint(AscDFH.historydescription_Document_MoveInlineObject);
                this.majorObject.parent.OnEnd_MoveInline(this.InlinePos);
            }
        }
        else
        {
            check_paragraphs.push(this.majorObject.parent.checkShapeChildAndGetTopParagraph(this.InlinePos.Paragraph));
            if(false === this.drawingObjects.document.Document_Is_SelectionLocked(changestype_Drawing_Props, {Type : changestype_2_ElementsArray_and_Type , Elements : check_paragraphs, CheckType : AscCommon.changestype_Paragraph_Content}, true))
            {
                History.Create_NewPoint(AscDFH.historydescription_Document_CopyAndMoveInlineObject);
                var new_para_drawing = new ParaDrawing(this.majorObject.parent.Extent.W, this.majorObject.parent.Extent.H, null, this.drawingObjects.drawingDocument, null, null);
                var drawing = this.majorObject.copy();
                drawing.setParent(new_para_drawing);
                new_para_drawing.Set_GraphicObject(drawing);
                new_para_drawing.Add_ToDocument(this.InlinePos, false);
                this.drawingObjects.resetSelection();
                this.drawingObjects.selectObject(drawing, pageIndex);
                this.drawingObjects.document.Recalculate();
            }
        }
        this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
    }
};




function PreRotateState(drawingObjects, majorObject)
{
    this.drawingObjects = drawingObjects;
    this.majorObject = majorObject;
}

PreRotateState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }

        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: "default", objectId: this.majorObject.Get_Id()};
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        if(!e.IsLocked)
        {
            this.onMouseUp(e, x, y, pageIndex);
            return;
        }
        this.drawingObjects.swapTrackObjects();
        this.drawingObjects.changeCurrentState(new RotateState(this.drawingObjects, this.majorObject));
        this.drawingObjects.OnMouseMove(e, x, y, pageIndex);
    },

    onMouseUp: function(e, x, y, pageIndex)
    {
        this.drawingObjects.clearPreTrackObjects();
        this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
    }
};

function RotateState(drawingObjects, majorObject)
{
    this.drawingObjects = drawingObjects;
    this.majorObject = majorObject;
}

RotateState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }

        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: "crosshair", objectId: this.majorObject.Get_Id()};
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        if(!e.IsLocked)
        {
            this.onMouseUp(e, x, y, pageIndex);
            return;
        }
        var coords = AscFormat.CheckCoordsNeedPage(x, y, pageIndex, this.majorObject.selectStartPage, this.drawingObjects.drawingDocument);
        this.drawingObjects.handleRotateTrack(e, coords.x, coords.y);
    },

    onMouseUp: function(e, x, y, pageIndex)
    {
        var bounds;
        if(this.majorObject.parent.Is_Inline())
        {
            if(this.drawingObjects.document.Document_Is_SelectionLocked(changestype_Drawing_Props) === false)
            {
                History.Create_NewPoint(AscDFH.historydescription_Document_RotateInlineDrawing);
                this.drawingObjects.arrTrackObjects[0].trackEnd(true);
                if(!this.drawingObjects.arrTrackObjects[0].view3D)
                {
                    this.majorObject.parent.CheckWH();
                }
                this.drawingObjects.document.Recalculate();
            }
        }
        else
        {
            var aCheckParagraphs = [], aNearestPos = [], aParentParagraphs = [], aBounds = [], aDrawings = [], bMoveState = (this instanceof MoveState), nearest_pos;
            var i, j, page_index, para_drawing;
            for(i = 0; i < this.drawingObjects.arrTrackObjects.length; ++i)
            {
                aDrawings[i] = this.drawingObjects.arrTrackObjects[i].originalObject.parent;
                bounds = this.drawingObjects.arrTrackObjects[i].getBounds();
                aBounds.push(bounds);
                page_index = AscFormat.isRealNumber(this.drawingObjects.arrTrackObjects[i].pageIndex) ? this.drawingObjects.arrTrackObjects[i].pageIndex : this.drawingObjects.arrTrackObjects[i].originalObject.parent.pageIndex;
                nearest_pos = this.drawingObjects.document.Get_NearestPos(page_index, bounds.min_x, bounds.min_y, true, this.drawingObjects.arrTrackObjects[i].originalObject.parent);
                aNearestPos.push(nearest_pos);
                aParentParagraphs.push(aDrawings[i].Get_ParentParagraph());
            }
            if(bMoveState && e.CtrlKey)
            {
                for(i = 0; i < aNearestPos.length; ++i)
                {
                    if(aDrawings[i].Locked !== true)
                        AscFormat.checkObjectInArray(aCheckParagraphs, aNearestPos[i].Paragraph);
                    else
                        AscFormat.checkObjectInArray(aCheckParagraphs, aParentParagraphs[i]);
                }
                if(false === this.drawingObjects.document.Document_Is_SelectionLocked(changestype_Drawing_Props, {Type : changestype_2_ElementsArray_and_Type , Elements : aCheckParagraphs, CheckType : AscCommon.changestype_Paragraph_Content}))
                {
                    this.drawingObjects.resetSelection();
                    History.Create_NewPoint(AscDFH.historydescription_Document_RotateFlowDrawingCtrl);
                    for(i = 0; i < this.drawingObjects.arrTrackObjects.length; ++i)
                    {
                        bounds = aBounds[i];
                        para_drawing = aDrawings[i].Copy();
                        para_drawing.Set_RelativeHeight(this.drawingObjects.getZIndex());
                        if(aDrawings[i].Locked !== true)
                        {
                            aNearestPos[i].Paragraph.Check_NearestPos(aNearestPos[i]);
                            para_drawing.Set_XYForAdd(bounds.posX, bounds.posY, aNearestPos[i], pageIndex);
                            para_drawing.Add_ToDocument(aNearestPos[i], false);
                        }
                        else
                        {
                            para_drawing.Set_XY(bounds.posX, bounds.posY, aDrawings[i].Get_ParentParagraph(), pageIndex, true);
                            para_drawing.Add_ToDocument2(aDrawings[i].Get_ParentParagraph());
                        }
                        this.drawingObjects.selectObject(para_drawing.GraphicObj, pageIndex);
                    }
                    this.drawingObjects.document.Recalculate();
                }
            }
            else
            {
                var bNoNeedCheck = false;
                if(bMoveState)
                {
                    bNoNeedCheck = true;
                    for(i = 0; i < aNearestPos.length; ++i)
                    {
                        if(aNearestPos[i].Paragraph !== aParentParagraphs[i] && aDrawings[i].Locked !== true)
                        {
                            AscFormat.checkObjectInArray(aCheckParagraphs, aNearestPos[i].Paragraph);
                            AscFormat.checkObjectInArray(aCheckParagraphs, aParentParagraphs[i]);
                        }
                        else{
                            bNoNeedCheck = false;
                        }
                    }
                }
                if(false === this.drawingObjects.document.Document_Is_SelectionLocked(changestype_Drawing_Props, {Type : changestype_2_ElementsArray_and_Type , Elements : aCheckParagraphs, CheckType : AscCommon.changestype_Paragraph_Content}, bNoNeedCheck))
                {
                    History.Create_NewPoint(AscDFH.historydescription_Document_RotateFlowDrawingNoCtrl);
                    if(bMoveState){
                        this.drawingObjects.resetSelection();
                    }
                    for(i = 0; i < aDrawings.length; ++i)
                    {
                        bounds = aBounds[i];
                        this.drawingObjects.arrTrackObjects[i].trackEnd(true);
                        var original = aDrawings[i];
                        if(!bMoveState && !this.drawingObjects.arrTrackObjects[i].view3D)
                        {
                            original.CheckWH();
                        }
                        if(bMoveState && aNearestPos[i].Paragraph !== aParentParagraphs[i] && aDrawings[i].Locked !== true)
                        {
                            // На удалении включаем пересчет из-за бага (28015), чтобы во время добавления автофигуры на эту же страницу
                            // расположение всех элементов было рассчитано с уже удаленной автофигурой.

                            // Автофигуры мы переносим так, как будто это происходит не в режиме рецензирования, но
                            // при этом мы должны сохранить их начальные настройки рецензирования.
                            var bTrackRevisions = this.drawingObjects.document.Is_TrackRevisions();
                            if (bTrackRevisions)
                                this.drawingObjects.document.Set_TrackRevisions(false);

                            var oOriginalRun = original.Parent.Get_DrawingObjectRun(original.Id);

                            original.Remove_FromDocument(false);
                            aNearestPos[i].Paragraph.Check_NearestPos(aNearestPos[i]);

                            // Всегда создаем копию при переносе, чтобы не было проблем при совместном редактировании
                            var originalCopy = original.Copy();
                            originalCopy.Set_XYForAdd(bounds.posX, bounds.posY, aNearestPos[i], pageIndex);
                            originalCopy.Add_ToDocument(aNearestPos[i], false, null, oOriginalRun);

                            if (bTrackRevisions)
                                this.drawingObjects.document.Set_TrackRevisions(true);

                            this.drawingObjects.selectObject(originalCopy.GraphicObj, pageIndex);
                        }
                        else
                        {
                            if(true !== this.drawingObjects.arrTrackObjects[i].bTextWarp)
                            {
                                original.Set_XY(bounds.posX, bounds.posY, aParentParagraphs[i], original.GraphicObj.selectStartPage, bMoveState)
                            }
                            if(bMoveState){
                                this.drawingObjects.selectObject(original.GraphicObj, pageIndex);
                            }
                        }
                        this.drawingObjects.document.Recalculate();
                    }
                }
            }
        }
        this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
        this.drawingObjects.clearTrackObjects();
        this.drawingObjects.updateOverlay();
    }
};


function ChangeAdjState(drawingObjects, majorObject)
{
    this.drawingObjects = drawingObjects;
    this.majorObject = majorObject;
}

ChangeAdjState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }

        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: "crosshair", objectId: this.majorObject.Get_Id()};
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        if(!e.IsLocked)
        {
            this.onMouseUp(e, x, y, pageIndex);
            return;
        }
        var t = AscFormat.CheckCoordsNeedPage(x, y, pageIndex, this.majorObject.selectStartPage, this.drawingObjects.drawingDocument);
        this.drawingObjects.arrTrackObjects[0].track(t.x, t.y);
        this.drawingObjects.updateOverlay();
    },

    onMouseUp:  RotateState.prototype.onMouseUp
};


function PreResizeState(drawingObjects, majorObject, cardDirection)
{
    this.drawingObjects = drawingObjects;
    this.majorObject = majorObject;
    this.cardDirection = cardDirection;
    this.handleNum = this.majorObject.getNumByCardDirection(cardDirection);
}

PreResizeState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: "default", objectId: this.majorObject.Get_Id()};
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        if(!e.IsLocked)
        {
            this.onMouseUp(e, x, y, pageIndex);
            return;
        }
        this.drawingObjects.swapTrackObjects();
        this.drawingObjects.changeCurrentState(new ResizeState(this.drawingObjects, this.majorObject, this.handleNum, this.cardDirection));
        this.drawingObjects.OnMouseMove(e, x, y, pageIndex);
    },

    onMouseUp: function(e, x, y, pageIndex)
    {
        this.drawingObjects.clearPreTrackObjects();
        this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
    }
};

function ResizeState(drawingObjects, majorObject, handleNum, cardDirection)
{
    this.drawingObjects = drawingObjects;
    this.majorObject  = majorObject;
    this.handleNum = handleNum;
    this.cardDirection = cardDirection;
}

ResizeState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: AscFormat.CURSOR_TYPES_BY_CARD_DIRECTION[this.cardDirection] ? AscFormat.CURSOR_TYPES_BY_CARD_DIRECTION[this.cardDirection] : "default", objectId: this.majorObject.Get_Id()};
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        if(!e.IsLocked)
        {
            this.onMouseUp(e, x, y, pageIndex);
            return;
        }
        var coords = AscFormat.CheckCoordsNeedPage(x, y, pageIndex, this.majorObject.selectStartPage, this.drawingObjects.drawingDocument);
        var resize_coef = this.majorObject.getResizeCoefficients(this.handleNum, coords.x, coords.y);
        this.drawingObjects.trackResizeObjects(resize_coef.kd1, resize_coef.kd2, e);
        this.drawingObjects.updateOverlay();
    },

    onMouseUp: RotateState.prototype.onMouseUp
};


function PreMoveState(drawingObjects,  startX, startY, shift, ctrl, majorObject, majorObjectIsSelected, bInside)
{
    this.drawingObjects = drawingObjects;
    this.majorObject = majorObject;
    this.startX = startX;
    this.startY = startY;
    this.shift = shift;
    this.ctrl = ctrl;
    this.majorObjectIsSelected = majorObjectIsSelected;
    this.bInside = bInside;
}

PreMoveState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: "default", objectId: this.majorObject.Get_Id()};
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        if(!e.IsLocked)
        {
            this.onMouseUp(e, x, y, pageIndex);
            return;
        }
        if(Math.abs(this.startX - x) > MOVE_DELTA || Math.abs(this.startY - y) > MOVE_DELTA || pageIndex !== this.majorObject.parent.pageIndex)
        {
            this.drawingObjects.swapTrackObjects();
            this.drawingObjects.changeCurrentState(new MoveState(this.drawingObjects, this.majorObject, this.startX, this.startY));
            this.drawingObjects.OnMouseMove(e, x, y, pageIndex);
        }
    },

    onMouseUp: function(e, x, y, pageIndex)
    {
        return AscFormat.handleMouseUpPreMoveState(this.drawingObjects, e, x, y, pageIndex, true)
    }
};

function MoveState(drawingObjects, majorObject, startX, startY)
{
    this.drawingObjects = drawingObjects;
    this.majorObject = majorObject;

    this.startX = startX;
    this.startY = startY;
}

MoveState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: "default", objectId: this.majorObject.Get_Id()};
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        if(!e.IsLocked)
        {
            this.onMouseUp(e, x, y, pageIndex);
            return;
        }
        var _arr_track_objects = this.drawingObjects.arrTrackObjects;
        var _objects_count = _arr_track_objects.length;
        var _object_index;

        var result_x, result_y;
        if(!e.ShiftKey)
        {
            result_x = x;
            result_y = y;
        }
        else
        {
            var abs_dist_x = Math.abs(this.startX - x);
            var abs_dist_y = Math.abs(this.startY - y);
            if(abs_dist_x > abs_dist_y)
            {
                result_x = x;
                result_y = this.startY;
            }
            else
            {
                result_x = this.startX;
                result_y = y;
            }
        }

        var t = AscFormat.CheckCoordsNeedPage(x, y, pageIndex, this.majorObject.selectStartPage, this.drawingObjects.drawingDocument);

        var startPage = this.drawingObjects.graphicPages[this.majorObject.selectStartPage];
        var startPos = {x: this.startX, y: this.startY};
        var start_arr = startPage.beforeTextObjects.concat(startPage.inlineObjects, startPage.behindDocObjects);
        var min_dx = null, min_dy = null;
        var dx, dy;
        var snap_x = null, snap_y = null;

        var snapHorArray = [], snapVerArray = [];

        var page = this.drawingObjects.document.Pages[pageIndex];
        snapHorArray.push(page.Margins.Left);
        snapHorArray.push(page.Margins.Right);
        snapHorArray.push(page.Width/2);
        snapVerArray.push(page.Margins.Top);
        snapVerArray.push(page.Margins.Bottom);
        snapVerArray.push(page.Height/2);
        if(result_x === this.startX)
        {
            min_dx = 0;
        }
        else
        {
            for(var track_index = 0; track_index < _arr_track_objects.length; ++track_index)
            {
                var cur_track_original_shape = _arr_track_objects[track_index].originalObject;
                var trackSnapArrayX = cur_track_original_shape.snapArrayX;
                var curDX =  result_x - startPos.x;


                for(snap_index = 0; snap_index < trackSnapArrayX.length; ++snap_index)
                {
                    var snap_obj = AscFormat.GetMinSnapDistanceXObjectByArrays(trackSnapArrayX[snap_index] + curDX, snapHorArray);
                    if(AscCommon.isRealObject(snap_obj))
                    {
                        dx = snap_obj.dist;
                        if(dx !== null)
                        {
                            if(min_dx === null)
                            {
                                min_dx = dx;
                                snap_x = snap_obj.pos;
                            }
                            else
                            {
                                if(Math.abs(min_dx) > Math.abs(dx))
                                {
                                    min_dx = dx;
                                    snap_x = snap_obj.pos;
                                }
                            }
                        }
                    }
                }

                if(start_arr.length > 0)
                {
                    for(var snap_index = 0; snap_index < trackSnapArrayX.length; ++snap_index)
                    {
                        var snap_obj = AscFormat.GetMinSnapDistanceXObject(trackSnapArrayX[snap_index] + curDX, start_arr);
                        if(AscCommon.isRealObject(snap_obj))
                        {
                            dx = snap_obj.dist;
                            if(dx !== null)
                            {
                                if(min_dx === null)
                                {
                                    snap_x = snap_obj.pos;
                                    min_dx = dx;
                                }
                                else
                                {
                                    if(Math.abs(min_dx) > Math.abs(dx))
                                    {
                                        min_dx = dx;
                                        snap_x = snap_obj.pos;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        if(result_y === this.startY)
        {
            min_dy = 0;
        }
        else
        {
            for(track_index = 0; track_index < _arr_track_objects.length; ++track_index)
            {
                cur_track_original_shape = _arr_track_objects[track_index].originalObject;
                var trackSnapArrayY = cur_track_original_shape.snapArrayY;
                var curDY =  result_y - startPos.y;


                for(snap_index = 0; snap_index < trackSnapArrayY.length; ++snap_index)
                {
                    var snap_obj = AscFormat.GetMinSnapDistanceYObjectByArrays(trackSnapArrayY[snap_index] + curDY, snapVerArray);
                    if(AscCommon.isRealObject(snap_obj))
                    {
                        dy = snap_obj.dist;
                        if(dy !== null)
                        {
                            if(min_dy === null)
                            {
                                min_dy = dy;
                                snap_y = snap_obj.pos;
                            }
                            else
                            {
                                if(Math.abs(min_dy) > Math.abs(dy))
                                {
                                    min_dy = dy;
                                    snap_y = snap_obj.pos;
                                }
                            }
                        }
                    }
                }

                if(start_arr.length > 0)
                {
                    for(snap_index = 0; snap_index < trackSnapArrayY.length; ++snap_index)
                    {
                        var snap_obj = AscFormat.GetMinSnapDistanceYObject(trackSnapArrayY[snap_index] + curDY, start_arr);
                        if(AscCommon.isRealObject(snap_obj))
                        {
                            dy = snap_obj.dist;
                            if(dy !== null)
                            {
                                if(min_dy === null)
                                {
                                    min_dy = dy;
                                    snap_y = snap_obj.pos;
                                }
                                else
                                {
                                    if(Math.abs(min_dy) > Math.abs(dy))
                                    {
                                        min_dy = dy;
                                        snap_y = snap_obj.pos;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }



        if(min_dx === null || Math.abs(min_dx) > SNAP_DISTANCE)
            min_dx = 0;
        else
        {
            if(AscFormat.isRealNumber(snap_x))
            {
                this.drawingObjects.drawingDocument.DrawVerAnchor(pageIndex, snap_x);
            }
        }

        if(min_dy === null || Math.abs(min_dy) > SNAP_DISTANCE)
            min_dy = 0;
        else
        {
            if(AscFormat.isRealNumber(snap_y))
            {
                this.drawingObjects.drawingDocument.DrawHorAnchor(pageIndex, snap_y);
            }
        }

        for(_object_index = 0; _object_index < _objects_count; ++_object_index)
            _arr_track_objects[_object_index].track(result_x - this.startX + min_dx, result_y - this.startY + min_dy, pageIndex);
        this.drawingObjects.updateOverlay();
    },

    onMouseUp: RotateState.prototype.onMouseUp
};

function PreMoveInGroupState(drawingObjects, group, startX, startY, ShiftKey, CtrlKey, majorObject,  majorObjectIsSelected)
{
    this.drawingObjects = drawingObjects;
    this.group = group;
    this.startX = startX;
    this.startY = startY;
    this.ShiftKey = ShiftKey;
    this.CtrlKey  = CtrlKey;
    this.majorObject = majorObject;
    this.majorObjectIsSelected = majorObjectIsSelected;


}

PreMoveInGroupState.prototype =
{
    onMouseDown: function(e, x,y,pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: "default", objectId: this.majorObject.Get_Id()};
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        if(!e.IsLocked)
        {
            this.onMouseUp(e, x, y, pageIndex);
            return;
        }
        if(Math.abs(this.startX - x) > MOVE_DELTA || Math.abs(this.startY - y) > MOVE_DELTA || pageIndex !== this.group.parent.pageIndex)
        {
            this.drawingObjects.swapTrackObjects();
            this.drawingObjects.changeCurrentState(new MoveInGroupState(this.drawingObjects, this.majorObject, this.group, this.startX, this.startY));
            this.drawingObjects.OnMouseMove(e, x, y, pageIndex);
        }
    },

    onMouseUp: function(e, x, y, pageIndex)
    {
        if(e.CtrlKey && this.majorObjectIsSelected)
        {
            this.group.deselectObject(this.majorObject);
            if(this.group.selectedObjects.length === 0){
                this.drawingObjects.resetInternalSelection();
            }
            this.drawingObjects.document && this.drawingObjects.document.Document_UpdateInterfaceState();
            this.drawingObjects.updateOverlay();
        }
        this.drawingObjects.clearPreTrackObjects();
        this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
    }
};

function MoveInGroupState(drawingObjects, majorObject, group, startX, startY)
{
    this.drawingObjects = drawingObjects;
    this.majorObject = majorObject;
    this.group = group;
    this.startX = startX;
    this.startY = startY;
}

MoveInGroupState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: "default", objectId: this.majorObject.Get_Id()};
    },

    onMouseMove: MoveState.prototype.onMouseMove,

    onMouseUp: function(e, x, y, pageIndex)
    {
        History.Create_NewPoint(AscDFH.historydescription_Document_MoveInGroup);
        var old_x = this.group.bounds.x;
        var old_y = this.group.bounds.y;
        var i;
        var tracks = this.drawingObjects.arrTrackObjects;
        if(this instanceof MoveInGroupState && e.CtrlKey)
        {
            this.group.resetSelection();
            for(i = 0; i < tracks.length; ++i)
            {
                var copy = tracks[i].originalObject.copy();
                copy.setGroup(tracks[i].originalObject.group);
                copy.group.addToSpTree(copy.group.length, copy);
                tracks[i].originalObject = copy;
                tracks[i].trackEnd(true);
                this.group.selectObject(copy, 0);
            }
        }
        else
        {
            for(i = 0; i < this.drawingObjects.arrTrackObjects.length; ++i)
            {
                this.drawingObjects.arrTrackObjects[i].trackEnd(true);
            }
        }
        var oPosObject = this.group.updateCoordinatesAfterInternalResize();
        this.group.recalculate();
        var bounds = this.group.bounds;
        var check_paragraphs = [];
        check_paragraphs.push(this.group.parent.Get_ParentParagraph());
        var posX = oPosObject.posX;
        var posY = oPosObject.posY;
        this.group.spPr.xfrm.setOffX(0);
        this.group.spPr.xfrm.setOffY(0);
        if(this.group.parent.Is_Inline())
        {
            this.group.parent.CheckWH();
        }
        else
        {
            this.group.parent.CheckWH();
            this.group.parent.Set_XY(this.group.posX + posX, this.group.posY + posY, check_paragraphs[0], this.group.parent.pageIndex, false);
            check_paragraphs.length = 0;
         }
        if(false === this.drawingObjects.document.Document_Is_SelectionLocked(changestype_Drawing_Props, {Type : changestype_2_ElementsArray_and_Type , Elements : check_paragraphs, CheckType : AscCommon.changestype_Paragraph_Content}))
        {
            this.drawingObjects.document.Recalculate();
        }
        else
        {
            this.drawingObjects.document.Document_Undo();
        }
        this.drawingObjects.clearTrackObjects();
        this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
    }
};


function PreRotateInGroupState(drawingObjects, group, majorObject)
{
    this.drawingObjects = drawingObjects;
    this.group = group;
    this.majorObject = majorObject;
}

PreRotateInGroupState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: "default", objectId: this.majorObject.Get_Id()};
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        if(!e.IsLocked)
        {
            this.onMouseUp(e, x, y, pageIndex);
            return;
        }
        this.drawingObjects.swapTrackObjects();
        this.drawingObjects.changeCurrentState(new RotateInGroupState(this.drawingObjects, this.group, this.majorObject))
    },

    onMouseUp: PreMoveInGroupState.prototype.onMouseUp
};

function RotateInGroupState(drawingObjects, group, majorObject)
{
    this.drawingObjects = drawingObjects;
    this.group = group;
    this.majorObject = majorObject;
}

RotateInGroupState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: "crosshair", objectId: this.majorObject.Get_Id()};
    },

    onMouseMove: RotateState.prototype.onMouseMove,

    onMouseUp: MoveInGroupState.prototype.onMouseUp
};

function PreResizeInGroupState(drawingObjects, group, majorObject, cardDirection)
{
    this.drawingObjects = drawingObjects;
    this.group = group;
    this.majorObject = majorObject;
    this.cardDirection = cardDirection;
}

PreResizeInGroupState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: "default", objectId: this.majorObject.Get_Id()};
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        this.drawingObjects.swapTrackObjects();
        this.drawingObjects.changeCurrentState(new ResizeInGroupState(this.drawingObjects, this.group, this.majorObject, this.majorObject.getNumByCardDirection(this.cardDirection), this.cardDirection));
        this.drawingObjects.OnMouseMove(e, x, y, pageIndex);
    },

    onMouseUp: PreMoveInGroupState.prototype.onMouseUp
};

function ResizeInGroupState(drawingObjects, group, majorObject, handleNum, cardDirection)
{
    this.drawingObjects = drawingObjects;
    this.group = group;
    this.majorObject = majorObject;
    this.handleNum = handleNum;
    this.cardDirection = cardDirection;
}

ResizeInGroupState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: AscFormat.CURSOR_TYPES_BY_CARD_DIRECTION[this.cardDirection] ? AscFormat.CURSOR_TYPES_BY_CARD_DIRECTION[this.cardDirection] : "default", objectId: this.majorObject.Get_Id()};
    },
    onMouseMove: ResizeState.prototype.onMouseMove,
    onMouseUp: MoveInGroupState.prototype.onMouseUp
};

function PreChangeAdjInGroupState(drawingObjects, group)
{
    this.drawingObjects = drawingObjects;
    this.group = group;
}

PreChangeAdjInGroupState.prototype =
{
    onMouseDown: function(e, x, y,pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        this.drawingObjects.swapTrackObjects();
        this.drawingObjects.changeCurrentState(new ChangeAdjInGroupState(this.drawingObjects, this.group));
        this.drawingObjects.OnMouseMove(e, x, y, pageIndex);
    },

    onMouseUp: PreMoveInGroupState.prototype.onMouseUp
};

function ChangeAdjInGroupState(drawingObjects, group)
{
    this.drawingObjects = drawingObjects;
    this.group = group;
    this.majorObject = drawingObjects.arrTrackObjects[0].originalShape;
}

ChangeAdjInGroupState.prototype =
{
    onMouseDown: function(e, x, y,pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {cursorType: "crosshair", objectId: this.majorObject.Get_Id()};
    },

    onMouseMove: ChangeAdjState.prototype.onMouseMove,

    onMouseUp: MoveInGroupState.prototype.onMouseUp
};

function TextAddState(drawingObjects, majorObject)
{
    this.drawingObjects =drawingObjects;
    this.majorObject = majorObject;
}

TextAddState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR){
            var oCheckObject = this.majorObject;
            if(oCheckObject instanceof AscFormat.CTitle){
                oCheckObject = oCheckObject.chart;
            }

            if(oCheckObject && oCheckObject.group){
                while(!oCheckObject.group){
                    oCheckObject = oCheckObject.group;
                }
            }
            if(oCheckObject && oCheckObject.parent){
                return {cursorType: "default", objectId: oCheckObject.Get_Id()};
            }
        }
    },
    onMouseMove: function(e, x, y, pageIndex)
    {
        var startPos = this.drawingObjects.startTrackPos;
        var tr_x, tr_y;
        if(pageIndex === startPos.pageIndex)
        {
            tr_x = x;
            tr_y = y;
        }
        else
        {
            var tr_point = this.drawingObjects.getDrawingDocument().ConvertCoordsToAnotherPage(x, y, pageIndex, startPos.pageIndex);
            tr_x = tr_point.X;
            tr_y = tr_point.Y;
        }

        if(!e.IsLocked)
        {
            this.onMouseUp(e, tr_x, tr_y, startPos.pageIndex);
            return;
        }
        this.majorObject.selectionSetEnd(e, tr_x, tr_y, startPos.pageIndex);
    },
    onMouseUp: function(e, x, y, pageIndex)
    {
        var startPos = this.drawingObjects.startTrackPos;
        var tr_x, tr_y;
        if(pageIndex === startPos.pageIndex)
        {
            tr_x = x;
            tr_y = y;
        }
        else
        {
            var tr_point = this.drawingObjects.getDrawingDocument().ConvertCoordsToAnotherPage(x, y, pageIndex, startPos.pageIndex);
            tr_x = tr_point.X;
            tr_y = tr_point.Y;
        }

        this.majorObject.selectionSetEnd(e, tr_x, tr_y, startPos.pageIndex);
        this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
    }

};



function StartChangeWrapContourState(drawingObjects, majorObject)
{
    this.drawingObjects = drawingObjects;
    this.majorObject = majorObject;
}

StartChangeWrapContourState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {

    },

    onMouseMove: function(e, x, y, pageIndex)
    {},

    onMouseUp: function(e, x, y, pageIndex)
    {}
};

function PreChangeWrapContour(drawingObjects, majorObject, pointNum)
{
    this.drawingObjects = drawingObjects;
    this.majorObject = majorObject;
    this.pointNum = pointNum;
}

PreChangeWrapContour.prototype.onMouseDown = function(e, x, y, pageIndex)
{
    if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
        this.onMouseUp(e, x, y, pageIndex);
        this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
    }
};
PreChangeWrapContour.prototype.onMouseMove = function(e, x, y, pageIndex)
{
    this.drawingObjects.clearPreTrackObjects();
    this.drawingObjects.addPreTrackObject(new TrackPointWrapPointWrapPolygon(this.majorObject, this.pointNum));
    this.drawingObjects.swapTrackObjects();
    this.drawingObjects.changeCurrentState(new ChangeWrapContour(this.drawingObjects, this.majorObject));
};
PreChangeWrapContour.prototype.onMouseUp =  function(e, x, y, pageIndex)
{
    this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
};



function ChangeWrapContour(drawingObjects, majorObject)
{
    this.drawingObjects = drawingObjects;
    this.majorObject = majorObject;
}



ChangeWrapContour.prototype.onMouseDown = function(e, x, y, pageIndex)
{
    if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
        this.onMouseUp(e, x, y, pageIndex);
        this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
    }
};
ChangeWrapContour.prototype.onMouseMove = function(e, x, y, pageIndex)
{
    var coords = AscFormat.CheckCoordsNeedPage(x, y, pageIndex, this.majorObject.selectStartPage);
    var tr_x, tr_y;
    tr_x = coords.x;
    tr_y = coords.y;
    this.drawingObjects.arrTrackObjects[0].track(tr_x, tr_y);
    this.drawingObjects.updateOverlay();
};
ChangeWrapContour.prototype.onMouseUp = function(e, x, y, pageIndex)
{
    if(false === this.drawingObjects.document.Document_Is_SelectionLocked(changestype_Drawing_Props))
    {
        History.Create_NewPoint(AscDFH.historydescription_Document_ChangeWrapContour);
        var calc_points = [], calc_points2 = [], i;
        for(i = 0; i < this.majorObject.parent.wrappingPolygon.calculatedPoints.length; ++i)
        {
            calc_points[i] = {x: this.majorObject.parent.wrappingPolygon.calculatedPoints[i].x, y: this.majorObject.parent.wrappingPolygon.calculatedPoints[i].y};
        }
        calc_points[this.drawingObjects.arrTrackObjects[0].point].x = this.drawingObjects.arrTrackObjects[0].pointCoord.x;
        calc_points[this.drawingObjects.arrTrackObjects[0].point].y = this.drawingObjects.arrTrackObjects[0].pointCoord.y;
        var invert_transform = this.majorObject.invertTransform;
        for(i = 0; i < calc_points.length; ++i)
        {
            calc_points2[i] =
            {
                x: (invert_transform.TransformPointX(calc_points[i].x, calc_points[i].y)/this.majorObject.extX)*21600 >> 0,
                y: (invert_transform.TransformPointY(calc_points[i].x, calc_points[i].y)/this.majorObject.extY)*21600 >> 0
            }
        }
        this.majorObject.parent.wrappingPolygon.setEdited(true);
        this.majorObject.parent.wrappingPolygon.setArrRelPoints(calc_points2);
        this.drawingObjects.document.Recalculate();
    }
    this.drawingObjects.clearTrackObjects();
    this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
};

function PreChangeWrapContourAddPoint(drawingObjects, majorObject, pointNum1, startX, startY)
{
    this.drawingObjects = drawingObjects;
    this.majorObject = majorObject;
    this.pointNum1 = pointNum1;
    this.startX = startX;
    this.startY = startY;
}

PreChangeWrapContourAddPoint.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
            this.onMouseUp(e, x, y, pageIndex);
            this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
        }
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        if(!e.IsLocked)
        {
            this.onMouseUp(e, x, y, pageIndex);
            return;
        }
        this.drawingObjects.clearPreTrackObjects();
        this.drawingObjects.addPreTrackObject(new TrackNewPointWrapPolygon(this.majorObject, this.pointNum1));
        this.drawingObjects.swapTrackObjects();
        this.drawingObjects.changeCurrentState(new ChangeWrapContourAddPoint(this.drawingObjects, this.majorObject));
        this.drawingObjects.OnMouseMove(e, x, y, pageIndex);
    },

    onMouseUp: function(e, x, y, pageIndex)
    {
        this.drawingObjects.clearPreTrackObjects();
        this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
    }
};



function ChangeWrapContourAddPoint(drawingObjects, majorObject)
{
    this.drawingObjects = drawingObjects;
    this.majorObject = majorObject;
}



ChangeWrapContourAddPoint.prototype.onMouseDown = function(e, x, y, pageIndex)
{
    if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE){
        this.onMouseUp(e, x, y, pageIndex);
        this.drawingObjects.OnMouseDown(e, x, y, pageIndex);
    }
};
ChangeWrapContourAddPoint.prototype.onMouseMove = function(e, x, y, pageIndex)
{
    var coords = AscFormat.CheckCoordsNeedPage(x, y, pageIndex, this.majorObject.selectStartPage);
    var tr_x, tr_y;
    tr_x = coords.x;
    tr_y = coords.y;
    this.drawingObjects.arrTrackObjects[0].track(tr_x, tr_y);
    this.drawingObjects.updateOverlay();
};
ChangeWrapContourAddPoint.prototype.onMouseUp = function(e, x, y, pageIndex)
{
    if(false === this.drawingObjects.document.Document_Is_SelectionLocked(changestype_Drawing_Props))
    {
        History.Create_NewPoint(AscDFH.historydescription_Document_ChangeWrapContourAddPoint);
        var calc_points = [], calc_points2 = [], i;
        for(i = 0; i < this.drawingObjects.arrTrackObjects[0].arrPoints.length; ++i)
        {
            calc_points[i] = {x: this.drawingObjects.arrTrackObjects[0].arrPoints[i].x, y: this.drawingObjects.arrTrackObjects[0].arrPoints[i].y};
        }
        //calc_points.splice(this.drawingObjects.arrTrackObjects[0].point1, 0, )
        var invert_transform = this.majorObject.invertTransform;
        for(i = 0; i < calc_points.length; ++i)
        {
            calc_points2[i] =
            {
                x: (invert_transform.TransformPointX(calc_points[i].x, calc_points[i].y)/this.majorObject.extX)*21600 >> 0,
                y: (invert_transform.TransformPointY(calc_points[i].x, calc_points[i].y)/this.majorObject.extY)*21600 >> 0
            }
        }
        this.majorObject.parent.wrappingPolygon.setEdited(true);
        this.majorObject.parent.wrappingPolygon.setArrRelPoints(calc_points2);
        this.drawingObjects.document.Recalculate();
    }
    this.drawingObjects.clearTrackObjects();
    this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
};


function SplineBezierState(drawingObjects)
{
    this.drawingObjects = drawingObjects;
    this.polylineFlag = true;

}
SplineBezierState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {objectId: null, bMarker: true};
        this.drawingObjects.startTrackPos = {x: x, y: y, pageIndex: pageIndex};
        this.drawingObjects.clearTrackObjects();
        this.drawingObjects.addTrackObject(new AscFormat.Spline(this.drawingObjects, this.drawingObjects.document.theme, null, null, null, pageIndex));
        this.drawingObjects.arrTrackObjects[0].path.push(new AscFormat.SplineCommandMoveTo(x, y));
        this.drawingObjects.changeCurrentState(new SplineBezierState33(this.drawingObjects, x, y,pageIndex));
        this.drawingObjects.resetSelection();
        this.drawingObjects.updateOverlay();
    },

    onMouseMove: function(e, X, Y, pageIndex)
    {
    },

    onMouseUp: function(e, X, Y, pageIndex)
    {
        this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
    }
};


function SplineBezierState33(drawingObjects, startX, startY, pageIndex)
{
    this.drawingObjects = drawingObjects;
    this.polylineFlag = true;
    this.pageIndex = pageIndex;
}

SplineBezierState33.prototype =
{

    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {objectId: null, bMarker: true};
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        var startPos = this.drawingObjects.startTrackPos;
        if(startPos.x === x && startPos.y === y && startPos.pageIndex === pageIndex)
            return;

        var tr_x, tr_y;
        if(pageIndex === startPos.pageIndex)
        {
            tr_x = x;
            tr_y = y;
        }
        else
        {
            var tr_point = this.drawingObjects.drawingDocument.ConvertCoordsToAnotherPage(x, y, pageIndex, startPos.pageIndex);
            tr_x = tr_point.X;
            tr_y = tr_point.Y;
        }
        this.drawingObjects.arrTrackObjects[0].path.push(new AscFormat.SplineCommandLineTo(tr_x, tr_y));
        this.drawingObjects.changeCurrentState(new SplineBezierState2(this.drawingObjects, this.pageIndex));
        this.drawingObjects.updateOverlay();
    },

    onMouseUp: function(e, x, y, pageIndex)
    {
    }
};

function SplineBezierState2(drawingObjects,pageIndex)
{
    this.drawingObjects = drawingObjects;
    this.polylineFlag = true;
    this.pageIndex = pageIndex;
}

SplineBezierState2.prototype =
{

    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {objectId: null, bMarker: true};
        if(e.ClickCount >= 2)
        {
            this.bStart = true;
            this.pageIndex = this.drawingObjects.startTrackPos.pageIndex;
            StartAddNewShape.prototype.onMouseUp.call(this, e, x, y, pageIndex);
        }
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        var startPos = this.drawingObjects.startTrackPos;
        var tr_x, tr_y;
        if(pageIndex === startPos.pageIndex)
        {
            tr_x = x;
            tr_y = y;
        }
        else
        {
            var tr_point = this.drawingObjects.drawingDocument.ConvertCoordsToAnotherPage(x, y, pageIndex, startPos.pageIndex);
            tr_x = tr_point.X;
            tr_y = tr_point.Y;
        }

        this.drawingObjects.arrTrackObjects[0].path[1].changeLastPoint(tr_x, tr_y);
        this.drawingObjects.updateOverlay();
    },

    onMouseUp: function(e, x, y, pageIndex)
    {
        if( e.ClickCount < 2)
        {
            var tr_x, tr_y;
            if(pageIndex === this.drawingObjects.startTrackPos.pageIndex)
            {
                tr_x = x;
                tr_y = y;
            }
            else
            {
                var tr_point = this.drawingObjects.drawingDocument.ConvertCoordsToAnotherPage(x, y, pageIndex, this.drawingObjects.startTrackPos.pageIndex);
                tr_x = tr_point.x;
                tr_y = tr_point.y;
            }
            this.drawingObjects.changeCurrentState(new SplineBezierState3(this.drawingObjects,tr_x, tr_y, this.pageIndex));
        }
    }
};

function SplineBezierState3(drawingObjects, startX, startY,pageIndex)
{
    this.drawingObjects = drawingObjects;
    this.startX = startX;
    this.startY = startY;
    this.polylineFlag = true;
    this.pageIndex =pageIndex;
}

SplineBezierState3.prototype =
{

    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {objectId: null, bMarker: true};
        if(e.ClickCount >= 2)
        {
            this.bStart = true;

            this.pageIndex = this.drawingObjects.startTrackPos.pageIndex;
            StartAddNewShape.prototype.onMouseUp.call(this, e, x, y, pageIndex);
        }
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        if(x === this.startX && y === this.startY && pageIndex === this.drawingObjects.startTrackPos.pageIndex)
        {
            return;
        }

        var tr_x, tr_y;
        if(pageIndex === this.drawingObjects.startTrackPos.pageIndex)
        {
            tr_x = x;
            tr_y = y;
        }
        else
        {
            var tr_point = this.drawingObjects.drawingDocument.ConvertCoordsToAnotherPage(x, y, pageIndex, this.drawingObjects.startTrackPos.pageIndex);
            tr_x = tr_point.X;
            tr_y = tr_point.Y;
        }

        var x0, y0, x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, x6, y6;
        var spline = this.drawingObjects.arrTrackObjects[0];
        x0 = spline.path[0].x;
        y0 = spline.path[0].y;
        x3 = spline.path[1].x;
        y3 = spline.path[1].y;
        x6 = tr_x;
        y6 = tr_y;

        var vx = (x6 - x0)/6;
        var vy = (y6 - y0)/6;

        x2 = x3 - vx;
        y2 = y3 - vy;

        x4 = x3 + vx;
        y4 = y3 + vy;

        x1 = (x0 + x2)*0.5;
        y1 = (y0 + y2)*0.5;

        x5 = (x4 + x6)*0.5;
        y5 = (y4 + y6)*0.5;


        spline.path.length = 1;
        spline.path.push(new AscFormat.SplineCommandBezier(x1, y1, x2, y2, x3, y3));


        spline.path.push(new AscFormat.SplineCommandBezier(x4, y4, x5, y5, x6, y6));
        this.drawingObjects.updateOverlay();
        this.drawingObjects.changeCurrentState(new SplineBezierState4(this.drawingObjects, this.pageIndex));
    },

    onMouseUp: function(e, x, y, pageIndex)
    {
        if(e.ClickCount >= 2)
        {
            this.bStart = true;
            this.pageIndex = this.drawingObjects.startTrackPos.pageIndex;
            StartAddNewShape.prototype.onMouseUp.call(this, e, x, y, pageIndex);
        }
    }
};


function SplineBezierState4(drawingObjects, pageIndex)
{
    this.drawingObjects = drawingObjects;
    this.polylineFlag = true;
    this.pageIndex = pageIndex;
}


SplineBezierState4.prototype =
{

    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {objectId: null, bMarker: true};
        if(e.ClickCount >= 2)
        {
            this.bStart = true;
            this.pageIndex = this.drawingObjects.startTrackPos.pageIndex;
            StartAddNewShape.prototype.onMouseUp.call(this, e, x, y, pageIndex);
        }
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        var spline = this.drawingObjects.arrTrackObjects[0];
        var lastCommand = spline.path[spline.path.length-1];
        var preLastCommand = spline.path[spline.path.length-2];
        var x0, y0, x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, x6, y6;
        if(spline.path[spline.path.length-3].id == 0)
        {
            x0 = spline.path[spline.path.length-3].x;
            y0 = spline.path[spline.path.length-3].y;
        }
        else
        {
            x0 = spline.path[spline.path.length-3].x3;
            y0 = spline.path[spline.path.length-3].y3;
        }

        x3 = preLastCommand.x3;
        y3 = preLastCommand.y3;

        var tr_x, tr_y;
        if(pageIndex === this.drawingObjects.startTrackPos.pageIndex)
        {
            tr_x = x;
            tr_y = y;
        }
        else
        {
            var tr_point = this.drawingObjects.drawingDocument.ConvertCoordsToAnotherPage(x, y, pageIndex, this.drawingObjects.startTrackPos.pageIndex);
            tr_x = tr_point.X;
            tr_y = tr_point.Y;
        }
        x6 = tr_x;
        y6 = tr_y;

        var vx = (x6 - x0)/6;
        var vy = (y6 - y0)/6;

        x2 = x3 - vx;
        y2 = y3 - vy;

        x4 = x3 + vx;
        y4 = y3 + vy;

        x5 = (x4 + x6)*0.5;
        y5 = (y4 + y6)*0.5;

        if(spline.path[spline.path.length-3].id == 0)
        {
            preLastCommand.x1 = (x0 + x2)*0.5;
            preLastCommand.y1 = (y0 + y2)*0.5;
        }

        preLastCommand.x2 = x2;
        preLastCommand.y2 = y2;
        preLastCommand.x3 = x3;
        preLastCommand.y3 = y3;

        lastCommand.x1 = x4;
        lastCommand.y1 = y4;
        lastCommand.x2 = x5;
        lastCommand.y2 = y5;
        lastCommand.x3 = x6;
        lastCommand.y3 = y6;

        this.drawingObjects.updateOverlay();
    },

    onMouseUp: function(e, x, y, pageIndex)
    {
        if(e.ClickCount < 2 )
        {
            var tr_x, tr_y;
            if(pageIndex === this.drawingObjects.startTrackPos.pageIndex)
            {
                tr_x = x;
                tr_y = y;
            }
            else
            {
                var tr_point = this.drawingObjects.drawingDocument.ConvertCoordsToAnotherPage(x, y, pageIndex, this.drawingObjects.startTrackPos.pageIndex);
                tr_x = tr_point.X;
                tr_y = tr_point.Y;
            }
            this.drawingObjects.changeCurrentState(new SplineBezierState5(this.drawingObjects, tr_x, tr_y, this.pageIndex));
        }
    }
};

function SplineBezierState5(drawingObjects, startX, startY,pageIndex)
{

    this.drawingObjects = drawingObjects;
    this.startX = startX;
    this.startY = startY;
    this.polylineFlag = true;
    this.pageIndex = pageIndex;

}

SplineBezierState5.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {objectId: null, bMarker: true};
        if(e.ClickCount >= 2)
        {
            this.bStart = true;
            this.pageIndex = this.drawingObjects.startTrackPos.pageIndex;
            StartAddNewShape.prototype.onMouseUp.call(this, e, x, y, pageIndex);
        }
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        if(x === this.startX && y === this.startY && pageIndex === this.drawingObjects.startTrackPos.pageIndex)
        {
            return;
        }
        var spline = this.drawingObjects.arrTrackObjects[0];
        var lastCommand = spline.path[spline.path.length-1];
        var x0, y0, x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, x6, y6;

        if(spline.path[spline.path.length-2].id == 0)
        {
            x0 = spline.path[spline.path.length-2].x;
            y0 = spline.path[spline.path.length-2].y;
        }
        else
        {
            x0 = spline.path[spline.path.length-2].x3;
            y0 = spline.path[spline.path.length-2].y3;
        }

        x3 = lastCommand.x3;
        y3 = lastCommand.y3;


        var tr_x, tr_y;
        if(pageIndex === this.drawingObjects.startTrackPos.pageIndex)
        {
            tr_x = x;
            tr_y = y;
        }
        else
        {
            var tr_point = this.drawingObjects.drawingDocument.ConvertCoordsToAnotherPage(x, y, pageIndex, this.drawingObjects.startTrackPos.pageIndex);
            tr_x = tr_point.X;
            tr_y = tr_point.Y;
        }
        x6 = tr_x;
        y6 = tr_y;

        var vx = (x6 - x0)/6;
        var vy = (y6 - y0)/6;


        x2 = x3 - vx;
        y2 = y3 - vy;

        x1 = (x2+x1)*0.5;
        y1 = (y2+y1)*0.5;

        x4 = x3 + vx;
        y4 = y3 + vy;

        x5 = (x4 + x6)*0.5;
        y5 = (y4 + y6)*0.5;

        if(spline.path[spline.path.length-2].id == 0)
        {
            lastCommand.x1 = x1;
            lastCommand.y1 = y1;
        }
        lastCommand.x2 = x2;
        lastCommand.y2 = y2;


        spline.path.push(new AscFormat.SplineCommandBezier(x4, y4, x5, y5, x6, y6));
        this.drawingObjects.updateOverlay();
        this.drawingObjects.changeCurrentState(new SplineBezierState4(this.drawingObjects, this.pageIndex));
    },

    onMouseUp: function(e, x, y, pageIndex)
    {
        if(e.ClickCount >= 2)
        {
            this.bStart = true;
            this.pageIndex = this.drawingObjects.startTrackPos.pageIndex;
            StartAddNewShape.prototype.onMouseUp.call(this, e, x, y, pageIndex);
        }
    }
};

function PolyLineAddState(drawingObjects)
{
    this.drawingObjects = drawingObjects;

    this.polylineFlag = true;
}

PolyLineAddState.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {objectId: null, bMarker: true};
        this.drawingObjects.startTrackPos = {x: x, y: y, pageIndex:pageIndex};
        this.drawingObjects.clearTrackObjects();
        this.drawingObjects.addTrackObject(new AscFormat.PolyLine(this.drawingObjects, this.drawingObjects.document.theme, null, null, null, pageIndex));
        this.drawingObjects.arrTrackObjects[0].arrPoint.push({x : x, y: y});
        this.drawingObjects.resetSelection();
        this.drawingObjects.updateOverlay();
        var _min_distance = this.drawingObjects.drawingDocument.GetMMPerDot(1);
        this.drawingObjects.changeCurrentState(new PolyLineAddState2(this.drawingObjects, _min_distance));
    },

    onMouseMove: function()
    {},

    onMouseUp: function()
    {
        this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
    }
};


function PolyLineAddState2(drawingObjects, minDistance)
{
    this.drawingObjects = drawingObjects;
    this.minDistance = minDistance;
    this.polylineFlag = true;

}
PolyLineAddState2.prototype =
{

    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {objectId: null, bMarker: true};
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        var _last_point = this.drawingObjects.arrTrackObjects[0].arrPoint[this.drawingObjects.arrTrackObjects[0].arrPoint.length - 1];

        var tr_x, tr_y;
        if(pageIndex === this.drawingObjects.startTrackPos.pageIndex)
        {
            tr_x = x;
            tr_y = y;
        }
        else
        {
            var tr_point = this.drawingObjects.drawingDocument.ConvertCoordsToAnotherPage(x, y, pageIndex, this.drawingObjects.startTrackPos.pageIndex);
            tr_x = tr_point.X;
            tr_y = tr_point.Y;
        }
        var dx = tr_x - _last_point.x;
        var dy = tr_y - _last_point.y;

        if(Math.sqrt(dx*dx + dy*dy) >= this.minDistance)
        {
            this.drawingObjects.arrTrackObjects[0].arrPoint.push({x : tr_x, y : tr_y});
            this.drawingObjects.updateOverlay();
        }
    },

    onMouseUp: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.arrTrackObjects[0].arrPoint.length > 1)
        {
            this.bStart = true;
            this.pageIndex = this.drawingObjects.startTrackPos.pageIndex;
            StartAddNewShape.prototype.onMouseUp.call(this, e, x, y, pageIndex);
        }
        else
        {
            this.drawingObjects.clearTrackObjects();
            this.drawingObjects.updateOverlay();
            this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
        }

    }
};



function AddPolyLine2State(drawingObjects)
{
    this.drawingObjects = drawingObjects;
    this.polylineFlag = true;

}
AddPolyLine2State.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {objectId: null, bMarker: true};
        this.drawingObjects.startTrackPos = {x: x, y: y, pageIndex : pageIndex};
        this.drawingObjects.resetSelection();
        this.drawingObjects.updateOverlay();
        this.drawingObjects.clearTrackObjects();
        this.drawingObjects.addTrackObject(new AscFormat.PolyLine(this.drawingObjects, this.drawingObjects.document.theme, null, null, null, pageIndex));
        this.drawingObjects.arrTrackObjects[0].arrPoint.push({x : x, y: y});
        this.drawingObjects.changeCurrentState(new AddPolyLine2State2(this.drawingObjects, x, y));
    },

    onMouseMove: function(e, x, y, pageIndex)
    {},

    onMouseUp: function(e, x, y, pageIndex)
    {
    }
};

function AddPolyLine2State2(drawingObjects, x, y)
{
    this.drawingObjects = drawingObjects;
    this.X = x;
    this.Y = y;
    this.polylineFlag = true;


}
AddPolyLine2State2.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {objectId: null, bMarker: true};
        if(e.ClickCount > 1)
        {
            this.drawingObjects.changeCurrentState(new NullState(this.drawingObjects));
        }
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        if(this.X !== x || this.Y !== y || this.drawingObjects.startTrackPos.pageIndex !== pageIndex)
        {
            var tr_x, tr_y;
            if(pageIndex === this.drawingObjects.startTrackPos.pageIndex)
            {
                tr_x = x;
                tr_y = y;
            }
            else
            {
                var tr_point = this.drawingObjects.drawingDocument.ConvertCoordsToAnotherPage(x, y, pageIndex, this.drawingObjects.startTrackPos.pageIndex);
                tr_x = tr_point.X;
                tr_y = tr_point.Y;
            }

            this.drawingObjects.arrTrackObjects[0].arrPoint.push({x : tr_x, y: tr_y});
            this.drawingObjects.changeCurrentState(new AddPolyLine2State3(this.drawingObjects));
        }
    },

    onMouseUp: function(e, x, y, pageIndex)
    {
    }
};

function AddPolyLine2State3(drawingObjects)
{
    this.drawingObjects = drawingObjects;
    this.minSize = drawingObjects.drawingDocument.GetMMPerDot(1);

    this.polylineFlag = true;
}
AddPolyLine2State3.prototype =
{
    onMouseDown: function(e, x, y, pageIndex)
    {
        if(this.drawingObjects.handleEventMode === HANDLE_EVENT_MODE_CURSOR)
            return {objectId: null, bMarker: true};
        var tr_x, tr_y;
        if(pageIndex === this.drawingObjects.startTrackPos.pageIndex)
        {
            tr_x = x;
            tr_y = y;
        }
        else
        {
            var tr_point = this.drawingObjects.drawingDocument.ConvertCoordsToAnotherPage(x, y, pageIndex, this.drawingObjects.startTrackPos.pageIndex);
            tr_x = tr_point.X;
            tr_y = tr_point.Y;
        }
        this.drawingObjects.arrTrackObjects[0].arrPoint.push({x: tr_x, y: tr_y});
        if(e.ClickCount > 1)
        {

            this.bStart = true;
            this.pageIndex = this.drawingObjects.startTrackPos.pageIndex;
            StartAddNewShape.prototype.onMouseUp.call(this, e, x, y, pageIndex);

        }
    },

    onMouseMove: function(e, x, y, pageIndex)
    {
        var tr_x, tr_y;
        if(pageIndex === this.drawingObjects.startTrackPos.pageIndex)
        {
            tr_x = x;
            tr_y = y;
        }
        else
        {
            var tr_point = this.drawingObjects.drawingDocument.ConvertCoordsToAnotherPage(x, y, pageIndex, this.drawingObjects.startTrackPos.pageIndex);
            tr_x = tr_point.X;
            tr_y = tr_point.Y;
        }

        if(!e.IsLocked)
        {
            this.drawingObjects.arrTrackObjects[0].arrPoint[this.drawingObjects.arrTrackObjects[0].arrPoint.length - 1] = {x: tr_x, y: tr_y};
        }
        else
        {
            var _last_point = this.drawingObjects.arrTrackObjects[0].arrPoint[this.drawingObjects.arrTrackObjects[0].arrPoint.length - 1];
            var dx = tr_x - _last_point.x;
            var dy = tr_y - _last_point.y;

            if(Math.sqrt(dx*dx + dy*dy) >= this.minSize)
            {
                this.drawingObjects.arrTrackObjects[0].arrPoint.push({x: tr_x, y: tr_y});
            }
        }
        this.drawingObjects.drawingDocument.m_oWordControl.OnUpdateOverlay();
    },

    onMouseUp: function(e, x, y, pageIndex)
    {
        if(e.ClickCount > 1)
        {

            this.bStart = true;

            this.pageIndex = this.drawingObjects.startTrackPos.pageIndex;
            StartAddNewShape.prototype.onMouseUp.call(this, e, x, y, pageIndex);
        }
    }
};

//--------------------------------------------------------export----------------------------------------------------
window['AscFormat'] = window['AscFormat'] || {};
window['AscFormat'].MOVE_DELTA = MOVE_DELTA;
window['AscFormat'].SNAP_DISTANCE = SNAP_DISTANCE;
window['AscFormat'].StartAddNewShape = StartAddNewShape;
window['AscFormat'].NullState = NullState;
window['AscFormat'].PreChangeAdjState = PreChangeAdjState;
window['AscFormat'].PreMoveInlineObject = PreMoveInlineObject;
window['AscFormat'].PreRotateState = PreRotateState;
window['AscFormat'].PreResizeState = PreResizeState;
window['AscFormat'].PreMoveState = PreMoveState;
window['AscFormat'].MoveState = MoveState;
window['AscFormat'].PreMoveInGroupState = PreMoveInGroupState;
window['AscFormat'].MoveInGroupState = MoveInGroupState;
window['AscFormat'].PreRotateInGroupState = PreRotateInGroupState;
window['AscFormat'].PreResizeInGroupState = PreResizeInGroupState;
window['AscFormat'].PreChangeAdjInGroupState = PreChangeAdjInGroupState;
window['AscFormat'].TextAddState = TextAddState;
window['AscFormat'].SplineBezierState = SplineBezierState;
window['AscFormat'].PolyLineAddState = PolyLineAddState;
window['AscFormat'].AddPolyLine2State = AddPolyLine2State;
})(window);

(function (window, undefined) {
    var drawingsChangesMap = {};
    var drawingConstructorsMap = {};
    var drawingContentChanges = {};
    window['AscDFH'].drawingsChangesMap = drawingsChangesMap;
    window['AscDFH'].drawingsConstructorsMap = drawingConstructorsMap;
    window['AscDFH'].drawingContentChanges = drawingContentChanges;


    var oPosExtMap = {};
    oPosExtMap[AscDFH.historyitem_Xfrm_SetOffX]  = true;
    oPosExtMap[AscDFH.historyitem_Xfrm_SetOffY]  = true;
    oPosExtMap[AscDFH.historyitem_Xfrm_SetExtX]  = true;
    oPosExtMap[AscDFH.historyitem_Xfrm_SetExtY]  = true;
    oPosExtMap[AscDFH.historyitem_Xfrm_SetChOffX]  = true;
    oPosExtMap[AscDFH.historyitem_Xfrm_SetChOffY]  = true;
    oPosExtMap[AscDFH.historyitem_Xfrm_SetChExtX]  = true;
    oPosExtMap[AscDFH.historyitem_Xfrm_SetChExtY]  = true;
    var oPosExtHor = {};
    oPosExtHor[AscDFH.historyitem_Xfrm_SetOffX]  = true;
    oPosExtHor[AscDFH.historyitem_Xfrm_SetExtX]  = true;
    oPosExtHor[AscDFH.historyitem_Xfrm_SetChOffX]  = true;
    oPosExtHor[AscDFH.historyitem_Xfrm_SetChExtX]  = true;
    function private_SetValue(Value) {
        if (!this.Class) {
            return;
        }
        if (AscDFH.drawingsChangesMap[this.Type]) {
            var _Value = Value === undefined ? null : Value;
            AscDFH.drawingsChangesMap[this.Type](this.Class, _Value, this.FromLoad);
        }
    }

    function CChangesDrawingsBool(Class, Type, OldPr, NewPr) {
        this.Type = Type;
        var _OldPr = AscFormat.isRealBool(OldPr) ? OldPr : undefined;
        var _NewPr = AscFormat.isRealBool(NewPr) ? NewPr : undefined;
		AscDFH.CChangesBaseBoolProperty.call(this, Class, _OldPr, _NewPr);
    }

	CChangesDrawingsBool.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
	CChangesDrawingsBool.prototype.constructor = CChangesDrawingsBool;
    CChangesDrawingsBool.prototype.private_SetValue = private_SetValue;
    CChangesDrawingsBool.prototype.Load = function(){
        this.Redo();
        this.RefreshRecalcData();
    };
    CChangesDrawingsBool.prototype.CreateReverseChange = function()
    {
        return new this.constructor(this.Class, this.Type, this.New, this.Old, this.Color);
    };

    CChangesDrawingsBool.prototype.ReadFromBinary = function (reader) {
        reader.Seek2(reader.GetCurPos() - 4);
        this.Type = reader.GetLong();
		AscDFH.CChangesBaseBoolProperty.prototype.ReadFromBinary.call(this, reader);
    };
    window['AscDFH'].CChangesDrawingsBool = CChangesDrawingsBool;


    function CChangesDrawingsLong(Class, Type, OldPr, NewPr) {
        this.Type = Type;
        var _OldPr = AscFormat.isRealNumber(OldPr) ? ((OldPr + 0.5) >> 0) : undefined;
        var _NewPr = AscFormat.isRealNumber(NewPr) ? ((NewPr + 0.5) >> 0) : undefined;
		AscDFH.CChangesBaseLongProperty.call(this, Class, _OldPr, _NewPr);
    }

	CChangesDrawingsLong.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
	CChangesDrawingsLong.prototype.constructor = CChangesDrawingsLong;

    CChangesDrawingsLong.prototype.CreateReverseChange = function()
    {
        return new this.constructor(this.Class, this.Type, this.New, this.Old, this.Color);
    };

    CChangesDrawingsLong.prototype.private_SetValue = private_SetValue;
    CChangesDrawingsLong.prototype.Load = function(){
        this.Redo();
        this.RefreshRecalcData();
    };
    CChangesDrawingsLong.prototype.ReadFromBinary = function (reader) {
        reader.Seek2(reader.GetCurPos() - 4);
        this.Type = reader.GetLong();
		AscDFH.CChangesBaseLongProperty.prototype.ReadFromBinary.call(this, reader);
    };
    window['AscDFH'].CChangesDrawingsLong = CChangesDrawingsLong;

    function CChangesDrawingsDouble(Class, Type, OldPr, NewPr) {
        this.Type = Type;
        var _OldPr = AscFormat.isRealNumber(OldPr) ? OldPr : undefined;
        var _NewPr = AscFormat.isRealNumber(NewPr) ? NewPr : undefined;
		AscDFH.CChangesBaseDoubleProperty.call(this, Class, _OldPr, _NewPr);
    }

	CChangesDrawingsDouble.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
	CChangesDrawingsDouble.prototype.constructor = CChangesDrawingsDouble;

    CChangesDrawingsDouble.prototype.CreateReverseChange = function()
    {
        return new this.constructor(this.Class, this.Type, this.New, this.Old, this.Color);
    };

    CChangesDrawingsDouble.prototype.private_SetValue = private_SetValue;

    CChangesDrawingsDouble.prototype.Load = function(){
        this.Redo();
        this.RefreshRecalcData();
    };
    CChangesDrawingsDouble.prototype.ReadFromBinary = function (reader) {

        reader.Seek2(reader.GetCurPos() - 4);
        this.Type = reader.GetLong();
		AscDFH.CChangesBaseDoubleProperty.prototype.ReadFromBinary.call(this, reader);
    };
    CChangesDrawingsDouble.prototype.IsPosExtChange = function () {
        return !!oPosExtMap[this.Type];
    };
    CChangesDrawingsDouble.prototype.IsHorizontal = function () {
        return !!oPosExtHor[this.Type];
    };
    window['AscDFH'].CChangesDrawingsDouble = CChangesDrawingsDouble;



    function CChangesDrawingsDouble2(Class, Type, OldPr, NewPr) {
        this.Type = Type;
        var _OldPr = AscFormat.isRealNumber(OldPr) ? OldPr : undefined;
        var _NewPr = AscFormat.isRealNumber(NewPr) ? NewPr : undefined;
		AscDFH.CChangesBaseDoubleProperty.call(this, Class, _OldPr, _NewPr);
    }

    CChangesDrawingsDouble2.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
    CChangesDrawingsDouble2.prototype.constructor = CChangesDrawingsDouble2;

    CChangesDrawingsDouble2.prototype.CreateReverseChange = function()
    {
        return new this.constructor(this.Class, this.Type, this.New, this.Old, this.Color);
    };

    CChangesDrawingsDouble2.prototype.private_SetValue = private_SetValue;

    CChangesDrawingsDouble2.prototype.Load = function(){
        this.Redo();
        this.RefreshRecalcData();
    };
    CChangesDrawingsDouble2.prototype.WriteToBinary = function(Writer)
    {
        // Long  : Flag
        // 1-bit : Подсвечивать ли данные изменения
        // 2-bit : IsUndefined New
        // 3-bit : IsUndefined Old
        // double : New
        // double : Old

        var nFlags = 0;

        if (false !== this.Color)
            nFlags |= 1;

        if (undefined === this.New)
            nFlags |= 2;

        if (undefined === this.Old)
            nFlags |= 4;

        Writer.WriteLong(nFlags);

        if (undefined !== this.New)
            Writer.WriteDouble2(this.New);

        if (undefined !== this.Old)
            Writer.WriteDouble2(this.Old);
    };
    CChangesDrawingsDouble2.prototype.ReadFromBinary = function(Reader)
    {



        Reader.Seek2(Reader.GetCurPos() - 4);
        this.Type = Reader.GetLong();
        // Long  : Flag
        // 1-bit : Подсвечивать ли данные изменения
        // 2-bit : IsUndefined New
        // 3-bit : IsUndefined Old
        // double : New
        // double : Old


        var nFlags = Reader.GetLong();

        if (nFlags & 1)
            this.Color = true;
        else
            this.Color = false;

        if (nFlags & 2)
            this.New = undefined;
        else
            this.New = Reader.GetDoubleLE();

        if (nFlags & 4)
            this.Old = undefined;
        else
            this.Old = Reader.GetDoubleLE();
    };
    CChangesDrawingsDouble2.prototype.IsPosExtChange = function () {
        return !!oPosExtMap[this.Type];
    };
    CChangesDrawingsDouble2.prototype.IsHorizontal = function () {
        return !!oPosExtHor[this.Type];
    };
    window['AscDFH'].CChangesDrawingsDouble2 = CChangesDrawingsDouble2;


    function CChangesDrawingsString(Class, Type, OldPr, NewPr) {
        this.Type = Type;
        var _OldPr = typeof OldPr === "string" ? OldPr : undefined;
        var _NewPr = typeof NewPr === "string" ? NewPr : undefined;
		AscDFH.CChangesBaseStringProperty.call(this, Class, _OldPr, _NewPr);
    }

	CChangesDrawingsString.prototype = Object.create(AscDFH.CChangesBaseStringProperty.prototype);
	CChangesDrawingsString.prototype.constructor = CChangesDrawingsString;

    CChangesDrawingsString.prototype.CreateReverseChange = function()
    {
        return new this.constructor(this.Class, this.Type, this.New, this.Old, this.Color);
    };

    CChangesDrawingsString.prototype.private_SetValue = private_SetValue;

    CChangesDrawingsString.prototype.Load = function(){
        this.Redo();
        this.RefreshRecalcData();
    };
    CChangesDrawingsString.prototype.ReadFromBinary = function (reader) {
        reader.Seek2(reader.GetCurPos() - 4);
        this.Type = reader.GetLong();
		AscDFH.CChangesBaseStringProperty.prototype.ReadFromBinary.call(this, reader);
    };
    window['AscDFH'].CChangesDrawingsString = CChangesDrawingsString;


    function CChangesDrawingsObjectNoId(Class, Type, OldPr, NewPr) {
        this.Type = Type;
        this.FromLoad = false;
        var _OldPr = AscCommon.isRealObject(OldPr) ? OldPr : undefined;
        var _NewPr = AscCommon.isRealObject(NewPr) ? NewPr : undefined;
		AscDFH.CChangesBaseObjectProperty.call(this, Class, _OldPr, _NewPr);
    }

	CChangesDrawingsObjectNoId.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
	CChangesDrawingsObjectNoId.prototype.constructor = CChangesDrawingsObjectNoId;
    CChangesDrawingsObjectNoId.prototype.CreateReverseChange = function()
    {
        return new this.constructor(this.Class, this.Type, this.New, this.Old, this.Color);
    };
    CChangesDrawingsObjectNoId.prototype.private_SetValue = private_SetValue;
    CChangesDrawingsObjectNoId.prototype.Load = function(){
        this.Redo();
        this.RefreshRecalcData();
    };
    window['AscDFH'].CChangesDrawingsObjectNoId = CChangesDrawingsObjectNoId;
    CChangesDrawingsObjectNoId.prototype.ReadFromBinary = function (reader) {
        reader.Seek2(reader.GetCurPos() - 4);
        var nType = reader.GetLong();
        this.Type = nType;
        this.FromLoad = true;
		AscDFH.CChangesBaseObjectProperty.prototype.ReadFromBinary.call(this, reader);
    };
    CChangesDrawingsObjectNoId.prototype.private_CreateObject = function () {
        if (AscDFH.drawingsConstructorsMap[this.Type]) {
            return new AscDFH.drawingsConstructorsMap[this.Type]();
        }
        return null;
    };


    function CChangesDrawingsObject(Class, Type, OldPr, NewPr) {
        this.Type = Type;
        var _OldPr = OldPr && OldPr.Get_Id ? OldPr.Get_Id() : undefined;
        var _NewPr = NewPr && NewPr.Get_Id ? NewPr.Get_Id() : undefined;
		AscDFH.CChangesBaseStringProperty.call(this, Class, _OldPr, _NewPr);
    }

	CChangesDrawingsObject.prototype = Object.create(AscDFH.CChangesBaseStringProperty.prototype);
	CChangesDrawingsObject.prototype.constructor = CChangesDrawingsObject;

    CChangesDrawingsObject.prototype.CreateReverseChange = function()
    {
        return new this.constructor(this.Class, this.Type, AscCommon.g_oTableId.Get_ById(this.New), AscCommon.g_oTableId.Get_ById(this.Old), this.Color);
    };
    window['AscDFH'].CChangesDrawingsObject = CChangesDrawingsObject;
    CChangesDrawingsObject.prototype.ReadFromBinary = function (reader) {
        reader.Seek2(reader.GetCurPos() - 4);
        this.Type = reader.GetLong();
		AscDFH.CChangesBaseStringProperty.prototype.ReadFromBinary.call(this, reader);
    };
    CChangesDrawingsObject.prototype.private_SetValue = function (Value) {
        var oObject = null;
        if (typeof Value === "string") {
            oObject = AscCommon.g_oTableId.Get_ById(Value);
            if (!oObject) {
                oObject = null;
            }
        }
        if (AscDFH.drawingsChangesMap[this.Type]) {
            AscDFH.drawingsChangesMap[this.Type](this.Class, oObject);
        }
    };
    CChangesDrawingsObject.prototype.Load = function(){
        this.Redo();
        this.RefreshRecalcData();
    };

    CChangesDrawingsObject.prototype.CheckCorrect = function()
    {
        if(this.Old){
            var oObject = AscCommon.g_oTableId.Get_ById(this.Old);
            if(oObject.CheckCorrect){
                if(!oObject.CheckCorrect()){
                    return false;
                }
            }
        }
        return true;
    };

    function CChangesDrawingsContent(Class, Type, Pos, Items, isAdd) {
        this.Type = Type;
		AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, isAdd);
    }

	CChangesDrawingsContent.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
	CChangesDrawingsContent.prototype.constructor = CChangesDrawingsContent;
    window['AscDFH'].CChangesDrawingsContent = CChangesDrawingsContent;
    CChangesDrawingsContent.prototype.ReadFromBinary = function (reader) {
        reader.Seek2(reader.GetCurPos() - 4);
        this.Type = reader.GetLong();
        this.Add = reader.GetBool();
        this.Pos = reader.GetLong();
		AscDFH.CChangesBaseContentChange.prototype.ReadFromBinary.call(this, reader);
    };
    CChangesDrawingsContent.prototype.WriteToBinary = function (writer) {
        writer.WriteBool(this.IsAdd());
        writer.WriteLong(this.Pos);
		AscDFH.CChangesBaseContentChange.prototype.WriteToBinary.call(this, writer);
    };

    CChangesDrawingsContent.prototype.private_WriteItem = function (Writer, Item) {
        Writer.WriteString2(Item.Get_Id());
    };
    CChangesDrawingsContent.prototype.private_ReadItem = function (Reader) {
        var Id = Reader.GetString2();
        return AscCommon.g_oTableId.Get_ById(Id);
    };


    CChangesDrawingsContent.prototype.private_GetChangedArray = function () {
        if (drawingContentChanges[this.Type]) {
            return drawingContentChanges[this.Type](this.Class);
        }
        return null;
    };

    CChangesDrawingsContent.prototype.private_GetContentChanges = function () {
        if (this.Class && this.Class.getContentChangesByType) {
            return this.Class.getContentChangesByType(this.Type);
        }
        return null;
    };

    CChangesDrawingsContent.prototype.private_InsertInArrayLoad = function () {
        if (this.Items.length <= 0)
            return;

        var aChangedArray = this.private_GetChangedArray();
        if (null !== aChangedArray) {
            var oContentChanges = this.private_GetContentChanges(), nPos;
            for (var i = 0; i < this.Items.length; ++i) {
                if (oContentChanges) {
                    nPos = oContentChanges.Check(AscCommon.contentchanges_Add, this.Pos + i);
                }
                else {
                    nPos = this.Pos + i;
                }

                var oElement = this.Items[i];

                nPos = Math.min(nPos, aChangedArray.length);
                aChangedArray.splice(nPos, 0, oElement);
            }
        }
    };

    CChangesDrawingsContent.prototype.private_RemoveInArrayLoad = function () {

        var aChangedArray = this.private_GetChangedArray();
        if (null !== aChangedArray) {
            var oContentChanges = this.private_GetContentChanges(), nPos;
            for (var i = 0; i < this.Items.length; ++i) {
                if (oContentChanges) {
                    nPos = oContentChanges.Check(AscCommon.contentchanges_Remove, this.Pos + i);
                }
                else {
                    nPos = this.Pos + i;
                }
                if (false === nPos) {
                    continue;
                }
                aChangedArray.splice(nPos, 1);
            }
        }
    };

    CChangesDrawingsContent.prototype.private_InsertInArrayUndoRedo = function () {
        var aChangedArray = this.private_GetChangedArray();
        if (null !== aChangedArray) {
            var nPos;
            for (var i = 0; i < this.Items.length; ++i) {
                nPos = Math.min(this.Pos + i, aChangedArray.length);
                aChangedArray.splice(nPos, 0, this.Items[i]);
            }
        }
    };

    CChangesDrawingsContent.prototype.private_RemoveInArrayUndoRedo = function () {

        var aChangedArray = this.private_GetChangedArray();
        if (null !== aChangedArray) {
            for (var i = 0; i < this.Items.length; ++i) {
                aChangedArray.splice(this.Pos + i, 1);
            }
        }
    };

    CChangesDrawingsContent.prototype.Load = function () {
        if (this.IsAdd()) {
            this.private_InsertInArrayLoad();
        }
        else {
            this.private_RemoveInArrayLoad();
        }
        this.RefreshRecalcData();
    };

    CChangesDrawingsContent.prototype.Undo = function () {
        if (this.IsAdd()) {
            this.private_RemoveInArrayUndoRedo();
        }
        else {
            this.private_InsertInArrayUndoRedo();
        }
    };

    CChangesDrawingsContent.prototype.Redo = function () {
        if (this.IsAdd()) {
            this.private_InsertInArrayUndoRedo();
        }
        else {
            this.private_RemoveInArrayUndoRedo();
        }
    };
    CChangesDrawingsContent.prototype.IsContentChange = function () {
        return false;
    };
    CChangesDrawingsContent.prototype.Copy = function()
    {
        var oChanges = new this.constructor(this.Class, this.Type, this.Pos, this.Items, this.Add);
        oChanges.UseArray = this.UseArray;
        oChanges.Pos = this.Pos;
        for (var nIndex = 0, nCount = this.PosArray.length; nIndex < nCount; ++nIndex)
            oChanges.PosArray[nIndex] = this.PosArray[nIndex];

        return oChanges;
    };

    CChangesDrawingsContent.prototype.CreateReverseChange = function(){
        var oRet = this.private_CreateReverseChange(this.constructor);
        oRet.Type = this.Type;
        oRet.Pos = this.Pos;
        return oRet;
    };


    function CChangesDrawingsContentPresentation(Class, Type, Pos, Items, isAdd){
		CChangesDrawingsContent.call(this, Class, Type, Pos, Items, isAdd);
    }

	CChangesDrawingsContentPresentation.prototype = Object.create(CChangesDrawingsContent.prototype);
	CChangesDrawingsContentPresentation.prototype.constructor = CChangesDrawingsContentPresentation;
    CChangesDrawingsContentPresentation.prototype.IsContentChange = function(){
        return true;
    };

    CChangesDrawingsContentPresentation.prototype.Load = function(Color)
    {
        var aContent = this.private_GetChangedArray();
        if(!Array.isArray(aContent)){
            return;
        }
        if(this.IsAdd()){
            if (this.PosArray.length <= 0 || this.Items.length <= 0)
                return;
            for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex){
                var Pos     = this.Class.m_oContentChanges.Check(AscCommon.contentchanges_Add, true !== this.UseArray ? this.Pos + nIndex : this.PosArray[nIndex]);
                if(Pos === false){
                    continue;
                }
                var Element = this.Items[nIndex];
                Pos = Math.min(Pos, aContent.length);
                aContent.splice(Pos, 0, Element);
            }
        }
        else{

            for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex) {
                var Pos = this.Class.m_oContentChanges.Check(AscCommon.contentchanges_Remove,  true !== this.UseArray ? this.Pos + nIndex : this.PosArray[nIndex]);
                if (false === Pos){
                    continue;
                }
                if(aContent[Pos] === this.Items[nIndex]){
                    aContent.splice(Pos, 1);
                    break;
                }
                for(var j = aContent.length - 1; j > -1 ; --j){
                    if(aContent[j] === this.Items[nIndex]){
                        aContent.splice(j, 1);
                        break;
                    }
                }
            }
        }
    };

    CChangesDrawingsContentPresentation.prototype.CheckCorrect = function(){
        if(!this.IsAdd()){
            for(var nIndex = 0; nIndex < this.Items.length; ++nIndex){
                if(this.Items[nIndex].CheckCorrect && !this.Items[nIndex].CheckCorrect()){
                    return false;
                }
            }
        }
        return true;
    };

    window['AscDFH'].CChangesDrawingsContentPresentation = CChangesDrawingsContentPresentation;

    function CChangesDrawingsContentNoId(Class, Type, Pos, Items, isAdd){
		AscDFH.CChangesDrawingsContent.call(this, Class, Type, Pos, Items, isAdd);
    }

	CChangesDrawingsContentNoId.prototype = Object.create(AscDFH.CChangesDrawingsContent.prototype);
	CChangesDrawingsContentNoId.prototype.constructor = CChangesDrawingsContentNoId;

    CChangesDrawingsContentNoId.prototype.private_WriteItem = function (Writer, Item) {
        Item.Write_ToBinary(Writer);
    };
    CChangesDrawingsContentNoId.prototype.private_ReadItem = function (Reader) {
        var oItem = null;
        if(drawingConstructorsMap[this.Type]){
            oItem = new drawingConstructorsMap[this.Type]();
            oItem.Read_FromBinary(Reader);
        }
        return oItem;
    };
    window['AscDFH'].CChangesDrawingsContentNoId = CChangesDrawingsContentNoId;

    function CChangesDrawingsContentLong(Class, Type, Pos, Items, isAdd){
		AscDFH.CChangesDrawingsContent.call(this, Class, Type, Pos, Items, isAdd);
    }

	CChangesDrawingsContentLong.prototype = Object.create(AscDFH.CChangesDrawingsContent.prototype);
	CChangesDrawingsContentLong.prototype.constructor = CChangesDrawingsContentLong;

    CChangesDrawingsContentLong.prototype.private_WriteItem = function (Writer, Item) {
        Writer.WriteLong(Item);
    };
    CChangesDrawingsContentLong.prototype.private_ReadItem = function (Reader) {
        return Reader.GetLong();
    };
    window['AscDFH'].CChangesDrawingsContentLong = CChangesDrawingsContentLong;


    function CChangesDrawingsContentLongMap(Class, Type, Pos, Items, isAdd){
		AscDFH.CChangesDrawingsContentLong.call(this, Class, Type, Pos, Items, isAdd);
    }

	CChangesDrawingsContentLongMap.prototype = Object.create(AscDFH.CChangesDrawingsContentLong.prototype);
	CChangesDrawingsContentLongMap.prototype.constructor = CChangesDrawingsContentLongMap;


    CChangesDrawingsContentLongMap.prototype.private_InsertInArrayLoad = function () {
        if (this.Items.length <= 0)
            return;
        var aChangedArray = this.private_GetChangedArray();
        if (null !== aChangedArray) {
            for (var i = 0; i < this.Items.length; ++i) {
                aChangedArray[this.Pos + i] = this.Items[i];
            }
        }
    };

    CChangesDrawingsContentLongMap.prototype.private_RemoveInArrayLoad = function () {

        var aChangedArray = this.private_GetChangedArray();
        if (null !== aChangedArray) {
            for (var i = 0; i < this.Items.length; ++i) {
                aChangedArray[this.Pos + i] = null;
            }
        }
    };

    CChangesDrawingsContentLongMap.prototype.private_InsertInArrayUndoRedo = function () {
        var aChangedArray = this.private_GetChangedArray();
        if (null !== aChangedArray) {
            for (var i = 0; i < this.Items.length; ++i) {
                aChangedArray[this.Pos + i] = this.Items[i];
            }
        }
    };

    CChangesDrawingsContentLongMap.prototype.private_RemoveInArrayUndoRedo = function () {
        var aChangedArray = this.private_GetChangedArray();
        if (null !== aChangedArray) {
            for (var i = 0; i < this.Items.length; ++i) {
                aChangedArray[this.Pos + i] = null;
            }
        }
    };

    window['AscDFH'].CChangesDrawingsContentLongMap = CChangesDrawingsContentLongMap;


    function CChangesDrawingChangeTheme(Class, Type, aIndexes){
        this.Type = Type;
        this.aIndexes = aIndexes;
		AscDFH.CChangesBase.call(this, Class);
    }

	CChangesDrawingChangeTheme.prototype = Object.create(AscDFH.CChangesBase.prototype);
	CChangesDrawingChangeTheme.prototype.constructor = CChangesDrawingChangeTheme;

    CChangesDrawingChangeTheme.prototype.WriteToBinary = function(Writer){
        Writer.WriteLong(this.Type);
        Writer.WriteLong(this.aIndexes.length);
        for(var i = 0; i < this.aIndexes.length; ++i){
            Writer.WriteLong(this.aIndexes[i]);
        }
    };

    CChangesDrawingChangeTheme.prototype.ReadFromBinary = function(Reader){
        this.Type = Reader.GetLong();
        this.aIndexes = [];
        var nLength = Reader.GetLong();
        for(var i = 0; i < nLength; ++i){
            this.aIndexes.push(Reader.GetLong());
        }
    };

    CChangesDrawingChangeTheme.prototype.Do = function () {
        var aSlides = this.Class.Slides;
        for(var i = 0; i < this.aIndexes.length; ++i)
        {
            aSlides[this.aIndexes[i]] && aSlides[this.aIndexes[i]].checkSlideTheme();
        }
    };

    CChangesDrawingChangeTheme.prototype.Undo = function(){
        this.Do();
    };

    CChangesDrawingChangeTheme.prototype.Redo = function(){
        this.Do();
    };

    CChangesDrawingChangeTheme.prototype.Load = function(){
        this.Redo();
        this.RefreshRecalcData();
    };

    CChangesDrawingChangeTheme.prototype.CreateReverseChange = function(){
        return new CChangesDrawingChangeTheme(this.Class, this.Type, this.aIndexes);
    };

    window['AscDFH'].CChangesDrawingChangeTheme = CChangesDrawingChangeTheme;


    function CChangesDrawingTimingLocks(Class, deleteLock, backgroundLock, timingLock, transitionLock, layoutLock, showLock){
        this.Type = AscDFH.historyitem_SlideSetLocks;
        this.deleteLock = deleteLock;
        this.backgroundLock = backgroundLock;
        this.timingLock = timingLock;
        this.transitionLock = transitionLock;
        this.layoutLock = layoutLock;
        this.showLock = showLock;
		AscDFH.CChangesBase.call(this, Class);
    }

	CChangesDrawingTimingLocks.prototype = Object.create(AscDFH.CChangesBase.prototype);
	CChangesDrawingTimingLocks.prototype.constructor = CChangesDrawingTimingLocks;

    CChangesDrawingTimingLocks.prototype.WriteToBinary = function(Writer){
        AscFormat.writeObject(Writer, this.deleteLock);
        AscFormat.writeObject(Writer, this.backgroundLock);
        AscFormat.writeObject(Writer, this.timingLock);
        AscFormat.writeObject(Writer, this.transitionLock);
        AscFormat.writeObject(Writer, this.layoutLock);
        AscFormat.writeObject(Writer, this.showLock);
    };

    CChangesDrawingTimingLocks.prototype.ReadFromBinary = function(Reader){
        this.deleteLock = AscFormat.readObject(Reader);
        this.backgroundLock = AscFormat.readObject(Reader);
        this.timingLock = AscFormat.readObject(Reader);
        this.transitionLock = AscFormat.readObject(Reader);
        this.layoutLock = AscFormat.readObject(Reader);
        this.showLock = AscFormat.readObject(Reader);
    };

    CChangesDrawingTimingLocks.prototype.Undo = function(){
        var oSlide = this.Class;
        oSlide.deleteLock = null;
        oSlide.backgroundLock = null;
        oSlide.timingLock = null;
        oSlide.transitionLock = null;
        oSlide.layoutLock = null;
        oSlide.showLock = null;
    };

    CChangesDrawingTimingLocks.prototype.Redo = function(){
        var oSlide = this.Class;
         oSlide.deleteLock = this.deleteLock;
         oSlide.backgroundLock = this.backgroundLock;
         oSlide.timingLock = this.timingLock;
         oSlide.transitionLock = this.transitionLock;
         oSlide.layoutLock = this.layoutLock;
         oSlide.showLock = this.showLock;
    };
    CChangesDrawingTimingLocks.prototype.Load = function(){
        this.Redo();
        this.RefreshRecalcData();
    };
    CChangesDrawingTimingLocks.prototype.CreateReverseChange = function()
    {
        return new this.constructor(this.Class, null, null, null, null, null);
    };

    window['AscDFH'].CChangesDrawingTimingLocks = CChangesDrawingTimingLocks;


    function CChangesSparklinesChangeData(Class, OldPr, NewPr){
        this.Type = AscDFH.historyitem_Sparkline_ChangeData;
        this.OldPr = OldPr;
        this.NewPr = NewPr;
		AscDFH.CChangesBase.call(this, Class);
    }

	CChangesSparklinesChangeData.prototype = Object.create(AscDFH.CChangesBase.prototype);
	CChangesSparklinesChangeData.prototype.constructor = CChangesSparklinesChangeData;

    CChangesSparklinesChangeData.prototype.WritePr = function(Writer, Pr){
        var bIsArray = Array.isArray(Pr) ;
        Writer.WriteBool(bIsArray);
        if(bIsArray){
            Writer.WriteLong(Pr.length);
            for(var i = 0; i < Pr.length; ++i){
                Writer.WriteLong(Pr[i].sqref.c1);
                Writer.WriteLong(Pr[i].sqref.r1);
                Writer.WriteString2(Pr[i].f);
            }
        }
    };

    CChangesSparklinesChangeData.prototype.ReadPr = function(Reader){
        var bIsArray = Reader.GetBool();
        var RetPr = null;
        if(bIsArray){
            var nLength = Reader.GetLong();
            RetPr = [];
            for(var i = 0; i < nLength; ++i){
                var oSparkline = new AscCommonExcel.sparkline();
                var col = Reader.GetLong();
                var row = Reader.GetLong();
                oSparkline.sqref = new Asc.Range(col, row, col, row);
                oSparkline.setF(Reader.GetString2());
                RetPr.push(oSparkline);
            }
        }
        return RetPr;
    };

    CChangesSparklinesChangeData.prototype.WriteToBinary = function(Writer){
        this.WritePr(Writer, this.OldPr);
        this.WritePr(Writer, this.NewPr);
    };

    CChangesSparklinesChangeData.prototype.ReadFromBinary = function(Reader){
        Reader.Seek2(Reader.GetCurPos() - 4);
        var nType = Reader.GetLong();
        this.Type = nType;
        this.OldPr = this.ReadPr(Reader);
        this.NewPr = this.ReadPr(Reader);
    };

    CChangesSparklinesChangeData.prototype.Fill = function(Pr){
        var aSparklines = this.Class.arrSparklines;
        aSparklines.length = 0;
        if(Array.isArray(Pr)){
            for(var i = 0; i < Pr.length; ++i){
                aSparklines.push(Pr[i].clone())
            }
        }
        this.Class.cleanCache();
    };

    CChangesSparklinesChangeData.prototype.Undo = function(){
        this.Fill(this.OldPr);
    };

    CChangesSparklinesChangeData.prototype.Redo = function(){
        this.Fill(this.NewPr);
    };
    CChangesSparklinesChangeData.prototype.Load = function(){
        this.Redo();
        this.RefreshRecalcData();
    };

    CChangesSparklinesChangeData.prototype.CreateReverseChange = function(){
        return new CChangesSparklinesChangeData(this.Class, this.NewPr, this.OldPr);
    };
    window['AscDFH'].CChangesSparklinesChangeData = CChangesSparklinesChangeData;



    function CChangesSparklinesRemoveData(Class, oSparkline, bReverse){
        this.Type = AscDFH.historyitem_Sparkline_RemoveData;
        this.sparkline = oSparkline;
        this.bReverse = bReverse;
		AscDFH.CChangesBase.call(this, Class);
    }

	CChangesSparklinesRemoveData.prototype = Object.create(AscDFH.CChangesBase.prototype);
	CChangesSparklinesRemoveData.prototype.constructor = CChangesSparklinesRemoveData;

    CChangesSparklinesRemoveData.prototype.WriteToBinary = function(Writer){
        var bIsObject = AscCommon.isRealObject(this.sparkline);
        Writer.WriteBool(bIsObject);
        if(bIsObject){
            Writer.WriteLong(this.sparkline.sqref.c1);
            Writer.WriteLong(this.sparkline.sqref.r1);
            Writer.WriteString2(this.sparkline.f);
        }
        Writer.WriteBool(this.bReverse === true);
    };
    CChangesSparklinesRemoveData.prototype.ReadFromBinary = function(Reader){
        var bIsObject = Reader.GetLong();
        if(bIsObject){
            this.sparkline = new AscCommonExcel.sparkline();
            var col = Reader.GetLong();
            var row = Reader.GetLong();
            this.sparkline.sqref = new Asc.Range(col, row, col, row);
            this.sparkline.setF(Reader.GetString2());
        }
        this.bReverse = Reader.GetBool();
    };

    CChangesSparklinesRemoveData.prototype.Undo = function(){
        if(this.bReverse){
            this.Class.remove(this.sparkline.sqref);
        }
        else{
            this.Class.arrSparklines.push(this.sparkline);
        }
        this.Class.cleanCache();
    };
    CChangesSparklinesRemoveData.prototype.Redo = function(){
        if(this.bReverse){
            this.Class.arrSparklines.push(this.sparkline);
        }
        else{
            this.Class.remove(this.sparkline.sqref);
        }
        this.Class.cleanCache();
    };

    CChangesSparklinesRemoveData.prototype.CreateReverseChange = function(){
        return new CChangesSparklinesRemoveData(this.Class, this.sparkline, !this.bReverse);
    };


    window['AscDFH'].CChangesSparklinesRemoveData = CChangesSparklinesRemoveData;

    function CChangesDrawingsExcelColor(Class, Type, OldPr, NewPr){
        this.Type = Type;
        this.OldPr = OldPr;
        this.NewPr = NewPr;
		AscDFH.CChangesBase.call(this, Class);
    }

	CChangesDrawingsExcelColor.prototype = Object.create(AscDFH.CChangesBase.prototype);
	CChangesDrawingsExcelColor.prototype.constructor = CChangesDrawingsExcelColor;

    CChangesDrawingsExcelColor.prototype.WritePr = function(Writer, Pr){
        var bIsObject = AscCommon.isRealObject(Pr) ;
        Writer.WriteBool(bIsObject);
        if(bIsObject){
            Writer.WriteLong(Pr.getType());
            Pr.Write_ToBinary2(Writer);
        }
    };

    CChangesDrawingsExcelColor.prototype.ReadPr = function(Reader){
        var RetPr = null;
        var bIsObject = Reader.GetBool();
        if(bIsObject){
            switch (Reader.GetLong()) {
                case AscCommonExcel.UndoRedoDataTypes.RgbColor:
                    RetPr = new AscCommonExcel.RgbColor();
                    RetPr.Read_FromBinary2(Reader);
                    break;
                case AscCommonExcel.UndoRedoDataTypes.ThemeColor:
                    RetPr = new AscCommonExcel.ThemeColor();
                    RetPr = RetPr.Read_FromBinary2AndReplace(Reader);
                    break;
            }
        }
        return RetPr;
    };

    CChangesDrawingsExcelColor.prototype.WriteToBinary = function(Writer){
        this.WritePr(Writer, this.OldPr);
        this.WritePr(Writer, this.NewPr);
    };
    CChangesDrawingsExcelColor.prototype.ReadFromBinary = function(Reader){
        Reader.Seek2(Reader.GetCurPos() - 4);
        var nType = Reader.GetLong();
        this.Type = nType;
        this.OldPr = this.ReadPr(Reader);
        this.NewPr = this.ReadPr(Reader);
    };

    CChangesDrawingsExcelColor.prototype.Undo = function(){
        this.Fill(this.OldPr);
    };

    CChangesDrawingsExcelColor.prototype.Redo = function(){
        this.Fill(this.NewPr);
    };

    CChangesDrawingsExcelColor.prototype.Load = function(){
        this.Redo();
        this.RefreshRecalcData();
    };
    CChangesDrawingsExcelColor.prototype.Fill = function(Pr){
        var oClass = this.Class;
        switch(this.Type){
            case AscDFH.historyitem_Sparkline_ColorSeries:
                oClass.colorSeries = Pr;
                break;
            case AscDFH.historyitem_Sparkline_ColorNegative:
                oClass.colorNegative = Pr;
                break;
            case AscDFH.historyitem_Sparkline_ColorAxis:
                oClass.colorAxis = Pr;
                break;
            case AscDFH.historyitem_Sparkline_ColorMarkers:
                oClass.colorMarkers = Pr;
                break;
            case AscDFH.historyitem_Sparkline_ColorFirst:
                oClass.colorFirst = Pr;
                break;
            case AscDFH.historyitem_Sparkline_colorLast:
                oClass.colorLast = Pr;
                break;
            case AscDFH.historyitem_Sparkline_ColorHigh:
                oClass.colorHigh = Pr;
                break;
            case AscDFH.historyitem_Sparkline_ColorLow:
                oClass.colorLow = Pr;
                break;
        }
        oClass.cleanCache();
    };


    CChangesDrawingsExcelColor.prototype.CreateReverseChange = function(){
        return new CChangesDrawingsExcelColor(this.Class, this.Type, this.NewPr, this.OldPr);
    };

    AscDFH.CChangesDrawingsExcelColor = CChangesDrawingsExcelColor;

    function CChangesDrawingsSparklinesRemove(Class, bReverse){
        this.Type = AscDFH.historyitem_Sparkline_RemoveSparkline;
        this.bReverse = bReverse;
		AscDFH.CChangesBase.call(this, Class);
    }

	CChangesDrawingsSparklinesRemove.prototype = Object.create(AscDFH.CChangesBase.prototype);
	CChangesDrawingsSparklinesRemove.prototype.constructor = CChangesDrawingsSparklinesRemove;
    CChangesDrawingsSparklinesRemove.prototype.Undo = function(){
        if (this.Class.worksheet) {
            if(this.bReverse){
                this.Class.worksheet.removeSparklineGroup(this.Class.Get_Id());
            }
            else{
                this.Class.worksheet.insertSparklineGroup(this.Class);
            }

        }
        this.Class.cleanCache();
    };
    CChangesDrawingsSparklinesRemove.prototype.Redo = function(){
        if (this.Class.worksheet) {
            if(this.bReverse){
                this.Class.worksheet.insertSparklineGroup(this.Class);
            }
            else{
                this.Class.worksheet.removeSparklineGroup(this.Class.Get_Id());
            }
        }
        this.Class.cleanCache();
    };

    CChangesDrawingsSparklinesRemove.prototype.WriteToBinary = function(Writer){
        Writer.WriteBool(!!this.bReverse);
    };

    CChangesDrawingsSparklinesRemove.prototype.ReadFromBinary = function(Reader){
        this.bReverse = Reader.GetBool();
    };

    CChangesDrawingsSparklinesRemove.prototype.Load = function(){
        this.Redo();
        this.RefreshRecalcData();
    };

    CChangesDrawingsSparklinesRemove.prototype.CreateReverseChange = function(){
        return new CChangesDrawingsSparklinesRemove(this.Class, !this.bReverse);
    };
    window['AscDFH'].CChangesDrawingsSparklinesRemove = CChangesDrawingsSparklinesRemove;




AscDFH.changesFactory[AscDFH.historyitem_Sparkline_Type               ] = AscDFH.CChangesDrawingsLong;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_LineWeight         ] = AscDFH.CChangesDrawingsDouble;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_DisplayEmptyCellsAs] = AscDFH.CChangesDrawingsLong;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_Markers            ] = AscDFH.CChangesDrawingsBool;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_High               ] = AscDFH.CChangesDrawingsBool;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_Low                ] = AscDFH.CChangesDrawingsBool;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_First              ] = AscDFH.CChangesDrawingsBool;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_Last               ] = AscDFH.CChangesDrawingsBool;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_Negative           ] = AscDFH.CChangesDrawingsBool;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_DisplayXAxis       ] = AscDFH.CChangesDrawingsBool;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_DisplayHidden      ] = AscDFH.CChangesDrawingsBool;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_MinAxisType        ] = AscDFH.CChangesDrawingsLong;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_MaxAxisType        ] = AscDFH.CChangesDrawingsLong;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_RightToLeft        ] = AscDFH.CChangesDrawingsBool;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_ManualMax          ] = AscDFH.CChangesDrawingsDouble;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_ManualMin          ] = AscDFH.CChangesDrawingsDouble;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_DateAxis           ] = AscDFH.CChangesDrawingsBool;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_F                  ] = AscDFH.CChangesDrawingsString;


AscDFH.changesFactory[AscDFH.historyitem_Sparkline_ColorSeries        ] = AscDFH.CChangesDrawingsExcelColor;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_ColorNegative      ] = AscDFH.CChangesDrawingsExcelColor;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_ColorAxis          ] = AscDFH.CChangesDrawingsExcelColor;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_ColorMarkers       ] = AscDFH.CChangesDrawingsExcelColor;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_ColorFirst         ] = AscDFH.CChangesDrawingsExcelColor;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_colorLast          ] = AscDFH.CChangesDrawingsExcelColor;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_ColorHigh          ] = AscDFH.CChangesDrawingsExcelColor;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_ColorLow           ] = AscDFH.CChangesDrawingsExcelColor;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_ChangeData]          = AscDFH.CChangesSparklinesChangeData;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_RemoveData]          = AscDFH.CChangesSparklinesRemoveData;
AscDFH.changesFactory[AscDFH.historyitem_Sparkline_RemoveSparkline]     = AscDFH.CChangesDrawingsSparklinesRemove;

    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_Type               ] = function(oClass, value){oClass.type                = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_LineWeight         ] = function(oClass, value){oClass.lineWeight          = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_DisplayEmptyCellsAs] = function(oClass, value){oClass.displayEmptyCellsAs = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_Markers            ] = function(oClass, value){oClass.markers             = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_High               ] = function(oClass, value){oClass.high                = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_Low                ] = function(oClass, value){oClass.low                 = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_First              ] = function(oClass, value){oClass.first               = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_Last               ] = function(oClass, value){oClass.last                = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_Negative           ] = function(oClass, value){oClass.negative            = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_DisplayXAxis       ] = function(oClass, value){oClass.displayXAxis        = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_DisplayHidden      ] = function(oClass, value){oClass.displayHidden       = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_MinAxisType        ] = function(oClass, value){oClass.minAxisType         = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_MaxAxisType        ] = function(oClass, value){oClass.maxAxisType         = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_RightToLeft        ] = function(oClass, value){oClass.rightToLeft         = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_ManualMax          ] = function(oClass, value){oClass.manualMax           = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_ManualMin          ] = function(oClass, value){oClass.manualMin           = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_DateAxis           ] = function(oClass, value){oClass.dateAxis            = value; oClass.cleanCache();};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_Sparkline_F                  ] = function(oClass, value){oClass.f                   = value; oClass.cleanCache();};

})(window);
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {

function CreateGeometry(prst){
    var f = new AscFormat.Geometry();
    switch(prst){
        case 'accentBorderCallout1':{
            f.AddAdj('adj1', 15, '18750');
            f.AddAdj('adj2', 15, '-8333');
            f.AddAdj('adj3', 15, '112500');
            f.AddAdj('adj4', 15, '-38333');
            f.AddGuide('y1', 0, 'h', 'adj1', '100000');
            f.AddGuide('x1', 0, 'w', 'adj2', '100000');
            f.AddGuide('y2', 0, 'h', 'adj3', '100000');
            f.AddGuide('x2', 0, 'w', 'adj4', '100000');
            f.AddHandleXY('adj2','-2147483647','2147483647','adj1','-2147483647','2147483647', 'x1', 'y1');
            f.AddHandleXY('adj4','-2147483647','2147483647','adj3','-2147483647','2147483647', 'x2', 'y2');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 't');
            f.AddPathCommand(6);
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'x2', 'y2');
            break;
        }
        case 'accentBorderCallout2':{
            f.AddAdj('adj1', 15, '18750');
            f.AddAdj('adj2', 15, '-8333');
            f.AddAdj('adj3', 15, '18750');
            f.AddAdj('adj4', 15, '-16667');
            f.AddAdj('adj5', 15, '112500');
            f.AddAdj('adj6', 15, '-46667');
            f.AddGuide('y1', 0, 'h', 'adj1', '100000');
            f.AddGuide('x1', 0, 'w', 'adj2', '100000');
            f.AddGuide('y2', 0, 'h', 'adj3', '100000');
            f.AddGuide('x2', 0, 'w', 'adj4', '100000');
            f.AddGuide('y3', 0, 'h', 'adj5', '100000');
            f.AddGuide('x3', 0, 'w', 'adj6', '100000');
            f.AddHandleXY('adj2','-2147483647','2147483647','adj1','-2147483647','2147483647', 'x1', 'y1');
            f.AddHandleXY('adj4','-2147483647','2147483647','adj3','-2147483647','2147483647', 'x2', 'y2');
            f.AddHandleXY('adj6','-2147483647','2147483647','adj5','-2147483647','2147483647', 'x3', 'y3');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 't');
            f.AddPathCommand(6);
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x3', 'y3');
            break;
        }
        case 'accentBorderCallout3':{
            f.AddAdj('adj1', 15, '18750');
            f.AddAdj('adj2', 15, '-8333');
            f.AddAdj('adj3', 15, '18750');
            f.AddAdj('adj4', 15, '-16667');
            f.AddAdj('adj5', 15, '100000');
            f.AddAdj('adj6', 15, '-16667');
            f.AddAdj('adj7', 15, '112963');
            f.AddAdj('adj8', 15, '-8333');
            f.AddGuide('y1', 0, 'h', 'adj1', '100000');
            f.AddGuide('x1', 0, 'w', 'adj2', '100000');
            f.AddGuide('y2', 0, 'h', 'adj3', '100000');
            f.AddGuide('x2', 0, 'w', 'adj4', '100000');
            f.AddGuide('y3', 0, 'h', 'adj5', '100000');
            f.AddGuide('x3', 0, 'w', 'adj6', '100000');
            f.AddGuide('y4', 0, 'h', 'adj7', '100000');
            f.AddGuide('x4', 0, 'w', 'adj8', '100000');
            f.AddHandleXY('adj2','-2147483647','2147483647','adj1','-2147483647','2147483647', 'x1', 'y1');
            f.AddHandleXY('adj4','-2147483647','2147483647','adj3','-2147483647','2147483647', 'x2', 'y2');
            f.AddHandleXY('adj6','-2147483647','2147483647','adj5','-2147483647','2147483647', 'x3', 'y3');
            f.AddHandleXY('adj8','-2147483647','2147483647','adj7','-2147483647','2147483647', 'x4', 'y4');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 't');
            f.AddPathCommand(6);
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(2, 'x4', 'y4');
            break;
        }
        case 'accentCallout1':{
            f.AddAdj('adj1', 15, '18750');
            f.AddAdj('adj2', 15, '-8333');
            f.AddAdj('adj3', 15, '112500');
            f.AddAdj('adj4', 15, '-38333');
            f.AddGuide('y1', 0, 'h', 'adj1', '100000');
            f.AddGuide('x1', 0, 'w', 'adj2', '100000');
            f.AddGuide('y2', 0, 'h', 'adj3', '100000');
            f.AddGuide('x2', 0, 'w', 'adj4', '100000');
            f.AddHandleXY('adj2','-2147483647','2147483647','adj1','-2147483647','2147483647', 'x1', 'y1');
            f.AddHandleXY('adj4','-2147483647','2147483647','adj3','-2147483647','2147483647', 'x2', 'y2');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 't');
            f.AddPathCommand(6);
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'x2', 'y2');
            break;
        }
        case 'accentCallout2':{
            f.AddAdj('adj1', 15, '18750');
            f.AddAdj('adj2', 15, '-8333');
            f.AddAdj('adj3', 15, '18750');
            f.AddAdj('adj4', 15, '-16667');
            f.AddAdj('adj5', 15, '112500');
            f.AddAdj('adj6', 15, '-46667');
            f.AddGuide('y1', 0, 'h', 'adj1', '100000');
            f.AddGuide('x1', 0, 'w', 'adj2', '100000');
            f.AddGuide('y2', 0, 'h', 'adj3', '100000');
            f.AddGuide('x2', 0, 'w', 'adj4', '100000');
            f.AddGuide('y3', 0, 'h', 'adj5', '100000');
            f.AddGuide('x3', 0, 'w', 'adj6', '100000');
            f.AddHandleXY('adj2','-2147483647','2147483647','adj1','-2147483647','2147483647', 'x1', 'y1');
            f.AddHandleXY('adj4','-2147483647','2147483647','adj3','-2147483647','2147483647', 'x2', 'y2');
            f.AddHandleXY('adj6','-2147483647','2147483647','adj5','-2147483647','2147483647', 'x3', 'y3');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 't');
            f.AddPathCommand(6);
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x3', 'y3');
            break;
        }
        case 'accentCallout3':{
            f.AddAdj('adj1', 15, '18750');
            f.AddAdj('adj2', 15, '-8333');
            f.AddAdj('adj3', 15, '18750');
            f.AddAdj('adj4', 15, '-16667');
            f.AddAdj('adj5', 15, '100000');
            f.AddAdj('adj6', 15, '-16667');
            f.AddAdj('adj7', 15, '112963');
            f.AddAdj('adj8', 15, '-8333');
            f.AddGuide('y1', 0, 'h', 'adj1', '100000');
            f.AddGuide('x1', 0, 'w', 'adj2', '100000');
            f.AddGuide('y2', 0, 'h', 'adj3', '100000');
            f.AddGuide('x2', 0, 'w', 'adj4', '100000');
            f.AddGuide('y3', 0, 'h', 'adj5', '100000');
            f.AddGuide('x3', 0, 'w', 'adj6', '100000');
            f.AddGuide('y4', 0, 'h', 'adj7', '100000');
            f.AddGuide('x4', 0, 'w', 'adj8', '100000');
            f.AddHandleXY('adj2','-2147483647','2147483647','adj1','-2147483647','2147483647', 'x1', 'y1');
            f.AddHandleXY('adj4','-2147483647','2147483647','adj3','-2147483647','2147483647', 'x2', 'y2');
            f.AddHandleXY('adj6','-2147483647','2147483647','adj5','-2147483647','2147483647', 'x3', 'y3');
            f.AddHandleXY('adj8','-2147483647','2147483647','adj7','-2147483647','2147483647', 'x4', 'y4');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 't');
            f.AddPathCommand(6);
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(2, 'x4', 'y4');
            break;
        }
        case 'actionButtonBackPrevious':{
            f.AddGuide('dx2', 0, 'ss', '3', '8');
            f.AddGuide('g9', 1, 'vc', '0', 'dx2');
            f.AddGuide('g10', 1, 'vc', 'dx2', '0');
            f.AddGuide('g11', 1, 'hc', '0', 'dx2');
            f.AddGuide('g12', 1, 'hc', 'dx2', '0');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g11', 'vc');
            f.AddPathCommand(2, 'g12', 'g9');
            f.AddPathCommand(2, 'g12', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darken', false, undefined, undefined);
            f.AddPathCommand(1, 'g11', 'vc');
            f.AddPathCommand(2, 'g12', 'g9');
            f.AddPathCommand(2, 'g12', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'g11', 'vc');
            f.AddPathCommand(2, 'g12', 'g9');
            f.AddPathCommand(2, 'g12', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'actionButtonBeginning':{
            f.AddGuide('dx2', 0, 'ss', '3', '8');
            f.AddGuide('g9', 1, 'vc', '0', 'dx2');
            f.AddGuide('g10', 1, 'vc', 'dx2', '0');
            f.AddGuide('g11', 1, 'hc', '0', 'dx2');
            f.AddGuide('g12', 1, 'hc', 'dx2', '0');
            f.AddGuide('g13', 0, 'ss', '3', '4');
            f.AddGuide('g14', 0, 'g13', '1', '8');
            f.AddGuide('g15', 0, 'g13', '1', '4');
            f.AddGuide('g16', 1, 'g11', 'g14', '0');
            f.AddGuide('g17', 1, 'g11', 'g15', '0');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g17', 'vc');
            f.AddPathCommand(2, 'g12', 'g9');
            f.AddPathCommand(2, 'g12', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g16', 'g9');
            f.AddPathCommand(2, 'g11', 'g9');
            f.AddPathCommand(2, 'g11', 'g10');
            f.AddPathCommand(2, 'g16', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darken', false, undefined, undefined);
            f.AddPathCommand(1, 'g17', 'vc');
            f.AddPathCommand(2, 'g12', 'g9');
            f.AddPathCommand(2, 'g12', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g16', 'g9');
            f.AddPathCommand(2, 'g11', 'g9');
            f.AddPathCommand(2, 'g11', 'g10');
            f.AddPathCommand(2, 'g16', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'g17', 'vc');
            f.AddPathCommand(2, 'g12', 'g9');
            f.AddPathCommand(2, 'g12', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g16', 'g9');
            f.AddPathCommand(2, 'g16', 'g10');
            f.AddPathCommand(2, 'g11', 'g10');
            f.AddPathCommand(2, 'g11', 'g9');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'actionButtonBlank':{
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'actionButtonDocument':{
            f.AddGuide('dx2', 0, 'ss', '3', '8');
            f.AddGuide('g9', 1, 'vc', '0', 'dx2');
            f.AddGuide('g10', 1, 'vc', 'dx2', '0');
            f.AddGuide('dx1', 0, 'ss', '9', '32');
            f.AddGuide('g11', 1, 'hc', '0', 'dx1');
            f.AddGuide('g12', 1, 'hc', 'dx1', '0');
            f.AddGuide('g13', 0, 'ss', '3', '16');
            f.AddGuide('g14', 1, 'g12', '0', 'g13');
            f.AddGuide('g15', 1, 'g9', 'g13', '0');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g11', 'g9');
            f.AddPathCommand(2, 'g14', 'g9');
            f.AddPathCommand(2, 'g12', 'g15');
            f.AddPathCommand(2, 'g12', 'g10');
            f.AddPathCommand(2, 'g11', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'g11', 'g9');
            f.AddPathCommand(2, 'g14', 'g9');
            f.AddPathCommand(2, 'g14', 'g15');
            f.AddPathCommand(2, 'g12', 'g15');
            f.AddPathCommand(2, 'g12', 'g10');
            f.AddPathCommand(2, 'g11', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darken', false, undefined, undefined);
            f.AddPathCommand(1, 'g14', 'g9');
            f.AddPathCommand(2, 'g14', 'g15');
            f.AddPathCommand(2, 'g12', 'g15');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'g11', 'g9');
            f.AddPathCommand(2, 'g14', 'g9');
            f.AddPathCommand(2, 'g12', 'g15');
            f.AddPathCommand(2, 'g12', 'g10');
            f.AddPathCommand(2, 'g11', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g12', 'g15');
            f.AddPathCommand(2, 'g14', 'g15');
            f.AddPathCommand(2, 'g14', 'g9');
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'actionButtonEnd':{
            f.AddGuide('dx2', 0, 'ss', '3', '8');
            f.AddGuide('g9', 1, 'vc', '0', 'dx2');
            f.AddGuide('g10', 1, 'vc', 'dx2', '0');
            f.AddGuide('g11', 1, 'hc', '0', 'dx2');
            f.AddGuide('g12', 1, 'hc', 'dx2', '0');
            f.AddGuide('g13', 0, 'ss', '3', '4');
            f.AddGuide('g14', 0, 'g13', '3', '4');
            f.AddGuide('g15', 0, 'g13', '7', '8');
            f.AddGuide('g16', 1, 'g11', 'g14', '0');
            f.AddGuide('g17', 1, 'g11', 'g15', '0');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g16', 'vc');
            f.AddPathCommand(2, 'g11', 'g9');
            f.AddPathCommand(2, 'g11', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g17', 'g9');
            f.AddPathCommand(2, 'g12', 'g9');
            f.AddPathCommand(2, 'g12', 'g10');
            f.AddPathCommand(2, 'g17', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darken', false, undefined, undefined);
            f.AddPathCommand(1, 'g16', 'vc');
            f.AddPathCommand(2, 'g11', 'g9');
            f.AddPathCommand(2, 'g11', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g17', 'g9');
            f.AddPathCommand(2, 'g12', 'g9');
            f.AddPathCommand(2, 'g12', 'g10');
            f.AddPathCommand(2, 'g17', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'g16', 'vc');
            f.AddPathCommand(2, 'g11', 'g10');
            f.AddPathCommand(2, 'g11', 'g9');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g17', 'g9');
            f.AddPathCommand(2, 'g12', 'g9');
            f.AddPathCommand(2, 'g12', 'g10');
            f.AddPathCommand(2, 'g17', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'actionButtonForwardNext':{
            f.AddGuide('dx2', 0, 'ss', '3', '8');
            f.AddGuide('g9', 1, 'vc', '0', 'dx2');
            f.AddGuide('g10', 1, 'vc', 'dx2', '0');
            f.AddGuide('g11', 1, 'hc', '0', 'dx2');
            f.AddGuide('g12', 1, 'hc', 'dx2', '0');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g12', 'vc');
            f.AddPathCommand(2, 'g11', 'g9');
            f.AddPathCommand(2, 'g11', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darken', false, undefined, undefined);
            f.AddPathCommand(1, 'g12', 'vc');
            f.AddPathCommand(2, 'g11', 'g9');
            f.AddPathCommand(2, 'g11', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'g12', 'vc');
            f.AddPathCommand(2, 'g11', 'g10');
            f.AddPathCommand(2, 'g11', 'g9');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'actionButtonHelp':{
            f.AddGuide('dx2', 0, 'ss', '3', '8');
            f.AddGuide('g9', 1, 'vc', '0', 'dx2');
            f.AddGuide('g11', 1, 'hc', '0', 'dx2');
            f.AddGuide('g13', 0, 'ss', '3', '4');
            f.AddGuide('g14', 0, 'g13', '1', '7');
            f.AddGuide('g15', 0, 'g13', '3', '14');
            f.AddGuide('g16', 0, 'g13', '2', '7');
            f.AddGuide('g19', 0, 'g13', '3', '7');
            f.AddGuide('g20', 0, 'g13', '4', '7');
            f.AddGuide('g21', 0, 'g13', '17', '28');
            f.AddGuide('g23', 0, 'g13', '21', '28');
            f.AddGuide('g24', 0, 'g13', '11', '14');
            f.AddGuide('g27', 1, 'g9', 'g16', '0');
            f.AddGuide('g29', 1, 'g9', 'g21', '0');
            f.AddGuide('g30', 1, 'g9', 'g23', '0');
            f.AddGuide('g31', 1, 'g9', 'g24', '0');
            f.AddGuide('g33', 1, 'g11', 'g15', '0');
            f.AddGuide('g36', 1, 'g11', 'g19', '0');
            f.AddGuide('g37', 1, 'g11', 'g20', '0');
            f.AddGuide('g41', 0, 'g13', '1', '14');
            f.AddGuide('g42', 0, 'g13', '3', '28');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g33', 'g27');
            f.AddPathCommand(3, 'g16', 'g16', 'cd2', 'cd2');
            f.AddPathCommand(3, 'g14', 'g15', '0', 'cd4');
            f.AddPathCommand(3, 'g41', 'g42', '_3cd4', '-5400000');
            f.AddPathCommand(2, 'g37', 'g30');
            f.AddPathCommand(2, 'g36', 'g30');
            f.AddPathCommand(2, 'g36', 'g29');
            f.AddPathCommand(3, 'g14', 'g15', 'cd2', 'cd4');
            f.AddPathCommand(3, 'g41', 'g42', 'cd4', '-5400000');
            f.AddPathCommand(3, 'g14', 'g14', '0', '-10800000');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'hc', 'g31');
            f.AddPathCommand(3, 'g42', 'g42', '_3cd4', '21600000');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darken', false, undefined, undefined);
            f.AddPathCommand(1, 'g33', 'g27');
            f.AddPathCommand(3, 'g16', 'g16', 'cd2', 'cd2');
            f.AddPathCommand(3, 'g14', 'g15', '0', 'cd4');
            f.AddPathCommand(3, 'g41', 'g42', '_3cd4', '-5400000');
            f.AddPathCommand(2, 'g37', 'g30');
            f.AddPathCommand(2, 'g36', 'g30');
            f.AddPathCommand(2, 'g36', 'g29');
            f.AddPathCommand(3, 'g14', 'g15', 'cd2', 'cd4');
            f.AddPathCommand(3, 'g41', 'g42', 'cd4', '-5400000');
            f.AddPathCommand(3, 'g14', 'g14', '0', '-10800000');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'hc', 'g31');
            f.AddPathCommand(3, 'g42', 'g42', '_3cd4', '21600000');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'g33', 'g27');
            f.AddPathCommand(3, 'g16', 'g16', 'cd2', 'cd2');
            f.AddPathCommand(3, 'g14', 'g15', '0', 'cd4');
            f.AddPathCommand(3, 'g41', 'g42', '_3cd4', '-5400000');
            f.AddPathCommand(2, 'g37', 'g30');
            f.AddPathCommand(2, 'g36', 'g30');
            f.AddPathCommand(2, 'g36', 'g29');
            f.AddPathCommand(3, 'g14', 'g15', 'cd2', 'cd4');
            f.AddPathCommand(3, 'g41', 'g42', 'cd4', '-5400000');
            f.AddPathCommand(3, 'g14', 'g14', '0', '-10800000');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'hc', 'g31');
            f.AddPathCommand(3, 'g42', 'g42', '_3cd4', '21600000');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'actionButtonHome':{
            f.AddGuide('dx2', 0, 'ss', '3', '8');
            f.AddGuide('g9', 1, 'vc', '0', 'dx2');
            f.AddGuide('g10', 1, 'vc', 'dx2', '0');
            f.AddGuide('g11', 1, 'hc', '0', 'dx2');
            f.AddGuide('g12', 1, 'hc', 'dx2', '0');
            f.AddGuide('g13', 0, 'ss', '3', '4');
            f.AddGuide('g14', 0, 'g13', '1', '16');
            f.AddGuide('g15', 0, 'g13', '1', '8');
            f.AddGuide('g16', 0, 'g13', '3', '16');
            f.AddGuide('g17', 0, 'g13', '5', '16');
            f.AddGuide('g18', 0, 'g13', '7', '16');
            f.AddGuide('g19', 0, 'g13', '9', '16');
            f.AddGuide('g20', 0, 'g13', '11', '16');
            f.AddGuide('g21', 0, 'g13', '3', '4');
            f.AddGuide('g22', 0, 'g13', '13', '16');
            f.AddGuide('g23', 0, 'g13', '7', '8');
            f.AddGuide('g24', 1, 'g9', 'g14', '0');
            f.AddGuide('g25', 1, 'g9', 'g16', '0');
            f.AddGuide('g26', 1, 'g9', 'g17', '0');
            f.AddGuide('g27', 1, 'g9', 'g21', '0');
            f.AddGuide('g28', 1, 'g11', 'g15', '0');
            f.AddGuide('g29', 1, 'g11', 'g18', '0');
            f.AddGuide('g30', 1, 'g11', 'g19', '0');
            f.AddGuide('g31', 1, 'g11', 'g20', '0');
            f.AddGuide('g32', 1, 'g11', 'g22', '0');
            f.AddGuide('g33', 1, 'g11', 'g23', '0');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'hc', 'g9');
            f.AddPathCommand(2, 'g11', 'vc');
            f.AddPathCommand(2, 'g28', 'vc');
            f.AddPathCommand(2, 'g28', 'g10');
            f.AddPathCommand(2, 'g33', 'g10');
            f.AddPathCommand(2, 'g33', 'vc');
            f.AddPathCommand(2, 'g12', 'vc');
            f.AddPathCommand(2, 'g32', 'g26');
            f.AddPathCommand(2, 'g32', 'g24');
            f.AddPathCommand(2, 'g31', 'g24');
            f.AddPathCommand(2, 'g31', 'g25');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'g32', 'g26');
            f.AddPathCommand(2, 'g32', 'g24');
            f.AddPathCommand(2, 'g31', 'g24');
            f.AddPathCommand(2, 'g31', 'g25');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g28', 'vc');
            f.AddPathCommand(2, 'g28', 'g10');
            f.AddPathCommand(2, 'g29', 'g10');
            f.AddPathCommand(2, 'g29', 'g27');
            f.AddPathCommand(2, 'g30', 'g27');
            f.AddPathCommand(2, 'g30', 'g10');
            f.AddPathCommand(2, 'g33', 'g10');
            f.AddPathCommand(2, 'g33', 'vc');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darken', false, undefined, undefined);
            f.AddPathCommand(1, 'hc', 'g9');
            f.AddPathCommand(2, 'g11', 'vc');
            f.AddPathCommand(2, 'g12', 'vc');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g29', 'g27');
            f.AddPathCommand(2, 'g30', 'g27');
            f.AddPathCommand(2, 'g30', 'g10');
            f.AddPathCommand(2, 'g29', 'g10');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'hc', 'g9');
            f.AddPathCommand(2, 'g31', 'g25');
            f.AddPathCommand(2, 'g31', 'g24');
            f.AddPathCommand(2, 'g32', 'g24');
            f.AddPathCommand(2, 'g32', 'g26');
            f.AddPathCommand(2, 'g12', 'vc');
            f.AddPathCommand(2, 'g33', 'vc');
            f.AddPathCommand(2, 'g33', 'g10');
            f.AddPathCommand(2, 'g28', 'g10');
            f.AddPathCommand(2, 'g28', 'vc');
            f.AddPathCommand(2, 'g11', 'vc');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g31', 'g25');
            f.AddPathCommand(2, 'g32', 'g26');
            f.AddPathCommand(1, 'g33', 'vc');
            f.AddPathCommand(2, 'g28', 'vc');
            f.AddPathCommand(1, 'g29', 'g10');
            f.AddPathCommand(2, 'g29', 'g27');
            f.AddPathCommand(2, 'g30', 'g27');
            f.AddPathCommand(2, 'g30', 'g10');
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'actionButtonInformation':{
            f.AddGuide('dx2', 0, 'ss', '3', '8');
            f.AddGuide('g9', 1, 'vc', '0', 'dx2');
            f.AddGuide('g11', 1, 'hc', '0', 'dx2');
            f.AddGuide('g13', 0, 'ss', '3', '4');
            f.AddGuide('g14', 0, 'g13', '1', '32');
            f.AddGuide('g17', 0, 'g13', '5', '16');
            f.AddGuide('g18', 0, 'g13', '3', '8');
            f.AddGuide('g19', 0, 'g13', '13', '32');
            f.AddGuide('g20', 0, 'g13', '19', '32');
            f.AddGuide('g22', 0, 'g13', '11', '16');
            f.AddGuide('g23', 0, 'g13', '13', '16');
            f.AddGuide('g24', 0, 'g13', '7', '8');
            f.AddGuide('g25', 1, 'g9', 'g14', '0');
            f.AddGuide('g28', 1, 'g9', 'g17', '0');
            f.AddGuide('g29', 1, 'g9', 'g18', '0');
            f.AddGuide('g30', 1, 'g9', 'g23', '0');
            f.AddGuide('g31', 1, 'g9', 'g24', '0');
            f.AddGuide('g32', 1, 'g11', 'g17', '0');
            f.AddGuide('g34', 1, 'g11', 'g19', '0');
            f.AddGuide('g35', 1, 'g11', 'g20', '0');
            f.AddGuide('g37', 1, 'g11', 'g22', '0');
            f.AddGuide('g38', 0, 'g13', '3', '32');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'hc', 'g9');
            f.AddPathCommand(3, 'dx2', 'dx2', '_3cd4', '21600000');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darken', false, undefined, undefined);
            f.AddPathCommand(1, 'hc', 'g9');
            f.AddPathCommand(3, 'dx2', 'dx2', '_3cd4', '21600000');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'hc', 'g25');
            f.AddPathCommand(3, 'g38', 'g38', '_3cd4', '21600000');
            f.AddPathCommand(1, 'g32', 'g28');
            f.AddPathCommand(2, 'g32', 'g29');
            f.AddPathCommand(2, 'g34', 'g29');
            f.AddPathCommand(2, 'g34', 'g30');
            f.AddPathCommand(2, 'g32', 'g30');
            f.AddPathCommand(2, 'g32', 'g31');
            f.AddPathCommand(2, 'g37', 'g31');
            f.AddPathCommand(2, 'g37', 'g30');
            f.AddPathCommand(2, 'g35', 'g30');
            f.AddPathCommand(2, 'g35', 'g28');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'lighten', false, undefined, undefined);
            f.AddPathCommand(1, 'hc', 'g25');
            f.AddPathCommand(3, 'g38', 'g38', '_3cd4', '21600000');
            f.AddPathCommand(1, 'g32', 'g28');
            f.AddPathCommand(2, 'g35', 'g28');
            f.AddPathCommand(2, 'g35', 'g30');
            f.AddPathCommand(2, 'g37', 'g30');
            f.AddPathCommand(2, 'g37', 'g31');
            f.AddPathCommand(2, 'g32', 'g31');
            f.AddPathCommand(2, 'g32', 'g30');
            f.AddPathCommand(2, 'g34', 'g30');
            f.AddPathCommand(2, 'g34', 'g29');
            f.AddPathCommand(2, 'g32', 'g29');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'hc', 'g9');
            f.AddPathCommand(3, 'dx2', 'dx2', '_3cd4', '21600000');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'hc', 'g25');
            f.AddPathCommand(3, 'g38', 'g38', '_3cd4', '21600000');
            f.AddPathCommand(1, 'g32', 'g28');
            f.AddPathCommand(2, 'g35', 'g28');
            f.AddPathCommand(2, 'g35', 'g30');
            f.AddPathCommand(2, 'g37', 'g30');
            f.AddPathCommand(2, 'g37', 'g31');
            f.AddPathCommand(2, 'g32', 'g31');
            f.AddPathCommand(2, 'g32', 'g30');
            f.AddPathCommand(2, 'g34', 'g30');
            f.AddPathCommand(2, 'g34', 'g29');
            f.AddPathCommand(2, 'g32', 'g29');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'actionButtonMovie':{
            f.AddGuide('dx2', 0, 'ss', '3', '8');
            f.AddGuide('g9', 1, 'vc', '0', 'dx2');
            f.AddGuide('g10', 1, 'vc', 'dx2', '0');
            f.AddGuide('g11', 1, 'hc', '0', 'dx2');
            f.AddGuide('g12', 1, 'hc', 'dx2', '0');
            f.AddGuide('g13', 0, 'ss', '3', '4');
            f.AddGuide('g14', 0, 'g13', '1455', '21600');
            f.AddGuide('g15', 0, 'g13', '1905', '21600');
            f.AddGuide('g16', 0, 'g13', '2325', '21600');
            f.AddGuide('g17', 0, 'g13', '16155', '21600');
            f.AddGuide('g18', 0, 'g13', '17010', '21600');
            f.AddGuide('g19', 0, 'g13', '19335', '21600');
            f.AddGuide('g20', 0, 'g13', '19725', '21600');
            f.AddGuide('g21', 0, 'g13', '20595', '21600');
            f.AddGuide('g22', 0, 'g13', '5280', '21600');
            f.AddGuide('g23', 0, 'g13', '5730', '21600');
            f.AddGuide('g24', 0, 'g13', '6630', '21600');
            f.AddGuide('g25', 0, 'g13', '7492', '21600');
            f.AddGuide('g26', 0, 'g13', '9067', '21600');
            f.AddGuide('g27', 0, 'g13', '9555', '21600');
            f.AddGuide('g28', 0, 'g13', '13342', '21600');
            f.AddGuide('g29', 0, 'g13', '14580', '21600');
            f.AddGuide('g30', 0, 'g13', '15592', '21600');
            f.AddGuide('g31', 1, 'g11', 'g14', '0');
            f.AddGuide('g32', 1, 'g11', 'g15', '0');
            f.AddGuide('g33', 1, 'g11', 'g16', '0');
            f.AddGuide('g34', 1, 'g11', 'g17', '0');
            f.AddGuide('g35', 1, 'g11', 'g18', '0');
            f.AddGuide('g36', 1, 'g11', 'g19', '0');
            f.AddGuide('g37', 1, 'g11', 'g20', '0');
            f.AddGuide('g38', 1, 'g11', 'g21', '0');
            f.AddGuide('g39', 1, 'g9', 'g22', '0');
            f.AddGuide('g40', 1, 'g9', 'g23', '0');
            f.AddGuide('g41', 1, 'g9', 'g24', '0');
            f.AddGuide('g42', 1, 'g9', 'g25', '0');
            f.AddGuide('g43', 1, 'g9', 'g26', '0');
            f.AddGuide('g44', 1, 'g9', 'g27', '0');
            f.AddGuide('g45', 1, 'g9', 'g28', '0');
            f.AddGuide('g46', 1, 'g9', 'g29', '0');
            f.AddGuide('g47', 1, 'g9', 'g30', '0');
            f.AddGuide('g48', 1, 'g9', 'g31', '0');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g11', 'g39');
            f.AddPathCommand(2, 'g11', 'g44');
            f.AddPathCommand(2, 'g31', 'g44');
            f.AddPathCommand(2, 'g32', 'g43');
            f.AddPathCommand(2, 'g33', 'g43');
            f.AddPathCommand(2, 'g33', 'g47');
            f.AddPathCommand(2, 'g35', 'g47');
            f.AddPathCommand(2, 'g35', 'g45');
            f.AddPathCommand(2, 'g36', 'g45');
            f.AddPathCommand(2, 'g38', 'g46');
            f.AddPathCommand(2, 'g12', 'g46');
            f.AddPathCommand(2, 'g12', 'g41');
            f.AddPathCommand(2, 'g38', 'g41');
            f.AddPathCommand(2, 'g37', 'g42');
            f.AddPathCommand(2, 'g35', 'g42');
            f.AddPathCommand(2, 'g35', 'g41');
            f.AddPathCommand(2, 'g34', 'g40');
            f.AddPathCommand(2, 'g32', 'g40');
            f.AddPathCommand(2, 'g31', 'g39');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darken', false, undefined, undefined);
            f.AddPathCommand(1, 'g11', 'g39');
            f.AddPathCommand(2, 'g11', 'g44');
            f.AddPathCommand(2, 'g31', 'g44');
            f.AddPathCommand(2, 'g32', 'g43');
            f.AddPathCommand(2, 'g33', 'g43');
            f.AddPathCommand(2, 'g33', 'g47');
            f.AddPathCommand(2, 'g35', 'g47');
            f.AddPathCommand(2, 'g35', 'g45');
            f.AddPathCommand(2, 'g36', 'g45');
            f.AddPathCommand(2, 'g38', 'g46');
            f.AddPathCommand(2, 'g12', 'g46');
            f.AddPathCommand(2, 'g12', 'g41');
            f.AddPathCommand(2, 'g38', 'g41');
            f.AddPathCommand(2, 'g37', 'g42');
            f.AddPathCommand(2, 'g35', 'g42');
            f.AddPathCommand(2, 'g35', 'g41');
            f.AddPathCommand(2, 'g34', 'g40');
            f.AddPathCommand(2, 'g32', 'g40');
            f.AddPathCommand(2, 'g31', 'g39');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'g11', 'g39');
            f.AddPathCommand(2, 'g31', 'g39');
            f.AddPathCommand(2, 'g32', 'g40');
            f.AddPathCommand(2, 'g34', 'g40');
            f.AddPathCommand(2, 'g35', 'g41');
            f.AddPathCommand(2, 'g35', 'g42');
            f.AddPathCommand(2, 'g37', 'g42');
            f.AddPathCommand(2, 'g38', 'g41');
            f.AddPathCommand(2, 'g12', 'g41');
            f.AddPathCommand(2, 'g12', 'g46');
            f.AddPathCommand(2, 'g38', 'g46');
            f.AddPathCommand(2, 'g36', 'g45');
            f.AddPathCommand(2, 'g35', 'g45');
            f.AddPathCommand(2, 'g35', 'g47');
            f.AddPathCommand(2, 'g33', 'g47');
            f.AddPathCommand(2, 'g33', 'g43');
            f.AddPathCommand(2, 'g32', 'g43');
            f.AddPathCommand(2, 'g31', 'g44');
            f.AddPathCommand(2, 'g11', 'g44');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'actionButtonReturn':{
            f.AddGuide('dx2', 0, 'ss', '3', '8');
            f.AddGuide('g9', 1, 'vc', '0', 'dx2');
            f.AddGuide('g10', 1, 'vc', 'dx2', '0');
            f.AddGuide('g11', 1, 'hc', '0', 'dx2');
            f.AddGuide('g12', 1, 'hc', 'dx2', '0');
            f.AddGuide('g13', 0, 'ss', '3', '4');
            f.AddGuide('g14', 0, 'g13', '7', '8');
            f.AddGuide('g15', 0, 'g13', '3', '4');
            f.AddGuide('g16', 0, 'g13', '5', '8');
            f.AddGuide('g17', 0, 'g13', '3', '8');
            f.AddGuide('g18', 0, 'g13', '1', '4');
            f.AddGuide('g19', 1, 'g9', 'g15', '0');
            f.AddGuide('g20', 1, 'g9', 'g16', '0');
            f.AddGuide('g21', 1, 'g9', 'g18', '0');
            f.AddGuide('g22', 1, 'g11', 'g14', '0');
            f.AddGuide('g23', 1, 'g11', 'g15', '0');
            f.AddGuide('g24', 1, 'g11', 'g16', '0');
            f.AddGuide('g25', 1, 'g11', 'g17', '0');
            f.AddGuide('g26', 1, 'g11', 'g18', '0');
            f.AddGuide('g27', 0, 'g13', '1', '8');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g12', 'g21');
            f.AddPathCommand(2, 'g23', 'g9');
            f.AddPathCommand(2, 'hc', 'g21');
            f.AddPathCommand(2, 'g24', 'g21');
            f.AddPathCommand(2, 'g24', 'g20');
            f.AddPathCommand(3, 'g27', 'g27', '0', 'cd4');
            f.AddPathCommand(2, 'g25', 'g19');
            f.AddPathCommand(3, 'g27', 'g27', 'cd4', 'cd4');
            f.AddPathCommand(2, 'g26', 'g21');
            f.AddPathCommand(2, 'g11', 'g21');
            f.AddPathCommand(2, 'g11', 'g20');
            f.AddPathCommand(3, 'g17', 'g17', 'cd2', '-5400000');
            f.AddPathCommand(2, 'hc', 'g10');
            f.AddPathCommand(3, 'g17', 'g17', 'cd4', '-5400000');
            f.AddPathCommand(2, 'g22', 'g21');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darken', false, undefined, undefined);
            f.AddPathCommand(1, 'g12', 'g21');
            f.AddPathCommand(2, 'g23', 'g9');
            f.AddPathCommand(2, 'hc', 'g21');
            f.AddPathCommand(2, 'g24', 'g21');
            f.AddPathCommand(2, 'g24', 'g20');
            f.AddPathCommand(3, 'g27', 'g27', '0', 'cd4');
            f.AddPathCommand(2, 'g25', 'g19');
            f.AddPathCommand(3, 'g27', 'g27', 'cd4', 'cd4');
            f.AddPathCommand(2, 'g26', 'g21');
            f.AddPathCommand(2, 'g11', 'g21');
            f.AddPathCommand(2, 'g11', 'g20');
            f.AddPathCommand(3, 'g17', 'g17', 'cd2', '-5400000');
            f.AddPathCommand(2, 'hc', 'g10');
            f.AddPathCommand(3, 'g17', 'g17', 'cd4', '-5400000');
            f.AddPathCommand(2, 'g22', 'g21');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'g12', 'g21');
            f.AddPathCommand(2, 'g22', 'g21');
            f.AddPathCommand(2, 'g22', 'g20');
            f.AddPathCommand(3, 'g17', 'g17', '0', 'cd4');
            f.AddPathCommand(2, 'g25', 'g10');
            f.AddPathCommand(3, 'g17', 'g17', 'cd4', 'cd4');
            f.AddPathCommand(2, 'g11', 'g21');
            f.AddPathCommand(2, 'g26', 'g21');
            f.AddPathCommand(2, 'g26', 'g20');
            f.AddPathCommand(3, 'g27', 'g27', 'cd2', '-5400000');
            f.AddPathCommand(2, 'hc', 'g19');
            f.AddPathCommand(3, 'g27', 'g27', 'cd4', '-5400000');
            f.AddPathCommand(2, 'g24', 'g21');
            f.AddPathCommand(2, 'hc', 'g21');
            f.AddPathCommand(2, 'g23', 'g9');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'actionButtonSound':{
            f.AddGuide('dx2', 0, 'ss', '3', '8');
            f.AddGuide('g9', 1, 'vc', '0', 'dx2');
            f.AddGuide('g10', 1, 'vc', 'dx2', '0');
            f.AddGuide('g11', 1, 'hc', '0', 'dx2');
            f.AddGuide('g12', 1, 'hc', 'dx2', '0');
            f.AddGuide('g13', 0, 'ss', '3', '4');
            f.AddGuide('g14', 0, 'g13', '1', '8');
            f.AddGuide('g15', 0, 'g13', '5', '16');
            f.AddGuide('g16', 0, 'g13', '5', '8');
            f.AddGuide('g17', 0, 'g13', '11', '16');
            f.AddGuide('g18', 0, 'g13', '3', '4');
            f.AddGuide('g19', 0, 'g13', '7', '8');
            f.AddGuide('g20', 1, 'g9', 'g14', '0');
            f.AddGuide('g21', 1, 'g9', 'g15', '0');
            f.AddGuide('g22', 1, 'g9', 'g17', '0');
            f.AddGuide('g23', 1, 'g9', 'g19', '0');
            f.AddGuide('g24', 1, 'g11', 'g15', '0');
            f.AddGuide('g25', 1, 'g11', 'g16', '0');
            f.AddGuide('g26', 1, 'g11', 'g18', '0');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g11', 'g21');
            f.AddPathCommand(2, 'g11', 'g22');
            f.AddPathCommand(2, 'g24', 'g22');
            f.AddPathCommand(2, 'g25', 'g10');
            f.AddPathCommand(2, 'g25', 'g9');
            f.AddPathCommand(2, 'g24', 'g21');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darken', false, undefined, undefined);
            f.AddPathCommand(1, 'g11', 'g21');
            f.AddPathCommand(2, 'g11', 'g22');
            f.AddPathCommand(2, 'g24', 'g22');
            f.AddPathCommand(2, 'g25', 'g10');
            f.AddPathCommand(2, 'g25', 'g9');
            f.AddPathCommand(2, 'g24', 'g21');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'g11', 'g21');
            f.AddPathCommand(2, 'g24', 'g21');
            f.AddPathCommand(2, 'g25', 'g9');
            f.AddPathCommand(2, 'g25', 'g10');
            f.AddPathCommand(2, 'g24', 'g22');
            f.AddPathCommand(2, 'g11', 'g22');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'g26', 'g21');
            f.AddPathCommand(2, 'g12', 'g20');
            f.AddPathCommand(1, 'g26', 'vc');
            f.AddPathCommand(2, 'g12', 'vc');
            f.AddPathCommand(1, 'g26', 'g22');
            f.AddPathCommand(2, 'g12', 'g23');
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'arc':{
            f.AddAdj('adj1', 15, '16200000');
            f.AddAdj('adj2', 15, '0');
            f.AddGuide('stAng', 10, '0', 'adj1', '21599999');
            f.AddGuide('enAng', 10, '0', 'adj2', '21599999');
            f.AddGuide('sw11', 1, 'enAng', '0', 'stAng');
            f.AddGuide('sw12', 1, 'sw11', '21600000', '0');
            f.AddGuide('swAng', 3, 'sw11', 'sw11', 'sw12');
            f.AddGuide('wt1', 12, 'wd2', 'stAng');
            f.AddGuide('ht1', 7, 'hd2', 'stAng');
            f.AddGuide('dx1', 6, 'wd2', 'ht1', 'wt1');
            f.AddGuide('dy1', 11, 'hd2', 'ht1', 'wt1');
            f.AddGuide('wt2', 12, 'wd2', 'enAng');
            f.AddGuide('ht2', 7, 'hd2', 'enAng');
            f.AddGuide('dx2', 6, 'wd2', 'ht2', 'wt2');
            f.AddGuide('dy2', 11, 'hd2', 'ht2', 'wt2');
            f.AddGuide('x1', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', 'dy1', '0');
            f.AddGuide('x2', 1, 'hc', 'dx2', '0');
            f.AddGuide('y2', 1, 'vc', 'dy2', '0');
            f.AddGuide('sw0', 1, '21600000', '0', 'stAng');
            f.AddGuide('da1', 1, 'swAng', '0', 'sw0');
            f.AddGuide('g1', 8, 'x1', 'x2');
            f.AddGuide('ir', 3, 'da1', 'r', 'g1');
            f.AddGuide('sw1', 1, 'cd4', '0', 'stAng');
            f.AddGuide('sw2', 1, '27000000', '0', 'stAng');
            f.AddGuide('sw3', 3, 'sw1', 'sw1', 'sw2');
            f.AddGuide('da2', 1, 'swAng', '0', 'sw3');
            f.AddGuide('g5', 8, 'y1', 'y2');
            f.AddGuide('ib', 3, 'da2', 'b', 'g5');
            f.AddGuide('sw4', 1, 'cd2', '0', 'stAng');
            f.AddGuide('sw5', 1, '32400000', '0', 'stAng');
            f.AddGuide('sw6', 3, 'sw4', 'sw4', 'sw5');
            f.AddGuide('da3', 1, 'swAng', '0', 'sw6');
            f.AddGuide('g9', 16, 'x1', 'x2');
            f.AddGuide('il', 3, 'da3', 'l', 'g9');
            f.AddGuide('sw7', 1, '_3cd4', '0', 'stAng');
            f.AddGuide('sw8', 1, '37800000', '0', 'stAng');
            f.AddGuide('sw9', 3, 'sw7', 'sw7', 'sw8');
            f.AddGuide('da4', 1, 'swAng', '0', 'sw9');
            f.AddGuide('g13', 16, 'y1', 'y2');
            f.AddGuide('it', 3, 'da4', 't', 'g13');
            f.AddGuide('cang1', 1, 'stAng', '0', 'cd4');
            f.AddGuide('cang2', 1, 'enAng', 'cd4', '0');
            f.AddGuide('cang3', 2, 'cang1', 'cang2', '2');
            f.AddHandlePolar('adj1','0','21599999', undefined, '0', '0', 'x1', 'y1');
            f.AddHandlePolar('adj2','0','21599999', undefined, '0', '0', 'x2', 'y2');
            f.AddCnx('cang1', 'x1', 'y1');
            f.AddCnx('cang3', 'hc', 'vc');
            f.AddCnx('cang2', 'x2', 'y2');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(3, 'wd2', 'hd2', 'stAng', 'swAng');
            f.AddPathCommand(2, 'hc', 'vc');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(3, 'wd2', 'hd2', 'stAng', 'swAng');
            break;
        }
        case 'bentArrow':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '25000');
            f.AddAdj('adj3', 15, '25000');
            f.AddAdj('adj4', 15, '43750');
            f.AddGuide('a2', 10, '0', 'adj2', '50000');
            f.AddGuide('maxAdj1', 0, 'a2', '2', '1');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('a3', 10, '0', 'adj3', '50000');
            f.AddGuide('th', 0, 'ss', 'a1', '100000');
            f.AddGuide('aw2', 0, 'ss', 'a2', '100000');
            f.AddGuide('th2', 0, 'th', '1', '2');
            f.AddGuide('dh2', 1, 'aw2', '0', 'th2');
            f.AddGuide('ah', 0, 'ss', 'a3', '100000');
            f.AddGuide('bw', 1, 'r', '0', 'ah');
            f.AddGuide('bh', 1, 'b', '0', 'dh2');
            f.AddGuide('bs', 16, 'bw', 'bh');
            f.AddGuide('maxAdj4', 0, '100000', 'bs', 'ss');
            f.AddGuide('a4', 10, '0', 'adj4', 'maxAdj4');
            f.AddGuide('bd', 0, 'ss', 'a4', '100000');
            f.AddGuide('bd3', 1, 'bd', '0', 'th');
            f.AddGuide('bd2', 8, 'bd3', '0');
            f.AddGuide('x3', 1, 'th', 'bd2', '0');
            f.AddGuide('x4', 1, 'r', '0', 'ah');
            f.AddGuide('y3', 1, 'dh2', 'th', '0');
            f.AddGuide('y4', 1, 'y3', 'dh2', '0');
            f.AddGuide('y5', 1, 'dh2', 'bd', '0');
            f.AddGuide('y6', 1, 'y3', 'bd2', '0');
            f.AddHandleXY('adj1','0','maxAdj1', undefined, '0', '0', 'th', 'b');
            f.AddHandleXY(undefined, '0', '0','adj2','0','50000', 'r', 'y4');
            f.AddHandleXY('adj3','0','50000', undefined, '0', '0', 'x4', 't');
            f.AddHandleXY('adj4','0','maxAdj4', undefined, '0', '0', 'bd', 't');
            f.AddCnx('_3cd4', 'x4', 't');
            f.AddCnx('cd4', 'x4', 'y4');
            f.AddCnx('cd4', 'th2', 'b');
            f.AddCnx('0', 'r', 'aw2');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'l', 'y5');
            f.AddPathCommand(3, 'bd', 'bd', 'cd2', 'cd4');
            f.AddPathCommand(2, 'x4', 'dh2');
            f.AddPathCommand(2, 'x4', 't');
            f.AddPathCommand(2, 'r', 'aw2');
            f.AddPathCommand(2, 'x4', 'y4');
            f.AddPathCommand(2, 'x4', 'y3');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(3, 'bd2', 'bd2', '_3cd4', '-5400000');
            f.AddPathCommand(2, 'th', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'bentConnector2':{
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            break;
        }
        case 'bentConnector3':{
            f.AddAdj('adj1', 15, '50000');
            f.AddGuide('x1', 0, 'w', 'adj1', '100000');
            f.AddHandleXY('adj1','-2147483647','2147483647', undefined, '0', '0', 'x1', 'vc');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'x1', 't');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(2, 'r', 'b');
            break;
        }
        case 'bentConnector4':{
            f.AddAdj('adj1', 15, '50000');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('x1', 0, 'w', 'adj1', '100000');
            f.AddGuide('x2', 2, 'x1', 'r', '2');
            f.AddGuide('y2', 0, 'h', 'adj2', '100000');
            f.AddGuide('y1', 2, 't', 'y2', '2');
            f.AddHandleXY('adj1','-2147483647','2147483647', undefined, '0', '0', 'x1', 'y1');
            f.AddHandleXY(undefined, '0', '0','adj2','-2147483647','2147483647', 'x2', 'y2');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'x1', 't');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(2, 'r', 'b');
            break;
        }
        case 'bentConnector5':{
            f.AddAdj('adj1', 15, '50000');
            f.AddAdj('adj2', 15, '50000');
            f.AddAdj('adj3', 15, '50000');
            f.AddGuide('x1', 0, 'w', 'adj1', '100000');
            f.AddGuide('x3', 0, 'w', 'adj3', '100000');
            f.AddGuide('x2', 2, 'x1', 'x3', '2');
            f.AddGuide('y2', 0, 'h', 'adj2', '100000');
            f.AddGuide('y1', 2, 't', 'y2', '2');
            f.AddGuide('y3', 2, 'b', 'y2', '2');
            f.AddHandleXY('adj1','-2147483647','2147483647', undefined, '0', '0', 'x1', 'y1');
            f.AddHandleXY(undefined, '0', '0','adj2','-2147483647','2147483647', 'x2', 'y2');
            f.AddHandleXY('adj3','-2147483647','2147483647', undefined, '0', '0', 'x3', 'y3');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'x1', 't');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(2, 'x3', 'y2');
            f.AddPathCommand(2, 'x3', 'b');
            f.AddPathCommand(2, 'r', 'b');
            break;
        }
        case 'bentUpArrow':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '25000');
            f.AddAdj('adj3', 15, '25000');
            f.AddGuide('a1', 10, '0', 'adj1', '50000');
            f.AddGuide('a2', 10, '0', 'adj2', '50000');
            f.AddGuide('a3', 10, '0', 'adj3', '50000');
            f.AddGuide('y1', 0, 'ss', 'a3', '100000');
            f.AddGuide('dx1', 0, 'ss', 'a2', '50000');
            f.AddGuide('x1', 1, 'r', '0', 'dx1');
            f.AddGuide('dx3', 0, 'ss', 'a2', '100000');
            f.AddGuide('x3', 1, 'r', '0', 'dx3');
            f.AddGuide('dx2', 0, 'ss', 'a1', '200000');
            f.AddGuide('x2', 1, 'x3', '0', 'dx2');
            f.AddGuide('x4', 1, 'x3', 'dx2', '0');
            f.AddGuide('dy2', 0, 'ss', 'a1', '100000');
            f.AddGuide('y2', 1, 'b', '0', 'dy2');
            f.AddGuide('x0', 0, 'x4', '1', '2');
            f.AddGuide('y3', 2, 'y2', 'b', '2');
            f.AddGuide('y15', 2, 'y1', 'b', '2');
            f.AddHandleXY(undefined, '0', '0','adj1','0','50000', 'l', 'y2');
            f.AddHandleXY('adj2','0','50000', undefined, '0', '0', 'x1', 't');
            f.AddHandleXY(undefined, '0', '0','adj3','0','50000', 'x2', 'y1');
            f.AddCnx('_3cd4', 'x3', 't');
            f.AddCnx('cd2', 'x1', 'y1');
            f.AddCnx('cd2', 'l', 'y3');
            f.AddCnx('cd4', 'x0', 'b');
            f.AddCnx('0', 'x4', 'y15');
            f.AddCnx('0', 'r', 'y1');
            f.AddRect('l', 'y2', 'x4', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y2');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'x1', 'y1');
            f.AddPathCommand(2, 'x3', 't');
            f.AddPathCommand(2, 'r', 'y1');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(2, 'x4', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'bevel':{
            f.AddAdj('adj', 15, '12500');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('x1', 0, 'ss', 'a', '100000');
            f.AddGuide('x2', 1, 'r', '0', 'x1');
            f.AddGuide('y2', 1, 'b', '0', 'x1');
            f.AddHandleXY('adj','0','50000', undefined, '0', '0', 'x1', 't');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('0', 'x2', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd4', 'hc', 'y2');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd2', 'x1', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('_3cd4', 'hc', 'x1');
            f.AddRect('x1', 'x1', 'x2', 'y2');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'x1');
            f.AddPathCommand(2, 'x2', 'x1');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'lightenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'x2', 'x1');
            f.AddPathCommand(2, 'x1', 'x1');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'lighten', false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'x1', 'x1');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darken', false, undefined, undefined);
            f.AddPathCommand(1, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x2', 'x1');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x1', 'x1');
            f.AddPathCommand(2, 'x2', 'x1');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'x1', 'x1');
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(1, 'r', 't');
            f.AddPathCommand(2, 'x2', 'x1');
            f.AddPathCommand(1, 'r', 'b');
            f.AddPathCommand(2, 'x2', 'y2');
            break;
        }
        case 'blockArc':{
            f.AddAdj('adj1', 15, '10800000');
            f.AddAdj('adj2', 15, '0');
            f.AddAdj('adj3', 15, '25000');
            f.AddGuide('stAng', 10, '0', 'adj1', '21599999');
            f.AddGuide('istAng', 10, '0', 'adj2', '21599999');
            f.AddGuide('a3', 10, '0', 'adj3', '50000');
            f.AddGuide('sw11', 1, 'istAng', '0', 'stAng');
            f.AddGuide('sw12', 1, 'sw11', '21600000', '0');
            f.AddGuide('swAng', 3, 'sw11', 'sw11', 'sw12');
            f.AddGuide('iswAng', 1, '0', '0', 'swAng');
            f.AddGuide('wt1', 12, 'wd2', 'stAng');
            f.AddGuide('ht1', 7, 'hd2', 'stAng');
            f.AddGuide('wt3', 12, 'wd2', 'istAng');
            f.AddGuide('ht3', 7, 'hd2', 'istAng');
            f.AddGuide('dx1', 6, 'wd2', 'ht1', 'wt1');
            f.AddGuide('dy1', 11, 'hd2', 'ht1', 'wt1');
            f.AddGuide('dx3', 6, 'wd2', 'ht3', 'wt3');
            f.AddGuide('dy3', 11, 'hd2', 'ht3', 'wt3');
            f.AddGuide('x1', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', 'dy1', '0');
            f.AddGuide('x3', 1, 'hc', 'dx3', '0');
            f.AddGuide('y3', 1, 'vc', 'dy3', '0');
            f.AddGuide('dr', 0, 'ss', 'a3', '100000');
            f.AddGuide('iwd2', 1, 'wd2', '0', 'dr');
            f.AddGuide('ihd2', 1, 'hd2', '0', 'dr');
            f.AddGuide('wt2', 12, 'iwd2', 'istAng');
            f.AddGuide('ht2', 7, 'ihd2', 'istAng');
            f.AddGuide('wt4', 12, 'iwd2', 'stAng');
            f.AddGuide('ht4', 7, 'ihd2', 'stAng');
            f.AddGuide('dx2', 6, 'iwd2', 'ht2', 'wt2');
            f.AddGuide('dy2', 11, 'ihd2', 'ht2', 'wt2');
            f.AddGuide('dx4', 6, 'iwd2', 'ht4', 'wt4');
            f.AddGuide('dy4', 11, 'ihd2', 'ht4', 'wt4');
            f.AddGuide('x2', 1, 'hc', 'dx2', '0');
            f.AddGuide('y2', 1, 'vc', 'dy2', '0');
            f.AddGuide('x4', 1, 'hc', 'dx4', '0');
            f.AddGuide('y4', 1, 'vc', 'dy4', '0');
            f.AddGuide('sw0', 1, '21600000', '0', 'stAng');
            f.AddGuide('da1', 1, 'swAng', '0', 'sw0');
            f.AddGuide('g1', 8, 'x1', 'x2');
            f.AddGuide('g2', 8, 'x3', 'x4');
            f.AddGuide('g3', 8, 'g1', 'g2');
            f.AddGuide('ir', 3, 'da1', 'r', 'g3');
            f.AddGuide('sw1', 1, 'cd4', '0', 'stAng');
            f.AddGuide('sw2', 1, '27000000', '0', 'stAng');
            f.AddGuide('sw3', 3, 'sw1', 'sw1', 'sw2');
            f.AddGuide('da2', 1, 'swAng', '0', 'sw3');
            f.AddGuide('g5', 8, 'y1', 'y2');
            f.AddGuide('g6', 8, 'y3', 'y4');
            f.AddGuide('g7', 8, 'g5', 'g6');
            f.AddGuide('ib', 3, 'da2', 'b', 'g7');
            f.AddGuide('sw4', 1, 'cd2', '0', 'stAng');
            f.AddGuide('sw5', 1, '32400000', '0', 'stAng');
            f.AddGuide('sw6', 3, 'sw4', 'sw4', 'sw5');
            f.AddGuide('da3', 1, 'swAng', '0', 'sw6');
            f.AddGuide('g9', 16, 'x1', 'x2');
            f.AddGuide('g10', 16, 'x3', 'x4');
            f.AddGuide('g11', 16, 'g9', 'g10');
            f.AddGuide('il', 3, 'da3', 'l', 'g11');
            f.AddGuide('sw7', 1, '_3cd4', '0', 'stAng');
            f.AddGuide('sw8', 1, '37800000', '0', 'stAng');
            f.AddGuide('sw9', 3, 'sw7', 'sw7', 'sw8');
            f.AddGuide('da4', 1, 'swAng', '0', 'sw9');
            f.AddGuide('g13', 16, 'y1', 'y2');
            f.AddGuide('g14', 16, 'y3', 'y4');
            f.AddGuide('g15', 16, 'g13', 'g14');
            f.AddGuide('it', 3, 'da4', 't', 'g15');
            f.AddGuide('x5', 2, 'x1', 'x4', '2');
            f.AddGuide('y5', 2, 'y1', 'y4', '2');
            f.AddGuide('x6', 2, 'x3', 'x2', '2');
            f.AddGuide('y6', 2, 'y3', 'y2', '2');
            f.AddGuide('cang1', 1, 'stAng', '0', 'cd4');
            f.AddGuide('cang2', 1, 'istAng', 'cd4', '0');
            f.AddGuide('cang3', 2, 'cang1', 'cang2', '2');
            f.AddHandlePolar('adj1','0','21599999', undefined, '0', '0', 'x1', 'y1');
            f.AddHandlePolar(undefined, '0', '0','adj3','0','50000', 'x2', 'y2');
            f.AddCnx('cang1', 'x5', 'y5');
            f.AddCnx('cang2', 'x6', 'y6');
            f.AddCnx('cang3', 'hc', 'vc');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(3, 'wd2', 'hd2', 'stAng', 'swAng');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(3, 'iwd2', 'ihd2', 'istAng', 'iswAng');
            f.AddPathCommand(6);
            break;
        }
        case 'borderCallout1':{
            f.AddAdj('adj1', 15, '18750');
            f.AddAdj('adj2', 15, '-8333');
            f.AddAdj('adj3', 15, '112500');
            f.AddAdj('adj4', 15, '-38333');
            f.AddGuide('y1', 0, 'h', 'adj1', '100000');
            f.AddGuide('x1', 0, 'w', 'adj2', '100000');
            f.AddGuide('y2', 0, 'h', 'adj3', '100000');
            f.AddGuide('x2', 0, 'w', 'adj4', '100000');
            f.AddHandleXY('adj2','-2147483647','2147483647','adj1','-2147483647','2147483647', 'x1', 'y1');
            f.AddHandleXY('adj4','-2147483647','2147483647','adj3','-2147483647','2147483647', 'x2', 'y2');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'x2', 'y2');
            break;
        }
        case 'borderCallout2':{
            f.AddAdj('adj1', 15, '18750');
            f.AddAdj('adj2', 15, '-8333');
            f.AddAdj('adj3', 15, '18750');
            f.AddAdj('adj4', 15, '-16667');
            f.AddAdj('adj5', 15, '112500');
            f.AddAdj('adj6', 15, '-46667');
            f.AddGuide('y1', 0, 'h', 'adj1', '100000');
            f.AddGuide('x1', 0, 'w', 'adj2', '100000');
            f.AddGuide('y2', 0, 'h', 'adj3', '100000');
            f.AddGuide('x2', 0, 'w', 'adj4', '100000');
            f.AddGuide('y3', 0, 'h', 'adj5', '100000');
            f.AddGuide('x3', 0, 'w', 'adj6', '100000');
            f.AddHandleXY('adj2','-2147483647','2147483647','adj1','-2147483647','2147483647', 'x1', 'y1');
            f.AddHandleXY('adj4','-2147483647','2147483647','adj3','-2147483647','2147483647', 'x2', 'y2');
            f.AddHandleXY('adj6','-2147483647','2147483647','adj5','-2147483647','2147483647', 'x3', 'y3');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x3', 'y3');
            break;
        }
        case 'borderCallout3':{
            f.AddAdj('adj1', 15, '18750');
            f.AddAdj('adj2', 15, '-8333');
            f.AddAdj('adj3', 15, '18750');
            f.AddAdj('adj4', 15, '-16667');
            f.AddAdj('adj5', 15, '100000');
            f.AddAdj('adj6', 15, '-16667');
            f.AddAdj('adj7', 15, '112963');
            f.AddAdj('adj8', 15, '-8333');
            f.AddGuide('y1', 0, 'h', 'adj1', '100000');
            f.AddGuide('x1', 0, 'w', 'adj2', '100000');
            f.AddGuide('y2', 0, 'h', 'adj3', '100000');
            f.AddGuide('x2', 0, 'w', 'adj4', '100000');
            f.AddGuide('y3', 0, 'h', 'adj5', '100000');
            f.AddGuide('x3', 0, 'w', 'adj6', '100000');
            f.AddGuide('y4', 0, 'h', 'adj7', '100000');
            f.AddGuide('x4', 0, 'w', 'adj8', '100000');
            f.AddHandleXY('adj2','-2147483647','2147483647','adj1','-2147483647','2147483647', 'x1', 'y1');
            f.AddHandleXY('adj4','-2147483647','2147483647','adj3','-2147483647','2147483647', 'x2', 'y2');
            f.AddHandleXY('adj6','-2147483647','2147483647','adj5','-2147483647','2147483647', 'x3', 'y3');
            f.AddHandleXY('adj8','-2147483647','2147483647','adj7','-2147483647','2147483647', 'x4', 'y4');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(2, 'x4', 'y4');
            break;
        }
        case 'bracePair':{
            f.AddAdj('adj', 15, '8333');
            f.AddGuide('a', 10, '0', 'adj', '25000');
            f.AddGuide('x1', 0, 'ss', 'a', '100000');
            f.AddGuide('x2', 0, 'ss', 'a', '50000');
            f.AddGuide('x3', 1, 'r', '0', 'x2');
            f.AddGuide('x4', 1, 'r', '0', 'x1');
            f.AddGuide('y2', 1, 'vc', '0', 'x1');
            f.AddGuide('y3', 1, 'vc', 'x1', '0');
            f.AddGuide('y4', 1, 'b', '0', 'x1');
            f.AddGuide('it', 0, 'x1', '29289', '100000');
            f.AddGuide('il', 1, 'x1', 'it', '0');
            f.AddGuide('ir', 1, 'r', '0', 'il');
            f.AddGuide('ib', 1, 'b', '0', 'it');
            f.AddHandleXY(undefined, '0', '0','adj','0','25000', 'l', 'x1');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('il', 'il', 'ir', 'ib');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'x2', 'b');
            f.AddPathCommand(3, 'x1', 'x1', 'cd4', 'cd4');
            f.AddPathCommand(2, 'x1', 'y3');
            f.AddPathCommand(3, 'x1', 'x1', '0', '-5400000');
            f.AddPathCommand(3, 'x1', 'x1', 'cd4', '-5400000');
            f.AddPathCommand(2, 'x1', 'x1');
            f.AddPathCommand(3, 'x1', 'x1', 'cd2', 'cd4');
            f.AddPathCommand(2, 'x3', 't');
            f.AddPathCommand(3, 'x1', 'x1', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'x4', 'y2');
            f.AddPathCommand(3, 'x1', 'x1', 'cd2', '-5400000');
            f.AddPathCommand(3, 'x1', 'x1', '_3cd4', '-5400000');
            f.AddPathCommand(2, 'x4', 'y4');
            f.AddPathCommand(3, 'x1', 'x1', '0', 'cd4');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined,  undefined, undefined, undefined);
            f.AddPathCommand(1, 'x2', 'b');
            f.AddPathCommand(3, 'x1', 'x1', 'cd4', 'cd4');
            f.AddPathCommand(2, 'x1', 'y3');
            f.AddPathCommand(3, 'x1', 'x1', '0', '-5400000');
            f.AddPathCommand(3, 'x1', 'x1', 'cd4', '-5400000');
            f.AddPathCommand(2, 'x1', 'x1');
            f.AddPathCommand(3, 'x1', 'x1', 'cd2', 'cd4');
            f.AddPathCommand(1, 'x3', 't');
            f.AddPathCommand(3, 'x1', 'x1', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'x4', 'y2');
            f.AddPathCommand(3, 'x1', 'x1', 'cd2', '-5400000');
            f.AddPathCommand(3, 'x1', 'x1', '_3cd4', '-5400000');
            f.AddPathCommand(2, 'x4', 'y4');
            f.AddPathCommand(3, 'x1', 'x1', '0', 'cd4');
            break;
        }
        case 'bracketPair':{
            f.AddAdj('adj', 15, '16667');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('x1', 0, 'ss', 'a', '100000');
            f.AddGuide('x2', 1, 'r', '0', 'x1');
            f.AddGuide('y2', 1, 'b', '0', 'x1');
            f.AddGuide('il', 0, 'x1', '29289', '100000');
            f.AddGuide('ir', 1, 'r', '0', 'il');
            f.AddGuide('ib', 1, 'b', '0', 'il');
            f.AddHandleXY(undefined, '0', '0','adj','0','50000', 'l', 'x1');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('il', 'il', 'ir', 'ib');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 'x1');
            f.AddPathCommand(3, 'x1', 'x1', 'cd2', 'cd4');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(3, 'x1', 'x1', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(3, 'x1', 'x1', '0', 'cd4');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(3, 'x1', 'x1', 'cd4', 'cd4');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'b');
            f.AddPathCommand(3, 'x1', 'x1', 'cd4', 'cd4');
            f.AddPathCommand(2, 'l', 'x1');
            f.AddPathCommand(3, 'x1', 'x1', 'cd2', 'cd4');
            f.AddPathCommand(1, 'x2', 't');
            f.AddPathCommand(3, 'x1', 'x1', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(3, 'x1', 'x1', '0', 'cd4');
            break;
        }
        case 'callout1':{
            f.AddAdj('adj1', 15, '18750');
            f.AddAdj('adj2', 15, '-8333');
            f.AddAdj('adj3', 15, '112500');
            f.AddAdj('adj4', 15, '-38333');
            f.AddGuide('y1', 0, 'h', 'adj1', '100000');
            f.AddGuide('x1', 0, 'w', 'adj2', '100000');
            f.AddGuide('y2', 0, 'h', 'adj3', '100000');
            f.AddGuide('x2', 0, 'w', 'adj4', '100000');
            f.AddHandleXY('adj2','-2147483647','2147483647','adj1','-2147483647','2147483647', 'x1', 'y1');
            f.AddHandleXY('adj4','-2147483647','2147483647','adj3','-2147483647','2147483647', 'x2', 'y2');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'x2', 'y2');
            break;
        }
        case 'callout2':{
            f.AddAdj('adj1', 15, '18750');
            f.AddAdj('adj2', 15, '-8333');
            f.AddAdj('adj3', 15, '18750');
            f.AddAdj('adj4', 15, '-16667');
            f.AddAdj('adj5', 15, '112500');
            f.AddAdj('adj6', 15, '-46667');
            f.AddGuide('y1', 0, 'h', 'adj1', '100000');
            f.AddGuide('x1', 0, 'w', 'adj2', '100000');
            f.AddGuide('y2', 0, 'h', 'adj3', '100000');
            f.AddGuide('x2', 0, 'w', 'adj4', '100000');
            f.AddGuide('y3', 0, 'h', 'adj5', '100000');
            f.AddGuide('x3', 0, 'w', 'adj6', '100000');
            f.AddHandleXY('adj2','-2147483647','2147483647','adj1','-2147483647','2147483647', 'x1', 'y1');
            f.AddHandleXY('adj4','-2147483647','2147483647','adj3','-2147483647','2147483647', 'x2', 'y2');
            f.AddHandleXY('adj6','-2147483647','2147483647','adj5','-2147483647','2147483647', 'x3', 'y3');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x3', 'y3');
            break;
        }
        case 'callout3':{
            f.AddAdj('adj1', 15, '18750');
            f.AddAdj('adj2', 15, '-8333');
            f.AddAdj('adj3', 15, '18750');
            f.AddAdj('adj4', 15, '-16667');
            f.AddAdj('adj5', 15, '100000');
            f.AddAdj('adj6', 15, '-16667');
            f.AddAdj('adj7', 15, '112963');
            f.AddAdj('adj8', 15, '-8333');
            f.AddGuide('y1', 0, 'h', 'adj1', '100000');
            f.AddGuide('x1', 0, 'w', 'adj2', '100000');
            f.AddGuide('y2', 0, 'h', 'adj3', '100000');
            f.AddGuide('x2', 0, 'w', 'adj4', '100000');
            f.AddGuide('y3', 0, 'h', 'adj5', '100000');
            f.AddGuide('x3', 0, 'w', 'adj6', '100000');
            f.AddGuide('y4', 0, 'h', 'adj7', '100000');
            f.AddGuide('x4', 0, 'w', 'adj8', '100000');
            f.AddHandleXY('adj2','-2147483647','2147483647','adj1','-2147483647','2147483647', 'x1', 'y1');
            f.AddHandleXY('adj4','-2147483647','2147483647','adj3','-2147483647','2147483647', 'x2', 'y2');
            f.AddHandleXY('adj6','-2147483647','2147483647','adj5','-2147483647','2147483647', 'x3', 'y3');
            f.AddHandleXY('adj8','-2147483647','2147483647','adj7','-2147483647','2147483647', 'x4', 'y4');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(2, 'x4', 'y4');
            break;
        }
        case 'can':{
            f.AddAdj('adj', 15, '25000');
            f.AddGuide('maxAdj', 0, '50000', 'h', 'ss');
            f.AddGuide('a', 10, '0', 'adj', 'maxAdj');
            f.AddGuide('y1', 0, 'ss', 'a', '200000');
            f.AddGuide('y2', 1, 'y1', 'y1', '0');
            f.AddGuide('y3', 1, 'b', '0', 'y1');
            f.AddHandleXY(undefined, '0', '0','adj','0','maxAdj', 'hc', 'y2');
            f.AddCnx('_3cd4', 'hc', 'y2');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 'y2', 'r', 'y3');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(3, 'wd2', 'y1', 'cd2', '-10800000');
            f.AddPathCommand(2, 'r', 'y3');
            f.AddPathCommand(3, 'wd2', 'y1', '0', 'cd2');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'lighten', false, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(3, 'wd2', 'y1', 'cd2', 'cd2');
            f.AddPathCommand(3, 'wd2', 'y1', '0', 'cd2');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'r', 'y1');
            f.AddPathCommand(3, 'wd2', 'y1', '0', 'cd2');
            f.AddPathCommand(3, 'wd2', 'y1', 'cd2', 'cd2');
            f.AddPathCommand(2, 'r', 'y3');
            f.AddPathCommand(3, 'wd2', 'y1', '0', 'cd2');
            f.AddPathCommand(2, 'l', 'y1');
            break;
        }
        case 'chartPlus':{
            f.AddPathCommand(0,false, 'none', undefined, 10, 10);
            f.AddPathCommand(1, '5', '0');
            f.AddPathCommand(2, '5', '10');
            f.AddPathCommand(1, '0', '5');
            f.AddPathCommand(2, '10', '5');
            f.AddPathCommand(0,undefined, undefined, false, 10, 10);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '0', '10');
            f.AddPathCommand(2, '10', '10');
            f.AddPathCommand(2, '10', '0');
            f.AddPathCommand(6);
            break;
        }
        case 'chartStar':{
            f.AddPathCommand(0,false, 'none', undefined, 10, 10);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '10', '10');
            f.AddPathCommand(1, '0', '10');
            f.AddPathCommand(2, '10', '0');
            f.AddPathCommand(1, '5', '0');
            f.AddPathCommand(2, '5', '10');
            f.AddPathCommand(0,undefined, undefined, false, 10, 10);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '0', '10');
            f.AddPathCommand(2, '10', '10');
            f.AddPathCommand(2, '10', '0');
            f.AddPathCommand(6);
            break;
        }
        case 'chartX':{
            f.AddPathCommand(0,false, 'none', undefined, 10, 10);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '10', '10');
            f.AddPathCommand(1, '0', '10');
            f.AddPathCommand(2, '10', '0');
            f.AddPathCommand(0,undefined, undefined, false, 10, 10);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '0', '10');
            f.AddPathCommand(2, '10', '10');
            f.AddPathCommand(2, '10', '0');
            f.AddPathCommand(6);
            break;
        }
        case 'chevron':{
            f.AddAdj('adj', 15, '50000');
            f.AddGuide('maxAdj', 0, '100000', 'w', 'ss');
            f.AddGuide('a', 10, '0', 'adj', 'maxAdj');
            f.AddGuide('x1', 0, 'ss', 'a', '100000');
            f.AddGuide('x2', 1, 'r', '0', 'x1');
            f.AddGuide('x3', 0, 'x2', '1', '2');
            f.AddGuide('dx', 1, 'x2', '0', 'x1');
            f.AddGuide('il', 3, 'dx', 'x1', 'l');
            f.AddGuide('ir', 3, 'dx', 'x2', 'r');
            f.AddHandleXY('adj','0','maxAdj', undefined, '0', '0', 'x2', 't');
            f.AddCnx('_3cd4', 'x3', 't');
            f.AddCnx('cd2', 'x1', 'vc');
            f.AddCnx('cd4', 'x3', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('il', 't', 'ir', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'x2', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(2, 'x1', 'vc');
            f.AddPathCommand(6);
            break;
        }
        case 'chord':{
            f.AddAdj('adj1', 15, '2700000');
            f.AddAdj('adj2', 15, '16200000');
            f.AddGuide('stAng', 10, '0', 'adj1', '21599999');
            f.AddGuide('enAng', 10, '0', 'adj2', '21599999');
            f.AddGuide('sw1', 1, 'enAng', '0', 'stAng');
            f.AddGuide('sw2', 1, 'sw1', '21600000', '0');
            f.AddGuide('swAng', 3, 'sw1', 'sw1', 'sw2');
            f.AddGuide('wt1', 12, 'wd2', 'stAng');
            f.AddGuide('ht1', 7, 'hd2', 'stAng');
            f.AddGuide('dx1', 6, 'wd2', 'ht1', 'wt1');
            f.AddGuide('dy1', 11, 'hd2', 'ht1', 'wt1');
            f.AddGuide('wt2', 12, 'wd2', 'enAng');
            f.AddGuide('ht2', 7, 'hd2', 'enAng');
            f.AddGuide('dx2', 6, 'wd2', 'ht2', 'wt2');
            f.AddGuide('dy2', 11, 'hd2', 'ht2', 'wt2');
            f.AddGuide('x1', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', 'dy1', '0');
            f.AddGuide('x2', 1, 'hc', 'dx2', '0');
            f.AddGuide('y2', 1, 'vc', 'dy2', '0');
            f.AddGuide('x3', 2, 'x1', 'x2', '2');
            f.AddGuide('y3', 2, 'y1', 'y2', '2');
            f.AddGuide('midAng0', 0, 'swAng', '1', '2');
            f.AddGuide('midAng', 1, 'stAng', 'midAng0', 'cd2');
            f.AddGuide('idx', 7, 'wd2', '2700000');
            f.AddGuide('idy', 12, 'hd2', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddHandlePolar('adj1','0','21599999', undefined, '0', '0', 'x1', 'y1');
            f.AddHandlePolar('adj2','0','21599999', undefined, '0', '0', 'x2', 'y2');
            f.AddCnx('stAng', 'x1', 'y1');
            f.AddCnx('enAng', 'x2', 'y2');
            f.AddCnx('midAng', 'x3', 'y3');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(3, 'wd2', 'hd2', 'stAng', 'swAng');
            f.AddPathCommand(6);
            break;
        }
        case 'circularArrow':{
            f.AddAdj('adj1', 15, '12500');
            f.AddAdj('adj2', 15, '1142319');
            f.AddAdj('adj3', 15, '20457681');
            f.AddAdj('adj4', 15, '10800000');
            f.AddAdj('adj5', 15, '12500');
            f.AddGuide('a5', 10, '0', 'adj5', '25000');
            f.AddGuide('maxAdj1', 0, 'a5', '2', '1');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('enAng', 10, '1', 'adj3', '21599999');
            f.AddGuide('stAng', 10, '0', 'adj4', '21599999');
            f.AddGuide('th', 0, 'ss', 'a1', '100000');
            f.AddGuide('thh', 0, 'ss', 'a5', '100000');
            f.AddGuide('th2', 0, 'th', '1', '2');
            f.AddGuide('rw1', 1, 'wd2', 'th2', 'thh');
            f.AddGuide('rh1', 1, 'hd2', 'th2', 'thh');
            f.AddGuide('rw2', 1, 'rw1', '0', 'th');
            f.AddGuide('rh2', 1, 'rh1', '0', 'th');
            f.AddGuide('rw3', 1, 'rw2', 'th2', '0');
            f.AddGuide('rh3', 1, 'rh2', 'th2', '0');
            f.AddGuide('wtH', 12, 'rw3', 'enAng');
            f.AddGuide('htH', 7, 'rh3', 'enAng');
            f.AddGuide('dxH', 6, 'rw3', 'htH', 'wtH');
            f.AddGuide('dyH', 11, 'rh3', 'htH', 'wtH');
            f.AddGuide('xH', 1, 'hc', 'dxH', '0');
            f.AddGuide('yH', 1, 'vc', 'dyH', '0');
            f.AddGuide('rI', 16, 'rw2', 'rh2');
            f.AddGuide('u1', 0, 'dxH', 'dxH', '1');
            f.AddGuide('u2', 0, 'dyH', 'dyH', '1');
            f.AddGuide('u3', 0, 'rI', 'rI', '1');
            f.AddGuide('u4', 1, 'u1', '0', 'u3');
            f.AddGuide('u5', 1, 'u2', '0', 'u3');
            f.AddGuide('u6', 0, 'u4', 'u5', 'u1');
            f.AddGuide('u7', 0, 'u6', '1', 'u2');
            f.AddGuide('u8', 1, '1', '0', 'u7');
            f.AddGuide('u9', 13, 'u8');
            f.AddGuide('u10', 0, 'u4', '1', 'dxH');
            f.AddGuide('u11', 0, 'u10', '1', 'dyH');
            f.AddGuide('u12', 2, '1', 'u9', 'u11');
            f.AddGuide('u13', 5, '1', 'u12');
            f.AddGuide('u14', 1, 'u13', '21600000', '0');
            f.AddGuide('u15', 3, 'u13', 'u13', 'u14');
            f.AddGuide('u16', 1, 'u15', '0', 'enAng');
            f.AddGuide('u17', 1, 'u16', '21600000', '0');
            f.AddGuide('u18', 3, 'u16', 'u16', 'u17');
            f.AddGuide('u19', 1, 'u18', '0', 'cd2');
            f.AddGuide('u20', 1, 'u18', '0', '21600000');
            f.AddGuide('u21', 3, 'u19', 'u20', 'u18');
            f.AddGuide('maxAng', 4, 'u21');
            f.AddGuide('aAng', 10, '0', 'adj2', 'maxAng');
            f.AddGuide('ptAng', 1, 'enAng', 'aAng', '0');
            f.AddGuide('wtA', 12, 'rw3', 'ptAng');
            f.AddGuide('htA', 7, 'rh3', 'ptAng');
            f.AddGuide('dxA', 6, 'rw3', 'htA', 'wtA');
            f.AddGuide('dyA', 11, 'rh3', 'htA', 'wtA');
            f.AddGuide('xA', 1, 'hc', 'dxA', '0');
            f.AddGuide('yA', 1, 'vc', 'dyA', '0');
            f.AddGuide('wtE', 12, 'rw1', 'stAng');
            f.AddGuide('htE', 7, 'rh1', 'stAng');
            f.AddGuide('dxE', 6, 'rw1', 'htE', 'wtE');
            f.AddGuide('dyE', 11, 'rh1', 'htE', 'wtE');
            f.AddGuide('xE', 1, 'hc', 'dxE', '0');
            f.AddGuide('yE', 1, 'vc', 'dyE', '0');
            f.AddGuide('dxG', 7, 'thh', 'ptAng');
            f.AddGuide('dyG', 12, 'thh', 'ptAng');
            f.AddGuide('xG', 1, 'xH', 'dxG', '0');
            f.AddGuide('yG', 1, 'yH', 'dyG', '0');
            f.AddGuide('dxB', 7, 'thh', 'ptAng');
            f.AddGuide('dyB', 12, 'thh', 'ptAng');
            f.AddGuide('xB', 1, 'xH', '0', 'dxB', '0');
            f.AddGuide('yB', 1, 'yH', '0', 'dyB', '0');
            f.AddGuide('sx1', 1, 'xB', '0', 'hc');
            f.AddGuide('sy1', 1, 'yB', '0', 'vc');
            f.AddGuide('sx2', 1, 'xG', '0', 'hc');
            f.AddGuide('sy2', 1, 'yG', '0', 'vc');
            f.AddGuide('rO', 16, 'rw1', 'rh1');
            f.AddGuide('x1O', 0, 'sx1', 'rO', 'rw1');
            f.AddGuide('y1O', 0, 'sy1', 'rO', 'rh1');
            f.AddGuide('x2O', 0, 'sx2', 'rO', 'rw1');
            f.AddGuide('y2O', 0, 'sy2', 'rO', 'rh1');
            f.AddGuide('dxO', 1, 'x2O', '0', 'x1O');
            f.AddGuide('dyO', 1, 'y2O', '0', 'y1O');
            f.AddGuide('dO', 9, 'dxO', 'dyO', '0');
            f.AddGuide('q1', 0, 'x1O', 'y2O', '1');
            f.AddGuide('q2', 0, 'x2O', 'y1O', '1');
            f.AddGuide('DO', 1, 'q1', '0', 'q2');
            f.AddGuide('q3', 0, 'rO', 'rO', '1');
            f.AddGuide('q4', 0, 'dO', 'dO', '1');
            f.AddGuide('q5', 0, 'q3', 'q4', '1');
            f.AddGuide('q6', 0, 'DO', 'DO', '1');
            f.AddGuide('q7', 1, 'q5', '0', 'q6');
            f.AddGuide('q8', 8, 'q7', '0');
            f.AddGuide('sdelO', 13, 'q8');
            f.AddGuide('ndyO', 0, 'dyO', '-1', '1');
            f.AddGuide('sdyO', 3, 'ndyO', '-1', '1');
            f.AddGuide('q9', 0, 'sdyO', 'dxO', '1');
            f.AddGuide('q10', 0, 'q9', 'sdelO', '1');
            f.AddGuide('q11', 0, 'DO', 'dyO', '1');
            f.AddGuide('dxF1', 2, 'q11', 'q10', 'q4');
            f.AddGuide('q12', 1, 'q11', '0', 'q10');
            f.AddGuide('dxF2', 0, 'q12', '1', 'q4');
            f.AddGuide('adyO', 4, 'dyO');
            f.AddGuide('q13', 0, 'adyO', 'sdelO', '1');
            f.AddGuide('q14', 0, 'DO', 'dxO', '-1');
            f.AddGuide('dyF1', 2, 'q14', 'q13', 'q4');
            f.AddGuide('q15', 1, 'q14', '0', 'q13');
            f.AddGuide('dyF2', 0, 'q15', '1', 'q4');
            f.AddGuide('q16', 1, 'x2O', '0', 'dxF1');
            f.AddGuide('q17', 1, 'x2O', '0', 'dxF2');
            f.AddGuide('q18', 1, 'y2O', '0', 'dyF1');
            f.AddGuide('q19', 1, 'y2O', '0', 'dyF2');
            f.AddGuide('q20', 9, 'q16', 'q18', '0');
            f.AddGuide('q21', 9, 'q17', 'q19', '0');
            f.AddGuide('q22', 1, 'q21', '0', 'q20');
            f.AddGuide('dxF', 3, 'q22', 'dxF1', 'dxF2');
            f.AddGuide('dyF', 3, 'q22', 'dyF1', 'dyF2');
            f.AddGuide('sdxF', 0, 'dxF', 'rw1', 'rO');
            f.AddGuide('sdyF', 0, 'dyF', 'rh1', 'rO');
            f.AddGuide('xF', 1, 'hc', 'sdxF', '0');
            f.AddGuide('yF', 1, 'vc', 'sdyF', '0');
            f.AddGuide('x1I', 0, 'sx1', 'rI', 'rw2');
            f.AddGuide('y1I', 0, 'sy1', 'rI', 'rh2');
            f.AddGuide('x2I', 0, 'sx2', 'rI', 'rw2');
            f.AddGuide('y2I', 0, 'sy2', 'rI', 'rh2');
            f.AddGuide('dxI', 1, 'x2I', '0', 'x1I');
            f.AddGuide('dyI', 1, 'y2I', '0', 'y1I');
            f.AddGuide('dI', 9, 'dxI', 'dyI', '0');
            f.AddGuide('v1', 0, 'x1I', 'y2I', '1');
            f.AddGuide('v2', 0, 'x2I', 'y1I', '1');
            f.AddGuide('DI', 1, 'v1', '0', 'v2');
            f.AddGuide('v3', 0, 'rI', 'rI', '1');
            f.AddGuide('v4', 0, 'dI', 'dI', '1');
            f.AddGuide('v5', 0, 'v3', 'v4', '1');
            f.AddGuide('v6', 0, 'DI', 'DI', '1');
            f.AddGuide('v7', 1, 'v5', '0', 'v6');
            f.AddGuide('v8', 8, 'v7', '0');
            f.AddGuide('sdelI', 13, 'v8');
            f.AddGuide('v9', 0, 'sdyO', 'dxI', '1');
            f.AddGuide('v10', 0, 'v9', 'sdelI', '1');
            f.AddGuide('v11', 0, 'DI', 'dyI', '1');
            f.AddGuide('dxC1', 2, 'v11', 'v10', 'v4');
            f.AddGuide('v12', 1, 'v11', '0', 'v10');
            f.AddGuide('dxC2', 0, 'v12', '1', 'v4');
            f.AddGuide('adyI', 4, 'dyI');
            f.AddGuide('v13', 0, 'adyI', 'sdelI', '1');
            f.AddGuide('v14', 0, 'DI', 'dxI', '-1');
            f.AddGuide('dyC1', 2, 'v14', 'v13', 'v4');
            f.AddGuide('v15', 1, 'v14', '0', 'v13');
            f.AddGuide('dyC2', 0, 'v15', '1', 'v4');
            f.AddGuide('v16', 1, 'x1I', '0', 'dxC1');
            f.AddGuide('v17', 1, 'x1I', '0', 'dxC2');
            f.AddGuide('v18', 1, 'y1I', '0', 'dyC1');
            f.AddGuide('v19', 1, 'y1I', '0', 'dyC2');
            f.AddGuide('v20', 9, 'v16', 'v18', '0');
            f.AddGuide('v21', 9, 'v17', 'v19', '0');
            f.AddGuide('v22', 1, 'v21', '0', 'v20');
            f.AddGuide('dxC', 3, 'v22', 'dxC1', 'dxC2');
            f.AddGuide('dyC', 3, 'v22', 'dyC1', 'dyC2');
            f.AddGuide('sdxC', 0, 'dxC', 'rw2', 'rI');
            f.AddGuide('sdyC', 0, 'dyC', 'rh2', 'rI');
            f.AddGuide('xC', 1, 'hc', 'sdxC', '0');
            f.AddGuide('yC', 1, 'vc', 'sdyC', '0');
            f.AddGuide('ist0', 5, 'sdxC', 'sdyC');
            f.AddGuide('ist1', 1, 'ist0', '21600000', '0');
            f.AddGuide('istAng', 3, 'ist0', 'ist0', 'ist1');
            f.AddGuide('isw1', 1, 'stAng', '0', 'istAng');
            f.AddGuide('isw2', 1, 'isw1', '0', '21600000');
            f.AddGuide('iswAng', 3, 'isw1', 'isw2', 'isw1');
            f.AddGuide('p1', 1, 'xF', '0', 'xC');
            f.AddGuide('p2', 1, 'yF', '0', 'yC');
            f.AddGuide('p3', 9, 'p1', 'p2', '0');
            f.AddGuide('p4', 0, 'p3', '1', '2');
            f.AddGuide('p5', 1, 'p4', '0', 'thh');
            f.AddGuide('xGp', 3, 'p5', 'xF', 'xG');
            f.AddGuide('yGp', 3, 'p5', 'yF', 'yG');
            f.AddGuide('xBp', 3, 'p5', 'xC', 'xB');
            f.AddGuide('yBp', 3, 'p5', 'yC', 'yB');
            f.AddGuide('en0', 5, 'sdxF', 'sdyF');
            f.AddGuide('en1', 1, 'en0', '21600000', '0');
            f.AddGuide('en2', 3, 'en0', 'en0', 'en1');
            f.AddGuide('sw0', 1, 'en2', '0', 'stAng');
            f.AddGuide('sw1', 1, 'sw0', '21600000', '0');
            f.AddGuide('swAng', 3, 'sw0', 'sw0', 'sw1');
            f.AddGuide('wtI', 12, 'rw3', 'stAng');
            f.AddGuide('htI', 7, 'rh3', 'stAng');
            f.AddGuide('dxI', 6, 'rw3', 'htI', 'wtI');
            f.AddGuide('dyI', 11, 'rh3', 'htI', 'wtI');
            f.AddGuide('xI', 1, 'hc', 'dxI', '0');
            f.AddGuide('yI', 1, 'vc', 'dyI', '0');
            f.AddGuide('aI', 1, 'stAng', '0', 'cd4');
            f.AddGuide('aA', 1, 'ptAng', 'cd4', '0');
            f.AddGuide('aB', 1, 'ptAng', 'cd2', '0');
            f.AddGuide('idx', 7, 'rw1', '2700000');
            f.AddGuide('idy', 12, 'rh1', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddHandlePolar('adj2','0','maxAng', undefined, '0', '0', 'xA', 'yA');
            f.AddHandlePolar('adj4','0','21599999', undefined, '0', '0', 'xE', 'yE');
            f.AddHandlePolar(undefined, '0', '0','adj1','0','maxAdj1', 'xF', 'yF');
            f.AddHandlePolar(undefined, '0', '0','adj5','0','25000', 'xB', 'yB');
            f.AddCnx('aI', 'xI', 'yI');
            f.AddCnx('ptAng', 'xGp', 'yGp');
            f.AddCnx('aA', 'xA', 'yA');
            f.AddCnx('aB', 'xBp', 'yBp');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'xE', 'yE');
            f.AddPathCommand(3, 'rw1', 'rh1', 'stAng', 'swAng');
            f.AddPathCommand(2, 'xGp', 'yGp');
            f.AddPathCommand(2, 'xA', 'yA');
            f.AddPathCommand(2, 'xBp', 'yBp');
            f.AddPathCommand(2, 'xC', 'yC');
            f.AddPathCommand(3, 'rw2', 'rh2', 'istAng', 'iswAng');
            f.AddPathCommand(6);
            break;
        }
        case 'cloud':{
            f.AddGuide('il', 0, 'w', '2977', '21600');
            f.AddGuide('it', 0, 'h', '3262', '21600');
            f.AddGuide('ir', 0, 'w', '17087', '21600');
            f.AddGuide('ib', 0, 'h', '17337', '21600');
            f.AddGuide('g27', 0, 'w', '67', '21600');
            f.AddGuide('g28', 0, 'h', '21577', '21600');
            f.AddGuide('g29', 0, 'w', '21582', '21600');
            f.AddGuide('g30', 0, 'h', '1235', '21600');
            f.AddCnx('0', 'g29', 'vc');
            f.AddCnx('cd4', 'hc', 'g28');
            f.AddCnx('cd2', 'g27', 'vc');
            f.AddCnx('_3cd4', 'hc', 'g30');
            f.AddRect('il', 'it', 'ir', 'ib');
             f.AddPathCommand(0,undefined, undefined, undefined, 43200, 43200);
            f.AddPathCommand(1, '3900', '14370');
            f.AddPathCommand(3, '6753', '9190', '-11429249', '7426832');
            f.AddPathCommand(3, '5333', '7267', '-8646143', '5396714');
            f.AddPathCommand(3, '4365', '5945', '-8748475', '5983381');
            f.AddPathCommand(3, '4857', '6595', '-7859164', '7034504');
            f.AddPathCommand(3, '5333', '7273', '-4722533', '6541615');
            f.AddPathCommand(3, '6775', '9220', '-2776035', '7816140');
            f.AddPathCommand(3, '5785', '7867', '37501', '6842000');
            f.AddPathCommand(3, '6752', '9215', '1347096', '6910353');
            f.AddPathCommand(3, '7720', '10543', '3974558', '4542661');
            f.AddPathCommand(3, '4360', '5918', '-16496525', '8804134');
            f.AddPathCommand(3, '4345', '5945', '-14809710', '9151131');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, 43200, 43200);
            f.AddPathCommand(1, '4693', '26177');
            f.AddPathCommand(3, '4345', '5945', '5204520', '1585770');
            f.AddPathCommand(1, '6928', '34899');
            f.AddPathCommand(3, '4360', '5918', '4416628', '686848');
            f.AddPathCommand(1, '16478', '39090');
            f.AddPathCommand(3, '6752', '9215', '8257449', '844866');
            f.AddPathCommand(1, '28827', '34751');
            f.AddPathCommand(3, '6752', '9215', '387196', '959901');
            f.AddPathCommand(1, '34129', '22954');
            f.AddPathCommand(3, '5785', '7867', '-4217541', '4255042');
            f.AddPathCommand(1, '41798', '15354');
            f.AddPathCommand(3, '5333', '7273', '1819082', '1665090');
            f.AddPathCommand(1, '38324', '5426');
            f.AddPathCommand(3, '4857', '6595', '-824660', '891534');
            f.AddPathCommand(1, '29078', '3952');
            f.AddPathCommand(3, '4857', '6595', '-8950887', '1091722');
            f.AddPathCommand(1, '22141', '4720');
            f.AddPathCommand(3, '4365', '5945', '-9809656', '1061181');
            f.AddPathCommand(1, '14000', '5192');
            f.AddPathCommand(3, '6753', '9190', '-4002417', '739161');
            f.AddPathCommand(1, '4127', '15789');
            f.AddPathCommand(3, '6753', '9190', '9459261', '711490');
            f.AddPathCommand(6);
            break;
        }
        case 'cloudCallout':{
            f.AddAdj('adj1', 15, '-20833');
            f.AddAdj('adj2', 15, '62500');
            f.AddGuide('dxPos', 0, 'w', 'adj1', '100000');
            f.AddGuide('dyPos', 0, 'h', 'adj2', '100000');
            f.AddGuide('xPos', 1, 'hc', 'dxPos', '0');
            f.AddGuide('yPos', 1, 'vc', 'dyPos', '0');
            f.AddGuide('ht', 6, 'hd2', 'dxPos', 'dyPos');
            f.AddGuide('wt', 11, 'wd2', 'dxPos', 'dyPos');
            f.AddGuide('g2', 6, 'wd2', 'ht', 'wt');
            f.AddGuide('g3', 11, 'hd2', 'ht', 'wt');
            f.AddGuide('g4', 1, 'hc', 'g2', '0');
            f.AddGuide('g5', 1, 'vc', 'g3', '0');
            f.AddGuide('g6', 1, 'g4', '0', 'xPos');
            f.AddGuide('g7', 1, 'g5', '0', 'yPos');
            f.AddGuide('g8', 9, 'g6', 'g7', '0');
            f.AddGuide('g9', 0, 'ss', '6600', '21600');
            f.AddGuide('g10', 1, 'g8', '0', 'g9');
            f.AddGuide('g11', 0, 'g10', '1', '3');
            f.AddGuide('g12', 0, 'ss', '1800', '21600');
            f.AddGuide('g13', 1, 'g11', 'g12', '0');
            f.AddGuide('g14', 0, 'g13', 'g6', 'g8');
            f.AddGuide('g15', 0, 'g13', 'g7', 'g8');
            f.AddGuide('g16', 1, 'g14', 'xPos', '0');
            f.AddGuide('g17', 1, 'g15', 'yPos', '0');
            f.AddGuide('g18', 0, 'ss', '4800', '21600');
            f.AddGuide('g19', 0, 'g11', '2', '1');
            f.AddGuide('g20', 1, 'g18', 'g19', '0');
            f.AddGuide('g21', 0, 'g20', 'g6', 'g8');
            f.AddGuide('g22', 0, 'g20', 'g7', 'g8');
            f.AddGuide('g23', 1, 'g21', 'xPos', '0');
            f.AddGuide('g24', 1, 'g22', 'yPos', '0');
            f.AddGuide('g25', 0, 'ss', '1200', '21600');
            f.AddGuide('g26', 0, 'ss', '600', '21600');
            f.AddGuide('x23', 1, 'xPos', 'g26', '0');
            f.AddGuide('x24', 1, 'g16', 'g25', '0');
            f.AddGuide('x25', 1, 'g23', 'g12', '0');
            f.AddGuide('il', 0, 'w', '2977', '21600');
            f.AddGuide('it', 0, 'h', '3262', '21600');
            f.AddGuide('ir', 0, 'w', '17087', '21600');
            f.AddGuide('ib', 0, 'h', '17337', '21600');
            f.AddGuide('g27', 0, 'w', '67', '21600');
            f.AddGuide('g28', 0, 'h', '21577', '21600');
            f.AddGuide('g29', 0, 'w', '21582', '21600');
            f.AddGuide('g30', 0, 'h', '1235', '21600');
            f.AddGuide('pang', 5, 'dxPos', 'dyPos');
            f.AddHandleXY('adj1','-2147483647','2147483647','adj2','-2147483647','2147483647', 'xPos', 'yPos');
            f.AddCnx('cd2', 'g27', 'vc');
            f.AddCnx('cd4', 'hc', 'g28');
            f.AddCnx('0', 'g29', 'vc');
            f.AddCnx('_3cd4', 'hc', 'g30');
            f.AddCnx('pang', 'xPos', 'yPos');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, 43200, 43200);
            f.AddPathCommand(1, '3900', '14370');
            f.AddPathCommand(3, '6753', '9190', '-11429249', '7426832');
            f.AddPathCommand(3, '5333', '7267', '-8646143', '5396714');
            f.AddPathCommand(3, '4365', '5945', '-8748475', '5983381');
            f.AddPathCommand(3, '4857', '6595', '-7859164', '7034504');
            f.AddPathCommand(3, '5333', '7273', '-4722533', '6541615');
            f.AddPathCommand(3, '6775', '9220', '-2776035', '7816140');
            f.AddPathCommand(3, '5785', '7867', '37501', '6842000');
            f.AddPathCommand(3, '6752', '9215', '1347096', '6910353');
            f.AddPathCommand(3, '7720', '10543', '3974558', '4542661');
            f.AddPathCommand(3, '4360', '5918', '-16496525', '8804134');
            f.AddPathCommand(3, '4345', '5945', '-14809710', '9151131');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x23', 'yPos');
            f.AddPathCommand(3, 'g26', 'g26', '0', '21600000');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x24', 'g17');
            f.AddPathCommand(3, 'g25', 'g25', '0', '21600000');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x25', 'g24');
            f.AddPathCommand(3, 'g12', 'g12', '0', '21600000');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, 43200, 43200);
            f.AddPathCommand(1, '4693', '26177');
            f.AddPathCommand(3, '4345', '5945', '5204520', '1585770');
            f.AddPathCommand(1, '6928', '34899');
            f.AddPathCommand(3, '4360', '5918', '4416628', '686848');
            f.AddPathCommand(1, '16478', '39090');
            f.AddPathCommand(3, '6752', '9215', '8257449', '844866');
            f.AddPathCommand(1, '28827', '34751');
            f.AddPathCommand(3, '6752', '9215', '387196', '959901');
            f.AddPathCommand(1, '34129', '22954');
            f.AddPathCommand(3, '5785', '7867', '-4217541', '4255042');
            f.AddPathCommand(1, '41798', '15354');
            f.AddPathCommand(3, '5333', '7273', '1819082', '1665090');
            f.AddPathCommand(1, '38324', '5426');
            f.AddPathCommand(3, '4857', '6595', '-824660', '891534');
            f.AddPathCommand(1, '29078', '3952');
            f.AddPathCommand(3, '4857', '6595', '-8950887', '1091722');
            f.AddPathCommand(1, '22141', '4720');
            f.AddPathCommand(3, '4365', '5945', '-9809656', '1061181');
            f.AddPathCommand(1, '14000', '5192');
            f.AddPathCommand(3, '6753', '9190', '-4002417', '739161');
            f.AddPathCommand(1, '4127', '15789');
            f.AddPathCommand(3, '6753', '9190', '9459261', '711490');
            f.AddPathCommand(6);
            break;
        }
        case 'corner':{
            f.AddAdj('adj1', 15, '50000');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('maxAdj1', 0, '100000', 'h', 'ss');
            f.AddGuide('maxAdj2', 0, '100000', 'w', 'ss');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('x1', 0, 'ss', 'a2', '100000');
            f.AddGuide('dy1', 0, 'ss', 'a1', '100000');
            f.AddGuide('y1', 1, 'b', '0', 'dy1');
            f.AddGuide('cx1', 0, 'x1', '1', '2');
            f.AddGuide('cy1', 2, 'y1', 'b', '2');
            f.AddGuide('d', 1, 'w', '0', 'h');
            f.AddGuide('it', 3, 'd', 'y1', 't');
            f.AddGuide('ir', 3, 'd', 'r', 'x1');
            f.AddHandleXY(undefined, '0', '0','adj1','0','maxAdj1', 'l', 'y1');
            f.AddHandleXY('adj2','0','maxAdj2', undefined, '0', '0', 'x1', 't');
            f.AddCnx('0', 'r', 'cy1');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'cx1', 't');
            f.AddRect('l', 'it', 'ir', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'x1', 't');
            f.AddPathCommand(2, 'x1', 'y1');
            f.AddPathCommand(2, 'r', 'y1');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'cornerTabs':{
            f.AddGuide('md', 9, 'w', 'h', '0');
            f.AddGuide('dx', 0, '1', 'md', '20');
            f.AddGuide('y1', 1, '0', 'b', 'dx');
            f.AddGuide('x1', 1, '0', 'r', 'dx');
            f.AddCnx('cd2', 'l', 't');
            f.AddCnx('cd2', 'l', 'dx');
            f.AddCnx('cd2', 'l', 'y1');
            f.AddCnx('cd2', 'l', 'b');
            f.AddCnx('_3cd4', 'dx', 't');
            f.AddCnx('_3cd4', 'x1', 't');
            f.AddCnx('cd4', 'dx', 'b');
            f.AddCnx('cd4', 'x1', 'b');
            f.AddCnx('0', 'r', 't');
            f.AddCnx('0', 'r', 'dx');
            f.AddCnx('0', 'r', 'y1');
            f.AddCnx('0', 'r', 'b');
            f.AddRect('dx', 'dx', 'x1', 'y1');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'dx', 't');
            f.AddPathCommand(2, 'l', 'dx');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(2, 'dx', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'dx');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'r', 'y1');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'cube':{
            f.AddAdj('adj', 15, '25000');
            f.AddGuide('a', 10, '0', 'adj', '100000');
            f.AddGuide('y1', 0, 'ss', 'a', '100000');
            f.AddGuide('y4', 1, 'b', '0', 'y1');
            f.AddGuide('y2', 0, 'y4', '1', '2');
            f.AddGuide('y3', 2, 'y1', 'b', '2');
            f.AddGuide('x4', 1, 'r', '0', 'y1');
            f.AddGuide('x2', 0, 'x4', '1', '2');
            f.AddGuide('x3', 2, 'y1', 'r', '2');
            f.AddHandleXY(undefined, '0', '0','adj','0','100000', 'l', 'y1');
            f.AddCnx('_3cd4', 'x3', 't');
            f.AddCnx('_3cd4', 'x2', 'y1');
            f.AddCnx('cd2', 'l', 'y3');
            f.AddCnx('cd4', 'x2', 'b');
            f.AddCnx('0', 'x4', 'y3');
            f.AddCnx('0', 'r', 'y2');
            f.AddRect('l', 'y1', 'x4', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(2, 'x4', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'x4', 'y1');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'y4');
            f.AddPathCommand(2, 'x4', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'lightenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(2, 'y1', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(2, 'y1', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'y4');
            f.AddPathCommand(2, 'x4', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(1, 'x4', 'y1');
            f.AddPathCommand(2, 'x4', 'b');
            break;
        }
        case 'curvedConnector2':{
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(5, 'wd2', 't', 'r', 'hd2', 'r', 'b');
            break;
        }
        case 'curvedConnector3':{
            f.AddAdj('adj1', 15, '50000');
            f.AddGuide('x2', 0, 'w', 'adj1', '100000');
            f.AddGuide('x1', 2, 'l', 'x2', '2');
            f.AddGuide('x3', 2, 'r', 'x2', '2');
            f.AddGuide('y3', 0, 'h', '3', '4');
            f.AddHandleXY('adj1','-2147483647','2147483647', undefined, '0', '0', 'x2', 'vc');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(5, 'x1', 't', 'x2', 'hd4', 'x2', 'vc');
            f.AddPathCommand(5, 'x2', 'y3', 'x3', 'b', 'r', 'b');
            break;
        }
        case 'curvedConnector4':{
            f.AddAdj('adj1', 15, '50000');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('x2', 0, 'w', 'adj1', '100000');
            f.AddGuide('x1', 2, 'l', 'x2', '2');
            f.AddGuide('x3', 2, 'r', 'x2', '2');
            f.AddGuide('x4', 2, 'x2', 'x3', '2');
            f.AddGuide('x5', 2, 'x3', 'r', '2');
            f.AddGuide('y4', 0, 'h', 'adj2', '100000');
            f.AddGuide('y1', 2, 't', 'y4', '2');
            f.AddGuide('y2', 2, 't', 'y1', '2');
            f.AddGuide('y3', 2, 'y1', 'y4', '2');
            f.AddGuide('y5', 2, 'b', 'y4', '2');
            f.AddHandleXY('adj1','-2147483647','2147483647', undefined, '0', '0', 'x2', 'y1');
            f.AddHandleXY(undefined, '0', '0','adj2','-2147483647','2147483647', 'x3', 'y4');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(5, 'x1', 't', 'x2', 'y2', 'x2', 'y1');
            f.AddPathCommand(5, 'x2', 'y3', 'x4', 'y4', 'x3', 'y4');
            f.AddPathCommand(5, 'x5', 'y4', 'r', 'y5', 'r', 'b');
            break;
        }
        case 'curvedConnector5':{
            f.AddAdj('adj1', 15, '50000');
            f.AddAdj('adj2', 15, '50000');
            f.AddAdj('adj3', 15, '50000');
            f.AddGuide('x3', 0, 'w', 'adj1', '100000');
            f.AddGuide('x6', 0, 'w', 'adj3', '100000');
            f.AddGuide('x1', 2, 'x3', 'x6', '2');
            f.AddGuide('x2', 2, 'l', 'x3', '2');
            f.AddGuide('x4', 2, 'x3', 'x1', '2');
            f.AddGuide('x5', 2, 'x6', 'x1', '2');
            f.AddGuide('x7', 2, 'x6', 'r', '2');
            f.AddGuide('y4', 0, 'h', 'adj2', '100000');
            f.AddGuide('y1', 2, 't', 'y4', '2');
            f.AddGuide('y2', 2, 't', 'y1', '2');
            f.AddGuide('y3', 2, 'y1', 'y4', '2');
            f.AddGuide('y5', 2, 'b', 'y4', '2');
            f.AddGuide('y6', 2, 'y5', 'y4', '2');
            f.AddGuide('y7', 2, 'y5', 'b', '2');
            f.AddHandleXY('adj1','-2147483647','2147483647', undefined, '0', '0', 'x3', 'y1');
            f.AddHandleXY(undefined, '0', '0','adj2','-2147483647','2147483647', 'x1', 'y4');
            f.AddHandleXY('adj3','-2147483647','2147483647', undefined, '0', '0', 'x6', 'y5');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(5, 'x2', 't', 'x3', 'y2', 'x3', 'y1');
            f.AddPathCommand(5, 'x3', 'y3', 'x4', 'y4', 'x1', 'y4');
            f.AddPathCommand(5, 'x5', 'y4', 'x6', 'y6', 'x6', 'y5');
            f.AddPathCommand(5, 'x6', 'y7', 'x7', 'b', 'r', 'b');
            break;
        }
        case 'curvedDownArrow':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '50000');
            f.AddAdj('adj3', 15, '25000');
            f.AddGuide('maxAdj2', 0, '50000', 'w', 'ss');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('a1', 10, '0', 'adj1', '100000');
            f.AddGuide('th', 0, 'ss', 'a1', '100000');
            f.AddGuide('aw', 0, 'ss', 'a2', '100000');
            f.AddGuide('q1', 2, 'th', 'aw', '4');
            f.AddGuide('wR', 1, 'wd2', '0', 'q1');
            f.AddGuide('q7', 0, 'wR', '2', '1');
            f.AddGuide('q8', 0, 'q7', 'q7', '1');
            f.AddGuide('q9', 0, 'th', 'th', '1');
            f.AddGuide('q10', 1, 'q8', '0', 'q9');
            f.AddGuide('q11', 13, 'q10');
            f.AddGuide('idy', 0, 'q11', 'h', 'q7');
            f.AddGuide('maxAdj3', 0, '100000', 'idy', 'ss');
            f.AddGuide('a3', 10, '0', 'adj3', 'maxAdj3');
            f.AddGuide('ah', 0, 'ss', 'adj3', '100000');
            f.AddGuide('x3', 1, 'wR', 'th', '0');
            f.AddGuide('q2', 0, 'h', 'h', '1');
            f.AddGuide('q3', 0, 'ah', 'ah', '1');
            f.AddGuide('q4', 1, 'q2', '0', 'q3');
            f.AddGuide('q5', 13, 'q4');
            f.AddGuide('dx', 0, 'q5', 'wR', 'h');
            f.AddGuide('x5', 1, 'wR', 'dx', '0');
            f.AddGuide('x7', 1, 'x3', 'dx', '0');
            f.AddGuide('q6', 1, 'aw', '0', 'th');
            f.AddGuide('dh', 0, 'q6', '1', '2');
            f.AddGuide('x4', 1, 'x5', '0', 'dh');
            f.AddGuide('x8', 1, 'x7', 'dh', '0');
            f.AddGuide('aw2', 0, 'aw', '1', '2');
            f.AddGuide('x6', 1, 'r', '0', 'aw2');
            f.AddGuide('y1', 1, 'b', '0', 'ah');
            f.AddGuide('swAng', 5, 'ah', 'dx');
            f.AddGuide('mswAng', 1, '0', '0', 'swAng');
            f.AddGuide('iy', 1, 'b', '0', 'idy');
            f.AddGuide('ix', 2, 'wR', 'x3', '2');
            f.AddGuide('q12', 0, 'th', '1', '2');
            f.AddGuide('dang2', 5, 'idy', 'q12');
            f.AddGuide('stAng', 1, '_3cd4', 'swAng', '0');
            f.AddGuide('stAng2', 1, '_3cd4', '0', 'dang2');
            f.AddGuide('swAng2', 1, 'dang2', '0', 'cd4');
            f.AddGuide('swAng3', 1, 'cd4', 'dang2', '0');
            f.AddHandleXY('adj1','0','adj2', undefined, '0', '0', 'x7', 'y1');
            f.AddHandleXY('adj2','0','maxAdj2', undefined, '0', '0', 'x4', 'b');
            f.AddHandleXY(undefined, '0', '0','adj3','0','maxAdj3', 'r', 'y1');
            f.AddCnx('_3cd4', 'ix', 't');
            f.AddCnx('cd4', 'q12', 'b');
            f.AddCnx('cd4', 'x4', 'y1');
            f.AddCnx('cd4', 'x6', 'b');
            f.AddCnx('0', 'x8', 'y1');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'x6', 'b');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(2, 'x5', 'y1');
            f.AddPathCommand(3, 'wR', 'h', 'stAng', 'mswAng');
            f.AddPathCommand(2, 'x3', 't');
            f.AddPathCommand(3, 'wR', 'h', '_3cd4', 'swAng');
            f.AddPathCommand(2, 'x8', 'y1');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'ix', 'iy');
            f.AddPathCommand(3, 'wR', 'h', 'stAng2', 'swAng2');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(3, 'wR', 'h', 'cd2', 'swAng3');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'ix', 'iy');
            f.AddPathCommand(3, 'wR', 'h', 'stAng2', 'swAng2');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(3, 'wR', 'h', 'cd2', 'cd4');
            f.AddPathCommand(2, 'x3', 't');
            f.AddPathCommand(3, 'wR', 'h', '_3cd4', 'swAng');
            f.AddPathCommand(2, 'x8', 'y1');
            f.AddPathCommand(2, 'x6', 'b');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(2, 'x5', 'y1');
            f.AddPathCommand(3, 'wR', 'h', 'stAng', 'mswAng');
            break;
        }
        case 'curvedLeftArrow':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '50000');
            f.AddAdj('adj3', 15, '25000');
            f.AddGuide('maxAdj2', 0, '50000', 'h', 'ss');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('a1', 10, '0', 'adj1', 'a2');
            f.AddGuide('th', 0, 'ss', 'a1', '100000');
            f.AddGuide('aw', 0, 'ss', 'a2', '100000');
            f.AddGuide('q1', 2, 'th', 'aw', '4');
            f.AddGuide('hR', 1, 'hd2', '0', 'q1');
            f.AddGuide('q7', 0, 'hR', '2', '1');
            f.AddGuide('q8', 0, 'q7', 'q7', '1');
            f.AddGuide('q9', 0, 'th', 'th', '1');
            f.AddGuide('q10', 1, 'q8', '0', 'q9');
            f.AddGuide('q11', 13, 'q10');
            f.AddGuide('idx', 0, 'q11', 'w', 'q7');
            f.AddGuide('maxAdj3', 0, '100000', 'idx', 'ss');
            f.AddGuide('a3', 10, '0', 'adj3', 'maxAdj3');
            f.AddGuide('ah', 0, 'ss', 'a3', '100000');
            f.AddGuide('y3', 1, 'hR', 'th', '0');
            f.AddGuide('q2', 0, 'w', 'w', '1');
            f.AddGuide('q3', 0, 'ah', 'ah', '1');
            f.AddGuide('q4', 1, 'q2', '0', 'q3');
            f.AddGuide('q5', 13, 'q4');
            f.AddGuide('dy', 0, 'q5', 'hR', 'w');
            f.AddGuide('y5', 1, 'hR', 'dy', '0');
            f.AddGuide('y7', 1, 'y3', 'dy', '0');
            f.AddGuide('q6', 1, 'aw', '0', 'th');
            f.AddGuide('dh', 0, 'q6', '1', '2');
            f.AddGuide('y4', 1, 'y5', '0', 'dh');
            f.AddGuide('y8', 1, 'y7', 'dh', '0');
            f.AddGuide('aw2', 0, 'aw', '1', '2');
            f.AddGuide('y6', 1, 'b', '0', 'aw2');
            f.AddGuide('x1', 1, 'l', 'ah', '0');
            f.AddGuide('swAng', 5, 'ah', 'dy');
            f.AddGuide('mswAng', 1, '0', '0', 'swAng');
            f.AddGuide('ix', 1, 'l', 'idx', '0');
            f.AddGuide('iy', 2, 'hR', 'y3', '2');
            f.AddGuide('q12', 0, 'th', '1', '2');
            f.AddGuide('dang2', 5, 'idx', 'q12');
            f.AddGuide('swAng2', 1, 'dang2', '0', 'swAng');
            f.AddGuide('swAng3', 1, 'swAng', 'dang2', '0');
            f.AddGuide('stAng3', 1, '0', '0', 'dang2');
            f.AddHandleXY(undefined, '0', '0','adj1','0','a2', 'x1', 'y5');
            f.AddHandleXY(undefined, '0', '0','adj2','0','maxAdj2', 'r', 'y4');
            f.AddHandleXY('adj3','0','maxAdj3', undefined, '0', '0', 'x1', 'b');
            f.AddCnx('cd2', 'l', 'q12');
            f.AddCnx('cd2', 'x1', 'y4');
            f.AddCnx('cd3', 'l', 'y6');
            f.AddCnx('cd4', 'x1', 'y8');
            f.AddCnx('0', 'r', 'iy');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y6');
            f.AddPathCommand(2, 'x1', 'y4');
            f.AddPathCommand(2, 'x1', 'y5');
            f.AddPathCommand(3, 'w', 'hR', 'swAng', 'swAng2');
            f.AddPathCommand(3, 'w', 'hR', 'stAng3', 'swAng3');
            f.AddPathCommand(2, 'x1', 'y8');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'r', 'y3');
            f.AddPathCommand(3, 'w', 'hR', '0', '-5400000');
            f.AddPathCommand(2, 'l', 't');
            f.AddPathCommand(3, 'w', 'hR', '_3cd4', 'cd4');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'r', 'y3');
            f.AddPathCommand(3, 'w', 'hR', '0', '-5400000');
            f.AddPathCommand(2, 'l', 't');
            f.AddPathCommand(3, 'w', 'hR', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'r', 'y3');
            f.AddPathCommand(3, 'w', 'hR', '0', 'swAng');
            f.AddPathCommand(2, 'x1', 'y8');
            f.AddPathCommand(2, 'l', 'y6');
            f.AddPathCommand(2, 'x1', 'y4');
            f.AddPathCommand(2, 'x1', 'y5');
            f.AddPathCommand(3, 'w', 'hR', 'swAng', 'swAng2');
            break;
        }
        case 'curvedRightArrow':{

            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '50000');
            f.AddAdj('adj3', 15, '25000');
            f.AddGuide('maxAdj2', 0, '50000', 'h', 'ss');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('a1', 10, '0', 'adj1', 'a2');
            f.AddGuide('th', 0, 'ss', 'a1', '100000');
            f.AddGuide('aw', 0, 'ss', 'a2', '100000');
            f.AddGuide('q1', 2, 'th', 'aw', '4');
            f.AddGuide('hR', 1, 'hd2', '0', 'q1');
            f.AddGuide('q7', 0, 'hR', '2', '1');
            f.AddGuide('q8', 0, 'q7', 'q7', '1');
            f.AddGuide('q9', 0, 'th', 'th', '1');
            f.AddGuide('q10', 1, 'q8', '0', 'q9');
            f.AddGuide('q11', 13, 'q10');
            f.AddGuide('idx', 0, 'q11', 'w', 'q7');
            f.AddGuide('maxAdj3', 0, '100000', 'idx', 'ss');
            f.AddGuide('a3', 10, '0', 'adj3', 'maxAdj3');
            f.AddGuide('ah', 0, 'ss', 'a3', '100000');
            f.AddGuide('y3', 1, 'hR', 'th', '0');
            f.AddGuide('q2', 0, 'w', 'w', '1');
            f.AddGuide('q3', 0, 'ah', 'ah', '1');
            f.AddGuide('q4', 1, 'q2', '0', 'q3');
            f.AddGuide('q5', 13, 'q4');
            f.AddGuide('dy', 0, 'q5', 'hR', 'w');
            f.AddGuide('y5', 1, 'hR', 'dy', '0');
            f.AddGuide('y7', 1, 'y3', 'dy', '0');
            f.AddGuide('q6', 1, 'aw', '0', 'th');
            f.AddGuide('dh', 0, 'q6', '1', '2');
            f.AddGuide('y4', 1, 'y5', '0', 'dh');
            f.AddGuide('y8', 1, 'y7', 'dh', '0');
            f.AddGuide('aw2', 0, 'aw', '1', '2');
            f.AddGuide('y6', 1, 'b', '0', 'aw2');
            f.AddGuide('x1', 1, 'r', '0', 'ah');
            f.AddGuide('swAng', 5, 'ah', 'dy');
            f.AddGuide('stAng', 1, 'cd2', '0', 'swAng');
            f.AddGuide('mswAng', 1, '0', '0', 'swAng');
            f.AddGuide('ix', 1, 'r', '0', 'idx');
            f.AddGuide('iy', 2, 'hR', 'y3', '2');
            f.AddGuide('q12', 0, 'th', '1', '2');
            f.AddGuide('dang2', 5, 'idx', 'q12');
            f.AddGuide('swAng2', 1, 'dang2', '0', 'cd4');
            f.AddGuide('swAng3', 1, 'cd4', 'dang2', '0');
            f.AddGuide('stAng3', 1, 'cd2', '0', 'dang2');
            f.AddHandleXY(undefined, '0', '0','adj1','0','a2', 'x1', 'y5');
            f.AddHandleXY(undefined, '0', '0','adj2','0','maxAdj2', 'r', 'y4');
            f.AddHandleXY('adj3','0','maxAdj3', undefined, '0', '0', 'x1', 'b');
            f.AddCnx('cd2', 'l', 'iy');
            f.AddCnx('cd4', 'x1', 'y8');
            f.AddCnx('0', 'r', 'y6');
            f.AddCnx('0', 'x1', 'y4');
            f.AddCnx('0', 'r', 'q12');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 'hR');
            f.AddPathCommand(3, 'w', 'hR', 'cd2', 'mswAng');
            f.AddPathCommand(2, 'x1', 'y4');
            f.AddPathCommand(2, 'r', 'y6');
            f.AddPathCommand(2, 'x1', 'y8');
            f.AddPathCommand(2, 'x1', 'y7');
            f.AddPathCommand(3, 'w', 'hR', 'stAng', 'swAng');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'r', 'th');
            f.AddPathCommand(3, 'w', 'hR', '_3cd4', 'swAng2');
            f.AddPathCommand(3, 'w', 'hR', 'stAng3', 'swAng3');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'hR');
            f.AddPathCommand(3, 'w', 'hR', 'cd2', 'mswAng');
            f.AddPathCommand(2, 'x1', 'y4');
            f.AddPathCommand(2, 'r', 'y6');
            f.AddPathCommand(2, 'x1', 'y8');
            f.AddPathCommand(2, 'x1', 'y7');
            f.AddPathCommand(3, 'w', 'hR', 'stAng', 'swAng');
            f.AddPathCommand(2, 'l', 'hR');
            f.AddPathCommand(3, 'w', 'hR', 'cd2', 'cd4');
            f.AddPathCommand(2, 'r', 'th');
            f.AddPathCommand(3, 'w', 'hR', '_3cd4', 'swAng2');
            break;
        }
        case 'curvedUpArrow':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '50000');
            f.AddAdj('adj3', 15, '25000');
            f.AddGuide('maxAdj2', 0, '50000', 'w', 'ss');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('a1', 10, '0', 'adj1', '100000');
            f.AddGuide('th', 0, 'ss', 'a1', '100000');
            f.AddGuide('aw', 0, 'ss', 'a2', '100000');
            f.AddGuide('q1', 2, 'th', 'aw', '4');
            f.AddGuide('wR', 1, 'wd2', '0', 'q1');
            f.AddGuide('q7', 0, 'wR', '2', '1');
            f.AddGuide('q8', 0, 'q7', 'q7', '1');
            f.AddGuide('q9', 0, 'th', 'th', '1');
            f.AddGuide('q10', 1, 'q8', '0', 'q9');
            f.AddGuide('q11', 13, 'q10');
            f.AddGuide('idy', 0, 'q11', 'h', 'q7');
            f.AddGuide('maxAdj3', 0, '100000', 'idy', 'ss');
            f.AddGuide('a3', 10, '0', 'adj3', 'maxAdj3');
            f.AddGuide('ah', 0, 'ss', 'adj3', '100000');
            f.AddGuide('x3', 1, 'wR', 'th', '0');
            f.AddGuide('q2', 0, 'h', 'h', '1');
            f.AddGuide('q3', 0, 'ah', 'ah', '1');
            f.AddGuide('q4', 1, 'q2', '0', 'q3');
            f.AddGuide('q5', 13, 'q4');
            f.AddGuide('dx', 0, 'q5', 'wR', 'h');
            f.AddGuide('x5', 1, 'wR', 'dx', '0');
            f.AddGuide('x7', 1, 'x3', 'dx', '0');
            f.AddGuide('q6', 1, 'aw', '0', 'th');
            f.AddGuide('dh', 0, 'q6', '1', '2');
            f.AddGuide('x4', 1, 'x5', '0', 'dh');
            f.AddGuide('x8', 1, 'x7', 'dh', '0');
            f.AddGuide('aw2', 0, 'aw', '1', '2');
            f.AddGuide('x6', 1, 'r', '0', 'aw2');
            f.AddGuide('y1', 1, 't', 'ah', '0');
            f.AddGuide('swAng', 5, 'ah', 'dx');
            f.AddGuide('mswAng', 1, '0', '0', 'swAng');
            f.AddGuide('iy', 1, 't', 'idy', '0');
            f.AddGuide('ix', 2, 'wR', 'x3', '2');
            f.AddGuide('q12', 0, 'th', '1', '2');
            f.AddGuide('dang2', 5, 'idy', 'q12');
            f.AddGuide('swAng2', 1, 'dang2', '0', 'swAng');
            f.AddGuide('mswAng2', 1, '0', '0', 'swAng2');
            f.AddGuide('stAng3', 1, 'cd4', '0', 'swAng');
            f.AddGuide('swAng3', 1, 'swAng', 'dang2', '0');
            f.AddGuide('stAng2', 1, 'cd4', '0', 'dang2');
            f.AddHandleXY('adj1','0','a2', undefined, '0', '0', 'x7', 'y1');
            f.AddHandleXY('adj2','0','maxAdj2', undefined, '0', '0', 'x4', 't');
            f.AddHandleXY(undefined, '0', '0','adj3','0','maxAdj3', 'r', 'y1');
            f.AddCnx('_3cd4', 'x6', 't');
            f.AddCnx('_3cd4', 'x4', 'y1');
            f.AddCnx('_3cd4', 'q12', 't');
            f.AddCnx('cd4', 'ix', 'b');
            f.AddCnx('0', 'x8', 'y1');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'x6', 't');
            f.AddPathCommand(2, 'x8', 'y1');
            f.AddPathCommand(2, 'x7', 'y1');
            f.AddPathCommand(3, 'wR', 'h', 'stAng3', 'swAng3');
            f.AddPathCommand(3, 'wR', 'h', 'stAng2', 'swAng2');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'wR', 'b');
            f.AddPathCommand(3, 'wR', 'h', 'cd4', 'cd4');
            f.AddPathCommand(2, 'th', 't');
            f.AddPathCommand(3, 'wR', 'h', 'cd2', '-5400000');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'ix', 'iy');
            f.AddPathCommand(3, 'wR', 'h', 'stAng2', 'swAng2');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(2, 'x6', 't');
            f.AddPathCommand(2, 'x8', 'y1');
            f.AddPathCommand(2, 'x7', 'y1');
            f.AddPathCommand(3, 'wR', 'h', 'stAng3', 'swAng');
            f.AddPathCommand(2, 'wR', 'b');
            f.AddPathCommand(3, 'wR', 'h', 'cd4', 'cd4');
            f.AddPathCommand(2, 'th', 't');
            f.AddPathCommand(3, 'wR', 'h', 'cd2', '-5400000');
            break;
        }
        case 'decagon':{
            f.AddAdj('vf', 15, '105146');
            f.AddGuide('shd2', 0, 'hd2', 'vf', '100000');
            f.AddGuide('dx1', 7, 'wd2', '2160000');
            f.AddGuide('dx2', 7, 'wd2', '4320000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'hc', 'dx2', '0');
            f.AddGuide('x4', 1, 'hc', 'dx1', '0');
            f.AddGuide('dy1', 12, 'shd2', '4320000');
            f.AddGuide('dy2', 12, 'shd2', '2160000');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y2', 1, 'vc', '0', 'dy2');
            f.AddGuide('y3', 1, 'vc', 'dy2', '0');
            f.AddGuide('y4', 1, 'vc', 'dy1', '0');
            f.AddCnx('0', 'x4', 'y2');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('0', 'x4', 'y3');
            f.AddCnx('cd4', 'x3', 'y4');
            f.AddCnx('cd4', 'x2', 'y4');
            f.AddCnx('cd2', 'x1', 'y3');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd2', 'x1', 'y2');
            f.AddCnx('_3cd4', 'x2', 'y1');
            f.AddCnx('_3cd4', 'x3', 'y1');
            f.AddRect('x1', 'y2', 'x4', 'y3');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(2, 'x4', 'y2');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'x4', 'y3');
            f.AddPathCommand(2, 'x3', 'y4');
            f.AddPathCommand(2, 'x2', 'y4');
            f.AddPathCommand(2, 'x1', 'y3');
            f.AddPathCommand(6);
            break;
        }
        case 'diagStripe':{
            f.AddAdj('adj', 15, '50000');
            f.AddGuide('a', 10, '0', 'adj', '100000');
            f.AddGuide('x2', 0, 'w', 'a', '100000');
            f.AddGuide('x1', 0, 'x2', '1', '2');
            f.AddGuide('x3', 2, 'x2', 'r', '2');
            f.AddGuide('y2', 0, 'h', 'a', '100000');
            f.AddGuide('y1', 0, 'y2', '1', '2');
            f.AddGuide('y3', 2, 'y2', 'b', '2');
            f.AddHandleXY(undefined, '0', '0','adj','0','100000', 'l', 'y2');
            f.AddCnx('0', 'hc', 'vc');
            f.AddCnx('cd2', 'l', 'y3');
            f.AddCnx('cd2', 'x1', 'y1');
            f.AddCnx('_3cd4', 'x3', 't');
            f.AddRect('l', 't', 'x3', 'y3');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y2');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'diamond':{
            f.AddGuide('ir', 0, 'w', '3', '4');
            f.AddGuide('ib', 0, 'h', '3', '4');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('wd4', 'hd4', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'dodecagon':{
            f.AddGuide('x1', 0, 'w', '2894', '21600');
            f.AddGuide('x2', 0, 'w', '7906', '21600');
            f.AddGuide('x3', 0, 'w', '13694', '21600');
            f.AddGuide('x4', 0, 'w', '18706', '21600');
            f.AddGuide('y1', 0, 'h', '2894', '21600');
            f.AddGuide('y2', 0, 'h', '7906', '21600');
            f.AddGuide('y3', 0, 'h', '13694', '21600');
            f.AddGuide('y4', 0, 'h', '18706', '21600');
            f.AddCnx('0', 'x4', 'y1');
            f.AddCnx('0', 'r', 'y2');
            f.AddCnx('0', 'r', 'y3');
            f.AddCnx('0', 'x4', 'y4');
            f.AddCnx('cd4', 'x3', 'b');
            f.AddCnx('cd4', 'x2', 'b');
            f.AddCnx('cd2', 'x1', 'y4');
            f.AddCnx('cd2', 'l', 'y3');
            f.AddCnx('cd2', 'l', 'y2');
            f.AddCnx('cd2', 'x1', 'y1');
            f.AddCnx('_3cd4', 'x2', 't');
            f.AddCnx('_3cd4', 'x3', 't');
            f.AddRect('x1', 'y1', 'x4', 'y4');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y2');
            f.AddPathCommand(2, 'x1', 'y1');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'x3', 't');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(2, 'r', 'y3');
            f.AddPathCommand(2, 'x4', 'y4');
            f.AddPathCommand(2, 'x3', 'b');
            f.AddPathCommand(2, 'x2', 'b');
            f.AddPathCommand(2, 'x1', 'y4');
            f.AddPathCommand(2, 'l', 'y3');
            f.AddPathCommand(6);
            break;
        }
        case 'donut':{
            f.AddAdj('adj', 15, '25000');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('dr', 0, 'ss', 'a', '100000');
            f.AddGuide('iwd2', 1, 'wd2', '0', 'dr');
            f.AddGuide('ihd2', 1, 'hd2', '0', 'dr');
            f.AddGuide('idx', 7, 'wd2', '2700000');
            f.AddGuide('idy', 12, 'hd2', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddHandlePolar(undefined, '0', '0','adj','0','50000', 'dr', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('_3cd4', 'il', 'it');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'il', 'ib');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd4', 'ir', 'ib');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('_3cd4', 'ir', 'it');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd2', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '_3cd4', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '0', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd4', 'cd4');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'dr', 'vc');
            f.AddPathCommand(3, 'iwd2', 'ihd2', 'cd2', '-5400000');
            f.AddPathCommand(3, 'iwd2', 'ihd2', 'cd4', '-5400000');
            f.AddPathCommand(3, 'iwd2', 'ihd2', '0', '-5400000');
            f.AddPathCommand(3, 'iwd2', 'ihd2', '_3cd4', '-5400000');
            f.AddPathCommand(6);
            break;
        }
        case 'doubleWave':{
            f.AddAdj('adj1', 15, '6250');
            f.AddAdj('adj2', 15, '0');
            f.AddGuide('a1', 10, '0', 'adj1', '12500');
            f.AddGuide('a2', 10, '-10000', 'adj2', '10000');
            f.AddGuide('y1', 0, 'h', 'a1', '100000');
            f.AddGuide('dy2', 0, 'y1', '10', '3');
            f.AddGuide('y2', 1, 'y1', '0', 'dy2');
            f.AddGuide('y3', 1, 'y1', 'dy2', '0');
            f.AddGuide('y4', 1, 'b', '0', 'y1');
            f.AddGuide('y5', 1, 'y4', '0', 'dy2');
            f.AddGuide('y6', 1, 'y4', 'dy2', '0');
            f.AddGuide('dx1', 0, 'w', 'a2', '100000');
            f.AddGuide('of2', 0, 'w', 'a2', '50000');
            f.AddGuide('x1', 4, 'dx1');
            f.AddGuide('dx2', 3, 'of2', '0', 'of2');
            f.AddGuide('x2', 1, 'l', '0', 'dx2');
            f.AddGuide('dx8', 3, 'of2', 'of2', '0');
            f.AddGuide('x8', 1, 'r', '0', 'dx8');
            f.AddGuide('dx3', 2, 'dx2', 'x8', '6');
            f.AddGuide('x3', 1, 'x2', 'dx3', '0');
            f.AddGuide('dx4', 2, 'dx2', 'x8', '3');
            f.AddGuide('x4', 1, 'x2', 'dx4', '0');
            f.AddGuide('x5', 2, 'x2', 'x8', '2');
            f.AddGuide('x6', 1, 'x5', 'dx3', '0');
            f.AddGuide('x7', 2, 'x6', 'x8', '2');
            f.AddGuide('x9', 1, 'l', 'dx8', '0');
            f.AddGuide('x15', 1, 'r', 'dx2', '0');
            f.AddGuide('x10', 1, 'x9', 'dx3', '0');
            f.AddGuide('x11', 1, 'x9', 'dx4', '0');
            f.AddGuide('x12', 2, 'x9', 'x15', '2');
            f.AddGuide('x13', 1, 'x12', 'dx3', '0');
            f.AddGuide('x14', 2, 'x13', 'x15', '2');
            f.AddGuide('x16', 1, 'r', '0', 'x1');
            f.AddGuide('xAdj', 1, 'hc', 'dx1', '0');
            f.AddGuide('il', 8, 'x2', 'x9');
            f.AddGuide('ir', 16, 'x8', 'x15');
            f.AddGuide('it', 0, 'h', 'a1', '50000');
            f.AddGuide('ib', 1, 'b', '0', 'it');
            f.AddHandleXY(undefined, '0', '0','adj1','0','12500', 'l', 'y1');
            f.AddHandleXY('adj2','-10000','10000', undefined, '0', '0', 'xAdj', 'b');
            f.AddCnx('cd4', 'x12', 'y1');
            f.AddCnx('cd2', 'x1', 'vc');
            f.AddCnx('_3cd4', 'x5', 'y4');
            f.AddCnx('0', 'x16', 'vc');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x2', 'y1');
            f.AddPathCommand(5, 'x3', 'y2', 'x4', 'y3', 'x5', 'y1');
            f.AddPathCommand(5, 'x6', 'y2', 'x7', 'y3', 'x8', 'y1');
            f.AddPathCommand(2, 'x15', 'y4');
            f.AddPathCommand(5, 'x14', 'y6', 'x13', 'y5', 'x12', 'y4');
            f.AddPathCommand(5, 'x11', 'y6', 'x10', 'y5', 'x9', 'y4');
            f.AddPathCommand(6);
            break;
        }
        case 'downArrow':{
            f.AddAdj('adj1', 15, '50000');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('maxAdj2', 0, '100000', 'h', 'ss');
            f.AddGuide('a1', 10, '0', 'adj1', '100000');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('dy1', 0, 'ss', 'a2', '100000');
            f.AddGuide('y1', 1, 'b', '0', 'dy1');
            f.AddGuide('dx1', 0, 'w', 'a1', '200000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', 'dx1', '0');
            f.AddGuide('dy2', 0, 'x1', 'dy1', 'wd2');
            f.AddGuide('y2', 1, 'y1', 'dy2', '0');
            f.AddHandleXY('adj1','0','100000', undefined, '0', '0', 'x1', 't');
            f.AddHandleXY(undefined, '0', '0','adj2','0','maxAdj2', 'l', 'y1');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'y1');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'y1');
            f.AddRect('x1', 't', 'x2', 'y2');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(2, 'x1', 'y1');
            f.AddPathCommand(2, 'x1', 't');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'r', 'y1');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'downArrowCallout':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '25000');
            f.AddAdj('adj3', 15, '25000');
            f.AddAdj('adj4', 15, '64977');
            f.AddGuide('maxAdj2', 0, '50000', 'w', 'ss');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('maxAdj1', 0, 'a2', '2', '1');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('maxAdj3', 0, '100000', 'h', 'ss');
            f.AddGuide('a3', 10, '0', 'adj3', 'maxAdj3');
            f.AddGuide('q2', 0, 'a3', 'ss', 'h');
            f.AddGuide('maxAdj4', 1, '100000', '0', 'q2');
            f.AddGuide('a4', 10, '0', 'adj4', 'maxAdj4');
            f.AddGuide('dx1', 0, 'ss', 'a2', '100000');
            f.AddGuide('dx2', 0, 'ss', 'a1', '200000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'hc', 'dx2', '0');
            f.AddGuide('x4', 1, 'hc', 'dx1', '0');
            f.AddGuide('dy3', 0, 'ss', 'a3', '100000');
            f.AddGuide('y3', 1, 'b', '0', 'dy3');
            f.AddGuide('y2', 0, 'h', 'a4', '100000');
            f.AddGuide('y1', 0, 'y2', '1', '2');
            f.AddHandleXY('adj1','0','maxAdj1', undefined, '0', '0', 'x2', 'y3');
            f.AddHandleXY('adj2','0','maxAdj2', undefined, '0', '0', 'x1', 'b');
            f.AddHandleXY(undefined, '0', '0','adj3','0','maxAdj3', 'r', 'y3');
            f.AddHandleXY(undefined, '0', '0','adj4','0','maxAdj4', 'l', 'y2');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'y1');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'y1');
            f.AddRect('l', 't', 'r', 'y2');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(2, 'x3', 'y2');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(2, 'x4', 'y3');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(2, 'x1', 'y3');
            f.AddPathCommand(2, 'x2', 'y3');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'l', 'y2');
            f.AddPathCommand(6);
            break;
        }
        case 'ellipse':{
            f.AddGuide('idx', 7, 'wd2', '2700000');
            f.AddGuide('idy', 12, 'hd2', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('_3cd4', 'il', 'it');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'il', 'ib');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd4', 'ir', 'ib');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('_3cd4', 'ir', 'it');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd2', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '_3cd4', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '0', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd4', 'cd4');
            f.AddPathCommand(6);
            break;
        }
        case 'ellipseRibbon':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '50000');
            f.AddAdj('adj3', 15, '12500');
            f.AddGuide('a1', 10, '0', 'adj1', '100000');
            f.AddGuide('a2', 10, '25000', 'adj2', '75000');
            f.AddGuide('q10', 1, '100000', '0', 'a1');
            f.AddGuide('q11', 0, 'q10', '1', '2');
            f.AddGuide('q12', 1, 'a1', '0', 'q11');
            f.AddGuide('minAdj3', 8, '0', 'q12');
            f.AddGuide('a3', 10, 'minAdj3', 'adj3', 'a1');
            f.AddGuide('dx2', 0, 'w', 'a2', '200000');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'x2', 'wd8', '0');
            f.AddGuide('x4', 1, 'r', '0', 'x3');
            f.AddGuide('x5', 1, 'r', '0', 'x2');
            f.AddGuide('x6', 1, 'r', '0', 'wd8');
            f.AddGuide('dy1', 0, 'h', 'a3', '100000');
            f.AddGuide('f1', 0, '4', 'dy1', 'w');
            f.AddGuide('q1', 0, 'x3', 'x3', 'w');
            f.AddGuide('q2', 1, 'x3', '0', 'q1');
            f.AddGuide('y1', 0, 'f1', 'q2', '1');
            f.AddGuide('cx1', 0, 'x3', '1', '2');
            f.AddGuide('cy1', 0, 'f1', 'cx1', '1');
            f.AddGuide('cx2', 1, 'r', '0', 'cx1');
            f.AddGuide('q1', 0, 'h', 'a1', '100000');
            f.AddGuide('dy3', 1, 'q1', '0', 'dy1');
            f.AddGuide('q3', 0, 'x2', 'x2', 'w');
            f.AddGuide('q4', 1, 'x2', '0', 'q3');
            f.AddGuide('q5', 0, 'f1', 'q4', '1');
            f.AddGuide('y3', 1, 'q5', 'dy3', '0');
            f.AddGuide('q6', 1, 'dy1', 'dy3', 'y3');
            f.AddGuide('q7', 1, 'q6', 'dy1', '0');
            f.AddGuide('cy3', 1, 'q7', 'dy3', '0');
            f.AddGuide('rh', 1, 'b', '0', 'q1');
            f.AddGuide('q8', 0, 'dy1', '14', '16');
            f.AddGuide('y2', 2, 'q8', 'rh', '2');
            f.AddGuide('y5', 1, 'q5', 'rh', '0');
            f.AddGuide('y6', 1, 'y3', 'rh', '0');
            f.AddGuide('cx4', 0, 'x2', '1', '2');
            f.AddGuide('q9', 0, 'f1', 'cx4', '1');
            f.AddGuide('cy4', 1, 'q9', 'rh', '0');
            f.AddGuide('cx5', 1, 'r', '0', 'cx4');
            f.AddGuide('cy6', 1, 'cy3', 'rh', '0');
            f.AddGuide('y7', 1, 'y1', 'dy3', '0');
            f.AddGuide('cy7', 1, 'q1', 'q1', 'y7');
            f.AddGuide('y8', 1, 'b', '0', 'dy1');
            f.AddHandleXY(undefined, '0', '0','adj1','0','100000', 'hc', 'q1');
            f.AddHandleXY('adj2','25000','75000', undefined, '0', '0', 'x2', 'b');
            f.AddHandleXY(undefined, '0', '0','adj3','minAdj3','a1', 'l', 'y8');
            f.AddCnx('_3cd4', 'hc', 'q1');
            f.AddCnx('cd2', 'wd8', 'y2');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'x6', 'y2');
            f.AddRect('x2', 'q1', 'x5', 'y6');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(4, 'cx1', 'cy1', 'x3', 'y1');
            f.AddPathCommand(2, 'x2', 'y3');
            f.AddPathCommand(4, 'hc', 'cy3', 'x5', 'y3');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(4, 'cx2', 'cy1', 'r', 't');
            f.AddPathCommand(2, 'x6', 'y2');
            f.AddPathCommand(2, 'r', 'rh');
            f.AddPathCommand(4, 'cx5', 'cy4', 'x5', 'y5');
            f.AddPathCommand(2, 'x5', 'y6');
            f.AddPathCommand(4, 'hc', 'cy6', 'x2', 'y6');
            f.AddPathCommand(2, 'x2', 'y5');
            f.AddPathCommand(4, 'cx4', 'cy4', 'l', 'rh');
            f.AddPathCommand(2, 'wd8', 'y2');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'x3', 'y7');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(2, 'x2', 'y3');
            f.AddPathCommand(4, 'hc', 'cy3', 'x5', 'y3');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(2, 'x4', 'y7');
            f.AddPathCommand(4, 'hc', 'cy7', 'x3', 'y7');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(4, 'cx1', 'cy1', 'x3', 'y1');
            f.AddPathCommand(2, 'x2', 'y3');
            f.AddPathCommand(4, 'hc', 'cy3', 'x5', 'y3');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(4, 'cx2', 'cy1', 'r', 't');
            f.AddPathCommand(2, 'x6', 'y2');
            f.AddPathCommand(2, 'r', 'rh');
            f.AddPathCommand(4, 'cx5', 'cy4', 'x5', 'y5');
            f.AddPathCommand(2, 'x5', 'y6');
            f.AddPathCommand(4, 'hc', 'cy6', 'x2', 'y6');
            f.AddPathCommand(2, 'x2', 'y5');
            f.AddPathCommand(4, 'cx4', 'cy4', 'l', 'rh');
            f.AddPathCommand(2, 'wd8', 'y2');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x2', 'y5');
            f.AddPathCommand(2, 'x2', 'y3');
            f.AddPathCommand(1, 'x5', 'y3');
            f.AddPathCommand(2, 'x5', 'y5');
            f.AddPathCommand(1, 'x3', 'y1');
            f.AddPathCommand(2, 'x3', 'y7');
            f.AddPathCommand(1, 'x4', 'y7');
            f.AddPathCommand(2, 'x4', 'y1');
            break;
        }
        case 'ellipseRibbon2':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '50000');
            f.AddAdj('adj3', 15, '12500');
            f.AddGuide('a1', 10, '0', 'adj1', '100000');
            f.AddGuide('a2', 10, '25000', 'adj2', '75000');
            f.AddGuide('q10', 1, '100000', '0', 'a1');
            f.AddGuide('q11', 0, 'q10', '1', '2');
            f.AddGuide('q12', 1, 'a1', '0', 'q11');
            f.AddGuide('minAdj3', 8, '0', 'q12');
            f.AddGuide('a3', 10, 'minAdj3', 'adj3', 'a1');
            f.AddGuide('dx2', 0, 'w', 'a2', '200000');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'x2', 'wd8', '0');
            f.AddGuide('x4', 1, 'r', '0', 'x3');
            f.AddGuide('x5', 1, 'r', '0', 'x2');
            f.AddGuide('x6', 1, 'r', '0', 'wd8');
            f.AddGuide('dy1', 0, 'h', 'a3', '100000');
            f.AddGuide('f1', 0, '4', 'dy1', 'w');
            f.AddGuide('q1', 0, 'x3', 'x3', 'w');
            f.AddGuide('q2', 1, 'x3', '0', 'q1');
            f.AddGuide('u1', 0, 'f1', 'q2', '1');
            f.AddGuide('y1', 1, 'b', '0', 'u1');
            f.AddGuide('cx1', 0, 'x3', '1', '2');
            f.AddGuide('cu1', 0, 'f1', 'cx1', '1');
            f.AddGuide('cy1', 1, 'b', '0', 'cu1');
            f.AddGuide('cx2', 1, 'r', '0', 'cx1');
            f.AddGuide('q1', 0, 'h', 'a1', '100000');
            f.AddGuide('dy3', 1, 'q1', '0', 'dy1');
            f.AddGuide('q3', 0, 'x2', 'x2', 'w');
            f.AddGuide('q4', 1, 'x2', '0', 'q3');
            f.AddGuide('q5', 0, 'f1', 'q4', '1');
            f.AddGuide('u3', 1, 'q5', 'dy3', '0');
            f.AddGuide('y3', 1, 'b', '0', 'u3');
            f.AddGuide('q6', 1, 'dy1', 'dy3', 'u3');
            f.AddGuide('q7', 1, 'q6', 'dy1', '0');
            f.AddGuide('cu3', 1, 'q7', 'dy3', '0');
            f.AddGuide('cy3', 1, 'b', '0', 'cu3');
            f.AddGuide('rh', 1, 'b', '0', 'q1');
            f.AddGuide('q8', 0, 'dy1', '14', '16');
            f.AddGuide('u2', 2, 'q8', 'rh', '2');
            f.AddGuide('y2', 1, 'b', '0', 'u2');
            f.AddGuide('u5', 1, 'q5', 'rh', '0');
            f.AddGuide('y5', 1, 'b', '0', 'u5');
            f.AddGuide('u6', 1, 'u3', 'rh', '0');
            f.AddGuide('y6', 1, 'b', '0', 'u6');
            f.AddGuide('cx4', 0, 'x2', '1', '2');
            f.AddGuide('q9', 0, 'f1', 'cx4', '1');
            f.AddGuide('cu4', 1, 'q9', 'rh', '0');
            f.AddGuide('cy4', 1, 'b', '0', 'cu4');
            f.AddGuide('cx5', 1, 'r', '0', 'cx4');
            f.AddGuide('cu6', 1, 'cu3', 'rh', '0');
            f.AddGuide('cy6', 1, 'b', '0', 'cu6');
            f.AddGuide('u7', 1, 'u1', 'dy3', '0');
            f.AddGuide('y7', 1, 'b', '0', 'u7');
            f.AddGuide('cu7', 1, 'q1', 'q1', 'u7');
            f.AddGuide('cy7', 1, 'b', '0', 'cu7');
            f.AddHandleXY(undefined, '0', '0','adj1','0','100000', 'hc', 'rh');
            f.AddHandleXY('adj2','25000','100000', undefined, '0', '0', 'x2', 't');
            f.AddHandleXY(undefined, '0', '0','adj3','minAdj3','a1', 'l', 'dy1');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'wd8', 'y2');
            f.AddCnx('cd4', 'hc', 'rh');
            f.AddCnx('0', 'x6', 'y2');
            f.AddRect('x2', 'y6', 'x5', 'rh');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(4, 'cx1', 'cy1', 'x3', 'y1');
            f.AddPathCommand(2, 'x2', 'y3');
            f.AddPathCommand(4, 'hc', 'cy3', 'x5', 'y3');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(4, 'cx2', 'cy1', 'r', 'b');
            f.AddPathCommand(2, 'x6', 'y2');
            f.AddPathCommand(2, 'r', 'q1');
            f.AddPathCommand(4, 'cx5', 'cy4', 'x5', 'y5');
            f.AddPathCommand(2, 'x5', 'y6');
            f.AddPathCommand(4, 'hc', 'cy6', 'x2', 'y6');
            f.AddPathCommand(2, 'x2', 'y5');
            f.AddPathCommand(4, 'cx4', 'cy4', 'l', 'q1');
            f.AddPathCommand(2, 'wd8', 'y2');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'x3', 'y7');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(2, 'x2', 'y3');
            f.AddPathCommand(4, 'hc', 'cy3', 'x5', 'y3');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(2, 'x4', 'y7');
            f.AddPathCommand(4, 'hc', 'cy7', 'x3', 'y7');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'wd8', 'y2');
            f.AddPathCommand(2, 'l', 'q1');
            f.AddPathCommand(4, 'cx4', 'cy4', 'x2', 'y5');
            f.AddPathCommand(2, 'x2', 'y6');
            f.AddPathCommand(4, 'hc', 'cy6', 'x5', 'y6');
            f.AddPathCommand(2, 'x5', 'y5');
            f.AddPathCommand(4, 'cx5', 'cy4', 'r', 'q1');
            f.AddPathCommand(2, 'x6', 'y2');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(4, 'cx2', 'cy1', 'x4', 'y1');
            f.AddPathCommand(2, 'x5', 'y3');
            f.AddPathCommand(4, 'hc', 'cy3', 'x2', 'y3');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(4, 'cx1', 'cy1', 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x2', 'y3');
            f.AddPathCommand(2, 'x2', 'y5');
            f.AddPathCommand(1, 'x5', 'y5');
            f.AddPathCommand(2, 'x5', 'y3');
            f.AddPathCommand(1, 'x3', 'y7');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(1, 'x4', 'y1');
            f.AddPathCommand(2, 'x4', 'y7');
            break;
        }
        case 'flowChartAlternateProcess':{
            f.AddGuide('x2', 1, 'r', '0', 'ssd6');
            f.AddGuide('y2', 1, 'b', '0', 'ssd6');
            f.AddGuide('il', 0, 'ssd6', '29289', '100000');
            f.AddGuide('ir', 1, 'r', '0', 'il');
            f.AddGuide('ib', 1, 'b', '0', 'il');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('il', 'il', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'ssd6');
            f.AddPathCommand(3, 'ssd6', 'ssd6', 'cd2', 'cd4');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(3, 'ssd6', 'ssd6', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(3, 'ssd6', 'ssd6', '0', 'cd4');
            f.AddPathCommand(2, 'ssd6', 'b');
            f.AddPathCommand(3, 'ssd6', 'ssd6', 'cd4', 'cd4');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartCollate':{
            f.AddGuide('ir', 0, 'w', '3', '4');
            f.AddGuide('ib', 0, 'h', '3', '4');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('_3cd4', 'hc', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddRect('wd4', 'hd4', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, 2, 2);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '2', '0');
            f.AddPathCommand(2, '1', '1');
            f.AddPathCommand(2, '2', '2');
            f.AddPathCommand(2, '0', '2');
            f.AddPathCommand(2, '1', '1');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartConnector':{
            f.AddGuide('idx', 7, 'wd2', '2700000');
            f.AddGuide('idy', 12, 'hd2', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('_3cd4', 'il', 'it');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'il', 'ib');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd4', 'ir', 'ib');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('_3cd4', 'ir', 'it');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd2', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '_3cd4', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '0', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd4', 'cd4');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartDecision':{
            f.AddGuide('ir', 0, 'w', '3', '4');
            f.AddGuide('ib', 0, 'h', '3', '4');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('wd4', 'hd4', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, 2, 2);
            f.AddPathCommand(1, '0', '1');
            f.AddPathCommand(2, '1', '0');
            f.AddPathCommand(2, '2', '1');
            f.AddPathCommand(2, '1', '2');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartDelay':{
            f.AddGuide('idx', 7, 'wd2', '2700000');
            f.AddGuide('idy', 12, 'hd2', '2700000');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(3, 'wd2', 'hd2', '_3cd4', 'cd2');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartDisplay':{
            f.AddGuide('x2', 0, 'w', '5', '6');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('wd6', 't', 'x2', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, 6, 6);
            f.AddPathCommand(1, '0', '3');
            f.AddPathCommand(2, '1', '0');
            f.AddPathCommand(2, '5', '0');
            f.AddPathCommand(3, '1', '3', '_3cd4', 'cd2');
            f.AddPathCommand(2, '1', '6');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartDocument':{
            f.AddGuide('y1', 0, 'h', '17322', '21600');
            f.AddGuide('y2', 0, 'h', '20172', '21600');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'y2');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 't', 'r', 'y1');
            f.AddPathCommand(0,undefined, undefined, undefined, 21600, 21600);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '21600', '0');
            f.AddPathCommand(2, '21600', '17322');
            f.AddPathCommand(5, '10800', '17322', '10800', '23922', '0', '20172');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartExtract':{
            f.AddGuide('x2', 0, 'w', '3', '4');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'wd4', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'x2', 'vc');
            f.AddRect('wd4', 'vc', 'x2', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, 2, 2);
            f.AddPathCommand(1, '0', '2');
            f.AddPathCommand(2, '1', '0');
            f.AddPathCommand(2, '2', '2');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartInputOutput':{
            f.AddGuide('x3', 0, 'w', '2', '5');
            f.AddGuide('x4', 0, 'w', '3', '5');
            f.AddGuide('x5', 0, 'w', '4', '5');
            f.AddGuide('x6', 0, 'w', '9', '10');
            f.AddCnx('_3cd4', 'x4', 't');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'wd10', 'vc');
            f.AddCnx('cd4', 'x3', 'b');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'x6', 'vc');
            f.AddRect('wd5', 't', 'x5', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, 5, 5);
            f.AddPathCommand(1, '0', '5');
            f.AddPathCommand(2, '1', '0');
            f.AddPathCommand(2, '5', '0');
            f.AddPathCommand(2, '4', '5');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartInternalStorage':{
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('wd8', 'hd8', 'r', 'b');
            f.AddPathCommand(0,false, undefined, false, 1, 1);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '1', '0');
            f.AddPathCommand(2, '1', '1');
            f.AddPathCommand(2, '0', '1');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, 8, 8);
            f.AddPathCommand(1, '1', '0');
            f.AddPathCommand(2, '1', '8');
            f.AddPathCommand(1, '0', '1');
            f.AddPathCommand(2, '8', '1');
            f.AddPathCommand(0,undefined, 'none', undefined, 1, 1);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '1', '0');
            f.AddPathCommand(2, '1', '1');
            f.AddPathCommand(2, '0', '1');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartMagneticDisk':{
            f.AddGuide('y3', 0, 'h', '5', '6');
            f.AddCnx('_3cd4', 'hc', 'hd3');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 'hd3', 'r', 'y3');
            f.AddPathCommand(0,false, undefined, false, 6, 6);
            f.AddPathCommand(1, '0', '1');
            f.AddPathCommand(3, '3', '1', 'cd2', 'cd2');
            f.AddPathCommand(2, '6', '5');
            f.AddPathCommand(3, '3', '1', '0', 'cd2');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, 6, 6);
            f.AddPathCommand(1, '6', '1');
            f.AddPathCommand(3, '3', '1', '0', 'cd2');
            f.AddPathCommand(0,undefined, 'none', undefined, 6, 6);
            f.AddPathCommand(1, '0', '1');
            f.AddPathCommand(3, '3', '1', 'cd2', 'cd2');
            f.AddPathCommand(2, '6', '5');
            f.AddPathCommand(3, '3', '1', '0', 'cd2');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartMagneticDrum':{
            f.AddGuide('x2', 0, 'w', '2', '3');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'x2', 'vc');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('wd6', 't', 'x2', 'b');
            f.AddPathCommand(0,false, undefined, false, 6, 6);
            f.AddPathCommand(1, '1', '0');
            f.AddPathCommand(2, '5', '0');
            f.AddPathCommand(3, '1', '3', '_3cd4', 'cd2');
            f.AddPathCommand(2, '1', '6');
            f.AddPathCommand(3, '1', '3', 'cd4', 'cd2');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, 6, 6);
            f.AddPathCommand(1, '5', '6');
            f.AddPathCommand(3, '1', '3', 'cd4', 'cd2');
            f.AddPathCommand(0,undefined, 'none', undefined, 6, 6);
            f.AddPathCommand(1, '1', '0');
            f.AddPathCommand(2, '5', '0');
            f.AddPathCommand(3, '1', '3', '_3cd4', 'cd2');
            f.AddPathCommand(2, '1', '6');
            f.AddPathCommand(3, '1', '3', 'cd4', 'cd2');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartMagneticTape':{
            f.AddGuide('idx', 7, 'wd2', '2700000');
            f.AddGuide('idy', 12, 'hd2', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddGuide('ang1', 5, '1', '1');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'hc', 'b');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd4', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd2', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '_3cd4', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '0', 'ang1');
            f.AddPathCommand(2, 'r', 'ib');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartManualInput':{
            f.AddCnx('_3cd4', 'hc', 'hd10');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 'hd5', 'r', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, 5, 5);
            f.AddPathCommand(1, '0', '1');
            f.AddPathCommand(2, '5', '0');
            f.AddPathCommand(2, '5', '5');
            f.AddPathCommand(2, '0', '5');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartManualOperation':{
            f.AddGuide('x3', 0, 'w', '4', '5');
            f.AddGuide('x4', 0, 'w', '9', '10');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'wd10', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'x4', 'vc');
            f.AddRect('wd5', 't', 'x3', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, 5, 5);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '5', '0');
            f.AddPathCommand(2, '4', '5');
            f.AddPathCommand(2, '1', '5');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartMerge':{
            f.AddGuide('x2', 0, 'w', '3', '4');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'wd4', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'x2', 'vc');
            f.AddRect('wd4', 't', 'x2', 'vc');
            f.AddPathCommand(0,undefined, undefined, undefined, 2, 2);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '2', '0');
            f.AddPathCommand(2, '1', '2');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartMultidocument':{
            f.AddGuide('y2', 0, 'h', '3675', '21600');
            f.AddGuide('y8', 0, 'h', '20782', '21600');
            f.AddGuide('x3', 0, 'w', '9298', '21600');
            f.AddGuide('x4', 0, 'w', '12286', '21600');
            f.AddGuide('x5', 0, 'w', '18595', '21600');
            f.AddCnx('_3cd4', 'x4', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'x3', 'y8');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 'y2', 'x5', 'y8');
            f.AddPathCommand(0,false, undefined, false, 21600, 21600);
            f.AddPathCommand(1, '0', '20782');
            f.AddPathCommand(5, '9298', '23542', '9298', '18022', '18595', '18022');
            f.AddPathCommand(2, '18595', '3675');
            f.AddPathCommand(2, '0', '3675');
            f.AddPathCommand(6);
            f.AddPathCommand(1, '1532', '3675');
            f.AddPathCommand(2, '1532', '1815');
            f.AddPathCommand(2, '20000', '1815');
            f.AddPathCommand(2, '20000', '16252');
            f.AddPathCommand(5, '19298', '16252', '18595', '16352', '18595', '16352');
            f.AddPathCommand(2, '18595', '3675');
            f.AddPathCommand(6);
            f.AddPathCommand(1, '2972', '1815');
            f.AddPathCommand(2, '2972', '0');
            f.AddPathCommand(2, '21600', '0');
            f.AddPathCommand(2, '21600', '14392');
            f.AddPathCommand(5, '20800', '14392', '20000', '14467', '20000', '14467');
            f.AddPathCommand(2, '20000', '1815');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, 21600, 21600);
            f.AddPathCommand(1, '0', '3675');
            f.AddPathCommand(2, '18595', '3675');
            f.AddPathCommand(2, '18595', '18022');
            f.AddPathCommand(5, '9298', '18022', '9298', '23542', '0', '20782');
            f.AddPathCommand(6);
            f.AddPathCommand(1, '1532', '3675');
            f.AddPathCommand(2, '1532', '1815');
            f.AddPathCommand(2, '20000', '1815');
            f.AddPathCommand(2, '20000', '16252');
            f.AddPathCommand(5, '19298', '16252', '18595', '16352', '18595', '16352');
            f.AddPathCommand(1, '2972', '1815');
            f.AddPathCommand(2, '2972', '0');
            f.AddPathCommand(2, '21600', '0');
            f.AddPathCommand(2, '21600', '14392');
            f.AddPathCommand(5, '20800', '14392', '20000', '14467', '20000', '14467');
            f.AddPathCommand(0,undefined, 'none', false, 21600, 21600);
            f.AddPathCommand(1, '0', '20782');
            f.AddPathCommand(5, '9298', '23542', '9298', '18022', '18595', '18022');
            f.AddPathCommand(2, '18595', '16352');
            f.AddPathCommand(5, '18595', '16352', '19298', '16252', '20000', '16252');
            f.AddPathCommand(2, '20000', '14467');
            f.AddPathCommand(5, '20000', '14467', '20800', '14392', '21600', '14392');
            f.AddPathCommand(2, '21600', '0');
            f.AddPathCommand(2, '2972', '0');
            f.AddPathCommand(2, '2972', '1815');
            f.AddPathCommand(2, '1532', '1815');
            f.AddPathCommand(2, '1532', '3675');
            f.AddPathCommand(2, '0', '3675');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartOfflineStorage':{
            f.AddGuide('x4', 0, 'w', '3', '4');
            f.AddCnx('0', 'x4', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'wd4', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('wd4', 't', 'x4', 'vc');
            f.AddPathCommand(0,false, undefined, false, 2, 2);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '2', '0');
            f.AddPathCommand(2, '1', '2');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, 5, 5);
            f.AddPathCommand(1, '2', '4');
            f.AddPathCommand(2, '3', '4');
            f.AddPathCommand(0,true, 'none', undefined, 2, 2);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '2', '0');
            f.AddPathCommand(2, '1', '2');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartOffpageConnector':{
            f.AddGuide('y1', 0, 'h', '4', '5');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 't', 'r', 'y1');
            f.AddPathCommand(0,undefined, undefined, undefined, 10, 10);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '10', '0');
            f.AddPathCommand(2, '10', '8');
            f.AddPathCommand(2, '5', '10');
            f.AddPathCommand(2, '0', '8');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartOnlineStorage':{
            f.AddGuide('x2', 0, 'w', '5', '6');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'x2', 'vc');
            f.AddRect('wd6', 't', 'x2', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, 6, 6);
            f.AddPathCommand(1, '1', '0');
            f.AddPathCommand(2, '6', '0');
            f.AddPathCommand(3, '1', '3', '_3cd4', '-10800000');
            f.AddPathCommand(2, '1', '6');
            f.AddPathCommand(3, '1', '3', 'cd4', 'cd2');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartOr':{
            f.AddGuide('idx', 7, 'wd2', '2700000');
            f.AddGuide('idy', 12, 'hd2', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('_3cd4', 'il', 'it');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'il', 'ib');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd4', 'ir', 'ib');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('_3cd4', 'ir', 'it');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd2', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '_3cd4', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '0', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd4', 'cd4');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'hc', 't');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd2', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '_3cd4', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '0', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd4', 'cd4');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartPredefinedProcess':{
            f.AddGuide('x2', 0, 'w', '7', '8');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('wd8', 't', 'x2', 'b');
            f.AddPathCommand(0,false, undefined, false, 1, 1);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '1', '0');
            f.AddPathCommand(2, '1', '1');
            f.AddPathCommand(2, '0', '1');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, 8, 8);
            f.AddPathCommand(1, '1', '0');
            f.AddPathCommand(2, '1', '8');
            f.AddPathCommand(1, '7', '0');
            f.AddPathCommand(2, '7', '8');
            f.AddPathCommand(0,undefined, 'none', undefined, 1, 1);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '1', '0');
            f.AddPathCommand(2, '1', '1');
            f.AddPathCommand(2, '0', '1');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartPreparation':{
            f.AddGuide('x2', 0, 'w', '4', '5');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('wd5', 't', 'x2', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, 10, 10);
            f.AddPathCommand(1, '0', '5');
            f.AddPathCommand(2, '2', '0');
            f.AddPathCommand(2, '8', '0');
            f.AddPathCommand(2, '10', '5');
            f.AddPathCommand(2, '8', '10');
            f.AddPathCommand(2, '2', '10');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartProcess':{
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, 1, 1);
            f.AddPathCommand(1, '0', '0');
            f.AddPathCommand(2, '1', '0');
            f.AddPathCommand(2, '1', '1');
            f.AddPathCommand(2, '0', '1');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartPunchedCard':{
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 'hd5', 'r', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, 5, 5);
            f.AddPathCommand(1, '0', '1');
            f.AddPathCommand(2, '1', '0');
            f.AddPathCommand(2, '5', '0');
            f.AddPathCommand(2, '5', '5');
            f.AddPathCommand(2, '0', '5');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartPunchedTape':{
            f.AddGuide('y2', 0, 'h', '9', '10');
            f.AddGuide('ib', 0, 'h', '4', '5');
            f.AddCnx('_3cd4', 'hc', 'hd10');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'y2');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 'hd5', 'r', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, 20, 20);
            f.AddPathCommand(1, '0', '2');
            f.AddPathCommand(3, '5', '2', 'cd2', '-10800000');
            f.AddPathCommand(3, '5', '2', 'cd2', 'cd2');
            f.AddPathCommand(2, '20', '18');
            f.AddPathCommand(3, '5', '2', '0', '-10800000');
            f.AddPathCommand(3, '5', '2', '0', 'cd2');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartSort':{
            f.AddGuide('ir', 0, 'w', '3', '4');
            f.AddGuide('ib', 0, 'h', '3', '4');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('wd4', 'hd4', 'ir', 'ib');
            f.AddPathCommand(0,false, undefined, false, 2, 2);
            f.AddPathCommand(1, '0', '1');
            f.AddPathCommand(2, '1', '0');
            f.AddPathCommand(2, '2', '1');
            f.AddPathCommand(2, '1', '2');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, 2, 2);
            f.AddPathCommand(1, '0', '1');
            f.AddPathCommand(2, '2', '1');
            f.AddPathCommand(0,undefined, 'none', undefined, 2, 2);
            f.AddPathCommand(1, '0', '1');
            f.AddPathCommand(2, '1', '0');
            f.AddPathCommand(2, '2', '1');
            f.AddPathCommand(2, '1', '2');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartSummingJunction':{
            f.AddGuide('idx', 7, 'wd2', '2700000');
            f.AddGuide('idy', 12, 'hd2', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('_3cd4', 'il', 'it');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'il', 'ib');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd4', 'ir', 'ib');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('_3cd4', 'ir', 'it');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd2', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '_3cd4', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '0', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd4', 'cd4');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'il', 'it');
            f.AddPathCommand(2, 'ir', 'ib');
            f.AddPathCommand(1, 'ir', 'it');
            f.AddPathCommand(2, 'il', 'ib');
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd2', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '_3cd4', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '0', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd4', 'cd4');
            f.AddPathCommand(6);
            break;
        }
        case 'flowChartTerminator':{
            f.AddGuide('il', 0, 'w', '1018', '21600');
            f.AddGuide('ir', 0, 'w', '20582', '21600');
            f.AddGuide('it', 0, 'h', '3163', '21600');
            f.AddGuide('ib', 0, 'h', '18437', '21600');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, 21600, 21600);
            f.AddPathCommand(1, '3475', '0');
            f.AddPathCommand(2, '18125', '0');
            f.AddPathCommand(3, '3475', '10800', '_3cd4', 'cd2');
            f.AddPathCommand(2, '3475', '21600');
            f.AddPathCommand(3, '3475', '10800', 'cd4', 'cd2');
            f.AddPathCommand(6);
            break;
        }
        case 'foldedCorner':{
            f.AddAdj('adj', 15, '16667');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('dy2', 0, 'ss', 'a', '100000');
            f.AddGuide('dy1', 0, 'dy2', '1', '5');
            f.AddGuide('x1', 1, 'r', '0', 'dy2');
            f.AddGuide('x2', 1, 'x1', 'dy1', '0');
            f.AddGuide('y2', 1, 'b', '0', 'dy2');
            f.AddGuide('y1', 1, 'y2', 'dy1', '0');
            f.AddHandleXY('adj','0','50000', undefined, '0', '0', 'x1', 'b');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 't', 'r', 'y2');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'b');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'b');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(2, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'y2');
            break;
        }
        case 'frame':{
            f.AddAdj('adj1', 15, '12500');
            f.AddGuide('a1', 10, '0', 'adj1', '50000');
            f.AddGuide('x1', 0, 'ss', 'a1', '100000');
            f.AddGuide('x4', 1, 'r', '0', 'x1');
            f.AddGuide('y4', 1, 'b', '0', 'x1');
            f.AddHandleXY('adj1','0','50000', undefined, '0', '0', 'x1', 't');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('x1', 'x1', 'x4', 'y4');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x1', 'x1');
            f.AddPathCommand(2, 'x1', 'y4');
            f.AddPathCommand(2, 'x4', 'y4');
            f.AddPathCommand(2, 'x4', 'x1');
            f.AddPathCommand(6);
            break;
        }
        case 'funnel':{
            f.AddGuide('d', 0, 'ss', '1', '20');
            f.AddGuide('rw2', 1, 'wd2', '0', 'd');
            f.AddGuide('rh2', 1, 'hd4', '0', 'd');
            f.AddGuide('t1', 7, 'wd2', '480000');
            f.AddGuide('t2', 12, 'hd4', '480000');
            f.AddGuide('da', 5, 't1', 't2');
            f.AddGuide('2da', 0, 'da', '2', '1');
            f.AddGuide('stAng1', 1, 'cd2', '0', 'da');
            f.AddGuide('swAng1', 1, 'cd2', '2da', '0');
            f.AddGuide('swAng3', 1, 'cd2', '0', '2da');
            f.AddGuide('rw3', 0, 'wd2', '1', '4');
            f.AddGuide('rh3', 0, 'hd4', '1', '4');
            f.AddGuide('ct1', 7, 'hd4', 'stAng1');
            f.AddGuide('st1', 12, 'wd2', 'stAng1');
            f.AddGuide('m1', 9, 'ct1', 'st1', '0');
            f.AddGuide('n1', 0, 'wd2', 'hd4', 'm1');
            f.AddGuide('dx1', 7, 'n1', 'stAng1');
            f.AddGuide('dy1', 12, 'n1', 'stAng1');
            f.AddGuide('x1', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'hd4', 'dy1', '0');
            f.AddGuide('ct3', 7, 'rh3', 'da');
            f.AddGuide('st3', 12, 'rw3', 'da');
            f.AddGuide('m3', 9, 'ct3', 'st3', '0');
            f.AddGuide('n3', 0, 'rw3', 'rh3', 'm3');
            f.AddGuide('dx3', 7, 'n3', 'da');
            f.AddGuide('dy3', 12, 'n3', 'da');
            f.AddGuide('x3', 1, 'hc', 'dx3', '0');
            f.AddGuide('vc3', 1, 'b', '0', 'rh3');
            f.AddGuide('y2', 1, 'vc3', 'dy3', '0');
            f.AddGuide('x2', 1, 'wd2', '0', 'rw2');
            f.AddGuide('cd', 0, 'cd2', '2', '1');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(3, 'wd2', 'hd4', 'stAng1', 'swAng1');
            f.AddPathCommand(2, 'x3', 'y2');
            f.AddPathCommand(3, 'rw3', 'rh3', 'da', 'swAng3');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x2', 'hd4');
            f.AddPathCommand(3, 'rw2', 'rh2', 'cd2', '-21600000');
            f.AddPathCommand(6);
            break;
        }
        case 'gear6':{
            f.AddAdj('adj1', 15, '15000');
            f.AddAdj('adj2', 15, '3526');
            f.AddGuide('a1', 10, '0', 'adj1', '20000');
            f.AddGuide('a2', 10, '0', 'adj2', '5358');
            f.AddGuide('th', 0, 'ss', 'a1', '100000');
            f.AddGuide('lFD', 0, 'ss', 'a2', '100000');
            f.AddGuide('th2', 0, 'th', '1', '2');
            f.AddGuide('l2', 0, 'lFD', '1', '2');
            f.AddGuide('l3', 1, 'th2', 'l2', '0');
            f.AddGuide('rh', 1, 'hd2', '0', 'th');
            f.AddGuide('rw', 1, 'wd2', '0', 'th');
            f.AddGuide('dr', 1, 'rw', '0', 'rh');
            f.AddGuide('maxr', 3, 'dr', 'rh', 'rw');
            f.AddGuide('ha', 5, 'maxr', 'l3');
            f.AddGuide('aA1', 1, '19800000', '0', 'ha');
            f.AddGuide('aD1', 1, '19800000', 'ha', '0');
            f.AddGuide('ta11', 7, 'rw', 'aA1');
            f.AddGuide('ta12', 12, 'rh', 'aA1');
            f.AddGuide('bA1', 5, 'ta11', 'ta12');
            f.AddGuide('cta1', 7, 'rh', 'bA1');
            f.AddGuide('sta1', 12, 'rw', 'bA1');
            f.AddGuide('ma1', 9, 'cta1', 'sta1', '0');
            f.AddGuide('na1', 0, 'rw', 'rh', 'ma1');
            f.AddGuide('dxa1', 7, 'na1', 'bA1');
            f.AddGuide('dya1', 12, 'na1', 'bA1');
            f.AddGuide('xA1', 1, 'hc', 'dxa1', '0');
            f.AddGuide('yA1', 1, 'vc', 'dya1', '0');
            f.AddGuide('td11', 7, 'rw', 'aD1');
            f.AddGuide('td12', 12, 'rh', 'aD1');
            f.AddGuide('bD1', 5, 'td11', 'td12');
            f.AddGuide('ctd1', 7, 'rh', 'bD1');
            f.AddGuide('std1', 12, 'rw', 'bD1');
            f.AddGuide('md1', 9, 'ctd1', 'std1', '0');
            f.AddGuide('nd1', 0, 'rw', 'rh', 'md1');
            f.AddGuide('dxd1', 7, 'nd1', 'bD1');
            f.AddGuide('dyd1', 12, 'nd1', 'bD1');
            f.AddGuide('xD1', 1, 'hc', 'dxd1', '0');
            f.AddGuide('yD1', 1, 'vc', 'dyd1', '0');
            f.AddGuide('xAD1', 1, 'xA1', '0', 'xD1');
            f.AddGuide('yAD1', 1, 'yA1', '0', 'yD1');
            f.AddGuide('lAD1', 9, 'xAD1', 'yAD1', '0');
            f.AddGuide('a1', 5, 'yAD1', 'xAD1');
            f.AddGuide('dxF1', 12, 'lFD', 'a1');
            f.AddGuide('dyF1', 7, 'lFD', 'a1');
            f.AddGuide('xF1', 1, 'xD1', 'dxF1', '0');
            f.AddGuide('yF1', 1, 'yD1', 'dyF1', '0');
            f.AddGuide('xE1', 1, 'xA1', '0', 'dxF1');
            f.AddGuide('yE1', 1, 'yA1', '0', 'dyF1');
            f.AddGuide('yC1t', 12, 'th', 'a1');
            f.AddGuide('xC1t', 7, 'th', 'a1');
            f.AddGuide('yC1', 1, 'yF1', 'yC1t', '0');
            f.AddGuide('xC1', 1, 'xF1', '0', 'xC1t');
            f.AddGuide('yB1', 1, 'yE1', 'yC1t', '0');
            f.AddGuide('xB1', 1, 'xE1', '0', 'xC1t');
            f.AddGuide('aD6', 1, '_3cd4', 'ha', '0');
            f.AddGuide('td61', 7, 'rw', 'aD6');
            f.AddGuide('td62', 12, 'rh', 'aD6');
            f.AddGuide('bD6', 5, 'td61', 'td62');
            f.AddGuide('ctd6', 7, 'rh', 'bD6');
            f.AddGuide('std6', 12, 'rw', 'bD6');
            f.AddGuide('md6', 9, 'ctd6', 'std6', '0');
            f.AddGuide('nd6', 0, 'rw', 'rh', 'md6');
            f.AddGuide('dxd6', 7, 'nd6', 'bD6');
            f.AddGuide('dyd6', 12, 'nd6', 'bD6');
            f.AddGuide('xD6', 1, 'hc', 'dxd6', '0');
            f.AddGuide('yD6', 1, 'vc', 'dyd6', '0');
            f.AddGuide('xA6', 1, 'hc', '0', 'dxd6');
            f.AddGuide('xF6', 1, 'xD6', '0', 'lFD');
            f.AddGuide('xE6', 1, 'xA6', 'lFD', '0');
            f.AddGuide('yC6', 1, 'yD6', '0', 'th');
            f.AddGuide('swAng1', 1, 'bA1', '0', 'bD6');
            f.AddGuide('aA2', 1, '1800000', '0', 'ha');
            f.AddGuide('aD2', 1, '1800000', 'ha', '0');
            f.AddGuide('ta21', 7, 'rw', 'aA2');
            f.AddGuide('ta22', 12, 'rh', 'aA2');
            f.AddGuide('bA2', 5, 'ta21', 'ta22');
            f.AddGuide('yA2', 1, 'h', '0', 'yD1');
            f.AddGuide('td21', 7, 'rw', 'aD2');
            f.AddGuide('td22', 12, 'rh', 'aD2');
            f.AddGuide('bD2', 5, 'td21', 'td22');
            f.AddGuide('yD2', 1, 'h', '0', 'yA1');
            f.AddGuide('yC2', 1, 'h', '0', 'yB1');
            f.AddGuide('yB2', 1, 'h', '0', 'yC1');
            f.AddGuide('xB2', 15, 'xC1');
            f.AddGuide('swAng2', 1, 'bA2', '0', 'bD1');
            f.AddGuide('aD3', 1, 'cd4', 'ha', '0');
            f.AddGuide('td31', 7, 'rw', 'aD3');
            f.AddGuide('td32', 12, 'rh', 'aD3');
            f.AddGuide('bD3', 5, 'td31', 'td32');
            f.AddGuide('yD3', 1, 'h', '0', 'yD6');
            f.AddGuide('yB3', 1, 'h', '0', 'yC6');
            f.AddGuide('aD4', 1, '9000000', 'ha', '0');
            f.AddGuide('td41', 7, 'rw', 'aD4');
            f.AddGuide('td42', 12, 'rh', 'aD4');
            f.AddGuide('bD4', 5, 'td41', 'td42');
            f.AddGuide('xD4', 1, 'w', '0', 'xD1');
            f.AddGuide('xC4', 1, 'w', '0', 'xC1');
            f.AddGuide('xB4', 1, 'w', '0', 'xB1');
            f.AddGuide('aD5', 1, '12600000', 'ha', '0');
            f.AddGuide('td51', 7, 'rw', 'aD5');
            f.AddGuide('td52', 12, 'rh', 'aD5');
            f.AddGuide('bD5', 5, 'td51', 'td52');
            f.AddGuide('xD5', 1, 'w', '0', 'xA1');
            f.AddGuide('xC5', 1, 'w', '0', 'xB1');
            f.AddGuide('xB5', 1, 'w', '0', 'xC1');
            f.AddGuide('xCxn1', 2, 'xB1', 'xC1', '2');
            f.AddGuide('yCxn1', 2, 'yB1', 'yC1', '2');
            f.AddGuide('yCxn2', 1, 'b', '0', 'yCxn1');
            f.AddGuide('xCxn4', 2, 'r', '0', 'xCxn1');
            f.AddHandleXY(undefined, '0', '0','adj1','0','20000', 'xD6', 'yD6');
            f.AddHandleXY('adj2','0','5358', undefined, '0', '0', 'xA6', 'yD6');
            f.AddCnx('19800000', 'xCxn1', 'yCxn1');
            f.AddCnx('1800000', 'xCxn1', 'yCxn2');
            f.AddCnx('cd4', 'hc', 'yB3');
            f.AddCnx('9000000', 'xCxn4', 'yCxn2');
            f.AddCnx('12600000', 'xCxn4', 'yCxn1');
            f.AddCnx('_3cd4', 'hc', 'yC6');
            f.AddRect('xD5', 'yA1', 'xA1', 'yD2');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'xA1', 'yA1');
            f.AddPathCommand(2, 'xB1', 'yB1');
            f.AddPathCommand(2, 'xC1', 'yC1');
            f.AddPathCommand(2, 'xD1', 'yD1');
            f.AddPathCommand(3, 'rh', 'rw', 'bD1', 'swAng2');
            f.AddPathCommand(2, 'xC1', 'yB2');
            f.AddPathCommand(2, 'xB1', 'yC2');
            f.AddPathCommand(2, 'xA1', 'yD2');
            f.AddPathCommand(3, 'rh', 'rw', 'bD2', 'swAng1');
            f.AddPathCommand(2, 'xF6', 'yB3');
            f.AddPathCommand(2, 'xE6', 'yB3');
            f.AddPathCommand(2, 'xA6', 'yD3');
            f.AddPathCommand(3, 'rh', 'rw', 'bD3', 'swAng1');
            f.AddPathCommand(2, 'xB4', 'yC2');
            f.AddPathCommand(2, 'xC4', 'yB2');
            f.AddPathCommand(2, 'xD4', 'yA2');
            f.AddPathCommand(3, 'rh', 'rw', 'bD4', 'swAng2');
            f.AddPathCommand(2, 'xB5', 'yC1');
            f.AddPathCommand(2, 'xC5', 'yB1');
            f.AddPathCommand(2, 'xD5', 'yA1');
            f.AddPathCommand(3, 'rh', 'rw', 'bD5', 'swAng1');
            f.AddPathCommand(2, 'xE6', 'yC6');
            f.AddPathCommand(2, 'xF6', 'yC6');
            f.AddPathCommand(2, 'xD6', 'yD6');
            f.AddPathCommand(3, 'rh', 'rw', 'bD6', 'swAng1');
            f.AddPathCommand(6);
            break;
        }
        case 'gear9':{
            f.AddAdj('adj1', 15, '10000');
            f.AddAdj('adj2', 15, '1763');
            f.AddGuide('a1', 10, '0', 'adj1', '20000');
            f.AddGuide('a2', 10, '0', 'adj2', '2679');
            f.AddGuide('th', 0, 'ss', 'a1', '100000');
            f.AddGuide('lFD', 0, 'ss', 'a2', '100000');
            f.AddGuide('th2', 0, 'th', '1', '2');
            f.AddGuide('l2', 0, 'lFD', '1', '2');
            f.AddGuide('l3', 1, 'th2', 'l2', '0');
            f.AddGuide('rh', 1, 'hd2', '0', 'th');
            f.AddGuide('rw', 1, 'wd2', '0', 'th');
            f.AddGuide('dr', 1, 'rw', '0', 'rh');
            f.AddGuide('maxr', 3, 'dr', 'rh', 'rw');
            f.AddGuide('ha', 5, 'maxr', 'l3');
            f.AddGuide('aA1', 1, '18600000', '0', 'ha');
            f.AddGuide('aD1', 1, '18600000', 'ha', '0');
            f.AddGuide('ta11', 7, 'rw', 'aA1');
            f.AddGuide('ta12', 12, 'rh', 'aA1');
            f.AddGuide('bA1', 5, 'ta11', 'ta12');
            f.AddGuide('cta1', 7, 'rh', 'bA1');
            f.AddGuide('sta1', 12, 'rw', 'bA1');
            f.AddGuide('ma1', 9, 'cta1', 'sta1', '0');
            f.AddGuide('na1', 0, 'rw', 'rh', 'ma1');
            f.AddGuide('dxa1', 7, 'na1', 'bA1');
            f.AddGuide('dya1', 12, 'na1', 'bA1');
            f.AddGuide('xA1', 1, 'hc', 'dxa1', '0');
            f.AddGuide('yA1', 1, 'vc', 'dya1', '0');
            f.AddGuide('td11', 7, 'rw', 'aD1');
            f.AddGuide('td12', 12, 'rh', 'aD1');
            f.AddGuide('bD1', 5, 'td11', 'td12');
            f.AddGuide('ctd1', 7, 'rh', 'bD1');
            f.AddGuide('std1', 12, 'rw', 'bD1');
            f.AddGuide('md1', 9, 'ctd1', 'std1', '0');
            f.AddGuide('nd1', 0, 'rw', 'rh', 'md1');
            f.AddGuide('dxd1', 7, 'nd1', 'bD1');
            f.AddGuide('dyd1', 12, 'nd1', 'bD1');
            f.AddGuide('xD1', 1, 'hc', 'dxd1', '0');
            f.AddGuide('yD1', 1, 'vc', 'dyd1', '0');
            f.AddGuide('xAD1', 1, 'xA1', '0', 'xD1');
            f.AddGuide('yAD1', 1, 'yA1', '0', 'yD1');
            f.AddGuide('lAD1', 9, 'xAD1', 'yAD1', '0');
            f.AddGuide('a1', 5, 'yAD1', 'xAD1');
            f.AddGuide('dxF1', 12, 'lFD', 'a1');
            f.AddGuide('dyF1', 7, 'lFD', 'a1');
            f.AddGuide('xF1', 1, 'xD1', 'dxF1', '0');
            f.AddGuide('yF1', 1, 'yD1', 'dyF1', '0');
            f.AddGuide('xE1', 1, 'xA1', '0', 'dxF1');
            f.AddGuide('yE1', 1, 'yA1', '0', 'dyF1');
            f.AddGuide('yC1t', 12, 'th', 'a1');
            f.AddGuide('xC1t', 7, 'th', 'a1');
            f.AddGuide('yC1', 1, 'yF1', 'yC1t', '0');
            f.AddGuide('xC1', 1, 'xF1', '0', 'xC1t');
            f.AddGuide('yB1', 1, 'yE1', 'yC1t', '0');
            f.AddGuide('xB1', 1, 'xE1', '0', 'xC1t');
            f.AddGuide('aA2', 1, '21000000', '0', 'ha');
            f.AddGuide('aD2', 1, '21000000', 'ha', '0');
            f.AddGuide('ta21', 7, 'rw', 'aA2');
            f.AddGuide('ta22', 12, 'rh', 'aA2');
            f.AddGuide('bA2', 5, 'ta21', 'ta22');
            f.AddGuide('cta2', 7, 'rh', 'bA2');
            f.AddGuide('sta2', 12, 'rw', 'bA2');
            f.AddGuide('ma2', 9, 'cta2', 'sta2', '0');
            f.AddGuide('na2', 0, 'rw', 'rh', 'ma2');
            f.AddGuide('dxa2', 7, 'na2', 'bA2');
            f.AddGuide('dya2', 12, 'na2', 'bA2');
            f.AddGuide('xA2', 1, 'hc', 'dxa2', '0');
            f.AddGuide('yA2', 1, 'vc', 'dya2', '0');
            f.AddGuide('td21', 7, 'rw', 'aD2');
            f.AddGuide('td22', 12, 'rh', 'aD2');
            f.AddGuide('bD2', 5, 'td21', 'td22');
            f.AddGuide('ctd2', 7, 'rh', 'bD2');
            f.AddGuide('std2', 12, 'rw', 'bD2');
            f.AddGuide('md2', 9, 'ctd2', 'std2', '0');
            f.AddGuide('nd2', 0, 'rw', 'rh', 'md2');
            f.AddGuide('dxd2', 7, 'nd2', 'bD2');
            f.AddGuide('dyd2', 12, 'nd2', 'bD2');
            f.AddGuide('xD2', 1, 'hc', 'dxd2', '0');
            f.AddGuide('yD2', 1, 'vc', 'dyd2', '0');
            f.AddGuide('xAD2', 1, 'xA2', '0', 'xD2');
            f.AddGuide('yAD2', 1, 'yA2', '0', 'yD2');
            f.AddGuide('lAD2', 9, 'xAD2', 'yAD2', '0');
            f.AddGuide('a2', 5, 'yAD2', 'xAD2');
            f.AddGuide('dxF2', 12, 'lFD', 'a2');
            f.AddGuide('dyF2', 7, 'lFD', 'a2');
            f.AddGuide('xF2', 1, 'xD2', 'dxF2', '0');
            f.AddGuide('yF2', 1, 'yD2', 'dyF2', '0');
            f.AddGuide('xE2', 1, 'xA2', '0', 'dxF2');
            f.AddGuide('yE2', 1, 'yA2', '0', 'dyF2');
            f.AddGuide('yC2t', 12, 'th', 'a2');
            f.AddGuide('xC2t', 7, 'th', 'a2');
            f.AddGuide('yC2', 1, 'yF2', 'yC2t', '0');
            f.AddGuide('xC2', 1, 'xF2', '0', 'xC2t');
            f.AddGuide('yB2', 1, 'yE2', 'yC2t', '0');
            f.AddGuide('xB2', 1, 'xE2', '0', 'xC2t');
            f.AddGuide('swAng1', 1, 'bA2', '0', 'bD1');
            f.AddGuide('aA3', 1, '1800000', '0', 'ha');
            f.AddGuide('aD3', 1, '1800000', 'ha', '0');
            f.AddGuide('ta31', 7, 'rw', 'aA3');
            f.AddGuide('ta32', 12, 'rh', 'aA3');
            f.AddGuide('bA3', 5, 'ta31', 'ta32');
            f.AddGuide('cta3', 7, 'rh', 'bA3');
            f.AddGuide('sta3', 12, 'rw', 'bA3');
            f.AddGuide('ma3', 9, 'cta3', 'sta3', '0');
            f.AddGuide('na3', 0, 'rw', 'rh', 'ma3');
            f.AddGuide('dxa3', 7, 'na3', 'bA3');
            f.AddGuide('dya3', 12, 'na3', 'bA3');
            f.AddGuide('xA3', 1, 'hc', 'dxa3', '0');
            f.AddGuide('yA3', 1, 'vc', 'dya3', '0');
            f.AddGuide('td31', 7, 'rw', 'aD3');
            f.AddGuide('td32', 12, 'rh', 'aD3');
            f.AddGuide('bD3', 5, 'td31', 'td32');
            f.AddGuide('ctd3', 7, 'rh', 'bD3');
            f.AddGuide('std3', 12, 'rw', 'bD3');
            f.AddGuide('md3', 9, 'ctd3', 'std3', '0');
            f.AddGuide('nd3', 0, 'rw', 'rh', 'md3');
            f.AddGuide('dxd3', 7, 'nd3', 'bD3');
            f.AddGuide('dyd3', 12, 'nd3', 'bD3');
            f.AddGuide('xD3', 1, 'hc', 'dxd3', '0');
            f.AddGuide('yD3', 1, 'vc', 'dyd3', '0');
            f.AddGuide('xAD3', 1, 'xA3', '0', 'xD3');
            f.AddGuide('yAD3', 1, 'yA3', '0', 'yD3');
            f.AddGuide('lAD3', 9, 'xAD3', 'yAD3', '0');
            f.AddGuide('a3', 5, 'yAD3', 'xAD3');
            f.AddGuide('dxF3', 12, 'lFD', 'a3');
            f.AddGuide('dyF3', 7, 'lFD', 'a3');
            f.AddGuide('xF3', 1, 'xD3', 'dxF3', '0');
            f.AddGuide('yF3', 1, 'yD3', 'dyF3', '0');
            f.AddGuide('xE3', 1, 'xA3', '0', 'dxF3');
            f.AddGuide('yE3', 1, 'yA3', '0', 'dyF3');
            f.AddGuide('yC3t', 12, 'th', 'a3');
            f.AddGuide('xC3t', 7, 'th', 'a3');
            f.AddGuide('yC3', 1, 'yF3', 'yC3t', '0');
            f.AddGuide('xC3', 1, 'xF3', '0', 'xC3t');
            f.AddGuide('yB3', 1, 'yE3', 'yC3t', '0');
            f.AddGuide('xB3', 1, 'xE3', '0', 'xC3t');
            f.AddGuide('swAng2', 1, 'bA3', '0', 'bD2');
            f.AddGuide('aA4', 1, '4200000', '0', 'ha');
            f.AddGuide('aD4', 1, '4200000', 'ha', '0');
            f.AddGuide('ta41', 7, 'rw', 'aA4');
            f.AddGuide('ta42', 12, 'rh', 'aA4');
            f.AddGuide('bA4', 5, 'ta41', 'ta42');
            f.AddGuide('cta4', 7, 'rh', 'bA4');
            f.AddGuide('sta4', 12, 'rw', 'bA4');
            f.AddGuide('ma4', 9, 'cta4', 'sta4', '0');
            f.AddGuide('na4', 0, 'rw', 'rh', 'ma4');
            f.AddGuide('dxa4', 7, 'na4', 'bA4');
            f.AddGuide('dya4', 12, 'na4', 'bA4');
            f.AddGuide('xA4', 1, 'hc', 'dxa4', '0');
            f.AddGuide('yA4', 1, 'vc', 'dya4', '0');
            f.AddGuide('td41', 7, 'rw', 'aD4');
            f.AddGuide('td42', 12, 'rh', 'aD4');
            f.AddGuide('bD4', 5, 'td41', 'td42');
            f.AddGuide('ctd4', 7, 'rh', 'bD4');
            f.AddGuide('std4', 12, 'rw', 'bD4');
            f.AddGuide('md4', 9, 'ctd4', 'std4', '0');
            f.AddGuide('nd4', 0, 'rw', 'rh', 'md4');
            f.AddGuide('dxd4', 7, 'nd4', 'bD4');
            f.AddGuide('dyd4', 12, 'nd4', 'bD4');
            f.AddGuide('xD4', 1, 'hc', 'dxd4', '0');
            f.AddGuide('yD4', 1, 'vc', 'dyd4', '0');
            f.AddGuide('xAD4', 1, 'xA4', '0', 'xD4');
            f.AddGuide('yAD4', 1, 'yA4', '0', 'yD4');
            f.AddGuide('lAD4', 9, 'xAD4', 'yAD4', '0');
            f.AddGuide('a4', 5, 'yAD4', 'xAD4');
            f.AddGuide('dxF4', 12, 'lFD', 'a4');
            f.AddGuide('dyF4', 7, 'lFD', 'a4');
            f.AddGuide('xF4', 1, 'xD4', 'dxF4', '0');
            f.AddGuide('yF4', 1, 'yD4', 'dyF4', '0');
            f.AddGuide('xE4', 1, 'xA4', '0', 'dxF4');
            f.AddGuide('yE4', 1, 'yA4', '0', 'dyF4');
            f.AddGuide('yC4t', 12, 'th', 'a4');
            f.AddGuide('xC4t', 7, 'th', 'a4');
            f.AddGuide('yC4', 1, 'yF4', 'yC4t', '0');
            f.AddGuide('xC4', 1, 'xF4', '0', 'xC4t');
            f.AddGuide('yB4', 1, 'yE4', 'yC4t', '0');
            f.AddGuide('xB4', 1, 'xE4', '0', 'xC4t');
            f.AddGuide('swAng3', 1, 'bA4', '0', 'bD3');
            f.AddGuide('aA5', 1, '6600000', '0', 'ha');
            f.AddGuide('aD5', 1, '6600000', 'ha', '0');
            f.AddGuide('ta51', 7, 'rw', 'aA5');
            f.AddGuide('ta52', 12, 'rh', 'aA5');
            f.AddGuide('bA5', 5, 'ta51', 'ta52');
            f.AddGuide('td51', 7, 'rw', 'aD5');
            f.AddGuide('td52', 12, 'rh', 'aD5');
            f.AddGuide('bD5', 5, 'td51', 'td52');
            f.AddGuide('xD5', 1, 'w', '0', 'xA4');
            f.AddGuide('xC5', 1, 'w', '0', 'xB4');
            f.AddGuide('xB5', 1, 'w', '0', 'xC4');
            f.AddGuide('swAng4', 1, 'bA5', '0', 'bD4');
            f.AddGuide('aD6', 1, '9000000', 'ha', '0');
            f.AddGuide('td61', 7, 'rw', 'aD6');
            f.AddGuide('td62', 12, 'rh', 'aD6');
            f.AddGuide('bD6', 5, 'td61', 'td62');
            f.AddGuide('xD6', 1, 'w', '0', 'xA3');
            f.AddGuide('xC6', 1, 'w', '0', 'xB3');
            f.AddGuide('xB6', 1, 'w', '0', 'xC3');
            f.AddGuide('aD7', 1, '11400000', 'ha', '0');
            f.AddGuide('td71', 7, 'rw', 'aD7');
            f.AddGuide('td72', 12, 'rh', 'aD7');
            f.AddGuide('bD7', 5, 'td71', 'td72');
            f.AddGuide('xD7', 1, 'w', '0', 'xA2');
            f.AddGuide('xC7', 1, 'w', '0', 'xB2');
            f.AddGuide('xB7', 1, 'w', '0', 'xC2');
            f.AddGuide('aD8', 1, '13800000', 'ha', '0');
            f.AddGuide('td81', 7, 'rw', 'aD8');
            f.AddGuide('td82', 12, 'rh', 'aD8');
            f.AddGuide('bD8', 5, 'td81', 'td82');
            f.AddGuide('xA8', 1, 'w', '0', 'xD1');
            f.AddGuide('xD8', 1, 'w', '0', 'xA1');
            f.AddGuide('xC8', 1, 'w', '0', 'xB1');
            f.AddGuide('xB8', 1, 'w', '0', 'xC1');
            f.AddGuide('aA9', 1, '_3cd4', '0', 'ha');
            f.AddGuide('aD9', 1, '_3cd4', 'ha', '0');
            f.AddGuide('td91', 7, 'rw', 'aD9');
            f.AddGuide('td92', 12, 'rh', 'aD9');
            f.AddGuide('bD9', 5, 'td91', 'td92');
            f.AddGuide('ctd9', 7, 'rh', 'bD9');
            f.AddGuide('std9', 12, 'rw', 'bD9');
            f.AddGuide('md9', 9, 'ctd9', 'std9', '0');
            f.AddGuide('nd9', 0, 'rw', 'rh', 'md9');
            f.AddGuide('dxd9', 7, 'nd9', 'bD9');
            f.AddGuide('dyd9', 12, 'nd9', 'bD9');
            f.AddGuide('xD9', 1, 'hc', 'dxd9', '0');
            f.AddGuide('yD9', 1, 'vc', 'dyd9', '0');
            f.AddGuide('ta91', 7, 'rw', 'aA9');
            f.AddGuide('ta92', 12, 'rh', 'aA9');
            f.AddGuide('bA9', 5, 'ta91', 'ta92');
            f.AddGuide('xA9', 1, 'hc', '0', 'dxd9');
            f.AddGuide('xF9', 1, 'xD9', '0', 'lFD');
            f.AddGuide('xE9', 1, 'xA9', 'lFD', '0');
            f.AddGuide('yC9', 1, 'yD9', '0', 'th');
            f.AddGuide('swAng5', 1, 'bA9', '0', 'bD8');
            f.AddGuide('xCxn1', 2, 'xB1', 'xC1', '2');
            f.AddGuide('yCxn1', 2, 'yB1', 'yC1', '2');
            f.AddGuide('xCxn2', 2, 'xB2', 'xC2', '2');
            f.AddGuide('yCxn2', 2, 'yB2', 'yC2', '2');
            f.AddGuide('xCxn3', 2, 'xB3', 'xC3', '2');
            f.AddGuide('yCxn3', 2, 'yB3', 'yC3', '2');
            f.AddGuide('xCxn4', 2, 'xB4', 'xC4', '2');
            f.AddGuide('yCxn4', 2, 'yB4', 'yC4', '2');
            f.AddGuide('xCxn5', 2, 'r', '0', 'xCxn4');
            f.AddGuide('xCxn6', 2, 'r', '0', 'xCxn3');
            f.AddGuide('xCxn7', 2, 'r', '0', 'xCxn2');
            f.AddGuide('xCxn8', 2, 'r', '0', 'xCxn1');
            f.AddHandleXY(undefined, '0', '0','adj1','0','20000', 'xD9', 'yD9');
            f.AddHandleXY('adj2','0','2679', undefined, '0', '0', 'xA9', 'yD9');
            f.AddCnx('18600000', 'xCxn1', 'yCxn1');
            f.AddCnx('21000000', 'xCxn2', 'yCxn2');
            f.AddCnx('1800000', 'xCxn3', 'yCxn3');
            f.AddCnx('4200000', 'xCxn4', 'yCxn4');
            f.AddCnx('6600000', 'xCxn5', 'yCxn4');
            f.AddCnx('9000000', 'xCxn6', 'yCxn3');
            f.AddCnx('11400000', 'xCxn7', 'yCxn2');
            f.AddCnx('13800000', 'xCxn8', 'yCxn1');
            f.AddCnx('_3cd4', 'hc', 'yC9');
            f.AddRect('xA8', 'yD1', 'xD1', 'yD3');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'xA1', 'yA1');
            f.AddPathCommand(2, 'xB1', 'yB1');
            f.AddPathCommand(2, 'xC1', 'yC1');
            f.AddPathCommand(2, 'xD1', 'yD1');
            f.AddPathCommand(3, 'rh', 'rw', 'bD1', 'swAng1');
            f.AddPathCommand(2, 'xB2', 'yB2');
            f.AddPathCommand(2, 'xC2', 'yC2');
            f.AddPathCommand(2, 'xD2', 'yD2');
            f.AddPathCommand(3, 'rh', 'rw', 'bD2', 'swAng2');
            f.AddPathCommand(2, 'xB3', 'yB3');
            f.AddPathCommand(2, 'xC3', 'yC3');
            f.AddPathCommand(2, 'xD3', 'yD3');
            f.AddPathCommand(3, 'rh', 'rw', 'bD3', 'swAng3');
            f.AddPathCommand(2, 'xB4', 'yB4');
            f.AddPathCommand(2, 'xC4', 'yC4');
            f.AddPathCommand(2, 'xD4', 'yD4');
            f.AddPathCommand(3, 'rh', 'rw', 'bD4', 'swAng4');
            f.AddPathCommand(2, 'xB5', 'yC4');
            f.AddPathCommand(2, 'xC5', 'yB4');
            f.AddPathCommand(2, 'xD5', 'yA4');
            f.AddPathCommand(3, 'rh', 'rw', 'bD5', 'swAng3');
            f.AddPathCommand(2, 'xB6', 'yC3');
            f.AddPathCommand(2, 'xC6', 'yB3');
            f.AddPathCommand(2, 'xD6', 'yA3');
            f.AddPathCommand(3, 'rh', 'rw', 'bD6', 'swAng2');
            f.AddPathCommand(2, 'xB7', 'yC2');
            f.AddPathCommand(2, 'xC7', 'yB2');
            f.AddPathCommand(2, 'xD7', 'yA2');
            f.AddPathCommand(3, 'rh', 'rw', 'bD7', 'swAng1');
            f.AddPathCommand(2, 'xB8', 'yC1');
            f.AddPathCommand(2, 'xC8', 'yB1');
            f.AddPathCommand(2, 'xD8', 'yA1');
            f.AddPathCommand(3, 'rh', 'rw', 'bD8', 'swAng5');
            f.AddPathCommand(2, 'xE9', 'yC9');
            f.AddPathCommand(2, 'xF9', 'yC9');
            f.AddPathCommand(2, 'xD9', 'yD9');
            f.AddPathCommand(3, 'rh', 'rw', 'bD9', 'swAng5');
            f.AddPathCommand(6);
            break;
        }
        case 'halfFrame':{
            f.AddAdj('adj1', 15, '33333');
            f.AddAdj('adj2', 15, '33333');
            f.AddGuide('maxAdj2', 0, '100000', 'w', 'ss');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('x1', 0, 'ss', 'a2', '100000');
            f.AddGuide('g1', 0, 'h', 'x1', 'w');
            f.AddGuide('g2', 1, 'h', '0', 'g1');
            f.AddGuide('maxAdj1', 0, '100000', 'g2', 'ss');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('y1', 0, 'ss', 'a1', '100000');
            f.AddGuide('dx2', 0, 'y1', 'w', 'h');
            f.AddGuide('x2', 1, 'r', '0', 'dx2');
            f.AddGuide('dy2', 0, 'x1', 'h', 'w');
            f.AddGuide('y2', 1, 'b', '0', 'dy2');
            f.AddGuide('cx1', 0, 'x1', '1', '2');
            f.AddGuide('cy1', 2, 'y2', 'b', '2');
            f.AddGuide('cx2', 2, 'x2', 'r', '2');
            f.AddGuide('cy2', 0, 'y1', '1', '2');
            f.AddHandleXY(undefined, '0', '0','adj1','0','maxAdj1', 'l', 'y1');
            f.AddHandleXY('adj2','0','maxAdj2', undefined, '0', '0', 'x1', 't');
            f.AddCnx('0', 'cx2', 'cy2');
            f.AddCnx('cd4', 'cx1', 'cy1');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'x1', 'y1');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'heart':{
            f.AddGuide('dx1', 0, 'w', '49', '48');
            f.AddGuide('dx2', 0, 'w', '10', '48');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'hc', 'dx2', '0');
            f.AddGuide('x4', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 't', '0', 'hd3');
            f.AddGuide('il', 0, 'w', '1', '6');
            f.AddGuide('ir', 0, 'w', '5', '6');
            f.AddGuide('ib', 0, 'h', '2', '3');
            f.AddCnx('_3cd4', 'hc', 'hd4');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddRect('il', 'hd4', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'hc', 'hd4');
            f.AddPathCommand(5, 'x3', 'y1', 'x4', 'hd4', 'hc', 'b');
            f.AddPathCommand(5, 'x1', 'hd4', 'x2', 'y1', 'hc', 'hd4');
            f.AddPathCommand(6);
            break;
        }
        case 'heptagon':{
            f.AddAdj('hf', 15, '102572');
            f.AddAdj('vf', 15, '105210');
            f.AddGuide('swd2', 0, 'wd2', 'hf', '100000');
            f.AddGuide('shd2', 0, 'hd2', 'vf', '100000');
            f.AddGuide('svc', 0, 'vc', 'vf', '100000');
            f.AddGuide('dx1', 0, 'swd2', '97493', '100000');
            f.AddGuide('dx2', 0, 'swd2', '78183', '100000');
            f.AddGuide('dx3', 0, 'swd2', '43388', '100000');
            f.AddGuide('dy1', 0, 'shd2', '62349', '100000');
            f.AddGuide('dy2', 0, 'shd2', '22252', '100000');
            f.AddGuide('dy3', 0, 'shd2', '90097', '100000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'hc', '0', 'dx3');
            f.AddGuide('x4', 1, 'hc', 'dx3', '0');
            f.AddGuide('x5', 1, 'hc', 'dx2', '0');
            f.AddGuide('x6', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'svc', '0', 'dy1');
            f.AddGuide('y2', 1, 'svc', 'dy2', '0');
            f.AddGuide('y3', 1, 'svc', 'dy3', '0');
            f.AddGuide('ib', 1, 'b', '0', 'y1');
            f.AddCnx('0', 'x5', 'y1');
            f.AddCnx('0', 'x6', 'y2');
            f.AddCnx('cd4', 'x4', 'y3');
            f.AddCnx('cd4', 'x3', 'y3');
            f.AddCnx('cd2', 'x1', 'y2');
            f.AddCnx('cd2', 'x2', 'y1');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('x2', 'y1', 'x5', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y2');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'x5', 'y1');
            f.AddPathCommand(2, 'x6', 'y2');
            f.AddPathCommand(2, 'x4', 'y3');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(6);
            break;
        }
        case 'hexagon':{
            f.AddAdj('adj', 15, '25000');
            f.AddAdj('vf', 15, '115470');
            f.AddGuide('maxAdj', 0, '50000', 'w', 'ss');
            f.AddGuide('a', 10, '0', 'adj', 'maxAdj');
            f.AddGuide('shd2', 0, 'hd2', 'vf', '100000');
            f.AddGuide('x1', 0, 'ss', 'a', '100000');
            f.AddGuide('x2', 1, 'r', '0', 'x1');
            f.AddGuide('dy1', 12, 'shd2', '3600000');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y2', 1, 'vc', 'dy1', '0');
            f.AddGuide('q1', 0, 'maxAdj', '-1', '2');
            f.AddGuide('q2', 1, 'a', 'q1', '0');
            f.AddGuide('q3', 3, 'q2', '4', '2');
            f.AddGuide('q4', 3, 'q2', '3', '2');
            f.AddGuide('q5', 3, 'q2', 'q1', '0');
            f.AddGuide('q6', 2, 'a', 'q5', 'q1');
            f.AddGuide('q7', 0, 'q6', 'q4', '-1');
            f.AddGuide('q8', 1, 'q3', 'q7', '0');
            f.AddGuide('il', 0, 'w', 'q8', '24');
            f.AddGuide('it', 0, 'h', 'q8', '24');
            f.AddGuide('ir', 1, 'r', '0', 'il');
            f.AddGuide('ib', 1, 'b', '0', 'it');
            f.AddHandleXY('adj','0','maxAdj', undefined, '0', '0', 'x1', 't');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'x2', 'y2');
            f.AddCnx('cd4', 'x1', 'y2');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'x1', 'y1');
            f.AddCnx('_3cd4', 'x2', 'y1');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'x1', 'y1');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(6);
            break;
        }
        case 'homePlate':{
            f.AddAdj('adj', 15, '50000');
            f.AddGuide('maxAdj', 0, '100000', 'w', 'ss');
            f.AddGuide('a', 10, '0', 'adj', 'maxAdj');
            f.AddGuide('dx1', 0, 'ss', 'a', '100000');
            f.AddGuide('x1', 1, 'r', '0', 'dx1');
            f.AddGuide('ir', 2, 'x1', 'r', '2');
            f.AddGuide('x2', 0, 'x1', '1', '2');
            f.AddHandleXY('adj','0','maxAdj', undefined, '0', '0', 'x1', 't');
            f.AddCnx('_3cd4', 'x2', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'x1', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 't', 'ir', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'x1', 't');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'horizontalScroll':{
            f.AddAdj('adj', 15, '12500');
            f.AddGuide('a', 10, '0', 'adj', '25000');
            f.AddGuide('ch', 0, 'ss', 'a', '100000');
            f.AddGuide('ch2', 0, 'ch', '1', '2');
            f.AddGuide('ch4', 0, 'ch', '1', '4');
            f.AddGuide('y3', 1, 'ch', 'ch2', '0');
            f.AddGuide('y4', 1, 'ch', 'ch', '0');
            f.AddGuide('y6', 1, 'b', '0', 'ch');
            f.AddGuide('y7', 1, 'b', '0', 'ch2');
            f.AddGuide('y5', 1, 'y6', '0', 'ch2');
            f.AddGuide('x3', 1, 'r', '0', 'ch');
            f.AddGuide('x4', 1, 'r', '0', 'ch2');
            f.AddHandleXY('adj','0','25000', undefined, '0', '0', 'ch', 't');
            f.AddCnx('cd4', 'hc', 'ch');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 'y6');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('ch', 'ch', 'x4', 'y6');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'r', 'ch2');
            f.AddPathCommand(3, 'ch2', 'ch2', '0', 'cd4');
            f.AddPathCommand(2, 'x4', 'ch2');
            f.AddPathCommand(3, 'ch4', 'ch4', '0', 'cd2');
            f.AddPathCommand(2, 'x3', 'ch');
            f.AddPathCommand(2, 'ch2', 'ch');
            f.AddPathCommand(3, 'ch2', 'ch2', '_3cd4', '-5400000');
            f.AddPathCommand(2, 'l', 'y7');
            f.AddPathCommand(3, 'ch2', 'ch2', 'cd2', '-10800000');
            f.AddPathCommand(2, 'ch', 'y6');
            f.AddPathCommand(2, 'x4', 'y6');
            f.AddPathCommand(3, 'ch2', 'ch2', 'cd4', '-5400000');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'ch2', 'y4');
            f.AddPathCommand(3, 'ch2', 'ch2', 'cd4', '-5400000');
            f.AddPathCommand(3, 'ch4', 'ch4', '0', '-10800000');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'ch2', 'y4');
            f.AddPathCommand(3, 'ch2', 'ch2', 'cd4', '-5400000');
            f.AddPathCommand(3, 'ch4', 'ch4', '0', '-10800000');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x4', 'ch');
            f.AddPathCommand(3, 'ch2', 'ch2', 'cd4', '-16200000');
            f.AddPathCommand(3, 'ch4', 'ch4', 'cd2', '-10800000');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y3');
            f.AddPathCommand(3, 'ch2', 'ch2', 'cd2', 'cd4');
            f.AddPathCommand(2, 'x3', 'ch');
            f.AddPathCommand(2, 'x3', 'ch2');
            f.AddPathCommand(3, 'ch2', 'ch2', 'cd2', 'cd2');
            f.AddPathCommand(2, 'r', 'y5');
            f.AddPathCommand(3, 'ch2', 'ch2', '0', 'cd4');
            f.AddPathCommand(2, 'ch', 'y6');
            f.AddPathCommand(2, 'ch', 'y7');
            f.AddPathCommand(3, 'ch2', 'ch2', '0', 'cd2');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x3', 'ch');
            f.AddPathCommand(2, 'x4', 'ch');
            f.AddPathCommand(3, 'ch2', 'ch2', 'cd4', '-5400000');
            f.AddPathCommand(1, 'x4', 'ch');
            f.AddPathCommand(2, 'x4', 'ch2');
            f.AddPathCommand(3, 'ch4', 'ch4', '0', 'cd2');
            f.AddPathCommand(1, 'ch2', 'y4');
            f.AddPathCommand(2, 'ch2', 'y3');
            f.AddPathCommand(3, 'ch4', 'ch4', 'cd2', 'cd2');
            f.AddPathCommand(3, 'ch2', 'ch2', '0', 'cd2');
            f.AddPathCommand(1, 'ch', 'y3');
            f.AddPathCommand(2, 'ch', 'y6');
            break;
        }
        case 'irregularSeal1':{
            f.AddGuide('x5', 0, 'w', '4627', '21600');
            f.AddGuide('x12', 0, 'w', '8485', '21600');
            f.AddGuide('x21', 0, 'w', '16702', '21600');
            f.AddGuide('x24', 0, 'w', '14522', '21600');
            f.AddGuide('y3', 0, 'h', '6320', '21600');
            f.AddGuide('y6', 0, 'h', '8615', '21600');
            f.AddGuide('y9', 0, 'h', '13937', '21600');
            f.AddGuide('y18', 0, 'h', '13290', '21600');
            f.AddCnx('_3cd4', 'x24', 't');
            f.AddCnx('cd2', 'l', 'y6');
            f.AddCnx('cd4', 'x12', 'b');
            f.AddCnx('0', 'r', 'y18');
            f.AddRect('x5', 'y3', 'x21', 'y9');
            f.AddPathCommand(0,undefined, undefined, undefined, 21600, 21600);
            f.AddPathCommand(1, '10800', '5800');
            f.AddPathCommand(2, '14522', '0');
            f.AddPathCommand(2, '14155', '5325');
            f.AddPathCommand(2, '18380', '4457');
            f.AddPathCommand(2, '16702', '7315');
            f.AddPathCommand(2, '21097', '8137');
            f.AddPathCommand(2, '17607', '10475');
            f.AddPathCommand(2, '21600', '13290');
            f.AddPathCommand(2, '16837', '12942');
            f.AddPathCommand(2, '18145', '18095');
            f.AddPathCommand(2, '14020', '14457');
            f.AddPathCommand(2, '13247', '19737');
            f.AddPathCommand(2, '10532', '14935');
            f.AddPathCommand(2, '8485', '21600');
            f.AddPathCommand(2, '7715', '15627');
            f.AddPathCommand(2, '4762', '17617');
            f.AddPathCommand(2, '5667', '13937');
            f.AddPathCommand(2, '135', '14587');
            f.AddPathCommand(2, '3722', '11775');
            f.AddPathCommand(2, '0', '8615');
            f.AddPathCommand(2, '4627', '7617');
            f.AddPathCommand(2, '370', '2295');
            f.AddPathCommand(2, '7312', '6320');
            f.AddPathCommand(2, '8352', '2295');
            f.AddPathCommand(6);
            break;
        }
        case 'irregularSeal2':{
            f.AddGuide('x2', 0, 'w', '9722', '21600');
            f.AddGuide('x5', 0, 'w', '5372', '21600');
            f.AddGuide('x16', 0, 'w', '11612', '21600');
            f.AddGuide('x19', 0, 'w', '14640', '21600');
            f.AddGuide('y2', 0, 'h', '1887', '21600');
            f.AddGuide('y3', 0, 'h', '6382', '21600');
            f.AddGuide('y8', 0, 'h', '12877', '21600');
            f.AddGuide('y14', 0, 'h', '19712', '21600');
            f.AddGuide('y16', 0, 'h', '18842', '21600');
            f.AddGuide('y17', 0, 'h', '15935', '21600');
            f.AddGuide('y24', 0, 'h', '6645', '21600');
            f.AddCnx('_3cd4', 'x2', 'y2');
            f.AddCnx('cd2', 'l', 'y8');
            f.AddCnx('cd4', 'x16', 'y16');
            f.AddCnx('0', 'r', 'y24');
            f.AddRect('x5', 'y3', 'x19', 'y17');
            f.AddPathCommand(0,undefined, undefined, undefined, 21600, 21600);
            f.AddPathCommand(1, '11462', '4342');
            f.AddPathCommand(2, '14790', '0');
            f.AddPathCommand(2, '14525', '5777');
            f.AddPathCommand(2, '18007', '3172');
            f.AddPathCommand(2, '16380', '6532');
            f.AddPathCommand(2, '21600', '6645');
            f.AddPathCommand(2, '16985', '9402');
            f.AddPathCommand(2, '18270', '11290');
            f.AddPathCommand(2, '16380', '12310');
            f.AddPathCommand(2, '18877', '15632');
            f.AddPathCommand(2, '14640', '14350');
            f.AddPathCommand(2, '14942', '17370');
            f.AddPathCommand(2, '12180', '15935');
            f.AddPathCommand(2, '11612', '18842');
            f.AddPathCommand(2, '9872', '17370');
            f.AddPathCommand(2, '8700', '19712');
            f.AddPathCommand(2, '7527', '18125');
            f.AddPathCommand(2, '4917', '21600');
            f.AddPathCommand(2, '4805', '18240');
            f.AddPathCommand(2, '1285', '17825');
            f.AddPathCommand(2, '3330', '15370');
            f.AddPathCommand(2, '0', '12877');
            f.AddPathCommand(2, '3935', '11592');
            f.AddPathCommand(2, '1172', '8270');
            f.AddPathCommand(2, '5372', '7817');
            f.AddPathCommand(2, '4502', '3625');
            f.AddPathCommand(2, '8550', '6382');
            f.AddPathCommand(2, '9722', '1887');
            f.AddPathCommand(6);
            break;
        }
        case 'leftArrow':{
            f.AddAdj('adj1', 15, '50000');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('maxAdj2', 0, '100000', 'w', 'ss');
            f.AddGuide('a1', 10, '0', 'adj1', '100000');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('dx2', 0, 'ss', 'a2', '100000');
            f.AddGuide('x2', 1, 'l', 'dx2', '0');
            f.AddGuide('dy1', 0, 'h', 'a1', '200000');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y2', 1, 'vc', 'dy1', '0');
            f.AddGuide('dx1', 0, 'y1', 'dx2', 'hd2');
            f.AddGuide('x1', 1, 'x2', '0', 'dx1');
            f.AddHandleXY(undefined, '0', '0','adj1','0','100000', 'r', 'y1');
            f.AddHandleXY('adj2','0','maxAdj2', undefined, '0', '0', 'x2', 't');
            f.AddCnx('_3cd4', 'x2', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'x2', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('x1', 'y1', 'r', 'y2');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'r', 'y1');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x2', 'b');
            f.AddPathCommand(6);
            break;
        }



        case 'upArrow':{
            f.AddAdj('adj1', 15, '50000');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('maxAdj2', 0, '100000', 'h', 'ss');
            f.AddGuide('a1', 10, '0', 'adj1', '100000');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('dy2', 0, 'ss', 'a2', '100000');
            f.AddGuide('y2', 1, 't', 'dy2', '0');
            f.AddGuide('dx1', 0, 'w', 'a1', '200000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', 'dx1', '0');
            f.AddGuide('dy1', 0, 'x1', 'dy2', 'wd2');
            f.AddGuide('y1', 1, 'y2', '0', 'dy1');
            f.AddHandleXY('adj1','0','100000', undefined, '0', '0', 'x1', 'b');
            f.AddHandleXY( undefined, '0', '0','adj2','0','maxAdj2', 'l', 'y2');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'y2');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'y2');
            f.AddRect('x1', 'y1', 'x2', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y2');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x2', 'b');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(6);
            break;
        }


        case 'leftArrowCallout':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '25000');
            f.AddAdj('adj3', 15, '25000');
            f.AddAdj('adj4', 15, '64977');
            f.AddGuide('maxAdj2', 0, '50000', 'h', 'ss');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('maxAdj1', 0, 'a2', '2', '1');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('maxAdj3', 0, '100000', 'w', 'ss');
            f.AddGuide('a3', 10, '0', 'adj3', 'maxAdj3');
            f.AddGuide('q2', 0, 'a3', 'ss', 'w');
            f.AddGuide('maxAdj4', 1, '100000', '0', 'q2');
            f.AddGuide('a4', 10, '0', 'adj4', 'maxAdj4');
            f.AddGuide('dy1', 0, 'ss', 'a2', '100000');
            f.AddGuide('dy2', 0, 'ss', 'a1', '200000');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y2', 1, 'vc', '0', 'dy2');
            f.AddGuide('y3', 1, 'vc', 'dy2', '0');
            f.AddGuide('y4', 1, 'vc', 'dy1', '0');
            f.AddGuide('x1', 0, 'ss', 'a3', '100000');
            f.AddGuide('dx2', 0, 'w', 'a4', '100000');
            f.AddGuide('x2', 1, 'r', '0', 'dx2');
            f.AddGuide('x3', 2, 'x2', 'r', '2');
            f.AddHandleXY(undefined, '0', '0','adj1','0','maxAdj1', 'x1', 'y2');
            f.AddHandleXY(undefined, '0', '0','adj2','0','maxAdj2', 'l', 'y1');
            f.AddHandleXY('adj3','0','maxAdj3', undefined, '0', '0', 'x1', 't');
            f.AddHandleXY('adj4','0','maxAdj4', undefined, '0', '0', 'x2', 'b');
            f.AddCnx('_3cd4', 'x3', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'x3', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('x2', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'x1', 'y1');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'x2', 'b');
            f.AddPathCommand(2, 'x2', 'y3');
            f.AddPathCommand(2, 'x1', 'y3');
            f.AddPathCommand(2, 'x1', 'y4');
            f.AddPathCommand(6);
            break;
        }
        case 'leftBrace':{
            f.AddAdj('adj1', 15, '8333');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('a2', 10, '0', 'adj2', '100000');
            f.AddGuide('q1', 1, '100000', '0', 'a2');
            f.AddGuide('q2', 16, 'q1', 'a2');
            f.AddGuide('q3', 0, 'q2', '1', '2');
            f.AddGuide('maxAdj1', 0, 'q3', 'h', 'ss');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('y1', 0, 'ss', 'a1', '100000');
            f.AddGuide('y3', 0, 'h', 'a2', '100000');
            f.AddGuide('y4', 1, 'y3', 'y1', '0');
            f.AddGuide('dx1', 7, 'wd2', '2700000');
            f.AddGuide('dy1', 12, 'y1', '2700000');
            f.AddGuide('il', 1, 'r', '0', 'dx1');
            f.AddGuide('it', 1, 'y1', '0', 'dy1');
            f.AddGuide('ib', 1, 'b', 'dy1', 'y1');
            f.AddHandleXY(undefined, '0', '0','adj1','0','maxAdj1', 'hc', 'y1');
            f.AddHandleXY(undefined, '0', '0','adj2','0','100000', 'l', 'y3');
            f.AddCnx('cd4', 'r', 't');
            f.AddCnx('cd2', 'l', 'y3');
            f.AddCnx('_3cd4', 'r', 'b');
            f.AddRect('il', 'it', 'r', 'ib');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'r', 'b');
            f.AddPathCommand(3, 'wd2', 'y1', 'cd4', 'cd4');
            f.AddPathCommand(2, 'hc', 'y4');
            f.AddPathCommand(3, 'wd2', 'y1', '0', '-5400000');
            f.AddPathCommand(3, 'wd2', 'y1', 'cd4', '-5400000');
            f.AddPathCommand(2, 'hc', 'y1');
            f.AddPathCommand(3, 'wd2', 'y1', 'cd2', 'cd4');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'r', 'b');
            f.AddPathCommand(3, 'wd2', 'y1', 'cd4', 'cd4');
            f.AddPathCommand(2, 'hc', 'y4');
            f.AddPathCommand(3, 'wd2', 'y1', '0', '-5400000');
            f.AddPathCommand(3, 'wd2', 'y1', 'cd4', '-5400000');
            f.AddPathCommand(2, 'hc', 'y1');
            f.AddPathCommand(3, 'wd2', 'y1', 'cd2', 'cd4');
            break;
        }
        case 'leftBracket':{
            f.AddAdj('adj', 15, '8333');
            f.AddGuide('maxAdj', 0, '50000', 'h', 'ss');
            f.AddGuide('a', 10, '0', 'adj', 'maxAdj');
            f.AddGuide('y1', 0, 'ss', 'a', '100000');
            f.AddGuide('y2', 1, 'b', '0', 'y1');
            f.AddGuide('dx1', 7, 'w', '2700000');
            f.AddGuide('dy1', 12, 'y1', '2700000');
            f.AddGuide('il', 1, 'r', '0', 'dx1');
            f.AddGuide('it', 1, 'y1', '0', 'dy1');
            f.AddGuide('ib', 1, 'b', 'dy1', 'y1');
            f.AddHandleXY(undefined, '0', '0','adj','0','maxAdj', 'l', 'y1');
            f.AddCnx('cd4', 'r', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'r', 'b');
            f.AddRect('il', 'it', 'r', 'ib');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'r', 'b');
            f.AddPathCommand(3, 'w', 'y1', 'cd4', 'cd4');
            f.AddPathCommand(2, 'l', 'y1');
            f.AddPathCommand(3, 'w', 'y1', 'cd2', 'cd4');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'r', 'b');
            f.AddPathCommand(3, 'w', 'y1', 'cd4', 'cd4');
            f.AddPathCommand(2, 'l', 'y1');
            f.AddPathCommand(3, 'w', 'y1', 'cd2', 'cd4');
            break;
        }
        case 'leftCircularArrow':{
            f.AddAdj('adj1', 15, '12500');
            f.AddAdj('adj2', 15, '-1142319');
            f.AddAdj('adj3', 15, '1142319');
            f.AddAdj('adj4', 15, '10800000');
            f.AddAdj('adj5', 15, '12500');
            f.AddGuide('a5', 10, '0', 'adj5', '25000');
            f.AddGuide('maxAdj1', 0, 'a5', '2', '1');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('enAng', 10, '1', 'adj3', '21599999');
            f.AddGuide('stAng', 10, '0', 'adj4', '21599999');
            f.AddGuide('th', 0, 'ss', 'a1', '100000');
            f.AddGuide('thh', 0, 'ss', 'a5', '100000');
            f.AddGuide('th2', 0, 'th', '1', '2');
            f.AddGuide('rw1', 1, 'wd2', 'th2', 'thh');
            f.AddGuide('rh1', 1, 'hd2', 'th2', 'thh');
            f.AddGuide('rw2', 1, 'rw1', '0', 'th');
            f.AddGuide('rh2', 1, 'rh1', '0', 'th');
            f.AddGuide('rw3', 1, 'rw2', 'th2', '0');
            f.AddGuide('rh3', 1, 'rh2', 'th2', '0');
            f.AddGuide('wtH', 12, 'rw3', 'enAng');
            f.AddGuide('htH', 7, 'rh3', 'enAng');
            f.AddGuide('dxH', 6, 'rw3', 'htH', 'wtH');
            f.AddGuide('dyH', 11, 'rh3', 'htH', 'wtH');
            f.AddGuide('xH', 1, 'hc', 'dxH', '0');
            f.AddGuide('yH', 1, 'vc', 'dyH', '0');
            f.AddGuide('rI', 16, 'rw2', 'rh2');
            f.AddGuide('u1', 0, 'dxH', 'dxH', '1');
            f.AddGuide('u2', 0, 'dyH', 'dyH', '1');
            f.AddGuide('u3', 0, 'rI', 'rI', '1');
            f.AddGuide('u4', 1, 'u1', '0', 'u3');
            f.AddGuide('u5', 1, 'u2', '0', 'u3');
            f.AddGuide('u6', 0, 'u4', 'u5', 'u1');
            f.AddGuide('u7', 0, 'u6', '1', 'u2');
            f.AddGuide('u8', 1, '1', '0', 'u7');
            f.AddGuide('u9', 13, 'u8');
            f.AddGuide('u10', 0, 'u4', '1', 'dxH');
            f.AddGuide('u11', 0, 'u10', '1', 'dyH');
            f.AddGuide('u12', 2, '1', 'u9', 'u11');
            f.AddGuide('u13', 5, '1', 'u12');
            f.AddGuide('u14', 1, 'u13', '21600000', '0');
            f.AddGuide('u15', 3, 'u13', 'u13', 'u14');
            f.AddGuide('u16', 1, 'u15', '0', 'enAng');
            f.AddGuide('u17', 1, 'u16', '21600000', '0');
            f.AddGuide('u18', 3, 'u16', 'u16', 'u17');
            f.AddGuide('u19', 1, 'u18', '0', 'cd2');
            f.AddGuide('u20', 1, 'u18', '0', '21600000');
            f.AddGuide('u21', 3, 'u19', 'u20', 'u18');
            f.AddGuide('u22', 4, 'u21');
            f.AddGuide('minAng', 0, 'u22', '-1', '1');
            f.AddGuide('u23', 4, 'adj2');
            f.AddGuide('a2', 0, 'u23', '-1', '1');
            f.AddGuide('aAng', 10, 'minAng', 'a2', '0');
            f.AddGuide('ptAng', 1, 'enAng', 'aAng', '0');
            f.AddGuide('wtA', 12, 'rw3', 'ptAng');
            f.AddGuide('htA', 7, 'rh3', 'ptAng');
            f.AddGuide('dxA', 6, 'rw3', 'htA', 'wtA');
            f.AddGuide('dyA', 11, 'rh3', 'htA', 'wtA');
            f.AddGuide('xA', 1, 'hc', 'dxA', '0');
            f.AddGuide('yA', 1, 'vc', 'dyA', '0');
            f.AddGuide('wtE', 12, 'rw1', 'stAng');
            f.AddGuide('htE', 7, 'rh1', 'stAng');
            f.AddGuide('dxE', 6, 'rw1', 'htE', 'wtE');
            f.AddGuide('dyE', 11, 'rh1', 'htE', 'wtE');
            f.AddGuide('xE', 1, 'hc', 'dxE', '0');
            f.AddGuide('yE', 1, 'vc', 'dyE', '0');
            f.AddGuide('wtD', 12, 'rw2', 'stAng');
            f.AddGuide('htD', 7, 'rh2', 'stAng');
            f.AddGuide('dxD', 6, 'rw2', 'htD', 'wtD');
            f.AddGuide('dyD', 11, 'rh2', 'htD', 'wtD');
            f.AddGuide('xD', 1, 'hc', 'dxD', '0');
            f.AddGuide('yD', 1, 'vc', 'dyD', '0');
            f.AddGuide('dxG', 7, 'thh', 'ptAng');
            f.AddGuide('dyG', 12, 'thh', 'ptAng');
            f.AddGuide('xG', 1, 'xH', 'dxG', '0');
            f.AddGuide('yG', 1, 'yH', 'dyG', '0');
            f.AddGuide('dxB', 7, 'thh', 'ptAng');
            f.AddGuide('dyB', 12, 'thh', 'ptAng');
            f.AddGuide('xB', 1, 'xH', '0', 'dxB', '0');
            f.AddGuide('yB', 1, 'yH', '0', 'dyB', '0');
            f.AddGuide('sx1', 1, 'xB', '0', 'hc');
            f.AddGuide('sy1', 1, 'yB', '0', 'vc');
            f.AddGuide('sx2', 1, 'xG', '0', 'hc');
            f.AddGuide('sy2', 1, 'yG', '0', 'vc');
            f.AddGuide('rO', 16, 'rw1', 'rh1');
            f.AddGuide('x1O', 0, 'sx1', 'rO', 'rw1');
            f.AddGuide('y1O', 0, 'sy1', 'rO', 'rh1');
            f.AddGuide('x2O', 0, 'sx2', 'rO', 'rw1');
            f.AddGuide('y2O', 0, 'sy2', 'rO', 'rh1');
            f.AddGuide('dxO', 1, 'x2O', '0', 'x1O');
            f.AddGuide('dyO', 1, 'y2O', '0', 'y1O');
            f.AddGuide('dO', 9, 'dxO', 'dyO', '0');
            f.AddGuide('q1', 0, 'x1O', 'y2O', '1');
            f.AddGuide('q2', 0, 'x2O', 'y1O', '1');
            f.AddGuide('DO', 1, 'q1', '0', 'q2');
            f.AddGuide('q3', 0, 'rO', 'rO', '1');
            f.AddGuide('q4', 0, 'dO', 'dO', '1');
            f.AddGuide('q5', 0, 'q3', 'q4', '1');
            f.AddGuide('q6', 0, 'DO', 'DO', '1');
            f.AddGuide('q7', 1, 'q5', '0', 'q6');
            f.AddGuide('q8', 8, 'q7', '0');
            f.AddGuide('sdelO', 13, 'q8');
            f.AddGuide('ndyO', 0, 'dyO', '-1', '1');
            f.AddGuide('sdyO', 3, 'ndyO', '-1', '1');
            f.AddGuide('q9', 0, 'sdyO', 'dxO', '1');
            f.AddGuide('q10', 0, 'q9', 'sdelO', '1');
            f.AddGuide('q11', 0, 'DO', 'dyO', '1');
            f.AddGuide('dxF1', 2, 'q11', 'q10', 'q4');
            f.AddGuide('q12', 1, 'q11', '0', 'q10');
            f.AddGuide('dxF2', 0, 'q12', '1', 'q4');
            f.AddGuide('adyO', 4, 'dyO');
            f.AddGuide('q13', 0, 'adyO', 'sdelO', '1');
            f.AddGuide('q14', 0, 'DO', 'dxO', '-1');
            f.AddGuide('dyF1', 2, 'q14', 'q13', 'q4');
            f.AddGuide('q15', 1, 'q14', '0', 'q13');
            f.AddGuide('dyF2', 0, 'q15', '1', 'q4');
            f.AddGuide('q16', 1, 'x2O', '0', 'dxF1');
            f.AddGuide('q17', 1, 'x2O', '0', 'dxF2');
            f.AddGuide('q18', 1, 'y2O', '0', 'dyF1');
            f.AddGuide('q19', 1, 'y2O', '0', 'dyF2');
            f.AddGuide('q20', 9, 'q16', 'q18', '0');
            f.AddGuide('q21', 9, 'q17', 'q19', '0');
            f.AddGuide('q22', 1, 'q21', '0', 'q20');
            f.AddGuide('dxF', 3, 'q22', 'dxF1', 'dxF2');
            f.AddGuide('dyF', 3, 'q22', 'dyF1', 'dyF2');
            f.AddGuide('sdxF', 0, 'dxF', 'rw1', 'rO');
            f.AddGuide('sdyF', 0, 'dyF', 'rh1', 'rO');
            f.AddGuide('xF', 1, 'hc', 'sdxF', '0');
            f.AddGuide('yF', 1, 'vc', 'sdyF', '0');
            f.AddGuide('x1I', 0, 'sx1', 'rI', 'rw2');
            f.AddGuide('y1I', 0, 'sy1', 'rI', 'rh2');
            f.AddGuide('x2I', 0, 'sx2', 'rI', 'rw2');
            f.AddGuide('y2I', 0, 'sy2', 'rI', 'rh2');
            f.AddGuide('dxI', 1, 'x2I', '0', 'x1I');
            f.AddGuide('dyI', 1, 'y2I', '0', 'y1I');
            f.AddGuide('dI', 9, 'dxI', 'dyI', '0');
            f.AddGuide('v1', 0, 'x1I', 'y2I', '1');
            f.AddGuide('v2', 0, 'x2I', 'y1I', '1');
            f.AddGuide('DI', 1, 'v1', '0', 'v2');
            f.AddGuide('v3', 0, 'rI', 'rI', '1');
            f.AddGuide('v4', 0, 'dI', 'dI', '1');
            f.AddGuide('v5', 0, 'v3', 'v4', '1');
            f.AddGuide('v6', 0, 'DI', 'DI', '1');
            f.AddGuide('v7', 1, 'v5', '0', 'v6');
            f.AddGuide('v8', 8, 'v7', '0');
            f.AddGuide('sdelI', 13, 'v8');
            f.AddGuide('v9', 0, 'sdyO', 'dxI', '1');
            f.AddGuide('v10', 0, 'v9', 'sdelI', '1');
            f.AddGuide('v11', 0, 'DI', 'dyI', '1');
            f.AddGuide('dxC1', 2, 'v11', 'v10', 'v4');
            f.AddGuide('v12', 1, 'v11', '0', 'v10');
            f.AddGuide('dxC2', 0, 'v12', '1', 'v4');
            f.AddGuide('adyI', 4, 'dyI');
            f.AddGuide('v13', 0, 'adyI', 'sdelI', '1');
            f.AddGuide('v14', 0, 'DI', 'dxI', '-1');
            f.AddGuide('dyC1', 2, 'v14', 'v13', 'v4');
            f.AddGuide('v15', 1, 'v14', '0', 'v13');
            f.AddGuide('dyC2', 0, 'v15', '1', 'v4');
            f.AddGuide('v16', 1, 'x1I', '0', 'dxC1');
            f.AddGuide('v17', 1, 'x1I', '0', 'dxC2');
            f.AddGuide('v18', 1, 'y1I', '0', 'dyC1');
            f.AddGuide('v19', 1, 'y1I', '0', 'dyC2');
            f.AddGuide('v20', 9, 'v16', 'v18', '0');
            f.AddGuide('v21', 9, 'v17', 'v19', '0');
            f.AddGuide('v22', 1, 'v21', '0', 'v20');
            f.AddGuide('dxC', 3, 'v22', 'dxC1', 'dxC2');
            f.AddGuide('dyC', 3, 'v22', 'dyC1', 'dyC2');
            f.AddGuide('sdxC', 0, 'dxC', 'rw2', 'rI');
            f.AddGuide('sdyC', 0, 'dyC', 'rh2', 'rI');
            f.AddGuide('xC', 1, 'hc', 'sdxC', '0');
            f.AddGuide('yC', 1, 'vc', 'sdyC', '0');
            f.AddGuide('ist0', 5, 'sdxC', 'sdyC');
            f.AddGuide('ist1', 1, 'ist0', '21600000', '0');
            f.AddGuide('istAng0', 3, 'ist0', 'ist0', 'ist1');
            f.AddGuide('isw1', 1, 'stAng', '0', 'istAng0');
            f.AddGuide('isw2', 1, 'isw1', '21600000', '0');
            f.AddGuide('iswAng0', 3, 'isw1', 'isw1', 'isw2');
            f.AddGuide('istAng', 1, 'istAng0', 'iswAng0', '0');
            f.AddGuide('iswAng', 1, '0', '0', 'iswAng0');
            f.AddGuide('p1', 1, 'xF', '0', 'xC');
            f.AddGuide('p2', 1, 'yF', '0', 'yC');
            f.AddGuide('p3', 9, 'p1', 'p2', '0');
            f.AddGuide('p4', 0, 'p3', '1', '2');
            f.AddGuide('p5', 1, 'p4', '0', 'thh');
            f.AddGuide('xGp', 3, 'p5', 'xF', 'xG');
            f.AddGuide('yGp', 3, 'p5', 'yF', 'yG');
            f.AddGuide('xBp', 3, 'p5', 'xC', 'xB');
            f.AddGuide('yBp', 3, 'p5', 'yC', 'yB');
            f.AddGuide('en0', 5, 'sdxF', 'sdyF');
            f.AddGuide('en1', 1, 'en0', '21600000', '0');
            f.AddGuide('en2', 3, 'en0', 'en0', 'en1');
            f.AddGuide('sw0', 1, 'en2', '0', 'stAng');
            f.AddGuide('sw1', 1, 'sw0', '0', '21600000');
            f.AddGuide('swAng', 3, 'sw0', 'sw1', 'sw0');
            f.AddGuide('stAng0', 1, 'stAng', 'swAng', '0');
            f.AddGuide('swAng0', 1, '0', '0', 'swAng');
            f.AddGuide('wtI', 12, 'rw3', 'stAng');
            f.AddGuide('htI', 7, 'rh3', 'stAng');
            f.AddGuide('dxI', 6, 'rw3', 'htI', 'wtI');
            f.AddGuide('dyI', 11, 'rh3', 'htI', 'wtI');
            f.AddGuide('xI', 1, 'hc', 'dxI', '0');
            f.AddGuide('yI', 1, 'vc', 'dyI', '0');
            f.AddGuide('aI', 1, 'stAng', 'cd4', '0');
            f.AddGuide('aA', 1, 'ptAng', '0', 'cd4');
            f.AddGuide('aB', 1, 'ptAng', 'cd2', '0');
            f.AddGuide('idx', 7, 'rw1', '2700000');
            f.AddGuide('idy', 12, 'rh1', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddHandlePolar('adj2','minAng','0', undefined, '0', '0', 'xA', 'yA');
            f.AddHandlePolar('adj4','0','21599999', undefined, '0', '0', 'xE', 'yE');
            f.AddHandlePolar(undefined, '0', '0','adj1','0','maxAdj1', 'xF', 'yF');
            f.AddHandlePolar(undefined, '0', '0','adj5','0','25000', 'xB', 'yB');
            f.AddCnx('aI', 'xI', 'yI');
            f.AddCnx('ptAng', 'xGp', 'yGp');
            f.AddCnx('aA', 'xA', 'yA');
            f.AddCnx('aB', 'xBp', 'yBp');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'xE', 'yE');
            f.AddPathCommand(2, 'xD', 'yD');
            f.AddPathCommand(3, 'rw2', 'rh2', 'istAng', 'iswAng');
            f.AddPathCommand(2, 'xBp', 'yBp');
            f.AddPathCommand(2, 'xA', 'yA');
            f.AddPathCommand(2, 'xGp', 'yGp');
            f.AddPathCommand(2, 'xF', 'yF');
            f.AddPathCommand(3, 'rw1', 'rh1', 'stAng0', 'swAng0');
            f.AddPathCommand(6);
            break;
        }
        case 'leftRightArrow':{
            f.AddAdj('adj1', 15, '50000');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('maxAdj2', 0, '50000', 'w', 'ss');
            f.AddGuide('a1', 10, '0', 'adj1', '100000');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('x2', 0, 'ss', 'a2', '100000');
            f.AddGuide('x3', 1, 'r', '0', 'x2');
            f.AddGuide('dy', 0, 'h', 'a1', '200000');
            f.AddGuide('y1', 1, 'vc', '0', 'dy');
            f.AddGuide('y2', 1, 'vc', 'dy', '0');
            f.AddGuide('dx1', 0, 'y1', 'x2', 'hd2');
            f.AddGuide('x1', 1, 'x2', '0', 'dx1');
            f.AddGuide('x4', 1, 'x3', 'dx1', '0');
            f.AddHandleXY(undefined, '0', '0','adj1','0','100000', 'x3', 'y1');
            f.AddHandleXY('adj2','0','maxAdj2', undefined, '0', '0', 'x2', 't');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'x3', 'b');
            f.AddCnx('cd4', 'x2', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'x2', 't');
            f.AddCnx('_3cd4', 'x3', 't');
            f.AddRect('x1', 'y1', 'x4', 'y2');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(2, 'x3', 't');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'x3', 'b');
            f.AddPathCommand(2, 'x3', 'y2');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x2', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'leftRightArrowCallout':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '25000');
            f.AddAdj('adj3', 15, '25000');
            f.AddAdj('adj4', 15, '48123');
            f.AddGuide('maxAdj2', 0, '50000', 'h', 'ss');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('maxAdj1', 0, 'a2', '2', '1');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('maxAdj3', 0, '50000', 'w', 'ss');
            f.AddGuide('a3', 10, '0', 'adj3', 'maxAdj3');
            f.AddGuide('q2', 0, 'a3', 'ss', 'wd2');
            f.AddGuide('maxAdj4', 1, '100000', '0', 'q2');
            f.AddGuide('a4', 10, '0', 'adj4', 'maxAdj4');
            f.AddGuide('dy1', 0, 'ss', 'a2', '100000');
            f.AddGuide('dy2', 0, 'ss', 'a1', '200000');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y2', 1, 'vc', '0', 'dy2');
            f.AddGuide('y3', 1, 'vc', 'dy2', '0');
            f.AddGuide('y4', 1, 'vc', 'dy1', '0');
            f.AddGuide('x1', 0, 'ss', 'a3', '100000');
            f.AddGuide('x4', 1, 'r', '0', 'x1');
            f.AddGuide('dx2', 0, 'w', 'a4', '200000');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'hc', 'dx2', '0');
            f.AddHandleXY(undefined, '0', '0','adj1','0','maxAdj1', 'x1', 'y2');
            f.AddHandleXY(undefined, '0', '0','adj2','0','maxAdj2', 'l', 'y1');
            f.AddHandleXY('adj3','0','maxAdj3', undefined, '0', '0', 'x1', 't');
            f.AddHandleXY('adj4','0','maxAdj4', undefined, '0', '0', 'x2', 'b');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('x2', 't', 'x3', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'x1', 'y1');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'x3', 't');
            f.AddPathCommand(2, 'x3', 'y2');
            f.AddPathCommand(2, 'x4', 'y2');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'x4', 'y4');
            f.AddPathCommand(2, 'x4', 'y3');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(2, 'x3', 'b');
            f.AddPathCommand(2, 'x2', 'b');
            f.AddPathCommand(2, 'x2', 'y3');
            f.AddPathCommand(2, 'x1', 'y3');
            f.AddPathCommand(2, 'x1', 'y4');
            f.AddPathCommand(6);
            break;
        }
        case 'leftRightCircularArrow':{
            f.AddAdj('adj1', 15, '12500');
            f.AddAdj('adj2', 15, '1142319');
            f.AddAdj('adj3', 15, '20457681');
            f.AddAdj('adj4', 15, '11942319');
            f.AddAdj('adj5', 15, '12500');
            f.AddGuide('a5', 10, '0', 'adj5', '25000');
            f.AddGuide('maxAdj1', 0, 'a5', '2', '1');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('enAng', 10, '1', 'adj3', '21599999');
            f.AddGuide('stAng', 10, '0', 'adj4', '21599999');
            f.AddGuide('th', 0, 'ss', 'a1', '100000');
            f.AddGuide('thh', 0, 'ss', 'a5', '100000');
            f.AddGuide('th2', 0, 'th', '1', '2');
            f.AddGuide('rw1', 1, 'wd2', 'th2', 'thh');
            f.AddGuide('rh1', 1, 'hd2', 'th2', 'thh');
            f.AddGuide('rw2', 1, 'rw1', '0', 'th');
            f.AddGuide('rh2', 1, 'rh1', '0', 'th');
            f.AddGuide('rw3', 1, 'rw2', 'th2', '0');
            f.AddGuide('rh3', 1, 'rh2', 'th2', '0');
            f.AddGuide('wtH', 12, 'rw3', 'enAng');
            f.AddGuide('htH', 7, 'rh3', 'enAng');
            f.AddGuide('dxH', 6, 'rw3', 'htH', 'wtH');
            f.AddGuide('dyH', 11, 'rh3', 'htH', 'wtH');
            f.AddGuide('xH', 1, 'hc', 'dxH', '0');
            f.AddGuide('yH', 1, 'vc', 'dyH', '0');
            f.AddGuide('rI', 16, 'rw2', 'rh2');
            f.AddGuide('u1', 0, 'dxH', 'dxH', '1');
            f.AddGuide('u2', 0, 'dyH', 'dyH', '1');
            f.AddGuide('u3', 0, 'rI', 'rI', '1');
            f.AddGuide('u4', 1, 'u1', '0', 'u3');
            f.AddGuide('u5', 1, 'u2', '0', 'u3');
            f.AddGuide('u6', 0, 'u4', 'u5', 'u1');
            f.AddGuide('u7', 0, 'u6', '1', 'u2');
            f.AddGuide('u8', 1, '1', '0', 'u7');
            f.AddGuide('u9', 13, 'u8');
            f.AddGuide('u10', 0, 'u4', '1', 'dxH');
            f.AddGuide('u11', 0, 'u10', '1', 'dyH');
            f.AddGuide('u12', 2, '1', 'u9', 'u11');
            f.AddGuide('u13', 5, '1', 'u12');
            f.AddGuide('u14', 1, 'u13', '21600000', '0');
            f.AddGuide('u15', 3, 'u13', 'u13', 'u14');
            f.AddGuide('u16', 1, 'u15', '0', 'enAng');
            f.AddGuide('u17', 1, 'u16', '21600000', '0');
            f.AddGuide('u18', 3, 'u16', 'u16', 'u17');
            f.AddGuide('u19', 1, 'u18', '0', 'cd2');
            f.AddGuide('u20', 1, 'u18', '0', '21600000');
            f.AddGuide('u21', 3, 'u19', 'u20', 'u18');
            f.AddGuide('maxAng', 4, 'u21');
            f.AddGuide('aAng', 10, '0', 'adj2', 'maxAng');
            f.AddGuide('ptAng', 1, 'enAng', 'aAng', '0');
            f.AddGuide('wtA', 12, 'rw3', 'ptAng');
            f.AddGuide('htA', 7, 'rh3', 'ptAng');
            f.AddGuide('dxA', 6, 'rw3', 'htA', 'wtA');
            f.AddGuide('dyA', 11, 'rh3', 'htA', 'wtA');
            f.AddGuide('xA', 1, 'hc', 'dxA', '0');
            f.AddGuide('yA', 1, 'vc', 'dyA', '0');
            f.AddGuide('dxG', 7, 'thh', 'ptAng');
            f.AddGuide('dyG', 12, 'thh', 'ptAng');
            f.AddGuide('xG', 1, 'xH', 'dxG', '0');
            f.AddGuide('yG', 1, 'yH', 'dyG', '0');
            f.AddGuide('dxB', 7, 'thh', 'ptAng');
            f.AddGuide('dyB', 12, 'thh', 'ptAng');
            f.AddGuide('xB', 1, 'xH', '0', 'dxB', '0');
            f.AddGuide('yB', 1, 'yH', '0', 'dyB', '0');
            f.AddGuide('sx1', 1, 'xB', '0', 'hc');
            f.AddGuide('sy1', 1, 'yB', '0', 'vc');
            f.AddGuide('sx2', 1, 'xG', '0', 'hc');
            f.AddGuide('sy2', 1, 'yG', '0', 'vc');
            f.AddGuide('rO', 16, 'rw1', 'rh1');
            f.AddGuide('x1O', 0, 'sx1', 'rO', 'rw1');
            f.AddGuide('y1O', 0, 'sy1', 'rO', 'rh1');
            f.AddGuide('x2O', 0, 'sx2', 'rO', 'rw1');
            f.AddGuide('y2O', 0, 'sy2', 'rO', 'rh1');
            f.AddGuide('dxO', 1, 'x2O', '0', 'x1O');
            f.AddGuide('dyO', 1, 'y2O', '0', 'y1O');
            f.AddGuide('dO', 9, 'dxO', 'dyO', '0');
            f.AddGuide('q1', 0, 'x1O', 'y2O', '1');
            f.AddGuide('q2', 0, 'x2O', 'y1O', '1');
            f.AddGuide('DO', 1, 'q1', '0', 'q2');
            f.AddGuide('q3', 0, 'rO', 'rO', '1');
            f.AddGuide('q4', 0, 'dO', 'dO', '1');
            f.AddGuide('q5', 0, 'q3', 'q4', '1');
            f.AddGuide('q6', 0, 'DO', 'DO', '1');
            f.AddGuide('q7', 1, 'q5', '0', 'q6');
            f.AddGuide('q8', 8, 'q7', '0');
            f.AddGuide('sdelO', 13, 'q8');
            f.AddGuide('ndyO', 0, 'dyO', '-1', '1');
            f.AddGuide('sdyO', 3, 'ndyO', '-1', '1');
            f.AddGuide('q9', 0, 'sdyO', 'dxO', '1');
            f.AddGuide('q10', 0, 'q9', 'sdelO', '1');
            f.AddGuide('q11', 0, 'DO', 'dyO', '1');
            f.AddGuide('dxF1', 2, 'q11', 'q10', 'q4');
            f.AddGuide('q12', 1, 'q11', '0', 'q10');
            f.AddGuide('dxF2', 0, 'q12', '1', 'q4');
            f.AddGuide('adyO', 4, 'dyO');
            f.AddGuide('q13', 0, 'adyO', 'sdelO', '1');
            f.AddGuide('q14', 0, 'DO', 'dxO', '-1');
            f.AddGuide('dyF1', 2, 'q14', 'q13', 'q4');
            f.AddGuide('q15', 1, 'q14', '0', 'q13');
            f.AddGuide('dyF2', 0, 'q15', '1', 'q4');
            f.AddGuide('q16', 1, 'x2O', '0', 'dxF1');
            f.AddGuide('q17', 1, 'x2O', '0', 'dxF2');
            f.AddGuide('q18', 1, 'y2O', '0', 'dyF1');
            f.AddGuide('q19', 1, 'y2O', '0', 'dyF2');
            f.AddGuide('q20', 9, 'q16', 'q18', '0');
            f.AddGuide('q21', 9, 'q17', 'q19', '0');
            f.AddGuide('q22', 1, 'q21', '0', 'q20');
            f.AddGuide('dxF', 3, 'q22', 'dxF1', 'dxF2');
            f.AddGuide('dyF', 3, 'q22', 'dyF1', 'dyF2');
            f.AddGuide('sdxF', 0, 'dxF', 'rw1', 'rO');
            f.AddGuide('sdyF', 0, 'dyF', 'rh1', 'rO');
            f.AddGuide('xF', 1, 'hc', 'sdxF', '0');
            f.AddGuide('yF', 1, 'vc', 'sdyF', '0');
            f.AddGuide('x1I', 0, 'sx1', 'rI', 'rw2');
            f.AddGuide('y1I', 0, 'sy1', 'rI', 'rh2');
            f.AddGuide('x2I', 0, 'sx2', 'rI', 'rw2');
            f.AddGuide('y2I', 0, 'sy2', 'rI', 'rh2');
            f.AddGuide('dxI', 1, 'x2I', '0', 'x1I');
            f.AddGuide('dyI', 1, 'y2I', '0', 'y1I');
            f.AddGuide('dI', 9, 'dxI', 'dyI', '0');
            f.AddGuide('v1', 0, 'x1I', 'y2I', '1');
            f.AddGuide('v2', 0, 'x2I', 'y1I', '1');
            f.AddGuide('DI', 1, 'v1', '0', 'v2');
            f.AddGuide('v3', 0, 'rI', 'rI', '1');
            f.AddGuide('v4', 0, 'dI', 'dI', '1');
            f.AddGuide('v5', 0, 'v3', 'v4', '1');
            f.AddGuide('v6', 0, 'DI', 'DI', '1');
            f.AddGuide('v7', 1, 'v5', '0', 'v6');
            f.AddGuide('v8', 8, 'v7', '0');
            f.AddGuide('sdelI', 13, 'v8');
            f.AddGuide('v9', 0, 'sdyO', 'dxI', '1');
            f.AddGuide('v10', 0, 'v9', 'sdelI', '1');
            f.AddGuide('v11', 0, 'DI', 'dyI', '1');
            f.AddGuide('dxC1', 2, 'v11', 'v10', 'v4');
            f.AddGuide('v12', 1, 'v11', '0', 'v10');
            f.AddGuide('dxC2', 0, 'v12', '1', 'v4');
            f.AddGuide('adyI', 4, 'dyI');
            f.AddGuide('v13', 0, 'adyI', 'sdelI', '1');
            f.AddGuide('v14', 0, 'DI', 'dxI', '-1');
            f.AddGuide('dyC1', 2, 'v14', 'v13', 'v4');
            f.AddGuide('v15', 1, 'v14', '0', 'v13');
            f.AddGuide('dyC2', 0, 'v15', '1', 'v4');
            f.AddGuide('v16', 1, 'x1I', '0', 'dxC1');
            f.AddGuide('v17', 1, 'x1I', '0', 'dxC2');
            f.AddGuide('v18', 1, 'y1I', '0', 'dyC1');
            f.AddGuide('v19', 1, 'y1I', '0', 'dyC2');
            f.AddGuide('v20', 9, 'v16', 'v18', '0');
            f.AddGuide('v21', 9, 'v17', 'v19', '0');
            f.AddGuide('v22', 1, 'v21', '0', 'v20');
            f.AddGuide('dxC', 3, 'v22', 'dxC1', 'dxC2');
            f.AddGuide('dyC', 3, 'v22', 'dyC1', 'dyC2');
            f.AddGuide('sdxC', 0, 'dxC', 'rw2', 'rI');
            f.AddGuide('sdyC', 0, 'dyC', 'rh2', 'rI');
            f.AddGuide('xC', 1, 'hc', 'sdxC', '0');
            f.AddGuide('yC', 1, 'vc', 'sdyC', '0');
            f.AddGuide('wtI', 12, 'rw3', 'stAng');
            f.AddGuide('htI', 7, 'rh3', 'stAng');
            f.AddGuide('dxI', 6, 'rw3', 'htI', 'wtI');
            f.AddGuide('dyI', 11, 'rh3', 'htI', 'wtI');
            f.AddGuide('xI', 1, 'hc', 'dxI', '0');
            f.AddGuide('yI', 1, 'vc', 'dyI', '0');
            f.AddGuide('lptAng', 1, 'stAng', '0', 'aAng');
            f.AddGuide('wtL', 12, 'rw3', 'lptAng');
            f.AddGuide('htL', 7, 'rh3', 'lptAng');
            f.AddGuide('dxL', 6, 'rw3', 'htL', 'wtL');
            f.AddGuide('dyL', 11, 'rh3', 'htL', 'wtL');
            f.AddGuide('xL', 1, 'hc', 'dxL', '0');
            f.AddGuide('yL', 1, 'vc', 'dyL', '0');
            f.AddGuide('dxK', 7, 'thh', 'lptAng');
            f.AddGuide('dyK', 12, 'thh', 'lptAng');
            f.AddGuide('xK', 1, 'xI', 'dxK', '0');
            f.AddGuide('yK', 1, 'yI', 'dyK', '0');
            f.AddGuide('dxJ', 7, 'thh', 'lptAng');
            f.AddGuide('dyJ', 12, 'thh', 'lptAng');
            f.AddGuide('xJ', 1, 'xI', '0', 'dxJ', '0');
            f.AddGuide('yJ', 1, 'yI', '0', 'dyJ', '0');
            f.AddGuide('p1', 1, 'xF', '0', 'xC');
            f.AddGuide('p2', 1, 'yF', '0', 'yC');
            f.AddGuide('p3', 9, 'p1', 'p2', '0');
            f.AddGuide('p4', 0, 'p3', '1', '2');
            f.AddGuide('p5', 1, 'p4', '0', 'thh');
            f.AddGuide('xGp', 3, 'p5', 'xF', 'xG');
            f.AddGuide('yGp', 3, 'p5', 'yF', 'yG');
            f.AddGuide('xBp', 3, 'p5', 'xC', 'xB');
            f.AddGuide('yBp', 3, 'p5', 'yC', 'yB');
            f.AddGuide('en0', 5, 'sdxF', 'sdyF');
            f.AddGuide('en1', 1, 'en0', '21600000', '0');
            f.AddGuide('en2', 3, 'en0', 'en0', 'en1');
            f.AddGuide('od0', 1, 'en2', '0', 'enAng');
            f.AddGuide('od1', 1, 'od0', '21600000', '0');
            f.AddGuide('od2', 3, 'od0', 'od0', 'od1');
            f.AddGuide('st0', 1, 'stAng', '0', 'od2');
            f.AddGuide('st1', 1, 'st0', '21600000', '0');
            f.AddGuide('st2', 3, 'st0', 'st0', 'st1');
            f.AddGuide('sw0', 1, 'en2', '0', 'st2');
            f.AddGuide('sw1', 1, 'sw0', '21600000', '0');
            f.AddGuide('swAng', 3, 'sw0', 'sw0', 'sw1');
            f.AddGuide('ist0', 5, 'sdxC', 'sdyC');
            f.AddGuide('ist1', 1, 'ist0', '21600000', '0');
            f.AddGuide('istAng', 3, 'ist0', 'ist0', 'ist1');
            f.AddGuide('id0', 1, 'istAng', '0', 'enAng');
            f.AddGuide('id1', 1, 'id0', '0', '21600000');
            f.AddGuide('id2', 3, 'id0', 'id1', 'id0');
            f.AddGuide('ien0', 1, 'stAng', '0', 'id2');
            f.AddGuide('ien1', 1, 'ien0', '0', '21600000');
            f.AddGuide('ien2', 3, 'ien1', 'ien1', 'ien0');
            f.AddGuide('isw1', 1, 'ien2', '0', 'istAng');
            f.AddGuide('isw2', 1, 'isw1', '0', '21600000');
            f.AddGuide('iswAng', 3, 'isw1', 'isw2', 'isw1');
            f.AddGuide('wtE', 12, 'rw1', 'st2');
            f.AddGuide('htE', 7, 'rh1', 'st2');
            f.AddGuide('dxE', 6, 'rw1', 'htE', 'wtE');
            f.AddGuide('dyE', 11, 'rh1', 'htE', 'wtE');
            f.AddGuide('xE', 1, 'hc', 'dxE', '0');
            f.AddGuide('yE', 1, 'vc', 'dyE', '0');
            f.AddGuide('wtD', 12, 'rw2', 'ien2');
            f.AddGuide('htD', 7, 'rh2', 'ien2');
            f.AddGuide('dxD', 6, 'rw2', 'htD', 'wtD');
            f.AddGuide('dyD', 11, 'rh2', 'htD', 'wtD');
            f.AddGuide('xD', 1, 'hc', 'dxD', '0');
            f.AddGuide('yD', 1, 'vc', 'dyD', '0');
            f.AddGuide('xKp', 3, 'p5', 'xE', 'xK');
            f.AddGuide('yKp', 3, 'p5', 'yE', 'yK');
            f.AddGuide('xJp', 3, 'p5', 'xD', 'xJ');
            f.AddGuide('yJp', 3, 'p5', 'yD', 'yJ');
            f.AddGuide('aL', 1, 'lptAng', '0', 'cd4');
            f.AddGuide('aA', 1, 'ptAng', 'cd4', '0');
            f.AddGuide('aB', 1, 'ptAng', 'cd2', '0');
            f.AddGuide('aJ', 1, 'lptAng', 'cd2', '0');
            f.AddGuide('idx', 7, 'rw1', '2700000');
            f.AddGuide('idy', 12, 'rh1', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddHandlePolar('adj2','0','maxAng', undefined, '0', '0', 'xA', 'yA');
            f.AddHandlePolar('adj4','0','21599999', undefined, '0', '0', 'xE', 'yE');
            f.AddHandlePolar(undefined, '0', '0','adj1','0','maxAdj1', 'xF', 'yF');
            f.AddHandlePolar(undefined, '0', '0','adj5','0','25000', 'xB', 'yB');
            f.AddCnx('aL', 'xL', 'yL');
            f.AddCnx('lptAng', 'xKp', 'yKp');
            f.AddCnx('ptAng', 'xGp', 'yGp');
            f.AddCnx('aA', 'xA', 'yA');
            f.AddCnx('aB', 'xBp', 'yBp');
            f.AddCnx('aJ', 'xJp', 'yJp');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'xL', 'yL');
            f.AddPathCommand(2, 'xKp', 'yKp');
            f.AddPathCommand(2, 'xE', 'yE');
            f.AddPathCommand(3, 'rw1', 'rh1', 'st2', 'swAng');
            f.AddPathCommand(2, 'xGp', 'yGp');
            f.AddPathCommand(2, 'xA', 'yA');
            f.AddPathCommand(2, 'xBp', 'yBp');
            f.AddPathCommand(2, 'xC', 'yC');
            f.AddPathCommand(3, 'rw2', 'rh2', 'istAng', 'iswAng');
            f.AddPathCommand(2, 'xJp', 'yJp');
            f.AddPathCommand(6);
            break;
        }
        case 'leftRightRibbon':{
            f.AddAdj('adj1', 15, '50000');
            f.AddAdj('adj2', 15, '50000');
            f.AddAdj('adj3', 15, '16667');
            f.AddGuide('a3', 10, '0', 'adj3', '33333');
            f.AddGuide('maxAdj1', 1, '100000', '0', 'a3');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('w1', 1, 'wd2', '0', 'wd32');
            f.AddGuide('maxAdj2', 0, '100000', 'w1', 'ss');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('x1', 0, 'ss', 'a2', '100000');
            f.AddGuide('x4', 1, 'r', '0', 'x1');
            f.AddGuide('dy1', 0, 'h', 'a1', '200000');
            f.AddGuide('dy2', 0, 'h', 'a3', '-200000');
            f.AddGuide('ly1', 1, 'vc', 'dy2', 'dy1');
            f.AddGuide('ry4', 1, 'vc', 'dy1', 'dy2');
            f.AddGuide('ly2', 1, 'ly1', 'dy1', '0');
            f.AddGuide('ry3', 1, 'b', '0', 'ly2');
            f.AddGuide('ly4', 0, 'ly2', '2', '1');
            f.AddGuide('ry1', 1, 'b', '0', 'ly4');
            f.AddGuide('ly3', 1, 'ly4', '0', 'ly1');
            f.AddGuide('ry2', 1, 'b', '0', 'ly3');
            f.AddGuide('hR', 0, 'a3', 'ss', '400000');
            f.AddGuide('x2', 1, 'hc', '0', 'wd32');
            f.AddGuide('x3', 1, 'hc', 'wd32', '0');
            f.AddGuide('y1', 1, 'ly1', 'hR', '0');
            f.AddGuide('y2', 1, 'ry2', '0', 'hR');
            f.AddHandleXY(undefined, '0', '0','adj1','0','maxAdj1', 'x4', 'ry2');
            f.AddHandleXY('adj2','0','maxAdj2', undefined, '0', '0', 'x1', 't');
            f.AddHandleXY(undefined, '0', '0','adj3','0','33333', 'x3', 'ry2');
            f.AddCnx('0', 'r', 'ry3');
            f.AddCnx('cd4', 'x4', 'b');
            f.AddCnx('cd4', 'x1', 'ly4');
            f.AddCnx('cd2', 'l', 'ly2');
            f.AddCnx('_3cd4', 'x1', 't');
            f.AddCnx('_3cd4', 'x4', 'ry1');
            f.AddRect('x1', 'ly1', 'x4', 'ry4');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 'ly2');
            f.AddPathCommand(2, 'x1', 't');
            f.AddPathCommand(2, 'x1', 'ly1');
            f.AddPathCommand(2, 'hc', 'ly1');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', 'cd2');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', '-10800000');
            f.AddPathCommand(2, 'x4', 'ry2');
            f.AddPathCommand(2, 'x4', 'ry1');
            f.AddPathCommand(2, 'r', 'ry3');
            f.AddPathCommand(2, 'x4', 'b');
            f.AddPathCommand(2, 'x4', 'ry4');
            f.AddPathCommand(2, 'hc', 'ry4');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd4', 'cd4');
            f.AddPathCommand(2, 'x2', 'ly3');
            f.AddPathCommand(2, 'x1', 'ly3');
            f.AddPathCommand(2, 'x1', 'ly4');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'x3', 'y1');
            f.AddPathCommand(3, 'wd32', 'hR', '0', 'cd4');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', '-10800000');
            f.AddPathCommand(2, 'x3', 'ry2');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'ly2');
            f.AddPathCommand(2, 'x1', 't');
            f.AddPathCommand(2, 'x1', 'ly1');
            f.AddPathCommand(2, 'hc', 'ly1');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', 'cd2');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', '-10800000');
            f.AddPathCommand(2, 'x4', 'ry2');
            f.AddPathCommand(2, 'x4', 'ry1');
            f.AddPathCommand(2, 'r', 'ry3');
            f.AddPathCommand(2, 'x4', 'b');
            f.AddPathCommand(2, 'x4', 'ry4');
            f.AddPathCommand(2, 'hc', 'ry4');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd4', 'cd4');
            f.AddPathCommand(2, 'x2', 'ly3');
            f.AddPathCommand(2, 'x1', 'ly3');
            f.AddPathCommand(2, 'x1', 'ly4');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x3', 'y1');
            f.AddPathCommand(2, 'x3', 'ry2');
            f.AddPathCommand(1, 'x2', 'y2');
            f.AddPathCommand(2, 'x2', 'ly3');
            break;
        }
        case 'leftRightUpArrow':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '25000');
            f.AddAdj('adj3', 15, '25000');
            f.AddGuide('a2', 10, '0', 'adj2', '50000');
            f.AddGuide('maxAdj1', 0, 'a2', '2', '1');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('q1', 1, '100000', '0', 'maxAdj1');
            f.AddGuide('maxAdj3', 0, 'q1', '1', '2');
            f.AddGuide('a3', 10, '0', 'adj3', 'maxAdj3');
            f.AddGuide('x1', 0, 'ss', 'a3', '100000');
            f.AddGuide('dx2', 0, 'ss', 'a2', '100000');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x5', 1, 'hc', 'dx2', '0');
            f.AddGuide('dx3', 0, 'ss', 'a1', '200000');
            f.AddGuide('x3', 1, 'hc', '0', 'dx3');
            f.AddGuide('x4', 1, 'hc', 'dx3', '0');
            f.AddGuide('x6', 1, 'r', '0', 'x1');
            f.AddGuide('dy2', 0, 'ss', 'a2', '50000');
            f.AddGuide('y2', 1, 'b', '0', 'dy2');
            f.AddGuide('y4', 1, 'b', '0', 'dx2');
            f.AddGuide('y3', 1, 'y4', '0', 'dx3');
            f.AddGuide('y5', 1, 'y4', 'dx3', '0');
            f.AddGuide('il', 0, 'dx3', 'x1', 'dx2');
            f.AddGuide('ir', 1, 'r', '0', 'il');
            f.AddHandleXY('adj1','0','maxAdj1', undefined, '0', '0', 'x3', 'x1');
            f.AddHandleXY('adj2','0','50000', undefined, '0', '0', 'x2', 't');
            f.AddHandleXY(undefined, '0', '0','adj3','0','maxAdj3', 'r', 'x1');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'y4');
            f.AddCnx('cd4', 'hc', 'y5');
            f.AddCnx('0', 'r', 'y4');
            f.AddRect('il', 'y3', 'ir', 'y5');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y4');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(2, 'x1', 'y3');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(2, 'x3', 'x1');
            f.AddPathCommand(2, 'x2', 'x1');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'x5', 'x1');
            f.AddPathCommand(2, 'x4', 'x1');
            f.AddPathCommand(2, 'x4', 'y3');
            f.AddPathCommand(2, 'x6', 'y3');
            f.AddPathCommand(2, 'x6', 'y2');
            f.AddPathCommand(2, 'r', 'y4');
            f.AddPathCommand(2, 'x6', 'b');
            f.AddPathCommand(2, 'x6', 'y5');
            f.AddPathCommand(2, 'x1', 'y5');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'leftUpArrow':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '25000');
            f.AddAdj('adj3', 15, '25000');
            f.AddGuide('a2', 10, '0', 'adj2', '50000');
            f.AddGuide('maxAdj1', 0, 'a2', '2', '1');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('maxAdj3', 1, '100000', '0', 'maxAdj1');
            f.AddGuide('a3', 10, '0', 'adj3', 'maxAdj3');
            f.AddGuide('x1', 0, 'ss', 'a3', '100000');
            f.AddGuide('dx2', 0, 'ss', 'a2', '50000');
            f.AddGuide('x2', 1, 'r', '0', 'dx2');
            f.AddGuide('y2', 1, 'b', '0', 'dx2');
            f.AddGuide('dx4', 0, 'ss', 'a2', '100000');
            f.AddGuide('x4', 1, 'r', '0', 'dx4');
            f.AddGuide('y4', 1, 'b', '0', 'dx4');
            f.AddGuide('dx3', 0, 'ss', 'a1', '200000');
            f.AddGuide('x3', 1, 'x4', '0', 'dx3');
            f.AddGuide('x5', 1, 'x4', 'dx3', '0');
            f.AddGuide('y3', 1, 'y4', '0', 'dx3');
            f.AddGuide('y5', 1, 'y4', 'dx3', '0');
            f.AddGuide('il', 0, 'dx3', 'x1', 'dx4');
            f.AddGuide('cx1', 2, 'x1', 'x5', '2');
            f.AddGuide('cy1', 2, 'x1', 'y5', '2');
            f.AddHandleXY(undefined, '0', '0','adj1','0','maxAdj1', 'x3', 'y3');
            f.AddHandleXY('adj2','0','50000', undefined, '0', '0', 'x2', 't');
            f.AddHandleXY(undefined, '0', '0','adj3','0','maxAdj3', 'x3', 'x1');
            f.AddCnx('_3cd4', 'x4', 't');
            f.AddCnx('cd2', 'x2', 'x1');
            f.AddCnx('_3cd4', 'x1', 'y2');
            f.AddCnx('cd2', 'l', 'y4');
            f.AddCnx('cd4', 'x1', 'b');
            f.AddCnx('cd4', 'cx1', 'y5');
            f.AddCnx('0', 'x5', 'cy1');
            f.AddCnx('0', 'r', 'x1');
            f.AddRect('il', 'y3', 'x4', 'y5');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y4');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(2, 'x1', 'y3');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(2, 'x3', 'x1');
            f.AddPathCommand(2, 'x2', 'x1');
            f.AddPathCommand(2, 'x4', 't');
            f.AddPathCommand(2, 'r', 'x1');
            f.AddPathCommand(2, 'x5', 'x1');
            f.AddPathCommand(2, 'x5', 'y5');
            f.AddPathCommand(2, 'x1', 'y5');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'lightningBolt':{
            f.AddGuide('x1', 0, 'w', '5022', '21600');
            f.AddGuide('x3', 0, 'w', '8472', '21600');
            f.AddGuide('x4', 0, 'w', '8757', '21600');
            f.AddGuide('x5', 0, 'w', '10012', '21600');
            f.AddGuide('x8', 0, 'w', '12860', '21600');
            f.AddGuide('x9', 0, 'w', '13917', '21600');
            f.AddGuide('x11', 0, 'w', '16577', '21600');
            f.AddGuide('y1', 0, 'h', '3890', '21600');
            f.AddGuide('y2', 0, 'h', '6080', '21600');
            f.AddGuide('y4', 0, 'h', '7437', '21600');
            f.AddGuide('y6', 0, 'h', '9705', '21600');
            f.AddGuide('y7', 0, 'h', '12007', '21600');
            f.AddGuide('y10', 0, 'h', '14277', '21600');
            f.AddGuide('y11', 0, 'h', '14915', '21600');
            f.AddCnx('_3cd4', 'x3', 't');
            f.AddCnx('_3cd4', 'l', 'y1');
            f.AddCnx('cd2', 'x1', 'y6');
            f.AddCnx('cd2', 'x5', 'y11');
            f.AddCnx('cd4', 'r', 'b');
            f.AddCnx('0', 'x11', 'y7');
            f.AddCnx('0', 'x8', 'y2');
            f.AddRect('x4', 'y4', 'x9', 'y10');
            f.AddPathCommand(0,undefined, undefined, undefined, 21600, 21600);
            f.AddPathCommand(1, '8472', '0');
            f.AddPathCommand(2, '12860', '6080');
            f.AddPathCommand(2, '11050', '6797');
            f.AddPathCommand(2, '16577', '12007');
            f.AddPathCommand(2, '14767', '12877');
            f.AddPathCommand(2, '21600', '21600');
            f.AddPathCommand(2, '10012', '14915');
            f.AddPathCommand(2, '12222', '13987');
            f.AddPathCommand(2, '5022', '9705');
            f.AddPathCommand(2, '7602', '8382');
            f.AddPathCommand(2, '0', '3890');
            f.AddPathCommand(6);
            break;
        }
        case 'line':{
            f.AddCnx('cd4', 'l', 't');
            f.AddCnx('_3cd4', 'r', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 'b');
            break;
        }
        case 'lineInv':{
            f.AddCnx('cd4', 'l', 'b');
            f.AddCnx('_3cd4', 'r', 't');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'r', 't');
            break;
        }
        case 'mathDivide':{
            f.AddAdj('adj1', 15, '23520');
            f.AddAdj('adj2', 15, '5880');
            f.AddAdj('adj3', 15, '11760');
            f.AddGuide('a1', 10, '1000', 'adj1', '36745');
            f.AddGuide('ma1', 1, '0', '0', 'a1');
            f.AddGuide('ma3h', 2, '73490', 'ma1', '4');
            f.AddGuide('ma3w', 0, '36745', 'w', 'h');
            f.AddGuide('maxAdj3', 16, 'ma3h', 'ma3w');
            f.AddGuide('a3', 10, '1000', 'adj3', 'maxAdj3');
            f.AddGuide('m4a3', 0, '-4', 'a3', '1');
            f.AddGuide('maxAdj2', 1, '73490', 'm4a3', 'a1');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('dy1', 0, 'h', 'a1', '200000');
            f.AddGuide('yg', 0, 'h', 'a2', '100000');
            f.AddGuide('rad', 0, 'h', 'a3', '100000');
            f.AddGuide('dx1', 0, 'w', '73490', '200000');
            f.AddGuide('y3', 1, 'vc', '0', 'dy1');
            f.AddGuide('y4', 1, 'vc', 'dy1', '0');
            f.AddGuide('a', 1, 'yg', 'rad', '0');
            f.AddGuide('y2', 1, 'y3', '0', 'a');
            f.AddGuide('y1', 1, 'y2', '0', 'rad');
            f.AddGuide('y5', 1, 'b', '0', 'y1');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x3', 1, 'hc', 'dx1', '0');
            f.AddGuide('x2', 1, 'hc', '0', 'rad');
            f.AddHandleXY(undefined, '0', '0','adj1','1000','36745', 'l', 'y3');
            f.AddHandleXY(undefined, '0', '0','adj2','0','maxAdj2', 'r', 'y2');
            f.AddHandleXY('adj3','1000','maxAdj3', undefined, '0', '0', 'x2', 't');
            f.AddCnx('0', 'x3', 'vc');
            f.AddCnx('cd4', 'hc', 'y5');
            f.AddCnx('cd2', 'x1', 'vc');
            f.AddCnx('_3cd4', 'hc', 'y1');
            f.AddRect('x1', 'y3', 'x3', 'y4');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'hc', 'y1');
            f.AddPathCommand(3, 'rad', 'rad', '_3cd4', '21600000');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'hc', 'y5');
            f.AddPathCommand(3, 'rad', 'rad', 'cd4', '21600000');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x1', 'y3');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(2, 'x3', 'y4');
            f.AddPathCommand(2, 'x1', 'y4');
            f.AddPathCommand(6);
            break;
        }
        case 'mathEqual':
        {
            f.AddAdj('adj1', 15, '23520');
            f.AddAdj('adj2', 15, '11760');
            f.AddGuide('a1', 10, '0', 'adj1', '36745');
            f.AddGuide('2a1', 0, 'a1', '2', '1');
            f.AddGuide('mAdj2', 1, '100000', '0', '2a1');
            f.AddGuide('a2', 10, '0', 'adj2', 'mAdj2');
            f.AddGuide('dy1', 0, 'h', 'a1', '100000');
            f.AddGuide('dy2', 0, 'h', 'a2', '200000');
            f.AddGuide('dx1', 0, 'w', '73490', '200000');
            f.AddGuide('y2', 1, 'vc', '0', 'dy2');
            f.AddGuide('y3', 1, 'vc', 'dy2', '0');
            f.AddGuide('y1', 1, 'y2', '0', 'dy1');
            f.AddGuide('y4', 1, 'y3', 'dy1', '0');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', 'dx1', '0');
            f.AddGuide('yC1', 2, 'y1', 'y2', '2');
            f.AddGuide('yC2', 2, 'y3', 'y4', '2');
            f.AddHandleXY(undefined, '0', '0','adj1','0','36745', 'l', 'y1');
            f.AddHandleXY(undefined, '0', '0','adj2','0','mAdj2', 'r', 'y2');
            f.AddCnx('0', 'x2', 'yC1');
            f.AddCnx('0', 'x2', 'yC2');
            f.AddCnx('cd4', 'hc', 'y4');
            f.AddCnx('cd2', 'x1', 'yC1');
            f.AddCnx('cd2', 'x1', 'yC2');
            f.AddCnx('_3cd4', 'hc', 'y1');
            f.AddRect('x1', 'y1', 'x2', 'y4');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x1', 'y3');
            f.AddPathCommand(2, 'x2', 'y3');
            f.AddPathCommand(2, 'x2', 'y4');
            f.AddPathCommand(2, 'x1', 'y4');
            f.AddPathCommand(6);
            break;
        }
        case 'mathMinus':{
            f.AddAdj('adj1', 15, '23520');
            f.AddGuide('a1', 10, '0', 'adj1', '100000');
            f.AddGuide('dy1', 0, 'h', 'a1', '200000');
            f.AddGuide('dx1', 0, 'w', '73490', '200000');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y2', 1, 'vc', 'dy1', '0');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', 'dx1', '0');
            f.AddHandleXY(undefined, '0', '0','adj1','0','100000', 'l', 'y1');
            f.AddCnx('0', 'x2', 'vc');
            f.AddCnx('cd4', 'hc', 'y2');
            f.AddCnx('cd2', 'x1', 'vc');
            f.AddCnx('_3cd4', 'hc', 'y1');
            f.AddRect('x1', 'y1', 'x2', 'y2');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(6);
            break;
        }
        case 'mathMultiply':{
            f.AddAdj('adj1', 15, '23520');
            f.AddGuide('a1', 10, '0', 'adj1', '51965');
            f.AddGuide('th', 0, 'ss', 'a1', '100000');
            f.AddGuide('a', 5, 'w', 'h');
            f.AddGuide('sa', 12, '1', 'a');
            f.AddGuide('ca', 7, '1', 'a');
            f.AddGuide('ta', 14, '1', 'a');
            f.AddGuide('dl', 9, 'w', 'h', '0');
            f.AddGuide('rw', 0, 'dl', '51965', '100000');
            f.AddGuide('lM', 1, 'dl', '0', 'rw');
            f.AddGuide('xM', 0, 'ca', 'lM', '2');
            f.AddGuide('yM', 0, 'sa', 'lM', '2');
            f.AddGuide('dxAM', 0, 'sa', 'th', '2');
            f.AddGuide('dyAM', 0, 'ca', 'th', '2');
            f.AddGuide('xA', 1, 'xM', '0', 'dxAM');
            f.AddGuide('yA', 1, 'yM', 'dyAM', '0');
            f.AddGuide('xB', 1, 'xM', 'dxAM', '0');
            f.AddGuide('yB', 1, 'yM', '0', 'dyAM');
            f.AddGuide('xBC', 1, 'hc', '0', 'xB');
            f.AddGuide('yBC', 0, 'xBC', 'ta', '1');
            f.AddGuide('yC', 1, 'yBC', 'yB', '0');
            f.AddGuide('xD', 1, 'r', '0', 'xB');
            f.AddGuide('xE', 1, 'r', '0', 'xA');
            f.AddGuide('yFE', 1, 'vc', '0', 'yA');
            f.AddGuide('xFE', 0, 'yFE', '1', 'ta');
            f.AddGuide('xF', 1, 'xE', '0', 'xFE');
            f.AddGuide('xL', 1, 'xA', 'xFE', '0');
            f.AddGuide('yG', 1, 'b', '0', 'yA');
            f.AddGuide('yH', 1, 'b', '0', 'yB');
            f.AddGuide('yI', 1, 'b', '0', 'yC');
            f.AddGuide('xC2', 1, 'r', '0', 'xM');
            f.AddGuide('yC3', 1, 'b', '0', 'yM');
            f.AddHandleXY(undefined, '0', '0','adj1','0','51965', 'l', 'th');
            f.AddCnx('cd2', 'xM', 'yM');
            f.AddCnx('_3cd4', 'xC2', 'yM');
            f.AddCnx('0', 'xC2', 'yC3');
            f.AddCnx('cd4', 'xM', 'yC3');
            f.AddRect('xA', 'yB', 'xE', 'yH');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'xA', 'yA');
            f.AddPathCommand(2, 'xB', 'yB');
            f.AddPathCommand(2, 'hc', 'yC');
            f.AddPathCommand(2, 'xD', 'yB');
            f.AddPathCommand(2, 'xE', 'yA');
            f.AddPathCommand(2, 'xF', 'vc');
            f.AddPathCommand(2, 'xE', 'yG');
            f.AddPathCommand(2, 'xD', 'yH');
            f.AddPathCommand(2, 'hc', 'yI');
            f.AddPathCommand(2, 'xB', 'yH');
            f.AddPathCommand(2, 'xA', 'yG');
            f.AddPathCommand(2, 'xL', 'vc');
            f.AddPathCommand(6);
            break;
        }
        case 'mathNotEqual':{
            f.AddAdj('adj1', 15, '23520');
            f.AddAdj('adj2', 15, '6600000');
            f.AddAdj('adj3', 15, '11760');
            f.AddGuide('a1', 10, '0', 'adj1', '50000');
            f.AddGuide('crAng', 10, '4200000', 'adj2', '6600000');
            f.AddGuide('2a1', 0, 'a1', '2', '1');
            f.AddGuide('maxAdj3', 1, '100000', '0', '2a1');
            f.AddGuide('a3', 10, '0', 'adj3', 'maxAdj3');
            f.AddGuide('dy1', 0, 'h', 'a1', '100000');
            f.AddGuide('dy2', 0, 'h', 'a3', '200000');
            f.AddGuide('dx1', 0, 'w', '73490', '200000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x8', 1, 'hc', 'dx1', '0');
            f.AddGuide('y2', 1, 'vc', '0', 'dy2');
            f.AddGuide('y3', 1, 'vc', 'dy2', '0');
            f.AddGuide('y1', 1, 'y2', '0', 'dy1');
            f.AddGuide('y4', 1, 'y3', 'dy1', '0');
            f.AddGuide('cadj2', 1, 'crAng', '0', 'cd4');
            f.AddGuide('xadj2', 14, 'hd2', 'cadj2');
            f.AddGuide('len', 9, 'xadj2', 'hd2', '0');
            f.AddGuide('bhw', 0, 'len', 'dy1', 'hd2');
            f.AddGuide('bhw2', 0, 'bhw', '1', '2');
            f.AddGuide('x7', 1, 'hc', 'xadj2', 'bhw2');
            f.AddGuide('dx67', 0, 'xadj2', 'y1', 'hd2');
            f.AddGuide('x6', 1, 'x7', '0', 'dx67');
            f.AddGuide('dx57', 0, 'xadj2', 'y2', 'hd2');
            f.AddGuide('x5', 1, 'x7', '0', 'dx57');
            f.AddGuide('dx47', 0, 'xadj2', 'y3', 'hd2');
            f.AddGuide('x4', 1, 'x7', '0', 'dx47');
            f.AddGuide('dx37', 0, 'xadj2', 'y4', 'hd2');
            f.AddGuide('x3', 1, 'x7', '0', 'dx37');
            f.AddGuide('dx27', 0, 'xadj2', '2', '1');
            f.AddGuide('x2', 1, 'x7', '0', 'dx27');
            f.AddGuide('rx7', 1, 'x7', 'bhw', '0');
            f.AddGuide('rx6', 1, 'x6', 'bhw', '0');
            f.AddGuide('rx5', 1, 'x5', 'bhw', '0');
            f.AddGuide('rx4', 1, 'x4', 'bhw', '0');
            f.AddGuide('rx3', 1, 'x3', 'bhw', '0');
            f.AddGuide('rx2', 1, 'x2', 'bhw', '0');
            f.AddGuide('dx7', 0, 'dy1', 'hd2', 'len');
            f.AddGuide('rxt', 1, 'x7', 'dx7', '0');
            f.AddGuide('lxt', 1, 'rx7', '0', 'dx7');
            f.AddGuide('rx', 3, 'cadj2', 'rxt', 'rx7');
            f.AddGuide('lx', 3, 'cadj2', 'x7', 'lxt');
            f.AddGuide('dy3', 0, 'dy1', 'xadj2', 'len');
            f.AddGuide('dy4', 1, '0', '0', 'dy3');
            f.AddGuide('ry', 3, 'cadj2', 'dy3', 't');
            f.AddGuide('ly', 3, 'cadj2', 't', 'dy4');
            f.AddGuide('dlx', 1, 'w', '0', 'rx');
            f.AddGuide('drx', 1, 'w', '0', 'lx');
            f.AddGuide('dly', 1, 'h', '0', 'ry');
            f.AddGuide('dry', 1, 'h', '0', 'ly');
            f.AddGuide('xC1', 2, 'rx', 'lx', '2');
            f.AddGuide('xC2', 2, 'drx', 'dlx', '2');
            f.AddGuide('yC1', 2, 'ry', 'ly', '2');
            f.AddGuide('yC2', 2, 'y1', 'y2', '2');
            f.AddGuide('yC3', 2, 'y3', 'y4', '2');
            f.AddGuide('yC4', 2, 'dry', 'dly', '2');
            f.AddHandleXY(undefined, '0', '0','adj1','0','50000', 'l', 'y1');
            f.AddHandlePolar('adj2','4200000','6600000', undefined, '0', '0', 'lx', 't');
            f.AddHandleXY(undefined, '0', '0','adj3','0','maxAdj3', 'r', 'y2');
            f.AddCnx('0', 'x8', 'yC2');
            f.AddCnx('0', 'x8', 'yC3');
            f.AddCnx('cd4', 'xC2', 'yC4');
            f.AddCnx('cd2', 'x1', 'yC2');
            f.AddCnx('cd2', 'x1', 'yC3');
            f.AddCnx('_3cd4', 'xC1', 'yC1');
            f.AddRect('x1', 'y1', 'x8', 'y4');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'x6', 'y1');
            f.AddPathCommand(2, 'lx', 'ly');
            f.AddPathCommand(2, 'rx', 'ry');
            f.AddPathCommand(2, 'rx6', 'y1');
            f.AddPathCommand(2, 'x8', 'y1');
            f.AddPathCommand(2, 'x8', 'y2');
            f.AddPathCommand(2, 'rx5', 'y2');
            f.AddPathCommand(2, 'rx4', 'y3');
            f.AddPathCommand(2, 'x8', 'y3');
            f.AddPathCommand(2, 'x8', 'y4');
            f.AddPathCommand(2, 'rx3', 'y4');
            f.AddPathCommand(2, 'drx', 'dry');
            f.AddPathCommand(2, 'dlx', 'dly');
            f.AddPathCommand(2, 'x3', 'y4');
            f.AddPathCommand(2, 'x1', 'y4');
            f.AddPathCommand(2, 'x1', 'y3');
            f.AddPathCommand(2, 'x4', 'y3');
            f.AddPathCommand(2, 'x5', 'y2');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(6);
            break;
        }
        case 'mathPlus':{
            f.AddAdj('adj1', 15, '23520');
            f.AddGuide('a1', 10, '0', 'adj1', '73490');
            f.AddGuide('dx1', 0, 'w', '73490', '200000');
            f.AddGuide('dy1', 0, 'h', '73490', '200000');
            f.AddGuide('dx2', 0, 'ss', 'a1', '200000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'hc', 'dx2', '0');
            f.AddGuide('x4', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y2', 1, 'vc', '0', 'dx2');
            f.AddGuide('y3', 1, 'vc', 'dx2', '0');
            f.AddGuide('y4', 1, 'vc', 'dy1', '0');
            f.AddHandleXY(undefined, '0', '0','adj1','0','73490', 'l', 'y2');
            f.AddCnx('0', 'x4', 'vc');
            f.AddCnx('cd4', 'hc', 'y4');
            f.AddCnx('cd2', 'x1', 'vc');
            f.AddCnx('_3cd4', 'hc', 'y1');
            f.AddRect('x1', 'y2', 'x4', 'y3');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y2');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(2, 'x3', 'y2');
            f.AddPathCommand(2, 'x4', 'y2');
            f.AddPathCommand(2, 'x4', 'y3');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(2, 'x3', 'y4');
            f.AddPathCommand(2, 'x2', 'y4');
            f.AddPathCommand(2, 'x2', 'y3');
            f.AddPathCommand(2, 'x1', 'y3');
            f.AddPathCommand(6);
            break;
        }
        case 'moon':{
            f.AddAdj('adj', 15, '50000');
            f.AddGuide('a', 10, '0', 'adj', '875000');
            f.AddGuide('g0', 0, 'ss', 'a', '100000');
            f.AddGuide('g0w', 0, 'g0', 'w', 'ss');
            f.AddGuide('g1', 1, 'ss', '0', 'g0');
            f.AddGuide('g2', 0, 'g0', 'g0', 'g1');
            f.AddGuide('g3', 0, 'ss', 'ss', 'g1');
            f.AddGuide('g4', 0, 'g3', '2', '1');
            f.AddGuide('g5', 1, 'g4', '0', 'g2');
            f.AddGuide('g6', 1, 'g5', '0', 'g0');
            f.AddGuide('g6w', 0, 'g6', 'w', 'ss');
            f.AddGuide('g7', 0, 'g5', '1', '2');
            f.AddGuide('g8', 1, 'g7', '0', 'g0');
            f.AddGuide('dy1', 0, 'g8', 'hd2', 'ss');
            f.AddGuide('g10h', 1, 'vc', '0', 'dy1');
            f.AddGuide('g11h', 1, 'vc', 'dy1', '0');
            f.AddGuide('g12', 0, 'g0', '9598', '32768');
            f.AddGuide('g12w', 0, 'g12', 'w', 'ss');
            f.AddGuide('g13', 1, 'ss', '0', 'g12');
            f.AddGuide('q1', 0, 'ss', 'ss', '1');
            f.AddGuide('q2', 0, 'g13', 'g13', '1');
            f.AddGuide('q3', 1, 'q1', '0', 'q2');
            f.AddGuide('q4', 13, 'q3');
            f.AddGuide('dy4', 0, 'q4', 'hd2', 'ss');
            f.AddGuide('g15h', 1, 'vc', '0', 'dy4');
            f.AddGuide('g16h', 1, 'vc', 'dy4', '0');
            f.AddGuide('g17w', 1, 'g6w', '0', 'g0w');
            f.AddGuide('g18w', 0, 'g17w', '1', '2');
            f.AddGuide('dx2p', 1, 'g0w', 'g18w', 'w');
            f.AddGuide('dx2', 0, 'dx2p', '-1', '1');
            f.AddGuide('dy2', 0, 'hd2', '-1', '1');
            f.AddGuide('stAng1', 5, 'dx2', 'dy2');
            f.AddGuide('enAngp1', 5, 'dx2', 'hd2');
            f.AddGuide('enAng1', 1, 'enAngp1', '0', '21600000');
            f.AddGuide('swAng1', 1, 'enAng1', '0', 'stAng1');
            f.AddHandleXY('adj','0','87500', undefined, '0', '0', 'g0w', 'vc');
            f.AddCnx('_3cd4', 'r', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'r', 'b');
            f.AddCnx('0', 'g0w', 'vc');
            f.AddRect('g12w', 'g15h', 'g0w', 'g16h');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'r', 'b');
            f.AddPathCommand(3, 'w', 'hd2', 'cd4', 'cd2');
            f.AddPathCommand(3, 'g18w', 'dy1', 'stAng1', 'swAng1');
            f.AddPathCommand(6);
            break;
        }
        case 'nonIsoscelesTrapezoid':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '25000');
            f.AddGuide('maxAdj', 0, '50000', 'w', 'ss');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj');
            f.AddGuide('x1', 0, 'ss', 'a1', '200000');
            f.AddGuide('x2', 0, 'ss', 'a1', '100000');
            f.AddGuide('dx3', 0, 'ss', 'a2', '100000');
            f.AddGuide('x3', 1, 'r', '0', 'dx3');
            f.AddGuide('x4', 2, 'r', 'x3', '2');
            f.AddGuide('il', 0, 'wd3', 'a1', 'maxAdj');
            f.AddGuide('adjm', 8, 'a1', 'a2');
            f.AddGuide('it', 0, 'hd3', 'adjm', 'maxAdj');
            f.AddGuide('irt', 0, 'wd3', 'a2', 'maxAdj');
            f.AddGuide('ir', 1, 'r', '0', 'irt');
            f.AddHandleXY('adj1','0','maxAdj', undefined, '0', '0', 'x2', 't');
            f.AddHandleXY('adj2','0','maxAdj', undefined, '0', '0', 'x3', 't');
            f.AddCnx('0', 'x4', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'x1', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('il', 'it', 'ir', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'x3', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'noSmoking':{
            f.AddAdj('adj', 15, '18750');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('dr', 0, 'ss', 'a', '100000');
            f.AddGuide('iwd2', 1, 'wd2', '0', 'dr');
            f.AddGuide('ihd2', 1, 'hd2', '0', 'dr');
            f.AddGuide('ang', 5, 'w', 'h');
            f.AddGuide('ct', 7, 'ihd2', 'ang');
            f.AddGuide('st', 12, 'iwd2', 'ang');
            f.AddGuide('m', 9, 'ct', 'st', '0');
            f.AddGuide('n', 0, 'iwd2', 'ihd2', 'm');
            f.AddGuide('drd2', 0, 'dr', '1', '2');
            f.AddGuide('dang', 5, 'n', 'drd2');
            f.AddGuide('2dang', 0, 'dang', '2', '1');
            f.AddGuide('swAng', 1, '-10800000', '2dang', '0');
            f.AddGuide('t3', 5, 'w', 'h');
            f.AddGuide('stAng1', 1, 't3', '0', 'dang');
            f.AddGuide('stAng2', 1, 'stAng1', '0', 'cd2');
            f.AddGuide('ct1', 7, 'ihd2', 'stAng1');
            f.AddGuide('st1', 12, 'iwd2', 'stAng1');
            f.AddGuide('m1', 9, 'ct1', 'st1', '0');
            f.AddGuide('n1', 0, 'iwd2', 'ihd2', 'm1');
            f.AddGuide('dx1', 7, 'n1', 'stAng1');
            f.AddGuide('dy1', 12, 'n1', 'stAng1');
            f.AddGuide('x1', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', 'dy1', '0');
            f.AddGuide('x2', 1, 'hc', '0', 'dx1');
            f.AddGuide('y2', 1, 'vc', '0', 'dy1');
            f.AddGuide('idx', 7, 'wd2', '2700000');
            f.AddGuide('idy', 12, 'hd2', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddHandlePolar(undefined, '0', '0','adj','0','50000', 'dr', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('_3cd4', 'il', 'it');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'il', 'ib');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd4', 'ir', 'ib');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('_3cd4', 'ir', 'it');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
           f.AddPathCommand(3, 'iwd2', 'ihd2', 'stAng1', 'swAng');
             f.AddPathCommand(2, 'x1', 'y1');
          // f.AddPathCommand(6);
            f.AddPathCommand(1, 'x2', 'y2');
            f.AddPathCommand(3, 'iwd2', 'ihd2', 'stAng2', 'swAng');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd2', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '_3cd4', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', '0', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd4', 'cd4');
            f.AddPathCommand(6);

            break;
        }
        case 'notchedRightArrow':{
            f.AddAdj('adj1', 15, '50000');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('maxAdj2', 0, '100000', 'w', 'ss');
            f.AddGuide('a1', 10, '0', 'adj1', '100000');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('dx2', 0, 'ss', 'a2', '100000');
            f.AddGuide('x2', 1, 'r', '0', 'dx2');
            f.AddGuide('dy1', 0, 'h', 'a1', '200000');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y2', 1, 'vc', 'dy1', '0');
            f.AddGuide('x1', 0, 'dy1', 'dx2', 'hd2');
            f.AddGuide('x3', 1, 'r', '0', 'x1');
            f.AddHandleXY(undefined, '0', '0','adj1','0','100000', 'r', 'y1');
            f.AddHandleXY('adj2','0','maxAdj2', undefined, '0', '0', 'x2', 't');
            f.AddCnx('_3cd4', 'x2', 't');
            f.AddCnx('cd2', 'x1', 'vc');
            f.AddCnx('cd4', 'x2', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('x1', 'y1', 'x3', 'y2');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'x2', 'b');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'l', 'y2');
            f.AddPathCommand(2, 'x1', 'vc');
            f.AddPathCommand(6);
            break;
        }
        case 'octagon':{
            f.AddAdj('adj', 15, '29289');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('x1', 0, 'ss', 'a', '100000');
            f.AddGuide('x2', 1, 'r', '0', 'x1');
            f.AddGuide('y2', 1, 'b', '0', 'x1');
            f.AddGuide('il', 0, 'x1', '1', '2');
            f.AddGuide('ir', 1, 'r', '0', 'il');
            f.AddGuide('ib', 1, 'b', '0', 'il');
            f.AddHandleXY('adj','0','50000', undefined, '0', '0', 'x1', 't');
            f.AddCnx('0', 'r', 'x1');
            f.AddCnx('0', 'r', 'y2');
            f.AddCnx('cd4', 'x2', 'b');
            f.AddCnx('cd4', 'x1', 'b');
            f.AddCnx('cd2', 'l', 'y2');
            f.AddCnx('cd2', 'l', 'x1');
            f.AddCnx('_3cd4', 'x1', 't');
            f.AddCnx('_3cd4', 'x2', 't');
            f.AddRect('il', 'il', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'x1');
            f.AddPathCommand(2, 'x1', 't');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'r', 'x1');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(2, 'x2', 'b');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(2, 'l', 'y2');
            f.AddPathCommand(6);
            break;
        }
        case 'parallelogram':{
            f.AddAdj('adj', 15, '25000');
            f.AddGuide('maxAdj', 0, '100000', 'w', 'ss');
            f.AddGuide('a', 10, '0', 'adj', 'maxAdj');
            f.AddGuide('x1', 0, 'ss', 'a', '200000');
            f.AddGuide('x2', 0, 'ss', 'a', '100000');
            f.AddGuide('x6', 1, 'r', '0', 'x1');
            f.AddGuide('x5', 1, 'r', '0', 'x2');
            f.AddGuide('x3', 0, 'x5', '1', '2');
            f.AddGuide('x4', 1, 'r', '0', 'x3');
            f.AddGuide('il', 0, 'wd2', 'a', 'maxAdj');
            f.AddGuide('q1', 0, '5', 'a', 'maxAdj');
            f.AddGuide('q2', 2, '1', 'q1', '12');
            f.AddGuide('il', 0, 'q2', 'w', '1');
            f.AddGuide('it', 0, 'q2', 'h', '1');
            f.AddGuide('ir', 1, 'r', '0', 'il');
            f.AddGuide('ib', 1, 'b', '0', 'it');
            f.AddGuide('q3', 0, 'h', 'hc', 'x2');
            f.AddGuide('y1', 10, '0', 'q3', 'h');
            f.AddGuide('y2', 1, 'b', '0', 'y1');
            f.AddHandleXY('adj','0','maxAdj', undefined, '0', '0', 'x2', 't');
            f.AddCnx('_3cd4', 'hc', 'y2');
            f.AddCnx('_3cd4', 'x4', 't');
            f.AddCnx('0', 'x6', 'vc');
            f.AddCnx('cd4', 'x3', 'b');
            f.AddCnx('cd4', 'hc', 'y1');
            f.AddCnx('cd2', 'x1', 'vc');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'x5', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'pentagon':{
            f.AddAdj('hf', 15, '105146');
            f.AddAdj('vf', 15, '110557');
            f.AddGuide('swd2', 0, 'wd2', 'hf', '100000');
            f.AddGuide('shd2', 0, 'hd2', 'vf', '100000');
            f.AddGuide('svc', 0, 'vc', 'vf', '100000');
            f.AddGuide('dx1', 7, 'swd2', '1080000');
            f.AddGuide('dx2', 7, 'swd2', '18360000');
            f.AddGuide('dy1', 12, 'shd2', '1080000');
            f.AddGuide('dy2', 12, 'shd2', '18360000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'hc', 'dx2', '0');
            f.AddGuide('x4', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'svc', '0', 'dy1');
            f.AddGuide('y2', 1, 'svc', '0', 'dy2');
            f.AddGuide('it', 0, 'y1', 'dx2', 'dx1');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'x1', 'y1');
            f.AddCnx('cd4', 'x2', 'y2');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd4', 'x3', 'y2');
            f.AddCnx('0', 'x4', 'y1');
            f.AddRect('x2', 'it', 'x3', 'y2');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(2, 'x3', 'y2');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(6);
            break;
        }
        case 'pie':{
            f.AddAdj('adj1', 15, '0');
            f.AddAdj('adj2', 15, '16200000');
            f.AddGuide('stAng', 10, '0', 'adj1', '21599999');
            f.AddGuide('enAng', 10, '0', 'adj2', '21599999');
            f.AddGuide('sw1', 1, 'enAng', '0', 'stAng');
            f.AddGuide('sw2', 1, 'sw1', '21600000', '0');
            f.AddGuide('swAng', 3, 'sw1', 'sw1', 'sw2');
            f.AddGuide('wt1', 12, 'wd2', 'stAng');
            f.AddGuide('ht1', 7, 'hd2', 'stAng');
            f.AddGuide('dx1', 6, 'wd2', 'ht1', 'wt1');
            f.AddGuide('dy1', 11, 'hd2', 'ht1', 'wt1');
            f.AddGuide('x1', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', 'dy1', '0');
            f.AddGuide('wt2', 12, 'wd2', 'enAng');
            f.AddGuide('ht2', 7, 'hd2', 'enAng');
            f.AddGuide('dx2', 6, 'wd2', 'ht2', 'wt2');
            f.AddGuide('dy2', 11, 'hd2', 'ht2', 'wt2');
            f.AddGuide('x2', 1, 'hc', 'dx2', '0');
            f.AddGuide('y2', 1, 'vc', 'dy2', '0');
            f.AddGuide('idx', 7, 'hc', '2700000');
            f.AddGuide('idy', 12, 'vc', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddHandlePolar('adj1','0','21599999', undefined, '0', '0', 'x1', 'y1');
            f.AddHandlePolar('adj2','0','21599999', undefined, '0', '0', 'x2', 'y2');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(3, 'wd2', 'hd2', 'stAng', 'swAng');
            f.AddPathCommand(2, 'hc', 'vc');
            f.AddPathCommand(6);
            break;
        }
        case 'pieWedge':{
            f.AddGuide('g1', 7, 'w', '13500000');
            f.AddGuide('g2', 12, 'h', '13500000');
            f.AddGuide('x1', 1, 'r', 'g1', '0');
            f.AddGuide('y1', 1, 'b', 'g2', '0');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddRect('x1', 'y1', 'r', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(3, 'w', 'h', 'cd2', 'cd4');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'plaque':{
            f.AddAdj('adj', 15, '16667');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('x1', 0, 'ss', 'a', '100000');
            f.AddGuide('x2', 1, 'r', '0', 'x1');
            f.AddGuide('y2', 1, 'b', '0', 'x1');
            f.AddGuide('il', 0, 'x1', '70711', '100000');
            f.AddGuide('ir', 1, 'r', '0', 'il');
            f.AddGuide('ib', 1, 'b', '0', 'il');
            f.AddHandleXY('adj','0','50000', undefined, '0', '0', 'x1', 't');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('il', 'il', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'x1');
            f.AddPathCommand(3, 'x1', 'x1', 'cd4', '-5400000');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(3, 'x1', 'x1', 'cd2', '-5400000');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(3, 'x1', 'x1', '_3cd4', '-5400000');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(3, 'x1', 'x1', '0', '-5400000');
            f.AddPathCommand(6);
            break;
        }
        case 'plaqueTabs':{
            f.AddGuide('md', 9, 'w', 'h', '0');
            f.AddGuide('dx', 0, '1', 'md', '20');
            f.AddGuide('y1', 1, '0', 'b', 'dx');
            f.AddGuide('x1', 1, '0', 'r', 'dx');
            f.AddCnx('cd2', 'l', 't');
            f.AddCnx('cd2', 'l', 'dx');
            f.AddCnx('cd2', 'l', 'y1');
            f.AddCnx('cd2', 'l', 'b');
            f.AddCnx('_3cd4', 'dx', 't');
            f.AddCnx('_3cd4', 'x1', 't');
            f.AddCnx('cd4', 'dx', 'b');
            f.AddCnx('cd4', 'x1', 'b');
            f.AddCnx('0', 'r', 't');
            f.AddCnx('0', 'r', 'dx');
            f.AddCnx('0', 'r', 'y1');
            f.AddCnx('0', 'r', 'b');
            f.AddRect('dx', 'dx', 'x1', 'y1');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'dx', 't');
            f.AddPathCommand(3, 'dx', 'dx', '0', 'cd4');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(3, 'dx', 'dx', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'r', 't');
            f.AddPathCommand(2, 'r', 'dx');
            f.AddPathCommand(3, 'dx', 'dx', 'cd4', 'cd4');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'b');
            f.AddPathCommand(3, 'dx', 'dx', 'cd2', 'cd4');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'plus':{
            f.AddAdj('adj', 15, '25000');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('x1', 0, 'ss', 'a', '100000');
            f.AddGuide('x2', 1, 'r', '0', 'x1');
            f.AddGuide('y2', 1, 'b', '0', 'x1');
            f.AddGuide('d', 1, 'w', '0', 'h');
            f.AddGuide('il', 3, 'd', 'l', 'x1');
            f.AddGuide('ir', 3, 'd', 'r', 'x2');
            f.AddGuide('it', 3, 'd', 'x1', 't');
            f.AddGuide('ib', 3, 'd', 'y2', 'b');
            f.AddHandleXY('adj','0','50000', undefined, '0', '0', 'x1', 't');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'x1');
            f.AddPathCommand(2, 'x1', 'x1');
            f.AddPathCommand(2, 'x1', 't');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'x2', 'x1');
            f.AddPathCommand(2, 'r', 'x1');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x2', 'b');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(2, 'l', 'y2');
            f.AddPathCommand(6);
            break;
        }
        case 'quadArrow':{
            f.AddAdj('adj1', 15, '22500');
            f.AddAdj('adj2', 15, '22500');
            f.AddAdj('adj3', 15, '22500');
            f.AddGuide('a2', 10, '0', 'adj2', '50000');
            f.AddGuide('maxAdj1', 0, 'a2', '2', '1');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('q1', 1, '100000', '0', 'maxAdj1');
            f.AddGuide('maxAdj3', 0, 'q1', '1', '2');
            f.AddGuide('a3', 10, '0', 'adj3', 'maxAdj3');
            f.AddGuide('x1', 0, 'ss', 'a3', '100000');
            f.AddGuide('dx2', 0, 'ss', 'a2', '100000');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x5', 1, 'hc', 'dx2', '0');
            f.AddGuide('dx3', 0, 'ss', 'a1', '200000');
            f.AddGuide('x3', 1, 'hc', '0', 'dx3');
            f.AddGuide('x4', 1, 'hc', 'dx3', '0');
            f.AddGuide('x6', 1, 'r', '0', 'x1');
            f.AddGuide('y2', 1, 'vc', '0', 'dx2');
            f.AddGuide('y5', 1, 'vc', 'dx2', '0');
            f.AddGuide('y3', 1, 'vc', '0', 'dx3');
            f.AddGuide('y4', 1, 'vc', 'dx3', '0');
            f.AddGuide('y6', 1, 'b', '0', 'x1');
            f.AddGuide('il', 0, 'dx3', 'x1', 'dx2');
            f.AddGuide('ir', 1, 'r', '0', 'il');
            f.AddHandleXY('adj1','0','maxAdj1', undefined, '0', '0', 'x3', 'x1');
            f.AddHandleXY('adj2','0','50000', undefined, '0', '0', 'x2', 't');
            f.AddHandleXY(undefined, '0', '0','adj3','0','maxAdj3', 'r', 'x1');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('il', 'y3', 'ir', 'y4');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(2, 'x1', 'y3');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(2, 'x3', 'x1');
            f.AddPathCommand(2, 'x2', 'x1');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'x5', 'x1');
            f.AddPathCommand(2, 'x4', 'x1');
            f.AddPathCommand(2, 'x4', 'y3');
            f.AddPathCommand(2, 'x6', 'y3');
            f.AddPathCommand(2, 'x6', 'y2');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'x6', 'y5');
            f.AddPathCommand(2, 'x6', 'y4');
            f.AddPathCommand(2, 'x4', 'y4');
            f.AddPathCommand(2, 'x4', 'y6');
            f.AddPathCommand(2, 'x5', 'y6');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(2, 'x2', 'y6');
            f.AddPathCommand(2, 'x3', 'y6');
            f.AddPathCommand(2, 'x3', 'y4');
            f.AddPathCommand(2, 'x1', 'y4');
            f.AddPathCommand(2, 'x1', 'y5');
            f.AddPathCommand(6);
            break;
        }
        case 'quadArrowCallout':{
            f.AddAdj('adj1', 15, '18515');
            f.AddAdj('adj2', 15, '18515');
            f.AddAdj('adj3', 15, '18515');
            f.AddAdj('adj4', 15, '48123');
            f.AddGuide('a2', 10, '0', 'adj2', '50000');
            f.AddGuide('maxAdj1', 0, 'a2', '2', '1');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('maxAdj3', 1, '50000', '0', 'a2');
            f.AddGuide('a3', 10, '0', 'adj3', 'maxAdj3');
            f.AddGuide('q2', 0, 'a3', '2', '1');
            f.AddGuide('maxAdj4', 1, '100000', '0', 'q2');
            f.AddGuide('a4', 10, 'a1', 'adj4', 'maxAdj4');
            f.AddGuide('dx2', 0, 'ss', 'a2', '100000');
            f.AddGuide('dx3', 0, 'ss', 'a1', '200000');
            f.AddGuide('ah', 0, 'ss', 'a3', '100000');
            f.AddGuide('dx1', 0, 'w', 'a4', '200000');
            f.AddGuide('dy1', 0, 'h', 'a4', '200000');
            f.AddGuide('x8', 1, 'r', '0', 'ah');
            f.AddGuide('x2', 1, 'hc', '0', 'dx1');
            f.AddGuide('x7', 1, 'hc', 'dx1', '0');
            f.AddGuide('x3', 1, 'hc', '0', 'dx2');
            f.AddGuide('x6', 1, 'hc', 'dx2', '0');
            f.AddGuide('x4', 1, 'hc', '0', 'dx3');
            f.AddGuide('x5', 1, 'hc', 'dx3', '0');
            f.AddGuide('y8', 1, 'b', '0', 'ah');
            f.AddGuide('y2', 1, 'vc', '0', 'dy1');
            f.AddGuide('y7', 1, 'vc', 'dy1', '0');
            f.AddGuide('y3', 1, 'vc', '0', 'dx2');
            f.AddGuide('y6', 1, 'vc', 'dx2', '0');
            f.AddGuide('y4', 1, 'vc', '0', 'dx3');
            f.AddGuide('y5', 1, 'vc', 'dx3', '0');
            f.AddHandleXY('adj1','0','maxAdj1', undefined, '0', '0', 'x4', 'ah');
            f.AddHandleXY('adj2','0','50000', undefined, '0', '0', 'x3', 't');
            f.AddHandleXY(undefined, '0', '0','adj3','0','maxAdj3', 'r', 'ah');
            f.AddHandleXY(undefined, '0', '0','adj4','a1','maxAdj4', 'l', 'y2');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('x2', 'y2', 'x7', 'y7');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'ah', 'y3');
            f.AddPathCommand(2, 'ah', 'y4');
            f.AddPathCommand(2, 'x2', 'y4');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x4', 'y2');
            f.AddPathCommand(2, 'x4', 'ah');
            f.AddPathCommand(2, 'x3', 'ah');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'x6', 'ah');
            f.AddPathCommand(2, 'x5', 'ah');
            f.AddPathCommand(2, 'x5', 'y2');
            f.AddPathCommand(2, 'x7', 'y2');
            f.AddPathCommand(2, 'x7', 'y4');
            f.AddPathCommand(2, 'x8', 'y4');
            f.AddPathCommand(2, 'x8', 'y3');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'x8', 'y6');
            f.AddPathCommand(2, 'x8', 'y5');
            f.AddPathCommand(2, 'x7', 'y5');
            f.AddPathCommand(2, 'x7', 'y7');
            f.AddPathCommand(2, 'x5', 'y7');
            f.AddPathCommand(2, 'x5', 'y8');
            f.AddPathCommand(2, 'x6', 'y8');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(2, 'x3', 'y8');
            f.AddPathCommand(2, 'x4', 'y8');
            f.AddPathCommand(2, 'x4', 'y7');
            f.AddPathCommand(2, 'x2', 'y7');
            f.AddPathCommand(2, 'x2', 'y5');
            f.AddPathCommand(2, 'ah', 'y5');
            f.AddPathCommand(2, 'ah', 'y6');
            f.AddPathCommand(6);
            break;
        }
        case 'rect':{
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'ribbon':{
            f.AddAdj('adj1', 15, '16667');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('a1', 10, '0', 'adj1', '33333');
            f.AddGuide('a2', 10, '25000', 'adj2', '75000');
            f.AddGuide('x10', 1, 'r', '0', 'wd8');
            f.AddGuide('dx2', 0, 'w', 'a2', '200000');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x9', 1, 'hc', 'dx2', '0');
            f.AddGuide('x3', 1, 'x2', 'wd32', '0');
            f.AddGuide('x8', 1, 'x9', '0', 'wd32');
            f.AddGuide('x5', 1, 'x2', 'wd8', '0');
            f.AddGuide('x6', 1, 'x9', '0', 'wd8');
            f.AddGuide('x4', 1, 'x5', '0', 'wd32');
            f.AddGuide('x7', 1, 'x6', 'wd32', '0');
            f.AddGuide('y1', 0, 'h', 'a1', '200000');
            f.AddGuide('y2', 0, 'h', 'a1', '100000');
            f.AddGuide('y4', 1, 'b', '0', 'y2');
            f.AddGuide('y3', 0, 'y4', '1', '2');
            f.AddGuide('hR', 0, 'h', 'a1', '400000');
            f.AddGuide('y5', 1, 'b', '0', 'hR');
            f.AddGuide('y6', 1, 'y2', '0', 'hR');
            f.AddHandleXY(undefined, '0', '0','adj1','0','33333', 'hc', 'y2');
            f.AddHandleXY('adj2','25000','75000', undefined, '0', '0', 'x2', 't');
            f.AddCnx('_3cd4', 'hc', 'y2');
            f.AddCnx('cd2', 'wd8', 'y3');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'x10', 'y3');
            f.AddRect('x2', 'y2', 'x9', 'b');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'x4', 't');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', 'cd2');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', '-10800000');
            f.AddPathCommand(2, 'x8', 'y2');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd4', '-10800000');
            f.AddPathCommand(2, 'x7', 'y1');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd4', 'cd2');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'x10', 'y3');
            f.AddPathCommand(2, 'r', 'y4');
            f.AddPathCommand(2, 'x9', 'y4');
            f.AddPathCommand(2, 'x9', 'y5');
            f.AddPathCommand(3, 'wd32', 'hR', '0', 'cd4');
            f.AddPathCommand(2, 'x3', 'b');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd4', 'cd4');
            f.AddPathCommand(2, 'x2', 'y4');
            f.AddPathCommand(2, 'l', 'y4');
            f.AddPathCommand(2, 'wd8', 'y3');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'x5', 'hR');
            f.AddPathCommand(3, 'wd32', 'hR', '0', 'cd4');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', '-10800000');
            f.AddPathCommand(2, 'x5', 'y2');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x6', 'hR');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd2', '-5400000');
            f.AddPathCommand(2, 'x8', 'y1');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', 'cd2');
            f.AddPathCommand(2, 'x6', 'y2');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'x4', 't');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', 'cd2');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', '-10800000');
            f.AddPathCommand(2, 'x8', 'y2');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd4', '-10800000');
            f.AddPathCommand(2, 'x7', 'y1');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd4', 'cd2');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'x10', 'y3');
            f.AddPathCommand(2, 'r', 'y4');
            f.AddPathCommand(2, 'x9', 'y4');
            f.AddPathCommand(2, 'x9', 'y5');
            f.AddPathCommand(3, 'wd32', 'hR', '0', 'cd4');
            f.AddPathCommand(2, 'x3', 'b');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd4', 'cd4');
            f.AddPathCommand(2, 'x2', 'y4');
            f.AddPathCommand(2, 'l', 'y4');
            f.AddPathCommand(2, 'wd8', 'y3');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x5', 'hR');
            f.AddPathCommand(2, 'x5', 'y2');
            f.AddPathCommand(1, 'x6', 'y2');
            f.AddPathCommand(2, 'x6', 'hR');
            f.AddPathCommand(1, 'x2', 'y4');
            f.AddPathCommand(2, 'x2', 'y6');
            f.AddPathCommand(1, 'x9', 'y6');
            f.AddPathCommand(2, 'x9', 'y4');
            break;
        }
        case 'ribbon2':{
            f.AddAdj('adj1', 15, '16667');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('a1', 10, '0', 'adj1', '33333');
            f.AddGuide('a2', 10, '25000', 'adj2', '75000');
            f.AddGuide('x10', 1, 'r', '0', 'wd8');
            f.AddGuide('dx2', 0, 'w', 'a2', '200000');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x9', 1, 'hc', 'dx2', '0');
            f.AddGuide('x3', 1, 'x2', 'wd32', '0');
            f.AddGuide('x8', 1, 'x9', '0', 'wd32');
            f.AddGuide('x5', 1, 'x2', 'wd8', '0');
            f.AddGuide('x6', 1, 'x9', '0', 'wd8');
            f.AddGuide('x4', 1, 'x5', '0', 'wd32');
            f.AddGuide('x7', 1, 'x6', 'wd32', '0');
            f.AddGuide('dy1', 0, 'h', 'a1', '200000');
            f.AddGuide('y1', 1, 'b', '0', 'dy1');
            f.AddGuide('dy2', 0, 'h', 'a1', '100000');
            f.AddGuide('y2', 1, 'b', '0', 'dy2');
            f.AddGuide('y4', 1, 't', 'dy2', '0');
            f.AddGuide('y3', 2, 'y4', 'b', '2');
            f.AddGuide('hR', 0, 'h', 'a1', '400000');
            f.AddGuide('y6', 1, 'b', '0', 'hR');
            f.AddGuide('y7', 1, 'y1', '0', 'hR');
            f.AddHandleXY(undefined, '0', '0','adj1','0','33333', 'hc', 'y2');
            f.AddHandleXY('adj2','25000','75000', undefined, '0', '0', 'x2', 'b');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'wd8', 'y3');
            f.AddCnx('cd4', 'hc', 'y2');
            f.AddCnx('0', 'x10', 'y3');
            f.AddRect('x2', 't', 'x9', 'y2');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'x4', 'b');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd4', '-10800000');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd4', 'cd2');
            f.AddPathCommand(2, 'x8', 'y2');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', 'cd2');
            f.AddPathCommand(2, 'x7', 'y1');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', '-10800000');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'x10', 'y3');
            f.AddPathCommand(2, 'r', 'y4');
            f.AddPathCommand(2, 'x9', 'y4');
            f.AddPathCommand(2, 'x9', 'hR');
            f.AddPathCommand(3, 'wd32', 'hR', '0', '-5400000');
            f.AddPathCommand(2, 'x3', 't');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', '-5400000');
            f.AddPathCommand(2, 'x2', 'y4');
            f.AddPathCommand(2, 'l', 'y4');
            f.AddPathCommand(2, 'wd8', 'y3');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'x5', 'y6');
            f.AddPathCommand(3, 'wd32', 'hR', '0', '-5400000');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd4', 'cd2');
            f.AddPathCommand(2, 'x5', 'y2');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x6', 'y6');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd2', 'cd4');
            f.AddPathCommand(2, 'x8', 'y1');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd4', '-10800000');
            f.AddPathCommand(2, 'x6', 'y2');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'wd8', 'y3');
            f.AddPathCommand(2, 'l', 'y4');
            f.AddPathCommand(2, 'x2', 'y4');
            f.AddPathCommand(2, 'x2', 'hR');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd2', 'cd4');
            f.AddPathCommand(2, 'x8', 't');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'x9', 'y4');
            f.AddPathCommand(2, 'x9', 'y4');
            f.AddPathCommand(2, 'r', 'y4');
            f.AddPathCommand(2, 'x10', 'y3');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'x7', 'b');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd4', 'cd2');
            f.AddPathCommand(2, 'x8', 'y1');
            f.AddPathCommand(3, 'wd32', 'hR', 'cd4', '-10800000');
            f.AddPathCommand(2, 'x3', 'y2');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', '-10800000');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(3, 'wd32', 'hR', '_3cd4', 'cd2');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x5', 'y2');
            f.AddPathCommand(2, 'x5', 'y6');
            f.AddPathCommand(1, 'x6', 'y6');
            f.AddPathCommand(2, 'x6', 'y2');
            f.AddPathCommand(1, 'x2', 'y7');
            f.AddPathCommand(2, 'x2', 'y4');
            f.AddPathCommand(1, 'x9', 'y4');
            f.AddPathCommand(2, 'x9', 'y7');
            break;
        }
        case 'rightArrow':{
            f.AddAdj('adj1', 15, '50000');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('maxAdj2', 0, '100000', 'w', 'ss');
            f.AddGuide('a1', 10, '0', 'adj1', '100000');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('dx1', 0, 'ss', 'a2', '100000');
            f.AddGuide('x1', 1, 'r', '0', 'dx1');
            f.AddGuide('dy1', 0, 'h', 'a1', '200000');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y2', 1, 'vc', 'dy1', '0');
            f.AddGuide('dx2', 0, 'y1', 'dx1', 'hd2');
            f.AddGuide('x2', 1, 'x1', 'dx2', '0');
            f.AddHandleXY(undefined, '0', '0','adj1','0','100000', 'l', 'y1');
            f.AddHandleXY('adj2','0','maxAdj2', undefined, '0', '0', 'x1', 't');
            f.AddCnx('_3cd4', 'x1', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'x1', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 'y1', 'x2', 'y2');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(2, 'x1', 'y1');
            f.AddPathCommand(2, 'x1', 't');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(2, 'l', 'y2');
            f.AddPathCommand(6);
            break;
        }
        case 'rightArrowCallout':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '25000');
            f.AddAdj('adj3', 15, '25000');
            f.AddAdj('adj4', 15, '64977');
            f.AddGuide('maxAdj2', 0, '50000', 'h', 'ss');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('maxAdj1', 0, 'a2', '2', '1');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('maxAdj3', 0, '100000', 'w', 'ss');
            f.AddGuide('a3', 10, '0', 'adj3', 'maxAdj3');
            f.AddGuide('q2', 0, 'a3', 'ss', 'w');
            f.AddGuide('maxAdj4', 1, '100000', '0', 'q2');
            f.AddGuide('a4', 10, '0', 'adj4', 'maxAdj4');
            f.AddGuide('dy1', 0, 'ss', 'a2', '100000');
            f.AddGuide('dy2', 0, 'ss', 'a1', '200000');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y2', 1, 'vc', '0', 'dy2');
            f.AddGuide('y3', 1, 'vc', 'dy2', '0');
            f.AddGuide('y4', 1, 'vc', 'dy1', '0');
            f.AddGuide('dx3', 0, 'ss', 'a3', '100000');
            f.AddGuide('x3', 1, 'r', '0', 'dx3');
            f.AddGuide('x2', 0, 'w', 'a4', '100000');
            f.AddGuide('x1', 0, 'x2', '1', '2');
            f.AddHandleXY(undefined, '0', '0','adj1','0','maxAdj1', 'x3', 'y2');
            f.AddHandleXY(undefined, '0', '0','adj2','0','maxAdj2', 'r', 'y1');
            f.AddHandleXY('adj3','0','maxAdj3', undefined, '0', '0', 'x3', 't');
            f.AddHandleXY('adj4','0','maxAdj4', undefined, '0', '0', 'x2', 'b');
            f.AddCnx('_3cd4', 'x1', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'x1', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 't', 'x2', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x3', 'y2');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'x3', 'y4');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(2, 'x2', 'y3');
            f.AddPathCommand(2, 'x2', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'rightBrace':{
            f.AddAdj('adj1', 15, '8333');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('a2', 10, '0', 'adj2', '100000');
            f.AddGuide('q1', 1, '100000', '0', 'a2');
            f.AddGuide('q2', 16, 'q1', 'a2');
            f.AddGuide('q3', 0, 'q2', '1', '2');
            f.AddGuide('maxAdj1', 0, 'q3', 'h', 'ss');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('y1', 0, 'ss', 'a1', '100000');
            f.AddGuide('y3', 0, 'h', 'a2', '100000');
            f.AddGuide('y2', 1, 'y3', '0', 'y1');
            f.AddGuide('y4', 1, 'b', '0', 'y1');
            f.AddGuide('dx1', 7, 'wd2', '2700000');
            f.AddGuide('dy1', 12, 'y1', '2700000');
            f.AddGuide('ir', 1, 'l', 'dx1', '0');
            f.AddGuide('it', 1, 'y1', '0', 'dy1');
            f.AddGuide('ib', 1, 'b', 'dy1', 'y1');
            f.AddHandleXY(undefined, '0', '0','adj1','0','maxAdj1', 'hc', 'y1');
            f.AddHandleXY(undefined, '0', '0','adj2','0','100000', 'r', 'y3');
            f.AddCnx('cd4', 'l', 't');
            f.AddCnx('cd2', 'r', 'y3');
            f.AddCnx('_3cd4', 'l', 'b');
            f.AddRect('l', 'it', 'ir', 'ib');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(3, 'wd2', 'y1', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'hc', 'y2');
            f.AddPathCommand(3, 'wd2', 'y1', 'cd2', '-5400000');
            f.AddPathCommand(3, 'wd2', 'y1', '_3cd4', '-5400000');
            f.AddPathCommand(2, 'hc', 'y4');
            f.AddPathCommand(3, 'wd2', 'y1', '0', 'cd4');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(3, 'wd2', 'y1', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'hc', 'y2');
            f.AddPathCommand(3, 'wd2', 'y1', 'cd2', '-5400000');
            f.AddPathCommand(3, 'wd2', 'y1', '_3cd4', '-5400000');
            f.AddPathCommand(2, 'hc', 'y4');
            f.AddPathCommand(3, 'wd2', 'y1', '0', 'cd4');
            break;
        }
        case 'rightBracket':{
            f.AddAdj('adj', 15, '8333');
            f.AddGuide('maxAdj', 0, '50000', 'h', 'ss');
            f.AddGuide('a', 10, '0', 'adj', 'maxAdj');
            f.AddGuide('y1', 0, 'ss', 'a', '100000');
            f.AddGuide('y2', 1, 'b', '0', 'y1');
            f.AddGuide('dx1', 7, 'w', '2700000');
            f.AddGuide('dy1', 12, 'y1', '2700000');
            f.AddGuide('ir', 1, 'l', 'dx1', '0');
            f.AddGuide('it', 1, 'y1', '0', 'dy1');
            f.AddGuide('ib', 1, 'b', 'dy1', 'y1');
            f.AddHandleXY(undefined, '0', '0','adj','0','maxAdj', 'r', 'y1');
            f.AddCnx('cd4', 'l', 't');
            f.AddCnx('_3cd4', 'l', 'b');
            f.AddCnx('cd2', 'r', 'vc');
            f.AddRect('l', 'it', 'ir', 'ib');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(3, 'w', 'y1', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(3, 'w', 'y1', '0', 'cd4');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(3, 'w', 'y1', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(3, 'w', 'y1', '0', 'cd4');
            break;
        }
        case 'round1Rect':{
            f.AddAdj('adj', 15, '16667');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('dx1', 0, 'ss', 'a', '100000');
            f.AddGuide('x1', 1, 'r', '0', 'dx1');
            f.AddGuide('idx', 0, 'dx1', '29289', '100000');
            f.AddGuide('ir', 1, 'r', '0', 'idx');
            f.AddHandleXY('adj','0','50000', undefined, '0', '0', 'x1', 't');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 't', 'ir', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'x1', 't');
            f.AddPathCommand(3, 'dx1', 'dx1', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'round2DiagRect':{
            f.AddAdj('adj1', 15, '16667');
            f.AddAdj('adj2', 15, '0');
            f.AddGuide('a1', 10, '0', 'adj1', '50000');
            f.AddGuide('a2', 10, '0', 'adj2', '50000');
            f.AddGuide('x1', 0, 'ss', 'a1', '100000');
            f.AddGuide('y1', 1, 'b', '0', 'x1');
            f.AddGuide('a', 0, 'ss', 'a2', '100000');
            f.AddGuide('x2', 1, 'r', '0', 'a');
            f.AddGuide('y2', 1, 'b', '0', 'a');
            f.AddGuide('dx1', 0, 'x1', '29289', '100000');
            f.AddGuide('dx2', 0, 'a', '29289', '100000');
            f.AddGuide('d', 1, 'dx1', '0', 'dx2');
            f.AddGuide('dx', 3, 'd', 'dx1', 'dx2');
            f.AddGuide('ir', 1, 'r', '0', 'dx');
            f.AddGuide('ib', 1, 'b', '0', 'dx');
            f.AddHandleXY('adj1','0','50000', undefined, '0', '0', 'x1', 't');
            f.AddHandleXY('adj2','0','50000', undefined, '0', '0', 'x2', 't');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('dx', 'dx', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 't');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(3, 'a', 'a', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'r', 'y1');
            f.AddPathCommand(3, 'x1', 'x1', '0', 'cd4');
            f.AddPathCommand(2, 'a', 'b');
            f.AddPathCommand(3, 'a', 'a', 'cd4', 'cd4');
            f.AddPathCommand(2, 'l', 'x1');
            f.AddPathCommand(3, 'x1', 'x1', 'cd2', 'cd4');
            f.AddPathCommand(6);
            break;
        }
        case 'round2SameRect':{
            f.AddAdj('adj1', 15, '16667');
            f.AddAdj('adj2', 15, '0');
            f.AddGuide('a1', 10, '0', 'adj1', '50000');
            f.AddGuide('a2', 10, '0', 'adj2', '50000');
            f.AddGuide('tx1', 0, 'ss', 'a1', '100000');
            f.AddGuide('tx2', 1, 'r', '0', 'tx1');
            f.AddGuide('bx1', 0, 'ss', 'a2', '100000');
            f.AddGuide('bx2', 1, 'r', '0', 'bx1');
            f.AddGuide('by1', 1, 'b', '0', 'bx1');
            f.AddGuide('d', 1, 'tx1', '0', 'bx1');
            f.AddGuide('tdx', 0, 'tx1', '29289', '100000');
            f.AddGuide('bdx', 0, 'bx1', '29289', '100000');
            f.AddGuide('il', 3, 'd', 'tdx', 'bdx');
            f.AddGuide('ir', 1, 'r', '0', 'il');
            f.AddGuide('ib', 1, 'b', '0', 'bdx');
            f.AddHandleXY('adj1','0','50000', undefined, '0', '0', 'tx2', 't');
            f.AddHandleXY('adj2','0','50000', undefined, '0', '0', 'bx1', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('il', 'tdx', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'tx1', 't');
            f.AddPathCommand(2, 'tx2', 't');
            f.AddPathCommand(3, 'tx1', 'tx1', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'r', 'by1');
            f.AddPathCommand(3, 'bx1', 'bx1', '0', 'cd4');
            f.AddPathCommand(2, 'bx1', 'b');
            f.AddPathCommand(3, 'bx1', 'bx1', 'cd4', 'cd4');
            f.AddPathCommand(2, 'l', 'tx1');
            f.AddPathCommand(3, 'tx1', 'tx1', 'cd2', 'cd4');
            f.AddPathCommand(6);
            break;
        }
        case 'roundRect':{
            f.AddAdj('adj', 15, '16667');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('x1', 0, 'ss', 'a', '100000');
            f.AddGuide('x2', 1, 'r', '0', 'x1');
            f.AddGuide('y2', 1, 'b', '0', 'x1');
            f.AddGuide('il', 0, 'x1', '29289', '100000');
            f.AddGuide('ir', 1, 'r', '0', 'il');
            f.AddGuide('ib', 1, 'b', '0', 'il');
            f.AddHandleXY('adj','0','50000', undefined, '0', '0', 'x1', 't');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('il', 'il', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'x1');
            f.AddPathCommand(3, 'x1', 'x1', 'cd2', 'cd4');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(3, 'x1', 'x1', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(3, 'x1', 'x1', '0', 'cd4');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(3, 'x1', 'x1', 'cd4', 'cd4');
            f.AddPathCommand(6);
            break;
        }
        case 'rtTriangle':{
            f.AddGuide('it', 0, 'h', '7', '12');
            f.AddGuide('ir', 0, 'w', '7', '12');
            f.AddGuide('ib', 0, 'h', '11', '12');
            f.AddCnx('_3cd4', 'l', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'l', 'b');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd4', 'r', 'b');
            f.AddCnx('0', 'hc', 'vc');
            f.AddRect('wd12', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'l', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'smileyFace':{
            f.AddAdj('adj', 15, '4653');
            f.AddGuide('a', 10, '-4653', 'adj', '4653');
            f.AddGuide('x1', 0, 'w', '4969', '21699');
            f.AddGuide('x2', 0, 'w', '6215', '21600');
            f.AddGuide('x3', 0, 'w', '13135', '21600');
            f.AddGuide('x4', 0, 'w', '16640', '21600');
            f.AddGuide('y1', 0, 'h', '7570', '21600');
            f.AddGuide('y3', 0, 'h', '16515', '21600');
            f.AddGuide('dy2', 0, 'h', 'a', '100000');
            f.AddGuide('y2', 1, 'y3', '0', 'dy2');
            f.AddGuide('y4', 1, 'y3', 'dy2', '0');
            f.AddGuide('dy3', 0, 'h', 'a', '50000');
            f.AddGuide('y5', 1, 'y4', 'dy3', '0');
            f.AddGuide('idx', 7, 'wd2', '2700000');
            f.AddGuide('idy', 12, 'hd2', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddGuide('wR', 0, 'w', '1125', '21600');
            f.AddGuide('hR', 0, 'h', '1125', '21600');
            f.AddHandleXY(undefined, '0', '0','adj','-4653','4653', 'hc', 'y4');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('_3cd4', 'il', 'it');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'il', 'ib');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd4', 'ir', 'ib');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('_3cd4', 'ir', 'it');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd2', '21600000');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x2', 'y1');
            f.AddPathCommand(3, 'wR', 'hR', 'cd2', '21600000');
            f.AddPathCommand(1, 'x3', 'y1');
            f.AddPathCommand(3, 'wR', 'hR', 'cd2', '21600000');
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y2');
            f.AddPathCommand(4, 'hc', 'y5', 'x4', 'y2');
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd2', '21600000');
            f.AddPathCommand(6);
            break;
        }
        case 'snip1Rect':{
            f.AddAdj('adj', 15, '16667');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('dx1', 0, 'ss', 'a', '100000');
            f.AddGuide('x1', 1, 'r', '0', 'dx1');
            f.AddGuide('it', 0, 'dx1', '1', '2');
            f.AddGuide('ir', 2, 'x1', 'r', '2');
            f.AddHandleXY('adj','0','50000', undefined, '0', '0', 'x1', 't');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('l', 'it', 'ir', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'x1', 't');
            f.AddPathCommand(2, 'r', 'dx1');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'snip2DiagRect':{
            f.AddAdj('adj1', 15, '0');
            f.AddAdj('adj2', 15, '16667');
            f.AddGuide('a1', 10, '0', 'adj1', '50000');
            f.AddGuide('a2', 10, '0', 'adj2', '50000');
            f.AddGuide('lx1', 0, 'ss', 'a1', '100000');
            f.AddGuide('lx2', 1, 'r', '0', 'lx1');
            f.AddGuide('ly1', 1, 'b', '0', 'lx1');
            f.AddGuide('rx1', 0, 'ss', 'a2', '100000');
            f.AddGuide('rx2', 1, 'r', '0', 'rx1');
            f.AddGuide('ry1', 1, 'b', '0', 'rx1');
            f.AddGuide('d', 1, 'lx1', '0', 'rx1');
            f.AddGuide('dx', 3, 'd', 'lx1', 'rx1');
            f.AddGuide('il', 0, 'dx', '1', '2');
            f.AddGuide('ir', 1, 'r', '0', 'il');
            f.AddGuide('ib', 1, 'b', '0', 'il');
            f.AddHandleXY('adj1','0','50000', undefined, '0', '0', 'lx1', 't');
            f.AddHandleXY('adj2','0','50000', undefined, '0', '0', 'rx2', 't');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('il', 'il', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'lx1', 't');
            f.AddPathCommand(2, 'rx2', 't');
            f.AddPathCommand(2, 'r', 'rx1');
            f.AddPathCommand(2, 'r', 'ly1');
            f.AddPathCommand(2, 'lx2', 'b');
            f.AddPathCommand(2, 'rx1', 'b');
            f.AddPathCommand(2, 'l', 'ry1');
            f.AddPathCommand(2, 'l', 'lx1');
            f.AddPathCommand(6);
            break;
        }
        case 'snip2SameRect':{
            f.AddAdj('adj1', 15, '16667');
            f.AddAdj('adj2', 15, '0');
            f.AddGuide('a1', 10, '0', 'adj1', '50000');
            f.AddGuide('a2', 10, '0', 'adj2', '50000');
            f.AddGuide('tx1', 0, 'ss', 'a1', '100000');
            f.AddGuide('tx2', 1, 'r', '0', 'tx1');
            f.AddGuide('bx1', 0, 'ss', 'a2', '100000');
            f.AddGuide('bx2', 1, 'r', '0', 'bx1');
            f.AddGuide('by1', 1, 'b', '0', 'bx1');
            f.AddGuide('d', 1, 'tx1', '0', 'bx1');
            f.AddGuide('dx', 3, 'd', 'tx1', 'bx1');
            f.AddGuide('il', 0, 'dx', '1', '2');
            f.AddGuide('ir', 1, 'r', '0', 'il');
            f.AddGuide('it', 0, 'tx1', '1', '2');
            f.AddGuide('ib', 2, 'by1', 'b', '2');
            f.AddHandleXY('adj1','0','50000', undefined, '0', '0', 'tx2', 't');
            f.AddHandleXY('adj2','0','50000', undefined, '0', '0', 'bx1', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'tx1', 't');
            f.AddPathCommand(2, 'tx2', 't');
            f.AddPathCommand(2, 'r', 'tx1');
            f.AddPathCommand(2, 'r', 'by1');
            f.AddPathCommand(2, 'bx2', 'b');
            f.AddPathCommand(2, 'bx1', 'b');
            f.AddPathCommand(2, 'l', 'by1');
            f.AddPathCommand(2, 'l', 'tx1');
            f.AddPathCommand(6);
            break;
        }
        case 'snipRoundRect':{
            f.AddAdj('adj1', 15, '16667');
            f.AddAdj('adj2', 15, '16667');
            f.AddGuide('a1', 10, '0', 'adj1', '50000');
            f.AddGuide('a2', 10, '0', 'adj2', '50000');
            f.AddGuide('x1', 0, 'ss', 'a1', '100000');
            f.AddGuide('dx2', 0, 'ss', 'a2', '100000');
            f.AddGuide('x2', 1, 'r', '0', 'dx2');
            f.AddGuide('il', 0, 'x1', '29289', '100000');
            f.AddGuide('ir', 2, 'x2', 'r', '2');
            f.AddHandleXY('adj1','0','50000', undefined, '0', '0', 'x1', 't');
            f.AddHandleXY('adj2','0','50000', undefined, '0', '0', 'x2', 't');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('il', 'il', 'ir', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 't');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'r', 'dx2');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(2, 'l', 'x1');
            f.AddPathCommand(3, 'x1', 'x1', 'cd2', 'cd4');
            f.AddPathCommand(6);
            break;
        }
        case 'squareTabs':{
            f.AddGuide('md', 9, 'w', 'h', '0');
            f.AddGuide('dx', 0, '1', 'md', '20');
            f.AddGuide('y1', 1, '0', 'b', 'dx');
            f.AddGuide('x1', 1, '0', 'r', 'dx');
            f.AddCnx('cd2', 'l', 't');
            f.AddCnx('cd2', 'l', 'dx');
            f.AddCnx('cd2', 'l', 'y1');
            f.AddCnx('cd2', 'l', 'b');
            f.AddCnx('cd2', 'dx', 'dx');
            f.AddCnx('cd2', 'dx', 'x1');
            f.AddCnx('_3cd4', 'dx', 't');
            f.AddCnx('_3cd4', 'x1', 't');
            f.AddCnx('cd4', 'dx', 'b');
            f.AddCnx('cd4', 'x1', 'b');
            f.AddCnx('0', 'r', 't');
            f.AddCnx('0', 'r', 'dx');
            f.AddCnx('0', 'r', 'y1');
            f.AddCnx('0', 'r', 'b');
            f.AddCnx('0', 'x1', 'dx');
            f.AddCnx('0', 'x1', 'y1');
            f.AddRect('dx', 'dx', 'x1', 'y1');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'dx', 't');
            f.AddPathCommand(2, 'dx', 'dx');
            f.AddPathCommand(2, 'l', 'dx');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(2, 'dx', 'y1');
            f.AddPathCommand(2, 'dx', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'dx');
            f.AddPathCommand(2, 'x1', 'dx');
            f.AddPathCommand(6);
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'r', 'y1');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'star10':{
            f.AddAdj('adj', 15, '42533');
            f.AddAdj('hf', 15, '105146');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('swd2', 0, 'wd2', 'hf', '100000');
            f.AddGuide('dx1', 0, 'swd2', '95106', '100000');
            f.AddGuide('dx2', 0, 'swd2', '58779', '100000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'hc', 'dx2', '0');
            f.AddGuide('x4', 1, 'hc', 'dx1', '0');
            f.AddGuide('dy1', 0, 'hd2', '80902', '100000');
            f.AddGuide('dy2', 0, 'hd2', '30902', '100000');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y2', 1, 'vc', '0', 'dy2');
            f.AddGuide('y3', 1, 'vc', 'dy2', '0');
            f.AddGuide('y4', 1, 'vc', 'dy1', '0');
            f.AddGuide('iwd2', 0, 'swd2', 'a', '50000');
            f.AddGuide('ihd2', 0, 'hd2', 'a', '50000');
            f.AddGuide('sdx1', 0, 'iwd2', '80902', '100000');
            f.AddGuide('sdx2', 0, 'iwd2', '30902', '100000');
            f.AddGuide('sdy1', 0, 'ihd2', '95106', '100000');
            f.AddGuide('sdy2', 0, 'ihd2', '58779', '100000');
            f.AddGuide('sx1', 1, 'hc', '0', 'iwd2');
            f.AddGuide('sx2', 1, 'hc', '0', 'sdx1');
            f.AddGuide('sx3', 1, 'hc', '0', 'sdx2');
            f.AddGuide('sx4', 1, 'hc', 'sdx2', '0');
            f.AddGuide('sx5', 1, 'hc', 'sdx1', '0');
            f.AddGuide('sx6', 1, 'hc', 'iwd2', '0');
            f.AddGuide('sy1', 1, 'vc', '0', 'sdy1');
            f.AddGuide('sy2', 1, 'vc', '0', 'sdy2');
            f.AddGuide('sy3', 1, 'vc', 'sdy2', '0');
            f.AddGuide('sy4', 1, 'vc', 'sdy1', '0');
            f.AddGuide('yAdj', 1, 'vc', '0', 'ihd2');
            f.AddHandleXY(undefined, '0', '0','adj','0','50000', 'hc', 'yAdj');
            f.AddCnx('0', 'x4', 'y2');
            f.AddCnx('0', 'x4', 'y3');
            f.AddCnx('cd4', 'x3', 'y4');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd4', 'x2', 'y4');
            f.AddCnx('cd2', 'x1', 'y3');
            f.AddCnx('cd2', 'x1', 'y2');
            f.AddCnx('_3cd4', 'x2', 'y1');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('_3cd4', 'x3', 'y1');
            f.AddRect('sx2', 'sy2', 'sx5', 'sy3');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y2');
            f.AddPathCommand(2, 'sx2', 'sy2');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'sx3', 'sy1');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'sx4', 'sy1');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(2, 'sx5', 'sy2');
            f.AddPathCommand(2, 'x4', 'y2');
            f.AddPathCommand(2, 'sx6', 'vc');
            f.AddPathCommand(2, 'x4', 'y3');
            f.AddPathCommand(2, 'sx5', 'sy3');
            f.AddPathCommand(2, 'x3', 'y4');
            f.AddPathCommand(2, 'sx4', 'sy4');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(2, 'sx3', 'sy4');
            f.AddPathCommand(2, 'x2', 'y4');
            f.AddPathCommand(2, 'sx2', 'sy3');
            f.AddPathCommand(2, 'x1', 'y3');
            f.AddPathCommand(2, 'sx1', 'vc');
            f.AddPathCommand(6);
            break;
        }
        case 'star12':{
            f.AddAdj('adj', 15, '37500');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('dx1', 7, 'wd2', '1800000');
            f.AddGuide('dy1', 12, 'hd2', '3600000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x3', 0, 'w', '3', '4');
            f.AddGuide('x4', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y3', 0, 'h', '3', '4');
            f.AddGuide('y4', 1, 'vc', 'dy1', '0');
            f.AddGuide('iwd2', 0, 'wd2', 'a', '50000');
            f.AddGuide('ihd2', 0, 'hd2', 'a', '50000');
            f.AddGuide('sdx1', 7, 'iwd2', '900000');
            f.AddGuide('sdx2', 7, 'iwd2', '2700000');
            f.AddGuide('sdx3', 7, 'iwd2', '4500000');
            f.AddGuide('sdy1', 12, 'ihd2', '4500000');
            f.AddGuide('sdy2', 12, 'ihd2', '2700000');
            f.AddGuide('sdy3', 12, 'ihd2', '900000');
            f.AddGuide('sx1', 1, 'hc', '0', 'sdx1');
            f.AddGuide('sx2', 1, 'hc', '0', 'sdx2');
            f.AddGuide('sx3', 1, 'hc', '0', 'sdx3');
            f.AddGuide('sx4', 1, 'hc', 'sdx3', '0');
            f.AddGuide('sx5', 1, 'hc', 'sdx2', '0');
            f.AddGuide('sx6', 1, 'hc', 'sdx1', '0');
            f.AddGuide('sy1', 1, 'vc', '0', 'sdy1');
            f.AddGuide('sy2', 1, 'vc', '0', 'sdy2');
            f.AddGuide('sy3', 1, 'vc', '0', 'sdy3');
            f.AddGuide('sy4', 1, 'vc', 'sdy3', '0');
            f.AddGuide('sy5', 1, 'vc', 'sdy2', '0');
            f.AddGuide('sy6', 1, 'vc', 'sdy1', '0');
            f.AddGuide('yAdj', 1, 'vc', '0', 'ihd2');
            f.AddHandleXY(undefined, '0', '0','adj','0','50000', 'hc', 'yAdj');
            f.AddCnx('0', 'x4', 'hd4');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('0', 'x4', 'y3');
            f.AddCnx('cd4', 'x3', 'y4');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd4', 'wd4', 'y4');
            f.AddCnx('cd2', 'x1', 'y3');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd2', 'x1', 'hd4');
            f.AddCnx('_3cd4', 'wd4', 'y1');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('_3cd4', 'x3', 'y1');
            f.AddRect('sx2', 'sy2', 'sx5', 'sy5');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'sx1', 'sy3');
            f.AddPathCommand(2, 'x1', 'hd4');
            f.AddPathCommand(2, 'sx2', 'sy2');
            f.AddPathCommand(2, 'wd4', 'y1');
            f.AddPathCommand(2, 'sx3', 'sy1');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'sx4', 'sy1');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(2, 'sx5', 'sy2');
            f.AddPathCommand(2, 'x4', 'hd4');
            f.AddPathCommand(2, 'sx6', 'sy3');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'sx6', 'sy4');
            f.AddPathCommand(2, 'x4', 'y3');
            f.AddPathCommand(2, 'sx5', 'sy5');
            f.AddPathCommand(2, 'x3', 'y4');
            f.AddPathCommand(2, 'sx4', 'sy6');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(2, 'sx3', 'sy6');
            f.AddPathCommand(2, 'wd4', 'y4');
            f.AddPathCommand(2, 'sx2', 'sy5');
            f.AddPathCommand(2, 'x1', 'y3');
            f.AddPathCommand(2, 'sx1', 'sy4');
            f.AddPathCommand(6);
            break;
        }
        case 'star16':{
            f.AddAdj('adj', 15, '37500');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('dx1', 0, 'wd2', '92388', '100000');
            f.AddGuide('dx2', 0, 'wd2', '70711', '100000');
            f.AddGuide('dx3', 0, 'wd2', '38268', '100000');
            f.AddGuide('dy1', 0, 'hd2', '92388', '100000');
            f.AddGuide('dy2', 0, 'hd2', '70711', '100000');
            f.AddGuide('dy3', 0, 'hd2', '38268', '100000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'hc', '0', 'dx3');
            f.AddGuide('x4', 1, 'hc', 'dx3', '0');
            f.AddGuide('x5', 1, 'hc', 'dx2', '0');
            f.AddGuide('x6', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y2', 1, 'vc', '0', 'dy2');
            f.AddGuide('y3', 1, 'vc', '0', 'dy3');
            f.AddGuide('y4', 1, 'vc', 'dy3', '0');
            f.AddGuide('y5', 1, 'vc', 'dy2', '0');
            f.AddGuide('y6', 1, 'vc', 'dy1', '0');
            f.AddGuide('iwd2', 0, 'wd2', 'a', '50000');
            f.AddGuide('ihd2', 0, 'hd2', 'a', '50000');
            f.AddGuide('sdx1', 0, 'iwd2', '98079', '100000');
            f.AddGuide('sdx2', 0, 'iwd2', '83147', '100000');
            f.AddGuide('sdx3', 0, 'iwd2', '55557', '100000');
            f.AddGuide('sdx4', 0, 'iwd2', '19509', '100000');
            f.AddGuide('sdy1', 0, 'ihd2', '98079', '100000');
            f.AddGuide('sdy2', 0, 'ihd2', '83147', '100000');
            f.AddGuide('sdy3', 0, 'ihd2', '55557', '100000');
            f.AddGuide('sdy4', 0, 'ihd2', '19509', '100000');
            f.AddGuide('sx1', 1, 'hc', '0', 'sdx1');
            f.AddGuide('sx2', 1, 'hc', '0', 'sdx2');
            f.AddGuide('sx3', 1, 'hc', '0', 'sdx3');
            f.AddGuide('sx4', 1, 'hc', '0', 'sdx4');
            f.AddGuide('sx5', 1, 'hc', 'sdx4', '0');
            f.AddGuide('sx6', 1, 'hc', 'sdx3', '0');
            f.AddGuide('sx7', 1, 'hc', 'sdx2', '0');
            f.AddGuide('sx8', 1, 'hc', 'sdx1', '0');
            f.AddGuide('sy1', 1, 'vc', '0', 'sdy1');
            f.AddGuide('sy2', 1, 'vc', '0', 'sdy2');
            f.AddGuide('sy3', 1, 'vc', '0', 'sdy3');
            f.AddGuide('sy4', 1, 'vc', '0', 'sdy4');
            f.AddGuide('sy5', 1, 'vc', 'sdy4', '0');
            f.AddGuide('sy6', 1, 'vc', 'sdy3', '0');
            f.AddGuide('sy7', 1, 'vc', 'sdy2', '0');
            f.AddGuide('sy8', 1, 'vc', 'sdy1', '0');
            f.AddGuide('idx', 7, 'iwd2', '2700000');
            f.AddGuide('idy', 12, 'ihd2', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddGuide('yAdj', 1, 'vc', '0', 'ihd2');
            f.AddHandleXY(undefined, '0', '0','adj','0','50000', 'hc', 'yAdj');
            f.AddCnx('0', 'x5', 'y2');
            f.AddCnx('0', 'x6', 'y3');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('0', 'x6', 'y4');
            f.AddCnx('0', 'x5', 'y5');
            f.AddCnx('cd4', 'x4', 'y6');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd4', 'x3', 'y6');
            f.AddCnx('cd2', 'x2', 'y5');
            f.AddCnx('cd2', 'x1', 'y4');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd2', 'x1', 'y3');
            f.AddCnx('cd2', 'x2', 'y2');
            f.AddCnx('_3cd4', 'x3', 'y1');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('_3cd4', 'x4', 'y1');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'sx1', 'sy4');
            f.AddPathCommand(2, 'x1', 'y3');
            f.AddPathCommand(2, 'sx2', 'sy3');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'sx3', 'sy2');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(2, 'sx4', 'sy1');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'sx5', 'sy1');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(2, 'sx6', 'sy2');
            f.AddPathCommand(2, 'x5', 'y2');
            f.AddPathCommand(2, 'sx7', 'sy3');
            f.AddPathCommand(2, 'x6', 'y3');
            f.AddPathCommand(2, 'sx8', 'sy4');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'sx8', 'sy5');
            f.AddPathCommand(2, 'x6', 'y4');
            f.AddPathCommand(2, 'sx7', 'sy6');
            f.AddPathCommand(2, 'x5', 'y5');
            f.AddPathCommand(2, 'sx6', 'sy7');
            f.AddPathCommand(2, 'x4', 'y6');
            f.AddPathCommand(2, 'sx5', 'sy8');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(2, 'sx4', 'sy8');
            f.AddPathCommand(2, 'x3', 'y6');
            f.AddPathCommand(2, 'sx3', 'sy7');
            f.AddPathCommand(2, 'x2', 'y5');
            f.AddPathCommand(2, 'sx2', 'sy6');
            f.AddPathCommand(2, 'x1', 'y4');
            f.AddPathCommand(2, 'sx1', 'sy5');
            f.AddPathCommand(6);
            break;
        }
        case 'star24':{
            f.AddAdj('adj', 15, '37500');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('dx1', 7, 'wd2', '900000');
            f.AddGuide('dx2', 7, 'wd2', '1800000');
            f.AddGuide('dx3', 7, 'wd2', '2700000');
            f.AddGuide('dx4', 15, 'wd4');
            f.AddGuide('dx5', 7, 'wd2', '4500000');
            f.AddGuide('dy1', 12, 'hd2', '4500000');
            f.AddGuide('dy2', 12, 'hd2', '3600000');
            f.AddGuide('dy3', 12, 'hd2', '2700000');
            f.AddGuide('dy4', 15, 'hd4');
            f.AddGuide('dy5', 12, 'hd2', '900000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'hc', '0', 'dx3');
            f.AddGuide('x4', 1, 'hc', '0', 'dx4');
            f.AddGuide('x5', 1, 'hc', '0', 'dx5');
            f.AddGuide('x6', 1, 'hc', 'dx5', '0');
            f.AddGuide('x7', 1, 'hc', 'dx4', '0');
            f.AddGuide('x8', 1, 'hc', 'dx3', '0');
            f.AddGuide('x9', 1, 'hc', 'dx2', '0');
            f.AddGuide('x10', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y2', 1, 'vc', '0', 'dy2');
            f.AddGuide('y3', 1, 'vc', '0', 'dy3');
            f.AddGuide('y4', 1, 'vc', '0', 'dy4');
            f.AddGuide('y5', 1, 'vc', '0', 'dy5');
            f.AddGuide('y6', 1, 'vc', 'dy5', '0');
            f.AddGuide('y7', 1, 'vc', 'dy4', '0');
            f.AddGuide('y8', 1, 'vc', 'dy3', '0');
            f.AddGuide('y9', 1, 'vc', 'dy2', '0');
            f.AddGuide('y10', 1, 'vc', 'dy1', '0');
            f.AddGuide('iwd2', 0, 'wd2', 'a', '50000');
            f.AddGuide('ihd2', 0, 'hd2', 'a', '50000');
            f.AddGuide('sdx1', 0, 'iwd2', '99144', '100000');
            f.AddGuide('sdx2', 0, 'iwd2', '92388', '100000');
            f.AddGuide('sdx3', 0, 'iwd2', '79335', '100000');
            f.AddGuide('sdx4', 0, 'iwd2', '60876', '100000');
            f.AddGuide('sdx5', 0, 'iwd2', '38268', '100000');
            f.AddGuide('sdx6', 0, 'iwd2', '13053', '100000');
            f.AddGuide('sdy1', 0, 'ihd2', '99144', '100000');
            f.AddGuide('sdy2', 0, 'ihd2', '92388', '100000');
            f.AddGuide('sdy3', 0, 'ihd2', '79335', '100000');
            f.AddGuide('sdy4', 0, 'ihd2', '60876', '100000');
            f.AddGuide('sdy5', 0, 'ihd2', '38268', '100000');
            f.AddGuide('sdy6', 0, 'ihd2', '13053', '100000');
            f.AddGuide('sx1', 1, 'hc', '0', 'sdx1');
            f.AddGuide('sx2', 1, 'hc', '0', 'sdx2');
            f.AddGuide('sx3', 1, 'hc', '0', 'sdx3');
            f.AddGuide('sx4', 1, 'hc', '0', 'sdx4');
            f.AddGuide('sx5', 1, 'hc', '0', 'sdx5');
            f.AddGuide('sx6', 1, 'hc', '0', 'sdx6');
            f.AddGuide('sx7', 1, 'hc', 'sdx6', '0');
            f.AddGuide('sx8', 1, 'hc', 'sdx5', '0');
            f.AddGuide('sx9', 1, 'hc', 'sdx4', '0');
            f.AddGuide('sx10', 1, 'hc', 'sdx3', '0');
            f.AddGuide('sx11', 1, 'hc', 'sdx2', '0');
            f.AddGuide('sx12', 1, 'hc', 'sdx1', '0');
            f.AddGuide('sy1', 1, 'vc', '0', 'sdy1');
            f.AddGuide('sy2', 1, 'vc', '0', 'sdy2');
            f.AddGuide('sy3', 1, 'vc', '0', 'sdy3');
            f.AddGuide('sy4', 1, 'vc', '0', 'sdy4');
            f.AddGuide('sy5', 1, 'vc', '0', 'sdy5');
            f.AddGuide('sy6', 1, 'vc', '0', 'sdy6');
            f.AddGuide('sy7', 1, 'vc', 'sdy6', '0');
            f.AddGuide('sy8', 1, 'vc', 'sdy5', '0');
            f.AddGuide('sy9', 1, 'vc', 'sdy4', '0');
            f.AddGuide('sy10', 1, 'vc', 'sdy3', '0');
            f.AddGuide('sy11', 1, 'vc', 'sdy2', '0');
            f.AddGuide('sy12', 1, 'vc', 'sdy1', '0');
            f.AddGuide('idx', 7, 'iwd2', '2700000');
            f.AddGuide('idy', 12, 'ihd2', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddGuide('yAdj', 1, 'vc', '0', 'ihd2');
            f.AddHandleXY(undefined, '0', '0','adj','0','50000', 'hc', 'yAdj');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'sx1', 'sy6');
            f.AddPathCommand(2, 'x1', 'y5');
            f.AddPathCommand(2, 'sx2', 'sy5');
            f.AddPathCommand(2, 'x2', 'y4');
            f.AddPathCommand(2, 'sx3', 'sy4');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(2, 'sx4', 'sy3');
            f.AddPathCommand(2, 'x4', 'y2');
            f.AddPathCommand(2, 'sx5', 'sy2');
            f.AddPathCommand(2, 'x5', 'y1');
            f.AddPathCommand(2, 'sx6', 'sy1');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'sx7', 'sy1');
            f.AddPathCommand(2, 'x6', 'y1');
            f.AddPathCommand(2, 'sx8', 'sy2');
            f.AddPathCommand(2, 'x7', 'y2');
            f.AddPathCommand(2, 'sx9', 'sy3');
            f.AddPathCommand(2, 'x8', 'y3');
            f.AddPathCommand(2, 'sx10', 'sy4');
            f.AddPathCommand(2, 'x9', 'y4');
            f.AddPathCommand(2, 'sx11', 'sy5');
            f.AddPathCommand(2, 'x10', 'y5');
            f.AddPathCommand(2, 'sx12', 'sy6');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'sx12', 'sy7');
            f.AddPathCommand(2, 'x10', 'y6');
            f.AddPathCommand(2, 'sx11', 'sy8');
            f.AddPathCommand(2, 'x9', 'y7');
            f.AddPathCommand(2, 'sx10', 'sy9');
            f.AddPathCommand(2, 'x8', 'y8');
            f.AddPathCommand(2, 'sx9', 'sy10');
            f.AddPathCommand(2, 'x7', 'y9');
            f.AddPathCommand(2, 'sx8', 'sy11');
            f.AddPathCommand(2, 'x6', 'y10');
            f.AddPathCommand(2, 'sx7', 'sy12');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(2, 'sx6', 'sy12');
            f.AddPathCommand(2, 'x5', 'y10');
            f.AddPathCommand(2, 'sx5', 'sy11');
            f.AddPathCommand(2, 'x4', 'y9');
            f.AddPathCommand(2, 'sx4', 'sy10');
            f.AddPathCommand(2, 'x3', 'y8');
            f.AddPathCommand(2, 'sx3', 'sy9');
            f.AddPathCommand(2, 'x2', 'y7');
            f.AddPathCommand(2, 'sx2', 'sy8');
            f.AddPathCommand(2, 'x1', 'y6');
            f.AddPathCommand(2, 'sx1', 'sy7');
            f.AddPathCommand(6);
            break;
        }
        case 'star32':{
            f.AddAdj('adj', 15, '37500');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('dx1', 0, 'wd2', '98079', '100000');
            f.AddGuide('dx2', 0, 'wd2', '92388', '100000');
            f.AddGuide('dx3', 0, 'wd2', '83147', '100000');
            f.AddGuide('dx4', 7, 'wd2', '2700000');
            f.AddGuide('dx5', 0, 'wd2', '55557', '100000');
            f.AddGuide('dx6', 0, 'wd2', '38268', '100000');
            f.AddGuide('dx7', 0, 'wd2', '19509', '100000');
            f.AddGuide('dy1', 0, 'hd2', '98079', '100000');
            f.AddGuide('dy2', 0, 'hd2', '92388', '100000');
            f.AddGuide('dy3', 0, 'hd2', '83147', '100000');
            f.AddGuide('dy4', 12, 'hd2', '2700000');
            f.AddGuide('dy5', 0, 'hd2', '55557', '100000');
            f.AddGuide('dy6', 0, 'hd2', '38268', '100000');
            f.AddGuide('dy7', 0, 'hd2', '19509', '100000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'hc', '0', 'dx3');
            f.AddGuide('x4', 1, 'hc', '0', 'dx4');
            f.AddGuide('x5', 1, 'hc', '0', 'dx5');
            f.AddGuide('x6', 1, 'hc', '0', 'dx6');
            f.AddGuide('x7', 1, 'hc', '0', 'dx7');
            f.AddGuide('x8', 1, 'hc', 'dx7', '0');
            f.AddGuide('x9', 1, 'hc', 'dx6', '0');
            f.AddGuide('x10', 1, 'hc', 'dx5', '0');
            f.AddGuide('x11', 1, 'hc', 'dx4', '0');
            f.AddGuide('x12', 1, 'hc', 'dx3', '0');
            f.AddGuide('x13', 1, 'hc', 'dx2', '0');
            f.AddGuide('x14', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y2', 1, 'vc', '0', 'dy2');
            f.AddGuide('y3', 1, 'vc', '0', 'dy3');
            f.AddGuide('y4', 1, 'vc', '0', 'dy4');
            f.AddGuide('y5', 1, 'vc', '0', 'dy5');
            f.AddGuide('y6', 1, 'vc', '0', 'dy6');
            f.AddGuide('y7', 1, 'vc', '0', 'dy7');
            f.AddGuide('y8', 1, 'vc', 'dy7', '0');
            f.AddGuide('y9', 1, 'vc', 'dy6', '0');
            f.AddGuide('y10', 1, 'vc', 'dy5', '0');
            f.AddGuide('y11', 1, 'vc', 'dy4', '0');
            f.AddGuide('y12', 1, 'vc', 'dy3', '0');
            f.AddGuide('y13', 1, 'vc', 'dy2', '0');
            f.AddGuide('y14', 1, 'vc', 'dy1', '0');
            f.AddGuide('iwd2', 0, 'wd2', 'a', '50000');
            f.AddGuide('ihd2', 0, 'hd2', 'a', '50000');
            f.AddGuide('sdx1', 0, 'iwd2', '99518', '100000');
            f.AddGuide('sdx2', 0, 'iwd2', '95694', '100000');
            f.AddGuide('sdx3', 0, 'iwd2', '88192', '100000');
            f.AddGuide('sdx4', 0, 'iwd2', '77301', '100000');
            f.AddGuide('sdx5', 0, 'iwd2', '63439', '100000');
            f.AddGuide('sdx6', 0, 'iwd2', '47140', '100000');
            f.AddGuide('sdx7', 0, 'iwd2', '29028', '100000');
            f.AddGuide('sdx8', 0, 'iwd2', '9802', '100000');
            f.AddGuide('sdy1', 0, 'ihd2', '99518', '100000');
            f.AddGuide('sdy2', 0, 'ihd2', '95694', '100000');
            f.AddGuide('sdy3', 0, 'ihd2', '88192', '100000');
            f.AddGuide('sdy4', 0, 'ihd2', '77301', '100000');
            f.AddGuide('sdy5', 0, 'ihd2', '63439', '100000');
            f.AddGuide('sdy6', 0, 'ihd2', '47140', '100000');
            f.AddGuide('sdy7', 0, 'ihd2', '29028', '100000');
            f.AddGuide('sdy8', 0, 'ihd2', '9802', '100000');
            f.AddGuide('sx1', 1, 'hc', '0', 'sdx1');
            f.AddGuide('sx2', 1, 'hc', '0', 'sdx2');
            f.AddGuide('sx3', 1, 'hc', '0', 'sdx3');
            f.AddGuide('sx4', 1, 'hc', '0', 'sdx4');
            f.AddGuide('sx5', 1, 'hc', '0', 'sdx5');
            f.AddGuide('sx6', 1, 'hc', '0', 'sdx6');
            f.AddGuide('sx7', 1, 'hc', '0', 'sdx7');
            f.AddGuide('sx8', 1, 'hc', '0', 'sdx8');
            f.AddGuide('sx9', 1, 'hc', 'sdx8', '0');
            f.AddGuide('sx10', 1, 'hc', 'sdx7', '0');
            f.AddGuide('sx11', 1, 'hc', 'sdx6', '0');
            f.AddGuide('sx12', 1, 'hc', 'sdx5', '0');
            f.AddGuide('sx13', 1, 'hc', 'sdx4', '0');
            f.AddGuide('sx14', 1, 'hc', 'sdx3', '0');
            f.AddGuide('sx15', 1, 'hc', 'sdx2', '0');
            f.AddGuide('sx16', 1, 'hc', 'sdx1', '0');
            f.AddGuide('sy1', 1, 'vc', '0', 'sdy1');
            f.AddGuide('sy2', 1, 'vc', '0', 'sdy2');
            f.AddGuide('sy3', 1, 'vc', '0', 'sdy3');
            f.AddGuide('sy4', 1, 'vc', '0', 'sdy4');
            f.AddGuide('sy5', 1, 'vc', '0', 'sdy5');
            f.AddGuide('sy6', 1, 'vc', '0', 'sdy6');
            f.AddGuide('sy7', 1, 'vc', '0', 'sdy7');
            f.AddGuide('sy8', 1, 'vc', '0', 'sdy8');
            f.AddGuide('sy9', 1, 'vc', 'sdy8', '0');
            f.AddGuide('sy10', 1, 'vc', 'sdy7', '0');
            f.AddGuide('sy11', 1, 'vc', 'sdy6', '0');
            f.AddGuide('sy12', 1, 'vc', 'sdy5', '0');
            f.AddGuide('sy13', 1, 'vc', 'sdy4', '0');
            f.AddGuide('sy14', 1, 'vc', 'sdy3', '0');
            f.AddGuide('sy15', 1, 'vc', 'sdy2', '0');
            f.AddGuide('sy16', 1, 'vc', 'sdy1', '0');
            f.AddGuide('idx', 7, 'iwd2', '2700000');
            f.AddGuide('idy', 12, 'ihd2', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddGuide('yAdj', 1, 'vc', '0', 'ihd2');
            f.AddHandleXY(undefined, '0', '0','adj','0','50000', 'hc', 'yAdj');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'sx1', 'sy8');
            f.AddPathCommand(2, 'x1', 'y7');
            f.AddPathCommand(2, 'sx2', 'sy7');
            f.AddPathCommand(2, 'x2', 'y6');
            f.AddPathCommand(2, 'sx3', 'sy6');
            f.AddPathCommand(2, 'x3', 'y5');
            f.AddPathCommand(2, 'sx4', 'sy5');
            f.AddPathCommand(2, 'x4', 'y4');
            f.AddPathCommand(2, 'sx5', 'sy4');
            f.AddPathCommand(2, 'x5', 'y3');
            f.AddPathCommand(2, 'sx6', 'sy3');
            f.AddPathCommand(2, 'x6', 'y2');
            f.AddPathCommand(2, 'sx7', 'sy2');
            f.AddPathCommand(2, 'x7', 'y1');
            f.AddPathCommand(2, 'sx8', 'sy1');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'sx9', 'sy1');
            f.AddPathCommand(2, 'x8', 'y1');
            f.AddPathCommand(2, 'sx10', 'sy2');
            f.AddPathCommand(2, 'x9', 'y2');
            f.AddPathCommand(2, 'sx11', 'sy3');
            f.AddPathCommand(2, 'x10', 'y3');
            f.AddPathCommand(2, 'sx12', 'sy4');
            f.AddPathCommand(2, 'x11', 'y4');
            f.AddPathCommand(2, 'sx13', 'sy5');
            f.AddPathCommand(2, 'x12', 'y5');
            f.AddPathCommand(2, 'sx14', 'sy6');
            f.AddPathCommand(2, 'x13', 'y6');
            f.AddPathCommand(2, 'sx15', 'sy7');
            f.AddPathCommand(2, 'x14', 'y7');
            f.AddPathCommand(2, 'sx16', 'sy8');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'sx16', 'sy9');
            f.AddPathCommand(2, 'x14', 'y8');
            f.AddPathCommand(2, 'sx15', 'sy10');
            f.AddPathCommand(2, 'x13', 'y9');
            f.AddPathCommand(2, 'sx14', 'sy11');
            f.AddPathCommand(2, 'x12', 'y10');
            f.AddPathCommand(2, 'sx13', 'sy12');
            f.AddPathCommand(2, 'x11', 'y11');
            f.AddPathCommand(2, 'sx12', 'sy13');
            f.AddPathCommand(2, 'x10', 'y12');
            f.AddPathCommand(2, 'sx11', 'sy14');
            f.AddPathCommand(2, 'x9', 'y13');
            f.AddPathCommand(2, 'sx10', 'sy15');
            f.AddPathCommand(2, 'x8', 'y14');
            f.AddPathCommand(2, 'sx9', 'sy16');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(2, 'sx8', 'sy16');
            f.AddPathCommand(2, 'x7', 'y14');
            f.AddPathCommand(2, 'sx7', 'sy15');
            f.AddPathCommand(2, 'x6', 'y13');
            f.AddPathCommand(2, 'sx6', 'sy14');
            f.AddPathCommand(2, 'x5', 'y12');
            f.AddPathCommand(2, 'sx5', 'sy13');
            f.AddPathCommand(2, 'x4', 'y11');
            f.AddPathCommand(2, 'sx4', 'sy12');
            f.AddPathCommand(2, 'x3', 'y10');
            f.AddPathCommand(2, 'sx3', 'sy11');
            f.AddPathCommand(2, 'x2', 'y9');
            f.AddPathCommand(2, 'sx2', 'sy10');
            f.AddPathCommand(2, 'x1', 'y8');
            f.AddPathCommand(2, 'sx1', 'sy9');
            f.AddPathCommand(6);
            break;
        }
        case 'star4':{
            f.AddAdj('adj', 15, '12500');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('iwd2', 0, 'wd2', 'a', '50000');
            f.AddGuide('ihd2', 0, 'hd2', 'a', '50000');
            f.AddGuide('sdx', 7, 'iwd2', '2700000');
            f.AddGuide('sdy', 12, 'ihd2', '2700000');
            f.AddGuide('sx1', 1, 'hc', '0', 'sdx');
            f.AddGuide('sx2', 1, 'hc', 'sdx', '0');
            f.AddGuide('sy1', 1, 'vc', '0', 'sdy');
            f.AddGuide('sy2', 1, 'vc', 'sdy', '0');
            f.AddGuide('yAdj', 1, 'vc', '0', 'ihd2');
            f.AddHandleXY(undefined, '0', '0','adj','0','50000', 'hc', 'yAdj');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('sx1', 'sy1', 'sx2', 'sy2');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'sx1', 'sy1');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'sx2', 'sy1');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'sx2', 'sy2');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(2, 'sx1', 'sy2');
            f.AddPathCommand(6);
            break;
        }
        case 'star5':{
            f.AddAdj('adj', 15, '19098');
            f.AddAdj('hf', 15, '105146');
            f.AddAdj('vf', 15, '110557');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('swd2', 0, 'wd2', 'hf', '100000');
            f.AddGuide('shd2', 0, 'hd2', 'vf', '100000');
            f.AddGuide('svc', 0, 'vc', 'vf', '100000');
            f.AddGuide('dx1', 7, 'swd2', '1080000');
            f.AddGuide('dx2', 7, 'swd2', '18360000');
            f.AddGuide('dy1', 12, 'shd2', '1080000');
            f.AddGuide('dy2', 12, 'shd2', '18360000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'hc', 'dx2', '0');
            f.AddGuide('x4', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'svc', '0', 'dy1');
            f.AddGuide('y2', 1, 'svc', '0', 'dy2');
            f.AddGuide('iwd2', 0, 'swd2', 'a', '50000');
            f.AddGuide('ihd2', 0, 'shd2', 'a', '50000');
            f.AddGuide('sdx1', 7, 'iwd2', '20520000');
            f.AddGuide('sdx2', 7, 'iwd2', '3240000');
            f.AddGuide('sdy1', 12, 'ihd2', '3240000');
            f.AddGuide('sdy2', 12, 'ihd2', '20520000');
            f.AddGuide('sx1', 1, 'hc', '0', 'sdx1');
            f.AddGuide('sx2', 1, 'hc', '0', 'sdx2');
            f.AddGuide('sx3', 1, 'hc', 'sdx2', '0');
            f.AddGuide('sx4', 1, 'hc', 'sdx1', '0');
            f.AddGuide('sy1', 1, 'svc', '0', 'sdy1');
            f.AddGuide('sy2', 1, 'svc', '0', 'sdy2');
            f.AddGuide('sy3', 1, 'svc', 'ihd2', '0');
            f.AddGuide('yAdj', 1, 'svc', '0', 'ihd2');
            f.AddHandleXY(undefined, '0', '0','adj','0','50000', 'hc', 'yAdj');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'x1', 'y1');
            f.AddCnx('cd4', 'x2', 'y2');
            f.AddCnx('cd4', 'x3', 'y2');
            f.AddCnx('0', 'x4', 'y1');
            f.AddRect('sx1', 'sy1', 'sx4', 'sy3');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(2, 'sx2', 'sy1');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'sx3', 'sy1');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(2, 'sx4', 'sy2');
            f.AddPathCommand(2, 'x3', 'y2');
            f.AddPathCommand(2, 'hc', 'sy3');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'sx1', 'sy2');
            f.AddPathCommand(6);
            break;
        }
        case 'star6':{
            f.AddAdj('adj', 15, '28868');
            f.AddAdj('hf', 15, '115470');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('swd2', 0, 'wd2', 'hf', '100000');
            f.AddGuide('dx1', 7, 'swd2', '1800000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', 'dx1', '0');
            f.AddGuide('y2', 1, 'vc', 'hd4', '0');
            f.AddGuide('iwd2', 0, 'swd2', 'a', '50000');
            f.AddGuide('ihd2', 0, 'hd2', 'a', '50000');
            f.AddGuide('sdx2', 0, 'iwd2', '1', '2');
            f.AddGuide('sx1', 1, 'hc', '0', 'iwd2');
            f.AddGuide('sx2', 1, 'hc', '0', 'sdx2');
            f.AddGuide('sx3', 1, 'hc', 'sdx2', '0');
            f.AddGuide('sx4', 1, 'hc', 'iwd2', '0');
            f.AddGuide('sdy1', 12, 'ihd2', '3600000');
            f.AddGuide('sy1', 1, 'vc', '0', 'sdy1');
            f.AddGuide('sy2', 1, 'vc', 'sdy1', '0');
            f.AddGuide('yAdj', 1, 'vc', '0', 'ihd2');
            f.AddHandleXY(undefined, '0', '0','adj','0','50000', 'hc', 'yAdj');
            f.AddCnx('0', 'x2', 'hd4');
            f.AddCnx('0', 'x2', 'y2');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'x1', 'y2');
            f.AddCnx('cd2', 'x1', 'hd4');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('sx1', 'sy1', 'sx4', 'sy2');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'hd4');
            f.AddPathCommand(2, 'sx2', 'sy1');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'sx3', 'sy1');
            f.AddPathCommand(2, 'x2', 'hd4');
            f.AddPathCommand(2, 'sx4', 'vc');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'sx3', 'sy2');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(2, 'sx2', 'sy2');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(2, 'sx1', 'vc');
            f.AddPathCommand(6);
            break;
        }
        case 'star7':{
            f.AddAdj('adj', 15, '34601');
            f.AddAdj('hf', 15, '102572');
            f.AddAdj('vf', 15, '105210');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('swd2', 0, 'wd2', 'hf', '100000');
            f.AddGuide('shd2', 0, 'hd2', 'vf', '100000');
            f.AddGuide('svc', 0, 'vc', 'vf', '100000');
            f.AddGuide('dx1', 0, 'swd2', '97493', '100000');
            f.AddGuide('dx2', 0, 'swd2', '78183', '100000');
            f.AddGuide('dx3', 0, 'swd2', '43388', '100000');
            f.AddGuide('dy1', 0, 'shd2', '62349', '100000');
            f.AddGuide('dy2', 0, 'shd2', '22252', '100000');
            f.AddGuide('dy3', 0, 'shd2', '90097', '100000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'hc', '0', 'dx3');
            f.AddGuide('x4', 1, 'hc', 'dx3', '0');
            f.AddGuide('x5', 1, 'hc', 'dx2', '0');
            f.AddGuide('x6', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'svc', '0', 'dy1');
            f.AddGuide('y2', 1, 'svc', 'dy2', '0');
            f.AddGuide('y3', 1, 'svc', 'dy3', '0');
            f.AddGuide('iwd2', 0, 'swd2', 'a', '50000');
            f.AddGuide('ihd2', 0, 'shd2', 'a', '50000');
            f.AddGuide('sdx1', 0, 'iwd2', '97493', '100000');
            f.AddGuide('sdx2', 0, 'iwd2', '78183', '100000');
            f.AddGuide('sdx3', 0, 'iwd2', '43388', '100000');
            f.AddGuide('sx1', 1, 'hc', '0', 'sdx1');
            f.AddGuide('sx2', 1, 'hc', '0', 'sdx2');
            f.AddGuide('sx3', 1, 'hc', '0', 'sdx3');
            f.AddGuide('sx4', 1, 'hc', 'sdx3', '0');
            f.AddGuide('sx5', 1, 'hc', 'sdx2', '0');
            f.AddGuide('sx6', 1, 'hc', 'sdx1', '0');
            f.AddGuide('sdy1', 0, 'ihd2', '90097', '100000');
            f.AddGuide('sdy2', 0, 'ihd2', '22252', '100000');
            f.AddGuide('sdy3', 0, 'ihd2', '62349', '100000');
            f.AddGuide('sy1', 1, 'svc', '0', 'sdy1');
            f.AddGuide('sy2', 1, 'svc', '0', 'sdy2');
            f.AddGuide('sy3', 1, 'svc', 'sdy3', '0');
            f.AddGuide('sy4', 1, 'svc', 'ihd2', '0');
            f.AddGuide('yAdj', 1, 'svc', '0', 'ihd2');
            f.AddHandleXY(undefined, '0', '0','adj','0','50000', 'hc', 'yAdj');
            f.AddCnx('0', 'x5', 'y1');
            f.AddCnx('0', 'x6', 'y2');
            f.AddCnx('cd4', 'x4', 'y3');
            f.AddCnx('cd4', 'x3', 'y3');
            f.AddCnx('cd2', 'x1', 'y2');
            f.AddCnx('cd2', 'x2', 'y1');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddRect('sx2', 'sy1', 'sx5', 'sy3');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y2');
            f.AddPathCommand(2, 'sx1', 'sy2');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'sx3', 'sy1');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'sx4', 'sy1');
            f.AddPathCommand(2, 'x5', 'y1');
            f.AddPathCommand(2, 'sx6', 'sy2');
            f.AddPathCommand(2, 'x6', 'y2');
            f.AddPathCommand(2, 'sx5', 'sy3');
            f.AddPathCommand(2, 'x4', 'y3');
            f.AddPathCommand(2, 'hc', 'sy4');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(2, 'sx2', 'sy3');
            f.AddPathCommand(6);
            break;
        }
        case 'star8':{
            f.AddAdj('adj', 15, '37500');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('dx1', 7, 'wd2', '2700000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', 'dx1', '0');
            f.AddGuide('dy1', 12, 'hd2', '2700000');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y2', 1, 'vc', 'dy1', '0');
            f.AddGuide('iwd2', 0, 'wd2', 'a', '50000');
            f.AddGuide('ihd2', 0, 'hd2', 'a', '50000');
            f.AddGuide('sdx1', 0, 'iwd2', '92388', '100000');
            f.AddGuide('sdx2', 0, 'iwd2', '38268', '100000');
            f.AddGuide('sdy1', 0, 'ihd2', '92388', '100000');
            f.AddGuide('sdy2', 0, 'ihd2', '38268', '100000');
            f.AddGuide('sx1', 1, 'hc', '0', 'sdx1');
            f.AddGuide('sx2', 1, 'hc', '0', 'sdx2');
            f.AddGuide('sx3', 1, 'hc', 'sdx2', '0');
            f.AddGuide('sx4', 1, 'hc', 'sdx1', '0');
            f.AddGuide('sy1', 1, 'vc', '0', 'sdy1');
            f.AddGuide('sy2', 1, 'vc', '0', 'sdy2');
            f.AddGuide('sy3', 1, 'vc', 'sdy2', '0');
            f.AddGuide('sy4', 1, 'vc', 'sdy1', '0');
            f.AddGuide('yAdj', 1, 'vc', '0', 'ihd2');
            f.AddHandleXY(undefined, '0', '0','adj','0','50000', 'hc', 'yAdj');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'x2', 'y2');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd4', 'x1', 'y2');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'x1', 'y1');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('_3cd4', 'x2', 'y1');
            f.AddRect('sx1', 'sy1', 'sx4', 'sy4');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'sx1', 'sy2');
            f.AddPathCommand(2, 'x1', 'y1');
            f.AddPathCommand(2, 'sx2', 'sy1');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'sx3', 'sy1');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'sx4', 'sy2');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'sx4', 'sy3');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'sx3', 'sy4');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(2, 'sx2', 'sy4');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(2, 'sx1', 'sy3');
            f.AddPathCommand(6);
            break;
        }
        case 'straightConnector1':{
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 'b');
            break;
        }
        case 'stripedRightArrow':{
            f.AddAdj('adj1', 15, '50000');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('maxAdj2', 0, '84375', 'w', 'ss');
            f.AddGuide('a1', 10, '0', 'adj1', '100000');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('x4', 0, 'ss', '5', '32');
            f.AddGuide('dx5', 0, 'ss', 'a2', '100000');
            f.AddGuide('x5', 1, 'r', '0', 'dx5');
            f.AddGuide('dy1', 0, 'h', 'a1', '200000');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('y2', 1, 'vc', 'dy1', '0');
            f.AddGuide('dx6', 0, 'dy1', 'dx5', 'hd2');
            f.AddGuide('x6', 1, 'r', '0', 'dx6');
            f.AddHandleXY(undefined, '0', '0','adj1','0','100000', 'l', 'y1');
            f.AddHandleXY('adj2','0','maxAdj2', undefined, '0', '0', 'x5', 't');
            f.AddCnx('_3cd4', 'x5', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'x5', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('x4', 'y1', 'x6', 'y2');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(2, 'ssd32', 'y1');
            f.AddPathCommand(2, 'ssd32', 'y2');
            f.AddPathCommand(2, 'l', 'y2');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'ssd16', 'y1');
            f.AddPathCommand(2, 'ssd8', 'y1');
            f.AddPathCommand(2, 'ssd8', 'y2');
            f.AddPathCommand(2, 'ssd16', 'y2');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x4', 'y1');
            f.AddPathCommand(2, 'x5', 'y1');
            f.AddPathCommand(2, 'x5', 't');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(2, 'x5', 'b');
            f.AddPathCommand(2, 'x5', 'y2');
            f.AddPathCommand(2, 'x4', 'y2');
            f.AddPathCommand(6);
            break;
        }
        case 'sun':{
            f.AddAdj('adj', 15, '25000');
            f.AddGuide('a', 10, '12500', 'adj', '46875');
            f.AddGuide('g0', 1, '50000', '0', 'a');
            f.AddGuide('g1', 0, 'g0', '30274', '32768');
            f.AddGuide('g2', 0, 'g0', '12540', '32768');
            f.AddGuide('g3', 1, 'g1', '50000', '0');
            f.AddGuide('g4', 1, 'g2', '50000', '0');
            f.AddGuide('g5', 1, '50000', '0', 'g1');
            f.AddGuide('g6', 1, '50000', '0', 'g2');
            f.AddGuide('g7', 0, 'g0', '23170', '32768');
            f.AddGuide('g8', 1, '50000', 'g7', '0');
            f.AddGuide('g9', 1, '50000', '0', 'g7');
            f.AddGuide('g10', 0, 'g5', '3', '4');
            f.AddGuide('g11', 0, 'g6', '3', '4');
            f.AddGuide('g12', 1, 'g10', '3662', '0');
            f.AddGuide('g13', 1, 'g11', '3662', '0');
            f.AddGuide('g14', 1, 'g11', '12500', '0');
            f.AddGuide('g15', 1, '100000', '0', 'g10');
            f.AddGuide('g16', 1, '100000', '0', 'g12');
            f.AddGuide('g17', 1, '100000', '0', 'g13');
            f.AddGuide('g18', 1, '100000', '0', 'g14');
            f.AddGuide('ox1', 0, 'w', '18436', '21600');
            f.AddGuide('oy1', 0, 'h', '3163', '21600');
            f.AddGuide('ox2', 0, 'w', '3163', '21600');
            f.AddGuide('oy2', 0, 'h', '18436', '21600');
            f.AddGuide('x8', 0, 'w', 'g8', '100000');
            f.AddGuide('x9', 0, 'w', 'g9', '100000');
            f.AddGuide('x10', 0, 'w', 'g10', '100000');
            f.AddGuide('x12', 0, 'w', 'g12', '100000');
            f.AddGuide('x13', 0, 'w', 'g13', '100000');
            f.AddGuide('x14', 0, 'w', 'g14', '100000');
            f.AddGuide('x15', 0, 'w', 'g15', '100000');
            f.AddGuide('x16', 0, 'w', 'g16', '100000');
            f.AddGuide('x17', 0, 'w', 'g17', '100000');
            f.AddGuide('x18', 0, 'w', 'g18', '100000');
            f.AddGuide('x19', 0, 'w', 'a', '100000');
            f.AddGuide('wR', 0, 'w', 'g0', '100000');
            f.AddGuide('hR', 0, 'h', 'g0', '100000');
            f.AddGuide('y8', 0, 'h', 'g8', '100000');
            f.AddGuide('y9', 0, 'h', 'g9', '100000');
            f.AddGuide('y10', 0, 'h', 'g10', '100000');
            f.AddGuide('y12', 0, 'h', 'g12', '100000');
            f.AddGuide('y13', 0, 'h', 'g13', '100000');
            f.AddGuide('y14', 0, 'h', 'g14', '100000');
            f.AddGuide('y15', 0, 'h', 'g15', '100000');
            f.AddGuide('y16', 0, 'h', 'g16', '100000');
            f.AddGuide('y17', 0, 'h', 'g17', '100000');
            f.AddGuide('y18', 0, 'h', 'g18', '100000');
            f.AddHandleXY('adj','12500','46875', undefined, '0', '0', 'x19', 'vc');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('x9', 'y9', 'x8', 'y8');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'r', 'vc');
            f.AddPathCommand(2, 'x15', 'y18');
            f.AddPathCommand(2, 'x15', 'y14');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'ox1', 'oy1');
            f.AddPathCommand(2, 'x16', 'y13');
            f.AddPathCommand(2, 'x17', 'y12');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'hc', 't');
            f.AddPathCommand(2, 'x18', 'y10');
            f.AddPathCommand(2, 'x14', 'y10');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'ox2', 'oy1');
            f.AddPathCommand(2, 'x13', 'y12');
            f.AddPathCommand(2, 'x12', 'y13');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'x10', 'y14');
            f.AddPathCommand(2, 'x10', 'y18');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'ox2', 'oy2');
            f.AddPathCommand(2, 'x12', 'y17');
            f.AddPathCommand(2, 'x13', 'y16');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'hc', 'b');
            f.AddPathCommand(2, 'x14', 'y15');
            f.AddPathCommand(2, 'x18', 'y15');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'ox1', 'oy2');
            f.AddPathCommand(2, 'x17', 'y16');
            f.AddPathCommand(2, 'x16', 'y17');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x19', 'vc');
            f.AddPathCommand(3, 'wR', 'hR', 'cd2', '21600000');
            f.AddPathCommand(6);
            break;
        }
        case 'swooshArrow':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '16667');
            f.AddGuide('a1', 10, '1', 'adj1', '75000');
            f.AddGuide('maxAdj2', 0, '70000', 'w', 'ss');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('ad1', 0, 'h', 'a1', '100000');
            f.AddGuide('ad2', 0, 'ss', 'a2', '100000');
            f.AddGuide('xB', 1, 'r', '0', 'ad2');
            f.AddGuide('yB', 1, 't', 'ssd8', '0');
            f.AddGuide('alfa', 0, 'cd4', '1', '14');
            f.AddGuide('dx0', 14, 'ssd8', 'alfa');
            f.AddGuide('xC', 1, 'xB', '0', 'dx0');
            f.AddGuide('dx1', 14, 'ad1', 'alfa');
            f.AddGuide('yF', 1, 'yB', 'ad1', '0');
            f.AddGuide('xF', 1, 'xB', 'dx1', '0');
            f.AddGuide('xE', 1, 'xF', 'dx0', '0');
            f.AddGuide('yE', 1, 'yF', 'ssd8', '0');
            f.AddGuide('dy2', 1, 'yE', '0', 't');
            f.AddGuide('dy22', 0, 'dy2', '1', '2');
            f.AddGuide('dy3', 0, 'h', '1', '20');
            f.AddGuide('yD', 1, 't', 'dy22', 'dy3');
            f.AddGuide('dy4', 0, 'hd6', '1', '1');
            f.AddGuide('yP1', 1, 'hd6', 'dy4', '0');
            f.AddGuide('xP1', 15, 'wd6');
            f.AddGuide('dy5', 0, 'hd6', '1', '2');
            f.AddGuide('yP2', 1, 'yF', 'dy5', '0');
            f.AddGuide('xP2', 15, 'wd4');
            f.AddHandleXY(undefined, '0', '0','adj1','1','75000', 'xF', 'yF');
            f.AddHandleXY('adj2','0','maxAdj2', undefined, '0', '0', 'xB', 'yB');
            f.AddCnx('cd4', 'l', 'b');
            f.AddCnx('_3cd4', 'xC', 't');
            f.AddCnx('0', 'r', 'yD');
            f.AddCnx('cd4', 'xE', 'yE');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(4, 'xP1', 'yP1', 'xB', 'yB');
            f.AddPathCommand(2, 'xC', 't');
            f.AddPathCommand(2, 'r', 'yD');
            f.AddPathCommand(2, 'xE', 'yE');
            f.AddPathCommand(2, 'xF', 'yF');
            f.AddPathCommand(4, 'xP2', 'yP2', 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'teardrop':{
            f.AddAdj('adj', 15, '100000');
            f.AddGuide('a', 10, '0', 'adj', '200000');
            f.AddGuide('r2', 13, '2');
            f.AddGuide('tw', 0, 'wd2', 'r2', '1');
            f.AddGuide('th', 0, 'hd2', 'r2', '1');
            f.AddGuide('sw', 0, 'tw', 'a', '100000');
            f.AddGuide('sh', 0, 'th', 'a', '100000');
            f.AddGuide('dx1', 7, 'sw', '2700000');
            f.AddGuide('dy1', 12, 'sh', '2700000');
            f.AddGuide('x1', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', '0', 'dy1');
            f.AddGuide('x2', 2, 'hc', 'x1', '2');
            f.AddGuide('y2', 2, 'vc', 'y1', '2');
            f.AddGuide('idx', 7, 'wd2', '2700000');
            f.AddGuide('idy', 12, 'hd2', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddHandleXY('adj','0','200000', undefined, '0', '0', 'x1', 't');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'ir', 'ib');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd4', 'il', 'ib');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('_3cd4', 'il', 'it');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('_3cd4', 'x1', 'y1');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd2', 'cd4');
            f.AddPathCommand(4, 'x2', 't', 'x1', 'y1');
            f.AddPathCommand(4, 'r', 'y2', 'r', 'vc');
            f.AddPathCommand(3, 'wd2', 'hd2', '0', 'cd4');
            f.AddPathCommand(3, 'wd2', 'hd2', 'cd4', 'cd4');
            f.AddPathCommand(6);
            break;
        }
        case 'trapezoid':{
            f.AddAdj('adj', 15, '25000');
            f.AddGuide('maxAdj', 0, '50000', 'w', 'ss');
            f.AddGuide('a', 10, '0', 'adj', 'maxAdj');
            f.AddGuide('x1', 0, 'ss', 'a', '200000');
            f.AddGuide('x2', 0, 'ss', 'a', '100000');
            f.AddGuide('x3', 1, 'r', '0', 'x2');
            f.AddGuide('x4', 1, 'r', '0', 'x1');
            f.AddGuide('il', 0, 'wd3', 'a', 'maxAdj');
            f.AddGuide('it', 0, 'hd3', 'a', 'maxAdj');
            f.AddGuide('ir', 1, 'r', '0', 'il');
            f.AddHandleXY('adj','0','maxAdj', undefined, '0', '0', 'x2', 't');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'x1', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'x4', 'vc');
            f.AddRect('il', 'it', 'ir', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'x3', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'triangle':{
            f.AddAdj('adj', 15, '50000');
            f.AddGuide('a', 10, '0', 'adj', '100000');
            f.AddGuide('x1', 0, 'w', 'a', '200000');
            f.AddGuide('x2', 0, 'w', 'a', '100000');
            f.AddGuide('x3', 1, 'x1', 'wd2', '0');
            f.AddHandleXY('adj','0','100000', undefined, '0', '0', 'x2', 't');
            f.AddCnx('_3cd4', 'x2', 't');
            f.AddCnx('cd2', 'x1', 'vc');
            f.AddCnx('cd4', 'l', 'b');
            f.AddCnx('cd4', 'x2', 'b');
            f.AddCnx('cd4', 'r', 'b');
            f.AddCnx('0', 'x3', 'vc');
            f.AddRect('x1', 'vc', 'x3', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'upArrowCallout':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '25000');
            f.AddAdj('adj3', 15, '25000');
            f.AddAdj('adj4', 15, '64977');
            f.AddGuide('maxAdj2', 0, '50000', 'w', 'ss');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('maxAdj1', 0, 'a2', '2', '1');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('maxAdj3', 0, '100000', 'h', 'ss');
            f.AddGuide('a3', 10, '0', 'adj3', 'maxAdj3');
            f.AddGuide('q2', 0, 'a3', 'ss', 'h');
            f.AddGuide('maxAdj4', 1, '100000', '0', 'q2');
            f.AddGuide('a4', 10, '0', 'adj4', 'maxAdj4');
            f.AddGuide('dx1', 0, 'ss', 'a2', '100000');
            f.AddGuide('dx2', 0, 'ss', 'a1', '200000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'hc', 'dx2', '0');
            f.AddGuide('x4', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 0, 'ss', 'a3', '100000');
            f.AddGuide('dy2', 0, 'h', 'a4', '100000');
            f.AddGuide('y2', 1, 'b', '0', 'dy2');
            f.AddGuide('y3', 2, 'y2', 'b', '2');
            f.AddHandleXY('adj1','0','maxAdj1', undefined, '0', '0', 'x2', 'y1');
            f.AddHandleXY('adj2','0','maxAdj2', undefined, '0', '0', 'x1', 't');
            f.AddHandleXY(undefined, '0', '0','adj3','0','maxAdj3', 'r', 'y1');
            f.AddHandleXY(undefined, '0', '0','adj4','0','maxAdj4', 'l', 'y2');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'y2');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'y2');
            f.AddRect('l', 'y2', 'r', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y2');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'x1', 'y1');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(2, 'x3', 'y2');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'upDownArrow':{
            f.AddAdj('adj1', 15, '50000');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('maxAdj2', 0, '50000', 'h', 'ss');
            f.AddGuide('a1', 10, '0', 'adj1', '100000');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('y2', 0, 'ss', 'a2', '100000');
            f.AddGuide('y3', 1, 'b', '0', 'y2');
            f.AddGuide('dx1', 0, 'w', 'a1', '200000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', 'dx1', '0');
            f.AddGuide('dy1', 0, 'x1', 'y2', 'wd2');
            f.AddGuide('y1', 1, 'y2', '0', 'dy1');
            f.AddGuide('y4', 1, 'y3', 'dy1', '0');
            f.AddHandleXY('adj1','0','100000', undefined, '0', '0', 'x1', 'y3');
            f.AddHandleXY(undefined, '0', '0','adj2','0','maxAdj2', 'l', 'y2');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'y2');
            f.AddCnx('cd2', 'x1', 'vc');
            f.AddCnx('cd2', 'l', 'y3');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'y3');
            f.AddCnx('0', 'x2', 'vc');
            f.AddCnx('0', 'r', 'y2');
            f.AddRect('x1', 'y1', 'x2', 'y4');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y2');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x2', 'y3');
            f.AddPathCommand(2, 'r', 'y3');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(2, 'l', 'y3');
            f.AddPathCommand(2, 'x1', 'y3');
            f.AddPathCommand(2, 'x1', 'y2');
            f.AddPathCommand(6);
            break;
        }
        case 'upDownArrowCallout':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '25000');
            f.AddAdj('adj3', 15, '25000');
            f.AddAdj('adj4', 15, '48123');
            f.AddGuide('maxAdj2', 0, '50000', 'w', 'ss');
            f.AddGuide('a2', 10, '0', 'adj2', 'maxAdj2');
            f.AddGuide('maxAdj1', 0, 'a2', '2', '1');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('maxAdj3', 0, '50000', 'h', 'ss');
            f.AddGuide('a3', 10, '0', 'adj3', 'maxAdj3');
            f.AddGuide('q2', 0, 'a3', 'ss', 'hd2');
            f.AddGuide('maxAdj4', 1, '100000', '0', 'q2');
            f.AddGuide('a4', 10, '0', 'adj4', 'maxAdj4');
            f.AddGuide('dx1', 0, 'ss', 'a2', '100000');
            f.AddGuide('dx2', 0, 'ss', 'a1', '200000');
            f.AddGuide('x1', 1, 'hc', '0', 'dx1');
            f.AddGuide('x2', 1, 'hc', '0', 'dx2');
            f.AddGuide('x3', 1, 'hc', 'dx2', '0');
            f.AddGuide('x4', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 0, 'ss', 'a3', '100000');
            f.AddGuide('y4', 1, 'b', '0', 'y1');
            f.AddGuide('dy2', 0, 'h', 'a4', '200000');
            f.AddGuide('y2', 1, 'vc', '0', 'dy2');
            f.AddGuide('y3', 1, 'vc', 'dy2', '0');
            f.AddHandleXY('adj1','0','maxAdj1', undefined, '0', '0', 'x2', 'y1');
            f.AddHandleXY('adj2','0','maxAdj2', undefined, '0', '0', 'x1', 't');
            f.AddHandleXY(undefined, '0', '0','adj3','0','maxAdj3', 'r', 'y1');
            f.AddHandleXY(undefined, '0', '0','adj4','0','maxAdj4', 'l', 'y2');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddRect('l', 'y2', 'r', 'y3');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y2');
            f.AddPathCommand(2, 'x2', 'y2');
            f.AddPathCommand(2, 'x2', 'y1');
            f.AddPathCommand(2, 'x1', 'y1');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'x4', 'y1');
            f.AddPathCommand(2, 'x3', 'y1');
            f.AddPathCommand(2, 'x3', 'y2');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(2, 'r', 'y3');
            f.AddPathCommand(2, 'x3', 'y3');
            f.AddPathCommand(2, 'x3', 'y4');
            f.AddPathCommand(2, 'x4', 'y4');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(2, 'x1', 'y4');
            f.AddPathCommand(2, 'x2', 'y4');
            f.AddPathCommand(2, 'x2', 'y3');
            f.AddPathCommand(2, 'l', 'y3');
            f.AddPathCommand(6);
            break;
        }
        case 'uturnArrow':{
            f.AddAdj('adj1', 15, '25000');
            f.AddAdj('adj2', 15, '25000');
            f.AddAdj('adj3', 15, '25000');
            f.AddAdj('adj4', 15, '43750');
            f.AddAdj('adj5', 15, '75000');
            f.AddGuide('a2', 10, '0', 'adj2', '25000');
            f.AddGuide('maxAdj1', 0, 'a2', '2', '1');
            f.AddGuide('a1', 10, '0', 'adj1', 'maxAdj1');
            f.AddGuide('q2', 0, 'a1', 'ss', 'h');
            f.AddGuide('q3', 1, '100000', '0', 'q2');
            f.AddGuide('maxAdj3', 0, 'q3', 'h', 'ss');
            f.AddGuide('a3', 10, '0', 'adj3', 'maxAdj3');
            f.AddGuide('q1', 1, 'a3', 'a1', '0');
            f.AddGuide('minAdj5', 0, 'q1', 'ss', 'h');
            f.AddGuide('a5', 10, 'minAdj5', 'adj5', '100000');
            f.AddGuide('th', 0, 'ss', 'a1', '100000');
            f.AddGuide('aw2', 0, 'ss', 'a2', '100000');
            f.AddGuide('th2', 0, 'th', '1', '2');
            f.AddGuide('dh2', 1, 'aw2', '0', 'th2');
            f.AddGuide('y5', 0, 'h', 'a5', '100000');
            f.AddGuide('ah', 0, 'ss', 'a3', '100000');
            f.AddGuide('y4', 1, 'y5', '0', 'ah');
            f.AddGuide('x9', 1, 'r', '0', 'dh2');
            f.AddGuide('bw', 0, 'x9', '1', '2');
            f.AddGuide('bs', 16, 'bw', 'y4');
            f.AddGuide('maxAdj4', 0, 'bs', '100000', 'ss');
            f.AddGuide('a4', 10, '0', 'adj4', 'maxAdj4');
            f.AddGuide('bd', 0, 'ss', 'a4', '100000');
            f.AddGuide('bd3', 1, 'bd', '0', 'th');
            f.AddGuide('bd2', 8, 'bd3', '0');
            f.AddGuide('x3', 1, 'th', 'bd2', '0');
            f.AddGuide('x8', 1, 'r', '0', 'aw2');
            f.AddGuide('x6', 1, 'x8', '0', 'aw2');
            f.AddGuide('x7', 1, 'x6', 'dh2', '0');
            f.AddGuide('x4', 1, 'x9', '0', 'bd');
            f.AddGuide('x5', 1, 'x7', '0', 'bd2');
            f.AddGuide('cx', 2, 'th', 'x7', '2');
            f.AddHandleXY('adj1','0','maxAdj1', undefined, '0', '0', 'th', 'b');
            f.AddHandleXY('adj2','0','25000', undefined, '0', '0', 'x6', 'b');
            f.AddHandleXY(undefined, '0', '0','adj3','0','maxAdj3', 'x6', 'y4');
            f.AddHandleXY('adj4','0','maxAdj4', undefined, '0', '0', 'bd', 't');
            f.AddHandleXY(undefined, '0', '0','adj5','minAdj5','100000', 'r', 'y5');
            f.AddCnx('cd4', 'x6', 'y4');
            f.AddCnx('cd4', 'x8', 'y5');
            f.AddCnx('0', 'r', 'y4');
            f.AddCnx('_3cd4', 'cx', 't');
            f.AddCnx('cd4', 'th2', 'b');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'l', 'bd');
            f.AddPathCommand(3, 'bd', 'bd', 'cd2', 'cd4');
            f.AddPathCommand(2, 'x4', 't');
            f.AddPathCommand(3, 'bd', 'bd', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'x9', 'y4');
            f.AddPathCommand(2, 'r', 'y4');
            f.AddPathCommand(2, 'x8', 'y5');
            f.AddPathCommand(2, 'x6', 'y4');
            f.AddPathCommand(2, 'x7', 'y4');
            f.AddPathCommand(2, 'x7', 'x3');
            f.AddPathCommand(3, 'bd2', 'bd2', '0', '-5400000');
            f.AddPathCommand(2, 'x3', 'th');
            f.AddPathCommand(3, 'bd2', 'bd2', '_3cd4', '-5400000');
            f.AddPathCommand(2, 'th', 'b');
            f.AddPathCommand(6);
            break;
        }
        case 'verticalScroll':{
            f.AddAdj('adj', 15, '12500');
            f.AddGuide('a', 10, '0', 'adj', '25000');
            f.AddGuide('ch', 0, 'ss', 'a', '100000');
            f.AddGuide('ch2', 0, 'ch', '1', '2');
            f.AddGuide('ch4', 0, 'ch', '1', '4');
            f.AddGuide('x3', 1, 'ch', 'ch2', '0');
            f.AddGuide('x4', 1, 'ch', 'ch', '0');
            f.AddGuide('x6', 1, 'r', '0', 'ch');
            f.AddGuide('x7', 1, 'r', '0', 'ch2');
            f.AddGuide('x5', 1, 'x6', '0', 'ch2');
            f.AddGuide('y3', 1, 'b', '0', 'ch');
            f.AddGuide('y4', 1, 'b', '0', 'ch2');
            f.AddHandleXY(undefined, '0', '0','adj','0','25000', 'l', 'ch');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('0', 'ch', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd2', 'x6', 'vc');
            f.AddRect('ch', 'ch', 'x6', 'y4');
            f.AddPathCommand(0,false, undefined, false, undefined, undefined);
            f.AddPathCommand(1, 'ch2', 'b');
            f.AddPathCommand(3, 'ch2', 'ch2', 'cd4', '-5400000');
            f.AddPathCommand(2, 'ch2', 'y4');
            f.AddPathCommand(3, 'ch4', 'ch4', 'cd4', '-10800000');
            f.AddPathCommand(2, 'ch', 'y3');
            f.AddPathCommand(2, 'ch', 'ch2');
            f.AddPathCommand(3, 'ch2', 'ch2', 'cd2', 'cd4');
            f.AddPathCommand(2, 'x7', 't');
            f.AddPathCommand(3, 'ch2', 'ch2', '_3cd4', 'cd2');
            f.AddPathCommand(2, 'x6', 'ch');
            f.AddPathCommand(2, 'x6', 'y4');
            f.AddPathCommand(3, 'ch2', 'ch2', '0', 'cd4');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x4', 'ch2');
            f.AddPathCommand(3, 'ch2', 'ch2', '0', 'cd4');
            f.AddPathCommand(3, 'ch4', 'ch4', 'cd4', 'cd2');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'darkenLess', false, undefined, undefined);
            f.AddPathCommand(1, 'x4', 'ch2');
            f.AddPathCommand(3, 'ch2', 'ch2', '0', 'cd4');
            f.AddPathCommand(3, 'ch4', 'ch4', 'cd4', 'cd2');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'ch', 'y4');
            f.AddPathCommand(3, 'ch2', 'ch2', '0', '_3cd4');
            f.AddPathCommand(3, 'ch4', 'ch4', '_3cd4', 'cd2');
            f.AddPathCommand(6);
            f.AddPathCommand(0,false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'ch', 'y3');
            f.AddPathCommand(2, 'ch', 'ch2');
            f.AddPathCommand(3, 'ch2', 'ch2', 'cd2', 'cd4');
            f.AddPathCommand(2, 'x7', 't');
            f.AddPathCommand(3, 'ch2', 'ch2', '_3cd4', 'cd2');
            f.AddPathCommand(2, 'x6', 'ch');
            f.AddPathCommand(2, 'x6', 'y4');
            f.AddPathCommand(3, 'ch2', 'ch2', '0', 'cd4');
            f.AddPathCommand(2, 'ch2', 'b');
            f.AddPathCommand(3, 'ch2', 'ch2', 'cd4', 'cd2');
            f.AddPathCommand(6);
            f.AddPathCommand(1, 'x3', 't');
            f.AddPathCommand(3, 'ch2', 'ch2', '_3cd4', 'cd2');
            f.AddPathCommand(3, 'ch4', 'ch4', 'cd4', 'cd2');
            f.AddPathCommand(2, 'x4', 'ch2');
            f.AddPathCommand(1, 'x6', 'ch');
            f.AddPathCommand(2, 'x3', 'ch');
            f.AddPathCommand(1, 'ch2', 'y3');
            f.AddPathCommand(3, 'ch4', 'ch4', '_3cd4', 'cd2');
            f.AddPathCommand(2, 'ch', 'y4');
            f.AddPathCommand(1, 'ch2', 'b');
            f.AddPathCommand(3, 'ch2', 'ch2', 'cd4', '-5400000');
            f.AddPathCommand(2, 'ch', 'y3');
            break;
        }
        case 'wave':{
            f.AddAdj('adj1', 15, '12500');
            f.AddAdj('adj2', 15, '0');
            f.AddGuide('a1', 10, '0', 'adj1', '20000');
            f.AddGuide('a2', 10, '-10000', 'adj2', '10000');
            f.AddGuide('y1', 0, 'h', 'a1', '100000');
            f.AddGuide('dy2', 0, 'y1', '10', '3');
            f.AddGuide('y2', 1, 'y1', '0', 'dy2');
            f.AddGuide('y3', 1, 'y1', 'dy2', '0');
            f.AddGuide('y4', 1, 'b', '0', 'y1');
            f.AddGuide('y5', 1, 'y4', '0', 'dy2');
            f.AddGuide('y6', 1, 'y4', 'dy2', '0');
            f.AddGuide('dx1', 0, 'w', 'a2', '100000');
            f.AddGuide('of2', 0, 'w', 'a2', '50000');
            f.AddGuide('x1', 4, 'dx1');
            f.AddGuide('dx2', 3, 'of2', '0', 'of2');
            f.AddGuide('x2', 1, 'l', '0', 'dx2');
            f.AddGuide('dx5', 3, 'of2', 'of2', '0');
            f.AddGuide('x5', 1, 'r', '0', 'dx5');
            f.AddGuide('dx3', 2, 'dx2', 'x5', '3');
            f.AddGuide('x3', 1, 'x2', 'dx3', '0');
            f.AddGuide('x4', 2, 'x3', 'x5', '2');
            f.AddGuide('x6', 1, 'l', 'dx5', '0');
            f.AddGuide('x10', 1, 'r', 'dx2', '0');
            f.AddGuide('x7', 1, 'x6', 'dx3', '0');
            f.AddGuide('x8', 2, 'x7', 'x10', '2');
            f.AddGuide('x9', 1, 'r', '0', 'x1');
            f.AddGuide('xAdj', 1, 'hc', 'dx1', '0');
            f.AddGuide('xAdj2', 1, 'hc', '0', 'dx1');
            f.AddGuide('il', 8, 'x2', 'x6');
            f.AddGuide('ir', 16, 'x5', 'x10');
            f.AddGuide('it', 0, 'h', 'a1', '50000');
            f.AddGuide('ib', 1, 'b', '0', 'it');
            f.AddHandleXY(undefined, '0', '0','adj1','0','20000', 'l', 'y1');
            f.AddHandleXY('adj2','-10000','10000', undefined, '0', '0', 'xAdj', 'b');
            f.AddCnx('cd4', 'xAdj2', 'y1');
            f.AddCnx('cd2', 'x1', 'vc');
            f.AddCnx('_3cd4', 'xAdj', 'y4');
            f.AddCnx('0', 'x9', 'vc');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'x2', 'y1');
            f.AddPathCommand(5, 'x3', 'y2', 'x4', 'y3', 'x5', 'y1');
            f.AddPathCommand(2, 'x10', 'y4');
            f.AddPathCommand(5, 'x8', 'y6', 'x7', 'y5', 'x6', 'y4');
            f.AddPathCommand(6);
            break;
        }
        case 'wedgeEllipseCallout':{
            f.AddAdj('adj1', 15, '-20833');
            f.AddAdj('adj2', 15, '62500');
            f.AddGuide('dxPos', 0, 'w', 'adj1', '100000');
            f.AddGuide('dyPos', 0, 'h', 'adj2', '100000');
            f.AddGuide('xPos', 1, 'hc', 'dxPos', '0');
            f.AddGuide('yPos', 1, 'vc', 'dyPos', '0');
            f.AddGuide('sdx', 0, 'dxPos', 'h', '1');
            f.AddGuide('sdy', 0, 'dyPos', 'w', '1');
            f.AddGuide('pang', 5, 'sdx', 'sdy');
            f.AddGuide('stAng', 1, 'pang', '660000', '0');
            f.AddGuide('enAng', 1, 'pang', '0', '660000');
            f.AddGuide('dx1', 7, 'wd2', 'stAng');
            f.AddGuide('dy1', 12, 'hd2', 'stAng');
            f.AddGuide('x1', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', 'dy1', '0');
            f.AddGuide('dx2', 7, 'wd2', 'enAng');
            f.AddGuide('dy2', 12, 'hd2', 'enAng');
            f.AddGuide('x2', 1, 'hc', 'dx2', '0');
            f.AddGuide('y2', 1, 'vc', 'dy2', '0');
            f.AddGuide('stAng1', 5, 'dx1', 'dy1');
            f.AddGuide('enAng1', 5, 'dx2', 'dy2');
            f.AddGuide('swAng1', 1, 'enAng1', '0', 'stAng1');
            f.AddGuide('swAng2', 1, 'swAng1', '21600000', '0');
            f.AddGuide('swAng', 3, 'swAng1', 'swAng1', 'swAng2');
            f.AddGuide('idx', 7, 'wd2', '2700000');
            f.AddGuide('idy', 12, 'hd2', '2700000');
            f.AddGuide('il', 1, 'hc', '0', 'idx');
            f.AddGuide('ir', 1, 'hc', 'idx', '0');
            f.AddGuide('it', 1, 'vc', '0', 'idy');
            f.AddGuide('ib', 1, 'vc', 'idy', '0');
            f.AddHandleXY('adj1','-2147483647','2147483647','adj2','-2147483647','2147483647', 'xPos', 'yPos');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('_3cd4', 'il', 'it');
            f.AddCnx('cd4', 'il', 'ib');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('cd4', 'ir', 'ib');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('_3cd4', 'ir', 'it');
            f.AddCnx('pang', 'xPos', 'yPos');
            f.AddRect('il', 'it', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'xPos', 'yPos');
            f.AddPathCommand(2, 'x1', 'y1');
            f.AddPathCommand(3, 'wd2', 'hd2', 'stAng1', 'swAng');
            f.AddPathCommand(6);
            break;
        }
        case 'wedgeRectCallout':{
            f.AddAdj('adj1', 15, '-20833');
            f.AddAdj('adj2', 15, '62500');
            f.AddGuide('dxPos', 0, 'w', 'adj1', '100000');
            f.AddGuide('dyPos', 0, 'h', 'adj2', '100000');
            f.AddGuide('xPos', 1, 'hc', 'dxPos', '0');
            f.AddGuide('yPos', 1, 'vc', 'dyPos', '0');
            f.AddGuide('dx', 1, 'xPos', '0', 'hc');
            f.AddGuide('dy', 1, 'yPos', '0', 'vc');
            f.AddGuide('dq', 0, 'dxPos', 'h', 'w');
            f.AddGuide('ady', 4, 'dyPos');
            f.AddGuide('adq', 4, 'dq');
            f.AddGuide('dz', 1, 'ady', '0', 'adq');
            f.AddGuide('xg1', 3, 'dxPos', '7', '2');
            f.AddGuide('xg2', 3, 'dxPos', '10', '5');
            f.AddGuide('x1', 0, 'w', 'xg1', '12');
            f.AddGuide('x2', 0, 'w', 'xg2', '12');
            f.AddGuide('yg1', 3, 'dyPos', '7', '2');
            f.AddGuide('yg2', 3, 'dyPos', '10', '5');
            f.AddGuide('y1', 0, 'h', 'yg1', '12');
            f.AddGuide('y2', 0, 'h', 'yg2', '12');
            f.AddGuide('t1', 3, 'dxPos', 'l', 'xPos');
            f.AddGuide('xl', 3, 'dz', 'l', 't1');
            f.AddGuide('t2', 3, 'dyPos', 'x1', 'xPos');
            f.AddGuide('xt', 3, 'dz', 't2', 'x1');
            f.AddGuide('t3', 3, 'dxPos', 'xPos', 'r');
            f.AddGuide('xr', 3, 'dz', 'r', 't3');
            f.AddGuide('t4', 3, 'dyPos', 'xPos', 'x1');
            f.AddGuide('xb', 3, 'dz', 't4', 'x1');
            f.AddGuide('t5', 3, 'dxPos', 'y1', 'yPos');
            f.AddGuide('yl', 3, 'dz', 'y1', 't5');
            f.AddGuide('t6', 3, 'dyPos', 't', 'yPos');
            f.AddGuide('yt', 3, 'dz', 't6', 't');
            f.AddGuide('t7', 3, 'dxPos', 'yPos', 'y1');
            f.AddGuide('yr', 3, 'dz', 'y1', 't7');
            f.AddGuide('t8', 3, 'dyPos', 'yPos', 'b');
            f.AddGuide('yb', 3, 'dz', 't8', 'b');
            f.AddHandleXY('adj1','-2147483647','2147483647','adj2','-2147483647','2147483647', 'xPos', 'yPos');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'xPos', 'yPos');
            f.AddRect('l', 't', 'r', 'b');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'x1', 't');
            f.AddPathCommand(2, 'xt', 'yt');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(2, 'r', 'y1');
            f.AddPathCommand(2, 'xr', 'yr');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(2, 'r', 'b');
            f.AddPathCommand(2, 'x2', 'b');
            f.AddPathCommand(2, 'xb', 'yb');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(2, 'l', 'b');
            f.AddPathCommand(2, 'l', 'y2');
            f.AddPathCommand(2, 'xl', 'yl');
            f.AddPathCommand(2, 'l', 'y1');
            f.AddPathCommand(6);
            break;
        }
        case 'wedgeRoundRectCallout':{
            f.AddAdj('adj1', 15, '-20833');
            f.AddAdj('adj2', 15, '62500');
            f.AddAdj('adj3', 15, '16667');
            f.AddGuide('dxPos', 0, 'w', 'adj1', '100000');
            f.AddGuide('dyPos', 0, 'h', 'adj2', '100000');
            f.AddGuide('xPos', 1, 'hc', 'dxPos', '0');
            f.AddGuide('yPos', 1, 'vc', 'dyPos', '0');
            f.AddGuide('dq', 0, 'dxPos', 'h', 'w');
            f.AddGuide('ady', 4, 'dyPos');
            f.AddGuide('adq', 4, 'dq');
            f.AddGuide('dz', 1, 'ady', '0', 'adq');
            f.AddGuide('xg1', 3, 'dxPos', '7', '2');
            f.AddGuide('xg2', 3, 'dxPos', '10', '5');
            f.AddGuide('x1', 0, 'w', 'xg1', '12');
            f.AddGuide('x2', 0, 'w', 'xg2', '12');
            f.AddGuide('yg1', 3, 'dyPos', '7', '2');
            f.AddGuide('yg2', 3, 'dyPos', '10', '5');
            f.AddGuide('y1', 0, 'h', 'yg1', '12');
            f.AddGuide('y2', 0, 'h', 'yg2', '12');
            f.AddGuide('t1', 3, 'dxPos', 'l', 'xPos');
            f.AddGuide('xl', 3, 'dz', 'l', 't1');
            f.AddGuide('t2', 3, 'dyPos', 'x1', 'xPos');
            f.AddGuide('xt', 3, 'dz', 't2', 'x1');
            f.AddGuide('t3', 3, 'dxPos', 'xPos', 'r');
            f.AddGuide('xr', 3, 'dz', 'r', 't3');
            f.AddGuide('t4', 3, 'dyPos', 'xPos', 'x1');
            f.AddGuide('xb', 3, 'dz', 't4', 'x1');
            f.AddGuide('t5', 3, 'dxPos', 'y1', 'yPos');
            f.AddGuide('yl', 3, 'dz', 'y1', 't5');
            f.AddGuide('t6', 3, 'dyPos', 't', 'yPos');
            f.AddGuide('yt', 3, 'dz', 't6', 't');
            f.AddGuide('t7', 3, 'dxPos', 'yPos', 'y1');
            f.AddGuide('yr', 3, 'dz', 'y1', 't7');
            f.AddGuide('t8', 3, 'dyPos', 'yPos', 'b');
            f.AddGuide('yb', 3, 'dz', 't8', 'b');
            f.AddGuide('u1', 0, 'ss', 'adj3', '100000');
            f.AddGuide('u2', 1, 'r', '0', 'u1');
            f.AddGuide('v2', 1, 'b', '0', 'u1');
            f.AddGuide('il', 0, 'u1', '29289', '100000');
            f.AddGuide('ir', 1, 'r', '0', 'il');
            f.AddGuide('ib', 1, 'b', '0', 'il');
            f.AddHandleXY('adj1','-2147483647','2147483647','adj2','-2147483647','2147483647', 'xPos', 'yPos');
            f.AddCnx('_3cd4', 'hc', 't');
            f.AddCnx('cd2', 'l', 'vc');
            f.AddCnx('cd4', 'hc', 'b');
            f.AddCnx('0', 'r', 'vc');
            f.AddCnx('cd4', 'xPos', 'yPos');
            f.AddRect('il', 'il', 'ir', 'ib');
            f.AddPathCommand(0,undefined, undefined, undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'u1');
            f.AddPathCommand(3, 'u1', 'u1', 'cd2', 'cd4');
            f.AddPathCommand(2, 'x1', 't');
            f.AddPathCommand(2, 'xt', 'yt');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'u2', 't');
            f.AddPathCommand(3, 'u1', 'u1', '_3cd4', 'cd4');
            f.AddPathCommand(2, 'r', 'y1');
            f.AddPathCommand(2, 'xr', 'yr');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(2, 'r', 'v2');
            f.AddPathCommand(3, 'u1', 'u1', '0', 'cd4');
            f.AddPathCommand(2, 'x2', 'b');
            f.AddPathCommand(2, 'xb', 'yb');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(2, 'u1', 'b');
            f.AddPathCommand(3, 'u1', 'u1', 'cd4', 'cd4');
            f.AddPathCommand(2, 'l', 'y2');
            f.AddPathCommand(2, 'xl', 'yl');
            f.AddPathCommand(2, 'l', 'y1');
            f.AddPathCommand(6);
            break;
        }
    }
    if(typeof prst === "string" && prst.length > 0)
    {
        f.setPreset(prst);
    }
    return f;
}

function getPrstByNumber(nPreset)
{
    switch(nPreset)
    {
         case  0:{
            return  "textArchDown";
    }
             case  1:{
                return  "textArchDownPour";
    }
             case  2:{
                return  "textArchUp";
    }
             case  3:{
                return  "textArchUpPour";
    }
             case  4:{
                return  "textButton";
    }
             case  5:{
                return  "textButtonPour";
    }
             case  6:{
                return  "textCanDown";
    }
             case  7:{
                return  "textCanUp";
    }
             case  8:{
                return  "textCascadeDown";
    }
             case  9:{
                return  "textCascadeUp";
    }
             case  10:{
                return  "textChevron";
    }
             case  11:{
                return  "textChevronInverted";
    }
             case  12:{
                return  "textCircle";
    }
             case  13:{
                return  "textCirclePour";
    }
             case  14:{
                return  "textCurveDown";
    }
             case  15:{
                return  "textCurveUp";
    }
             case  16:{
                return  "textDeflate";
    }
             case  17:{
                return  "textDeflateBottom";
    }
             case  18:{
                return  "textDeflateInflate";
    }
             case  19:{
                return  "textDeflateInflateDeflate";
    }
             case  20:{
                return  "textDeflateTop";
    }
             case  21:{
                return  "textDoubleWave1";
    }
             case  22:{
                return  "textFadeDown";
    }
             case  23:{
                return  "textFadeLeft";
    }
             case  24:{
                return  "textFadeRight";
    }
             case  25:{
                return  "textFadeUp";
    }
             case  26:{
                return  "textInflate";
    }
             case  27:{
                return  "textInflateBottom";
    }
             case  28:{
                return  "textInflateTop";
    }
             case  29:{
                return  "textNoShape";
    }
             case  30:{
                return  "textPlain";
    }
             case  31:{
                return  "textRingInside";
    }
             case  32:{
                return  "textRingOutside";
    }
             case  33:{
                return  "textSlantDown";
    }
             case  34:{
                return  "textSlantUp";
    }
             case  35:{
                return  "textStop";
    }
             case  36:{
                return  "textTriangle";
    }
             case  37:{
                return  "textTriangleInverted";
    }
             case  38:{
                return  "textWave1";
    }
             case  39:{
                return  "textWave2";
    }
             case  40:{
                return  "textWave4";
    }
    }
    return  "textNoShape";
}


function getNumByTxPrst(sPreset)
{
    if ("textArchDown" == sPreset) return 0;
    if ("textArchDownPour" == sPreset) return 1;
    if ("textArchUp" == sPreset) return 2;
    if ("textArchUpPour" == sPreset) return 3;
    if ("textButton" == sPreset) return 4;
    if ("textButtonPour" == sPreset) return 5;
    if ("textCanDown" == sPreset) return 6;
    if ("textCanUp" == sPreset) return 7;
    if ("textCascadeDown" == sPreset) return 8;
    if ("textCascadeUp" == sPreset) return 9;
    if ("textChevron" == sPreset) return 10;
    if ("textChevronInverted" == sPreset) return 11;
    if ("textCircle" == sPreset) return 12;
    if ("textCirclePour" == sPreset) return 13;
    if ("textCurveDown" == sPreset) return 14;
    if ("textCurveUp" == sPreset) return 15;
    if ("textDeflate" == sPreset) return 16;
    if ("textDeflateBottom" == sPreset) return 17;
    if ("textDeflateInflate" == sPreset) return 18;
    if ("textDeflateInflateDeflate" == sPreset) return 19;
    if ("textDeflateTop" == sPreset) return 20;
    if ("textDoubleWave1" == sPreset) return 21;
    if ("textFadeDown" == sPreset) return 22;
    if ("textFadeLeft" == sPreset) return 23;
    if ("textFadeRight" == sPreset) return 24;
    if ("textFadeUp" == sPreset) return 25;
    if ("textInflate" == sPreset) return 26;
    if ("textInflateBottom" == sPreset) return 27;
    if ("textInflateTop" == sPreset) return 28;
    if ("textNoShape" == sPreset) return 29;
    if ("textPlain" == sPreset) return 30;
    if ("textRingInside" == sPreset) return 31;
    if ("textRingOutside" == sPreset) return 32;
    if ("textSlantDown" == sPreset) return 33;
    if ("textSlantUp" == sPreset) return 34;
    if ("textStop" == sPreset) return 35;
    if ("textTriangle" == sPreset) return 36;
    if ("textTriangleInverted" == sPreset) return 37;
    if ("textWave1" == sPreset) return 38;
    if ("textWave2" == sPreset) return 39;
    if ("textWave4" == sPreset) return 40;
    return 29;
}

function CreatePrstTxWarpGeometry(prst)
{
    var f = new AscFormat.Geometry();
    switch(prst)
    {
        case 'textArchDown':{
            f.AddAdj('adj', 15, '0');
            f.AddGuide('adval', 10, '0', 'adj', '21599999');
            f.AddGuide('v1', 1, '10800000', '0', 'adval');
            f.AddGuide('v2', 1, '32400000', '0', 'adval');
            f.AddGuide('nv1', 1, '0', '0', 'v1');
            f.AddGuide('stAng', 3, 'nv1', 'v2', 'v1');
            f.AddGuide('w1', 1, '5400000', '0', 'adval');
            f.AddGuide('w2', 1, '16200000', '0', 'adval');
            f.AddGuide('d1', 1, 'adval', '0', 'stAng');
            f.AddGuide('d2', 1, 'd1', '0', '21600000');
            f.AddGuide('v3', 1, '0', '0', '10800000');
            f.AddGuide('c2', 3, 'w2', 'd1', 'd2');
            f.AddGuide('c1', 3, 'v1', 'd2', 'c2');
            f.AddGuide('c0', 3, 'w1', 'd1', 'c1');
            f.AddGuide('swAng', 3, 'stAng', 'c0', 'v3');
            f.AddGuide('wt1', 12, 'wd2', 'adj');
            f.AddGuide('ht1', 7, 'hd2', 'adj');
            f.AddGuide('dx1', 6, 'wd2', 'ht1', 'wt1');
            f.AddGuide('dy1', 11, 'hd2', 'ht1', 'wt1');
            f.AddGuide('x1', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', 'dy1', '0');
            f.AddGuide('wt2', 12, 'wd2', 'stAng');
            f.AddGuide('ht2', 7, 'hd2', 'stAng');
            f.AddGuide('dx2', 6, 'wd2', 'ht2', 'wt2');
            f.AddGuide('dy2', 11, 'hd2', 'ht2', 'wt2');
            f.AddGuide('x2', 1, 'hc', 'dx2', '0');
            f.AddGuide('y2', 1, 'vc', 'dy2', '0');
            f.AddHandlePolar('adj', '0', '21599999', undefined, '0', '0', 'x1', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x2', 'y2');
            f.AddPathCommand(3, 'wd2', 'hd2', 'stAng', 'swAng');
            break;
        }
        case 'textArchDownPour':{
            f.AddAdj('adj1', 15, '0');
            f.AddAdj('adj2', 15, '25000');
            f.AddGuide('adval', 10, '0', 'adj1', '21599999');
            f.AddGuide('v1', 1, '10800000', '0', 'adval');
            f.AddGuide('v2', 1, '32400000', '0', 'adval');
            f.AddGuide('nv1', 1, '0', '0', 'v1');
            f.AddGuide('stAng', 3, 'nv1', 'v2', 'v1');
            f.AddGuide('w1', 1, '5400000', '0', 'adval');
            f.AddGuide('w2', 1, '16200000', '0', 'adval');
            f.AddGuide('d1', 1, 'adval', '0', 'stAng');
            f.AddGuide('d2', 1, 'd1', '0', '21600000');
            f.AddGuide('v3', 1, '0', '0', '10800000');
            f.AddGuide('c2', 3, 'w2', 'd1', 'd2');
            f.AddGuide('c1', 3, 'v1', 'd2', 'c2');
            f.AddGuide('c0', 3, 'w1', 'd1', 'c1');
            f.AddGuide('swAng', 3, 'stAng', 'c0', 'v3');
            f.AddGuide('wt1', 12, 'wd2', 'stAng');
            f.AddGuide('ht1', 7, 'hd2', 'stAng');
            f.AddGuide('dx1', 6, 'wd2', 'ht1', 'wt1');
            f.AddGuide('dy1', 11, 'hd2', 'ht1', 'wt1');
            f.AddGuide('x1', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', 'dy1', '0');
            f.AddGuide('adval2', 10, '0', 'adj2', '99000');
            f.AddGuide('ratio', 0, 'adval2', '1', '100000');
            f.AddGuide('iwd2', 0, 'wd2', 'ratio', '1');
            f.AddGuide('ihd2', 0, 'hd2', 'ratio', '1');
            f.AddGuide('wt2', 12, 'iwd2', 'adval');
            f.AddGuide('ht2', 7, 'ihd2', 'adval');
            f.AddGuide('dx2', 6, 'iwd2', 'ht2', 'wt2');
            f.AddGuide('dy2', 11, 'ihd2', 'ht2', 'wt2');
            f.AddGuide('x2', 1, 'hc', 'dx2', '0');
            f.AddGuide('y2', 1, 'vc', 'dy2', '0');
            f.AddGuide('wt3', 12, 'iwd2', 'stAng');
            f.AddGuide('ht3', 7, 'ihd2', 'stAng');
            f.AddGuide('dx3', 6, 'iwd2', 'ht3', 'wt3');
            f.AddGuide('dy3', 11, 'ihd2', 'ht3', 'wt3');
            f.AddGuide('x3', 1, 'hc', 'dx3', '0');
            f.AddGuide('y3', 1, 'vc', 'dy3', '0');
            f.AddHandlePolar('adj1', '0', '21599999', 'adj2', '0', '100000', 'x2', 'y2');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x3', 'y3');
            f.AddPathCommand(3, 'iwd2', 'ihd2', 'stAng', 'swAng');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(3, 'wd2', 'hd2', 'stAng', 'swAng');
            break;
        }
        case 'textArchUp':{
            f.AddAdj('adj', 15, 'cd2');
            f.AddGuide('adval', 10, '0', 'adj', '21599999');
            f.AddGuide('v1', 1, '10800000', '0', 'adval');
            f.AddGuide('v2', 1, '32400000', '0', 'adval');
            f.AddGuide('end', 3, 'v1', 'v1', 'v2');
            f.AddGuide('w1', 1, '5400000', '0', 'adval');
            f.AddGuide('w2', 1, '16200000', '0', 'adval');
            f.AddGuide('d1', 1, 'end', '0', 'adval');
            f.AddGuide('d2', 1, '21600000', 'd1', '0');
            f.AddGuide('c2', 3, 'w2', 'd1', 'd2');
            f.AddGuide('c1', 3, 'v1', 'd2', 'c2');
            f.AddGuide('swAng', 3, 'w1', 'd1', 'c1');
            f.AddGuide('wt1', 12, 'wd2', 'adj');
            f.AddGuide('ht1', 7, 'hd2', 'adj');
            f.AddGuide('dx1', 6, 'wd2', 'ht1', 'wt1');
            f.AddGuide('dy1', 11, 'hd2', 'ht1', 'wt1');
            f.AddGuide('x1', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', 'dy1', '0');
            f.AddHandlePolar('adj', '0', '21599999', undefined, '0', '0', 'x1', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(3, 'wd2', 'hd2', 'adval', 'swAng');
            break;
        }
        case 'textArchUpPour':{
            f.AddAdj('adj1', 15, 'cd2');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('adval', 10, '0', 'adj1', '21599999');
            f.AddGuide('v1', 1, '10800000', '0', 'adval');
            f.AddGuide('v2', 1, '32400000', '0', 'adval');
            f.AddGuide('end', 3, 'v1', 'v1', 'v2');
            f.AddGuide('w1', 1, '5400000', '0', 'adval');
            f.AddGuide('w2', 1, '16200000', '0', 'adval');
            f.AddGuide('d1', 1, 'end', '0', 'adval');
            f.AddGuide('d2', 1, '21600000', 'd1', '0');
            f.AddGuide('c2', 3, 'w2', 'd1', 'd2');
            f.AddGuide('c1', 3, 'v1', 'd2', 'c2');
            f.AddGuide('swAng', 3, 'w1', 'd1', 'c1');
            f.AddGuide('wt1', 12, 'wd2', 'adval');
            f.AddGuide('ht1', 7, 'hd2', 'adval');
            f.AddGuide('dx1', 6, 'wd2', 'ht1', 'wt1');
            f.AddGuide('dy1', 11, 'hd2', 'ht1', 'wt1');
            f.AddGuide('x1', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', 'dy1', '0');
            f.AddGuide('adval2', 10, '0', 'adj2', '99000');
            f.AddGuide('ratio', 0, 'adval2', '1', '100000');
            f.AddGuide('iwd2', 0, 'wd2', 'ratio', '1');
            f.AddGuide('ihd2', 0, 'hd2', 'ratio', '1');
            f.AddGuide('wt2', 12, 'iwd2', 'adval');
            f.AddGuide('ht2', 7, 'ihd2', 'adval');
            f.AddGuide('dx2', 6, 'iwd2', 'ht2', 'wt2');
            f.AddGuide('dy2', 11, 'ihd2', 'ht2', 'wt2');
            f.AddGuide('x2', 1, 'hc', 'dx2', '0');
            f.AddGuide('y2', 1, 'vc', 'dy2', '0');
            f.AddHandlePolar('adj1', '0', '21599999', 'adj2', '0', '100000', 'x2', 'y2');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(3, 'wd2', 'hd2', 'adval', 'swAng');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x2', 'y2');
            f.AddPathCommand(3, 'iwd2', 'ihd2', 'adval', 'swAng');
            break;
        }
        case 'textButton':{
            f.AddAdj('adj', 15, '10800000');
            f.AddGuide('adval', 10, '0', 'adj', '21599999');
            f.AddGuide('bot', 1, '5400000', '0', 'adval');
            f.AddGuide('lef', 1, '10800000', '0', 'adval');
            f.AddGuide('top', 1, '16200000', '0', 'adval');
            f.AddGuide('rig', 1, '21600000', '0', 'adval');
            f.AddGuide('c3', 3, 'top', 'adval', '0');
            f.AddGuide('c2', 3, 'lef', '10800000', 'c3');
            f.AddGuide('c1', 3, 'bot', 'rig', 'c2');
            f.AddGuide('stAng', 3, 'adval', 'c1', '0');
            f.AddGuide('w1', 1, '21600000', '0', 'stAng');
            f.AddGuide('stAngB', 3, 'stAng', 'w1', '0');
            f.AddGuide('td1', 0, 'bot', '2', '1');
            f.AddGuide('td2', 0, 'top', '2', '1');
            f.AddGuide('ntd2', 1, '0', '0', 'td2');
            f.AddGuide('w2', 1, '0', '0', '10800000');
            f.AddGuide('c6', 3, 'top', 'ntd2', 'w2');
            f.AddGuide('c5', 3, 'lef', '10800000', 'c6');
            f.AddGuide('c4', 3, 'bot', 'td1', 'c5');
            f.AddGuide('v1', 3, 'adval', 'c4', '10800000');
            f.AddGuide('swAngT', 1, '0', '0', 'v1');
            f.AddGuide('stT', 3, 'lef', 'stAngB', 'stAng');
            f.AddGuide('stB', 3, 'lef', 'stAng', 'stAngB');
            f.AddGuide('swT', 3, 'lef', 'v1', 'swAngT');
            f.AddGuide('swB', 3, 'lef', 'swAngT', 'v1');
            f.AddGuide('wt1', 12, 'wd2', 'stT');
            f.AddGuide('ht1', 7, 'hd2', 'stT');
            f.AddGuide('dx1', 6, 'wd2', 'ht1', 'wt1');
            f.AddGuide('dy1', 11, 'hd2', 'ht1', 'wt1');
            f.AddGuide('x1', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', 'dy1', '0');
            f.AddGuide('wt2', 12, 'wd2', 'stB');
            f.AddGuide('ht2', 7, 'hd2', 'stB');
            f.AddGuide('dx2', 6, 'wd2', 'ht2', 'wt2');
            f.AddGuide('dy2', 11, 'hd2', 'ht2', 'wt2');
            f.AddGuide('x2', 1, 'hc', 'dx2', '0');
            f.AddGuide('y2', 1, 'vc', 'dy2', '0');
            f.AddGuide('wt3', 12, 'wd2', 'adj');
            f.AddGuide('ht3', 7, 'hd2', 'adj');
            f.AddGuide('dx3', 6, 'wd2', 'ht3', 'wt3');
            f.AddGuide('dy3', 11, 'hd2', 'ht3', 'wt3');
            f.AddGuide('x3', 1, 'hc', 'dx3', '0');
            f.AddGuide('y3', 1, 'vc', 'dy3', '0');
            f.AddHandlePolar('adj', '0', '21599999', undefined, '0', '0', 'x3', 'y3');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(3, 'wd2', 'hd2', 'stT', 'swT');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'vc');
            f.AddPathCommand(2, 'r', 'vc');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x2', 'y2');
            f.AddPathCommand(3, 'wd2', 'hd2', 'stB', 'swB');
            break;
        }
        case 'textButtonPour':{
            f.AddAdj('adj1', 15, 'cd2');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('adval', 10, '0', 'adj1', '21599999');
            f.AddGuide('bot', 1, '5400000', '0', 'adval');
            f.AddGuide('lef', 1, '10800000', '0', 'adval');
            f.AddGuide('top', 1, '16200000', '0', 'adval');
            f.AddGuide('rig', 1, '21600000', '0', 'adval');
            f.AddGuide('c3', 3, 'top', 'adval', '0');
            f.AddGuide('c2', 3, 'lef', '10800000', 'c3');
            f.AddGuide('c1', 3, 'bot', 'rig', 'c2');
            f.AddGuide('stAng', 3, 'adval', 'c1', '0');
            f.AddGuide('w1', 1, '21600000', '0', 'stAng');
            f.AddGuide('stAngB', 3, 'stAng', 'w1', '0');
            f.AddGuide('td1', 0, 'bot', '2', '1');
            f.AddGuide('td2', 0, 'top', '2', '1');
            f.AddGuide('ntd2', 1, '0', '0', 'td2');
            f.AddGuide('w2', 1, '0', '0', '10800000');
            f.AddGuide('c6', 3, 'top', 'ntd2', 'w2');
            f.AddGuide('c5', 3, 'lef', '10800000', 'c6');
            f.AddGuide('c4', 3, 'bot', 'td1', 'c5');
            f.AddGuide('v1', 3, 'adval', 'c4', '10800000');
            f.AddGuide('swAngT', 1, '0', '0', 'v1');
            f.AddGuide('stT', 3, 'lef', 'stAngB', 'stAng');
            f.AddGuide('stB', 3, 'lef', 'stAng', 'stAngB');
            f.AddGuide('swT', 3, 'lef', 'v1', 'swAngT');
            f.AddGuide('swB', 3, 'lef', 'swAngT', 'v1');
            f.AddGuide('wt1', 12, 'wd2', 'stT');
            f.AddGuide('ht1', 7, 'hd2', 'stT');
            f.AddGuide('dx1', 6, 'wd2', 'ht1', 'wt1');
            f.AddGuide('dy1', 11, 'hd2', 'ht1', 'wt1');
            f.AddGuide('x1', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', 'dy1', '0');
            f.AddGuide('wt6', 12, 'wd2', 'stB');
            f.AddGuide('ht6', 7, 'hd2', 'stB');
            f.AddGuide('dx6', 6, 'wd2', 'ht6', 'wt6');
            f.AddGuide('dy6', 11, 'hd2', 'ht6', 'wt6');
            f.AddGuide('x6', 1, 'hc', 'dx6', '0');
            f.AddGuide('y6', 1, 'vc', 'dy6', '0');
            f.AddGuide('adval2', 10, '40000', 'adj2', '99000');
            f.AddGuide('ratio', 0, 'adval2', '1', '100000');
            f.AddGuide('iwd2', 0, 'wd2', 'ratio', '1');
            f.AddGuide('ihd2', 0, 'hd2', 'ratio', '1');
            f.AddGuide('wt2', 12, 'iwd2', 'stT');
            f.AddGuide('ht2', 7, 'ihd2', 'stT');
            f.AddGuide('dx2', 6, 'iwd2', 'ht2', 'wt2');
            f.AddGuide('dy2', 11, 'ihd2', 'ht2', 'wt2');
            f.AddGuide('x2', 1, 'hc', 'dx2', '0');
            f.AddGuide('y2', 1, 'vc', 'dy2', '0');
            f.AddGuide('wt5', 12, 'iwd2', 'stB');
            f.AddGuide('ht5', 7, 'ihd2', 'stB');
            f.AddGuide('dx5', 6, 'iwd2', 'ht5', 'wt5');
            f.AddGuide('dy5', 11, 'ihd2', 'ht5', 'wt5');
            f.AddGuide('x5', 1, 'hc', 'dx5', '0');
            f.AddGuide('y5', 1, 'vc', 'dy5', '0');
            f.AddGuide('d1', 1, 'hd2', '0', 'ihd2');
            f.AddGuide('d12', 0, 'd1', '1', '2');
            f.AddGuide('yu', 1, 'vc', '0', 'd12');
            f.AddGuide('yd', 1, 'vc', 'd12', '0');
            f.AddGuide('v1', 0, 'd12', 'd12', '1');
            f.AddGuide('v2', 0, 'ihd2', 'ihd2', '1');
            f.AddGuide('v3', 0, 'v1', '1', 'v2');
            f.AddGuide('v4', 1, '1', '0', 'v3');
            f.AddGuide('v5', 0, 'iwd2', 'iwd2', '1');
            f.AddGuide('v6', 0, 'v4', 'v5', '1');
            f.AddGuide('v7', 13, 'v6');
            f.AddGuide('xl', 1, 'hc', '0', 'v7');
            f.AddGuide('xr', 1, 'hc', 'v7', '0');
            f.AddGuide('wtadj', 12, 'iwd2', 'adj1');
            f.AddGuide('htadj', 7, 'ihd2', 'adj1');
            f.AddGuide('dxadj', 6, 'iwd2', 'htadj', 'wtadj');
            f.AddGuide('dyadj', 11, 'ihd2', 'htadj', 'wtadj');
            f.AddGuide('xadj', 1, 'hc', 'dxadj', '0');
            f.AddGuide('yadj', 1, 'vc', 'dyadj', '0');
            f.AddHandlePolar('adj1', '0', '21599999', 'adj2', '0', '100000', 'xadj', 'yadj');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(3, 'wd2', 'hd2', 'stT', 'swT');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x2', 'y2');
            f.AddPathCommand(3, 'iwd2', 'ihd2', 'stT', 'swT');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'xl', 'yu');
            f.AddPathCommand(2, 'xr', 'yu');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'xl', 'yd');
            f.AddPathCommand(2, 'xr', 'yd');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x5', 'y5');
            f.AddPathCommand(3, 'iwd2', 'ihd2', 'stB', 'swB');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x6', 'y6');
            f.AddPathCommand(3, 'wd2', 'hd2', 'stB', 'swB');
            break;
        }
        case 'textCanDown':{
            f.AddAdj('adj', 15, '14286');
            f.AddGuide('a', 10, '0', 'adj', '33333');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('y0', 1, 't', 'dy', '0');
            f.AddGuide('y1', 1, 'b', '0', 'dy');
            f.AddGuide('ncd2', 0, 'cd2', '-1', '1');
            f.AddHandleXY(undefined, '0', '0', 'adj', '0', '33333', 'hc', 'y0');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(3, 'wd2', 'y0', 'cd2', 'ncd2');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(3, 'wd2', 'y0', 'cd2', 'ncd2');
            break;
        }
        case 'textCanUp':{
            f.AddAdj('adj', 15, '85714');
            f.AddGuide('a', 10, '66667', 'adj', '100000');
            f.AddGuide('dy1', 0, 'a', 'h', '100000');
            f.AddGuide('dy', 1, 'h', '0', 'dy1');
            f.AddGuide('y0', 1, 't', 'dy1', '0');
            f.AddGuide('y1', 1, 't', 'dy', '0');
            f.AddHandleXY(undefined, '0', '0', 'adj', '66667', '100000', 'hc', 'y0');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(3, 'wd2', 'y1', 'cd2', 'cd2');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(3, 'wd2', 'y1', 'cd2', 'cd2');
            break;
        }
        case 'textCascadeDown':{
            f.AddAdj('adj', 15, '44444');
            f.AddGuide('a', 10, '28570', 'adj', '100000');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('y1', 1, 't', 'dy', '0');
            f.AddGuide('dy2', 1, 'h', '0', 'dy');
            f.AddGuide('dy3', 0, 'dy2', '1', '4');
            f.AddGuide('y2', 1, 't', 'dy3', '0');
            f.AddHandleXY(undefined, '0', '0', 'adj', '28570', '100000', 'l', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(2, 'r', 'b');
            break;
        }
        case 'textCascadeUp':{
            f.AddAdj('adj', 15, '44444');
            f.AddGuide('a', 10, '28570', 'adj', '100000');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('y1', 1, 't', 'dy', '0');
            f.AddGuide('dy2', 1, 'h', '0', 'dy');
            f.AddGuide('dy3', 0, 'dy2', '1', '4');
            f.AddGuide('y2', 1, 't', 'dy3', '0');
            f.AddHandleXY(undefined, '0', '0', 'adj', '28570', '100000', 'r', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y2');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'r', 'y1');
            break;
        }
        case 'textChevron':{
            f.AddAdj('adj', 15, '25000');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('y', 0, 'a', 'h', '100000');
            f.AddGuide('y1', 1, 't', 'b', 'y');
            f.AddHandleXY(undefined, '0', '0', 'adj', '0', '50000', 'l', 'y');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'r', 'y');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'hc', 'y1');
            f.AddPathCommand(2, 'r', 'b');
            break;
        }
        case 'textChevronInverted':{
            f.AddAdj('adj', 15, '75000');
            f.AddGuide('a', 10, '50000', 'adj', '100000');
            f.AddGuide('y', 0, 'a', 'h', '100000');
            f.AddGuide('y1', 1, 'b', '0', 'y');
            f.AddHandleXY(undefined, '0', '0', 'adj', '50000', '100000', 'l', 'y');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'hc', 'y1');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(2, 'r', 'y');
            break;
        }
        case 'textCircle':{
            f.AddAdj('adj', 15, '10800000');
            f.AddGuide('adval', 10, '0', 'adj', '21599999');
            f.AddGuide('d0', 1, 'adval', '0', '10800000');
            f.AddGuide('d1', 1, '10800000', '0', 'adval');
            f.AddGuide('d2', 1, '21600000', '0', 'adval');
            f.AddGuide('d3', 3, 'd1', 'd1', '10799999');
            f.AddGuide('d4', 3, 'd0', 'd2', 'd3');
            f.AddGuide('swAng', 0, 'd4', '2', '1');
            f.AddGuide('wt1', 12, 'wd2', 'adj');
            f.AddGuide('ht1', 7, 'hd2', 'adj');
            f.AddGuide('dx1', 6, 'wd2', 'ht1', 'wt1');
            f.AddGuide('dy1', 11, 'hd2', 'ht1', 'wt1');
            f.AddGuide('x1', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', 'dy1', '0');
            f.AddHandlePolar('adj', '0', '21599999', undefined, '0', '0', 'x1', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(3, 'wd2', 'hd2', 'adval', 'swAng');
            break;
        }
        case 'textCirclePour':{
            f.AddAdj('adj1', 15, 'cd2');
            f.AddAdj('adj2', 15, '50000');
            f.AddGuide('adval', 10, '0', 'adj1', '21599999');
            f.AddGuide('d0', 1, 'adval', '0', '10800000');
            f.AddGuide('d1', 1, '10800000', '0', 'adval');
            f.AddGuide('d2', 1, '21600000', '0', 'adval');
            f.AddGuide('d3', 3, 'd1', 'd1', '10799999');
            f.AddGuide('d4', 3, 'd0', 'd2', 'd3');
            f.AddGuide('swAng', 0, 'd4', '2', '1');
            f.AddGuide('wt1', 12, 'wd2', 'adval');
            f.AddGuide('ht1', 7, 'hd2', 'adval');
            f.AddGuide('dx1', 6, 'wd2', 'ht1', 'wt1');
            f.AddGuide('dy1', 11, 'hd2', 'ht1', 'wt1');
            f.AddGuide('x1', 1, 'hc', 'dx1', '0');
            f.AddGuide('y1', 1, 'vc', 'dy1', '0');
            f.AddGuide('adval2', 10, '0', 'adj2', '99000');
            f.AddGuide('ratio', 0, 'adval2', '1', '100000');
            f.AddGuide('iwd2', 0, 'wd2', 'ratio', '1');
            f.AddGuide('ihd2', 0, 'hd2', 'ratio', '1');
            f.AddGuide('wt2', 12, 'iwd2', 'adval');
            f.AddGuide('ht2', 7, 'ihd2', 'adval');
            f.AddGuide('dx2', 6, 'iwd2', 'ht2', 'wt2');
            f.AddGuide('dy2', 11, 'ihd2', 'ht2', 'wt2');
            f.AddGuide('x2', 1, 'hc', 'dx2', '0');
            f.AddGuide('y2', 1, 'vc', 'dy2', '0');
            f.AddHandlePolar('adj1', '0', '21599999', 'adj2', '0', '100000', 'x2', 'y2');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'y1');
            f.AddPathCommand(3, 'wd2', 'hd2', 'adval', 'swAng');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x2', 'y2');
            f.AddPathCommand(3, 'iwd2', 'ihd2', 'adval', 'swAng');
            break;
        }
        case 'textCurveDown':{
            f.AddAdj('adj', 15, '45977');
            f.AddGuide('a', 10, '0', 'adj', '56338');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('gd1', 0, 'dy', '3', '4');
            f.AddGuide('gd2', 0, 'dy', '5', '4');
            f.AddGuide('gd3', 0, 'dy', '3', '8');
            f.AddGuide('gd4', 0, 'dy', '1', '8');
            f.AddGuide('gd5', 1, 'h', '0', 'gd3');
            f.AddGuide('gd6', 1, 'gd4', 'h', '0');
            f.AddGuide('y0', 1, 't', 'dy', '0');
            f.AddGuide('y1', 1, 't', 'gd1', '0');
            f.AddGuide('y2', 1, 't', 'gd2', '0');
            f.AddGuide('y3', 1, 't', 'gd3', '0');
            f.AddGuide('y4', 1, 't', 'gd4', '0');
            f.AddGuide('y5', 1, 't', 'gd5', '0');
            f.AddGuide('y6', 1, 't', 'gd6', '0');
            f.AddGuide('x1', 1, 'l', 'wd3', '0');
            f.AddGuide('x2', 1, 'r', '0', 'wd3');
            f.AddHandleXY(undefined, '0', '0', 'adj', '0', '56338', 'r', 'y0');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(5, 'x1', 'y1', 'x2', 'y2', 'r', 'y0');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y5');
            f.AddPathCommand(5, 'x1', 'y6', 'x2', 'y6', 'r', 'y5');
            break;
        }
        case 'textCurveUp':{
            f.AddAdj('adj', 15, '45977');
            f.AddGuide('a', 10, '0', 'adj', '56338');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('gd1', 0, 'dy', '3', '4');
            f.AddGuide('gd2', 0, 'dy', '5', '4');
            f.AddGuide('gd3', 0, 'dy', '3', '8');
            f.AddGuide('gd4', 0, 'dy', '1', '8');
            f.AddGuide('gd5', 1, 'h', '0', 'gd3');
            f.AddGuide('gd6', 1, 'gd4', 'h', '0');
            f.AddGuide('y0', 1, 't', 'dy', '0');
            f.AddGuide('y1', 1, 't', 'gd1', '0');
            f.AddGuide('y2', 1, 't', 'gd2', '0');
            f.AddGuide('y3', 1, 't', 'gd3', '0');
            f.AddGuide('y4', 1, 't', 'gd4', '0');
            f.AddGuide('y5', 1, 't', 'gd5', '0');
            f.AddGuide('y6', 1, 't', 'gd6', '0');
            f.AddGuide('x1', 1, 'l', 'wd3', '0');
            f.AddGuide('x2', 1, 'r', '0', 'wd3');
            f.AddHandleXY(undefined, '0', '0', 'adj', '0', '56338', 'l', 'y0');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y0');
            f.AddPathCommand(5, 'x1', 'y2', 'x2', 'y1', 'r', 't');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y5');
            f.AddPathCommand(5, 'x1', 'y6', 'x2', 'y6', 'r', 'y5');
            break;
        }
        case 'textDeflate':{
            f.AddAdj('adj', 15, '18750');
            f.AddGuide('a', 10, '0', 'adj', '37500');
            f.AddGuide('dy', 0, 'a', 'ss', '100000');
            f.AddGuide('gd0', 0, 'dy', '4', '3');
            f.AddGuide('gd1', 1, 'h', '0', 'gd0');
            f.AddGuide('adjY', 1, 't', 'dy', '0');
            f.AddGuide('y0', 1, 't', 'gd0', '0');
            f.AddGuide('y1', 1, 't', 'gd1', '0');
            f.AddGuide('x0', 1, 'l', 'wd3', '0');
            f.AddGuide('x1', 1, 'r', '0', 'wd3');
            f.AddHandleXY(undefined, '0', '0', 'adj', '0', '37500', 'hc', 'adjY');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(5, 'x0', 'y0', 'x1', 'y0', 'r', 't');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(5, 'x0', 'y1', 'x1', 'y1', 'r', 'b');
            break;
        }
        case 'textDeflateBottom':{
            f.AddAdj('adj', 15, '50000');
            f.AddGuide('a', 10, '6250', 'adj', '100000');
            f.AddGuide('dy', 0, 'a', 'ss', '100000');
            f.AddGuide('dy2', 1, 'h', '0', 'dy');
            f.AddGuide('y1', 1, 't', 'dy', '0');
            f.AddGuide('cp', 1, 'y1', '0', 'dy2');
            f.AddHandleXY(undefined, '0', '0', 'adj', '6250', '100000', 'hc', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(4, 'hc', 'cp', 'r', 'b');
            break;
        }
        case 'textDeflateInflate':{
            f.AddAdj('adj', 15, '35000');
            f.AddGuide('a', 10, '5000', 'adj', '95000');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('del', 0, 'h', '5', '100');
            f.AddGuide('dh1', 0, 'h', '45', '100');
            f.AddGuide('dh2', 0, 'h', '55', '100');
            f.AddGuide('yh', 1, 'dy', '0', 'del');
            f.AddGuide('yl', 1, 'dy', 'del', '0');
            f.AddGuide('y3', 1, 'yh', 'yh', 'dh1');
            f.AddGuide('y4', 1, 'yl', 'yl', 'dh2');
            f.AddHandleXY(undefined, '0', '0', 'adj', '5000', '95000', 'hc', 'dy');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'dh1');
            f.AddPathCommand(4, 'hc', 'y3', 'r', 'dh1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'dh2');
            f.AddPathCommand(4, 'hc', 'y4', 'r', 'dh2');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'r', 'b');
            break;
        }
        case 'textDeflateInflateDeflate':{
            f.AddAdj('adj', 15, '25000');
            f.AddGuide('a', 10, '3000', 'adj', '47000');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('del', 0, 'h', '3', '100');
            f.AddGuide('ey1', 0, 'h', '30', '100');
            f.AddGuide('ey2', 0, 'h', '36', '100');
            f.AddGuide('ey3', 0, 'h', '63', '100');
            f.AddGuide('ey4', 0, 'h', '70', '100');
            f.AddGuide('by', 1, 'b', '0', 'dy');
            f.AddGuide('yh1', 1, 'dy', '0', 'del');
            f.AddGuide('yl1', 1, 'dy', 'del', '0');
            f.AddGuide('yh2', 1, 'by', '0', 'del');
            f.AddGuide('yl2', 1, 'by', 'del', '0');
            f.AddGuide('y1', 1, 'yh1', 'yh1', 'ey1');
            f.AddGuide('y2', 1, 'yl1', 'yl1', 'ey2');
            f.AddGuide('y3', 1, 'yh2', 'yh2', 'ey3');
            f.AddGuide('y4', 1, 'yl2', 'yl2', 'ey4');
            f.AddHandleXY(undefined, '0', '0', 'adj', '3000', '47000', 'hc', 'dy');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'ey1');
            f.AddPathCommand(4, 'hc', 'y1', 'r', 'ey1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'ey2');
            f.AddPathCommand(4, 'hc', 'y2', 'r', 'ey2');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'ey3');
            f.AddPathCommand(4, 'hc', 'y3', 'r', 'ey3');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'ey4');
            f.AddPathCommand(4, 'hc', 'y4', 'r', 'ey4');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'r', 'b');
            break;
        }
        case 'textDeflateTop':{
            f.AddAdj('adj', 15, '50000');
            f.AddGuide('a', 10, '0', 'adj', '93750');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('y1', 1, 't', 'dy', '0');
            f.AddGuide('cp', 1, 'y1', 'dy', '0');
            f.AddHandleXY(undefined, '0', '0', 'adj', '0', '93750', 'hc', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(4, 'hc', 'cp', 'r', 't');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'r', 'b');
            break;
        }
        case 'textDoubleWave1':{
            f.AddAdj('adj1', 15, '6250');
            f.AddAdj('adj2', 15, '0');
            f.AddGuide('a1', 10, '0', 'adj1', '12500');
            f.AddGuide('a2', 10, '-10000', 'adj2', '10000');
            f.AddGuide('y1', 0, 'h', 'a1', '100000');
            f.AddGuide('dy2', 0, 'y1', '10', '3');
            f.AddGuide('y2', 1, 'y1', '0', 'dy2');
            f.AddGuide('y3', 1, 'y1', 'dy2', '0');
            f.AddGuide('y4', 1, 'b', '0', 'y1');
            f.AddGuide('y5', 1, 'y4', '0', 'dy2');
            f.AddGuide('y6', 1, 'y4', 'dy2', '0');
            f.AddGuide('of', 0, 'w', 'a2', '100000');
            f.AddGuide('of2', 0, 'w', 'a2', '50000');
            f.AddGuide('x1', 4, 'of');
            f.AddGuide('dx2', 3, 'of2', '0', 'of2');
            f.AddGuide('x2', 1, 'l', '0', 'dx2');
            f.AddGuide('dx8', 3, 'of2', 'of2', '0');
            f.AddGuide('x8', 1, 'r', '0', 'dx8');
            f.AddGuide('dx3', 2, 'dx2', 'x8', '6');
            f.AddGuide('x3', 1, 'x2', 'dx3', '0');
            f.AddGuide('dx4', 2, 'dx2', 'x8', '3');
            f.AddGuide('x4', 1, 'x2', 'dx4', '0');
            f.AddGuide('x5', 2, 'x2', 'x8', '2');
            f.AddGuide('x6', 1, 'x5', 'dx3', '0');
            f.AddGuide('x7', 2, 'x6', 'x8', '2');
            f.AddGuide('x9', 1, 'l', 'dx8', '0');
            f.AddGuide('x15', 1, 'r', 'dx2', '0');
            f.AddGuide('x10', 1, 'x9', 'dx3', '0');
            f.AddGuide('x11', 1, 'x9', 'dx4', '0');
            f.AddGuide('x12', 2, 'x9', 'x15', '2');
            f.AddGuide('x13', 1, 'x12', 'dx3', '0');
            f.AddGuide('x14', 2, 'x13', 'x15', '2');
            f.AddGuide('x16', 1, 'r', '0', 'x1');
            f.AddGuide('xAdj', 1, 'hc', 'of', '0');
            f.AddHandleXY(undefined, '0', '0', 'adj1', '0', '12500', 'l', 'y1');
            f.AddHandleXY('adj2', '-10000', '10000', undefined, '0', '0', 'xAdj', 'b');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x2', 'y1');
            f.AddPathCommand(5, 'x3', 'y2', 'x4', 'y3', 'x5', 'y1');
            f.AddPathCommand(5, 'x6', 'y2', 'x7', 'y3', 'x8', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x9', 'y4');
            f.AddPathCommand(5, 'x10', 'y5', 'x11', 'y6', 'x12', 'y4');
            f.AddPathCommand(5, 'x13', 'y5', 'x14', 'y6', 'x15', 'y4');
            break;
        }
        case 'textFadeDown':{
            f.AddAdj('adj', 15, '33333');
            f.AddGuide('a', 10, '0', 'adj', '49999');
            f.AddGuide('dx', 0, 'a', 'w', '100000');
            f.AddGuide('x1', 1, 'l', 'dx', '0');
            f.AddGuide('x2', 1, 'r', '0', 'dx');
            f.AddHandleXY('adj', '0', '49999', undefined, '0', '0', 'x1', 'b');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 'b');
            f.AddPathCommand(2, 'x2', 'b');
            break;
        }
        case 'textFadeLeft':{
            f.AddAdj('adj', 15, '33333');
            f.AddGuide('a', 10, '0', 'adj', '49999');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('y1', 1, 't', 'dy', '0');
            f.AddGuide('y2', 1, 'b', '0', 'dy');
            f.AddHandleXY(undefined, '0', '0', 'adj', '0', '49999', 'l', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y2');
            f.AddPathCommand(2, 'r', 'b');
            break;
        }
        case 'textFadeRight':{
            f.AddAdj('adj', 15, '33333');
            f.AddGuide('a', 10, '0', 'adj', '49999');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('y1', 1, 't', 'dy', '0');
            f.AddGuide('y2', 1, 'b', '0', 'dy');
            f.AddHandleXY(undefined, '0', '0', 'adj', '0', '49999', 'r', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'r', 'y2');
            break;
        }
        case 'textFadeUp':{
            f.AddAdj('adj', 15, '33333');
            f.AddGuide('a', 10, '0', 'adj', '49999');
            f.AddGuide('dx', 0, 'a', 'w', '100000');
            f.AddGuide('x1', 1, 'l', 'dx', '0');
            f.AddGuide('x2', 1, 'r', '0', 'dx');
            f.AddHandleXY('adj', '0', '49999', undefined, '0', '0', 'x1', 't');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x1', 't');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'r', 'b');
            break;
        }
        case 'textInflate':{
            f.AddAdj('adj', 15, '18750');
            f.AddGuide('a', 10, '0', 'adj', '20000');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('gd', 0, 'dy', '1', '3');
            f.AddGuide('gd0', 1, '0', '0', 'gd');
            f.AddGuide('gd1', 1, 'h', '0', 'gd0');
            f.AddGuide('ty', 1, 't', 'dy', '0');
            f.AddGuide('by', 1, 'b', '0', 'dy');
            f.AddGuide('y0', 1, 't', 'gd0', '0');
            f.AddGuide('y1', 1, 't', 'gd1', '0');
            f.AddGuide('x0', 1, 'l', 'wd3', '0');
            f.AddGuide('x1', 1, 'r', '0', 'wd3');
            f.AddHandleXY(undefined, '0', '0', 'adj', '0', '20000', 'l', 'ty');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'ty');
            f.AddPathCommand(5, 'x0', 'y0', 'x1', 'y0', 'r', 'ty');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'by');
            f.AddPathCommand(5, 'x0', 'y1', 'x1', 'y1', 'r', 'by');
            break;
        }
        case 'textInflateBottom':{
            f.AddAdj('adj', 15, '60000');
            f.AddGuide('a', 10, '60000', 'adj', '100000');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('ty', 1, 't', 'dy', '0');
            f.AddHandleXY(undefined, '0', '0', 'adj', '60000', '100000', 'l', 'ty');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'ty');
            f.AddPathCommand(4, 'hc', 'b', 'r', 'ty');
            break;
        }
        case 'textInflateTop':{
            f.AddAdj('adj', 15, '40000');
            f.AddGuide('a', 10, '0', 'adj', '50000');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('ty', 1, 't', 'dy', '0');
            f.AddHandleXY(undefined, '0', '0', 'adj', '0', '50000', 'l', 'ty');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'ty');
            f.AddPathCommand(4, 'hc', 't', 'r', 'ty');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'r', 'b');
            break;
        }
        case 'textPlain':{
            f.AddAdj('adj', 15, '50000');
            f.AddGuide('a', 10, '30000', 'adj', '70000');
            f.AddGuide('mid', 0, 'a', 'w', '100000');
            f.AddGuide('midDir', 1, 'mid', '0', 'hc');
            f.AddGuide('dl', 1, 'mid', '0', 'l');
            f.AddGuide('dr', 1, 'r', '0', 'mid');
            f.AddGuide('dl2', 0, 'dl', '2', '1');
            f.AddGuide('dr2', 0, 'dr', '2', '1');
            f.AddGuide('dx', 3, 'midDir', 'dr2', 'dl2');
            f.AddGuide('xr', 1, 'l', 'dx', '0');
            f.AddGuide('xl', 1, 'r', '0', 'dx');
            f.AddGuide('tlx', 3, 'midDir', 'l', 'xl');
            f.AddGuide('trx', 3, 'midDir', 'xr', 'r');
            f.AddGuide('blx', 3, 'midDir', 'xl', 'l');
            f.AddGuide('brx', 3, 'midDir', 'r', 'xr');
            f.AddHandleXY('adj', '30000', '70000', undefined, '0', '0', 'mid', 'b');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'tlx', 't');
            f.AddPathCommand(2, 'trx', 't');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'blx', 'b');
            f.AddPathCommand(2, 'brx', 'b');
            break;
        }
        case 'textRingInside':{
            f.AddAdj('adj', 15, '60000');
            f.AddGuide('a', 10, '50000', 'adj', '99000');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('y', 1, 't', 'dy', '0');
            f.AddGuide('r', 0, 'dy', '1', '2');
            f.AddGuide('y1', 1, 't', 'r', '0');
            f.AddGuide('y2', 1, 'b', '0', 'r');
            f.AddHandleXY(undefined, '0', '0', 'adj', '50000', '99000', 'hc', 'y');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(3, 'wd2', 'y1', '10800000', '21599999');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y2');
            f.AddPathCommand(3, 'wd2', 'r', '10800000', '21599999');
            break;
        }
        case 'textRingOutside':{
            f.AddAdj('adj', 15, '60000');
            f.AddGuide('a', 10, '50000', 'adj', '99000');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('y', 1, 't', 'dy', '0');
            f.AddGuide('r', 0, 'dy', '1', '2');
            f.AddGuide('y1', 1, 't', 'r', '0');
            f.AddGuide('y2', 1, 'b', '0', 'r');
            f.AddHandleXY(undefined, '0', '0', 'adj', '50000', '99000', 'hc', 'y');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(3, 'wd2', 'y1', '10800000', '-21599999');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y2');
            f.AddPathCommand(3, 'wd2', 'r', '10800000', '-21599999');
            break;
        }
        case 'textSlantDown':{
            f.AddAdj('adj', 15, '44445');
            f.AddGuide('a', 10, '28569', 'adj', '100000');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('y1', 1, 't', 'dy', '0');
            f.AddGuide('y2', 1, 'b', '0', 'dy');
            f.AddHandleXY(undefined, '0', '0', 'adj', '28569', '100000', 'l', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 'y2');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(2, 'r', 'b');
            break;
        }
        case 'textSlantUp':{
            f.AddAdj('adj', 15, '55555');
            f.AddGuide('a', 10, '0', 'adj', '71431');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('y1', 1, 't', 'dy', '0');
            f.AddGuide('y2', 1, 'b', '0', 'dy');
            f.AddHandleXY(undefined, '0', '0', 'adj', '0', '71431', 'l', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'r', 'y2');
            break;
        }
        case 'textStop':{
            f.AddAdj('adj', 15, '25000');
            f.AddGuide('a', 10, '14286', 'adj', '50000');
            f.AddGuide('dx', 0, 'w', '1', '3');
            f.AddGuide('dy', 0, 'a', 'h', '100000');
            f.AddGuide('x1', 1, 'l', 'dx', '0');
            f.AddGuide('x2', 1, 'r', '0', 'dx');
            f.AddGuide('y1', 1, 't', 'dy', '0');
            f.AddGuide('y2', 1, 'b', '0', 'dy');
            f.AddHandleXY(undefined, '0', '0', 'adj', '14286', '50000', 'l', 'dy');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y1');
            f.AddPathCommand(2, 'x1', 't');
            f.AddPathCommand(2, 'x2', 't');
            f.AddPathCommand(2, 'r', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y2');
            f.AddPathCommand(2, 'x1', 'b');
            f.AddPathCommand(2, 'x2', 'b');
            f.AddPathCommand(2, 'r', 'y2');
            break;
        }
        case 'textTriangle':{
            f.AddAdj('adj', 15, '50000');
            f.AddGuide('a', 10, '0', 'adj', '100000');
            f.AddGuide('y', 0, 'a', 'h', '100000');
            f.AddHandleXY(undefined, '0', '0', 'adj', '0', '100000', 'l', 'y');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y');
            f.AddPathCommand(2, 'hc', 't');
            f.AddPathCommand(2, 'r', 'y');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'b');
            f.AddPathCommand(2, 'r', 'b');
            break;
        }
        case 'textTriangleInverted':{
            f.AddAdj('adj', 15, '50000');
            f.AddGuide('a', 10, '0', 'adj', '100000');
            f.AddGuide('y', 0, 'a', 'h', '100000');
            f.AddHandleXY(undefined, '0', '0', 'adj', '0', '100000', 'l', 'y');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 't');
            f.AddPathCommand(2, 'r', 't');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'l', 'y');
            f.AddPathCommand(2, 'hc', 'b');
            f.AddPathCommand(2, 'r', 'y');
            break;
        }
        case 'textWave1':{
            f.AddAdj('adj1', 15, '12500');
            f.AddAdj('adj2', 15, '0');
            f.AddGuide('a1', 10, '0', 'adj1', '20000');
            f.AddGuide('a2', 10, '-10000', 'adj2', '10000');
            f.AddGuide('y1', 0, 'h', 'a1', '100000');
            f.AddGuide('dy2', 0, 'y1', '10', '3');
            f.AddGuide('y2', 1, 'y1', '0', 'dy2');
            f.AddGuide('y3', 1, 'y1', 'dy2', '0');
            f.AddGuide('y4', 1, 'b', '0', 'y1');
            f.AddGuide('y5', 1, 'y4', '0', 'dy2');
            f.AddGuide('y6', 1, 'y4', 'dy2', '0');
            f.AddGuide('of', 0, 'w', 'a2', '100000');
            f.AddGuide('of2', 0, 'w', 'a2', '50000');
            f.AddGuide('x1', 4, 'of');
            f.AddGuide('dx2', 3, 'of2', '0', 'of2');
            f.AddGuide('x2', 1, 'l', '0', 'dx2');
            f.AddGuide('dx5', 3, 'of2', 'of2', '0');
            f.AddGuide('x5', 1, 'r', '0', 'dx5');
            f.AddGuide('dx3', 2, 'dx2', 'x5', '3');
            f.AddGuide('x3', 1, 'x2', 'dx3', '0');
            f.AddGuide('x4', 2, 'x3', 'x5', '2');
            f.AddGuide('x6', 1, 'l', 'dx5', '0');
            f.AddGuide('x10', 1, 'r', 'dx2', '0');
            f.AddGuide('x7', 1, 'x6', 'dx3', '0');
            f.AddGuide('x8', 2, 'x7', 'x10', '2');
            f.AddGuide('x9', 1, 'r', '0', 'x1');
            f.AddGuide('xAdj', 1, 'hc', 'of', '0');
            f.AddHandleXY(undefined, '0', '0', 'adj1', '0', '20000', 'l', 'y1');
            f.AddHandleXY('adj2', '-10000', '10000', undefined, '0', '0', 'xAdj', 'b');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x2', 'y1');
            f.AddPathCommand(5, 'x3', 'y2', 'x4', 'y3', 'x5', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x6', 'y4');
            f.AddPathCommand(5, 'x7', 'y5', 'x8', 'y6', 'x10', 'y4');
            break;
        }
        case 'textWave2':{
            f.AddAdj('adj1', 15, '12500');
            f.AddAdj('adj2', 15, '0');
            f.AddGuide('a1', 10, '0', 'adj1', '20000');
            f.AddGuide('a2', 10, '-10000', 'adj2', '10000');
            f.AddGuide('y1', 0, 'h', 'a1', '100000');
            f.AddGuide('dy2', 0, 'y1', '10', '3');
            f.AddGuide('y2', 1, 'y1', '0', 'dy2');
            f.AddGuide('y3', 1, 'y1', 'dy2', '0');
            f.AddGuide('y4', 1, 'b', '0', 'y1');
            f.AddGuide('y5', 1, 'y4', '0', 'dy2');
            f.AddGuide('y6', 1, 'y4', 'dy2', '0');
            f.AddGuide('of', 0, 'w', 'a2', '100000');
            f.AddGuide('of2', 0, 'w', 'a2', '50000');
            f.AddGuide('x1', 4, 'of');
            f.AddGuide('dx2', 3, 'of2', '0', 'of2');
            f.AddGuide('x2', 1, 'l', '0', 'dx2');
            f.AddGuide('dx5', 3, 'of2', 'of2', '0');
            f.AddGuide('x5', 1, 'r', '0', 'dx5');
            f.AddGuide('dx3', 2, 'dx2', 'x5', '3');
            f.AddGuide('x3', 1, 'x2', 'dx3', '0');
            f.AddGuide('x4', 2, 'x3', 'x5', '2');
            f.AddGuide('x6', 1, 'l', 'dx5', '0');
            f.AddGuide('x10', 1, 'r', 'dx2', '0');
            f.AddGuide('x7', 1, 'x6', 'dx3', '0');
            f.AddGuide('x8', 2, 'x7', 'x10', '2');
            f.AddGuide('x9', 1, 'r', '0', 'x1');
            f.AddGuide('xAdj', 1, 'hc', 'of', '0');
            f.AddHandleXY(undefined, '0', '0', 'adj1', '0', '20000', 'l', 'y1');
            f.AddHandleXY('adj2', '-10000', '10000', undefined, '0', '0', 'xAdj', 'b');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x2', 'y1');
            f.AddPathCommand(5, 'x3', 'y3', 'x4', 'y2', 'x5', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x6', 'y4');
            f.AddPathCommand(5, 'x7', 'y6', 'x8', 'y5', 'x10', 'y4');
            break;
        }
        case 'textWave4':{
            f.AddAdj('adj1', 15, '6250');
            f.AddAdj('adj2', 15, '0');
            f.AddGuide('a1', 10, '0', 'adj1', '12500');
            f.AddGuide('a2', 10, '-10000', 'adj2', '10000');
            f.AddGuide('y1', 0, 'h', 'a1', '100000');
            f.AddGuide('dy2', 0, 'y1', '10', '3');
            f.AddGuide('y2', 1, 'y1', '0', 'dy2');
            f.AddGuide('y3', 1, 'y1', 'dy2', '0');
            f.AddGuide('y4', 1, 'b', '0', 'y1');
            f.AddGuide('y5', 1, 'y4', '0', 'dy2');
            f.AddGuide('y6', 1, 'y4', 'dy2', '0');
            f.AddGuide('of', 0, 'w', 'a2', '100000');
            f.AddGuide('of2', 0, 'w', 'a2', '50000');
            f.AddGuide('x1', 4, 'of');
            f.AddGuide('dx2', 3, 'of2', '0', 'of2');
            f.AddGuide('x2', 1, 'l', '0', 'dx2');
            f.AddGuide('dx8', 3, 'of2', 'of2', '0');
            f.AddGuide('x8', 1, 'r', '0', 'dx8');
            f.AddGuide('dx3', 2, 'dx2', 'x8', '6');
            f.AddGuide('x3', 1, 'x2', 'dx3', '0');
            f.AddGuide('dx4', 2, 'dx2', 'x8', '3');
            f.AddGuide('x4', 1, 'x2', 'dx4', '0');
            f.AddGuide('x5', 2, 'x2', 'x8', '2');
            f.AddGuide('x6', 1, 'x5', 'dx3', '0');
            f.AddGuide('x7', 2, 'x6', 'x8', '2');
            f.AddGuide('x9', 1, 'l', 'dx8', '0');
            f.AddGuide('x15', 1, 'r', 'dx2', '0');
            f.AddGuide('x10', 1, 'x9', 'dx3', '0');
            f.AddGuide('x11', 1, 'x9', 'dx4', '0');
            f.AddGuide('x12', 2, 'x9', 'x15', '2');
            f.AddGuide('x13', 1, 'x12', 'dx3', '0');
            f.AddGuide('x14', 2, 'x13', 'x15', '2');
            f.AddGuide('x16', 1, 'r', '0', 'x1');
            f.AddGuide('xAdj', 1, 'hc', 'of', '0');
            f.AddHandleXY(undefined, '0', '0', 'adj1', '0', '12500', 'l', 'y1');
            f.AddHandleXY('adj2', '-10000', '10000', undefined, '0', '0', 'xAdj', 'b');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x2', 'y1');
            f.AddPathCommand(5, 'x3', 'y3', 'x4', 'y2', 'x5', 'y1');
            f.AddPathCommand(5, 'x6', 'y3', 'x7', 'y2', 'x8', 'y1');
            f.AddPathCommand(0, false, 'none', undefined, undefined, undefined);
            f.AddPathCommand(1, 'x9', 'y4');
            f.AddPathCommand(5, 'x10', 'y6', 'x11', 'y5', 'x12', 'y4');
            f.AddPathCommand(5, 'x13', 'y6', 'x14', 'y5', 'x15', 'y4');
            break;
        }
    }
    if(typeof prst === "string" && prst.length > 0)
    {
        f.setPreset(prst);
    }
    return f;
}

    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].CreateGeometry = CreateGeometry;
    window['AscFormat'].getPrstByNumber = getPrstByNumber;
    window['AscFormat'].getNumByTxPrst = getNumByTxPrst;
    window['AscFormat'].CreatePrstTxWarpGeometry = CreatePrstTxWarpGeometry;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {
    // Import
    var ArcToCurvers = AscFormat.ArcToCurvers;

    var History = AscCommon.History;


var EPSILON_TEXT_AUTOFIT = 0.001;
var FORMULA_TYPE_MULT_DIV = 0,
    FORMULA_TYPE_PLUS_MINUS = 1,
    FORMULA_TYPE_PLUS_DIV = 2,
    FORMULA_TYPE_IF_ELSE =3,
    FORMULA_TYPE_ABS = 4,
    FORMULA_TYPE_AT2 = 5,
    FORMULA_TYPE_CAT2 = 6,
    FORMULA_TYPE_COS = 7,
    FORMULA_TYPE_MAX = 8,
    FORMULA_TYPE_MOD = 9,
    FORMULA_TYPE_PIN = 10,
    FORMULA_TYPE_SAT2 = 11,
    FORMULA_TYPE_SIN = 12,
    FORMULA_TYPE_SQRT = 13,
    FORMULA_TYPE_TAN = 14,
    FORMULA_TYPE_VALUE = 15,
    FORMULA_TYPE_MIN = 16;


var cToRad = Math.PI/(60000*180);
var cToDeg = 1/cToRad;
var MAX_ITER_COUNT = 50;

var oGdLst = {};
oGdLst["_3cd4"]= 16200000;
oGdLst["_3cd8"]= 8100000;
oGdLst["_5cd8"]= 13500000;
oGdLst["_7cd8"]= 18900000;
oGdLst["cd2"]= 10800000;
oGdLst["cd4"]= 5400000;
oGdLst["cd8"]= 2700000;
oGdLst["l"]= 0;
oGdLst["t"]= 0;

function Cos(angle)
{
    return Math.cos(cToRad*angle);
}

function Sin(angle)
{
    return Math.sin(cToRad*angle);
}

function Tan(angle)
{
    return Math.tan(cToRad*angle);
}

function ATan(x)
{
    return cToDeg*Math.atan(x);
}

function ATan2(y, x)
{
    return  cToDeg*Math.atan2(y, x);
}

function CAt2(x, y, z)
{
    return  x*(Math.cos(Math.atan2(z, y)));
}

function SAt2(x, y, z)
{
    return  x*(Math.sin(Math.atan2(z, y)));
}

function CalculateGuideValue(name, formula, x, y, z, gdLst)
{
    var xt, yt, zt;

    xt=gdLst[x];  //TODO : возможно, что gdLst[x] еще не расчитан
    if(xt===undefined)
        xt=parseInt(x,10);

    yt=gdLst[y];
    if(yt===undefined)
        yt=parseInt(y,10);

    zt=gdLst[z];
    if(zt===undefined)
        zt=parseInt(z,10);

    switch(formula)
    {
        case FORMULA_TYPE_MULT_DIV:
        {
            gdLst[name]=xt*yt/zt;
            break;
        }
        case FORMULA_TYPE_PLUS_MINUS:
        {
            gdLst[name] = xt+yt-zt;
            break;
        }
        case FORMULA_TYPE_PLUS_DIV:
        {
            gdLst[name] = (xt+yt)/zt;
            break;
        }
        case FORMULA_TYPE_IF_ELSE:
        {
            if(xt>0)
                gdLst[name] = yt;
            else
                gdLst[name] = zt;
            break;
        }

        case FORMULA_TYPE_ABS:
        {
            gdLst[name] = Math.abs(xt);
            break;
        }
        case FORMULA_TYPE_AT2:
        {
            gdLst[name] = ATan2(yt, xt);
            break;
        }
        case FORMULA_TYPE_CAT2:
        {
            gdLst[name] = CAt2(xt,yt,zt);
            break;
        }

        case FORMULA_TYPE_COS:
        {
            gdLst[name] = xt*Cos(yt);
            break;
        }

        case FORMULA_TYPE_MAX:
        {
            gdLst[name] = Math.max(xt, yt);
            break;
        }

        case FORMULA_TYPE_MOD:
        {
            gdLst[name] = Math.sqrt(xt*xt+yt*yt+zt*zt);
            break;
        }

        case FORMULA_TYPE_PIN:
        {
            if (yt < xt)
                gdLst[name] = xt;
            else if (yt > zt)
                gdLst[name] = zt;
            else
                gdLst[name] = yt;
            break;
        }
        case FORMULA_TYPE_SAT2:
        {
            gdLst[name] = SAt2(xt,yt,zt);
            break;
        }
        case FORMULA_TYPE_SIN:
        {
            gdLst[name] = xt*Sin(yt);
            break;
        }
        case FORMULA_TYPE_SQRT:
        {
            gdLst[name] = Math.sqrt(xt);
            break;
        }

        case FORMULA_TYPE_TAN:
        {
            gdLst[name] = xt*Tan(yt);
            break;
        }
        case FORMULA_TYPE_VALUE:
        {
            gdLst[name] = xt;
            break;
        }
        case FORMULA_TYPE_MIN:
        {
            gdLst[name] = Math.min(xt, yt);
        }

    }
}

function CalculateGuideLst(gdLstInfo, gdLst)
{
    var info;
    for(var i=0, n=gdLstInfo.length; i<n;i++)
    {
        info=gdLstInfo[i];
        CalculateGuideValue(info.name, info.formula, info.x, info.y, info.z, gdLst);
    }
}

function CalculateCnxLst(cnxLstInfo, cnxLst, gdLst)
{
    var x_, y_, ang_;
    for(var i=0, n=cnxLstInfo.length; i<n;i++)
    {
        ang_=parseInt(cnxLstInfo[i].ang);
        if(isNaN(ang_))
            ang_=gdLst[cnxLstInfo[i].ang];


        x_=gdLst[cnxLstInfo[i].x];
        if(x_===undefined)
            x_=parseInt(cnxLstInfo[i].x);


        y_=gdLst[cnxLstInfo[i].y];
        if(y_===undefined)
            y_=parseInt(cnxLstInfo[i].y);

        if(cnxLst[i]==undefined)
            cnxLst[i]={};

        cnxLst[i].ang=ang_;
        cnxLst[i].x=x_;
        cnxLst[i].y=y_;
    }
}

function CalculateAhXYList(ahXYListInfo, ahXYLst, gdLst)
{
    var  minX, maxX, minY, maxY, posX, posY;
    for(var i=0, n=ahXYListInfo.length; i<n;i++)
    {

        minX=parseInt(ahXYListInfo[i].minX);
        if(isNaN(minX))
            minX=gdLst[ahXYListInfo[i].minX];

        maxX=parseInt(ahXYListInfo[i].maxX);
        if(isNaN(maxX))
            maxX=gdLst[ahXYListInfo[i].maxX];


        minY=parseInt(ahXYListInfo[i].minY);
        if(isNaN(minY))
            minY=gdLst[ahXYListInfo[i].minY];

        maxY=parseInt(ahXYListInfo[i].maxY);
        if(isNaN(maxY))
            maxY=gdLst[ahXYListInfo[i].maxY];


        posX=parseInt(ahXYListInfo[i].posX);
        if(isNaN(posX))
        {
            posX=gdLst[ahXYListInfo[i].posX];
        }

        posY=parseInt(ahXYListInfo[i].posY);
        if(isNaN(posY))
        {
            posY=gdLst[ahXYListInfo[i].posY];
        }


        if(ahXYLst[i]==undefined)
            ahXYLst[i]={};

        ahXYLst[i].gdRefX=ahXYListInfo[i].gdRefX;
        ahXYLst[i].minX= minX;
        ahXYLst[i].maxX= maxX;

        ahXYLst[i].gdRefY=ahXYListInfo[i].gdRefY;
        ahXYLst[i].minY= minY;
        ahXYLst[i].maxY= maxY;

        ahXYLst[i].posX= posX;
        ahXYLst[i].posY= posY;

    }
}

function CalculateAhPolarList(ahPolarListInfo, ahPolarLst, gdLst)
{
    var  minR, maxR, minAng, maxAng, posX, posY;
    for(var i=0, n=ahPolarListInfo.length; i<n;i++)
    {

        minR=parseInt(ahPolarListInfo[i].minR);
        if(isNaN(minR))
            minR=gdLst[ahPolarListInfo[i].minR];

        maxR=parseInt(ahPolarListInfo[i].maxR);
        if(isNaN(maxR))
            maxR=gdLst[ahPolarListInfo[i].maxR];


        minAng=parseInt(ahPolarListInfo[i].minAng);
        if(isNaN(minAng))
            minAng=gdLst[ahPolarListInfo[i].minAng];

        maxAng=parseInt(ahPolarListInfo[i].maxAng);
        if(isNaN(maxAng))
            maxAng=gdLst[ahPolarListInfo[i].maxAng];


        posX=parseInt(ahPolarListInfo[i].posX);
        if(isNaN(posX))
        {
            posX=gdLst[ahPolarListInfo[i].posX]
        }

        posY=parseInt(ahPolarListInfo[i].posY);
        if(isNaN(posY))
        {
            posY=gdLst[ahPolarListInfo[i].posY];
        }


        if(ahPolarLst[i]==undefined)
        {
            ahPolarLst[i]={};
        }
        ahPolarLst[i].gdRefR=ahPolarListInfo[i].gdRefR;
        ahPolarLst[i].minR = minR;
        ahPolarLst[i].maxR = maxR;

        ahPolarLst[i].gdRefAng = ahPolarListInfo[i].gdRefAng;
        ahPolarLst[i].minAng = minAng;
        ahPolarLst[i].maxAng = maxAng;

        ahPolarLst[i].posX=posX;
        ahPolarLst[i].posY=posY;

    }
}

function CChangesGeometryAddAdj(Class, Name, OldValue, NewValue, OldAvValue, bReverse){
    this.Type = AscDFH.historyitem_GeometryAddAdj;
    this.Name = Name;
    this.OldValue = OldValue;
    this.NewValue = NewValue;
    this.OldAvValue = OldAvValue;
    this.bReverse = bReverse;
	AscDFH.CChangesBase.call(this, Class);
}

	CChangesGeometryAddAdj.prototype = Object.create(AscDFH.CChangesBase.prototype);
	CChangesGeometryAddAdj.prototype.constructor = CChangesGeometryAddAdj;

    CChangesGeometryAddAdj.prototype.CreateReverseChange = function(){
        return new CChangesGeometryAddAdj(this.Class, this.Name, this.OldValue, this.NewValue, this.OldAvValue, !this.bReverse)
    };

    CChangesGeometryAddAdj.prototype.AddAdj = function(){

        this.Class.gdLst[this.Name] = parseInt(this.NewValue);
        this.Class.avLst[this.Name] = true;
        if(this.Class.parent && this.Class.parent.handleUpdateGeometry)
        {
            this.Class.parent.handleUpdateGeometry();
        }
    };

    CChangesGeometryAddAdj.prototype.RemoveAdj = function(){
        var _OldValue = parseInt(this.OldValue);
        if(!isNaN(_OldValue)){
            this.Class.gdLst[this.Name] = _OldValue;
            if(this.Class.parent && this.Class.parent.handleUpdateGeometry)
            {
                this.Class.parent.handleUpdateGeometry();
            }
        }
        else{
            delete this.Class.gdLst[this.Name];
        }

        this.Class.avLst[this.Name] = this.OldAvValue;
    };

    CChangesGeometryAddAdj.prototype.Undo = function(){
        if(this.bReverse){
            this.AddAdj();
        }
        else{
            this.RemoveAdj();
        }
    };
    CChangesGeometryAddAdj.prototype.Redo = function(){
        if(this.bReverse){
            this.RemoveAdj();
        }
        else{
            this.AddAdj();
        }
    };
    CChangesGeometryAddAdj.prototype.WriteToBinary = function(Writer){
        Writer.WriteString2(this.Name);
        Writer.WriteString2(this.NewValue);
        AscFormat.writeString(Writer, this.OldValue);
        AscFormat.writeBool(Writer, this.OldAvValue);
        Writer.WriteBool(!!this.bReverse);
    };
    CChangesGeometryAddAdj.prototype.ReadFromBinary = function(Reader){
        this.Name = Reader.GetString2();
        this.NewValue = Reader.GetString2();
        this.OldValue = AscFormat.readString(Reader);
        this.OldAvValue = AscFormat.readBool(Reader);
        this.bReverse = Reader.GetBool();
    };
    AscDFH.changesFactory[AscDFH.historyitem_GeometryAddAdj] = CChangesGeometryAddAdj;


    function CChangesGeometryAddGuide(Class, Name, formula, x, y, z, bReverse){
        this.Type = AscDFH.historyitem_GeometryAddGuide;
        this.Name = Name;
        this.formula = formula;
        this.x = x;
        this.y = y;
        this.z = z;
        this.bReverse = bReverse;
		AscDFH.CChangesBase.call(this, Class);
    }

	CChangesGeometryAddGuide.prototype = Object.create(AscDFH.CChangesBase.prototype);
	CChangesGeometryAddGuide.prototype.constructor = CChangesGeometryAddGuide;

    CChangesGeometryAddGuide.prototype.RemoveGuide = function(){
        var aGdLstInfo = this.Class.gdLstInfo;
        for(var i = aGdLstInfo.length - 1; i > -1 ; --i){
            var oCurGd = aGdLstInfo[i];
            if(oCurGd.name == this.Name && oCurGd.formula == this.formula
                && oCurGd.x == this.x && oCurGd.y == this.y && oCurGd.z == this.z){
                aGdLstInfo.splice(i, 1);
            }
        }
    };

    CChangesGeometryAddGuide.prototype.AddGuide = function(){
        this.Class.gdLstInfo.push({name: this.Name, formula: this.formula, x: this.x, y: this.y, z: this.z});
    };

    CChangesGeometryAddGuide.prototype.Undo = function(){
        if(this.bReverse){
            this.AddGuide();
        }
        else{
            this.RemoveGuide();
        }
    };
    CChangesGeometryAddGuide.prototype.Redo = function(){
        if(this.bReverse){
            this.RemoveGuide();
        }
        else{
            this.AddGuide();
        }
    };
    CChangesGeometryAddGuide.prototype.WriteToBinary = function(Writer){
        Writer.WriteString2(this.Name);
        Writer.WriteLong(this.formula);
        AscFormat.writeString(Writer, this.x);
        AscFormat.writeString(Writer, this.y);
        AscFormat.writeString(Writer, this.z);
        Writer.WriteBool(!!this.bReverse);
    };
    CChangesGeometryAddGuide.prototype.ReadFromBinary = function(Reader){
        this.Name = Reader.GetString2();
        this.formula = Reader.GetLong();
        this.x = AscFormat.readString(Reader);
        this.y = AscFormat.readString(Reader);
        this.z = AscFormat.readString(Reader);
        this.bReverse = Reader.GetBool();
    };


    CChangesGeometryAddGuide.prototype.CreateReverseChange = function(){
        return new CChangesGeometryAddGuide(this.Class, this.Name, this.formula, this.x, this.y, this.z, !this.bReverse);
    };

    AscDFH.changesFactory[AscDFH.historyitem_GeometryAddGuide] = CChangesGeometryAddGuide;

    function CChangesGeometryAddCnx(Class, ang, x, y, bReverse){
        this.Type = AscDFH.historyitem_GeometryAddCnx;
        this.ang = ang;
        this.x = x;
        this.y = y;
        this.bReverse = bReverse;
		AscDFH.CChangesBase.call(this, Class);
    }

	CChangesGeometryAddCnx.prototype = Object.create(AscDFH.CChangesBase.prototype);
	CChangesGeometryAddCnx.prototype.constructor = CChangesGeometryAddCnx;


    CChangesGeometryAddCnx.prototype.RemoveCnx = function(){
        var aCnxLstInfo = this.Class.cnxLstInfo;
        for(var i = aCnxLstInfo.length - 1; i > -1 ; --i){
            var oCurCnx = aCnxLstInfo[i];
            if(oCurCnx.ang == this.ang && oCurCnx.x == this.x && oCurCnx.y == this.y){
                aCnxLstInfo.splice(i, 1);
            }
        }
    };
    CChangesGeometryAddCnx.prototype.AddCnx = function(){
        this.Class.cnxLstInfo.push({ang: this.ang, x: this.x, y: this.y});
    };

    CChangesGeometryAddCnx.prototype.Undo = function(){
        if(this.bReverse){
            this.AddCnx();
        }
        else{
            this.RemoveCnx();
        }
    };
    CChangesGeometryAddCnx.prototype.Redo = function(){
        if(this.bReverse){
            this.RemoveCnx();
        }
        else{
            this.AddCnx();
        }
    };
    CChangesGeometryAddCnx.prototype.WriteToBinary = function(Writer){
        AscFormat.writeString(Writer, this.ang);
        AscFormat.writeString(Writer, this.x);
        AscFormat.writeString(Writer, this.y);
        Writer.WriteBool(!!this.bReverse);
    };
    CChangesGeometryAddCnx.prototype.ReadFromBinary = function(Reader){
        this.ang = AscFormat.readString(Reader);
        this.x = AscFormat.readString(Reader);
        this.y = AscFormat.readString(Reader);
        this.bReverse = Reader.GetBool();
    };

    CChangesGeometryAddCnx.prototype.CreateReverseChange = function(){
        return new CChangesGeometryAddCnx(this.Class, this.ang, this.x, this.y, !this.bReverse);
    };
    AscDFH.changesFactory[AscDFH.historyitem_GeometryAddCnx] = CChangesGeometryAddCnx;


    function CChangesGeometryAddHandleXY(Class, gdRefX, minX, maxX, gdRefY, minY, maxY, posX, posY, bReverse){
        this.Type = AscDFH.historyitem_GeometryAddHandleXY;
        this.gdRefX = gdRefX;
        this.minX = minX;
        this.maxX = maxX;
        this.gdRefY = gdRefY;
        this.minY = minY;
        this.maxY = maxY;
        this.posX = posX;
        this.posY = posY;
        this.bReverse = bReverse;
		AscDFH.CChangesBase.call(this, Class);
    }

	CChangesGeometryAddHandleXY.prototype = Object.create(AscDFH.CChangesBase.prototype);
	CChangesGeometryAddHandleXY.prototype.constructor = CChangesGeometryAddHandleXY;

    CChangesGeometryAddHandleXY.prototype.RemoveHandleXY = function(){
        var ahXYLstInfo = this.Class.ahXYLstInfo;
        for(var i = ahXYLstInfo.length - 1; i > -1 ; --i){
            var oCurXY = ahXYLstInfo[i];
            if(oCurXY.gdRefX == this.gdRefX && oCurXY.minX == this.minX && oCurXY.maxX == this.maxX &&
                oCurXY.gdRefY == this.gdRefY && oCurXY.minY == this.minY && oCurXY.maxY == this.maxY &&
                oCurXY.posX == this.posX && oCurXY.posY == this.posY){
                ahXYLstInfo.splice(i, 1);
            }
        }
    };
    CChangesGeometryAddHandleXY.prototype.AddHandleXY = function(){
        this.Class.ahXYLstInfo.push({gdRefX: this.gdRefX, minX: this.minX, maxX: this.maxX, gdRefY: this.gdRefY, minY: this.minY, maxY: this.maxY, posX: this.posX,posY: this.posY});
    };

    CChangesGeometryAddHandleXY.prototype.Undo = function(){
        if(this.bReverse){
            this.AddHandleXY();
        }
        else{
            this.RemoveHandleXY();
        }
    };
    CChangesGeometryAddHandleXY.prototype.Redo = function(){
        if(this.bReverse){
            this.RemoveHandleXY();
        }
        else{
            this.AddHandleXY();
        }
    };
    CChangesGeometryAddHandleXY.prototype.WriteToBinary = function(Writer){
        AscFormat.writeString(Writer, this.gdRefX);
        AscFormat.writeString(Writer, this.minX);
        AscFormat.writeString(Writer, this.maxX);
        AscFormat.writeString(Writer, this.gdRefY);
        AscFormat.writeString(Writer, this.minY);
        AscFormat.writeString(Writer, this.maxY);
        AscFormat.writeString(Writer, this.posX);
        AscFormat.writeString(Writer, this.posY);
        Writer.WriteBool(!!this.bReverse);
    };
    CChangesGeometryAddHandleXY.prototype.ReadFromBinary = function(Reader){
        this.gdRefX = AscFormat.readString(Reader);
        this.minX = AscFormat.readString(Reader);
        this.maxX = AscFormat.readString(Reader);
        this.gdRefY = AscFormat.readString(Reader);
        this.minY = AscFormat.readString(Reader);
        this.maxY = AscFormat.readString(Reader);
        this.posX = AscFormat.readString(Reader);
        this.posY = AscFormat.readString(Reader);
        this.bReverse = Reader.GetBool();
    };

    CChangesGeometryAddHandleXY.prototype.CreateReverseChange = function(){
        return new CChangesGeometryAddHandleXY(this.Class, this.gdRefX, this.minX, this.maxX, this.gdRefY, this.minY, this.maxY, this.posX, this.posY, !this.bReverse);
    };
    AscDFH.changesFactory[AscDFH.historyitem_GeometryAddHandleXY] = CChangesGeometryAddHandleXY;

    function CChangesGeometryAddHandlePolar(Class, gdRefR, minR, maxR, gdRefAng, minAng, maxAng, posX, posY, bReverse){
        this.Type = AscDFH.historyitem_GeometryAddHandlePolar;
        this.gdRefAng = gdRefAng;
        this.minAng = minAng;
        this.maxAng = maxAng;
        this.gdRefR = gdRefR;
        this.minR = minR;
        this.maxR = maxR;
        this.posX = posX;
        this.posY = posY;
        this.bReverse = bReverse;
		AscDFH.CChangesBase.call(this, Class);
    }

	CChangesGeometryAddHandlePolar.prototype = Object.create(AscDFH.CChangesBase.prototype);
	CChangesGeometryAddHandlePolar.prototype.constructor = CChangesGeometryAddHandlePolar;

    CChangesGeometryAddHandlePolar.prototype.RemoveHandlePolar = function(){
        var ahPolarLstInfo = this.Class.ahPolarLstInfo;
        for(var i = ahPolarLstInfo.length - 1; i > -1 ; --i){
            var oCurPolar= ahPolarLstInfo[i];
            if(oCurPolar.gdRefR == this.gdRefR && oCurPolar.minR == this.minR && oCurPolar.maxR == this.maxR &&
                oCurPolar.gdRefAng == this.gdRefAng && oCurPolar.minAng == this.minAng && oCurPolar.maxAng == this.maxAng &&
                oCurPolar.posX == this.posX && oCurPolar.posY == this.posY){
                ahPolarLstInfo.splice(i, 1);
            }
        }
    };

    CChangesGeometryAddHandlePolar.prototype.AddHandlePolar = function(){
        this.Class.ahPolarLstInfo.push({gdRefR: this.gdRefR, minR: this.minR, maxR: this.maxR, gdRefAng: this.gdRefAng, minAng: this.minAng, maxAng: this.maxAng, posX: this.posX,posY: this.posY});
    };

    CChangesGeometryAddHandlePolar.prototype.Undo = function(){
        if(this.bReverse){
            this.AddHandlePolar();
        }
        else{
            this.RemoveHandlePolar();
        }
    };
    CChangesGeometryAddHandlePolar.prototype.Redo = function(){
        if(this.bReverse){
            this.RemoveHandlePolar();
        }
        else{
            this.AddHandlePolar();
        }
    };
    CChangesGeometryAddHandlePolar.prototype.WriteToBinary = function(Writer){
        AscFormat.writeString(Writer, this.gdRefR);
        AscFormat.writeString(Writer, this.minR);
        AscFormat.writeString(Writer, this.maxR);
        AscFormat.writeString(Writer, this.gdRefAng);
        AscFormat.writeString(Writer, this.minAng);
        AscFormat.writeString(Writer, this.maxAng);
        AscFormat.writeString(Writer, this.posX);
        AscFormat.writeString(Writer, this.posY);
        Writer.WriteBool(!!this.bReverse);
    };
    CChangesGeometryAddHandlePolar.prototype.ReadFromBinary = function(Reader){
        this.gdRefR = AscFormat.readString(Reader);
        this.minR = AscFormat.readString(Reader);
        this.maxR = AscFormat.readString(Reader);
        this.gdRefAng = AscFormat.readString(Reader);
        this.minAng = AscFormat.readString(Reader);
        this.maxAng = AscFormat.readString(Reader);
        this.posX = AscFormat.readString(Reader);
        this.posY = AscFormat.readString(Reader);
        this.bReverse = Reader.GetBool();
    };
    CChangesGeometryAddHandlePolar.prototype.CreateReverseChange = function(){
        return new CChangesGeometryAddHandlePolar(this.Class, this.gdRefR, this.minR, this.maxR, this.gdRefAng, this.minAng, this.maxAng, this.posX, this.posY, !this.bReverse);
    };
    AscDFH.changesFactory[AscDFH.historyitem_GeometryAddHandlePolar] = CChangesGeometryAddHandlePolar;

    function CChangesGeometryAddRect(Class, l, t, r, b, bReverse){
        this.Type = AscDFH.historyitem_GeometryAddRect;
        this.l = l;
        this.t = t;
        this.r = r;
        this.b = b;
        this.bReverse = bReverse;
		AscDFH.CChangesBase.call(this, Class);
    }

	CChangesGeometryAddRect.prototype = Object.create(AscDFH.CChangesBase.prototype);
	CChangesGeometryAddRect.prototype.constructor = CChangesGeometryAddRect;
    CChangesGeometryAddRect.prototype.Undo = function(){
        if(this.bReverse){
            this.Class.rectS = {l: this.l, t: this.t, r: this.r, b: this.b};
        }
        else{
            this.Class.rectS = null;
        }

    };
    CChangesGeometryAddRect.prototype.Redo = function(){
        if(this.bReverse){
            this.Class.rectS = null;
        }
        else{
            this.Class.rectS = {l: this.l, t: this.t, r: this.r, b: this.b};
        }
    };
    CChangesGeometryAddRect.prototype.WriteToBinary = function(Writer){
        AscFormat.writeString(Writer, this.l);
        AscFormat.writeString(Writer, this.t);
        AscFormat.writeString(Writer, this.r);
        AscFormat.writeString(Writer, this.b);
        Writer.WriteBool(!!this.bReverse);
    };
    CChangesGeometryAddRect.prototype.ReadFromBinary = function(Reader){
        this.l = AscFormat.readString(Reader);
        this.t = AscFormat.readString(Reader);
        this.r = AscFormat.readString(Reader);
        this.b = AscFormat.readString(Reader);
        this.bReverse = Reader.GetBool();
    };
    AscDFH.changesFactory[AscDFH.historyitem_GeometryAddRect] = CChangesGeometryAddRect;
    AscDFH.changesFactory[AscDFH.historyitem_GeometrySetPreset ] = AscDFH.CChangesDrawingsString;
    AscDFH.drawingsChangesMap[AscDFH.historyitem_GeometrySetPreset] = function(oClass, value){oClass.preset = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_GeometrySetParent] = function(oClass, value){oClass.parent = value;};

    AscDFH.changesFactory[AscDFH.historyitem_GeometryAddPath] = AscDFH.CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_GeometrySetParent] = AscDFH.CChangesDrawingsObject;
    AscDFH.drawingContentChanges[AscDFH.historyitem_GeometryAddPath] = function(oClass){return oClass.pathLst;};

function Geometry()
{
    this.gdLstInfo      = [];
    this.gdLst          = {};
    this.avLst          = {};

    this.cnxLstInfo     = [];
    this.cnxLst         = [];

    this.ahXYLstInfo    = [];
    this.ahXYLst        = [];

    this.ahPolarLstInfo = [];
    this.ahPolarLst     = [];

    this.pathLst        = [];
    this.preset = null;
    this.rectS = null;

    this.parent = null;

    this.bDrawSmart = false;


    this.Id = AscCommon.g_oIdCounter.Get_NewId();
    AscCommon.g_oTableId.Add(this, this.Id);
}

Geometry.prototype=
{
    Get_Id: function()
    {
        return this.Id;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_Geometry;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    Refresh_RecalcData: function(data)
    {
        if(this.parent && this.parent.handleUpdateGeometry)
        {
            this.parent.handleUpdateGeometry();
        }
    },

    isEmpty: function()
    {
        if(this.pathLst.length === 0)
            return true;
        if(this.pathLst.length === 1)
        {
            return this.pathLst[0].ArrPathCommandInfo.length === 0;
        }
        return false;
    },

    createDuplicate: function()
    {
        var g = new Geometry();
        for(var i = 0; i < this.gdLstInfo.length; ++i)
        {
            var gd = this.gdLstInfo[i];
            g.AddGuide(gd.name, gd.formula, gd.x, gd.y, gd.z);
        }
        for(var key in this.avLst)
        {
            g.AddAdj(key, 15, this.gdLst[key] + "", undefined, undefined);
        }
        g.setPreset(this.preset);
        for(i = 0; i < this.cnxLstInfo.length; ++i)
        {
            var cn = this.cnxLstInfo[i];
            g.AddCnx(cn.ang, cn.x, cn.y);
        }
        for(i = 0; i < this.ahXYLstInfo.length; ++i)
        {
            var ah = this.ahXYLstInfo[i];
            g.AddHandleXY(ah.gdRefX, ah.minX, ah.maxX, ah.gdRefY, ah.minY, ah.maxY, ah.posX, ah.posY);
        }
        for(i = 0; i < this.ahPolarLstInfo.length; ++i)
        {
            var ah = this.ahPolarLstInfo[i];
            g.AddHandlePolar(ah.gdRefAng, ah.minAng, ah.maxAng, ah.gdRefR, ah.minR, ah.maxR, ah.posX, ah.posY);
        }
        for(i = 0; i < this.pathLst.length; ++i)
        {
            g.AddPath(this.pathLst[i].createDuplicate());
        }
        if(this.rectS)
        {
            g.AddRect(this.rectS.l, this.rectS.t, this.rectS.r, this.rectS.b);
        }
        return g;
    },

    setParent: function(pr)
    {
        History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_GeometrySetParent, this.parent, pr));
        this.parent = pr;
    },

    setPreset: function(preset)
    {
        History.Add(new AscDFH.CChangesDrawingsString(this, AscDFH.historyitem_GeometrySetPreset, this.preset, preset));
        this.preset = preset;
    },

    AddAdj: function(name, formula, x)
    {
        var OldValue = null;
        if(this.gdLst[name] !== null && this.gdLst[name] !== undefined){
            OldValue = this.gdLst[name] + "";
        }
        History.Add(new CChangesGeometryAddAdj(this, name, OldValue, x, this.avLst[name]));
        var dVal = parseInt(x);
        if(isNaN(dVal))
        {
            if(AscFormat.isRealNumber(oGdLst[x]))
            {
                dVal = oGdLst[x];
            }
            else
            {
                dVal = 0;
            }
        }
        this.gdLst[name] = dVal;
        this.avLst[name] = true;
    },

    setAdjValue: function(name, val)
    {
        this.AddAdj(name, 15, val + "");
        if(this.parent && this.parent.handleUpdateGeometry)
        {
            this.parent.handleUpdateGeometry();
        }
    },

    CheckCorrect: function(){
        if(!this.parent){
            return false;
        }
        if(this.pathLst.length === 0){
            return false;
        }
        return true;
    },

    AddGuide: function(name, formula, x, y, z)
    {
        History.Add(new CChangesGeometryAddGuide(this, name, formula, x, y, z));
        this.gdLstInfo.push(
            {
                name: name,
                formula: formula,
                x: x,
                y: y,
                z: z
            });
    },

    AddCnx: function(ang, x, y)
    {
        History.Add(new CChangesGeometryAddCnx(this, ang, x, y));
        this.cnxLstInfo.push(
            {
                ang:ang,
                x:x,
                y:y
            });
    },

    AddHandleXY: function(gdRefX, minX, maxX, gdRefY, minY, maxY, posX, posY)
    {
        History.Add(new CChangesGeometryAddHandleXY(this, gdRefX, minX, maxX, gdRefY, minY, maxY, posX, posY));
        this.ahXYLstInfo.push(
            {
                gdRefX:gdRefX,
                minX:minX,
                maxX:maxX,

                gdRefY:gdRefY,
                minY:minY,
                maxY:maxY,

                posX:posX,
                posY:posY
            });
    },

    AddHandlePolar: function(gdRefAng, minAng, maxAng, gdRefR, minR, maxR, posX, posY)
    {
        History.Add(new CChangesGeometryAddHandlePolar(this, gdRefR, minR, maxR, gdRefAng, minAng, maxAng, posX, posY));
        this.ahPolarLstInfo.push(
            {
                gdRefAng:gdRefAng,
                minAng:minAng,
                maxAng:maxAng,

                gdRefR:gdRefR,
                minR:minR,
                maxR:maxR,

                posX:posX,
                posY:posY
            })
    },

    AddPath: function(pr)
    {
        History.Add(new AscDFH.CChangesDrawingsContent(this, AscDFH.historyitem_GeometryAddPath, this.pathLst.length, [pr], true));
        this.pathLst.push(pr);
    },

    AddPathCommand: function(command, x1, y1, x2, y2, x3, y3)
    {
        switch(command)
        {
            case 0:
            {                              /* extrusionOk, fill, stroke, w, h*/
                var path = new AscFormat.Path();
                path.setExtrusionOk(x1 || false);
                path.setFill(y1 || "norm");
                path.setStroke(x2 != undefined ? x2 : true);
                path.setPathW(y2);
                path.setPathH(x3);
                this.AddPath(path);
                break;
            }
            case 1:
            {
                this.pathLst[this.pathLst.length-1].moveTo(x1, y1);
                break;
            }
            case 2:
            {
                this.pathLst[this.pathLst.length-1].lnTo(x1, y1);
                break;
            }
            case 3:
            {
                this.pathLst[this.pathLst.length-1].arcTo(x1/*wR*/, y1/*hR*/, x2/*stAng*/, y2/*swAng*/);
                break;
            }
            case 4:
            {
                this.pathLst[this.pathLst.length-1].quadBezTo(x1, y1, x2, y2);
                break;
            }
            case 5:
            {
                this.pathLst[this.pathLst.length-1].cubicBezTo(x1, y1, x2, y2, x3, y3);
                break;
            }
            case 6:
            {
                this.pathLst[this.pathLst.length-1].close();
                break;
            }
        }
    },

    AddRect: function(l, t, r, b)
    {
        History.Add(new CChangesGeometryAddRect(this, l, t, r, b));
        this.rectS = {};
        this.rectS.l = l;
        this.rectS.t = t;
        this.rectS.r = r;
        this.rectS.b = b;
    },

    findConnector: function(x, y, distanse){
        var dx, dy;
        for(var i = 0; i < this.cnxLst.length; i++)
        {
            dx=x-this.cnxLst[i].x;
            dy=y-this.cnxLst[i].y;

            if(Math.sqrt(dx*dx+dy*dy) < distanse)
            {
                return {idx: i, ang: this.cnxLst[i].ang, x: this.cnxLst[i].x, y: this.cnxLst[i].y};
            }
        }
        return null;
    },


    drawConnectors: function(overlay, transform){

        var dOldAlpha;

        var oGraphics = overlay.Graphics ? overlay.Graphics : overlay;
        if(AscFormat.isRealNumber(oGraphics.globalAlpha) && oGraphics.put_GlobalAlpha){
            dOldAlpha = oGraphics.globalAlpha;
            oGraphics.put_GlobalAlpha(false, 1);
        }
        for(var i = 0; i < this.cnxLst.length; i++)
        {
            overlay.DrawEditWrapPointsPolygon([{x: this.cnxLst[i].x, y: this.cnxLst[i].y}], transform);
        }
        if(AscFormat.isRealNumber(dOldAlpha) && oGraphics.put_GlobalAlpha){
            oGraphics.put_GlobalAlpha(true, dOldAlpha);
        }

    },

    Recalculate: function(w, h, bResetPathsInfo)
    {
        this.gdLst["_3cd4"]= 16200000;
        this.gdLst["_3cd8"]= 8100000;
        this.gdLst["_5cd8"]= 13500000;
        this.gdLst["_7cd8"]= 18900000;
        this.gdLst["cd2"]= 10800000;
        this.gdLst["cd4"]= 5400000;
        this.gdLst["cd8"]= 2700000;
        this.gdLst["l"]= 0;
        this.gdLst["t"]= 0;
        this.gdLst["h"]= h;
        this.gdLst["b"]= h;
        this.gdLst["hd2"]= h/2;
        this.gdLst["hd3"]= h/3;
        this.gdLst["hd4"]= h/4;
        this.gdLst["hd5"]= h/5;
        this.gdLst["hd6"]= h/6;
        this.gdLst["hd8"]= h/8;
        this.gdLst["hd10"]= h/10;
        this.gdLst["hd12"]= h/12;
        this.gdLst["hd32"]= h/32;
        this.gdLst["vc"]= h/2;
        this.gdLst["w"]= w;
        this.gdLst["r"]= w;
        this.gdLst["wd2"]= w/2;
        this.gdLst["wd3"]= w/3;
        this.gdLst["wd4"]= w/4;
        this.gdLst["wd5"]= w/5;
        this.gdLst["wd6"]= w/6;
        this.gdLst["wd8"]= w/8;
        this.gdLst["wd10"] = w/10;
        this.gdLst["wd12"] = w/12;
        this.gdLst["wd32"] = w/32;
        this.gdLst["hc"]=w/2;
        this.gdLst["ls"]=Math.max(w,h);
        this.gdLst["ss"]=Math.min(w,h);
        this.gdLst["ssd2"]=this.gdLst["ss"]/2;
        this.gdLst["ssd4"]=this.gdLst["ss"]/4;
        this.gdLst["ssd6"]=this.gdLst["ss"]/6;
        this.gdLst["ssd8"]=this.gdLst["ss"]/8;
        this.gdLst["ssd16"]=this.gdLst["ss"]/16;
        this.gdLst["ssd32"]=this.gdLst["ss"]/32;
        CalculateGuideLst(this.gdLstInfo, this.gdLst);
        CalculateCnxLst(this.cnxLstInfo, this.cnxLst, this.gdLst);
        CalculateAhXYList(this.ahXYLstInfo, this.ahXYLst, this.gdLst);
        CalculateAhPolarList(this.ahPolarLstInfo, this.ahPolarLst, this.gdLst);
        for(var i=0, n=this.pathLst.length; i<n; i++)
            this.pathLst[i].recalculate(this.gdLst, bResetPathsInfo);

        this.rect = {};
        if(this.rectS)
        {
            this.rect.l = this.gdLst[this.rectS.l];
            if(this.rect.l === undefined)
            {
                this.rect.l = parseInt(this.rectS.l);
            }

            this.rect.t = this.gdLst[this.rectS.t];
            if(this.rect.t === undefined)
            {
                this.rect.t = parseInt(this.rectS.t);
            }

            this.rect.r = this.gdLst[this.rectS.r];
            if(this.rect.r === undefined)
            {
                this.rect.r = parseInt(this.rectS.r);
            }

            this.rect.b = this.gdLst[this.rectS.b];
            if(this.rect.b === undefined)
            {
                this.rect.b = parseInt(this.rectS.b);
            }
        }
        else{
            this.rect.l = this.gdLst["l"];
            this.rect.t = this.gdLst["t"];
            this.rect.r = this.gdLst["r"];
            this.rect.b = this.gdLst["b"];
        }
        if(bResetPathsInfo){
            delete this.gdLst;
            delete this.gdLstInfo;
            delete this.rect;
            delete this.rectS;
            delete this.gdLstInfo;
            delete this.cnxLstInfo;
            delete this.ahXYLstInfo;
            delete this.ahPolarLstInfo;
        }
    },

    getMaxPathPolygonLength: function()
    {
        var aByPaths = this.getArrayPolygonsByPaths(AscFormat.PATH_DIV_EPSILON);

        var dLength = 0;
        for(var i = 0; i < aByPaths.length; ++i)
        {
            var oWarpPathPolygon = new AscFormat.PolygonWrapper(aByPaths[i]);
            if(dLength < oWarpPathPolygon.dLen)
            {
                dLength = oWarpPathPolygon.dLen;
            }
        }
        return dLength;
    },
    getMinPathPolygonLength: function()
    {
        var aByPaths = this.getArrayPolygonsByPaths(AscFormat.PATH_DIV_EPSILON);

        var dLength = 10000000;
        for(var i = 0; i < aByPaths.length; ++i)
        {
            var oWarpPathPolygon = new AscFormat.PolygonWrapper(aByPaths[i]);
            if(dLength > oWarpPathPolygon.dLen)
            {
                dLength = oWarpPathPolygon.dLen;
            }
        }
        return dLength;
    },

    draw: function(shape_drawer)
    {
        if(shape_drawer.Graphics && shape_drawer.Graphics.bDrawSmart || this.bDrawSmart)
        {
            this.drawSmart(shape_drawer);
            return;
        }
        for (var i=0, n=this.pathLst.length; i<n;++i)
            this.pathLst[i].draw(shape_drawer);
    },

    drawSmart: function(shape_drawer)
    {
        for (var i=0, n=this.pathLst.length; i<n;++i)
            this.pathLst[i].drawSmart(shape_drawer);
    },

    check_bounds: function(checker)
    {
        for(var i=0, n=this.pathLst.length; i<n;++i)
            this.pathLst[i].check_bounds(checker);
    },

    drawAdjustments: function(drawingDocument, transform, bTextWarp)
    {
        var _adjustments = this.ahXYLst;
        var _adj_count = _adjustments.length;
        var _adj_index;
        for(_adj_index = 0; _adj_index < _adj_count; ++_adj_index)
            drawingDocument.DrawAdjustment(transform, _adjustments[_adj_index].posX, _adjustments[_adj_index].posY, bTextWarp);

        _adjustments = this.ahPolarLst;
        _adj_count = _adjustments.length;
        for(_adj_index = 0; _adj_index < _adj_count; ++_adj_index)
            drawingDocument.DrawAdjustment(transform, _adjustments[_adj_index].posX, _adjustments[_adj_index].posY, bTextWarp);
    },

    canFill: function()
    {
        if(this.preset === "line")
            return false;
        for(var i = 0; i < this.pathLst.length; ++i)
        {
            if(this.pathLst[i].fill !== "none")
                return true;
        }
        return  false;
    },

    hitInInnerArea: function(canvasContext, x, y)
    {
        var _path_list = this.pathLst;
        var _path_count = _path_list.length;
        var _path_index;
        for(_path_index = 0; _path_index < _path_count; ++_path_index)
        {
            if(_path_list[_path_index].hitInInnerArea(canvasContext, x, y) === true)
                return true;
        }
        return false;
    },

    hitInPath: function(canvasContext, x, y)
    {
        var _path_list = this.pathLst;
        var _path_count = _path_list.length;
        var _path_index;
        for(_path_index = 0; _path_index < _path_count; ++_path_index)
        {
            if(_path_list[_path_index].hitInPath(canvasContext, x, y) === true)
                return true;
        }
        return false;
    },

    hitToAdj: function(x, y, distanse)
    {
        var dx, dy;
        for(var i=0; i<this.ahXYLst.length; i++)
        {
            dx=x-this.ahXYLst[i].posX;
            dy=y-this.ahXYLst[i].posY;

            if(Math.sqrt(dx*dx+dy*dy) < distanse)
            {
                return {hit: true, adjPolarFlag: false, adjNum: i};
            }
        }

        for( i=0; i<this.ahPolarLst.length; i++)
        {
            dx=x-this.ahPolarLst[i].posX;
            dy=y-this.ahPolarLst[i].posY;

            if(Math.sqrt(dx*dx+dy*dy) < distanse)
            {
                return {hit: true, adjPolarFlag: true, adjNum: i};
            }
        }
        return {hit: false, adjPolarFlag: null, adjNum: null};
    },

    getArrayPolygonsByPaths: function(epsilon)
    {
        return GetArrayPolygonsByPaths(epsilon, this.pathLst);
    },


    getArrayPolygons: function(epsilon)
    {
        var used_epsilon;
        if(typeof epsilon !== "number" || isNaN(epsilon))
            used_epsilon = AscFormat.APPROXIMATE_EPSILON;
        else
            used_epsilon = epsilon;
        var arr_polygons = [];
        var cur_polygon = [];
        for(var path_index = 0; path_index < this.pathLst.length; ++path_index)
        {
            var arr_cur_path_commands = this.pathLst[path_index].ArrPathCommand;
            var last_command = null, last_point_x = null, last_point_y = null;
            var first_point_x = null, first_point_y = null;
            var bezier_polygon = null;
            for(var command_index = 0; command_index < arr_cur_path_commands.length; ++command_index)
            {
                var cur_command = arr_cur_path_commands[command_index];
                switch(cur_command.id)
                {
                    case AscFormat.moveTo:
                    {
                        if(last_command === null || last_command.id === AscFormat.close)
                        {
                            cur_polygon.push({x: cur_command.X, y: cur_command.Y});
                            last_command = cur_command;
                            last_point_x = cur_command.X;
                            last_point_y = cur_command.Y;
                            first_point_x = cur_command.X;
                            first_point_y = cur_command.Y;
                        }
                        break;
                    }
                    case AscFormat.lineTo:
                    {
                        cur_polygon.push({x: cur_command.X, y: cur_command.Y});
                        last_command = cur_command;
                        last_point_x = cur_command.X;
                        last_point_y = cur_command.Y;
                        break;
                    }
                    case AscFormat.bezier3:
                    {
                        bezier_polygon = AscFormat.partition_bezier3(last_point_x, last_point_y, cur_command.X0, cur_command.Y0, cur_command.X1, cur_command.Y1, used_epsilon);
                        for(var point_index = 1; point_index < bezier_polygon.length; ++point_index)
                        {
                            cur_polygon.push(bezier_polygon[point_index]);
                        }
                        last_command = cur_command;
                        last_point_x = cur_command.X1;
                        last_point_y = cur_command.Y1;
                        break;
                    }
                    case AscFormat.bezier4:
                    {
                        bezier_polygon = AscFormat.partition_bezier4(last_point_x, last_point_y, cur_command.X0, cur_command.Y0, cur_command.X1, cur_command.Y1, cur_command.X2, cur_command.Y2, used_epsilon);
                        for(point_index = 1; point_index < bezier_polygon.length; ++point_index)
                        {
                            cur_polygon.push(bezier_polygon[point_index]);
                        }
                        last_command = cur_command;
                        last_point_x = cur_command.X2;
                        last_point_y = cur_command.Y2;
                        break;
                    }

                    case AscFormat.arcTo:
                    {
                        var path_accumulator = new PathAccumulator();
                        ArcToCurvers(path_accumulator, cur_command.stX, cur_command.stY, cur_command.wR, cur_command.hR, cur_command.stAng, cur_command.swAng);
                        var arc_to_path_commands = path_accumulator.pathCommand;
                        for(var arc_to_path_index = 0; arc_to_path_index < arc_to_path_commands.length; ++arc_to_path_index)
                        {
                            var cur_arc_to_command = arc_to_path_commands[arc_to_path_index];
                            switch (cur_arc_to_command.id)
                            {
                                case AscFormat.moveTo:
                                {
                                    cur_polygon.push({x: cur_arc_to_command.X, y: cur_arc_to_command.Y});
                                    last_command = cur_arc_to_command;
                                    last_point_x = cur_arc_to_command.X;
                                    last_point_y = cur_arc_to_command.Y;
                                    break;
                                }
                                case AscFormat.bezier4:
                                {
                                    bezier_polygon = AscFormat.partition_bezier4(last_point_x, last_point_y, cur_arc_to_command.X0, cur_arc_to_command.Y0, cur_arc_to_command.X1, cur_arc_to_command.Y1, cur_arc_to_command.X2, cur_arc_to_command.Y2, used_epsilon);
                                    for(point_index = 0; point_index < bezier_polygon.length; ++point_index)
                                    {
                                        cur_polygon.push(bezier_polygon[point_index]);
                                    }
                                    last_command = cur_arc_to_command;
                                    last_point_x = cur_arc_to_command.X2;
                                    last_point_y = cur_arc_to_command.Y2;
                                    break;
                                }
                            }
                        }
                        break;
                    }

                    case AscFormat.close:
                    {

                        if(last_command.id !== AscFormat.moveTo)
                        {
                            if(cur_polygon.length >= 2)
                            {
                                if(first_point_x !== null && first_point_y !== null)
                                {
                                    cur_polygon.push({x: first_point_x, y: first_point_y});
                                }
                                arr_polygons.push(cur_polygon);
                            }
                            cur_polygon = [];
                            last_command = cur_command;
                        }
                        break;
                    }
                }
            }
            if(cur_polygon.length >= 2)
            {
                /*if(first_point_x !== null && first_point_y !== null)
                 {
                 cur_polygon.push({x: first_point_x, y: first_point_y});
                 }             */
                arr_polygons.push(cur_polygon);
            }
            if(cur_polygon.length === 1)
            {
                cur_polygon.push({x:cur_polygon[0].x, y:cur_polygon[0].y});
                arr_polygons.push(cur_polygon);
            }
        }
        return arr_polygons;
    },


    getBounds: function()
    {

    },

    getNewWHByTextRect: function(dTextWidth, dTextHeight, dGeometryWidth, dGeometryHeight)
    {
        var dDelta = 0;
        var dWi = dTextWidth, dHi = dTextHeight, dWNext, dHNext;
        var oGeometry = AscFormat.ExecuteNoHistory(function(){return this.createDuplicate()}, this, []);
        var iter_Count = 0;
        if(!AscFormat.isRealNumber(dGeometryWidth) && !AscFormat.isRealNumber(dGeometryHeight))
        {
            do
            {
                oGeometry.Recalculate(dWi, dHi);
                dWNext = dTextWidth - (oGeometry.rect.r - oGeometry.rect.l) + dWi;
                dHNext = dTextHeight - (oGeometry.rect.b - oGeometry.rect.t) + dHi;
                dDelta = Math.max(Math.abs(dWNext - dWi), Math.abs(dHNext - dHi));
                dWi = dWNext;
                dHi = dHNext;
                ++iter_Count;
            }
            while(dDelta > EPSILON_TEXT_AUTOFIT && iter_Count < MAX_ITER_COUNT);
            return {W: dWi, H: dHi, bError: dDelta > EPSILON_TEXT_AUTOFIT};
        }
        else if(AscFormat.isRealNumber(dGeometryWidth))
        {
            do
            {
                oGeometry.Recalculate(dGeometryWidth, dHi);
                dHNext = dTextHeight - (oGeometry.rect.b - oGeometry.rect.t) + dHi;
                dDelta = Math.abs(dHNext - dHi);
                dHi = dHNext;
                ++iter_Count;
            }
            while(dDelta > EPSILON_TEXT_AUTOFIT && iter_Count < MAX_ITER_COUNT);
            return {W: dGeometryWidth, H: dHi, bError: dDelta > EPSILON_TEXT_AUTOFIT};
        }
        else
        {
            do
            {
                oGeometry.Recalculate(dWi, dGeometryHeight);
                dWNext = dTextWidth - (oGeometry.rect.r - oGeometry.rect.l) + dWi;
                dDelta = Math.abs(dWNext - dWi);
                dWi = dWNext;
                ++iter_Count;
            }
            while(dDelta > EPSILON_TEXT_AUTOFIT && iter_Count < MAX_ITER_COUNT);
            return {W: dWi, H: dGeometryHeight, bError: dDelta > EPSILON_TEXT_AUTOFIT};
        }
    }
};



function PathAccumulator()
{
    this.pathCommand = [];
}

PathAccumulator.prototype =
{
    _m: function(x, y)
    {
        this.pathCommand.push({id: AscFormat.moveTo, X: x, Y: y});
    },

    _c: function(x0, y0, x1, y1, x2, y2)
    {
        this.pathCommand.push({id: AscFormat.bezier4, X0: x0, Y0: y0, X1: x1, Y1: y1, X2: x2, Y2: y2});
    }
};

function GraphEdge(point1, point2)
{
    if(point1.y <= point2.y)
    {
        this.point1 = point1;
        this.point2 = point2;
    }
    else
    {
        this.point1 = point2;
        this.point2 = point1;
    }

    this.getIntersectionPointX = function(y)
    {
        var ret = [];
        if(this.point2.y < y || this.point1.y > y)
        {
            return ret;
        }
        else
        {
            if(this.point1.y === this.point2.y)
            {
                if(this.point1.x <= this.point2.x)
                {
                    ret.push(this.point1.x);
                    ret.push(this.point2.x);
                    return ret;
                }
                else
                {
                    ret.push(this.point2.x);
                    ret.push(this.point1.x);
                    return ret;
                }
            }
            else
            {
                if(!(this.point1.x === this.point2.x))
                {
                    var ret_x = this.point1.x + ((y -  this.point1.y)/(this.point2.y - this.point1.y))*(this.point2.x - this.point1.x);
                    ret.push(ret_x);
                    return ret;
                }
                else
                {
                    ret.push(this.point1.x);
                    return ret;
                }
            }
        }
    }
}


function GetArrayPolygonsByPaths(dEpsilon, aPathLst)
{
    var geom = new Geometry();
    var aByPaths = [];
    for(var i = 0; i < aPathLst.length; ++i)
    {
        geom.pathLst.length = 0;
        geom.pathLst.push(aPathLst[i]);
        var a = geom.getArrayPolygons(dEpsilon);
        aByPaths[i] = [];
        for(var t = 0; t < a.length; ++t)
        {
            aByPaths[i] = aByPaths[i].concat(a[t]);
        }
    }
    return aByPaths;
}

function ComparisonEdgeByTopPoint(graphEdge1, graphEdge2)
{
    return Math.min(graphEdge1.point1.y, graphEdge1.point2.y) - Math.min(graphEdge2.point1.y, graphEdge2.point2.y);
}



    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].Geometry = Geometry;
    window['AscFormat'].GraphEdge = GraphEdge;

    window['AscFormat'].EPSILON_TEXT_AUTOFIT = EPSILON_TEXT_AUTOFIT;
    window['AscFormat'].APPROXIMATE_EPSILON = 1;
    window['AscFormat'].APPROXIMATE_EPSILON2 = 3;
    window['AscFormat'].APPROXIMATE_EPSILON3 = 5;
    window['AscFormat'].cToRad = cToRad;
    window['AscFormat'].cToDeg = cToDeg;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {

	var recalcSlideInterval = 30;

// Import
var CreateAscColor = AscCommon.CreateAscColor;
var g_oIdCounter = AscCommon.g_oIdCounter;
var g_oTableId = AscCommon.g_oTableId;
var isRealObject = AscCommon.isRealObject;
var History = AscCommon.History;

var c_oAscColor = Asc.c_oAscColor;
var c_oAscFill = Asc.c_oAscFill;
var asc_CShapeFill = Asc.asc_CShapeFill;
var c_oAscFillGradType = Asc.c_oAscFillGradType;
var c_oAscFillBlipType = Asc.c_oAscFillBlipType;
var c_oAscStrokeType = Asc.c_oAscStrokeType;
var asc_CShapeProperty = Asc.asc_CShapeProperty;


    function CT_Hyperlink()
    {
        this.snd = null;
        this.id = null;
        this.invalidUrl = null;
        this.action = null;
        this.tgtFrame = null;
        this.tooltip = null;
        this.history = null;
        this.highlightClick = null;
        this.endSnd = null;
    }


    CT_Hyperlink.prototype.Write_ToBinary = function(w)
    {
        var nStartPos = w.GetCurPosition();
        var nFlags = 0;
        w.WriteLong(0);

        if(null !== this.snd){
            nFlags |= 1;
            w.WriteString2(this.snd);
        }
        if(null !== this.id){
            nFlags |= 2;
            w.WriteString2(this.id);
        }
        if(null !== this.invalidUrl){
            nFlags |= 4;
            w.WriteString2(this.invalidUrl);
        }
        if(null !== this.action){
            nFlags |= 8;
            w.WriteString2(this.action);
        }
        if(null !== this.tgtFrame){
            nFlags |= 16;
            w.WriteString2(this.tgtFrame);
        }
        if(null !== this.tooltip){
            nFlags |= 32;
            w.WriteString2(this.tooltip);
        }
        if(null !== this.history){
            nFlags |= 64;
            w.WriteBool(this.history);
        }
        if(null !== this.highlightClick){
            nFlags |= 128;
            w.WriteBool(this.highlightClick);
        }
        if(null !== this.endSnd){
            nFlags |= 256;
            w.WriteBool(this.endSnd);
        }
        var nEndPos = w.GetCurPosition();
        w.Seek(nStartPos);
        w.WriteLong(nFlags);
        w.Seek(nEndPos);
    };

    CT_Hyperlink.prototype.Read_FromBinary = function(r){
        var nFlags = r.GetLong();
        if(nFlags & 1){
            this.snd = r.GetString2();
        }
        if(nFlags & 2){
            this.id = r.GetString2();
        }
        if(nFlags & 4){
            this.invalidUrl = r.GetString2();
        }
        if(nFlags & 8){
            this.action = r.GetString2();
        }
        if(nFlags & 16){
            this.tgtFrame = r.GetString2();
        }
        if(nFlags & 32){
            this.tooltip = r.GetString2();
        }
        if(nFlags & 64){
            this.history = r.GetBool();
        }
        if(nFlags & 128){
            this.highlightClick = r.GetBool();
        }
        if(nFlags & 256){
            this.endSnd = r.GetBool();
        }
    };

    CT_Hyperlink.prototype.createDuplicate = function(r){
        var ret = new CT_Hyperlink();
        ret.snd = this.snd;
        ret.id = this.id;
        ret.invalidUrl = this.invalidUrl;
        ret.action = this.action;
        ret.tgtFrame = this.tgtFrame;
        ret.tooltip = this.tooltip;
        ret.history = this.history;
        ret.highlightClick = this.highlightClick;
        ret.endSnd = this.endSnd;
        return ret;
    };



    var CChangesDrawingsBool = AscDFH.CChangesDrawingsBool;
    var CChangesDrawingsLong = AscDFH.CChangesDrawingsLong;
    var CChangesDrawingsDouble = AscDFH.CChangesDrawingsDouble;
    var CChangesDrawingsString = AscDFH.CChangesDrawingsString;
    var CChangesDrawingsObjectNoId = AscDFH.CChangesDrawingsObjectNoId;
    var CChangesDrawingsObject = AscDFH.CChangesDrawingsObject;
    var CChangesDrawingsContentNoId = AscDFH.CChangesDrawingsContentNoId;
    var CChangesDrawingsContentLong = AscDFH.CChangesDrawingsContentLong;
    var CChangesDrawingsContentLongMap = AscDFH.CChangesDrawingsContentLongMap;
    var CChangesDrawingsContent = AscDFH.CChangesDrawingsContent;


    var drawingsChangesMap = window['AscDFH'].drawingsChangesMap;
    var drawingConstructorsMap = window['AscDFH'].drawingsConstructorsMap;
    var drawingContentChanges = window['AscDFH'].drawingContentChanges;



        drawingsChangesMap[AscDFH.historyitem_DefaultShapeDefinition_SetSpPr    ] = function (oClass, value){oClass.spPr     = value;};
        drawingsChangesMap[AscDFH.historyitem_DefaultShapeDefinition_SetBodyPr  ] = function (oClass, value){oClass.bodyPr   = value;};
        drawingsChangesMap[AscDFH.historyitem_DefaultShapeDefinition_SetLstStyle] = function (oClass, value){oClass.lstStyle = value;};
        drawingsChangesMap[AscDFH.historyitem_DefaultShapeDefinition_SetStyle   ] = function (oClass, value){oClass.style    = value;};
        drawingsChangesMap[AscDFH.historyitem_CNvPr_SetId                       ] = function (oClass, value){oClass.id        = value;};
        drawingsChangesMap[AscDFH.historyitem_CNvPr_SetName                     ] = function (oClass, value){oClass.name      = value;};
        drawingsChangesMap[AscDFH.historyitem_CNvPr_SetIsHidden                 ] = function (oClass, value){oClass.isHidden  = value;};
        drawingsChangesMap[AscDFH.historyitem_CNvPr_SetDescr                    ] = function (oClass, value){oClass.descr     = value;};
        drawingsChangesMap[AscDFH.historyitem_CNvPr_SetTitle                    ] = function (oClass, value){oClass.title     = value;};
        drawingsChangesMap[AscDFH.historyitem_CNvPr_SetHlinkClick                    ] = function (oClass, value){oClass.hlinkClick     = value;};
        drawingsChangesMap[AscDFH.historyitem_CNvPr_SetHlinkHover                    ] = function (oClass, value){oClass.hlinkHover     = value;};
        drawingsChangesMap[AscDFH.historyitem_NvPr_SetIsPhoto                   ] = function (oClass, value){oClass.isPhoto   = value;};
        drawingsChangesMap[AscDFH.historyitem_NvPr_SetUserDrawn                 ] = function (oClass, value){oClass.userDrawn = value;};
        drawingsChangesMap[AscDFH.historyitem_NvPr_SetPh                        ] = function (oClass, value){oClass.ph        = value;};
        drawingsChangesMap[AscDFH.historyitem_Ph_SetHasCustomPrompt             ] = function (oClass, value){oClass.hasCustomPrompt = value;};
        drawingsChangesMap[AscDFH.historyitem_Ph_SetIdx                         ] = function (oClass, value){oClass.idx             = value;};
        drawingsChangesMap[AscDFH.historyitem_Ph_SetOrient                      ] = function (oClass, value){oClass.orient          = value;};
        drawingsChangesMap[AscDFH.historyitem_Ph_SetSz                          ] = function (oClass, value){oClass.sz              = value;};
        drawingsChangesMap[AscDFH.historyitem_Ph_SetType                        ] = function (oClass, value){oClass.type            = value;};
        drawingsChangesMap[AscDFH.historyitem_UniNvPr_SetCNvPr                  ] = function (oClass, value){oClass.cNvPr = value;};
        drawingsChangesMap[AscDFH.historyitem_UniNvPr_SetUniPr                  ] = function (oClass, value){oClass.uniPr = value;};
        drawingsChangesMap[AscDFH.historyitem_UniNvPr_SetNvPr                   ] = function (oClass, value){oClass.nvPr  = value;};
        drawingsChangesMap[AscDFH.historyitem_ShapeStyle_SetLnRef               ] = function (oClass, value){oClass.lnRef     = value;};
        drawingsChangesMap[AscDFH.historyitem_ShapeStyle_SetFillRef             ] = function (oClass, value){oClass.fillRef   = value;};
        drawingsChangesMap[AscDFH.historyitem_ShapeStyle_SetFontRef             ] = function (oClass, value){oClass.fontRef   = value;};
        drawingsChangesMap[AscDFH.historyitem_ShapeStyle_SetEffectRef           ] = function (oClass, value){oClass.effectRef = value;};
        drawingsChangesMap[AscDFH.historyitem_Xfrm_SetParent                    ] = function (oClass, value){oClass.parent   = value;};
        drawingsChangesMap[AscDFH.historyitem_Xfrm_SetOffX                      ] = function (oClass, value){oClass.offX     = value; oClass.handleUpdatePosition();};
        drawingsChangesMap[AscDFH.historyitem_Xfrm_SetOffY                      ] = function (oClass, value){oClass.offY     = value; oClass.handleUpdatePosition();};
        drawingsChangesMap[AscDFH.historyitem_Xfrm_SetExtX                      ] = function (oClass, value){oClass.extX     = value; oClass.handleUpdateExtents();};
        drawingsChangesMap[AscDFH.historyitem_Xfrm_SetExtY                      ] = function (oClass, value){oClass.extY     = value; oClass.handleUpdateExtents();};
        drawingsChangesMap[AscDFH.historyitem_Xfrm_SetChOffX                    ] = function (oClass, value){oClass.chOffX   = value; oClass.handleUpdateChildOffset();};
        drawingsChangesMap[AscDFH.historyitem_Xfrm_SetChOffY                    ] = function (oClass, value){oClass.chOffY   = value; oClass.handleUpdateChildOffset();};
        drawingsChangesMap[AscDFH.historyitem_Xfrm_SetChExtX                    ] = function (oClass, value){oClass.chExtX   = value; oClass.handleUpdateChildExtents();};
        drawingsChangesMap[AscDFH.historyitem_Xfrm_SetChExtY                    ] = function (oClass, value){oClass.chExtY   = value; oClass.handleUpdateChildExtents();};
        drawingsChangesMap[AscDFH.historyitem_Xfrm_SetFlipH                     ] = function (oClass, value){oClass.flipH    = value; oClass.handleUpdateFlip();};
        drawingsChangesMap[AscDFH.historyitem_Xfrm_SetFlipV                     ] = function (oClass, value){oClass.flipV    = value; oClass.handleUpdateFlip();};
        drawingsChangesMap[AscDFH.historyitem_Xfrm_SetRot                       ] = function (oClass, value){oClass.rot      = value; oClass.handleUpdateRot();};
        drawingsChangesMap[AscDFH.historyitem_SpPr_SetParent                    ] = function (oClass, value){oClass.parent   = value;};
        drawingsChangesMap[AscDFH.historyitem_SpPr_SetBwMode                    ] = function (oClass, value){oClass.bwMode   = value;};
        drawingsChangesMap[AscDFH.historyitem_SpPr_SetXfrm                      ] = function (oClass, value){oClass.xfrm     = value;};
        drawingsChangesMap[AscDFH.historyitem_SpPr_SetGeometry                  ] = function (oClass, value){oClass.geometry = value; oClass.handleUpdateGeometry();};
        drawingsChangesMap[AscDFH.historyitem_SpPr_SetFill                      ] = function (oClass, value, FromLoad){
            oClass.Fill     = value;
            oClass.handleUpdateFill();
            if(FromLoad){
                if(typeof AscCommon.CollaborativeEditing !== "undefined")
                {
                    if(oClass.Fill && oClass.Fill.fill && oClass.Fill.fill.type === c_oAscFill.FILL_TYPE_BLIP && typeof oClass.Fill.fill.RasterImageId === "string" && oClass.Fill.fill.RasterImageId.length > 0)
                    {
                        AscCommon.CollaborativeEditing.Add_NewImage(oClass.Fill.fill.RasterImageId);
                    }
                }
            }
        };
        drawingsChangesMap[AscDFH.historyitem_SpPr_SetLn                        ] = function (oClass, value){oClass.ln       = value; oClass.handleUpdateLn();};
        drawingsChangesMap[AscDFH.historyitem_ExtraClrScheme_SetClrScheme       ] = function (oClass, value){oClass.clrScheme = value;};
        drawingsChangesMap[AscDFH.historyitem_ExtraClrScheme_SetClrMap          ] = function (oClass, value){oClass.clrMap    = value;};
        drawingsChangesMap[AscDFH.historyitem_ThemeSetColorScheme               ] = function (oClass, value){
            oClass.themeElements.clrScheme = value;
            var oWordGraphicObjects = oClass.GetWordDrawingObjects();
            if(oWordGraphicObjects){
                oWordGraphicObjects.drawingDocument.CheckGuiControlColors();
                oWordGraphicObjects.document.Api.chartPreviewManager.clearPreviews();
                oWordGraphicObjects.document.Api.textArtPreviewManager.clear();
            }
        };
        drawingsChangesMap[AscDFH.historyitem_ThemeSetFontScheme] = function (oClass, value){oClass.themeElements.fontScheme  = value;};
        drawingsChangesMap[AscDFH.historyitem_ThemeSetFmtScheme ] = function (oClass, value){oClass.themeElements.fmtScheme   = value;};
        drawingsChangesMap[AscDFH.historyitem_ThemeSetName ] = function (oClass, value){oClass.name   = value;};
        drawingsChangesMap[AscDFH.historyitem_ThemeSetIsThemeOverride ] = function (oClass, value){oClass.isThemeOverride   = value;};
        drawingsChangesMap[AscDFH.historyitem_ThemeSetSpDef ]     = function (oClass, value){oClass.spDef   = value;};
        drawingsChangesMap[AscDFH.historyitem_ThemeSetLnDef ]     = function (oClass, value){oClass.lnDef   = value;};
        drawingsChangesMap[AscDFH.historyitem_ThemeSetTxDef ]     = function (oClass, value){oClass.txDef   = value;};
        drawingsChangesMap[AscDFH.historyitem_HF_SetDt          ] = function (oClass, value){oClass.dt     = value;};
        drawingsChangesMap[AscDFH.historyitem_HF_SetFtr         ] = function (oClass, value){oClass.ftr    = value;};
        drawingsChangesMap[AscDFH.historyitem_HF_SetHdr         ] = function (oClass, value){oClass.hdr    = value;};
        drawingsChangesMap[AscDFH.historyitem_HF_SetSldNum      ] = function (oClass, value){oClass.sldNum = value;};
        drawingsChangesMap[AscDFH.historyitem_UniNvPr_SetUniSpPr] = function (oClass, value){oClass.nvUniSpPr = value;};
        drawingsChangesMap[AscDFH.historyitem_NvPr_SetUniMedia] = function (oClass, value){oClass.unimedia = value;};

    drawingContentChanges[AscDFH.historyitem_ClrMap_SetClr] = function(oClass){return oClass.color_map};
    drawingContentChanges[AscDFH.historyitem_ThemeAddExtraClrScheme] =  function(oClass){return oClass.extraClrSchemeLst;};


    drawingConstructorsMap[AscDFH.historyitem_ClrMap_SetClr] =  CUniColor;
    drawingConstructorsMap[AscDFH.historyitem_DefaultShapeDefinition_SetBodyPr  ] = CBodyPr;
    drawingConstructorsMap[AscDFH.historyitem_DefaultShapeDefinition_SetLstStyle] = TextListStyle;
    drawingConstructorsMap[AscDFH.historyitem_ShapeStyle_SetLnRef               ] =
    drawingConstructorsMap[AscDFH.historyitem_ShapeStyle_SetFillRef             ] =
    drawingConstructorsMap[AscDFH.historyitem_ShapeStyle_SetEffectRef           ] = StyleRef;
    drawingConstructorsMap[AscDFH.historyitem_ShapeStyle_SetFontRef             ] = FontRef;
    drawingConstructorsMap[AscDFH.historyitem_SpPr_SetFill                      ] = CUniFill;
    drawingConstructorsMap[AscDFH.historyitem_SpPr_SetLn                        ] = CLn;
    drawingConstructorsMap[AscDFH.historyitem_ThemeSetColorScheme               ] = ClrScheme;
    drawingConstructorsMap[AscDFH.historyitem_ThemeSetFontScheme                ] = FontScheme;
    drawingConstructorsMap[AscDFH.historyitem_ThemeSetFmtScheme                 ] = FmtScheme;
    drawingConstructorsMap[AscDFH.historyitem_UniNvPr_SetUniSpPr                 ] = CNvUniSpPr;

    drawingConstructorsMap[AscDFH.historyitem_CNvPr_SetHlinkClick] = CT_Hyperlink;
    drawingConstructorsMap[AscDFH.historyitem_CNvPr_SetHlinkHover] = CT_Hyperlink;


    AscDFH.changesFactory[AscDFH.historyitem_DefaultShapeDefinition_SetSpPr] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DefaultShapeDefinition_SetBodyPr] = CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_DefaultShapeDefinition_SetLstStyle] = CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_DefaultShapeDefinition_SetStyle] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_CNvPr_SetId] = CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_CNvPr_SetName] = CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_CNvPr_SetIsHidden] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_CNvPr_SetDescr] = CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_CNvPr_SetTitle] = CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_CNvPr_SetHlinkClick] = CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_CNvPr_SetHlinkHover] = CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_NvPr_SetIsPhoto] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_NvPr_SetUserDrawn] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_NvPr_SetPh] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_NvPr_SetUniMedia] = CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_Ph_SetHasCustomPrompt] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_Ph_SetIdx] = CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_Ph_SetOrient] = CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_Ph_SetSz] = CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_Ph_SetType] = CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_UniNvPr_SetCNvPr] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_UniNvPr_SetUniPr] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_UniNvPr_SetNvPr] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_UniNvPr_SetUniSpPr] = CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_ShapeStyle_SetLnRef] = CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_ShapeStyle_SetFillRef] = CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_ShapeStyle_SetFontRef] = CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_ShapeStyle_SetEffectRef] = CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_Xfrm_SetParent] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Xfrm_SetOffX] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Xfrm_SetOffY] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Xfrm_SetExtX] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Xfrm_SetExtY] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Xfrm_SetChOffX] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Xfrm_SetChOffY] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Xfrm_SetChExtX] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Xfrm_SetChExtY] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Xfrm_SetFlipH] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_Xfrm_SetFlipV] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_Xfrm_SetRot] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_SpPr_SetParent] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_SpPr_SetBwMode] = CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_SpPr_SetXfrm] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_SpPr_SetGeometry] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_SpPr_SetFill] = CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_SpPr_SetLn] = CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_ClrMap_SetClr] = CChangesDrawingsContentLongMap;
    AscDFH.changesFactory[AscDFH.historyitem_ExtraClrScheme_SetClrScheme] = CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_ExtraClrScheme_SetClrMap] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ThemeSetColorScheme] = CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_ThemeSetFontScheme] = CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_ThemeSetFmtScheme] = CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_ThemeSetName] = CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_ThemeSetIsThemeOverride] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_ThemeSetSpDef] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ThemeSetLnDef] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ThemeSetTxDef] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ThemeAddExtraClrScheme] = CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_HF_SetDt] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_HF_SetFtr] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_HF_SetHdr] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_HF_SetSldNum] = CChangesDrawingsBool;

// COLOR -----------------------
/*
 var map_color_scheme = {};
 map_color_scheme["accent1"] = 0;
 map_color_scheme["accent2"] = 1;
 map_color_scheme["accent3"] = 2;
 map_color_scheme["accent4"] = 3;
 map_color_scheme["accent5"] = 4;
 map_color_scheme["accent6"] = 5;
 map_color_scheme["bg1"]     = 6;
 map_color_scheme["bg2"]     = 7;
 map_color_scheme["dk1"]     = 8;
 map_color_scheme["dk2"]     = 9;
 map_color_scheme["folHlink"] = 10;
 map_color_scheme["hlink"]   = 11;
 map_color_scheme["lt1"]     = 12;
 map_color_scheme["lt2"]     = 13;
 map_color_scheme["phClr"]   = 14;
 map_color_scheme["tx1"]     = 15;
 map_color_scheme["tx2"]     = 16;
 */

//Типы изменений в классе CTheme

function CreateFontRef(idx, color)
{
    var ret = new FontRef();
    ret.idx = idx;
    ret.Color = color;
    return ret;
}


function CreateStyleRef(idx, color)
{
    var ret = new StyleRef();
    ret.idx = idx;
    ret.Color = color;
    return ret;
}

function CreatePresetColor(id)
{
    var ret = new CPrstColor();
    ret.idx = id;
    return ret;
}

function sRGB_to_scRGB(value)
{
    if(value < 0)
        return 0;
    if(value <= 0.04045)
        return value / 12.92;
    if(value <= 1)
        return Math.pow(((value + 0.055) / 1.055), 2.4);
    return  1;
}

function scRGB_to_sRGB(value)
{
    if( value < 0)
        return 0;
    if(value <= 0.0031308)
        return value * 12.92;
    if(value < 1)
        return 1.055 * (Math.pow(value , (1 / 2.4))) - 0.055;
    return 1;
}

function checkRasterImageId(rasterImageId) {
  var imageLocal = AscCommon.g_oDocumentUrls.getImageLocal(rasterImageId);
  return imageLocal ? imageLocal : rasterImageId;
}


var g_oThemeFontsName = {};
g_oThemeFontsName["+mj-cs"] = true;
g_oThemeFontsName["+mj-ea"] = true;
g_oThemeFontsName["+mj-lt"] = true;
g_oThemeFontsName["+mn-cs"] = true;
g_oThemeFontsName["+mn-ea"] = true;
g_oThemeFontsName["+mn-lt"] = true;

function isRealNumber(n)
{
    return typeof n === "number" && !isNaN(n);
}

function isRealBool(b)
{
    return b === true || b === false;
}


function writeLong(w, val)
{
    w.WriteBool(isRealNumber(val));
    if(isRealNumber(val))
    {
        w.WriteLong(val);
    }
}

function readLong(r)
{
    var ret;
    if(r.GetBool())
    {
        ret = r.GetLong();
    }
    else
    {
        ret = null;
    }
    return ret;
}

function writeDouble(w, val)
{
    w.WriteBool(isRealNumber(val));
    if(isRealNumber(val))
    {
        w.WriteDouble(val);
    }
}

function readDouble(r)
{
    var ret;
    if(r.GetBool())
    {
        ret = r.GetDouble();
    }
    else
    {
        ret = null;
    }
    return ret;
}

function writeBool(w, val)
{
    w.WriteBool(isRealBool(val));
    if(isRealBool(val))
    {
        w.WriteBool(val);
    }
}

function readBool(r)
{
    var ret;
    if(r.GetBool())
    {
        ret = r.GetBool();
    }
    else
    {
        ret = null;
    }
    return ret;
}

function writeString(w, val)
{
    w.WriteBool(typeof  val === "string");
    if(typeof  val === "string")
    {
        w.WriteString2(val);
    }
}

function readString(r)
{
    var ret;
    if(r.GetBool())
    {
        ret = r.GetString2();
    }
    else
    {
        ret = null;
    }
    return ret;
}

function writeObject(w, val)
{
    w.WriteBool(isRealObject(val));
    if(isRealObject(val))
    {
        w.WriteString2(val.Get_Id());
    }
}

function readObject(r)
{
    var ret;
    if(r.GetBool())
    {
        ret = g_oTableId.Get_ById(r.GetString2());
    }
    else
    {
        ret = null;
    }
    return ret;
}


function checkThemeFonts(oFontMap, font_scheme)
{
    if(oFontMap["+mj-lt"])
    {
        if(font_scheme.majorFont && typeof font_scheme.majorFont.latin === "string" && font_scheme.majorFont.latin.length > 0)
            oFontMap[font_scheme.majorFont.latin] = 1;
        delete oFontMap["+mj-lt"];
    }
    if(oFontMap["+mj-ea"])
    {
        if(font_scheme.majorFont && typeof  font_scheme.majorFont.ea === "string" && font_scheme.majorFont.ea.length > 0)
            oFontMap[font_scheme.majorFont.ea] = 1;
        delete oFontMap["+mj-ea"];
    }
    if(oFontMap["+mj-cs"])
    {
        if(font_scheme.majorFont && typeof  font_scheme.majorFont.cs === "string" && font_scheme.majorFont.cs.length > 0)
            oFontMap[font_scheme.majorFont.cs] = 1;
        delete oFontMap["+mj-cs"];
    }

    if(oFontMap["+mn-lt"])
    {
        if(font_scheme.minorFont && typeof  font_scheme.minorFont.latin === "string" && font_scheme.minorFont.latin.length > 0)
            oFontMap[font_scheme.minorFont.latin] = 1;
        delete oFontMap["+mn-lt"];
    }
    if(oFontMap["+mn-ea"])
    {
        if(font_scheme.minorFont && typeof  font_scheme.minorFont.ea === "string" && font_scheme.minorFont.ea.length > 0)
            oFontMap[font_scheme.minorFont.ea] = 1;
        delete oFontMap["+mn-ea"];
    }
    if(oFontMap["+mn-cs"])
    {
        if(font_scheme.minorFont && typeof  font_scheme.minorFont.cs === "string" && font_scheme.minorFont.cs.length > 0)
            oFontMap[font_scheme.minorFont.cs] = 1;
        delete oFontMap["+mn-cs"];
    }
}

function ExecuteNoHistory(f, oThis, args)
{
    History.TurnOff && History.TurnOff();

    var b_table_id = false;
    if(g_oTableId && !g_oTableId.m_bTurnOff)
    {
        g_oTableId.m_bTurnOff = true;
        b_table_id = true;
    }

    var ret = f.apply(oThis, args);
    History.TurnOn && History.TurnOn();
    if(b_table_id)
    {
        g_oTableId.m_bTurnOff = false;
    }
    return ret;
}


function checkObjectUnifill(obj, theme, colorMap)
{
    if(obj && obj.Unifill)
    {
        obj.Unifill.check(theme, colorMap);
        var rgba = obj.Unifill.getRGBAColor();
        obj.Color = new CDocumentColor(rgba.R, rgba.G, rgba.B, false);
    }
}
function checkTableCellPr(cellPr, slide, layout, master, theme)
{
    cellPr.Check_PresentationPr(theme);
    var color_map, rgba;
    if( slide.clrMap)
    {
        color_map = slide.clrMap;
    }
    else if(layout.clrMap)
    {
        color_map = layout.clrMap;
    }
    else if(master.clrMap)
    {
        color_map = master.clrMap;
    }
    else
    {
        color_map = AscFormat.G_O_DEFAULT_COLOR_MAP;
    }

    checkObjectUnifill(cellPr.Shd, theme, color_map);
    if(cellPr.TableCellBorders)
    {
        checkObjectUnifill(cellPr.TableCellBorders.Left, theme, color_map);
        checkObjectUnifill(cellPr.TableCellBorders.Top, theme, color_map);
        checkObjectUnifill(cellPr.TableCellBorders.Right, theme, color_map);
        checkObjectUnifill(cellPr.TableCellBorders.Bottom, theme, color_map);
        checkObjectUnifill(cellPr.TableCellBorders.InsideH, theme, color_map);
        checkObjectUnifill(cellPr.TableCellBorders.InsideV, theme, color_map);
    }
    return cellPr;
}

var Ax_Counter = {
    GLOBAL_AX_ID_COUNTER : 1000
};
var TYPE_TRACK = {
    SHAPE : 0,
    GROUP : 0,
    GROUP_PASSIVE : 1,
    TEXT : 2,
    EMPTY_PH : 3,
    CHART_TEXT : 4
};
var TYPE_KIND = {
    SLIDE : 0,
    LAYOUT : 1,
    MASTER : 2,
    NOTES  : 3,
    NOTES_MASTER: 4
};

var TYPE_TRACK_SHAPE = 0;
var TYPE_TRACK_GROUP = TYPE_TRACK_SHAPE;
var TYPE_TRACK_GROUP_PASSIVE = 1;
var TYPE_TRACK_TEXT = 2;
var TYPE_TRACK_EMPTY_PH = 3;
var TYPE_TRACK_CHART = 4;

var SLIDE_KIND = 0;
var LAYOUT_KIND = 1;
var MASTER_KIND = 2;

var map_prst_color = {};

map_prst_color["aliceBlue"] = 		0xF0F8FF;
map_prst_color["antiqueWhite"] = 	0xFAEBD7;
map_prst_color["aqua"] = 			0x00FFFF;
map_prst_color["aquamarine"] = 		0x7FFFD4;
map_prst_color["azure"] = 			0xF0FFFF;
map_prst_color["beige"] = 			0xF5F5DC;
map_prst_color["bisque"] = 			0xFFE4C4;
map_prst_color["black"] = 			0x000000;
map_prst_color["blanchedAlmond"] = 	0xFFEBCD;
map_prst_color["blue"] = 			0x0000FF;
map_prst_color["blueViolet"] = 		0x8A2BE2;
map_prst_color["brown"] = 			0xA52A2A;
map_prst_color["burlyWood"] = 		0xDEB887;
map_prst_color["cadetBlue"] = 		0x5F9EA0;
map_prst_color["chartreuse"] = 		0x7FFF00;
map_prst_color["chocolate"] = 		0xD2691E;
map_prst_color["coral"] = 			0xFF7F50;
map_prst_color["cornflowerBlue"] = 	0x6495ED;
map_prst_color["cornsilk"] = 		0xFFF8DC;
map_prst_color["crimson"] = 		0xDC143C;
map_prst_color["cyan"] = 			0x00FFFF;
map_prst_color["darkBlue"] = 		0x00008B;
map_prst_color["darkCyan"] = 		0x008B8B;
map_prst_color["darkGoldenrod"] = 	0xB8860B;
map_prst_color["darkGray"] = 		0xA9A9A9;
map_prst_color["darkGreen"] = 		0x006400;
map_prst_color["darkGrey"] = 		0xA9A9A9;
map_prst_color["darkKhaki"] = 		0xBDB76B;
map_prst_color["darkMagenta"] = 	0x8B008B;
map_prst_color["darkOliveGreen"] = 	0x556B2F;
map_prst_color["darkOrange"] = 		0xFF8C00;
map_prst_color["darkOrchid"] = 		0x9932CC;
map_prst_color["darkRed"] = 		0x8B0000;
map_prst_color["darkSalmon"] = 		0xE9967A;
map_prst_color["darkSeaGreen"] = 	0x8FBC8F;
map_prst_color["darkSlateBlue"] = 	0x483D8B;
map_prst_color["darkSlateGray"] = 	0x2F4F4F;
map_prst_color["darkSlateGrey"] = 	0x2F4F4F;
map_prst_color["darkTurquoise"] = 	0x00CED1;
map_prst_color["darkViolet"] = 		0x9400D3;
map_prst_color["deepPink"] = 		0xFF1493;
map_prst_color["deepSkyBlue"] = 	0x00BFFF;
map_prst_color["dimGray"] = 		0x696969;
map_prst_color["dimGrey"] = 		0x696969;
map_prst_color["dkBlue"] = 			0x00008B;
map_prst_color["dkCyan"] = 			0x008B8B;
map_prst_color["dkGoldenrod"] = 	0xB8860B;
map_prst_color["dkGray"] = 			0xA9A9A9;
map_prst_color["dkGreen"] = 		0x006400;
map_prst_color["dkGrey"] = 			0xA9A9A9;
map_prst_color["dkKhaki"] = 		0xBDB76B;
map_prst_color["dkMagenta"] = 		0x8B008B;
map_prst_color["dkOliveGreen"] = 	0x556B2F;
map_prst_color["dkOrange"] = 		0xFF8C00;
map_prst_color["dkOrchid"] = 		0x9932CC;
map_prst_color["dkRed"] = 			0x8B0000;
map_prst_color["dkSalmon"] = 		0xE9967A;
map_prst_color["dkSeaGreen"] = 		0x8FBC8B;
map_prst_color["dkSlateBlue"] = 	0x483D8B;
map_prst_color["dkSlateGray"] = 	0x2F4F4F;
map_prst_color["dkSlateGrey"] = 	0x2F4F4F;
map_prst_color["dkTurquoise"] = 	0x00CED1;
map_prst_color["dkViolet"] = 		0x9400D3;
map_prst_color["dodgerBlue"] = 		0x1E90FF;
map_prst_color["firebrick"] = 		0xB22222;
map_prst_color["floralWhite"] = 	0xFFFAF0;
map_prst_color["forestGreen"] = 	0x228B22;
map_prst_color["fuchsia"] = 		0xFF00FF;
map_prst_color["gainsboro"] = 		0xDCDCDC;
map_prst_color["ghostWhite"] = 		0xF8F8FF;
map_prst_color["gold"] = 			0xFFD700;
map_prst_color["goldenrod"] = 		0xDAA520;
map_prst_color["gray"] = 			0x808080;
map_prst_color["green"] = 			0x008000;
map_prst_color["greenYellow"] = 	0xADFF2F;
map_prst_color["grey"] = 			0x808080;
map_prst_color["honeydew"] = 		0xF0FFF0;
map_prst_color["hotPink"] = 		0xFF69B4;
map_prst_color["indianRed"] = 		0xCD5C5C;
map_prst_color["indigo"] = 			0x4B0082;
map_prst_color["ivory"] = 			0xFFFFF0;
map_prst_color["khaki"] = 			0xF0E68C;
map_prst_color["lavender"] = 		0xE6E6FA;
map_prst_color["lavenderBlush"] = 	0xFFF0F5;
map_prst_color["lawnGreen"] = 		0x7CFC00;
map_prst_color["lemonChiffon"] = 	0xFFFACD;
map_prst_color["lightBlue"] = 		0xADD8E6;
map_prst_color["lightCoral"] = 		0xF08080;
map_prst_color["lightCyan"] = 		0xE0FFFF;
map_prst_color["lightGoldenrodYellow"] = 0xFAFAD2;
map_prst_color["lightGray"] = 		0xD3D3D3;
map_prst_color["lightGreen"] = 		0x90EE90;
map_prst_color["lightGrey"] = 		0xD3D3D3;
map_prst_color["lightPink"] = 		0xFFB6C1;
map_prst_color["lightSalmon"] = 	0xFFA07A;
map_prst_color["lightSeaGreen"] = 	0x20B2AA;
map_prst_color["lightSkyBlue"] = 	0x87CEFA;
map_prst_color["lightSlateGray"] = 	0x778899;
map_prst_color["lightSlateGrey"] = 	0x778899;
map_prst_color["lightSteelBlue"] = 	0xB0C4DE;
map_prst_color["lightYellow"] = 	0xFFFFE0;
map_prst_color["lime"] = 			0x00FF00;
map_prst_color["limeGreen"] = 		0x32CD32;
map_prst_color["linen"] = 			0xFAF0E6;
map_prst_color["ltBlue"] = 			0xADD8E6;
map_prst_color["ltCoral"] = 		0xF08080;
map_prst_color["ltCyan"] = 			0xE0FFFF;
map_prst_color["ltGoldenrodYellow"] = 0xFAFA78;
map_prst_color["ltGray"] = 			0xD3D3D3;
map_prst_color["ltGreen"] = 		0x90EE90;
map_prst_color["ltGrey"] = 			0xD3D3D3;
map_prst_color["ltPink"] = 			0xFFB6C1;
map_prst_color["ltSalmon"] = 		0xFFA07A;
map_prst_color["ltSeaGreen"] = 		0x20B2AA;
map_prst_color["ltSkyBlue"] = 		0x87CEFA;
map_prst_color["ltSlateGray"] = 	0x778899;
map_prst_color["ltSlateGrey"] = 	0x778899;
map_prst_color["ltSteelBlue"] = 	0xB0C4DE;
map_prst_color["ltYellow"] = 		0xFFFFE0;
map_prst_color["magenta"] = 		0xFF00FF;
map_prst_color["maroon"] = 			0x800000;
map_prst_color["medAquamarine"] = 	0x66CDAA;
map_prst_color["medBlue"] = 		0x0000CD;
map_prst_color["mediumAquamarine"] =  0x66CDAA;
map_prst_color["mediumBlue"] = 		0x0000CD;
map_prst_color["mediumOrchid"] = 	0xBA55D3;
map_prst_color["mediumPurple"] = 	0x9370DB;
map_prst_color["mediumSeaGreen"] = 	0x3CB371;
map_prst_color["mediumSlateBlue"] = 0x7B68EE;
map_prst_color["mediumSpringGreen"] = 0x00FA9A;
map_prst_color["mediumTurquoise"] = 0x48D1CC;
map_prst_color["mediumVioletRed"] = 0xC71585;
map_prst_color["medOrchid"] = 		0xBA55D3;
map_prst_color["medPurple"] = 		0x9370DB;
map_prst_color["medSeaGreen"] = 	0x3CB371;
map_prst_color["medSlateBlue"] = 	0x7B68EE;
map_prst_color["medSpringGreen"] = 	0x00FA9A;
map_prst_color["medTurquoise"] = 	0x48D1CC;
map_prst_color["medVioletRed"] = 	0xC71585;
map_prst_color["midnightBlue"] = 	0x191970;
map_prst_color["mintCream"] = 		0xF5FFFA;
map_prst_color["mistyRose"] = 		0xFFE4FF;
map_prst_color["moccasin"] = 		0xFFE4B5;
map_prst_color["navajoWhite"] = 	0xFFDEAD;
map_prst_color["navy"] = 			0x000080;
map_prst_color["oldLace"] = 		0xFDF5E6;
map_prst_color["olive"] = 			0x808000;
map_prst_color["oliveDrab"] = 		0x6B8E23;
map_prst_color["orange"] = 			0xFFA500;
map_prst_color["orangeRed"] = 		0xFF4500;
map_prst_color["orchid"] = 			0xDA70D6;
map_prst_color["paleGoldenrod"] = 	0xEEE8AA;
map_prst_color["paleGreen"] = 		0x98FB98;
map_prst_color["paleTurquoise"] = 	0xAFEEEE;
map_prst_color["paleVioletRed"] = 	0xDB7093;
map_prst_color["papayaWhip"] = 		0xFFEFD5;
map_prst_color["peachPuff"] = 		0xFFDAB9;
map_prst_color["peru"] = 			0xCD853F;
map_prst_color["pink"] = 			0xFFC0CB;
map_prst_color["plum"] = 			0xD3A0D3;
map_prst_color["powderBlue"] = 		0xB0E0E6;
map_prst_color["purple"] = 			0x800080;
map_prst_color["red"] = 			0xFF0000;
map_prst_color["rosyBrown"] = 		0xBC8F8F;
map_prst_color["royalBlue"] = 		0x4169E1;
map_prst_color["saddleBrown"] = 	0x8B4513;
map_prst_color["salmon"] = 			0xFA8072;
map_prst_color["sandyBrown"] = 		0xF4A460;
map_prst_color["seaGreen"] = 		0x2E8B57;
map_prst_color["seaShell"] = 		0xFFF5EE;
map_prst_color["sienna"] = 			0xA0522D;
map_prst_color["silver"] = 			0xC0C0C0;
map_prst_color["skyBlue"] = 		0x87CEEB;
map_prst_color["slateBlue"] = 		0x6A5AEB;
map_prst_color["slateGray"] = 		0x708090;
map_prst_color["slateGrey"] = 		0x708090;
map_prst_color["snow"] = 			0xFFFAFA;
map_prst_color["springGreen"] = 	0x00FF7F;
map_prst_color["steelBlue"] = 		0x4682B4;
map_prst_color["tan"] = 			0xD2B48C;
map_prst_color["teal"] = 			0x008080;
map_prst_color["thistle"] = 		0xD8BFD8;
map_prst_color["tomato"] = 			0xFF7347;
map_prst_color["turquoise"] = 		0x40E0D0;
map_prst_color["violet"] = 			0xEE82EE;
map_prst_color["wheat"] = 			0xF5DEB3;
map_prst_color["white"] = 			0xFFFFFF;
map_prst_color["whiteSmoke"] = 		0xF5F5F5;
map_prst_color["yellow"] = 			0xFFFF00;
map_prst_color["yellowGreen"] = 	0x9ACD32;

function CColorMod()
{
    this.name = "";
    this.val = 0;
}

CColorMod.prototype =
{
    getObjectType: function()
    {
        return AscDFH.historyitem_type_ColorMod;
    },

    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    setName: function(name)
    {
        this.name = name;
    },

    setVal: function(val)
    {
        this.val = val;
    },

    createDuplicate : function()
    {
        var duplicate = new CColorMod();
        duplicate.name = this.name;
        duplicate.val = this.val;
        return duplicate;
    }
};

var cd16 = 1.0/6.0;
var cd13 = 1.0/3.0;
var cd23 = 2.0/3.0;
var max_hls = 255.0;

var DEC_GAMMA          = 2.3;
var INC_GAMMA          = 1.0 / DEC_GAMMA;
var MAX_PERCENT        = 100000;

function CColorModifiers()
{
    this.Mods = [];

}

CColorModifiers.prototype =
{
    getObjectType: function()
    {
        return AscDFH.historyitem_type_ColorModifiers;
    },

    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    getModsToWrite: function()
    {

    },



    Write_ToBinary: function(w)
    {
        w.WriteLong(this.Mods.length);
        for(var i = 0; i < this.Mods.length; ++i)
        {
            w.WriteString2(this.Mods[i].name);
            w.WriteLong(this.Mods[i].val);
        }
    },

    Read_FromBinary: function(r)
    {
        var len = r.GetLong();
        for(var i = 0; i < len; ++i)
        {
            var mod = new CColorMod();
            mod.name = r.GetString2();
            mod.val = r.GetLong();
            this.Mods.push(mod);
        }
    },

    addMod: function(mod)
    {
        this.Mods.push(mod);
    },


    removeMod: function(pos)
    {
        this.Mods.splice(pos, 1)[0];
    },


    IsIdentical : function(mods)
    {
        if(mods == null)
        {
            return false
        }
        if(mods.Mods == null || this.Mods.length!=mods.Mods.length)
        {
            return false;
        }

        for(var i = 0; i<this.Mods.length; ++i)
        {
            if(this.Mods[i].name!=mods.Mods[i].name
                || this.Mods[i].val!=mods.Mods[i].val)
            {
                return false;
            }
        }
        return true;

    },

    createDuplicate : function()
    {
        var duplicate = new CColorModifiers();
        for(var  i=0; i< this.Mods.length; ++i)
        {
            duplicate.Mods[i] = this.Mods[i].createDuplicate();
        }
        return duplicate;
    },

    RGB2HSL : function(R, G, B, HLS)
    {
        var iMin = Math.min(R, G, B);
        var iMax = Math.max(R, G, B);
        var iDelta = iMax - iMin;
        var dMax = (iMax + iMin)/255.0;
        var dDelta = iDelta/255.0;
        var H = 0;
        var S = 0;
        var L = dMax / 2.0;

        if (iDelta != 0)
        {
            if ( L < 0.5 ) S = dDelta / dMax;
            else           S = dDelta / ( 2.0 - dMax );

            dDelta = dDelta * 1530.0;
            var dR = ( iMax - R ) / dDelta;
            var dG = ( iMax - G ) / dDelta;
            var dB = ( iMax - B ) / dDelta;

            if      ( R == iMax ) H = dB - dG;
            else if ( G == iMax ) H = cd13 + dR - dB;
            else if ( B == iMax ) H = cd23 + dG - dR;

            if ( H < 0.0 ) H += 1.0;
            if ( H > 1.0 ) H -= 1.0;
        }

        H = ((H * max_hls) >> 0) & 0xFF;
        if (H < 0)
            H = 0;
        if (H > 255)
            H = 255;

        S = ((S * max_hls) >> 0) & 0xFF;
        if (S < 0)
            S = 0;
        if (S > 255)
            S = 255;

        L = ((L * max_hls) >> 0) & 0xFF;
        if (L < 0)
            L = 0;
        if (L > 255)
            L = 255;

        HLS.H = H;
        HLS.S = S;
        HLS.L = L;
    },

    HSL2RGB : function(HSL, RGB)
    {
        if (HSL.S == 0)
        {
            RGB.R = HSL.L;
            RGB.G = HSL.L;
            RGB.B = HSL.L;
        }
        else
        {
            var H = HSL.H/max_hls;
            var S = HSL.S/max_hls;
            var L = HSL.L/max_hls;
            var v2 = 0;
            if (L < 0.5)
                v2 = L * (1.0 + S);
            else
                v2 = L + S - S*L;

            var v1 = 2.0 * L - v2;

            var R = (255 * this.Hue_2_RGB(v1, v2, H + cd13)) >> 0;
            var G = (255 * this.Hue_2_RGB(v1, v2, H)) >> 0;
            var B = (255 * this.Hue_2_RGB(v1, v2, H - cd13)) >> 0;

            if (R < 0)
                R = 0;
            if (R > 255)
                R = 255;

            if (G < 0)
                G = 0;
            if (G > 255)
                G = 255;

            if (B < 0)
                B = 0;
            if (B > 255)
                B = 255;

            RGB.R = R;
            RGB.G = G;
            RGB.B = B;
        }
    },

    Hue_2_RGB : function(v1,v2,vH)
    {
        if (vH < 0.0)
            vH += 1.0;
        if (vH > 1.0)
            vH -= 1.0;
        if (vH < cd16)
            return v1 + (v2 - v1) * 6.0 * vH;
        if (vH < 0.5)
            return v2;
        if (vH < cd23)
            return v1 + (v2 - v1) * (cd23 - vH) * 6.0;
        return v1;
    },

    lclRgbCompToCrgbComp: function(value)
    {
        return (value * MAX_PERCENT / 255);
    },

    lclCrgbCompToRgbComp: function(value)
    {
        return (value * 255 / MAX_PERCENT);
    },

    lclGamma: function(nComp, fGamma)
    {
        return (Math.pow(nComp/MAX_PERCENT, fGamma)*MAX_PERCENT + 0.5) >> 0;
    },

    RgbtoCrgb: function(RGBA)
    {
        RGBA.R = this.lclGamma(this.lclRgbCompToCrgbComp(RGBA.R), DEC_GAMMA);
        RGBA.G = this.lclGamma(this.lclRgbCompToCrgbComp(RGBA.G), DEC_GAMMA);
        RGBA.B = this.lclGamma(this.lclRgbCompToCrgbComp(RGBA.B), DEC_GAMMA);
    },


    CrgbtoRgb: function(RGBA)
    {
        RGBA.R = (this.lclCrgbCompToRgbComp(this.lclGamma(RGBA.R, INC_GAMMA)) + 0.5) >> 0;
        RGBA.G = (this.lclCrgbCompToRgbComp(this.lclGamma(RGBA.G, INC_GAMMA)) + 0.5) >> 0;
        RGBA.B = (this.lclCrgbCompToRgbComp(this.lclGamma(RGBA.B, INC_GAMMA)) + 0.5) >> 0;
    },

    Apply : function(RGBA)
    {
        if (null == this.Mods)
            return;

        var _len = this.Mods.length;
        for (var i = 0; i < _len; i++)
        {
            var colorMod = this.Mods[i];
            var val = colorMod.val/100000.0;

            if (colorMod.name == "alpha")
            {
                RGBA.A = Math.min(255, Math.max(0, 255 * val + 0.5)) >> 0;
            }
            else if (colorMod.name == "blue")
            {
                RGBA.B = Math.min(255, Math.max(0, 255 * val + 0.5)) >> 0;
            }
            else if (colorMod.name == "blueMod")
            {
                RGBA.B = Math.max(0, ((RGBA.B * val) + 0.5) >> 0);
            }
            else if (colorMod.name == "blueOff")
            {
                RGBA.B = Math.max(0, ((RGBA.B + val * 255) + 0.5)) >> 0;
            }
            else if (colorMod.name == "green")
            {
                RGBA.G = Math.min(255, Math.max(0, 255 * val + 0.5)) >> 0;
            }
            else if (colorMod.name == "greenMod")
            {
                RGBA.G = Math.max(0, (RGBA.G * val  + 0.5) >> 0);
            }
            else if (colorMod.name == "greenOff")
            {
                RGBA.G = Math.max(0, (RGBA.G + val * 255  + 0.5)) >> 0;
            }
            else if (colorMod.name == "red")
            {
                RGBA.R = Math.min(255, Math.max(0, 255 * val + 0.5)) >> 0;
            }
            else if (colorMod.name == "redMod")
            {
                RGBA.R = Math.max(0, (RGBA.R * val + 0.5) >> 0);
            }
            else if (colorMod.name == "redOff")
            {
                RGBA.R = Math.max(0, (RGBA.R + val * 255 + 0.5) >> 0);
            }
            else if (colorMod.name == "hueOff")
            {
                var HSL = {H: 0, S: 0, L: 0};
                this.RGB2HSL(RGBA.R, RGBA.G, RGBA.B, HSL);

                var res = (HSL.H + (val * 10.0) / 9.0 + 0.5) >> 0;
                HSL.H = Math.min(max_hls, Math.max(0, res));

                this.HSL2RGB(HSL, RGBA);
            }
            else if (colorMod.name == "inv")
            {
                RGBA.R ^= 0xFF;
                RGBA.G ^= 0xFF;
                RGBA.B ^= 0xFF;
            }
            else if (colorMod.name == "lumMod")
            {
                var HSL = {H: 0, S: 0, L: 0};
                this.RGB2HSL(RGBA.R, RGBA.G, RGBA.B, HSL);

                if(HSL.L*val > max_hls)
                    HSL.L = max_hls;
                else
                    HSL.L = Math.max(0, (HSL.L * val + 0.5) >> 0);
                this.HSL2RGB(HSL, RGBA);
            }
            else if (colorMod.name == "lumOff")
            {
                var HSL = {H: 0, S: 0, L: 0};
                this.RGB2HSL(RGBA.R, RGBA.G, RGBA.B, HSL);

                var res = (HSL.L + val * max_hls + 0.5) >> 0;
                HSL.L = Math.min(max_hls, Math.max(0, res));

                this.HSL2RGB(HSL, RGBA);
            }
            else if (colorMod.name == "satMod")
            {
                var HSL = {H: 0, S: 0, L: 0};
                this.RGB2HSL(RGBA.R, RGBA.G, RGBA.B, HSL);

                if(HSL.S*val > max_hls)
                    HSL.S = max_hls;
                else
                    HSL.S = Math.max(0, (HSL.S * val + 0.5) >> 0);
                this.HSL2RGB(HSL, RGBA);
            }
            else if (colorMod.name == "satOff")
            {
                var HSL = {H: 0, S: 0, L: 0};
                this.RGB2HSL(RGBA.R, RGBA.G, RGBA.B, HSL);

                var res = (HSL.S + val * max_hls + 0.5) >> 0;
                HSL.S = Math.min(max_hls, Math.max(0, res));

                this.HSL2RGB(HSL, RGBA);
            }
            else if (colorMod.name == "wordShade")
            {
                var val_ = colorMod.val/255;
                //GBA.R = Math.max(0, (RGBA.R * (1 - val_)) >> 0);
                //GBA.G = Math.max(0, (RGBA.G * (1 - val_)) >> 0);
                //GBA.B = Math.max(0, (RGBA.B * (1 - val_)) >> 0);


                //RGBA.R = Math.max(0,  ((1 - val_)*(- RGBA.R) + RGBA.R) >> 0);
                //RGBA.G = Math.max(0,  ((1 - val_)*(- RGBA.G) + RGBA.G) >> 0);
                //RGBA.B = Math.max(0,  ((1 - val_)*(- RGBA.B) + RGBA.B) >> 0);

                var HSL = {H: 0, S: 0, L: 0};
                this.RGB2HSL(RGBA.R, RGBA.G, RGBA.B, HSL);

                if(HSL.L*val_ > max_hls)
                    HSL.L = max_hls;
                else
                    HSL.L = Math.max(0, (HSL.L * val_ + 0.5) >> 0);
                this.HSL2RGB(HSL, RGBA);
            }
            else if (colorMod.name == "wordTint")
            {
                var _val = colorMod.val/255;
                //RGBA.R = Math.max(0,  ((1 - _val)*(255 - RGBA.R) + RGBA.R) >> 0);
                //RGBA.G = Math.max(0,  ((1 - _val)*(255 - RGBA.G) + RGBA.G) >> 0);
                //RGBA.B = Math.max(0,  ((1 - _val)*(255 - RGBA.B) + RGBA.B) >> 0);

                var HSL = {H: 0, S: 0, L: 0};
                this.RGB2HSL(RGBA.R, RGBA.G, RGBA.B, HSL);

                var L_ = HSL.L*_val + (255 - colorMod.val);
                if(L_ > max_hls)
                    HSL.L = max_hls;
                else
                    HSL.L = Math.max(0, (L_ + 0.5) >> 0);
                this.HSL2RGB(HSL, RGBA);
            }
            else if (colorMod.name == "shade")
            {
                this.RgbtoCrgb(RGBA);
                if (val < 0) val = 0;
                if (val > 1) val = 1;
                RGBA.R = (RGBA.R * val);
                RGBA.G = (RGBA.G * val);
                RGBA.B = (RGBA.B * val);
                this.CrgbtoRgb(RGBA);
            }
            else if (colorMod.name == "tint")
            {
                this.RgbtoCrgb(RGBA);
                if (val < 0) val = 0;
                if (val > 1) val = 1;
                RGBA.R = ( MAX_PERCENT - (MAX_PERCENT - RGBA.R) * val );
                RGBA.G = ( MAX_PERCENT - (MAX_PERCENT - RGBA.G) * val );
                RGBA.B = ( MAX_PERCENT - (MAX_PERCENT - RGBA.B) * val );
                this.CrgbtoRgb(RGBA);
            }
            else if (colorMod.name == "gamma")
            {
                this.RgbtoCrgb(RGBA);
                RGBA.R = this.lclGamma(RGBA.R, INC_GAMMA);
                RGBA.G = this.lclGamma(RGBA.G, INC_GAMMA);
                RGBA.B = this.lclGamma(RGBA.B, INC_GAMMA);
                this.CrgbtoRgb(RGBA);
            }
            else if (colorMod.name == "invGamma")
            {
                this.RgbtoCrgb(RGBA);
                RGBA.R = this.lclGamma(RGBA.R, DEC_GAMMA);
                RGBA.G = this.lclGamma(RGBA.G, DEC_GAMMA);
                RGBA.B = this.lclGamma(RGBA.B, DEC_GAMMA);
                this.CrgbtoRgb(RGBA);
            }
        }
    }
};

function CSysColor()
{
    this.type = c_oAscColor.COLOR_TYPE_SYS;
    this.id = "";
    this.RGBA = {
        R: 0,
        G: 0,
        B: 0,
        A: 255,
        needRecalc: true
    };
}

CSysColor.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},


    setR: function(pr)
    {
        this.RGBA.R = pr;
    },
    setG: function(pr)
    {
        this.RGBA.G = pr;
    },
    setB: function(pr)
    {
        this.RGBA.B = pr;
    },

    check: function()
    {
        var ret = this.RGBA.needRecalc;
        this.RGBA.needRecalc = false;
        return ret;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_SysColor;
    },

    Write_ToBinary: function (w)
    {
        w.WriteLong(this.type);
        w.WriteString2(this.id);
        w.WriteLong(((this.RGBA.R << 16) & 0xFF0000) + ((this.RGBA.G << 8) & 0xFF00) + this.RGBA.B);
    },

    Read_FromBinary: function (r)
    {
        this.id = r.GetString2();

        var RGB = r.GetLong();
        this.RGBA.R = (RGB >> 16) & 0xFF;
        this.RGBA.G = (RGB >> 8) & 0xFF;
        this.RGBA.B = RGB & 0xFF;
    },

    setId: function(id)
    {
        this.id = id;
    },

    IsIdentical :  function(color)
    {
        return color && color.type == this.type && color.id == this.id;
    },
    Calculate : function(obj)
    {
    },

    createDuplicate : function()
    {
        var duplicate = new CSysColor();
        duplicate.id = this.id;
        duplicate.RGBA.R = this.RGBA.R;
        duplicate.RGBA.G = this.RGBA.G;
        duplicate.RGBA.B = this.RGBA.B;
        duplicate.RGBA.A = this.RGBA.A;
        return duplicate;
    }
};
function CPrstColor()
{
    this.type = c_oAscColor.COLOR_TYPE_PRST;
    this.id = "";
    this.RGBA = {
        R:0, G:0, B:0, A:255, needRecalc: true
    };
}

CPrstColor.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_PrstColor;
    },


    Write_ToBinary: function (w)
    {
        w.WriteLong(this.type);
        w.WriteString2(this.id);
    },

    Read_FromBinary: function (r)
    {
        this.id = r.GetString2();
    },

    setId: function(id)
    {
        this.id = id;
    },

    IsIdentical : function(color)
    {
        return color && color.type == this.type && color.id == this.id;
    },

    createDuplicate : function()
    {
        var duplicate = new CPrstColor();
        duplicate.id = this.id;
        duplicate.RGBA.R = this.RGBA.R;
        duplicate.RGBA.G = this.RGBA.G;
        duplicate.RGBA.B = this.RGBA.B;
        duplicate.RGBA.A = this.RGBA.A;
        return duplicate;
    },

    Calculate : function(obj)
    {
        var RGB = map_prst_color[this.id];
        this.RGBA.R = (RGB >> 16) & 0xFF;
        this.RGBA.G = (RGB >> 8) & 0xFF;
        this.RGBA.B = RGB & 0xFF;
    },

    check: function()
    {
        var r, g, b , rgb;
        rgb = map_prst_color[this.id];
        r = (rgb >> 16) & 0xFF;
        g = (rgb >> 8) & 0xFF;
        b = rgb & 0xFF;

        var RGBA = this.RGBA;
        if(RGBA.needRecalc)
        {
            RGBA.R = r;
            RGBA.G = g;
            RGBA.B = b;
            RGBA.needRecalc = false;
            return true;
        }
        else
        {
            if(RGBA.R === r && RGBA.G === g && RGBA.B === b)
                return false;
            else
            {
                RGBA.R = r;
                RGBA.G = g;
                RGBA.B = b;
                return true;
            }
        }
    }
};
function CRGBColor()
{
    this.type = c_oAscColor.COLOR_TYPE_SRGB;
    this.RGBA = {R:0, G:0, B:0, A:255, needRecalc: true};
}

CRGBColor.prototype =
{

    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    check: function()
    {
        var ret = this.RGBA.needRecalc;
        this.RGBA.needRecalc = false;
        return ret;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_RGBColor;
    },

    writeToBinaryLong: function(w)
    {
        w.WriteLong(((this.RGBA.R << 16) & 0xFF0000) + ((this.RGBA.G << 8) & 0xFF00) + this.RGBA.B);
    },

    readFromBinaryLong: function(r)
    {
        var RGB = r.GetLong();
        this.RGBA.R = (RGB >> 16) & 0xFF;
        this.RGBA.G = (RGB >> 8) & 0xFF;
        this.RGBA.B = RGB & 0xFF;
    },

    Write_ToBinary: function(w)
    {
        w.WriteLong(this.type);
        w.WriteLong(((this.RGBA.R << 16) & 0xFF0000) + ((this.RGBA.G << 8) & 0xFF00) + this.RGBA.B);
    },

    Read_FromBinary: function(r)
    {
        var RGB = r.GetLong();
        this.RGBA.R = (RGB >> 16) & 0xFF;
        this.RGBA.G = (RGB >> 8) & 0xFF;
        this.RGBA.B = RGB & 0xFF;
    },

    setColor: function(r, g, b)
    {
        this.RGBA.R = r;
        this.RGBA.G = g;
        this.RGBA.B = b;
    },

    IsIdentical : function(color)
    {
        return color && color.type == this.type && color.RGBA.R == this.RGBA.R && color.RGBA.G == this.RGBA.G && color.RGBA.B == this.RGBA.B && color.RGBA.A == this.RGBA.A;
    },

    createDuplicate : function()
    {
        var duplicate = new CRGBColor();
        duplicate.id = this.id;
        duplicate.RGBA.R = this.RGBA.R;
        duplicate.RGBA.G = this.RGBA.G;
        duplicate.RGBA.B = this.RGBA.B;
        duplicate.RGBA.A = this.RGBA.A;
        return duplicate;
    },

    Calculate : function(obj)
    {
    }
};

function CSchemeColor()
{
    this.type = c_oAscColor.COLOR_TYPE_SCHEME;
    this.id = 0;
    this.RGBA = {
        R:0,
        G:0,
        B:0,
        A:255,
        needRecalc: true
    };
}

CSchemeColor.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    check: function(theme, colorMap)
    {
        var RGBA, colors = theme.themeElements.clrScheme.colors;
        if (colorMap[this.id]!=null && colors[colorMap[this.id]] != null)
            RGBA =  colors[colorMap[this.id]].color.RGBA;
        else if ( colors[this.id] != null)
            RGBA = colors[this.id].color.RGBA;
        if(!RGBA)
        {
            RGBA = {R: 0, G: 0, B: 0, A: 255};
        }
        var _RGBA = this.RGBA;
        if(this.RGBA.needRecalc)
        {
            _RGBA.R = RGBA.R;
            _RGBA.G = RGBA.G;
            _RGBA.B = RGBA.B;
            _RGBA.A = RGBA.A;
            this.RGBA.needRecalc = false;
            return true;
        }
        else
        {
            if(_RGBA.R === RGBA.R && _RGBA.G === RGBA.G && _RGBA.B === RGBA.B && _RGBA.A === RGBA.A)
            {
                return false;
            }
            else
            {
                _RGBA.R = RGBA.R;
                _RGBA.G = RGBA.G;
                _RGBA.B = RGBA.B;
                _RGBA.A = RGBA.A;
                return true;
            }
        }
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_SchemeColor;
    },


    Write_ToBinary: function (w)
    {
        w.WriteLong(this.type);
        w.WriteLong(this.id);
    },

    Read_FromBinary: function (r)
    {
        this.id = r.GetLong();
    },

    setId: function(id)
    {
        this.id = id;
    },


    IsIdentical : function(color)
    {
        return color && color.type == this.type && color.id == this.id;
    },
    createDuplicate : function()
    {
        var duplicate = new CSchemeColor();
        duplicate.id = this.id;
        duplicate.RGBA.R = this.RGBA.R;
        duplicate.RGBA.G = this.RGBA.G;
        duplicate.RGBA.B = this.RGBA.B;
        duplicate.RGBA.A = this.RGBA.A;
        return duplicate;
    },

    Calculate : function(theme, slide, layout, masterSlide, RGBA, colorMap)
    {
        if(theme.themeElements.clrScheme)
        {
            if(this.id == phClr)
            {
                this.RGBA = RGBA;
            }
            else
            {
                var clrMap;
                if(colorMap && colorMap.color_map)
                {
                    clrMap = colorMap.color_map;
                }
                else if(slide!=null && slide.clrMap!=null)
                {
                    clrMap = slide.clrMap.color_map;
                }
                else if(layout!=null && layout.clrMap!=null)
                {
                    clrMap = layout.clrMap.color_map;
                }
                else if(masterSlide!=null && masterSlide.clrMap!=null)
                {
                    clrMap = masterSlide.clrMap.color_map;
                }
                else
                {
                    clrMap = AscFormat.DEFAULT_COLOR_MAP.color_map;
                }
                if (clrMap[this.id]!=null && theme.themeElements.clrScheme.colors[clrMap[this.id]] != null && theme.themeElements.clrScheme.colors[clrMap[this.id]].color != null)
                    this.RGBA = theme.themeElements.clrScheme.colors[clrMap[this.id]].color.RGBA;
                else if (theme.themeElements.clrScheme.colors[this.id] != null && theme.themeElements.clrScheme.colors[this.id].color != null)
                    this.RGBA = theme.themeElements.clrScheme.colors[this.id].color.RGBA;
            }
        }
    }
};

function CUniColor()
{
    this.color = null;
    this.Mods = null;//new CColorModifiers();
    this.RGBA = {
        R: 0,
        G: 0,
        B: 0,
        A: 255
    };
}

CUniColor.prototype =
{
    checkPhColor: function(unicolor)
    {
        if(this.color && this.color.type === c_oAscColor.COLOR_TYPE_SCHEME && this.color.id === 14)
        {
            if(unicolor)
            {
                if(unicolor.color)
                {
                    this.color = unicolor.color.createDuplicate();
                }
                if(unicolor.Mods)
                {
                    this.Mods = unicolor.Mods.createDuplicate();
                }
            }
        }
    },

    saveSourceFormatting: function()
    {
        var _ret = new CUniColor();
        _ret.color = new CRGBColor();
        _ret.color.RGBA.R = this.RGBA.R;
        _ret.color.RGBA.G = this.RGBA.G;
        _ret.color.RGBA.B = this.RGBA.B;
        return _ret;
    },

    addColorMod: function(mod)
    {
        if(!this.Mods)
        {
            this.Mods = new CColorModifiers();
        }
        this.Mods.addMod(mod.createDuplicate());
    },

    check: function(theme, colorMap)
    {
        if(this.color && this.color.check(theme, colorMap.color_map)/*возвращает был ли изменен RGBA*/)
        {
            this.RGBA.R = this.color.RGBA.R;
            this.RGBA.G = this.color.RGBA.G;
            this.RGBA.B = this.color.RGBA.B;
            if(this.Mods)
                this.Mods.Apply(this.RGBA);
        }
    },

    checkWordMods: function()
    {
        return this.Mods && this.Mods.Mods.length === 1
            && (this.Mods.Mods[0].name === "wordTint" || this.Mods.Mods[0].name === "wordShade");
    },

    convertToPPTXMods: function()
    {
        if(this.checkWordMods())
        {
            var val_, mod_;
            if(this.Mods.Mods[0].name === "wordShade")
            {
                mod_ = new CColorMod();
                mod_.setName("lumMod");
                mod_.setVal(((this.Mods.Mods[0].val/255)*100000) >> 0);
                this.Mods.Mods.splice(0, this.Mods.Mods.length);
                this.Mods.Mods.push(mod_);
            }
            else
            {
                val_ = ((this.Mods.Mods[0].val/255)*100000) >> 0;
                this.Mods.Mods.splice(0, this.Mods.Mods.length);
                mod_ = new CColorMod();
                mod_.setName("lumMod");
                mod_.setVal(val_);
                this.Mods.Mods.push(mod_);
                mod_ = new CColorMod();
                mod_.setName("lumOff");
                mod_.setVal(100000 - val_);
                this.Mods.Mods.push(mod_);
            }
        }
    },

    canConvertPPTXModsToWord: function()
    {
        return this.Mods
            && ((this.Mods.Mods.length === 1 && this.Mods.Mods[0].name === "lumMod" && this.Mods.Mods[0].val > 0)
            || (this.Mods.Mods.length === 2 && this.Mods.Mods[0].name === "lumMod" && this.Mods.Mods[0].val > 0
            &&  this.Mods.Mods[1].name === "lumOff" && this.Mods.Mods[1].val > 0));
    },

    convertToWordMods: function()
    {
        if(this.canConvertPPTXModsToWord())
        {
            var mod_ = new CColorMod();
            mod_.setName( this.Mods.Mods.length === 1 ? "wordShade" : "wordTint");
            mod_.setVal(((this.Mods.Mods[0].val*255)/100000) >> 0);
            this.Mods.Mods.splice(0, this.Mods.Mods.length);
            this.Mods.Mods.push(mod_);
        }
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_UniColor;
    },


    setColor: function(color)
    {
        this.color = color;
    },

    setMods: function(mods)
    {
        this.Mods = mods;
    },

    Write_ToBinary: function(w)
    {
        if(this.color)
        {
            w.WriteBool(true);
            this.color.Write_ToBinary(w);
        }
        else
        {
            w.WriteBool(false);
        }
        if(this.Mods)
        {
            w.WriteBool(true);
            this.Mods.Write_ToBinary(w);
        }
        else
        {
            w.WriteBool(false);
        }
    },

    Read_FromBinary: function(r)
    {
        if(r.GetBool())
        {
            var type = r.GetLong();
            switch(type)
            {
                case c_oAscColor.COLOR_TYPE_NONE:
                {
                    break;
                }
                case c_oAscColor.COLOR_TYPE_SRGB:
                {
                    this.color = new CRGBColor();
                    this.color.Read_FromBinary(r);
                    break;
                }
                case c_oAscColor.COLOR_TYPE_PRST:
                {
                    this.color = new CPrstColor();
                    this.color.Read_FromBinary(r);
                    break;
                }
                case c_oAscColor.COLOR_TYPE_SCHEME:
                {
                    this.color = new CSchemeColor();
                    this.color.Read_FromBinary(r);
                    break;
                }
                case c_oAscColor.COLOR_TYPE_SYS:
                {
                    this.color = new CSysColor();
                    this.color.Read_FromBinary(r);
                    break;
                }
            }
        }
        if(r.GetBool())
        {
            this.Mods = new CColorModifiers();
            this.Mods.Read_FromBinary(r);
        }
        else
        {
            this.Mods = null;
        }
    },

    createDuplicate : function()
    {
        var duplicate = new CUniColor();
        if(this.color!=null)
        {
            duplicate.color = this.color.createDuplicate();
        }
        if(this.Mods)
            duplicate.Mods = this.Mods.createDuplicate();

        duplicate.RGBA.R = this.RGBA.R;
        duplicate.RGBA.G = this.RGBA.G;
        duplicate.RGBA.B = this.RGBA.B;
        duplicate.RGBA.A = this.RGBA.A;
        return duplicate;
    },

    IsIdentical : function(unicolor)
    {
        if(!isRealObject(unicolor))
        {
            return false;
        }
        if(!isRealObject(unicolor.color) && isRealObject(this.color)
            || !isRealObject(this.color) && isRealObject(unicolor.color)
            || isRealObject(this.color) && !this.color.IsIdentical(unicolor.color))
        {
            return false;
        }
        if(!isRealObject(unicolor.Mods) && isRealObject(this.Mods) && this.Mods.Mods.length > 0
            || !isRealObject(this.Mods) && isRealObject(unicolor.Mods) && unicolor.Mods.Mods.length > 0
            || isRealObject(this.Mods) && !this.Mods.IsIdentical(unicolor.Mods))
        {
            return false;
        }
        return true;
    },

    Calculate : function(theme, slide, layout, masterSlide, RGBA, colorMap)
    {
        if (this.color == null)
            return this.RGBA;

        this.color.Calculate(theme, slide, layout, masterSlide, RGBA, colorMap);

        this.RGBA = {R:this.color.RGBA.R, G:this.color.RGBA.G, B: this.color.RGBA.B, A: this.color.RGBA.A};
        if(this.Mods)
            this.Mods.Apply(this.RGBA);
    },

    compare : function(unicolor)
    {
        if(unicolor == null)
        {
            return null;
        }
        var _ret = new CUniColor();
        if(this.color == null || unicolor.color == null ||
            this.color.type !== unicolor.color.type)
        {
            return _ret;
        }

        if(this.Mods && unicolor.Mods)
        {
            var aMods = this.Mods.Mods;
            var aMods2 = unicolor.Mods.Mods;
            if(aMods.length === aMods2.length)
            {
                for (var i = 0; i < aMods.length; ++i)
                {
                    if(aMods2[i].name !== aMods[i].name || aMods2[i].val !== aMods[i].val)
                    {
                        break;
                    }
                }
                if(i === aMods.length)
                {
                    _ret.Mods = this.Mods.createDuplicate();
                }
            }
        }
        switch(this.color.type)
        {
            case c_oAscColor.COLOR_TYPE_NONE:
            {
                break;
            }
            case c_oAscColor.COLOR_TYPE_PRST:
            {
                _ret.color = new CPrstColor();
                if(unicolor.color.id == this.color.id)
                {
                    _ret.color.id = this.color.id;
                    _ret.color.RGBA.R = this.color.RGBA.R;
                    _ret.color.RGBA.G = this.color.RGBA.G;
                    _ret.color.RGBA.B = this.color.RGBA.B;
                    _ret.color.RGBA.A = this.color.RGBA.A;
                    _ret.RGBA.R  = this.RGBA.R;
                    _ret.RGBA.G  = this.RGBA.G;
                    _ret.RGBA.B  = this.RGBA.B;
                    _ret.RGBA.A  = this.RGBA.A;
                }
                break;
            }
            case c_oAscColor.COLOR_TYPE_SCHEME:
            {
                _ret.color = new CSchemeColor();
                if(unicolor.color.id == this.color.id)
                {
                    _ret.color.id = this.color.id;
                    _ret.color.RGBA.R = this.color.RGBA.R;
                    _ret.color.RGBA.G = this.color.RGBA.G;
                    _ret.color.RGBA.B = this.color.RGBA.B;
                    _ret.color.RGBA.A = this.color.RGBA.A;
                    _ret.RGBA.R  = this.RGBA.R;
                    _ret.RGBA.G  = this.RGBA.G;
                    _ret.RGBA.B  = this.RGBA.B;
                    _ret.RGBA.A  = this.RGBA.A;
                }
                break;
            }
            case c_oAscColor.COLOR_TYPE_SRGB:
            {
                _ret.color = new CRGBColor();
                var _RGBA1 = this.color.RGBA;
                var _RGBA2 = this.color.RGBA;
                if(_RGBA1.R === _RGBA2.R
                    && _RGBA1.G === _RGBA2.G
                    && _RGBA1.B === _RGBA2.B)
                {
                    _ret.color.RGBA.R = this.color.RGBA.R;
                    _ret.color.RGBA.G = this.color.RGBA.G;
                    _ret.color.RGBA.B = this.color.RGBA.B;
                    _ret.RGBA.R  = this.RGBA.R;
                    _ret.RGBA.G  = this.RGBA.G;
                    _ret.RGBA.B  = this.RGBA.B;
                }
                if(_RGBA1.A === _RGBA2.A)
                {
                    _ret.color.RGBA.A = this.color.RGBA.A;
                }

                break;
            }
            case c_oAscColor.COLOR_TYPE_SYS:
            {
                _ret.color = new CSysColor();
                if(unicolor.color.id == this.color.id)
                {
                    _ret.color.id = this.color.id;
                    _ret.color.RGBA.R = this.color.RGBA.R;
                    _ret.color.RGBA.G = this.color.RGBA.G;
                    _ret.color.RGBA.B = this.color.RGBA.B;
                    _ret.color.RGBA.A = this.color.RGBA.A;
                    _ret.RGBA.R  = this.RGBA.R;
                    _ret.RGBA.G  = this.RGBA.G;
                    _ret.RGBA.B  = this.RGBA.B;
                    _ret.RGBA.A  = this.RGBA.A;
                }
                break;
            }
        }
        return _ret;
    },

    getCSSColor : function(transparent)
    {
        if (transparent != null)
        {
            var _css = "rgba(" + this.RGBA.R + "," + this.RGBA.G + "," + this.RGBA.B + ",1)";
            return _css;
        }
        var _css = "rgba(" + this.RGBA.R + "," + this.RGBA.G + "," + this.RGBA.B + "," + (this.RGBA.A / 255) + ")";
        return _css;
    }
};

function CreateUniColorRGB(r, g, b)
{
    var ret = new CUniColor();
    ret.setColor(new CRGBColor());
    ret.color.setColor(r, g, b);
    return ret;
}

function CreteSolidFillRGB(r, g, b)
{
    var ret = new CUniFill();
    ret.setFill(new CSolidFill());
    ret.fill.setColor(new CUniColor());
    var _uni_color = ret.fill.color;
    _uni_color.setColor(new CRGBColor());
    _uni_color.color.setColor(r, g, b);
    return ret;
}

function CreateSolidFillRGBA(r, g, b, a)
{
    var ret = new CUniFill();
    ret.setFill(new CSolidFill());
    ret.fill.setColor(new CUniColor());
    var _uni_color = ret.fill.color;
    _uni_color.setColor(new CRGBColor());
    _uni_color.color.setColor(r, g, b);
	_uni_color.RGBA.R = r;
	_uni_color.RGBA.G = g;
	_uni_color.RGBA.B = b;
	_uni_color.RGBA.A = a;
    return ret;
}

// -----------------------------

function CSrcRect()
{
    this.l = null;
    this.t = null;
    this.r = null;
    this.b = null;
}

CSrcRect.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_SrcRect;
    },

    setLTRB: function(l, t, r, b)
    {
        this.l = l;
        this.t = t;
        this.r = r;
        this.b = b;
    },


    Write_ToBinary: function (w)
    {
        writeDouble(w, this.l);
        writeDouble(w, this.t);
        writeDouble(w, this.r);
        writeDouble(w, this.b);
    },

    Read_FromBinary: function (r)
    {
        this.l = readDouble(r);
        this.t = readDouble(r);
        this.r = readDouble(r);
        this.b = readDouble(r);
    },
    createDublicate : function()
    {
        var _ret = new CSrcRect();
        _ret.l = this.l;
        _ret.t = this.t;
        _ret.r = this.r;
        _ret.b = this.b;
        return _ret;
    }
};

function CBlipFillTile()
{
    this.tx = null;
    this.ty = null;
    this.sx = null;
    this.sy = null;
    this.flip = null;
    this.algn = null;
}
CBlipFillTile.prototype.Write_ToBinary = function(w)
{
    writeLong(w, this.tx);
    writeLong(w, this.ty);
    writeLong(w, this.sx);
    writeLong(w, this.sy);
    writeLong(w, this.flip);
    writeLong(w, this.algn);
};
CBlipFillTile.prototype.Read_FromBinary = function(r)
{
    this.tx = readLong(r);
    this.ty = readLong(r);
    this.sx = readLong(r);
    this.sy = readLong(r);
    this.flip = readLong(r);
    this.algn = readLong(r);
};
CBlipFillTile.prototype.createDuplicate = function()
{
    var ret = new CBlipFillTile();
    ret.tx = this.tx;
    ret.ty = this.ty;
    ret.sx = this.sx;
    ret.sy = this.sy;
    ret.flip = this.flip;
    ret.algn = this.algn;
    return ret;
};
CBlipFillTile.prototype.IsIdentical = function(o)
{
    if(!o)
    {
        return false;
    }
    return (  o.tx == this.tx &&
        o.ty == this.ty &&
    o.sx == this.sx &&
    o.sy == this.sy &&
    o.flip == this.flip &&
    o.algn == this.algn)
};
function CBlipFill()
{
    this.type = c_oAscFill.FILL_TYPE_BLIP;

    this.RasterImageId = "";

    this.srcRect = null;

    this.stretch = null;
    this.tile = null;

    this.rotWithShape = null;
}

CBlipFill.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    saveSourceFormatting: function()
    {
        return this.createDuplicate();
    },

    Write_ToBinary: function(w)
    {
        writeString(w, this.RasterImageId);
        if(this.srcRect)
        {
            writeBool(w, true);
            writeDouble(w, this.srcRect.l);
            writeDouble(w, this.srcRect.t);
            writeDouble(w, this.srcRect.r);
            writeDouble(w, this.srcRect.b);
        }
        else
        {
            writeBool(w, false);
        }
        writeBool(w, this.stretch);
        if(isRealObject(this.tile))
        {
            w.WriteBool(true);
            this.tile.Write_ToBinary(w);
        }
        else
        {
            w.WriteBool(false);
        }
        writeBool(w, this.rotWithShape);
    },

    Read_FromBinary: function(r)
    {
        this.RasterImageId = readString(r);

        var _correct_id = AscCommon.getImageFromChanges(this.RasterImageId);
        if (null != _correct_id)
            this.RasterImageId = _correct_id;

        //var srcUrl = readString(r);
        //if(srcUrl) {
        //    AscCommon.g_oDocumentUrls.addImageUrl(this.RasterImageId, srcUrl);
        //}

        if(readBool(r))
        {

            this.srcRect = new CSrcRect();
            this.srcRect.l = readDouble(r);
            this.srcRect.t = readDouble(r);
            this.srcRect.r = readDouble(r);
            this.srcRect.b = readDouble(r);
        }
        else
        {
            this.srcRect = null;
        }
        this.stretch      = readBool(r);
        if(r.GetBool())
        {
            this.tile = new CBlipFillTile();
            this.tile.Read_FromBinary(r);
        }
        else
        {
            this.tile = null;
        }
        this.rotWithShape = readBool(r);
    },


    Refresh_RecalcData: function()
    {},


    check: function()
    {},

    checkWordMods: function()
    {
        return false;
    },

    convertToPPTXMods: function()
    {
    },

    canConvertPPTXModsToWord: function()
    {
        return false;
    },

    convertToWordMods: function()
    {
    },


    getObjectType: function()
    {
        return AscDFH.historyitem_type_BlipFill;
    },

    setRasterImageId: function(rasterImageId)
    {
        this.RasterImageId = checkRasterImageId(rasterImageId);
    },


    setSrcRect: function(srcRect)
    {
        this.srcRect = srcRect;
    },

    setStretch: function(stretch)
    {
        this.stretch = stretch;
    },

    setTile: function(tile)
    {
        this.tile = tile;
    },

    setRotWithShape: function(rotWithShape)
    {
        this.rotWithShape = rotWithShape;
    },


    createDuplicate : function()
    {
        var duplicate = new CBlipFill();
        duplicate.RasterImageId = this.RasterImageId;

        duplicate.stretch = this.stretch;
        if(isRealObject(this.tile))
        {
            duplicate.tile = this.tile.createDuplicate();
        }

        if (null != this.srcRect)
            duplicate.srcRect = this.srcRect.createDublicate();

        duplicate.rotWithShape = this.rotWithShape;
        return duplicate;
    },

    IsIdentical : function(fill)
    {
        if(fill == null)
        {
            return false;
        }
        if(fill.type !=  c_oAscFill.FILL_TYPE_BLIP)
        {
            return false;
        }

        if(fill.RasterImageId !=  this.RasterImageId)
        {
            return false;
        }

        /*if(fill.VectorImageBin !=  this.VectorImageBin)
         {
         return false;
         }    */

        if(fill.stretch !=  this.stretch)
        {
            return false;
        }

        if(isRealObject(this.tile))
        {
            if(!this.tile.IsIdentical(fill.tile))
            {
                return false;
            }
        }
        else
        {
            if(fill.tile)
            {
                return false;
            }
        }
        /*
         if(fill.rotWithShape !=  this.rotWithShape)
         {
         return false;
         }
         */
        return true;

    },

    compare : function(fill)
    {
        if(fill == null || fill.type !== c_oAscFill.FILL_TYPE_BLIP)
        {
            return null;
        }
        var _ret = new CBlipFill();
        if(this.RasterImageId == fill.RasterImageId)
        {
            _ret.RasterImageId = this.RasterImageId;
        }
        if(fill.stretch == this.stretch)
        {
            _ret.stretch = this.stretch;
        }
        if(isRealObject(fill.tile))
        {
            if(fill.tile.IsIdentical(this.tile))
            {
                _ret.tile = this.tile.createDuplicate();
            }
            else
            {
                _ret.tile = new CBlipFillTile();
            }
        }
        if(fill.rotWithShape === this.rotWithShape)
        {
            _ret.rotWithShape = this.rotWithShape;
        }
        return _ret;
    }
};

function CSolidFill()
{
    this.type = c_oAscFill.FILL_TYPE_SOLID;
    this.color = null;
}

CSolidFill.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},


    check: function(theme, colorMap)
    {
        if(this.color)
        {
            this.color.check(theme, colorMap);
        }
    },

    saveSourceFormatting: function()
    {
        var _ret = new CSolidFill();
        if(this.color){
            _ret.color = this.color.saveSourceFormatting();
        }
        return _ret;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_SolidFill;
    },

    setColor: function(color)
    {
        this.color = color;
    },

    Write_ToBinary: function(w)
    {
        if(this.color)
        {
            w.WriteBool(true);
            this.color.Write_ToBinary(w);
        }
        else
        {
            w.WriteBool(false);
        }
    },

    Read_FromBinary: function(r)
    {
        if(r.GetBool())
        {
            this.color = new CUniColor();
            this.color.Read_FromBinary(r);
        }
    },


    checkWordMods: function()
    {
        return this.color && this.color.checkWordMods();
    },

    convertToPPTXMods: function()
    {
        this.color && this.color.convertToPPTXMods();
    },

    canConvertPPTXModsToWord: function()
    {
        return this.color && this.color.canConvertPPTXModsToWord();
    },

    convertToWordMods: function()
    {
        this.color && this.color.convertToWordMods();
    },

    IsIdentical : function(fill)
    {
        if(fill == null)
        {
            return false;
        }
        if(fill.type !=  c_oAscFill.FILL_TYPE_SOLID)
        {
            return false;
        }

        return this.color.IsIdentical(fill.color);

    },

    createDuplicate : function()
    {
        var duplicate = new CSolidFill();
        if(this.color)
        {
            duplicate.color = this.color.createDuplicate();
        }
        return duplicate;
    },

    compare : function(fill)
    {
        if(fill == null || fill.type !== c_oAscFill.FILL_TYPE_SOLID)
        {
            return null;
        }
        var _ret = new CSolidFill();
        _ret.color = this.color.compare(fill.color);
        return _ret;
    }
};

function CGs()
{
    this.color = null;
    this.pos = 0;
}

CGs.prototype =
{

    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_Gs;
    },

    setColor: function(color)
    {
        this.color = color;
    },

    setPos: function(pos)
    {
        this.pos = pos;
    },

    saveSourceFormatting: function()
    {
        var _ret = new CGs();
        _ret.pos = this.pos;
        if(this.color){
            _ret.color = this.color.saveSourceFormatting();
        }
        return _ret;
    },

    Write_ToBinary: function(w)
    {
        w.WriteBool(isRealObject(this.color));
        if(isRealObject(this.color))
        {
            this.color.Write_ToBinary(w);
        }
        writeLong(w, this.pos);
    },

    Read_FromBinary: function(r)
    {
        if(r.GetBool())
        {
            this.color = new CUniColor();
            this.color.Read_FromBinary(r);
        }
        else
        {
            this.color = null;
        }
        this.pos = readLong(r);
    },

    IsIdentical : function(fill)
    {
        if(!fill)
            return false;
        if(this.pos !== fill.pos)
            return false;

        if(!this.color && fill.color || this.color && !fill.color || (this.color && fill.color && !this.color.IsIdentical(fill.color)))
            return false;
        return true;
    },

    createDuplicate : function()
    {
        var duplicate = new CGs();
        duplicate.pos = this.pos;
        if(this.color)
        {
            duplicate.color = this.color.createDuplicate();
        }
        return duplicate;
    },

    compare: function(gs)
    {
        if( gs.pos !== this.pos){
            return null;
        }
        var compare_unicolor = this.color.compare(gs.color);
        if(!isRealObject(compare_unicolor))
        {
            return null;
        }
        var ret = new CGs();
        ret.color = compare_unicolor;
        ret.pos = gs.pos === this.pos ? this.pos : 0;
        return ret;
    }
};

function GradLin()
{
    this.angle = 5400000;
    this.scale = true;
}
GradLin.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function()
    {},
    getObjectType: function()
    {
        return AscDFH.historyitem_type_GradLin;
    },

    setAngle: function(angle)
    {
        this.angle = angle;
    },

    setScale: function(scale)
    {
        this.scale = scale;
    },

    Write_ToBinary: function(w)
    {
        writeLong(w, this.angle);
        writeBool(w, this.scale);
    },

    Read_FromBinary: function(r)
    {
        this.angle = readLong(r);
        this.scale = readBool(r);
    },

    IsIdentical : function(lin)
    {
        if (this.angle != lin.angle)
            return false;
        if (this.scale != lin.scale)
            return false;

        return true;
    },

    createDuplicate : function()
    {
        var duplicate = new GradLin();
        duplicate.angle = this.angle;
        duplicate.scale = this.scale;
        return duplicate;
    },

    compare : function(lin)
    {
        return null;
    }
};

function GradPath()
{
    this.path = 0;
    this.rect = null;
}
GradPath.prototype =
{

    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},
    getObjectType: function()
    {
        return AscDFH.historyitem_type_GradPath;
    },

    setPath: function(path)
    {
        this.path = path;
    },

    setRect: function(rect)
    {
        this.rect = rect;
    },


    Write_ToBinary: function(w)
    {
        writeLong(w, this.path);
        w.WriteBool(isRealObject(this.rect));
        if(isRealObject(this.rect))
        {
            this.rect.Write_ToBinary(w);
        }
    },

    Read_FromBinary: function(r)
    {
        this.path = readLong(r);
        if(r.GetBool())
        {
            this.rect = new CSrcRect();
            this.rect.Read_FromBinary(r);
        }
    },


    IsIdentical : function(path)
    {
        if (this.path != path.path)
            return false;
        return true;
    },

    createDuplicate : function()
    {
        var duplicate = new GradPath();
        duplicate.path = this.path;
        return duplicate;
    },

    compare : function(path)
    {
        return null;
    }
};

function CGradFill()
{
    this.type = c_oAscFill.FILL_TYPE_GRAD;
    // пока просто front color
    this.colors = [];

    this.lin = null;
    this.path = null;

    this.rotateWithShape = null;
}

CGradFill.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    saveSourceFormatting: function()
    {
        var _ret = new CGradFill();
        if(this.lin){
            _ret.lin = this.lin.createDuplicate();
        }
        if(this.path){
            _ret.path = this.path.createDuplicate();
        }
        for(var i = 0; i < this.colors.length; ++i){
            _ret.colors.push(this.colors[i].saveSourceFormatting());
        }
        return _ret;
    },

    check: function(theme, colorMap)
    {
        for(var i = 0; i < this.colors.length; ++i)
        {
            if(this.colors[i].color)
            {
                this.colors[i].color.check(theme, colorMap);
            }
        }
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_GradFill;
    },

    checkWordMods: function()
    {
        for(var i = 0; i < this.colors.length; ++i)
        {
            if(this.colors[i] && this.colors[i].color && this.colors[i].color.checkWordMods())
            {
                return true;
            }
        }
        return false;
    },

    convertToPPTXMods: function()
    {
        for(var i = 0; i < this.colors.length; ++i)
        {
            this.colors[i] && this.colors[i].color && this.colors[i].color.convertToPPTXMods();

        }
    },

    canConvertPPTXModsToWord: function()
    {
        for(var i = 0; i < this.colors.length; ++i)
        {
            if(this.colors[i] && this.colors[i].color && this.colors[i].color.canConvertPPTXModsToWord())
            {
                return true;
            }
        }
        return false;
    },

    convertToWordMods: function()
    {
        for(var i = 0; i < this.colors.length; ++i)
        {
            this.colors[i] && this.colors[i].color && this.colors[i].color.convertToWordMods();

        }
    },


    addColor: function(color)
    {
        this.colors.push(color);
    },

    setLin: function(lin)
    {
        this.lin = lin;
    },

    setPath: function(path)
    {
        this.path = path;
    },

    Write_ToBinary: function (w)
    {
        w.WriteLong(this.colors.length);
        for(var i = 0; i < this.colors.length; ++i)
        {
            this.colors[i].Write_ToBinary(w) ;
        }
        w.WriteBool(isRealObject(this.lin));
        if(isRealObject(this.lin))
        {
            this.lin.Write_ToBinary(w);
        }
        w.WriteBool(isRealObject(this.path));
        if(isRealObject(this.path))
        {
            this.path.Write_ToBinary(w);
        }
    },

    Read_FromBinary: function (r)
    {
        var len = r.GetLong();
        for(var i = 0; i < len; ++i)
        {
            this.colors[i] = new CGs();
            this.colors[i].Read_FromBinary(r);
        }
        if(r.GetBool())
        {
            this.lin = new GradLin();
            this.lin.Read_FromBinary(r);
        }
        else
        {
            this.lin = null;
        }
        if(r.GetBool())
        {
            this.path = new GradPath();
            this.path.Read_FromBinary(r);
        }
        else
        {
            this.path = null;
        }
    },

    IsIdentical : function(fill)
    {
        if(fill == null)
        {
            return false;
        }
        if(fill.type !=  c_oAscFill.FILL_TYPE_GRAD)
        {
            return false;
        }
        if(fill.colors.length!= this.colors.length)
        {
            return false;
        }
        for(var i = 0; i < this.colors.length; ++i)
        {
            if(!this.colors[i].IsIdentical(fill.colors[i]))
            {
                return false;
            }
        }

        if(!this.path && fill.path || this.path && !fill.path || (this.path && fill.path && !this.path.IsIdentical(fill.path)))
            return false;

        if(!this.lin && fill.lin || !fill.lin && this.lin || (this.lin && fill.lin && !this.lin.IsIdentical(fill.lin)))
            return false;

        return true;
    },

    createDuplicate : function()
    {
        var duplicate = new CGradFill();
        for(var i=0; i<this.colors.length; ++i)
        {
            duplicate.colors[i] = this.colors[i].createDuplicate();
        }

        if (this.lin)
            duplicate.lin = this.lin.createDuplicate();

        if (this.path)
            duplicate.path = this.path.createDuplicate();

        if (this.rotateWithShape != null)
            duplicate.rotateWithShape = this.rotateWithShape;

        return duplicate;
    },

    compare : function(fill)
    {
        if(fill == null || fill.type !== c_oAscFill.FILL_TYPE_GRAD)
        {
            return null;
        }
        var _ret  = new CGradFill();
        if(this.lin == null || fill.lin == null)
            _ret.lin = null;
        else
        {
            _ret.lin = new GradLin();
            _ret.lin.angle = this.lin && this.lin.angle === fill.lin.angle ? fill.lin.angle : 5400000;
            _ret.lin.scale = this.lin && this.lin.scale === fill.lin.scale ? fill.lin.scale : true;
        }
        if(this.path == null || fill.path == null)
        {
            _ret.path = null;
        }
        else
        {
            _ret.path = new GradPath();
        }

        if(this.colors.length === fill.colors.length )
        {
            for(var i = 0;  i < this.colors.length; ++i )
            {
                var compare_unicolor = this.colors[i].compare(fill.colors[i]);
                if(!isRealObject(compare_unicolor))
                {
                    return null;
                }
                _ret.colors[i] = compare_unicolor;
            }
        }
        return _ret;
    }
};

function CPattFill()
{
    this.type = c_oAscFill.FILL_TYPE_PATT;
    this.ftype = 0;
    this.fgClr = null;//new CUniColor();
    this.bgClr = null;//new CUniColor();
}

CPattFill.prototype =
{
    getObjectType: function()
    {
        return AscDFH.historyitem_type_PathFill;
    },

    check: function(theme, colorMap)
    {
        if(this.fgClr)
            this.fgClr.check(theme, colorMap);
        if(this.bgClr)
            this.bgClr.check(theme, colorMap);
    },

    checkWordMods: function()
    {
        if(this.fgClr && this.fgClr.checkWordMods())
        {
            return true;
        }
        return this.bgClr && this.bgClr.checkWordMods();

    },

    saveSourceFormatting: function()
    {
        var _ret = new CPattFill();
        if(this.fgClr){
            _ret.fgClr = this.fgClr.saveSourceFormatting();
        }
        if(this.bgClr){
            _ret.bgClr = this.bgClr.saveSourceFormatting();
        }
        _ret.ftype = this.ftype;
        return _ret;
    },

    convertToPPTXMods: function()
    {
        this.fgClr && this.fgClr.convertToPPTXMods();
        this.bgClr && this.bgClr.convertToPPTXMods();
    },

    canConvertPPTXModsToWord: function()
    {
        if(this.fgClr && this.fgClr.canConvertPPTXModsToWord())
        {
            return true;
        }
        return this.bgClr && this.bgClr.canConvertPPTXModsToWord();
    },

    convertToWordMods: function()
    {

        this.fgClr && this.fgClr.convertToWordMods();
        this.bgClr && this.bgClr.convertToWordMods();
    },

    setFType: function(fType)
    {
        this.ftype = fType;
    },

    setFgColor: function(fgClr)
    {
        this.fgClr = fgClr;
    },

    setBgColor: function(bgClr)
    {
        this.bgClr = bgClr;
    },


    Write_ToBinary: function(w)
    {
        writeLong(w, this.ftype);
        w.WriteBool(isRealObject(this.fgClr));
        if(isRealObject(this.fgClr))
        {
            this.fgClr.Write_ToBinary(w);
        }
        w.WriteBool(isRealObject(this.bgClr));
        if(isRealObject(this.bgClr))
        {
            this.bgClr.Write_ToBinary(w);
        }
    },

    Read_FromBinary: function(r)
    {
        this.ftype = readLong(r);
        if(r.GetBool())
        {
            this.fgClr = new CUniColor();
            this.fgClr.Read_FromBinary(r);
        }
        if(r.GetBool())
        {
            this.bgClr = new CUniColor();
            this.bgClr.Read_FromBinary(r);
        }
    },


    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    IsIdentical : function(fill)
    {
        if(fill == null)
        {
            return false;
        }
        if(fill.type !=  c_oAscFill.FILL_TYPE_PATT && this.ftype!=fill.ftype)
        {
            return false;
        }

        return this.fgClr.IsIdentical(fill.fgClr) && this.bgClr.IsIdentical(fill.bgClr) &&  this.ftype === fill.ftype;
    },

    createDuplicate : function()
    {
        var duplicate = new CPattFill();
        duplicate.ftype = this.ftype;
        if(this.fgClr)
        {
            duplicate.fgClr = this.fgClr.createDuplicate();
        }
        if(this.bgClr)
        {
            duplicate.bgClr = this.bgClr.createDuplicate();
        }
        return duplicate;
    },
    compare : function(fill)
    {
        if(fill == null)
        {
            return null;
        }
        if(fill.type !== c_oAscFill.FILL_TYPE_PATT)
        {
            return null;
        }
        var _ret = new CPattFill();
        if(fill.ftype == this.ftype)
        {
            _ret.ftype = this.ftype;
        }
        _ret.fgClr = this.fgClr.compare(fill.fgClr);
        _ret.bgClr = this.bgClr.compare(fill.bgClr);
        return _ret;
    }
};

function CNoFill()
{
    this.type = c_oAscFill.FILL_TYPE_NOFILL;
}

CNoFill.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    check: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_NoFill;
    },


    saveSourceFormatting: function()
    {
        return this.createDuplicate();
    },

    Write_ToBinary: function(w)
    {

    },

    Read_FromBinary: function(r)
    {
    },


    checkWordMods: function()
    {
        return false;

    },

    convertToPPTXMods: function()
    {
    },

    canConvertPPTXModsToWord: function()
    {
        return false;
    },

    convertToWordMods: function()
    {
    },

    createDuplicate : function()
    {
        return new CNoFill();
    },

    IsIdentical : function(fill)
    {
        if(fill == null)
        {
            return false;
        }
        return fill.type ===  c_oAscFill.FILL_TYPE_NOFILL;
    },
    compare : function(nofill)
    {
        if(nofill == null)
        {
            return null;
        }
        if(nofill.type === this.type)
        {
            return new CNoFill();
        }
        return null;
    }
};

function CGrpFill()
{
    this.type = c_oAscFill.FILL_TYPE_GRP;
}

CGrpFill.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    check: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_GrpFill;
    },



    Write_ToBinary: function(w)
    {
    },

    Read_FromBinary: function(r)
    {
    },


    checkWordMods: function()
    {
        return false;

    },

    convertToPPTXMods: function()
    {
    },

    canConvertPPTXModsToWord: function()
    {
        return false;
    },

    convertToWordMods: function()
    {
    },

    createDuplicate : function()
    {
        return new CGrpFill();
    },

    IsIdentical : function(fill)
    {
        if(fill == null)
        {
            return false;
        }
        return fill.type ===  c_oAscFill.FILL_TYPE_GRP;
    },
    compare : function(grpfill)
    {
        if(grpfill == null)
        {
            return null;
        }
        if(grpfill.type === this.type)
        {
            return new CGrpFill();
        }
        return null;
    }
};


function CreateBlackRGBUnifill()
{
    var ret = new CUniFill();
    ret.setFill(new CSolidFill());
    ret.fill.setColor(new CUniColor());
    ret.fill.color.setColor(new CRGBColor());
    ret.fill.color.color.setColor(0, 0, 0);
    return ret;
}

function FormatRGBAColor()
{
    this.R = 0;
    this.G = 0;
    this.B = 0;
    this.A = 255;
}

function CUniFill()
{
    this.fill = null;
    this.transparent = null;
}

CUniFill.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    check: function(theme, colorMap)
    {
        if(this.fill)
        {
            this.fill.check(theme, colorMap);
        }
    },


    addColorMod: function(mod)
    {
        if(this.fill)
        {
            switch(this.fill.type)
            {
                case c_oAscFill.FILL_TYPE_NONE:
                case c_oAscFill.FILL_TYPE_BLIP:
                case c_oAscFill.FILL_TYPE_NOFILL:
                case c_oAscFill.FILL_TYPE_GRP:
                {
                    break;
                }
                case c_oAscFill.FILL_TYPE_SOLID:
                {
                    if(this.fill.color && this.fill.color)
                    {
                        this.fill.color.addColorMod(mod);
                    }
                    break;
                }
                case c_oAscFill.FILL_TYPE_GRAD:
                {
                    for(var i = 0; i < this.fill.colors.length; ++i)
                    {
                        if(this.fill.colors[i] && this.fill.colors[i].color)
                        {
                            this.fill.colors[i].color.addColorMod(mod);
                        }
                    }
                    break;
                }
                case c_oAscFill.FILL_TYPE_PATT:
                {
                    if(this.fill.bgClr)
                    {
                        this.fill.bgClr.addColorMod(mod);
                    }
                    if(this.fill.fgClr)
                    {
                        this.fill.fgClr.addColorMod(mod);
                    }
                    break;
                }
            }
        }
    },

    checkPhColor: function(unicolor)
    {
        if(this.fill)
        {
            switch(this.fill.type)
            {
                case c_oAscFill.FILL_TYPE_NONE:
                case c_oAscFill.FILL_TYPE_BLIP:
                case c_oAscFill.FILL_TYPE_NOFILL:
                case c_oAscFill.FILL_TYPE_GRP:
                {
                    break;
                }
                case c_oAscFill.FILL_TYPE_SOLID:
                {
                    if(this.fill.color && this.fill.color)
                    {
                        this.fill.color.checkPhColor(unicolor);
                    }
                    break;
                }
                case c_oAscFill.FILL_TYPE_GRAD:
                {
                    for(var i = 0; i < this.fill.colors.length; ++i)
                    {
                        if(this.fill.colors[i] && this.fill.colors[i].color)
                        {
                            this.fill.colors[i].color.checkPhColor(unicolor);
                        }
                    }
                    break;
                }
                case c_oAscFill.FILL_TYPE_PATT:
                {
                    if(this.fill.bgClr)
                    {
                        this.fill.bgClr.checkPhColor(unicolor);
                    }
                    if(this.fill.fgClr)
                    {
                        this.fill.fgClr.checkPhColor(unicolor);
                    }
                    break;
                }
            }
        }
    },

    checkWordMods: function()
    {
        return this.fill && this.fill.checkWordMods();
    },

    convertToPPTXMods: function()
    {
        this.fill && this.fill.convertToPPTXMods();
    },

    canConvertPPTXModsToWord: function()
    {
        return this.fill && this.fill.canConvertPPTXModsToWord();
    },

    convertToWordMods: function()
    {
        this.fill && this.fill.convertToWordMods();
    },


    getObjectType: function()
    {
        return AscDFH.historyitem_type_UniFill;
    },

    setFill: function(fill)
    {
        this.fill = fill;
    },

    setTransparent: function(transparent)
    {
        this.transparent = transparent;
    },

    Set_FromObject: function(o)
    {
        //TODO:
    },


    Write_ToBinary: function(w)
    {
        writeDouble(w, this.transparent);
        w.WriteBool(isRealObject(this.fill));

        if(isRealObject(this.fill)){
            w.WriteLong(this.fill.type);
            this.fill.Write_ToBinary(w);
        }

    },

    Read_FromBinary: function(r)
    {
        this.transparent = readDouble(r);
        if(r.GetBool())
        {
            var type = r.GetLong();
            switch(type)
            {
                case c_oAscFill.FILL_TYPE_NONE:
                {
                    break;
                }
                case c_oAscFill.FILL_TYPE_BLIP:
                {
                    this.fill = new CBlipFill();
                    this.fill.Read_FromBinary(r);
                    break;
                }
                case c_oAscFill.FILL_TYPE_NOFILL:
                {
                    this.fill = new CNoFill();
                    this.fill.Read_FromBinary(r);
                    break;
                }
                case c_oAscFill.FILL_TYPE_SOLID:
                {
                    this.fill = new CSolidFill();
                    this.fill.Read_FromBinary(r);
                    break;
                }
                case c_oAscFill.FILL_TYPE_GRAD:
                {
                    this.fill = new CGradFill();
                    this.fill.Read_FromBinary(r);
                    break;
                }
                case c_oAscFill.FILL_TYPE_PATT:
                {
                    this.fill = new CPattFill();
                    this.fill.Read_FromBinary(r);
                    break;
                }
                case c_oAscFill.FILL_TYPE_GRP:
                {
                    this.fill = new CGrpFill();
                    this.fill.Read_FromBinary(r);
                    break;
                }
            }
        }
    },



    calculate : function(theme, slide, layout, masterSlide, RGBA, colorMap)
    {
        if(this.fill )
        {
            if(this.fill.color)
            {
                this.fill.color.Calculate(theme, slide, layout, masterSlide, RGBA, colorMap);
            }
            if(this.fill.colors)
            {
                for(var i  = 0; i <this.fill.colors.length; ++i )
                {
                    this.fill.colors[i].color.Calculate(theme, slide, layout, masterSlide, RGBA, colorMap);
                }
            }
            if (this.fill.fgClr)
                this.fill.fgClr.Calculate(theme, slide, layout, masterSlide, RGBA, colorMap);
            if (this.fill.bgClr)
                this.fill.bgClr.Calculate(theme, slide, layout, masterSlide, RGBA, colorMap);
        }
    },

    getRGBAColor : function()
    {
        if (this.fill)
        {
            if (this.fill.type == c_oAscFill.FILL_TYPE_SOLID)
            {
                if(this.fill.color)
                {
                    return this.fill.color.RGBA;
                }
                else
                {
                    return new FormatRGBAColor();
                }
            }
            if (this.fill.type == c_oAscFill.FILL_TYPE_GRAD)
            {
                var RGBA = new FormatRGBAColor();
                var _colors = this.fill.colors;
                var _len = _colors.length;

                if (0 == _len)
                    return RGBA;

                for (var i = 0; i < _len; i++)
                {
                    RGBA.R += _colors[i].color.RGBA.R;
                    RGBA.G += _colors[i].color.RGBA.G;
                    RGBA.B += _colors[i].color.RGBA.B;
                }

                RGBA.R = (RGBA.R / _len) >> 0;
                RGBA.G = (RGBA.G / _len) >> 0;
                RGBA.B = (RGBA.B / _len) >> 0;

                return RGBA;
            }
            if (this.fill.type == c_oAscFill.FILL_TYPE_PATT)
            {
                return this.fill.fgClr.RGBA;
            }
            if(this.fill.type == c_oAscFill.FILL_TYPE_NOFILL)
            {
                return {R: 0, G: 0, B: 0};
            }
        }
        return new FormatRGBAColor();
    },

    createDuplicate : function()
    {
        var duplicate = new CUniFill();
        if(this.fill != null)
        {
            duplicate.fill = this.fill.createDuplicate();
        }
        duplicate.transparent = this.transparent;
        return duplicate;
    },

    saveSourceFormatting: function()
    {
        var duplicate = new CUniFill();
        if(this.fill)
        {
            if(this.fill.saveSourceFormatting){
                duplicate.fill = this.fill.saveSourceFormatting();
            }
            else{
                duplicate.fill = this.fill.createDuplicate();
            }

        }
        duplicate.transparent = this.transparent;
        return duplicate;
    },

    merge : function(unifill)
    {
        if(unifill )
        {
            if(unifill.fill!=null)
            {
                this.fill = unifill.fill.createDuplicate();
                if(this.fill.type === c_oAscFill.FILL_TYPE_PATT){
                    var _patt_fill = this.fill;
                    if(!_patt_fill.fgClr){
                        _patt_fill.setFgColor(CreateUniColorRGB(0, 0, 0));
                    }
                    if(!_patt_fill.bgClr){
                        _patt_fill.bgClr = CreateUniColorRGB(255, 255, 255);
                    }
                }
            }
            if(unifill.transparent != null)
            {
                this.transparent = unifill.transparent;
            }
        }
    },

    IsIdentical : function(unifill)
    {
        if(unifill == null)
        {
            return false;
        }
		
		if(isRealNumber(this.transparent) !== isRealNumber(unifill.transparent)
		|| isRealNumber(this.transparent) && this.transparent !== unifill.transparent)
		{
			return false;
		}
		
        if(this.fill == null && unifill.fill == null)
        {
            return true;
        }
        if(this.fill!=null)
        {
            return this.fill.IsIdentical(unifill.fill);
        }
        else
        {
            return false;
        }
    },

    Is_Equal : function(unfill)
    {
        return this.IsIdentical(unfill);
    },

    compare : function(unifill)
    {
        if(unifill == null)
        {
            return null;
        }
        var _ret = new CUniFill();
        if(!(this.fill == null || unifill.fill == null))
        {
            if(this.fill.compare)
            {
                _ret.fill = this.fill.compare(unifill.fill);
            }
        }
        return _ret.fill;
    }
};

function CompareUniFill(unifill_1, unifill_2)
{

    if(unifill_1 == null || unifill_2 == null)
    {
        return null;
    }

    var _ret = new CUniFill();

    if(!(unifill_1.transparent === null || unifill_2.transparent === null
        || unifill_1.transparent !== unifill_2.transparent))
    {
        _ret.transparent = unifill_1.transparent;
    }

    if(unifill_1.fill == null || unifill_2.fill == null
        || unifill_1.fill.type != unifill_2.fill.type)
    {
        return _ret;
    }
    _ret.fill = unifill_1.compare(unifill_2);
    return _ret;
}


function CompareBlipTiles(tile1, tile2)
{
    if(isRealObject(tile1))
    {
        return tile1.IsIdentical(tile2);
    }
    return tile1 === tile2;
}

function CompareUnifillBool(u1, u2)
{
    if(!u1 && !u2)
        return true;
    if(!u1 && u2 || u1 && !u2)
        return false;

	if(isRealNumber(u1.transparent) !== isRealNumber(u2.transparent)
		|| isRealNumber(u1.transparent) && u1.transparent !== u2.transparent)
		{
			return false;
		}
    if(!u1.fill && !u2.fill)
        return true;
    if(!u1.fill && u2.fill || u1.fill && !u2.fill)
        return false;

    if(u1.fill.type !== u2.fill.type)
        return false
    switch(u1.fill.type)
    {
        case c_oAscFill.FILL_TYPE_BLIP:
        {
            if(u1.fill.RasterImageId && !u2.fill.RasterImageId || u2.fill.RasterImageId && !u1.fill.RasterImageId)
                return false;

            if(typeof u1.fill.RasterImageId === "string" && typeof u2.fill.RasterImageId === "string"
                && AscCommon.getFullImageSrc2(u1.fill.RasterImageId) !== AscCommon.getFullImageSrc2(u2.fill.RasterImageId))
                return false;


            if(u1.fill.srcRect && !u2.fill.srcRect || !u1.fill.srcRect && u2.fill.srcRect)
                return false;

            if(u1.fill.srcRect && u2.fill.srcRect)
            {
                if( u1.fill.srcRect.l !== u2.fill.srcRect.l||
                    u1.fill.srcRect.t !== u2.fill.srcRect.t||
                    u1.fill.srcRect.r !== u2.fill.srcRect.r||
                    u1.fill.srcRect.b !== u2.fill.srcRect.b)
                    return false;
            }

            if(u1.fill.stretch !== u2.fill.stretch || !CompareBlipTiles(u1.fill.tile, u2.fill.tile) || u1.fill.rotWithShape !== u2.fill.rotWithShape)
                return false;
            break;
        }
        case c_oAscFill.FILL_TYPE_SOLID:
        {
            if(u1.fill.color && u2.fill.color)
            {
                return CompareUniColor(u1.fill.color, u2.fill.color)
            }
            break;
        }
        case c_oAscFill.FILL_TYPE_GRAD:
        {
            if(u1.fill.colors.length !== u2.fill.colors.length)
                return false;
            if(isRealObject(u1.fill.path) !== isRealObject(u2.fill.path))
                return false;
            if(u1.fill.path && !u1.fill.path.IsIdentical(u2.fill.path))
                return false;

            if(isRealObject(u1.fill.lin) !== isRealObject(u2.fill.lin))
                return false;

            if(u1.fill.lin && !u1.fill.lin.IsIdentical(u2.fill.lin))
                return false;

            for(var i = 0; i < u1.fill.colors.length; ++i)
            {
                if(u1.fill.colors[i].pos !== u2.fill.colors[i].pos
                    || ! CompareUniColor(u1.fill.colors[i].color, u2.fill.colors[i].color))
                    return false;
            }
            break;
        }
        case c_oAscFill.FILL_TYPE_PATT:
        {
            if(u1.fill.ftype !== u2.fill.ftype
                || !CompareUniColor(u1.fill.fgClr, u2.fill.fgClr)
                || !CompareUniColor(u1.fill.bgClr, u2.fill.bgClr))
                return false;
            break;
        }
    }
    return true;
}


function CompareUniColor(u1, u2)
{
    if(!u1 && !u2)
        return true;
    if(!u1 && u2 || u1 && !u2)
        return false;
    if(!u1.color && u2.color || u1.color && !u2.color)
        return false;
    if(u1.color && u2.color)
    {
        if(u1.color.type !== u2.color.type)
            return false;
        switch (u1.color.type)
        {
            case c_oAscColor.COLOR_TYPE_NONE:
            {
                break;
            }
            case c_oAscColor.COLOR_TYPE_SRGB:
            {
                if(u1.color.RGBA.R !== u2.color.RGBA.R
                    || u1.color.RGBA.G !== u2.color.RGBA.G
                    || u1.color.RGBA.B !== u2.color.RGBA.B
                    || u1.color.RGBA.A !== u2.color.RGBA.A)
                {
                    return false;
                }
                break;
            }
            case c_oAscColor.COLOR_TYPE_PRST:
            case c_oAscColor.COLOR_TYPE_SCHEME:
            {
                if(u1.color.id !== u2.color.id)
                    return false;
                break;
            }
            case c_oAscColor.COLOR_TYPE_SYS:
            {
                if(u1.color.RGBA.R !== u2.color.RGBA.R
                    || u1.color.RGBA.G !== u2.color.RGBA.G
                    || u1.color.RGBA.B !== u2.color.RGBA.B
                    || u1.color.RGBA.A !== u2.color.RGBA.A
                    || u1.color.id !== u2.color.id)
                {
                    return false;
                }
                break;
            }
        }
    }
    if(!u1.Mods && u2.Mods || !u2.Mods && u1.Mods)
        return false;

    if(u1.Mods && u2.Mods)
    {
        if(u1.Mods.Mods.length !== u2.Mods.Mods.length)
            return false;
        for(var i = 0; i < u1.Mods.Mods.length; ++i)
        {
            if(u1.Mods.Mods[i].name !== u2.Mods.Mods[i].name
                || u1.Mods.Mods[i].val !== u2.Mods.Mods[i].val)
                return false;
        }
    }
    return true;
}
// -----------------------------

function CompareShapeProperties(shapeProp1, shapeProp2)
{
    var _result_shape_prop = {};
    if(shapeProp1.type === shapeProp2.type)
    {
        _result_shape_prop.type = shapeProp1.type;
    }
    else
    {
        _result_shape_prop.type = null;
    }

    if(shapeProp1.h === shapeProp2.h)
    {
        _result_shape_prop.h = shapeProp1.h;
    }
    else
    {
        _result_shape_prop.h = null;
    }

    if(shapeProp1.w === shapeProp2.w)
    {
        _result_shape_prop.w = shapeProp1.w;
    }
    else
    {
        _result_shape_prop.w = null;
    }

    if(shapeProp1.stroke == null || shapeProp2.stroke == null)
    {
        _result_shape_prop.stroke = null;
    }
    else
    {
        _result_shape_prop.stroke = shapeProp1.stroke.compare(shapeProp2.stroke)
    }

    /* if(shapeProp1.verticalTextAlign === shapeProp2.verticalTextAlign)
     {
     _result_shape_prop.verticalTextAlign = shapeProp1.verticalTextAlign;
     }
     else */
    {
        _result_shape_prop.verticalTextAlign = null;
        _result_shape_prop.vert = null;
    }

    if(shapeProp1.canChangeArrows !== true || shapeProp2.canChangeArrows !== true)
        _result_shape_prop.canChangeArrows = false;
    else
        _result_shape_prop.canChangeArrows = true;

    _result_shape_prop.fill = CompareUniFill(shapeProp1.fill, shapeProp2.fill);
    _result_shape_prop.IsLocked = shapeProp1.IsLocked === true || shapeProp2.IsLocked === true;
    if(isRealObject(shapeProp1.paddings) && isRealObject(shapeProp2.paddings))
    {
        _result_shape_prop.paddings = new Asc.asc_CPaddings();
        _result_shape_prop.paddings.Left = isRealNumber(shapeProp1.paddings.Left) ? (shapeProp1.paddings.Left === shapeProp2.paddings.Left ? shapeProp1.paddings.Left : undefined) : undefined;
        _result_shape_prop.paddings.Top = isRealNumber(shapeProp1.paddings.Top) ? (shapeProp1.paddings.Top === shapeProp2.paddings.Top ? shapeProp1.paddings.Top : undefined) : undefined;
        _result_shape_prop.paddings.Right = isRealNumber(shapeProp1.paddings.Right) ? (shapeProp1.paddings.Right === shapeProp2.paddings.Right ? shapeProp1.paddings.Right : undefined) : undefined;
        _result_shape_prop.paddings.Bottom = isRealNumber(shapeProp1.paddings.Bottom) ? (shapeProp1.paddings.Bottom === shapeProp2.paddings.Bottom ? shapeProp1.paddings.Bottom : undefined) : undefined;
    }
    _result_shape_prop.canFill = shapeProp1.canFill === true || shapeProp2.canFill === true;

    if(shapeProp1.bFromChart || shapeProp2.bFromChart)
    {
        _result_shape_prop.bFromChart = true;
    }
    else
    {
        _result_shape_prop.bFromChart = false;
    }
    if(!shapeProp1.bFromImage || !shapeProp2.bFromImage)
    {
        _result_shape_prop.bFromImage = false;
    }
    else
    {
        _result_shape_prop.bFromImage = true;
    }
    if(shapeProp1.locked || shapeProp2.locked)
    {
        _result_shape_prop.locked = true;
    }
    _result_shape_prop.lockAspect = !!(shapeProp1.lockAspect && shapeProp2.lockAspect);
    _result_shape_prop.textArtProperties = CompareTextArtProperties(shapeProp1.textArtProperties, shapeProp2.textArtProperties);
    if(shapeProp1.title === shapeProp2.title){
        _result_shape_prop.title = shapeProp1.title;
    }
    if(shapeProp1.description === shapeProp2.description){
        _result_shape_prop.description = shapeProp1.description;
    }
    if(shapeProp1.columnNumber === shapeProp2.columnNumber){
        _result_shape_prop.columnNumber = shapeProp1.columnNumber;
    }
    if(shapeProp1.columnSpace === shapeProp2.columnSpace){
        _result_shape_prop.columnSpace = shapeProp1.columnSpace;
    }

    return _result_shape_prop;
}

function CompareTextArtProperties(oProps1, oProps2)
{
    if(!oProps1 || !oProps2)
        return null;
    var oRet = {Fill: undefined, Line: undefined, Form: undefined};
    if(oProps1.Form === oProps2.Form)
    {
        oRet.From = oProps1.Form;
    }
    if(oProps1.Fill && oProps2.Fill)
    {
        oRet.Fill = CompareUniFill(oProps1.Fill, oProps2.Fill);
    }
    if(oProps1.Line && oProps2.Line)
    {
        oRet.Line = oProps1.Line.compare(oProps2.Line);
    }
    return oRet;
}

// LN --------------------------
// размеры стрелок;
var lg=500,  mid=300, sm=200;
//типы стрелок
var ar_arrow=0, ar_diamond=1, ar_none=2, ar_oval=3, ar_stealth=4, ar_triangle=5;

var LineEndType = {
    None: 0,
    Arrow: 1,
    Diamond: 2,
    Oval: 3,
    Stealth: 4,
    Triangle: 5
};
var LineEndSize = {
    Large: 0,
    Mid: 1,
    Small: 2
};

function EndArrow()
{
    this.type = null;
    this.len = null;
    this.w = null;

}



var LineJoinType = {
    Empty : 0,
    Round : 1,
    Bevel : 2,
    Miter : 3
};


EndArrow.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    compare: function(end_arrow)
    {
        if(end_arrow == null)
        {
            return null;
        }
        var _ret = new EndArrow();
        if(this.type === end_arrow.type)
        {
            _ret.type = this.type;
        }
        if(this.len === end_arrow.len)
        {
            _ret.len = this.len;
        }
        if(this.w === end_arrow)
        {
            _ret.w = this.w;
        }
        return _ret;
    },

    createDuplicate: function()
    {
        var duplicate =  new EndArrow();
        duplicate.type = this.type;
        duplicate.len = this.len;
        duplicate.w = this.w;
        return duplicate;
    },

    IsIdentical: function(arrow)
    {
        return arrow && arrow.type == this.type &&  arrow.len == this.len && arrow.w  == this.w;
    },

    GetWidth: function(size, _max)
    {
        var _ret = 3 * size;
        if (null != this.w)
        {
            switch (this.w)
            {
                case LineEndSize.Large:
                    _ret = 5 * size;
                    break;
                case LineEndSize.Small:
                    _ret = 2 * size;
                    break;
                default:
                    break;
            }
        }
        return Math.max(_ret, _max ? _max : 7);
    },
    GetLen: function(size, _max)
    {
        var _ret = 3 * size;
        if (null != this.len)
        {
            switch (this.len)
            {
                case LineEndSize.Large:
                    _ret = 5 * size;
                    break;
                case LineEndSize.Small:
                    _ret = 2 * size;
                    break;
                default:
                    break;
            }
        }
        return Math.max(_ret, _max ? _max : 7);
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_EndArrow;
    },

    setType: function(type)
    {
        this.type = type;
    },

    setLen: function(len)
    {
        this.len = len;
    },


    setW: function(w)
    {
        this.w = w;
    },


    Write_ToBinary: function (w)
    {
        writeLong(w, this.type);
        writeLong(w, this.len);
        writeLong(w, this.w);
    },

    Read_FromBinary: function (r)
    {
        this.type = readLong(r);
        this.len = readLong(r);
        this.w = readLong(r);
    }

};

function ConvertJoinAggType(_type)
{
    switch (_type)
    {
        case LineJoinType.Round:
            return 2;
        case LineJoinType.Bevel:
            return 1;
        case LineJoinType.Miter:
            return 0;
        default:
            break;
    }
    return 2;
}

function LineJoin()
{
    this.type = null;
    this.limit = null;
}

LineJoin.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},


    IsIdentical : function(oJoin)
    {
        if(!oJoin)
            return false;
        if(this.type !== oJoin.type)
        {
            return false;
        }
        if(this.limit !== oJoin.limit)
            return false;
        return true;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_LineJoin;
    },

    createDuplicate: function()
    {
        var duplicate =  new LineJoin();
        duplicate.type = this.type;
        duplicate.limit = this.limit;
        return duplicate;
    },

    setType: function(type)
    {
        this.type = type;
    },

    setLimit: function(limit)
    {
        this.limit = limit;
    },

    Write_ToBinary: function(w)
    {
        writeLong(w, this.type);
        writeBool(w, this.limit);
    },

    Read_FromBinary: function(r)
    {
        this.type = readLong(r);
        this.limit = readBool(r);
    }

};

function CLn()
{
    this.Fill = null;//new CUniFill();
    this.prstDash = null;

    this.Join = null;
    this.headEnd = null;
    this.tailEnd = null;

    this.algn = null;
    this.cap = null;
    this.cmpd = null;
    this.w = null;
}


CLn.prototype =
{
    getObjectType: function()
    {
        return AscDFH.historyitem_type_Ln;
    },

    compare: function(line)
    {
        if(line == null)
        {
            return null;
        }
        var _ret = new CLn();
        if(this.Fill != null)
        {
            _ret.Fill = CompareUniFill(this.Fill, line.Fill);
        }
        if(this.prstDash === line.prstDash)
        {
            _ret.prstDash = this.prstDash;
        }
        else{
            _ret.prstDash = undefined;
        }
        if(this.Join === line.Join)
        {
            _ret.Join = this.Join;
        }
        if(this.tailEnd != null)
        {
            _ret.tailEnd = this.tailEnd.compare(line.tailEnd);
        }
        if(this.headEnd != null)
        {
            _ret.headEnd = this.headEnd.compare(line.headEnd);
        }

        if(this.algn === line.algn)
        {
            _ret.algn = this.algn;
        }
        if(this.cap === line.cap)
        {
            _ret.cap = this.cap;
        }
        if(this.cmpd === line.cmpd)
        {
            _ret.cmpd = this.cmpd;
        }
        if(this.w === line.w)
        {
            _ret.w = this.w;
        }
        return _ret;
    },

    merge:  function(ln)
    {
        if(ln == null)
        {
            return;
        }
        if(ln.Fill != null && ln.Fill.fill!= null)
        {
            this.Fill = ln.Fill.createDuplicate();
        }

        if(ln.prstDash != null)
        {
            this.prstDash = ln.prstDash;
        }

        if(ln.Join != null)
        {
            this.Join = ln.Join.createDuplicate();
        }

        if(ln.headEnd != null)
        {
            this.headEnd = ln.headEnd.createDuplicate();
        }

        if(ln.tailEnd != null)
        {
            this.tailEnd = ln.tailEnd.createDuplicate();
        }

        if(ln.algn != null)
        {
            this.algn = ln.algn;
        }

        if(ln.cap != null)
        {
            this.cap = ln.cap;
        }

        if(ln.cmpd != null)
        {
            this.cmpd = ln.cmpd;
        }

        if(ln.w != null)
        {
            this.w = ln.w;
        }
    },

    calculate: function(theme, slide, layout, master, RGBA, colorMap)
    {
        if(isRealObject(this.Fill))
        {
            this.Fill.calculate(theme, slide, layout, master, RGBA, colorMap);
        }
    },

    createDuplicate:  function(bSaveFormatting)
    {
        var duplicate = new CLn();

        if (null != this.Fill)
        {
            if(bSaveFormatting === true){
                duplicate.Fill = this.Fill.saveSourceFormatting();
            }
            else{
                duplicate.Fill = this.Fill.createDuplicate();
            }

        }

        duplicate.prstDash = this.prstDash;
        duplicate.Join = this.Join;
        if(this.headEnd!=null)
        {
            duplicate.headEnd = this.headEnd.createDuplicate();
        }

        if(this.tailEnd!=null)
        {
            duplicate.tailEnd = this.tailEnd.createDuplicate();
        }

        duplicate.algn = this.algn;
        duplicate.cap = this.cap;
        duplicate.cmpd = this.cmpd;
        duplicate.w = this.w;
        return duplicate;
    },

    IsIdentical: function(ln)
    {
        return ln && (this.Fill == null ? ln.Fill == null : this.Fill.IsIdentical(ln.Fill) )&& (this.Join == null ? ln.Join == null : this.Join.IsIdentical(ln.Join) )
            && (this.headEnd == null ? ln.headEnd == null : this.headEnd.IsIdentical(ln.headEnd) )
            && (this.tailEnd == null ? ln.tailEnd == null : this.tailEnd.IsIdentical(ln.headEnd)) &&
            this.algn == ln.algn && this.cap == ln.cap && this.cmpd == ln.cmpd && this.w== ln.w && this.prstDash === ln.prstDash;
    },

    setFill: function(fill)
    {
        this.Fill = fill;
    },

    setPrstDash: function(prstDash)
    {
        this.prstDash = prstDash;
    },

    setJoin: function(join)
    {
        this.Join = join;
    },

    setHeadEnd: function(headEnd)
    {
        this.headEnd = headEnd;
    },

    setTailEnd: function(tailEnd)
    {
        this.tailEnd = tailEnd;
    },

    setAlgn: function(algn)
    {
        this.algn = algn;
    },

    setCap: function(cap)
    {
        this.cap = cap;
    },

    setCmpd: function(cmpd)
    {
        this.cmpd = cmpd;
    },
    setW: function(w)
    {
        this.w = w;
    },

    Write_ToBinary: function(w)
    {
        w.WriteBool(isRealObject(this.Fill));
        if(isRealObject(this.Fill))
        {
            this.Fill.Write_ToBinary(w);
        }
        writeLong(w, this.prstDash);

        w.WriteBool(isRealObject(this.Join));
        if(isRealObject(this.Join))
        {
            this.Join.Write_ToBinary(w);
        }

        w.WriteBool(isRealObject(this.headEnd));
        if(isRealObject(this.headEnd))
        {
            this.headEnd.Write_ToBinary(w);
        }
        w.WriteBool(isRealObject(this.tailEnd));
        if(isRealObject(this.tailEnd))
        {
            this.tailEnd.Write_ToBinary(w);
        }
        writeLong(w, this.algn);
        writeLong(w, this.cap);
        writeLong(w, this.cmpd);
        writeLong(w, this.w);
    },

    Read_FromBinary: function(r)
    {
        if(r.GetBool())
        {
            this.Fill = new CUniFill();
            this.Fill.Read_FromBinary(r);
        }
        else
        {
            this.Fill = null;
        }
        this.prstDash = readLong(r);

        if(r.GetBool())
        {
            this.Join = new LineJoin();
            this.Join.Read_FromBinary(r);
        }

        if(r.GetBool())
        {
            this.headEnd = new EndArrow();
            this.headEnd.Read_FromBinary(r);
        }
        if(r.GetBool())
        {
            this.tailEnd = new EndArrow();
            this.tailEnd.Read_FromBinary(r);
        }
        this.algn = readLong(r);
        this.cap  = readLong(r);
        this.cmpd = readLong(r);
        this.w    = readLong(r);
    }
};

// -----------------------------

// SHAPE ----------------------------

function DefaultShapeDefinition()
{
    this.spPr = new CSpPr();
    this.bodyPr = new CBodyPr();
    this.lstStyle = new TextListStyle();
    this.style = null;
    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

DefaultShapeDefinition.prototype=
{
    Get_Id: function()
    {
        return this.Id;
    },


    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    },

    Refresh_RecalcData: function()
    {},
    getObjectType: function()
    {
        return AscDFH.historyitem_type_DefaultShapeDefinition;
    },

    setSpPr: function(spPr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DefaultShapeDefinition_SetSpPr, this.spPr, spPr));
        this.spPr = spPr;
    },

    setBodyPr: function(bodyPr)
    {
        History.Add(new CChangesDrawingsObjectNoId(this, AscDFH.historyitem_DefaultShapeDefinition_SetBodyPr, this.bodyPr, bodyPr));
        this.bodyPr = bodyPr;
    },

    setLstStyle: function(lstStyle)
    {
        History.Add(new CChangesDrawingsObjectNoId(this, AscDFH.historyitem_DefaultShapeDefinition_SetLstStyle, this.lstStyle, lstStyle));
        this.lstStyle = lstStyle;
    },

    setStyle: function(style)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DefaultShapeDefinition_SetStyle, this.style, style));
        this.style = style;
    },

    createDuplicate: function()
    {
        var ret = new DefaultShapeDefinition();
        if(this.spPr)
        {
            ret.setSpPr(this.spPr.createDuplicate());
        }
        if(this.bodyPr)
        {
            ret.setBodyPr(this.bodyPr.createDuplicate());
        }
        if(this.lstStyle)
        {
            ret.setLstStyle(this.lstStyle.createDuplicate());
        }
        if(this.style)
        {
            ret.setStyle(this.style.createDuplicate());
        }
        return ret;
    }
};



function CHyperlink(){

}

function CNvPr()
{
    this.id = 0;
    this.name = "";
    this.isHidden = false;
    this.descr = null;
    this.title = null;

    this.hlinkClick = null;
    this.hlinkHover = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id)
}


CNvPr.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_CNvPr;
    },

    createDuplicate: function()
    {
        var duplicate = new CNvPr();
        duplicate.setId(this.id);
        duplicate.setName(this.name);
        duplicate.setIsHidden(this.isHidden);
        duplicate.setDescr(this.descr);
        duplicate.setTitle(this.title);
        if(this.hlinkClick){
            duplicate.setHlinkClick(this.hlinkClick.createDuplicate());
        }
        if(this.hlinkHover){
            duplicate.setHlinkClick(this.hlinkHover.createDuplicate());
        }
        return duplicate;
    },

    setId: function(id)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_CNvPr_SetId, this.id, id));
        this.id = id;
    },

    setName: function(name)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_CNvPr_SetName, this.name, name));
        this.name = name;
    },

    setIsHidden: function(isHidden)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_CNvPr_SetIsHidden, this.isHidden, isHidden));
        this.isHidden = isHidden;
    },

    setDescr: function(descr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_CNvPr_SetDescr , this.descr,  descr));
        this.descr = descr;
    },

    setHlinkClick: function(pr)
    {
        History.Add(new CChangesDrawingsObjectNoId(this, AscDFH.historyitem_CNvPr_SetHlinkClick, this.hlinkClick, pr));
        this.hlinkClick = pr;
    },

    setHlinkHover: function(pr)
    {
        History.Add(new CChangesDrawingsObjectNoId(this, AscDFH.historyitem_CNvPr_SetHlinkHover, this.hlinkHover, pr));
        this.hlinkHover = pr;
    },

    setTitle: function(title)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_CNvPr_SetTitle, this.title,  title));
        this.title = title;
    },

    setFromOther: function(oOther){
        if(!oOther){
            return;
        }
        if(oOther.name){
            this.setName(oOther.name);
        }
        if(oOther.descr){
            this.setDescr(oOther.descr);
        }
        if(oOther.title){
            this.setTitle(oOther.title);
        }
    },

    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    }
};



var AUDIO_CD = 0;
var WAV_AUDIO_FILE = 1;
var AUDIO_FILE = 2;
var VIDEO_FILE = 3;
var QUICK_TIME_FILE = 4;


function UniMedia() {
    this.type = null;
    this.media = null;
}
    UniMedia.prototype.Write_ToBinary = function(w){
        var bType = this.type !== null && this.type !== undefined;
        var bMedia = typeof this.media === 'string';
        var nFlags = 0;
        bType && (nFlags |= 1);
        bMedia && (nFlags |= 2);
        w.WriteLong(nFlags);
        bType && w.WriteLong(this.type);
        bMedia && w.WriteString2(this.media);
    };
    UniMedia.prototype.Read_FromBinary = function(r){
        var nFlags = r.GetLong();
        if(nFlags & 1){
            this.type = r.GetLong();
        }
        if(nFlags & 2){
            this.media = r.GetString2();
        }
    };

    UniMedia.prototype.createDuplicate = function(r){
        var _ret = new UniMedia();
        _ret.type = this.type;
        _ret.media = this.media;
        return _ret;
    };

    drawingConstructorsMap[AscDFH.historyitem_NvPr_SetUniMedia                 ] = UniMedia;

function NvPr()
{
    this.isPhoto = false;
    this.userDrawn = false;
    this.ph = null;
    this.unimedia = null;


    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

NvPr.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},
    getObjectType: function()
    {
        return AscDFH.historyitem_type_NvPr;
    },

    setIsPhoto: function(isPhoto)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_NvPr_SetIsPhoto, this.isPhoto, isPhoto));
        this.isPhoto = isPhoto;
    },

    setUserDrawn: function(userDrawn)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_NvPr_SetUserDrawn, this.userDrawn, userDrawn));
        this.userDrawn = userDrawn;
    },

    setPh: function(ph)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_NvPr_SetPh, this.ph, ph));
        this.ph = ph;
    },

    setUniMedia: function(pr){
        History.Add(new CChangesDrawingsObjectNoId(this, AscDFH.historyitem_NvPr_SetUniMedia, this.unimedia, pr));
        this.unimedia = pr;
    },

    createDuplicate: function()
    {
        var duplicate = new NvPr();
        duplicate.setIsPhoto(this.isPhoto);
        duplicate.setUserDrawn(this.userDrawn);
        if(this.ph != null)
        {
            duplicate.setPh(this.ph.createDuplicate());
        }
        return duplicate;
    },

    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    }
};

var szPh_full    = 0,
    szPh_half    = 1,
    szPh_quarter = 2;

var orientPh_horz = 0,
    orientPh_vert = 1;

function Ph()
{
    this.hasCustomPrompt = false;
    this.idx = null;
    this.orient = null;
    this.sz = null;
    this.type = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

Ph.prototype =
{
    createDuplicate:  function()
    {
        var duplicate = new Ph();
        duplicate.setHasCustomPrompt(this.hasCustomPrompt);
        duplicate.setIdx(this.idx);
        duplicate.setOrient(this.orient);
        duplicate.setSz(this.sz);
        duplicate.setType(this.type);
        return duplicate;
    },

    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_Ph;
    },

    setHasCustomPrompt: function(hasCustomPrompt)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_Ph_SetHasCustomPrompt, this.hasCustomPrompt, hasCustomPrompt));
        this.hasCustomPrompt = hasCustomPrompt;
    },

    setIdx: function(idx)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_Ph_SetIdx, this.idx, idx));
        this.idx = idx;
    },

    setOrient: function(orient)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_Ph_SetOrient, this.orient, orient));
        this.orient = orient;
    },

    setSz: function(sz)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_Ph_SetSz, this.sz, sz));
        this.sz = sz;
    },

    setType: function(type)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_Ph_SetType, this.type, type));
        this.type = type;
    },

    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    }
};



function CNvUniSpPr()
{
    this.locks = null;

    this.stCnxIdx = null;
    this.stCnxId  = null;

    this.endCnxIdx = null;
    this.endCnxId  = null;
}

    CNvUniSpPr.prototype.Write_ToBinary = function(w){
        if(AscFormat.isRealNumber(this.locks)){
            w.WriteBool(true);
            w.WriteLong(this.locks);
        }
        else {
            w.WriteBool(false);
        }
        if(AscFormat.isRealNumber(this.stCnxIdx) && typeof (this.stCnxId) === "string" && this.stCnxId.length > 0){
            w.WriteBool(true);
            w.WriteLong(this.stCnxIdx);
            w.WriteString2(this.stCnxId);
        }
        else {
            w.WriteBool(false);
        }
        if(AscFormat.isRealNumber(this.endCnxIdx) && typeof (this.endCnxId) === "string" && this.endCnxId.length > 0){
            w.WriteBool(true);
            w.WriteLong(this.endCnxIdx);
            w.WriteString2(this.endCnxId);
        }
        else {
            w.WriteBool(false);
        }
    };
    CNvUniSpPr.prototype.Read_FromBinary = function(r){
        var bCnx = r.GetBool();
        if(bCnx){
            this.locks = r.GetLong();
        }
        else{
            this.locks = null;
        }
        bCnx = r.GetBool();
        if(bCnx){
            this.stCnxIdx = r.GetLong();
            this.stCnxId = r.GetString2();
        }
        else{
            this.stCnxIdx = null;
            this.stCnxId =  null;
        }
        bCnx = r.GetBool();
        if(bCnx){
            this.endCnxIdx = r.GetLong();
            this.endCnxId = r.GetString2();
        }
        else{
            this.endCnxIdx = null;
            this.endCnxId =  null;
        }
    };

    CNvUniSpPr.prototype.copy = function(){
        var _ret = new CNvUniSpPr();
        _ret.locks = this.locks;
        _ret.stCnxId = this.stCnxId;
        _ret.stCnxIdx = this.stCnxIdx;
        _ret.endCnxId = this.endCnxId;
        _ret.endCnxIdx = this.endCnxIdx;
        return _ret;
    };

function UniNvPr()
{
    this.cNvPr = new CNvPr();
    this.UniPr = null;
    this.nvPr = new NvPr();
    this.nvUniSpPr = new CNvUniSpPr();
    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);

}

UniNvPr.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_UniNvPr;
    },

    setCNvPr: function(cNvPr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_UniNvPr_SetCNvPr, this.cNvPr, cNvPr));
        this.cNvPr = cNvPr;
    },

    setUniSpPr: function(pr){
        History.Add(new CChangesDrawingsObjectNoId(this, AscDFH.historyitem_UniNvPr_SetUniSpPr, this.nvUniSpPr, pr));
        this.nvUniSpPr = pr;
    },

    setUniPr: function(uniPr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_UniNvPr_SetUniPr, this.UniPr, uniPr));
        this.UniPr = uniPr;
    },

    setNvPr: function(nvPr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_UniNvPr_SetNvPr, this.nvPr, nvPr));
        this.nvPr = nvPr;
    },


    createDuplicate: function()
    {
        var duplicate = new UniNvPr();
        this.cNvPr && duplicate.setCNvPr(this.cNvPr.createDuplicate());
        this.nvPr && duplicate.setNvPr(this.nvPr.createDuplicate());
        this.nvUniSpPr && duplicate.setUniSpPr(this.nvUniSpPr.copy());
        return duplicate;
    },


    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
        writeObject(w, this.cNvPr);
        writeObject(w, this.nvPr);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
        this.cNvPr = readObject(r);
        this.nvPr  = readObject(r);
    }
};

function StyleRef()
{
    this.idx = 0;
    this.Color = new CUniColor();
}

StyleRef.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    isIdentical: function(styleRef)
    {
        if(styleRef == null)
        {
            return false;
        }
        if(this.idx !== styleRef.idx)
        {
            return false;
        }

        if(this.Color.IsIdentical(styleRef.Color) == false)
        {
            return false;
        }

        return true;
    },

    getObjectType: function()
    {
        return  AscDFH.historyitem_type_StyleRef;
    },

    setIdx: function(idx)
    {
        this.idx= idx;
    },

    setColor: function(color)
    {
        this.Color = color;
    },

    createDuplicate: function()
    {
        var duplicate  = new StyleRef();
        duplicate.setIdx(this.idx);
        if(this.Color)
            duplicate.setColor(this.Color.createDuplicate());
        return duplicate;
    },

    Refresh_RecalcData: function()
    {},

    Write_ToBinary: function (w)
    {
        writeLong(w, this.idx);
        w.WriteBool(isRealObject(this.Color));
        if(isRealObject(this.Color))
        {
            this.Color.Write_ToBinary(w);
        }
    },

    Read_FromBinary: function (r)
    {
        this.idx = readLong(r);
        if(r.GetBool())
        {
            this.Color = new CUniColor();
            this.Color.Read_FromBinary(r);
        }
    }
};

function FontRef()
{
    this.idx = AscFormat.fntStyleInd_none;
    this.Color = null;
}

FontRef.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    setIdx: function(idx)
    {
        this.idx = idx;
    },

    setColor: function(color)
    {
        this.Color = color;
    },

    createDuplicate: function()
    {
        var duplicate  = new FontRef();
        duplicate.setIdx(this.idx);
        if(this.Color)
            duplicate.setColor(this.Color.createDuplicate());
        return duplicate;
    },

    Write_ToBinary: function (w)
    {
        writeLong(w, this.idx);
        w.WriteBool(isRealObject(this.Color));
        if(isRealObject(this.Color))
        {
            this.Color.Write_ToBinary(w);
        }
    },

    Read_FromBinary: function (r)
    {
        this.idx = readLong(r);
        if(r.GetBool())
        {
            this.Color = new CUniColor();
            this.Color.Read_FromBinary(r);
        }
    }
};

function CShapeStyle()
{
    this.lnRef = null;
    this.fillRef = null;
    this.effectRef = null;
    this.fontRef = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CShapeStyle.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    },

    merge: function(style)
    {
        if(style!=null)
        {
            if(style.lnRef != null)
            {
                this.lnRef = style.lnRef.createDuplicate();
            }

            if(style.fillRef != null)
            {
                this.fillRef = style.fillRef.createDuplicate();
            }

            if(style.effectRef != null)
            {
                this.effectRef = style.effectRef.createDuplicate();
            }

            if(style.fontRef != null)
            {
                this.fontRef = style.fontRef.createDuplicate();
            }
        }
    },

    createDuplicate:  function()
    {
        var duplicate = new CShapeStyle();
        if(this.lnRef!=null)
        {
            duplicate.setLnRef(this.lnRef.createDuplicate());
        }
        if(this.fillRef!=null)
        {
            duplicate.setFillRef(this.fillRef.createDuplicate());
        }
        if(this.effectRef!=null)
        {
            duplicate.setEffectRef(this.effectRef.createDuplicate());
        }
        if(this.fontRef!=null)
        {
            duplicate.setFontRef(this.fontRef.createDuplicate());
        }
        return duplicate;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_ShapeStyle;
    },

    setLnRef: function(pr)
    {
        History.Add(new CChangesDrawingsObjectNoId(this, AscDFH.historyitem_ShapeStyle_SetLnRef, this.lnRef,  pr));
        this.lnRef = pr;
    },
    setFillRef: function(pr)
    {
        History.Add(new CChangesDrawingsObjectNoId(this, AscDFH.historyitem_ShapeStyle_SetFillRef, this.fillRef,  pr));
        this.fillRef = pr;
    },
    setFontRef: function(pr)
    {
        History.Add(new CChangesDrawingsObjectNoId(this, AscDFH.historyitem_ShapeStyle_SetFontRef, this.fontRef,  pr));
        this.fontRef = pr;
    },

    setEffectRef: function(pr)
    {
        History.Add(new CChangesDrawingsObjectNoId(this, AscDFH.historyitem_ShapeStyle_SetEffectRef, this.effectRef,  pr));
        this.effectRef = pr;
    }
};

var LINE_PRESETS_MAP = {};

LINE_PRESETS_MAP["line"] = true;
LINE_PRESETS_MAP["bracePair"] = true;
LINE_PRESETS_MAP["leftBrace"] = true;
LINE_PRESETS_MAP["rightBrace"] = true;
LINE_PRESETS_MAP["bracketPair"] = true;
LINE_PRESETS_MAP["leftBracket"] = true;
LINE_PRESETS_MAP["rightBracket"] = true;
LINE_PRESETS_MAP["bentConnector2"] = true;
LINE_PRESETS_MAP["bentConnector3"] = true;
LINE_PRESETS_MAP["bentConnector4"] = true;
LINE_PRESETS_MAP["bentConnector5"] = true;
LINE_PRESETS_MAP["curvedConnector2"] = true;
LINE_PRESETS_MAP["curvedConnector3"] = true;
LINE_PRESETS_MAP["curvedConnector4"] = true;
LINE_PRESETS_MAP["curvedConnector5"] = true;
LINE_PRESETS_MAP["straightConnector1"] = true;
LINE_PRESETS_MAP["arc"] = true;

function CreateDefaultShapeStyle(preset)
{

    var b_line = typeof preset === "string" && LINE_PRESETS_MAP[preset];
    var tx_color = b_line;
    var unicolor;
    var style = new CShapeStyle();
    var lnRef = new StyleRef();
    lnRef.setIdx(b_line ? 1 : 2);

    unicolor = new CUniColor();
    unicolor.setColor(new CSchemeColor());
    unicolor.color.setId(g_clr_accent1);
    var mod = new CColorMod();
    mod.setName("shade");
    mod.setVal(50000);
    unicolor.setMods(new CColorModifiers());
    unicolor.Mods.addMod(mod);
    lnRef.setColor(unicolor);

    style.setLnRef(lnRef);


    var fillRef = new StyleRef();
    unicolor = new CUniColor();
    unicolor.setColor(new CSchemeColor());
    unicolor.color.setId(g_clr_accent1);
    fillRef.setIdx(b_line ? 0 : 1);
    fillRef.setColor(unicolor);
    style.setFillRef(fillRef);



    var effectRef = new StyleRef();
    unicolor = new CUniColor();
    unicolor.setColor(new CSchemeColor());
    unicolor.color.setId(g_clr_accent1);
    effectRef.setIdx(0);
    effectRef.setColor(unicolor);
    style.setEffectRef(effectRef);

    var fontRef = new FontRef();
    unicolor = new CUniColor();
    unicolor.setColor(new CSchemeColor());
    unicolor.color.setId(tx_color ? 15 : 12);
    fontRef.setIdx(AscFormat.fntStyleInd_minor);
    fontRef.setColor(unicolor);
    style.setFontRef(fontRef);
    return style;
}




function CXfrm()
{
    this.offX   = null;
    this.offY   = null;
    this.extX   = null;
    this.extY   = null;
    this.chOffX = null;
    this.chOffY = null;
    this.chExtX = null;
    this.chExtY = null;

    this.flipH  = null;
    this.flipV  = null;
    this.rot    = null;

    this.parent = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CXfrm.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_Xfrm;
    },

    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    },


    isNotNull: function()
    {
        return isRealNumber(this.offX) && isRealNumber(this.offY) && isRealNumber(this.extX) && isRealNumber(this.extY);
    },


    isNotNullForGroup: function()
    {
        return isRealNumber(this.offX) && isRealNumber(this.offY)
            && isRealNumber(this.chOffX) && isRealNumber(this.chOffY)
            && isRealNumber(this.extX) && isRealNumber(this.extY)
            && isRealNumber(this.chExtX) && isRealNumber(this.chExtY);
    },

    isEqual: function(xfrm)
    {

        return xfrm && this.offX == xfrm.offX && this.offY == xfrm.offY && this.extX == xfrm.extX &&
            this.extY == xfrm.extY && this.chOffX == xfrm.chOffX && this.chOffY == xfrm.chOffY && this.chExtX == xfrm.chExtX &&
            this.chExtY == xfrm.chExtY ;
    },

    merge: function(xfrm)
    {
        if(xfrm.offX != null)
        {
            this.offX = xfrm.offX;
        }
        if(xfrm.offY != null)
        {
            this.offY = xfrm.offY;
        }


        if(xfrm.extX != null)
        {
            this.extX = xfrm.extX;
        }
        if(xfrm.extY != null)
        {
            this.extY = xfrm.extY;
        }


        if(xfrm.chOffX != null)
        {
            this.chOffX = xfrm.chOffX;
        }
        if(xfrm.chOffY != null)
        {
            this.chOffY = xfrm.chOffY;
        }


        if(xfrm.chExtX != null)
        {
            this.chExtX = xfrm.chExtX;
        }
        if(xfrm.chExtY != null)
        {
            this.chExtY = xfrm.chExtY;
        }


        if(xfrm.flipH != null)
        {
            this.flipH = xfrm.flipH;
        }
        if(xfrm.flipV != null)
        {
            this.flipV = xfrm.flipV;
        }

        if(xfrm.rot != null)
        {
            this.rot = xfrm.rot;
        }
    },

    createDuplicate: function()
    {
        var duplicate = new CXfrm();
        duplicate.setOffX(this.offX);
        duplicate.setOffY(this.offY);
        duplicate.setExtX(this.extX);
        duplicate.setExtY(this.extY);
        duplicate.setChOffX(this.chOffX);
        duplicate.setChOffY(this.chOffY);
        duplicate.setChExtX(this.chExtX);
        duplicate.setChExtY(this.chExtY);

        duplicate.setFlipH(this.flipH);
        duplicate.setFlipV(this.flipV);
        duplicate.setRot(this.rot);
        return duplicate;
    },

    checkFromSerialize: function()
    {
        if(this.parent && this.parent.checkFromSerialize)
        {
            this.parent.checkFromSerialize();
        }
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Xfrm_SetParent, this.parent,  pr));
        this.parent = pr;
    },

    setOffX: function(pr)
    {
        this.checkFromSerialize();
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Xfrm_SetOffX, this.offX,  pr));
        this.offX = pr;
        this.handleUpdatePosition();
    },
    setOffY: function(pr)
    {
        this.checkFromSerialize();
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Xfrm_SetOffY, this.offY,  pr));
        this.offY = pr;
        this.handleUpdatePosition();
    },
    setExtX: function(pr)
    {
        this.checkFromSerialize();
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Xfrm_SetExtX, this.extX,  pr));
        this.extX = pr;
        this.handleUpdateExtents();
    },
    setExtY: function(pr)
    {
        this.checkFromSerialize();
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Xfrm_SetExtY, this.extY,  pr));
        this.extY = pr;
        this.handleUpdateExtents();
    },
    setChOffX: function(pr)
    {
        this.checkFromSerialize();
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Xfrm_SetChOffX, this.chOffX,  pr));
        this.chOffX = pr;
        this.handleUpdateChildOffset();
    },
    setChOffY: function(pr)
    {
        this.checkFromSerialize();
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Xfrm_SetChOffY, this.chOffY,  pr));
        this.chOffY = pr;
        this.handleUpdateChildOffset();
    },
    setChExtX: function(pr)
    {
        this.checkFromSerialize();
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Xfrm_SetChExtX, this.chExtX,  pr));
        this.chExtX = pr;
        this.handleUpdateChildExtents();
    },
    setChExtY: function(pr)
    {
        this.checkFromSerialize();
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Xfrm_SetChExtY, this.chExtY,  pr));
        this.chExtY = pr;
        this.handleUpdateChildExtents();
    },
    setFlipH: function(pr)
    {
        this.checkFromSerialize();
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_Xfrm_SetFlipH, this.flipH,  pr));
        this.flipH = pr;
        this.handleUpdateFlip();
    },
    setFlipV: function(pr)
    {
        this.checkFromSerialize();
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_Xfrm_SetFlipV, this.flipV,  pr));
        this.flipV = pr;
        this.handleUpdateFlip();
    },
    setRot: function(pr)
    {
        this.checkFromSerialize();
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Xfrm_SetRot, this.rot,  pr));
        this.rot = pr;
        this.handleUpdateRot();
    },

    handleUpdatePosition: function()
    {
        if(this.parent && this.parent.handleUpdatePosition)
        {
            this.parent.handleUpdatePosition();
        }
    },

    handleUpdateExtents: function()
    {
        if(this.parent && this.parent.handleUpdateExtents)
        {
            this.parent.handleUpdateExtents();
        }
    },

    handleUpdateChildOffset: function()
    {
        if(this.parent && this.parent.handleUpdateChildOffset)
        {
            this.parent.handleUpdateChildOffset();
        }
    },

    handleUpdateChildExtents: function()
    {
        if(this.parent && this.parent.handleUpdateChildExtents)
        {
            this.parent.handleUpdateChildExtents();
        }
    },

    handleUpdateFlip: function()
    {
        if(this.parent && this.parent.handleUpdateFlip)
        {
            this.parent.handleUpdateFlip();
        }
    },

    handleUpdateRot: function()
    {
        if(this.parent && this.parent.handleUpdateRot)
        {
            this.parent.handleUpdateRot();
        }
    },


    Refresh_RecalcData: function(data)
    {
        switch (data.Type)
        {
            case AscDFH.historyitem_Xfrm_SetOffX:
            {
                this.handleUpdatePosition();
                break;
            }
            case AscDFH.historyitem_Xfrm_SetOffY:
            {
                this.handleUpdatePosition();
                break;
            }
            case AscDFH.historyitem_Xfrm_SetExtX:
            {
                this.handleUpdateExtents();
                break;
            }
            case AscDFH.historyitem_Xfrm_SetExtY:
            {
                this.handleUpdateExtents();
                break;
            }
            case AscDFH.historyitem_Xfrm_SetChOffX:
            {
                this.handleUpdateChildOffset();
                break;
            }
            case AscDFH.historyitem_Xfrm_SetChOffY:
            {
                this.handleUpdateChildOffset();
                break;
            }
            case AscDFH.historyitem_Xfrm_SetChExtX:
            {
                this.handleUpdateChildExtents();
                break;
            }
            case AscDFH.historyitem_Xfrm_SetChExtY:
            {
                this.handleUpdateChildExtents();
                break;
            }
            case AscDFH.historyitem_Xfrm_SetFlipH:
            {
                this.handleUpdateFlip();
                break;
            }
            case AscDFH.historyitem_Xfrm_SetFlipV:
            {
                this.handleUpdateFlip();
                break;
            }
            case AscDFH.historyitem_Xfrm_SetRot:
            {
                this.handleUpdateRot();
                break;
            }
        }
    }
};

function CSpPr()
{
    this.bwMode    = 0;

    this.xfrm       = null;
    this.geometry   = null;
    this.Fill       = null;
    this.ln         = null;
    this.parent     = null;


    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CSpPr.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function(data)
    {
        switch(data.Type)
        {
            case AscDFH.historyitem_SpPr_SetParent:
            {
                break;
            }
            case AscDFH.historyitem_SpPr_SetBwMode:
            {
                break;
            }
            case AscDFH.historyitem_SpPr_SetXfrm:
            {
                break;
            }
            case AscDFH.historyitem_SpPr_SetGeometry:
            {
                this.handleUpdateGeometry();
                break;
            }
            case AscDFH.historyitem_SpPr_SetFill:
            {
                this.handleUpdateFill();
                break;
            }
            case AscDFH.historyitem_SpPr_SetLn:
            {
                this.handleUpdateLn();
                break;
            }
        }
    },

    Refresh_RecalcData2: function(data)
    {
    },

    createDuplicate: function()
    {
        var duplicate = new CSpPr();
        duplicate.setBwMode(this.bwMode);
        if(this.xfrm)
        {
            duplicate.setXfrm(this.xfrm.createDuplicate());
            duplicate.xfrm.setParent(duplicate);
        }
        if(this.geometry!=null)
        {
            duplicate.setGeometry(this.geometry.createDuplicate());
        }
        if(this.Fill!=null)
        {
            duplicate.setFill(this.Fill.createDuplicate());
        }
        if(this.ln!=null)
        {
            duplicate.setLn(this.ln.createDuplicate());
        }
        return duplicate;
    },

    checkUniFillRasterImageId: function(unifill)
    {
        if(unifill && unifill.fill && typeof unifill.fill.RasterImageId === "string" && unifill.fill.RasterImageId.length > 0)
            return unifill.fill.RasterImageId;
        return null;
    },

    checkBlipFillRasterImage: function(images)
    {
        var fill_image_id = this.checkUniFillRasterImageId(this.Fill);
        if(fill_image_id !== null)
            images.push(fill_image_id);
        if(this.ln)
        {
            var line_image_id = this.checkUniFillRasterImageId(this.ln.Fill);
            if(line_image_id)
                images.push(line_image_id);
        }
    },

    merge: function(spPr)
    {
        /*if(spPr.xfrm != null)
         {
         this.xfrm.merge(spPr.xfrm);
         }  */
        if(spPr.geometry!=null)
        {
            this.geometry = spPr.geometry.createDuplicate();
        }

        if(spPr.Fill!=null && spPr.Fill.fill!=null)
        {
            //this.Fill = spPr.Fill.createDuplicate();
        }

        /*if(spPr.ln!=null)
         {
         if(this.ln == null)
         this.ln = new CLn();
         this.ln.merge(spPr.ln);
         }  */
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_SpPr;
    },

    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    },

    checkFromSerialize: function()
    {
        if(this.parent && this.parent.deleteBFromSerialize)
        {
            this.parent.deleteBFromSerialize();
        }
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_SpPr_SetParent, this.parent,  pr));
        this.parent = pr;
    },

    setBwMode: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_SpPr_SetBwMode, this.bwMode,  pr));
        this.bwMode = pr;
    },

    setXfrm: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_SpPr_SetXfrm, this.xfrm,  pr));
        this.xfrm = pr;
    },

    setGeometry: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_SpPr_SetGeometry, this.geometry,  pr));
        this.geometry = pr;
        if(this.geometry){
            this.geometry.setParent(this);
        }
        this.handleUpdateGeometry();
    },

    setFill: function(pr)
    {
        History.Add(new CChangesDrawingsObjectNoId(this, AscDFH.historyitem_SpPr_SetFill, this.Fill,  pr));
        this.Fill = pr;
        if(this.parent && this.parent.handleUpdateFill)
        {
            this.parent.handleUpdateFill();
        }
    },

    setLn: function(pr)
    {
        History.Add(new CChangesDrawingsObjectNoId(this, AscDFH.historyitem_SpPr_SetLn, this.ln,  pr));
        this.ln = pr;
        if(this.parent && this.parent.handleUpdateLn)
        {
            this.parent.handleUpdateLn();
        }
    },

    handleUpdatePosition: function()
    {
        if(this.parent && this.parent.handleUpdatePosition)
        {
            this.parent.handleUpdatePosition();
        }
    },

    handleUpdateExtents: function()
    {
        if(this.parent && this.parent.handleUpdateExtents)
        {
            this.parent.handleUpdateExtents();
        }
    },

    handleUpdateChildOffset: function()
    {
        if(this.parent && this.parent.handleUpdateChildOffset)
        {
            this.parent.handleUpdateChildOffset();
        }
    },

    handleUpdateChildExtents: function()
    {
        if(this.parent && this.parent.handleUpdateChildExtents)
        {
            this.parent.handleUpdateChildExtents();
        }
    },

    handleUpdateFlip: function()
    {
        if(this.parent && this.parent.handleUpdateFlip)
        {
            this.parent.handleUpdateFlip();
        }
    },

    handleUpdateRot: function()
    {
        if(this.parent && this.parent.handleUpdateRot)
        {
            this.parent.handleUpdateRot();
        }
    },


    handleUpdateGeometry: function()
    {
        if(this.parent && this.parent.handleUpdateGeometry)
        {
            this.parent.handleUpdateGeometry();
        }
    },

    handleUpdateFill: function()
    {
        if(this.parent && this.parent.handleUpdateFill)
        {
            this.parent.handleUpdateFill();
        }
    },
    handleUpdateLn: function()
    {
        if(this.parent && this.parent.handleUpdateLn)
        {
            this.parent.handleUpdateLn();
        }
    }
};
// ----------------------------------

// THEME ----------------------------

var g_clr_MIN = 0;
var g_clr_accent1 = 0;
var g_clr_accent2 = 1;
var g_clr_accent3 = 2;
var g_clr_accent4 = 3;
var g_clr_accent5 = 4;
var g_clr_accent6 = 5;
var g_clr_dk1 = 6;
var g_clr_dk2 = 7;
var g_clr_folHlink = 8;
var g_clr_hlink = 9;
var g_clr_lt1 = 10;
var g_clr_lt2 = 11;
var g_clr_MAX = 11;

var g_clr_bg1 = g_clr_lt1;
var g_clr_bg2 = g_clr_lt2;
var g_clr_tx1 = g_clr_dk1;
var g_clr_tx2 = g_clr_dk2;

var phClr   = 14;
var tx1     = 15;
var tx2     = 16;

function ClrScheme()
{
    this.name = "";
    this.colors = [];

    for (var i = g_clr_MIN; i <= g_clr_MAX; i++)
        this.colors[i] = null;

}

ClrScheme.prototype =
{
    isIdentical: function(clrScheme)
    {
        if(clrScheme == null)
        {
            return false;
        }
        if(!(clrScheme instanceof ClrScheme) )
        {
            return false;
        }
        if(clrScheme.name != this.name)
        {
            return false;
        }
        for(var _clr_index = g_clr_MIN; _clr_index <= g_clr_MAX; ++_clr_index)
        {
            if(this.colors[_clr_index] != clrScheme.colors[_clr_index])
            {
                return false;
            }
        }
        return true;
    },

    createDuplicate: function()
    {
        var _duplicate = new ClrScheme();
        _duplicate.name = this.name;
        for(var _clr_index = 0; _clr_index <= this.colors.length; ++_clr_index)
        {
            _duplicate.colors[_clr_index] = this.colors[_clr_index];
        }
        return _duplicate;
    },

    Write_ToBinary: function (w)
    {
        w.WriteLong(this.colors.length);
        w.WriteString2(this.name);
        for(var i = 0; i < this.colors.length; ++i)
        {
            w.WriteBool(isRealObject(this.colors[i]));
            if(isRealObject(this.colors[i]))
            {
                this.colors[i].Write_ToBinary(w);
            }
        }

    },

    Read_FromBinary: function (r)
    {
        var len = r.GetLong();
        this.name = r.GetString2();
        for(var i = 0; i < len; ++i)
        {
            if(r.GetBool())
            {
                this.colors[i] = new CUniColor();
                this.colors[i].Read_FromBinary(r);
            }
            else
            {
                this.colors[i] = null;
            }
        }

    },

    setName: function(name)
    {
        this.name = name;
    },

    addColor: function(index, color)
    {
        this.colors[index] = color;
    }
};

function ClrMap()
{
    this.color_map = [];

    for (var i = g_clr_MIN; i <= g_clr_MAX; i++)
        this.color_map[i] = null;


    if (g_oTableId.checkInit())
    {
        this.Id = g_oIdCounter.Get_NewId();
        g_oTableId.Add(this, this.Id);
    }

}

ClrMap.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    createDuplicate:  function()
    {
        var _copy = new ClrMap();
        for(var _color_index = g_clr_MIN; _color_index <= this.color_map.length; ++_color_index)
        {
            _copy.setClr(_color_index, this.color_map[_color_index]);
        }
        return _copy;
    },

    compare: function(other)
    {
        if(!other)
            return false;
        for(var i = g_clr_MIN; i < this.color_map.length; ++i)
        {
            if(this.color_map[i] !== other.color_map[i])
            {
                return false;
            }
        }
        return true;
    },


    getObjectType: function()
    {
        return AscDFH.historyitem_type_ClrMap;
    },

    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    },

    setClr: function(index, clr)
    {
        History.Add(new CChangesDrawingsContentLongMap(this, AscDFH.historyitem_ClrMap_SetClr, index, [clr], true));
        this.color_map[index] = clr;
    }
};
function ExtraClrScheme()
{
    this.clrScheme = null;
    this.clrMap = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

ExtraClrScheme.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_ExtraClrScheme;
    },

    setClrScheme: function(pr)
    {
        History.Add(new CChangesDrawingsObjectNoId(this, AscDFH.historyitem_ExtraClrScheme_SetClrScheme, this.clrScheme,  pr));
        this.clrScheme = pr;
    },

    setClrMap: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ExtraClrScheme_SetClrMap, this.clrMap,  pr));
        this.clrMap = pr;
    },

    createDuplicate: function()
    {
        var ret = new ExtraClrScheme();
        if(this.clrScheme)
        {
            ret.setClrScheme(this.clrScheme.createDuplicate())
        }
        if(this.clrMap)
        {
            ret.setClrMap(this.clrMap.createDuplicate());
        }
        return ret;
    },

    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    }
};

function FontCollection(fontScheme)
{

    this.latin = null;
    this.ea   = null;
    this.cs   = null;
    if(fontScheme)
    {
        this.setFontScheme(fontScheme);
    }
}

FontCollection.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    setFontScheme: function(fontScheme)
    {
        this.fontScheme = fontScheme;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_FontCollection;
    },


    setLatin: function(pr)
    {
        this.latin = pr;
        if(this.fontScheme)
            this.fontScheme.checkFromFontCollection(pr, this, FONT_REGION_LT);
    },

    setEA: function(pr)
    {
        this.ea = pr;
        if(this.fontScheme)
            this.fontScheme.checkFromFontCollection(pr, this, FONT_REGION_EA);
    },

    setCS: function(pr)
    {
        this.cs = pr;
        if(this.fontScheme)
            this.fontScheme.checkFromFontCollection(pr, this, FONT_REGION_CS);
    },


    Write_ToBinary: function (w)
    {
        writeString(w, this.latin);
        writeString(w, this.ea   );
        writeString(w, this.cs   );
    },

    Read_FromBinary: function (r)
    {
        this.latin = readString(r);
        this.ea = readString(r);
        this.cs = readString(r);

        if(this.fontScheme)
        {
            this.fontScheme.checkFromFontCollection(this.latin, this, FONT_REGION_LT);
            this.fontScheme.checkFromFontCollection(this.ea, this, FONT_REGION_EA);
            this.fontScheme.checkFromFontCollection(this.cs, this, FONT_REGION_CS);
        }
    }
};

function FontScheme()
{
    this.name = "";

    this.majorFont = new FontCollection(this);
    this.minorFont = new FontCollection(this);
    this.fontMap = {
        "+mj-lt": undefined,
        "+mj-ea": undefined,
        "+mj-cs": undefined,
        "+mn-lt": undefined,
        "+mn-ea": undefined,
        "+mn-cs": undefined
    };
}

var FONT_REGION_LT = 0x00;
var FONT_REGION_EA = 0x01;
var FONT_REGION_CS = 0x02;

FontScheme.prototype =
{
    createDuplicate: function()
    {
        var oCopy = new FontScheme();
        oCopy.majorFont.setLatin(this.majorFont.latin);
        oCopy.majorFont.setEA(this.majorFont.ea);
        oCopy.majorFont.setCS(this.majorFont.cs);

        oCopy.minorFont.setLatin(this.minorFont.latin);
        oCopy.minorFont.setEA(this.minorFont.ea);
        oCopy.minorFont.setCS(this.minorFont.cs);
        return oCopy;
    },

    Refresh_RecalcData: function()
    {},

    Write_ToBinary: function (w)
    {
        this.majorFont.Write_ToBinary(w);
        this.minorFont.Write_ToBinary(w);
    },

    Read_FromBinary: function (r)
    {
        this.majorFont.Read_FromBinary(r);
        this.minorFont.Read_FromBinary(r);
    },

    checkFromFontCollection: function(font, fontCollection, region)
    {
        if(fontCollection === this.majorFont)
        {
            switch (region)
            {
                case FONT_REGION_LT:
                {
                    this.fontMap["+mj-lt"] = font;
                    break;
                }
                case FONT_REGION_EA:
                {
                    this.fontMap["+mj-ea"] = font;
                    break;
                }
                case FONT_REGION_CS:
                {
                    this.fontMap["+mj-cs"] = font;
                    break;
                }
            }
        }
        else if(fontCollection === this.minorFont)
        {
            switch (region)
            {
                case FONT_REGION_LT:
                {
                    this.fontMap["+mn-lt"] = font;
                    break;
                }
                case FONT_REGION_EA:
                {
                    this.fontMap["+mn-ea"] = font;
                    break;
                }
                case FONT_REGION_CS:
                {
                    this.fontMap["+mn-cs"] = font;
                    break;
                }
            }
        }
    },

    checkFont: function(font)
    {
        if(g_oThemeFontsName[font])
        {
            if(this.fontMap[font])
            {
                return this.fontMap[font];
            }
            else if(this.fontMap["+mn-lt"])
            {
                return this.fontMap["+mn-lt"];
            }
            else
            {
                return "Arial";
            }
        }
        return font;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_FontScheme;
    },


    setName: function(pr)
    {
        this.name = pr;
    },

    setMajorFont: function(pr)
    {
        this.majorFont = pr;
    },
    setMinorFont: function(pr)
    {
        this.minorFont = pr;
    }
};

function FmtScheme()
{
    this.name           = "";
    this.fillStyleLst   = [];
    this.lnStyleLst     = [];
    this.effectStyleLst = null;
    this.bgFillStyleLst = [];
}

FmtScheme.prototype =
{
    GetFillStyle: function(number, unicolor)
    {
        if (number >= 1 && number <= 999)
        {
            var ret = this.fillStyleLst[number - 1];
            if (!ret)
                return null;
            var ret2 = ret.createDuplicate();
            ret2.checkPhColor(unicolor);
            return ret2;
        }
        else if (number >= 1001)
        {
            var ret = this.bgFillStyleLst[number - 1001];
            if (!ret)
                return null;
            var ret2 = ret.createDuplicate();
            ret2.checkPhColor(unicolor);
            return ret2;
        }
        return null;
    },

    Write_ToBinary: function (w)
    {
        writeString(w, this.name);
        var i;
        w.WriteLong(this.fillStyleLst.length);
        for(i = 0; i < this.fillStyleLst.length; ++i)
        {
            this.fillStyleLst[i].Write_ToBinary(w);
        }

        w.WriteLong(this.lnStyleLst.length);
        for(i = 0; i < this.lnStyleLst.length; ++i)
        {
            this.lnStyleLst[i].Write_ToBinary(w);
        }

        w.WriteLong(this.bgFillStyleLst.length);
        for(i = 0; i < this.bgFillStyleLst.length; ++i)
        {
            this.bgFillStyleLst[i].Write_ToBinary(w);
        }
    },

    Read_FromBinary: function (r)
    {
        this.name = readString(r);
        var _len = r.GetLong(), i;
        for(i = 0; i < _len; ++i)
        {
            this.fillStyleLst[i] = new CUniFill();
            this.fillStyleLst[i].Read_FromBinary(r);
        }

        _len = r.GetLong();
        for(i = 0; i < _len; ++i)
        {
            this.lnStyleLst[i] = new CLn();
            this.lnStyleLst[i].Read_FromBinary(r);
        }

        _len = r.GetLong();
        for(i = 0; i < _len; ++i)
        {
            this.bgFillStyleLst[i] = new CUniFill();
            this.bgFillStyleLst[i].Read_FromBinary(r);
        }
    },

    createDuplicate: function()
    {
        var oCopy = new FmtScheme();
        oCopy.name = this.name;
        var i;
        for(i = 0; i < this.fillStyleLst.length; ++i)
        {
            oCopy.fillStyleLst[i] = this.fillStyleLst[i].createDuplicate();
        }
        for(i = 0; i < this.lnStyleLst.length; ++i)
        {
            oCopy.lnStyleLst[i] = this.lnStyleLst[i].createDuplicate();
        }

        for(i = 0; i < this.bgFillStyleLst.length; ++i)
        {
            oCopy.bgFillStyleLst[i] = this.bgFillStyleLst[i].createDuplicate();
        }
        return oCopy;
    },

    setName: function(pr)
    {
        this.name = pr;
    },
    addFillToStyleLst: function(pr)
    {
        this.fillStyleLst.push(pr);
    },
    addLnToStyleLst: function(pr)
    {
        this.lnStyleLst.push(pr);
    },
    addEffectToStyleLst: function(pr)
    {
        this.effectStyleLst.push(pr);
    },
    addBgFillToStyleLst: function(pr)
    {
        this.bgFillStyleLst.push(pr);
    }
};

function ThemeElements()
{
    this.clrScheme = new ClrScheme();
    this.fontScheme = new FontScheme();
    this.fmtScheme = new FmtScheme();
}

function CTheme()
{
    this.name = "";
    this.themeElements = new ThemeElements();
    this.spDef = null;
    this.lnDef = null;
    this.txDef = null;

    this.extraClrSchemeLst = [];

    this.isThemeOverride = false;

    // pointers
    this.presentation = null;
    this.clrMap = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}


CTheme.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    createDuplicate: function()
    {
        var oTheme = new CTheme();
        oTheme.setName(this.name);
        oTheme.changeColorScheme(this.themeElements.clrScheme.createDuplicate());
        oTheme.setFontScheme(this.themeElements.fontScheme.createDuplicate());
        oTheme.setFormatScheme(this.themeElements.fmtScheme.createDuplicate());
        if(this.spDef){
            oTheme.setSpDef(this.spDef.createDuplicate());
        }
        if(this.lnDef)
        {
            oTheme.setLnDef(this.lnDef.createDuplicate());
        }
        if(this.txDef)
        {
            oTheme.setTxDef(this.txDef.createDuplicate());
        }
        for(var i = 0; i < this.extraClrSchemeLst.length; ++i)
        {
            oTheme.addExtraClrSceme(this.extraClrSchemeLst[i].createDuplicate());
        }
        return oTheme;
    },

    Document_Get_AllFontNames: function(AllFonts)
    {
        var font_scheme = this.themeElements.fontScheme;
        var major_font = font_scheme.majorFont;
        typeof major_font.latin === "string" && major_font.latin.length > 0 && (AllFonts[major_font.latin] = 1);
        typeof major_font.ea === "string" && major_font.ea.length > 0 && (AllFonts[major_font.ea] = 1);
        typeof major_font.cs === "string" && major_font.latin.length > 0 && (AllFonts[major_font.cs] = 1);
        var minor_font = font_scheme.minorFont;
        typeof minor_font.latin === "string" && minor_font.latin.length > 0 && (AllFonts[minor_font.latin] = 1);
        typeof minor_font.ea === "string" && minor_font.ea.length > 0 && (AllFonts[minor_font.ea] = 1);
        typeof minor_font.cs === "string" && minor_font.latin.length > 0 && (AllFonts[minor_font.cs] = 1);
    },

    getFillStyle: function(idx, unicolor)
    {
        if(idx === 0 || idx === 1000)
        {
            return AscFormat.CreateNoFillUniFill();
        }
        var ret;
        if (idx >= 1 && idx <= 999)
        {
            if (this.themeElements.fmtScheme.fillStyleLst[idx-1])
            {
                ret = this.themeElements.fmtScheme.fillStyleLst[idx-1].createDuplicate();
                if(ret)
                {
                    ret.checkPhColor(unicolor);
                    return ret;
                }
            }
        }
        else if (idx >= 1001)
        {
            if (this.themeElements.fmtScheme.bgFillStyleLst[idx-1001])
            {
                ret = this.themeElements.fmtScheme.bgFillStyleLst[idx-1001].createDuplicate();
                if(ret)
                {
                    ret.checkPhColor(unicolor);
                    return ret;
                }
            }
        }
        return CreateSolidFillRGBA(0, 0, 0, 255);
    },

    getLnStyle: function(idx, unicolor)
    {
        if (this.themeElements.fmtScheme.lnStyleLst[idx-1])
        {
            var ret = this.themeElements.fmtScheme.lnStyleLst[idx-1].createDuplicate();
            if(ret.Fill)
            {
                ret.Fill.checkPhColor(unicolor);
            }
            return ret;
        }
        return new CLn();
    },

    changeColorScheme: function(clrScheme)
    {
        History.Add(new CChangesDrawingsObjectNoId(this, AscDFH.historyitem_ThemeSetColorScheme, this.themeElements.clrScheme,  clrScheme));
        this.themeElements.clrScheme = clrScheme;
    },

    setFontScheme: function(fontScheme)
    {
        History.Add(new CChangesDrawingsObjectNoId(this, AscDFH.historyitem_ThemeSetFontScheme, this.themeElements.fontScheme,  fontScheme));
        this.themeElements.fontScheme = fontScheme;
    },

    setFormatScheme: function(fmtScheme)
    {
        History.Add(new CChangesDrawingsObjectNoId(this, AscDFH.historyitem_ThemeSetFmtScheme, this.themeElements.fmtScheme,  fmtScheme));
        this.themeElements.fmtScheme = fmtScheme;
    },

    setName: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_ThemeSetName, this.name,  pr));
        this.name = pr;
    },

    setIsThemeOverride: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_ThemeSetIsThemeOverride, this.isThemeOverride,  pr));
        this.isThemeOverride = pr;
    },


    setSpDef: function(pr){
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ThemeSetSpDef, this.spDef, pr));
        this.spDef = pr;
    },
    setLnDef: function(pr){
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ThemeSetLnDef, this.spDef, pr));
        this.lnDef = pr;
    },
    setTxDef: function(pr){
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ThemeSetTxDef, this.spDef, pr));
        this.txDef = pr;
    },


    addExtraClrSceme: function(pr, idx)
    {
        var pos;
        if(AscFormat.isRealNumber(idx))
            pos = idx;
        else
            pos = this.extraClrSchemeLst.length;
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_ThemeAddExtraClrScheme, pos, [pr], true));
        this.extraClrSchemeLst.splice(pos, 0, pr);
    },


    GetWordDrawingObjects: function(){
        var oRet = typeof editor !== "undefined" &&
            editor.WordControl &&
            editor.WordControl.m_oLogicDocument &&
            editor.WordControl.m_oLogicDocument.DrawingObjects;
        return AscCommon.isRealObject(oRet) ? oRet : null;
    },

    Refresh_RecalcData: function(oData)
    {
        if(oData){
            if(oData.Type === AscDFH.historyitem_ThemeSetColorScheme){
                var oWordGraphicObject = this.GetWordDrawingObjects();
                if(oWordGraphicObject){
                    History.RecalcData_Add({All: true});
                    for(var i = 0; i < oWordGraphicObject.drawingObjects.length; ++i){
                        if(oWordGraphicObject.drawingObjects[i].GraphicObj){
                            oWordGraphicObject.drawingObjects[i].GraphicObj.handleUpdateFill();
                            oWordGraphicObject.drawingObjects[i].GraphicObj.handleUpdateLn();
                        }
                    }
                    oWordGraphicObject.document.Api.chartPreviewManager.clearPreviews();
                    oWordGraphicObject.document.Api.textArtPreviewManager.clear();
                }
            }
        }
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_Theme;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(AscDFH.historyitem_type_Theme);
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    }
};
// ----------------------------------

// CSLD -----------------------------

function HF()
{
    this.dt     = true;
    this.ftr    = true;
    this.hdr    = true;
    this.sldNum = true;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

HF.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function()
    {},
    getObjectType: function()
    {
        return AscDFH.historyitem_type_HF;
    },

    createDuplicate: function()
    {
        var ret = new HF();
        if(ret.dt !== this.dt){
            ret.setDt(this.dt);
        }
        if(ret.ftr !== this.ftr){
            ret.setFtr(this.ftr);
        }
        if(ret.hdr !== this.hdr){
            ret.setHdr(this.hdr);
        }
        if(ret.sldNum !== this.sldNum){
            ret.setSldNum(this.sldNum);
        }
        return ret;
    },

    setDt: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_HF_SetDt, this.dt,  pr));
        this.dt = pr;
    },
    setFtr: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_HF_SetFtr, this.ftr,  pr));
        this.ftr = pr;
    },
    setHdr: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_HF_SetHdr, this.hdr,  pr));
        this.hdr = pr;
    },
    setSldNum: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_HF_SetSldNum, this.sldNum,  pr));
        this.sldNum = pr;
    },

    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    }
};

function CBgPr()
{
    this.Fill         = null;
    this.shadeToTitle = false;

}

CBgPr.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    merge: function(bgPr)
    {

        if(this.Fill == null)
        {
            this.Fill = new CUniFill();
            if(bgPr.Fill != null)
            {
                this.Fill.merge(bgPr.Fill)
            }
        }
    },

    createFullCopy: function()
    {
        var _copy = new CBgPr();
        if(this.Fill != null)
        {
            _copy.Fill = this.Fill.createDuplicate();
        }
        _copy.shadeToTitle = this.shadeToTitle;
        return _copy;
    },

    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_BgPr;
    },

    setFill: function(pr)
    {
        this.Fill = pr;
    },

    setShadeToTitle: function(pr)
    {
        this.shadeToTitle = pr;
    },

    Write_ToBinary: function (w)
    {
        w.WriteBool(isRealObject(this.Fill));
        if(isRealObject(this.Fill))
        {
            this.Fill.Write_ToBinary(w);
        }
        w.WriteBool(this.shadeToTitle);
    },

    Read_FromBinary: function (r)
    {
        if(r.GetBool())
        {
            this.Fill = new CUniFill();
            this.Fill.Read_FromBinary(r);
        }
        this.shadeToTitle = r.GetBool();
    }
};

function CBg()
{
    this.bwMode = null;
    this.bgPr   = null;
    this.bgRef  = null;
}

CBg.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    setBwMode: function(pr)
    {
        this.bwMode = pr;
    },
    setBgPr: function(pr)
    {
        this.bgPr = pr;
    },
    setBgRef: function(pr)
    {
        this.bgRef = pr;
    },

    merge:  function(bg)
    {
        if(this.bgPr == null)
        {
            this.bgPr = new CBgPr();
            if(bg.bgPr != null)
            {
                this.bgPr.merge(bg.bgPr);
            }
        }
    },

    createFullCopy: function()
    {
        var _copy = new CBg();
        _copy.bwMode = this.bwMode;
        if(this.bgPr != null)
        {
            _copy.bgPr = this.bgPr.createFullCopy();
        }
        if(this.bgRef != null)
        {
            _copy.bgRef = this.bgRef.createDuplicate();
        }
        return _copy;
    },

    Write_ToBinary: function(w)
    {
        w.WriteBool(isRealObject(this.bgPr));
        if(isRealObject(this.bgPr))
        {
            this.bgPr.Write_ToBinary(w);
        }
        w.WriteBool(isRealObject(this.bgRef));
        if(isRealObject(this.bgRef))
        {
            this.bgRef.Write_ToBinary(w);
        }
    },

    Read_FromBinary: function(r)
    {
        if(r.GetBool())
        {
            this.bgPr = new CBgPr();
            this.bgPr.Read_FromBinary(r);
        }
        if(r.GetBool())
        {
            this.bgRef = new StyleRef();
            this.bgRef.Read_FromBinary(r);
        }
    }
};

function CSld()
{
    this.name = "";
    this.Bg = null;
    this.spTree = [];//new GroupShape();
}

// ----------------------------------

// MASTERSLIDE ----------------------

function CTextStyle()
{
    this.defPPr = null;
    this.lvl1pPr = null;
    this.lvl2pPr = null;
    this.lvl3pPr = null;
    this.lvl4pPr = null;
    this.lvl5pPr = null;
    this.lvl6pPr = null;
    this.lvl7pPr = null;
    this.lvl8pPr = null;
    this.lvl9pPr = null;
}

CTextStyle.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {}
};

function CTextStyles()
{
    this.titleStyle = null;
    this.bodyStyle = null;
    this.otherStyle = null;

}


CTextStyles.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    createDuplicate: function()
    {
        var ret = new CTextStyles();
        if(isRealObject(this.titleStyle))
        {
            ret.titleStyle = this.titleStyle.createDuplicate();
        }

        if(isRealObject(this.bodyStyle))
        {
            ret.bodyStyle = this.bodyStyle.createDuplicate();
        }

        if(isRealObject(this.otherStyle))
        {
            ret.otherStyle = this.otherStyle.createDuplicate();
        }
        return ret;
    },

    Refresh_RecalcData: function()
    {},

    Write_ToBinary: function(w)
    {
        w.WriteBool(isRealObject(this.titleStyle));
        if(isRealObject(this.titleStyle))
        {
            this.titleStyle.Write_ToBinary(w);
        }


        w.WriteBool(isRealObject(this.bodyStyle));
        if(isRealObject(this.bodyStyle))
        {
            this.bodyStyle.Write_ToBinary(w);
        }

        w.WriteBool(isRealObject(this.otherStyle));
        if(isRealObject(this.otherStyle))
        {
            this.otherStyle.Write_ToBinary(w);
        }
    },

    Read_FromBinary: function(r)
    {
        if(r.GetBool())
        {
            this.titleStyle = new TextListStyle();
            this.titleStyle.Read_FromBinary(r);
        }
        else
        {
            this.titleStyle = null;
        }


        if(r.GetBool())
        {
            this.bodyStyle = new TextListStyle();
            this.bodyStyle.Read_FromBinary(r);
        }
        else
        {
            this.bodyStyle = null;
        }

        if(r.GetBool())
        {
            this.otherStyle = new TextListStyle();
            this.otherStyle.Read_FromBinary(r);
        }
        else
        {
            this.otherStyle = null;
        }
    },

    Document_Get_AllFontNames: function(AllFonts){
        if(this.titleStyle){
            this.titleStyle.Document_Get_AllFontNames(AllFonts);
        }
        if(this.bodyStyle){
            this.bodyStyle.Document_Get_AllFontNames(AllFonts);
        }
        if(this.otherStyle){
            this.otherStyle.Document_Get_AllFontNames(AllFonts);
        }
    }

};

//---------------------------

// SLIDELAYOUT ----------------------

//Layout types
var nSldLtTBlank                   = 0; // Blank ))
var nSldLtTChart                   = 1; //Chart)
var nSldLtTChartAndTx              = 2; //( Chart and Text ))
var nSldLtTClipArtAndTx            = 3; //Clip Art and Text)
var nSldLtTClipArtAndVertTx        = 4; //Clip Art and Vertical Text)
var nSldLtTCust                    = 5; // Custom ))
var nSldLtTDgm                     = 6; //Diagram ))
var nSldLtTFourObj                 = 7; //Four Objects)
var nSldLtTMediaAndTx              = 8; // ( Media and Text ))
var nSldLtTObj                     = 9; //Title and Object)
var nSldLtTObjAndTwoObj            = 10; //Object and Two Object)
var nSldLtTObjAndTx                = 11; // ( Object and Text ))
var nSldLtTObjOnly                 = 12; //Object)
var nSldLtTObjOverTx               = 13; // ( Object over Text))
var nSldLtTObjTx                   = 14; //Title, Object, and Caption)
var nSldLtTPicTx                   = 15; //Picture and Caption)
var nSldLtTSecHead                 = 16; //Section Header)
var nSldLtTTbl                     = 17; // ( Table ))
var nSldLtTTitle                   = 18; // ( Title ))
var nSldLtTTitleOnly               = 19; // ( Title Only ))
var nSldLtTTwoColTx                = 20; // ( Two Column Text ))
var nSldLtTTwoObj                  = 21; //Two Objects)
var nSldLtTTwoObjAndObj            = 22; //Two Objects and Object)
var nSldLtTTwoObjAndTx             = 23; //Two Objects and Text)
var nSldLtTTwoObjOverTx            = 24; //Two Objects over Text)
var nSldLtTTwoTxTwoObj             = 25; //Two Text and Two Objects)
var nSldLtTTx                      = 26; // ( Text ))
var nSldLtTTxAndChart              = 27; // ( Text and Chart ))
var nSldLtTTxAndClipArt            = 28; //Text and Clip Art)
var nSldLtTTxAndMedia              = 29; // ( Text and Media ))
var nSldLtTTxAndObj                = 30; // ( Text and Object ))
var nSldLtTTxAndTwoObj             = 31; //Text and Two Objects)
var nSldLtTTxOverObj               = 32; // ( Text over Object))
var nSldLtTVertTitleAndTx          = 33; //Vertical Title and Text)
var nSldLtTVertTitleAndTxOverChart = 34; //Vertical Title and Text Over Chart)
var nSldLtTVertTx                  = 35; //Vertical Text)

var _ph_multiplier = 4;

var _weight_body = 9;
var _weight_chart = 5;
var _weight_clipArt = 2;
var _weight_ctrTitle = 11;
var _weight_dgm = 4;
var _weight_media = 3;
var _weight_obj = 8;
var _weight_pic = 7;
var _weight_subTitle = 10;
var _weight_tbl = 6;
var _weight_title = 11;

var _ph_summ_blank = 0;
var _ph_summ_chart = Math.pow(_ph_multiplier, _weight_title) + Math.pow(_ph_multiplier, _weight_chart);
var _ph_summ_chart_and_tx = Math.pow(_ph_multiplier, _weight_title) + Math.pow(_ph_multiplier, _weight_chart) + Math.pow(_ph_multiplier, _weight_body);
var _ph_summ_dgm = Math.pow(_ph_multiplier, _weight_title) + Math.pow(_ph_multiplier, _weight_dgm);
var _ph_summ_four_obj = Math.pow(_ph_multiplier, _weight_title) + 4*Math.pow(_ph_multiplier, _weight_obj);
var _ph_summ__media_and_tx = Math.pow(_ph_multiplier, _weight_title) + Math.pow(_ph_multiplier, _weight_media) + Math.pow(_ph_multiplier, _weight_body);
var _ph_summ__obj = Math.pow(_ph_multiplier, _weight_title) + Math.pow(_ph_multiplier, _weight_obj);
var _ph_summ__obj_and_two_obj = Math.pow(_ph_multiplier, _weight_title) + 3*Math.pow(_ph_multiplier, _weight_obj);
var _ph_summ__obj_and_tx = Math.pow(_ph_multiplier, _weight_title) + Math.pow(_ph_multiplier, _weight_obj) + Math.pow(_ph_multiplier, _weight_body);
var _ph_summ__obj_only = Math.pow(_ph_multiplier, _weight_obj);
var _ph_summ__pic_tx = Math.pow(_ph_multiplier, _weight_title) + Math.pow(_ph_multiplier, _weight_pic) + Math.pow(_ph_multiplier, _weight_body);
var _ph_summ__sec_head = Math.pow(_ph_multiplier, _weight_title) + Math.pow(_ph_multiplier, _weight_subTitle);
var _ph_summ__tbl = Math.pow(_ph_multiplier, _weight_title) + Math.pow(_ph_multiplier, _weight_tbl);
var _ph_summ__title_only = Math.pow(_ph_multiplier, _weight_title);
var _ph_summ__two_col_tx = Math.pow(_ph_multiplier, _weight_title) + 2*Math.pow(_ph_multiplier, _weight_body);
var _ph_summ__two_obj_and_tx = Math.pow(_ph_multiplier, _weight_title) + 2*Math.pow(_ph_multiplier, _weight_obj) + Math.pow(_ph_multiplier, _weight_body);
var _ph_summ__two_obj_and_two_tx = Math.pow(_ph_multiplier, _weight_title) + 2*Math.pow(_ph_multiplier, _weight_obj) +2* Math.pow(_ph_multiplier, _weight_body);
var _ph_summ__tx = Math.pow(_ph_multiplier, _weight_title) + Math.pow(_ph_multiplier, _weight_body);
var _ph_summ__tx_and_clip_art = Math.pow(_ph_multiplier, _weight_title) + Math.pow(_ph_multiplier, _weight_body) + + Math.pow(_ph_multiplier, _weight_clipArt);

var _arr_lt_types_weight = [];
_arr_lt_types_weight[0] =   _ph_summ_blank;
_arr_lt_types_weight[1] =   _ph_summ_chart;
_arr_lt_types_weight[2] =   _ph_summ_chart_and_tx;
_arr_lt_types_weight[3] =   _ph_summ_dgm;
_arr_lt_types_weight[4] =   _ph_summ_four_obj;
_arr_lt_types_weight[5] =   _ph_summ__media_and_tx;
_arr_lt_types_weight[6] =   _ph_summ__obj;
_arr_lt_types_weight[7] =   _ph_summ__obj_and_two_obj;
_arr_lt_types_weight[8] =   _ph_summ__obj_and_tx;
_arr_lt_types_weight[9] =   _ph_summ__obj_only;
_arr_lt_types_weight[10] =  _ph_summ__pic_tx;
_arr_lt_types_weight[11] =  _ph_summ__sec_head;
_arr_lt_types_weight[12] =  _ph_summ__tbl;
_arr_lt_types_weight[13] =  _ph_summ__title_only;
_arr_lt_types_weight[14] =  _ph_summ__two_col_tx;
_arr_lt_types_weight[15] =  _ph_summ__two_obj_and_tx;
_arr_lt_types_weight[16] =  _ph_summ__two_obj_and_two_tx;
_arr_lt_types_weight[17] =  _ph_summ__tx;
_arr_lt_types_weight[18] =  _ph_summ__tx_and_clip_art;

_arr_lt_types_weight.sort(AscCommon.fSortAscending);


var _global_layout_summs_array = {};
_global_layout_summs_array["_" + _ph_summ_blank] = nSldLtTBlank;
_global_layout_summs_array["_" + _ph_summ_chart] = nSldLtTChart;
_global_layout_summs_array["_" + _ph_summ_chart_and_tx] = nSldLtTChartAndTx;
_global_layout_summs_array["_" + _ph_summ_dgm] = nSldLtTDgm;
_global_layout_summs_array["_" + _ph_summ_four_obj] = nSldLtTFourObj;
_global_layout_summs_array["_" + _ph_summ__media_and_tx] = nSldLtTMediaAndTx;
_global_layout_summs_array["_" + _ph_summ__obj] = nSldLtTObj;
_global_layout_summs_array["_" + _ph_summ__obj_and_two_obj] = nSldLtTObjAndTwoObj;
_global_layout_summs_array["_" + _ph_summ__obj_and_tx] = nSldLtTObjAndTx;
_global_layout_summs_array["_" + _ph_summ__obj_only] = nSldLtTObjOnly;
_global_layout_summs_array["_" + _ph_summ__pic_tx] = nSldLtTPicTx;
_global_layout_summs_array["_" + _ph_summ__sec_head] = nSldLtTSecHead;
_global_layout_summs_array["_" + _ph_summ__tbl] = nSldLtTTbl;
_global_layout_summs_array["_" + _ph_summ__title_only] = nSldLtTTitleOnly;
_global_layout_summs_array["_" + _ph_summ__two_col_tx] = nSldLtTTwoColTx;
_global_layout_summs_array["_" + _ph_summ__two_obj_and_tx] = nSldLtTTwoObjAndTx;
_global_layout_summs_array["_" + _ph_summ__two_obj_and_two_tx] = nSldLtTTwoTxTwoObj;
_global_layout_summs_array["_" + _ph_summ__tx] = nSldLtTTx;
_global_layout_summs_array["_" + _ph_summ__tx_and_clip_art] = nSldLtTTxAndClipArt;


// ----------------------------------

// NOTEMASTER -----------------------

function NoteMaster()
{
    this.cSld = new CSld();
    this.clrMap = new ClrMap();

    this.hf = new HF();
    this.notesStyle = null;

    // pointers
    this.Theme = null;
    this.TableStyles = null;

}

NoteMaster.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    } ,

    Refresh_RecalcData: function()
    {},

    Calculate: function()
    {
        // нужно пробежаться по всем шейпам:
        // учесть тему во всех заливках
        // учесть тему во всех текстовых настройках,
    }
};

// ----------------------------------

// NOTE -----------------------------

function NoteSlide()
{
    this.cSld = new CSld();
    this.clrMap = null; // override ClrMap

    this.showMasterPhAnim = false;
    this.showMasterSp = false;
}

NoteSlide.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    // pointers
    Calculate: function()
    {
        // нужно пробежаться по всем шейпам:
        // учесть тему во всех заливках
        // учесть тему во всех текстовых настройках,
    }
};

// ----------------------------------

// SLIDE ----------------------------
function redrawSlide(slide, presentation, arrInd, pos,  direction, arr_slides)
{
    if(slide)
    {
        slide.recalculate();
        presentation.DrawingDocument.OnRecalculatePage(slide.num, slide);
    }
    if(direction == 0)
    {
        if(pos > 0)
        {
            presentation.backChangeThemeTimeOutId = setTimeout(function(){redrawSlide(arr_slides[arrInd[pos - 1]], presentation, arrInd,pos - 1,  -1, arr_slides)}, recalcSlideInterval);
        }
        else
        {
            presentation.backChangeThemeTimeOutId = null;
        }
        if(pos < arrInd.length-1)
        {
            presentation.forwardChangeThemeTimeOutId = setTimeout(function(){redrawSlide(arr_slides[arrInd[pos + 1]], presentation, arrInd, pos + 1,  +1, arr_slides)}, recalcSlideInterval);
        }
        else
        {
            presentation.forwardChangeThemeTimeOutId = null;
        }
        presentation.startChangeThemeTimeOutId = null;
    }
    if(direction > 0)
    {
        if(pos < arrInd.length-1)
        {
            presentation.forwardChangeThemeTimeOutId =setTimeout(function(){redrawSlide(arr_slides[arrInd[pos + 1]], presentation, arrInd, pos + 1,  +1, arr_slides)}, recalcSlideInterval);
        }
        else
        {
            presentation.forwardChangeThemeTimeOutId = null;
        }
    }
    if(direction < 0)
    {
        if(pos > 0)
        {
            presentation.backChangeThemeTimeOutId = setTimeout(function(){redrawSlide(arr_slides[arrInd[pos - 1]], presentation, arrInd, pos - 1,  -1, arr_slides)}, recalcSlideInterval);
        }
        else
        {
            presentation.backChangeThemeTimeOutId = null;
        }
    }
}


function CTextFit()
{
    this.type           = 0;
    this.fontScale      = null;
    this.lnSpcReduction = null;
}

CTextFit.prototype =
{
    CreateDublicate : function()
    {
        var d = new CTextFit();
        d.type = this.type;
        d.fontScale = this.fontScale;
        d.lnSpcReduction = this.lnSpcReduction;
        return d;
    },


    Write_ToBinary: function(w)
    {
        writeLong(w, this.type);
        writeDouble(w, this.fontScale);
        writeDouble(w, this.lnSpcReduction);
    },

    Read_FromBinary: function(r)
    {
        this.type = readLong(r);
        this.fontScale = readDouble(r);
        this.lnSpcReduction = readDouble(r);
    },

    Get_Id: function()
    {
        return this.Id;
    }  ,
    Refresh_RecalcData: function()
    {}
};

//Overflow Types
var nOTClip     = 0;
var nOTEllipsis = 1;
var nOTOwerflow = 2;
//-----------------------------

//Text Anchoring Types
var nTextATB = 0;// (Text Anchor Enum ( Bottom ))
var nTextATCtr = 1;// (Text Anchor Enum ( Center ))
var nTextATDist = 2;// (Text Anchor Enum ( Distributed ))
var nTextATJust = 3;// (Text Anchor Enum ( Justified ))
var nTextATT = 4;// Top

function CBodyPr()
{
    this.flatTx           = null;
    this.anchor           = null;
    this.anchorCtr        = null;
    this.bIns             = null;
    this.compatLnSpc      = null;
    this.forceAA          = null;
    this.fromWordArt      = null;
    this.horzOverflow     = null;
    this.lIns             = null;
    this.numCol           = null;
    this.rIns             = null;
    this.rot              = null;
    this.rtlCol           = null;
    this.spcCol           = null;
    this.spcFirstLastPara = null;
    this.tIns             = null;
    this.upright          = null;
    this.vert             = null;
    this.vertOverflow     = null;
    this.wrap             = null;
    this.textFit          = null;
    this.prstTxWarp       = null;


    this.parent = null;
  // this.Id = g_oIdCounter.Get_NewId();
  // g_oTableId.Add(this, this.Id);
}

CBodyPr.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    isNotNull: function()
    {
        return this.flatTx          !== null ||
        this.anchor           !== null ||
        this.anchorCtr        !== null ||
        this.bIns             !== null ||
        this.compatLnSpc      !== null ||
        this.forceAA          !== null ||
        this.fromWordArt      !== null ||
        this.horzOverflow     !== null ||
        this.lIns             !== null ||
        this.numCol           !== null ||
        this.rIns             !== null ||
        this.rot              !== null ||
        this.rtlCol           !== null ||
        this.spcCol           !== null ||
        this.spcFirstLastPara !== null ||
        this.tIns             !== null ||
        this.upright          !== null ||
        this.vert             !== null ||
        this.vertOverflow     !== null ||
        this.wrap             !== null ||
        this.textFit          !== null ||
        this.prstTxWarp       !== null;
    },

    setAnchor: function(val)
    {
        this.anchor = val;
    },

    setVert: function(val)
    {
        this.vert = val;
    },

    setRot: function(val)
    {
        this.rot = val;
    },

    reset: function()
    {
        this.flatTx           = null;
        this.anchor           = null;
        this.anchorCtr        = null;
        this.bIns             = null;
        this.compatLnSpc      = null;
        this.forceAA          = null;
        this.fromWordArt      = null;
        this.horzOverflow     = null;
        this.lIns             = null;
        this.numCol           = null;
        this.rIns             = null;
        this.rot              = null;
        this.rtlCol           = null;
        this.spcCol           = null;
        this.spcFirstLastPara = null;
        this.tIns             = null;
        this.upright          = null;
        this.vert             = null;
        this.vertOverflow     = null;
        this.wrap             = null;
        this.textFit          = null;
        this.prstTxWarp       = null;
    },


    WritePrstTxWarp: function(w)
    {
        w.WriteBool(isRealObject(this.prstTxWarp));
        if(isRealObject(this.prstTxWarp))
        {
            writeString(w, this.prstTxWarp.preset);
            var startPos = w.GetCurPosition(), countAv = 0;
            w.Skip(4);
            for(var key in this.prstTxWarp.avLst)
            {
                if(this.prstTxWarp.avLst.hasOwnProperty(key))
                {
                    ++countAv;
                    w.WriteString2(key);
                    w.WriteLong(this.prstTxWarp.gdLst[key]);
                }
            }
            var endPos = w.GetCurPosition();
            w.Seek(startPos);
            w.WriteLong(countAv);
            w.Seek(endPos);
        }
    },

    ReadPrstTxWarp: function(r)
    {
        ExecuteNoHistory(function(){
            if(r.GetBool())
            {
                this.prstTxWarp = AscFormat.CreatePrstTxWarpGeometry(readString(r));
                var count = r.GetLong();
                for(var i = 0; i < count; ++i)
                {
                    var sAdj = r.GetString2();
                    var nVal = r.GetLong();
                    this.prstTxWarp.AddAdj(sAdj, 15, nVal + "", undefined, undefined);
                }
            }
        }, this, []);
    },

    Write_ToBinary2: function(w)
    {
        var flag = this.flatTx != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteLong(this.flatTx);
        }

        flag = this.anchor != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteLong(this.anchor);
        }

        flag = this.anchorCtr != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteBool(this.anchorCtr);
        }

        flag = this.bIns != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteDouble(this.bIns);
        }

        flag = this.compatLnSpc != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteBool(this.compatLnSpc);
        }

        flag = this.forceAA != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteBool(this.forceAA);
        }

        flag = this.fromWordArt != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteBool(this.fromWordArt);
        }

        flag = this.horzOverflow != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteLong(this.horzOverflow);
        }

        flag = this.lIns != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteDouble(this.lIns);
        }

        flag = this.numCol != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteLong(this.numCol);
        }

        flag = this.rIns != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteDouble(this.rIns);
        }


        flag = this.rot != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteLong(this.rot);
        }

        flag = this.rtlCol != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteBool(this.rtlCol);
        }

        flag = this.spcCol != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteDouble(this.spcCol);
        }

        flag = this.spcFirstLastPara != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteBool(this.spcFirstLastPara);
        }

        flag = this.tIns != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteDouble(this.tIns);
        }

        flag = this.upright != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteBool(this.upright);
        }

        flag = this.vert != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteLong(this.vert);
        }


        flag = this.vertOverflow != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteLong(this.vertOverflow);
        }

        flag = this.wrap != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteLong(this.wrap);
        }

        this.WritePrstTxWarp(w);

        w.WriteBool(isRealObject(this.textFit));
        if(this.textFit)
        {
            this.textFit.Write_ToBinary(w);
        }
    },

    Read_FromBinary2: function(r)
    {
        var flag = r.GetBool();
        if(flag)
        {
            this.flatTx = r.GetLong();
        }

        flag = r.GetBool();
        if(flag)
        {
            this.anchor = r.GetLong();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.anchorCtr = r.GetBool();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.bIns = r.GetDouble();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.compatLnSpc = r.GetBool();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.forceAA = r.GetBool();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.fromWordArt = r.GetBool();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.horzOverflow = r.GetLong();
        }



        flag = r.GetBool();
        if(flag)
        {
            this.lIns = r.GetDouble();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.numCol = r.GetLong();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.rIns = r.GetDouble();
        }



        flag = r.GetBool();
        if(flag)
        {
            this.rot = r.GetLong();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.rtlCol = r.GetBool();
        }

        flag = r.GetBool();
        if(flag)
        {
            this.spcCol = r.GetDouble();
        }

        flag = r.GetBool();
        if(flag)
        {
            this.spcFirstLastPara = r.GetBool();
        }



        flag = r.GetBool();
        if(flag)
        {
            this.tIns = r.GetDouble();
        }



        flag = r.GetBool();
        if(flag)
        {
            this.upright = r.GetBool();
        }



        flag = r.GetBool();
        if(flag)
        {
            this.vert = r.GetLong();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.vertOverflow = r.GetLong();
        }



        flag = r.GetBool();
        if(flag)
        {
            this.wrap = r.GetLong();
        }
        this.ReadPrstTxWarp(r);

        if(r.GetBool())
        {
            this.textFit = new CTextFit();
            this.textFit.Read_FromBinary(r);
        }
    },

    setDefault:  function()
    {
        this.flatTx         = null;
        this.anchor         = 4;
        this.anchorCtr      = false;
        this.bIns           = 45720/36000;
        this.compatLnSpc    = false;
        this.forceAA        = false;
        this.fromWordArt    = false;
        this.horzOverflow   = nOTOwerflow;
        this.lIns           = 91440/36000;
        this.numCol         = 1;
        this.rIns           = 91440/36000;
        this.rot            = null;
        this.rtlCol         = false;
        this.spcCol         = false ;
        this.spcFirstLastPara = null;
        this.tIns           = 45720/36000;
        this.upright        = false;
        this.vert           = AscFormat.nVertTThorz;
        this.vertOverflow   = nOTOwerflow;
        this.wrap           = AscFormat.nTWTSquare;
        this.prstTxWarp     = null;
    },

    createDuplicate: function()
    {
        var duplicate = new CBodyPr();
        duplicate.flatTx         = this.flatTx;
        duplicate.anchor         = this.anchor;
        duplicate.anchorCtr      = this.anchorCtr;
        duplicate.bIns           = this.bIns;
        duplicate.compatLnSpc    = this.compatLnSpc;
        duplicate.forceAA        = this.forceAA;
        duplicate.fromWordArt    = this.fromWordArt;
        duplicate.horzOverflow   = this.horzOverflow;
        duplicate.lIns           = this.lIns;
        duplicate.numCol         = this.numCol;
        duplicate.rIns           = this.rIns;
        duplicate.rot            = this.rot;
        duplicate.rtlCol         = this.rtlCol;
        duplicate.spcCol         = this.spcCol;
        duplicate.spcFirstLastPara = this.spcFirstLastPara;
        duplicate.tIns           = this.tIns;
        duplicate.upright        = this.upright;
        duplicate.vert           = this.vert;
        duplicate.vertOverflow   = this.vertOverflow;
        duplicate.wrap           = this.wrap;
        if(this.prstTxWarp)
        {
            duplicate.prstTxWarp = ExecuteNoHistory(function(){return this.prstTxWarp.createDuplicate();}, this, []);
        }
        if(this.textFit)
        {
            duplicate.textFit = this.textFit.CreateDublicate();
        }
        return duplicate;
    },

    merge: function(bodyPr)
    {
        if(!bodyPr)
            return;
        if(bodyPr.flatTx!=null)
        {
            this.flatTx = bodyPr.flatTx;
        }
        if(bodyPr.anchor!=null)
        {
            this.anchor = bodyPr.anchor;
        }
        if(bodyPr.anchorCtr!=null)
        {
            this.anchorCtr = bodyPr.anchorCtr;
        }
        if(bodyPr.bIns!=null)
        {
            this.bIns = bodyPr.bIns;
        }
        if(bodyPr.compatLnSpc!=null)
        {
            this.compatLnSpc = bodyPr.compatLnSpc;
        }
        if(bodyPr.forceAA!=null)
        {
            this.forceAA = bodyPr.forceAA;
        }
        if(bodyPr.fromWordArt!=null)
        {
            this.fromWordArt = bodyPr.fromWordArt;
        }

        if(bodyPr.horzOverflow!=null)
        {
            this.horzOverflow = bodyPr.horzOverflow;
        }

        if(bodyPr.lIns!=null)
        {
            this.lIns = bodyPr.lIns;
        }

        if(bodyPr.numCol != null){
            this.numCol = bodyPr.numCol;
        }
        if(bodyPr.rIns!=null)
        {
            this.rIns = bodyPr.rIns;
        }

        if(bodyPr.rot!=null)
        {
            this.rot = bodyPr.rot;
        }

        if(bodyPr.rtlCol!=null)
        {
            this.rtlCol = bodyPr.rtlCol;
        }

        if(bodyPr.spcCol!=null)
        {
            this.spcCol = bodyPr.spcCol;
        }
        if(bodyPr.spcFirstLastPara!=null)
        {
            this.spcFirstLastPara = bodyPr.spcFirstLastPara;
        }

        if(bodyPr.tIns!=null)
        {
            this.tIns = bodyPr.tIns;
        }
        if(bodyPr.upright!=null)
        {
            this.upright = bodyPr.upright;
        }

        if(bodyPr.vert!=null)
        {
            this.vert = bodyPr.vert;
        }
        if(bodyPr.vertOverflow!=null)
        {
            this.vertOverflow = bodyPr.vertOverflow;
        }
        if(bodyPr.wrap!=null)
        {
            this.wrap = bodyPr.wrap;
        }
        if(bodyPr.prstTxWarp)
        {
            this.prstTxWarp = ExecuteNoHistory(function(){return bodyPr.prstTxWarp.createDuplicate();}, this, []);
        }
        if(bodyPr.textFit)
        {
            this.textFit = bodyPr.textFit.CreateDublicate();
        }
        if(bodyPr.numCol != null){
            this.numCol = bodyPr.numCol;
        }
        return this;
    },

    Write_ToBinary: function(w)
    {
        var flag = this.flatTx != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteLong(this.flatTx);
        }

        flag = this.anchor != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteLong(this.anchor);
        }

        flag = this.anchorCtr != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteBool(this.anchorCtr);
        }

        flag = this.bIns != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteDouble(this.bIns);
        }

        flag = this.compatLnSpc != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteBool(this.compatLnSpc);
        }

        flag = this.forceAA != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteBool(this.forceAA);
        }

        flag = this.fromWordArt != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteBool(this.fromWordArt);
        }

        flag = this.horzOverflow != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteLong(this.horzOverflow);
        }

        flag = this.lIns != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteDouble(this.lIns);
        }

        flag = this.numCol != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteLong(this.numCol);
        }

        flag = this.rIns != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteDouble(this.rIns);
        }


        flag = this.rot != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteLong(this.rot);
        }

        flag = this.rtlCol != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteBool(this.rtlCol);
        }

        flag = this.spcCol != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteDouble(this.spcCol);
        }

        flag = this.spcFirstLastPara != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteBool(this.spcFirstLastPara);
        }

        flag = this.tIns != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteDouble(this.tIns);
        }

        flag = this.upright != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteBool(this.upright);
        }

        flag = this.vert != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteLong(this.vert);
        }


        flag = this.vertOverflow != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteLong(this.vertOverflow);
        }

        flag = this.wrap != null;
        w.WriteBool(flag);
        if(flag)
        {
            w.WriteLong(this.wrap);
        }
        this.WritePrstTxWarp(w);
        w.WriteBool(isRealObject(this.textFit));
        if(this.textFit)
        {
            this.textFit.Write_ToBinary(w);
        }
    },

    Read_FromBinary: function(r)
    {
        var flag = r.GetBool();
        if(flag)
        {
            this.flatTx = r.GetLong();
        }

        flag = r.GetBool();
        if(flag)
        {
            this.anchor = r.GetLong();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.anchorCtr = r.GetBool();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.bIns = r.GetDouble();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.compatLnSpc = r.GetBool();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.forceAA = r.GetBool();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.fromWordArt = r.GetBool();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.horzOverflow = r.GetLong();
        }



        flag = r.GetBool();
        if(flag)
        {
            this.lIns = r.GetDouble();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.numCol = r.GetLong();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.rIns = r.GetDouble();
        }



        flag = r.GetBool();
        if(flag)
        {
            this.rot = r.GetLong();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.rtlCol = r.GetBool();
        }

        flag = r.GetBool();
        if(flag)
        {
            this.spcCol = r.GetDouble();
        }

        flag = r.GetBool();
        if(flag)
        {
            this.spcFirstLastPara = r.GetBool();
        }



        flag = r.GetBool();
        if(flag)
        {
            this.tIns = r.GetDouble();
        }



        flag = r.GetBool();
        if(flag)
        {
            this.upright = r.GetBool();
        }



        flag = r.GetBool();
        if(flag)
        {
            this.vert = r.GetLong();
        }


        flag = r.GetBool();
        if(flag)
        {
            this.vertOverflow = r.GetLong();
        }



        flag = r.GetBool();
        if(flag)
        {
            this.wrap = r.GetLong();
        }
        this.ReadPrstTxWarp(r);

        if(r.GetBool())
        {
            this.textFit = new CTextFit();
            this.textFit.Read_FromBinary(r)
        }
    }
};


function CHyperlink()
{
    this.url = "";
    this.action = "";
    this.tooltip = null;
}

CHyperlink.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {}
};

function CTextParagraphPr()
{
    this.bullet = new CBullet();
    this.lvl = null;
    this.pPr = new CParaPr();
    this.rPr = new CTextPr();
}


function CompareBullets(bullet1, bullet2)
{

    //TODO: пока будем сравнивать только bulletType, т. к. эта функция используется для мержа свойств при отдаче в интерфейс, а для интерфейса bulletTyp'a достаточно. Если понадобится нужно сделать полное сравнение.
    //
    if(bullet1.bulletType && bullet2.bulletType
        && bullet1.bulletType.type === bullet2.bulletType.type
        && bullet1.bulletType.type !== BULLET_TYPE_BULLET_NONE)
    {
        var ret = new CBullet();
        ret.bulletType = new CBulletType();
        switch(bullet1.bulletType.type)
        {
            case BULLET_TYPE_BULLET_CHAR:
            {
                ret.bulletType.type = BULLET_TYPE_BULLET_CHAR;
                if(bullet1.bulletType.Char === bullet2.bulletType.Char)
                {
                    ret.bulletType.Char = bullet1.bulletType.Char;
                }
                break;
            }
            case BULLET_TYPE_BULLET_BLIP:
            {
                ret.bulletType.type = BULLET_TYPE_BULLET_CHAR; //TODO: в меню отдаем, что символьный.
                break;
            }
            case BULLET_TYPE_BULLET_AUTONUM:
            {
                if(bullet1.bulletType.AutoNumType === bullet2.bulletType.AutoNumType)
                {
                    ret.bulletType.AutoNumType = bullet1.bulletType.AutoNumType;
                }
                if(bullet1.bulletType.startAt === bullet2.bulletType.startAt)
                {
                    ret.bulletType.startAt = bullet1.bulletType.startAt;
                }
                if(bullet1.bulletType.type === bullet2.bulletType.type)
                {
                    ret.bulletType.type = bullet1.bulletType.type;
                }
                break;
            }
        }
        return ret;
    }
    else
    {
        return undefined;
    }
}

function CBullet()
{
    this.bulletColor = null;
    this.bulletSize = null;
    this.bulletTypeface = null;
    this.bulletType = null;
    this.Bullet = null;
}

CBullet.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    Set_FromObject: function(obj)
    {
        if(obj)
        {
            if(obj.bulletColor)
            {
                this.bulletColor = new CBulletColor();
                this.bulletColor.Set_FromObject(obj.bulletColor);
            }
            else
                this.bulletColor = null;

            if(obj.bulletSize)
            {
                this.bulletSize = new CBulletSize();
                this.bulletSize.Set_FromObject(obj.bulletSize);
            }
            else
                this.bulletSize = null;

            if(obj.bulletTypeface)
            {
                this.bulletTypeface = new CBulletTypeface();
                this.bulletTypeface.Set_FromObject(obj.bulletTypeface);
            }
            else
                this.bulletTypeface = null;
        }
    },

    createDuplicate: function()
    {
        var duplicate = new CBullet();
        if(this.bulletColor)
        {
            duplicate.bulletColor = this.bulletColor.createDuplicate();
        }
        if(this.bulletSize)
        {
            duplicate.bulletSize = this.bulletSize.createDuplicate();
        }
        if(this.bulletTypeface)
        {
            duplicate.bulletTypeface = this.bulletTypeface.createDuplicate();
        }

        if(this.bulletType)
        {
            duplicate.bulletType = this.bulletType.createDuplicate();
        }

        duplicate.Bullet = this.Bullet;
        return duplicate;
    },

    isBullet: function()
    {
        return this.bulletType != null && this.bulletType.type != null;
    },

    getPresentationBullet: function(theme, color)
    {
        var para_pr = new CParaPr();
        para_pr.Bullet = this;
        return para_pr.Get_PresentationBullet(theme, color);
    },

    getBulletType: function(theme, color)
    {
        return this.getPresentationBullet(theme, color).m_nType;
    },

    Write_ToBinary: function(w)
    {
        w.WriteBool(isRealObject(this.bulletColor));
        if(isRealObject(this.bulletColor))
        {
            this.bulletColor.Write_ToBinary(w);
        }

        w.WriteBool(isRealObject(this.bulletSize));
        if(isRealObject(this.bulletSize))
        {
            this.bulletSize.Write_ToBinary(w);
        }


        w.WriteBool(isRealObject(this.bulletTypeface));
        if(isRealObject(this.bulletTypeface))
        {
            this.bulletTypeface.Write_ToBinary(w);
        }


        w.WriteBool(isRealObject(this.bulletType));
        if(isRealObject(this.bulletType))
        {
            this.bulletType.Write_ToBinary(w);
        }

    },

    Read_FromBinary: function(r)
    {
        if(r.GetBool())
        {
            this.bulletColor = new CBulletColor();
            this.bulletColor.Read_FromBinary(r);
        }

        if(r.GetBool())
        {
            this.bulletSize = new CBulletSize();
            this.bulletSize.Read_FromBinary(r);
        }

        if(r.GetBool())
        {
            this.bulletTypeface = new CBulletTypeface();
            this.bulletTypeface.Read_FromBinary(r);
        }

        if(r.GetBool())
        {
            this.bulletType = new CBulletType();
            this.bulletType.Read_FromBinary(r);
        }
    },

    Get_AllFontNames: function(AllFonts){
        if(this.bulletTypeface && typeof this.bulletTypeface.typeface === "string" && this.bulletTypeface.typeface.length > 0){
            AllFonts[this.bulletTypeface.typeface] = true;
        }
    }

};

function CBulletColor()
{
    this.type = AscFormat.BULLET_TYPE_COLOR_CLRTX;
    this.UniColor = null;

}

CBulletColor.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},
    Set_FromObject: function(o)
    {
        this.type = o.type;
        if(o.UniColor)
        {

        }
    },

    createDuplicate: function()
    {
        var duplicate = new CBulletColor();
        duplicate.type = this.type;
        if(this.UniColor != null)
        {
            duplicate.UniColor = this.UniColor.createDuplicate();
        }
        return duplicate;
    },

    Write_ToBinary: function(w)
    {
        w.WriteBool(isRealNumber(this.type));
        if(isRealNumber(this.type))
        {
            w.WriteLong(this.type);
        }
        w.WriteBool(isRealObject(this.UniColor));
        if(isRealObject(this.UniColor))
        {
            this.UniColor.Write_ToBinary(w);
        }

    },

    Read_FromBinary: function(r)
    {
        if(r.GetBool())
        {
            (this.type) = r.GetLong();
        }

        if(r.GetBool())
        {
            this.UniColor = new CUniColor();
            this.UniColor.Read_FromBinary(r);
        }
    }
};

function CBulletSize()
{
    this.type = AscFormat.BULLET_TYPE_SIZE_NONE;
    this.val = 0;

}

CBulletSize.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var d = new CBulletSize();
        d.type = this.type;
        d.val = this.val;
        return d;
    },

    Write_ToBinary: function(w)
    {
        w.WriteBool(isRealNumber(this.type));
        if(isRealNumber(this.type))
        {
            w.WriteLong(this.type);
        }

        w.WriteBool(isRealNumber(this.val));
        if(isRealNumber(this.val))
        {
            w.WriteLong(this.val);
        }

    },

    Read_FromBinary: function(r)
    {
        if(r.GetBool())
        {
            (this.type) = r.GetLong();
        }
        if(r.GetBool())
        {
            (this.val) = r.GetLong();
        }
    }
};

function CBulletTypeface()
{
    this.type = AscFormat.BULLET_TYPE_TYPEFACE_NONE;
    this.typeface = "";
}

CBulletTypeface.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var d = new CBulletTypeface();
        d.type = this.type;
        d.typeface = this.typeface;
        return d;
    },

    Write_ToBinary: function(w)
    {
        w.WriteBool(isRealNumber(this.type));
        if(isRealNumber(this.type))
        {
            w.WriteLong(this.type);
        }

        w.WriteBool(typeof this.typeface === "string");
        if(typeof this.typeface === "string")
        {
            w.WriteString2(this.typeface);
        }

    },

    Read_FromBinary: function(r)
    {
        if(r.GetBool())
        {
            (this.type) = r.GetLong();
        }
        if(r.GetBool())
        {
            (this.typeface) = r.GetString2();
        }
    }
};

var BULLET_TYPE_BULLET_NONE		= 0;
var BULLET_TYPE_BULLET_CHAR		= 1;
var BULLET_TYPE_BULLET_AUTONUM	= 2;
var BULLET_TYPE_BULLET_BLIP		= 3;

function CBulletType()
{
    this.type = null;//BULLET_TYPE_BULLET_NONE;
    this.Char = "*";
    this.AutoNumType = 0;
    this.startAt = 1;
}

CBulletType.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    } ,

    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var d = new CBulletType();
        d.type = this.type;
        d.Char = this.Char;
        d.AutoNumType = this.AutoNumType;
        d.startAt = this.startAt;
        return d;
    },

    Write_ToBinary: function(w)
    {
        w.WriteBool(isRealNumber(this.type));
        if(isRealNumber(this.type))
        {
            w.WriteLong(this.type);
        }

        w.WriteBool(typeof this.Char === "string");
        if(typeof this.Char === "string")
        {
            w.WriteString2(this.Char);
        }

        w.WriteBool(isRealNumber(this.AutoNumType));
        if(isRealNumber(this.AutoNumType))
        {
            w.WriteLong(this.AutoNumType);
        }

        w.WriteBool(isRealNumber(this.startAt));
        if(isRealNumber(this.startAt))
        {
            w.WriteLong(this.startAt);
        }
    },

    Read_FromBinary: function(r)
    {
        if(r.GetBool())
        {
            (this.type) = r.GetLong();
        }
        if(r.GetBool())
        {
            (this.Char) = r.GetString2();
        }

        if(r.GetBool())
        {
            (this.AutoNumType) = r.GetLong();
        }

        if(r.GetBool())
        {
            (this.startAt) = r.GetLong();
        }
    }
};

function TextListStyle()
{
    this.levels = new Array(10);

    for (var i = 0; i < 10; i++)
        this.levels[i] = null;


}

TextListStyle.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var duplicate = new TextListStyle();
        for(var i=0; i<10; ++i)
        {
            if(this.levels[i]!=null)
            {
                duplicate.levels[i] = this.levels[i].Copy();
            }
        }
        return duplicate;
    },

    Write_ToBinary: function(w)
    {
        for(var i = 0; i < 10; ++i)
        {
            w.WriteBool(isRealObject(this.levels[i]));
            if(isRealObject(this.levels[i]))
            {
                this.levels[i].Write_ToBinary(w);
            }
        }
    },

    Read_FromBinary: function(r)
    {
        for(var i = 0; i < 10; ++i)
        {
            if(r.GetBool())
            {
                this.levels[i] = new CParaPr();
                this.levels[i].Read_FromBinary(r);
            }
            else
            {
                this.levels[i] = null;
            }
        }
    },


    Document_Get_AllFontNames: function(AllFonts){
        for(var i = 0; i < 10; ++i){
            if(this.levels[i]){
                if(this.levels[i].DefaultRunPr){
                    this.levels[i].DefaultRunPr.Document_Get_AllFontNames(AllFonts);
                }
                if(this.levels[i].Bullet){
                    this.levels[i].Bullet.Get_AllFontNames(AllFonts);
                }
            }
        }
    }
};





// DEFAULT OBJECTS
function GenerateDefaultTheme(presentation, opt_fontName)
{
    return ExecuteNoHistory(function()
    {
		if (!opt_fontName) {
			opt_fontName = "Arial";
		}
        var theme = new CTheme();
        theme.presentation = presentation;
        theme.setFontScheme(new FontScheme());
        theme.themeElements.fontScheme.setMajorFont(new FontCollection(theme.themeElements.fontScheme));
        theme.themeElements.fontScheme.setMinorFont(new FontCollection(theme.themeElements.fontScheme));
        theme.themeElements.fontScheme.majorFont.setLatin(opt_fontName);
        theme.themeElements.fontScheme.minorFont.setLatin(opt_fontName);


        var scheme = theme.themeElements.clrScheme;

        scheme.colors[8] = CreateUniColorRGB(0,0,0);
        scheme.colors[12] = CreateUniColorRGB(255,255,255);
        scheme.colors[9] = CreateUniColorRGB(0x1F,0x49, 0x7D);
        scheme.colors[13] = CreateUniColorRGB(0xEE,0xEC,0xE1);
        scheme.colors[0] = CreateUniColorRGB(0x4F, 0x81, 0xBD); //CreateUniColorRGB(0xFF, 0x81, 0xBD);//
        scheme.colors[1] = CreateUniColorRGB(0xC0,0x50,0x4D);
        scheme.colors[2] = CreateUniColorRGB(0x9B,0xBB,0x59);
        scheme.colors[3] = CreateUniColorRGB(0x80,0x64,0xA2);
        scheme.colors[4] = CreateUniColorRGB(0x4B,0xAC,0xC6);
        scheme.colors[5] = CreateUniColorRGB(0xF7,0x96,0x46);
        scheme.colors[11] = CreateUniColorRGB(0x00,0x00,0xFF);
        scheme.colors[10] = CreateUniColorRGB(0x80, 0x00, 0x80);

        // -------------- fill styles -------------------------
        var brush = new CUniFill();
        brush.setFill(new CSolidFill());
        brush.fill.setColor(new CUniColor());
        brush.fill.color.setColor(new CSchemeColor());
        brush.fill.color.color.setId(phClr);
        theme.themeElements.fmtScheme.fillStyleLst.push(brush);

        brush = new CUniFill();
        brush.setFill(new CSolidFill());
        brush.fill.setColor(new CUniColor());
        brush.fill.color.setColor(CreateUniColorRGB(0,0,0));
        theme.themeElements.fmtScheme.fillStyleLst.push(brush);

        brush = new CUniFill();
        brush.setFill(new CSolidFill());
        brush.fill.setColor(new CUniColor());
        brush.fill.color.setColor(CreateUniColorRGB(0,0,0));
        theme.themeElements.fmtScheme.fillStyleLst.push(brush);
        // ----------------------------------------------------

        // -------------- back styles -------------------------
        brush = new CUniFill();
        brush.setFill(new CSolidFill());
        brush.fill.setColor(new CUniColor());
        brush.fill.color.setColor(new CSchemeColor());
        brush.fill.color.color.setId(phClr);
        theme.themeElements.fmtScheme.bgFillStyleLst.push(brush);

        brush = new CUniFill();
        brush.setFill(new CSolidFill());
        brush.fill.setColor(new CUniColor());
        brush.fill.color.setColor(CreateUniColorRGB(0,0,0));
        theme.themeElements.fmtScheme.bgFillStyleLst.push(brush);

        brush = new CUniFill();
        brush.setFill(new CSolidFill());
        brush.fill.setColor(new CUniColor());
        brush.fill.color.setColor(CreateUniColorRGB(0,0,0));
        theme.themeElements.fmtScheme.bgFillStyleLst.push(brush);
        // ----------------------------------------------------

        var pen = new CLn();
        pen.setW(9525);
        pen.setFill(new CUniFill());
        pen.Fill.setFill(new CSolidFill());
        pen.Fill.fill.setColor(new CUniColor());
        pen.Fill.fill.color.setColor(new CSchemeColor());
        pen.Fill.fill.color.color.setId(phClr);
        pen.Fill.fill.color.setMods(new CColorModifiers());

        var mod = new CColorMod();
        mod.setName("shade");
        mod.setVal(95000);
        pen.Fill.fill.color.Mods.addMod(mod);
        mod = new CColorMod();
        mod.setName("satMod");
        mod.setVal(105000);
        pen.Fill.fill.color.Mods.addMod(mod);
        theme.themeElements.fmtScheme.lnStyleLst.push(pen);

        pen = new CLn();
        pen.setW(25400);
        pen.setFill(new CUniFill());
        pen.Fill.setFill(new CSolidFill());

        pen.Fill.fill.setColor(new CUniColor());
        pen.Fill.fill.color.setColor(new CSchemeColor());
        pen.Fill.fill.color.color.setId(phClr);
        theme.themeElements.fmtScheme.lnStyleLst.push(pen);

        pen = new CLn();
        pen.setW(38100);
        pen.setFill(new CUniFill());
        pen.Fill.setFill(new CSolidFill());
        pen.Fill.fill.setColor(new CUniColor());
        pen.Fill.fill.color.setColor(new CSchemeColor());
        pen.Fill.fill.color.color.setId(phClr);
        theme.themeElements.fmtScheme.lnStyleLst.push(pen);
        theme.extraClrSchemeLst = [];
        return theme;
    }, this, []);
}

function GenerateDefaultMasterSlide(theme)
{
    var master = new MasterSlide(theme.presentation, theme);
    master.Theme = theme;

    master.sldLayoutLst[0] = GenerateDefaultSlideLayout(master);

    return master;
}

function GenerateDefaultSlideLayout(master)
{
    var layout = new SlideLayout();
    layout.Theme = master.Theme;
    layout.Master = master;
    return layout;
}

function GenerateDefaultSlide(layout)
{
    var slide = new Slide(layout.Master.presentation, layout, 0);
    slide.Master = layout.Master;
    slide.Theme = layout.Master.Theme;
    slide.setNotes(AscCommonSlide.CreateNotes());
    slide.notes.setNotesMaster(layout.Master.presentation.notesMasters[0]);
    slide.notes.setSlide(slide);
    return slide;
}

function CreateDefaultTextRectStyle()
{
    var style = new CShapeStyle();
    var lnRef = new StyleRef();
    lnRef.setIdx(0);
    var unicolor = new CUniColor();

    unicolor.setColor(new CSchemeColor());
    unicolor.color.setId(g_clr_accent1);
    var mod = new CColorMod();
    mod.setName("shade");
    mod.setVal(50000);
    unicolor.setMods(new CColorModifiers());
    unicolor.Mods.addMod(mod);
    lnRef.setColor(unicolor);
    style.setLnRef(lnRef);


    var fillRef = new StyleRef();
    fillRef.setIdx(0);
    unicolor = new CUniColor();
    unicolor.setColor(new CSchemeColor());
    unicolor.color.setId(g_clr_accent1);
    fillRef.setColor(unicolor);
    style.setFillRef(fillRef);


    var effectRef = new StyleRef();
    effectRef.setIdx(0);
    unicolor = new  CUniColor();
    unicolor.setColor(new CSchemeColor());
    unicolor.color.setId(g_clr_accent1);
    effectRef.setColor(unicolor);
    style.setEffectRef(effectRef);

    var fontRef = new FontRef();
    fontRef.setIdx(AscFormat.fntStyleInd_minor);
    unicolor = new CUniColor();
    unicolor.setColor(new CSchemeColor());
    unicolor.color.setId(8);
    fontRef.setColor(unicolor);
    style.setFontRef(fontRef);

    return style;
}

function GenerateDefaultColorMap()
{
    var clrMap = new ClrMap();

    clrMap.color_map[0] = 0;
    clrMap.color_map[1] = 1;
    clrMap.color_map[2] = 2;
    clrMap.color_map[3] = 3;
    clrMap.color_map[4] = 4;
    clrMap.color_map[5] = 5;
    clrMap.color_map[10] = 10;
    clrMap.color_map[11] = 11;
    clrMap.color_map[6] = 12;
    clrMap.color_map[7] = 13;
    clrMap.color_map[15] = 8;
    clrMap.color_map[16] = 9;

    return clrMap;

}

function CreateAscFill(unifill)
{
    if (null == unifill || null == unifill.fill)
        return new asc_CShapeFill();

    var ret = new asc_CShapeFill();

    var _fill = unifill.fill;
    switch (_fill.type)
    {
        case c_oAscFill.FILL_TYPE_SOLID:
        {
            ret.type = c_oAscFill.FILL_TYPE_SOLID;
            ret.fill = new Asc.asc_CFillSolid();
            ret.fill.color = CreateAscColor(_fill.color);
            break;
        }
        case c_oAscFill.FILL_TYPE_PATT:
        {
            ret.type = c_oAscFill.FILL_TYPE_PATT;
            ret.fill = new Asc.asc_CFillHatch();
            ret.fill.PatternType = _fill.ftype;
            ret.fill.fgClr = CreateAscColor(_fill.fgClr);
            ret.fill.bgClr = CreateAscColor(_fill.bgClr);
            break;
        }
        case c_oAscFill.FILL_TYPE_GRAD:
        {
            ret.type = c_oAscFill.FILL_TYPE_GRAD;
            ret.fill = new Asc.asc_CFillGrad();
            var bCheckTransparent = true, nLastTransparent = null, nLastTempTransparent, j, aMods;
            for (var i = 0; i < _fill.colors.length; i++)
            {
                if (0 == i)
                {
                    ret.fill.Colors = [];
                    ret.fill.Positions = [];
                }
                if(bCheckTransparent)
                {
                    if(_fill.colors[i].color.Mods)
                    {
                        aMods = _fill.colors[i].color.Mods.Mods;
                        nLastTempTransparent = null;
                        for(j = 0; j < aMods.length; ++j)
                        {
                            if(aMods[j].name === "alpha")
                            {
                                if(nLastTempTransparent === null)
                                {
                                    nLastTempTransparent = aMods[j].val;
                                    if(nLastTransparent === null)
                                    {
                                        nLastTransparent = nLastTempTransparent;
                                    }
                                    else
                                    {
                                        if(nLastTransparent !== nLastTempTransparent)
                                        {
                                            bCheckTransparent = false;
                                            break;
                                        }
                                    }
                                }
                                else
                                {
                                    bCheckTransparent = false;
                                    break;
                                }
                            }
                        }
                    }
                    else
                    {
                        bCheckTransparent = false;
                    }
                }
                ret.fill.Colors.push(CreateAscColor(_fill.colors[i].color));
                ret.fill.Positions.push(_fill.colors[i].pos);
            }
            if(bCheckTransparent && nLastTransparent !== null)
            {
                ret.transparent = (nLastTransparent/100000)*255;
            }

            if (_fill.lin)
            {
                ret.fill.GradType = c_oAscFillGradType.GRAD_LINEAR;
                ret.fill.LinearAngle = _fill.lin.angle;
                ret.fill.LinearScale = _fill.lin.scale;
            }
            else if(_fill.path)
            {
                ret.fill.GradType = c_oAscFillGradType.GRAD_PATH;
                ret.fill.PathType = 0;
            }
            else
            {
                ret.fill.GradType = c_oAscFillGradType.GRAD_LINEAR;
                ret.fill.LinearAngle = 0;
                ret.fill.LinearScale = false;
            }

            break;
        }
        case c_oAscFill.FILL_TYPE_BLIP:
        {
            ret.type = c_oAscFill.FILL_TYPE_BLIP;
            ret.fill = new Asc.asc_CFillBlip();

            ret.fill.url = _fill.RasterImageId;
            ret.fill.type = (_fill.tile == null) ? c_oAscFillBlipType.STRETCH : c_oAscFillBlipType.TILE;
            break;
        }
        case c_oAscFill.FILL_TYPE_NOFILL:
        case c_oAscFill.FILL_TYPE_NONE:
        {
            ret.type = c_oAscFill.FILL_TYPE_NOFILL;
            break;
        }
        default:
            break;
    }

    if(isRealNumber(unifill.transparent))
    {
        ret.transparent = unifill.transparent;
    }
    return ret;
}
function CorrectUniFill(asc_fill, unifill, editorId)
{
    if (null == asc_fill)
        return unifill;

    var ret = unifill;
    if (null == ret)
        ret = new CUniFill();

    var _fill = asc_fill.fill;
    var _type = asc_fill.type;

    if (null != _type)
    {
        switch (_type)
        {
            case c_oAscFill.FILL_TYPE_NOFILL:
            {
                ret.fill = new CNoFill();
                break;
            }
            case c_oAscFill.FILL_TYPE_GRP:
            {
                ret.fill = new CGrpFill();
                break;
            }
            case c_oAscFill.FILL_TYPE_BLIP:
            {

                var _url = _fill.url;
                var _tx_id = _fill.texture_id;
                if (null != _tx_id && (0 <= _tx_id) && (_tx_id < AscCommon.g_oUserTexturePresets.length))
                {
                    _url = AscCommon.g_oUserTexturePresets[_tx_id];
                }


                if (ret.fill == null)
                {
                    ret.fill = new CBlipFill();
                }

                if(ret.fill.type != c_oAscFill.FILL_TYPE_BLIP)
                {
                    if(!(typeof (_url) === "string" && _url.length > 0) || !isRealNumber(_fill.type))
                    {
                        break;
                    }
                    ret.fill = new CBlipFill();
                }

                if (_url != null && _url !== undefined && _url != "")
                    ret.fill.setRasterImageId(_url);

                if (ret.fill.RasterImageId == null)
                    ret.fill.RasterImageId = "";

                var tile = _fill.type;
                if (tile == c_oAscFillBlipType.STRETCH)
                    ret.fill.tile = null;
                else if (tile == c_oAscFillBlipType.TILE)
                    ret.fill.tile = new CBlipFillTile();
                break;
            }
            case c_oAscFill.FILL_TYPE_PATT:
            {
                if (ret.fill == null)
                {
                    ret.fill = new CPattFill();
                }

                if(ret.fill.type != c_oAscFill.FILL_TYPE_PATT)
                {
                    if(undefined != _fill.PatternType && undefined != _fill.fgClr && undefined != _fill.bgClr)
                    {
                        ret.fill = new CPattFill();
                    }
                    else
                    {
                        break;
                    }
                }

                if (undefined != _fill.PatternType)
                {
                    ret.fill.ftype = _fill.PatternType;
                }
                if (undefined != _fill.fgClr)
                {
                    ret.fill.fgClr = CorrectUniColor(_fill.fgClr, ret.fill.fgClr, editorId);
                }
                if(!ret.fill.fgClr)
                {
                    ret.fill.fgClr = CreateUniColorRGB(0, 0, 0);
                }
                if (undefined != _fill.bgClr)
                {
                    ret.fill.bgClr = CorrectUniColor(_fill.bgClr, ret.fill.bgClr, editorId);
                }
                if(!ret.fill.bgClr)
                {
                    ret.fill.bgClr = CreateUniColorRGB(0, 0, 0);
                }

                break;
            }
            case c_oAscFill.FILL_TYPE_GRAD:
            {
                if (ret.fill == null)
                {
                    ret.fill = new CGradFill();
                }

                var _colors     = _fill.Colors;
                var _positions  = _fill.Positions;

                if(ret.fill.type != c_oAscFill.FILL_TYPE_GRAD )
                {
                    if(undefined != _colors && undefined != _positions)
                    {
                        ret.fill = new CGradFill();
                    }
                    else
                    {
                        break;
                    }
                }

                if (undefined != _colors && undefined != _positions)
                {
                    if (_colors.length == _positions.length)
                    {
                        if(ret.fill.colors.length === _colors.length){
                            for (var i = 0; i < _colors.length; i++){
                                var _gs = ret.fill.colors[i] ? ret.fill.colors[i] : new CGs();
                                _gs.color = CorrectUniColor(_colors[i], _gs.color, editorId);
                                _gs.pos = _positions[i];
                                ret.fill.colors[i] = _gs;
                            }
                        }
                        else{
                            for (var i = 0; i < _colors.length; i++){
                                var _gs = new CGs();
                                _gs.color = CorrectUniColor(_colors[i], _gs.color, editorId);
                                _gs.pos = _positions[i];

                                ret.fill.colors.push(_gs);
                            }
                        }
                    }
                }
                else if (undefined != _colors)
                {
                    if (_colors.length == ret.fill.colors.length)
                    {
                        for (var i = 0; i < _colors.length; i++)
                        {
                            ret.fill.colors[i].color = CorrectUniColor(_colors[i], ret.fill.colors[i].color, editorId);
                        }
                    }
                }
                else if (undefined != _positions)
                {
                    if (_positions.length <= ret.fill.colors.length)
                    {
                        if(_positions.length < ret.fill.colors.length)
                        {
                            ret.fill.colors.splice(_positions.length, ret.fill.colors.length - _positions.length);
                        }
                        for (var i = 0; i < _positions.length; i++)
                        {
                            ret.fill.colors[i].pos = _positions[i];
                        }
                    }
                }

                var _grad_type = _fill.GradType;

                if (c_oAscFillGradType.GRAD_LINEAR == _grad_type)
                {
                    var _angle = _fill.LinearAngle;
                    var _scale = _fill.LinearScale;

                    if (!ret.fill.lin){
                        ret.fill.lin = new GradLin();
                        ret.fill.lin.angle = 0;
                        ret.fill.lin.scale = false;
                    }

                    if (undefined != _angle)
                        ret.fill.lin.angle = _angle;
                    if (undefined != _scale)
                        ret.fill.lin.scale = _scale;
                    ret.fill.path = null;
                }
                else if (c_oAscFillGradType.GRAD_PATH == _grad_type)
                {
                    ret.fill.lin = null;
                    ret.fill.path = new GradPath();
                }
                break;
            }
            default:
            {
                if (ret.fill == null || ret.fill.type != c_oAscFill.FILL_TYPE_SOLID)
                {
                    ret.fill = new CSolidFill();
                }
                ret.fill.color = CorrectUniColor(_fill.color, ret.fill.color, editorId);
            }
        }
    }

    var _alpha = asc_fill.transparent;
    if (null != _alpha)
        ret.transparent = _alpha;

    return ret;
}
// эта функция ДОЛЖНА минимизироваться
function CreateAscStroke(ln, _canChangeArrows)
{
    if (null == ln || null == ln.Fill || ln.Fill.fill == null)
        return new Asc.asc_CStroke();

    var ret = new Asc.asc_CStroke();

    var _fill = ln.Fill.fill;
    if(_fill != null)
    {
        switch (_fill.type)
        {
            case c_oAscFill.FILL_TYPE_BLIP:
            {
                break;
            }
            case c_oAscFill.FILL_TYPE_SOLID:
            {
                ret.color = CreateAscColor(_fill.color);
                ret.type = c_oAscStrokeType.STROKE_COLOR;
                break;
            }
            case c_oAscFill.FILL_TYPE_GRAD:
            {
                var _c = _fill.colors;
                if (_c != 0)
                {
                    ret.color = CreateAscColor(_fill.colors[0].color);
                    ret.type = c_oAscStrokeType.STROKE_COLOR;
                }

                break;
            }
            case c_oAscFill.FILL_TYPE_PATT:
            {
                ret.color = CreateAscColor(_fill.fgClr);
                ret.type = c_oAscStrokeType.STROKE_COLOR;
                break;
            }
            case c_oAscFill.FILL_TYPE_NOFILL:
            {
                ret.color = null;
                ret.type = c_oAscStrokeType.STROKE_NONE;
                break;
            }
            default:
            {
                break;
            }
        }

    }


    ret.width = (ln.w == null) ? 12700 : (ln.w >> 0);
    ret.width /= 36000.0;

    if (ln.cap != null)
        ret.asc_putLinecap(ln.cap);

    if (ln.Join != null)
        ret.asc_putLinejoin(ln.Join.type);

    if (ln.headEnd != null)
    {
        ret.asc_putLinebeginstyle((ln.headEnd.type == null) ? LineEndType.None : ln.headEnd.type);

        var _len = (null == ln.headEnd.len) ? 1 : (2 - ln.headEnd.len);
        var _w = (null == ln.headEnd.w) ? 1 : (2 - ln.headEnd.w);

        ret.asc_putLinebeginsize(_w * 3 + _len);
    }
    else
    {
        ret.asc_putLinebeginstyle(LineEndType.None);
    }

    if (ln.tailEnd != null)
    {
        ret.asc_putLineendstyle((ln.tailEnd.type == null) ? LineEndType.None : ln.tailEnd.type);

        var _len = (null == ln.tailEnd.len) ? 1 : (2 - ln.tailEnd.len);
        var _w = (null == ln.tailEnd.w) ? 1 : (2 - ln.tailEnd.w);

        ret.asc_putLineendsize(_w * 3 + _len);
    }
    else
    {
        ret.asc_putLineendstyle(LineEndType.None);
    }
    if(AscFormat.isRealNumber(ln.prstDash)){
        ret.prstDash = ln.prstDash;
    }
    else if(ln.prstDash === null){
        ret.prstDash = Asc.c_oDashType.solid;
    }
    if (true === _canChangeArrows)
        ret.canChangeArrows = true;

    return ret;
}

function CorrectUniStroke(asc_stroke, unistroke, flag)
{
    if (null == asc_stroke)
        return unistroke;

    var ret = unistroke;
    if (null == ret)
        ret = new CLn();

    var _type = asc_stroke.type;
    var _w = asc_stroke.width;

    if (_w != null && _w !== undefined)
        ret.w = _w * 36000.0;

    var _color = asc_stroke.color;
    if (_type == c_oAscStrokeType.STROKE_NONE)
    {
        ret.Fill = new CUniFill();
        ret.Fill.fill = new CNoFill();
    }
    else if (_type != null)
    {
        if (null != _color && undefined !== _color)
        {
            ret.Fill = new CUniFill();
            ret.Fill.type = c_oAscFill.FILL_TYPE_SOLID;
            ret.Fill.fill = new CSolidFill();
            ret.Fill.fill.color = CorrectUniColor(_color, ret.Fill.fill.color, flag);
        }
    }

    var _join = asc_stroke.LineJoin;
    if (null != _join)
    {
        ret.Join = new LineJoin();
        ret.Join.type = _join;
    }

    var _cap = asc_stroke.LineCap;
    if (null != _cap)
    {
        ret.cap = _cap;
    }

    var _begin_style = asc_stroke.LineBeginStyle;
    if (null != _begin_style)
    {
        if (ret.headEnd == null)
            ret.headEnd = new EndArrow();

        ret.headEnd.type = _begin_style;
    }

    var _end_style = asc_stroke.LineEndStyle;
    if (null != _end_style)
    {
        if (ret.tailEnd == null)
            ret.tailEnd = new EndArrow();

        ret.tailEnd.type = _end_style;
    }

    var _begin_size = asc_stroke.LineBeginSize;
    if (null != _begin_size)
    {
        if (ret.headEnd == null)
            ret.headEnd = new EndArrow();

        ret.headEnd.w = 2 - ((_begin_size/3) >> 0);
        ret.headEnd.len = 2 - (_begin_size % 3);
    }

    var _end_size = asc_stroke.LineEndSize;
    if (null != _end_size)
    {
        if (ret.tailEnd == null)
            ret.tailEnd = new EndArrow();

        ret.tailEnd.w = 2 - ((_end_size/3) >> 0);
        ret.tailEnd.len = 2 - (_end_size % 3);
    }
    if(AscFormat.isRealNumber(asc_stroke.prstDash)){
        ret.prstDash = asc_stroke.prstDash;
    }
    return ret;
}

// эта функция ДОЛЖНА минимизироваться
function CreateAscShapeProp(shape)
{
    if (null == shape)
        return new asc_CShapeProperty();

    var ret = new asc_CShapeProperty();
    ret.fill = CreateAscFill(shape.brush);
    ret.stroke = CreateAscStroke(shape.pen);
    ret.lockAspect = shape.getNoChangeAspect();
    var paddings = null;
    if(shape.textBoxContent)
    {
        var body_pr = shape.bodyPr;
        paddings = new asc_CPaddings();
        if(typeof body_pr.lIns === "number")
            paddings.Left = body_pr.lIns;
        else
            paddings.Left = 2.54;

        if(typeof body_pr.tIns === "number")
            paddings.Top = body_pr.tIns;
        else
            paddings.Top = 1.27;

        if(typeof body_pr.rIns === "number")
            paddings.Right = body_pr.rIns;
        else
            paddings.Right = 2.54;

        if(typeof body_pr.bIns === "number")
            paddings.Bottom = body_pr.bIns;
        else
            paddings.Bottom = 1.27;
    }
    return ret;
}

function CreateAscShapePropFromProp(shapeProp)
{
    var obj = new asc_CShapeProperty();
    if(!isRealObject(shapeProp))
        return obj;
    if(isRealBool(shapeProp.locked))
    {
        obj.Locked = shapeProp.locked;
    }
    obj.lockAspect = shapeProp.lockAspect;
    if(typeof shapeProp.type === "string")
        obj.type = shapeProp.type;
    if(isRealObject(shapeProp.fill))
        obj.fill = CreateAscFill(shapeProp.fill);
    if(isRealObject(shapeProp.stroke))
        obj.stroke = CreateAscStroke(shapeProp.stroke, shapeProp.canChangeArrows);
    if(isRealObject(shapeProp.paddings))
        obj.paddings = shapeProp.paddings;
    if(shapeProp.canFill === true || shapeProp.canFill === false)
    {
        obj.canFill = shapeProp.canFill;
    }
    obj.bFromChart = shapeProp.bFromChart;
    obj.bFromImage = shapeProp.bFromImage;
    obj.w = shapeProp.w;
    obj.h = shapeProp.h;
    obj.vert = shapeProp.vert;
    obj.verticalTextAlign = shapeProp.verticalTextAlign;
    if(shapeProp.textArtProperties)
    {
        obj.textArtProperties = CreateAscTextArtProps(shapeProp.textArtProperties);
    }
    obj.title = shapeProp.title;
    obj.description = shapeProp.description;
    obj.columnNumber = shapeProp.columnNumber;
    obj.columnSpace = shapeProp.columnSpace;
    if(shapeProp.signatureId)
    {
        obj.signatureId = shapeProp.signatureId;
    }
    return obj;
}

function CorrectShapeProp(asc_shape_prop, shape)
{
    if (null == shape || null == asc_shape_prop)
        return;

    shape.spPr.Fill = CorrectUniFill(asc_shape_prop.asc_getFill(), shape.spPr.Fill);
    shape.spPr.ln = CorrectUniFill(asc_shape_prop.asc_getStroke(), shape.spPr.ln);
}


function CreateAscTextArtProps(oTextArtProps)
{
    if(!oTextArtProps)
    {
        return undefined;
    }
    var oRet = new Asc.asc_TextArtProperties();
    if(oTextArtProps.Fill)
    {
        oRet.asc_putFill(CreateAscFill(oTextArtProps.Fill));
    }
    if(oTextArtProps.Line)
    {
        oRet.asc_putLine(CreateAscStroke(oTextArtProps.Line, false));
    }
    oRet.asc_putForm(oTextArtProps.Form);
    return oRet;
}

function CreateUnifillFromAscColor(asc_color, editorId)
{
    var Unifill = new CUniFill();
    Unifill.fill = new CSolidFill();
    Unifill.fill.color = CorrectUniColor(asc_color, Unifill.fill.color, editorId);
    return Unifill;
}

function CorrectUniColor(asc_color, unicolor, flag)
{
    if (null == asc_color)
        return unicolor;

    var ret = unicolor;
    if (null == ret)
        ret = new CUniColor();

    var _type = asc_color.asc_getType();
    switch (_type)
    {
        case c_oAscColor.COLOR_TYPE_PRST:
        {
            if (ret.color == null || ret.color.type != c_oAscColor.COLOR_TYPE_PRST)
            {
                ret.color = new CPrstColor();
            }
            ret.color.id = asc_color.value;

            if (ret.Mods.Mods.length != 0)
                ret.Mods.Mods.splice(0, ret.Mods.Mods.length);
            break;
        }
        case c_oAscColor.COLOR_TYPE_SCHEME:
        {
            if (ret.color == null || ret.color.type != c_oAscColor.COLOR_TYPE_SCHEME)
            {
                ret.color = new CSchemeColor();
            }

            // тут выставляется ТОЛЬКО из меню. поэтому:
            var _index = parseInt(asc_color.value);
            if(isNaN(_index))
                break;
            var _id = (_index / 6) >> 0;
            var _pos = _index - _id * 6;

            var array_colors_types = [6, 15, 7, 16, 0, 1, 2, 3, 4, 5];
            ret.color.id = array_colors_types[_id];
            if(!ret.Mods)
            {
                ret.setMods(new CColorModifiers());
            }

            if (ret.Mods.Mods.length != 0)
                ret.Mods.Mods.splice(0, ret.Mods.Mods.length);

            var __mods = null;

            var _flag;
            if (editor && editor.WordControl && editor.WordControl.m_oDrawingDocument && editor.WordControl.m_oDrawingDocument.GuiControlColorsMap)
            {
                var _map = editor.WordControl.m_oDrawingDocument.GuiControlColorsMap;
                _flag = isRealNumber(flag) ? flag : 1;
                __mods = AscCommon.GetDefaultMods(_map[_id].r, _map[_id].g, _map[_id].b, _pos, _flag);
            }
            else
            {
                var _editor = window["Asc"] && window["Asc"]["editor"];
                if (_editor && _editor.wbModel)
                {
                    var _theme = _editor.wbModel.theme;
                    var _clrMap = _editor.wbModel.clrSchemeMap;

                    if (_theme && _clrMap)
                    {
                        var _schemeClr = new CSchemeColor();
                        _schemeClr.id = array_colors_types[_id];

                        var _rgba = {R:0, G:0, B:0, A:255};
                        _schemeClr.Calculate(_theme, _clrMap.color_map, _rgba);
                        _flag = isRealNumber(flag) ? flag : 0;
                        __mods = AscCommon.GetDefaultMods(_schemeClr.RGBA.R, _schemeClr.RGBA.G, _schemeClr.RGBA.B, _pos, _flag);
                    }
                }
            }

            if (null != __mods)
            {
                ret.Mods.Mods = __mods;
            }

            break;
        }
        default:
        {
            if (ret.color == null || ret.color.type != c_oAscColor.COLOR_TYPE_SRGB)
            {
                ret.color = new CRGBColor();
            }
            ret.color.RGBA.R = asc_color.r;
            ret.color.RGBA.G = asc_color.g;
            ret.color.RGBA.B = asc_color.b;
            ret.color.RGBA.A = asc_color.a;

            if (ret.Mods && ret.Mods.Mods.length != 0)
                ret.Mods.Mods.splice(0, ret.Mods.Mods.length);
        }
    }
    return ret;
}

    function deleteDrawingBase(aObjects, graphicId)
    {
        var position = null;
        for (var i = 0; i < aObjects.length; i++) {
            if ( aObjects[i].graphicObject.Get_Id() == graphicId ) {
                aObjects.splice(i, 1);
                position = i;
                break;
            }
        }
        return position;
    }


    /* Common Functions For Builder*/
    function builder_CreateShape(sType, nWidth, nHeight, oFill, oStroke, oParent, oTheme, oDrawingDocument, bWord, worksheet){
        var oShapeTrack = new AscFormat.NewShapeTrack(sType, 0, 0, oTheme, null, null, null, 0);
        oShapeTrack.track({}, nWidth, nHeight);
        var oShape = oShapeTrack.getShape(bWord === true, oDrawingDocument, null);
        oShape.setParent(oParent);
        if(worksheet){
            oShape.setWorksheet(worksheet);
        }
        if(bWord){
            oShape.createTextBoxContent();
        }
        else{
            oShape.createTextBody();
        }
        oShape.spPr.setFill(oFill);
        oShape.spPr.setLn(oStroke);
        return oShape;
    }

    function builder_CreateChart(nW, nH, sType, aCatNames, aSeriesNames, aSeries, nStyleIndex){
        var settings = new Asc.asc_ChartSettings();
        switch (sType)
        {
            case "bar" :
            {
                settings.type = Asc.c_oAscChartTypeSettings.barNormal;
                break;
            }
            case "barStacked":
            {
                settings.type = Asc.c_oAscChartTypeSettings.barStacked;
                break;
            }
            case "barStackedPercent":
            {
                settings.type = Asc.c_oAscChartTypeSettings.barStackedPer;
                break;
            }
            case "bar3D":
            {
                settings.type = Asc.c_oAscChartTypeSettings.barNormal3d;
                break;
            }
            case "barStacked3D":
            {
                settings.type = Asc.c_oAscChartTypeSettings.barStacked3d;
                break;
            }
            case "barStackedPercent3D":
            {
                settings.type = Asc.c_oAscChartTypeSettings.barStackedPer3d;
                break;
            }
            case "barStackedPercent3DPerspective":
            {
                settings.type = Asc.c_oAscChartTypeSettings.barNormal3dPerspective;
                break;
            }
            case "horizontalBar":
            {
                settings.type = Asc.c_oAscChartTypeSettings.hBarNormal;
                break;
            }
            case "horizontalBarStacked":
            {
                settings.type = Asc.c_oAscChartTypeSettings.hBarStacked;
                break;
            }
            case "horizontalBarStackedPercent":
            {
                settings.type = Asc.c_oAscChartTypeSettings.hBarStackedPer;
                break;
            }
            case "horizontalBar3D":
            {
                settings.type = Asc.c_oAscChartTypeSettings.hBarNormal3d;
                break;
            }
            case "horizontalBarStacked3D":
            {
                settings.type = Asc.c_oAscChartTypeSettings.hBarStacked3d;
                break;
            }
            case "horizontalBarStackedPercent3D":
            {
                settings.type = Asc.c_oAscChartTypeSettings.hBarStackedPer3d;
                break;
            }
            case "lineNormal":
            {
                settings.type = Asc.c_oAscChartTypeSettings.lineNormal;
                break;
            }
            case "lineStacked":
            {
                settings.type = Asc.c_oAscChartTypeSettings.lineStacked;
                break;
            }
            case "lineStackedPercent":
            {
                settings.type = Asc.c_oAscChartTypeSettings.lineStackedPer;
                break;
            }
            case "line3D":
            {
                settings.type = Asc.c_oAscChartTypeSettings.line3d;
                break;
            }
            case "pie":
            {
                settings.type = Asc.c_oAscChartTypeSettings.pie;
                break;
            }
            case "pie3D":
            {
                settings.type = Asc.c_oAscChartTypeSettings.pie3d;
                break;
            }
            case "doughnut":
            {
                settings.type = Asc.c_oAscChartTypeSettings.doughnut;
                break;
            }
            case "scatter":
            {
                settings.type = Asc.c_oAscChartTypeSettings.scatter;
                break;
            }
            case "stock":
            {
                settings.type = Asc.c_oAscChartTypeSettings.stock;
                break;
            }
            case "area":
            {
                settings.type = Asc.c_oAscChartTypeSettings.areaNormal;
                break;
            }
            case "areaStacked":
            {
                settings.type = Asc.c_oAscChartTypeSettings.areaStacked;
                break;
            }
            case "areaStackedPercent":
            {
                settings.type = Asc.c_oAscChartTypeSettings.areaStackedPer;
                break;
            }
        }
        var aAscSeries = [];
        var aAlphaBet = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
        var oCat, i;
        if(aCatNames.length > 0)
        {
            var aNumCache = [];
            for(i = 0; i < aCatNames.length; ++i)
            {
                aNumCache.push({val: aCatNames[i] + ""});
            }
            oCat = { Formula: "Sheet1!$B$1:$" + AscFormat.CalcLiterByLength(aAlphaBet, aCatNames.length) + "$1", NumCache: aNumCache };
        }
        for(i = 0; i < aSeries.length; ++i)
        {
            var oAscSeries = new AscFormat.asc_CChartSeria();
            oAscSeries.Val.NumCache = [];
            var aData = aSeries[i];
            var sEndLiter = AscFormat.CalcLiterByLength(aAlphaBet, aData.length);
            oAscSeries.Val.Formula = 'Sheet1!' + '$B$' + (i + 2) + ':$' + sEndLiter + '$' + (i + 2);
            if(aSeriesNames[i])
            {
                oAscSeries.TxCache.Formula =  'Sheet1!' + '$A$' + (i + 2);
                oAscSeries.TxCache.Tx = aSeriesNames[i];
            }
            if(oCat)
            {
                oAscSeries.Cat = oCat;
            }
            for(var j = 0; j < aData.length; ++j)
            {

                oAscSeries.Val.NumCache.push({ numFormatStr: "General", isDateTimeFormat: false, val: aData[j], isHidden: false });
            }
            aAscSeries.push(oAscSeries);
        }
        var chartSeries = {series: aAscSeries, parsedHeaders: {bLeft: true, bTop: true}};

        var oChartSpace = AscFormat.DrawingObjectsController.prototype._getChartSpace(chartSeries, settings, true);
        if(!oChartSpace)
        {
            return null;
        }
        oChartSpace.setBDeleted(false);
        oChartSpace.extX = nW;
        oChartSpace.extY = nH;
        if(AscFormat.isRealNumber(nStyleIndex)){
            oChartSpace.setStyle(nStyleIndex);
        }
        AscFormat.CheckSpPrXfrm(oChartSpace);
        return oChartSpace;
    }

    function builder_CreateGroup(aDrawings, oController){
        if(!oController){
            return null;
        }
        var aForGroup = [];
        for(var i = 0; i < aDrawings.length; ++i){
            if(!aDrawings[i].Drawing || !aDrawings[i].Drawing.canGroup()){
                return null;
            }
            aForGroup.push(aDrawings[i].Drawing);
        }
        return oController.getGroup(aForGroup);
    }

    function builder_CreateSchemeColor(sColorId){
        var oUniColor = new AscFormat.CUniColor();
        oUniColor.setColor(new AscFormat.CSchemeColor());
        switch(sColorId)
        {
            case "accent1": {  oUniColor.color.id  = 0; break;}
            case "accent2": {  oUniColor.color.id  = 1; break;}
            case "accent3": {  oUniColor.color.id  = 2; break;}
            case "accent4": {  oUniColor.color.id  = 3; break;}
            case "accent5": {  oUniColor.color.id  = 4; break;}
            case "accent6": {  oUniColor.color.id  = 5; break;}
            case "bg1": {  oUniColor.color.id      = 6; break;}
            case "bg2": {  oUniColor.color.id      = 7; break;}
            case "dk1": {  oUniColor.color.id      = 8; break;}
            case "dk2": {  oUniColor.color.id      = 9; break;}
            case "lt1": {  oUniColor.color.id      = 12; break;}
            case "lt2": {  oUniColor.color.id      = 13; break;}
            case "tx1": {  oUniColor.color.id      = 15; break;}
            case "tx2": {  oUniColor.color.id      = 16; break;}
            default: {  oUniColor.color.id      = 16; break;}
        }
        return oUniColor;
    }

    function builder_CreatePresetColor(sPresetColor){
        var oUniColor = new AscFormat.CUniColor();
        oUniColor.setColor(new AscFormat.CPrstColor());
        oUniColor.color.id = sPresetColor;
        return oUniColor;
    }

    function builder_CreateGradientStop(oUniColor, nPos){
        var Gs = new AscFormat.CGs();
        Gs.pos = nPos;
        Gs.color = oUniColor;
        return Gs;
    }

    function builder_CreateGradient(aGradientStop){
        var oUniFill = new AscFormat.CUniFill();
        oUniFill.fill = new AscFormat.CGradFill();
        for(var i = 0; i < aGradientStop.length; ++i)
        {
            oUniFill.fill.colors.push(aGradientStop[i].Gs);
        }
        return oUniFill;
    }

    function builder_CreateLinearGradient(aGradientStop, Angle){
        var oUniFill = builder_CreateGradient(aGradientStop);
        oUniFill.fill.lin = new AscFormat.GradLin();
        if(!AscFormat.isRealNumber(Angle)){
            oUniFill.fill.lin.angle = 0;
        }
        else{
            oUniFill.fill.lin.angle = Angle;
        }
        return oUniFill;
    }

    function builder_CreateRadialGradient(aGradientStop){
        var oUniFill = builder_CreateGradient(aGradientStop);
        oUniFill.fill.path = new AscFormat.GradPath();
        return oUniFill;
    }

    function builder_CreatePatternFill(sPatternType, BgColor, FgColor){
        var oUniFill = new AscFormat.CUniFill();
        oUniFill.fill = new AscFormat.CPattFill();
        oUniFill.fill.ftype = AscCommon.global_hatch_offsets[sPatternType];
        oUniFill.fill.fgClr = FgColor.Unicolor;
        oUniFill.fill.bgClr = BgColor.Unicolor;
        return oUniFill;
    }

    function builder_CreateBlipFill(sImageUrl, sBlipFillType){
        var oUniFill = new AscFormat.CUniFill();
        oUniFill.fill = new AscFormat.CBlipFill();
        oUniFill.fill.RasterImageId = sImageUrl;
        if(sBlipFillType === "tile")
        {
            oUniFill.fill.tile = new AscFormat.CBlipFillTile();
        }
        else if(sBlipFillType === "stretch")
        {
            oUniFill.fill.stretch = true;
        }
        return oUniFill;
    }

    function builder_CreateLine(nWidth, oFill) {
        if(nWidth === 0)
        {
            return new AscFormat.CreateNoFillLine();
        }
        var oLn = new AscFormat.CLn();
        oLn.w = nWidth;
        oLn.Fill = oFill.UniFill;
        return oLn;
    }

    function builder_CreateChartTitle(sTitle, nFontSize, bIsBold, oDrawingDocument){
        if(typeof sTitle === "string" && sTitle.length > 0){
            var oTitle = new AscFormat.CTitle();
            oTitle.setOverlay(false);
            oTitle.setTx(new AscFormat.CChartText());
            var oTextBody = AscFormat.CreateTextBodyFromString(sTitle, oDrawingDocument, oTitle.tx);
            if(AscFormat.isRealNumber(nFontSize)){
                oTextBody.content.Set_ApplyToAll(true);
                oTextBody.content.AddToParagraph(new ParaTextPr({ FontSize : nFontSize, Bold: bIsBold}));
                oTextBody.content.Set_ApplyToAll(false);
            }
            oTitle.tx.setRich(oTextBody);
            return oTitle;
        }
        return null;
    }


    function builder_CreateTitle(sTitle, nFontSize, bIsBold, oChartSpace)
    {
        if(typeof sTitle === "string" && sTitle.length > 0){
            var oTitle = new AscFormat.CTitle();
            oTitle.setOverlay(false);
            oTitle.setTx(new AscFormat.CChartText());
            var oTextBody = AscFormat.CreateTextBodyFromString(sTitle, oChartSpace.getDrawingDocument(), oTitle.tx);
            if(AscFormat.isRealNumber(nFontSize)){
                oTextBody.content.Set_ApplyToAll(true);
                oTextBody.content.AddToParagraph(new ParaTextPr({ FontSize : nFontSize, Bold: bIsBold}));
                oTextBody.content.Set_ApplyToAll(false);
            }
            oTitle.tx.setRich(oTextBody);
            return oTitle;
        }
        return null;
    }

    function builder_SetChartTitle(oChartSpace, sTitle, nFontSize, bIsBold){
        if(oChartSpace){
            oChartSpace.chart.setTitle(builder_CreateChartTitle(sTitle, nFontSize, bIsBold, oChartSpace.getDrawingDocument()));
        }
    }

    function builder_SetChartHorAxisTitle(oChartSpace, sTitle, nFontSize, bIsBold){
        if(oChartSpace){
            var horAxis = oChartSpace.chart.plotArea.getHorizontalAxis();
            if(horAxis){
                horAxis.setTitle(builder_CreateTitle(sTitle, nFontSize, bIsBold, oChartSpace));
            }
        }
    }

    function builder_SetChartVertAxisTitle(oChartSpace, sTitle, nFontSize, bIsBold){
        if(oChartSpace){
            var verAxis = oChartSpace.chart.plotArea.getVerticalAxis();
            if(verAxis)
            {
                if(typeof sTitle === "string" && sTitle.length > 0)
                {
                    verAxis.setTitle(builder_CreateTitle(sTitle, nFontSize, bIsBold, oChartSpace));
                    if(verAxis.title){
                        var _body_pr = new AscFormat.CBodyPr();
                        _body_pr.reset();
                        if(!verAxis.title.txPr)
                        {
                            verAxis.title.setTxPr(AscFormat.CreateTextBodyFromString("", oChartSpace.getDrawingDocument(), verAxis.title));
                        }
                        var _text_body =  verAxis.title.txPr;
                        _text_body.setBodyPr(_body_pr);
                        verAxis.title.setOverlay(false);
                    }
                }
                else
                {
                    verAxis.setTitle(null);
                }
            }
        }
    }

    function builder_SetChartVertAxisOrientation(oChartSpace, bIsMinMax) {
        if(oChartSpace){
            var verAxis = oChartSpace.chart.plotArea.getVerticalAxis();
            if(verAxis)
            {
                if(!verAxis.scaling)
                    verAxis.setScaling(new CScaling());
                var scaling = verAxis.scaling;
                if(bIsMinMax){
                    scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
                }
                else{
                    scaling.setOrientation(AscFormat.ORIENTATION_MAX_MIN);
                }
            }
        }
    }

    function builder_SetChartHorAxisOrientation(oChartSpace, bIsMinMax){
        if(oChartSpace){
            var horAxis = oChartSpace.chart.plotArea.getHorizontalAxis();
            if(horAxis){
                if(!horAxis.scaling)
                    horAxis.setScaling(new CScaling());
                var scaling = horAxis.scaling;
                if(bIsMinMax){
                    scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
                }
                else{
                    scaling.setOrientation(AscFormat.ORIENTATION_MAX_MIN);
                }
            }
        }
    }

    function builder_SetChartLegendPos(oChartSpace, sLegendPos){

        if(oChartSpace && oChartSpace.chart)
        {
            if(sLegendPos === "none")
            {
                if(oChartSpace.chart.legend)
                {
                    oChartSpace.chart.setLegend(null);
                }
            }
            else
            {
                var nLegendPos = null;
                switch(sLegendPos)
                {
                    case "left":
                    {
                        nLegendPos = Asc.c_oAscChartLegendShowSettings.left;
                        break;
                    }
                    case "top":
                    {
                        nLegendPos = Asc.c_oAscChartLegendShowSettings.top;
                        break;
                    }
                    case "right":
                    {
                        nLegendPos = Asc.c_oAscChartLegendShowSettings.right;
                        break;
                    }
                    case "bottom":
                    {
                        nLegendPos = Asc.c_oAscChartLegendShowSettings.bottom;
                        break;
                    }
                }
                if(null !== nLegendPos)
                {
                    if(!oChartSpace.chart.legend)
                    {
                        oChartSpace.chart.setLegend(new AscFormat.CLegend());
                    }
                    if(oChartSpace.chart.legend.legendPos !== nLegendPos)
                        oChartSpace.chart.legend.setLegendPos(nLegendPos);
                    if(oChartSpace.chart.legend.overlay !== false)
                    {
                        oChartSpace.chart.legend.setOverlay(false);
                    }
                }
            }
        }
    }

    function builder_SetObjectFontSize(oObject, nFontSize, oDrawingDocument){
        if(!oObject){
            return;
        }
        if(!oObject.txPr)
        {
            oObject.setTxPr(new AscFormat.CTextBody());
        }
        if(!oObject.txPr.bodyPr)
        {
            oObject.txPr.setBodyPr(new AscFormat.CBodyPr());
        }
        if(!oObject.txPr.content)
        {
            oObject.txPr.setContent(new AscFormat.CDrawingDocContent(oObject.txPr, oDrawingDocument, 0, 0, 100, 500, false, false, true));
        }
        var oPr = oObject.txPr.content.Content[0].Pr.Copy();
        if(!oPr.DefaultRunPr){
            oPr.DefaultRunPr = new AscCommonWord.CTextPr();
        }
        oPr.DefaultRunPr.FontSize = nFontSize;
        oObject.txPr.content.Content[0].Set_Pr(oPr);
    }

    function builder_SetLegendFontSize(oChartSpace, nFontSize){
        builder_SetObjectFontSize(oChartSpace.chart.legend, nFontSize, oChartSpace.getDrawingDocument());
    }

    function builder_SetHorAxisFontSize(oChartSpace, nFontSize){
        builder_SetObjectFontSize(oChartSpace.chart.plotArea.getHorizontalAxis(), nFontSize, oChartSpace.getDrawingDocument());
    }

    function builder_SetVerAxisFontSize(oChartSpace, nFontSize){
        builder_SetObjectFontSize(oChartSpace.chart.plotArea.getVerticalAxis(), nFontSize, oChartSpace.getDrawingDocument());
    }


    function builder_SetShowPointDataLabel(oChartSpace, nSeriesIndex, nPointIndex, bShowSerName, bShowCatName, bShowVal, bShowPerecent){
        if(oChartSpace && oChartSpace.chart && oChartSpace.chart.plotArea && oChartSpace.chart.plotArea.charts[0]){
            var oChart =  oChartSpace.chart.plotArea.charts[0];
            var bPieChart = oChart.getObjectType() === AscDFH.historyitem_type_PieChart || oChart.getObjectType() === AscDFH.historyitem_type_DoughnutChart;
            var ser = oChart.series[nSeriesIndex];
            if(ser){
                {
                    if(!ser.dLbls){
                        if(oChart.dLbls){
                            ser.setDLbls(oChart.dLbls.createDuplicate());
                        }
                        else{
                            ser.setDLbls(new AscFormat.CDLbls());
                            ser.dLbls.setSeparator(",");
                            ser.dLbls.setShowSerName(false);
                            ser.dLbls.setShowCatName(false);
                            ser.dLbls.setShowVal(false);
                            ser.dLbls.setShowLegendKey(false);
                            if(bPieChart){
                                ser.dLbls.setShowPercent(false);
                            }
                            ser.dLbls.setShowBubbleSize(false);
                        }
                    }
                    var dLbl  = ser.dLbls.findDLblByIdx(nPointIndex);
                    if(!dLbl)
                    {
                        dLbl = new AscFormat.CDLbl();
                        dLbl.setIdx(nPointIndex);
                        if(ser.dLbls.txPr)
                        {
                            dLbl.merge(ser.dLbls);
                        }
                        ser.dLbls.addDLbl(dLbl);
                    }
                    dLbl.setSeparator(",");
                    dLbl.setShowSerName(true == bShowSerName);
                    dLbl.setShowCatName(true == bShowCatName);
                    dLbl.setShowVal(true == bShowVal);
                    dLbl.setShowLegendKey(false);
                    if(bPieChart){
                        dLbl.setShowPercent(true === bShowPerecent);
                    }
                    dLbl.setShowBubbleSize(false);
                }
            }
        }
    }

    function builder_SetShowDataLabels(oChartSpace, bShowSerName, bShowCatName, bShowVal, bShowPerecent){
        if(oChartSpace && oChartSpace.chart && oChartSpace.chart.plotArea && oChartSpace.chart.plotArea.charts[0]){
            var oChart = oChartSpace.chart.plotArea.charts[0];
            var bPieChart = oChart.getObjectType() === AscDFH.historyitem_type_PieChart || oChart.getObjectType() === AscDFH.historyitem_type_DoughnutChart;
            if(false == bShowSerName && false == bShowCatName && false == bShowVal && (bPieChart && bShowPerecent === false))
            {
                if(oChart.dLbls)
                {
                    oChart.setDLbls(null);
                }
            }
            if(!oChart.dLbls)
            {
                oChart.setDLbls(new AscFormat.CDLbls());
            }
            oChart.dLbls.setSeparator(",");
            oChart.dLbls.setShowSerName(true == bShowSerName);
            oChart.dLbls.setShowCatName(true == bShowCatName);
            oChart.dLbls.setShowVal(true == bShowVal);
            oChart.dLbls.setShowLegendKey(false);
            if(bPieChart){
                oChart.dLbls.setShowPercent(true === bShowPerecent);
            }

            oChart.dLbls.setShowBubbleSize(false);
        }
    }

    function builder_SetChartAxisLabelsPos(oAxis, sPosition){
        if(!oAxis || !oAxis.setTickLblPos){
            return;
        }
        var nPositionType = null;
        var c_oAscTickLabelsPos = window['Asc'].c_oAscTickLabelsPos;
        switch(sPosition){
            case "high":{
                nPositionType = c_oAscTickLabelsPos.TICK_LABEL_POSITION_HIGH;
                break;
            }
            case "low":{
                nPositionType = c_oAscTickLabelsPos.TICK_LABEL_POSITION_LOW;
                break;
            }
            case "nextTo":{
                nPositionType = c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO;
                break;
            }
            case "none":{
                nPositionType = c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE;
                break;
            }
        }
        if(nPositionType !== null){
            oAxis.setTickLblPos(nPositionType);
        }
    }

    function builder_SetChartVertAxisTickLablePosition(oChartSpace, sPosition){
        if(oChartSpace){
            builder_SetChartAxisLabelsPos(oChartSpace.chart.plotArea.getVerticalAxis(), sPosition);
        }
    }

    function builder_SetChartHorAxisTickLablePosition(oChartSpace, sPosition){
        if(oChartSpace){
            builder_SetChartAxisLabelsPos(oChartSpace.chart.plotArea.getHorizontalAxis(), sPosition);
        }
    }

    function builder_GetTickMark(sTickMark){
        var nNewTickMark = null;
        switch(sTickMark){
            case 'cross':
            {
                nNewTickMark = Asc.c_oAscTickMark.TICK_MARK_CROSS;
                break;
            }
            case 'in':
            {
                nNewTickMark = Asc.c_oAscTickMark.TICK_MARK_IN;
                break;
            }
            case 'none':
            {
                nNewTickMark = Asc.c_oAscTickMark.TICK_MARK_NONE;
                break;
            }
            case 'out':
            {
                nNewTickMark = Asc.c_oAscTickMark.TICK_MARK_OUT;
                break;
            }
        }
        return nNewTickMark;
    }

    function builder_SetChartAxisMajorTickMark(oAxis, sTickMark){
        if(!oAxis){
            return;
        }
        var nNewTickMark = builder_GetTickMark(sTickMark);
        if(nNewTickMark !== null){
            oAxis.setMajorTickMark(nNewTickMark);
        }
    }

    function builder_SetChartAxisMinorTickMark(oAxis, sTickMark){
        if(!oAxis){
            return;
        }
        var nNewTickMark = builder_GetTickMark(sTickMark);
        if(nNewTickMark !== null){
            oAxis.setMinorTickMark(nNewTickMark);
        }
    }

    function builder_SetChartHorAxisMajorTickMark(oChartSpace, sTickMark){
        if(oChartSpace){
            builder_SetChartAxisMajorTickMark(oChartSpace.chart.plotArea.getHorizontalAxis(), sTickMark);
        }
    }

    function builder_SetChartHorAxisMinorTickMark(oChartSpace, sTickMark){
        if(oChartSpace){
            builder_SetChartAxisMinorTickMark(oChartSpace.chart.plotArea.getHorizontalAxis(), sTickMark);
        }
    }

    function builder_SetChartVerAxisMajorTickMark(oChartSpace, sTickMark){
        if(oChartSpace){
            builder_SetChartAxisMajorTickMark(oChartSpace.chart.plotArea.getVerticalAxis(), sTickMark);
        }
    }

    function builder_SetChartVerAxisMinorTickMark(oChartSpace, sTickMark){
        if(oChartSpace){
            builder_SetChartAxisMinorTickMark(oChartSpace.chart.plotArea.getVerticalAxis(), sTickMark);
        }
    }

    function builder_SetAxisMajorGridlines(oAxis, oLn){
        if(oAxis){
            if(!oAxis.majorGridlines){
                oAxis.setMajorGridlines(new AscFormat.CSpPr());
            }
            oAxis.majorGridlines.setLn(oLn);
            if(!oAxis.majorGridlines.Fill && !oAxis.majorGridlines.ln){
                oAxis.setMajorGridlines(null);
            }
        }
    }
    function builder_SetAxisMinorGridlines(oAxis, oLn){
        if(oAxis){
            if(!oAxis.minorGridlines){
                oAxis.setMinorGridlines(new AscFormat.CSpPr());
            }
            oAxis.minorGridlines.setLn(oLn);
            if(!oAxis.minorGridlines.Fill && !oAxis.minorGridlines.ln){
                oAxis.setMinorGridlines(null);
            }
        }
    }

    function builder_SetHorAxisMajorGridlines(oChartSpace, oLn){
        builder_SetAxisMajorGridlines(oChartSpace.chart.plotArea.getVerticalAxis(), oLn);
    }
    function builder_SetHorAxisMinorGridlines(oChartSpace, oLn){
        builder_SetAxisMinorGridlines(oChartSpace.chart.plotArea.getVerticalAxis(), oLn);
    }
    function builder_SetVerAxisMajorGridlines(oChartSpace, oLn){
        builder_SetAxisMajorGridlines(oChartSpace.chart.plotArea.getHorizontalAxis(), oLn);
    }
    function builder_SetVerAxisMinorGridlines(oChartSpace, oLn){
        builder_SetAxisMinorGridlines(oChartSpace.chart.plotArea.getHorizontalAxis(), oLn);
    }

    //----------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].CreateFontRef = CreateFontRef;
    window['AscFormat'].CreatePresetColor = CreatePresetColor;
    window['AscFormat'].isRealNumber = isRealNumber;
    window['AscFormat'].isRealBool = isRealBool;
    window['AscFormat'].writeLong = writeLong;
    window['AscFormat'].readLong = readLong;
    window['AscFormat'].writeDouble = writeDouble;
    window['AscFormat'].readDouble = readDouble;
    window['AscFormat'].writeBool = writeBool;
    window['AscFormat'].readBool = readBool;
    window['AscFormat'].writeString = writeString;
    window['AscFormat'].readString = readString;
    window['AscFormat'].writeObject = writeObject;
    window['AscFormat'].readObject = readObject;
    window['AscFormat'].checkThemeFonts = checkThemeFonts;
    window['AscFormat'].ExecuteNoHistory = ExecuteNoHistory;
    window['AscFormat'].checkTableCellPr = checkTableCellPr;
    window['AscFormat'].CColorMod = CColorMod;
    window['AscFormat'].CColorModifiers = CColorModifiers;
    window['AscFormat'].CSysColor = CSysColor;
    window['AscFormat'].CPrstColor = CPrstColor;
    window['AscFormat'].CRGBColor = CRGBColor;
    window['AscFormat'].CSchemeColor = CSchemeColor;
    window['AscFormat'].CUniColor = CUniColor;
    window['AscFormat'].CreateUniColorRGB = CreateUniColorRGB;
    window['AscFormat'].CreteSolidFillRGB = CreteSolidFillRGB;
    window['AscFormat'].CreateSolidFillRGBA = CreateSolidFillRGBA;
    window['AscFormat'].CSrcRect = CSrcRect;
    window['AscFormat'].CBlipFillTile = CBlipFillTile;
    window['AscFormat'].CBlipFill = CBlipFill;
    window['AscFormat'].CSolidFill = CSolidFill;
    window['AscFormat'].CGs = CGs;
    window['AscFormat'].GradLin = GradLin;
    window['AscFormat'].GradPath = GradPath;
    window['AscFormat'].CGradFill = CGradFill;
    window['AscFormat'].CPattFill = CPattFill;
    window['AscFormat'].CNoFill = CNoFill;
	window['AscFormat'].CGrpFill = CGrpFill;
    window['AscFormat'].CUniFill = CUniFill;
    window['AscFormat'].CompareUniFill = CompareUniFill;
    window['AscFormat'].CompareUnifillBool = CompareUnifillBool;
    window['AscFormat'].CompareShapeProperties = CompareShapeProperties;
    window['AscFormat'].EndArrow = EndArrow;
    window['AscFormat'].ConvertJoinAggType = ConvertJoinAggType;
    window['AscFormat'].LineJoin = LineJoin;
    window['AscFormat'].CLn = CLn;
    window['AscFormat'].DefaultShapeDefinition = DefaultShapeDefinition;
    window['AscFormat'].CNvPr = CNvPr;
    window['AscFormat'].NvPr = NvPr;
    window['AscFormat'].Ph = Ph;
    window['AscFormat'].UniNvPr = UniNvPr;
    window['AscFormat'].StyleRef = StyleRef;
    window['AscFormat'].FontRef = FontRef;
    window['AscFormat'].CShapeStyle = CShapeStyle;
    window['AscFormat'].CreateDefaultShapeStyle = CreateDefaultShapeStyle;
    window['AscFormat'].CXfrm = CXfrm;
    window['AscFormat'].CSpPr = CSpPr;
    window['AscFormat'].ClrScheme = ClrScheme;
    window['AscFormat'].ClrMap = ClrMap;
    window['AscFormat'].ExtraClrScheme = ExtraClrScheme;
    window['AscFormat'].FontCollection = FontCollection;
    window['AscFormat'].FontScheme = FontScheme;
    window['AscFormat'].FmtScheme = FmtScheme;
    window['AscFormat'].ThemeElements = ThemeElements;
    window['AscFormat'].CTheme = CTheme;
    window['AscFormat'].HF = HF;
    window['AscFormat'].CBgPr = CBgPr;
    window['AscFormat'].CBg = CBg;
    window['AscFormat'].CSld = CSld;
    window['AscFormat'].CTextStyles = CTextStyles;
    window['AscFormat'].redrawSlide = redrawSlide;
    window['AscFormat'].CTextFit = CTextFit;
    window['AscFormat'].CBodyPr = CBodyPr;
    window['AscFormat'].CHyperlink = CHyperlink;
    window['AscFormat'].CTextParagraphPr = CTextParagraphPr;
    window['AscFormat'].CompareBullets = CompareBullets;
    window['AscFormat'].CBullet = CBullet;
    window['AscFormat'].CBulletColor = CBulletColor;
    window['AscFormat'].CBulletSize = CBulletSize;
    window['AscFormat'].CBulletTypeface = CBulletTypeface;
    window['AscFormat'].CBulletType = CBulletType;
    window['AscFormat'].TextListStyle = TextListStyle;
    window['AscFormat'].GenerateDefaultTheme = GenerateDefaultTheme;
    window['AscFormat'].GenerateDefaultMasterSlide = GenerateDefaultMasterSlide;
    window['AscFormat'].GenerateDefaultSlideLayout = GenerateDefaultSlideLayout;
    window['AscFormat'].GenerateDefaultSlide = GenerateDefaultSlide;
    window['AscFormat'].CreateDefaultTextRectStyle = CreateDefaultTextRectStyle;
    window['AscFormat'].GenerateDefaultColorMap = GenerateDefaultColorMap;
    window['AscFormat'].CreateAscFill = CreateAscFill;
    window['AscFormat'].CorrectUniFill = CorrectUniFill;
    window['AscFormat'].CreateAscStroke = CreateAscStroke;
    window['AscFormat'].CorrectUniStroke = CorrectUniStroke;
    window['AscFormat'].CreateAscShapePropFromProp = CreateAscShapePropFromProp;
    window['AscFormat'].CreateAscTextArtProps = CreateAscTextArtProps;
    window['AscFormat'].CreateUnifillFromAscColor = CreateUnifillFromAscColor;
    window['AscFormat'].CorrectUniColor = CorrectUniColor;
    window['AscFormat'].deleteDrawingBase = deleteDrawingBase;
    window['AscFormat'].CNvUniSpPr = CNvUniSpPr;
    window['AscFormat'].UniMedia = UniMedia;
    window['AscFormat'].CT_Hyperlink = CT_Hyperlink;


    window['AscFormat'].builder_CreateShape = builder_CreateShape;
    window['AscFormat'].builder_CreateChart = builder_CreateChart;
    window['AscFormat'].builder_CreateGroup = builder_CreateGroup;
    window['AscFormat'].builder_CreateSchemeColor = builder_CreateSchemeColor;
    window['AscFormat'].builder_CreatePresetColor = builder_CreatePresetColor;
    window['AscFormat'].builder_CreateGradientStop = builder_CreateGradientStop;
    window['AscFormat'].builder_CreateLinearGradient = builder_CreateLinearGradient;
    window['AscFormat'].builder_CreateRadialGradient = builder_CreateRadialGradient;
    window['AscFormat'].builder_CreatePatternFill = builder_CreatePatternFill;
    window['AscFormat'].builder_CreateBlipFill = builder_CreateBlipFill;
    window['AscFormat'].builder_CreateLine    = builder_CreateLine;
    window['AscFormat'].builder_SetChartTitle = builder_SetChartTitle;
    window['AscFormat'].builder_SetChartHorAxisTitle = builder_SetChartHorAxisTitle;
    window['AscFormat'].builder_SetChartVertAxisTitle = builder_SetChartVertAxisTitle;
    window['AscFormat'].builder_SetChartLegendPos = builder_SetChartLegendPos;
    window['AscFormat'].builder_SetShowDataLabels = builder_SetShowDataLabels;

    window['AscFormat'].builder_SetChartVertAxisOrientation = builder_SetChartVertAxisOrientation;
    window['AscFormat'].builder_SetChartHorAxisOrientation = builder_SetChartHorAxisOrientation;
    window['AscFormat'].builder_SetChartVertAxisTickLablePosition = builder_SetChartVertAxisTickLablePosition;
    window['AscFormat'].builder_SetChartHorAxisTickLablePosition = builder_SetChartHorAxisTickLablePosition;

    window['AscFormat'].builder_SetChartHorAxisMajorTickMark = builder_SetChartHorAxisMajorTickMark;
    window['AscFormat'].builder_SetChartHorAxisMinorTickMark = builder_SetChartHorAxisMinorTickMark;
    window['AscFormat'].builder_SetChartVerAxisMajorTickMark = builder_SetChartVerAxisMajorTickMark;
    window['AscFormat'].builder_SetChartVerAxisMinorTickMark = builder_SetChartVerAxisMinorTickMark;
    window['AscFormat'].builder_SetLegendFontSize = builder_SetLegendFontSize;
    window['AscFormat'].builder_SetHorAxisMajorGridlines = builder_SetHorAxisMajorGridlines;
    window['AscFormat'].builder_SetHorAxisMinorGridlines = builder_SetHorAxisMinorGridlines;
    window['AscFormat'].builder_SetVerAxisMajorGridlines = builder_SetVerAxisMajorGridlines;
    window['AscFormat'].builder_SetVerAxisMinorGridlines = builder_SetVerAxisMinorGridlines;
    window['AscFormat'].builder_SetHorAxisFontSize = builder_SetHorAxisFontSize;
    window['AscFormat'].builder_SetVerAxisFontSize = builder_SetVerAxisFontSize;
    window['AscFormat'].builder_SetShowPointDataLabel = builder_SetShowPointDataLabel;



    window['AscFormat'].Ax_Counter = Ax_Counter;
    window['AscFormat'].TYPE_TRACK = TYPE_TRACK;
    window['AscFormat'].TYPE_KIND = TYPE_KIND;
	window['AscFormat'].mapPrstColor = map_prst_color;
    window['AscFormat'].ar_arrow = ar_arrow;
    window['AscFormat'].ar_diamond = ar_diamond;
    window['AscFormat'].ar_none = ar_none;
    window['AscFormat'].ar_oval = ar_oval;
    window['AscFormat'].ar_stealth = ar_stealth;
    window['AscFormat'].ar_triangle = ar_triangle;
    window['AscFormat'].LineEndType = LineEndType;
    window['AscFormat'].LineEndSize = LineEndSize;
    window['AscFormat'].LineJoinType = LineJoinType;

    //типы плейсхолдеров
    window['AscFormat'].phType_body     = 0;
    window['AscFormat'].phType_chart    = 1;
    window['AscFormat'].phType_clipArt  = 2; //(Clip Art)
    window['AscFormat'].phType_ctrTitle = 3; //(Centered Title)
    window['AscFormat'].phType_dgm      = 4; //(Diagram)
    window['AscFormat'].phType_dt       = 5; //(Date and Time)
    window['AscFormat'].phType_ftr      = 6; //(Footer)
    window['AscFormat'].phType_hdr      = 7; //(Header)
    window['AscFormat'].phType_media    = 8; //(Media)
    window['AscFormat'].phType_obj      = 9; //(Object)
    window['AscFormat'].phType_pic      = 10; //(Picture)
    window['AscFormat'].phType_sldImg   = 11; //(Slide Image)
    window['AscFormat'].phType_sldNum   = 12; //(Slide Number)
    window['AscFormat'].phType_subTitle = 13; //(Subtitle)
    window['AscFormat'].phType_tbl      = 14; //(Table)
    window['AscFormat'].phType_title    = 15; //(Title)

    window['AscFormat'].fntStyleInd_none = 2;
    window['AscFormat'].fntStyleInd_major = 0;
    window['AscFormat'].fntStyleInd_minor = 1;

    window['AscFormat'].VERTICAL_ANCHOR_TYPE_BOTTOM = 0;
    window['AscFormat'].VERTICAL_ANCHOR_TYPE_CENTER = 1;
    window['AscFormat'].VERTICAL_ANCHOR_TYPE_DISTRIBUTED = 2;
    window['AscFormat'].VERTICAL_ANCHOR_TYPE_JUSTIFIED = 3;
    window['AscFormat'].VERTICAL_ANCHOR_TYPE_TOP = 4;

    //Vertical Text Types
    window['AscFormat'].nVertTTeaVert          = 0; //( ( East Asian Vertical ))
    window['AscFormat'].nVertTThorz            = 1; //( ( Horizontal ))
    window['AscFormat'].nVertTTmongolianVert   = 2; //( ( Mongolian Vertical ))
    window['AscFormat'].nVertTTvert            = 3; //( ( Vertical ))
    window['AscFormat'].nVertTTvert270         = 4;//( ( Vertical 270 ))
    window['AscFormat'].nVertTTwordArtVert     = 5;//( ( WordArt Vertical ))
    window['AscFormat'].nVertTTwordArtVertRtl  = 6;//(Vertical WordArt Right to Left)

    //Text Wrapping Types
    window['AscFormat'].nTWTNone   = 0;
    window['AscFormat'].nTWTSquare = 1;

    window['AscFormat'].text_fit_No         = 0;
    window['AscFormat'].text_fit_Auto       = 1;
    window['AscFormat'].text_fit_NormAuto   = 2;

    window['AscFormat'].BULLET_TYPE_COLOR_NONE	= 0;
    window['AscFormat'].BULLET_TYPE_COLOR_CLRTX	= 1;
    window['AscFormat'].BULLET_TYPE_COLOR_CLR	= 2;

    window['AscFormat'].BULLET_TYPE_SIZE_NONE	= 0;
    window['AscFormat'].BULLET_TYPE_SIZE_TX		= 1;
    window['AscFormat'].BULLET_TYPE_SIZE_PCT	= 2;
    window['AscFormat'].BULLET_TYPE_SIZE_PTS	= 3;

    window['AscFormat'].BULLET_TYPE_TYPEFACE_NONE	= 0;
    window['AscFormat'].BULLET_TYPE_TYPEFACE_TX		= 1;
    window['AscFormat'].BULLET_TYPE_TYPEFACE_BUFONT	= 2;

    window['AscFormat'].PARRUN_TYPE_NONE      = 0;
    window['AscFormat'].PARRUN_TYPE_RUN		  = 1;
    window['AscFormat'].PARRUN_TYPE_FLD		  = 2;
    window['AscFormat'].PARRUN_TYPE_BR		  = 3;
	window['AscFormat'].PARRUN_TYPE_MATH	  = 4;
	window['AscFormat'].PARRUN_TYPE_MATHPARA  = 5;

    window['AscFormat']._weight_body = _weight_body;
    window['AscFormat']._weight_chart = _weight_chart;
    window['AscFormat']._weight_clipArt = _weight_clipArt;
    window['AscFormat']._weight_ctrTitle = _weight_ctrTitle;
    window['AscFormat']._weight_dgm = _weight_dgm;
    window['AscFormat']._weight_media = _weight_media;
    window['AscFormat']._weight_obj = _weight_obj;
    window['AscFormat']._weight_pic = _weight_pic;
    window['AscFormat']._weight_subTitle = _weight_subTitle;
    window['AscFormat']._weight_tbl = _weight_tbl;
    window['AscFormat']._weight_title = _weight_title;

    window['AscFormat']._ph_multiplier = _ph_multiplier;

    window['AscFormat'].nSldLtTTitle = nSldLtTTitle;
    window['AscFormat'].nSldLtTObj = nSldLtTObj;
    window['AscFormat'].nSldLtTTx = nSldLtTTx;

    window['AscFormat']._arr_lt_types_weight = _arr_lt_types_weight;
    window['AscFormat']._global_layout_summs_array = _global_layout_summs_array;

    window['AscFormat'].nOTOwerflow = nOTOwerflow;
    window['AscFormat'].nOTClip = nOTClip;
    window['AscFormat'].nOTEllipsis = nOTEllipsis;

    window['AscFormat'].BULLET_TYPE_BULLET_NONE = BULLET_TYPE_BULLET_NONE;
    window['AscFormat'].BULLET_TYPE_BULLET_CHAR = BULLET_TYPE_BULLET_CHAR;
    window['AscFormat'].BULLET_TYPE_BULLET_AUTONUM = BULLET_TYPE_BULLET_AUTONUM;
    window['AscFormat'].BULLET_TYPE_BULLET_BLIP = BULLET_TYPE_BULLET_BLIP;

    window['AscFormat'].AUDIO_CD = AUDIO_CD;
    window['AscFormat'].WAV_AUDIO_FILE = WAV_AUDIO_FILE;
    window['AscFormat'].AUDIO_FILE = AUDIO_FILE;
    window['AscFormat'].VIDEO_FILE = VIDEO_FILE;
    window['AscFormat'].QUICK_TIME_FILE = QUICK_TIME_FILE;



    window['AscFormat'].DEFAULT_COLOR_MAP = GenerateDefaultColorMap();
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

/**
 * @param {Window} window
 * @param {undefined} undefined
 */
(function (window, undefined) {



    AscDFH.changesFactory[AscDFH.historyitem_AutoShapes_SetLocks] = AscDFH.CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_AutoShapes_SetDrawingBaseType] = AscDFH.CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_AutoShapes_SetWorksheet] = AscDFH.CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_ShapeSetBDeleted] = AscDFH.CChangesDrawingsBool;



    AscDFH.changesFactory[AscDFH.historyitem_AutoShapes_SetDrawingBasePos] = AscDFH.CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_AutoShapes_SetDrawingBaseExt] = AscDFH.CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_AutoShapes_SetDrawingBaseCoors] = AscDFH.CChangesDrawingsObjectNoId;


    var drawingsChangesMap = window['AscDFH'].drawingsChangesMap;

    drawingsChangesMap[AscDFH.historyitem_AutoShapes_SetLocks] = function(oClass, value){oClass.locks = value;};
    drawingsChangesMap[AscDFH.historyitem_ShapeSetBDeleted] = function(oClass, value){oClass.bDeleted = value;};
    drawingsChangesMap[AscDFH.historyitem_AutoShapes_SetDrawingBaseType] = function(oClass, value){
        if(oClass.drawingBase){
            oClass.drawingBase.Type = value;
        }
    };

    drawingsChangesMap[AscDFH.historyitem_AutoShapes_SetWorksheet] = function(oClass, value){
        if(typeof value === "string"){
            var oApi = window['Asc'] && window['Asc']['editor'];
            if(oApi && oApi.wbModel){
                oClass.worksheet = oApi.wbModel.getWorksheetById(value);
            }
            else{
                oClass.worksheet = null;
            }
        }
        else{
            oClass.worksheet = null;
        }
    };


    drawingsChangesMap[AscDFH.historyitem_AutoShapes_SetDrawingBasePos] = function(oClass, value){
        if(value){
            if(oClass.drawingBase && oClass.drawingBase.Pos){
                oClass.drawingBase.Pos.X = value.a;
                oClass.drawingBase.Pos.Y = value.b;
            }
        }
    };

    drawingsChangesMap[AscDFH.historyitem_AutoShapes_SetDrawingBaseExt] = function(oClass, value){
        if(value){
            if(oClass.drawingBase && oClass.drawingBase.ext){
                oClass.drawingBase.ext.cx = value.a;
                oClass.drawingBase.ext.cy = value.b;
            }
        }
    };
    drawingsChangesMap[AscDFH.historyitem_AutoShapes_SetDrawingBaseCoors] = function(oClass, value){
        if(value){
            if(oClass.drawingBase){
                oClass.drawingBase.from.col = value.fromCol;
                oClass.drawingBase.from.colOff = value.fromColOff;
                oClass.drawingBase.from.row = value.fromRow;
                oClass.drawingBase.from.rowOff = value.fromRowOff;
                oClass.drawingBase.to.col = value.toCol;
                oClass.drawingBase.to.colOff = value.toColOff;
                oClass.drawingBase.to.row = value.toRow;
                oClass.drawingBase.to.rowOff = value.toRowOff;
                oClass.drawingBase.Pos.X = value.posX;
                oClass.drawingBase.Pos.Y = value.posY;
                oClass.drawingBase.ext.cx = value.cx ;
                oClass.drawingBase.ext.cy = value.cy ;
            }
        }
    };

    AscDFH.drawingsConstructorsMap[AscDFH.historyitem_AutoShapes_SetDrawingBasePos] = CDrawingBaseCoordsWritable;
    AscDFH.drawingsConstructorsMap[AscDFH.historyitem_AutoShapes_SetDrawingBaseExt] = CDrawingBaseCoordsWritable;
    AscDFH.drawingsConstructorsMap[AscDFH.historyitem_AutoShapes_SetDrawingBaseCoors] = CDrawingBasePosWritable;

    var LOCKS_MASKS =
    {
        noGrp: 1,
        noUngrp: 4,
        noSelect: 16,
        noRot: 64,
        noChangeAspect: 256,
        noMove: 1024,
        noResize: 4096,
        noEditPoints: 16384,
        noAdjustHandles: 65536,
        noChangeArrowheads: 262144,
        noChangeShapeType: 1048576,
        noDrilldown: 4194304,
        noTextEdit: 8388608,
        noCrop: 16777216
    };

    function checkNormalRotate(rot)
    {
        var _rot = normalizeRotate(rot);
        return (_rot >= 0 && _rot < Math.PI * 0.25) || (_rot >= 3 * Math.PI * 0.25 && _rot < 5 * Math.PI * 0.25) || (_rot >= 7 * Math.PI * 0.25 && _rot < 2 * Math.PI);
    }

    function normalizeRotate(rot)
    {
        var new_rot = rot;
        if(AscFormat.isRealNumber(new_rot))
        {
            while(new_rot >= 2*Math.PI)
                new_rot -= 2*Math.PI;
            while(new_rot < 0)
                new_rot += 2*Math.PI;
            return new_rot;
        }
        return new_rot;
    }


    function CDrawingBaseCoordsWritable(a, b){
        this.a = a;
        this.b = b;
    }

    CDrawingBaseCoordsWritable.prototype.Write_ToBinary = function(Writer){
        Writer.WriteDouble(this.a);
        Writer.WriteDouble(this.b);
    };

    CDrawingBaseCoordsWritable.prototype.Read_FromBinary = function(Reader){
        this.a = Reader.GetDouble();
        this.b = Reader.GetDouble();
    };

    window['AscFormat'].CDrawingBaseCoordsWritable = CDrawingBaseCoordsWritable;

    function CDrawingBasePosWritable(oObject){

            this.fromCol       = null;
            this.fromColOff    = null;
            this.fromRow       = null;
            this.fromRowOff    = null;
            this.toCol         = null;
            this.toColOff      = null;
            this.toRow         = null;
            this.toRowOff      = null;
            this.posX          = null;
            this.posY          = null;
            this.cx            = null;
            this.cy            = null;
            if(oObject){
                this.fromCol       = oObject.fromCol   ;
                this.fromColOff    = oObject.fromColOff;
                this.fromRow       = oObject.fromRow   ;
                this.fromRowOff    = oObject.fromRowOff;
                this.toCol         = oObject.toCol     ;
                this.toColOff      = oObject.toColOff  ;
                this.toRow         = oObject.toRow     ;
                this.toRowOff      = oObject.toRowOff  ;
                this.posX          = oObject.posX      ;
                this.posY          = oObject.posY      ;
                this.cx            = oObject.cx        ;
                this.cy            = oObject.cy        ;
            }
    }

    CDrawingBasePosWritable.prototype.Write_ToBinary = function(Writer){
        AscFormat.writeDouble(Writer, this.fromCol      );
        AscFormat.writeDouble(Writer, this.fromColOff   );
        AscFormat.writeDouble(Writer, this.fromRow      );
        AscFormat.writeDouble(Writer, this.fromRowOff   );
        AscFormat.writeDouble(Writer, this.toCol        );
        AscFormat.writeDouble(Writer, this.toColOff     );
        AscFormat.writeDouble(Writer, this.toRow        );
        AscFormat.writeDouble(Writer, this.toRowOff     );
        AscFormat.writeDouble(Writer, this.posX         );
        AscFormat.writeDouble(Writer, this.posY         );
        AscFormat.writeDouble(Writer, this.cx           );
        AscFormat.writeDouble(Writer, this.cy           );
    };
    CDrawingBasePosWritable.prototype.Read_FromBinary = function(Reader){
        this.fromCol      = AscFormat.readDouble(Reader);
        this.fromColOff   = AscFormat.readDouble(Reader);
        this.fromRow      = AscFormat.readDouble(Reader);
        this.fromRowOff   = AscFormat.readDouble(Reader);
        this.toCol        = AscFormat.readDouble(Reader);
        this.toColOff     = AscFormat.readDouble(Reader);
        this.toRow        = AscFormat.readDouble(Reader);
        this.toRowOff     = AscFormat.readDouble(Reader);
        this.posX         = AscFormat.readDouble(Reader);
        this.posY         = AscFormat.readDouble(Reader);
        this.cx           = AscFormat.readDouble(Reader);
        this.cy           = AscFormat.readDouble(Reader);
    };
    /**
     * Class represent bounds graphical object
     * @param {number} l
     * @param {number} t
     * @param {number} r
     * @param {number} b
     * @constructor
     */
    function CGraphicBounds(l, t, r, b){
        this.l = l;
        this.t = t;
        this.r = r;
        this.b = b;

        this.x = l;
        this.y = t;
        this.w = r - l;
        this.h = b - t;
    }

    CGraphicBounds.prototype.fromOther = function(oBounds){
        this.l = oBounds.l;
        this.t = oBounds.t;
        this.r = oBounds.r;
        this.b = oBounds.b;

        this.x = oBounds.x;
        this.y = oBounds.y;
        this.w = oBounds.w;
        this.h = oBounds.h;
    };
    CGraphicBounds.prototype.copy = function(){
        return new CGraphicBounds(this.l, this.t, this.r, this.b);
    };
    CGraphicBounds.prototype.transform = function(oTransform){

        var xlt = oTransform.TransformPointX(this.l, this.t);
        var ylt = oTransform.TransformPointY(this.l, this.t);

        var xrt = oTransform.TransformPointX(this.r, this.t);
        var yrt = oTransform.TransformPointY(this.r, this.t);
        var xlb = oTransform.TransformPointX(this.l, this.b);
        var ylb = oTransform.TransformPointY(this.l, this.b);

        var xrb = oTransform.TransformPointX(this.r, this.b);
        var yrb = oTransform.TransformPointY(this.r, this.b);

        this.l = Math.min(xlb, xlt, xrb, xrt);
        this.t = Math.min(ylb, ylt, yrb, yrt);

        this.r = Math.max(xlb, xlt, xrb, xrt);
        this.b = Math.max(ylb, ylt, yrb, yrt);

        this.x = this.l;
        this.y = this.t;
        this.w = this.r - this.l;
        this.h = this.b - this.t;
    };

    CGraphicBounds.prototype.checkByOther = function(oBounds){
        if(oBounds){
            if(oBounds.l < this.l){
                this.l = oBounds.l;
            }
            if(oBounds.t < this.t){
                this.t = oBounds.t;
            }
            if(oBounds.r > this.r){
                this.r = oBounds.r;
            }
            if(oBounds.b > this.b){
                this.b = oBounds.b;
            }
        }
    };
    CGraphicBounds.prototype.checkWH = function(){

        this.x = this.l;
        this.y = this.t;
        this.w = this.r - this.l;
        this.h = this.b - this.t;
    };
    CGraphicBounds.prototype.reset = function(l, t, r, b){

        this.l = l;
        this.t = t;
        this.r = r;
        this.b = b;

        this.x = l;
        this.y = t;
        this.w = r - l;
        this.h = b - t;
    };

    /**
     * Base class for all graphic objects
     * @constructor
     */
    function CGraphicObjectBase() {
        /*Format fields*/
        this.spPr  = null;
        this.group = null;
        this.parent = null;
        this.bDeleted = true;
        this.locks = 0;
        this.Id = '';

        /*Calculated fields*/
        this.posX = null;
        this.posY = null;
        this.x    = 0;
        this.y    = 0;
        this.extX = 0;
        this.extY = 0;
        this.rot  = 0;
        this.flipH = false;
        this.flipV = false;
        this.bounds = new CGraphicBounds(0, 0, 0, 0);
        this.localTransform = new AscCommon.CMatrix();
        this.transform = new AscCommon.CMatrix();
        this.invertTransform = null;
        this.pen = null;
        this.brush = null;
        this.snapArrayX = [];
        this.snapArrayY = [];

        this.selected = false;

        this.Lock = new AscCommon.CLock();
        this.setRecalculateInfo();
    }

    /**
     * Create a scheme color
     * @memberof CGraphicObjectBase
     * @returns {CGraphicBounds}
     */
    CGraphicObjectBase.prototype.checkBoundsRect = function(){
        var aCheckX = [], aCheckY = [];
        this.calculateSnapArrays(aCheckX, aCheckY, this.localTransform);
        return new CGraphicBounds(Math.min.apply(Math, aCheckX), Math.min.apply(Math, aCheckY), Math.max.apply(Math, aCheckX), Math.max.apply(Math, aCheckY));
    };

    
    /**
     * Set default recalculate info
     * @memberof CGraphicObjectBase
     */
    CGraphicObjectBase.prototype.setRecalculateInfo = function(){};
    
    /**
     * Get object Id
     * @memberof CGraphicObjectBase
     * @returns {string}
     */
    CGraphicObjectBase.prototype.Get_Id = function () {
        return this.Id;
    };

    /**
     * Get type object
     * @memberof CGraphicObjectBase
     * @returns {number}
     */
    CGraphicObjectBase.prototype.getObjectType = function () {
        return AscDFH.historyitem_type_Unknown;
    };

    /**
     * Write object to stream
     * @memberof CGraphicObjectBase
     */
    CGraphicObjectBase.prototype.Write_ToBinary2 = function (oWriter) {
        oWriter.WriteLong(this.getObjectType());
        oWriter.WriteString2(this.Get_Id());
    };

    /**
     * Read object from stream
     * @memberof CGraphicObjectBase
     */
    CGraphicObjectBase.prototype.Read_FromBinary2 = function (oReader) {
        this.Id = oReader.GetString2();
    };


    /**
     * Get object Id
     * @memberof CGraphicObjectBase
     * @returns {string}
     */
    CGraphicObjectBase.prototype.Get_Id = function () {
        return this.Id;
    };

    /**
     * Get object bounds for defining group size
     * @memberof CGraphicObjectBase
     * @returns {CGraphicBounds}
     */
    CGraphicObjectBase.prototype.getBoundsInGroup = function () {
        var r = this.rot;
        if (!AscFormat.isRealNumber(r) || AscFormat.checkNormalRotate(r)) {
            return new CGraphicBounds(this.x, this.y, this.x + this.extX, this.y + this.extY);
        }
        else {
            var hc = this.extX * 0.5;
            var vc = this.extY * 0.5;
            var xc = this.x + hc;
            var yc = this.y + vc;
            return new CGraphicBounds(xc - vc, yc - hc, xc + vc, yc + hc);
        }
    };

    /**
     * Normalize a size object in group
     * @memberof CGraphicObjectBase
     */
    CGraphicObjectBase.prototype.normalize = function () {
        var new_off_x, new_off_y, new_ext_x, new_ext_y;
        var xfrm = this.spPr.xfrm;
        if (!isRealObject(this.group)) {
            new_off_x = xfrm.offX;
            new_off_y = xfrm.offY;
            new_ext_x = xfrm.extX;
            new_ext_y = xfrm.extY;
        }
        else {
            var scale_scale_coefficients = this.group.getResultScaleCoefficients();
            new_off_x = scale_scale_coefficients.cx * (xfrm.offX - this.group.spPr.xfrm.chOffX);
            new_off_y = scale_scale_coefficients.cy * (xfrm.offY - this.group.spPr.xfrm.chOffY);
            new_ext_x = scale_scale_coefficients.cx * xfrm.extX;
            new_ext_y = scale_scale_coefficients.cy * xfrm.extY;
        }
        Math.abs(new_off_x - xfrm.offX) > AscFormat.MOVE_DELTA &&  xfrm.setOffX(new_off_x);
        Math.abs(new_off_y - xfrm.offY) > AscFormat.MOVE_DELTA &&  xfrm.setOffY(new_off_y);
        Math.abs(new_ext_x - xfrm.extX) > AscFormat.MOVE_DELTA &&  xfrm.setExtX(new_ext_x);
        Math.abs(new_ext_y - xfrm.extY) > AscFormat.MOVE_DELTA &&  xfrm.setExtY(new_ext_y);
    };

    /**
     * Check point hit to bounds object
     * @memberof CGraphicObjectBase
     */
    CGraphicObjectBase.prototype.checkHitToBounds = function(x, y) {
        if(this.parent && (this.parent.Get_ParentTextTransform  && this.parent.Get_ParentTextTransform())) {
            return true;
        }
        var _x, _y;
        if(AscFormat.isRealNumber(this.posX) && AscFormat.isRealNumber(this.posY)){
            _x = x - this.posX - this.bounds.x;
            _y = y - this.posY - this.bounds.y;
        }
        else{
            _x = x - this.bounds.x;
            _y = y - this.bounds.y;
        }
        var delta = 3 + (this.pen && AscFormat.isRealNumber(this.pen.w) ? this.pen.w/36000 : 0);
        return _x >= -delta && _x <= this.bounds.w + delta && _y >= -delta && _y <= this.bounds.h + delta;
    };

    /**
     * Internal method for calculating snap arrays
     * @param {Array} snapArrayX
     * @param {Array} snapArrayY
     * @param {CMatrix} transform
     * @memberof CGraphicObjectBase
     */
    CGraphicObjectBase.prototype.calculateSnapArrays = function(snapArrayX, snapArrayY, transform)
    {
        var t = transform ? transform : this.transform;
        snapArrayX.push(t.TransformPointX(0, 0));
        snapArrayY.push(t.TransformPointY(0, 0));
        snapArrayX.push(t.TransformPointX(this.extX, 0));
        snapArrayY.push(t.TransformPointY(this.extX, 0));

        snapArrayX.push(t.TransformPointX(this.extX*0.5, this.extY*0.5));
        snapArrayY.push(t.TransformPointY(this.extX*0.5, this.extY*0.5));
        snapArrayX.push(t.TransformPointX(this.extX, this.extY));
        snapArrayY.push(t.TransformPointY(this.extX, this.extY));
        snapArrayX.push(t.TransformPointX(0, this.extY));
        snapArrayY.push(t.TransformPointY(0, this.extY));
    };

    /**
     * Public method for calculating snap arrays
     * @memberof CGraphicObjectBase
     */
    CGraphicObjectBase.prototype.recalculateSnapArrays = function()
    {
        this.snapArrayX.length = 0;
        this.snapArrayY.length = 0;
        this.calculateSnapArrays(this.snapArrayX, this.snapArrayY, null);
    };

    CGraphicObjectBase.prototype.setLocks = function(nLocks){
        AscCommon.History.Add( new AscDFH.CChangesDrawingsLong(this, AscDFH.historyitem_AutoShapes_SetLocks, this.locks, nLocks));
        this.locks = nLocks;
    };

    CGraphicObjectBase.prototype.getLockValue = function(nMask) {
        return  !!((this.locks & nMask) && (this.locks & (nMask << 1)));
    };

    CGraphicObjectBase.prototype.setLockValue = function(nMask, bValue) {
        if(!AscFormat.isRealBool(bValue)) {
            this.setLocks((~nMask) & this.locks);
        }
        else{
            this.setLocks(this.locks | nMask | (bValue ? nMask << 1 : 0));
        }
    };

    CGraphicObjectBase.prototype.getNoGrp = function(){
        return this.getLockValue(LOCKS_MASKS.noGrp);
    };
    CGraphicObjectBase.prototype.getNoUngrp = function(){
        return this.getLockValue(LOCKS_MASKS.noUngrp);
    };
    CGraphicObjectBase.prototype.getNoSelect = function(){
        return this.getLockValue(LOCKS_MASKS.noSelect);
    };
    CGraphicObjectBase.prototype.getNoRot = function(){
        return this.getLockValue(LOCKS_MASKS.noRot);
    };
    CGraphicObjectBase.prototype.getNoChangeAspect = function(){
        return this.getLockValue(LOCKS_MASKS.noChangeAspect);
    };
    CGraphicObjectBase.prototype.getNoMove = function(){
        return this.getLockValue(LOCKS_MASKS.noMove);
    };
    CGraphicObjectBase.prototype.getNoResize = function(){
        return this.getLockValue(LOCKS_MASKS.noResize);
    };
    CGraphicObjectBase.prototype.getNoEditPoints = function(){
        return this.getLockValue(LOCKS_MASKS.noEditPoints);
    };
    CGraphicObjectBase.prototype.getNoAdjustHandles = function(){
        return this.getLockValue(LOCKS_MASKS.noAdjustHandles);
    };
    CGraphicObjectBase.prototype.getNoChangeArrowheads = function(){
        return this.getLockValue(LOCKS_MASKS.noChangeArrowheads);
    };
    CGraphicObjectBase.prototype.getNoChangeShapeType = function(){
        return this.getLockValue(LOCKS_MASKS.noChangeShapeType);
    };
    CGraphicObjectBase.prototype.getNoDrilldown = function(){
        return this.getLockValue(LOCKS_MASKS.noDrilldown);
    };
    CGraphicObjectBase.prototype.getNoTextEdit = function(){
        return this.getLockValue(LOCKS_MASKS.noTextEdit);
    };
    CGraphicObjectBase.prototype.getNoCrop = function(){
        return this.getLockValue(LOCKS_MASKS.noCrop);
    };
    CGraphicObjectBase.prototype.setNoChangeAspect = function(bValue){
        return this.setLockValue(LOCKS_MASKS.noChangeAspect, bValue);
    };
    CGraphicObjectBase.prototype.Reassign_ImageUrls = function(mapUrl){
        if(this.blipFill){
            if(mapUrl[this.blipFill.RasterImageId]){
                if(this.setBlipFill){
                    var blip_fill = new AscFormat.CBlipFill();
                    blip_fill.setRasterImageId(mapUrl[this.blipFill.RasterImageId]);
                    blip_fill.setStretch(true);
                    this.setBlipFill(blip_fill);
                }
            }
        }
        if(this.spPr && this.spPr.Fill && this.spPr.Fill.fill && this.spPr.Fill.fill.RasterImageId){
            if(mapUrl[this.spPr.Fill.fill.RasterImageId]){
                var blip_fill = new AscFormat.CBlipFill();
                blip_fill.setRasterImageId(mapUrl[this.spPr.Fill.fill.RasterImageId]);
                blip_fill.setStretch(true);
                var oUniFill = new AscFormat.CUniFill();
                oUniFill.setFill(blip_fill);
                this.spPr.setFill(oUniFill);
            }
        }
        if(Array.isArray(this.spTree)){
            for(var i = 0; i < this.spTree.length; ++i){
                if(this.spTree[i].Reassign_ImageUrls){
                    this.spTree[i].Reassign_ImageUrls(mapUrl);
                }
            }
        }
    };

    CGraphicObjectBase.prototype.getAllFonts = function(mapUrl){
    };


    CGraphicObjectBase.prototype.getAllRasterImages = function(mapUrl){
    };

    CGraphicObjectBase.prototype.checkCorrect = function(){
        if(this.bDeleted === true){
            return false;
        }
        return this.checkTypeCorrect();
    };



    CGraphicObjectBase.prototype.Clear_ContentChanges = function()
    {
    };

    CGraphicObjectBase.prototype.Add_ContentChanges = function(Changes)
    {
    };

    CGraphicObjectBase.prototype.Refresh_ContentChanges = function()
    {
    };


    CGraphicObjectBase.prototype.CheckCorrect = function(){
        return this.checkCorrect();
    };

    CGraphicObjectBase.prototype.checkTypeCorrect = function(){
        return true;
    };

    CGraphicObjectBase.prototype.setDrawingBaseType = function(nType){
        if(this.drawingBase){
            History.Add(new AscDFH.CChangesDrawingsLong(this, AscDFH.historyitem_AutoShapes_SetDrawingBaseType, this.drawingBase.Type, nType));
            this.drawingBase.Type = nType;
        }
    };
    CGraphicObjectBase.prototype.setDrawingBasePos = function(fPosX, fPosY){
        if(this.drawingBase && this.drawingBase.Pos){
            History.Add(new AscDFH.CChangesDrawingsObjectNoId(this, AscDFH.historyitem_AutoShapes_SetDrawingBasePos, new CDrawingBaseCoordsWritable(this.drawingBase.Pos.X, this.drawingBase.Pos.Y), new CDrawingBaseCoordsWritable(fPosX, fPosY)));
            this.drawingBase.Pos.X = fPosX;
            this.drawingBase.Pos.Y = fPosY;
        }
    };
    CGraphicObjectBase.prototype.setDrawingBaseExt = function(fExtX, fExtY){
        if(this.drawingBase && this.drawingBase.ext){
            History.Add(new AscDFH.CChangesDrawingsObjectNoId(this, AscDFH.historyitem_AutoShapes_SetDrawingBaseExt, new CDrawingBaseCoordsWritable(this.drawingBase.ext.cx, this.drawingBase.ext.cy), new CDrawingBaseCoordsWritable(fExtX, fExtY)));
            this.drawingBase.ext.cx = fExtX;
            this.drawingBase.ext.cy = fExtY;
        }
    };

    CGraphicObjectBase.prototype.getPlaceholderType = function()
    {
        return null;
    };

    CGraphicObjectBase.prototype.getPlaceholderIndex = function()
    {
        return null;
    };

    CGraphicObjectBase.prototype.getPhType = function()
    {
        return null;
    };

    CGraphicObjectBase.prototype.getPhIndex = function()
    {
        return null;
    };



    CGraphicObjectBase.prototype.checkDrawingBaseCoords = function()
    {
        if(this.drawingBase && this.spPr && this.spPr.xfrm && !this.group) {
            var oldX = this.x, oldY = this.y, oldExtX = this.extX, oldExtY = this.extY;
            var oldRot = this.rot;
            this.x = this.spPr.xfrm.offX;
            this.y = this.spPr.xfrm.offY;
            this.extX = this.spPr.xfrm.extX;
            this.extY = this.spPr.xfrm.extY;
            this.rot = AscFormat.isRealNumber(this.spPr.xfrm.rot) ? AscFormat.normalizeRotate(this.spPr.xfrm.rot) : 0;

            var oldFromCol = this.drawingBase.from.col,
                oldFromColOff = this.drawingBase.from.colOff,
                oldFromRow = this.drawingBase.from.row,
                oldFromRowOff = this.drawingBase.from.rowOff,
                oldToCol = this.drawingBase.to.col,
                oldToColOff = this.drawingBase.to.colOff,
                oldToRow = this.drawingBase.to.row,
                oldToRowOff = this.drawingBase.to.rowOff,
                oldPosX = this.drawingBase.Pos.X,
                oldPosY = this.drawingBase.Pos.Y,
                oldCx = this.drawingBase.ext.cx,
                oldCy = this.drawingBase.ext.cy;


            this.drawingBase.setGraphicObjectCoords();
            this.x = oldX;
            this.y = oldY;
            this.extX = oldExtX;
            this.extY = oldExtY;
            this.rot = oldRot;
            var from = this.drawingBase.from, to = this.drawingBase.to;
            History.Add(new AscDFH.CChangesDrawingsObjectNoId(this, AscDFH.historyitem_AutoShapes_SetDrawingBaseCoors,
                new CDrawingBasePosWritable({
                    fromCol: oldFromCol,
                    fromColOff: oldFromColOff,
                    fromRow: oldFromRow,
                    fromRowOff: oldFromRowOff,
                    toCol: oldToCol,
                    toColOff: oldToColOff,
                    toRow: oldToRow,
                    toRowOff: oldToRowOff,
                    posX: oldPosX,
                    posY: oldPosY,
                    cx: oldCx,
                    cy: oldCy
                }),
                new CDrawingBasePosWritable({
                    fromCol: from.col,
                    fromColOff: from.colOff,
                    fromRow: from.row,
                    fromRowOff: from.rowOff,
                    toCol: to.col,
                    toColOff: to.colOff,
                    toRow: to.row,
                    toRowOff: to.rowOff,
                    posX: this.drawingBase.Pos.X,
                    posY: this.drawingBase.Pos.Y,
                    cx: this.drawingBase.ext.cx,
                    cy: this.drawingBase.ext.cy
                })));
        }
};

    CGraphicObjectBase.prototype.setDrawingBaseCoords = function(fromCol, fromColOff, fromRow, fromRowOff, toCol, toColOff, toRow, toRowOff, posX, posY, extX, extY)
{
    if(this.drawingBase)
    {
        History.Add(new AscDFH.CChangesDrawingsObjectNoId(this, AscDFH.historyitem_AutoShapes_SetDrawingBaseCoors, new CDrawingBasePosWritable({
                fromCol   : this.drawingBase.from.col,
                fromColOff: this.drawingBase.from.colOff,
                fromRow   : this.drawingBase.from.row,
                fromRowOff: this.drawingBase.from.rowOff,
                toCol     : this.drawingBase.to.col,
                toColOff  : this.drawingBase.to.colOff,
                toRow     : this.drawingBase.to.row,
                toRowOff  : this.drawingBase.to.rowOff,
                posX      : this.drawingBase.Pos.X,
                posY      : this.drawingBase.Pos.Y,
                cx        : this.drawingBase.ext.cx,
                cy        : this.drawingBase.ext.cy
            }),
            new CDrawingBasePosWritable({
                fromCol:    fromCol,
                fromColOff: fromColOff,
                fromRow   : fromRow,
                fromRowOff: fromRowOff,
                toCol:    toCol,
                toColOff: toColOff,
                toRow   : toRow,
                toRowOff: toRowOff,
                posX    : posX,
                posY    : posY,
                cx      : extX,
                cy      : extY
            })));


            this.drawingBase.from.col    = fromCol;
            this.drawingBase.from.colOff = fromColOff;
            this.drawingBase.from.row    = fromRow;
            this.drawingBase.from.rowOff = fromRowOff;

            this.drawingBase.to.col    = toCol;
            this.drawingBase.to.colOff = toColOff;
            this.drawingBase.to.row    = toRow;
            this.drawingBase.to.rowOff = toRowOff;

            this.drawingBase.Pos.X  = posX;
            this.drawingBase.Pos.Y  = posY;
            this.drawingBase.ext.cx = extX;
            this.drawingBase.ext.cy = extY;
}
};


    CGraphicObjectBase.prototype.setWorksheet = function(worksheet)
    {
        AscCommon.History.Add(new AscDFH.CChangesDrawingsString(this, AscDFH.historyitem_AutoShapes_SetWorksheet, this.worksheet ? this.worksheet.getId() : null, worksheet ? worksheet.getId() : null));
        this.worksheet = worksheet;
        if(Array.isArray(this.spTree)){
            for(var i = 0; i < this.spTree.length; ++i)
            {
                this.spTree[i].setWorksheet(worksheet);
            }
        }
    };

    CGraphicObjectBase.prototype.getUniNvProps = function(){
        return this.nvSpPr || this.nvPicPr || this.nvGrpSpPr || this.nvGraphicFramePr || null;
    };

    CGraphicObjectBase.prototype.getNvProps = function(){
        var oUniNvPr = this.getUniNvProps();
        if(oUniNvPr){
            return oUniNvPr.cNvPr;
        }
        return null;
    };


    CGraphicObjectBase.prototype.setTitle = function(sTitle){
        if(undefined === sTitle || null === sTitle){
            return;
        }
        var oNvPr = this.getNvProps();
        if(oNvPr){
            oNvPr.setTitle(sTitle ? sTitle : null);
        }
    };

    CGraphicObjectBase.prototype.setDescription = function(sDescription){
        if(undefined === sDescription || null === sDescription){
            return;
        }
        var oNvPr = this.getNvProps();
        if(oNvPr){
            oNvPr.setDescr(sDescription ? sDescription : null);
        }
    };

    CGraphicObjectBase.prototype.getTitle = function(){
        var oNvPr = this.getNvProps();
        if(oNvPr){
            return oNvPr.title ? oNvPr.title : undefined;
        }
        return undefined;
    };

    CGraphicObjectBase.prototype.getDescription = function(){
        var oNvPr = this.getNvProps();
        if(oNvPr){
            return oNvPr.descr ? oNvPr.descr : undefined;
        }
        return undefined;
    };

    CGraphicObjectBase.prototype.setBDeleted = function(pr)
    {
        History.Add(new AscDFH.CChangesDrawingsBool(this, AscDFH.historyitem_ShapeSetBDeleted, this.bDeleted, pr));
        this.bDeleted = pr;
    };


    CGraphicObjectBase.prototype.getEditorType = function()
    {
        return 1;
    };
    CGraphicObjectBase.prototype.isEmptyPlaceholder = function()
    {
        return false;
    };

    CGraphicObjectBase.prototype.Restart_CheckSpelling = function()
    {
    };

    CGraphicObjectBase.prototype.convertToConnectionParams = function(rot, flipH, flipV, oTransform, oBounds, oConnectorInfo){
        var _ret =  new AscFormat.ConnectionParams();
        var _rot = oConnectorInfo.ang*AscFormat.cToRad + rot;
        var _normalized_rot = AscFormat.normalizeRotate(_rot);
        _ret.dir = AscFormat.CARD_DIRECTION_E;
        if(_normalized_rot >= 0 && _normalized_rot < Math.PI * 0.25 || _normalized_rot >= 7 * Math.PI * 0.25 && _normalized_rot < 2 * Math.PI){
            _ret.dir = AscFormat.CARD_DIRECTION_E;
            if(flipH){
                _ret.dir = AscFormat.CARD_DIRECTION_W;
            }
        }
        else if(_normalized_rot >= Math.PI * 0.25 && _normalized_rot < 3 * Math.PI * 0.25){
            _ret.dir = AscFormat.CARD_DIRECTION_S;
            if(flipV){
                _ret.dir = AscFormat.CARD_DIRECTION_N;
            }
        }
        else if(_normalized_rot >= 3 * Math.PI * 0.25 && _normalized_rot < 5 * Math.PI * 0.25){
            _ret.dir = AscFormat.CARD_DIRECTION_W;
            if(flipH){
                _ret.dir = AscFormat.CARD_DIRECTION_E;
            }
        }
        else if(_normalized_rot >= 5 * Math.PI * 0.25 && _normalized_rot < 7 * Math.PI * 0.25){
            _ret.dir = AscFormat.CARD_DIRECTION_N;
            if(flipV){
                _ret.dir = AscFormat.CARD_DIRECTION_S;
            }
        }
        _ret.x = oTransform.TransformPointX(oConnectorInfo.x, oConnectorInfo.y);
        _ret.y = oTransform.TransformPointY(oConnectorInfo.x, oConnectorInfo.y);
        _ret.bounds.fromOther(oBounds);
        _ret.idx = oConnectorInfo.idx;
        return _ret;
    };



    CGraphicObjectBase.prototype.getRectGeometry = function(){
        return AscFormat.ExecuteNoHistory(
            function(){
                var _ret = AscFormat.CreateGeometry("rect");
                _ret.Recalculate(this.extX, this.extY);
                return _ret;
            }, this, []
        );
    };

    CGraphicObjectBase.prototype.getGeom = function () {

        var _geom;
        if(this.rectGeometry){
            _geom = this.rectGeometry;
        }
        else if(this.calcGeometry){
            _geom = this.calcGeometry;
        }
        else if(this.spPr && this.spPr.geometry){
            _geom = this.spPr.geometry;
        }
        else{
            _geom = this.getRectGeometry();
        }
        return _geom;
    };

    CGraphicObjectBase.prototype.findGeomConnector = function(x, y){
        var _geom = this.getGeom();
        var oInvertTransform = this.invertTransform;
        var _x = oInvertTransform.TransformPointX(x, y);
        var _y = oInvertTransform.TransformPointY(x, y);
        return _geom.findConnector(_x, _y, this.convertPixToMM(AscCommon.global_mouseEvent.KoefPixToMM * AscCommon.TRACK_CIRCLE_RADIUS));

    };

    CGraphicObjectBase.prototype.findConnector = function(x, y){
        var oConnGeom = this.findGeomConnector(x, y);
        if(oConnGeom){
            var _rot = this.rot;
            var _flipH = this.flipH;
            var _flipV = this.flipV;
            if(this.group){
                _rot = AscFormat.normalizeRotate(this.group.getFullRotate() + _rot);
                if(this.group.getFullFlipH()){
                    _flipH = !_flipH;
                }
                if(this.group.getFullFlipV()){
                    _flipV = !_flipV;
                }
            }
            return this.convertToConnectionParams(_rot, _flipH, _flipV, this.transform, this.bounds, oConnGeom);
        }
        return null;
    };

    CGraphicObjectBase.prototype.findConnectionShape = function(x, y){
        if(this.hit(x, y)){
            return this;
        }
        return null;
    };
    CGraphicObjectBase.prototype.getAllDocContents = function(aDrawings){

    };


    CGraphicObjectBase.prototype.getFullRotate = function () {
        return !isRealObject(this.group) ? this.rot : this.rot + this.group.getFullRotate();
    };

    CGraphicObjectBase.prototype.getAspect = function (num) {
        var _tmp_x = this.extX !== 0 ? this.extX : 0.1;
        var _tmp_y = this.extY !== 0 ? this.extY : 0.1;
        return num === 0 || num === 4 ? _tmp_x / _tmp_y : _tmp_y / _tmp_x;
    };

    CGraphicObjectBase.prototype.getFullFlipH = function () {
        if (!isRealObject(this.group))
            return this.flipH;
        return this.group.getFullFlipH() ? !this.flipH : this.flipH;
    };

    CGraphicObjectBase.prototype.getFullFlipV = function () {
        if (!isRealObject(this.group))
            return this.flipV;
        return this.group.getFullFlipV() ? !this.flipV : this.flipV;
    };

    CGraphicObjectBase.prototype.getMainGroup = function () {
        if(!isRealObject(this.group)){
            if(this.getObjectType() === AscDFH.historyitem_type_GroupShape){
                return this;
            }
            return null;
        }
        return this.group.getMainGroup();
    };


    CGraphicObjectBase.prototype.drawConnectors = function(overlay)
    {
        var _geom = this.getGeom();
        _geom.drawConnectors(overlay, this.transform);
    };
    CGraphicObjectBase.prototype.getConnectionParams = function(cnxIdx, _group)
    {
        if(this.recalculateTransform){
            this.recalculateTransform();
        }
        if(cnxIdx !== null){
            var oConnectionObject = this.getGeom().cnxLst[cnxIdx];
            if(oConnectionObject){
                var g_conn_info =  {idx: cnxIdx, ang: oConnectionObject.ang, x: oConnectionObject.x, y: oConnectionObject.y};
                var _rot = AscFormat.normalizeRotate(this.getFullRotate());
                var _flipH =  this.getFullFlipH();
                var _flipV =  this.getFullFlipV();
                var _bounds = this.bounds;
                var _transform = this.transform;

                if(_group){
                    _rot = AscFormat.normalizeRotate((this.group ? this.group.getFullRotate() : 0) + _rot - _group.getFullRotate());
                    if(_group.getFullFlipH()){
                        _flipH = !_flipH;
                    }
                    if(_group.getFullFlipV()){
                        _flipV = !_flipV;
                    }
                    _bounds = _bounds.copy();
                    _bounds.transform(_group.invertTransform);
                    _transform = _transform.CreateDublicate();
                    AscCommon.global_MatrixTransformer.MultiplyAppend(_transform, _group.invertTransform);
                }
                return this.convertToConnectionParams(_rot, _flipH, _flipV, _transform, _bounds, g_conn_info);
            }
        }
        return null;
    };

    CGraphicObjectBase.prototype.getCardDirectionByNum = function (num) {
        var num_north = this.getNumByCardDirection(AscFormat.CARD_DIRECTION_N);
        var full_flip_h = this.getFullFlipH();
        var full_flip_v = this.getFullFlipV();
        var same_flip = !full_flip_h && !full_flip_v || full_flip_h && full_flip_v;
        if (same_flip)
            return ((num - num_north) + AscFormat.CARD_DIRECTION_N + 8) % 8;

        return (AscFormat.CARD_DIRECTION_N - (num - num_north) + 8) % 8;
    };

    CGraphicObjectBase.prototype.getTransformMatrix = function(){
        return this.transform;
    };

    CGraphicObjectBase.prototype.getNumByCardDirection = function (cardDirection) {
        var hc = this.extX * 0.5;
        var vc = this.extY * 0.5;
        var transform = this.getTransformMatrix();
        var y1, y3, y5, y7;
        y1 = transform.TransformPointY(hc, 0);
        y3 = transform.TransformPointY(this.extX, vc);
        y5 = transform.TransformPointY(hc, this.extY);
        y7 = transform.TransformPointY(0, vc);

        var north_number;
        var full_flip_h = this.getFullFlipH();
        var full_flip_v = this.getFullFlipV();
        switch (Math.min(y1, y3, y5, y7)) {
            case y1:
            {
                north_number = 1;
                break;
            }
            case y3:
            {
                north_number = 3;
                break;
            }
            case y5:
            {
                north_number = 5;
                break;
            }
            default:
            {
                north_number = 7;
                break;
            }
        }
        var same_flip = !full_flip_h && !full_flip_v || full_flip_h && full_flip_v;

        if (same_flip)
            return (north_number + cardDirection) % 8;
        return (north_number - cardDirection + 8) % 8;
    };

    CGraphicObjectBase.prototype.getInvertTransform = function(){
        return this.invertTransform;
    };

    CGraphicObjectBase.prototype.getResizeCoefficients = function (numHandle, x, y) {
        var cx, cy;
        cx = this.extX > 0 ? this.extX : 0.01;
        cy = this.extY > 0 ? this.extY : 0.01;

        var invert_transform = this.getInvertTransform();
        var t_x = invert_transform.TransformPointX(x, y);
        var t_y = invert_transform.TransformPointY(x, y);

        switch (numHandle) {
            case 0:
                return { kd1: (cx - t_x) / cx, kd2: (cy - t_y) / cy };
            case 1:
                return { kd1: (cy - t_y) / cy, kd2: 0 };
            case 2:
                return { kd1: (cy - t_y) / cy, kd2: t_x / cx };
            case 3:
                return { kd1: t_x / cx, kd2: 0 };
            case 4:
                return { kd1: t_x / cx, kd2: t_y / cy };
            case 5:
                return { kd1: t_y / cy, kd2: 0 };
            case 6:
                return { kd1: t_y / cy, kd2: (cx - t_x) / cx };
            case 7:
                return { kd1: (cx - t_x) / cx, kd2: 0 };
        }
        return { kd1: 1, kd2: 1 };
    };


    CGraphicObjectBase.prototype.GetAllContentControls = function(arrContentControls)
    {
    };

    CGraphicObjectBase.prototype.CheckContentControlEditingLock = function () {
        if(this.group){
            this.group.CheckContentControlEditingLock();
            return;
        }
        if(this.parent && this.parent.CheckContentControlEditingLock){
            this.parent.CheckContentControlEditingLock();
        }
    };

    CGraphicObjectBase.prototype.drawLocks = function(transform, graphics){
        var bNotes = !!(this.parent && this.parent.kind === AscFormat.TYPE_KIND.NOTES);
        if(!this.group && !bNotes)
        {
            var oLock;
            if(this.parent instanceof ParaDrawing)
            {
                oLock = this.parent.Lock;
            }
            else if(this.Lock)
            {
                oLock = this.Lock;
            }
            if(oLock && AscCommon.locktype_None !== oLock.Get_Type())
            {
                var bCoMarksDraw = true;
                var oApi = editor || Asc['editor'];
                if(oApi){

                    switch(oApi.getEditorId()){
                        case AscCommon.c_oEditorId.Word:{
                            bCoMarksDraw = (true === oApi.isCoMarksDraw || AscCommon.locktype_Mine !== oLock.Get_Type());
                            break;
                        }
                        case AscCommon.c_oEditorId.Presentation:{
                            bCoMarksDraw = (!AscCommon.CollaborativeEditing.Is_Fast() || AscCommon.locktype_Mine !== oLock.Get_Type());
                            break;
                        }
                        case AscCommon.c_oEditorId.Spreadsheet:{
                            bCoMarksDraw = (!oApi.collaborativeEditing.getFast() || AscCommon.locktype_Mine !== oLock.Get_Type());
                            break;
                        }
                    }
                }
                if(bCoMarksDraw){
                    graphics.transform3(transform);
                    graphics.DrawLockObjectRect(oLock.Get_Type(), 0, 0, this.extX, this.extY);
                    return true;
                }
            }
        }
        return false;
    };
    CGraphicObjectBase.prototype.getSignatureLineGuid = function(){
        return null;
    };

    CGraphicObjectBase.prototype.getCopyWithSourceFormatting = function(oIdMap){
        return this.copy(oIdMap);
    };

    CGraphicObjectBase.prototype.checkNeedRecalculate = function(){
        return false;
    };

    CGraphicObjectBase.prototype.canChangeArrows = function () {
        if (!this.spPr || this.spPr.geometry == null) {
            return false;
        }
        var _path_list = this.spPr.geometry.pathLst;
        var _path_index;
        var _path_command_index;
        var _path_command_arr;
        for (_path_index = 0; _path_index < _path_list.length; ++_path_index) {
            _path_command_arr = _path_list[_path_index].ArrPathCommandInfo;
            for (_path_command_index = 0; _path_command_index < _path_command_arr.length; ++_path_command_index) {
                if (_path_command_arr[_path_command_index].id == 5) {
                    break;
                }
            }
            if (_path_command_index == _path_command_arr.length) {
                return true;
            }
        }
        return false;
    };

    CGraphicObjectBase.prototype.getStroke = function () {
        if(this.pen && this.pen.Fill)
        {
            if(this.getObjectType() === AscDFH.historyitem_type_ImageShape && AscFormat.isRealNumber(this.pen.w))
            {
                var _ret = this.pen.createDuplicate();
                _ret.w/=2.0;
                return _ret;
            }
            return this.pen;
        }
        var ret = AscFormat.CreateNoFillLine();
        ret.w = 0;
        return ret;
    };


    CGraphicObjectBase.prototype.getPresetGeom = function () {
        if (this.spPr && this.spPr.geometry) {
            return this.spPr.geometry.preset;
        }
        else {
            if(this.calcGeometry)
            {
                return this.calcGeometry.preset;
            }
            return null;
        }
    };


    CGraphicObjectBase.prototype.getFill = function () {
        if(this.brush && this.brush.fill)
        {
            return this.brush;
        }
        return AscFormat.CreateNoFillUniFill();
    };



    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].CGraphicObjectBase = CGraphicObjectBase;
    window['AscFormat'].CGraphicBounds     = CGraphicBounds;
    window['AscFormat'].checkNormalRotate  = checkNormalRotate;
    window['AscFormat'].normalizeRotate    = normalizeRotate;
    window['AscFormat'].LOCKS_MASKS        = LOCKS_MASKS;
})(window);
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {

// Import
var g_memory = AscFonts.g_memory;
var DecodeBase64Char = AscFonts.DecodeBase64Char;
var b64_decode = AscFonts.b64_decode;
    
var c_oAscSizeRelFromH = AscCommon.c_oAscSizeRelFromH;
var c_oAscSizeRelFromV = AscCommon.c_oAscSizeRelFromV;
var CMatrix = AscCommon.CMatrix;
var isRealObject = AscCommon.isRealObject;
var global_mouseEvent = AscCommon.global_mouseEvent;
    var History = AscCommon.History;
    var global_MatrixTransformer = AscCommon.global_MatrixTransformer;

var checkNormalRotate = AscFormat.checkNormalRotate;
var HitInLine = AscFormat.HitInLine;
var MOVE_DELTA = AscFormat.MOVE_DELTA;

var c_oAscFill = Asc.c_oAscFill;


function CheckObjectLine(obj)
{
    return (obj instanceof CShape && obj.spPr && obj.spPr.geometry && AscFormat.CheckLinePreset(obj.spPr.geometry.preset));
}


function CheckWordArtTextPr(oRun)
{
    var oTextPr = oRun.Get_CompiledPr();
    if(oTextPr.TextFill || (oTextPr.TextOutline && oTextPr.TextOutline.Fill && oTextPr.TextOutline.Fill.fill && oTextPr.TextOutline.Fill.fill.type !==  Asc.c_oAscFill.FILL_TYPE_NOFILL) || (oTextPr.Unifill && oTextPr.Unifill.fill && (oTextPr.Unifill.fill.type !== c_oAscFill.FILL_TYPE_SOLID || oTextPr.Unifill.transparent != null && oTextPr.Unifill.transparent < 254.5)))
        return true;
    return false;
}

function hitToHandles(x, y, object)
{
    var invert_transform = object.getInvertTransform();
    var t_x, t_y;
    t_x = invert_transform.TransformPointX(x, y);
    t_y = invert_transform.TransformPointY(x, y);
    var radius = object.convertPixToMM(AscCommon.TRACK_CIRCLE_RADIUS);

    if(typeof global_mouseEvent !== "undefined" && isRealObject(global_mouseEvent) && AscFormat.isRealNumber(global_mouseEvent.KoefPixToMM))
    {
        radius *= global_mouseEvent.KoefPixToMM;
    }

    if (global_mouseEvent && global_mouseEvent.AscHitToHandlesEpsilon)
    {
        radius = global_mouseEvent.AscHitToHandlesEpsilon;
    }

    // чтобы не считать корни
    radius *= radius;

    // считаем ближайший маркер, так как окрестность может быть большой, и пересекаться.

    var _min_dist = 2 * radius; // главное что больше
    var _ret_value = -1;

    var check_line = CheckObjectLine(object);

    var sqr_x = t_x * t_x, sqr_y = t_y * t_y;
    var _tmp_dist = sqr_x + sqr_y;
    if (_tmp_dist < _min_dist)
    {
        _min_dist = _tmp_dist;
        _ret_value = 0;
    }

    var hc = object.extX * 0.5;
    var dist_x = t_x - hc;
    sqr_x = dist_x * dist_x;
    _tmp_dist = sqr_x + sqr_y;
    if (_tmp_dist < _min_dist && !check_line)
    {
        _min_dist = _tmp_dist;
        _ret_value = 1;
    }

    dist_x = t_x - object.extX;
    sqr_x = dist_x * dist_x;
    _tmp_dist = sqr_x + sqr_y;
    if (_tmp_dist < _min_dist && !check_line)
    {
        _min_dist = _tmp_dist;
        _ret_value = 2;
    }

    var vc = object.extY * 0.5;
    var dist_y = t_y - vc;
    sqr_y = dist_y * dist_y;
    _tmp_dist = sqr_x + sqr_y;
    if (_tmp_dist < _min_dist && !check_line)
    {
        _min_dist = _tmp_dist;
        _ret_value = 3;
    }

    dist_y = t_y - object.extY;
    sqr_y = dist_y * dist_y;
    _tmp_dist = sqr_x + sqr_y;
    if (_tmp_dist < _min_dist)
    {
        _min_dist = _tmp_dist;
        _ret_value = 4;
    }

    dist_x = t_x - hc;
    sqr_x = dist_x * dist_x;
    _tmp_dist = sqr_x + sqr_y;
    if (_tmp_dist < _min_dist && !check_line)
    {
        _min_dist = _tmp_dist;
        _ret_value = 5;
    }

    dist_x = t_x;
    sqr_x = dist_x * dist_x;
    _tmp_dist = sqr_x + sqr_y;
    if (_tmp_dist < _min_dist && !check_line)
    {
        _min_dist = _tmp_dist;
        _ret_value = 6;
    }

    dist_y = t_y - vc;
    sqr_y = dist_y * dist_y;
    _tmp_dist = sqr_x + sqr_y;
    if (_tmp_dist < _min_dist && !check_line)
    {
        _min_dist = _tmp_dist;
        _ret_value = 7;
    }

    if(object.canRotate && object.canRotate() && !check_line)
    {
        var rotate_distance = object.convertPixToMM(AscCommon.TRACK_DISTANCE_ROTATE);
        dist_y = t_y + rotate_distance;
        sqr_y = dist_y * dist_y;
        dist_x = t_x - hc;
        sqr_x = dist_x * dist_x;

        _tmp_dist = sqr_x + sqr_y;
        if (_tmp_dist < _min_dist)
        {
            _min_dist = _tmp_dist;
            _ret_value = 8;
        }
    }

    // теперь смотрим расстояние до центра фигуры, чтобы можно было двигать маленькую
    dist_x = t_x - hc;
    dist_y = t_y - vc;
    _tmp_dist =  dist_x * dist_x + dist_y * dist_y;
    if (_tmp_dist < _min_dist && !check_line)
    {
        _min_dist = _tmp_dist;
        _ret_value = -1;
    }

    if (_min_dist < radius)
        return _ret_value;

    return -1;
}

function CreateUniFillByUniColorCopy(uniColor)
{
    var ret = new AscFormat.CUniFill();
    ret.setFill(new AscFormat.CSolidFill());
    ret.fill.setColor(uniColor.createDuplicate());
    return ret;
}

function CreateUniFillByUniColor(uniColor)
{
    var ret = new AscFormat.CUniFill();
    ret.setFill(new AscFormat.CSolidFill());
    ret.fill.setColor(uniColor.createDuplicate());
    return ret;
}

function CopyRunToPPTX(Run, Paragraph, bHyper)
{
    var NewRun = new ParaRun(Paragraph, false);
    var RunPr = Run.Pr.Copy();
    if(RunPr.RStyle != undefined)
    {
        RunPr.RStyle = undefined;
    }

    if(bHyper)
    {
        if(!RunPr.Unifill)
        {
            RunPr.Unifill = AscFormat.CreateUniFillSchemeColorWidthTint(11, 0);
        }
        RunPr.Underline = true;
    }
    if(RunPr.TextFill)
    {
        RunPr.Unifill = RunPr.TextFill;
        RunPr.TextFill = undefined;
    }

    NewRun.Set_Pr( RunPr );

    var PosToAdd = 0;
    for ( var CurPos = 0; CurPos < Run.Content.length; CurPos++ )
    {
        var Item = Run.Content[CurPos];
        if ( para_End !== Item.Type && Item.Type !== para_Drawing && Item.Type !== para_Comment &&
            Item.Type !== para_PageCount && Item.Type !== para_FootnoteRef && Item.Type !== para_FootnoteReference && Item.Type !== para_PageNum)
        {
            NewRun.Add_ToContent( PosToAdd, Item.Copy(), false );
            ++PosToAdd;
        }
    }
    return NewRun;
}

function ConvertParagraphToPPTX(paragraph, drawingDocument, newParent, bIsAddMath, bRemoveHyperlink)
{
    var _drawing_document = isRealObject(drawingDocument) ? drawingDocument : paragraph.DrawingDocument;
    var _new_parent = isRealObject(newParent) ? newParent : paragraph.Parent;

    var new_paragraph = new Paragraph(_drawing_document, _new_parent, true);
    if(!(paragraph instanceof Paragraph))
        return new_paragraph;
    var oCopyPr = paragraph.Pr.Copy();

    oCopyPr.ContextualSpacing = undefined;
    oCopyPr.KeepLines       = undefined;
    oCopyPr.KeepNext        = undefined;
    oCopyPr.PageBreakBefore = undefined;
    oCopyPr.Shd = undefined;
    oCopyPr.Brd.First = undefined;
    oCopyPr.Brd.Last  = undefined;
    oCopyPr.Brd.Between = undefined;
    oCopyPr.Brd.Bottom = undefined;
    oCopyPr.Brd.Left = undefined;
    oCopyPr.Brd.Right = undefined;
    oCopyPr.Brd.Top = undefined;
    oCopyPr.WidowControl = undefined;
    oCopyPr.Tabs = undefined;
    oCopyPr.NumPr = undefined;
    oCopyPr.PStyle = undefined;
    oCopyPr.FramePr = undefined;


    new_paragraph.Set_Pr(oCopyPr);
    var oNewEndPr = paragraph.TextPr.Value.Copy();
    if(oNewEndPr.TextFill)
    {
        oNewEndPr.Unifill = oNewEndPr.TextFill;
        oNewEndPr.TextFill = undefined;
    }
    new_paragraph.TextPr.Set_Value( oNewEndPr );
    new_paragraph.Internal_Content_Remove2(0, new_paragraph.Content.length);
    var Count = paragraph.Content.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        var Item = paragraph.Content[Index];
        if(Item.Type === para_Run)
        {
            new_paragraph.Internal_Content_Add(new_paragraph.Content.length, CopyRunToPPTX(Item, new_paragraph), false);
        }
        else if(Item.Type === para_Hyperlink)
        {
            if(bRemoveHyperlink === true)
            {
                for(var j = 0; j < Item.Content.length; ++j)
                {
                    if(Item.Content[j].Type === para_Run)
                    {
                        new_paragraph.Internal_Content_Add(new_paragraph.Content.length, CopyRunToPPTX(Item.Content[j], new_paragraph), false);
                    }
                }
            }
            else
            {
                new_paragraph.Internal_Content_Add(new_paragraph.Content.length, ConvertHyperlinkToPPTX(Item, new_paragraph), false);
            }

        }
        else if(true === bIsAddMath && Item.Type === para_Math)
        {
            new_paragraph.Internal_Content_Add(new_paragraph.Content.length, Item.Copy(), false);
        }
    }
    var EndRun = new ParaRun(new_paragraph);
    EndRun.Add_ToContent( 0, new ParaEnd() );
    new_paragraph.Internal_Content_Add( new_paragraph.Content.length, EndRun, false );
    return new_paragraph;
}

function ConvertHyperlinkToPPTX(hyperlink, paragraph)
{
    var hyperlink_ret = new ParaHyperlink(), i, item, pos = 0;
    hyperlink_ret.SetValue( hyperlink.Value );
    hyperlink_ret.SetToolTip( hyperlink.ToolTip );
    for(i = 0; i < hyperlink.Content.length; ++i)
    {
        item = hyperlink.Content[i];
        if(item.Type === para_Run)
        {
            hyperlink_ret.Add_ToContent(pos++, CopyRunToPPTX(item, paragraph, true));
        }
        else if(item.Type === para_Hyperlink)
        {
            hyperlink_ret.Add_ToContent(pos++, ConvertHyperlinkToPPTX(item, paragraph));
        }
    }
    return hyperlink_ret;
}

function ConvertParagraphToWord(paragraph, docContent)
{
    var _docContent = isRealObject(docContent) ? docContent : paragraph.Parent;
    var oldFlag = paragraph.bFromDocument;
    paragraph.bFromDocument = true;
    var new_paragraph = paragraph.Copy(_docContent);
    CheckWordParagraphContent(new_paragraph.Content, new_paragraph.Pr.DefaultRunPr);
    var NewRPr = CheckWordRunPr(new_paragraph.TextPr.Value);
    var oCopyDefaultPr;
    if(NewRPr)
    {
        if(new_paragraph.Pr.DefaultRunPr)
        {
            oCopyDefaultPr  = new_paragraph.Pr.DefaultRunPr.Copy();
            oCopyDefaultPr.Merge(NewRPr);
            NewRPr = CheckWordRunPr(oCopyDefaultPr);
            if(!NewRPr)
            {
                NewRPr = oCopyDefaultPr;
            }
        }
        new_paragraph.TextPr.Apply_TextPr(NewRPr);
    }
    else
    {
        if(new_paragraph.Pr.DefaultRunPr)
        {
            oCopyDefaultPr  = new_paragraph.Pr.DefaultRunPr.Copy();
            oCopyDefaultPr.Merge(new_paragraph.TextPr.Value);
            NewRPr = CheckWordRunPr(oCopyDefaultPr);
            if(!NewRPr)
            {
                NewRPr = oCopyDefaultPr;
            }
            new_paragraph.TextPr.Apply_TextPr(NewRPr);
        }
    }
    paragraph.bFromDocument = oldFlag;
    return new_paragraph;
}

function CheckWordRunPr(Pr, bMath)
{
    var NewRPr = null;
    if(Pr.Unifill && Pr.Unifill.fill )
    {
        switch(Pr.Unifill.fill.type)
        {
            case c_oAscFill.FILL_TYPE_SOLID:
            {
                if(Pr.Unifill.fill.color && Pr.Unifill.fill.color.color)
                {
                    switch(Pr.Unifill.fill.color.color.type)
                    {
                        case Asc.c_oAscColor.COLOR_TYPE_SCHEME:
                        {
                            if(Pr.Unifill.fill.color.Mods && Pr.Unifill.fill.color.Mods.Mods.length !== 0)
                            {
                                if(!Pr.Unifill.fill.color.canConvertPPTXModsToWord())
                                {
                                    NewRPr = Pr.Copy();
                                    NewRPr.TextFill = NewRPr.Unifill;
                                    NewRPr.Unifill = undefined;
                                }
                                else
                                {
                                    NewRPr = Pr.Copy();
                                    NewRPr.Unifill.convertToWordMods();
                                }
                            }
                            break;
                        }
                        case Asc.c_oAscColor.COLOR_TYPE_SRGB:
                        {

                            NewRPr = Pr.Copy();
                            var RGBA = Pr.Unifill.fill.color.color.RGBA;
                            NewRPr.Color = new CDocumentColor(RGBA.R, RGBA.G, RGBA.B);
                            NewRPr.Unifill = undefined;
                            break;
                        }
                        default:
                        {
                            NewRPr = Pr.Copy();
                            NewRPr.TextFill = NewRPr.Unifill;
                            NewRPr.Unifill = undefined;
                        }
                    }
                }
                break;
            }
            case c_oAscFill.FILL_TYPE_PATT:
            case c_oAscFill.FILL_TYPE_BLIP:
            {
                NewRPr = Pr.Copy();
                NewRPr.TextFill = AscFormat.CreateUnfilFromRGB(0, 0, 0);
                NewRPr.Unifill = undefined;
                break;
            }
            default :
            {
                NewRPr = Pr.Copy();
                NewRPr.TextFill = NewRPr.Unifill;
                NewRPr.Unifill = undefined;
                break;
            }
        }
    }

    if(bMath){
        NewRPr = Pr.Copy();
        NewRPr.RFonts.Set_All("Cambria Math", -1);
    }
    return NewRPr;
}

function CheckWordParagraphContent(aContent, oTextPr)
{
    var NewRPr, MergePr;
    for(var i = 0; i < aContent.length; ++i)
    {
        var oItem = aContent[i];
        switch(oItem.Type)
        {
            case para_Run:
            {
                NewRPr = CheckWordRunPr(oItem.Pr);
                if(NewRPr)
                {
                    MergePr = NewRPr;
                    if(oTextPr)
                    {
                        MergePr = oTextPr.Copy();
                        MergePr.Merge(NewRPr);
                        NewRPr = CheckWordRunPr(MergePr);
                        if(!NewRPr)
                        {
                            NewRPr = MergePr;
                        }
                    }
                    oItem.Set_Pr(NewRPr);
                }
                else
                {
                    if(oTextPr)
                    {
                        MergePr = oTextPr.Copy();
                        MergePr.Merge(oItem.Pr);
                        NewRPr = CheckWordRunPr(MergePr);
                        if(!NewRPr)
                        {
                            NewRPr = MergePr;
                        }
                        oItem.Set_Pr(NewRPr);
                    }
                }
                break;
            }
            case para_Hyperlink:
            {
                CheckWordParagraphContent(oItem.Content);
                break;
            }
            case para_Math:
            {
                if(oItem.Root && oItem.Root.Content)
                {
                    CheckWordParagraphContent(oItem.Root.Content);
                }
                break;
            }
            case para_Math_Run:
            {
                NewRPr = CheckWordRunPr(oItem.Pr, true);
                if(NewRPr)
                {
                    MergePr = NewRPr;
                    if(oTextPr)
                    {
                        MergePr = oTextPr.Copy();
                        MergePr.Merge(NewRPr);
                        NewRPr = CheckWordRunPr(MergePr);
                        if(!NewRPr)
                        {
                            NewRPr = MergePr;
                        }
                    }
                    oItem.Set_Pr(NewRPr);
                }
                else
                {
                    if(oTextPr)
                    {
                        MergePr = oTextPr.Copy();
                        MergePr.Merge(oItem.Pr);
                        NewRPr = CheckWordRunPr(MergePr);
                        if(!NewRPr)
                        {
                            NewRPr = MergePr;
                        }
                        oItem.Set_Pr(NewRPr);
                    }
                }
                break;
            }
        }

    }
}

function ConvertGraphicFrameToWordTable(oGraphicFrame, oDocument){
    oGraphicFrame.setWordFlag(false, oDocument);
    return oGraphicFrame.graphicObject.Copy(oDocument);
}
function ConvertTableToGraphicFrame(oTable, oPresentation){
    var oGraphicFrame = new AscFormat.CGraphicFrame();
    var oTable2 = new CTable(oPresentation.DrawingDocument, oGraphicFrame, true, 0, [].concat(oTable.TableGrid), oTable.TableGrid.length, true);
    oTable2.Reset(0, 0, 50, 100000, 0, 0, 1);
    oTable2.SetTableLayout(tbllayout_Fixed);
    oTable2.Set_Pr(oTable.Pr.Copy());
    oTable2.Set_TableLook(oTable.TableLook.Copy());
    for(var i = 0; i < oTable.Content.length; ++i){
        var oRow = oTable.Content[i];
        var oNewRow = new CTableRow(oTable2, oRow.Content.length, oTable2.TableGrid);
        for(var j = 0;  j < oRow.Content.length; ++j){
            var oContent = oRow.Content[j].Content;
            var oNewContent = oNewRow.Content[j].Content;
            for(var t = 0; t < oContent.Content.length; ++t){
                if(oContent.Content[t].Get_Type() === type_Paragraph){
                    oNewContent.Internal_Content_Add(oNewContent.Content.length, AscFormat.ConvertParagraphToPPTX(oContent.Content[t], oPresentation.DrawingDocument, oNewContent));
                }
            }
        }
        var nIndex = oTable2.Content.length;
        oTable2.Content[nIndex] = oNewRow;
        History.Add(new CChangesTableAddRow(oTable2, nIndex, [oNewRow]));
    }

    if(!oGraphicFrame.spPr){
        oGraphicFrame.setSpPr(new AscFormat.CSpPr());
        oGraphicFrame.spPr.setParent(oGraphicFrame);
    }
    oGraphicFrame.spPr.setXfrm(new  AscFormat.CXfrm());
    oGraphicFrame.spPr.xfrm.setExtX(50);
    oGraphicFrame.spPr.xfrm.setExtY(50);
    oGraphicFrame.spPr.xfrm.setParent(oGraphicFrame.spPr);
    var _nvGraphicFramePr =  new AscFormat.UniNvPr();
    oGraphicFrame.setNvSpPr(_nvGraphicFramePr);
    if(AscCommon.isRealObject(_nvGraphicFramePr) && AscFormat.isRealNumber(_nvGraphicFramePr.locks)){
        oGraphicFrame.setLocks(_nvGraphicFramePr.locks);
    }
    oGraphicFrame.setGraphicObject(oTable2);
    oGraphicFrame.setBDeleted(false);
    return oGraphicFrame;
}


function fHandleContent(aContent, oMax){
    for(var i = 0;  i < aContent.length; ++i)
    {
        var oContentElement = aContent[i];
        if(oContentElement.Get_Type() === type_Paragraph)
        {
            var paragraph_lines = aContent[i].Lines;
            for(var j = 0;  j < paragraph_lines.length; ++j)
            {
                if(paragraph_lines[j].Ranges[0].W > oMax.max_width)
                    oMax.max_width = paragraph_lines[j].Ranges[0].X + paragraph_lines[j].Ranges[0].W;
            }
        }
        else if(oContentElement.Get_Type() === type_Table)
        {

        }
        else if(oContentElement.Get_Type() === type_BlockLevelSdt)
        {
            if(oContentElement && oContentElement.Content){
                fHandleContent(oContentElement.Content.Content, oMax);
            }
        }
    }
}

function RecalculateDocContentByMaxLine(oDocContent, dMaxWidth, bNeedRecalcAllDrawings)
{
    var oMaxWidth = {max_width: 0}, i;
    oDocContent.Reset(0, 0, dMaxWidth, 20000);
    if(bNeedRecalcAllDrawings)
    {
        var aAllDrawings = oDocContent.GetAllDrawingObjects();
        for(i = 0; i < aAllDrawings.length; ++i)
        {
            aAllDrawings[i].GraphicObj.recalculate();
        }
    }
    oDocContent.Recalculate_Page(0, true);
    fHandleContent(oDocContent.Content, oMaxWidth);
    if(oMaxWidth.max_width === 0)
    {
        if(oDocContent.Is_Empty())
        {
            if(oDocContent.Content[0] && oDocContent.Content[0].Content[0] && oDocContent.Content[0].Content[0].Content[0])
            {
                return oDocContent.Content[0].Content[0].Content[0].WidthVisible/TEXTWIDTH_DIVIDER;
            }
        }
        return 0.001;
    }
    return oMaxWidth.max_width;
}


function CheckExcelDrawingXfrm(xfrm)
{
    var rot = AscFormat.isRealNumber(xfrm.rot) ? xfrm.rot : 0;

    if (checkNormalRotate(rot))
    {
        if(xfrm.offX < 0)
        {
            xfrm.setOffX(0);
        }
        if(xfrm.offY < 0)
        {
            xfrm.setOffY(0);
        }
    }
    else
    {
        var dPosX = xfrm.offX + xfrm.extX/2 - xfrm.extY/2;
        var dPosY = xfrm.offY + xfrm.extY/2 - xfrm.extX/2;
        if(dPosX < 0)
        {
            xfrm.setOffX(xfrm.offX - dPosX);
        }
        if(dPosY < 0)
        {
            xfrm.setOffY(xfrm.offY - dPosY);
        }
    }
}


function SetXfrmFromMetrics(oDrawing, metrics)
{
    AscFormat.CheckSpPrXfrm(oDrawing);
    var rot = AscFormat.isRealNumber(oDrawing.spPr.xfrm.rot) ? AscFormat.normalizeRotate(oDrawing.spPr.xfrm.rot) : 0;

    var metricExtX, metricExtY;
    if(!(oDrawing instanceof AscFormat.CGroupShape))
    {
        metricExtX = metrics.extX;
        metricExtY = metrics.extY;
        if (checkNormalRotate(rot))
        {
            oDrawing.spPr.xfrm.setExtX(metrics.extX);
            oDrawing.spPr.xfrm.setExtY(metrics.extY);
        }
        else
        {
            oDrawing.spPr.xfrm.setExtX(metrics.extY);
            oDrawing.spPr.xfrm.setExtY(metrics.extX);
        }
    }
    else
    {
        if(AscFormat.isRealNumber(oDrawing.spPr.xfrm.extX) && AscFormat.isRealNumber(oDrawing.spPr.xfrm.extY))
        {
            metricExtX = oDrawing.spPr.xfrm.extX;
            metricExtY = oDrawing.spPr.xfrm.extY;
        }
        else
        {
            metricExtX = metrics.extX;
            metricExtY = metrics.extY;
        }
    }

    if (checkNormalRotate(rot))
    {
        oDrawing.spPr.xfrm.setOffX(metrics.x);
        oDrawing.spPr.xfrm.setOffY(metrics.y);
    }
    else
    {
        oDrawing.spPr.xfrm.setOffX(metrics.x + metricExtX/2 - metricExtY/2);
        oDrawing.spPr.xfrm.setOffY(metrics.y + metricExtY/2 - metricExtX/2);
    }
}


           AscDFH.changesFactory[AscDFH.historyitem_ShapeSetNvSpPr]   = AscDFH.CChangesDrawingsObject;
           AscDFH.changesFactory[AscDFH.historyitem_ShapeSetSpPr]   = AscDFH.CChangesDrawingsObject;
           AscDFH.changesFactory[AscDFH.historyitem_ShapeSetStyle]   = AscDFH.CChangesDrawingsObject;
           AscDFH.changesFactory[AscDFH.historyitem_ShapeSetTxBody]   = AscDFH.CChangesDrawingsObject;
           AscDFH.changesFactory[AscDFH.historyitem_ShapeSetTextBoxContent]   = AscDFH.CChangesDrawingsObject;
           AscDFH.changesFactory[AscDFH.historyitem_ShapeSetBodyPr]   = AscDFH.CChangesDrawingsObjectNoId;
           AscDFH.changesFactory[AscDFH.historyitem_AutoShapes_SetBFromSerialize]   = AscDFH.CChangesDrawingsBool;
           AscDFH.changesFactory[AscDFH.historyitem_ShapeSetParent]   = AscDFH.CChangesDrawingsObject;
           AscDFH.changesFactory[AscDFH.historyitem_ShapeSetGroup]   = AscDFH.CChangesDrawingsObject;
           AscDFH.changesFactory[AscDFH.historyitem_ShapeSetWordShape]   = AscDFH.CChangesDrawingsBool;
           AscDFH.changesFactory[AscDFH.historyitem_ShapeSetSignature]   = AscDFH.CChangesDrawingsObjectNoId;



    AscDFH.drawingsChangesMap[AscDFH.historyitem_ShapeSetNvSpPr]               = function(oClass, value){oClass.nvSpPr = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_ShapeSetSpPr]                 = function(oClass, value){oClass.spPr = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_ShapeSetStyle]                = function(oClass, value){oClass.style = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_ShapeSetTxBody]               = function(oClass, value){oClass.txBody = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_ShapeSetTextBoxContent]       = function(oClass, value){oClass.textBoxContent = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_ShapeSetBodyPr]               = function(oClass, value){oClass.bodyPr = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_AutoShapes_SetBFromSerialize] = function(oClass, value){oClass.fromSerialize = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_ShapeSetParent]               = function(oClass, value){oClass.parent = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_ShapeSetGroup]                = function(oClass, value){oClass.group = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_ShapeSetWordShape]            = function(oClass, value){oClass.bWordShape = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_ShapeSetSignature]            = function(oClass, value){oClass.signatureLine = value;};


    function CSignatureLine(){
        this.id = null;
        this.signer = null;
        this.signer2 = null;
        this.email = null;
    }

    CSignatureLine.prototype.Write_ToBinary = function(writer){
        AscFormat.writeString(writer, this.id);
        AscFormat.writeString(writer, this.signer);
        AscFormat.writeString(writer, this.signer2);
        AscFormat.writeString(writer, this.email);
    };
    CSignatureLine.prototype.Read_FromBinary = function(reader){
        this.id =  AscFormat.readString(reader);
        this.signer = AscFormat.readString(reader);
        this.signer2 =  AscFormat.readString(reader);
        this.email =  AscFormat.readString(reader);
    };
    CSignatureLine.prototype.copy = function(){
        var ret = new CSignatureLine();
        ret.id =  this.id;
        ret.signer = this.signer;
        ret.signer2 = this.signer2;
        ret.email = this.email;
        return ret;
    };

    AscDFH.drawingsConstructorsMap[AscDFH.historyitem_ShapeSetBodyPr] = AscFormat.CBodyPr;
    AscDFH.drawingsConstructorsMap[AscDFH.historyitem_ShapeSetSignature] = CSignatureLine;




function CShape()
{
	AscFormat.CGraphicObjectBase.call(this);
    this.nvSpPr         = null;
    this.style          = null;
    this.txBody         = null;
    this.bodyPr			= null;
    this.textBoxContent = null;
    this.drawingBase    = null;//DrawingBase в Excell'е
    this.bWordShape     = null;//если этот флаг стоит в true то автофигура имеет формат как в редакторе документов
    this.bCheckAutoFitFlag = false;
    this.signatureLine = null;


    this.transformText = new CMatrix();
    this.invertTransformText = null;

    this.localTransformText = new CMatrix();
    this.worksheet = null;
    this.cachedImage = null;

    this.txWarpStruct = null;
    this.txWarpStructParamarks = null;

    this.txWarpStructNoTransform = null;
    this.txWarpStructParamarksNoTransform = null;

    this.Id = AscCommon.g_oIdCounter.Get_NewId();
    AscCommon.g_oTableId.Add( this, this.Id );
}

	CShape.prototype = Object.create(AscFormat.CGraphicObjectBase.prototype);
	CShape.prototype.constructor = CShape;

CShape.prototype.getObjectType = function () {
    return AscDFH.historyitem_type_Shape;
};

CShape.prototype.GetAllDrawingObjects = function(DrawingObjects)
{
    var oContent = this.getDocContent();
    if(oContent)
    {
        oContent.GetAllDrawingObjects(DrawingObjects);
    }
};
CShape.prototype.setSignature = function(oSignature)
{
    History.Add(new AscDFH.CChangesDrawingsObjectNoId(this, AscDFH.historyitem_ShapeSetSignature, this.signatureLine, oSignature));
    this.signatureLine = oSignature;
};

CShape.prototype.convertToWord = function (document) {
    this.setBDeleted(true);
    var c = new CShape();
    c.setWordShape(true);
    c.setBDeleted(false);
    if (this.nvSpPr) {
        c.setNvSpPr(this.nvSpPr.createDuplicate());
    }
    if (this.spPr) {
        c.setSpPr(this.spPr.createDuplicate());
        if(!c.spPr.geometry){
            c.spPr.setGeometry(AscFormat.CreateGeometry("rect"));
        }
        c.spPr.setParent(c);
    }
    if (this.style) {
        c.setStyle(this.style.createDuplicate());
    }
    if (this.txBody) {
        if (this.txBody.bodyPr) {
            c.setBodyPr(this.txBody.bodyPr.createDuplicate());
        }
        if (this.txBody.content) {
            var new_content = new CDocumentContent(c, document.DrawingDocument, 0, 0, 0, 20000, false, false, false);
            var paragraphs = this.txBody.content.Content;

            new_content.Internal_Content_RemoveAll();
            for (var i = 0; i < paragraphs.length; ++i) {
                var cur_par = paragraphs[i];
                var new_paragraph = ConvertParagraphToWord(cur_par, new_content);
                new_content.Internal_Content_Add(i, new_paragraph, false);
                /*var bullet = cur_par.Pr.Bullet;
                 if(bullet && bullet.bulletType && bullet.bulletType.type !== AscFormat.BULLET_TYPE_BULLET_NONE)
                 {
                 switch(bullet.bulletType.type)
                 {
                 case AscFormat.BULLET_TYPE_BULLET_CHAR:
                 case AscFormat.BULLET_TYPE_BULLET_BLIP :
                 {
                 _bullet.m_nType = numbering_presentationnumfrmt_Char;
                 _bullet.m_sChar = _final_bullet.bulletType.Char[0];
                 _cur_paragraph.Add_PresentationNumbering(_bullet, true);
                 break;
                 }
                 case AscFormat.BULLET_TYPE_BULLET_AUTONUM :
                 {
                 _bullet.m_nType = g_NumberingArr[_final_bullet.bulletType.AutoNumType];
                 _bullet.m_nStartAt = _final_bullet.bulletType.startAt;
                 _cur_paragraph.Add_PresentationNumbering(_bullet, true);
                 break;
                 }
                 }
                 } */
            }
            c.setTextBoxContent(new_content);
        }
    }
    return c;
};

CShape.prototype.convertToPPTX = function (drawingDocument, worksheet, bIsAddMath) {
    var c = new CShape();
    c.setWordShape(false);
    c.setBDeleted(false);
    c.setWorksheet(worksheet);
    if (this.nvSpPr) {
        c.setNvSpPr(this.nvSpPr.createDuplicate());
    }
    if (this.spPr) {
        c.setSpPr(this.spPr.createDuplicate());
        c.spPr.setParent(c);
    }
    if (this.style) {
        c.setStyle(this.style.createDuplicate());
    }
    if (this.textBoxContent) {
        var tx_body = new AscFormat.CTextBody();
        tx_body.setParent(c);
        if (this.bodyPr) {
            tx_body.setBodyPr(this.bodyPr.createDuplicate());
        }
        var new_content = new AscFormat.CDrawingDocContent(tx_body, drawingDocument, 0, 0, 0, 0, false, false, true);
        new_content.Internal_Content_RemoveAll();
        var paragraphs = this.textBoxContent.Content;

        var index = 0;
        for (var i = 0; i < paragraphs.length; ++i) {
            var cur_par = paragraphs[i];
            if (cur_par instanceof Paragraph) {
                var new_paragraph = ConvertParagraphToPPTX(cur_par, drawingDocument, new_content, bIsAddMath);
                new_content.Internal_Content_Add(index++, new_paragraph, false);
            }
        }
        tx_body.setContent(new_content);
        c.setTxBody(tx_body);
    }
    return c;
};

CShape.prototype.documentGetAllFontNames = function (AllFonts) {
    //TODO
    var content = this.getDocContent();
    if (content) {
        content.Document_Get_AllFontNames(AllFonts);
    }
};

CShape.prototype.documentCreateFontMap = function (map) {
    var content = this.getDocContent();
    if (content) {
        content.Document_CreateFontMap(map);
    }
};


CShape.prototype.setNvSpPr = function (pr) {
    History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_ShapeSetNvSpPr, this.nvSpPr, pr));
    this.nvSpPr = pr;
};

CShape.prototype.setSpPr = function (spPr) {
    History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_ShapeSetSpPr, this.spPr, spPr));
    this.spPr = spPr;
};

CShape.prototype.setStyle = function (style) {
    History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_ShapeSetStyle, this.style, style));
    this.style = style;
    var content = this.getDocContent();

    this.recalcInfo.recalculateShapeStyleForParagraph = true;
    if (this.recalcTextStyles)
        this.recalcTextStyles();
    if (content) {
        content.Recalc_AllParagraphs_CompiledPr();
    }
};

CShape.prototype.setTxBody = function (txBody) {
    History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_ShapeSetTxBody, this.txBody, txBody));
    this.txBody = txBody;
};

CShape.prototype.setTextBoxContent = function (textBoxContent) {
    History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_ShapeSetTextBoxContent, this.textBoxContent, textBoxContent));
    this.textBoxContent = textBoxContent;
};

CShape.prototype.setBodyPr = function (pr) {
    History.Add(new AscDFH.CChangesDrawingsObjectNoId(this, AscDFH.historyitem_ShapeSetBodyPr, this.bodyPr, pr));
    this.bodyPr = pr;
    this.recalcInfo.recalcContent = true;
    this.recalcInfo.recalcTransformText = true;
    this.addToRecalculate();
};

CShape.prototype.createTextBody = function () {
    var tx_body = new AscFormat.CTextBody();
    tx_body.setParent(this);
    tx_body.setContent(new AscFormat.CDrawingDocContent(tx_body, this.getDrawingDocument(), 0, 0, 0, 20000, false, false, true));
    var oBodyPr = new AscFormat.CBodyPr();
    if(this.worksheet){
        oBodyPr.vertOverflow = AscFormat.nOTClip;
        oBodyPr.horzOverflow = AscFormat.nOTClip;
    }
    tx_body.setBodyPr(oBodyPr);
    tx_body.content.Content[0].Set_DocumentIndex(0);
    this.setTxBody(tx_body);
};

CShape.prototype.createTextBoxContent = function () {
    var body_pr = new AscFormat.CBodyPr();
    body_pr.setAnchor(1);
    this.setBodyPr(body_pr);
    this.setTextBoxContent(new CDocumentContent(this, this.getDrawingDocument(), 0, 0, 0, 20000, false, false));
    this.textBoxContent.SetParagraphAlign(AscCommon.align_Center);
    this.textBoxContent.Content[0].Set_DocumentIndex(0);
};

CShape.prototype.paragraphAdd = function (paraItem, bRecalculate) {
    var content_to_add = this.getDocContent();
    if (!content_to_add) {
        if (this.bWordShape) {
            this.createTextBoxContent();
        }
        else {
            this.createTextBody();
        }
        content_to_add = this.getDocContent();
    }
    if (content_to_add) {
        content_to_add.AddToParagraph(paraItem, bRecalculate);
    }
};

CShape.prototype.applyTextFunction = function (docContentFunction, tableFunction, args)
{
    var content_to_add = this.getDocContent();
    if (!content_to_add)
    {
        if (this.bWordShape)
        {
            this.createTextBoxContent();
        }
        else
        {
            this.createTextBody();
        }
        content_to_add = this.getDocContent();
        content_to_add.MoveCursorToStartPos();
    }
    if (content_to_add)
    {
        docContentFunction.apply(content_to_add, args);
    }
    if(!editor || !editor.noCreatePoint || editor.exucuteHistory)
    {
        this.checkExtentsByDocContent();
    }
};

CShape.prototype.clearContent = function () {
    var content = this.getDocContent();
    if (content) {
        content.Set_ApplyToAll(true);
        content.Remove(-1);
        content.AddToParagraph(new AscCommonWord.ParaTextPr({Lang : {Val : undefined}}), false);
        content.Set_ApplyToAll(false);
    }
};


CShape.prototype.setBFromSerialize = function(bVal)
{
    History.Add(new AscDFH.CChangesDrawingsBool(this, AscDFH.historyitem_AutoShapes_SetBFromSerialize, this.fromSerialize, bVal));
    this.fromSerialize = bVal;
};

CShape.prototype.deleteBFromSerialize = function()
{
    if(this.fromSerialize)
    {
        this.setBFromSerialize(false);
        if(this.drawingBase)
        {
            var drawingObject = this.drawingBase;
            var metrics = drawingObject.getGraphicObjectMetrics();
            SetXfrmFromMetrics(this, metrics);
        }
    }
};

CShape.prototype.getDocContent = function () {
    if (this.txBody) {
        return this.txBody.content;
    }
    else if (this.textBoxContent) {
        return this.textBoxContent;
    }
    return null;
};

CShape.prototype.getBodyPr = function () {
    return AscFormat.ExecuteNoHistory(function () {

        if (this.bWordShape) {
            var ret = new AscFormat.CBodyPr();
            ret.setDefault();
            if (this.bodyPr)
                ret.merge(this.bodyPr);
            return ret;
        }
        else {
            if (this.txBody && this.txBody.bodyPr)
                return this.txBody.getCompiledBodyPr();
            var ret = new AscFormat.CBodyPr();
            ret.setDefault();
            return ret;
        }
    }, this, []);
};

CShape.prototype.GetRevisionsChangeParagraph = function(SearchEngine){
    var oContent = this.getDocContent();
    if(oContent){
        oContent.GetRevisionsChangeParagraph(SearchEngine);
    }
};

CShape.prototype.Search = function (Str, Props, SearchEngine, Type) {
    if (this.textBoxContent) {
        var dd = this.getDrawingDocument();
        dd.StartSearchTransform(this.transformText);
        this.textBoxContent.Search(Str, Props, SearchEngine, Type);
        dd.EndSearchTransform();
    }
    else if (this.txBody && this.txBody.content) {
        //var dd = this.getDrawingDocument();
        //dd.StartSearchTransform(this.transformText);
        this.txBody.content.Search(Str, Props, SearchEngine, Type);
        //dd.EndSearchTransform();
    }
};

CShape.prototype.Search_GetId = function (bNext, bCurrent) {
    if (this.textBoxContent)
        return this.textBoxContent.Search_GetId(bNext, bCurrent);

    else if (this.txBody && this.txBody.content) {
        return this.txBody.content.Search_GetId(bNext, bCurrent);
    }

    return null;
};

CShape.prototype.documentUpdateRulersState = function () {
    var content = this.getDocContent();
    if (!content)
        return;
    var xc, yc;
    var l, t, r, b;
    var body_pr = this.getBodyPr();
    var l_ins, t_ins, r_ins, b_ins;
    if (typeof body_pr.lIns === "number")
        l_ins = body_pr.lIns;
    else
        l_ins = 2.54;

    if (typeof body_pr.tIns === "number")
        t_ins = body_pr.tIns;
    else
        t_ins = 1.27;

    if (typeof body_pr.rIns === "number")
        r_ins = body_pr.rIns;
    else
        r_ins = 2.54;

    if (typeof body_pr.bIns === "number")
        b_ins = body_pr.bIns;
    else
        b_ins = 1.27;

    if (this.spPr && isRealObject(this.spPr.geometry) && isRealObject(this.spPr.geometry.rect)) {
        l = this.spPr.geometry.rect.l + l_ins;
        t = this.spPr.geometry.rect.t + t_ins;
        r = this.spPr.geometry.rect.r - r_ins;
        b = this.spPr.geometry.rect.b - b_ins;

    }
    else {
        l = l_ins;
        t = t_ins;
        r = this.extX - r_ins;
        b = this.extY - b_ins;
    }

    var x_lt, y_lt, x_rt, y_rt, x_rb, y_rb, x_lb, y_lb;
    var tr = this.transform;
    x_lt = tr.TransformPointX(l, t);
    y_lt = tr.TransformPointY(l, t);

    x_rb = tr.TransformPointX(r, b);
    y_rb = tr.TransformPointY(r, b);


    xc = (x_lt + x_rb) * 0.5;
    yc = (y_lt + y_rb) * 0.5;

    var hc = (r - l) * 0.5;
    var vc = (b - t) * 0.5;

    this.getDrawingDocument().Set_RulerState_Paragraph({L: xc - hc, T: yc - vc, R: xc + hc, B: yc + vc});
    content.Document_UpdateRulersState(AscFormat.isRealNumber(this.selectStartPage) ? this.selectStartPage : 0);
};

CShape.prototype.setParent = function (parent) {
    History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_ShapeSetParent, this.parent, parent));
    this.parent = parent;
};

CShape.prototype.setGroup = function (group) {
    History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_ShapeSetGroup, this.group, group));
    this.group = group;
};

CShape.prototype.getAllImages = function (images) {
    if (this.spPr && this.spPr.Fill && this.spPr.Fill.fill instanceof AscFormat.CBlipFill && typeof this.spPr.Fill.fill.RasterImageId === "string") {
        images[AscCommon.getFullImageSrc2(this.spPr.Fill.fill.RasterImageId)] = true;
    }
};

CShape.prototype.getAllFonts = function (fonts) {
    if (this.txBody) {
        this.txBody.content.Document_Get_AllFontNames(fonts);
        if(this.txBody && this.txBody.lstStyle){
            this.txBody.lstStyle.Document_Get_AllFontNames(fonts);
        }
        delete fonts["+mj-lt"];
        delete fonts["+mn-lt"];
        delete fonts["+mj-ea"];
        delete fonts["+mn-ea"];
        delete fonts["+mj-cs"];
        delete fonts["+mn-cs"];
    }
};

CShape.prototype.canFill = function () {
    if (this.spPr && this.spPr.geometry) {
        return this.spPr.geometry.canFill();
    }
    return true;
};

CShape.prototype.isShape = function () {
    return true;
};

CShape.prototype.isImage = function () {
    return false;
};

CShape.prototype.isChart = function () {
    return false;
};

CShape.prototype.isGroup = function () {
    return false;
};

CShape.prototype.getHierarchy = function(bIsSingleBody, info)
{
    //if(this.recalcInfo.recalculateShapeHierarchy)
    {
        this.compiledHierarchy = [];
        if(this.parent)
        {
            var hierarchy = this.compiledHierarchy;
            if(this.isPlaceholder())
            {
                var ph_type = this.getPlaceholderType();
                var ph_index = this.getPlaceholderIndex();
                var b_is_single_body;
                if(AscFormat.isRealBool(bIsSingleBody))
                {
                    b_is_single_body = bIsSingleBody;
                }
                else
                {
                    b_is_single_body = this.getIsSingleBody && this.getIsSingleBody();
                }
                switch (this.parent.kind)
                {
                    case AscFormat.TYPE_KIND.SLIDE:
                    {
                        hierarchy.push(this.parent.Layout.getMatchingShape(ph_type, ph_index, b_is_single_body, info));
                        hierarchy.push(this.parent.Layout.Master.getMatchingShape(ph_type, ph_index, true));
                        break;
                    }

                    case AscFormat.TYPE_KIND.LAYOUT:
                    {
                        hierarchy.push(this.parent.Master.getMatchingShape(ph_type, ph_index, true));
                        break;
                    }
                }
            }
            this.recalcInfo.recalculateShapeHierarchy = true;
        }
    }
    return this.compiledHierarchy;
};


CShape.prototype.getPaddings = function () {
    var paddings = null;
    var shape = this;
    var body_pr;
    if (shape.txBody) {
        body_pr = shape.txBody.bodyPr;
    }
    else if (shape.textBoxContent) {
        body_pr = shape.bodyPr;
    }
    if (body_pr) {
        paddings = new Asc.asc_CPaddings();
        if (typeof body_pr.lIns === "number")
            paddings.Left = body_pr.lIns;
        else
            paddings.Left = 2.54;

        if (typeof body_pr.tIns === "number")
            paddings.Top = body_pr.tIns;
        else
            paddings.Top = 1.27;

        if (typeof body_pr.rIns === "number")
            paddings.Right = body_pr.rIns;
        else
            paddings.Right = 2.54;

        if (typeof body_pr.bIns === "number")
            paddings.Bottom = body_pr.bIns;
        else
            paddings.Bottom = 1.27;
    }
    return paddings;
};

CShape.prototype.getCompiledFill = function () {
    if (this.recalcInfo.recalculateFill) {
        this.compiledFill = null;
        if (isRealObject(this.spPr) && isRealObject(this.spPr.Fill) && isRealObject(this.spPr.Fill.fill)) {
            if (this.spPr.Fill.fill instanceof AscFormat.CGradFill && this.spPr.Fill.fill.colors.length === 0) {
                var parent_objects = this.getParentObjects();
                var theme = parent_objects.theme;
                var fmt_scheme = theme.themeElements.fmtScheme;
                var fill_style_lst = fmt_scheme.fillStyleLst;
                for (var i = fill_style_lst.length - 1; i > -1; --i) {
                    if (fill_style_lst[i] && fill_style_lst[i].fill instanceof AscFormat.CGradFill) {
                        this.spPr.Fill = fill_style_lst[i].createDuplicate();
                        break;
                    }
                }
            }
            this.compiledFill = this.spPr.Fill.createDuplicate();
            if(this.compiledFill && this.compiledFill.fill && this.compiledFill.fill.type === c_oAscFill.FILL_TYPE_GRP)
            {
                if(this.group)
                {
                    var group_compiled_fill = this.group.getCompiledFill();
                    if (isRealObject(group_compiled_fill) && isRealObject(group_compiled_fill.fill)) {
                        this.compiledFill = group_compiled_fill.createDuplicate();
                    }
                    else
                    {
                        this.compiledFill = null;
                    }
                }
                else
                {
                    this.compiledFill = null;
                }
            }
        }
        else if (isRealObject(this.group)) {
            var group_compiled_fill = this.group.getCompiledFill();
            if (isRealObject(group_compiled_fill) && isRealObject(group_compiled_fill.fill)) {
                this.compiledFill = group_compiled_fill.createDuplicate();
            }
            else {
                var hierarchy = this.getHierarchy();
                for (var i = 0; i < hierarchy.length; ++i) {
                    if (isRealObject(hierarchy[i]) && isRealObject(hierarchy[i].spPr) && isRealObject(hierarchy[i].spPr.Fill) && isRealObject(hierarchy[i].spPr.Fill.fill)) {
                        this.compiledFill = hierarchy[i].spPr.Fill.createDuplicate();
                        break;
                    }
                }
            }
        }
        else {
            var hierarchy = this.getHierarchy();
            for (var i = 0; i < hierarchy.length; ++i) {
                if (isRealObject(hierarchy[i]) && isRealObject(hierarchy[i].spPr) && isRealObject(hierarchy[i].spPr.Fill) && isRealObject(hierarchy[i].spPr.Fill.fill)) {
                    this.compiledFill = hierarchy[i].spPr.Fill.createDuplicate();
                    break;
                }
            }
        }
        this.recalcInfo.recalculateFill = false;
    }
    return this.compiledFill;
};

CShape.prototype.getMargins = function () {
    if (this.txBody) {
        return this.txBody.getMargins()
    }
    else {
        return null;
    }
};
CShape.prototype.Document_UpdateRulersState = function (margins) {
    if (this.txBody && this.txBody.content) {
        this.txBody.content.Document_UpdateRulersState(this.parent.num, this.getMargins());
    }
};

CShape.prototype.getCompiledLine = function () {
    if (this.recalcInfo.recalculateLine) {
        this.compiledLine = null;
        if (isRealObject(this.spPr) && isRealObject(this.spPr.ln) && isRealObject(this.spPr.ln)) {
            this.compiledLine = this.spPr.ln.createDuplicate();
        }
        else if (isRealObject(this.group)) {
            var group_compiled_line = this.group.getCompiledLine();
            if (isRealObject(group_compiled_line) && isRealObject(group_compiled_line.fill)) {
                this.compiledLine = group_compiled_line.createDuplicate();
            }
            else {
                var hierarchy = this.getHierarchy();
                for (var i = 0; i < hierarchy.length; ++i) {
                    if (isRealObject(hierarchy[i]) && isRealObject(hierarchy[i].spPr) && isRealObject(hierarchy[i].spPr.ln)) {
                        this.compiledLine = hierarchy[i].spPr.ln.createDuplicate();
                        break;
                    }
                }
            }
        }
        else {
            var hierarchy = this.getHierarchy();
            for (var i = 0; i < hierarchy.length; ++i) {
                if (isRealObject(hierarchy[i]) && isRealObject(hierarchy[i].spPr) && isRealObject(hierarchy[i].spPr.ln)) {
                    this.compiledLine = hierarchy[i].spPr.ln.createDuplicate();
                    break;
                }
            }
        }
        this.recalcInfo.recalculateLine = false;
    }
    return this.compiledLine;
};

CShape.prototype.getCompiledTransparent = function () {
    if (this.recalcInfo.recalculateTransparent) {
        this.compiledTransparent = null;
        if (isRealObject(this.spPr) && isRealObject(this.spPr.Fill))
        {
            if(AscFormat.isRealNumber(this.spPr.Fill.transparent))
            {
                this.compiledTransparent = this.spPr.Fill.transparent;
            }
            else
            {
                if(this.spPr.Fill && this.spPr.Fill.fill && this.spPr.Fill.fill.type === c_oAscFill.FILL_TYPE_GRP)
                {
                    if(this.group && this.group.spPr && this.group.spPr.Fill && AscFormat.isRealNumber(this.group.spPr.Fill.transparent))
                    {
                        this.compiledTransparent = this.group.spPr.Fill.transparent;
                    }
                }
            }

        }
        if(null !== this.compiledTransparent)
        {

            this.recalcInfo.recalculateTransparent = false;
            return this.compiledTransparent;
        }
        if (isRealObject(this.group)) {
            var group_transparent = this.group.getCompiledTransparent();
            if (AscFormat.isRealNumber(group_transparent)) {
                this.compiledTransparent = group_transparent;
            }
            else {
                var hierarchy = this.getHierarchy();
                for (var i = 0; i < hierarchy.length; ++i) {
                    if (isRealObject(hierarchy[i]) && isRealObject(hierarchy[i].spPr) && isRealObject(hierarchy[i].spPr.Fill) && AscFormat.isRealNumber(hierarchy[i].spPr.Fill.transparent)) {
                        this.compiledTransparent = hierarchy[i].spPr.Fill.transparent;
                        break;
                    }

                }
            }
        }
        else {
            var hierarchy = this.getHierarchy();
            for (var i = 0; i < hierarchy.length; ++i) {
                if (isRealObject(hierarchy[i]) && isRealObject(hierarchy[i].spPr) && isRealObject(hierarchy[i].spPr.Fill) && AscFormat.isRealNumber(hierarchy[i].spPr.Fill.transparent)) {
                    this.compiledTransparent = hierarchy[i].spPr.Fill.transparent;
                    break;
                }

            }
        }
        this.recalcInfo.recalculateTransparent = false;
    }
    return this.compiledTransparent;
};

CShape.prototype.isPlaceholder = function () {
    return isRealObject(this.nvSpPr) && isRealObject(this.nvSpPr.nvPr) && isRealObject(this.nvSpPr.nvPr.ph);
};

CShape.prototype.getPlaceholderType = function () {
    return this.isPlaceholder() ? this.nvSpPr.nvPr.ph.type : null;
};

CShape.prototype.getPlaceholderIndex = function () {
    return this.isPlaceholder() ? this.nvSpPr.nvPr.ph.idx : null;
};

CShape.prototype.getPhType = function () {
    return this.isPlaceholder() ? this.nvSpPr.nvPr.ph.type : null;
};

CShape.prototype.getPhIndex = function () {
    return this.isPlaceholder() ? this.nvSpPr.nvPr.ph.idx : null;
};

CShape.prototype.setVerticalAlign = function (align) {
    var new_body_pr = this.getBodyPr();
    if (new_body_pr) {
        new_body_pr = new_body_pr.createDuplicate();
        new_body_pr.anchor = align;
        if (this.bWordShape) {
            this.setBodyPr(new_body_pr);
        }
        else {
            if (this.txBody) {
                this.txBody.setBodyPr(new_body_pr);
            }
        }
    }
};
CShape.prototype.setVert = function (vert) {
    var new_body_pr = this.getBodyPr();
    if (new_body_pr) {
        new_body_pr = new_body_pr.createDuplicate();
        new_body_pr.vert = vert;
        if (this.bWordShape) {
            this.setBodyPr(new_body_pr);
        }
        else {
            if (this.txBody) {
                this.txBody.setBodyPr(new_body_pr);
            }
        }
    }
    this.checkExtentsByDocContent && this.checkExtentsByDocContent();
};

CShape.prototype.setPaddings = function (paddings) {
    if (paddings) {

        var new_body_pr = this.getBodyPr();
        if (new_body_pr) {
            new_body_pr = new_body_pr.createDuplicate();
            if (AscFormat.isRealNumber(paddings.Left)) {
                new_body_pr.lIns = paddings.Left;
            }

            if (AscFormat.isRealNumber(paddings.Top)) {
                new_body_pr.tIns = paddings.Top;
            }

            if (AscFormat.isRealNumber(paddings.Right)) {
                new_body_pr.rIns = paddings.Right;
            }
            if (AscFormat.isRealNumber(paddings.Bottom)) {
                new_body_pr.bIns = paddings.Bottom;
            }

            if (this.bWordShape) {
                this.setBodyPr(new_body_pr);
            }
            else {
                if (this.txBody) {
                    this.txBody.setBodyPr(new_body_pr);
                }
            }
        }
    }
};

CShape.prototype.recalculateTransformText = function () {

    var oContent = this.getDocContent();
    if (!oContent)
        return;

    var oBodyPr = this.getBodyPr();
    this.clipRect = this.checkTransformTextMatrix(this.localTransformText, oContent, oBodyPr, false);
    this.transformText = this.localTransformText.CreateDublicate();
    this.invertTransformText = global_MatrixTransformer.Invert(this.transformText);

    if (this.txBody && this.txBody.content2) {
        this.transformText2 = new CMatrix();
        this.clipRect2 = this.checkTransformTextMatrix(this.transformText2, this.txBody.content2, oBodyPr, false);
        this.invertTransformText2 = global_MatrixTransformer.Invert(this.transformText2);
    }
    //if (oBodyPr.prstTxWarp) {
        var bNoTextNoShape = oBodyPr.prstTxWarp && oBodyPr.prstTxWarp.preset !== "textNoShape";
        /*if (this.bWordShape) {
            this.transformTextWordArt = this.transformText;
            this.invertTransformTextWordArt = this.invertTransformText;
        }
        else*/ {
            this.localTransformTextWordArt = new CMatrix();
            this.checkTransformTextMatrix(this.localTransformTextWordArt, oContent, oBodyPr, bNoTextNoShape, !this.bWordShape && bNoTextNoShape);
            this.transformTextWordArt = this.localTransformTextWordArt.CreateDublicate();
            this.invertTransformTextWordArt = global_MatrixTransformer.Invert(this.transformTextWordArt);
        }
        if (this.txBody && this.txBody.content2) {
            this.checkTransformTextMatrix(this.transformText2, this.txBody.content2, oBodyPr, bNoTextNoShape, !this.bWordShape && bNoTextNoShape);
            this.transformTextWordArt2 = new CMatrix();
            this.checkTransformTextMatrix(this.transformTextWordArt2, this.txBody.content2, oBodyPr, bNoTextNoShape, !this.bWordShape && bNoTextNoShape);
        }
   // }

    if (this.checkPosTransformText) {
        this.checkPosTransformText();
    }
    if (this.checkContentDrawings) {
        this.checkContentDrawings();
    }
};

CShape.prototype.getFullFlip = function () {
    var _transform = this.localTransform;
    var _full_rotate = this.getFullRotate();
    var _full_pos_x_lt = _transform.TransformPointX(0, 0);
    var _full_pos_y_lt = _transform.TransformPointY(0, 0);

    var _full_pos_x_rt = _transform.TransformPointX(this.extX, 0);
    var _full_pos_y_rt = _transform.TransformPointY(this.extX, 0);

    var _full_pos_x_rb = _transform.TransformPointX(this.extX, this.extY);
    var _full_pos_y_rb = _transform.TransformPointY(this.extX, this.extY);

    var _rotate_matrix = new CMatrix();
    global_MatrixTransformer.RotateRadAppend(_rotate_matrix, _full_rotate);

    var _rotated_pos_x_lt = _rotate_matrix.TransformPointX(_full_pos_x_lt, _full_pos_y_lt);

    var _rotated_pos_x_rt = _rotate_matrix.TransformPointX(_full_pos_x_rt, _full_pos_y_rt);
    var _rotated_pos_y_rt = _rotate_matrix.TransformPointY(_full_pos_x_rt, _full_pos_y_rt);

    var _rotated_pos_y_rb = _rotate_matrix.TransformPointY(_full_pos_x_rb, _full_pos_y_rb);
    return {
        flipH: _rotated_pos_x_lt > _rotated_pos_x_rt,
        flipV: _rotated_pos_y_rt > _rotated_pos_y_rb
    };
};

CShape.prototype.recalculateTransformText2 = function () {
    if (this.txBody === null)
        return;
    if (!this.txBody.content2)
        return;
    this.transformText2 = new CMatrix();
    var _text_transform = this.transformText2;
    var _shape_transform = this.transform;
    var _body_pr = this.txBody.getBodyPr();
    var _content_height = this.txBody.getSummaryHeight2();
    var _l, _t, _r, _b;

    var _t_x_lt, _t_y_lt, _t_x_rt, _t_y_rt, _t_x_lb, _t_y_lb, _t_x_rb, _t_y_rb;
    if (this.spPr && isRealObject(this.spPr.geometry) && isRealObject(this.spPr.geometry.rect)) {
        var _rect = this.spPr.geometry.rect;
        _l = _rect.l + _body_pr.lIns;
        _t = _rect.t + _body_pr.tIns;
        _r = _rect.r - _body_pr.rIns;
        _b = _rect.b - _body_pr.bIns;
    }
    else {
        _l = _body_pr.lIns;
        _t = _body_pr.tIns;
        _r = this.extX - _body_pr.rIns;
        _b = this.extY - _body_pr.bIns;
    }

    if (_l >= _r) {
        var _c = (_l + _r) * 0.5;
        _l = _c - 0.01;
        _r = _c + 0.01;
    }

    if (_t >= _b) {
        _c = (_t + _b) * 0.5;
        _t = _c - 0.01;
        _b = _c + 0.01;
    }

    _t_x_lt = _shape_transform.TransformPointX(_l, _t);
    _t_y_lt = _shape_transform.TransformPointY(_l, _t);

    _t_x_rt = _shape_transform.TransformPointX(_r, _t);
    _t_y_rt = _shape_transform.TransformPointY(_r, _t);

    _t_x_lb = _shape_transform.TransformPointX(_l, _b);
    _t_y_lb = _shape_transform.TransformPointY(_l, _b);

    _t_x_rb = _shape_transform.TransformPointX(_r, _b);
    _t_y_rb = _shape_transform.TransformPointY(_r, _b);

    var _dx_t, _dy_t;
    _dx_t = _t_x_rt - _t_x_lt;
    _dy_t = _t_y_rt - _t_y_lt;

    var _dx_lt_rb, _dy_lt_rb;
    _dx_lt_rb = _t_x_rb - _t_x_lt;
    _dy_lt_rb = _t_y_rb - _t_y_lt;

    var _vertical_shift;
    var _text_rect_height = _b - _t;
    var _text_rect_width = _r - _l;
    if (!_body_pr.upright) {
        if (!(_body_pr.vert === AscFormat.nVertTTvert || _body_pr.vert === AscFormat.nVertTTvert270  || _body_pr.vert === AscFormat.nVertTTeaVert)) {
            if (/*_content_height < _text_rect_height*/true) {
                switch (_body_pr.anchor) {
                    case 0: //b
                    { // (Text Anchor Enum ( Bottom ))
                        _vertical_shift = _text_rect_height - _content_height;
                        break;
                    }
                    case 1:    //ctr
                    {// (Text Anchor Enum ( Center ))
                        _vertical_shift = (_text_rect_height - _content_height) * 0.5;
                        break;
                    }
                    case 2: //dist
                    {// (Text Anchor Enum ( Distributed )) TODO: пока выравнивание  по центру. Переделать!
                        _vertical_shift = (_text_rect_height - _content_height) * 0.5;
                        break;
                    }
                    case 3: //just
                    {// (Text Anchor Enum ( Justified )) TODO: пока выравнивание  по центру. Переделать!
                        _vertical_shift = (_text_rect_height - _content_height) * 0.5;
                        break;
                    }
                    case 4: //t
                    {//Top
                        _vertical_shift = 0;
                        break;
                    }
                }

            }
            else {
                _vertical_shift = 0;

                //_vertical_shift =  _text_rect_height - _content_height;
                /*if(_body_pr.anchor === 0)
                 {
                 _vertical_shift =  _text_rect_height - _content_height;
                 }
                 else
                 {
                 _vertical_shift = 0;
                 } */
            }
            global_MatrixTransformer.TranslateAppend(_text_transform, 0, _vertical_shift);
            if (_dx_lt_rb * _dy_t - _dy_lt_rb * _dx_t <= 0) {
                var alpha = Math.atan2(_dy_t, _dx_t);
                global_MatrixTransformer.RotateRadAppend(_text_transform, -alpha);
                global_MatrixTransformer.TranslateAppend(_text_transform, _t_x_lt, _t_y_lt);
            }
            else {
                alpha = Math.atan2(_dy_t, _dx_t);
                global_MatrixTransformer.RotateRadAppend(_text_transform, Math.PI - alpha);
                global_MatrixTransformer.TranslateAppend(_text_transform, _t_x_rt, _t_y_rt);
            }
        }
        else {
            if (/*_content_height < _text_rect_width*/true) {
                switch (_body_pr.anchor) {
                    case 0: //b
                    { // (Text Anchor Enum ( Bottom ))
                        _vertical_shift = _text_rect_width - _content_height;
                        break;
                    }
                    case 1:    //ctr
                    {// (Text Anchor Enum ( Center ))
                        _vertical_shift = (_text_rect_width - _content_height) * 0.5;
                        break;
                    }
                    case 2: //dist
                    {// (Text Anchor Enum ( Distributed ))
                        _vertical_shift = (_text_rect_width - _content_height) * 0.5;
                        break;
                    }
                    case 3: //just
                    {// (Text Anchor Enum ( Justified ))
                        _vertical_shift = (_text_rect_width - _content_height) * 0.5;
                        break;
                    }
                    case 4: //t
                    {//Top
                        _vertical_shift = 0;
                        break;
                    }
                }
            }
            else {
                _vertical_shift = 0;
                /*if(_body_pr.anchor === 0)
                 {
                 _vertical_shift =  _text_rect_width - _content_height;
                 }
                 else
                 {
                 _vertical_shift = 0;
                 }  */
            }
            global_MatrixTransformer.TranslateAppend(_text_transform, 0, _vertical_shift);
            var _alpha;
            _alpha = Math.atan2(_dy_t, _dx_t);
            if (_body_pr.vert === AscFormat.nVertTTvert  || _body_pr.vert === AscFormat.nVertTTeaVert) {
                if (_dx_lt_rb * _dy_t - _dy_lt_rb * _dx_t <= 0) {
                    global_MatrixTransformer.RotateRadAppend(_text_transform, -_alpha - Math.PI * 0.5);
                    global_MatrixTransformer.TranslateAppend(_text_transform, _t_x_rt, _t_y_rt);
                }
                else {
                    global_MatrixTransformer.RotateRadAppend(_text_transform, Math.PI * 0.5 - _alpha);
                    global_MatrixTransformer.TranslateAppend(_text_transform, _t_x_lt, _t_y_lt);
                }
            }
            else {
                if (_dx_lt_rb * _dy_t - _dy_lt_rb * _dx_t <= 0) {
                    global_MatrixTransformer.RotateRadAppend(_text_transform, -_alpha - Math.PI * 1.5);
                    global_MatrixTransformer.TranslateAppend(_text_transform, _t_x_lb, _t_y_lb);
                }
                else {
                    global_MatrixTransformer.RotateRadAppend(_text_transform, -Math.PI * 0.5 - _alpha);
                    global_MatrixTransformer.TranslateAppend(_text_transform, _t_x_rb, _t_y_rb);
                }
            }
        }
        if (this.spPr && isRealObject(this.spPr.geometry) && isRealObject(this.spPr.geometry.rect)) {
            var rect = this.spPr.geometry.rect;
            this.clipRect = {x: -1, y: rect.t, w: this.extX + 2, h: rect.b - rect.t};
        }
        else {
            this.clipRect = {x: -1, y: 0, w: this.extX + 2, h: this.extY};
        }
    }
    else {
        var _full_rotate = this.getFullRotate();
        var _full_flip = this.getFullFlip();

        var _hc = this.extX * 0.5;
        var _vc = this.extY * 0.5;
        var _transformed_shape_xc = this.transform.TransformPointX(_hc, _vc);
        var _transformed_shape_yc = this.transform.TransformPointY(_hc, _vc);


        var _content_width, content_height2;
        if (checkNormalRotate(_full_rotate)) {
            if (!(_body_pr.vert === AscFormat.nVertTTvert || _body_pr.vert === AscFormat.nVertTTvert270 || _body_pr.vert === AscFormat.nVertTTeaVert)) {
                _content_width = _r - _l;
                content_height2 = _b - _t;
            }
            else {
                _content_width = _b - _t;
                content_height2 = _r - _l;
            }
        }
        else {
            if (!(_body_pr.vert === AscFormat.nVertTTvert || _body_pr.vert === AscFormat.nVertTTvert270 || _body_pr.vert === AscFormat.nVertTTeaVert)) {
                _content_width = _b - _t;
                content_height2 = _r - _l;

            }
            else {
                _content_width = _r - _l;
                content_height2 = _b - _t;
            }
        }

        if (/*_content_height < content_height2*/true) {
            switch (_body_pr.anchor) {
                case 0: //b
                { // (Text Anchor Enum ( Bottom ))
                    _vertical_shift = content_height2 - _content_height;
                    break;
                }
                case 1:    //ctr
                {// (Text Anchor Enum ( Center ))
                    _vertical_shift = (content_height2 - _content_height) * 0.5;
                    break;
                }
                case 2: //dist
                {// (Text Anchor Enum ( Distributed ))
                    _vertical_shift = (content_height2 - _content_height) * 0.5;
                    break;
                }
                case 3: //just
                {// (Text Anchor Enum ( Justified ))
                    _vertical_shift = (content_height2 - _content_height) * 0.5;
                    break;
                }
                case 4: //t
                {//Top
                    _vertical_shift = 0;
                    break;
                }
            }
        }
        else {
            _vertical_shift = 0;
            /*if(_body_pr.anchor === 0)
             {
             _vertical_shift =  content_height2 - _content_height;
             }
             else
             {
             _vertical_shift = 0;
             } */
        }

        var _text_rect_xc = _l + (_r - _l) * 0.5;
        var _text_rect_yc = _t + (_b - _t) * 0.5;

        var _vx = _text_rect_xc - _hc;
        var _vy = _text_rect_yc - _vc;

        var _transformed_text_xc, _transformed_text_yc;
        if (!_full_flip.flipH) {
            _transformed_text_xc = _transformed_shape_xc + _vx;
        }
        else {
            _transformed_text_xc = _transformed_shape_xc - _vx;
        }

        if (!_full_flip.flipV) {
            _transformed_text_yc = _transformed_shape_yc + _vy;
        }
        else {
            _transformed_text_yc = _transformed_shape_yc - _vy;
        }

        global_MatrixTransformer.TranslateAppend(_text_transform, 0, _vertical_shift);
        if (_body_pr.vert === AscFormat.nVertTTvert || _body_pr.vert === AscFormat.nVertTTeaVert) {
            global_MatrixTransformer.TranslateAppend(_text_transform, -_content_width * 0.5, -content_height2 * 0.5);
            global_MatrixTransformer.RotateRadAppend(_text_transform, -Math.PI * 0.5);
            global_MatrixTransformer.TranslateAppend(_text_transform, _content_width * 0.5, content_height2 * 0.5);

        }
        if (_body_pr.vert === AscFormat.nVertTTvert270) {
            global_MatrixTransformer.TranslateAppend(_text_transform, -_content_width * 0.5, -content_height2 * 0.5);
            global_MatrixTransformer.RotateRadAppend(_text_transform, -Math.PI * 1.5);
            global_MatrixTransformer.TranslateAppend(_text_transform, _content_width * 0.5, content_height2 * 0.5);
        }
        global_MatrixTransformer.TranslateAppend(_text_transform, _transformed_text_xc - _content_width * 0.5, _transformed_text_yc - content_height2 * 0.5);

        var body_pr = this.bodyPr;
        var l_ins = typeof body_pr.lIns === "number" ? body_pr.lIns : 2.54;
        var t_ins = typeof body_pr.tIns === "number" ? body_pr.tIns : 1.27;
        var r_ins = typeof body_pr.rIns === "number" ? body_pr.rIns : 2.54;
        var b_ins = typeof body_pr.bIns === "number" ? body_pr.bIns : 1.27;
        this.clipRect = {
            x: -1,
            y: -_vertical_shift - t_ins,
            w: Math.max(this.extX, this.extY) + 2,
            h: this.contentHeight + (b_ins + t_ins)
        };
    }
    this.invertTransformText2 = global_MatrixTransformer.Invert(this.transformText2);
};

CShape.prototype.getTextRect = function () {
    return this.spPr && this.spPr.geometry && this.spPr.geometry.rect ? this.spPr.geometry.rect : {
        l: 0,
        t: 0,
        r: this.extX,
        b: this.extY
    };
};

CShape.prototype.checkTransformTextMatrix = function (oMatrix, oContent, oBodyPr, bWordArtTransform, bIgnoreInsets) {
    oMatrix.Reset();
    var _shape_transform = this.localTransform;
    var _content_height = oContent.GetSummaryHeight();
    var _l, _t, _r, _b;
    var _t_x_lt, _t_y_lt, _t_x_rt, _t_y_rt, _t_x_lb, _t_y_lb, _t_x_rb, _t_y_rb;
    var oRect = this.getTextRect();
    var l_ins = bIgnoreInsets ? 0 : (AscFormat.isRealNumber(oBodyPr.lIns) ? oBodyPr.lIns : 2.54);
    var t_ins = bIgnoreInsets ? 0 : (AscFormat.isRealNumber(oBodyPr.tIns) ? oBodyPr.tIns : 1.27);
    var r_ins = bIgnoreInsets ? 0 : (AscFormat.isRealNumber(oBodyPr.rIns) ? oBodyPr.rIns : 2.54);
    var b_ins = bIgnoreInsets ? 0 : (AscFormat.isRealNumber(oBodyPr.bIns) ? oBodyPr.bIns : 1.27);

    if(this.bWordShape)
    {
        var oPen = this.pen;
        if(oPen)
        {
            var penW = (oPen.w == null) ? 12700 : parseInt(oPen.w);
            penW /= 36000.0;
            switch (oPen.algn)
            {
                case 1:
                {
                    break;
                }
                default:
                {
                    penW/=2.0;
                    break;
                }
            }

            l_ins += penW;
            r_ins += penW;
            t_ins += penW;
            b_ins += penW;
        }
    }

    _l = oRect.l + l_ins;
    _t = oRect.t + t_ins;
    _r = oRect.r - r_ins;
    _b = oRect.b - b_ins;

    if (_l >= _r) {
        var _c = (_l + _r) * 0.5;
        _l = _c - 0.01;
        _r = _c + 0.01;
    }

    if (_t >= _b) {
        _c = (_t + _b) * 0.5;
        _t = _c - 0.01;
        _b = _c + 0.01;
    }

    var XC = oContent.XLimit/2.0;
    var YC = _content_height/2.0;

    var _rot_angle = AscFormat.normalizeRotate((AscFormat.isRealNumber(oBodyPr.rot) ? oBodyPr.rot : 0)*AscFormat.cToRad);

    if(!AscFormat.fApproxEqual(_rot_angle, 0.0))
    {
        global_MatrixTransformer.TranslateAppend(oMatrix, -XC, -YC);
        global_MatrixTransformer.RotateRadAppend(oMatrix, -_rot_angle);
        global_MatrixTransformer.TranslateAppend(oMatrix, XC, YC);
    }
    _t_x_lt = _shape_transform.TransformPointX(_l, _t);
    _t_y_lt = _shape_transform.TransformPointY(_l, _t);

    _t_x_rt = _shape_transform.TransformPointX(_r, _t);
    _t_y_rt = _shape_transform.TransformPointY(_r, _t);

    _t_x_lb = _shape_transform.TransformPointX(_l, _b);
    _t_y_lb = _shape_transform.TransformPointY(_l, _b);

    _t_x_rb = _shape_transform.TransformPointX(_r, _b);
    _t_y_rb = _shape_transform.TransformPointY(_r, _b);

    var _dx_t, _dy_t;
    _dx_t = _t_x_rt - _t_x_lt;
    _dy_t = _t_y_rt - _t_y_lt;

    var _dx_lt_rb, _dy_lt_rb;
    _dx_lt_rb = _t_x_rb - _t_x_lt;
    _dy_lt_rb = _t_y_rb - _t_y_lt;

    var _vertical_shift;
    var _text_rect_height = _b - _t;
    var _text_rect_width = _r - _l;
    var oClipRect;
    if (!oBodyPr.upright) {
        if (!(oBodyPr.vert === AscFormat.nVertTTvert || oBodyPr.vert === AscFormat.nVertTTvert270 || oBodyPr.vert === AscFormat.nVertTTeaVert)) {
            if (bWordArtTransform) {
                _vertical_shift = 0;
            }
            else {
                if ((!this.bWordShape && oBodyPr.vertOverflow === AscFormat.nOTOwerflow) || _content_height < _text_rect_height) {
                    switch (oBodyPr.anchor) {
                        case 0: //b
                        { // (Text Anchor Enum ( Bottom ))
                            _vertical_shift = _text_rect_height - _content_height;
                            break;
                        }
                        case 1:    //ctr
                        {// (Text Anchor Enum ( Center ))
                            _vertical_shift = (_text_rect_height - _content_height) * 0.5;
                            break;
                        }
                        case 2: //dist
                        {// (Text Anchor Enum ( Distributed )) TODO: пока выравнивание  по центру. Переделать!
                            _vertical_shift = (_text_rect_height - _content_height) * 0.5;
                            break;
                        }
                        case 3: //just
                        {// (Text Anchor Enum ( Justified )) TODO: пока выравнивание  по центру. Переделать!
                            _vertical_shift = (_text_rect_height - _content_height) * 0.5;
                            break;
                        }
                        case 4: //t
                        {//Top
                            _vertical_shift = 0;
                            break;
                        }
                    }
                }
                else {


                    if((!this.bWordShape && oBodyPr.vertOverflow === AscFormat.nOTClip)
                        && oContent.Content[0] && oContent.Content[0].Lines[0]  && oContent.Content[0].Lines[0].Bottom > _text_rect_height )
                    {
                        var _content_first_line = oContent.Content[0].Lines[0].Bottom;
                        switch (oBodyPr.anchor) {
                            case 0: //b
                            { // (Text Anchor Enum ( Bottom ))
                                _vertical_shift = _text_rect_height - _content_first_line;
                                break;
                            }
                            case 1:    //ctr
                            {// (Text Anchor Enum ( Center ))
                                _vertical_shift = (_text_rect_height - _content_first_line) * 0.5;
                                break;
                            }
                            case 2: //dist
                            {// (Text Anchor Enum ( Distributed ))
                                _vertical_shift = (_text_rect_height - _content_first_line) * 0.5;
                                break;
                            }
                            case 3: //just
                            {// (Text Anchor Enum ( Justified ))
                                _vertical_shift = (_text_rect_height - _content_first_line) * 0.5;
                                break;
                            }
                            case 4: //t
                            {//Top
                                _vertical_shift = 0;
                                break;
                            }
                        }
                    }
                    else{
                        _vertical_shift = _text_rect_height - _content_height;
                        if (oBodyPr.anchor === 0) {
                            _vertical_shift = _text_rect_height - _content_height;
                        }
                        else {
                            _vertical_shift = 0;
                        }
                    }

                }
            }
            global_MatrixTransformer.TranslateAppend(oMatrix, 0, _vertical_shift);
            if (_dx_lt_rb * _dy_t - _dy_lt_rb * _dx_t <= 0) {
                var alpha = Math.atan2(_dy_t, _dx_t);
                global_MatrixTransformer.RotateRadAppend(oMatrix, -alpha);
                global_MatrixTransformer.TranslateAppend(oMatrix, _t_x_lt, _t_y_lt);
            }
            else {
                alpha = Math.atan2(_dy_t, _dx_t);
                global_MatrixTransformer.RotateRadAppend(oMatrix, Math.PI - alpha);
                global_MatrixTransformer.TranslateAppend(oMatrix, _t_x_rt, _t_y_rt);
            }
        }
        else {
            if (bWordArtTransform) {
                _vertical_shift = 0;
            }
            else {
                if ((!this.bWordShape && oBodyPr.vertOverflow === AscFormat.nOTOwerflow) || _content_height <= _text_rect_width) {
                    switch (oBodyPr.anchor) {
                        case 0: //b
                        { // (Text Anchor Enum ( Bottom ))
                            _vertical_shift = _text_rect_width - _content_height;
                            break;
                        }
                        case 1:    //ctr
                        {// (Text Anchor Enum ( Center ))
                            _vertical_shift = (_text_rect_width - _content_height) * 0.5;
                            break;
                        }
                        case 2: //dist
                        {// (Text Anchor Enum ( Distributed ))
                            _vertical_shift = (_text_rect_width - _content_height) * 0.5;
                            break;
                        }
                        case 3: //just
                        {// (Text Anchor Enum ( Justified ))
                            _vertical_shift = (_text_rect_width - _content_height) * 0.5;
                            break;
                        }
                        case 4: //t
                        {//Top
                            _vertical_shift = 0;
                            break;
                        }
                    }
                }
                else {


                    if (oBodyPr.anchor === 0) {
                        _vertical_shift = _text_rect_width - _content_height;
                    }
                    else {
                        _vertical_shift = 0;
                    }
                }
            }
            global_MatrixTransformer.TranslateAppend(oMatrix, 0, _vertical_shift);
            var _alpha;
            _alpha = Math.atan2(_dy_t, _dx_t);
            if (oBodyPr.vert === AscFormat.nVertTTvert || oBodyPr.vert === AscFormat.nVertTTeaVert) {
                if (_dx_lt_rb * _dy_t - _dy_lt_rb * _dx_t <= 0) {
                    global_MatrixTransformer.RotateRadAppend(oMatrix, -_alpha - Math.PI * 0.5);
                    global_MatrixTransformer.TranslateAppend(oMatrix, _t_x_rt, _t_y_rt);
                }
                else {
                    global_MatrixTransformer.RotateRadAppend(oMatrix, Math.PI * 0.5 - _alpha);
                    global_MatrixTransformer.TranslateAppend(oMatrix, _t_x_lt, _t_y_lt);
                }
            }
            else {
                if (_dx_lt_rb * _dy_t - _dy_lt_rb * _dx_t <= 0) {
                    global_MatrixTransformer.RotateRadAppend(oMatrix, -_alpha - Math.PI * 1.5);
                    global_MatrixTransformer.TranslateAppend(oMatrix, _t_x_lb, _t_y_lb);
                }
                else {
                    global_MatrixTransformer.RotateRadAppend(oMatrix, -Math.PI * 0.5 - _alpha);
                    global_MatrixTransformer.TranslateAppend(oMatrix, _t_x_rb, _t_y_rb);
                }
            }
        }
        if (this.spPr && isRealObject(this.spPr.geometry) && isRealObject(this.spPr.geometry.rect)) {
            var rect = this.spPr.geometry.rect;
            var Diff = 1.6;
            var clipW = rect.r - rect.l + Diff;
            if(clipW <= 0)
            {
                clipW = 0.01;
            }
            var clipH = rect.b - rect.t + Diff - b_ins - t_ins;
            if(clipH < 0)
            {
                clipH = 0.01;
            }
            oClipRect = {x: rect.l - Diff, y: rect.t - Diff + t_ins, w: clipW, h: clipH};
        }
        else {
            oClipRect = {x: -1.6, y: t_ins, w: this.extX + 3.2, h: this.extY - b_ins};
        }

    }
    else {
        var _full_rotate = this.getFullRotate();
        var _full_flip = this.getFullFlip();

        var _hc = this.extX * 0.5;
        var _vc = this.extY * 0.5;
        var _transformed_shape_xc = this.localTransform.TransformPointX(_hc, _vc);
        var _transformed_shape_yc = this.localTransform.TransformPointY(_hc, _vc);


        var _content_width, content_height2;
        if (checkNormalRotate(_full_rotate)) {
            if (!(oBodyPr.vert === AscFormat.nVertTTvert || oBodyPr.vert === AscFormat.nVertTTvert270 || oBodyPr.vert === AscFormat.nVertTTeaVert)) {
                _content_width = _r - _l;
                content_height2 = _b - _t;
            }
            else {
                _content_width = _b - _t;
                content_height2 = _r - _l;
            }
        }
        else {
            if (!(oBodyPr.vert === AscFormat.nVertTTvert || oBodyPr.vert === AscFormat.nVertTTvert270 || oBodyPr.vert === AscFormat.nVertTTeaVert)) {
                _content_width = _b - _t;
                content_height2 = _r - _l;

            }
            else {
                _content_width = _r - _l;
                content_height2 = _b - _t;
            }
        }

        if (bWordArtTransform) {
            _vertical_shift = 0;
        }
        else {
            if (!(this.bWordShape || this.worksheet) || _content_height < content_height2) {
                switch (oBodyPr.anchor) {
                    case 0: //b
                    { // (Text Anchor Enum ( Bottom ))
                        _vertical_shift = content_height2 - _content_height;
                        break;
                    }
                    case 1:    //ctr
                    {// (Text Anchor Enum ( Center ))
                        _vertical_shift = (content_height2 - _content_height) * 0.5;
                        break;
                    }
                    case 2: //dist
                    {// (Text Anchor Enum ( Distributed ))
                        _vertical_shift = (content_height2 - _content_height) * 0.5;
                        break;
                    }
                    case 3: //just
                    {// (Text Anchor Enum ( Justified ))
                        _vertical_shift = (content_height2 - _content_height) * 0.5;
                        break;
                    }
                    case 4: //t
                    {//Top
                        _vertical_shift = 0;
                        break;
                    }
                }
            }
            else {
                if (oBodyPr.anchor === 0) {
                    _vertical_shift = content_height2 - _content_height;
                }
                else {
                    _vertical_shift = 0;
                }
            }

        }

        var _text_rect_xc = _l + (_r - _l) * 0.5;
        var _text_rect_yc = _t + (_b - _t) * 0.5;

        var _vx = _text_rect_xc - _hc;
        var _vy = _text_rect_yc - _vc;

        var _transformed_text_xc, _transformed_text_yc;
        if (!_full_flip.flipH) {
            _transformed_text_xc = _transformed_shape_xc + _vx;
        }
        else {
            _transformed_text_xc = _transformed_shape_xc - _vx;
        }

        if (!_full_flip.flipV) {
            _transformed_text_yc = _transformed_shape_yc + _vy;
        }
        else {
            _transformed_text_yc = _transformed_shape_yc - _vy;
        }

        global_MatrixTransformer.TranslateAppend(oMatrix, 0, _vertical_shift);
        if (oBodyPr.vert === AscFormat.nVertTTvert || oBodyPr.vert === AscFormat.nVertTTeaVert) {
            global_MatrixTransformer.TranslateAppend(oMatrix, -_content_width * 0.5, -content_height2 * 0.5);
            global_MatrixTransformer.RotateRadAppend(oMatrix, -Math.PI * 0.5);
            global_MatrixTransformer.TranslateAppend(oMatrix, _content_width * 0.5, content_height2 * 0.5);

        }
        if (oBodyPr.vert === AscFormat.nVertTTvert270) {
            global_MatrixTransformer.TranslateAppend(oMatrix, -_content_width * 0.5, -content_height2 * 0.5);
            global_MatrixTransformer.RotateRadAppend(oMatrix, -Math.PI * 1.5);
            global_MatrixTransformer.TranslateAppend(oMatrix, _content_width * 0.5, content_height2 * 0.5);
        }
        global_MatrixTransformer.TranslateAppend(oMatrix, _transformed_text_xc - _content_width * 0.5, _transformed_text_yc - content_height2 * 0.5);


        var Diff = 1.6;
        if(this.bWordShape)
        {
            var DiffLeft = 0.8;
            var DiffRight = 1.6;
            var aContent = oContent.Content;
            for(var i = 0; i < aContent.length; ++i)
            {
                if(aContent[i].GetType && type_Paragraph === aContent[i].GetType())
                {
                    var oCompiledParaPr = aContent[i].CompiledPr && aContent[i].CompiledPr.Pr && aContent[i].CompiledPr.Pr.ParaPr;
                    if(oCompiledParaPr)
                    {
                        var oBorders = oCompiledParaPr.Brd;
                        if(oBorders)
                        {
                            if(oBorders.Left  && AscFormat.isRealNumber(oBorders.Left.Space) && AscFormat.isRealNumber(oBorders.Left.Size) && oBorders.Left.Size > 0.0)
                            {
                                var DiffLeft2 = oBorders.Left.Space + oBorders.Left.Size + 1.0;
                                if(DiffLeft2 > DiffLeft)
                                {
                                    DiffLeft = DiffLeft2;
                                }
                            }
                            if(oBorders.Right && AscFormat.isRealNumber(oBorders.Right.Space) && AscFormat.isRealNumber(oBorders.Right.Size) && oBorders.Right.Size > 0.0)
                            {
                                var DiffRight2 = oBorders.Right.Space + oBorders.Right.Size + 1.0;
                                if(oCompiledParaPr.Ind && AscFormat.isRealNumber(oCompiledParaPr.Ind.Right))
                                {
                                    DiffRight2 -= oCompiledParaPr.Ind.Right;
                                }
                                if(DiffRight2 > DiffRight)
                                {
                                    DiffRight = DiffRight2;
                                }
                            }
                        }
                    }
                }
            }


            var clipW = oRect.r - oRect.l + DiffLeft + DiffRight - l_ins - r_ins;
            if(clipW <= 0)
            {
                clipW = 0.01;
            }
            var clipH = oRect.b - oRect.t + Diff - b_ins - t_ins;
            if(clipH < 0)
            {
                clipH = 0.01;
            }
            oClipRect = {x: oRect.l + l_ins - DiffLeft, y: oRect.t - Diff + t_ins, w: clipW, h: clipH};
        }
        else
        {
            var clipW = oRect.r - oRect.l + Diff - l_ins - r_ins;
            if(clipW <= 0)
            {
                clipW = 0.01;
            }
            var clipH = oRect.b - oRect.t + Diff - b_ins - t_ins;
            if(clipH < 0)
            {
                clipH = 0.01;
            }
            oClipRect = {x: oRect.l + l_ins - Diff, y: oRect.t - Diff + t_ins, w: clipW, h: clipH};

        }
    }
    return oClipRect;
};

CShape.prototype.setWordShape = function (pr) {
    History.Add(new AscDFH.CChangesDrawingsBool(this, AscDFH.historyitem_ShapeSetWordShape, this.bWordShape, pr));
    this.bWordShape = pr;
};

CShape.prototype.selectionCheck = function (X, Y, PageAbs, NearPos) {

    var content = this.getDocContent();
    if (content) {
        if (undefined !== NearPos)
            return content.CheckPosInSelection(X, Y, 0, NearPos);

        if (isRealObject(content) && this.hitInTextRect(X, Y) && this.invertTransformText) {
            var t_x = this.invertTransformText.TransformPointX(X, Y);
            var t_y = this.invertTransformText.TransformPointY(X, Y);
            return content.CheckPosInSelection(t_x, t_y, 0, NearPos);
        }
    }
    return false;
};

CShape.prototype.fillObject = function(copy){
    if (this.nvSpPr)
        copy.setNvSpPr(this.nvSpPr.createDuplicate());
    if (this.spPr) {
        copy.setSpPr(this.spPr.createDuplicate());
        copy.spPr.setParent(copy);
    }
    if (this.style) {
        copy.setStyle(this.style.createDuplicate());
    }
    if (this.txBody) {
        copy.setTxBody(this.txBody.createDuplicate());
        copy.txBody.setParent(copy);
    }
    if (this.bodyPr) {
        copy.setBodyPr(this.bodyPr.createDuplicate());
    }
    if (this.textBoxContent) {
        copy.setTextBoxContent(this.textBoxContent.Copy(copy));
    }
    if(this.signatureLine && copy.setSignature){
        copy.setSignature(this.signatureLine.copy());
    }
    copy.setWordShape(this.bWordShape);
    copy.setBDeleted(this.bDeleted);
    if(this.fromSerialize)
    {
        copy.setBFromSerialize(true);
    }
    copy.setLocks(this.locks);
    copy.cachedImage = this.getBase64Img();
    copy.cachedPixH = this.cachedPixH;
    copy.cachedPixW = this.cachedPixW;
};

CShape.prototype.copy = function () {
    var copy = new CShape();
    this.fillObject(copy);
    return copy;
};

CShape.prototype.Get_Styles = function (level) {

    var _level = AscFormat.isRealNumber(level) ? level : 0;
    if (this.recalcInfo.recalculateTextStyles[_level]) {
        this.recalculateTextStyles(_level);
        this.recalcInfo.recalculateTextStyles[_level] = false;
    }
    this.recalcInfo.recalculateTextStyles[_level] = true;
    var ret = this.compiledStyles[_level];
    this.compiledStyles[_level] = undefined;
    return ret;
    //   return this.compiledStyles[_level];
};


CShape.prototype.recalculateTextStyles = function (level) {
    return AscFormat.ExecuteNoHistory(function () {
        var parent_objects = this.getParentObjects();
        var default_style = new CStyle("defaultStyle", null, null, null, true);
        default_style.ParaPr.Spacing.LineRule = Asc.linerule_Auto;
        default_style.ParaPr.Spacing.Line = 1;
        default_style.ParaPr.Spacing.Before = 0;
        default_style.ParaPr.Spacing.After = 0;
        default_style.ParaPr.DefaultTab = 25.4;
        default_style.ParaPr.Align = AscCommon.align_Center;
        if(parent_objects.theme)
        {
            default_style.TextPr.RFonts.Ascii = {Name: "+mn-lt", Index: -1};
            default_style.TextPr.RFonts.EastAsia = {Name: "+mn-ea", Index: -1};
            default_style.TextPr.RFonts.CS = {Name: "+mn-cs", Index: -1};
            default_style.TextPr.RFonts.HAnsi = {Name: "+mn-lt", Index: -1};
        }
        if(this.getObjectType && this.getObjectType() === AscDFH.historyitem_type_GraphicFrame){
            default_style.TextPr.FontSize = 18;
        }
        if (isRealObject(parent_objects.presentation) && isRealObject(parent_objects.presentation.defaultTextStyle)) {

            if(isRealObject(parent_objects.presentation.defaultTextStyle.levels[9]))
            {
                var default_ppt_style = parent_objects.presentation.defaultTextStyle.levels[9];
                default_style.ParaPr.Merge(default_ppt_style.Copy());
                default_ppt_style.DefaultRunPr && default_style.TextPr.Merge(default_ppt_style.DefaultRunPr.Copy());
            }
            if(!isRealObject(parent_objects.master) || !isRealObject(parent_objects.master.txStyles) || !this.isPlaceholder())
            {
                if(isRealObject(parent_objects.presentation.defaultTextStyle.levels[level]))
                {
                    var default_ppt_style = parent_objects.presentation.defaultTextStyle.levels[level];
                    default_style.ParaPr.Merge(default_ppt_style.Copy());
                    default_ppt_style.DefaultRunPr && default_style.TextPr.Merge(default_ppt_style.DefaultRunPr.Copy());
                }
            }
        }

        var master_style;
        if (isRealObject(parent_objects.master) && isRealObject(parent_objects.master.txStyles)) {
            var master_ppt_styles;
            master_style = new CStyle("masterStyle", null, null, null, true);
            if(parent_objects.master.kind === AscFormat.TYPE_KIND.NOTES_MASTER){
                master_ppt_styles = parent_objects.master.txStyles;
            }
            else{
                if (this.isPlaceholder() && !(this instanceof AscFormat.CGraphicFrame)) {
                    switch (this.getPlaceholderType()) {
                        case AscFormat.phType_ctrTitle:
                        case AscFormat.phType_title:
                        {
                            master_ppt_styles = parent_objects.master.txStyles.titleStyle;
                            break;
                        }
                        case AscFormat.phType_body:
                        case AscFormat.phType_subTitle:
                        case AscFormat.phType_obj:
                        case null:
                        {
                            master_ppt_styles = parent_objects.master.txStyles.bodyStyle;
                            break;
                        }
                        default:
                        {
                            master_ppt_styles = parent_objects.master.txStyles.otherStyle;
                            break;
                        }
                    }
                }
                else {
                    master_ppt_styles = parent_objects.master.txStyles.otherStyle;
                }
            }

            if (isRealObject(master_ppt_styles) && isRealObject(master_ppt_styles.levels) && isRealObject(master_ppt_styles.levels[level])) {
                var master_ppt_style = master_ppt_styles.levels[level];
                master_style.ParaPr = master_ppt_style.Copy();
                if (master_ppt_style.DefaultRunPr) {
                    master_style.TextPr = master_ppt_style.DefaultRunPr.Copy();
                }
            }
        }

        var hierarchy = this.getHierarchy(false);
        var hierarchy_styles = [];
        for (var i = 0; i < hierarchy.length; ++i) {
            var hierarchy_shape = hierarchy[i];
            if (isRealObject(hierarchy_shape)
                && isRealObject(hierarchy_shape.txBody)
                && isRealObject(hierarchy_shape.txBody.lstStyle)
                && isRealObject(hierarchy_shape.txBody.lstStyle.levels)
                && isRealObject(hierarchy_shape.txBody.lstStyle.levels[level])) {
                var hierarchy_ppt_style = hierarchy_shape.txBody.lstStyle.levels[level];
                var hierarchy_style = new CStyle("hierarchyStyle" + i, null, null, null, true);
                hierarchy_style.ParaPr = hierarchy_ppt_style.Copy();
                if (hierarchy_ppt_style.DefaultRunPr) {
                    hierarchy_style.TextPr = hierarchy_ppt_style.DefaultRunPr.Copy();
                }
                hierarchy_styles.push(hierarchy_style);
            }
        }

        var ownStyle;
        if (isRealObject(this.txBody) && isRealObject(this.txBody.lstStyle) && isRealObject(this.txBody.lstStyle.levels[level])) {
            ownStyle = new CStyle("ownStyle", null, null, null, true);
            var own_ppt_style = this.txBody.lstStyle.levels[level];
            ownStyle.ParaPr = own_ppt_style.Copy();
            if (own_ppt_style.DefaultRunPr) {
                ownStyle.TextPr = own_ppt_style.DefaultRunPr.Copy();
            }
            hierarchy_styles.splice(0, 0, ownStyle);
        }
        var shape_text_style;
        var compiled_style = this.getCompiledStyle && this.getCompiledStyle();
        if (isRealObject(compiled_style) && isRealObject(compiled_style.fontRef)) {
            shape_text_style = new CStyle("shapeTextStyle", null, null, null, true);
            var first_name;
            if (compiled_style.fontRef.idx === AscFormat.fntStyleInd_major)
                first_name = "+mj-";
            else
                first_name = "+mn-";

            shape_text_style.TextPr.RFonts.Ascii = {Name: first_name + "lt", Index: -1};
            shape_text_style.TextPr.RFonts.EastAsia = {Name: first_name + "ea", Index: -1};
            shape_text_style.TextPr.RFonts.CS = {Name: first_name + "cs", Index: -1};
            shape_text_style.TextPr.RFonts.HAnsi = {Name: first_name + "lt", Index: -1};

            if (compiled_style.fontRef.Color != null && compiled_style.fontRef.Color.color != null) {
                var unifill = new AscFormat.CUniFill();
                unifill.fill = new AscFormat.CSolidFill();
                unifill.fill.color = compiled_style.fontRef.Color;
                shape_text_style.TextPr.Unifill = unifill;
            }
        }
        var Styles = new CStyles(false);


        var last_style_id;
        var b_checked = false;
        var isPlaceholder = this.isPlaceholder();
        if (isPlaceholder || this.graphicObject instanceof CTable) {
            if (default_style) {
                //checkTextPr(default_style.TextPr);
                b_checked = true;
                Styles.Add(default_style);
                default_style.BasedOn = null;
                last_style_id = default_style.Id;
            }

            if (master_style) {
                //checkTextPr(master_style.TextPr);
                Styles.Add(master_style);
                master_style.BasedOn = last_style_id;
                last_style_id = master_style.Id;
            }
        }
        else {
            if (master_style) {
                // checkTextPr(master_style.TextPr);
                b_checked = true;
                Styles.Add(master_style);
                master_style.BasedOn = null;
                last_style_id = master_style.Id;
            }

            if (default_style) {
                //checkTextPr(default_style.TextPr);
                Styles.Add(default_style);
                default_style.BasedOn = last_style_id;
                last_style_id = default_style.Id;
            }
        }

        for (var i = hierarchy_styles.length - 1; i > -1; --i) {

            if (hierarchy_styles[i]) {
                //checkTextPr(hierarchy_styles[i].TextPr);
                Styles.Add(hierarchy_styles[i]);
                hierarchy_styles[i].BasedOn = last_style_id;
                last_style_id = hierarchy_styles[i].Id;
            }
        }


        if (shape_text_style) {
            //checkTextPr(shape_text_style.TextPr);
            Styles.Add(shape_text_style);
            shape_text_style.BasedOn = last_style_id;
            last_style_id = shape_text_style.Id;
        }

        this.compiledStyles[level] = {styles: Styles, lastId: last_style_id};
        return this.compiledStyles[level];
    }, this, []);
};

CShape.prototype.recalculateBrush = function () {
    var compiled_style = this.getCompiledStyle();
    var RGBA = {R: 0, G: 0, B: 0, A: 255};
    var parents = this.getParentObjects();
    if (isRealObject(parents.theme) && isRealObject(compiled_style) && isRealObject(compiled_style.fillRef)) {
        //compiled_style.fillRef.Color.Calculate(parents.theme, parents.slide, parents.layout, parents.master, {R: 0, G: 0, B: 0, A:255});
        //RGBA = compiled_style.fillRef.Color.RGBA;
        this.brush = parents.theme.getFillStyle(compiled_style.fillRef.idx, compiled_style.fillRef.Color);
        //if (isRealObject(this.brush))
        //{
        //    if (isRealObject(compiled_style.fillRef.Color.color)
        //        && isRealObject(this.brush)
        //        && isRealObject(this.brush.fill)
        //        && this.brush.fill.type === FILL_TYPE_SOLID)
        //    {
        //        this.brush.fill.color = compiled_style.fillRef.Color.createDuplicate();
        //    }
        //}
        //else
        //{
        //    this.brush = new AscFormat.CUniFill();
        //}
    }
    else {
        this.brush = new AscFormat.CUniFill();
    }

    this.brush.merge(this.getCompiledFill());
    this.brush.transparent = this.getCompiledTransparent();
    this.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA);
    if(this.bWordShape){
        if(this.brush.fill && this.brush.fill.type === Asc.c_oAscFill.FILL_TYPE_GRAD){
            var oGradFill = this.brush.fill;
            if(!oGradFill.lin && !oGradFill.path){
                var oLin = new AscFormat.GradLin();
                oLin.setScale(false);
                oLin.setAngle(5400000);
                oGradFill.setLin(oLin);
            }
        }
    }
};

CShape.prototype.recalculatePen = function () {
    var compiled_style = this.getCompiledStyle();
    var RGBA = {R: 0, G: 0, B: 0, A: 255};
    var parents = this.getParentObjects();
    if (isRealObject(parents.theme) && isRealObject(compiled_style) && isRealObject(compiled_style.lnRef)) {
        //compiled_style.lnRef.Color.Calculate(parents.theme, parents.slide, parents.layout, parents.master, {R: 0, G: 0, B: 0, A:255});
        //RGBA = compiled_style.lnRef.Color.RGBA;
        this.pen = parents.theme.getLnStyle(compiled_style.lnRef.idx, compiled_style.lnRef.Color);
        //if (isRealObject(this.pen)) {
        //    if (isRealObject(compiled_style.lnRef.Color.color)
        //        && isRealObject(this.pen)
        //        && isRealObject(this.pen.Fill)
        //        && isRealObject(this.pen.Fill.fill)
        //        && this.pen.Fill.fill.type === FILL_TYPE_SOLID) {
        //        this.pen.Fill.fill.color = compiled_style.lnRef.Color.createDuplicate();
        //    }
        //}
        //else
        //{
        //    this.pen = new AscFormat.CLn();
        //}
    }
    else {
        this.pen = null;
    }

    var oCompiledLine = this.getCompiledLine();
    if(oCompiledLine)
    {
        if(!this.pen)
        {
            this.pen = new AscFormat.CLn();
        }
        this.pen.merge(oCompiledLine);
    }
    if(this.pen)
    {
        this.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA);
    }
};

CShape.prototype.Get_ParentTextTransform = function()
{
    return this.transformText.CreateDublicate();
};

CShape.prototype.isEmptyPlaceholder = function () {
    if (this.isPlaceholder()) {
        if (this.nvSpPr.nvPr.ph.type == AscFormat.phType_title
            || this.nvSpPr.nvPr.ph.type == AscFormat.phType_ctrTitle
            || this.nvSpPr.nvPr.ph.type == AscFormat.phType_body
            || this.nvSpPr.nvPr.ph.type == AscFormat.phType_subTitle
            || this.nvSpPr.nvPr.ph.type == null
            || this.nvSpPr.nvPr.ph.type == AscFormat.phType_dt
            || this.nvSpPr.nvPr.ph.type == AscFormat.phType_ftr
            || this.nvSpPr.nvPr.ph.type == AscFormat.phType_hdr
            || this.nvSpPr.nvPr.ph.type == AscFormat.phType_sldNum
            || this.nvSpPr.nvPr.ph.type == AscFormat.phType_sldImg) {
            if (this.txBody) {
                if (this.txBody.content) {
                    return this.txBody.content.Is_Empty();
                }
                return true;
            }
            return true;
        }
        if (this.nvSpPr.nvPr.ph.type == AscFormat.phType_chart
            || this.nvSpPr.nvPr.ph.type == AscFormat.phType_media) {
            return true;
        }
        if (this.nvSpPr.nvPr.ph.type == AscFormat.phType_pic) {
            var _b_empty_text = true;
            if (this.txBody) {
                if (this.txBody.content) {
                    _b_empty_text = this.txBody.content.Is_Empty();
                }
            }
            return (_b_empty_text /* && (this.brush == null || this.brush.fill == null)*/);
        }
    }
    else {
        return false;
    }
};


CShape.prototype.changeSize = function (kw, kh) {
    if (this.spPr && this.spPr.xfrm && this.spPr.xfrm.isNotNull()) {
        var xfrm = this.spPr.xfrm;
        // if(this.getNoChangeAspect()){
        //     var k = Math.min(kw, kh);
        //     var oldXC = xfrm.offX + xfrm.extX/2.0;
        //     var oldYC = xfrm.offY + xfrm.extY/2.0;
        //     xfrm.setExtX(xfrm.extX * k);
        //     xfrm.setExtY(xfrm.extY * k);
        //     xfrm.setOffX(oldXC * kw - xfrm.extX/2.0);
        //     xfrm.setOffY(oldYC * kh - xfrm.extY/2.0);
        // }
        // else
            {

            xfrm.setOffX(xfrm.offX * kw);
            xfrm.setOffY(xfrm.offY * kh);
            xfrm.setExtX(xfrm.extX * kw);
            xfrm.setExtY(xfrm.extY * kh);
        }
    }
    this.recalcTransform && this.recalcTransform();
};

CShape.prototype.recalculateTransform = function () {
    this.cachedImage = null;
    this.recalculateLocalTransform(this.transform);
    this.invertTransform = global_MatrixTransformer.Invert(this.transform);
    this.localTransform = this.transform.CreateDublicate();
};


CShape.prototype.checkAutofit = function (bIgnoreWordShape) {
    if (this.bWordShape || bIgnoreWordShape || this.bCheckAutoFitFlag) {
        var content = this.getDocContent();
        if (content) {
            var oBodyPr = this.getBodyPr();
            if (oBodyPr.textFit && oBodyPr.textFit.type === AscFormat.text_fit_Auto || oBodyPr.wrap === AscFormat.nTWTNone) {
                return true;
            }
        }
    }
    return false;
};

CShape.prototype.Check_AutoFit = function () {
    return this.checkAutofit(true) || this.checkContentWordArt(this.getDocContent()) || this.getBodyPr().prstTxWarp != null;
};

CShape.prototype.checkExtentsByAutofit = function(oShape)
{

};


CShape.prototype.recalculateLocalTransform = function(transform)
{
    var bNotesShape = false;
    if (!isRealObject(this.group))
    {
        if(this.drawingBase  && this.fromSerialize)
        {
            var metrics = this.drawingBase.getGraphicObjectMetrics();
            this.x = metrics.x;
            this.y = metrics.y;
            var rot = 0;
            if(this.spPr && this.spPr.xfrm){
                if(AscFormat.isRealNumber(this.spPr.xfrm.rot)){
                    rot =  AscFormat.normalizeRotate(this.spPr.xfrm.rot);
                }
                this.flipH = this.spPr.xfrm.flipH === true;
                this.flipV = this.spPr.xfrm.flipV === true;
            }
            this.rot = rot;

            var metricExtX, metricExtY;
          //  if(!(this instanceof AscFormat.CGroupShape))
            {
                metricExtX = metrics.extX;
                metricExtY = metrics.extY;
                if (checkNormalRotate(rot))
                {
                    this.extX = metrics.extX;
                    this.extY = metrics.extY;
                }
                else
                {
                    this.extX = metrics.extY;
                    this.extY = metrics.extX;
                }
            }
            // else
            // {
            //     if(this.spPr && this.spPr.xfrm && AscFormat.isRealNumber(this.spPr.xfrm.extX) && AscFormat.isRealNumber(this.spPr.xfrm.extY))
            //     {
            //         this.extX = this.spPr.xfrm.extX;
            //         this.extY = this.spPr.xfrm.extY;
            //     }
            //     else
            //     {
            //         metricExtX = metrics.extX;
            //         metricExtY = metrics.extY;
            //     }
            // }

            if (checkNormalRotate(rot))
            {
                this.x = metrics.x;
                this.y = metrics.y;
            }
            else
            {
                this.x = metrics.x + metricExtX/2 - metricExtY/2;
                this.y = metrics.y + metricExtY/2 - metricExtX/2;
            }
        }
        else if(typeof AscCommonSlide !== "undefined" && AscCommonSlide
            && AscCommonSlide.CNotes && this.parent && this.parent instanceof AscCommonSlide.CNotes){
            bNotesShape = true;
            this.x = 0;
            this.y = editor.WordControl.m_oLogicDocument.Height;
            this.extX = this.parent.getWidth();
            this.extY = 2000;
            this.rot = 0;
            this.flipH = false;
            this.flipV = false;
        }
        else if (this.spPr && this.spPr.xfrm && this.spPr.xfrm.isNotNull())
        {
            var xfrm = this.spPr.xfrm;
            this.x = xfrm.offX;
            this.y = xfrm.offY;
            this.extX = xfrm.extX;
            this.extY = xfrm.extY;
            this.rot = AscFormat.isRealNumber(xfrm.rot) ? xfrm.rot : 0;
            this.flipH = xfrm.flipH === true;
            this.flipV = xfrm.flipV === true;
            if(this.extX < 0.01 && this.extY < 0.01)
            {
                if(this.parent && this.parent.Extent && AscFormat.isRealNumber(this.parent.Extent.W) && AscFormat.isRealNumber(this.parent.Extent.H))
                {
                    this.x = 0;
                    this.y = 0;
                    this.extX = this.parent.Extent.W;
                    this.extY = this.parent.Extent.H;
                }
            }
            else
            {
                    var oParaDrawing = getParaDrawing(this);
                    if(oParaDrawing)
                    {
                        this.x = 0;
                        this.y = 0;

                        if(oParaDrawing.Extent && AscFormat.isRealNumber(oParaDrawing.Extent.W) && AscFormat.isRealNumber(oParaDrawing.Extent.H))
                        {
                            this.x = 0;
                            this.y = 0;
                            this.extX = oParaDrawing.Extent.W;
                            this.extY = oParaDrawing.Extent.H;
                        }
                        if(oParaDrawing.SizeRelH || oParaDrawing.SizeRelV)
                        {
                            this.m_oSectPr = null;
                            var oParentParagraph = oParaDrawing.Get_ParentParagraph();
                            if(oParentParagraph)
                            {

                                var oSectPr = oParentParagraph.Get_SectPr();
                                if(oSectPr)
                                {
                                    if(oParaDrawing.SizeRelH && oParaDrawing.SizeRelH.Percent > 0)
                                    {
                                        switch(oParaDrawing.SizeRelH.RelativeFrom)
                                        {
                                            case c_oAscSizeRelFromH.sizerelfromhMargin:
                                            {
                                                this.extX = oSectPr.Get_PageWidth() - oSectPr.Get_PageMargin_Left() - oSectPr.Get_PageMargin_Right();
                                                break;
                                            }
                                            case c_oAscSizeRelFromH.sizerelfromhPage:
                                            {
                                                this.extX = oSectPr.Get_PageWidth();
                                                break;
                                            }
                                            case c_oAscSizeRelFromH.sizerelfromhLeftMargin:
                                            {
                                                this.extX = oSectPr.Get_PageMargin_Left();
                                                break;
                                            }

                                            case c_oAscSizeRelFromH.sizerelfromhRightMargin:
                                            {
                                                this.extX = oSectPr.Get_PageMargin_Right();
                                                break;
                                            }
                                            default:
                                            {
                                                this.extX = oSectPr.Get_PageMargin_Left();
                                                break;
                                            }
                                        }
                                        this.extX *= oParaDrawing.SizeRelH.Percent;
                                    }
                                    if(oParaDrawing.SizeRelV && oParaDrawing.SizeRelV.Percent > 0)
                                    {
                                        switch(oParaDrawing.SizeRelV.RelativeFrom)
                                        {
                                            case c_oAscSizeRelFromV.sizerelfromvMargin:
                                            {
                                                this.extY = oSectPr.Get_PageHeight() - oSectPr.Get_PageMargin_Top() - oSectPr.Get_PageMargin_Bottom();
                                                break;
                                            }
                                            case c_oAscSizeRelFromV.sizerelfromvPage:
                                            {
                                                this.extY = oSectPr.Get_PageHeight();
                                                break;
                                            }
                                            case c_oAscSizeRelFromV.sizerelfromvTopMargin:
                                            {
                                                this.extY = oSectPr.Get_PageMargin_Top();
                                                break;
                                            }
                                            case c_oAscSizeRelFromV.sizerelfromvBottomMargin:
                                            {
                                                this.extY = oSectPr.Get_PageMargin_Bottom();
                                                break;
                                            }
                                            default:
                                            {
                                                this.extY = oSectPr.Get_PageMargin_Top();
                                                break;
                                            }
                                        }
                                        this.extY *= oParaDrawing.SizeRelV.Percent;
                                    }
                                    this.m_oSectPr = new CSectionPr();
                                    this.m_oSectPr.Copy(oSectPr);
                                }
                            }
                        }
                    }

            }
        }
        else
        {
            if (this.isPlaceholder())
            {
                var hierarchy = this.getHierarchy();
                for (var i = 0; i < hierarchy.length; ++i)
                {
                    var hierarchy_sp = hierarchy[i];
                    if (isRealObject(hierarchy_sp)  && hierarchy_sp.spPr.xfrm && hierarchy_sp.spPr.xfrm.isNotNull())
                    {
                        var xfrm = hierarchy_sp.spPr.xfrm;
                        this.x = xfrm.offX;
                        this.y = xfrm.offY;
                        this.extX = xfrm.extX;
                        this.extY = xfrm.extY;
                        this.rot = AscFormat.isRealNumber(xfrm.rot) ? xfrm.rot : 0;
                        this.flipH = xfrm.flipH === true;
                        this.flipV = xfrm.flipV === true;
                        break;
                    }
                }
                if (i === hierarchy.length)
                {
                    this.x = 0;
                    this.y = 0;
                    this.extX = 5;
                    this.extY = 5;
                    this.rot = 0;
                    this.flipH = false;
                    this.flipV = false;
                }
            }
            else
            {
                var extX, extY;
                if(this.parent && this.parent.Extent)
                {
                    this.x = 0;
                    this.y = 0;
                    extX = this.parent.Extent.W;
                    extY = this.parent.Extent.H;
                }
                else
                {
                    this.x = 0;
                    this.y = 0;
                    extX = 5;
                    extY = 5;
                }
                this.extX = extX;
                this.extY = extY;
                this.rot = 0;
                this.flipH = false;
                this.flipV = false;
            }
        }
    }
    else
    {
        var xfrm;
        if (this.spPr && this.spPr.xfrm && this.spPr.xfrm.isNotNull())
        {
            xfrm = this.spPr.xfrm;
        }
        else
        {
            if (this.isPlaceholder()) {
                var hierarchy = this.getHierarchy();
                for (var i = 0; i < hierarchy.length; ++i) {
                    var hierarchy_sp = hierarchy[i];
                    if (isRealObject(hierarchy_sp) && hierarchy_sp.spPr.xfrm.isNotNull()) {
                        xfrm = hierarchy_sp.spPr.xfrm;
                        break;
                    }
                }
                if (i === hierarchy.length) {
                    xfrm = new AscFormat.CXfrm();
                    xfrm.offX = 0;
                    xfrm.offX = 0;
                    xfrm.extX = 5;
                    xfrm.extY = 5;
                }
            }
            else {
                xfrm = new AscFormat.CXfrm();
                xfrm.offX = 0;
                xfrm.offY = 0;
                xfrm.extX = 5;
                xfrm.extY = 5;
            }
        }


        var scale_scale_coefficients = this.group.getResultScaleCoefficients();
        this.x = scale_scale_coefficients.cx * (xfrm.offX - this.group.spPr.xfrm.chOffX);
        this.y = scale_scale_coefficients.cy * (xfrm.offY - this.group.spPr.xfrm.chOffY);
        this.extX = scale_scale_coefficients.cx * xfrm.extX;
        this.extY = scale_scale_coefficients.cy * xfrm.extY;
        this.rot = AscFormat.isRealNumber(xfrm.rot) ? xfrm.rot : 0;
        this.flipH = xfrm.flipH === true;
        this.flipV = xfrm.flipV === true;
    }


    if(this.checkAutofit && this.checkAutofit() && (!this.bWordShape || !this.group || this.bCheckAutoFitFlag) && !bNotesShape) {
        var oBodyPr = this.getBodyPr();
        if (this.bWordShape) {
            if (this.recalcInfo.recalculateTxBoxContent) {
                this.recalcInfo.oContentMetrics = this.recalculateTxBoxContent();
                //this.recalcInfo.recalculateTxBoxContent = false;
                this.recalcInfo.AllDrawings = [];
                var oContent = this.getDocContent();
                if(oContent)
                {
                    oContent.GetAllDrawingObjects(this.recalcInfo.AllDrawings);
                }
            }
        }
        else {
            if (this.recalcInfo.recalculateContent) {
                this.recalcInfo.oContentMetrics = this.recalculateContent();
                this.recalcInfo.recalculateContent = false;
            }
        }
        var oContentMetrics = this.recalcInfo.oContentMetrics;

        var l_ins, t_ins, r_ins, b_ins;
        if (oBodyPr) {
            l_ins = AscFormat.isRealNumber(oBodyPr.lIns) ? oBodyPr.lIns : 2.54;
            r_ins = AscFormat.isRealNumber(oBodyPr.rIns) ? oBodyPr.rIns : 2.54;
            t_ins = AscFormat.isRealNumber(oBodyPr.tIns) ? oBodyPr.tIns : 1.27;
            b_ins = AscFormat.isRealNumber(oBodyPr.bIns) ? oBodyPr.bIns : 1.27;
        }
        else {
            l_ins = 2.54;
            r_ins = 2.54;
            t_ins = 1.27;
            b_ins = 1.27;
        }
        var oGeometry = this.spPr && this.spPr.geometry, oWH;
        var dOldExtX = this.extX, dOldExtY = this.extY, dDeltaX = 0, dDeltaY = 0;


        var bAutoFit = AscCommon.isRealObject(oBodyPr.textFit) && oBodyPr.textFit.type === AscFormat.text_fit_Auto;
        if (oBodyPr.wrap === AscFormat.nTWTNone) {
            if (!oBodyPr.upright) {
                if (!(oBodyPr.vert === AscFormat.nVertTTvert || oBodyPr.vert === AscFormat.nVertTTvert270 || oBodyPr.vert === AscFormat.nVertTTeaVert)) {
                    if (oGeometry) {
                        oWH = oGeometry.getNewWHByTextRect(oContentMetrics.w + l_ins + r_ins, oContentMetrics.contentH + t_ins + b_ins, undefined, bAutoFit ? undefined : this.extY);
                        if(!oWH.bError)
                        {
                            this.extX = oWH.W;
                            this.extY = oWH.H;
                        }
                    }
                    else {
                        this.extX = oContentMetrics.w + l_ins + r_ins;
                        this.extY =  bAutoFit ?  oContentMetrics.contentH + t_ins + b_ins : this.extY;
                    }

                }
                else {
                    if (oGeometry) {
                        oWH = oGeometry.getNewWHByTextRect(oContentMetrics.contentH + l_ins + r_ins, oContentMetrics.w + t_ins + b_ins, bAutoFit ? undefined : this.extX);
                        if(!oWH.bError)
                        {
                            this.extX = oWH.W;
                            this.extY = oWH.H;
                        }
                    }
                    else {
                        this.extY = oContentMetrics.w + t_ins + b_ins;
                        this.extX =  bAutoFit ? oContentMetrics.contentH + l_ins + r_ins : this.extX;
                    }
                }
            }
            else {
                var _full_rotate = this.getFullRotate();
                if (checkNormalRotate(_full_rotate)) {
                    if (!(oBodyPr.vert === AscFormat.nVertTTvert || oBodyPr.vert === AscFormat.nVertTTvert270 || oBodyPr.vert === AscFormat.nVertTTeaVert)) {

                        if (oGeometry) {
                            oWH = oGeometry.getNewWHByTextRect(oContentMetrics.w + l_ins + r_ins, oContentMetrics.contentH + t_ins + b_ins, undefined, bAutoFit ? undefined : this.extY);
                            if(!oWH.bError) {
                                this.extX = oWH.W;
                                this.extY = oWH.H;
                            }
                        }
                        else {
                            this.extX = oContentMetrics.w + l_ins + r_ins;
                            this.extY =  bAutoFit ? oContentMetrics.contentH + t_ins + b_ins : this.extY;
                        }
                    }
                    else {
                        if (oGeometry) {
                            oWH = oGeometry.getNewWHByTextRect(oContentMetrics.contentH + l_ins + r_ins, oContentMetrics.w + t_ins + b_ins, bAutoFit ? undefined : this.extX);
                            if(!oWH.bError) {
                                this.extX = oWH.W;
                                this.extY = oWH.H;
                            }
                        }
                        else {
                            this.extY = oContentMetrics.w + t_ins + b_ins;
                            this.extX = bAutoFit ? oContentMetrics.contentH + l_ins + r_ins : this.extX;
                        }

                    }
                }
                else {
                    if (!(oBodyPr.vert === AscFormat.nVertTTvert || oBodyPr.vert === AscFormat.nVertTTvert270 || oBodyPr.vert === AscFormat.nVertTTeaVert)) {
                        if (oGeometry) {
                            oWH = oGeometry.getNewWHByTextRect(oContentMetrics.w + l_ins + r_ins, oContentMetrics.contentH + t_ins + b_ins, undefined, bAutoFit ? undefined : this.extY);
                            if(!oWH.bError) {
                                this.extX = oWH.W;
                                this.extY = oWH.H;
                            }
                        }
                        else {
                            this.extX = oContentMetrics.w + l_ins + r_ins;
                            this.extY =  bAutoFit ?  oContentMetrics.contentH + t_ins + b_ins : this.extY;
                        }
                    }
                    else {
                        if (oGeometry) {
                            oWH = oGeometry.getNewWHByTextRect(oContentMetrics.contentH + l_ins + r_ins, oContentMetrics.w + t_ins + b_ins, bAutoFit ? undefined : this.extX);
                            if(!oWH.bError) {
                                this.extX = oWH.W;
                                this.extY = oWH.H;
                            }
                        }
                        else {
                            this.extY = oContentMetrics.w + t_ins + b_ins;
                            this.extX =  bAutoFit ? oContentMetrics.contentH + l_ins + r_ins : this.extX;
                        }
                    }
                }
            }
        }
        else {
            if (!oBodyPr.upright) {
                if (!(oBodyPr.vert === AscFormat.nVertTTvert || oBodyPr.vert === AscFormat.nVertTTvert270 || oBodyPr.vert === AscFormat.nVertTTeaVert)) {
                    if (oGeometry) {
                        oWH = oGeometry.getNewWHByTextRect(undefined, oContentMetrics.contentH + t_ins + b_ins, this.extX, undefined);
                        if(!oWH.bError) {
                            this.extY = oWH.H;
                        }
                    }
                    else {
                        this.extY = oContentMetrics.contentH + t_ins + b_ins;
                    }
                }
                else {
                    if (oGeometry) {
                        oWH = oGeometry.getNewWHByTextRect(oContentMetrics.contentH + l_ins + b_ins, undefined, undefined, this.extY);
                        if(!oWH.bError) {
                            this.extX = oWH.W;
                        }
                    }
                    else {
                        this.extX = oContentMetrics.contentH + l_ins + r_ins;
                    }
                }
            }
            else {
                var _full_rotate = this.getFullRotate();
                if (checkNormalRotate(_full_rotate)) {
                    if (!(oBodyPr.vert === AscFormat.nVertTTvert || oBodyPr.vert === AscFormat.nVertTTvert270 || oBodyPr.vert === AscFormat.nVertTTeaVert)) {
                        if (oGeometry) {
                            oWH = oGeometry.getNewWHByTextRect(undefined, oContentMetrics.contentH + t_ins + b_ins, this.extX, undefined);
                            if(!oWH.bError) {
                                this.extY = oWH.H;
                            }
                        }
                        else {
                            this.extY = oContentMetrics.contentH + t_ins + b_ins;
                        }
                    }
                    else {
                        if (oGeometry) {
                            oWH = oGeometry.getNewWHByTextRect(oContentMetrics.contentH + l_ins + r_ins, undefined, undefined, this.extY);
                            if(!oWH.bError) {
                                this.extX = oWH.W;
                            }
                        }
                        else {
                            this.extX = oContentMetrics.contentH + l_ins + r_ins;
                        }
                    }
                }
                else {
                    if (!(oBodyPr.vert === AscFormat.nVertTTvert || oBodyPr.vert === AscFormat.nVertTTvert270 || oBodyPr.vert === AscFormat.nVertTTeaVert)) {
                        if (oGeometry) {
                            oWH = oGeometry.getNewWHByTextRect(oContentMetrics.contentH + l_ins + r_ins, undefined, undefined, this.extY);
                            if(!oWH.bError) {
                                this.extX = oWH.W;
                            }
                        }
                        else {
                            this.extX = oContentMetrics.contentH + l_ins + r_ins;
                        }
                    }
                    else {
                        if (oGeometry) {
                            oWH = oGeometry.getNewWHByTextRect(undefined, oContentMetrics.contentH + t_ins + b_ins, this.extX, undefined);
                            if(!oWH.bError) {
                                this.extY = oWH.H;
                            }
                        }
                        else {
                            this.extY = oContentMetrics.contentH + t_ins + b_ins;
                        }
                    }
                }
            }
        }

        if(!this.bWordShape || this.group)//в презентациях и в таблицах изменям позицию: по горизонтали - в зависимости от выравнивания первого параграфа в контенте,
        // по вертикали - в зависимости от вертикального выравнивания контента.
        {
            var dSin = Math.sin(this.rot), dCos = Math.cos(this.rot);
            var oContent = this.getDocContent();
            var nJc, nAnchor;
            if(AscFormat.isRealNumber(this.rot) && !AscFormat.fApproxEqual(this.rot, 0))
            {
                nJc = AscCommon.align_Center;
                nAnchor = 1;
            }
            else
            {
                nJc = oContent.Content[0].CompiledPr.Pr.ParaPr.Jc;
                nAnchor = oBodyPr.anchor;
            }
            var FreezePointX, FreezePointY;
            switch(nJc)
            {
                case AscCommon.align_Right:
                {
                    dDeltaX = dOldExtX - this.extX;
                    FreezePointX = oContent.XLimit;
                    break;
                }
                case AscCommon.align_Left:
                {
                    dDeltaX = 0;
                    FreezePointX = 0;
                    break;
                }
                default:
                {
                    dDeltaX = (dOldExtX - this.extX)/2;
                    FreezePointX = oContent.XLimit/2.0;
                    break;
                }
            }

            switch (nAnchor)
            {
                case 0: //b
                {
                    dDeltaY = dOldExtY - this.extY;
                    FreezePointY = oContent.GetSummaryHeight();
                    break;
                }
                case 1:    //ctr
                case 2: //dist
                case 3: //just
                {// (Text Anchor Enum ( Center ))
                    dDeltaY = (dOldExtY - this.extY) / 2;
                    FreezePointY = oContent.GetSummaryHeight()/2.0;
                    break;
                }
                default:
                {
                    FreezePointY = 0.0;
                    break;
                }
            }
            // var tx1 = this.localTransformText.TransformPointX(FreezePointX, FreezePointY);
            // var ty1 = this.localTransformText.TransformPointY(FreezePointX, FreezePointY);
            // this.recalculateTransformText();
            // var tx2 = this.localTransformText.TransformPointX(FreezePointX, FreezePointY);
            // var ty2 = this.localTransformText.TransformPointY(FreezePointX, FreezePointY);


            var dTrDeltaX, dTrDeltaY;
            // if(this.invertTransform)
            // {
            //     var oInvMatrix = this.invertTransform.CreateDublicate();
            //     oInvMatrix.tx = 0.0;
            //     oInvMatrix.ty = 0.0;
            //     dTrDeltaX = oInvMatrix.TransformPointX(dDeltaX, dDeltaY);
            //     dTrDeltaY = oInvMatrix.TransformPointY(dDeltaX, dDeltaY);
            // }
            // else
            {
                dTrDeltaX = dDeltaX;
                dTrDeltaY = dDeltaY;
            }
            this.x += dTrDeltaX;
            this.y += dTrDeltaY;
        }
    }
    this.localX = this.x;
    this.localY = this.y;
    transform.Reset();
    var hc = this.extX * 0.5;
    var vc = this.extY * 0.5;
    global_MatrixTransformer.TranslateAppend(transform, -hc, -vc);
    if (this.flipH)
        global_MatrixTransformer.ScaleAppend(transform, -1, 1);
    if (this.flipV)
        global_MatrixTransformer.ScaleAppend(transform, 1, -1);
    global_MatrixTransformer.RotateRadAppend(transform, -this.rot);
    global_MatrixTransformer.TranslateAppend(transform, this.x + hc, this.y + vc);
    if (isRealObject(this.group)) {
        global_MatrixTransformer.MultiplyAppend(transform, this.group.getLocalTransform());
    }
    var oParaDrawing = getParaDrawing(this);
    if(oParaDrawing) {
        this.m_oSectPr = null;
        var oParentParagraph = oParaDrawing.Get_ParentParagraph();
        if (oParentParagraph) {
            var oSectPr = oParentParagraph.Get_SectPr();
            if(oSectPr)
            {
                this.m_oSectPr = new CSectionPr();
                this.m_oSectPr.Copy(oSectPr);
            }
        }
    }
    this.localTransform = transform;
    this.transform = transform;
};

CShape.prototype.CheckNeedRecalcAutoFit  = function(oSectPr)
{
    var Width, Height, Width2, Height2;
    var bRet = false;
    var oParaDrawing = getParaDrawing(this);
    var bSizRel = (oParaDrawing && (oParaDrawing.SizeRelH || oParaDrawing.SizeRelV));
    if(this.checkAutofit() || bSizRel )
    {
        if(oSectPr)
        {
            if(!this.m_oSectPr)
            {
                this.recalcBounds();
                this.recalcText();
                this.recalcGeometry();
                if(bSizRel)
                {
                    this.recalcTransform();
                }
                bRet = true;
            }
            else
            {

                Width = oSectPr.Get_PageWidth() - oSectPr.Get_PageMargin_Left() - oSectPr.Get_PageMargin_Right();
                Height = oSectPr.Get_PageHeight() - oSectPr.Get_PageMargin_Top() - oSectPr.Get_PageMargin_Bottom();

                Width2 = this.m_oSectPr.Get_PageWidth() - this.m_oSectPr.Get_PageMargin_Left() - this.m_oSectPr.Get_PageMargin_Right();
                Height2 = this.m_oSectPr.Get_PageHeight() - this.m_oSectPr.Get_PageMargin_Top() - this.m_oSectPr.Get_PageMargin_Bottom();
                bRet = (Math.abs(Width - Width2) > 0.001 || Math.abs(Height - Height2) > 0.001);
                if(bRet)
                {
                    this.recalcBounds();
                    this.recalcText();
                    this.recalcGeometry();
                    if(bSizRel)
                    {
                        this.recalcTransform();
                    }
                }
                return bRet;
            }
        }
        else
        {
            if(this.m_oSectPr)
            {
                this.recalcBounds();
                this.recalcText();
                this.recalcGeometry();
                bRet = true;
            }
        }
    }
    return bRet;
};


CShape.prototype.recalculateDocContent = function(oDocContent, oBodyPr)
{
    var nStartPage = this.Get_AbsolutePage ? this.Get_AbsolutePage() : 0;
    var oRet = {w: 0, h: 0, contentH: 0};
    var l_ins, t_ins, r_ins, b_ins;
    if(oBodyPr)
    {
        l_ins = AscFormat.isRealNumber(oBodyPr.lIns) ? oBodyPr.lIns : 2.54;
        r_ins = AscFormat.isRealNumber(oBodyPr.rIns) ? oBodyPr.rIns : 2.54;
        t_ins = AscFormat.isRealNumber(oBodyPr.tIns) ? oBodyPr.tIns : 1.27;
        b_ins = AscFormat.isRealNumber(oBodyPr.bIns) ? oBodyPr.bIns : 1.27;
    }
    else
    {
        l_ins = 2.54;
        r_ins = 2.54;
        t_ins = 1.27;
        b_ins = 1.27;
    }
    if(this.bWordShape)
    {
        var oPen = this.pen;
        if(oPen)
        {
            var penW = (oPen.w == null) ? 12700 : parseInt(oPen.w);
            penW /= 36000.0;
           switch (oPen.algn)
           {
               case 1:
               {
                   break;
               }
               default:
               {
                   penW/=2.0;
                   break;
               }
           }

            l_ins += penW;
            r_ins += penW;
            t_ins += penW;
            b_ins += penW;
        }
    }
    var oRect = this.getTextRect();
    var w, h;
    w = oRect.r - oRect.l - (l_ins + r_ins);
    h = oRect.b - oRect.t - (t_ins + b_ins);
    if(oBodyPr.wrap === AscFormat.nTWTNone)
    {
        var dMaxWidth = 100000;
        if(this.bWordShape)
        {
            this.m_oSectPr = null;
            var oParaDrawing = getParaDrawing(this);
            if(oParaDrawing)
            {
                var oParentParagraph = oParaDrawing.Get_ParentParagraph();
                if(oParentParagraph)
                {
                    var oSectPr = oParentParagraph.Get_SectPr();
                    if(oSectPr)
                    {
                        if(!(oBodyPr.vert === AscFormat.nVertTTvert || oBodyPr.vert === AscFormat.nVertTTvert270 || oBodyPr.vert === AscFormat.nVertTTeaVert))
                        {
                            dMaxWidth = oSectPr.Get_PageWidth() - oSectPr.Get_PageMargin_Left() - oSectPr.Get_PageMargin_Right() - l_ins - r_ins;
                        }
                        else
                        {
                            dMaxWidth = oSectPr.Get_PageHeight() - oSectPr.Get_PageMargin_Top() - oSectPr.Get_PageMargin_Bottom();
                        }
                        this.m_oSectPr = new CSectionPr();
                        this.m_oSectPr.Copy(oSectPr);
                    }
                }
            }
        }
        var dMaxWidthRec = RecalculateDocContentByMaxLine(oDocContent, dMaxWidth, this.bWordShape);
        if(!(oBodyPr.vert === AscFormat.nVertTTvert || oBodyPr.vert === AscFormat.nVertTTvert270 || oBodyPr.vert === AscFormat.nVertTTeaVert))
        {
            if(dMaxWidthRec < w && (!this.bWordShape && !this.bCheckAutoFitFlag))
            {
                oDocContent.RecalculateContent(w, h, nStartPage);
                oRet.w = w + 0.001;
                oRet.contentH = oDocContent.GetSummaryHeight();
                oRet.h = oRet.contentH;
            }
            else
            {
                oDocContent.RecalculateContent(dMaxWidthRec, h, nStartPage);
                oRet.w = dMaxWidthRec + 0.001;
                oRet.contentH = oDocContent.GetSummaryHeight();
                oRet.h = oRet.contentH;
            }
            oRet.correctW = l_ins + r_ins;
            oRet.correctH = t_ins + b_ins;
            oRet.textRectW = w;
            oRet.textRectH = h;
        }
        else
        {
            if(dMaxWidthRec < h && !this.bWordShape)
            {
                oDocContent.RecalculateContent( h, h, nStartPage);
                oRet.w = h + 0.001;
                oRet.contentH = oDocContent.GetSummaryHeight();
                oRet.h = oRet.contentH;
            }
            else
            {
                oDocContent.RecalculateContent(dMaxWidthRec, h, nStartPage);
                oRet.w = dMaxWidthRec + 0.001;
                oRet.contentH = oDocContent.GetSummaryHeight();
                oRet.h = oRet.contentH;
            }
            oRet.correctW = t_ins + b_ins;
            oRet.correctH = l_ins + r_ins;
            oRet.textRectW = h;
            oRet.textRectH = w;
        }
    }
    else//AscFormat.nTWTSquare
    {
        if(!oBodyPr.upright)
        {
            if(!(oBodyPr.vert === AscFormat.nVertTTvert || oBodyPr.vert === AscFormat.nVertTTvert270 || oBodyPr.vert === AscFormat.nVertTTeaVert))
            {
                oRet.w = w + 0.001;
                oRet.h = h + 0.001;
                oRet.correctW = l_ins + r_ins;
                oRet.correctH = t_ins + b_ins;
            }
            else
            {
                oRet.w = h + 0.001;
                oRet.h = w + 0.001;
                oRet.correctW = t_ins + b_ins;
                oRet.correctH = l_ins + r_ins;
            }
        }
        else
        {
            var _full_rotate = this.getFullRotate();
            if(checkNormalRotate(_full_rotate))
            {
                if(!(oBodyPr.vert === AscFormat.nVertTTvert || oBodyPr.vert === AscFormat.nVertTTvert270 || oBodyPr.vert === AscFormat.nVertTTeaVert))
                {
                    oRet.w = w + 0.001;
                    oRet.h = h + 0.001;
                    oRet.correctW = l_ins + r_ins;
                    oRet.correctH = t_ins + b_ins;
                }
                else
                {
                    oRet.w = h + 0.001;
                    oRet.h = w + 0.001;
                    oRet.correctW = t_ins + b_ins;
                    oRet.correctH = l_ins + r_ins;
                }
            }
            else
            {
                if(!(oBodyPr.vert === AscFormat.nVertTTvert || oBodyPr.vert === AscFormat.nVertTTvert270 || oBodyPr.vert === AscFormat.nVertTTeaVert))
                {
                    oRet.w = h + 0.001;
                    oRet.h = w + 0.001;
                    oRet.correctW = t_ins + b_ins;
                    oRet.correctH = l_ins + r_ins;
                }
                else
                {
                    oRet.w = w + 0.001;
                    oRet.h = h + 0.001;
                    oRet.correctW = l_ins + r_ins;
                    oRet.correctH = t_ins + b_ins;
                }
            }
        }
        oRet.textRectW = oRet.w;
        oRet.textRectH = oRet.h;

        //oDocContent.Set_StartPage(0);
        /*oDocContent.Reset(0, 0, oRet.w, 20000);
        var CurPage = 0;
        var RecalcResult = recalcresult2_NextPage;
        while ( recalcresult2_End !== RecalcResult  )
            RecalcResult = oDocContent.Recalculate_Page( CurPage++, true );*/

        oDocContent.RecalculateContent(oRet.w, oRet.h, nStartPage);

        oRet.contentH = oDocContent.GetSummaryHeight();

        if(this.bWordShape)
        {
            this.m_oSectPr = null;
            var oParaDrawing = getParaDrawing(this);
            if(oParaDrawing)
            {
                var oParentParagraph = oParaDrawing.Get_ParentParagraph();
                if(oParentParagraph)
                {
                    var oSectPr = oParentParagraph.Get_SectPr();
                    if(oSectPr)
                    {
                        this.m_oSectPr = new CSectionPr();
                        this.m_oSectPr.Copy(oSectPr);
                    }
                }
            }
        }
    }
    return oRet;
};

CShape.prototype.checkExtentsByDocContent = function(bForce, bNeedRecalc)
{
    if((!this.bWordShape || this.group || bForce) && this.checkAutofit(true))
    {
        var oMainGroup = this.getMainGroup();
        if(oMainGroup && !(bNeedRecalc === false))
        {
            oMainGroup.normalize();
        }
        this.bCheckAutoFitFlag = true;
        var oOldRecalcTitle = this.recalcInfo.recalcTitle;
        var bOldRecalcTitle = this.recalcInfo.bRecalculatedTitle;
        this.handleUpdateExtents();
        this.recalcInfo.bRecalculatedTitle = false;
        this.recalcInfo.recalcTitle = this;
        this.recalculate();
        this.bCheckAutoFitFlag = false;
        this.recalcInfo.recalcTitle =  oOldRecalcTitle;
        this.recalcInfo.bRecalculatedTitle =  bOldRecalcTitle;
        AscFormat.CheckSpPrXfrm(this, true);
        this.spPr.xfrm.setExtX(this.extX + 0.001);
        this.spPr.xfrm.setExtY(this.extY + 0.001);
        if(!this.bWordShape || this.group)
        {
            this.spPr.xfrm.setOffX(this.x);
            this.spPr.xfrm.setOffY(this.y);
            if(this.drawingBase)
            {
                CheckExcelDrawingXfrm(this.spPr.xfrm);
            }
        }
        if(!(bNeedRecalc === false))
        {
            if(oMainGroup)
            {
                oMainGroup.updateCoordinatesAfterInternalResize();
                if(oMainGroup.parent && oMainGroup.parent.CheckWH)
                {
                    oMainGroup.parent.CheckWH();
                    if(this.bWordShape)
                    {
                        editor.WordControl.m_oLogicDocument.Recalculate();
                    }
                }
            }
            else
            {
                this.checkDrawingBaseCoords();
            }
        }
        return true;
    }
    return false;
};


CShape.prototype.getTransformMatrix = function ()
{
    return this.transform;
};

CShape.prototype.getTransform = function () {

    return { x: this.x, y: this.y, extX: this.extX, extY: this.extY, rot: this.rot, flipH: this.flipH, flipV: this.flipV };
};

CShape.prototype.getAngle = function (x, y) {
    var px = this.invertTransform.TransformPointX(x, y);
    var py = this.invertTransform.TransformPointY(x, y);
    return Math.PI * 0.5 + Math.atan2(px - this.extX * 0.5, py - this.extY * 0.5);
};


CShape.prototype.recalculateGeometry = function () {
    if (this.spPr && isRealObject(this.spPr.geometry)) {
        var transform = this.getTransform();
        this.spPr.geometry.Recalculate(transform.extX, transform.extY);
    }
};
CShape.prototype.drawAdjustments = function (drawingDocument) {
    if (this.spPr && isRealObject(this.spPr.geometry)) {
        this.spPr.geometry.drawAdjustments(drawingDocument, this.transform, false);
    }
    if(this.recalcInfo.warpGeometry)
    {
        this.recalcInfo.warpGeometry.drawAdjustments(drawingDocument, this.transformTextWordArt, true);
    }
};

CShape.prototype.getHandlePosByIndex = function(numHandle){
    var t = this.transform;
    switch (numHandle){
        case 0:
            return { x: t.TransformPointX(0, 0), y: t.TransformPointY(0, 0) };
        case 1:
            return { x: t.TransformPointX(this.extX/2.0, 0), y: t.TransformPointY(this.extX/2.0, 0) };
        case 2:
            return { x: t.TransformPointX(this.extX, 0), y: t.TransformPointY(this.extX, 0) };
        case 3:
            return { x: t.TransformPointX(this.extX, this.extY/2.0), y: t.TransformPointY(this.extX, this.extY/2.0) };
        case 4:
            return { x: t.TransformPointX(this.extX, this.extY), y: t.TransformPointY(this.extX, this.extY) };
        case 5:
            return { x: t.TransformPointX(this.extX/2.0, this.extY), y: t.TransformPointY(this.extX/2.0, this.extY) };
        case 6:
            return { x: t.TransformPointX(0, this.extY), y: t.TransformPointY(0, this.extY) };
        case 7:
            return { x: t.TransformPointX(0, this.extY/2.0), y: t.TransformPointY(0, 0) };
        default:
    }
};

CShape.prototype.select = function (drawingObjectsController, pageIndex)
{
    this.selected = true;
    this.selectStartPage = pageIndex;
    var content = this.getDocContent && this.getDocContent();
    if(content)
        content.Set_StartPage(pageIndex);
    var selected_objects;
    if (!isRealObject(this.group))
        selected_objects = drawingObjectsController.selectedObjects;
    else
        selected_objects = this.group.getMainGroup().selectedObjects;
    for (var i = 0; i < selected_objects.length; ++i) {
        if (selected_objects[i] === this)
            break;
    }
    if (i === selected_objects.length)
        selected_objects.push(this);
};

CShape.prototype.deselect = function (drawingObjectsController) {
    this.selected = false;
    this.addTextFlag = false;
    var selected_objects;
    if (!isRealObject(this.group))
        selected_objects = drawingObjectsController.selectedObjects;
    else
        selected_objects = this.group.getMainGroup().selectedObjects;
    for (var i = 0; i < selected_objects.length; ++i) {
        if (selected_objects[i] === this) {
            selected_objects.splice(i, 1);
            break;
        }
    }
    if(this.graphicObject)
    {
        this.graphicObject.RemoveSelection();
    }
    return this;
};

CShape.prototype.getGroupHierarchy = function () {
    if (this.recalcInfo.recalculateGroupHierarchy) {
        this.groupHierarchy = [];
        if (isRealObject(this.group)) {
            var parent_group_hierarchy = this.group.getGroupHierarchy();
            for (var i = 0; i < parent_group_hierarchy.length; ++i) {
                this.groupHierarchy.push(parent_group_hierarchy[i]);
            }
            this.groupHierarchy.push(this.group);
        }
        this.recalcInfo.recalculateGroupHierarchy = false;
    }
    return this.groupHierarchy;
};



CShape.prototype.hitInTextRectWord = function(x, y)
{

    var content = this.getDocContent && this.getDocContent();
    if (content && this.invertTransform)
    {
        var t_x, t_y;
        t_x = this.invertTransform.TransformPointX(x, y);
        t_y = this.invertTransform.TransformPointY(x, y);

        var w, h, x_, y_;

        if(this.spPr && this.spPr.geometry && this.spPr.geometry.rect
            && AscFormat.isRealNumber(this.spPr.geometry.rect.l) && AscFormat.isRealNumber(this.spPr.geometry.rect.t)
            && AscFormat.isRealNumber(this.spPr.geometry.rect.r) && AscFormat.isRealNumber(this.spPr.geometry.rect.r))
        {
            x_ = this.spPr.geometry.rect.l;
            y_ = this.spPr.geometry.rect.t;
            w = this.spPr.geometry.rect.r - this.spPr.geometry.rect.l;
            h = this.spPr.geometry.rect.b - this.spPr.geometry.rect.t;
        }
        else
        {
            x_ = 0;
            y_ = 0;
            w = this.extX ;
            h = this.extY ;
        }
        return t_x > x_  && t_x < x_ + w && t_y > y_ && t_y < y_ + h;
    }
    return false;
};


CShape.prototype.hitInTextRect = function (x, y) {
    var oController = this.getDrawingObjectsController && this.getDrawingObjectsController();
    if(this.parent && this.parent.kind === AscFormat.TYPE_KIND.NOTES){
        return true;
    }


    var bForceWord = ((this.isEmptyPlaceholder && this.isEmptyPlaceholder()) || (this.isPlaceholder && this.isPlaceholder() && oController && (AscFormat.getTargetTextObject(oController) === this)));
    if(bForceWord){
        if(this.hitInTextRectWord(x, y)){
            return true;
        }
    }
    if(!this.txWarpStruct || !this.recalcInfo.warpGeometry ||
        this.recalcInfo.warpGeometry.preset === "textNoShape" ||
        oController && (AscFormat.getTargetTextObject(oController) === this || (oController.curState.startTargetTextObject === this)))
    {
        var content = this.getDocContent && this.getDocContent();
        if ( content && this.invertTransformText)
        {
            var t_x, t_y;
            t_x = this.invertTransformText.TransformPointX(x, y);
            t_y = this.invertTransformText.TransformPointY(x, y);
            return t_x > 0 && t_x < this.contentWidth && t_y > 0 && t_y < this.contentHeight;
        }
    }
    else
    {
        return this.hitInTextRectWord(x, y);
    }

    return false;
};


CShape.prototype.updateCursorType = function (x, y, e)
{
    if(this.invertTransformText)
    {
        var tx = this.invertTransformText.TransformPointX(x, y);
        var ty = this.invertTransformText.TransformPointY(x, y);
        this.txBody.content.UpdateCursorType(tx, ty, 0);
    }
};



CShape.prototype.selectionSetStart = function (e, x, y, slideIndex)
{
    var content = this.getDocContent();
    if (isRealObject(content))
    {
        var tx, ty;
        tx = this.invertTransformText.TransformPointX(x, y);
        ty = this.invertTransformText.TransformPointY(x, y);
        if(e.Button === AscCommon.g_mouse_button_right)
        {
            if(content.CheckPosInSelection(tx, ty,  0))
            {
                this.rightButtonFlag = true;
                return;
            }
        }
        if(!(/*content.IsTextSelectionUse() && */e.ShiftKey))
            content.Selection_SetStart(tx, ty, slideIndex - content.Get_StartPage_Relative(), e);
        else
        {
            if(!content.IsTextSelectionUse()){
                content.StartSelectionFromCurPos();
            }
            content.Selection_SetEnd(tx, ty, slideIndex - content.Get_StartPage_Relative(), e);
        }
    }
};

CShape.prototype.selectionSetEnd = function (e, x, y, slideIndex)
{
    var content = this.getDocContent();
    if (isRealObject(content)) {
        var tx, ty;
        tx = this.invertTransformText.TransformPointX(x, y);
        ty = this.invertTransformText.TransformPointY(x, y);
        if(!(e.Type === AscCommon.g_mouse_event_type_up && this.rightButtonFlag))
        {
            content.Selection_SetEnd(tx, ty, slideIndex - content.Get_StartPage_Relative(), e);
        }
    }
    delete this.rightButtonFlag;
};

CShape.prototype.Get_Theme = function()
{
    return this.getParentObjects().theme;
};

CShape.prototype.updateSelectionState = function ()
{
    var drawing_document = this.getDrawingDocument();
    if(drawing_document)
    {
        var content = this.getDocContent();
        if(content)
        {
            var oMatrix = null;
            if(this.transformText)
            {
                oMatrix = this.transformText.CreateDublicate();
            }
            drawing_document.UpdateTargetTransform(oMatrix);
            if ( true === content.IsSelectionUse() )
            {
                // Выделение нумерации
                if ( selectionflag_Numbering == content.Selection.Flag )
                {
                    drawing_document.TargetEnd();
                    drawing_document.SelectEnabled(true);
                    drawing_document.SelectClear();
                    drawing_document.SelectShow();
                }
                // Обрабатываем движение границы у таблиц
                else if ( null != content.Selection.Data && true === content.Selection.Data.TableBorder && type_Table == content.Content[content.Selection.Data.Pos].GetType() )
                {
                    // Убираем курсор, если он был
                    drawing_document.TargetEnd();
                }
                else
                {
                    if ( false === content.IsSelectionEmpty() )
                    {
                        drawing_document.TargetEnd();
                        drawing_document.SelectEnabled(true);
                        drawing_document.SelectClear();
                        drawing_document.SelectShow();
                    }
                    else
                    {
                        if (true !== content.Selection.Start)
                        {
                            content.RemoveSelection();
                        }
                        drawing_document.SelectEnabled(false);
                        content.RecalculateCurPos();

                        drawing_document.TargetStart();
                        drawing_document.TargetShow();
                    }
                }
            }
            else
            {
                drawing_document.SelectEnabled(false);
                content.RecalculateCurPos();

                drawing_document.TargetStart();
                drawing_document.TargetShow();
            }
        }
        else
        {
            drawing_document.UpdateTargetTransform(new CMatrix());
            drawing_document.TargetEnd();
            drawing_document.SelectEnabled(false);
            drawing_document.SelectClear();
            drawing_document.SelectShow();
        }
    }
};

CShape.prototype.check_bounds = function (checker) {
    if (this.spPr && this.spPr.geometry) {
        this.spPr.geometry.check_bounds(checker);
    }
    else {
        checker._s();
        checker._m(0, 0);
        checker._l(this.extX, 0);
        checker._l(this.extX, this.extY);
        checker._l(0, this.extY);
        checker._z();
        checker._e();
    }
};

CShape.prototype.getBase64Img = function ()
{
    if(typeof this.cachedImage === "string")
    {
        return this.cachedImage;
    }
    if(!AscFormat.isRealNumber(this.x) || !AscFormat.isRealNumber(this.y) || !AscFormat.isRealNumber(this.extX) || !AscFormat.isRealNumber(this.extY)
    || (AscFormat.fApproxEqual(this.extX, 0) && AscFormat.fApproxEqual(this.extY, 0)))
        return "";
    var img_object = AscCommon.ShapeToImageConverter(this, this.pageIndex);
    if(img_object)
    {
        if(img_object.ImageNative)
        {
            try
            {
                this.cachedPixW = img_object.ImageNative.width;
                this.cachedPixH = img_object.ImageNative.height;
            }
            catch(e)
            {
                this.cachedPixW = 50;
                this.cachedPixH = 50;
            }
        }
        return img_object.ImageUrl;
    }
    else
    {

        return "";
    }
};

CShape.prototype.haveSelectedDrawingInContent = function()
{
    if(this.bWordShape)
    {
        var aAllDrawings = this.recalcInfo.AllDrawings;
        for(var i = 0; i < aAllDrawings.length; ++i)
        {
            if(aAllDrawings[i] && aAllDrawings[i].GraphicObj && aAllDrawings[i].GraphicObj.selected)
            {
                return true;
            }
        }
    }
    return false;
};


CShape.prototype.clipTextRect = function(graphics)
{
    if(this.clipRect)
    {
        var clip_rect = this.clipRect;
        var oBodyPr = this.getBodyPr();
        if(!this.bWordShape)
        {
            if(oBodyPr.vertOverflow === AscFormat.nOTOwerflow)
            {
                return;
            }
        }
        if(!oBodyPr || !oBodyPr.upright)
        {
            graphics.transform3(this.transform);
            graphics.AddClipRect(clip_rect.x, clip_rect.y, clip_rect.w, clip_rect.h);

            graphics.SetIntegerGrid(false);
            graphics.transform3(this.transformText, true);
        }
        else
        {
            var oTransform = new CMatrix();
            var cX = this.transform.TransformPointX(this.extX/2, this.extY/2);
            var cY = this.transform.TransformPointY(this.extX/2, this.extY/2);

            if(checkNormalRotate(this.rot))
            {
                oTransform.tx = cX - this.extX/2;
                oTransform.ty = cY - this.extY/2;
            }
            else
            {
                global_MatrixTransformer.TranslateAppend(oTransform, - this.extX/2, -this.extY/2);
                global_MatrixTransformer.RotateRadAppend(oTransform, Math.PI/2);
                global_MatrixTransformer.TranslateAppend(oTransform, cX, cY);
            }
            graphics.transform3(oTransform, true);
            graphics.AddClipRect(clip_rect.x, clip_rect.y, clip_rect.w, clip_rect.h);

            graphics.SetIntegerGrid(false);
            graphics.transform3(this.transformText, true);
        }
    }
};

CShape.prototype.draw = function (graphics, transform, transformText, pageIndex) {

    if(this.checkNeedRecalculate && this.checkNeedRecalculate()){
        return;
    }

    if(graphics.updatedRect && this.bounds)
    {
        var rect = graphics.updatedRect;
        var bounds = this.bounds;
        if(bounds.x > rect.x + rect.w
            || bounds.y > rect.y + rect.h
            || bounds.x + bounds.w < rect.x
            || bounds.y + bounds.h < rect.y)
            return;
    }


    var _transform = transform ? transform : this.transform;
    var _transform_text = transformText ? transformText : this.transformText;
    var geometry = this.calcGeometry || this.spPr && this.spPr.geometry;
    if (graphics.IsSlideBoundsCheckerType === true) {
        graphics.transform3(_transform);
        if (!this.spPr || null == geometry || geometry.pathLst.length === 0 || (geometry.pathLst.length === 1 && geometry.pathLst[0].ArrPathCommandInfo.length === 0) || !graphics.IsShapeNeedBounds(geometry.preset)) {
            graphics._s();
            graphics._m(0, 0);
            graphics._l(this.extX, 0);
            graphics._l(this.extX, this.extY);
            graphics._l(0, this.extY);
            graphics._e();
        }
        else {
            geometry.check_bounds(graphics);
        }

        if (this.txBody) {
            graphics.SetIntegerGrid(false);

            var transform_text;
            if ((!this.txBody.content || this.txBody.content.Is_Empty()) && this.txBody.content2 != null && !this.txBody.checkCurrentPlaceholder() && (this.isEmptyPlaceholder ? this.isEmptyPlaceholder() : false) && this.transformText2) {
                transform_text = this.transformText2;
            }
            else if (this.txBody.content) {
                transform_text = _transform_text;
            }

            graphics.transform3(transform_text);

            if (graphics.CheckUseFonts2 !== undefined)
                graphics.CheckUseFonts2(transform_text);
            this.txBody.draw(graphics);
            if (graphics.UncheckUseFonts2 !== undefined)
                graphics.UncheckUseFonts2(transform_text);
            graphics.SetIntegerGrid(true);
        }

        graphics.reset();
        return;
    }


    var _oldBrush = this.brush;
    if(this.signatureLine){
        var sSignatureUrl = null;

		var _editor = window["Asc"]["editor"] ? window["Asc"]["editor"] : window.editor;
        if(_editor){
            sSignatureUrl = _editor.asc_getSignatureImage(this.signatureLine.id);
        }
        if(typeof sSignatureUrl === "string" && sSignatureUrl.length > 0){
            this.brush = AscFormat.CreateBlipFillUniFillFromUrl(sSignatureUrl);
        }
    }
    if (geometry || this.style || (this.brush && this.brush.fill) || (this.pen && this.pen.Fill && this.pen.Fill.fill)) {
        graphics.SetIntegerGrid(false);
        graphics.transform3(_transform, false);

        var shape_drawer = new AscCommon.CShapeDrawer();
        shape_drawer.fromShape2(this, graphics, geometry);
        shape_drawer.draw(geometry);
    }
    if (!this.bWordShape && this.isEmptyPlaceholder() && !(this.pen && this.pen.Fill && this.pen.Fill.fill) && graphics.IsNoDrawingEmptyPlaceholder !== true  && !AscCommon.IsShapeToImageConverter)
    {
        var drawingObjects = this.getDrawingObjectsController();
        if (typeof editor !== "undefined" && editor && graphics.m_oContext !== undefined && graphics.m_oContext !== null && graphics.IsTrack === undefined && (!drawingObjects || AscFormat.getTargetTextObject(drawingObjects) !== this ))
        {
            var angle = _transform.GetRotation();
            if (AscFormat.fApproxEqual(angle, 0.0, 0.0) ||
                AscFormat.fApproxEqual(angle, 90.0, 0.0) ||
                AscFormat.fApproxEqual(angle, 180.0, 0.0) ||
                AscFormat.fApproxEqual(angle, 270.0, 0.0))
            {
                graphics.transform3(_transform, false);
                var tr = graphics.m_oFullTransform;
                graphics.SetIntegerGrid(true);

                var _x = tr.TransformPointX(0, 0);
                var _y = tr.TransformPointY(0, 0);
                var _r = tr.TransformPointX(this.extX, this.extY);
                var _b = tr.TransformPointY(this.extX, this.extY);

                var __x = Math.min(_x, _r);
                var __y = Math.min(_y, _b);
                var __r = Math.max(_x, _r);
                var __b = Math.max(_y, _b);
                graphics.m_oContext.lineWidth = 1;
                graphics.p_color(127, 127, 127, 255);

                graphics._s();
                editor.WordControl.m_oDrawingDocument.AutoShapesTrack.AddRectDashClever(graphics.m_oContext, __x >> 0, __y >> 0, __r >> 0, __b >> 0, 2, 2, true);
                graphics._s();
            }
            else {
                graphics.transform3(_transform, false);
                var tr = graphics.m_oFullTransform;
                graphics.SetIntegerGrid(true);

                var _r = this.extX;
                var _b = this.extY;

                var x1 = tr.TransformPointX(0, 0) >> 0;
                var y1 = tr.TransformPointY(0, 0) >> 0;

                var x2 = tr.TransformPointX(_r, 0) >> 0;
                var y2 = tr.TransformPointY(_r, 0) >> 0;

                var x3 = tr.TransformPointX(0, _b) >> 0;
                var y3 = tr.TransformPointY(0, _b) >> 0;

                var x4 = tr.TransformPointX(_r, _b) >> 0;
                var y4 = tr.TransformPointY(_r, _b) >> 0;

                graphics.m_oContext.lineWidth = 1;
                graphics.p_color(127, 127, 127, 255);

                graphics._s();
                editor.WordControl.m_oDrawingDocument.AutoShapesTrack.AddRectDash(graphics.m_oContext, x1, y1, x2, y2, x3, y3, x4, y4, 3, 1, true);
                graphics._s();
            }
        }
        else
        {
            graphics.SetIntegerGrid(false);
            graphics.p_width(70);
            graphics.transform3(_transform, false);
            graphics.p_color(0, 0, 0, 255);
            graphics._s();
            graphics._m(0, 0);
            graphics._l(this.extX, 0);
            graphics._l(this.extX, this.extY);
            graphics._l(0, this.extY);
            graphics._z();
            graphics.ds();

            graphics.SetIntegerGrid(true);
        }
    }
    this.brush = _oldBrush;
    var oController = this.getDrawingObjectsController && this.getDrawingObjectsController();
    if(!this.txWarpStruct && !this.txWarpStructParamarksNoTransform || (!this.txWarpStructParamarksNoTransform && oController && (AscFormat.getTargetTextObject(oController) === this) || (!this.txBody && !this.textBoxContent)) /*|| this.haveSelectedDrawingInContent()*/)
    {
        if (this.txBody)
        {
            graphics.SaveGrState();
            graphics.SetIntegerGrid(false);
            var transform_text;
            if ((!this.txBody.content || this.txBody.content.Is_Empty()) && !AscCommon.IsShapeToImageConverter && this.txBody.content2 != null && !this.txBody.checkCurrentPlaceholder() && (this.isEmptyPlaceholder ? this.isEmptyPlaceholder() : false) && this.transformText2)
            {
                transform_text = this.transformText2;
            }
            else if (this.txBody.content)
            {
                transform_text = _transform_text;
            }

            if(this instanceof CShape)
            {
                if(!(oController && (AscFormat.getTargetTextObject(oController) === this)))
                    this.clipTextRect(graphics);
            }
            graphics.transform3(transform_text, true);
            if (graphics.CheckUseFonts2 !== undefined)
                graphics.CheckUseFonts2(transform_text);

            graphics.SetIntegerGrid(true);
            this.txBody.draw(graphics);
            if (graphics.UncheckUseFonts2 !== undefined)
                graphics.UncheckUseFonts2(transform_text);
            graphics.RestoreGrState();
        }

        if(this.textBoxContent && !graphics.IsNoSupportTextDraw && this.transformText)
        {
            var old_start_page = this.textBoxContent.Get_StartPage_Relative();
            this.textBoxContent.Set_StartPage(pageIndex);

            graphics.SaveGrState();
            graphics.SetIntegerGrid(false);
            this.clipTextRect(graphics);
            var result_page_index = AscFormat.isRealNumber(graphics.shapePageIndex) ? graphics.shapePageIndex : old_start_page;

            if (graphics.CheckUseFonts2 !== undefined)
                graphics.CheckUseFonts2(this.transformText);

            if (AscCommon.IsShapeToImageConverter)
            {
                this.textBoxContent.Set_StartPage(0);
                result_page_index = 0;
            }


            this.textBoxContent.Set_StartPage(result_page_index);
            this.textBoxContent.Draw(result_page_index, graphics);

            if (graphics.UncheckUseFonts2 !== undefined)
                graphics.UncheckUseFonts2();

            this.textBoxContent.Set_StartPage(old_start_page);
            graphics.RestoreGrState();
        }
    }
    else
    {
        var oTheme = this.getParentObjects().theme;
        var oColorMap = this.Get_ColorMap();
        if(!this.bWordShape && (!this.txBody.content || this.txBody.content.Is_Empty()) && !AscCommon.IsShapeToImageConverter && this.txBody.content2 != null && !this.txBody.checkCurrentPlaceholder() && (this.isEmptyPlaceholder ? this.isEmptyPlaceholder() : false))
        {
            if (graphics.IsNoDrawingEmptyPlaceholder !== true && graphics.IsNoDrawingEmptyPlaceholderText !== true)
            {
                if(editor && editor.ShowParaMarks)
                {
                    this.txWarpStructParamarks2.draw(graphics, this.transformTextWordArt2, oTheme, oColorMap);
                }
                else
                {
                	if (this.txWarpStruct2)
                		this.txWarpStruct2.draw(graphics, this.transformTextWordArt2, oTheme, oColorMap);
                }
            }
        }
        else
        {

            var oContent = this.getDocContent();
            var result_page_index = AscFormat.isRealNumber(graphics.shapePageIndex) ? graphics.shapePageIndex : (oContent ? oContent.Get_StartPage_Relative() : 0);
            graphics.PageNum = result_page_index;
            var bNeedRestoreState = false;
            var bEditTextArt = isRealObject(oController) && (AscFormat.getTargetTextObject(oController) === this);
            if(this.bWordShape && this.clipRect /*&& (!this.bodyPr.prstTxWarp || this.bodyPr.prstTxWarp.preset === "textNoShape" || bEditTextArt)*/)
            {
                bNeedRestoreState = true;
                var clip_rect = this.clipRect;
                if(!this.bodyPr.upright)
                {
                    graphics.SaveGrState();
                    graphics.SetIntegerGrid(false);
                    graphics.transform3(this.transform);
                    graphics.AddClipRect(clip_rect.x, clip_rect.y, clip_rect.w, clip_rect.h);
                }
                else
                {
                    graphics.SaveGrState();
                    graphics.SetIntegerGrid(false);
                    graphics.transform3(this.transformText, true);
                    graphics.AddClipRect(clip_rect.x, clip_rect.y, clip_rect.w, clip_rect.h);
                }
            }

            var oTransform = this.transformTextWordArt;
            if(editor && editor.ShowParaMarks)
            {
                if(bEditTextArt && this.txWarpStructParamarksNoTransform)
                {
                    this.txWarpStructParamarksNoTransform.draw(graphics, this.transformText, oTheme, oColorMap);
                }
                else if(this.txWarpStructParamarks)
                {
                    this.txWarpStructParamarks.draw(graphics, oTransform, oTheme, oColorMap);
                    if(this.checkNeedRecalcDocContentForTxWarp(this.bodyPr))
                    {
                        if(this.txWarpStructParamarksNoTransform)
                        {
                            this.txWarpStructParamarksNoTransform.drawComments(graphics, undefined, oTransform);
                        }
                    }
                }
            }
            else
            {
                if(bEditTextArt && this.txWarpStructNoTransform)
                {
                    this.txWarpStructNoTransform.draw(graphics, this.transformText, oTheme, oColorMap);
                }
                else if(this.txWarpStruct)
                {
                    this.txWarpStruct.draw(graphics, oTransform, oTheme, oColorMap);
                    if(this.checkNeedRecalcDocContentForTxWarp(this.bodyPr))
                    {
                        if(this.txWarpStructNoTransform)
                        {
                            this.txWarpStructNoTransform.drawComments(graphics, undefined, oTransform);
                        }
                    }
                }
            }
            delete graphics.PageNum;
            if(bNeedRestoreState)
            {
                graphics.RestoreGrState();
            }
        }
    }
    this.drawLocks && this.drawLocks(_transform, graphics);
    graphics.SetIntegerGrid(true);
    graphics.reset();
};

    CShape.prototype.recalculateGeometry = function()
    {
        this.calcGeometry = null;
        if(isRealObject(this.spPr && this.spPr.geometry)){
            this.calcGeometry = this.spPr.geometry;
        }
        else{
            if(this.getHierarchy){
                var hierarchy = this.getHierarchy();
                for(var i = 0; i < hierarchy.length; ++i){
                    if(hierarchy[i] && hierarchy[i].spPr && hierarchy[i].spPr.geometry){
                        var _g = hierarchy[i].spPr.geometry;
                        this.calcGeometry = AscFormat.ExecuteNoHistory(function(){
                            var _r = _g.createDuplicate();
                            _r.setParent(this);
                            return _r;
                        }, this, []);
                        break;
                    }
                }
            }
        }
        if(isRealObject(this.calcGeometry))
        {
            var transform = this.getTransform();
            this.calcGeometry.Recalculate(transform.extX, transform.extY);
        }
    };

CShape.prototype.getRotateAngle = function (x, y) {
    var transform = this.getTransformMatrix();
    var rotate_distance = this.convertPixToMM(AscCommon.TRACK_DISTANCE_ROTATE);
    var hc = this.extX * 0.5;
    var vc = this.extY * 0.5;
    var xc_t = transform.TransformPointX(hc, vc);
    var yc_t = transform.TransformPointY(hc, vc);
    var rot_x_t = transform.TransformPointX(hc, -rotate_distance);
    var rot_y_t = transform.TransformPointY(hc, -rotate_distance);

    var invert_transform = this.getInvertTransform();
    var rel_x = invert_transform.TransformPointX(x, y);

    var v1_x, v1_y, v2_x, v2_y;
    v1_x = x - xc_t;
    v1_y = y - yc_t;

    v2_x = rot_x_t - xc_t;
    v2_y = rot_y_t - yc_t;

    var flip_h = this.getFullFlipH();
    var flip_v = this.getFullFlipV();
    var same_flip = flip_h && flip_v || !flip_h && !flip_v;
    var angle = rel_x > this.extX * 0.5 ? Math.atan2(Math.abs(v1_x * v2_y - v1_y * v2_x), v1_x * v2_x + v1_y * v2_y) : -Math.atan2(Math.abs(v1_x * v2_y - v1_y * v2_x), v1_x * v2_x + v1_y * v2_y);
    return same_flip ? angle : -angle;
};

CShape.prototype.getRectBounds = function () {
    var transform = this.getTransformMatrix();
    var w = this.extX;
    var h = this.extY;
    var rect_points = [{ x: 0, y: 0 }, { x: w, y: 0 }, { x: w, y: h }, { x: 0, y: h}];
    var min_x, max_x, min_y, max_y;
    min_x = transform.TransformPointX(rect_points[0].x, rect_points[0].y);
    min_y = transform.TransformPointY(rect_points[0].x, rect_points[0].y);
    max_x = min_x;
    max_y = min_y;
    var cur_x, cur_y;
    for (var i = 1; i < 4; ++i) {
        cur_x = transform.TransformPointX(rect_points[i].x, rect_points[i].y);
        cur_y = transform.TransformPointY(rect_points[i].x, rect_points[i].y);
        if (cur_x < min_x)
            min_x = cur_x;
        if (cur_x > max_x)
            max_x = cur_x;

        if (cur_y < min_y)
            min_y = cur_y;
        if (cur_y > max_y)
            max_y = cur_y;
    }
    return { minX: min_x, maxX: max_x, minY: min_y, maxY: max_y };
};

CShape.prototype.getInvertTransform = function ()
{
    return this.invertTransform ? this.invertTransform : new CMatrix();
};



CShape.prototype.getFullOffset = function () {
    if (!isRealObject(this.group))
        return { offX: this.x, offY: this.y };
    var group_offset = this.group.getFullOffset();
    return { offX: this.x + group_offset.offX, offY: this.y + group_offset.offY };
};




CShape.prototype.getTextArtProperties = function()
{
    var oContent = this.getDocContent(), oTextPr, oRet = null;
    if(oContent)
    {
        oRet = {Fill: undefined, Line: undefined, Form: undefined};
        var oController = this.getDrawingObjectsController();
       // if(oController)
        {
            //var oTargetDocContent = oController.getTargetDocContent();
            //if(oTargetDocContent === oContent)
            //{
            //    oTextPr = oContent.GetCalculatedTextPr();
            //}
            //else
            //{
            //    oContent.Set_ApplyToAll(true);
            //    oTextPr = oContent.GetCalculatedTextPr();
            //    oContent.Set_ApplyToAll(false);
            //}
            //if(oTextPr.TextFill)
            //{
            //    oRet.Fill = oTextPr.TextFill;
            //}
            //else if(oTextPr.Unifill)
            //{
            //    oRet.Fill = oTextPr.Unifill;
            //}
            //else if(oTextPr.Color)
            //{
            //    oRet.Fill = CreateUnfilFromRGB(oTextPr.Color.r, oTextPr.Color.g, oTextPr.Color.b);
            //}
            //oRet.Line = oTextPr.TextOutline;
            var oBodyPr = this.getBodyPr();
            if(oBodyPr && oBodyPr.prstTxWarp)
            {
                oRet.Form = oBodyPr.prstTxWarp.preset;
            }
            else
            {
                oRet.Form = "textNoShape";
            }
        }
    }
    return oRet;
};

CShape.prototype.applyTextArtForm = function(sPreset)
{
    var oBodyPr = this.getBodyPr().createDuplicate();
    oBodyPr.prstTxWarp = AscFormat.ExecuteNoHistory(function(){return AscFormat.CreatePrstTxWarpGeometry(sPreset)}, this, []);
    if(this.bWordShape)
    {
        this.setBodyPr(oBodyPr);
    }
    else
    {
        if(this.txBody)
        {
            this.txBody.setBodyPr(oBodyPr);
        }
    }
};

CShape.prototype.getParagraphParaPr = function () {
    if (this.txBody && this.txBody.content) {
        var _result;
        this.txBody.content.Set_ApplyToAll(true);
        _result = this.txBody.content.GetCalculatedParaPr();
        this.txBody.content.Set_ApplyToAll(false);
        return _result;
    }
    return null;
};

CShape.prototype.getParagraphTextPr = function () {
    if (this.txBody && this.txBody.content) {
        var _result;
        this.txBody.content.Set_ApplyToAll(true);
        _result = this.txBody.content.GetCalculatedTextPr();
        this.txBody.content.Set_ApplyToAll(false);
        return _result;
    }
    return null;
};

CShape.prototype.getAllRasterImages = function(images)
{
    if(this.spPr && this.spPr.Fill && this.spPr.Fill.fill && typeof (this.spPr.Fill.fill.RasterImageId) === "string" && this.spPr.Fill.fill.RasterImageId.length > 0)
        images.push(this.spPr.Fill.fill.RasterImageId);


    var compiled_style = this.getCompiledStyle();
    var parents = this.getParentObjects();
    if (isRealObject(parents.theme) && isRealObject(compiled_style) && isRealObject(compiled_style.fillRef))
    {
        var brush = parents.theme.getFillStyle(compiled_style.fillRef.idx, compiled_style.fillRef.Color);
        if(brush && brush.fill && typeof (brush.fill.RasterImageId) === "string" && brush.fill.RasterImageId.length > 0)
        {
            images.push(brush.fill.RasterImageId);
        }
    }
    var oContent = this.getDocContent();
    if(oContent)
    {
        if(this.bWordShape)
        {
            var drawings = oContent.GetAllDrawingObjects();
            for(var i = 0; i < drawings.length; ++i)
            {
                drawings[i].GraphicObj && drawings[i].GraphicObj.getAllRasterImages && drawings[i].GraphicObj.getAllRasterImages(images);
            }
        }
        var fCallback = function(oTextPr)
        {
            if( (oTextPr.Unifill && oTextPr.Unifill.fill && oTextPr.Unifill.fill.type == c_oAscFill.FILL_TYPE_BLIP))
            {
                images.push(oTextPr.Unifill.fill.RasterImageId);
            }
            return false;
        }
        this.checkContentByCallback(oContent, fCallback);
    }
};
CShape.prototype.getAllDocContents = function(aDocContents)
{
    if(this.textBoxContent){
        aDocContents.push(this.textBoxContent);
    }
};

CShape.prototype.changePresetGeom = function (sPreset) {


    if(sPreset === "textRect")
    {
        this.spPr.setGeometry(AscFormat.CreateGeometry("rect"));
        this.setStyle(AscFormat.CreateDefaultTextRectStyle());
        var fill = new AscFormat.CUniFill();
        fill.setFill(new AscFormat.CSolidFill());
        fill.fill.setColor(new AscFormat.CUniColor());
        fill.fill.color.setColor(new AscFormat.CSchemeColor());
        fill.fill.color.color.setId(12);
        this.spPr.setFill(fill);

        var ln = new AscFormat.CLn();
        ln.setW(6350);
        ln.setFill(new AscFormat.CUniFill());
        ln.Fill.setFill(new AscFormat.CSolidFill());
        ln.Fill.fill.setColor(new AscFormat.CUniColor());
        ln.Fill.fill.color.setColor(new AscFormat.CPrstColor());
        ln.Fill.fill.color.color.setId("black");
        this.spPr.setLn(ln);
        if(this.bWordShape)
        {
            if(!this.textBoxContent)
            {
                this.setTextBoxContent(new CDocumentContent(this, this.getDrawingDocument(), 0, 0, 0, 0, false, false, false));
                var body_pr = new AscFormat.CBodyPr();
                body_pr.setDefault();
                this.setBodyPr(body_pr);
            }
        }
        else
        {
            if(!this.txBody)
            {
                this.setTxBody(new AscFormat.CTextBody());
                var content = new AscFormat.CDrawingDocContent(this.txBody, this.getDrawingDocument(), 0, 0, 0, 0, false, false, true);
                this.txBody.setParent(this);
                this.txBody.setContent(content);
                var body_pr = new AscFormat.CBodyPr();
                body_pr.setDefault();
                this.txBody.setBodyPr(body_pr);
            }
        }
        return;
    }
    var _final_preset;
    var _old_line;
    var _new_line;


    if (this.spPr.ln == null) {
        _old_line = null;
    }
    else {
        _old_line = this.spPr.ln.createDuplicate();
    }
    switch (sPreset) {
        case "lineWithArrow":
        {
            _final_preset = "line";
            if (_old_line == null) {
                _new_line = new AscFormat.CLn();
            }
            else {
                _new_line = this.spPr.ln.createDuplicate();
            }
            _new_line.tailEnd = new AscFormat.EndArrow();
            _new_line.tailEnd.type = AscFormat.LineEndType.Arrow;
            _new_line.tailEnd.len = AscFormat.LineEndSize.Mid;
            _new_line.tailEnd.w = AscFormat.LineEndSize.Mid;
            break;
        }
        case "lineWithTwoArrows":
        {
            _final_preset = "line";
            if (_old_line == null) {
                _new_line = new AscFormat.CLn();

            }
            else {
                _new_line = this.spPr.ln.createDuplicate();
            }
            _new_line.tailEnd = new AscFormat.EndArrow();
            _new_line.tailEnd.type = AscFormat.LineEndType.Arrow;
            _new_line.tailEnd.len = AscFormat.LineEndSize.Mid;
            _new_line.tailEnd.w = AscFormat.LineEndSize.Mid;

            _new_line.headEnd = new AscFormat.EndArrow();
            _new_line.headEnd.type = AscFormat.LineEndType.Arrow;
            _new_line.headEnd.len = AscFormat.LineEndSize.Mid;
            _new_line.headEnd.w = AscFormat.LineEndSize.Mid;
            break;
        }
        case "bentConnector5WithArrow":
        {
            _final_preset = "bentConnector5";
            if (_old_line == null) {
                _new_line = new AscFormat.CLn();

            }
            else {
                _new_line = this.spPr.ln.createDuplicate();
            }
            _new_line.tailEnd = new AscFormat.EndArrow();
            _new_line.tailEnd.type = AscFormat.LineEndType.Arrow;
            _new_line.tailEnd.len = AscFormat.LineEndSize.Mid;
            _new_line.tailEnd.w = AscFormat.LineEndSize.Mid;
            break;
        }
        case "bentConnector5WithTwoArrows":
        {
            _final_preset = "bentConnector5";
            if (_old_line == null) {
                _new_line = new AscFormat.CLn();
            }
            else {
                _new_line = this.spPr.ln.createDuplicate();
            }
            _new_line.tailEnd = new AscFormat.EndArrow();
            _new_line.tailEnd.type = AscFormat.LineEndType.Arrow;
            _new_line.tailEnd.len = AscFormat.LineEndSize.Mid;
            _new_line.tailEnd.w = AscFormat.LineEndSize.Mid;

            _new_line.headEnd = new AscFormat.EndArrow();
            _new_line.headEnd.type = AscFormat.LineEndType.Arrow;
            _new_line.headEnd.len = AscFormat.LineEndSize.Mid;
            _new_line.headEnd.w = AscFormat.LineEndSize.Mid;
            break;
        }
        case "curvedConnector3WithArrow":
        {
            _final_preset = "curvedConnector3";
            if (_old_line == null) {
                _new_line = new AscFormat.CLn();
            }
            else {
                _new_line = this.spPr.ln.createDuplicate();
            }
            _new_line.tailEnd = new AscFormat.EndArrow();
            _new_line.tailEnd.type = AscFormat.LineEndType.Arrow;
            _new_line.tailEnd.len = AscFormat.LineEndSize.Mid;
            _new_line.tailEnd.w = AscFormat.LineEndSize.Mid;
            break;
        }
        case "curvedConnector3WithTwoArrows":
        {
            _final_preset = "curvedConnector3";
            if (_old_line == null) {
                _new_line = new AscFormat.CLn();

            }
            else {
                _new_line = this.spPr.ln.createDuplicate();
            }
            _new_line.tailEnd = new AscFormat.EndArrow();
            _new_line.tailEnd.type = AscFormat.LineEndType.Arrow;
            _new_line.tailEnd.len = AscFormat.LineEndSize.Mid;
            _new_line.tailEnd.w = AscFormat.LineEndSize.Mid;

            _new_line.headEnd = new AscFormat.EndArrow();
            _new_line.headEnd.type = AscFormat.LineEndType.Arrow;
            _new_line.headEnd.len = AscFormat.LineEndSize.Mid;
            _new_line.headEnd.w = AscFormat.LineEndSize.Mid;
            break;
        }
        default:
        {
            _final_preset = sPreset;
            if (_old_line == null) {
                _new_line = new AscFormat.CLn();
            }
            else {
                _new_line = this.spPr.ln.createDuplicate();
            }
            _new_line.tailEnd = null;

            _new_line.headEnd = null;
            break;
        }
    }
    if (_final_preset != null) {
        this.spPr.setGeometry(AscFormat.CreateGeometry(_final_preset));
    }
    else {
        this.spPr.setGeometry(null);
    }
    if(!this.bWordShape)
    {
        this.checkExtentsByDocContent();
    }
    if ((!this.brush || !this.brush.fill) && (!this.pen || !this.pen.Fill || !this.pen.Fill.fill)) {
        var new_line2 = new AscFormat.CLn();
        new_line2.Fill = new AscFormat.CUniFill();
        new_line2.Fill.fill = new AscFormat.CSolidFill();
        new_line2.Fill.fill.color = new AscFormat.CUniColor();
        new_line2.Fill.fill.color.color = new AscFormat.CSchemeColor();
        new_line2.Fill.fill.color.color.id = 0;
        if (isRealObject(_new_line)) {
            new_line2.merge(_new_line);
        }
        this.spPr.setLn(new_line2);
    }
    else
        this.spPr.setLn(_new_line);
};

CShape.prototype.changeFill = function (unifill) {

    if(this.recalcInfo.recalculateBrush)
    {
        this.recalculateBrush();
    }
    var unifill2 = AscFormat.CorrectUniFill(unifill, this.brush, this.getEditorType());
    unifill2.convertToPPTXMods();
    this.spPr.setFill(unifill2);
};
CShape.prototype.setFill = function (fill) {

    this.spPr.setFill(fill);
};

CShape.prototype.changeLine = function (line)
{
    if(this.recalcInfo.recalculatePen)
    {
        this.recalculatePen();
    }
    var stroke = AscFormat.CorrectUniStroke(line, this.pen);
    if(stroke.Fill)
    {
        stroke.Fill.convertToPPTXMods();
    }
    this.spPr.setLn(stroke);
};

CShape.prototype.hitToAdjustment = function (x, y) {
    var invert_transform = this.getInvertTransform();
    var t_x, t_y, ret;
    t_x = invert_transform.TransformPointX(x, y);
    t_y = invert_transform.TransformPointY(x, y);
    var _calcGeoem = this.calcGeometry || (this.spPr && this.spPr.geometry);
    if (_calcGeoem)
    {
        invert_transform = this.getInvertTransform();
        t_x = invert_transform.TransformPointX(x, y);
        t_y = invert_transform.TransformPointY(x, y);
        ret = _calcGeoem.hitToAdj(t_x, t_y, this.convertPixToMM(global_mouseEvent.KoefPixToMM * AscCommon.TRACK_CIRCLE_RADIUS));
        if(ret.hit)
        {
            ret.warp = false;
            return ret;
        }
    }
    if(this.recalcInfo.warpGeometry && this.invertTransformTextWordArt)
    {
        invert_transform = this.invertTransformTextWordArt;
        t_x = invert_transform.TransformPointX(x, y);
        t_y = invert_transform.TransformPointY(x, y);
        ret = this.recalcInfo.warpGeometry.hitToAdj(t_x, t_y, this.convertPixToMM(global_mouseEvent.KoefPixToMM * AscCommon.TRACK_CIRCLE_RADIUS));
        ret.warp = true;
        return ret;
    }

    return { hit: false, adjPolarFlag: null, adjNum: null, warp: false };
};

CShape.prototype.hitToHandles = function (x, y) {
    if(this.parent && this.parent.kind === AscFormat.TYPE_KIND.NOTES){
        return -1;
    }
    return hitToHandles(x, y, this);

};

CShape.prototype.hit = function (x, y) {
    return this.hitInInnerArea(x, y) || this.hitInPath(x, y) || this.hitInTextRect(x, y);
};

CShape.prototype.hitInPath = function (x, y) {
    if(!this.checkHitToBounds(x, y))
        return false;
    var invert_transform = this.getInvertTransform();
    var x_t = invert_transform.TransformPointX(x, y);
    var y_t = invert_transform.TransformPointY(x, y);
    if (isRealObject(this.spPr) && isRealObject(this.spPr.geometry))
        return this.spPr.geometry.hitInPath(this.getCanvasContext(), x_t, y_t);
    else
        return this.hitInBoundingRect(x, y);
    return false;
};

CShape.prototype.hitInInnerArea = function (x, y) {
    if ((this.getObjectType && this.getObjectType() === AscDFH.historyitem_type_ChartSpace || this.getObjectType() === AscDFH.historyitem_type_Title) || (this.brush != null && this.brush.fill != null
        && this.brush.fill.type != c_oAscFill.FILL_TYPE_NOFILL || this.blipFill) && this.checkHitToBounds(x, y)) {
        var invert_transform = this.getInvertTransform();
        var x_t = invert_transform.TransformPointX(x, y);
        var y_t = invert_transform.TransformPointY(x, y);
        if (isRealObject(this.spPr) && isRealObject(this.spPr.geometry) && this.spPr.geometry.pathLst.length > 0 && !(this.getObjectType && this.getObjectType() === AscDFH.historyitem_type_ChartSpace))
            return this.spPr.geometry.hitInInnerArea(this.getCanvasContext(), x_t, y_t);
        return x_t > 0 && x_t < this.extX && y_t > 0 && y_t < this.extY;
    }
    return false;
};

CShape.prototype.hitInBoundingRect = function (x, y) {
    if(this.parent && this.parent.kind === AscFormat.TYPE_KIND.NOTES){
        return false;
    }
    var invert_transform = this.getInvertTransform();
    var x_t = invert_transform.TransformPointX(x, y);
    var y_t = invert_transform.TransformPointY(x, y);

    var _hit_context = this.getCanvasContext();

    return !(CheckObjectLine(this)) && (HitInLine(_hit_context, x_t, y_t, 0, 0, this.extX, 0) ||
        HitInLine(_hit_context, x_t, y_t, this.extX, 0, this.extX, this.extY) ||
        HitInLine(_hit_context, x_t, y_t, this.extX, this.extY, 0, this.extY) ||
        HitInLine(_hit_context, x_t, y_t, 0, this.extY, 0, 0) ||
        (this.canRotate && this.canRotate() && HitInLine(_hit_context, x_t, y_t, this.extX * 0.5, 0, this.extX * 0.5, -this.convertPixToMM(AscCommon.TRACK_DISTANCE_ROTATE))));
};

CShape.prototype.canRotate = function () {
    return true;
};

CShape.prototype.canResize = function () {
    return true;
};

CShape.prototype.canMove = function () {
    return true; //TODO
};

CShape.prototype.canGroup = function () {
    return !this.isPlaceholder(); //TODO
};



CShape.prototype.canChangeAdjustments = function () {
    return true; //TODO
};

CShape.prototype.createRotateTrack = function () {
    return new AscFormat.RotateTrackShapeImage(this);
};

CShape.prototype.createResizeTrack = function (cardDirection, oController) {
    return new AscFormat.ResizeTrackShapeImage(this, cardDirection, oController);
};

CShape.prototype.createMoveTrack = function () {
    return new AscFormat.MoveShapeImageTrack(this);
};


CShape.prototype.remove = function (Count, bOnlyText, bRemoveOnlySelection) {
    if (this.txBody) {
        this.txBody.content.Remove(Count, bOnlyText, bRemoveOnlySelection);
        this.recalcInfo.recalculateContent = true;
        this.recalcInfo.recalculateTransformText = true;
    }
};


CShape.prototype.Restart_CheckSpelling = function()
{
    this.recalcInfo.recalculateShapeStyleForParagraph = true;
    var content = this.getDocContent();
    content && content.Restart_CheckSpelling();
};

CShape.prototype.Refresh_RecalcData = function (data)
{
    switch (data.Type)
    {
        case AscDFH.historyitem_AutoShapes_SetDrawingBaseCoors:
        {
            break;
        }
        case AscDFH.historyitem_AutoShapes_RemoveFromDrawingObjects:
        {
            break;
        }

        case AscDFH.historyitem_AutoShapes_AddToDrawingObjects:
        {
            break;
        }
        case AscDFH.historyitem_AutoShapes_SetWorksheet:
        {
            break;
        }
        case AscDFH.historyitem_ShapeSetBDeleted:
        {
            break;
        }
        case AscDFH.historyitem_ShapeSetNvSpPr:
        {
            break;
        }
        case AscDFH.historyitem_ShapeSetSpPr:
        {
            break;
        }
        case AscDFH.historyitem_ShapeSetStyle:
        {
            break;
        }
        case AscDFH.historyitem_ShapeSetTxBody:
        {
            this.Refresh_RecalcData2();
            break;
        }
        case AscDFH.historyitem_ShapeSetTextBoxContent:
        {
            this.Refresh_RecalcData2();
            break;
        }
        case AscDFH.historyitem_ShapeSetParent:
        {
            break;
        }
        case AscDFH.historyitem_ShapeSetGroup:
        {
            break;
        }
        case AscDFH.historyitem_ShapeSetBodyPr:
        {
            this.Refresh_RecalcData2();
            break;
        }
        case AscDFH.historyitem_ShapeSetWordShape:
        {
            break;
        }
        default:
        {
            this.Refresh_RecalcData2();
        }
    }
};

CShape.prototype.Refresh_RecalcData2 = function(pageIndex/*для текста*/)
{
    this.recalcContent();
    this.recalcContent2 && this.recalcContent2();
    this.recalcTransformText();
    this.addToRecalculate();
    var oController = this.getDrawingObjectsController();
    if(oController && AscFormat.getTargetTextObject(oController) === this)
    {
        this.recalcInfo.recalcTitle = this.getDocContent();
        this.recalcInfo.bRecalculatedTitle = true;
    }
};


CShape.prototype.Load_LinkData = function (linkData)
{
};

CShape.prototype.Get_PageContentStartPos = function(pageNum)
{
    if(this.textBoxContent)
    {
        if(this.spPr && this.spPr.geometry && this.spPr.geometry.rect)
        {
            var rect = this.spPr.geometry.rect;
            return {X: 0, Y: 0, XLimit: rect.r - rect.l, YLimit: 20000};
        }
        else
        {
            return {X: 0, Y: 0, XLimit: this.extX, YLimit: 20000};
        }
    }
    return null;
};

CShape.prototype.OnContentRecalculate = function()
{};

CShape.prototype.recalculateBounds = function()
{
    var boundsChecker = new  AscFormat.CSlideBoundsChecker();
    this.draw(boundsChecker, this.localTransform, this.localTransformText);
    this.bounds.l = boundsChecker.Bounds.min_x;
    this.bounds.t = boundsChecker.Bounds.min_y;
    this.bounds.r = boundsChecker.Bounds.max_x;
    this.bounds.b = boundsChecker.Bounds.max_y;

    this.bounds.x = this.bounds.l;
    this.bounds.y = this.bounds.t;
    this.bounds.w = this.bounds.r - this.bounds.l;
    this.bounds.h = this.bounds.b - this.bounds.t;
};

CShape.prototype.checkRunWordArtContent = function(aContent, fCallback)
{
    for(var j = 0; j < aContent.length; ++j)
    {
        if(aContent[j].Type === para_Run)
        {
            if(fCallback(aContent[j]))
            {
                return true;
            }
        }
        else if(aContent[j].Type === para_Hyperlink)
        {
            if(this.checkRunWordArtContent(aContent[j].Content, fCallback))
            {
                return true;
            }
        }
    }
    return false;
};

CShape.prototype.checkContentByCallback = function(oContent, fCallback)
{
    if(!oContent)
        return false;
    var i, j, k, oElement, aRows, oRow;
    for(i = 0; i < oContent.Content.length; ++i)
    {
        oElement = oContent.Content[i];
        if(oElement.Get_Type() === type_Paragraph)
        {
            if(this.checkRunWordArtContent(oElement.Content, fCallback))
            {
                return true;
            }
        }
        else if(oElement.Get_Type() === type_Table)
        {
            aRows = oElement.Content;
            for(j = 0; j < aRows.length; ++j)
            {
                oRow = aRows[j];
                for(k = 0; k < oRow.Content.length; ++k)
                {
                    if(this.checkContentByCallback(oRow.Content[k].Content, fCallback))
                    {
                        return true;
                    }
                }
            }
        }
    }
    return false;
};

CShape.prototype.checkContentWordArt = function(oContent)
{
    return this.checkContentByCallback(oContent, CheckWordArtTextPr);
};

CShape.prototype.checkNeedRecalcDocContentForTxWarp = function(oBodyPr)
{
    return oBodyPr && oBodyPr.prstTxWarp && (oBodyPr.prstTxWarp.pathLst.length / 2 - ((oBodyPr.prstTxWarp.pathLst.length / 2) >> 0) > 0);
};

CShape.prototype.chekBodyPrTransform = function(oBodyPr)
{
    return isRealObject(oBodyPr) && isRealObject(oBodyPr.prstTxWarp) && oBodyPr.prstTxWarp.preset !== "textNoShape";
};

CShape.prototype.checkTextWarp = function(oContent, oBodyPr, dWidth, dHeight, bNeedNoTransform, bNeedWarp)
{
    return AscFormat.ExecuteNoHistory(function(){
        var oRet = {oTxWarpStruct: null, oTxWarpStructParamarks: null, oTxWarpStructNoTransform: null, oTxWarpStructParamarksNoTransform: null};
        if(window["IS_NATIVE_EDITOR"]){
            return oRet;
        }
        //return oRet;
        var bTransform = this.chekBodyPrTransform(oBodyPr) && bNeedWarp;
        var warpGeometry = oBodyPr.prstTxWarp;
        warpGeometry && warpGeometry.Recalculate(dWidth, dHeight);
        this.recalcInfo.warpGeometry = warpGeometry;
        var bCheckWordArtContent = this.checkContentWordArt(oContent);
        var bColumns = oContent.Get_ColumnsCount() > 1;
        var bContentRecalculated = false;
        if(bTransform || bCheckWordArtContent)
        {
            var bNeedRecalc = this.checkNeedRecalcDocContentForTxWarp(oBodyPr), dOneLineWidth, dMinPolygonLength = 0, dKoeff = 1;
            var oTheme = this.Get_Theme(), oColorMap = this.Get_ColorMap();
            var oTextDrawer = new AscFormat.CTextDrawer(dWidth, dHeight, true, oTheme, bNeedRecalc);
            oTextDrawer.bCheckLines = bTransform && bNeedWarp;
            var oContentToDraw = oContent;
            if(bNeedRecalc && bNeedWarp)
            {
                oContentToDraw = oContent.Copy(oContent.Parent, oContent.DrawingDocument);
                var bNeedTurnOn = false;
                if(this.bWordShape && editor && editor.WordControl.m_oLogicDocument)
                {
                    if(!editor.WordControl.m_oLogicDocument.TurnOffRecalc)
                    {
                        bNeedTurnOn = true;
                        editor.WordControl.m_oLogicDocument.TurnOff_Recalculate();
                    }
                }
                oContentToDraw.Set_ApplyToAll(true);
                oContentToDraw.SetParagraphSpacing({Before: 0, After: 0});
                oContentToDraw.Set_ApplyToAll(false);
                if(bNeedTurnOn)
                {
                    editor.WordControl.m_oLogicDocument.TurnOn_Recalculate(false);
                }
                dMinPolygonLength = warpGeometry.getMinPathPolygonLength();
                dOneLineWidth = AscFormat.GetRectContentWidth(oContentToDraw);
                if(dOneLineWidth > dMinPolygonLength)
                {
                    dKoeff = dMinPolygonLength/dOneLineWidth;
                    oContentToDraw.Reset(0, 0, dOneLineWidth, 20000);
                }
                else
                {
                    oContentToDraw.Reset(0, 0, dMinPolygonLength, 20000);
                }
                oContentToDraw.Recalculate_Page(0, true);
            }
            else if(bTransform && bColumns){
                oContentToDraw = oContent.Copy(oContent.Parent, oContent.DrawingDocument);
                oContentToDraw.Reset(0, 0, oContent.XLimit, 20000);
                oContentToDraw.Recalculate_Page(0, true);
            }
            var dContentHeight = oContentToDraw.GetSummaryHeight();
            var OldShowParaMarks, width_ = dWidth*dKoeff, height_ = dHeight*dKoeff;
            if(isRealObject(editor))
            {
                OldShowParaMarks = editor.ShowParaMarks;
                editor.ShowParaMarks = true;
            }
            if(bNeedWarp)
            {
                oContentToDraw.Draw(oContentToDraw.StartPage, oTextDrawer);
                oRet.oTxWarpStructParamarks = oTextDrawer.m_oDocContentStructure;
                oRet.oTxWarpStructParamarks.Recalculate(oTheme, oColorMap, width_, height_, this);
                if(bTransform)
                {
                    oRet.oTxWarpStructParamarks.checkByWarpStruct(warpGeometry, dWidth, dHeight, oTheme, oColorMap, this, dOneLineWidth, oContentToDraw.XLimit, dContentHeight, dKoeff);
                    if(bNeedNoTransform && bCheckWordArtContent)
                    {
                        if(oRet.oTxWarpStructParamarks.m_aComments.length > 0)
                        {
                            oContent.Recalculate_Page(0, true);
                            bContentRecalculated = true;
                        }
                        oContent.Draw(oContent.StartPage, oTextDrawer);
                        oRet.oTxWarpStructParamarksNoTransform = oTextDrawer.m_oDocContentStructure;
                        oRet.oTxWarpStructParamarksNoTransform.Recalculate(oTheme, oColorMap, dWidth, dHeight, this);
                        oRet.oTxWarpStructParamarksNoTransform.checkUnionPaths();
                    }
                }
                else
                {
                    oRet.oTxWarpStructParamarks.checkUnionPaths();
                    if(bNeedNoTransform && bCheckWordArtContent)
                    {
                        oRet.oTxWarpStructParamarksNoTransform = oRet.oTxWarpStructParamarks;
                    }
                }
            }
            else
            {
                if(bNeedNoTransform && bCheckWordArtContent)
                {
                    oContent.Draw(oContent.StartPage, oTextDrawer);
                    oRet.oTxWarpStructParamarksNoTransform = oTextDrawer.m_oDocContentStructure;
                    oRet.oTxWarpStructParamarksNoTransform.Recalculate(oTheme, oColorMap, dWidth, dHeight, this);
                    oRet.oTxWarpStructParamarksNoTransform.checkUnionPaths();
                }
            }

            if(isRealObject(editor))
            {
                editor.ShowParaMarks = false;
            }
            if(bNeedWarp)
            {
                oContentToDraw.Draw(oContentToDraw.StartPage, oTextDrawer);
                oRet.oTxWarpStruct = oTextDrawer.m_oDocContentStructure;
                oRet.oTxWarpStruct.Recalculate(oTheme, oColorMap, width_, height_, this);
                if(bTransform)
                {
                    oRet.oTxWarpStruct.checkByWarpStruct(warpGeometry, dWidth, dHeight, oTheme, oColorMap, this, dOneLineWidth, oContentToDraw.XLimit, dContentHeight, dKoeff);
                    if(bNeedNoTransform && bCheckWordArtContent)
                    {
                        if(oRet.oTxWarpStruct.m_aComments.length > 0 && !bContentRecalculated)
                        {
                            oContent.Recalculate_Page(0, true);
                        }
                        oContent.Draw(oContent.StartPage, oTextDrawer);
                        oRet.oTxWarpStructNoTransform = oTextDrawer.m_oDocContentStructure;
                        oRet.oTxWarpStructNoTransform.Recalculate(oTheme, oColorMap, dWidth, dHeight, this);
                        oRet.oTxWarpStructNoTransform.checkUnionPaths();
                    }
                }
                else
                {
                    oRet.oTxWarpStruct.checkUnionPaths();
                    if(bNeedNoTransform && bCheckWordArtContent)
                    {
                        oRet.oTxWarpStructNoTransform = oRet.oTxWarpStruct;
                    }
                }
            }
            else
            {
                if(bNeedNoTransform && bCheckWordArtContent)
                {
                    oContent.Draw(oContent.StartPage, oTextDrawer);
                    oRet.oTxWarpStructNoTransform = oTextDrawer.m_oDocContentStructure;
                    oRet.oTxWarpStructNoTransform.Recalculate(oTheme, oColorMap, dWidth, dHeight, this);
                    oRet.oTxWarpStructNoTransform.checkUnionPaths();
                }
            }

            if(isRealObject(editor))
            {
                editor.ShowParaMarks = OldShowParaMarks;
            }
        }
        return oRet;
    }, this, []);
};

CShape.prototype.checkTypeCorrect = function(){
    if(!this.spPr){
        return false;
    }
    return true;
};


CShape.prototype.getColumnNumber = function(){
    if(this.bWordShape){
        return 1;
    }
    var oBodyPr = this.getBodyPr();
    if(AscFormat.isRealNumber(oBodyPr.numCol))
    {
        return oBodyPr.numCol;
    }
    return 1;
};

    CShape.prototype.getColumnSpace = function(){
        if(this.bWordShape){
            return 0;
        }
        var oBodyPr = this.getBodyPr();
        if(AscFormat.isRealNumber(oBodyPr.spcCol))
        {
            return oBodyPr.spcCol;
        }
        return 0;
    };


    CShape.prototype.checkWrap = function(){
        if(!this.txBody){
            return;
        }
        var new_body_pr = this.getBodyPr();
        if (new_body_pr) {
            if(new_body_pr.numCol > 1){
                if(new_body_pr.wrap === AscFormat.nTWTNone){
                    new_body_pr = new_body_pr.createDuplicate();
                    new_body_pr.wrap =  AscFormat.nTWTSquare;
                    this.txBody.setBodyPr(new_body_pr);
                }
            }
        }
    };


    CShape.prototype.setColumnNumber = function(num){
        if(!this.bWordShape && !CheckObjectLine(this)){
            var new_body_pr = this.getBodyPr();
            if (new_body_pr) {
                new_body_pr = new_body_pr.createDuplicate();
                new_body_pr.numCol = (num >> 0);

                if(!this.txBody){
                    this.createTextBody();
                }
                if (this.txBody) {
                    this.txBody.setBodyPr(new_body_pr);
                }
                this.checkWrap();
            }
        }

    };

    CShape.prototype.setColumnSpace = function(spcCol){
        if(!this.bWordShape && !CheckObjectLine(this)){
            var new_body_pr = this.getBodyPr();
            if (new_body_pr) {
                new_body_pr = new_body_pr.createDuplicate();
                new_body_pr.spcCol = spcCol;
                if(!this.txBody){
                    this.createTextBody();
                }
                if (this.txBody) {
                    this.txBody.setBodyPr(new_body_pr);
                }
                this.checkWrap();
            }
        }
    };
    CShape.prototype.GetAllContentControls = function(arrContentControls){
        var oContent = this.getDocContent();
        if(oContent){
            oContent.GetAllContentControls(arrContentControls);
        }
    };

    CShape.prototype.getCopyWithSourceFormatting = function(){
        var oCopy = this.copy();
        if(this.pen || this.brush){
            if(!oCopy.spPr){
                oCopy.setSpPr(AscFormat.CSpPr());
                oCopy.spPr.setParent(oCopy);
            }
            if(this.brush){
                oCopy.spPr.setFill(this.brush.saveSourceFormatting());
            }
            if(this.pen){
                oCopy.spPr.setLn(this.pen.createDuplicate(true));
            }
        }
        if(oCopy.txBody && oCopy.txBody.content){
            var oTheme = this.Get_Theme();
            var oColorMap = this.Get_ColorMap();
            if(this.txBody && this.txBody.content){
                SaveContentSourceFormatting(this.txBody.content.Content, oCopy.txBody.content.Content, oTheme, oColorMap)
            }
        }
        if(oCopy.isPlaceholder() && !this.recalcInfo.recalculateTransform){
            var oXfrm = oCopy.spPr.xfrm;
            if(!oXfrm || !oXfrm.isNotNull()){
                oCopy.x = this.x;
                oCopy.y = this.y;
                oCopy.extX = this.extX;
                oCopy.extY = this.extY;
                AscFormat.CheckSpPrXfrm(oCopy, true);
            }
        }
        return oCopy;
    };
    CShape.prototype.getSignatureLineGuid = function()
    {
        if(this.signatureLine){
            return this.signatureLine.id;
        }
        return null;
    };
function CreateBinaryReader(szSrc, offset, srcLen)
{
    var nWritten = 0;

    var index =  -1 + offset;
    var dst_len = "";

    for( ; index < srcLen; )
    {
        index++;
        var _c = szSrc.charCodeAt(index);
        if (_c == ";".charCodeAt(0))
        {
            index++;
            break;
        }

        dst_len += String.fromCharCode(_c);
    }

    var dstLen = parseInt(dst_len);
    if(isNaN(dstLen))
        return null;
    var pointer = g_memory.Alloc(dstLen);
    var stream = new AscCommon.FT_Stream2(pointer.data, dstLen);
    stream.obj = pointer.obj;

    var dstPx = stream.data;

    if (window.chrome)
    {
        while (index < srcLen)
        {
            var dwCurr = 0;
            var i;
            var nBits = 0;
            for (i=0; i<4; i++)
            {
                if (index >= srcLen)
                    break;
                var nCh = DecodeBase64Char(szSrc.charCodeAt(index++));
                if (nCh == -1)
                {
                    i--;
                    continue;
                }
                dwCurr <<= 6;
                dwCurr |= nCh;
                nBits += 6;
            }

            dwCurr <<= 24-nBits;
            for (i=0; i<nBits/8; i++)
            {
                dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
                dwCurr <<= 8;
            }
        }
    }
    else
    {
        var p = b64_decode;
        while (index < srcLen)
        {
            var dwCurr = 0;
            var i;
            var nBits = 0;
            for (i=0; i<4; i++)
            {
                if (index >= srcLen)
                    break;
                var nCh = p[szSrc.charCodeAt(index++)];
                if (nCh == undefined)
                {
                    i--;
                    continue;
                }
                dwCurr <<= 6;
                dwCurr |= nCh;
                nBits += 6;
            }

            dwCurr <<= 24-nBits;
            for (i=0; i<nBits/8; i++)
            {
                dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
                dwCurr <<= 8;
            }
        }
    }

    return stream;
}

function getParaDrawing(oDrawing)
{
    var oCurDrawing = oDrawing;
    while(oCurDrawing.group)
    {
        oCurDrawing = oCurDrawing.group;
    }
    if(oCurDrawing.parent instanceof ParaDrawing)
    {
        return oCurDrawing.parent;
    }
    return null;
}

function checkDrawingsTransformBeforePaste(oEndContent, oSourceContent, oTempParent)
{
    var i, j;
    for(i = 0; i < oEndContent.Drawings.length; ++i)
    {
        var shape = oEndContent.Drawings[i].Drawing;
        if(shape.isPlaceholder && shape.isPlaceholder() && (!shape.spPr || !shape.spPr.xfrm || !shape.spPr.xfrm.isNotNull()))
        {
            var oOldParent = shape.parent;
            shape.parent = oTempParent;
            var hierarchy = shape.getHierarchy();
            for(j = 0; j < hierarchy.length; ++j)
            {
                if(hierarchy[j] && hierarchy[j].spPr && hierarchy[j].spPr.xfrm && hierarchy[j].spPr.xfrm.isNotNull())
                {
                    break;
                }
            }
            if(j === hierarchy.length)
            {
                if(oSourceContent.Drawings[i] && oSourceContent.Drawings[i].Drawing)
                {
                    var oSourceShape = oSourceContent.Drawings[i].Drawing;
                    if(oSourceShape && oSourceShape.spPr && oSourceShape.spPr.xfrm && oSourceShape.spPr.xfrm.isNotNull())
                    {
                        shape.x = oSourceShape.spPr.xfrm.offX;
                        shape.y = oSourceShape.spPr.xfrm.offY;
                        shape.extX = oSourceShape.spPr.xfrm.extX;
                        shape.extY = oSourceShape.spPr.xfrm.extY;
                        AscFormat.CheckSpPrXfrm(shape);
                    }
                }
            }
            shape.parent = oOldParent;
        }
    }
}


function SaveSourceFormattingTextPr(oTextPr, oTheme, oColorMap) {
    if(oTextPr.RFonts){
        if(oTextPr.RFonts.Ascii){
            oTextPr.RFonts.Ascii.Name = oTheme.themeElements.fontScheme.checkFont(oTextPr.RFonts.Ascii.Name);
        }
        if(oTextPr.RFonts.EastAsia){
            oTextPr.RFonts.EastAsia.Name = oTheme.themeElements.fontScheme.checkFont(oTextPr.RFonts.EastAsia.Name);
        }
        if(oTextPr.RFonts.HAnsi){
            oTextPr.RFonts.HAnsi.Name = oTheme.themeElements.fontScheme.checkFont(oTextPr.RFonts.HAnsi.Name);
        }
        if(oTextPr.RFonts.CS){
            oTextPr.RFonts.CS.Name = oTheme.themeElements.fontScheme.checkFont(oTextPr.RFonts.CS.Name);
        }
    }
    if(oTextPr.Unifill){
        oTextPr.Unifill.check(oTheme, oColorMap);
        oTextPr.Unifill = oTextPr.Unifill.saveSourceFormatting();
    }
    if(oTextPr.TextOutline && oTextPr.TextOutline.Fill){
        oTextPr.TextOutline.Fill.check(oTheme, oColorMap);
        oTextPr.TextOutline.Fill = oTextPr.TextOutline.Fill.saveSourceFormatting();
    }
    return oTextPr;
}

function SaveContentSourceFormatting(aSourceContent, aCopyContent, oTheme, oColorMap) {
    if(aCopyContent.length === aSourceContent.length){
        var bMergeRunPr = (aCopyContent === aSourceContent);
        var oElem;
        for(var i = 0; i< aSourceContent.length; ++i){
            oElem = aSourceContent[i];
            if(oElem.CompiledPr.Pr){
                var oPr = oElem.CompiledPr.Pr.ParaPr.Copy();
                oPr.DefaultRunPr = SaveSourceFormattingTextPr(oElem.CompiledPr.Pr.TextPr.Copy(), oTheme, oColorMap);
                aCopyContent[i].Set_Pr(oPr);
                SaveRunsFormatting(oElem.Content, aCopyContent[i].Content, oTheme, oColorMap, oPr);
            }
            else{
                if(aCopyContent[i].Pr && aCopyContent[i].Pr.DefaultRunPr && aCopyContent[i].Pr.DefaultRunPr.Unifill){
                    var oPr = aCopyContent[i].Pr.Copy();
                    oPr.DefaultRunPr.Unifill.check(oTheme, oColorMap);
                    oPr.DefaultRunPr.Unifill = oPr.DefaultRunPr.Unifill.saveSourceFormatting();
                    oPr.DefaultRunPr = SaveSourceFormattingTextPr(oPr.DefaultRunPr.Copy(), oTheme, oColorMap);
                    aCopyContent[i].Set_Pr(oPr);
                }
            }
        }
    }
}

function SaveRunsFormatting(aSourceContent, aCopyContent, oTheme, oColorMap, oPr){
    var bMergeRunPr = (aCopyContent === aSourceContent);
    for(var i = 0; i < aCopyContent.length; ++i){
        if(aCopyContent[i] instanceof ParaRun && aCopyContent[i].Pr){
            if(bMergeRunPr){
                var oCoprPr = oPr.DefaultRunPr.Copy();
                oCoprPr.Merge(SaveSourceFormattingTextPr(aCopyContent[i].Pr.Copy(), oTheme, oColorMap));
                aCopyContent[i].Set_Pr(oCoprPr)
            }
            else {
                aCopyContent[i].Set_Pr(SaveSourceFormattingTextPr(aCopyContent[i].Pr.Copy(), oTheme, oColorMap));
            }

        }
        else if(aSourceContent[i].Content){
            var oElem = aSourceContent[i];
            SaveRunsFormatting(oElem.Content, aCopyContent[i].Content, oTheme, oColorMap, oPr);
            if(oElem.Get_CompiledCtrPrp && aCopyContent[i].setCtrPrp){
                var oCtrPr = oElem.Get_CompiledCtrPrp();
                aCopyContent[i].setCtrPrp(oCtrPr);
            }
        }
        else if(aSourceContent[i] instanceof AscCommonWord.ParaMath && aSourceContent[i].Root && aSourceContent[i].Root.Content){
            SaveRunsFormatting(aSourceContent[i].Root.Content, aCopyContent[i].Root.Content, oTheme, oColorMap, oPr);

        }
    }
}
    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].CheckObjectLine = CheckObjectLine;
    window['AscFormat'].CreateUniFillByUniColorCopy = CreateUniFillByUniColorCopy;
    window['AscFormat'].CreateUniFillByUniColor = CreateUniFillByUniColor;
    window['AscFormat'].ConvertParagraphToPPTX = ConvertParagraphToPPTX;
    window['AscFormat'].ConvertParagraphToWord = ConvertParagraphToWord;
    window['AscFormat'].SetXfrmFromMetrics = SetXfrmFromMetrics;
    window['AscFormat'].CShape = CShape;
    window['AscFormat'].CreateBinaryReader = CreateBinaryReader;
    window['AscFormat'].getParaDrawing = getParaDrawing;
    window['AscFormat'].ConvertGraphicFrameToWordTable = ConvertGraphicFrameToWordTable;
    window['AscFormat'].ConvertTableToGraphicFrame = ConvertTableToGraphicFrame;
    window['AscFormat'].CSignatureLine = CSignatureLine;
    window['AscFormat'].checkDrawingsTransformBeforePaste = checkDrawingsTransformBeforePaste;
    window['AscFormat'].SaveContentSourceFormatting = SaveContentSourceFormatting;

})(window);

/**
 * Created by Sergey.Luzyanin on 4/25/2017.
 */
(function(undefined){


    var CONNECTOR_MARGIN = 6.35;

    /**
    * @constructor
    * */
    function ConnectionParams(){
        this.bounds = new AscFormat.CGraphicBounds(0, 0, 0, 0);
        this.dir = AscFormat.CARD_DIRECTION_E;
        this.x = 0;
        this.y = 0;
        this.idx = 0;
    }
    ConnectionParams.prototype.copy = function(){
        var _c = new ConnectionParams();
        _c.bounds.fromOther(this.bounds);
        _c.dir = this.dir;
        _c.x = this.x;
        _c.y = this.y;
        _c.idx = this.idx;
        return _c;
    };
    ConnectionParams.prototype.transform = function(oTransform){
        this.bounds.transform(oTransform);
        //this.dir = AscFormat.CARD_DIRECTION_E;
        var _x = oTransform.TransformPointX(this.x, this.y);
        var _y = oTransform.TransformPointY(this.x, this.y);
        this.x = _x;
        this.y = _y;
    };

    function fCalculateSpPr(begin, end, sPreset, penW){
        return AscFormat.ExecuteNoHistory(function(){
            var oSpPr = new AscFormat.CSpPr();
            var oXfrm = new AscFormat.CXfrm();
            oSpPr.setXfrm(oXfrm);
            oXfrm.setParent(oSpPr);

            var _begin = begin.copy();
            var _end = end.copy();
            var fAngle = 0;

            if(!penW){
                penW = 12700;
            }

            switch(begin.dir){
                case AscFormat.CARD_DIRECTION_N:{
                    fAngle = Math.PI/2;
                    switch(_end.dir){
                        case AscFormat.CARD_DIRECTION_N:{
                            _end.dir = AscFormat.CARD_DIRECTION_E;
                            break;
                        }
                        case AscFormat.CARD_DIRECTION_S:{
                            _end.dir = AscFormat.CARD_DIRECTION_W;
                            break;
                        }
                        case AscFormat.CARD_DIRECTION_W:{
                            _end.dir = AscFormat.CARD_DIRECTION_N;
                            break;
                        }
                        case AscFormat.CARD_DIRECTION_E:{
                            _end.dir = AscFormat.CARD_DIRECTION_S;
                            break;
                        }
                    }
                    break;
                }
                case AscFormat.CARD_DIRECTION_S:{
                    fAngle = -Math.PI/2;
                    switch(_end.dir){
                        case AscFormat.CARD_DIRECTION_N:{
                            _end.dir = AscFormat.CARD_DIRECTION_W;
                            break;
                        }
                        case AscFormat.CARD_DIRECTION_S:{
                            _end.dir = AscFormat.CARD_DIRECTION_E;
                            break;
                        }
                        case AscFormat.CARD_DIRECTION_W:{
                            _end.dir = AscFormat.CARD_DIRECTION_S;
                            break;
                        }
                        case AscFormat.CARD_DIRECTION_E:{
                            _end.dir = AscFormat.CARD_DIRECTION_N;
                            break;
                        }
                    }
                    break;
                }
                case AscFormat.CARD_DIRECTION_W:{
                    fAngle = Math.PI;
                    switch(_end.dir){
                        case AscFormat.CARD_DIRECTION_N:{
                            _end.dir = AscFormat.CARD_DIRECTION_S;
                            break;
                        }
                        case AscFormat.CARD_DIRECTION_S:{
                            _end.dir = AscFormat.CARD_DIRECTION_N;
                            break;
                        }
                        case AscFormat.CARD_DIRECTION_W:{
                            _end.dir = AscFormat.CARD_DIRECTION_E;
                            break;
                        }
                        case AscFormat.CARD_DIRECTION_E:{
                            _end.dir = AscFormat.CARD_DIRECTION_W;
                            break;
                        }
                    }
                    break;
                }
                default:{
                    //East is default direction
                    fAngle = 0;
                    break;
                }
            }

            var oTransform = new AscCommon.CMatrix();
            AscCommon.global_MatrixTransformer.RotateRadAppend(oTransform, -fAngle);
            _begin.transform(oTransform);
            _end.transform(oTransform);

            var extX = Math.max(penW/36000.0, Math.abs(_end.x - _begin.x));
            var extY = Math.max(penW/36000.0, Math.abs(_end.y - _begin.y));
            var flipV = false;
            var flipH = false;
            var rot = 0;
            var oMapAdj = {};
            if(sPreset === "line" ||
                sPreset.indexOf("straightConnector") > -1){
                flipH = (_begin.x > _end.x);
                flipV = (_begin.y > _end.y);
            }
            else{
                var sPrefix = "bentConnector";
                if(sPreset.indexOf("curvedConnector") > -1){
                    sPrefix = "curvedConnector";
                }
                //returns "bentConnector" by default
                switch(_end.dir){
                    case AscFormat.CARD_DIRECTION_N:{

                        if(_end.bounds.l > _begin.bounds.r){
                            if(_end.bounds.t < _begin.y){
                                if(_end.y <= _begin.y){
                                    sPreset = "4";
                                    flipV = true;
                                    oMapAdj["adj1"] = (100000*(((_begin.bounds.r + _end.bounds.l)/2  - _begin.x)/extX) + 0.5) >> 0;
                                    oMapAdj["adj2"] = (100000*(_begin.y - (_end.bounds.t - CONNECTOR_MARGIN))/extY + 0.5) >> 0;
                                }
                                else{
                                    sPreset = "4";
                                    oMapAdj["adj1"] = (100000*(((_begin.bounds.r + _end.bounds.l)/2  - _begin.x)/extX) + 0.5) >> 0;
                                    oMapAdj["adj2"] = (-100000*(  ( _begin.y - (_end.bounds.t - CONNECTOR_MARGIN) )/extY) + 0.5) >> 0;
                                }
                            }
                            else{
                                sPreset = "2";
                            }
                        }
                        else{
                            if(_end.bounds.t > _begin.bounds.b){
                                if(_end.x < _begin.x){
                                    sPreset = "4";
                                    flipH = true;
                                    oMapAdj["adj1"] = -((100000*(_begin.bounds.r + CONNECTOR_MARGIN - _begin.x)/extX + 0.5) >> 0);
                                    oMapAdj["adj2"] = (100000*((_end.bounds.t + _begin.bounds.b)/2.0 - _begin.y)/extY) >> 0;
                                }
                                else{
                                    sPreset = "2";
                                }

                            }
                            else if(_end.bounds.b < _begin.bounds.t){
                                if(_end.x < _begin.x){
                                    sPreset = "4";
                                    flipH = true;
                                    flipV = true;
                                    oMapAdj["adj1"] = -((100000*(_begin.bounds.r + CONNECTOR_MARGIN - _begin.x)/extX + 0.5) >> 0);
                                    oMapAdj["adj2"] = (100000*(_begin.y - (_end.bounds.t - CONNECTOR_MARGIN))/extY + 0.5) >> 0;
                                }
                                else{
                                    sPreset = "4";
                                    flipV = true;
                                    oMapAdj["adj1"] = (100000*(Math.max(_begin.bounds.r, _end.bounds.r) + CONNECTOR_MARGIN - _begin.x)/extX) >> 0;
                                    oMapAdj["adj2"] = (100000*(_begin.y - (_end.bounds.t - CONNECTOR_MARGIN))/extY + 0.5) >> 0;
                                }
                            }
                            else{

                                if(_end.y < _begin.y){
                                    if(_end.x < _begin.x){
                                        sPreset = "4";
                                        flipH = true;
                                        flipV = true;
                                        oMapAdj["adj1"] = -((100000*(_begin.bounds.r + CONNECTOR_MARGIN - _begin.x)/extX + 0.5) >> 0);
                                        oMapAdj["adj2"] = (100000*(_begin.y - (_end.bounds.t - CONNECTOR_MARGIN))/extY + 0.5) >> 0;
                                    }
                                    else {
                                        sPreset = "4";
                                        flipV = true;
                                        oMapAdj["adj1"] =  (100000*(Math.max(_begin.bounds.r, _end.bounds.r) + CONNECTOR_MARGIN - _begin.x)/extX + 0.5) >> 0;
                                        oMapAdj["adj2"] =  (100000*(_begin.y - (_end.bounds.t - CONNECTOR_MARGIN))/extY + 0.5) >> 0;
                                    }
                                }
                                else{
                                    if(_end.x > _begin.x){
                                        sPreset = "2";
                                    }
                                    else{
                                        sPreset = "4";
                                        flipH = true;
                                        oMapAdj["adj1"] =  -(100000*(Math.max(_begin.bounds.r, _end.bounds.r) + CONNECTOR_MARGIN - _begin.x)/extX + 0.5) >> 0;
                                        oMapAdj["adj2"] =  -((100000*(_begin.y - (Math.min(_begin.bounds.t, _end.bounds.t) - CONNECTOR_MARGIN))/extY + 0.5) >> 0);

                                    }

                                }
                            }
                        }
                        break;
                    }
                    case AscFormat.CARD_DIRECTION_S:{
                        if(_end.bounds.l > _begin.bounds.r){
                            if(_end.bounds.b < _begin.y){
                                sPreset = "2";
                                flipV = true;
                            }
                            else{
                                if(_end.y < _begin.y){
                                    sPreset = "4";
                                    flipV = true;
                                    oMapAdj["adj2"] = -((100000*((_end.bounds.b + CONNECTOR_MARGIN - _end.y)/extY) + 0.5) >> 0);
                                    oMapAdj["adj1"] = ((100000*(((_begin.bounds.r + _end.bounds.l)/2 - _begin.x))/extX) + 0.5) >> 0;
                                }
                                else{
                                    sPreset = "4";
                                    oMapAdj["adj1"] = (100000*(((_begin.bounds.r + _end.bounds.l)/2.0 - _begin.x)/extX) + 0.5) >> 0;
                                    oMapAdj["adj2"] = 100000 + ((100000*((_end.bounds.b + CONNECTOR_MARGIN - _end.y)/extY) + 0.5) >> 0);
                                }
                            }
                        }
                        else{
                            if(_end.bounds.b < _begin.bounds.t){

                                if(_end.x > _begin.bounds.r){
                                    sPreset = "2";
                                    flipV = true;
                                }
                                else{
                                    sPreset = "4";
                                    flipH = true;
                                    flipV = true;

                                    oMapAdj["adj1"] = -((100000*(_begin.bounds.r + CONNECTOR_MARGIN - _begin.x)/extX + 0.5) >> 0);
                                    oMapAdj["adj2"] =  (100000*(_begin.y - ((_end.bounds.b + _begin.bounds.t)/2.0))/extY + 0.5) >> 0;
                                }
                            }
                            else{

                                if(_end.x < _begin.x){
                                    if(_end.y > _begin.y){
                                        sPreset = "4";
                                        flipH = true;
                                        oMapAdj["adj1"] = -((100000*(Math.max(_begin.bounds.r, _end.bounds.r) + CONNECTOR_MARGIN - _begin.x)/extX + 0.5) >> 0);
                                        oMapAdj["adj2"] = (100000*((Math.max(_end.bounds.b, _begin.bounds.b) - _begin.y + CONNECTOR_MARGIN)/extY) + 0.5) >> 0;
                                    }
                                    else{
                                        sPreset = "4";
                                        flipH = true;
                                        flipV = true;
                                        oMapAdj["adj1"] = -((100000*(Math.max(_begin.bounds.r, _end.bounds.r) + CONNECTOR_MARGIN - _begin.x)/extX + 0.5) >> 0);
                                        oMapAdj["adj2"] = - (100000*((Math.max(_end.bounds.b, _begin.bounds.b) - _begin.y + CONNECTOR_MARGIN)/extY) + 0.5) >> 0;
                                    }
                                }
                                else{
                                    if(_end.y > _begin.y){
                                        sPreset = "4";

                                        oMapAdj["adj1"] = ((100000*(Math.max(_begin.bounds.r, _end.bounds.r) + CONNECTOR_MARGIN - _begin.x)/extX + 0.5) >> 0);
                                        oMapAdj["adj2"] = ((100000*(_end.bounds.b + CONNECTOR_MARGIN - _begin.y)/extY + 0.5) >> 0);
                                    }
                                    else{
                                        sPreset = "2";
                                        flipV = true;
                                    }
                                }
                            }
                        }
                        break;
                    }
                    case AscFormat.CARD_DIRECTION_W:{

                        if(_begin.x < _end.x){
                            sPreset = "3";
                            flipV = _begin.y > _end.y;
                        }
                        else{

                            sPreset = "5";
                            if(_end.bounds.t > _begin.bounds.b){

                                flipH = true;
                                oMapAdj["adj1"] =  -((100000*(_begin.bounds.r + CONNECTOR_MARGIN - _begin.x)/extX + 0.5) >> 0);
                                oMapAdj["adj2"] =   (100000*((_end.bounds.t + _begin.bounds.b)/2.0 - _begin.y)/extY + 0.5) >> 0;
                                oMapAdj["adj3"] =   (100000*(_begin.x - (_end.bounds.l - CONNECTOR_MARGIN))/extX + 0.5) >> 0;
                            }
                            else if(_end.bounds.b < _begin.bounds.t){
                                flipH = true;
                                flipV = true;
                                oMapAdj["adj1"] =  -((100000*(_begin.bounds.r + CONNECTOR_MARGIN - _begin.x)/extX + 0.5) >> 0);
                                oMapAdj["adj2"] =  (100000*(_begin.y - (_end.bounds.b + _begin.bounds.t)/2.0)/extY + 0.5) >> 0;
                                oMapAdj["adj3"] =   (100000*(_begin.x - (_end.bounds.l - CONNECTOR_MARGIN))/extX + 0.5) >> 0;
                            }
                            else{
                                if(_end.y > _begin.y){
                                    flipH = true;
                                    oMapAdj["adj1"] = -((100000*(_begin.bounds.r + CONNECTOR_MARGIN - _begin.x)/extX + 0.5) >> 0);
                                    oMapAdj["adj2"] =  (100000*(Math.max(_begin.bounds.b, _end.bounds.b) + CONNECTOR_MARGIN - _begin.y)/extY + 0.5) >> 0;
                                    oMapAdj["adj3"] =  (100000*(_begin.x - (_end.bounds.l - CONNECTOR_MARGIN))/extX + 0.5) >> 0;
                                }
                                else{
                                    flipH = true;
                                    flipV = true;
                                    oMapAdj["adj1"] = -((100000*(_begin.bounds.r + CONNECTOR_MARGIN - _begin.x)/extX + 0.5) >> 0);
                                    oMapAdj["adj2"] =  (100000*(_begin.y - (Math.min(_begin.bounds.t, _end.bounds.t) - CONNECTOR_MARGIN))/extY + 0.5) >> 0;
                                    oMapAdj["adj3"] =  (100000*(_begin.x - (_end.bounds.l - CONNECTOR_MARGIN))/extX + 0.5) >> 0;
                                }
                            }

                        }
                        break;
                    }
                    case AscFormat.CARD_DIRECTION_E:{
                        if(_end.bounds.l > _begin.bounds.r){
                            if(_end.bounds.b < _begin.y ){
                                sPreset = "3";
                                flipV = true;
                                oMapAdj["adj1"] = (100000*(_end.bounds.r + CONNECTOR_MARGIN - _begin.x)/extX) >> 0;
                            }
                            else if(_end.bounds.t > _begin.y){
                                sPreset = "3";

                                oMapAdj["adj1"] = 100000 + (100000*(CONNECTOR_MARGIN/extX) + 0.5) >> 0;

                            }
                            else{
                                if(_end.y < _begin.y){
                                    sPreset = "5";
                                    flipV = true;
                                    oMapAdj["adj1"] = (100000*((_end.bounds.l + _begin.bounds.r)/2 - _begin.x)/extX + 0.5) >> 0;
                                    oMapAdj["adj2"] =  (100000 + 100000*(_end.y  - (_end.bounds.t - CONNECTOR_MARGIN))/extY + 0.5) >> 0;
                                    oMapAdj["adj3"] = 100000 + (100000*(_end.bounds.r + CONNECTOR_MARGIN - _end.x)/extX + 0.5) >> 0;
                                }
                                else{
                                    sPreset = "5";
                                    oMapAdj["adj1"] = (100000*((_end.bounds.l + _begin.bounds.r)/2 - _begin.x)/extX + 0.5) >> 0;
                                    oMapAdj["adj2"] =  -(100000*(_begin.y  - (_end.bounds.t - CONNECTOR_MARGIN))/extY + 0.5) >> 0;
                                    oMapAdj["adj3"] = 100000 + (100000*(_end.bounds.r + CONNECTOR_MARGIN - _end.x)/extX + 0.5) >> 0;
                                }
                            }
                        }
                        else{
                            if(_end.x >= _begin.bounds.l || _end.y > _begin.bounds.b || _end.y < _begin.bounds.t){
                                if(_end.y < _begin.y){
                                    if(_end.x < _begin.x){
                                        flipH = true;
                                        flipV = true;
                                        sPreset = "3";
                                        oMapAdj["adj1"] = -(100000*(Math.max(_end.bounds.r, _begin.bounds.r) + CONNECTOR_MARGIN - _begin.x)/extX + 0.5) >> 0;
                                    }
                                    else {
                                        flipV = true;
                                        sPreset = "3";
                                        oMapAdj["adj1"] =  100000 + (100000*(Math.max(_end.bounds.r, _begin.bounds.r) + CONNECTOR_MARGIN - _end.x)/extX + 0.5) >> 0;
                                    }
                                }
                                else{
                                    if(_end.x < _begin.x){
                                        flipH = true;
                                        sPreset = "3";
                                        oMapAdj["adj1"] = -(100000*(Math.max(_end.bounds.r, _begin.bounds.r) + CONNECTOR_MARGIN - _begin.x)/extX + 0.5) >> 0;
                                    }
                                    else {
                                        sPreset = "3";
                                        oMapAdj["adj1"] =  100000 + (100000*(Math.max(_end.bounds.r, _begin.bounds.r) + CONNECTOR_MARGIN - _end.x)/extX + 0.5) >> 0;
                                    }
                                }
                            }
                            else{
                                if(_end.y >= _begin.y){
                                    sPreset = "5";
                                    flipH = true;
                                    oMapAdj["adj1"] = -((100000*(CONNECTOR_MARGIN/extX) + 0.5) >> 0);
                                    oMapAdj["adj2"] = (100000 + 100000*(_begin.bounds.b + CONNECTOR_MARGIN - _end.y)/extY + 0.5) >> 0;
                                    oMapAdj["adj3"] = (100000*(_begin.x - (_end.bounds.r + _begin.bounds.l)/2.0)/extX + 0.5) >> 0;
                                }
                                else{
                                    sPreset = "5";
                                    flipH = true;
                                    flipV = true;
                                    oMapAdj["adj1"] = -((100000*(CONNECTOR_MARGIN/extX) + 0.5) >> 0);
                                    oMapAdj["adj2"] = -(100000*(_begin.bounds.b + CONNECTOR_MARGIN - _begin.y)/extY + 0.5) >> 0;
                                    oMapAdj["adj3"] = (100000*(_begin.x - (_end.bounds.r + _begin.bounds.l)/2.0)/extX + 0.5) >> 0;
                                }
                            }
                        }
                        break;
                    }
                }
                sPreset = sPrefix + sPreset;
            }
            var _posX = (end.x + begin.x)/2.0 - extX/2.0;
            var _posY = (end.y + begin.y)/2.0 - extY/2.0;
            var _fAng = AscFormat.normalizeRotate(rot - fAngle);

            var oGeometry = AscFormat.CreateGeometry(sPreset);
            for(var key in oMapAdj){
                if(oMapAdj.hasOwnProperty(key)){
                    oGeometry.setAdjValue(key, oMapAdj[key]);
                }
            }
            oSpPr.setGeometry(oGeometry);
            oGeometry.setParent(oSpPr);
            oXfrm.setOffX(_posX);
            oXfrm.setOffY(_posY);
            oXfrm.setExtX(extX);
            oXfrm.setExtY(extY);
            oXfrm.setRot(_fAng);
            oXfrm.setFlipH(flipH);
            oXfrm.setFlipV(flipV);
            return oSpPr;

        }, this, []);
    }


    function fCalculateConnectionInfo(oConnInfo, x, y) {

        var oConnecInfo2 = new ConnectionParams();
        oConnecInfo2.x = x;
        oConnecInfo2.y = y;
        oConnecInfo2.bounds.fromOther(new AscFormat.CGraphicBounds(x, y, x, y));

        var diffX = x - oConnInfo.x;
        var diffY = y - oConnInfo.y;

        if(Math.abs(diffX) > Math.abs(diffY)){
            if(diffX < 0){
                oConnecInfo2.dir = AscFormat.CARD_DIRECTION_E;
            }
            else{
                oConnecInfo2.dir = AscFormat.CARD_DIRECTION_W;
            }
        }
        else{
            if(diffY < 0){
                oConnecInfo2.dir = AscFormat.CARD_DIRECTION_S;
            }
            else{
                oConnecInfo2.dir = AscFormat.CARD_DIRECTION_N;
            }
        }
        return oConnecInfo2;
    }

    function CConnectionShape() {
        AscFormat.CShape.call(this);
    }
    CConnectionShape.prototype = Object.create(AscFormat.CShape.prototype);
    CConnectionShape.prototype.constructor = CConnectionShape;

    CConnectionShape.prototype.getObjectType = function(){
        return AscDFH.historyitem_type_Cnx;
    };

    CConnectionShape.prototype.copy = function () {
        var copy = new CConnectionShape();
        this.fillObject(copy);
        return copy;
    };

    CConnectionShape.prototype.resetShape = function (oShape) {
		if (!this.nvSpPr)
		    return;

        var cnxPr = this.nvSpPr.nvUniSpPr;

        if(cnxPr.stCnxId === oShape.Id || cnxPr.endCnxId === oShape.Id){
            var oNewPr = cnxPr.copy();
            if(cnxPr.stCnxId === oShape.Id){
                oNewPr.stCnxId = null;
                oNewPr.stCnxIdx = null;
            }
            if(cnxPr.endCnxId === oShape.Id){
                oNewPr.endCnxId = null;
                oNewPr.endCnxIdx = null;
            }
            this.nvSpPr.setUniSpPr(oNewPr);
        }
    };

    CConnectionShape.prototype.getStCxnId = function(){
        return this.nvSpPr.nvUniSpPr.stCnxId;
    };
    CConnectionShape.prototype.getEndCxnId = function(){
        return this.nvSpPr.nvUniSpPr.endCnxId;
    };
    CConnectionShape.prototype.getStCxnIdx = function(){
        return this.nvSpPr.nvUniSpPr.stCnxIdx;
    };
    CConnectionShape.prototype.getEndCxnIdx = function(){
        return this.nvSpPr.nvUniSpPr.endCnxIdx;
    };

    CConnectionShape.prototype.calculateTransform = function (bMove) {
        var oBeginDrawing = null;
        var oEndDrawing = null;
        var sStId = this.getStCxnId();
        var sEndId = this.getEndCxnId();
        var _group;
        if(null !== sStId){
            oBeginDrawing = AscCommon.g_oTableId.Get_ById(sStId);
            if(oBeginDrawing && oBeginDrawing.bDeleted){
                oBeginDrawing = null;
            }
            if(oBeginDrawing){
                _group = oBeginDrawing.getMainGroup();
                if(_group){
                    _group.recalculate();
                }
                else{
                    oBeginDrawing.recalculate();
                }
            }
        }
        if(null !== sEndId){
            oEndDrawing = AscCommon.g_oTableId.Get_ById(sEndId);
            if(oEndDrawing && oEndDrawing.bDeleted){
                oEndDrawing = null;
            }
            if(oEndDrawing){
                _group = oEndDrawing.getMainGroup();
                if(_group){
                    _group.recalculate();
                }
                else{
                    oEndDrawing.recalculate();
                }
            }
        }
        var _startConnectionParams, _endConnectionParams, _spPr, _xfrm2;
        var _xfrm = this.spPr.xfrm;

        if(oBeginDrawing && oEndDrawing){
            _startConnectionParams = oBeginDrawing.getConnectionParams(this.getStCxnIdx(), null);
            _endConnectionParams = oEndDrawing.getConnectionParams(this.getEndCxnIdx(), null);
            _spPr = AscFormat.fCalculateSpPr(_startConnectionParams, _endConnectionParams, this.spPr.geometry.preset, this.pen.w);
            _xfrm2 = _spPr.xfrm;
            _xfrm.setExtX(_xfrm2.extX);
            _xfrm.setExtY(_xfrm2.extY);
            if(!this.group){
                _xfrm.setOffX(_xfrm2.offX);
                _xfrm.setOffY(_xfrm2.offY);
                _xfrm.setFlipH(_xfrm2.flipH);
                _xfrm.setFlipV(_xfrm2.flipV);
                _xfrm.setRot(_xfrm2.rot);
            }
            else{

                var _xc = _xfrm2.offX + _xfrm2.extX / 2.0;
                var _yc = _xfrm2.offY + _xfrm2.extY / 2.0;
                var xc = this.group.invertTransform.TransformPointX(_xc, _yc);
                var yc = this.group.invertTransform.TransformPointY(_xc, _yc);
                _xfrm.setOffX(xc - _xfrm2.extX / 2.0);
                _xfrm.setOffY(yc - _xfrm2.extY / 2.0);
                _xfrm.setFlipH(this.group.getFullFlipH() ? !_xfrm2.flipH : _xfrm2.flipH);
                _xfrm.setFlipV(this.group.getFullFlipV() ? !_xfrm2.flipV : _xfrm2.flipV);
                _xfrm.setRot(AscFormat.normalizeRotate(_xfrm2.rot - this.group.getFullRotate()));
            }
            this.spPr.setGeometry(_spPr.geometry.createDuplicate());
            this.checkDrawingBaseCoords();
            this.recalculate();
        }
        else if(oBeginDrawing || oEndDrawing){
            if(bMove){
                var _x, _y;
                var _spX, _spY, diffX, diffY, bChecked = false;
                var _oCnxInfo;
                var _groupTransform;
                if(oBeginDrawing){
                    _oCnxInfo = oBeginDrawing.getGeom().cnxLst[this.getStCxnIdx()];
                    if(_oCnxInfo){
                        _spX = oBeginDrawing.transform.TransformPointX(_oCnxInfo.x, _oCnxInfo.y);
                        _spY = oBeginDrawing.transform.TransformPointY(_oCnxInfo.x, _oCnxInfo.y);
                        _x = this.transform.TransformPointX(0, 0);
                        _y = this.transform.TransformPointY(0, 0);
                        bChecked = true;
                    }
                }
                else {
                    _oCnxInfo = oEndDrawing.getGeom().cnxLst[this.getEndCxnIdx()];
                    if(_oCnxInfo){
                        _spX = oEndDrawing.transform.TransformPointX(_oCnxInfo.x, _oCnxInfo.y);
                        _spY = oEndDrawing.transform.TransformPointY(_oCnxInfo.x, _oCnxInfo.y);
                        _x = this.transform.TransformPointX(this.extX, this.extY);
                        _y = this.transform.TransformPointY(this.extX, this.extY);
                        bChecked = true;
                    }
                }

                if(bChecked){
                    if(this.group){
                        _groupTransform = this.group.invertTransform.CreateDublicate();
                        _groupTransform.tx = 0;
                        _groupTransform.ty = 0;
                        diffX = _groupTransform.TransformPointX(_spX - _x, _spY - _y);
                        diffY = _groupTransform.TransformPointY(_spX - _x, _spY - _y);
                    }
                    else{
                        diffX = _spX - _x;
                        diffY = _spY - _y;
                    }
                    this.spPr.xfrm.setOffX(this.spPr.xfrm.offX + diffX);
                    this.spPr.xfrm.setOffY(this.spPr.xfrm.offY + diffY);
                    this.recalculate();
                }
            }
            else{
                if(oBeginDrawing){
                    _startConnectionParams = oBeginDrawing.getConnectionParams(this.getStCxnIdx(), null);
                }
                if(oEndDrawing){
                    _endConnectionParams = oEndDrawing.getConnectionParams(this.getEndCxnIdx(), null);
                }
                var _tx, _ty;
                if(_startConnectionParams || _endConnectionParams){

                    if(!_startConnectionParams){
                        _tx = this.transform.TransformPointX(0, 0);
                        _ty = this.transform.TransformPointY(0, 0);
                        _startConnectionParams = AscFormat.fCalculateConnectionInfo(_endConnectionParams, _tx, _ty);
                    }
                    if(!_endConnectionParams){
                        _tx = this.transform.TransformPointX(this.extX, this.extY);
                        _ty = this.transform.TransformPointY(this.extX, this.extY);
                        _endConnectionParams = AscFormat.fCalculateConnectionInfo(_startConnectionParams, _tx, _ty);
                    }
                    _spPr = AscFormat.fCalculateSpPr(_startConnectionParams, _endConnectionParams, this.spPr.geometry.preset, this.pen && this.pen.w);
                    _xfrm2 = _spPr.xfrm;
                    _xfrm.setExtX(_xfrm2.extX);
                    _xfrm.setExtY(_xfrm2.extY);
                    if(!this.group){
                        _xfrm.setOffX(_xfrm2.offX);
                        _xfrm.setOffY(_xfrm2.offY);
                        _xfrm.setFlipH(_xfrm2.flipH);
                        _xfrm.setFlipV(_xfrm2.flipV);
                        _xfrm.setRot(_xfrm2.rot);
                    }
                    else{
                        var _xc = _xfrm2.offX + _xfrm2.extX / 2.0;
                        var _yc = _xfrm2.offY + _xfrm2.extY / 2.0;
                        var xc = this.group.invertTransform.TransformPointX(_xc, _yc);
                        var yc = this.group.invertTransform.TransformPointY(_xc, _yc);
                        _xfrm.setOffX(xc - _xfrm2.extX / 2.0);
                        _xfrm.setOffY(yc - _xfrm2.extY / 2.0);
                        _xfrm.setFlipH(this.group.getFullFlipH() ? !_xfrm2.flipH : _xfrm2.flipH);
                        _xfrm.setFlipV(this.group.getFullFlipV() ? !_xfrm2.flipV : _xfrm2.flipV);
                        _xfrm.setRot(AscFormat.normalizeRotate(_xfrm2.rot - this.group.getFullRotate()));
                    }
                    this.spPr.setGeometry(_spPr.geometry.createDuplicate());
                    this.checkDrawingBaseCoords();
                    this.recalculate();
                }
            }
        }
    };

    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].fCalculateSpPr = fCalculateSpPr;
    window['AscFormat'].fCalculateConnectionInfo = fCalculateConnectionInfo;
    window['AscFormat'].ConnectionParams = ConnectionParams;
    window['AscFormat'].CConnectionShape = CConnectionShape;
})();
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {
var moveTo=0,
    lineTo=1,
    arcTo=2,
    bezier3=3,
    bezier4=4,
    close=5;

// Import
var cToRad = AscFormat.cToRad;
var HitToArc = AscFormat.HitToArc;
var ArcToCurvers = AscFormat.ArcToCurvers;
var ArcToOnCanvas = AscFormat.ArcToOnCanvas;
var HitInLine = AscFormat.HitInLine;
var HitInBezier4 = AscFormat.HitInBezier4;
var HitInBezier3 = AscFormat.HitInBezier3;
var MOVE_DELTA = AscFormat.MOVE_DELTA;

    var History = AscCommon.History;

var cToRad2 = (Math.PI/60000)/180;


function CChangesDrawingsAddPathCommand(Class, oCommand, nIndex, bReverse){
    this.Type = AscDFH.historyitem_PathAddPathCommand;
    this.Command = oCommand;
    this.Index = nIndex;
    this.bReverse = bReverse;
	AscDFH.CChangesBase.call(this, Class);
}

	CChangesDrawingsAddPathCommand.prototype = Object.create(AscDFH.CChangesBase.prototype);
	CChangesDrawingsAddPathCommand.prototype.constructor = CChangesDrawingsAddPathCommand;

    CChangesDrawingsAddPathCommand.prototype.Undo = function(){
        if(this.bReverse){
            this.Class.ArrPathCommandInfo.splice(this.Index, 0, this.Command);
        }
        else{
            this.Class.ArrPathCommandInfo.splice(this.Index, 1);
        }
    };
    CChangesDrawingsAddPathCommand.prototype.Redo = function(){
        if(this.bReverse){
            this.Class.ArrPathCommandInfo.splice(this.Index, 1);
        }
        else{
            this.Class.ArrPathCommandInfo.splice(this.Index, 0, this.Command);
        }
    };


    CChangesDrawingsAddPathCommand.prototype.WriteToBinary = function(Writer){
        Writer.WriteLong(this.Index);
        Writer.WriteLong(this.Command.id);
        Writer.WriteBool(!!this.bReverse);
        switch(this.Command.id){
            case moveTo:
            case lineTo:
            {
                Writer.WriteString2(this.Command.X);
                Writer.WriteString2(this.Command.Y);
                break;
            }
            case bezier3:
            {
                Writer.WriteString2(this.Command.X0);
                Writer.WriteString2(this.Command.Y0);
                Writer.WriteString2(this.Command.X1);
                Writer.WriteString2(this.Command.Y1);
                break;
            }
            case bezier4:
            {
                Writer.WriteString2(this.Command.X0);
                Writer.WriteString2(this.Command.Y0);
                Writer.WriteString2(this.Command.X1);
                Writer.WriteString2(this.Command.Y1);
                Writer.WriteString2(this.Command.X2);
                Writer.WriteString2(this.Command.Y2);
                break;
            }
            case arcTo:
            {
                Writer.WriteString2(this.Command.hR);
                Writer.WriteString2(this.Command.wR);
                Writer.WriteString2(this.Command.stAng);
                Writer.WriteString2(this.Command.swAng);
                break;
            }
            case close:
            {
                break;
            }
        }
    };


    CChangesDrawingsAddPathCommand.prototype.ReadFromBinary = function(Reader){
        this.Index = Reader.GetLong();
        this.Command = {};
        this.Command.id = Reader.GetLong();
        this.bReverse = Reader.GetBool();
        switch(this.Command.id){
            case moveTo:
            case lineTo:
            {
                this.Command.X = Reader.GetString2();
                this.Command.Y = Reader.GetString2();
                break;
            }
            case bezier3:
            {
                this.Command.X0 = Reader.GetString2();
                this.Command.Y0 = Reader.GetString2();
                this.Command.X1 = Reader.GetString2();
                this.Command.Y1 = Reader.GetString2();
                break;
            }
            case bezier4:
            {
                this.Command.X0 = Reader.GetString2();
                this.Command.Y0 = Reader.GetString2();
                this.Command.X1 = Reader.GetString2();
                this.Command.Y1 = Reader.GetString2();
                this.Command.X2 = Reader.GetString2();
                this.Command.Y2 = Reader.GetString2();
                break;
            }
            case arcTo:
            {
                this.Command.hR = Reader.GetString2();
                this.Command.wR = Reader.GetString2();
                this.Command.stAng = Reader.GetString2();
                this.Command.swAng = Reader.GetString2();
                break;
            }
            case close:
            {
                break;
            }
        }
    };



    AscDFH.changesFactory[AscDFH.historyitem_PathSetStroke] = AscDFH.CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_PathSetExtrusionOk] = AscDFH.CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_PathSetFill] = AscDFH.CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_PathSetPathH] = AscDFH.CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_PathSetPathW] = AscDFH.CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_PathAddPathCommand] = CChangesDrawingsAddPathCommand;

    AscDFH.drawingsChangesMap[AscDFH.historyitem_PathSetStroke] = function(oClass, value){oClass.stroke = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_PathSetExtrusionOk] = function(oClass, value){oClass.extrusionOk = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_PathSetFill] = function(oClass, value){oClass.fill = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_PathSetPathH] = function(oClass, value){oClass.pathH = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_PathSetPathW] = function(oClass, value){oClass.pathW = value;};


    function Path()
{
    this.stroke      = null;
    this.extrusionOk = null;
    this.fill        = null;
    this.pathH       = null;
    this.pathW       = null;

    this.ArrPathCommandInfo = [];
    this.ArrPathCommand = [];


    this.Id = AscCommon.g_oIdCounter.Get_NewId();
    AscCommon.g_oTableId.Add(this, this.Id);
}

Path.prototype = {

    Get_Id: function()
    {
        return this.Id;
    },
    getObjectType: function()
    {
        return AscDFH.historyitem_type_Path;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var p = new Path();
        p.setStroke(this.stroke);
        p.setExtrusionOk(this.extrusionOk);
        p.setFill(this.fill);
        p.setPathH(this.pathH);
        p.setPathW(this.pathW);
        for(var i = 0; i < this.ArrPathCommandInfo.length; ++i)
        {
            var command = this.ArrPathCommandInfo[i];
            switch (command.id)
            {
                case moveTo:
                case lineTo:
                {
                    var x = command.X;
                    var y = command.Y;
                    p.addPathCommand({id: command.id, X: x, Y: y});
                    break;
                }
                case bezier3:
                {
                    var X0 = command.X0;
                    var Y0 = command.Y0;
                    var X1 = command.X1;
                    var Y1 = command.Y1;
                    p.addPathCommand({id: bezier3, X0: X0, Y0: Y0, X1: X1, Y1: Y1});
                    break;
                }
                case bezier4:
                {
                    var X0 = command.X0;
                    var Y0 = command.Y0;
                    var X1 = command.X1;
                    var Y1 = command.Y1;
                    var X2 = command.X2;
                    var Y2 = command.Y2;
                    p.addPathCommand({id: bezier4, X0: X0, Y0: Y0, X1: X1, Y1: Y1, X2: X2, Y2: Y2});
                    break;
                }
                case arcTo:
                {
                    var hR    = command.hR;
                    var wR    = command.wR;
                    var stAng = command.stAng;
                    var swAng = command.swAng;
                    p.addPathCommand({id: arcTo, hR: hR, wR: wR, stAng: stAng, swAng: swAng});
                    break;
                }
                case close:
                {
                    p.addPathCommand({id:close});
                    break;
                }
            }
        }
        return p;
    },

    setStroke: function(pr)
    {
        History.Add(new AscDFH.CChangesDrawingsBool(this, AscDFH.historyitem_PathSetStroke, this.stroke, pr));
        this.stroke = pr;
    },

    setExtrusionOk: function(pr)
    {
        History.Add(new AscDFH.CChangesDrawingsBool(this, AscDFH.historyitem_PathSetExtrusionOk, this.extrusionOk, pr));
        this.extrusionOk = pr;
    },

    setFill: function(pr)
    {
        History.Add(new AscDFH.CChangesDrawingsString(this, AscDFH.historyitem_PathSetFill, this.fill, pr));
        this.fill = pr;
    },

    setPathH: function(pr)
    {
        History.Add(new AscDFH.CChangesDrawingsLong(this, AscDFH.historyitem_PathSetPathH, this.pathH, pr));
        this.pathH = pr;
    },

    setPathW: function(pr)
    {
        History.Add(new AscDFH.CChangesDrawingsLong(this, AscDFH.historyitem_PathSetPathW, this.pathW, pr));
        this.pathW = pr;
    },

    addPathCommand: function(cmd)
    {
        History.Add(new CChangesDrawingsAddPathCommand(this, cmd, this.ArrPathCommandInfo.length));
        this.ArrPathCommandInfo.push(cmd);
    },

    moveTo: function(x, y)
    {
        this.addPathCommand({id:moveTo, X:x, Y:y});
    },

    lnTo: function(x, y)
    {
        this.addPathCommand({id:lineTo, X:x, Y:y});
    },

    arcTo: function(wR, hR, stAng, swAng)
    {
        this.addPathCommand({id: arcTo, wR: wR, hR: hR, stAng: stAng, swAng: swAng});
    },

    quadBezTo: function(x0, y0, x1, y1)
    {
        this.addPathCommand({id:bezier3, X0:x0, Y0:y0, X1:x1, Y1:y1});
    },

    cubicBezTo: function(x0, y0, x1, y1, x2, y2)
    {
        this.addPathCommand({id:bezier4, X0:x0, Y0:y0, X1:x1, Y1:y1, X2:x2, Y2:y2});
    },

    close: function()
    {
        this.addPathCommand({id:close});
    },

    recalculate: function(gdLst, bResetPathsInfo)
    {
        var ch, cw;
        if(this.pathW!=undefined)
        {
            if(this.pathW > MOVE_DELTA)
            {
                cw = (gdLst["w"]/this.pathW);
            }
            else
            {
                cw = 0;
            }
        }
        else
        {
            cw=1;
        }
        if(this.pathH!=undefined)
        {
            if(this.pathH > MOVE_DELTA)
            {
                ch = (gdLst["h"]/this.pathH);
            }
            else
            {
                ch = 0;
            }
        }
        else
        {
            ch=1;
        }
        var APCI=this.ArrPathCommandInfo, n = APCI.length, cmd;
        var x0, y0, x1, y1, x2, y2, wR, hR, stAng, swAng, lastX, lastY;
        for(var i=0; i<n; ++i)
        {
            cmd=APCI[i];
            switch(cmd.id)
            {
                case moveTo:
                case lineTo:
                {
                    x0=gdLst[cmd.X];
                    if(x0 === undefined)
                    {
                        x0 = parseInt(cmd.X, 10);
                    }

                    y0=gdLst[cmd.Y];
                    if(y0===undefined)
                    {
                        y0=parseInt(cmd.Y, 10);
                    }

                    this.ArrPathCommand[i] ={id:cmd.id, X:x0*cw, Y:y0*ch};

                    lastX=x0*cw;
                    lastY=y0*ch;

                    break;
                }
                case bezier3:
                {

                    x0=gdLst[cmd.X0];
                    if(x0===undefined)
                    {
                        x0=parseInt(cmd.X0, 10);
                    }

                    y0=gdLst[cmd.Y0];
                    if(y0===undefined)
                    {
                        y0=parseInt(cmd.Y0, 10);
                    }

                    x1=gdLst[cmd.X1];
                    if(x1===undefined)
                    {
                        x1=parseInt(cmd.X1, 10);
                    }

                    y1=gdLst[cmd.Y1];
                    if(y1===undefined)
                    {
                        y1=parseInt(cmd.Y1, 10);
                    }

                    this.ArrPathCommand[i]={id:bezier3, X0:x0*cw, Y0: y0*ch, X1:x1*cw, Y1:y1*ch};

                    lastX=x1*cw;
                    lastY=y1*ch;
                    break;
                }
                case bezier4:
                {
                    x0=gdLst[cmd.X0];
                    if(x0===undefined)
                    {
                        x0=parseInt(cmd.X0, 10);
                    }

                    y0=gdLst[cmd.Y0];
                    if(y0===undefined)
                    {
                        y0=parseInt(cmd.Y0, 10);
                    }

                    x1=gdLst[cmd.X1];
                    if(x1===undefined)
                    {
                        x1=parseInt(cmd.X1, 10);
                    }

                    y1=gdLst[cmd.Y1];
                    if(y1===undefined)
                    {
                        y1=parseInt(cmd.Y1, 10);
                    }

                    x2=gdLst[cmd.X2];
                    if(x2===undefined)
                    {
                        x2=parseInt(cmd.X2, 10);
                    }

                    y2=gdLst[cmd.Y2];
                    if(y2===undefined)
                    {
                        y2=parseInt(cmd.Y2, 10);
                    }


                    this.ArrPathCommand[i]={id:bezier4, X0:x0*cw, Y0: y0*ch, X1:x1*cw, Y1:y1*ch, X2:x2*cw, Y2:y2*ch};

                    lastX=x2*cw;
                    lastY=y2*ch;

                    break;
                }
                case arcTo:
                {
                    hR=gdLst[cmd.hR];

                    if(hR===undefined)
                    {
                        hR=parseInt(cmd.hR, 10);
                    }


                    wR=gdLst[cmd.wR];
                    if(wR===undefined)
                    {
                        wR=parseInt(cmd.wR, 10);
                    }

                    stAng=gdLst[cmd.stAng];
                    if(stAng===undefined)
                    {
                        stAng=parseInt(cmd.stAng, 10);
                    }


                    swAng=gdLst[cmd.swAng];
                    if(swAng===undefined)
                    {
                        swAng=parseInt(cmd.swAng, 10);
                    }


                    var a1 = stAng;
                    var a2 = stAng + swAng;
                    var a3 = swAng;

                    stAng = Math.atan2(ch * Math.sin(a1 * cToRad), cw * Math.cos(a1 * cToRad)) / cToRad;
                    swAng = Math.atan2(ch * Math.sin(a2 * cToRad), cw * Math.cos(a2 * cToRad)) / cToRad - stAng;

                    if((swAng > 0) && (a3 < 0)) swAng -= 21600000;
                    if((swAng < 0) && (a3 > 0)) swAng += 21600000;
                    if(swAng == 0 && a3 != 0) swAng = 21600000;

                    var a = wR*cw;
                    var b = hR*ch;
                    var sin2 = Math.sin(stAng*cToRad);
                    var cos2 = Math.cos(stAng*cToRad);
                    var _xrad = cos2 / a;
                    var _yrad = sin2 / b;
                    var l = 1 / Math.sqrt(_xrad * _xrad + _yrad * _yrad);
                    var xc = lastX - l * cos2;
                    var yc = lastY - l * sin2;

                    var sin1 = Math.sin((stAng+swAng)*cToRad);
                    var cos1 = Math.cos((stAng+swAng)*cToRad);
                    var _xrad1 = cos1 / a;
                    var _yrad1 = sin1 / b;
                    var l1 = 1 / Math.sqrt(_xrad1 * _xrad1 + _yrad1 * _yrad1);

                    this.ArrPathCommand[i]={id: arcTo,
                        stX: lastX,
                        stY: lastY,
                        wR: wR*cw,
                        hR: hR*ch,
                        stAng: stAng*cToRad,
                        swAng: swAng*cToRad};

                    lastX = xc + l1 * cos1;
                    lastY = yc + l1 * sin1;


                    break;
                }
                case close:
                {
                    this.ArrPathCommand[i]={id: close};
                    break;
                }
                default:
                {
                    break;
                }
            }
        }
        if(bResetPathsInfo){
            delete this.ArrPathCommandInfo;
        }
    },
    recalculate2: function(gdLst, bResetPathsInfo)
    {
        var k = 10e-10;
        var APCI=this.ArrPathCommandInfo, n = APCI.length, cmd;
        var stAng, swAng, lastX, lastY;
        for(var i=0; i<n; ++i)
        {
            cmd=APCI[i];
            switch(cmd.id)
            {
                case moveTo:
                case lineTo:
                {

                    lastX=cmd.X*k;
                    lastY=cmd.Y*k;
                    this.ArrPathCommand[i] ={id:cmd.id, X:lastX, Y:lastY};
                    break;
                }
                case bezier3:
                {

                    lastX=cmd.X1;
                    lastY=cmd.Y1;

                    this.ArrPathCommand[i]={id:bezier3, X0: cmd.X0*k, Y0: cmd.Y0*k, X1:lastX, Y1:lastY};

                    break;
                }
                case bezier4:
                {
                    lastX=cmd.X2;
                    lastY=cmd.Y2;

                    this.ArrPathCommand[i]={id:bezier4, X0: cmd.X0*k, Y0: cmd.Y0*k, X1: cmd.X1*k, Y1: cmd.Y1*k, X2:lastX, Y2:lastY};
                    break;
                }
                case arcTo:
                {


                    var a1 = cmd.stAng;
                    var a2 = cmd.stAng + cmd.swAng;
                    var a3 = cmd.swAng;

                    stAng = Math.atan2(k * Math.sin(a1 * cToRad), k * Math.cos(a1 * cToRad)) / cToRad;
                    swAng = Math.atan2(k * Math.sin(a2 * cToRad), k * Math.cos(a2 * cToRad)) / cToRad - cmd.stAng;

                    if((swAng > 0) && (a3 < 0)) swAng -= 21600000;
                    if((swAng < 0) && (a3 > 0)) swAng += 21600000;
                    if(swAng == 0 && a3 != 0) swAng = 21600000;

                    var a = cmd.wR*k;
                    var b = cmd.hR*k;
                    var sin2 = Math.sin(stAng*cToRad);
                    var cos2 = Math.cos(stAng*cToRad);
                    var _xrad = cos2 / a;
                    var _yrad = sin2 / b;
                    var l = 1 / Math.sqrt(_xrad * _xrad + _yrad * _yrad);
                    var xc = lastX - l * cos2;
                    var yc = lastY - l * sin2;

                    var sin1 = Math.sin((stAng+swAng)*cToRad);
                    var cos1 = Math.cos((stAng+swAng)*cToRad);
                    var _xrad1 = cos1 / a;
                    var _yrad1 = sin1 / b;
                    var l1 = 1 / Math.sqrt(_xrad1 * _xrad1 + _yrad1 * _yrad1);

                    this.ArrPathCommand[i]={id: arcTo,
                        stX: lastX,
                        stY: lastY,
                        wR: cmd.wR*k,
                        hR: cmd.hR*k,
                        stAng: stAng*cToRad,
                        swAng: swAng*cToRad};

                    lastX = xc + l1 * cos1;
                    lastY = yc + l1 * sin1;


                    break;
                }
                case close:
                {
                    this.ArrPathCommand[i]={id: close};
                    break;
                }
                default:
                {
                    break;
                }
            }
        }
       // if(bResetPathsInfo)
        {
            delete this.ArrPathCommandInfo;
        }
    },

    draw: function(shape_drawer)
    {
        if (shape_drawer.bIsCheckBounds === true && this.fill == "none")
        {
            // это для текстур
            return;
        }
        var bIsDrawLast = false;
        var path = this.ArrPathCommand;
        shape_drawer._s();
        for(var j = 0, l = path.length; j < l; ++j)
        {
            var cmd=path[j];
            switch(cmd.id)
            {
                case moveTo:
                {
                    bIsDrawLast = true;
                    shape_drawer._m(cmd.X, cmd.Y);
                    break;
                }
                case lineTo:
                {
                    bIsDrawLast = true;
                    shape_drawer._l(cmd.X, cmd.Y);
                    break;
                }
                case bezier3:
                {
                    bIsDrawLast = true;
                    shape_drawer._c2(cmd.X0, cmd.Y0, cmd.X1, cmd.Y1);
                    break;
                }
                case bezier4:
                {
                    bIsDrawLast = true;
                    shape_drawer._c(cmd.X0, cmd.Y0, cmd.X1, cmd.Y1, cmd.X2, cmd.Y2);
                    break;
                }
                case arcTo:
                {
                    bIsDrawLast = true;
                    ArcToCurvers(shape_drawer, cmd.stX, cmd.stY, cmd.wR, cmd.hR, cmd.stAng, cmd.swAng);
                    break;
                }
                case close:
                {
                    shape_drawer._z();
                    break;
                }
            }
        }

        if (bIsDrawLast)
        {
            shape_drawer.drawFillStroke(true, this.fill, this.stroke && !shape_drawer.bIsNoStrokeAttack);
        }

        shape_drawer._e();
    },

    check_bounds: function(checker)
    {
        var path=this.ArrPathCommand;
        for(var j=0, l=path.length; j<l; ++j)
        {
            var cmd=path[j];
            switch(cmd.id)
            {
                case moveTo:
                {
                    checker._m(cmd.X, cmd.Y);
                    break;
                }
                case lineTo:
                {
                    checker._l(cmd.X, cmd.Y);
                    break;
                }
                case bezier3:
                {
                    checker._c2(cmd.X0, cmd.Y0, cmd.X1, cmd.Y1);
                    break;
                }
                case bezier4:
                {
                    checker._c(cmd.X0, cmd.Y0, cmd.X1, cmd.Y1, cmd.X2, cmd.Y2);
                    break;
                }
                case arcTo:
                {
                    ArcToCurvers(checker, cmd.stX, cmd.stY, cmd.wR, cmd.hR, cmd.stAng, cmd.swAng);
                    break;
                }
                case close:
                {
                    checker._z();
                    break;
                }
            }
        }
    },

    hitInInnerArea: function(canvasContext, x, y)
    {
        if(this.fill === "none")
            return false;

        var _arr_commands = this.ArrPathCommand;
        var _commands_count = _arr_commands.length;
        var _command_index;
        var _command;
        canvasContext.beginPath();
        for(_command_index = 0; _command_index < _commands_count; ++_command_index)
        {
            _command = _arr_commands[_command_index];
            switch(_command.id)
            {
                case moveTo:
                {
                    canvasContext.moveTo(_command.X, _command.Y);
                    break;
                }
                case lineTo:
                {
                    canvasContext.lineTo(_command.X, _command.Y);
                    break;
                }
                case arcTo:
                {
                    ArcToOnCanvas(canvasContext, _command.stX, _command.stY, _command.wR, _command.hR, _command.stAng, _command.swAng);
                    break;
                }
                case bezier3:
                {
                    canvasContext.quadraticCurveTo(_command.X0, _command.Y0, _command.X1, _command.Y1);
                    break;
                }
                case bezier4:
                {
                    canvasContext.bezierCurveTo(_command.X0, _command.Y0, _command.X1, _command.Y1, _command.X2, _command.Y2);
                    break;
                }
                case close:
                {
                    canvasContext.closePath();
                    if(canvasContext.isPointInPath(x, y))
                    {
                        return true;
                    }
                }
            }
        }
        return false;
    },

    hitInPath: function(canvasContext, x, y)
    {
        var _arr_commands = this.ArrPathCommand;
        var _commands_count = _arr_commands.length;
        var _command_index;
        var _command;
        var _last_x, _last_y;
        var _begin_x, _begin_y;
        for(_command_index = 0; _command_index< _commands_count; ++_command_index)
        {
            _command = _arr_commands[_command_index];
            switch(_command.id)
            {
                case moveTo:
                {
                    _last_x = _command.X;
                    _last_y = _command.Y;
                    _begin_x = _command.X;
                    _begin_y = _command.Y;
                    break;
                }
                case lineTo:
                {
                    if(HitInLine(canvasContext, x, y, _last_x, _last_y, _command.X, _command.Y))
                        return true;
                    _last_x = _command.X;
                    _last_y = _command.Y;
                    break;
                }
                case arcTo:
                {
                    if(HitToArc(canvasContext, x, y,  _command.stX, _command.stY, _command.wR, _command.hR, _command.stAng, _command.swAng))
                        return true;
                    _last_x=(_command.stX-_command.wR*Math.cos(_command.stAng)+_command.wR*Math.cos(_command.swAng));
                    _last_y=(_command.stY-_command.hR*Math.sin(_command.stAng)+_command.hR*Math.sin(_command.swAng));
                    break;
                }
                case bezier3:
                {
                    if(HitInBezier3(canvasContext, x, y, _last_x, _last_y, _command.X0, _command.Y0, _command.X1, _command.Y1))
                        return true;
                    _last_x=_command.X1;
                    _last_y=_command.Y1;
                    break;
                }
                case bezier4:
                {
                    if(HitInBezier4(canvasContext, x, y, _last_x, _last_y, _command.X0, _command.Y0, _command.X1, _command.Y1, _command.X2, _command.Y2))
                        return true;
                    _last_x=_command.X2;
                    _last_y=_command.Y2;
                    break;
                }
                case close:
                {
                    if(HitInLine(canvasContext, x, y, _last_x, _last_y, _begin_x, _begin_y))
                        return true;
                }
            }
        }
        return false;
    },

    isSmartLine : function()
    {
        if (this.ArrPathCommand.length != 2)
            return false;

        if (this.ArrPathCommand[0].id == moveTo && this.ArrPathCommand[1].id == lineTo)
        {
            if (Math.abs(this.ArrPathCommand[0].X - this.ArrPathCommand[1].X) < 0.0001)
                return true;

            if (Math.abs(this.ArrPathCommand[0].Y - this.ArrPathCommand[1].Y) < 0.0001)
                return true;
        }

        return false;
    },

    isSmartRect : function()
    {
        if (this.ArrPathCommand.length != 5)
            return false;

        if (this.ArrPathCommand[0].id != moveTo ||
            this.ArrPathCommand[1].id != lineTo ||
            this.ArrPathCommand[2].id != lineTo ||
            this.ArrPathCommand[3].id != lineTo ||
            (this.ArrPathCommand[4].id != lineTo && this.ArrPathCommand[4].id != close))
            return false;

        var _float_eps = 0.0001;
        if (Math.abs(this.ArrPathCommand[0].X - this.ArrPathCommand[1].X) < _float_eps)
        {
            if (Math.abs(this.ArrPathCommand[1].Y - this.ArrPathCommand[2].Y) < _float_eps)
            {
                if (Math.abs(this.ArrPathCommand[2].X - this.ArrPathCommand[3].X) < _float_eps &&
                    Math.abs(this.ArrPathCommand[3].Y - this.ArrPathCommand[0].Y) < _float_eps)
                {
                    if (this.ArrPathCommand[4].id == close)
                        return true;

                    if (Math.abs(this.ArrPathCommand[0].X - this.ArrPathCommand[4].X) < _float_eps &&
                        Math.abs(this.ArrPathCommand[0].Y - this.ArrPathCommand[4].Y) < _float_eps)
                    {
                        return true;
                    }
                }
            }
        }
        else if (Math.abs(this.ArrPathCommand[0].Y - this.ArrPathCommand[1].Y) < _float_eps)
        {
            if (Math.abs(this.ArrPathCommand[1].X - this.ArrPathCommand[2].X) < _float_eps)
            {
                if (Math.abs(this.ArrPathCommand[2].Y - this.ArrPathCommand[3].Y) < _float_eps &&
                    Math.abs(this.ArrPathCommand[3].X - this.ArrPathCommand[0].X) < _float_eps)
                {
                    if (this.ArrPathCommand[4].id == close)
                        return true;

                    if (Math.abs(this.ArrPathCommand[0].X - this.ArrPathCommand[4].X) < _float_eps &&
                        Math.abs(this.ArrPathCommand[0].Y - this.ArrPathCommand[4].Y) < _float_eps)
                    {
                        return true;
                    }
                }
            }
        }

        return false;
    },

    drawSmart : function(shape_drawer)
    {
        var _graphics   = shape_drawer.Graphics;
        var _full_trans = _graphics.m_oFullTransform;

        if (!_graphics || !_full_trans || undefined == _graphics.m_bIntegerGrid || true === shape_drawer.bIsNoSmartAttack)
            return this.draw(shape_drawer);

        var bIsTransformed = (_full_trans.shx == 0 && _full_trans.shy == 0) ? false : true;

        if (bIsTransformed)
            return this.draw(shape_drawer);

        var isLine = this.isSmartLine();
        var isRect = false;
        if (!isLine)
            isRect = this.isSmartRect();

        if (window["NATIVE_EDITOR_ENJINE"] || ( !isLine && !isRect))
            return this.draw(shape_drawer);

        var _old_int = _graphics.m_bIntegerGrid;

        if (false == _old_int)
            _graphics.SetIntegerGrid(true);

        var dKoefMMToPx = Math.max(_graphics.m_oCoordTransform.sx, 0.001);

        var _ctx = _graphics.m_oContext;
        var bIsStroke = (shape_drawer.bIsNoStrokeAttack || (this.stroke !== true)) ? false : true;
        var bIsEven = false;
        if (bIsStroke)
        {
            var _lineWidth = Math.max((shape_drawer.StrokeWidth * dKoefMMToPx + 0.5) >> 0, 1);
            _ctx.lineWidth = _lineWidth;

            if (_lineWidth & 0x01 == 0x01)
                bIsEven = true;
        }

        var bIsDrawLast = false;
        var path = this.ArrPathCommand;
        shape_drawer._s();

        if (!isRect)
        {
            for(var j = 0, l = path.length; j < l; ++j)
            {
                var cmd=path[j];
                switch(cmd.id)
                {
                    case moveTo:
                    {
                        bIsDrawLast = true;

                        var _x = (_full_trans.TransformPointX(cmd.X, cmd.Y)) >> 0;
                        var _y = (_full_trans.TransformPointY(cmd.X, cmd.Y)) >> 0;
                        if (bIsEven)
                        {
                            _x -= 0.5;
                            _y -= 0.5;
                        }
                        _ctx.moveTo(_x, _y);
                        break;
                    }
                    case lineTo:
                    {
                        bIsDrawLast = true;

                        var _x = (_full_trans.TransformPointX(cmd.X, cmd.Y)) >> 0;
                        var _y = (_full_trans.TransformPointY(cmd.X, cmd.Y)) >> 0;
                        if (bIsEven)
                        {
                            _x -= 0.5;
                            _y -= 0.5;
                        }
                        _ctx.lineTo(_x, _y);
                        break;
                    }
                    case close:
                    {
                        _ctx.closePath();
                        break;
                    }
                }
            }
        }
        else
        {
            var minX = 100000;
            var minY = 100000;
            var maxX = -100000;
            var maxY = -100000;
            bIsDrawLast = true;
            for(var j = 0, l = path.length; j < l; ++j)
            {
                var cmd=path[j];
                switch(cmd.id)
                {
                    case moveTo:
                    case lineTo:
                    {
                        if (minX > cmd.X)
                            minX = cmd.X;
                        if (minY > cmd.Y)
                            minY = cmd.Y;

                        if (maxX < cmd.X)
                            maxX = cmd.X;
                        if (maxY < cmd.Y)
                            maxY = cmd.Y;

                        break;
                    }
                    default:
                        break;
                }
            }

            var _x1 = (_full_trans.TransformPointX(minX, minY)) >> 0;
            var _y1 = (_full_trans.TransformPointY(minX, minY)) >> 0;
            var _x2 = (_full_trans.TransformPointX(maxX, maxY)) >> 0;
            var _y2 = (_full_trans.TransformPointY(maxX, maxY)) >> 0;

            if (bIsEven)
                _ctx.rect(_x1 + 0.5, _y1 + 0.5, _x2 - _x1, _y2 - _y1);
            else
                _ctx.rect(_x1, _y1, _x2 - _x1, _y2 - _y1);
        }

        if (bIsDrawLast)
        {
            shape_drawer.drawFillStroke(true, this.fill, bIsStroke);
        }

        shape_drawer._e();

        if (false == _old_int)
            _graphics.SetIntegerGrid(false);
    }
};




    function Path2(oPathMemory)
    {
        this.stroke      = null;
        this.extrusionOk = null;
        this.fill        = null;
        this.pathH       = null;
        this.pathW       = null;



        this.startPos = 0;
        this.size = 25;

        this.PathMemory = oPathMemory;
        this.ArrPathCommand = oPathMemory.ArrPathCommand;
        this.curLen = 0;

        this.lastX = null;
        this.lastY = null;
    }

    Path2.prototype = {

        checkArray: function(nSize){
            this.ArrPathCommand[this.startPos] += nSize;
            this.PathMemory.curPos = this.startPos + this.ArrPathCommand[this.startPos];
            if(this.PathMemory.curPos + 1 > this.ArrPathCommand.length){

                var aNewArray = new Float64Array((((3/2)*(this.PathMemory.curPos + 1)) >> 0) + 1);
                for(var i = 0; i < this.ArrPathCommand.length; ++i){
                    aNewArray[i] = this.ArrPathCommand[i];
                }
                this.PathMemory.ArrPathCommand = aNewArray;
                this.ArrPathCommand = aNewArray;
            }
        },


        setStroke: function(pr)
        {

            this.stroke = pr;
        },

        setExtrusionOk: function(pr)
        {

            this.extrusionOk = pr;
        },

        setFill: function(pr)
        {

            this.fill = pr;
        },

        setPathH: function(pr)
        {

            this.pathH = pr;
        },

        setPathW: function(pr)
        {

            this.pathW = pr;
        },

        addPathCommand: function(cmd)
        {

            this.ArrPathCommand.push(cmd);
        },

        moveTo: function(x, y)
        {
            this.lastX = x*10e-10;
            this.lastY = y*10e-10;
            this.checkArray(3);
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = moveTo;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = this.lastX;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = this.lastY;
        },

        lnTo: function(x, y)
        {

            this.lastX = x*10e-10;
            this.lastY = y*10e-10;
            this.checkArray(3);
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = lineTo;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = this.lastX;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = this.lastY;
        },

        arcTo: function(wR, hR, stAng, swAng)
        {

            var a1 = stAng;
            var a2 = stAng + swAng;
            var a3 = swAng;

            stAng = Math.atan2(10e-10 * Math.sin(a1 * cToRad), 10e-10 * Math.cos(a1 * cToRad)) / cToRad;
            swAng = Math.atan2(10e-10 * Math.sin(a2 * cToRad), 10e-10 * Math.cos(a2 * cToRad)) / cToRad - stAng;

            if((swAng > 0) && (a3 < 0)) swAng -= 21600000;
            if((swAng < 0) && (a3 > 0)) swAng += 21600000;
            if(swAng == 0 && a3 != 0) swAng = 21600000;

            var a = wR*10e-10;
            var b = hR*10e-10;
            var sin2 = Math.sin(stAng*cToRad);
            var cos2 = Math.cos(stAng*cToRad);
            var _xrad = cos2 / a;
            var _yrad = sin2 / b;
            var l = 1 / Math.sqrt(_xrad * _xrad + _yrad * _yrad);
            var xc = this.lastX - l * cos2;
            var yc = this.lastY - l * sin2;

            var sin1 = Math.sin((stAng+swAng)*cToRad);
            var cos1 = Math.cos((stAng+swAng)*cToRad);
            var _xrad1 = cos1 / a;
            var _yrad1 = sin1 / b;
            var l1 = 1 / Math.sqrt(_xrad1 * _xrad1 + _yrad1 * _yrad1);




            this.checkArray(7);
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = arcTo;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = this.lastX;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = this.lastY;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = wR*10e-10;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = hR*10e-10;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = stAng*cToRad;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = swAng*cToRad;
        },

        quadBezTo: function(x0, y0, x1, y1)
        {


            this.lastX = x1*10e-10;
            this.lastY = y1*10e-10;


            this.checkArray(5);
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = bezier3;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = x0*10e-10;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = y0*10e-10;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = this.lastX;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = this.lastY;
        },

        cubicBezTo: function(x0, y0, x1, y1, x2, y2)
        {


            this.lastX = x2*10e-10;
            this.lastY = y2*10e-10;

            this.checkArray(7);
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = bezier4;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = x0*10e-10;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = y0*10e-10;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = y1*10e-10;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = y1*10e-10;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = this.lastX;
            this.ArrPathCommand[this.startPos + (this.curLen++) + 1] = this.lastY;
        },


        close: function()
        {
            this.checkArray(1);
            this.ArrPathCommand.push(close);
        },

        draw: function(shape_drawer)
        {
            if (shape_drawer.bIsCheckBounds === true && this.fill == "none")
            {
                // это для текстур
                return;
            }
            var bIsDrawLast = false;
            var path = this.ArrPathCommand;
            shape_drawer._s();
            var i = 0;
            var len = this.PathMemory.ArrPathCommand[this.startPos];
            while(i < len)
            {
                var cmd=path[this.startPos + i + 1];
                switch(cmd)
                {
                    case moveTo:
                    {
                        bIsDrawLast = true;
                        shape_drawer._m(path[this.startPos + i+2], path[this.startPos + i + 3]);
                        i+=3;
                        break;
                    }
                    case lineTo:
                    {
                        bIsDrawLast = true;
                        shape_drawer._l(path[this.startPos + i+2], path[this.startPos + i + 3]);
                        i+=3;
                        break;
                    }
                    case bezier3:
                    {
                        bIsDrawLast = true;
                        shape_drawer._c2(path[this.startPos + i+2], path[this.startPos + i + 3], path[this.startPos + i+4], path[this.startPos + i + 5]);
                        i+=5;
                        break;
                    }
                    case bezier4:
                    {
                        bIsDrawLast = true;
                        shape_drawer._c(path[this.startPos + i+2], path[this.startPos + i + 3], path[this.startPos + i+4], path[this.startPos + i + 5], path[this.startPos + i+6], path[this.startPos + i + 7]);
                        i+=7;
                        break;
                    }
                    case arcTo:
                    {
                        bIsDrawLast = true;
                        ArcToCurvers(shape_drawer, path[this.startPos + i + 2], path[this.startPos + i + 3], path[this.startPos + i + 4], path[this.startPos + i + 5], path[this.startPos + i + 6], path[this.startPos + i + 7]);
                        i+=7;
                        break;
                    }
                    case close:
                    {
                        shape_drawer._z();
                        i+=1;
                        break;
                    }
                }
            }

            if (bIsDrawLast)
            {
                shape_drawer.drawFillStroke(true, "normal", this.stroke && !shape_drawer.bIsNoStrokeAttack);
            }

            shape_drawer._e();
        },


        getCommandByIndex: function(idx){
            var i = 0;
            var path = this.PathMemory.ArrPathCommand;
            var len = path[this.startPos];
            var commandIndex = 0;
            while(i < len)
            {
                var cmd = path[this.startPos + i + 1];
                switch(cmd)
                {
                    case moveTo:
                    {
                        if(idx === commandIndex){
                            return {id: moveTo, X: path[this.startPos + i + 2], Y: path[this.startPos + i + 3]};
                        }
                        i+=3;
                        break;
                    }
                    case lineTo:
                    {
                        if(idx === commandIndex){
                            return {id: moveTo, X: path[this.startPos + i + 2], Y: path[this.startPos + i + 3]};
                        }
                        i+=3;
                        break;
                    }
                    case bezier3:
                    {
                        if(idx === commandIndex){
                            return {id: bezier3, X0: path[this.startPos + i+2], Y0: path[this.startPos + i + 3], X1: path[this.startPos + i+4], Y1: path[this.startPos + i + 5]};
                        }
                        i+=5;
                        break;
                    }
                    case bezier4:
                    {
                        if(idx === commandIndex){
                            return {id: bezier4, X0: path[this.startPos + i+2], Y0: path[this.startPos + i + 3], X1: path[this.startPos + i+4], Y1: path[this.startPos + i + 5],  X2: path[this.startPos + i+6], Y2: path[this.startPos + i + 7]};
                        }
                        i+=7;
                        break;
                    }
                    case arcTo:
                    {
                        if(idx === commandIndex){
                            return {id: arcTo,
                                stX: path[this.startPos + i + 2],
                                stY: path[this.startPos + i + 3],
                                wR: path[this.startPos + i + 4],
                                hR: path[this.startPos + i + 5],
                                stAng: path[this.startPos + i + 6],
                                swAng: path[this.startPos + i + 7]};
                        }

                        i+=7;
                        break;
                    }
                    case close:
                    {

                        if(idx === commandIndex){
                            return {id: close};
                        }
                        i+=1;
                        break;
                    }
                }
                ++commandIndex;
            }
            return null;
        },

        check_bounds: function(shape_drawer)
        {
            var path = this.ArrPathCommand;

            var i = 0;
            var len = this.PathMemory.ArrPathCommand[this.startPos];
            while(i < len)
            {
                var cmd=path[this.startPos + i + 1];
                switch(cmd)
                {
                    case moveTo:
                    {

                        shape_drawer._m(path[this.startPos + i+2], path[this.startPos + i + 3]);
                        i+=3;
                        break;
                    }
                    case lineTo:
                    {

                        shape_drawer._l(path[this.startPos + i+2], path[this.startPos + i + 3]);
                        i+=3;
                        break;
                    }
                    case bezier3:
                    {

                        shape_drawer._c2(path[this.startPos + i+2], path[this.startPos + i + 3], path[this.startPos + i+4], path[this.startPos + i + 5]);
                        i+=5;
                        break;
                    }
                    case bezier4:
                    {

                        shape_drawer._c(path[this.startPos + i+2], path[this.startPos + i + 3], path[this.startPos + i+4], path[this.startPos + i + 5], path[this.startPos + i+6], path[this.startPos + i + 7]);
                        i+=7;
                        break;
                    }
                    case arcTo:
                    {

                        ArcToCurvers(shape_drawer, path[this.startPos + i + 2], path[this.startPos + i + 3], path[this.startPos + i + 4], path[this.startPos + i + 5], path[this.startPos + i + 6], path[this.startPos + i + 7]);
                        i+=7;
                        break;
                    }
                    case close:
                    {
                        shape_drawer._z();
                        i+=1;
                        break;
                    }
                }
            }

        },


        isSmartLine : function()
        {
            var i = 0;
            var path = this.PathMemory.ArrPathCommand;
            var len = path[this.startPos];
            var commandIndex = 0;
            while(i < len)
            {
                if(commandIndex > 1){
                    return false;
                }
                var cmd = path[this.startPos + i + 1];
                switch(cmd)
                {
                    case moveTo:
                    {
                        if(0 !== commandIndex){
                            return false;
                        }
                        i+=3;
                        break;
                    }
                    case lineTo:
                    {
                        if(1 !== commandIndex){
                            return false;
                        }
                        i+=3;
                        break;
                    }
                    default:
                    {
                        return false;
                    }
                }
                ++commandIndex;
            }

            return true;
        },

        isSmartRect : function()
        {
            var i = 0;
            var path = this.PathMemory.ArrPathCommand;
            var len = path[this.startPos];
            var commandIndex = 0;
            var x0, y0, x1, y1, x2, y2, x3, y3, x4, y4,  isCommand4Close = false;
            while(i < len)
            {
                if(commandIndex > 4){
                    return false;
                }
                var cmd = path[this.startPos + i + 1];
                switch(cmd)
                {
                    case moveTo:
                    {
                        if(0 !== commandIndex){
                            return false;
                        }
                        x0 = path[this.startPos + i + 2];
                        y0 = path[this.startPos + i + 3];
                        i+=3;
                        break;
                    }
                    case lineTo:
                    {
                        if(commandIndex === 1){
                            x1 = path[this.startPos + i + 2];
                            y1 = path[this.startPos + i + 3];
                        }
                        else if(commandIndex === 2){
                            x2 = path[this.startPos + i + 2];
                            y2 = path[this.startPos + i + 3];
                        }
                        else if(commandIndex === 3){
                            x3 = path[this.startPos + i + 2];
                            y3 = path[this.startPos + i + 3];
                        }
                        else if(commandIndex === 4){
                            x4 = path[this.startPos + i + 2];
                            y4 = path[this.startPos + i + 3];
                        }
                        i+=3;
                        break;
                    }
                    case close:
                    {
                        if(4 !== commandIndex){
                            return false;
                        }
                        isCommand4Close = true;
                        break;
                    }
                    default:
                    {
                        return false;
                    }
                }
                ++commandIndex;
            }

            if (AscFormat.fApproxEqual(x0, x1))
            {
                if (AscFormat.fApproxEqual(y1, y2))
                {
                    if (AscFormat.fApproxEqual(x2, x3)&&
                        AscFormat.fApproxEqual(y3, y0))
                    {
                        if (isCommand4Close)
                            return true;

                        if (AscFormat.fApproxEqual(x0, x4) &&
                            AscFormat.fApproxEqual(y0, y4))
                        {
                            return true;
                        }
                    }
                }
            }
            else if (AscFormat.fApproxEqual(y0, y1))
            {
                if (AscFormat.fApproxEqual(x1, x2))
                {
                    if (AscFormat.fApproxEqual(y2, y3) &&
                        AscFormat.fApproxEqual(x3, x0))
                    {
                        if (isCommand4Close)
                            return true;

                        if (AscFormat.fApproxEqual(x0, x4) &&
                            AscFormat.fApproxEqual(y0, y4))
                        {
                            return true;
                        }
                    }
                }
            }

            return false;
        },

        drawSmart : function(shape_drawer)
        {
            var _graphics   = shape_drawer.Graphics;
            var _full_trans = _graphics.m_oFullTransform;

            if (!_graphics || !_full_trans || undefined == _graphics.m_bIntegerGrid || true === shape_drawer.bIsNoSmartAttack)
                return this.draw(shape_drawer);

            var bIsTransformed = (_full_trans.shx == 0 && _full_trans.shy == 0) ? false : true;

            if (bIsTransformed)
                return this.draw(shape_drawer);

            var isLine = this.isSmartLine();
            var isRect = false;
            if (!isLine)
                isRect = this.isSmartRect();

            if (window["NATIVE_EDITOR_ENJINE"] || ( !isLine && !isRect))
                return this.draw(shape_drawer);

            var _old_int = _graphics.m_bIntegerGrid;

            if (false == _old_int)
                _graphics.SetIntegerGrid(true);

            var dKoefMMToPx = Math.max(_graphics.m_oCoordTransform.sx, 0.001);

            var _ctx = _graphics.m_oContext;
            var bIsStroke = (shape_drawer.bIsNoStrokeAttack || (this.stroke !== true)) ? false : true;
            var bIsEven = false;
            if (bIsStroke)
            {
                var _lineWidth = Math.max((shape_drawer.StrokeWidth * dKoefMMToPx + 0.5) >> 0, 1);
                _ctx.lineWidth = _lineWidth;

                if (_lineWidth & 0x01 == 0x01)
                    bIsEven = true;
            }

            var bIsDrawLast = false;
            var path = this.ArrPathCommand;
            shape_drawer._s();

            if (!isRect)
            {
                var i = 0;
                var len = this.PathMemory.ArrPathCommand[this.startPos];
                var X, Y;
                while(i < len)
                {
                    var cmd=path[this.startPos + i + 1];
                    switch(cmd)
                    {
                        case moveTo:
                        {
                            bIsDrawLast = true;
                            X = path[this.startPos + i+2];
                            Y = path[this.startPos + i+3];
                            var _x = (_full_trans.TransformPointX(X, Y)) >> 0;
                            var _y = (_full_trans.TransformPointY(X, Y)) >> 0;
                            if (bIsEven)
                            {
                                _x -= 0.5;
                                _y -= 0.5;
                            }
                            _ctx.moveTo(_x, _y);
                            i+=3;
                            break;
                        }
                        case lineTo:
                        {
                            bIsDrawLast = true;
                            X = path[this.startPos + i+2];
                            Y = path[this.startPos + i+3];
                            var _x = (_full_trans.TransformPointX(X, Y)) >> 0;
                            var _y = (_full_trans.TransformPointY(X, Y)) >> 0;
                            if (bIsEven)
                            {
                                _x -= 0.5;
                                _y -= 0.5;
                            }
                            _ctx.lineTo(_x, _y);

                            i+=3;
                            break;
                        }
                        case bezier3:
                        {
                            bIsDrawLast = true;

                            i+=5;
                            break;
                        }
                        case bezier4:
                        {
                            bIsDrawLast = true;
                            i+=7;
                            break;
                        }
                        case arcTo:
                        {
                            bIsDrawLast = true;
                            i+=7;
                            break;
                        }
                        case close:
                        {
                            _ctx.closePath();
                            i+=1;
                            break;
                        }
                    }
                }
            }
            else
            {
                var minX = 100000;
                var minY = 100000;
                var maxX = -100000;
                var maxY = -100000;
                bIsDrawLast = true;
                var i = 0;
                var len = this.PathMemory.ArrPathCommand[this.startPos], X, Y;
                while(i < len)
                {
                    var cmd=path[this.startPos + i + 1];
                    switch(cmd)
                    {
                        case moveTo:
                        case lineTo:
                        {
                            bIsDrawLast = true;
                            X = path[this.startPos + i + 2];
                            Y = path[this.startPos + i + 3];
                            if (minX > X)
                                minX = X;
                            if (minY > Y)
                                minY = Y;

                            if (maxX < X)
                                maxX = X;
                            if (maxY < Y)
                                maxY = Y;

                            i+=3;
                            break;
                        }
                        case bezier3:
                        {
                            bIsDrawLast = true;
                            i+=5;
                            break;
                        }
                        case bezier4:
                        {
                            bIsDrawLast = true;
                            i+=7;
                            break;
                        }
                        case arcTo:
                        {
                            bIsDrawLast = true;
                            i+=7;
                            break;
                        }
                        case close:
                        {
                            i+=1;
                            break;
                        }
                    }
                }

                var _x1 = (_full_trans.TransformPointX(minX, minY)) >> 0;
                var _y1 = (_full_trans.TransformPointY(minX, minY)) >> 0;
                var _x2 = (_full_trans.TransformPointX(maxX, maxY)) >> 0;
                var _y2 = (_full_trans.TransformPointY(maxX, maxY)) >> 0;

                if (bIsEven)
                    _ctx.rect(_x1 + 0.5, _y1 + 0.5, _x2 - _x1, _y2 - _y1);
                else
                    _ctx.rect(_x1, _y1, _x2 - _x1, _y2 - _y1);
            }

            if (bIsDrawLast)
            {
                shape_drawer.drawFillStroke(true, this.fill, bIsStroke);
            }

            shape_drawer._e();

            if (false == _old_int)
                _graphics.SetIntegerGrid(false);
        }
    };





function partition_bezier3(x0, y0, x1, y1, x2, y2, epsilon)
{
    var dx01 = x1 - x0;
    var dy01 = y1 - y0;
    var dx12 = x2 - x1;
    var dy12 = y2 - y1;

    var r01 = Math.sqrt(dx01*dx01 + dy01*dy01);
    var r12 = Math.sqrt(dx12*dx12 + dy12*dy12);
    if(Math.max(r01, r12) < epsilon)
    {
        return [{x: x0, y: y0}, {x: x1, y: y1}, {x: x2, y: y2}];
    }

    var x01 = (x0 + x1)*0.5;
    var y01 = (y0 + y1)*0.5;

    var x12 = (x1 + x2)*0.5;
    var y12 = (y1 + y2)*0.5;

    var x012 = (x01 + x12)*0.5;
    var y012 = (y01 + y12)*0.5;

    return  partition_bezier3(x0, y0, x01, y01, x012, y012, epsilon).concat(partition_bezier3(x012, y012, x12, y12, x2, y2, epsilon));
}

function partition_bezier4(x0, y0, x1, y1, x2, y2, x3, y3, epsilon)
{
    var dx01 = x1 - x0;
    var dy01 = y1 - y0;
    var dx12 = x2 - x1;
    var dy12 = y2 - y1;
    var dx23 = x3 - x2;
    var dy23 = y3 - y2;

    var r01 = Math.sqrt(dx01*dx01 + dy01*dy01);
    var r12 = Math.sqrt(dx12*dx12 + dy12*dy12);
    var r23 = Math.sqrt(dx23*dx23 + dy23*dy23);

    if(Math.max(r01, r12, r23) < epsilon)
        return [{x: x0, y: y0}, {x: x1, y: y1}, {x: x2, y: y2}, {x: x3, y: y3}];


    var x01 = (x0 + x1)*0.5;
    var y01 = (y0 + y1)*0.5;

    var x12 = (x1 + x2)*0.5;
    var y12 = (y1 + y2)*0.5;

    var x23 = (x2 + x3)*0.5;
    var y23 = (y2 + y3)*0.5;

    var x012 = (x01 + x12)*0.5;
    var y012 = (y01 + y12)*0.5;

    var x123 = (x12 + x23)*0.5;
    var y123 = (y12 + y23)*0.5;

    var x0123 = (x012 + x123)*0.5;
    var y0123 = (y012 + y123)*0.5;

    return partition_bezier4(x0, y0, x01, y01, x012, y012, x0123, y0123, epsilon).concat(partition_bezier4(x0123, y0123, x123, y123, x23, y23, x3, y3, epsilon));
}

    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].moveTo = moveTo;
    window['AscFormat'].lineTo = lineTo;
    window['AscFormat'].arcTo = arcTo;
    window['AscFormat'].bezier3 = bezier3;
    window['AscFormat'].bezier4 = bezier4;
    window['AscFormat'].close = close;
    window['AscFormat'].cToRad2 = cToRad2;
    window['AscFormat'].Path = Path;
    window['AscFormat'].Path2 = Path2;
    window['AscFormat'].partition_bezier3 = partition_bezier3;
    window['AscFormat'].partition_bezier4 = partition_bezier4;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {
// Import
var CShape = AscFormat.CShape;
var History = AscCommon.History;
var global_MatrixTransformer = AscCommon.global_MatrixTransformer;

var isRealObject = AscCommon.isRealObject;

    AscDFH.changesFactory[AscDFH.historyitem_ImageShapeSetSpPr] =  AscDFH.CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ImageShapeSetBlipFill] =  AscDFH.CChangesDrawingsObjectNoId;
    AscDFH.changesFactory[AscDFH.historyitem_ImageShapeSetParent] =  AscDFH.CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ImageShapeSetGroup] =  AscDFH.CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ImageShapeSetStyle] =  AscDFH.CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ImageShapeSetNvPicPr] =  AscDFH.CChangesDrawingsObject;

    AscDFH.drawingsChangesMap[AscDFH.historyitem_ImageShapeSetSpPr] =    function(oClass, value){oClass.spPr = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_ImageShapeSetBlipFill] =  function(oClass, value, FromLoad){
        oClass.blipFill = value;
        if(FromLoad){
            if(typeof AscCommon.CollaborativeEditing !== "undefined")
            {
                if(value && (typeof value.RasterImageId === "string") && value.RasterImageId.length > 0)
                {
                    AscCommon.CollaborativeEditing.Add_NewImage(value.RasterImageId);
                }
            }
        }
    };
    AscDFH.drawingsChangesMap[AscDFH.historyitem_ImageShapeSetParent] =  function(oClass, value){oClass.parent = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_ImageShapeSetGroup] =   function(oClass, value){oClass.group = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_ImageShapeSetStyle] =   function(oClass, value){oClass.style = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_ImageShapeSetNvPicPr] =  function(oClass, value){oClass.nvPicPr = value;};



    AscDFH.drawingsConstructorsMap[AscDFH.historyitem_ImageShapeSetBlipFill] = AscFormat.CBlipFill;



function CImageShape()
{
	AscFormat.CGraphicObjectBase.call(this);
    this.nvPicPr  = null;
    this.blipFill = null;
    this.style    = null;

    this.Id = AscCommon.g_oIdCounter.Get_NewId();
    AscCommon.g_oTableId.Add( this, this.Id );
}

	CImageShape.prototype = Object.create(AscFormat.CGraphicObjectBase.prototype);
	CImageShape.prototype.constructor = CImageShape;

CImageShape.prototype.getObjectType = function()
{
    return AscDFH.historyitem_type_ImageShape;
};

CImageShape.prototype.setNvPicPr = function(pr)
{
    History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_ImageShapeSetNvPicPr, this.nvPicPr, pr));
    this.nvPicPr = pr;
};

CImageShape.prototype.setSpPr = function(pr)
{
    History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_ImageShapeSetSpPr, this.spPr, pr));
    this.spPr = pr;
};

CImageShape.prototype.setBlipFill = function(pr)
{
    History.Add(new AscDFH.CChangesDrawingsObjectNoId(this, AscDFH.historyitem_ImageShapeSetBlipFill, this.blipFill, pr));
    this.blipFill = pr;
};

CImageShape.prototype.setParent = function(pr)
{
    History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_ImageShapeSetParent, this.parent, pr));
    this.parent = pr;
};

CImageShape.prototype.setGroup = function(pr)
{
    History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_ImageShapeSetGroup, this.group, pr));
    this.group = pr;
};

CImageShape.prototype.setStyle = function(pr)
{
    History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_ImageShapeSetStyle, this.style, pr));
    this.style = pr;
};

CImageShape.prototype.copy = function()
{
    var copy = new CImageShape();

    if(this.nvPicPr)
    {
        copy.setNvPicPr(this.nvPicPr.createDuplicate());
    }
    if(this.spPr)
    {
        copy.setSpPr(this.spPr.createDuplicate());
        copy.spPr.setParent(copy);
    }
    if(this.blipFill)
    {
        copy.setBlipFill(this.blipFill.createDuplicate());
    }
    if(this.style)
    {
        copy.setStyle(this.style.createDuplicate());
    }
    copy.setBDeleted(this.bDeleted);
    if(this.fromSerialize)
    {
        copy.setBFromSerialize(true);
    }
    copy.cachedImage = this.getBase64Img();
    copy.cachedPixH = this.cachedPixH;
    copy.cachedPixW = this.cachedPixW;
    copy.setLocks(this.locks);
    return copy;
};

CImageShape.prototype.getImageUrl = function()
{
    if(isRealObject(this.blipFill))
        return this.blipFill.RasterImageId;
    return null;
};

CImageShape.prototype.getSnapArrays = function(snapX, snapY)
{
    var transform = this.getTransformMatrix();
    snapX.push(transform.tx);
    snapX.push(transform.tx + this.extX*0.5);
    snapX.push(transform.tx + this.extX);
    snapY.push(transform.ty);
    snapY.push(transform.ty + this.extY*0.5);
    snapY.push(transform.ty + this.extY);
};

CImageShape.prototype.checkDrawingBaseCoords = CShape.prototype.checkDrawingBaseCoords;

CImageShape.prototype.setDrawingBaseCoords = CShape.prototype.setDrawingBaseCoords;

CImageShape.prototype.deleteBFromSerialize = CShape.prototype.deleteBFromSerialize;

CImageShape.prototype.setBFromSerialize = CShape.prototype.setBFromSerialize;

CImageShape.prototype.isPlaceholder  = function()
{
    return this.nvPicPr != null && this.nvPicPr.nvPr != undefined && this.nvPicPr.nvPr.ph != undefined;
};

CImageShape.prototype.isShape = function()
{
    return false;
};

CImageShape.prototype.isImage = function()
{
    return true;
};

CImageShape.prototype.isChart = function()
{
    return false;
};

CImageShape.prototype.isGroup = function()
{
    return false;
};

CImageShape.prototype.getParentObjects = CShape.prototype.getParentObjects;

CImageShape.prototype.hitInPath = CShape.prototype.hitInPath;

CImageShape.prototype.hitInInnerArea = CShape.prototype.hitInInnerArea;

CImageShape.prototype.getRotateAngle = CShape.prototype.getRotateAngle;

CImageShape.prototype.changeSize = CShape.prototype.changeSize;

CImageShape.prototype.getRectBounds = function()
{
    var transform = this.getTransformMatrix();
    var w = this.extX;
    var h = this.extY;
    var rect_points = [{x:0, y:0}, {x: w, y: 0}, {x: w, y: h}, {x: 0, y: h}];
    var min_x, max_x, min_y, max_y;
    min_x = transform.TransformPointX(rect_points[0].x, rect_points[0].y);
    min_y = transform.TransformPointY(rect_points[0].x, rect_points[0].y);
    max_x = min_x;
    max_y = min_y;
    var cur_x, cur_y;
    for(var i = 1; i < 4; ++i)
    {
        cur_x = transform.TransformPointX(rect_points[i].x, rect_points[i].y);
        cur_y = transform.TransformPointY(rect_points[i].x, rect_points[i].y);
        if(cur_x < min_x)
            min_x = cur_x;
        if(cur_x > max_x)
            max_x = cur_x;

        if(cur_y < min_y)
            min_y = cur_y;
        if(cur_y > max_y)
            max_y = cur_y;
    }
    return {minX: min_x, maxX: max_x, minY: min_y, maxY: max_y};
};

CImageShape.prototype.canRotate = function()
{
    return true;
};

CImageShape.prototype.canResize = function()
{
    return true;//TODO
};

CImageShape.prototype.canMove = function()
{
    return true;//TODO
};

CImageShape.prototype.canGroup = function()
{
    return true;//TODO
};

CImageShape.prototype.canChangeAdjustments = function()
{
    return true;//TODO
};

CImageShape.prototype.createRotateTrack = function()
{
    return new AscFormat.RotateTrackShapeImage(this);
};

CImageShape.prototype.createResizeTrack = function(cardDirection)
{
    return new AscFormat.ResizeTrackShapeImage(this, cardDirection);
};

CImageShape.prototype.createMoveTrack = function()
{
    return new AscFormat.MoveShapeImageTrack(this);
};

CImageShape.prototype.getInvertTransform = function()
{
    if(this.recalcInfo.recalculateTransform)
    {
        this.recalculateTransform();
        this.recalcInfo.recalculateTransform = true;
    }
    return this.invertTransform;
};

CImageShape.prototype.hitInTextRect = function(x, y)
{
    return false;
};

CImageShape.prototype.getBase64Img = CShape.prototype.getBase64Img;

CImageShape.prototype.convertToWord = function(document)
{
    this.setBDeleted(true);
    var oCopy = this.copy();
    oCopy.setBDeleted(false);
    return oCopy;
};

CImageShape.prototype.convertToPPTX = function(drawingDocument, worksheet)
{
    var ret = this.copy();
    ret.setWorksheet(worksheet);
    ret.setParent(null);
    ret.setBDeleted(false);
    return ret;
};

CImageShape.prototype.recalculateBrush = CShape.prototype.recalculateBrush;

CImageShape.prototype.recalculatePen = function()
{
    CShape.prototype.recalculatePen.call(this);
    if(this.pen)
    {
        if(AscFormat.isRealNumber(this.pen.w)){
            this.pen.w *= 2;
        }
       // if(!this.pen.Fill){
       //     this.pen = null;
       // }
    }
};

CImageShape.prototype.getCompiledLine = CShape.prototype.getCompiledLine;

CImageShape.prototype.getCompiledFill = CShape.prototype.getCompiledFill;

CImageShape.prototype.getCompiledTransparent = CShape.prototype.getCompiledTransparent;

CImageShape.prototype.getAllRasterImages = function(images)
{
    this.blipFill && typeof this.blipFill.RasterImageId === "string" && this.blipFill.RasterImageId.length > 0 && images.push(this.blipFill.RasterImageId);
};

CImageShape.prototype.getHierarchy = function()
{
    if(this.recalcInfo.recalculateShapeHierarchy)
    {
        this.compiledHierarchy.length = 0;
        var hierarchy = this.compiledHierarchy;
        if(this.isPlaceholder())
        {
            var ph_type = this.getPlaceholderType();
            var ph_index = this.getPlaceholderIndex();
            var b_is_single_body = this.getIsSingleBody();
            switch (this.parent.kind)
            {
                case AscFormat.TYPE_KIND.SLIDE:
                {
                    hierarchy.push(this.parent.Layout.getMatchingShape(ph_type, ph_index, b_is_single_body));
                    hierarchy.push(this.parent.Layout.Master.getMatchingShape(ph_type, ph_index, b_is_single_body));
                    break;
                }

                case AscFormat.TYPE_KIND.LAYOUT:
                {
                    hierarchy.push(this.parent.Master.getMatchingShape(ph_type, ph_index, b_is_single_body));
                    break;
                }
            }
        }
        this.recalcInfo.recalculateShapeHierarchy = true;
    }
    return this.compiledHierarchy;
};

CImageShape.prototype.recalculateTransform = function()
{
    this.cachedImage = null;
    if(!isRealObject(this.group))
    {
        if(this.spPr.xfrm.isNotNull())
        {
            var xfrm = this.spPr.xfrm;
            this.x = xfrm.offX;
            this.y = xfrm.offY;
            this.extX = xfrm.extX;
            this.extY = xfrm.extY;
            this.rot = AscFormat.isRealNumber(xfrm.rot) ? xfrm.rot : 0;
            this.flipH = xfrm.flipH === true;
            this.flipV = xfrm.flipV === true;
        }
        else
        {
            if(this.isPlaceholder())
            {
                var hierarchy = this.getHierarchy();
                for(var i = 0; i < hierarchy.length; ++i)
                {
                    var hierarchy_sp = hierarchy[i];
                    if(isRealObject(hierarchy_sp) && hierarchy_sp.spPr.xfrm.isNotNull())
                    {
                        var xfrm = hierarchy_sp.spPr.xfrm;
                        this.x = xfrm.offX;
                        this.y = xfrm.offY;
                        this.extX = xfrm.extX;
                        this.extY = xfrm.extY;
                        this.rot = AscFormat.isRealNumber(xfrm.rot) ? xfrm.rot : 0;
                        this.flipH = xfrm.flipH === true;
                        this.flipV = xfrm.flipV === true;
                        break;
                    }
                }
                if(i === hierarchy.length)
                {
                    this.x = 0;
                    this.y = 0;
                    this.extX = 5;
                    this.extY = 5;
                    this.rot = 0;
                    this.flipH = false;
                    this.flipV = false;
                }
            }
            else
            {
                this.x = 0;
                this.y = 0;
                this.extX = 5;
                this.extY = 5;
                this.rot = 0;
                this.flipH = false;
                this.flipV = false;
            }
        }
    }
    else
    {
        var xfrm;
        if(this.spPr.xfrm.isNotNull())
        {
            xfrm = this.spPr.xfrm;
        }
        else
        {
            if(this.isPlaceholder())
            {
                var hierarchy = this.getHierarchy();
                for(var i = 0; i < hierarchy.length; ++i)
                {
                    var hierarchy_sp = hierarchy[i];
                    if(isRealObject(hierarchy_sp) && hierarchy_sp.spPr.xfrm.isNotNull())
                    {
                        xfrm = hierarchy_sp.spPr.xfrm;
                        break;
                    }
                }
                if(i === hierarchy.length)
                {
                    xfrm = new AscFormat.CXfrm();
                    xfrm.offX = 0;
                    xfrm.offX = 0;
                    xfrm.extX = 5;
                    xfrm.extY = 5;
                }
            }
            else
            {
                xfrm = new AscFormat.CXfrm();
                xfrm.offX = 0;
                xfrm.offY = 0;
                xfrm.extX = 5;
                xfrm.extY = 5;
            }
        }
        var scale_scale_coefficients = this.group.getResultScaleCoefficients();
        this.x = scale_scale_coefficients.cx*(xfrm.offX - this.group.spPr.xfrm.chOffX);
        this.y = scale_scale_coefficients.cy*(xfrm.offY - this.group.spPr.xfrm.chOffY);
        this.extX = scale_scale_coefficients.cx*xfrm.extX;
        this.extY = scale_scale_coefficients.cy*xfrm.extY;
        this.rot = AscFormat.isRealNumber(xfrm.rot) ? xfrm.rot : 0;
        this.flipH = xfrm.flipH === true;
        this.flipV = xfrm.flipV === true;
    }
    this.transform.Reset();
    var hc = this.extX*0.5;
    var vc = this.extY*0.5;
    global_MatrixTransformer.TranslateAppend(this.transform, -hc, -vc);
    if(this.flipH)
        global_MatrixTransformer.ScaleAppend(this.transform, -1, 1);
    if(this.flipV)
        global_MatrixTransformer.ScaleAppend(this.transform, 1, -1);
    global_MatrixTransformer.RotateRadAppend(this.transform, -this.rot);
    global_MatrixTransformer.TranslateAppend(this.transform, this.x + hc, this.y + vc);
    if(isRealObject(this.group))
    {
        global_MatrixTransformer.MultiplyAppend(this.transform, this.group.getTransformMatrix());
    }
    this.invertTransform = global_MatrixTransformer.Invert(this.transform);
   //if(this.drawingBase && !this.group)
   //{
   //    this.drawingBase.setGraphicObjectCoords();
   //}
};

CImageShape.prototype.Refresh_RecalcData = function(data)
{
    switch(data.Type)
    {
        case AscDFH.historyitem_ImageShapeSetBlipFill:
        {
            this.recalcBrush();
            this.recalcFill();
            this.addToRecalculate();
            break;
        }
        case AscDFH.historyitem_ShapeSetBDeleted:{
            if(!this.bDeleted){
                this.addToRecalculate();
            }
            break;
        }
    }
};

CImageShape.prototype.recalculateGeometry = function()
{
    this.calcGeometry = null;
    if(isRealObject(this.spPr.geometry)){
        this.calcGeometry = this.spPr.geometry;
    }
    else{
        var hierarchy = this.getHierarchy();
        for(var i = 0; i < hierarchy.length; ++i){
            if(hierarchy[i] && hierarchy[i].spPr && hierarchy[i].spPr.geometry){
                var _g = hierarchy[i].spPr.geometry;
                this.calcGeometry = AscFormat.ExecuteNoHistory(function(){
                    var _r = _g.createDuplicate();
                    _r.setParent(this);
                    return _r;
                }, this, []);
                break;
            }
        }
    }
    if(isRealObject(this.calcGeometry))
    {
        var transform = this.getTransform();
        this.calcGeometry.Recalculate(transform.extX, transform.extY);
    }
};

CImageShape.prototype.getTransformMatrix = function()
{
    if(this.recalcInfo.recalculateTransform)
    {
        this.recalculateTransform();
        this.recalcInfo.recalculateTransform = false;
    }
    return this.transform;
};

CImageShape.prototype.getTransform = function()
{
    if(this.recalcInfo.recalculateTransform)
    {
        this.recalculateTransform();
        this.recalcInfo.recalculateTransform = false;
    }
    return {x: this.x, y: this.y, extX: this.extX, extY: this.extY, rot: this.rot, flipH: this.flipH, flipV: this.flipV};
};

CImageShape.prototype.draw = function(graphics, transform)
{
    if(this.checkNeedRecalculate && this.checkNeedRecalculate()){
        return;
    }
    if(graphics.updatedRect)
    {
        var rect = graphics.updatedRect;
        var bounds = this.bounds;
        if(bounds.x > rect.x + rect.w
            || bounds.y > rect.y + rect.h
            || bounds.x + bounds.w < rect.x
            || bounds.y + bounds.h < rect.y)
            return;
    }
    var _transform = transform ? transform :this.transform;
    graphics.SetIntegerGrid(false);
    graphics.transform3(_transform, false);
    var shape_drawer = new AscCommon.CShapeDrawer();
    if(this.getObjectType() !== AscDFH.historyitem_type_OleObject && (this.pen || this.brush))
    {
        shape_drawer.fromShape2(this, graphics, this.calcGeometry);
        shape_drawer.draw(this.calcGeometry);
        shape_drawer.Clear();
    }
    var oldBrush = this.brush;
    var oldPen = this.pen;

    if(this.getObjectType() === AscDFH.historyitem_type_OleObject){
        var sImageId = this.blipFill && this.blipFill.RasterImageId;
        if(sImageId){
            var oApi = editor || window['Asc']['editor'];
            if(oApi){
                sImageId = AscCommon.getFullImageSrc2(sImageId);
                var _img = oApi.ImageLoader.map_image_index[sImageId];
                if ((_img && _img.Status === AscFonts.ImageLoadStatus.Loading) || (_img && _img.Image) || true === graphics.IsSlideBoundsCheckerType || true == graphics.RENDERER_PDF_FLAG){
                    this.brush = new AscFormat.CUniFill();
                    this.brush.fill = this.blipFill;
                    this.pen = null;
                }
                else{
                    this.brush = AscFormat.CreateNoFillUniFill();
                }
            }
        }
        else{
            this.brush = new AscFormat.CUniFill();
            this.brush.fill = this.blipFill;
            this.pen = null;
        }
    }
    else{
        this.brush = new AscFormat.CUniFill();
        this.brush.fill = this.blipFill;
        this.pen = null;
    }

    shape_drawer.fromShape2(this, graphics, this.calcGeometry);
    shape_drawer.draw(this.calcGeometry);
    this.brush = oldBrush;
    this.pen = oldPen;

    this.drawLocks(_transform, graphics);
    graphics.reset();
    graphics.SetIntegerGrid(true);
};

CImageShape.prototype.select = CShape.prototype.select;


    CImageShape.prototype.handleUpdateLn = function()
    {
        this.recalcLine();
        this.recalcPen();
        this.addToRecalculate();
    };

    CImageShape.prototype.changePresetGeom = function (sPreset) {
        if(sPreset === "textRect"){
            return;
        }
        this.spPr.setGeometry( AscFormat.CreateGeometry(sPreset));
    };


    CImageShape.prototype.recalculateLocalTransform = CShape.prototype.recalculateLocalTransform;
CImageShape.prototype.hit = CShape.prototype.hit;

    CImageShape.prototype.changeLine = function (line)
    {
        if(this.recalcInfo.recalculatePen)
        {
            this.recalculatePen();
        }
        var stroke = AscFormat.CorrectUniStroke(line, this.pen);
        if(stroke.Fill)
        {
            stroke.Fill.convertToPPTXMods();
        }
        this.spPr.setLn(stroke);
    };

CImageShape.prototype.deselect = function(drawingObjectsController)
{
    this.selected = false;
    var selected_objects;
    if(!isRealObject(this.group))
        selected_objects = drawingObjectsController.selectedObjects;
    else
        selected_objects = this.group.getMainGroup().selectedObjects;
    for(var i = 0; i < selected_objects.length; ++i)
    {
        if(selected_objects[i] === this)
        {
            selected_objects.splice(i, 1);
            break;
        }
    }
    return this;
};

CImageShape.prototype.drawAdjustments = function(drawingDocument)
{
    if (this.calcGeometry) {
        this.calcGeometry.drawAdjustments(drawingDocument, this.transform, false);
    }
};

CImageShape.prototype.hitToAdjustment = CShape.prototype.hitToAdjustment;

CImageShape.prototype.getPlaceholderType = function()
{
    return this.isPlaceholder() ? this.nvPicPr.nvPr.ph.type : null;
};

CImageShape.prototype.getPlaceholderIndex = function()
{
    return this.isPlaceholder() ? this.nvPicPr.nvPr.ph.idx : null;
};

CImageShape.prototype.getPhType = function()
{
    return this.isPlaceholder() ? this.nvPicPr.nvPr.ph.type : null;
};

CImageShape.prototype.getPhIndex = function()
{
    return this.isPlaceholder() ? this.nvPicPr.nvPr.ph.idx : null;
};

CImageShape.prototype.setNvSpPr = function(pr)
{
    History.Add(new AscDFH.CChangesDrawingsObject(this,  AscDFH.historyitem_ImageShapeSetNvPicPr, this.nvPicPr, pr));
    this.nvPicPr = pr;
};

CImageShape.prototype.getAllImages = function(images)
{
    if(this.blipFill instanceof  AscFormat.CBlipFill && typeof this.blipFill.RasterImageId === "string")
    {
        images[AscCommon.getFullImageSrc2(this.blipFill.RasterImageId)] = true;
    }
};
CImageShape.prototype.checkTypeCorrect = function()
{
    if(!this.blipFill){
        return false;
    }
    if(!this.spPr){
        return false;
    }
    return true;
};

CImageShape.prototype.Load_LinkData = function(linkData)
{
};

    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].CImageShape = CImageShape;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {
// Import
var c_oAscSizeRelFromH = AscCommon.c_oAscSizeRelFromH;
var c_oAscSizeRelFromV = AscCommon.c_oAscSizeRelFromV;
var isRealObject = AscCommon.isRealObject;
    var History = AscCommon.History;
    var global_MatrixTransformer = AscCommon.global_MatrixTransformer;

var CShape = AscFormat.CShape;





 AscDFH.changesFactory[AscDFH.historyitem_GroupShapeSetNvGrpSpPr]   = AscDFH.CChangesDrawingsObject;
 AscDFH.changesFactory[AscDFH.historyitem_GroupShapeSetSpPr]   = AscDFH.CChangesDrawingsObject;
 AscDFH.changesFactory[AscDFH.historyitem_GroupShapeSetParent]    = AscDFH.CChangesDrawingsObject;
 AscDFH.changesFactory[AscDFH.historyitem_GroupShapeAddToSpTree]   = AscDFH.CChangesDrawingsContent;
 AscDFH.changesFactory[AscDFH.historyitem_GroupShapeSetGroup]   = AscDFH.CChangesDrawingsObject;
 AscDFH.changesFactory[AscDFH.historyitem_GroupShapeRemoveFromSpTree]   = AscDFH.CChangesDrawingsContent;

    AscDFH.drawingsChangesMap[AscDFH.historyitem_GroupShapeSetNvGrpSpPr] = function(oClass, value){oClass.nvGrpSpPr = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_GroupShapeSetSpPr] = function(oClass, value){oClass.spPr = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_GroupShapeSetParent] = function(oClass, value){oClass.parent = value;};
    AscDFH.drawingsChangesMap[AscDFH.historyitem_GroupShapeSetGroup] = function(oClass, value){oClass.group = value;};

    AscDFH.drawingContentChanges[AscDFH.historyitem_GroupShapeAddToSpTree] =  AscDFH.drawingContentChanges[AscDFH.historyitem_GroupShapeRemoveFromSpTree] = function(oClass){return oClass.spTree;};

function CGroupShape()
{
	AscFormat.CGraphicObjectBase.call(this);
    this.nvGrpSpPr = null;
    this.spTree    = [];


    this.invertTransform = null;
    this.scaleCoefficients = {cx: 1, cy: 1};

    this.arrGraphicObjects = [];
    this.selectedObjects = [];


    this.selection =
    {
        groupSelection: null,
        chartSelection: null,
        textSelection: null
    };

    this.Id = AscCommon.g_oIdCounter.Get_NewId();
    AscCommon.g_oTableId.Add(this, this.Id);
}
	CGroupShape.prototype = Object.create(AscFormat.CGraphicObjectBase.prototype);
	CGroupShape.prototype.constructor = CGroupShape;

    CGroupShape.prototype.getObjectType = function()
    {
        return AscDFH.historyitem_type_GroupShape;
    };

    CGroupShape.prototype.GetAllDrawingObjects = function(DrawingObjects)
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].GetAllDrawingObjects)
            {
                this.spTree[i].GetAllDrawingObjects(DrawingObjects);
            }
        }
    };

    CGroupShape.prototype.documentGetAllFontNames = function(allFonts)
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].documentGetAllFontNames)
                this.spTree[i].documentGetAllFontNames(allFonts);
        }
    };
    CGroupShape.prototype.getAllDocContents = function(aDocContents)
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].getAllDocContents)
                this.spTree[i].getAllDocContents(aDocContents);
        }
    };

    CGroupShape.prototype.documentCreateFontMap = function(allFonts)
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].documentCreateFontMap)
                this.spTree[i].documentCreateFontMap(allFonts);
        }
    };

    CGroupShape.prototype.setBDeleted2 = function(pr)
    {
        this.bDeleted = pr;
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].setBDeleted2)
            {
                this.spTree[i].setBDeleted2(pr);
            }
            else
            {
                this.spTree[i].bDeleted = pr;
            }
        }
    };

    CGroupShape.prototype.checkRemoveCache = function()
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            this.spTree[i].checkRemoveCache && this.spTree[i].checkRemoveCache();
        }
    };

    CGroupShape.prototype.documentUpdateSelectionState = function()
    {
        if(this.selection.textSelection)
        {
            this.selection.textSelection.updateSelectionState();
        }
        else if(this.selection.groupSelection)
        {
            this.selection.groupSelection.documentUpdateSelectionState();
        }
        else if(this.selection.chartSelection)
        {
            this.selection.chartSelection.documentUpdateSelectionState();
        }
        else
        {
            this.getDrawingDocument().SelectClear();
            this.getDrawingDocument().TargetEnd();
        }
    };

    CGroupShape.prototype.drawSelectionPage = function(pageIndex)
    {
        var oMatrix = null;
        if(this.selection.textSelection)
        {
            if(this.selection.textSelection.transformText)
            {
                oMatrix = this.selection.textSelection.transformText.CreateDublicate();
            }
            this.getDrawingDocument().UpdateTargetTransform(oMatrix);
            this.selection.textSelection.getDocContent().DrawSelectionOnPage(pageIndex);
        }
        else if(this.selection.chartSelection && this.selection.chartSelection.selection.textSelection)
        {
            if(this.selection.chartSelection.selection.textSelection.transformText)
            {
                oMatrix = this.selection.chartSelection.selection.textSelection.transformText.CreateDublicate();
            }
            this.getDrawingDocument().UpdateTargetTransform(oMatrix);
            this.selection.chartSelection.selection.textSelection.getDocContent().DrawSelectionOnPage(pageIndex);
        }
    };

    CGroupShape.prototype.setNvGrpSpPr = function(pr)
    {
        History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_GroupShapeSetNvGrpSpPr, this.nvGrpSpPr, pr));
        this.nvGrpSpPr = pr;
    };

    CGroupShape.prototype.setSpPr = function(pr)
    {
        History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_GroupShapeSetSpPr, this.spPr, pr));
        this.spPr = pr;
    };

    CGroupShape.prototype.addToSpTree = function(pos, item)
    {
        if(!AscFormat.isRealNumber(pos))
            pos = this.spTree.length;
        History.Add(new AscDFH.CChangesDrawingsContent(this, AscDFH.historyitem_GroupShapeAddToSpTree, pos, [item], true));
        this.handleUpdateSpTree();
        this.spTree.splice(pos, 0, item);
    };

    CGroupShape.prototype.setParent = function(pr)
    {
        History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_GroupShapeSetParent, this.parent, pr));
        this.parent = pr;
    };

    CGroupShape.prototype.setGroup = function(group)
    {
        History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_GroupShapeSetGroup, this.group, group));
        this.group = group;
    };

    CGroupShape.prototype.removeFromSpTree = function(id)
    {
        for(var i = this.spTree.length-1; i > -1 ; --i)
        {
            if(this.spTree[i].Get_Id() === id)
            {
                return this.removeFromSpTreeByPos(i);
            }
        }
        return null;
    };

    CGroupShape.prototype.removeFromSpTreeByPos = function(pos)
    {
        var aSplicedShape = this.spTree.splice(pos, 1);
        History.Add(new AscDFH.CChangesDrawingsContent(this,AscDFH.historyitem_GroupShapeRemoveFromSpTree, pos, aSplicedShape, false));
        this.handleUpdateSpTree();
        return aSplicedShape[0];
    };

    CGroupShape.prototype.handleUpdateSpTree = function()
    {
        if(!this.group)
        {
            this.recalcInfo.recalculateArrGraphicObjects = true;
            this.recalcBounds();
            this.addToRecalculate();
        }
        else
        {
            this.recalcInfo.recalculateArrGraphicObjects = true;
            this.group.handleUpdateSpTree();
            this.recalcBounds();
        }
    };

    CGroupShape.prototype.copy = function(oIdMap, bSourceFormatting)
    {
        var copy = new CGroupShape();
        if(this.nvGrpSpPr)
        {
            copy.setNvGrpSpPr(this.nvGrpSpPr.createDuplicate());
        }
        if(this.spPr)
        {
            copy.setSpPr(this.spPr.createDuplicate());
            copy.spPr.setParent(copy);
        }
        for(var i = 0; i < this.spTree.length; ++i)
        {
            var _copy;
            if(this.spTree[i].getObjectType() === AscDFH.historyitem_type_GroupShape){
                _copy = this.spTree[i].copy(oIdMap, bSourceFormatting);
            }
            else{
                if(bSourceFormatting){
                    _copy = this.spTree[i].getCopyWithSourceFormatting();
                }
                else{
                    _copy = this.spTree[i].copy();
                }

            }
            if(AscCommon.isRealObject(oIdMap)){
                oIdMap[this.spTree[i].Id] = _copy.Id;
            }
            copy.addToSpTree(copy.spTree.length, _copy);
            copy.spTree[copy.spTree.length-1].setGroup(copy);
        }
        copy.setBDeleted(this.bDeleted);
        copy.cachedImage = this.getBase64Img();
        copy.cachedPixH = this.cachedPixH;
        copy.cachedPixW = this.cachedPixW;
        copy.setLocks(this.locks);
        if(this.fromSerialize)
        {
            copy.setBFromSerialize(true);
        }
        return copy;
    };

    CGroupShape.prototype.getAllImages = function(images)
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(typeof this.spTree[i].getAllImages === "function")
            {
                this.spTree[i].getAllImages(images);
            }
        }
    };

    CGroupShape.prototype.getBase64Img = CShape.prototype.getBase64Img;

    CGroupShape.prototype.convertToWord = function(document)
    {
        this.setBDeleted(true);
        var c = new CGroupShape();
        c.setBDeleted(false);
        if(this.nvGrpSpPr)
        {
            c.setNvSpPr(this.nvGrpSpPr.createDuplicate());
        }
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
            c.spPr.setParent(c);
        }

        for(var i = 0; i < this.spTree.length; ++i)
        {
            c.addToSpTree(c.spTree.length, this.spTree[i].convertToWord(document));
            c.spTree[c.spTree.length - 1].setGroup(c);
        }
        return c;
    };

    CGroupShape.prototype.convertToPPTX = function(drawingDocument, worksheet)
    {
        var c = new CGroupShape();
        c.setBDeleted(false);
        c.setWorksheet(worksheet);
        if(this.nvGrpSpPr)
        {
            c.setNvSpPr(this.nvGrpSpPr.createDuplicate());
        }
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
            c.spPr.setParent(c);
        }

        for(var i = 0; i < this.spTree.length; ++i)
        {
            c.addToSpTree(c.spTree.length, this.spTree[i].convertToPPTX(drawingDocument, worksheet));
            c.spTree[c.spTree.length - 1].setGroup(c);
        }
        return c;
    };

    CGroupShape.prototype.getAllFonts = function(fonts)
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(typeof  this.spTree[i].getAllFonts === "function")
                this.spTree[i].getAllFonts(fonts);
        }
    };

    CGroupShape.prototype.isShape = function()
    {
        return false;
    };

    CGroupShape.prototype.isImage = function()
    {
        return false;
    };

    CGroupShape.prototype.isChart = function()
    {
        return false;
    };

    CGroupShape.prototype.isGroup = function()
    {
        return true;
    };

    CGroupShape.prototype.isPlaceholder  = function()
    {
        return this.nvGrpSpPr != null && this.nvGrpSpPr.nvPr != undefined && this.nvGrpSpPr.nvPr.ph != undefined;
    };

    CGroupShape.prototype.getAllRasterImages = function(images)
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].getAllRasterImages)
                this.spTree[i].getAllRasterImages(images);
        }
    };

    CGroupShape.prototype.draw = function(graphics)
    {
        if(this.checkNeedRecalculate && this.checkNeedRecalculate()){
            return;
        }
        for(var i = 0; i < this.spTree.length; ++i)
            this.spTree[i].draw(graphics);


        this.drawLocks(this.transform, graphics);
        graphics.reset();
        graphics.SetIntegerGrid(true);
    };

    CGroupShape.prototype.deselectObject = function(object)
    {
        for(var i = 0; i < this.selectedObjects.length; ++i)
        {
            if(this.selectedObjects[i] === object){
                object.selected = false;
                this.selectedObjects.splice(i, 1);
                return;
            }
        }
    };



    CGroupShape.prototype.getLocalTransform = function()
    {
        if(this.recalcInfo.recalculateTransform)
        {
            this.recalculateTransform();
            this.recalcInfo.recalculateTransform = false;
        }
        return this.localTransform;
    };

    CGroupShape.prototype.getArrGraphicObjects = function()
    {
        if(this.recalcInfo.recalculateArrGraphicObjects)
            this.recalculateArrGraphicObjects();
        return this.arrGraphicObjects;
    };

    CGroupShape.prototype.getInvertTransform = function()
    {
        return this.invertTransform;
    };

    CGroupShape.prototype.getRectBounds = function()
    {
        var transform = this.getTransformMatrix();
        var w = this.extX;
        var h = this.extY;
        var rect_points = [{x:0, y:0}, {x: w, y: 0}, {x: w, y: h}, {x: 0, y: h}];
        var min_x, max_x, min_y, max_y;
        min_x = transform.TransformPointX(rect_points[0].x, rect_points[0].y);
        min_y = transform.TransformPointY(rect_points[0].x, rect_points[0].y);
        max_x = min_x;
        max_y = min_y;
        var cur_x, cur_y;
        for(var i = 1; i < 4; ++i)
        {
            cur_x = transform.TransformPointX(rect_points[i].x, rect_points[i].y);
            cur_y = transform.TransformPointY(rect_points[i].x, rect_points[i].y);
            if(cur_x < min_x)
                min_x = cur_x;
            if(cur_x > max_x)
                max_x = cur_x;

            if(cur_y < min_y)
                min_y = cur_y;
            if(cur_y > max_y)
                max_y = cur_y;
        }
        return {minX: min_x, maxX: max_x, minY: min_y, maxY: max_y};
    };

    CGroupShape.prototype.getResultScaleCoefficients = function()
    {
        if(this.recalcInfo.recalculateScaleCoefficients)
        {
            var cx, cy;
            if(this.spPr.xfrm.isNotNullForGroup())
            {

                var dExtX = this.spPr.xfrm.extX, dExtY = this.spPr.xfrm.extY;
                var oParaDrawing = AscFormat.getParaDrawing(this);
                if(false && oParaDrawing)
                {
                    if(oParaDrawing.SizeRelH || oParaDrawing.SizeRelV)
                    {
                        this.m_oSectPr = null;
                        var oParentParagraph = oParaDrawing.Get_ParentParagraph();
                        if(oParentParagraph)
                        {

                            var oSectPr = oParentParagraph.Get_SectPr();
                            if(oSectPr)
                            {
                                if(oParaDrawing.SizeRelH && oParaDrawing.SizeRelH.Percent > 0)
                                {
                                    switch(oParaDrawing.SizeRelH.RelativeFrom)
                                    {
                                        case c_oAscSizeRelFromH.sizerelfromhMargin:
                                        {
                                            dExtX = oSectPr.Get_PageWidth() - oSectPr.Get_PageMargin_Left() - oSectPr.Get_PageMargin_Right();
                                            break;
                                        }
                                        case c_oAscSizeRelFromH.sizerelfromhPage:
                                        {
                                            dExtX = oSectPr.Get_PageWidth();
                                            break;
                                        }
                                        case c_oAscSizeRelFromH.sizerelfromhLeftMargin:
                                        {
                                            dExtX = oSectPr.Get_PageMargin_Left();
                                            break;
                                        }

                                        case c_oAscSizeRelFromH.sizerelfromhRightMargin:
                                        {
                                            dExtX = oSectPr.Get_PageMargin_Right();
                                            break;
                                        }
                                        default:
                                        {
                                            dExtX = oSectPr.Get_PageMargin_Left();
                                            break;
                                        }
                                    }
                                    dExtX *= oParaDrawing.SizeRelH.Percent;
                                }
                                if(oParaDrawing.SizeRelV && oParaDrawing.SizeRelV.Percent > 0)
                                {
                                    switch(oParaDrawing.SizeRelV.RelativeFrom)
                                    {
                                        case c_oAscSizeRelFromV.sizerelfromvMargin:
                                        {
                                            dExtY = oSectPr.Get_PageHeight() - oSectPr.Get_PageMargin_Top() - oSectPr.Get_PageMargin_Bottom();
                                            break;
                                        }
                                        case c_oAscSizeRelFromV.sizerelfromvPage:
                                        {
                                            dExtY = oSectPr.Get_PageHeight();
                                            break;
                                        }
                                        case c_oAscSizeRelFromV.sizerelfromvTopMargin:
                                        {
                                            dExtY = oSectPr.Get_PageMargin_Top();
                                            break;
                                        }
                                        case c_oAscSizeRelFromV.sizerelfromvBottomMargin:
                                        {
                                            dExtY = oSectPr.Get_PageMargin_Bottom();
                                            break;
                                        }
                                        default:
                                        {
                                            dExtY = oSectPr.Get_PageMargin_Top();
                                            break;
                                        }
                                    }
                                    dExtY *= oParaDrawing.SizeRelV.Percent;
                                }
                            }
                        }
                    }
                }


                if(this.drawingBase  && this.fromSerialize)
                {
                    var metrics = this.drawingBase.getGraphicObjectMetrics();
                    var rot = 0;
                    if(this.spPr && this.spPr.xfrm){
                        if(AscFormat.isRealNumber(this.spPr.xfrm.rot)){
                            rot =  AscFormat.normalizeRotate(this.spPr.xfrm.rot);
                        }
                    }

                    var metricExtX, metricExtY;
                    //  if(!(this instanceof AscFormat.CGroupShape))
                    {
                        if (AscFormat.checkNormalRotate(rot))
                        {
                            dExtX = metrics.extX;
                            dExtY = metrics.extY;
                        }
                        else
                        {
                            dExtX = metrics.extY;
                            dExtY = metrics.extX;
                        }
                    }
                }

                if(this.spPr.xfrm.chExtX > 0)
                    cx = dExtX/this.spPr.xfrm.chExtX;
                else
                    cx = 1;

                if(this.spPr.xfrm.chExtY > 0)
                    cy = dExtY/this.spPr.xfrm.chExtY;
                else
                    cy = 1;
            }
            else
            {
                cx = 1;
                cy = 1;
            }
            if(isRealObject(this.group))
            {
                var group_scale_coefficients = this.group.getResultScaleCoefficients();
                cx *= group_scale_coefficients.cx;
                cy *= group_scale_coefficients.cy;
            }
            this.scaleCoefficients.cx = cx;
            this.scaleCoefficients.cy = cy;
            this.recalcInfo.recalculateScaleCoefficients = false;
        }
        return this.scaleCoefficients;
    };

    CGroupShape.prototype.getCompiledTransparent = function()
    {
        return null;
    };

    CGroupShape.prototype.selectObject = function(object, pageIndex)
    {
        object.select(this, pageIndex);
    };

    CGroupShape.prototype.recalculate = function()
    {
        var recalcInfo = this.recalcInfo;

        if(recalcInfo.recalculateBrush)
        {
            this.recalculateBrush();
            recalcInfo.recalculateBrush = false;
        }
        if(recalcInfo.recalculatePen)
        {
            this.recalculatePen();
            recalcInfo.recalculatePen = false;
        }
        if(recalcInfo.recalculateScaleCoefficients)
        {
            this.getResultScaleCoefficients();
            recalcInfo.recalculateScaleCoefficients = false;
        }

        if(recalcInfo.recalculateTransform)
        {
            this.recalculateTransform();
            recalcInfo.recalculateTransform = false;
        }
        if(recalcInfo.recalculateArrGraphicObjects)
            this.recalculateArrGraphicObjects();
        for(var i = 0;  i < this.spTree.length; ++i)
            this.spTree[i].recalculate();
        if(recalcInfo.recalculateBounds)
        {
            this.recalculateBounds();
            recalcInfo.recalculateBounds = false;
        }
    };

    CGroupShape.prototype.recalcTransform = function()
    {
        this.recalcInfo.recalculateTransform = true;
        this.recalcInfo.recalculateScaleCoefficients = true;
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].recalcTransform)
                this.spTree[i].recalcTransform();
            else
            {
                this.spTree[i].recalcInfo.recalculateTransform = true;
                this.spTree[i].recalcInfo.recalculateTransformText = true;
            }
        }
    };

    CGroupShape.prototype.canRotate = function()
    {
        //TODO: сделать еще проверку SpLock
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(!this.spTree[i].canRotate || !this.spTree[i].canRotate())
                return false;
        }
        return true;
    };

    CGroupShape.prototype.canResize = function()
    {
        //TODO: сделать еще проверку SpLock
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(!this.spTree[i].canResize || !this.spTree[i].canResize())
                return false
        }
        return true;
    };

    CGroupShape.prototype.canMove = function()
    {
        //TODO: сделать еще проверку SpLock
        return true;//TODO
    };

    CGroupShape.prototype.canGroup = function()
    {
        //TODO: сделать еще проверку SpLock
        return true;//TODO
    };

    CGroupShape.prototype.canChangeAdjustments = function()
    {
        return false;
    };

    CGroupShape.prototype.drawAdjustments = function()
    {};

    CGroupShape.prototype.hitToAdjustment = function()
    {
        return {hit: false};
    };

    CGroupShape.prototype.recalculateBrush = function()
    {};

    CGroupShape.prototype.recalculatePen = function()
    {};

    CGroupShape.prototype.recalculateArrGraphicObjects = function()
    {
        this.arrGraphicObjects.length = 0;
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(!this.spTree[i].isGroup())
                this.arrGraphicObjects.push(this.spTree[i]);
            else
            {
                var arr_graphic_objects = this.spTree[i].getArrGraphicObjects();
                for(var j = 0; j < arr_graphic_objects.length; ++j)
                    this.arrGraphicObjects.push(arr_graphic_objects[j]);
            }
        }
    };

    CGroupShape.prototype.paragraphAdd = function(paraItem, bRecalculate)
    {
        if(this.selection.textSelection)
        {
            this.selection.textSelection.paragraphAdd(paraItem, bRecalculate);
        }
        else if(this.selection.chartSelection)
        {
            this.selection.chartSelection.paragraphAdd(paraItem, bRecalculate);
        }
        else
        {
            var i;
            if(paraItem.Type === para_TextPr)
            {
                AscFormat.DrawingObjectsController.prototype.applyDocContentFunction.call(this, CDocumentContent.prototype.AddToParagraph, [paraItem, bRecalculate], CTable.prototype.AddToParagraph);
            }
            else if(this.selectedObjects.length === 1
                && this.selectedObjects[0].getObjectType() === AscDFH.historyitem_type_Shape
                &&  !AscFormat.CheckLinePreset(this.selectedObjects[0].getPresetGeom()))
            {
                this.selection.textSelection = this.selectedObjects[0];
                this.selection.textSelection.paragraphAdd(paraItem, bRecalculate);
                if(AscFormat.isRealNumber(this.selection.textSelection.selectStartPage))
                    this.selection.textSelection.select(this, this.selection.textSelection.selectStartPage);
            }
            else if(this.selectedObjects.length > 0)
            {
                if(this.parent)
                {
                    this.parent.GoTo_Text();
                    this.resetSelection();
                }
            }
        }
    };

    CGroupShape.prototype.applyTextFunction = AscFormat.DrawingObjectsController.prototype.applyTextFunction;

    CGroupShape.prototype.applyDocContentFunction = AscFormat.DrawingObjectsController.prototype.applyDocContentFunction;

    CGroupShape.prototype.applyAllAlign = function(val)
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(typeof this.spTree[i].applyAllAlign === "function")
            {
                this.spTree[i].applyAllAlign(val);
            }
        }
    };

    CGroupShape.prototype.applyAllSpacing = function(val)
    {

        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(typeof this.spTree[i].applyAllSpacing === "function")
            {
                this.spTree[i].applyAllSpacing(val);
            }
        }
    };

    CGroupShape.prototype.applyAllNumbering = function(val)
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(typeof this.spTree[i].applyAllNumbering === "function")
            {
                this.spTree[i].applyAllNumbering(val);
            }
        }
    };

    CGroupShape.prototype.applyAllIndent = function(val)
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(typeof this.spTree[i].applyAllIndent === "function")
            {
                this.spTree[i].applyAllIndent(val);
            }
        }
    };

    CGroupShape.prototype.checkExtentsByDocContent = function()
    {
        var bRet = false;
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(typeof this.spTree[i].checkExtentsByDocContent === "function")
            {
                if(this.spTree[i].checkExtentsByDocContent())
                {
                    bRet = true;
                }
            }
        }
        return bRet;
    };

    CGroupShape.prototype.changeSize = function(kw, kh)
    {
        if(this.spPr && this.spPr.xfrm && this.spPr.xfrm.isNotNullForGroup())
        {
            var xfrm = this.spPr.xfrm;
            xfrm.setOffX(xfrm.offX * kw);
            xfrm.setOffY(xfrm.offY * kh);
            xfrm.setExtX(xfrm.extX * kw);
            xfrm.setExtY(xfrm.extY * kh);
            xfrm.setChExtX(xfrm.chExtX*kw);
            xfrm.setChExtY(xfrm.chExtY*kh);
            xfrm.setChOffX(xfrm.chOffX*kw);
            xfrm.setChOffY(xfrm.chOffY*kh);
        }
        for(var i = 0; i < this.spTree.length; ++i)
        {
            this.spTree[i].changeSize(kw, kh);
        }
    };

    CGroupShape.prototype.recalculateTransform = function()
    {
        this.cachedImage = null;
        var xfrm;
        if(this.spPr.xfrm.isNotNullForGroup())
            xfrm = this.spPr.xfrm;
        else
        {
            xfrm = new AscFormat.CXfrm();
            xfrm.offX = 0;
            xfrm.offY = 0;
            xfrm.extX = 5;
            xfrm.extY = 5;
            xfrm.chOffX = 0;
            xfrm.chOffY = 0;
            xfrm.chExtX = 5;
            xfrm.chExtY = 5;
        }

        if(!isRealObject(this.group))
        {
            this.x = xfrm.offX;
            this.y = xfrm.offY;
            this.extX = xfrm.extX;
            this.extY = xfrm.extY;
            this.rot = AscFormat.isRealNumber(xfrm.rot) ? xfrm.rot : 0;
            this.flipH = this.flipH === true;
            this.flipV = this.flipV === true;
        }
        else
        {
            var scale_scale_coefficients = this.group.getResultScaleCoefficients();
            this.x = scale_scale_coefficients.cx*(xfrm.offX - this.group.spPr.xfrm.chOffX);
            this.y = scale_scale_coefficients.cy*(xfrm.offY - this.group.spPr.xfrm.chOffY);
            this.extX = scale_scale_coefficients.cx*xfrm.extX;
            this.extY = scale_scale_coefficients.cy*xfrm.extY;
            this.rot = AscFormat.isRealNumber(xfrm.rot) ? xfrm.rot : 0;
            this.flipH = xfrm.flipH === true;
            this.flipV = xfrm.flipV === true;
        }
        this.transform.Reset();
        var hc = this.extX*0.5;
        var vc = this.extY*0.5;
        global_MatrixTransformer.TranslateAppend(this.transform, -hc, -vc);
        if(this.flipH)
            global_MatrixTransformer.ScaleAppend(this.transform, -1, 1);
        if(this.flipV)
            global_MatrixTransformer.ScaleAppend(this.transform, 1, -1);
        global_MatrixTransformer.RotateRadAppend(this.transform, -this.rot);
        global_MatrixTransformer.TranslateAppend(this.transform, this.x + hc, this.y + vc);
        if(isRealObject(this.group))
        {
            global_MatrixTransformer.MultiplyAppend(this.transform, this.group.getTransformMatrix());
        }
        this.invertTransform = global_MatrixTransformer.Invert(this.transform);
        //if(this.drawingBase && !this.group)
        //{
        //    this.drawingBase.setGraphicObjectCoords();
        //}
    };

    CGroupShape.prototype.getTransformMatrix = function()
    {
        if(this.recalcInfo.recalculateTransform)
        {
            this.recalculateTransform();
        }
        return this.transform;
    };

    CGroupShape.prototype.getSnapArrays = function(snapX, snapY)
    {
        var transform = this.getTransformMatrix();
        snapX.push(transform.tx);
        snapX.push(transform.tx + this.extX*0.5);
        snapX.push(transform.tx + this.extX);
        snapY.push(transform.ty);
        snapY.push(transform.ty + this.extY*0.5);
        snapY.push(transform.ty + this.extY);
        for(var i = 0; i < this.arrGraphicObjects.length; ++i)
        {
            if(this.arrGraphicObjects[i].getSnapArrays)
            {
                this.arrGraphicObjects[i].getSnapArrays(snapX, snapY);
            }
        }
    };

    CGroupShape.prototype.getPlaceholderType = function()
    {
        return this.isPlaceholder() ? this.nvGrpSpPr.nvPr.ph.type : null;
    };

    CGroupShape.prototype.getPlaceholderIndex = function()
    {
        return this.isPlaceholder() ? this.nvGrpSpPr.nvPr.ph.idx : null;
    };

    CGroupShape.prototype.getPhType = function()
    {
        return this.isPlaceholder() ? this.nvGrpSpPr.nvPr.ph.type : null;
    };

    CGroupShape.prototype.getPhIndex = function()
    {
        return this.isPlaceholder() ? this.nvGrpSpPr.nvPr.ph.idx : null;
    };

    CGroupShape.prototype.getSelectionState = function()
    {
        var selection_state = {};
        if(this.selection.textSelection)
        {
            selection_state.textObject = this.selection.textSelection;
            selection_state.selectStartPage = this.selection.textSelection.selectStartPage;
            selection_state.textSelection = this.selection.textSelection.getDocContent().GetSelectionState();
        }
        else if(this.selection.chartSelection)
        {
            selection_state.chartObject = this.selection.chartSelection;
            selection_state.selectStartPage = this.selection.chartSelection.selectStartPage;
            selection_state.chartSelection = this.selection.chartSelection.getSelectionState();
        }
        else
        {
            selection_state.selection = [];
            for(var i = 0; i < this.selectedObjects.length; ++i)
            {
                selection_state.selection.push({object: this.selectedObjects[i], pageIndex: this.selectedObjects[i].selectStartPage});
            }
        }
        return selection_state;
    };

    CGroupShape.prototype.setSelectionState = function(selection_state)
    {
        this.resetSelection(this);
        if(selection_state.textObject)
        {
            this.selectObject(selection_state.textObject, selection_state.selectStartPage);
            this.selection.textSelection = selection_state.textObject;
            selection_state.textObject.getDocContent().SetSelectionState(selection_state.textSelection, selection_state.textSelection.length-1);
        }
        else if(selection_state.chartSelection)
        {
            this.selectObject(selection_state.chartObject, selection_state.selectStartPage);
            this.selection.chartSelection = selection_state.chartObject;
            selection_state.chartObject.setSelectionState(selection_state.chartSelection);
        }
        else
        {
            for(var i = 0; i < selection_state.selection.length; ++i)
            {
                this.selectObject(selection_state.selection[i].object, selection_state.selection[i].pageIndex);
            }
        }
    };

    CGroupShape.prototype.documentUpdateRulersState = function()
    {
        if(this.selectedObjects.length === 1 && this.selectedObjects[0].documentUpdateRulersState)
            this.selectedObjects[0].documentUpdateRulersState();
    };

    CGroupShape.prototype.updateChartReferences = function(oldWorksheet, newWorksheet, bNoRebuildCache)
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].updateChartReferences)
                this.spTree[i].updateChartReferences(oldWorksheet, newWorksheet, bNoRebuildCache);
        }
    };

    CGroupShape.prototype.rebuildSeries = function(data)
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].rebuildSeries)
                this.spTree[i].rebuildSeries(data);
        }
    };

    CGroupShape.prototype.CheckNeedRecalcAutoFit = function(oSectPr)
    {
        var bRet = false;
        for(var i = 0;  i< this.spTree.length; ++i)
        {
            if(this.spTree[i].CheckNeedRecalcAutoFit && this.spTree[i].CheckNeedRecalcAutoFit(oSectPr))
            {
                bRet = true;
            }
        }
        if(bRet)
        {
            this.recalcWrapPolygon();
        }
        return bRet;
    };

    CGroupShape.prototype.CheckGroupSizes = function()
    {
        var bRet = false;
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].checkExtentsByDocContent)
            {
                if(this.spTree[i].checkExtentsByDocContent(undefined, false))
                {
                    bRet = true;
                }
            }
        }
        if(bRet)
        {
            if(!this.group)
            {
                this.updateCoordinatesAfterInternalResize();
            }
            if(this.parent instanceof ParaDrawing)
            {
                this.parent.CheckWH();
            }
        }
        return bRet;
    };

    CGroupShape.prototype.GetRevisionsChangeParagraph = function(SearchEngine){
        var i;
        if(this.selectedObjects.length === 0){
            if(SearchEngine.Get_Direction() > 0){
                i = 0;
            }
            else{
                i = this.arrGraphicObjects.length - 1;
            }
        }
        else{
            if(SearchEngine.Get_Direction() > 0){
                for(i = 0; i < this.arrGraphicObjects.length; ++i){
                    if(this.arrGraphicObjects[i].selected){
                        break;
                    }
                }
                if(i === this.arrGraphicObjects.length){
                    return;
                }
            }
            else{
                for(i = this.arrGraphicObjects.length - 1; i > -1 ; --i){
                    if(this.arrGraphicObjects[i].selected){
                        break;
                    }
                }
                if(i === -1){
                    return;
                }
            }
        }
        while(!SearchEngine.Is_Found()){
            if(this.arrGraphicObjects[i].GetRevisionsChangeParagraph){
                this.arrGraphicObjects[i].GetRevisionsChangeParagraph(SearchEngine);
            }
            if(SearchEngine.Get_Direction() > 0){
                if(i === this.arrGraphicObjects.length - 1){
                    break;
                }
                ++i;
            }
            else{
                if(i === 0){
                    break;
                }
                --i;
            }
        }
    };

    CGroupShape.prototype.Search  = function(Str, Props, SearchEngine, Type)
    {
        var Len = this.arrGraphicObjects.length;
        for(var i = 0; i < Len; ++i)
        {
            if(this.arrGraphicObjects[i].Search)
            {
                this.arrGraphicObjects[i].Search(Str, Props, SearchEngine, Type);
            }
        }
    };

    CGroupShape.prototype.Search_GetId  = function(bNext, bCurrent)
    {
        var Current = -1;
        var Len = this.arrGraphicObjects.length;
       
        var Id = null;
        if ( true === bCurrent )
        {
            for(var i = 0; i < Len; ++i)
            {                
                if(this.arrGraphicObjects[i] === this.selection.textSelection)
                {
                    Current = i;
                    break;
                }
            } 
        }
        
        if ( true === bNext )
        {      
            var Start = ( -1 !== Current ? Current : 0 );
            
            for ( var i = Start; i < Len; i++ )
            {
                if ( this.arrGraphicObjects[i].Search_GetId )
                {
                    Id = this.arrGraphicObjects[i].Search_GetId(true, i === Current ? true : false);
                    if ( null !== Id )
                        return Id;
                }
            }
        }        
        else
        {
            var Start = ( -1 !== Current ? Current : Len - 1 );

            for ( var i = Start; i >= 0; i-- )
            {
                if ( this.arrGraphicObjects[i].Search_GetId )
                {
                    Id = this.arrGraphicObjects[i].Search_GetId(false, i === Current ? true : false);
                    if ( null !== Id )
                        return Id;
                }
            }
        }
                
        return null;
    };

    CGroupShape.prototype.getCompiledFill = function()
    {
        this.compiledFill = null;
        if(isRealObject(this.spPr) && isRealObject(this.spPr.Fill) && isRealObject(this.spPr.Fill.fill))
        {
            this.compiledFill = this.spPr.Fill.createDuplicate();
            if(this.compiledFill && this.compiledFill.fill && this.compiledFill.fill.type === Asc.c_oAscFill.FILL_TYPE_GRP)
            {
                if(this.group)
                {
                    var group_compiled_fill = this.group.getCompiledFill();
                    if (isRealObject(group_compiled_fill) && isRealObject(group_compiled_fill.fill)) {
                        this.compiledFill = group_compiled_fill.createDuplicate();
                    }
                    else
                    {
                        this.compiledFill = null;
                    }
                }
                else
                {
                    this.compiledFill = null;
                }
            }
        }
        else if(isRealObject(this.group))
        {
            var group_compiled_fill = this.group.getCompiledFill();
            if(isRealObject(group_compiled_fill) && isRealObject(group_compiled_fill.fill))
            {
                this.compiledFill = group_compiled_fill.createDuplicate();
            }
            else
            {
                var hierarchy = this.getHierarchy();
                for(var i = 0; i < hierarchy.length; ++i)
                {
                    if(isRealObject(hierarchy[i]) && isRealObject(hierarchy[i].spPr) && isRealObject(hierarchy[i].spPr.Fill) && isRealObject(hierarchy[i].spPr.Fill.fill))
                    {
                        this.compiledFill = hierarchy[i].spPr.Fill.createDuplicate();
                        break;
                    }
                }
            }
        }
        else
        {
            var hierarchy = this.getHierarchy();
            for(var i = 0; i < hierarchy.length; ++i)
            {
                if(isRealObject(hierarchy[i]) && isRealObject(hierarchy[i].spPr) && isRealObject(hierarchy[i].spPr.Fill) && isRealObject(hierarchy[i].spPr.Fill.fill))
                {
                    this.compiledFill = hierarchy[i].spPr.Fill.createDuplicate();
                    break;
                }
            }
        }
        return this.compiledFill;
    };

    CGroupShape.prototype.getCompiledLine = function()
    {
        return null;
    };

    CGroupShape.prototype.setVerticalAlign  = function(align)
    {
        for(var _shape_index = 0; _shape_index < this.spTree.length; ++_shape_index)
        {
            if(this.spTree[_shape_index].setVerticalAlign)
            {
                this.spTree[_shape_index].setVerticalAlign(align);
            }
        }
    };

    CGroupShape.prototype.setVert  = function(vert)
    {
        for(var _shape_index = 0; _shape_index < this.spTree.length; ++_shape_index)
        {
            if(this.spTree[_shape_index].setVert)
            {
                this.spTree[_shape_index].setVert(vert);
            }
        }
    };

    CGroupShape.prototype.setPaddings = function(paddings)
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].setPaddings)
            {
                this.spTree[i].setPaddings(paddings);
            }
        }
    };

    CGroupShape.prototype.setColumnNumber = function(num){
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].setColumnNumber)
            {
                this.spTree[i].setColumnNumber(num);
            }
        }
    };

    CGroupShape.prototype.setColumnSpace = function(spcCol){
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].setColumnSpace)
            {
                this.spTree[i].setColumnSpace(spcCol);
            }
        }
    };

    CGroupShape.prototype.changePresetGeom = function(preset)
    {
        for(var _shape_index = 0; _shape_index < this.spTree.length; ++_shape_index)
        {
            if(this.spTree[_shape_index].getObjectType() === AscDFH.historyitem_type_Shape)
            {
                this.spTree[_shape_index].changePresetGeom(preset);
            }
        }
    };

    CGroupShape.prototype.changeFill = function(fill)
    {
        for(var _shape_index = 0; _shape_index < this.spTree.length; ++_shape_index)
        {
            if(this.spTree[_shape_index].changeFill)
            {
                this.spTree[_shape_index].changeFill(fill);
            }
        }
    };

    CGroupShape.prototype.changeLine = function(line)
    {
        for(var _shape_index = 0; _shape_index < this.spTree.length; ++_shape_index)
        {
            if(this.spTree[_shape_index].changeLine)
            {
                this.spTree[_shape_index].changeLine(line);
            }
        }
    };

    CGroupShape.prototype.canUnGroup = function()
    {
        return true;
    };

    CGroupShape.prototype.normalize = function()
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            this.spTree[i].normalize();
        }
		AscFormat.CGraphicObjectBase.prototype.normalize.call(this);
        var xfrm = this.spPr.xfrm;
        xfrm.setChExtX(xfrm.extX);
        xfrm.setChExtY(xfrm.extY);
        xfrm.setChOffX(0);
        xfrm.setChOffY(0);
    };

    CGroupShape.prototype.updateCoordinatesAfterInternalResize = function()
    {
        this.normalize();
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].isGroup())
                this.spTree[i].updateCoordinatesAfterInternalResize();
        }

        var sp_tree = this.spTree;

        var min_x, max_x, min_y, max_y;
        var sp = sp_tree[0];
        var xfrm  = sp.spPr.xfrm;
        var rot = xfrm.rot == null ? 0 : xfrm.rot;
        var xc, yc;
        if(AscFormat.checkNormalRotate(rot))
        {
            min_x = xfrm.offX;
            min_y = xfrm.offY;
            max_x = xfrm.offX + xfrm.extX;
            max_y = xfrm.offY + xfrm.extY;
        }
        else
        {
            xc = xfrm.offX + xfrm.extX*0.5;
            yc = xfrm.offY + xfrm.extY*0.5;
            min_x = xc - xfrm.extY*0.5;
            min_y = yc - xfrm.extX*0.5;
            max_x = xc + xfrm.extY*0.5;
            max_y = yc + xfrm.extX*0.5;
        }
        var cur_max_x, cur_min_x, cur_max_y, cur_min_y;
        for(i = 1; i < sp_tree.length; ++i)
        {
            sp = sp_tree[i];
            xfrm  = sp.spPr.xfrm;
            rot = xfrm.rot == null ? 0 : xfrm.rot;

            if(AscFormat.checkNormalRotate(rot))
            {
                cur_min_x = xfrm.offX;
                cur_min_y = xfrm.offY;
                cur_max_x = xfrm.offX + xfrm.extX;
                cur_max_y = xfrm.offY + xfrm.extY;
            }
            else
            {
                xc = xfrm.offX + xfrm.extX*0.5;
                yc = xfrm.offY + xfrm.extY*0.5;
                cur_min_x = xc - xfrm.extY*0.5;
                cur_min_y = yc - xfrm.extX*0.5;
                cur_max_x = xc + xfrm.extY*0.5;
                cur_max_y = yc + xfrm.extX*0.5;
            }
            if(cur_max_x > max_x)
                max_x = cur_max_x;
            if(cur_min_x < min_x)
                min_x = cur_min_x;

            if(cur_max_y > max_y)
                max_y = cur_max_y;
            if(cur_min_y < min_y)
                min_y = cur_min_y;
        }

        var temp;
        var x_min_clear = min_x;
        var y_min_clear = min_y;
        if(this.spPr.xfrm.flipH === true)
        {
            temp = max_x;
            max_x = this.spPr.xfrm.extX - min_x;
            min_x = this.spPr.xfrm.extX - temp;
        }

        if(this.spPr.xfrm.flipV === true)
        {
            temp = max_y;
            max_y = this.spPr.xfrm.extY - min_y;
            min_y = this.spPr.xfrm.extY - temp;
        }

        var old_x0, old_y0;
        var xfrm = this.spPr.xfrm;
        var rot = xfrm.rot == null ? 0 : xfrm.rot;
        var hc = xfrm.extX*0.5;
        var vc = xfrm.extY*0.5;
        old_x0 = this.spPr.xfrm.offX + hc - (hc*Math.cos(rot) - vc*Math.sin(rot));
        old_y0 = this.spPr.xfrm.offY  + vc - (hc*Math.sin(rot) + vc*Math.cos(rot));
        var t_dx = min_x*Math.cos(rot) - min_y*Math.sin(rot);
        var t_dy = min_x*Math.sin(rot) + min_y*Math.cos(rot);
        var new_x0, new_y0;
        new_x0 = old_x0 + t_dx;
        new_y0 = old_y0 + t_dy;
        var new_hc = Math.abs(max_x - min_x)*0.5;
        var new_vc = Math.abs(max_y - min_y)*0.5;
        var new_xc = new_x0 + (new_hc*Math.cos(rot) - new_vc*Math.sin(rot));
        var new_yc = new_y0 + (new_hc*Math.sin(rot) + new_vc*Math.cos(rot));

        var pos_x, pos_y;
        pos_x = new_xc - new_hc;
        pos_y = new_yc - new_vc;

        var xfrm = this.spPr.xfrm;
        if(this.group || !(editor && editor.isDocumentEditor))
        {
            xfrm.setOffX(pos_x);
            xfrm.setOffY(pos_y);
        }
        xfrm.setExtX(Math.abs(max_x - min_x));
        xfrm.setExtY(Math.abs(max_y - min_y));
        xfrm.setChExtX(Math.abs(max_x - min_x));
        xfrm.setChExtY(Math.abs(max_y - min_y));
        xfrm.setChOffX(0);
        xfrm.setChOffY(0);
        for(i = 0; i < sp_tree.length; ++i)
        {
            sp_tree[i].spPr.xfrm.setOffX(sp_tree[i].spPr.xfrm.offX - x_min_clear);
            sp_tree[i].spPr.xfrm.setOffY(sp_tree[i].spPr.xfrm.offY - y_min_clear);
        }
        this.checkDrawingBaseCoords();
        return {posX: pos_x, posY: pos_y};
    };

    CGroupShape.prototype.select = CShape.prototype.select;

    CGroupShape.prototype.deselect = function(drawingObjectsController)
    {
        this.selected = false;
        var selected_objects;
        if(!isRealObject(this.group))
            selected_objects = drawingObjectsController.selectedObjects;
        else
            selected_objects = this.group.getMainGroup().selectedObjects;
        for(var i = 0; i < selected_objects.length; ++i)
        {
            if(selected_objects[i] === this)
            {
                selected_objects.splice(i, 1);
                break;
            }
        }
        return this;
    };

    CGroupShape.prototype.getParentObjects = function()
    {
        var parents = {slide: null, layout: null, master: null, theme: null};
        return parents;
    };

    CGroupShape.prototype.applyTextArtForm = function(sPreset)
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].applyTextArtForm)
            {
                this.spTree[i].applyTextArtForm(sPreset);
            }
        }
    };

    CGroupShape.prototype.createRotateTrack = function()
    {
        return new AscFormat.RotateTrackGroup(this);
    };

    CGroupShape.prototype.createMoveTrack = function()
    {
        return new AscFormat.MoveGroupTrack(this);
    };

    CGroupShape.prototype.createResizeTrack = function(cardDirection)
    {
        return new AscFormat.ResizeTrackGroup(this, cardDirection);
    };

    CGroupShape.prototype.resetSelection = function(graphicObjects)
    {
        this.selection.textSelection = null;
        if(this.selection.chartSelection)
        {
            this.selection.chartSelection.resetSelection();
        }
        this.selection.chartSelection = null;

        for(var i = this.selectedObjects.length - 1; i > -1; --i)
        {
            var old_gr = this.selectedObjects[i].group;
            var obj = this.selectedObjects[i];
            obj.group = this;
            obj.deselect(graphicObjects);
            obj.group = old_gr;
        }
    };

    CGroupShape.prototype.resetInternalSelection = AscFormat.DrawingObjectsController.prototype.resetInternalSelection;

    CGroupShape.prototype.recalculateCurPos = AscFormat.DrawingObjectsController.prototype.recalculateCurPos;

    CGroupShape.prototype.loadDocumentStateAfterLoadChanges = AscFormat.DrawingObjectsController.prototype.loadDocumentStateAfterLoadChanges;
    CGroupShape.prototype.getAllConnectors = AscFormat.DrawingObjectsController.prototype.getAllConnectors;
    CGroupShape.prototype.getAllShapes = AscFormat.DrawingObjectsController.prototype.getAllShapes;

    CGroupShape.prototype.checkDrawingBaseCoords = CShape.prototype.checkDrawingBaseCoords;

    CGroupShape.prototype.setDrawingBaseCoords = CShape.prototype.setDrawingBaseCoords;

    CGroupShape.prototype.deleteBFromSerialize = CShape.prototype.deleteBFromSerialize;

    CGroupShape.prototype.setBFromSerialize = CShape.prototype.setBFromSerialize;

    CGroupShape.prototype.calculateSnapArrays = function(snapArrayX, snapArrayY)
    {
        var sp;
        for(var i = 0; i < this.arrGraphicObjects.length; ++i)
        {
            sp = this.arrGraphicObjects[i];
            sp.calculateSnapArrays(snapArrayX, snapArrayY);
            sp.recalculateSnapArrays();
        }
    };

    CGroupShape.prototype.setNvSpPr = function(pr)
    {
        History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_GroupShapeSetNvGrpSpPr, this.nvGrpSpPr, pr));
        this.nvGrpSpPr = pr;
    };

    CGroupShape.prototype.Restart_CheckSpelling = function()
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            this.spTree[i].Restart_CheckSpelling && this.spTree[i].Restart_CheckSpelling();
        }
    };

    CGroupShape.prototype.recalculateLocalTransform =  CShape.prototype.recalculateLocalTransform;

    CGroupShape.prototype.bringToFront  = function()//перемещаем заселекченые объекты наверх
    {
        var i;
        var arrDrawings = [];
        for(i = this.spTree.length - 1;  i > -1; --i)
        {
            if(this.spTree[i].getObjectType() === AscDFH.historyitem_type_GroupShape)
            {
                this.spTree[i].bringToFront();
            }
            else if(this.spTree[i].selected)
            {
                arrDrawings.push(this.removeFromSpTreeByPos(i));
            }
        }
        for(i = arrDrawings.length-1; i > -1 ; --i)
        {
            this.addToSpTree(null, arrDrawings[i]);
        }
    };

    CGroupShape.prototype.bringForward  = function()
    {
        var i;
        for(i = this.spTree.length-1; i > -1; --i)
        {
            if(this.spTree[i].getObjectType() === AscDFH.historyitem_type_GroupShape)
            {
                this.spTree[i].bringForward();
            }
            else if(i < this.spTree.length-1 && this.spTree[i].selected && !this.spTree[i+1].selected)
            {
                var item = this.removeFromSpTreeByPos(i);
                this.addToSpTree(i+1, item);
            }
        }
    };

    CGroupShape.prototype.sendToBack  = function()
    {
        var i, arrDrawings = [];
        for(i = this.spTree.length-1; i > -1; --i)
        {
            if(this.spTree[i].getObjectType() === AscDFH.historyitem_type_GroupShape)
            {
                this.spTree[i].sendToBack();
            }
            else if(this.spTree[i].selected)
            {
                arrDrawings.push(this.removeFromSpTreeByPos(i));
            }
        }
        arrDrawings.reverse();
        for(i = 0; i < arrDrawings.length; ++i)
        {
            this.addToSpTree(i, arrDrawings[i]);
        }
    };

    CGroupShape.prototype.bringBackward  = function()
    {
        var i;
        for(i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].getObjectType() === AscDFH.historyitem_type_GroupShape)
            {
                this.spTree[i].bringBackward();
            }
            else if(i > 0 && this.spTree[i].selected && !this.spTree[i-1].selected)
            {
                this.addToSpTree(i-1, this.removeFromSpTreeByPos(i));
            }
        }
    };

    CGroupShape.prototype.Refresh_RecalcData = function(oData)
    {
        if(oData){
            switch (oData.Type){

                case AscDFH.historyitem_ShapeSetBDeleted:{
                    if(!this.bDeleted){
                        this.addToRecalculate();
                    }
                    break;
                }
                case AscDFH.historyitem_GroupShapeAddToSpTree:
                case AscDFH.historyitem_GroupShapeRemoveFromSpTree:{
                    if(!this.bDeleted){
                        this.handleUpdateSpTree();
                    }
                    break;
                }
            }
        }
    };

    CGroupShape.prototype.checkTypeCorrect = function()
    {
        if(!this.spPr){
            return false;
        }
        if(this.spTree.length === 0){
            return false;
        }
        return true;
    };

    CGroupShape.prototype.resetGroups = function()
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].resetGroups){
                this.spTree[i].resetGroups();
            }
            if(this.spTree[i].group !== this){
                this.spTree[i].setGroup(this);
            }
        }
    };

    CGroupShape.prototype.findConnector = function(x, y){
        for(var i = this.spTree.length - 1; i > -1; --i ){
            var oConInfo = this.spTree[i].findConnector(x, y);
            if(oConInfo){
                return oConInfo;
            }
        }
        return null;
    };

    CGroupShape.prototype.findConnectionShape = function(x, y){
        for(var i = this.spTree.length - 1; i > -1; --i){
            var _ret = this.spTree[i].findConnectionShape(x, y);
            if(_ret){
                return _ret;
            }
        }
        return null;
    };

    CGroupShape.prototype.GetAllContentControls = function(arrContentControls){
        for(var i = 0; i < this.spTree.length; ++i)
        {
            this.spTree[i].GetAllContentControls(arrContentControls);
        }
    };


    CGroupShape.prototype.getCopyWithSourceFormatting = function(oIdMap){
        return this.copy(oIdMap, true);
    };
    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].CGroupShape = CGroupShape;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
var GLOBAL_PATH_COUNT = 0;
(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {


    var MAX_LABELS_COUNT = 300;
// Import
    var oNonSpaceRegExp = new RegExp('' + String.fromCharCode(0x00A0),'g');
var c_oAscChartType = AscCommon.c_oAscChartType;
var c_oAscChartSubType = AscCommon.c_oAscChartSubType;
var parserHelp = AscCommon.parserHelp;
var g_oIdCounter = AscCommon.g_oIdCounter;
var g_oTableId = AscCommon.g_oTableId;
var oNumFormatCache = AscCommon.oNumFormatCache;
var CellAddress = AscCommon.CellAddress;
var isRealObject = AscCommon.isRealObject;
    var History = AscCommon.History;
    var global_MatrixTransformer = AscCommon.global_MatrixTransformer;

var CShape = AscFormat.CShape;
var Ax_Counter = AscFormat.Ax_Counter;
var checkTxBodyDefFonts = AscFormat.checkTxBodyDefFonts;

var c_oAscNumFormatType = Asc.c_oAscNumFormatType;
var c_oAscTickLabelsPos = Asc.c_oAscTickLabelsPos;
var c_oAscChartLegendShowSettings = Asc.c_oAscChartLegendShowSettings;
var c_oAscTickMark = Asc.c_oAscTickMark;

var EFFECT_NONE = 0;
var EFFECT_SUBTLE = 1;
var EFFECT_MODERATE = 2;
var EFFECT_INTENSE = 3;

var CHART_STYLE_MANAGER = null;
var SKIP_LBL_LIMIT = 100;

    var BAR_SHAPE_CONE = 0;
    var BAR_SHAPE_CONETOMAX = 1;
    var BAR_SHAPE_BOX = 2;
    var BAR_SHAPE_CYLINDER = 3;
    var BAR_SHAPE_PYRAMID = 4;
    var BAR_SHAPE_PYRAMIDTOMAX = 5;

    var DISP_BLANKS_AS_GAP = 0;
    var DISP_BLANKS_AS_SPAN = 1;
    var DISP_BLANKS_AS_ZERO = 2;

    function removePtsFromLit(lit)
    {
        var i;
        var start_idx = Array.isArray(lit.pts) ? lit.pts.length - 1 : -1;
        for(i = start_idx; i > -1; --i)
        {
            lit.removeDPt(i);
        }
    }
    function removeAllSeriesFromChart(chart)
    {
        for(var i = chart.series.length-1; i > -1; --i)
            chart.removeSeries(i);
    }

    function checkVerticalTitle(title)
    {
        return false;
    }



    function GetTextPrFormArrObjects(aObjects, bFirstBreak, bLbl)
    {
        var oResultTextPr;
        for(var i = 0; i < aObjects.length; ++i)
        {
            var oContent = aObjects[i];
            oContent = bLbl ? oContent.compiledDlb && oContent.compiledDlb.txBody && oContent.compiledDlb.txBody.content : oContent.txBody && oContent.txBody.content;
            if(!oContent)
                continue;
            oContent.Set_ApplyToAll(true);
            var oTextPr = oContent.GetCalculatedTextPr();
            oContent.Set_ApplyToAll(false);
            if(!oResultTextPr)
            {
                oResultTextPr = oTextPr;
                if(bFirstBreak)
                {
                    return oResultTextPr;
                }
            }
            else
            {
                oResultTextPr.Compare(oTextPr);
            }
        }
        return oResultTextPr;
    }


    function checkBlackUnifill(unifill, bLines)
{
    if(unifill && unifill.fill && unifill.fill.color)
    {
        var RGBA = unifill.fill.color.RGBA;
        if(RGBA.R === 0 && RGBA.G === 0 && RGBA.B === 0)
        {
            if(bLines)
            {
                RGBA.R = 134;
                RGBA.G = 134;
                RGBA.B = 134;
            }
            else
            {
                RGBA.R = 255;
                RGBA.G = 255;
                RGBA.B = 255;
            }
        }
    }
}

function CRect(x, y, w, h){
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.fHorPadding = 0.0;
        this.fVertPadding = 0.0;
}

    CRect.prototype.copy = function(){
        var ret  = new CRect(this.x, this.y, this.w, this.h);
        ret.fHorPadding = this.fHorPadding;
        ret.fVertPadding = this.fVertPadding;
        return ret;
    };
    CRect.prototype.intersection = function(oRect){
        if(this.x + this.w < oRect.x || oRect.x + oRect.w < this.x
            || this.y + this.h < oRect.y || oRect.y + oRect.h < this.y){
            return false;
        }

        var x0, y0, x1, y1;
        var bResetHorPadding = true, bResetVertPadding = true;
        if(this.fHorPadding > 0.0 && oRect.fHorPadding > 0.0){
            x0 = this.x + oRect.fHorPadding;
            bResetHorPadding = false;
        }
        else{
            x0 = Math.max(this.x, oRect.x);
        }
        if(this.fVertPadding > 0.0 && oRect.fVertPadding > 0.0){
            y0 = this.y + oRect.fVertPadding;
            bResetVertPadding = false;
        }
        else{
            y0 = Math.max(this.y, oRect.y);
        }
        if(this.fHorPadding < 0.0 && oRect.fHorPadding < 0.0){
            x1 = this.x + this.w + oRect.fHorPadding;
            bResetHorPadding = false;
        }
        else{
            x1 = Math.min(this.x + this.w, oRect.x + oRect.w);
        }
        if(this.fVertPadding < 0.0 && oRect.fVertPadding < 0.0){
            y1 = this.y + this.h + oRect.fVertPadding;
            bResetVertPadding = false;
        }
        else{
            y1 = Math.min(this.y + this.h, oRect.y + oRect.h);
        }
        if(bResetHorPadding){
            this.fHorPadding = 0.0;
        }
        if(bResetVertPadding){
            this.fVertPadding = 0.0;
        }
        this.x = x0;
        this.y = y0;
        this.w = x1 - x0;
        this.h = y1 - y0;
        return true;

    };

function BBoxInfo(worksheet, bbox)
{
    this.worksheet = worksheet;
    if(window["Asc"] && typeof window["Asc"].Range === "function")
    {
        this.bbox = window["Asc"].Range(bbox.c1, bbox.r1, bbox.c2, bbox.r2, false);
    }
    else
    {
        this.bbox = bbox;
    }
}

BBoxInfo.prototype =
{
    checkIntersection: function(bboxInfo)
    {
        if(this.worksheet !== bboxInfo.worksheet)
        {
            return false;
        }
        return this.bbox.isIntersect(bboxInfo.bbox);
    }
};

function CreateUnifillSolidFillSchemeColorByIndex(index)
{
    var ret =  new AscFormat.CUniFill();
    ret.setFill(new AscFormat.CSolidFill());
    ret.fill.setColor(new AscFormat.CUniColor());
    ret.fill.color.setColor(new AscFormat.CSchemeColor());
    ret.fill.color.color.setId(index);
    return ret;
}

function CChartStyleManager()
{
    this.styles = [];
}

CChartStyleManager.prototype =
{
    init: function() {
        AscFormat.ExecuteNoHistory(
          function()
          {
              var DefaultDataPointPerDataPoint =
                [
                    [
                        CreateUniFillSchemeColorWidthTint(8, 0.885),
                        CreateUniFillSchemeColorWidthTint(8, 0.55),
                        CreateUniFillSchemeColorWidthTint(8, 0.78),
                        CreateUniFillSchemeColorWidthTint(8, 0.925),
                        CreateUniFillSchemeColorWidthTint(8, 0.7),
                        CreateUniFillSchemeColorWidthTint(8, 0.3)
                    ],
                    [
                        CreateUniFillSchemeColorWidthTint(0, 0),
                        CreateUniFillSchemeColorWidthTint(1, 0),
                        CreateUniFillSchemeColorWidthTint(2, 0),
                        CreateUniFillSchemeColorWidthTint(3, 0),
                        CreateUniFillSchemeColorWidthTint(4, 0),
                        CreateUniFillSchemeColorWidthTint(5, 0)
                    ],
                    [
                        CreateUniFillSchemeColorWidthTint(0, -0.5),
                        CreateUniFillSchemeColorWidthTint(1, -0.5),
                        CreateUniFillSchemeColorWidthTint(2, -0.5),
                        CreateUniFillSchemeColorWidthTint(3, -0.5),
                        CreateUniFillSchemeColorWidthTint(4, -0.5),
                        CreateUniFillSchemeColorWidthTint(5, -0.5)
                    ],
                    [
                        CreateUniFillSchemeColorWidthTint(8, 0.05),
                        CreateUniFillSchemeColorWidthTint(8, 0.55),
                        CreateUniFillSchemeColorWidthTint(8, 0.78),
                        CreateUniFillSchemeColorWidthTint(8, 0.15),
                        CreateUniFillSchemeColorWidthTint(8, 0.7),
                        CreateUniFillSchemeColorWidthTint(8, 0.3)
                    ]
                ];
              var s = DefaultDataPointPerDataPoint;
              var f = CreateUniFillSchemeColorWidthTint;
              this.styles[0] = new CChartStyle(EFFECT_NONE, EFFECT_SUBTLE, s[0], EFFECT_SUBTLE, EFFECT_NONE, [], 3, s[0], 7);
              this.styles[1] = new CChartStyle(EFFECT_NONE, EFFECT_SUBTLE, s[1], EFFECT_SUBTLE, EFFECT_NONE, [], 3, s[1], 7);
              for(var i = 2; i < 8; ++i)
              {
                  this.styles[i] = new CChartStyle(EFFECT_NONE, EFFECT_SUBTLE, [f(i - 2,0)], EFFECT_SUBTLE, EFFECT_NONE, [], 3, [f(i - 2,0)], 7);
              }
              this.styles[8] = new CChartStyle(EFFECT_SUBTLE, EFFECT_SUBTLE, s[0], EFFECT_SUBTLE, EFFECT_SUBTLE,  [f(12,0)], 5, s[0], 9);
              this.styles[9] = new CChartStyle(EFFECT_SUBTLE, EFFECT_SUBTLE, s[1], EFFECT_SUBTLE, EFFECT_SUBTLE,  [f(12,0)], 5, s[1], 9);
              for(i = 10; i < 16; ++i)
              {
                  this.styles[i] = new CChartStyle(EFFECT_SUBTLE, EFFECT_SUBTLE, [f(i-10,0)], EFFECT_SUBTLE, EFFECT_SUBTLE,  [f(12,0)], 5, [f(i-10,0)], 9);
              }
              this.styles[16] = new CChartStyle(EFFECT_MODERATE, EFFECT_INTENSE, s[0], EFFECT_SUBTLE, EFFECT_NONE,  [], 5, s[0], 9);
              this.styles[17] = new CChartStyle(EFFECT_MODERATE, EFFECT_INTENSE, s[1], EFFECT_INTENSE, EFFECT_NONE,  [], 5, s[1], 9);
              for(i = 18; i < 24; ++i)
              {
                  this.styles[i] = new CChartStyle(EFFECT_MODERATE, EFFECT_INTENSE, [f(i-18,0)], EFFECT_SUBTLE, EFFECT_NONE,  [], 5, [f(i-18,0)], 9);
              }
              this.styles[24] = new CChartStyle(EFFECT_INTENSE, EFFECT_INTENSE, s[0], EFFECT_SUBTLE, EFFECT_NONE,  [], 7, s[0], 13);
              this.styles[25] = new CChartStyle(EFFECT_MODERATE, EFFECT_INTENSE, s[1], EFFECT_SUBTLE, EFFECT_NONE,  [], 7, s[1], 13);
              for(i = 26; i < 32; ++i)
              {
                  this.styles[i] = new CChartStyle(EFFECT_MODERATE, EFFECT_INTENSE, [f(i-26,0)], EFFECT_SUBTLE, EFFECT_NONE,  [], 7, [f(i-26,0)], 13);
              }
              this.styles[32] = new CChartStyle(EFFECT_NONE, EFFECT_SUBTLE, s[0], EFFECT_SUBTLE, EFFECT_SUBTLE,  [f(8, -0.5)], 5, s[0], 9);
              this.styles[33] = new CChartStyle(EFFECT_NONE, EFFECT_SUBTLE, s[1], EFFECT_SUBTLE, EFFECT_SUBTLE,  s[2], 5, s[1], 9);
              for(i = 34; i < 40; ++i)
              {
                  this.styles[i] = new CChartStyle(EFFECT_NONE, EFFECT_SUBTLE, [f(i - 34, 0)], EFFECT_SUBTLE, EFFECT_SUBTLE, [f(i-34, -0.5)], 5, [f(i-34, 0)], 9);
              }
              this.styles[40] = new CChartStyle(EFFECT_INTENSE, EFFECT_INTENSE, s[3], EFFECT_SUBTLE, EFFECT_NONE, [], 5, s[3], 9);
              this.styles[41] = new CChartStyle(EFFECT_INTENSE, EFFECT_INTENSE, s[1], EFFECT_INTENSE, EFFECT_NONE, [], 5, s[1], 9);
              for(i = 42; i < 48; ++i)
              {
                  this.styles[i] = new CChartStyle(EFFECT_INTENSE, EFFECT_INTENSE, [f(i-42, 0)], EFFECT_SUBTLE, EFFECT_NONE, [], 5, [f(i-42, 0)], 9);
              }

              this.defaultLineStyles = [];
              this.defaultLineStyles[0] = new ChartLineStyle(f(15, 0.75), f(15, 0.5), f(15, 0.75), f(15, 0), EFFECT_SUBTLE);
              for(i = 0; i < 32; ++i)
              {
                  this.defaultLineStyles[i] = this.defaultLineStyles[0];
              }
              this.defaultLineStyles[32] = new ChartLineStyle(f(8, 0.75), f(8, 0.5), f(8, 0.75), f(8, 0), EFFECT_SUBTLE);
              this.defaultLineStyles[33] = this.defaultLineStyles[32];
              this.defaultLineStyles[34] = new ChartLineStyle(f(8, 0.75), f(8, 0.5), f(8, 0.75), f(8, 0), EFFECT_SUBTLE);
              for(i = 35; i < 40; ++i)
              {
                  this.defaultLineStyles[i] = this.defaultLineStyles[34];
              }
              this.defaultLineStyles[40] = new ChartLineStyle(f(8, 0.75), f(8, 0.9), f(12, 0), f(12, 0), EFFECT_NONE);
              for(i = 41; i < 48; ++i)
              {
                  this.defaultLineStyles[i] = this.defaultLineStyles[40];
              }
          },
          this, []);
    },
    getStyleByIndex: function(index)
    {
        if(AscFormat.isRealNumber(index))
        {
            return this.styles[(index - 1) % 48];
        }
        return this.styles[1];
    },

    getDefaultLineStyleByIndex: function(index)
    {
        if(AscFormat.isRealNumber(index))
        {
            return this.defaultLineStyles[(index - 1) % 48];
        }
        return this.defaultLineStyles[2];
    }
};

CHART_STYLE_MANAGER = new CChartStyleManager();



function ChartLineStyle(axisAndMajorGridLines, minorGridlines, chartArea, otherLines, floorChartArea)
{
    this.axisAndMajorGridLines = axisAndMajorGridLines;
    this.minorGridlines = minorGridlines;
    this.chartArea = chartArea;
    this.otherLines = otherLines;
    this.floorChartArea = floorChartArea;
}



function CChartStyle(effect, fill1, fill2, fill3, line1, line2, line3, line4, markerSize)
{
    this.effect = effect;
    this.fill1 = fill1;
    this.fill2 = fill2;
    this.fill3 = fill3;

    this.line1 = line1;
    this.line2 = line2;
    this.line3 = line3;
    this.line4 = line4;

    this.markerSize = markerSize;
}


function CreateUniFillSchemeColorWidthTint(schemeColorId, tintVal)
{
    return AscFormat.ExecuteNoHistory(
        function(schemeColorId, tintVal)
        {
            return CreateUniFillSolidFillWidthTintOrShade(CreateUnifillSolidFillSchemeColorByIndex(schemeColorId), tintVal);
        },
        this, [schemeColorId, tintVal]);
}


function checkFiniteNumber(num)
{
    if(AscFormat.isRealNumber(num) && isFinite(num) && num > 0)
    {
        return num;
    }
    return 0;
}

var G_O_VISITED_HLINK_COLOR = CreateUniFillSolidFillWidthTintOrShade(CreateUnifillSolidFillSchemeColorByIndex(10), 0);
var G_O_HLINK_COLOR = CreateUniFillSolidFillWidthTintOrShade(CreateUnifillSolidFillSchemeColorByIndex(11), 0);
var G_O_NO_ACTIVE_COMMENT_BRUSH = AscFormat.CreateUniFillByUniColor(AscFormat.CreateUniColorRGB(248, 231, 195));
var G_O_ACTIVE_COMMENT_BRUSH = AscFormat.CreateUniFillByUniColor(AscFormat.CreateUniColorRGB(240, 200, 120));
/*function addPointToMap(map, worksheet, row, col, pt)
{
    if(!Array.isArray(map[worksheet.getId()+""]))
    {
        map[worksheet.getId()+""] = [];
    }
    if(!Array.isArray(map[worksheet.getId()+""][row]))
    {
        map[worksheet.getId()+""][row] = [];
    }
    if(!Array.isArray(map[worksheet.getId()+""][row][col]))
    {
        map[worksheet.getId()+""][row][col] = [];
    }
    map[worksheet.getId()+""][row][col].push(pt);
}


function checkPointInMap(map, worksheet, row, col)
{
    if(map[worksheet.getId() + ""] && map[worksheet.getId() + ""][row] && map[worksheet.getId() + ""][row][col])
    {
        var cell = worksheet.getCell3(row, col);
        var pts = map[worksheet.getId() + ""][row][col];
        for(var i = 0; i < pts.length; ++i)
        {
            pts[i].setVal(cell.getValue());
        }
        return true;
    }
    else
    {
        return false;
    }
}*/


    var CChangesDrawingsBool = AscDFH.CChangesDrawingsBool;
    var CChangesDrawingsLong = AscDFH.CChangesDrawingsLong;
    var CChangesDrawingsDouble = AscDFH.CChangesDrawingsDouble;
    var CChangesDrawingsString = AscDFH.CChangesDrawingsString;
    var CChangesDrawingsObject = AscDFH.CChangesDrawingsObject;


    var drawingsChangesMap = window['AscDFH'].drawingsChangesMap;



    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetNvGrFrProps          ] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetThemeOverride        ] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ShapeSetBDeleted                     ] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetParent               ] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetChart                ] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetClrMapOvr        ] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetDate1904               ] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetExternalData         ] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetLang                 ] = CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetPivotSource          ] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetPrintSettings        ] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetProtection           ] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetRoundedCorners         ] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetSpPr                 ] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetStyle                  ] = CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetTxPr                 ] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetUserShapes           ] = CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_ChartSpace_SetGroup                ] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ExternalData_SetAutoUpdate           ] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_ExternalData_SetId                 ] = CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_PivotSource_SetFmtId                 ] = CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_PivotSource_SetName                ] = CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_Protection_SetChartObject            ] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_Protection_SetData                   ] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_Protection_SetFormatting             ] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_Protection_SetSelection              ] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_Protection_SetUserInterface          ] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_PrintSettingsSetHeaderFooter       ] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PrintSettingsSetPageMargins        ] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PrintSettingsSetPageSetup          ] = CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_HeaderFooterChartSetAlignWithMargins ] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_HeaderFooterChartSetDifferentFirst   ] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_HeaderFooterChartSetDifferentOddEven ] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_HeaderFooterChartSetEvenFooter     ] = CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_HeaderFooterChartSetEvenHeader     ] = CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_HeaderFooterChartSetFirstFooter    ] = CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_HeaderFooterChartSetFirstHeader    ] = CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_HeaderFooterChartSetOddFooter      ] = CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_HeaderFooterChartSetOddHeader      ] = CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_PageMarginsSetB                    ] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_PageMarginsSetFooter               ] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_PageMarginsSetHeader               ] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_PageMarginsSetL                    ] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_PageMarginsSetR                    ] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_PageMarginsSetT                    ] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_PageSetupSetBlackAndWhite            ] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_PageSetupSetCopies                   ] = CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_PageSetupSetDraft                    ] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_PageSetupSetFirstPageNumber          ] = CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_PageSetupSetHorizontalDpi            ] = CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_PageSetupSetOrientation              ] = CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_PageSetupSetPaperHeight            ] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_PageSetupSetPaperSize                ] = CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_PageSetupSetPaperWidth             ] = CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_PageSetupSetUseFirstPageNumb         ] = CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_PageSetupSetVerticalDpi              ] = CChangesDrawingsLong;
    
    

    function CheckParagraphTextPr(oParagraph, oTextPr)
    {
        var oParaPr = oParagraph.Pr.Copy();
        var oParaPr2 = new CParaPr();
        var oCopyTextPr = oTextPr.Copy();
        if(oCopyTextPr.FontFamily)
        {
            oCopyTextPr.RFonts.Set_FromObject(
                {
                    Ascii: {
                        Name: oCopyTextPr.FontFamily.Name,
                        Index: -1
                    },
                    EastAsia: {
                        Name: oCopyTextPr.FontFamily.Name,
                        Index: -1
                    },
                    HAnsi: {
                        Name: oCopyTextPr.FontFamily.Name,
                        Index: -1
                    },
                    CS: {
                        Name: oCopyTextPr.FontFamily.Name,
                        Index: -1
                    }
                }
            );
        }
        oParaPr2.DefaultRunPr = oCopyTextPr;
        oParaPr.Merge(oParaPr2);
        oParagraph.Set_Pr(oParaPr);
    }

    function CheckObjectTextPr(oElement, oTextPr, oDrawingDocument)
    {
        if(oElement)
        {
            if(!oElement.txPr)
            {
                oElement.setTxPr(AscFormat.CreateTextBodyFromString("", oDrawingDocument, oElement));
            }
            oElement.txPr.content.Content[0].Set_DocumentIndex(0);

            CheckParagraphTextPr(oElement.txPr.content.Content[0], oTextPr);
            if(oElement.tx && oElement.tx.rich)
            {
                var aContent = oElement.tx.rich.content.Content;
                for(var i = 0; i < aContent.length; ++i)
                {
                    CheckParagraphTextPr(aContent[i], oTextPr);
                }

                oElement.tx.rich.content.Set_ApplyToAll(true);
                var oParTextPr = new AscCommonWord.ParaTextPr(oTextPr);
                oElement.tx.rich.content.AddToParagraph(oParTextPr);
                oElement.tx.rich.content.Set_ApplyToAll(false);
            }
            CheckParagraphTextPr(oElement.txPr.content.Content[0], oTextPr);
        }
    }

    function CheckIncDecFontSize(oElement, bIncrease, oDrawingDocument,nDefaultSize)
    {
        if(oElement)
        {
            if(!oElement.txPr)
            {
                oElement.setTxPr(AscFormat.CreateTextBodyFromString("", oDrawingDocument, oElement));
            }
            var oParaPr = oElement.txPr.content.Content[0].Pr.Copy();
            oElement.txPr.content.Content[0].Set_DocumentIndex(0);
            var oCopyTextPr;
            if(oParaPr.DefaultRunPr)
            {
                oCopyTextPr = oParaPr.DefaultRunPr.Copy();
            }
            else
            {
                oCopyTextPr = new CTextPr();
            }
            oCopyTextPr.FontSize = FontSize_IncreaseDecreaseValue( bIncrease, AscFormat.isRealNumber(oCopyTextPr.FontSize) ? oCopyTextPr.FontSize : nDefaultSize);
            oParaPr.DefaultRunPr = oCopyTextPr;
            oElement.txPr.content.Content[0].Set_Pr(oParaPr);
            if(oElement.tx && oElement.tx.rich)
            {
                oElement.tx.rich.content.Set_ApplyToAll(true);
                oElement.tx.rich.content.IncreaseDecreaseFontSize(bIncrease);
                oElement.tx.rich.content.Set_ApplyToAll(false);

            }
        }
    }


    function CPathMemory(){
        this.size = 1000;
        this.ArrPathCommand = new Float64Array(this.size);
        this.curPos = -1;

        this.path = new AscFormat.Path2(this);
 }

    CPathMemory.prototype.AllocPath = function(){

        if(this.curPos + 1 >= this.ArrPathCommand.length){
            var aNewArray = new Float64Array((((3/2)*(this.curPos + 1)) >> 0) + 1);
            for(var i = 0; i < this.ArrPathCommand.length; ++i){
                aNewArray[i] = this.ArrPathCommand[i];
            }
            this.ArrPathCommand = aNewArray;
            this.path.ArrPathCommand = aNewArray;
        }

        this.path.startPos = ++this.curPos;
        this.path.curLen = 0;
        this.ArrPathCommand[this.curPos] = 0;
        return this.path;
    };

    CPathMemory.prototype.GetPath = function(index){
        this.path.startPos = index;
        this.path.curLen = 0;
        return this.path;
    };


    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetNvGrFrProps                ] = function(oClass, value){oClass.nvGraphicFramePr   = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetThemeOverride              ] = function(oClass, value){oClass.themeOverride = value;};
    drawingsChangesMap[AscDFH.historyitem_ShapeSetBDeleted                         ] = function(oClass, value){oClass.bDeleted = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetParent                     ] = function(oClass, value){oClass.parent         = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetChart                      ] = function(oClass, value){oClass.chart          = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetClrMapOvr                  ] = function(oClass, value){oClass.clrMapOvr      = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetDate1904                   ] = function(oClass, value){oClass.date1904       = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetExternalData               ] = function(oClass, value){oClass.externalData   = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetLang                       ] = function(oClass, value){oClass.lang           = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetPivotSource                ] = function(oClass, value){oClass.pivotSource    = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetPrintSettings              ] = function(oClass, value){oClass.printSettings  = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetProtection                 ] = function(oClass, value){oClass.protection     = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetRoundedCorners             ] = function(oClass, value){oClass.roundedCorners = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetSpPr                       ] = function(oClass, value){oClass.spPr           = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetStyle                      ] = function(oClass, value){oClass.style          = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetTxPr                       ] = function(oClass, value){oClass.txPr           = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetUserShapes                 ] = function(oClass, value){oClass.userShapes     = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartSpace_SetGroup                      ] = function(oClass, value){oClass.group          = value;};
    drawingsChangesMap[AscDFH.historyitem_ExternalData_SetAutoUpdate               ] = function(oClass, value){oClass.autoUpdate     = value;};
    drawingsChangesMap[AscDFH.historyitem_ExternalData_SetId                       ] = function(oClass, value){oClass.id             = value;};
    drawingsChangesMap[AscDFH.historyitem_PivotSource_SetFmtId                     ] = function(oClass, value){oClass.fmtId = value;};
    drawingsChangesMap[AscDFH.historyitem_PivotSource_SetName                      ] = function(oClass, value){oClass.name  = value;};
    drawingsChangesMap[AscDFH.historyitem_Protection_SetChartObject                ] = function(oClass, value){oClass.chartObject      = value;};
    drawingsChangesMap[AscDFH.historyitem_Protection_SetData                       ] = function(oClass, value){oClass.data             = value;};
    drawingsChangesMap[AscDFH.historyitem_Protection_SetFormatting                 ] = function(oClass, value){oClass.formatting       = value;};
    drawingsChangesMap[AscDFH.historyitem_Protection_SetSelection                  ] = function(oClass, value){oClass.selection        = value;};
    drawingsChangesMap[AscDFH.historyitem_Protection_SetUserInterface              ] = function(oClass, value){oClass.userInterface    = value;};
    drawingsChangesMap[AscDFH.historyitem_PrintSettingsSetHeaderFooter             ] = function(oClass, value){oClass.headerFooter = value;};
    drawingsChangesMap[AscDFH.historyitem_PrintSettingsSetPageMargins              ] = function(oClass, value){oClass.pageMargins  = value;};
    drawingsChangesMap[AscDFH.historyitem_PrintSettingsSetPageSetup                ] = function(oClass, value){oClass.pageSetup    = value;};
    drawingsChangesMap[AscDFH.historyitem_HeaderFooterChartSetAlignWithMargins     ] = function(oClass, value){oClass.alignWithMargins = value;};
    drawingsChangesMap[AscDFH.historyitem_HeaderFooterChartSetDifferentFirst       ] = function(oClass, value){oClass.differentFirst   = value;};
    drawingsChangesMap[AscDFH.historyitem_HeaderFooterChartSetDifferentOddEven     ] = function(oClass, value){oClass.differentOddEven = value;};
    drawingsChangesMap[AscDFH.historyitem_HeaderFooterChartSetEvenFooter           ] = function(oClass, value){oClass.evenFooter       = value;};
    drawingsChangesMap[AscDFH.historyitem_HeaderFooterChartSetEvenHeader           ] = function(oClass, value){oClass.evenHeader       = value;};
    drawingsChangesMap[AscDFH.historyitem_HeaderFooterChartSetFirstFooter          ] = function(oClass, value){oClass.firstFooter      = value;};
    drawingsChangesMap[AscDFH.historyitem_HeaderFooterChartSetFirstHeader          ] = function(oClass, value){oClass.firstHeader      = value;};
    drawingsChangesMap[AscDFH.historyitem_HeaderFooterChartSetOddFooter            ] = function(oClass, value){oClass.oddFooter        = value;};
    drawingsChangesMap[AscDFH.historyitem_HeaderFooterChartSetOddHeader            ] = function(oClass, value){oClass.oddHeader        = value;};
    drawingsChangesMap[AscDFH.historyitem_PageMarginsSetB                          ] = function(oClass, value){oClass.b        = value;};
    drawingsChangesMap[AscDFH.historyitem_PageMarginsSetFooter                     ] = function(oClass, value){oClass.footer   = value;};
    drawingsChangesMap[AscDFH.historyitem_PageMarginsSetHeader                     ] = function(oClass, value){oClass.header   = value;};
    drawingsChangesMap[AscDFH.historyitem_PageMarginsSetL                          ] = function(oClass, value){oClass.l        = value;};
    drawingsChangesMap[AscDFH.historyitem_PageMarginsSetR                          ] = function(oClass, value){oClass.r        = value;};
    drawingsChangesMap[AscDFH.historyitem_PageMarginsSetT                          ] = function(oClass, value){oClass.t        = value;};
    drawingsChangesMap[AscDFH.historyitem_PageSetupSetBlackAndWhite                ] = function(oClass, value){oClass.blackAndWhite    = value;};
    drawingsChangesMap[AscDFH.historyitem_PageSetupSetCopies                       ] = function(oClass, value){oClass.copies           = value;};
    drawingsChangesMap[AscDFH.historyitem_PageSetupSetDraft                        ] = function(oClass, value){oClass.draft            = value;};
    drawingsChangesMap[AscDFH.historyitem_PageSetupSetFirstPageNumber              ] = function(oClass, value){oClass.firstPageNumber  = value;};
    drawingsChangesMap[AscDFH.historyitem_PageSetupSetHorizontalDpi                ] = function(oClass, value){oClass.horizontalDpi    = value;};
    drawingsChangesMap[AscDFH.historyitem_PageSetupSetOrientation                  ] = function(oClass, value){oClass.orientation      = value;};
    drawingsChangesMap[AscDFH.historyitem_PageSetupSetPaperHeight                  ] = function(oClass, value){oClass.paperHeight      = value;};
    drawingsChangesMap[AscDFH.historyitem_PageSetupSetPaperSize                    ] = function(oClass, value){oClass.paperSize        = value;};
    drawingsChangesMap[AscDFH.historyitem_PageSetupSetPaperWidth                   ] = function(oClass, value){oClass.paperWidth       = value;};
    drawingsChangesMap[AscDFH.historyitem_PageSetupSetUseFirstPageNumb             ] = function(oClass, value){oClass.useFirstPageNumb = value;};
    drawingsChangesMap[AscDFH.historyitem_PageSetupSetVerticalDpi                  ] = function(oClass, value){oClass.verticalDpi      = value;};


    function CLabelsBox(aStrings, oAxis, oChartSpace){
        this.x = 0.0;
        this.y = 0.0;
        this.extX = 0.0;
        this.extY = 0.0;
        this.aLabels = [];
        this.maxMinWidth = -1.0;

        this.chartSpace = oChartSpace;
        this.axis = oAxis;

        var oStyle = null, oLbl, fMinW;
        var oFirstTextPr = null;
        for(var i = 0; i < aStrings.length; ++i){
            if(typeof aStrings[i] === "string"){
                oLbl = fCreateLabel(aStrings[i], i, oAxis, oChartSpace, oAxis.txPr, oAxis.spPr, oChartSpace.getDrawingDocument());
                if(oStyle){
                    oLbl.lastStyleObject = oStyle;
                }
                if(oFirstTextPr){
                    var aRuns = oLbl.tx.rich.content.Content[0] && oLbl.tx.rich.content.Content[0].Content;
                    if(aRuns){
                        for(var j = 0; j < aRuns.length; ++j){
                            var oRun = aRuns[j];
                            if(oRun.RecalcInfo && true === oRun.RecalcInfo.TextPr){
                                oRun.RecalcInfo.TextPr = false;
                                oRun.CompiledPr = oFirstTextPr;
                            }
                        }
                    }
                }
                fMinW = oLbl.tx.rich.content.RecalculateMinMaxContentWidth().Min;
                if(!oFirstTextPr){
                    if(oLbl.tx.rich.content.Content[0]){
                        oFirstTextPr = oLbl.tx.rich.content.Content[0].Get_FirstTextPr2();
                    }
                }
                if(fMinW > this.maxMinWidth){
                    this.maxMinWidth = fMinW;
                }
                this.aLabels.push(oLbl);
                if(!oStyle){
                    oStyle = oLbl.lastStyleObject;
                }
            }
            else{
                this.aLabels.push(null);
            }
        }

    }
    CLabelsBox.prototype.draw = function(graphics){
        for(var i = 0; i < this.aLabels.length; ++i)
        {
            if(this.aLabels[i])
                this.aLabels[i].draw(graphics);
        }
        // graphics.p_width(70);
        // graphics.p_color(0, 0, 0, 255);
        // graphics._s();
        // graphics._m(this.x, this.y);
        // graphics._l(this.x + this.extX, this.y + 0);
        // graphics._l(this.x + this.extX, this.y + this.extY);
        // graphics._l(this.x + 0, this.y + this.extY);
        // graphics._z();
        // graphics.ds();
    };

    CLabelsBox.prototype.checkMaxMinWidth = function () {
        if(this.maxMinWidth < 0.0){
            var oStyle = null, oLbl, fMinW;
            for(var i = 0; i < this.aLabels.length; ++i){
                oLbl = this.aLabels[i];
                if(oLbl){
                    if(oStyle){
                        oLbl.lastStyleObject = oStyle;
                    }
                    fMinW = oLbl.tx.rich.content.RecalculateMinMaxContentWidth().Min;
                    if(fMinW > this.maxMinWidth){
                        this.maxMinWidth = fMinW;
                    }
                    if(!oStyle){
                        oStyle = oLbl.lastStyleObject;
                    }
                }
            }
        }
        return this.maxMinWidth >= 0.0 ? this.maxMinWidth : 0.0;
    };


    CLabelsBox.prototype.hit = function(x, y){
        var tx, ty;
        if(this.chartSpace && this.chartSpace.invertTransform)
        {
            tx = this.chartSpace.invertTransform.TransformPointX(x, y);
            ty = this.chartSpace.invertTransform.TransformPointY(x, y);
            return tx >= this.x && ty >= this.y && tx <= this.x + this.extX && ty <= this.y + this.extY;
        }
        return false;
    };

    CLabelsBox.prototype.updatePosition = function(x, y)
    {
        // this.posX = x;
        // this.posY = y;
        // this.transform = this.localTransform.CreateDublicate();
        // global_MatrixTransformer.TranslateAppend(this.transform, x, y);
        // this.invertTransform = global_MatrixTransformer.Invert(this.transform);
        for(var i = 0; i < this.aLabels.length; ++i)
        {
            if(this.aLabels[i])
                this.aLabels[i].updatePosition(x, y);
        }
    };

    CLabelsBox.prototype.layoutHorNormal = function(fAxisY, fDistance, fXStart, fInterval, bOnTickMark, fForceContentWidth){
        var fMaxHeight = 0.0;
        var fCurX = bOnTickMark ? fXStart - fInterval/2.0 : fXStart;
        if(fInterval < 0.0){
            fCurX += fInterval;
        }
        var oFirstLabel = null, fFirstLabelCenterX = null, oLastLabel = null, fLastLabelCenterX = null;
        var fContentWidth = fForceContentWidth ? fForceContentWidth : Math.abs(fInterval);
        var fHorShift = Math.abs(fInterval)/2.0 - fContentWidth/2.0;
        for(var i = 0; i < this.aLabels.length; ++i){
            if(this.aLabels[i]){
                var oLabel = this.aLabels[i];
                var oContent = oLabel.tx.rich.content;
                oContent.Reset(0, 0, fContentWidth, 20000.0);
                oContent.Recalculate_Page(0, true);
                var fCurHeight = oContent.GetSummaryHeight();
                if(fCurHeight > fMaxHeight){
                    fMaxHeight = fCurHeight;
                }
                var fX, fY;
                fX = fCurX + fHorShift;
                if(fDistance >= 0.0){
                    fY = fAxisY + fDistance;
                }
                else{
                    fY = fAxisY + fDistance - fCurHeight;
                }
                var oTransform = oLabel.transformText;
                oTransform.Reset();
                global_MatrixTransformer.TranslateAppend(oTransform, fX, fY);
                oTransform = oLabel.localTransformText;
                oTransform.Reset();
                global_MatrixTransformer.TranslateAppend(oTransform, fX, fY);


                if(oFirstLabel === null){
                    oFirstLabel = oLabel;
                    fFirstLabelCenterX = fCurX + Math.abs(fInterval)/2.0;
                }
                oLastLabel = oLabel;
                fLastLabelCenterX = fCurX + Math.abs(fInterval)/2.0;
            }
            fCurX += fInterval;
        }

        var x0, x1;
        if(bOnTickMark && oFirstLabel && oLastLabel){
            var fFirstLabelContentWidth = oFirstLabel.tx.rich.getMaxContentWidth(fContentWidth);
            var fLastLabelContentWidth = oLastLabel.tx.rich.getMaxContentWidth(fContentWidth);
            x0 = Math.min(fFirstLabelCenterX - fFirstLabelContentWidth/2.0,
                fLastLabelCenterX - fLastLabelContentWidth/2.0, fXStart, fXStart + fInterval*(this.aLabels.length - 1));
            x1 = Math.max(fFirstLabelCenterX + fFirstLabelContentWidth/2.0,
                fLastLabelCenterX + fLastLabelContentWidth/2.0, fXStart, fXStart + fInterval*(this.aLabels.length - 1));
        }
        else{
            x0 = Math.min(fXStart, fXStart + fInterval*(this.aLabels.length));
            x1 = Math.max(fXStart, fXStart + fInterval*(this.aLabels.length));
        }
        this.x = x0;
        this.extX = x1 - x0;

        if(fDistance >= 0.0){
            this.y = fAxisY;
            this.extY = fDistance + fMaxHeight;
        }
        else{
            this.y = fAxisY + fDistance - fMaxHeight;
            this.extY = fMaxHeight - fDistance;
        }
    };

    CLabelsBox.prototype.layoutHorRotated = function(fAxisY, fDistance, fXStart, fInterval, bOnTickMark){


        var bTickLblSkip = AscFormat.isRealNumber(this.axis.tickLblSkip) ? true : false;
        if(bTickLblSkip){
            this.layoutHorRotated2(this.aLabels, fAxisY, fDistance, fXStart, fInterval, bOnTickMark);
        }
        else{

            var fAngle = Math.PI/4.0, fMultiplier = Math.sin(fAngle);
            var aLabelsSource = [].concat(this.aLabels);
            var oLabel = aLabelsSource[0];
            var i = 1;
            while(!oLabel && i < aLabelsSource.length){
                oLabel = aLabelsSource[i];
            }
            if(oLabel){
                var oContent = oLabel.tx.rich.content;
                oContent.Set_ApplyToAll(true);
                oContent.SetParagraphAlign(AscCommon.align_Left);
                oContent.SetParagraphIndent({FirstLine: 0.0, Left: 0.0});
                oContent.Set_ApplyToAll(false);
                var oSize = oLabel.tx.rich.getContentOneStringSizes();
                var fInset = fMultiplier*(oSize.h);
                fInset *= 2;
                if(fInset <= fInterval){
                    this.layoutHorRotated2(this.aLabels, fAxisY, fDistance, fXStart, fInterval, bOnTickMark);
                }
                else{
                    var nLblTickSkip = (fInset/fInterval + 0.5) >> 0;
                    var aLabels = [].concat(aLabelsSource);
                    for(i = 0; i < aLabels.length; ++i){
                        if((i % nLblTickSkip) !== 0){
                            aLabels[i] = null;
                        }
                    }
                    this.layoutHorRotated2(aLabels, fAxisY, fDistance, fXStart, fInterval, bOnTickMark);
                }
            }
        }

    };

    CLabelsBox.prototype.layoutHorRotated2 = function (aLabels, fAxisY, fDistance, fXStart, fInterval, bOnTickMark) {
        var i;
        var fMaxHeight = 0.0;
        var fCurX = bOnTickMark ? fXStart : fXStart + fInterval/2.0;
        var fAngle = Math.PI/4.0, fMultiplier = Math.sin(fAngle);
        var fMinLeft = null, fMaxRight = null;
        for(i = 0; i < aLabels.length; ++i){
            if(aLabels[i]){
                var oLabel = aLabels[i];
                var oContent = oLabel.tx.rich.content;
                oContent.Set_ApplyToAll(true);
                oContent.SetParagraphAlign(AscCommon.align_Left);
                oContent.SetParagraphIndent({FirstLine: 0.0, Left: 0.0});
                oContent.Set_ApplyToAll(false);
                var oSize = oLabel.tx.rich.getContentOneStringSizes();
                var fBoxW = fMultiplier*(oSize.w + oSize.h);
                var fBoxH = fBoxW;
                if(fBoxH > fMaxHeight){
                    fMaxHeight = fBoxH;
                }
                var fX1, fY0, fXC, fYC;
                fY0 = fAxisY + fDistance;
                if(fDistance >= 0.0){
                    fXC = fCurX - oSize.w*fMultiplier/2.0;
                    fYC = fY0 + fBoxH/2.0;
                }
                else{
                    //fX1 = fCurX - oSize.h*fMultiplier;
                    fXC = fCurX + oSize.w*fMultiplier/2.0;
                    fYC = fY0 - fBoxH/2.0;
                }
                var oTransform = oLabel.localTransformText;
                oTransform.Reset();
                global_MatrixTransformer.TranslateAppend(oTransform, -oSize.w/2.0, -oSize.h/2.0);
                global_MatrixTransformer.RotateRadAppend(oTransform, fAngle);
                global_MatrixTransformer.TranslateAppend(oTransform, fXC, fYC);
                oLabel.transformText = oTransform.CreateDublicate();
                if(null === fMinLeft || (fXC - fBoxW/2.0) < fMinLeft){
                    fMinLeft = fXC - fBoxW/2.0;
                }
                if(null === fMaxRight || (fXC + fBoxW/2.0) > fMaxRight){
                    fMaxRight = fXC + fBoxW/2.0;
                }
            }
            fCurX += fInterval;
        }
        this.aLabels = aLabels;
        var aPoints = [];
        aPoints.push(fXStart);
        var nIntervalCount = bOnTickMark ? aLabels.length - 1 : aLabels.length;
        aPoints.push(fXStart + fInterval*nIntervalCount);
        if(null !== fMinLeft){
            aPoints.push(fMinLeft);
        }
        if(null !== fMaxRight){
            aPoints.push(fMaxRight);
        }
        this.x = Math.min.apply(Math, aPoints);
        this.extX = Math.max.apply(Math, aPoints) - this.x;
        if(fDistance >= 0.0){
            this.y = fAxisY;
            this.extY = fDistance + fMaxHeight;
        }
        else{
            this.y = fAxisY + fDistance - fMaxHeight;
            this.extY = fMaxHeight - fDistance;
        }
    };

    CLabelsBox.prototype.layoutVertNormal = function(fAxisX, fDistance, fYStart, fInterval, bOnTickMark, fMaxBlockWidth){
        var fCurY = bOnTickMark ? fYStart : fYStart + fInterval/2.0;

        var fDistance_ = Math.abs(fDistance);
        var oTransform, oContent, oLabel, fMinY = fYStart, fMaxY = fYStart + fInterval*(this.aLabels.length - 1), fY;
        var fMaxContentWidth = 0.0;
        for(var i = 0; i < this.aLabels.length; ++i){
            if(this.aLabels[i]){
                oLabel = this.aLabels[i];
                oContent = oLabel.tx.rich.content;
                oContent.Set_ApplyToAll(true);
                oContent.SetParagraphAlign(AscCommon.align_Left);
                oContent.Set_ApplyToAll(false);
                var oSize = oLabel.tx.rich.getContentOneStringSizes();
                if(oSize.w + fDistance_ > fMaxBlockWidth){
                    break;
                }

                if(oSize.w > fMaxContentWidth){
                    fMaxContentWidth = oSize.w;
                }
                oTransform = oLabel.localTransformText;
                oTransform.Reset();
                fY = fCurY - oSize.h/2.0;
                if(fDistance > 0.0){
                    global_MatrixTransformer.TranslateAppend(oTransform, fAxisX + fDistance, fY);
                }
                else{
                    global_MatrixTransformer.TranslateAppend(oTransform, fAxisX + fDistance - oSize.w, fY);
                }
                oLabel.transformText = oTransform.CreateDublicate();
                if(fY < fMinY){
                    fMinY = fY;
                }
                if(fY + oSize.h > fMaxY){
                    fMaxY = fY + oSize.h;
                }
            }
            fCurY += fInterval;
        }

        if(i < this.aLabels.length){
            var fMaxMinWidth = this.checkMaxMinWidth();
            fMaxContentWidth = 0.0;
            for(i = 0; i < this.aLabels.length; ++i){
                oLabel = this.aLabels[i];
                if(oLabel){
                    oContent = oLabel.tx.rich.content;
                    oContent.Set_ApplyToAll(true);
                    oContent.SetParagraphAlign(AscCommon.align_Center);
                    oContent.Set_ApplyToAll(false);
                    var fContentWidth;
                    if(fMaxMinWidth + fDistance_ < fMaxBlockWidth) {
                        fContentWidth = oContent.RecalculateMinMaxContentWidth().Min + 0.1;
                    }
                    else{
                        fContentWidth = fMaxBlockWidth - fDistance_;
                    }
                    if(fContentWidth > fMaxContentWidth){
                        fMaxContentWidth = fContentWidth;
                    }
                    oContent.Reset(0, 0, fContentWidth, 20000);//выставляем большую ширину чтобы текст расчитался в одну строку.
                    oContent.Recalculate_Page(0, true);
                    var fContentHeight = oContent.GetSummaryHeight();
                    oTransform = oLabel.localTransformText;
                    oTransform.Reset();
                    fY = fCurY - fContentHeight/2.0;
                    if(fDistance > 0.0){
                        global_MatrixTransformer.TranslateAppend(oTransform, fAxisX + fDistance, fY);
                    }
                    else{
                        fY = fCurY - fContentHeight/2.0;
                        global_MatrixTransformer.TranslateAppend(oTransform, fAxisX + fDistance - fContentWidth, fY);
                    }
                    oLabel.transformText = oTransform.CreateDublicate();
                    if(fY < fMinY){
                        fMinY = fY;
                    }
                    if(fY + fContentHeight > fMaxY){
                        fMaxY = fY + fContentHeight;
                    }
                }
                fCurY += fInterval;
            }
        }

        if(fDistance > 0.0){
            this.x = fAxisX;
        }
        else{
            this.x = fAxisX + fDistance - fMaxContentWidth;
        }
        this.extX = fMaxContentWidth + fDistance_;
        
        this.y = fMinY;
        this.extY = fMaxY - fMinY;
    };



    CLabelsBox.prototype.setPosition = function(x, y)
    {
        this.x = x;
        this.y = y;
        for(var i = 0; i < this.aLabels.length; ++i)
        {
            if(this.aLabels[i])
            {
                var lbl = this.aLabels[i];
                lbl.setPosition(lbl.relPosX + x, lbl.relPosY + y);
            }
        }
    };


    CLabelsBox.prototype.checkShapeChildTransform = function(t)
    {
        // this.transform = this.localTransform.CreateDublicate();
        // global_MatrixTransformer.TranslateAppend(this.transform, this.posX, this.posY);
        // this.invertTransform = global_MatrixTransformer.Invert(this.transform);
        for(var i = 0; i < this.aLabels.length; ++i)
        {
            if(this.aLabels[i])
                this.aLabels[i].checkShapeChildTransform(t);
        }
    };



    function fCreateLabel(sText, idx, oParent, oChart, oTxPr, oSpPr, oDrawingDocument){
        var dlbl = new AscFormat.CDLbl();
        dlbl.parent = oParent;
        dlbl.chart = oChart;
        dlbl.spPr = oSpPr;
        dlbl.txPr = oTxPr;
        dlbl.idx = idx;
        dlbl.tx = new AscFormat.CChartText();
        dlbl.tx.rich = AscFormat.CreateTextBodyFromString(sText, oDrawingDocument, dlbl);
        var content = dlbl.tx.rich.content;
        content.Set_ApplyToAll(true);
        content.SetParagraphAlign(AscCommon.align_Center);
        content.Set_ApplyToAll(false);
        dlbl.txBody = dlbl.tx.rich;
        dlbl.oneStringWidth = -1.0;
        return dlbl;
    }

    function fLayoutHorLabelsBox(oLabelsBox, fY, fXStart, fXEnd, bOnTickMark, fDistance, bForceVertical, bNumbers, fForceContentWidth){
        var fAxisLength = fXEnd - fXStart;
        var nLabelsCount = oLabelsBox.aLabels.length;

        var bOnTickMark_ = bOnTickMark && nLabelsCount > 1;
        var nIntervalCount = bOnTickMark_ ? nLabelsCount - 1 : nLabelsCount;
        var fInterval = fAxisLength/nIntervalCount;
        if(!bForceVertical || true){//TODO: implement for vertical labels
            var fMaxMinWidth = oLabelsBox.checkMaxMinWidth();
            var fCheckInterval = AscFormat.isRealNumber(fForceContentWidth) ? fForceContentWidth : Math.abs(fInterval);
            if(fMaxMinWidth <= fCheckInterval){
                oLabelsBox.layoutHorNormal(fY, fDistance, fXStart, fInterval, bOnTickMark_, fForceContentWidth);
            }
            else{
                oLabelsBox.layoutHorRotated(fY, fDistance, fXStart, fInterval, bOnTickMark_);
            }
        }
    }
    function fLayoutVertLabelsBox(oLabelsBox, fX, fYStart, fYEnd, bOnTickMark, fDistance, bForceVertical){
        var fAxisLength = fYEnd - fYStart;
        var nLabelsCount = oLabelsBox.aLabels.length;

        var bOnTickMark_ = bOnTickMark && nLabelsCount > 1;
        var nIntervalCount = bOnTickMark_ ? nLabelsCount - 1 : nLabelsCount;
        var fInterval = fAxisLength/nIntervalCount;

        if(!bForceVertical || true){
            oLabelsBox.layoutVertNormal(fX, fDistance, fYStart, fInterval, bOnTickMark_);
        }
        else{
            //TODO: vertical text
        }
    }

    function CAxisGrid(){
        this.nType = 0;//0 - horizontal, 1 - vertical, 2 - series axis
        this.fStart = 0.0;
        this.fStride = 0.0;
        this.bOnTickMark = true;
        this.nCount = 0;
        this.minVal = 0.0;
        this.maxVal = 0.0;
        this.aStrings = [];
    }
function CChartSpace()
{
	AscFormat.CGraphicObjectBase.call(this);

    this.nvGraphicFramePr = null;
    this.chart = null;
    this.clrMapOvr = null;
    this.date1904 = null;
    this.externalData = null;
    this.lang = null;
    this.pivotSource = null;
    this.printSettings = null;
    this.protection = null;
    this.roundedCorners = null;
    this.spPr = null;
    this.style = 2;
    this.txPr = null;
    this.userShapes = null;
    this.themeOverride = null;

    this.pathMemory = new CPathMemory();


    this.bbox = null;
    this.ptsCount = 0;

    this.selection =
    {
        title:         null,
        legend:        null,
        legendEntry:   null,
        axisLbls:      null,
        dataLbls:      null,
        dataLbl:       null,
        plotArea:      null,
        rotatePlotArea: null,
        gridLines:     null,
        series:        null,
        datPoint:      null,
        textSelection: null
    };

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

	CChartSpace.prototype = Object.create(AscFormat.CGraphicObjectBase.prototype);
	CChartSpace.prototype.constructor = CChartSpace;

    CChartSpace.prototype.AllocPath = function(){
        return this.pathMemory.AllocPath().startPos;
    };

    CChartSpace.prototype.GetPath = function(index){
        return this.pathMemory.GetPath(index);
    };

    CChartSpace.prototype.select = CShape.prototype.select;
CChartSpace.prototype.checkDrawingBaseCoords = CShape.prototype.checkDrawingBaseCoords;
CChartSpace.prototype.setDrawingBaseCoords = CShape.prototype.setDrawingBaseCoords;
CChartSpace.prototype.deleteBFromSerialize = CShape.prototype.deleteBFromSerialize;
CChartSpace.prototype.setBFromSerialize = CShape.prototype.setBFromSerialize;
CChartSpace.prototype.checkTypeCorrect = function(){
    if(!this.chart){
        return false;
    }
    if(!this.chart.plotArea){
        return false
    }
    if(this.chart.plotArea.charts.length === 0){
        return false;
    }
    var allSeries = this.getAllSeries();
    if(allSeries.length === 0){
        return false;
    }
    return true;
};
CChartSpace.prototype.drawSelect = function(drawingDocument, nPageIndex)
    {
        var i;
        if(this.selectStartPage === nPageIndex)
        {
            drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.SHAPE, this.getTransformMatrix(), 0, 0, this.extX, this.extY, false, this.canRotate());
			if(window["NATIVE_EDITOR_ENJINE"]){
				return;
			}
            if(this.selection.textSelection)
            {
                drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.CHART_TEXT, this.selection.textSelection.transform, 0, 0, this.selection.textSelection.extX, this.selection.textSelection.extY, false, false, false);
            }
            else if(this.selection.title)
            {
                drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.CHART_TEXT, this.selection.title.transform, 0, 0, this.selection.title.extX, this.selection.title.extY, false, false, false);
            }
            else if(AscFormat.isRealNumber(this.selection.dataLbls))
            {
                var series = this.getAllSeries();
                var ser = series[this.selection.dataLbls];
                if(ser)
                {
                    var pts = AscFormat.getPtsFromSeries(ser);
                    if(!AscFormat.isRealNumber(this.selection.dataLbl))
                    {
                        for(i = 0; i < pts.length; ++i)
                        {
                            if(pts[i] && pts[i].compiledDlb && !pts[i].compiledDlb.bDelete)
                            {
                                drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.CHART_TEXT, pts[i].compiledDlb.transform, 0, 0, pts[i].compiledDlb.extX, pts[i].compiledDlb.extY, false, false);
                            }
                        }
                    }
                    else
                    {
                        if(pts[this.selection.dataLbl] && pts[this.selection.dataLbl].compiledDlb)
                        {
                            drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.CHART_TEXT, pts[this.selection.dataLbl].compiledDlb.transform, 0, 0, pts[this.selection.dataLbl].compiledDlb.extX, pts[this.selection.dataLbl].compiledDlb.extY, false, false);
                        }
                    }
                }

            }
            else if(this.selection.dataLbl)
            {
                drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.CHART_TEXT, this.selection.dataLbl.transform, 0, 0, this.selection.dataLbl.extX, this.selection.dataLbl.extY, false, false);
            }
            else if(this.selection.legend)
            {
                if(AscFormat.isRealNumber(this.selection.legendEntry))
                {
                    var oEntry = this.chart.legend.findCalcEntryByIdx(this.selection.legendEntry);
                    if(oEntry){
                        drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.CHART_TEXT, oEntry.transformText, 0, 0, oEntry.contentWidth, oEntry.contentHeight, false, false);
                    }
                }
                else
                {
                    drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.CHART_TEXT, this.selection.legend.transform, 0, 0, this.selection.legend.extX, this.selection.legend.extY, false, false);
                }
            }
            else if(this.selection.axisLbls)
            {
                var oLabels = this.selection.axisLbls.labels;
                drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.CHART_TEXT, this.transform, oLabels.x, oLabels.y, oLabels.extX, oLabels.extY, false, false);
            }
            else if(this.selection.plotArea)
            {

                var oChartSize = this.getChartSizes(true);
                drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.CHART_TEXT, this.transform, oChartSize.startX, oChartSize.startY, oChartSize.w, oChartSize.h, false, false);
                /*if(!this.selection.rotatePlotArea)
                {
                    drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.CHART_TEXT, this.transform, oChartSize.startX, oChartSize.startY, oChartSize.w, oChartSize.h, false, false);
                }
                else
                {
                    var arr = [
                        {x: oChartSize.startX, y: oChartSize.startY},
                        {x: oChartSize.startX + oChartSize.w/2, y: oChartSize.startY},
                        {x: oChartSize.startX + oChartSize.w, y: oChartSize.startY},
                        {x: oChartSize.startX + oChartSize.w, y: oChartSize.startY + oChartSize.h/2},
                        {x: oChartSize.startX + oChartSize.w, y: oChartSize.startY + oChartSize.h},
                        {x: oChartSize.startX + oChartSize.w/2, y: oChartSize.startY + oChartSize.h},
                        {x: oChartSize.startX, y: oChartSize.startY + oChartSize.h},
                        {x: oChartSize.startX, y: oChartSize.startY + oChartSize.h/2},
                        {x: oChartSize.startX, y: oChartSize.startY}
                    ];
                    drawingDocument.AutoShapesTrack.DrawEditWrapPointsPolygon(arr, this.transform);
                }*/
            }
        }
    };
CChartSpace.prototype.recalculateTextPr = function()
{
    if(this.txPr && this.txPr.content)
    {
        this.txPr.content.Reset(0, 0, 10, 10);
        this.txPr.content.Recalculate_Page(0, true);
    }
};
CChartSpace.prototype.getSelectionState = function()
{
    var content_selection = null, content = null;
    if(this.selection.textSelection)
    {
        content = this.selection.textSelection.getDocContent();
        if(content)
            content_selection = content.GetSelectionState();
    }
    return {
        content: content,
        title:            this.selection.title,
        legend:           this.selection.legend,
        legendEntry:      this.selection.legendEntry,
        axisLbls:         this.selection.axisLbls,
        dataLbls:         this.selection.dataLbls,
        dataLbl:          this.selection.dataLbl,
        textSelection:    this.selection.textSelection,
        plotArea:         this.selection.plotArea,
        rotatePlotArea:         this.selection.rotatePlotArea,
        contentSelection: content_selection,
        recalcTitle: this.recalcInfo.recalcTitle,
        bRecalculatedTitle: this.recalcInfo.bRecalculatedTitle
    }
};
CChartSpace.prototype.setSelectionState = function(state)
{
   this.selection.title          = state.title;
   this.selection.legend         = state.legend;
   this.selection.legendEntry    = state.legendEntry;
   this.selection.axisLbls       = state.axisLbls;
   this.selection.dataLbls       = state.dataLbls;
   this.selection.dataLbl        = state.dataLbl;
   this.selection.rotatePlotArea        = state.rotatePlotArea;
   this.selection.textSelection  = state.textSelection;
   this.selection.plotArea       = state.plotArea;
   if(isRealObject(state.recalcTitle))
   {
       this.recalcInfo.recalcTitle = state.recalcTitle;
       this.recalcInfo.bRecalculatedTitle = state.bRecalculatedTitle;
   }
    if(state.contentSelection)
   {
       if(this.selection.textSelection)
       {
           var content = this.selection.textSelection.getDocContent();
           if(content)
               content.SetSelectionState(state.contentSelection, state.contentSelection.length - 1);
       }
   }
};
CChartSpace.prototype.loadDocumentStateAfterLoadChanges = function(state)
{
     this.selection.title =    null;
     this.selection.legend =        null;
     this.selection.legendEntry =   null;
     this.selection.axisLbls =      null;
     this.selection.dataLbls =      null;
     this.selection.dataLbl =       null;
     this.selection.plotArea =      null;
     this.selection.rotatePlotArea =  null;
     this.selection.gridLine =     null;
     this.selection.series =        null;
     this.selection.datPoint =      null;
     this.selection.textSelection = null;
    var bRet = false;
    if(state.DrawingsSelectionState){
        var chartSelection = state.DrawingsSelectionState.chartSelection;
        if(chartSelection){
            if(this.chart){
                if(chartSelection.title){
                    if(this.chart.title === chartSelection.title){
                        this.selection.title = this.chart.title;
                        bRet = true;
                    }
                    else{
                        var plot_area = this.chart.plotArea;
                        if(plot_area){
                            for(var i = 0; i < plot_area.axId.length; ++i){
                                var axis = plot_area.axId[i];
                                if(axis && axis.title === chartSelection.title){
                                    this.selection.title = axis.title;
                                    bRet = true;
                                    break;
                                }
                            }
                        }
                    }
                    if(this.selection.title){
                        if(this.selection.title === chartSelection.textSelection){
                            var oTitleContent = this.selection.title.getDocContent();
                            if(oTitleContent && oTitleContent === chartSelection.content){
                                this.selection.textSelection = this.selection.title;
                                if (true === state.DrawingSelection)
                                {
                                    oTitleContent.SetContentPosition(state.StartPos, 0, 0);
                                    oTitleContent.SetContentSelection(state.StartPos, state.EndPos, 0, 0, 0);
                                }
                                else
                                {
                                    oTitleContent.SetContentPosition(state.Pos, 0, 0);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return bRet;
};
CChartSpace.prototype.resetInternalSelection = function(noResetContentSelect)
{
    if(this.selection.title)
    {
        this.selection.title.selected = false;
    }
    if(this.selection.textSelection)
    {
        if(!(noResetContentSelect === true))
        {
            var content = this.selection.textSelection.getDocContent();
            content && content.RemoveSelection();
        }
        this.selection.textSelection = null;
    }
};
CChartSpace.prototype.getDocContent = function()
{
    return null;
};
CChartSpace.prototype.resetSelection = function(noResetContentSelect)
{
    this.resetInternalSelection(noResetContentSelect);
    this.selection.title = null;
    this.selection.legend = null;
    this.selection.legendEntry = null;
    this.selection.axisLbls = null;
    this.selection.dataLbls = null;
    this.selection.dataLbl = null;
    this.selection.textSelection = null;
    this.selection.plotArea = null;
    this.selection.rotatePlotArea = null;
};
CChartSpace.prototype.getStyles = function()
{
    return AscFormat.ExecuteNoHistory(function(){

        var styles = new CStyles(false);
        var style = new CStyle("dataLblStyle", null, null, null, true);
        var text_pr = new CTextPr();
        text_pr.FontSize = 10;
        text_pr.Unifill = CreateUnfilFromRGB(0,0,0);
        var parent_objects = this.getParentObjects();
        var theme = parent_objects.theme;

        var para_pr = new CParaPr();
        para_pr.Jc = AscCommon.align_Center;
        para_pr.Spacing.Before = 0.0;
        para_pr.Spacing.After = 0.0;
        para_pr.Spacing.Line = 1;
        para_pr.Spacing.LineRule = Asc.linerule_Auto;
        style.ParaPr = para_pr;

        var minor_font = theme.themeElements.fontScheme.minorFont;


        if(minor_font)
        {
            if(typeof minor_font.latin === "string" && minor_font.latin.length > 0)
            {
                text_pr.RFonts.Ascii = {Name: minor_font.latin, Index: -1};
            }
            if(typeof minor_font.ea === "string" && minor_font.ea.length > 0)
            {
                text_pr.RFonts.EastAsia = {Name: minor_font.ea, Index: -1};
            }
            if(typeof minor_font.cs === "string" && minor_font.cs.length > 0)
            {
                text_pr.RFonts.CS = {Name: minor_font.cs, Index: -1};
            }

            if(typeof minor_font.sym === "string" && minor_font.sym.length > 0)
            {
                text_pr.RFonts.HAnsi = {Name: minor_font.sym, Index: -1};
            }
        }
        style.TextPr = text_pr;

        var chart_text_pr;

        if(this.txPr
            && this.txPr.content
            && this.txPr.content.Content[0]
            && this.txPr.content.Content[0].Pr)
        {
            style.ParaPr.Merge(this.txPr.content.Content[0].Pr);
            if(this.txPr.content.Content[0].Pr.DefaultRunPr)
            {
                chart_text_pr = this.txPr.content.Content[0].Pr.DefaultRunPr;
                style.TextPr.Merge(chart_text_pr);
            }

        }

        if(this.txPr
            && this.txPr.content
            && this.txPr.content.Content[0]
            && this.txPr.content.Content[0].Pr)
        {
            style.ParaPr.Merge(this.txPr.content.Content[0].Pr);
            if(this.txPr.content.Content[0].Pr.DefaultRunPr)
                style.TextPr.Merge(this.txPr.content.Content[0].Pr.DefaultRunPr);
        }
        styles.Add(style);
        return {lastId: style.Id, styles: styles};
    }, this, []);
};

CChartSpace.prototype.getParagraphTextPr = function()
{
    if(this.selection.title && !this.selection.textSelection)
    {
        return  GetTextPrFormArrObjects([this.selection.title]);
    }
    else if(this.selection.legend)
    {
        if(!AscFormat.isRealNumber(this.selection.legendEntry))
        {
            if(AscFormat.isRealNumber(this.legendLength))
            {
                var arrForProps = [];
                for(var i = 0; i < this.legendLength; ++i)
                {
                    arrForProps.push(this.chart.legend.getCalcEntryByIdx(i, this.getDrawingDocument()))
                }
                return GetTextPrFormArrObjects(arrForProps);
            }
            return GetTextPrFormArrObjects(this.chart.legend.calcEntryes);
        }
        else
        {
            var calcLegendEntry = this.chart.legend.getCalcEntryByIdx(this.selection.legendEntry, this.getDrawingDocument());
            if(calcLegendEntry)
            {
                return GetTextPrFormArrObjects([calcLegendEntry]);
            }
        }
    }
    else  if(this.selection.textSelection)
    {
        return this.selection.textSelection.txBody.content.GetCalculatedTextPr();
    }
    else if(this.selection.axisLbls && this.selection.axisLbls.labels)
    {
        return GetTextPrFormArrObjects(this.selection.axisLbls.labels.aLabels, true);
    }
    else if(AscFormat.isRealNumber(this.selection.dataLbls))
    {
        var ser = this.getAllSeries()[this.selection.dataLbls];
        if(ser)
        {
            var pts = AscFormat.getPtsFromSeries(ser);
            if(!AscFormat.isRealNumber(this.selection.dataLbl))
            {
                return GetTextPrFormArrObjects(pts, undefined , true);
            }
            else
            {
                var pt = pts[this.selection.dataLbl];
                if(pt)
                {
                    return GetTextPrFormArrObjects([pt], undefined , true);
                }
            }
        }
    }
    if(this.txPr && this.txPr.content && this.txPr.content.Content[0] && this.txPr.content.Content[0].Pr.DefaultRunPr)
    {
        this.txPr.content.Content[0].Pr.DefaultRunPr.Copy();
    }
    return new AscCommonWord.CTextPr();
};


CChartSpace.prototype.applyLabelsFunction = function(fCallback, value)
{
    if(this.selection.title)
    {
        var DefaultFontSize = 18;
        if(this.selection.title !== this.chart.title)
        {
            DefaultFontSize = 10;
        }
        fCallback(this.selection.title, value, this.getDrawingDocument(), DefaultFontSize);
    }
    else if(this.selection.legend)
    {
        if(!AscFormat.isRealNumber(this.selection.legendEntry))
        {
            fCallback(this.selection.legend, value, this.getDrawingDocument(), 10);
            for(var i = 0; i < this.selection.legend.legendEntryes.length; ++i)
            {
                fCallback(this.selection.legend.legendEntryes[i], value, this.getDrawingDocument(), 10);
            }
        }
        else
        {
            var entry = this.selection.legend.findLegendEntryByIndex(this.selection.legendEntry);
            if(!entry)
            {
                entry = new AscFormat.CLegendEntry();
                entry.setIdx(this.selection.legendEntry);
                if(this.selection.legend.txPr)
                {
                    entry.setTxPr(this.selection.legend.txPr.createDuplicate());
                }

                this.selection.legend.addLegendEntry(entry);
            }
            if(entry)
            {
                fCallback(entry, value, this.getDrawingDocument(), 10);
            }
        }
    }
    else if(this.selection.axisLbls)
    {
        fCallback(this.selection.axisLbls, value, this.getDrawingDocument(), 10);
    }
    else if(AscFormat.isRealNumber(this.selection.dataLbls))
    {
        var ser = this.getAllSeries()[this.selection.dataLbls];
        if(ser)
        {
            var pts = AscFormat.getPtsFromSeries(ser);
            if(!ser.dLbls)
            {
                var oDlbls;
                var oChart = ser.parent;
                if(oChart && oChart.dLbls)
                {
                    oDlbls = oChart.dLbls.createDuplicate();
                }
                else
                {
                    oDlbls = new AscFormat.CDLbls();
                }
                ser.setDLbls(oDlbls);
            }
            if(!AscFormat.isRealNumber(this.selection.dataLbl))
            {
                fCallback(ser.dLbls, value, this.getDrawingDocument(), 10);
                for(var i = 0; i < pts.length; ++i)
                {
                    var dLbl  = ser.dLbls.findDLblByIdx(pts[i].idx);
                    if(dLbl)
                    {
                        if(ser.dLbls.txPr && !dLbl.txPr)
                        {
                            dLbl.setTxPr(ser.dLbls.txPr.createDuplicate());
                        }
                        fCallback(dLbl, value, this.getDrawingDocument(), 10);
                    }
                }
            }
            else
            {
                var pt = pts[this.selection.dataLbl];
                if(pt)
                {
                    var dLbl  = ser.dLbls.findDLblByIdx(pt.idx);
                    if(!dLbl)
                    {
                        dLbl = new AscFormat.CDLbl();
                        dLbl.setIdx(pt.idx);
                        if(ser.dLbls.txPr)
                        {
                            dLbl.merge(ser.dLbls);
                        }
                        ser.dLbls.addDLbl(dLbl);

                    }
                    fCallback(dLbl, value, this.getDrawingDocument(), 10);
                }
            }
        }
    }
};

CChartSpace.prototype.paragraphIncDecFontSize = function(bIncrease)
{
    if(this.selection.textSelection)
    {
        this.selection.textSelection.checkDocContent();
        var content = this.selection.textSelection.getDocContent();
        if(content)
        {
            content.IncreaseDecreaseFontSize(bIncrease);
        }
        return;
    }
    this.applyLabelsFunction(CheckIncDecFontSize, bIncrease);
};

CChartSpace.prototype.paragraphAdd = function(paraItem, bRecalculate)
{
    if(paraItem.Type === para_TextPr)
    {
        var _paraItem;
        if(paraItem.Value.Unifill && paraItem.Value.Unifill.checkWordMods())
        {
            _paraItem = paraItem.Copy();
            _paraItem.Value.Unifill.convertToPPTXMods();
        }
        else
        {
            _paraItem = paraItem;
        }
        if(this.selection.textSelection)
        {
            this.selection.textSelection.checkDocContent();
            this.selection.textSelection.paragraphAdd(paraItem, bRecalculate);
            return;
        }
        /*if(this.selection.title)
        {
            this.selection.title.checkDocContent();
            CheckObjectTextPr(this.selection.title, _paraItem.Value, this.getDrawingDocument(), 18);
            if(this.selection.title.tx && this.selection.title.tx.rich && this.selection.title.tx.rich.content)
            {
                this.selection.title.tx.rich.content.Set_ApplyToAll(true);
                this.selection.title.tx.rich.content.AddToParagraph(_paraItem);
                this.selection.title.tx.rich.content.Set_ApplyToAll(false);
            }
            return;
        }*/
        this.applyLabelsFunction(CheckObjectTextPr, _paraItem.Value);
    }
    else if(paraItem.Type === para_Text || paraItem.Type === para_Space){
        if(this.selection.title){
            this.selection.textSelection = this.selection.title;
            this.selection.textSelection.checkDocContent();
            this.selection.textSelection.txBody.content.SelectAll();
            this.selection.textSelection.paragraphAdd(paraItem, bRecalculate);
        }
    }
};
CChartSpace.prototype.applyTextFunction = function(docContentFunction, tableFunction, args)
{
    if(docContentFunction === CDocumentContent.prototype.AddToParagraph && !this.selection.textSelection)
    {
        this.paragraphAdd(args[0], args[1]);
        return;
    }
    if(this.selection.textSelection)
    {
        this.selection.textSelection.checkDocContent();

        var bTrackRevision = false;
        if(typeof editor !== "undefined" && editor && editor.WordControl && editor.WordControl.m_oLogicDocument.TrackRevisions === true){
            bTrackRevision = true;
            editor.WordControl.m_oLogicDocument.TrackRevisions = false;
        }
        this.selection.textSelection.applyTextFunction(docContentFunction, tableFunction, args);
        if(bTrackRevision){
            editor.WordControl.m_oLogicDocument.TrackRevisions = true;
        }
    }
};
CChartSpace.prototype.selectTitle = function(title, pageIndex)
{
    title.select(this, pageIndex);
    this.resetInternalSelection();
    this.selection.legend = null;
    this.selection.legendEntry = null;
    this.selection.axisLbls = null;
    this.selection.dataLbls = null;
    this.selection.dataLbl = null;
    this.selection.textSelection = null;
    this.selection.plotArea = null;
    this.selection.rotatePlotArea = null;
};
CChartSpace.prototype.recalculateCurPos = AscFormat.DrawingObjectsController.prototype.recalculateCurPos;
CChartSpace.prototype.documentUpdateSelectionState = function()
{
    if(this.selection.textSelection)
    {
        this.selection.textSelection.updateSelectionState();
    }
};

CChartSpace.prototype.getLegend = function()
{
    if(this.chart)
    {
        return this.chart.legend;
    }
    return null;
};

CChartSpace.prototype.getAllTitles = function()
{
    var ret = [];
    if(this.chart)
    {
        if(this.chart.title)
        {
            ret.push(this.chart.title);
        }
        if(this.chart.plotArea)
        {
            var aAxes = this.chart.plotArea.axId;
            for(var i = 0; i < aAxes.length; ++i){
                if(aAxes[i] && aAxes[i].title){
                    ret.push(aAxes[i].title);
                }
            }
        }
    }
    return ret;
};
CChartSpace.prototype.getFill = CShape.prototype.getFill;
CChartSpace.prototype.changeSize = CShape.prototype.changeSize;
CChartSpace.prototype.changeFill = function (unifill)
{
    if(this.recalcInfo.recalculatePenBrush)
    {
        this.recalculatePenBrush();
    }
    var unifill2 = AscFormat.CorrectUniFill(unifill, this.brush, this.getEditorType());
    unifill2.convertToPPTXMods();
    if(!this.spPr){
        this.setSpPr(new AscFormat.CSpPr());
        this.spPr.setParent(this);
    }
    this.spPr.setFill(unifill2);
};
CChartSpace.prototype.setFill = function (fill) {
    if(!this.spPr){
        this.setSpPr(new AscFormat.CSpPr());
        this.spPr.setParent(this);
    }
    this.spPr.setFill(fill);
};

CChartSpace.prototype.setNvSpPr = function(pr) {
    History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartSpace_SetNvGrFrProps, this.nvGraphicFramePr, pr));
    this.nvGraphicFramePr = pr;
};

CChartSpace.prototype.changeLine = function (line)
{
    if(this.recalcInfo.recalculatePenBrush)
    {
        this.recalculatePenBrush();
    }
    var stroke = AscFormat.CorrectUniStroke(line, this.pen);
    if(stroke.Fill)
    {
        stroke.Fill.convertToPPTXMods();
    }
    if(!this.spPr){
        this.setSpPr(new AscFormat.CSpPr());
        this.spPr.setParent(this);
    }
    this.spPr.setLn(stroke);
};
CChartSpace.prototype.parseChartFormula = function(sFormula)
{
    if(this.worksheet && typeof sFormula === "string" && sFormula.length > 0){
        var res, ws = this.worksheet;
		AscCommonExcel.executeInR1C1Mode(false, function () {
			res = AscCommonExcel.getRangeByRef(sFormula, ws);
		});
        return res;
    }
    return [];
};
CChartSpace.prototype.checkBBoxIntersection = function(bbox1, bbox2)
{
    return !(bbox1.r1 > bbox2.r2 || bbox2.r1 > bbox1.r2 || bbox1.c1 > bbox2.c2 || bbox2.c1 > bbox1.c2)
};
CChartSpace.prototype.checkSeriesIntersection = function(val, bbox, worksheet)
{
    if(val && bbox && worksheet)
    {
        var parsed_formulas = val.parsedFormulas;
        for(var i = 0; i < parsed_formulas.length; ++i)
        {
            if(parsed_formulas[i].worksheet === worksheet && this.checkBBoxIntersection(parsed_formulas[i].bbox, bbox))
            {
                return true;
            }
        }
    }
    return false;
};
CChartSpace.prototype.checkVal = function(val)
{
    if(val)
    {
        if(val.numRef)
        {
            val.numRef.parsedFormulas = this.parseChartFormula(val.numRef.f);
        }
        if(val.strRef)
        {
            val.strRef.parsedFormulas = this.parseChartFormula(val.strRef.f);
        }
    }
};
CChartSpace.prototype.recalculateSeriesFormulas = function()
{
    this.checkSeriesRefs(this.checkVal);
};
CChartSpace.prototype.checkChartIntersection = function(bbox, worksheet)
{
    return this.checkSeriesRefs(this.checkSeriesIntersection, bbox, worksheet);
};
CChartSpace.prototype.changeListName = function(val, oldName, newName)
{
    if(val)
    {
        if(val.numRef && typeof val.numRef.f === "string")
        {
            if(val.numRef.f.indexOf(newName) > -1)
                return;
        }
        if(val.strRef && typeof val.strRef.f === "string")
        {
            if(val.strRef.f.indexOf(newName) > -1)
                return;
        }
        if(val.numRef && typeof val.numRef.f === "string" || val.strRef && typeof val.strRef.f === "string")
        {
            var checkString = oldName.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,  "\\$&");
            if(val.numRef && typeof val.numRef.f === "string")
            {
                val.numRef.setF(val.numRef.f.replace(new RegExp(checkString,'g'), newName));
            }
            if(val.strRef && typeof val.strRef.f === "string")
            {
                val.strRef.setF(val.strRef.f.replace(new RegExp(checkString,'g'), newName));
            }
        }
    }
};
CChartSpace.prototype.checkListName = function(val, oldName)
{
    if(val)
    {
        if(val.numRef && typeof val.numRef.f === "string")
        {
            if(val.numRef.f.indexOf(oldName) > -1)
                return true;
        }
        if(val.strRef && typeof val.strRef.f === "string")
        {
            if(val.strRef.f.indexOf(oldName) > -1)
                return true;
        }
    }
    return false;
};
CChartSpace.prototype.changeChartReferences = function(oldWorksheetName, newWorksheetName)
{
    this.checkSeriesRefs(this.changeListName, oldWorksheetName, newWorksheetName);
};
CChartSpace.prototype.checkChartReferences = function(oldWorksheetName)
{
    return this.checkSeriesRefs(this.checkListName, oldWorksheetName);
};
CChartSpace.prototype.updateChartReferences = function(oldWorksheetName, newWorksheetName, bNoRebuildCache)
{
    if(this.checkChartReferences(oldWorksheetName))
    {
        if(bNoRebuildCache === true)
        {
            this.bNoHandleRecalc = true;
        }
        this.changeChartReferences(oldWorksheetName, newWorksheetName);
        if(!(bNoRebuildCache === true))
        {
            this.rebuildSeries();
        }
        this.bNoHandleRecalc = false;
    }
};
CChartSpace.prototype.updateChartReferences2 = function(oldWorksheetName, newWorksheetName)
{
    if(this.checkChartReferences(oldWorksheetName))
    {
        this.changeChartReferences(oldWorksheetName, newWorksheetName);
    }
};
CChartSpace.prototype.checkSeriesRefs = function(callback, bbox, worksheet)
{
    if(this.chart && this.chart.plotArea)
    {
        var charts = this.chart.plotArea.charts, i, j, series, ser;
        for(i = 0; i < charts.length; ++i)
        {
            series = charts[i].series;
            if(charts[i].getObjectType() === AscDFH.historyitem_type_ScatterChart)
            {
                for(j = 0; j < series.length; ++j)
                {
                    ser = series[j];
                    if(callback(ser.xVal, bbox, worksheet))
                        return true;
                    if(callback(ser.yVal, bbox, worksheet))
                        return true;
                    if(callback(ser.tx, bbox, worksheet))
                        return true;
                }
            }
            else
            {
                for(j = 0; j < series.length; ++j)
                {
                    ser = series[j];
                    if(callback(ser.val, bbox, worksheet))
                        return true;
                    if(callback(ser.cat, bbox, worksheet))
                        return true;
                    if(callback(ser.tx, bbox, worksheet))
                        return true;
                }
            }

        }
    }
    return false;
};
CChartSpace.prototype.clearCacheVal = function(val)
{
    if(!val)
        return;
    if(val.numRef)
    {
        if(val.numRef.numCache)
        {
            removePtsFromLit(val.numRef.numCache);
        }
    }
    if(val.strRef)
    {
        if(val.strRef.strCache)
        {
            val.strRef.setStrCache(null);
        }
    }
};
CChartSpace.prototype.checkIntersectionChangedRange = function(data)
{
    if(!data)
        return true;
    var i, j;
    if(this.seriesBBoxes)
    {
        for(i = 0; i < this.seriesBBoxes.length; ++i)
        {
            for(j = 0; j < data.length; ++j)
            {
                if(this.seriesBBoxes[i].checkIntersection(data[j]))
                    return true;
            }
        }
    }
    if(this.seriesTitlesBBoxes)
    {
        for(i = 0; i < this.seriesTitlesBBoxes.length; ++i)
        {
            for(j = 0; j < data.length; ++j)
            {
                if(this.seriesTitlesBBoxes[i].checkIntersection(data[j]))
                    return true;
            }
        }
    }
    if(this.catTitlesBBoxes)
    {
        for(i = 0; i < this.catTitlesBBoxes.length; ++i)
        {
            for(j = 0; j < data.length; ++j)
            {
                if(this.catTitlesBBoxes[i].checkIntersection(data[j]))
                    return true;
            }
        }
    }
    return false;
};
CChartSpace.prototype.rebuildSeries = function(data)
{
    if( this.checkIntersectionChangedRange(data))
    {
        AscFormat.ExecuteNoHistory(function(){
            this.checkRemoveCache();
            this.recalculateReferences();
            this.recalcInfo.recalculateReferences = false;
            // this.recalculate();
        }, this, [])

    }
};
CChartSpace.prototype.checkRemoveCache = function()
{
    this.handleUpdateInternalChart();
    this.recalcInfo.recalculateReferences = true;
    this.checkSeriesRefs(this.clearCacheVal);
};
CChartSpace.prototype.getTypeSubType = function()
{
    var type = null, subtype = null;
    if(this.chart && this.chart.plotArea && this.chart.plotArea.charts[0])
    {
        switch (this.chart.plotArea.charts[0].getObjectType())
        {
            case AscDFH.historyitem_type_LineChart:
            {
                type = c_oAscChartType.line;
                break;
            }
            case AscDFH.historyitem_type_AreaChart:
            {
                type = c_oAscChartType.area;
                break;
            }
            case AscDFH.historyitem_type_DoughnutChart:
            {
                type = c_oAscChartType.doughnut;
                break;
            }
            case AscDFH.historyitem_type_PieChart:
            {
                type = c_oAscChartType.pie;
                break;
            }
            case AscDFH.historyitem_type_ScatterChart:
            {
                type = c_oAscChartType.scatter;
                break;
            }
            case AscDFH.historyitem_type_StockChart:
            {
                type = c_oAscChartType.stock;
                break;
            }
            case AscDFH.historyitem_type_BarChart:
            {
                if(this.chart.plotArea.charts[0].barDir === AscFormat.BAR_DIR_BAR)
                    type = c_oAscChartType.hbar;
                else
                    type = c_oAscChartType.bar;
                break;
            }
        }

        if(AscFormat.isRealNumber(this.chart.plotArea.charts[0].grouping))
        {
            if(!this.chart.plotArea.charts[0].getObjectType() === AscDFH.historyitem_type_BarChart)
            {
                switch(this.chart.plotArea.charts[0].grouping)
                {
                    case AscFormat.GROUPING_STANDARD:
                    {
                        subtype = c_oAscChartSubType.normal;
                        break;
                    }
                    case AscFormat.GROUPING_STACKED:
                    {
                        subtype = c_oAscChartSubType.stacked;
                        break;
                    }
                    case AscFormat.GROUPING_PERCENT_STACKED:
                    {
                        subtype = c_oAscChartSubType.stackedPer;
                        break;
                    }
                }
            }
            else
            {
                switch(this.chart.plotArea.charts[0].grouping)
                {
                    case AscFormat.BAR_GROUPING_CLUSTERED:
                    case AscFormat.BAR_GROUPING_STANDARD:
                    {
                        subtype = c_oAscChartSubType.normal;
                        break;
                    }
                    case AscFormat.BAR_GROUPING_STACKED:
                    {
                        subtype = c_oAscChartSubType.stacked;
                        break;
                    }
                    case AscFormat.BAR_GROUPING_PERCENT_STACKED:
                    {
                        subtype = c_oAscChartSubType.stackedPer;
                        break;
                    }
                }
            }
        }

    }
    return {type: type, subtype: subtype};
};
CChartSpace.prototype.clearFormatting = function(bNoClearShapeProps)
{
    if(this.spPr && !(bNoClearShapeProps === true))
    {
        this.spPr.Fill && this.spPr.setFill(null);
        this.spPr.ln && this.spPr.setLn(null);
    }
    if(this.chart)
    {
        if(this.chart.plotArea)
        {
            if(this.chart.plotArea.spPr)
            {
                this.chart.plotArea.spPr.Fill && this.chart.plotArea.spPr.setFill(null);
                this.chart.plotArea.spPr.ln && this.chart.plotArea.spPr.setLn(null);
            }
            var i, j, k, series, pts, chart, ser;
            for(i = this.chart.plotArea.charts.length-1; i > -1; --i)
            {
                chart = this.chart.plotArea.charts[i];
                if(chart.upDownBars /*&& chart.getObjectType() !== AscDFH.historyitem_type_StockChart*/)
                {
                    if(chart.upDownBars.upBars)
                    {
                        if(chart.upDownBars.upBars.Fill)
                        {
                            chart.upDownBars.upBars.setFill(null);
                        }

                        if(chart.upDownBars.upBars.ln)
                        {
                            chart.upDownBars.upBars.setLn(null);
                        }
                    }

                    if(chart.upDownBars.downBars)
                    {
                        if(chart.upDownBars.downBars.Fill)
                        {
                            chart.upDownBars.downBars.setFill(null);
                        }

                        if(chart.upDownBars.downBars.ln)
                        {
                            chart.upDownBars.downBars.setLn(null);
                        }
                    }
                }
                series = chart.series;
                for(j = series.length - 1; j > -1; --j)
                {
                    ser = series[j];
                    if(ser.spPr && chart.getObjectType() !== AscDFH.historyitem_type_StockChart)
                    {
                        if(ser.spPr.Fill)
                        {
                            ser.spPr.setFill(null);
                        }
                        if(ser.spPr.ln)
                        {
                            ser.spPr.setLn(null);
                        }
                    }
                    AscFormat.removeDPtsFromSeries(ser)
                }
            }
        }
    }
};
    CChartSpace.prototype.remove = function()
    {
        if(this.selection.title)
        {
            if(this.selection.title.parent)
            {
                this.selection.title.parent.setTitle(null);
            }
        }
        else if(this.selection.legend)
        {
            if(!AscFormat.isRealNumber(this.selection.legendEntry))
            {
                if(this.selection.legend.parent && this.selection.legend.parent.setLegend)
                {
                    this.selection.legend.parent.setLegend(null);
                }
            }
            else
            {
                var entry = this.selection.legend.findLegendEntryByIndex(this.selection.legendEntry);
                if(!entry)
                {
                    entry = new AscFormat.CLegendEntry();
                    entry.setIdx(this.selection.legendEntry);
                    this.selection.legend.addLegendEntry(entry);
                }
                entry.setDelete(true);
            }
        }
        else if(this.selection.axisLbls)
        {
            if(this.selection.axisLbls && this.selection.axisLbls.setDelete)
            {
                this.selection.axisLbls.setDelete(true);
            }
        }
        else if(AscFormat.isRealNumber(this.selection.dataLbls))
        {
            var ser = this.getAllSeries()[this.selection.dataLbls];
            if(ser)
            {
                var oDlbls = ser.dLbls;
                if(!ser.dLbls)
                {

                    if(ser.parent && ser.parent.dLbls)
                    {
                        oDlbls = ser.parent.dLbls.createDuplicate();
                    }
                    else
                    {
                        oDlbls = new AscFormat.CDLbls();
                    }

                    ser.setDLbls(oDlbls);
                }
                if(!AscFormat.isRealNumber(this.selection.dataLbl))
                {
                    oDlbls.setDelete(true);
                }
                else
                {
                    var pts = AscFormat.getPtsFromSeries(ser);
                    var pt = pts[this.selection.dataLbl];
                    if(pt)
                    {
                        var dLbl  = ser.dLbls.findDLblByIdx(pt.idx);
                        if(!dLbl)
                        {
                            dLbl = new AscFormat.CDLbl();
                            dLbl.setIdx(pt.idx);
                            if(ser.dLbls.txPr)
                            {
                                dLbl.merge(ser.dLbls);
                            }
                            ser.dLbls.addDLbl(dLbl);

                        }
                        dLbl.setDelete(true);
                    }
                }
            }
        }

        this.selection.title =    null;
        this.selection.legend =        null;
        this.selection.legendEntry =   null;
        this.selection.axisLbls =      null;
        this.selection.dataLbls =      null;
        this.selection.dataLbl =       null;
        this.selection.plotArea =      null;
        this.selection.rotatePlotArea = null;
        this.selection.gridLine =     null;
        this.selection.series =        null;
        this.selection.datPoint =      null;
        this.selection.textSelection = null;
    };

CChartSpace.prototype.copy = function(drawingDocument)
{
    var copy = new CChartSpace();
    if(this.chart)
    {
        copy.setChart(this.chart.createDuplicate(drawingDocument));
    }
    if(this.clrMapOvr)
    {
        copy.setClrMapOvr(this.clrMapOvr.createDuplicate());
    }
    copy.setDate1904(this.date1904);
    if(this.externalData)
    {
        copy.setExternalData(this.externalData.createDuplicate());
    }
    copy.setLang(this.lang);
    if(this.pivotSource)
    {
        copy.setPivotSource(this.pivotSource.createDuplicate());
    }
    if(this.printSettings)
    {
        copy.setPrintSettings(this.printSettings.createDuplicate());
    }
    if(this.protection)
    {
        copy.setProtection(this.protection.createDuplicate());
    }
    copy.setRoundedCorners(this.roundedCorners);
    if(this.spPr)
    {
        copy.setSpPr(this.spPr.createDuplicate());
        copy.spPr.setParent(copy);
    }
    copy.setStyle(this.style);
    if(this.txPr)
    {
        copy.setTxPr(this.txPr.createDuplicate(drawingDocument))
    }
    copy.setUserShapes(this.userShapes);
    copy.setThemeOverride(this.themeOverride);
    copy.setBDeleted(this.bDeleted);
    copy.setLocks(this.locks);
    copy.cachedImage = this.getBase64Img();
    copy.cachedPixH = this.cachedPixH;
    copy.cachedPixW = this.cachedPixW;
    if(this.fromSerialize)
    {
        copy.setBFromSerialize(true);
    }
    return copy;
};
CChartSpace.prototype.convertToWord = function(document)
{
    this.setBDeleted(true);
    var oCopy = this.copy();
    oCopy.setBDeleted(false);
    return oCopy;
};
CChartSpace.prototype.convertToPPTX = function(drawingDocument, worksheet)
{
    var copy = this.copy(drawingDocument);
    copy.setBDeleted(false);
    copy.setWorksheet(worksheet);
    copy.setParent(null);
    return copy;
};
CChartSpace.prototype.rebuildSeriesFromAsc = function(asc_chart)
{
    if(this.chart && this.chart.plotArea && this.chart.plotArea.charts[0])
    {
        this.chart.plotArea.removeCharts(1, this.chart.plotArea.charts.length - 1);
        var  asc_series = asc_chart.series;
        var chart_type = this.chart.plotArea.charts[0];
        var first_series = chart_type.series[0] ? chart_type.series[0] : chart_type.getSeriesConstructor();

        var bAccent1Background = false;
        if(this.spPr && this.spPr.Fill && this.spPr.Fill.fill && this.spPr.Fill.fill.color && this.spPr.Fill.fill.color.color
            && this.spPr.Fill.fill.color.color.type === window['Asc'].c_oAscColor.COLOR_TYPE_SCHEME &&  this.spPr.Fill.fill.color.color.id === 0){
            bAccent1Background = true;
        }

        var oFirstSpPrPreset = 0;
        if(chart_type.getObjectType() === AscDFH.historyitem_type_PieChart || chart_type.getObjectType() === AscDFH.historyitem_type_DoughnutChart){
            if(chart_type.series[0] && chart_type.series[0].dPt[0] && chart_type.series[0].dPt[0].spPr){
                oFirstSpPrPreset = AscFormat.CollectSettingsSpPr(chart_type.series[0].dPt[0].spPr);
            }
        }
        else{
            if(chart_type.series[0]){
                oFirstSpPrPreset = AscFormat.CollectSettingsSpPr(chart_type.series[0].spPr);
            }
        }

        if(first_series.spPr){
            first_series.spPr.setFill(null);
            first_series.spPr.setLn(null);
        }

        var style = AscFormat.CHART_STYLE_MANAGER.getStyleByIndex(this.style);
        var base_fills = AscFormat.getArrayFillsFromBase(style.fill2, asc_series.length);
        if(chart_type.getObjectType() !== AscDFH.historyitem_type_ScatterChart)
        {

            if(asc_series.length < chart_type.series.length){
                for(var i = chart_type.series.length - 1; i >= asc_series.length; --i){
                    chart_type.removeSeries(i);
                }
            }
            for(var i = 0; i < asc_series.length; ++i)
            {
                var series = null, bNeedAdd = false;
                if(chart_type.series[i])
                {
                    series = chart_type.series[i];
                }
                else
                {
                    bNeedAdd = true;
                    series = first_series.createDuplicate();
                }

                series.setIdx(i);
                series.setOrder(i);
                series.setVal(new AscFormat.CYVal());




                FillValNum(series.val, asc_series[i].Val, true, false);

                if(chart_type.getObjectType() === AscDFH.historyitem_type_PieChart || chart_type.getObjectType() === AscDFH.historyitem_type_DoughnutChart){
                    if(oFirstSpPrPreset){
                        var pts = AscFormat.getPtsFromSeries(series);
                        for(var j = 0; j < pts.length; ++j){
                            var oDPt = new AscFormat.CDPt();
                            oDPt.setBubble3D(false);
                            oDPt.setIdx(j);
                            AscFormat.ApplySpPr(oFirstSpPrPreset, oDPt, j, base_fills, bAccent1Background);
                            series.series[i].addDPt(oDPt);
                        }
                    }
                }
                else{
                    AscFormat.ApplySpPr(oFirstSpPrPreset, series, i, base_fills, bAccent1Background);
                }
                if(asc_series[i].Cat && asc_series[i].Cat.NumCache && typeof asc_series[i].Cat.Formula === "string" && asc_series[i].Cat.Formula.length > 0)
                {
                    series.setCat(new AscFormat.CCat());
                    FillCatStr(series.cat, asc_series[i].Cat, true, false);
                }
                else
                {
                    series.setCat(null);
                }
                if(asc_series[i].TxCache && typeof asc_series[i].TxCache.Formula === "string" && asc_series[i].TxCache.Formula.length > 0)
                {
                    FillSeriesTx(series, asc_series[i].TxCache, true, false);
                }
                else
                {
                    series.setTx(null);
                }
                if(bNeedAdd)
                {
                    chart_type.addSer(series);
                }

            }
        }
        else
        {
            for(var i = chart_type.series.length - 1; i > -1; --i){
                chart_type.removeSeries(i);
            }
            var oXVal;
            var start_index = 0;
            var minus = 0;
            if(asc_series[0].xVal && asc_series[0].xVal.NumCache && typeof asc_series[0].xVal.Formula === "string" && asc_series[0].xVal.Formula.length > 0)
            {
                oXVal = new AscFormat.CXVal();
                FillCatStr(oXVal, asc_series[0].xVal, true, false);
            }
            else if(asc_series[0].Cat && asc_series[0].Cat.NumCache && typeof asc_series[0].Cat.Formula === "string" && asc_series[0].Cat.Formula.length > 0)
            {
                oXVal = new AscFormat.CXVal();
                FillCatStr(oXVal, asc_series[0].Cat, true, false);
            }
            for(var i = start_index; i < asc_series.length; ++i)
            {
                var series = new AscFormat.CScatterSeries();
                series.setIdx(i - minus);
                series.setOrder(i - minus);
                AscFormat.ApplySpPr(oFirstSpPrPreset, series, i, base_fills, bAccent1Background);
                if(oXVal)
                {
                    series.setXVal(oXVal.createDuplicate());
                }
                series.setYVal(new AscFormat.CYVal());
                FillValNum(series.yVal, asc_series[i].Val, true, false);
                if(asc_series[i].TxCache && typeof asc_series[i].TxCache.Formula === "string" && asc_series[i].TxCache.Formula.length > 0)
                {
                    FillSeriesTx(series, asc_series[i].TxCache, true, false);
                }
                chart_type.addSer(series);
            }
        }
        this.recalculateReferences();
    }
};
CChartSpace.prototype.Write_ToBinary2 = function (w)
{
    w.WriteLong(this.getObjectType());
    w.WriteString2(this.Id);
};
CChartSpace.prototype.Read_FromBinary2 = function (r)
{
    this.Id = r.GetString2();
};
CChartSpace.prototype.handleUpdateType = function()
{
    if(this.bNoHandleRecalc === true)
    {
        return;
    }
    this.recalcInfo.recalculateChart =  true;
    this.recalcInfo.recalculateSeriesColors = true;
    this.recalcInfo.recalculateMarkers = true;
    this.recalcInfo.recalculateGridLines = true;
    this.recalcInfo.recalculateDLbls = true;
    this.recalcInfo.recalculateAxisLabels = true;
    //this.recalcInfo.dataLbls.length = 0;
    //this.recalcInfo.axisLabels.length = 0;
    this.recalcInfo.recalculateAxisVal = true;
    this.recalcInfo.recalculateAxisTickMark = true;
    this.recalcInfo.recalculateHiLowLines = true;
    this.recalcInfo.recalculateUpDownBars = true;
    this.recalcInfo.recalculateLegend = true;
    this.recalcInfo.recalculateReferences = true;
    this.recalcInfo.recalculateBBox = true;
    this.recalcInfo.recalculateFormulas = true;
    this.chartObj = null;
    this.addToRecalculate();
};
CChartSpace.prototype.handleUpdateInternalChart = function()
{
    if(this.bNoHandleRecalc === true)
    {
        return;
    }
    this.recalcInfo.recalculateChart =  true;
    this.recalcInfo.recalculateSeriesColors = true;
    this.recalcInfo.recalculateDLbls = true;
    this.recalcInfo.recalculateAxisLabels = true;
    this.recalcInfo.recalculateMarkers = true;
    this.recalcInfo.recalculatePlotAreaBrush = true;
    this.recalcInfo.recalculatePlotAreaPen   = true;
    this.recalcInfo.recalculateAxisTickMark  = true;
    //this.recalcInfo.dataLbls.length = 0;
    //this.recalcInfo.axisLabels.length = 0;
    this.recalcInfo.recalculateAxisVal = true;
    this.recalcInfo.recalculateLegend = true;
    this.recalcInfo.recalculateBBox = true;
    this.chartObj = null;
    this.addToRecalculate();

};
CChartSpace.prototype.handleUpdateGridlines = function()
{
    this.recalcInfo.recalculateGridLines = true;
    this.addToRecalculate();
};
CChartSpace.prototype.handleUpdateDataLabels = function()
{
    this.recalcInfo.recalculateDLbls = true;
    this.addToRecalculate();
};
CChartSpace.prototype.updateChildLabelsTransform = function(posX, posY)
{

    if(this.localTransformText)
    {
        this.transformText = this.localTransformText.CreateDublicate();
        global_MatrixTransformer.TranslateAppend(this.transformText, posX, posY);
        this.invertTransformText = global_MatrixTransformer.Invert(this.transformText);
    }

    if(this.chart)
    {
        if(this.chart.plotArea)
        {
            var aCharts = this.chart.plotArea.charts;
            for(var t = 0; t < aCharts.length; ++t){
                var oChart = aCharts[t];
                var series = oChart.series;
                for(var i = 0; i < series.length; ++i)
                {
                    var ser = series[i];
                    var pts = AscFormat.getPtsFromSeries(ser);
                    for(var j = 0; j < pts.length; ++j)
                    {
                        if(pts[j].compiledDlb)
                        {
                            pts[j].compiledDlb.updatePosition(posX, posY);
                        }
                    }
                }
            }
            var aAxes = this.chart.plotArea.axId;
            for(var i = 0; i < aAxes.length; ++i){
                var oAxis = aAxes[i];
                if(oAxis){
                    if(oAxis.title){
                        oAxis.title.updatePosition(posX, posY);
                    }
                    if(oAxis.labels){
                        oAxis.labels.updatePosition(posX, posY);
                    }
                }
            }

        }
        if(this.chart.title)
        {
            this.chart.title.updatePosition(posX, posY);
        }
        if(this.chart.legend)
        {
            this.chart.legend.updatePosition(posX, posY);
        }
    }
};
CChartSpace.prototype.recalcTitles = function()
{
    if(this.chart && this.chart.title)
    {
        this.chart.title.recalcInfo.recalculateContent = true;
        this.chart.title.recalcInfo.recalcTransform = true;
        this.chart.title.recalcInfo.recalcTransformText = true;
    }
    if(this.chart && this.chart.plotArea)
    {
        var aAxes = this.chart.plotArea.axId;
        if(aAxes)
        {
            for(var i = 0; i < aAxes.length; ++i)
            {
                var axis = aAxes[i];
                if(axis && axis.title)
                {
                    axis.title.recalcInfo.recalculateContent = true;
                    axis.title.recalcInfo.recalcTransform = true;
                    axis.title.recalcInfo.recalcTransformText = true;
                }
            }
        }
    }
};
CChartSpace.prototype.recalcTitles2 = function()
{
    if(this.chart && this.chart.title)
    {
        this.chart.title.recalcInfo.recalculateContent = true;
        this.chart.title.recalcInfo.recalcTransform = true;
        this.chart.title.recalcInfo.recalcTransformText = true;
        this.chart.title.recalcInfo.recalculateTxBody = true;
    }
    if(this.chart && this.chart.plotArea)
    {
        var aAxes = this.chart.plotArea.axId;
        if(aAxes)
        {
            for(var i = 0; i < aAxes.length; ++i)
            {
                var axis = aAxes[i];
                if(axis && axis.title)
                {
                    axis.title.recalcInfo.recalculateContent = true;
                    axis.title.recalcInfo.recalcTransform = true;
                    axis.title.recalcInfo.recalcTransformText = true;
                    axis.title.recalcInfo.recalculateTxBody = true;
                }
            }
        }
    }
};
CChartSpace.prototype.Refresh_RecalcData2 = function(pageIndex, object)
{
    if(object && object.getObjectType && object.getObjectType() === AscDFH.historyitem_type_Title && this.selection.title === object)
    {
        this.recalcInfo.recalcTitle = object;
    }
    else
    {
        var bOldRecalculateRef = this.recalcInfo.recalculateReferences;
        this.setRecalculateInfo();
        this.recalcInfo.recalculateReferences = bOldRecalculateRef;
    }
    this.addToRecalculate();
};
CChartSpace.prototype.Refresh_RecalcData = function(data)
{
    switch(data.Type)
    {
        case AscDFH.historyitem_ChartSpace_SetStyle:
        {
            this.handleUpdateStyle();
            break;
        }
        case AscDFH.historyitem_ChartSpace_SetTxPr:
        {
            this.recalcInfo.recalculateChart = true;
            this.recalcInfo.recalculateLegend = true;
            this.recalcInfo.recalculateDLbls = true;
            this.recalcInfo.recalculateAxisVal = true;
            this.recalcInfo.recalculateAxisCat = true;
            this.recalcInfo.recalculateAxisLabels = true;
            this.addToRecalculate();
            break;
        }
        case AscDFH.historyitem_ChartSpace_SetChart:
        {
            this.handleUpdateType();
            break;
        }
        case AscDFH.historyitem_ShapeSetBDeleted:{
            if(!this.bDeleted){
                this.handleUpdateType();
            }
            break;
        }
    }
};
CChartSpace.prototype.getObjectType = function()
{
    return AscDFH.historyitem_type_ChartSpace;
};
CChartSpace.prototype.getAllRasterImages = function(images)
{
    if(this.spPr)
    {
        this.spPr.checkBlipFillRasterImage(images);
    }
    var chart = this.chart;
    if(chart)
    {
        chart.backWall && chart.backWall.spPr && chart.backWall.spPr.checkBlipFillRasterImage(images);
        chart.floor && chart.floor.spPr && chart.floor.spPr.checkBlipFillRasterImage(images);
        chart.legend && chart.legend.spPr && chart.legend.spPr.checkBlipFillRasterImage(images);
        chart.sideWall && chart.sideWall.spPr && chart.sideWall.spPr.checkBlipFillRasterImage(images);
        chart.title && chart.title.spPr && chart.title.spPr.checkBlipFillRasterImage(images);
        //plotArea
        var plot_area = this.chart.plotArea;
        if(plot_area)
        {
            plot_area.spPr && plot_area.spPr.checkBlipFillRasterImage(images);
            var i;
            for(i = 0; i < plot_area.axId.length; ++i)
            {
                var axis = plot_area.axId[i];
                if(axis)
                {
                    axis.spPr && axis.spPr.checkBlipFillRasterImage(images);
                    axis.title && axis.title && axis.title.spPr && axis.title.spPr.checkBlipFillRasterImage(images);
                }
            }
            for(i = 0; i < plot_area.charts.length; ++i)
            {
                plot_area.charts[i].getAllRasterImages(images);
            }
        }
    }
};
CChartSpace.prototype.getAllContents = function()
{

};

    CChartSpace.prototype.getAllFonts = function (allFonts) {
        this.documentGetAllFontNames(allFonts);
    };
CChartSpace.prototype.documentGetAllFontNames = function(allFonts)
{
    allFonts["+mn-lt"] = 1;
    allFonts["+mn-ea"] = 1;
    allFonts["+mn-cs"] = 1;
    checkTxBodyDefFonts(allFonts, this.txPr);
    var chart = this.chart, i;
    if(chart)
    {
        for(i = 0; i < chart.pivotFmts.length; ++i)
        {
            chart.pivotFmts[i] &&  checkTxBodyDefFonts(allFonts, chart.pivotFmts[i].txPr);
        }
        if(chart.legend)
        {
            checkTxBodyDefFonts(allFonts, chart.legend.txPr);
            for(i = 0;  i < chart.legend.legendEntryes.length; ++i)
            {
                chart.legend.legendEntryes[i] && checkTxBodyDefFonts(allFonts, chart.legend.legendEntryes[i].txPr);
            }
        }
        if(chart.title)
        {
            checkTxBodyDefFonts(allFonts, chart.title.txPr);
            if(chart.title.tx && chart.title.tx.rich)
            {
                checkTxBodyDefFonts(allFonts, chart.title.tx.rich);
                chart.title.tx.rich.content && chart.title.tx.rich.content.Document_Get_AllFontNames(allFonts);
            }
        }
        var plot_area = chart.plotArea;
        if(plot_area)
        {
            for(i = 0; i < plot_area.charts.length; ++i)
            {
                plot_area.charts[i] && plot_area.charts[i].documentCreateFontMap(allFonts);/*TODO надо бы этот метод переименовать чтоб название не вводило в заблуждение*/
            }
            var cur_axis;
            for(i = 0; i < plot_area.axId.length; ++i)
            {
                cur_axis = plot_area.axId[i];
                checkTxBodyDefFonts(allFonts, cur_axis.txPr);
                if(cur_axis.title)
                {
                    checkTxBodyDefFonts(allFonts, cur_axis.title.txPr);
                    if(cur_axis.title.tx && cur_axis.title.tx.rich)
                    {
                        checkTxBodyDefFonts(allFonts, cur_axis.title.tx.rich);
                        cur_axis.title.tx.rich.content && cur_axis.title.tx.rich.content.Document_Get_AllFontNames(allFonts);
                    }
                }
            }
        }
    }
};
CChartSpace.prototype.documentCreateFontMap = function(allFonts)
{
    if(this.chart)
    {
        this.chart.title && this.chart.title.txBody && this.chart.title.txBody.content.Document_CreateFontMap(allFonts);
        var i, j, k;
        if(this.chart.legend)
        {
            var calc_entryes = this.chart.legend.calcEntryes;
            for(i = 0; i < calc_entryes.length; ++i)
            {
                calc_entryes[i].txBody.content.Document_CreateFontMap(allFonts);
            }
        }
        var axis = this.chart.plotArea.axId, cur_axis;
        for(i = axis.length-1; i > -1 ; --i)
        {
            cur_axis = axis[i];
            if(cur_axis)
            {
                cur_axis && cur_axis.title && cur_axis.title.txBody && cur_axis.title.txBody.content.Document_CreateFontMap(allFonts);
                if(cur_axis.labels)
                {
                    for(j = cur_axis.labels.aLabels.length - 1; j > -1; --j)
                    {
                        cur_axis.labels.aLabels[j] && cur_axis.labels.aLabels[j].txBody && cur_axis.labels.aLabels[j].txBody.content.Document_CreateFontMap(allFonts);
                    }
                }
            }
        }

        var series, pts;
        for(i = this.chart.plotArea.charts.length-1; i > -1; --i)
        {
            series = this.chart.plotArea.charts[i].series;
            for(j = series.length -1; j > -1; --j)
            {
                pts = AscFormat.getPtsFromSeries(series[i]);
                if(Array.isArray(pts))
                {
                    for(k = pts.length - 1; k > -1; --k)
                    {
                        pts[k].compiledDlb && pts[k].compiledDlb.txBody && pts[k].compiledDlb.txBody.content.Document_CreateFontMap(allFonts);
                    }
                }
            }
        }
    }
};
CChartSpace.prototype.setThemeOverride = function(pr)
{
    History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartSpace_SetThemeOverride, this.themeOverride,  pr));
    this.themeOverride = pr;
};
CChartSpace.prototype.setParent = function (parent)
{
    History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartSpace_SetParent, this.parent, parent ));
    this.parent = parent;
};
CChartSpace.prototype.setChart = function(chart)
{
    History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartSpace_SetChart, this.chart,  chart));
    this.chart = chart;
    if(chart)
    {
        chart.setParent(this);
    }
};
CChartSpace.prototype.setClrMapOvr = function(clrMapOvr)
{
    History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartSpace_SetClrMapOvr,  this.clrMapOvr, clrMapOvr));
    this.clrMapOvr = clrMapOvr;
};
CChartSpace.prototype.setDate1904 = function(date1904)
{
    History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_ChartSpace_SetDate1904, this.date1904, date1904));
    this.date1904 = date1904;
};
CChartSpace.prototype.setExternalData = function(externalData)
{
    History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartSpace_SetExternalData, this.externalData, externalData));
    this.externalData = externalData;
};
CChartSpace.prototype.setLang = function(lang)
{
    History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_ChartSpace_SetLang, this.lang, lang));
    this.lang = lang;
};
CChartSpace.prototype.setPivotSource = function(pivotSource)
{
    History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartSpace_SetPivotSource, this.pivotSource, pivotSource));
    this.pivotSource = pivotSource;
};
CChartSpace.prototype.setPrintSettings = function(printSettings)
{
    History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartSpace_SetPrintSettings, this.printSettings, printSettings));
    this.printSettings = printSettings;
};
CChartSpace.prototype.setProtection = function(protection)
{
    History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartSpace_SetProtection, this.protection, protection));
    this.protection = protection;
};
CChartSpace.prototype.setRoundedCorners = function(roundedCorners)
{
    History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_ChartSpace_SetRoundedCorners, this.roundedCorners, roundedCorners));
    this.roundedCorners = roundedCorners;
};
CChartSpace.prototype.setSpPr = function(spPr)
{
    History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartSpace_SetSpPr, this.spPr, spPr));
    this.spPr = spPr;
};
CChartSpace.prototype.setStyle = function(style)
{
    History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_ChartSpace_SetStyle, this.style, style));
    this.style = style;
    this.handleUpdateStyle();
};
CChartSpace.prototype.setTxPr = function(txPr)
{
    History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartSpace_SetTxPr, this.txPr, txPr));
    this.txPr = txPr;
    if(txPr)
    {
        txPr.setParent(this);
    }
};
CChartSpace.prototype.setUserShapes = function(userShapes)
{
    History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_ChartSpace_SetUserShapes, this.userShapes, userShapes));
    this.userShapes = userShapes;
};
CChartSpace.prototype.getTransformMatrix = function()
{
    return this.transform;
};
CChartSpace.prototype.canRotate = function()
{
    return false;
};
CChartSpace.prototype.drawAdjustments = function()
{};
CChartSpace.prototype.isChart = function()
{
    return true;
};
CChartSpace.prototype.isShape = function()
{
    return false;
};
CChartSpace.prototype.isImage = function()
{
    return false;
};
CChartSpace.prototype.isGroup = function()
{
    return false;
};
CChartSpace.prototype.isPlaceholder = CShape.prototype.isPlaceholder;
CChartSpace.prototype.setGroup = function (group)
{
    History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartSpace_SetGroup, this.group, group ));
    this.group = group;
};

CChartSpace.prototype.getBase64Img = CShape.prototype.getBase64Img;

CChartSpace.prototype.getRangeObjectStr = function()
{
    if(this.recalcInfo.recalculateBBox)
    {
        this.recalculateBBox();
        this.recalcInfo.recalculateBBox = false;
    }
    var ret = {range: null, bVert: null};
    if(this.bbox && this.bbox.seriesBBox)
    {
        var r1 = this.bbox.seriesBBox.r1, r2 = this.bbox.seriesBBox.r2, c1 = this.bbox.seriesBBox.c1, c2 = this.bbox.seriesBBox.c2;
        ret.bVert = this.bbox.seriesBBox.bVert;
       if(this.bbox.seriesBBox.bVert)
       {
           if(this.bbox.catBBox)
           {
               if(r1 > 0)
               {
                   --r1;
               }
           }
           if(this.bbox.serBBox)
           {
               if(c1 > 0)
               {
                   --c1;
               }
           }
       }
       else
       {
           if(this.bbox.catBBox)
           {
               if(c1 > 0)
               {
                   --c1;
               }
           }
           if(this.bbox.serBBox)
           {
               if(r1 > 0)
               {
                   --r1;
               }
           }
       }

        if (this.bbox.worksheet) {
            var sRef = (new Asc.Range(c1, r1, c2, r2)).getName(AscCommonExcel.referenceType.A);
            ret.range = parserHelp.get3DRef(this.bbox.worksheet.sName, sRef);
        }
    }
    return ret;
};

CChartSpace.prototype.recalculateBBox = function()
{
    this.bbox = null;
    this.seriesBBoxes = [];
    this.seriesTitlesBBoxes = [];
    this.catTitlesBBoxes = [];


    var series_bboxes = [], cat_bboxes = [], ser_titles_bboxes = [];

    var series_sheet, cur_bbox, parsed_formulas;

    if(this.chart && this.chart.plotArea && this.chart.plotArea && this.worksheet)
    {
        var series = [];
        var aCharts = this.chart.plotArea.charts;
        for(var i = 0; i < aCharts.length; ++i){
            series = series.concat(aCharts[i].series);
        }
        series.sort(function(a, b){
            return a.idx - b.idx;
        });
        if(Array.isArray(series) && series.length > 0)
        {
            var series_title_f = [], cat_title_f, series_f = [], i, range1;
            var ref;

            var b_vert/*флаг означает, что значения в серии идут по горизонтали, а сами серии по вертикали сверху вниз*/
                , b_titles_vert;
            var first_series_sheet;
            for(i = 0; i < series.length; ++i)
            {
                var numRef = null;
                if(series[i].val)
                    numRef = series[i].val.numRef;
                else if(series[i].yVal)
                    numRef = series[i].yVal.numRef;
                if(numRef)
                {
                    parsed_formulas = this.parseChartFormula(numRef.f);
                    if(parsed_formulas && parsed_formulas.length > 0 && parsed_formulas[0].worksheet)
                    {
                        series_bboxes = series_bboxes.concat(parsed_formulas);
                        if(series_f !== null && parsed_formulas.length === 1)
                        {
                            series_sheet = parsed_formulas[0].worksheet;
                            if(!first_series_sheet)
                                first_series_sheet = series_sheet;
                            if(series_sheet !== first_series_sheet)
                                series_f = null;
                            if(parsed_formulas[0].bbox)
                            {
                                cur_bbox = parsed_formulas[0].bbox;
                                if(cur_bbox.r1 !== cur_bbox.r2 && cur_bbox.c1 !== cur_bbox.c2)
                                    series_f = null;
                                if(series_f && series_f.length > 0)
                                {
                                    if(!AscFormat.isRealBool(b_vert))
                                    {
                                        if(series_f[0].c1 === cur_bbox.c1 && series_f[0].c2 === cur_bbox.c2)
                                        {
                                            b_vert = true;
                                        }
                                        else if(series_f[0].r1 === cur_bbox.r1 && series_f[0].r2 === cur_bbox.r2)
                                        {
                                            b_vert = false;
                                        }
                                        else
                                        {
                                            series_f = null;
                                        }
                                    }
                                    else
                                    {
                                        if(b_vert)
                                        {
                                            if(!(series_f[0].c1 === cur_bbox.c1 && series_f[0].c2 === cur_bbox.c2))
                                            {
                                                series_f = null;
                                            }
                                        }
                                        else
                                        {
                                            if(!(series_f[0].r1 === cur_bbox.r1 && series_f[0].r2 === cur_bbox.r2))
                                            {
                                                series_f = null;
                                            }
                                        }
                                    }
                                    if(series_f)
                                    {
                                        if(b_vert )
                                        {
                                            if(cur_bbox.r1 - series_f[series_f.length-1].r1 !== 1)
                                                series_f = null;
                                        }
                                        else
                                        {
                                            if(cur_bbox.c1 - series_f[series_f.length-1].c1 !== 1)
                                                series_f = null;
                                        }
                                    }
                                }
                                if(series_f !== null)
                                    series_f.push(cur_bbox);
                            }
                            else
                                series_f = null;
                        }
                    }
                }
                else
                    series_f = null;
                if(series[i].tx && series[i].tx.strRef)
                {
                    parsed_formulas = this.parseChartFormula(series[i].tx.strRef.f);
                    if(parsed_formulas && parsed_formulas.length > 0 && parsed_formulas[0].worksheet)
                    {
                        ser_titles_bboxes = ser_titles_bboxes.concat(parsed_formulas);
                    }
                    if(series_title_f !== null)
                    {
                        if(!parsed_formulas || parsed_formulas.length !== 1 || !parsed_formulas[0].worksheet)
                        {
                            series_title_f = null;
                            continue;
                        }
                        var series_cat_sheet = parsed_formulas[0].worksheet;
                        if(series_cat_sheet !== first_series_sheet)
                        {
                            series_title_f = null;
                            continue;
                        }
                        cur_bbox = parsed_formulas[0].bbox;
                        if(cur_bbox)
                        {
                            if(cur_bbox.r1 !== cur_bbox.r2 || cur_bbox.c1 !== cur_bbox.c2)
                            {
                                series_title_f = null;
                                continue;
                            }
                            if(!AscFormat.isRealBool(b_titles_vert))
                            {
                                if(series_title_f.length > 0)
                                {
                                    if( cur_bbox.r1 - series_title_f[0].r1 === 1)
                                        b_titles_vert = true;
                                    else if(cur_bbox.c1 - series_title_f[0].c1 === 1)
                                        b_titles_vert = false;
                                    else
                                    {
                                        series_title_f = null;
                                        continue;
                                    }
                                }
                            }
                            else
                            {
                                if(b_titles_vert)
                                {
                                    if( cur_bbox.r1 - series_title_f[series_title_f.length-1].r1 !== 1)
                                    {
                                        series_title_f = null;
                                        continue;
                                    }
                                }
                                else
                                {
                                    if( cur_bbox.c1 - series_title_f[series_title_f.length-1].c1 !== 1)
                                    {
                                        series_title_f = null;
                                        continue;
                                    }
                                }
                            }
                            series_title_f.push(cur_bbox);
                        }
                        else
                        {
                            series_title_f = null;
                            continue;
                        }
                    }
                }
                else
                {
                    series_title_f = null;
                }
            }

            if(series[0].cat)
            {
                if(series[0].cat.strRef)
                {
                    ref = series[0].cat.strRef;
                }
                else if(series[0].cat.numRef)
                {
                    ref = series[0].cat.numRef;
                }
            }
            else if(series[0].xVal)
            {
                if(series[0].xVal.strRef)
                {
                    ref = series[0].xVal.strRef;
                }
                else if(series[0].xVal.numRef)
                {
                    ref = series[0].xVal.numRef;
                }
            }
            if(ref)
            {
                parsed_formulas = this.parseChartFormula(ref.f);
                if(parsed_formulas && parsed_formulas.length === 1 && parsed_formulas[0].worksheet)
                {
                    cat_bboxes = cat_bboxes.concat(parsed_formulas);
                    if(parsed_formulas.length === 1)
                    {
                        var cat_title_sheet = parsed_formulas[0].worksheet;
                        if(cat_title_sheet === first_series_sheet)
                        {
                            if(parsed_formulas[0].bbox)
                            {
                                cat_title_f = parsed_formulas[0].bbox;
                            }
                        }
                    }
                }
            }

            if(series_f !== null && series_f.length === 1)
            {
                if(series_f[0].r1 === series_f[0].r2 && series_f[0].c1 !== series_f[0].c2)
                {
                    b_vert = true;
                }
                else if(series_f[0].c1 === series_f[0].c2 && series_f[0].r1 !== series_f[0].r2)
                {
                    b_vert = false;
                }

                if(!AscFormat.isRealBool(b_vert) && Array.isArray(series_title_f) )
                {
                    if(series_f[0].r1 === series_f[0].r2 && series_title_f[0].r1 === series_f[0].r1)
                    {
                        b_vert = true;
                    }
                    else if(series_f[0].c1 === series_f[0].c2 && series_title_f[0].c1 === series_f[0].c1)
                    {
                        b_vert = false;
                    }
                }
                if(!AscFormat.isRealBool(b_vert))
                {
                    if(cat_title_f)
                    {
                        if(series_f[0].r1 === series_f[0].r2 && cat_title_f.c1 === series_f[0].c1 && cat_title_f.c2 === series_f[0].c2)
                        {
                            b_vert = true;
                        }
                        else if(series_f[0].c1 === series_f[0].c2 && cat_title_f.r1 === series_f[0].r1 && cat_title_f.r2 === series_f[0].r2)
                        {
                            b_vert = false;
                        }
                    }
                    if(!AscFormat.isRealBool(b_vert))
                    {
                        b_vert = true;
                    }
                }
            }

            if(series_f !== null && series_f.length > 0)
            {
                this.bbox =  {
                    seriesBBox: null,
                    catBBox: null,
                    serBBox: null,
                    worksheet: first_series_sheet
                };


                this.bbox.seriesBBox = {
                    r1: series_f[0].r1,
                    r2: series_f[series_f.length-1].r2,
                    c1: series_f[0].c1,
                    c2: series_f[series_f.length-1].c2,
                    bVert: b_vert
                };


                this.seriesBBoxes.push(new BBoxInfo(first_series_sheet, this.bbox.seriesBBox));

                if(cat_title_f)
                {
                    if(b_vert)
                    {
                        if(cat_title_f.c1 !== this.bbox.seriesBBox.c1
                            || cat_title_f.c2 !== this.bbox.seriesBBox.c2
                            || cat_title_f.r1 !== cat_title_f.r1)
                        {
                            cat_title_f = null;
                        }
                    }
                    else
                    {
                        if(cat_title_f.c1 !== cat_title_f.c2
                            || cat_title_f.r1 !== this.bbox.seriesBBox.r1
                            || cat_title_f.r2 !== this.bbox.seriesBBox.r2)
                        {
                            cat_title_f = null;
                        }
                    }
                    this.bbox.catBBox = cat_title_f;

                    if(cat_title_f)
                    {
                        this.catTitlesBBoxes.push(new BBoxInfo(first_series_sheet, cat_title_f));
                    }
                }
                if(Array.isArray(series_title_f))
                {
                    this.bbox.serBBox = {
                        r1: series_title_f[0].r1,
                        r2: series_title_f[series_title_f.length-1].r2,
                        c1: series_title_f[0].c1,
                        c2: series_title_f[series_title_f.length-1].c2
                    };
                    this.seriesTitlesBBoxes.push(new BBoxInfo(first_series_sheet, this.bbox.serBBox));
                }
            }
            else
            {
                for(i = 0;  i < series_bboxes.length; ++i)
                {
                    this.seriesBBoxes.push(new BBoxInfo(series_bboxes[i].worksheet, series_bboxes[i].bbox));
                }

                for(i = 0;  i < cat_bboxes.length; ++i)
                {
                    this.catTitlesBBoxes.push(new BBoxInfo(cat_bboxes[i].worksheet, cat_bboxes[i].bbox));
                }

                for(i = 0;  i < ser_titles_bboxes.length; ++i)
                {
                    this.seriesTitlesBBoxes.push(new BBoxInfo(ser_titles_bboxes[i].worksheet, ser_titles_bboxes[i].bbox));
                }
            }
        }
    }
};

CChartSpace.prototype.getCommonBBox = function()
{
    if(this.recalcInfo.recalculateBBox)
    {
        this.recalculateBBox();
        this.recalcInfo.recalculateBBox = false;
    }
    var oRet = null;
    if(this.bbox && this.bbox.seriesBBox && AscFormat.isRealBool(this.bbox.seriesBBox.bVert))
    {
        oRet = {r1: this.bbox.seriesBBox.r1, r2: this.bbox.seriesBBox.r2, c1: this.bbox.seriesBBox.c1, c2: this.bbox.seriesBBox.c2};
        if(this.bbox.seriesBBox.bVert)
        {
            if(this.bbox.catBBox )
            {
                if(this.bbox.catBBox.r1 === this.bbox.catBBox.r2 && this.bbox.catBBox.r1 === this.bbox.seriesBBox.r1 - 1)
                {
                    --oRet.r1;
                }
                else
                {
                    oRet = null;
                }
            }
            if(oRet)
            {
                if(this.bbox.serBBox)
                {
                    if(this.bbox.serBBox.c1 === this.bbox.serBBox.c2 && this.bbox.serBBox.c1 === this.bbox.seriesBBox.c1 - 1)
                    {
                        --oRet.c1;
                    }
                    else
                    {
                        oRet = null;
                    }
                }
            }
        }
        else
        {
            if(this.bbox.catBBox )
            {
                if(this.bbox.catBBox.c1 === this.bbox.catBBox.c2 && this.bbox.catBBox.c1 === this.bbox.seriesBBox.c1 - 1)
                {
                    --oRet.c1;
                }
                else
                {
                    oRet = null;
                }
            }
            if(oRet)
            {
                if(this.bbox.serBBox)
                {
                    if(this.bbox.serBBox.r1 === this.bbox.serBBox.r2 && this.bbox.serBBox.r1 === this.bbox.seriesBBox.r1 - 1)
                    {
                        --oRet.r1;
                    }
                    else
                    {
                        oRet = null;
                    }
                }
            }
        }
    }
    return oRet;

};

CChartSpace.prototype.checkValByNumRef = function(workbook, ser, val, bVertical)
{
    if(val && val.numRef && typeof val.numRef.f === "string"/*(!val.numRef.numCache || val.numRef.numCache.pts.length === 0)*/)
    {
        var aParsedRef = this.parseChartFormula(val.numRef.f);
        var num_cache;
        var hidden = true;
        if(!val.numRef.numCache )
        {
            num_cache = new AscFormat.CNumLit();
            num_cache.setFormatCode("General");
            num_cache.setPtCount(0);
        }
        else
        {
            num_cache = val.numRef.numCache;
            if(aParsedRef.length > 0){
                removePtsFromLit(num_cache);
            }
            else{
                hidden = false;
            }

        }
        var lit_format_code = typeof num_cache.formatCode === "string" && num_cache.formatCode.length > 0 ? num_cache.formatCode : "General";
        var pt_index = 0, i, j, cell, pt, row_hidden, col_hidden, nPtCount = 0, t;
        for(i = 0; i < aParsedRef.length; ++i)
        {
            var oCurRef = aParsedRef[i];
            var source_worksheet = oCurRef.worksheet;
            if(source_worksheet)
            {
                var range = oCurRef.bbox;
                var nLastNoEmptyIndex = null, dLastNoEmptyVal = null, aSpanPoints = [], nSpliceIndex = null;
                if(range.r1 === range.r2 || bVertical === true)
                {
                    row_hidden = source_worksheet.getRowHidden(range.r1);
                    for(j = range.c1;  j <= range.c2; ++j)
                    {
                        if(!row_hidden && !source_worksheet.getColHidden(j) || (this.displayHidden === true))
                        {
                            hidden = false;
                            cell = source_worksheet.getCell3(range.r1, j);
                            var sCellValue = cell.getValue();
                            var value = cell.getNumberValue();
                            if(!AscFormat.isRealNumber(value) && (!AscFormat.isRealNumber(this.displayEmptyCellsAs) || this.displayEmptyCellsAs === 1)){
                                var sVal = cell.getValueForEdit();
                                if((typeof sVal === "string") && sVal.length > 0){
                                    value = 0;
                                }
                            }
                            if(AscFormat.isRealNumber(value))
                            {
                                pt = new AscFormat.CNumericPoint();
                                pt.setIdx(pt_index);
                                pt.setVal(value);
                                if(cell.getNumFormatStr() !== lit_format_code)
                                {
                                    pt.setFormatCode(cell.getNumFormatStr())
                                }
                                num_cache.addPt(pt);

                                if(aSpanPoints.length > 0 )
                                {
                                    if(AscFormat.isRealNumber(nLastNoEmptyIndex))
                                    {
                                        var oStartPoint = num_cache.getPtByIndex(nLastNoEmptyIndex);
                                        for(t = 0; t < aSpanPoints.length; ++t)
                                        {
                                            aSpanPoints[t].val = oStartPoint.val + ((pt.val - oStartPoint.val)/(aSpanPoints.length + 1))*(t+1);
                                            num_cache.pts.splice(nSpliceIndex + t, 0, aSpanPoints[t]);
                                        }
                                    }
                                    aSpanPoints.length = 0;
                                }
                                nLastNoEmptyIndex = pt_index;
                                nSpliceIndex = num_cache.pts.length;
                                dLastNoEmptyVal = pt.val;
                            }
                            else
                            {
                                if(AscFormat.isRealNumber(this.displayEmptyCellsAs) && this.displayEmptyCellsAs !== 1)
                                {
                                    if(this.displayEmptyCellsAs === 2 || ((typeof sCellValue === "string") && sCellValue.length > 0))
                                    {
                                        pt = new AscFormat.CNumericPoint();
                                        pt.setIdx(pt_index);
                                        pt.setVal(0);
                                        num_cache.addPt(pt);
                                        if(aSpanPoints.length > 0 )
                                        {
                                            if(AscFormat.isRealNumber(nLastNoEmptyIndex))
                                            {
                                                var oStartPoint = num_cache.getPtByIndex(nLastNoEmptyIndex);
                                                for(t = 0; t < aSpanPoints.length; ++t)
                                                {
                                                    aSpanPoints[t].val = oStartPoint.val + ((pt.val - oStartPoint.val)/(aSpanPoints.length + 1))*(t+1);
                                                    num_cache.pts.splice(nSpliceIndex + t, 0, aSpanPoints[t]);
                                                }
                                            }
                                            aSpanPoints.length = 0;
                                        }
                                        nLastNoEmptyIndex = pt_index;
                                        nSpliceIndex = num_cache.pts.length;
                                        dLastNoEmptyVal = pt.val;
                                    }
                                    else if(this.displayEmptyCellsAs === 0 && ser.getObjectType() === AscDFH.historyitem_type_LineSeries)
                                    {
                                        pt = new AscFormat.CNumericPoint();
                                        pt.setIdx(pt_index);
                                        pt.setVal(0);
                                        aSpanPoints.push(pt);
                                    }
                                }
                            }
                            nPtCount++;
                        }
                        pt_index++;
                    }
                }
                else
                {
                    col_hidden = source_worksheet.getColHidden(range.c1);
                    for(j = range.r1; j <= range.r2; ++j)
                    {
                        if(!col_hidden && !source_worksheet.getRowHidden(j) || (this.displayHidden === true))
                        {
                            hidden = false;
                            cell = source_worksheet.getCell3(j, range.c1);
                            var value = cell.getNumberValue();
                            var sCellValue = cell.getValue();
                            if(!AscFormat.isRealNumber(value) && !AscFormat.isRealNumber(this.displayEmptyCellsAs)){
                                var sVal = cell.getValueForEdit();
                                if((typeof sVal === "string") && sVal.length > 0){
                                    value = 0;
                                }
                            }
                            if(AscFormat.isRealNumber(value))
                            {
                                pt = new AscFormat.CNumericPoint();
                                pt.setIdx(pt_index);
                                pt.setVal(value);
                                if(cell.getNumFormatStr() !== lit_format_code)
                                {
                                    pt.setFormatCode(cell.getNumFormatStr());
                                }
                                num_cache.addPt(pt);
                            }
                            else
                            {
                                if(AscFormat.isRealNumber(this.displayEmptyCellsAs) && this.displayEmptyCellsAs !== 1)
                                {
                                    if(this.displayEmptyCellsAs === 2 || ((typeof sCellValue === "string") && sCellValue.length > 0))
                                    {
                                        pt = new AscFormat.CNumericPoint();
                                        pt.setIdx(pt_index);
                                        pt.setVal(0);
                                        num_cache.addPt(pt);
                                        if(aSpanPoints.length > 0 )
                                        {
                                            if(AscFormat.isRealNumber(nLastNoEmptyIndex))
                                            {
                                                var oStartPoint = num_cache.getPtByIndex(nLastNoEmptyIndex);
                                                for(t = 0; t < aSpanPoints.length; ++t)
                                                {
                                                    aSpanPoints[t].val = oStartPoint.val + ((pt.val - oStartPoint.val)/(aSpanPoints.length + 1))*(t+1);
                                                    num_cache.pts.splice(nSpliceIndex + t, 0, aSpanPoints[t]);
                                                }
                                            }
                                            aSpanPoints.length = 0;
                                        }
                                        nLastNoEmptyIndex = pt_index;
                                        nSpliceIndex = num_cache.pts.length;
                                        dLastNoEmptyVal = pt.val;
                                    }
                                    else if(this.displayEmptyCellsAs === 0 && ser.getObjectType() === AscDFH.historyitem_type_LineSeries)
                                    {
                                        pt = new AscFormat.CNumericPoint();
                                        pt.setIdx(pt_index);
                                        pt.setVal(0);
                                        aSpanPoints.push(pt);
                                    }
                                }
                            }
                            nPtCount++;
                        }
                        pt_index++;
                    }
                }

            }
            else{
                pt_index = 0;
                // var fCollectArray = function(oRef, oNumCache){
                //     if(Array.isArray(oRef)){
                //         for(var i = 0; i < oRef.length; ++i){
                //             if(Array.isArray(oRef[i])){
                //                 fCollectArray(oRef[i], oNumCache);
                //             }
                //             else{
                //                 cell = source_worksheet.getCell3(j, range.c1);
                //                 var value = cell.getNumberValue();
                //                 if(AscFormat.isRealNumber(value))
                //                 {
                //                     hidden = false;
                //                     pt = new AscFormat.CNumericPoint();
                //                     pt.setIdx(pt_index);
                //                     pt.setVal(value);
                //                     if(cell.getNumFormatStr() !== lit_format_code)
                //                     {
                //                         pt.setFormatCode(cell.getNumFormatStr());
                //                     }
                //                     num_cache.addPt(pt);
                //
                //                 }
                //             }
                //         }
                //     }
                //
                // };
            }
        }
        if(aParsedRef.length > 0){
            num_cache.setPtCount(nPtCount);
        }
        val.numRef.setNumCache(num_cache);
        if(!(val instanceof AscFormat.CCat))
        {
            ser.isHidden = hidden;
            ser.isHiddenForLegend = hidden;
        }
    }
};

CChartSpace.prototype.checkCatByNumRef = function(oThis, ser, cat, bVertical)
{

    if(cat && cat.strRef && typeof cat.strRef.f === "string" /*(!cat.strRef.strCache || cat.strRef.strCache.pt.length === 0)*/)
    {
        var aParsedRef = this.parseChartFormula(cat.strRef.f);
        var str_cache = new AscFormat.CStrCache();
        //str_cache.setFormatCode("General");
        var pt_index = 0, i, j, cell, pt, value_width_format, row_hidden, col_hidden, nPtCount = 0;

        var fParseTableDataString = function(oRef, oCache){
            if(Array.isArray(oRef)){
                for(var i = 0; i < oRef.length; ++i){
                    if(Array.isArray(oRef[i])){
                        fParseTableDataString(oRef, oCache);
                    }
                    else{
                        pt = new AscFormat.CStringPoint();
                        pt.setIdx(pt_index);
                        pt.setVal(oRef[i].value);
                        str_cache.addPt(pt);
                        ++pt_index;
                        ++nPtCount;
                    }
                }
            }
        };
        for(i = 0; i < aParsedRef.length; ++i)
        {
            var oCurRef = aParsedRef[i];
            var source_worksheet = oCurRef.worksheet;
            if(source_worksheet)
            {
                var range = oCurRef.bbox;
                if(range.r1 === range.r2 || bVertical === true)
                {
                    row_hidden = source_worksheet.getRowHidden(range.r1);
                    for(j = range.c1;  j <= range.c2; ++j)
                    {
                        if(!row_hidden && !source_worksheet.getColHidden(j))
                        {
                            cell = source_worksheet.getCell3(range.r1, j);
                            value_width_format = cell.getValueWithFormat();
                            if(typeof value_width_format === "string" && value_width_format.length > 0)
                            {
                                pt = new AscFormat.CStringPoint();
                                pt.setIdx(pt_index);
                                pt.setVal(value_width_format);

                                if(str_cache.pts.length === 0){
                                    pt.formatCode = cell.getNumFormatStr()
                                }
                                str_cache.addPt(pt);
                                //addPointToMap(oThis.pointsMap, source_worksheet, range.r1, j, pt);
                            }
                            ++nPtCount;
                        }
                        pt_index++;
                    }
                }
                else
                {
                    col_hidden = source_worksheet.getColHidden(range.c1);
                    for(j = range.r1;  j <= range.r2; ++j)
                    {
                        if(!col_hidden && !source_worksheet.getRowHidden(j))
                        {
                            cell = source_worksheet.getCell3(j, range.c1);
                            value_width_format = cell.getValueWithFormat();
                            if(typeof value_width_format === "string" && value_width_format.length > 0)
                            {
                                pt = new AscFormat.CStringPoint();
                                pt.setIdx(pt_index);
                                pt.setVal(cell.getValueWithFormat());

                                if(str_cache.pts.length === 0){
                                    pt.formatCode = cell.getNumFormatStr()
                                }
                                str_cache.addPt(pt);
                                //addPointToMap(oThis.pointsMap, source_worksheet, j, range.c1,  pt);
                            }
                            ++nPtCount;
                        }
                        pt_index++;
                    }
                }
            }
            else{
                fParseTableDataString(oCurRef);
            }
        }
        str_cache.setPtCount(nPtCount);
        cat.strRef.setStrCache(str_cache);
    }
};

CChartSpace.prototype.recalculateReferences = function()
{
    var worksheet = this.worksheet;
    //this.pointsMap = {};
    if(!worksheet)
        return;

    if(this.recalcInfo.recalculateBBox)
    {
        this.recalculateBBox();
        this.recalcInfo.recalculateBBox = false;
    }



    var charts, series, i, j, ser;
    charts = this.chart.plotArea.charts;
    var bVert = undefined;
    if(this.bbox && this.bbox.seriesBBox && AscFormat.isRealBool(this.bbox.seriesBBox.bVert))
    {
        bVert = this.bbox.seriesBBox.bVert;
    }
    for(i = 0; i < charts.length; ++i)
    {
        series = charts[i].series;
        var bHaveHidden = false, bHaveNoHidden = false;
        var bCheckFormatCode = false;
        if(charts[i].getObjectType() !== AscDFH.historyitem_type_ScatterChart)
        {
            for(j = 0; j < series.length; ++j)
            {
                ser = series[j];
                //val
                this.checkValByNumRef(this.worksheet.workbook, ser, ser.val);
                //cat
                this.checkValByNumRef(this.worksheet.workbook, ser, ser.cat, bVert);
                this.checkCatByNumRef(this, ser, ser.cat, bVert);
                //tx
                this.checkCatByNumRef(this, ser, ser.tx, AscFormat.isRealBool(bVert) ? !bVert : undefined);

                if(ser.isHidden)
                {
                    bHaveHidden = true;
                }
                else
                {
                    bHaveNoHidden = true;
                }

            }
        }
        else
        {
            for(j = 0; j < series.length; ++j)
            {
                ser = series[j];
                this.checkValByNumRef(this.worksheet.workbook, ser, ser.xVal, bVert);
                this.checkValByNumRef(this.worksheet.workbook, ser, ser.yVal);
                this.checkCatByNumRef(this, ser, ser.tx, AscFormat.isRealBool(bVert) ? !bVert : undefined);
                this.checkCatByNumRef(this, ser, ser.xVal, bVert);

                if(ser.isHidden)
                {
                    bHaveHidden = true;
                }
                else
                {
                    bHaveNoHidden = true;
                }
            }
        }




        // if(bHaveHidden && bHaveNoHidden)
        // {
        //     for(j = 0; j < series.length; ++j)
        //     {
        //         series[j].isHidden = false;
        //     }
        // }
    }

    var aTitles = this.getAllTitles();
    for(i = 0; i < aTitles.length; ++i){
        var oTitle = aTitles[i];
        this.checkCatByNumRef(this, oTitle, oTitle.tx, undefined);
    }
    var aAxis = this.chart.plotArea.axId;
    for(i = 0; i < aAxis.length; ++i){
        var oAxis = aAxis[i];
        if(oAxis.getObjectType() === AscDFH.historyitem_type_ValAx){
            var aCharts = this.chart.plotArea.getChartsForAxis(oAxis);
            for(j = 0; j < aCharts.length; ++j){
                var oChart = aCharts[j];
                if((oChart.getObjectType() === AscDFH.historyitem_type_BarChart && oChart.grouping === AscFormat.BAR_GROUPING_PERCENT_STACKED)
                    || (oChart.getObjectType() !== AscDFH.historyitem_type_BarChart && oChart.grouping === AscFormat.GROUPING_PERCENT_STACKED)
                    || (oChart.getObjectType() === AscDFH.historyitem_type_ScatterChart)){
                    break;
                }
            }
            if(j === aCharts.length){
                if(oAxis.numFmt && oAxis.numFmt.sourceLinked){
                    var aPoints = AscFormat.getPtsFromSeries(ser);
                    if(aPoints[0] && typeof aPoints[0].formatCode === "string" && aPoints[0].formatCode.length > 0){
                        oAxis.numFmt.setFormatCode(aPoints[0].formatCode);
                    }
                    else{
                        if(oAxis.numFmt.formatCode === null || oAxis.numFmt.formatCode === ""){
                            oAxis.numFmt.setFormatCode("General");
                        }
                    }
                }
            }
        }
    }
};

    CChartSpace.prototype.checkEmptyVal = function(val)
    {
        if(val.numRef)
        {
            if(!val.numRef.numCache)
                return true;
            if(val.numRef.numCache.pts.length === 0)
                return true;
        }
        else if(val.numLit)
        {
            if(val.numLit.pts.length === 0)
                return true;
        }
        else
        {
            return true;
        }
        return false;
    };

    CChartSpace.prototype.isEmptySeries = function(series, nSeriesLength){
        for(var i = 0; i < series.length && i < nSeriesLength; ++i){
            var ser = series[i];
            if(ser.val)
            {
                if(!this.checkEmptyVal(ser.val))
                    return false;
            }
            if(ser.yVal)
            {
                if(!this.checkEmptyVal(ser.yVal))
                    return false;
            }
        }
        return true;
    };

CChartSpace.prototype.checkEmptySeries = function()
{
    for(var t = 0; t < this.chart.plotArea.charts.length; ++t){
        var chart_type = this.chart.plotArea.charts[t];
        var series = chart_type.series;
        var nChartType = chart_type.getObjectType();
        var nSeriesLength = (nChartType === AscDFH.historyitem_type_PieChart || nChartType === AscDFH.historyitem_type_DoughnutChart) && this.chart.plotArea.charts.length === 1 ? Math.min(1, series.length) : series.length;
        if(this.isEmptySeries(series, nSeriesLength)){
            return true;
        }
    }
    return t < 1;
};

CChartSpace.prototype.getNeedReflect = function()
{
    if(!this.chartObj)
    {
        this.chartObj = new AscFormat.CChartsDrawer();
    }
    return this.chartObj.calculatePositionLabelsCatAxFromAngle(this);
};

CChartSpace.prototype.isChart3D = function(oChart){
    var oOldFirstChart = this.chart.plotArea.charts[0];
    this.chart.plotArea.charts[0] = oChart;
    var ret = AscFormat.CChartsDrawer.prototype._isSwitchCurrent3DChart(this);
    this.chart.plotArea.charts[0] = oOldFirstChart;
    return ret;
};

CChartSpace.prototype.getAxisCrossType = function(oAxis){
    if(oAxis.getObjectType() === AscDFH.historyitem_type_ValAx){
        return AscFormat.CROSS_BETWEEN_MID_CAT;
    }
    var oCrossAxis = oAxis.crossAx;
    if(oCrossAxis && oCrossAxis.getObjectType() === AscDFH.historyitem_type_ValAx){
        var oChart = this.chart.plotArea.getChartsForAxis(oCrossAxis)[0];
        if(oChart){
            var nChartType = oChart.getObjectType();
            if(nChartType === AscDFH.historyitem_type_ScatterChart){
                return null;
            }
            else if(nChartType !== AscDFH.historyitem_type_BarChart && (nChartType !== AscDFH.historyitem_type_PieChart && nChartType !== AscDFH.historyitem_type_DoughnutChart)
                || (nChartType === AscDFH.historyitem_type_BarChart && oChart.barDir !== AscFormat.BAR_DIR_BAR)){
                if(oCrossAxis){
                    if(this.isChart3D(oChart)){
                        if(nChartType === AscDFH.historyitem_type_AreaChart || nChartType === AscDFH.historyitem_type_SurfaceChart ){
                            return AscFormat.isRealNumber(oCrossAxis.crossBetween) ? oCrossAxis.crossBetween : AscFormat.CROSS_BETWEEN_MID_CAT;
                        }
                        else if(nChartType === AscDFH.historyitem_type_LineChart){
                            return AscFormat.isRealNumber(oCrossAxis.crossBetween) ? oCrossAxis.crossBetween : AscFormat.CROSS_BETWEEN_BETWEEN;
                        }
                        else{
                            return AscFormat.CROSS_BETWEEN_BETWEEN;
                        }
                    }
                    else{
                        return AscFormat.isRealNumber(oCrossAxis.crossBetween) ? oCrossAxis.crossBetween :  ((nChartType === AscDFH.historyitem_type_AreaChart|| nChartType === AscDFH.historyitem_type_SurfaceChart ) ? AscFormat.CROSS_BETWEEN_MID_CAT : AscFormat.CROSS_BETWEEN_BETWEEN);
                    }
                }
            }
            else if(nChartType === AscDFH.historyitem_type_BarChart && oChart.barDir === AscFormat.BAR_DIR_BAR){
                return AscFormat.isRealNumber(oCrossAxis.crossBetween) && !this.isChart3D(oChart) ? oCrossAxis.crossBetween : AscFormat.CROSS_BETWEEN_BETWEEN;
            }
        }
    }
    switch(oAxis.getObjectType()){
        case AscDFH.historyitem_type_ValAx:{
            return AscFormat.CROSS_BETWEEN_MID_CAT;
        }
        case AscDFH.historyitem_type_CatAx:
        case AscDFH.historyitem_type_DateAx:{
            return AscFormat.CROSS_BETWEEN_BETWEEN;
        }
        default:{
            return AscFormat.CROSS_BETWEEN_BETWEEN;
        }
    }
    return AscFormat.CROSS_BETWEEN_BETWEEN;
};

CChartSpace.prototype.getValAxisCrossType = function()
{
    if(this.chart && this.chart.plotArea && this.chart.plotArea.charts[0]){
        var chartType = this.chart.plotArea.charts[0].getObjectType();
        var valAx = this.chart.plotArea.valAx;
        if(chartType === AscDFH.historyitem_type_ScatterChart){
            return null;
        }
        else if(chartType !== AscDFH.historyitem_type_BarChart && (chartType !== AscDFH.historyitem_type_PieChart && chartType !== AscDFH.historyitem_type_DoughnutChart)
            || (chartType === AscDFH.historyitem_type_BarChart && this.chart.plotArea.charts[0].barDir !== AscFormat.BAR_DIR_BAR)){
            if(valAx){
                if(AscFormat.CChartsDrawer.prototype._isSwitchCurrent3DChart(this)){
                    if(chartType === AscDFH.historyitem_type_AreaChart || chartType === AscDFH.historyitem_type_SurfaceChart ){
                        return AscFormat.isRealNumber(valAx.crossBetween) ? valAx.crossBetween : AscFormat.CROSS_BETWEEN_MID_CAT;
                    }
                    else if(chartType === AscDFH.historyitem_type_LineChart){
                        return AscFormat.isRealNumber(valAx.crossBetween) ? valAx.crossBetween : AscFormat.CROSS_BETWEEN_BETWEEN;
                    }
                    else{
                        return AscFormat.CROSS_BETWEEN_BETWEEN;
                    }
                }
                else{
                    return AscFormat.isRealNumber(valAx.crossBetween) ? valAx.crossBetween :  ((chartType === AscDFH.historyitem_type_AreaChart|| chartType === AscDFH.historyitem_type_SurfaceChart ) ? AscFormat.CROSS_BETWEEN_MID_CAT : AscFormat.CROSS_BETWEEN_BETWEEN);
                }
            }
        }
        else if(chartType === AscDFH.historyitem_type_BarChart && this.chart.plotArea.charts[0].barDir === AscFormat.BAR_DIR_BAR){
            if(valAx){
                return AscFormat.isRealNumber(valAx.crossBetween) && !AscFormat.CChartsDrawer.prototype._isSwitchCurrent3DChart(this) ? valAx.crossBetween : AscFormat.CROSS_BETWEEN_BETWEEN;
            }
        }
    }
    return null;
};

    CChartSpace.prototype.calculatePosByLayout = function(fPos, nLayoutMode, fLayoutValue, fSize, fChartSize){
        if(!AscFormat.isRealNumber(fLayoutValue)){
            return fPos;
        }
        var fRetPos = 0;
        if(nLayoutMode === AscFormat.LAYOUT_MODE_EDGE){
            fRetPos = fChartSize*fLayoutValue;
        }
        else{
            fRetPos = fPos + fChartSize*fLayoutValue;
        }
        if(fRetPos < 0){
            fRetPos = 0;
        }
        return fRetPos;
    };
    CChartSpace.prototype.calculateSizeByLayout = function(fPos, fChartSize, fLayoutSize, fSizeMode ){
        if(!AscFormat.isRealNumber(fLayoutSize)){
            return -1;
        }
        var fRetSize = Math.min(fChartSize*fLayoutSize, fChartSize);
        if(fSizeMode === AscFormat.LAYOUT_MODE_EDGE){
            fRetSize = fRetSize - fPos;
        }
        return fRetSize;
    };

    CChartSpace.prototype.calculateLabelsPositions = function(b_recalc_labels, b_recalc_legend)
    {
        var layout;
        for(var i = 0; i < this.recalcInfo.dataLbls.length; ++i)
        {
            var series = this.getAllSeries();
            if(this.recalcInfo.dataLbls[i].series && this.recalcInfo.dataLbls[i].pt)
            {

                var ser_idx = this.recalcInfo.dataLbls[i].series.idx; //сделаем проверку лежит ли серия с индексом this.recalcInfo.dataLbls[i].series.idx в сериях первой диаграммы
                for(var j = 0;  j < series.length; ++j)
                {
                    if(series[j].idx === this.recalcInfo.dataLbls[i].series.idx)
                    {
                        var bLayout = AscCommon.isRealObject(this.recalcInfo.dataLbls[i].layout) && (AscFormat.isRealNumber(this.recalcInfo.dataLbls[i].layout.x) || AscFormat.isRealNumber(this.recalcInfo.dataLbls[i].layout.y));
                        var pos = this.chartObj.recalculatePositionText(this.recalcInfo.dataLbls[i]);
                        var oLbl = this.recalcInfo.dataLbls[i];
                        if(oLbl.layout){
                            layout = oLbl.layout;
                            if(AscFormat.isRealNumber(layout.x)){
                                pos.x = this.calculatePosByLayout(pos.x, layout.xMode, layout.x, this.recalcInfo.dataLbls[i].extX, this.extX);
                            }
                            if(AscFormat.isRealNumber(layout.y)){
                                pos.y = this.calculatePosByLayout(pos.y, layout.yMode, layout.y, this.recalcInfo.dataLbls[i].extY, this.extY);
                            }
                        }
                        if(pos.x + oLbl.extX > this.extX){
                            pos.x -= (pos.x + oLbl.extX - this.extX);
                        }
                        if(pos.y + oLbl.extY > this.extY){
                            pos.y -= (pos.y + oLbl.extY - this.extY);
                        }
                        if(pos.x < 0){
                            pos.x = 0;
                        }
                        if(pos.y < 0){
                            pos.y = 0;
                        }
                        oLbl.setPosition(pos.x, pos.y);
                        break;
                    }
                }
            }
        }
        this.recalcInfo.dataLbls.length = 0;

        if(b_recalc_labels)
        {
            if(this.chart && this.chart.title)
            {
                var pos = this.chartObj.recalculatePositionText(this.chart.title);
                if(this.chart.title.layout){
                    layout = this.chart.title.layout;
                    if(AscFormat.isRealNumber(layout.x)){
                        pos.x = this.calculatePosByLayout(pos.x, layout.xMode, layout.x, this.chart.title.extX, this.extX);
                    }if(AscFormat.isRealNumber(layout.y)){
                        pos.y = this.calculatePosByLayout(pos.y, layout.yMode, layout.y, this.chart.title.extY, this.extY);
                    }
                }
                this.chart.title.setPosition(pos.x, pos.y);
            }

            if(this.chart && this.chart.plotArea)
            {
                var aAxes = this.chart.plotArea.axId;
                for(var i = 0; i < aAxes.length; ++i){
                    var oAxis = aAxes[i];
                    if(oAxis && oAxis.title)
                    {
                        var pos = this.chartObj.recalculatePositionText(oAxis);

                        if(oAxis.title.layout){
                            layout = oAxis.title.layout;
                            if(AscFormat.isRealNumber(layout.x)){
                                pos.x = this.calculatePosByLayout(pos.x, layout.xMode, layout.x, oAxis.title.extX, this.extX);
                            }if(AscFormat.isRealNumber(layout.y)){
                                pos.y = this.calculatePosByLayout(pos.y, layout.yMode, layout.y, oAxis.title.extY, this.extY);
                            }
                        }
                        oAxis.title.setPosition(pos.x, pos.y);
                    }
                }


            }
        }

        if(b_recalc_legend && this.chart && this.chart.legend)
        {
            var bResetLegendPos = false;
            if(!AscFormat.isRealNumber(this.chart.legend.legendPos))
            {
                this.chart.legend.legendPos = Asc.c_oAscChartLegendShowSettings.bottom;
                bResetLegendPos = true;
            }
            var pos = this.chartObj.recalculatePositionText(this.chart.legend);
            if(this.chart.legend.layout){
                layout = this.chart.legend.layout;
                if(AscFormat.isRealNumber(layout.x)){
                    pos.x = this.calculatePosByLayout(pos.x, layout.xMode, layout.x, this.chart.legend.extX, this.extX);
                }if(AscFormat.isRealNumber(layout.y)){
                    pos.y = this.calculatePosByLayout(pos.y, layout.yMode, layout.y, this.chart.legend.extY, this.extY);
                }
            }
            this.chart.legend.setPosition(pos.x, pos.y);
            if(bResetLegendPos)
            {
                this.chart.legend.legendPos = null;
            }
        }
    };


    CChartSpace.prototype.getLabelsForAxis = function(oAxis){
        var aStrings = [];
        var oPlotArea = this.chart.plotArea, i;
        var nAxisType = oAxis.getObjectType();
        var oSeries = oPlotArea.getSeriesWithSmallestIndexForAxis(oAxis);
        switch(nAxisType){
            case AscDFH.historyitem_type_DateAx:
            case AscDFH.historyitem_type_CatAx:{
                //расчитаем подписи для горизонтальной оси
                var nPtsLen = 0;
                var aScale = [];
                if(Array.isArray(oAxis.scale)){
                    aScale = aScale.concat(oAxis.scale);

                }
                if(oSeries && oSeries.cat) {
                    var  oLit;
                    var oCat = oSeries.cat;
                    if(oCat.strRef && oCat.strRef.strCache){
                        oLit = oCat.strRef.strCache;
                    }
                    else if(oCat.strLit){
                        oLit = oCat.strLit;
                    }
                    else if(oCat.numRef && oCat.numRef.numCache){
                        oLit = oCat.numRef.numCache;
                    }
                    else if(oCat.numLit){
                        oLit = oCat.numLit;
                    }
                    if(oLit){
                        var oLitFormat = null, oPtFormat = null;
                        if(typeof oLit.formatCode === "string" && oLit.formatCode.length > 0){
                            oLitFormat = oNumFormatCache.get(oLit.formatCode);
                        }
                        if(/*nAxisType === AscDFH.historyitem_type_DateAx && */oAxis.numFmt && typeof oAxis.numFmt.formatCode === "string" && oAxis.numFmt.formatCode.length > 0){
                            oLitFormat = oNumFormatCache.get(oAxis.numFmt.formatCode);
                        }
                        nPtsLen = oLit.ptCount;

                        var bTickSkip =  AscFormat.isRealNumber(oAxis.tickLblSkip);
                        var nTickLblSkip = AscFormat.isRealNumber(oAxis.tickLblSkip) ? oAxis.tickLblSkip : 1;
                        for(i = 0; i < nPtsLen; ++i){
                            if(!bTickSkip || ((i % nTickLblSkip) === 0)){
                                var oPt = oLit.getPtByIndex(i);
                                if(oPt){
                                    var sPt;
                                    if(typeof oPt.formatCode === "string" && oPt.formatCode.length > 0){
                                        oPtFormat = oNumFormatCache.get(oPt.formatCode);
                                        if(oPtFormat){
                                            sPt = oPtFormat.formatToChart(oPt.val);
                                        }
                                        else{
                                            sPt = oPt.val + "";
                                        }
                                    }
                                    else if(oLitFormat){
                                        sPt = oLitFormat.formatToChart(oPt.val);
                                    }
                                    else{
                                        sPt = oPt.val + "";
                                    }
                                    aStrings.push(sPt);
                                }
                                else{
                                    aStrings.push("");
                                }
                            }
                            else{
                                aStrings.push(null);
                            }
                        }
                    }
                }


                var nPtsLength = 0;
                var aChartsForAxis = oPlotArea.getChartsForAxis(oAxis);
                for(i = 0; i < aChartsForAxis.length; ++i){
                    var oChart = aChartsForAxis[i];
                    for(var j = 0; j < oChart.series.length; ++j){
                        var oCurPts = null;
                        oSeries = oChart.series[j];
                        if(oSeries.val) {
                            if(oSeries.val.numRef && oSeries.val.numRef.numCache){
                                oCurPts = oSeries.val.numRef.numCache;
                            }
                            else if(oSeries.val.numLit){
                                oCurPts = oSeries.val.numLit;
                            }
                            if(oCurPts){
                                nPtsLength = Math.max(nPtsLength, oCurPts.ptCount);
                            }
                        }
                    }
                }
                var nCrossBetween = this.getAxisCrossType(oAxis);
                if(nCrossBetween === AscFormat.CROSS_BETWEEN_MID_CAT && nPtsLength < 2){
                    nPtsLength = 2;
                }
                var oLitFormatDate = null;
                if(nAxisType === AscDFH.historyitem_type_DateAx && oAxis.numFmt && typeof oAxis.numFmt.formatCode === "string" && oAxis.numFmt.formatCode.length > 0){
                    oLitFormatDate = oNumFormatCache.get(oAxis.numFmt.formatCode);
                }

                if(nPtsLength > aStrings.length){
                    for(i = aStrings.length; i < nPtsLength; ++i){
                        if(oLitFormatDate){
                            aStrings.push(oLitFormatDate.formatToChart(i + 1));
                        }
                        else{
                            aStrings.push(i + 1 + "");
                        }
                    }
                }
                else{
                    aStrings.splice(nPtsLength, aStrings.length - nPtsLength);
                }
                if(aScale.length > 0){
                    while(aStrings.length < aScale[aScale.length - 1]){
                        aStrings.push("");
                    }
                    for(i = 0; i < aScale.length; ++i){
                        if(aScale[i] > 0){
                            break;
                        }
                        aStrings.splice(0, 0, "");
                    }
                }

                break;
            }
            case AscDFH.historyitem_type_ValAx:{
                var aVal =  [].concat(oAxis.scale);
                var fMultiplier;
                if(oAxis.dispUnits){
                    fMultiplier = oAxis.dispUnits.getMultiplier();
                }
                else{
                    fMultiplier = 1.0;
                }
                var oNumFmt = oAxis.numFmt;
                var oNumFormat = null;
                if(oNumFmt && typeof oNumFmt.formatCode === "string"){
                    oNumFormat = oNumFormatCache.get(oNumFmt.formatCode);
                }
                else{
                    if(oSeries && oSeries.xVal){
                        var strCache = oSeries.xVal.strRef && oSeries.xVal.strRef.strCache;
                        if(strCache && strCache.pts[0] && typeof strCache.pts[0].formatCode === "string"){
                            oNumFormat = oNumFormatCache.get(strCache.pts[0].formatCode);
                        }
                    }
                }
                for(var t = 0; t < aVal.length; ++t){
                    var fCalcValue = aVal[t]*fMultiplier;
                    var sRichValue;
                    if(oNumFormat){
                        sRichValue = oNumFormat.formatToChart(fCalcValue);
                    }
                    else{
                        sRichValue = fCalcValue + "";
                    }
                    aStrings.push(sRichValue);
                }

                break;
            }
            case AscDFH.historyitem_type_SerAx:{
                break;
            }
        }
        return aStrings;
    };

    CChartSpace.prototype.calculateAxisGrid = function(oAxis, oRect){
        if(!oAxis){
            return;
        }
        var oAxisGrid = new CAxisGrid();
        oAxis.grid = oAxisGrid;

       // oAxis.nType = 0;//0 - horizontal, 1 - vertical, 2 - series axis
        var nOrientation = oAxis.scaling && AscFormat.isRealNumber(oAxis.scaling.orientation) ?  oAxis.scaling.orientation : AscFormat.ORIENTATION_MIN_MAX;
        var aStrings = this.getLabelsForAxis(oAxis);
        var nCrossType = this.getAxisCrossType(oAxis);
        var bOnTickMark = ((nCrossType === AscFormat.CROSS_BETWEEN_MID_CAT) && (aStrings.length > 1));
        var nIntervalsCount =  bOnTickMark ? (aStrings.length - 1) : (aStrings.length);
        var fInterval;
        oAxisGrid.nCount = nIntervalsCount;
        oAxisGrid.bOnTickMark = bOnTickMark;
        oAxisGrid.aStrings = aStrings;
        if(oAxis.axPos === AscFormat.AX_POS_B || oAxis.axPos === AscFormat.AX_POS_T){

            oAxisGrid.nType = 0;
            fInterval = oRect.w/nIntervalsCount;
            if(nOrientation === AscFormat.ORIENTATION_MIN_MAX){
                oAxisGrid.fStart = oRect.x;
                oAxisGrid.fStride = fInterval;
            }
            else{
                oAxisGrid.fStart = oRect.x + oRect.w;
                oAxisGrid.fStride = -fInterval;
            }
        }
        else{
            oAxis.yPoints =[];
            oAxisGrid.nType = 1;
            fInterval = oRect.h/nIntervalsCount;
            if(nOrientation === AscFormat.ORIENTATION_MIN_MAX){
                oAxisGrid.fStart = oRect.y + oRect.h;
                oAxisGrid.fStride = -fInterval;
            }
            else{
                oAxisGrid.fStart = oRect.y;
                oAxisGrid.fStride = fInterval;
            }
        }
    };

    CChartSpace.prototype.recalculateAxesSet = function (aAxesSet, oRect, oBaseRect, nIndex, fForceContentWidth) {
        var oCorrectedRect = null;

        var bWithoutLabels = false;
        if(this.chart.plotArea.layout && this.chart.plotArea.layout.layoutTarget === AscFormat.LAYOUT_TARGET_INNER){
            bWithoutLabels = true;
        }
        var bCorrected = false;
        var fL = oRect.x, fT = oRect.y, fR = oRect.x + oRect.w, fB = oRect.y + oRect.h;
        var fHorPadding = 0.0;
        var fVertPadding = 0.0;
        var fHorInterval = null;
        var oCalcMap = {};
        for(var i = 0; i < aAxesSet.length; ++i){
            var oCurAxis = aAxesSet[i];
            var oCrossAxis = oCurAxis.crossAx;
            if(!oCalcMap[oCurAxis.Id]){
                this.calculateAxisGrid(oCurAxis, oRect);
                oCalcMap[oCurAxis.Id] = true;
            }
            if(!oCalcMap[oCrossAxis.Id]){
                this.calculateAxisGrid(oCrossAxis, oRect);
                oCalcMap[oCrossAxis.Id] = true;
            }
            var fCrossValue;
            var fAxisPos;
            var fDistance = 10.0*(25.4/72);///TODO
            var nLabelsPos;
            var bLabelsExtremePosition = false;
            var bOnTickMark = oCurAxis.grid.bOnTickMark;
            if(oCurAxis.bDelete){
                nLabelsPos = c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE;
            }
            else{
                if(null !== oCurAxis.tickLblPos){
                    nLabelsPos = oCurAxis.tickLblPos;
                }
                else{
                    nLabelsPos = c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO;
                }
            }

            var bCrossAt = false;

            var oCrossGrid = oCrossAxis.grid;
            if(AscFormat.isRealNumber(oCurAxis.crossesAt) && oCrossAxis.scale[0] <= oCurAxis.crossesAt && oCrossAxis.scale[oCrossAxis.scale.length - 1] >= oCurAxis.crossesAt){

                if(oCrossAxis.getObjectType() === AscDFH.historyitem_type_ValAx){
                    fCrossValue = oCurAxis.crossesAt;
                }
                else{
                    fCrossValue = oCurAxis.crossesAt - 1;
                }

                bCrossAt = true;
            }
            else{
                switch (oCurAxis.crosses) {
                    case AscFormat.CROSSES_MAX:{
                        fCrossValue = oCrossAxis.scale[oCrossAxis.scale.length - 1];
                        if(!oCrossGrid.bOnTickMark){
                            fCrossValue += 1;
                        }
                        if(nLabelsPos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO){
                            fDistance = -fDistance;
                            bLabelsExtremePosition = true;
                        }
                        break;
                    }
                    case AscFormat.CROSSES_MIN:{
                        fCrossValue = oCrossAxis.scale[0];
                        if(nLabelsPos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO){
                            bLabelsExtremePosition = true;
                        }
                        if(!oCrossGrid.bOnTickMark){
                            fCrossValue -= 1;
                        }
                    }
                    default:{ //includes AutoZero
                        if(oCrossAxis.scale[0] <=0 && oCrossAxis.scale[oCrossAxis.scale.length - 1] >= 0){
                            fCrossValue = 0;
                        }
                        else if(oCrossAxis.scale[0] > 0){
                            fCrossValue = oCrossAxis.scale[0];
                        }
                        else{
                            fCrossValue = oCrossAxis.scale[oCrossAxis.scale.length - 1];
                        }
                    }
                }
            }

            if(AscFormat.fApproxEqual(fCrossValue, oCrossAxis.scale[0]) || AscFormat.fApproxEqual(fCrossValue, oCrossAxis.scale[oCrossAxis.scale.length - 1])){
                bLabelsExtremePosition = true;
            }
            var fTickAdd = 0.0;
            // if(!oCrossGrid.bOnTickMark && bCrossAt){
            //     fTickAdd = 1.0;
            // }
            // if(oCrossGrid.bOnTickMark){
            var bKoeff = 1.0;
            if(oCrossAxis.scale.length > 1){
                bKoeff = oCrossAxis.scale[1] - oCrossAxis.scale[0];
            }
                fAxisPos = oCrossGrid.fStart + (fCrossValue - oCrossAxis.scale[0])*(oCrossGrid.fStride)/bKoeff;
            // }
            // else{
            //     fAxisPos = oCrossGrid.fStart + (fCrossValue + 1 - oCrossAxis.scale[0])*(oCrossGrid.fStride)/(oCrossAxis.scale[1] - oCrossAxis.scale[0]);
            // }


            var nOrientation = isRealObject(oCrossAxis.scaling) && AscFormat.isRealNumber(oCrossAxis.scaling.orientation) ? oCrossAxis.scaling.orientation : AscFormat.ORIENTATION_MIN_MAX;
            if(nOrientation === AscFormat.ORIENTATION_MAX_MIN){
                fDistance = -fDistance;
            }
            var oLabelsBox = null, fPos;
            var fPosStart = oCurAxis.grid.fStart;
            var fPosEnd = oCurAxis.grid.fStart + oCurAxis.grid.nCount*oCurAxis.grid.fStride;

            var bForceVertical = false;
            var bNumbers = false;//TODO

            if(nLabelsPos !== c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE){
                oLabelsBox = new CLabelsBox(oCurAxis.grid.aStrings, oCurAxis, this);
                switch(nLabelsPos){
                    case c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO:{
                        fPos = fAxisPos;
                        break;
                    }
                    case c_oAscTickLabelsPos.TICK_LABEL_POSITION_HIGH:{
                        fPos = oCrossGrid.fStart + oCrossGrid.nCount*oCrossGrid.fStride;
                        fDistance = - fDistance;
                        break;
                    }
                    case c_oAscTickLabelsPos.TICK_LABEL_POSITION_LOW:{
                        fPos = oCrossGrid.fStart;
                        break;
                    }
                }
            }


            oCurAxis.labels = oLabelsBox;
            oCurAxis.posX  = null;
            oCurAxis.posY  = null;
            oCurAxis.xPoints = null;
            oCurAxis.yPoints = null;
            var aPoints = null;
            if(oCurAxis.getObjectType() === AscDFH.historyitem_type_SerAx){
                //TODO
            }
            else if(oCurAxis.axPos === AscFormat.AX_POS_B || oCurAxis.axPos === AscFormat.AX_POS_T){
                oCurAxis.posY  = fAxisPos;
                oCurAxis.xPoints = [];
                aPoints = oCurAxis.xPoints;
                if(oLabelsBox){
                    if(!AscFormat.fApproxEqual(oRect.fVertPadding, 0)){
                        fPos -= oRect.fVertPadding;
                        if(nLabelsPos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO){
                            oCurAxis.posY -= oRect.fVertPadding;
                        }
                    }


                    var bTickSkip = AscFormat.isRealNumber(oCurAxis.tickLblSkip);
                    var nTickLblSkip = AscFormat.isRealNumber(oCurAxis.tickLblSkip) ? oCurAxis.tickLblSkip :  1;

                    var fAxisLength = fPosEnd - fPosStart;
                    var nLabelsCount = oLabelsBox.aLabels.length;

                    var bOnTickMark_ = bOnTickMark && nLabelsCount > 1;
                    var nIntervalCount = bOnTickMark_ ? nLabelsCount - 1 : nLabelsCount;
                    fHorInterval = Math.abs(fAxisLength/nIntervalCount);
                    if(bTickSkip && !AscFormat.isRealNumber(fForceContentWidth)){
                        fForceContentWidth = Math.abs(fHorInterval) +  fHorInterval/nTickLblSkip;
                    }


                    if(AscFormat.isRealNumber(oCurAxis.lblOffset)){
                        var fStakeOffset = oCurAxis.lblOffset/100.0;
                        var oFirstTextPr = null;
                        for(var tt = 0; tt < oLabelsBox.aLabels.length; ++tt){
                            var oLbl = oLabelsBox.aLabels[tt];
                            if(oLbl && oLbl.tx && oLbl.tx.rich && oLbl.tx.rich.content && oLbl.tx.rich.content.Content[0]){
                                oFirstTextPr = oLbl.tx.rich.content.Content[0].Get_FirstTextPr2();
                                break;
                            }
                        }
                        if(oFirstTextPr && AscFormat.isRealNumber(oFirstTextPr.FontSize)){
                            fDistance = fStakeOffset*oFirstTextPr.FontSize*fDistance/10.0;
                        }
                    }


                    fLayoutHorLabelsBox(oLabelsBox, fPos, fPosStart, fPosEnd, bOnTickMark, fDistance, bForceVertical, bNumbers, fForceContentWidth);


                    if(bLabelsExtremePosition){
                        if(fDistance > 0){
                            fVertPadding = -oLabelsBox.extY;
                        }
                        else{
                            fVertPadding = oLabelsBox.extY;
                        }
                    }
                }
            }
            else{//vertical axis
                fDistance = -fDistance;
                oCurAxis.posX  = fAxisPos;
                oCurAxis.yPoints = [];
                aPoints = oCurAxis.yPoints;
                if(oLabelsBox){
                    if(!AscFormat.fApproxEqual(oRect.fHorPadding, 0)){
                        fPos -= oRect.fHorPadding;
                        if(nLabelsPos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO){
                            oCurAxis.posX -= oRect.fHorPadding;
                        }
                    }
                    fLayoutVertLabelsBox(oLabelsBox, fPos, fPosStart, fPosEnd, bOnTickMark, fDistance, bForceVertical);
                    if(bLabelsExtremePosition){
                        if(fDistance > 0){
                            fHorPadding = -oLabelsBox.extX;
                        }
                        else{
                            fHorPadding = oLabelsBox.extX;
                        }
                    }
                }
            }
            if(null !== aPoints){
                var fStartSeriesPos = 0.0;
                if(!bOnTickMark){
                    fStartSeriesPos = oCurAxis.grid.fStride/2.0;
                }
                for(var j = 0; j < oCurAxis.grid.aStrings.length; ++j){
                    aPoints.push({val: oCurAxis.scale[j], pos: oCurAxis.grid.fStart + j*oCurAxis.grid.fStride + fStartSeriesPos})
                }
            }
            if(oLabelsBox){
                if(oLabelsBox.x < fL){
                    fL = oLabelsBox.x;
                }
                if(oLabelsBox.x + oLabelsBox.extX > fR){
                    fR = oLabelsBox.x + oLabelsBox.extX;
                }
                if(oLabelsBox.y < fT){
                    fT = oLabelsBox.y;
                }
                if(oLabelsBox.y + oLabelsBox.extY > fB){
                    fB = oLabelsBox.y + oLabelsBox.extY;
                }
            }
        }
        // function CAxisGrid(){
        //     this.nType = 0;//0 - horizontal, 1 - vertical, 2 - series axis
        //     this.fStart = 0.0;
        //     this.fStride = 0.0;
        //     this.nCount = 0;
        // }
        if(nIndex < 2){
            var fDiff;
            var fPrecision = 0.01;
            oCorrectedRect = new CRect(oRect.x, oRect.y, oRect.w, oRect.h);
            if(bWithoutLabels){
                fDiff = fL;
                if(fDiff < 0.0 && !AscFormat.fApproxEqual(fDiff, 0.0, fPrecision)){
                    oCorrectedRect.x -= fDiff;
                    //oCorrectedRect.w -= fDiff;
                    bCorrected = true;
                }
                fDiff = fR - this.extX;
                if(fDiff > 0.0 && !AscFormat.fApproxEqual(fDiff, 0.0, fPrecision)){
                    oCorrectedRect.w -= fDiff;
                    bCorrected = true;
                }
                fDiff = fT;
                if( fDiff < 0.0 && !AscFormat.fApproxEqual(fDiff, 0.0, fPrecision)){
                    oCorrectedRect.y -= fDiff;
                    //oCorrectedRect.h -= fDiff;
                    bCorrected = true;
                }
                fDiff = fB - this.extY;
                if( fDiff > 0.0 &&  !AscFormat.fApproxEqual(fDiff, 0.0, fPrecision)){
                    oCorrectedRect.h -= (fB - this.extY);
                    bCorrected = true;
                }
            }
            else{
                fDiff = oBaseRect.x - fL;
                if(/*fDiff > 0.0 && */!AscFormat.fApproxEqual(fDiff, 0.0, fPrecision) ){
                    oCorrectedRect.x += fDiff;
                    oCorrectedRect.w -= fDiff;
                    bCorrected = true;
                }
                fDiff = oBaseRect.x + oBaseRect.w - fR;
                if(/*fDiff < 0.0 && */!AscFormat.fApproxEqual(fDiff, 0.0, fPrecision)){
                    oCorrectedRect.w += fDiff;
                    bCorrected = true;
                }
                fDiff = oBaseRect.y - fT;
                if(/*fDiff > 0.0 &&*/ !AscFormat.fApproxEqual(fDiff, 0.0, fPrecision)){
                    oCorrectedRect.y += fDiff;
                    oCorrectedRect.h -= fDiff;
                    bCorrected = true;
                }
                fDiff = oBaseRect.y + oBaseRect.h - fB;
                if(/*fDiff < 0.0 && */!AscFormat.fApproxEqual(fDiff, 0.0, fPrecision)){
                    oCorrectedRect.h += fDiff;
                    bCorrected = true;
                }
            }
            if(oCorrectedRect && bCorrected){
                if(oCorrectedRect.w > oRect.w){
                    return this.recalculateAxesSet(aAxesSet, oCorrectedRect, oBaseRect, ++nIndex, fHorInterval);
                }
                else{
                    return this.recalculateAxesSet(aAxesSet, oCorrectedRect, oBaseRect, ++nIndex);
                }
            }
        }
        var _ret = oRect.copy();
        _ret.fHorPadding = fHorPadding;
        _ret.fVertPadding = fVertPadding;
        return _ret;
    };


    CChartSpace.prototype.getReplaceAxis = function(oAxis){
        var aAxes = this.chart.plotArea.axId;
        if(oAxis.bDelete && oAxis.getObjectType() === AscDFH.historyitem_type_ValAx){
            var bHorizontal = (oAxis.axPos === AscFormat.AX_POS_T || oAxis.axPos === AscFormat.AX_POS_B);
            for(var j = 0; j < aAxes.length; ++j){
                var oCheckAxis = aAxes[j];
                if(!oCheckAxis.bDelete){
                    if(bHorizontal){
                        if(oCheckAxis.axPos === AscFormat.AX_POS_T || oCheckAxis.axPos === AscFormat.AX_POS_B){
                            if(!oAxis.crossAx || oAxis.crossAx && oCheckAxis.crossAx && oAxis.crossAx.getObjectType() === oCheckAxis.crossAx.getObjectType()){
                                return oCheckAxis;
                            }
                        }
                    }
                    else{
                        if(oCheckAxis.axPos === AscFormat.AX_POS_R || oCheckAxis.axPos === AscFormat.AX_POS_L){
                            if(!oAxis.crossAx || oAxis.crossAx && oCheckAxis.crossAx && oAxis.crossAx.getObjectType() === oCheckAxis.crossAx.getObjectType()){
                                return oCheckAxis;
                            }
                        }
                    }
                }
            }
        }
        return null;
    };

    CChartSpace.prototype.recalculateAxes = function(){
        this.plotAreaRect = null;
        this.bEmptySeries = this.checkEmptySeries();
        if(this.chart && this.chart.plotArea){

            var oPlotArea = this.chart.plotArea;
            for(i = 0; i < oPlotArea.axId.length; ++i){
                oCurAxis = oPlotArea.axId[i];
                oCurAxis.posY  = null;
                oCurAxis.posX  = null;
                oCurAxis.xPoints = null;
                oCurAxis.yPoints  = null;
            }
            if(this.bEmptySeries){
                return;
            }
            if(!this.chartObj){
                this.chartObj = new AscFormat.CChartsDrawer()
            }
            var i, j;
            var aCharts = this.chart.plotArea.charts, oChart;
            var oCurAxis, oCurAxis2, aCurAxesSet;
            //temporary add axes to charts with deleted axes
            var oChartsToAxesCount = {};
            var bAdd, nAxesCount;
            var oReplaceAxis;
            for(i = 0; i < aCharts.length; ++i){
                bAdd = false;
                oChart = aCharts[i];
                if(oChart.axId){
                    nAxesCount = oChart.axId.length;
                    for(j = nAxesCount - 1; j > -1; --j){
                        oCurAxis = oChart.axId[j];
                        oReplaceAxis = this.getReplaceAxis(oCurAxis);
                        if(oReplaceAxis){
                            bAdd = true;
                            oChart.axId.push(oReplaceAxis);
                        }
                    }
                    if(bAdd){
                        oChartsToAxesCount[oChart.Id] = nAxesCount;
                    }
                }
            }
            this.chartObj.preCalculateData(this);
            for(i in oChartsToAxesCount){
                if(oChartsToAxesCount.hasOwnProperty(i)){
                    oChart = AscCommon.g_oTableId.Get_ById(i);
                    if(oChart){
                        oChart.axId.length = oChartsToAxesCount[i]
                    }
                }
            }
            var aAxes = [].concat(oPlotArea.axId);
            var aAllAxes = [];//array of axes sets

            while(aAxes.length > 0){
                oCurAxis = aAxes.splice(0, 1)[0];
                aCurAxesSet = [];
                aCurAxesSet.push(oCurAxis);
                for(i = aAxes.length - 1; i > -1; --i){
                    oCurAxis2 = aAxes[i];
                    for(j = 0; j < aCurAxesSet.length; ++j){
                        if(aCurAxesSet[j].crossAx === oCurAxis2 || oCurAxis2.crossAx === aCurAxesSet[j]){
                            aCurAxesSet.push(oCurAxis2);
                        }
                    }
                }
                if(aCurAxesSet.length > 1){
                    aAllAxes.push(aCurAxesSet);
                }
            }


            var oSize = this.getChartSizes();
            var oRect = new CRect(oSize.startX, oSize.startY, oSize.w, oSize.h);
            var oBaseRect = oRect;
            var aRects = [];
            for(i = 0; i < aAllAxes.length; ++i){
                aCurAxesSet = aAllAxes[i];
                aRects.push(this.recalculateAxesSet(aCurAxesSet, oRect, oBaseRect, 0));
            }
            if(aRects.length > 1){


                oRect = aRects[0].copy();
                for(i = 1; i < aRects.length; ++i){
                    if(!oRect.intersection(aRects[i])){
                        break;
                    }
                }
                var fOldHorPadding = 0.0, fOldVertPadding = 0.0;
                if(i === aRects.length){
                    var aRects2 = [];
                    for(i = 0; i < aAllAxes.length; ++i){
                        aCurAxesSet = aAllAxes[i];
                        if(i === 0){
                            fOldHorPadding = oRect.fHorPadding;
                            fOldVertPadding = oRect.fVertPadding;
                            oRect.fHorPadding = 0.0;
                            oRect.fVertPadding = 0.0;
                        }
                        aRects2.push(this.recalculateAxesSet(aCurAxesSet, oRect, oBaseRect, 2));
                        if(i === 0){
                            oRect.fHorPadding = fOldHorPadding;
                            oRect.fVertPadding = fOldVertPadding;
                        }
                    }

                    var bCheckPaddings = false;
                    for(i = 0; i < aRects.length; ++i){
                        if(Math.abs(aRects2[i].fVertPadding) > Math.abs(aRects[i].fVertPadding)){
                            if(aRects2[i].fVertPadding > 0){
                                aRects[i].y += (aRects2[i].fVertPadding - aRects[i].fVertPadding);
                                aRects[i].h -= (aRects2[i].fVertPadding - aRects[i].fVertPadding);
                            }
                            else{
                                aRects[i].h -= Math.abs(aRects2[i].fVertPadding - aRects[i].fVertPadding);
                            }
                            aRects[i].fVertPadding = aRects2[i].fVertPadding;
                            bCheckPaddings = true;
                        }
                        if(Math.abs(aRects2[i].fHorPadding) > Math.abs(aRects[i].fHorPadding)){
                            if(aRects2[i].fHorPadding > 0){
                                aRects[i].x += (aRects2[i].fHorPadding - aRects[i].fHorPadding);
                                aRects[i].w -= (aRects2[i].fHorPadding - aRects[i].fHorPadding);
                            }
                            else{
                                aRects[i].w -= Math.abs(aRects2[i].fHorPadding - aRects[i].fHorPadding);
                            }
                            aRects[i].fHorPadding = aRects2[i].fHorPadding;
                            bCheckPaddings = true;
                        }
                    }
                    if(bCheckPaddings){
                        oRect = aRects[0].copy();
                        for(i = 1; i < aRects.length; ++i){
                            if(!oRect.intersection(aRects[i])){
                                break;
                            }
                        }
                        if(i === aRects.length){
                            var aRects2 = [];
                            for(i = 0; i < aAllAxes.length; ++i){
                                aCurAxesSet = aAllAxes[i];
                                if(i === 0){
                                    fOldHorPadding = oRect.fHorPadding;
                                    fOldVertPadding = oRect.fVertPadding;
                                    oRect.fHorPadding = 0.0;
                                    oRect.fVertPadding = 0.0;
                                }
                                aRects2.push(this.recalculateAxesSet(aCurAxesSet, oRect, oBaseRect, 2));
                                if(i === 0){
                                    oRect.fHorPadding = fOldHorPadding;
                                    oRect.fVertPadding = fOldVertPadding;
                                }
                            }
                        }
                    }
                }
                this.plotAreaRect = oRect.copy();
            }
            else{
                if(aRects[0]){
                    this.plotAreaRect = aRects[0].copy();
                }
            }
            aAxes = oPlotArea.axId;
            var oCheckAxis;
            for(i = 0; i < aAxes.length; ++i){
                oCurAxis = aAxes[i];
                var bHorizontal = (oCurAxis.axPos === AscFormat.AX_POS_T || oCurAxis.axPos === AscFormat.AX_POS_B);
                oReplaceAxis = this.getReplaceAxis(oCurAxis);
                if(oReplaceAxis){
                    if(bHorizontal){
                        oCurAxis.xPoints = oReplaceAxis.xPoints;
                    }
                    else{
                        oCurAxis.yPoints = oReplaceAxis.yPoints;
                    }
                }
            }
        }
    };
    
CChartSpace.prototype.recalculateAxis = function()
{
    if(this.chart && this.chart.plotArea && this.chart.plotArea.charts[0])
    {
        var b_checkEmpty = this.checkEmptySeries();
        this.bEmptySeries = b_checkEmpty;

        var plot_area = this.chart.plotArea;
        var chart_object = plot_area.chart;
        var i;
        var chart_type = chart_object.getObjectType();
        var bWithoutLabels = false;
        if(plot_area.layout && plot_area.layout.layoutTarget === AscFormat.LAYOUT_TARGET_INNER){
            bWithoutLabels = true;
        }

        this.plotAreaRect = null;
        var rect;
        var bCorrectedLayoutRect = false;
        if(b_checkEmpty)
        {
            if(chart_type === AscDFH.historyitem_type_ScatterChart)
            {
                var x_ax, y_ax;
                y_ax = this.chart.plotArea.valAx;
                x_ax = this.chart.plotArea.catAx;
                y_ax.labels  = null;
                x_ax.labels  = null;

                y_ax.posX  = null;
                x_ax.posY  = null;
                y_ax.posY  = null;
                x_ax.posX  = null;


                y_ax.xPoints = null;
                x_ax.yPoints = null;
                y_ax.yPoints = null;
                x_ax.xPoints = null;
            }
            else if(chart_type !== AscDFH.historyitem_type_BarChart && (chart_type !== AscDFH.historyitem_type_PieChart && chart_type !== AscDFH.historyitem_type_DoughnutChart)
                || (chart_type === AscDFH.historyitem_type_BarChart && chart_object.barDir !== AscFormat.BAR_DIR_BAR))
            {
                var cat_ax, val_ax;
                val_ax = this.chart.plotArea.valAx;
                cat_ax = this.chart.plotArea.catAx;
                if(val_ax && cat_ax)
                {
                    val_ax.labels  = null;
                    cat_ax.labels  = null;

                    val_ax.posX  = null;
                    cat_ax.posY  = null;
                    val_ax.posY  = null;
                    cat_ax.posX  = null;

                    val_ax.xPoints  = null;
                    cat_ax.yPoints  = null;
                    val_ax.yPoints  = null;
                    cat_ax.xPoints  = null;
                    val_ax.transformYPoints  = null;
                    cat_ax.transformXPoints  = null;
                    val_ax.transformXPoints  = null;
                    cat_ax.transformYPoints  = null;
                }
            }
            else if(chart_type === AscDFH.historyitem_type_BarChart && chart_object.barDir === AscFormat.BAR_DIR_BAR)
            {
                var cat_ax, val_ax;
                var axis_by_types = chart_object.getAxisByTypes();
                cat_ax = axis_by_types.catAx[0];
                val_ax = axis_by_types.valAx[0];
                if(cat_ax && val_ax)
                {
                    val_ax.labels  = null;
                    cat_ax.labels  = null;

                    val_ax.posX  = null;
                    cat_ax.posY  = null;
                    val_ax.posY  = null;
                    cat_ax.posX  = null;

                    val_ax.xPoints  = null;
                    cat_ax.yPoints  = null;
                    val_ax.yPoints  = null;
                    cat_ax.xPoints  = null;
                    val_ax.transformYPoints  = null;
                    cat_ax.transformXPoints  = null;
                    val_ax.transformXPoints  = null;
                    cat_ax.transformYPoints  = null;
                }
            }
            return;
        }

        var bNeedReflect =  this.getNeedReflect();
        if(chart_type === AscDFH.historyitem_type_ScatterChart)
        {
            var x_ax, y_ax;
            y_ax = this.chart.plotArea.valAx;
            x_ax = this.chart.plotArea.catAx;
            if(x_ax && y_ax)
            {
                /*new recalc*/
                y_ax.labels  = null;
                x_ax.labels  = null;
                y_ax.posX  = null;
                x_ax.posY  = null;
                y_ax.posY  = null;
                x_ax.posX  = null;

                y_ax.xPoints = null;
                x_ax.yPoints  = null;
                y_ax.yPoints  = null;
                x_ax.xPoints  = null;
                var sizes = this.getChartSizes();
                rect = {x: sizes.startX, y:sizes.startY, w:sizes.w, h: sizes.h};
                var arr_val =  this.getValAxisValues();
                var arr_strings = [];
                var multiplier;
                if(y_ax.dispUnits)
                    multiplier = y_ax.dispUnits.getMultiplier();
                else
                    multiplier = 1;
                var num_fmt = y_ax.numFmt;
                if(num_fmt && typeof num_fmt.formatCode === "string" /*&& !(num_fmt.formatCode === "General")*/)
                {
                    var num_format = oNumFormatCache.get(num_fmt.formatCode);
                    for(i = 0; i < arr_val.length; ++i)
                    {
                        var calc_value = arr_val[i]*multiplier;
                        var rich_value = num_format.formatToChart(calc_value);
                        arr_strings.push(rich_value);
                    }
                }
                else
                {
                    for(i = 0; i < arr_val.length; ++i)
                    {
                        var calc_value = arr_val[i]*multiplier;
                        arr_strings.push(calc_value + "");
                    }
                }

                //расчитаем подписи для вертикальной оси найдем ширину максимальной и возьмем её удвоенную за ширину подписей верт оси
                var left_align_labels = true;
                y_ax.labels = new AscFormat.CValAxisLabels(this, y_ax);
                y_ax.yPoints = [];
                var max_width = 0;
                for(i = 0; i < arr_strings.length; ++i)
                {
                    var dlbl = new AscFormat.CDLbl();
                    dlbl.parent = y_ax;
                    dlbl.chart = this;
                    dlbl.spPr = y_ax.spPr;
                    dlbl.txPr = y_ax.txPr;
                    dlbl.tx = new AscFormat.CChartText();
                    dlbl.tx.rich = AscFormat.CreateTextBodyFromString(arr_strings[i], this.getDrawingDocument(), dlbl);
                    if(i > 0)
                    {
                        dlbl.lastStyleObject = y_ax.labels.aLabels[0].lastStyleObject;
                    }
                    var oRecalculateByMaxWord =  dlbl.tx.rich.recalculateByMaxWord();
                    var cur_width = oRecalculateByMaxWord.w;
                    if(i === arr_strings.length-1){
                        rect.y += oRecalculateByMaxWord.h/2;
                    }
                    if(cur_width > max_width)
                        max_width = cur_width;
                    y_ax.labels.aLabels.push(dlbl);
                }


                //пока расстояние между подписями и краем блока с подписями берем размер шрифта.
                var hor_gap = y_ax.labels.aLabels[0].tx.rich.content.Content[0].CompiledPr.Pr.TextPr.FontSize*(25.4/72);
                y_ax.labels.extX = max_width + hor_gap;

                /*расчитаем надписи в блоке для горизонтальной оси*/
                var arr_x_val = this.getXValAxisValues();
                var num_fmt = x_ax.numFmt;
                var string_pts = [];
                if(num_fmt && typeof num_fmt.formatCode === "string" /*&& !(num_fmt.formatCode === "General")*/)
                {
                    var num_format = oNumFormatCache.get(num_fmt.formatCode);
                    for(i = 0; i < arr_x_val.length; ++i)
                    {
                        var calc_value = arr_x_val[i]*multiplier;
                        var rich_value = num_format.formatToChart(calc_value);
                        string_pts.push({val:rich_value});
                    }
                }
                else
                {
                    for(i = 0; i < arr_x_val.length; ++i)
                    {
                        var calc_value = arr_x_val[i]*multiplier;
                        string_pts.push({val:calc_value + ""});
                    }
                }

                x_ax.labels = new AscFormat.CValAxisLabels(this, x_ax);
                var bottom_align_labels = true;
                var max_height = 0;
                for(i = 0; i < string_pts.length; ++i)
                {
                    var dlbl = new AscFormat.CDLbl();
                    dlbl.parent = x_ax;
                    dlbl.chart = this;
                    dlbl.spPr = x_ax.spPr;
                    dlbl.txPr = x_ax.txPr;
                    dlbl.tx = new AscFormat.CChartText();
                    dlbl.tx.rich = AscFormat.CreateTextBodyFromString(string_pts[i].val.replace(oNonSpaceRegExp,  ' '), this.getDrawingDocument(), dlbl);
                    if(x_ax.labels.aLabels[0])
                    {
                        dlbl.lastStyleObject = x_ax.labels.aLabels[0].lastStyleObject;
                    }

                    var oWH = dlbl.tx.rich.recalculateByMaxWord();
                    var cur_height = oWH.h;
                    if(cur_height > max_height)
                        max_height = cur_height;
                    if(i === string_pts.length - 1){
                        rect.w -= oWH.w/2;
                    }
                    x_ax.labels.aLabels.push(dlbl);
                }
                var vert_gap = x_ax.labels.aLabels[0].tx.rich.content.Content[0].CompiledPr.Pr.TextPr.FontSize*(25.4/72);
                x_ax.labels.extY = max_height + vert_gap;


                /*расчитаем позицию блока с подпиясями вертикальной оси*/
                var x_ax_orientation = isRealObject(x_ax.scaling) && AscFormat.isRealNumber(x_ax.scaling.orientation) ? x_ax.scaling.orientation : AscFormat.ORIENTATION_MIN_MAX;
                var crosses;//точка на горизонтальной оси где её пересекает вертикальная
                if(y_ax.crosses === AscFormat.CROSSES_AUTO_ZERO)
                {
                    if(arr_x_val[0] <=0 && arr_x_val[arr_x_val.length -1] >= 0)
                        crosses = 0;
                    else if(arr_x_val[0] > 0)
                        crosses = arr_x_val[0];
                    else
                        crosses = arr_x_val[arr_x_val.length-1];
                }
                else if(y_ax.crosses === AscFormat.CROSSES_MAX)
                    crosses =  arr_x_val[arr_x_val.length-1];
                else if(y_ax.crosses === AscFormat.CROSSES_MIN)
                    crosses = arr_x_val[0];
                else if(AscFormat.isRealNumber(y_ax.crossesAt) && arr_val[0] <= y_ax.crossesAt && arr_val[arr_val.length-1] >= y_ax.crossesAt)
                {
                    crosses = y_ax.crossesAt;
                }
                else
                {
                    //в кайнем случае ведем себя как с AUTO_ZERO
                    if(arr_x_val[0] <=0 && arr_x_val[arr_x_val.length -1] >= 0)
                        crosses = 0;
                    else if(arr_x_val[0] > 0)
                        crosses = arr_x_val[0];
                    else
                        crosses = arr_x_val[arr_x_val.length-1];
                }


                var hor_interval_width = checkFiniteNumber(rect.w/(arr_x_val[arr_x_val.length-1] - arr_x_val[0]));
                var vert_interval_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length-1] - arr_val[0]));
                var arr_x_points = [], arr_y_points = [];
                var labels_pos = y_ax.tickLblPos;

                var first_hor_label_half_width = (x_ax.tickLblPos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE || x_ax.bDelete) ? 0 : x_ax.labels.aLabels[0].tx.rich.content.XLimit/2;
                var last_hor_label_half_width = (x_ax.tickLblPos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE || x_ax.bDelete) ? 0 : x_ax.labels.aLabels[x_ax.labels.aLabels.length-1].tx.rich.content.XLimit/2;
                var left_gap = 0, right_gap = 0;
                if(x_ax_orientation === AscFormat.ORIENTATION_MIN_MAX)
                {
                    switch(labels_pos)
                    {
                        case c_oAscTickLabelsPos.TICK_LABEL_POSITION_HIGH:
                        {
                            left_align_labels = false;

                            if(bNeedReflect)
                            {
                                right_gap = Math.max(last_hor_label_half_width, 0);
                            }
                            else
                            {
                                right_gap = Math.max(last_hor_label_half_width, y_ax.labels.extX);
                            }
                            if(!bWithoutLabels){
                                hor_interval_width = checkFiniteNumber((rect.w - right_gap - first_hor_label_half_width)/(arr_x_val[arr_x_val.length-1] - arr_x_val[0]));
                                for(i = 0; i < arr_x_val.length; ++i)
                                {
                                    arr_x_points[i] = rect.x + first_hor_label_half_width + hor_interval_width*(arr_x_val[i] - arr_x_val[0]);
                                }
                                y_ax.labels.x = rect.x + first_hor_label_half_width + hor_interval_width*(arr_x_val[arr_x_val.length-1] - arr_x_val[0]);
                                y_ax.posX = rect.x + first_hor_label_half_width + (crosses-arr_x_val[0])*hor_interval_width;
                            }
                            else{
                                hor_interval_width = checkFiniteNumber(rect.w/(arr_x_val[arr_x_val.length-1] - arr_x_val[0]));
                                for(i = 0; i < arr_x_val.length; ++i)
                                {
                                    arr_x_points[i] = rect.x + hor_interval_width*(arr_x_val[i] - arr_x_val[0]);
                                }
                                y_ax.labels.x = rect.x + hor_interval_width*(arr_x_val[arr_x_val.length-1] - arr_x_val[0]);
                                y_ax.posX = rect.x + (crosses-arr_x_val[0])*hor_interval_width;

                                if(y_ax.labels.x < 0 && !bNeedReflect){
                                    rect.x -= y_ax.labels.x;
                                    rect.w += y_ax.labels.x;
                                    bCorrectedLayoutRect = true;
                                }
                                if(y_ax.labels.x + y_ax.labels.extX > this.extX && !bNeedReflect){
                                    rect.w -= (y_ax.labels.x + y_ax.labels.extX - this.extX);
                                    bCorrectedLayoutRect = true;
                                }
                                if(bCorrectedLayoutRect){
                                    hor_interval_width = checkFiniteNumber(rect.w/(arr_x_val[arr_x_val.length-1] - arr_x_val[0]));
                                    for(i = 0; i < arr_x_val.length; ++i)
                                    {
                                        arr_x_points[i] = rect.x + hor_interval_width*(arr_x_val[i] - arr_x_val[0]);
                                    }
                                    y_ax.labels.x = rect.x + hor_interval_width*(arr_x_val[arr_x_val.length-1] - arr_x_val[0]);
                                    y_ax.posX = rect.x + (crosses-arr_x_val[0])*hor_interval_width;
                                }
                            }
                            break;
                        }
                        case c_oAscTickLabelsPos.TICK_LABEL_POSITION_LOW:
                        {
                            if(bNeedReflect)
                            {
                                left_gap = Math.max(first_hor_label_half_width, 0);
                            }
                            else
                            {
                                left_gap = Math.max(first_hor_label_half_width, y_ax.labels.extX);
                            }

                            if(!bWithoutLabels){
                                hor_interval_width = checkFiniteNumber((rect.w-left_gap - last_hor_label_half_width)/(arr_x_val[arr_x_val.length-1] - arr_x_val[0]));
                                for(i = 0; i < arr_x_val.length; ++i)
                                {
                                    arr_x_points[i] = rect.x + left_gap + hor_interval_width*(arr_x_val[i] - arr_x_val[0]);
                                }
                                y_ax.labels.x = rect.x - y_ax.labels.extX;
                                y_ax.posX = rect.x + (crosses-arr_x_val[0])*hor_interval_width;
                            }
                            else{
                                hor_interval_width = checkFiniteNumber(rect.w/(arr_x_val[arr_x_val.length-1] - arr_x_val[0]));
                                for(i = 0; i < arr_x_val.length; ++i)
                                {
                                    arr_x_points[i] = rect.x + hor_interval_width*(arr_x_val[i] - arr_x_val[0]);
                                }
                                y_ax.labels.x = rect.x - y_ax.labels.extX;
                                y_ax.posX = rect.x + (crosses-arr_x_val[0])*hor_interval_width;


                                if(y_ax.labels.x < 0 && !bNeedReflect){
                                    rect.x -= y_ax.labels.x;
                                    rect.w += y_ax.labels.x;
                                    bCorrectedLayoutRect = true;
                                }
                                if(y_ax.labels.x + y_ax.labels.extX > this.extX && !bNeedReflect){
                                    rect.w -= (y_ax.labels.x + y_ax.labels.extX - this.extX);
                                    bCorrectedLayoutRect = true;
                                }
                                if(bCorrectedLayoutRect){
                                    hor_interval_width = checkFiniteNumber(rect.w/(arr_x_val[arr_x_val.length-1] - arr_x_val[0]));
                                    for(i = 0; i < arr_x_val.length; ++i)
                                    {
                                        arr_x_points[i] = rect.x + hor_interval_width*(arr_x_val[i] - arr_x_val[0]);
                                    }
                                    y_ax.labels.x = rect.x - y_ax.labels.extX;
                                    y_ax.posX = rect.x + (crosses-arr_x_val[0])*hor_interval_width;
                                }

                            }

                            break;
                        }
                        case c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE:
                        {
                            if(!bWithoutLabels) {
                                y_ax.labels = null;
                                hor_interval_width = checkFiniteNumber((rect.w - first_hor_label_half_width - last_hor_label_half_width) / (arr_x_val[arr_x_val.length - 1] - arr_x_val[0]));
                                for (i = 0; i < arr_x_val.length; ++i) {
                                    arr_x_points[i] = rect.x + first_hor_label_half_width + hor_interval_width * (arr_x_val[i] - arr_x_val[0]);
                                }
                                y_ax.posX = rect.x + first_hor_label_half_width + hor_interval_width * (crosses - arr_x_val[0]);
                            }
                            else{
                                y_ax.labels = null;
                                hor_interval_width = checkFiniteNumber(rect.w/ (arr_x_val[arr_x_val.length - 1] - arr_x_val[0]));
                                for (i = 0; i < arr_x_val.length; ++i) {
                                    arr_x_points[i] = rect.x + first_hor_label_half_width + hor_interval_width * (arr_x_val[i] - arr_x_val[0]);
                                }
                                y_ax.posX = rect.x + hor_interval_width * (crosses - arr_x_val[0]);
                            }
                            break;
                        }
                        default :
                        {//c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO рядом с осью
                            if(y_ax.crosses === AscFormat.CROSSES_MAX)
                            {
                                left_align_labels = false;
                                if(bNeedReflect)
                                {
                                    right_gap = Math.max(right_gap, 0);
                                }
                                else
                                {
                                    right_gap = Math.max(right_gap, y_ax.labels.extX);
                                }

                                if(!bWithoutLabels){
                                    y_ax.labels.x = rect.x + rect.w - right_gap;
                                    y_ax.posX = rect.x + rect.w - right_gap;
                                    hor_interval_width = checkFiniteNumber((rect.w - right_gap - first_hor_label_half_width)/(arr_x_val[arr_x_val.length-1] - arr_x_val[0]));
                                    for(i = 0; i < arr_x_val.length; ++i)
                                    {
                                        arr_x_points[i] = rect.x + first_hor_label_half_width + hor_interval_width*(arr_x_val[i] - arr_x_val[0]);
                                    }
                                }
                                else{

                                    y_ax.labels.x = rect.x + rect.w;
                                    y_ax.posX = rect.x + rect.w;
                                    hor_interval_width = checkFiniteNumber(rect.w/(arr_x_val[arr_x_val.length-1] - arr_x_val[0]));
                                    for(i = 0; i < arr_x_val.length; ++i)
                                    {
                                        arr_x_points[i] = rect.x + hor_interval_width*(arr_x_val[i] - arr_x_val[0]);
                                    }

                                    if(y_ax.labels.x < 0 && !bNeedReflect){
                                        rect.x -= y_ax.labels.x;
                                        rect.w += y_ax.labels.x;
                                        bCorrectedLayoutRect = true;
                                    }
                                    if(y_ax.labels.x + y_ax.labels.extX > this.extX && !bNeedReflect){
                                        rect.w -= (y_ax.labels.x + y_ax.labels.extX - this.extX);
                                        bCorrectedLayoutRect = true;
                                    }
                                    if(bCorrectedLayoutRect){
                                        y_ax.labels.x = rect.x + rect.w;
                                        y_ax.posX = rect.x + rect.w;
                                        hor_interval_width = checkFiniteNumber(rect.w/(arr_x_val[arr_x_val.length-1] - arr_x_val[0]));
                                        for(i = 0; i < arr_x_val.length; ++i)
                                        {
                                            arr_x_points[i] = rect.x + hor_interval_width*(arr_x_val[i] - arr_x_val[0]);
                                        }
                                    }

                                }
                            }
                            else
                            {

                                if(!bWithoutLabels) {
                                    hor_interval_width = checkFiniteNumber((rect.w - first_hor_label_half_width - last_hor_label_half_width) / (arr_x_val[arr_x_val.length - 1] - arr_x_val[0]));
                                    if (!bNeedReflect && first_hor_label_half_width + (crosses - arr_x_val[0]) * hor_interval_width < y_ax.labels.extX) {
                                        hor_interval_width = checkFiniteNumber((rect.w - y_ax.labels.extX - last_hor_label_half_width) / (arr_x_val[arr_x_val.length - 1] - crosses));
                                    }
                                    y_ax.posX = rect.x + rect.w - last_hor_label_half_width - (arr_x_val[arr_x_val.length - 1] - crosses) * hor_interval_width;
                                    for (i = 0; i < arr_x_val.length; ++i) {
                                        arr_x_points[i] = y_ax.posX + (arr_x_val[i] - crosses) * hor_interval_width;
                                    }
                                    y_ax.labels.x = y_ax.posX - y_ax.labels.extX;
                                }
                                else{
                                    hor_interval_width = checkFiniteNumber(rect.w/ (arr_x_val[arr_x_val.length - 1] - arr_x_val[0]));
                                    y_ax.posX = rect.x + rect.w - (arr_x_val[arr_x_val.length - 1] - crosses) * hor_interval_width;
                                    for (i = 0; i < arr_x_val.length; ++i) {
                                        arr_x_points[i] = y_ax.posX + (arr_x_val[i] - crosses) * hor_interval_width;
                                    }
                                    y_ax.labels.x = y_ax.posX - y_ax.labels.extX;

                                    if(y_ax.labels.x < 0 && !bNeedReflect){
                                        rect.x -= y_ax.labels.x;
                                        rect.w += y_ax.labels.x;
                                        bCorrectedLayoutRect = true;
                                    }
                                    if(y_ax.labels.x + y_ax.labels.extX > this.extX && !bNeedReflect){
                                        rect.w -= (y_ax.labels.x + y_ax.labels.extX - this.extX);
                                        bCorrectedLayoutRect = true;
                                    }
                                    if(bCorrectedLayoutRect){
                                        hor_interval_width = checkFiniteNumber(rect.w/ (arr_x_val[arr_x_val.length - 1] - arr_x_val[0]));
                                        y_ax.posX = rect.x + rect.w - (arr_x_val[arr_x_val.length - 1] - crosses) * hor_interval_width;
                                        for (i = 0; i < arr_x_val.length; ++i) {
                                            arr_x_points[i] = y_ax.posX + (arr_x_val[i] - crosses) * hor_interval_width;
                                        }
                                        y_ax.labels.x = y_ax.posX - y_ax.labels.extX;
                                    }

                                }
                            }
                            break;
                        }
                    }
                }
                else
                {
                    switch(labels_pos)
                    {
                        case c_oAscTickLabelsPos.TICK_LABEL_POSITION_HIGH:
                        {
                            if(bNeedReflect)
                            {
                                left_gap = Math.max(0, last_hor_label_half_width);
                            }
                            else
                            {
                                left_gap = Math.max(y_ax.labels.extX, last_hor_label_half_width);
                            }
                            if(!bWithoutLabels){
                                hor_interval_width = checkFiniteNumber((rect.w - left_gap - first_hor_label_half_width)/(arr_x_val[arr_x_val.length-1] - arr_x_val[0]));

                                y_ax.posX = rect.x + rect.w - (crosses - arr_x_val[0])*hor_interval_width - first_hor_label_half_width;
                                for(i = 0; i < arr_x_val.length; ++i)
                                {
                                    arr_x_points[i] = y_ax.posX - (arr_x_val[i]-crosses)*hor_interval_width;
                                }
                                y_ax.labels.x = y_ax.posX - (arr_x_val[arr_x_val.length-1]-crosses)*hor_interval_width - y_ax.labels.extX;
                            }
                            else{
                                hor_interval_width = checkFiniteNumber(rect.w/(arr_x_val[arr_x_val.length-1] - arr_x_val[0]));

                                y_ax.posX = rect.x + rect.w - (crosses - arr_x_val[0])*hor_interval_width;
                                for(i = 0; i < arr_x_val.length; ++i)
                                {
                                    arr_x_points[i] = y_ax.posX - (arr_x_val[i]-crosses)*hor_interval_width;
                                }
                                y_ax.labels.x = y_ax.posX - (arr_x_val[arr_x_val.length-1]-crosses)*hor_interval_width - y_ax.labels.extX;

                                if(y_ax.labels.x < 0 && !bNeedReflect){
                                    rect.x -= y_ax.labels.x;
                                    rect.w += y_ax.labels.x;
                                    bCorrectedLayoutRect = true;
                                }
                                if(y_ax.labels.x + y_ax.labels.extX > this.extX && !bNeedReflect){
                                    rect.w -= (y_ax.labels.x + y_ax.labels.extX - this.extX);
                                    bCorrectedLayoutRect = true;
                                }
                                if(bCorrectedLayoutRect){
                                    hor_interval_width = checkFiniteNumber(rect.w/(arr_x_val[arr_x_val.length-1] - arr_x_val[0]));

                                    y_ax.posX = rect.x + rect.w - (crosses - arr_x_val[0])*hor_interval_width;
                                    for(i = 0; i < arr_x_val.length; ++i)
                                    {
                                        arr_x_points[i] = y_ax.posX - (arr_x_val[i]-crosses)*hor_interval_width;
                                    }
                                    y_ax.labels.x = y_ax.posX - (arr_x_val[arr_x_val.length-1]-crosses)*hor_interval_width - y_ax.labels.extX;
                                }


                            }
                            break;
                        }
                        case c_oAscTickLabelsPos.TICK_LABEL_POSITION_LOW:
                        {
                            left_align_labels = false;

                            if(bNeedReflect)
                            {
                                right_gap = Math.max(0, first_hor_label_half_width);
                            }
                            else
                            {
                                right_gap = Math.max(y_ax.labels.extX, first_hor_label_half_width);
                            }

                            if(!bWithoutLabels){
                                hor_interval_width = checkFiniteNumber((rect.w - right_gap - last_hor_label_half_width)/(arr_x_val[arr_x_val.length-1] - arr_x_val[0]));
                                y_ax.posX = rect.x + rect.w - right_gap - (crosses - arr_x_val[0])*hor_interval_width;
                                for(i = 0; i < arr_x_val.length; ++i)
                                {
                                    arr_x_points[i] = y_ax.posX - (arr_x_val[i]-crosses)*hor_interval_width;
                                }
                                y_ax.labels.x = rect.x + rect.w - right_gap;
                            }
                            else{
                                hor_interval_width = checkFiniteNumber(rect.w/(arr_x_val[arr_x_val.length-1] - arr_x_val[0]));
                                y_ax.posX = rect.x + rect.w - (crosses - arr_x_val[0])*hor_interval_width;
                                for(i = 0; i < arr_x_val.length; ++i)
                                {
                                    arr_x_points[i] = y_ax.posX - (arr_x_val[i]-crosses)*hor_interval_width;
                                }
                                y_ax.labels.x = rect.x + rect.w;

                                if(y_ax.labels.x < 0 && !bNeedReflect){
                                    rect.x -= y_ax.labels.x;
                                    rect.w += y_ax.labels.x;
                                    bCorrectedLayoutRect = true;
                                }
                                if(y_ax.labels.x + y_ax.labels.extX > this.extX && !bNeedReflect){
                                    rect.w -= (y_ax.labels.x + y_ax.labels.extX - this.extX);
                                    bCorrectedLayoutRect = true;
                                }
                                if(bCorrectedLayoutRect){
                                    hor_interval_width = checkFiniteNumber(rect.w/(arr_x_val[arr_x_val.length-1] - arr_x_val[0]));
                                    y_ax.posX = rect.x + rect.w - (crosses - arr_x_val[0])*hor_interval_width;
                                    for(i = 0; i < arr_x_val.length; ++i)
                                    {
                                        arr_x_points[i] = y_ax.posX - (arr_x_val[i]-crosses)*hor_interval_width;
                                    }
                                    y_ax.labels.x = rect.x + rect.w;
                                }

                            }
                            break;
                        }
                        case c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE:
                        {
                            y_ax.labels = null;

                            if(!bWithoutLabels) {
                                hor_interval_width = checkFiniteNumber((rect.w - first_hor_label_half_width - last_hor_label_half_width) / (arr_x_val[arr_x_val.length - 1] - arr_x_val[0]));
                                y_ax.posX = rect.x + rect.w - first_hor_label_half_width - (crosses - arr_x_val[0]) * hor_interval_width;
                                for (i = 0; i < arr_x_val.length; ++i) {
                                    arr_x_points[i] = y_ax.posX - (arr_x_val[i] - crosses) * hor_interval_width;
                                }
                            }
                            else{
                                hor_interval_width = checkFiniteNumber(rect.w / (arr_x_val[arr_x_val.length - 1] - arr_x_val[0]));
                                y_ax.posX = rect.x + rect.w - (crosses - arr_x_val[0]) * hor_interval_width;
                                for (i = 0; i < arr_x_val.length; ++i) {
                                    arr_x_points[i] = y_ax.posX - (arr_x_val[i] - crosses) * hor_interval_width;
                                }
                            }
                            break;
                        }
                        default :
                        {//c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO рядом с осью

                            if(y_ax.crosses === AscFormat.CROSSES_MAX)
                            {
                                if(bNeedReflect)
                                {
                                    left_gap = Math.max(0, last_hor_label_half_width);
                                }
                                else
                                {
                                    left_gap = Math.max(y_ax.labels.extX, last_hor_label_half_width);
                                }
                                if(!bWithoutLabels) {
                                    hor_interval_width = checkFiniteNumber((rect.w - left_gap - first_hor_label_half_width) / (arr_x_val[arr_x_val.length - 1] - arr_x_val[0]));
                                    y_ax.posX = rect.x + rect.w - first_hor_label_half_width - (crosses - arr_x_val[0]) * hor_interval_width;
                                    y_ax.labels.x = y_ax.posX - ((arr_x_val[arr_x_val.length - 1] - crosses) * hor_interval_width) - y_ax.labels.extX;
                                }
                                else{
                                    hor_interval_width = checkFiniteNumber(rect.w/ (arr_x_val[arr_x_val.length - 1] - arr_x_val[0]));
                                    y_ax.posX = rect.x + rect.w  - (crosses - arr_x_val[0]) * hor_interval_width;
                                    y_ax.labels.x = y_ax.posX - ((arr_x_val[arr_x_val.length - 1] - crosses) * hor_interval_width) - y_ax.labels.extX;



                                    if(y_ax.labels.x < 0 && !bNeedReflect){
                                        rect.x -= y_ax.labels.x;
                                        rect.w += y_ax.labels.x;
                                        bCorrectedLayoutRect = true;
                                    }
                                    if(y_ax.labels.x + y_ax.labels.extX > this.extX && !bNeedReflect){
                                        rect.w -= (y_ax.labels.x + y_ax.labels.extX - this.extX);
                                        bCorrectedLayoutRect = true;
                                    }
                                    if(bCorrectedLayoutRect){
                                        hor_interval_width = checkFiniteNumber(rect.w/ (arr_x_val[arr_x_val.length - 1] - arr_x_val[0]));
                                        y_ax.posX = rect.x + rect.w  - (crosses - arr_x_val[0]) * hor_interval_width;
                                        y_ax.labels.x = y_ax.posX - ((arr_x_val[arr_x_val.length - 1] - crosses) * hor_interval_width) - y_ax.labels.extX;
                                    }

                                }
                            }
                            else
                            {
                                left_align_labels = false;
                                if(!bWithoutLabels) {
                                    hor_interval_width = checkFiniteNumber((rect.w - first_hor_label_half_width - last_hor_label_half_width) / (arr_x_val[arr_x_val.length - 1] - arr_x_val[0]));
                                    if (!bNeedReflect && first_hor_label_half_width + (crosses - arr_x_val[0]) * hor_interval_width < y_ax.labels.extX) {
                                        hor_interval_width = checkFiniteNumber((rect.w - y_ax.labels.extX - last_hor_label_half_width) / (arr_x_val[arr_x_val.length - 1] - crosses));
                                    }
                                    left_align_labels = false;
                                    y_ax.posX = rect.x + last_hor_label_half_width + hor_interval_width * (arr_x_val[arr_x_val.length - 1] - crosses);
                                    y_ax.labels.x = y_ax.posX;
                                }
                                else{
                                    hor_interval_width = checkFiniteNumber(rect.w / (arr_x_val[arr_x_val.length - 1] - arr_x_val[0]));
                                    left_align_labels = false;
                                    y_ax.posX = rect.x + hor_interval_width * (arr_x_val[arr_x_val.length - 1] - crosses);
                                    y_ax.labels.x = y_ax.posX;



                                    if(y_ax.labels.x < 0 && !bNeedReflect){
                                        rect.x -= y_ax.labels.x;
                                        rect.w += y_ax.labels.x;
                                        bCorrectedLayoutRect = true;
                                    }
                                    if(y_ax.labels.x + y_ax.labels.extX > this.extX && !bNeedReflect){
                                        rect.w -= (y_ax.labels.x + y_ax.labels.extX - this.extX);
                                        bCorrectedLayoutRect = true;
                                    }
                                    if(bCorrectedLayoutRect){
                                        hor_interval_width = checkFiniteNumber(rect.w / (arr_x_val[arr_x_val.length - 1] - arr_x_val[0]));
                                        left_align_labels = false;
                                        y_ax.posX = rect.x + hor_interval_width * (arr_x_val[arr_x_val.length - 1] - crosses);
                                        y_ax.labels.x = y_ax.posX;
                                    }

                                }
                            }
                            for(i = 0;  i < arr_x_val.length; ++i)
                            {
                                arr_x_points[i] = y_ax.posX - (arr_x_val[i] - crosses)*hor_interval_width;
                            }
                            break;
                        }
                    }
                }
                x_ax.interval = hor_interval_width;

                /*рассчитаем позицию блока с подписями горизонтальной оси*/
                var y_ax_orientation = isRealObject(y_ax.scaling) && AscFormat.isRealNumber(y_ax.scaling.orientation) ? y_ax.scaling.orientation : AscFormat.ORIENTATION_MIN_MAX;
                var crosses_x;
                if(x_ax.crosses === AscFormat.CROSSES_AUTO_ZERO)
                {
                    if(arr_val[0] <= 0 && arr_val[arr_val.length-1] >=0)
                    {
                        crosses_x = 0;
                    }
                    else if(arr_val[0] > 0)
                        crosses_x = arr_val[0];
                    else
                        crosses_x = arr_val[arr_val.length-1];
                }
                else if(x_ax.crosses === AscFormat.CROSSES_MAX)
                {
                    crosses_x = arr_val[arr_val.length-1];
                }
                else if(x_ax.crosses === AscFormat.CROSSES_MIN)
                {
                    crosses_x = arr_val[0];
                }
                else if(AscFormat.isRealNumber(x_ax.crossesAt) && arr_val[0] <= x_ax.crossesAt && arr_val[arr_val.length-1] >= x_ax.crossesAt)
                {
                    crosses_x = x_ax.crossesAt;
                }
                else
                {   //как с AUTO_ZERO
                    if(arr_val[0] <= 0 && arr_val[arr_val.length-1] >=0)
                    {
                        crosses_x = 0;
                    }
                    else if(arr_val[0] > 0)
                        crosses_x = arr_val[0];
                    else
                        crosses_x = arr_val[arr_val.length-1];
                }

                var tick_labels_pos_x = x_ax.tickLblPos;

                var first_vert_label_half_height = 0; //TODO (y_ax.tickLblPos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE || y_ax.bDelete) ? 0 :  y_ax.labels.aLabels[0].tx.rich.content.GetSummaryHeight()/2;
                var last_vert_label_half_height =  0; //(y_ax.tickLblPos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE || y_ax.bDelete) ? 0 :  y_ax.labels.aLabels[0].tx.rich.content.GetSummaryHeight()/2;

                var bottom_gap = 0, top_height = 0;
                if(y_ax_orientation === AscFormat.ORIENTATION_MIN_MAX)
                {
                    switch(tick_labels_pos_x)
                    {
                        case c_oAscTickLabelsPos.TICK_LABEL_POSITION_HIGH:
                        {
                            bottom_align_labels = false;
                            var bottom_start_point = rect.y + rect.h - first_vert_label_half_height;


                            top_height = Math.max(x_ax.labels.extY, last_vert_label_half_height);
                            if(!bWithoutLabels){
                                vert_interval_height = checkFiniteNumber((rect.h - top_height - first_vert_label_half_height)/(arr_val[arr_val.length-1] - arr_val[0]));

                                x_ax.labels.y = bottom_start_point - (arr_val[arr_val.length - 1] - arr_val[0])*vert_interval_height - x_ax.labels.extY;

                                for(i = 0; i < arr_val.length; ++i)
                                {
                                    arr_y_points[i] = bottom_start_point - (arr_val[i] - arr_val[0])*vert_interval_height;
                                }
                                x_ax.posY = bottom_start_point - (crosses_x - arr_val[0])*vert_interval_height;
                            }
                            else{
                                vert_interval_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length-1] - arr_val[0]));

                                x_ax.labels.y = rect.y + rect.h - (arr_val[arr_val.length - 1] - arr_val[0])*vert_interval_height - x_ax.labels.extY;

                                for(i = 0; i < arr_val.length; ++i)
                                {
                                    arr_y_points[i] = rect.y + rect.h - (arr_val[i] - arr_val[0])*vert_interval_height;
                                }
                                x_ax.posY = rect.y + rect.h - (crosses_x - arr_val[0])*vert_interval_height;

                                var bCheckXLabels = false;
                                if(x_ax.labels.y < 0){
                                    bCheckXLabels = true;
                                    rect.y -= x_ax.labels.y;
                                    rect.h -= x_ax.labels.h;
                                }
                                if(x_ax.labels.y + x_ax.labels.extY > this.extY){
                                    bCheckXLabels = true;
                                    rect.h -= (x_ax.labels.y + x_ax.labels.extY - this.extY)
                                }
                                if(bCheckXLabels){
                                    vert_interval_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length-1] - arr_val[0]));
                                    x_ax.labels.y = rect.y + rect.h - (arr_val[arr_val.length - 1] - arr_val[0])*vert_interval_height - x_ax.labels.extY;
                                    for(i = 0; i < arr_val.length; ++i)
                                    {
                                        arr_y_points[i] = rect.y + rect.h - (arr_val[i] - arr_val[0])*vert_interval_height;
                                    }
                                    x_ax.posY = rect.y + rect.h - (crosses_x - arr_val[0])*vert_interval_height;
                                }
                            }
                            break;
                        }
                        case c_oAscTickLabelsPos.TICK_LABEL_POSITION_LOW:
                        {
                            bottom_gap = Math.max(x_ax.labels.extY, first_vert_label_half_height);
                            if(!bWithoutLabels){
                                x_ax.labels.y = rect.y + rect.h - bottom_gap;
                                vert_interval_height = checkFiniteNumber((rect.h - bottom_gap - last_vert_label_half_height)/(arr_val[arr_val.length-1] - arr_val[0]));

                                for(i = 0; i < arr_val.length; ++i)
                                {
                                    arr_y_points[i] = rect.y + rect.h - bottom_gap -  (arr_val[i] - arr_val[0])*vert_interval_height;
                                }
                                x_ax.posY = rect.y + rect.h - bottom_gap - (crosses_x - arr_val[0])*vert_interval_height;
                            }
                            else{
                                x_ax.labels.y = rect.y + rect.h;
                                vert_interval_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length-1] - arr_val[0]));

                                for(i = 0; i < arr_val.length; ++i)
                                {
                                    arr_y_points[i] = rect.y + rect.h - (arr_val[i] - arr_val[0])*vert_interval_height;
                                }
                                x_ax.posY = rect.y + rect.h - (crosses_x - arr_val[0])*vert_interval_height;

                                var bCheckXLabels = false;
                                if(x_ax.labels.y < 0){
                                    bCheckXLabels = true;
                                    rect.y -= x_ax.labels.y;
                                    rect.h -= x_ax.labels.h;
                                }
                                if(x_ax.labels.y + x_ax.labels.extY > this.extY){
                                    bCheckXLabels = true;
                                    rect.h -= (x_ax.labels.y + x_ax.labels.extY - this.extY)
                                }
                                if(bCheckXLabels){

                                    x_ax.labels.y = rect.y + rect.h;
                                    vert_interval_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length-1] - arr_val[0]));

                                    for(i = 0; i < arr_val.length; ++i)
                                    {
                                        arr_y_points[i] = rect.y + rect.h - (arr_val[i] - arr_val[0])*vert_interval_height;
                                    }
                                    x_ax.posY = rect.y + rect.h - (crosses_x - arr_val[0])*vert_interval_height;
                                }
                            }
                            break;
                        }
                        case c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE:
                        {
                            x_ax.labels = null;
                            if(!bWithoutLabels){
                                vert_interval_height = checkFiniteNumber((rect.h - first_vert_label_half_height - last_vert_label_half_height)/(arr_val[arr_val.length-1] - arr_val[0]));
                                for(i = 0; i < arr_val.length; ++i)
                                {
                                    arr_y_points[i] = rect.y + rect.h - first_vert_label_half_height - (arr_val[i] - arr_val[0])*vert_interval_height;
                                }
                                x_ax.posY = rect.y + rect.h - first_vert_label_half_height - (crosses_x - arr_val[0])*vert_interval_height;
                            }
                            else{
                                vert_interval_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length-1] - arr_val[0]));
                                for(i = 0; i < arr_val.length; ++i)
                                {
                                    arr_y_points[i] = rect.y + rect.h - (arr_val[i] - arr_val[0])*vert_interval_height;
                                }
                                x_ax.posY = rect.y + rect.h - (crosses_x - arr_val[0])*vert_interval_height;
                            }
                            break;
                        }
                        default :
                        {//c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO рядом с осью
                            if(x_ax.crosses === AscFormat.CROSSES_MAX)
                            {
                                bottom_align_labels = false;
                                top_height = Math.max(x_ax.labels.extY, last_vert_label_half_height);


                                if(!bWithoutLabels) {
                                    vert_interval_height = checkFiniteNumber((rect.h - top_height - first_vert_label_half_height) / (arr_val[arr_val.length - 1] - arr_val[0]));
                                    for (i = 0; i < arr_val.length; ++i) {
                                        arr_y_points[i] = rect.y + rect.h - first_vert_label_half_height - (arr_val[i] - arr_val[0]) * vert_interval_height;
                                    }
                                    x_ax.posY = rect.y + rect.h - first_vert_label_half_height - (arr_val[arr_val.length - 1] - arr_val[0]) * vert_interval_height;
                                    x_ax.labels.y = x_ax.posY - x_ax.labels.extY;
                                }
                                else{
                                    vert_interval_height = checkFiniteNumber(rect.h / (arr_val[arr_val.length - 1] - arr_val[0]));
                                    for (i = 0; i < arr_val.length; ++i) {
                                        arr_y_points[i] = rect.y + rect.h - (arr_val[i] - arr_val[0]) * vert_interval_height;
                                    }
                                    x_ax.posY = rect.y + rect.h - (arr_val[arr_val.length - 1] - arr_val[0]) * vert_interval_height;
                                    x_ax.labels.y = x_ax.posY - x_ax.labels.extY;



                                    var bCheckXLabels = false;
                                    if(x_ax.labels.y < 0){
                                        bCheckXLabels = true;
                                        rect.y -= x_ax.labels.y;
                                        rect.h -= x_ax.labels.h;
                                    }
                                    if(x_ax.labels.y + x_ax.labels.extY > this.extY){
                                        bCheckXLabels = true;
                                        rect.h -= (x_ax.labels.y + x_ax.labels.extY - this.extY)
                                    }
                                    if(bCheckXLabels){
                                        vert_interval_height = checkFiniteNumber(rect.h / (arr_val[arr_val.length - 1] - arr_val[0]));
                                        for (i = 0; i < arr_val.length; ++i) {
                                            arr_y_points[i] = rect.y + rect.h - (arr_val[i] - arr_val[0]) * vert_interval_height;
                                        }
                                        x_ax.posY = rect.y + rect.h - (arr_val[arr_val.length - 1] - arr_val[0]) * vert_interval_height;
                                        x_ax.labels.y = x_ax.posY - x_ax.labels.extY;
                                    }

                                }
                            }
                            else
                            {
                                if(!bWithoutLabels) {
                                    vert_interval_height = checkFiniteNumber((rect.h - first_vert_label_half_height - last_vert_label_half_height) / (arr_val[arr_val.length - 1] - arr_val[0]));
                                    if (first_vert_label_half_height + (crosses_x - arr_val[0]) * vert_interval_height < x_ax.labels.extY) {
                                        vert_interval_height = checkFiniteNumber((rect.h - x_ax.labels.extY - last_vert_label_half_height) / (arr_val[arr_val.length - 1] - crosses_x));
                                    }

                                    x_ax.posY = rect.y + last_vert_label_half_height + (arr_val[arr_val.length - 1] - crosses_x) * vert_interval_height;
                                    x_ax.labels.y = x_ax.posY;
                                    for (i = 0; i < arr_val.length; ++i) {
                                        arr_y_points[i] = x_ax.posY - (arr_val[i] - crosses_x) * vert_interval_height;
                                    }
                                }
                                else{
                                    vert_interval_height = checkFiniteNumber(rect.h / (arr_val[arr_val.length - 1] - arr_val[0]));


                                    x_ax.posY = rect.y + (arr_val[arr_val.length - 1] - crosses_x) * vert_interval_height;
                                    x_ax.labels.y = x_ax.posY;
                                    for (i = 0; i < arr_val.length; ++i) {
                                        arr_y_points[i] = x_ax.posY - (arr_val[i] - crosses_x) * vert_interval_height;
                                    }


                                    var bCheckXLabels = false;
                                    if(x_ax.labels.y < 0){
                                        bCheckXLabels = true;
                                        rect.y -= x_ax.labels.y;
                                        rect.h -= x_ax.labels.h;
                                    }
                                    if(x_ax.labels.y + x_ax.labels.extY > this.extY){
                                        bCheckXLabels = true;
                                        rect.h -= (x_ax.labels.y + x_ax.labels.extY - this.extY)
                                    }
                                    if(bCheckXLabels){
                                        vert_interval_height = checkFiniteNumber(rect.h / (arr_val[arr_val.length - 1] - arr_val[0]));
                                        x_ax.posY = rect.y + (arr_val[arr_val.length - 1] - crosses_x) * vert_interval_height;
                                        x_ax.labels.y = x_ax.posY;
                                        for (i = 0; i < arr_val.length; ++i) {
                                            arr_y_points[i] = x_ax.posY - (arr_val[i] - crosses_x) * vert_interval_height;
                                        }
                                    }

                                }
                            }
                            break;
                        }
                    }
                }
                else
                {
                    switch(tick_labels_pos_x)
                    {
                        case c_oAscTickLabelsPos.TICK_LABEL_POSITION_HIGH:
                        {
                            bottom_gap = Math.max(last_vert_label_half_height, x_ax.labels.extY);
                            if(!bWithoutLabels) {
                                vert_interval_height = checkFiniteNumber((rect.h - bottom_gap - first_vert_label_half_height) / (arr_val[arr_val.length - 1] - arr_val[0]));
                                x_ax.posY = rect.y + first_vert_label_half_height + (crosses_x - arr_val[0]) * vert_interval_height;
                                for (i = 0; i < arr_val.length; ++i) {
                                    arr_y_points[i] = x_ax.posY + vert_interval_height * (arr_val[i] - crosses_x);
                                }
                                x_ax.labels.y = x_ax.posY + vert_interval_height * (arr_val[arr_val.length - 1] - crosses_x);
                            }
                            else{
                                vert_interval_height = checkFiniteNumber(rect.h / (arr_val[arr_val.length - 1] - arr_val[0]));
                                x_ax.posY = rect.y + (crosses_x - arr_val[0]) * vert_interval_height;
                                for (i = 0; i < arr_val.length; ++i) {
                                    arr_y_points[i] = x_ax.posY + vert_interval_height * (arr_val[i] - crosses_x);
                                }
                                x_ax.labels.y = x_ax.posY + vert_interval_height * (arr_val[arr_val.length - 1] - crosses_x);


                                var bCheckXLabels = false;
                                if(x_ax.labels.y < 0){
                                    bCheckXLabels = true;
                                    rect.y -= x_ax.labels.y;
                                    rect.h -= x_ax.labels.h;
                                }
                                if(x_ax.labels.y + x_ax.labels.extY > this.extY){
                                    bCheckXLabels = true;
                                    rect.h -= (x_ax.labels.y + x_ax.labels.extY - this.extY)
                                }
                                if(bCheckXLabels){
                                    vert_interval_height = checkFiniteNumber(rect.h / (arr_val[arr_val.length - 1] - arr_val[0]));
                                    x_ax.posY = rect.y + (crosses_x - arr_val[0]) * vert_interval_height;
                                    for (i = 0; i < arr_val.length; ++i) {
                                        arr_y_points[i] = x_ax.posY + vert_interval_height * (arr_val[i] - crosses_x);
                                    }
                                    x_ax.labels.y = x_ax.posY + vert_interval_height * (arr_val[arr_val.length - 1] - crosses_x);
                                }

                            }
                            break;
                        }
                        case c_oAscTickLabelsPos.TICK_LABEL_POSITION_LOW:
                        {
                            top_height = Math.max(x_ax.labels.extY, first_vert_label_half_height);

                            bottom_align_labels = false;
                            if(!bWithoutLabels) {
                                vert_interval_height = checkFiniteNumber((rect.h - top_height - last_vert_label_half_height) / (arr_val[arr_val.length - 1] - arr_val[0]));
                                x_ax.posY = rect.y + top_height + (crosses_x - arr_val[0]) * vert_interval_height;
                                for (i = 0; i < arr_val.length; ++i) {
                                    arr_y_points[i] = rect.y + top_height + vert_interval_height * (arr_val[i] - arr_val[0]);
                                }
                                x_ax.labels.y = rect.y + top_height - x_ax.labels.extY;
                            }
                            else{
                                vert_interval_height = checkFiniteNumber(rect.h / (arr_val[arr_val.length - 1] - arr_val[0]));
                                x_ax.posY = rect.y + (crosses_x - arr_val[0]) * vert_interval_height;
                                for (i = 0; i < arr_val.length; ++i) {
                                    arr_y_points[i] = rect.y + vert_interval_height * (arr_val[i] - arr_val[0]);
                                }
                                x_ax.labels.y = rect.y - x_ax.labels.extY;


                                var bCheckXLabels = false;
                                if(x_ax.labels.y < 0){
                                    bCheckXLabels = true;
                                    rect.y -= x_ax.labels.y;
                                    rect.h -= x_ax.labels.h;
                                }
                                if(x_ax.labels.y + x_ax.labels.extY > this.extY){
                                    bCheckXLabels = true;
                                    rect.h -= (x_ax.labels.y + x_ax.labels.extY - this.extY)
                                }
                                if(bCheckXLabels){
                                    vert_interval_height = checkFiniteNumber(rect.h / (arr_val[arr_val.length - 1] - arr_val[0]));
                                    x_ax.posY = rect.y + (crosses_x - arr_val[0]) * vert_interval_height;
                                    for (i = 0; i < arr_val.length; ++i) {
                                        arr_y_points[i] = rect.y + vert_interval_height * (arr_val[i] - arr_val[0]);
                                    }
                                    x_ax.labels.y = rect.y - x_ax.labels.extY;
                                }
                            }
                            break;
                        }
                        case c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE:
                        {
                            x_ax.labels = null;
                            if(!bWithoutLabels){
                                vert_interval_height = checkFiniteNumber((rect.h - first_vert_label_half_height - last_vert_label_half_height)/(arr_val[arr_val.length-1] - arr_val[0]));
                                x_ax.posY = rect.y + first_vert_label_half_height + (crosses_x-arr_val[0])*vert_interval_height;
                                for(i = 0; i < arr_val.length;++i)
                                {
                                    arr_y_points[i] = rect.y + first_vert_label_half_height + vert_interval_height*(arr_val[i] - arr_val[0]);
                                }
                            }
                            else{
                                vert_interval_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length-1] - arr_val[0]));
                                x_ax.posY = rect.y + (crosses_x-arr_val[0])*vert_interval_height;
                                for(i = 0; i < arr_val.length;++i)
                                {
                                    arr_y_points[i] = rect.y + vert_interval_height*(arr_val[i] - arr_val[0]);
                                }
                            }
                            break;
                        }
                        default :
                        {//c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO рядом с осью
                            if(x_ax.crosses === AscFormat.CROSSES_MAX)
                            {
                                bottom_gap = Math.max(x_ax.labels.extY, last_vert_label_half_height);


                                if(!bWithoutLabels) {
                                    vert_interval_height = checkFiniteNumber((rect.h - bottom_gap - first_vert_label_half_height) / (arr_val[arr_val.length - 1] - arr_val[0]));
                                    x_ax.posY = rect.y + first_vert_label_half_height + (crosses_x - arr_val[0]) * vert_interval_height;
                                    for (i = 0; i < arr_val.length; ++i) {
                                        arr_y_points[i] = rect.y + first_vert_label_half_height + vert_interval_height * (arr_val[i] - arr_val[0]);
                                    }
                                    x_ax.labels.y = rect.y + rect.extY - bottom_gap;
                                }
                                else{
                                    vert_interval_height = checkFiniteNumber(rect.h / (arr_val[arr_val.length - 1] - arr_val[0]));
                                    x_ax.posY = rect.y + (crosses_x - arr_val[0]) * vert_interval_height;
                                    for (i = 0; i < arr_val.length; ++i) {
                                        arr_y_points[i] = rect.y + vert_interval_height * (arr_val[i] - arr_val[0]);
                                    }
                                    x_ax.labels.y = rect.y + rect.extY;


                                    var bCheckXLabels = false;
                                    if(x_ax.labels.y < 0){
                                        bCheckXLabels = true;
                                        rect.y -= x_ax.labels.y;
                                        rect.h -= x_ax.labels.h;
                                    }
                                    if(x_ax.labels.y + x_ax.labels.extY > this.extY){
                                        bCheckXLabels = true;
                                        rect.h -= (x_ax.labels.y + x_ax.labels.extY - this.extY)
                                    }
                                    if(bCheckXLabels){
                                        vert_interval_height = checkFiniteNumber(rect.h / (arr_val[arr_val.length - 1] - arr_val[0]));
                                        x_ax.posY = rect.y + (crosses_x - arr_val[0]) * vert_interval_height;
                                        for (i = 0; i < arr_val.length; ++i) {
                                            arr_y_points[i] = rect.y + vert_interval_height * (arr_val[i] - arr_val[0]);
                                        }
                                        x_ax.labels.y = rect.y + rect.extY;
                                    }
                                }
                            }
                            else
                            {
                                bottom_align_labels = false;

                                if(!bWithoutLabels) {

                                    vert_interval_height = checkFiniteNumber((rect.h - last_vert_label_half_height - first_vert_label_half_height) / (arr_val[arr_val.length - 1] - arr_val[0]));
                                    if (first_vert_label_half_height + (crosses_x - arr_val[0]) * vert_interval_height < x_ax.labels.extY) {
                                        x_ax.posY = rect.y + x_ax.labels.extY;
                                        vert_interval_height = checkFiniteNumber((rect.h - x_ax.labels.extY - last_vert_label_half_height) / (arr_val[arr_val.length - 1] - crosses_x));
                                    }
                                    else {
                                        x_ax.posY = rect.y + rect.h - vert_interval_height * (arr_val[arr_val.length - 1] - crosses_x) - last_vert_label_half_height;
                                    }
                                    x_ax.labels.y = x_ax.posY - x_ax.labels.extY;
                                    for (i = 0; i < arr_val.length; ++i) {
                                        arr_y_points[i] = x_ax.posY + vert_interval_height * (arr_val[i] - crosses_x);
                                    }
                                }
                                else{
                                    vert_interval_height = checkFiniteNumber(rect.h / (arr_val[arr_val.length - 1] - arr_val[0]));
                                    x_ax.posY = rect.y + rect.h - vert_interval_height * (arr_val[arr_val.length - 1] - crosses_x);
                                    x_ax.labels.y = x_ax.posY - x_ax.labels.extY;
                                    for (i = 0; i < arr_val.length; ++i) {
                                        arr_y_points[i] = x_ax.posY + vert_interval_height * (arr_val[i] - crosses_x);
                                    }

                                    var bCheckXLabels = false;
                                    if(x_ax.labels.y < 0){
                                        bCheckXLabels = true;
                                        rect.y -= x_ax.labels.y;
                                        rect.h -= x_ax.labels.h;
                                    }
                                    if(x_ax.labels.y + x_ax.labels.extY > this.extY){
                                        bCheckXLabels = true;
                                        rect.h -= (x_ax.labels.y + x_ax.labels.extY - this.extY)
                                    }
                                    if(bCheckXLabels){
                                        vert_interval_height = checkFiniteNumber(rect.h / (arr_val[arr_val.length - 1] - arr_val[0]));
                                        x_ax.posY = rect.y + rect.h - vert_interval_height * (arr_val[arr_val.length - 1] - crosses_x);
                                        x_ax.labels.y = x_ax.posY - x_ax.labels.extY;
                                        for (i = 0; i < arr_val.length; ++i) {
                                            arr_y_points[i] = x_ax.posY + vert_interval_height * (arr_val[i] - crosses_x);
                                        }
                                    }
                                }
                            }
                            break;
                        }
                    }
                }
                y_ax.interval = vert_interval_height;

                y_ax.yPoints = [];
                for(i = 0; i < arr_val.length; ++i)
                {
                    y_ax.yPoints.push({pos: arr_y_points[i], val: arr_val[i]});
                }


                x_ax.xPoints = [];
                for(i = 0; i < arr_x_val.length; ++i)
                {
                    x_ax.xPoints.push({pos: arr_x_points[i], val: arr_x_val[i]});
                }

                var arr_labels;
                var text_transform;
                var local_text_transform;
                if(x_ax.bDelete)
                {
                    x_ax.labels = null;
                }
                if(y_ax.bDelete)
                {
                    y_ax.labels = null;
                }
                if(x_ax.labels)
                {
                    arr_labels = x_ax.labels.aLabels;
                    x_ax.labels.align = bottom_align_labels;
                    if(bottom_align_labels)
                    {
                        var top_line = x_ax.labels.y + vert_gap;
                        for(i = 0; i < arr_labels.length; ++i)
                        {
                            if(arr_labels[i])
                            {
                                arr_labels[i].txBody = arr_labels[i].tx.rich;
                                text_transform = arr_labels[i].transformText;


                                text_transform.Reset();
                                global_MatrixTransformer.TranslateAppend(text_transform, arr_x_points[i] - arr_labels[i].tx.rich.content.XLimit/2, top_line);
                               // global_MatrixTransformer.MultiplyAppend(text_transform, this.getTransformMatrix());


                                local_text_transform = arr_labels[i].localTransformText;
                                local_text_transform.Reset();
                                global_MatrixTransformer.TranslateAppend(local_text_transform, arr_x_points[i] - arr_labels[i].tx.rich.content.XLimit/2, top_line);
                            }
                        }
                    }
                    else
                    {
                        for(i = 0; i < arr_labels.length; ++i)
                        {
                            if(arr_labels[i])
                            {
                                arr_labels[i].txBody = arr_labels[i].tx.rich;
                                text_transform = arr_labels[i].transformText;
                                text_transform.Reset();
                                global_MatrixTransformer.TranslateAppend(text_transform, arr_x_points[i] - arr_labels[i].tx.rich.content.XLimit/2, x_ax.labels.y + x_ax.labels.extY - vert_gap - arr_labels[i].tx.rich.content.GetSummaryHeight());
                              //  global_MatrixTransformer.MultiplyAppend(text_transform, this.getTransformMatrix());

                                local_text_transform = arr_labels[i].localTransformText;
                                local_text_transform.Reset();
                                global_MatrixTransformer.TranslateAppend(local_text_transform, arr_x_points[i] - arr_labels[i].tx.rich.content.XLimit/2, x_ax.labels.y + x_ax.labels.extY - vert_gap - arr_labels[i].tx.rich.content.GetSummaryHeight());

                            }
                        }
                    }
                }


                if(y_ax.labels)
                {
                    if(bNeedReflect)
                    {
                        if(left_align_labels)
                        {
                            left_align_labels = false;
                            y_ax.labels.x += y_ax.labels.extX;
                        }
                        else
                        {
                            left_align_labels = true;
                            y_ax.labels.x -= y_ax.labels.extX;
                        }
                    }
                    y_ax.labels.align = left_align_labels;
                    arr_labels = y_ax.labels.aLabels;
                    if(left_align_labels)
                    {
                        for(i = 0; i < arr_labels.length; ++i)
                        {
                            if(arr_labels[i])
                            {
                                arr_labels[i].txBody = arr_labels[i].tx.rich;
                                text_transform = arr_labels[i].transformText;
                                text_transform.Reset();
                                global_MatrixTransformer.TranslateAppend(text_transform, y_ax.labels.x + y_ax.labels.extX - hor_gap - arr_labels[i].tx.rich.content.XLimit, arr_y_points[i] - arr_labels[i].tx.rich.content.GetSummaryHeight()/2);
                           //     global_MatrixTransformer.MultiplyAppend(text_transform, this.getTransformMatrix());

                                local_text_transform = arr_labels[i].localTransformText;
                                local_text_transform.Reset();
                                global_MatrixTransformer.TranslateAppend(local_text_transform, y_ax.labels.x + y_ax.labels.extX - hor_gap - arr_labels[i].tx.rich.content.XLimit, arr_y_points[i] - arr_labels[i].tx.rich.content.GetSummaryHeight()/2);
                            }
                        }
                    }
                    else
                    {
                        for(i = 0; i < arr_labels.length; ++i)
                        {
                            if(arr_labels[i])
                            {
                                arr_labels[i].txBody = arr_labels[i].tx.rich;
                                text_transform = arr_labels[i].transformText;
                                text_transform.Reset();
                                global_MatrixTransformer.TranslateAppend(text_transform, y_ax.labels.x + hor_gap, arr_y_points[i] - arr_labels[i].tx.rich.content.GetSummaryHeight()/2);
                           //     global_MatrixTransformer.MultiplyAppend(text_transform, this.getTransformMatrix());

                                local_text_transform = arr_labels[i].transformText;
                                local_text_transform.Reset();
                                global_MatrixTransformer.TranslateAppend(local_text_transform, y_ax.labels.x + hor_gap, arr_y_points[i] - arr_labels[i].tx.rich.content.GetSummaryHeight()/2);

                            }
                        }
                    }
                }

                if(y_ax.labels)
                {
                    if(y_ax_orientation === AscFormat.ORIENTATION_MIN_MAX)
                    {
                        var t = y_ax.labels.aLabels[y_ax.labels.aLabels.length-1].tx.rich.content.GetSummaryHeight()/2;
                        y_ax.labels.y = arr_y_points[arr_y_points.length-1] - t;
                        y_ax.labels.extY = arr_y_points[0] - arr_y_points[arr_y_points.length-1] + t + y_ax.labels.aLabels[0].tx.rich.content.GetSummaryHeight()/2;
                    }
                    else
                    {
                        var t = y_ax.labels.aLabels[0].tx.rich.content.GetSummaryHeight()/2;
                        y_ax.labels.y = arr_y_points[0] - t;
                        y_ax.labels.extY = arr_y_points[arr_y_points.length-1] - arr_y_points[0] + t + y_ax.labels.aLabels[y_ax.labels.aLabels.length-1].tx.rich.content.GetSummaryHeight()/2;
                    }
                }

                if(x_ax.labels)
                {
                    if(x_ax_orientation === AscFormat.ORIENTATION_MIN_MAX)
                    {
                        var t = x_ax.labels.aLabels[0].tx.rich.content.XLimit/2;
                        x_ax.labels.x = arr_x_points[0] - t;
                        x_ax.labels.extX = arr_x_points[arr_x_points.length-1] + x_ax.labels.aLabels[x_ax.labels.aLabels.length-1].tx.rich.content.XLimit/2 - x_ax.labels.x;
                    }
                    else
                    {
                        var t = x_ax.labels.aLabels[x_ax.labels.aLabels.length-1].tx.rich.content.XLimit/2;
                        x_ax.labels.x = arr_x_points[arr_x_points.length-1] - t;
                        x_ax.labels.extX = arr_x_points[0] + x_ax.labels.aLabels[0].tx.rich.content.XLimit/2 - x_ax.labels.x;
                    }
                }
                /*new recalc*/
            }
        }
        else if(chart_type !== AscDFH.historyitem_type_BarChart && (chart_type !== AscDFH.historyitem_type_PieChart && chart_type !== AscDFH.historyitem_type_DoughnutChart)
            || (chart_type === AscDFH.historyitem_type_BarChart && chart_object.barDir !== AscFormat.BAR_DIR_BAR))
        {
            var cat_ax, val_ax, ser_ax;
            val_ax = this.chart.plotArea.valAx;
            cat_ax = this.chart.plotArea.catAx;
            ser_ax = this.chart.plotArea.serAx;
            if(val_ax && cat_ax)
            {
                val_ax.labels  = null;
                cat_ax.labels  = null;
                if(ser_ax){
                    ser_ax.labels = null;
                    ser_ax.posY  = null;
                    ser_ax.posX  = null;
                    ser_ax.xPoints = null;
                    ser_ax.yPoints = null;
                }

                val_ax.posX  = null;
                cat_ax.posY  = null;
                val_ax.posY  = null;
                cat_ax.posX  = null;

                val_ax.xPoints = null;
                cat_ax.yPoints = null;
                val_ax.yPoints = null;
                cat_ax.xPoints = null;
                var sizes = this.getChartSizes();
                rect = {x: sizes.startX, y:sizes.startY, w:sizes.w, h: sizes.h};
                var arr_val =  this.getValAxisValues();
                //Получим строки для оси значений с учетом формата и единиц
                var arr_strings = [];
                var multiplier;
                if(val_ax.dispUnits)
                    multiplier = val_ax.dispUnits.getMultiplier();
                else
                    multiplier = 1;
                var num_fmt = val_ax.numFmt;
                if(num_fmt && typeof num_fmt.formatCode === "string" /*&& !(num_fmt.formatCode === "General")*/)
                {
                    var num_format = oNumFormatCache.get(num_fmt.formatCode);
                    for(i = 0; i < arr_val.length; ++i)
                    {
                        var calc_value = arr_val[i]*multiplier;
                        var rich_value = num_format.formatToChart(calc_value);
                        arr_strings.push(rich_value);
                    }
                }
                else
                {
                    for(i = 0; i < arr_val.length; ++i)
                    {
                        var calc_value = arr_val[i]*multiplier;
                        arr_strings.push(calc_value + "");
                    }
                }


                /*если у нас шкала логарифмическая то будем вместо полученных значений использовать логарифм*/

                val_ax.labels = new AscFormat.CValAxisLabels(this, val_ax);
                var max_width = 0;
                val_ax.yPoints = [];

                var max_val_labels_text_height = 0;
                var lastStyleObject = null;
                for(i = 0; i < arr_strings.length; ++i)
                {
                    var dlbl = new AscFormat.CDLbl();
                    if(lastStyleObject)
                    {
                        dlbl.lastStyleObject = lastStyleObject;
                    }
                    dlbl.parent = val_ax;
                    dlbl.chart = this;
                    dlbl.spPr = val_ax.spPr;
                    dlbl.txPr = val_ax.txPr;
                    dlbl.tx = new AscFormat.CChartText();
                    dlbl.tx.rich = AscFormat.CreateTextBodyFromString(arr_strings[i], this.getDrawingDocument(), dlbl);
                    var t = dlbl.tx.rich.recalculateByMaxWord();
                    if(!lastStyleObject)
                    {
                        lastStyleObject = dlbl.lastStyleObject;
                    }
                    var cur_width = t.w;
                    if(cur_width > max_width)
                        max_width = cur_width;
                    if(t.h > max_val_labels_text_height)
                        max_val_labels_text_height = t.h;
                    val_ax.labels.aLabels.push(dlbl);
                    val_ax.yPoints.push({val: arr_val[i], pos: null});

                }
                var val_axis_labels_gap = val_ax.labels.aLabels[0].tx.rich.content.Content[0].CompiledPr.Pr.TextPr.FontSize*25.4/72;
                val_ax.labels.extX = max_width + val_axis_labels_gap;

                //расчитаем подписи для горизонтальной оси
                var ser = chart_object.series[0];
                var string_pts = [], pts_len = 0;

                /*string_pts  pts_len*/
                if(ser && ser.cat)
                {
                    var  lit, b_num_lit = true;
                    if(ser.cat.strRef && ser.cat.strRef.strCache)
                    {
                        lit = ser.cat.strRef.strCache;
                    }
                    else if(ser.cat.strLit)
                    {
                        lit = ser.cat.strLit;
                    }
                    else if(ser.cat.numRef && ser.cat.numRef.numCache)
                    {
                        lit = ser.cat.numRef.numCache;
                        b_num_lit = true;
                    }
                    else if(ser.cat.numLit)
                    {
                        lit = ser.cat.numLit;
                        b_num_lit = true;
                    }
                    if(lit)
                    {
                        var lit_format = null, pt_format = null;
                        if(b_num_lit && typeof lit.formatCode === "string" && lit.formatCode.length > 0)
                        {
                            lit_format = oNumFormatCache.get(lit.formatCode);
                        }
                        pts_len = lit.ptCount;
                        for(i = 0; i < pts_len; ++i)
                        {
                            var pt = lit.getPtByIndex(i);
                            if(pt)
                            {
                                var str_pt;
                                if(b_num_lit)
                                {
                                    if(typeof pt.formatCode === "string" && pt.formatCode.length > 0)
                                    {
                                        pt_format = oNumFormatCache.get(pt.formatCode);
                                        if(pt_format)
                                        {
                                            str_pt = pt_format.formatToChart(pt.val);
                                        }
                                        else
                                        {
                                            str_pt = pt.val;
                                        }
                                    }
                                    else if(lit_format)
                                    {
                                        str_pt = lit_format.formatToChart(pt.val);
                                    }
                                    else
                                    {
                                        str_pt = pt.val;
                                    }
                                }
                                else
                                {
                                    str_pt = pt.val;
                                }
                                string_pts.push({val: str_pt + ""});
                            }
                            else
                            {
                                string_pts.push({val: /*i + */""});
                            }
                        }
                    }
                }


                var cross_between = this.getValAxisCrossType();

                if(cross_between === null){
                    cross_between = AscFormat.CROSS_BETWEEN_BETWEEN;
                }
                //if(string_pts.length === 0)
                {
                    pts_len = 0;
                    for(i = 0; i < chart_object.series.length; ++i)
                    {
                        var cur_pts= null;
                        ser = chart_object.series[i];
                        if(ser.val)
                        {
                            if(ser.val.numRef && ser.val.numRef.numCache)
                                cur_pts = ser.val.numRef.numCache;
                            else if(ser.val.numLit)
                                cur_pts = ser.val.numLit;
                            if(cur_pts)
                            {
                                pts_len = Math.max(pts_len, cur_pts.ptCount);
                            }
                        }
                    }
                    if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT && pts_len < 2)
                    {
                        pts_len = 2;
                    }
                    if(pts_len > string_pts.length)
                    {
                        for(i = string_pts.length; i < pts_len; ++i)
                        {
                            string_pts.push({val:i+1 + ""});
                        }
                    }
                    else
                    {
                        string_pts.splice(pts_len, string_pts.length - pts_len);
                    }
                }




                /*---------------------расчет позиции блока с подписями вертикальной оси-----------------------------------------------------------------------------*/
                //расчитаем ширину интервала без учета горизонтальной оси;
                var crosses;//номер категории в которой вертикалная ось пересекает горизонтальную;
                if(val_ax.crosses === AscFormat.CROSSES_AUTO_ZERO || val_ax.crosses === AscFormat.CROSSES_MIN)
                    crosses = 1;
                else if(val_ax.crosses === AscFormat.CROSSES_MAX)
                    crosses = string_pts.length;
                else if(AscFormat.isRealNumber(val_ax.crossesAt))
                {
                    if(val_ax.crossesAt <= string_pts.length + 1 && val_ax.crossesAt > 0)
                        crosses = val_ax.crossesAt;
                    else if(val_ax.crossesAt <= 0)
                        crosses = 1;
                    else
                        crosses = string_pts.length;
                }
                else
                    crosses = 1;

                cat_ax.maxCatVal = string_pts.length;

                var cat_ax_orientation = cat_ax.scaling && AscFormat.isRealNumber(cat_ax.scaling.orientation) ?  cat_ax.scaling.orientation : AscFormat.ORIENTATION_MIN_MAX;
                var point_width = rect.w/string_pts.length;
                var labels_pos = val_ax.tickLblPos;
                if(val_ax.bDelete)
                {
                    labels_pos = c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE;
                }
                // if(string_pts.length === 1)
                // {
                //     cross_between = AscFormat.CROSS_BETWEEN_BETWEEN;
                // }
                var left_val_ax_labels_align = true;//приленгание подписей оси значений к левому краю.

                var intervals_count = cross_between === AscFormat.CROSS_BETWEEN_MID_CAT ? string_pts.length - 1 : string_pts.length;
                var point_interval  = rect.w/intervals_count;//интервал между точками. Зависит от crossBetween, а также будет потом корректироваться в зависимости от подписей вертикальной и горизонтальной оси.

                if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                    point_interval = checkFiniteNumber(rect.w/(string_pts.length - 1));
                else
                    point_interval = checkFiniteNumber(rect.w/string_pts.length);

                var left_points_width, right_point_width;
                var arr_cat_labels_points = [];//массив середин подписей горизонтальной оси; i-й элемент - x-координата центра подписи категории с номером i;
                if(cat_ax_orientation === AscFormat.ORIENTATION_MIN_MAX)
                {
                    if(labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO || !AscFormat.isRealNumber(labels_pos)) //подписи рядом с осью
                    {
                        if(val_ax.crosses === AscFormat.CROSSES_MAX)
                        {
                            left_val_ax_labels_align = false;
                            if(!bWithoutLabels){
                                val_ax.labels.x = rect.x + rect.w - val_ax.labels.extX;
                                if(!bNeedReflect)
                                {
                                    point_interval =  checkFiniteNumber((rect.w - val_ax.labels.extX)/intervals_count);
                                }
                                else
                                {
                                    point_interval = checkFiniteNumber(rect.w/intervals_count);
                                }
                                val_ax.posX = val_ax.labels.x;
                                if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = rect.x + point_interval*i;
                                }
                                else
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = point_interval/2 + rect.x + point_interval*i;
                                }
                            }
                            else{
                                val_ax.labels.x = rect.x + rect.w;
                                if(val_ax.labels.x < 0 && !bNeedReflect){
                                    rect.x -= val_ax.labels.x;
                                    rect.w += val_ax.labels.x;
                                    val_ax.labels.x = 0;
                                    bCorrectedLayoutRect = true;
                                }
                                if(rect.x + rect.w > this.extX){
                                    rect.w -= (rect.x + rect.w - this.extX);
                                    bCorrectedLayoutRect = true;
                                }

                                point_interval = checkFiniteNumber(rect.w/intervals_count);
                                val_ax.posX = val_ax.labels.x;
                                if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = rect.x + point_interval*i;
                                }
                                else
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = point_interval/2 + rect.x + point_interval*i;
                                }
                            }
                        }
                        else
                        {
                            left_points_width = point_interval*(crosses-1);//общая ширина левых точек если считать что точки занимают все пространство
                            if(!bWithoutLabels) {
                                if (!bNeedReflect && left_points_width < val_ax.labels.extX)//подписи верт. оси выходят за пределы области построения
                                {
                                    var right_intervals_count = intervals_count - (crosses - 1);//количесво интервалов правее вертикальной оси
                                    //скорректируем point_interval, поделив расстояние, которое осталось справа от подписей осей на количество интервалов справа
                                    point_interval = checkFiniteNumber((rect.w - val_ax.labels.extX) / right_intervals_count);
                                    val_ax.labels.x = rect.x;
                                    var start_point = val_ax.labels.x + val_ax.labels.extX - (crosses - 1) * point_interval;//x-координата точки, где начинается собственно область диаграммы
                                    if (cross_between === AscFormat.CROSS_BETWEEN_MID_CAT) {
                                        for (i = 0; i < string_pts.length; ++i)
                                            arr_cat_labels_points[i] = start_point + point_interval * i;
                                    }
                                    else {
                                        for (i = 0; i < string_pts.length; ++i)
                                            arr_cat_labels_points[i] = point_interval / 2 + start_point + point_interval * i;
                                    }
                                }
                                else {
                                    val_ax.labels.x = rect.x + left_points_width - val_ax.labels.extX;
                                    if (cross_between === AscFormat.CROSS_BETWEEN_MID_CAT) {
                                        for (i = 0; i < string_pts.length; ++i)
                                            arr_cat_labels_points[i] = rect.x + point_interval * i;
                                    }
                                    else {
                                        for (i = 0; i < string_pts.length; ++i)
                                            arr_cat_labels_points[i] = point_interval / 2 + rect.x + point_interval * i;
                                    }

                                }
                                val_ax.posX = val_ax.labels.x + val_ax.labels.extX;
                            }
                            else{
                                val_ax.labels.x = rect.x + left_points_width - val_ax.labels.extX;
                                if(val_ax.labels.x < 0 && !bNeedReflect){
                                    rect.x -= val_ax.labels.x;
                                    rect.w += val_ax.labels.x;
                                    val_ax.labels.x = 0;
                                    bCorrectedLayoutRect = true;
                                }
                                if(rect.x + rect.w > this.extX){
                                    rect.w -= (rect.x + rect.w - this.extX);
                                    bCorrectedLayoutRect = true;
                                }

                                point_interval = checkFiniteNumber( rect.w/intervals_count);

                                if (cross_between === AscFormat.CROSS_BETWEEN_MID_CAT) {
                                    for (i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = rect.x + point_interval * i;
                                }
                                else {
                                    for (i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = point_interval / 2 + rect.x + point_interval * i;
                                }
                                val_ax.posX = val_ax.labels.x + val_ax.labels.extX;
                            }
                        }
                    }
                    else if(labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_LOW)//подписи слева от области построения
                    {
                        if(!bNeedReflect)
                        {
                            point_interval = checkFiniteNumber((rect.w -  val_ax.labels.extX)/intervals_count);
                        }
                        else
                        {
                            point_interval = checkFiniteNumber( rect.w/intervals_count);
                        }
                        val_ax.labels.x = rect.x;
                        if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                        {
                            if(!bNeedReflect)
                            {
                                for(i = 0; i < string_pts.length; ++i)
                                    arr_cat_labels_points[i] = rect.x + val_ax.labels.extX + point_interval*i;
                            }
                            else
                            {
                                for(i = 0; i < string_pts.length; ++i)
                                    arr_cat_labels_points[i] = rect.x + point_interval*i;
                            }
                        }
                        else
                        {
                            if(!bNeedReflect)
                            {
                                for(i = 0; i < string_pts.length; ++i)
                                    arr_cat_labels_points[i] = rect.x + val_ax.labels.extX + point_interval/2 + point_interval*i;
                            }
                            else
                            {
                                for(i = 0; i < string_pts.length; ++i)
                                    arr_cat_labels_points[i] = rect.x + point_interval/2 + point_interval*i;
                            }
                        }
                        val_ax.posX = val_ax.labels.x + val_ax.labels.extX + point_interval*(crosses-1);
                    }
                    else if(labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_HIGH)//подписи справа от области построения
                    {
                        if(!bNeedReflect)
                        {
                            point_interval = checkFiniteNumber( (rect.w - val_ax.labels.extX)/intervals_count);
                        }
                        else
                        {
                            point_interval = checkFiniteNumber( rect.w/intervals_count);
                        }

                        val_ax.labels.x = rect.x + rect.w - val_ax.labels.extX;
                        left_val_ax_labels_align = false;
                        if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = rect.x + point_interval*i;
                        }
                        else
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = point_interval/2 + rect.x + point_interval*i;
                        }
                        val_ax.posX = rect.x + point_interval*(crosses-1);
                    }
                    else
                    {
                        val_ax.labels = null;
                        if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = rect.x + point_interval*i;
                        }
                        else
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = point_interval/2 + rect.x + point_interval*i;
                        }
                        val_ax.posX = rect.x + point_interval*(crosses-1);
                    }
                }
                else
                {//то же самое, только зеркально отраженное
                    if(labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO || !AscFormat.isRealNumber(labels_pos)) //подписи рядом с осью
                    {
                        if(val_ax.crosses === AscFormat.CROSSES_MAX)
                        {
                            if(!bWithoutLabels){
                                val_ax.labels.x = rect.x;
                                if(!bNeedReflect)
                                {
                                    point_interval = checkFiniteNumber( (rect.w - val_ax.labels.extX)/intervals_count);
                                }
                                else
                                {
                                    point_interval = checkFiniteNumber( rect.w/intervals_count);
                                }
                                if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = rect.x + rect.w - point_interval*i;
                                }
                                else
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = rect.x + rect.w - point_interval/2 - point_interval*i;
                                }
                                if(!bNeedReflect)
                                {
                                    val_ax.posX = val_ax.labels.x + val_ax.labels.extX;
                                }
                                else
                                {
                                    val_ax.posX = val_ax.labels.x;
                                }
                            }
                            else{
                                val_ax.labels.x = rect.x - val_ax.labels.extX;
                                if(val_ax.labels.x < 0 && !bNeedReflect){
                                    rect.x -= val_ax.labels.x;
                                    rect.w += val_ax.labels.x;
                                    val_ax.labels.x = 0;
                                    bCorrectedLayoutRect = true;
                                }
                                if(rect.x + rect.w > this.extX){
                                    rect.w -= (rect.x + rect.w - this.extX);
                                    bCorrectedLayoutRect = true;
                                }

                                point_interval = checkFiniteNumber( rect.w/intervals_count);
                                if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = rect.x + rect.w - point_interval*i;
                                }
                                else
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = rect.x + rect.w - point_interval/2 - point_interval*i;
                                }
                                if(!bNeedReflect)
                                {
                                    val_ax.posX = val_ax.labels.x + val_ax.labels.extX;
                                }
                                else
                                {
                                    val_ax.posX = val_ax.labels.x;
                                }
                            }

                        }
                        else
                        {
                            left_val_ax_labels_align = false;
                            right_point_width = point_interval*(crosses-1);
                            if(!bNeedReflect && right_point_width < val_ax.labels.extX && !bWithoutLabels)
                            {
                                val_ax.labels.x = rect.x + rect.w - val_ax.labels.extX;
                                var left_points_interval_count = intervals_count - (crosses - 1);
                                point_interval = checkFiniteNumber( checkFiniteNumber( (val_ax.labels.x - rect.x)/left_points_interval_count));
                                var start_point_right = rect.x + point_interval*intervals_count;
                                if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = start_point_right - point_interval*i;
                                }
                                else
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = start_point_right - point_interval/2 - point_interval*i;
                                }
                            }
                            else
                            {
                                val_ax.labels.x = rect.x + rect.w - right_point_width;
                                if(val_ax.labels.x < 0 && !bNeedReflect){
                                    rect.x -= val_ax.labels.x;
                                    rect.w += val_ax.labels.x;
                                    val_ax.labels.x = 0;
                                    bCorrectedLayoutRect = true;
                                }
                                if(rect.x + rect.w > this.extX){
                                    rect.w -= (rect.x + rect.w - this.extX);
                                    bCorrectedLayoutRect = true;
                                }

                                point_interval = checkFiniteNumber( rect.w/intervals_count);
                                if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = rect.x + rect.w - point_interval*i;
                                }
                                else
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = rect.x + rect.w - point_interval/2 - point_interval*i;
                                }
                            }
                            val_ax.posX = val_ax.labels.x;
                        }
                    }
                    else if(labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_LOW)//подписи справа от области построения
                    {
                        left_val_ax_labels_align = false;
                        if(!bNeedReflect && !bWithoutLabels)
                        {
                            point_interval = checkFiniteNumber( (rect.w - val_ax.labels.extX)/intervals_count);
                        }
                        else
                        {
                            point_interval = checkFiniteNumber( rect.w/intervals_count);
                        }
                        if(!bWithoutLabels){
                            val_ax.labels.x = rect.x + rect.w - val_ax.labels.extX;

                            if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                            {
                                for(i = 0; i < string_pts.length; ++i)
                                    arr_cat_labels_points[i] = val_ax.labels.x - point_interval*i;
                            }
                            else
                            {
                                for(i = 0; i < string_pts.length; ++i)
                                    arr_cat_labels_points[i] = val_ax.labels.x - point_interval/2 - point_interval*i;
                            }
                            if(!bNeedReflect)
                            {
                                val_ax.posX = rect.x + rect.w - point_interval*(crosses-1) - val_ax.labels.extX;
                            }
                            else
                            {
                                val_ax.posX = rect.x + rect.w - point_interval*(crosses-1);
                            }

                        }
                        else{
                            val_ax.labels.x = rect.x + rect.w;

                            if(val_ax.labels.x < 0 && !bNeedReflect){
                                rect.x -= val_ax.labels.x;
                                rect.w += val_ax.labels.x;
                                val_ax.labels.x = 0;
                                bCorrectedLayoutRect = true;
                            }
                            if(rect.x + rect.w > this.extX){
                                rect.w -= (rect.x + rect.w - this.extX);
                                bCorrectedLayoutRect = true;
                            }

                            point_interval = checkFiniteNumber(rect.w/intervals_count);


                            if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                            {
                                for(i = 0; i < string_pts.length; ++i)
                                    arr_cat_labels_points[i] = val_ax.labels.x - point_interval*i;
                            }
                            else
                            {
                                for(i = 0; i < string_pts.length; ++i)
                                    arr_cat_labels_points[i] = val_ax.labels.x - point_interval/2 - point_interval*i;
                            }
                            if(!bNeedReflect)
                            {
                                val_ax.posX = rect.x + rect.w - point_interval*(crosses-1) - val_ax.labels.extX;
                            }
                            else
                            {
                                val_ax.posX = rect.x + rect.w - point_interval*(crosses-1);
                            }
                        }

                    }
                    else if(labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_HIGH)//подписи слева от области построения
                    {
                        if(!bNeedReflect && !bWithoutLabels)
                        {
                            point_interval = checkFiniteNumber((rect.w - val_ax.labels.extX)/intervals_count);
                        }
                        else
                        {
                            point_interval = checkFiniteNumber(rect.w/intervals_count);
                        }
                        if(!bWithoutLabels){
                            val_ax.labels.x = rect.x;

                            if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                            {
                                for(i = 0; i < string_pts.length; ++i)
                                    arr_cat_labels_points[i] = rect.x + rect.w - point_interval*i;
                            }
                            else
                            {
                                for(i = 0; i < string_pts.length; ++i)
                                    arr_cat_labels_points[i] = rect.x + rect.w - point_interval/2 - point_interval*i;
                            }
                            val_ax.posX = rect.x + rect.w - point_interval*(crosses-1);
                        }
                        else{
                            val_ax.labels.x = rect.x - val_ax.labels.extX;
                            if(val_ax.labels.x < 0 && !bNeedReflect){
                                rect.x -= val_ax.labels.x;
                                rect.w += val_ax.labels.x;
                                val_ax.labels.x = 0;
                                bCorrectedLayoutRect = true;
                            }
                            if(rect.x + rect.w > this.extX){
                                rect.w -= (rect.x + rect.w - this.extX);
                                bCorrectedLayoutRect = true;
                            }

                            point_interval = checkFiniteNumber(rect.w/intervals_count);
                            if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                            {
                                for(i = 0; i < string_pts.length; ++i)
                                    arr_cat_labels_points[i] = rect.x + rect.w - point_interval*i;
                            }
                            else
                            {
                                for(i = 0; i < string_pts.length; ++i)
                                    arr_cat_labels_points[i] = rect.x + rect.w - point_interval/2 - point_interval*i;
                            }
                            val_ax.posX = rect.x + rect.w - point_interval*(crosses-1);
                        }
                    }
                    else
                    {
                        val_ax.labels = null;
                        if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = rect.x + rect.w - point_interval*i;
                        }
                        else
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = rect.x + rect.w - point_interval/2 - point_interval*i;
                        }
                        val_ax.posX = rect.x + rect.w - point_interval*(crosses-1);
                    }
                }

                cat_ax.interval = point_interval;

                var diagram_width = point_interval*intervals_count;//размер области с самой диаграммой позже будет корректироватся;



                var bTickSkip =  AscFormat.isRealNumber(cat_ax.tickLblSkip);
                var tick_lbl_skip = AscFormat.isRealNumber(cat_ax.tickLblSkip) ? cat_ax.tickLblSkip :  1;
                var max_cat_label_width = diagram_width / string_pts.length; // максимальная ширина подписи горизонтальной оси;


                cat_ax.labels = null;
                var b_rotated = false;//флаг означает, что водписи не уместились в отведенное для них пространство и их пришлось перевернуть.
                //проверим умещаются ли подписи горизонтальной оси в point_interval
                if(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE !== cat_ax.tickLblPos && !(cat_ax.bDelete === true)) //будем корректировать вертикальные подписи только если есть горизонтальные
                {
                    cat_ax.labels = new AscFormat.CValAxisLabels(this, cat_ax);

                    var max_min_width = 0;
                    var max_max_width = 0;
                    var arr_max_contents = [];
                    var fMaxContentStringH = 0;
                    for(i = 0; i < string_pts.length; ++i)
                    {
                        var dlbl = null;
                        if(i%tick_lbl_skip === 0)
                        {
                            dlbl = new AscFormat.CDLbl();
                            dlbl.parent = cat_ax;
                            dlbl.chart = this;
                            dlbl.spPr = cat_ax.spPr;
                            dlbl.txPr = cat_ax.txPr;
                            dlbl.tx = new AscFormat.CChartText();
                            dlbl.tx.rich = AscFormat.CreateTextBodyFromString(string_pts[i].val.replace(oNonSpaceRegExp, ' '), this.getDrawingDocument(), dlbl);
                            //dlbl.recalculate();

                            var content = dlbl.tx.rich.content;
                            content.Set_ApplyToAll(true);
                            content.SetParagraphAlign(AscCommon.align_Center);
                            content.Set_ApplyToAll(false);
                            dlbl.txBody = dlbl.tx.rich;
                            if(cat_ax.labels.aLabels.length > 0)
                            {
                                dlbl.lastStyleObject = cat_ax.labels.aLabels[0].lastStyleObject;
                            }
                            var min_max =  dlbl.tx.rich.content.RecalculateMinMaxContentWidth();
                            var max_min_content_width = min_max.Min;
                            if(max_min_content_width > max_min_width)
                                max_min_width = max_min_content_width;
                            if(min_max.Max > max_max_width)
                                max_max_width = min_max.Max;
                            if(dlbl.tx.rich.content.Content[0].Content[0].TextHeight > fMaxContentStringH){
                                fMaxContentStringH = dlbl.tx.rich.content.Content[0].Content[0].TextHeight;
                            }
                        }
                        cat_ax.labels.aLabels.push(dlbl);
                    }

                    fMaxContentStringH *= 1;
                    var stake_offset = AscFormat.isRealNumber(cat_ax.lblOffset) ? cat_ax.lblOffset/100 : 1;
                    var labels_offset = cat_ax.labels.aLabels[0].tx.rich.content.Content[0].CompiledPr.Pr.TextPr.FontSize*(25.4/72)*stake_offset;
                    if(max_min_width < max_cat_label_width)//значит текст каждой из точек умещается в point_width
                    {
                        var max_height = 0;
                        for(i = 0; i < cat_ax.labels.aLabels.length; ++i)
                        {
                            if(cat_ax.labels.aLabels[i])
                            {
                                var content = cat_ax.labels.aLabels[i].tx.rich.content;
                                content.Reset(0, 0, max_cat_label_width, 20000);
                                content.Recalculate_Page(0, true);
                                var cur_height = content.GetSummaryHeight();
                                if(cur_height > max_height)
                                    max_height = cur_height;
                            }
                        }

                        cat_ax.labels.extY = max_height + labels_offset;
                        if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT) //корректируем позиции центров подписей горизонтальной оси, положение  вертикальной оси и её подписей
                        {
                            var left_gap_point, right_gap_point;
                            if(cat_ax_orientation === AscFormat.ORIENTATION_MIN_MAX)
                            {
                                var first_label_left_gap = cat_ax.labels.aLabels[0].tx.rich.getMaxContentWidth(max_cat_label_width)/2;//на сколько вправа выходит первая подпись
                                var last_labels_right_gap = cat_ax.labels.aLabels[cat_ax.labels.aLabels.length - 1] ? cat_ax.labels.aLabels[cat_ax.labels.aLabels.length - 1].tx.rich.getMaxContentWidth(max_cat_label_width)/2 : 0;

                                //смотрим, выходит ли подпись первой категориии выходит за пределы области построения
                                left_gap_point = arr_cat_labels_points[0] - first_label_left_gap;
                                if(rect.x > left_gap_point && !bWithoutLabels)
                                {
                                    if(val_ax.labels)//скорректируем позицию подписей вертикальной оси, если они есть
                                    {
                                        val_ax.labels.x = rect.x + (val_ax.labels.x - left_gap_point)*checkFiniteNumber((rect.w/(rect.x + rect.w - left_gap_point)));
                                    }
                                    //скорректируем point_interval
                                    point_interval *= checkFiniteNumber((rect.w/(rect.x + rect.w - left_gap_point)));
                                    //скорректируем arr_cat_labels_points
                                    for(i = 0; i < arr_cat_labels_points.length; ++i)
                                    {
                                        arr_cat_labels_points[i] = rect.x + (arr_cat_labels_points[i] - left_gap_point)*checkFiniteNumber((rect.w/(rect.x + rect.w - left_gap_point)));
                                    }
                                    //скорректируем позицию вертикальной оси
                                    val_ax.posX =  rect.x + (val_ax.posX - left_gap_point)*checkFiniteNumber((rect.w/(rect.x + rect.w - left_gap_point)));
                                }

                                //смотри выходит ли подпись последней категории за пределы области построения
                                right_gap_point = arr_cat_labels_points[arr_cat_labels_points.length - 1] + last_labels_right_gap;
                                if(right_gap_point > rect.x + rect.w && !bWithoutLabels)
                                {
                                    if(val_ax.labels)//скорректируем позицию подписей вертикальной оси
                                    {
                                        val_ax.labels.x = rect.x + (val_ax.labels.x - rect.x)*checkFiniteNumber((rect.w/(right_gap_point - rect.x)));
                                    }
                                    //скорректируем point_interval
                                    point_interval *= checkFiniteNumber((rect.w/(right_gap_point - rect.x)));
                                    for(i = 0; i < arr_cat_labels_points.length; ++i)
                                    {
                                        arr_cat_labels_points[i] = rect.x + (arr_cat_labels_points[i] - rect.x)*checkFiniteNumber((rect.w/(right_gap_point - rect.x)));
                                    }
                                    //скорректируем позицию вертикальной оси
                                    val_ax.posX = rect.x + (val_ax.posX - rect.x)*checkFiniteNumber((rect.w/(right_gap_point - rect.x)));

                                }
                            }
                            else
                            {
                                var last_label_left_gap = cat_ax.labels.aLabels[cat_ax.labels.aLabels.length - 1] ? cat_ax.labels.aLabels[cat_ax.labels.aLabels.length - 1].tx.rich.getMaxContentWidth(max_cat_label_width)/2 : 0;
                                var first_label_right_gap = cat_ax.labels.aLabels[0].tx.rich.getMaxContentWidth(max_cat_label_width)/2;
                                left_gap_point = arr_cat_labels_points[arr_cat_labels_points.length - 1] - last_label_left_gap;
                                right_gap_point = arr_cat_labels_points[0] + first_label_right_gap;
                                if(rect.x > left_gap_point && !bWithoutLabels)
                                {
                                    if(val_ax.labels)//скорректируем позицию подписей вертикальной оси, если они есть
                                    {
                                        val_ax.labels.x = rect.x + (val_ax.labels.x - left_gap_point)*checkFiniteNumber((rect.w/(rect.x + rect.w - left_gap_point)));
                                    }
                                    //скорректируем point_interval
                                    point_interval *= checkFiniteNumber((rect.w/(rect.x + rect.w - left_gap_point)));
                                    //скорректируем arr_cat_labels_points
                                    for(i = 0; i < arr_cat_labels_points.length; ++i)
                                    {
                                        arr_cat_labels_points[i] = rect.x + (arr_cat_labels_points[i] - left_gap_point)*checkFiniteNumber((rect.w/(rect.x + rect.w - left_gap_point)));
                                    }

                                    //скорректируем позицию вертикальной оси
                                    val_ax.posX = rect.x + (val_ax.posX - left_gap_point)*checkFiniteNumber((rect.w/(rect.x + rect.w - left_gap_point)));
                                }
                                if(right_gap_point > rect.x + rect.w && !bWithoutLabels)
                                {
                                    if(val_ax.labels)//скорректируем позицию подписей вертикальной оси
                                    {
                                        val_ax.labels.x = rect.x + (val_ax.labels.x - rect.x)*checkFiniteNumber((rect.w/(right_gap_point - rect.x)));
                                    }
                                    //скорректируем point_interval
                                    point_interval *= checkFiniteNumber((rect.w/(right_gap_point - rect.x)));
                                    for(i = 0; i < arr_cat_labels_points.length; ++i)
                                    {
                                        arr_cat_labels_points[i] = rect.x + (arr_cat_labels_points[i] - rect.x)*checkFiniteNumber((rect.w/(right_gap_point - rect.x)));
                                    }
                                    //скорректируем позицию вертикальной оси
                                    val_ax.posX = rect.x + (val_ax.posX - rect.x)*checkFiniteNumber((rect.w/(right_gap_point - rect.x)));
                                }
                            }
                        }
                    }
                    else
                    {
                        b_rotated = true;
                        //пока сделаем без обрезки
                        var arr_left_points = [];
                        var arr_right_points = [];

                        var max_rotated_height = 0;
                        cat_ax.labels.bRotated = true;
                        var nMaxCount = 1;
                        var nLblCount = 0;
                        var nCount = 0;
                        var nSkip = 1;
                        if(!bTickSkip && fMaxContentStringH > 0){
                            nMaxCount = diagram_width/fMaxContentStringH;
                            nSkip = Math.max(1, ((cat_ax.labels.aLabels.length/nMaxCount + 1) >> 0));
                        }
                        else{
                            bTickSkip = true;
                        }
                        //смотрим на сколько подписи горизонтальной оси выходят влево за пределы области построения
                        for(i = 0; i < cat_ax.labels.aLabels.length; ++i)
                        {
                            if(cat_ax.labels.aLabels[i])
                            {
                                if(i%nSkip !== 0){
                                    cat_ax.labels.aLabels[i] = null;
                                    arr_left_points[i] = arr_cat_labels_points[i];
                                    arr_right_points[i] = arr_cat_labels_points[i];
                                    nCount++;
                                    continue;
                                }
                                //сначала расчитаем высоту и ширину подписи так чтобы она умещалась в одну строку
                                var wh = cat_ax.labels.aLabels[i].tx.rich.getContentOneStringSizes();
                                arr_left_points[i] = arr_cat_labels_points[i] - (wh.w*Math.cos(Math.PI/4) + wh.h*Math.sin(Math.PI/4) - wh.h*Math.sin(Math.PI/4)/2);//вычитаем из точки привязки ширину получившейся подписи
                                arr_right_points[i] = arr_cat_labels_points[i] + wh.h*Math.sin(Math.PI/4)/2;
                                var h2 = wh.w*Math.sin(Math.PI/4) + wh.h*Math.cos(Math.PI/4);
                                if(h2 > max_rotated_height)
                                    max_rotated_height = h2;

                                nLblCount++;
                                nCount++;
                                cat_ax.labels.aLabels[i].widthForTransform = wh.w;
                            }
                            else
                            {//подписи нет
                                arr_left_points[i] = arr_cat_labels_points[i];
                                arr_right_points[i] = arr_cat_labels_points[i];
                            }
                        }

                        cat_ax.labels.extY = max_rotated_height + labels_offset;
                        //
                        left_gap_point = Math.max(0, Math.min.apply(Math, arr_left_points));
                        right_gap_point = Math.max(0, Math.max.apply(Math, arr_right_points));

                        if(!bWithoutLabels){
                            if(AscFormat.ORIENTATION_MIN_MAX === cat_ax_orientation)
                            {
                                if(rect.x > left_gap_point)
                                {
                                    if(val_ax.labels)//скорректируем позицию подписей вертикальной оси, если они есть
                                    {
                                        val_ax.labels.x = rect.x + (val_ax.labels.x - left_gap_point)*checkFiniteNumber((rect.w/(rect.x + rect.w - left_gap_point)));
                                    }
                                    //скорректируем point_interval
                                    point_interval *= checkFiniteNumber(rect.w/(rect.x + rect.w - left_gap_point));
                                    //скорректируем arr_cat_labels_points
                                    for(i = 0; i < arr_cat_labels_points.length; ++i)
                                    {
                                        arr_cat_labels_points[i] = rect.x + (arr_cat_labels_points[i] - left_gap_point)*checkFiniteNumber((rect.w/(rect.x + rect.w - left_gap_point)));
                                    }

                                    //скорректируем позицию вертикальной оси
                                    val_ax.posX = rect.x + (val_ax.posX - left_gap_point)*checkFiniteNumber((rect.w/(rect.x + rect.w - left_gap_point)));
                                }
                                //смотри выходит ли подпись последней категории за пределы области построения
                                if(right_gap_point > rect.x + rect.w)
                                {
                                    if(val_ax.labels)//скорректируем позицию подписей вертикальной оси
                                    {
                                        val_ax.labels.x = rect.x + (val_ax.labels.x - rect.x)*checkFiniteNumber((rect.w/(right_gap_point - rect.x)));
                                    }
                                    //скорректируем point_interval
                                    point_interval *= checkFiniteNumber((right_gap_point - rect.x)/(rect.x + rect.w - rect.x));
                                    for(i = 0; i < arr_cat_labels_points.length; ++i)
                                    {
                                        arr_cat_labels_points[i] = rect.x + (arr_cat_labels_points[i] - rect.x)*checkFiniteNumber((rect.w/(right_gap_point - rect.x)));
                                    }


                                    //скорректируем позицию вертикальной оси
                                    val_ax.posX = rect.x + (val_ax.posX - rect.x)*checkFiniteNumber((rect.w/(right_gap_point - rect.x)));
                                }
                            }
                            else
                            {
                                if(rect.x > left_gap_point)
                                {
                                    if(val_ax.labels)//скорректируем позицию подписей вертикальной оси, если они есть
                                    {
                                        val_ax.labels.x = rect.x + (val_ax.labels.x - left_gap_point)*checkFiniteNumber((rect.w/(rect.x + rect.w - left_gap_point)));
                                    }
                                    //скорректируем point_interval
                                    point_interval *= (rect.w)/checkFiniteNumber((rect.x + rect.w - left_gap_point));
                                    //скорректируем arr_cat_labels_points
                                    for(i = 0; i < arr_cat_labels_points.length; ++i)
                                    {
                                        arr_cat_labels_points[i] = rect.x + (arr_cat_labels_points[i] - left_gap_point)*checkFiniteNumber((rect.w/(rect.x + rect.w - left_gap_point)));
                                    }

                                    //скорректируем позицию вертикальной оси
                                    val_ax.posX = rect.x + (val_ax.posX - left_gap_point)*checkFiniteNumber((rect.w/(rect.x + rect.w - left_gap_point)));
                                }
                                if(right_gap_point > rect.x + rect.w)
                                {
                                    if(val_ax.labels)//скорректируем позицию подписей вертикальной оси
                                    {
                                        val_ax.labels.x = rect.x + (val_ax.labels.x - rect.x)*checkFiniteNumber((rect.w/(right_gap_point - rect.x)));
                                    }
                                    //скорректируем point_interval
                                    point_interval *= checkFiniteNumber((right_gap_point - rect.x)/(rect.x + rect.w - rect.x));
                                    for(i = 0; i < arr_cat_labels_points.length; ++i)
                                    {
                                        arr_cat_labels_points[i] = rect.x + (arr_cat_labels_points[i] - rect.x)*checkFiniteNumber((rect.w/(right_gap_point - rect.x)));
                                    }

                                    //скорректируем позицию вертикальной оси
                                    val_ax.posX = rect.x + (val_ax.posX - rect.x)*checkFiniteNumber((rect.w/(right_gap_point - rect.x)));
                                }
                            }
                        }
                    }
                }



                //series axis
                if(ser_ax){
                    if(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE !== ser_ax.tickLblPos && !(ser_ax.bDelete === true)){
                        var arr_series_labels_str = [];
                        var aSeries = chart_object.series;
                        for(var i = 0; i < aSeries.length; ++i){
                            if(aSeries[i].getSeriesName){
                                arr_series_labels_str.push(aSeries[i].getSeriesName());
                            }
                            else{
                                arr_series_labels_str.push('Series ' + (i+1));
                            }
                        }
                        ser_ax.labels = new AscFormat.CValAxisLabels(this, ser_ax);
                        tick_lbl_skip = AscFormat.isRealNumber(ser_ax.tickLblSkip) ? ser_ax.tickLblSkip :  1;

                        var lastStyleObject = null;
                        max_val_labels_text_height = 0;
                        max_width = 0;
                        for(i = 0; i < arr_series_labels_str.length; ++i)
                        {
                            var dlbl = null;
                            if(i%tick_lbl_skip === 0)
                            {
                                var dlbl = new AscFormat.CDLbl();
                                if(lastStyleObject)
                                {
                                    dlbl.lastStyleObject = lastStyleObject;
                                }
                                dlbl.parent = val_ax;
                                dlbl.chart = this;
                                dlbl.spPr = val_ax.spPr;
                                dlbl.txPr = val_ax.txPr;
                                dlbl.tx = new AscFormat.CChartText();
                                dlbl.tx.rich = AscFormat.CreateTextBodyFromString(arr_series_labels_str[i], this.getDrawingDocument(), dlbl);
                                var t = dlbl.tx.rich.recalculateByMaxWord();
                                if(!lastStyleObject)
                                {
                                    lastStyleObject = dlbl.lastStyleObject;
                                }
                                var cur_width = t.w;
                                if(cur_width > max_width)
                                    max_width = cur_width;
                                if(t.h > max_val_labels_text_height)
                                    max_val_labels_text_height = t.h;
                                ser_ax.labels.aLabels.push(dlbl);
                            }
                        }

                        var ser_axis_labels_gap = ser_ax.labels.aLabels[0].tx.rich.content.Content[0].CompiledPr.Pr.TextPr.FontSize*25.4/72;
                        ser_ax.labels.extX = max_width + ser_axis_labels_gap;
                        ser_ax.labels.extY = max_val_labels_text_height;
                    }
                    else{
                        ser_ax.labels = null;
                    }
                }

                //расчет позиции блока с подписями горизонтальной оси
                var cat_labels_align_bottom = true;
                /*-----------------------------------------------------------------------*/
                var crosses_val_ax;//значение на ветикальной оси в котором её пересекает горизонтальная

                if(cat_ax.crosses === AscFormat.CROSSES_AUTO_ZERO)
                {
                    if(arr_val[0] <=0 && arr_val[arr_val.length-1] >= 0)
                        crosses_val_ax = 0;
                    else if(arr_val[arr_val.length-1] < 0)
                        crosses_val_ax = arr_val[arr_val.length-1];
                    else
                        crosses_val_ax = arr_val[0];
                }
                else if(cat_ax.crosses === AscFormat.CROSSES_MIN)
                {
                    crosses_val_ax = arr_val[0];
                }
                else if(cat_ax.crosses === AscFormat.CROSSES_MAX)
                {
                    crosses_val_ax = arr_val[arr_val.length - 1];
                }
                else if(AscFormat.isRealNumber(cat_ax.crossesAt) && cat_ax.crossesAt >= arr_val[0] && cat_ax.crossesAt <= arr_val[arr_val.length - 1])
                {
                    //сделаем провеку на попадание в интервал
                    if(cat_ax.crossesAt >= arr_val[0] && cat_ax.crossesAt <= arr_val[arr_val.length - 1])
                        crosses_val_ax = cat_ax.crossesAt;
                }
                else
                { //ведем себя как в случае (cat_ax.crosses === AscFormat.CROSSES_AUTO_ZERO)
                    if(arr_val[0] <=0 && arr_val[arr_val.length-1] >= 0)
                        crosses_val_ax = 0;
                    else if(arr_val[arr_val.length-1] < 0)
                        crosses_val_ax = arr_val[arr_val.length-1];
                    else
                        crosses_val_ax = arr_val[0];
                }
                var val_ax_orientation = val_ax.scaling && AscFormat.isRealNumber(val_ax.scaling.orientation) ? val_ax.scaling.orientation : AscFormat.ORIENTATION_MIN_MAX;
                var hor_labels_pos = cat_ax.tickLblPos;

                var arr_val_labels_points = [];//массив середин подписей вертикальной оси; i-й элемент - y-координата центра подписи i-огто значения;
                var top_val_axis_gap, bottom_val_axis_gap;
                var first_val_axis_label_half_height = 0; //TODO  (val_ax.bDelete || val_ax.tickLblPos ===c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE) ? 0 :val_ax.labels.aLabels[0].tx.rich.content.GetSummaryHeight()/2;
                var last_val_axis_label_half_height = 0; //TODO (val_ax.bDelete || val_ax.tickLblPos ===c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE) ? 0 : val_ax.labels.aLabels[val_ax.labels.aLabels.length-1].tx.rich.content.GetSummaryHeight()/2;

                var unit_height;
                if(!bWithoutLabels){
                    unit_height = checkFiniteNumber((rect.h - first_val_axis_label_half_height - last_val_axis_label_half_height)/(arr_val[arr_val.length - 1] - arr_val[0]));//высота единицы измерения на вертикальной оси
                }
                else{
                    unit_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length - 1] - arr_val[0]));
                }

                
                var cat_ax_ext_y = cat_ax.labels ? cat_ax.labels.extY : 0;
                if(val_ax_orientation === AscFormat.ORIENTATION_MIN_MAX)
                {
                    if(hor_labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO || !AscFormat.isRealNumber(hor_labels_pos))
                    {
                        if(cat_ax.crosses === AscFormat.CROSSES_MAX)
                        {
                            cat_labels_align_bottom = false;
                            top_val_axis_gap = Math.max(last_val_axis_label_half_height, cat_ax_ext_y);
                            if(!bWithoutLabels){
                                unit_height = checkFiniteNumber((rect.h - top_val_axis_gap - first_val_axis_label_half_height)/(arr_val[arr_val.length - 1] - arr_val[0]));
                                cat_labels_align_bottom = false;//в данном случае подписи будут выравниваться по верхнему краю блока с подписями
                                cat_ax.posY = rect.y + rect.h - first_val_axis_label_half_height - (crosses_val_ax - arr_val[0])*unit_height;
                                if(cat_ax.labels)
                                    cat_ax.labels.y = cat_ax.posY - cat_ax_ext_y;
                            }
                            else{

                                unit_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length - 1] - arr_val[0]));
                                cat_labels_align_bottom = false;//в данном случае подписи будут выравниваться по верхнему краю блока с подписями
                                cat_ax.posY = rect.y + rect.h - (crosses_val_ax - arr_val[0])*unit_height;
                                if(cat_ax.labels){
                                    cat_ax.labels.y = cat_ax.posY - cat_ax_ext_y;

                                    if(true){
                                        var bCorrectedCat = false;
                                        if(cat_ax.labels.y < 0){
                                            rect.y -= cat_ax.labels.y;
                                            rect.h += cat_ax.labels.y;
                                            cat_ax.labels.y = 0;
                                            bCorrectedCat = true;
                                        }
                                        if(cat_ax.labels.y + cat_ax.labels.extY > this.extY){
                                            rect.h -= (cat_ax.labels.y + cat_ax.labels.extY - this.extY);
                                            bCorrectedCat = true;
                                        }
                                        if(bCorrectedCat){
                                            unit_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length - 1] - arr_val[0]));
                                            cat_labels_align_bottom = false;//в данном случае подписи будут выравниваться по верхнему краю блока с подписями
                                            cat_ax.posY = rect.y + rect.h - (crosses_val_ax - arr_val[0])*unit_height;
                                        }
                                    }
                                }

                            }
                        }
                        else
                        {
                            if(!bWithoutLabels){
                                var bottom_points_height = first_val_axis_label_half_height + (crosses_val_ax - arr_val[0])*unit_height;//высота области под горизонтальной осью
                                if(bottom_points_height < cat_ax_ext_y)
                                {
                                    unit_height = checkFiniteNumber((rect.h - last_val_axis_label_half_height - cat_ax_ext_y)/(arr_val[arr_val.length-1] - crosses_val_ax));
                                }
                                cat_ax.posY = rect.y + last_val_axis_label_half_height + (arr_val[arr_val.length-1] - crosses_val_ax)*unit_height;
                                if(cat_ax.labels)
                                    cat_ax.labels.y = cat_ax.posY;
                            }
                            else{
                                cat_ax.posY = rect.y + (arr_val[arr_val.length-1] - crosses_val_ax)*unit_height;
                                if(cat_ax.labels){
                                    cat_ax.labels.y = cat_ax.posY;

                                    if(true){
                                        var bCorrectedCat = false;
                                        if(cat_ax.labels.y < 0){
                                            rect.y -= cat_ax.labels.y;
                                            rect.h += cat_ax.labels.y;
                                            cat_ax.labels.y = 0;
                                            bCorrectedCat = true;
                                        }
                                        if(cat_ax.labels.y + cat_ax.labels.extY > this.extY){
                                            rect.h -= (cat_ax.labels.y + cat_ax.labels.extY - this.extY);
                                            bCorrectedCat = true;
                                        }
                                        if(bCorrectedCat){
                                            unit_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length - 1] - arr_val[0]));
                                            cat_ax.posY = rect.y + (arr_val[arr_val.length-1] - crosses_val_ax)*unit_height;
                                            cat_ax.labels.y = cat_ax.posY;
                                        }
                                    }
                                }
                            }
                        }
                        for(i = 0; i < arr_val.length; ++i)
                            arr_val_labels_points[i] = cat_ax.posY - (arr_val[i] - crosses_val_ax)*unit_height;
                    }
                    else if(hor_labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_LOW)
                    {
                        if(!bWithoutLabels){
                            bottom_val_axis_gap = Math.max(cat_ax_ext_y, first_val_axis_label_half_height);
                            unit_height = checkFiniteNumber((rect.h - bottom_val_axis_gap - last_val_axis_label_half_height)/(arr_val[arr_val.length - 1] - arr_val[0]));
                            cat_ax.posY = rect.y + last_val_axis_label_half_height + (arr_val[arr_val.length-1] - crosses_val_ax)*unit_height;
                            if(cat_ax.labels)
                                cat_ax.labels.y = rect.y + rect.h - bottom_val_axis_gap;
                            for(i = 0; i < arr_val.length; ++i)
                                arr_val_labels_points[i] = cat_ax.posY - (arr_val[i] - crosses_val_ax)*unit_height;
                        }
                        else{
                            unit_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length - 1] - arr_val[0]));
                            cat_ax.posY = rect.y + (arr_val[arr_val.length-1] - crosses_val_ax)*unit_height;
                            if(cat_ax.labels){
                                cat_ax.labels.y = rect.y + rect.h;
                                if(true){
                                    var bCorrectedCat = false;
                                    if(cat_ax.labels.y < 0){
                                        rect.y -= cat_ax.labels.y;
                                        rect.h += cat_ax.labels.y;
                                        cat_ax.labels.y = 0;
                                        bCorrectedCat = true;
                                    }
                                    if(cat_ax.labels.y + cat_ax.labels.extY > this.extY){
                                        rect.h -= (cat_ax.labels.y + cat_ax.labels.extY - this.extY);
                                        bCorrectedCat = true;
                                    }
                                    if(bCorrectedCat){
                                        unit_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length - 1] - arr_val[0]));
                                        cat_ax.posY = rect.y + (arr_val[arr_val.length-1] - crosses_val_ax)*unit_height;
                                        cat_ax.labels.y = rect.y + rect.h;
                                    }
                                }
                            }
                            for(i = 0; i < arr_val.length; ++i)
                                arr_val_labels_points[i] = cat_ax.posY - (arr_val[i] - crosses_val_ax)*unit_height;
                        }
                    }
                    else if(hor_labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_HIGH)
                    {
                        if(!bWithoutLabels){
                            top_val_axis_gap = Math.max(last_val_axis_label_half_height, cat_ax_ext_y);
                            unit_height = checkFiniteNumber((rect.h - top_val_axis_gap - first_val_axis_label_half_height)/(arr_val[arr_val.length - 1] - arr_val[0]));
                            cat_labels_align_bottom = false;//в данном случае подписи будут выравниваться по верхнему краю блока с подписями
                            cat_ax.posY = rect.y + rect.h - first_val_axis_label_half_height - (crosses_val_ax - arr_val[0])*unit_height;
                            if(cat_ax.labels)
                                cat_ax.labels.y = rect.y + top_val_axis_gap  - cat_ax_ext_y;
                            for(i = 0; i < arr_val.length; ++i)
                                arr_val_labels_points[i] = cat_ax.posY - (arr_val[i] - crosses_val_ax)*unit_height;
                        }
                        else{
                            unit_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length - 1] - arr_val[0]));
                            cat_labels_align_bottom = false;//в данном случае подписи будут выравниваться по верхнему краю блока с подписями
                            cat_ax.posY = rect.y + rect.h - (crosses_val_ax - arr_val[0])*unit_height;
                            if(cat_ax.labels){
                                cat_ax.labels.y = rect.y - cat_ax_ext_y;
                                if(true){
                                    var bCorrectedCat = false;
                                    if(cat_ax.labels.y < 0){
                                        rect.y -= cat_ax.labels.y;
                                        rect.h += cat_ax.labels.y;
                                        cat_ax.labels.y = 0;
                                        bCorrectedCat = true;
                                    }
                                    if(cat_ax.labels.y + cat_ax.labels.extY > this.extY){
                                        rect.h -= (cat_ax.labels.y + cat_ax.labels.extY - this.extY);
                                        bCorrectedCat = true;
                                    }
                                    if(bCorrectedCat){
                                        unit_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length - 1] - arr_val[0]));
                                        cat_ax.posY = rect.y + rect.h - (crosses_val_ax - arr_val[0])*unit_height;
                                        cat_ax.labels.y = rect.y - cat_ax_ext_y;
                                    }
                                }
                            }

                            for(i = 0; i < arr_val.length; ++i)
                                arr_val_labels_points[i] = cat_ax.posY - (arr_val[i] - crosses_val_ax)*unit_height;
                        }
                    }
                    else
                    {
                        //подписей осей нет
                        cat_ax.labels = null;
                        if(!bWithoutLabels){
                            for(i = 0; i < arr_val.length; ++i)
                                arr_val_labels_points[i] = rect.y + rect.h - first_val_axis_label_half_height - (arr_val[i] - arr_val[0])*unit_height;
                            cat_ax.posY = rect.y + rect.h - first_val_axis_label_half_height -  (crosses_val_ax - arr_val[0])*unit_height;
                        }
                        else{
                            for(i = 0; i < arr_val.length; ++i)
                                arr_val_labels_points[i] = rect.y + rect.h - (arr_val[i] - arr_val[0])*unit_height;
                            cat_ax.posY = rect.y + rect.h - (crosses_val_ax - arr_val[0])*unit_height;
                        }
                    }
                }
                else
                {//зеркально отражаем
                    if(hor_labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO || !AscFormat.isRealNumber(hor_labels_pos))
                    {
                        if(cat_ax.crosses === AscFormat.CROSSES_MAX)
                        {
                            if(!bWithoutLabels){
                                bottom_val_axis_gap = Math.max(cat_ax_ext_y, last_val_axis_label_half_height);
                                unit_height = checkFiniteNumber((rect.h - bottom_val_axis_gap - first_val_axis_label_half_height)/(arr_val[arr_val.length - 1] - arr_val[0]));
                                cat_ax.posY = rect.y + first_val_axis_label_half_height + (crosses_val_ax - arr_val[0])*unit_height;
                                if(cat_ax.labels)
                                    cat_ax.labels.y = rect.y + rect.h - bottom_val_axis_gap;
                            }
                            else{

                                unit_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length - 1] - arr_val[0]));
                                cat_ax.posY = rect.y + (crosses_val_ax - arr_val[0])*unit_height;
                                if(cat_ax.labels){
                                    cat_ax.labels.y = rect.y + rect.h;
                                    if(true){
                                        var bCorrectedCat = false;
                                        if(cat_ax.labels.y < 0){
                                            rect.y -= cat_ax.labels.y;
                                            rect.h += cat_ax.labels.y;
                                            cat_ax.labels.y = 0;
                                            bCorrectedCat = true;
                                        }
                                        if(cat_ax.labels.y + cat_ax.labels.extY > this.extY){
                                            rect.h -= (cat_ax.labels.y + cat_ax.labels.extY - this.extY);
                                            bCorrectedCat = true;
                                        }
                                        if(bCorrectedCat){
                                            unit_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length - 1] - arr_val[0]));
                                            cat_ax.posY = rect.y + (crosses_val_ax - arr_val[0])*unit_height;
                                            cat_ax.labels.y = rect.y + rect.h;
                                        }
                                    }
                                }

                            }
                        }
                        else
                        {
                            cat_labels_align_bottom = false;
                            if(!bWithoutLabels){
                                var top_points_height = first_val_axis_label_half_height + (crosses_val_ax - arr_val[0])*unit_height;
                                if(top_points_height < cat_ax_ext_y)
                                {
                                    unit_height = checkFiniteNumber((rect.h - cat_ax_ext_y - last_val_axis_label_half_height)/(arr_val[arr_val.length-1] - crosses_val_ax));
                                }
                                cat_ax.posY = rect.y + rect.h - last_val_axis_label_half_height - (arr_val[arr_val.length-1] - crosses_val_ax)*unit_height;
                                if(cat_ax.labels)
                                    cat_ax.labels.y = cat_ax.posY - cat_ax_ext_y;
                            }
                            else{
                                cat_ax.posY = rect.y + rect.h - (arr_val[arr_val.length-1] - crosses_val_ax)*unit_height;
                                if(cat_ax.labels){
                                    cat_ax.labels.y = cat_ax.posY - cat_ax_ext_y;
                                    if(true){
                                        var bCorrectedCat = false;
                                        if(cat_ax.labels.y < 0){
                                            rect.y -= cat_ax.labels.y;
                                            rect.h += cat_ax.labels.y;
                                            cat_ax.labels.y = 0;
                                            bCorrectedCat = true;
                                        }
                                        if(cat_ax.labels.y + cat_ax.labels.extY > this.extY){
                                            rect.h -= (cat_ax.labels.y + cat_ax.labels.extY - this.extY);
                                            bCorrectedCat = true;
                                        }
                                        if(bCorrectedCat){
                                            unit_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length - 1] - arr_val[0]));
                                            cat_ax.posY = rect.y + rect.h - (arr_val[arr_val.length-1] - crosses_val_ax)*unit_height;
                                            cat_ax.labels.y = cat_ax.posY - cat_ax_ext_y;
                                        }
                                    }
                                }

                            }
                        }
                        for(i = 0; i < arr_val.length; ++i)
                            arr_val_labels_points[i] = cat_ax.posY + (arr_val[i] - crosses_val_ax)*unit_height;
                    }
                    else if(hor_labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_LOW)
                    {
                        cat_labels_align_bottom = false;
                        if(!bWithoutLabels){
                            top_val_axis_gap = Math.max(first_val_axis_label_half_height, cat_ax_ext_y);
                            unit_height = checkFiniteNumber((rect.h  - top_val_axis_gap - last_val_axis_label_half_height)/(arr_val[arr_val.length-1] - arr_val[0]));
                            cat_ax.posY = rect.y + rect.h - last_val_axis_label_half_height - (arr_val[arr_val.length-1] - crosses_val_ax)*unit_height;


                            for(i = 0; i < arr_val.length; ++i)
                                arr_val_labels_points[i] = cat_ax.posY + (arr_val[i] - crosses_val_ax)*unit_height;
                            if(cat_ax.labels)
                                cat_ax.labels.y = cat_ax.posY + (arr_val[0] - crosses_val_ax)*unit_height - cat_ax_ext_y;
                        }
                        else{
                            unit_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length-1] - arr_val[0]));
                            cat_ax.posY = rect.y + rect.h - (arr_val[arr_val.length-1] - crosses_val_ax)*unit_height;


                            for(i = 0; i < arr_val.length; ++i)
                                arr_val_labels_points[i] = cat_ax.posY + (arr_val[i] - crosses_val_ax)*unit_height;
                            if(cat_ax.labels)
                            {
                                cat_ax.labels.y = cat_ax.posY + (arr_val[0] - crosses_val_ax)*unit_height - cat_ax_ext_y;
                                if(true){
                                    var bCorrectedCat = false;
                                    if(cat_ax.labels.y < 0){
                                        rect.y -= cat_ax.labels.y;
                                        rect.h += cat_ax.labels.y;
                                        cat_ax.labels.y = 0;
                                        bCorrectedCat = true;
                                    }
                                    if(cat_ax.labels.y + cat_ax.labels.extY > this.extY){
                                        rect.h -= (cat_ax.labels.y + cat_ax.labels.extY - this.extY);
                                        bCorrectedCat = true;
                                    }
                                    if(bCorrectedCat){
                                        unit_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length-1] - arr_val[0]));
                                        cat_ax.posY = rect.y + rect.h - (arr_val[arr_val.length-1] - crosses_val_ax)*unit_height;

                                        for(i = 0; i < arr_val.length; ++i)
                                            arr_val_labels_points[i] = cat_ax.posY + (arr_val[i] - crosses_val_ax)*unit_height;
                                        cat_ax.labels.y = cat_ax.posY + (arr_val[0] - crosses_val_ax)*unit_height - cat_ax_ext_y;
                                    }
                                }
                            }

                        }
                    }
                    else if(hor_labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_HIGH)
                    {

                        if(!bWithoutLabels){
                            bottom_val_axis_gap = Math.max(cat_ax_ext_y, last_val_axis_label_half_height);
                            unit_height = checkFiniteNumber((rect.h  - bottom_val_axis_gap - first_val_axis_label_half_height)/(arr_val[arr_val.length-1] - arr_val[0]));
                            cat_ax.posY = rect.y + first_val_axis_label_half_height + (crosses_val_ax - arr_val[0])*unit_height;
                            for(i = 0; i < arr_val.length; ++i)
                                arr_val_labels_points[i] = cat_ax.posY + (arr_val[i] - crosses_val_ax)*unit_height;
                            if(cat_ax.labels)
                                cat_ax.labels.y = rect.y + rect.h - bottom_val_axis_gap;
                        }
                        else{

                            unit_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length-1] - arr_val[0]));
                            cat_ax.posY = rect.y + (crosses_val_ax - arr_val[0])*unit_height;
                            for(i = 0; i < arr_val.length; ++i)
                                arr_val_labels_points[i] = cat_ax.posY + (arr_val[i] - crosses_val_ax)*unit_height;
                            if(cat_ax.labels){
                                cat_ax.labels.y = rect.y + rect.h;
                                if(true){
                                    var bCorrectedCat = false;
                                    if(cat_ax.labels.y < 0){
                                        rect.y -= cat_ax.labels.y;
                                        rect.h += cat_ax.labels.y;
                                        cat_ax.labels.y = 0;
                                        bCorrectedCat = true;
                                    }
                                    if(cat_ax.labels.y + cat_ax.labels.extY > this.extY){
                                        rect.h -= (cat_ax.labels.y + cat_ax.labels.extY - this.extY);
                                        bCorrectedCat = true;
                                    }
                                    if(bCorrectedCat){
                                        unit_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length-1] - arr_val[0]));
                                        cat_ax.posY = rect.y + (crosses_val_ax - arr_val[0])*unit_height;
                                        for(i = 0; i < arr_val.length; ++i)
                                            arr_val_labels_points[i] = cat_ax.posY + (arr_val[i] - crosses_val_ax)*unit_height;
                                        cat_ax.labels.y = rect.y + rect.h;
                                    }
                                }
                            }

                        }
                    }
                    else
                    {//подписей осей нет
                        cat_ax.labels = null;
                        if(!bWithoutLabels){
                            unit_height = checkFiniteNumber((rect.h  - last_val_axis_label_half_height - first_val_axis_label_half_height)/(arr_val[arr_val.length-1] - arr_val[0]));
                            for(i = 0; i < arr_val.length; ++i)
                                arr_val_labels_points[i] = rect.y + first_val_axis_label_half_height + (arr_val[i] - arr_val[0])*unit_height;
                        }
                        else{
                            unit_height = checkFiniteNumber(rect.h/(arr_val[arr_val.length-1] - arr_val[0]));
                            for(i = 0; i < arr_val.length; ++i)
                                arr_val_labels_points[i] = rect.y + (arr_val[i] - arr_val[0])*unit_height;
                        }
                    }
                }

                cat_ax.interval = unit_height;
                //запишем в оси необходимую информацию для отрисовщика plotArea  и выставим окончательные позиции для подписей
                var arr_labels, transform_text, local_text_transform;
                if(val_ax.labels)
                {
                    if(bNeedReflect)
                    {
                        if(left_val_ax_labels_align)
                        {
                            left_val_ax_labels_align = false;
                            val_ax.labels.x += val_ax.labels.extX;
                        }
                        else
                        {
                            left_val_ax_labels_align = true;
                            val_ax.labels.x -= val_ax.labels.extX;
                        }
                    }
                    val_ax.labels.align = left_val_ax_labels_align;
                    val_ax.labels.y = Math.min.apply(Math, arr_val_labels_points) - max_val_labels_text_height/2;
                    val_ax.labels.extY = Math.max.apply(Math, arr_val_labels_points) - Math.min.apply(Math, arr_val_labels_points) + max_val_labels_text_height;
                    arr_labels = val_ax.labels.aLabels;
                    if(left_val_ax_labels_align)
                    {
                        for(i = 0; i < arr_labels.length; ++i)
                        {
                            arr_labels[i].txBody = arr_labels[i].tx.rich;
                            transform_text = arr_labels[i].transformText;
                            transform_text.Reset();
                            global_MatrixTransformer.TranslateAppend(transform_text, val_ax.labels.x + val_ax.labels.extX - val_axis_labels_gap - arr_labels[i].tx.rich.content.XLimit, arr_val_labels_points[i] - val_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);
                          //  global_MatrixTransformer.MultiplyAppend(transform_text, this.getTransformMatrix());

                            local_text_transform = arr_labels[i].localTransformText;
                            local_text_transform.Reset();
                            global_MatrixTransformer.TranslateAppend(local_text_transform, val_ax.labels.x + val_ax.labels.extX - val_axis_labels_gap - arr_labels[i].tx.rich.content.XLimit, arr_val_labels_points[i] - val_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);


                        }
                    }
                    else
                    {
                        var left_line = val_ax.labels.x + val_axis_labels_gap;
                        for(i = 0; i < arr_labels.length; ++i)
                        {
                            arr_labels[i].txBody = arr_labels[i].tx.rich;
                            transform_text = arr_labels[i].transformText;
                            transform_text.Reset();
                            global_MatrixTransformer.TranslateAppend(transform_text, left_line, arr_val_labels_points[i] - val_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);
                          //  global_MatrixTransformer.MultiplyAppend(transform_text, this.getTransformMatrix());

                            local_text_transform = arr_labels[i].localTransformText;
                            local_text_transform.Reset();
                            global_MatrixTransformer.TranslateAppend(local_text_transform, left_line, arr_val_labels_points[i] - val_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);

                        }
                    }
                }
                val_ax.yPoints = [];
                for(i = 0; i < arr_val_labels_points.length; ++i)
                {
                    val_ax.yPoints[i] = {val:arr_val[i], pos: arr_val_labels_points[i]};
                }
                cat_ax.xPoints = [];
                for(i = 0; i <arr_cat_labels_points.length; ++i)
                {
                    cat_ax.xPoints[i] = {val: i + 1, pos: arr_cat_labels_points[i]};
                }
                if(cat_ax.labels)
                {
                    cat_ax.labels.align = cat_labels_align_bottom;
                    if(!b_rotated)//подписи не повернутые
                    {
                        if(cat_ax_orientation === AscFormat.ORIENTATION_MIN_MAX)
                        {
                            cat_ax.labels.x = arr_cat_labels_points[0] - max_cat_label_width/2;
                        }
                        else
                        {
                            cat_ax.labels.x = arr_cat_labels_points[arr_cat_labels_points.length-1] - max_cat_label_width/2;
                        }
                        cat_ax.labels.extX = arr_cat_labels_points[arr_cat_labels_points.length-1] + max_cat_label_width/2 - cat_ax.labels.x;
                        if(cat_labels_align_bottom)
                        {
                            for(i = 0; i < cat_ax.labels.aLabels.length; ++i)
                            {
                                if(cat_ax.labels.aLabels[i])
                                {
                                    var label_text_transform = cat_ax.labels.aLabels[i].transformText;
                                    label_text_transform.Reset();
                                    global_MatrixTransformer.TranslateAppend(label_text_transform, arr_cat_labels_points[i] - max_cat_label_width/2, cat_ax.labels.y + labels_offset);
                                 //   global_MatrixTransformer.MultiplyAppend(label_text_transform, this.getTransformMatrix());

                                    local_text_transform = cat_ax.labels.aLabels[i].localTransformText;
                                    local_text_transform.Reset();
                                    global_MatrixTransformer.TranslateAppend(local_text_transform, arr_cat_labels_points[i] - max_cat_label_width/2, cat_ax.labels.y + labels_offset);

                                }
                            }
                        }
                        else
                        {
                            for(i = 0; i < cat_ax.labels.aLabels.length; ++i)
                            {
                                if(cat_ax.labels.aLabels[i])
                                {
                                    var label_text_transform = cat_ax.labels.aLabels[i].transformText;
                                    label_text_transform.Reset();
                                    global_MatrixTransformer.TranslateAppend(label_text_transform, arr_cat_labels_points[i] - max_cat_label_width/2, cat_ax.labels.y + cat_ax.labels.extY - labels_offset - cat_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight());
                                  //  global_MatrixTransformer.MultiplyAppend(label_text_transform, this.getTransformMatrix());

                                    local_text_transform = cat_ax.labels.aLabels[i].localTransformText;
                                    local_text_transform.Reset();
                                    global_MatrixTransformer.TranslateAppend(local_text_transform, arr_cat_labels_points[i] - max_cat_label_width/2, cat_ax.labels.y + cat_ax.labels.extY - labels_offset - cat_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight());

                                }
                            }
                        }
                    }
                    else
                    {
                        var left_x, right_x;
                        var w2, h2, x1, xc, yc, y0;
                        if(cat_labels_align_bottom)
                        {
                            for(i = 0; i < cat_ax.labels.aLabels.length; ++i)
                            {
                                if(cat_ax.labels.aLabels[i])
                                {
                                    var label_text_transform = cat_ax.labels.aLabels[i].transformText;
                                    cat_ax.labels.aLabels[i].tx.rich.content.Set_ApplyToAll(true);
                                    cat_ax.labels.aLabels[i].tx.rich.content.SetParagraphAlign(AscCommon.align_Left);
                                    cat_ax.labels.aLabels[i].tx.rich.content.Set_ApplyToAll(false);
                                    var wh = cat_ax.labels.aLabels[i].tx.rich.getContentOneStringSizes();//Todo: не расчитывать больше контент
                                    w2 = wh.w*Math.cos(Math.PI/4) + wh.h*Math.sin(Math.PI/4);
                                    h2 = wh.w*Math.sin(Math.PI/4) + wh.h*Math.cos(Math.PI/4);
                                    x1 = arr_cat_labels_points[i] + wh.h*Math.sin(Math.PI/4);

                                    y0 = cat_ax.labels.y + labels_offset;

                                    xc = x1 - w2/2;
                                    yc = y0 + h2/2;
                                    label_text_transform.Reset();
                                    global_MatrixTransformer.TranslateAppend(label_text_transform, -wh.w/2, -wh.h/2);
                                    global_MatrixTransformer.RotateRadAppend(label_text_transform, Math.PI/4);//TODO
                                    global_MatrixTransformer.TranslateAppend(label_text_transform, xc, yc);
                                    global_MatrixTransformer.MultiplyAppend(label_text_transform,this.transform);
                                    if(!AscFormat.isRealNumber(left_x))
                                    {
                                        left_x = xc - w2/2;
                                        right_x = xc + w2/2;
                                    }
                                    else
                                    {
                                        if(xc - w2/2 < left_x)
                                            left_x = xc - w2/2;
                                        if(xc + w2/2 > right_x)
                                            right_x = xc + w2/2;
                                    }

                                    local_text_transform = cat_ax.labels.aLabels[i].localTransformText;
                                    local_text_transform.Reset();
                                    global_MatrixTransformer.TranslateAppend(local_text_transform, -wh.w/2, -wh.h/2);
                                    global_MatrixTransformer.RotateRadAppend(local_text_transform, Math.PI/4);//TODO
                                    global_MatrixTransformer.TranslateAppend(local_text_transform, xc, yc);
                                }
                            }
                        }
                        else
                        {
                            for(i = 0; i < cat_ax.labels.aLabels.length; ++i)
                            {
                                if(cat_ax.labels.aLabels[i])
                                {
                                    var label_text_transform = cat_ax.labels.aLabels[i].transformText;
                                    cat_ax.labels.aLabels[i].tx.rich.content.Set_ApplyToAll(true);
                                    cat_ax.labels.aLabels[i].tx.rich.content.SetParagraphAlign(AscCommon.align_Left);
                                    cat_ax.labels.aLabels[i].tx.rich.content.Set_ApplyToAll(false);
                                    var wh = cat_ax.labels.aLabels[i].tx.rich.getContentOneStringSizes();//Todo: не расчитывать больше контент
                                    w2 = wh.w*Math.cos(Math.PI/4) + wh.h*Math.sin(Math.PI/4);
                                    h2 = wh.w*Math.sin(Math.PI/4) + wh.h*Math.cos(Math.PI/4);
                                    x1 = arr_cat_labels_points[i] - wh.h*Math.sin(Math.PI/4);

                                    y0 = cat_ax.labels.y + cat_ax.labels.extY - labels_offset;

                                    xc = x1 + w2/2;
                                    yc = y0 - h2/2;
                                    label_text_transform.Reset();
                                    global_MatrixTransformer.TranslateAppend(label_text_transform, -wh.w/2, -wh.h/2);
                                    global_MatrixTransformer.RotateRadAppend(label_text_transform, Math.PI/4);//TODO
                                    global_MatrixTransformer.TranslateAppend(label_text_transform, xc, yc);
                                    global_MatrixTransformer.MultiplyAppend(label_text_transform,this.transform);

                                    if(!AscFormat.isRealNumber(left_x))
                                    {
                                        left_x = xc - w2/2;
                                        right_x = xc + w2/2;
                                    }
                                    else
                                    {
                                        if(xc - w2/2 < left_x)
                                            left_x = xc - w2/2;
                                        if(xc + w2/2 > right_x)
                                            right_x = xc + w2/2;
                                    }

                                    local_text_transform = cat_ax.labels.aLabels[i].localTransformText;
                                    local_text_transform.Reset();
                                    global_MatrixTransformer.TranslateAppend(local_text_transform, -wh.w/2, -wh.h/2);
                                    global_MatrixTransformer.RotateRadAppend(local_text_transform, Math.PI/4);//TODO
                                    global_MatrixTransformer.TranslateAppend(local_text_transform, xc, yc);
                                }
                            }
                        }
                        cat_ax.labels.x = left_x;
                        cat_ax.labels.extX = right_x - left_x;
                    }
                }
                cat_ax.xPoints.sort(function(a, b){return a.val - b.val});
                val_ax.yPoints.sort(function(a, b){return a.val - b.val});
            }
            else{
                this.bEmptySeries = true;
            }
        }
        else if(chart_type === AscDFH.historyitem_type_BarChart && chart_object.barDir === AscFormat.BAR_DIR_BAR)
        {
            var cat_ax, val_ax;
            var axis_by_types = chart_object.getAxisByTypes();
            cat_ax = axis_by_types.catAx[0];
            val_ax = axis_by_types.valAx[0];
            if(cat_ax && val_ax)
            {
                /*---------------------new version---------------------------------------*/
                val_ax.labels  = null;
                cat_ax.labels  = null;

                val_ax.posX  = null;
                cat_ax.posY  = null;
                val_ax.posY  = null;
                cat_ax.posX  = null;

                val_ax.xPoints  = null;
                cat_ax.yPoints  = null;
                val_ax.yPoints  = null;
                cat_ax.xPoints  = null;


                val_ax.transformYPoints  = null;
                cat_ax.transformXPoints  = null;
                val_ax.transformXPoints  = null;
                cat_ax.transformYPoints  = null;
                var sizes = this.getChartSizes();
                rect = {x: sizes.startX, y:sizes.startY, w:sizes.w, h: sizes.h};
                var arr_val =  this.getValAxisValues();
                //Получим строки для оси значений с учетом формата и единиц
                var arr_strings = [];
                var multiplier;
                if(val_ax.dispUnits)
                    multiplier = val_ax.dispUnits.getMultiplier();
                else
                    multiplier = 1;
                var num_fmt = val_ax.numFmt;
                if(num_fmt && typeof num_fmt.formatCode === "string" /*&& !(num_fmt.formatCode === "General")*/)
                {
                    var num_format = oNumFormatCache.get(num_fmt.formatCode);
                    for(i = 0; i < arr_val.length; ++i)
                    {
                        var calc_value = arr_val[i]*multiplier;
                        var rich_value = num_format.formatToChart(calc_value);
                        arr_strings.push(rich_value);
                    }
                }
                else
                {
                    for(i = 0; i < arr_val.length; ++i)
                    {
                        var calc_value = arr_val[i]*multiplier;
                        arr_strings.push(calc_value + "");
                    }
                }



                //расчитаем подписи горизонтальной оси значений
                val_ax.labels = new AscFormat.CValAxisLabels(this, val_ax);
                var max_height = 0;
                val_ax.xPoints = [];
                var max_val_ax_label_width = 0;
                for(i = 0; i < arr_strings.length; ++i)
                {
                    var dlbl = new AscFormat.CDLbl();
                    dlbl.parent = val_ax;
                    dlbl.chart = this;
                    dlbl.spPr = val_ax.spPr;
                    dlbl.txPr = val_ax.txPr;
                    dlbl.tx = new AscFormat.CChartText();
                    dlbl.tx.rich = AscFormat.CreateTextBodyFromString(arr_strings[i], this.getDrawingDocument(), dlbl);
                    dlbl.txBody = dlbl.tx.rich;
                    if(val_ax.labels.aLabels[0])
                    {
                        dlbl.lastStyleObject = val_ax.labels.aLabels[0].lastStyleObject;
                    }
                    var t = dlbl.tx.rich.recalculateByMaxWord();
                    var h = t.h;
                    if(t.w > max_val_ax_label_width)
                        max_val_ax_label_width = t.w;
                    if(h > max_height)
                        max_height = h;
                    val_ax.labels.aLabels.push(dlbl);
                    val_ax.xPoints.push({val: arr_val[i], pos: null});
                }

                var val_axis_labels_gap = val_ax.labels.aLabels[0].tx.rich.content.Content[0].CompiledPr.Pr.TextPr.FontSize*25.4/72;
                val_ax.labels.extY = max_height + val_axis_labels_gap;

                //расчитаем подписи для горизонтальной оси
                var ser = chart_object.series[0];
                var string_pts = [], pts_len = 0;

                /*string_pts  pts_len*/
                if(ser && ser.cat)
                {
                    var  lit, b_num_lit = true;
                    if(ser.cat.strRef && ser.cat.strRef.strCache)
                    {
                        lit = ser.cat.strRef.strCache;
                    }
                    else if(ser.cat.strLit)
                    {
                        lit = ser.cat.strLit;
                    }
                    else if(ser.cat.numRef && ser.cat.numRef.numCache)
                    {
                        lit = ser.cat.numRef.numCache;
                        b_num_lit = true;
                    }
                    else if(ser.cat.numLit)
                    {
                        lit = ser.cat.numLit;
                        b_num_lit = true;
                    }
                    if(lit)
                    {
                        var lit_format = null, pt_format = null;
                        if(b_num_lit && typeof lit.formatCode === "string" && lit.formatCode.length > 0)
                        {
                            lit_format = oNumFormatCache.get(lit.formatCode);
                        }
                        pts_len = lit.ptCount;
                        for(i = 0; i < pts_len; ++i)
                        {
                            var pt = lit.getPtByIndex(i);
                            if(pt)
                            {
                                var str_pt;
                                if(b_num_lit)
                                {
                                    if(typeof pt.formatCode === "string" && pt.formatCode.length > 0)
                                    {
                                        pt_format = oNumFormatCache.get(pt.formatCode);
                                        if(pt_format)
                                        {
                                            str_pt = pt_format.formatToChart(pt.val);
                                        }
                                        else
                                        {
                                            str_pt = pt.val;
                                        }
                                    }
                                    else if(lit_format)
                                    {
                                        str_pt = lit_format.formatToChart(pt.val);
                                    }
                                    else
                                    {
                                        str_pt = pt.val;
                                    }
                                }
                                else
                                {
                                    str_pt = pt.val;
                                }
                                string_pts.push({val: str_pt + ""});
                            }
                            else
                            {
                                string_pts.push({val: i + ""});
                            }
                        }
                    }
                }
                //if(string_pts.length === 0)
                {
                    pts_len = 0;
                    for(i = 0; i < chart_object.series.length; ++i)
                    {
                        var cur_pts= null;
                        ser = chart_object.series[i];
                        if(ser.val)
                        {
                            if(ser.val.numRef && ser.val.numRef.numCache)
                                cur_pts = ser.val.numRef.numCache;
                            else if(ser.val.numLit)
                                cur_pts = ser.val.numLit;
                            if(cur_pts)
                            {
                                pts_len = Math.max(pts_len, cur_pts.ptCount);
                            }
                        }
                    }
                    if(pts_len > string_pts.length)
                    {
                        for(i = string_pts.length; i < pts_len; ++i)
                        {
                            string_pts.push({val:i+1 + ""});
                        }
                    }
                    else
                    {
                        string_pts.splice(pts_len, string_pts.length - pts_len);
                    }
                }
                /*---------------------расчет позиции блока с подписями вертикальной оси-----------------------------------------------------------------------------*/
                //расчитаем ширину интервала без учета горизонтальной оси;
                var crosses;//номер категории в которой вертикалная ось пересекает горизонтальную;
                if(val_ax.crosses === AscFormat.CROSSES_AUTO_ZERO || val_ax.crosses === AscFormat.CROSSES_MIN)
                    crosses = 1;
                else if(val_ax.crosses === AscFormat.CROSSES_MAX)
                    crosses = string_pts.length;
                else if(AscFormat.isRealNumber(val_ax.crossesAt))
                {
                    if(val_ax.crossesAt <= string_pts.length + 1 && val_ax.crossesAt > 0)
                        crosses = val_ax.crossesAt;
                    else if(val_ax.crossesAt <= 0)
                        crosses = 1;
                    else
                        crosses = string_pts.length;
                }
                else
                    crosses = 1;


                cat_ax.maxCatVal = string_pts.length;

                var cat_ax_orientation = cat_ax.scaling && AscFormat.isRealNumber(cat_ax.scaling.orientation) ?  cat_ax.scaling.orientation : AscFormat.ORIENTATION_MIN_MAX;
                var labels_pos = val_ax.tickLblPos;
                var cross_between = this.getValAxisCrossType();
                if(cross_between === null){
                    cross_between = AscFormat.CROSS_BETWEEN_BETWEEN;
                }


                var bottom_val_ax_labels_align = true;//приленгание подписей оси значений к левому краю.

                var intervals_count = cross_between === AscFormat.CROSS_BETWEEN_MID_CAT ? string_pts.length - 1 : string_pts.length;
                var point_interval  = rect.h/intervals_count;//интервал между точками. Зависит от crossBetween, а также будет потом корректироваться в зависимости от подписей вертикальной и горизонтальной оси.


                var bottom_points_height, top_point_height;
                var arr_cat_labels_points = [];//массив середин подписей горизонтальной оси; i-й элемент - x-координата центра подписи категории с номером i;
                if(cat_ax_orientation === AscFormat.ORIENTATION_MIN_MAX)
                {
                    if(labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE || val_ax.bDelete === true)
                    {
                        val_ax.labels = null;
                        if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = rect.y + rect.h - point_interval*i;
                        }
                        else
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = rect.y + rect.h - (point_interval/2 + point_interval*i);
                        }
                        val_ax.posY = rect.y + rect.h - point_interval*(crosses-1);
                    }
                    else if(labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO || !AscFormat.isRealNumber(labels_pos)) //подписи рядом с осью
                    {
                        if(val_ax.crosses === AscFormat.CROSSES_MAX)
                        {
                            if(!bWithoutLabels){
                                val_ax.labels.y = rect.y;
                                point_interval = checkFiniteNumber((rect.h - val_ax.labels.extY)/intervals_count);
                            }
                            else{
                                val_ax.labels.y = rect.y - val_ax.labels.extY;
                            }
                            bottom_val_ax_labels_align = false;
                            val_ax.posY = val_ax.labels.y + val_ax.labels.extY;
                            if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                            {
                                for(i = 0; i < string_pts.length; ++i)
                                    arr_cat_labels_points[i] = rect.y + rect.h - point_interval*i;
                            }
                            else
                            {
                                for(i = 0; i < string_pts.length; ++i)
                                    arr_cat_labels_points[i] = point_interval/2 + rect.y + rect.h - point_interval*i;
                            }
                        }
                        else
                        {
                            bottom_points_height = point_interval*(crosses-1);//общая ширина левых точек если считать что точки занимают все пространство
                            if(bottom_points_height < val_ax.labels.extY && !bWithoutLabels)//подписи верт. оси выходят за пределы области построения
                            {
                                var top_intervals_count = intervals_count - (crosses - 1);//количесво интервалов выше горизонтальной оси
                                //скорректируем point_interval, поделив расстояние, которое осталось справа от подписей осей на количество интервалов справа
                                point_interval = checkFiniteNumber((rect.h - val_ax.labels.extY)/top_intervals_count);
                                val_ax.labels.y = rect.y + rect.h - val_ax.labels.extY;
                                var start_point = val_ax.labels.y + (crosses-1)*point_interval;//y-координата точки низа области постоения

                                if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = start_point - point_interval*i;
                                }
                                else
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = start_point - point_interval/2 - point_interval*i;
                                }
                            }
                            else
                            {
                                val_ax.labels.y = rect.y + rect.h - bottom_points_height;
                                if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = rect.y + rect.h - point_interval*i;
                                }
                                else
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = rect.y + rect.h - (point_interval/2 + point_interval*i);
                                }
                            }
                            val_ax.posY = val_ax.labels.y;
                        }
                    }
                    else if(labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_LOW)//подписи снизу от области построения
                    {
						if(!bWithoutLabels){
							point_interval = checkFiniteNumber((rect.h -  val_ax.labels.extY)/intervals_count);
							val_ax.labels.y = rect.y + rect.h - val_ax.labels.extY;	
						}
						else{
							val_ax.labels.y = rect.y + rect.h;	
						}
                        if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = val_ax.labels.y - point_interval*i;
                        }
                        else
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = rect.y + rect.h  - val_ax.labels.extY - point_interval/2 - point_interval*i;
                        }
                        val_ax.posY = val_ax.labels.y - point_interval*(crosses-1);
                    }
                    else if(labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_HIGH)//подписи сверху от области построения
                    {
						if(!bWithoutLabels){
							point_interval = checkFiniteNumber((rect.h - val_ax.labels.extY)/intervals_count);
							val_ax.labels.y = rect.y;
						}
						else{
							val_ax.labels.y = rect.y - val_ax.labels.extY;
						}
                        point_interval = checkFiniteNumber((rect.h - val_ax.labels.extY)/intervals_count);
                        val_ax.labels.y = rect.y;
                        bottom_val_ax_labels_align = false;
                        if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = rect.y + rect.h - point_interval*i;
                        }
                        else
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] =rect.y + rect.h - (point_interval/2 + point_interval*i);
                        }
                        val_ax.posY = rect.y + rect.h - point_interval*(crosses-1);
                    }
                    else
                    {
                        val_ax.labels = null;
                        if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = rect.y + rect.h - point_interval*i;
                        }
                        else
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = rect.y + rect.h - (point_interval/2 + point_interval*i);
                        }
                        val_ax.posY = rect.y + rect.h - point_interval*(crosses-1);
                    }
                }
                else
                {//то же самое, только зеркально отраженное
                    if(labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE || val_ax.bDelete === true)
                    {
                        val_ax.labels = null;
                        if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = rect.y + point_interval*i;
                        }
                        else
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = rect.y + point_interval/2 + point_interval*i;
                        }
                        val_ax.posY = rect.y + point_interval*(crosses-1);
                    }
                    else if(labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO || !AscFormat.isRealNumber(labels_pos)) //подписи рядом с осью
                    {
                        if(val_ax.crosses === AscFormat.CROSSES_MAX)
                        {
							if(!bWithoutLabels){
								val_ax.labels.y = rect.y + rect.h - val_ax.labels.extY;
								point_interval = checkFiniteNumber((rect.h - val_ax.labels.extY)/intervals_count);
							}
							else{
								val_ax.labels.y = rect.y + rect.h;								
							}
                            if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                            {
                                for(i = 0; i < string_pts.length; ++i)
                                    arr_cat_labels_points[i] = rect.y + point_interval*i;
                            }
                            else
                            {
                                for(i = 0; i < string_pts.length; ++i)
                                    arr_cat_labels_points[i] = rect.y + point_interval/2 + point_interval*i;
                            }
                            val_ax.posY = val_ax.labels.y;
                        }
                        else
                        {
                            bottom_val_ax_labels_align = false;
                            top_point_height = point_interval*(crosses-1);
                            if(top_point_height < val_ax.labels.extY && !bWithoutLabels)
                            {
                                val_ax.labels.y = rect.y;
                                var bottom_points_interval_count = intervals_count - (crosses - 1);
                                point_interval = checkFiniteNumber((rect.h - val_ax.labels.extY)/bottom_points_interval_count);
                                var start_point_bottom = rect.y + rect.h - point_interval*intervals_count;
                                if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = start_point_bottom + point_interval*i;
                                }
                                else
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = start_point_bottom + point_interval/2 + point_interval*i;
                                }
                            }
                            else
                            {
                                val_ax.labels.y = rect.y +  point_interval*(crosses-1) - val_ax.labels.extY;
                                if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = rect.y + point_interval*i;
                                }
                                else
                                {
                                    for(i = 0; i < string_pts.length; ++i)
                                        arr_cat_labels_points[i] = rect.y + point_interval/2 + point_interval*i;
                                }
                            }
                            val_ax.posY = val_ax.labels.y + val_ax.labels.extY;
                        }
                    }
                    else if(labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_LOW)//подписи сверху от области построения
                    {
                        bottom_val_ax_labels_align = false;
						if(!bWithoutLabels){
							point_interval = checkFiniteNumber((rect.h - val_ax.labels.extY)/intervals_count);
							val_ax.labels.y = rect.y;	
						}
						else{
							val_ax.labels.y = rect.y - val_ax.labels.extY;	
						}
                        if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = val_ax.labels.y + val_ax.labels.extY + point_interval*i;
                        }
                        else
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = val_ax.labels.y + val_ax.labels.extY + point_interval/2 + point_interval*i;
                        }
                        val_ax.posY = rect.y + val_ax.labels.extY + point_interval*(crosses-1);
                    }
                    else if(labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_HIGH)//подписи снизу от области построения
                    {
						if(!bWithoutLabels){
							point_interval = checkFiniteNumber((rect.h - val_ax.labels.extY)/intervals_count);
							val_ax.labels.y = rect.y + rect.h - val_ax.labels.extY;
						}
						else{
							val_ax.labels.y = rect.y + rect.h;
						}
                        if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = rect.y + point_interval*i;
                        }
                        else
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = rect.y + point_interval/2 + point_interval*i;
                        }
                        val_ax.posY = rect.y + point_interval*(crosses-1);
                    }
                    else
                    {
                        val_ax.labels = null;
                        if(cross_between === AscFormat.CROSS_BETWEEN_MID_CAT)
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = rect.y + point_interval*i;
                        }
                        else
                        {
                            for(i = 0; i < string_pts.length; ++i)
                                arr_cat_labels_points[i] = rect.y + point_interval/2 + point_interval*i;
                        }
                        val_ax.posY = rect.y + point_interval*(crosses-1);
                    }
                }

                cat_ax.interval = point_interval;

                var diagram_height = point_interval*intervals_count;//размер области с самой диаграммой позже будет корректироватся;
                var max_cat_label_height = diagram_height / string_pts.length; // максимальная высота подписи горизонтальной оси;

                cat_ax.labels = null;
                var max_cat_labels_block_width = rect.w/2;
                if(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE !== cat_ax.tickLblPos && !(cat_ax.bDelete === true)) //будем корректировать вертикальные подписи только если есть горизонтальные
                {
                    cat_ax.labels = new AscFormat.CValAxisLabels(this, cat_ax);
                    var tick_lbl_skip = AscFormat.isRealNumber(cat_ax.tickLblSkip) ? cat_ax.tickLblSkip : (string_pts.length < SKIP_LBL_LIMIT ?  1 :  Math.floor(string_pts.length/SKIP_LBL_LIMIT));
                    var max_min_width = 0;
                    var max_max_width = 0;
                    var max_content_width = 0;
                    var arr_min_max_min = [];
                    for(i = 0; i < string_pts.length; ++i)
                    {
                        var dlbl = null;
                        if(i%tick_lbl_skip === 0)
                        {
                            dlbl = new AscFormat.CDLbl();
                            dlbl.parent = cat_ax;
                            dlbl.chart = this;
                            dlbl.spPr = cat_ax.spPr;
                            dlbl.txPr = cat_ax.txPr;
                            dlbl.tx = new AscFormat.CChartText();
                            dlbl.tx.rich = AscFormat.CreateTextBodyFromString(string_pts[i].val.replace(oNonSpaceRegExp, ' '), this.getDrawingDocument(), dlbl);
                            if(cat_ax.labels.aLabels[0])
                            {
                                dlbl.lastStyleObject = cat_ax.labels.aLabels[0].lastStyleObject;
                            }
                            dlbl.tx.rich.content.Set_ApplyToAll(true);
                            dlbl.tx.rich.content.SetParagraphAlign(AscCommon.align_Center);
                            dlbl.tx.rich.content.Set_ApplyToAll(false);
                            var min_max =  dlbl.tx.rich.content.RecalculateMinMaxContentWidth();
                            var max_min_content_width = min_max.Min;
                            if(min_max.Max > max_max_width)
                                max_max_width = min_max.Max;

                            if(min_max.Min > max_min_width)
                                max_min_width = min_max.Min;

                            arr_min_max_min[i] = min_max.Min;

                            dlbl.getMaxWidth = function(){return 20000};
                            dlbl.recalcInfo.recalculatePen = false;
                            dlbl.recalcInfo.recalculateBrush = false;
                            dlbl.recalculate();
                            delete dlbl.getMaxWidth;
                            if(dlbl.tx.rich.content.XLimit > max_content_width)
                                max_content_width = dlbl.tx.rich.content.XLimit;
                        }
                        cat_ax.labels.aLabels.push(dlbl);
                    }
                    var stake_offset = AscFormat.isRealNumber(cat_ax.lblOffset) ? cat_ax.lblOffset/100 : 1;
                    var labels_offset = cat_ax.labels.aLabels[0].tx.rich.content.Content[0].CompiledPr.Pr.TextPr.FontSize*(25.4/72)*stake_offset;
                    //сначала посмотрим убираются ли в максимальную допустимую ширину подписей подписи расчитанные в одну строку

                    var width_flag;
                    if(max_content_width + labels_offset < max_cat_labels_block_width)
                    {
                        width_flag = 0;
                        cat_ax.labels.extX = max_content_width + labels_offset;
                    }
                    else if(max_min_width + labels_offset < max_cat_labels_block_width)//ситуация, когда возможно разместить подписи без переноса слов
                    {
                        width_flag = 1;
                        cat_ax.labels.extX = max_min_width + labels_offset;
                    }
                    else //выставляем максимально возможную ширину
                    {
                        width_flag = 2;
                        cat_ax.labels.extX = max_cat_labels_block_width;
                    }
                }
                var cat_labels_align_left = true;//выравнивание подписей в блоке сподписями по левому краю(т. е. зазор находится справа)
                /*-----------------------------------------------------------------------*/
                var crosses_val_ax;//значение на горизонтальной оси значений в котором её пересекает горизонтальная
                if(cat_ax.crosses === AscFormat.CROSSES_AUTO_ZERO)
                {
                    if(arr_val[0] <=0 && arr_val[arr_val.length-1] >= 0)
                        crosses_val_ax = 0;
                    else if(arr_val[arr_val.length-1] < 0)
                        crosses_val_ax = arr_val[arr_val.length-1];
                    else
                        crosses_val_ax = arr_val[0];
                }
                else if(cat_ax.crosses === AscFormat.CROSSES_MIN)
                {
                    crosses_val_ax = arr_val[0];
                }
                else if(cat_ax.crosses === AscFormat.CROSSES_MAX)
                {
                    crosses_val_ax = arr_val[arr_val.length - 1];
                }
                else if(AscFormat.isRealNumber(cat_ax.crossesAt) && cat_ax.crossesAt >= arr_val[0] && cat_ax.crossesAt <= arr_val[arr_val.length - 1])
                {
                    //сделаем провеку на попадание в интервал
                    if(cat_ax.crossesAt >= arr_val[0] && cat_ax.crossesAt <= arr_val[arr_val.length - 1])
                        crosses_val_ax = cat_ax.crossesAt;
                }
                else
                { //ведем себя как в случае (cat_ax.crosses === AscFormat.CROSSES_AUTO_ZERO)
                    if(arr_val[0] <=0 && arr_val[arr_val.length-1] >= 0)
                        crosses_val_ax = 0;
                    else if(arr_val[arr_val.length-1] < 0)
                        crosses_val_ax = arr_val[arr_val.length-1];
                    else
                        crosses_val_ax = arr_val[0];
                }
                var val_ax_orientation = val_ax.scaling && AscFormat.isRealNumber(val_ax.scaling.orientation) ? val_ax.scaling.orientation : AscFormat.ORIENTATION_MIN_MAX;
                var hor_labels_pos = cat_ax.tickLblPos;



                var first_val_lbl_half_width = (val_ax.tickLblPos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE || val_ax.bDelete) ? 0 : val_ax.labels.aLabels[0].tx.rich.content.XLimit/2;
                var last_val_lbl_half_width = (val_ax.tickLblPos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE || val_ax.bDelete) ? 0 : val_ax.labels.aLabels[val_ax.labels.aLabels.length-1].tx.rich.content.XLimit/2;
                var right_gap, left_gap;

                var arr_val_labels_points = [];//массив середин подписей вертикальной оси; i-й элемент - x-координата центра подписи i-огто значения;
                var unit_width = checkFiniteNumber((rect.w - first_val_lbl_half_width - last_val_lbl_half_width)/(arr_val[arr_val.length - 1] - arr_val[0]));//ширина единицы измерения на вертикальной оси
                var cat_ax_ext_x = cat_ax.labels && !bWithoutLabels ? cat_ax.labels.extX : 0;
                if(val_ax_orientation === AscFormat.ORIENTATION_MIN_MAX)
                {
                    if(hor_labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO || !AscFormat.isRealNumber(hor_labels_pos))
                    {
                        if(cat_ax.crosses === AscFormat.CROSSES_MAX)
                        {
                            if(!bNeedReflect)
                            {
                                right_gap = Math.max(last_val_lbl_half_width, cat_ax_ext_x);
                            }
                            else
                            {
                                right_gap = Math.max(last_val_lbl_half_width, 0);
                            }
                            cat_labels_align_left = false;//в данном случае подписи будут выравниваться по верхнему краю блока с подписями
                            if(cat_ax.labels)
                                cat_ax.labels.x = rect.x + rect.w - right_gap;
                            unit_width = checkFiniteNumber((rect.w - right_gap - first_val_lbl_half_width)/(arr_val[arr_val.length - 1] - arr_val[0]));
                            cat_ax.posX = rect.x + first_val_lbl_half_width + (crosses_val_ax - arr_val[0])*unit_width;
                        }
                        else
                        {
                            if(!bNeedReflect && (crosses_val_ax - arr_val[0])*unit_width + first_val_lbl_half_width  < cat_ax_ext_x)
                            {
                                unit_width = checkFiniteNumber((rect.w -  cat_ax_ext_x - last_val_lbl_half_width)/(arr_val[arr_val.length-1] - crosses_val_ax));
                            }
                            cat_ax.posX = rect.x + rect.w - last_val_lbl_half_width - (arr_val[arr_val.length-1] - crosses_val_ax)*unit_width;
                            if(cat_ax.labels)
                                cat_ax.labels.x = cat_ax.posX - cat_ax.labels.extX;
                        }
                        for(i = 0; i < arr_val.length; ++i)
                            arr_val_labels_points[i] = cat_ax.posX + (arr_val[i] - crosses_val_ax)*unit_width;
                    }
                    else if(hor_labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_LOW)
                    {
                        if(!bNeedReflect)
                        {
                            left_gap = Math.max(first_val_lbl_half_width, cat_ax_ext_x);
                        }
                        else
                        {
                            left_gap = Math.max(first_val_lbl_half_width, 0);
                        }


                        unit_width = checkFiniteNumber((rect.w - left_gap - last_val_lbl_half_width)/(arr_val[arr_val.length - 1] - arr_val[0]));

                        cat_ax.posX = rect.x + rect.w - (arr_val[arr_val.length-1] - crosses_val_ax )*unit_width - last_val_lbl_half_width;

                        for(i = 0; i < arr_val.length; ++i)
                            arr_val_labels_points[i] = cat_ax.posX + (arr_val[i] - crosses_val_ax)*unit_width;
                        if(cat_ax.labels)
                            cat_ax.labels.x = cat_ax.posX + (arr_val[i] - crosses_val_ax)*unit_width - cat_ax.labels.extX;
                    }
                    else if(hor_labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_HIGH)
                    {
                        cat_labels_align_left = false;

                        if(!bNeedReflect)
                        {
                            right_gap = Math.max(last_val_lbl_half_width, cat_ax_ext_x);
                        }
                        else
                        {
                            right_gap = Math.max(last_val_lbl_half_width, 0);
                        }

                        unit_width = checkFiniteNumber((rect.w - right_gap - first_val_lbl_half_width)/(arr_val[arr_val.length - 1] - arr_val[0]));
                        cat_ax.posX = rect.x +  first_val_lbl_half_width + (crosses_val_ax - arr_val[0])*unit_width;

                        for(i = 0; i < arr_val.length; ++i)
                            arr_val_labels_points[i] = cat_ax.posX + (arr_val[i] - crosses_val_ax)*unit_width;
                    }
                    else
                    {
                        //подписей осей нет
                        cat_ax.labels = null;
                        unit_width = checkFiniteNumber((rect.w - last_val_lbl_half_width - first_val_lbl_half_width)/(arr_val[arr_val.length - 1] - arr_val[0]));
                        cat_ax.posX = rect.x +  first_val_lbl_half_width + (crosses_val_ax - arr_val[0])*unit_width;
                        for(i = 0; i < arr_val.length; ++i)
                            arr_val_labels_points[i] = cat_ax.posX + (arr_val[i] - crosses_val_ax)*unit_width;
                    }
                }
                else
                {//зеркально отражаем
                    if(hor_labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO || !AscFormat.isRealNumber(hor_labels_pos))
                    {
                        if(cat_ax.crosses === AscFormat.CROSSES_MAX)
                        {
                            if(!bNeedReflect)
                            {
                                left_gap = Math.max(cat_ax_ext_x, last_val_lbl_half_width);
                            }
                            else
                            {
                                left_gap = Math.max(0, last_val_lbl_half_width);
                            }
                            unit_width = checkFiniteNumber((rect.w - left_gap - first_val_lbl_half_width)/(arr_val[arr_val.length - 1] - arr_val[0]));
                            cat_ax.posX = rect.x + rect.w - first_val_lbl_half_width - (crosses_val_ax - arr_val[0])*unit_width;
                            if(cat_ax.labels)
                                cat_ax.labels.x = cat_ax.posX - cat_ax.labels.extX;
                        }
                        else
                        {
                            cat_labels_align_left = false;
                            if(!bNeedReflect && first_val_lbl_half_width < cat_ax_ext_x)
                            {
                                unit_width = checkFiniteNumber((rect.w - cat_ax_ext_x - last_val_lbl_half_width)/(arr_val[arr_val.length - 1] - arr_val[0]));
                            }
                            cat_ax.posX = rect.x + last_val_lbl_half_width + (arr_val[arr_val.length-1] - crosses_val_ax)*unit_width;
                            if(cat_ax.labels)
                                cat_ax.labels.x = cat_ax.posX;
                        }
                        for(i = 0; i < arr_val.length; ++i)
                            arr_val_labels_points[i] = cat_ax.posX - (arr_val[i] - crosses_val_ax)*unit_width;
                    }
                    else if(hor_labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_LOW)
                    {
                        cat_labels_align_left = false;
                        if(!bNeedReflect)
                        {
                            right_gap = Math.max(first_val_lbl_half_width, cat_ax_ext_x);
                        }
                        else
                        {
                            right_gap = Math.max(first_val_lbl_half_width, 0);
                        }

                        unit_width = checkFiniteNumber((rect.w - last_val_lbl_half_width - right_gap)/(arr_val[arr_val.length-1] - arr_val[0]));
                        cat_ax.posX = rect.x + last_val_lbl_half_width + (arr_val[arr_val.length-1] - crosses_val_ax)*crosses_val_ax;
                        if(cat_ax.labels)
                            cat_ax.labels.x = cat_ax.posX - (arr_val[0] - crosses_val_ax)*unit_width;
                        for(i = 0; i < arr_val.length; ++i)
                            arr_val_labels_points[i] = cat_ax.posX - (arr_val[i] - crosses_val_ax)*unit_width;

                    }
                    else if(hor_labels_pos === c_oAscTickLabelsPos.TICK_LABEL_POSITION_HIGH)
                    {
                        if(!bNeedReflect)
                        {
                            left_gap = Math.max(cat_ax_ext_x, last_val_lbl_half_width);
                        }
                        else
                        {
                            left_gap = Math.max(0, last_val_lbl_half_width);
                        }

                        unit_width = checkFiniteNumber((rect.w - left_gap - first_val_lbl_half_width)/(arr_val[arr_val.length - 1] - arr_val[0]));
                        cat_ax.posX = rect.x + rect.w - first_val_lbl_half_width - (crosses_val_ax - arr_val[0])*unit_width;
                        if(cat_ax.labels)
                            cat_ax.labels.x = cat_ax.posX - (arr_val[arr_val.length-1] - crosses_val_ax)*unit_width - cat_ax.labels.extX;
                        for(i = 0; i < arr_val.length; ++i)
                            arr_val_labels_points[i] = cat_ax.posX - (arr_val[i] - crosses_val_ax)*unit_width;
                    }
                    else
                    {//подписей осей нет
                        cat_ax.labels = null;
                        unit_width = checkFiniteNumber((rect.w - last_val_lbl_half_width - first_val_lbl_half_width)/(arr_val[arr_val.length - 1] - arr_val[0]));
                        cat_ax.posX = rect.x + rect.w - first_val_lbl_half_width - (crosses_val_ax - arr_val[0])*unit_width;
                        for(i = 0; i < arr_val.length; ++i)
                            arr_val_labels_points[i] = cat_ax.posX - (arr_val[i] - crosses_val_ax)*unit_width;
                    }
                }
                val_ax.interval = unit_width;
                //запишем в оси необходимую информацию для отрисовщика plotArea  и выставим окончательные позиции для подписей
                var local_transform_text;
                if(val_ax.labels)
                {
                    val_ax.labels.x = Math.min.apply(Math, arr_val_labels_points) - max_val_ax_label_width/2;
                    val_ax.labels.extX = Math.max.apply(Math, arr_val_labels_points) - Math.min.apply(Math, arr_val_labels_points) + max_val_ax_label_width;
                    //val_axis_labels_gap - вертикальный зазор

                    val_ax.labels.align = bottom_val_ax_labels_align;
                    if(bottom_val_ax_labels_align)
                    {
                        var y_pos = val_ax.labels.y + val_axis_labels_gap;
                        for(i = 0;  i < val_ax.labels.aLabels.length; ++i)
                        {
                            var text_transform = val_ax.labels.aLabels[i].transformText;
                            text_transform.Reset();
                            global_MatrixTransformer.TranslateAppend(text_transform, arr_val_labels_points[i] - val_ax.labels.aLabels[i].tx.rich.content.XLimit/2, y_pos);
                           // global_MatrixTransformer.MultiplyAppend(text_transform, this.getTransformMatrix());

                            var local_transform_text = val_ax.labels.aLabels[i].localTransformText;
                            local_transform_text.Reset();
                            global_MatrixTransformer.TranslateAppend(local_transform_text, arr_val_labels_points[i] - val_ax.labels.aLabels[i].tx.rich.content.XLimit/2, y_pos);
                        }
                    }
                    else
                    {
                        for(i = 0;  i < val_ax.labels.aLabels.length; ++i)
                        {
                            var text_transform = val_ax.labels.aLabels[i].transformText;
                            text_transform.Reset();
                            global_MatrixTransformer.TranslateAppend(text_transform, arr_val_labels_points[i] - val_ax.labels.aLabels[i].tx.rich.content.XLimit/2, val_ax.labels.y + val_ax.labels.extY - val_axis_labels_gap - val_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight());
                        //    global_MatrixTransformer.MultiplyAppend(text_transform, this.getTransformMatrix());


                            var local_transform_text = val_ax.labels.aLabels[i].localTransformText;
                            local_transform_text.Reset();
                            global_MatrixTransformer.TranslateAppend(local_transform_text, arr_val_labels_points[i] - val_ax.labels.aLabels[i].tx.rich.content.XLimit/2, val_ax.labels.y + val_ax.labels.extY - val_axis_labels_gap - val_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight());
                        }
                    }
                }
                val_ax.xPoints = [];


                for(i = 0; i < arr_val_labels_points.length; ++i)
                {
                    val_ax.xPoints[i] = {val:arr_val[i], pos: arr_val_labels_points[i]};
                }

                cat_ax.yPoints = [];
                for(i = 0; i <arr_cat_labels_points.length; ++i)
                {
                    cat_ax.yPoints[i] = {val: i + 1, pos: arr_cat_labels_points[i]};
                }
                if(cat_ax.labels)
                {
                    cat_ax.labels.y = rect.y;
                    cat_ax.labels.extY = point_interval*intervals_count;

                    if(bNeedReflect)
                    {
                        if(cat_labels_align_left)
                        {
                            cat_labels_align_left = false;
                            cat_ax.labels.x += cat_ax.labels.extX;
                        }
                        else
                        {
                            cat_labels_align_left = true;
                            cat_ax.labels.x -= cat_ax.labels.extX;
                        }
                    }
                    if(cat_labels_align_left)
                    {


                        if(width_flag === 0)
                        {
                            for(i = 0; i < cat_ax.labels.aLabels.length; ++i)
                            {
                                if(cat_ax.labels.aLabels[i])
                                {
                                    var transform_text = cat_ax.labels.aLabels[i].transformText;
                                    transform_text.Reset();
                                    global_MatrixTransformer.TranslateAppend(transform_text, cat_ax.labels.x + cat_ax.labels.extX - cat_ax.labels.aLabels[i].tx.rich.content.XLimit - labels_offset, arr_cat_labels_points[i] - cat_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);
                               //     global_MatrixTransformer.MultiplyAppend(transform_text, this.getTransformMatrix());

                                    local_transform_text = cat_ax.labels.aLabels[i].localTransformText;
                                    local_transform_text.Reset();
                                    global_MatrixTransformer.TranslateAppend(local_transform_text, cat_ax.labels.x + cat_ax.labels.extX - cat_ax.labels.aLabels[i].tx.rich.content.XLimit - labels_offset, arr_cat_labels_points[i] - cat_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);

                                }
                            }
                        }
                        else if(width_flag === 1)
                        {
                            for(i = 0; i < cat_ax.labels.aLabels.length; ++i)
                            {
                                if(cat_ax.labels.aLabels[i])
                                {
                                    cat_ax.labels.aLabels[i].tx.rich.content.Reset(0, 0, arr_min_max_min[i], 20000);
                                    cat_ax.labels.aLabels[i].tx.rich.content.Recalculate_Page(0, true);

                                    var transform_text = cat_ax.labels.aLabels[i].transformText;
                                    transform_text.Reset();
                                    global_MatrixTransformer.TranslateAppend(transform_text, cat_ax.labels.x + cat_ax.labels.extX - cat_ax.labels.aLabels[i].tx.rich.content.XLimit - labels_offset, arr_cat_labels_points[i] - cat_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);
                                  //  global_MatrixTransformer.MultiplyAppend(transform_text, this.getTransformMatrix());

                                    local_transform_text = cat_ax.labels.aLabels[i].localTransformText;
                                    local_transform_text.Reset();
                                    global_MatrixTransformer.TranslateAppend(local_transform_text, cat_ax.labels.x + cat_ax.labels.extX - cat_ax.labels.aLabels[i].tx.rich.content.XLimit - labels_offset, arr_cat_labels_points[i] - cat_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);

                                }
                            }
                        }
                        else
                        {
                            for(i = 0; i < cat_ax.labels.aLabels.length; ++i)
                            {
                                if(cat_ax.labels.aLabels[i])
                                {
                                    cat_ax.labels.aLabels[i].tx.rich.content.Reset(0, 0, cat_ax.labels.extX - labels_offset, 20000);
                                    cat_ax.labels.aLabels[i].tx.rich.content.Recalculate_Page(0, true);

                                    var transform_text = cat_ax.labels.aLabels[i].transformText;
                                    transform_text.Reset();
                                    global_MatrixTransformer.TranslateAppend(transform_text, cat_ax.labels.x + cat_ax.labels.extX - cat_ax.labels.aLabels[i].tx.rich.content.XLimit - labels_offset, arr_cat_labels_points[i] - cat_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);
                                  //  global_MatrixTransformer.MultiplyAppend(transform_text, this.getTransformMatrix());

                                    local_text_transform = cat_ax.labels.aLabels[i].localTransformText;
                                    local_text_transform.Reset();
                                    global_MatrixTransformer.TranslateAppend(local_text_transform, cat_ax.labels.x + cat_ax.labels.extX - cat_ax.labels.aLabels[i].tx.rich.content.XLimit - labels_offset, arr_cat_labels_points[i] - cat_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);

                                }
                            }
                        }



                        /*for(i = 0; i < cat_ax.labels.aLabels.length; ++i)
                         {
                         if(cat_ax.labels.aLabels[i])
                         {
                         cat_ax.labels.aLabels[i].tx.rich.content.Set_ApplyToAll(true);
                         cat_ax.labels.aLabels[i].tx.rich.content.SetParagraphAlign(align_Center);
                         cat_ax.labels.aLabels[i].tx.rich.content.Set_ApplyToAll(false);
                         cat_ax.labels.aLabels[i].tx.rich.content.Reset(0, 0, cat_ax.labels.extX - labels_offset, 2000);
                         cat_ax.labels.aLabels[i].tx.rich.content.Recalculate_Page(0, true);
                         cat_ax.labels.aLabels[i].setPosition(cat_ax.labels.x, arr_cat_labels_points[i] - cat_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);
                         }
                         }    */
                    }
                    else
                    {
                        if(width_flag === 0)
                        {
                            for(i = 0; i < cat_ax.labels.aLabels.length; ++i)
                            {
                                if(cat_ax.labels.aLabels[i])
                                {
                                    var transform_text = cat_ax.labels.aLabels[i].transformText;
                                    transform_text.Reset();
                                    global_MatrixTransformer.TranslateAppend(transform_text, cat_ax.labels.x + labels_offset, arr_cat_labels_points[i] - cat_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);
                                 //   global_MatrixTransformer.MultiplyAppend(transform_text, this.getTransformMatrix());

                                    local_text_transform = cat_ax.labels.aLabels[i].localTransformText;
                                    local_text_transform.Reset();
                                    global_MatrixTransformer.TranslateAppend(local_text_transform, cat_ax.labels.x + labels_offset, arr_cat_labels_points[i] - cat_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);

                                }
                            }
                        }
                        else if(width_flag === 1)
                        {
                            for(i = 0; i < cat_ax.labels.aLabels.length; ++i)
                            {
                                if(cat_ax.labels.aLabels[i])
                                {
                                    cat_ax.labels.aLabels[i].tx.rich.content.Reset(0, 0, arr_min_max_min[i], 20000);
                                    cat_ax.labels.aLabels[i].tx.rich.content.Recalculate_Page(0, true);

                                    var transform_text = cat_ax.labels.aLabels[i].transformText;
                                    transform_text.Reset();
                                    global_MatrixTransformer.TranslateAppend(transform_text, cat_ax.labels.x + labels_offset, arr_cat_labels_points[i] - cat_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);
                                  //  global_MatrixTransformer.MultiplyAppend(transform_text, this.getTransformMatrix());

                                    local_text_transform = cat_ax.labels.aLabels[i].localTransformText;
                                    local_text_transform.Reset();
                                    global_MatrixTransformer.TranslateAppend(local_text_transform, cat_ax.labels.x + labels_offset, arr_cat_labels_points[i] - cat_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);

                                }
                            }
                        }
                        else
                        {
                            for(i = 0; i < cat_ax.labels.aLabels.length; ++i)
                            {
                                if(cat_ax.labels.aLabels[i])
                                {
                                    cat_ax.labels.aLabels[i].tx.rich.content.Reset(0, 0, cat_ax.labels.extX - labels_offset, 20000);
                                    cat_ax.labels.aLabels[i].tx.rich.content.Recalculate_Page(0, true);
                                    var transform_text = cat_ax.labels.aLabels[i].transformText;
                                    transform_text.Reset();
                                    global_MatrixTransformer.TranslateAppend(transform_text, cat_ax.labels.x + labels_offset, arr_cat_labels_points[i] - cat_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);
                                  //  global_MatrixTransformer.MultiplyAppend(transform_text, this.getTransformMatrix());

                                    local_text_transform = cat_ax.labels.aLabels[i].localTransformText;
                                    local_text_transform.Reset();
                                    global_MatrixTransformer.TranslateAppend(local_text_transform, cat_ax.labels.x + labels_offset, arr_cat_labels_points[i] - cat_ax.labels.aLabels[i].tx.rich.content.GetSummaryHeight()/2);
                                }
                            }
                        }
                    }
                }

                cat_ax.yPoints.sort(function(a, b){return a.val - b.val});
                val_ax.xPoints.sort(function(a, b){return a.val - b.val});
            }
            else{
                this.bEmptySeries = true;
            }
        }
        this.plotAreaRect = rect;
    }
};

CChartSpace.prototype.checkAxisLabelsTransform = function()
{
    if(this.chart && this.chart.plotArea && this.chart.plotArea.charts[0] && this.chart.plotArea.charts[0].getAxisByTypes)
    {
        var oAxisByTypes = this.chart.plotArea.charts[0].getAxisByTypes();
        var oCatAx = oAxisByTypes.catAx[0], oValAx = oAxisByTypes.valAx[0], deltaX, deltaY, i, oAxisLabels, oLabel, oNewPos;
        var oProcessor3D = this.chartObj && this.chartObj.processor3D;
        var aXPoints = [], aYPoints = [];
        if(oCatAx && oValAx && oProcessor3D)
        {
            if(( (oCatAx.axPos === AscFormat.AX_POS_B || oCatAx.axPos === AscFormat.AX_POS_T) && oCatAx.xPoints) &&
                ((oValAx.axPos === AscFormat.AX_POS_L || oValAx.axPos === AscFormat.AX_POS_R) && oValAx.yPoints))
            {
                oAxisLabels = oCatAx.labels;
                
                if(oAxisLabels)
                {
                    var dZPositionCatAxis = oProcessor3D.calculateZPositionCatAxis();
                    var dPosY, dPosY2
                    if(oAxisLabels.align)
                    {
                        dPosY = oAxisLabels.y*this.chartObj.calcProp.pxToMM;
                        dPosY2 = oAxisLabels.y;
                    }
                    else
                    {

                        dPosY = (oAxisLabels.y + oAxisLabels.extY)*this.chartObj.calcProp.pxToMM;
                        dPosY2 = oAxisLabels.y + oAxisLabels.extY;
                    }
                    var fBottomLabels = -100;
                    if(!oAxisLabels.bRotated)
                    {
                        for(i = 0; i < oAxisLabels.aLabels.length; ++i)
                        {
                            oLabel = oAxisLabels.aLabels[i];
                            if(oLabel)
                            {
                                var oCPosLabelX;
                                oCPosLabelX = oLabel.localTransformText.TransformPointX(oLabel.txBody.content.XLimit/2, 0);
                                oNewPos = oProcessor3D.convertAndTurnPoint(oCPosLabelX*this.chartObj.calcProp.pxToMM, dPosY, dZPositionCatAxis);
                                oLabel.setPosition2(oNewPos.x/this.chartObj.calcProp.pxToMM + oLabel.localTransformText.tx - oCPosLabelX, oLabel.localTransformText.ty - dPosY2 + oNewPos.y/this.chartObj.calcProp.pxToMM );
                                var fBottomContent = oLabel.y + oLabel.tx.rich.content.GetSummaryHeight();
                                if(fBottomContent > fBottomLabels){
                                    fBottomLabels = fBottomContent;
                                }

                            }
                        }
                    }
                    else
                    {
                        if(oAxisLabels.align)
                        {
                            var stake_offset = AscFormat.isRealNumber(oCatAx.lblOffset) ? oCatAx.lblOffset/100 : 1;
                            var labels_offset = oCatAx.labels.aLabels[0].tx.rich.content.Content[0].CompiledPr.Pr.TextPr.FontSize*(25.4/72)*stake_offset;
                            for(i = 0; i < oAxisLabels.aLabels.length; ++i)
                            {
                                if(oAxisLabels.aLabels[i])
                                {
                                    oLabel = oAxisLabels.aLabels[i];
                                    var wh = {w: oLabel.widthForTransform, h: oLabel.tx.rich.content.GetSummaryHeight()}, w2, h2, x1, y0, xc, yc;
                                    w2 = wh.w*Math.cos(Math.PI/4) + wh.h*Math.sin(Math.PI/4);
                                    h2 = wh.w*Math.sin(Math.PI/4) + wh.h*Math.cos(Math.PI/4);
                                    x1 = oCatAx.xPoints[i].pos + wh.h*Math.sin(Math.PI/4);
                                    y0 = oAxisLabels.y + labels_offset;
                                    var x1t, y0t;
                                    var oRes = oProcessor3D.convertAndTurnPoint(x1*this.chartObj.calcProp.pxToMM, y0*this.chartObj.calcProp.pxToMM, dZPositionCatAxis);
                                    x1t = oRes.x/this.chartObj.calcProp.pxToMM;
                                    y0t = oRes.y/this.chartObj.calcProp.pxToMM;
                                    xc = x1t - w2/2;
                                    yc = y0t + h2/2;
                                    var local_text_transform = oLabel.localTransformText;
                                    local_text_transform.Reset();
                                    global_MatrixTransformer.TranslateAppend(local_text_transform, -wh.w/2, -wh.h/2);
                                    global_MatrixTransformer.RotateRadAppend(local_text_transform, Math.PI/4);
                                    global_MatrixTransformer.TranslateAppend(local_text_transform, xc, yc);

                                    var fBottomContent = y0t + h2;
                                    if(fBottomContent > fBottomLabels){
                                        fBottomLabels = fBottomContent;
                                    }
                                }
                            }
                        }
                        else
                        {
                            var stake_offset = AscFormat.isRealNumber(oCatAx.lblOffset) ? oCatAx.lblOffset/100 : 1;
                            var labels_offset = oCatAx.labels.aLabels[0].tx.rich.content.Content[0].CompiledPr.Pr.TextPr.FontSize*(25.4/72)*stake_offset;
                            for(i = 0; i < oAxisLabels.aLabels.length; ++i)
                            {
                                if(oAxisLabels.aLabels[i])
                                {
                                    oLabel = oAxisLabels.aLabels[i];
                                    var wh = {w: oLabel.widthForTransform, h: oLabel.tx.rich.content.GetSummaryHeight()}, w2, h2, x1, y0, xc, yc;
                                    w2 = wh.w*Math.cos(Math.PI/4) + wh.h*Math.sin(Math.PI/4);
                                    h2 = wh.w*Math.sin(Math.PI/4) + wh.h*Math.cos(Math.PI/4);
                                    x1 = oCatAx.xPoints[i].pos - wh.h*Math.sin(Math.PI/4);
                                    y0 =  oAxisLabels.y +  oAxisLabels.extY - labels_offset;
                                    var x1t, y0t;
                                    var oRes = oProcessor3D.convertAndTurnPoint(x1*this.chartObj.calcProp.pxToMM, y0*this.chartObj.calcProp.pxToMM, dZPositionCatAxis);
                                    x1t = oRes.x/this.chartObj.calcProp.pxToMM;
                                    y0t = oRes.y/this.chartObj.calcProp.pxToMM;
                                    xc = x1t + w2/2;
                                    yc = y0t - h2/2;
                                    local_text_transform = oLabel.localTransformText;
                                    local_text_transform.Reset();
                                    global_MatrixTransformer.TranslateAppend(local_text_transform, -wh.w/2, -wh.h/2);
                                    global_MatrixTransformer.RotateRadAppend(local_text_transform, Math.PI/4);//TODO
                                    global_MatrixTransformer.TranslateAppend(local_text_transform, xc, yc);
                                }
                            }
                        }
                    }

                    oNewPos = oProcessor3D.convertAndTurnPoint(oAxisLabels.x*this.chartObj.calcProp.pxToMM, oAxisLabels.y*this.chartObj.calcProp.pxToMM, dZPositionCatAxis);
                    aXPoints.push(oNewPos.x/this.chartObj.calcProp.pxToMM);
                    aYPoints.push(oNewPos.y/this.chartObj.calcProp.pxToMM);
                    oNewPos = oProcessor3D.convertAndTurnPoint((oAxisLabels.x + oAxisLabels.extX)*this.chartObj.calcProp.pxToMM, oAxisLabels.y*this.chartObj.calcProp.pxToMM, dZPositionCatAxis);
                    aXPoints.push(oNewPos.x/this.chartObj.calcProp.pxToMM);
                    aYPoints.push(oNewPos.y/this.chartObj.calcProp.pxToMM);
                    oNewPos = oProcessor3D.convertAndTurnPoint((oAxisLabels.x + oAxisLabels.extX)*this.chartObj.calcProp.pxToMM, (oAxisLabels.y + oAxisLabels.extY)*this.chartObj.calcProp.pxToMM, dZPositionCatAxis);
                    aXPoints.push(oNewPos.x/this.chartObj.calcProp.pxToMM);
                    aYPoints.push(oNewPos.y/this.chartObj.calcProp.pxToMM);
                    oNewPos = oProcessor3D.convertAndTurnPoint((oAxisLabels.x)*this.chartObj.calcProp.pxToMM, (oAxisLabels.y + oAxisLabels.extY)*this.chartObj.calcProp.pxToMM, dZPositionCatAxis);
                    aXPoints.push(oNewPos.x/this.chartObj.calcProp.pxToMM);
                    aYPoints.push(oNewPos.y/this.chartObj.calcProp.pxToMM);
                    oAxisLabels.x = Math.min.apply(Math, aXPoints);
                    oAxisLabels.y = Math.min.apply(Math, aYPoints);
                    oAxisLabels.extX = Math.max.apply(Math, aXPoints) - oAxisLabels.x;
                    oAxisLabels.extY = Math.max(Math.max.apply(Math, aYPoints), fBottomLabels) - oAxisLabels.y;
                }
                oAxisLabels = oValAx.labels;
                if(oAxisLabels)
                {
                    var dZPositionCatAxis = oProcessor3D.calculateZPositionValAxis();

                    var dPosX, dPosX2;
                    if(!oAxisLabels.align)
                    {
                        dPosX2 = oAxisLabels.x;
                        dPosX =  oAxisLabels.x*this.chartObj.calcProp.pxToMM;
                    }
                    else
                    {
                        dPosX2 = oAxisLabels.x + oAxisLabels.extX;
                        dPosX = (oAxisLabels.x + oAxisLabels.extX)*this.chartObj.calcProp.pxToMM;
                    }
                    aXPoints.length = 0;
                    aYPoints.length = 0;
                    for(i = 0; i < oAxisLabels.aLabels.length; ++i)
                    {
                        oLabel = oAxisLabels.aLabels[i];
                        if(oLabel)
                        {
                            oNewPos =  oProcessor3D.convertAndTurnPoint(dPosX, oLabel.localTransformText.ty*this.chartObj.calcProp.pxToMM, dZPositionCatAxis);
                            oLabel.setPosition2(oLabel.localTransformText.tx - dPosX2 + oNewPos.x/this.chartObj.calcProp.pxToMM, oNewPos.y/this.chartObj.calcProp.pxToMM);
                            aXPoints.push(oLabel.x);
                            aYPoints.push(oLabel.y);
                            aXPoints.push(oLabel.x + oLabel.txBody.content.XLimit);
                            aYPoints.push(oLabel.y + oLabel.txBody.content.GetSummaryHeight());
                        }
                    }
                    if(aXPoints.length > 0 && aYPoints.length > 0)
                    {
                        oAxisLabels.x = Math.min.apply(Math, aXPoints);
                        oAxisLabels.y = Math.min.apply(Math, aYPoints);
                        oAxisLabels.extX = Math.max.apply(Math, aXPoints) - oAxisLabels.x;
                        oAxisLabels.extY = Math.max.apply(Math, aYPoints) - oAxisLabels.y;
                    }
                }
            }
            else if(((oCatAx.axPos === AscFormat.AX_POS_L || oCatAx.axPos === AscFormat.AX_POS_R) && oCatAx.yPoints) &&
                ((oValAx.axPos === AscFormat.AX_POS_T || oValAx.axPos === AscFormat.AX_POS_B) && oValAx.xPoints))
            {
                oAxisLabels = oValAx.labels;

                if(oAxisLabels)
                {
                    var dZPositionValAxis = oProcessor3D.calculateZPositionValAxis();
                    var dPosY, dPosY2
                    if(oAxisLabels.align)
                    {
                        dPosY = oAxisLabels.y*this.chartObj.calcProp.pxToMM;
                        dPosY2 = oAxisLabels.y;
                    }
                    else
                    {
                        dPosY = (oAxisLabels.y + oAxisLabels.extY)*this.chartObj.calcProp.pxToMM;
                        dPosY2 = oAxisLabels.y + oAxisLabels.extY;
                    }

                    for(i = 0; i < oAxisLabels.aLabels.length; ++i)
                    {
                        oLabel = oAxisLabels.aLabels[i];
                        if(oLabel)
                        {

                            var oCPosLabelX = oLabel.localTransformText.TransformPointX(oLabel.txBody.content.XLimit/2, 0);
                            var oCPosLabelY = oLabel.localTransformText.TransformPointY(oLabel.txBody.content.XLimit/2, 0);
                            oNewPos = oProcessor3D.convertAndTurnPoint(oCPosLabelX*this.chartObj.calcProp.pxToMM, dPosY, dZPositionValAxis);

                            oLabel.setPosition2(oNewPos.x/this.chartObj.calcProp.pxToMM + oLabel.localTransformText.tx - oCPosLabelX, oLabel.localTransformText.ty - dPosY2 + oNewPos.y/this.chartObj.calcProp.pxToMM );


                            //oNewPos = oProcessor3D.convertAndTurnPoint(oLabel.localTransformText.tx*this.chartObj.calcProp.pxToMM, oLabel.localTransformText.ty*this.chartObj.calcProp.pxToMM, dZPositionValAxis);;
                           //oLabel.setPosition2(oNewPos.x/this.chartObj.calcProp.pxToMM, oNewPos.y/this.chartObj.calcProp.pxToMM);
                        }
                    }
                    oNewPos = oProcessor3D.convertAndTurnPoint(oAxisLabels.x*this.chartObj.calcProp.pxToMM, oAxisLabels.y*this.chartObj.calcProp.pxToMM, dZPositionValAxis);
                    aXPoints.push(oNewPos.x/this.chartObj.calcProp.pxToMM);
                    aYPoints.push(oNewPos.y/this.chartObj.calcProp.pxToMM);
                    oNewPos = oProcessor3D.convertAndTurnPoint((oAxisLabels.x + oAxisLabels.extX)*this.chartObj.calcProp.pxToMM, oAxisLabels.y*this.chartObj.calcProp.pxToMM, dZPositionValAxis);
                    aXPoints.push(oNewPos.x/this.chartObj.calcProp.pxToMM);
                    aYPoints.push(oNewPos.y/this.chartObj.calcProp.pxToMM);
                    oNewPos = oProcessor3D.convertAndTurnPoint((oAxisLabels.x + oAxisLabels.extX)*this.chartObj.calcProp.pxToMM, (oAxisLabels.y + oAxisLabels.extY)*this.chartObj.calcProp.pxToMM, dZPositionValAxis);
                    aXPoints.push(oNewPos.x/this.chartObj.calcProp.pxToMM);
                    aYPoints.push(oNewPos.y/this.chartObj.calcProp.pxToMM);
                    oNewPos = oProcessor3D.convertAndTurnPoint((oAxisLabels.x)*this.chartObj.calcProp.pxToMM, (oAxisLabels.y + oAxisLabels.extY)*this.chartObj.calcProp.pxToMM, dZPositionValAxis);
                    aXPoints.push(oNewPos.x/this.chartObj.calcProp.pxToMM);
                    aYPoints.push(oNewPos.y/this.chartObj.calcProp.pxToMM);
                    oAxisLabels.x = Math.min.apply(Math, aXPoints);
                    oAxisLabels.y = Math.min.apply(Math, aYPoints);
                    oAxisLabels.extX = Math.max.apply(Math, aXPoints) - oAxisLabels.x;
                    oAxisLabels.extY = Math.max.apply(Math, aYPoints) - oAxisLabels.y;
                }


                oAxisLabels = oCatAx.labels;

                aXPoints.length = 0;
                aYPoints.length = 0;
                if(oAxisLabels)
                {
                    var dZPositionCatAxis = oProcessor3D.calculateZPositionCatAxis();
                    var dPosX, dPosX2;
                    if(oAxisLabels.align)
                    {
                        dPosX2 = oAxisLabels.x;
                        dPosX =  oAxisLabels.x*this.chartObj.calcProp.pxToMM;
                    }
                    else
                    {
                        dPosX2 = oAxisLabels.x + oAxisLabels.extX;
                        dPosX = (oAxisLabels.x + oAxisLabels.extX)*this.chartObj.calcProp.pxToMM;
                    }

                    for(i = 0; i < oAxisLabels.aLabels.length; ++i)
                    {
                        oLabel = oAxisLabels.aLabels[i];

                        if(oLabel)
                        {
                            oNewPos =  oProcessor3D.convertAndTurnPoint(dPosX, oLabel.localTransformText.ty*this.chartObj.calcProp.pxToMM, dZPositionCatAxis);
                            oLabel.setPosition2(oLabel.localTransformText.tx - dPosX2 + oNewPos.x/this.chartObj.calcProp.pxToMM, oNewPos.y/this.chartObj.calcProp.pxToMM);
                            aXPoints.push(oLabel.x);
                            aYPoints.push(oLabel.y);
                            aXPoints.push(oLabel.x + oLabel.txBody.content.XLimit);
                            aYPoints.push(oLabel.y + oLabel.txBody.content.GetSummaryHeight());
                        }
                    }
                    if(aXPoints.length > 0 && aYPoints.length > 0)
                    {
                        oAxisLabels.x = Math.min.apply(Math, aXPoints);
                        oAxisLabels.y = Math.min.apply(Math, aYPoints);
                        oAxisLabels.extX = Math.max.apply(Math, aXPoints) - oAxisLabels.x;
                        oAxisLabels.extY = Math.max.apply(Math, aYPoints) - oAxisLabels.y;
                    }
                }
            }
        }
    }
};


CChartSpace.prototype.layoutLegendEntry = function(oEntry, fX, fY, fDistance){
    oEntry.localY = fY;
    var oFirstLine = oEntry.txBody.content.Content[0].Lines[0];
    var fYFirstLineMiddle = oEntry.localY + oFirstLine.Top + oFirstLine.Metrics.Descent/2.0 + oFirstLine.Metrics.TextAscent - oFirstLine.Metrics.TextAscent2/2.0;// (oFirstLine.Bottom - oFirstLine.Top - oFirstLine.Metrics.Descent - oFirstLine.Metrics.Ascent)/2.0;
    var fPenWidth;
    var oUnionMarker = oEntry.calcMarkerUnion;
    var oLineMarker = oUnionMarker.lineMarker;
    var oMarker = oUnionMarker.marker;
    if(oLineMarker){
        oLineMarker.localX = fX;
        if(oLineMarker.pen){
            if(AscFormat.isRealNumber(oLineMarker.pen.w)){
                fPenWidth = oLineMarker.pen.w/36000.0;
            }
            else{
                fPenWidth = 12700.0/36000.0;
            }
        }
        else{
            fPenWidth = 0.0;
        }
        oLineMarker.localY = fYFirstLineMiddle - fPenWidth / 2.0;
        if(oMarker){
            oMarker.localX = oLineMarker.localX + oLineMarker.spPr.geometry.gdLst['w']/2.0 - oMarker.spPr.geometry.gdLst['w']/2.0;
            oMarker.localY = fYFirstLineMiddle - oMarker.spPr.geometry.gdLst['h']/2.0;
        }
        oEntry.localX = oLineMarker.localX + oLineMarker.spPr.geometry.gdLst['w'] + fDistance;
    }
    else{
        if(oMarker){
            oMarker.localX = fX;
            oMarker.localY = fYFirstLineMiddle - oMarker.spPr.geometry.gdLst['h']/2.0;
            oEntry.localX = oMarker.localX + oMarker.spPr.geometry.gdLst['w'] + fDistance;
        }
        else{
            oEntry.localX = fX + fDistance;
        }
    }
};

CChartSpace.prototype.hitInTextRect = function()
{
    return false;
};

    CChartSpace.prototype.recalculateLegend = function()
    {
        if(this.chart && this.chart.legend)
        {
            var aSeries = this.getAllSeries();
            var oParents = this.getParentObjects();
            var oLegend = this.chart.legend;

            var parents = this.getParentObjects();
            var RGBA = {R:0, G:0, B: 0, A:255};
            var legend = this.chart.legend;
            var arr_str_labels = [], i, j;
            var calc_entryes = legend.calcEntryes;
            calc_entryes.length = 0;
            var series = this.getAllSeries();
            var calc_entry, union_marker, entry;
            var max_width = 0, cur_width, max_font_size = 0, cur_font_size, ser, b_line_series;
            var max_word_width = 0;
            var b_no_line_series = false;
            this.chart.legend.chart = this;
            var b_scatter_no_line = false;/*(this.chart.plotArea.charts[0].getObjectType() === AscDFH.historyitem_type_ScatterChart &&
         (this.chart.plotArea.charts[0].scatterStyle === AscFormat.SCATTER_STYLE_MARKER || this.chart.plotArea.charts[0].scatterStyle === AscFormat.SCATTER_STYLE_NONE));  */
            this.legendLength = null;

            if( !(this.chart.plotArea.charts.length === 1 && this.chart.plotArea.charts[0].varyColors)
                || (this.chart.plotArea.charts[0].getObjectType() !== AscDFH.historyitem_type_PieChart && this.chart.plotArea.charts[0].getObjectType() !== AscDFH.historyitem_type_DoughnutChart) && series.length !== 1
                || this.chart.plotArea.charts[0].getObjectType() === AscDFH.historyitem_type_SurfaceChart)
            {
                var bSurfaceChart = false;
                if(this.chart.plotArea.charts[0].getObjectType() === AscDFH.historyitem_type_SurfaceChart){
                    this.legendLength = this.chart.plotArea.charts[0].compiledBandFormats.length;
                    ser = series[0];
                    bSurfaceChart = true;
                }
                else {
                    this.legendLength = series.length;
                }
                for(i = 0; i < this.legendLength; ++i)
                {
                    if(!bSurfaceChart){
                        ser = series[i];

                        if(ser.isHiddenForLegend)
                            continue;
                        entry = legend.findLegendEntryByIndex(i);
                        if(entry && entry.bDelete)
                            continue;
                        arr_str_labels.push(ser.getSeriesName());
                    }
                    else{
                        entry = legend.findLegendEntryByIndex(i);
                        if(entry && entry.bDelete)
                            continue;
                        var oBandFmt = this.chart.plotArea.charts[0].compiledBandFormats[i];
                        arr_str_labels.push(oBandFmt.startValue + "-" + oBandFmt.endValue);
                    }
                    calc_entry = new AscFormat.CalcLegendEntry(legend, this, i);
                    calc_entry.series = ser;
                    calc_entry.txBody = AscFormat.CreateTextBodyFromString(arr_str_labels[arr_str_labels.length - 1], this.getDrawingDocument(), calc_entry);

                    //if(entry)
                    //    calc_entry.txPr = entry.txPr;

                    /*if(calc_entryes[0])
                     {
                     calc_entry.lastStyleObject = calc_entryes[0].lastStyleObject;
                     }*/
                    calc_entryes.push(calc_entry);
                    cur_width = calc_entry.txBody.getRectWidth(2000);
                    if(cur_width > max_width)
                        max_width = cur_width;

                    cur_font_size = calc_entry.txBody.content.Content[0].CompiledPr.Pr.TextPr.FontSize;
                    if(cur_font_size > max_font_size)
                        max_font_size = cur_font_size;

                    calc_entry.calcMarkerUnion = new AscFormat.CUnionMarker();
                    union_marker = calc_entry.calcMarkerUnion;
                    var pts = AscFormat.getPtsFromSeries(ser);
                    switch(ser.getObjectType())
                    {
                        case AscDFH.historyitem_type_BarSeries:
                        case AscDFH.historyitem_type_BubbleSeries:
                        case AscDFH.historyitem_type_AreaSeries:
                        case AscDFH.historyitem_type_PieSeries:
                        {
                            union_marker.marker = AscFormat.CreateMarkerGeometryByType(AscFormat.SYMBOL_SQUARE, null);
                            union_marker.marker.pen = ser.compiledSeriesPen;
                            union_marker.marker.brush = ser.compiledSeriesBrush;
                            break;
                        }
                        case AscDFH.historyitem_type_SurfaceSeries:{

                            var oBandFmt = this.chart.plotArea.charts[0].compiledBandFormats[i];
                            union_marker.marker = AscFormat.CreateMarkerGeometryByType(AscFormat.SYMBOL_SQUARE, null);
                            union_marker.marker.pen = oBandFmt.spPr.ln;
                            union_marker.marker.brush = oBandFmt.spPr.Fill;
                            break;
                        }
                        case AscDFH.historyitem_type_LineSeries:
                        case AscDFH.historyitem_type_ScatterSer:
                        case AscDFH.historyitem_type_SurfaceSeries:
                        {
                            if(AscFormat.CChartsDrawer.prototype._isSwitchCurrent3DChart(this))
                            {
                                union_marker.marker = AscFormat.CreateMarkerGeometryByType(AscFormat.SYMBOL_SQUARE, null);
                                union_marker.marker.pen = ser.compiledSeriesPen;
                                union_marker.marker.brush = ser.compiledSeriesBrush;
                                break;
                            }
                            if(ser.compiledSeriesMarker)
                            {
                                var pts = AscFormat.getPtsFromSeries(ser);
                                union_marker.marker = AscFormat.CreateMarkerGeometryByType(ser.compiledSeriesMarker.symbol, null);
                                if(pts[0] && pts[0].compiledMarker)
                                {
                                    union_marker.marker.brush = pts[0].compiledMarker.brush;
                                    union_marker.marker.pen = pts[0].compiledMarker.pen;

                                }
                            }

                            if(ser.compiledSeriesPen && !b_scatter_no_line)
                            {
                                union_marker.lineMarker = AscFormat.CreateMarkerGeometryByType(AscFormat.SYMBOL_DASH, null);
                                union_marker.lineMarker.pen = ser.compiledSeriesPen.createDuplicate(); //Копируем, так как потом возможно придется изменять толщину линии;
                            }
                            if(!b_scatter_no_line && !AscFormat.CChartsDrawer.prototype._isSwitchCurrent3DChart(this))
                                b_line_series = true;
                            break;
                        }
                    }
                    if(union_marker.marker)
                    {
                        union_marker.marker.pen && union_marker.marker.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                        union_marker.marker.brush && union_marker.marker.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                    }
                    union_marker.lineMarker && union_marker.lineMarker.pen && union_marker.lineMarker.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                }
            }
            else
            {
                ser = series[0];
                i = 1;
                while(ser && ser.isHiddenForLegend)
                {
                    ser = series[i];
                    ++i;
                }
                var pts = AscFormat.getPtsFromSeries(ser), pt;
                var cat_str_lit = getCatStringPointsFromSeries(ser);
                this.legendLength = pts.length;
                for(i = 0; i < pts.length; ++i)
                {
                    entry = legend.findLegendEntryByIndex(i);
                    if(entry && entry.bDelete)
                        continue;
                    pt = pts[i];
                    var str_pt = cat_str_lit ? cat_str_lit.getPtByIndex(pt.idx) : null;
                    if(str_pt)
                        arr_str_labels.push(str_pt.val);
                    else
                        arr_str_labels.push((pt.idx + 1) + "");

                    calc_entry = new AscFormat.CalcLegendEntry(legend, this, pt.idx);
                    calc_entry.txBody = AscFormat.CreateTextBodyFromString(arr_str_labels[arr_str_labels.length - 1], this.getDrawingDocument(), calc_entry);

                    //if(entry)
                    //    calc_entry.txPr = entry.txPr;
                    //if(calc_entryes[0])
                    //{
                    //    calc_entry.lastStyleObject = calc_entryes[0].lastStyleObject;
                    //}
                    calc_entryes.push(calc_entry);

                    cur_width = calc_entry.txBody.getRectWidth(2000);
                    if(cur_width > max_width)
                        max_width = cur_width;

                    cur_font_size = calc_entry.txBody.content.Content[0].CompiledPr.Pr.TextPr.FontSize;
                    if(cur_font_size > max_font_size)
                        max_font_size = cur_font_size;

                    calc_entry.calcMarkerUnion = new AscFormat.CUnionMarker();
                    union_marker = calc_entry.calcMarkerUnion;
                    if(ser.getObjectType() === AscDFH.historyitem_type_LineSeries && !AscFormat.CChartsDrawer.prototype._isSwitchCurrent3DChart(this) || ser.getObjectType() === AscDFH.historyitem_type_ScatterSer)
                    {
                        if(pt.compiledMarker)
                        {
                            union_marker.marker = AscFormat.CreateMarkerGeometryByType(pt.compiledMarker.symbol, null);
                            union_marker.marker.brush = pt.compiledMarker.pen.Fill;
                            union_marker.marker.pen = pt.compiledMarker.pen;
                        }
                        if(pt.pen)
                        {
                            union_marker.lineMarker = AscFormat.CreateMarkerGeometryByType(AscFormat.SYMBOL_DASH, null);
                            union_marker.lineMarker.pen = pt.pen;
                        }
                        if(!b_scatter_no_line && !AscFormat.CChartsDrawer.prototype._isSwitchCurrent3DChart(this))
                            b_line_series = true;
                    }
                    else
                    {
                        b_no_line_series = false;
                        union_marker.marker = AscFormat.CreateMarkerGeometryByType(AscFormat.SYMBOL_SQUARE, null);
                        union_marker.marker.pen = pt.pen;
                        union_marker.marker.brush = pt.brush;
                    }
                    if(union_marker.marker)
                    {
                        union_marker.marker.pen && union_marker.marker.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                        union_marker.marker.brush && union_marker.marker.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                    }
                    union_marker.lineMarker && union_marker.lineMarker.pen && union_marker.lineMarker.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                }
            }
            var marker_size;
            var distance_to_text;
            var line_marker_width;
            if(b_line_series)
            {
                marker_size = 2.5;
                line_marker_width = 7.7;//Пока так
                for(i = 0; i < calc_entryes.length; ++i)
                {
                    calc_entry = calc_entryes[i];
                    if(calc_entry.calcMarkerUnion.lineMarker)
                    {
                        calc_entry.calcMarkerUnion.lineMarker.spPr.geometry.Recalculate(line_marker_width, 1);
                        /*Excel не дает сделать толщину линии для маркера легенды больше определенной. Считаем, что это толщина равна 133000emu*/
                        if(calc_entry.calcMarkerUnion.lineMarker.pen
                            && AscFormat.isRealNumber(calc_entry.calcMarkerUnion.lineMarker.pen.w) && calc_entry.calcMarkerUnion.lineMarker.pen.w > 133000)
                        {
                            calc_entry.calcMarkerUnion.lineMarker.pen.w = 133000;
                        }
                        calc_entry.calcMarkerUnion.lineMarker.penWidth = calc_entry.calcMarkerUnion.lineMarker.pen && AscFormat.isRealNumber(calc_entry.calcMarkerUnion.lineMarker.pen.w) ? calc_entry.calcMarkerUnion.lineMarker.pen.w/36000 : 0;
                    }
                    if(calc_entryes[i].calcMarkerUnion.marker)
                    {
                        var marker_width = marker_size;
                        if(calc_entryes[i].series){
                            if(calc_entryes[i].series.getObjectType() !== AscDFH.historyitem_type_LineSeries && calc_entryes[i].series.getObjectType() !== AscDFH.historyitem_type_ScatterSer){
                                marker_width = line_marker_width;
                            }
                        }
                        calc_entryes[i].calcMarkerUnion.marker.spPr.geometry.Recalculate(marker_width, marker_size);
                        calc_entryes[i].calcMarkerUnion.marker.extX = marker_width;
                        calc_entryes[i].calcMarkerUnion.marker.extY = marker_size;
                    }
                }
                distance_to_text = 0.5;
            }
            else
            {
                marker_size = 0.2*max_font_size;
                for(i = 0; i < calc_entryes.length; ++i)
                {
                    calc_entryes[i].calcMarkerUnion.marker.spPr.geometry.Recalculate(marker_size, marker_size);
                }
                distance_to_text = marker_size*0.7;
            }
            var left_inset = marker_size + 3*distance_to_text;
            var legend_pos = c_oAscChartLegendShowSettings.right;
            if(AscFormat.isRealNumber(legend.legendPos))
            {
                legend_pos = legend.legendPos;
            }
            var legend_width, legend_height;
            var fFixedWidth = null, fFixedHeight = null;
            var bFixedSize = false;
            if(legend.layout){
                fFixedWidth = this.calculateSizeByLayout(0, this.extX, legend.layout.w, legend.layout.wMode);
                fFixedHeight = this.calculateSizeByLayout(0, this.extY, legend.layout.h, legend.layout.hMode);
                bFixedSize = AscFormat.isRealNumber(fFixedWidth) && fFixedWidth > 0 && AscFormat.isRealNumber(fFixedHeight) && fFixedHeight > 0;
                if(bFixedSize){
                    var oOldLayout = legend.layout;
                    legend.layout = null;
                    this.recalculateLegend();

                    legend.naturalWidth = legend.extX;
                    legend.naturalHeight = legend.extY;
                    legend.layout = oOldLayout;
                    var bResetLegendPos = false;
                    if(!AscFormat.isRealNumber(this.chart.legend.legendPos))
                    {
                        bResetLegendPos = true;
                        this.chart.legend.legendPos = Asc.c_oAscChartLegendShowSettings.bottom;
                    }
                    if(!this.chartObj)
                    {
                        this.chartObj = new AscFormat.CChartsDrawer();
                    }
                    this.chartObj.preCalculateData(this);
                    var pos = this.chartObj.recalculatePositionText(this.chart.legend);
                    if(this.chart.legend.layout){
                        if(AscFormat.isRealNumber(legend.layout.x)){
                            pos.x = this.calculatePosByLayout(pos.x, legend.layout.xMode, legend.layout.x, this.chart.legend.extX, this.extX);
                        }if(AscFormat.isRealNumber(legend.layout.y)){
                            pos.y = this.calculatePosByLayout(pos.y, legend.layout.yMode, legend.layout.y, this.chart.legend.extY, this.extY);
                        }
                    }
                    if(bResetLegendPos){
                        this.chart.legend.legendPos = null;
                    }

                    fFixedWidth = this.calculateSizeByLayout(pos.x, this.extX, legend.layout.w, legend.layout.wMode);
                    fFixedHeight = this.calculateSizeByLayout(pos.y, this.extY, legend.layout.h, legend.layout.hMode);

                }
            }
            if(AscFormat.isRealNumber(legend_pos))
            {
                var max_legend_width, max_legend_height;
                var cut_index;
                if ((legend_pos === c_oAscChartLegendShowSettings.left ||
                    legend_pos === c_oAscChartLegendShowSettings.leftOverlay ||
                    legend_pos === c_oAscChartLegendShowSettings.right ||
                    legend_pos === c_oAscChartLegendShowSettings.rightOverlay || legend_pos === c_oAscChartLegendShowSettings.topRight) && !bFixedSize)
                {
                    max_legend_width = this.extX/3;//Считаем, что ширина легенды не больше трети ширины всей диаграммы;
                    var sizes = this.getChartSizes();
                    max_legend_height = sizes.h;
                    if(b_line_series)
                    {
                        left_inset = line_marker_width + 3*distance_to_text;
                        var content_width = max_legend_width - left_inset;
                        if(content_width <= 0)
                            content_width = 0.01;
                        var cur_content_width, max_content_width = 0;
                        var arr_heights = [];
                        var arr_heights2 = [];
                        for(i = 0; i < calc_entryes.length; ++i)
                        {
                            calc_entry = calc_entryes[i];
                            cur_content_width = calc_entry.txBody.getMaxContentWidth(content_width, true);
                            if(cur_content_width > max_content_width)
                                max_content_width = cur_content_width;
                            arr_heights.push(calc_entry.txBody.getSummaryHeight());
                            arr_heights2.push(calc_entry.txBody.getSummaryHeight3());
                        }
                        if(max_content_width < max_legend_width - left_inset)
                        {
                            legend_width = max_content_width + left_inset;
                        }
                        else
                        {
                            legend_width = max_legend_width;
                        }

                        var max_entry_height2 = Math.max(0, Math.max.apply(Math, arr_heights));
                        for(i = 0; i < arr_heights.length; ++i)
                            arr_heights[i] = max_entry_height2;
                        var max_entry_height2 = Math.max(0, Math.max.apply(Math, arr_heights2));
                        for(i = 0; i < arr_heights2.length; ++i)
                            arr_heights2[i] = max_entry_height2;

                        var height_summ = 0;
                        var height_summ2 = 0;
                        for(i = 0;  i < arr_heights2.length; ++i)
                        {
                            height_summ+=arr_heights2[i];
                            height_summ2+=arr_heights[i];
                            if(height_summ > max_legend_height)
                            {
                                cut_index = i;
                                break;
                            }
                        }
                        if(AscFormat.isRealNumber(cut_index))
                        {
                            if(cut_index > 0)
                            {
                                legend_height = height_summ2 - arr_heights[cut_index];
                            }
                            else
                            {
                                legend_height = max_legend_height;
                            }
                        }
                        else
                        {
                            cut_index = arr_heights.length;
                            legend_height = height_summ2;
                        }
                        legend.x = 0;
                        legend.y = 0;
                        legend.extX = legend_width;
                        legend.extY = legend_height;
                        var summ_h = 0;
                        calc_entryes.splice(cut_index, calc_entryes.length - cut_index);
                        for(i = 0; i <  cut_index && i < calc_entryes.length; ++i)
                        {
                            calc_entry = calc_entryes[i];
                            this.layoutLegendEntry(calc_entry, distance_to_text, summ_h, distance_to_text);
                            // if(calc_entry.calcMarkerUnion.marker)
                            // {
                            //     calc_entry.calcMarkerUnion.marker.localX = distance_to_text + line_marker_width/2 - calc_entry.calcMarkerUnion.marker.extX/2;
                            //     calc_entry.calcMarkerUnion.marker.localY = summ_h + (calc_entry.txBody.content.Content[0].Lines[0].Bottom - calc_entry.txBody.content.Content[0].Lines[0].Top)/2 - marker_size/2;
                            //     calc_entry.localX = calc_entry.calcMarkerUnion.marker.localX + line_marker_width + distance_to_text;
                            // }
                            //
                            // if(calc_entry.calcMarkerUnion.lineMarker)
                            // {
                            //     calc_entry.calcMarkerUnion.lineMarker.localX = distance_to_text;
                            //     calc_entry.calcMarkerUnion.lineMarker.localY = summ_h + (calc_entry.txBody.content.Content[0].Lines[0].Bottom - calc_entry.txBody.content.Content[0].Lines[0].Top)/2;// - calc_entry.calcMarkerUnion.lineMarker.penWidth/2;
                            //     calc_entry.localX = calc_entry.calcMarkerUnion.lineMarker.localX + line_marker_width + distance_to_text;
                            // }
                            // calc_entry.localY = summ_h;



                            summ_h+=arr_heights[i];
                        }
                        legend.setPosition(0, 0);
                    }
                    else
                    {
                        var content_width = max_legend_width - left_inset;
                        if(content_width <= 0)
                            content_width = 0.01;
                        var cur_content_width, max_content_width = 0;
                        var arr_heights = [];
                        var arr_heights2 = [];
                        for(i = 0; i < calc_entryes.length; ++i)
                        {
                            calc_entry = calc_entryes[i];
                            cur_content_width = calc_entry.txBody.getMaxContentWidth(content_width, true);
                            if(cur_content_width > max_content_width)
                                max_content_width = cur_content_width;
                            arr_heights.push(calc_entry.txBody.getSummaryHeight());
                            arr_heights2.push(calc_entry.txBody.getSummaryHeight3());
                        }


                        var chart_object;
                        if(this.chart && this.chart.plotArea && this.chart.plotArea.charts[0])
                        {
                            chart_object = this.chart.plotArea.charts[0];
                        }
                        var b_reverse_order = false;
                        if(chart_object && chart_object.getObjectType() === AscDFH.historyitem_type_BarChart && chart_object.barDir === AscFormat.BAR_DIR_BAR &&
                            (cat_ax && cat_ax.scaling && AscFormat.isRealNumber(cat_ax.scaling.orientation) ?  cat_ax.scaling.orientation : AscFormat.ORIENTATION_MIN_MAX) === AscFormat.ORIENTATION_MIN_MAX
                            || chart_object && chart_object.getObjectType() === AscDFH.historyitem_type_SurfaceChart)
                        {
                            b_reverse_order = true;
                        }

                        var max_entry_height2 = Math.max(0, Math.max.apply(Math, arr_heights));
                        for(i = 0; i < arr_heights.length; ++i)
                            arr_heights[i] = max_entry_height2;
                        var max_entry_height2 = Math.max(0, Math.max.apply(Math, arr_heights2));
                        for(i = 0; i < arr_heights2.length; ++i)
                            arr_heights2[i] = max_entry_height2;
                        if(max_content_width < max_legend_width - left_inset)
                        {
                            legend_width = max_content_width + left_inset;
                        }
                        else
                        {
                            legend_width = max_legend_width;
                        }
                        var height_summ = 0;
                        var height_summ2 = 0;
                        for(i = 0;  i < arr_heights.length; ++i)
                        {
                            height_summ+=arr_heights2[i];
                            height_summ2+= arr_heights[i];
                            if(height_summ > max_legend_height)
                            {
                                cut_index = i;
                                break;
                            }
                        }


                        if(AscFormat.isRealNumber(cut_index))
                        {
                            if(cut_index > 0)
                            {
                                legend_height = height_summ2 - arr_heights[cut_index];
                            }
                            else
                            {
                                legend_height = max_legend_height;
                            }
                        }
                        else
                        {
                            cut_index = arr_heights.length;
                            legend_height = height_summ2;
                        }
                        legend.x = 0;
                        legend.y = 0;
                        legend.extX = legend_width;
                        legend.extY = legend_height;
                        var summ_h = 0;


                        var b_reverse_order = false;
                        var chart_object, cat_ax, start_index, end_index;
                        if(this.chart && this.chart.plotArea && this.chart.plotArea.charts[0])
                        {
                            chart_object = this.chart.plotArea.charts[0];
                            if(chart_object && chart_object.getAxisByTypes)
                            {
                                var axis_by_types = chart_object.getAxisByTypes();
                                cat_ax = axis_by_types.catAx[0];
                            }
                        }
                        if(chart_object && chart_object.getObjectType() === AscDFH.historyitem_type_BarChart && chart_object.barDir === AscFormat.BAR_DIR_BAR &&
                            (cat_ax && cat_ax.scaling && AscFormat.isRealNumber(cat_ax.scaling.orientation) ?  cat_ax.scaling.orientation : AscFormat.ORIENTATION_MIN_MAX) === AscFormat.ORIENTATION_MIN_MAX)
                        {
                            b_reverse_order = true;
                        }


                        if(!b_reverse_order)
                        {
                            calc_entryes.splice(cut_index, calc_entryes.length - cut_index);
                            for(i = 0; i <  cut_index && i < calc_entryes.length; ++i)
                            {
                                calc_entry = calc_entryes[i];
                                this.layoutLegendEntry(calc_entry, distance_to_text, summ_h, distance_to_text);
                                // if(calc_entry.calcMarkerUnion.marker)
                                // {
                                //     calc_entry.calcMarkerUnion.marker.localX = distance_to_text;
                                //     calc_entry.calcMarkerUnion.marker.localY = summ_h + (calc_entry.txBody.content.Content[0].Lines[0].Bottom - calc_entry.txBody.content.Content[0].Lines[0].Top)/2 - marker_size/2;
                                // }
                                // calc_entry.localX = 2*distance_to_text + marker_size;
                                // calc_entry.localY = summ_h;
                                summ_h+=arr_heights[i];
                            }
                        }
                        else
                        {
                            calc_entryes.splice(0, calc_entryes.length - cut_index);
                            for(i = calc_entryes.length-1; i > -1; --i)
                            {
                                calc_entry = calc_entryes[i];
                                this.layoutLegendEntry(calc_entry, distance_to_text, summ_h, distance_to_text);
                                // if(calc_entry.calcMarkerUnion.marker)
                                // {
                                //     calc_entry.calcMarkerUnion.marker.localX = distance_to_text;
                                //     calc_entry.calcMarkerUnion.marker.localY = summ_h + (calc_entry.txBody.content.Content[0].Lines[0].Bottom - calc_entry.txBody.content.Content[0].Lines[0].Top)/2 - marker_size/2;
                                // }
                                // calc_entry.localX = 2*distance_to_text + marker_size;
                                // calc_entry.localY = summ_h;
                                summ_h+=arr_heights[i];
                            }
                        }

                        legend.setPosition(0, 0);
                    }
                }
                else
                {
                    /*пока сделаем так: максимальная ширимна 0.9 от ширины дмаграммы
                     без заголовка  максимальная высота легенды 0.6 от высоты диаграммы,
                     с заголовком 0.6 от высоты за вычетом высоты заголовка*/
                    var fMaxLegendHeight, fMaxLegendWidth;
                    if(bFixedSize){
                        fMaxLegendWidth = fFixedWidth;
                        fMaxLegendHeight = fFixedHeight;
                    }
                    else{
                        fMaxLegendWidth = 0.9*this.extX;
                        fMaxLegendHeight = (this.extY - (this.chart.title ? this.chart.title.extY : 0))*0.6;
                    }
                    var fMarkerWidth;
                    if(b_line_series){
                        fMarkerWidth = line_marker_width
                    }
                    else{
                        fMarkerWidth = marker_size;
                    }
                    var oUnionMarker;
                    var fMaxEntryWidth = 0.0;
                    var fSummWidth = 0.0;
                    var fCurEntryWidth, oCurEntry;
                    var fLegendWidth, fLegendHeight;
                    var aHeights = [];
                    var aHeights2 = [];
                    var fMaxEntryHeight = 0.0;
                    var fCurEntryHeight = 0.0;
                    var fCurEntryHeight2 = 0.0;
                    var aWidths = [];
                    var fCurPosX;
                    var fCurPosY;
                    var fDistanceBetweenLabels;
                    var fVertDistanceBetweenLabels;
                    var oLineMarker, fPenWidth, oMarker;
                    for(i = 0; i < calc_entryes.length; ++i){
                        oCurEntry = calc_entryes[i];
                        var fWidth = oCurEntry.txBody.getMaxContentWidth(20000, true);
                        aWidths.push(fWidth);
                        fCurEntryWidth = distance_to_text + fMarkerWidth + distance_to_text + fWidth;
                        if(fMaxEntryWidth < fCurEntryWidth){
                            fMaxEntryWidth = fCurEntryWidth;
                        }
                        fCurEntryHeight = oCurEntry.txBody.getSummaryHeight();
                        fCurEntryHeight2 = oCurEntry.txBody.getSummaryHeight3();
                        aHeights.push(fCurEntryHeight);
                        aHeights2.push(fCurEntryHeight2);
                        if(fMaxEntryHeight < fCurEntryHeight2){
                            fMaxEntryHeight = fCurEntryHeight2;
                        }
                        fSummWidth += fCurEntryWidth;
                    }
                    if(fSummWidth <= fMaxLegendWidth){
                        if(bFixedSize){
                            fLegendWidth = fFixedWidth;
                            fLegendHeight = fFixedHeight;
                        }
                        else{
                            fLegendWidth = fSummWidth;
                            fLegendHeight = Math.max.apply(Math, aHeights);
                        }
                        fDistanceBetweenLabels = (fLegendWidth - fSummWidth)/(calc_entryes.length + 1);
                        fCurPosX = 0.0;
                        legend.extX = fLegendWidth;
                        legend.extY = fLegendHeight;
                        for(i = 0; i < calc_entryes.length; ++i){
                            fCurPosX += fDistanceBetweenLabels;
                            oCurEntry = calc_entryes[i];
                            this.layoutLegendEntry(oCurEntry, fCurPosX + distance_to_text, Math.max(0, fLegendHeight/2.0 - aHeights[i]/2.0), distance_to_text);
                            // oUnionMarker = oCurEntry.calcMarkerUnion;
                            // oLineMarker = oUnionMarker.lineMarker;
                            // oMarker = oUnionMarker.marker;
                            //
                            // if(oLineMarker){
                            //     oLineMarker.localX = fCurPosX + distance_to_text;
                            //     if(oLineMarker.pen){
                            //         if(AscFormat.isRealNumber(oLineMarker.pen.w)){
                            //             fPenWidth = oLineMarker.pen.w/36000.0;
                            //         }
                            //         else{
                            //             fPenWidth = 12700.0/36000.0;
                            //         }
                            //     }
                            //     else{
                            //         fPenWidth = 0.0;
                            //     }
                            //     oLineMarker.localY = Math.max(0.0, fLegendHeight/2.0 - fPenWidth/2.0);
                            //     if(oMarker){
                            //         oMarker.localX = oLineMarker.localX + line_marker_width/2.0 - marker_size/2.0;
                            //         oMarker.localY = Math.max(0.0, fLegendHeight/2.0 - marker_size/2.0);
                            //     }
                            // }
                            // else{
                            //     if(oMarker){
                            //         oMarker.localX = fCurPosX + distance_to_text;
                            //         oMarker.localY = Math.max(0.0, fLegendHeight/2.0 - marker_size/2.0);
                            //     }
                            // }
                            // oCurEntry.localX = fCurPosX + distance_to_text + fMarkerWidth + distance_to_text;
                            // oCurEntry.localY = Math.max(0, fLegendHeight/2.0 - aHeights[i]/2.0);
                            fCurPosX += distance_to_text + fMarkerWidth + distance_to_text + aWidths[i];
                        }

                        legend.setPosition(0, 0);
                    }
                    else {
                        if(fMaxLegendWidth < fMaxEntryWidth){
                            var fTextWidth = Math.max(1.0, fMaxLegendWidth - distance_to_text - fMarkerWidth - distance_to_text);
                            fMaxEntryWidth = 0.0;
                            fMaxEntryHeight = 0.0;
                            aWidths.length = 0;
                            aHeights.length = 0;
                            for(i = 0; i < calc_entryes.length; ++i){
                                oCurEntry = calc_entryes[i];
                                var fWidth = oCurEntry.txBody.getMaxContentWidth(fTextWidth, true);
                                aWidths.push(fWidth);
                                fCurEntryWidth = distance_to_text + fMarkerWidth + distance_to_text + fWidth;
                                if(fMaxEntryWidth < fCurEntryWidth){
                                    fMaxEntryWidth = fCurEntryWidth;
                                }
                                fCurEntryHeight = oCurEntry.txBody.getSummaryHeight();
                                fCurEntryHeight2 = oCurEntry.txBody.getSummaryHeight3();
                                aHeights.push(fCurEntryHeight);
                                aHeights2.push(fCurEntryHeight2);
                                if(fMaxEntryHeight < fCurEntryHeight2){
                                    fMaxEntryHeight = fCurEntryHeight2;
                                }
                                fSummWidth += fCurEntryWidth;
                            }
                        }
                        var nColsCount = Math.max(1, (fMaxLegendWidth / fMaxEntryWidth) >> 0);
                        var nMaxRowsCount = Math.max(1, (fMaxLegendHeight/fMaxEntryHeight) >> 0);
                        var nMaxEntriesCount = nColsCount*nMaxRowsCount;
                        if(calc_entryes.length > nMaxEntriesCount){
                            calc_entryes.splice(nMaxEntriesCount, calc_entryes.length - nMaxEntriesCount);
                            aWidths.splice(nMaxEntriesCount, aWidths.length - nMaxEntriesCount);
                            aHeights.splice(nMaxEntriesCount, aHeights.length - nMaxEntriesCount);
                            aHeights2.splice(nMaxEntriesCount, aHeights2.length - nMaxEntriesCount);
                            fMaxEntryWidth =  distance_to_text + fMarkerWidth + distance_to_text + Math.max.apply(Math, aWidths);
                            fMaxEntryHeight = Math.max.apply(Math, aHeights2);
                        }
                        var nRowsCount = Math.ceil(calc_entryes.length / nColsCount);
                        if(bFixedSize){
                            fLegendWidth = fFixedWidth;
                            fLegendHeight = fFixedHeight;
                        }
                        else{
                            fLegendWidth = fMaxEntryWidth*nColsCount;
                            fLegendHeight = nRowsCount* Math.max.apply(Math, aHeights);
                        }
                        fDistanceBetweenLabels = (fLegendWidth - nColsCount*fMaxEntryWidth)/nColsCount;
                        fVertDistanceBetweenLabels = (fLegendHeight - nRowsCount* Math.max.apply(Math, aHeights))/nRowsCount;
                        legend.extX = fLegendWidth;
                        legend.extY = fLegendHeight;
                        fCurPosY = fVertDistanceBetweenLabels/2.0;
                        for(i = 0; i < nRowsCount; ++i){
                            fCurPosX = fDistanceBetweenLabels/2.0;
                            for(j = 0; j < nColsCount && (i*nColsCount + j) < calc_entryes.length; ++j){
                                var nEntryIndex = i*nColsCount + j;
                                oCurEntry = calc_entryes[nEntryIndex];
                                // oUnionMarker = oCurEntry.calcMarkerUnion;
                                // oLineMarker = oUnionMarker.lineMarker;
                                // oMarker = oUnionMarker.marker;
                                // if(oLineMarker){
                                //     oLineMarker.localX = fCurPosX + distance_to_text;
                                //     if(oLineMarker.pen){
                                //         if(AscFormat.isRealNumber(oLineMarker.pen.w)){
                                //             fPenWidth = oLineMarker.pen.w/36000.0;
                                //         }
                                //         else{
                                //             fPenWidth = 12700.0/36000.0;
                                //         }
                                //     }
                                //     else{
                                //         fPenWidth = 0.0;
                                //     }
                                //     oLineMarker.localY = Math.max(0.0, fCurPosY + Math.max.apply(Math, aHeights)/2.0 - fPenWidth/2.0);
                                //     if(oMarker){
                                //         oMarker.localX = oLineMarker.localX + line_marker_width/2.0 - marker_size/2.0;
                                //         oMarker.localY = Math.max(0.0, fCurPosY + Math.max.apply(Math, aHeights)/2.0 - marker_size/2.0);
                                //     }
                                // }
                                // else{
                                //     if(oMarker){
                                //         oMarker.localX = fCurPosX + distance_to_text;
                                //         oMarker.localY = Math.max(0.0, fCurPosY + Math.max.apply(Math, aHeights)/2.0  - marker_size/2.0);
                                //     }
                                // }
                                this.layoutLegendEntry(oCurEntry, fCurPosX + distance_to_text, Math.max(0, fCurPosY + Math.max.apply(Math, aHeights)/2.0 - aHeights[nEntryIndex]/2.0), distance_to_text);
                                // oCurEntry.localX = fCurPosX + distance_to_text + fMarkerWidth + distance_to_text;
                                // oCurEntry.localY = Math.max(0, fCurPosY + Math.max.apply(Math, aHeights)/2.0 - aHeights[nEntryIndex]/2.0);
                                fCurPosX += (fMaxEntryWidth + fDistanceBetweenLabels);
                            }
                            fCurPosY += (Math.max.apply(Math, aHeights) + fVertDistanceBetweenLabels);
                        }
                        legend.setPosition(0, 0);
                    }
                }
            }
            else
            {
                //TODO
            }
            legend.recalcInfo = {recalculateLine: true, recalculateFill: true, recalculateTransparent: true};
            legend.recalculatePen();
            legend.recalculateBrush();
            for(var i = 0; i < calc_entryes.length; ++i)
            {
                calc_entryes[i].checkWidhtContent();
            }
        }
    };

CChartSpace.prototype.internalCalculatePenBrushFloorWall = function(oSide, nSideType)
{
    if(!oSide)
    {
        return;
    }

    var parent_objects = this.getParentObjects();
    if(oSide.spPr && oSide.spPr.ln)
    {
        oSide.pen = oSide.spPr.ln.createDuplicate();
    }
    else
    {
        var oCompiledPen = null;
        if(this.style >= 1 && this.style <= 40 && 2 === nSideType)
        {
            if(parent_objects.theme  && parent_objects.theme.themeElements
                && parent_objects.theme.themeElements.fmtScheme
                && parent_objects.theme.themeElements.fmtScheme.lnStyleLst
                && parent_objects.theme.themeElements.fmtScheme.lnStyleLst[0])
            {
                oCompiledPen = parent_objects.theme.themeElements.fmtScheme.lnStyleLst[0].createDuplicate();
                if(this.style >= 1 && this.style <= 32)
                {
                    oCompiledPen.Fill = CreateUnifillSolidFillSchemeColor(15, 0.75);
                }
                else
                {
                    oCompiledPen.Fill = CreateUnifillSolidFillSchemeColor(8, 0.75);
                }
            }
        }
        oSide.pen = oCompiledPen;
    }
    if(this.style >= 1 && this.style <= 32)
    {
        if(oSide.spPr && oSide.spPr.Fill)
        {
            oSide.brush = oSide.spPr.Fill.createDuplicate();
            if(nSideType === 0 || nSideType === 2)
            {
                var cColorMod = new AscFormat.CColorMod;
                if(nSideType === 2)
                    cColorMod.val = 45000;
                else
                    cColorMod.val = 35000;
                cColorMod.name = "shade";
                oSide.brush.addColorMod(cColorMod);
            }
        }
        else
        {
            oSide.brush = null;
        }
    }
    else
    {
        var oSubtleFill;
        if(parent_objects.theme  && parent_objects.theme.themeElements
            && parent_objects.theme.themeElements.fmtScheme
            && parent_objects.theme.themeElements.fmtScheme.fillStyleLst)
        {
            oSubtleFill = parent_objects.theme.themeElements.fmtScheme.fillStyleLst[0];
        }

        var oDefaultBrush;
        var tint = 0.20000;
        if(this.style >=33 && this.style <= 34)
            oDefaultBrush = CreateUnifillSolidFillSchemeColor(8, 0.20000);
        else if(this.style >=35 && this.style <=40)
            oDefaultBrush = CreateUnifillSolidFillSchemeColor(this.style - 35, tint);
        else
            oDefaultBrush = CreateUnifillSolidFillSchemeColor(8, 0.95000);

        if(oSide.spPr)
        {
            oDefaultBrush.merge(oSide.spPr.Fill);
        }

        if(nSideType === 0 || nSideType === 2)
        {
            var cColorMod = new AscFormat.CColorMod;
            if(nSideType === 0)
                cColorMod.val = 45000;
            else
                cColorMod.val = 35000;
            cColorMod.name = "shade";
            oDefaultBrush.addColorMod(cColorMod);
        }
        oSide.brush = oDefaultBrush;
    }

    if(oSide.brush)
    {
        oSide.brush.calculate(parent_objects.theme, parent_objects.slide, parent_objects.layout, parent_objects.master, {R: 0, G: 0, B: 0, A: 255}, this.clrMapOvr);
    }
    if(oSide.pen)
    {
        oSide.pen.calculate(parent_objects.theme, parent_objects.slide, parent_objects.layout, parent_objects.master, {R: 0, G: 0, B: 0, A: 255}, this.clrMapOvr);
    }
};

CChartSpace.prototype.recalculateWalls = function()
{
    if(this.chart)
    {
        this.internalCalculatePenBrushFloorWall(this.chart.sideWall, 0);
        this.internalCalculatePenBrushFloorWall(this.chart.backWall, 1);
        this.internalCalculatePenBrushFloorWall(this.chart.floor, 2);
    }
};

CChartSpace.prototype.recalculateUpDownBars = function()
{
    if(this.chart && this.chart.plotArea)
    {
        var aCharts = this.chart.plotArea.charts;
        for(var t = 0; t < aCharts.length; ++t){
            var oChart = aCharts[t];
            if(oChart && oChart.upDownBars){
                var bars = oChart.upDownBars;
                var up_bars = bars.upBars;
                var down_bars = bars.downBars;
                var parents = this.getParentObjects();
                bars.upBarsBrush = null;
                bars.upBarsPen = null;
                bars.downBarsBrush = null;
                bars.downBarsPen = null;
                if(up_bars || down_bars)
                {
                    var default_bar_line = new AscFormat.CLn();
                    if(parents.theme  && parents.theme.themeElements
                        && parents.theme.themeElements.fmtScheme
                        && parents.theme.themeElements.fmtScheme.lnStyleLst)
                    {
                        default_bar_line.merge(parents.theme.themeElements.fmtScheme.lnStyleLst[0]);
                    }
                    if(this.style >= 1 && this.style <= 16)
                        default_bar_line.setFill(CreateUnifillSolidFillSchemeColor(15, 0));
                    else if(this.style >= 17 && this.style <= 32 ||
                        this.style >= 41 && this.style <= 48)
                        default_bar_line = CreateNoFillLine();
                    else if(this.style === 33 || this.style === 34)
                        default_bar_line.setFill(CreateUnifillSolidFillSchemeColor(8, 0));
                    else if(this.style >= 35 && this.style <= 40)
                        default_bar_line.setFill(CreateUnifillSolidFillSchemeColor(this.style - 35, -0.25000));
                }
                if(up_bars)
                {
                    var default_up_bars_fill;
                    if(this.style === 1 || this.style === 9 || this.style === 17 || this.style === 25 || this.style === 41)
                    {
                        default_up_bars_fill = CreateUnifillSolidFillSchemeColor(8, 0.25000);
                    }
                    else if(this.style === 2 || this.style === 10 || this.style === 18 || this.style === 26)
                    {
                        default_up_bars_fill = CreateUnifillSolidFillSchemeColor(8, 0.05000);
                    }
                    else if(this.style >= 3 && this.style <= 8)
                    {
                        default_up_bars_fill = CreateUnifillSolidFillSchemeColor(this.style - 3, 0.25000);
                    }
                    else if(this.style >= 11 && this.style <= 16)
                    {
                        default_up_bars_fill = CreateUnifillSolidFillSchemeColor(this.style - 11, 0.25000);
                    }
                    else if(this.style >=19 && this.style <= 24)
                    {
                        default_up_bars_fill = CreateUnifillSolidFillSchemeColor(this.style - 19, 0.25000);
                    }
                    else if(this.style >= 27 && this.style <= 32 )
                    {
                        default_up_bars_fill = CreateUnifillSolidFillSchemeColor(this.style - 27, 0.25000);
                    }
                    else if(this.style >= 33 && this.style <= 40 || this.style === 42)
                    {
                        default_up_bars_fill = CreateUnifillSolidFillSchemeColor(12, 0);
                    }
                    else
                    {
                        default_up_bars_fill = CreateUnifillSolidFillSchemeColor(this.style - 43, 0.25000);
                    }
                    if(up_bars.Fill)
                    {
                        default_up_bars_fill.merge(up_bars.Fill);
                    }
                    default_up_bars_fill.calculate(parents.theme, parents.slide, parents.layout, parents.master, {R: 0, G: 0, B: 0, A: 255}, this.clrMapOvr);
                    oChart.upDownBars.upBarsBrush = default_up_bars_fill;
                    var up_bars_line = default_bar_line.createDuplicate();
                    if(up_bars.ln)
                        up_bars_line.merge(up_bars.ln);
                    up_bars_line.calculate(parents.theme, parents.slide, parents.layout, parents.master, {R: 0, G: 0, B: 0, A: 255}, this.clrMapOvr);
                    oChart.upDownBars.upBarsPen = up_bars_line;

                }
                if(down_bars)
                {
                    var default_down_bars_fill;
                    if(this.style === 1 || this.style === 9 || this.style === 17 || this.style === 25 || this.style === 41 || this.style === 33)
                    {
                        default_down_bars_fill = CreateUnifillSolidFillSchemeColor(8, 0.85000);
                    }
                    else if(this.style === 2 || this.style === 10 || this.style === 18 || this.style === 26 || this.style === 34)
                    {
                        default_down_bars_fill = CreateUnifillSolidFillSchemeColor(8, 0.95000);
                    }
                    else if(this.style >= 3 && this.style <= 8)
                    {
                        default_down_bars_fill = CreateUnifillSolidFillSchemeColor(this.style - 3, -0.25000);
                    }
                    else if(this.style >= 11 && this.style <= 16)
                    {
                        default_down_bars_fill = CreateUnifillSolidFillSchemeColor(this.style - 11, -0.25000);
                    }
                    else if(this.style >=19 && this.style <= 24)
                    {
                        default_down_bars_fill = CreateUnifillSolidFillSchemeColor(this.style - 19, -0.25000);
                    }
                    else if(this.style >= 27 && this.style <= 32 )
                    {
                        default_down_bars_fill = CreateUnifillSolidFillSchemeColor(this.style - 27, -0.25000);
                    }
                    else if(this.style >= 35 && this.style <= 40)
                    {
                        default_down_bars_fill = CreateUnifillSolidFillSchemeColor(this.style - 35, -0.25000);
                    }
                    else if(this.style === 42)
                    {
                        default_down_bars_fill = CreateUnifillSolidFillSchemeColor(8, 0);
                    }
                    else
                    {
                        default_down_bars_fill = CreateUnifillSolidFillSchemeColor(this.style - 43, -0.25000);
                    }
                    if(down_bars.Fill)
                    {
                        default_down_bars_fill.merge(down_bars.Fill);
                    }
                    default_down_bars_fill.calculate(parents.theme, parents.slide, parents.layout, parents.master, {R: 0, G: 0, B: 0, A: 255}, this.clrMapOvr);
                    oChart.upDownBars.downBarsBrush = default_down_bars_fill;
                    var down_bars_line = default_bar_line.createDuplicate();
                    if(down_bars.ln)
                        down_bars_line.merge(down_bars.ln);
                    down_bars_line.calculate(parents.theme, parents.slide, parents.layout, parents.master, {R: 0, G: 0, B: 0, A: 255}, this.clrMapOvr);
                    oChart.upDownBars.downBarsPen = down_bars_line;
                }
            }
        }
    }
};

CChartSpace.prototype.recalculatePlotAreaChartPen = function()
{
    if(this.chart && this.chart.plotArea)
    {
        if(this.chart.plotArea.spPr && this.chart.plotArea.spPr.ln)
        {
            this.chart.plotArea.pen = this.chart.plotArea.spPr.ln;
            var parents = this.getParentObjects();
            this.chart.plotArea.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, {R: 0, G: 0, B: 0, A: 255}, this.clrMapOvr);
        }
        else
        {
            this.chart.plotArea.pen = null;
        }
    }
};

CChartSpace.prototype.recalculatePenBrush = function()
{
    var parents = this.getParentObjects(), RGBA = {R: 0, G: 0, B: 0, A: 255};
    if(this.brush)
    {
        this.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
    }
    if(this.pen)
    {
        this.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
        checkBlackUnifill(this.pen.Fill, true);
    }
    if(this.chart)
    {
        if(this.chart.title)
        {
            if(this.chart.title.brush)
            {
                this.chart.title.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
            }
            if(this.chart.title.pen)
            {
                this.chart.title.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
            }
        }
        if(this.chart.plotArea)
        {
            if(this.chart.plotArea.brush)
            {
                this.chart.plotArea.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
            }
            if(this.chart.plotArea.pen)
            {
                this.chart.plotArea.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
            }
            for(var t = 0; t < this.chart.plotArea.axId.length; ++t){
                var oAxis = this.chart.plotArea.axId[t];
                if(oAxis.compiledTickMarkLn)
                {
                    oAxis.compiledTickMarkLn.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                    checkBlackUnifill(oAxis.compiledTickMarkLn.Fill, true);
                }
                if(oAxis.compiledMajorGridLines)
                {
                    oAxis.compiledMajorGridLines.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                    checkBlackUnifill(oAxis.compiledMajorGridLines.Fill, true);
                }
                if(oAxis.compiledMinorGridLines)
                {
                    oAxis.compiledMinorGridLines.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                    checkBlackUnifill(oAxis.compiledMinorGridLines.Fill, true);
                }
                if(oAxis.title)
                {
                    if(oAxis.title.brush)
                    {
                        oAxis.title.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                    }
                    if(oAxis.title.pen)
                    {
                        oAxis.title.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                    }
                }
            }

            for(t = 0; t < this.chart.plotArea.charts.length; ++t){
                var oChart = this.chart.plotArea.charts[t];
                var series = oChart.series;
                for(var i = 0; i < series.length; ++i)
                {
                    var pts = AscFormat.getPtsFromSeries(series[i]);
                    for(var j = 0; j < pts.length; ++j)
                    {
                        var pt = pts[j];
                        if(pt.brush)
                        {
                            pt.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);

                        }
                        if(pt.pen)
                        {
                            pt.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                        }
                        if(pt.compiledMarker)
                        {
                            if(pt.compiledMarker.brush)
                            {
                                pt.compiledMarker.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                            }
                            if(pt.compiledMarker.pen)
                            {
                                pt.compiledMarker.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                            }
                        }
                        if(pt.compiledDlb)
                        {
                            if(pt.compiledDlb.brush)
                            {
                                pt.compiledDlb.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                            }
                            if(pt.compiledDlb.pen)
                            {
                                pt.compiledDlb.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                            }

                        }
                    }
                }
                if(oChart.calculatedHiLowLines)
                {
                    oChart.calculatedHiLowLines.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                }
                if(oChart.upDownBars)
                {
                    if(oChart.upDownBars.upBarsBrush)
                    {
                        oChart.upDownBars.upBarsBrush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                    }
                    if(oChart.upDownBars.upBarsPen)
                    {
                        oChart.upDownBars.upBarsPen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                    }
                    if(oChart.upDownBars.downBarsBrush)
                    {
                        oChart.upDownBars.downBarsBrush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                    }
                    if(oChart.upDownBars.downBarsPen)
                    {
                        oChart.upDownBars.downBarsPen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                    }
                }
            }
        }
        if(this.chart.legend)
        {
            if(this.chart.legend.brush)
            {
                this.chart.legend.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
            }
            if(this.chart.legend.pen)
            {
                this.chart.legend.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
            }

            var legend = this.chart.legend;
            for(var i = 0; i < legend.calcEntryes.length; ++i)
            {
                var union_marker = legend.calcEntryes[i].calcMarkerUnion;
                if(union_marker)
                {
                    if(union_marker.marker)
                    {
                        if(union_marker.marker.pen)
                        {
                            union_marker.marker.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                        }
                        if(union_marker.marker.brush)
                        {
                            union_marker.marker.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                        }
                    }
                    if(union_marker.lineMarker)
                    {
                        if(union_marker.lineMarker.pen)
                        {
                            union_marker.lineMarker.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                        }
                        if(union_marker.lineMarker.brush)
                        {
                            union_marker.lineMarker.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                        }
                    }
                }
            }
        }
        if(this.chart.floor)
        {
            if(this.chart.floor.brush)
            {
                this.chart.floor.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
            }
            if(this.chart.floor.pen)
            {
                this.chart.floor.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
            }
        }
        if(this.chart.sideWall)
        {
            if(this.chart.sideWall.brush)
            {
                this.chart.sideWall.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
            }
            if(this.chart.sideWall.pen)
            {
                this.chart.sideWall.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
            }
        }
        if(this.chart.backWall)
        {
            if(this.chart.backWall.brush)
            {
                this.chart.backWall.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
            }
            if(this.chart.backWall.pen)
            {
                this.chart.backWall.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
            }
        }
    }
};

function fSaveChartObjectSourceFormatting(oObject, oObjectCopy, oTheme, oColorMap){
    if(oObject === oObjectCopy || !oObjectCopy || !oObject){
        return;
    }

    if(oObject.pen || oObject.brush){
        if(oObject.pen || oObject.brush){
            if(!oObjectCopy.spPr){
                if(oObjectCopy.setSpPr){
                    oObjectCopy.setSpPr(new AscFormat.CSpPr());
                    oObjectCopy.spPr.setParent(oObjectCopy);
                }
            }
            if(oObject.brush){
                oObjectCopy.spPr.setFill(oObject.brush.saveSourceFormatting());
            }
            if(oObject.pen){
                oObjectCopy.spPr.setLn(oObject.pen.createDuplicate(true));
            }
        }
    }
    if(oObject.txPr && oObject.txPr.content){
        AscFormat.SaveContentSourceFormatting(oObject.txPr.content.Content, oObjectCopy.txPr.content.Content, oTheme, oColorMap);
    }
    if(oObject.tx && oObject.tx.rich && oObject.tx.rich.content){
        AscFormat.SaveContentSourceFormatting(oObject.tx.rich.content.Content, oObjectCopy.tx.rich.content.Content, oTheme, oColorMap);
    }
}

CChartSpace.prototype.getCopyWithSourceFormatting = function(oIdMap)
{
    var oCopy = this.copy(this.getDrawingDocument());
    oCopy.updateLinks();
    if(oIdMap){
        oIdMap[this.Id] = oCopy.Id;
    }
    var oTheme = this.Get_Theme();
    var oColorMap = this.Get_ColorMap();




    fSaveChartObjectSourceFormatting(this, oCopy, oTheme, oColorMap);

    if(!oCopy.txPr || !oCopy.txPr.content || !oCopy.txPr.content.Content[0] || !oCopy.txPr.content.Content[0].Pr){
        oCopy.setTxPr(AscFormat.CreateTextBodyFromString("", this.getDrawingDocument(), oCopy));
    }
    var bMerge = false;
    var oTextPr = new CTextPr();
    if(!oCopy.txPr.content.Content[0].Pr.DefaultRunPr ||
        !oCopy.txPr.content.Content[0].Pr.DefaultRunPr.RFonts || !oCopy.txPr.content.Content[0].Pr.DefaultRunPr.RFonts.Ascii
        || !oCopy.txPr.content.Content[0].Pr.DefaultRunPr.RFonts.Ascii.Name){
        bMerge = true;
        oTextPr.RFonts.Set_FromObject(
            {
                Ascii: {
                    Name: "+mn-lt",
                    Index: -1
                },
                EastAsia: {
                    Name: "+mn-ea",
                    Index: -1
                },
                HAnsi: {
                    Name: "+mn-lt",
                    Index: -1
                },
                CS: {
                    Name: "+mn-lt",
                    Index: -1
                }
            }
        );
    }

    if(this.txPr.content.Content[0].Pr.DefaultRunPr && this.txPr.content.Content[0].Pr.DefaultRunPr.Unifill){
        bMerge = true;
        var oUnifill = this.txPr.content.Content[0].Pr.DefaultRunPr.Unifill.createDuplicate();
        oUnifill.check(this.Get_Theme(), this.Get_ColorMap());
        oTextPr.Unifill = oUnifill.saveSourceFormatting();
    }
    else if(!AscFormat.isRealNumber(this.style) || this.style < 33){
        bMerge = true;
        var oUnifill = CreateUnifillSolidFillSchemeColor(15, 0.0);
        oUnifill.check(this.Get_Theme(), this.Get_ColorMap());
        oTextPr.Unifill = oUnifill.saveSourceFormatting();
    }
    else{
        bMerge = true;
        var oUnifill = CreateUnifillSolidFillSchemeColor(6, 0.0);
        oUnifill.check(this.Get_Theme(), this.Get_ColorMap());
        oTextPr.Unifill = oUnifill.saveSourceFormatting();
    }

    if(bMerge){

        var oParaPr = oCopy.txPr.content.Content[0].Pr.Copy();
        var oParaPr2 = new CParaPr();
        var oCopyTextPr = oTextPr.Copy();
        oParaPr2.DefaultRunPr = oCopyTextPr;
        oParaPr.Merge(oParaPr2);
        oCopy.txPr.content.Content[0].Set_Pr(oParaPr);
        //CheckObjectTextPr(oCopy, oTextPr, this.getDrawingDocument());
        // fSaveChartObjectSourceFormatting(oCopy, oCopy, oTheme, oColorMap);
    }
    if(this.chart)
    {
        if(this.chart.title)
        {
            fSaveChartObjectSourceFormatting(this.chart.title, oCopy.chart.title, oTheme, oColorMap);
        }
        if(this.chart.plotArea)
        {
            fSaveChartObjectSourceFormatting(this.chart.plotArea, oCopy.chart.plotArea, oTheme, oColorMap);
            var aAxes = oCopy.chart.plotArea.axId;
            if(aAxes)
            {
                for(var i = 0; i < aAxes.length; ++i)
                {
                    if(aAxes[i] && this.chart.plotArea.axId[i])
                    {
                        fSaveChartObjectSourceFormatting(this.chart.plotArea.axId[i], aAxes[i], oTheme, oColorMap);
                        if(this.chart.plotArea.axId[i].compiledLn)
                        {
                            if(!aAxes[i].spPr){
                                aAxes[i].setSpPr(new AscFormat.CSpPr());
                            }
                            aAxes[i].spPr.setLn(this.chart.plotArea.axId[i].compiledLn.createDuplicate(true));
                        }
                        if(this.chart.plotArea.axId[i].compiledMajorGridLines)
                        {
                            if(!aAxes[i].majorGridlines){
                                aAxes[i].setMajorGridlines(new AscFormat.CSpPr());
                            }
                            aAxes[i].majorGridlines.setLn(this.chart.plotArea.axId[i].compiledMajorGridLines.createDuplicate(true));
                        }
                        if(this.chart.plotArea.axId[i].compiledMinorGridLines)
                        {
                            if(!aAxes[i].minorGridlines){
                                aAxes[i].setMinorGridlines(new AscFormat.CSpPr());
                            }
                            aAxes[i].minorGridlines.setLn(this.chart.plotArea.axId[i].compiledMinorGridLines.createDuplicate(true));
                        }
                        if(aAxes[i].title)
                        {
                            fSaveChartObjectSourceFormatting(this.chart.plotArea.axId[i].title, aAxes[i].title, oTheme, oColorMap);
                        }
                    }
                }
            }

            for(var t = 0; t < this.chart.plotArea.charts.length; ++t)
            {
                if(this.chart.plotArea.charts[t])
                {
                    var oChartOrig = this.chart.plotArea.charts[t];
                    var oChartCopy = oCopy.chart.plotArea.charts[t];
                    var series = oChartOrig.series;
                    var seriesCopy = oChartCopy.series;

                    var oDataPoint;
                    for(var i = 0; i < series.length; ++i)
                    {
                        series[i].brush = series[i].compiledSeriesBrush;
                        series[i].pen = series[i].compiledSeriesPen;
                        fSaveChartObjectSourceFormatting(series[i], seriesCopy[i], oTheme, oColorMap);
                        var pts = AscFormat.getPtsFromSeries(series[i]);
                        var ptsCopy = AscFormat.getPtsFromSeries(seriesCopy[i]);
                        for(var j = 0; j < pts.length; ++j)
                        {
                            var pt = pts[j];
                            oDataPoint = null;
                            if(Array.isArray(seriesCopy[i].dPt))
                            {
                                for(var k = 0; k < seriesCopy[i].dPt.length; ++k)
                                {
                                    if(seriesCopy[i].dPt[k].idx === pts[j].idx)
                                    {
                                        oDataPoint = seriesCopy[i].dPt[k];
                                        break;
                                    }
                                }
                            }
                            if(!oDataPoint)
                            {
                                oDataPoint = new AscFormat.CDPt();
                                oDataPoint.setIdx(pt.idx);
                                seriesCopy[i].addDPt(oDataPoint);
                            }
                            fSaveChartObjectSourceFormatting(pt, oDataPoint, oTheme, oColorMap);
                            if(pt.compiledMarker)
                            {
                                var oMarker = pt.compiledMarker.createDuplicate();
                                oDataPoint.setMarker(oMarker);
                                fSaveChartObjectSourceFormatting(pt.compiledMarker, oMarker, oTheme, oColorMap);
                            }
                        }
                    }
                    if(oChartOrig.calculatedHiLowLines)
                    {
                        if(!oChartCopy.hiLowLines)
                        {
                            oChartCopy.setHiLowLines(new AscFormat.CSpPr());
                        }
                        oChartCopy.hiLowLines.setLn(oChartOrig.calculatedHiLowLines.createDuplicate(true));
                    }
                    if( oChartOrig.upDownBars)
                    {
                        if(oChartOrig.upDownBars.upBarsBrush)
                        {
                            if(!oChartCopy.upDownBars.upBars)
                            {
                                oChartCopy.upDownBars.setUpBars(new AscFormat.CSpPr());
                            }
                            oChartCopy.upDownBars.upBars.setFill(oChartOrig.upDownBars.upBarsBrush.saveSourceFormatting());
                        }
                        if(oChartOrig.upDownBars.upBarsPen)
                        {
                            if(!oChartCopy.upDownBars.upBars)
                            {
                                oChartCopy.upDownBars.setUpBars(new AscFormat.CSpPr());
                            }
                            oChartCopy.upDownBars.upBars.setLn(oChartOrig.upDownBars.upBarsPen.createDuplicate(true));
                        }
                        if(oChartOrig.upDownBars.downBarsBrush)
                        {
                            if(!oChartCopy.upDownBars.downBars)
                            {
                                oChartCopy.upDownBars.setDownBars(new AscFormat.CSpPr());
                            }
                            oChartCopy.upDownBars.downBars.setFill(oChartOrig.upDownBars.downBarsBrush.saveSourceFormatting());
                        }
                        if(oChartOrig.upDownBars.downBarsPen)
                        {
                            if(!oChartCopy.upDownBars.downBars)
                            {
                                oChartCopy.upDownBars.setDownBars(new AscFormat.CSpPr());
                            }
                            oChartCopy.upDownBars.downBars.setLn(oChartOrig.upDownBars.downBarsPen.createDuplicate(true));
                        }
                    }
                }
            }
        }
        if(this.chart.legend)
        {
            fSaveChartObjectSourceFormatting(this.chart.legend, oCopy.chart.legend, oTheme, oColorMap);
            var legend = this.chart.legend;
            for(var i = 0; i < legend.legendEntryes.length; ++i)
            {
                fSaveChartObjectSourceFormatting(legend.legendEntryes[i], oCopy.chart.legend.legendEntryes[i], oTheme, oColorMap);
            }
        }
        if(this.chart.floor)
        {
            fSaveChartObjectSourceFormatting(this.chart.floor, oCopy.chart.floor, oTheme, oColorMap);
        }
        if(this.chart.sideWall)
        {

            fSaveChartObjectSourceFormatting(this.chart.sideWall, oCopy.chart.sideWall, oTheme, oColorMap);
        }
        if(this.chart.backWall)
        {
            fSaveChartObjectSourceFormatting(this.chart.backWall, oCopy.chart.backWall, oTheme, oColorMap);
        }
    }
    return oCopy;
};

CChartSpace.prototype.getChartSizes = function(bNotRecalculate)
{
    if(this.plotAreaRect && !this.recalcInfo.recalculateAxisVal){
        return {startX: this.plotAreaRect.x, startY: this.plotAreaRect.y, w : this.plotAreaRect.w, h: this.plotAreaRect.h};
    }
    if(!this.chartObj)
        this.chartObj = new AscFormat.CChartsDrawer();
    var oChartSize = this.chartObj.calculateSizePlotArea(this, bNotRecalculate);
    var oLayout = this.chart.plotArea.layout;
    if(oLayout){

        oChartSize.startX = this.calculatePosByLayout(oChartSize.startX, oLayout.xMode, oLayout.x, oChartSize.w, this.extX);
        oChartSize.startY = this.calculatePosByLayout(oChartSize.startY, oLayout.yMode, oLayout.y, oChartSize.h, this.extY);
        var fSize = this.calculateSizeByLayout(oChartSize.startX, this.extX, oLayout.w, oLayout.wMode );
        if(AscFormat.isRealNumber(fSize) && fSize > 0){
            var fSize2 = this.calculateSizeByLayout(oChartSize.startY, this.extY, oLayout.h, oLayout.hMode );
            if(AscFormat.isRealNumber(fSize2) && fSize2 > 0){
                oChartSize.w = fSize;
                oChartSize.h = fSize2;
                var aCharts = this.chart.plotArea.charts;
                for(var i = 0; i < aCharts.length; ++i){
                    var nChartType = aCharts[i].getObjectType();
                    if(nChartType === AscDFH.historyitem_type_PieChart || nChartType === AscDFH.historyitem_type_DoughnutChart){
                        var fCX = oChartSize.startX + oChartSize.w/2.0;
                        var fCY = oChartSize.startY + oChartSize.h/2.0;
                        var fPieSize = Math.min(oChartSize.w, oChartSize.h);
                        oChartSize.startX = fCX  - fPieSize/2.0;
                        oChartSize.startY = fCY  - fPieSize/2.0;
                        oChartSize.w = fPieSize;
                        oChartSize.h = fPieSize;
                        break;
                    }
                }
            }
        }
    }
    if(oChartSize.w <= 0){
        oChartSize.w = 1;
    }
    if(oChartSize.h <= 0){
        oChartSize.h = 1;
    }

    return oChartSize;
};

CChartSpace.prototype.getAllSeries =  function()
{
    var _ret = [];
    var aCharts = this.chart.plotArea.charts;
    for(var i = 0; i < aCharts.length; ++i){
        _ret = _ret.concat(aCharts[i].series);
    }

    return _ret;
};

CChartSpace.prototype.recalculatePlotAreaChartBrush = function()
{
    if(this.chart && this.chart.plotArea)
    {
        var plot_area = this.chart.plotArea;
        var default_brush;
        if(AscFormat.CChartsDrawer.prototype._isSwitchCurrent3DChart(this))
        {
            default_brush = CreateNoFillUniFill();
        }
        else
        {
            if(this.chart.plotArea && this.chart.plotArea.charts.length === 1 && this.chart.plotArea.charts[0] &&
                (this.chart.plotArea.charts[0].getObjectType() === AscDFH.historyitem_type_PieChart
                || this.chart.plotArea.charts[0].getObjectType() === AscDFH.historyitem_type_DoughnutChart))
            {
                default_brush = CreateNoFillUniFill();
            }
            else {
                var tint = 0.20000;
                if(this.style >=1 && this.style <=32)
                    default_brush = CreateUnifillSolidFillSchemeColor(6, tint);
                else if(this.style >=33 && this.style <= 34)
                    default_brush = CreateUnifillSolidFillSchemeColor(8, 0.20000);
                else if(this.style >=35 && this.style <=40)
                    default_brush = CreateUnifillSolidFillSchemeColor(this.style - 35, tint);
                else
                    default_brush = CreateUnifillSolidFillSchemeColor(8, 0.95000);
            }
        }
        if(plot_area.spPr && plot_area.spPr.Fill)
        {
            default_brush.merge(plot_area.spPr.Fill);
        }
        var parents = this.getParentObjects();
        default_brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, {R: 0, G: 0, B: 0, A: 255}, this.clrMapOvr);
        plot_area.brush = default_brush;
    }
};

CChartSpace.prototype.recalculateChartPen = function()
{
    var parent_objects = this.getParentObjects();
    var default_line = new AscFormat.CLn();
    if(parent_objects.theme  && parent_objects.theme.themeElements
        && parent_objects.theme.themeElements.fmtScheme
        && parent_objects.theme.themeElements.fmtScheme.lnStyleLst)
    {
        default_line.merge(parent_objects.theme.themeElements.fmtScheme.lnStyleLst[0]);
    }

    var fill;
    if(this.style >= 1 && this.style <= 32)
        fill = CreateUnifillSolidFillSchemeColor(15, 0.75000);
    else if(this.style >= 33 && this.style <= 40)
        fill = CreateUnifillSolidFillSchemeColor(8, 0.75000);
    else
        fill = CreateUnifillSolidFillSchemeColor(12, 0);
    default_line.setFill(fill);
    if(this.spPr && this.spPr.ln)
        default_line.merge(this.spPr.ln);
    var parents = this.getParentObjects();
    default_line.calculate(parents.theme, parents.slide, parents.layout, parents.master, {R: 0, G: 0, B: 0, A: 255}, this.clrMapOvr);
    this.pen = default_line;
    checkBlackUnifill(this.pen.Fill, true);
};

CChartSpace.prototype.recalculateChartBrush = function()
{
    var default_brush;
    if(this.style >=1 && this.style <=32)
        default_brush = CreateUnifillSolidFillSchemeColor(6, 0);
    else if(this.style >=33 && this.style <= 40)
        default_brush = CreateUnifillSolidFillSchemeColor(12, 0);
    else
        default_brush = CreateUnifillSolidFillSchemeColor(8, 0);

    if(this.spPr && this.spPr.Fill)
    {
        default_brush.merge(this.spPr.Fill);
    }
    var parents = this.getParentObjects();
    default_brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, {R: 0, G: 0, B: 0, A: 255}, this.clrMapOvr);
    this.brush = default_brush;

};

CChartSpace.prototype.recalculateAxisTickMark = function()
{
    if(this.chart && this.chart.plotArea)
    {
        var oThis = this;
        var calcMajorMinorGridLines = function (axis, defaultStyle, subtleLine, parents)
        {
            function calcGridLine(defaultStyle, spPr, subtleLine, parents)
            {
                var compiled_grid_lines = new AscFormat.CLn();
                compiled_grid_lines.merge(subtleLine);
                // if(compiled_grid_lines.Fill && compiled_grid_lines.Fill.fill && compiled_grid_lines.Fill.fill.color && compiled_grid_lines.Fill.fill.color.Mods)
                // {
                //     compiled_grid_lines.Fill.fill.color.Mods.Mods.length = 0;
                // }
                if(!compiled_grid_lines.Fill)
                {
                    compiled_grid_lines.setFill(new AscFormat.CUniFill());
                }
                //if(compiled_grid_lines.Fill && compiled_grid_lines.Fill.fill && compiled_grid_lines.Fill.fill.color && compiled_grid_lines.Fill.fill.color.Mods)
                //{
                //    compiled_grid_lines.Fill.fill.color.Mods.Mods.length = 0;
                //}
                compiled_grid_lines.Fill.merge(defaultStyle);

                if(subtleLine && subtleLine.Fill && subtleLine.Fill.fill && subtleLine.Fill.fill.color && subtleLine.Fill.fill.color.Mods
                    && compiled_grid_lines.Fill && compiled_grid_lines.Fill.fill && compiled_grid_lines.Fill.fill.color)
                {
                    compiled_grid_lines.Fill.fill.color.Mods =  subtleLine.Fill.fill.color.Mods.createDuplicate();
                }

                compiled_grid_lines.calculate(parents.theme, parents.slide, parents.layout, parents.master, {R: 0, G: 0, B: 0, A: 255}, oThis.clrMapOvr);
                checkBlackUnifill(compiled_grid_lines.Fill, true);
                if(spPr && spPr.ln)
                {
                    compiled_grid_lines.merge(spPr.ln);
                    compiled_grid_lines.calculate(parents.theme, parents.slide, parents.layout, parents.master, {R: 0, G: 0, B: 0, A: 255}, oThis.clrMapOvr);
                }

                return compiled_grid_lines;
            }
            axis.compiledLn = calcGridLine(defaultStyle.axisAndMajorGridLines, axis.spPr, subtleLine, parents);
            axis.compiledTickMarkLn = axis.compiledLn.createDuplicate();
            axis.compiledTickMarkLn.calculate(parents.theme, parents.slide, parents.layout, parents.master, {R: 0, G: 0, B: 0, A: 255}, oThis.clrMapOvr);
            checkBlackUnifill(axis.compiledTickMarkLn.Fill, true);
        };
        var default_style = CHART_STYLE_MANAGER.getDefaultLineStyleByIndex(this.style);
        var parent_objects = this.getParentObjects();
        var subtle_line;
        if(parent_objects.theme  && parent_objects.theme.themeElements
            && parent_objects.theme.themeElements.fmtScheme
            && parent_objects.theme.themeElements.fmtScheme.lnStyleLst)
        {
            subtle_line = parent_objects.theme.themeElements.fmtScheme.lnStyleLst[0];
        }
        var aAxes = this.chart.plotArea.axId;
        for(var i = 0; i < aAxes.length; ++i){
            calcMajorMinorGridLines(aAxes[i], default_style, subtle_line, parent_objects);
        }
    }
};

CChartSpace.prototype.getXValAxisValues = function()
{
    if(!this.chartObj)
    {
        this.chartObj = new AscFormat.CChartsDrawer()
    }
    this.chartObj.preCalculateData(this);
    return [].concat(this.chart.plotArea.catAx.scale)
};

CChartSpace.prototype.getValAxisValues = function()
{
    if(!this.chartObj)
    {
        this.chartObj = new AscFormat.CChartsDrawer()
    }
    this.chartObj.preCalculateData(this);
    return [].concat(this.chart.plotArea.valAx.scale);
};

CChartSpace.prototype.getCalcProps = function()
{
    if(!this.chartObj)
    {
        this.chartObj = new AscFormat.CChartsDrawer()
    }
    this.chartObj.preCalculateData(this);
    return this.chartObj.calcProp;
};

CChartSpace.prototype.recalculateDLbls = function()
{
    if(this.chart && this.chart.plotArea)
    {
        var aCharts = this.chart.plotArea.charts;
        for(var t = 0; t < aCharts.length; ++t){

            var series = aCharts[t].series;
            var nDefaultPosition;
            if(aCharts[t].getDefaultDataLabelsPosition)
            {
                nDefaultPosition = aCharts[t].getDefaultDataLabelsPosition();
            }

            var default_lbl = new AscFormat.CDLbl();
            default_lbl.initDefault(nDefaultPosition);
            var bSkip = false;
            if(this.ptsCount > MAX_LABELS_COUNT){
                bSkip = true;
            }
            var nCount = 0;
            var nLblCount = 0;
            for(var i = 0; i < series.length; ++i)
            {
                var ser = series[i];
                var pts = AscFormat.getPtsFromSeries(ser);
                for(var j = 0; j < pts.length; ++j)
                {

                    var pt = pts[j];

                    if(bSkip){

                        if(nLblCount > (MAX_LABELS_COUNT*(nCount/this.ptsCount))){
                            pt.compiledDlb = null;
                            nCount++;
                            continue;
                        }

                    }
                    var compiled_dlb = new AscFormat.CDLbl();
                    compiled_dlb.merge(default_lbl);
                    compiled_dlb.merge(aCharts[t].dLbls);
                    if(aCharts[t].dLbls)
                        compiled_dlb.merge(aCharts[t].dLbls.findDLblByIdx(pt.idx), false);
                    compiled_dlb.merge(ser.dLbls);
                    if(ser.dLbls)
                        compiled_dlb.merge(ser.dLbls.findDLblByIdx(pt.idx));

                    if(compiled_dlb.checkNoLbl())
                    {
                        pt.compiledDlb = null;
                    }
                    else
                    {
                        pt.compiledDlb = compiled_dlb;
                        pt.compiledDlb.chart = this;
                        pt.compiledDlb.series = ser;
                        pt.compiledDlb.pt = pt;
                        pt.compiledDlb.recalculate();
                        nLblCount++;
                    }
                    ++nCount;
                }
            }
        }
    }
};

CChartSpace.prototype.recalculateHiLowLines = function()
{
    if(this.chart && this.chart.plotArea){
        var aCharts = this.chart.plotArea.charts;
        var parents = this.getParentObjects();
        for(var i = 0; i < aCharts.length; ++i){
            var oCurChart = aCharts[i];
            if((oCurChart instanceof AscFormat.CStockChart || oCurChart instanceof AscFormat.CLineChart) && oCurChart.hiLowLines){
                var default_line = parents.theme.themeElements.fmtScheme.lnStyleLst[0].createDuplicate();
                if(this.style >=1 && this.style <= 32)
                    default_line.setFill(CreateUnifillSolidFillSchemeColor(15, 0));
                else if(this.style >= 33 && this.style <= 34)
                    default_line.setFill(CreateUnifillSolidFillSchemeColor(8, 0));
                else if(this.style >= 35 && this.style <= 40)
                    default_line.setFill(CreateUnifillSolidFillSchemeColor(8, -0.25000));
                else
                    default_line.setFill(CreateUnifillSolidFillSchemeColor(12, 0));
                default_line.merge(oCurChart.hiLowLines.ln);
                oCurChart.calculatedHiLowLines = default_line;
                default_line.calculate(parents.theme, parents.slide, parents.layout, parents.master, {R:0, G:0, B:0, A:255}, this.clrMapOvr);
            }
            else{
                oCurChart.calculatedHiLowLines = null;
            }
        }
    }
};

CChartSpace.prototype.recalculateSeriesColors = function()
{
    this.ptsCount = 0;
    if(this.chart && this.chart.plotArea)
    {
        var style = CHART_STYLE_MANAGER.getStyleByIndex(this.style);
        var parents = this.getParentObjects();
        var RGBA = {R: 0, G: 0, B: 0, A: 255};
        var aCharts = this.chart.plotArea.charts;
        var aAllSeries = [];
        for(var t = 0; t < aCharts.length; ++t){
            aAllSeries = aAllSeries.concat(aCharts[t].series);
        }
        var nMaxSeriesIdx = getMaxIdx(aAllSeries);
        for(t = 0; t < aCharts.length; ++t){
            var oChart = aCharts[t];
            var series = oChart.series;
            if(oChart.varyColors
                && (series.length === 1 || oChart.getObjectType() === AscDFH.historyitem_type_PieChart || oChart.getObjectType() === AscDFH.historyitem_type_DoughnutChart))
            {
                var base_fills2 = getArrayFillsFromBase(style.fill2, getMaxIdx(series));
                for(var ii = 0; ii < series.length; ++ ii)
                {
                    var ser = series[ii];
                    var pts = AscFormat.getPtsFromSeries(ser);
                    this.ptsCount += pts.length;

                    ser.compiledSeriesBrush = new AscFormat.CUniFill();
                    ser.compiledSeriesBrush.merge(base_fills2[ser.idx]);
                    if(ser.spPr && ser.spPr.Fill)
                    {
                        ser.compiledSeriesBrush.merge(ser.spPr.Fill);
                    }


                    ser.compiledSeriesPen =  new AscFormat.CLn();
                    if(style.line1 === EFFECT_NONE)
                    {
                        ser.compiledSeriesPen.w = 0;
                    }
                    else if(style.line1 === EFFECT_SUBTLE)
                    {
                        ser.compiledSeriesPen.merge(parents.theme.themeElements.fmtScheme.lnStyleLst[0]);
                    }
                    else if(style.line1 === EFFECT_MODERATE)
                    {
                        ser.compiledSeriesPen.merge(parents.theme.themeElements.fmtScheme.lnStyleLst[1]);
                    }
                    else if(style.line1 === EFFECT_INTENSE)
                    {
                        ser.compiledSeriesPen.merge(parents.theme.themeElements.fmtScheme.lnStyleLst[2]);
                    }
                    var base_line_fills2;
                    if(this.style === 34)
                        base_line_fills2 = getArrayFillsFromBase(style.line2, getMaxIdx(series));

                    ser.compiledSeriesPen.Fill = new AscFormat.CUniFill();
                    if(this.style !== 34)
                    {
                        ser.compiledSeriesPen.Fill.merge(style.line2[0]);
                    }
                    else
                    {
                        ser.compiledSeriesPen.Fill.merge(base_line_fills[ser.idx]);
                    }
                    if(ser.spPr && ser.spPr.ln)
                        ser.compiledSeriesPen.merge(ser.spPr.ln);


                    if(!(oChart.getObjectType() === AscDFH.historyitem_type_LineChart || oChart.getObjectType() === AscDFH.historyitem_type_ScatterChart))
                    {
                        var base_fills = getArrayFillsFromBase(style.fill2, getMaxIdx(pts));
                        for(var i = 0; i < pts.length; ++i)
                        {
                            var compiled_brush = new AscFormat.CUniFill();
                            compiled_brush.merge(base_fills[pts[i].idx]);
                            if(ser.spPr && ser.spPr.Fill)
                            {
                                compiled_brush.merge(ser.spPr.Fill);
                            }
                            if(Array.isArray(ser.dPt))
                            {
                                for(var j = 0; j < ser.dPt.length; ++j)
                                {
                                    if(ser.dPt[j].idx === pts[i].idx)
                                    {
                                        if(ser.dPt[j].spPr)
                                        {
                                            compiled_brush.merge(ser.dPt[j].spPr.Fill);
                                        }
                                        break;
                                    }
                                }
                            }
                            pts[i].brush = compiled_brush;
                            pts[i].brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                        }

                        default_line =  new AscFormat.CLn();
                        if(style.line1 === EFFECT_NONE)
                        {
                            default_line.w = 0;
                        }
                        else if(style.line1 === EFFECT_SUBTLE)
                        {
                            default_line.merge(parents.theme.themeElements.fmtScheme.lnStyleLst[0]);
                        }
                        else if(style.line1 === EFFECT_MODERATE)
                        {
                            default_line.merge(parents.theme.themeElements.fmtScheme.lnStyleLst[1]);
                        }
                        else if(style.line1 === EFFECT_INTENSE)
                        {
                            default_line.merge(parents.theme.themeElements.fmtScheme.lnStyleLst[2]);
                        }
                        var base_line_fills;
                        if(this.style === 34)
                            base_line_fills = getArrayFillsFromBase(style.line2, getMaxIdx(pts));
                        for(i = 0; i < pts.length; ++i)
                        {
                            var compiled_line = new AscFormat.CLn();
                            compiled_line.merge(default_line);
                            compiled_line.Fill = new AscFormat.CUniFill();
                            if(this.style !== 34)
                            {
                                compiled_line.Fill.merge(style.line2[0]);
                            }
                            else
                            {
                                compiled_line.Fill.merge(base_line_fills[pts[i].idx]);
                            }
                            if(ser.spPr && ser.spPr.ln)
                                compiled_line.merge(ser.spPr.ln);
                            if(Array.isArray(ser.dPt) && !(ser.getObjectType && ser.getObjectType() === AscDFH.historyitem_type_AreaSeries))
                            {
                                for(var j = 0; j < ser.dPt.length; ++j)
                                {
                                    if(ser.dPt[j].idx === pts[i].idx)
                                    {
                                        if(ser.dPt[j].spPr)
                                        {
                                            compiled_line.merge(ser.dPt[j].spPr.ln);
                                        }
                                        break;
                                    }
                                }
                            }
                            pts[i].pen = compiled_line;
                            pts[i].pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                        }
                    }
                    else
                    {
                        var default_line;
                        if(oChart.getObjectType() === AscDFH.historyitem_type_ScatterChart && oChart.scatterStyle === AscFormat.SCATTER_STYLE_MARKER || oChart.scatterStyle === AscFormat.SCATTER_STYLE_NONE)
                        {
                            default_line = new AscFormat.CLn();
                            default_line.setFill(new AscFormat.CUniFill());
                            default_line.Fill.setFill(new AscFormat.CNoFill());
                        }
                        else
                        {
                            default_line = parents.theme.themeElements.fmtScheme.lnStyleLst[0];
                        }
                        var base_line_fills = getArrayFillsFromBase(style.line4, getMaxIdx(pts));
                        for(var i = 0; i < pts.length; ++i)
                        {
                            var compiled_line = new AscFormat.CLn();
                            compiled_line.merge(default_line);
                            if(!(oChart.getObjectType() === AscDFH.historyitem_type_ScatterChart && oChart.scatterStyle === AscFormat.SCATTER_STYLE_MARKER || oChart.scatterStyle === AscFormat.SCATTER_STYLE_NONE))
                                compiled_line.Fill.merge(base_line_fills[pts[i].idx]);
                            compiled_line.w *= style.line3;
                            if(ser.spPr && ser.spPr.ln)
                            {
                                compiled_line.merge(ser.spPr.ln);
                            }
                            if(Array.isArray(ser.dPt))
                            {
                                for(var j = 0; j < ser.dPt.length; ++j)
                                {
                                    if(ser.dPt[j].idx === pts[i].idx)
                                    {
                                        if(ser.dPt[j].spPr)
                                        {
                                            compiled_line.merge(ser.dPt[j].spPr.ln);
                                        }
                                        break;
                                    }
                                }
                            }
                            pts[i].brush = null;
                            pts[i].pen = compiled_line;
                            pts[i].pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                        }
                    }
                    for(var j = 0; j < pts.length; ++j)
                    {
                        if(pts[j].compiledMarker)
                        {
                            pts[j].compiledMarker.pen &&  pts[j].compiledMarker.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                            pts[j].compiledMarker.brush &&  pts[j].compiledMarker.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);

                        }
                    }

                }
            }
            else
            {
                switch(oChart.getObjectType())
                {
                    case AscDFH.historyitem_type_LineChart:
                    case AscDFH.historyitem_type_RadarChart:
                    {
                        var base_line_fills = getArrayFillsFromBase(style.line4, nMaxSeriesIdx);
                        if(!AscFormat.CChartsDrawer.prototype._isSwitchCurrent3DChart(this))
                        {
                            for(var i = 0; i < series.length; ++i)
                            {
                                var default_line = parents.theme.themeElements.fmtScheme.lnStyleLst[0];
                                var ser = series[i];
                                var pts = AscFormat.getPtsFromSeries(ser);
                                this.ptsCount += pts.length;
                                var compiled_line = new AscFormat.CLn();
                                compiled_line.merge(default_line);
                                compiled_line.Fill && compiled_line.Fill.merge(base_line_fills[ser.idx]);
                                compiled_line.w *= style.line3;
                                if(ser.spPr && ser.spPr.ln)
                                    compiled_line.merge(ser.spPr.ln);
                                ser.compiledSeriesPen = compiled_line.createDuplicate();
                                for(var j = 0; j < pts.length; ++j)
                                {
                                    var compiled_line = new AscFormat.CLn();
                                    compiled_line.merge(default_line);
                                    compiled_line.Fill && compiled_line.Fill.merge(base_line_fills[ser.idx]);
                                    compiled_line.w *= style.line3;
                                    if(ser.spPr && ser.spPr.ln)
                                        compiled_line.merge(ser.spPr.ln);
                                    if(Array.isArray(ser.dPt))
                                    {
                                        for(var k = 0; k < ser.dPt.length; ++k)
                                        {
                                            if(ser.dPt[k].idx === pts[j].idx)
                                            {
                                                if(ser.dPt[k].spPr)
                                                {
                                                    compiled_line.merge(ser.dPt[k].spPr.ln);
                                                }
                                                break;
                                            }
                                        }
                                    }
                                    pts[j].brush = null;
                                    pts[j].pen = compiled_line;
                                    pts[j].pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                                    if(pts[j].compiledMarker)
                                    {

                                        pts[j].compiledMarker.pen &&  pts[j].compiledMarker.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                                        pts[j].compiledMarker.brush &&  pts[j].compiledMarker.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);

                                    }
                                }
                            }
                        }
                        else
                        {
                            var base_fills = getArrayFillsFromBase(style.fill2, nMaxSeriesIdx);
                            var base_line_fills = null;
                            if(style.line1 === EFFECT_SUBTLE && this.style === 34)
                                base_line_fills	= getArrayFillsFromBase(style.line2, nMaxSeriesIdx);
                            for(var i = 0; i < series.length; ++i)
                            {
                                var ser = series[i];
                                var compiled_brush = new AscFormat.CUniFill();
                                compiled_brush.merge(base_fills[ser.idx]);
                                if(ser.spPr && ser.spPr.Fill)
                                {
                                    compiled_brush.merge(ser.spPr.Fill);
                                }
                                ser.compiledSeriesBrush = compiled_brush.createDuplicate();
                                var pts = AscFormat.getPtsFromSeries(ser);
                                for(var j = 0; j < pts.length; ++j)
                                {
                                    var compiled_brush = new AscFormat.CUniFill();
                                    compiled_brush.merge(base_fills[ser.idx]);
                                    if(ser.spPr && ser.spPr.Fill)
                                    {
                                        compiled_brush.merge(ser.spPr.Fill);
                                    }
                                    if(Array.isArray(ser.dPt) && !(ser.getObjectType && ser.getObjectType() === AscDFH.historyitem_type_AreaSeries))
                                    {
                                        for(var k = 0; k < ser.dPt.length; ++k)
                                        {
                                            if(ser.dPt[k].idx === pts[j].idx)
                                            {
                                                if(ser.dPt[k].spPr)
                                                {
                                                    compiled_brush.merge(ser.dPt[k].spPr.Fill);
                                                }
                                                break;
                                            }
                                        }
                                    }
                                    pts[j].brush = compiled_brush;
                                    pts[j].brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                                }


                                //
                                {
                                    default_line =  new AscFormat.CLn();
                                    if(style.line1 === EFFECT_NONE)
                                    {
                                        default_line.w = 0;
                                    }
                                    else if(style.line1 === EFFECT_SUBTLE)
                                    {
                                        default_line.merge(parents.theme.themeElements.fmtScheme.lnStyleLst[0]);
                                    }
                                    else if(style.line1 === EFFECT_MODERATE)
                                    {
                                        default_line.merge(parents.theme.themeElements.fmtScheme.lnStyleLst[1]);
                                    }
                                    else if(style.line1 === EFFECT_INTENSE)
                                    {
                                        default_line.merge(parents.theme.themeElements.fmtScheme.lnStyleLst[2]);
                                    }
                                    var base_line_fills;
                                    if(this.style === 34)
                                        base_line_fills = getArrayFillsFromBase(style.line2, getMaxIdx(pts));


                                    var compiled_line = new AscFormat.CLn();
                                    compiled_line.merge(default_line);
                                    compiled_line.Fill = new AscFormat.CUniFill();
                                    if(this.style !== 34)
                                        compiled_line.Fill.merge(style.line2[0]);
                                    else
                                        compiled_line.Fill.merge(base_line_fills[ser.idx]);
                                    if(ser.spPr && ser.spPr.ln)
                                    {
                                        compiled_line.merge(ser.spPr.ln);
                                    }
                                    ser.compiledSeriesPen = compiled_line.createDuplicate();
                                    for(var j = 0; j < pts.length; ++j)
                                    {
                                        var compiled_line = new AscFormat.CLn();
                                        compiled_line.merge(default_line);
                                        compiled_line.Fill = new AscFormat.CUniFill();
                                        if(this.style !== 34)
                                            compiled_line.Fill.merge(style.line2[0]);
                                        else
                                            compiled_line.Fill.merge(base_line_fills[ser.idx]);
                                        if(ser.spPr && ser.spPr.ln)
                                        {
                                            compiled_line.merge(ser.spPr.ln);
                                        }
                                        if(Array.isArray(ser.dPt) && !(ser.getObjectType && ser.getObjectType() === AscDFH.historyitem_type_AreaSeries))
                                        {
                                            for(var k = 0; k < ser.dPt.length; ++k)
                                            {
                                                if(ser.dPt[k].idx === pts[j].idx)
                                                {
                                                    if(ser.dPt[k].spPr)
                                                    {
                                                        compiled_line.merge(ser.dPt[k].spPr.ln);
                                                    }
                                                    break;
                                                }
                                            }
                                        }
                                        pts[j].pen = compiled_line;
                                        pts[j].pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                                        if(pts[j].compiledMarker)
                                        {
                                            pts[j].compiledMarker.pen &&  pts[j].compiledMarker.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                                            pts[j].compiledMarker.brush &&  pts[j].compiledMarker.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                                        }
                                    }
                                }
                            }
                        }
                        break;
                    }
                    case AscDFH.historyitem_type_ScatterChart:
                    {
                        var base_line_fills = getArrayFillsFromBase(style.line4, nMaxSeriesIdx);
                        for(var i = 0; i < series.length; ++i)
                        {
                            var default_line = parents.theme.themeElements.fmtScheme.lnStyleLst[0];
                            var ser = series[i];
                            var pts = AscFormat.getPtsFromSeries(ser);
                            this.ptsCount += pts.length;
                            if(oChart.scatterStyle === AscFormat.SCATTER_STYLE_SMOOTH || oChart.scatterStyle === AscFormat.SCATTER_STYLE_SMOOTH_MARKER)
                            {
                                if(!AscFormat.isRealBool(ser.smooth))
                                {
                                    ser.smooth = true;
                                }
                            }
                            if(oChart.scatterStyle === AscFormat.SCATTER_STYLE_MARKER || oChart.scatterStyle === AscFormat.SCATTER_STYLE_NONE)
                            {
                                default_line = new AscFormat.CLn();
                                default_line.setFill(new AscFormat.CUniFill());
                                default_line.Fill.setFill(new AscFormat.CNoFill());
                            }

                            var compiled_line = new AscFormat.CLn();
                            compiled_line.merge(default_line);
                            if(!(oChart.scatterStyle === AscFormat.SCATTER_STYLE_MARKER || oChart.scatterStyle === AscFormat.SCATTER_STYLE_NONE))
                            {
                                compiled_line.Fill && compiled_line.Fill.merge(base_line_fills[ser.idx]);
                            }
                            compiled_line.w *= style.line3;
                            if(ser.spPr && ser.spPr.ln)
                                compiled_line.merge(ser.spPr.ln);
                            ser.compiledSeriesPen = compiled_line.createDuplicate();
                            for(var j = 0; j < pts.length; ++j)
                            {
                                var compiled_line = new AscFormat.CLn();
                                compiled_line.merge(default_line);
                                if(!(oChart.scatterStyle === AscFormat.SCATTER_STYLE_MARKER || oChart.scatterStyle === AscFormat.SCATTER_STYLE_NONE))
                                {
                                    compiled_line.Fill && compiled_line.Fill.merge(base_line_fills[ser.idx]);
                                }
                                compiled_line.w *= style.line3;
                                if(ser.spPr && ser.spPr.ln)
                                    compiled_line.merge(ser.spPr.ln);
                                if(Array.isArray(ser.dPt))
                                {
                                    for(var k = 0; k < ser.dPt.length; ++k)
                                    {
                                        if(ser.dPt[k].idx === pts[j].idx)
                                        {
                                            if(ser.dPt[k].spPr)
                                            {
                                                compiled_line.merge(ser.dPt[k].spPr.ln);
                                            }
                                            break;
                                        }
                                    }
                                }
                                pts[j].brush = null;
                                pts[j].pen = compiled_line;
                                pts[j].pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                                if(pts[j].compiledMarker)
                                {

                                    pts[j].compiledMarker.pen &&  pts[j].compiledMarker.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                                    pts[j].compiledMarker.brush &&  pts[j].compiledMarker.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);

                                }
                            }
                        }
                        break;
                    }
                    case AscDFH.historyitem_type_SurfaceChart:
                    {
                        var oSurfaceChart = oChart;
                        var aValAxArray = this.getValAxisValues();
                        var nFmtsCount = aValAxArray.length - 1;
                        var oSpPr, oBandFmt, oCompiledBandFmt;
                        oSurfaceChart.compiledBandFormats.length = 0;
                        var multiplier;
                        var axis_by_types = oSurfaceChart.getAxisByTypes();
                        var val_ax = axis_by_types.valAx[0];
                        if(val_ax.dispUnits)
                            multiplier = val_ax.dispUnits.getMultiplier();
                        else
                            multiplier = 1;
                        var num_fmt = val_ax.numFmt, num_format = null, calc_value, rich_value;
                        if(num_fmt && typeof num_fmt.formatCode === "string" /*&& !(num_fmt.formatCode === "General")*/)
                        {
                            num_format = oNumFormatCache.get(num_fmt.formatCode);
                        }
                        var oParentObjects = this.getParentObjects();
                        var RGBA = {R: 255, G: 255, B: 255, A: 255};
                        if(oSurfaceChart.isWireframe()){
                            var base_line_fills = getArrayFillsFromBase(style.line4, nFmtsCount);
                            var default_line = parents.theme.themeElements.fmtScheme.lnStyleLst[0];
                            for(var i = 0; i < nFmtsCount; ++i)
                            {
                                oBandFmt = oSurfaceChart.getBandFmtByIndex(i);
                                oSpPr = new AscFormat.CSpPr();
                                oSpPr.setFill(AscFormat.CreateNoFillUniFill());
                                var compiled_line = new AscFormat.CLn();
                                compiled_line.merge(default_line);
                                compiled_line.Fill.merge(base_line_fills[i]);
                                //compiled_line.w *= style.line3;
                                compiled_line.Join = new AscFormat.LineJoin();
                                compiled_line.Join.type = AscFormat.LineJoinType.Bevel;
                                if(oBandFmt && oBandFmt.spPr){
                                    compiled_line.merge(oBandFmt.spPr.ln);
                                }
                                compiled_line.calculate(oParentObjects.theme, oParentObjects.slide, oParentObjects.layout, oParentObjects.master, RGBA, this.clrMapOvr);
                                oSpPr.setLn(compiled_line);
                                oCompiledBandFmt = new AscFormat.CBandFmt();
                                oCompiledBandFmt.setIdx(i);
                                oCompiledBandFmt.setSpPr(oSpPr);



                                if(num_format){
                                    oCompiledBandFmt.startValue = num_format.formatToChart(aValAxArray[i]*multiplier);
                                    oCompiledBandFmt.endValue = num_format.formatToChart(aValAxArray[i+1]*multiplier);

                                }
                                else{
                                    oCompiledBandFmt.startValue = '' + (aValAxArray[i]*multiplier);
                                    oCompiledBandFmt.endValue = '' + (aValAxArray[i+1]*multiplier);
                                }
                                oCompiledBandFmt.setSpPr(oSpPr);
                                oSurfaceChart.compiledBandFormats.push(oCompiledBandFmt);
                            }
                        }
                        else{
                            var base_fills = getArrayFillsFromBase(style.fill2, nFmtsCount);
                            var base_line_fills = null;
                            if(style.line1 === EFFECT_SUBTLE && this.style === 34)
                                base_line_fills	= getArrayFillsFromBase(style.line2, nFmtsCount);

                            var default_line =  new AscFormat.CLn();
                            if(style.line1 === EFFECT_NONE)
                            {
                                default_line.w = 0;
                            }
                            else if(style.line1 === EFFECT_SUBTLE)
                            {
                                default_line.merge(parents.theme.themeElements.fmtScheme.lnStyleLst[0]);
                            }
                            else if(style.line1 === EFFECT_MODERATE)
                            {
                                default_line.merge(parents.theme.themeElements.fmtScheme.lnStyleLst[1]);
                            }
                            else if(style.line1 === EFFECT_INTENSE)
                            {
                                default_line.merge(parents.theme.themeElements.fmtScheme.lnStyleLst[2]);
                            }

                            for(var i = 0; i < nFmtsCount; ++i) {
                                oBandFmt = oSurfaceChart.getBandFmtByIndex(i);
                                var compiled_brush = new AscFormat.CUniFill();
                                oSpPr = new AscFormat.CSpPr();
                                compiled_brush.merge(base_fills[i]);
                                if (oBandFmt && oBandFmt.spPr) {
                                    compiled_brush.merge(oBandFmt.spPr.Fill);
                                }
                                oSpPr.setFill(compiled_brush);

                                var compiled_line = new AscFormat.CLn();
                                compiled_line.merge(default_line);
                                compiled_line.Fill = new AscFormat.CUniFill();
                                if(this.style !== 34)
                                    compiled_line.Fill.merge(style.line2[0]);
                                else
                                    compiled_line.Fill.merge(base_line_fills[i]);
                                if(oBandFmt && oBandFmt.spPr && oBandFmt.spPr.ln)
                                {
                                    compiled_line.merge(oBandFmt.spPr.ln);
                                }
                                oSpPr.setLn(compiled_line);
                                compiled_line.calculate(oParentObjects.theme, oParentObjects.slide, oParentObjects.layout, oParentObjects.master, RGBA, this.clrMapOvr);
                                compiled_brush.calculate(oParentObjects.theme, oParentObjects.slide, oParentObjects.layout, oParentObjects.master, RGBA, this.clrMapOvr);
                                oCompiledBandFmt = new AscFormat.CBandFmt();
                                oCompiledBandFmt.setIdx(i);
                                oCompiledBandFmt.setSpPr(oSpPr);
                                if(num_format){
                                    oCompiledBandFmt.startValue = num_format.formatToChart(aValAxArray[i]*multiplier);
                                    oCompiledBandFmt.endValue = num_format.formatToChart(aValAxArray[i+1]*multiplier);

                                }
                                else{
                                    oCompiledBandFmt.startValue = '' + (aValAxArray[i]*multiplier);
                                    oCompiledBandFmt.endValue = '' + (aValAxArray[i+1]*multiplier);
                                }
                                oSurfaceChart.compiledBandFormats.push(oCompiledBandFmt);
                            }
                        }
                        break;
                    }
                    default :
                    {
                        var base_fills = getArrayFillsFromBase(style.fill2, nMaxSeriesIdx);
                        var base_line_fills = null;
                        if(style.line1 === EFFECT_SUBTLE && this.style === 34)
                            base_line_fills	= getArrayFillsFromBase(style.line2, nMaxSeriesIdx);
                        for(var i = 0; i < series.length; ++i)
                        {
                            var ser = series[i];
                            var compiled_brush = new AscFormat.CUniFill();
                            compiled_brush.merge(base_fills[ser.idx]);
                            if(ser.spPr && ser.spPr.Fill)
                            {
                                compiled_brush.merge(ser.spPr.Fill);
                            }
                            ser.compiledSeriesBrush = compiled_brush.createDuplicate();
                            var pts = AscFormat.getPtsFromSeries(ser);
                            this.ptsCount += pts.length;
                            for(var j = 0; j < pts.length; ++j)
                            {
                                var compiled_brush = new AscFormat.CUniFill();
                                compiled_brush.merge(base_fills[ser.idx]);
                                if(ser.spPr && ser.spPr.Fill)
                                {
                                    compiled_brush.merge(ser.spPr.Fill);
                                }
                                if(Array.isArray(ser.dPt) && !(ser.getObjectType && ser.getObjectType() === AscDFH.historyitem_type_AreaSeries))
                                {
                                    for(var k = 0; k < ser.dPt.length; ++k)
                                    {
                                        if(ser.dPt[k].idx === pts[j].idx)
                                        {
                                            if(ser.dPt[k].spPr)
                                            {
                                                compiled_brush.merge(ser.dPt[k].spPr.Fill);
                                            }
                                            break;
                                        }
                                    }
                                }
                                pts[j].brush = compiled_brush;
                                pts[j].brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                            }


                            //
                            {
                                default_line =  new AscFormat.CLn();
                                if(style.line1 === EFFECT_NONE)
                                {
                                    default_line.w = 0;
                                }
                                else if(style.line1 === EFFECT_SUBTLE)
                                {
                                    default_line.merge(parents.theme.themeElements.fmtScheme.lnStyleLst[0]);
                                }
                                else if(style.line1 === EFFECT_MODERATE)
                                {
                                    default_line.merge(parents.theme.themeElements.fmtScheme.lnStyleLst[1]);
                                }
                                else if(style.line1 === EFFECT_INTENSE)
                                {
                                    default_line.merge(parents.theme.themeElements.fmtScheme.lnStyleLst[2]);
                                }
                                var base_line_fills;
                                if(this.style === 34)
                                    base_line_fills = getArrayFillsFromBase(style.line2, getMaxIdx(pts));


                                var compiled_line = new AscFormat.CLn();
                                compiled_line.merge(default_line);
                                compiled_line.Fill = new AscFormat.CUniFill();
                                if(this.style !== 34)
                                    compiled_line.Fill.merge(style.line2[0]);
                                else
                                    compiled_line.Fill.merge(base_line_fills[ser.idx]);
                                if(ser.spPr && ser.spPr.ln)
                                {
                                    compiled_line.merge(ser.spPr.ln);
                                }
                                ser.compiledSeriesPen = compiled_line.createDuplicate();
                                for(var j = 0; j < pts.length; ++j)
                                {
                                    var compiled_line = new AscFormat.CLn();
                                    compiled_line.merge(default_line);
                                    compiled_line.Fill = new AscFormat.CUniFill();
                                    if(this.style !== 34)
                                        compiled_line.Fill.merge(style.line2[0]);
                                    else
                                        compiled_line.Fill.merge(base_line_fills[ser.idx]);
                                    if(ser.spPr && ser.spPr.ln)
                                    {
                                        compiled_line.merge(ser.spPr.ln);
                                    }
                                    if(Array.isArray(ser.dPt) && !(ser.getObjectType && ser.getObjectType() === AscDFH.historyitem_type_AreaSeries))
                                    {
                                        for(var k = 0; k < ser.dPt.length; ++k)
                                        {
                                            if(ser.dPt[k].idx === pts[j].idx)
                                            {
                                                if(ser.dPt[k].spPr)
                                                {
                                                    compiled_line.merge(ser.dPt[k].spPr.ln);
                                                }
                                                break;
                                            }
                                        }
                                    }
                                    pts[j].pen = compiled_line;
                                    pts[j].pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                                    if(pts[j].compiledMarker)
                                    {
                                        pts[j].compiledMarker.pen &&  pts[j].compiledMarker.pen.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                                        pts[j].compiledMarker.brush &&  pts[j].compiledMarker.brush.calculate(parents.theme, parents.slide, parents.layout, parents.master, RGBA, this.clrMapOvr);
                                    }
                                }
                            }
                        }
                        break;
                    }
                }
            }
        }
    }
};

CChartSpace.prototype.recalculateChartTitleEditMode = function(bWord)
{
    var old_pos_x, old_pos_y, old_pos_cx, old_pos_cy;
    var pos_x, pos_y;
    old_pos_x = this.recalcInfo.recalcTitle.x;
    old_pos_y = this.recalcInfo.recalcTitle.y;
    old_pos_cx = this.recalcInfo.recalcTitle.x + this.recalcInfo.recalcTitle.extX/2;
    old_pos_cy = this.recalcInfo.recalcTitle.y + this.recalcInfo.recalcTitle.extY/2;

    this.recalculateAxisLabels();
    if(checkVerticalTitle(this.recalcInfo.recalcTitle))
    {
        pos_x = old_pos_x;
        pos_y = old_pos_cy - this.recalcInfo.recalcTitle.extY/2;
    }
    else
    {
        pos_x = old_pos_cx - this.recalcInfo.recalcTitle.extX/2;
        pos_y = old_pos_y;
    }
    this.recalcInfo.recalcTitle.setPosition(pos_x, pos_y);
    if(bWord)
    {
        this.recalcInfo.recalcTitle.updatePosition(this.posX, this.posY);
    }
};

CChartSpace.prototype.recalculateMarkers = function()
{
    if(this.chart && this.chart.plotArea)
    {
        var aCharts = this.chart.plotArea.charts;
        var oCurChart;
        var aAllsSeries = [];
        for(var t = 0; t < aCharts.length; ++t){
            oCurChart = aCharts[t];
            var series = oCurChart.series, pts;
            aAllsSeries = aAllsSeries.concat(series);
            for(var i = 0; i < series.length; ++i)
            {
                var ser = series[i];
                ser.compiledSeriesMarker = null;
                pts =  AscFormat.getPtsFromSeries(ser);
                for(var j = 0; j < pts.length; ++j)
                {
                    pts[j].compiledMarker = null;
                }
            }

            var oThis = this;
            var recalculateMarkers2 = function()
            {
                var chart_style = CHART_STYLE_MANAGER.getStyleByIndex(oThis.style);
                var effect_fill = chart_style.fill1;
                var fill = chart_style.fill2;
                var line = chart_style.line4;
                var masrker_default_size = AscFormat.isRealNumber(oThis.style) ? chart_style.markerSize : 5;
                var default_marker = new AscFormat.CMarker();
                default_marker.setSize(masrker_default_size);
                var parent_objects = oThis.getParentObjects();

                if(parent_objects.theme  && parent_objects.theme.themeElements
                    && parent_objects.theme.themeElements.fmtScheme
                    && parent_objects.theme.themeElements.fmtScheme.lnStyleLst)
                {
                    default_marker.setSpPr(new AscFormat.CSpPr());
                    default_marker.spPr.setLn(new AscFormat.CLn());
                    default_marker.spPr.ln.merge(parent_objects.theme.themeElements.fmtScheme.lnStyleLst[0]);
                }
                var RGBA = {R:0, G:0, B:0, A: 255};
                if(oCurChart.varyColors && (oCurChart.series.length === 1 || oCurChart.getObjectType() === AscDFH.historyitem_type_PieChart || oCurChart.getObjectType() === AscDFH.historyitem_type_DoughnutChart))
                {
                    if(oCurChart.series.length < 1){
                        return;
                    }
                    var ser = oCurChart.series[0], pts;
                    if(ser.marker && ser.marker.symbol === AscFormat.SYMBOL_NONE && (!Array.isArray(ser.dPt) || ser.dPt.length === 0))
                        return;
                    pts = AscFormat.getPtsFromSeries(ser);
                    var series_marker = ser.marker;
                    var brushes = getArrayFillsFromBase(fill, getMaxIdx(pts));
                    var pens_fills = getArrayFillsFromBase(line, getMaxIdx(pts));
                    var compiled_markers = [];

                    for(var i = 0;  i < pts.length; ++i)
                    {
                        var compiled_marker = new AscFormat.CMarker();
                        compiled_marker.merge(default_marker);
                        if(!compiled_marker.spPr)
                        {
                            compiled_marker.setSpPr(new AscFormat.CSpPr());
                        }
                        compiled_marker.spPr.setFill(brushes[pts[i].idx]);
                        compiled_marker.spPr.Fill.merge(pts[i].brush);
                        if(!compiled_marker.spPr.ln)
                            compiled_marker.spPr.setLn(new AscFormat.CLn());
                        compiled_marker.spPr.ln.merge(pts[i].pen);
                        compiled_marker.setSymbol(GetTypeMarkerByIndex(i));
                        compiled_marker.merge(ser.marker);

                        if(Array.isArray(ser.dPt))
                        {
                            for(var j = 0; j < ser.dPt.length; ++j)
                            {
                                if(ser.dPt[j].idx === pts[i].idx)
                                {

                                    var d_pt = ser.dPt[j];
                                    if(d_pt.spPr && (d_pt.spPr.Fill || d_pt.spPr.ln))
                                    {
                                        if(!compiled_marker.spPr)
                                        {
                                            compiled_marker.setSpPr(new AscFormat.CSpPr());
                                        }
                                        if(d_pt.spPr.Fill)
                                        {
                                            compiled_marker.spPr.setFill(d_pt.spPr.Fill.createDuplicate());
                                        }
                                        if(d_pt.spPr.ln)
                                        {
                                            if(!compiled_marker.spPr.ln)
                                            {
                                                compiled_marker.spPr.setLn(new AscFormat.CLn());
                                            }
                                            compiled_marker.spPr.ln.merge(d_pt.spPr.ln);
                                        }
                                    }

                                    compiled_marker.merge(ser.dPt[j].marker);
                                    break;
                                }
                            }
                        }
                        pts[i].compiledMarker = compiled_marker;
                        pts[i].compiledMarker.pen = compiled_marker.spPr.ln;
                        pts[i].compiledMarker.brush = compiled_marker.spPr.Fill;
                        pts[i].compiledMarker.brush.calculate(parent_objects.theme, parent_objects.slide, parent_objects.layout, parent_objects.master, RGBA, oThis.clrMapOvr);
                        pts[i].compiledMarker.pen.calculate(parent_objects.theme, parent_objects.slide, parent_objects.layout, parent_objects.master, RGBA, oThis.clrMapOvr);
                    }
                }
                else
                {
                    var series = oCurChart.series;
                    var brushes = getArrayFillsFromBase(fill, getMaxIdx(aAllsSeries));
                    var pens_fills = getArrayFillsFromBase(line, getMaxIdx(aAllsSeries));
                    for(var i = 0; i < series.length; ++i)
                    {
                        var ser = series[i];
                        if(ser.marker && ser.marker.symbol === AscFormat.SYMBOL_NONE && (!Array.isArray(ser.dPt) || ser.dPt.length === 0))
                            continue;
                        pts = AscFormat.getPtsFromSeries(ser);
                        for(var j = 0; j < pts.length; ++j)
                        {
                            var compiled_marker = new AscFormat.CMarker();
                            compiled_marker.merge(default_marker);
                            if(!compiled_marker.spPr)
                            {
                                compiled_marker.setSpPr(new AscFormat.CSpPr());
                            }
                            compiled_marker.spPr.setFill(brushes[series[i].idx]);
                            if(!compiled_marker.spPr.ln)
                                compiled_marker.spPr.setLn(new AscFormat.CLn());
                            compiled_marker.spPr.ln.setFill(pens_fills[series[i].idx]);
                            compiled_marker.setSymbol(GetTypeMarkerByIndex(series[i].idx));
                            compiled_marker.merge(ser.marker);
                            if(j === 0)
                                ser.compiledSeriesMarker = compiled_marker.createDuplicate();
                            if(Array.isArray(ser.dPt))
                            {
                                for(var k = 0; k < ser.dPt.length; ++k)
                                {
                                    if(ser.dPt[k].idx === pts[j].idx)
                                    {
                                        compiled_marker.merge(ser.dPt[k].marker);
                                        break;
                                    }
                                }
                            }
                            pts[j].compiledMarker = compiled_marker;
                            pts[j].compiledMarker.pen = compiled_marker.spPr.ln;
                            pts[j].compiledMarker.brush = compiled_marker.spPr.Fill;
                            pts[j].compiledMarker.brush.calculate(parent_objects.theme, parent_objects.slide, parent_objects.layout, parent_objects.master, RGBA, oThis.clrMapOvr);
                            pts[j].compiledMarker.pen.calculate(parent_objects.theme, parent_objects.slide, parent_objects.layout, parent_objects.master, RGBA, oThis.clrMapOvr);
                        }
                    }
                }
            };

            switch (oCurChart.getObjectType())
            {
                case AscDFH.historyitem_type_LineChart:
                case AscDFH.historyitem_type_RadarChart:
                {
                    if(oCurChart.marker !== false)
                    {
                        recalculateMarkers2();
                    }
                    break;
                }
                case AscDFH.historyitem_type_ScatterChart:
                {
                    if(oCurChart.scatterStyle === AscFormat.SCATTER_STYLE_MARKER || oCurChart.scatterStyle === AscFormat.SCATTER_STYLE_LINE_MARKER || oCurChart.scatterStyle === AscFormat.SCATTER_STYLE_SMOOTH_MARKER)
                    {
                        recalculateMarkers2();
                    }
                    break;
                }
                default:
                {
                    recalculateMarkers2();
                    break;
                }
            }
        }
    }
};

CChartSpace.prototype.calcGridLine = function(defaultStyle, spPr, subtleLine, parents)
{
    if(spPr)
    {
        var compiled_grid_lines = new AscFormat.CLn();
        compiled_grid_lines.merge(subtleLine);
        // if(compiled_grid_lines.Fill && compiled_grid_lines.Fill.fill && compiled_grid_lines.Fill.fill.color && compiled_grid_lines.Fill.fill.color.Mods)
        // {
        //     compiled_grid_lines.Fill.fill.color.Mods.Mods.length = 0;
        // }
        if(!compiled_grid_lines.Fill)
        {
            compiled_grid_lines.setFill(new AscFormat.CUniFill());
        }
        //if(compiled_grid_lines.Fill && compiled_grid_lines.Fill.fill && compiled_grid_lines.Fill.fill.color && compiled_grid_lines.Fill.fill.color.Mods)
        //{
        //    compiled_grid_lines.Fill.fill.color.Mods.Mods.length = 0;
        //}
        compiled_grid_lines.Fill.merge(defaultStyle);

        if(subtleLine && subtleLine.Fill && subtleLine.Fill.fill && subtleLine.Fill.fill.color && subtleLine.Fill.fill.color.Mods
            && compiled_grid_lines.Fill && compiled_grid_lines.Fill.fill && compiled_grid_lines.Fill.fill.color)
        {
            compiled_grid_lines.Fill.fill.color.Mods =  subtleLine.Fill.fill.color.Mods.createDuplicate();
        }
        compiled_grid_lines.merge(spPr.ln);
        compiled_grid_lines.calculate(parents.theme, parents.slide, parents.layout, parents.master, {R: 0, G: 0, B: 0, A: 255}, this.clrMapOvr);
        checkBlackUnifill(compiled_grid_lines.Fill, true);
        return compiled_grid_lines;
    }
    return null;
};

CChartSpace.prototype.calcMajorMinorGridLines = function (axis, defaultStyle, subtleLine, parents)
{
    if(!axis)
        return;
    axis.compiledMajorGridLines = this.calcGridLine(defaultStyle.axisAndMajorGridLines, axis.majorGridlines, subtleLine, parents);
    axis.compiledMinorGridLines = this.calcGridLine(defaultStyle.minorGridlines, axis.minorGridlines, subtleLine, parents);
};

CChartSpace.prototype.handleTitlesAfterChangeTheme = function()
{
    if(this.chart && this.chart.title)
    {
        this.chart.title.checkAfterChangeTheme();
    }
    if(this.chart && this.chart.plotArea)
    {
        var hor_axis = this.chart.plotArea.getHorizontalAxis();
        if(hor_axis && hor_axis.title)
        {
            hor_axis.title.checkAfterChangeTheme();
        }
        var vert_axis = this.chart.plotArea.getVerticalAxis();
        if(vert_axis && vert_axis.title)
        {
            vert_axis.title.checkAfterChangeTheme();
        }
    }
};

CChartSpace.prototype.recalculateGridLines = function()
{
    if(this.chart && this.chart.plotArea)
    {
        var default_style = CHART_STYLE_MANAGER.getDefaultLineStyleByIndex(this.style);
        var parent_objects = this.getParentObjects();
        var subtle_line;
        if(parent_objects.theme  && parent_objects.theme.themeElements
            && parent_objects.theme.themeElements.fmtScheme
            && parent_objects.theme.themeElements.fmtScheme.lnStyleLst)
        {
            subtle_line = parent_objects.theme.themeElements.fmtScheme.lnStyleLst[0];
        }
        var aAxes = this.chart.plotArea.axId;
        for(var i = 0; i < aAxes.length; ++i){
            var oCurAxis = aAxes[i];
            this.calcMajorMinorGridLines(oCurAxis, default_style, subtle_line, parent_objects);
            this.calcMajorMinorGridLines(oCurAxis, default_style, subtle_line, parent_objects);
        }
    }
};

CChartSpace.prototype.hitToAdjustment = function()
{
    return {hit: false};
};

CChartSpace.prototype.recalculateAxisLabels = function()
{
    if(this.chart && this.chart.title)
    {
        var title = this.chart.title;
        //title.parent = this.chart;
        title.chart = this;
        title.recalculate();
    }
    if(this.chart && this.chart.plotArea)
    {
        var aAxis = this.chart.plotArea.axId;
        for(var i = 0; i < aAxis.length; ++i){
            var title = aAxis[i].title;
            if(title){
                title.chart = this;
                title.recalculate();
            }
        }
    }
};


CChartSpace.prototype.updateLinks = function()
{
    //Этот метод нужен, т. к. мы не полностью поддерживаем формат в котором в одном plotArea может быть несколько разных диаграмм(конкретных типов).
    // Здесь мы берем первую из диаграмм лежащих в массиве plotArea.charts, а также выставляем ссылки для осей ;
    if(this.chart && this.chart.plotArea)
    {
        var oCheckChart;
        var oPlotArea = this.chart.plotArea;
        var aCharts = oPlotArea.charts;

        this.chart.plotArea.chart = aCharts[0];
        for(var i = 0; i < aCharts.length; ++i){
            if(aCharts[i].getObjectType() !== AscDFH.historyitem_type_PieChart && aCharts[i].getObjectType() !== AscDFH.historyitem_type_DoughnutChart){
                oCheckChart = aCharts[i];
                break;
            }
        }

        if(oCheckChart){

            this.chart.plotArea.chart = oCheckChart;
            this.chart.plotArea.serAx = null;
            if(oCheckChart.getAxisByTypes)
            {
                var axis_by_types = oCheckChart.getAxisByTypes();
                if(axis_by_types.valAx.length > 0 && axis_by_types.catAx.length > 0)
                {
                    for(var i = 0; i < axis_by_types.valAx.length; ++i)
                    {
                        if(axis_by_types.valAx[i].crossAx)
                        {
                            for(var j = 0; j < axis_by_types.catAx.length; ++j)
                            {
                                if(axis_by_types.catAx[j] === axis_by_types.valAx[i].crossAx)
                                {
                                    this.chart.plotArea.valAx = axis_by_types.valAx[i];
                                    this.chart.plotArea.catAx = axis_by_types.catAx[j];
                                    break;
                                }
                            }
                            if(j < axis_by_types.catAx.length)
                            {
                                break;
                            }
                        }
                    }
                    if(i ===  axis_by_types.valAx.length)
                    {
                        this.chart.plotArea.valAx = axis_by_types.valAx[0];
                        this.chart.plotArea.catAx = axis_by_types.catAx[0];
                    }
                    if(this.chart.plotArea.valAx && this.chart.plotArea.catAx)
                    {
                        for(i = 0; i < axis_by_types.serAx.length; ++i)
                        {
                            if(axis_by_types.serAx[i].crossAx === this.chart.plotArea.valAx)
                            {
                                this.chart.plotArea.serAx = axis_by_types.serAx[i];
                                break;
                            }
                        }
                    }
                }
                else
                {
                    if(axis_by_types.valAx.length > 1)
                    {//TODO: выставлять оси исходя из настроек
                        this.chart.plotArea.valAx = axis_by_types.valAx[1];
                        this.chart.plotArea.catAx = axis_by_types.valAx[0];
                    }
                }
            }
            else
            {
                this.chart.plotArea.valAx = null;
                this.chart.plotArea.catAx = null;
            }
        }
    }
};

CChartSpace.prototype.draw = function(graphics)
{
    if(this.checkNeedRecalculate && this.checkNeedRecalculate()){
        return;
    }
    if(graphics.IsSlideBoundsCheckerType)
    {
        graphics.transform3(this.transform);
        graphics._s();
        graphics._m(0, 0);
        graphics._l(this.extX, 0);
        graphics._l(this.extX, this.extY);
        graphics._l(0, this.extY);
        graphics._e();
        return;
    }
    if(graphics.updatedRect)
    {
        var rect = graphics.updatedRect;
        var bounds = this.bounds;
        if(bounds.x > rect.x + rect.w
            || bounds.y > rect.y + rect.h
            || bounds.x + bounds.w < rect.x
            || bounds.y + bounds.h < rect.y)
            return;
    }
    graphics.SaveGrState();
    graphics.SetIntegerGrid(false);
    graphics.transform3(this.transform, false);

    var ln_width;
    if(this.pen && AscFormat.isRealNumber(this.pen.w))
    {
        ln_width = this.pen.w/36000;
    }
    else
    {
        ln_width = 0;
    }
    graphics.AddClipRect(-ln_width, -ln_width, this.extX+2*ln_width, this.extY+2*ln_width);

    if(this.chartObj)
    {
        this.chartObj.draw(this, graphics);
    }
    if(this.chart && !this.bEmptySeries)
    {
        if(this.chart.plotArea)
        {
            // var oChartSize = this.getChartSizes();
            // graphics.p_width(70);
            // graphics.p_color(0, 0, 0, 255);
            // graphics._s();
            // graphics._m(oChartSize.startX, oChartSize.startY);
            // graphics._l(oChartSize.startX + oChartSize.w, oChartSize.startY + 0);
            // graphics._l(oChartSize.startX + oChartSize.w, oChartSize.startY + oChartSize.h);
            // graphics._l(oChartSize.startX + 0, oChartSize.startY + oChartSize.h);
            // graphics._z();
            // graphics.ds();
            var aCharts = this.chart.plotArea.charts;
            for(var t = 0; t < aCharts.length; ++t){
                var oChart = aCharts[t];
                if(oChart && oChart.series)
                {
                    var series = oChart.series;
                    var _len = oChart.getObjectType() === AscDFH.historyitem_type_PieChart ? 1 : series.length;
                    for(var i = 0; i < _len; ++i)
                    {
                        var ser = series[i];
                        var pts = AscFormat.getPtsFromSeries(ser);
                        for(var j = 0; j < pts.length; ++j)
                        {
                            if(pts[j].compiledDlb)
                                pts[j].compiledDlb.draw(graphics);
                        }
                    }
                }
            }
            for(var  i = 0; i < this.chart.plotArea.axId.length; ++i){
                var oAxis = this.chart.plotArea.axId[i];
                if(oAxis.title){
                    oAxis.title.draw(graphics);
                }
                if(oAxis.labels){
                    oAxis.labels.draw(graphics);
                }
            }
        }
        if(this.chart.title)
        {
            this.chart.title.draw(graphics);
        }
        if(this.chart.legend)
        {
            this.chart.legend.draw(graphics);
        }
    }
    graphics.RestoreGrState();
    if(this.drawLocks(this.transform, graphics)){
        graphics.RestoreGrState();
    }
};

CChartSpace.prototype.addToSetPosition = function(dLbl)
{
    if(dLbl instanceof AscFormat.CDLbl)
        this.recalcInfo.dataLbls.push(dLbl);
    else if(dLbl instanceof AscFormat.CTitle)
        this.recalcInfo.axisLabels.push(dLbl);
};

CChartSpace.prototype.recalculateChart = function()
{
    this.pathMemory.curPos = -1;
    if(this.chartObj == null)
        this.chartObj =  new AscFormat.CChartsDrawer();
    this.chartObj.recalculate(this);
};



CChartSpace.prototype.GetRevisionsChangeParagraph = function(SearchEngine){
    var titles = this.getAllTitles(), i;
    if(titles.length === 0){
        return;
    }
    var oSelectedTitle = this.selection.title || this.selection.textSelection;
    if(oSelectedTitle){
        for(i = 0; i < titles.length; ++i){
            if(oSelectedTitle === titles[i]){
                break;
            }
        }
        if(i === titles.length){
            return;
        }
    }
    else{
        if(SearchEngine.Get_Direction() > 0){
            i = 0;
        }
        else{
            i = titles.length - 1;
        }
    }
    while(!SearchEngine.Is_Found()){
        titles[i].GetRevisionsChangeParagraph(SearchEngine);
        if(SearchEngine.Get_Direction() > 0){
            if(i === titles.length - 1){
                break;
            }
            ++i;
        }
        else{
            if(i === 0){
                break;
            }
            --i;
        }
    }
};

CChartSpace.prototype.Search  = function(Str, Props, SearchEngine, Type)
{
    var titles = this.getAllTitles();
    for(var i = 0; i < titles.length; ++i)
    {
        titles[i].Search(Str, Props, SearchEngine, Type)
    }
};

CChartSpace.prototype.Search_GetId  = function(bNext, bCurrent)
{
    var Current = -1;
    var titles = this.getAllTitles();
    var Len = titles.length;

    var Id = null;
    if ( true === bCurrent )
    {
        for(var i = 0; i < Len; ++i)
        {
            if(titles[i] === this.selection.textSelection)
            {
                Current = i;
                break;
            }
        }
    }

    if ( true === bNext )
    {
        var Start = ( -1 !== Current ? Current : 0 );

        for ( var i = Start; i < Len; i++ )
        {
            if ( titles[i].Search_GetId )
            {
                Id = titles[i].Search_GetId(true, i === Current ? true : false);
                if ( null !== Id )
                    return Id;
            }
        }
    }
    else
    {
        var Start = ( -1 !== Current ? Current : Len - 1 );

        for ( var i = Start; i >= 0; i-- )
        {
            if (titles[i].Search_GetId )
            {
                Id = titles[i].Search_GetId(false, i === Current ? true : false);
                if ( null !== Id )
                    return Id;
            }
        }
    }
    return null;
};
    
function getPtsFromSeries(ser)
{
    if(ser)
    {
        if(ser.val)
        {
            if(ser.val.numRef && ser.val.numRef.numCache)
                return ser.val.numRef.numCache.pts;
            else if(ser.val.numLit)
                return ser.val.numLit.pts;
        }
        else if(ser.yVal)
        {
            if(ser.yVal.numRef && ser.yVal.numRef.numCache)
                return ser.yVal.numRef.numCache.pts;
            else if(ser.yVal.numLit)
                return ser.yVal.numLit.pts;
        }
    }
    return [];
}
    
function getCatStringPointsFromSeries(ser)
{
    if(!ser){
        return null;
    }
    return getStringPointsFromCat(ser.cat);
}

function getStringPointsFromCat(oCat){
    if(oCat){
        if(oCat.strRef && oCat.strRef.strCache)
        {
            return oCat.strRef.strCache;
        }
        else if(oCat.strLit)
        {
            return oCat.strLit;
        }
    }
    return null;
}

function getMaxIdx(arr)
{
    var max_idx = 0;
    for(var i = 0; i < arr.length;++i)
        arr[i].idx > max_idx && (max_idx = arr[i].idx);
    return max_idx+1;
}
    
function getArrayFillsFromBase(arrBaseFills, needFillsCount)
{
    var ret = [];
    var nMaxCycleIdx = parseInt((needFillsCount - 1)/arrBaseFills.length);
    for(var i = 0;  i <  needFillsCount; ++i)
    {
        var nCycleIdx = ( i / arrBaseFills.length ) >> 0;
        var fShadeTint = ( nCycleIdx + 1 ) / (nMaxCycleIdx + 2) * 1.4 - 0.7;

        if(fShadeTint < 0)
        {
            fShadeTint = -(1 + fShadeTint);
        }
        else
        {
            fShadeTint = (1 - fShadeTint);
        }
        var color = CreateUniFillSolidFillWidthTintOrShade(arrBaseFills[i % arrBaseFills.length], fShadeTint);
        ret.push(color);
    }
    return ret;
}

function GetTypeMarkerByIndex(index)
{
    return AscFormat.MARKER_SYMBOL_TYPE[index % 9];
}

function CreateUnfilFromRGB(r, g, b)
{
    var ret =  new AscFormat.CUniFill();
    ret.setFill(new AscFormat.CSolidFill());
    ret.fill.setColor(new AscFormat.CUniColor());
    ret.fill.color.setColor(new AscFormat.CRGBColor());
    ret.fill.color.color.setColor(r, g, b);
    return ret;
}

function CreateColorMapByIndex(index)
{
    var ret = [];
    switch(index)
    {
        case 1:
        {
            ret.push(CreateUnfilFromRGB(85, 85, 85));
            ret.push(CreateUnfilFromRGB(158, 158, 158));
            ret.push(CreateUnfilFromRGB(114, 114, 114));
            ret.push(CreateUnfilFromRGB(70, 70, 70));
            ret.push(CreateUnfilFromRGB(131, 131, 131));
            ret.push(CreateUnfilFromRGB(193, 193, 193));
            break;
        }
        case 2:
        {
            for(var i = 0;  i < 6; ++i)
            {
                ret.push(CreateUnifillSolidFillSchemeColorByIndex(i));
            }
            break;
        }
        default:
        {
            ret.push(CreateUnifillSolidFillSchemeColorByIndex(index - 3));
            break;
        }
    }
    return ret;
}


function CreateUniFillSolidFillWidthTintOrShade(unifill, effectVal)
{
    var ret = unifill.createDuplicate();
    var unicolor = ret.fill.color;
    if(effectVal !== 0)
    {
        effectVal*=100000.0;
        if(!unicolor.Mods)
            unicolor.setMods(new AscFormat.CColorModifiers());
        var mod = new AscFormat.CColorMod();
        if(effectVal > 0)
        {
            mod.setName("tint");
            mod.setVal(effectVal);
        }
        else
        {
            mod.setName("shade");
            mod.setVal(Math.abs(effectVal));
        }
        unicolor.Mods.addMod(mod);
    }
    return ret;
}
    
function CreateUnifillSolidFillSchemeColor(colorId, tintOrShade)
{
    var unifill = new AscFormat.CUniFill();
    unifill.setFill(new AscFormat.CSolidFill());
    unifill.fill.setColor(new AscFormat.CUniColor());
    unifill.fill.color.setColor(new AscFormat.CSchemeColor());
    unifill.fill.color.color.setId(colorId);
    return CreateUniFillSolidFillWidthTintOrShade(unifill, tintOrShade);
}

function CreateNoFillLine()
{
    var ret = new AscFormat.CLn();
    ret.setFill(CreateNoFillUniFill());
    return ret;
}

function CreateNoFillUniFill()
{
    var ret = new AscFormat.CUniFill();
    ret.setFill(new AscFormat.CNoFill());
    return ret;
}

function CExternalData()
{
    this.autoUpdate = null;
    this.id  = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CExternalData.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_ExternalData;
    },

    setAutoUpdate: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_ExternalData_SetAutoUpdate, this.autoUpdate,  pr));
        this.autoUpdate = pr;
    },

    setId: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_ExternalData_SetId, this.id,  pr));
        this.id = pr;
    }
};

function CPivotSource()
{
    this.fmtId = null;
    this.name  = null;
    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CPivotSource.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_PivotSource;
    },
    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    },

    setFmtId: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_PivotSource_SetFmtId, this.fmtId,  pr));
        this.fmtId = pr;
    },

    setName: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_PivotSource_SetName, this.name,  pr));
        this.name = pr;
    },


    createDuplicate: function()
    {
        var copy = new CPivotSource();
        if(AscFormat.isRealNumber(this.fmtId))
        {
            copy.setFmtId(this.fmtId);
        }
        if(typeof  this.name === "string")
        {
            copy.setName(this.name);
        }
        return copy;
    }
};


function CProtection()
{
    this.chartObject   = null;
    this.data          = null;
    this.formatting    = null;
    this.selection     = null;
    this.userInterface = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CProtection.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_Protection;
    },
    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    },

    setChartObject: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_Protection_SetChartObject, this.chartObject, pr));
        this.chartObject = pr;
    },
    setData: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_Protection_SetData, this.data, pr));
        this.data = pr;
    },
    setFormatting: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_Protection_SetFormatting, this.formatting, pr));
        this.formatting = pr;
    },
    setSelection: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_Protection_SetSelection, this.selection, pr));
        this.selection = pr;
    },
    setUserInterface: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_Protection_SetUserInterface, this.userInterface, pr));
        this.userInterface = pr;
    },

    createDuplicate: function()
    {
        var c = new CProtection();
        if(this.chartObject !== null)
            c.setChartObject(this.chartObject);
        if(this.data !== null)
            c.setData(this.data);
        if(this.formatting !== null)
            c.setFormatting(this.formatting);
        if(this.selection !== null)
            c.setSelection(this.selection);
        if(this.userInterface !== null)
            c.setUserInterface(this.userInterface);
        return c;
    }
};


function CPrintSettings()
{
    this.headerFooter = null;
    this.pageMargins  = null;
    this.pageSetup    = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CPrintSettings.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    createDuplicate : function()
    {
        var oPS = new CPrintSettings();
        
        if ( this.headerFooter )
            oPS.setHeaderFooter(this.headerFooter.createDuplicate());
        
        if ( this.pageMargins )
            oPS.setPageMargins(this.pageMargins.createDuplicate());
        
        if ( this.pageSetup )
            oPS.setPageSetup(this.pageSetup.createDuplicate());
        
        return oPS;
    },

    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_PrintSettings;
    },

    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    },

    setHeaderFooter: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PrintSettingsSetHeaderFooter, this.headerFooter,  pr));
        this.headerFooter = pr;
    },
    setPageMargins: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PrintSettingsSetPageMargins, this.pageMargins,  pr));
        this.pageMargins = pr;
    },
    setPageSetup: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PrintSettingsSetPageSetup, this.pageSetup,  pr));
        this.pageSetup = pr;
    }
};


function CHeaderFooterChart()
{
    this.alignWithMargins = null;
    this.differentFirst   = null;
    this.differentOddEven = null;
    this.evenFooter       = null;
    this.evenHeader       = null;
    this.firstFooter      = null;
    this.firstHeader      = null;
    this.oddFooter        = null;
    this.oddHeader        = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CHeaderFooterChart.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    createDuplicate : function()
    {
        var oHFC = new CHeaderFooterChart();

        if(this.alignWithMargins !== null)
            oHFC.setAlignWithMargins(this.alignWithMargins);
        if(this.differentFirst !== null)
            oHFC.setDifferentFirst(this.differentFirst);

        if(this.differentOddEven !== null)
            oHFC.setDifferentOddEven(this.differentOddEven);

        if ( this.evenFooter !== null )
            oHFC.setEvenFooter(this.evenFooter);

        if ( this.evenHeader !== null)
            oHFC.setEvenHeader(this.evenHeader);

        if ( this.firstFooter !== null)
            oHFC.setFirstFooter(this.firstFooter);

        if ( this.firstHeader !== null)
            oHFC.setFirstHeader(this.firstHeader);

        if ( this.oddFooter !== null)
            oHFC.setOddFooter(this.oddFooter);

        if ( this.oddHeader !== null)
            oHFC.setOddHeader(this.oddHeader);

        return oHFC;
    },


    Refresh_RecalcData: function()
    {},

    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_HeaderFooterChart;
    },


    setAlignWithMargins: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_HeaderFooterChartSetAlignWithMargins, this.alignWithMargins,  pr));
        this.alignWithMargins = pr;
    },
    setDifferentFirst: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_HeaderFooterChartSetDifferentFirst, this.differentFirst,  pr));
        this.differentFirst = pr;
    },
    setDifferentOddEven: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_HeaderFooterChartSetDifferentOddEven, this.differentOddEven,  pr));
        this.differentOddEven = pr;
    },
    setEvenFooter: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_HeaderFooterChartSetEvenFooter, this.evenFooter,  pr));
        this.evenFooter = pr;
    },
    setEvenHeader: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_HeaderFooterChartSetEvenHeader, this.evenHeader,  pr));
        this.evenHeader = pr;
    },
    setFirstFooter: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_HeaderFooterChartSetFirstFooter, this.firstFooter,  pr));
        this.firstFooter = pr;
    },
    setFirstHeader: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_HeaderFooterChartSetFirstHeader, this.firstHeader,  pr));
        this.firstHeader = pr;
    },
    setOddFooter: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_HeaderFooterChartSetOddFooter, this.oddFooter,  pr));
        this.oddFooter = pr;
    },
    setOddHeader: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_HeaderFooterChartSetOddHeader, this.oddHeader,  pr));
        this.oddHeader = pr;
    }
};

function CPageMarginsChart()
{
    this.b      = null;
    this.footer = null;
    this.header = null;
    this.l      = null;
    this.r      = null;
    this.t      = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CPageMarginsChart.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    createDuplicate : function()
    {
        var oPMC = new CPageMarginsChart();

        if(this.b !== null)
            oPMC.setB(this.b);
        if(this.footer !== null)
            oPMC.setFooter(this.footer);
        if(this.header !== null)
            oPMC.setHeader(this.header);
        if(this.l !== null)
            oPMC.setL(this.l);
        if(this.r !== null)
            oPMC.setR(this.r);
        if(this.t !== null)
            oPMC.setT(this.t);

        return oPMC;
    },

    Refresh_RecalcData: function()
    {},

    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_PageMarginsChart;
    },

    setB: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_PageMarginsSetB, this.b,  pr));
        this.b = pr;
    },
    setFooter: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_PageMarginsSetFooter, this.footer,  pr));
        this.footer = pr;
    },
    setHeader: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_PageMarginsSetHeader, this.header,  pr));
        this.header = pr;
    },
    setL: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_PageMarginsSetL, this.l,  pr));
        this.l = pr;
    },
    setR: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_PageMarginsSetR, this.r,  pr));
        this.r = pr;
    },
    setT: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_PageMarginsSetT, this.t,  pr));
        this.t = pr;
    }
};

function CPageSetup()
{
    this.blackAndWhite     = null;
    this.copies            = null;
    this.draft             = null;
    this.firstPageNumber   = null;
    this.horizontalDpi     = null;
    this.orientation       = null;
    this.paperHeight       = null;
    this.paperSize         = null;
    this.paperWidth        = null;
    this.useFirstPageNumb  = null;
    this.verticalDpi       = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CPageSetup.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    
    createDuplicate : function()
    {
        var oPS = new CPageSetup();

        if(this.blackAndWhite !== null)
            oPS.setBlackAndWhite(this.blackAndWhite);
        if(this.copies !== null)
            oPS.setCopies(this.copies);
        if(this.draft !== null)
            oPS.setDraft(this.draft);
        if(this.firstPageNumber !== null)
            oPS.setFirstPageNumber(this.firstPageNumber);
        if(this.horizontalDpi !== null)
            oPS.setHorizontalDpi(this.horizontalDpi);
        if(this.orientation !== null)
            oPS.setOrientation(this.orientation);
        if(this.paperHeight !== null)
            oPS.setPaperHeight(this.paperHeight);
        if(this.paperSize !== null)
            oPS.setPaperSize(this.paperSize);
        if(this.paperWidth !== null)
            oPS.setPaperWidth(this.paperWidth);
        if(this.useFirstPageNumb !== null)
            oPS.setUseFirstPageNumb(this.useFirstPageNumb);
        if(this.verticalDpi !== null)
            oPS.setVerticalDpi(this.verticalDpi);
                
        return oPS;
    },

    Refresh_RecalcData: function()
    {},

    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_PageSetup;
    },
    setBlackAndWhite: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_PageSetupSetBlackAndWhite, this.blackAndWhite,  pr));
        this.blackAndWhite = pr;
    },
    setCopies: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_PageSetupSetCopies, this.copies,  pr));
        this.copies = pr;
    },
    setDraft: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_PageSetupSetDraft, this.draft,  pr));
        this.draft = pr;
    },
    setFirstPageNumber: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_PageSetupSetFirstPageNumber, this.firstPageNumber,  pr));
        this.firstPageNumber = pr;
    },
    setHorizontalDpi: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_PageSetupSetHorizontalDpi, this.horizontalDpi,  pr));
        this.horizontalDpi = pr;
    },
    setOrientation: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_PageSetupSetOrientation, this.orientation,  pr));
        this.orientation = pr;
    },
    setPaperHeight: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_PageSetupSetPaperHeight, this.paperHeight,  pr));
        this.paperHeight = pr;
    },
    setPaperSize: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_PageSetupSetPaperSize, this.paperSize,  pr));
        this.paperSize = pr;
    },
    setPaperWidth: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_PageSetupSetPaperWidth, this.paperWidth,  pr));
        this.paperWidth = pr;
    },
    setUseFirstPageNumb: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_PageSetupSetUseFirstPageNumb, this.useFirstPageNumb,  pr));
        this.useFirstPageNumb = pr;
    },
    setVerticalDpi: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_PageSetupSetVerticalDpi, this.verticalDpi,  pr));
        this.verticalDpi = pr;
    }
};


function CreateView3d(nRotX, nRotY, bRAngAx, nDepthPercent)
{
    var oView3d = new AscFormat.CView3d();
    AscFormat.isRealNumber(nRotX) && oView3d.setRotX(nRotX);
    AscFormat.isRealNumber(nRotY) && oView3d.setRotY(nRotY);
    AscFormat.isRealBool(bRAngAx) && oView3d.setRAngAx(bRAngAx);
    AscFormat.isRealNumber(nDepthPercent) && oView3d.setDepthPercent(nDepthPercent);
    return oView3d;
}

function GetNumFormatFromSeries(aAscSeries){
    if(aAscSeries &&
        aAscSeries[0] &&
        aAscSeries[0].Val &&
        aAscSeries[0].Val.NumCache &&
        aAscSeries[0].Val.NumCache[0]){
        if(typeof (aAscSeries[0].Val.NumCache[0].numFormatStr) === "string" && aAscSeries[0].Val.NumCache[0].numFormatStr.length > 0){
            return aAscSeries[0].Val.NumCache[0].numFormatStr;
        }
    }
    return "General";
}


function FillCatAxNumFormat(oCatAxis, aAscSeries){
    if(!oCatAxis){
        return;
    }
    var sFormatCode = null;
    if(aAscSeries &&
        aAscSeries[0] &&
        aAscSeries[0].Cat &&
        aAscSeries[0].Cat.NumCache &&
        aAscSeries[0].Cat.NumCache[0]){
        if(typeof (aAscSeries[0].Cat.NumCache[0].numFormatStr) === "string" && aAscSeries[0].Cat.NumCache[0].numFormatStr.length > 0){
            sFormatCode = aAscSeries[0].Cat.NumCache[0].numFormatStr;
        }
    }
    if(sFormatCode){
        oCatAxis.setNumFmt(new AscFormat.CNumFmt());
        oCatAxis.numFmt.setFormatCode(sFormatCode ? sFormatCode : "General");
        oCatAxis.numFmt.setSourceLinked(true);
    }
}

function CreateLineChart(chartSeries, type, bUseCache, oOptions, b3D)
{
    var asc_series = chartSeries.series;
    var chart_space = new CChartSpace();
    chart_space.setDate1904(false);
    chart_space.setLang("en-US");
    chart_space.setRoundedCorners(false);
    chart_space.setChart(new AscFormat.CChart());
    chart_space.setPrintSettings(new CPrintSettings());
    var chart = chart_space.chart;
    if(b3D)
    {
        chart.setView3D(CreateView3d(15, 20, true, 100));
        chart.setDefaultWalls();
    }
    chart.setAutoTitleDeleted(false);
    chart.setPlotArea(new AscFormat.CPlotArea());
    chart.setPlotVisOnly(true);
    var disp_blanks_as;
    if(type === AscFormat.GROUPING_STANDARD)
    {
        disp_blanks_as = DISP_BLANKS_AS_GAP;
    }
    else
    {
        disp_blanks_as = DISP_BLANKS_AS_ZERO;
    }
    chart.setDispBlanksAs(disp_blanks_as);
    chart.setShowDLblsOverMax(false);
    var plot_area = chart.plotArea;
    plot_area.setLayout(new AscFormat.CLayout());
    plot_area.addChart(new AscFormat.CLineChart());

    var cat_ax = new AscFormat.CCatAx();
    var val_ax = new AscFormat.CValAx();
    cat_ax.setAxId(++Ax_Counter.GLOBAL_AX_ID_COUNTER);
    val_ax.setAxId(++Ax_Counter.GLOBAL_AX_ID_COUNTER);
    cat_ax.setCrossAx(val_ax);
    val_ax.setCrossAx(cat_ax);

    plot_area.addAxis(cat_ax);
    plot_area.addAxis(val_ax);

    var line_chart = plot_area.charts[0];
    line_chart.setGrouping(type);
    line_chart.setVaryColors(false);
    line_chart.setMarker(true);
    line_chart.setSmooth(false);
    line_chart.addAxId(cat_ax);
    line_chart.addAxId(val_ax);
    val_ax.setCrosses(2);
    var parsedHeaders = chartSeries.parsedHeaders;
    var bInCols;
    if(isRealObject(oOptions))
    {
        bInCols = oOptions.inColumns === true;
    }
    else
    {
        bInCols = false;
    }
    for(var i = 0; i < asc_series.length; ++i)
    {
        var series = new AscFormat.CLineSeries();
        series.setIdx(i);
        series.setOrder(i);
        series.setMarker(new AscFormat.CMarker());
        series.marker.setSymbol(AscFormat.SYMBOL_NONE);
        series.setSmooth(false);
        series.setVal(new AscFormat.CYVal());
        FillValNum(series.val, asc_series[i].Val, bUseCache);
        if(parsedHeaders.bTop && !bInCols || bInCols && parsedHeaders.bLeft)
        {
            series.setCat(new AscFormat.CCat());
            FillCatStr(series.cat, asc_series[i].Cat, bUseCache);
        }
        if((parsedHeaders.bLeft && !bInCols || bInCols && parsedHeaders.bTop) && asc_series[i].TxCache && typeof asc_series[i].TxCache.Formula === "string" && asc_series[i].TxCache.Formula.length > 0)
        {
            FillSeriesTx(series, asc_series[i].TxCache, bUseCache);
        }
        line_chart.addSer(series);
    }
    cat_ax.setScaling(new AscFormat.CScaling());
    cat_ax.setDelete(false);
    cat_ax.setAxPos(AscFormat.AX_POS_B);
    cat_ax.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    cat_ax.setMinorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    cat_ax.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
    cat_ax.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    cat_ax.setAuto(true);
    cat_ax.setLblAlgn(AscFormat.LBL_ALG_CTR);
    cat_ax.setLblOffset(100);
    cat_ax.setNoMultiLvlLbl(false);
    var scaling = cat_ax.scaling;
    scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
    FillCatAxNumFormat(cat_ax, asc_series);
    val_ax.setScaling(new AscFormat.CScaling());
    val_ax.setDelete(false);
    val_ax.setAxPos(AscFormat.AX_POS_L);
    val_ax.setMajorGridlines(new AscFormat.CSpPr());
    val_ax.setNumFmt(new AscFormat.CNumFmt());
    val_ax.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    val_ax.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
    val_ax.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
    val_ax.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    val_ax.setCrossBetween(AscFormat.CROSS_BETWEEN_BETWEEN);
    scaling = val_ax.scaling;
    scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
    var num_fmt = val_ax.numFmt;
    var format_code;
    if(type === AscFormat.GROUPING_PERCENT_STACKED)
    {
        format_code = "0%";
    }
    else
    {
        format_code = GetNumFormatFromSeries(asc_series);
    }
    num_fmt.setFormatCode(format_code);
    num_fmt.setSourceLinked(true);


    if(asc_series.length > 1)
    {
        chart.setLegend(new AscFormat.CLegend());
        var legend = chart.legend;
        legend.setLegendPos(c_oAscChartLegendShowSettings.right);
        legend.setLayout(new AscFormat.CLayout());
        legend.setOverlay(false);
    }


    var print_settings = chart_space.printSettings;
    print_settings.setHeaderFooter(new CHeaderFooterChart());
    print_settings.setPageMargins(new CPageMarginsChart());
    print_settings.setPageSetup(new CPageSetup());
    var page_margins = print_settings.pageMargins;
    page_margins.setB(0.75);
    page_margins.setL(0.7);
    page_margins.setR(0.7);
    page_margins.setT(0.75);
    page_margins.setHeader(0.3);
    page_margins.setFooter(0.3);
    return chart_space;
}

function CreateBarChart(chartSeries, type, bUseCache, oOptions, b3D, bDepth)
{
    var asc_series = chartSeries.series;
    var chart_space = new CChartSpace();
    chart_space.setDate1904(false);
    chart_space.setLang("en-US");
    chart_space.setRoundedCorners(false);
    chart_space.setChart(new AscFormat.CChart());
    chart_space.setPrintSettings(new CPrintSettings());
    var chart = chart_space.chart;
    chart.setAutoTitleDeleted(false);
    if(b3D)
    {
        chart.setView3D(CreateView3d(15, 20, true, bDepth ? 100 : undefined));
        chart.setDefaultWalls();
    }
    chart.setPlotArea(new AscFormat.CPlotArea());
    chart.setPlotVisOnly(true);
    chart.setDispBlanksAs(DISP_BLANKS_AS_GAP);
    chart.setShowDLblsOverMax(false);
    var plot_area = chart.plotArea;
    plot_area.setLayout(new AscFormat.CLayout());
    plot_area.addChart(new AscFormat.CBarChart());

    var bInCols;
    if(isRealObject(oOptions))
    {
        bInCols = oOptions.inColumns === true;
    }
    else
    {
        bInCols = false;
    }


    var cat_ax = new AscFormat.CCatAx();
    var val_ax = new AscFormat.CValAx();
    cat_ax.setAxId(++Ax_Counter.GLOBAL_AX_ID_COUNTER);
    val_ax.setAxId(++Ax_Counter.GLOBAL_AX_ID_COUNTER);
    cat_ax.setCrossAx(val_ax);
    val_ax.setCrossAx(cat_ax);

    plot_area.addAxis(cat_ax);
    plot_area.addAxis(val_ax);

    var bar_chart = plot_area.charts[0];
    if(b3D)
    {
        bar_chart.set3D(true);
    }
    bar_chart.setBarDir(AscFormat.BAR_DIR_COL);
    bar_chart.setGrouping(type);
    bar_chart.setVaryColors(false);
    var parsedHeaders = chartSeries.parsedHeaders;
    for(var i = 0; i < asc_series.length; ++i)
    {
        var series = new AscFormat.CBarSeries();
        series.setIdx(i);
        series.setOrder(i);
        series.setInvertIfNegative(false);
        series.setVal(new AscFormat.CYVal());
        FillValNum(series.val, asc_series[i].Val, bUseCache);
        if(parsedHeaders.bTop && !bInCols || bInCols && parsedHeaders.bLeft)
        {
            series.setCat(new AscFormat.CCat());
            FillCatStr(series.cat, asc_series[i].Cat, bUseCache);
        }
        if((parsedHeaders.bLeft && !bInCols || bInCols && parsedHeaders.bTop) && asc_series[i].TxCache && typeof asc_series[i].TxCache.Formula === "string" && asc_series[i].TxCache.Formula.length > 0)
        {
            FillSeriesTx(series, asc_series[i].TxCache, bUseCache);
        }
        bar_chart.addSer(series);
    }
    bar_chart.setGapWidth(150);
    if(AscFormat.BAR_GROUPING_PERCENT_STACKED === type || AscFormat.BAR_GROUPING_STACKED === type)
        bar_chart.setOverlap(100);
    if(b3D)
    {
        bar_chart.setShape(BAR_SHAPE_BOX);
    }
    bar_chart.addAxId(cat_ax);
    bar_chart.addAxId(val_ax);
    cat_ax.setScaling(new AscFormat.CScaling());
    cat_ax.setDelete(false);
    cat_ax.setAxPos(AscFormat.AX_POS_B);
    cat_ax.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    cat_ax.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
    cat_ax.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    cat_ax.setAuto(true);
    cat_ax.setLblAlgn(AscFormat.LBL_ALG_CTR);
    cat_ax.setLblOffset(100);
    cat_ax.setNoMultiLvlLbl(false);
    var scaling = cat_ax.scaling;
    scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
    FillCatAxNumFormat(cat_ax, asc_series);
    val_ax.setScaling(new AscFormat.CScaling());
    val_ax.setDelete(false);
    val_ax.setAxPos(AscFormat.AX_POS_L);
    val_ax.setMajorGridlines(new AscFormat.CSpPr());
    val_ax.setNumFmt(new AscFormat.CNumFmt());
    var num_fmt = val_ax.numFmt;
    var format_code;
    if(type === AscFormat.BAR_GROUPING_PERCENT_STACKED)
    {
        format_code = "0%";
    }
    else
    {
        format_code = GetNumFormatFromSeries(asc_series);
    }
    num_fmt.setFormatCode(format_code);
    num_fmt.setSourceLinked(true);
    val_ax.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    val_ax.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
    val_ax.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
    val_ax.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    val_ax.setCrossBetween(AscFormat.CROSS_BETWEEN_BETWEEN);
    scaling = val_ax.scaling;
    scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
    if(asc_series.length > 1)
    {
        chart.setLegend(new AscFormat.CLegend());
        var legend = chart.legend;
        legend.setLegendPos(c_oAscChartLegendShowSettings.right);
        legend.setLayout(new AscFormat.CLayout());
        legend.setOverlay(false);
    }
    var print_settings = chart_space.printSettings;
    print_settings.setHeaderFooter(new CHeaderFooterChart());
    print_settings.setPageMargins(new CPageMarginsChart());
    print_settings.setPageSetup(new CPageSetup());
    var page_margins = print_settings.pageMargins;
    page_margins.setB(0.75);
    page_margins.setL(0.7);
    page_margins.setR(0.7);
    page_margins.setT(0.75);
    page_margins.setHeader(0.3);
    page_margins.setFooter(0.3);
    return chart_space;
}

function CreateHBarChart(chartSeries, type, bUseCache, oOptions, b3D)
{
    var asc_series = chartSeries.series;
    var chart_space = new CChartSpace();
    chart_space.setDate1904(false);
    chart_space.setLang("en-US");
    chart_space.setRoundedCorners(false);
    chart_space.setChart(new AscFormat.CChart());
    chart_space.setPrintSettings(new CPrintSettings());
    var chart = chart_space.chart;
    chart.setAutoTitleDeleted(false);
    if(b3D)
    {
        chart.setView3D(CreateView3d(15, 20, true, undefined));
        chart.setDefaultWalls();
    }
    chart.setPlotArea(new AscFormat.CPlotArea());
    chart.setPlotVisOnly(true);
    chart.setDispBlanksAs(DISP_BLANKS_AS_GAP);
    chart.setShowDLblsOverMax(false);
    var plot_area = chart.plotArea;
    plot_area.setLayout(new AscFormat.CLayout());
    plot_area.addChart(new AscFormat.CBarChart());


    var cat_ax = new AscFormat.CCatAx();
    var val_ax = new AscFormat.CValAx();
    cat_ax.setAxId(++Ax_Counter.GLOBAL_AX_ID_COUNTER);
    val_ax.setAxId(++Ax_Counter.GLOBAL_AX_ID_COUNTER);
    cat_ax.setCrossAx(val_ax);
    val_ax.setCrossAx(cat_ax);

    plot_area.addAxis(cat_ax);
    plot_area.addAxis(val_ax);

    var bar_chart = plot_area.charts[0];
    bar_chart.setBarDir(AscFormat.BAR_DIR_BAR);
    bar_chart.setGrouping(type);
    bar_chart.setVaryColors(false);
    var parsedHeaders = chartSeries.parsedHeaders;

    var bInCols;
    if(isRealObject(oOptions))
    {
        bInCols = oOptions.inColumns === true;
    }
    else
    {
        bInCols = false;
    }

    for(var i = 0; i < asc_series.length; ++i)
    {
        var series = new AscFormat.CBarSeries();
        series.setIdx(i);
        series.setOrder(i);
        series.setInvertIfNegative(false);
        series.setVal(new AscFormat.CYVal());
        FillValNum(series.val, asc_series[i].Val, bUseCache);
        if((parsedHeaders.bTop && !bInCols || bInCols && parsedHeaders.bLeft))
        {
            series.setCat(new AscFormat.CCat());
            FillCatStr(series.cat, asc_series[i].Cat, bUseCache);
        }
        if((parsedHeaders.bLeft && !bInCols || bInCols && parsedHeaders.bTop) && asc_series[i].TxCache && typeof asc_series[i].TxCache.Formula === "string" && asc_series[i].TxCache.Formula.length > 0)
        {
            FillSeriesTx(series, asc_series[i].TxCache, bUseCache);
        }
        bar_chart.addSer(series);
        if(b3D)
        {
            bar_chart.setShape(BAR_SHAPE_BOX);
        }
    }
    //bar_chart.setDLbls(new CDLbls());
    //var d_lbls = bar_chart.dLbls;
    //d_lbls.setShowLegendKey(false);
    //d_lbls.setShowVal(true);
    bar_chart.setGapWidth(150);
    if(AscFormat.BAR_GROUPING_PERCENT_STACKED === type || AscFormat.BAR_GROUPING_STACKED === type)
        bar_chart.setOverlap(100);
    bar_chart.addAxId(cat_ax);
    bar_chart.addAxId(val_ax);
    cat_ax.setScaling(new AscFormat.CScaling());
    cat_ax.setDelete(false);
    cat_ax.setAxPos(AscFormat.AX_POS_L);
    cat_ax.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    cat_ax.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
    cat_ax.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
    cat_ax.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    cat_ax.setAuto(true);
    cat_ax.setLblAlgn(AscFormat.LBL_ALG_CTR);
    cat_ax.setLblOffset(100);
    cat_ax.setNoMultiLvlLbl(false);
    var scaling = cat_ax.scaling;
    scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
    FillCatAxNumFormat(cat_ax, asc_series);
    val_ax.setScaling(new AscFormat.CScaling());
    val_ax.setDelete(false);
    val_ax.setAxPos(AscFormat.AX_POS_B);
    val_ax.setMajorGridlines(new AscFormat.CSpPr());
    val_ax.setNumFmt(new AscFormat.CNumFmt());
    val_ax.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    val_ax.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
    val_ax.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
    val_ax.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    val_ax.setCrossBetween(AscFormat.CROSS_BETWEEN_BETWEEN);
    scaling = val_ax.scaling;
    scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
    var num_fmt = val_ax.numFmt;
    var format_code;
    /*if(type === GROUPING_PERCENT_STACKED)
     {
     format_code = "0%";
     }
     else */
    {
        format_code = GetNumFormatFromSeries(asc_series);
    }
    num_fmt.setFormatCode(format_code);
    num_fmt.setSourceLinked(true);

    if(asc_series.length > 1)
    {
        chart.setLegend(new AscFormat.CLegend());
        var legend = chart.legend;
        legend.setLegendPos(c_oAscChartLegendShowSettings.right);
        legend.setLayout(new AscFormat.CLayout());
        legend.setOverlay(false);
    }
    var print_settings = chart_space.printSettings;
    print_settings.setHeaderFooter(new CHeaderFooterChart());
    print_settings.setPageMargins(new CPageMarginsChart());
    print_settings.setPageSetup(new CPageSetup());
    var page_margins = print_settings.pageMargins;
    page_margins.setB(0.75);
    page_margins.setL(0.7);
    page_margins.setR(0.7);
    page_margins.setT(0.75);
    page_margins.setHeader(0.3);
    page_margins.setFooter(0.3);
    return chart_space;
}

function CreateAreaChart(chartSeries, type, bUseCache, oOptions)
{
    var asc_series = chartSeries.series;
    var chart_space = new CChartSpace();
    chart_space.setDate1904(false);
    chart_space.setLang("en-US");
    chart_space.setRoundedCorners(false);
    chart_space.setChart(new AscFormat.CChart());
    chart_space.setPrintSettings(new CPrintSettings());
    var chart = chart_space.chart;
    chart.setAutoTitleDeleted(false);
    chart.setPlotArea(new AscFormat.CPlotArea());
    chart.setPlotVisOnly(true);
    chart.setDispBlanksAs(DISP_BLANKS_AS_ZERO);
    chart.setShowDLblsOverMax(false);
    var plot_area = chart.plotArea;
    plot_area.setLayout(new AscFormat.CLayout());
    plot_area.addChart(new AscFormat.CAreaChart());

    var cat_ax = new AscFormat.CCatAx();
    var val_ax = new AscFormat.CValAx();
    cat_ax.setAxId(++Ax_Counter.GLOBAL_AX_ID_COUNTER);
    val_ax.setAxId(++Ax_Counter.GLOBAL_AX_ID_COUNTER);
    cat_ax.setCrossAx(val_ax);
    val_ax.setCrossAx(cat_ax);

    plot_area.addAxis(cat_ax);
    plot_area.addAxis(val_ax);

    var bInCols;
    if(isRealObject(oOptions))
    {
        bInCols = oOptions.inColumns === true;
    }
    else
    {
        bInCols = false;
    }

    var area_chart = plot_area.charts[0];
    area_chart.setGrouping(type);
    area_chart.setVaryColors(false);
    var parsedHeaders = chartSeries.parsedHeaders;
    for(var i = 0; i < asc_series.length; ++i)
    {
        var series = new AscFormat.CAreaSeries();
        series.setIdx(i);
        series.setOrder(i);
        series.setVal(new AscFormat.CYVal());
        FillValNum(series.val, asc_series[i].Val, bUseCache);
        if(parsedHeaders.bTop && !bInCols || bInCols && parsedHeaders.bLeft)
        {
            series.setCat(new AscFormat.CCat());
            FillCatStr(series.cat, asc_series[i].Cat, bUseCache);
        }
        if((parsedHeaders.bLeft && !bInCols || bInCols && parsedHeaders.bTop) && asc_series[i].TxCache && typeof asc_series[i].TxCache.Formula === "string" && asc_series[i].TxCache.Formula.length > 0)
        {
            FillSeriesTx(series, asc_series[i].TxCache, bUseCache);
        }

        area_chart.addSer(series);
    }
    //area_chart.setDLbls(new CDLbls());
    area_chart.addAxId(cat_ax);
    area_chart.addAxId(val_ax);
    //var d_lbls = area_chart.dLbls;
    //d_lbls.setShowLegendKey(false);
    //d_lbls.setShowVal(true);
    cat_ax.setScaling(new AscFormat.CScaling());
    cat_ax.setDelete(false);
    cat_ax.setAxPos(AscFormat.AX_POS_B);
    cat_ax.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    cat_ax.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
    cat_ax.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
    cat_ax.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    cat_ax.setAuto(true);
    cat_ax.setLblAlgn(AscFormat.LBL_ALG_CTR);
    cat_ax.setLblOffset(100);
    cat_ax.setNoMultiLvlLbl(false);
    cat_ax.scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
    FillCatAxNumFormat(cat_ax, asc_series);
    val_ax.setScaling(new AscFormat.CScaling());
    val_ax.setDelete(false);
    val_ax.setAxPos(AscFormat.AX_POS_L);
    val_ax.setMajorGridlines(new AscFormat.CSpPr());
    val_ax.setNumFmt(new AscFormat.CNumFmt());
    val_ax.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    val_ax.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
    val_ax.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
    val_ax.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    val_ax.setCrossBetween(AscFormat.CROSS_BETWEEN_MID_CAT);
    var scaling = val_ax.scaling;
    scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
    var num_fmt = val_ax.numFmt;
    var format_code;
    if(type === AscFormat.GROUPING_PERCENT_STACKED)
    {
        format_code = "0%";
    }
    else
    {
        format_code = GetNumFormatFromSeries(asc_series);
    }
    num_fmt.setFormatCode(format_code);
    num_fmt.setSourceLinked(true);

    if(asc_series.length > 1)
    {
        chart.setLegend(new AscFormat.CLegend());
        var legend = chart.legend;
        legend.setLegendPos(c_oAscChartLegendShowSettings.right);
        legend.setLayout(new AscFormat.CLayout());
        legend.setOverlay(false);
    }
    var print_settings = chart_space.printSettings;
    print_settings.setHeaderFooter(new CHeaderFooterChart());
    print_settings.setPageMargins(new CPageMarginsChart());
    print_settings.setPageSetup(new CPageSetup());
    var page_margins = print_settings.pageMargins;
    page_margins.setB(0.75);
    page_margins.setL(0.7);
    page_margins.setR(0.7);
    page_margins.setT(0.75);
    page_margins.setHeader(0.3);
    page_margins.setFooter(0.3);
    return chart_space;
}

function CreatePieChart(chartSeries, bDoughnut, bUseCache, oOptions, b3D)
{
    var asc_series = chartSeries.series;
    var chart_space = new CChartSpace();
    chart_space.setDate1904(false);
    chart_space.setLang("en-US");
    chart_space.setRoundedCorners(false);
    chart_space.setStyle(2);
    chart_space.setChart(new AscFormat.CChart());
    var chart = chart_space.chart;
    chart.setAutoTitleDeleted(false);
    if(b3D)
    {
        chart.setView3D(CreateView3d(30, 0, true, 100));
        chart.setDefaultWalls();
    }
    chart.setPlotArea(new AscFormat.CPlotArea());
    var plot_area = chart.plotArea;
    plot_area.setLayout(new AscFormat.CLayout());
    plot_area.addChart(bDoughnut ? new AscFormat.CDoughnutChart() : new AscFormat.CPieChart());
    var pie_chart = plot_area.charts[0];
    pie_chart.setVaryColors(true);
    var parsedHeaders = chartSeries.parsedHeaders;
    var bInCols;
    if(isRealObject(oOptions))
    {
        bInCols = oOptions.inColumns === true;
    }
    else
    {
        bInCols = false;
    }
    for(var i = 0; i < asc_series.length; ++i)
    {
        var series = new AscFormat.CPieSeries();
        series.setIdx(i);
        series.setOrder(i);
        series.setVal(new AscFormat.CYVal());
        var val = series.val;
        FillValNum(series.val, asc_series[i].Val, bUseCache);
        if(parsedHeaders.bTop && !bInCols || bInCols && parsedHeaders.bLeft)
        {
            series.setCat(new AscFormat.CCat());
            FillCatStr(series.cat, asc_series[i].Cat, bUseCache);
        }
        if((parsedHeaders.bLeft && !bInCols || bInCols && parsedHeaders.bTop) && asc_series[i].TxCache && typeof asc_series[i].TxCache.Formula === "string" && asc_series[i].TxCache.Formula.length > 0)
        {
            FillSeriesTx(series, asc_series[i].TxCache, bUseCache);
        }

        pie_chart.addSer(series);
    }
    pie_chart.setFirstSliceAng(0);
    if(bDoughnut)
        pie_chart.setHoleSize(50);
    chart.setLegend(new AscFormat.CLegend());
    var legend = chart.legend;
    legend.setLegendPos(c_oAscChartLegendShowSettings.right);
    legend.setLayout(new AscFormat.CLayout());
    legend.setOverlay(false);
    chart.setPlotVisOnly(true);
    chart.setDispBlanksAs(DISP_BLANKS_AS_GAP);
    chart.setShowDLblsOverMax(false);
    chart_space.setPrintSettings(new CPrintSettings());
    var print_settings = chart_space.printSettings;
    print_settings.setHeaderFooter(new CHeaderFooterChart());
    print_settings.setPageMargins(new CPageMarginsChart());
    print_settings.setPageSetup(new CPageSetup());
    var page_margins = print_settings.pageMargins;
    page_margins.setB(0.75);
    page_margins.setL(0.7);
    page_margins.setR(0.7);
    page_margins.setT(0.75);
    page_margins.setHeader(0.3);
    page_margins.setFooter(0.3);
    return chart_space;
}

function FillCatStr(oCat, oCatCache, bUseCache, bFillCache)
{
    oCat.setStrRef(new AscFormat.CStrRef());
    var str_ref = oCat.strRef;
    str_ref.setF(oCatCache.Formula);
    if(bUseCache)
    {
        str_ref.setStrCache(new AscFormat.CStrCache());
        var str_cache = str_ref.strCache;
        var cat_num_cache = oCatCache.NumCache;
        str_cache.setPtCount(cat_num_cache.length);
        if(!(bFillCache === false))
        {

            for(var j = 0; j < cat_num_cache.length; ++j)
            {
                var string_pt = new AscFormat.CStringPoint();
                string_pt.setIdx(j);
                string_pt.setVal(cat_num_cache[j].val);
                str_cache.addPt(string_pt);
            }
        }
    }
}

function FillValNum(oVal, oValCache, bUseCache, bFillCache)
{
    oVal.setNumRef(new AscFormat.CNumRef());
    var num_ref = oVal.numRef;
    num_ref.setF(oValCache.Formula);
    if(bUseCache)
    {
        num_ref.setNumCache(new AscFormat.CNumLit());
        var num_cache = num_ref.numCache;
        num_cache.setPtCount(oValCache.NumCache.length);
        if(!(bFillCache === false))
        {
            for(var j = 0; j < oValCache.NumCache.length; ++j)
            {
                var pt = new AscFormat.CNumericPoint();
                pt.setIdx(j);
                pt.setFormatCode(oValCache.NumCache[j].numFormatStr);
                pt.setVal(oValCache.NumCache[j].val);
                num_cache.addPt(pt);
            }
        }
    }
}

function FillSeriesTx(oSeries, oTxCache, bUseCache, bFillCache)
{
    oSeries.setTx(new AscFormat.CTx());
    var tx= oSeries.tx;
    tx.setStrRef(new AscFormat.CStrRef());
    var str_ref = tx.strRef;
    str_ref.setF(oTxCache.Formula);
    if(bUseCache)
    {
        str_ref.setStrCache(new AscFormat.CStrCache());
        var str_cache = str_ref.strCache;
        str_cache.setPtCount(1);
        if(!(bFillCache === false))
        {
            str_cache.addPt(new AscFormat.CStringPoint());
            var pt = str_cache.pts[0];
            pt.setIdx(0);
            pt.setVal(oTxCache.Tx);
        }
    }
}


function CreateScatterChart(chartSeries, bUseCache, oOptions)
{
    var asc_series = chartSeries.series;
    var chart_space = new CChartSpace();
    chart_space.setDate1904(false);
    chart_space.setLang("en-US");
    chart_space.setRoundedCorners(false);
    chart_space.setStyle(2);
    chart_space.setChart(new AscFormat.CChart());
    var chart = chart_space.chart;
    chart.setAutoTitleDeleted(false);
    chart.setPlotArea(new AscFormat.CPlotArea());
    var plot_area = chart.plotArea;
    plot_area.setLayout(new AscFormat.CLayout());
    plot_area.addChart(new AscFormat.CScatterChart());
    var scatter_chart = plot_area.charts[0];
    scatter_chart.setScatterStyle(AscFormat.SCATTER_STYLE_MARKER);
    scatter_chart.setVaryColors(false);

    var bInCols;
    if(isRealObject(oOptions))
    {
        bInCols = oOptions.inColumns === true;
    }
    else
    {
        bInCols = false;
    }

    var parsedHeaders = chartSeries.parsedHeaders;

    var cat_ax = new AscFormat.CValAx();
    var val_ax = new AscFormat.CValAx();
    cat_ax.setAxId(++Ax_Counter.GLOBAL_AX_ID_COUNTER);
    val_ax.setAxId(++Ax_Counter.GLOBAL_AX_ID_COUNTER);
    cat_ax.setCrossAx(val_ax);
    val_ax.setCrossAx(cat_ax);
    plot_area.addAxis(cat_ax);
    plot_area.addAxis(val_ax);
    var oXVal;
    var first_series = null;
    var start_index = 0;
    var minus = 0;
    if(parsedHeaders.bTop && !bInCols || bInCols && parsedHeaders.bLeft)
    {
        oXVal = new AscFormat.CXVal();
        FillCatStr(oXVal, asc_series[0].xVal, bUseCache);
    }
    else
    {
        first_series = asc_series.length > 1 ? asc_series[0] : null;
        start_index = asc_series.length > 1 ? 1 : 0;
        minus = start_index === 1 ? 1 : 0;
        if(first_series)
        {
            oXVal = new AscFormat.CXVal();
            FillValNum(oXVal, first_series.Val, bUseCache);
        }
    }
    for(var i = start_index; i < asc_series.length; ++i)
    {
        var series = new AscFormat.CScatterSeries();
        series.setIdx(i - minus);
        series.setOrder(i - minus);
        if(oXVal)
        {
            series.setXVal(oXVal.createDuplicate());
        }
        series.setYVal(new AscFormat.CYVal());
        FillValNum(series.yVal, asc_series[i].Val, bUseCache);
        if((parsedHeaders.bLeft && !bInCols || bInCols && parsedHeaders.bTop) && asc_series[i].TxCache && typeof asc_series[i].TxCache.Formula === "string" && asc_series[i].TxCache.Formula.length > 0)
        {
            FillSeriesTx(series, asc_series[i].TxCache, bUseCache)
        }
        scatter_chart.addSer(series);
    }
    scatter_chart.addAxId(cat_ax);
    scatter_chart.addAxId(val_ax);
    cat_ax.setScaling(new AscFormat.CScaling());
    cat_ax.setDelete(false);
    cat_ax.setAxPos(AscFormat.AX_POS_B);
    cat_ax.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    cat_ax.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
    cat_ax.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
    cat_ax.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    cat_ax.scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
    val_ax.setScaling(new AscFormat.CScaling());
    val_ax.setDelete(false);
    val_ax.setAxPos(AscFormat.AX_POS_L);
    val_ax.setMajorGridlines(new AscFormat.CSpPr());
    val_ax.setNumFmt(new AscFormat.CNumFmt());
    val_ax.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    val_ax.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
    val_ax.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
    val_ax.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    val_ax.setCrossBetween(AscFormat.CROSS_BETWEEN_BETWEEN);
    var scaling = val_ax.scaling;
    scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
    var num_fmt = val_ax.numFmt;
    var format_code = GetNumFormatFromSeries(asc_series);
    num_fmt.setFormatCode(format_code);
    num_fmt.setSourceLinked(true);
    if(scatter_chart.series.length > 1)
    {
        chart.setLegend(new AscFormat.CLegend());
        var legend = chart.legend;
        legend.setLegendPos(c_oAscChartLegendShowSettings.right);
        legend.setLayout(new AscFormat.CLayout());
        legend.setOverlay(false);
    }
    chart_space.setPrintSettings(new CPrintSettings());
    var print_settings = chart_space.printSettings;
    print_settings.setHeaderFooter(new CHeaderFooterChart());
    print_settings.setPageMargins(new CPageMarginsChart());
    print_settings.setPageSetup(new CPageSetup());
    var page_margins = print_settings.pageMargins;
    page_margins.setB(0.75);
    page_margins.setL(0.7);
    page_margins.setR(0.7);
    page_margins.setT(0.75);
    page_margins.setHeader(0.3);
    page_margins.setFooter(0.3);
    return chart_space;
}

function CreateStockChart(chartSeries, bUseCache, oOptions)
{
    var asc_series = chartSeries.series;
    var chart_space = new CChartSpace();
    chart_space.setDate1904(false);
    chart_space.setLang("en-US");
    chart_space.setRoundedCorners(false);
    chart_space.setChart(new AscFormat.CChart());
    chart_space.setPrintSettings(new CPrintSettings());
    var chart = chart_space.chart;
    chart.setAutoTitleDeleted(false);
    chart.setPlotArea(new AscFormat.CPlotArea());
    chart.setLegend(new AscFormat.CLegend());
    chart.setPlotVisOnly(true);
    var disp_blanks_as;
    disp_blanks_as = DISP_BLANKS_AS_GAP;
    chart.setDispBlanksAs(disp_blanks_as);
    chart.setShowDLblsOverMax(false);
    var plot_area = chart.plotArea;
    plot_area.setLayout(new AscFormat.CLayout());
    plot_area.addChart(new AscFormat.CStockChart());

    var bInCols;
    if(isRealObject(oOptions))
    {
        bInCols = oOptions.inColumns === true;
    }
    else
    {
        bInCols = false;
    }


    var cat_ax = new AscFormat.CCatAx();
    var val_ax = new AscFormat.CValAx();
    cat_ax.setAxId(++Ax_Counter.GLOBAL_AX_ID_COUNTER);
    val_ax.setAxId(++Ax_Counter.GLOBAL_AX_ID_COUNTER);
    cat_ax.setCrossAx(val_ax);
    val_ax.setCrossAx(cat_ax);

    plot_area.addAxis(cat_ax);
    plot_area.addAxis(val_ax);

    var line_chart = plot_area.charts[0];
    line_chart.addAxId(cat_ax);
    line_chart.addAxId(val_ax);
    line_chart.setHiLowLines(new AscFormat.CSpPr());
    line_chart.setUpDownBars(new AscFormat.CUpDownBars());
    line_chart.upDownBars.setGapWidth(150);
    line_chart.upDownBars.setUpBars(new AscFormat.CSpPr());
    line_chart.upDownBars.setDownBars(new AscFormat.CSpPr());
    var parsedHeaders = chartSeries.parsedHeaders;
    for(var i = 0; i < asc_series.length; ++i)
    {
        var series = new AscFormat.CLineSeries();
        series.setIdx(i);
        series.setOrder(i);
        series.setMarker(new AscFormat.CMarker());
        series.setSpPr(new AscFormat.CSpPr());
        series.spPr.setLn(new AscFormat.CLn());
        series.spPr.ln.setW(28575);
        series.spPr.ln.setFill(CreateNoFillUniFill());
        series.marker.setSymbol(AscFormat.SYMBOL_NONE);
        series.setSmooth(false);
        series.setVal(new AscFormat.CYVal());
        var val = series.val;
        FillValNum(val, asc_series[i].Val, bUseCache);
        if((parsedHeaders.bTop && !bInCols || bInCols && parsedHeaders.bLeft))
        {
            series.setCat(new AscFormat.CCat());
            var cat = series.cat;
            if(typeof asc_series[i].Cat.formatCode === "string" && asc_series[i].Cat.formatCode.length > 0)
            {
                cat.setNumRef(new AscFormat.CNumRef());
                var num_ref = cat.numRef;
                num_ref.setF(asc_series[i].Cat.Formula);
                if(bUseCache)
                {
                    num_ref.setNumCache(new AscFormat.CNumLit());
                    var num_cache = num_ref.numCache;
                    var cat_num_cache = asc_series[i].Cat.NumCache;
                    num_cache.setPtCount(cat_num_cache.length);
                    num_cache.setFormatCode(asc_series[i].Cat.formatCode);
                    for(var j= 0; j < cat_num_cache.length; ++j)
                    {
                        var pt = new AscFormat.CNumericPoint();
                        pt.setIdx(j);
                        pt.setVal(cat_num_cache[j].val);
                        if(cat_num_cache[j].numFormatStr !== asc_series[i].Cat.formatCode)
                        {
                            pt.setFormatCode(cat_num_cache[j].numFormatStr);
                        }
                        num_cache.addPt(pt);
                    }
                }
            }
            else
            {
                FillCatStr(cat, asc_series[i].Cat, bUseCache);
            }

        }
        if((parsedHeaders.bLeft && !bInCols || bInCols && parsedHeaders.bTop) && asc_series[i].TxCache && typeof asc_series[i].TxCache.Formula === "string" && asc_series[i].TxCache.Formula.length > 0)
        {
            FillSeriesTx(series, asc_series[i].TxCache, bUseCache);
        }
        line_chart.addSer(series);
    }
    cat_ax.setScaling(new AscFormat.CScaling());
    cat_ax.setDelete(false);
    cat_ax.setAxPos(AscFormat.AX_POS_B);
    cat_ax.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    cat_ax.setMinorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    cat_ax.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
    cat_ax.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    cat_ax.setAuto(true);
    cat_ax.setLblAlgn(AscFormat.LBL_ALG_CTR);
    cat_ax.setLblOffset(100);
    cat_ax.setNoMultiLvlLbl(false);
    var scaling = cat_ax.scaling;
    scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
    val_ax.setScaling(new AscFormat.CScaling());
    val_ax.setDelete(false);
    val_ax.setAxPos(AscFormat.AX_POS_L);
    val_ax.setMajorGridlines(new AscFormat.CSpPr());
    val_ax.setNumFmt(new AscFormat.CNumFmt());
    val_ax.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    val_ax.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
    val_ax.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
    val_ax.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    val_ax.setCrossBetween(AscFormat.CROSS_BETWEEN_BETWEEN);
    scaling = val_ax.scaling;
    scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
    var num_fmt = val_ax.numFmt;
    var format_code;
    format_code = GetNumFormatFromSeries(asc_series);
    num_fmt.setFormatCode(format_code);
    num_fmt.setSourceLinked(true);
    var legend = chart.legend;
    legend.setLegendPos(c_oAscChartLegendShowSettings.right);
    legend.setLayout(new AscFormat.CLayout());
    legend.setOverlay(false);
    var print_settings = chart_space.printSettings;
    print_settings.setHeaderFooter(new CHeaderFooterChart());
    print_settings.setPageMargins(new CPageMarginsChart());
    print_settings.setPageSetup(new CPageSetup());
    var page_margins = print_settings.pageMargins;
    page_margins.setB(0.75);
    page_margins.setL(0.7);
    page_margins.setR(0.7);
    page_margins.setT(0.75);
    page_margins.setHeader(0.3);
    page_margins.setFooter(0.3);
    return chart_space;
}


    function CreateSurfaceChart(chartSeries, bUseCache, oOptions, bContour, bWireFrame){
        var asc_series = chartSeries.series;
        var oChartSpace = new AscFormat.CChartSpace();
        oChartSpace.setDate1904(false);
        oChartSpace.setLang("en-Us");
        oChartSpace.setRoundedCorners(false);
        oChartSpace.setStyle(2);
        oChartSpace.setChart(new AscFormat.CChart());
        var oChart = oChartSpace.chart;
        oChart.setAutoTitleDeleted(false);
        var oView3D = new AscFormat.CView3d();
        oChart.setView3D(oView3D);
        if(!bContour){
            oView3D.setRotX(15);
            oView3D.setRotY(20);
            oView3D.setRAngAx(false);
            oView3D.setPerspective(30);
        }
        else{
            oView3D.setRotX(90);
            oView3D.setRotY(0);
            oView3D.setRAngAx(false);
            oView3D.setPerspective(0);
        }
        oChart.setFloor(new AscFormat.CChartWall());
        oChart.floor.setThickness(0);
        oChart.setSideWall(new AscFormat.CChartWall());
        oChart.sideWall.setThickness(0);
        oChart.setBackWall(new AscFormat.CChartWall());
        oChart.backWall.setThickness(0);
        oChart.setPlotArea(new AscFormat.CPlotArea());
        oChart.plotArea.setLayout(new AscFormat.CLayout());
        var oSurfaceChart;
        //if(bContour){
        oSurfaceChart = new AscFormat.CSurfaceChart();
        //}
        if(bWireFrame){
            oSurfaceChart.setWireframe(true);
        }
        else{
            oSurfaceChart.setWireframe(false);
        }

        oChart.plotArea.addChart(oSurfaceChart);
        var bInCols;
        if(isRealObject(oOptions))
        {
            bInCols = oOptions.inColumns === true;
        }
        else
        {
            bInCols = false;
        }

        var parsedHeaders = chartSeries.parsedHeaders;
        for(var i = 0; i < asc_series.length; ++i)
        {
            var series = new AscFormat.CSurfaceSeries();
            series.setIdx(i);
            series.setOrder(i);
            series.setVal(new AscFormat.CYVal());
            FillValNum(series.val, asc_series[i].Val, bUseCache);
            if(parsedHeaders.bTop && !bInCols || bInCols && parsedHeaders.bLeft)
            {
                series.setCat(new AscFormat.CCat());
                FillCatStr(series.cat, asc_series[i].Cat, bUseCache);
            }
            if((parsedHeaders.bLeft && !bInCols || bInCols && parsedHeaders.bTop) && asc_series[i].TxCache && typeof asc_series[i].TxCache.Formula === "string" && asc_series[i].TxCache.Formula.length > 0)
            {
                FillSeriesTx(series, asc_series[i].TxCache, bUseCache);
            }
            oSurfaceChart.addSer(series);
        }
        var oCatAx = new AscFormat.CCatAx();
        oCatAx.setAxId(++AscFormat.Ax_Counter.GLOBAL_AX_ID_COUNTER);
        var oScaling = new AscFormat.CScaling();
        oScaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
        oCatAx.setScaling(oScaling);
        oCatAx.setDelete(false);
        oCatAx.setAxPos(AscFormat.AX_POS_B);
        oCatAx.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
        oCatAx.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
        oCatAx.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
        oCatAx.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
        oCatAx.setAuto(true);
        oCatAx.setLblAlgn(AscFormat.LBL_ALG_CTR);
        oCatAx.setLblOffset(100);
        oCatAx.setNoMultiLvlLbl(false);
        var oValAx = new AscFormat.CValAx();
        oValAx.setAxId(++AscFormat.Ax_Counter.GLOBAL_AX_ID_COUNTER);
        var oValScaling = new AscFormat.CScaling();
        oValScaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
        oValAx.setScaling(oValScaling);
        oValAx.setDelete(false);
        oValAx.setAxPos(AscFormat.AX_POS_L);
        oValAx.setMajorGridlines(new AscFormat.CSpPr());
        var oNumFmt = new AscFormat.CNumFmt();
        oNumFmt.setFormatCode(GetNumFormatFromSeries(asc_series));
        oNumFmt.setSourceLinked(true);
        oValAx.setNumFmt(oNumFmt);
        oValAx.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
        oValAx.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
        oValAx.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
        oCatAx.setCrossAx(oValAx);
        oValAx.setCrossAx(oCatAx);
        oValAx.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
        oValAx.setCrossBetween(AscFormat.CROSS_BETWEEN_MID_CAT);
        var oSerAx =  new AscFormat.CSerAx();
        oSerAx.setAxId(++AscFormat.Ax_Counter.GLOBAL_AX_ID_COUNTER);
        var oSerScaling = new AscFormat.CScaling();
        oSerScaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
        oSerAx.setScaling(oSerScaling);
        oSerAx.setDelete(false);
        oSerAx.setAxPos(AscFormat.AX_POS_B);
        oSerAx.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
        oSerAx.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
        oSerAx.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
        oSerAx.setCrossAx(oCatAx);
        oSerAx.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
        oChart.plotArea.addAxis(oCatAx);
        oChart.plotArea.addAxis(oValAx);
        oChart.plotArea.addAxis(oSerAx);
        oSurfaceChart.addAxId(oCatAx);
        oSurfaceChart.addAxId(oValAx);
        oSurfaceChart.addAxId(oSerAx);
        var oLegend = new AscFormat.CLegend();
        oLegend.setLegendPos(c_oAscChartLegendShowSettings.right);
        oLegend.setLayout(new AscFormat.CLayout());
        oLegend.setOverlay(false);
        //oLegend.setTxPr(AscFormat.CreateTextBodyFromString("", oDrawingDocument, oElement));
        oChart.setLegend(oLegend);
        oChart.setPlotVisOnly(true);
        oChart.setDispBlanksAs(DISP_BLANKS_AS_ZERO);
        oChart.setShowDLblsOverMax(false);
        var oPrintSettings = new AscFormat.CPrintSettings();
        oPrintSettings.setHeaderFooter(new AscFormat.CHeaderFooterChart());
        var oPageMargins = new AscFormat.CPageMarginsChart();
        oPageMargins.setB(0.75);
        oPageMargins.setL(0.7);
        oPageMargins.setR(0.7);
        oPageMargins.setT(0.75);
        oPageMargins.setHeader(0.3);
        oPageMargins.setFooter(0.3);
        oPrintSettings.setPageMargins(oPageMargins);
        oPrintSettings.setPageSetup(new AscFormat.CPageSetup());
        oChartSpace.setPrintSettings(oPrintSettings);
        return oChartSpace;
    }


function CreateDefaultAxises(valFormatCode)
{
    var cat_ax = new AscFormat.CCatAx();
    var val_ax = new AscFormat.CValAx();
    cat_ax.setAxId(++Ax_Counter.GLOBAL_AX_ID_COUNTER);
    val_ax.setAxId(++Ax_Counter.GLOBAL_AX_ID_COUNTER);
    cat_ax.setCrossAx(val_ax);
    val_ax.setCrossAx(cat_ax);


    cat_ax.setScaling(new AscFormat.CScaling());
    cat_ax.setDelete(false);
    cat_ax.setAxPos(AscFormat.AX_POS_B);
    cat_ax.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    cat_ax.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
    cat_ax.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    cat_ax.setAuto(true);
    cat_ax.setLblAlgn(AscFormat.LBL_ALG_CTR);
    cat_ax.setLblOffset(100);
    cat_ax.setNoMultiLvlLbl(false);
    var scaling = cat_ax.scaling;
    scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
    val_ax.setScaling(new AscFormat.CScaling());
    val_ax.setDelete(false);
    val_ax.setAxPos(AscFormat.AX_POS_L);
    val_ax.setMajorGridlines(new AscFormat.CSpPr());
    val_ax.setNumFmt(new AscFormat.CNumFmt());
    var num_fmt = val_ax.numFmt;
    num_fmt.setFormatCode(valFormatCode);
    num_fmt.setSourceLinked(true);
    val_ax.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    val_ax.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
    val_ax.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
    val_ax.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    val_ax.setCrossBetween(AscFormat.CROSS_BETWEEN_BETWEEN);
    scaling = val_ax.scaling;
    scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
    //cat_ax.setTitle(new CTitle());
    //val_ax.setTitle(new CTitle());
   // var title = val_ax.title;
   // title.setTxPr(new CTextBody());
   // title.txPr.setBodyPr(new AscFormat.CBodyPr());
   // title.txPr.bodyPr.setVert(AscFormat.nVertTTvert);
    return {valAx: val_ax, catAx: cat_ax};
}

function CreateScatterAxis()
{
    var cat_ax = new AscFormat.CValAx();
    var val_ax = new AscFormat.CValAx();
    cat_ax.setAxId(++Ax_Counter.GLOBAL_AX_ID_COUNTER);
    val_ax.setAxId(++Ax_Counter.GLOBAL_AX_ID_COUNTER);
    cat_ax.setCrossAx(val_ax);
    val_ax.setCrossAx(cat_ax);

    cat_ax.setScaling(new AscFormat.CScaling());
    cat_ax.setDelete(false);
    cat_ax.setAxPos(AscFormat.AX_POS_B);
    cat_ax.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    cat_ax.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
    cat_ax.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
    cat_ax.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    cat_ax.scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
    val_ax.setScaling(new AscFormat.CScaling());
    val_ax.setDelete(false);
    val_ax.setAxPos(AscFormat.AX_POS_L);
    val_ax.setMajorGridlines(new AscFormat.CSpPr());
    val_ax.setNumFmt(new AscFormat.CNumFmt());
    val_ax.setMajorTickMark(c_oAscTickMark.TICK_MARK_OUT);
    val_ax.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
    val_ax.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
    val_ax.setCrosses(AscFormat.CROSSES_AUTO_ZERO);
    val_ax.setCrossBetween(AscFormat.CROSS_BETWEEN_BETWEEN);
    var scaling = val_ax.scaling;
    scaling.setOrientation(AscFormat.ORIENTATION_MIN_MAX);
    var num_fmt = val_ax.numFmt;
    var format_code = "General";
    num_fmt.setFormatCode(format_code);
    num_fmt.setSourceLinked(true);
    return {valAx: val_ax, catAx: cat_ax};
}


function fCheckNumFormatType(numFormatType){
        return (numFormatType === c_oAscNumFormatType.Time || numFormatType === c_oAscNumFormatType.Date || numFormatType === c_oAscNumFormatType.Percent)
}

function parseSeriesHeaders (ws, rangeBBox) {
	var cntLeft = 0, cntTop = 0;
	var headers = { bLeft: false, bTop: false };
	var i, cell, value, numFormatType, j;

    var bLeftOnlyDateTime = true, bTopOnlyDateTime = true;
    var nStartIndex;
	if (rangeBBox) {
		if (rangeBBox.c2 - rangeBBox.c1 > 0) {

		    var nStartIndex = (rangeBBox.r1 === rangeBBox.r2) ? rangeBBox.r1 : (rangeBBox.r1 + 1);
			for (i = nStartIndex; i <= rangeBBox.r2; i++) {
				cell = ws.getCell3(i, rangeBBox.c1);
				value = cell.getValue();
                numFormatType = cell.getNumFormatType();
                if(!AscCommon.isNumber(value) && (value != ""))
                {
                    bLeftOnlyDateTime = false;
                    headers.bLeft = true;
                }
                else if(fCheckNumFormatType(numFormatType))
                {
                    headers.bLeft = true;
                }
			}
		}

		if (rangeBBox.r2 - rangeBBox.r1 > 0) {
            var nStartIndex = (rangeBBox.c1 === rangeBBox.c2) ? rangeBBox.c1 : (rangeBBox.c1 + 1);
			for (i = nStartIndex; i <= rangeBBox.c2; i++) {

				cell = ws.getCell3(rangeBBox.r1, i);
				value = cell.getValue();
                numFormatType= cell.getNumFormatType();
                if(!AscCommon.isNumber(value) && value != "")
                {
                    bTopOnlyDateTime = false;
                    headers.bTop = true;
                }
                else if(fCheckNumFormatType(numFormatType) )
                {
                    headers.bTop = true;
                }
			}
		}
        if(headers.bTop || headers.bLeft)
        {
            var nRowStart = headers.bTop ? rangeBBox.r1 + 1 : rangeBBox.r1, nColStart = headers.bLeft ? rangeBBox.c1 + 1 : rangeBBox.c1;
            for(i = nRowStart; i <= rangeBBox.r2; ++i)
            {
                for(j = nColStart; j <= rangeBBox.c2; ++j)
                {
                    cell = ws.getCell3(i, j);
                    value = cell.getValue();
                    numFormatType= cell.getNumFormatType();
                    if (!fCheckNumFormatType(numFormatType) && value !== "")
                    {
                        break;
                    }
                }
                if(j <= rangeBBox.c2)
                {
                    break;
                }
            }
            if(i === rangeBBox.r2 + 1)
            {
                if(headers.bLeft && bLeftOnlyDateTime)
                {
                    headers.bLeft = false;
                }
                if(headers.bTop && bTopOnlyDateTime)
                {
                    headers.bTop = false;
                }
            }
        }
	}
	else
		headers = { bLeft: true, bTop: true };

	return headers;
}

function getChartSeries (worksheet, options, catHeadersBBox, serHeadersBBox) {
	var ws, range;
	var result = parserHelp.parse3DRef(options.range);
	if (result) {
		ws = worksheet.workbook.getWorksheetByName(result.sheet);
		if (ws)
			range = ws.getRange2(result.range);
	}

	if (!range)
		return null;

	var bbox = range.getBBox0();
	var nameIndex = 1;

	var i, series = [];

	function getNumCache(c1, c2, r1, r2) {

		// (c1 == c2) || (r1 == r2)
		var cache = [], cell, item;

		if ( c1 == c2 ) {		// vertical cache
			for (var row = r1; row <= r2; row++) {
				cell = ws.getCell3(row, c1);

				item = {};
				item.numFormatStr = cell.getNumFormatStr();
				item.isDateTimeFormat = cell.getNumFormat().isDateTimeFormat();
				item.val = cell.getValue();
				item.isHidden = ws.getColHidden(c1) || ws.getRowHidden(row);
				cache.push(item);
			}
		} else /*r1 == r2*/ {		// horizontal cache
			for (var col = c1; col <= c2; col++) {
				cell = ws.getCell3(r1, col, 0);
				item = {};
				item.numFormatStr = cell.getNumFormatStr();
				item.isDateTimeFormat = cell.getNumFormat().isDateTimeFormat();
				item.val = cell.getValue();
				item.isHidden = ws.getColHidden(col) || ws.getRowHidden(r1);
				cache.push(item);
			}
		}

		return cache;
	}

	var parsedHeaders = parseSeriesHeaders(ws, bbox);

    var data_bbox = {r1: bbox.r1, r2: bbox.r2, c1: bbox.c1, c2: bbox.c2};
    if(parsedHeaders.bTop)
    {
        ++data_bbox.r1;
    }
    else
    {
        if(!options.getInColumns())
        {
            if(catHeadersBBox && catHeadersBBox.c1 === data_bbox.c1 && catHeadersBBox.c2 === data_bbox.c2 && catHeadersBBox.r1 === catHeadersBBox.r2 && catHeadersBBox.r1 === data_bbox.r1)
            {
                ++data_bbox.r1;
            }
        }
        else
        {
            if(serHeadersBBox && serHeadersBBox.c1 === data_bbox.c1 && serHeadersBBox.c2 === data_bbox.c2 && serHeadersBBox.r1 === serHeadersBBox.r2 && serHeadersBBox.r1 === data_bbox.r1)
            {
                ++data_bbox.r1;
            }
        }
    }

    if(parsedHeaders.bLeft)
    {
        ++data_bbox.c1;
    }
    else
    {
        if(!options.getInColumns())
        {
            if(serHeadersBBox && serHeadersBBox.c1 === serHeadersBBox.c2 && serHeadersBBox.r1 === data_bbox.r1 && serHeadersBBox.r2 === data_bbox.r2 && serHeadersBBox.c1 === data_bbox.c1)
            {
                ++data_bbox.c1;
            }
        }
        else
        {
            if(catHeadersBBox && catHeadersBBox.c1 === catHeadersBBox.c2 && catHeadersBBox.r1 === data_bbox.r1 && catHeadersBBox.r2 === data_bbox.r2 && catHeadersBBox.c1 === data_bbox.c1)
            {
                ++data_bbox.c1;
            }
        }
    }

	var bIsScatter = (Asc.c_oAscChartTypeSettings.scatter <= options.type && options.type <= Asc.c_oAscChartTypeSettings.scatterSmoothMarker);
	var top_header_bbox, left_header_bbox, ser, startCell, endCell, formulaCell, start, end, formula, numCache, sStartCellId, sEndCellId;
	if (!options.getInColumns()) {
		if(parsedHeaders.bTop)
			top_header_bbox = {r1: bbox.r1, c1: data_bbox.c1, r2: bbox.r1, c2: data_bbox.c2};
		else if(catHeadersBBox && catHeadersBBox.c1 === data_bbox.c1 && catHeadersBBox.c2 === data_bbox.c2 && catHeadersBBox.r1 === catHeadersBBox.r2)
			top_header_bbox = {r1: catHeadersBBox.r1, c1: catHeadersBBox.c1, r2: catHeadersBBox.r1, c2:catHeadersBBox.c2};

		if(parsedHeaders.bLeft)
			left_header_bbox = {r1: data_bbox.r1, r2: data_bbox.r2, c1: bbox.c1, c2: bbox.c1};
		else if(serHeadersBBox && serHeadersBBox.c1 === serHeadersBBox.c2 && serHeadersBBox.r1 === data_bbox.r1 && serHeadersBBox.r2 === data_bbox.r2)
			left_header_bbox = {r1: serHeadersBBox.r1, c1: serHeadersBBox.c1, r2: serHeadersBBox.r1, c2: serHeadersBBox.c2};

		for (i = data_bbox.r1; i <= data_bbox.r2; ++i) {
			ser = new AscFormat.asc_CChartSeria();
			startCell = new CellAddress(i, data_bbox.c1, 0);
			endCell = new CellAddress(i, data_bbox.c2, 0);

			ser.isHidden = !!ws.getRowHidden(i);

			// Val
            sStartCellId = startCell.getIDAbsolute();
            sEndCellId = endCell.getIDAbsolute();
            ser.Val.Formula = parserHelp.get3DRef(ws.sName, sStartCellId === sEndCellId ?
                sStartCellId : sStartCellId + ':' + sEndCellId);
			ser.Val.NumCache = getNumCache(data_bbox.c1, data_bbox.c2, i, i);

			if(left_header_bbox)
			{
				formulaCell = new CellAddress( i, left_header_bbox.c1, 0 );
				ser.TxCache.Formula = parserHelp.get3DRef(ws.sName, formulaCell.getIDAbsolute());
			}
			// xVal

			if(top_header_bbox)
			{
				start = new CellAddress(top_header_bbox.r1, top_header_bbox.c1, 0);
				end = new CellAddress(top_header_bbox.r1, top_header_bbox.c2, 0);

				formula = parserHelp.get3DRef(ws.sName, start.getIDAbsolute() + ':' + end.getIDAbsolute());
				numCache = getNumCache(top_header_bbox.c1, top_header_bbox.c2, top_header_bbox.r1, top_header_bbox.r1 );

				if (bIsScatter)
				{
					ser.xVal.Formula = formula;
					ser.xVal.NumCache = numCache;
				}
				else
				{
					ser.Cat.Formula = formula;
					ser.Cat.NumCache = numCache;
				}
			}

			ser.TxCache.Tx = left_header_bbox ? (ws.getCell3(i, left_header_bbox.c1).getValue()) :
				(AscCommon.translateManager.getValue('Series') + " " + nameIndex);
			series.push(ser);
			nameIndex++;
		}
	} else {
		if(parsedHeaders.bTop)
			top_header_bbox = {r1: bbox.r1, c1: data_bbox.c1, r2: bbox.r1, c2: data_bbox.c2};
		else if(serHeadersBBox && serHeadersBBox.r1 === serHeadersBBox.r2 && serHeadersBBox.c1 === data_bbox.c1 && serHeadersBBox.c2 === data_bbox.c2)
			top_header_bbox = {r1: serHeadersBBox.r1, c1: serHeadersBBox.c1, r2: serHeadersBBox.r2, c2: serHeadersBBox.c2};

		if(parsedHeaders.bLeft)
			left_header_bbox = {r1: data_bbox.r1, c1: bbox.c1, r2: data_bbox.r2, c2: bbox.c1};
		else if(catHeadersBBox && catHeadersBBox.c1 === catHeadersBBox.c2 && catHeadersBBox.r1 === data_bbox.r1 && catHeadersBBox.r2 === data_bbox.r2)
			left_header_bbox = {r1: catHeadersBBox.r1, c1: catHeadersBBox.c1, r2: catHeadersBBox.r2, c2: catHeadersBBox.c2};


		for (i = data_bbox.c1; i <= data_bbox.c2; i++) {

			ser = new AscFormat.asc_CChartSeria();
			startCell = new CellAddress(data_bbox.r1, i, 0);
			endCell = new CellAddress(data_bbox.r2, i, 0);

			ser.isHidden = !!ws.getColHidden(i);

			// Val
            sStartCellId = startCell.getIDAbsolute();
            sEndCellId = endCell.getIDAbsolute();
            if (sStartCellId == sEndCellId)
                ser.Val.Formula =  parserHelp.get3DRef(ws.sName, sStartCellId);
            else
                ser.Val.Formula = parserHelp.get3DRef(ws.sName, sStartCellId + ':' + sEndCellId);
			ser.Val.NumCache = getNumCache(i, i, data_bbox.r1, bbox.r2);


			if ( left_header_bbox )
			{
				start = new CellAddress(left_header_bbox.r1, left_header_bbox.c1, 0);
				end = new CellAddress(left_header_bbox.r2, left_header_bbox.c1, 0);

				formula = parserHelp.get3DRef(ws.sName, start.getIDAbsolute() + ':' + end.getIDAbsolute());
				numCache = getNumCache( left_header_bbox.c1, left_header_bbox.c1, left_header_bbox.r1, left_header_bbox.r2 );

				if (bIsScatter) {
					ser.xVal.Formula = formula;
					ser.xVal.NumCache = numCache;
				}
				else {
					ser.Cat.Formula = formula;
					ser.Cat.NumCache = numCache;
				}
			}

			if (top_header_bbox)
			{
				formulaCell = new CellAddress( top_header_bbox.r1, i, 0 );
				ser.TxCache.Formula = parserHelp.get3DRef(ws.sName, formulaCell.getIDAbsolute());
			}

			ser.TxCache.Tx = top_header_bbox ? (ws.getCell3(top_header_bbox.r1, i).getValue()) :
				(AscCommon.translateManager.getValue('Series') + " " + nameIndex);
			series.push(ser);
			nameIndex++;
		}
	}

	return {series: series, parsedHeaders: parsedHeaders};
}

function checkSpPrRasterImages(spPr)
{
    if(spPr && spPr.Fill && spPr.Fill && spPr.Fill.fill && spPr.Fill.fill.type === Asc.c_oAscFill.FILL_TYPE_BLIP)
    {
        var copyBlipFill = spPr.Fill.createDuplicate();
        copyBlipFill.fill.setRasterImageId(spPr.Fill.fill.RasterImageId);
        spPr.setFill(copyBlipFill);
    }
}
function checkBlipFillRasterImages(sp)
{
    switch (sp.getObjectType())
    {
        case AscDFH.historyitem_type_Shape:
        {
            checkSpPrRasterImages(sp.spPr);
            break;
        }
        case AscDFH.historyitem_type_ImageShape:
        case AscDFH.historyitem_type_OleObject:
        {
            if(sp.blipFill)
            {
                var newBlipFill = sp.blipFill.createDuplicate();
                newBlipFill.setRasterImageId(sp.blipFill.RasterImageId);
                sp.setBlipFill(newBlipFill);
            }
            break;
        }
        case AscDFH.historyitem_type_ChartSpace:
        {
            checkSpPrRasterImages(sp.spPr);
            var chart = sp.chart;
            if(chart)
            {
                chart.backWall && checkSpPrRasterImages(chart.backWall.spPr);
                chart.floor && checkSpPrRasterImages(chart.floor.spPr);
                chart.legend && checkSpPrRasterImages(chart.legend.spPr);
                chart.sideWall && checkSpPrRasterImages(chart.sideWall.spPr);
                chart.title && checkSpPrRasterImages(chart.title.spPr);
                //plotArea
                var plot_area = sp.chart.plotArea;
                if(plot_area)
                {
                    checkSpPrRasterImages(plot_area.spPr);
                    for(var j = 0; j < plot_area.axId.length; ++j)
                    {
                        var axis = plot_area.axId[j];
                        if(axis)
                        {
                            checkSpPrRasterImages(axis.spPr);
                            axis.title && axis.title && checkSpPrRasterImages(axis.title.spPr);
                        }
                    }
                    for(j = 0; j < plot_area.charts.length; ++j)
                    {
                        plot_area.charts[j].checkSpPrRasterImages();
                    }
                }
            }
            break;
        }
        case AscDFH.historyitem_type_GroupShape:
        {
            for(var i = 0; i < sp.spTree.length; ++i)
            {
                checkBlipFillRasterImages(sp.spTree[i]);
            }
            break;
        }
        case AscDFH.historyitem_type_GraphicFrame:
        {
            break;
        }
    }
}
    
    function initStyleManager() {
        CHART_STYLE_MANAGER.init();
    }

    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].BAR_SHAPE_CONE = BAR_SHAPE_CONE;
    window['AscFormat'].BAR_SHAPE_CONETOMAX = BAR_SHAPE_CONETOMAX;
    window['AscFormat'].BAR_SHAPE_BOX = BAR_SHAPE_BOX;
    window['AscFormat'].BAR_SHAPE_CYLINDER = BAR_SHAPE_CYLINDER;
    window['AscFormat'].BAR_SHAPE_PYRAMID = BAR_SHAPE_PYRAMID;
    window['AscFormat'].BAR_SHAPE_PYRAMIDTOMAX = BAR_SHAPE_PYRAMIDTOMAX;
    window['AscFormat'].DISP_BLANKS_AS_GAP = DISP_BLANKS_AS_GAP;
    window['AscFormat'].DISP_BLANKS_AS_SPAN = DISP_BLANKS_AS_SPAN;
    window['AscFormat'].DISP_BLANKS_AS_ZERO = DISP_BLANKS_AS_ZERO;
    window['AscFormat'].checkBlackUnifill = checkBlackUnifill;
    window['AscFormat'].BBoxInfo = BBoxInfo;
    window['AscFormat'].CreateUnifillSolidFillSchemeColorByIndex = CreateUnifillSolidFillSchemeColorByIndex;
    window['AscFormat'].CreateUniFillSchemeColorWidthTint = CreateUniFillSchemeColorWidthTint;
    window['AscFormat'].G_O_VISITED_HLINK_COLOR = G_O_VISITED_HLINK_COLOR;
    window['AscFormat'].G_O_HLINK_COLOR = G_O_HLINK_COLOR;
    window['AscFormat'].G_O_NO_ACTIVE_COMMENT_BRUSH = G_O_NO_ACTIVE_COMMENT_BRUSH;
    window['AscFormat'].G_O_ACTIVE_COMMENT_BRUSH = G_O_ACTIVE_COMMENT_BRUSH;
    window['AscFormat'].CChartSpace = CChartSpace;
    window['AscFormat'].getPtsFromSeries = getPtsFromSeries;
    window['AscFormat'].CreateUnfilFromRGB = CreateUnfilFromRGB;
    window['AscFormat'].CreateUniFillSolidFillWidthTintOrShade = CreateUniFillSolidFillWidthTintOrShade;
    window['AscFormat'].CreateUnifillSolidFillSchemeColor = CreateUnifillSolidFillSchemeColor;
    window['AscFormat'].CreateNoFillLine = CreateNoFillLine;
    window['AscFormat'].CreateNoFillUniFill = CreateNoFillUniFill;
    window['AscFormat'].CExternalData = CExternalData;
    window['AscFormat'].CPivotSource = CPivotSource;
    window['AscFormat'].CProtection = CProtection;
    window['AscFormat'].CPrintSettings = CPrintSettings;
    window['AscFormat'].CHeaderFooterChart = CHeaderFooterChart;
    window['AscFormat'].CPageMarginsChart = CPageMarginsChart;
    window['AscFormat'].CPageSetup = CPageSetup;
    window['AscFormat'].CreateView3d = CreateView3d;
    window['AscFormat'].CreateLineChart = CreateLineChart;
    window['AscFormat'].CreateBarChart = CreateBarChart;
    window['AscFormat'].CreateHBarChart = CreateHBarChart;
    window['AscFormat'].CreateAreaChart = CreateAreaChart;
    window['AscFormat'].CreatePieChart = CreatePieChart;
    window['AscFormat'].CreateScatterChart = CreateScatterChart;
    window['AscFormat'].CreateStockChart = CreateStockChart;
    window['AscFormat'].CreateDefaultAxises = CreateDefaultAxises;
    window['AscFormat'].CreateScatterAxis = CreateScatterAxis;
    window['AscFormat'].getChartSeries = getChartSeries;
    window['AscFormat'].checkSpPrRasterImages = checkSpPrRasterImages;
    window['AscFormat'].checkBlipFillRasterImages = checkBlipFillRasterImages;

    window['AscFormat'].PAGE_SETUP_ORIENTATION_DEFAULT = 0;
    window['AscFormat'].PAGE_SETUP_ORIENTATION_LANDSCAPE = 1;
    window['AscFormat'].PAGE_SETUP_ORIENTATION_PORTRAIT = 2;

    window['AscFormat'].initStyleManager = initStyleManager;
    window['AscFormat'].CHART_STYLE_MANAGER = CHART_STYLE_MANAGER;
    window['AscFormat'].CheckParagraphTextPr = CheckParagraphTextPr;
    window['AscFormat'].CheckObjectTextPr = CheckObjectTextPr;
    window['AscFormat'].CreateColorMapByIndex = CreateColorMapByIndex;
    window['AscFormat'].getArrayFillsFromBase = getArrayFillsFromBase;
    window['AscFormat'].getMaxIdx = getMaxIdx;
    window['AscFormat'].CreateSurfaceChart = CreateSurfaceChart;
    window['AscFormat'].getStringPointsFromCat = getStringPointsFromCat;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {


    var drawingsChangesMap = window['AscDFH'].drawingsChangesMap;
    var drawingContentChanges = window['AscDFH'].drawingContentChanges;

    drawingsChangesMap[AscDFH.historyitem_DLbl_SetDelete]         = function(oClass, value){oClass.bDelete        = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbl_SetDLblPos]        = function(oClass, value){oClass.dLblPos        = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbl_SetIdx]            = function(oClass, value){oClass.idx            = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbl_SetLayout]         = function(oClass, value){oClass.layout         = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbl_SetNumFmt]         = function(oClass, value){oClass.numFmt         = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbl_SetSeparator]      = function(oClass, value){oClass.separator      = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbl_SetShowBubbleSize] = function(oClass, value){oClass.showBubbleSize = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbl_SetShowCatName]    = function(oClass, value){oClass.showCatName    = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbl_SetShowLegendKey]  = function(oClass, value){oClass.showLegendKey  = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbl_SetShowPercent]    = function(oClass, value){oClass.showPercent    = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbl_SetShowSerName]    = function(oClass, value){oClass.showSerName    = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbl_SetShowVal]        = function(oClass, value){oClass.showVal        = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbl_SetSpPr]           = function(oClass, value){oClass.spPr           = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbl_SetTx]             = function(oClass, value){oClass.tx             = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbl_SetTxPr]           = function(oClass, value){oClass.txPr           = value;};
    drawingsChangesMap[AscDFH.historyitem_PlotArea_SetCatAx]      = function(oClass, value){oClass.catAx  = value;};
    drawingsChangesMap[AscDFH.historyitem_PlotArea_SetDateAx]     = function(oClass, value){oClass.dateAx = value;};
    drawingsChangesMap[AscDFH.historyitem_PlotArea_SetDTable]     = function(oClass, value){oClass.dTable = value;};
    drawingsChangesMap[AscDFH.historyitem_PlotArea_SetLayout]     = function(oClass, value){oClass.layout = value;};
    drawingsChangesMap[AscDFH.historyitem_PlotArea_SetSpPr]       = function(oClass, value){oClass.spPr   = value;};
    drawingsChangesMap[AscDFH.historyitem_CommonChartFormat_SetParent]  = function(oClass, value){oClass.parent  = value;};
    drawingsChangesMap[AscDFH.historyitem_BarChart_Set3D]              = function(oClass, value){oClass.b3D  = value;};
    drawingsChangesMap[AscDFH.historyitem_BarChart_SetGapDepth]        = function(oClass, value){oClass.gapDepth  = value;};
    drawingsChangesMap[AscDFH.historyitem_BarChart_SetShape]           = function(oClass, value){oClass.shape  = value;};
    drawingsChangesMap[AscDFH.historyitem_BarChart_SetBarDir]        = function(oClass, value){oClass.barDir   = value;};
    drawingsChangesMap[AscDFH.historyitem_BarChart_SetDLbls]         = function(oClass, value){oClass.dLbls    = value;};
    drawingsChangesMap[AscDFH.historyitem_BarChart_SetGapWidth]      = function(oClass, value){oClass.gapWidth  = value;};
    drawingsChangesMap[AscDFH.historyitem_BarChart_SetGrouping]      = function(oClass, value){oClass.grouping  = value;};
    drawingsChangesMap[AscDFH.historyitem_BarChart_SetOverlap]       = function(oClass, value){oClass.overlap  = value;};
    drawingsChangesMap[AscDFH.historyitem_BarChart_SetSerLines]        = function(oClass, value){oClass.serLines = value;};
    drawingsChangesMap[AscDFH.historyitem_BarChart_SetVaryColors]      = function(oClass, value){oClass.varyColors = value;};
    drawingsChangesMap[AscDFH.historyitem_AreaChart_SetDLbls]          = function(oClass, value){oClass.dLbls    = value;};
    drawingsChangesMap[AscDFH.historyitem_AreaChart_SetDropLines]      = function(oClass, value){oClass.dropLines = value;};
    drawingsChangesMap[AscDFH.historyitem_AreaChart_SetGrouping]       = function(oClass, value){oClass.grouping = value;};
    drawingsChangesMap[AscDFH.historyitem_AreaChart_SetVaryColors]     = function(oClass, value){oClass.varyColors = value;};
    drawingsChangesMap[AscDFH.historyitem_AreaSeries_SetCat]           = function(oClass, value){oClass.cat   = value;};
    drawingsChangesMap[AscDFH.historyitem_AreaSeries_SetDLbls]         = function(oClass, value){oClass.dLbls = value;};
    drawingsChangesMap[AscDFH.historyitem_AreaSeries_SetErrBars]           = function(oClass, value){oClass.errBars       = value;};
    drawingsChangesMap[AscDFH.historyitem_AreaSeries_SetIdx]               = function(oClass, value){oClass.idx           = value;};
    drawingsChangesMap[AscDFH.historyitem_AreaSeries_SetOrder]             = function(oClass, value){oClass.order         = value;};
    drawingsChangesMap[AscDFH.historyitem_AreaSeries_SetPictureOptions]    = function(oClass, value){oClass.pictureOptions = value;};
    drawingsChangesMap[AscDFH.historyitem_AreaSeries_SetSpPr]              = function(oClass, value){oClass.spPr          = value;};
    drawingsChangesMap[AscDFH.historyitem_AreaSeries_SetTrendline]         = function(oClass, value){oClass.trendline     = value;};
    drawingsChangesMap[AscDFH.historyitem_AreaSeries_SetTx]                = function(oClass, value){oClass.tx            = value;};
    drawingsChangesMap[AscDFH.historyitem_AreaSeries_SetVal]               = function(oClass, value){oClass.val           = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetAuto]                       = function(oClass, value){oClass.auto           = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetAxId]                       = function(oClass, value){oClass.axId           = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetAxPos]                      = function(oClass, value){oClass.axPos          = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetCrossAx]                    = function(oClass, value){oClass.crossAx        = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetCrosses]                    = function(oClass, value){oClass.crosses        = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetCrossesAt]                  = function(oClass, value){oClass.crossesAt      = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetDelete]                     = function(oClass, value){oClass.bDelete        = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetLblAlgn]                    = function(oClass, value){oClass.lblAlgn        = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetLblOffset]                  = function(oClass, value){oClass.lblOffset      = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetMajorGridlines]             = function(oClass, value){oClass.majorGridlines = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetMajorTickMark]              = function(oClass, value){oClass.majorTickMark  = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetMinorGridlines]             = function(oClass, value){oClass.minorGridlines = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetMinorTickMark]              = function(oClass, value){oClass.minorTickMark  = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetNoMultiLvlLbl]              = function(oClass, value){oClass.noMultiLvlLbl  = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetNumFmt]                     = function(oClass, value){oClass.numFmt         = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetScaling]                    = function(oClass, value){oClass.scaling        = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetSpPr]                       = function(oClass, value){oClass.spPr           = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetTickLblPos]                 = function(oClass, value){oClass.tickLblPos     = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetTickLblSkip]                = function(oClass, value){oClass.tickLblSkip    = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetTickMarkSkip]               = function(oClass, value){oClass.tickMarkSkip   = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetTitle]                      = function(oClass, value){oClass.title          = value;};
    drawingsChangesMap[AscDFH.historyitem_CatAxSetTxPr]                       = function(oClass, value){oClass.txPr           = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxAuto]                         = function(oClass, value){oClass.auto             = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxAxId]                         = function(oClass, value){oClass.axId             = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxAxPos]                        = function(oClass, value){oClass.axPos            = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxBaseTimeUnit]                 = function(oClass, value){oClass.baseTimeUnit     = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxCrossAx]                      = function(oClass, value){oClass.crossAx          = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxCrosses]                      = function(oClass, value){oClass.crosses          = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxCrossesAt]                    = function(oClass, value){oClass.crossesAt       = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxDelete]                       = function(oClass, value){oClass.bDelete           = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxLblOffset]                    = function(oClass, value){oClass.lblOffset        = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxMajorGridlines]               = function(oClass, value){oClass.majorGridlines   = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxMajorTickMark]                = function(oClass, value){oClass.majorTickMark    = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxMajorTimeUnit]                = function(oClass, value){oClass.majorTimeUnit    = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxMajorUnit]                    = function(oClass, value){oClass.majorUnit        = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxMajorGridlines]               = function(oClass, value){oClass.majorGridlines   = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxMinorTickMark]                = function(oClass, value){oClass.minorTickMark    = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxMinorTimeUnit]                = function(oClass, value){oClass.minorTimeUnit    = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxMinorUnit]                    = function(oClass, value){oClass.minorUnit        = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxNumFmt]                       = function(oClass, value){oClass.numFmt           = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxScaling]                      = function(oClass, value){oClass.scaling          = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxSpPr]                         = function(oClass, value){oClass.spPr             = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxTickLblPos]                   = function(oClass, value){oClass.tickLblPos       = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxTitle]                        = function(oClass, value){oClass.title            = value;};
    drawingsChangesMap[AscDFH.historyitem_DateAxTxPr]                         = function(oClass, value){oClass.txPr             = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetAxId]                       = function(oClass, value){oClass.axId           = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetAxPos]                      = function(oClass, value){oClass.axPos          = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetCrossAx]                    = function(oClass, value){oClass.crossAx        = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetCrosses]                    = function(oClass, value){oClass.crosses        = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetCrossesAt]                  = function(oClass, value){oClass.crossesAt      = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetDelete]                     = function(oClass, value){oClass.delete         = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetMajorGridlines]             = function(oClass, value){oClass.majorGridlines = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetMajorTickMark]              = function(oClass, value){oClass.majorTickMark  = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetMinorGridlines]             = function(oClass, value){oClass.minorGridlines = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetMinorTickMark]              = function(oClass, value){oClass.minorTickMark  = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetNumFmt]                     = function(oClass, value){oClass.numFmt         = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetScaling]                    = function(oClass, value){oClass.scaling        = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetSpPr]                       = function(oClass, value){oClass.spPr           = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetTickLblPos]                 = function(oClass, value){oClass.tickLblPos     = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetTickLblSkip]                = function(oClass, value){oClass.tickLblSkip    = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetTickMarkSkip]               = function(oClass, value){oClass.tickMarkSkip   = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetTitle]                      = function(oClass, value){oClass.title          = value;};
    drawingsChangesMap[AscDFH.historyitem_SerAxSetTxPr]                       = function(oClass, value){oClass.txPr           = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetAxId]                       = function(oClass, value){oClass.axId            = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetAxPos]                      = function(oClass, value){oClass.axPos           = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetCrossAx]                    = function(oClass, value){oClass.crossAx         = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetCrossBetween]               = function(oClass, value){oClass.crossBetween    = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetCrosses]                    = function(oClass, value){oClass.crosses         = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetCrossesAt]                  = function(oClass, value){oClass.crossesAt       = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetDelete]                     = function(oClass, value){oClass.bDelete          = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetDispUnits]                  = function(oClass, value){oClass.dispUnits       = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetMajorGridlines]             = function(oClass, value){oClass.majorGridlines  = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetMajorTickMark]              = function(oClass, value){oClass.majorTickMark   = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetMajorUnit]                  = function(oClass, value){oClass.majorUnit       = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetMinorGridlines]             = function(oClass, value){oClass.minorGridlines  = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetMinorTickMark]              = function(oClass, value){oClass.minorTickMark   = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetMinorUnit]                  = function(oClass, value){oClass.minorUnit       = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetNumFmt]                     = function(oClass, value){oClass.numFmt          = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetScaling]                    = function(oClass, value){oClass.scaling         = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetSpPr]                       = function(oClass, value){oClass.spPr            = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetTickLblPos]                 = function(oClass, value){oClass.tickLblPos      = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetTitle]                      = function(oClass, value){oClass.title           = value;};
    drawingsChangesMap[AscDFH.historyitem_ValAxSetTxPr]                       = function(oClass, value){oClass.txPr            = value;};
    drawingsChangesMap[AscDFH.historyitem_BandFmt_SetIdx]                     = function(oClass, value){oClass.idx = value;};
    drawingsChangesMap[AscDFH.historyitem_BandFmt_SetSpPr]                    = function(oClass, value){oClass.spPr = value;};
    drawingsChangesMap[AscDFH.historyitem_BarSeries_SetCat]                   = function(oClass, value){oClass.cat = value;};
    drawingsChangesMap[AscDFH.historyitem_BarSeries_SetDLbls]                 = function(oClass, value){oClass.dLbls = value;};
    drawingsChangesMap[AscDFH.historyitem_BarSeries_SetErrBars]               = function(oClass, value){oClass.errBars         = value;};
    drawingsChangesMap[AscDFH.historyitem_BarSeries_SetIdx]                   = function(oClass, value){oClass.idx             = value;};
    drawingsChangesMap[AscDFH.historyitem_BarSeries_SetInvertIfNegative]      = function(oClass, value){oClass.invertIfNegative = value;};
    drawingsChangesMap[AscDFH.historyitem_BarSeries_SetOrder]                 = function(oClass, value){oClass.order           = value;};
    drawingsChangesMap[AscDFH.historyitem_BarSeries_SetPictureOptions]        = function(oClass, value){oClass.pictureOptions  = value;};
    drawingsChangesMap[AscDFH.historyitem_BarSeries_SetShape]                 = function(oClass, value){oClass.shape           = value;};
    drawingsChangesMap[AscDFH.historyitem_BarSeries_SetSpPr]                  = function(oClass, value){oClass.spPr            = value;};
    drawingsChangesMap[AscDFH.historyitem_BarSeries_SetTrendline]             = function(oClass, value){oClass.trendline       = value;};
    drawingsChangesMap[AscDFH.historyitem_BarSeries_SetTx]                    = function(oClass, value){oClass.tx              = value;};
    drawingsChangesMap[AscDFH.historyitem_BarSeries_SetVal]                   = function(oClass, value){oClass.val             = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleChart_SetBubble3D]            = function(oClass, value){oClass.bubble3D   = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleChart_SetBubbleScale]         = function(oClass, value){oClass.bubbleScale = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleChart_SetDLbls]               = function(oClass, value){oClass.dLbls      = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleChart_SetShowNegBubbles]      = function(oClass, value){oClass.showNegBubbles  = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleChart_SetSizeRepresents]      = function(oClass, value){oClass.sizeRepresents  = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleChart_SetVaryColors]          = function(oClass, value){oClass.varyColors      = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleSeries_SetBubble3D]           = function(oClass, value){oClass.bubble3D        = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleSeries_SetBubbleSize]         = function(oClass, value){oClass.bubbleSize      = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleSeries_SetDLbls]              = function(oClass, value){oClass.dLbls           = value;};

    drawingsChangesMap[AscDFH.historyitem_BubbleSeries_SetErrBars]            = function(oClass, value){oClass.errBars         = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleSeries_SetIdx]                = function(oClass, value){oClass.idx             = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleSeries_SetInvertIfNegative]   = function(oClass, value){oClass.invertIfNegative = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleSeries_SetOrder]              = function(oClass, value){oClass.order           = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleSeries_SetSpPr]               = function(oClass, value){oClass.spPr           = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleSeries_SetTrendline]          = function(oClass, value){oClass.trendline       = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleSeries_SetTx]                 = function(oClass, value){oClass.tx              = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleSeries_SetXVal]               = function(oClass, value){oClass.xVal            = value;};
    drawingsChangesMap[AscDFH.historyitem_BubbleSeries_SetYVal]               = function(oClass, value){oClass.yVal            = value;};
    drawingsChangesMap[AscDFH.historyitem_Cat_SetMultiLvlStrRef]              = function(oClass, value){oClass.multiLvlStrRef = value;};
    drawingsChangesMap[AscDFH.historyitem_Cat_SetNumLit]                      = function(oClass, value){oClass.numLit        = value;};
    drawingsChangesMap[AscDFH.historyitem_Cat_SetNumRef]                      = function(oClass, value){oClass.numRef        = value;};
    drawingsChangesMap[AscDFH.historyitem_Cat_SetStrLit]                      = function(oClass, value){oClass.strLit        = value;};
    drawingsChangesMap[AscDFH.historyitem_Cat_SetStrRef]                      = function(oClass, value){oClass.strRef        = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartText_SetRich]                  = function(oClass, value){oClass.rich = value;};
    drawingsChangesMap[AscDFH.historyitem_ChartText_SetStrRef]                = function(oClass, value){oClass.strRef = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbls_SetDelete]                    = function(oClass, value){oClass.bDelete = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbls_SetDLblPos]                   = function(oClass, value){oClass.dLblPos        = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbls_SetLeaderLines]               = function(oClass, value){oClass.leaderLines    = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbls_SetNumFmt]                    = function(oClass, value){oClass.numFmt         = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbls_SetSeparator]                 = function(oClass, value){oClass.separator      = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbls_SetShowBubbleSize]            = function(oClass, value){oClass.showBubbleSize = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbls_SetShowCatName]               = function(oClass, value){oClass.showCatName    = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbls_SetShowLeaderLines]           = function(oClass, value){oClass.showLeaderLines = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbls_SetShowLegendKey]             = function(oClass, value){oClass.showLegendKey  = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbls_SetShowPercent]               = function(oClass, value){oClass.showPercent    = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbls_SetShowSerName]               = function(oClass, value){oClass.showSerName    = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbls_SetShowVal]                   = function(oClass, value){oClass.showVal        = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbls_SetSpPr]                      = function(oClass, value){oClass.spPr           = value;};
    drawingsChangesMap[AscDFH.historyitem_DLbls_SetTxPr]                      = function(oClass, value){oClass.txPr           = value;};
    drawingsChangesMap[AscDFH.historyitem_DPt_SetBubble3D]                    = function(oClass, value){oClass.bubble3D        = value;};
    drawingsChangesMap[AscDFH.historyitem_DPt_SetExplosion]                   = function(oClass, value){oClass.explosion       = value;};
    drawingsChangesMap[AscDFH.historyitem_DPt_SetIdx]                         = function(oClass, value){oClass.idx             = value;};
    drawingsChangesMap[AscDFH.historyitem_DPt_SetInvertIfNegative]            = function(oClass, value){oClass.invertIfNegative = value;};
    drawingsChangesMap[AscDFH.historyitem_DPt_SetMarker]                      = function(oClass, value){oClass.marker          = value;};
    drawingsChangesMap[AscDFH.historyitem_DPt_SetPictureOptions]              = function(oClass, value){oClass.pictureOptions  = value;};
    drawingsChangesMap[AscDFH.historyitem_DPt_SetSpPr]                        = function(oClass, value){oClass.spPr            = value;};
    drawingsChangesMap[AscDFH.historyitem_DTable_SetShowHorzBorder]           = function(oClass, value){oClass.showHorzBorder = value;};
    drawingsChangesMap[AscDFH.historyitem_DTable_SetShowKeys]                 = function(oClass, value){oClass.showKeys       = value;};
    drawingsChangesMap[AscDFH.historyitem_DTable_SetShowOutline]              = function(oClass, value){oClass.showOutline    = value;};
    drawingsChangesMap[AscDFH.historyitem_DTable_SetShowVertBorder]           = function(oClass, value){oClass.showVertBorder = value;};
    drawingsChangesMap[AscDFH.historyitem_DTable_SetSpPr]                     = function(oClass, value){oClass.spPr           = value;};
    drawingsChangesMap[AscDFH.historyitem_DTable_SetTxPr]                     = function(oClass, value){oClass.txPr           = value;};
    drawingsChangesMap[AscDFH.historyitem_DispUnitsSetParent]                 = function(oClass, value){oClass.parent         = value;};
    drawingsChangesMap[AscDFH.historyitem_DispUnitsSetBuiltInUnit]            = function(oClass, value){oClass.builtInUnit    = value;};
    drawingsChangesMap[AscDFH.historyitem_DispUnitsSetCustUnit]               = function(oClass, value){oClass.custUnit       = value;};
    drawingsChangesMap[AscDFH.historyitem_DispUnitsSetDispUnitsLbl]           = function(oClass, value){oClass.dispUnitsLbl   = value;};
    drawingsChangesMap[AscDFH.historyitem_DoughnutChart_SetDLbls]             = function(oClass, value){oClass.dLbls         = value;};
    drawingsChangesMap[AscDFH.historyitem_DoughnutChart_SetFirstSliceAng]     = function(oClass, value){oClass.firstSliceAng = value;};
    drawingsChangesMap[AscDFH.historyitem_DoughnutChart_SetHoleSize]          = function(oClass, value){oClass.holeSize     = value;};
    drawingsChangesMap[AscDFH.historyitem_DoughnutChart_SetVaryColor]         = function(oClass, value){oClass.varyColors = value;};
    drawingsChangesMap[AscDFH.historyitem_ErrBars_SetErrBarType]              = function(oClass, value){oClass.errBarType   = value;};
    drawingsChangesMap[AscDFH.historyitem_ErrBars_SetErrDir]                  = function(oClass, value){oClass.errDir       = value;};
    drawingsChangesMap[AscDFH.historyitem_ErrBars_SetErrValType]              = function(oClass, value){oClass.errValType   = value;};
    drawingsChangesMap[AscDFH.historyitem_ErrBars_SetMinus]                   = function(oClass, value){oClass.minus        = value;};
    drawingsChangesMap[AscDFH.historyitem_ErrBars_SetNoEndCap]                = function(oClass, value){oClass.noEndCap     = value;};
    drawingsChangesMap[AscDFH.historyitem_ErrBars_SetPlus]                    = function(oClass, value){oClass.plus         = value;};
    drawingsChangesMap[AscDFH.historyitem_ErrBars_SetSpPr]                    = function(oClass, value){oClass.spPr         = value;};
    drawingsChangesMap[AscDFH.historyitem_ErrBars_SetVal]                     = function(oClass, value){oClass.val          = value;};
    drawingsChangesMap[AscDFH.historyitem_Layout_SetH]                        = function(oClass, value){oClass.h            = value;};
    drawingsChangesMap[AscDFH.historyitem_Layout_SetHMode]                    = function(oClass, value){oClass.hMode        = value;};
    drawingsChangesMap[AscDFH.historyitem_Layout_SetLayoutTarget]             = function(oClass, value){oClass.layoutTarget = value;};
    drawingsChangesMap[AscDFH.historyitem_Layout_SetW]                        = function(oClass, value){oClass.w            = value;};
    drawingsChangesMap[AscDFH.historyitem_Layout_SetWMode]                    = function(oClass, value){oClass.wMode        = value;};
    drawingsChangesMap[AscDFH.historyitem_Layout_SetX]                        = function(oClass, value){oClass.x            = value;};
    drawingsChangesMap[AscDFH.historyitem_Layout_SetXMode]                    = function(oClass, value){oClass.xMode        = value;};
    drawingsChangesMap[AscDFH.historyitem_Layout_SetY]                        = function(oClass, value){oClass.y            = value;};
    drawingsChangesMap[AscDFH.historyitem_Layout_SetYMode]                    = function(oClass, value){oClass.yMode        = value;};
    drawingsChangesMap[AscDFH.historyitem_Legend_SetLayout]                   = function(oClass, value){oClass.layout       = value;};
    drawingsChangesMap[AscDFH.historyitem_Legend_SetLegendPos]                = function(oClass, value){oClass.legendPos  = value;};
    drawingsChangesMap[AscDFH.historyitem_Legend_SetOverlay]                  = function(oClass, value){oClass.overlay   = value;};
    drawingsChangesMap[AscDFH.historyitem_Legend_SetSpPr]                     = function(oClass, value){oClass.spPr      = value;};
    drawingsChangesMap[AscDFH.historyitem_Legend_SetTxPr]                     = function(oClass, value){oClass.txPr      = value;};
    drawingsChangesMap[AscDFH.historyitem_LegendEntry_SetDelete]              = function(oClass, value){oClass.delete = value;};
    drawingsChangesMap[AscDFH.historyitem_LegendEntry_SetIdx]                 = function(oClass, value){oClass.idx    = value;};
    drawingsChangesMap[AscDFH.historyitem_LegendEntry_SetTxPr]                = function(oClass, value){oClass.txPr   = value;};
    drawingsChangesMap[AscDFH.historyitem_LineChart_SetDLbls]                 = function(oClass, value){oClass.dLbls      = value;};
    drawingsChangesMap[AscDFH.historyitem_LineChart_SetDropLines]             = function(oClass, value){oClass.dropLines  = value;};
    drawingsChangesMap[AscDFH.historyitem_LineChart_SetGrouping]              = function(oClass, value){oClass.grouping   = value;};
    drawingsChangesMap[AscDFH.historyitem_LineChart_SetHiLowLines]            = function(oClass, value){oClass.hiLowLines = value;};
    drawingsChangesMap[AscDFH.historyitem_LineChart_SetMarker]                = function(oClass, value){oClass.marker     = value;};
    drawingsChangesMap[AscDFH.historyitem_LineChart_SetSmooth]                = function(oClass, value){oClass.smooth      = value;};
    drawingsChangesMap[AscDFH.historyitem_LineChart_SetUpDownBars]            = function(oClass, value){oClass.upDownBars  = value;};
    drawingsChangesMap[AscDFH.historyitem_LineChart_SetVaryColors]            = function(oClass, value){oClass.varyColors  = value;};
    drawingsChangesMap[AscDFH.historyitem_LineSeries_SetCat]                  = function(oClass, value){oClass.cat      = value;};
    drawingsChangesMap[AscDFH.historyitem_LineSeries_SetDLbls]                = function(oClass, value){oClass.dLbls    = value;};
    drawingsChangesMap[AscDFH.historyitem_LineSeries_SetErrBars]              = function(oClass, value){oClass.errBars  = value;};
    drawingsChangesMap[AscDFH.historyitem_LineSeries_SetIdx]                  = function(oClass, value){oClass.idx      = value;};
    drawingsChangesMap[AscDFH.historyitem_LineSeries_SetMarker]               = function(oClass, value){oClass.marker   = value;};
    drawingsChangesMap[AscDFH.historyitem_LineSeries_SetOrder]                = function(oClass, value){oClass.order    = value;};
    drawingsChangesMap[AscDFH.historyitem_LineSeries_SetSmooth]               = function(oClass, value){oClass.smooth   = value;};
    drawingsChangesMap[AscDFH.historyitem_LineSeries_SetSpPr]                 = function(oClass, value){oClass.spPr     = value;};
    drawingsChangesMap[AscDFH.historyitem_LineSeries_SetTrendline]            = function(oClass, value){oClass.trendline = value;};
    drawingsChangesMap[AscDFH.historyitem_LineSeries_SetTx]                   = function(oClass, value){oClass.tx       = value;};
    drawingsChangesMap[AscDFH.historyitem_LineSeries_SetVal]                  = function(oClass, value){oClass.val      = value;};
    drawingsChangesMap[AscDFH.historyitem_Marker_SetSize]                     = function(oClass, value){oClass.size = value;};
    drawingsChangesMap[AscDFH.historyitem_Marker_SetSpPr]                     = function(oClass, value){oClass.spPr = value;};
    drawingsChangesMap[AscDFH.historyitem_Marker_SetSymbol]                   = function(oClass, value){oClass.symbol = value;};
    drawingsChangesMap[AscDFH.historyitem_MinusPlus_SetnNumLit]               = function(oClass, value){oClass.numLit = value;};
    drawingsChangesMap[AscDFH.historyitem_MinusPlus_SetnNumRef]               = function(oClass, value){oClass.numRef = value;};
    drawingsChangesMap[AscDFH.historyitem_MultiLvlStrRef_SetF]                = function(oClass, value){oClass.f                = value;};
    drawingsChangesMap[AscDFH.historyitem_MultiLvlStrRef_SetMultiLvlStrCache] = function(oClass, value){oClass.multiLvlStrCache = value;};
    drawingsChangesMap[AscDFH.historyitem_NumRef_SetF]                        = function(oClass, value){oClass.f       = value;};
    drawingsChangesMap[AscDFH.historyitem_NumRef_SetNumCache]                 = function(oClass, value){oClass.numCache = value;};
    drawingsChangesMap[AscDFH.historyitem_NumericPoint_SetFormatCode]         = function(oClass, value){oClass.formatCode = value;};
    drawingsChangesMap[AscDFH.historyitem_NumericPoint_SetIdx]                = function(oClass, value){oClass.idx        = value;};
    drawingsChangesMap[AscDFH.historyitem_NumericPoint_SetVal]                = function(oClass, value){oClass.val        = value;};
    drawingsChangesMap[AscDFH.historyitem_NumFmt_SetFormatCode]               = function(oClass, value){oClass.formatCode  = value;};
    drawingsChangesMap[AscDFH.historyitem_NumFmt_SetSourceLinked]             = function(oClass, value){oClass.sourceLinked = value;};
    drawingsChangesMap[AscDFH.historyitem_NumLit_SetFormatCode]               = function(oClass, value){oClass.formatCode = value;};
    drawingsChangesMap[AscDFH.historyitem_NumLit_SetPtCount]                  = function(oClass, value){oClass.ptCount = value;};
    drawingsChangesMap[AscDFH.historyitem_OfPieChart_SetDLbls]                = function(oClass, value){oClass.dLbls = value;};
    drawingsChangesMap[AscDFH.historyitem_OfPieChart_SetGapWidth]             = function(oClass, value){oClass.gapWidth = value;};
    drawingsChangesMap[AscDFH.historyitem_OfPieChart_SetOfPieType]            = function(oClass, value){oClass.ofPieType = value;};
    drawingsChangesMap[AscDFH.historyitem_OfPieChart_SetSecondPieSize]        = function(oClass, value){oClass.secondPieSize = value;};
    drawingsChangesMap[AscDFH.historyitem_OfPieChart_SetSerLines]             = function(oClass, value){oClass.serLines   = value;};
    drawingsChangesMap[AscDFH.historyitem_OfPieChart_SetSplitPos]             = function(oClass, value){oClass.splitPos   = value;};
    drawingsChangesMap[AscDFH.historyitem_OfPieChart_SetSplitType]            = function(oClass, value){oClass.splitType  = value;};
    drawingsChangesMap[AscDFH.historyitem_OfPieChart_SetVaryColors]           = function(oClass, value){oClass.varyColors = value;};
    drawingsChangesMap[AscDFH.historyitem_PictureOptions_SetApplyToEnd]       = function(oClass, value){oClass.applyToEnd         = value;};
    drawingsChangesMap[AscDFH.historyitem_PictureOptions_SetApplyToFront]     = function(oClass, value){oClass.applyToFront       = value;};
    drawingsChangesMap[AscDFH.historyitem_PictureOptions_SetApplyToSides]     = function(oClass, value){oClass.applyToSides       = value;};
    drawingsChangesMap[AscDFH.historyitem_PictureOptions_SetPictureFormat]    = function(oClass, value){oClass.pictureFormat      = value;};
    drawingsChangesMap[AscDFH.historyitem_PictureOptions_SetPictureStackUnit] = function(oClass, value){oClass.pictureStackUnit   = value;};
    drawingsChangesMap[AscDFH.historyitem_PieChart_SetDLbls]                  = function(oClass, value){oClass.dLbls          = value;};
    drawingsChangesMap[AscDFH.historyitem_PieChart_SetFirstSliceAng]          = function(oClass, value){oClass.firstSliceAng  = value;};
    drawingsChangesMap[AscDFH.historyitem_PieChart_SetVaryColors]             = function(oClass, value){oClass.varyColors = value;};
    drawingsChangesMap[AscDFH.historyitem_PieSeries_SetCat]                   = function(oClass, value){oClass.cat       = value;};
    drawingsChangesMap[AscDFH.historyitem_PieSeries_SetDLbls]                 = function(oClass, value){oClass.dLbls     = value;};
    drawingsChangesMap[AscDFH.historyitem_PieSeries_SetExplosion]             = function(oClass, value){oClass.explosion = value;};
    drawingsChangesMap[AscDFH.historyitem_PieSeries_SetIdx]                   = function(oClass, value){oClass.idx       = value;};
    drawingsChangesMap[AscDFH.historyitem_PieSeries_SetOrder]                 = function(oClass, value){oClass.order     = value;};
    drawingsChangesMap[AscDFH.historyitem_PieSeries_SetSpPr]                  = function(oClass, value){oClass.spPr      = value;};
    drawingsChangesMap[AscDFH.historyitem_PieSeries_SetTx]                    = function(oClass, value){oClass.tx        = value;};
    drawingsChangesMap[AscDFH.historyitem_PieSeries_SetVal]                   = function(oClass, value){oClass.val       = value;};
    drawingsChangesMap[AscDFH.historyitem_PivotFmt_SetDLbl]                   = function(oClass, value){oClass.dLbl    = value;};
    drawingsChangesMap[AscDFH.historyitem_PivotFmt_SetIdx]                    = function(oClass, value){oClass.idx     = value;};
    drawingsChangesMap[AscDFH.historyitem_PivotFmt_SetMarker]                 = function(oClass, value){oClass.marker  = value;};
    drawingsChangesMap[AscDFH.historyitem_PivotFmt_SetSpPr]                   = function(oClass, value){oClass.spPr    = value;};
    drawingsChangesMap[AscDFH.historyitem_PivotFmt_SetTxPr]                   = function(oClass, value){oClass.txPr    = value;};
    drawingsChangesMap[AscDFH.historyitem_RadarChart_SetDLbls]                = function(oClass, value){oClass.dLbls       =  value;};
    drawingsChangesMap[AscDFH.historyitem_RadarChart_SetRadarStyle]           = function(oClass, value){oClass.radarStyle  =  value;};
    drawingsChangesMap[AscDFH.historyitem_RadarChart_SetVaryColors]           = function(oClass, value){oClass.varyColors = value;};
    drawingsChangesMap[AscDFH.historyitem_RadarSeries_SetCat]              = function(oClass, value){oClass.cat     = value;};
    drawingsChangesMap[AscDFH.historyitem_RadarSeries_SetDLbls]              = function(oClass, value){oClass.dLbls   = value;};
    drawingsChangesMap[AscDFH.historyitem_RadarSeries_SetIdx]              = function(oClass, value){oClass.idx     = value;};
    drawingsChangesMap[AscDFH.historyitem_RadarSeries_SetMarker]              = function(oClass, value){oClass.marker  = value;};
    drawingsChangesMap[AscDFH.historyitem_RadarSeries_SetOrder]              = function(oClass, value){oClass.order   = value;};
    drawingsChangesMap[AscDFH.historyitem_RadarSeries_SetSpPr]              = function(oClass, value){oClass.spPr    = value;};
    drawingsChangesMap[AscDFH.historyitem_RadarSeries_SetTx]              = function(oClass, value){oClass.tx      = value;};
    drawingsChangesMap[AscDFH.historyitem_RadarSeries_SetVal]              = function(oClass, value){oClass.val     = value;};
    drawingsChangesMap[AscDFH.historyitem_Scaling_SetParent]                  = function(oClass, value){oClass.parent      = value;};
    drawingsChangesMap[AscDFH.historyitem_Scaling_SetLogBase]                 = function(oClass, value){oClass.logBase     = value;};
    drawingsChangesMap[AscDFH.historyitem_Scaling_SetMax]                     = function(oClass, value){oClass.max         = value;};
    drawingsChangesMap[AscDFH.historyitem_Scaling_SetMin]                     = function(oClass, value){oClass.min         = value;};
    drawingsChangesMap[AscDFH.historyitem_Scaling_SetOrientation]             = function(oClass, value){oClass.orientation  = value;};
    drawingsChangesMap[AscDFH.historyitem_ScatterChart_SetDLbls]              = function(oClass, value){oClass.dLbls        =  value;};
    drawingsChangesMap[AscDFH.historyitem_ScatterChart_SetScatterStyle]       = function(oClass, value){oClass.scatterStyle =  value;};
    drawingsChangesMap[AscDFH.historyitem_ScatterChart_SetVaryColors]         = function(oClass, value){oClass.varyColors =  value;};
    drawingsChangesMap[AscDFH.historyitem_ScatterSer_SetDLbls]                 =  function(oClass, value){oClass.dLbls     = value;};

    drawingsChangesMap[AscDFH.historyitem_ScatterSer_SetErrBars]               =  function(oClass, value){oClass.errBars   = value;};
    drawingsChangesMap[AscDFH.historyitem_ScatterSer_SetIdx]                   =  function(oClass, value){oClass.idx       = value;};
    drawingsChangesMap[AscDFH.historyitem_ScatterSer_SetMarker]                =  function(oClass, value){oClass.marker    = value;};
    drawingsChangesMap[AscDFH.historyitem_ScatterSer_SetOrder]                 =  function(oClass, value){oClass.order    = value;};
    drawingsChangesMap[AscDFH.historyitem_ScatterSer_SetSmooth]                =  function(oClass, value){oClass.smooth    = value;};
    drawingsChangesMap[AscDFH.historyitem_ScatterSer_SetSpPr]                  =  function(oClass, value){oClass.spPr      = value;};
    drawingsChangesMap[AscDFH.historyitem_ScatterSer_SetTrendline]             =  function(oClass, value){oClass.trendline  = value;};
    drawingsChangesMap[AscDFH.historyitem_ScatterSer_SetTx]                    =  function(oClass, value){oClass.tx        = value;};
    drawingsChangesMap[AscDFH.historyitem_ScatterSer_SetXVal]                  =  function(oClass, value){oClass.xVal      = value;};
    drawingsChangesMap[AscDFH.historyitem_ScatterSer_SetYVal]                  =  function(oClass, value){oClass.yVal      = value;};
    drawingsChangesMap[AscDFH.historyitem_Tx_SetStrRef]                        =  function(oClass, value){oClass.strRef     = value;};
    drawingsChangesMap[AscDFH.historyitem_Tx_SetVal]                           =  function(oClass, value){oClass.val        = value;};
    drawingsChangesMap[AscDFH.historyitem_StockChart_SetDLbls]                 = function(oClass, value){oClass.dLbls     = value;};
    drawingsChangesMap[AscDFH.historyitem_StockChart_SetDropLines]             = function(oClass, value){oClass.dropLines = value;};
    drawingsChangesMap[AscDFH.historyitem_StockChart_SetHiLowLines]            = function(oClass, value){oClass.hiLowLines = value;};
    drawingsChangesMap[AscDFH.historyitem_StockChart_SetUpDownBars]            = function(oClass, value){oClass.upDownBars = value;};
    drawingsChangesMap[AscDFH.historyitem_StrCache_SetPtCount]                 = function(oClass, value){oClass.ptCount = value;};
    drawingsChangesMap[AscDFH.historyitem_StrPoint_SetIdx]                     = function(oClass, value){oClass.idx =  value;};
    drawingsChangesMap[AscDFH.historyitem_StrPoint_SetVal]                     = function(oClass, value){oClass.val =  value;};
    drawingsChangesMap[AscDFH.historyitem_StrRef_SetF]                          = function(oClass, value){oClass.f =  value;};
    drawingsChangesMap[AscDFH.historyitem_StrRef_SetStrCache]                   = function(oClass, value){oClass.strCache =  value;};
    drawingsChangesMap[AscDFH.historyitem_SurfaceChart_SetWireframe]              = function(oClass, value){oClass.wireframe =  value;};
    drawingsChangesMap[AscDFH.historyitem_SurfaceSeries_SetCat]                    = function(oClass, value){oClass.cat   =  value;};
    drawingsChangesMap[AscDFH.historyitem_SurfaceSeries_SetIdx]                    = function(oClass, value){oClass.idx   =  value;};
    drawingsChangesMap[AscDFH.historyitem_SurfaceSeries_SetOrder]                  = function(oClass, value){oClass.order =  value;};
    drawingsChangesMap[AscDFH.historyitem_SurfaceSeries_SetSpPr]                   = function(oClass, value){oClass.spPr  =  value;};
    drawingsChangesMap[AscDFH.historyitem_SurfaceSeries_SetTx]                     = function(oClass, value){oClass.tx    =  value;};
    drawingsChangesMap[AscDFH.historyitem_SurfaceSeries_SetVal]                    = function(oClass, value){oClass.val   =  value;};
    drawingsChangesMap[AscDFH.historyitem_Title_SetLayout]                         = function(oClass, value){oClass.layout  =  value;};
    drawingsChangesMap[AscDFH.historyitem_Title_SetOverlay]                        = function(oClass, value){oClass.overlay =  value;};
    drawingsChangesMap[AscDFH.historyitem_Title_SetSpPr]                           = function(oClass, value){oClass.spPr    =  value;};
    drawingsChangesMap[AscDFH.historyitem_Title_SetTx]                             = function(oClass, value){oClass.tx      =  value;};
    drawingsChangesMap[AscDFH.historyitem_Title_SetTxPr]                           = function(oClass, value){oClass.txPr    =  value;};
    drawingsChangesMap[AscDFH.historyitem_Trendline_SetBackward]                     = function(oClass, value){oClass.backward      =  value;};
    drawingsChangesMap[AscDFH.historyitem_Trendline_SetDispEq]                       = function(oClass, value){oClass.dispEq        =  value;};
    drawingsChangesMap[AscDFH.historyitem_Trendline_SetDispRSqr]                     = function(oClass, value){oClass.dispRSqr      =  value;};
    drawingsChangesMap[AscDFH.historyitem_Trendline_SetForward]                      = function(oClass, value){oClass.forward       =  value;};
    drawingsChangesMap[AscDFH.historyitem_Trendline_SetIntercept]                    = function(oClass, value){oClass.intercept     =  value;};
    drawingsChangesMap[AscDFH.historyitem_Trendline_SetName]                         = function(oClass, value){oClass.name          =  value;};
    drawingsChangesMap[AscDFH.historyitem_Trendline_SetOrder]                        = function(oClass, value){oClass.order         =  value;};
    drawingsChangesMap[AscDFH.historyitem_Trendline_SetPeriod]                       = function(oClass, value){oClass.period        =  value;};
    drawingsChangesMap[AscDFH.historyitem_Trendline_SetSpPr]                         = function(oClass, value){oClass.spPr          =  value;};
    drawingsChangesMap[AscDFH.historyitem_Trendline_SetTrendlineLbl]                 = function(oClass, value){oClass.trendlineLbl  =  value;};
    drawingsChangesMap[AscDFH.historyitem_Trendline_SetTrendlineType]                = function(oClass, value){oClass.trendlineType =  value;};
    drawingsChangesMap[AscDFH.historyitem_UpDownBars_SetDownBars]                    = function(oClass, value){oClass.downBars =  value;};
    drawingsChangesMap[AscDFH.historyitem_UpDownBars_SetGapWidth]                    = function(oClass, value){oClass.gapWidth =  value;};
    drawingsChangesMap[AscDFH.historyitem_UpDownBars_SetUpBars]                      = function(oClass, value){oClass.upBars   =  value;};
    drawingsChangesMap[AscDFH.historyitem_XVal_SetMultiLvlStrRef]                    = function(oClass, value){oClass.multiLvlStrRef =  value;};
    drawingsChangesMap[AscDFH.historyitem_XVal_SetNumLit]                            = function(oClass, value){oClass.numLit         =  value;};
    drawingsChangesMap[AscDFH.historyitem_XVal_SetNumRef]                            = function(oClass, value){oClass.numRef         =  value;};
    drawingsChangesMap[AscDFH.historyitem_XVal_SetStrLit]                            = function(oClass, value){oClass.strLit         =  value;};
    drawingsChangesMap[AscDFH.historyitem_XVal_SetStrRef]                            = function(oClass, value){oClass.strRef         =  value;};
    drawingsChangesMap[AscDFH.historyitem_YVal_SetNumLit]                             = function(oClass, value){oClass.numLit =  value;};
    drawingsChangesMap[AscDFH.historyitem_YVal_SetNumRef]                             = function(oClass, value){oClass.numRef =  value;};
    drawingsChangesMap[AscDFH.historyitem_Chart_SetAutoTitleDeleted]                  = function(oClass, value){oClass.autoTitleDeleted =  value;};
    drawingsChangesMap[AscDFH.historyitem_Chart_SetBackWall]                          = function(oClass, value){oClass.backWall         =  value;};
    drawingsChangesMap[AscDFH.historyitem_Chart_SetDispBlanksAs]                      = function(oClass, value){oClass.dispBlanksAs     =  value;};
    drawingsChangesMap[AscDFH.historyitem_Chart_SetFloor]                             = function(oClass, value){oClass.floor            =  value;};
    drawingsChangesMap[AscDFH.historyitem_Chart_SetLegend]                            = function(oClass, value){oClass.legend           =  value;};
    drawingsChangesMap[AscDFH.historyitem_Chart_SetPlotArea]                           = function(oClass, value){oClass.plotArea         =  value;};
    drawingsChangesMap[AscDFH.historyitem_Chart_SetPlotVisOnly]                        = function(oClass, value){oClass.plotVisOnly      =  value;};
    drawingsChangesMap[AscDFH.historyitem_Chart_SetShowDLblsOverMax]                   = function(oClass, value){oClass.showDLblsOverMax =  value;};
    drawingsChangesMap[AscDFH.historyitem_Chart_SetSideWall]                           = function(oClass, value){oClass.sideWall         =  value;};
    drawingsChangesMap[AscDFH.historyitem_Chart_SetTitle]                              = function(oClass, value){oClass.title            =  value;};
    drawingsChangesMap[AscDFH.historyitem_Chart_SetView3D]                             = function(oClass, value){oClass.view3D           =  value; oClass.Refresh_RecalcData();};
    drawingsChangesMap[AscDFH.historyitem_ChartWall_SetPictureOptions]                   = function(oClass, value){oClass.pictureOptions  =  value;};
    drawingsChangesMap[AscDFH.historyitem_ChartWall_SetSpPr]                             = function(oClass, value){oClass.spPr            =  value;};
    drawingsChangesMap[AscDFH.historyitem_ChartWall_SetThickness]                        = function(oClass, value){oClass.thickness       =  value;};
    drawingsChangesMap[AscDFH.historyitem_View3d_SetDepthPercent]                        = function(oClass, value){oClass.depthPercent  =  value; oClass.Refresh_RecalcData();};
    drawingsChangesMap[AscDFH.historyitem_View3d_SetHPercent]                            = function(oClass, value){oClass.hPercent      =  value; oClass.Refresh_RecalcData();};
    drawingsChangesMap[AscDFH.historyitem_View3d_SetPerspective]                         = function(oClass, value){oClass.perspective   =  value; oClass.Refresh_RecalcData();};
    drawingsChangesMap[AscDFH.historyitem_View3d_SetRAngAx]                              = function(oClass, value){oClass.rAngAx        =  value; oClass.Refresh_RecalcData();};
    drawingsChangesMap[AscDFH.historyitem_View3d_SetRotX]                                = function(oClass, value){oClass.rotX          =  value; oClass.Refresh_RecalcData();};
    drawingsChangesMap[AscDFH.historyitem_View3d_SetRotY]                                = function(oClass, value){oClass.rotY          =  value; oClass.Refresh_RecalcData();};



    AscDFH.changesFactory[AscDFH.historyitem_DLbl_SetDelete                  ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DLbl_SetShowBubbleSize          ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DLbl_SetShowCatName             ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DLbl_SetShowLegendKey           ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DLbl_SetShowPercent             ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DLbl_SetShowSerName             ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DLbl_SetShowVal                 ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_BarChart_Set3D                  ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_BarChart_SetVaryColors          ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_AreaChart_SetVaryColors         ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetAuto                    ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetDelete                  ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetNoMultiLvlLbl           ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxAuto                      ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxDelete                    ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetDelete                  ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetDelete                  ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_BarSeries_SetInvertIfNegative   ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleChart_SetBubble3D         ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleChart_SetShowNegBubbles   ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleChart_SetVaryColors       ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleSeries_SetBubble3D        ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleSeries_SetInvertIfNegative] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DLbls_SetDelete                 ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DLbls_SetShowBubbleSize         ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DLbls_SetShowCatName            ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DLbls_SetShowLeaderLines        ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DLbls_SetShowLegendKey          ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DLbls_SetShowPercent            ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DLbls_SetShowSerName            ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DLbls_SetShowVal                ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DPt_SetBubble3D                 ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DPt_SetInvertIfNegative         ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DTable_SetShowHorzBorder        ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DTable_SetShowKeys              ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DTable_SetShowOutline           ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DTable_SetShowVertBorder        ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_DoughnutChart_SetVaryColor      ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_ErrBars_SetNoEndCap             ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_Legend_SetOverlay               ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_LegendEntry_SetDelete           ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_LineChart_SetMarker             ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_LineChart_SetSmooth             ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_LineChart_SetVaryColors         ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_LineSeries_SetSmooth            ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_NumFmt_SetSourceLinked          ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_OfPieChart_SetVaryColors        ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_PieChart_SetVaryColors          ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_RadarChart_SetVaryColors        ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterChart_SetVaryColors      ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterSer_SetSmooth            ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_SurfaceChart_SetWireframe       ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_Title_SetOverlay                ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_Trendline_SetDispEq             ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_Trendline_SetDispRSqr           ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_Chart_SetAutoTitleDeleted       ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_Chart_SetPlotVisOnly            ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_Chart_SetShowDLblsOverMax       ] = window['AscDFH'].CChangesDrawingsBool;
    AscDFH.changesFactory[AscDFH.historyitem_View3d_SetRAngAx                ] = window['AscDFH'].CChangesDrawingsBool;

    AscDFH.changesFactory[AscDFH.historyitem_DLbl_SetDLblPos                  ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_DLbl_SetIdx                      ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_BarChart_SetGapDepth             ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_BarChart_SetShape                ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_BarChart_SetBarDir               ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_BarChart_SetGapWidth             ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_BarChart_SetGrouping             ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_BarChart_SetOverlap              ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_AreaChart_SetGrouping            ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_AreaSeries_SetIdx                ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_AreaSeries_SetOrder              ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetAxId                     ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetAxPos                    ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetCrosses                  ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetLblAlgn                  ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetLblOffset                ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetMajorTickMark            ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetMinorTickMark            ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetTickLblPos               ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetTickLblSkip              ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetTickMarkSkip             ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxAxPos                      ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxCrosses                    ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxLblOffset                  ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxMajorTickMark              ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxMinorTickMark              ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxTickLblPos                 ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetAxId                     ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetAxPos                    ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetMajorTickMark            ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetMinorTickMark            ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetTickLblPos               ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetTickLblSkip              ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetTickMarkSkip             ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetAxId                     ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetAxPos                    ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetCrossBetween             ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetMajorTickMark            ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetMinorTickMark            ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetTickLblPos               ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_BandFmt_SetIdx                   ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_BarSeries_SetIdx                 ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_BarSeries_SetOrder               ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleChart_SetBubbleScale       ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleChart_SetSizeRepresents    ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleSeries_SetIdx              ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleSeries_SetOrder            ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_DLbls_SetDLblPos                 ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_DPt_SetExplosion                 ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_DPt_SetIdx                       ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_DispUnitsSetParent               ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_DoughnutChart_SetFirstSliceAng   ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_DoughnutChart_SetHoleSize        ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_ErrBars_SetErrBarType            ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_ErrBars_SetErrDir                ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_ErrBars_SetErrValType            ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_Layout_SetHMode                  ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_Layout_SetLayoutTarget           ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_Layout_SetWMode                  ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_Layout_SetXMode                  ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_Layout_SetYMode                  ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_Legend_SetLegendPos              ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_LegendEntry_SetIdx               ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_LineChart_SetGrouping            ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_LineSeries_SetIdx                ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_LineSeries_SetOrder              ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_Marker_SetSize                   ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_Marker_SetSymbol                 ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_MultiLvlStrCache_SetPtCount      ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_NumLit_SetPtCount                ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_OfPieChart_SetGapWidth           ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_OfPieChart_SetOfPieType          ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_OfPieChart_SetSecondPieSize      ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_OfPieChart_SetSplitType          ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_PictureOptions_SetPictureFormat  ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_PieChart_SetFirstSliceAng        ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_PieSeries_SetExplosion           ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_PieSeries_SetIdx                 ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_PieSeries_SetOrder               ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_PivotFmt_SetIdx                  ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_RadarSeries_SetIdx               ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_Scaling_SetOrientation           ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterChart_SetScatterStyle     ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterSer_SetIdx                ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterSer_SetOrder              ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_StrCache_SetPtCount              ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_StringLiteral_SetPtCount         ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_StrPoint_SetIdx                  ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_SurfaceSeries_SetIdx             ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_SurfaceSeries_SetOrder           ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_Trendline_SetOrder               ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_Trendline_SetPeriod              ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_Trendline_SetTrendlineType       ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_UpDownBars_SetGapWidth           ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_Chart_SetDispBlanksAs            ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_ChartWall_SetThickness           ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_View3d_SetDepthPercent           ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_View3d_SetHPercent               ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_View3d_SetPerspective            ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_View3d_SetRotX                   ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_View3d_SetRotY                   ] = window['AscDFH'].CChangesDrawingsLong;
    AscDFH.changesFactory[AscDFH.historyitem_NumericPoint_SetIdx              ] = window['AscDFH'].CChangesDrawingsLong;


    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetCrossesAt                 ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxBaseTimeUnit                ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxCrossesAt                   ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxMajorTimeUnit               ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxMajorUnit                   ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxMinorTimeUnit               ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxMinorUnit                   ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetCrosses                   ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetCrossesAt                 ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetCrosses                   ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetCrossesAt                 ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetMajorUnit                 ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetMinorUnit                 ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_DispUnitsSetBuiltInUnit           ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_ErrBars_SetVal                    ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Layout_SetH                       ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Layout_SetW                       ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Layout_SetX                       ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Layout_SetY                       ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_OfPieChart_SetSplitPos            ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_PictureOptions_SetPictureStackUnit] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Scaling_SetLogBase                ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Scaling_SetMax                    ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Scaling_SetMin                    ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Trendline_SetBackward             ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Trendline_SetForward              ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_Trendline_SetIntercept            ] = window['AscDFH'].CChangesDrawingsDouble;
    AscDFH.changesFactory[AscDFH.historyitem_NumericPoint_SetVal               ] = window['AscDFH'].CChangesDrawingsDouble2;

    AscDFH.changesFactory[AscDFH.historyitem_DLbl_SetSeparator         ] = window['AscDFH'].CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxAxId                ] = window['AscDFH'].CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_DLbls_SetSeparator        ] = window['AscDFH'].CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_MultiLvlStrRef_SetF       ] = window['AscDFH'].CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_NumRef_SetF               ] = window['AscDFH'].CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_NumericPoint_SetFormatCode] = window['AscDFH'].CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_NumFmt_SetFormatCode      ] = window['AscDFH'].CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_NumLit_SetFormatCode      ] = window['AscDFH'].CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_Tx_SetVal                 ] = window['AscDFH'].CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_StrPoint_SetVal           ] = window['AscDFH'].CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_StrRef_SetF               ] = window['AscDFH'].CChangesDrawingsString;
    AscDFH.changesFactory[AscDFH.historyitem_Trendline_SetName         ] = window['AscDFH'].CChangesDrawingsString;

    AscDFH.changesFactory[AscDFH.historyitem_DLbl_SetLayout                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DLbl_SetNumFmt                        ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DLbl_SetSpPr                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DLbl_SetTx                            ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DLbl_SetTxPr                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PlotArea_SetDTable                    ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PlotArea_SetLayout                    ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PlotArea_SetSpPr                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_CommonChartFormat_SetParent           ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BarChart_SetDLbls                     ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BarChart_SetSerLines                  ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_AreaChart_SetDLbls                    ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_AreaChart_SetDropLines                ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_AreaSeries_SetCat                     ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_AreaSeries_SetDLbls                   ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_AreaSeries_SetErrBars                 ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_AreaSeries_SetPictureOptions          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_AreaSeries_SetSpPr                    ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_AreaSeries_SetTrendline               ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_AreaSeries_SetTx                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_AreaSeries_SetVal                     ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetCrossAx                       ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetMajorGridlines                ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetMinorGridlines                ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetNumFmt                        ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetScaling                       ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetSpPr                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetTitle                         ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_CatAxSetTxPr                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxCrossAx                         ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxMajorGridlines                  ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxMajorGridlines                  ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxNumFmt                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxScaling                         ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxSpPr                            ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxTitle                           ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DateAxTxPr                            ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetCrossAx                       ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetMajorGridlines                ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetMinorGridlines                ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetNumFmt                        ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetScaling                       ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetSpPr                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetTitle                         ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_SerAxSetTxPr                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetCrossAx                       ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetDispUnits                     ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetMajorGridlines                ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetMinorGridlines                ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetNumFmt                        ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetScaling                       ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetSpPr                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetTitle                         ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ValAxSetTxPr                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BandFmt_SetSpPr                       ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BarSeries_SetCat                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BarSeries_SetDLbls                    ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BarSeries_SetErrBars                  ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BarSeries_SetPictureOptions           ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BarSeries_SetShape                    ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BarSeries_SetSpPr                     ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BarSeries_SetTrendline                ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BarSeries_SetTx                       ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BarSeries_SetVal                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleChart_SetDLbls                  ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleSeries_SetBubbleSize            ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleSeries_SetDLbls                 ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleSeries_SetDPt                   ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleSeries_SetErrBars               ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleSeries_SetSpPr                  ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleSeries_SetTrendline             ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleSeries_SetTx                    ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleSeries_SetXVal                  ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleSeries_SetYVal                  ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Cat_SetMultiLvlStrRef                 ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Cat_SetNumLit                         ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Cat_SetNumRef                         ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Cat_SetStrLit                         ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Cat_SetStrRef                         ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ChartFormatSetChart                   ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ChartText_SetRich                     ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ChartText_SetStrRef                   ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DLbls_SetLeaderLines                  ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DLbls_SetNumFmt                       ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DLbls_SetSpPr                         ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DLbls_SetTxPr                         ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DPt_SetMarker                         ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DPt_SetPictureOptions                 ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DPt_SetSpPr                           ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DTable_SetSpPr                        ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DTable_SetTxPr                        ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DispUnitsSetCustUnit                  ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DispUnitsSetDispUnitsLbl              ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_DoughnutChart_SetDLbls                ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ErrBars_SetMinus                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ErrBars_SetPlus                       ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ErrBars_SetSpPr                       ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Legend_SetLayout                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Legend_SetSpPr                        ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Legend_SetTxPr                        ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_LegendEntry_SetTxPr                   ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_LineChart_SetDLbls                    ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_LineChart_SetDropLines                ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_LineChart_SetHiLowLines               ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_LineChart_SetUpDownBars               ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_LineSeries_SetCat                     ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_LineSeries_SetDLbls                   ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_LineSeries_SetErrBars                 ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_LineSeries_SetMarker                  ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_LineSeries_SetSpPr                    ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_LineSeries_SetTrendline               ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_LineSeries_SetTx                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_LineSeries_SetVal                     ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Marker_SetSpPr                        ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_MinusPlus_SetnNumLit                  ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_MinusPlus_SetnNumRef                  ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_MultiLvlStrRef_SetMultiLvlStrCache   ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_NumRef_SetNumCache                    ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_OfPieChart_SetDLbls                   ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_OfPieChart_SetSerLines                ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PictureOptions_SetApplyToEnd          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PictureOptions_SetApplyToFront        ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PictureOptions_SetApplyToSides        ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PieChart_SetDLbls                     ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PieSeries_SetCat                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PieSeries_SetDLbls                    ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PieSeries_SetSpPr                     ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PieSeries_SetTx                         ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PieSeries_SetVal                        ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PivotFmt_SetDLbl                        ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PivotFmt_SetMarker                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PivotFmt_SetSpPr                        ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_PivotFmt_SetTxPr                        ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_RadarChart_SetDLbls                     ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_RadarChart_SetRadarStyle                ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_RadarSeries_SetCat                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_RadarSeries_SetDLbls                    ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_RadarSeries_SetCat                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_RadarSeries_SetCat                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_RadarSeries_SetCat                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_RadarSeries_SetCat                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_RadarSeries_SetCat                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Scaling_SetParent                       ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterChart_SetDLbls                   ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterSer_SetDLbls                     ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterSer_SetDPt                       ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterSer_SetErrBars                   ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterSer_SetMarker                    ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterSer_SetSpPr                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterSer_SetTrendline                 ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterSer_SetTx                        ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterSer_SetXVal                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterSer_SetYVal                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Tx_SetStrRef                            ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_StockChart_SetDLbls                     ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_StockChart_SetDropLines                 ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_StockChart_SetHiLowLines                ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_StockChart_SetUpDownBars                ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_StrRef_SetStrCache                      ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_SurfaceSeries_SetCat                    ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_SurfaceSeries_SetSpPr                   ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_SurfaceSeries_SetTx                     ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_SurfaceSeries_SetVal                    ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Title_SetLayout                         ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Title_SetSpPr                           ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Title_SetTx                             ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Title_SetTxPr                           ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Trendline_SetSpPr                       ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Trendline_SetTrendlineLbl               ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_UpDownBars_SetDownBars                  ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_UpDownBars_SetUpBars                    ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_XVal_SetMultiLvlStrRef                  ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_XVal_SetNumLit                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_XVal_SetNumRef                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_XVal_SetStrLit                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_XVal_SetStrRef                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_YVal_SetNumLit                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_YVal_SetNumRef                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Chart_SetBackWall                       ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Chart_SetFloor                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Chart_SetLegend                         ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Chart_SetPlotArea                       ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Chart_SetSideWall                       ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Chart_SetTitle                          ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_Chart_SetView3D                         ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ChartWall_SetPictureOptions             ] = window['AscDFH'].CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_ChartWall_SetSpPr                       ] = window['AscDFH'].CChangesDrawingsObject;

    AscDFH.changesFactory[AscDFH.historyitem_PlotArea_AddAxis          ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_PlotArea_AddChart         ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_PlotArea_RemoveChart      ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_PlotArea_RemoveAxis       ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_CommonChart_RemoveSeries  ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_BarChart_AddAxId          ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_BarChart_AddSer           ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_AreaChart_AddAxId         ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_AreaChart_AddSer          ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_AreaSeries_SetDPt         ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_CommonSeries_RemoveDPt    ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_BarSeries_SetDPt          ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleChart_AddAxId       ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_BubbleChart_AddSerie      ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_DLbls_SetDLbl             ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_DoughnutChart_AddSer      ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_Legend_AddLegendEntry     ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_LineChart_AddAxId         ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_LineChart_AddSer          ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_LineSeries_SetDPt         ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_MultiLvlStrCache_SetLvl   ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_CommonLit_RemoveDPt       ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_NumLit_AddPt              ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_OfPieChart_AddCustSplit   ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_OfPieChart_AddSer         ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_PieChart_AddSer           ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_PieSeries_SetDPt          ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_RadarChart_AddAxId        ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_RadarChart_AddSer         ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_RadarSeries_SetDPt        ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterChart_AddAxId      ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_ScatterChart_AddSer       ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_StockChart_AddAxId        ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_StockChart_AddSer         ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_CommonLit_RemoveDPt       ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_StrCache_AddPt            ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_StringLiteral_SetPt       ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_SurfaceChart_AddAxId      ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_SurfaceChart_AddBandFmt   ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_SurfaceChart_AddSer       ] = window['AscDFH'].CChangesDrawingsContent;
    AscDFH.changesFactory[AscDFH.historyitem_Chart_AddPivotFmt         ] = window['AscDFH'].CChangesDrawingsContent;


    drawingContentChanges[AscDFH.historyitem_PlotArea_AddAxis] =
    drawingContentChanges[AscDFH.historyitem_BarChart_AddAxId] =
    drawingContentChanges[AscDFH.historyitem_AreaChart_AddAxId] =
    drawingContentChanges[AscDFH.historyitem_BubbleChart_AddAxId] =
    drawingContentChanges[AscDFH.historyitem_LineChart_AddAxId] =
    drawingContentChanges[AscDFH.historyitem_RadarChart_AddAxId] =
    drawingContentChanges[AscDFH.historyitem_ScatterChart_AddAxId] =
    drawingContentChanges[AscDFH.historyitem_StockChart_AddAxId] =
    drawingContentChanges[AscDFH.historyitem_SurfaceChart_AddAxId] =
    drawingContentChanges[AscDFH.historyitem_PlotArea_RemoveAxis]      =  function(oClass){return oClass.axId;};

    drawingContentChanges[AscDFH.historyitem_PlotArea_AddChart] =
    drawingContentChanges[AscDFH.historyitem_PlotArea_RemoveChart] =  function(oClass){return oClass.charts;};

    drawingContentChanges[AscDFH.historyitem_CommonChart_RemoveSeries] =
    drawingContentChanges[AscDFH.historyitem_BarChart_AddSer] =
    drawingContentChanges[AscDFH.historyitem_AreaChart_AddSer] =
    drawingContentChanges[AscDFH.historyitem_AreaChart_AddSer] =
    drawingContentChanges[AscDFH.historyitem_BubbleChart_AddSerie] =
    drawingContentChanges[AscDFH.historyitem_DoughnutChart_AddSer] =
    drawingContentChanges[AscDFH.historyitem_LineChart_AddSer] =
    drawingContentChanges[AscDFH.historyitem_OfPieChart_AddSer] =
    drawingContentChanges[AscDFH.historyitem_PieChart_AddSer] =
    drawingContentChanges[AscDFH.historyitem_RadarChart_AddSer] =
    drawingContentChanges[AscDFH.historyitem_ScatterChart_AddSer] =
    drawingContentChanges[AscDFH.historyitem_StockChart_AddSer] =
    drawingContentChanges[AscDFH.historyitem_SurfaceChart_AddSer] =  function(oClass){return oClass.series;};



    drawingContentChanges[AscDFH.historyitem_AreaSeries_SetDPt]        =
    drawingContentChanges[AscDFH.historyitem_CommonSeries_RemoveDPt]   =
    drawingContentChanges[AscDFH.historyitem_BarSeries_SetDPt]         =
    drawingContentChanges[AscDFH.historyitem_LineSeries_SetDPt]        =
    drawingContentChanges[AscDFH.historyitem_PieSeries_SetDPt]         =
    drawingContentChanges[AscDFH.historyitem_ScatterSer_SetDPt]        =
    drawingContentChanges[AscDFH.historyitem_BubbleSeries_SetDPt]      =
    drawingContentChanges[AscDFH.historyitem_RadarSeries_SetDPt]       =
    drawingContentChanges[AscDFH.historyitem_PieSeries_SetDPt]         =
    drawingContentChanges[AscDFH.historyitem_LineSeries_SetDPt]        =
    drawingContentChanges[AscDFH.historyitem_RadarSeries_SetDPt]       =  function(oClass){return oClass.dPt;};

    drawingContentChanges[AscDFH.historyitem_DLbls_SetDLbl]            =  function(oClass){return oClass.dLbl;};

    drawingContentChanges[AscDFH.historyitem_Legend_AddLegendEntry]    =  function(oClass){return oClass.legendEntryes;};

    drawingContentChanges[AscDFH.historyitem_MultiLvlStrCache_SetLvl]  =  function(oClass){return oClass.lvl;};

    drawingContentChanges[AscDFH.historyitem_CommonLit_RemoveDPt]      =
    drawingContentChanges[AscDFH.historyitem_NumLit_AddPt]             =
    drawingContentChanges[AscDFH.historyitem_StrCache_AddPt]           =
    drawingContentChanges[AscDFH.historyitem_StringLiteral_SetPt]      =  function(oClass){return oClass.pts;};

    drawingContentChanges[AscDFH.historyitem_OfPieChart_AddCustSplit]  =  function(oClass){return oClass.custSplit};

    drawingContentChanges[AscDFH.historyitem_SurfaceChart_AddBandFmt]  =  function(oClass){return oClass.bandFmts;};

    drawingContentChanges[AscDFH.historyitem_Chart_AddPivotFmt]        =  function(oClass){return oClass.pivotFmts;};





// Import
var g_oIdCounter = AscCommon.g_oIdCounter;
var g_oTableId = AscCommon.g_oTableId;
var CMatrix = AscCommon.CMatrix;
var isRealObject = AscCommon.isRealObject;
    var History = AscCommon.History;
    var global_MatrixTransformer = AscCommon.global_MatrixTransformer;

var CShape = AscFormat.CShape;
var checkSpPrRasterImages = AscFormat.checkSpPrRasterImages;

var c_oAscChartLegendShowSettings = Asc.c_oAscChartLegendShowSettings;
var c_oAscChartDataLabelsPos = Asc.c_oAscChartDataLabelsPos;
var c_oAscValAxisRule = Asc.c_oAscValAxisRule;
var c_oAscValAxUnits = Asc.c_oAscValAxUnits;
var c_oAscTickMark = Asc.c_oAscTickMark;
var c_oAscTickLabelsPos = Asc.c_oAscTickLabelsPos;
var c_oAscCrossesRule = Asc.c_oAscCrossesRule;
var c_oAscBetweenLabelsRule = Asc.c_oAscBetweenLabelsRule;
var c_oAscLabelsPosition = Asc.c_oAscLabelsPosition;
var c_oAscAxisType = Asc.c_oAscAxisType;


    var CChangesDrawingsBool = AscDFH.CChangesDrawingsBool;
    var CChangesDrawingsLong = AscDFH.CChangesDrawingsLong;
    var CChangesDrawingsDouble = AscDFH.CChangesDrawingsDouble;
    var CChangesDrawingsString = AscDFH.CChangesDrawingsString;
    var CChangesDrawingsObjectNoId = AscDFH.CChangesDrawingsObjectNoId;
    var CChangesDrawingsObject = AscDFH.CChangesDrawingsObject;
    var CChangesDrawingsContent = AscDFH.CChangesDrawingsContent;
    var CChangesDrawingsDouble2 = AscDFH.CChangesDrawingsDouble2;


function getMinMaxFromArrPoints(aPoints)
{
    if(Array.isArray(aPoints) && aPoints.length > 0)
    {
        if(isRealObject(aPoints[0]) && AscFormat.isRealNumber(aPoints[0].val) && isRealObject(aPoints[aPoints.length - 1]) && AscFormat.isRealNumber(aPoints[aPoints.length - 1].val))
        {
            if(aPoints[0].val - aPoints[aPoints.length - 1].val <= 0)
            {
                return {min: aPoints[0].val, max: aPoints[aPoints.length - 1].val};
            }
            else
            {
                return {min: aPoints[aPoints.length - 1].val, max: aPoints[0].val};
            }
        }
    }
    return {min: null, max: null};
}


var SCALE_INSET_COEFF = 1.016;//Возможно придется уточнять
function CDLbl()
{
    this.bDelete = null;
    this.dLblPos = null;
    this.idx = null;
    this.layout = null;
    this.numFmt = null;
    this.separator = null;
    this.showBubbleSize = null;
    this.showCatName = null;
    this.showLegendKey = null;
    this.showPercent = null;
    this.showSerName = null;
    this.showVal = null;
    this.spPr = null;
    this.tx = null;
    this.txPr = null;

    this.parent = null;

    this.recalcInfo =
    {
        recalcTransform: true,
        recalcTransformText: true,
        recalcStyle: true,
        recalculateTxBody: true,
        recalculateBrush: true,
        recalculatePen: true,
        recalculateContent: true
    };

    this.chart = null;
    this.series = null;

    this.x = 0;
    this.y = 0;
    this.calcX = null;
    this.calcY = null;


    this.relPosX = null;
    this.relPosY = null;

    this.txBody = null;

    this.transform = new CMatrix();
    this.transformText = new CMatrix();
    this.ownTransform = new CMatrix();
    this.ownTransformText = new CMatrix();
    this.localTransform = new CMatrix();
    this.localTransformText = new CMatrix();

    this.compiledStyles = null;

    this.parent = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CDLbl.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {
        this.Refresh_RecalcData2();
    },


    getObjectType: function()
    {
        return AscDFH.historyitem_type_DLbl;
    },

    Check_AutoFit: function(){
        return true;
    },

    createDuplicate: function()
    {

        var c = new CDLbl();
        c.setDelete(this.bDelete);
        c.setDLblPos(this.dLblPos);
        c.setIdx(this.idx);
        if(this.layout)
        {
            c.setLayout(this.layout.createDuplicate());
        }
        if(this.numFmt)
        {
            c.setNumFmt(this.numFmt.createDuplicate());
        }
        c.setSeparator(this.separator);
        c.setShowBubbleSize(this.showBubbleSize);
        c.setShowCatName(this.showCatName);
        c.setShowLegendKey(this.showLegendKey);
        c.setShowPercent(this.showPercent);
        c.setShowSerName(this.showSerName);
        c.setShowVal(this.showVal);
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        if(this.tx)
        {
            c.setTx(this.tx.createDuplicate());
        }
        if(this.txPr)
        {
            c.setTxPr(this.txPr.createDuplicate());
        }
        return c;
    },

    checkShapeChildTransform: function(transform)
    {
        this.updatePosition(this.posX, this.posY);
        global_MatrixTransformer.MultiplyAppend(this.transform, transform);
        global_MatrixTransformer.MultiplyAppend(this.transformText, transform);
        if((this instanceof CTitle) || (this instanceof CDLbl))
        {
            this.invertTransform = global_MatrixTransformer.Invert(this.transform);
            this.invertTransformText = global_MatrixTransformer.Invert(this.transformText);
        }
    },

    getCompiledFill: function()
    {
        return this.spPr && this.spPr.Fill ? this.spPr.Fill : null;
    },

    getCompiledLine: function()
    {
        return this.spPr && this.spPr.ln ? this.spPr.ln : null;
    },

    getCompiledTransparent: function()
    {
        return this.spPr && this.spPr.Fill ? this.spPr.Fill.transparent : null;
    },


    recalculate: function()
    {
        if(this.bDelete)
        {
            return;
        }
        AscFormat.ExecuteNoHistory(function()
        {
            if(this.recalcInfo.recalculateBrush)
            {
                this.recalculateBrush();
                this.recalcInfo.recalculateBrush = false;
            }
            if(this.recalcInfo.recalculatePen)
            {
                this.recalculatePen();
                this.recalcInfo.recalculatePen = false;
            }
            if(this.recalcInfo.recalcStyle)
            {
                this.recalculateStyle();
                //this.recalcInfo.recalcStyle = false;
            }
            if(this.recalcInfo.recalculateTxBody)
            {
                this.recalculateTxBody();
                this.recalcInfo.recalculateTxBody = false;
            }
            if(this.recalcInfo.recalculateContent)
            {
                this.recalculateContent();
                //this.recalcInfo.recalculateContent = false;
            }
            if(this.recalcInfo.recalcTransform)
            {
                this.recalculateTransform();
                //this.recalcInfo.recalcTransform = false;
            }
            if(this.recalcInfo.recalcTransformText)
            {
                this.recalculateTransformText();
                //this.recalcInfo.recalcTransformText = false;
            }
            if(this.chart)
            {
                this.chart.addToSetPosition(this);
            }
        }, this, []);
    },

    recalculateBrush: CShape.prototype.recalculateBrush,
    recalculatePen: CShape.prototype.recalculatePen,
    check_bounds: CShape.prototype.check_bounds,

    hit: function(x, y)
    {
        var tx = this.invertTransform.TransformPointX(x, y);
        var ty = this.invertTransform.TransformPointY(x, y);
        return tx>=0 && tx <= this.extX && ty >=0 && ty <=this.extY;
    },

    getCompiledStyle: function()
    {
        return null;
    },

    getParentObjects: function()
    {
        return this.chart.getParentObjects();
    },

    recalculateTransform: function()
    {

    },

    recalculateTransformText: function()
    {
        if (this.txBody === null)
            return;
        this.ownTransformText.Reset();
        var _text_transform = this.ownTransformText;
        var _shape_transform = this.ownTransform;
        var _body_pr = this.getBodyPr();
        var _content_height = this.txBody.content.GetSummaryHeight();
        var _l, _t, _r, _b;

        var _t_x_lt, _t_y_lt, _t_x_rt, _t_y_rt, _t_x_lb, _t_y_lb, _t_x_rb, _t_y_rb;
        if (isRealObject(this.spPr) && isRealObject(this.spPr.geometry) && isRealObject(this.spPr.geometry.rect)) {
            var _rect = this.spPr.geometry.rect;
            _l = _rect.l + _body_pr.lIns;
            _t = _rect.t + _body_pr.tIns;
            _r = _rect.r - _body_pr.rIns;
            _b = _rect.b - _body_pr.bIns;
        }
        else
        {
            _l = _body_pr.lIns;
            _t = _body_pr.tIns;
            _r = this.extX - _body_pr.rIns;
            _b = this.extY - _body_pr.bIns;
        }

        if (_l >= _r) {
            var _c = (_l + _r) * 0.5;
            _l = _c - 0.01;
            _r = _c + 0.01;
        }

        if (_t >= _b) {
            _c = (_t + _b) * 0.5;
            _t = _c - 0.01;
            _b = _c + 0.01;
        }

        _t_x_lt = _shape_transform.TransformPointX(_l, _t);
        _t_y_lt = _shape_transform.TransformPointY(_l, _t);

        _t_x_rt = _shape_transform.TransformPointX(_r, _t);
        _t_y_rt = _shape_transform.TransformPointY(_r, _t);

        _t_x_lb = _shape_transform.TransformPointX(_l, _b);
        _t_y_lb = _shape_transform.TransformPointY(_l, _b);

        _t_x_rb = _shape_transform.TransformPointX(_r, _b);
        _t_y_rb = _shape_transform.TransformPointY(_r, _b);

        var _dx_t, _dy_t;
        _dx_t = _t_x_rt - _t_x_lt;
        _dy_t = _t_y_rt - _t_y_lt;

        var _dx_lt_rb, _dy_lt_rb;
        _dx_lt_rb = _t_x_rb - _t_x_lt;
        _dy_lt_rb = _t_y_rb - _t_y_lt;

        var _vertical_shift;
        var _text_rect_height = _b - _t;
        var _text_rect_width = _r - _l;
        var nVert = _body_pr.vert;




        if (!_body_pr.upright)
        {
            if (!(nVert === AscFormat.nVertTTvert || nVert === AscFormat.nVertTTvert270))
            {
                switch (_body_pr.anchor)
                {
                    case 0: //b
                    { // (Text Anchor Enum ( Bottom ))
                        _vertical_shift = _text_rect_height - _content_height;
                        break;
                    }
                    case 1:    //ctr
                    {// (Text Anchor Enum ( Center ))
                        _vertical_shift = (_text_rect_height - _content_height) * 0.5;
                        break;
                    }
                    case 2: //dist
                    {// (Text Anchor Enum ( Distributed )) TODO: пока выравнивание  по центру. Переделать!
                        _vertical_shift = (_text_rect_height - _content_height) * 0.5;
                        break;
                    }
                    case 3: //just
                    {// (Text Anchor Enum ( Justified )) TODO: пока выравнивание  по центру. Переделать!
                        _vertical_shift = (_text_rect_height - _content_height) * 0.5;
                        break;
                    }
                    case 4: //t
                    {//Top
                        _vertical_shift = 0;
                        break;
                    }
                }
                global_MatrixTransformer.TranslateAppend(_text_transform, 0, _vertical_shift);
                if (_dx_lt_rb * _dy_t - _dy_lt_rb * _dx_t <= 0) {
                    var alpha = Math.atan2(_dy_t, _dx_t);
                    global_MatrixTransformer.RotateRadAppend(_text_transform, -alpha);
                    global_MatrixTransformer.TranslateAppend(_text_transform, _t_x_lt, _t_y_lt);
                }
                else {
                    alpha = Math.atan2(_dy_t, _dx_t);
                    global_MatrixTransformer.RotateRadAppend(_text_transform, Math.PI - alpha);
                    global_MatrixTransformer.TranslateAppend(_text_transform, _t_x_rt, _t_y_rt);
                }
            }
            else
            {
                switch (_body_pr.anchor)
                {
                    case 0: //b
                    { // (Text Anchor Enum ( Bottom ))
                        _vertical_shift = _text_rect_width - _content_height;
                        break;
                    }
                    case 1:    //ctr
                    {// (Text Anchor Enum ( Center ))
                        _vertical_shift = (_text_rect_width - _content_height) * 0.5;
                        break;
                    }
                    case 2: //dist
                    {// (Text Anchor Enum ( Distributed ))
                        _vertical_shift = (_text_rect_width - _content_height) * 0.5;
                        break;
                    }
                    case 3: //just
                    {// (Text Anchor Enum ( Justified ))
                        _vertical_shift = (_text_rect_width - _content_height) * 0.5;
                        break;
                    }
                    case 4: //t
                    {//Top
                        _vertical_shift = 0;
                        break;
                    }
                }
                global_MatrixTransformer.TranslateAppend(_text_transform, 0, _vertical_shift);
                var _alpha;
                _alpha = Math.atan2(_dy_t, _dx_t);
                if (nVert === AscFormat.nVertTTvert) {
                    if (_dx_lt_rb * _dy_t - _dy_lt_rb * _dx_t <= 0) {
                        global_MatrixTransformer.RotateRadAppend(_text_transform, -_alpha - Math.PI * 0.5);
                        global_MatrixTransformer.TranslateAppend(_text_transform, _t_x_rt, _t_y_rt);
                    }
                    else {
                        global_MatrixTransformer.RotateRadAppend(_text_transform, Math.PI * 0.5 - _alpha);
                        global_MatrixTransformer.TranslateAppend(_text_transform, _t_x_lt, _t_y_lt);
                    }
                }
                else {
                    if (_dx_lt_rb * _dy_t - _dy_lt_rb * _dx_t <= 0) {
                        global_MatrixTransformer.RotateRadAppend(_text_transform, -_alpha - Math.PI * 1.5);
                        global_MatrixTransformer.TranslateAppend(_text_transform, _t_x_lb, _t_y_lb);
                    }
                    else {
                        global_MatrixTransformer.RotateRadAppend(_text_transform, -Math.PI * 0.5 - _alpha);
                        global_MatrixTransformer.TranslateAppend(_text_transform, _t_x_rb, _t_y_rb);
                    }
                }
            }
        }
        else {

            var _full_flip = {flipH: false, flipV: false};

            var _hc = this.extX * 0.5;
            var _vc = this.extY * 0.5;
            var _transformed_shape_xc = this.transform.TransformPointX(_hc, _vc);
            var _transformed_shape_yc = this.transform.TransformPointY(_hc, _vc);


            var _content_width, content_height2;
            if (!(nVert === AscFormat.nVertTTvert || nVert === AscFormat.nVertTTvert270))
            {
                _content_width = _r - _l;
                content_height2 = _b - _t;
            }
            else
            {
                _content_width = _b - _t;
                content_height2 = _r - _l;
            }

            switch (_body_pr.anchor)
            {
                case 0: //b
                { // (Text Anchor Enum ( Bottom ))
                    _vertical_shift = content_height2 - _content_height;
                    break;
                }
                case 1:    //ctr
                {// (Text Anchor Enum ( Center ))
                    _vertical_shift = (content_height2 - _content_height) * 0.5;
                    break;
                }
                case 2: //dist
                {// (Text Anchor Enum ( Distributed ))
                    _vertical_shift = (content_height2 - _content_height) * 0.5;
                    break;
                }
                case 3: //just
                {// (Text Anchor Enum ( Justified ))
                    _vertical_shift = (content_height2 - _content_height) * 0.5;
                    break;
                }
                case 4: //t
                {//Top
                    _vertical_shift = 0;
                    break;
                }
            }

            var _text_rect_xc = _l + (_r - _l) * 0.5;
            var _text_rect_yc = _t + (_b - _t) * 0.5;

            var _vx = _text_rect_xc - _hc;
            var _vy = _text_rect_yc - _vc;

            var _transformed_text_xc, _transformed_text_yc;
            if (!_full_flip.flipH) {
                _transformed_text_xc = _transformed_shape_xc + _vx;
            }
            else {
                _transformed_text_xc = _transformed_shape_xc - _vx;
            }

            if (!_full_flip.flipV) {
                _transformed_text_yc = _transformed_shape_yc + _vy;
            }
            else {
                _transformed_text_yc = _transformed_shape_yc - _vy;
            }

            global_MatrixTransformer.TranslateAppend(_text_transform, 0, _vertical_shift);
            if (nVert === AscFormat.nVertTTvert) {
                global_MatrixTransformer.TranslateAppend(_text_transform, -_content_width * 0.5, -content_height2 * 0.5);
                global_MatrixTransformer.RotateRadAppend(_text_transform, -Math.PI * 1.5);
                global_MatrixTransformer.TranslateAppend(_text_transform, _content_width * 0.5, content_height2 * 0.5);

            }
            if (nVert === AscFormat.nVertTTvert270) {
                global_MatrixTransformer.TranslateAppend(_text_transform, -_content_width * 0.5, -content_height2 * 0.5);
                global_MatrixTransformer.RotateRadAppend(_text_transform, -Math.PI * 1.5);
                global_MatrixTransformer.TranslateAppend(_text_transform, _content_width * 0.5, content_height2 * 0.5);
            }
            global_MatrixTransformer.TranslateAppend(_text_transform, _transformed_text_xc - _content_width * 0.5, _transformed_text_yc - content_height2 * 0.5);

            this.clipRect =
            {
                x: -_body_pr.lIns,
                y: -_vertical_shift - _body_pr.tIns,
                w: this.contentWidth + (_body_pr.rIns + _body_pr.lIns),
                h: this.contentHeight + (_body_pr.bIns + _body_pr.tIns)
            };
        }

        this.transformText = this.ownTransformText.CreateDublicate();
    },

    getStyles: function()
    {
        if(this.lastStyleObject)
            return this.lastStyleObject;
        return AscFormat.ExecuteNoHistory(function(){
            var styles = new CStyles(false);
            var style = new CStyle("dataLblStyle", null, null, null, true);
            var text_pr = new CTextPr();
            text_pr.FontSize = 10;
            if(this.chart && AscFormat.isRealNumber(this.chart.style) )
            {

                if(this.chart.style > 40)
                {
                    text_pr.Unifill = AscFormat.CreateUnfilFromRGB(255, 255, 255);
                }
                else
                {
                    var default_style = AscFormat.CHART_STYLE_MANAGER.getDefaultLineStyleByIndex(this.chart.style);
                    var oUnifill = default_style.axisAndMajorGridLines.createDuplicate();
                    if(oUnifill && oUnifill.fill && oUnifill.fill.color && oUnifill.fill.color.Mods)
                    {
                        oUnifill.fill.color.Mods.Mods.length = 0;
                    }
                    text_pr.Unifill = oUnifill;
                }
            }
            else
            {
                text_pr.Unifill = AscFormat.CreateUnfilFromRGB(0,0,0);
            }

            var para_pr = new CParaPr();
            para_pr.Jc = AscCommon.align_Center;
            para_pr.Spacing.Before = 0.0;
            para_pr.Spacing.After = 0.0;
            para_pr.Spacing.Line = 1;
            para_pr.Spacing.LineRule = Asc.linerule_Auto;
            style.ParaPr = para_pr;
            text_pr.RFonts.Set_FromObject(
                {
                    Ascii: {
                        Name: "+mn-lt",
                        Index: -1
                    },
                    EastAsia: {
                        Name: "+mn-ea",
                        Index: -1
                    },
                    HAnsi: {
                        Name: "+mn-lt",
                        Index: -1
                    },
                    CS: {
                        Name: "+mn-lt",
                        Index: -1
                    }
                }
            );
            style.TextPr = text_pr;
            var chart_text_pr;

            if(this.chart && this.chart.txPr
                && this.chart.txPr.content
                && this.chart.txPr.content.Content[0]
                && this.chart.txPr.content.Content[0].Pr)
            {
                this.chart.txPr.content.Content[0].Set_DocumentIndex(0);
                style.ParaPr.Merge(this.chart.txPr.content.Content[0].Pr);
                if(this.chart.txPr.content.Content[0].Pr.DefaultRunPr)
                {
                    chart_text_pr = this.chart.txPr.content.Content[0].Pr.DefaultRunPr;
                    style.TextPr.Merge(chart_text_pr);
                }
            }
            if(this instanceof  CTitle || this.parent  instanceof  CTitle)
            {
                style.TextPr.Bold = true;
                if(this.parent instanceof CChart || (this.parent && (this.parent.parent instanceof  CChart)))
                {
                    if(chart_text_pr && typeof chart_text_pr.FontSize === "number")
                        style.TextPr.FontSize = (chart_text_pr.FontSize*1.2) >> 0;
                    else
                        style.TextPr.FontSize = 18;
                }
            }
            if(this instanceof  CalcLegendEntry
                && this.legend)
            {
                if(this.legend.txPr
                && this.legend.txPr.content
                && this.legend.txPr.content.Content[0]
                && this.legend.txPr.content.Content[0].Pr)
                {
                    this.legend.txPr.content.Content[0].Set_DocumentIndex(0);
                    style.ParaPr.Merge(this.legend.txPr.content.Content[0].Pr);
                    if(this.legend.txPr.content.Content[0].Pr.DefaultRunPr)
                        style.TextPr.Merge(this.legend.txPr.content.Content[0].Pr.DefaultRunPr);
                }

                if(AscFormat.isRealNumber(this.idx))
                {
                    var aLegendEntries = this.legend.legendEntryes;
                    for(var i = 0; i < aLegendEntries.length; ++i)
                    {
                        if(this.idx === aLegendEntries[i].idx)
                        {
                            var oLegendEntry = aLegendEntries[i];
                            if(oLegendEntry.txPr
                                && oLegendEntry.txPr.content
                                && oLegendEntry.txPr.content.Content[0]
                                && oLegendEntry.txPr.content.Content[0].Pr)
                            {
                                style.ParaPr.Merge(oLegendEntry.txPr.content.Content[0].Pr);
                                if(oLegendEntry.txPr.content.Content[0].Pr.DefaultRunPr)
                                    style.TextPr.Merge(oLegendEntry.txPr.content.Content[0].Pr.DefaultRunPr);
                            }
                            break;
                        }
                    }
                }

            }

            if(!(this instanceof  CTitle) && this.parent && this.parent.txPr
                && this.parent.txPr.content
                && this.parent.txPr.content.Content[0]
                && this.parent.txPr.content.Content[0].Pr)
            {
                this.parent.txPr.content.Content[0].Set_DocumentIndex(0);
                style.ParaPr.Merge(this.parent.txPr.content.Content[0].Pr);
                if(this.parent.txPr.content.Content[0].Pr.DefaultRunPr)
                    style.TextPr.Merge(this.parent.txPr.content.Content[0].Pr.DefaultRunPr);
            }

            if(this.txPr
                && this.txPr.content
                && this.txPr.content.Content[0]
                && this.txPr.content.Content[0].Pr)
            {
                this.txPr.content.Content[0].Set_DocumentIndex(0);
                style.ParaPr.Merge(this.txPr.content.Content[0].Pr);
                if(this.txPr.content.Content[0].Pr.DefaultRunPr)
                    style.TextPr.Merge(this.txPr.content.Content[0].Pr.DefaultRunPr);
            }
            styles.Add(style);
            if(!(this instanceof CTitle))
                this.lastStyleObject = {lastId: style.Id, styles: styles};
            return {lastId: style.Id, styles: styles};
        }, this, []);
    },

    Get_Theme: function()
    {
        if(this.chart){
            return this.chart.Get_Theme();
        }
        return null;

    },
    Get_ColorMap: function()
    {
        if(this.chart){
            return this.chart.Get_ColorMap();
        }
        else {
            return AscFormat.G_O_DEFAULT_COLOR_MAP;
        }

    },

    Get_AbsolutePage: function()
    {
        if(this.chart && this.chart.Get_AbsolutePage)
        {
            return this.chart.Get_AbsolutePage();
        }
        return 0;
    },

    recalculateStyle: function()
    {
        AscFormat.ExecuteNoHistory(function()
            {
                this.compiledStyles = this.getStyles();
            },
            this, []);
    },

    Get_Styles: function(lvl)
    {
        if(this.recalcInfo.recalcStyle)
        {
            this.recalculateStyle();
            this.recalcInfo.recalcStyle = false;
        }
        return this.compiledStyles;
    },

    checkNoLbl: function()
    {
        if(this.tx && this.tx.rich)
            return false;
        else
        {
            return !(this.showSerName || this.showCatName || this.showVal || this.showPercent);
        }
    },

    getDefaultTextForTxBody: function()
    {
        var compiled_string = "";
        var separator;
        if(typeof this.separator === "string"){
            separator = this.separator + " ";
        }
        else if(this.series.getObjectType() === AscDFH.historyitem_type_PieSeries){
            if(this.showPercent && this.showCatName && !this.showSerName && !this.showVal){
                separator = "\n";
            }
            else{
                separator = ", "
            }
        }
        else{
            separator = ", "
        }
        if(this.showSerName)
        {
            compiled_string += this.series.getSeriesName();
        }
        if(this.showCatName)
        {
            if(compiled_string.length > 0)
                compiled_string += separator;
            compiled_string += this.series.getCatName(this.pt.idx);
        }
        if(this.showVal)
        {
            if(compiled_string.length > 0)
                compiled_string += separator;
            var sFormatCode;
            if(typeof this.pt.formatCode === "string" && this.pt.formatCode.length > 0){
                sFormatCode =  this.pt.formatCode;
            }
            else{
                sFormatCode = this.series.getFormatCode();
            }

            var num_format = AscCommon.oNumFormatCache.get(sFormatCode);
            compiled_string += num_format.formatToChart(this.series.getValByIndex(this.pt.idx));
        }
        if(this.showPercent)
        {
            if(compiled_string.length > 0)
                compiled_string += separator;
            compiled_string += this.series.getValByIndex(this.pt.idx, true);
        }
        return compiled_string;
    },

    getMaxWidth: function(bodyPr)
    {
        if(!(this.parent && (this.parent.axPos === AX_POS_L || this.parent.axPos === AX_POS_R)))
        {
            switch (bodyPr.vert)
            {
                case AscFormat.nVertTTeaVert:
                case AscFormat.nVertTTmongolianVert:
                case AscFormat.nVertTTvert:
                case AscFormat.nVertTTwordArtVert:
                case AscFormat.nVertTTwordArtVertRtl:
                case AscFormat.nVertTTvert270:
                {
                    return this.chart.extY/2;
                }
                case AscFormat.nVertTThorz:
                {
                    return this.chart.extX/5
                }
            }
            return this.chart.extX/5;
        }
        else
        {
            return 20000;//надписи для осей значений не переносятся поэтому выставляем большую ширину.
        }
    },

    getBodyPr: function()
    {
        var ret = new AscFormat.CBodyPr();
        ret.setDefault();
        if(this.tx && this.tx.rich)
        {
            ret.merge(this.tx.rich.bodyPr);
        }
        else
        {
            if(this.txPr && this.txPr.bodyPr)
            {
                ret.merge(this.txPr.bodyPr);
            }
        }

        if(this.parent && AscFormat.isRealNumber(this.parent.axPos) && (this.parent.axPos === AX_POS_L || this.parent.axPos === AX_POS_R)
            && ((this.tx && this.tx.rich && (!this.tx.rich.bodyPr ||  !AscFormat.isRealNumber(this.tx.rich.bodyPr.vert) ) ) || (!(this.tx && this.tx.rich) && (!this.txPr || !this.txPr.bodyPr || !AscFormat.isRealNumber(this.txPr.bodyPr.vert))))  )
        {
            ret.vert = AscFormat.nVertTTvert270;
        }
        if( (!this.txPr || !this.txPr.bodyPr || !AscFormat.isRealNumber(this.txPr.bodyPr.anchor)))
        {
            ret.anchor = 1;
        }


        //Пока не поддерживаем bodyPr.rot. Костыль под эффект_штурмовика.docx.
        if(AscFormat.isRealNumber(ret.rot) && 0 !== ret.rot)
        {
            if(Math.abs(ret.rot - 5400000) < 1000)
            {
                if(ret.vert === AscFormat.nVertTTvert270)
                {
                    ret.vert = AscFormat.nVertTThorz;
                }
                else if(ret.vert === AscFormat.nVertTThorz)
                {
                    ret.vert = AscFormat.nVertTTvert;
                }
            }
            else if(Math.abs(ret.rot + 5400000) < 1000)
            {
                if(ret.vert === AscFormat.nVertTTvert)
                {
                    ret.vert = AscFormat.nVertTThorz;
                }
                else if(ret.vert === AscFormat.nVertTThorz)
                {
                    ret.vert = AscFormat.nVertTTvert270;
                }
            }
        }
        //

        switch (ret.vert)
        {
            case AscFormat.nVertTTeaVert:
            case AscFormat.nVertTTmongolianVert:
            case AscFormat.nVertTTvert:
            case AscFormat.nVertTTwordArtVert:
            case AscFormat.nVertTTwordArtVertRtl:
            case AscFormat.nVertTTvert270:
            {
                ret.lIns = SCALE_INSET_COEFF;
                ret.rIns = SCALE_INSET_COEFF;
                ret.tIns = SCALE_INSET_COEFF*0.5;
                ret.bIns = SCALE_INSET_COEFF*0.5;
                break;
            }
            case AscFormat.nVertTThorz:
            {
                ret.lIns = SCALE_INSET_COEFF;
                ret.rIns = SCALE_INSET_COEFF;
                ret.tIns = SCALE_INSET_COEFF*0.5;
                ret.bIns = SCALE_INSET_COEFF*0.5;
                break;
            }
        }
        return ret;
    },

    recalculateContent: function()
    {
        if(this.txBody)
        {
            var bodyPr = this.getBodyPr();
            var max_box_width = this.getMaxWidth(bodyPr);/*получено экспериментальным путем нужно уточнить*/
            var max_content_width = max_box_width - 2*SCALE_INSET_COEFF;

            var content = this.txBody.content;
            content.Reset(0, 0, max_content_width, 20000);

            content.Recalculate_Page(0, true);
            var pargs = content.Content;
            var max_width = 0;
            for(var i = 0; i < pargs.length; ++i)
            {
                var par = pargs[i];
                for(var j = 0; j < par.Lines.length; ++j)
                {
                    if(par.Lines[j].Ranges[0].W > max_width)
                    {
                        max_width = par.Lines[j].Ranges[0].W;
                    }
                }
            }
            max_width += 1;
            content.Reset(0, 0, max_width, 20000);
            content.Recalculate_Page(0, true);

            switch (bodyPr.vert)
            {
                case AscFormat.nVertTTeaVert:
                case AscFormat.nVertTTmongolianVert:
                case AscFormat.nVertTTvert:
                case AscFormat.nVertTTwordArtVert:
                case AscFormat.nVertTTwordArtVertRtl:
                case AscFormat.nVertTTvert270:
                {
                    this.extX = Math.min(content.GetSummaryHeight() + 4.4*SCALE_INSET_COEFF, max_box_width);
                    this.extY = max_width + 2*SCALE_INSET_COEFF;
                    this.x = 0;
                    this.y = 0;

                    this.txBody.contentWidth = this.extY;
                    this.txBody.contentHeight = this.extX;
                    this.contentWidth = this.extY;
                    this.contentHeight = this.extX;
                    break;
                }
                default:
                {
                    var _rot = AscFormat.isRealNumber(bodyPr.rot) ? bodyPr.rot*AscFormat.cToRad2 : 0;
                    var t = new CMatrix();
                    global_MatrixTransformer.RotateRadAppend(t, -_rot);
                    var w, h, x0, y0, x1, y1, x2, y2, x3, y3;
                    w = max_width;
                    h = this.txBody.content.GetSummaryHeight();
                    x0 = 0;
                    y0 = 0;
                    x1 = t.TransformPointX(w, 0);
                    y1 = t.TransformPointY(w, 0);
                    x2 = t.TransformPointX(w, h);
                    y2 = t.TransformPointY(w, h);
                    x3 = t.TransformPointX(0, h);
                    y3 = t.TransformPointY(0, h);

                    this.extX = Math.max(x0, x1, x2, x3) - Math.min(x0, x1, x2, x3) + 1.25;
                    this.extY =  Math.max(y0, y1, y2, y3) - Math.min(y0, y1, y2, y3) + SCALE_INSET_COEFF;
                    this.x = 0;
                    this.y = 0;

                    this.txBody.contentWidth = this.extX;
                    this.txBody.contentHeight = this.extY;
                    this.contentWidth = this.extX;
                    this.contentHeight = this.extY;
                    break;
                }
            }

        }
    },

    recalculateTxBody: function()
    {
        if(this.tx && this.tx.rich)
        {
            this.txBody = this.tx.rich;
            this.txBody.parent = this;
        }
        else
        {
            this.txBody = AscFormat.CreateTextBodyFromString(this.getDefaultTextForTxBody(), this.chart.getDrawingDocument(), this);
        }
    },

    initDefault: function(nDefaultPosition)
    {
        this.setDelete(false);
        this.setDLblPos(AscFormat.isRealNumber(nDefaultPosition) ? nDefaultPosition : c_oAscChartDataLabelsPos.inBase);
        this.setIdx(null);
        this.setLayout(null);
        this.setNumFmt(null);
        this.setSeparator(null);
        this.setShowBubbleSize(false);
        this.setShowCatName(false);
        this.setShowLegendKey(false);
        this.setShowPercent(false);
        this.setShowSerName(false);
        this.setShowVal(false);
        this.setSpPr(null);
        this.setTx(null);
        this.setTxPr(null);
    },

    merge: function(dLbl, noCopyTxBody)
    {
        if(!dLbl)
            return;
        if(dLbl.bDelete != null)
            this.setDelete(dLbl.bDelete);
        if(dLbl.dLblPos != null)
            this.setDLblPos(dLbl.dLblPos);

        if(dLbl.idx != null)
            this.setIdx(dLbl.idx);
        
        if(dLbl.layout != null)
        {
            this.setLayout(dLbl.layout.createDuplicate());
        }

        if(dLbl.numFmt != null)
            this.setNumFmt(dLbl.numFmt);

        if(dLbl.separator != null)
            this.setSeparator(dLbl.separator);

        if(dLbl.showBubbleSize != null)
            this.setShowBubbleSize(dLbl.showBubbleSize);

        if(dLbl.showCatName != null)
            this.setShowCatName(dLbl.showCatName);

        if(dLbl.showLegendKey != null)
            this.setShowLegendKey(dLbl.showLegendKey);

        if(dLbl.showPercent != null)
            this.setShowPercent(dLbl.showPercent);

        if(dLbl.showSerName != null)
            this.setShowSerName(dLbl.showSerName);


        if(dLbl.showVal != null)
            this.setShowVal(dLbl.showVal);

        if(dLbl.spPr != null)
        {
            if(this.spPr == null)
            {
                this.setSpPr(new AscFormat.CSpPr());
            }
            if(dLbl.spPr.Fill)
            {
                if(this.spPr.Fill == null)
                {
                    this.spPr.setFill(new AscFormat.CUniFill());
                }
                this.spPr.Fill.merge(dLbl.spPr.Fill);
            }
            if(dLbl.spPr.ln)
            {
                if(this.spPr.ln == null)
                {
                    this.spPr.setLn(new AscFormat.CLn());
                }
                this.spPr.ln.merge(dLbl.spPr.ln);
            }
        }
        if(dLbl.tx)
        {
            if(this.tx == null)
            {
                this.setTx(new CChartText());
            }
            this.tx.merge(dLbl.tx, noCopyTxBody);
        }
        if(dLbl.txPr)
        {
            if(noCopyTxBody === true)
            {
                var oldParent = dLbl.txPr.parent;
                this.setTxPr(dLbl.txPr);
                dLbl.txPr.parent = oldParent;
            }
            else
            {
                this.setTxPr(dLbl.txPr.createDuplicate());
            }
            this.txPr.setParent(this);
        }
    },

    draw: CShape.prototype.draw,

    isEmptyPlaceholder: function()
    {
        return false;
    },
    setPosition: function(x, y)
    {
        this.x = x;
        this.y = y;

    
            this.calcX = this.x;
            this.calcY = this.y;

        this.localTransform.Reset();
        global_MatrixTransformer.TranslateAppend(this.localTransform, this.calcX, this.calcY);
      //  if (isRealObject(this.chart))
      //  {
      //      global_MatrixTransformer.MultiplyAppend(this.localTransform, this.chart.localTransform);
      //  }

        this.transform = this.localTransform.CreateDublicate();
        this.invertTransform = global_MatrixTransformer.Invert(this.transform);



        this.localTransformText = this.ownTransformText.CreateDublicate();
        global_MatrixTransformer.TranslateAppend(this.localTransformText, this.calcX, this.calcY);
      //  if (isRealObject(this.chart))
      //  {
      //      global_MatrixTransformer.MultiplyAppend(this.localTransformText, this.chart.localTransform);
      //  }

        this.transformText = this.localTransformText.CreateDublicate();
        this.invertTransformText = global_MatrixTransformer.Invert(this.transformText);
    },

    setPosition2: function(x, y)
    {
        this.x = x;
        this.y = y;

        this.calcX = this.x;
        this.calcY = this.y;



        this.localTransform.tx = x;
        this.localTransform.ty = y;

        this.transform = this.localTransform.CreateDublicate();
        this.invertTransform = global_MatrixTransformer.Invert(this.transform);


        this.localTransformText.tx = x;
        this.localTransformText.ty = y;
        this.transformText = this.localTransformText.CreateDublicate();
        this.invertTransformText = global_MatrixTransformer.Invert(this.transformText);
    },

    updateTransformMatrix: function()
    {
        this.transform = this.localTransform.CreateDublicate();
        global_MatrixTransformer.TranslateAppend(this.transform, this.posX, this.posY);
        this.invertTransform = global_MatrixTransformer.Invert(this.transform);

        if(this.localTransformText)
        {
            this.transformText = this.localTransformText.CreateDublicate();
            global_MatrixTransformer.TranslateAppend(this.transformText, this.posX, this.posY);
            this.invertTransformText = global_MatrixTransformer.Invert(this.transformText);
        }

    },

    updatePosition: function(x, y)
    {
        this.posX = x;
        this.posY = y;
        this.transform = this.localTransform.CreateDublicate();
        global_MatrixTransformer.TranslateAppend(this.transform, x, y);

        this.transformText = this.localTransformText.CreateDublicate();
        global_MatrixTransformer.TranslateAppend(this.transformText, x, y);


        this.invertTransform = global_MatrixTransformer.Invert(this.transform);
        this.invertTransformText = global_MatrixTransformer.Invert(this.transformText);

    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setDelete: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DLbl_SetDelete, this.bDelete, pr));
        this.bDelete = pr;
        this.Refresh_RecalcData2();
    },
    setDLblPos: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_DLbl_SetDLblPos, this.dLblPos, pr));
        this.dLblPos = pr;
    },
    setIdx: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_DLbl_SetIdx, this.idx, pr));
        this.idx = pr;
    },
    setLayout: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DLbl_SetLayout, this.layout, pr));
        this.layout = pr;
    },
    setNumFmt: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DLbl_SetNumFmt, this.numFmt, pr));
        this.numFmt = pr;
    },
    setSeparator: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_DLbl_SetSeparator, this.separator, pr));
        this.separator = pr;
    },
    setShowBubbleSize: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DLbl_SetShowBubbleSize, this.showBubbleSize, pr));
        this.showBubbleSize = pr;
    },
    setShowCatName: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DLbl_SetShowCatName, this.showCatName, pr));
        this.showCatName = pr;
    },
    setShowLegendKey: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DLbl_SetShowLegendKey, this.showLegendKey, pr));
        this.showLegendKey = pr;
    },
    setShowPercent: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DLbl_SetShowPercent, this.showPercent, pr));
        this.showPercent = pr;
    },
    setShowSerName: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DLbl_SetShowSerName, this.showSerName, pr));
        this.showSerName = pr;
    },
    setShowVal: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DLbl_SetShowVal, this.showVal, pr));
        this.showVal = pr;
    },
    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DLbl_SetSpPr, this.spPr, pr));
        this.spPr = pr;
    },
    setTx: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DLbl_SetTx, this.tx, pr));
        this.tx = pr;
    },
    setTxPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DLbl_SetTxPr, this.txPr, pr));
        this.txPr = pr;
        if(this.txPr)
        {
            this.txPr.setParent(this);
        }
    },

    Refresh_RecalcData2: function()
    {
        if(this.parent && this.parent.Refresh_RecalcData2)
        {
            this.parent.Refresh_RecalcData2();
        }
            }
};


function CPlotArea()
{
    this.charts = [];
    this.dTable = null;
    this.layout = null;
    this.serAx = null;
    this.spPr = null;
    this.axId = [];

    //ТоDo
    this.valAx = null;
    this.catAx = null;
    this.serAx = null;
    this.dateAx = null;
    this.chart = null;

    this.parent = null;


    this.m_oChartsContentChnages = new AscCommon.CContentChanges();
    this.m_oAxIdContentChanges = new AscCommon.CContentChanges();
    //

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CPlotArea.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function(data)
    {
        switch (data.Type)
        {
            case AscDFH.historyitem_CommonChartFormat_SetParent:
            {
                break;
            }
            case AscDFH.historyitem_PlotArea_RemoveAxis:
            {
                break;
            }
            case AscDFH.historyitem_PlotArea_RemoveChart:
            {
                break;
            }
            case AscDFH.historyitem_PlotArea_AddChart:
            {
                if(this.parent && this.parent.parent)
                    this.parent.parent.handleUpdateType();
                break;
            }
            case AscDFH.historyitem_PlotArea_SetCatAx:
            {
                break;
            }
            case AscDFH.historyitem_PlotArea_SetDateAx:
            {
                break;
            }
            case AscDFH.historyitem_PlotArea_SetDTable:
            {
                break;
            }
            case AscDFH.historyitem_PlotArea_SetLayout:
            {
                break;
            }
            case AscDFH.historyitem_PlotArea_SetSerAx:
            {
                break;
            }
            case AscDFH.historyitem_PlotArea_SetSpPr:
            {
                break;
            }
            case AscDFH.historyitem_PlotArea_SetValAx:
            {
                break;
            }
            case AscDFH.historyitem_PlotArea_AddAxis:
            {
                break;
            }
        }
    },

    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_PlotArea_AddAxis:
            case AscDFH.historyitem_PlotArea_RemoveAxis:{
                return this.m_oAxIdContentChanges;
            }
            case AscDFH.historyitem_PlotArea_AddChart:
            case AscDFH.historyitem_PlotArea_RemoveChart:{
                return this.m_oChartsContentChnages;
            }
        }
        return null;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_PlotArea;
    },

    createDuplicate: function()
    {
        var c = new CPlotArea(), i, j, k;

        if(this.dTable)
        {
            c.setDTable(this.dTable.createDuplicate());
        }
        if(this.layout)
        {
            c.setLayout(this.layout.createDuplicate());
        }
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        
        var len = this.axId.length;
        for(i = 0; i < len; i++)
        {
            var oAxis = this.axId[i].createDuplicate();
            oAxis.setAxId(++AscFormat.Ax_Counter.GLOBAL_AX_ID_COUNTER);
            c.addAxis(oAxis);
        }

        var cur_chart, cur_axis;
        for(i = 0; i < this.charts.length; ++i)
        {
            cur_chart = this.charts[i];
            c.addChart(cur_chart.createDuplicate(), c.charts.length);
            if(Array.isArray(cur_chart.axId))
            {
                for(j = 0; j < cur_chart.axId.length; ++j)
                {
                    cur_axis = cur_chart.axId[j];
                    for(k = 0; k < this.axId.length; ++k)
                    {
                        if(cur_axis === this.axId[k])
                        {
                            c.charts[i].addAxId(c.axId[k]);
                        }
                    }
                }
            }
        }

        //выставим пересечения осей в копии

        for(i = 0; i < this.axId.length; ++i)
        {
            cur_axis = this.axId[i];
            for(j = 0; j < this.axId.length; ++j)
            {
                if(cur_axis.crossAx === this.axId[j])
                {
                    c.axId[i].setCrossAx(c.axId[j]);
                    break;
                }
            }
        }
        return c;
    },


    getSeriesWithSmallestIndexForAxis: function(oAxis){
        var aCharts = this.charts;
        var oRet = null;
        var oChart, aSeries;
        for(var i = 0; i < aCharts.length; ++i){
            oChart = aCharts[i];
            var aAxes = aCharts[i].axId;
            if(!aAxes){
                continue;
            }
            for(var j = 0; j < aAxes.length; ++j){
                if(aAxes[j] === oAxis){
                    aSeries = oChart.series;
                    for(var k = 0; k < aSeries.length; ++k){
                        if(oRet === null
                            || aSeries[k].cat && !oRet.cat
                            || aSeries[k].idx < oRet.idx && aSeries[k].cat && oRet.cat){
                            oRet = aSeries[k];
                        }
                    }
                }
            }
        }
        return oRet;
    },

    getChartsForAxis: function(oAxis){
        var aCharts = this.charts;
        var oRet = null;
        var oChart, aSeries;
        var aRet = []
        for(var i = 0; i < aCharts.length; ++i){
            oChart = aCharts[i];
            var aAxes = aCharts[i].axId;
            if(!aAxes){
                continue;
            }
            for(var j = 0; j < aAxes.length; ++j){
                if(aAxes[j] === oAxis){
                    aRet.push(oChart);
                    break;
                }
            }
        }
        return aRet;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },


    addAxis: function(axis)
    {
        //сначала проверим не лежит ли ось уже в plotArea
        if(!axis)
            return;
        var i;
        for(i = 0; i < this.axId.length; ++i)
        {
            if(this.axId[i] === axis)
                return;
        }
        //если такой оси нет, можно добавлять.
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_PlotArea_AddAxis, this.axId.length, [axis], true));
        this.axId.push(axis);
        axis.setParent(this);
    },

    addChart: function(pr, idx)
    {
        var pos;
        if(AscFormat.isRealNumber(idx))
            pos = idx;
        else
            pos = this.charts.length;
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_PlotArea_AddChart, pos, [pr], true));
        this.charts.splice(pos, 0, pr);
        pr.setParent(this);
        if(this.parent && this.parent.parent)
            this.parent.parent.handleUpdateType();
    },


    removeChartByPos: function(pos)
    {
        if(this.charts[pos])
        {
            var chart  = this.charts.splice(pos, 1)[0];
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_PlotArea_RemoveChart, pos, [chart], false));
            //удалим все оси этой диаграммы, проверив прежде нет ли ссылок на данные оси в других диаграммах
            if(Array.isArray(chart.axId))
            {
                var chart_axis = chart.axId;
                for(var i = 0; i < chart_axis.length; ++i)
                {
                    var axis = chart_axis[i];
                    for(var j = 0; j  < this.charts.length; ++j)
                    {
                        var other_chart = this.charts[j];
                        if(Array.isArray(other_chart.axId))
                        {
                            for(var k = 0;  k  < other_chart.axId.length; ++k)
                            {
                                if(other_chart.axId[k] === axis)
                                    break;
                            }
                            if(k < other_chart.axId.length)
                                break;
                        }
                    }
                    if(j === this.charts.length)
                        this.removeAxis(axis);
                }
            }
        }
    },

    removeCharts: function(startPos, endPos)
    {
        for(var i = endPos; i >= startPos; --i)
        {
            this.removeChartByPos(i);
        }
    },

    removeAxis: function(axis)
    {
        for(var i = this.axId.length - 1; i > -1; --i)
        {
            if(this.axId[i] === axis)
            {
                History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_PlotArea_RemoveAxis, i, [axis], false));
                this.axId.splice(i, 1);
            }
        }
    },

    setDTable: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PlotArea_SetDTable, this.dTable, pr));
        this.dTable = pr;
    },

    setLayout: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PlotArea_SetLayout, this.layout, pr));
        this.layout = pr;
    },



    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PlotArea_SetSpPr, this.spPr, pr));
        this.spPr = pr;
        if(pr)
        {
            pr.setParent(this);
        }
    },


    getHorizontalAxis: function()
    {
        if(this.charts[0])
        {
            var aAxes = this.charts[0].axId;
            if(aAxes)
            {
                for(var i = 0; i < aAxes.length; ++i)
                {
                    if(aAxes[i].axPos === AX_POS_B || aAxes[i].axPos === AX_POS_T)
                        return aAxes[i];
                }
            }
        }
        return null;
    },


    getVerticalAxis: function()
    {
        if(this.charts[0])
        {
            var aAxes = this.charts[0].axId;
            if(aAxes)
            {
                for(var i = 0; i < aAxes.length; ++i)
                {
                    if(aAxes[i].axPos === AX_POS_L || aAxes[i].axPos === AX_POS_R)
                        return aAxes[i];
                }
            }
        }
        return null;
    },

    getAxisByTypes: function()
    {
        var  ret = {valAx:[], catAx: [], dateAx: [], serAx: []};
        for(var i = 0; i < this.axId.length; ++i)
        {
            var axis = this.axId[i];
            switch(axis.getObjectType())
            {
                case AscDFH.historyitem_type_CatAx:
                case AscDFH.historyitem_type_DateAx:
                {
                    ret.catAx.push(axis);
                    break;
                }
                case AscDFH.historyitem_type_ValAx:
                {
                    ret.valAx.push(axis);
                    break;
                }
                case AscDFH.historyitem_type_SerAx:
                {
                    ret.serAx.push(axis);
                    break;
                }
            }
        }
        return ret;
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};


function CBarChart()
{
    this.axId        = [];
    this.barDir      = null;
    this.dLbls       = null;
    this.gapWidth    = null;
    this.grouping    = null;
    this.overlap     = null;
    this.series      = [];
    this.serLines    = null;
    this.varyColors  = null;

    this.parent = null;
    this.b3D = null;
    this.gapDepth = null;
    this.shape = null;


    this.m_oAxIdContentChanges = new AscCommon.CContentChanges();
    this.m_oSeriesContentChanges = new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CBarChart.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    set3D: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_BarChart_Set3D, this.b3D, pr));
        this.b3D = pr;
    },

    setGapDepth: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_BarChart_SetGapDepth, this.gapDepth, pr));
        this.gapDepth = pr;
    },

    setShape: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_BarChart_SetShape, this.shape, pr));
        this.shape = pr;
    },

    getSeriesConstructor: function()
    {
        return new CBarSeries();
    },

    removeSeries: function(idx)
    {
        if(this.series[idx])
        {
            var aRemoved = this.series.splice(idx, 1);
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonChart_RemoveSeries, idx, aRemoved, false))
        }
    },

    createDuplicate: function()
    {
        //axId будут выставлены из родительского класса
        var c = new CBarChart();
        c.setBarDir(this.barDir);
        if(this.b3D)
        {
            c.set3D(true);
        }
        if(this.dLbls)
        {
            c.setDLbls(this.dLbls.createDuplicate());
        }
        c.setGapWidth(this.gapWidth);
        c.setGrouping(this.grouping);
        c.setOverlap(this.overlap);
        c.setGapDepth(this.gapDepth);
        c.setShape(this.shape);

        for(var i = 0; i < this.series.length; ++i)
        {
            c.addSer(this.series[i].createDuplicate());
        }
        if(this.serLines)
        {
            c.setSerLines(this.serLines.createDuplicate());
        }
        c.setVaryColors(this.varyColors);
        return c;
    },


    getDefaultDataLabelsPosition: function()
    {
        if(!AscFormat.isRealNumber(this.grouping) || this.grouping === AscFormat.BAR_GROUPING_CLUSTERED || this.grouping === AscFormat.BAR_GROUPING_STANDARD)
        {
            return c_oAscChartDataLabelsPos.outEnd;
        }
        return c_oAscChartDataLabelsPos.ctr;
    },

    documentCreateFontMap: function(allFonts)
    {
        this.dLbls && this.dLbls.documentCreateFontMap(allFonts);
        for(var i =0 ; i < this.series.length; ++i)
        {
            this.series[i] && this.series[i].documentCreateFontMap(allFonts);
        }
    },

    removeDataLabels: function()
    {
        var i;
        for(i = 0; i < this.series.length; ++i)
        {
            if(typeof this.series[i].setDLbls === "function" && this.series[i].dLbls)
                this.series[i].setDLbls(null);
        }
    },

    getAllRasterImages: function(images)
    {
        this.dLbls && this.dLbls.getAllRasterImages(images);
        for(var i = 0; i < this.series.length; ++i)
            this.series[i].getAllRasterImages(images);
    },


    checkSpPrRasterImages: function(images)
    {
        this.dLbls && this.dLbls.checkSpPrRasterImages(images);
        for(var i = 0; i < this.series.length; ++i)
            this.series[i].checkSpPrRasterImages(images);
    },

    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_BarChart_AddAxId:{
                return this.m_oAxIdContentChanges;
            }
            case AscDFH.historyitem_BarChart_AddSer:
            case AscDFH.historyitem_CommonChart_RemoveSeries:{
                return this.m_oSeriesContentChanges;
            }
        }
        return null;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_BarChart;
    },


    Refresh_RecalcData: function(data)
    {
        if(!isRealObject(data))
            return;
        switch(data.Type)
        {
            case AscDFH.historyitem_CommonChartFormat_SetParent:
            {
                break;
            }
            case AscDFH.historyitem_CommonChart_RemoveSeries:
            {
                break;
            }
            case AscDFH.historyitem_BarChart_AddAxId:
            {
                break;
            }
            case AscDFH.historyitem_BarChart_SetBarDir:
            case AscDFH.historyitem_BarChart_Set3D:
            case AscDFH.historyitem_BarChart_SetGapDepth:
            case AscDFH.historyitem_BarChart_SetShape:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateInternalChart();
                }
                break;
            }
            case AscDFH.historyitem_BarChart_SetDLbls:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateDataLabels();
                }
                break;
            }
            case AscDFH.historyitem_BarChart_SetGapWidth:
            {
                break;
            }
            case AscDFH.historyitem_BarChart_SetGrouping:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateInternalChart();
                }
                break;
            }
            case AscDFH.historyitem_BarChart_SetOverlap:
            {
                break;
            }
            case AscDFH.historyitem_BarChart_AddSer:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateType();
                }
                break;
            }
            case AscDFH.historyitem_BarChart_SetSerLines:
            {
                break;
            }
            case AscDFH.historyitem_BarChart_SetVaryColors:
            {
                break;
            }
        }

    },

    getAxisByTypes: CPlotArea.prototype.getAxisByTypes,

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setFromOtherChart: function(c)
    {
        var i;
        //if(Array.isArray(c.axId))
        //{
        //    for(i = 0; i < c.axId.length; ++i)
        //    {
        //        this.addAxId(c.axId[i]);
        //    }
        //}
        if(AscFormat.isRealNumber(c.barDir))
            this.setBarDir(c.barDir);

        if(c.dLbls)
            this.setDLbls(c.dLbls);

        if(AscFormat.isRealNumber(c.gapWidth))
            this.setGapWidth(c.gapWidth);
        if(AscFormat.isRealNumber(c.grouping))
            this.setGrouping(c.grouping);
        if(AscFormat.isRealNumber(c.overlap))
            this.setOverlap(c.overlap);
        if(Array.isArray(c.series))
        {
            for(i = 0; i < c.series.length; ++i)
            {
                var ser = new CBarSeries();
                ser.setFromOtherSeries(c.series[i]);
                this.addSer(ser);
            }
        }
        if(AscFormat.isRealBool(c.varyColors))
            this.setVaryColors(c.varyColors);
    },

    addAxId: function(pr)
    {
        if(!pr)
            return;
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_BarChart_AddAxId, this.axId.length, [pr], true));
        this.axId.push(pr);
    },

    setBarDir: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_BarChart_SetBarDir, this.barDir, pr));
        this.barDir = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },

    setDLbls     : function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BarChart_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateDataLabels();
        }
    },
    setGapWidth: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_BarChart_SetGapWidth, this.gapWidth, pr));
        this.gapWidth = pr;
    },
    setGrouping: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_BarChart_SetGrouping, this.grouping, pr));
        this.grouping = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setOverlap: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_BarChart_SetOverlap, this.overlap, pr));
        this.overlap = pr;
    },
    addSer: function(pr)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_BarChart_AddSer, this.series.length, [pr], true));
        this.series.push(pr);
        pr.setParent(this);
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateType();
        }
    },
    setSerLines: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BarChart_SetSerLines, this.serLines, pr));
        this.serLines = pr;
    },
    setVaryColors: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_BarChart_SetVaryColors, this.varyColors, pr));
        this.varyColors = pr;
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};

function CAreaChart()
{
    this.axId         = [];
    this.dLbls        = null;
    this.dropLines    = null;
    this.grouping     = null;
    this.series       = [];
    this.varyColors   = null;
    this.parent  = null;

    this.m_oAxIdContentChanges = new AscCommon.CContentChanges();
    this.m_oSeriesContentChanges = new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CAreaChart.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_AreaChart_AddAxId:{
                return this.m_oAxIdContentChanges;
            }
            case AscDFH.historyitem_AreaChart_AddSer:
            case AscDFH.historyitem_CommonChart_RemoveSeries:{
                return this.m_oSeriesContentChanges;
            }
        }
        return null;
    },

    removeSeries: function(idx)
    {
        if(this.series[idx])
        {
            var arrSeries = this.series.splice(idx, 1);
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonChart_RemoveSeries, idx, arrSeries, false));
        }
    },

    getDefaultDataLabelsPosition: function()
    {
        return c_oAscChartDataLabelsPos.ctr;
    },

    getSeriesConstructor: function()
    {
        return new CAreaSeries();
    },
    createDuplicate: function()
    {
        //axId будут выставлены из родительского класса
        var c = new CAreaChart();
        if(this.dLbls)
        {
            c.setDLbls(this.dLbls.createDuplicate());
        }
        if(this.dropLines)
        {
            c.setDropLines(this.dropLines.createDuplicate());
        }
        c.setGrouping(this.grouping);
        for(var i = 0; i < this.series.length; ++i)
        {
            c.addSer(this.series[i].createDuplicate());
        }
        c.setVaryColors(this.varyColors);
        return c;
    },

    documentCreateFontMap: CBarChart.prototype.documentCreateFontMap,

    Refresh_RecalcData: function(data)
    {
        if(!isRealObject(data))
            return;
        switch (data.Type)
        {
            case AscDFH.historyitem_CommonChartFormat_SetParent:
            {
                break;
            }
            case AscDFH.historyitem_CommonChart_RemoveSeries:
            {
                break;
            }
            case AscDFH.historyitem_AreaChart_AddAxId:
            {
                break
            }
            case AscDFH.historyitem_AreaChart_SetDLbls:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateDataLabels();
                }
                break
            }
            case AscDFH.historyitem_AreaChart_SetDropLines:
            {
                break
            }
            case AscDFH.historyitem_AreaChart_SetGrouping:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateInternalChart();
                }
                break
            }
            case AscDFH.historyitem_AreaChart_SetVaryColors:
            {
                break
            }
            case AscDFH.historyitem_AreaChart_AddSer:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateType();
                }
                break;
            }
        }
    },

    getObjectType: function()
    {
        return  AscDFH.historyitem_type_AreaChart;
    },

    getAllRasterImages: CBarChart.prototype.getAllRasterImages,
    checkSpPrRasterImages: CBarChart.prototype.checkSpPrRasterImages,
    removeDataLabels: CBarChart.prototype.removeDataLabels,
    getAxisByTypes: CPlotArea.prototype.getAxisByTypes,

    setFromOtherChart: function(c)
    {
        var i;
        //if(Array.isArray(c.axId))
        //{
        //    for(i = 0; i < c.axId.length; ++i)
        //    {
        //        this.addAxId(c.axId[i]);
        //    }
        //}
        if(c.dLbls)
            this.setDLbls(c.dLbls);
        if(c.dropLines)
            this.setDropLines(c.dropLines);
        if(AscFormat.isRealNumber(c.grouping))
            this.setGrouping(c.grouping);
        if(Array.isArray(c.series))
        {
            for(i = 0; i < c.series.length; ++i)
            {
                var ser = new CAreaSeries();
                ser.setFromOtherSeries(c.series[i]);
                this.addSer(ser);
            }
        }
        if(AscFormat.isRealBool(c.varyColors))
            this.setVaryColors(c.varyColors);
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    addAxId: function(pr)
    {
        if(!pr)
            return;
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_AreaChart_AddAxId, this.axId.length, [pr], true));
        this.axId.push(pr);
    },

    setDLbls: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_AreaChart_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateDataLabels();
        }
    },

    setDropLines: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_AreaChart_SetDropLines, this.dropLines, pr));
        this.dropLines = pr;
    },
    setGrouping: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_AreaChart_SetGrouping, this.grouping, pr));
        this.grouping = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    addSer: function(ser)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_AreaChart_AddSer, this.series.length, [ser], true));
        this.series.push(ser);
        ser.setParent(this);
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateType();
        }
    },
    setVaryColors: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_AreaChart_SetVaryColors, this.varyColors, pr));
        this.varyColors = pr;
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};


function CAreaSeries()
{
    this.cat            = null;
    this.dLbls          = null;
    this.dPt            = [];
    this.errBars        = null;
    this.idx            = null;
    this.order          = null;
    this.pictureOptions = null;
    this.spPr           = null;
    this.trendline      = null;

    this.parent = null;

    this.tx  = null;
    this.val = null;

    this.m_oDPtContentChanges = new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}
CAreaSeries.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_AreaSeries_SetDPt:
            case AscDFH.historyitem_CommonSeries_RemoveDPt:{
                return this.m_oDPtContentChanges;
            }
        }
        return null;
    },

    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var c = new CAreaSeries();
        if(this.cat)
        {
            c.setCat(this.cat.createDuplicate());
        }
        if(this.dLbls)
        {
            c.setDLbls(this.dLbls.createDuplicate());
        }
        for(var i = 0; i < this.dPt.length; ++i)
        {
            c.addDPt(this.dPt[i].createDuplicate());
        }
        if(this.errBars)
        {
            c.setErrBars(this.errBars.createDuplicate());
        }
        c.setIdx(this.idx);
        c.setOrder(this.order);
        if(this.pictureOptions)
        {
            c.setPictureOptions(this.pictureOptions.createDuplicate());
        }
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        if(this.trendline)
        {
            c.setTrendline(this.trendline.createDuplicate());
        }
        if(this.tx)
        {
            c.setTx(this.tx.createDuplicate());
        }
        if(this.val)
        {
            c.setVal(this.val.createDuplicate());
        }
        return c;
    },

    documentCreateFontMap: function(allFonts)
    {
        this.dLbls && this.dLbls.documentCreateFontMap(allFonts);
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_AreaSeries;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },


    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    getAllRasterImages: function(images)
    {
        this.spPr && this.spPr.checkBlipFillRasterImage(images);
        this.dLbls && this.dLbls.getAllRasterImages(images);
        this.marker && this.marker.spPr && this.marker.spPr.checkBlipFillRasterImage(images);
        if(this.dPt){
            for(var i = 0; i < this.dPt.length; ++i)
            {
                this.dPt[i].spPr && this.dPt[i].spPr.checkBlipFillRasterImage(images);
                this.dPt[i].marker && this.dPt[i].marker.spPr && this.dPt[i].marker.spPr.checkBlipFillRasterImage(images);
            }
        }
    },

    checkSpPrRasterImages: function(images)
    {
        checkSpPrRasterImages(this.spPr);
        checkSpPrRasterImages(this.dLbls);
        for(var i = 0; i < this.dPt.length; ++i)
        {
            checkSpPrRasterImages(this.dPt[i].spPr);
            this.dPt[i].marker && checkSpPrRasterImages(this.dPt[i].marker.spPr);
        }
    },

    setFromOtherSeries: function(o)
    {
        if(o.cat)
            this.setCat(o.cat);
        if(o.dLbls)
            this.setDLbls(o.dLbls);
        if(o.dPt)
        {
            for(var i = 0; i < o.dPt.length; ++i)
            {
                this.addDPt(o.dPt[i]);
            }
        }
        if(o.errBars)
            this.setErrBars(o.errBars);
        if(AscFormat.isRealNumber(o.idx))
            this.setIdx(o.idx);
        if(AscFormat.isRealNumber(o.order))
            this.setOrder(o.order);
        if(o.pictureOptions)
            this.setPictureOptions(o.pictureOptions);
        if(o.spPr){
            this.setSpPr(o.spPr);
            if((o instanceof AscFormat.CLineSeries) || (o instanceof AscFormat.CScatterSeries)){
                if(this.spPr && this.spPr.Fill && this.spPr.Fill.fill && this.spPr.Fill.fill.type ===  window['Asc'].c_oAscFill.FILL_TYPE_NOFILL){
                    this.spPr.setFill(null);
                }
            }
        }
        if(o.trendline)
            this.setTrendline(o.trendline);
        if(o.tx)
            this.setTx(o.tx);
        if(o.val)
            this.setVal(o.val);

        if(o.xVal)
        {
            this.setCat(new CCat());
            this.cat.setFromOtherObject(o.xVal);
        }
        if(o.yVal)
        {
            this.setVal(new CYVal());
            this.val.setFromOtherObject(o.yVal);
        }
    },

    getSeriesName: function()
    {
        if(this.tx)
        {
            if(typeof this.tx.val === "string")
            {
                return this.tx.val;
            }
            if(this.tx.strRef
                && this.tx.strRef.strCache
                && this.tx.strRef.strCache.pts.length > 0
                && this.tx.strRef.strCache.pts[0]
                && typeof this.tx.strRef.strCache.pts[0].val === "string")
            {
                return this.tx.strRef.strCache.pts[0].val;
            }
        }
        return AscCommon.translateManager.getValue('Series') + " " + (this.idx + 1);
    },

    getCatName: function(idx)
    {
        var pts;
        var cat;
        if(this.cat)
        {
            cat = this.cat;
        }
        else if(this.xVal)
        {
            cat = this.xVal;
        }

        if(cat)
        {
            if(cat && cat.strRef && cat.strRef.strCache)
            {
                pts = cat.strRef.strCache.pts;
            }
            else if(cat.numRef && cat.numRef.numCache)
            {
                pts = cat.numRef.numCache.pts;
            }
            if(Array.isArray(pts))
            {
                for(var i = 0; i < pts.length; ++i)
                {
                    if(pts[i].idx === idx)
                    {
                        return pts[i].val + "";
                    }
                }
            }
        }
        return (idx + 1) + "";
    },

    getFormatCode: function()
    {
        var pts;
        var val;
        if(this.val)
        {
            val = this.val;
        }
        else if(this.yVal)
        {
            val = this.yVal;
        }

        if(val)
        {
            if(val && val.strRef && val.strRef.strCache && val.strRef.strCache.formatCode)
            {
                return val.strRef.strCache.formatCode;
            }
            else if(val.strLit && val.strLit.formatCode)
            {
                return val.strLit.formatCode;
            }
            else if(val.numRef && val.numRef.numCache && val.numRef.numCache.formatCode)
            {
                return val.numRef.numCache.formatCode;
            }
            else if(val.numLit && val.numLit.formatCode)
            {
                return val.numLit.formatCode;
            }
        }
        return "General"
    },

    getValByIndex: function(idx, bPercent)
    {
        var pts;
        var val;
        if(this.val)
        {
            val = this.val;
        }
        else if(this.yVal)
        {
            val = this.yVal;
        }

        if(val)
        {
            if(val && val.strRef && val.strRef.strCache)
            {
                pts = val.strRef.strCache.pts;
            }
            else if(val.strLit)
            {
                pts = val.strLit.pts;
            }
            else if(val.numRef && val.numRef.numCache)
            {
                pts = val.numRef.numCache.pts;
            }
            else if(val.numLit)
            {
                pts = val.numLit.pts;
            }
            if(Array.isArray(pts))
            {
                var i;
                if(!(bPercent === true))
                {
                    for(i = 0; i < pts.length; ++i)
                    {
                        if(pts[i].idx === idx)
                        {
                            return pts[i].val + "";
                        }
                    }
                }
                else
                {
                    var summ = 0, value;
                    for(i = 0; i < pts.length; ++i)
                    {
                        if(AscFormat.isRealNumber(pts[i].val))
                            summ += Math.abs(pts[i].val);

                        if(pts[i].idx === idx)
                        {
                            value = pts[i].val;
                        }
                    }

                    if(summ > 0 && AscFormat.isRealNumber(value))
                        return Math.round(100*(value/summ)) + "%";
                }
            }
        }
        return "";
    },

    setCat: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_AreaSeries_SetCat, this.cat, pr));
        this.cat = pr;
    },
    setDLbls: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_AreaSeries_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
    },
    addDPt: function(pr)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_AreaSeries_SetDPt, this.dPt.length, [pr], true));
        this.dPt.push(pr);
    },

    removeDPt: function(idx)
    {
        if(this.dPt[idx])
        {
            var arrPt =  this.dPt.splice(idx, 1);
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonSeries_RemoveDPt, idx, arrPt, false));
        }
    },

    setErrBars: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_AreaSeries_SetErrBars, this.errBars, pr));
        this.errBars = pr;
    },
    setIdx: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_AreaSeries_SetIdx, this.idx, pr));
        this.idx = pr;
    },
    setOrder: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_AreaSeries_SetOrder, this.order, pr));
        this.order = pr;
    },
    setPictureOptions: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_AreaSeries_SetPictureOptions, this.pictureOptions, pr));
        this.pictureOptions = pr;
    },
    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_AreaSeries_SetSpPr, this.spPr, pr));
        this.spPr = pr;
    },
    setTrendline: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_AreaSeries_SetTrendline, this.trendline, pr));
        this.trendline = pr;
    },
    setTx: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_AreaSeries_SetTx, this.tx, pr));
        this.tx = pr;
    },

    setVal: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_AreaSeries_SetVal, this.val, pr));
        this.val = pr;
        if(this.val && this.val.setParent)
        {
            this.val.setParent(this);
        }
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};

var TYPE_AXIS_CAT = 0;
var TYPE_AXIS_DATE = 1;
var TYPE_AXIS_SER = 2;
var TYPE_AXIS_VAL = 3;

var AX_POS_L = 0;
var AX_POS_T = 1;
var AX_POS_R = 2;
var AX_POS_B = 3;

var CROSSES_AUTO_ZERO = 0;
var CROSSES_MAX = 1;
var CROSSES_MIN = 2;

var LBL_ALG_CTR = 0;
var LBL_ALG_L = 1;
var LBL_ALG_R = 2;

var TIME_UNIT_DAYS = 0;
var TIME_UNIT_MONTHS = 1;
var TIME_UNIT_YEARS = 2;

var CROSS_BETWEEN_BETWEEN = 0;
var CROSS_BETWEEN_MID_CAT = 1;

function CCatAx()
{
    this.auto            = null;
    this.axId            = null;
    this.axPos           = null;
    this.crossAx         = null;
    this.crosses         = null;
    this.crossesAt       = null;
    this.bDelete          = null;
    this.extLst          = null;
    this.lblAlgn         = null;
    this.lblOffset       = null;
    this.majorGridlines  = null;
    this.majorTickMark   = null;
    this.minorGridlines  = null;
    this.minorTickMark   = null;
    this.noMultiLvlLbl   = null;
    this.numFmt          = null;
    this.scaling         = null;
    this.spPr            = null;
    this.tickLblPos      = null;
    this.tickLblSkip     = null;
    this.tickMarkSkip    = null;
    this.title           = null;
    this.txPr            = null;

    this.parent = null;
    this.posX = null;
    this.posY = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);

}


CCatAx.prototype =
{

    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function()
    {
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
            this.parent.parent.parent.addToRecalculate();
        }
    },

    Refresh_RecalcData2: function(pageIndex, object)
    {
        this.parent && this.parent.parent && this.parent.parent.Refresh_RecalcData2(pageIndex, object);
    },

    getDrawingDocument: function()
    {
        return this.parent && this.parent.parent && this.parent.parent.getDrawingDocument && this.parent.parent.getDrawingDocument();
    },

    createDuplicate: function()
    {
        var c = new CCatAx();
        c.setAuto(this.auto);
        c.setAxPos(this.axPos);
        //todo crossAx выставляется родительским классом
        c.setCrosses(this.crosses);
        c.setCrossesAt(this.crossesAt);
        c.setDelete(this.bDelete);
        c.setLblAlgn(this.lblAlgn);
        c.setLblOffset(this.lblOffset);
        if(this.majorGridlines)
        {
            c.setMajorGridlines(this.majorGridlines.createDuplicate());
        }
        c.setMajorTickMark(this.majorTickMark);
        if(this.minorGridlines)
        {
            c.setMinorGridlines(this.minorGridlines.createDuplicate());
        }
        c.setMinorTickMark(this.minorTickMark);
        c.setNoMultiLvlLbl(this.noMultiLvlLbl);
        if(this.numFmt)
        {
            c.setNumFmt(this.numFmt.createDuplicate());
        }
        if(this.scaling)
        {
            c.setScaling(this.scaling.createDuplicate());
        }
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        c.setTickLblPos(this.tickLblPos);
        c.setTickLblSkip(this.tickLblSkip);
        c.setTickMarkSkip(this.tickMarkSkip);
        if(this.title)
        {
            c.setTitle(this.title.createDuplicate());
        }
        if(this.txPr)
        {
            c.setTxPr(this.txPr.createDuplicate());
        }
        return c;
    },

    getMenuProps: function()
    {
        var ret = new AscCommon.asc_CatAxisSettings();

        if(AscFormat.isRealNumber(this.tickMarkSkip))
            ret.putIntervalBetweenTick(this.tickMarkSkip);
        else
            ret.putIntervalBetweenTick(1);


        if(!AscFormat.isRealNumber(this.tickLblSkip))
            ret.putIntervalBetweenLabelsRule(c_oAscBetweenLabelsRule.auto);
        else
        {
            ret.putIntervalBetweenLabelsRule(c_oAscBetweenLabelsRule.manual);
            ret.putIntervalBetweenLabels(this.tickLblSkip);
        }

        var scaling = this.scaling;
        if(!scaling || scaling.orientation !== ORIENTATION_MAX_MIN)
            ret.putInvertCatOrder(false);
        else
            ret.putInvertCatOrder(true);

        //настройки пересечения с другой осью

        var crossAx = this.crossAx;

        if(crossAx)
        {
            if(AscFormat.isRealNumber(this.maxCatVal))
            {
                ret.putCrossMaxVal(this.maxCatVal);
            }
            ret.putCrossMinVal(1);
            if(AscFormat.isRealNumber(crossAx.crossesAt))
            {
                ret.putCrossesRule(c_oAscCrossesRule.value);
                ret.putCrosses(crossAx.crossesAt);
            }
            else if(crossAx.crosses === CROSSES_MAX)
            {
                ret.putCrossesRule(c_oAscCrossesRule.maxValue);
                if(AscFormat.isRealNumber(this.maxCatVal))
                {
                    ret.putCrosses(this.maxCatVal);
                }
            }
            else if(crossAx.crosses === CROSSES_MIN)
            {
                ret.putCrossesRule(c_oAscCrossesRule.minValue);
                ret.putCrosses(1);
            }
            else
            {
                ret.putCrossesRule(c_oAscCrossesRule.auto);
                ret.putCrosses(1);
            }
        }

        if(AscFormat.isRealNumber(this.lblOffset))
            ret.putLabelsAxisDistance(this.lblOffset);
        else
            ret.putLabelsAxisDistance(100);

        if(this.crossAx)
        {
            ret.putLabelsPosition(this.crossAx.crossBetween === CROSS_BETWEEN_MID_CAT ? c_oAscLabelsPosition.byDivisions : c_oAscLabelsPosition.betweenDivisions);
        }
        else
        {
            ret.putLabelsPosition(c_oAscLabelsPosition.betweenDivisions);
        }
        if(AscFormat.isRealNumber(this.tickLblPos))
            ret.putTickLabelsPos(this.tickLblPos);
        else
            ret.putTickLabelsPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);

        //настройки засечек на оси
        if(AscFormat.isRealNumber(this.majorTickMark))
            ret.putMajorTickMark(this.majorTickMark);
        else
            ret.putMajorTickMark(c_oAscTickMark.TICK_MARK_NONE);

        if(AscFormat.isRealNumber(this.minorTickMark))
            ret.putMinorTickMark(this.minorTickMark);
        else
            ret.putMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
        return ret;
    },


    setMenuProps: function(props)
    {
        if(!(isRealObject(props)
            && typeof props.getAxisType === "function"
            &&(props.getAxisType() === c_oAscAxisType.cat || props.getAxisType() === c_oAscAxisType.date)))
            return;

        var  intervalBetweenTick       = props.getIntervalBetweenTick();
        var  intervalBetweenLabelsRule = props.getIntervalBetweenLabelsRule();
        var  intervalBetweenLabels     = props.getIntervalBetweenLabels();
        var  invertCatOrder            = props.getInvertCatOrder();
        var  labelsAxisDistance        = props.getLabelsAxisDistance();
        var  axisType                  = props.getAxisType();
        var  majorTickMark             = props.getMajorTickMark();
        var  minorTickMark             = props.getMinorTickMark();
        var  tickLabelsPos             = props.getTickLabelsPos();
        var  crossesRule               = props.getCrossesRule();
        var  crosses                   = props.getCrosses();
        var  labelsPosition            = props.getLabelsPosition();


        var bChanged = false;
        if(AscFormat.isRealNumber(intervalBetweenTick) && this.tickMarkSkip !== intervalBetweenTick && this.setTickMarkSkip)
        {
            this.setTickMarkSkip(intervalBetweenTick);
            bChanged = true;
        }

        if(AscFormat.isRealNumber(intervalBetweenLabelsRule) && this.setTickLblSkip)
        {
            if(intervalBetweenLabelsRule === c_oAscBetweenLabelsRule.auto)
            {
                if(AscFormat.isRealNumber(this.tickLblSkip))
                {
                    this.setTickLblSkip(null);
                    bChanged = true;
                }
            }
            else if(intervalBetweenLabelsRule === c_oAscBetweenLabelsRule.manual && AscFormat.isRealNumber(intervalBetweenLabels) && this.tickLblSkip !== intervalBetweenLabels)
            {
                this.setTickLblSkip(intervalBetweenLabels);
                bChanged = true;
            }
        }

        if(!this.scaling)
            this.setScaling(new CScaling());
        var scaling = this.scaling;
        if(AscFormat.isRealBool(invertCatOrder))
        {
            var new_orientation = invertCatOrder ? ORIENTATION_MAX_MIN : ORIENTATION_MIN_MAX;
            if(scaling.orientation !== new_orientation)
            {
                scaling.setOrientation(invertCatOrder ? ORIENTATION_MAX_MIN : ORIENTATION_MIN_MAX);
                bChanged = true;
            }
        }
        if(AscFormat.isRealNumber(labelsAxisDistance) && this.lblOffset !== labelsAxisDistance && this.setLblOffset)
        {
            this.setLblOffset(labelsAxisDistance);
            bChanged = true;
        }

        if(AscFormat.isRealNumber(axisType))
        {
            //TODO
        }

        if(AscFormat.isRealNumber(majorTickMark) && this.majorTickMark !== majorTickMark)
        {
            this.setMajorTickMark(majorTickMark);
            bChanged = true;
        }

        if(AscFormat.isRealNumber(minorTickMark) && this.minorTickMark !== minorTickMark)
        {
            this.setMinorTickMark(minorTickMark);
            bChanged = true;
        }
        if(bChanged){
            if(this.spPr && this.spPr.ln && this.spPr.ln.Fill
                && this.spPr.ln.Fill.fill && this.spPr.ln.Fill.fill.type === window['Asc'].c_oAscFill.FILL_TYPE_NOFILL
            && (this.majorTickMark !== c_oAscTickMark.TICK_MARK_NONE || this.minorTickMark !== c_oAscTickMark.TICK_MARK_NONE)){
                this.spPr.setLn(null);
            }
        }

        if(AscFormat.isRealNumber(tickLabelsPos) && this.tickLblPos !== tickLabelsPos)
        {
            this.setTickLblPos(tickLabelsPos);
            bChanged = true;
        }


        if(AscFormat.isRealNumber(crossesRule) && isRealObject(this.crossAx))
        {
            if(crossesRule === c_oAscCrossesRule.auto)
            {
                if(this.crossAx.crossesAt !== null)
                {
                    this.crossAx.setCrossesAt(null);
                    bChanged = true;
                }
                if(this.crossAx.crosses !== CROSSES_AUTO_ZERO)
                {
                    this.crossAx.setCrosses(CROSSES_AUTO_ZERO);
                    bChanged = true;
                }
            }
            else if(crossesRule === c_oAscCrossesRule.value)
            {
                if(AscFormat.isRealNumber(crosses))
                {
                    if(this.crossAx.crossesAt !== crosses)
                    {
                        this.crossAx.setCrossesAt(crosses);
                        bChanged = true;
                    }
                    if(this.crossAx !== null)
                    {
                        this.crossAx.setCrosses(null);
                        bChanged = true;
                    }
                }
            }
            else if(crossesRule === c_oAscCrossesRule.maxValue)
            {
                if(this.crossAx.crossesAt !== null)
                {
                    this.crossAx.setCrossesAt(null);
                    bChanged = true;
                }
                if(this.crossAx.crosses !== CROSSES_MAX)
                {
                    this.crossAx.setCrosses(CROSSES_MAX);
                    bChanged = true;
                }
            }
            else if(crossesRule === c_oAscCrossesRule.minValue)
            {
                if(this.crossAx.crossesAt !== null)
                {
                    this.crossAx.setCrossesAt(null);
                    bChanged = true;
                }
                if(this.crossAx.crosses !== CROSSES_MIN)
                {
                    this.crossAx.setCrosses(CROSSES_MIN);
                    bChanged = true;
                }
            }
        }

        if(AscFormat.isRealNumber(labelsPosition) && isRealObject(this.crossAx) && this.crossAx.setCrossBetween)
        {
            var new_lbl_position = labelsPosition === c_oAscLabelsPosition.byDivisions ? CROSS_BETWEEN_MID_CAT : CROSS_BETWEEN_BETWEEN;
            if(this.crossAx.crossBetween !== new_lbl_position)
            {
                this.crossAx.setCrossBetween(new_lbl_position);
                bChanged = true;
            }
        }
        if(bChanged)
        {
            if(this.bDelete === true)
            {
                this.setDelete(false);
            }
        }
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_CatAx;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
    },

    setAuto: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_CatAxSetAuto, this.auto, pr));
        this.auto = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setAxId: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_CatAxSetAxId, this.axId, pr));
        this.axId = pr;
    },
    setAxPos: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_CatAxSetAxPos, this.axPos, pr));
        this.axPos = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setCrossAx: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CatAxSetCrossAx, this.crossAx, pr));
        this.crossAx = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setCrosses: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_CatAxSetCrosses, this.crosses, pr));
        this.crosses = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setCrossesAt: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_CatAxSetCrossesAt, this.crossesAt, pr));
        this.crossesAt = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setDelete: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_CatAxSetDelete, this.bDelete, pr));
        this.bDelete = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setLblAlgn: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_CatAxSetLblAlgn, this.lblAlgn, pr));
        this.lblAlgn = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setLblOffset: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_CatAxSetLblOffset, this.lblOffset, pr));
        this.lblOffset = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setMajorGridlines: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CatAxSetMajorGridlines, this.majorGridlines, pr));
        this.majorGridlines = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateGridlines();
        }
    },
    setMajorTickMark: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_CatAxSetMajorTickMark, this.majorTickMark, pr));
        this.majorTickMark = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setMinorGridlines: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CatAxSetMinorGridlines, this.minorGridlines, pr));
        this.minorGridlines = pr;

        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateGridlines();
        }
    },
    setMinorTickMark: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_CatAxSetMinorTickMark, this.minorTickMark, pr));
        this.minorTickMark = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setNoMultiLvlLbl: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_CatAxSetNoMultiLvlLbl, this.noMultiLvlLbl, pr));
        this.noMultiLvlLbl = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setNumFmt: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CatAxSetNumFmt, this.numFmt, pr));
        this.numFmt = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setScaling: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CatAxSetScaling, this.scaling, pr));
        this.scaling = pr;
        if(this.scaling)
        {
            this.scaling.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CatAxSetSpPr, this.spPr, pr));
        this.spPr = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setTickLblPos: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_CatAxSetTickLblPos, this.tickLblPos, pr));
        this.tickLblPos = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setTickLblSkip: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_CatAxSetTickLblSkip, this.tickLblSkip, pr));
        this.tickLblSkip = pr;
    },
    setTickMarkSkip: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_CatAxSetTickMarkSkip, this.tickMarkSkip, pr));
        this.tickMarkSkip = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setTitle: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CatAxSetTitle, this.title, pr));
        this.title = pr;
        if(pr)
        {
            pr.setParent(this);
        }

        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },

    getParentObjects: function()
    {
        return this.parent && this.parent.getParentObjects();
    },

    setTxPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CatAxSetTxPr, this.txPr, pr));
        this.txPr = pr;
        if(this.txPr)
        {
            this.txPr.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.handleUpdateInternalChart)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },

    handleUpdateFill: function()
    {
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },

    handleUpdateLn: function()
    {
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
            }
};

function CDateAx()
{
    this.auto           = null;
    this.axId           = null;
    this.axPos          = null;
    this.baseTimeUnit   = null;
    this.crossAx        = null;
    this.crosses        = null;
    this.crossesAt      = null;
    this.bDelete        = null;
    this.extLst         = null;
    this.lblOffset      = null;
    this.majorGridlines = null;
    this.majorTickMark  = null;
    this.majorTimeUnit  = null;
    this.majorUnit      = null;
    this.minorGridlines = null;
    this.minorTickMark  = null;
    this.minorTimeUnit  = null;

    this.minorUnit      = null;
    this.numFmt         = null;
    this.scaling        = null;
    this.spPr           = null;
    this.tickLblPos     = null;
    this.title          = null;
    this.txPr           = null;

    this.parent = null;
    this.posX = null;
    this.posY = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CDateAx.prototype =
{
    Get_Id: function()
    {
        return  this.Id;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_DateAx;
    },

    Refresh_RecalcData2: function(pageIndex, object)
    {
        this.parent && this.parent.parent && this.parent.parent.Refresh_RecalcData2(pageIndex, object);
    },

    getDrawingDocument: function()
    {
        return this.parent && this.parent.parent && this.parent.parent.getDrawingDocument && this.parent.parent.getDrawingDocument();
    },
    Refresh_RecalcData: function(pageIndex, object)
    {
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
            this.parent.parent.parent.addToRecalculate();
        }
    },

    getMenuProps: CCatAx.prototype.getMenuProps,
    setMenuProps: CCatAx.prototype.setMenuProps,

    createDuplicate: function()
    {
        var c = new CDateAx();
        c.setAuto(this.auto);
        c.setAxPos(this.axPos);
        c.setBaseTimeUnit(this.baseTimeUnit);
        c.setCrosses(this.crosses);
        c.setCrossesAt(this.crossesAt);
        c.setDelete(this.bDelete);
        c.setLblOffset(this.lblOffset);
        if(this.majorGridlines)
        {
            c.setMajorGridlines(this.majorGridlines.createDuplicate());
        }
        c.setMajorTickMark(this.majorTickMark);
        c.setMajorTimeUnit(this.majorTimeUnit);
        if(this.minorGridlines)
        {
            c.setMinorGridlines(this.minorGridlines.createDuplicate());
        }
        c.setMinorTickMark(this.minorTickMark);
        c.setMinorTimeUnit(this.minorTimeUnit);
        if(this.numFmt)
        {
            c.setNumFmt(this.numFmt.createDuplicate());
        }
        if(this.scaling)
        {
            c.setScaling(this.scaling.createDuplicate());
        }
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        c.setTickLblPos(this.tickLblPos);
        if(this.title)
        {
            c.setTitle(this.title.createDuplicate());
        }
        if(this.txPr)
        {
            c.setTxPr(this.txPr.createDuplicate());
        }
        return c;
    },

    setAuto: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DateAxAuto, this.auto, pr));
        this.auto = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }

    },
    setAxId: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_DateAxAxId, this.axId, pr));
        this.axId = pr;

    },
    setAxPos: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_DateAxAxPos, this.axPos, pr));
        this.axPos = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }

    },
    setBaseTimeUnit: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_DateAxBaseTimeUnit, this.baseTimeUnit, pr));
        this.baseTimeUnit = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }

    },
    setCrossAx: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DateAxCrossAx, this.crossAx, pr));
        this.crossAx = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }

    },
    setCrosses: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_DateAxCrosses, this.crosses, pr));
        this.crosses = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }

    },
    setCrossesAt: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_DateAxCrossesAt, this.crossesAt, pr));
        this.crossesAt = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setDelete: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DateAxDelete, this.bDelete, pr));
        this.bDelete = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }

    },
    setLblOffset: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_DateAxLblOffset, this.lblOffset, pr));
        this.lblOffset = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }

    },
    setMajorGridlines: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DateAxMajorGridlines, this.majorGridlines, pr));
        this.majorGridlines = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateGridlines();
        }

    },
    setMajorTickMark: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_DateAxMajorTickMark, this.majorTickMark, pr));
        this.majorTickMark = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }

    },
    setMajorTimeUnit: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_DateAxMajorTimeUnit, this.majorTimeUnit, pr));
        this.majorTimeUnit = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }

    },
    setMajorUnit: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_DateAxMajorUnit, this.majorUnit, pr));
        this.majorUnit = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }

    },
    setMinorGridlines: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DateAxMajorGridlines, this.majorGridlines, pr));
        this.majorGridlines = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateGridlines();
        }

    },
    setMinorTickMark: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_DateAxMinorTickMark, this.minorTickMark, pr));
        this.minorTickMark = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }

    },
    setMinorTimeUnit: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_DateAxMinorTimeUnit, this.minorTimeUnit, pr));
        this.minorTimeUnit = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    ///
    setMinorUnit: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_DateAxMinorUnit, this.minorUnit, pr));
        this.minorUnit = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setNumFmt: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DateAxNumFmt, this.numFmt, pr));
        this.numFmt = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setScaling: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DateAxScaling, this.scaling, pr));
        this.scaling = pr;
        if(this.scaling)
        {
            this.scaling.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DateAxSpPr, this.spPr, pr));
        this.spPr = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setTickLblPos: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_DateAxTickLblPos, this.tickLblPos, pr));
        this.tickLblPos = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setTitle: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DateAxTitle, this.title, pr));
        this.title = pr;
        if(pr)
        {
            pr.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },

    getParentObjects: function()
    {
        return this.parent && this.parent.getParentObjects();
    },

    setTxPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DateAxTxPr, this.txPr, pr));
        this.txPr = pr;
        if(this.txPr)
        {
            this.txPr.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.handleUpdateInternalChart)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    //

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },


    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};

function CSerAx()
{
    this.axId           = null;
    this.axPos          = null;
    this.crossAx        = null;
    this.crosses        = null;
    this.crossesAt      = null;
    this.bDelete        = null;
    this.extLst         = null;
    this.majorGridlines = null;
    this.majorTickMark  = null;
    this.minorGridlines = null;
    this.minorTickMark  = null;
    this.numFmt         = null;
    this.scaling        = null;
    this.spPr           = null;
    this.tickLblPos     = null;
    this.tickLblSkip    = null;
    this.tickMarkSkip   = null;
    this.title          = null;
    this.txPr           = null;

    this.parent = null;
    this.posX = null;
    this.posY = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CSerAx.prototype =
{
    getObjectType: function()
    {
        return AscDFH.historyitem_type_SerAx;
    },

    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData2: function(pageIndex, object)
    {
        this.parent && this.parent.parent && this.parent.parent.Refresh_RecalcData2(pageIndex, object);
    },


    getMenuProps: CCatAx.prototype.getMenuProps,
    setMenuProps: CCatAx.prototype.setMenuProps,


    getDrawingDocument: function()
    {
        return this.parent && this.parent.parent && this.parent.parent.getDrawingDocument && this.parent.parent.getDrawingDocument();
    },
    Refresh_RecalcData: function(pageIndex, object)
    {
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
            this.parent.parent.parent.addToRecalculate();
        }
    },

    createDuplicate: function()
    {
        var c = new CSerAx();
        c.setAxPos(this.axPos);
        c.setCrosses(this.crosses);
        c.setCrossesAt(this.crossesAt);
        c.setDelete(this.bDelete);
        if(this.majorGridlines)
        {
            c.setMajorGridlines(this.majorGridlines.createDuplicate());
        }
        c.setMajorTickMark(this.majorTickMark);
        if(this.minorGridlines)
        {
            c.setMajorGridlines(this.minorGridlines.createDuplicate());
        }
        c.setMajorTickMark(this.minorTickMark);
        if(this.numFmt)
        {
            c.setNumFmt(this.numFmt.createDuplicate());
        }
        if(this.scaling)
        {
            c.setScaling(this.scaling.createDuplicate());
        }
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        c.setTickLblPos(this.tickLblPos);
        c.setTickLblSkip(this.tickLblSkip);
        c.setTickMarkSkip(this.tickMarkSkip);
        if(this.title)
        {
            c.setTitle(this.title.createDuplicate());
        }
        if(this.txPr)
        {
            c.setTxPr(this.txPr.createDuplicate());
        }
        return c;
    },

    setAxId: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_SerAxSetAxId, this.axId, pr));
        this.axId = pr;
    },
    setAxPos: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_SerAxSetAxPos, this.axPos, pr));
        this.axPos = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setCrossAx: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_SerAxSetCrossAx, this.crossAx, pr));
        this.crossAx = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setCrosses: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_SerAxSetCrosses, this.crosses, pr));
        this.crosses = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setCrossesAt: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_SerAxSetCrossesAt, this.crossesAt, pr));
        this.crossesAt = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setDelete: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_SerAxSetDelete, this.bDelete, pr));
        this.bDelete = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setMajorGridlines: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_SerAxSetMajorGridlines, this.majorGridlines, pr));
        this.majorGridlines = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateGridlines();
        }
    },
    setMajorTickMark: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_SerAxSetMajorTickMark, this.majorTickMark, pr));
        this.majorTickMark = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateGridlines();
        }
    },
    setMinorGridlines: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_SerAxSetMinorGridlines, this.majorGridlines, pr));
        this.majorGridlines = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateGridlines();
        }
    },
    setMinorTickMark: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_SerAxSetMinorTickMark, this.minorTickMark, pr));
        this.minorTickMark = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setNumFmt: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_SerAxSetNumFmt, this.numFmt, pr));
        this.numFmt = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setScaling: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_SerAxSetScaling, this.scaling, pr));
        this.scaling = pr;
        if(this.scaling)
        {
            this.scaling.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_SerAxSetSpPr, this.spPr, pr));
        this.spPr = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setTickLblPos: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_SerAxSetTickLblPos, this.tickLblPos, pr));
        this.tickLblPos = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setTickLblSkip: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_SerAxSetTickLblSkip, this.tickLblSkip, pr));
        this.tickLblSkip = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setTickMarkSkip: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_SerAxSetTickMarkSkip, this.tickMarkSkip, pr));
        this.tickMarkSkip = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setTitle: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_SerAxSetTitle, this.title, pr));
        this.title = pr;
        if(pr)
        {
            pr.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },

    getParentObjects: function()
    {
        return this.parent && this.parent.getParentObjects();
    },

    setTxPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_SerAxSetTxPr, this.txPr, pr));
        this.txPr = pr;
        if(this.txPr)
        {
            this.txPr.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.handleUpdateInternalChart)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
            }
};



function CValAx()
{
    this.axId           = null;
    this.axPos          = null;
    this.crossAx        = null;
    this.crossBetween   = null;
    this.crosses        = null;
    this.crossesAt      = null;
    this.bDelete        = null;
    this.dispUnits      = null;
    this.extLst         = null;
    this.majorGridlines = null;
    this.majorTickMark  = null;
    this.majorUnit      = null;
    this.minorGridlines = null;
    this.minorTickMark  = null;
    this.minorUnit      = null;
    this.numFmt         = null;
    this.scaling        = null;
    this.spPr           = null;
    this.tickLblPos     = null;
    this.title          = null;
    this.txPr           = null;

    this.parent = null;
    this.posX = null;
    this.posY = null;


    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}


CValAx.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function()
    {
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
            this.parent.parent.parent.addToRecalculate();
        }
    },


    Refresh_RecalcData2: function(pageIndex, object)
    {
        this.parent && this.parent.parent && this.parent.parent.Refresh_RecalcData2(pageIndex, object);
    },
    getDrawingDocument: function()
    {
        return this.parent && this.parent.parent && this.parent.parent.getDrawingDocument && this.parent.parent.getDrawingDocument();
    },

    createDuplicate: function(o)
    {
        var c;
        if(o)
        {
            c = o;
        }
        else
        {
            c = new CValAx();
        }
        c.setAxPos(this.axPos);
        c.setCrossBetween(this.crossBetween);
        c.setCrosses(this.crosses);
        c.setCrossesAt(this.crossesAt);
        c.setDelete(this.bDelete);
        if(this.dispUnits)
        {
            c.setDispUnits(this.dispUnits.createDuplicate());
        }
        if(this.majorGridlines)
        {
            c.setMajorGridlines(this.majorGridlines.createDuplicate());
        }
        c.setMajorTickMark(this.majorTickMark);
        c.setMajorUnit(this.majorUnit);

        if(this.minorGridlines)
        {
            c.setMinorGridlines(this.minorGridlines.createDuplicate());
        }
        c.setMinorTickMark(this.minorTickMark);
        c.setMinorUnit(this.minorUnit);

        this.numFmt && c.setNumFmt(this.numFmt.createDuplicate());
        this.scaling && c.setScaling(this.scaling.createDuplicate());
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        c.setTickLblPos(this.tickLblPos);
        if(this.title)
        {
            c.setTitle(this.title.createDuplicate());
        }
        if(this.txPr)
        {
            c.setTxPr(this.txPr.createDuplicate());
        }
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_ValAx;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },


    setAxId: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_ValAxSetAxId, this.axId, pr));
        this.axId = pr;
    },
    setAxPos: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_ValAxSetAxPos, this.axPos, pr));
        this.axPos = pr;

        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setCrossAx: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ValAxSetCrossAx, this.crossAx, pr));
        this.crossAx = pr;

        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setCrossBetween: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_ValAxSetCrossBetween, this.crossBetween, pr));
        this.crossBetween = pr;

        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setCrosses: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_ValAxSetCrosses, this.crosses, pr));
        this.crosses = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setCrossesAt: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_ValAxSetCrossesAt, this.crossesAt, pr));
        this.crossesAt = pr;

        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setDelete: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_ValAxSetDelete, this.bDelete, pr));
        this.bDelete = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setDispUnits: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ValAxSetDispUnits, this.dispUnits, pr));
        this.dispUnits = pr;
        if(this.dispUnits)
        {
            this.dispUnits.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setMajorGridlines: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ValAxSetMajorGridlines, this.majorGridlines, pr));
        this.majorGridlines = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateGridlines();
        }
    },
    setMajorTickMark: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_ValAxSetMajorTickMark, this.majorTickMark, pr));
        this.majorTickMark = pr;

        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setMajorUnit: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_ValAxSetMajorUnit, this.majorUnit, pr));
        this.majorUnit = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setMinorGridlines: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ValAxSetMinorGridlines, this.minorGridlines, pr));
        this.minorGridlines = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateGridlines();
        }
    },
    setMinorTickMark: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_ValAxSetMinorTickMark, this.minorTickMark, pr));
        this.minorTickMark = pr;

        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setMinorUnit: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_ValAxSetMinorUnit, this.minorUnit, pr));
        this.minorUnit = pr;

        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setNumFmt: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ValAxSetNumFmt, this.numFmt, pr));
        this.numFmt = pr;

        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setScaling: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ValAxSetScaling, this.scaling, pr));
        this.scaling = pr;
        if(this.scaling)
        {
            this.scaling.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ValAxSetSpPr, this.spPr, pr));
        this.spPr = pr;

        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setTickLblPos: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_ValAxSetTickLblPos, this.tickLblPos, pr));
        this.tickLblPos = pr;

        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setTitle: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ValAxSetTitle, this.title, pr));
        this.title = pr;
        if(pr)
        {
            pr.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },

    getParentObjects: function()
    {
        return this.parent && this.parent.getParentObjects();
    },

    setTxPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ValAxSetTxPr, this.txPr, pr));
        this.txPr = pr;
        if(this.txPr)
        {
            this.txPr.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.handleUpdateInternalChart)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
    },

    handleUpdateFill: function()
    {
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },

    handleUpdateLn: function()
    {
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },


    getMenuProps: function()
    {
        var ret = new AscCommon.asc_ValAxisSettings();
        var scaling = this.scaling;

        //настройки логарифмической шкалы
        if(scaling && AscFormat.isRealNumber(scaling.logBase))
        {
            ret.putLogScale(true);
            ret.putLogBase(scaling.logBase);
        }
        else
        {
            ret.putLogScale(false);
        }

        var oMinMaxOnAxis;
        if(this.axPos === AX_POS_L || this.axPos === AX_POS_R)
        {
            oMinMaxOnAxis = getMinMaxFromArrPoints(this.yPoints);
        }
        else
        {
            oMinMaxOnAxis = getMinMaxFromArrPoints(this.xPoints);
        }
        //настроки максимального значения по оси
        if(scaling && AscFormat.isRealNumber(scaling.max))
        {
            ret.putMaxValRule(c_oAscValAxisRule.fixed);
            ret.putMaxVal(scaling.max);
        }
        else
        {
            ret.putMaxValRule(c_oAscValAxisRule.auto);
            ret.putMaxVal(oMinMaxOnAxis.max);
        }

        //настройки минимального значения по оси
        if(scaling && AscFormat.isRealNumber(scaling.min))
        {
            ret.putMinValRule(c_oAscValAxisRule.fixed);
            ret.putMinVal(scaling.min);
        }
        else
        {
            ret.putMinValRule(c_oAscValAxisRule.auto);
            ret.putMinVal(oMinMaxOnAxis.min);
        }

        //настройка ориентации оси
        ret.putInvertValOrder(scaling && scaling.orientation === ORIENTATION_MAX_MIN);

        //настройка множителя единиц на оси
        if(isRealObject(this.dispUnits))
        {
            var disp_units = this.dispUnits;
            if(AscFormat.isRealNumber(disp_units.builtInUnit))
            {
                ret.putDispUnitsRule(disp_units.builtInUnit);
                ret.putShowUnitsOnChart(isRealObject(disp_units.dispUnitsLbl));
            }
            else if(AscFormat.isRealNumber(disp_units.custUnit))
            {
                ret.putDispUnitsRule(c_oAscValAxUnits.CUSTOM);
                ret.putUnits(disp_units.custUnit);
                ret.putShowUnitsOnChart(isRealObject(disp_units.dispUnitsLbl));
            }
            else
            {
                ret.putDispUnitsRule(c_oAscValAxUnits.none);
                ret.putShowUnitsOnChart(false);
            }
        }
        else
        {
            ret.putDispUnitsRule(c_oAscValAxUnits.none);
            ret.putShowUnitsOnChart(false);
        }

        //настройки засечек на оси
        if(AscFormat.isRealNumber(this.majorTickMark))
            ret.putMajorTickMark(this.majorTickMark);
        else
            ret.putMajorTickMark( c_oAscTickMark.TICK_MARK_NONE);

        if(AscFormat.isRealNumber(this.minorTickMark))
            ret.putMinorTickMark(this.minorTickMark);
        else
            ret.putMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);

        if(AscFormat.isRealNumber(this.tickLblPos))
            ret.putTickLabelsPos(this.tickLblPos);
        else
            ret.putTickLabelsPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);

        var crossAx = this.crossAx;
        if(crossAx)
        {
            //настройки пересечения с другой осью
            if(AscFormat.isRealNumber(crossAx.crossesAt))
            {
                ret.putCrossesRule(c_oAscCrossesRule.value);
                ret.putCrosses(crossAx.crossesAt);
            }
            else if(crossAx.crosses === CROSSES_MAX)
            {
                ret.putCrossesRule(c_oAscCrossesRule.maxValue);
                ret.putCrosses(oMinMaxOnAxis.max);
            }
            else if(crossAx.crosses === CROSSES_MIN)
            {
                ret.putCrossesRule(c_oAscCrossesRule.minValue);
                ret.putCrosses(oMinMaxOnAxis.min);
            }
            else
            {
                ret.putCrossesRule(c_oAscCrossesRule.auto);
                if(AscFormat.isRealNumber(oMinMaxOnAxis.min) && AscFormat.isRealNumber(oMinMaxOnAxis.max))
                {
                    if(0 >= oMinMaxOnAxis.min && 0 <= oMinMaxOnAxis.max)
                    {
                        ret.putCrosses(0);
                    }
                    else if(oMinMaxOnAxis.min > 0)
                    {
                        ret.putCrosses(oMinMaxOnAxis.min);
                    }
                    else
                    {
                        ret.putCrosses(oMinMaxOnAxis.max);
                    }
                }
            }
        }
        return ret;
    },

    setMenuProps: function(props)
    {
        var bChanged = false;
        if(!(isRealObject(props) && typeof props.getAxisType === "function" && props.getAxisType() === c_oAscAxisType.val))
            return;
        if(!this.scaling)
            this.setScaling(new CScaling());

        var scaling = this.scaling;
        if(AscFormat.isRealNumber(props.minValRule))
        {
            if(props.minValRule === c_oAscValAxisRule.auto)
            {
                if(AscFormat.isRealNumber(scaling.min))
                {
                    scaling.setMin(null);
                    bChanged = true;
                }
            }
            else
            {
                if(AscFormat.isRealNumber(props.minVal))
                {
                    if(!(props.maxValRule === c_oAscValAxisRule.fixed && props.maxVal < props.minVal) && scaling.min !== props.minVal)
                    {
                        scaling.setMin(props.minVal);
                        bChanged = true;
                    }
                }
            }
        }

        if(AscFormat.isRealNumber(props.maxValRule))
        {
            if(props.maxValRule === c_oAscValAxisRule.auto)
            {
                if(AscFormat.isRealNumber(scaling.max))
                {
                    scaling.setMax(null);
                    bChanged = true;
                }
            }
            else
            {
                if(AscFormat.isRealNumber(props.maxVal))
                {
                    if(!AscFormat.isRealNumber(scaling.min) || scaling.min < props.maxVal)
                    {
                        if(scaling.max !== props.maxVal)
                        {
                            scaling.setMax(props.maxVal);
                            bChanged = true;
                        }
                    }
                }
            }
        }

        if(AscFormat.isRealBool(props.invertValOrder))
        {
            var new_or = props.invertValOrder ? ORIENTATION_MAX_MIN : ORIENTATION_MIN_MAX;
            if(scaling.orientation !== new_or)
            {
                scaling.setOrientation(new_or);
                bChanged = true;
            }
        }


        if(AscFormat.isRealBool(props.logScale))
        {
            if(props.logScale && AscFormat.isRealNumber(props.logBase) && props.logBase >= 2 && props.logBase <=1000)
            {
                if(scaling.logBase !== props.logBase)
                {
                    scaling.setLogBase(props.logBase);
                    bChanged = true;
                }
            }
            else if(!props.logBase && scaling.logBase !== null)
            {
                scaling.setLogBase(null);
                bChanged = true;
            }
        }

        if(AscFormat.isRealNumber(props.dispUnitsRule))
        {
            if(props.dispUnitsRule === c_oAscValAxUnits.none)
            {
                if(this.dispUnits)
                {
                    this.setDispUnits(null);
                    bChanged = true;
                }
            }
            else
            {
                if(!this.dispUnits)
                {
                    this.setDispUnits(new CDispUnits());
                    bChanged = true;
                }
                if(this.dispUnits.builtInUnit !== props.dispUnitsRule)
                {
                    this.dispUnits.setBuiltInUnit(props.dispUnitsRule);
                    bChanged = true;
                }
                if(AscFormat.isRealBool(this.showUnitsOnChart))
                {
                    this.dispUnits.setDispUnitsLbl(new CDLbl());
                    bChanged = true;
                }
            }
        }

        if(AscFormat.isRealNumber(props.majorTickMark) && this.majorTickMark !== props.majorTickMark)
        {
            this.setMajorTickMark(props.majorTickMark);
            bChanged = true;
        }

        if(AscFormat.isRealNumber(props.minorTickMark) && this.minorTickMark !== props.minorTickMark)
        {
            this.setMinorTickMark(props.minorTickMark);
            bChanged = true;
        }
        if(bChanged){
            if(this.spPr && this.spPr.ln && this.spPr.ln.Fill
                && this.spPr.ln.Fill.fill && this.spPr.ln.Fill.fill.type === window['Asc'].c_oAscFill.FILL_TYPE_NOFILL
                && (this.majorTickMark !== c_oAscTickMark.TICK_MARK_NONE || this.minorTickMark !== c_oAscTickMark.TICK_MARK_NONE)){
                this.spPr.setLn(null);
            }
        }

        if(AscFormat.isRealNumber(props.tickLabelsPos) && this.tickLblPos !== props.tickLabelsPos)
        {
            this.setTickLblPos(props.tickLabelsPos);
            bChanged = true;
        }

        if(AscFormat.isRealNumber(props.crossesRule) && isRealObject(this.crossAx))
        {
            if(props.crossesRule === c_oAscCrossesRule.auto)
            {
                if(this.crossAx.crossesAt !== null)
                {
                    this.crossAx.setCrossesAt(null);
                    bChanged = true;
                }
                if(this.crossAx.crosses !== CROSSES_AUTO_ZERO)
                {
                    this.crossAx.setCrosses(CROSSES_AUTO_ZERO);
                    bChanged = true;
                }
            }
            else if(props.crossesRule === c_oAscCrossesRule.value)
            {
                if(AscFormat.isRealNumber(props.crosses))
                {
                    if(this.crossAx.crossesAt !== props.crosses)
                    {
                        this.crossAx.setCrossesAt(props.crosses);
                        bChanged = true;
                    }
                    if(this.crossAx.crosses !== null)
                    {
                        this.crossAx.setCrosses(null);
                        bChanged = true;
                    }
                }
            }
            else if(props.crossesRule === c_oAscCrossesRule.maxValue)
            {
                if(this.crossAx.crossesAt !== null)
                {
                    this.crossAx.setCrossesAt(null);
                    bChanged = true;
                }
                if(this.crossAx.crosses !== CROSSES_MAX)
                {
                    this.crossAx.setCrosses(CROSSES_MAX);
                    bChanged = true;
                }
            }
            else if(props.crossesRule === c_oAscCrossesRule.minValue)
            {
                if(this.crossAx.crossesAt !== null)
                {
                    this.crossAx.setCrossesAt(null);
                    bChanged = true;
                }
                if(this.crossAx.crosses !== CROSSES_MIN)
                {
                    this.crossAx.setCrosses(CROSSES_MIN);
                    bChanged = true;
                }
            }
        }

        if(bChanged)
        {
            if(this.bDelete === true)
            {
                this.setDelete(false);
            }
        }
    }
};


function CBandFmt()
{
    this.idx = null;
    this.spPr = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CBandFmt.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var c = new CBandFmt();
        c.setIdx(this.idx);
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_BandFmt;
    },

    setIdx: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_BandFmt_SetIdx, this.idx, pr));
        this.idx = pr;
    },

    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BandFmt_SetSpPr, this.spPr, pr));
        this.spPr = pr;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
            }
};

function CBarSeries()
{
    this.cat               = null;
    this.dLbls            = null;
    this.dPt               = [];
    this.errBars           = null;
    this.idx              = null;
    this.invertIfNegative  = null;
    this.order             = null;
    this.pictureOptions    = null;
    this.shape            = null;
    this.spPr             = null;
    this.trendline        = null;
    this.tx              = null;
    this.val             = null;

    this.parent = null;


    this.m_oDPtContentChanges = new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CBarSeries.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_BarSeries_SetDPt:
            case AscDFH.historyitem_CommonSeries_RemoveDPt:{
                return this.m_oDPtContentChanges;
            }
        }
        return null;
    },

    Refresh_RecalcData: function()
    {},

    removeDPt: function(idx)
    {
        if(this.dPt[idx])
        {
            var arrPt = this.dPt.splice(idx, 1);
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonSeries_RemoveDPt, idx, arrPt, false));
        }
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_BarSeries;
    },

    createDuplicate: function()
    {
        var c = new CBarSeries();
        if(this.cat)
        {
            c.setCat(this.cat.createDuplicate());
        }
        if(this.dLbls)
        {
            c.setDLbls(this.dLbls.createDuplicate());
        }
        for(var i = 0; i < this.dPt.length; ++i)
        {
            c.addDPt(this.dPt[i].createDuplicate());
        }
        if(this.errBars)
        {
            c.setErrBars(this.errBars.createDuplicate());
        }
        c.setIdx(this.idx);
        c.setInvertIfNegative(this.invertIfNegative);
        c.setOrder(this.order);
        if(this.pictureOptions)
        {
            c.setPictureOptions(this.pictureOptions.createDuplicate());
        }
        c.setShape(this.shape);
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        if(this.trendline)
        {
            c.setTrendline(this.trendline.createDuplicate());
        }
        if(this.tx)
        {
            c.setTx(this.tx.createDuplicate());
        }
        if(this.val)
        {
            c.setVal(this.val.createDuplicate());
        }
        return c;
    },

    documentCreateFontMap: CAreaSeries.prototype.documentCreateFontMap,

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    getAllRasterImages: CAreaSeries.prototype.getAllRasterImages,
    checkSpPrRasterImages: CAreaSeries.prototype.checkSpPrRasterImages,

    setFromOtherSeries: function(o)
    {
        if(o.cat)
            this.setCat(o.cat);
        if(o.dLbls)
            this.setDLbls(o.dLbls);
        if(o.dPt)
        {
            for(var i = 0;  i< o.dPt.length; ++i)
            {
                this.addDPt(o.dPt[i]);
            }
        }
        if(o.errBars)
            this.setErrBars(o.errBars);
        if(AscFormat.isRealNumber(o.idx))
            this.setIdx(o.idx);
        if(AscFormat.isRealBool(o.invertIfNegative))
            this.setInvertIfNegative(o.invertIfNegative);
        if(AscFormat.isRealNumber(o.order))
            this.setOrder(o.order);
        if(o.pictureOptions)
            this.setPictureOptions(o.pictureOptions);
        if(o.shape)
            this.setShape(o.shape);
        if(o.spPr){
            this.setSpPr(o.spPr);
            if((o instanceof AscFormat.CLineSeries) || (o instanceof AscFormat.CScatterSeries)){
                if(this.spPr && this.spPr.Fill && this.spPr.Fill.fill && this.spPr.Fill.fill.type ===  window['Asc'].c_oAscFill.FILL_TYPE_NOFILL){
                    this.spPr.setFill(null);
                }
            }
        }

        if(o.trendline)
            this.setTrendline(o.trendline);
        if(o.tx)
            this.setTx(o.tx);
        if(o.val)
            this.setVal(o.val);
        if(o.xVal)
        {
            this.setCat(new CCat());
            this.cat.setFromOtherObject(o.xVal);
        }
        if(o.yVal)
        {
            this.setVal(new CYVal());
            this.val.setFromOtherObject(o.yVal);
        }
    },

    getSeriesName: CAreaSeries.prototype.getSeriesName,
    getCatName: CAreaSeries.prototype.getCatName,
    getValByIndex: CAreaSeries.prototype.getValByIndex,
    getFormatCode: CAreaSeries.prototype.getFormatCode,

    setCat: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BarSeries_SetCat, this.cat, pr));
        this.cat = pr;
    },
    setDLbls: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BarSeries_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
    },
    addDPt: function(pr)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_BarSeries_SetDPt, this.dPt.length,  [pr], true));
        this.dPt.push(pr);
    },
    setErrBars: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BarSeries_SetErrBars, this.errBars, pr));
        this.errBars = pr;
    },
    setIdx: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_BarSeries_SetIdx, this.idx, pr));
        this.idx = pr;
    },
    setInvertIfNegative: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_BarSeries_SetInvertIfNegative, this.invertIfNegative, pr));
        this.invertIfNegative = pr;
    },
    setOrder: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_BarSeries_SetOrder, this.order, pr));
        this.order = pr;
    },
    setPictureOptions: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BarSeries_SetPictureOptions, this.pictureOptions, pr));
        this.pictureOptions = pr;
    },
    setShape: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BarSeries_SetShape, this.shape, pr));
        this.shape = pr;
    },
    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BarSeries_SetSpPr, this.spPr, pr));
        this.spPr = pr;
    },
    setTrendline: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BarSeries_SetTrendline, this.trendline, pr));
        this.trendline = pr;
    },
    setTx: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BarSeries_SetTx, this.tx, pr));
        this.tx = pr;
    },
    setVal: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BarSeries_SetVal, this.val, pr));
        this.val = pr;
        if(this.val && this.val.setParent)
        {
            this.val.setParent(this);
        }
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};

function CBubbleChart()
{
    this.axId          = [];
    this.bubble3D      = null;
    this.bubbleScale   = null;
    this.dLbls         = null;
    this.series = [];
    this.showNegBubbles = null;
    this.sizeRepresents = null;
    this.varyColors     = null;

    this.parent = null;


    this.m_oAxIdContentChanges = new AscCommon.CContentChanges();
    this.m_oSeriesContentChanges =  new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CBubbleChart.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},
    removeSeries: function(idx)
    {
        if(this.series[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonChart_RemoveSeries, idx, this.series.splice(idx, 1), false));
        }
    },
    getSeriesConstructor: function()
    {
        return new CBubbleSeries();
    },
    getObjectType: function()
    {
        return AscDFH.historyitem_type_BubbleChart;
    },

    getDefaultDataLabelsPosition: function()
    {
        return c_oAscChartDataLabelsPos.r;
    },


    createDuplicate: function()
    {
        var c = new CBubbleChart();
        c.setBubble3D(this.bubble3D);
        c.setBubbleScale(this.bubbleScale);
        if(this.dLbls)
        {
            c.setDLbls(this.dLbls.createDuplicate());
        }
        for(var i = 0; i < this.series.length; ++i)
        {
            c.addSer(this.series[i].createDuplicate());
        }
        c.setShowNegBubbles(this.showNegBubbles);
        c.setSizeRepresents(this.sizeRepresents);
        c.setVaryColors(this.varyColors);
        return c;
    },

    documentCreateFontMap: CBarChart.prototype.documentCreateFontMap,

    getAllRasterImages: CBarChart.prototype.getAllRasterImages,
    checkSpPrRasterImages: CBarChart.prototype.checkSpPrRasterImages,


    getAxisByTypes: CPlotArea.prototype.getAxisByTypes,

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_BubbleChart_AddAxId:{
                return this.m_oAxIdContentChanges;
            }
            case AscDFH.historyitem_BubbleChart_AddSerie:
            case AscDFH.historyitem_CommonChart_RemoveSeries:{
                return this.m_oSeriesContentChanges;
            }
        }
        return null;
    },

    addAxId: function(pr)
    {
        if(!pr)
            return;
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_BubbleChart_AddAxId, this.axId.length, [pr], true));
        this.axId.push(pr);
    },
    setBubble3D: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_BubbleChart_SetBubble3D, this.bubble3D, pr));
        this.bubble3D = pr;
    },
    setBubbleScale: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_BubbleChart_SetBubbleScale, this.bubbleScale, pr));
        this.bubbleScale = pr;
    },
    setDLbls: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BubbleChart_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateDataLabels();
        }
    },
    addSer: function(ser)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_BubbleChart_AddSerie, this.series.length, [ser], true));
        this.series.push(ser);
        ser.setParent(this);
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateType();
        }
    },
    setShowNegBubbles: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_BubbleChart_SetShowNegBubbles, this.showNegBubbles, pr));
        this.showNegBubbles = pr;
    },
    setSizeRepresents: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_BubbleChart_SetSizeRepresents, this.sizeRepresents, pr));
        this.sizeRepresents = pr;
    },

    setVaryColors: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_BubbleChart_SetVaryColors, this.varyColors, pr));
        this.varyColors = pr;
    },


    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};


function CBubbleSeries()
{
    this.bubble3D         = null;
    this.bubbleSize       = null;
    this.dLbls            = null;
    this.dPt              = [];
    this.errBars          = null;
    this.idx              = null;
    this.invertIfNegative = null;
    this.order            = null;
    this.spPr             = null;
    this.trendline        = null;
    this.tx               = null;
    this.xVal             = null;
    this.yVal             = null;

    this.parent = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CBubbleSeries.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_BubbleSeries;
    },

    cd: function()
    {},

    removeDPt: function(idx)
    {
        if(this.dPt[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonSeries_RemoveDPt, idx, this.dPt.splice(idx, 1), false));
        }
    },

    createDuplicate: function()
    {
        var c = new CBubbleSeries();
        c.setBubble3D(this.bubble3D);
        c.setBubbleSize(this.bubbleSize);
        if(this.dLbls)
        {
            c.setDLbls(this.dLbls.createDuplicate());
        }
        for(var i = 0; i < this.dPt.length; ++i)
        {
            c.addDPt(this.dPt[i].createDuplicate());
        }
        if(this.errBars)
        {
            c.setErrBars(this.errBars.createDuplicate());
        }
        c.setIdx(this.idx);
        c.setInvertIfNegative(this.invertIfNegative);
        c.setOrder(this.order);
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        if(this.trendline)
        {
            c.setTrendline(this.trendline.createDuplicate());
        }
        if(this.tx)
        {
            c.setTx(this.tx.createDuplicate());
        }
        if(this.xVal)
        {
            c.setXVal(this.xVal.createDuplicate());
        }
        if(this.yVal)
        {
            c.setYVal(this.yVal.createDuplicate());
        }
        return c;
    },


    documentCreateFontMap: CAreaSeries.prototype.documentCreateFontMap,
    getAllRasterImages: CAreaSeries.prototype.getAllRasterImages,
    checkSpPrRasterImages: CAreaSeries.prototype.checkSpPrRasterImages,

    getSeriesName: CAreaSeries.prototype.getSeriesName,
    getCatName: CAreaSeries.prototype.getCatName,
    getValByIndex: CAreaSeries.prototype.getValByIndex,
    getFormatCode: CAreaSeries.prototype.getFormatCode,


    setFromOtherSeries: function(o)
    {

    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },


    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
    },

    setBubble3D: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_BubbleSeries_SetBubble3D, this.bubble3D, pr));
        this.bubble3D = pr;
    },
    setBubbleSize: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BubbleSeries_SetBubbleSize, this.bubbleSize, pr));
        this.bubbleSize = pr;
    },
    setDLbls: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BubbleSeries_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
    },
    addDPt: function(pr)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_BubbleSeries_SetDPt, this.dPt.length, [pr], true));
        this.dPt.push(pr);
    },
    setErrBars: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BubbleSeries_SetErrBars, this.errBars, pr));
        this.errBars = pr;
    },
    setIdx: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_BubbleSeries_SetIdx, this.idx, pr));
        this.idx = pr;
    },
    setInvertIfNegative: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_BubbleSeries_SetInvertIfNegative, this.invertIfNegative, pr));
        this.invertIfNegative = pr;
    },
    setOrder: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_BubbleSeries_SetOrder, this.order, pr));
        this.order = pr;
    },
    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BubbleSeries_SetSpPr, this.spPr, pr));
        this.spPr = pr;
    },
    setTrendline: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BubbleSeries_SetTrendline, this.trendline, pr));
        this.trendline = pr;
    },
    setTx: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BubbleSeries_SetTx, this.tx, pr));
        this.tx = pr;
    },
    setXVal: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BubbleSeries_SetXVal, this.xVal, pr));
        this.xVal = pr;
    },
    setYVal: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_BubbleSeries_SetYVal, this.yVal, pr));
        this.yVal = pr;
        if(this.yVal && this.yVal.setParent)
        {
            this.yVal.setParent(this);
        }
    }
};



function CCat()
{
    this.multiLvlStrRef = null;
    this.numLit         = null;
    this.numRef         = null;
    this.strLit         = null;
    this.strRef         = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CCat.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },


    createDuplicate: function()
    {
        var c = new CCat();
        if(this.multiLvlStrRef)
        {
            c.setMultiLvlStrRef(this.multiLvlStrRef.createDuplicate());
        }
        if(this.numLit)
        {
            c.setNumLit(this.numLit.createDuplicate());
        }
        if(this.numRef)
        {
            c.setNumRef(this.numRef.createDuplicate());
        }
        if(this.strLit)
        {
            c.setStrLit(this.strLit.createDuplicate());
        }
        if(this.strRef)
        {
            c.setStrRef(this.strRef.createDuplicate());
        }
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_Cat;
    },

    setFromOtherObject: function(o)
    {
        if(o.multiLvlStrRef)
            this.setMultiLvlStrRef(o.multiLvlStrRef);
        if(o.numLit)
            this.setNumLit(o.numLit);
        if(o.numRef)
            this.setNumRef(o.numRef);
        if(o.strLit)
            this.setStrLit(o.strLit);
        if(o.strRef)
            this.setStrRef(o.strRef);
    },


    setMultiLvlStrRef: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Cat_SetMultiLvlStrRef, this.multiLvlStrRef, pr));
        this.multiLvlStrRef = pr;
    },
    setNumLit: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Cat_SetNumLit, this.multiLvlStrRef, pr));
        this.numLit = pr;
    },
    setNumRef: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Cat_SetNumRef, this.multiLvlStrRef, pr));
        this.numRef = pr;
    },
    setStrLit: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Cat_SetStrLit, this.multiLvlStrRef, pr));
        this.strLit = pr;
    },
    setStrRef: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Cat_SetStrRef, this.multiLvlStrRef, pr));
        this.strRef = pr;
            }
};


function CChartText()
{
    this.rich = null;
    this.strRef = null;
    this.chart = null;

    this.parent = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CChartText.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},


    createDuplicate: function()
    {
        var c = new CChartText();
        if(this.rich)
        {
            c.setRich(this.rich.createDuplicate());
            c.rich.setParent(c);
        }
        if(this.strRef)
        {
            c.setStrRef(this.strRef.createDuplicate());
        }
        return c;
    },

    getStyles: CDLbl.prototype.getStyles,

    Get_Theme: CDLbl.prototype.Get_Theme,
    Get_ColorMap: CDLbl.prototype.Get_ColorMap,

    setChart: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartFormatSetChart, this.chart, pr));
        this.chart = pr;
    },

    getDrawingDocument: function()
    {
        return this.parent && this.parent.getDrawingDocument && this.parent.getDrawingDocument();
    },


    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
    },

    merge: function(tx, noCopyTextBody)
    {
        if(tx.rich)
        {
            if(noCopyTextBody === true)
            {
                this.setRich(tx.rich);
            }
            else
            {
                this.setRich(tx.rich.createDuplicate());
            }
            this.rich.setParent(this);
        }
        if(tx.strRef)
        {
            this.strRef = tx.strRef;
        }
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_ChartText;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id())
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setRich: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartText_SetRich, this.rich, pr));
        this.rich = pr;
    },

    setStrRef: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartText_SetStrRef, this.strRef, pr));
        this.strRef = pr;
            }
};

function CDLbls()
{
    this.bDelete          = null;
    this.dLbl            = [];
    this.dLblPos         = null;
    this.leaderLines     = null;
    this.numFmt          = null;
    this.separator       = null;
    this.showBubbleSize  = null;
    this.showCatName     = null;
    this.showLeaderLines = null;
    this.showLegendKey   = null;
    this.showPercent     = null;
    this.showSerName     = null;
    this.showVal         = null;
    this.spPr            = null;
    this.txPr            = null;

    this.parent = null;

    this.m_oDLblContentChanges = new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CDLbls.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {
        this.Refresh_RecalcData2();
    },
    Refresh_RecalcData2: function()
    {
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent )
        {
            if(this.parent.parent.parent.parent.handleUpdateDataLabels){
                this.parent.parent.parent.parent.handleUpdateDataLabels();
            }
            else{
                if(this.parent.parent.parent.parent.parent && this.parent.parent.parent.parent.parent.handleUpdateDataLabels){
                    this.parent.parent.parent.parent.parent.handleUpdateDataLabels();
                }
            }
        }
    },


    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_DLbls_SetDLbl:{
                return this.m_oDLblContentChanges;
            }
        }
        return null;
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
    },


    createDuplicate: function()
    {
        var c = new CDLbls();
        c.setDelete(this.bDelete);
        for(var i = 0; i < this.dLbl.length; ++i)
        {
            c.addDLbl(this.dLbl[i].createDuplicate());
        }
        c.setDLblPos(this.dLblPos);
        if(this.leaderLines)
        {
            c.setLeaderLines(this.leaderLines.createDuplicate());
        }
        if(this.numFmt)
        {
            c.setNumFmt(this.numFmt.createDuplicate());
        }
        c.setSeparator(this.separator);
        c.setShowBubbleSize(this.showBubbleSize);
        c.setShowCatName(this.showCatName);
        c.setShowLeaderLines(this.showLeaderLines);
        c.setShowLegendKey(this.showLegendKey);
        c.setShowPercent(this.showPercent);
        c.setShowSerName(this.showSerName);
        c.setShowVal(this.showVal);
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        if(this.txPr)
        {
            c.setTxPr(this.txPr.createDuplicate());
        }
        return c;
    },


    documentCreateFontMap: function(allFonts)
    {
        AscFormat.checkTxBodyDefFonts(allFonts, this.txPr);
        for(var i = 0; i < this.dLbl.length; ++i)
        {
            this.dLbl[i] && AscFormat.checkTxBodyDefFonts(allFonts, this.dLbl[i].txPr);
            this.dLbl[i].tx && this.dLbl[i].tx.rich && this.dLbl[i].tx.rich.content && this.dLbl[i].tx.rich.content.Document_Get_AllFontNames(allFonts);
        }
    },
    getObjectType: function()
    {
        return AscDFH.historyitem_type_DLbls;
    },

    findDLblByIdx: function(idx)
    {
        for(var i = 0; i < this.dLbl.length; ++i)
        {
            if(this.dLbl[i].idx === idx)
                return this.dLbl[i];
        }
        return null;
    },

    getAllRasterImages: function(images)
    {
        this.spPr && this.spPr.checkBlipFillRasterImage(images);
        for(var i = 0; i < this.dLbl.length; ++i)
        {
            this.dLbl[i] && this.dLbl[i].spPr && this.dLbl[i].spPr.checkBlipFillRasterImage(images);
        }
    },

    checkSpPrRasterImages: function()
    {
        checkSpPrRasterImages(this.spPr);
        for(var i = 0; i < this.dLbl.length; ++i)
        {
            this.dLbl[i] && checkSpPrRasterImages(this.dLbl[i].spPr);
        }
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setDelete: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DLbls_SetDelete, this.bDelete, pr));
        this.bDelete = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateDataLabels)
        {
            this.parent.parent.parent.parent.handleUpdateDataLabels();
        }
    },
    addDLbl: function(pr)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_DLbls_SetDLbl, this.dLbl.length, [pr], true));
        this.dLbl.push(pr);
        if(pr)
        {
            pr.parent = this;
        }
    },
    removeDLbl: function(nIndex)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_DLbls_SetDLbl, nIndex, this.dLbl.splice(nIndex, 1), false));
    },
    removeAllDLbls: function(){
        for(var i = this.dLbl.length - 1; i > -1; --i){
            this.removeDLbl(i);
        }
    },
    setDLblPos: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_DLbls_SetDLblPos, this.dLblPos, pr));
        this.dLblPos = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateDataLabels)
        {
            this.parent.parent.parent.parent.handleUpdateDataLabels();
        }
    },
    setLeaderLines: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DLbls_SetLeaderLines, this.leaderLines, pr));
        this.leaderLines = pr;
    },
    setNumFmt: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DLbls_SetNumFmt, this.numFmt, pr));
        this.numFmt = pr;
    },
    setSeparator: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_DLbls_SetSeparator, this.separator, pr));
        this.separator = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateDataLabels)
        {
            this.parent.parent.parent.parent.handleUpdateDataLabels();
        }
    },
    setShowBubbleSize: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DLbls_SetShowBubbleSize, this.showBubbleSize, pr));
        this.showBubbleSize = pr;
    },
    setShowCatName: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DLbls_SetShowCatName, this.showCatName, pr));
        this.showCatName = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateDataLabels)
        {
            this.parent.parent.parent.parent.handleUpdateDataLabels();
        }
    },
    setShowLeaderLines: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DLbls_SetShowLeaderLines, this.showLeaderLines, pr));
        this.showLeaderLines = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateDataLabels)
        {
            this.parent.parent.parent.parent.handleUpdateDataLabels();
        }
    },
    setShowLegendKey: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DLbls_SetShowLegendKey, this.showLegendKey, pr));
        this.showLegendKey = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateDataLabels)
        {
            this.parent.parent.parent.parent.handleUpdateDataLabels();
        }
    },
    setShowPercent: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DLbls_SetShowPercent, this.showPercent, pr));
        this.showPercent = pr;
    },
    setShowSerName: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DLbls_SetShowSerName, this.showSerName, pr));
        this.showSerName = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateDataLabels)
        {
            this.parent.parent.parent.parent.handleUpdateDataLabels();
        }
    },
    setShowVal: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DLbls_SetShowVal, this.showVal, pr));
        this.showVal = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateDataLabels)
        {
            this.parent.parent.parent.parent.handleUpdateDataLabels();
        }
    },
    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DLbls_SetSpPr, this.spPr, pr));
        this.spPr = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateDataLabels)
        {
            this.parent.parent.parent.parent.handleUpdateDataLabels();
        }
    },
    setTxPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DLbls_SetTxPr, this.txPr, pr));
        this.txPr = pr;
        if(pr)
        {
            pr.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateDataLabels)
        {
            this.parent.parent.parent.parent.handleUpdateDataLabels();
        }
            }
};

function CDPt()
{
    this.bubble3D         = null;
    this.explosion        = null;
    this.idx              = null;
    this.invertIfNegative = null;
    this.marker           = null;
    this.pictureOptions   = null;
    this.spPr             = null;


    this.recalcInfo =
    {
        recalcLbl: true
    };
    this.compiledLbl = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CDPt.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_DPt;
    },

    createDuplicate: function()
    {
        var c = new CDPt();
        c.setBubble3D(this.bubble3D);
        c.setExplosion(this.explosion);
        c.setIdx(this.idx);
        c.setInvertIfNegative(this.invertIfNegative);
        if(this.marker)
        {
            c.setMarker(this.marker.createDuplicate());
        }
        if(this.pictureOptions)
        {
            c.setPictureOptions(this.pictureOptions.createDuplicate());
        }
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        return c;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setBubble3D: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DPt_SetBubble3D, this.bubble3D, pr));
        this.bubble3D = pr;
    },

    setExplosion: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_DPt_SetExplosion, this.explosion, pr));
        this.explosion = pr;
    },

    setIdx: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_DPt_SetIdx, this.idx, pr));
        this.idx = pr;
    },

    setInvertIfNegative: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DPt_SetInvertIfNegative, this.invertIfNegative, pr));
        this.invertIfNegative = pr;
    },

    setMarker: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DPt_SetMarker, this.marker, pr));
        this.marker = pr;
    },

    setPictureOptions: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DPt_SetPictureOptions, this.pictureOptions, pr));
        this.pictureOptions = pr;
    },

    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DPt_SetSpPr, this.spPr, pr));
        this.spPr = pr;
            }
};


function CDTable()
{
    this.showHorzBorder = null;
    this.showKeys       = null;
    this.showOutline    = null;
    this.showVertBorder = null;
    this.spPr = null;
    this.txPr = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}


CDTable.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_DTable;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    createDuplicate: function()
    {
        var c = new CDTable();
        c.setShowHorzBorder(this.showHorzBorder);
        c.setShowKeys(this.showKeys);
        c.setShowOutline(this.showOutline);
        c.setShowVertBorder(this.showVertBorder);
        if(this.spPr)
            c.setSpPr(this.spPr.createDuplicate());
        if(this.txPr)
            c.setTxPr(this.txPr.createDuplicate());
        return c;
    },

    setShowHorzBorder: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DTable_SetShowHorzBorder, this.showHorzBorder, pr));
        this.showHorzBorder = pr;
    },
    setShowKeys: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DTable_SetShowKeys, this.showHorzBorder, pr));
        this.showKeys = pr;
    },
    setShowOutline: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DTable_SetShowOutline, this.showHorzBorder, pr));
        this.showOutline = pr;
    },
    setShowVertBorder: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DTable_SetShowVertBorder, this.showHorzBorder, pr));
        this.showVertBorder = pr;
    },
    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DTable_SetSpPr, this.showHorzBorder, pr));
        this.spPr = pr;
    },
    setTxPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DTable_SetTxPr, this.showHorzBorder, pr));
        this.txPr = pr;
            }
};

var UNIT_MULTIPLIERS = [];
UNIT_MULTIPLIERS[c_oAscValAxUnits.BILLIONS]           = 1.0/1000000000.0;
UNIT_MULTIPLIERS[c_oAscValAxUnits.HUNDRED_MILLIONS]   = 1.0/100000000.0;
UNIT_MULTIPLIERS[c_oAscValAxUnits.HUNDREDS]           = 1.0/100.0;
UNIT_MULTIPLIERS[c_oAscValAxUnits.HUNDRED_THOUSANDS]  = 1.0/100000.0;
UNIT_MULTIPLIERS[c_oAscValAxUnits.MILLIONS]           = 1.0/1000000.0;
UNIT_MULTIPLIERS[c_oAscValAxUnits.TEN_MILLIONS]       = 1.0/10000000.0;
UNIT_MULTIPLIERS[c_oAscValAxUnits.TEN_THOUSANDS]      = 1.0/10000.0;
UNIT_MULTIPLIERS[c_oAscValAxUnits.TRILLIONS]          = 1.0/1000000000000.0;
UNIT_MULTIPLIERS[c_oAscValAxUnits.THOUSANDS]          = 1.0/1000.0;

function CDispUnits()
{
    this.builtInUnit  = null;
    this.custUnit     = null;
    this.dispUnitsLbl = null;
    this.parent       = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}
CDispUnits.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var c = new CDispUnits();
        c.setBuiltInUnit(this.builtInUnit);
        c.setCustUnit(this.custUnit);
        if(this.dispUnitsLbl)
        {
            c.setDispUnitsLbl(this.dispUnitsLbl.createDuplicate());
        }
        return c;
    },


    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_DispUnitsSetParent, this.parent, pr));
        this.parent = pr;
    },

    getMultiplier: function()
    {
        if(AscFormat.isRealNumber(this.builtInUnit))
        {
            if(AscFormat.isRealNumber(UNIT_MULTIPLIERS[this.builtInUnit]))
                return UNIT_MULTIPLIERS[this.builtInUnit];
        }
        else if(AscFormat.isRealNumber(this.custUnit))
            return this.custUnit;
        return 1;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_DispUnits;
    },

    setBuiltInUnit: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_DispUnitsSetBuiltInUnit, this.builtInUnit, pr));
        this.builtInUnit = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateInternalChart)
        {
            this.parent.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setCustUnit: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DispUnitsSetCustUnit, this.custUnit, pr));
        this.custUnit = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateInternalChart)
        {
            this.parent.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setDispUnitsLbl: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DispUnitsSetDispUnitsLbl, this.dispUnitsLbl, pr));
        this.dispUnitsLbl = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateInternalChart)
        {
            this.parent.parent.parent.parent.handleUpdateInternalChart();
        }
    },


    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
            }
};

function CDoughnutChart()
{
    this.dLbls = null;
    this.firstSliceAng = null;
    this.holeSize = null;
    this.series = [];
    this.varyColors  = null;

    this.parent = null;


    this.m_oSeriesContentChanges =  new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CDoughnutChart.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_DoughnutChart_AddSer:
            case AscDFH.historyitem_CommonChart_RemoveSeries:{
                return this.m_oSeriesContentChanges;
            }
        }
        return null;
    },


    Refresh_RecalcData: function(data)
    {
        if(!isRealObject(data))
            return;

        switch (data.Type)
        {
            case AscDFH.historyitem_CommonChartFormat_SetParent:
            {
                break;
            }
            case AscDFH.historyitem_CommonChart_RemoveSeries:
            {
                break;
            }
            case AscDFH.historyitem_DoughnutChart_SetDLbls :
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateDataLabels();
                }
                break;
            }
            case AscDFH.historyitem_DoughnutChart_SetFirstSliceAng :
            {
                break;
            }
            case AscDFH.historyitem_DoughnutChart_SetHoleSize :
            {
                break;
            }
            case AscDFH.historyitem_DoughnutChart_AddSer:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateType();
                }
                break;
            }
            case AscDFH.historyitem_DoughnutChart_SetVaryColor :
            {
                break;
            }
        }
    },
    removeSeries: function(idx)
    {
        if(this.series[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonChart_RemoveSeries, idx, this.series.splice(idx, 1), true));
        }
    },

    getDefaultDataLabelsPosition: function()
    {
        return c_oAscChartDataLabelsPos.ctr;
    },

    getSeriesConstructor: function()
    {
        return new CPieSeries();
    },
    createDuplicate: function()
    {
        var c = new CDoughnutChart();
        if(this.dLbls)
        {
            c.setDLbls(this.dLbls.createDuplicate());
        }
        c.setFirstSliceAng(this.firstSliceAng);
        c.setHoleSize(this.holeSize);
        for(var i = 0; i < this.series.length; ++i)
        {
            c.addSer(this.series[i].createDuplicate());
        }
        c.setVaryColors(this.varyColors);
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_DoughnutChart;
    },


    documentCreateFontMap: CBarChart.prototype.documentCreateFontMap,

    getAllRasterImages: CBarChart.prototype.getAllRasterImages,
    checkSpPrRasterImages: CBarChart.prototype.checkSpPrRasterImages,

    removeDataLabels: CBarChart.prototype.removeDataLabels,

    setFromOtherChart: function(c)
    {
        if(c.dLbls)
            this.setDLbls(c.dLbls);
        if(AscFormat.isRealNumber(c.firstSliceAng))
            this.setFirstSliceAng(c.firstSliceAng);
        if(AscFormat.isRealNumber(c.holeSize))
            this.setHoleSize(c.holeSize);
        if(Array.isArray(c.series))
        {
            var i;
            for(i = 0; i < c.series.length; ++i)
            {
                var ser = new CPieSeries();
                ser.setFromOtherSeries(c.series[i]);
                this.addSer(ser);
            }
        }
        if(AscFormat.isRealBool(c.varyColors))
            this.setVaryColors(c.varyColors);
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setDLbls: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_DoughnutChart_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateDataLabels();
        }
    },
    setFirstSliceAng: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_DoughnutChart_SetFirstSliceAng, this.firstSliceAng, pr));
        this.firstSliceAng = pr;
    },
    setHoleSize: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_DoughnutChart_SetHoleSize, this.holeSize, pr));
        this.holeSize = pr;
    },

    addSer: function(ser)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_DoughnutChart_AddSer, this.series.length, [ser], true));
        this.series.push(ser);
        ser.setParent(this);
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateType();
        }
    },

    setVaryColors: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_DoughnutChart_SetVaryColor, this.varyColors, pr));
        this.varyColors = pr;
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};

function CErrBars()
{
    this.errBarType = null;
    this.errDir     = null;
    this.errValType = null;
    this.minus      = null;
    this.noEndCap   = null;
    this.plus       = null;
    this.spPr       = null;
    this.val        = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CErrBars.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var c = new CErrBars();
        c.setErrBarType(this.errBarType);
        c.setErrDir(this.errDir);
        c.setErrValType(this.errValType);
        if(this.minus)
        {
            c.setMinus(this.minus.createDuplicate());
        }
        c.setNoEndCap(this.noEndCap);
        if(this.plus)
        {
            c.setPlus(this.plus.createDuplicate());
        }
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        c.setVal(this.val);
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_ErrBars;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setErrBarType: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_ErrBars_SetErrBarType, this.errBarType, pr));
        this.errBarType = pr;
    },
    setErrDir: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_ErrBars_SetErrDir, this.errDir, pr));
        this.errDir = pr;
    },
    setErrValType: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_ErrBars_SetErrValType, this.errDir, pr));
        this.errValType = pr;
    },
    setMinus: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ErrBars_SetMinus, this.minus, pr));
        this.minus = pr;
    },
    setNoEndCap: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_ErrBars_SetNoEndCap, this.noEndCap, pr));
        this.noEndCap = pr;
    },
    setPlus: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ErrBars_SetPlus, this.plus, pr));
        this.plus = pr;
    },
    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ErrBars_SetSpPr, this.spPr, pr));
        this.spPr = pr;
    },
    setVal: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_ErrBars_SetVal, this.val, pr));
        this.val = pr;
            }
};

function CLayout()
{
    this.h = null;
    this.hMode = null;
    this.layoutTarget = null;
    this.w  = null;
    this.wMode = null;
    this.x = null;
    this.xMode = null;
    this.y = null;
    this.yMode = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CLayout.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {},

    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    },

    createDuplicate: function()
    {
        var c = new CLayout();
        c.setH(this.h);
        c.setHMode(this.hMode);
        c.setLayoutTarget(this.layoutTarget);
        c.setW(this.w);
        c.setWMode(this.wMode);
        c.setX(this.x);
        c.setXMode(this.xMode);
        c.setY(this.y);
        c.setYMode(this.yMode);
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_Layout;
    },

    setH: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Layout_SetH, this.h, pr));
        this.h = pr;
    },

    setHMode: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_Layout_SetHMode, this.hMode, pr));
        this.hMode = pr;
    },

    setLayoutTarget: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_Layout_SetLayoutTarget, this.layoutTarget, pr));
        this.layoutTarget = pr;
    },

    setW: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Layout_SetW, this.w, pr));
        this.w = pr;
    },

    setWMode: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_Layout_SetWMode, this.wMode, pr));
        this.wMode = pr;
    },

    setX: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Layout_SetX, this.x, pr));
        this.x = pr;
    },

    setXMode: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_Layout_SetXMode, this.xMode, pr));
        this.xMode = pr;
    },

    setY: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Layout_SetY, this.y, pr));
        this.y = pr;
    },

    setYMode: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_Layout_SetYMode, this.yMode, pr));
        this.yMode = pr;
            }
};

function CLegend()
{
    this.layout = null;
    this.legendEntryes = [];
    this.legendPos = null;
    this.overlay = false;
    this.spPr = null;
    this.txPr = null;

    this.x = null;
    this.y = null;
    this.extX = null;
    this.extY = null;
    this.calcEntryes = [];

    this.parent = null;

    this.transform = new CMatrix();
    this.invertTransform = new CMatrix();

    this.localTransform = new CMatrix();


    this.m_oLegendEntryesContentChanges = new AscCommon.CContentChanges()

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}
CLegend.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {
        this.Refresh_RecalcData2();
    },


    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_Legend_AddLegendEntry:{
                return this.m_oLegendEntryesContentChanges;
            }
        }
        return null;
    },

    findCalcEntryByIdx: function(idx)
    {
        for(var i = 0; i < this.calcEntryes.length; ++i){
            if(this.calcEntryes[i] && this.calcEntryes[i].idx === idx){
                return this.calcEntryes[i];
            }
        }
        return null;
    },

    createDuplicate: function()
    {
        var c = new CLegend();
        if(this.layout)
        {
            c.setLayout(this.layout.createDuplicate());
        }
        for(var i = 0; i < this.legendEntryes.length; ++i)
        {
            c.addLegendEntry(this.legendEntryes[i].createDuplicate());
        }
        c.setLegendPos(this.legendPos);
        c.setOverlay(this.overlay);
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        if(this.txPr)
        {
            c.setTxPr(this.txPr.createDuplicate());
        }
        return c;
    },

    getCalcEntryByIdx: function(idx, drawingDocument)
    {
        for(var i = 0; i < this.calcEntryes.length; ++i)
        {
            if(this.calcEntryes[i] && this.calcEntryes[i].idx == idx)
            {
                return this.calcEntryes[i];
            }
        }
        return AscFormat.ExecuteNoHistory(function(){

            var calcEntry = new AscFormat.CalcLegendEntry(this, this.chart, idx);
            calcEntry.txBody = AscFormat.CreateTextBodyFromString("" + idx, drawingDocument, calcEntry);
            calcEntry.txBody.getRectWidth(2000);
            return calcEntry;
        }, this, []);
    },

    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    },
    
    updateLegendPos: function() {
        if (this.overlay) {
            if (c_oAscChartLegendShowSettings.left === this.legendPos) {
                this.legendPos = c_oAscChartLegendShowSettings.leftOverlay;
            } else if (c_oAscChartLegendShowSettings.right === this.legendPos) {
                this.legendPos = c_oAscChartLegendShowSettings.rightOverlay;
            }
        }
    },


    recalculatePen:CShape.prototype.recalculatePen,
    recalculateBrush:CShape.prototype.recalculateBrush,
    getCompiledStyle: function()
    {
        return null;
    },

    getParentObjects: function()
    {
        if(this.chart)
        {
            return this.chart.getParentObjects();
        }
        else
        {
            return {};
        }
    },

    getCompiledLine: CShape.prototype.getCompiledLine,
    getCompiledFill: CShape.prototype.getCompiledFill,
    getCompiledTransparent: CShape.prototype.getCompiledTransparent,
    check_bounds: CShape.prototype.check_bounds,
    getHierarchy: function(){return this.chart ? this.chart.getHierarchy() : []},
    isEmptyPlaceholder: function()
    {
        return false;
    },
    isPlaceholder: function()
    {
        return false;
    },
    draw: function(g)
    {
        g.bDrawSmart = true;
        CShape.prototype.draw.call(this, g);
        for(var i = 0; i < this.calcEntryes.length; ++i)
        {
            this.calcEntryes[i].draw(g);
        }
        g.bDrawSmart = false;
    },

    hit: function(x, y)
    {
        var t_x = this.invertTransform.TransformPointX(x, y);
        var t_y = this.invertTransform.TransformPointY(x, y);
        return t_x >= 0 && t_y >= 0 && t_x <= this.extX && t_y <=this.extY;
    },

    setPosition: function(x, y)
    {
        this.x = x;
        this.y = y;
        this.localTransform.Reset();
        global_MatrixTransformer.TranslateAppend(this.localTransform, this.x, this.y);
        //if(this.chart)
        //    global_MatrixTransformer.MultiplyAppend(this.localTransform, this.chart.localTransform);
        this.transform = this.localTransform.CreateDublicate();
        this.invertTransform = global_MatrixTransformer.Invert(this.transform);
        var entry;
        for(var i = 0; i < this.calcEntryes.length; ++i)
        {
            entry = this.calcEntryes[i];
            entry.localTransformText.Reset();
            global_MatrixTransformer.TranslateAppend(entry.localTransformText, entry.localX, entry.localY);

            global_MatrixTransformer.MultiplyAppend(entry.localTransformText, this.localTransform);
            entry.transformText = entry.localTransformText.CreateDublicate();
            entry.invertTransformText = global_MatrixTransformer.Invert(entry.transformText);
            if(entry.calcMarkerUnion.marker)
            {
                entry.calcMarkerUnion.marker.localTransform.Reset();
                global_MatrixTransformer.TranslateAppend(entry.calcMarkerUnion.marker.localTransform, entry.calcMarkerUnion.marker.localX, entry.calcMarkerUnion.marker.localY);

                global_MatrixTransformer.MultiplyAppend(entry.calcMarkerUnion.marker.localTransform, this.localTransform);
                entry.calcMarkerUnion.marker.transform = entry.calcMarkerUnion.marker.localTransform.CreateDublicate();
                entry.calcMarkerUnion.marker.invertTransform = global_MatrixTransformer.Invert(entry.calcMarkerUnion.marker.transform);
            }
            if(entry.calcMarkerUnion.lineMarker)
            {
                entry.calcMarkerUnion.lineMarker.localTransform.Reset();
                global_MatrixTransformer.TranslateAppend(entry.calcMarkerUnion.lineMarker.localTransform, entry.calcMarkerUnion.lineMarker.localX, entry.calcMarkerUnion.lineMarker.localY);

                global_MatrixTransformer.MultiplyAppend(entry.calcMarkerUnion.lineMarker.localTransform, this.localTransform);
                entry.calcMarkerUnion.lineMarker.transform = entry.calcMarkerUnion.lineMarker.localTransform.CreateDublicate();
                entry.calcMarkerUnion.lineMarker.invertTransform = global_MatrixTransformer.Invert(entry.calcMarkerUnion.lineMarker.transform);
            }
        }
    },


    updatePosition: function(x, y)
    {
        this.posX = x;
        this.posY = y;
        this.transform = this.localTransform.CreateDublicate();
        global_MatrixTransformer.TranslateAppend(this.transform, x, y);
        this.invertTransform = global_MatrixTransformer.Invert(this.transform);
        var entry;
        for(var i = 0; i < this.calcEntryes.length; ++i)
        {
            entry = this.calcEntryes[i];
            entry.transformText = entry.localTransformText.CreateDublicate();
            global_MatrixTransformer.TranslateAppend(entry.transformText, x, y);
            entry.invertTransformText = global_MatrixTransformer.Invert(entry.transformText);

            if(entry.calcMarkerUnion.marker)
            {
                entry.calcMarkerUnion.marker.transform = entry.calcMarkerUnion.marker.localTransform.CreateDublicate();
                global_MatrixTransformer.TranslateAppend(entry.calcMarkerUnion.marker.transform, x, y);

                entry.calcMarkerUnion.marker.invertTransform = global_MatrixTransformer.Invert(entry.calcMarkerUnion.marker.transform);
            }

            if(entry.calcMarkerUnion.lineMarker)
            {
                entry.calcMarkerUnion.lineMarker.transform = entry.calcMarkerUnion.lineMarker.localTransform.CreateDublicate();
                global_MatrixTransformer.TranslateAppend(entry.calcMarkerUnion.lineMarker.transform, x, y);

                entry.calcMarkerUnion.lineMarker.invertTransform = global_MatrixTransformer.Invert(entry.calcMarkerUnion.lineMarker.transform);

            }
        }
    },


    checkShapeChildTransform: function(t)
    {
        this.transform = this.localTransform.CreateDublicate();
        global_MatrixTransformer.TranslateAppend(this.transform, this.posX, this.posY);
        global_MatrixTransformer.MultiplyAppend(this.transform, t);
        this.invertTransform = global_MatrixTransformer.Invert(this.transform);
        var entry;
        for(var i = 0; i < this.calcEntryes.length; ++i)
        {
            entry = this.calcEntryes[i];
            entry.transformText = entry.localTransformText.CreateDublicate();
            global_MatrixTransformer.TranslateAppend(entry.transformText, this.posX, this.posY);


            global_MatrixTransformer.MultiplyAppend(entry.transformText, t);

            entry.invertTransformText = global_MatrixTransformer.Invert(entry.transformText);


            if(entry.calcMarkerUnion.marker)
            {
                entry.calcMarkerUnion.marker.transform = entry.calcMarkerUnion.marker.localTransform.CreateDublicate();
                global_MatrixTransformer.TranslateAppend(entry.calcMarkerUnion.marker.transform, this.posX, this.posY);

                global_MatrixTransformer.MultiplyAppend(entry.calcMarkerUnion.marker.transform, t);

                entry.calcMarkerUnion.marker.invertTransform = global_MatrixTransformer.Invert(entry.calcMarkerUnion.marker.transform);
            }

            if(entry.calcMarkerUnion.lineMarker)
            {
                entry.calcMarkerUnion.lineMarker.transform = entry.calcMarkerUnion.lineMarker.localTransform.CreateDublicate();
                global_MatrixTransformer.TranslateAppend(entry.calcMarkerUnion.lineMarker.transform, this.posX, this.posY);
                global_MatrixTransformer.MultiplyAppend(entry.calcMarkerUnion.lineMarker.transform, t);

                entry.calcMarkerUnion.lineMarker.invertTransform = global_MatrixTransformer.Invert(entry.calcMarkerUnion.lineMarker.transform);
            }
        }
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_Legend;
    },

    setLayout: function(layout)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Legend_SetLayout, this.layout, layout));
        this.layout = layout;
    },
    addLegendEntry: function(legendEntry)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_Legend_AddLegendEntry, this.legendEntryes.length, [legendEntry], true));
        this.legendEntryes.push(legendEntry);
        legendEntry.parent = this;
    },

    setLegendPos: function(legendPos)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_Legend_SetLegendPos, this.legendPos, legendPos));
        this.legendPos = legendPos;
        if(this.parent && this.parent.parent)
        {
            this.parent.parent.handleUpdateInternalChart();
        }
    },
    setOverlay: function(overlay)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_Legend_SetOverlay, this.overlay, overlay));
        this.overlay = overlay;
        if(this.parent && this.parent.parent)
        {
            this.parent.parent.handleUpdateInternalChart();
        }
    },
    setSpPr: function(spPr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Legend_SetSpPr, this.spPr, spPr));
        this.spPr = spPr;
    },
    setTxPr: function(txPr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Legend_SetTxPr, this.txPr, txPr));
        this.txPr = txPr;
        if(txPr)
        {
            txPr.setParent(this);
        }
    },

    Refresh_RecalcData2: function()
    {
        if(this.parent && this.parent.parent)
        {
            this.parent.parent.handleUpdateInternalChart();
        }
    },

    findLegendEntryByIndex: function(idx)
    {
        for(var i = 0; i < this.legendEntryes.length; ++i)
        {
            if(this.legendEntryes[i].idx === idx)
                return this.legendEntryes[i];
        }
        return null;
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};

function CLegendEntry()
{
    this.bDelete = null;
    this.idx = null;
    this.txPr  = null;


    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CLegendEntry.prototype =
{
    getObjectType: function()
    {
        return AscDFH.historyitem_type_LegendEntry;
    },

    createDuplicate: function()
    {
        var c = new CLegendEntry();
        c.setDelete(this.bDelete);
        c.setIdx(this.idx);
        if(this.txPr)
        {
            c.setTxPr(this.txPr.createDuplicate());
        }
        return c;
    },

    Get_Id: function()
    {
        return this.Id;
    },
    Refresh_RecalcData: function()
    {
        this.Refresh_RecalcData2();
    },

    Write_ToBinary2: function (w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function (r)
    {
        this.Id = r.GetString2();
    },

    setDelete: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_LegendEntry_SetDelete, this.bDelete, pr));
        this.bDelete = pr;
        this.Refresh_RecalcData2();
    },
    setIdx: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_LegendEntry_SetIdx, this.idx, pr));
        this.idx = pr;
    },

    Refresh_RecalcData2: function()
    {
        if(this.parent && this.parent.Refresh_RecalcData2)
        {
            this.parent.Refresh_RecalcData2();
        }
    },

    setTxPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_LegendEntry_SetTxPr, this.txPr, pr));
        this.txPr = pr;
        if(this.txPr)
        {
            this.txPr.setParent(this);
        }
            }
};
    
function CLineChart()
{
    this.axId       = [];
    this.dLbls      = null;
    this.dropLines  = null;
    this.grouping   = null;
    this.hiLowLines = null;
    this.marker     = null;
    this.series      = [];
    this.smooth     = null;
    this.upDownBars = null;
    this.varyColors = null;

    this.parent = null;




    this.m_oAxIdContentChanges = new AscCommon.CContentChanges();
    this.m_oSeriesContentChanges =  new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CLineChart.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_LineChart_AddAxId:{
                return this.m_oAxIdContentChanges;
            }
            case AscDFH.historyitem_LineChart_AddSer:
            case AscDFH.historyitem_CommonChart_RemoveSeries:{
                return this.m_oSeriesContentChanges;
            }
        }
        return null;
    },

    Refresh_RecalcData: function(data)
    {
        if(!isRealObject(data))
            return;
        switch (data.Type)
        {
            case AscDFH.historyitem_CommonChartFormat_SetParent:
            {
                break;
            }
            case AscDFH.historyitem_CommonChart_RemoveSeries:
            {
                break;
            }
            case AscDFH.historyitem_LineChart_AddAxId:
            {
                break
            }
            case AscDFH.historyitem_LineChart_SetDLbls:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateDataLabels();
                }
                break
            }
            case AscDFH.historyitem_LineChart_SetDropLines:
            {
                break
            }
            case AscDFH.historyitem_LineChart_SetGrouping:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateInternalChart();
                }
                break
            }
            case AscDFH.historyitem_LineChart_SetHiLowLines:
            {
                break
            }
            case AscDFH.historyitem_LineChart_SetMarker:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateType();
                }
                break
            }
            case AscDFH.historyitem_LineChart_AddSer:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateType();
                }
                break
            }
            case AscDFH.historyitem_LineChart_SetSmooth:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateType();
                }
                break
            }
            case AscDFH.historyitem_LineChart_SetUpDownBars:
            {
                break
            }
            case AscDFH.historyitem_LineChart_SetVaryColors:
            {
                break
            }
        }
    },

    removeSeries: function(idx)
    {
        if(this.series[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonChart_RemoveSeries, idx, this.series.splice(idx, 1), false));
        }
    },

    documentCreateFontMap: CBarChart.prototype.documentCreateFontMap,

    getSeriesConstructor: function()
    {
        return new CLineSeries();
    },

    getDefaultDataLabelsPosition: function()
    {
        return c_oAscChartDataLabelsPos.r;
    },

    getObjectType: function()
    {
        return  AscDFH.historyitem_type_LineChart;
    },

    createDuplicate: function()
    {
        var c = new CLineChart();
        if(this.dLbls)
        {
            c.setDLbls(this.dLbls.createDuplicate());
        }
        if(this.dropLines)
        {
            c.setDropLines(this.dropLines.createDuplicate());
        }
        c.setGrouping(this.grouping);
        if(this.hiLowLines)
        {
            c.setHiLowLines(this.hiLowLines.createDuplicate());
        }
        c.setMarker(this.marker);
        for(var i = 0; i < this.series.length; ++i)
        {
            c.addSer(this.series[i].createDuplicate());
        }
        c.setSmooth(this.smooth);
        if(this.upDownBars)
        {
            c.setUpDownBars(this.upDownBars.createDuplicate());
        }
        c.setVaryColors(this.varyColors);
        return c;
    },


    getAllRasterImages: function(images)
    {
        CBarChart.prototype.getAllRasterImages.call(this, images);
        if(this.upDownBars)
        {
            this.upDownBars.upBars && this.upDownBars.upBars.checkBlipFillRasterImage(images);
            this.upDownBars.downBars && this.upDownBars.downBars.checkBlipFillRasterImage(images);
        }
    },

    checkSpPrRasterImages: function(images)
    {
        CBarChart.prototype.checkSpPrRasterImages.call(this, images);
        if(this.upDownBars)
        {
            checkSpPrRasterImages(this.upDownBars.upBars);
            checkSpPrRasterImages(this.upDownBars.downBars);
        }
    },

    removeDataLabels: CBarChart.prototype.removeDataLabels,

    getAxisByTypes: CPlotArea.prototype.getAxisByTypes,

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },


    setFromOtherChart: function(c)
    {
        var i;
        //if(Array.isArray(c.axId))
        //{
        //    for(i = 0; i < c.axId.length; ++i)
        //    {
        //        this.addAxId(c.axId[i]);
        //    }
        //}
        if(c.dLbls)
            this.setDLbls(c.dLbls);

        if(c.dropLines)
            this.setDropLines(c.dropLines);

        if(AscFormat.isRealNumber(c.grouping))
            this.setGrouping(c.grouping);
        if(c.hiLowLines)
            this.setHiLowLines(c.hiLowLines);

        if(c.marker)
            this.setMarker(c.marker);

        if(Array.isArray(c.series))
        {
            for(i = 0; i < c.series.length; ++i)
            {
                var ser = new CLineSeries();
                ser.setFromOtherSeries(c.series[i]);
                this.addSer(ser);
            }
        }
        if(AscFormat.isRealBool(c.smooth))
            this.setSmooth(c.smooth);
        if(AscFormat.isRealBool(c.varyColors))
            this.setVaryColors(c.varyColors);
    },


    addAxId: function(pr)
    {
        if(!pr)
            return;
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_LineChart_AddAxId, this.axId.length, [pr], true));
        this.axId.push(pr);
    },

    setDLbls: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_LineChart_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateDataLabels();
        }
    },

    setDropLines: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_LineChart_SetDropLines, this.dropLines, pr));
        this.dropLines = pr;
    },
    setGrouping: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_LineChart_SetGrouping, this.grouping, pr));
        this.grouping = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setHiLowLines: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_LineChart_SetHiLowLines, this.hiLowLines, pr));
        this.hiLowLines = pr;
    },
    setMarker: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_LineChart_SetMarker, this.marker, pr));
        this.marker = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateType();
        }
    },
    addSer: function(ser)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_LineChart_AddSer, this.series.length, [ser], true));
        this.series.push(ser);
        ser.setParent(this);
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateType();
        }
    },
    setSmooth: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_LineChart_SetSmooth, this.smooth, pr));
        this.smooth = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateType();
        }
    },
    setUpDownBars: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_LineChart_SetUpDownBars, this.upDownBars, pr));
        this.upDownBars = pr;
        if(pr && pr.setParent)
        {
            pr.setParent(this);
        }
    },
    setVaryColors: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_LineChart_SetVaryColors, this.varyColors, pr));
        this.varyColors = pr;
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};

function CLineSeries()
{
    this.cat           = null;
    this.dLbls         = null;
    this.dPt           = [];
    this.errBars       = null;
    this.idx           = null;
    this.marker        = null;
    this.order         = null;
    this.smooth        = null;
    this.spPr          = null;
    this.trendline     = null;
    this.tx            = null;
    this.val           = null;

    this.parent = null;

    this.m_oDPtContentChanges = new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CLineSeries.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_LineSeries_SetDPt:
            case AscDFH.historyitem_CommonSeries_RemoveDPt:{
                return this.m_oDPtContentChanges;
            }
        }
        return null;
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
    },


    removeDPt: function(idx)
    {
        if(this.dPt[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonSeries_RemoveDPt, idx, this.dPt.splice(idx, 1), false));
            this.dPt.splice(idx, 1);
        }
    },

    Refresh_RecalcData: function()
    {},
    createDuplicate: function()
    {
        var c = new CLineSeries();
        if(this.cat)
        {
            c.setCat(this.cat.createDuplicate());
        }
        if(this.dLbls)
        {
            c.setDLbls(this.dLbls.createDuplicate());
        }
        for(var i = 0; i < this.dPt.length; ++i)
        {
            c.addDPt(this.dPt[i].createDuplicate());
        }
        if(this.errBars)
        {
            c.setErrBars(this.errBars.createDuplicate());
        }
        c.setIdx(this.idx);
        if(this.marker)
        {
            c.setMarker(this.marker.createDuplicate());
        }
        c.setOrder(this.order);
        c.setSmooth(this.smooth);
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        if(this.trendline)
        {
            c.setTrendline(this.trendline.createDuplicate());
        }
        if(this.tx)
        {
            c.setTx(this.tx.createDuplicate());
        }
        if(this.val)
        {
            c.setVal(this.val.createDuplicate());
        }
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_LineSeries;
    },

    documentCreateFontMap: CAreaSeries.prototype.documentCreateFontMap,

    getAllRasterImages: CAreaSeries.prototype.getAllRasterImages,
    checkSpPrRasterImages: CAreaSeries.prototype.checkSpPrRasterImages,

    getSeriesName: CAreaSeries.prototype.getSeriesName,
    getCatName: CAreaSeries.prototype.getCatName,
    getValByIndex: CAreaSeries.prototype.getValByIndex,
    getFormatCode: CAreaSeries.prototype.getFormatCode,

    setFromOtherSeries: function(other)
    {
        if(other.cat)
            this.setCat(other.cat);
        if(other.dLbls)
            this.setDLbls(other.dLbls);
        if(other.dPt)
            copyDPt(this, other.dPt);
        if(other.errBars)
            this.setErrBars(other.errBars);
        if(AscFormat.isRealNumber(other.idx))
            this.setIdx(other.idx);
        if(other.marker)
            this.setMarker(other.marker);
        if(AscFormat.isRealNumber(other.order))
            this.setOrder(other.order);
        if(AscFormat.isRealBool(other.smooth))
            this.setSmooth(other.smooth);
        if(other.spPr){
            this.setSpPr(other.spPr);
            if(this.spPr && this.spPr.Fill && this.spPr.Fill.fill && this.spPr.Fill.fill.type ===  window['Asc'].c_oAscFill.FILL_TYPE_NOFILL){
                this.spPr.setFill(null);
            }
            if(this.spPr && this.spPr.ln && this.spPr.ln && this.spPr.ln.Fill && this.spPr.ln.Fill.fill && this.spPr.ln.Fill.fill.type ===  window['Asc'].c_oAscFill.FILL_TYPE_NOFILL){
                this.spPr.setLn(null);
            }
        }
        if(other.trendline)
            this.setTrendline(other.trendline);
        if(other.tx)
            this.setTx(other.tx);
        if(other.val)
            this.setVal(other.val);

        if(other.xVal)
        {
            this.setCat(new CCat());
            this.cat.setFromOtherObject(other.xVal);
        }
        if(other.yVal)
        {
            this.setVal(new CYVal());
            this.val.setFromOtherObject(other.yVal);
        }
    },


    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    recalculateBrush: function()
    {

    },

    setCat: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_LineSeries_SetCat, this.cat, pr));
        this.cat = pr;
    },
    setDLbls: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_LineSeries_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
    },
    addDPt: function(pr)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_LineSeries_SetDPt, this.dPt.length, [pr], true));
        this.dPt.push(pr);
    },
    setErrBars: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_LineSeries_SetErrBars, this.errBars, pr));
        this.errBars = pr;
    },
    setIdx: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_LineSeries_SetIdx, this.idx, pr));
        this.idx = pr;
    },
    setMarker: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_LineSeries_SetMarker, this.marker, pr));
        this.marker = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateInternalChart)
        {
            this.parent.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setOrder: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_LineSeries_SetOrder, this.order, pr));
        this.order = pr;
    },
    setSmooth: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_LineSeries_SetSmooth, this.smooth, pr));
        this.smooth = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateInternalChart)
        {
            this.parent.parent.parent.parent.handleUpdateInternalChart();
        }
    },
    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_LineSeries_SetSpPr, this.spPr, pr));
        this.spPr = pr;
        if(this.spPr && this.spPr.parent !== this)
        {
            this.spPr.setParent(this);
        }
    },
    setTrendline: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_LineSeries_SetTrendline, this.trendline, pr));
        this.trendline = pr;
    },
    setTx: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_LineSeries_SetTx, this.tx, pr));
        this.tx = pr;
    },
    setVal: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_LineSeries_SetVal, this.val, pr));
        this.val = pr;
        if(this.val && this.val.setParent)
        {
            this.val.setParent(this);
        }
    },

    handleUpdateLn: function()
    {
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateInternalChart)
        {
            this.parent.parent.parent.parent.handleUpdateInternalChart();
        }
            }
};


var SYMBOL_CIRCLE   = 0;
var SYMBOL_DASH     = 1;
var SYMBOL_DIAMOND  = 2;
var SYMBOL_DOT      = 3;
var SYMBOL_NONE     = 4;
var SYMBOL_PICTURE  = 5;
var SYMBOL_PLUS     = 6;
var SYMBOL_SQUARE   = 7;
var SYMBOL_STAR     = 8;
var SYMBOL_TRIANGLE = 9;
var SYMBOL_X        = 10;


var MARKER_SYMBOL_TYPE = [];
MARKER_SYMBOL_TYPE[0] = SYMBOL_DIAMOND;
MARKER_SYMBOL_TYPE[1] = SYMBOL_SQUARE;
MARKER_SYMBOL_TYPE[2] = SYMBOL_TRIANGLE;
MARKER_SYMBOL_TYPE[3] = SYMBOL_X;
MARKER_SYMBOL_TYPE[4] = SYMBOL_STAR;
MARKER_SYMBOL_TYPE[5] = SYMBOL_CIRCLE;
MARKER_SYMBOL_TYPE[6] = SYMBOL_PLUS;
MARKER_SYMBOL_TYPE[7] = SYMBOL_DOT;
MARKER_SYMBOL_TYPE[8] = SYMBOL_DASH;

function CMarker()
{
    this.size = null; //2 <= size <= 72
    this.spPr = null;
    this.symbol = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CMarker.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_Marker;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    merge: function(otherMarker)
    {
        if(isRealObject(otherMarker))
        {
            if(AscFormat.isRealNumber(otherMarker.size))
            {
                this.setSize(otherMarker.size);
            }
            if(AscFormat.isRealNumber(otherMarker.symbol))
            {
                this.setSymbol(otherMarker.symbol);
            }
            if(otherMarker.spPr && (otherMarker.spPr.Fill || otherMarker.spPr.ln))
            {
                if(!this.spPr)
                {
                    this.setSpPr(new AscFormat.CSpPr());
                }
                if(otherMarker.spPr.Fill)
                {
                    this.spPr.setFill(otherMarker.spPr.Fill.createDuplicate());
                }
                if(otherMarker.spPr.ln)
                {
                    if(!this.spPr.ln)
                    {
                        this.spPr.setLn(new AscFormat.CLn());
                    }
                    this.spPr.ln.merge(otherMarker.spPr.ln);
                }
            }
        }
        return this;
    },


    createDuplicate: function()
    {
        return (new CMarker()).merge(this);
    },

    setSize: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_Marker_SetSize, this.size, pr));
        this.size = pr;
    },

    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Marker_SetSpPr, this.spPr, pr));
        this.spPr = pr;
    },

    setSymbol: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_Marker_SetSymbol, this.symbol, pr));
        this.symbol = pr;
            }
};


function CMinusPlus()
{
    this.numLit = null;
    this.numRef = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CMinusPlus.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var c = new CMinusPlus();
        if(this.numRef)
        {
            c.setNumRef(this.numRef.createDuplicate());
        }
        if(this.numLit)
        {
            c.setNumLit(this.numLit.createDuplicate());
        }
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_MinusPlus;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },


    setNumLit: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_MinusPlus_SetnNumLit, this.numLit, pr));
        this.numLit = pr;
    },

    setNumRef: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_MinusPlus_SetnNumRef, this.numRef, pr));
        this.numRef = pr;
            }
};


function CMultiLvlStrCache()
{
    this.lvl     = [];
    this.ptCount = null;

    this.m_LvlContentChanges = new AscCommon.CContentChanges();
    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CMultiLvlStrCache.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_MultiLvlStrCache_SetLvl:{
                return this.m_LvlContentChanges;
            }
        }
        return null;
    },

    createDuplicate: function()
    {
        var c = new CMultiLvlStrCache();

        for(var i = 0; i < this.lvl.length; ++i)
        {
            c.setLvl(this.lvl[i].createDuplicate());
        }
        c.setPtCount(this.ptCount);
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_MultiLvlStrCache;
    },

    setLvl: function(pr)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_MultiLvlStrCache_SetLvl, this.lvl.length, [pr], true));
        this.lvl.push(pr);
    },

    setPtCount: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_MultiLvlStrCache_SetPtCount, this.ptCount, pr));
        this.ptCount = pr;
        },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    }
};

function CMultiLvlStrRef()
{
    this.f                = null;
    this.multiLvlStrCache = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CMultiLvlStrRef.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function()
    {},

    getObjectType:  function()
    {
        return AscDFH.historyitem_type_MultiLvlStrRef;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    createDuplicate: function()
    {
        var c = new CMultiLvlStrRef();
        c.setF(this.f);
        if(this.multiLvlStrCache)
        {
            c.setMultiLvlStrCache(this.multiLvlStrCache.createDuplicate());
        }
        return c;
    },

    setF: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_MultiLvlStrRef_SetF, this.f, pr));
        this.f = pr;
    },

    setMultiLvlStrCache: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_MultiLvlStrRef_SetMultiLvlStrCache, this.multiLvlStrCache, pr));
        this.multiLvlStrCache = pr;
            }
};

function CNumRef()
{
    this.f = null;
    this.numCache = null;
    this.parent = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CNumRef.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function(data)
    {
        if(data && data.Type === AscDFH.historyitem_NumRef_SetF && this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent
            && this.parent.parent.parent.parent.parent && this.parent.parent.parent.parent.parent.parent && this.parent.parent.parent.parent.parent.parent.handleUpdateInternalChart)
        {
            this.parent.parent.parent.parent.parent.parent.handleUpdateInternalChart();
            this.parent.parent.parent.parent.parent.parent.recalcInfo.recalculateReferences = true;
            this.parent.parent.parent.parent.parent.parent.addToRecalculate();
        }
    },

    createDuplicate: function()
    {
        var c = new CNumRef();
        c.setF(this.f);
        if(this.numCache)
        {
            c.setNumCache(this.numCache.createDuplicate());
        }
        return c;        
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_NumRef;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
    },

    setF: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_NumRef_SetF, this.f, pr));
        this.f = pr;

        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent
            && this.parent.parent.parent.parent.parent && this.parent.parent.parent.parent.parent.parent && this.parent.parent.parent.parent.parent.parent.handleUpdateInternalChart)
        {
            if(this.parent.parent.parent.parent.parent.parent.bNoHandleRecalc === true)
            {
                return;
            }
            this.parent.parent.parent.parent.parent.parent.recalcInfo.recalculateReferences = true;
            this.parent.parent.parent.parent.parent.parent.handleUpdateInternalChart();
        }
    },

    setNumCache: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_NumRef_SetNumCache, this.numCache, pr));
        this.numCache = pr;
                }
};


function CNumericPoint()
{
    this.formatCode = null;
    this.idx        = null;
    this.val        = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CNumericPoint.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    createDuplicate: function()
    {
        var c = new CNumericPoint();
        c.setFormatCode(this.formatCode);
        c.setIdx(this.idx);
        c.setVal(this.val);
        return c;
    },

    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_NumericPoint;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setFormatCode: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_NumericPoint_SetFormatCode, this.formatCode, pr));
        this.formatCode = pr;
    },

    setIdx: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_NumericPoint_SetIdx, this.idx, pr));
        this.idx = pr;
    },

    setVal: function(pr)
    {
        var _pr = parseFloat(pr);
        if(isNaN(_pr))
        {
            _pr = 0;
        }
        History.Add(new CChangesDrawingsDouble2(this, AscDFH.historyitem_NumericPoint_SetVal, this.val, _pr));
        this.val = _pr;
            }
};


function CNumFmt()
{
    this.formatCode = null;
    this.sourceLinked = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}
CNumFmt.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var c = new CNumFmt();
        c.setFormatCode(this.formatCode);
        c.setSourceLinked(this.sourceLinked);
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_NumFmt;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setFormatCode: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_NumFmt_SetFormatCode, this.formatCode, pr));
        this.formatCode = pr;
    },

    setSourceLinked: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_NumFmt_SetSourceLinked, this.sourceLinked, pr));
        this.sourceLinked = pr;
            }
};


function CNumLit()
{
    this.formatCode  = null;
    this.pts          = [];
    this.ptCount     = null;

    this.m_oPtsContentChanges = new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CNumLit.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function()
    {},


    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_CommonLit_RemoveDPt:
            case AscDFH.historyitem_NumLit_AddPt:{
                return this.m_oPtsContentChanges;
            }
        }
        return null;
    },

    removeDPt: function(idx)
    {
        if(this.pts[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonLit_RemoveDPt, idx, this.pts.splice(idx, 1), false));
            this.pts.splice(idx, 1);
        }
    },

    createDuplicate: function()
    {
        var c = new CNumLit();
        c.setFormatCode(this.formatCode);
        for(var i = 0; i < this.pts.length; ++i)
        {
            c.addPt(this.pts[i].createDuplicate());
        }
        c.setPtCount(this.ptCount);
        return c;
    },

    getPtByIndex: function(idx)
    {
        for(var i = 0; i < this.pts.length; ++i)
        {
            if(this.pts[i].idx === idx)
                return this.pts[i];
        }
        return null;
    },

    getPtCount: function()
    {
        if(AscFormat.isRealNumber(this.ptCount))
        {
            return this.ptCount;
        }
        return this.pts.length;
    },


    getObjectType: function()
    {
        return AscDFH.historyitem_type_NumLit;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setFormatCode: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_NumLit_SetFormatCode, this.formatCode, pr));
        this.formatCode = pr;
    },

    addPt: function(pr)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_NumLit_AddPt, this.pts.length, [pr], true));
        this.pts.push(pr);
    },

    setPtCount: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_NumLit_SetPtCount, this.ptCount, pr));
        this.ptCount = pr;
            }
};

function COfPieChart()
{
    this.custSplit     = [];
    this.dLbls         = null;
    this.gapWidth      = null;
    this.ofPieType     = null;
    this.secondPieSize = null;
    this.series        = [];
    this.serLines      = null;
    this.splitPos      = null;
    this.splitType     = null;
    this.varyColors    = null;

    this.parent = null;



    this.m_oCustSplitContentChanges = new AscCommon.CContentChanges();
    this.m_oSeriesContentChanges =  new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

COfPieChart.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_OfPieChart_AddSer:
            case AscDFH.historyitem_CommonChart_RemoveSeries:{
                return this.m_oSeriesContentChanges;
            }
            case AscDFH.historyitem_OfPieChart_AddCustSplit:{
                return this.m_oCustSplitContentChanges;
            }
        }
        return null;
    },


    documentCreateFontMap: CBarChart.prototype.documentCreateFontMap,

    Refresh_RecalcData: function()
    {},

    getSeriesConstructor: function()
    {
        return new CPieSeries();
    },
    removeSeries: function(idx)
    {
        if(this.series[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonChart_RemoveSeries, idx, this.series.splice(idx, 1), false));
        }
    },

    getDefaultDataLabelsPosition: function()
    {
        return c_oAscChartDataLabelsPos.bestFit;
    },

    createDuplicate: function()
    {
        var c = new COfPieChart(), i;
        for(i = 0; i < this.custSplit.length; ++i)
        {
            c.addCustSplit(this.custSplit[i].createDuplicate());
        }
        if(this.dLbls)
        {
            c.setDLbls((this.dLbls.createDuplicate()));
        }
        c.setGapWidth(this.gapWidth);
        c.setOfPieType(this.ofPieType);
        c.setSecondPieSize(this.secondPieSize);
        for(i = 0; i < this.series.length; ++i)
        {
            c.addSer(this.series[i].createDuplicate());
        }
        if(this.serLines)
        {
            c.setSerLines(this.serLines.createDuplicate());
        }
        c.setSplitPos(this.splitPos);
        c.setSplitType(this.splitType);
        c.setVaryColors(this.varyColors);
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_OfPieChart;
    },

    getAllRasterImages: function(images)
    {
        CBarChart.prototype.getAllRasterImages.call(this, images);
        if(this.serLines && this.serLines.spPr)
        {
            this.serLines.spPr.checkBlipFillRasterImage(images);
        }
    },

    checkSpPrRasterImages: function(images)
    {
        CBarChart.prototype.checkSpPrRasterImages.call(this, images);
        if(this.serLines && this.serLines.spPr)
        {
            checkSpPrRasterImages(this.serLines.spPr);
        }
    },


    removeDataLabels: CBarChart.prototype.removeDataLabels,

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    addCustSplit: function(pr)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_OfPieChart_AddCustSplit, this.custSplit.length, [pr], true));
        this.custSplit.push(pr);
    },
    setDLbls: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_OfPieChart_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateDataLabels();
        }
    },
    setGapWidth: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_OfPieChart_SetGapWidth, this.gapWidth, pr));
        this.gapWidth = pr;
    },
    setOfPieType: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_OfPieChart_SetOfPieType, this.ofPieType, pr));
        this.ofPieType = pr;
    },
    setSecondPieSize: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_OfPieChart_SetSecondPieSize, this.secondPieSize, pr));
        this.secondPieSize = pr;
    },
    addSer: function(ser)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_OfPieChart_AddSer, this.series.length, [ser], true));
        this.series.push(ser);
        ser.setParent(this);
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateType();
        }
    },
    setSerLines: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_OfPieChart_SetSerLines, this.serLines, pr));
        this.serLines = pr;
    },
    setSplitPos: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_OfPieChart_SetSplitPos, this.splitPos, pr));
        this.splitPos = pr;
    },
    setSplitType: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_OfPieChart_SetSplitType, this.splitType, pr));
        this.splitType = pr;
    },
    setVaryColors: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_OfPieChart_SetVaryColors, this.varyColors, pr));
        this.varyColors = pr;
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};

function CPictureOptions()
{
    this.applyToEnd       = null;
    this.applyToFront     = null;
    this.applyToSides     = null;
    this.pictureFormat    = null;
    this.pictureStackUnit = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CPictureOptions.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var c = new CPictureOptions();
        c.setApplyToEnd(this.applyToEnd);
        c.setApplyToFront(this.applyToFront);
        c.setApplyToSides(this.applyToSides);
        c.setPictureFormat(this.pictureFormat);
        c.setPictureStackUnit(this.pictureStackUnit);
        return  c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_PictureOptions;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setApplyToEnd: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PictureOptions_SetApplyToEnd, this.applyToEnd, pr));
        this.applyToEnd = pr;
    },
    setApplyToFront: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PictureOptions_SetApplyToFront, this.applyToFront, pr));
        this.applyToFront = pr;
    },
    setApplyToSides: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PictureOptions_SetApplyToSides, this.applyToSides, pr));
        this.applyToSides = pr;
    },
    setPictureFormat: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_PictureOptions_SetPictureFormat, this.pictureFormat, pr));
        this.pictureFormat = pr;
    },
    setPictureStackUnit: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_PictureOptions_SetPictureStackUnit, this.pictureStackUnit, pr));
        this.pictureStackUnit = pr;
            }
};


function CPieChart()
{
    this.dLbls         = null;
    this.firstSliceAng = null;
    this.series        = [];
    this.varyColors    = null;
    this.parent = null;


    this.m_oSeriesContentChanges =  new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CPieChart.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_PieChart_AddSer:
            case AscDFH.historyitem_CommonChart_RemoveSeries:{
                return this.m_oSeriesContentChanges;
            }
        }
        return null;
    },

    Refresh_RecalcData: function(data)
    {
        if(!isRealObject(data))
            return;

        switch (data.Type)
        {
            case AscDFH.historyitem_CommonChartFormat_SetParent:
            {
                break;
            }
            case AscDFH.historyitem_CommonChart_RemoveSeries:
            {
                break;
            }
            case AscDFH.historyitem_PieChart_SetDLbls:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateDataLabels();
                }
                break;
            }
            case AscDFH.historyitem_PieChart_SetFirstSliceAng:
            {
                break;
            }
            case AscDFH.historyitem_PieChart_AddSer:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateType();
                }
                break;
            }
            case AscDFH.historyitem_PieChart_SetVaryColors:
            {
                break;
            }
        }
    },

    removeSeries: function(idx)
    {
        if(this.series[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonChart_RemoveSeries, idx, this.series.splice(idx, 1), false));
        }
    },

    getDefaultDataLabelsPosition: function()
    {
        return c_oAscChartDataLabelsPos.bestFit;
    },

    getSeriesConstructor: function()
    {
        return new CPieSeries();
    },

    createDuplicate: function()
    {
        var c = new CPieChart();
        if(this.dLbls)
        {
            c.setDLbls(this.dLbls.createDuplicate());
        }
        c.setFirstSliceAng(this.firstSliceAng);
        for(var i = 0; i < this.series.length; ++i)
        {
            c.addSer(this.series[i].createDuplicate());
        }
        c.setVaryColors(this.varyColors);
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_PieChart;
    },


    documentCreateFontMap: CBarChart.prototype.documentCreateFontMap,

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    getAllRasterImages: CBarChart.prototype.getAllRasterImages,
    checkSpPrRasterImages: CBarChart.prototype.checkSpPrRasterImages,

    removeDataLabels: CBarChart.prototype.removeDataLabels,

    setFromOtherChart: function(c)
    {
        var i;
        if(c.dLbls)
            this.setDLbls(c.dLbls);

        if(AscFormat.isRealNumber(c.firstSliceAng))
            this.setFirstSliceAng(c.firstSliceAng);


        if(Array.isArray(c.series))
        {
            for(i = 0; i < c.series.length; ++i)
            {
                var ser = new CPieSeries();
                ser.setFromOtherSeries(c.series[i]);
                this.addSer(ser);
            }
        }
        if(AscFormat.isRealBool(c.varyColors))
            this.setVaryColors(c.varyColors);
    },

    setDLbls: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PieChart_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateDataLabels();
        }
    },

    setFirstSliceAng: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_PieChart_SetFirstSliceAng, this.firstSliceAng, pr));
        this.firstSliceAng = pr;
    },

    addSer: function(ser)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_PieChart_AddSer, this.series.length, [ser], true));
        this.series.push(ser);
        ser.setParent(this);
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateType();
        }
    },
    setVaryColors: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_PieChart_SetVaryColors, this.varyColors, pr));
        this.varyColors = pr;
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }


};


function CPieSeries()
{
    this.cat       = null;
    this.dLbls     = null;
    this.dPt       = [];
    this.explosion = null;
    this.idx       = null;
    this.order     = null;
    this.spPr      = null;
    this.tx        = null;
    this.val       = null;


    this.parent = null;


    this.m_oDPtContentChanges = new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CPieSeries.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_PieSeries_SetDPt:
            case AscDFH.historyitem_CommonSeries_RemoveDPt:{
                return this.m_oDPtContentChanges;
            }
        }
        return null;
    },

    getDptByIdx: function(idx){
        for(var i = 0; i < this.dPt.length; ++i){
            if(this.dPt[i].idx === idx){
                return this.dPt[i];
            }
        }
        return null;
    },

    Refresh_RecalcData: function()
    {},

    removeDPt: function(idx)
    {
        if(this.dPt[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonSeries_RemoveDPt, idx, this.dPt.splice(idx, 1), false));
            this.dPt.splice(idx, 1);
        }
    },

    createDuplicate: function()
    {
        var c = new CPieSeries();
        if(this.cat)
        {
            c.setCat(this.cat.createDuplicate());
        }
        if(this.dLbls)
        {
            c.setDLbls(this.dLbls.createDuplicate());
        }
        for(var  i = 0; i < this.dPt.length; ++i)
        {
            c.addDPt(this.dPt[i].createDuplicate());
        }
        c.setExplosion(this.explosion);
        c.setIdx(this.idx);
        c.setOrder(this.order);
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        if(this.tx)
        {
            c.setTx(this.tx.createDuplicate());
        }
        if(this.val)
        {
            c.setVal(this.val.createDuplicate());
        }
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_PieSeries;
    },


    documentCreateFontMap: CAreaSeries.prototype.documentCreateFontMap,

    getAllRasterImages: CAreaSeries.prototype.getAllRasterImages,
    checkSpPrRasterImages: CAreaSeries.prototype.checkSpPrRasterImages,

    setFromOtherSeries: function(o)
    {
        if(o.cat)
            this.setCat(o.cat);
        if(o.dLbls)
            this.setDLbls(o.dLbls);
        if(o.dPt)
        {
            for(var i = 0; i < o.dPt.length; ++i)
            {
                this.addDPt(o.dPt[i]);
            }
        }
        if(o.explosion)
            this.setExplosion(o.explosion);
        if(AscFormat.isRealNumber(o.idx))
            this.setIdx(o.idx);
        if(o.order)
            this.setOrder(o.order);
        if(o.spPr){
            this.setSpPr(o.spPr);
            if(!(o instanceof AscFormat.CPieSeries)){
                this.spPr.setFill(null);
            }
        }
        if(o.tx)
            this.setTx(o.tx);
        if(o.val)
            this.setVal(o.val);

        if(o.xVal)
        {
            this.setCat(new CCat());
            this.cat.setFromOtherObject(o.xVal);
        }
        if(o.yVal)
        {
            this.setVal(new CYVal());
            this.val.setFromOtherObject(o.yVal);
        }
    },

    getSeriesName: CAreaSeries.prototype.getSeriesName,
    getCatName: CAreaSeries.prototype.getCatName,
    getValByIndex: CAreaSeries.prototype.getValByIndex,
    getFormatCode: CAreaSeries.prototype.getFormatCode,

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setCat: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PieSeries_SetCat, this.cat, pr));
        this.cat = pr;
    },

    setDLbls: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PieSeries_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
    },

    addDPt: function(pr)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_PieSeries_SetDPt, this.dPt.length, [pr], true));
        this.dPt.push(pr);
    },

    setExplosion: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_PieSeries_SetExplosion, this.explosion, pr));
        this.explosion = pr;
    },

    setIdx: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_PieSeries_SetIdx, this.idx, pr));
        this.idx = pr;
    },

    setOrder: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_PieSeries_SetOrder, this.order, pr));
        this.order = pr;
    },

    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PieSeries_SetSpPr, this.spPr, pr));
        this.spPr = pr;
    },

    setTx: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PieSeries_SetTx, this.tx, pr));
        this.tx = pr;
    },

    setVal: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PieSeries_SetVal, this.val, pr));
        this.val = pr;
        if(this.val && this.val.setParent)
        {
            this.val.setParent(this);
        }
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};


function CPivotFmt()
{
    this.dLbl = null;
    this.idx = null;
    this.marker = null;
    this.spPr = null;
    this.txPr = null;
    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}
CPivotFmt.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var c = new CPivotFmt();
        if(this.dLbl)
        {
            c.setLbl(this.dLbl.createDuplicate());
        }
        c.setIdx(this.idx);
        if(this.marker)
        {
            c.setMarker(this.marker.createDuplicate());
        }
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        if(this.txPr)
        {
            c.setTxPr(this.txPr.createDuplicate());
        }
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_PivotFmt;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setLbl: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PivotFmt_SetDLbl, this.dLbl, pr));
        this.dLbl = pr;
    },

    setIdx: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_PivotFmt_SetIdx, this.idx, pr));
        this.idx = pr;
    },

    setMarker: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PivotFmt_SetMarker, this.marker, pr));
        this.marker = pr;
    },

    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PivotFmt_SetSpPr, this.spPr, pr));
        this.spPr = pr;
    },

    setTxPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_PivotFmt_SetTxPr, this.txPr, pr));
        this.txPr = pr;
            }
};

function CRadarChart()
{
    this.axId        = [];
    this.dLbls       = null;
    this.radarStyle  = null;
    this.series      = [];
    this.varyColors  = null;
    this.parent = null;


    this.m_oAxIdContentChanges = new AscCommon.CContentChanges();
    this.m_oSeriesContentChanges =  new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CRadarChart.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_RadarChart_AddAxId:{
                return this.m_oAxIdContentChanges;
            }
            case AscDFH.historyitem_RadarChart_AddSer:
            case AscDFH.historyitem_CommonChart_RemoveSeries:{
                return this.m_oSeriesContentChanges;
            }
        }
        return null;
    },

    removeSeries: function(idx)
    {
        if(this.series[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonChart_RemoveSeries, idx, this.series.splice(idx, 1), false));
        }
    },


    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    getSeriesConstructor: function()
    {
        return new CRadarSeries();
    },

    getDefaultDataLabelsPosition: function()
    {
        return c_oAscChartDataLabelsPos.outEnd;
    },

    Refresh_RecalcData: function(data)
    {
        if(!isRealObject(data))
            return;
        switch(data.Type)
        {
            case AscDFH.historyitem_CommonChartFormat_SetParent:
            {
                break;
            }
            case AscDFH.historyitem_CommonChart_RemoveSeries:
            {
                break;
            }
            case AscDFH.historyitem_RadarChart_AddAxId:
            {
                break;
            }
            case AscDFH.historyitem_RadarChart_SetDLbls:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateDataLabels();
                }
                break;
            }
            case AscDFH.historyitem_RadarChart_SetRadarStyle:
            {
                break;
            }
            case AscDFH.historyitem_RadarChart_AddSer:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateType();
                }
                break;
            }
            case AscDFH.historyitem_RadarChart_SetVaryColors:
            {
                break;
            }
        }
    },

    createDuplicate: function()
    {
        var c = new CRadarChart();
        if(this.dLbls)
        {
            c.setDLbls(this.dLbls.createDuplicate());
        }
        c.setRadarStyle(this.radarStyle);
        for(var  i = 0; i < this.series.length; ++i)
        {
            c.addSer(this.series[i].createDuplicate());
        }
        c.setVaryColors(this.varyColors);
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_RadarChart;
    },


    documentCreateFontMap: CBarChart.prototype.documentCreateFontMap,

    removeDataLabels: CBarChart.prototype.removeDataLabels,
    getAllRasterImages: CBarChart.prototype.getAllRasterImages,
    checkSpPrRasterImages: CBarChart.prototype.checkSpPrRasterImages,

    getAxisByTypes: CPlotArea.prototype.getAxisByTypes,

    addAxId: function(pr)
    {
        if(!pr)
            return;
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_RadarChart_AddAxId, this.axId.length, [pr], true));
        this.axId.push(pr);
    },

    setDLbls: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_RadarChart_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateDataLabels();
        }
    },

    setRadarStyle: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_RadarChart_SetRadarStyle, this.radarStyle, pr));
        this.radarStyle = pr;
    },

    addSer: function(ser)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_RadarChart_AddSer, this.series.length, [ser], true));
        this.series.push(ser);
        ser.setParent(this);
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateType();
        }
    },

    setVaryColors: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_RadarChart_SetVaryColors, this.varyColors, pr));
        this.varyColors = pr;
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};


function copyDPt(oThis, pt)
{
    for(var i = 0; i < pt.length; ++i)
    {
        oThis.addDPt(pt[i]);
    }
}

function CRadarSeries()
{
    this.cat     = null;
    this.dLbls   = null;
    this.dPt     = [];
    this.idx     = null;
    this.marker  = null;
    this.order   = null;
    this.spPr    = null;
    this.tx      = null;
    this.val     = null;

    this.parent = null;

    this.m_oDPtContentChanges = new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CRadarSeries.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function()
    {},


    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_RadarSeries_SetDPt:
            case AscDFH.historyitem_CommonSeries_RemoveDPt:{
                return this.m_oDPtContentChanges;
            }
        }
        return null;
    },

    removeDPt: function(idx)
    {
        if(this.dPt[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonSeries_RemoveDPt, idx, this.dPt.splice(idx, 1), false));
        }
    },

    createDuplicate: function()
    {
        var c = new CRadarSeries();
        if(this.cat)
        {
            c.setCat(this.cat.createDuplicate());
        }
        if(this.dLbls)
        {
            c.setDLbls(this.dLbls.createDuplicate());
        }
        for(var i = 0; i < this.dPt.length; ++i)
        {
            c.addDPt(this.dPt[i].createDuplicate());
        }
        c.setIdx(this.idx);
        if(this.marker)
        {
            c.setMarker(this.marker.createDuplicate());
        }
        c.setOrder(this.order);
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        if(this.tx)
        {
            c.setTx(this.tx.createDuplicate());
        }
        if(this.val)
        {
            c.setVal(this.val.createDuplicate());
        }
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_RadarSeries;
    },

    documentCreateFontMap: CAreaSeries.prototype.documentCreateFontMap,
    getSeriesName: CAreaSeries.prototype.getSeriesName,
    getCatName: CAreaSeries.prototype.getCatName,
    getValByIndex: CAreaSeries.prototype.getValByIndex,
    getFormatCode: CAreaSeries.prototype.getFormatCode,


    getAllRasterImages: CAreaSeries.prototype.getAllRasterImages,
    checkSpPrRasterImages: CAreaSeries.prototype.checkSpPrRasterImages,

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setCat: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_RadarSeries_SetCat, this.cat, pr));
        this.cat = pr;
    },

    setFromOtherSeries: function(o)
    {
        if(o.cat)
            this.setCat(o.cat);
        if(o.dLbls)
            this.setDLbls(o.dLbls);
        if(o.dPt)
        {
            copyDPt(this, o.dPt)
        }
        if(o.marker)
            this.setMarker(o.marker);
        if(AscFormat.isRealNumber(o.idx))
            this.setIdx(o.idx);
        if(o.order)
            this.setOrder(o.order);
        if(o.spPr)
            this.setSpPr(o.spPr);
        if(o.tx)
            this.setTx(o.tx);
        if(o.val)
            this.setVal(o.val);
        if(o.xVal)
        {
            this.setCat(new CCat());
            this.cat.setFromOtherObject(o.xVal);
        }
        if(o.yVal)
        {
            this.setVal(new CYVal());
            this.val.setFromOtherObject(o.yVal);
        }
    },

    setDLbls: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_RadarSeries_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
    },
    addDPt: function(pr)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_RadarSeries_SetDPt, this.dPt.length, [pr], true));
        this.dPt.push(pr);
    },
    setIdx: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_RadarSeries_SetIdx, this.idx, pr));
        this.idx = pr;
    },
    setMarker: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_RadarSeries_SetCat, this.marker, pr));
        this.marker = pr;
    },
    setOrder: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_RadarSeries_SetCat, this.order, pr));
        this.order = pr;
    },
    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_RadarSeries_SetCat, this.spPr, pr));
        this.spPr = pr;
    },
    setTx: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_RadarSeries_SetCat, this.tx, pr));
        this.tx = pr;
    },
    setVal: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_RadarSeries_SetCat, this.val, pr));
        this.val = pr;
        if(this.val && this.val.setParent)
        {
            this.val.setParent(this);
        }
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};


var ORIENTATION_MAX_MIN = 0;
var ORIENTATION_MIN_MAX = 1;

function CScaling()
{
    this.logBase = null;
    this.max = null;
    this.min = null;
    this.orientation = null;
    this.parent = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CScaling.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var c = new CScaling();
        c.setLogBase(this.logBase);
        c.setMax(this.max);
        c.setMin(this.min);
        c.setOrientation(this.orientation);
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_Scaling;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Scaling_SetParent, this.parent, pr));
        this.parent = pr;
    },

    setLogBase: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Scaling_SetLogBase, this.logBase, pr));
        this.logBase = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateInternalChart)
        {
            this.parent.parent.parent.parent.handleUpdateInternalChart();
        }
    },

    setMax: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Scaling_SetMax, this.max, pr));
        this.max = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateInternalChart)
        {
            this.parent.parent.parent.parent.handleUpdateInternalChart();
        }
    },

    setMin: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Scaling_SetMin, this.min, pr));
        this.min = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateInternalChart)
        {
            this.parent.parent.parent.parent.handleUpdateInternalChart();
        }
    },

    setOrientation: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_Scaling_SetOrientation, this.orientation, pr));
        this.orientation = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent && this.parent.parent.parent.parent.handleUpdateInternalChart)
        {
            this.parent.parent.parent.parent.handleUpdateInternalChart();
        }
            }
};

function CScatterChart()
{
    this.axId        = [];
    this.dLbls       = null;
    this.scatterStyle  = null;
    this.series      = [];
    this.varyColors  = null;

    this.parent = null;


    this.m_oAxIdContentChanges = new AscCommon.CContentChanges();
    this.m_oSeriesContentChanges =  new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CScatterChart.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_ScatterChart_AddAxId:{
                return this.m_oAxIdContentChanges;
            }
            case AscDFH.historyitem_ScatterChart_AddSer:
            case AscDFH.historyitem_CommonChart_RemoveSeries:{
                return this.m_oSeriesContentChanges;
            }
        }
        return null;
    },


    Refresh_RecalcData: function(data)
    {
        if(!isRealObject(data))
            return;
        switch(data.Type)
        {
            case AscDFH.historyitem_CommonChartFormat_SetParent:
            {
                break;
            }
            case AscDFH.historyitem_CommonChart_RemoveSeries:
            {
                break;
            }
            case AscDFH.historyitem_ScatterChart_AddAxId:
            {
                break;
            }
            case AscDFH.historyitem_ScatterChart_SetDLbls:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateDataLabels();
                }
                break;
            }
            case AscDFH.historyitem_ScatterChart_SetScatterStyle:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateType();
                }
                break;
            }
            case AscDFH.historyitem_ScatterChart_AddSer:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateType();
                }
                break;
            }
            case AscDFH.historyitem_ScatterChart_SetVaryColors:
            {
                break;
            }
        }
    },


    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    removeSeries: function(idx)
    {
        if(this.series[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonChart_RemoveSeries, idx, this.series.splice(idx, 1), false));
        }
    },

    getDefaultDataLabelsPosition: function()
    {
        return c_oAscChartDataLabelsPos.r;
    },

    getSeriesConstructor: function()
    {
        return new CScatterSeries();
    },

    createDuplicate: function()
    {
        var c = new CScatterChart();
        if(this.dLbls)
        {
            c.setDLbls(this.dLbls.createDuplicate());
        }
        c.setScatterStyle(this.scatterStyle);
        for(var i = 0; i < this.series.length; ++i)
        {
            c.addSer(this.series[i].createDuplicate());
        }
        c.setVaryColors(this.varyColors);
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_ScatterChart;
    },


    documentCreateFontMap: CBarChart.prototype.documentCreateFontMap,

    getAllRasterImages: CBarChart.prototype.getAllRasterImages,
    checkSpPrRasterImages: CBarChart.prototype.checkSpPrRasterImages,


    removeDataLabels: CBarChart.prototype.removeDataLabels,

    setFromOtherChart: function(o)
    {
        if(o.dLbls)
            this.setDLbls(o.dLbls);
        if(AscFormat.isRealNumber(o.scatterStyle))
            this.setScatterStyle(o.scatterStyle);
        if(Array.isArray(o.series))
        {
            for(var i = 0; i < o.series.length; ++i)
            {
                var ser = new CScatterSeries();
                ser.setFromOtherSeries(o.series[i]);
                this.addSer(ser);
            }
        }
    },

    getAxisByTypes: CPlotArea.prototype.getAxisByTypes,

    addAxId: function(pr)
    {
        if(!pr)
            return;
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_ScatterChart_AddAxId, this.axId.length, [pr], true));
        this.axId.push(pr);
    },

    setDLbls: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ScatterChart_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateDataLabels();
        }
    },

    setScatterStyle: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_ScatterChart_SetScatterStyle, this.scatterStyle, pr));
        this.scatterStyle = pr;
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateType();
        }
    },

    addSer: function(ser)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_ScatterChart_AddSer, this.series.length, [ser], true));
        this.series.push(ser);
        ser.setParent(this);
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateType();
        }
    },

    setVaryColors: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_ScatterChart_SetVaryColors, this.varyColors, pr));
        this.varyColors = pr;
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};


function CScatterSeries()
{
    this.dLbls     = null;
    this.dPt       = [];
    this.errBars   = null;
    this.idx       = null;
    this.marker    = null;
    this.order     = null;
    this.smooth    = null;
    this.spPr      = null;
    this.trendline = null;
    this.tx        = null;
    this.xVal      = null;
    this.yVal      = null;
    this.parent = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}
CScatterSeries.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
    },

    documentCreateFontMap: CAreaSeries.prototype.documentCreateFontMap,

    removeDPt: function(idx)
    {
        if(this.dPt[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonSeries_RemoveDPt, idx, this.dPt.splice(idx, 1), false));
        }
    },

    createDuplicate: function()
    {
        var c = new CScatterSeries();
        this.dLbls && c.setDLbls(this.dLbls.createDuplicate());
        for(var i = 0; i < this.dPt.length; ++i)
        {
            c.addDPt(this.dPt[i].createDuplicate());
        }
        if(this.errBars)
        {
            c.setErrBars(this.errBars.createDuplicate());
        }
        c.setIdx(this.idx);
        if(this.marker)
        {
            c.setMarker(this.marker.createDuplicate());
        }
        c.setOrder(this.order);
        c.setSmooth(this.smooth);
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        if(this.trendline)
        {
            c.setTrendline(this.trendline.createDuplicate())
        }
        if(this.tx)
        {
            c.setTx(this.tx.createDuplicate());
        }
        if(this.xVal)
        {
            c.setXVal(this.xVal.createDuplicate());
        }
        if(this.yVal)
        {
            c.setYVal(this.yVal.createDuplicate());
        }
        return c;
    },

    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_ScatterSer;
    },

    getAllRasterImages: CAreaSeries.prototype.getAllRasterImages,
    checkSpPrRasterImages: CAreaSeries.prototype.checkSpPrRasterImages,

    setFromOtherSeries: function(o)
    {
        if(o.dLbls)
            this.setDLbls(o.dLbls);
        if(o.dPt)
            copyDPt(this, o.dPt);
        if(o.errBars)
            this.setErrBars(o.errBars);
        if(AscFormat.isRealNumber(o.idx))
            this.setIdx(o.idx);
        if(o.marker)
            this.setMarker(o.marker);
        if(AscFormat.isRealNumber(o.order))
            this.setOrder(o.order);

        if(AscFormat.isRealBool(o.smooth))
            this.setSmooth(o.smooth);

        if(o.spPr)
            this.setSpPr(o.spPr);
        if(o.trendline)
            this.setTrendline(o.trendline);
        if(o.tx)
            this.setTx(o.tx);
        if(o.xVal)
            this.setXVal(o.xVal);
        if(o.yVal)
            this.setYVal(o.yVal);
        if(o.cat)
        {
            this.setXVal(new CXVal());
            this.xVal.setFromOtherObject(o.cat);
        }
        if(o.val)
        {
            this.setYVal(new CYVal());
            this.yVal.setFromOtherObject(o.val);
        }
    },

    getSeriesName: CAreaSeries.prototype.getSeriesName,

    getCatName: CAreaSeries.prototype.getCatName,

    getValByIndex: CAreaSeries.prototype.getValByIndex,
    getFormatCode: CAreaSeries.prototype.getFormatCode,

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setDLbls: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ScatterSer_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
    },
    addDPt: function(pr)
    {

        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_ScatterSer_SetDPt, this.dPt.length, [pr], true));
        //History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ScatterSer_SetDPt, this.dPt, pr));
        this.dPt.push(pr);
    },
    setErrBars: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ScatterSer_SetErrBars, this.errBars, pr));
        this.errBars = pr;
    },
    setIdx: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_ScatterSer_SetIdx, this.idx, pr));
        this.idx = pr;
    },
    setMarker: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ScatterSer_SetMarker, this.marker, pr));
        this.marker = pr;
    },
    setOrder: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_ScatterSer_SetOrder, this.order, pr));
        this.order = pr;
    },
    setSmooth: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_ScatterSer_SetSmooth, this.smooth, pr));
        this.smooth = pr;
    },
    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ScatterSer_SetSpPr, this.spPr, pr));
        this.spPr = pr;
    },
    setTrendline: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ScatterSer_SetTrendline, this.trendline, pr));
        this.trendline = pr;
    },
    setTx: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ScatterSer_SetTx, this.tx, pr));
        this.tx = pr;
    },
    setXVal: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ScatterSer_SetXVal, this.xVal, pr));
        this.xVal = pr;
    },
    setYVal: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ScatterSer_SetYVal, this.yVal, pr));
        this.yVal = pr;
        if(this.yVal && this.yVal.setParent)
        {
            this.yVal.setParent(this);
        }
            }
};

function CTx()
{
    this.strRef = null;
    this.val    = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CTx.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var c = new CTx();
        if(this.strRef)
        {
            c.setStrRef(this.strRef.createDuplicate());
        }
        c.setVal(this.val);
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_Tx;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setStrRef: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Tx_SetStrRef, this.strRef, pr));
        this.strRef = pr;
    },

    setVal: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_Tx_SetVal, this.strRef, pr));
        this.val = pr;
            }
};


function CStockChart()
{
    this.axId       = [];
    this.dLbls      = null;
    this.dropLines  = null;
    this.hiLowLines = null;
    this.series      = [];
    this.upDownBars = null;
    this.parent = null;

    this.m_oAxIdContentChanges = new AscCommon.CContentChanges();
    this.m_oSeriesContentChanges =  new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CStockChart.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_StockChart_AddAxId:{
                return this.m_oAxIdContentChanges;
            }
            case AscDFH.historyitem_StockChart_AddSer:
            case AscDFH.historyitem_CommonChart_RemoveSeries:{
                return this.m_oSeriesContentChanges;
            }
        }
        return null;
    },

    getDefaultDataLabelsPosition: function()
    {
        return c_oAscChartDataLabelsPos.r;
    },

    setFromOtherChart: function(c)
    {
        var i;
        //if(Array.isArray(c.axId))
        //{
        //    for(i = 0; i < c.axId.length; ++i)
        //    {
        //        this.addAxId(c.axId[i]);
        //    }
        //}
        if(c.dLbls)
            this.setDLbls(c.dLbls);

        if(c.dropLines)
            this.setDropLines(c.dropLines);

        if(c.hiLowLines)
            this.setHiLowLines(c.hiLowLines);


        if(Array.isArray(c.series))
        {
            for(i = 0; i < c.series.length; ++i)
            {
                var ser = new CLineSeries();
                ser.setFromOtherSeries(c.series[i]);
                ser.setMarker(new CMarker());
                ser.setSpPr(new AscFormat.CSpPr());
                ser.spPr.setLn(new AscFormat.CLn());
                ser.spPr.ln.setW(28575);
                ser.spPr.ln.setFill(AscFormat.CreateNoFillUniFill());
                ser.marker.setSymbol(SYMBOL_NONE);
                ser.setSmooth(false);
                this.addSer(ser);
            }
        }
        if(c.upDownBars)
        {
            this.setUpDownBars(c.upDownBars);
        }
    },

    Refresh_RecalcData: function()
    {
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateType();
        }
    },
    removeSeries: function(idx)
    {
        if(this.series[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonChart_RemoveSeries, idx, this.series.splice(idx, 1), false));
        }
    },

    getSeriesConstructor: function()
    {
        return new CLineSeries();
    },
    createDuplicate: function()
    {
        var c = new CStockChart();
        if(this.dLbls)
        {
            c.setDLbls(this.dLbls.createDuplicate());
        }
        if(this.dropLines)
        {
            c.setDropLines(this.dropLines.createDuplicate());
        }
        if(this.hiLowLines)
        {
            c.setHiLowLines(this.hiLowLines.createDuplicate());
        }
        for(var i = 0; i < this.series.length; ++i)
        {
            c.addSer(this.series[i].createDuplicate());
        }
        if(this.upDownBars)
        {
            c.setUpDownBars(this.upDownBars.createDuplicate());
        }
        return c;
    },

    getObjectType: function()
    {
        return  AscDFH.historyitem_type_StockChart;
    },

    documentCreateFontMap: CBarChart.prototype.documentCreateFontMap,

    getAllRasterImages: CBarChart.prototype.getAllRasterImages,
    checkSpPrRasterImages: CBarChart.prototype.checkSpPrRasterImages,

    removeDataLabels: CBarChart.prototype.removeDataLabels,

    getAxisByTypes: CPlotArea.prototype.getAxisByTypes,

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    addAxId: function(pr)
    {
        if(!pr)
            return;
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_StockChart_AddAxId, this.axId.length, [pr], true));
        this.axId.push(pr);
    },

    setDLbls: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_StockChart_SetDLbls, this.dLbls, pr));
        this.dLbls = pr;
        if(this.dLbls)
        {
            this.dLbls.setParent(this);
        }
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateDataLabels();
        }
    },

    setDropLines: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_StockChart_SetDropLines, this.dropLines, pr));
        this.dropLines = pr;
    },
    setHiLowLines: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_StockChart_SetHiLowLines, this.hiLowLines, pr));
        this.hiLowLines = pr;
    },
    addSer: function(ser)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_StockChart_AddSer, this.series.length, [ser], true));
        this.series.push(ser);
        ser.setParent(this);
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateType();
        }
    },
    setUpDownBars: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_StockChart_SetUpDownBars, this.upDownBars, pr));
        this.upDownBars = pr;
        if(pr && pr.setParent)
        {
            pr.setParent(this);
        }
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};


function CStrCache()
{
    this.pts      = [];
    this.ptCount = null;

    this.m_oPtsContentChanges = new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CStrCache.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_CommonLit_RemoveDPt:
            case AscDFH.historyitem_StrCache_AddPt:{
                return this.m_oPtsContentChanges;
            }
        }
        return null;
    },

    Refresh_RecalcData: function()
    {},

    removeDPt: function(idx)
    {
        if(this.pts[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonLit_RemoveDPt, idx, this.pts.splice(idx, 1), false));
        }
    },

    createDuplicate: function()
    {
        var c = new CStrCache();
        for(var i = 0; i < this.pts.length; ++i)
        {
            c.addPt(this.pts[i].createDuplicate());
        }
        c.setPtCount(this.ptCount);
        return c;
    },

    getPtByIndex: function(idx)
    {
        for(var i = 0; i < this.pts.length; ++i)
        {
            if(this.pts[i].idx === idx)
                return this.pts[i];
        }
        return null;
    },

    getPtCount: function()
    {
        if(AscFormat.isRealNumber(this.ptCount))
        {
            return this.ptCount;
        }
        return this.pts.length;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_StrCache;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    addPt: function(pr)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_StrCache_AddPt, this.pts.length, [pr], true));
        this.pts.push(pr);
    },

    setPtCount: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_StrCache_SetPtCount, this.ptCount, pr));
        this.ptCount = pr;
                    }
};



function CStringLiteral()
{
    this.pts      = [];
    this.ptCount = null;

    this.m_oPtsContentChanges = new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CStringLiteral.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_StringLiteral_SetPt:{
                return this.m_oPtsContentChanges;
            }
        }
        return null;
    },

    createDuplicate: function()
    {
        var c = new CStringLiteral();
        for(var i = 0; i < this.pts.length; ++i)
        {
            c.addPt(this.pts[i].createDuplicate());
        }
        c.setPtCount(this.ptCount);
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_StringLiteral;
    },


    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },


    addPt: function(pr){
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_StringLiteral_SetPt, this.pts.length, [pr], true));
        this.pts.push(pr);
    },

    setPtCount: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_StringLiteral_SetPtCount, this.ptCount, pr));
        this.ptCount = pr;
            }
};


function CStringPoint()
{
    this.idx = null;
    this.val = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CStringPoint.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var c = new CStringPoint();
        c.setIdx(this.idx);
        c.setVal(this.val);
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_StrPoint;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setIdx: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_StrPoint_SetIdx, this.idx, pr));
        this.idx = pr;
    },

    setVal: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_StrPoint_SetVal, this.val, pr));
        this.val = pr;
            }
};


function CStrRef()
{
    this.f        = null;
    this.strCache = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CStrRef.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var c = new CStrRef();
        c.setF(this.f);
        if(this.strCache)
        {
            c.setStrCache(this.strCache.createDuplicate());
        }
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_StrRef;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setF: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_StrRef_SetF, this.f, pr));
        this.f = pr;
    },

    setStrCache: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_StrRef_SetStrCache, this.strCache, pr));
        this.strCache = pr;
            }
};


function CSurfaceChart()
{
    this.axId = [];
    this.bandFmts = [];
    this.series = [];
    this.wireframe = null;

    this.parent = null;

    this.compiledBandFormats = [];

    this.m_oAxIdContentChanges = new AscCommon.CContentChanges();
    this.m_oSeriesContentChanges =  new AscCommon.CContentChanges();
    this.m_oBandFormatsContentChanges = new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CSurfaceChart.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function(data)
    {
        if(!isRealObject(data))
            return;
        switch (data.Type)
        {
            case AscDFH.historyitem_CommonChartFormat_SetParent:
            {
                break;
            }
            case AscDFH.historyitem_CommonChart_RemoveSeries:
            {
                break;
            }
            case AscDFH.historyitem_SurfaceChart_AddAxId:
            {
                break;
            }
            case AscDFH.historyitem_SurfaceChart_AddBandFmt:
            {
                break;
            }
            case AscDFH.historyitem_SurfaceChart_AddSer:
            {
                if(this.parent && this.parent.parent && this.parent.parent.parent)
                {
                    this.parent.parent.parent.handleUpdateType();
                }
                break;
            }
            case AscDFH.historyitem_SurfaceChart_SetWireframe:
            {
                break;
            }
        }
    },


    isWireframe: function(){
        return this.wireframe === true;
    },

    getBandFmtByIndex: function(idx){
        for(var i = 0; i < this.bandFmts.length; ++i){
            if(this.bandFmts[i].idx === idx){
                return this.bandFmts[i];
            }
        }
        return null;
    },

    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_SurfaceChart_AddAxId:{
                return this.m_oAxIdContentChanges;
            }
            case AscDFH.historyitem_SurfaceChart_AddSer:
            case AscDFH.historyitem_CommonChart_RemoveSeries:{
                return this.m_oSeriesContentChanges;
            }
            case AscDFH.historyitem_SurfaceChart_AddBandFmt:{
                return this.m_oBandFormatsContentChanges;
            }
        }
        return null;
    },

    removeSeries: function(idx)
    {
        if(this.series[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonChart_RemoveSeries, idx, this.series.splice(idx, 1), false));
        }
    },

    getSeriesConstructor: function()
    {
        return new CSurfaceSeries();
    },

    getDefaultDataLabelsPosition: function()
    {
        return c_oAscChartDataLabelsPos.ctr;
    },

    createDuplicate: function()
    {
        var c = new CSurfaceChart(), i;
        for(i = 0; i < this.bandFmts.length; ++i)
        {
            c.addBandFmt(this.bandFmts[i].createDuplicate());
        }
        for(i =0 ; i < this.series.length; ++i)
        {
            c.addSer(this.series[i].createDuplicate());
        }
        c.setWireframe(this.wireframe);
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_SurfaceChart;
    },


    documentCreateFontMap: CBarChart.prototype.documentCreateFontMap,

    removeDataLabels: CBarChart.prototype.removeDataLabels,

    getAxisByTypes: CPlotArea.prototype.getAxisByTypes,


    getAllRasterImages: function(images)
    {
        CBarChart.prototype.getAllRasterImages.call(this, images);
        for(var i = 0; i < this.bandFmts.length; ++i)
        {
            this.bandFmts[i] && this.bandFmts[i].spPr && this.bandFmts[i].spPr.checkBlipFillRasterImage(images);
        }
    },

    checkSpPrRasterImages: function(images)
    {
        CBarChart.prototype.checkSpPrRasterImages.call(this, images);
        for(var i = 0; i < this.bandFmts.length; ++i)
        {
            this.bandFmts[i] && checkSpPrRasterImages(this.bandFmts[i].spPr);
        }
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    addAxId: function(pr)
    {
        if(!pr)
            return;
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_SurfaceChart_AddAxId, this.axId.length, [pr], true));
        this.axId.push(pr);
    },

    addBandFmt: function(fmt)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_SurfaceChart_AddBandFmt, this.bandFmts.length, [fmt], true));
        this.bandFmts.push(fmt);
    },

    addSer: function(ser)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_SurfaceChart_AddSer, this.series.length, [ser], true));
        this.series.push(ser);
        ser.setParent(this);
        if(this.parent && this.parent.parent && this.parent.parent.parent)
        {
            this.parent.parent.parent.handleUpdateType();
        }
    },

    setWireframe: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_SurfaceChart_SetWireframe, this.wireframe, pr));
        this.wireframe = pr;
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }
};



function CSurfaceSeries()
{
    this.cat   = null;
    this.idx   = null;
    this.order = null;
    this.spPr  = null;
    this.tx    = null;
    this.val   = null;

    this.parent = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CSurfaceSeries.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },


    Refresh_RecalcData: function()
    {},

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
    },

    removeDPt: function(idx)
    {
        if(this.dPt[idx])
        {
            History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_CommonSeries_RemoveDPt, idx, this.dPt.splice(idx, 1), false));
        }
    },

    createDuplicate: function()
    {
        var c = new CSurfaceSeries();
        if(this.cat)
        {
            c.setCat(this.cat.createDuplicate());
        }
        c.setIdx(this.idx);
        c.setOrder(this.order);
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        if(this.tx)
        {
            c.setTx(this.tx.createDuplicate());
        }

        if(this.val)
        {
            c.setVal(this.val.createDuplicate());
        }
        return c;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_SurfaceSeries;
    },

    documentCreateFontMap: CAreaSeries.prototype.documentCreateFontMap,


    getAllRasterImages: CAreaSeries.prototype.getAllRasterImages,
    checkSpPrRasterImages: CAreaSeries.prototype.checkSpPrRasterImages,


    setFromOtherSeries: function(o)
    {
        if(o.cat)
            this.setCat(o.cat);
        if(AscFormat.isRealNumber(o.idx))
            this.setIdx(o.idx);
        if(o.order)
            this.setOrder(o.order);
        if(o.spPr)
            this.setSpPr(o.spPr);
        if(o.tx)
            this.setTx(o.tx);
        if(o.val)
            this.setVal(o.val);
        if(o.xVal)
        {
            this.setCat(new CCat());
            this.cat.setFromOtherObject(o.xVal);
        }
        if(o.yVal)
        {
            this.setVal(new CYVal());
            this.val.setFromOtherObject(o.yVal);
        }
    },

    getSeriesName: CAreaSeries.prototype.getSeriesName,
    getCatName: CAreaSeries.prototype.getCatName,
    getValByIndex: CAreaSeries.prototype.getValByIndex,
    getFormatCode: CAreaSeries.prototype.getFormatCode,

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setCat: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_SurfaceSeries_SetCat, this.cat, pr));
        this.cat = pr;
    },
    setIdx: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_SurfaceSeries_SetIdx, this.idx, pr));
        this.idx = pr;
    },
    setOrder: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_SurfaceSeries_SetOrder, this.order, pr));
        this.order = pr;
    },
    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_SurfaceSeries_SetSpPr, this.spPr, pr));
        this.spPr = pr;
    },
    setTx: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_SurfaceSeries_SetTx, this.tx, pr));
        this.tx = pr;
    },
    setVal: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_SurfaceSeries_SetVal, this.val, pr));
        this.val = pr;
        if(this.val && this.val.setParent)
        {
            this.val.setParent(this);
        }
    }
};


function CTitle()
{
    this.layout  = null;
    this.overlay = false;
    this.spPr    = null;
    this.tx      = null;
    this.txPr    = null;

    this.parent = null;//ссылка на родительский элемент
    //расчетные значения
    this.txBody = null;
    this.x = null;
    this.y = null;
    this.calcX = null;
    this.calcY = null;
    this.extX = null;
    this.extY = null;

    this.transform = new CMatrix();
    this.transformText = new CMatrix();
    this.ownTransform = new CMatrix();
    this.ownTransformText = new CMatrix();
    this.localTransform = new CMatrix();
    this.localTransformText = new CMatrix();

    this.recalcInfo =
    {
        recalculateTxBody: true,
        recalcTransform: true,
        recalcTransformText: true,
        recalcContent: true,
        recalculateBrush: true,
        recalculatePen: true,
        recalcStyle: true,
        recalculateContent: true,
        recalculateGeometry: true
    };



    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CTitle.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {
        this.Refresh_RecalcData2();
    },

    chekBodyPrTransform: function()
    {
        return false;
    },

    checkContentWordArt: function()
    {
        return false;
    },


    Get_AbsolutePage: function()
    {
        if(this.chart && this.chart.Get_AbsolutePage)
        {
            return this.chart.Get_AbsolutePage();
        }
        return 0;
    },

    Refresh_RecalcData2: function(pageIndex)
    {
        this.recalcInfo.recalculateTxBody = true;
        this.recalcInfo.recalcTransform = true;
        this.recalcInfo.recalcTransformText = true;
        this.recalcInfo.recalcContent = true;
        this.recalcInfo.recalculateContent = true;
        this.recalcInfo.recalculateGeometry = true;

        this.parent && this.parent.Refresh_RecalcData2 && this.parent.Refresh_RecalcData2(pageIndex, this);
    },

    checkAfterChangeTheme: function()
    {
        this.recalcInfo.recalculateTxBody = true;
        this.recalcInfo.recalcTransform = true;
        this.recalcInfo.recalcTransformText = true;
        this.recalcInfo.recalcContent = true;
        this.recalcInfo.recalculateContent = true;
        this.recalcInfo.recalculateGeometry = true;
        if(this.tx && this.tx.rich && this.tx.rich.content)
        {
            this.tx.rich.content.Recalc_AllParagraphs_CompiledPr();
        }
    },

    GetRevisionsChangeParagraph: function(SearchEngine){
        var oContent = this.getDocContent();
        if(oContent){
            oContent.GetRevisionsChangeParagraph(SearchEngine);
        }
    },

    Search : function(Str, Props, SearchEngine, Type)
    {
        var content = this.getDocContent();
        if(content && this.tx && this.tx.rich)
        {
            var dd = this.getDrawingDocument();
            dd.StartSearchTransform && dd.StartSearchTransform( this.transformText);
            content.Search(Str, Props, SearchEngine, Type);
            dd.EndSearchTransform && dd.EndSearchTransform();
        }
    },


    Search_GetId : function(bNext, bCurrent)
    {
        var content = this.getDocContent();
        if(content && this.tx && this.tx.rich)
        {
            return content.Search_GetId(bNext, bCurrent);
        }
        return null;
    },

    Set_CurrentElement: function(bUpdate, pageIndex)
    {

        var chart = this.chart, controller;
        if(chart && typeof editor !== "undefined" && editor && editor.WordControl && editor.WordControl.m_oLogicDocument)
        {
            var bDocument = false, bPresentation = false, drawing_objects;
            if(editor.WordControl.m_oLogicDocument instanceof CDocument)
            {
                bDocument = true;
                drawing_objects = editor.WordControl.m_oLogicDocument.DrawingObjects;
            }
            else if(editor.WordControl.m_oLogicDocument instanceof CPresentation)
            {
                bPresentation = true;
                if(chart.parent)
                {
                    drawing_objects = chart.parent.graphicObject;
                }
            }
            if(drawing_objects)
            {
                drawing_objects.resetSelection(true);
                var para_drawing;
                if(chart.group)
                {
                    var main_group = chart.group.getMainGroup();
                    drawing_objects.selectObject(main_group, pageIndex);
                    main_group.selectObject(chart, pageIndex);
                    main_group.selection.chartSelection = chart;

                    chart.selection.textSelection = this;
                    chart.selection.title = this;
                    drawing_objects.selection.groupSelection = main_group;
                    para_drawing = main_group.parent;
                }
                else
                {
                    drawing_objects.selectObject(chart, pageIndex);
                    drawing_objects.selection.chartSelection = chart;
                    chart.selection.textSelection = this;
                    chart.selection.title = this;
                    para_drawing = chart.parent;
                }
                if(bDocument && para_drawing instanceof ParaDrawing)
                {

                    var hdr_ftr = para_drawing.DocumentContent.IsHdrFtr(true);
                    if(hdr_ftr)
                    {
                        hdr_ftr.Content.Set_DocPosType(docpostype_DrawingObjects);
                        hdr_ftr.Set_CurrentElement(bUpdate);
                    }
                    else
                    {
                        drawing_objects.document.Set_DocPosType(docpostype_DrawingObjects);
                    }
                }
            }

        }
    },

    createDuplicate: function()
    {
        var c = new CTitle();
        if(this.layout)
        {
            c.setLayout(this.layout.createDuplicate());
        }
        c.setOverlay(this.overlay);
        if(this.spPr)
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        if(this.tx)
        {
            c.setTx(this.tx.createDuplicate());
        }
        if(this.txPr)
        {
            c.setTxPr(this.txPr.createDuplicate());
        }
        return c;
    },

    getObjectType: function()
    {
        return  AscDFH.historyitem_type_Title;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    paragraphAdd: function(paraItem, bRecalculate)
    {
        var content = this.getDocContent();
        if(content)
        {
            content.AddToParagraph(paraItem, bRecalculate);
        }
    },

    applyTextFunction: function(docContentFunction, tableFunction, args)
    {
        var content = this.getDocContent();
        if(content)
        {
            docContentFunction.apply(content, args);
        }
    },

    setPosition: CDLbl.prototype.setPosition,


    hitInPath: CShape.prototype.hitInPath,

    hitInInnerArea: CShape.prototype.hitInInnerArea,

    hitInBoundingRect:  CShape.prototype.hitInBoundingRect,

    hitInTextRect: CShape.prototype.hitInTextRect,
    recalculateGeometry: CShape.prototype.recalculateGeometry,
    getTransform : CShape.prototype.getTransform ,

    checkHitToBounds: function(x, y)
    {
        var _x = x - this.transform.tx;
        var _y = y - this.transform.ty;
        return _x >= 0 && _x <= this.extX && _y >= 0 && _y < this.extY;
    },

    checkDocContent: function()
    {
        if(this.tx && this.tx.rich && this.tx.rich.content)
        {
            return;
        }
        else if(this.txBody && this.txBody.content)
        {
            var StartPage = this.txBody.content.StartPage;
            if(!this.tx)
            {
                this.setTx(new CChartText());
            }
            this.tx.setRich(this.txBody.createDuplicate2());
            this.tx.rich.setParent(this);
            if(this.txPr && this.txPr.content && this.txPr.content.Content[0] && this.txPr.content.Content[0].Pr.DefaultRunPr)
            {
                for(var i = 0; i < this.tx.rich.content.Content.length; ++i)
                {
                    AscFormat.CheckParagraphTextPr(this.tx.rich.content.Content[i], this.txPr.content.Content[0].Pr.DefaultRunPr);
                }
            }
            var selection_state = this.txBody.content.GetSelectionState();
            this.txBody = this.tx.rich;
            this.txBody.content.SetSelectionState(selection_state, selection_state.length - 1);
            if(AscFormat.isRealNumber(StartPage))
            {
                this.txBody.content.Set_StartPage(StartPage);
            }
            //if(editor && editor.isDocumentEditor)
            //{
            //    this.recalculateContent();
            //}
        }
    },

    getDocContent: function()
    {
        if(this.recalcInfo.recalculateTxBody){
            AscFormat.ExecuteNoHistory(this.recalculateTxBody, this, []);
            this.recalcInfo.recalculateTxBody = false;
        }
        if(this.txBody && this.txBody.content)
        {
            return this.txBody.content;
        }
    },

    selectionSetStart: CShape.prototype.selectionSetStart,

    selectionSetEnd: CShape.prototype.selectionSetEnd,

    select: function(chartSpace, pageIndex)
    {
        this.selected = true;
        this.selectStartPage = pageIndex;
        var content = this.getDocContent && this.getDocContent();
        if(content)
            content.Set_StartPage(pageIndex);
        chartSpace.selection.title = this;
    },

    getMaxWidth: function(bodyPr)
    {
        switch (bodyPr.vert)
        {
            case AscFormat.nVertTTeaVert:
            case AscFormat.nVertTTmongolianVert:
            case AscFormat.nVertTTvert:
            case AscFormat.nVertTTwordArtVert:
            case AscFormat.nVertTTwordArtVertRtl:
            case AscFormat.nVertTTvert270:
            {
                var vert_axis = this.chart.chart.plotArea.getVerticalAxis();
                if( vert_axis  && vert_axis.title === this)
                {
                    var hor_axis = this.chart.chart.plotArea.getHorizontalAxis();
                    return this.chart.extY - (hor_axis && hor_axis.title ? hor_axis.title.extY : 0 )
                }
                return this.chart.extY/2;
            }
            case AscFormat.nVertTThorz:
            {
                return this.chart.extX*0.8;
            }
        }
        return this.chart.extX*0.5;
    },

    Is_UseInDocument: function()
    {
        if(this.parent && this.parent.title === this &&
            this.chart && this.chart.Is_UseInDocument)
        {
            return this.chart.Is_UseInDocument();
        }
        return false;
    },


    Check_AutoFit: function(){
        return true;
    },
    getBodyPr: CDLbl.prototype.getBodyPr,

    getCompiledStyle: CDLbl.prototype.getCompiledStyle,

    getCompiledFill: CDLbl.prototype.getCompiledFill,

    getCompiledLine: CDLbl.prototype.getCompiledLine,
    getCompiledTransparent: CDLbl.prototype.getCompiledTransparent,
    Get_Styles: CDLbl.prototype.Get_Styles,
    check_bounds: CShape.prototype.check_bounds,
    selectionCheck: CShape.prototype.selectionCheck,
    getInvertTransform: CShape.prototype.getInvertTransform,
    getCanvasContext: function()
    {
        return this.chart && this.chart.getCanvasContext();
    },
    convertPixToMM: function(pix)
    {
        return this.chart && this.chart.convertPixToMM(pix);
    },
    getDrawingDocument: function()
    {
        if(this.chart && this.chart.getDrawingDocument)
            return this.chart && this.chart.getDrawingDocument();
        return this.parent && this.parent.getDrawingDocument && this.parent.getDrawingDocument();
    },
    draw: function(graphics)
    {
        CDLbl.prototype.draw.call(this, graphics);
    },

    isEmptyPlaceholder: CDLbl.prototype.isEmptyPlaceholder,

    recalculatePen: CShape.prototype.recalculatePen,

    recalculateBrush: CShape.prototype.recalculateBrush,

    updateSelectionState: CShape.prototype.updateSelectionState,

    checkShapeChildTransform: CDLbl.prototype.checkShapeChildTransform,

    updatePosition: function(x, y)
    {
        this.posX = x;
        this.posY = y;
        this.transform = this.localTransform.CreateDublicate();
        global_MatrixTransformer.TranslateAppend(this.transform, x, y);

        this.transformText = this.localTransformText.CreateDublicate();
        global_MatrixTransformer.TranslateAppend(this.transformText, x, y);

        this.invertTransform = global_MatrixTransformer.Invert(this.transform);
        this.invertTransformText = global_MatrixTransformer.Invert(this.transformText);

    },

    getParentObjects: function()
    {
        if(this.chart)
        {
            return this.chart.getParentObjects();
        }
        else if(this.parent)
        {
            return this.parent.getParentObjects();
        }
        return null;
    },

    getDefaultTextForTxBody: function()
    {
        var oStrCache = AscFormat.getStringPointsFromCat(this.tx);
        if(oStrCache){
            var oPoint = oStrCache.getPtByIndex(0);
            if(oPoint && oPoint.val){
                return oPoint.val;
            }
        }
        var key = 'Axis Title';
        if(this.parent)
        {
            if(this.parent.getObjectType() === AscDFH.historyitem_type_Chart)
            {
                if(this.parent.plotArea && this.parent.plotArea.charts.length === 1 && Array.isArray(this.parent.plotArea.charts[0].series)
                    && this.parent.plotArea.charts[0].series.length === 1 && this.parent.plotArea.charts[0].series[0].tx)
                {
                    var oTx = this.parent.plotArea.charts[0].series[0].tx;
                    if(typeof oTx.val === "string" && oTx.val.length > 0)
                    {
                        return oTx.val;
                    }
                    if(oTx.strRef && oTx.strRef.strCache && oTx.strRef.strCache.pts.length === 1 && isRealObject(oTx.strRef.strCache.pts[0]) && typeof oTx.strRef.strCache.pts[0].val === "string"
                        && oTx.strRef.strCache.pts[0].val.length > 0)
                    {
                        return oTx.strRef.strCache.pts[0].val;
                    }
                }
				key = 'Diagram Title';
            }
            else
            {
                if(this.parent.axPos === AX_POS_B || this.parent.axPos === AX_POS_T)
                {
                    key = 'X Axis';
                }
                else
                {
					key = 'Y Axis';
                }
            }
        }
		return AscCommon.translateManager.getValue(key);
    },

    getStyles: CDLbl.prototype.getStyles,

    Get_Theme: CDLbl.prototype.Get_Theme,

    Get_ColorMap: CDLbl.prototype.Get_ColorMap,

    recalculateStyle: CDLbl.prototype.recalculateStyle,

    recalculateTxBody: CDLbl.prototype.recalculateTxBody,

    recalculateTransform: CDLbl.prototype.recalculateTransform,

    recalculateTransformText: CDLbl.prototype.recalculateTransformText,

    recalculateContent: CDLbl.prototype.recalculateContent,

    recalculate: function()
    {
        AscFormat.ExecuteNoHistory(function()
        {
            if(this.recalcInfo.recalculateBrush)
            {
                this.recalculateBrush();
                this.recalcInfo.recalculateBrush = false;
            }
            if(this.recalcInfo.recalculatePen)
            {
                this.recalculatePen();
                this.recalcInfo.recalculatePen = false;
            }
            if(this.recalcInfo.recalcStyle)
            {
                this.recalculateStyle();
                this.recalcInfo.recalcStyle = false;
            }
            if(this.recalcInfo.recalculateTxBody)
            {
                this.recalculateTxBody();
                this.recalcInfo.recalculateTxBody = false;
            }
            if(this.recalcInfo.recalculateContent)
            {
                this.recalculateContent();
                this.recalcInfo.recalculateContent = false;
            }
            if(this.recalcInfo.recalcTransform)
            {
                this.recalculateTransform();
                this.recalcInfo.recalcTransform = false;
            }
            if(this.recalcInfo.recalculateGeometry)
            {
                this.recalculateGeometry && this.recalculateGeometry();
                this.recalcInfo.recalculateGeometry = false;
            }
            if(this.recalcInfo.recalcTransformText)
            {
                this.recalculateTransformText();
                this.recalcInfo.recalcTransformText = false;
            }
            if(this.chart)
            {
                this.chart.addToSetPosition(this);
            }
        }, this, []);
    },

    setLayout: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Title_SetLayout, this.layout, pr));
        this.layout = pr;
    },

    setOverlay: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_Title_SetOverlay, this.overlay, pr));
        this.overlay = pr;
    },

    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Title_SetSpPr, this.spPr, pr));
        this.spPr = pr;
    },

    setTx: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Title_SetTx, this.tx, pr));
        this.tx = pr;
        if(this.tx)
        {
            this.tx.setParent(this);
        }
    },

    setTxPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Title_SetTxPr, this.txPr, pr));
        this.txPr = pr;
        if(this.txPr)
        {
            this.txPr.setParent(this);
        }
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
    }
};

function CTrendLine()
{
    this.backward       = null;
    this.dispEq         = null;
    this.dispRSqr       = null;
    this.forward        = null;
    this.intercept      = null;
    this.name           = null;
    this.order          = null;
    this.period         = null;
    this.spPr           = null;
    this.trendlineLbl   = null;
    this.trendlineType  = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CTrendLine.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_TrendLine;
    },

    setBackward: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Trendline_SetBackward, this.backward, pr));
        this.backward = pr;
    },

    setDispEq: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_Trendline_SetDispEq, this.dispEq, pr));
        this.dispEq = pr;
    },

    setDispRSqr: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_Trendline_SetDispRSqr, this.dispRSqr, pr));
        this.dispRSqr = pr;
    },

    setForward: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Trendline_SetForward, this.forward, pr));
        this.forward = pr;
    },

    setIntercept: function(pr)
    {
        History.Add(new CChangesDrawingsDouble(this, AscDFH.historyitem_Trendline_SetIntercept, this.intercept, pr));
        this.intercept = pr;
    },

    setName: function(pr)
    {
        History.Add(new CChangesDrawingsString(this, AscDFH.historyitem_Trendline_SetName, this.name, pr));
        this.name = pr;
    },

    setOrder: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_Trendline_SetOrder, this.order, pr));
        this.order = pr;
    },

    setPeriod: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_Trendline_SetPeriod, this.period, pr));
        this.period = pr;
    },

    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Trendline_SetSpPr, this.spPr, pr));
        this.spPr = pr;
    },

    setTrendlineLbl: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Trendline_SetTrendlineLbl, this.trendlineLbl, pr));
        this.trendlineLbl = pr;
    },

    setTrendlineType: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_Trendline_SetTrendlineType, this.trendlineType, pr));
        this.trendlineType = pr;
    },

    createDuplicate: function()
    {
        var c = new CTrendLine();

        if(AscFormat.isRealNumber(this.backward))
        {
            c.setBackward(this.backward);
        }
        if(AscFormat.isRealBool(this.dispEq))
        {
            c.setDispEq(this.dispEq);
        }
        if(AscFormat.isRealBool(this.dispRSqr))
        {
            c.setDispRSqr(this.dispRSqr);
        }
        if(AscFormat.isRealNumber(this.forward))
        {
            c.setForward(this.forward);
        }
        if(AscFormat.isRealNumber(this.intercept))
        {
            c.setIntercept(this.intercept);
        }
        if(typeof this.name === "string")
        {
            c.setName(this.name);
        }
        if(AscFormat.isRealNumber(this.order))
        {
            c.setOrder(this.order);
        }
        if(AscFormat.isRealNumber(this.period))
        {
            c.setPeriod(this.period);
        }
        if(isRealObject(this.spPr))
        {
            c.setSpPr(this.spPr.createDuplicate());
        }
        //this.trendlineLbl   = null;

        if(AscFormat.isRealNumber(this.trendlineType))
        {
            c.setTrendlineType(this.trendlineType);
        }
        return c;
    },


    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
            }
};



function CUpDownBars()
{
    this.downBars = null;
    this.gapWidth = null;
    this.upBars   = null;
    this.parent   = null;
    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CUpDownBars.prototype =
{

    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {
        if(this.parent){
            this.parent.Refresh_RecalcData && this.parent.Refresh_RecalcData();
        }
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_UpDownBars;
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
    },

    setDownBars: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_UpDownBars_SetDownBars, this.downBars, pr));
        this.downBars = pr;
        if(this.downBars){
            this.downBars.setParent(this);
        }
    },

    setGapWidth: function(pr)
    {

        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_UpDownBars_SetGapWidth, this.downBars, pr));
        this.gapWidth = pr;
    },

    setUpBars: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_UpDownBars_SetUpBars, this.downBars, pr));
        this.upBars = pr;

        if(this.upBars){
            this.upBars.setParent(this);
        }
    },


    handleUpdateFill: function()
    {
        this.Refresh_RecalcData();
    },

    handleUpdateLn: function()
    {
        this.Refresh_RecalcData();
    },

    createDuplicate: function()
    {
        var c = new CUpDownBars();
        if(AscFormat.isRealNumber(this.gapWidth))
        {
            c.setGapWidth(this.gapWidth);
        }
        if(isRealObject(this.upBars))
        {
            c.setUpBars(this.upBars.createDuplicate());
        }
        if(isRealObject(this.downBars))
        {
            c.setDownBars(this.downBars.createDuplicate());
        }
        return c;
    },


    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
            }
};


function CXVal()
{
    this.multiLvlStrRef = null;
    this.numLit         = null;
    this.numRef         = null;
    this.strLit         = null;
    this.strRef         = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CXVal.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_XVal;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id());
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    createDuplicate: function()
    {
        var ret = new CXVal();
        if(this.multiLvlStrRef)
        {
            ret.setMultiLvlStrRef(this.multiLvlStrRef.createDuplicate());
        }
        if(this.numLit)
        {
            ret.setNumLit(this.numLit.createDuplicate());
        }
        if(this.numRef)
        {
            ret.setNumRef(this.numRef.createDuplicate());
        }
        if(this.strRef)
        {
            ret.setStrRef(this.strRef.createDuplicate());
        }
        if(this.strLit)
        {
            ret.setStrLit(this.strLit.createDuplicate());
        }
        return ret;
    },

    setFromOtherObject: function(o)
    {
        if(o.multiLvlStrRef)
            this.setMultiLvlStrRef(o.multiLvlStrRef);
        if(o.numLit)
            this.setNumLit(o.numLit);
        if(o.numRef)
            this.setNumRef(o.numRef);
        if(o.strLit)
            this.setStrLit(o.strLit);
        if(o.strRef)
            this.setStrRef(o.strRef);
    },

    setMultiLvlStrRef: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_XVal_SetMultiLvlStrRef, this.multiLvlStrRef, pr));
        this.multiLvlStrRef = pr;
    },

    setNumLit: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_XVal_SetNumLit, this.numLit, pr));
        this.numLit = pr;
    },

    setNumRef: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_XVal_SetNumRef, this.numRef, pr));
        this.numRef = pr;
    },

    setStrLit: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_XVal_SetStrLit, this.strLit, pr));
        this.strLit = pr;
    },

    setStrRef: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_XVal_SetStrRef, this.strRef, pr));
        this.strRef = pr;
            }
};



function CYVal()
{
    this.numLit = null;
    this.numRef = null;

    this.parent = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CYVal.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    createDuplicate: function()
    {
        var copy = new CYVal();
        if(this.numLit)
        {
            copy.setNumLit(this.numLit.createDuplicate());
        }
        if(this.numRef)
        {
            copy.setNumRef(this.numRef.createDuplicate());
        }
        
        return copy;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_YVal;
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
    },

    setFromOtherObject: function(o)
    {
        if(o.numLit)
            this.setNumLit(o.numLit);
        if(o.numRef)
            this.setNumRef(o.numRef);
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Get_Id())
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setNumLit: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_YVal_SetNumLit, this.numLit, pr));
        this.numLit = pr;
    },

    setNumRef: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_YVal_SetNumRef, this.numRef, pr));
        this.numRef = pr;
        if(this.numRef && this.numRef.setParent)
        {
            this.numRef.setParent(this);
        }
            }
};


function CChart()
{
    this.autoTitleDeleted = null;
    this.backWall = null;
    this.dispBlanksAs = null;
    this.floor = null;
    this.legend = null;
    this.pivotFmts = [];
    this.plotArea = null;
    this.plotVisOnly = null;
    this.showDLblsOverMax = null;
    this.sideWall = null;
    this.title = null;
    this.view3D = null;

    this.parent = null;

    this.m_oPivotFmtsContentChanges = new AscCommon.CContentChanges();

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CChart.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {
        if(this.parent)
        {
            this.parent.handleUpdateInternalChart();
        }

    },

    CheckCorrect: function(){
        if(!this.plotArea){
            return false;
        }
        return true;
    },

    getContentChangesByType: function(type){
        switch(type){
            case AscDFH.historyitem_Chart_AddPivotFmt:{
                return this.m_oPivotFmtsContentChanges;
            }
        }
        return null;
    },


    getView3d: function(){
        return AscFormat.ExecuteNoHistory(function(){

            if(this.view3D){
                var _ret = this.view3D.createDuplicate();
                var oChart = this.plotArea &&  this.plotArea.charts[0];
                if(oChart){
                    if(oChart.getObjectType() === AscDFH.historyitem_type_SurfaceChart){
                        if(!AscFormat.isRealNumber(_ret.rotX)){
                            _ret.rotX = 15;
                        }
                        if(!AscFormat.isRealNumber(_ret.rotY)){
                            _ret.rotY = 20;
                        }
                    }
                    else{
                        if(!AscFormat.isRealNumber(_ret.rotX)){
                            _ret.rotX = 0;
                        }
                        if(!AscFormat.isRealNumber(_ret.rotY)){
                            _ret.rotY = 0;
                        }
                    }
                    return _ret;
                }
            }
            return null;
        }, this, []);
    },

    getObjectType: function()
    {
        return  AscDFH.historyitem_type_Chart;
    },

    getParentObjects: function()
    {
        return this.parent && this.parent.getParentObjects();
    },

    handleUpdateDataLabels: function()
    {
        if(this.parent && this.parent.handleUpdateDataLabels)
        {
            this.parent.handleUpdateDataLabels();
        }
    },

    setDefaultWalls: function()
    {
        var oFloor = new CChartWall();
        oFloor.setThickness(0);
        this.setFloor(oFloor);
        var oSideWall = new CChartWall();
        oSideWall.setThickness(0);
        this.setSideWall(oSideWall);
        var oBackWall = new CChartWall();
        oBackWall.setThickness(0);
        this.setBackWall(oBackWall);
    },

    createDuplicate: function()
    {
        var c = new CChart();
        
        c.autoTitleDeleted = this.autoTitleDeleted;
        if(this.backWall)
        {
            c.setBackWall(this.backWall.createDuplicate());
        }

        c.setDispBlanksAs(this.dispBlanksAs);

        if(this.floor)
        {
            c.setFloor(this.floor.createDuplicate());
        }

        if ( this.legend )
        {
            c.setLegend(this.legend.createDuplicate());
        }
        
        var Count = this.pivotFmts.length;
        for ( var i = 0; i < Count; i++ )
        {
            c.setPivotFmts(this.pivotFmts[i].createDuplicate());
        }
        
        if ( this.plotArea )
        {
            c.setPlotArea(this.plotArea.createDuplicate());
        }
        c.setPlotVisOnly(this.plotVisOnly);
        c.setShowDLblsOverMax(this.showDLblsOverMax);
        if(this.sideWall)
        {
            c.setSideWall(this.sideWall.createDuplicate());
        }
        
        if ( this.title )
        {
            c.setTitle(this.title.createDuplicate());
        }
        
        if ( this.view3D )
        {
            c.setView3D(this.view3D.createDuplicate());
        }

        return c;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },


    Refresh_RecalcData2: function(pageIndex, object)
    {
        this.parent && this.parent.Refresh_RecalcData2 && this.parent.Refresh_RecalcData2(pageIndex, object);
    },

    getDrawingDocument: function()
    {
        return this.parent && this.parent && this.parent.getDrawingDocument && this.parent.getDrawingDocument();
    },

    setAutoTitleDeleted: function(autoTitleDeleted)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_Chart_SetAutoTitleDeleted, this.autoTitleDeleted, autoTitleDeleted));
        this.autoTitleDeleted = autoTitleDeleted;
    },
    setBackWall: function(backWall)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Chart_SetBackWall, this.backWall, backWall));
        this.backWall = backWall;
    },
    setDispBlanksAs: function(dispBlanksAs)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_Chart_SetDispBlanksAs, this.dispBlanksAs, dispBlanksAs));
        this.dispBlanksAs = dispBlanksAs;
    },
    setFloor: function(floor)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Chart_SetFloor, this.floor, floor));
        this.floor = floor;
    },
    setLegend: function(legend)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Chart_SetLegend, this.legend, legend));
        this.legend = legend;
        if(legend)
        {
            legend.setParent(this);
        }
    },
    setPivotFmts: function(pivotFmt)
    {
        History.Add(new CChangesDrawingsContent(this, AscDFH.historyitem_Chart_AddPivotFmt, this.pivotFmts.length, [pivotFmt], true));
        this.pivotFmts.push(pivotFmt);
    },
    setPlotArea: function(plotArea)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Chart_SetPlotArea, this.plotArea, plotArea));
        this.plotArea = plotArea;
        if(plotArea)
        {
            plotArea.setParent(this);
        }
    },
    setPlotVisOnly: function(plotVisOnly)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_Chart_SetPlotVisOnly, this.plotVisOnly, plotVisOnly));
        this.plotVisOnly = plotVisOnly;
    },

    setShowDLblsOverMax: function(showDLblsOverMax)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_Chart_SetShowDLblsOverMax, this.showDLblsOverMax, showDLblsOverMax));
        this.showDLblsOverMax = showDLblsOverMax;
    },

    setSideWall: function(sideWall)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Chart_SetSideWall, this.sideWall, sideWall));
        this.sideWall = sideWall;
    },

    setTitle: function(title)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Chart_SetTitle, this.title, title));
        this.title = title;
        if(title)
        {
            title.setParent(this);
        }
        if(this.parent)
        {
            this.parent.handleUpdateInternalChart();
        }
    },

    setView3D: function(view3D)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_Chart_SetView3D, this.view3D, view3D));
        this.view3D = view3D;
        if(this.parent)
        {
            this.parent.handleUpdateInternalChart();
        }
    },

    setParent: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_CommonChartFormat_SetParent, this.parent, pr));
        this.parent = pr;
            }

};


function CChartWall()
{
    this.pictureOptions = null;
    this.spPr           = null;
    this.thickness      = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CChartWall.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_ChartWall;
    },


    createDuplicate: function()
    {
        var copy = new CChartWall();
        if(this.pictureOptions)
        {
            copy.setPictureOptions(this.pictureOptions.createDuplicate());
        }
        if(this.spPr)
        {
            copy.setSpPr(this.spPr.createDuplicate());
        }
        if(AscFormat.isRealNumber(this.thickness))
        {
            copy.setThickness(this.thickness);
        }
        return copy;

    },


    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setPictureOptions: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartWall_SetPictureOptions, this.pictureOptions, pr));
        this.pictureOptions = pr;
    },
    setSpPr: function(pr)
    {
        History.Add(new CChangesDrawingsObject(this, AscDFH.historyitem_ChartWall_SetSpPr, this.spPr, pr));
        this.spPr = pr;
    },
    setThickness: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_ChartWall_SetThickness, this.thickness, pr));
        this.thickness = pr;
            }
};

function CView3d()
{
    this.depthPercent = null;
    this.hPercent     = null;
    this.perspective  = null;
    this.rAngAx       = null;
    this.rotX         = null;
    this.rotY         = null;

    this.Id = g_oIdCounter.Get_NewId();
    g_oTableId.Add(this, this.Id);
}

CView3d.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    Refresh_RecalcData: function()
    {},

    getObjectType: function()
    {
        return AscDFH.historyitem_type_View3d;
    },

    createDuplicate: function()
    {
        var c = new CView3d();
        AscFormat.isRealNumber(this.depthPercent) && c.setDepthPercent(this.depthPercent);
        AscFormat.isRealNumber(this.hPercent) && c.setHPercent(this.hPercent);
        AscFormat.isRealNumber(this.perspective) && c.setPerspective(this.perspective);
        AscFormat.isRealBool(this.rAngAx) && c.setRAngAx(this.rAngAx);
        AscFormat.isRealNumber(this.rotX) && c.setRotX(this.rotX);
        AscFormat.isRealNumber(this.rotY) && c.setRotY(this.rotY);
        return c;
    },


    Write_ToBinary2: function(w)
    {
        w.WriteLong(this.getObjectType());
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    setDepthPercent: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_View3d_SetDepthPercent, this.depthPercent, pr));
        this.depthPercent = pr;
    },
    setHPercent: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_View3d_SetHPercent, this.hPercent, pr));
        this.hPercent = pr;
    },
    setPerspective: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_View3d_SetPerspective, this.perspective, pr));
        this.perspective = pr;
    },
    setRAngAx: function(pr)
    {
        History.Add(new CChangesDrawingsBool(this, AscDFH.historyitem_View3d_SetRAngAx, this.rAngAx, pr));
        this.rAngAx = pr;
    },

    getRAngAx: function(){

        if(AscFormat.isRealBool(this.rAngAx)){
            return this.rAngAx;
        }
        if(AscFormat.isRealNumber(this.perspective)){
            return false;
        }
        return this.rAngAx !== false;
    },

    setRotX: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_View3d_SetRotX, this.rotX, pr));
        this.rotX = pr;
    },
    setRotY: function(pr)
    {
        History.Add(new CChangesDrawingsLong(this, AscDFH.historyitem_View3d_SetRotY, this.rotY, pr));
        this.rotY = pr;
    }
};

function CreateTextBodyFromString(str, drawingDocument, parent)
{
    var tx_body = new AscFormat.CTextBody();
    tx_body.setParent(parent);
    tx_body.setBodyPr(new AscFormat.CBodyPr());
    var old_is_doc_editor = false;
    if(typeof editor !== "undefined" && editor && editor.isDocumentEditor)
    {
        editor.isDocumentEditor = false;
        old_is_doc_editor = true;
    }
    tx_body.setContent(CreateDocContentFromString(str, drawingDocument, tx_body));

    if(typeof editor !== "undefined" && editor && old_is_doc_editor)
    {
        editor.isDocumentEditor = true;
    }
    return tx_body;
}

function CreateDocContentFromString(str, drawingDocument, parent)
{
    var content = new AscFormat.CDrawingDocContent(parent, drawingDocument, 0, 0, 0, 0, false, false, true);
    AddToContentFromString(content, str);
    return content;
}


function AddToContentFromString(content, str)
{
	content.MoveCursorToStartPos(false);
	for (var oIterator = str.getUnicodeIterator(); oIterator.check(); oIterator.next())
	{
		var nCharCode = oIterator.value();

		if (9 === nCharCode) // \t
			content.AddToParagraph(new ParaTab(), false);
		if (10 === nCharCode) // \n
			content.AddToParagraph(new ParaNewLine(break_Line), false);
		else if (13 === nCharCode) // \r
			continue;
		else if (32 === nCharCode) // space
			content.AddToParagraph(new ParaSpace(), false);
		else
			content.AddToParagraph(new ParaText(nCharCode), false);
	}
}

function CValAxisLabels(chart, axis)
{
    this.x = null;
    this.y = null;
    this.extX = null;
    this.extY = null;
    this.transform = new CMatrix();
    this.localTransform = new CMatrix();
    this.aLabels = [];
    this.chart = chart;
    this.posX = null;
    this.posY = null;
    this.axis = axis;
}

CValAxisLabels.prototype =
{
    recalculateExtX: function()
    {
        var max_ext_x = 0;
        for(var i = 0; i < this.aLabels.length; ++i)
        {
            if(this.aLabels[i].extX > max_ext_x)
            {
                max_ext_x = this.aLabels[i].extX;
            }
        }
        this.extX = max_ext_x;
    },

    hit: function(x, y)
    {
        var tx, ty;
        if(this.chart && this.chart.invertTransform)
        {
            tx = this.chart.invertTransform.TransformPointX(x, y);
            ty = this.chart.invertTransform.TransformPointY(x, y);
            return tx >= this.x && ty >= this.y && tx <= this.x + this.extX && ty <= this.y + this.extY;
        }
        return false;
    },

    getMinWidth: function()
    {
        var max_min_width = this.aLabels[0].txBody.content.RecalculateMinMaxContentWidth().Min;
        for(var i = 1; i < this.aLabels.length; ++i)
        {
            var t = this.aLabels[i].txBody.content.RecalculateMinMaxContentWidth().Min;
            if(t > max_min_width)
                max_min_width = t;
        }
        return max_min_width;
    },

    draw: function(g)
    {
        if(this.chart)
        {
            //g.SetIntegerGrid(false);
            //g.p_width(70);
            //g.transform3(this.chart.transform, false);
            //g.p_color(0, 0, 0, 255);
            //g._s();
            //g._m(this.x, this.y);
            //g._l(this.x + this.extX, this.y + 0);
            //g._l(this.x + this.extX, this.y + this.extY);
            //g._l(this.x + 0, this.y + this.extY);
            //g._z();
            //g.ds();
            //g.SetIntegerGrid(true);
        }
        for(var i = 0; i < this.aLabels.length; ++i)
        {
            if(this.aLabels[i])
                this.aLabels[i].draw(g);
        }
    },

    setPosition: function(x, y)
    {
        this.x = x;
        this.y = y;
        for(var i = 0; i < this.aLabels.length; ++i)
        {
            if(this.aLabels[i])
            {
                var lbl = this.aLabels[i];
                lbl.setPosition(lbl.relPosX + x, lbl.relPosY + y);
            }
        }
    },

    updatePosition: function(x, y)
    {
        this.posX = x;
        this.posY = y;
        this.transform = this.localTransform.CreateDublicate();
        global_MatrixTransformer.TranslateAppend(this.transform, x, y);
        this.invertTransform = global_MatrixTransformer.Invert(this.transform);
        for(var i = 0; i < this.aLabels.length; ++i)
        {
            if(this.aLabels[i])
                this.aLabels[i].updatePosition(x, y);
        }
    },

    checkShapeChildTransform: function(t)
    {
        this.transform = this.localTransform.CreateDublicate();
        global_MatrixTransformer.TranslateAppend(this.transform, this.posX, this.posY);
        this.invertTransform = global_MatrixTransformer.Invert(this.transform);
        for(var i = 0; i < this.aLabels.length; ++i)
        {
            if(this.aLabels[i])
                this.aLabels[i].checkShapeChildTransform(t);
        }
    }

};


function CalcLegendEntry(legend, chart, idx)
{
    this.chart = chart;
    this.legend = legend;
    this.idx = idx;
    this.x = null;
    this.y = null;
    this.extX = null;
    this.extY = null;
    this.calcMarkerUnion = null;
    this.txBody = null;
    this.txPr = null;
    this.spPr = new AscFormat.CSpPr();
    this.transform = new CMatrix();
    this.transformText = new CMatrix();

    this.contentWidth = 0;
    this.contentHeight = 0;

    this.localTransform = new CMatrix();
    this.localTransformText = new CMatrix();

    this.localX = null;
    this.localY = null;

    this.recalcInfo =
    {
        recalcStyle: true
    };
}

CalcLegendEntry.prototype =
{
    recalculate: function()
    {
    },
    getStyles: CDLbl.prototype.getStyles,
    recalculateStyle: CDLbl.prototype.recalculateStyle,
    Get_Styles: CDLbl.prototype.Get_Styles,

    Get_Theme: CDLbl.prototype.Get_Theme,
    Get_ColorMap: CDLbl.prototype.Get_ColorMap,

    draw: function(g)
    {

        CShape.prototype.draw.call(this, g);
        if(this.calcMarkerUnion)
            this.calcMarkerUnion.draw(g);
    },

    isEmptyPlaceholder: function()
    {
        return false;
    },

    updatePosition: CShape.prototype.updatePosition,

    checkWidhtContent: function()
    {
        var par = this.txBody.content.Content[0];
        var max_width = 0;
        for(var j = 0; j < par.Lines.length; ++j)
        {
            if(par.Lines[j].Ranges[0].W  > max_width)
            {
                max_width = par.Lines[j].Ranges[0].W;
            }
        }
        this.contentWidth = max_width;
        this.contentHeight = this.txBody.getSummaryHeight();
    },

    hit: function(x, y)
    {
        var tx, ty, oGeometry;
        if(this.invertTransformText)
        {
            tx = this.invertTransformText.TransformPointX(x, y);
            ty = this.invertTransformText.TransformPointY(x, y);
            if(tx >= 0 && tx <= this.contentWidth && ty >= 0 && ty <= this.contentHeight)
            {
                return true;
            }
        }
        if(this.chart)
        {
            var oCanvasHit = this.chart.getCanvasContext();
            var calcMarkerUnion = this.calcMarkerUnion;
            if(calcMarkerUnion.marker && calcMarkerUnion.marker.invertTransform)
            {
                tx = calcMarkerUnion.marker.invertTransform.TransformPointX(x, y);
                ty = calcMarkerUnion.marker.invertTransform.TransformPointY(x, y);
                oGeometry = calcMarkerUnion.marker.spPr.geometry;
                if(oGeometry.hitInInnerArea(oCanvasHit, tx, ty) || oGeometry.hitInPath(oCanvasHit, tx, ty))
                {
                    return true;
                }
            }
            if(calcMarkerUnion.lineMarker && calcMarkerUnion.lineMarker.invertTransform)
            {
                tx = calcMarkerUnion.lineMarker.invertTransform.TransformPointX(x, y);
                ty = calcMarkerUnion.lineMarker.invertTransform.TransformPointY(x, y);
                oGeometry = calcMarkerUnion.lineMarker.spPr.geometry;
                if(oGeometry.hitInInnerArea(oCanvasHit, tx, ty) || oGeometry.hitInPath(oCanvasHit, tx, ty))
                {
                    return true;
                }
            }
        }
        return false;
    }
};


function CompiledMarker()
{
    this.spPr = new AscFormat.CSpPr();
    this.x = null;
    this.y = null;
    this.extX = null;
    this.extY = null;
    this.localX = null;
    this.localY = null;
    this.transform = new CMatrix();
    this.localTransform = new CMatrix();
    this.pen = null;
    this.brush = null;
}

CompiledMarker.prototype =
{
    draw: CShape.prototype.draw,
    check_bounds: CShape.prototype.check_bounds,


    isEmptyPlaceholder: function()
    {
        return false;
    }


};

function CUnionMarker()
{
    this.lineMarker = null;
    this.marker = null;
}

CUnionMarker.prototype =
{
    draw: function(g)
    {
        this.lineMarker && this.lineMarker.draw(g);
        this.marker && this.marker.draw(g);
    }
};

function CreateMarkerGeometryByType(type, src)
{
    var ret = new AscFormat.Geometry();
    var w = 43200, h = 43200;
    function AddRect(geom, w, h)
    {
        geom.AddPathCommand(1, "0", "0");
        geom.AddPathCommand(2, w+"", "0");
        geom.AddPathCommand(2, w+"", h+"");
        geom.AddPathCommand(2, "0", h+"");
        geom.AddPathCommand(6);
    }

    function AddPlus(geom, w, h)
    {
        geom.AddPathCommand(0,undefined, "none", undefined, w, h);
        geom.AddPathCommand(1, w/2 + "", "0");
        geom.AddPathCommand(2, w/2 + "", h + "");
        geom.AddPathCommand(1, "0", h/2+"");
        geom.AddPathCommand(2, w+"", h/2+"");
    }

    function AddX(geom, w, h)
    {
        geom.AddPathCommand(0,undefined, "none", undefined, w, h);
        geom.AddPathCommand(1, "0", "0");
        geom.AddPathCommand(2, w + "", h + "");
        geom.AddPathCommand(1, w + "", "0");
        geom.AddPathCommand(2, "0", h + "");
    }

    switch(type)
    {
        case SYMBOL_CIRCLE:
        {
            ret.AddPathCommand(0,undefined, undefined, undefined, w, h);
            ret.AddPathCommand(1, "0", h/2 + "");
            ret.AddPathCommand(3, w/2 + "", h/2 + "", "cd2", "cd4");
            ret.AddPathCommand(3, w/2 + "", h/2 + "", "_3cd4", "cd4");
            ret.AddPathCommand(3, w/2 + "", h/2 + "", "0", "cd4");
            ret.AddPathCommand(3, w/2 + "", h/2 + "", "cd4", "cd4");
            ret.AddPathCommand(6);
            break;
        }
        case SYMBOL_DASH:
        case SYMBOL_DOT:
        {
            ret.AddPathCommand(0,undefined, "none", undefined, w, h);
            ret.AddPathCommand(1, type === SYMBOL_DASH ? "0" : w/2+"", h/2 +"");
            ret.AddPathCommand(2, w + "", h/2 +"");
            break;
        }
        case SYMBOL_DIAMOND:
        {
            ret.AddPathCommand(0,undefined, undefined, undefined, w, h);
            ret.AddPathCommand(1, w/2+"", "0");
            ret.AddPathCommand(2, w+"", h/2+"");
            ret.AddPathCommand(2, w/2 + "", h+"");
            ret.AddPathCommand(2, "0", h/2+"");
            ret.AddPathCommand(6);
            break;
        }
        case SYMBOL_NONE:
        {
            break;
        }
        case SYMBOL_PICTURE:
        case SYMBOL_SQUARE:
        {
            ret.AddPathCommand(0,undefined, undefined, undefined, w, h);
            AddRect(ret, w, h);
            break;
        }
        case SYMBOL_PLUS:
        {
            ret.AddPathCommand(0,undefined,  "none", false, w, h);
            AddRect(ret, w, h);
            AddPlus(ret, w, h);
            break;
        }
        case SYMBOL_STAR:
        {
            ret.AddPathCommand(0,undefined,  "none", false, w, h);
            AddRect(ret, w, h);
            AddPlus(ret, w, h);
            AddX(ret, w, h);
            break;
        }
        case SYMBOL_TRIANGLE:
        {
            ret.AddPathCommand(0,undefined, undefined, undefined, w, h);
            ret.AddPathCommand(1, w/2+"", "0");
            ret.AddPathCommand(2, w+"", h + "");
            ret.AddPathCommand(2, "0", h+"");
            ret.AddPathCommand(6);
            break;
        }
        case SYMBOL_X:
        {
            ret.AddPathCommand(0,undefined, "none", false, w, h);
            AddRect(ret, w, h);
            AddX(ret, w, h);
            break;
        }
    }
    var ret2 = new CompiledMarker();
    ret2.spPr.geometry = ret;
    return ret2;
}

    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].CDLbl = CDLbl;
    window['AscFormat'].CPlotArea = CPlotArea;
    window['AscFormat'].CBarChart = CBarChart;
    window['AscFormat'].CAreaChart = CAreaChart;
    window['AscFormat'].CAreaSeries = CAreaSeries;
    window['AscFormat'].CCatAx = CCatAx;
    window['AscFormat'].CDateAx = CDateAx;
    window['AscFormat'].CSerAx = CSerAx;
    window['AscFormat'].CValAx = CValAx;
    window['AscFormat'].CBandFmt = CBandFmt;
    window['AscFormat'].CBarSeries = CBarSeries;
    window['AscFormat'].CBubbleChart = CBubbleChart;
    window['AscFormat'].CBubbleSeries = CBubbleSeries;
    window['AscFormat'].CCat = CCat;
    window['AscFormat'].CChartText = CChartText;
    window['AscFormat'].CDLbls = CDLbls;
    window['AscFormat'].CDPt = CDPt;
    window['AscFormat'].CDTable = CDTable;
    window['AscFormat'].CDispUnits = CDispUnits;
    window['AscFormat'].CDoughnutChart = CDoughnutChart;
    window['AscFormat'].CErrBars = CErrBars;
    window['AscFormat'].CLayout = CLayout;
    window['AscFormat'].CLegend = CLegend;
    window['AscFormat'].CLegendEntry = CLegendEntry;
    window['AscFormat'].CLineChart = CLineChart;
    window['AscFormat'].CLineSeries = CLineSeries;
    window['AscFormat'].CMarker = CMarker;
    window['AscFormat'].CMinusPlus = CMinusPlus;
    window['AscFormat'].CMultiLvlStrCache = CMultiLvlStrCache;
    window['AscFormat'].CMultiLvlStrRef = CMultiLvlStrRef;
    window['AscFormat'].CNumRef = CNumRef;
    window['AscFormat'].CNumericPoint = CNumericPoint;
    window['AscFormat'].CNumFmt = CNumFmt;
    window['AscFormat'].CNumLit = CNumLit;
    window['AscFormat'].COfPieChart = COfPieChart;
    window['AscFormat'].CPictureOptions = CPictureOptions;
    window['AscFormat'].CPieChart = CPieChart;
    window['AscFormat'].CPieSeries = CPieSeries;
    window['AscFormat'].CPivotFmt = CPivotFmt;
    window['AscFormat'].CRadarChart = CRadarChart;
    window['AscFormat'].CRadarSeries = CRadarSeries;
    window['AscFormat'].CScaling = CScaling;
    window['AscFormat'].CScatterChart = CScatterChart;
    window['AscFormat'].CScatterSeries = CScatterSeries;
    window['AscFormat'].CTx = CTx;
    window['AscFormat'].CStockChart = CStockChart;
    window['AscFormat'].CStrCache = CStrCache;
    window['AscFormat'].CStringLiteral = CStringLiteral;
    window['AscFormat'].CStringPoint = CStringPoint;
    window['AscFormat'].CStrRef = CStrRef;
    window['AscFormat'].CSurfaceChart = CSurfaceChart;
    window['AscFormat'].CSurfaceSeries = CSurfaceSeries;
    window['AscFormat'].CTitle = CTitle;
    window['AscFormat'].CTrendLine = CTrendLine;
    window['AscFormat'].CUpDownBars = CUpDownBars;
    window['AscFormat'].CXVal = CXVal;
    window['AscFormat'].CYVal = CYVal;
    window['AscFormat'].CChart = CChart;
    window['AscFormat'].CChartWall = CChartWall;
    window['AscFormat'].CView3d = CView3d;
    window['AscFormat'].CreateTextBodyFromString = CreateTextBodyFromString;
    window['AscFormat'].CreateDocContentFromString = CreateDocContentFromString;
    window['AscFormat'].AddToContentFromString = AddToContentFromString;
    window['AscFormat'].CValAxisLabels = CValAxisLabels;
    window['AscFormat'].CalcLegendEntry = CalcLegendEntry;
    window['AscFormat'].CUnionMarker = CUnionMarker;
    window['AscFormat'].CreateMarkerGeometryByType = CreateMarkerGeometryByType;

    window['AscFormat'].NEW_WORKSHEET_DRAWING_DOCUMENT = null;
    
    window['AscFormat'].AX_POS_L = AX_POS_L;
    window['AscFormat'].AX_POS_T = AX_POS_T;
    window['AscFormat'].AX_POS_R = AX_POS_R;
    window['AscFormat'].AX_POS_B = AX_POS_B;
    
    window['AscFormat'].CROSSES_AUTO_ZERO = CROSSES_AUTO_ZERO;
    window['AscFormat'].CROSSES_MAX = CROSSES_MAX;
    window['AscFormat'].CROSSES_MIN = CROSSES_MIN;

    window['AscFormat'].LBL_ALG_CTR = LBL_ALG_CTR;
    window['AscFormat'].LBL_ALG_L = LBL_ALG_L;
    window['AscFormat'].LBL_ALG_R = LBL_ALG_R;

    window['AscFormat'].TIME_UNIT_DAYS = TIME_UNIT_DAYS;
    window['AscFormat'].TIME_UNIT_MONTHS = TIME_UNIT_MONTHS;
    window['AscFormat'].TIME_UNIT_YEARS = TIME_UNIT_YEARS;

    window['AscFormat'].CROSS_BETWEEN_BETWEEN = CROSS_BETWEEN_BETWEEN;
    window['AscFormat'].CROSS_BETWEEN_MID_CAT = CROSS_BETWEEN_MID_CAT;

    window['AscFormat'].SYMBOL_CIRCLE = SYMBOL_CIRCLE;
    window['AscFormat'].SYMBOL_DASH = SYMBOL_DASH;
    window['AscFormat'].SYMBOL_DIAMOND = SYMBOL_DIAMOND;
    window['AscFormat'].SYMBOL_DOT = SYMBOL_DOT;
    window['AscFormat'].SYMBOL_NONE = SYMBOL_NONE;
    window['AscFormat'].SYMBOL_PICTURE = SYMBOL_PICTURE;
    window['AscFormat'].SYMBOL_PLUS = SYMBOL_PLUS;
    window['AscFormat'].SYMBOL_SQUARE = SYMBOL_SQUARE;
    window['AscFormat'].SYMBOL_STAR = SYMBOL_STAR;
    window['AscFormat'].SYMBOL_TRIANGLE = SYMBOL_TRIANGLE;
    window['AscFormat'].SYMBOL_X = SYMBOL_X;
    window['AscFormat'].MARKER_SYMBOL_TYPE = MARKER_SYMBOL_TYPE;

    window['AscFormat'].ORIENTATION_MAX_MIN = ORIENTATION_MAX_MIN;
    window['AscFormat'].ORIENTATION_MIN_MAX = ORIENTATION_MIN_MAX;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {

    // Import
    var isRealObject = AscCommon.isRealObject;
    var History = AscCommon.History;

var  field_type_slidenum   = 0;
var  field_type_datetime   = 1;
var  field_type_datetime1  = 2;
var  field_type_datetime2  = 3;
var  field_type_datetime3  = 4;
var  field_type_datetime4  = 5;
var  field_type_datetime5  = 6;
var  field_type_datetime6  = 7;
var  field_type_datetime7  = 8;
var  field_type_datetime8  = 9;
var  field_type_datetime9  = 10;
var  field_type_datetime10 = 11;
var  field_type_datetime11 = 12;
var  field_type_datetime12 = 13;
var  field_type_datetime13 = 14;

var field_months = [];
field_months[0] = [];//rus
field_months[0][0]  = "января" ;
field_months[0][1]  = "февраля";
field_months[0][2]  = "марта";
field_months[0][3]  = "апреля";
field_months[0][4]  = "мая";
field_months[0][5]  = "июня";
field_months[0][6]  = "июля";
field_months[0][7]  = "августа";
field_months[0][8]  = "сентября";
field_months[0][9]  = "октября";
field_months[0][10] = "ноября";
field_months[0][11] = "декабря";

//-----------------------------

   AscDFH.changesFactory[AscDFH.historyitem_TextBodySetParent] = AscDFH.CChangesDrawingsObject;
   AscDFH.changesFactory[AscDFH.historyitem_TextBodySetBodyPr] = AscDFH.CChangesDrawingsObjectNoId;
   AscDFH.changesFactory[AscDFH.historyitem_TextBodySetContent] = AscDFH.CChangesDrawingsObject;
   AscDFH.changesFactory[AscDFH.historyitem_TextBodySetLstStyle] = AscDFH.CChangesDrawingsObjectNoId;


AscDFH.drawingsChangesMap[AscDFH.historyitem_TextBodySetParent] =   function(oClass, value){oClass.parent = value;};
AscDFH.drawingsChangesMap[AscDFH.historyitem_TextBodySetBodyPr] =   function(oClass, value){oClass.bodyPr = value;};
AscDFH.drawingsChangesMap[AscDFH.historyitem_TextBodySetContent] =  function(oClass, value){oClass.content = value;};
AscDFH.drawingsChangesMap[AscDFH.historyitem_TextBodySetLstStyle] = function(oClass, value){oClass.lstStyle = value;};

    AscDFH.drawingsConstructorsMap[AscDFH.historyitem_TextBodySetBodyPr] = AscFormat.CBodyPr;
    AscDFH.drawingsConstructorsMap[AscDFH.historyitem_TextBodySetLstStyle] = AscFormat.TextListStyle;



function CTextBody()
{
    this.bodyPr = null;
    this.lstStyle = null;
    this.content = null;
    this.parent = null;

    this.content2 = null;
    this.compiledBodyPr = null;
    this.parent = null;
    this.recalcInfo =
    {
        recalculateBodyPr: true,
        recalculateContent2: true
    };
    this.Id = AscCommon.g_oIdCounter.Get_NewId();
    AscCommon.g_oTableId.Add(this, this.Id);
}

CTextBody.prototype =
{
    createDuplicate: function()
    {
        var ret = new CTextBody();
        if(this.bodyPr)
            ret.setBodyPr(this.bodyPr.createDuplicate());
        if(this.lstStyle)
            ret.setLstStyle(this.lstStyle.createDuplicate());
        if(this.content)
            ret.setContent(this.content.Copy(ret, AscFormat.NEW_WORKSHEET_DRAWING_DOCUMENT));
        return ret;
    },

    createDuplicate2: function()
    {
        var ret = new CTextBody();
        if(this.bodyPr)
            ret.setBodyPr(this.bodyPr.createDuplicate());
        if(this.lstStyle)
            ret.setLstStyle(this.lstStyle.createDuplicate());
        if(this.content){
            var bTrackRevision = false;
            if(typeof editor !== "undefined" && editor && editor.WordControl && editor.WordControl.m_oLogicDocument.TrackRevisions === true){
                bTrackRevision= true;
                editor.WordControl.m_oLogicDocument.TrackRevisions = false;
            }
            ret.setContent(this.content.Copy3(ret));
            if(bTrackRevision){
                editor.WordControl.m_oLogicDocument.TrackRevisions = true;
            }
        }
        return ret;
    },

    Get_Id: function()
    {
        return this.Id;
    },

    Is_TopDocument: function()
    {
        return false;
    },

    Is_DrawingShape: function(bRetShape)
    {
        if(bRetShape === true)
        {
            return this.parent;
        }
        return true;
    },

    Get_Theme : function()
    {
        if(this.parent){
            return this.parent.Get_Theme();
        }
        return null;
    },

    Get_ColorMap: function()
    {
        if(this.parent){
            return this.parent.Get_ColorMap();
        }
        return null;
    },

    setParent: function(pr)
    {
        History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_TextBodySetParent, this.parent, pr));
        this.parent = pr;
    },

    setBodyPr: function(pr)
    {
        History.Add(new AscDFH.CChangesDrawingsObjectNoId(this, AscDFH.historyitem_TextBodySetBodyPr, this.bodyPr, pr));
        this.bodyPr = pr;
        if(this.parent && this.parent.recalcInfo)
        {
            this.parent.recalcInfo.recalcContent = true;
            this.parent.recalcInfo.recalculateContent = true;
            this.parent.recalcInfo.recalculateContent2 = true;
            this.parent.recalcInfo.recalcTransformText = true;
            if(this.parent.addToRecalculate)
            {
                this.parent.addToRecalculate();
            }
        }

        if(this.parent && this.parent.parent && this.parent.parent.parent && this.parent.parent.parent.parent
            && this.parent.parent.parent.parent.parent && this.parent.parent.parent.parent.parent.handleUpdateInternalChart && History.Is_On())
        {
            this.parent.parent.parent.parent.parent.handleUpdateInternalChart();
        }
    },

    setContent: function(pr)
    {
        History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_TextBodySetContent, this.content, pr));
        this.content = pr;
    },

    setLstStyle: function(lstStyle)
    {
        History.Add(new AscDFH.CChangesDrawingsObjectNoId(this, AscDFH.historyitem_TextBodySetLstStyle, this.lstStyle, lstStyle));
        this.lstStyle = lstStyle;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_TextBody;
    },

    Write_ToBinary2: function(w)
    {
        w.WriteLong(AscDFH.historyitem_type_TextBody);
        w.WriteString2(this.Id);
    },

    Read_FromBinary2: function(r)
    {
        this.Id = r.GetString2();
    },

    recalculate: function()
    {

    },


    getFieldText: function(fieldType, slide, firstSlideNum)
    {
        var ret = "";
        if(this.parent && this.parent.isPlaceholder())
        {
            var _ph_type = this.parent.getPlaceholderType();
            switch (_ph_type)
            {
                case AscFormat.phType_dt :
                {
                    var _cur_date = new Date();
                    var _cur_year = _cur_date.getFullYear();
                    var _cur_month = _cur_date.getMonth();
                    var _cur_month_day = _cur_date.getDate();
                    //TODO: switch по fieldType
                    ret += (_cur_month_day > 9 ? _cur_month_day : "0" + _cur_month_day)
                                +  "." +   ((_cur_month +1) > 9 ? (_cur_month + 1) : "0" + (_cur_month +1))
                                + "." + _cur_year;
                    break;
                }
                case AscFormat.phType_sldNum :
                {
                    var _firstSlideNum = AscFormat.isRealNumber(firstSlideNum) ? firstSlideNum : 1;
                    if(slide instanceof Slide)
                    {
                        ret += "" + (slide.num+_firstSlideNum);
                    }
                    break;
                }
            }
        }
        return ret;
    },

    recalculateBodyPr: function()
    {
        AscFormat.ExecuteNoHistory(function()
        {
            if(!this.compiledBodyPr)
                this.compiledBodyPr = new AscFormat.CBodyPr();
            this.compiledBodyPr.setDefault();
            if(this.parent && this.parent.isPlaceholder && this.parent.isPlaceholder())
            {
                var hierarchy = this.parent.getHierarchy();
                for(var i = hierarchy.length - 1; i > -1; --i)
                {
                    if(isRealObject(hierarchy[i]) && isRealObject(hierarchy[i].txBody) && isRealObject(hierarchy[i].txBody.bodyPr))
                        this.compiledBodyPr.merge(hierarchy[i].txBody.bodyPr)
                }
            }
            if(isRealObject(this.bodyPr))
            {
                this.compiledBodyPr.merge(this.bodyPr);
            }
        }, this, []);
    },

    checkTextFit: function()
    {
        if(this.parent && this.parent.parent && this.parent.parent instanceof Slide)
        {
            if(isRealObject(this.bodyPr.textFit))
            {
                if(this.bodyPr.textFit.type === AscFormat.text_fit_NormAuto)
                {
                    var text_fit = this.bodyPr.textFit;
                    var font_scale, spacing_scale;
                    if(AscFormat.isRealNumber(text_fit.fontScale))
                        font_scale = text_fit.fontScale/100000;
                    if(AscFormat.isRealNumber(text_fit.lnSpcReduction))
                        spacing_scale = text_fit.lnSpcReduction/100000;

                    if(AscFormat.isRealNumber(font_scale)|| AscFormat.isRealNumber(spacing_scale))
                    {
                        var pars = this.content.Content;
                        for(var index = 0; index < pars.length; ++index)
                        {
                            var parg = pars[index];
                            if(AscFormat.isRealNumber(spacing_scale))
                            {
                                var spacing2 = parg.Get_CompiledPr(false).ParaPr.Spacing;
                                var new_spacing = {};
                                var spc = spacing2.Line*spacing_scale;
                                new_spacing.LineRule = spacing2.LineRule;
                                if(AscFormat.isRealNumber(spc))
                                {
                                    if(spacing2.LineRule === Asc.linerule_Auto)
                                    {
                                        new_spacing.Line = spacing2.Line - spacing_scale;
                                    }
                                    else
                                    {
                                        new_spacing.Line = spc;
                                    }
                                }
                                parg.Set_Spacing(new_spacing);
                            }
                            if(AscFormat.isRealNumber(font_scale))
                            {
                                var bReset = false;
                                if(AscCommon.g_oIdCounter.m_bLoad)
                                {
                                    bReset = true;
                                    AscCommon.g_oIdCounter.m_bLoad = false;
                                }
                                 var redFontSize = Math.round(parg.Get_CompiledPr(false).TextPr.FontSize*font_scale);
                                if(bReset)
                                {
                                    AscCommon.g_oIdCounter.m_bLoad = true;
                                }
                                this.checkParagraphContent(parg, font_scale, true, redFontSize);
                            }
                        }
                    }
                    this.bodyPr.textFit = null;
                }
            }
        }
    },

    checkParagraphContent: function(parg, fontScale, bParagraph, paragrRedFontSize)
    {
        for(var r = 0; r < parg.Content.length; ++r)
        {
            var item = parg.Content[r];
            switch(item.Type)
            {
                case para_Run:
                {
                    if(AscFormat.isRealNumber(item.Pr.FontSize))
                    {
                        item.Set_FontSize(Math.round(item.Pr.FontSize*fontScale));
                    }
                    else
                    {
                        item.Set_FontSize(paragrRedFontSize);
                    }
                    break;
                }
                case para_Hyperlink:
                {
                    this.checkParagraphContent(item, fontScale, false, paragrRedFontSize);
                    break;
                }
            }
        }

        if(parg.TextPr && parg.TextPr.Value)
        {
            if(AscFormat.isRealNumber(parg.TextPr.Value.FontSize))
            {
                parg.TextPr.Set_FontSize(Math.round(parg.TextPr.Value.FontSize*fontScale));
            }
            else
            {
                parg.TextPr.Set_FontSize(paragrRedFontSize);
            }
        }
    },

    Check_AutoFit: function()
    {
        return this.parent && this.parent.Check_AutoFit && this.parent.Check_AutoFit(true) || false;
    },

    Refresh_RecalcData: function()
    {
        if(this.parent && this.parent.recalcInfo)
        {
            this.parent.recalcInfo.recalcContent = true;
            this.parent.recalcInfo.recalcTransformText = true;

            this.parent.recalcInfo.recalculateContent = true;
            this.parent.recalcInfo.recalculateContent2 = true;
            this.parent.recalcInfo.recalculateTransformText = true;

            if(this.parent.addToRecalculate)
            {
                this.parent.addToRecalculate();
            }
        }
    },

    isEmpty: function()
    {
        return this.content.Is_Empty();
    },

    OnContentReDraw: function()
    {
        if(this.parent && this.parent.OnContentReDraw)
        {
            this.parent.OnContentReDraw();
        }
    },

    Get_StartPage_Absolute: function()
    {
        return 0;//TODO;
    },

    Get_AbsolutePage : function(CurPage)
    {
        if(this.parent && this.parent.Get_AbsolutePage)
        {
            return this.parent.Get_AbsolutePage();
        }
        return 0;//TODO;
    },

    Get_AbsoluteColumn : function(CurPage)
    {
        return 0;//TODO;
    },

    Get_TextBackGroundColor: function()
    {
        return undefined;
    },

    IsHdrFtr: function(bReturnHdrFtr)
    {
    	if (bReturnHdrFtr)
    		return null;

        return false;
    },

	IsFootnote : function(bReturnFootnote)
	{
		if (bReturnFootnote)
			return null;

		return false;
	},

    Get_PageContentStartPos: function(pageNum)
    {
        return {X: 0, Y: 0, XLimit: this.contentWidth, YLimit: 20000};
    },

    Get_Numbering: function()
    {
        return new CNumbering();
    },

    Set_CurrentElement: function(bUpdate, pageIndex)
    {
        if(this.parent.Set_CurrentElement)
        {
            this.parent.Set_CurrentElement(bUpdate, pageIndex);
        }
    },

    checkDocContent: function()
    {
        this.parent && this.parent.checkDocContent && this.parent.checkDocContent();
    },

    getBodyPr: function()
    {
        if(this.recalcInfo.recalculateBodyPr)
        {
            this.recalculateBodyPr();
            this.recalcInfo.recalculateBodyPr = false;
        }
        return this.compiledBodyPr;
    },

    getSummaryHeight: function()
    {
        return this.content.GetSummaryHeight();
    },

    getSummaryHeight2: function()
    {
        return this.content2 ? this.content2.GetSummaryHeight() : 0;
    },

    getSummaryHeight3: function()
    {
        if(this.content && this.content.GetSummaryHeight_){
            return this.content.GetSummaryHeight_();
        }
        return 0;
    },

    getCompiledBodyPr: function()
    {
        this.recalculateBodyPr();
        return this.compiledBodyPr;
    },

    Get_TableStyleForPara: function()
    {
        return null;
    },

    checkCurrentPlaceholder: function()
    {
        return false;
    },

    draw: function(graphics)
    {
        if((!this.content || this.content.Is_Empty()) && !AscCommon.IsShapeToImageConverter && this.parent.isEmptyPlaceholder() && !this.checkCurrentPlaceholder() )
        {
            if (graphics.IsNoDrawingEmptyPlaceholder !== true && graphics.IsNoDrawingEmptyPlaceholderText !== true && this.content2)
            {
                if(graphics.IsNoSupportTextDraw)
                {
                    var _w2 = this.content2.XLimit;
                    var _h2 = this.content2.GetSummaryHeight();
                    graphics.rect(this.content2.X, this.content2.Y, _w2, _h2);
                }

                this.content2.Set_StartPage(0);
                this.content2.Draw(0, graphics);
            }
        }
        else if(this.content)
        {
            if(graphics.IsNoSupportTextDraw)
            {
                var bEmpty = this.content.IsEmpty();
                var _w = bEmpty ? 0.1 : this.content.XLimit;
                var _h = this.content.GetSummaryHeight();
                graphics.rect(this.content.X, this.content.Y, _w, _h);
            }
            var old_start_page = this.content.StartPage;
            this.content.Set_StartPage(0);
            this.content.Draw(0, graphics);
            this.content.Set_StartPage(old_start_page);
        }
    },

    Get_Styles: function(level)
    {
        if(this.parent)
        {
            return this.parent.getStyles(level);
        }
        return AscFormat.ExecuteNoHistory(function(){
            var oStyles = new CStyles(false);
            var Style_Para_Def = new CStyle( "Normal", null, null, styletype_Paragraph );
            Style_Para_Def.CreateNormal();
            oStyles.Default.Paragraph = oStyles.Add( Style_Para_Def );
            return {styles: oStyles, lastId: oStyles.Default.Paragraph};
        }, this, []);
    },

    IsCell: function(isReturnCell)
    {
    	if (true === isReturnCell)
    		return null;

        return false;
    },

    OnContentRecalculate: function()
    {},

    getMargins: function ()
    {
        var _parent_transform = this.parent.transform;
        var _l;
        var _r;
        var _b;
        var _t;
        var _body_pr = this.getBodyPr();
        var sp = this.parent;
        if(isRealObject(sp.spPr) && isRealObject(sp.spPr.geometry) && isRealObject(sp.spPr.geometry.rect))
        {
            var _rect = sp.spPr.geometry.rect;
            _l = _rect.l + _body_pr.lIns;
            _t = _rect.t + _body_pr.tIns;
            _r = _rect.r - _body_pr.rIns;
            _b = _rect.b - _body_pr.bIns;
        }
        else
        {
            _l = _body_pr.lIns;
            _t = _body_pr.tIns;
            _r = sp.extX - _body_pr.rIns;
            _b = sp.extY - _body_pr.bIns;
        }

        var x_lt, y_lt, x_rb, y_rb;

        x_lt = _parent_transform.TransformPointX(_l, _t);
        y_lt = _parent_transform.TransformPointY(_l, _t);

        x_rb = _parent_transform.TransformPointX(_r, _b);
        y_rb = _parent_transform.TransformPointY(_r, _b);

        var hc = (_r - _l)/2;
        var vc = (_b - _t)/2;

        var xc = (x_lt + x_rb)/2;
        var yc = (y_lt + y_rb)/2;

        return {L : xc - hc , T: yc - vc , R : xc + hc , B : yc + vc, textMatrix : this.parent.transform};
    },

    Refresh_RecalcData2: function(pageIndex)
    {
        this.parent && this.parent.Refresh_RecalcData2 && this.parent.Refresh_RecalcData2(pageIndex, this);
    },

    getContentOneStringSizes: function()
    {
        //TODO: потом переделать
        this.content.Reset(0, 0, 20000, 20000);//выставляем большую ширину чтобы текст расчитался в одну строку.
        this.content.Recalculate_Page(0, true);
        return {w: this.content.Content[0].Lines[0].Ranges[0].W+0.1, h: this.content.GetSummaryHeight()+0.1};
    },

    recalculateByMaxWord: function()
    {
        var max_content = this.content.RecalculateMinMaxContentWidth().Max;
        this.content.Set_ApplyToAll(true);
        this.content.SetParagraphAlign(AscCommon.align_Center);
        this.content.Set_ApplyToAll(false);
        this.content.Reset(0, 0,max_content, 20000);
        this.content.Recalculate_Page(0, true);
        return {w: max_content, h: this.content.GetSummaryHeight()};
    },

	GetFirstElementInNextCell : function()
	{
		return null;
	},

	GetLastElementInPrevCell : function()
	{
		return null;
	},

    getRectWidth: function(maxWidth)
    {
        var body_pr = this.getBodyPr();
        var r_ins = body_pr.rIns;
        var l_ins = body_pr.lIns;
        var max_content_width = maxWidth - r_ins - l_ins;
        this.content.Reset(0, 0, max_content_width, 20000);
        this.content.Recalculate_Page(0, true);
        var max_width = 0;
        for(var i = 0; i < this.content.Content.length; ++i)
        {
            var par = this.content.Content[i];
            for(var j = 0; j < par.Lines.length; ++j)
            {
                if(par.Lines[j].Ranges[0].W  > max_width)
                {
                    max_width = par.Lines[j].Ranges[0].W;
                }
            }
        }
        return max_width + 2 + r_ins + l_ins;
    },

    getMaxContentWidth: function(maxWidth, bLeft)
    {
        this.content.Reset(0, 0, maxWidth - 0.01, 20000);
        if(bLeft)
        {
            this.content.Set_ApplyToAll(true);
            this.content.SetParagraphAlign(AscCommon.align_Left);
            this.content.Set_ApplyToAll(false);
        }
        this.content.Recalculate_Page(0, true);
        var max_width = 0, arr_content = this.content.Content, paragraph_lines, i, j;
        for(i = 0;  i < arr_content.length; ++i)
        {
            paragraph_lines = arr_content[i].Lines;
            for(j = 0;  j < paragraph_lines.length; ++j)
            {
                if(paragraph_lines[j].Ranges[0].W > max_width)
                    max_width = paragraph_lines[j].Ranges[0].W;
            }
        }
        return max_width + 0.01;
    },

	GetPrevElementEndInfo : function(CurElement)
    {
        return null;
    },

    Is_UseInDocument: function(Id)
    {
        if(Id != undefined)
        {
            if(!this.content || this.content.Get_Id() !== Id)
            {
                return false;
            }
        }
        if(this.parent && this.parent.Is_UseInDocument)
        {
            return this.parent.Is_UseInDocument();
        }
        return false;
    },

    Get_ParentTextTransform: function()
    {
        if(this.parent && this.parent.transformText)
        {
            return this.parent.transformText.CreateDublicate();
        }
        return null;
    },

    Is_ThisElementCurrent: function () {
        if(this.parent && this.parent.Is_ThisElementCurrent)
        {
            return this.parent.Is_ThisElementCurrent();
        }
        return false;
    }
};

    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].CTextBody = CTextBody;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

// Import
var CShape = AscFormat.CShape;
var HitInLine = AscFormat.HitInLine;

var isRealObject = AscCommon.isRealObject;
var History = AscCommon.History;


    window['AscDFH'].drawingsChangesMap[AscDFH.historyitem_GraphicFrameSetSpPr] = function(oClass, value){oClass.spPr = value;};
    window['AscDFH'].drawingsChangesMap[AscDFH.historyitem_GraphicFrameSetGraphicObject] = function(oClass, value){
        oClass.graphicObject = value;
        if(value)
        {
            value.Parent = oClass;
            oClass.graphicObject.Index = 0;
        }
    };
    window['AscDFH'].drawingsChangesMap[AscDFH.historyitem_GraphicFrameSetSetNvSpPr] = function(oClass, value){oClass.nvGraphicFramePr = value;};
    window['AscDFH'].drawingsChangesMap[AscDFH.historyitem_GraphicFrameSetSetParent] = function(oClass, value){oClass.parent = value;};
    window['AscDFH'].drawingsChangesMap[AscDFH.historyitem_GraphicFrameSetSetGroup] = function(oClass, value){oClass.group = value;};

    AscDFH.changesFactory[AscDFH.historyitem_GraphicFrameSetSpPr] = AscDFH.CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_GraphicFrameSetGraphicObject] = AscDFH.CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_GraphicFrameSetSetNvSpPr] = AscDFH.CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_GraphicFrameSetSetParent] = AscDFH.CChangesDrawingsObject;
    AscDFH.changesFactory[AscDFH.historyitem_GraphicFrameSetSetGroup] = AscDFH.CChangesDrawingsObject;

function CGraphicFrame()
{
	AscFormat.CGraphicObjectBase.call(this);
    this.graphicObject = null;
    this.nvGraphicFramePr = null;

    this.compiledHierarchy = [];
    this.Pages      = [];
    this.Id = AscCommon.g_oIdCounter.Get_NewId();
    AscCommon.g_oTableId.Add(this, this.Id);
    this.compiledStyles = [];
    this.recalcInfo =
    {
        recalculateTransform: true,
        recalculateSizes: true,
        recalculateNumbering: true,
        recalculateShapeHierarchy: true,
        recalculateTable: true
    };
    this.RecalcInfo = {};
}

	CGraphicFrame.prototype = Object.create(AscFormat.CGraphicObjectBase.prototype);
	CGraphicFrame.prototype.constructor = CGraphicFrame;

CGraphicFrame.prototype.addToRecalculate = CShape.prototype.addToRecalculate;

CGraphicFrame.prototype.Get_Theme = CShape.prototype.Get_Theme;

CGraphicFrame.prototype.Get_ColorMap = CShape.prototype.Get_ColorMap;

CGraphicFrame.prototype.setBDeleted = CShape.prototype.setBDeleted;
CGraphicFrame.prototype.getBase64Img = CShape.prototype.getBase64Img;
CGraphicFrame.prototype.checkDrawingBaseCoords = CShape.prototype.checkDrawingBaseCoords;
CGraphicFrame.prototype.getSlideIndex = CShape.prototype.getSlideIndex;
CGraphicFrame.prototype.Is_UseInDocument = CShape.prototype.Is_UseInDocument;
CGraphicFrame.prototype.convertPixToMM = CShape.prototype.convertPixToMM;
CGraphicFrame.prototype.hit = CShape.prototype.hit;

CGraphicFrame.prototype.GetDocumentPositionFromObject= function(PosArray)
{
	if (!PosArray)
		PosArray = [];

	// TODO: Судя по тому как записывается позиция и как она читается
	//       класс CGraphicFrame не должен попадать в позицию
	if (PosArray && PosArray.length > 0 && PosArray[0].Class === this)
		PosArray.splice(0, 1);

	return PosArray;
};

CGraphicFrame.prototype.Is_DrawingShape = function(bRetShape)
    {
        if(bRetShape === true)
        {
            return null;
        }
        return false;
};

CGraphicFrame.prototype.handleUpdatePosition= function()
    {
        this.recalcInfo.recalculateTransform = true;
        this.addToRecalculate();
};

CGraphicFrame.prototype.handleUpdateTheme= function()
    {
        this.compiledStyles = [];
        if(this.graphicObject)
        {
            this.graphicObject.Recalc_CompiledPr2();
            this.graphicObject.RecalcInfo.Recalc_AllCells();
            this.recalcInfo.recalculateSizes          = true;
            this.recalcInfo.recalculateShapeHierarchy = true;
            this.recalcInfo.recalculateTable          = true;
            this.addToRecalculate();
        }
};

CGraphicFrame.prototype.handleUpdateFill= function()
{};

CGraphicFrame.prototype.handleUpdateLn= function()
{};

CGraphicFrame.prototype.handleUpdateExtents= function()
    {
        this.recalcInfo.recalculateTransform = true;
        this.addToRecalculate();
};

CGraphicFrame.prototype.recalcText= function()
    {
        this.compiledStyles = [];
        if(this.graphicObject)
        {
            this.graphicObject.Recalc_CompiledPr2();
            this.graphicObject.RecalcInfo.Reset(true);
        }
        this.recalcInfo.recalculateTable = true;
        this.recalcInfo.recalculateSizes = true;
};

CGraphicFrame.prototype.Get_TextBackGroundColor= function()
    {
        return undefined;
};

CGraphicFrame.prototype.GetPrevElementEndInfo = function()
    {
        return null;
};

CGraphicFrame.prototype.Get_PageFields= function()
    {
        return editor.WordControl.m_oLogicDocument.Get_PageFields();
};

CGraphicFrame.prototype.Get_ParentTextTransform= function()
    {
        return this.transformText;
};

CGraphicFrame.prototype.getDocContent= function()
    {
        if(this.graphicObject && this.graphicObject.CurCell && ( false === this.graphicObject.Selection.Use || ( true === this.graphicObject.Selection.Use && table_Selection_Text === this.graphicObject.Selection.Type ) ) )
        {
            return this.graphicObject.CurCell.Content;
        }
        return null;
};

CGraphicFrame.prototype.setSpPr= function(spPr)
{
        History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_GraphicFrameSetSpPr, this.spPr, spPr));
        this.spPr = spPr;
};

CGraphicFrame.prototype.setGraphicObject= function(graphicObject)
    {
        History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_GraphicFrameSetGraphicObject, this.graphicObject, graphicObject));
        this.graphicObject = graphicObject;
        if(this.graphicObject)
        {
            this.graphicObject.Index = 0;
            this.graphicObject.Parent = this;
        }
};

CGraphicFrame.prototype.setNvSpPr= function(pr)
{
        History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_GraphicFrameSetSetNvSpPr, this.nvGraphicFramePr, pr));
        this.nvGraphicFramePr = pr;
};

CGraphicFrame.prototype.setParent= function(parent)
{
        History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_GraphicFrameSetSetParent, this.parent, parent));
        this.parent = parent;
};

CGraphicFrame.prototype.setGroup= function(group)
    {
        History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_GraphicFrameSetSetGroup, this.group, group));
        this.group = group;
};

CGraphicFrame.prototype.getObjectType= function()
    {
        return AscDFH.historyitem_type_GraphicFrame;
};

CGraphicFrame.prototype.Search = function(Str, Props, SearchEngine, Type)
    {
        if(this.graphicObject)
        {
            this.graphicObject.Search(Str, Props, SearchEngine, Type);
        }
};

CGraphicFrame.prototype.Search_GetId = function(bNext, bCurrent)
    {
        if(this.graphicObject)
        {
            return this.graphicObject.Search_GetId(bNext, bCurrent);
        }

        return null;
};

CGraphicFrame.prototype.copy= function()
    {
        var ret = new CGraphicFrame();
        if(this.graphicObject)
        {
            ret.setGraphicObject(this.graphicObject.Copy(ret));
            if(editor && editor.WordControl && editor.WordControl.m_oLogicDocument && isRealObject(editor.WordControl.m_oLogicDocument.globalTableStyles))
            {
                ret.graphicObject.Reset(0, 0, this.graphicObject.XLimit, this.graphicObject.YLimit, ret.graphicObject.PageNum);
            }
        }
        if(this.nvGraphicFramePr)
        {
            ret.setNvSpPr(this.nvGraphicFramePr.createDuplicate());
        }
        if(this.spPr)
        {
            ret.setSpPr(this.spPr.createDuplicate());
            ret.spPr.setParent(ret);
        }
        ret.setBDeleted(false);

        if(!this.recalcInfo.recalculateTable && !this.recalcInfo.recalculateSizes && !this.recalcInfo.recalculateTransform)
        {
            ret.cachedImage = this.getBase64Img();
            ret.cachedPixW = this.cachedPixW;
            ret.cachedPixH = this.cachedPixH;
        }
        return ret;
};

CGraphicFrame.prototype.getAllFonts= function(fonts)
    {
        if(this.graphicObject)
        {
            for(var i = 0; i < this.graphicObject.Content.length; ++i)
            {
                var row = this.graphicObject.Content[i];
                var cells = row.Content;
                for(var j = 0; j < cells.length;++j)
                {
                    cells[j].Content.Document_Get_AllFontNames(fonts);
                }
            }
            delete fonts["+mj-lt"];
            delete fonts["+mn-lt"];
            delete fonts["+mj-ea"];
            delete fonts["+mn-ea"];
            delete fonts["+mj-cs"];
            delete fonts["+mn-cs"];
        }
};

CGraphicFrame.prototype.MoveCursorToStartPos = function()
    {
        if(isRealObject(this.graphicObject))
        {
            this.graphicObject.MoveCursorToStartPos();
            this.graphicObject.RecalculateCurPos();

        }
};

CGraphicFrame.prototype.MoveCursorToEndPos = function()
    {
        if(isRealObject(this.graphicObject))
        {
            this.graphicObject.MoveCursorToEndPos();
            this.graphicObject.RecalculateCurPos();

        }
};

CGraphicFrame.prototype.hitInPath= function()
    {
        return false;
};

CGraphicFrame.prototype.paragraphFormatPaste= function(CopyTextPr, CopyParaPr, Bool)
    {
        if(isRealObject(this.graphicObject))
        {
            this.graphicObject.PasteFormatting(CopyTextPr, CopyParaPr, Bool);

            this.recalcInfo.recalculateContent = true;
            this.recalcInfo.recalculateTransformText = true;
            editor.WordControl.m_oLogicDocument.recalcMap[this.Id] = this;
        }

};

CGraphicFrame.prototype.ClearParagraphFormatting= function(isClearParaPr, isClearTextPr)
    {
        if(isRealObject(this.graphicObject))
        {
            this.graphicObject.ClearParagraphFormatting(isClearParaPr, isClearTextPr);

            this.recalcInfo.recalculateContent = true;
            this.recalcInfo.recalculateTransformText = true;
            editor.WordControl.m_oLogicDocument.recalcMap[this.Id] = this;
        }

};

CGraphicFrame.prototype.Set_Props= function(props)
    {
        if(this.graphicObject)
        {
            var bApplyToAll = this.parent.graphicObjects.State.textObject !== this;
           // if(bApplyToAll)
           //     this.graphicObject.Set_ApplyToAll(true);
            this.graphicObject.Set_Props(props, bApplyToAll);
            //if(bApplyToAll)
            //    this.graphicObject.Set_ApplyToAll(false);
            this.OnContentRecalculate();
            editor.WordControl.m_oLogicDocument.recalcMap[this.Id] = this;
        }
};

CGraphicFrame.prototype.updateCursorType= function(x, y, e)
    {
        var tx = this.invertTransform.TransformPointX(x, y);
        var ty = this.invertTransform.TransformPointY(x, y);
        this.graphicObject.UpdateCursorType(tx, ty, 0)
};

CGraphicFrame.prototype.getIsSingleBody = CShape.prototype.getIsSingleBody;

CGraphicFrame.prototype.getHierarchy = CShape.prototype.getHierarchy;

CGraphicFrame.prototype.getAllImages = function (images) {
};
CGraphicFrame.prototype.recalculateTable = function () {
    if(this.graphicObject)
    {
        this.graphicObject.Set_PositionH(Asc.c_oAscHAnchor.Page, false, 0, false);
        this.graphicObject.Set_PositionV(Asc.c_oAscVAnchor.Page, false, 0, false);
        this.graphicObject.Parent = this;
        this.graphicObject.Reset(0, 0, this.spPr.xfrm.extX, 10000, 0);
        this.graphicObject.Recalculate_Page(0);
    }
};

CGraphicFrame.prototype.recalculate = function()
    {
        if(this.bDeleted  || !this.parent)
            return;
        AscFormat.ExecuteNoHistory(function(){
            if(this.recalcInfo.recalculateTable)
            {
                this.recalculateTable();
                this.recalcInfo.recalculateTable = false;
            }
            if(this.recalcInfo.recalculateSizes)
            {
                this.recalculateSizes();
                this.recalcInfo.recalculateSizes = false;

            }
            if(this.recalcInfo.recalculateTransform)
            {
                this.recalculateTransform();
            this.recalculateSnapArrays();
                this.recalcInfo.recalculateTransform = false;
                this.transformText = this.transform;
                this.invertTransformText = this.invertTransform;
                this.cachedImage = null;
                this.bounds.l = this.x;
                this.bounds.t = this.y;
                this.bounds.r = this.x + this.extX;
                this.bounds.b = this.y + this.extY;
                this.bounds.x = this.x;
                this.bounds.y = this.y;
                this.bounds.w = this.extX;
                this.bounds.h = this.extY;
            }
        }, this, []);

};

CGraphicFrame.prototype.recalculateSizes = function()
    {
        if(this.graphicObject)
        {
            this.graphicObject.XLimit -= this.graphicObject.X;
            this.graphicObject.X = 0;
            this.graphicObject.Y = 0;
            this.graphicObject.X_origin = 0;
            var _page_bounds = this.graphicObject.Get_PageBounds(0);
            this.spPr.xfrm.extY = _page_bounds.Bottom - _page_bounds.Top;
            this.spPr.xfrm.extX = _page_bounds.Right - _page_bounds.Left;
            this.extX =  this.spPr.xfrm.extX;
            this.extY =  this.spPr.xfrm.extY;
        }
};

CGraphicFrame.prototype.IsSelectedSingleElement = function()
    {
        return true;
};

CGraphicFrame.prototype.recalculateCurPos = function()
    {
        this.graphicObject.RecalculateCurPos();
};

CGraphicFrame.prototype.isShape = function()
    {
        return false;
};

CGraphicFrame.prototype.isImage = function()
    {
        return false;
};

CGraphicFrame.prototype.isGroup = function()
    {
        return false;
};

CGraphicFrame.prototype.isChart = function()
    {
        return false;
};

CGraphicFrame.prototype.isTable = function()
    {
        return this.graphicObject instanceof CTable;
};

CGraphicFrame.prototype.CanAddHyperlink = function(bCheck)
    {
        if(this.graphicObject)
            return this.graphicObject.CanAddHyperlink(bCheck);
        return false;
};

CGraphicFrame.prototype.IsCursorInHyperlink = function(bCheck)
    {
        if(this.graphicObject)
            return this.graphicObject.IsCursorInHyperlink(bCheck);
        return false;
};

CGraphicFrame.prototype.getTransformMatrix = function()
    {
        return this.transform;
        if(this.recalcInfo.recalculateTransform)
        {
            this.recalculateTransform();
            this.recalcInfo.recalculateTransform = false;
        }
        return this.transform;
};

CGraphicFrame.prototype.OnContentReDraw = function()
{};

CGraphicFrame.prototype.getRectBounds = function()
    {
        var transform = this.getTransformMatrix();
        var w = this.extX;
        var h = this.extY;
        var rect_points = [{x:0, y:0}, {x: w, y: 0}, {x: w, y: h}, {x: 0, y: h}];
        var min_x, max_x, min_y, max_y;
        min_x = transform.TransformPointX(rect_points[0].x, rect_points[0].y);
        min_y = transform.TransformPointY(rect_points[0].x, rect_points[0].y);
        max_x = min_x;
        max_y = min_y;
        var cur_x, cur_y;
        for(var i = 1; i < 4; ++i)
        {
            cur_x = transform.TransformPointX(rect_points[i].x, rect_points[i].y);
            cur_y = transform.TransformPointY(rect_points[i].x, rect_points[i].y);
            if(cur_x < min_x)
                min_x = cur_x;
            if(cur_x > max_x)
                max_x = cur_x;

            if(cur_y < min_y)
                min_y = cur_y;
            if(cur_y > max_y)
                max_y = cur_y;
        }
        return {minX: min_x, maxX: max_x, minY: min_y, maxY: max_y};
};

CGraphicFrame.prototype.changeSize = function(kw, kh)
    {
        if (this.spPr && this.spPr.xfrm && this.spPr.xfrm.isNotNull()) {
            var xfrm = this.spPr.xfrm;
            xfrm.setOffX(xfrm.offX * kw);
            xfrm.setOffY(xfrm.offY * kh);
        }
        this.recalcTransform && this.recalcTransform();
};

CGraphicFrame.prototype.recalcTransform = function()
    {
        this.recalcInfo.recalculateTransform = true;
};

CGraphicFrame.prototype.getTransform = function()
    {
        if(this.recalcInfo.recalculateTransform)
        {
            this.recalculateTransform();
            this.recalcInfo.recalculateTransform = false;
        }
        return {x: this.x, y: this.y, extX: this.extX, extY: this.extY, rot: this.rot, flipH: this.flipH, flipV: this.flipV};
};

CGraphicFrame.prototype.canRotate = function()
    {
        return false;
};

CGraphicFrame.prototype.canResize = function()
    {
        return true;
};

CGraphicFrame.prototype.canMove = function()
    {
        return true;
};

CGraphicFrame.prototype.canGroup = function()
    {
        return false;
};

CGraphicFrame.prototype.createRotateTrack = function()
    {
        return new AscFormat.RotateTrackShapeImage(this);
};

CGraphicFrame.prototype.createResizeTrack = function(cardDirection)
    {
        return new AscFormat.ResizeTrackShapeImage(this, cardDirection);
};

CGraphicFrame.prototype.createMoveTrack = function()
    {
        return new AscFormat.MoveShapeImageTrack(this);
};

CGraphicFrame.prototype.getSnapArrays = function(snapX, snapY)
    {
        var transform = this.getTransformMatrix();
        snapX.push(transform.tx);
        snapX.push(transform.tx + this.extX*0.5);
        snapX.push(transform.tx + this.extX);
        snapY.push(transform.ty);
        snapY.push(transform.ty + this.extY*0.5);
        snapY.push(transform.ty + this.extY);
};

CGraphicFrame.prototype.hitInInnerArea = function(x, y)
    {
        var invert_transform = this.getInvertTransform();
        var x_t = invert_transform.TransformPointX(x, y);
        var y_t = invert_transform.TransformPointY(x, y);
        return x_t > 0 && x_t < this.extX && y_t > 0 && y_t < this.extY;
};

CGraphicFrame.prototype.hitInTextRect = function(x, y)
    {
        return this.hitInInnerArea(x, y);
};

CGraphicFrame.prototype.getInvertTransform = function()
    {
        if(this.recalcInfo.recalculateTransform)
            this.recalculateTransform();
        return this.invertTransform;
};

CGraphicFrame.prototype.hitInBoundingRect = function(x, y)
    {
        var invert_transform = this.getInvertTransform();
        var x_t = invert_transform.TransformPointX(x, y);
        var y_t = invert_transform.TransformPointY(x, y);

        var _hit_context = this.getParentObjects().presentation.DrawingDocument.CanvasHitContext;

        return (HitInLine(_hit_context, x_t, y_t, 0, 0, this.extX, 0) ||
            HitInLine(_hit_context, x_t, y_t, this.extX, 0, this.extX, this.extY)||
            HitInLine(_hit_context, x_t, y_t, this.extX, this.extY, 0, this.extY)||
            HitInLine(_hit_context, x_t, y_t, 0, this.extY, 0, 0));
};

CGraphicFrame.prototype.Document_UpdateRulersState  = function(margins)
    {
        if(this.graphicObject)
        {
            this.graphicObject.Document_UpdateRulersState(this.parent.num);
        }
};

CGraphicFrame.prototype.Get_PageLimits  = function(PageIndex)
    {
        return { X : 0, Y : 0, XLimit : Page_Width, YLimit : Page_Height };
};

CGraphicFrame.prototype.getParentObjects = CShape.prototype.getParentObjects;

CGraphicFrame.prototype.IsHdrFtr = function(bool)
{
	if (bool)
		return null;

	return false;
};
CGraphicFrame.prototype.IsFootnote = function(bReturnFootnote)
{
	if (bReturnFootnote)
		return null;

	return false;
};

	CGraphicFrame.prototype.IsTableCellContent = function(isReturnCell)
	{
		if (true === isReturnCell)
			return null;

		return false;
	};

CGraphicFrame.prototype.Check_AutoFit = function()
    {
        return false;
};

CGraphicFrame.prototype.Is_InTable = function()
    {
        return null;
};

CGraphicFrame.prototype.selectionSetStart = function(e, x, y, slideIndex)
    {
        if ( AscCommon.g_mouse_button_right === e.Button )
        {
            this.rightButtonFlag = true;
            return;
        }
        if(isRealObject(this.graphicObject))
        {
            var tx, ty;
            tx = this.invertTransform.TransformPointX(x, y);
            ty = this.invertTransform.TransformPointY(x, y);
            if(AscCommon.g_mouse_event_type_down === e.Type)
            {
                if(this.graphicObject.IsTableBorder( tx, ty, 0))
                {
                    if(editor.WordControl.m_oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_Drawing_Props) !== false)
                    {
                        return;
                    }
                    else
                    {
                    }
                }
            }

            if(!(/*content.IsTextSelectionUse() && */e.ShiftKey))
            {
                if(editor.WordControl.m_oLogicDocument.CurPosition){
                    editor.WordControl.m_oLogicDocument.CurPosition.X = tx;
                    editor.WordControl.m_oLogicDocument.CurPosition.Y = ty;
                }
                this.graphicObject.Selection_SetStart(tx, ty, this.parent.num, e);
            }
            else
            {
                if(!this.graphicObject.IsSelectionUse()){
                    this.graphicObject.StartSelectionFromCurPos();
                }
                this.graphicObject.Selection_SetEnd(tx, ty, this.parent.num, e);
            }
            this.graphicObject.RecalculateCurPos();
            return;
        }
};

CGraphicFrame.prototype.selectionSetEnd = function(e, x, y, slideIndex)
    {
        if(AscCommon.g_mouse_event_type_move === e.Type)
        {
            this.rightButtonFlag = false;
        }
        if(this.rightButtonFlag && AscCommon.g_mouse_event_type_up === e.Type)
        {
            this.rightButtonFlag = false;
            return;
        }
        if(isRealObject(this.graphicObject))
        {
            var tx, ty;
            tx = this.invertTransform.TransformPointX(x, y);
            ty = this.invertTransform.TransformPointY(x, y);
            //var bBorder = this.graphicObject.Selection.Type2 === table_Selection_Border;
            this.graphicObject.Selection_SetEnd(tx, ty, 0, e);
            //if(g_mouse_event_type_up === e.Type && bBorder)
            //    editor.WordControl.m_oLogicDocument.Recalculate();  TODO: пересчет вызывается в CTable
        }
};

CGraphicFrame.prototype.updateSelectionState = function()
    {
        if(isRealObject(this.graphicObject))
        {
            var drawingDocument = this.parent.presentation.DrawingDocument;
            var Doc = this.graphicObject;
            if ( true === Doc.IsSelectionUse() && !Doc.IsSelectionEmpty()) {
                drawingDocument.UpdateTargetTransform(this.transform);
                drawingDocument.TargetEnd();
                drawingDocument.SelectEnabled(true);
                drawingDocument.SelectClear();
                Doc.DrawSelectionOnPage(0);
                drawingDocument.SelectShow();
            }
            else
            {
                drawingDocument.SelectEnabled(false);
                Doc.RecalculateCurPos();
                drawingDocument.UpdateTargetTransform(this.transform);
                drawingDocument.TargetShow();
            }
        }
        else
        {
            this.parent.presentation.DrawingDocument.UpdateTargetTransform(null);
            this.parent.presentation.DrawingDocument.TargetEnd();
            this.parent.presentation.DrawingDocument.SelectEnabled(false);
            this.parent.presentation.DrawingDocument.SelectClear();
            this.parent.presentation.DrawingDocument.SelectShow();
        }
};

CGraphicFrame.prototype.Get_AbsolutePage  = function(CurPage)
    {
        return this.Get_StartPage_Absolute();
};

CGraphicFrame.prototype.Get_AbsoluteColumn  = function(CurPage)
    {
        return 0;
};

CGraphicFrame.prototype.Is_TopDocument = function()
    {
        return false;
};

CGraphicFrame.prototype.drawAdjustments = function()
{};

CGraphicFrame.prototype.recalculateTransform = CShape.prototype.recalculateTransform;

CGraphicFrame.prototype.recalculateLocalTransform = CShape.prototype.recalculateLocalTransform;

CGraphicFrame.prototype.deleteDrawingBase = CShape.prototype.deleteDrawingBase;

CGraphicFrame.prototype.addToDrawingObjects = CShape.prototype.addToDrawingObjects;

CGraphicFrame.prototype.select = CShape.prototype.select;

CGraphicFrame.prototype.deselect = CShape.prototype.deselect;

CGraphicFrame.prototype.Update_ContentIndexing = function()
{};
    
CGraphicFrame.prototype.GetTopDocumentContent = function()
{
    return null;
};

CGraphicFrame.prototype.draw = function(graphics)
    {
        if (graphics.IsSlideBoundsCheckerType === true) {
            graphics.transform3(this.transform);
            graphics._s();
            graphics._m(0, 0);
            graphics._l(this.extX, 0);
            graphics._l(this.extX, this.extY);
            graphics._l(0, this.extY);
            graphics._e();
            return;
        }
        if(this.graphicObject)
        {


            graphics.SaveGrState();
            graphics.transform3(this.transform);
            graphics.SetIntegerGrid(true);
            this.graphicObject.Draw(0, graphics);
            this.drawLocks(this.transform, graphics);
            graphics.RestoreGrState();
        }
};

CGraphicFrame.prototype.Select = function()
{};

CGraphicFrame.prototype.Set_CurrentElement = function()
    {
        if(this.parent && this.parent.graphicObjects)
        {
            this.parent.graphicObjects.resetSelection(true);
            if(this.group)
            {
                var main_group = this.group.getMainGroup();
                this.parent.graphicObjects.selectObject(main_group, 0);
                main_group.selectObject(this, 0);
                main_group.selection.textSelection = this;
            }
            else
            {
                this.parent.graphicObjects.selectObject(this, 0);
                this.parent.graphicObjects.selection.textSelection = this;
            }
            if(editor.WordControl.m_oLogicDocument.CurPage !== this.parent.num)
            {
                editor.WordControl.m_oLogicDocument.Set_CurPage(this.parent.num);
                editor.WordControl.GoToPage(this.parent.num);
            }
        }
};

CGraphicFrame.prototype.OnContentRecalculate = function()
    {
        this.recalcInfo.recalculateSizes = true;
        this.recalcInfo.recalculateTransform = true;
        editor.WordControl.m_oLogicDocument.Document_UpdateRulersState();
};

CGraphicFrame.prototype.getTextSelectionState = function()
    {
        return this.graphicObject.GetSelectionState();
};

CGraphicFrame.prototype.setTextSelectionState = function(Sate)
    {
        return this.graphicObject.SetSelectionState(Sate, Sate.length-1);
};

CGraphicFrame.prototype.isPlaceholder = function()
    {
        return this.nvGraphicFramePr &&  this.nvGraphicFramePr.nvPr && this.nvGraphicFramePr.nvPr.ph !== null;
};

CGraphicFrame.prototype.getPhType = function()
    {
        if(this.isPlaceholder())
        {
            return this.nvGraphicFramePr.nvPr.ph.type;
        }
        return null;
};

CGraphicFrame.prototype.getPhIndex = function()
    {
        if(this.isPlaceholder())
        {
            return this.nvGraphicFramePr.nvPr.ph.idx;
        }
        return null;
};

CGraphicFrame.prototype.getPlaceholderType = function()
    {
        return this.getPhType();
};

CGraphicFrame.prototype.getPlaceholderIndex = function()
    {
        return this.getPhIndex();
};

CGraphicFrame.prototype.paragraphAdd = function(paraItem, bRecalculate)
    {
};

CGraphicFrame.prototype.applyTextFunction = function(docContentFunction, tableFunction, args)
    {
        if(tableFunction === CTable.prototype.AddToParagraph)
        {
            if((args[0].Type === para_NewLine
                || args[0].Type === para_Text
                || args[0].Type === para_Space
                || args[0].Type === para_Tab
                || args[0].Type === para_PageNum)
                && this.graphicObject.Selection.Use)
            {
                this.graphicObject.Remove(1, true, undefined, true);
            }
        }
        else if(tableFunction === CTable.prototype.AddNewParagraph)
        {
            this.graphicObject.Selection.Use && this.graphicObject.Remove(1, true, undefined, true);
        }
        tableFunction.apply(this.graphicObject, args);
};

CGraphicFrame.prototype.remove = function(Count, bOnlyText, bRemoveOnlySelection)
    {
        this.graphicObject.Remove(Count, bOnlyText, bRemoveOnlySelection);
        this.recalcInfo.recalculateSizes = true;
        this.recalcInfo.recalculateTransform = true;
};

CGraphicFrame.prototype.addNewParagraph = function()
    {
        this.graphicObject.AddNewParagraph(false);
        this.recalcInfo.recalculateContent = true;
        this.recalcInfo.recalculateTransformText = true;
};

CGraphicFrame.prototype.setParagraphAlign = function(val)
    {
        if(isRealObject(this.graphicObject))
        {
            this.graphicObject.SetParagraphAlign(val);
            this.recalcInfo.recalculateContent = true;
            this.recalcInfo.recalculateTransform = true;
        }
};

CGraphicFrame.prototype.applyAllAlign = function(val)
    {
        if(isRealObject(this.graphicObject))
        {
            this.graphicObject.Set_ApplyToAll(true);
            this.graphicObject.SetParagraphAlign(val);
            this.graphicObject.Set_ApplyToAll(false);
        }
};

CGraphicFrame.prototype.setParagraphSpacing = function(val)
    {
        if(isRealObject(this.graphicObject))
        {
            this.graphicObject.SetParagraphSpacing(val);
        }
};

CGraphicFrame.prototype.applyAllSpacing = function(val)
    {
        if(isRealObject(this.graphicObject))
        {
            this.graphicObject.Set_ApplyToAll(true);
            this.graphicObject.SetParagraphSpacing(val);
            this.graphicObject.Set_ApplyToAll(false);
        }
};

CGraphicFrame.prototype.setParagraphNumbering = function(val)
    {
        if(isRealObject(this.graphicObject))
        {
            this.graphicObject.SetParagraphNumbering(val);
        }
};

CGraphicFrame.prototype.setParagraphIndent = function(val)
    {
        if(isRealObject(this.graphicObject))
        {
            this.graphicObject.SetParagraphIndent(val);
        }
};

CGraphicFrame.prototype.setParent2 = function(parent)
    {
        History.Add(new AscDFH.CChangesDrawingsObject(this, AscDFH.historyitem_GraphicFrameSetSetParent, this.parent, parent));
        this.parent = parent;
};

CGraphicFrame.prototype.setWordFlag = function(bPresentation, Document)
    {
        if(this.graphicObject)
        {
            this.graphicObject.bPresentation = bPresentation;
            for(var i = 0; i < this.graphicObject.Content.length; ++i)
            {
                var row = this.graphicObject.Content[i];
                for(var j = 0; j < row.Content.length; ++j)
                {
                    var content = row.Content[j].Content;
                    if(!bPresentation && Document)
                    {
                        content.Styles = Document.Styles;
                    }
                    else
                    {
                        content.Styles = null;
                    }
                    content.bPresentation = bPresentation;
                    for(var k = 0; k < content.Content.length; ++k)
                    {
                        content.Content[k].bFromDocument = !bPresentation;
                    }
                }
            }
        }
};

CGraphicFrame.prototype.Get_Styles = function(level)
    {
        if(AscFormat.isRealNumber(level))
        {
            if(!this.compiledStyles[level])
            {
                CShape.prototype.recalculateTextStyles.call(this, level);
            }
            return this.compiledStyles[level];
        }
        else
        {
            return editor.WordControl.m_oLogicDocument.globalTableStyles;
        }
};

CGraphicFrame.prototype.Get_StartPage_Absolute = function()
{
    if(this.parent)
    {
        return this.parent.num;
    }
    return 0;
};

CGraphicFrame.prototype.Get_PageContentStartPos = function(PageNum)
    {
        var presentation = editor.WordControl.m_oLogicDocument;
        return {
            X : 0,
            XLimit: presentation.Width,
            Y : 0,
            YLimit : presentation.Height,
            MaxTopBorder : 0
        };


};

CGraphicFrame.prototype.Get_PageContentStartPos2 = function()
    {
        return this.Get_PageContentStartPos();
};

CGraphicFrame.prototype.hitToHandles = CShape.prototype.hitToHandles;
CGraphicFrame.prototype.hitToAdjustment = function()
    {
        return {hit:false};
};

CGraphicFrame.prototype.Refresh_RecalcData = function()
    {
        this.Refresh_RecalcData2();
};

CGraphicFrame.prototype.Refresh_RecalcData2 = function()
    {
        this.recalcInfo.recalculateTable = true;
        this.recalcInfo.recalculateSizes = true;
        this.addToRecalculate();
    };
CGraphicFrame.prototype.checkTypeCorrect = function()
    {
        if(!this.graphicObject){
            return false;
        }
        return true;
    };
CGraphicFrame.prototype.Is_ThisElementCurrent = function()
    {
        if(this.parent && this.parent.graphicObjects)
        {
            if(this.group)
            {
                var main_group = this.group.getMainGroup();
                return main_group.selection.textSelection === this;
            }
            else
            {
                return this.parent.graphicObjects.selection.textSelection === this;
            }
        }
        return false;
    };


    CGraphicFrame.prototype.GetAllContentControls = function(arrContentControls){
       if(this.graphicObject){
           this.graphicObject.GetAllContentControls(arrContentControls);
       }
    };

    CGraphicFrame.prototype.getCopyWithSourceFormatting = function(){
        var ret = this.copy();
        var oCopyTable = ret.graphicObject;
        var oSourceTable = this.graphicObject;
        var oTheme = this.Get_Theme();
        var oColorMap = this.Get_ColorMap();
        var RGBA;
        if(oCopyTable && oSourceTable){
            var oPr2 = oCopyTable.Pr;
            if(oSourceTable.CompiledPr.Pr && oSourceTable.CompiledPr.Pr.TablePr){
                oCopyTable.Set_Pr(oSourceTable.CompiledPr.Pr.TablePr.Copy());
                oPr2 = oCopyTable.Pr;
                if(oPr2.TableBorders){
                    if(oPr2.TableBorders){
                        if(oPr2.TableBorders.Bottom && oPr2.TableBorders.Bottom.Unifill){
                            oPr2.TableBorders.Bottom.Unifill.check(oTheme, oColorMap);
                            RGBA = oPr2.TableBorders.Bottom.Unifill.getRGBAColor();
                            oPr2.TableBorders.Bottom.Unifill = AscFormat.CreteSolidFillRGB(RGBA.R, RGBA.G, RGBA.B, 255);
                        }
                        if(oPr2.TableBorders.Left && oPr2.TableBorders.Left.Unifill){
                            oPr2.TableBorders.Left.Unifill.check(oTheme, oColorMap);
                            RGBA = oPr2.TableBorders.Left.Unifill.getRGBAColor();
                            oPr2.TableBorders.Left.Unifill = AscFormat.CreteSolidFillRGB(RGBA.R, RGBA.G, RGBA.B, 255);
                        }
                        if(oPr2.TableBorders.Right && oPr2.TableBorders.Right.Unifill){
                            oPr2.TableBorders.Right.Unifill.check(oTheme, oColorMap);
                            RGBA = oPr2.TableBorders.Right.Unifill.getRGBAColor();
                            oPr2.TableBorders.Right.Unifill = AscFormat.CreteSolidFillRGB(RGBA.R, RGBA.G, RGBA.B, 255);
                        }
                        if(oPr2.TableBorders.Top && oPr2.TableBorders.Top.Unifill){
                            oPr2.TableBorders.Top.Unifill.check(oTheme, oColorMap);
                            RGBA = oPr2.TableBorders.Top.Unifill.getRGBAColor();
                            oPr2.TableBorders.Top.Unifill = AscFormat.CreteSolidFillRGB(RGBA.R, RGBA.G, RGBA.B, 255);
                        }
                        if(oPr2.TableBorders.InsideH && oPr2.TableBorders.InsideH.Unifill){
                            oPr2.TableBorders.InsideH.Unifill.check(oTheme, oColorMap);
                            RGBA = oPr2.TableBorders.InsideH.Unifill.getRGBAColor();
                            oPr2.TableBorders.InsideH.Unifill = AscFormat.CreteSolidFillRGB(RGBA.R, RGBA.G, RGBA.B, 255);
                        }
                        if(oPr2.TableBorders.InsideV && oPr2.TableBorders.InsideV.Unifill){
                            oPr2.TableBorders.InsideV.Unifill.check(oTheme, oColorMap);
                            RGBA = oPr2.TableBorders.InsideV.Unifill.getRGBAColor();
                            oPr2.TableBorders.InsideV.Unifill = AscFormat.CreteSolidFillRGB(RGBA.R, RGBA.G, RGBA.B, 255);
                        }
                    }
                }
            }
            if(oCopyTable.Content.length === oSourceTable.Content.length){
                for(var i = 0;  i < oCopyTable.Content.length; ++i){
                    var aSourceCells = oSourceTable.Content[i].Content;
                    var aCopyCells = oCopyTable.Content[i].Content;
                    if(aSourceCells.length === aCopyCells.length){
                        for(var j = 0; j < aSourceCells.length; ++j){
                            var aSourceContent = aSourceCells[j].Content.Content;
                            var aCopyContent = aCopyCells[j].Content.Content;
                            AscFormat.SaveContentSourceFormatting(aSourceContent, aCopyContent, oTheme, oColorMap);
                            if(aSourceCells[j].CompiledPr.Pr){
                                var oCellPr = new CTableCellPr();
                                if(oPr2.TableBorders){
                                    if(i === 0){
                                        if(oPr2.TableBorders.Top){
                                            oCellPr.TableCellBorders.Top = oPr2.TableBorders.Top.Copy();
                                        }
                                    }
                                    if(i === oCopyTable.Content.length - 1){
                                        if(oPr2.TableBorders.Bottom){
                                            oCellPr.TableCellBorders.Bottom = oPr2.TableBorders.Bottom.Copy();
                                        }
                                    }
                                    if(oPr2.TableBorders.InsideH){
                                        if(i !== 0){
                                            oCellPr.TableCellBorders.Top = oPr2.TableBorders.InsideH.Copy();
                                        }
                                        if(i !== oCopyTable.Content.length - 1){
                                                oCellPr.TableCellBorders.Bottom = oPr2.TableBorders.InsideH.Copy();
                                        }
                                    }
                                    if(j === 0){
                                        if(oPr2.TableBorders.Left){
                                            oCellPr.TableCellBorders.Left = oPr2.TableBorders.Left.Copy();
                                        }
                                    }
                                    if(j === aSourceCells.length - 1){
                                        if(oPr2.TableBorders.Right){
                                            oCellPr.TableCellBorders.Right = oPr2.TableBorders.Right.Copy();
                                        }
                                    }
                                    if(oPr2.TableBorders.InsideV){
                                        if(j !== 0){
                                            oCellPr.TableCellBorders.Left = oPr2.TableBorders.InsideV.Copy();
                                        }
                                        if(j !== aSourceCells.length - 1){
                                            oCellPr.TableCellBorders.Right = oPr2.TableBorders.InsideV.Copy();
                                        }
                                    }
                                }
                                oCellPr.Merge(aSourceCells[j].CompiledPr.Pr.Copy());
                                aCopyCells[j].Set_Pr(oCellPr);
                                var oPr = aCopyCells[j].Pr;
                                if(oPr.Shd && oPr.Shd.Unifill){
                                    if(oPr.Shd.Unifill){
                                        oPr.Shd.Unifill.check(oTheme, oColorMap);
                                        RGBA = oPr.Shd.Unifill.getRGBAColor();
                                        oPr.Shd.Unifill = AscFormat.CreteSolidFillRGB(RGBA.R, RGBA.G, RGBA.B, 255);
                                    }
                                }
                                if(oPr.TableCellBorders){
                                    if(oPr.TableCellBorders.Bottom && oPr.TableCellBorders.Bottom.Unifill){
                                        oPr.TableCellBorders.Bottom.Unifill.check(oTheme, oColorMap);
                                        RGBA = oPr.TableCellBorders.Bottom.Unifill.getRGBAColor();
                                        oPr.TableCellBorders.Bottom.Unifill = AscFormat.CreteSolidFillRGB(RGBA.R, RGBA.G, RGBA.B, 255);
                                    }

                                    if(oPr.TableCellBorders.Left && oPr.TableCellBorders.Left.Unifill){
                                        oPr.TableCellBorders.Left.Unifill.check(oTheme, oColorMap);
                                        RGBA = oPr.TableCellBorders.Left.Unifill.getRGBAColor();
                                        oPr.TableCellBorders.Left.Unifill = AscFormat.CreteSolidFillRGB(RGBA.R, RGBA.G, RGBA.B, 255);
                                    }
                                    if(oPr.TableCellBorders.Right && oPr.TableCellBorders.Right.Unifill){
                                        oPr.TableCellBorders.Right.Unifill.check(oTheme, oColorMap);
                                        RGBA = oPr.TableCellBorders.Right.Unifill.getRGBAColor();
                                        oPr.TableCellBorders.Right.Unifill = AscFormat.CreteSolidFillRGB(RGBA.R, RGBA.G, RGBA.B, 255);
                                    }
                                    if(oPr.TableCellBorders.Top && oPr.TableCellBorders.Top.Unifill){
                                        oPr.TableCellBorders.Top.Unifill.check(oTheme, oColorMap);
                                        RGBA = oPr.TableCellBorders.Top.Unifill.getRGBAColor();
                                        oPr.TableCellBorders.Top.Unifill = AscFormat.CreteSolidFillRGB(RGBA.R, RGBA.G, RGBA.B, 255);
                                    }
                                }
                            }
                        }
                    }

                }
            }
        }
        return ret;
    };
    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].CGraphicFrame = CGraphicFrame;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {
// Import

	var CreateNoFillLine = AscFormat.CreateNoFillLine;
	var CreateNoFillUniFill = AscFormat.CreateNoFillUniFill;
	
var c_oAscChartTypeSettings = Asc.c_oAscChartTypeSettings;
var c_oAscTickMark = Asc.c_oAscTickMark;
var c_oAscTickLabelsPos = Asc.c_oAscTickLabelsPos;
var fChartSize = 75;

function ChartPreviewManager() {
	this.previewGroups = [];
	this.chartsByTypes = [];

	this.CHART_PREVIEW_WIDTH_PIX = 50;
	this.CHART_PREVIEW_HEIGHT_PIX = 50;

	this._canvas_charts = null;
}

ChartPreviewManager.prototype.getAscChartSeriesDefault = function(type) {
	function createItem(value) {
		return { numFormatStr: "General", isDateTimeFormat: false, val: value, isHidden: false };
	}

	// Set data
	var series = [], ser;
	switch(type)
	{
		case c_oAscChartTypeSettings.lineNormal:
		{
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(2), createItem(3), createItem(2), createItem(3) ];
			series.push(ser);
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(1), createItem(2), createItem(3), createItem(2) ];
			series.push(ser);
			break;
		}
        case c_oAscChartTypeSettings.line3d:
        {
            ser = new AscFormat.asc_CChartSeria();
            ser.Val.NumCache = [ createItem(1), createItem(2), createItem(1), createItem(2) ];
            series.push(ser);
            ser = new AscFormat.asc_CChartSeria();
            ser.Val.NumCache = [ createItem(3), createItem(2.5), createItem(3), createItem(3.5) ];
            series.push(ser);
            break;
        }
		case c_oAscChartTypeSettings.lineStacked:
		{
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(1), createItem(6), createItem(2), createItem(8) ];
			series.push(ser);
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(4), createItem(4), createItem(4), createItem(5) ];
			series.push(ser);
			break;
		}
		case c_oAscChartTypeSettings.lineStackedPer:
		{
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(2), createItem(4), createItem(2), createItem(4) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(2), createItem(2), createItem(2), createItem(2) ];
			series.push(ser);
			break;
		}

		case c_oAscChartTypeSettings.hBarNormal:
		case c_oAscChartTypeSettings.hBarNormal3d:
		{
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(4) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(3) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(2) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(1) ];
			series.push(ser);
			break;
		}

		case c_oAscChartTypeSettings.hBarStacked:
		case c_oAscChartTypeSettings.hBarStacked3d:
		{
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(4), createItem(3), createItem(2), createItem(1) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(5), createItem(4), createItem(3), createItem(2) ];
			series.push(ser);
			break;
		}

		case c_oAscChartTypeSettings.hBarStackedPer:
		case c_oAscChartTypeSettings.hBarStackedPer3d:
		{
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(7), createItem(5), createItem(3), createItem(1) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(7), createItem(6), createItem(5), createItem(4) ];
			series.push(ser);
			break;
		}

		case c_oAscChartTypeSettings.barNormal:
		case c_oAscChartTypeSettings.barNormal3d:
		{
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(1) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(2) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(3) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(4) ];
			series.push(ser);
			break;
		}

		case c_oAscChartTypeSettings.barStacked:
		case c_oAscChartTypeSettings.barStacked3d:
		{
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(1), createItem(2), createItem(3), createItem(4) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(2), createItem(3), createItem(4), createItem(5) ];
			series.push(ser);
			break;
		}

		case c_oAscChartTypeSettings.barStackedPer:
		case c_oAscChartTypeSettings.barStackedPer3d:
		{
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(1), createItem(3), createItem(5), createItem(7) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(4), createItem(5), createItem(6), createItem(7) ];
			series.push(ser);
			break;
		}
        case c_oAscChartTypeSettings.barNormal3dPerspective:
        {
            ser = new AscFormat.asc_CChartSeria();
            ser.Val.NumCache = [ createItem(1), createItem(2), createItem(3), createItem(4) ];
            series.push(ser);

            ser = new AscFormat.asc_CChartSeria();
            ser.Val.NumCache = [ createItem(2), createItem(3), createItem(4), createItem(5) ];
            series.push(ser);
            break;
        }
		case c_oAscChartTypeSettings.pie:
		case c_oAscChartTypeSettings.doughnut:
		{
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(3), createItem(1) ];
			series.push(ser);
			break;
		}

		case c_oAscChartTypeSettings.areaNormal:
		{
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(0), createItem(8), createItem(5), createItem(6) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(0), createItem(4), createItem(2), createItem(9) ];
			series.push(ser);
			break;
		}

		case c_oAscChartTypeSettings.areaStacked:
		{
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(0), createItem(8), createItem(5), createItem(11) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(4), createItem(4), createItem(4), createItem(4) ];
			series.push(ser);
			break;
		}

		case c_oAscChartTypeSettings.areaStackedPer:
		{
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(0), createItem(4), createItem(1), createItem(16) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(4), createItem(4), createItem(4), createItem(4) ];
			series.push(ser);
			break;
		}

		case c_oAscChartTypeSettings.scatter:
		{
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(1), createItem(5) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(2), createItem(6) ];
			series.push(ser);
			break;
		}

		default:
		{
			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(3), createItem(5), createItem(7) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(10), createItem(12), createItem(14) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(1), createItem(3), createItem(5) ];
			series.push(ser);

			ser = new AscFormat.asc_CChartSeria();
			ser.Val.NumCache = [ createItem(8), createItem(10), createItem(12) ];
			series.push(ser);
			break;
		}
	}
	return series;
};

ChartPreviewManager.prototype.getChartByType = function(type)
{
	return AscFormat.ExecuteNoHistory(function()
	{
		var settings = new Asc.asc_ChartSettings();
		settings.type = type;
		var chartSeries = {series: this.getAscChartSeriesDefault(type), parsedHeaders: {bLeft: true, bTop: true}};
		var chart_space = AscFormat.DrawingObjectsController.prototype._getChartSpace(chartSeries, settings, true);
        chart_space.bPreview = true;
		if (Asc['editor'] && AscCommon.c_oEditorId.Spreadsheet === Asc['editor'].getEditorId()) {
			var api_sheet = Asc['editor'];
			chart_space.setWorksheet(api_sheet.wb.getWorksheet().model);
		} else {
			if (editor && editor.WordControl && editor.WordControl.m_oLogicDocument.Slides &&
				editor.WordControl.m_oLogicDocument.Slides[editor.WordControl.m_oLogicDocument.CurPage]) {
				chart_space.setParent(editor.WordControl.m_oLogicDocument.Slides[editor.WordControl.m_oLogicDocument.CurPage]);
			}
		}
		AscFormat.CheckSpPrXfrm(chart_space);
		chart_space.spPr.xfrm.setOffX(0);
		chart_space.spPr.xfrm.setOffY(0);
		chart_space.spPr.xfrm.setExtX(fChartSize);
		chart_space.spPr.xfrm.setExtY(fChartSize);
		settings.putTitle(Asc.c_oAscChartTitleShowSettings.noOverlay);
		//settings.putHorAxisLabel(Asc.c_oAscChartTitleShowSettings.none);
		//settings.putVertAxisLabel(Asc.c_oAscChartTitleShowSettings.none);
		//settings.putLegendPos(Asc.c_oAscChartLegendShowSettings.none);
		//settings.putHorGridLines(Asc.c_oAscGridLinesSettings.none);
		//settings.putVertGridLines(Asc.c_oAscGridLinesSettings.none);


		var val_ax_props = new AscCommon.asc_ValAxisSettings();
		val_ax_props.putMinValRule(Asc.c_oAscValAxisRule.auto);
		val_ax_props.putMaxValRule(Asc.c_oAscValAxisRule.auto);
		val_ax_props.putTickLabelsPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
		val_ax_props.putInvertValOrder(false);
		val_ax_props.putDispUnitsRule(Asc.c_oAscValAxUnits.none);
		val_ax_props.putMajorTickMark(c_oAscTickMark.TICK_MARK_NONE);
		val_ax_props.putMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
		val_ax_props.putCrossesRule(Asc.c_oAscCrossesRule.auto);


		var cat_ax_props = new AscCommon.asc_CatAxisSettings();
		cat_ax_props.putIntervalBetweenLabelsRule(Asc.c_oAscBetweenLabelsRule.auto);
		cat_ax_props.putLabelsPosition(Asc.c_oAscLabelsPosition.betweenDivisions);
		cat_ax_props.putTickLabelsPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NEXT_TO);
		cat_ax_props.putLabelsAxisDistance(100);
		cat_ax_props.putMajorTickMark(c_oAscTickMark.TICK_MARK_NONE);
		cat_ax_props.putMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
		cat_ax_props.putIntervalBetweenTick(1);
		cat_ax_props.putCrossesRule(Asc.c_oAscCrossesRule.auto);
		var vert_axis_settings, hor_axis_settings, isScatter;
		switch(type)
		{
			case c_oAscChartTypeSettings.hBarNormal:
			case c_oAscChartTypeSettings.hBarStacked:
			case c_oAscChartTypeSettings.hBarStackedPer:
			{
				vert_axis_settings = cat_ax_props;
				hor_axis_settings = val_ax_props;
				break;
			}
			case c_oAscChartTypeSettings.scatter:
			case c_oAscChartTypeSettings.scatterLine:
			case c_oAscChartTypeSettings.scatterLineMarker:
			case c_oAscChartTypeSettings.scatterMarker:
			case c_oAscChartTypeSettings.scatterNone:
			case c_oAscChartTypeSettings.scatterSmooth:
			case c_oAscChartTypeSettings.scatterSmoothMarker:
			{
				vert_axis_settings = val_ax_props;
				hor_axis_settings = val_ax_props;
				isScatter = true;
                settings.showMarker = true;
                settings.smooth = false;
                settings.bLine = false;
				break;
			}
            case c_oAscChartTypeSettings.areaNormal:
            case c_oAscChartTypeSettings.areaStacked:
            case c_oAscChartTypeSettings.areaStackedPer:
            {
                cat_ax_props.putLabelsPosition(AscFormat.CROSS_BETWEEN_BETWEEN);
                vert_axis_settings = val_ax_props;
                hor_axis_settings = cat_ax_props;

                break;
            }

			default :
			{
				vert_axis_settings = val_ax_props;
				hor_axis_settings = cat_ax_props;
				break;
			}
		}

		settings.putVertAxisProps(vert_axis_settings);
		settings.putHorAxisProps(hor_axis_settings);

		AscFormat.DrawingObjectsController.prototype.applyPropsToChartSpace(settings, chart_space);
		chart_space.setBDeleted(false);
		chart_space.updateLinks();
		if(!(isScatter || type === c_oAscChartTypeSettings.stock))
		{
			if(chart_space.chart.plotArea.valAx)
				chart_space.chart.plotArea.valAx.setDelete(true);
			if(chart_space.chart.plotArea.catAx)
				chart_space.chart.plotArea.catAx.setDelete(true);
		}
		else
		{
			if(chart_space.chart.plotArea.valAx)
			{
				chart_space.chart.plotArea.valAx.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE);
				chart_space.chart.plotArea.valAx.setMajorTickMark(c_oAscTickMark.TICK_MARK_NONE);
				chart_space.chart.plotArea.valAx.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
			}
			if(chart_space.chart.plotArea.catAx)
			{
				chart_space.chart.plotArea.catAx.setTickLblPos(c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE);
				chart_space.chart.plotArea.catAx.setMajorTickMark(c_oAscTickMark.TICK_MARK_NONE);
				chart_space.chart.plotArea.catAx.setMinorTickMark(c_oAscTickMark.TICK_MARK_NONE);
			}
		}
		if(!chart_space.spPr)
			chart_space.setSpPr(new AscFormat.CSpPr());

		var new_line = new AscFormat.CLn();
		new_line.setFill(new AscFormat.CUniFill());
		new_line.Fill.setFill(new AscFormat.CNoFill());
		chart_space.spPr.setLn(new_line);

        chart_space.recalcInfo.recalculateReferences = false;
		chart_space.recalculate();

		return chart_space;
	}, this, []);
};

ChartPreviewManager.prototype.clearPreviews = function()
{
	this.previewGroups.length = 0;
};
ChartPreviewManager.prototype.createChartPreview = function(type, styleIndex) {
    return AscFormat.ExecuteNoHistory(function(){
        if(!this.chartsByTypes[type])
            this.chartsByTypes[type] = this.getChartByType(type);
        var chart_space = this.chartsByTypes[type];
		AscFormat.ApplyPresetToChartSpace(chart_space, AscCommon.g_oChartPresets[type][styleIndex]);
		chart_space.recalcInfo.recalculateReferences = false;
		chart_space.recalculate();

        if (null === this._canvas_charts) {
            this._canvas_charts = document.createElement('canvas');
            this._canvas_charts.width = this.CHART_PREVIEW_WIDTH_PIX;
            this._canvas_charts.height = this.CHART_PREVIEW_HEIGHT_PIX;

            if (AscCommon.AscBrowser.isRetina) {
                this._canvas_charts.width = AscCommon.AscBrowser.convertToRetinaValue(this._canvas_charts.width, true);
                this._canvas_charts.height = AscCommon.AscBrowser.convertToRetinaValue(this._canvas_charts.height, true);
            }
        }

        var _canvas = this._canvas_charts;
        var ctx = _canvas.getContext('2d');
        var graphics = new AscCommon.CGraphics();
        graphics.init(ctx, _canvas.width, _canvas.height, fChartSize, fChartSize);
        graphics.m_oFontManager = AscCommon.g_fontManager;
        graphics.transform(1,0,0,1,0,0);
        chart_space.draw(graphics);
        return _canvas.toDataURL("image/png");
    }, this, []);

};

ChartPreviewManager.prototype.getChartPreviews = function(chartType) {
	if (AscFormat.isRealNumber(chartType)) {
		if (!this.previewGroups.hasOwnProperty(chartType)) {
			this.previewGroups[chartType] = [];
			var arr = this.previewGroups[chartType];
			if(AscCommon.g_oChartPresets[chartType]){
				var nStylesCount = AscCommon.g_oChartPresets[chartType].length;
				for(var i = 0; i < nStylesCount; ++i)
					arr.push(this.createChartPreview(chartType, i));
			}

			if (Asc['editor'] && AscCommon.c_oEditorId.Spreadsheet === Asc['editor'].getEditorId()) {
				var api_sheet = Asc['editor'];
				var _graphics = api_sheet.wb.getWorksheet().shapeCtx;
				if (_graphics.ClearLastFont)
					_graphics.ClearLastFont();
			}

		}
		var group = this.previewGroups[chartType];
		var objectGroup = [];

		for (var style = 0; style <  group.length; ++style) {
			var chartStyle = new AscFormat.asc_CChartStyle();
			chartStyle.asc_setStyle(style + 1);
			chartStyle.asc_setImageUrl(group[style]);
			objectGroup.push(chartStyle);
		}

		return objectGroup;
	}
	else
		return null;
};

function CreateAscColorByIndex(nIndex)
{
	var oColor = new Asc.asc_CColor();
	oColor.type = Asc.c_oAscColor.COLOR_TYPE_SCHEME;
	oColor.value = nIndex;
	return oColor;
}

function CreateAscFillByIndex(nIndex)
{
	var oAscFill = new Asc.asc_CShapeFill();
	oAscFill.type = Asc.c_oAscFill.FILL_TYPE_SOLID;
	oAscFill.fill = new Asc.asc_CFillSolid();
	oAscFill.fill.color = CreateAscColorByIndex(nIndex);
	return oAscFill;
}

function CreateAscGradFillByIndex(nIndex1, nIndex2, nAngle)
{
	var oAscFill = new Asc.asc_CShapeFill();
	oAscFill.type = Asc.c_oAscFill.FILL_TYPE_GRAD;
	oAscFill.fill = new Asc.asc_CFillGrad();
	oAscFill.fill.GradType = Asc.c_oAscFillGradType.GRAD_LINEAR;
	oAscFill.fill.LinearAngle = nAngle;
	oAscFill.fill.LinearScale = true;
	oAscFill.fill.Colors = [CreateAscColorByIndex(nIndex1), CreateAscColorByIndex(nIndex2)];
	oAscFill.fill.Positions = [0, 100000];
	oAscFill.fill.LinearAngle = nAngle;
	oAscFill.fill.LinearScale = true;
	return oAscFill;
}
function TextArtPreviewManager()
{
	this.canvas = null;
	this.canvasWidth = 50;
	this.canvasHeight = 50;
	this.shapeWidth = 50;
	this.shapeHeight = 50;
	this.TAShape = null;
	this.TextArtStyles = [];

	this.aStylesByIndex = [];
	this.aStylesByIndexToApply = [];

	this.dKoeff = 4;
	//if (AscBrowser.isRetina) {
	//	this.dKoeff <<= 1;
	//}
}
TextArtPreviewManager.prototype.initStyles = function()
{

	var oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = AscFormat.CorrectUniFill(CreateAscFillByIndex(24), new AscFormat.CUniFill(), 0);
	oTextPr.TextOutline = CreateNoFillLine();
	this.aStylesByIndex[0] = oTextPr;
	this.aStylesByIndexToApply[0] = oTextPr;

	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = AscFormat.CorrectUniFill(CreateAscGradFillByIndex(52, 24, 5400000), new AscFormat.CUniFill(), 0);
	oTextPr.TextOutline = CreateNoFillLine();
	this.aStylesByIndex[4] = oTextPr;
	this.aStylesByIndexToApply[4] = oTextPr;

	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = AscFormat.CorrectUniFill(CreateAscGradFillByIndex(44, 42, 5400000), new AscFormat.CUniFill(), 0);
	oTextPr.TextOutline = CreateNoFillLine();
	this.aStylesByIndex[8] = oTextPr;
	this.aStylesByIndexToApply[8] = oTextPr;

	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = CreateNoFillUniFill();
	oTextPr.TextOutline = AscFormat.CreatePenFromParams(AscFormat.CorrectUniFill(CreateAscFillByIndex(34), new AscFormat.CUniFill(), 0), undefined, undefined, undefined, undefined, (15773/36000)*this.dKoeff);
	this.aStylesByIndex[1] = oTextPr;
	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = CreateNoFillUniFill();
	oTextPr.TextOutline = AscFormat.CreatePenFromParams(AscFormat.CorrectUniFill(CreateAscFillByIndex(34), new AscFormat.CUniFill(), 0), undefined, undefined, undefined, undefined, (15773/36000));
	this.aStylesByIndexToApply[1] = oTextPr;

	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = CreateNoFillUniFill();
	oTextPr.TextOutline = AscFormat.CreatePenFromParams(AscFormat.CorrectUniFill(CreateAscFillByIndex(59), new AscFormat.CUniFill(), 0), undefined, undefined, undefined, undefined, (15773/36000)*this.dKoeff);
	this.aStylesByIndex[5] = oTextPr;
	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = CreateNoFillUniFill();
	oTextPr.TextOutline = AscFormat.CreatePenFromParams(AscFormat.CorrectUniFill(CreateAscFillByIndex(59), new AscFormat.CUniFill(), 0), undefined, undefined, undefined, undefined, (15773/36000));
	this.aStylesByIndexToApply[5] = oTextPr;

	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = CreateNoFillUniFill();
	oTextPr.TextOutline = AscFormat.CreatePenFromParams(AscFormat.CorrectUniFill(CreateAscFillByIndex(52), new AscFormat.CUniFill(), 0), undefined, undefined, undefined, undefined, (15773/36000)*this.dKoeff);
	this.aStylesByIndex[9] = oTextPr;
	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = CreateNoFillUniFill();
	oTextPr.TextOutline = AscFormat.CreatePenFromParams(AscFormat.CorrectUniFill(CreateAscFillByIndex(52), new AscFormat.CUniFill(), 0), undefined, undefined, undefined, undefined, (15773/36000));
	this.aStylesByIndexToApply[9] = oTextPr;

	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = AscFormat.CorrectUniFill(CreateAscFillByIndex(27), new AscFormat.CUniFill(), 0);
	oTextPr.TextOutline = AscFormat.CreatePenFromParams(AscFormat.CorrectUniFill(CreateAscFillByIndex(52), new AscFormat.CUniFill(), 0), undefined, undefined, undefined, undefined, (12700/36000)*this.dKoeff);
	this.aStylesByIndex[2] = oTextPr;
	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = AscFormat.CorrectUniFill(CreateAscFillByIndex(27), new AscFormat.CUniFill(), 0);
	oTextPr.TextOutline = AscFormat.CreatePenFromParams(AscFormat.CorrectUniFill(CreateAscFillByIndex(52), new AscFormat.CUniFill(), 0), undefined, undefined, undefined, undefined, (12700/36000));
	this.aStylesByIndexToApply[2] = oTextPr;

	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = AscFormat.CorrectUniFill(CreateAscFillByIndex(42), new AscFormat.CUniFill(), 0);
	oTextPr.TextOutline = AscFormat.CreatePenFromParams(AscFormat.CorrectUniFill(CreateAscFillByIndex(46), new AscFormat.CUniFill(), 0), undefined, undefined, undefined, undefined, (12700/36000)*this.dKoeff);
	this.aStylesByIndex[6] = oTextPr;
	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = AscFormat.CorrectUniFill(CreateAscFillByIndex(42), new AscFormat.CUniFill(), 0);
	oTextPr.TextOutline = AscFormat.CreatePenFromParams(AscFormat.CorrectUniFill(CreateAscFillByIndex(46), new AscFormat.CUniFill(), 0), undefined, undefined, undefined, undefined, (12700/36000));
	this.aStylesByIndexToApply[6] = oTextPr;

	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = AscFormat.CorrectUniFill(CreateAscFillByIndex(57), new AscFormat.CUniFill(), 0);
	oTextPr.TextOutline = AscFormat.CreatePenFromParams(AscFormat.CorrectUniFill(CreateAscFillByIndex(54), new AscFormat.CUniFill(), 0), undefined, undefined, undefined, undefined, (12700/36000)*this.dKoeff);
	this.aStylesByIndex[10] = oTextPr;
	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = AscFormat.CorrectUniFill(CreateAscFillByIndex(57), new AscFormat.CUniFill(), 0);
	oTextPr.TextOutline = AscFormat.CreatePenFromParams(AscFormat.CorrectUniFill(CreateAscFillByIndex(54), new AscFormat.CUniFill(), 0), undefined, undefined, undefined, undefined, (12700/36000));
	this.aStylesByIndexToApply[10] = oTextPr;

	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = AscFormat.CorrectUniFill(CreateAscGradFillByIndex(45, 57, 0), new AscFormat.CUniFill(), 0);
	oTextPr.TextOutline = CreateNoFillLine();
	this.aStylesByIndex[3] = oTextPr;
	this.aStylesByIndexToApply[3] = oTextPr;

	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = AscFormat.CorrectUniFill(CreateAscGradFillByIndex(52, 33, 0), new AscFormat.CUniFill(), 0);
	oTextPr.TextOutline = CreateNoFillLine();
	this.aStylesByIndex[7] = oTextPr;
	this.aStylesByIndexToApply[7] = oTextPr;

	oTextPr = new CTextPr();
	oTextPr.Bold = true;
	oTextPr.TextFill = AscFormat.CorrectUniFill(CreateAscGradFillByIndex(27, 45, 5400000), new AscFormat.CUniFill(), 0);
	oTextPr.TextOutline = CreateNoFillLine();
	this.aStylesByIndex[11] = oTextPr;
	this.aStylesByIndexToApply[11] = oTextPr;
};

TextArtPreviewManager.prototype.getStylesToApply = function()
{
	if(this.aStylesByIndex.length === 0)
	{
		this.initStyles();
	}
	return this.aStylesByIndexToApply;
};

TextArtPreviewManager.prototype.clear = function()
{
	this.TextArtStyles.length = 0;
};

TextArtPreviewManager.prototype.getWordArtStyles = function()
{
	if(this.TextArtStyles.length === 0)
	{
		this.generateTextArtStyles();
	}
	return this.TextArtStyles;
};

TextArtPreviewManager.prototype.getCanvas = function()
{
	if (null === this.canvas)
	{
		this.canvas = document.createElement('canvas');
		this.canvas.width = this.canvasWidth;
		this.canvas.height = this.canvasHeight;

		if (AscCommon.AscBrowser.isRetina) {
			this.canvas.width <<= 1;
			this.canvas.height <<= 1;
		}
	}
	return this.canvas;
};

TextArtPreviewManager.prototype.getShapeByPrst = function(prst)
{
	var oShape = this.getShape();
    if(!oShape)
    {
        return null;
    }
	var oContent = oShape.getDocContent();

	var TextSpacing = undefined;
	switch(prst)
	{
		case "textButton":
		{
			TextSpacing = 4;
			oContent.AddText("abcde");
			oContent.AddNewParagraph();
			oContent.AddText("Fghi");
			oContent.AddNewParagraph();
			oContent.AddText("Jklmn");
			break;
		}
		case "textArchUp":
		case "textArchDown":
		{
			TextSpacing = 4;
			oContent.AddText("abcdefg");
			break;
		}

		case "textCircle":
		{
			TextSpacing = 4;
			oContent.AddText("abcdefghijklmnop");
			break;
		}
        case "textButtonPour":
        {
			oContent.AddText("abcde");
            oContent.AddNewParagraph();
			oContent.AddText("abc");
            oContent.AddNewParagraph();
			oContent.AddText("abcde");
            break;
        }
        case "textDeflateInflate":
        {
			oContent.AddText("abcde");
            oContent.AddNewParagraph();
			oContent.AddText("abcde");
            break;
        }
        case "textDeflateInflateDeflate":
        {
			oContent.AddText("abcde");
            oContent.AddNewParagraph();
			oContent.AddText("abcde");
            oContent.AddNewParagraph();
			oContent.AddText("abcde");
            break;
        }
		default:
		{
			oContent.AddText("abcde");
			break;
		}
	}
	oContent.Set_ApplyToAll(true);
	oContent.SetParagraphAlign(AscCommon.align_Center);
	oContent.AddToParagraph(new ParaTextPr({FontSize: 36, Spacing: TextSpacing}));
	oContent.Set_ApplyToAll(false);

	var oBodypr = oShape.getBodyPr().createDuplicate();
	oBodypr.prstTxWarp = AscFormat.ExecuteNoHistory(
		function()
		{
			return  CreatePrstTxWarpGeometry(prst)
		}, []);
	if(!oShape.bWordShape)
	{
		oShape.txBody.setBodyPr(oBodypr);
	}
	else
	{
		oShape.setBodyPr(oBodypr);
	}
	oShape.setBDeleted(false);
	oShape.recalculate();
	return oShape;
};
TextArtPreviewManager.prototype.getShape =  function()
{
	var oShape = new AscFormat.CShape();
	var oParent = null, oWorkSheet = null;
	var bWord = true;
	if (Asc['editor'] && AscCommon.c_oEditorId.Spreadsheet === Asc['editor'].getEditorId()) {
		var api_sheet = Asc['editor'];
		oShape.setWorksheet(api_sheet.wb.getWorksheet().model);
		oWorkSheet = api_sheet.wb.getWorksheet().model;
		bWord = false;
	} else {
		if (editor && editor.WordControl && Array.isArray(editor.WordControl.m_oLogicDocument.Slides)) {
			if (editor.WordControl.m_oLogicDocument.Slides[editor.WordControl.m_oLogicDocument.CurPage]) {
				oShape.setParent(editor.WordControl.m_oLogicDocument.Slides[editor.WordControl.m_oLogicDocument.CurPage]);
				oParent = editor.WordControl.m_oLogicDocument.Slides[editor.WordControl.m_oLogicDocument.CurPage];
				bWord = false;
			} else {
				return null;
			}
		}
	}
	var oParentObjects = oShape.getParentObjects();
	var oTrack = new AscFormat.NewShapeTrack("textRect", 0, 0, oParentObjects.theme, oParentObjects.master, oParentObjects.layout, oParentObjects.slide, 0);
	oTrack.track({}, oShape.convertPixToMM(this.canvasWidth), oShape.convertPixToMM(this.canvasHeight));
	oShape = oTrack.getShape(bWord, oShape.getDrawingDocument(), oShape.drawingObjects);
    oShape.setStyle(null);
    oShape.spPr.setFill(AscFormat.CreateUnfilFromRGB(255, 255, 255));
	var oBodypr = oShape.getBodyPr().createDuplicate();
	oBodypr.lIns = 0;
	oBodypr.tIns = 0;
	oBodypr.rIns = 0;
	oBodypr.bIns = 0;
	oBodypr.anchor = 1;
	if(!bWord)
	{
		oShape.txBody.setBodyPr(oBodypr);
	}
	else
	{
		oShape.setBodyPr(oBodypr);
	}
	oShape.spPr.setLn(AscFormat.CreatePenFromParams(CreateNoFillUniFill(), null, null, null, 2, null));
	if(oWorkSheet)
	{
		oShape.setWorksheet(oWorkSheet);
	}
	if(oParent)
	{
		oShape.setParent(oParent);
	}
	oShape.spPr.xfrm.setOffX(0);
	oShape.spPr.xfrm.setOffY(0);
	oShape.spPr.xfrm.setExtX(this.shapeWidth);
	oShape.spPr.xfrm.setExtY(this.shapeHeight);
	return oShape;
};

TextArtPreviewManager.prototype.getTAShape = function()
{
	if(!this.TAShape)
	{
		var oShape = this.getShape();
        if(!oShape)
        {
            return null;
        }
		var oContent = oShape.getDocContent();
		oContent.AddText("Ta");
		oContent.Set_ApplyToAll(true);
		oContent.AddToParagraph(new ParaTextPr({FontSize: 109, RFonts: {Ascii : {Name: "Arial", Index: -1}}}));
		oContent.SetParagraphAlign(AscCommon.align_Center);
		oContent.SetParagraphIndent({FirstLine: 0, Left: 0, Right: 0});
		oContent.Set_ApplyToAll(false);
		this.TAShape = oShape;
	}
	return this.TAShape;
};

TextArtPreviewManager.prototype.getWordArtPreview = function(prst)
{
	var _canvas = this.getCanvas();
	var ctx = _canvas.getContext('2d');
	var graphics = new AscCommon.CGraphics();
	var oShape = this.getShapeByPrst(prst);
    if(!oShape)
    {
        return "";
    }
	graphics.init(ctx, _canvas.width, _canvas.height, oShape.extX, oShape.extY);
	graphics.m_oFontManager = AscCommon.g_fontManager;
	graphics.transform(1,0,0,1,0,0);

	var oldShowParaMarks;
	if(editor)
	{
		oldShowParaMarks = editor.ShowParaMarks;
		editor.ShowParaMarks = false;
	}
	oShape.draw(graphics);

	if(editor)
	{
		editor.ShowParaMarks = oldShowParaMarks;
	}
	return _canvas.toDataURL("image/png");
};

TextArtPreviewManager.prototype.generateTextArtStyles = function()
{
    AscFormat.ExecuteNoHistory(function(){

        if(this.aStylesByIndex.length === 0)
        {
            this.initStyles();
        }
        var _canvas = this.getCanvas();
        var ctx = _canvas.getContext('2d');
        var graphics = new AscCommon.CGraphics();
        var oShape = this.getTAShape();
        if(!oShape)
        {
            this.TextArtStyles.length = 0;
            return;
        }
        oShape.recalculate();

        graphics.m_oFontManager = AscCommon.g_fontManager;

        var oldShowParaMarks;
        if(editor)
        {
            oldShowParaMarks = editor.ShowParaMarks;
            editor.ShowParaMarks = false;
        }
        var oContent = oShape.getDocContent();
        oContent.Set_ApplyToAll(true);
        for(var i = 0; i < this.aStylesByIndex.length; ++i)
        {
            oContent.AddToParagraph(new ParaTextPr(this.aStylesByIndex[i]));
            graphics.init(ctx, _canvas.width, _canvas.height, oShape.extX, oShape.extY);
            graphics.transform(1,0,0,1,0,0);
            oShape.recalcText();
            if(!oShape.bWordShape)
            {
                oShape.recalculate();
            }
            else
            {
                oShape.recalculateText();
            }
            oShape.draw(graphics);
            this.TextArtStyles[i] = _canvas.toDataURL("image/png");
        }
        oContent.Set_ApplyToAll(false);

        if(editor)
        {
            editor.ShowParaMarks = oldShowParaMarks;
        }
    }, this, []);
};



function GenerateWordArtPrewiewCode()
{
	var oWordArtPreview = new TextArtPreviewManager();
	var i, j;
	var oRetString =  "g_PresetTxWarpTypes = \n [";
	for(i = 0; i < g_PresetTxWarpTypes.length; ++i)
	{
		var aByTypes = g_PresetTxWarpTypes[i];
		oRetString += "\n\t[";
		for(j = 0; j < aByTypes.length; ++j)
		{
			oRetString += "\n\t\t{Type: \"" + aByTypes[j]['Type'] + "\", Image: \"" + oWordArtPreview.getWordArtPreview(aByTypes[j]['Image']) + "\"}" + ((j === aByTypes.length - 1) ? "" : ",");
		}
		oRetString += "\n\t]" + (i < (AscCommon.g_PresetTxWarpTypes.length - 1) ? "," : "");
	}
	oRetString += "\n];";
	return oRetString;
}

	//----------------------------------------------------------export----------------------------------------------------
	window['AscCommon'] = window['AscCommon'] || {};
	window['AscCommon'].ChartPreviewManager = ChartPreviewManager;
	window['AscCommon'].TextArtPreviewManager = TextArtPreviewManager;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {

//-----------------------------------------------------------------------------------
// Drawing area manager
//-----------------------------------------------------------------------------------

// Type
var FrozenAreaType = {

	Top				: "Top",
	Bottom			: "Bottom",
	Left			: "Left",
	Right			: "Right",
	Center			: "Center",		// Default without frozen places
	
	LeftTop			: "LeftTop",
	RightTop		: "RightTop",
	LeftBottom		: "LeftBottom",
	RightBottom		: "RightBottom"
};

// Frozen place
function FrozenPlace(ws, type) {
	var log = false;
	var _this = this;
	var asc = window["Asc"];
	var asc_Range = asc.Range;
	
	_this.worksheet = ws;
	_this.type = type;
	_this.range = null;
	_this.frozenCell = {
		col: _this.worksheet.topLeftFrozenCell ? _this.worksheet.topLeftFrozenCell.getCol0() : 0,
		row: _this.worksheet.topLeftFrozenCell ? _this.worksheet.topLeftFrozenCell.getRow0() : 0
	};
	_this.isValid = true;

	// Methods	
	_this.initRange = function() {
		switch (_this.type) {
		
			case FrozenAreaType.Top: {
				if (!_this.frozenCell.col && _this.frozenCell.row)
					_this.range = new asc_Range(_this.worksheet.getFirstVisibleCol(), 0, _this.worksheet.getLastVisibleCol(), _this.frozenCell.row - 1);
				else
					_this.isValid = false;
			}
			break;
			
			case FrozenAreaType.Bottom: {
				if (!_this.frozenCell.col && _this.frozenCell.row)
					_this.range = new asc_Range(0, _this.worksheet.getFirstVisibleRow(), _this.worksheet.getLastVisibleCol(), _this.worksheet.getLastVisibleRow());
				else
					_this.isValid = false;
			}
			break;
			
			case FrozenAreaType.Left: {
				if (_this.frozenCell.col && !_this.frozenCell.row)
					_this.range = new asc_Range(0, 0, _this.frozenCell.col - 1, _this.worksheet.getLastVisibleRow());
				else
					_this.isValid = false;
			}
			break;
			
			case FrozenAreaType.Right: {
				if (_this.frozenCell.col && !_this.frozenCell.row)
					_this.range = new asc_Range(_this.worksheet.getFirstVisibleCol(), 0, _this.worksheet.getLastVisibleCol(), _this.worksheet.getLastVisibleRow());
				else
					_this.isValid = false;
			}
			break;
			
			case FrozenAreaType.Center: {
				if (!_this.frozenCell.col && !_this.frozenCell.row)
					_this.range = new asc_Range(_this.worksheet.getFirstVisibleCol(true), _this.worksheet.getFirstVisibleRow(true), _this.worksheet.getLastVisibleCol(), _this.worksheet.getLastVisibleRow());
				else
					_this.isValid = false;
			}
			break;
			
			// Other
			case FrozenAreaType.LeftTop: {
				if (_this.frozenCell.col && _this.frozenCell.row)
					_this.range = new asc_Range(0, 0, _this.frozenCell.col - 1, _this.frozenCell.row - 1);
				else
					_this.isValid = false;
			}
			break;
			
			case FrozenAreaType.RightTop: {
				if (_this.frozenCell.col && _this.frozenCell.row)
					_this.range = new asc_Range(_this.worksheet.getFirstVisibleCol(), 0, _this.worksheet.getLastVisibleCol(), _this.frozenCell.row - 1);
				else
					_this.isValid = false;
			}
			break;
			
			case FrozenAreaType.LeftBottom: {
				if (_this.frozenCell.col && _this.frozenCell.row)
					_this.range = new asc_Range(0, _this.worksheet.getFirstVisibleRow(), _this.frozenCell.col - 1, _this.worksheet.getLastVisibleRow());
				else
					_this.isValid = false;
			}
			break;
			
			case FrozenAreaType.RightBottom: {
				if (_this.frozenCell.col && _this.frozenCell.row)
					_this.range = new asc_Range(_this.worksheet.getFirstVisibleCol(), _this.worksheet.getFirstVisibleRow(), _this.worksheet.getLastVisibleCol(), _this.worksheet.getLastVisibleRow());
				else
					_this.isValid = false;
			}
			break;
		}
	};
	
	_this.getVisibleRange = function() {
		var vr = _this.range.clone();
		var fv = _this.getFirstVisible();
		
		switch (_this.type) {
			// Two places
			case FrozenAreaType.Top: {
				// without changes
			}
			break;
			case FrozenAreaType.Bottom: {
				vr.r1 = fv.row;
				vr.r2 = _this.worksheet.getLastVisibleRow();
			}
			break;
			case FrozenAreaType.Left: {
				vr.r1 = fv.row;
				vr.r2 = _this.worksheet.getLastVisibleRow();
			}
			break;
			case FrozenAreaType.Right: {
				vr.c1 = fv.col;
				vr.c2 = _this.worksheet.getLastVisibleCol();
			}
			break;
			
			// Four places
			case FrozenAreaType.LeftTop: {
				// without changes
			}
			break;
			case FrozenAreaType.RightTop: {
				vr.c1 = fv.col;
				vr.c2 = _this.worksheet.getLastVisibleCol();
			}
			break;
			case FrozenAreaType.LeftBottom: {
				vr.r1 = fv.row;
				vr.r2 = _this.worksheet.getLastVisibleRow();
			}
			break;
			case FrozenAreaType.RightBottom: {
				vr.c1 = fv.col;
				vr.c2 = _this.worksheet.getLastVisibleCol();
				vr.r1 = fv.row;
				vr.r2 = _this.worksheet.getLastVisibleRow();
			}
			break;
			
			// No frozen areas
			case FrozenAreaType.Center: {
				vr.c1 = fv.col;
				vr.c2 = _this.worksheet.getLastVisibleCol();
				vr.r1 = fv.row;
				vr.r2 = _this.worksheet.getLastVisibleRow();
			}
			break;
		}
		return vr;
	};
	
	_this.getRect = function(bEvent) {
		var rect = { x: 0, y: 0, w: 0, h: 0, r: 0, b: 0 };
		rect.x = _this.worksheet.getCellLeftRelative(_this.range.c1, 0);
		rect.y = _this.worksheet.getCellTopRelative(_this.range.r1, 0);
		rect.w = _this.worksheet.getCellLeftRelative(_this.range.c2, 0) + _this.worksheet.getColumnWidth(_this.range.c2, 0) - rect.x;
		rect.h = _this.worksheet.getCellTopRelative(_this.range.r2, 0) + _this.worksheet.getRowHeight(_this.range.r2, 0) - rect.y;

        rect.r = rect.x + rect.w;
        rect.b = rect.y + rect.h;


        switch (_this.type) {

            case FrozenAreaType.Top:
            {
                rect.w = +Infinity;
                rect.r = +Infinity;
                if(bEvent)
                {
                    rect.x = -Infinity;
                    rect.y = -Infinity;
                }
                break;
            }

            case FrozenAreaType.Bottom:
            {
                rect.w = +Infinity;
                rect.h = +Infinity;
                rect.r = +Infinity;
                rect.b = +Infinity;

                if(bEvent)
                {
                    rect.x = -Infinity;
                }
                break;
            }

            case FrozenAreaType.Left:
            {
                rect.h = +Infinity;
                rect.b = +Infinity;

                if(bEvent)
                {
                    rect.x = -Infinity;
                    rect.y = -Infinity;
                }
                break;
            }

            case FrozenAreaType.Right:
            {

                rect.w = +Infinity;
                rect.h = +Infinity;
                rect.r = +Infinity;
                rect.b = +Infinity;

                if(bEvent)
                {
                    rect.y = -Infinity;
                }
                break;
            }

            case FrozenAreaType.Center:
            {
                rect.w = +Infinity;
                rect.h = +Infinity;
                rect.r = +Infinity;
                rect.b = +Infinity;
                if(bEvent)
                {
                    rect.x = -Infinity;
                    rect.y = -Infinity;
                }
                break;
            }
            // Other
            case FrozenAreaType.LeftTop:
            {
                if(bEvent)
                {
                    rect.x = -Infinity;
                    rect.y = -Infinity;
                }
                break;
            }

            case FrozenAreaType.RightTop:
            {
                rect.w = +Infinity;
                rect.r = +Infinity;
                if(bEvent)
                {
                    rect.y = -Infinity;
                }
                break;
            }

            case FrozenAreaType.LeftBottom:
            {
                rect.h = +Infinity;
                rect.b = +Infinity;
                if(bEvent)
                {
                    rect.x = -Infinity;
                }
                break;
            }

            case FrozenAreaType.RightBottom:
            {
                rect.w = +Infinity;
                rect.h = +Infinity;
                rect.r = +Infinity;
                rect.b = +Infinity;
                break;
            }
        }

		return rect;
	};

    _this.getRect2 = function() {
        var rect = { x: 0, y: 0, w: 0, h: 0 };
        rect.x = _this.worksheet.getCellLeftRelative(_this.range.c1, 0);
        rect.y = _this.worksheet.getCellTopRelative(_this.range.r1, 0);
        rect.w = _this.worksheet.getCellLeftRelative(_this.range.c2, 0) + _this.worksheet.getColumnWidth(_this.range.c2, 0) - rect.x;
        rect.h = _this.worksheet.getCellTopRelative(_this.range.r2, 0) + _this.worksheet.getRowHeight(_this.range.r2, 0) - rect.y;
        return rect;
    };



	_this.getFirstVisible = function() {
		var fv = { col: 0, row: 0 };
		
		switch (_this.type) {
			// Two places
			case FrozenAreaType.Top: {
				fv.col = _this.worksheet.getFirstVisibleCol();
			}
			break;
			
			case FrozenAreaType.Bottom: {
				fv.col = _this.worksheet.getFirstVisibleCol();
				fv.row = _this.worksheet.getFirstVisibleRow();
			}
			break;
			
			case FrozenAreaType.Left: {
				fv.row = _this.worksheet.getFirstVisibleRow();
			}
			break;
			
			case FrozenAreaType.Right: {
				fv.col = _this.worksheet.getFirstVisibleCol();
				fv.row = _this.worksheet.getFirstVisibleRow();
			}
			break;
			
			// Four places
			case FrozenAreaType.LeftTop: {
			}
			break;
			
			case FrozenAreaType.RightTop: {
				fv.col = _this.worksheet.getFirstVisibleCol();
			}
			break;
			
			case FrozenAreaType.LeftBottom: {
				fv.row = _this.worksheet.getFirstVisibleRow();
			}
			break;
			
			case FrozenAreaType.RightBottom: {
				fv.col = _this.worksheet.getFirstVisibleCol();
				fv.row = _this.worksheet.getFirstVisibleRow();
			}
			break;
			
			// No frozen areas
			case FrozenAreaType.Center: {
				fv.col = _this.worksheet.getFirstVisibleCol();
				fv.row = _this.worksheet.getFirstVisibleRow();
			}
			break;
		}
		
		return fv;
	};
	
	_this.isPointInside = function(x, y, bEvent)
    {
        var rect = _this.getRect(bEvent);
         var result = (x >= rect.x ) && (y >= rect.y) && (x <= rect.r) && (y <= rect.b);
         if ( log && result )
         console.log( x + "," + y + " in " + _this.type);
         return result;
	};
	
	_this.isCellInside = function(cell) {
		var result = false;
		if (cell && _this.range) {
			var cellRange = new asc_Range(cell.col, cell.row, cell.col, cell.row);
			result = _this.range.isIntersect(cellRange);
		}
		return result;
	};
	
	_this.isObjectInside = function(object) {
		// TODO Нужно учитывать collOff, rowOff

        var boundsFromTo = object.boundsFromTo;
		var objectRange = new asc_Range(boundsFromTo.from.col, boundsFromTo.from.row, boundsFromTo.to.col, boundsFromTo.to.row);
		return _this.range.isIntersect(objectRange);
	};
	
	_this.getVerticalScroll = function() {
		
		// No scroll for Top, LeftTop, RightTop
		var scroll = 0;
		var fv = _this.getFirstVisible();
		var headerPx = _this.worksheet._getRowTop(0);
		
		switch (_this.type) {
			// Two places
			case FrozenAreaType.Top: {
				scroll = headerPx;
			}
			break;
			
			case FrozenAreaType.Bottom: {
				scroll = -(_this.worksheet._getRowTop(fv.row) - _this.worksheet._getRowTop(_this.frozenCell.row)) + headerPx;
			}
			break;
			
			case FrozenAreaType.Left:
			case FrozenAreaType.Right: {
				scroll = -(_this.worksheet._getRowTop(fv.row) - _this.worksheet.cellsTop) + headerPx;
			}
			break;
			
			// Four places
			case FrozenAreaType.LeftTop:
			case FrozenAreaType.RightTop: {
				scroll = headerPx;
			}
			break;
			
			case FrozenAreaType.LeftBottom:
			case FrozenAreaType.RightBottom: {
				scroll = -(_this.worksheet._getRowTop(fv.row) - _this.worksheet._getRowTop(_this.frozenCell.row)) + headerPx;
			}
			break;
			
			// No frozen areas
			case FrozenAreaType.Center: {
				scroll = -(_this.worksheet._getRowTop(fv.row) - _this.worksheet.cellsTop) + headerPx;
			}
			break;
		}
		return scroll;
	};
	
	_this.getHorizontalScroll = function() {
		
		// No scroll for Left, LeftTop, LeftBottom
		var scroll = 0;
		var fv = _this.getFirstVisible();
		var headerPx = _this.worksheet._getColLeft(0);
		
		switch (_this.type) {
			// Two places
			case FrozenAreaType.Top:
			case FrozenAreaType.Bottom: {
				scroll = -(_this.worksheet._getColLeft(fv.col) - _this.worksheet.cellsLeft) + headerPx;
			}
			break;
			
			case FrozenAreaType.Left: {
				scroll = headerPx;
			}
			break;
			
			case FrozenAreaType.Right: {
				scroll = -(_this.worksheet._getColLeft(fv.col) - _this.worksheet._getColLeft(_this.frozenCell.col)) + headerPx;
			}
			break;
			
			// Four places
			case FrozenAreaType.LeftTop:
			case FrozenAreaType.LeftBottom: {
				scroll = headerPx;
			}
			break;
			
			case FrozenAreaType.RightTop:
			case FrozenAreaType.RightBottom: {
				scroll = -(_this.worksheet._getColLeft(fv.col) - _this.worksheet._getColLeft(_this.frozenCell.col)) + headerPx;
			}
			break;			
			
			// No frozen areas
			case FrozenAreaType.Center: {
				scroll = -(_this.worksheet._getColLeft(fv.col) - _this.worksheet.cellsLeft) + headerPx;
			}
			break;
		}
		return scroll;
	};
	
	_this.clip = function(canvas) {
		var rect = _this.getRect2();
		canvas.m_oContext.save();
		canvas.m_oContext.beginPath();
		canvas.m_oContext.rect(rect.x, rect.y, rect.w, rect.h);
		canvas.m_oContext.clip();
        // этот сэйв нужен для восстановления сложных вложенных клипов
        canvas.m_oContext.save();
	};
	
	_this.restore = function(canvas) {
		canvas.m_oContext.restore();
		// этот рестор нужен для восстановления сложных вложенных клипов
        canvas.m_oContext.restore();
	};
	
	_this.drawObject = function(object) {
		var canvas = _this.worksheet.objectRender.getDrawingCanvas();
		_this.setTransform(canvas.shapeCtx, canvas.shapeOverlayCtx, canvas.autoShapeTrack);
		
		_this.clip(canvas.shapeCtx);
		object.graphicObject.draw(canvas.shapeCtx);
		
		// Lock
		if ( (object.graphicObject.lockType !== undefined) && (object.graphicObject.lockType !== AscCommon.c_oAscLockTypes.kLockTypeNone) ) {
			var oApi = Asc['editor'];
			if(oApi){
				if (!oApi.collaborativeEditing.getFast() || object.graphicObject.lockType !== AscCommon.c_oAscLockTypes.kLockTypeMine){
					canvas.shapeCtx.SetIntegerGrid(false);
					canvas.shapeCtx.transform3(object.graphicObject.transform, false);
					canvas.shapeCtx.DrawLockObjectRect(object.graphicObject.lockType, 0, 0, object.graphicObject.extX, object.graphicObject.extY );
					canvas.shapeCtx.reset();
					canvas.shapeCtx.SetIntegerGrid(true);
				}
			}
		}
					
		_this.restore(canvas.shapeCtx);
	};
	
	_this.setTransform = function(shapeCtx, shapeOverlayCtx, autoShapeTrack, trackOverlay) {
		
		if ( shapeCtx && shapeOverlayCtx && autoShapeTrack ) {
			
			var x = _this.getHorizontalScroll();
			var y = _this.getVerticalScroll();

			shapeCtx.m_oCoordTransform.tx = x;
			shapeCtx.m_oCoordTransform.ty = y;
			shapeCtx.CalculateFullTransform();
			
			shapeOverlayCtx.m_oCoordTransform.tx = x;
			shapeOverlayCtx.m_oCoordTransform.ty = y;
			shapeOverlayCtx.CalculateFullTransform();
			
			autoShapeTrack.Graphics.m_oCoordTransform.tx = x;
			autoShapeTrack.Graphics.m_oCoordTransform.ty = y;
			autoShapeTrack.Graphics.CalculateFullTransform();
            _this.worksheet.objectRender.controller.recalculateCurPos();
		}
        if(trackOverlay && trackOverlay.m_oHtmlPage)
        {
            var width = trackOverlay.m_oHtmlPage.drawingPage.right -  trackOverlay.m_oHtmlPage.drawingPage.left;
            var height = trackOverlay.m_oHtmlPage.drawingPage.bottom -  trackOverlay.m_oHtmlPage.drawingPage.top;
            trackOverlay.m_oHtmlPage.drawingPage.left = x;
            trackOverlay.m_oHtmlPage.drawingPage.top  = y;
            trackOverlay.m_oHtmlPage.drawingPage.right = x + width;
            trackOverlay.m_oHtmlPage.drawingPage.bottom  = y + height;
        }
	};
	
	// Range constructor	
	_this.initRange();
}

// Container
function DrawingArea(ws) {

    var asc = window["Asc"];
    this.api = asc["editor"];

    this.worksheet = ws;
    this.frozenPlaces = [];
}

DrawingArea.prototype.init = function() {
    this.frozenPlaces = [];
    if ( this.worksheet ) {
        var place;
        if ( this.worksheet.topLeftFrozenCell ) {
            place = new FrozenPlace(this.worksheet, FrozenAreaType.Top);
            if ( place.isValid )
                this.frozenPlaces.push(place);
            place = new FrozenPlace(this.worksheet, FrozenAreaType.Bottom);
            if ( place.isValid )
                this.frozenPlaces.push(place);
            place = new FrozenPlace(this.worksheet, FrozenAreaType.Left);
            if ( place.isValid )
                this.frozenPlaces.push(place);
            place = new FrozenPlace(this.worksheet, FrozenAreaType.Right);
            if ( place.isValid )
                this.frozenPlaces.push(place);

            place = new FrozenPlace(this.worksheet, FrozenAreaType.LeftTop);
            if ( place.isValid )
                this.frozenPlaces.push(place);
            place = new FrozenPlace(this.worksheet, FrozenAreaType.RightTop);
            if ( place.isValid )
                this.frozenPlaces.push(place);
            place = new FrozenPlace(this.worksheet, FrozenAreaType.LeftBottom);
            if ( place.isValid )
                this.frozenPlaces.push(place);
            place = new FrozenPlace(this.worksheet, FrozenAreaType.RightBottom);
            if ( place.isValid )
                this.frozenPlaces.push(place);
        }
        else
            this.frozenPlaces.push(new FrozenPlace(this.worksheet, FrozenAreaType.Center));
    }
};

DrawingArea.prototype.clear = function() {
    this.worksheet.drawingGraphicCtx.clear();
};

DrawingArea.prototype.drawObject = function(object) {
    for ( var i = 0; i < this.frozenPlaces.length; i++ ) {
        if ( this.frozenPlaces[i].isObjectInside(object) ) {
            this.frozenPlaces[i].drawObject(object);
        }
    }
};

DrawingArea.prototype.reinitRanges = function() {
    for ( var i = 0; i < this.frozenPlaces.length; i++ ) {
        this.frozenPlaces[i].initRange();
    }
};

DrawingArea.prototype.drawSelection = function(drawingDocument) {

    var canvas = this.worksheet.objectRender.getDrawingCanvas();
    var shapeCtx = canvas.shapeCtx;
    var shapeOverlayCtx = canvas.shapeOverlayCtx;
    var autoShapeTrack = canvas.autoShapeTrack;
    var trackOverlay = canvas.trackOverlay;

    var ctx = trackOverlay.m_oContext;
    trackOverlay.Clear();
    drawingDocument.Overlay = trackOverlay;

    this.worksheet.overlayCtx.clear();
    this.worksheet.overlayGraphicCtx.clear();
    this.worksheet._drawCollaborativeElements();

    if ( !this.worksheet.objectRender.controller.selectedObjects.length && !this.api.isStartAddShape )
        this.worksheet._drawSelection();

    var chart;
    var controller = this.worksheet.objectRender.controller;
    var selected_objects = controller.selection.groupSelection ? controller.selection.groupSelection.selectedObjects : controller.selectedObjects;
    if(selected_objects.length === 1 && selected_objects[0].getObjectType() === AscDFH.historyitem_type_ChartSpace)
    {
        chart = selected_objects[0];
        this.worksheet.objectRender.selectDrawingObjectRange(chart);
        //shapeOverlayCtx.ClearMode = true;
        ////selected_objects[0].draw(shapeOverlayCtx);
        //shapeOverlayCtx.ClearMode = false;
    }
    for ( var i = 0; i < this.frozenPlaces.length; i++ ) {

        this.frozenPlaces[i].setTransform(shapeCtx, shapeOverlayCtx, autoShapeTrack, trackOverlay);

        // Clip
        this.frozenPlaces[i].clip(shapeOverlayCtx);

		if (drawingDocument.m_bIsSelection) {
			drawingDocument.SelectionMatrix = null;
			trackOverlay.m_oControl.HtmlElement.style.display = "block";

			if (null == trackOverlay.m_oContext)
				trackOverlay.m_oContext = trackOverlay.m_oControl.HtmlElement.getContext('2d');

			drawingDocument.private_StartDrawSelection(trackOverlay);
			this.worksheet.objectRender.controller.drawTextSelection();
			drawingDocument.private_EndDrawSelection();

			this.worksheet.handlers.trigger("drawMobileSelection");
		}

		ctx.globalAlpha = 1.0;

		this.worksheet.objectRender.controller.drawSelection(drawingDocument);


		if ( this.worksheet.objectRender.controller.needUpdateOverlay() ) {
			trackOverlay.Show();
			autoShapeTrack.Graphics.put_GlobalAlpha(true, 0.5);
			this.worksheet.objectRender.controller.drawTracks(autoShapeTrack);
			autoShapeTrack.Graphics.put_GlobalAlpha(true, 1);
			this.frozenPlaces[i].restore(autoShapeTrack);
		}


        // Restore
        this.frozenPlaces[i].restore(autoShapeTrack);


		var nShadowLength = 10;
		var fLeft, fTop, fRight, fBottom;
		if(this.frozenPlaces[i].type === FrozenAreaType.Bottom){
			//autoShapeTrack.Graphics.put_GlobalAlpha(true, 1);
			fTop = this.worksheet._getRowTop(this.frozenPlaces[i].frozenCell.row);
			fLeft = 0;
			autoShapeTrack.drawImage(AscFormat.sFrozenImageUrl, fLeft, fTop, autoShapeTrack.Graphics.m_lWidthPix, nShadowLength);
		}
		else if(this.frozenPlaces[i].type === FrozenAreaType.Right){
			fTop = 0;
			fLeft = this.worksheet._getColLeft(this.frozenPlaces[i].frozenCell.col);
			autoShapeTrack.drawImage(AscFormat.sFrozenImageRotUrl, fLeft, fTop, nShadowLength, autoShapeTrack.Graphics.m_lHeightPix);
		}
		else if(this.frozenPlaces[i].type === FrozenAreaType.RightBottom){
			//autoShapeTrack.Graphics.put_GlobalAlpha(true, 1);
			fTop = this.worksheet._getRowTop(this.frozenPlaces[i].frozenCell.row);
			fLeft = this.worksheet._getColLeft(this.frozenPlaces[i].frozenCell.col);
			autoShapeTrack.drawImage(AscFormat.sFrozenImageUrl, fLeft, fTop, autoShapeTrack.Graphics.m_lWidthPix, nShadowLength);
			autoShapeTrack.drawImage(AscFormat.sFrozenImageRotUrl, fLeft, fTop, nShadowLength, autoShapeTrack.Graphics.m_lHeightPix);
		}
		else if(this.frozenPlaces[i].type === FrozenAreaType.LeftBottom){
			fTop = this.worksheet._getRowTop(this.frozenPlaces[i].frozenCell.row);
			fLeft = 0;
			fRight = this.worksheet._getColLeft(this.frozenPlaces[i].frozenCell.col);
			autoShapeTrack.drawImage(AscFormat.sFrozenImageUrl, fLeft, fTop, fRight, nShadowLength);
		}
		else if(this.frozenPlaces[i].type === FrozenAreaType.RightTop){
			fTop = 0;
			fLeft = this.worksheet._getColLeft(this.frozenPlaces[i].frozenCell.col);
			fBottom = this.worksheet._getRowTop(this.frozenPlaces[i].frozenCell.row);
			autoShapeTrack.drawImage(AscFormat.sFrozenImageRotUrl, fLeft, fTop, nShadowLength, fBottom);
		}

    }
};

DrawingArea.prototype.getOffsets = function(x, y, bEvents) {
        for ( var i = 0; i < this.frozenPlaces.length; i++ ) {
            if ( this.frozenPlaces[i].isPointInside(x, y, bEvents) ) {
                return { x: this.frozenPlaces[i].getHorizontalScroll(), y: this.frozenPlaces[i].getVerticalScroll() }
            }
        }
        return null;
    };

	//--------------------------------------------------------export----------------------------------------------------
	window['AscFormat'] = window['AscFormat'] || {};
	window['AscFormat'].DrawingArea = DrawingArea;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {

    
    var sFrozenImageUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAKCAYAAAB10jRKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTZEaa/1AAAAJElEQVQYV2MAAjUQoQIiFECEDIiQABHCIIIPRHCBCDYgZmACABohANImre1SAAAAAElFTkSuQmCC';
    //var sFrozenImageUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAQAAAD41K0JAAAAD0lEQVR42mNgEGJmAAJmAACcABmX0vttAAAAAElFTkSuQmCC';
    var sFrozenImageRotUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAABCAYAAADn9T9+AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTZEaa/1AAAAGklEQVQYV2NkYGBQA+J/QPwHCf+GYiif4Q8AnJAJBNqB9DYAAAAASUVORK5CYII='
// Import
var c_oAscCellAnchorType = AscCommon.c_oAscCellAnchorType;
var c_oAscLockTypes = AscCommon.c_oAscLockTypes;
var parserHelp = AscCommon.parserHelp;
var gc_nMaxRow = AscCommon.gc_nMaxRow;
var gc_nMaxCol = AscCommon.gc_nMaxCol;
    var History = AscCommon.History;

var BBoxInfo = AscFormat.BBoxInfo;
var MOVE_DELTA = AscFormat.MOVE_DELTA;

var c_oAscError = Asc.c_oAscError;
var c_oAscChartTypeSettings = Asc.c_oAscChartTypeSettings;
var c_oAscChartTitleShowSettings = Asc.c_oAscChartTitleShowSettings;
var c_oAscGridLinesSettings = Asc.c_oAscGridLinesSettings;
var c_oAscValAxisRule = Asc.c_oAscValAxisRule;
var c_oAscInsertOptions = Asc.c_oAscInsertOptions;
var c_oAscDeleteOptions = Asc.c_oAscDeleteOptions;
var c_oAscSelectionType = Asc.c_oAscSelectionType;
var global_mouseEvent = AscCommon.global_mouseEvent;

var aSparklinesStyles =
[
    [
        [4, -0.499984740745262],
        [5, 0],
        [4, -0.499984740745262],
        [4,  0.39997558519241921],
        [4, 0.39997558519241921],
        [4, 0],
        [4, 0]
    ],
    [
        [5, -0.499984740745262],
        [6, 0],
        [5,  -0.499984740745262],
        [5, 0.39997558519241921],
        [5, 0.39997558519241921],
        [5, 0],
        [5, 0]
    ],
    [
        [6, -0.499984740745262],
        [7, 0],
        [6, -0.499984740745262],
        [6, 0.39997558519241921],
        [6, 0.39997558519241921],
        [6, 0],
        [6, 0]
    ],
    [
        [7, -0.499984740745262],
        [8, 0],
        [7, -0.499984740745262],
        [7, 0.39997558519241921],
        [7, 0.39997558519241921],
        [7, 0],
        [7, 0]
    ],
    [
        [8, -0.499984740745262],
        [9, 0],
        [8, -0.499984740745262],
        [8, 0.39997558519241921],
        [8, 0.39997558519241921],
        [8, 0],
        [8, 0]
    ],
    [
        [9, -0.499984740745262],
        [4, 0],

        [9, -0.499984740745262],
        [9, 0.39997558519241921],
        [9, 0.39997558519241921],
        [9, 0],
        [9, 0]
    ],
    [
        [4, -0.249977111117893],
        [5, 0],
        [5, -0.249977111117893],
        [5, -0.249977111117893],
        [5, -0.249977111117893],
        [5, -0.249977111117893],
        [5, -0.249977111117893]
    ],
    [
        [5, -0.249977111117893],
        [6, 0],
        [6, -0.249977111117893],
        [6, -0.249977111117893],
        [6, -0.249977111117893],
        [6, -0.249977111117893],
        [6, -0.249977111117893]
    ],
    [
        [6, -0.249977111117893],
        [7, 0],
        [7, -0.249977111117893],
        [7, -0.249977111117893],
        [7, -0.249977111117893],
        [7, -0.249977111117893],
        [7, -0.249977111117893]
    ],
    [
        [7, -0.249977111117893],
        [8, 0],
        [8, -0.249977111117893],
        [8, -0.249977111117893],
        [8, -0.249977111117893],
        [8, -0.249977111117893],
        [8, -0.249977111117893]
    ],
    [
        [8, -0.249977111117893],
        [9, 0],
        [9, -0.249977111117893],
        [9, -0.249977111117893],
        [9, -0.249977111117893],
        [9, -0.249977111117893],
        [9, -0.249977111117893]
    ],
    [
        [9, -0.249977111117893],
        [4, 0],
        [4, -0.249977111117893],
        [4, -0.249977111117893],
        [4, -0.249977111117893],
        [4, -0.249977111117893],
        [4, -0.249977111117893]
    ],
    [
        [4, 0],
        [5, 0],
        [4, -0.249977111117893],
        [4, -0.249977111117893],
        [4, -0.249977111117893],
        [4, -0.249977111117893],
        [4, -0.249977111117893]
    ],
    [
        [5, 0],
        [6, 0],
        [5, -0.249977111117893],
        [5, -0.249977111117893],
        [5, -0.249977111117893],
        [5, -0.249977111117893],
        [5, -0.249977111117893]
    ],
    [
        [6, 0],
        [7, 0],
        [6, -0.249977111117893],
        [6, -0.249977111117893],
        [6, -0.249977111117893],
        [6, -0.249977111117893],
        [6, -0.249977111117893]
    ],
    [
        [7, 0],
        [8, 0],
        [7, -0.249977111117893],
        [7, -0.249977111117893],
        [7, -0.249977111117893],
        [7, -0.249977111117893],
        [7, -0.249977111117893]
    ],
    [
        [8, 0],
        [9, 0],
        [8, -0.249977111117893],
        [8, -0.249977111117893],
        [8, -0.249977111117893],
        [8, -0.249977111117893],
        [8, -0.249977111117893]
    ],
    [
        [9, 0],
        [4, 0],
        [9, -0.249977111117893],
        [9, -0.249977111117893],
        [9, -0.249977111117893],
        [9, -0.249977111117893],
        [9, -0.249977111117893]
    ],
    [
        [4, 0.39997558519241921],
        [0, -0.499984740745262],
        [4, 0.79998168889431442],
        [4, -0.249977111117893],
        [4, -0.249977111117893],
        [4, -0.499984740745262],
        [4, -0.499984740745262]
    ],
    [
        [5, 0.39997558519241921],
        [0, -0.499984740745262],
        [5, 0.79998168889431442],
        [5, -0.249977111117893],
        [5, -0.249977111117893],
        [5, -0.499984740745262],
        [5, -0.499984740745262]
    ],
    [
        [6, 0.39997558519241921],
        [0, -0.499984740745262],
        [6, 0.79998168889431442],
        [6, -0.249977111117893],
        [6, -0.249977111117893],
        [6, -0.499984740745262],
        [6, -0.499984740745262]
    ],
    [
        [7, 0.39997558519241921],
        [0, -0.499984740745262],
        [7, 0.79998168889431442],
        [7, -0.249977111117893],
        [7, -0.249977111117893],
        [7, -0.499984740745262],
        [7, -0.499984740745262]
    ],
    [
        [8, 0.39997558519241921],
        [0, -0.499984740745262],
        [8, 0.79998168889431442],
        [8, -0.249977111117893],
        [8, -0.249977111117893],
        [8, -0.499984740745262],
        [8, -0.499984740745262]
    ],
    [
        [9, 0.39997558519241921],
        [0, -0.499984740745262],
        [9, 0.79998168889431442],
        [9, -0.249977111117893],
        [9, -0.249977111117893],
        [9, -0.499984740745262],
        [9, -0.499984740745262]
    ],
    [
        [1, 0.499984740745262],
        [1, 0.249977111117893],
        [1, 0.249977111117893],
        [1, 0.249977111117893],
        [1, 0.249977111117893],
        [1, 0.249977111117893],
        [1, 0.249977111117893]
    ],
    [
        [1, 0.34998626667073579],
        [0, -0.249977111117893],
        [0, -0.249977111117893],
        [0, -0.249977111117893],
        [0, -0.249977111117893],
        [0, -0.249977111117893],
        [0, -0.249977111117893]
    ],
    [
        [0xFF323232],
        [0xFFD00000],
        [0xFFD00000],
        [0xFFD00000],
        [0xFFD00000],
        [0xFFD00000],
        [0xFFD00000]
    ],
    [
        [0xFF000000],
        [0xFF0070C0],
        [0xFF0070C0],
        [0xFF0070C0],
        [0xFF0070C0],
        [0xFF0070C0],
        [0xFF0070C0]
    ],
    [
        [0xFF376092],
        [0xFFD00000],
        [0xFFD00000],
        [0xFFD00000],
        [0xFFD00000],
        [0xFFD00000],
        [0xFFD00000]
    ],
    [
        [0xFF0070C0],
        [0xFF000000],
        [0xFF000000],
        [0xFF000000],
        [0xFF000000],
        [0xFF000000],
        [0xFF000000]
    ],
    [
        [0xFF5F5F5F],
        [0xFFFFB620],
        [0xFFD70077],
        [0xFF5687C2],
        [0xFF359CEB],
        [0xFF56BE79],
        [0xFFFF5055]
    ],
    [
        [0xFF5687C2],
        [0xFFFFB620],
        [0xFFD70077],
        [0xFF777777],
        [0xFF359CEB],
        [0xFF56BE79],
        [0xFFFF5055]
    ],
    [
        [0xFFC6EFCE],
        [0xFFFFC7CE],
        [0xFF8CADD6],
        [0xFFFFDC47],
        [0xFFFFEB9C],
        [0xFF60D276],
        [0xFFFF5367]
    ],
    [
        [0xFF00B050],
        [0xFFFF0000],
        [0xFF0070C0],
        [0xFFFFC000],
        [0xFFFFC000],
        [0xFF00B050],
        [0xFFFF0000]
    ],
    [
        [3, 0],
        [9, 0],
        [8, 0],
        [4, 0],
        [5, 0],
        [6, 0],
        [7, 0]
    ],
    [
        [1, 0],
        [9, 0],
        [8, 0],
        [4, 0],
        [5, 0],
        [6, 0],
        [7, 0]
    ]
];

function isObject(what) {
    return ( (what != null) && (typeof(what) == "object") );
}

function DrawingBounds(minX, maxX, minY, maxY)
{
    this.minX = minX;
    this.maxX = maxX;
    this.minY = minY;
    this.maxY = maxY;
}

function getCurrentTime() {
    var currDate = new Date();
    return currDate.getTime();
}

function roundPlus(x, n) { //x - число, n - количество знаков 
    if ( isNaN(x) || isNaN(n) ) return false;
    var m = Math.pow(10,n);
    return Math.round(x * m) / m;
}

// Класс для информации о ячейке для объектов ToDo возможно стоит поправить
function CCellObjectInfo () {
	this.col = 0;
	this.row = 0;
	this.colOff = 0;
	this.rowOff = 0;
	this.colOffPx = 0;
	this.rowOffPx = 0;
}

/** @constructor */
function asc_CChartStyle() {
    this.style = null;
    this.imageUrl = null;
}

asc_CChartStyle.prototype = {
    asc_getStyle: function() { return this.style; },
    asc_setStyle: function(style) { this.style = style; },

    asc_getImageUrl: function() { return this.imageUrl; },
    asc_setImageUrl: function(imageUrl) { this.imageUrl = imageUrl; }
};

/** @constructor */
function asc_CChartBinary(chart) {

    this["binary"] = null;
    if (chart && chart.getObjectType() === AscDFH.historyitem_type_ChartSpace)
    {
        var writer = new AscCommon.BinaryChartWriter(new AscCommon.CMemory(false)), pptx_writer;
        writer.WriteCT_ChartSpace(chart);
        this["binary"] = writer.memory.pos + ";" + writer.memory.GetBase64Memory();
        if(chart.theme)
        {
            pptx_writer = new AscCommon.CBinaryFileWriter();
            pptx_writer.WriteTheme(chart.theme);
            this["themeBinary"] = pptx_writer.pos + ";" + pptx_writer.GetBase64Memory();
        }
        if(chart.colorMapOverride)
        {
            pptx_writer = new AscCommon.CBinaryFileWriter();
            pptx_writer.WriteRecord1(1, chart.colorMapOverride, pptx_writer.WriteClrMap);
            this["colorMapBinary"] = pptx_writer.pos + ";" + pptx_writer.GetBase64Memory();
        }
        this["urls"] = JSON.stringify(AscCommon.g_oDocumentUrls.getUrls());
        if(chart.parent && chart.parent.docPr){
            this["cTitle"] = chart.parent.docPr.title;
            this["cDescription"] = chart.parent.docPr.descr;
        }
        else{
            this["cTitle"] = chart.getTitle();
            this["cDescription"] = chart.getDescription();
        }
    }
}

asc_CChartBinary.prototype = {

    asc_getBinary: function() { return this["binary"]; },
    asc_setBinary: function(val) { this["binary"] = val; },
    asc_getThemeBinary: function() { return this["themeBinary"]; },
    asc_setThemeBinary: function(val) { this["themeBinary"] = val; },
    asc_setColorMapBinary: function(val){this["colorMapBinary"] = val;},
    asc_getColorMapBinary: function(){return this["colorMapBinary"];},
    getChartSpace: function(workSheet)
    {
        var binary = this["binary"];
        var stream = AscFormat.CreateBinaryReader(this["binary"], 0, this["binary"].length);
        //надо сбросить то, что остался после открытия документа
        AscCommon.pptx_content_loader.Clear();
        var oNewChartSpace = new AscFormat.CChartSpace();
        var oBinaryChartReader = new AscCommon.BinaryChartReader(stream);
        oBinaryChartReader.ExternalReadCT_ChartSpace(stream.size , oNewChartSpace, workSheet);
        return oNewChartSpace;
    },

    getTheme: function()
    {
        var binary = this["themeBinary"];
        if(binary)
        {
            var stream = AscFormat.CreateBinaryReader(binary, 0, binary.length);
            var oBinaryReader = new AscCommon.BinaryPPTYLoader();

            oBinaryReader.stream = new AscCommon.FileStream();
            oBinaryReader.stream.obj    = stream.obj;
            oBinaryReader.stream.data   = stream.data;
            oBinaryReader.stream.size   = stream.size;
            oBinaryReader.stream.pos    = stream.pos;
            oBinaryReader.stream.cur    = stream.cur;
            return oBinaryReader.ReadTheme();
        }
        return null;
    },

    getColorMap: function()
    {
        var binary = this["colorMapBinary"];
        if(binary)
        {
            var stream = AscFormat.CreateBinaryReader(binary, 0, binary.length);
            var oBinaryReader = new AscCommon.BinaryPPTYLoader();
            oBinaryReader.stream = new AscCommon.FileStream();
            oBinaryReader.stream.obj    = stream.obj;
            oBinaryReader.stream.data   = stream.data;
            oBinaryReader.stream.size   = stream.size;
            oBinaryReader.stream.pos    = stream.pos;
            oBinaryReader.stream.cur    = stream.cur;
            var _rec = oBinaryReader.stream.GetUChar();
            var ret = new AscFormat.ClrMap();
            oBinaryReader.ReadClrMap(ret);
            return ret;
        }
        return null;
    }

};

/** @constructor */
function asc_CChartSeria() {
    this.Val = { Formula: "", NumCache: [] };
    this.xVal = { Formula: "", NumCache: [] };
    this.Cat = { Formula: "", NumCache: [] };
    this.TxCache = { Formula: "", Tx: "" };
    this.Marker = { Size: 0, Symbol: "" };
    this.FormatCode = "";
    this.isHidden = false;
}

asc_CChartSeria.prototype = {

    asc_getValFormula: function() { return this.Val.Formula; },
    asc_setValFormula: function(formula) { this.Val.Formula = formula; },

    asc_getxValFormula: function() { return this.xVal.Formula; },
    asc_setxValFormula: function(formula) { this.xVal.Formula = formula; },

    asc_getCatFormula: function() { return this.Cat.Formula; },
    asc_setCatFormula: function(formula) { this.Cat.Formula = formula; },

    asc_getTitle: function() { return this.TxCache.Tx; },
    asc_setTitle: function(title) { this.TxCache.Tx = title; },

    asc_getTitleFormula: function() { return this.TxCache.Formula; },
    asc_setTitleFormula: function(val) { this.TxCache.Formula = val; },

    asc_getMarkerSize: function() { return this.Marker.Size; },
    asc_setMarkerSize: function(size) { this.Marker.Size = size; },

    asc_getMarkerSymbol: function() { return this.Marker.Symbol; },
    asc_setMarkerSymbol: function(symbol) { this.Marker.Symbol = symbol; },

    asc_getFormatCode: function() { return this.FormatCode; },
    asc_setFormatCode: function(format) { this.FormatCode = format; }
};

var nSparklineMultiplier = 3.75;

function CSparklineView()
{
    this.col = null;
    this.row = null;
    this.ws = null;
    this.extX = null;
    this.extY = null;
    this.chartSpace = null;
}

function CreateSparklineMarker(oUniFill, bPreview)
{
    var oMarker = new AscFormat.CMarker();
    oMarker.symbol = AscFormat.SYMBOL_DIAMOND;
    oMarker.size = 10;
    if(bPreview){
        oMarker.size = 30;
    }
    oMarker.spPr = new AscFormat.CSpPr();
    oMarker.spPr.Fill = oUniFill;
    oMarker.spPr.ln = AscFormat.CreateNoFillLine();
    return oMarker;
}

function CreateUniFillFromExcelColor(oExcelColor)
{
    var oUnifill;
    /*if(oExcelColor instanceof AscCommonExcel.ThemeColor)
    {

        oUnifill = AscFormat.CreateUnifillSolidFillSchemeColorByIndex(AscCommonExcel.map_themeExcel_to_themePresentation[oExcelColor.theme]);
        if(oExcelColor.tint != null)
        {
            var unicolor = oUnifill.fill.color;
            if(!unicolor.Mods)
                unicolor.setMods(new AscFormat.CColorModifiers());
            var mod = new AscFormat.CColorMod();
            if(oExcelColor.tint > 0)
            {
                mod.setName("wordTint");
                mod.setVal(Math.round(oExcelColor.tint*255));
            }
            else
            {
                mod.setName("wordShade");
                mod.setVal(Math.round(255 + oExcelColor.tint*255));
            }
            unicolor.Mods.addMod(mod);
        }

        //oUnifill = AscFormat.CreateUniFillSchemeColorWidthTint(map_themeExcel_to_themePresentation[oExcelColor.theme], oExcelColor.tint != null ? oExcelColor.tint : 0);
    }
    else*/
    {
        oUnifill = AscFormat.CreateUnfilFromRGB(oExcelColor.getR(), oExcelColor.getG(), oExcelColor.getB())
    }
    return oUnifill;
}

CSparklineView.prototype.initFromSparkline = function(oSparkline, oSparklineGroup, worksheetView, bForPreview)
{
    AscFormat.ExecuteNoHistory(function(){
        this.ws = worksheetView;
        var settings = new Asc.asc_ChartSettings();
        var nSparklineType = oSparklineGroup.asc_getType();
        switch(nSparklineType)
        {
            case Asc.c_oAscSparklineType.Column:
            {
                settings.type = c_oAscChartTypeSettings.barNormal;
                break;
            }
            case Asc.c_oAscSparklineType.Stacked:
            {
                settings.type = c_oAscChartTypeSettings.barStackedPer;
                break;
            }
            default:
            {
                settings.type = c_oAscChartTypeSettings.lineNormal;
                break;
            }
        }
        var ser = new asc_CChartSeria();
        ser.Val.Formula = oSparkline.f;
        if(oSparkline.oCache){
            ser.Val.NumCache = oSparkline.oCache;
        }
        var chartSeries = {series: [ser], parsedHeaders: {bLeft: false, bTop: false}};
        var chart_space = AscFormat.DrawingObjectsController.prototype._getChartSpace(chartSeries, settings, true);
        chart_space.setBDeleted(false);
        if(worksheetView){
            chart_space.setWorksheet(worksheetView.model);
        }

        chart_space.displayHidden = oSparklineGroup.asc_getDisplayHidden();
        chart_space.displayEmptyCellsAs = oSparklineGroup.asc_getDisplayEmpty();
        settings.putTitle(c_oAscChartTitleShowSettings.none);
        settings.putHorAxisLabel(c_oAscChartTitleShowSettings.none);
        settings.putVertAxisLabel(c_oAscChartTitleShowSettings.none);
        settings.putLegendPos(Asc.c_oAscChartLegendShowSettings.none);
        settings.putHorGridLines(c_oAscGridLinesSettings.none);
        settings.putVertGridLines(c_oAscGridLinesSettings.none);


        chart_space.recalculateReferences();
        chart_space.recalcInfo.recalculateReferences = false;
        var oSerie = chart_space.chart.plotArea.charts[0].series[0];
        var aSeriesPoints = AscFormat.getPtsFromSeries(oSerie);

        var val_ax_props = new AscCommon.asc_ValAxisSettings();
        var i, fMinVal = null, fMaxVal = null;
        if(settings.type !== c_oAscChartTypeSettings.barStackedPer) {
            if (oSparklineGroup.asc_getMinAxisType() === Asc.c_oAscSparklineAxisMinMax.Custom && oSparklineGroup.asc_getManualMin() !== null) {
                val_ax_props.putMinValRule(c_oAscValAxisRule.fixed);
                val_ax_props.putMinVal(oSparklineGroup.asc_getManualMin());
            }
            else {
                val_ax_props.putMinValRule(c_oAscValAxisRule.auto);

					for (i = 0; i < aSeriesPoints.length; ++i) {
						if (fMinVal === null) {
							fMinVal = aSeriesPoints[i].val;
						}
						else {
							if (fMinVal > aSeriesPoints[i].val) {
								fMinVal = aSeriesPoints[i].val;
							}
						}
					}
            }
            if (oSparklineGroup.asc_getMaxAxisType() === Asc.c_oAscSparklineAxisMinMax.Custom && oSparklineGroup.asc_getManualMax() !== null) {
                val_ax_props.putMinValRule(c_oAscValAxisRule.fixed);
                val_ax_props.putMinVal(oSparklineGroup.asc_getManualMax());
            }
            else {
                val_ax_props.putMaxValRule(c_oAscValAxisRule.auto);
                for (i = 0; i < aSeriesPoints.length; ++i) {
                    if (fMaxVal === null) {
                        fMaxVal = aSeriesPoints[i].val;
                    } else {
                        if (fMaxVal < aSeriesPoints[i].val) {
                            fMaxVal = aSeriesPoints[i].val;
                        }
                    }
                }
            }
            if (fMinVal !== null && fMaxVal !== null) {
                if (fMinVal !== fMaxVal) {
                    val_ax_props.putMinValRule(c_oAscValAxisRule.fixed);
                    val_ax_props.putMinVal(fMinVal);
                    val_ax_props.putMaxValRule(c_oAscValAxisRule.fixed);
                    val_ax_props.putMaxVal(fMaxVal);
                }
            }
            else if (fMinVal !== null) {
                val_ax_props.putMinValRule(c_oAscValAxisRule.fixed);
                val_ax_props.putMinVal(fMinVal);
            }
            else if (fMaxVal !== null) {
                val_ax_props.putMaxValRule(c_oAscValAxisRule.fixed);
                val_ax_props.putMaxVal(fMaxVal);
            }
        }
        else
        {
            val_ax_props.putMinValRule(c_oAscValAxisRule.fixed);
            val_ax_props.putMinVal(-1);

            val_ax_props.putMaxValRule(c_oAscValAxisRule.fixed);
            val_ax_props.putMaxVal(1);
        }

        val_ax_props.putTickLabelsPos(Asc.c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE);
        val_ax_props.putInvertValOrder(false);
        val_ax_props.putDispUnitsRule(Asc.c_oAscValAxUnits.none);
        val_ax_props.putMajorTickMark(Asc.c_oAscTickMark.TICK_MARK_NONE);
        val_ax_props.putMinorTickMark(Asc.c_oAscTickMark.TICK_MARK_NONE);
        val_ax_props.putCrossesRule(Asc.c_oAscCrossesRule.auto);

        var cat_ax_props = new AscCommon.asc_CatAxisSettings();
        cat_ax_props.putIntervalBetweenLabelsRule(Asc.c_oAscBetweenLabelsRule.auto);
        cat_ax_props.putLabelsPosition(Asc.c_oAscLabelsPosition.betweenDivisions);
        cat_ax_props.putTickLabelsPos(Asc.c_oAscTickLabelsPos.TICK_LABEL_POSITION_NONE);
        cat_ax_props.putLabelsAxisDistance(100);
        cat_ax_props.putMajorTickMark(Asc.c_oAscTickMark.TICK_MARK_NONE);
        cat_ax_props.putMinorTickMark(Asc.c_oAscTickMark.TICK_MARK_NONE);
        cat_ax_props.putIntervalBetweenTick(1);
        cat_ax_props.putCrossesRule(Asc.c_oAscCrossesRule.auto);
        if(oSparklineGroup.rightToLeft)
        {
            cat_ax_props.putInvertCatOrder(true);
        }
        settings.putVertAxisProps(val_ax_props);
        settings.putHorAxisProps(cat_ax_props);

        AscFormat.DrawingObjectsController.prototype.applyPropsToChartSpace(settings, chart_space);

        oSerie = chart_space.chart.plotArea.charts[0].series[0];
        aSeriesPoints = AscFormat.getPtsFromSeries(oSerie);
        if(!chart_space.spPr)
            chart_space.setSpPr(new AscFormat.CSpPr());

        var new_line = new AscFormat.CLn();
        new_line.setFill(AscFormat.CreateNoFillUniFill());
        chart_space.spPr.setLn(new_line);
        chart_space.spPr.setFill(AscFormat.CreateNoFillUniFill());
        var dLineWidthSpaces = 500;
        if(!chart_space.chart.plotArea.spPr)
        {
            chart_space.chart.plotArea.setSpPr(new AscFormat.CSpPr());
            chart_space.chart.plotArea.spPr.setFill(AscFormat.CreateNoFillUniFill());
        }
        var oAxis = chart_space.chart.plotArea.getAxisByTypes();
        oAxis.valAx[0].setDelete(true);

        if(!oSerie.spPr)
        {
            oSerie.setSpPr(new AscFormat.CSpPr());
        }
        var fCallbackSeries = null;
        if(nSparklineType === Asc.c_oAscSparklineType.Line)
        {
            var oLn = new AscFormat.CLn();
            oLn.setW(36000*nSparklineMultiplier*25.4*(bForPreview ? 2.25 : oSparklineGroup.asc_getLineWeight())/72);
            oSerie.spPr.setLn(oLn);
            if(oSparklineGroup.markers && oSparklineGroup.colorMarkers)
            {
                oSerie.marker = CreateSparklineMarker(CreateUniFillFromExcelColor(oSparklineGroup.colorMarkers), bForPreview);
            }

            fCallbackSeries = function(oSeries, nIdx, oExcelColor)
            {
                for(var t = 0; t < oSeries.dPt.length; ++t)
                {
                    if(oSeries.dPt[t].idx === nIdx)
                    {
                        if(oSeries.dPt[t].marker && oSeries.dPt[t].marker.spPr)
                        {
                            oSeries.dPt[t].marker.spPr.Fill = CreateUniFillFromExcelColor(oExcelColor);
                        }
                        return;
                    }
                }
                var oDPt = new AscFormat.CDPt();
                oDPt.idx = nIdx;
                oDPt.marker = CreateSparklineMarker(CreateUniFillFromExcelColor(oExcelColor), bForPreview);
                oSeries.addDPt(oDPt);
            }
        }
        else
        {
            chart_space.chart.plotArea.charts[0].setGapWidth(30);
            chart_space.chart.plotArea.charts[0].setOverlap(50);
            fCallbackSeries = function(oSeries, nIdx, oExcelColor)
            {
                for(var t = 0; t < oSeries.dPt.length; ++t)
                {
                    if(oSeries.dPt[t].idx === nIdx)
                    {
                        if(oSeries.dPt[t].spPr)
                        {
                            if(oExcelColor){
                                oSeries.dPt[t].spPr.Fill = CreateUniFillFromExcelColor(oExcelColor);
                                oSeries.dPt[t].spPr.ln = new AscFormat.CLn();
                                oSeries.dPt[t].spPr.ln.Fill = oSeries.dPt[t].spPr.Fill.createDuplicate();
                                oSeries.dPt[t].spPr.ln.w = dLineWidthSpaces;
                            }
                            else{
                                oSeries.dPt[t].spPr.Fill = AscFormat.CreateNoFillUniFill();
                                oSeries.dPt[t].spPr.ln = AscFormat.CreateNoFillLine();
                            }
                        }
                        return;
                    }
                }

                var oDPt = new AscFormat.CDPt();
                oDPt.idx = nIdx;
                oDPt.spPr = new AscFormat.CSpPr();
                if(oExcelColor ) {
                    oDPt.spPr.Fill = CreateUniFillFromExcelColor(oExcelColor);
                    oDPt.spPr.ln = new AscFormat.CLn();
                    oDPt.spPr.ln.Fill = oDPt.spPr.Fill.createDuplicate();
                    oDPt.spPr.ln.w = dLineWidthSpaces;
                }
                else{
                    oDPt.spPr.Fill = AscFormat.CreateNoFillUniFill();
                    oDPt.spPr.ln = AscFormat.CreateNoFillLine();
                }
                oSeries.addDPt(oDPt);
            }
        }
        var aMaxPoints = null, aMinPoints = null;
        if(aSeriesPoints.length > 0)
        {
            if(fCallbackSeries)
            {


                if(oSparklineGroup.negative && oSparklineGroup.colorNegative)
                {
                    for(i = 0; i < aSeriesPoints.length; ++i)
                    {
                        if(aSeriesPoints[i].val < 0)
                        {
                            fCallbackSeries(oSerie, aSeriesPoints[i].idx, oSparklineGroup.colorNegative);
                        }
                    }
                }
                if(oSparklineGroup.last && oSparklineGroup.colorLast)
                {
                    fCallbackSeries(oSerie, aSeriesPoints[aSeriesPoints.length - 1].idx, oSparklineGroup.colorLast);
                }
                if(oSparklineGroup.first && oSparklineGroup.colorFirst)
                {
                    fCallbackSeries(oSerie, aSeriesPoints[0].idx, oSparklineGroup.colorFirst);
                }
                if(oSparklineGroup.high && oSparklineGroup.colorHigh)
                {
                    aMaxPoints = [aSeriesPoints[0]];
                    for(i = 1; i < aSeriesPoints.length; ++i)
                    {
                        if(aSeriesPoints[i].val > aMaxPoints[0].val)
                        {
                            aMaxPoints.length = 0;
                            aMaxPoints.push(aSeriesPoints[i]);
                        }
                        else if(aSeriesPoints[i].val === aMaxPoints[0].val)
                        {
                            aMaxPoints.push(aSeriesPoints[i]);
                        }
                    }
                    for(i = 0; i < aMaxPoints.length; ++i)
                    {
                        fCallbackSeries(oSerie, aMaxPoints[i].idx, oSparklineGroup.colorHigh);
                    }
                }
                if(oSparklineGroup.low && oSparklineGroup.colorLow)
                {
                    aMinPoints = [aSeriesPoints[0]];
                    for(i = 1; i < aSeriesPoints.length; ++i)
                    {
                        if(aSeriesPoints[i].val < aMinPoints[0].val)
                        {
                            aMinPoints.length = 0;
                            aMinPoints.push(aSeriesPoints[i]);
                        }
                        else if(aSeriesPoints[i].val === aMinPoints[0].val)
                        {
                            aMinPoints.push(aSeriesPoints[i]);
                        }
                    }
                    for(i = 0; i < aMinPoints.length; ++i)
                    {
                        fCallbackSeries(oSerie, aMinPoints[i].idx, oSparklineGroup.colorLow);
                    }
                }


                if(nSparklineType !== Asc.c_oAscSparklineType.Line){
                    for(i = 0; i < aSeriesPoints.length; ++i)
                    {
                        if(AscFormat.fApproxEqual(aSeriesPoints[i].val,  0))
                        {
                            fCallbackSeries(oSerie, aSeriesPoints[i].idx, null);
                        }
                    }
                }
            }
        }


        if(!oSparklineGroup.displayXAxis)
        {
            oAxis.catAx[0].setDelete(true);
        }
        else if(aSeriesPoints.length > 1)
        {
            aSeriesPoints = [].concat(aSeriesPoints);
            var dMinVal, dMaxVal, bSorted = false;
            if(val_ax_props.minVal == null)
            {
                if(aMinPoints)
                {
                    dMinVal = aMinPoints[0].val;
                }
                else
                {

                    aSeriesPoints.sort(function(a, b){return a.val - b.val;});
                    bSorted = true;
                    dMinVal = aSeriesPoints[0].val;
                }
            }
            else
            {
                dMinVal = val_ax_props.minVal;
            }

            if(val_ax_props.maxVal == null)
            {
                if(aMaxPoints)
                {
                    dMaxVal = aMaxPoints[0].val;
                }
                else
                {
                    if(!bSorted)
                    {
                        aSeriesPoints.sort(function(a, b){return a.val - b.val;});
                        bSorted = true;
                    }
                    dMaxVal = aSeriesPoints[aSeriesPoints.length - 1].val;
                }
            }
            else
            {
                dMaxVal = val_ax_props.maxVal;
            }
            if((dMaxVal !== dMinVal) && (dMaxVal < 0 || dMinVal > 0))
            {
                oAxis.catAx[0].setDelete(true);
            }
        }
        if(oSparklineGroup.colorSeries)
        {
            var oUnifill = CreateUniFillFromExcelColor(oSparklineGroup.colorSeries);
            var oSerie = chart_space.chart.plotArea.charts[0].series[0];

            //oSerie.setSpPr(new AscFormat.CSpPr());
            if(nSparklineType === Asc.c_oAscSparklineType.Line)
            {
                var oLn = oSerie.spPr.ln;
                oLn.setFill(oUnifill);
                oSerie.spPr.setLn(oLn);
            }
            else
            {
                    oSerie.spPr.setFill(oUnifill);
                    oSerie.spPr.ln = new AscFormat.CLn();
                    oSerie.spPr.ln.Fill = oSerie.spPr.Fill.createDuplicate();
                    oSerie.spPr.ln.w = dLineWidthSpaces;
            }
        }

        this.chartSpace = chart_space;
        if(worksheetView){

            var oBBox = oSparkline.sqref;
            this.col = oBBox.c1;
            this.row = oBBox.r1;
            this.x = worksheetView.getCellLeft(oBBox.c1, 3);
            this.y = worksheetView.getCellTop(oBBox.r1, 3);


            var oMergeInfo = worksheetView.model.getMergedByCell( oBBox.r1, oBBox.c1 );
            if(oMergeInfo){
                this.extX = 0;
                for(i = oMergeInfo.c1; i <= oMergeInfo.c2; ++i){
                    this.extX += worksheetView.getColumnWidth(i, 3)
                }
                this.extY = 0;
                for(i = oMergeInfo.r1; i <= oMergeInfo.r2; ++i){
                    this.extY = worksheetView.getRowHeight(i, 3);
                }
            }
            else{
                this.extX = worksheetView.getColumnWidth(oBBox.c1, 3);
                this.extY = worksheetView.getRowHeight(oBBox.r1, 3);
            }
            AscFormat.CheckSpPrXfrm(this.chartSpace);
            this.chartSpace.spPr.xfrm.setOffX(this.x*nSparklineMultiplier);
            this.chartSpace.spPr.xfrm.setOffY(this.y*nSparklineMultiplier);
            this.chartSpace.spPr.xfrm.setExtX(this.extX*nSparklineMultiplier);
            this.chartSpace.spPr.xfrm.setExtY(this.extY*nSparklineMultiplier);
            this.chartSpace.recalculate();
        }
    }, this, []);
};

CSparklineView.prototype.draw = function(graphics, offX, offY)
{
    var x = this.ws.getCellLeft(this.col, 3) - offX;
    var y = this.ws.getCellTop(this.row, 3) - offY;

    var i;

    var extX;
    var extY;
    var oMergeInfo = this.ws.model.getMergedByCell( this.row, this.col );
    if(oMergeInfo){
        extX = 0;
        for(i = oMergeInfo.c1; i <= oMergeInfo.c2; ++i){
            extX += this.ws.getColumnWidth(i, 3)
        }
        extY = 0;
        for(i = oMergeInfo.r1; i <= oMergeInfo.r2; ++i){
            extY = this.ws.getRowHeight(i, 3);
        }
    }
    else{
        extX = this.ws.getColumnWidth(this.col, 3);
        extY = this.ws.getRowHeight(this.row, 3);
    }


    var bExtent = Math.abs(this.extX - extX) > 0.01 || Math.abs(this.extY - extY) > 0.01;
    var bPosition = Math.abs(this.x - x) > 0.01 || Math.abs(this.y - y) > 0.01;
    if(bExtent || bPosition)
    {
        AscFormat.ExecuteNoHistory(function(){
            if(bPosition)
            {
                this.chartSpace.spPr.xfrm.setOffX(x*nSparklineMultiplier);
                this.chartSpace.spPr.xfrm.setOffY(y*nSparklineMultiplier);
            }
            if(bExtent)
            {
                this.chartSpace.spPr.xfrm.setExtX(extX*nSparklineMultiplier);
                this.chartSpace.spPr.xfrm.setExtY(extY*nSparklineMultiplier);
            }
        }, this, []);
        this.x = x;
        this.y = y;
        this.extX = extX;
        this.extY = extY;
        if(bExtent)
        {
            this.chartSpace.handleUpdateExtents();
            this.chartSpace.recalculate();
        }
        else
        {
            this.chartSpace.x = x*nSparklineMultiplier;
            this.chartSpace.y = y*nSparklineMultiplier;
            this.chartSpace.transform.tx = this.chartSpace.x;
            this.chartSpace.transform.ty = this.chartSpace.y;
        }
    }

    var tx, ty, sx, sy, oldExtX, oldExtY;

    var _true_height = this.chartSpace.chartObj.calcProp.trueHeight;
    var _true_width = this.chartSpace.chartObj.calcProp.trueWidht;


	this.chartSpace.chartObj.calcProp.trueWidht = this.chartSpace.extX * this.chartSpace.chartObj.calcProp.pxToMM;
	this.chartSpace.chartObj.calcProp.trueHeight = this.chartSpace.extY * this.chartSpace.chartObj.calcProp.pxToMM;

    this.chartSpace.draw(graphics);

	this.chartSpace.chartObj.calcProp.trueWidht = _true_width;
	this.chartSpace.chartObj.calcProp.trueHeight = _true_height;


};


CSparklineView.prototype.setMinMaxValAx = function(minVal, maxVal, oSparklineGroup)
{
    var oAxis = this.chartSpace.chart.plotArea.getAxisByTypes();
    var oValAx = oAxis.valAx[0];
    if(oValAx)
    {
        if(minVal !== null)
        {
            if(!oValAx.scaling)
            {
                oValAx.setScaling(new AscFormat.CScaling());
            }
            oValAx.scaling.setMin(minVal);
        }
        if(maxVal !== null)
        {
            if(!oValAx.scaling)
            {
                oValAx.setScaling(new AscFormat.CScaling());
            }
            oValAx.scaling.setMax(maxVal);
        }


        if(oSparklineGroup.displayXAxis)
        {
             var  aSeriesPoints = AscFormat.getPtsFromSeries(this.chartSpace.chart.plotArea.charts[0].series[0]);
            if(aSeriesPoints.length > 1)
            {
                aSeriesPoints = [].concat(aSeriesPoints);
                var dMinVal, dMaxVal, bSorted = false;
                if(minVal == null)
                {
                    aSeriesPoints.sort(function(a, b){return a.val - b.val;});
                    bSorted = true;
                    dMinVal = aSeriesPoints[0].val;
                }
                else
                {
                    dMinVal = minVal;
                }

                if(maxVal == null)
                {
                    if(!bSorted)
                    {
                        aSeriesPoints.sort(function(a, b){return a.val - b.val;});
                        bSorted = true;
                    }
                    dMaxVal = aSeriesPoints[aSeriesPoints.length - 1].val;
                }
                else
                {
                    dMaxVal = maxVal;
                }
                if(dMaxVal < 0 || dMinVal > 0)
                {
                    oAxis.catAx[0].setDelete(true);
                }
                else
                {
                    oAxis.catAx[0].setDelete(false);
                }
            }
        }


        this.chartSpace.recalcInfo.recalculateAxisVal = true;
        this.chartSpace.recalculate();
    }
};
//-----------------------------------------------------------------------------------
// Manager
//-----------------------------------------------------------------------------------


function CChangeTableData(changedRange, added, hided, removed, arrChanged)
{
    this.changedRange = changedRange;
    this.added = added;
    this.hided = hided;
    this.removed = removed;
    this.arrChanged = arrChanged;
}

function GraphicOption(ws, type, range, offset) {
    this.ws = ws;
	this.type = type;
	this.range = range;

	this.offset = offset;
}

GraphicOption.prototype.isScrollType = function() {
	return ((this.type === AscCommonExcel.c_oAscScrollType.ScrollVertical) || (this.type === AscCommonExcel.c_oAscScrollType.ScrollHorizontal));
};

GraphicOption.prototype.getUpdatedRange = function() {
	return this.range;
};
GraphicOption.prototype.getOffset = function () {
	return this.offset;
};

function DrawingObjects() {

    //-----------------------------------------------------------------------------------
    // Scroll offset
    //-----------------------------------------------------------------------------------

    var ScrollOffset = function() {

        this.getX = function() {
            return 2 * worksheet._getColLeft(0) - worksheet._getColLeft(worksheet.getFirstVisibleCol(true));
        };

        this.getY = function() {
            return 2 * worksheet._getRowTop(0) - worksheet._getRowTop(worksheet.getFirstVisibleRow(true));
        }
    };

    //-----------------------------------------------------------------------------------
    // Private
    //-----------------------------------------------------------------------------------

    var _this = this;
    var asc = window["Asc"];
    var api = asc["editor"];
    var worksheet = null;
    var asc_Range = asc.Range;

    var drawingCtx = null;
    var overlayCtx = null;
    var shapeCtx = null;
    var shapeOverlayCtx = null;

    var trackOverlay = null;
    var autoShapeTrack = null;
    var scrollOffset = new ScrollOffset();

    var aObjects = [];
    var aImagesSync = [];


    var oStateBeforeLoadChanges = null;

    _this.zoom = { last: 1, current: 1 };
    _this.canEdit = null;
    _this.objectLocker = null;
    _this.drawingArea = null;
    _this.drawingDocument = null;
    _this.asyncImageEndLoaded = null;
    _this.asyncImagesDocumentEndLoaded = null;
    _this.CompositeInput = null;

    _this.lastX = 0;
    _this.lastY = 0;

    _this.nCurPointItemsLength = -1;
    // Task timer
    var aDrawTasks = [];

    function drawTaskFunction() {

        // При скролах нужно выполнить все задачи

        _this.drawingDocument.CheckTargetShow();
        var taskLen = aDrawTasks.length;
        if ( taskLen ) {
            var lastTask = aDrawTasks[taskLen - 1];
            _this.showDrawingObjectsEx(lastTask.params.clearCanvas, lastTask.params.graphicOption, lastTask.params.printOptions);
            aDrawTasks.splice(0, (taskLen - 1 > 0) ? taskLen - 1 : 1);
        }
    }

    //-----------------------------------------------------------------------------------
    // Create drawing
    //-----------------------------------------------------------------------------------

    function DrawingBase(ws) {
        this.worksheet = ws;

		this.imageUrl = "";
		this.Type = c_oAscCellAnchorType.cellanchorTwoCell;
		this.Pos = { X: 0, Y: 0 };

		this.from = new CCellObjectInfo();
		this.to = new CCellObjectInfo();
		this.ext = { cx: 0, cy: 0 };
		this.size = { width: 0, height: 0 };

		this.graphicObject = null; // CImage, CShape, GroupShape or CChartAsGroup

        this.boundsFromTo =
        {
            from: new CCellObjectInfo(),
            to  : new CCellObjectInfo()
        };

		this.flags = {
            anchorUpdated: false,
            lockState: c_oAscLockTypes.kLockTypeNone
        };
    }

    //{ prototype


    DrawingBase.prototype.isUseInDocument = function() {
        if(worksheet && worksheet.model){
            var aDrawings = worksheet.model.Drawings;
            for(var i = 0; i < aDrawings.length; ++i){
                if(aDrawings[i] === this){
                    return true;
                }
            }
        }
        return false;
    };

    DrawingBase.prototype.getAllFonts = function(AllFonts) {
        var _t = this;
        _t.graphicObject && _t.graphicObject.documentGetAllFontNames && _t.graphicObject.documentGetAllFontNames(AllFonts);
    };

    DrawingBase.prototype.isImage = function() {
        var _t = this;
        return _t.graphicObject ? _t.graphicObject.isImage() : false;
    };

    DrawingBase.prototype.isShape = function() {
        var _t = this;
        return _t.graphicObject ? _t.graphicObject.isShape() : false;
    };

    DrawingBase.prototype.isGroup = function() {
        var _t = this;
        return _t.graphicObject ? _t.graphicObject.isGroup() : false;
    };

    DrawingBase.prototype.isChart = function() {
        var _t = this;
        return _t.graphicObject ? _t.graphicObject.isChart() : false;
    };

    DrawingBase.prototype.isGraphicObject = function() {
        var _t = this;
        return _t.graphicObject != null;
    };

    DrawingBase.prototype.isLocked = function() {
        var _t = this;
        return ( (_t.graphicObject.lockType != c_oAscLockTypes.kLockTypeNone) && (_t.graphicObject.lockType != c_oAscLockTypes.kLockTypeMine) )
    };

    DrawingBase.prototype.getCanvasContext = function() {
        return _this.drawingDocument.CanvasHitContext;
    };

    // GraphicObject: x, y, extX, extY
    DrawingBase.prototype.getGraphicObjectMetrics = function() {
        var _t = this;
        var metrics = { x: 0, y: 0, extX: 0, extY: 0 };

        var coordsFrom, coordsTo;
        switch(_t.Type)
        {
            case c_oAscCellAnchorType.cellanchorAbsolute:
            {
                metrics.x = this.Pos.X;
                metrics.y = this.Pos.Y;
                metrics.extX = this.ext.cx;
                metrics.extY = this.ext.cy;
                break;
            }
            case c_oAscCellAnchorType.cellanchorOneCell:
            {
                if (worksheet) {
					coordsFrom = _this.calculateCoords(_t.from);
					metrics.x = pxToMm( coordsFrom.x );
					metrics.y = pxToMm( coordsFrom.y );
					metrics.extX = this.ext.cx;
					metrics.extY = this.ext.cy;
                }
                break;
            }
            case c_oAscCellAnchorType.cellanchorTwoCell:
            {
				if (worksheet) {
					coordsFrom = _this.calculateCoords(_t.from);
					metrics.x = pxToMm( coordsFrom.x );
					metrics.y = pxToMm( coordsFrom.y );

					coordsTo = _this.calculateCoords(_t.to);
					metrics.extX = pxToMm( coordsTo.x - coordsFrom.x );
					metrics.extY = pxToMm( coordsTo.y - coordsFrom.y );
				}
                break;
            }
        }


        return metrics;
    };

    // Считаем From/To исходя из graphicObject
    DrawingBase.prototype.setGraphicObjectCoords = function() {
        var _t = this;

        if ( _t.isGraphicObject() ) {

            var rot = AscFormat.isRealNumber(_t.graphicObject.rot) ? _t.graphicObject.rot : 0;
            rot = AscFormat.normalizeRotate(rot);

            var fromX, fromY, toX, toY;
            if (AscFormat.checkNormalRotate(rot))
            {
                fromX =  mmToPx(_t.graphicObject.x);
                fromY =  mmToPx(_t.graphicObject.y);
                toX = mmToPx(_t.graphicObject.x + _t.graphicObject.extX);
                toY = mmToPx(_t.graphicObject.y + _t.graphicObject.extY);
                this.Pos.X = _t.graphicObject.x;
                this.Pos.Y = _t.graphicObject.y;
                this.ext.cx = _t.graphicObject.extX;
                this.ext.cy = _t.graphicObject.extY;
            }
            else
            {
                var _xc, _yc;
                _xc = _t.graphicObject.x + _t.graphicObject.extX/2;
                _yc = _t.graphicObject.y + _t.graphicObject.extY/2;
                fromX =  mmToPx(_xc - _t.graphicObject.extY/2);
                fromY =  mmToPx(_yc - _t.graphicObject.extX/2);
                toX = mmToPx(_xc + _t.graphicObject.extY/2);
                toY = mmToPx(_yc + _t.graphicObject.extX/2);
                this.Pos.X = _xc - _t.graphicObject.extY/2;
                this.Pos.Y = _yc - _t.graphicObject.extX/2;
                this.ext.cx = _t.graphicObject.extY;
                this.ext.cy = _t.graphicObject.extX;
            }

            var fromColCell = worksheet.findCellByXY(fromX, fromY, true, false, true);
            var fromRowCell = worksheet.findCellByXY(fromX, fromY, true, true, false);
            var toColCell = worksheet.findCellByXY(toX, toY, true, false, true);
            var toRowCell = worksheet.findCellByXY(toX, toY, true, true, false);

            _t.from.col = fromColCell.col;
            _t.from.colOff = pxToMm(fromColCell.colOff);
            _t.from.row = fromRowCell.row;
            _t.from.rowOff = pxToMm(fromRowCell.rowOff);

            _t.to.col = toColCell.col;
            _t.to.colOff = pxToMm(toColCell.colOff);
            _t.to.row = toRowCell.row;
            _t.to.rowOff = pxToMm(toRowCell.rowOff);
        }
    };

    DrawingBase.prototype.checkBoundsFromTo = function() {
        var _t = this;

        if ( _t.isGraphicObject() && _t.graphicObject.bounds) {


            var bounds = _t.graphicObject.bounds;


            var fromX =  mmToPx(bounds.x > 0 ? bounds.x : 0), fromY =  mmToPx(bounds.y > 0 ? bounds.y : 0),
                toX = mmToPx(bounds.x + bounds.w), toY = mmToPx(bounds.y + bounds.h);
            if(toX < 0)
            {
                toX = 0;
            }
            if(toY < 0)
            {
                toY = 0;
            }

            var fromColCell = worksheet.findCellByXY(fromX, fromY, true, false, true);
            var fromRowCell = worksheet.findCellByXY(fromX, fromY, true, true, false);
            var toColCell = worksheet.findCellByXY(toX, toY, true, false, true);
            var toRowCell = worksheet.findCellByXY(toX, toY, true, true, false);

            _t.boundsFromTo.from.col = fromColCell.col;
            _t.boundsFromTo.from.colOff = pxToMm(fromColCell.colOff);
            _t.boundsFromTo.from.row = fromRowCell.row;
            _t.boundsFromTo.from.rowOff = pxToMm(fromRowCell.rowOff);

            _t.boundsFromTo.to.col = toColCell.col;
            _t.boundsFromTo.to.colOff = pxToMm(toColCell.colOff);
            _t.boundsFromTo.to.row = toRowCell.row;
            _t.boundsFromTo.to.rowOff = pxToMm(toRowCell.rowOff);
        }
    };

    // Реальное смещение по высоте
    DrawingBase.prototype.getRealTopOffset = function() {
        var _t = this;
        var val = _t.worksheet._getRowTop(_t.from.row) + mmToPx(_t.from.rowOff);
        return asc.round(val);
    };

    // Реальное смещение по ширине
    DrawingBase.prototype.getRealLeftOffset = function() {
        var _t = this;
        var val = _t.worksheet._getColLeft(_t.from.col) + mmToPx(_t.from.colOff);
        return asc.round(val);
    };

    // Ширина по координатам
    DrawingBase.prototype.getWidthFromTo = function() {
        return (this.worksheet._getColLeft(this.to.col) + mmToPx(this.to.colOff) -
			this.worksheet._getColLeft(this.from.col) - mmToPx(this.from.colOff));
    };

    // Высота по координатам
    DrawingBase.prototype.getHeightFromTo = function() {
        return this.worksheet._getRowTop(this.to.row) + mmToPx(this.to.rowOff) -
			this.worksheet._getRowTop(this.from.row) - mmToPx(this.from.rowOff);
    };

    // Видимое смещение объекта от первой видимой строки
    DrawingBase.prototype.getVisibleTopOffset = function(withHeader) {
        var _t = this;
        var headerRowOff = _t.worksheet._getRowTop(0);
        var fvr = _t.worksheet._getRowTop(_t.worksheet.getFirstVisibleRow(true));
        var off = _t.getRealTopOffset() - fvr;
        off = (off > 0) ? off : 0;
        return withHeader ? headerRowOff + off : off;
    };

    // Видимое смещение объекта от первой видимой колонки
    DrawingBase.prototype.getVisibleLeftOffset = function(withHeader) {
        var _t = this;
        var headerColOff = _t.worksheet._getColLeft(0);
        var fvc = _t.worksheet._getColLeft(_t.worksheet.getFirstVisibleCol(true));
        var off = _t.getRealLeftOffset() - fvc;
        off = (off > 0) ? off : 0;
        return withHeader ? headerColOff + off : off;
    };

    DrawingBase.prototype.getDrawingObjects = function() {
        return _this;
    };

    //}

    //-----------------------------------------------------------------------------------
    // Constructor
    //-----------------------------------------------------------------------------------

    _this.addShapeOnSheet = function(sType){
        if(this.controller){
            if (_this.canEdit()) {

                var oVisibleRange = worksheet.getVisibleRange();

                _this.objectLocker.reset();
                _this.objectLocker.addObjectId(AscCommon.g_oIdCounter.Get_NewId());
                _this.objectLocker.checkObjects(function (bLock) {
                    if (bLock !== true)
                        return;
                    _this.controller.resetSelection();

                    var activeCell = worksheet.model.selectionRange.activeCell;



                    var metrics = {};
                    metrics.col = activeCell.col;
                    metrics.colOff = 0;
                    metrics.row = activeCell.row;
                    metrics.rowOff = 0;


                    var coordsFrom = _this.calculateCoords(metrics);



                    var ext_x, ext_y;
                    if(typeof AscFormat.SHAPE_EXT[sType] === "number")
                    {
                        ext_x = AscFormat.SHAPE_EXT[sType];
                    }
                    else
                    {
                        ext_x = 25.4;
                    }
                    if(typeof AscFormat.SHAPE_ASPECTS[sType] === "number")
                    {
                        var _aspect = AscFormat.SHAPE_ASPECTS[sType];
                        ext_y = ext_x/_aspect;
                    }
                    else
                    {
                        ext_y = ext_x;
                    }
                    History.Create_NewPoint();

                    var posX = pxToMm(coordsFrom.x) + MOVE_DELTA;
                    var posY = pxToMm(coordsFrom.y) + MOVE_DELTA;
                    var oTrack = new AscFormat.NewShapeTrack(sType, posX, posY, _this.controller.getTheme(), null, null, null, 0);
                    oTrack.track({}, posX + ext_x, posY + ext_y);
                    var oShape = oTrack.getShape(false, _this.drawingDocument, null);
                    oShape.setWorksheet(worksheet.model);
                    oShape.addToDrawingObjects();
                    oShape.select(_this.controller, 0);
                    _this.controller.startRecalculate();
                    worksheet.setSelectionShape(true);
                });
            }
        }
    };

    _this.getScrollOffset = function()
    {
        return scrollOffset;
    };

    _this.saveStateBeforeLoadChanges = function(){
        if(this.controller){
            oStateBeforeLoadChanges = {};
            this.controller.Save_DocumentStateBeforeLoadChanges(oStateBeforeLoadChanges);
        }
        else{
            oStateBeforeLoadChanges = null;
        }
        return oStateBeforeLoadChanges;
    };

    _this.loadStateAfterLoadChanges = function(){
        if(_this.controller){
            _this.controller.clearPreTrackObjects();
            _this.controller.clearTrackObjects();
            _this.controller.resetSelection();
            _this.controller.changeCurrentState(new AscFormat.NullState(this.controller));
            if(oStateBeforeLoadChanges){
                _this.controller.loadDocumentStateAfterLoadChanges(oStateBeforeLoadChanges);
            }
        }
        oStateBeforeLoadChanges = null;
        return oStateBeforeLoadChanges;
    };

    _this.getStateBeforeLoadChanges = function(){
        return oStateBeforeLoadChanges;
    };

    _this.createDrawingObject = function(type) {
        var drawingBase = new DrawingBase(worksheet);
        if(AscFormat.isRealNumber(type))
        {
            drawingBase.Type = type;
        }
        return drawingBase;
    };

    _this.cloneDrawingObject = function(object) {

        var copyObject = _this.createDrawingObject();

        copyObject.Type = object.Type;
        copyObject.Pos.X = object.Pos.X;
        copyObject.Pos.Y = object.Pos.Y;
        copyObject.ext.cx = object.ext.cx;
        copyObject.ext.cy = object.ext.cy;

        copyObject.from.col = object.from.col;
        copyObject.from.colOff = object.from.colOff;
        copyObject.from.row = object.from.row;
        copyObject.from.rowOff = object.from.rowOff;

        copyObject.to.col = object.to.col;
        copyObject.to.colOff = object.to.colOff;
        copyObject.to.row = object.to.row;
        copyObject.to.rowOff = object.to.rowOff;


        copyObject.boundsFromTo.from.col =  object.boundsFromTo.from.col;
        copyObject.boundsFromTo.from.colOff = object.boundsFromTo.from.colOff;
        copyObject.boundsFromTo.from.row =  object.boundsFromTo.from.row;
        copyObject.boundsFromTo.from.rowOff = object.boundsFromTo.from.rowOff;
        copyObject.boundsFromTo.to.col =  object.boundsFromTo.to.col;
        copyObject.boundsFromTo.to.colOff = object.boundsFromTo.to.colOff;
        copyObject.boundsFromTo.to.row =  object.boundsFromTo.to.row;
        copyObject.boundsFromTo.to.rowOff = object.boundsFromTo.to.rowOff;

        copyObject.graphicObject = object.graphicObject;
        return copyObject;
    };


    _this.createShapeAndInsertContent = function(oParaContent){
        var track_object = new AscFormat.NewShapeTrack("textRect", 0, 0, Asc['editor'].wbModel.theme, null, null, null, 0);
        track_object.track({}, 0, 0);
        var shape = track_object.getShape(false, _this.drawingDocument, this);
        shape.spPr.setFill(AscFormat.CreateNoFillUniFill());
        //shape.setParent(this);
        shape.txBody.content.Content[0].Add_ToContent(0, oParaContent.Copy());
        var body_pr = shape.getBodyPr();
        var w = shape.txBody.getMaxContentWidth(150, true) + body_pr.lIns + body_pr.rIns;
        var h = shape.txBody.content.GetSummaryHeight() + body_pr.tIns + body_pr.bIns;
        shape.spPr.xfrm.setExtX(w);
        shape.spPr.xfrm.setExtY(h);
        shape.spPr.xfrm.setOffX(0);
        shape.spPr.xfrm.setOffY(0);
        shape.spPr.setLn(AscFormat.CreateNoFillLine());
        shape.setWorksheet(worksheet.model);
        //shape.addToDrawingObjects();
        return shape;
    };
    //-----------------------------------------------------------------------------------
    // Public methods
    //-----------------------------------------------------------------------------------

    _this.init = function(currentSheet) {
 
        if (!window['IS_NATIVE_EDITOR']) {
            setInterval(drawTaskFunction, 5);
        }

        var api = window["Asc"]["editor"];
        worksheet = currentSheet;

        drawingCtx = currentSheet.drawingGraphicCtx;
        overlayCtx = currentSheet.overlayGraphicCtx;
        shapeCtx = currentSheet.shapeCtx;
        shapeOverlayCtx = currentSheet.shapeOverlayCtx;

        trackOverlay = new AscCommon.COverlay();
        trackOverlay.IsCellEditor = true;
        trackOverlay.init( shapeOverlayCtx.m_oContext, "ws-canvas-graphic-overlay", 0, 0, shapeOverlayCtx.m_lWidthPix, shapeOverlayCtx.m_lHeightPix, shapeOverlayCtx.m_dWidthMM, shapeOverlayCtx.m_dHeightMM );

        autoShapeTrack = new AscCommon.CAutoshapeTrack();
        autoShapeTrack.init( trackOverlay, 0, 0, shapeOverlayCtx.m_lWidthPix, shapeOverlayCtx.m_lHeightPix, shapeOverlayCtx.m_dWidthMM, shapeOverlayCtx.m_dHeightMM );
        shapeCtx.m_oAutoShapesTrack = autoShapeTrack;


        _this.objectLocker = new ObjectLocker(worksheet);
        _this.drawingArea = currentSheet.drawingArea;
        _this.drawingArea.init();
        _this.drawingDocument = currentSheet.model.DrawingDocument ? currentSheet.model.DrawingDocument : new AscCommon.CDrawingDocument(this);
        _this.drawingDocument.drawingObjects = this;
        _this.drawingDocument.AutoShapesTrack = autoShapeTrack;
        _this.drawingDocument.TargetHtmlElement = document.getElementById('id_target_cursor');
        _this.drawingDocument.InitGuiCanvasShape(api.shapeElementId);
        _this.controller = new AscFormat.DrawingObjectsController(_this);
        _this.lasteForzenPlaseNum = 0;

        _this.canEdit = function() { return worksheet.handlers.trigger('canEdit'); };

        aImagesSync = [];

		var i;
        aObjects = currentSheet.model.Drawings;
        for (i = 0; currentSheet.model.Drawings && (i < currentSheet.model.Drawings.length); i++)
        {
            aObjects[i] = _this.cloneDrawingObject(aObjects[i]);
            var drawingObject = aObjects[i];
            // Check drawing area
            drawingObject.drawingArea = _this.drawingArea;
            drawingObject.worksheet = currentSheet;
            var metrics = drawingObject.getGraphicObjectMetrics();
            drawingObject.graphicObject.drawingBase = aObjects[i];
            drawingObject.graphicObject.drawingObjects = _this;
            drawingObject.graphicObject.getAllRasterImages(aImagesSync);
        }

        for(i = 0; i < aImagesSync.length; ++i)
        {
			var localUrl = aImagesSync[i];
			if(api.DocInfo && api.DocInfo.get_OfflineApp()) {
          AscCommon.g_oDocumentUrls.addImageUrl(localUrl, "/sdkjs/cell/document/media/" + localUrl);
			}
            aImagesSync[i] = AscCommon.getFullImageSrc2(localUrl);
        }

        // Загружаем все картинки листа
        _this.asyncImagesDocumentEndLoaded = function()
        {
            _this.showDrawingObjects(true);
        };

        if(!Asc['editor'].ImageLoader.map_image_index[sFrozenImageUrl]){
            aImagesSync.push(sFrozenImageUrl);
        }
        if(!Asc['editor'].ImageLoader.map_image_index[sFrozenImageRotUrl]){
            aImagesSync.push(sFrozenImageRotUrl);
        }
        if(aImagesSync.length > 0)
        {
            var old_val = api.ImageLoader.bIsAsyncLoadDocumentImages;
            api.ImageLoader.bIsAsyncLoadDocumentImages = true;
            api.ImageLoader.LoadDocumentImages(aImagesSync, null);
            api.ImageLoader.bIsAsyncLoadDocumentImages = old_val;
        }

		_this.recalculate(true);

        _this.shiftMap = {};
        worksheet.model.Drawings = aObjects;
    };


    _this.getSelectedDrawingsRange = function()
    {
        var i, rmin=gc_nMaxRow, rmax = 0, cmin = gc_nMaxCol, cmax = 0, selectedObjects = this.controller.selectedObjects, drawingBase;
        for(i = 0; i < selectedObjects.length; ++i)
        {

            drawingBase = selectedObjects[i].drawingBase;
            if(drawingBase)
            {
                if(drawingBase.from.col < cmin)
                {
                    cmin = drawingBase.from.col;
                }
                if(drawingBase.from.row < rmin)
                {
                    rmin = drawingBase.from.row;
                }
                if(drawingBase.to.col > cmax)
                {
                    cmax = drawingBase.to.col;
                }
                if(drawingBase.to.row > rmax)
                {
                    rmax = drawingBase.to.row;
                }
            }
        }
        return new Asc.Range(cmin, rmin, cmax, rmax, true);
    };


    _this.getContextMenuPosition = function(){

        if(!worksheet){
            return new AscCommon.asc_CRect( 0, 0, 5, 5 );
        }
        var oPos = this.controller.getContextMenuPosition(0);

        var _x = oPos.X * Asc.getCvtRatio(3, 0, worksheet._getPPIX()) + scrollOffset.getX();
        var _y = oPos.Y * Asc.getCvtRatio(3, 0, worksheet._getPPIY()) + scrollOffset.getY();
        return new AscCommon.asc_CRect(_x, _y, 0, 0 );
    };

    _this.recalculate =  function(all)
    {
        _this.controller.recalculate2(all);
    };

    _this.preCopy = function() {
        _this.shiftMap = {};
        var selected_objects = _this.controller.selectedObjects;
        if(selected_objects.length > 0)
        {
            var min_x, min_y, i;
            min_x = selected_objects[0].x;
            min_y = selected_objects[0].y;
            for(i = 1; i < selected_objects.length; ++i)
            {
                if(selected_objects[i].x < min_x)
                    min_x = selected_objects[i].x;

                if(selected_objects[i].y < min_y)
                    min_y = selected_objects[i].y;
            }
            for(i = 0; i < selected_objects.length; ++i)
            {
                _this.shiftMap[selected_objects[i].Get_Id()] = {x: selected_objects[i].x - min_x, y: selected_objects[i].y - min_y};
            }
        }

    };

    _this.getAllFonts = function(AllFonts) {

    };

    _this.getOverlay = function() {
        return trackOverlay;
    };

    _this.OnUpdateOverlay = function() {
        _this.drawingArea.drawSelection(_this.drawingDocument);
    };

    _this.changeZoom = function(factor) {

        _this.zoom.last = _this.zoom.current;
        _this.zoom.current = factor;

        _this.resizeCanvas();
    };

    _this.resizeCanvas = function() {
		_this.drawingArea.init();

        var canvasWidth = drawingCtx.canvas.width;
        var canvasHeight = drawingCtx.canvas.height;

        shapeCtx.init( drawingCtx.ctx, canvasWidth, canvasHeight, (canvasWidth*25.4/drawingCtx.ppiX), (canvasHeight*25.4/drawingCtx.ppiY));
        shapeCtx.CalculateFullTransform();




        var overlayWidth = overlayCtx.canvas.width;
        var overlayHeight = overlayCtx.canvas.height;

        shapeOverlayCtx.init( overlayCtx.ctx, overlayWidth, overlayHeight, (overlayWidth*25.4/overlayCtx.ppiX), (overlayHeight*25.4/overlayCtx.ppiY));
        shapeOverlayCtx.CalculateFullTransform();

        trackOverlay.init( shapeOverlayCtx.m_oContext, "ws-canvas-graphic-overlay", 0, 0, overlayWidth, overlayHeight, (overlayWidth*25.4/overlayCtx.ppiX), (overlayHeight*25.4/overlayCtx.ppiY));
        autoShapeTrack.init( trackOverlay, 0, 0,  overlayWidth, overlayHeight, (overlayWidth*25.4/overlayCtx.ppiX), (overlayHeight*25.4/overlayCtx.ppiY) );
        autoShapeTrack.Graphics.CalculateFullTransform();
    };

    _this.getCanvasContext = function() {
        return _this.drawingDocument.CanvasHitContext;
    };

    _this.getDrawingObjects = function() {
        return aObjects;
    };

    _this.getWorksheet = function() {
        return worksheet;
    };

	_this.getContextWidth = function () {
		return drawingCtx.getWidth();
	};
	_this.getContextHeight = function () {
		return drawingCtx.getHeight();
	};
    _this.getContext = function () {
        return drawingCtx;
    };

    _this.getWorksheetModel = function() {
        return worksheet.model;
    };

    _this.callTrigger = function(triggerName, param) {
        if ( triggerName )
            worksheet.model.workbook.handlers.trigger(triggerName, param);
    };

    _this.getDrawingObjectsBounds = function()
    {
        var arr_x = [], arr_y = [], bounds;
        for(var i = 0; i < aObjects.length; ++i)
        {
            bounds = aObjects[i].graphicObject.bounds;
            arr_x.push(bounds.l);
            arr_x.push(bounds.r);
            arr_y.push(bounds.t);
            arr_y.push(bounds.b);
        }
        return new DrawingBounds(Math.min.apply(Math, arr_x), Math.max.apply(Math, arr_x), Math.min.apply(Math, arr_y), Math.max.apply(Math, arr_y));
    };

    //-----------------------------------------------------------------------------------
    // Drawing objects
    //-----------------------------------------------------------------------------------

    _this.showDrawingObjects = function(clearCanvas, graphicOption, printOptions) {

        var currTime = getCurrentTime();
        if ( aDrawTasks.length ) {

            var lastTask = aDrawTasks[aDrawTasks.length - 1];

			// ToDo не всегда грамотно так делать, т.к. в одном scroll я могу прислать 2 области (и их объединять не нужно)
            if ( lastTask.params.graphicOption && lastTask.params.graphicOption.isScrollType() && graphicOption && (lastTask.params.graphicOption.type === graphicOption.type) ) {
                lastTask.params.graphicOption.range.c1 = Math.min(lastTask.params.graphicOption.range.c1, graphicOption.range.c1);
                lastTask.params.graphicOption.range.r1 = Math.min(lastTask.params.graphicOption.range.r1, graphicOption.range.r1);
                lastTask.params.graphicOption.range.c2 = Math.max(lastTask.params.graphicOption.range.c2, graphicOption.range.c2);
                lastTask.params.graphicOption.range.r2 = Math.max(lastTask.params.graphicOption.range.r2, graphicOption.range.r2);
                return;
            }
            if ( (currTime - lastTask.time < 40) )
                return;
        }

        aDrawTasks.push({ time: currTime, params: { clearCanvas: clearCanvas, graphicOption: graphicOption, printOptions: printOptions} });
    };

    _this.showDrawingObjectsEx = function(clearCanvas, graphicOption, printOptions) {

        /*********** Print Options ***************
         printOptions : {
			ctx,
			printPagesData
		}
         *****************************************/

        // Undo/Redo
        if ( (worksheet.model.index != api.wb.model.getActive()) && !printOptions )
            return;

        if ( drawingCtx ) {
            if ( clearCanvas ) {
                _this.drawingArea.clear();
            }

            if ( aObjects.length ) {
                if (graphicOption) {
                    // Выставляем нужный диапазон для отрисовки
                    var updatedRect = { x: 0, y: 0, w: 0, h: 0 };
                    var updatedRange = graphicOption.getUpdatedRange();

					var x1 = worksheet._getColLeft(updatedRange.c1);
                    var y1 = worksheet._getRowTop(updatedRange.r1);
                    var x2 = worksheet._getColLeft(updatedRange.c2 + 1);
                    var y2 = worksheet._getRowTop(updatedRange.r2 + 1);
                    var w = x2 - x1;
                    var h = y2 - y1;
					var offset = worksheet.getCellsOffset(0);

                    updatedRect.x = pxToMm(x1 - offset.left);
                    updatedRect.y = pxToMm(y1 - offset.top);
                    updatedRect.w = pxToMm(w);
                    updatedRect.h = pxToMm(h);

					var offsetScroll = graphicOption.getOffset();
                    shapeCtx.m_oContext.save();
                    shapeCtx.m_oContext.beginPath();
                    shapeCtx.m_oContext.rect(x1 - offsetScroll.offsetX, y1 - offsetScroll.offsetY, w, h);
                    shapeCtx.m_oContext.clip();

                    shapeCtx.updatedRect = updatedRect;
                } else
                    shapeCtx.updatedRect = null;


                for (var i = 0; i < aObjects.length; i++) {
                    var drawingObject = aObjects[i];

                    // Shape render (drawForPrint)
                    if ( drawingObject.isGraphicObject() ) {
                        if ( printOptions ) {

                            var range = printOptions.printPagesData.pageRange;
                            var printPagesData = printOptions.printPagesData;
                            var offsetCols = printPagesData.startOffsetPx;

                            var left = worksheet.getCellLeft(range.c1, 3) - worksheet.getCellLeft(0, 3) - pxToMm(printPagesData.leftFieldInPx);
                            var top = worksheet.getCellTop(range.r1, 3) - worksheet.getCellTop(0, 3) - pxToMm(printPagesData.topFieldInPx);

                            _this.printGraphicObject(drawingObject.graphicObject, printOptions.ctx.DocumentRenderer, top, left);

                            if ( printPagesData.pageHeadings ) {
                                worksheet._drawColumnHeaders(printOptions.ctx, range.c1, range.c2, /*style*/ undefined, worksheet._getColLeft(range.c1) - printPagesData.leftFieldInPx + offsetCols, printPagesData.topFieldInPx - worksheet.cellsTop);
                                worksheet._drawRowHeaders(printOptions.ctx, range.r1, range.r2, /*style*/ undefined, printPagesData.leftFieldInPx - worksheet.cellsLeft, worksheet._getRowTop(range.r1) - printPagesData.topFieldInPx);
                            }
                        }
                        else {
                            _this.drawingArea.drawObject(drawingObject);
                        }
                    }
                }

				if (graphicOption)
                {
                    shapeCtx.m_oContext.restore();
                }
            }
            worksheet.model.Drawings = aObjects;
        }

        if ( !printOptions ) {

            var bChangedFrozen = _this.lasteForzenPlaseNum !== _this.drawingArea.frozenPlaces.length;
            if ( _this.controller.selectedObjects.length || _this.drawingArea.frozenPlaces.length > 1 || bChangedFrozen) {
                _this.OnUpdateOverlay();
                _this.controller.updateSelectionState(true);
            }
        }
        _this.lasteForzenPlaseNum = _this.drawingArea.frozenPlaces.length;
    };

    _this.getDrawingDocument = function()
    {
        return _this.drawingDocument;
    };

    _this.printGraphicObject = function(graphicObject, ctx, top, left) {

        if ( graphicObject && ctx ) {
            // Image
            if ( graphicObject instanceof AscFormat.CImageShape )
                printImage(graphicObject, ctx, top, left);
            // Shape
            else if ( graphicObject instanceof AscFormat.CShape )
                printShape(graphicObject, ctx, top, left);
            // Chart
            else if (graphicObject instanceof AscFormat.CChartSpace)
                printChart(graphicObject, ctx, top, left);
            // Group
            else if ( graphicObject instanceof AscFormat.CGroupShape )
                printGroup(graphicObject, ctx, top, left);
        }

        // Print functions
        function printImage(graphicObject, ctx, top, left) {

            if ( (graphicObject instanceof AscFormat.CImageShape) && graphicObject && ctx ) {
                // Save
                var tx = graphicObject.transform.tx;
                var ty = graphicObject.transform.ty;
                graphicObject.transform.tx -= left;
                graphicObject.transform.ty -= top;
                // Print
                graphicObject.draw( ctx );
                // Restore
                graphicObject.transform.tx = tx;
                graphicObject.transform.ty = ty;
            }
        }

        function printShape(graphicObject, ctx, top, left) {

            if ( (graphicObject instanceof AscFormat.CShape) && graphicObject && ctx ) {
                // Save
                var tx = graphicObject.transform.tx;
                var ty = graphicObject.transform.ty;
                graphicObject.transform.tx -= left;
                graphicObject.transform.ty -= top;
                var txTxt, tyTxt, txWA, tyWA;
                if ( graphicObject.txBody && graphicObject.transformText ) {
                    txTxt = graphicObject.transformText.tx;
                    tyTxt = graphicObject.transformText.ty;
                    graphicObject.transformText.tx -= left;
                    graphicObject.transformText.ty -= top;
                }

                if(graphicObject.transformTextWordArt)
                {
                    graphicObject.transformTextWordArt.tx -= left;
                    graphicObject.transformTextWordArt.ty -= top;
                }
                // Print
                graphicObject.draw( ctx );
                // Restore
                graphicObject.transform.tx = tx;
                graphicObject.transform.ty = ty;
                if ( graphicObject.txBody && graphicObject.transformText ) {
                    graphicObject.transformText.tx = txTxt;
                    graphicObject.transformText.ty = tyTxt;
                }
                if(graphicObject.transformTextWordArt)
                {
                    graphicObject.transformTextWordArt.tx += left;
                    graphicObject.transformTextWordArt.ty += top;
                }
            }
        }

        function printChart(graphicObject, ctx, top, left) {

            if ( (graphicObject instanceof AscFormat.CChartSpace) && graphicObject && ctx ) {

                // Save
                var tx = graphicObject.transform.tx;
                var ty = graphicObject.transform.ty;
                graphicObject.transform.tx -= left;
                graphicObject.transform.ty -= top;

                graphicObject.updateChildLabelsTransform(graphicObject.transform.tx, graphicObject.transform.ty);
                // Print
                graphicObject.draw( ctx );
                // Restore
                graphicObject.transform.tx = tx;
                graphicObject.transform.ty = ty;
                graphicObject.updateChildLabelsTransform(graphicObject.transform.tx, graphicObject.transform.ty);

            }
        }

        function printGroup(graphicObject, ctx, top, left) {

            if ( (graphicObject instanceof AscFormat.CGroupShape) && graphicObject && ctx ) {
                for ( var i = 0; i < graphicObject.arrGraphicObjects.length; i++ ) {
                    var graphicItem = graphicObject.arrGraphicObjects[i];

                    if ( graphicItem instanceof AscFormat.CImageShape )
                        printImage(graphicItem, ctx, top, left);

                    else if ( graphicItem instanceof AscFormat.CShape )
                        printShape(graphicItem, ctx, top, left);

                    else if (graphicItem instanceof AscFormat.CChartSpace )
                        printChart(graphicItem, ctx, top, left);
                }
            }
        }
    };

    _this.getMaxColRow = function() {
        var r = -1, c = -1;
        aObjects.forEach(function (item) {
            r = Math.max(r, item.boundsFromTo.to.row);
            c = Math.max(c, item.boundsFromTo.to.col);
        });

        return new AscCommon.CellBase(r, c);
    };

    _this.clipGraphicsCanvas = function(canvas, graphicOption) {
        if ( canvas instanceof AscCommon.CGraphics ) {

            var x, y, w, h;

            if ( graphicOption ) {
                var updatedRange = graphicOption.getUpdatedRange();

                var offset = worksheet.getCellsOffset();
                var offsetX = worksheet._getColLeft(worksheet.getFirstVisibleCol(true)) - offset.left;
                var offsetY = worksheet._getRowTop(worksheet.getFirstVisibleRow(true)) - offset.top;

                var vr = worksheet.visibleRange;
                var borderOffsetX = (updatedRange.c1 <= vr.c1) ? 0 : 3;
                var borderOffsetY = (updatedRange.r1 <= vr.r1) ? 0 : 3;

                x = worksheet._getColLeft(updatedRange.c1) - offsetX - borderOffsetX;
                y = worksheet._getRowTop(updatedRange.r1) - offsetY - borderOffsetY;
                w = worksheet._getColLeft(updatedRange.c2) - worksheet._getColLeft(updatedRange.c1) + 3;
                h = worksheet._getRowTop(updatedRange.r2) - worksheet._getRowTop(updatedRange.r1) + 3;

                /*canvas.m_oContext.beginPath();
                 canvas.m_oContext.strokeStyle = "#FF0000";
                 canvas.m_oContext.rect(x + 0.5, y + 0.5, w, h);
                 canvas.m_oContext.stroke();*/
            }
            else {
                x = worksheet._getColLeft(0);
                y = worksheet._getRowTop(0);
                w = shapeCtx.m_lWidthPix - x;
                h = shapeCtx.m_lHeightPix - y;
            }

            canvas.m_oContext.save();
            canvas.m_oContext.beginPath();
            canvas.m_oContext.rect(x, y, w, h);
            canvas.m_oContext.clip();

            // этот сэйв нужен для восстановления сложных вложенных клипов
            canvas.m_oContext.save();
        }
    };

    _this.restoreGraphicsCanvas = function(canvas) {
        if ( canvas instanceof AscCommon.CGraphics ) {
            canvas.m_oContext.restore();

            // этот рестор нужен для восстановления сложных вложенных клипов
            canvas.m_oContext.restore();
        }
    };

    //-----------------------------------------------------------------------------------
    // For object type
    //-----------------------------------------------------------------------------------


    _this.calculateObjectMetrics = function (object, width, height) {
        // Обработка картинок большого разрешения
        var metricCoeff = 1;

        var coordsFrom = _this.calculateCoords(object.from);
        var realTopOffset = coordsFrom.y;
        var realLeftOffset = coordsFrom.x;

        var areaWidth = worksheet._getColLeft(worksheet.getLastVisibleCol()) - worksheet._getColLeft(worksheet.getFirstVisibleCol(true)); 	// по ширине
        if (areaWidth < width) {
            metricCoeff = width / areaWidth;

            width = areaWidth;
            height /= metricCoeff;
        }

        var areaHeight = worksheet._getRowTop(worksheet.getLastVisibleRow()) - worksheet._getRowTop(worksheet.getFirstVisibleRow(true)); 	// по высоте
        if (areaHeight < height) {
            metricCoeff = height / areaHeight;

            height = areaHeight;
            width /= metricCoeff;
        }

        var toCell = worksheet.findCellByXY(realLeftOffset + width, realTopOffset + height, true, false, false);
        object.to.col = toCell.col;
        object.to.colOff = pxToMm(toCell.colOff);
        object.to.row = toCell.row;
        object.to.rowOff = pxToMm(toCell.rowOff);
    };



    _this.addImageObjectCallback = function (_image, options) {
        var isOption = options && options.cell;
        if (!_image.Image) {
            worksheet.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.UplImageUrl, c_oAscError.Level.NoCritical);
        } else {
            var drawingObject = _this.createDrawingObject();
            drawingObject.worksheet = worksheet;

            var activeCell = worksheet.model.selectionRange.activeCell;
            drawingObject.from.col = isOption ? options.cell.col : activeCell.col;
            drawingObject.from.row = isOption ? options.cell.row : activeCell.row;

            _this.calculateObjectMetrics(drawingObject, isOption ? options.width : _image.Image.width, isOption ? options.height : _image.Image.height);

            var coordsFrom = _this.calculateCoords(drawingObject.from);
            var coordsTo = _this.calculateCoords(drawingObject.to);
            _this.controller.addImageFromParams(_image.src, pxToMm(coordsFrom.x) + MOVE_DELTA, pxToMm(coordsFrom.y) + MOVE_DELTA, pxToMm(coordsTo.x - coordsFrom.x), pxToMm(coordsTo.y - coordsFrom.y));
        }
    };



    _this.addImageDrawingObject = function(imageUrls, options) {
        if (imageUrls && _this.canEdit()) {
            api.ImageLoader.LoadImagesWithCallback(imageUrls, function(){
                // CImage
                _this.objectLocker.reset();
                _this.objectLocker.addObjectId(AscCommon.g_oIdCounter.Get_NewId());
                _this.objectLocker.checkObjects(function (bLock) {
                    if (bLock !== true)
                        return;
                    _this.controller.resetSelection();
                    History.Create_NewPoint();
                    for(var i = 0; i < imageUrls.length; ++i){
                        var sImageUrl = imageUrls[i];
                        var _image = api.ImageLoader.LoadImage(sImageUrl, 1);
                        if (null != _image) {
                            _this.addImageObjectCallback(_image, options);
                        } else {
                            worksheet.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.UplImageUrl, c_oAscError.Level.NoCritical);
                            break;
                        }
                    }
                    _this.controller.startRecalculate();
                    worksheet.setSelectionShape(true);
                });
            }, []);






        }
    };

    _this.addTextArt = function(nStyle)
    {
        if (_this.canEdit()) {

            var oVisibleRange = worksheet.getVisibleRange();

            _this.objectLocker.reset();
            _this.objectLocker.addObjectId(AscCommon.g_oIdCounter.Get_NewId());
            _this.objectLocker.checkObjects(function (bLock) {
                if (bLock !== true)
                    return;
                _this.controller.resetSelection();
                var dLeft = worksheet.getCellLeft(oVisibleRange.c1, 3);
                var dTop = worksheet.getCellTop(oVisibleRange.r1, 3);
                var dRight = worksheet.getCellLeft(oVisibleRange.c2, 3) + worksheet.getColumnWidth(oVisibleRange.c2, 3);
                var dBottom = worksheet.getCellTop(oVisibleRange.r2, 3) + worksheet.getRowHeight(oVisibleRange.r2, 3);
                _this.controller.addTextArtFromParams(nStyle, dLeft, dTop, dRight - dLeft, dBottom - dTop, worksheet.model);
                worksheet.setSelectionShape(true);
            });
        }

    };

    _this.addSignatureLine = function(sGuid, sSigner, sSigner2, sEmail, Width, Height, sImgUrl)
    {
        _this.objectLocker.reset();
        _this.objectLocker.addObjectId(AscCommon.g_oIdCounter.Get_NewId());
        _this.objectLocker.checkObjects(function (bLock) {
            if (bLock !== true)
                return;
            _this.controller.resetSelection();
            var dLeft = worksheet.getCellLeft(worksheet.model.selectionRange.activeCell.col, 3);
            var dTop = worksheet.getCellTop(worksheet.model.selectionRange.activeCell.row, 3);
            var oSignatureLine = AscFormat.fCreateSignatureShape(sGuid, sSigner, sSigner2, sEmail, false, worksheet.model, Width, Height, sImgUrl);
            oSignatureLine.spPr.xfrm.setOffX(dLeft);
            oSignatureLine.spPr.xfrm.setOffY(dTop);
            oSignatureLine.addToDrawingObjects();
            oSignatureLine.checkDrawingBaseCoords();
            _this.controller.selectObject(oSignatureLine, 0);
            _this.controller.startRecalculate();
            worksheet.setSelectionShape(true);
            window["Asc"]["editor"].sendEvent("asc_onAddSignature", sGuid);
        });
    };

    _this.addMath = function(Type){
        if (_this.canEdit() && _this.controller) {

            var oTargetContent = _this.controller.getTargetDocContent();
            if(oTargetContent){

                _this.controller.checkSelectedObjectsAndCallback(function(){
                    var MathElement = new AscCommonWord.MathMenu(Type);
                    _this.controller.paragraphAdd(MathElement, false);
                }, [], false, AscDFH.historydescription_Spreadsheet_CreateGroup);
                return;
            }

            _this.objectLocker.reset();
            _this.objectLocker.addObjectId(AscCommon.g_oIdCounter.Get_NewId());
            _this.objectLocker.checkObjects(function (bLock) {
                if (bLock !== true)
                    return;
                _this.controller.resetSelection();

                var activeCell = worksheet.model.selectionRange.activeCell;
                var coordsFrom = _this.calculateCoords({col: activeCell.col, row: activeCell.row, colOff: 0, rowOff: 0});

                History.Create_NewPoint();
                var oTextArt = _this.controller.createTextArt(0, false, worksheet.model, "");
                _this.controller.resetSelection();
                oTextArt.setWorksheet(_this.controller.drawingObjects.getWorksheetModel());
                oTextArt.setDrawingObjects(_this.controller.drawingObjects);
                oTextArt.addToDrawingObjects();

                var oContent = oTextArt.getDocContent();
                if(oContent){
                    oContent.MoveCursorToStartPos(false);
                    oContent.AddToParagraph(new AscCommonWord.MathMenu(Type), false);
                }
                oTextArt.checkExtentsByDocContent();
                oTextArt.spPr.xfrm.setOffX(pxToMm(coordsFrom.x) + MOVE_DELTA);
                oTextArt.spPr.xfrm.setOffY(pxToMm(coordsFrom.y) + MOVE_DELTA);

                oTextArt.checkDrawingBaseCoords();
                _this.controller.selectObject(oTextArt, 0);
                var oContent = oTextArt.getDocContent();
                _this.controller.selection.textSelection = oTextArt;
                //oContent.SelectAll();
                oTextArt.addToRecalculate();
                _this.controller.startRecalculate();
                worksheet.setSelectionShape(true);
            });
        }
    };


    _this.setMathProps = function(MathProps)
    {
        _this.controller.setMathProps(MathProps);
    }

    _this.setListType = function(type, subtype)
    {
        var NumberInfo =
            {
                Type    : 0,
                SubType : -1
            };

        NumberInfo.Type    = type;
        NumberInfo.SubType = subtype;
        _this.controller.checkSelectedObjectsAndCallback(_this.controller.setParagraphNumbering, [AscFormat.fGetPresentationBulletByNumInfo(NumberInfo)], false, AscDFH.historydescription_Presentation_SetParagraphNumbering);
    };

    _this.editImageDrawingObject = function(imageUrl) {

        if ( imageUrl ) {
            var _image = api.ImageLoader.LoadImage(imageUrl, 1);

            var addImageObject = function (_image) {

                if ( !_image.Image ) {
                    worksheet.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.UplImageUrl, c_oAscError.Level.NoCritical);
                }
                else {
                    if ( api.isImageChangeUrl ) {
                        var imageProp = new Asc.asc_CImgProperty();
                        imageProp.ImageUrl = _image.src;
                        _this.setGraphicObjectProps(imageProp);
                        api.isImageChangeUrl = false;
                    }
                    else if ( api.isShapeImageChangeUrl ) {
                        var imgProps = new Asc.asc_CImgProperty();
                        var shapeProp = new Asc.asc_CShapeProperty();
                        imgProps.ShapeProperties = shapeProp;
                        shapeProp.fill = new Asc.asc_CShapeFill();
                        shapeProp.fill.type = Asc.c_oAscFill.FILL_TYPE_BLIP;
                        shapeProp.fill.fill = new Asc.asc_CFillBlip();
                        shapeProp.fill.fill.asc_putUrl(_image.src);
                        if(api.textureType !== null && api.textureType !== undefined){
                            shapeProp.fill.fill.asc_putType(api.textureType);
                        }
                        api.textureType = null;
                        _this.setGraphicObjectProps(imgProps);
                        api.isShapeImageChangeUrl = false;
                    }
                    else if(api.isTextArtChangeUrl)
                    {

                        var imgProps = new Asc.asc_CImgProperty();
                        var AscShapeProp = new Asc.asc_CShapeProperty();
                        imgProps.ShapeProperties = AscShapeProp;
                        var oFill = new Asc.asc_CShapeFill();
                        oFill.type = Asc.c_oAscFill.FILL_TYPE_BLIP;
                        oFill.fill = new Asc.asc_CFillBlip();
                        oFill.fill.asc_putUrl(imageUrl);
                        if(api.textureType !== null && api.textureType !== undefined){
                            oFill.fill.asc_putType(api.textureType);
                        }
                        api.textureType = null;
                        AscShapeProp.textArtProperties = new Asc.asc_TextArtProperties();
                        AscShapeProp.textArtProperties.asc_putFill(oFill);

                        _this.setGraphicObjectProps(imgProps);
                        api.isTextArtChangeUrl = false;
                    }

                    _this.showDrawingObjects(true);
                }
            };

            if (null != _image) {
                addImageObject(_image);
            }
            else {
                _this.asyncImageEndLoaded = function(_image) {
                    addImageObject(_image);
                    _this.asyncImageEndLoaded = null;
                }
            }
        }
    };

    _this.addChartDrawingObject = function(chart) {

        if (!_this.canEdit())
            return;

        worksheet.setSelectionShape(true);

        if ( chart instanceof Asc.asc_ChartSettings )
        {
            if(api.isChartEditor)
            {
				_this.controller.selectObject(aObjects[0].graphicObject, 0);
				_this.controller.editChartDrawingObjects(chart);
                return;
            }

            _this.objectLocker.reset();
            _this.objectLocker.addObjectId(AscCommon.g_oIdCounter.Get_NewId());
            _this.objectLocker.checkObjects(function(bLock){
                if(bLock)
                {
                    _this.controller.addChartDrawingObject(chart);
                }
            });
        }
        else if ( isObject(chart) && chart["binary"] )
        {
            var model = worksheet.model;
			History.Clear();
			History.TurnOff();

            for (var i = 0; i < aObjects.length; i++) {
                aObjects[i].graphicObject.deleteDrawingBase();
            }
			aObjects.length = 0;

			var oAllRange = model.getRange3(0, 0, model.getRowsCount(), model.getColsCount());
			oAllRange.cleanAll();

			worksheet.endEditChart();

			//worksheet._clean();

            var asc_chart_binary = new Asc.asc_CChartBinary();
            asc_chart_binary.asc_setBinary(chart["binary"]);
            asc_chart_binary.asc_setThemeBinary(chart["themeBinary"]);
            asc_chart_binary.asc_setColorMapBinary(chart["colorMapBinary"]);
            var oNewChartSpace = asc_chart_binary.getChartSpace(model);
            var theme = asc_chart_binary.getTheme();
            if(theme)
            {
                model.workbook.theme = theme;
            }
            if(chart["cTitle"] || chart["cDescription"]){
                if(!oNewChartSpace.nvGraphicFramePr){
                    var nv_sp_pr = new AscFormat.UniNvPr();
                    nv_sp_pr.cNvPr.setId(1024);
                    oNewChartSpace.setNvSpPr(nv_sp_pr);
                }
                oNewChartSpace.setTitle(chart["cTitle"]);
                oNewChartSpace.setDescription(chart["cDescription"]);
            }
            var colorMapOverride = asc_chart_binary.getColorMap();
            if(colorMapOverride)
            {
                AscFormat.DEFAULT_COLOR_MAP = colorMapOverride;
            }

            if(typeof chart["urls"] === "string") {
                AscCommon.g_oDocumentUrls.addUrls(JSON.parse(chart["urls"]));
            }
            var font_map = {};
            oNewChartSpace.documentGetAllFontNames(font_map);
            AscFormat.checkThemeFonts(font_map, model.workbook.theme.themeElements.fontScheme);
            window["Asc"]["editor"]._loadFonts(font_map,
                function()
                {
                    var max_r = 0, max_c = 0;

                    var series = oNewChartSpace.getAllSeries(), ser;
					
					function fFillCell(oCell, sNumFormat, value)
					{
						var oCellValue = new AscCommonExcel.CCellValue();
						if(AscFormat.isRealNumber(value))
						{
							oCellValue.number = value;
							oCellValue.type = AscCommon.CellValueType.Number;
						}
						else
						{
							oCellValue.text = value;
							oCellValue.type = AscCommon.CellValueType.String;
						}
						oCell.setNumFormat(sNumFormat);
						oCell.setValueData(new AscCommonExcel.UndoRedoData_CellValueData(null, oCellValue));
					}
					
                    function fillTableFromRef(ref)
                    {
                        var cache = ref.numCache ? ref.numCache : (ref.strCache ? ref.strCache : null);
                        var lit_format_code;
                        if(cache)
                        {
							lit_format_code = (typeof cache.formatCode === "string" && cache.formatCode.length > 0) ? cache.formatCode : "General";

                            var sFormula = ref.f + "";
                            if(sFormula[0] === '(')
                                sFormula = sFormula.slice(1);
                            if(sFormula[sFormula.length-1] === ')')
                                sFormula = sFormula.slice(0, -1);
                            var f1 = sFormula;

                            var arr_f = f1.split(",");
                            var pt_index = 0, i, j, pt, nPtCount, k;
                            for(i = 0; i < arr_f.length; ++i)
                            {
                                var parsed_ref = parserHelp.parse3DRef(arr_f[i]);
                                if(parsed_ref)
                                {
                                    var source_worksheet = model.workbook.getWorksheetByName(parsed_ref.sheet);
                                    if(source_worksheet === model)
                                    {
                                        var range = source_worksheet.getRange2(parsed_ref.range);
                                        if(range)
                                        {
											range = range.bbox;

                                            if(range.r1 > max_r)
                                                max_r = range.r1;
                                            if(range.r2 > max_r)
                                                max_r = range.r2;

                                            if(range.c1 > max_c)
                                                max_c = range.c1;
                                            if(range.c2 > max_c)
                                                max_c = range.c2;

                                            if(i === arr_f.length - 1)
                                            {
                                                nPtCount = cache.getPtCount();
                                                if((nPtCount - pt_index) <=(range.r2 - range.r1 + 1))
                                                {
                                                    for(k = range.c1; k <= range.c2; ++k)
                                                    {
                                                        for(j = range.r1; j <= range.r2; ++j)
                                                        {
                                                            source_worksheet._getCell(j, k, function(cell) {
                                                                pt = cache.getPtByIndex(pt_index + j - range.r1);
                                                                if(pt)
                                                                {
                                                                    fFillCell(cell, typeof pt.formatCode === "string" && pt.formatCode.length > 0 ? pt.formatCode : lit_format_code, pt.val);
                                                                }
                                                            });
                                                        }
                                                    }
                                                    pt_index += (range.r2 - range.r1 + 1);
                                                }
                                                else if((nPtCount - pt_index) <= (range.c2 - range.c1 + 1))
                                                {
                                                    for(k = range.r1; k <= range.r2; ++k)
                                                    {
                                                        for(j = range.c1;  j <= range.c2; ++j)
                                                        {
                                                            source_worksheet._getCell(k, j, function(cell) {
                                                                pt = cache.getPtByIndex(pt_index + j - range.c1);
                                                                if(pt)
                                                                {
                                                                    fFillCell(cell, typeof pt.formatCode === "string" && pt.formatCode.length > 0 ? pt.formatCode : lit_format_code, pt.val);
                                                                }
                                                            });
                                                        }
                                                    }
                                                    pt_index += (range.c2 - range.c1 + 1);
                                                }
                                            }
                                            else
                                            {
                                                if(range.r1 === range.r2)
                                                {
                                                    for(j = range.c1;  j <= range.c2; ++j)
                                                    {
                                                        source_worksheet._getCell(range.r1, j, function(cell) {
                                                            pt = cache.getPtByIndex(pt_index);
                                                            if(pt)
                                                            {
                                                                fFillCell(cell, typeof pt.formatCode === "string" && pt.formatCode.length > 0 ? pt.formatCode : lit_format_code, pt.val);
                                                            }
                                                            ++pt_index;
                                                        });
                                                    }
                                                }
                                                else
                                                {
                                                    for(j = range.r1; j <= range.r2; ++j)
                                                    {
                                                        source_worksheet._getCell(j, range.c1, function(cell) {
                                                            pt = cache.getPtByIndex(pt_index);
                                                            if(pt)
                                                            {
                                                                fFillCell(cell, typeof pt.formatCode === "string" && pt.formatCode.length > 0 ? pt.formatCode : lit_format_code, pt.val);
                                                            }
                                                            ++pt_index;
                                                        });
                                                    }
                                                }

                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    var first_num_ref;
                    if(series[0])
                    {
                        if(series[0].val)
                            first_num_ref = series[0].val.numRef;
                        else if(series[0].yVal)
                            first_num_ref = series[0].yVal.numRef;
                    }
                    if(first_num_ref)
                    {
                        var resultRef = parserHelp.parse3DRef(first_num_ref.f);
                        if(resultRef)
                        {
                            model.workbook.aWorksheets[0].sName = resultRef.sheet;
                            if(series[0] && series[0].xVal && series[0].xVal.numRef)
                            {
                                fillTableFromRef(series[0].xVal.numRef);
                            }
                            if(series[0].cat && series[0].cat.strRef)
                            {
                                fillTableFromRef(series[0].cat.strRef);
                            }
                            for(var i = 0; i < series.length; ++i)
                            {
                                ser = series[i];
                                if(ser.val && ser.val.numRef)
                                {
                                    fillTableFromRef(ser.val.numRef);
                                }
                                if(ser.yVal && ser.yVal.numRef)
                                {
                                    fillTableFromRef(ser.yVal.numRef);
                                }
                                if(ser.cat && ser.cat.numRef)
                                {
                                    fillTableFromRef(ser.cat.numRef);
                                }
                                if(ser.cat && ser.cat.strRef)
                                {
                                    fillTableFromRef(ser.cat.strRef);
                                }
                                if(ser.tx && ser.tx.strRef)
                                {
                                    fillTableFromRef(ser.tx.strRef);
                                }
                            }
                        }
                    }
					oAllRange = oAllRange.bbox;
					oAllRange.r2 = Math.max(oAllRange.r2, max_r);
					oAllRange.c2 = Math.max(oAllRange.c2, max_c);
					worksheet._updateRange(oAllRange);
					worksheet.draw();
                    aImagesSync.length = 0;
                    oNewChartSpace.getAllRasterImages(aImagesSync);
                    oNewChartSpace.setBDeleted(false);
                    oNewChartSpace.setWorksheet(model);
                    oNewChartSpace.addToDrawingObjects();
                    oNewChartSpace.recalcInfo.recalculateReferences = false;
                    oNewChartSpace.recalculate();
                    AscFormat.CheckSpPrXfrm(oNewChartSpace);

                    var canvas_height = worksheet.drawingCtx.getHeight(3);
                    var pos_y = (canvas_height - oNewChartSpace.spPr.xfrm.extY)/2;
                    if(pos_y < 0)
                    {
                        pos_y = 0;
                    }

                    var canvas_width = worksheet.drawingCtx.getWidth(3);
                    var pos_x = (canvas_width - oNewChartSpace.spPr.xfrm.extX)/2;
                    if(pos_x < 0)
                    {
                        pos_x = 0;
                    }
                    oNewChartSpace.spPr.xfrm.setOffX(pos_x);
                    oNewChartSpace.spPr.xfrm.setOffY(pos_y);
                    oNewChartSpace.checkDrawingBaseCoords();
                    oNewChartSpace.recalculate();
                    worksheet._scrollToRange(_this.getSelectedDrawingsRange());
                    _this.showDrawingObjects(false);
                    _this.controller.resetSelection();
                    _this.controller.selectObject(oNewChartSpace, 0);
                    _this.controller.updateSelectionState();
                    _this.sendGraphicObjectProps();
                    History.TurnOn();
                    if(aImagesSync.length > 0)
                    {
                        window["Asc"]["editor"].ImageLoader.LoadDocumentImages(aImagesSync, null, function(){_this.showDrawingObjects(true)});
                    }
                });


        }
    };

    _this.editChartDrawingObject = function(chart)
    {
        if ( chart )
        {
            if(api.isChartEditor)
            {
				_this.controller.selectObject(aObjects[0].graphicObject, 0);
            }
            _this.controller.editChartDrawingObjects(chart);
            //_this.showDrawingObjects(false);
        }
    };

    _this.checkSparklineGroupMinMaxVal = function(oSparklineGroup)
    {
        var maxVal = null, minVal = null, i, j, sparkline;
        if(oSparklineGroup.type !== Asc.c_oAscSparklineType.Stacked &&
            (Asc.c_oAscSparklineAxisMinMax.Group === oSparklineGroup.minAxisType || Asc.c_oAscSparklineAxisMinMax.Group === oSparklineGroup.maxAxisType))
        {
            for(i = 0; i < oSparklineGroup.arrSparklines.length; ++i)
            {
				sparkline = oSparklineGroup.arrSparklines[i];
                if (!sparkline.oCacheView) {
					sparkline.oCacheView = new CSparklineView();
					sparkline.oCacheView.initFromSparkline(sparkline, oSparklineGroup, worksheet);
                }
                var aPoints = AscFormat.getPtsFromSeries(sparkline.oCacheView.chartSpace.chart.plotArea.charts[0].series[0]);
                for(j = 0; j < aPoints.length; ++j)
                {
                    if(Asc.c_oAscSparklineAxisMinMax.Group === oSparklineGroup.maxAxisType)
                    {
                        if(maxVal === null)
                        {
                            maxVal = aPoints[j].val;
                        }
                        else
                        {
                            if(maxVal < aPoints[j].val)
                            {
                                maxVal = aPoints[j].val;
                            }
                        }
                    }
                    if(Asc.c_oAscSparklineAxisMinMax.Group === oSparklineGroup.minAxisType)
                    {
                        if(minVal === null)
                        {
                            minVal = aPoints[j].val;
                        }
                        else
                        {
                            if(minVal > aPoints[j].val)
                            {
                                minVal = aPoints[j].val;
                            }
                        }
                    }
                }
            }
            if(maxVal !== null || minVal !== null)
            {
                for(i = 0; i < oSparklineGroup.arrSparklines.length; ++i)
                {
					oSparklineGroup.arrSparklines[i].oCacheView.setMinMaxValAx(minVal, maxVal, oSparklineGroup);
                }
            }
        }
    };

    _this.drawSparkLineGroups = function(oDrawingContext, aSparklineGroups, range, offsetX, offsetY)
    {

        var graphics, i, j, sparkline;
        if(oDrawingContext instanceof AscCommonExcel.CPdfPrinter)
        {
            graphics = oDrawingContext.DocumentRenderer;
        }
        else
        {
            graphics = new AscCommon.CGraphics();
            graphics.init(oDrawingContext.ctx, oDrawingContext.getWidth(0), oDrawingContext.getHeight(0),
                oDrawingContext.getWidth(3)*nSparklineMultiplier, oDrawingContext.getHeight(3)*nSparklineMultiplier);
            graphics.m_oFontManager = AscCommon.g_fontManager;
        }

        for(i = 0; i < aSparklineGroups.length; ++i) {
            var oSparklineGroup = aSparklineGroups[i];

            if(oSparklineGroup.type !== Asc.c_oAscSparklineType.Stacked &&
                (Asc.c_oAscSparklineAxisMinMax.Group === oSparklineGroup.minAxisType || Asc.c_oAscSparklineAxisMinMax.Group === oSparklineGroup.maxAxisType))
            {
                _this.checkSparklineGroupMinMaxVal(oSparklineGroup);
            }
            for(j = 0; j < oSparklineGroup.arrSparklines.length; ++j) {
				sparkline = oSparklineGroup.arrSparklines[j];
				if (!sparkline.checkInRange(range)) {
					continue;
				}

                if (!sparkline.oCacheView) {
					sparkline.oCacheView = new CSparklineView();
					sparkline.oCacheView.initFromSparkline(sparkline, oSparklineGroup, worksheet);
                }

                if(oDrawingContext instanceof AscCommonExcel.CPdfPrinter)
                {
                    graphics.SaveGrState();
                    var _baseTransform = new AscCommon.CMatrix();
                    _baseTransform.sx /= nSparklineMultiplier;
                    _baseTransform.sy /= nSparklineMultiplier;

                    graphics.SetBaseTransform(_baseTransform);
                }

				sparkline.oCacheView.draw(graphics, offsetX, offsetY);

                if(oDrawingContext instanceof AscCommonExcel.CPdfPrinter)
                {
                    graphics.SetBaseTransform(null);
                    graphics.RestoreGrState();
                }
            }
        }
        if(oDrawingContext instanceof AscCommonExcel.CPdfPrinter)
        {
        }
        else
        {
            oDrawingContext.restore();
        }
    };

    _this.rebuildChartGraphicObjects = function(data)
    {
        if(!worksheet){
            return;
        }
        if(data.length === 0){
            return;
        }
        AscFormat.ExecuteNoHistory(function(){
            var wsViews = Asc["editor"].wb.wsViews;
            var changedArr = [];
            for (var i = 0; i < data.length; ++i) {
                changedArr.push(new BBoxInfo(worksheet.model, data[i]));
            }

            for(i = 0; i < wsViews.length; ++i)
            {
                if(wsViews[i] && wsViews[i].objectRender)
                {
                    wsViews[i].objectRender.rebuildCharts(changedArr);
                    wsViews[i].objectRender.recalculate(true);
                }
            }
        }, _this, []);


    };

    _this.pushToAObjects = function(aDrawing)
    {
        aObjects = [];
        for(var i = 0; i < aDrawing.length; ++i)
        {
            aObjects.push(aDrawing[i]);
        }
    };

    _this.rebuildCharts = function(data)
    {
        for(var i = 0; i < aObjects.length; ++i)
        {
            if(aObjects[i].graphicObject.rebuildSeries)
            {
                aObjects[i].graphicObject.rebuildSeries(data);
            }
        }
    };

    _this.updateDrawingObject = function(bInsert, operType, updateRange) {

        if(!History.Is_On())
            return;

        var metrics = null;
		var count, bNeedRedraw = false, offset;
       //this.controller.checkObjectsAndCallback(
       //    function()
       //    {
            for (var i = 0; i < aObjects.length; i++)
            {
                var obj = aObjects[i];
                    metrics = { from: {}, to: {} };
                    metrics.from.col = obj.from.col; metrics.to.col = obj.to.col;
                    metrics.from.colOff = obj.from.colOff; metrics.to.colOff = obj.to.colOff;
                    metrics.from.row = obj.from.row; metrics.to.row = obj.to.row;
                    metrics.from.rowOff = obj.from.rowOff; metrics.to.rowOff = obj.to.rowOff;

                    if (bInsert)
                    {		// Insert
                        switch (operType)
                        {
                            case c_oAscInsertOptions.InsertColumns:
                            {
                                count = updateRange.c2 - updateRange.c1 + 1;
                                // Position
                                if (updateRange.c1 <= obj.from.col) {
                                    metrics.from.col += count;
                                    metrics.to.col += count;
                                }
                                else if ((updateRange.c1 > obj.from.col) && (updateRange.c1 <= obj.to.col)) {
                                    metrics.to.col += count;
                                }
                                else
                                    metrics = null;

                            }
                                break;
                            case c_oAscInsertOptions.InsertCellsAndShiftRight:

                                break;

                            case c_oAscInsertOptions.InsertRows:
                            {
                                // Position
                                count = updateRange.r2 - updateRange.r1 + 1;

                                if (updateRange.r1 <= obj.from.row) {
                                    metrics.from.row += count;
                                    metrics.to.row += count;
                                }
                                else if ((updateRange.r1 > obj.from.row) && (updateRange.r1 <= obj.to.row)) {
                                    metrics.to.row += count;
                                }
                                else
                                    metrics = null;
                            }
                                break;
                            case c_oAscInsertOptions.InsertCellsAndShiftDown:

                                break;
                        }
                    }
                    else {				// Delete
                        switch (operType)
                        {
                            case c_oAscDeleteOptions.DeleteColumns:
                            {

                                // Position
                                count = updateRange.c2 - updateRange.c1 + 1;

                                if (updateRange.c1 <= obj.from.col) {

                                    // outside
                                    if (updateRange.c2 < obj.from.col) {
                                        metrics.from.col -= count;
                                        metrics.to.col -= count;
                                    }
                                    // inside
                                    else {
                                        metrics.from.col = updateRange.c1;
                                        metrics.from.colOff = 0;

                                        offset = 0;
                                        if (obj.to.col - updateRange.c2 - 1 > 0)
                                            offset = obj.to.col - updateRange.c2 - 1;
                                        else {
                                            offset = 1;
                                            metrics.to.colOff = 0;
                                        }
                                        metrics.to.col = metrics.from.col + offset;
                                    }
                                }

                                else if ((updateRange.c1 > obj.from.col) && (updateRange.c1 <= obj.to.col)) {

                                    // outside
                                    if (updateRange.c2 >= obj.to.col) {
                                        metrics.to.col = updateRange.c1;
                                        metrics.to.colOff = 0;
                                    }
                                    else
                                        metrics.to.col -= count;
                                }
                                else
                                    metrics = null;


                            }
                                break;
                            case c_oAscDeleteOptions.DeleteCellsAndShiftLeft:
                                // Range

                                break;

                            case c_oAscDeleteOptions.DeleteRows:
                            {

                                // Position
                                count = updateRange.r2 - updateRange.r1 + 1;

                                if (updateRange.r1 <= obj.from.row) {

                                    // outside
                                    if (updateRange.r2 < obj.from.row) {
                                        metrics.from.row -= count;
                                        metrics.to.row -= count;
                                    }
                                    // inside
                                    else {
                                        metrics.from.row = updateRange.r1;
                                        metrics.from.colOff = 0;

                                        offset = 0;
                                        if (obj.to.row - updateRange.r2 - 1 > 0)
                                            offset = obj.to.row - updateRange.r2 - 1;
                                        else {
                                            offset = 1;
                                            metrics.to.colOff = 0;
                                        }
                                        metrics.to.row = metrics.from.row + offset;
                                    }
                                }

                                else if ((updateRange.r1 > obj.from.row) && (updateRange.r1 <= obj.to.row)) {

                                    // outside
                                    if (updateRange.r2 >= obj.to.row) {
                                        metrics.to.row = updateRange.r1;
                                        metrics.to.colOff = 0;
                                    }
                                    else
                                        metrics.to.row -= count;
                                }
                                else
                                    metrics = null;

                            }
                                break;
                            case c_oAscDeleteOptions.DeleteCellsAndShiftTop:
                                // Range

                                break;
                        }
                    }

                    // Normalize position
                    if (metrics)
                    {
                        if (metrics.from.col < 0)
                        {
                            metrics.from.col = 0;
                            metrics.from.colOff = 0;
                        }

                        if (metrics.to.col <= 0) {
                            metrics.to.col = 1;
                            metrics.to.colOff = 0;
                        }

                        if (metrics.from.row < 0) {
                            metrics.from.row = 0;
                            metrics.from.rowOff = 0;
                        }

                        if (metrics.to.row <= 0) {
                            metrics.to.row = 1;
                            metrics.to.rowOff = 0;
                        }

                        if (metrics.from.col == metrics.to.col) {
                            metrics.to.col++;
                            metrics.to.colOff = 0;
                        }
                        if (metrics.from.row == metrics.to.row) {
                            metrics.to.row++;
                            metrics.to.rowOff = 0;
                        }

                        /*obj.from.col = metrics.from.col;
                        obj.from.colOff = metrics.from.colOff;
                        obj.from.row = metrics.from.row;
                        obj.from.rowOff = metrics.from.rowOff;

                        obj.to.col = metrics.to.col;
                        obj.to.colOff = metrics.to.colOff;
                        obj.to.row = metrics.to.row;
                        obj.to.rowOff = metrics.to.rowOff;
                        */

                        var coords = _this.calculateCoords(metrics.from);


                        if(obj.graphicObject.spPr && obj.graphicObject.spPr.xfrm){
                            var rot = AscFormat.isRealNumber(obj.graphicObject.spPr.xfrm.rot) ? obj.graphicObject.spPr.xfrm.rot : 0;
                            rot = AscFormat.normalizeRotate(rot);
                            if (AscFormat.checkNormalRotate(rot))
                            {
                                obj.graphicObject.spPr.xfrm.setOffX(pxToMm(coords.x));
                                obj.graphicObject.spPr.xfrm.setOffY(pxToMm(coords.y));
                            }
                            else
                            {
                                obj.graphicObject.spPr.xfrm.setOffX(pxToMm(coords.x) - obj.graphicObject.spPr.xfrm.extX/2 + obj.graphicObject.spPr.xfrm.extY/2);
                                obj.graphicObject.spPr.xfrm.setOffY(pxToMm(coords.y) - obj.graphicObject.spPr.xfrm.extY/2 + obj.graphicObject.spPr.xfrm.extX/2);
                            }
                            obj.graphicObject.checkDrawingBaseCoords();
                        }
                        obj.graphicObject.recalculate();
                        bNeedRedraw = true;
                    }
                }

        //    },  []);
        bNeedRedraw && _this.showDrawingObjects(true);
    };


    _this.updateSizeDrawingObjects = function(target, bNoChangeCoords) {

        var oGraphicObject;
        var bCheck, bRecalculate;
        if(!History.Is_On() || true === bNoChangeCoords){
            if (target.target === AscCommonExcel.c_oTargetType.RowResize) {
                for (i = 0; i < aObjects.length; i++) {
                    drawingObject = aObjects[i];
                    bCheck = false;
                    if(target.target === AscCommonExcel.c_oTargetType.RowResize){
                        if(drawingObject.from.row >= target.row){
                            bCheck = true;
                        }
                    }
                    else{
                        if(drawingObject.from.col >= target.col){
                            bCheck = true;
                        }
                    }
                    if (bCheck) {
                        oGraphicObject = drawingObject.graphicObject;
                        if(oGraphicObject){
                            if(oGraphicObject.handleUpdateExtents) {

                                bRecalculate = true;
                                if(oGraphicObject.recalculateTransform){
                                    var oldX = oGraphicObject.x;
                                    var oldY = oGraphicObject.y;
                                    var oldExtX = oGraphicObject.extX;
                                    var oldExtY = oGraphicObject.extY;
                                    oGraphicObject.recalculateTransform();
                                    var fDelta = 0.01;
                                    bRecalculate = false;
                                    if(!AscFormat.fApproxEqual(oldX, oGraphicObject.x, fDelta) || !AscFormat.fApproxEqual(oldY, oGraphicObject.y, fDelta)
                                        || !AscFormat.fApproxEqual(oldExtX, oGraphicObject.extX, fDelta) || !AscFormat.fApproxEqual(oldExtY, oGraphicObject.extY, fDelta)){
                                        bRecalculate = true;
                                    }
                                }
                                if(bRecalculate){
                                    oGraphicObject.handleUpdateExtents();
                                    oGraphicObject.recalculate();
                                }
                            }
                            else {
                                if(oGraphicObject.recalculateTransform){
                                    oGraphicObject.recalculateTransform();
                                }
                                if(oGraphicObject.recalculateBounds){
                                    oGraphicObject.recalculateBounds();
                                }
                            }
                        }
                    }
                }
            }
            return;
        }

        var i, bNeedRecalc = false, drawingObject, coords;
        if (target.target === AscCommonExcel.c_oTargetType.RowResize) {
            for (i = 0; i < aObjects.length; i++) {
                drawingObject = aObjects[i];

                if (drawingObject.from.row >= target.row) {
                    coords = _this.calculateCoords(drawingObject.from);
                    AscFormat.CheckSpPrXfrm(drawingObject.graphicObject);

                    var rot = AscFormat.isRealNumber(drawingObject.graphicObject.spPr.xfrm.rot) ? drawingObject.graphicObject.spPr.xfrm.rot : 0;
                    rot = AscFormat.normalizeRotate(rot);
                    if (AscFormat.checkNormalRotate(rot)) {
                        drawingObject.graphicObject.spPr.xfrm.setOffX(pxToMm(coords.x));
                        drawingObject.graphicObject.spPr.xfrm.setOffY(pxToMm(coords.y));
                    } else {
                        drawingObject.graphicObject.spPr.xfrm.setOffX(pxToMm(coords.x) - drawingObject.graphicObject.spPr.xfrm.extX / 2 + drawingObject.graphicObject.spPr.xfrm.extY / 2);
                        drawingObject.graphicObject.spPr.xfrm.setOffY(pxToMm(coords.y) - drawingObject.graphicObject.spPr.xfrm.extY / 2 + drawingObject.graphicObject.spPr.xfrm.extX / 2);
                    }
                    drawingObject.graphicObject.checkDrawingBaseCoords();
                    bNeedRecalc = true;
                }
            }
        } else {
            for (i = 0; i < aObjects.length; i++) {
                drawingObject = aObjects[i];

                if (drawingObject.from.col >= target.col) {
                    coords = _this.calculateCoords(drawingObject.from);
                    AscFormat.CheckSpPrXfrm(drawingObject.graphicObject);

                    var rot = AscFormat.isRealNumber(drawingObject.graphicObject.spPr.xfrm.rot) ? drawingObject.graphicObject.spPr.xfrm.rot : 0;
                    rot = AscFormat.normalizeRotate(rot);
                    if (AscFormat.checkNormalRotate(rot)) {
                        drawingObject.graphicObject.spPr.xfrm.setOffX(pxToMm(coords.x));
                        drawingObject.graphicObject.spPr.xfrm.setOffY(pxToMm(coords.y));
                    } else {
                        drawingObject.graphicObject.spPr.xfrm.setOffX(pxToMm(coords.x) - drawingObject.graphicObject.spPr.xfrm.extX / 2 + drawingObject.graphicObject.spPr.xfrm.extY / 2);
                        drawingObject.graphicObject.spPr.xfrm.setOffY(pxToMm(coords.y) - drawingObject.graphicObject.spPr.xfrm.extY / 2 + drawingObject.graphicObject.spPr.xfrm.extX / 2);
                    }

                    drawingObject.graphicObject.checkDrawingBaseCoords();
                    bNeedRecalc = true;
                }
            }
        }
        if (bNeedRecalc) {
            _this.controller.recalculate2();
            _this.showDrawingObjects(true);
        }
    };


    _this.moveRangeDrawingObject = function(oBBoxFrom, oBBoxTo) {

        if ( oBBoxFrom && oBBoxTo )
        {
            var selected_objects = _this.controller.selection.groupSelection ? _this.controller.selection.groupSelection.selectedObjects : _this.controller.selectedObjects;
            var chart;
            if(selected_objects.length === 1 && selected_objects[0].getObjectType() === AscDFH.historyitem_type_ChartSpace)
            {
                chart = selected_objects[0];
            }
            var object_to_check  = _this.controller.selection.groupSelection ? _this.controller.selection.groupSelection : chart;

            if(chart && !(!chart.bbox || !chart.bbox.seriesBBox || oBBoxTo.isEqual(chart.bbox.seriesBBox)))
            {
                var editChart = function (drawingObject)
                {
					var options = new Asc.asc_ChartSettings();
					var catHeadersBBox, serHeadersBBox;
                    var final_bbox = oBBoxTo.clone();
                    var bOneCell = false;
                    if(!chart.bbox.catBBox && !chart.bbox.serBBox){
                        if(chart.bbox.seriesBBox.r1 === chart.bbox.seriesBBox.r2 && chart.bbox.seriesBBox.c1 === chart.bbox.seriesBBox.c2){
                            bOneCell = true;
                        }
                    }
                    if((!bOneCell && chart.bbox.seriesBBox.bVert) || (bOneCell && (final_bbox.r1 === final_bbox.r2)))
                    {
						options.putInColumns(false);
                        if(chart.bbox.catBBox && chart.bbox.catBBox.r1 === chart.bbox.catBBox.r2 && oBBoxTo.r1 > chart.bbox.catBBox.r1)
                        {
							catHeadersBBox = {
                                r1: chart.bbox.catBBox.r1,
                                r2: chart.bbox.catBBox.r1,
                                c1: oBBoxTo.c1,
                                c2: oBBoxTo.c2
                            };
                        }


                        if(chart.bbox.serBBox && chart.bbox.serBBox && chart.bbox.serBBox.c1 === chart.bbox.serBBox.c2 && chart.bbox.serBBox.c1 < oBBoxTo.c1)
                        {
                            serHeadersBBox = {
                                r1: oBBoxTo.r1,
                                r2: oBBoxTo.r2,
                                c1: chart.bbox.serBBox.c1,
                                c2: chart.bbox.serBBox.c2
                            };
                        }
                      //
                      //  if(chart.bbox.catBBox && oBBoxTo.r1 === chart.bbox.seriesBBox.r1)
                      //  {
                      //      --final_bbox.r1;
                      //  }
                      //  if(chart.bbox.serBBox && oBBoxTo.c1 === chart.bbox.seriesBBox.c1)
                      //  {
                      //      --final_bbox.c1;
                      //  }
                    }
                    else
                    {
						options.putInColumns(true);

                        if(chart.bbox.catBBox && chart.bbox.catBBox.c1 === chart.bbox.catBBox.c2 && oBBoxTo.c1 > chart.bbox.catBBox.c1)
                        {
                            catHeadersBBox = {
                                r1: oBBoxTo.r1,
                                r2: oBBoxTo.r2,
                                c1: chart.bbox.catBBox.c1,
                                c2: chart.bbox.catBBox.c2
                            };
                        }


                        if(chart.bbox.serBBox && chart.bbox.serBBox && chart.bbox.serBBox.r1 === chart.bbox.serBBox.r2 && chart.bbox.serBBox.r1 < oBBoxTo.r1)
                        {
                            serHeadersBBox = {
                                r1: chart.bbox.serBBox.r1,
                                r2: chart.bbox.serBBox.r2,
                                c1: oBBoxTo.c1,
                                c2: oBBoxTo.c2
                            };
                        }


                        //if(chart.bbox.catBBox && oBBoxTo.c1 === chart.bbox.seriesBBox.c1)
                        //{
                        //    --final_bbox.c1;
                        //}
                        //if(chart.bbox.serBBox && oBBoxTo.r1 === chart.bbox.seriesBBox.r1)
                        //{
                        //    --final_bbox.r1;
                        //}
                    }

                    var sRef = (new Asc.Range(final_bbox.c1, final_bbox.r1, final_bbox.c2, final_bbox.r2)).getName(AscCommonExcel.referenceType.A);
                    options.range = parserHelp.get3DRef(worksheet.model.sName, sRef);

					var chartSeries = AscFormat.getChartSeries(worksheet.model, options, catHeadersBBox, serHeadersBBox);
					drawingObject.rebuildSeriesFromAsc(chartSeries);
                    _this.controller.startRecalculate();
                    _this.sendGraphicObjectProps();
                };
                var callbackCheck = function (result) {
                    if(result)
                    {
                        History.Create_NewPoint(AscDFH.historydescription_ChartDrawingObjects);
                        editChart(chart);
                        _this.showDrawingObjects(true);
                    }
                    else
                    {
                        _this.selectDrawingObjectRange(chart);
                    }
                };
                _this.objectLocker.reset();
                _this.objectLocker.addObjectId(object_to_check.Get_Id());
                _this.objectLocker.checkObjects(callbackCheck);
            }
        }
    };

    //-----------------------------------------------------------------------------------
    // Chart
    //-----------------------------------------------------------------------------------

    _this.updateChartReferences = function(oldWorksheet, newWorksheet, bNoRedraw)
    {
        AscFormat.ExecuteNoHistory(function(){
            for (var i = 0; i < aObjects.length; i++) {
                var graphicObject = aObjects[i].graphicObject;
                if ( graphicObject.updateChartReferences )
                {
                    graphicObject.updateChartReferences(oldWorksheet, newWorksheet);
                }
            }
        }, this, []);

    };
    _this.updateChartReferences2 = function(oldWorksheet, newWorksheet)
    {
        for (var i = 0; i < aObjects.length; i++) {
            var graphicObject = aObjects[i].graphicObject;
            if ( graphicObject.updateChartReferences2 )
            {
                graphicObject.updateChartReferences2(oldWorksheet, newWorksheet);
            }
        }
    };

    //-----------------------------------------------------------------------------------
    // Graphic object
    //-----------------------------------------------------------------------------------

    _this.addGraphicObject = function(graphic, position, lockByDefault) {

        worksheet.cleanSelection();
        var drawingObject = _this.createDrawingObject();
        drawingObject.graphicObject = graphic;
        graphic.setDrawingBase(drawingObject);

        var ret;
        if (AscFormat.isRealNumber(position)) {
            aObjects.splice(position, 0, drawingObject);
            ret = position;
        }
        else {
            ret = aObjects.length;
            aObjects.push(drawingObject);
        }

        if ( lockByDefault ) {
            _this.objectLocker.reset();
            _this.objectLocker.addObjectId(drawingObject.graphicObject.Id);
            _this.objectLocker.checkObjects( function(result) {} );
        }
        worksheet.setSelectionShape(true);

        return ret;
    };


    _this.addOleObject = function(fWidth, fHeight, nWidthPix, nHeightPix, sLocalUrl, sData, sApplicationId){
        var drawingObject = _this.createDrawingObject();
        drawingObject.worksheet = worksheet;

        var activeCell = worksheet.model.selectionRange.activeCell;
        drawingObject.from.col = activeCell.col;
        drawingObject.from.row = activeCell.row;

        _this.calculateObjectMetrics(drawingObject, nWidthPix, nHeightPix);

        var coordsFrom = _this.calculateCoords(drawingObject.from);

        _this.objectLocker.reset();
        _this.objectLocker.addObjectId(AscCommon.g_oIdCounter.Get_NewId());
        _this.objectLocker.checkObjects(function (bLock) {
            if (bLock !== true)
                return;
            _this.controller.resetSelection();
            _this.controller.addOleObjectFromParams(pxToMm(coordsFrom.x), pxToMm(coordsFrom.y), fWidth, fHeight, nWidthPix, nHeightPix, sLocalUrl, sData, sApplicationId);
            worksheet.setSelectionShape(true);
        });
    };

    _this.editOleObject = function(oOleObject, sData, sImageUrl, nPixWidth, nPixHeight, bResize){
        this.controller.editOleObjectFromParams(oOleObject, sData, sImageUrl, nPixWidth, nPixHeight, bResize);
    };

    _this.startEditCurrentOleObject = function(){
        this.controller.startEditCurrentOleObject();
    };

    _this.groupGraphicObjects = function() {

        if ( _this.controller.canGroup() ) {
            _this.controller.checkSelectedObjectsAndCallback(_this.controller.createGroup, [], false, AscDFH.historydescription_Spreadsheet_CreateGroup);
            worksheet.setSelectionShape(true);
        }
    };

    _this.unGroupGraphicObjects = function() {

        if ( _this.controller.canUnGroup() ) {
            _this.controller.unGroup();
            worksheet.setSelectionShape(true);
            api.isStartAddShape = false;
        }
    };

    _this.getDrawingBase = function(graphicId) {
        var oDrawing = AscCommon.g_oTableId.Get_ById(graphicId);
        if(oDrawing){
            while(oDrawing.group){
                oDrawing = oDrawing.group;
            }
        }
        if(oDrawing.drawingBase){
            for (var i = 0; i < aObjects.length; i++) {
                if ( aObjects[i] === oDrawing.drawingBase )
                    return aObjects[i];
            }
        }
        return null;
    };

    _this.deleteDrawingBase = function(graphicId) {

        var position = null;
        var bRedraw = false;
        for (var i = 0; i < aObjects.length; i++) {
            if ( aObjects[i].graphicObject.Id == graphicId ) {
                aObjects[i].graphicObject.deselect(_this.controller);
                if ( aObjects[i].isChart() )
                    worksheet.endEditChart();
                aObjects.splice(i, 1);
                bRedraw = true;
                position = i;
                break;
            }
        }

        /*if ( bRedraw ) {
         worksheet._endSelectionShape();
         _this.sendGraphicObjectProps();
         _this.showDrawingObjects(true);
         }*/

        return position;
    };

    _this.checkGraphicObjectPosition = function(x, y, w, h) {

        /*	Принцип:
         true - если перемещение в области или требуется увеличить лист вправо/вниз
         false - наезд на хидеры
         */

        var response = { result: true, x: 0, y: 0 };


        // выход за границу слева или сверху
        if ( y < 0 ) {
            response.result = false;
            response.y = Math.abs(y);
        }
        if ( x < 0 ) {
            response.result = false;
            response.x = Math.abs(x);
        }

        return response;
    };

    _this.resetLockedGraphicObjects = function() {

        for (var i = 0; i < aObjects.length; i++) {
            aObjects[i].graphicObject.lockType = c_oAscLockTypes.kLockTypeNone;
        }
    };

    _this.tryResetLockedGraphicObject = function(id) {

        var bObjectFound = false;
        for (var i = 0; i < aObjects.length; i++) {
            if ( aObjects[i].graphicObject.Id == id ) {
                aObjects[i].graphicObject.lockType = c_oAscLockTypes.kLockTypeNone;
                bObjectFound = true;
                break;
            }
        }
        return bObjectFound;
    };

    _this.getDrawingCanvas = function() {
        return { shapeCtx: shapeCtx, shapeOverlayCtx: shapeOverlayCtx, autoShapeTrack: autoShapeTrack, trackOverlay: trackOverlay };
    };

    _this.convertMetric = function(val, from, to) {
        /* Параметры конвертирования (from/to)
         0 - px, 1 - pt, 2 - in, 3 - mm
         */
        return val * ascCvtRatio(from, to);
    };

    _this.convertPixToMM = function(pix)
    {
        return _this.convertMetric(pix, 0, 3);
    };
    _this.getSelectedGraphicObjects = function() {
        return _this.controller.selectedObjects;
    };

    _this.selectedGraphicObjectsExists = function() {
        return _this.controller && _this.controller.selectedObjects.length > 0;
    };

    _this.loadImageRedraw = function(imageUrl) {

        var _image = api.ImageLoader.LoadImage(imageUrl, 1);

        if (null != _image) {
            imageLoaded(_image);
        }
        else {
            _this.asyncImageEndLoaded = function(_image) {
                imageLoaded(_image);
                _this.asyncImageEndLoaded = null;
            }
        }

        function imageLoaded(_image) {
            if ( !_image.Image ) {
                worksheet.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.UplImageUrl, c_oAscError.Level.NoCritical);
            }
            else
                _this.showDrawingObjects(true);
        }
    };

    _this.getOriginalImageSize = function() {

        var selectedObjects = _this.controller.selectedObjects;
        if ( (selectedObjects.length == 1) ) {

            if(AscFormat.isRealNumber(selectedObjects[0].m_fDefaultSizeX) && AscFormat.isRealNumber(selectedObjects[0].m_fDefaultSizeY)){
                return new AscCommon.asc_CImageSize( selectedObjects[0].m_fDefaultSizeX, selectedObjects[0].m_fDefaultSizeY, true);
            }
            if(selectedObjects[0].isImage()){
                var imageUrl = selectedObjects[0].getImageUrl();

                var _image = api.ImageLoader.map_image_index[AscCommon.getFullImageSrc2(imageUrl)];
                if (_image != undefined && _image.Image != null && _image.Status == AscFonts.ImageLoadStatus.Complete) {

                    var _w = 1, _h = 1;
                    var bIsCorrect = false;
                    if (_image.Image != null) {

                        bIsCorrect = true;
                        _w = Math.max( pxToMm(_image.Image.width), 1 );
                        _h = Math.max( pxToMm(_image.Image.height), 1 );
                    }

                    return new AscCommon.asc_CImageSize( _w, _h, bIsCorrect);
                }
            }
        }
        return new AscCommon.asc_CImageSize( 50, 50, false );
    };

    _this.sendGraphicObjectProps = function () {
        if (worksheet) {
            worksheet.handlers.trigger("selectionChanged");
        }
    };

    _this.setGraphicObjectProps = function(props) {

        var objectProperties = props;

		var _img;
        if ( !AscCommon.isNullOrEmptyString(objectProperties.ImageUrl) ) {
            _img = api.ImageLoader.LoadImage(objectProperties.ImageUrl, 1);

            if (null != _img) {
                _this.controller.setGraphicObjectProps( objectProperties );
            }
            else {
                _this.asyncImageEndLoaded = function(_image) {
                    _this.controller.setGraphicObjectProps( objectProperties );
                    _this.asyncImageEndLoaded = null;
                }
            }
        }
        else if ( objectProperties.ShapeProperties && objectProperties.ShapeProperties.fill && objectProperties.ShapeProperties.fill.fill &&
            !AscCommon.isNullOrEmptyString(objectProperties.ShapeProperties.fill.fill.url) ) {

            if (window['IS_NATIVE_EDITOR']) {
                _this.controller.setGraphicObjectProps( objectProperties );
            } else {
                _img = api.ImageLoader.LoadImage(objectProperties.ShapeProperties.fill.fill.url, 1);
                if ( null != _img ) {
                    _this.controller.setGraphicObjectProps( objectProperties );
                }
                else {
                    _this.asyncImageEndLoaded = function(_image) {
                        _this.controller.setGraphicObjectProps( objectProperties );
                        _this.asyncImageEndLoaded = null;
                    }
                }
            }
        }
        else {
            objectProperties.ImageUrl = null;

            if(!api.noCreatePoint || api.exucuteHistory)
            {
                if( !api.noCreatePoint && !api.exucuteHistory && api.exucuteHistoryEnd)
                {
                    if(_this.nCurPointItemsLength === -1){
                        _this.controller.setGraphicObjectProps( props );
                    }
                    else{
                        _this.controller.setGraphicObjectPropsCallBack(props);
                        _this.controller.startRecalculate();
                        _this.sendGraphicObjectProps();
                    }
                    api.exucuteHistoryEnd = false;
                    _this.nCurPointItemsLength = -1;
                }
                else
                {
                    _this.controller.setGraphicObjectProps( props );
                }
                if(api.exucuteHistory)
                {

                    var Point =  History.Points[History.Index];
                    if(Point)
                    {
                        _this.nCurPointItemsLength = Point.Items.length;
                    }
                    else
                    {
                        _this.nCurPointItemsLength = -1;
                    }
                    api.exucuteHistory = false;
                }
            }
            else
            {

                var Point =  History.Points[History.Index];
                if(Point && Point.Items.length > 0)
                {
                    if(this.nCurPointItemsLength > -1){
                        var nBottomIndex = - 1;
                        for ( var Index = Point.Items.length - 1; Index > nBottomIndex; Index-- )
                        {
                            var Item = Point.Items[Index];
                            if(!Item.Class.Read_FromBinary2)
                                Item.Class.Undo( Item.Type, Item.Data, Item.SheetId );
                            else
                                Item.Class.Undo(Item.Data);
                        }
                        _this.controller.setSelectionState(Point.SelectionState);
                        Point.Items.length = 0;

                        _this.controller.setGraphicObjectPropsCallBack(props);
                        _this.controller.startRecalculate();
                    }
                    else{
                        _this.controller.setGraphicObjectProps( props );
                        var Point =  History.Points[History.Index];
                        if(Point)
                        {
                            _this.nCurPointItemsLength = Point.Items.length;
                        }
                        else
                        {
                            _this.nCurPointItemsLength = -1;
                        }
                    }
                }
            }
            api.exucuteHistoryEnd = false;
        }

    };

    _this.showChartSettings = function() {
        api.wb.handlers.trigger("asc_onShowChartDialog", true);
    };

    _this.setDrawImagePlaceParagraph = function(element_id, props) {
        _this.drawingDocument.InitGuiCanvasTextProps(element_id);
        _this.drawingDocument.DrawGuiCanvasTextProps(props);
    };

    //-----------------------------------------------------------------------------------
    // Graphic object mouse & keyboard events
    //-----------------------------------------------------------------------------------

    _this.graphicObjectMouseDown = function(e, x, y) {
        var offsets = _this.drawingArea.getOffsets(x, y, true);
        if ( offsets )
            _this.controller.onMouseDown( e, pxToMm(x - offsets.x), pxToMm(y - offsets.y) );
    };

    _this.graphicObjectMouseMove = function(e, x, y) {
        e.IsLocked = e.isLocked;

        _this.lastX = x;
        _this.lastY = y;
        var offsets = _this.drawingArea.getOffsets(x, y, true);
        if ( offsets )
            _this.controller.onMouseMove( e, pxToMm(x - offsets.x), pxToMm(y - offsets.y) );
    };

    _this.graphicObjectMouseUp = function(e, x, y) {
        var offsets = _this.drawingArea.getOffsets(x, y, true);
        if ( offsets )
            _this.controller.onMouseUp( e, pxToMm(x - offsets.x), pxToMm(y - offsets.y) );
    };

    // keyboard

    _this.graphicObjectKeyDown = function(e) {
        return _this.controller.onKeyDown( e );
    };

    _this.graphicObjectKeyPress = function(e) {

        e.KeyCode = e.keyCode;
        e.CtrlKey = e.metaKey || e.ctrlKey;
        e.AltKey = e.altKey;
        e.ShiftKey = e.shiftKey;
        e.Which = e.which;
        return _this.controller.onKeyPress( e );
    };

    //-----------------------------------------------------------------------------------
    // Asc
    //-----------------------------------------------------------------------------------

    _this.cleanWorksheet = function() {
    };

    _this.getWordChartObject = function() {
        for (var i = 0; i < aObjects.length; i++) {
            var drawingObject = aObjects[i];

            if ( drawingObject.isChart() ) {
                return new asc_CChartBinary(drawingObject.graphicObject);
            }
        }
        return null;
    };

    _this.getAscChartObject = function(bNoLock) {

        var settings;
        if(api.isChartEditor)
        {
            return _this.controller.getPropsFromChart(aObjects[0].graphicObject);
        }
        settings = _this.controller.getChartProps();
        if ( !settings )
        {
            settings = new Asc.asc_ChartSettings();
            var selectedRange = worksheet.getSelectedRange();
            if (selectedRange)
            {
                var box = selectedRange.getBBox0();
                settings.putInColumns((box.r2 - box.r1 > box.c2 - box.c1));
            }
            var oRangeValue = worksheet.getSelectionRangeValue();
            if(oRangeValue){
                settings.putRange(oRangeValue.asc_getName());
            }

            settings.putStyle(2);
            settings.putType(Asc.c_oAscChartTypeSettings.lineNormal);
            settings.putTitle(Asc.c_oAscChartTitleShowSettings.noOverlay);
            settings.putShowHorAxis(true);
            settings.putShowVerAxis(true);
            var series = AscFormat.getChartSeries(worksheet.model, settings);
            // if(series && series.series.length > 1)
            // {
            //     settings.putLegendPos(Asc.c_oAscChartLegendShowSettings.right);
            // }
            // else
            // {
            //     settings.putLegendPos(Asc.c_oAscChartLegendShowSettings.none);
            // }
            settings.putHorAxisLabel(Asc.c_oAscChartHorAxisLabelShowSettings.none);
            settings.putVertAxisLabel(Asc.c_oAscChartVertAxisLabelShowSettings.none);
            settings.putDataLabelsPos(Asc.c_oAscChartDataLabelsPos.none);
            settings.putHorGridLines(Asc.c_oAscGridLinesSettings.major);
            settings.putVertGridLines(Asc.c_oAscGridLinesSettings.none);
            //settings.putInColumns(false);
            settings.putSeparator(",");
            settings.putLine(true);
            settings.putShowMarker(false);

            var vert_axis_settings = new AscCommon.asc_ValAxisSettings();
            settings.putVertAxisProps(vert_axis_settings);
            vert_axis_settings.setDefault();

            var hor_axis_settings = new AscCommon.asc_CatAxisSettings();
            settings.putHorAxisProps(hor_axis_settings);
            hor_axis_settings.setDefault();
        }
        else{
            if(true !== bNoLock){
                this.controller.checkSelectedObjectsAndFireCallback(function(){});
            }
        }
        return settings;
    };

    //-----------------------------------------------------------------------------------
    // Selection
    //-----------------------------------------------------------------------------------

    _this.selectDrawingObjectRange = function(drawing) {

		worksheet.cleanSelection();
        worksheet.endEditChart();

        if(!drawing.bbox || drawing.bbox.worksheet !== worksheet.model)
            return;

        if(drawing.bbox.serBBox)
        {
            worksheet._drawElements(worksheet._drawSelectionElement,
              asc.Range(drawing.bbox.serBBox.c1, drawing.bbox.serBBox.r1, drawing.bbox.serBBox.c2,
                drawing.bbox.serBBox.r2, true), AscCommonExcel.selectionLineType.Selection | AscCommonExcel.selectionLineType.Resize,
              AscCommonExcel.c_oAscFormulaRangeBorderColor[1]);
        }
        if(drawing.bbox.catBBox)
        {
            worksheet._drawElements(worksheet._drawSelectionElement,
              asc.Range(drawing.bbox.catBBox.c1, drawing.bbox.catBBox.r1, drawing.bbox.catBBox.c2,
                drawing.bbox.catBBox.r2, true), AscCommonExcel.selectionLineType.Selection | AscCommonExcel.selectionLineType.Resize,
              AscCommonExcel.c_oAscFormulaRangeBorderColor[2]);
        }
        var BB = drawing.bbox.seriesBBox;
        var range = asc.Range(BB.c1, BB.r1, BB.c2, BB.r2, true);
        worksheet.setChartRange(range);
        worksheet._drawSelection();
    };

    _this.unselectDrawingObjects = function() {

        worksheet.endEditChart();
        _this.controller.resetSelectionState();
        _this.OnUpdateOverlay();
    };

    _this.getDrawingObject = function(id) {

        for (var i = 0; i < aObjects.length; i++) {
            if (aObjects[i].graphicObject.Id == id)
                return aObjects[i];
        }
        return null;
    };

    _this.getGraphicSelectionType = function(id) {

        var selected_objects, selection, controller = _this.controller;
        if(controller.selection.groupSelection)
        {
            selected_objects = controller.selection.groupSelection.selectedObjects;
            selection = controller.selection.groupSelection.selection;
        }
        else
        {
            selected_objects = controller.selectedObjects;
            selection = controller.selection;
        }
        if(selection.chartSelection && selection.chartSelection.selection.textSelection)
        {
            return c_oAscSelectionType.RangeChartText;
        }
        if(selection.textSelection)
        {
            return c_oAscSelectionType.RangeShapeText;
        }
        if(selected_objects[0] )
        {
            if(selected_objects[0].getObjectType() === AscDFH.historyitem_type_ChartSpace && selected_objects.length === 1)
                return c_oAscSelectionType.RangeChart;

            if(selected_objects[0].getObjectType() === AscDFH.historyitem_type_ImageShape)
                return c_oAscSelectionType.RangeImage;

            return c_oAscSelectionType.RangeShape;

        }
        return undefined;
    };

    //-----------------------------------------------------------------------------------
    // Position
    //-----------------------------------------------------------------------------------

    _this.setGraphicObjectLayer = function(layerType) {
        _this.controller.setGraphicObjectLayer(layerType);
    };

    _this.setGraphicObjectAlign = function(alignType) {
        _this.controller.setGraphicObjectAlign(alignType);
    };

    _this.saveSizeDrawingObjects = function() {

        for (var i = 0; i < aObjects.length; i++) {
            var obj = aObjects[i];

            obj.size.width = obj.getWidthFromTo();
            obj.size.height = obj.getHeightFromTo();
        }
    };

    _this.checkCursorDrawingObject = function(x, y) {

        var offsets = _this.drawingArea.getOffsets(x, y);
       // console.log('getOffsets: ' + x + ':' + y);
        if ( offsets ) {
            var objectInfo = { cursor: null, id: null, object: null };
            var graphicObjectInfo = _this.controller.isPointInDrawingObjects( pxToMm(x - offsets.x), pxToMm(y - offsets.y) );
           // console.log('isPointInDrawingObjects: ' + pxToMm(x - offsets.x) + ':' + pxToMm(y - offsets.y));
            if ( graphicObjectInfo && graphicObjectInfo.objectId ) {
                objectInfo.object = _this.getDrawingBase(graphicObjectInfo.objectId);
                if(objectInfo.object){
                    objectInfo.id = graphicObjectInfo.objectId;
                    objectInfo.cursor = graphicObjectInfo.cursorType;
                    objectInfo.hyperlink = graphicObjectInfo.hyperlink;
                }
                else{
                    return null;
                }
                return objectInfo;
            }
        }
        return null;
    };

    _this.getPositionInfo = function(x, y) {

        var info = new CCellObjectInfo();

        var tmp = worksheet._findColUnderCursor(x, true);
        if (tmp) {
            info.col = tmp.col;
            info.colOff = pxToMm(x - worksheet._getColLeft(info.col));
        }
        tmp = worksheet._findRowUnderCursor(y, true);
        if (tmp) {
            info.row = tmp.row;
            info.rowOff = pxToMm(y - worksheet._getRowTop(info.row));
        }

        return info;
    };


    _this.checkCurrentTextObjectExtends = function()
    {
        var oController = this.controller;
        if(oController)
        {
            var oTargetTextObject = AscFormat.getTargetTextObject(oController);
            if(oTargetTextObject.checkExtentsByDocContent)
            {
                oTargetTextObject.checkExtentsByDocContent(true, true);
            }
        }
    };

    _this.beginCompositeInput = function(){
        History.Create_NewPoint(AscDFH.historydescription_Document_CompositeInput);
        _this.controller.CreateDocContent();
        _this.drawingDocument.TargetStart();
        _this.drawingDocument.TargetShow();
        var oContent = _this.controller.getTargetDocContent(true);
        if (!oContent) {
            return false;
        }
        var oPara = oContent.GetCurrentParagraph();
        if (!oPara) {
            return false;
        }
        if (true === oContent.IsSelectionUse())
            oContent.Remove(1, true, false, true);
        var oRun = oPara.Get_ElementByPos(oPara.Get_ParaContentPos(false, false));
        if (!oRun || !(oRun instanceof ParaRun)) {
            return false;
        }

        _this.CompositeInput = {
            Run    : oRun,
            Pos    : oRun.State.ContentPos,
            Length : 0
        };

        oRun.Set_CompositeInput(_this.CompositeInput);
        _this.controller.startRecalculate();
        _this.sendGraphicObjectProps();
        return true;
    };

    _this.Begin_CompositeInput = function(){
        if(_this.controller){
            _this.controller.checkSelectedObjectsAndCallback(_this.beginCompositeInput, [], false, AscDFH.historydescription_Document_CompositeInput);
        }
    };


    _this.addCompositeText = function(nCharCode){

        if (null === _this.CompositeInput)
            return;

        var oRun = _this.CompositeInput.Run;
        var nPos = _this.CompositeInput.Pos + _this.CompositeInput.Length;
        var oChar;

        if (para_Math_Run === oRun.Type)
        {
            oChar = new CMathText();
            oChar.add(nCharCode);
        }
        else
        {
            if (32 == nCharCode || 12288 == nCharCode)
                oChar = new ParaSpace();
            else
                oChar = new ParaText(nCharCode);
        }

        oRun.Add_ToContent(nPos, oChar, true);
        _this.CompositeInput.Length++;
    };
    _this.Add_CompositeText = function(nCharCode)
    {

        if (null === _this.CompositeInput)
            return;
        History.Create_NewPoint(AscDFH.historydescription_Document_CompositeInputReplace);
        _this.addCompositeText(nCharCode);

        _this.checkCurrentTextObjectExtends();
        _this.controller.recalculate();
        _this.controller.recalculateCurPos();
        _this.controller.updateSelectionState();
    };

    _this.removeCompositeText = function(nCount){
        if (null === _this.CompositeInput)
            return;

        var oRun = _this.CompositeInput.Run;
        var nPos = _this.CompositeInput.Pos + _this.CompositeInput.Length;

        var nDelCount = Math.max(0, Math.min(nCount, _this.CompositeInput.Length, oRun.Content.length, nPos));
        oRun.Remove_FromContent(nPos - nDelCount, nDelCount, true);
        _this.CompositeInput.Length -= nDelCount;
    };

    _this.Remove_CompositeText = function(nCount){
        _this.removeCompositeText(nCount);
        _this.checkCurrentTextObjectExtends();
        _this.controller.recalculate();
        _this.controller.updateSelectionState();
    };
    _this.Replace_CompositeText = function(arrCharCodes)
    {
        if (null === _this.CompositeInput)
            return;
        History.Create_NewPoint(AscDFH.historydescription_Document_CompositeInputReplace);
        _this.removeCompositeText(_this.CompositeInput.Length);
        for (var nIndex = 0, nCount = arrCharCodes.length; nIndex < nCount; ++nIndex)
        {
            _this.addCompositeText(arrCharCodes[nIndex]);
        }
        _this.checkCurrentTextObjectExtends();
		_this.controller.startRecalculate();
        _this.controller.updateSelectionState();
    };
    _this.Set_CursorPosInCompositeText = function(nPos)
    {
        if (null === _this.CompositeInput)
            return;
        var oRun = _this.CompositeInput.Run;

        var nInRunPos = Math.max(Math.min(_this.CompositeInput.Pos + nPos, _this.CompositeInput.Pos + _this.CompositeInput.Length, oRun.Content.length), _this.CompositeInput.Pos);
        oRun.State.ContentPos = nInRunPos;
        _this.controller.updateSelectionState();
    };
    _this.Get_CursorPosInCompositeText = function()
    {
        if (null === _this.CompositeInput)
            return 0;

        var oRun = _this.CompositeInput.Run;
        var nInRunPos = oRun.State.ContentPos;
        var nPos = Math.min(_this.CompositeInput.Length, Math.max(0, nInRunPos - _this.CompositeInput.Pos));
        return nPos;
    };
    _this.End_CompositeInput = function()
    {
        if (null === _this.CompositeInput)
            return;

        var oRun = _this.CompositeInput.Run;
        oRun.Set_CompositeInput(null);
        _this.CompositeInput = null;
        var oController = _this.controller;
        if(oController)
        {
            var oTargetTextObject = AscFormat.getTargetTextObject(oController);
            if(oTargetTextObject && oTargetTextObject.txWarpStructNoTransform)
            {
                oTargetTextObject.recalculateContent();
            }
        }
        _this.sendGraphicObjectProps();
        _this.showDrawingObjects(true);
    };
    _this.Get_MaxCursorPosInCompositeText = function()
    {
        if (null === _this.CompositeInput)
            return 0;

        return _this.CompositeInput.Length;
    };


    //-----------------------------------------------------------------------------------
    // Private Misc Methods
    //-----------------------------------------------------------------------------------

    function ascCvtRatio(fromUnits, toUnits) {
        return asc.getCvtRatio( fromUnits, toUnits, drawingCtx.getPPIX() );
    }

    function mmToPx(val) {
        return val * ascCvtRatio(3, 0);
    }

    function pxToMm(val) {
        return val * ascCvtRatio(0, 3);
    }
}

	DrawingObjects.prototype.calculateCoords = function (cell) {
        var ws = this.getWorksheet();
		var coords = {x: 0, y: 0};
		//0 - px, 1 - pt, 2 - in, 3 - mm
		if (cell && ws) {
			var rowHeight = ws.getRowHeight(cell.row, 3);
			var colWidth = ws.getColumnWidth(cell.col, 3);
			var resultRowOff = cell.rowOff > rowHeight ? rowHeight : cell.rowOff;
			var resultColOff = cell.colOff > colWidth ? colWidth : cell.colOff;
			coords.y = ws._getRowTop(cell.row) + ws.objectRender.convertMetric(resultRowOff, 3, 0) - ws._getRowTop(0);
			coords.x = ws._getColLeft(cell.col) + ws.objectRender.convertMetric(resultColOff, 3, 0) - ws._getColLeft(0);
		}
		return coords;
	};

//-----------------------------------------------------------------------------------
// Universal object locker/checker
//-----------------------------------------------------------------------------------

function ObjectLocker(ws) {
    var asc_applyFunction = AscCommonExcel.applyFunction;

    var _t = this;
    _t.bLock = true;
    var aObjectId = [];
    var worksheet = ws;

    _t.reset = function() {
        _t.bLock = true;
        aObjectId = [];
    };

    _t.addObjectId = function(id) {
        aObjectId.push(id);
    };

    // For array of objects -=Use reset before use=-
    _t.checkObjects = function(callback) {

        var callbackEx = function(result, sync) {
            //if ( worksheet )
            //	worksheet._drawCollaborativeElements(true);
            if ( callback )
                callback(result, sync);
        };

        if(Asc.editor && Asc.editor.collaborativeEditing && Asc.editor.collaborativeEditing.getGlobalLock()){
            callbackEx(false, true);
            return false;
        }
        var bRet = true;
        if (!aObjectId.length) {
            // Запрещено совместное редактирование
            asc_applyFunction(callbackEx, true, true);
            return bRet;
        }

        var sheetId = worksheet.model.getId();
        worksheet.collaborativeEditing.onStartCheckLock();
        for ( var i = 0; i < aObjectId.length; i++ ) {

            var lockInfo = worksheet.collaborativeEditing.getLockInfo( AscCommonExcel.c_oAscLockTypeElem.Object, /*subType*/null, sheetId, aObjectId[i] );

            if ( false === worksheet.collaborativeEditing.getCollaborativeEditing() ) {
                // Пользователь редактирует один: не ждем ответа, а сразу продолжаем редактирование
                asc_applyFunction(callbackEx, true, true);
                callbackEx = undefined;
            }
            if ( false !== worksheet.collaborativeEditing.getLockIntersection(lockInfo, c_oAscLockTypes.kLockTypeMine) ) {
                // Редактируем сами, проверяем дальше
                continue;
            }
            else if ( false !== worksheet.collaborativeEditing.getLockIntersection(lockInfo, c_oAscLockTypes.kLockTypeOther) ) {
                // Уже ячейку кто-то редактирует
                asc_applyFunction(callbackEx, false);
                return false;
            }
            if ( _t.bLock )
                worksheet.collaborativeEditing.addCheckLock(lockInfo);
        }
        if ( _t.bLock )
            worksheet.collaborativeEditing.onEndCheckLock(callbackEx);
        else
            asc_applyFunction(callbackEx, true, true);
        return bRet;
    }
}

function ClickCounter() {
    this.x = 0;
    this.y = 0;

    this.lastX = -1000;
    this.lastY = -1000;

    this.button = 0;
    this.time = 0;
    this.clickCount = 0;
    this.log = false;
}
ClickCounter.prototype.mouseDownEvent = function(x, y, button) {
    var currTime = getCurrentTime();

    if (undefined === button)
        button = 0;

	var _eps = 3 * global_mouseEvent.KoefPixToMM;
	if ((Math.abs(global_mouseEvent.X - global_mouseEvent.LastX) > _eps) || (Math.abs(global_mouseEvent.Y - global_mouseEvent.LastY) > _eps))
	{
		// not only move!!! (touch - fast click in different places)
		global_mouseEvent.LastClickTime = -1;
		global_mouseEvent.ClickCount    = 0;
	}

	this.x = x;
	this.y = y;

	if (this.button === button && Math.abs(this.x - this.lastX) <= _eps && Math.abs(this.y - this.lastY) <= _eps && (currTime - this.time < 500)) {
        ++this.clickCount;
    } else {
        this.clickCount = 1;
    }

    this.lastX = this.x;
	this.lastY = this.y;

    if (this.log) {
        console.log("-----");
        console.log("x-> " + this.x + " : " + x);
        console.log("y-> " + this.y + " : " + y);
        console.log("Time: " + (currTime - this.time));
        console.log("Count: " + this.clickCount);
        console.log("");
    }
    this.time = currTime;
};
ClickCounter.prototype.mouseMoveEvent = function(x, y) {
    if (this.x !== x || this.y !== y) {
        this.x = x;
        this.y = y;
        this.clickCount = 0;

        if (this.log) {
            console.log("Reset counter");
        }
    }
};
ClickCounter.prototype.getClickCount = function() {
    return this.clickCount;
};

//--------------------------------------------------------export----------------------------------------------------
    var prot;
    window['AscFormat'] = window['AscFormat'] || {};
    window['Asc'] = window['Asc'] || {};
    window['AscFormat'].isObject = isObject;
    window['AscFormat'].CCellObjectInfo = CCellObjectInfo;

    window["AscFormat"].asc_CChartStyle = asc_CChartStyle;
    prot = asc_CChartStyle.prototype;
    prot["asc_getStyle"] = prot.asc_getStyle;
    prot["asc_setStyle"] = prot.asc_setStyle;
    prot["asc_getImageUrl"] = prot.asc_getImageUrl;
    prot["asc_setImageUrl"] = prot.asc_setImageUrl;

    window["Asc"]["asc_CChartBinary"] = window["Asc"].asc_CChartBinary = asc_CChartBinary;
    prot = asc_CChartBinary.prototype;
    prot["asc_getBinary"] = prot.asc_getBinary;
    prot["asc_setBinary"] = prot.asc_setBinary;
    prot["asc_getThemeBinary"] = prot.asc_getThemeBinary;
    prot["asc_setThemeBinary"] = prot.asc_setThemeBinary;
    prot["asc_setColorMapBinary"] = prot.asc_setColorMapBinary;
    prot["asc_getColorMapBinary"] = prot.asc_getColorMapBinary;

    window["AscFormat"].asc_CChartSeria = asc_CChartSeria;
    prot = asc_CChartSeria.prototype;
    prot["asc_getValFormula"] = prot.asc_getValFormula;
    prot["asc_setValFormula"] = prot.asc_setValFormula;
    prot["asc_getxValFormula"] = prot.asc_getxValFormula;
    prot["asc_setxValFormula"] = prot.asc_setxValFormula;
    prot["asc_getCatFormula"] = prot.asc_getCatFormula;
    prot["asc_setCatFormula"] = prot.asc_setCatFormula;
    prot["asc_getTitle"] = prot.asc_getTitle;
    prot["asc_setTitle"] = prot.asc_setTitle;
    prot["asc_getTitleFormula"] = prot.asc_getTitleFormula;
    prot["asc_setTitleFormula"] = prot.asc_setTitleFormula;
    prot["asc_getMarkerSize"] = prot.asc_getMarkerSize;
    prot["asc_setMarkerSize"] = prot.asc_setMarkerSize;
    prot["asc_getMarkerSymbol"] = prot.asc_getMarkerSymbol;
    prot["asc_setMarkerSymbol"] = prot.asc_setMarkerSymbol;
    prot["asc_getFormatCode"] = prot.asc_getFormatCode;
    prot["asc_setFormatCode"] = prot.asc_setFormatCode;

    window["AscFormat"].CChangeTableData = CChangeTableData;
    window["AscFormat"].GraphicOption = GraphicOption;
    window["AscFormat"].DrawingObjects = DrawingObjects;
    window["AscFormat"].ClickCounter = ClickCounter;
    window["AscFormat"].aSparklinesStyles = aSparklinesStyles;
    window["AscFormat"].CSparklineView = CSparklineView;
    window["AscFormat"].sFrozenImageUrl = sFrozenImageUrl;
    window["AscFormat"].sFrozenImageRotUrl = sFrozenImageRotUrl;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {

// Import
var ORIENTATION_MIN_MAX = AscFormat.ORIENTATION_MIN_MAX;

var globalBasePercent = 100;
var global3DPersperctive = 30; // ToDo а нужна ли она в ChartsDrawer ?

var c_oChartFloorPosition =
{
	None: 0,
	Left: 1,
	Right: 2,
	Bottom: 3,
	Top: 4
};

/** @constructor */
function Processor3D(width, height, left, right, bottom, top, chartSpace, chartsDrawer) {
	this.widthCanvas = width;
	this.heightCanvas = height;
	
	this.left = left ? left : 0;
	this.right = right ? right : 0;
	this.bottom = bottom ?  bottom : 0;
	this.top = top ? top : 0;
	
	this.cameraDiffZ = 0;
	this.cameraDiffX = 0;
	this.cameraDiffY = 0;
	
	this.scaleY = 1;
	this.scaleX = 1;
	this.scaleZ = 1;
	
	this.aspectRatioY = 1;
	this.aspectRatioX = 1;
	this.aspectRatioZ = 1;
	
	this.specialStandardScaleX = 1;
	
	this.view3D = chartSpace.chart.getView3d();
	this.chartSpace = chartSpace;
	this.chartsDrawer = chartsDrawer;
	
	this.rPerspective = 0;
	
	this.hPercent = null;
	
	this.angleOx = this.view3D && this.view3D.rotX ? (- this.view3D.rotX / 360) * (Math.PI * 2) : 0;
	this.angleOy = this.view3D && this.view3D.rotY ? (- this.view3D.rotY / 360) * (Math.PI * 2) : 0;
	//this.angleOz = this.view3D && this.view3D.rotZ ? (- this.view3D.rotZ / 360) * (Math.PI * 2) : 0;
	
	if(!this.view3D.getRAngAx() && AscFormat.c_oChartTypes.Pie === this.chartsDrawer.calcProp.type)
	{	
		this.angleOy = 0;
	}
	
	this.orientationCatAx = null;
	this.orientationValAx = null;
	
	this.matrixRotateOx = null;
	this.matrixRotateOy = null;
	this.matrixRotateAllAxis = null;
	this.matrixShearXY = null;
	this.projectMatrix = null;
}

Processor3D.prototype.calaculate3DProperties = function(baseDepth, gapDepth, bIsCheck)
{
	this.calculateCommonOptions();
	
	//TODO baseDepth -  не универсальный параметр, позже переделать
	this._calculateAutoHPercent();
	
	//рассчёт коэффициэнта отношения ширины / высоты
	this._calcAspectRatio();
	
	//TODO рассчёт коэффицианты для диаграмм типа standard. позже необходимо отказаться
	//this._calcSpecialStandardScaleX();
	
	//глубина
	this.depthPerspective = this.view3D.getRAngAx() ? this._calculateDepth() : this._calculateDepthPerspective();
	
	//угол перспективы
	this._calculatePerspective(this.view3D);
	
	//после рассчета глубины меняются пропорции ширины и высоты
	if(this.view3D.getRAngAx())
		this._calculateScaleFromDepth();
	
	//сдвиг камеры для того, чтобы попали все линии
	if(!bIsCheck)
	{
		this._calculateCameraDiff();
		
		if(this.view3D.getRAngAx())
		{
			this._recalculateScaleWithMaxWidth();
		}
	}
	
	if(AscFormat.c_oChartTypes.Pie === this.chartsDrawer.calcProp.type && !this.view3D.getRAngAx())
	{
		//TODO пересмотреть функцию
		this.tempChangeAspectRatioForPie();
	}
};

Processor3D.prototype.tempChangeAspectRatioForPie = function()
{
	var perspectiveDepth = this.depthPerspective;
	
	var widthCanvas = this.widthCanvas;
	var originalWidthChart = widthCanvas - this.left - this.right;
	
	var heightCanvas = this.heightCanvas;
	var heightChart = heightCanvas - this.top - this.bottom;
	
	var points = [], faces = [];
	
	points.push(new Point3D(this.left + originalWidthChart / 2, this.top, perspectiveDepth, this));
	points.push(new Point3D(this.left, this.top, perspectiveDepth / 2, this));
	points.push(new Point3D(this.left + originalWidthChart, this.top, perspectiveDepth / 2, this));
	points.push(new Point3D(this.left + originalWidthChart / 2, this.top, 0, this));
	
	points.push(new Point3D(this.left + originalWidthChart / 2, this.top + heightChart, perspectiveDepth, this));
	points.push(new Point3D(this.left, this.top + heightChart, perspectiveDepth / 2, this));
	points.push(new Point3D(this.left + originalWidthChart, this.top + heightChart, perspectiveDepth / 2, this));
	points.push(new Point3D(this.left + originalWidthChart / 2, this.top + heightChart, 0, this));
	
	faces.push([0,1,2,3]);
	faces.push([2,5,4,3]);
	faces.push([1,6,7,0]);
	faces.push([6,5,4,7]);
	faces.push([7,4,3,0]);
	faces.push([1,6,2,5]);
	
	var minMaxOx = this._getMinMaxOx(points, faces);
	var minMaxOy = this._getMinMaxOy(points, faces);
	
	var kF = ((minMaxOx.right - minMaxOx.left) / originalWidthChart);
	if((minMaxOy.bottom - minMaxOy.top) / kF > heightChart)
	{
		kF =  ((minMaxOy.bottom - minMaxOy.top) / heightChart);
	}
	
	this.aspectRatioX = this.aspectRatioX * kF;
	this.aspectRatioY = this.aspectRatioY * kF;
	this.aspectRatioZ = this.aspectRatioZ * kF;
};

Processor3D.prototype.calculateCommonOptions = function()
{
	this.orientationCatAx = this.chartSpace && this.chartSpace.chart.plotArea.catAx ? this.chartSpace.chart.plotArea.catAx.scaling.orientation : ORIENTATION_MIN_MAX;
	this.orientationValAx = this.chartSpace && this.chartSpace.chart.plotArea.valAx ? this.chartSpace.chart.plotArea.valAx.scaling.orientation : ORIENTATION_MIN_MAX;
};

Processor3D.prototype._calculateAutoHPercent = function()
{
	var widthLine = this.widthCanvas - (this.left + this.right);
	var heightLine = this.heightCanvas - (this.top + this.bottom);
	
	if(this.hPercent == null)
	{
		this.hPercent = this.view3D.hPercent === null ? (heightLine / widthLine) : this.view3D.hPercent / 100;
		if(this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar && ((this.view3D.hPercent === null && this.view3D.getRAngAx()) || (this.view3D.hPercent !== null && !this.view3D.getRAngAx())))
			this.hPercent = 1 / this.hPercent;
			
		if(AscFormat.c_oChartTypes.Pie === this.chartsDrawer.calcProp.type)
		{
			this.hPercent = 0.12;
			//this.view3D.depthPercent = 180;
		}
		
	}
};

Processor3D.prototype._recalculateScaleWithMaxWidth = function()
{	
	var widthLine = this.widthCanvas - (this.left + this.right);
	var heightLine = this.heightCanvas - (this.top + this.bottom);
    var widthCanvas = this.widthCanvas;
    //todo оптимальную ширину нужно пересмотреть
    //оптимальная ширина -  ширина при которой не происходит масштабирования по ширине
    var optimalWidth = heightLine * 10;
	
	var subType = this.chartsDrawer.calcProp.subType;
	var type = this.chartsDrawer.calcProp.type;
	var isStandardType = subType === "standard" || type === AscFormat.c_oChartTypes.Line || (type === AscFormat.c_oChartTypes.Area && subType === "normal") || type === AscFormat.c_oChartTypes.Surface;

    var optimalWidthLine, kF;
	if(!isStandardType)
	{
		this.widthCanvas = optimalWidth + (this.left + this.right);
		this._calculateScaleNStandard();
		optimalWidthLine = Math.abs(this.depthPerspective * Math.sin(-this.angleOy)) + ((this.widthCanvas - (this.left + this.right)) / this.aspectRatioX) / this.scaleX;
		kF = optimalWidthLine / widthLine;
		
		if(optimalWidthLine < widthLine)
		{
			this.widthCanvas = widthCanvas;
			this._calculateScaleNStandard();
		}
		else
		{
			this.aspectRatioX = widthLine / ((optimalWidthLine - Math.abs(this.depthPerspective * Math.sin(-this.angleOy))) / kF);
			this.scaleY = this.scaleY * kF;
			this.scaleZ = this.scaleZ * kF;
			
			this.widthCanvas = widthCanvas;
		}

		this._recalculateCameraDiff();
	}
	else
	{
		var scaleX = this.scaleX;
		var scaleY = this.scaleY;
		var scaleZ = this.scaleZ;
		
		var aspectRatioX = this.aspectRatioX;
		var aspectRatioY = this.aspectRatioY;
		var aspectRatioZ = this.aspectRatioZ;
		
		//если будут проблемы с поворотом standard диграмм, раскомментровать!
		//TODO протестировать, и если не будет проблем, то убрать if-else
		if(Math.abs(this.angleOy) > Math.PI)
		{
			//рассчитываем параметры диаграммы при оптимальной ширине
			this.widthCanvas = optimalWidth + (this.left + this.right);
			
			this.calaculate3DProperties(null, null, true);
			
			var newDepth = Math.abs(this.depthPerspective * Math.sin(-this.angleOy));
			optimalWidthLine =  newDepth + ((this.widthCanvas - (this.left + this.right)) / this.aspectRatioX) / this.scaleX;
			kF = optimalWidthLine / widthLine;
			
			if(optimalWidthLine < widthLine)
			{
				this.widthCanvas = widthCanvas;
				this.scaleX = scaleX;
				this.scaleY = scaleY;
				this.scaleZ = scaleZ;
				
				this.aspectRatioX = aspectRatioX;
				this.aspectRatioY = aspectRatioY;
				this.aspectRatioZ = aspectRatioZ;
				
				return;
			}
			
			this.aspectRatioX = widthLine / ((optimalWidthLine - newDepth) / kF);
			this.scaleY = this.scaleY * kF;
			this.scaleZ = this.scaleZ * kF;
			
			this.widthCanvas = widthCanvas;
			
			this._recalculateCameraDiff();
		}
		else
		{
			//рассчитываем параметры диаграммы при оптимальной ширине
			this.widthCanvas = optimalWidth + (this.left + this.right);
			this.calaculate3DProperties(null, null, true);
			
			optimalWidthLine = this.depthPerspective * Math.sin(-this.angleOy) + ((this.widthCanvas - (this.left + this.right)) / this.aspectRatioX) / this.scaleX;
			
			if(optimalWidthLine < widthLine)
			{
				this.widthCanvas = widthCanvas;
				this.scaleX = scaleX;
				this.scaleY = scaleY;
				this.scaleZ = scaleZ;
				
				this.aspectRatioX = aspectRatioX;
				this.aspectRatioY = aspectRatioY;
				this.aspectRatioZ = aspectRatioZ;
				
				return;
			}
			
			kF = optimalWidthLine / widthLine;
			this.aspectRatioX = widthLine / ((optimalWidthLine - this.depthPerspective*Math.sin(-this.angleOy))/kF);
			this.scaleY = this.scaleY * kF;
			this.scaleZ = this.scaleZ * kF;
			
			this.widthCanvas = widthCanvas;
			
			this._recalculateCameraDiff();
		}
	}
};

Processor3D.prototype._calculateScaleNStandard = function()
{
	var ptCount = this.chartsDrawer.calcProp.ptCount;
	
	var widthLine = this.widthCanvas - (this.left + this.right);
	var heightLine = this.heightCanvas - (this.top + this.bottom);
	
	var trueDepth = Math.abs(this.depthPerspective * Math.sin(-this.angleOx));
	var mustHeight = heightLine - trueDepth;
	var mustWidth = this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar ? mustHeight * this.hPercent : mustHeight / this.hPercent;
	
	var areaStackedKf = this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Area && this.chartsDrawer.calcProp.subType !== "normal" ?  (ptCount / ((ptCount - 1))) : 1;
	
	//без маштабирования
	if(this.angleOy === 0)
	{
		this.aspectRatioX = ((this.widthCanvas - (this.left + this.right)) / mustWidth) / areaStackedKf;
		this.scaleX = 1;
		this.scaleY = 1;
		this.aspectRatioY = heightLine / mustHeight;
	}
	else
	{
		this.aspectRatioX = ((this.widthCanvas - (this.left + this.right)) / mustWidth) / areaStackedKf;
		this.scaleX = 1;
		this.scaleY = 1;
		this.aspectRatioY = heightLine / mustHeight;
	}
	
	var optimalWidthLine = (widthLine / this.aspectRatioX) / this.scaleX;
	
	
	if(optimalWidthLine < widthLine)
	{
		return;
	}
	
	var kF = optimalWidthLine / (widthLine);
	this.aspectRatioX = kF * this.aspectRatioX;
	this.scaleY = this.scaleY * kF;
	this.scaleZ = this.scaleZ * kF;
};

Processor3D.prototype._recalculateCameraDiff = function()
{
	this.cameraDiffX = 0;
	this.cameraDiffY = 0;
	this.cameraDiffZ = 0;
	
	this._calculateCameraDiff();
};

Processor3D.prototype.calculateZPositionValAxis = function()
{
	var result = 0;
	if(!this.view3D.getRAngAx())
	{
		var angleOyAbs = Math.abs(this.angleOy);
		if((angleOyAbs >= Math.PI / 2 && angleOyAbs < Math.PI) ||  (angleOyAbs >= 3 * Math.PI / 2 && angleOyAbs < 2 * Math.PI))
			result = this.depthPerspective;
	}
	else if(this.chartsDrawer.calcProp.type !== AscFormat.c_oChartTypes.HBar && this.orientationCatAx !== ORIENTATION_MIN_MAX && this.depthPerspective !== undefined)
	{
		//if(this.chartSpace.chart.plotArea.valAx && this.chartSpace.chart.plotArea.valAx.yPoints && this.chartSpace.chart.plotArea.catAx.posY === this.chartSpace.chart.plotArea.valAx.yPoints[0].pos)
			result = this.depthPerspective;
	}
	else if(this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar && this.orientationCatAx !== ORIENTATION_MIN_MAX && this.depthPerspective !== undefined)
	{
		//if(this.chartSpace.chart.plotArea.valAx && this.chartSpace.chart.plotArea.valAx.yPoints && this.chartSpace.chart.plotArea.catAx.posY === this.chartSpace.chart.plotArea.valAx.yPoints[0].pos)
			result = this.depthPerspective;
	}
	
	return result;
};

Processor3D.prototype.calculateZPositionCatAxis = function()
{
	var result = 0;
	if(!this.view3D.getRAngAx())
	{
		result = Math.cos(this.angleOy) > 0 ? 0 : this.depthPerspective;
	}
	else if(this.chartsDrawer.calcProp.type !== AscFormat.c_oChartTypes.HBar && this.orientationValAx !== ORIENTATION_MIN_MAX && this.depthPerspective !== undefined)
	{
		if(this.chartSpace.chart.plotArea.valAx && this.chartSpace.chart.plotArea.valAx.yPoints && this.chartSpace.chart.plotArea.catAx.posY === this.chartSpace.chart.plotArea.valAx.yPoints[0].pos)
			result = this.depthPerspective;
	}
	else if(this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar && this.orientationValAx !== ORIENTATION_MIN_MAX && this.depthPerspective !== undefined)
	{
		result = this.depthPerspective;
	}
	
	return result;
};

Processor3D.prototype.calculateFloorPosition = function()
{
	var res, absOy;
	
	if(this.view3D.getRAngAx())
	{
		if(this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar)
		{	
			absOy = Math.abs(this.angleOy);
			res = c_oChartFloorPosition.Left;
			if(absOy > Math.PI)
			{
				res = c_oChartFloorPosition.Right;
			}
		}
		else
		{
			res = c_oChartFloorPosition.Bottom;
			if(this.angleOx > 0)
			{
				res = c_oChartFloorPosition.None;
			}
		}
		
	}
	else
	{
		if(this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar)
		{	
			absOy = Math.abs(this.angleOy);
			res = c_oChartFloorPosition.Left;
			if(absOy > Math.PI)
			{
				res = c_oChartFloorPosition.Right;
			}
		}
		else
		{
			res = c_oChartFloorPosition.Bottom;
			if(this.angleOx > 0)
			{
				res = c_oChartFloorPosition.None;
			}
		}
	}
	
	return res;
};

//***functions for complete transformation point***
Processor3D.prototype.convertAndTurnPoint = function(x, y, z, isNScale, isNRotate, isNProject)
{
	var res = null;
	
	if(this.view3D.getRAngAx())
	{
		res = this.convertAndTurnPointRAngAx(x, y, z);
	}
	else
	{
		res = this.convertAndTurnPointPerspective(x, y, z, isNScale, isNRotate, isNProject);
	}
	
	return res;
};

Processor3D.prototype.convertAndTurnPointRAngAx = function(x, y, z)
{
	var heightChart = this.heightCanvas - this.top - this.bottom;
	var widthOriginalChart = this.widthCanvas - this.left - this.right;

	var point3D = new Point3D(x, y, z, this);
	this.scale(point3D);
	
	//diff
	var centerXDiff = heightChart / 2 + this.left / 2;
	var centerYDiff = heightChart / 2 + this.top;
	var centerZDiff = this.depthPerspective / 2;
	
	point3D.offset(-centerXDiff, -centerYDiff, -centerZDiff);
	
	//rotate
	var matrixRotateAllAxis = this._shearXY();
	point3D.multiplyPointOnMatrix1(matrixRotateAllAxis);
	
	// diff camera for charts write into rect
	point3D.offset(this.cameraDiffX, this.cameraDiffY, this.cameraDiffZ);
	
	//undiff
	var specialReverseDiff = this.widthCanvas / 2 + (this.left - this.right) / 2;
	point3D.offset(specialReverseDiff, centerYDiff, centerZDiff);
	
	return {x: point3D.x, y: point3D.y, z: z};
};

Processor3D.prototype.convertAndTurnPointPerspective = function(x, y, z, isNScale, isNRotate, isNProject)
{
	var point3D = new Point3D(x, y, z, this);
	
	if(!isNScale)
	{
		this.scale(point3D);
	}
	
	if(!isNRotate)
	{
		this.rotatePerspective(point3D);
	}
	
	if(!isNProject)
	{
		this.projectPerspective(point3D);
	}
	
	return {x: point3D.x, y: point3D.y, z: point3D.z};
};

Processor3D.prototype.scale = function(point3D)
{
	//aspectRatio
	point3D.x = point3D.x / this.aspectRatioX;
	point3D.y = point3D.y / this.aspectRatioY;

	point3D.x = point3D.x / this.scaleX;
	point3D.y = point3D.y / this.scaleY;
	point3D.z = point3D.z / this.scaleZ;
};


Processor3D.prototype.rotatePerspective = function(point3D)
{
	//diff
	point3D.offset((-this.widthCanvas / 2) / this.aspectRatioX, (-this.heightCanvas / 2) / this.aspectRatioY, 0);
	//rotate
	var matrixRotateAllAxis = this._getMatrixRotateAllAxis();	
	point3D.multiplyPointOnMatrix1(matrixRotateAllAxis);
	
	point3D.offset((this.widthCanvas / 2) / this.aspectRatioX, (this.heightCanvas / 2) / this.aspectRatioY, 0);
};


Processor3D.prototype.projectPerspective = function(point3D)
{
	//diff
	point3D.offset((-this.widthCanvas / 2) / this.aspectRatioX, (-this.heightCanvas / 2) / this.aspectRatioY /** aspectRatio*/, 0);
	
	// diff camera for charts write into rect
	point3D.offset(this.cameraDiffX, this.cameraDiffY, this.cameraDiffZ);
	
	//project
	var projectiveMatrix = this._getPerspectiveProjectionMatrix(1 / (this.rPerspective));
	point3D.project(projectiveMatrix);
	
	//undiff
	var specialReverseDiffX = this.widthCanvas / 2 + (this.left - this.right) / 2;
	var specialReverseDiffY = this.heightCanvas / 2 + (this.top - this.bottom) / 2; 
	point3D.offset(specialReverseDiffX, specialReverseDiffY, 0);
};

//functions for step transformation point
Processor3D.prototype.calculatePointManual = function(x, y, z, diffX, diffY, diffZ)
{
	diffX = diffX !== undefined ? diffX : this.cameraDiffX;
	diffY = diffY !== undefined ? diffY : this.cameraDiffY;
	diffZ = diffZ !== undefined ? diffZ : this.cameraDiffZ;
	
	var diffAndScalePoints = this.diffAndScale(x, y, z);
	var x11 = diffAndScalePoints.x;
	var y11 = diffAndScalePoints.y;
	var z11 = diffAndScalePoints.z;
	
	
	var rotatePoints = this.rotate(x11, y11, z11);
	var x111 = rotatePoints.x;
	var y111 = rotatePoints.y;
	var z111 = rotatePoints.z;
	
	var x1111 = x111 + diffX;
	var y1111 = y111 + diffY;
	var z1111 = z111 + diffZ;
	
	
	var projectPoints = this.project(x1111, y1111, z1111);
	var x11111 = projectPoints.x;
	var y11111 = projectPoints.y;
	
	return {x: x11111, y: y11111};	
};

Processor3D.prototype.diffAndScale = function(x, y, z)
{
	var aRX = this.aspectRatioX;
	var aRY = this.aspectRatioY;
	
	var w = this.widthCanvas;
	var h = this.heightCanvas;
	
	var x1 = x / aRX;
	var x11 = x1 - (w / 2) / aRX;
	
	var z1 = z;
	var z11 = z1;
	
	var y1 = y / aRY;
	var y11 = y1 - (h / 2) / aRY;
	
	return {x: x11, y: y11, z: z11};
};

Processor3D.prototype.rotate = function(x11, y11, z11)
{
	var sinOY = Math.sin(-this.angleOy);
	var cosOY = Math.cos(-this.angleOy);
	var sinOX = Math.sin(-this.angleOx);
	var cosOX = Math.cos(-this.angleOx);
	
	var x111 = z11 * sinOY + x11 * cosOY;
	var y111 = x11 * sinOX * sinOY + y11 * cosOX - z11 * sinOX * cosOY;
	var z111 = -x11 * sinOY * cosOX +  y11 * sinOX + z11 * (cosOY * cosOX);
	
	return {x: x111, y: y111, z: z111};
};

Processor3D.prototype.project = function(x1111, y1111, z1111)
{
	var fov = 1 / this.rPerspective;
	
	var w = this.widthCanvas;
	var h = this.heightCanvas;
	
	var x11111 = (fov * x1111) / (z1111 + fov) + w / 2;
	var y11111 = (fov * y1111) / (z1111 + fov) + h / 2;
	
	return {x: x11111, y: y11111};
};

//exception for pie charts
Processor3D.prototype.convertAndTurnPointForPie = function(x, y, z, cameraDiffZ)
{
	var heightChart = this.heightCanvas - this.top - this.bottom;

	//aspectRatio
	/*x = x / this.aspectRatioX;
	y = y / this.aspectRatioY;

	x = x / this.scaleX;
	y = y / this.scaleY;
	z = z / this.scaleZ;*/
	
	var point3D = new Point3D(x, y, z, this);
	
	//diff
	var centerXDiff = heightChart / 2 + this.left / 2;
	var centerYDiff = heightChart / 2 + this.top;
	var centerZDiff = this.depthPerspective / 2;
	
	
	point3D.offset(-centerXDiff, -centerYDiff, -centerZDiff);
	
	//rotate
	var matrixRotateAllAxis;
	if(!this.view3D.getRAngAx())
		matrixRotateAllAxis = this._getMatrixRotateAllAxis();
	else
		matrixRotateAllAxis = this._shearXY();
		
	point3D.multiplyPointOnMatrix1(matrixRotateAllAxis);
	
	// diff camera for charts write into rect
	point3D.offset(this.cameraDiffX, this.cameraDiffY, this.cameraDiffZ);
	
	//project
	var projectionPoint = point3D;
	if(!this.view3D.getRAngAx())
	{
		var projectiveMatrix = this._getPerspectiveProjectionMatrix(1 / (this.rPerspective));
		projectionPoint = point3D.project(projectiveMatrix);
	}
	
	//undiff
	var specialReverseDiff = this.widthCanvas / 2 + (this.left - this.right) / 2;
	projectionPoint.offset(specialReverseDiff, centerYDiff, centerZDiff);
	
	//console.log(" this.aspectRatioX: " + this.aspectRatioX + " this.aspectRatioY: " + this.aspectRatioY + " this.scaleX: " + this.scaleX + " this.scaleY: " + this.scaleY);
	
	return {x: projectionPoint.x, y: projectionPoint.y};
};

Processor3D.prototype.calculatePropertiesForPieCharts = function()
{
	var sinAngleOx = Math.sin(-this.angleOx);
	var cosAngleOx = Math.cos(-this.angleOx);
	
	var widthCharts = this.widthCanvas - this.left - this.right;
	var heightCharts = this.heightCanvas - this.bottom - this.top;
	var radius1 = widthCharts / 2;
	var radius2 = radius1 * sinAngleOx;
	var depth = ((widthCharts + 4.89) / 8.37) * cosAngleOx;
	
	if((radius2 * 2 + depth ) > heightCharts)
	{
		var kF = (radius2 * 2 + depth ) / heightCharts;
		radius1 = radius1 / kF;
		radius2 = radius2 / kF;
		depth = depth / kF;
	}
	
	//ToDo временная правка для круговой диграммы с углом поворота 0 градусов
	if(0 === radius2)
	{
		radius2 = 1;
	}
	
	return {radius1: radius1, radius2: radius2, depth: depth};
};



//***functions for matrix transformation***
Processor3D.prototype._shearXY = function()
{
	if(null === this.matrixShearXY)
	{
		this.matrixShearXY = new Matrix4D();
		
		this.matrixShearXY.a31 =  Math.sin(-this.angleOy);
		this.matrixShearXY.a32 =  Math.sin(this.angleOx);
		this.matrixShearXY.a33 =  0;
		this.matrixShearXY.a44 =  0;
	}
	
	return this.matrixShearXY;
};
Processor3D.prototype._shearXY2 = function()
{
	if(null === this.matrixShearXY)
	{
		this.matrixShearXY = [[1, 0, 0, 0], [0, 1, 0, 0], [Math.sin(-this.angleOy), Math.sin(this.angleOx), 0, 0], [0, 0, 0, 0]];
	}
	return this.matrixShearXY;
};

Processor3D.prototype._getMatrixRotateAllAxis = function()
{
	var matrixRotateOY = this._getMatrixRotateOy();
	var matrixRotateOX = this._getMatrixRotateOx();
	
	/*итоговая матрица
	
	|cosOy               0           sinOy      0|
	|sinOx * sinOy     cosOx    -sinOx * cosOy  0|
	|-sinOy * cosOx     sinOx     cosOy * cosOx  0|
	|-sinOy              0        (cosOy + 1)   1|*/
	
	if(null === this.matrixRotateAllAxis)
	{
		this.matrixRotateAllAxis = matrixRotateOY.multiply(matrixRotateOX);
	}
	
	return this.matrixRotateAllAxis;
};

Processor3D.prototype._getMatrixRotateOx = function()
{
	//todo посмотреть возможность заменить массивы на Float32Array
	if(null === this.matrixRotateOx)
	{
		this.matrixRotateOx = new Matrix4D()/*[[1, 0, 0, 0], [0, Math.cos(-this.angleOx), Math.sin(-this.angleOx), 0], [0, - Math.sin(-this.angleOx), Math.cos(-this.angleOx), 1], [0, 0, 0, 1]]*/;
		
		var cos = Math.cos(-this.angleOx);
		var sin = Math.sin(-this.angleOx);
		
		this.matrixRotateOx.a22 =  cos;
		this.matrixRotateOx.a23 =  sin;
		this.matrixRotateOx.a32 = -sin;
		this.matrixRotateOx.a33 = cos;
		this.matrixRotateOx.a34 = 1;
	}
	
	return this.matrixRotateOx;
};

Processor3D.prototype._getMatrixRotateOy = function()
{
	if(null === this.matrixRotateOy)
	{
		this.matrixRotateOy = new Matrix4D()/*[[Math.cos(-this.angleOy), 0, -Math.sin(-this.angleOy), 0], [0, 1, 0, 0], [Math.sin(-this.angleOy), 0, Math.cos(-this.angleOy), 1], [0, 0, 0, 1]]*/;
		
		var cos = Math.cos(-this.angleOy);
		var sin = Math.sin(-this.angleOy);
		
		this.matrixRotateOy.a11 =  cos;
		this.matrixRotateOy.a13 = -sin;
		this.matrixRotateOy.a31 =  sin;
		this.matrixRotateOy.a33 =  cos;
		this.matrixRotateOy.a34 =  1;
	}
	
	return this.matrixRotateOy;
};

Processor3D.prototype._getMatrixRotateOz = function()
{
	return [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 0, 1]];
};

Processor3D.prototype._getPerspectiveProjectionMatrix = function(fov)
{
	/*var zf = this.rPerspective + this.depthPerspective;
	var zn = this.rPerspective;
	var q = zf / (zf - zn);
	return [[1 / Math.tan(this.rPerspective / 2), 0, 0, 0], [0, 1 / Math.tan(this.rPerspective / 2), 0, 0], [0, 0, q, 1], [0, 0, -q * zn, 0]];*/
	//[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1 / fov], [0, 0, 0, 1]]
	if(null === this.projectMatrix)
	{
		this.projectMatrix = new Matrix4D();
		this.projectMatrix.a33 = 0;
		this.projectMatrix.a34 = 1 / fov;
	}
	
	return this.projectMatrix;
};

Processor3D.prototype.correctPointsPosition = function(chartSpace)
{
	if(this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Pie)
		return;
	
	var pxToMM = 1 / AscCommon.g_dKoef_pix_to_mm;
	var t = this;
	//коррективы для подписей	
	var xPoints = chartSpace.chart.plotArea && chartSpace.chart.plotArea.catAx ? chartSpace.chart.plotArea.catAx.xPoints : null;
	if(!xPoints)
		xPoints = chartSpace.chart.plotArea && chartSpace.chart.plotArea.valAx ? chartSpace.chart.plotArea.valAx.xPoints : null;
	
	var coordYAxisOx = chartSpace.chart.plotArea.catAx.posY;
	if(!coordYAxisOx)
		coordYAxisOx = chartSpace.chart.plotArea.valAx.posY != undefined ? chartSpace.chart.plotArea.valAx.posY : chartSpace.chart.plotArea.valAx.posY;
	
	var yPoints = chartSpace.chart.plotArea && chartSpace.chart.plotArea.valAx ? chartSpace.chart.plotArea.valAx.yPoints : null;
	if(!yPoints)
		yPoints = chartSpace.chart.plotArea && chartSpace.chart.plotArea.catAx ? chartSpace.chart.plotArea.catAx.yPoints : null;
	
	var coordXAxisOy = chartSpace.chart.plotArea.catAx.posX ? chartSpace.chart.plotArea.catAx.posX : chartSpace.chart.plotArea.catAx.xPos;
	if(!coordXAxisOy)
		coordXAxisOy = chartSpace.chart.plotArea.valAx.posX != undefined ? chartSpace.chart.plotArea.valAx.posX : null;
	
	var correctPointsOx = function()
	{
		var z = t.calculateZPositionCatAxis();
		var valCatAx = chartSpace.chart.plotArea.catAx;
		if(!valCatAx.transformXPoints)
			valCatAx.transformXPoints = [];
		
		for(var i = 0; i < xPoints.length; i++)
		{
			var widthText = 0;
			if(valCatAx && valCatAx.labels && t.orientationValAx !== ORIENTATION_MIN_MAX)
				widthText = valCatAx.labels.extY * pxToMM;
			
			var point = t.convertAndTurnPoint(xPoints[i].pos * pxToMM, coordYAxisOx * pxToMM - widthText, z);
				
			valCatAx.transformXPoints[i] = {x: point.x / pxToMM, y: point.y / pxToMM};
		}
	};
	
	var correctPointsOxHBar = function()
	{
		var z = t.calculateZPositionValAxis();
		var valCatAx = chartSpace.chart.plotArea.valAx;
		if(!valCatAx.transformXPoints)
			valCatAx.transformXPoints = [];
		
		for(var i = 0; i < xPoints.length; i++)
		{
			var widthText = 0;
			if(t.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar && valCatAx && valCatAx.labels && t.orientationCatAx !== ORIENTATION_MIN_MAX)
				widthText = valCatAx.labels.extY * pxToMM;
			
			var point = t.convertAndTurnPoint(xPoints[i].pos * pxToMM, coordYAxisOx * pxToMM - widthText, z);
				
			valCatAx.transformXPoints[i] = {x: point.x / pxToMM, y: point.y / pxToMM};
		}
	};
	
	var correctPointsOy = function()
	{
		var zPosition = t.calculateZPositionValAxis();
		var valCatAx = chartSpace.chart.plotArea.valAx;
		
		if(!valCatAx.transformYPoints)
			valCatAx.transformYPoints = [];
		
		for(var i = 0; i < yPoints.length; i++)
		{
			var point = t.convertAndTurnPoint(coordXAxisOy * pxToMM , yPoints[i].pos * (pxToMM), zPosition);
			
			//TODO значения высчитать
			var widthText = 5;
			if(valCatAx && valCatAx.labels)
				widthText = valCatAx.labels.extX * pxToMM;
			
			if(t.orientationCatAx !== ORIENTATION_MIN_MAX)
			{
				widthText = 0;
			}
			
			var diffXText = 0;
			var angleOyAbs = Math.abs(t.angleOy);
			if(!t.view3D.getRAngAx() && (angleOyAbs >= Math.PI / 2 && angleOyAbs < 3 * Math.PI/2))
				diffXText = - diffXText;	
			
			valCatAx.transformYPoints[i] = {x: (point.x - (diffXText + widthText)) / pxToMM, y: point.y / pxToMM};
		}
	};
	
	var correctPointsOyHBar = function()
	{
		var zPosition = t.calculateZPositionCatAxis();
		var valCatAx = chartSpace.chart.plotArea.catAx;
		if(!valCatAx.transformYPoints)
			valCatAx.transformYPoints = [];
		
		for(var i = 0; i < yPoints.length; i++)
		{
			var point = t.convertAndTurnPoint(coordXAxisOy * pxToMM , yPoints[i].pos * (pxToMM), zPosition);
			
			//TODO значения высчитать
			var widthText = 0;
			if(valCatAx && valCatAx.labels)
				widthText = valCatAx.labels.extX * pxToMM;
			
			if(t.orientationValAx !== ORIENTATION_MIN_MAX)
			{
				widthText -= 10;
			}
			else
			{
				widthText += 5;
			}
			
			valCatAx.transformYPoints[i] = {x: (point.x - widthText) / pxToMM, y: point.y / pxToMM};
		}
	};
	
	
	if(xPoints)
	{	
		if(this.chartsDrawer.calcProp.type !== AscFormat.c_oChartTypes.HBar)
			correctPointsOx(xPoints);
		else
			correctPointsOxHBar(xPoints);
	}
	
	if(yPoints)
	{
		if(this.chartsDrawer.calcProp.type !== AscFormat.c_oChartTypes.HBar)
			correctPointsOy(yPoints);
		else
			correctPointsOyHBar(yPoints);
	}
};

Processor3D.prototype._calculatePerspective = function(view3D)
{
	var heightLine = this.heightCanvas - (this.top + this.bottom);
	
	var perspective = view3D && view3D.perspective ? view3D.perspective : global3DPersperctive;
	if(view3D && 0 === view3D.perspective && this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Surface)
	{
		perspective = 1;
	}
	
	var alpha = perspective / 4;//в xml проиходит двойной угол(в параметрах ms стоит 40, приходит в xml 80)
	//TODO this.top - this.bottom пересмотреть
	var catt = ((heightLine / 2 + (Math.abs(this.top - this.bottom)))) / Math.tan((alpha / 360) * (Math.PI * 2));
	var rPerspective;
	if(catt === 0)
		rPerspective = 0;
	else
		rPerspective = 1 / catt;
	
	this.rPerspective = rPerspective;
};

Processor3D.prototype._calculateDepth = function()
{
	var widthOriginalChart = this.widthCanvas - (this.left + this.right);
	var heightOriginalChart = this.heightCanvas - (this.top + this.bottom);
	var subType = this.chartsDrawer.calcProp.subType;
	var type = this.chartsDrawer.calcProp.type;
	var defaultOverlap = (subType == "stacked" || subType == "stackedPer" || subType == "standard" || type == AscFormat.c_oChartTypes.Line || type == AscFormat.c_oChartTypes.Area || type == AscFormat.c_oChartTypes.Surface) ? 100 : 0;
	var overlap       = AscFormat.isRealNumber(this.chartSpace.chart.plotArea.chart.overlap) ? (this.chartSpace.chart.plotArea.chart.overlap / 100) : (defaultOverlap / 100);
	var gapWidth = this.chartSpace.chart.plotArea.chart.gapWidth != null ? (this.chartSpace.chart.plotArea.chart.gapWidth / 100) : (150 / 100);
	var gapDepth = this.chartSpace.chart.plotArea.chart.gapDepth != null ? (this.chartSpace.chart.plotArea.chart.gapDepth / 100) : type === AscFormat.c_oChartTypes.Area && subType !== "normal" ? 1 : (150 / 100);
	var basePercent = this.view3D && this.view3D.depthPercent ? this.view3D.depthPercent / 100 : globalBasePercent / 100;//процент от базовой глубины
	var seriesCount = this.chartsDrawer.calcProp.seriesCount;
	var ptCount = this.chartsDrawer.calcProp.ptCount;
	var sinOx = Math.abs(Math.sin(-this.angleOx));
	var sinOy = Math.sin(-this.angleOy);
	var hPercent = type == AscFormat.c_oChartTypes.HBar ? 1 : this.hPercent;
	var depthPercent = this.view3D.depthPercent !== null ? this.view3D.depthPercent / 100 : 1;
	var t = this;
	
	var areaStackedKf = (type === AscFormat.c_oChartTypes.Area && subType !== "normal") || type === AscFormat.c_oChartTypes.Surface ?  (ptCount / (2 * (ptCount - 1))) : 1;
	
	var depth = 0;
	var chartWidth = 0;
	
	var standardType = false;
	if(subType == "standard" || type == AscFormat.c_oChartTypes.Line || (type == AscFormat.c_oChartTypes.Area && subType == "normal") || (type === AscFormat.c_oChartTypes.Surface))
		standardType = true;
	
	var heightHPercent = heightOriginalChart / hPercent;
    var angleOxKf;
	if(!standardType)
	{
        var widthOneBar = ((heightHPercent / seriesCount) / (ptCount - (ptCount - 1) * (overlap) + gapWidth)) * sinOy;
        var a, b;

		if(this.angleOx === 0 && this.angleOy === 0)//withoutAngleNoAuto + withoutAngleAuto
		{
			chartWidth = widthOneBar + heightHPercent;
		}
		else if(this.angleOx !== 0)//AngleOYNoAut + AngleOYNoAutPerHeight + (ANGLEOX+ANGLEOY) + AngleOYOXNoAut + ANGLEOXANGLEOYHPerDPer(ANGLEOX+ANGLEOY HPercent)
		{
			//если выставить ширину 255 будет так же, как и в документе с расчётами
			b = (seriesCount - (seriesCount - 1) * overlap + gapWidth);
			a = (depthPercent / (ptCount * b)) / hPercent;
			var width = heightOriginalChart * areaStackedKf;
			depth = (width * a +  gapDepth * width * a) / (1 / sinOx + (gapDepth) * a + a);
			
			chartWidth = heightHPercent - depth;
		}
		else if(this.angleOy !== 0)//angleOxNoAuto
		{
			//если выставить ширину = 321.25 будет так же, как и в документе с расчётам
			//TODO глубина с некоторыми графиками имеет различия, пересчитать!
			var widthChart = (widthOriginalChart / t.aspectRatioX) / t.specialStandardScaleX;

			b = (seriesCount - (seriesCount - 1) * overlap + gapWidth);
			if(subType == "standard" || type == AscFormat.c_oChartTypes.Line || type == AscFormat.c_oChartTypes.Area || type === AscFormat.c_oChartTypes.Surface)
				b = b / seriesCount;
			
			angleOxKf = sinOx === 0 ? 1 : sinOx;
			a = basePercent / (t.chartsDrawer.calcProp.ptCount * b);
			depth = (widthChart * a +  gapDepth * widthChart * a) / (1 / angleOxKf + (gapDepth) * a + a);
			
			depth = depth / angleOxKf;
		}
	}
	else//allStandardDepth
	{
		angleOxKf = sinOx === 0 ? 0 : sinOx;
		
		if(type == AscFormat.c_oChartTypes.Area)
			depth = (depthPercent / (angleOxKf*depthPercent + ((ptCount + (Math.floor((seriesCount - ptCount) / 2 - 0.5))) / seriesCount * hPercent))) * (heightOriginalChart);
		else
			depth = (depthPercent / (angleOxKf*depthPercent + ((ptCount + (Math.floor((seriesCount - ptCount) / 2))) / seriesCount * hPercent))) * (heightOriginalChart);
		
		if((this.angleOx !== 0))
			depth = depth * Math.sin(-this.angleOx);
	}
	
	return sinOx !== 0 ? Math.abs(depth / sinOx) : Math.abs(depth);
};

Processor3D.prototype._calculateDepthPerspective = function()
{
	var widthCanvas = this.widthCanvas;
	var widthOriginalChart = widthCanvas - (this.left + this.right);
	
	var aspectRatio = this.aspectRatioX / (this.specialStandardScaleX);
	var widthChart = widthOriginalChart / aspectRatio;
	widthChart = widthChart / this.scaleX;

	var seriesCount = this.chartsDrawer.calcProp.seriesCount;
	
	var width = widthChart / this.chartsDrawer.calcProp.ptCount;
	
	var isNormalArea = (this.chartsDrawer.calcProp.subType == "normal" && this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Area) || this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Surface;
	
	var defaultOverlap = (this.chartsDrawer.calcProp.subType == "stacked" || this.chartsDrawer.calcProp.subType == "stackedPer" || this.chartsDrawer.calcProp.subType == "standard" || this.chartsDrawer.calcProp.type == AscFormat.c_oChartTypes.Line || isNormalArea) ? 100 : 0;
	var overlap       = AscFormat.isRealNumber(this.chartSpace.chart.plotArea.chart.overlap) ? (this.chartSpace.chart.plotArea.chart.overlap / 100) : (defaultOverlap / 100);
	
	var gapWidth = this.chartSpace.chart.plotArea.chart.gapWidth != null ? (this.chartSpace.chart.plotArea.chart.gapWidth / 100) : (150 / 100);
	var gapDepth = this.chartSpace.chart.plotArea.chart.gapDepth != null ? (this.chartSpace.chart.plotArea.chart.gapDepth / 100) : (150 / 100);
	
	if(AscFormat.c_oChartTypes.Area === this.chartsDrawer.calcProp.type || AscFormat.c_oChartTypes.Surface === this.chartsDrawer.calcProp.type)
	{
		gapWidth = 0;
		gapDepth = 0;
	}
	
	var baseDepth = width / (seriesCount - (seriesCount - 1) * overlap + gapWidth);
	if(this.chartsDrawer.calcProp.subType == "standard" || this.chartsDrawer.calcProp.type == AscFormat.c_oChartTypes.Line || isNormalArea)
		baseDepth = (width / (seriesCount - (seriesCount - 1) * overlap + gapWidth)) * seriesCount;
		
	//РїСЂРѕС†РµРЅС‚ РѕС‚ Р±Р°Р·РѕРІРѕР№ РіР»СѓР±РёРЅС‹
	var basePercent = this.view3D && this.view3D.depthPercent ? this.view3D.depthPercent / 100 : globalBasePercent / 100;
	var depth = baseDepth * basePercent;
	depth = depth + depth * gapDepth;
	
	if(this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar && this.hPercent !== null)
	{
		depth = this.hPercent * depth;
	}
	
	//TODO глубина в некоторых случаях отличается(тип Standard)
	if(this.chartsDrawer.calcProp.subType === "standard" || this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Line || isNormalArea)
	{
		var b = 1 / seriesCount;
		
		var sinOx = Math.sin(-this.angleOx);
		var angleOxKf = 1;
		var a = basePercent / (this.chartsDrawer.calcProp.ptCount * b);
		depth = (widthChart * a + widthChart * a) / (1 / angleOxKf + a);
		
		depth = depth / angleOxKf;
	}
	
	return depth;
};

Processor3D.prototype._calcSpecialStandardScaleX = function()
{
	if(!(this.chartsDrawer.calcProp.subType == "standard" || this.chartsDrawer.calcProp.type == AscFormat.c_oChartTypes.Line || (this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Area && this.chartsDrawer.calcProp.subType == "normal") || this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Surface))
		return;
	
	//calculate width in 3d standard charts with rAngAx
	var n = Math.floor((this.chartsDrawer.calcProp.seriesCount + this.chartsDrawer.calcProp.ptCount) / 2);
	var kf = this.chartsDrawer.calcProp.ptCount / n;
	
	this.specialStandardScaleX = 1 / kf;
};

Processor3D.prototype._calculateScaleFromDepth = function (/*isSkip*/)
{
	//***Calculate scaleY***
	if(this.view3D.getRAngAx() && this.aspectRatioY === 1)
	{
		var heightCanvas = this.heightCanvas;
		var heightChart = heightCanvas - this.top - this.bottom;
		
		this.scaleY = heightChart / (-this.depthPerspective * Math.sin(Math.abs(this.angleOx)) + heightChart);
		//меняется ширина в зависимости от количества значений
		//if(this.chartsDrawer.calcProp.subType == "standard")
			//this.scaleX += parseInt((this.chartsDrawer.calcProp.seriesCount  + 1) / 2) - 1;
		
		var subType = this.chartsDrawer.calcProp.subType;
        var newDepth, newWidth;
		if(!(subType == "standard" || this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Line || this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Surface || (this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Area && subType == "normal")))
		{
            newDepth = this.depthPerspective * Math.sin(-this.angleOx);
            newWidth = heightChart - newDepth;
			this.scaleX =  heightChart / newWidth;
		}
	}
};

Processor3D.prototype._calculateCameraDiff = function (/*isSkip*/)
{	
	//глубина по OZ
	var perspectiveDepth = this.depthPerspective;
	
	var widthCanvas = this.widthCanvas;
	var originalWidthChart = widthCanvas - this.left - this.right;
	
	var heightCanvas = this.heightCanvas;
	var heightChart = heightCanvas - this.top - this.bottom;
	
	//add test points for parallelepiped rect
	var points = [];
	var faces = [];
	
	/*if(AscFormat.c_oChartTypes.Pie === this.chartsDrawer.calcProp.type)
	{
		points.push(new Point3D(this.left + originalWidthChart / 2, this.top, perspectiveDepth, this));
		points.push(new Point3D(this.left, this.top, perspectiveDepth / 2, this));
		points.push(new Point3D(this.left + originalWidthChart, this.top, perspectiveDepth / 2, this));
		points.push(new Point3D(this.left + originalWidthChart / 2, this.top, 0, this));
		
		points.push(new Point3D(this.left + originalWidthChart / 2, this.top + heightChart, perspectiveDepth, this));
		points.push(new Point3D(this.left, this.top + heightChart, perspectiveDepth / 2, this));
		points.push(new Point3D(this.left + originalWidthChart, this.top + heightChart, perspectiveDepth / 2, this));
		points.push(new Point3D(this.left + originalWidthChart / 2, this.top + heightChart, 0, this));
	}
	else
	{*/
		points.push(new Point3D(this.left, this.top, perspectiveDepth, this));
		points.push(new Point3D(this.left, heightChart + this.top, perspectiveDepth, this));
		points.push(new Point3D(originalWidthChart + this.left, heightChart + this.top, perspectiveDepth, this));
		points.push(new Point3D(originalWidthChart + this.left, this.top, perspectiveDepth, this));
		points.push(new Point3D(originalWidthChart + this.left, this.top, 0, this));
		points.push(new Point3D(originalWidthChart + this.left, heightChart + this.top, 0, this));
		points.push(new Point3D(this.left, heightChart + this.top, 0, this));
		points.push(new Point3D(this.left, this.top, 0, this));
	//}
	
	faces.push([0,1,2,3]);
	faces.push([2,5,4,3]);
	faces.push([1,6,7,0]);
	faces.push([6,5,4,7]);
	faces.push([7,4,3,0]);
	faces.push([1,6,2,5]);
	
	
	//***Calculate cameraDiffZ***
	if(!this.view3D.getRAngAx())
	{
		//быстрая функция поиска сдвигов камеры
		//console.time("sdf");
		this._calculateCameraDiffZX(points, faces);
		//console.timeEnd("sdf");
	}
	
	//***Calculate cameraDiffX***
	if(this.view3D.getRAngAx())
	{
		var minMaxOx = this._getMinMaxOx(points, faces);
		this._calculateCameraDiffX(minMaxOx);
	
		//***Calculate cameraDiffY***
		var minMaxOy = this._getMinMaxOy(points, faces);
		this._calculateCameraDiffY(minMaxOy.top, minMaxOy.bottom);
	}
};

Processor3D.prototype._calculateCameraDiffZX = function (newPoints)
{
	var heightChart = this.heightCanvas - this.top - this.bottom;
	var widthOriginalChart = this.widthCanvas - this.left - this.right;
	var heightOriginalChart = heightChart;
	
	var minX = null;
	var maxX = null;
	var minZ = null;

	var aspectRatio = (widthOriginalChart) / (heightOriginalChart);
	

	for(var i = 0; i < newPoints.length; i++)
	{
		var point3D = new Point3D(newPoints[i].x, newPoints[i].y, newPoints[i].z, this);
		
		point3D.scale(aspectRatio, 1, 1);
		point3D.offset((-this.widthCanvas / 2) / aspectRatio, (-this.heightCanvas / 2) , 0);
		
		//rotate
		var matrixRotateAllAxis = this._getMatrixRotateAllAxis();
		point3D.multiplyPointOnMatrix1(matrixRotateAllAxis);
		
		
		
		if(minZ === null || point3D.z < minZ)
			minZ = point3D.z;
			
		if(minX === null || point3D.x < minX)
			minX = point3D.x;
			
		if(maxX === null || point3D.x > maxX)
			maxX = point3D.x;
	}
	
	//get min and max point's and diffX
	/*if(-t.angleOx === 0)
	{
		var minMaxOx = this._getMinMaxOxPoints(newPoints, minZ);
		this.cameraDiffZ = - minZ;
		this.cameraDiffX = - minMaxOx.diffX;
		
		var x111 = this.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
		var x222 = this.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
		
		if(Math.abs(x222.x - x111.x) > widthOriginalChart)
		{
			var correctOffset;
			if(x222.x > x111.x)
			{
				correctOffset = this._correctZPosition4(minMaxOx.tempX1, minMaxOx.tempX2, minMaxOx.tempZ1, minMaxOx.tempZ2, minZ, minMaxOx.tempY1, minMaxOx.tempY2);
			}
			else
			{
				correctOffset = this._correctZPosition4(minMaxOx.tempX1, minMaxOx.tempX2, minMaxOx.tempZ1, minMaxOx.tempZ2, minZ, minMaxOx.tempY1, minMaxOx.tempY2);
			}
			
			this.cameraDiffZ = Math.abs(correctOffset.minZ);
			this.cameraDiffX = correctOffset.diffX;
		}
	}
	else if(-t.angleOy === 0 && -t.angleOx !== 0)
	{
		var minMaxOy = this._getMinMaxOyPoints(newPoints, minZ);
		this.cameraDiffZ = - minZ;
		this.cameraDiffY = -minMaxOy.diffY;
		
		var y111 = this.convertAndTurnPoint(minMaxOy.tempX1, minMaxOy.tempY1, minMaxOy.tempZ1);
		var y222 = this.convertAndTurnPoint(minMaxOy.tempX2, minMaxOy.tempY2, minMaxOy.tempZ2);
		
		if(Math.abs(y111.y - y222.y) < heightOriginalChart)
		{
			var minMaxOx = this._getMinMaxOxPoints(newPoints, minZ);
			var x111 = this.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
			var x222 = this.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
			
			var correctOffset;
			if(x222.x > x111.x)
			{
				correctOffset = this._correctZPosition4(minMaxOx.tempX1, minMaxOx.tempX2, minMaxOx.tempZ1, minMaxOx.tempZ2, minZ, minMaxOx.tempY1, minMaxOx.tempY2);
			}
			else
			{
				correctOffset = this._correctZPosition4(minMaxOx.tempX1, minMaxOx.tempX2, minMaxOx.tempZ1, minMaxOx.tempZ2, minZ, minMaxOx.tempY1, minMaxOx.tempY2);
			}
			
			this.cameraDiffZ = Math.abs(correctOffset.minZ);
			this.cameraDiffX = correctOffset.diffX;
			
			
			var minMaxOy = this._getMinMaxOyPoints(newPoints, 0);
			//this.cameraDiffZ = - minZ;
			this.cameraDiffY = -minMaxOy.diffY;
		}
	}*/
	/*else if(-t.angleOy !== 0 && -t.angleOx !== 0)
	{
		var minMaxOx = this._getMinMaxOxPoints(newPoints, minZ);
		var x111 = this.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
		var x222 = this.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
		
		var correctOffset;
		if(x222.x > x111.x)
		{
			correctOffset = this._correctZPosition4(minMaxOx.tempX1, minMaxOx.tempX2, minMaxOx.tempZ1, minMaxOx.tempZ2, minZ, minMaxOx.tempY1, minMaxOx.tempY2);
		}
		else
		{
			correctOffset = this._correctZPosition4(minMaxOx.tempX2, minMaxOx.tempX1, minMaxOx.tempZ2, minMaxOx.tempZ1, minZ, minMaxOx.tempY2, minMaxOx.tempY1);
		}
		
		this.cameraDiffZ = correctOffset.minZ;
		this.cameraDiffX = correctOffset.diffX;
		
		var minMaxOy = this._getMinMaxOyPoints2(newPoints, this.cameraDiffZ);
		this.cameraDiffY = minMaxOy.diffY;
		
		console.log(" tempX1: " + minMaxOy.tempX1 + " tempX2: " + minMaxOy.tempX2 + " tempY1: " + minMaxOy.tempY1 + " tempY2: " + minMaxOy.tempY2 + " tempZ1: " + minMaxOy.tempZ1 + " tempZ2: " + minMaxOy.tempZ2);
		
		var y111 = this.convertAndTurnPoint(minMaxOy.tempX1, minMaxOy.tempY1, minMaxOy.tempZ1);
		var y222 = this.convertAndTurnPoint(minMaxOy.tempX2, minMaxOy.tempY2, minMaxOy.tempZ2);
		
		if(y111.y < this.top || y222.y > this.top + heightOriginalChart)
		{
			//correctOffset = this._correctZPositionOY(minMaxOy.tempX1, minMaxOy.tempX2, minMaxOy.tempZ1, minMaxOy.tempZ2, minZ, minMaxOy.tempY1, minMaxOy.tempY2);
			this.cameraDiffZ = minMaxOy.diffZ;
			//this.cameraDiffY = minMaxOy.diffY;
			
			var minMaxOx = this._getMinMaxOxPoints(newPoints, -this.cameraDiffZ);
			//correctOffset = this._correctZPosition4(minMaxOx.tempX1, minMaxOx.tempX2, minMaxOx.tempZ1, minMaxOx.tempZ2, -this.cameraDiffZ, minMaxOx.tempY1, minMaxOx.tempY2);
			this.cameraDiffX = -minMaxOx.diffX;
		}
		
		
		
		//TODO пока включаю для поворотов  по OX + по OY checkOutSideArea(медленная функция), затем нужно переделать, используя закомментированный код сверху
		this.cameraDiffZ = -minZ;
		//this.cameraDiffX = -minMaxOx.diffX;
		this.checkOutSideArea(newPoints);
	}*/
	
	//TODO пока включаю для ВСЕГО checkOutSideArea(медленная функция), затем нужно переделать, используя закомментированный код сверху
	this.cameraDiffZ = -minZ;
	this.checkOutSideArea2(newPoints);
	
};

//TODO если будут проблемы при маштабировании, вернуть функцию checkOutSideArea2 вместо checkOutSideArea
Processor3D.prototype.checkOutSideArea2 = function(newPoints)
{
	var i = 0;
	var maxI = 1000;
	var t = this;
	
	var heightChart = this.heightCanvas - this.top - this.bottom;
	var widthChart = this.widthCanvas - this.left - this.right;	
	
	var calculateZ = function(step)
	{
		var minMaxOx = t._getMinMaxOxPoints(newPoints, -t.cameraDiffZ);
		t.cameraDiffX = -minMaxOx.diffX;
		var x111 = t.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
		var x222 = t.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
		
		var diffX = Math.abs(x222.x - x111.x);
		
		var minMaxOy = t._getMinMaxOyPoints(newPoints, t.cameraDiffZ);
		t.cameraDiffY = -minMaxOy.diffY;
		var y111 = t.convertAndTurnPoint(minMaxOy.tempX1, minMaxOy.tempY1, minMaxOy.tempZ1);
		var y222 = t.convertAndTurnPoint(minMaxOy.tempX2, minMaxOy.tempY2, minMaxOy.tempZ2);
		
		var diffY = Math.abs(y222.y - y111.y);
		
		if(diffX < widthChart && diffY < heightChart)//if size less then width or height
		{
			while(diffX < widthChart && diffY < heightChart)
			{
				t.cameraDiffZ -= step;
				i++;
				minMaxOx = t._getMinMaxOxPoints(newPoints, -t.cameraDiffZ);
				t.cameraDiffX = -minMaxOx.diffX;
				
				x111 = t.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
				x222 = t.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
				diffX = Math.abs(x222.x - x111.x);
				
				minMaxOy = t._getMinMaxOyPoints(newPoints, t.cameraDiffZ);
				t.cameraDiffY = -minMaxOy.diffY;
				y111 = t.convertAndTurnPoint(minMaxOy.tempX1, minMaxOy.tempY1, minMaxOy.tempZ1);
				y222 = t.convertAndTurnPoint(minMaxOy.tempX2, minMaxOy.tempY2, minMaxOy.tempZ2);
				diffY = Math.abs(y222.y - y111.y);
				
				if(i > maxI)
					break;
			}
		}
		else if(diffX > widthChart || diffY > heightChart)//if size more then width or height
		{
			while(diffX > widthChart || diffY > heightChart)
			{
				t.cameraDiffZ += step;
				i++;
				minMaxOx = t._getMinMaxOxPoints(newPoints, -t.cameraDiffZ);
				t.cameraDiffX = -minMaxOx.diffX;
				
				x111 = t.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
				x222 = t.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
				diffX = Math.abs(x222.x - x111.x);
				
				minMaxOy = t._getMinMaxOyPoints(newPoints, t.cameraDiffZ);
				t.cameraDiffY = -minMaxOy.diffY;
				y111 = t.convertAndTurnPoint(minMaxOy.tempX1, minMaxOy.tempY1, minMaxOy.tempZ1);
				y222 = t.convertAndTurnPoint(minMaxOy.tempX2, minMaxOy.tempY2, minMaxOy.tempZ2);
				diffY = Math.abs(y222.y - y111.y);
				
				if(i > maxI)
					break;
			}
		}
	};
	
	calculateZ(100);
	calculateZ(10);
	calculateZ(1);
	
};

Processor3D.prototype.checkOutSideArea = function(newPoints)
{
	var t = this;
	
	var heightChart = this.heightCanvas - this.top - this.bottom;
	var widthChart = this.widthCanvas - this.left - this.right;	
	var DELTA = 3;
	var maxCount = 1000;
	var calculateZ = function()
	{
		var minMaxOx = t._getMinMaxOxPoints(newPoints, -t.cameraDiffZ);
		t.cameraDiffX = -minMaxOx.diffX;
		var x111 = t.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
		var x222 = t.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
		
		var diffX = Math.abs(x222.x - x111.x);
		
		var minMaxOy = t._getMinMaxOyPoints(newPoints, t.cameraDiffZ);
		t.cameraDiffY = -minMaxOy.diffY;
		var y111 = t.convertAndTurnPoint(minMaxOy.tempX1, minMaxOy.tempY1, minMaxOy.tempZ1);
		var y222 = t.convertAndTurnPoint(minMaxOy.tempX2, minMaxOy.tempY2, minMaxOy.tempZ2);
		
		var diffY = Math.abs(y222.y - y111.y);

		if(diffX <= widthChart && diffY <= heightChart && ((widthChart - diffX) < DELTA ||  (heightChart - diffY) < DELTA))
		{
			return;
        }

        var count = 0;
        var fStart = t.cameraDiffZ ? t.cameraDiffZ : 1;
        var fLeftDiffZ, fRightDiffZ;
        if(diffX < widthChart && diffY < heightChart)
		{
            fLeftDiffZ = 0;
            fRightDiffZ = t.cameraDiffZ;
		}
		else
		{
            fLeftDiffZ = t.cameraDiffZ;
            while (diffX >= widthChart || diffY >= heightChart)
			{
                count++;
                t.cameraDiffZ += fStart/2;
                minMaxOx = t._getMinMaxOxPoints(newPoints, -t.cameraDiffZ);
                t.cameraDiffX = -minMaxOx.diffX;
                x111 = t.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
                x222 = t.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);
                diffX = Math.abs(x222.x - x111.x);
                minMaxOy = t._getMinMaxOyPoints(newPoints, t.cameraDiffZ);
                t.cameraDiffY = -minMaxOy.diffY;
                y111 = t.convertAndTurnPoint(minMaxOy.tempX1, minMaxOy.tempY1, minMaxOy.tempZ1);
                y222 = t.convertAndTurnPoint(minMaxOy.tempX2, minMaxOy.tempY2, minMaxOy.tempZ2);
                diffY = Math.abs(y222.y - y111.y);
				
				if(count > maxCount)
				{
					return;
				}
            }
            if(diffX <= widthChart && diffY <= heightChart && ((widthChart - diffX) < DELTA ||  (heightChart - diffY) < DELTA))
			{
                return;
            }
            fRightDiffZ = t.cameraDiffZ;
        }
		
		
		while((diffX > widthChart || diffY > heightChart) || (fRightDiffZ - fLeftDiffZ) > DELTA)
		{
            t.cameraDiffZ = fLeftDiffZ + ((fRightDiffZ - fLeftDiffZ)/2);

            count++;
            minMaxOx = t._getMinMaxOxPoints(newPoints, -t.cameraDiffZ);
            t.cameraDiffX = -minMaxOx.diffX;
            var x111 = t.convertAndTurnPoint(minMaxOx.tempX1, minMaxOx.tempY1, minMaxOx.tempZ1);
            var x222 = t.convertAndTurnPoint(minMaxOx.tempX2, minMaxOx.tempY2, minMaxOx.tempZ2);


            var diffX = Math.abs(x222.x - x111.x);

            var minMaxOy = t._getMinMaxOyPoints(newPoints, t.cameraDiffZ);
            t.cameraDiffY = -minMaxOy.diffY;
            var y111 = t.convertAndTurnPoint(minMaxOy.tempX1, minMaxOy.tempY1, minMaxOy.tempZ1);
            var y222 = t.convertAndTurnPoint(minMaxOy.tempX2, minMaxOy.tempY2, minMaxOy.tempZ2);

            var diffY = Math.abs(y222.y - y111.y);
			if(diffX < widthChart && diffY < heightChart)
			{
				if(((widthChart - diffX) < DELTA) || ((heightChart - diffY) < DELTA))
				{
					break;
				}
                fRightDiffZ = t.cameraDiffZ;
			}
			else 
			{
                fLeftDiffZ = t.cameraDiffZ;
			}
			
			if(count > maxCount)
			{
				return;
			}
        }
	};
	
	calculateZ();
	
};

Processor3D.prototype._getMinMaxOxPoints = function(points, minZ)
{
	var fov = 1 / this.rPerspective;
	
	var t = this;
	var aspectRatioX = this.aspectRatioX;
	var aspectRatioY = this.aspectRatioY;

	
	var diffAndRotatePoint = function(point)
	{
		var point3D = new Point3D(point.x, point.y, point.z, t);
		
		point3D.scale(aspectRatioX, aspectRatioY, 1);
		point3D.offset((-t.widthCanvas / 2) / aspectRatioX, (-t.heightCanvas / 2) / aspectRatioY /** aspectRatio*/, 0);
		
		//rotate
		var matrixRotateAllAxis = t._getMatrixRotateAllAxis();
		point3D.multiplyPointOnMatrix1(matrixRotateAllAxis);
		
		return point3D;
	};
	
	var calculateDiffX = function (x1, x2, z1, z2, minZ, y1, y2)
	{
		var diffAndScalePoints1 = t.diffAndScale(x1, y1, z1);
		x1 = diffAndScalePoints1.x;
		y1 = diffAndScalePoints1.y;
		z1 = diffAndScalePoints1.z;
		
		var rotatePoints1 = t.rotate(x1, y1, z1);
		
		var a1 = rotatePoints1.x;
		//var x1S = a1 - diffX;
		var z1S = rotatePoints1.z - minZ;
		//var x1SS = (fov * x1S / (z1S + fov)) + w / 2;
		
		
		var diffAndScalePoints2 = t.diffAndScale(x2, y2, z2);
		x2 = diffAndScalePoints2.x;
		y2 = diffAndScalePoints2.y;
	    z2 = diffAndScalePoints2.z;
		
		var rotatePoints2 = t.rotate(x2, y2, z2);
		
		var a2 = rotatePoints2.x;
		//var x2S = a2 - diffX;
		var z2S = rotatePoints2.z - minZ;
		//var x2SS = (fov * x2S / (z2S + fov)) + w / 2;
		
		return (-a1 * z2S - a1 * fov - a2 * z1S -a2 * fov) / ( -z2S - fov - z1S - fov);
	};
	

    var w = t.widthCanvas;

	var tempArray = this._getArrayAllVergeCube(points);
	
	var x11, x22, y11, y22, z11, z22;
	var tempX1, tempY1, tempZ1, tempX2, tempY2, tempZ2, start, end;
	for(var i = 0; i < tempArray.length - 1; i++)
	{
		start = i;
		end = i + 1;
		x11 = tempArray[start].x -  (t.widthCanvas / 2);
		x22 = tempArray[end].x -  (t.widthCanvas / 2);
		
		y11 = tempArray[start].y -  (t.heightCanvas / 2);
		y22 = tempArray[end].y -  (t.heightCanvas / 2);
		
		z11 = tempArray[start].z;
		z22 = tempArray[end].z;
		
		tempX1 = tempArray[start].x;
		tempY1 = tempArray[start].y;
		tempZ1 = tempArray[start].z;
		
		tempX2 = tempArray[end].x;
		tempY2 = tempArray[end].y;
		tempZ2 = tempArray[end].z;
		
		if(x11 > x22)
		{
			start = i + 1;
			end = i;
			x11 = tempArray[start].x -  (t.widthCanvas / 2);
			x22 = tempArray[end].x -  (t.widthCanvas / 2);
			
			y11 = tempArray[start].y -  (t.heightCanvas / 2);
			y22 = tempArray[end].y -  (t.heightCanvas / 2);
			
			z11 = tempArray[start].z;
			z22 = tempArray[end].z;
			
			tempX1 = tempArray[start].x;
			tempY1 = tempArray[start].y;
			tempZ1 = tempArray[start].z;
			
			tempX2 = tempArray[end].x;
			tempY2 = tempArray[end].y;
			tempZ2 = tempArray[end].z;
		}
		
		
		var diffX = calculateDiffX(tempX1, tempX2, tempZ1, tempZ2, minZ, tempY1, tempY2);
		
		var projectiveMatrix = t._getPerspectiveProjectionMatrix(1 / (t.rPerspective));
		
		var rotatePoint1 = diffAndRotatePoint(tempArray[start]);
		rotatePoint1.offset(-diffX, 0, -minZ);
		rotatePoint1 = rotatePoint1.project(projectiveMatrix);
		var x1 = Math.floor(rotatePoint1.x + t.widthCanvas / 2);
		
		
		var rotatePoint2 = diffAndRotatePoint(tempArray[end]);
		rotatePoint2.offset(-diffX, 0, -minZ);
		rotatePoint2 = rotatePoint2.project(projectiveMatrix);
		var x2 = Math.floor(rotatePoint2.x + t.widthCanvas / 2);
		
		var leftMargin = x1;
		var rightMargin = Math.floor(w - x2);
		if(!((leftMargin >= rightMargin - 1) && (leftMargin <= rightMargin + 1)))
			continue;
		
		var isTrue = true;
		for(var l = 0; l < tempArray.length - 1; l++)
		{
			var rotatePoint = diffAndRotatePoint(tempArray[l]);
			rotatePoint.offset(-diffX, 0, -minZ);
			rotatePoint = rotatePoint.project(projectiveMatrix);
			var tempX11 = Math.floor(rotatePoint.x + t.widthCanvas / 2);
			
		
			if(x1 < x2)
			{
				if(tempX11 < x1 || tempX11 > x2)
				{
					isTrue = false;
					break;
				}	
			}
			else
			{
				if(tempX11 > x1 || tempX11 < x2)
				{
					isTrue = false;
					break;
				}	
			}
		}
		
		if(isTrue)
			break;		
	}
	
	return {diffX: diffX, tempX1: tempX1, tempY1: tempY1, tempZ1: tempZ1, tempX2: tempX2, tempY2: tempY2, tempZ2: tempZ2, x11: x11, z11: z11, x22: x22, z22: z22, y11: y11, y22: y22};
};

Processor3D.prototype._getMinMaxOyPoints = function(points, minZ)
{
	var fov = 1 / this.rPerspective;
	
	var t = this;
	
	var h = t.heightCanvas;
	var w = t.widthCanvas;

	var calculateDiffY = function (x1, x2, y1, y2, z1, z2, minZ)
	{
		//var cos1 = Math.cos(-t.angleOy);
		//var sin1 = Math.sin(-t.angleOy);
		var diffY = 0;
		
		var diffAndScalePoints = t.diffAndScale(x1, y1, z1);
		var x1 = diffAndScalePoints.x;
		var y1 = diffAndScalePoints.y;
		var z1 = diffAndScalePoints.z;
		
	
		var rotatePoints = t.rotate(x1, y1, z1);
		
		var a1 =  rotatePoints.y;
		//var y1S = (a1 - diffY);
		var z1S = rotatePoints.z + minZ;
		
		//var x1SS = (fov * y1S / (z1S + fov)) + h / 2;
		
		
		
		diffAndScalePoints = t.diffAndScale(x2, y2, z2);
		x2 = diffAndScalePoints.x;
		y2 = diffAndScalePoints.y;
		z2 = diffAndScalePoints.z;
		
		rotatePoints = t.rotate(x2, y2, z2);
		
		var a2 =  rotatePoints.y;
		//var y2S = (a2 - diffY);
		var z2S = rotatePoints.z + minZ;
		
		//var x2SS = (fov * y2S / (z2S + fov)) + h / 2;
		
		//var topMargin = (fov * y1S / (z1S + fov)) + h / 2;
		//var bottomMargin = h - ((fov * y2S / (z2S + fov)) + h / 2);
		
		
		//((a1 - diffY) / (z1S + fov)) =  - (((a2 - diffY) / (z2S + fov)))
		
		/*(a1 - diffY) * (z2S + fov) = -(z1S + fov) * (a2 - diffY)
		
		a1 * z2S + a1 * fov - diffY * z2S - diffY * fov = -z1S * a2 + z1S * diffY - fov * a2 + fov * diffY
		
		a1 * z2S + a1 * fov + fov * a2 + z1S * a2= diffY * z2S + diffY * fov + z1S * diffY + fov * diffY*/
		
		diffY =  (a1 * z2S + a1 * fov + fov * a2 + z1S * a2) / (z2S + fov + z1S + fov);
		
		//var diffY = (-a1 * z2S - a1 * fov - a2 * z1S -a2 * fov) / ( -z2S - fov - z1S - fov);
		
		
		return diffY;
		
	};
	
	var tempArray = this._getArrayAllVergeCube(points);

	var tempX1, tempY1, tempZ1, tempX2, tempY2, tempZ2;
	for(var i = 0; i < tempArray.length - 1; i++)
	{
		var start = i;
		var end = i + 1;
		
		tempX1 = tempArray[start].x;
		tempY1 = tempArray[start].y;
		tempZ1 = tempArray[start].z;
		
		tempX2 = tempArray[end].x;
		tempY2 = tempArray[end].y;
		tempZ2 = tempArray[end].z;
		
		if(tempY1 > tempY2)
		{
			start = i + 1;
			end = i;
			
			tempX1 = tempArray[start].x;
			tempY1 = tempArray[start].y;
			tempZ1 = tempArray[start].z;
			
			tempX2 = tempArray[end].x;
			tempY2 = tempArray[end].y;
			tempZ2 = tempArray[end].z;
		}
		
		
		var diffY = calculateDiffY(tempX1, tempX2, tempY1, tempY2, tempZ1, tempZ2, minZ);
		
		var rotatePoint1 = this.calculatePointManual(tempX1, tempY1, tempZ1, this.cameraDiffX, -diffY, minZ);
		var y1 = rotatePoint1.y;
		
		
		var rotatePoint2 = this.calculatePointManual(tempX2, tempY2, tempZ2, this.cameraDiffX, -diffY, minZ);
		var y2 = rotatePoint2.y;
		
		var topMargin = y1;
		var bottomMargin = Math.floor(h - y2);
		if(!((topMargin >= bottomMargin - 1) && (topMargin <= bottomMargin + 1)))
			continue;
		
		var isTrue = true;
		for(var l = 0; l < tempArray.length - 1; l++)
		{
			var rotatePoint = this.calculatePointManual(tempArray[l].x, tempArray[l].y, tempArray[l].z, this.cameraDiffX, -diffY, minZ);
			var tempY11 = rotatePoint.y;
			
			if(y1 < y2)
			{
				if(tempY11 < y1 || tempY11 > y2)
				{
					isTrue = false;
					break;
				}	
			}
			else
			{
				if(tempY11 > y1 || tempY11 < y2)
				{
					isTrue = false;
					break;
				}	
			}
		}
		
		if(isTrue)
			break;		
	}
	
	return {diffY: diffY, tempX1: tempX1, tempY1: tempY1, tempZ1: tempZ1, tempX2: tempX2, tempY2: tempY2, tempZ2: tempZ2};
};

Processor3D.prototype._getArrayAllVergeCube = function(points)
{
	var res = [];
	
	res[0] = points[0];
	res[1] = points[1];
	res[2] = points[2];
	res[3] = points[3];
	res[4] = points[0];
	res[5] = points[4];
	res[6] = points[7];
	res[7] = points[6];
	res[8] = points[5];
	res[9] = points[2];
	res[10] = points[6];
	res[11] = points[1];
	res[12] = points[7];
	res[13] = points[0];
	res[14] = points[5];
	res[15] = points[1];
	res[16] = points[4];
	res[17] = points[3];
	res[18] = points[6];
	res[19] = points[0];
	res[20] = points[2];
	res[21] = points[7];
	res[22] = points[3];
	res[23] = points[5];
	res[24] = points[7];
	res[25] = points[4];
	res[26] = points[2];
	res[27] = points[3];
	res[28] = points[1];
	res[29] = points[4];
	res[30] = points[5];
	res[31] = points[6];
	res[32] = points[4];
	
	
	/*for(var i = 0; i < points.length; i++)
	{
		for(var j = 0; j < points.length; j++)
		{
			res.push(points[i]);
			res.push(points[j]);
			
		}
	}*/
	
	return res;
};

Processor3D.prototype._getMinMaxOyPoints2 = function(points, minZ)
{
	var t = this;
	
	var h = t.heightCanvas;
	
	var tempArray = [];
	tempArray[0] = points[0];//leftNear
	tempArray[1] = points[1];//leftFar
	tempArray[2] = points[2];//rightFar
	tempArray[3] = points[3];//rightNear
	tempArray[4] = points[4];//leftNear
	tempArray[5] = points[5];//leftFar
	tempArray[6] = points[6];//leftFar
	tempArray[7] = points[7];//leftFar
	tempArray[8] = points[4];//leftFar
	tempArray[9] = points[1];//leftFar
	tempArray[10] = points[3];//leftFar
	tempArray[11] = points[0];//leftFar
	tempArray[12] = points[7];//leftFar
	tempArray[13] = points[2];//leftFar
	tempArray[14] = points[0];//leftFar
	tempArray[15] = points[6];//leftFar
	tempArray[16] = points[5];//leftFar
	tempArray[17] = points[0];//leftFar
	tempArray[18] = points[4];//leftFar
	

	var tempX1, tempY1, tempZ1, tempX2, tempY2, tempZ2;
	for(var i = 0; i < tempArray.length - 1; i++)
	{
		var start = i;
		var end = i + 1;
		
		tempX1 = tempArray[start].x;
		tempY1 = tempArray[start].y;
		tempZ1 = tempArray[start].z;
		
		tempX2 = tempArray[end].x;
		tempY2 = tempArray[end].y;
		tempZ2 = tempArray[end].z;
		
		if(tempY1 > tempY2)
		{
			start = i + 1;
			end = i;
			
			tempX1 = tempArray[start].x;
			tempY1 = tempArray[start].y;
			tempZ1 = tempArray[start].z;
			
			tempX2 = tempArray[end].x;
			tempY2 = tempArray[end].y;
			tempZ2 = tempArray[end].z;
		}
		
		
		//var diffY = calculateDiffY(tempX1, tempX2, tempY1, tempY2, tempZ1, tempZ2, minZ);
		
		
		var correctOffset = this._correctZPositionOY(tempX1, tempX2, tempZ1, tempZ2, minZ, tempY1, tempY2);
		var diffZ = correctOffset.minZ;
		var diffY = correctOffset.diffY;
		
		
		var rotatePoint1 = this.calculatePointManual(tempX1, tempY1, tempZ1, this.cameraDiffX, diffY, diffZ);
		var y1 = rotatePoint1.y;
		
		
		var rotatePoint2 = this.calculatePointManual(tempX2, tempY2, tempZ2, this.cameraDiffX, diffY, diffZ);
		var y2 = rotatePoint2.y;
		
		var topMargin = y1;
		var bottomMargin = Math.floor(h - y2);
		if(!((topMargin >= bottomMargin - 1) && (topMargin <= bottomMargin + 1)))
			continue;
		
		var isTrue = true;
		for(var l = 0; l < tempArray.length - 1; l++)
		{
			var rotatePoint = this.calculatePointManual(tempArray[l].x, tempArray[l].y, tempArray[l].z, this.cameraDiffX, diffY, diffZ);
			var tempY11 = rotatePoint.y;
			
			if(y1 < y2)
			{
				if(tempY11 < y1 || tempY11 > y2)
				{
					isTrue = false;
					break;
				}	
			}
			else
			{
				if(tempY11 > y1 || tempY11 < y2)
				{
					isTrue = false;
					break;
				}	
			}
		}
		
		if(isTrue)
			break;		
	}
	
	return {diffY: diffY, tempX1: tempX1, tempY1: tempY1, tempZ1: tempZ1, tempX2: tempX2, tempY2: tempY2, tempZ2: tempZ2, diffZ: diffZ};
};

Processor3D.prototype._correctZPosition4 = function(x1, x2, z1, z2, minZ, y1, y2)
{
	var t = this;

	var getDiffXZ3 = function(x1, x2, z1, z2, y1, y2)
	{
		var w = t.widthCanvas;
		
		var fov = 1 / t.rPerspective;
		
		var diffAndScalePoints = t.diffAndScale(x1, y1, z1);
		var x11 = diffAndScalePoints.x;
		var y11 = diffAndScalePoints.y;
		var z11 = diffAndScalePoints.z;
		
		
		var rotatePoints = t.rotate(x11, y11, z11);
		var x111 = rotatePoints.x;
		var z111 = rotatePoints.z;
		
		
		/*var x1111 = x111 + diffX;
		var y1111 = y111 + diffY;
		var z1111 = z111 + diffZ;
		var x11111 = (fov * x1111) / (z1111 + fov) + w / 2;
		var y11111 = (fov * y1111) / (z1111 + fov) + h / 2;*/
		
		
		//(fov * x1111) / (z1111 + fov) + w / 2 = t.left
		//(fov * (x111 + diffX)) / ((z111 + diffZ) + fov) + w / 2 = t.left
		var wL = t.left - w / 2;
		//fov * (x111 + diffX) = wL * ((z111 + diffZ) + fov)
		//fov * x111 + fov * diffX = wL * z111 + wL * diffZ + wL * fov
		
		
		
		diffAndScalePoints = t.diffAndScale(x2, y2, z2);
		var x22 = diffAndScalePoints.x;
		var y22 = diffAndScalePoints.y;
		var z22 = diffAndScalePoints.z;
		
		
		
		rotatePoints = t.rotate(x22, y22, z22);
		var x222 = rotatePoints.x;
		var z222 = rotatePoints.z;
		
		
		/*var x1111 = x111 + diffX;
		var y1111 = y111 + diffY;
		var z1111 = z111 + diffZ;
		var x11111 = (fov * x1111) / (z1111 + fov) + w / 2;
		var y11111 = (fov * y1111) / (z1111 + fov) + h / 2;*/
		
		
		var wR = w / 2 - t.left;
		//fov * (x222 + diffX) = wR * ((z222 + diffZ) + fov)
		//fov * x222 + fov * diffX = wR * z222 + wR * diffZ + wR * fov
		
		
		//итого
		//fov * x111 + fov * diffX = wL * z111 + wL * diffZ + wL * fov
		//fov * x222 + fov * diffX = wR * z222 + wR * diffZ + wR * fov
		
		
		/*diffX = (wL * z111 + wL * diffZ + wL * fov - fov * x111) / fov;
		
		fov * x222 + wL * z111 + wL * diffZ + wL * fov - fov * x111 = wR * z222 + wR * diffZ + wR * fov
		
		fov * x222 + wL * z111 + wL * fov - fov * x111 - wR * z222 - wR * fov =  wR * diffZ - wL * diffZ*/
		
		
		
		var diffZ = (fov * x222 + wL * z111 + wL * fov - fov * x111 - wR * z222 - wR * fov) / (wR - wL);
		var diffX = (wL * z111 + wL * diffZ + wL * fov - fov * x111) / fov;
		
		
		return {minZ: diffZ, diffX: diffX};
	};
	
	var diffXZ3 = getDiffXZ3(x1, x2, z1, z2, y1, y2);
	
	return {minZ: diffXZ3.minZ, diffX: diffXZ3.diffX};
};


Processor3D.prototype._correctZPositionOY = function(x1, x2, z1, z2, minZ, y1, y2)
{
	var t = this;

	var getDiffXZ3 = function(x1, x2, z1, z2, y1, y2)
	{
		var h = t.heightCanvas;
		
		var fov = 1 / t.rPerspective;
		
		var diffAndScalePoints = t.diffAndScale(x1, y1, z1);
		var x11 = diffAndScalePoints.x;
		var y11 = diffAndScalePoints.y;
		var z11 = diffAndScalePoints.z;
		
		
		var rotatePoints = t.rotate(x11, y11, z11);
		var y111 = rotatePoints.y;
		var z111 = rotatePoints.z;
		
		
		/*var x1111 = x111 + diffX;
		var y1111 = y111 + diffY;
		var z1111 = z111 + diffZ;
		var x11111 = (fov * x1111) / (z1111 + fov) + w / 2;
		var y11111 = (fov * y1111) / (z1111 + fov) + h / 2;*/
		
		
		//(fov * x1111) / (z1111 + fov) + w / 2 = t.left
		//(fov * (x111 + diffX)) / ((z111 + diffZ) + fov) + w / 2 = t.left
		//var wL = t.left - w / 2;
		//fov * (x111 + diffX) = wL * ((z111 + diffZ) + fov)
		//fov * x111 + fov * diffX = wL * z111 + wL * diffZ + wL * fov
		
		
		
		diffAndScalePoints = t.diffAndScale(x2, y2, z2);
		var x22 = diffAndScalePoints.x;
		var y22 = diffAndScalePoints.y;
		var z22 = diffAndScalePoints.z;
		
		
		
		rotatePoints = t.rotate(x22, y22, z22);
		var y222 = rotatePoints.y;
		var z222 = rotatePoints.z;
		
		
		/*var x1111 = x111 + diffX;
		var y1111 = y111 + diffY;
		var z1111 = z111 + diffZ;
		var x11111 = (fov * x1111) / (z1111 + fov) + w / 2;
		var y11111 = (fov * y1111) / (z1111 + fov) + h / 2;*/
		
		
		//(fov * (y111 + diffY)) / ((z111 + diffZ) + fov) + h / 2 = t.top
		//(fov * (y222 + diffY)) / ((z222 + diffZ) + fov) + h / 2 = h - t.bottom
		var wL = t.top - h / 2;
		var wR = h / 2 - t.bottom;
		
		/*(fov * (y111 + diffY)) / ((z111 + diffZ) + fov) = wL
		(fov * (y222 + diffY)) / ((z222 + diffZ) + fov) = wR
		
		
		fov * (y111 + diffY) = wL * ((z111 + diffZ) + fov)
		
		fov * y111 + fov * diffY = wL * z111 + wL * diffZ + wL * fov
		fov * y222 + fov * diffY = wR * z222 + wR * diffZ + wR * fov
		
		diffY = (wR * z222 + wR * diffZ + wR * fov - fov * y222) / fov
		
		fov * y111 + wR * z222 + wR * diffZ + wR * fov - fov * y222 = wL * z111 + wL * diffZ + wL * fov
		
		fov * y111 + wR * z222 + wR * fov - fov * y222  - wL * z111 - wL * fov = wL * diffZ - wR * diffZ*/
		
		var diffZ = (fov * y111 + wR * z222 + wR * fov - fov * y222  - wL * z111 - wL * fov) / (wL - wR);
		var diffY = (wR * z222 + wR * diffZ + wR * fov - fov * y222) / fov;
		
		
		//var diffZ = (fov * x222 + wL * z111 + wL * fov - fov * x111 - wR * z222 - wR * fov) / (wR - wL);
		//var diffX = (wL * z111 + wL * diffZ + wL * fov - fov * x111) / fov;
		
		
		return {minZ: diffZ, diffY: diffY};
	};
	
	var diffXZ3 = getDiffXZ3(x1, x2, z1, z2, y1, y2);
	
	return {minZ: diffXZ3.minZ, diffY: diffXZ3.diffY};
};

Processor3D.prototype._calculateCameraDiffX = function (minMaxOx)
{
	//test ровно по центру, но циклом
	var maxLeftPoint = minMaxOx.left;
	var maxRightPoint = minMaxOx.right;
	
	//так ближе к тому, как смещает excel
	var widthCanvas = this.widthCanvas;
	var originalWidthChart = widthCanvas - this.left - this.right;
	
	var diffLeft = maxLeftPoint - this.left;
	var diffRight  = (this.left + originalWidthChart) - maxRightPoint;
	
	this.cameraDiffX = (((diffRight - diffLeft) / 2) * ( 1 / (this.rPerspective) + this.cameraDiffZ)) / ( 1 / (this.rPerspective));
};

Processor3D.prototype._calculateCameraDiffY = function (maxTopPoint, maxBottomPoint)
{
	var top = this.top;
	var bottom = this.bottom;
	var heightCanvas = this.heightCanvas;
	var heightChart = heightCanvas - top - bottom;
	
	var diffTop = maxTopPoint - top;
	var diffBottom = (heightChart + top) - maxBottomPoint;
	
	//this.cameraDiffY = this.top - minMaxOy.top; - для rAngAx
	this.cameraDiffY = (diffBottom - diffTop) / 2;
};

Processor3D.prototype._getMinMaxOx = function (points, faces)
{
	var mostLeftPointX;
	var mostRightPointX;
	var xRight;
	var xLeft;
	
	for(var i = 0; i < faces.length - 1; i++){
		for(var k = 0; k <= 3; k++){
			
			var point1 = this.convertAndTurnPoint(points[faces[i][k]].x, points[faces[i][k]].y, points[faces[i][k]].z);
			//var point2 = this.convertAndTurnPoint(points[faces[i][k + 1]].x, points[faces[i][k + 1]].y, points[faces[i][k + 1]].z, true);
			var x1 = point1.x;
			//var x2 = point2.x;
			
			if(!xLeft)
			{
				xLeft = x1;
				mostLeftPointX = new Point3D(points[faces[i][k]].x, points[faces[i][k]].y, points[faces[i][k]].z, this.cChartDrawer);
				
				xRight = x1;
				mostRightPointX = new Point3D(points[faces[i][k]].x, points[faces[i][k]].y, points[faces[i][k]].z, this.cChartDrawer);
			}
			else
			{
				if(x1 < xLeft)
				{
					xLeft = x1;
					mostLeftPointX = new Point3D(points[faces[i][k]].x, points[faces[i][k]].y, points[faces[i][k]].z, this.cChartDrawer);
				}
				
				if(x1 > xRight)
				{
					xRight = x1;
					mostRightPointX = new Point3D(points[faces[i][k]].x, points[faces[i][k]].y, points[faces[i][k]].z, this.cChartDrawer);
				}
			}
			
		}
	}
	
	return {left: xLeft, right: xRight, mostLeftPointX: mostLeftPointX, mostRightPointX: mostRightPointX};
};

Processor3D.prototype._getMinMaxOy = function (points, faces)
{
	var mostTopPointY;
	var mostBottomPointY;
	var xTop = this.top + this.heightCanvas;
	var xBottom = 0;
	for(var i = 0; i < faces.length - 1; i++){
		for(var k = 0; k < 3; k++){
			
			var point1 = this.convertAndTurnPoint(points[faces[i][k]].x, points[faces[i][k]].y, points[faces[i][k]].z);
			var point2 = this.convertAndTurnPoint(points[faces[i][k + 1]].x, points[faces[i][k + 1]].y, points[faces[i][k + 1]].z);
			var y1 = point1.y;
			var y2 = point2.y;
		
			
			if(y1 <= xTop)
			{
				xTop = y1;
				mostTopPointY = new Point3D(points[faces[i][k]].x, points[faces[i][k]].y, points[faces[i][k]].z, this.cChartDrawer);
			}	
			
			if(y2 <= xTop)
			{
				xTop = y2;
				mostTopPointY = new Point3D(points[faces[i][k + 1]].x, points[faces[i][k + 1]].y, points[faces[i][k + 1]].z, this.cChartDrawer);
			}
			
			if(y1 >= xBottom)
			{
				xBottom = y1;
				mostBottomPointY = new Point3D(points[faces[i][k]].x, points[faces[i][k]].y, points[faces[i][k]].z, this.cChartDrawer);
			}	
			
			if(y2 >= xBottom)
			{
				xBottom = y2;
				mostBottomPointY = new Point3D(points[faces[i][k + 1]].x, points[faces[i][k + 1]].y, points[faces[i][k + 1]].z, this.cChartDrawer);
			}

		}
	}
	
	return {top: xTop, bottom: xBottom, mostTopPointY: mostTopPointY, mostBottomPointY: mostBottomPointY};
};

Processor3D.prototype._calcAspectRatio = function()
{
	//return width / height
	var widthOriginalChart = this.widthCanvas - (this.left + this.right);
	var heightOriginalChart = this.heightCanvas - (this.top + this.bottom);
	//auto scale if hPercent == null
	var hPercent = this.hPercent;
	var depthPercent = this.view3D.depthPercent !== null ? this.view3D.depthPercent / 100 : 1;
	
	var aspectRatioX = 1;
	var aspectRatioY = 1;
	
	var subType = this.chartsDrawer.calcProp.subType;
	if((subType === "standard"  || this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Line  || (this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Area && subType == "normal") || this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Surface) && !this.view3D.getRAngAx())
	{
		this._calcSpecialStandardScaleX();
		
		aspectRatioX = (widthOriginalChart / (heightOriginalChart / hPercent)) * this.specialStandardScaleX;
	}
	else if(subType === "standard" || this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Line || this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.Surface)
	{
		var seriesCount = this.chartsDrawer.calcProp.seriesCount;
		var ptCount = this.chartsDrawer.calcProp.ptCount;
		
		var depth = this.view3D.getRAngAx() ? this._calculateDepth() : this._calculateDepthPerspective();
		var width = (depth / depthPercent) * (ptCount / seriesCount);
		
		aspectRatioX = (widthOriginalChart) / width;
	}
	else if(hPercent !== null)//auto scale height
		aspectRatioX = widthOriginalChart / (heightOriginalChart / hPercent);
	
	if(aspectRatioX < 1 && this.view3D.getRAngAx())
	{
		aspectRatioY = 1 / aspectRatioX;
		aspectRatioX = 1;
	}
	
	this.aspectRatioX = aspectRatioX;
	this.aspectRatioY = aspectRatioY;
};


function Point3D(x, y, z, chartsDrawer)
{
	this.x = x;
	this.y = y;
	this.z = z;
	this.t = 1;
	
	if(chartsDrawer)
	{
		this.chartProp = chartsDrawer.calcProp;
		this.cChartDrawer = chartsDrawer;
		this.cChartSpace = chartsDrawer.cChartSpace;
	}
}

Point3D.prototype = 
{	
	constructor: Point3D,
	
	rotate: function(angleOx, angleOy, angleOz)
	{
		var x = this.x;
		var y = this.y;
		var z = this.z;
		var cosy  = Math.cos(angleOy);
		var siny  = Math.sin(angleOy);
		var cosx  = Math.cos(angleOx);
		var sinx  = Math.sin(angleOx);
		var cosz  = Math.cos(angleOz);
		var sinz  = Math.sin(angleOz);
		
		
		var newX = cosy * (sinz * y + cosz * x) - siny * z;
		var newY = sinx * (cosy * z + siny * (sinz * y + cosz * x)) + cosx * (cosz * y - sinz * x);
		var newZ = cosx * (cosy * z + siny * (sinz * y + cosz * x)) - sinx * (cosz * y - sinz * x);
		
		this.x = newX;
		this.y = newY;
		this.z = newZ;
		
		return this;
	},
	
	project: function(matrix)
	{
		//умножаем
		var projectPoint = matrix.multiplyPoint(this);
		
		//делим на 4 коэффициэнт
		var newX = projectPoint.x / projectPoint.t;
		var newY = projectPoint.y / projectPoint.t;
		
		this.x = newX;
		this.y = newY;
		
		return this;
	},
	
	offset: function(offsetX, offsetY, offsetZ)
	{
		this.x = this.x + offsetX;
		this.y = this.y + offsetY;
		this.z = this.z + offsetZ;
		
		return this;
	},
	
	scale: function(aspectRatioOx, aspectRatioOy, aspectRatioOz)
	{
		this.x = this.x / aspectRatioOx;
		this.y = this.y / aspectRatioOy;
		this.z = this.z / aspectRatioOz;
		
		return this;
	},
	
	multiplyPointOnMatrix1: function(matrix)
	{
		var multiplyMatrix = matrix.multiplyPoint(this);
		this.x = multiplyMatrix.x;
		this.y = multiplyMatrix.y;
		this.z = multiplyMatrix.z;
	}
};

function Matrix4D() 
{
	this.a11 = 1.0;
	this.a12 = 0.0;
	this.a13 = 0.0;
	this.a14 = 0.0;
	
	this.a21 = 0.0;
	this.a22 = 1.0;
	this.a23 = 0.0;
	this.a24 = 0.0;
	
	this.a31 = 0.0;
	this.a32 = 0.0;
	this.a33 = 1.0;
	this.a34 = 0.0;
	
	this.a41 = 0.0;
	this.a42 = 0.0;
	this.a43 = 0.0;
	this.a44 = 1.0;

	return this;
}
Matrix4D.prototype.reset = function () 
{
	this.a11 = 1.0;
	this.a12 = 0.0;
	this.a13 = 0.0;
	this.a14 = 0.0;
	
	this.a21 = 0.0;
	this.a22 = 1.0;
	this.a23 = 0.0;
	this.a24 = 0.0;
	
	this.a31 = 0.0;
	this.a32 = 0.0;
	this.a33 = 1.0;
	this.a34 = 0.0;
	
	this.a41 = 0.0;
	this.a42 = 0.0;
	this.a43 = 0.0;
	this.a44 = 1.0;
};
Matrix4D.prototype.multiply = function (m) 
{
	var res = new Matrix4D();
	
	res.a11 = this.a11 * m.a11 + this.a12 * m.a21 + this.a13 * m.a31 + this.a14 * m.a41;
	res.a12 = this.a11 * m.a12 + this.a12 * m.a22 + this.a13 * m.a32 + this.a14 * m.a42;
	res.a13 = this.a11 * m.a13 + this.a12 * m.a23 + this.a13 * m.a33 + this.a14 * m.a43;
	res.a14 = this.a11 * m.a14 + this.a12 * m.a24 + this.a13 * m.a34 + this.a14 * m.a44;
	
	res.a21 = this.a21 * m.a11 + this.a22 * m.a21 + this.a23 * m.a31 + this.a24 * m.a41;
	res.a22 = this.a21 * m.a12 + this.a22 * m.a22 + this.a23 * m.a32 + this.a24 * m.a42;
	res.a23 = this.a21 * m.a13 + this.a22 * m.a23 + this.a23 * m.a33 + this.a24 * m.a43;
	res.a24 = this.a21 * m.a14 + this.a22 * m.a24 + this.a23 * m.a34 + this.a24 * m.a44;
	
	res.a31 = this.a31 * m.a11 + this.a32 * m.a21 + this.a33 * m.a31 + this.a34 * m.a41;
	res.a32 = this.a31 * m.a12 + this.a32 * m.a22 + this.a33 * m.a32 + this.a34 * m.a42;
	res.a33 = this.a31 * m.a13 + this.a32 * m.a23 + this.a33 * m.a33 + this.a34 * m.a43;
	res.a34 = this.a31 * m.a14 + this.a32 * m.a24 + this.a33 * m.a34 + this.a34 * m.a44;
	
	res.a41 = this.a41 * m.a11 + this.a42 * m.a21 + this.a43 * m.a31 + this.a44 * m.a41;
	res.a42 = this.a41 * m.a12 + this.a42 * m.a22 + this.a43 * m.a32 + this.a44 * m.a42;
	res.a43 = this.a41 * m.a13 + this.a42 * m.a23 + this.a43 * m.a33 + this.a44 * m.a43;
	res.a44 = this.a41 * m.a14 + this.a42 * m.a24 + this.a43 * m.a34 + this.a44 * m.a44;
	
	return res;
};
Matrix4D.prototype.multiplyPoint = function (p) 
{
	var res = new Point3D();
	
	res.x = p.x * this.a11 + p.y * this.a21 + p.z * this.a31 + this.a41;
	res.y = p.x * this.a12 + p.y * this.a22 + p.z * this.a32 + this.a42;
	res.z = p.x * this.a13 + p.y * this.a23 + p.z * this.a33 + this.a43;
	res.t = p.x * this.a14 + p.y * this.a24 + p.z * this.a34 + this.a44;
	
	return res;
};


//sort parallalepiped faces
function CSortFaces(cChartDrawer, centralViewPoint)
{
	this.cChartDrawer = cChartDrawer;
	this.chartProp = cChartDrawer.calcProp;
	this.centralViewPoint = null;
	this._initProperties(centralViewPoint)
}

CSortFaces.prototype =
{
	constructor: CSortFaces,

	_initProperties: function(centralViewPoint)
	{
		if(!centralViewPoint)
		{
			var top = this.chartProp.chartGutter._top;
			var bottom = this.chartProp.chartGutter._bottom;
			var left = this.chartProp.chartGutter._left;
			var right = this.chartProp.chartGutter._right;

			var widthCanvas = this.chartProp.widthCanvas;
			var heightCanvas = this.chartProp.heightCanvas;
			var heightChart = heightCanvas - top - bottom;
			var widthChart = widthCanvas - left - right;

			var centerChartY = top + heightChart / 2;
			var centerChartX = left + widthChart / 2;

			var diffX = centerChartX;
			var diffY = centerChartY;
			var diffZ = -1 / this.cChartDrawer.processor3D.rPerspective;
			//TODO протестировать на bar и затем сделать для всех перспективных диаграмм данный сдвиг
			if(!this.cChartDrawer.processor3D.view3D.getRAngAx() && this.chartProp.type === AscFormat.c_oChartTypes.Bar)
			{
				diffX -= this.cChartDrawer.processor3D.cameraDiffX;
				diffY -= this.cChartDrawer.processor3D.cameraDiffY;
				diffZ -= this.cChartDrawer.processor3D.cameraDiffZ;
			}

			//TODO пересмотреть правку!
			if(diffZ > 0 && this.chartProp.type === AscFormat.c_oChartTypes.Bar && this.cChartDrawer.processor3D.view3D.getRAngAx() && (this.chartProp.subType === "stackedPer" || this.chartProp.subType == "stacked"))
			{
				diffZ -= 500;
			}

			this.centralViewPoint = {x: diffX, y: diffY, z: diffZ};
		}
		else
		{
			this.centralViewPoint = centralViewPoint;
		}
	},

	sortParallelepipeds: function(parallelepipeds)
	{
		var intersectionsParallelepipeds = this._getIntersectionsParallelepipeds(parallelepipeds);
		var revIntersections = intersectionsParallelepipeds.reverseIntersections;
		var countIntersection = intersectionsParallelepipeds.countIntersection;

		var startIndexes = [];
		for(var i = 0; i < countIntersection.length; i++)
		{
			if(countIntersection[i] === 0)
			{
				startIndexes.push({index: parseInt(i)});
			}
		}

		if(startIndexes.length === 0)
		{
			//TODO сделано для графиков типа stacked, когда пересечения найдены всех параллалеп.
			var minZ = parallelepipeds[0].z;
			var minZArray = [];
			for(var i = 0; i < parallelepipeds.length; i++)
			{
				if(parallelepipeds[i].z < minZ)
				{
					minZ = parallelepipeds[i].z;
					minZArray = [];
				}

				if(minZ === parallelepipeds[i].z)
				{
					minZArray.push({index: parseInt(i)});
				}
			}

			startIndexes = minZArray.reverse();
		}

		var g = revIntersections;
		var color = {}; // цвет вершины (0, 1, или 2)
		var time_in = {}, time_out = {}; // "времена" захода и выхода из вершины
		var dfs_timer = 0;

		var dfs = function(v)
		{
			time_in[v] = dfs_timer++;
			color[v] = 1;

			for (var i in g[v])
			{
				if (!color[i])
				{
					dfs (i);
				}
			}

			color[v] = 2;
			time_out[v] = dfs_timer++;
		};
		var getMax = function()
		{
			var max = 0;
			var res = null;
			for(var i in time_out)
			{
				if(!addIndexes[i] && time_out[i] > max)
				{
					max = time_out[i];
					res = i;
				}
			}
			return res;
		};

		for(var i = 0; i < startIndexes.length; i++)
		{
			dfs(startIndexes[i].index);
		}

		var addIndexes = {};
		var res = [];
		while(true)
		{
			var index = getMax();

			if(null === index)
			{
				break;
			}

			res.push({nextIndex: index});
			addIndexes[index] = 1;
		}

		return res.reverse();
	},

	_getIntersectionsParallelepipeds: function(parallelepipeds)
	{
		//TODO нужно по максимуму оптимизировать, при большом количестве значений работает медленно
		var usuallyIntersect = {};
		var usuallyIntersectRev = {};

		var intersections = [];
		var reverseIntersections = [];
		var countIntersection = [];
		for(var i = 0; i < parallelepipeds.length; i++)
		{
			//из каждой точки данного параллалепипеда строим прямые до точки наблюдателя
			var fromParallalepiped = parallelepipeds[i];
			countIntersection[i] = 0;

			for(var m = 0; m < parallelepipeds.length; m++)
			{
				if(m === i || usuallyIntersect[i] === m || usuallyIntersectRev[i] === m)
				{
					continue;
				}

				for(var l = 0; l < fromParallalepiped.arrPoints.length; l++)
				{
					//перебираем точки параллалепипеда FROM
					var point = fromParallalepiped.arrPoints[l];

					//перебираем грани параллалепипеда TO и проверяем на пересечения с прямыми из параллалепипеда FROM
					var toParallalepiped = parallelepipeds[m];
					for(var n = 0; n < toParallalepiped.faces.length; n++)
					{
						var toVerge = toParallalepiped.faces[n];
						var lineEqucation = this.cChartDrawer.getLineEquation(point, this.centralViewPoint);
						var intersection = this._isIntersectionFaceAndLine(toVerge, lineEqucation, point);
						if(intersection)
						{
							usuallyIntersect[i] = m;
							usuallyIntersectRev[m] = i;

							if(!intersections[i])
							{
								intersections[i] = [];
							}

							if(!reverseIntersections[m])
							{
								reverseIntersections[m] = [];
							}

							countIntersection[i]++;

							intersections[i][m] = 1;
							reverseIntersections[m][i] = 1;

							l = point.length;
							//console.log("fromParallalepiped: " + i + " toParallalepiped " + m + " x: " + intersection.x  + " y: " + intersection.y  + " z: " + intersection.z);

							break;
						}
					}
				}
			}
		}

		return {intersections: intersections, reverseIntersections: reverseIntersections, countIntersection: countIntersection};
	},

	//смотрим есть ли пересечения точек, выходящих из вершин данной грани, с другими гранями
	_isIntersectionFacesPointLines: function(plainVerge, i, sortZIndexPaths)
	{
		var res = false;
		var t = this;

		for(var j = 0; j < plainVerge.points.length; j++)
		{
			var pointFromVerge = plainVerge.points[j];
			var lineEqucation = t.cChartDrawer.getLineEquation(pointFromVerge, this.centralViewPoint);

			//пересечение грани и прямой
			if(t._isIntersectionFacesAndLine(lineEqucation, pointFromVerge, i, j, sortZIndexPaths))
			{
				res = true;
				break;
			}
		}

		return res;
	},

	//пересечение прямой с другими гранями
	_isIntersectionFacesAndLine: function(lineEqucation, pointFromVerge, i, j, sortZIndexPaths)
	{
		var res = false;

		for(var k = 0; k < sortZIndexPaths.length; k++)
		{
			if(k === i)
				continue;

			if(this._isIntersectionFaceAndLine(sortZIndexPaths[k], lineEqucation, pointFromVerge, i, j, k))
			{
				res = true;
				break;
			}
		}

		return res;
	},

	//пересечение прямой гранью
	_isIntersectionFaceAndLine: function(plain, lineEquation, pointFromVerge)
	{
		var res = false;
		var t = this;

		//get intersection
		var nIntersectionPlainAndLine = t.cChartDrawer.isIntersectionPlainAndLine(plain.plainEquation ,lineEquation);

		if(null === nIntersectionPlainAndLine)
		{
			return res;
		}

		var iSX = nIntersectionPlainAndLine.x;
		var iSY = nIntersectionPlainAndLine.y;
		var iSZ = nIntersectionPlainAndLine.z;

		if(Math.round(iSZ * 1000) / 1000 < Math.round(pointFromVerge.z * 1000) / 1000)
		{
			var minMaxpoints = t.cChartDrawer.getMinMaxPoints(plain.points);
			var minX = minMaxpoints.minX, maxX = minMaxpoints.maxX, minY = minMaxpoints.minY, maxY = minMaxpoints.maxY, minZ = minMaxpoints.minZ, maxZ = minMaxpoints.maxZ;

			var isBeetwenX = t._isBetweenPoint(iSX, minX, maxX);
			var isBeetwenY = t._isBetweenPoint(iSY, minY, maxY);
			var isBeetwenZ = t._isBetweenPoint(iSZ, minZ, maxZ);

			if(isBeetwenX && isBeetwenY && isBeetwenZ)
			{
				var point0 = plain.points2[0];
				var point1 = plain.points2[1];
				var point2 = plain.points2[2];
				var point3 = plain.points2[3];

				var projectIntersection = nIntersectionPlainAndLine;
				if(!this.cChartDrawer.processor3D.view3D.getRAngAx())
				{
					projectIntersection = t.cChartDrawer._convertAndTurnPoint(nIntersectionPlainAndLine.x, nIntersectionPlainAndLine.y, nIntersectionPlainAndLine.z, true, true);
				}

				var areaQuadrilateral = plain.plainArea;
				var areaTriangle1 = t.cChartDrawer.getAreaTriangle(point0, projectIntersection, point1);
				var areaTriangle2 = t.cChartDrawer.getAreaTriangle(point1, projectIntersection, point2);
				var areaTriangle3 = t.cChartDrawer.getAreaTriangle(point2, projectIntersection, point3);
				var areaTriangle4 = t.cChartDrawer.getAreaTriangle(point3, projectIntersection, point0);

				if(parseInt(areaQuadrilateral) === parseInt(areaTriangle1 + areaTriangle2 + areaTriangle3 + areaTriangle4))
				{
					//var pointFromVergeProject = t.cChartDrawer._convertAndTurnPoint(pointFromVerge.x, pointFromVerge.y, pointFromVerge.z, true, true);
					//console.log("x: " + projectIntersection.x + " ;y: " + projectIntersection.y + " ;fromX:" + pointFromVergeProject.x + " ;fromY:" + pointFromVergeProject.y);

					res = nIntersectionPlainAndLine;
				}
			}
		}

		return res;
	},

	_isBetweenPoint: function(point, start, end)
	{
		//TODO округление пересмотреть
		var res = false;
		point = Math.round(point * 100) / 100;
		start = Math.round(start * 100) / 100;
		end = Math.round(end * 100) / 100;

		if(point >= start && point <= end)
		{
			res = true;
		}

		return res;
	},

	_isEqualPoints: function(point1, point2)
	{
		//TODO округление пересмотреть
		var res = false;

		if(parseInt(point1.x) === parseInt(point2.x) && parseInt(point1.y) === parseInt(point2.y) && parseInt(point1.y) === parseInt(point2.y))
		{
			res = true;
		}

		return res;
	}
};

	//----------------------------------------------------------export----------------------------------------------------
	window['AscFormat'] = window['AscFormat'] || {};
	window['AscFormat'].Processor3D = Processor3D;
	window['AscFormat'].Point3D = Point3D;
	window['AscFormat'].CSortFaces = CSortFaces;
	window['AscCommon'].c_oChartFloorPosition = c_oChartFloorPosition;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(
/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {

// Import
var cToDeg = AscFormat.cToDeg;
var Path = AscFormat.Path2;
var ORIENTATION_MIN_MAX = AscFormat.ORIENTATION_MIN_MAX;
var Point3D = AscFormat.Point3D;

var c_oAscTickMark = Asc.c_oAscTickMark;
var c_oAscChartDataLabelsPos = Asc.c_oAscChartDataLabelsPos;
var c_oAscChartLegendShowSettings = Asc.c_oAscChartLegendShowSettings;

var c_oChartTypes =
{
	Bar: 0,
	Line: 1,
	HBar: 2,
	Pie: 3,
	Scatter: 4,
	Area: 5,
	Stock: 6,
	DoughnutChart: 7,
	Radar: 8,
	BubbleChart: 9,
	Surface: 10
};

var c_oChartBar3dFaces =
{
	front: 0,
	up: 1,
	left: 2,
	right: 3,
	down: 4,
	back: 5
};


var globalGapDepth = 150;
var isTurnOn3DCharts = true;
var standartMarginForCharts = 13;

function arrReverse(arr) {
	if(!arr || !arr.length)
		return;
	var newarr = [];
	for (var i = 0; i < arr[0].length; ++i) {
		newarr[i] = [];
		for (var j = 0; j < arr.length; ++j) {
			newarr[i][j] = arr[j][i];
		}
	}
	return newarr;
}

//*****MAIN*****
function CChartsDrawer()
{
	this.calcProp = {};

	this.areaChart = null;
	this.chart = null;
	this.cChartSpace = null;
	this.cShapeDrawer = null;
	this.processor3D = null;

	this.areaChart = null;
	this.catAxisChart = null;
	this.valAxisChart = null;
	this.serAxisChart = null;

	this.floor3DChart = null;
	this.sideWall3DChart = null;
	this.backWall3DChart = null;

	this.changeAxisMap = null;
}

CChartsDrawer.prototype =
{
    constructor: CChartsDrawer,

	//****draw and recalculate functions****
	recalculate : function (chartSpace) {
		this.cChartSpace = chartSpace;

		this.calcProp = {};

		//nDimensionCount - flag for 3d/2d charts
		if (this._isSwitchCurrent3DChart(chartSpace)) {
			standartMarginForCharts = 16;
			this.nDimensionCount = 3;
		} else {
			this.nDimensionCount = 2;
		}

		if (!chartSpace.bEmptySeries) {
			this._calculateProperties(chartSpace);
		}

		if (this.calcProp.widthCanvas == undefined && this.calcProp.pxToMM == undefined) {
			this.calcProp.pathH = 1000000000;
			this.calcProp.pathW = 1000000000;
			this.calcProp.pxToMM = 1 / AscCommon.g_dKoef_pix_to_mm;
			this.calcProp.widthCanvas = chartSpace.extX * this.calcProp.pxToMM;
			this.calcProp.heightCanvas = chartSpace.extY * this.calcProp.pxToMM;
		}

		this.init(chartSpace);

		//****recalculate****
		//PLOTAREA
		if (!chartSpace.bEmptySeries) {
			if (this.nDimensionCount === 3) {
				this._calaculate3DProperties(chartSpace);
			}

			this.plotAreaChart.recalculate(this);
		}

		//AREA
		this.areaChart.recalculate(this);

		//AXIS
		if (!chartSpace.bEmptySeries) {

			//оси значений и категорий
			this.valAxisChart = [];
			this.catAxisChart = [];
			this.serAxisChart = [];
			for (var i = 0; i < chartSpace.chart.plotArea.axId.length; i++) {
				var axId = chartSpace.chart.plotArea.axId[i];
				if (axId instanceof AscFormat.CCatAx) {
					var catAx = new catAxisChart();
					catAx.recalculate(this, axId);
					this.catAxisChart.push(catAx);
				} else if (axId instanceof AscFormat.CValAx) {
					var valAx = new valAxisChart();
					valAx.recalculate(this, axId);
					this.valAxisChart.push(valAx);
				} else if (axId instanceof AscFormat.CSerAx) {
					var serAx = new serAxisChart();
					serAx.recalculate(this, axId);
					this.serAxisChart.push(serAx);
				} else if (axId instanceof AscFormat.CDateAx) {
					var catAx = new serAxisChart();
					catAx.recalculate(this, axId);
					this.catAxisChart.push(catAx);
				}
			}

			if (this.nDimensionCount === 3) {
				this.floor3DChart.recalculate(this);
				this.sideWall3DChart.recalculate(this);
				this.backWall3DChart.recalculate(this);
			}

		}

		//CHARTS
		if (!chartSpace.bEmptySeries) {
			for(var i in this.charts) {
				this.charts[i].recalculate();
			}
		}
	},

	init: function(chartSpace) {
		//создаём область
		this.areaChart = new areaChart();
		//создаём область
		this.plotAreaChart = new plotAreaChart();
		//Floor This element specifies the floor of a 3D chart.
		this.floor3DChart = new floor3DChart();
		this.sideWall3DChart = new sideWall3DChart();
		this.backWall3DChart = new backWall3DChart();

		//draw chart
		var newChart;
		for (var i = 0; i < chartSpace.chart.plotArea.charts.length; i++) {
			var chart = chartSpace.chart.plotArea.charts[i];
			switch (this._getChartType(chart)) {
				case c_oChartTypes.Bar: {
					newChart = new drawBarChart(chart, this);
					break;
				}
				case c_oChartTypes.Line: {
					newChart = new drawLineChart(chart, this);
					break;
				}
				case c_oChartTypes.HBar: {
					newChart = new drawHBarChart(chart, this);
					break;
				}
				case c_oChartTypes.Pie: {
					newChart = new drawPieChart(chart, this);
					break;
				}
				case c_oChartTypes.Scatter: {
					newChart = new drawScatterChart(chart, this);
					break;
				}
				case c_oChartTypes.Area: {
					newChart = new drawAreaChart(chart, this);
					break;
				}
				case c_oChartTypes.Stock: {
					newChart = new drawStockChart(chart, this);
					break;
				}
				case c_oChartTypes.DoughnutChart: {
					newChart = new drawDoughnutChart(chart, this);
					break;
				}
				case c_oChartTypes.Radar: {
					newChart = new drawRadarChart(chart, this);
					break;
				}
				case c_oChartTypes.BubbleChart: {
					newChart = new drawBubbleChart(chart, this);
					break;
				}
				case c_oChartTypes.Surface: {
					newChart = new drawSurfaceChart(chart, this);
					break;
				}
			}
			if (i === 0) {
				this.chart = newChart;
				this.charts = {};
			}
			this.charts[chart.Id] = newChart;
		}
	},

	draw: function (chartSpace, graphics) {
		var t = this;

		this.cChartSpace = chartSpace;

		var cShapeDrawer = new AscCommon.CShapeDrawer();
		cShapeDrawer.Graphics = graphics;
		this.calcProp.series = chartSpace.chart.plotArea.chart.series;

		this.cShapeDrawer = cShapeDrawer;

		//отрисовываем без пересчёта
		this.areaChart.draw(this);


		var drawCharts = function(bBeforeAxes) {
			//рисуем 3d диаграммы только до отрисовки сетки
			if(!bBeforeAxes && t.nDimensionCount === 3) {
				return;
			}

			//TODO в дальнейшем нужно вместо массива формировать map с id модели
			for(var i in t.charts) {
				var chartModel = t._getChartModelById(chartSpace.chart.plotArea, i);
				if(!chartModel) {
					continue;
				}

				var type = chartModel.getObjectType();
				var isLinesChart = type === AscDFH.historyitem_type_LineChart || type === AscDFH.historyitem_type_ScatterChart;
				//рисуем линейные диаграммы после отрисовки сетки
				if(t.nDimensionCount !== 3 && ((isLinesChart && bBeforeAxes) || (!isLinesChart && !bBeforeAxes))) {
					continue;
				} 

				var bIsNoSmartAttack = false;
				if(t.nDimensionCount === 3 || isLinesChart) {
					bIsNoSmartAttack = true;
				}

				if(bIsNoSmartAttack) {
					t.cShapeDrawer.bIsNoSmartAttack = true;
				}
				t.calcProp.series = chartModel.series;
				t.charts[i].draw();
				if(bIsNoSmartAttack) {
					t.cShapeDrawer.bIsNoSmartAttack = false;
				}
			}

		};

		if (!chartSpace.bEmptySeries) {
			this.plotAreaChart.draw(this, true);

			if (this.calcProp.type !== c_oChartTypes.Pie && this.calcProp.type !== c_oChartTypes.DoughnutChart) {
				if (this.nDimensionCount === 3) {
					this.floor3DChart.draw(this);
					this.sideWall3DChart.draw(this);
					this.backWall3DChart.draw(this);
				}
				//GRID
				for(var i = 0; i < this.catAxisChart.length; i++) {
					this.catAxisChart[i].draw(this, null, true);
				}
				for(var i = 0; i < this.valAxisChart.length; i++) {
					this.valAxisChart[i].draw(this, null, true);
				}
				this.plotAreaChart.draw(this, null, true);
			}

			//DRAW 3D CHARTS
			//рисуем оси поверх 3d-диаграмм и линейных/точечных
			drawCharts(true);

			for(var i = 0; i < this.catAxisChart.length; i++) {
				this.catAxisChart[i].draw(this);
			}
			for(var i = 0; i < this.valAxisChart.length; i++) {
				this.valAxisChart[i].draw(this);
			}
			for(var i = 0; i < this.serAxisChart.length; i++) {
				this.serAxisChart[i].draw(this);
			}

			//DRAW CHARTS
			drawCharts();
		}
	},

	recalculateOnly3dProps: function (chartSpace) {
		//this.cChartSpace = chartSpace;
		this.calcProp = {};

		if (this._isSwitchCurrent3DChart(chartSpace)) {
			standartMarginForCharts = 16;
			this.nDimensionCount = 3;

			if (!chartSpace.bEmptySeries) {
				this._calculateProperties(chartSpace);
			}

			if (this.calcProp.widthCanvas == undefined && this.calcProp.pxToMM == undefined) {
				this.calcProp.pathH = 1000000000;
				this.calcProp.pathW = 1000000000;
				this.calcProp.pxToMM = 1 / AscCommon.g_dKoef_pix_to_mm;
				this.calcProp.widthCanvas = chartSpace.extX * this.calcProp.pxToMM;
				this.calcProp.heightCanvas = chartSpace.extY * this.calcProp.pxToMM;
			}

			if (!chartSpace.bEmptySeries) {
				if (this.nDimensionCount === 3) {
					this._calaculate3DProperties(chartSpace);
				}
			}
		}
	},

	_getChartModelById: function(plotArea, id) {
		var res = null;

		var charts = plotArea.charts;
		if(charts) {
			for(var i = 0; i < charts.length; i ++) {
				if(id === charts[i].Id) {
					res = charts[i];
					break;
				}
			}
		}

    	return res;
	},

	_getChartModelIdBySerIdx: function(plotArea, idx) {
		var res = null;

		var charts = plotArea.charts;
		if(charts) {
			for(var i = 0; i < charts.length; i ++) {
				for(var j = 0; j < charts[i].series.length; j++) {
					if(idx === charts[i].series[j].idx) {
						res = charts[i].Id;
						break;
					}
				}
			}
		}

		return res;
	},

	_getIndexByIdxSeria: function(series, val) {
		for(var i = 0; i < series.length; i++) {
			if(series[i].idx === val)
				return i;
		}
	},

	//****positions text labels****
	recalculatePositionText: function (obj) {
		var pos;

		if (!this.cChartSpace.bEmptySeries) {
			var type = obj.getObjectType();
			switch (type) {
				case AscDFH.historyitem_type_DLbl: {
					pos = this._calculatePositionDlbl(obj);
					break;
				}
				case AscDFH.historyitem_type_Title: {
					pos = this._calculatePositionTitle(obj);
					break;
				}
				case AscDFH.historyitem_type_ValAx:
				case AscDFH.historyitem_type_CatAx:
				case AscDFH.historyitem_type_DateAx: {
					pos = this._calculatePositionAxisTitle(obj);
					break;
				}
				case AscDFH.historyitem_type_Legend: {
					pos = this._calculatePositionLegend(obj);
					break;
				}
				default: {
					pos = {x: 0, y: 0};
					break;
				}
			}
		}

		return {x: pos ? pos.x : undefined, y: pos ? pos.y : undefined};
	},
	
	_calculatePositionDlbl: function(obj/*chartSpace, ser, val, bLayout*/)
	{
		var res = null;

		var chartSpace = obj.chart;
		var bLayout = AscCommon.isRealObject(obj.layout) && (AscFormat.isRealNumber(obj.layout.x) || AscFormat.isRealNumber(obj.layout.y));
		var ser = obj.series.idx;
		var val = obj.pt.idx;

		var chartId = this._getChartModelIdBySerIdx(chartSpace.chart.plotArea, ser);
		if(null !== chartId && this.charts[chartId] && this.charts[chartId].chart && this.charts[chartId].chart.series ) {
			var seriaIdx = this._getIndexByIdxSeria(this.charts[chartId].chart.series, ser);
			res = this.charts[chartId]._calculateDLbl(chartSpace, seriaIdx, val, bLayout);
		}

		return res;
	},
	
	_calculatePositionTitle: function(title)
	{	
		var widthGraph = title.chart.extX;

		var widthTitle = title.extX;
		var standartMargin = 7;
		
		var y = standartMargin / this.calcProp.pxToMM;
		var x = widthGraph / 2 - widthTitle / 2;
		
		return {x: x, y: y}
	},

	_calculatePositionAxisTitle: function(axis)
	{
		var chart = axis.parent && axis.parent.parent ? axis.parent.parent : null;
		var legend = chart ? chart.legend : null;
		var title = chart ? chart.title : null;
		var x = 0, y = 0, pxToMM = this.calcProp.pxToMM;

		if(axis && axis.title) {
			var widthAxisTitle = axis.title.extX;
			var heightAxisTitle = axis.title.extY;

			switch (axis.axPos) {
				case window['AscFormat'].AX_POS_B: {
					y = (this.calcProp.heightCanvas - standartMarginForCharts) / pxToMM - heightAxisTitle;
					x = (this.calcProp.chartGutter._left + this.calcProp.trueWidth / 2) / pxToMM - widthAxisTitle / 2;

					if(legend && legend.legendPos === c_oAscChartLegendShowSettings.bottom) {
						y -= legend.extY + (standartMarginForCharts / 2) / pxToMM;
					}
					break;
				}
				case window['AscFormat'].AX_POS_T: {
					y = standartMarginForCharts / pxToMM;
					x = (this.calcProp.chartGutter._left + this.calcProp.trueWidth / 2) / pxToMM - widthAxisTitle / 2;

					if(legend && legend.legendPos === c_oAscChartLegendShowSettings.top) {
						y += legend.extY + (standartMarginForCharts / 2) / pxToMM;
					}
					if (title !== null && !title.overlay) {
						y += title.extY + (standartMarginForCharts / 2) / pxToMM;
					}
					break;
				}
				case window['AscFormat'].AX_POS_L: {
					y = (this.calcProp.chartGutter._top + this.calcProp.trueHeight / 2) / pxToMM - heightAxisTitle / 2;
					x = standartMarginForCharts / pxToMM;

					if(legend && legend.legendPos === c_oAscChartLegendShowSettings.left) {
						x += legend.extX;
					}
					break;
				}
				case window['AscFormat'].AX_POS_R: {
					y = (this.calcProp.chartGutter._top + this.calcProp.trueHeight / 2) / pxToMM - heightAxisTitle / 2;
					x = (this.calcProp.widthCanvas - standartMarginForCharts) / pxToMM - widthAxisTitle;

					if(legend && legend.legendPos === c_oAscChartLegendShowSettings.right) {
						x -= legend.extX;
					}
					break;
				}
			}


			if(this.nDimensionCount === 3)
			{
				var convertResult;
				if(axis instanceof AscFormat.CCatAx) {
					convertResult = this._convertAndTurnPoint((x + widthAxisTitle / 2) * pxToMM, y * pxToMM, this.processor3D.calculateZPositionCatAxis());
					x = convertResult.x / pxToMM - widthAxisTitle / 2;
				} else {
					//TODO избавиться от привзяки к типу диаграммы
					if(!this.processor3D.view3D.getRAngAx() && (this.calcProp.type === c_oChartTypes.Bar || this.calcProp.type === c_oChartTypes.Line))
					{
						var posX = axis.posX;
						var widthLabels = axis.labels && axis.labels.extX ? axis.labels.extX : 0;
						var yPoints = axis.yPoints;
						var upYPoint = yPoints && yPoints[0] ? yPoints[0].pos : 0;
						var downYPoint = yPoints && yPoints[yPoints.length - 1] ? yPoints[yPoints.length - 1].pos : 0;

						var tempX = posX - widthLabels;
						var convertResultX = this._convertAndTurnPoint(tempX * pxToMM, y * pxToMM, 0);
						x = convertResultX.x / pxToMM - widthAxisTitle;

						var convertResultY1 = this._convertAndTurnPoint(posX * pxToMM, upYPoint * pxToMM, 0);
						var convertResultY2 = this._convertAndTurnPoint(posX * pxToMM, downYPoint * pxToMM, 0);
						var heightPerspectiveChart = convertResultY1.y - convertResultY2.y;

						y = (convertResultY2.y + heightPerspectiveChart / 2) / pxToMM - heightAxisTitle / 2;
					}
					else
					{
						convertResult = this._convertAndTurnPoint(x * pxToMM, y * pxToMM, 0);
						y = convertResult.y / pxToMM;
					}
				}

			}
		}

		return {x: x , y: y};
	},

	_calculatePositionLegend: function (legend) {
		var widthLegend = legend.extX;
		var heightLegend = legend.extY;
		var x, y;

		var nLegendPos = legend.legendPos !== null ? legend.legendPos : c_oAscChartLegendShowSettings.right;
		switch (nLegendPos) {
			case c_oAscChartLegendShowSettings.left:
			case c_oAscChartLegendShowSettings.leftOverlay: {
				x = standartMarginForCharts / 2 / this.calcProp.pxToMM;
				y = this.calcProp.heightCanvas / 2 / this.calcProp.pxToMM - heightLegend / 2;
				break;
			}
			case c_oAscChartLegendShowSettings.top: {
				x = this.calcProp.widthCanvas / 2 / this.calcProp.pxToMM - widthLegend / 2;
				y = standartMarginForCharts / 2 / this.calcProp.pxToMM;

				if (legend.parent.title !== null && !legend.parent.title.overlay) {
					y += legend.parent.title.extY + standartMarginForCharts / 2 / this.calcProp.pxToMM;
				}
				break;
			}
			case c_oAscChartLegendShowSettings.right:
			case c_oAscChartLegendShowSettings.rightOverlay: {
				x = (this.calcProp.widthCanvas - standartMarginForCharts / 2) / this.calcProp.pxToMM - widthLegend;
				y = (this.calcProp.heightCanvas / 2) / this.calcProp.pxToMM - heightLegend / 2;
				break;
			}
			case c_oAscChartLegendShowSettings.bottom: {
				x = this.calcProp.widthCanvas / 2 / this.calcProp.pxToMM - widthLegend / 2;
				y = (this.calcProp.heightCanvas - standartMarginForCharts / 2) / this.calcProp.pxToMM - heightLegend;
				break;
			}
			case c_oAscChartLegendShowSettings.topRight: {
				x = (this.calcProp.widthCanvas - standartMarginForCharts / 2) / this.calcProp.pxToMM - widthLegend;
				y = standartMarginForCharts / 2 / this.calcProp.pxToMM;

				if (legend.parent.title !== null && !legend.parent.title.overlay) {
					y += legend.parent.title.extY + standartMarginForCharts / 2 / this.calcProp.pxToMM;
				}
				break;
			}
			default: {
				x = (this.calcProp.widthCanvas - standartMarginForCharts / 2) / this.calcProp.pxToMM - widthLegend;
				y = (this.calcProp.heightCanvas) / this.calcProp.pxToMM - heightLegend / 2;
				break;
			}
		}

		return {x: x, y: y};
	},
	
	
	
	//****calculate margins****
	_calculateMarginsChart: function (chartSpace, dNotPutResult) {
		this.calcProp.chartGutter = {};

		if (this._isSwitchCurrent3DChart(chartSpace)) {
			standartMarginForCharts = 16;
		}
		if (!this.calcProp.pxToMM) {
			this.calcProp.pxToMM = 1 / AscCommon.g_dKoef_pix_to_mm;
		}

		var pxToMM = this.calcProp.pxToMM;
		var plotArea = chartSpace.chart.plotArea;

		//если точки рассчитаны - ставим маргин в зависимости от них
		var marginOnPoints = this._calculateMarginOnPoints(chartSpace/*, isHBar*/);
		var calculateLeft = marginOnPoints.calculateLeft, calculateRight = marginOnPoints.calculateRight, calculateTop = marginOnPoints.calculateTop, calculateBottom = marginOnPoints.calculateBottom;

		//высчитываем выходящие за пределы подписи осей
		var labelsMargin = this._calculateMarginLabels(chartSpace);
		var left = labelsMargin.left, right = labelsMargin.right, top = labelsMargin.top, bottom = labelsMargin.bottom;


		var leftTextLabels = 0;
		var rightTextLabels = 0;
		var topTextLabels = 0;
		var bottomTextLabels = 0;

		//добавляем размеры подписей осей + размеры названия
		//TODO генерировать extX для всех осей
		var axId = chartSpace.chart.plotArea.axId;
		if(axId) {
			for(var i = 0; i < axId.length; i++) {
				if(null !== axId[i].title) {
					switch (axId[i].axPos) {
						case window['AscFormat'].AX_POS_B: {
							bottomTextLabels += axId[i].title.extY;
							break;
						}
						case window['AscFormat'].AX_POS_T: {
							topTextLabels += axId[i].title.extY;
							break;
						}
						case window['AscFormat'].AX_POS_L: {
							leftTextLabels += axId[i].title.extX;
							break;
						}
						case window['AscFormat'].AX_POS_R: {
							rightTextLabels += axId[i].title.extX;
							break;
						}
					}
				}
			}
		}


		//TITLE
		var topMainTitle = 0;
		if (chartSpace.chart.title !== null && !chartSpace.chart.title.overlay) {
			topMainTitle += chartSpace.chart.title.extY;
		}

		//KEY
		var leftKey = 0, rightKey = 0, topKey = 0, bottomKey = 0;
		if (chartSpace.chart.legend && !chartSpace.chart.legend.overlay) {
			var fLegendExtX = chartSpace.chart.legend.extX;
			var fLegendExtY = chartSpace.chart.legend.extY;
			if (chartSpace.chart.legend.layout) {
				if (AscFormat.isRealNumber(chartSpace.chart.legend.naturalWidth) && AscFormat.isRealNumber(chartSpace.chart.legend.naturalHeight)) {
					fLegendExtX = chartSpace.chart.legend.naturalWidth;
					fLegendExtY = chartSpace.chart.legend.naturalHeight;
				}
			}
			var nLegendPos = chartSpace.chart.legend.legendPos !== null ? chartSpace.chart.legend.legendPos : c_oAscChartLegendShowSettings.right;
			switch (nLegendPos) {
				case c_oAscChartLegendShowSettings.left:
				case c_oAscChartLegendShowSettings.leftOverlay: {
					leftKey += fLegendExtX;
					break;
				}
				case c_oAscChartLegendShowSettings.top: {
					topKey += fLegendExtY;
					break;
				}
				case c_oAscChartLegendShowSettings.right:
				case c_oAscChartLegendShowSettings.rightOverlay: {
					rightKey += fLegendExtX;
					break;
				}
				case c_oAscChartLegendShowSettings.bottom: {
					bottomKey += fLegendExtY;
					break;
				}
				case c_oAscChartLegendShowSettings.topRight: {
					rightKey += fLegendExtX;
					break;
				}
			}
		}

		//исключение - когда среди диаграмм есть груговая
		var pieChart = null;
		if(!this._isSwitchCurrent3DChart(chartSpace)) {
			var charts = plotArea.charts;
			for(var i = 0; i < charts.length; i++) {
				var chartType = this._getChartType(charts[i]);
				if(c_oChartTypes.Pie === chartType || c_oChartTypes.DoughnutChart === chartType) {
					pieChart = charts[i];
					break;
				}
			}
			if(null !== pieChart) {
				//вычисляем истинную(первоначальную) ширину и высоту диаграммы
				left = this._getStandartMargin(left, leftKey, leftTextLabels, 0) + leftKey + leftTextLabels;
				bottom = this._getStandartMargin(bottom, bottomKey, bottomTextLabels, 0) + bottomKey + bottomTextLabels;
				top = this._getStandartMargin(top, topKey, topTextLabels, topMainTitle) + topKey + topTextLabels + topMainTitle;
				right = this._getStandartMargin(right, rightKey, rightTextLabels, 0) + rightKey + rightTextLabels;

				var width = chartSpace.extX - left - right;
				var height = chartSpace.extY - top - bottom;
				var pieSize = width > height ? height : width;

				//размещаем по центру относительно width/height
				left += (width - pieSize)/2;
				right += (width - pieSize)/2;
				top += (height - pieSize)/2;
				bottom += (height - pieSize)/2;
			}
		}

		if(null === pieChart) {
			left += this._getStandartMargin(left, leftKey, leftTextLabels, 0) + leftKey + leftTextLabels;
			bottom += this._getStandartMargin(bottom, bottomKey, bottomTextLabels, 0) + bottomKey + bottomTextLabels;
			top += this._getStandartMargin(top, topKey, topTextLabels, topMainTitle) + topKey + topTextLabels + topMainTitle;
			right += this._getStandartMargin(right, rightKey, rightTextLabels, 0) + rightKey + rightTextLabels;
		}

		var pxLeft = calculateLeft ? calculateLeft * pxToMM : left * pxToMM;
		var pxRight = calculateRight ? calculateRight * pxToMM : right * pxToMM;
		var pxTop = calculateTop ? calculateTop * pxToMM : top * pxToMM;
		var pxBottom = calculateBottom ? calculateBottom * pxToMM : bottom * pxToMM;

		//TODO позже пересмотреть правку
		if(topMainTitle && topMainTitle * pxToMM > pxTop) {
			pxTop = (this._getStandartMargin(top, topKey, topTextLabels, topMainTitle) / 2 + topMainTitle) * pxToMM;
		}

		//TODO пересмотреть!!!
		if(pieChart && plotArea.charts.length === 1) {
			if (plotArea.layout) {
				var oLayout = plotArea.layout;
				pxLeft = chartSpace.calculatePosByLayout(pxLeft / pxToMM, oLayout.xMode, oLayout.x, (pxRight - pxLeft) / pxToMM, chartSpace.extX) * pxToMM;
				pxTop = chartSpace.calculatePosByLayout(pxTop / pxToMM, oLayout.yMode, oLayout.y, (pxBottom - pxTop) / pxToMM, chartSpace.extY) * pxToMM;

				var fWidthPlotArea = chartSpace.calculateSizeByLayout(pxLeft / pxToMM, chartSpace.extX, oLayout.w, oLayout.wMode);
				if (fWidthPlotArea > 0) {
					pxRight = chartSpace.extX * pxToMM - (pxLeft + fWidthPlotArea * pxToMM);
				}
				var fHeightPlotArea = chartSpace.calculateSizeByLayout(pxTop / pxToMM, chartSpace.extY, oLayout.h, oLayout.hMode);
				if (fHeightPlotArea > 0) {
					pxBottom = chartSpace.extY * pxToMM - (pxTop + fHeightPlotArea * pxToMM);
				}
			}
		}

		if (dNotPutResult) {
			return {left: pxLeft, right: pxRight, top: pxTop, bottom: pxBottom};
		} else {
			this.calcProp.chartGutter._left = pxLeft;
			this.calcProp.chartGutter._right = pxRight;
			this.calcProp.chartGutter._top = pxTop;
			this.calcProp.chartGutter._bottom = pxBottom;
		}

		this._checkMargins();
	},

	_checkMargins: function () {
		if (this.calcProp.chartGutter._left < 0) {
			this.calcProp.chartGutter._left = standartMarginForCharts;
		}
		if (this.calcProp.chartGutter._right < 0) {
			this.calcProp.chartGutter._right = standartMarginForCharts;
		}
		if (this.calcProp.chartGutter._top < 0) {
			this.calcProp.chartGutter._top = standartMarginForCharts;
		}
		if (this.calcProp.chartGutter._bottom < 0) {
			this.calcProp.chartGutter._bottom = standartMarginForCharts;
		}

		if ((this.calcProp.chartGutter._left + this.calcProp.chartGutter._right) >
			this.calcProp.widthCanvas) {
			this.calcProp.chartGutter._left = standartMarginForCharts;
		}
		if (this.calcProp.chartGutter._right > this.calcProp.widthCanvas) {
			this.calcProp.chartGutter._right = standartMarginForCharts;
		}

		if ((this.calcProp.chartGutter._top + this.calcProp.chartGutter._bottom) >
			this.calcProp.heightCanvas) {
			this.calcProp.chartGutter._top = 0;
		}
		if (this.calcProp.chartGutter._bottom > this.calcProp.heightCanvas) {
			this.calcProp.chartGutter._bottom = 0;
		}
	},

	//включаю новую функцию. если будут проблемы с отступами - использовать функцию _calculateMarginOnPoints2
	_calculateMarginOnPoints: function (chartSpace) {
		var calculateLeft = 0, calculateRight = 0, calculateTop = 0, calculateBottom = 0, diffPoints, curBetween;
		var pxToMM = this.calcProp.pxToMM;

		var horizontalAxes = this._getHorizontalAxes(chartSpace);
		var verticalAxes = this._getVerticalAxes(chartSpace);
		var horizontalAxis = horizontalAxes ? horizontalAxes[0] : null;
		var verticalAxis = verticalAxes ? verticalAxes[0] : null;
		var crossBetween = null;
		if(verticalAxis instanceof AscFormat.CValAx) {
			crossBetween = verticalAxis.crossBetween;
		} else if(horizontalAxis instanceof AscFormat.CValAx) {
			crossBetween = horizontalAxis.crossBetween;
		}

		if (horizontalAxis && horizontalAxis.xPoints && horizontalAxis.xPoints.length && this.calcProp.widthCanvas != undefined) {
			if (horizontalAxis instanceof AscFormat.CValAx) {
				if (horizontalAxis.scaling.orientation == ORIENTATION_MIN_MAX) {
					calculateLeft = horizontalAxis.xPoints[0].pos;
					calculateRight = this.calcProp.widthCanvas / pxToMM - horizontalAxis.xPoints[horizontalAxis.xPoints.length - 1].pos;
				} else {
					calculateLeft = horizontalAxis.xPoints[horizontalAxis.xPoints.length - 1].pos;
					calculateRight = this.calcProp.widthCanvas / pxToMM - horizontalAxis.xPoints[0].pos;
				}
			} else if ((horizontalAxis instanceof AscFormat.CCatAx || horizontalAxis instanceof AscFormat.CDateAx) && verticalAxis && !isNaN(verticalAxis.posX)) {
				diffPoints = horizontalAxis.xPoints[1] ? Math.abs(horizontalAxis.xPoints[1].pos - horizontalAxis.xPoints[0].pos) : Math.abs(horizontalAxis.xPoints[0].pos - verticalAxis.posX) * 2;

				curBetween = 0;
				if (horizontalAxis.scaling.orientation === ORIENTATION_MIN_MAX) {
					if (crossBetween === AscFormat.CROSS_BETWEEN_BETWEEN) {
						curBetween = diffPoints / 2;
					}

					calculateLeft = horizontalAxis.xPoints[0].pos - curBetween;
					calculateRight = this.calcProp.widthCanvas / pxToMM - (horizontalAxis.xPoints[horizontalAxis.xPoints.length - 1].pos + curBetween);
				} else {
					if (crossBetween === AscFormat.CROSS_BETWEEN_BETWEEN) {
						curBetween = diffPoints / 2;
					}

					calculateLeft = horizontalAxis.xPoints[horizontalAxis.xPoints.length - 1].pos - curBetween;
					calculateRight = this.calcProp.widthCanvas / pxToMM - (horizontalAxis.xPoints[0].pos + curBetween);
				}
			}
		}

		if (verticalAxis && verticalAxis.yPoints && verticalAxis.yPoints.length && this.calcProp.heightCanvas != undefined) {
			if (verticalAxis instanceof AscFormat.CValAx) {
				if (verticalAxis.scaling.orientation === ORIENTATION_MIN_MAX) {
					calculateTop = verticalAxis.yPoints[verticalAxis.yPoints.length - 1].pos;
					calculateBottom = this.calcProp.heightCanvas / pxToMM - verticalAxis.yPoints[0].pos;
				} else {
					calculateTop = verticalAxis.yPoints[0].pos;
					calculateBottom = this.calcProp.heightCanvas / pxToMM - verticalAxis.yPoints[verticalAxis.yPoints.length - 1].pos;
				}
			} else if ((verticalAxis instanceof AscFormat.CCatAx || verticalAxis instanceof AscFormat.CDateAx) && horizontalAxis && !isNaN(horizontalAxis.posY)) {

				diffPoints = verticalAxis.yPoints[1] ? Math.abs(verticalAxis.yPoints[1].pos - verticalAxis.yPoints[0].pos) : Math.abs(verticalAxis.yPoints[0].pos - horizontalAxis.posY) * 2;

				curBetween = 0;
				if (verticalAxis.scaling.orientation === ORIENTATION_MIN_MAX) {
					if (crossBetween === AscFormat.CROSS_BETWEEN_BETWEEN) {
						curBetween = diffPoints / 2;
					}

					calculateTop = verticalAxis.yPoints[verticalAxis.yPoints.length - 1].pos - curBetween;
					calculateBottom = this.calcProp.heightCanvas / pxToMM - (verticalAxis.yPoints[0].pos + curBetween);
				} else {
					if (crossBetween === AscFormat.CROSS_BETWEEN_BETWEEN) {
						curBetween = diffPoints / 2;
					}

					calculateTop = verticalAxis.yPoints[0].pos - curBetween;
					calculateBottom = this.calcProp.heightCanvas / pxToMM - (verticalAxis.yPoints[verticalAxis.yPoints.length - 1].pos + curBetween);
				}
			}
		}

		return {calculateLeft: calculateLeft, calculateRight : calculateRight, calculateTop: calculateTop, calculateBottom: calculateBottom};
	},
	
	_getStandartMargin: function(labelsMargin, keyMargin, textMargin, topMainTitleMargin)
	{
		var defMargin = standartMarginForCharts / this.calcProp.pxToMM;
		var result;

		if (labelsMargin == 0 && keyMargin == 0 && textMargin == 0 && topMainTitleMargin == 0) {
			result = defMargin;
		} else if (labelsMargin != 0 && keyMargin == 0 && textMargin == 0 && topMainTitleMargin == 0) {
			result = defMargin / 2;
		} else if (labelsMargin != 0 && keyMargin == 0 && textMargin != 0 && topMainTitleMargin == 0) {
			result = defMargin;
		} else if (labelsMargin != 0 && keyMargin != 0 && textMargin != 0 && topMainTitleMargin == 0) {
			result = defMargin + defMargin / 2;
		} else if (labelsMargin == 0 && keyMargin != 0 && textMargin == 0 && topMainTitleMargin == 0) {
			result = defMargin;
		} else if (labelsMargin == 0 && keyMargin == 0 && textMargin != 0 && topMainTitleMargin == 0) {
			result = defMargin;
		} else if (labelsMargin == 0 && keyMargin != 0 && textMargin != 0 && topMainTitleMargin == 0) {
			result = defMargin + defMargin / 2;
		} else if (labelsMargin != 0 && keyMargin != 0 && textMargin == 0 && topMainTitleMargin == 0) {
			result = defMargin;
		} else if (labelsMargin == 0 && keyMargin != 0 && textMargin != 0 && topMainTitleMargin == 0) {
			result = defMargin + defMargin / 2;
		} else if (labelsMargin == 0 && keyMargin == 0 && topMainTitleMargin != 0) {
			result = defMargin + defMargin / 2;
		} else if (labelsMargin == 0 && keyMargin != 0 && topMainTitleMargin != 0) {
			result = 2 * defMargin;
		} else if (labelsMargin != 0 && keyMargin == 0 && topMainTitleMargin != 0) {
			result = defMargin;
		} else if (labelsMargin != 0 && keyMargin != 0 && topMainTitleMargin != 0) {
			result = 2 * defMargin;
		}

		return result;
	},

	//TEST and change _calculateMarginLabels->_calculateMarginLabels2
	_calculateMarginLabels: function (chartSpace) {
		var left = 0, right = 0, bottom = 0, top = 0;
		var leftDownPointX, leftDownPointY, rightUpPointX, rightUpPointY;

		var crossBetween = chartSpace.getValAxisCrossType();
		var horizontalAxes = this._getHorizontalAxes(chartSpace);
		var verticalAxes = this._getVerticalAxes(chartSpace);
		var horizontalAxis = horizontalAxes ? horizontalAxes[0] : null;
		var verticalAxis = verticalAxes ? verticalAxes[0] : null;

		var diffPoints;
		if(horizontalAxis && horizontalAxis.xPoints &&  horizontalAxis.xPoints.length) {
			var orientationHorAxis = horizontalAxis.scaling.orientation === ORIENTATION_MIN_MAX;
			diffPoints = 0;
			if((horizontalAxis instanceof AscFormat.CDateAx || horizontalAxis instanceof AscFormat.CCatAx) && crossBetween === AscFormat.CROSS_BETWEEN_BETWEEN) {
				diffPoints = Math.abs((horizontalAxis.interval) / 2);
			}
			if(orientationHorAxis) {
				leftDownPointX = horizontalAxis.xPoints[0].pos - diffPoints;
				rightUpPointX = horizontalAxis.xPoints[horizontalAxis.xPoints.length - 1].pos + diffPoints;
			} else {
				leftDownPointX = horizontalAxis.xPoints[horizontalAxis.xPoints.length - 1].pos - diffPoints;
				rightUpPointX = horizontalAxis.xPoints[0].pos + diffPoints;
			}

			if (verticalAxis.labels && !verticalAxis.bDelete) {
				//подпись оси OY находится левее крайней левой точки
				if (leftDownPointX >= verticalAxis.labels.x) {
					left = leftDownPointX - verticalAxis.labels.x;
				} else if ((verticalAxis.labels.x + verticalAxis.labels.extX) >= rightUpPointX)//правее крайней правой точки
				{
					right = verticalAxis.labels.x + verticalAxis.labels.extX - rightUpPointX;
				}
			}
		}

		if(verticalAxis && verticalAxis.yPoints && verticalAxis.yPoints.length) {
			var orientationVerAxis = verticalAxis.scaling.orientation === ORIENTATION_MIN_MAX;
			diffPoints = 0;
			if((verticalAxis instanceof AscFormat.CDateAx || verticalAxis instanceof AscFormat.CCatAx)&& crossBetween === AscFormat.CROSS_BETWEEN_BETWEEN) {
				diffPoints = Math.abs((verticalAxis.interval) / 2);
			}
			if(orientationVerAxis) {
				leftDownPointY = verticalAxis.yPoints[0].pos + diffPoints;
				rightUpPointY = verticalAxis.yPoints[verticalAxis.yPoints.length - 1].pos - diffPoints;
			} else {
				leftDownPointY = verticalAxis.yPoints[verticalAxis.yPoints.length - 1].pos + diffPoints;
				rightUpPointY = verticalAxis.yPoints[0].pos - diffPoints;
			}

			if (horizontalAxis.labels && !horizontalAxis.bDelete) {
				//подпись оси OX находится ниже крайней нижней точки
				if ((horizontalAxis.labels.y + horizontalAxis.labels.extY) >= leftDownPointY) {
					bottom = (horizontalAxis.labels.y + horizontalAxis.labels.extY) - leftDownPointY;
				} else if (horizontalAxis.labels.y <= rightUpPointY)//выше верхней
				{
					top = rightUpPointY - horizontalAxis.labels.y;
				}
			}
		}

		return {left: left, right: right, top: top, bottom: bottom};
	},

	_getHorizontalAxes: function(chartSpace) {
		var res = null;

		var axId = chartSpace.chart.plotArea.axId;
		for(var i = 0; i < axId.length; i++) {
			var axis = chartSpace.chart.plotArea.axId[i];
			if(axis.axPos === window['AscFormat'].AX_POS_B || axis.axPos === window['AscFormat'].AX_POS_T) {
				if(!res) {
					res = [];
				}
				res.push(axis);
			}
		}

		return res;
	},

	_getVerticalAxes: function(chartSpace) {
		var res = null;

		var axId = chartSpace.chart.plotArea.axId;
		for(var i = 0; i < axId.length; i++) {
			var axis = chartSpace.chart.plotArea.axId[i];
			if(axis.axPos === window['AscFormat'].AX_POS_R || axis.axPos === window['AscFormat'].AX_POS_L) {
				if(!res) {
					res = [];
				}
				res.push(axis);
			}
		}

		return res;
	},


	//****calculate properties****
	_calculateProperties: function (chartSpace) {
		if (!this.calcProp.scale) {
			this.preCalculateData(chartSpace);
		}

		//считаем маргины
		this._calculateMarginsChart(chartSpace);

		this.calcProp.trueWidth = this.calcProp.widthCanvas - this.calcProp.chartGutter._left - this.calcProp.chartGutter._right;
		this.calcProp.trueHeight = this.calcProp.heightCanvas - this.calcProp.chartGutter._top - this.calcProp.chartGutter._bottom;
	},
	
	//****new calculate data****
	_calculateStackedData2: function (data, chart) {
		if(!data) {
			return;
		}

		var maxMinObj;
		var grouping = this.getChartGrouping(chart);
		var chartType = this._getChartType(chart);
		var t = this;

		//TODO стоит сделать общую обработку для всех диаграмм
		var calculateStacked = function(sum) {
			if(c_oChartTypes.HBar === chartType || c_oChartTypes.Bar === chartType) {
				var originalData = $.extend(true, [], data);
				for (var j = 0; j < data.length; j++) {
					for (var i = 0; i < data[j].length; i++) {
						data[j][i] = t._findPrevValue(originalData, j, i)
					}
				}

				if(sum) {
					for (var j = 0; j < data.length; j++) {
						for (var i = 0; i < data[j].length; i++) {
							data[j][i] = data[j][i] / sum[j];
						}
					}
				}
			} else {
				for (var j = 0; j < (data.length - 1); j++) {
					for (var i = 0; i < data[j].length; i++) {
						if (!data[j + 1]) {
							data[j + 1] = [];
						}
						data[j + 1][i] = data[j + 1][i] + data[j][i];
					}
				}

				if(sum && data[0]) {
					for (var j = 0; j < (data[0].length); j++) {
						for (var i = 0; i < data.length; i++) {
							if (sum[j] == 0) {
								data[i][j] = 0;
							} else {
								data[i][j] = (data[i][j]) / (sum[j]);
							}
						}
					}
				}
			}
		};

		var calculateSum = function() {
			//вычисляем сумму
			//для разных диаграмм она вычисляется по-разному
			var res = [];
			if(c_oChartTypes.HBar === chartType || c_oChartTypes.Bar === chartType) {
				for (var j = 0; j < (data.length); j++) {
					res[j] = 0;
					for (var i = 0; i < data[j].length; i++) {
						res[j] += Math.abs(data[j][i]);
					}
				}
			} else {
				if(data[0]) {
					for (var j = 0; j < (data[0].length); j++) {
						res[j] = 0;
						for (var i = 0; i < data.length; i++) {
							res[j] += Math.abs(data[i][j]);
						}
					}
				}
			}
			return res;
		};

		if (grouping === 'stacked') {
			calculateStacked();
		} else if (grouping === 'stackedPer') {
			calculateStacked(calculateSum());
		}

		maxMinObj = this._getMaxMinValueArray(data);
		return maxMinObj;
	},

	_calculateExtremumAllCharts: function (chartSpace, isFirstChart) {
		//возвращает массив, где первый элемент - для основной оси, второй - для вспомогательной
		//максимальные/минимальные значения среди всех графиков
		var t = this, isStackedType;
		var plotArea = chartSpace.chart.plotArea;
		var charts = plotArea.charts;
		if(!charts || isFirstChart) {
			charts = [plotArea.chart];
		}

		var getMinMaxCurCharts = function(axisCharts, axis) {

			//предварительно проходимся по всем диаграммам и ищем 100% stacked тип
			isStackedType = false;
			for (var i = 0; i < axisCharts.length; i++) {
				grouping = t.getChartGrouping(axisCharts[i]);
				if("stackedPer" === grouping) {
					isStackedType = true;
					break;
				}
			}

			var minMaxData, min, max, chart, grouping;
			for (var i = 0; i < axisCharts.length; i++) {
				chart = axisCharts[i];
				grouping = t.getChartGrouping(chart);
				minMaxData = t._calculateData2(chart, grouping, axis);

				/*if("stackedPer" !== grouping && isStackedType) {
					minMaxData.min = minMaxData.min*100;
					minMaxData.max = minMaxData.max*100;
					minMaxData.ymin = minMaxData.ymin*100;
					minMaxData.ymax = minMaxData.ymax*100;
				}*/

				if(AscDFH.historyitem_type_ScatterChart === chart.getObjectType()) {
					if(axis.axPos === window['AscFormat'].AX_POS_B || axis.axPos === window['AscFormat'].AX_POS_T) {
						if(i == 0 || minMaxData.min < min) {
							min = minMaxData.min;
						}
						if(i == 0 || minMaxData.max > max) {
							max = minMaxData.max;
						}
					} else {
						if(i == 0 || minMaxData.ymin < min) {
							min = minMaxData.ymin;
						}
						if(i == 0 || minMaxData.ymax > max) {
							max = minMaxData.ymax;
						}
					}
				} else {
					if(i == 0 || minMaxData.min < min) {
						min = minMaxData.min;
					}
					if(i == 0 || minMaxData.max > max) {
						max = minMaxData.max;
					}
				}
			}

			return {min: min, max: max};
		};

		for(var j = 0; j < plotArea.axId.length; j++) {
			var axObj = plotArea.axId[j];
			var axisCharts = this._getChartsByAxisId(charts, axObj.axId);
			var minMaxAxis = getMinMaxCurCharts(axisCharts, axObj);
			axObj.min = minMaxAxis.min;
			axObj.max = minMaxAxis.max;
			//если будут проблемы, протестить со старой функцией -> this._getAxisValues(false, minMaxAxis.min, minMaxAxis.max, chartSpace)
			axObj.scale = this._roundValues(this._getAxisValues2(axObj, chartSpace, isStackedType));

			if(isStackedType) {
				//для случая 100% stacked - если макс/мин равно определенному делению, большие/меньшие - убираем
				if(axObj.scale[0] !== 0 && axObj.min === axObj.scale[1]) {
					axObj.scale.splice(0, 1);
				}
				if(axObj.max === axObj.scale[axObj.scale.length - 2]) {
					axObj.scale.splice(axObj.scale.length - 1, 1);
				}
			}
		}
	},

	_getChartsByAxisId: function(charts, id) {
		var res = [];
		for(var i = 0; i < charts.length; i++) {
			if(!charts[i].axId) {
				continue;
			}

			for(var j = 0; j < charts[i].axId.length; j++) {
				if(id === this._searchChangedAxisId(charts[i].axId[j].axId)) {
					res.push(charts[i]);
					break;
				}
			}
		}
		return res;
	},

	_searchChangedAxisId: function(id) {
		var res = id;

		if(this.changeAxisMap && this.changeAxisMap[id]) {
			res = this.changeAxisMap[id];
		}

		return res;
	},

	_searchChangedAxis: function(axis) {
		var res = axis;

		if(this.changeAxisMap && axis.axId && this.changeAxisMap[axis.axId]) {
			var newId = this.changeAxisMap[axis.axId];
			var newAxis = this._searchAxisById(newId);
			if(null !== newAxis) {
				res = newAxis;
			}
		}

		return res;
	},

	_searchAxisById: function(id, chartSpace) {
		var res = null;
		chartSpace = chartSpace || this.cChartSpace;
		if(chartSpace) {
			var axId = chartSpace.chart.plotArea.axId;
			for(var i = 0; i < axId.length; i++) {
				if(id === axId[i].axId) {
					res = axId[i];
					break;
				}
			}
		}

		return res;
	},
	
	_calculateChangeAxisMap: function (chartSpace) {
		//ms рисует по-разному диаграммы со скрытымми/не скрытыми осями
		//если ось скрыта - ищем замену среди основных открытых
		this.changeAxisMap = {};
		var axId = chartSpace.chart.plotArea.axId;

		var searchNeedAxis = function(excludeAxis) {
			var res = null;

			var needPos = excludeAxis.axPos === window['AscFormat'].AX_POS_L || excludeAxis.axPos === window['AscFormat'].AX_POS_R;
			for (var j = 0; j < axId.length; j++) {
				var curAxis = axId[j];
				var curPos = curAxis.axPos === window['AscFormat'].AX_POS_L || curAxis.axPos === window['AscFormat'].AX_POS_R;
				if(excludeAxis.axId !== axId[j].axId && needPos === curPos) {
					if(excludeAxis.getObjectType() === curAxis.getObjectType()) {
						res = curAxis;
						break;
					}
				}
			}

			return res;
		};

		if(axId) {
			for (var i = 0; i < axId.length; i++) {
				if(axId[i].bDelete && AscDFH.historyitem_type_ValAx === axId[i].getObjectType()) {
					var needAxis = searchNeedAxis(axId[i]);
					if(needAxis) {
						this.changeAxisMap[axId[i].axId] = needAxis.axId;
					}
				}
			}
		}
	},

	_calculateData2: function(chart, grouping, axis)
	{
		var xNumCache, yNumCache, newArr, arrValues = [], max = 0, min = 0, minY = 0, maxY = 0;
		var series = chart.series;
		var chartType = this._getChartType(chart);
		var t = this;

		var generateArrValues = function () {

			var seria, numCache, pts;
			if(AscDFH.historyitem_type_ValAx === axis.getObjectType()) {
				var isEn = false, numSeries = 0;
				for (var l = 0; l < series.length; l++) {
					seria = series[l];
					numCache = t.getNumCache(seria.val);
					pts = numCache ? numCache.pts : null;

					if (!pts || !pts.length || seria.isHidden === true) {
						continue;
					}

					var n = 0;
					arrValues[numSeries] = [];
					for (var col = 0; col < numCache.ptCount; col++) {
						var curPoint = numCache.pts[col];

						//условие дбавлено для того, чтобы диаграммы, данные которых имеют мин/макс и пустые ячейки, рисовались грамотно
						if(!curPoint && (t.calcProp.subType === 'stackedPer' || t.calcProp.subType === 'stacked')) {
							curPoint = {val: 0};
						} else if (!curPoint || curPoint.isHidden === true) {
							continue;
						}

						var val = curPoint.val;
						var value = parseFloat(val);

						if (!isEn && !isNaN(value)) {
							min = value;
							max = value;
							isEn = true;
						}
						if (!isNaN(value) && value > max) {
							max = value;
						}
						if (!isNaN(value) && value < min) {
							min = value;
						}

						if (isNaN(value) && val == '' && (((chartType === c_oChartTypes.Line ) && grouping === 'normal'))) {
							value = '';
						} else if (isNaN(value)) {
							value = 0;
						}

						if (chartType === c_oChartTypes.Pie || chartType === c_oChartTypes.DoughnutChart) {
							value = Math.abs(value);
						}

						arrValues[numSeries][n] = value;
						n++;
					}
					numSeries++;
				}

				if(min === max) {
					if(min < 0) {
						max = 0;
					} else {
						min = 0;
					}
				}
			} else {
				if(series.length > 0) {
					//возможно стоит пройтись по всем сериям
					seria = series[0];
					numCache = t.getNumCache(seria.val);
					min = 1;
					if(numCache){
						max = numCache.ptCount;
					}
					else{
						max = 1;
					}
				}
			}
		};

		var generateArrValuesScatter = function () {
			var yVal;
			var xVal;
			newArr = [];
			for (var l = 0; l < series.length; ++l) {
				newArr[l] = [];
				yNumCache = t.getNumCache(series[l].yVal);

				if (!yNumCache) {
					continue;
				}

				for (var j = 0; j < yNumCache.ptCount; ++j) {
					if (yNumCache.pts[j]) {
						yVal = parseFloat(yNumCache.pts[j].val);

						xNumCache = t.getNumCache(series[l].xVal);

						if (xNumCache && xNumCache.pts[j]) {
							if (!isNaN(parseFloat(xNumCache.pts[j].val))) {
								xVal = parseFloat(xNumCache.pts[j].val);
							} else {
								xVal = j + 1;
							}
						} else {
							xVal = j + 1;
						}

						newArr[l][j] = [xVal, yVal];

						if (l === 0 && j === 0) {
							min = xVal;
							max = xVal;
							minY = yVal;
							maxY = yVal;
						}

						if (xVal < min) {
							min = xVal;
						}
						if (xVal > max) {
							max = xVal;
						}
						if (yVal < minY) {
							minY = yVal;
						}
						if (yVal > maxY) {
							maxY = yVal;
						}
					} else {
						xNumCache = t.getNumCache(series[l].xVal);

						if (xNumCache && xNumCache.pts[j]) {
							if (!isNaN(parseFloat(xNumCache.pts[j].val))) {
								xVal = parseFloat(xNumCache.pts[j].val);
							} else {
								xVal = j + 1;
							}
						} else {
							xVal = j + 1;
						}

						if (l === 0 && j === 0) {
							min = xVal;
							max = xVal;
						}
						if (xVal < min) {
							min = xVal;
						}
						if (xVal > max) {
							max = xVal;
						}
					}
				}
			}
		};

		if (chartType !== c_oChartTypes.Scatter) {
			generateArrValues();
		} else {
			generateArrValuesScatter();
		}

		if(chartType === c_oChartTypes.Bar || chartType === c_oChartTypes.HBar) {
			arrValues = arrReverse(arrValues);
		}

		//пересчёт данных для накопительных диаграмм
		if (AscDFH.historyitem_type_ValAx === axis.getObjectType() && ("stackedPer" === grouping || "stacked" === grouping)) {
			if (newArr) {
				arrValues = newArr;
			}
			var stackedExtremum = this._calculateStackedData2(arrValues, chart);
			if(stackedExtremum) {
				min = stackedExtremum.min;
				max = stackedExtremum.max;
			}
		}

		return {min: min, max: max, ymin: minY, ymax: maxY};
	},

	_getAxisValues2: function (axis, chartSpace, isStackedType) {
		//для оси категорий берем интервал 1
		var arrayValues;
		if(AscDFH.historyitem_type_CatAx === axis.getObjectType() || AscDFH.historyitem_type_DateAx === axis.getObjectType()) {
			arrayValues = [];
			var max = axis.max;
			for(var i = axis.min; i <= max; i++) {
				arrayValues.push(i);
			}
			return arrayValues;
		}

		//chartProp.chart.plotArea.valAx.scaling.logBase
		var axisMin, axisMax, firstDegree, step;

		var yMin = axis.min;
		var yMax = axis.max;

		if (axis.scaling && axis.scaling.logBase) {
			arrayValues = this._getLogArray(yMin, yMax, axis.scaling.logBase);
			return arrayValues;
		}

		//максимальное и минимальное значение(по документации excel)
		var trueMinMax = this._getTrueMinMax(yMin, yMax, isStackedType);

		var manualMin = axis.scaling && axis.scaling.min !== null ? axis.scaling.min : null;
		var manualMax = axis.scaling && axis.scaling.max !== null ? axis.scaling.max : null;

		//TODO временная проверка для некорректных минимальных и максимальных значений
		if (manualMax && manualMin && manualMax < manualMin) {
			if (manualMax < 0) {
				manualMax = 0;
			} else {
				manualMin = 0;
			}
		}

		axisMin = manualMin !== null && manualMin !== undefined ? manualMin : trueMinMax.min;
		axisMax = manualMax !== null && manualMax !== undefined ? manualMax : trueMinMax.max;

		//TODO пересмотреть зависимость значений оси от типа диаграммы
		/*var percentChartMax = 100;
		if (this.calcProp.subType === 'stackedPer' && axisMax > percentChartMax && manualMax === null) {
			axisMax = percentChartMax;
		}
		if (this.calcProp.subType === 'stackedPer' && axisMin < -percentChartMax && manualMin === null) {
			axisMin = -percentChartMax;
		}*/

		if (axisMax < axisMin) {
			manualMax = 2 * axisMin;
			axisMax = manualMax;
		}

		//приводим к первому порядку
		firstDegree = this._getFirstDegree((Math.abs(axisMax - axisMin)) / 10);

		var bIsManualStep = false;
		//находим шаг
		if (axis && axis.majorUnit != null) {
			step = axis.majorUnit;
			bIsManualStep = true;
		} else {
			//было следующее условие - isOx || c_oChartTypes.HBar === this.calcProp.type
			if (axis.axPos === window['AscFormat'].AX_POS_B || axis.axPos === window['AscFormat'].AX_POS_T) {
				step = this._getStep(firstDegree.val + (firstDegree.val / 10) * 3);
			} else {
				step = this._getStep(firstDegree.val);
			}

			step = step * firstDegree.numPow;
		}
		
		if (isNaN(step) || step === 0) {
			arrayValues = [0, 0.2, 0.4, 0.6, 0.8, 1, 1.2];
		} else {
			arrayValues = this._getArrayDataValues(step, axisMin, axisMax, manualMin, manualMax);
		}

		//проверка на переход в другой диапазон из-за ограничения по высоте
		if (!bIsManualStep) {
			var props = {
				arrayValues: arrayValues,
				step: step,
				axisMin: axisMin,
				axisMax: axisMax,
				manualMin: manualMin,
				manualMax: manualMax
			};
			arrayValues = this._correctDataValuesFromHeight(props, chartSpace);
		}

		//TODO для 3d диаграмм. пересмотреть!
		if (this._isSwitchCurrent3DChart(chartSpace)) {
			if (yMax > 0 && yMin < 0) {
				if (manualMax == null && yMax <= arrayValues[arrayValues.length - 2]) {
					arrayValues.splice(arrayValues.length - 1, 1);
				}
				if (manualMin == null && yMin >= arrayValues[1]) {
					arrayValues.splice(0, 1);
				}
			} else if (yMax > 0 && yMin >= 0) {
				if (manualMax == null && yMax <= arrayValues[arrayValues.length - 2]) {
					arrayValues.splice(arrayValues.length - 1, 1);
				}
			} else if (yMin < 0 && yMax <= 0) {
				if (manualMin == null && yMin >= arrayValues[1]) {
					arrayValues.splice(0, 1);
				}
			}
		}

		return arrayValues;
	},

	_correctDataValuesFromHeight: function (props, chartSpace, isOxAxis) {
		var res = props.arrayValues;
		var heightCanvas = chartSpace.extY * this.calcProp.pxToMM;
		var margins = this._calculateMarginsChart(chartSpace, true);
		var trueHeight = heightCanvas - margins.top - margins.bottom;

		var axisMin = props.axisMin;
		var axisMax = props.axisMax;
		var manualMin = props.manualMin;
		var manualMax = props.manualMax;
		var newStep = props.step;


		if (isOxAxis) {

		} else {
			if (axisMin < 0 && axisMax > 0) {
				/*var limitArr = [0, 0, 0, 28, 20, 20, 18, 20, 18, 18, 17, 16];
				 var limit = limitArr[res.length - 1];
				 var heightGrid = Math.round((trueHeight / (res.length - 1)));
				 while(heightGrid <= limit)
				 {
				 var firstDegreeStep = this._getFirstDegree(newStep);
				 var tempStep = this._getNextStep(firstDegreeStep.val);
				 newStep = tempStep * firstDegreeStep.numPow;
				 res = this._getArrayDataValues(newStep, axisMin, axisMax, manualMin, manualMax);

				 if(res.length <= 3)
				 {
				 break;
				 }

				 limit = limitArr[res.length - 1];
				 heightGrid = Math.round((trueHeight / (res.length - 1)));
				 }*/
			} else {
				var limitArr = [0, 0, 32, 26, 24, 22, 21, 19, 18, 17, 16];
				var limit = limitArr[res.length - 1];
				var heightGrid = Math.round((trueHeight / (res.length - 1)));
				while (heightGrid <= limit) {
					var firstDegreeStep = this._getFirstDegree(newStep);
					var tempStep = this._getNextStep(firstDegreeStep.val);
					newStep = tempStep * firstDegreeStep.numPow;
					res = this._getArrayDataValues(newStep, axisMin, axisMax, manualMin, manualMax);

					if (res.length <= 2) {
						break;
					}

					limit = limitArr[res.length - 1];
					heightGrid = Math.round((trueHeight / (res.length - 1)));
				}
			}
		}


		return res;
	},

	_getNextStep: function (step) {
		if (step === 1) {
			step = 2;
		} else if (step === 2) {
			step = 5;
		} else if (step === 5) {
			step = 10;
		}

		return step;
	},

	_getArrayDataValues: function (step, axisMin, axisMax, manualMin, manualMax) {
		var arrayValues;
		//минимальное значение оси
		//TODO use axisMin
		var minUnit = 0;

		if (manualMin != null) {
			minUnit = manualMin;
		} else if (manualMin == null && axisMin != null && axisMin != 0 && axisMin > 0 && axisMax > 0)//TODO пересмотреть все значения, где-то могут быть расхождения с EXCEL
		{
			minUnit = parseInt(axisMin / step) * step;
		} else {
			if (axisMin < 0) {
				while (minUnit > axisMin) {
					minUnit -= step;
				}
			} else if (axisMin > 0) {
				while (minUnit < axisMin && minUnit > (axisMin - step)) {
					minUnit += step;
				}
			}
		}

		//массив подписей
		arrayValues = this._getArrayAxisValues(minUnit, axisMin, axisMax, step, manualMin, manualMax);

		return arrayValues;
	},

	_getLogArray: function (yMin, yMax, logBase) {
		var result = [];

		var temp;
		var pow = 0;
		var tempPow = yMin;

		if (yMin < 1 && yMin > 0) {
			temp = this._getFirstDegree(yMin).numPow;

			tempPow = temp;
			while (tempPow < 1) {
				pow--;
				tempPow = tempPow * 10;
			}
		} else {
			temp = Math.pow(logBase, 0);
		}

		if (logBase < 1) {
			logBase = 2;
		}

		var step = 0;
		var lMax = 1;
		if (yMin < 1 && yMin > 0) {
			if (lMax < yMax) {
				lMax = yMax;
			}

			while (temp < lMax) {
				temp = Math.pow(logBase, pow);
				result[step] = temp;
				pow++;
				step++;
			}
		} else {
			while (temp <= yMax) {
				temp = Math.pow(logBase, pow);
				result[step] = temp;
				pow++;
				step++;
			}
		}

		return result;
	},

	_getArrayAxisValues: function (minUnit, axisMin, axisMax, step, manualMin, manualMax) {
		var arrayValues = [];
		var stackedPerMax = null !== manualMax ? manualMax : 100;

		if (this.calcProp.subType === 'stackedPer' && step > stackedPerMax) {
			stackedPerMax = step;
		}

		var maxPointsCount = 40;
		for (var i = 0; i < maxPointsCount; i++) {
			if (this.calcProp.subType === 'stackedPer' && (minUnit + step * i) > stackedPerMax) {
				break;
			}

			arrayValues[i] = minUnit + step * i;

			if (axisMax == 0 && axisMin < 0 && arrayValues[i] == axisMax) {
				break;
			} else if ((manualMax != null && arrayValues[i] >= axisMax) || (manualMax == null && arrayValues[i] > axisMax)) {
				if (this.calcProp.subType === 'stackedPer') {
					arrayValues[i] = arrayValues[i];
				}

				break;
			} else if (this.calcProp.subType === 'stackedPer') {
				arrayValues[i] = arrayValues[i];
			}
		}

		/*if(this.calcProp.subType == 'stackedPer')
		 {
		 //TODO пересмотреть все ситуации, когда заданы фиксированные максимальные и минимальные значение выше 100%
		 if(step > axisMax)
		 arrayValues = [axisMin, axisMax];
		 }*/

		if (!arrayValues.length) {
			arrayValues = [0.2, 0.4, 0.6, 0.8, 1, 1.2];
		}

		return arrayValues;
	},

	_getStep: function (step) {
		if (step > 1 && step <= 2) {
			step = 2;
		} else if (step > 2 && step <= 5) {
			step = 5;
		} else if (step > 5 &&
			step <= 10) {
			step = 10;
		} else if (step > 10 && step <= 20) {
			step = 20;
		}

		return step;
	},

	_getTrueMinMax: function (yMin, yMax, isStackedType) {

		var axisMax, axisMin, diffMaxMin;
		var cDiff = 1/6;
		if (yMin >= 0 && yMax >= 0) {
			axisMax = isStackedType ? yMax : yMax + 0.05 * ( yMax - yMin );

			diffMaxMin = (yMax - yMin) / yMax;
			if (cDiff > diffMaxMin) {
				axisMin = yMin - ((yMax - yMin) / 2);
			} else {
				axisMin = 0;
			}
		} else if (yMin <= 0 && yMax <= 0) {
			diffMaxMin = (yMin - yMax) / yMin;
			axisMin = isStackedType ? yMin : yMin + 0.05 * (yMin - yMax);

			if (cDiff < diffMaxMin) {
				axisMax = 0;
			} else {
				axisMax = yMax - ((yMin - yMax) / 2)
			}
		} else if (yMax > 0 && yMin < 0) {
			axisMax = isStackedType ? yMax : yMax + 0.05 * (yMax - yMin);
			axisMin = isStackedType ? yMin : yMin + 0.05 * (yMin - yMax);
		}

		if (axisMin === axisMax) {
			if (axisMin < 0) {
				axisMax = 0;
			} else {
				axisMin = 0;
			}
		}

		return {min: axisMin, max: axisMax};
	},


	//****functions for UP Functions****
	preCalculateData: function (chartSpace) {
		this._calculateChangeAxisMap(chartSpace);
		this.cChartSpace = chartSpace;
		this.calcProp.pxToMM = 1 / AscCommon.g_dKoef_pix_to_mm;

		this.calcProp.pathH = 1000000000;
		this.calcProp.pathW = 1000000000;

		this.calcProp.type = this._getChartType(chartSpace.chart.plotArea.chart);
		this.calcProp.subType = this.getChartGrouping(chartSpace.chart.plotArea.chart);

		this.calcProp.xaxispos = null;
		this.calcProp.yaxispos = null;

		//рассчёт данных и ещё некоторых параметров(this.calcProp./min/max/ymax/ymin/)
		this._calculateExtremumAllCharts(chartSpace);

		//***series***
		this.calcProp.series = chartSpace.chart.plotArea.chart.series;

		//отсеиваем пустые серии
		var countSeries = this.calculateCountSeries(chartSpace.chart.plotArea.chart);
		this.calcProp.seriesCount = countSeries.series;
		this.calcProp.ptCount = countSeries.points;

		this.calcProp.widthCanvas = chartSpace.extX * this.calcProp.pxToMM;
		this.calcProp.heightCanvas = chartSpace.extY * this.calcProp.pxToMM;
	},

	_getChartType: function (chart) {
		var res;
		var typeChart = chart.getObjectType();
		switch (typeChart) {
			case AscDFH.historyitem_type_LineChart: {
				res = c_oChartTypes.Line;
				break;
			}
			case AscDFH.historyitem_type_BarChart: {
				if (chart.barDir !== AscFormat.BAR_DIR_BAR) {
					res = c_oChartTypes.Bar;
				} else {
					res = c_oChartTypes.HBar;
				}
				break;
			}
			case AscDFH.historyitem_type_PieChart: {
				res = c_oChartTypes.Pie;
				break;
			}
			case AscDFH.historyitem_type_AreaChart: {
				res = c_oChartTypes.Area;
				break;
			}
			case AscDFH.historyitem_type_ScatterChart: {
				res = c_oChartTypes.Scatter;
				break;
			}
			case AscDFH.historyitem_type_StockChart: {
				res = c_oChartTypes.Stock;
				break;
			}
			case AscDFH.historyitem_type_DoughnutChart: {
				res = c_oChartTypes.DoughnutChart;
				break;
			}
			case AscDFH.historyitem_type_RadarChart: {
				res = c_oChartTypes.Radar;
				break;
			}
			case AscDFH.historyitem_type_BubbleChart: {
				res = c_oChartTypes.BubbleChart;
				break;
			}
			case AscDFH.historyitem_type_SurfaceChart: {
				res = c_oChartTypes.Surface;
				break;
			}
		}
		return res;
	},

	getChartGrouping: function(chart) {
		var res = null;

		var grouping = chart.grouping;
		var typeChart = chart.getObjectType();

		if (typeChart ===  AscDFH.historyitem_type_LineChart || typeChart === AscDFH.historyitem_type_AreaChart) {
			res = (grouping === AscFormat.GROUPING_PERCENT_STACKED) ? "stackedPer" : (grouping === AscFormat.GROUPING_STACKED) ? "stacked" : "normal";
		} else if (this.nDimensionCount === 3 && grouping === AscFormat.BAR_GROUPING_STANDARD) {
			res = "standard";
		} else {
			res = (grouping === AscFormat.BAR_GROUPING_PERCENT_STACKED) ? "stackedPer" : (grouping === AscFormat.BAR_GROUPING_STACKED) ? "stacked" : "normal";
		}

		return res;
	},

	calculateSizePlotArea : function(chartSpace, bNotRecalculate)
	{
		if(!bNotRecalculate || undefined === this.calcProp.chartGutter) {
			this._calculateMarginsChart(chartSpace);
		}

		var widthCanvas = chartSpace.extX;
		var heightCanvas = chartSpace.extY;
		
		var w = widthCanvas - (this.calcProp.chartGutter._left + this.calcProp.chartGutter._right) / this.calcProp.pxToMM;
		var h = heightCanvas - (this.calcProp.chartGutter._top + this.calcProp.chartGutter._bottom) / this.calcProp.pxToMM;
		

        return {w: w , h: h , startX: this.calcProp.chartGutter._left / this.calcProp.pxToMM, startY: this.calcProp.chartGutter._top / this.calcProp.pxToMM};
	},

	drawPaths: function (paths, series, useNextPoint, bIsYVal) {

		var seria, brush, pen, numCache, point;
		var seriesPaths = paths.series;
		var pointDiff = useNextPoint ? 1 : 0;

		if(!seriesPaths) {
			return;
		}

		for (var i = 0; i < seriesPaths.length; i++) {

			if (!seriesPaths[i]) {
				continue;
			}

			seria = series[i];
			brush = seria.brush;
			pen = seria.pen;

			for (var j = 0; j < seriesPaths[i].length; j++) {

				if (bIsYVal) {
					numCache = this.getNumCache(seria.yVal);
				} else {
					numCache = this.getNumCache(seria.val);
				}

				if(numCache){
					point = numCache.pts[j + pointDiff];
					if (point && point.pen) {
						pen = point.pen;
					}
					if (point && point.brush) {
						brush = point.brush;
					}
				}
				if (seriesPaths[i][j]) {
					this.drawPath(seriesPaths[i][j], pen, brush);
				}
			}
		}
	},

	drawPathsPoints: function (paths, series, bIsYVal) {

		var seria, brush, pen, dataSeries, markerBrush, markerPen, numCache;

		if(!paths.series) {
			return;
		}

		for (var i = 0; i < paths.series.length; i++) {
			seria = series[i];
			brush = seria.brush;
			pen = seria.pen;

			if (bIsYVal) {
				numCache = this.getNumCache(seria.yVal);
			} else {
				numCache = this.getNumCache(seria.val);
			}

			dataSeries = paths.series[i];

			if (!dataSeries) {
				continue;
			}

			//draw point
			for (var k = 0; k < paths.points[i].length; k++) {
				var numPoint = numCache ? numCache.getPtByIndex(k) : null;
				if (numPoint) {
					markerBrush = numPoint.compiledMarker ? numPoint.compiledMarker.brush : null;
					markerPen = numPoint.compiledMarker ? numPoint.compiledMarker.pen : null;
				}

				//frame of point
				if (paths.points[i][0] && paths.points[i][0].framePaths) {
					this.drawPath(paths.points[i][k].framePaths, markerPen, markerBrush, false);
				}
				//point
				if (paths.points[i][k]) {
					this.drawPath(paths.points[i][k].path, markerPen, markerBrush, true);
				}
			}
		}
	},

	drawPathsByIdx: function (paths, series, useNextPoint, bIsYVal) {

		var seria, brush, pen, numCache, point;
		var seriesPaths = paths.series;

		if(!seriesPaths) {
			return;
		}

		for (var i = 0; i < seriesPaths.length; i++) {

			if (!seriesPaths[i]) {
				continue;
			}

			seria = series[i];
			brush = seria.brush;
			pen = seria.pen;

			for (var j = 0; j < seriesPaths[i].length; j++) {

				if (bIsYVal) {
					numCache = this.getNumCache(seria.yVal);
				} else {
					numCache = this.getNumCache(seria.val);
				}

				var idx = seriesPaths[i][j].idx;
				if(numCache){
					if(useNextPoint) {
						idx = seriesPaths[i][j + 1] ? seriesPaths[i][j + 1].idx : seriesPaths[i][j].idx;
						point = numCache.getPtByIndex(idx);
					} else {
						point = numCache.getPtByIndex(idx);
					}
				}

				if (point && point.pen) {
					pen = point.pen;
				}
				if (point && point.brush) {
					brush = point.brush;
				}

				if (seriesPaths[i][j]) {
					this.drawPath(seriesPaths[i][j].path, pen, brush);
				}
			}
		}
	},

	drawPath: function(path, pen, brush)
	{
		if(!AscFormat.isRealNumber(path)){
			return;
		}
		var oPath = this.cChartSpace.GetPath(path);
		if(!oPath)
			return;
		
		if(pen)
            oPath.stroke = true;

		var cGeometry = new CGeometry2();
		this.cShapeDrawer.Clear();

        cGeometry.AddPath(oPath);
		this.cShapeDrawer.fromShape2(new CColorObj(pen, brush, cGeometry) ,this.cShapeDrawer.Graphics, cGeometry);

		this.cShapeDrawer.draw(cGeometry);
	},
	
	//****functions for chart classes****
	calculatePoint: function(x, y, size, symbol)
	{
		size = size / 2.69;
		var halfSize = size / 2;
		var dashDotHeight = size / 5;
		var pathId = this.cChartSpace.AllocPath();
		var path  = this.cChartSpace.GetPath(pathId);
		var pathH = this.calcProp.pathH;
		var pathW = this.calcProp.pathW;

		var framePaths = null, framePathsId = null;
		
		var result;

		/*
		var AscFormat.SYMBOL_PICTURE = 5;*/
		
		path.moveTo(x * pathW, y * pathW);
		
		switch ( symbol )
		{
			case AscFormat.SYMBOL_DASH:
			{
				path.moveTo((x - halfSize) * pathW, (y - dashDotHeight/2) * pathW);
				path.lnTo((x + halfSize) * pathW, (y - dashDotHeight/2) * pathW);
				path.lnTo((x + halfSize) * pathW, (y + dashDotHeight/2) * pathW);
				path.lnTo((x - halfSize) * pathW, (y + dashDotHeight/2) * pathW);
				break;
			}
			case AscFormat.SYMBOL_DOT:
			{
				path.moveTo((x) * pathW, (y - dashDotHeight/2) * pathW);
				path.lnTo((x + halfSize) * pathW, (y - dashDotHeight/2) * pathW);
				path.lnTo((x + halfSize) * pathW, (y + dashDotHeight/2) * pathW);
				path.lnTo((x) * pathW, (y + dashDotHeight/2) * pathW);
				break;
			}
			
			case AscFormat.SYMBOL_PLUS:
			{
				path.moveTo(x * pathW, (y  + halfSize) * pathW);
				path.lnTo(x * pathW, (y  - halfSize) * pathW);
				path.moveTo((x - halfSize) * pathW, y * pathW);
				path.lnTo((x  + halfSize) * pathW, y * pathW);
				break;
			}
			
			case AscFormat.SYMBOL_CIRCLE:
			{
				path.moveTo((x + halfSize) * pathW, y * pathW);
				path.arcTo(halfSize * pathW, halfSize * pathW, 0, Math.PI * 2 * cToDeg);
				break;
			}
			
			case AscFormat.SYMBOL_STAR:
			{
				path.moveTo((x - halfSize) * pathW, (y  + halfSize) * pathW);
				path.lnTo((x + halfSize) * pathW, (y  - halfSize) * pathW);
				path.moveTo((x + halfSize) * pathW, (y  + halfSize) * pathW);
				path.lnTo((x  - halfSize) * pathW, (y  - halfSize) * pathW);
				path.moveTo(x * pathW, (y  + halfSize) * pathW);
				path.lnTo(x * pathW, (y  - halfSize) * pathW);
				break;
			}
			
			case AscFormat.SYMBOL_X:
			{
				path.moveTo((x - halfSize) * pathW, (y  + halfSize) * pathW);
				path.lnTo((x + halfSize) * pathW, (y  - halfSize) * pathW);
				path.moveTo((x + halfSize) * pathW, (y  + halfSize) * pathW);
				path.lnTo((x  - halfSize) * pathW, (y  - halfSize) * pathW);
				break;
			}
			
			case AscFormat.SYMBOL_TRIANGLE:
			{
				path.moveTo((x - size/Math.sqrt(3)) * pathW, (y  + size/3) * pathW);
				path.lnTo(x * pathW, (y  - (2/3)*size) * pathW);
				path.lnTo((x + size/Math.sqrt(3)) * pathW, (y  + size/3) * pathW);
				path.lnTo((x - size/Math.sqrt(3)) * pathW, (y  + size/3) * pathW);
				break;
			}
			
			case AscFormat.SYMBOL_SQUARE:
			{
				path.moveTo((x - halfSize) * pathW, (y + halfSize) * pathW);
				path.lnTo((x - halfSize) * pathW, (y - halfSize) * pathW);
				path.lnTo((x + halfSize) * pathW, (y - halfSize) * pathW);
				path.lnTo((x + halfSize) * pathW, (y + halfSize) * pathW);
				path.lnTo((x - halfSize) * pathW, (y + halfSize) * pathW);
				break;
			}
			
			case AscFormat.SYMBOL_DIAMOND:
			{
				path.moveTo((x - halfSize) * pathW, y * pathW);
				path.lnTo(x * pathW, (y  - halfSize) * pathW);
				path.lnTo((x + halfSize) * pathW, y * pathW);
				path.lnTo(x * pathW, (y  + halfSize) * pathW);
				path.lnTo((x - halfSize) * pathW, y  * pathW);
				break;
			}
		}
		
		if(symbol === "Plus" || symbol === "Star" || symbol === "X")
		{
			framePathsId = this.cChartSpace.AllocPath();
            framePaths = this.cChartSpace.GetPath(framePathsId);
			framePaths.moveTo((x - halfSize) * pathW, (y + halfSize) * pathW);
			framePaths.lnTo((x - halfSize) * pathW, (y - halfSize) * pathW);
			framePaths.lnTo((x + halfSize) * pathW, (y - halfSize) * pathW);
			framePaths.lnTo((x + halfSize) * pathW, (y + halfSize) * pathW);
			framePaths.lnTo((x - halfSize) * pathW, (y + halfSize) * pathW);
		}
		

		result = {framePaths: framePaths, path: pathId};
		
		return result;
	},

	getYPosition: function (val, axis) {
		var yPoints = axis.yPoints ? axis.yPoints : axis.xPoints;
		var isOx = axis.axPos === window['AscFormat'].AX_POS_T || axis.axPos === window['AscFormat'].AX_POS_B;
		var logBase = axis.scaling.logBase;
		if (logBase) {
			return this._getYPositionLogBase(val, yPoints, isOx, logBase);
		}

		//позиция в заисимости от положения точек на оси OY
		var result, resPos, resVal, diffVal;
		var plotArea = this.cChartSpace.chart.plotArea;

		if (!yPoints[1] && val === yPoints[0].val) {
			result = yPoints[0].pos;
		} else if (val < yPoints[0].val) {
			resPos = Math.abs(yPoints[1].pos - yPoints[0].pos);
			resVal = yPoints[1].val - yPoints[0].val;
			diffVal = Math.abs(yPoints[0].val) - Math.abs(val);
			if (isOx) {
				result = yPoints[0].pos - Math.abs((diffVal / resVal) * resPos);
			} else {
				result = yPoints[0].pos + Math.abs((diffVal / resVal) * resPos);
			}

			if (result > yPoints[yPoints.length - 1].pos || result < yPoints[0].pos) {
				result = yPoints[0].pos;
			}
		} else if (val > yPoints[yPoints.length - 1].val) {
			var test = yPoints[1] ? yPoints[1] : yPoints[0];
			resPos = Math.abs(test.pos - yPoints[0].pos);
			resVal = test.val - yPoints[0].val;
			diffVal = Math.abs(yPoints[yPoints.length - 1].val - val);

			if (axis.scaling.orientation === ORIENTATION_MIN_MAX) {
				if (isOx) {
					result = yPoints[yPoints.length - 1].pos + (diffVal / resVal) * resPos;
				} else {
					result = yPoints[yPoints.length - 1].pos - (diffVal / resVal) * resPos;
				}
			} else {
				if (isOx) {
					result = yPoints[yPoints.length - 1].pos - (diffVal / resVal) * resPos;
				} else {
					result = yPoints[yPoints.length - 1].pos + (diffVal / resVal) * resPos;
				}
			}

			if (result > yPoints[yPoints.length - 1].pos || result < yPoints[0].pos) {
				result = yPoints[yPoints.length - 1].pos;
			}
		} else {
			for (var s = 0; s < yPoints.length; s++) {
				if (val >= yPoints[s].val && val <= yPoints[s + 1].val) {
					resPos = Math.abs(yPoints[s + 1].pos - yPoints[s].pos);
					resVal = yPoints[s + 1].val - yPoints[s].val;

					if(resVal === 0) {
						resVal = 1;
					}

					var startPos = yPoints[s].pos;

					if (!isOx) {
						if (axis.scaling.orientation === ORIENTATION_MIN_MAX) {
							result = -(resPos / resVal) * (Math.abs(val - yPoints[s].val)) + startPos;
						} else {
							result = (resPos / resVal) * (Math.abs(val - yPoints[s].val)) + startPos;
						}
					} else {
						if (axis.scaling.orientation !== ORIENTATION_MIN_MAX) {
							result = -(resPos / resVal) * (Math.abs(val - yPoints[s].val)) + startPos;
						} else {
							result = (resPos / resVal) * (Math.abs(val - yPoints[s].val)) + startPos;
						}
					}
					break;
				}
			}
		}

		return result;
	},

	_getYPositionLogBase: function (val, yPoints, isOx, logBase) {
		if (val < 0) {
			return 0;
		}

		var logVal = Math.log(val) / Math.log(logBase);
		var result;

		var parseVal, maxVal, minVal, startPos = 0, diffPos;
		if (logVal < 0) {
			parseVal = logVal.toString().split(".");
			maxVal = Math.pow(logBase, parseVal[0]);
			minVal = Math.pow(logBase, parseFloat(parseVal[0]) - 1);
			for (var i = 0; i < yPoints.length; i++) {
				if (yPoints[i].val < maxVal && yPoints[i].val >= minVal) {
					startPos = yPoints[i + 1].pos;
					diffPos = yPoints[i].pos - yPoints[i + 1].pos;
					break;
				}
			}
			result = startPos + parseFloat("0." + parseVal[1]) * diffPos;
		} else {
			parseVal = logVal.toString().split(".");
			minVal = Math.pow(logBase, parseVal[0]);
			maxVal = Math.pow(logBase, parseFloat(parseVal[0]) + 1);
			for (var i = 0; i < yPoints.length; i++) {
				if (yPoints[i].val < maxVal && yPoints[i].val >= minVal) {
					startPos = yPoints[i].pos;
					diffPos = yPoints[i].pos - yPoints[i + 1].pos;
					break;
				}
			}
			result = startPos - parseFloat("0." + parseVal[1]) * diffPos;
		}

		return result;
	},
	
	getLogarithmicValue: function(val, logBase)
	{
		if(val < 0)
			return 0;
			
		var logVal = Math.log(val) / Math.log(logBase);
		
		var temp = 0;
		if(logVal > 0)
		{
			for(var l = 0; l < logVal; l++)
			{
				if(l !== 0)
					temp += Math.pow(logBase, l);
				if(l + 1 > logVal)
				{
					temp += (logVal - l) * Math.pow(logBase, l + 1);
					break;
				}	
			}
		}
		else
		{
			var parseTemp = logVal.toString().split(".");
			temp = Math.pow(logBase, parseFloat(parseTemp[0]));
			
			temp =  temp - temp * parseFloat("0." + parseTemp[1]);
		}
		
		return temp;
	},
	
	
	
	//****for 3D****
	_calaculate3DProperties: function(chartSpace)
	{
		var widthCanvas = this.calcProp.widthCanvas;
		var heightCanvas = this.calcProp.heightCanvas;
		var left = this.calcProp.chartGutter._left;
		var right = this.calcProp.chartGutter._right;
		var bottom = this.calcProp.chartGutter._bottom;
		var top = this.calcProp.chartGutter._top;
		
		standartMarginForCharts = 17;
		
		
		this.processor3D = new AscFormat.Processor3D(widthCanvas, heightCanvas, left, right, bottom, top, chartSpace, this);
		this.processor3D.calaculate3DProperties();
		this.processor3D.correctPointsPosition(chartSpace);
	},
	
	_convertAndTurnPoint: function(x, y, z, isNScale, isNRotate, isNProject)
	{
		return this.processor3D.convertAndTurnPoint(x, y, z, isNScale, isNRotate, isNProject);
	},

	//position of catAx labels(left or right) - returns false(left of axis)/true(right of axis) or null(standard position)
	calculatePositionLabelsCatAxFromAngle: function (chartSpace) {
		var res = null;
		var oView3D = chartSpace.chart.getView3d();
		var angleOy = oView3D && oView3D.rotY ? (-oView3D.rotY / 360) * (Math.PI * 2) : 0;
		if (oView3D && !oView3D.getRAngAx() && angleOy !== 0) {
			angleOy = Math.abs(angleOy);
			res = angleOy >= Math.PI / 2 && angleOy < 3 * Math.PI / 2;
		}

		return res;
	},
	
	
	//****accessory functions****
	_getSumArray: function (arr, isAbs)
    {
        if (typeof(arr) === 'number') {
            return arr;
        }
		else if(typeof(arr) === 'string'){
			return parseFloat(arr);
		}

        var i, sum;
        for(i = 0,sum = 0; i < arr.length; i++)
		{
			if(typeof(arr[i]) === 'object' && arr[i].val != null && arr[i].val != undefined)
				sum += parseFloat(isAbs ? Math.abs(arr[i].val) : arr[i].val);
			else if(arr[i])
				sum += isAbs ? Math.abs(arr[i]) : arr[i];
		}
        return sum;
    },
	
	_getMaxMinValueArray: function(array)
	{
		var max = 0, min = 0;
		for(var i = 0; i < array.length; i++)
		{
			for(var j = 0; j < array[i].length; j++)
			{
				if(i === 0 && j === 0)
				{
					min =  array[i][j];
					max =  array[i][j];
				}
				
				if(array[i][j] > max)
					max = array[i][j];
					
				if(array[i][j] < min)
					min = array[i][j];
			}
		}
		return {max: max, min: min};
	},
	
	_findPrevValue: function(originalData, num, max) {
		var summ = 0;
		for (var i = 0; i <= max; i++) {
			if (originalData[num][max] >= 0) {
				if (originalData[num][i] >= 0)
					summ += originalData[num][i];
			}

			else {
				if (originalData[num][i] < 0)
					summ += originalData[num][i];
			}
		}
		return summ;
	},
	
	_getFirstDegree: function(val)
	{
		var secPart = val.toString().split('.');
		var numPow = 1, tempMax, expNum;
		
		if(secPart[1] && secPart[1].toString().indexOf('e+') != -1 && secPart[0] && secPart[0].toString().length == 1)
		{
			expNum = secPart[1].toString().split('e+');
			numPow = Math.pow(10, expNum[1]);
		}
		else if(secPart[1] && secPart[1].toString().indexOf('e-') != -1 && secPart[0] && secPart[0].toString().length == 1)
		{
			expNum = secPart[1].toString().split('e');
			numPow = Math.pow(10, expNum[1]);
		}
		else if(0 != secPart[0])
			numPow = Math.pow(10, secPart[0].toString().length - 1);
		else if(0 == secPart[0] && secPart[1] != undefined)
		{
			tempMax = val;
			var num = 0;
			while(1 > tempMax)
			{
				tempMax = tempMax * 10;
                num--;
			}
            numPow = Math.pow(10, num);
			val = tempMax;
		}

		if(tempMax == undefined)
			val = val / numPow;
		
		return {val: val, numPow: numPow};
	},
	
	getIdxPoint: function(seria, val, bXVal)
	{
		var seriaVal;
		if(bXVal) {
			seriaVal = seria.val ? seria.val :  seria.xVal;
		} else {
			seriaVal = seria.val ? seria.val :  seria.yVal;
		}
		
		if(!seriaVal)
			return null;

		//todo use getNumCache
		var pts = seriaVal.numRef &&  seriaVal.numRef.numCache ? seriaVal.numRef.numCache.pts : seriaVal.numLit ? seriaVal.numLit.pts : null;
		
		if(pts == null)
			return null;
		
		for(var p = 0; p < pts.length; p++)
		{
			if(pts[p].idx === val)
				return pts[p];
		}
	},
	
	getPointByIndex: function(seria, index, bXVal)
	{
		var seriaVal;
		if(bXVal) {
			seriaVal = seria.val ? seria.val :  seria.xVal;
		} else {
			seriaVal = seria.val ? seria.val :  seria.yVal;
		}

		if(!seriaVal)
			return null;

		//todo use getNumCache
		var pts = seriaVal.numRef &&  seriaVal.numRef.numCache ? seriaVal.numRef.numCache.pts : seriaVal.numLit ? seriaVal.numLit.pts : null;

		if(pts == null)
			return null;

		return pts[index];
	},

	getPtCount: function(series)
	{
		var numCache;
		for(var i = 0; i < series.length; i++)
		{
			//todo use getNumCache
			numCache = series[i].val && series[i].val.numRef ? series[i].val.numRef.numCache : series[i].val.numLit;
			if(numCache && numCache.ptCount)
				return numCache.ptCount;
		}
		
		return 0;
	},
	
	_roundValues: function(values)
	{
		//ToDo пересмотреть округление. на числа << 0 могут быть проблемы!
		var kF = 1000000000;
		if(values.length)
		{
			for(var i = 0; i < values.length; i++)
			{
				values[i] = Math.round(values[i] * kF) / kF;
			}
		}
		
		return values;
	},
	
	
	//***spline functions***
	//TODO пока включаю calculate_Bezier. проверить корретность calculate_Bezier2!
	calculate_Bezier2: function(x, y, x1, y1, x2, y2, x3, y3)
	{
		var pts = [], bz = [];   

		pts[0] = {x: x, y: y};
		pts[1] = {x: x1, y: y1};
		pts[2] = {x: x2, y: y2};
		pts[3] = {x: x3, y: y3};
		
		var d01 = this.XYZDist(pts[0], pts[1]);
		var d12 = this.XYZDist(pts[1], pts[2]);
		var d23 = this.XYZDist(pts[2], pts[3]);
		var d02 = this.XYZDist(pts[0], pts[2]);
		var d13 = this.XYZDist(pts[1], pts[3]);
		
		//start point
		bz[0] = pts[1];
		
		
		//control points
		if ((d02 / 6 < d12 / 2) && (d13 / 6 < d12 / 2))
		{
			var f;
			if (x !== x1)
				f = 1 / 6;
			else
				f = 1 / 3;
				
			bz[1] = this.XYZAdd(pts[1], this.XYZMult(this.XYZSub(pts[2], pts[0]), f));
			
			if (x2 !== x3)
				f = 1 / 6;
			else
				f = 1 / 3;

			bz[2] = this.XYZAdd(pts[2], this.XYZMult(this.XYZSub(pts[1], pts[3]), f))
		}  
		else if ((d02 / 6 >= d12 / 2) && (d13 / 6 >= d12 / 2)) 
		{
			bz[1] = this.XYZAdd(pts[1], this.XYZMult(this.XYZSub(pts[2], pts[0]), d12 / 2 / d02));
			bz[2] = this.XYZAdd(pts[2], this.XYZMult(this.XYZSub(pts[1], pts[3]), d12 / 2 / d13));
		}
		else if((d02 / 6 >= d12 / 2))
		{
			bz[1] = this.XYZAdd(pts[1], this.XYZMult(this.XYZSub(pts[2], pts[0]), d12 / 2 / d02));
			bz[2] = this.XYZAdd(pts[2], this.XYZMult(this.XYZSub(pts[1], pts[3]), d12 / 2 / d13 * (d13 / d02)));
		}
		else
		{
			bz[1] = this.XYZAdd(pts[1], this.XYZMult(this.XYZSub(pts[2], pts[0]), d12 / 2 / d02 * (d02 / d13)));
			bz[2] = this.XYZAdd(pts[2], this.XYZMult(this.XYZSub(pts[1], pts[3]), d12 / 2 / d13));
		}
		
		//end point
		bz[3] = pts[2];
		
		return bz;
	},

	//***spline functions***
	calculate_Bezier: function(x, y, x1, y1, x2, y2, x3, y3, t)
	{
		var pts = [], bz = [];

		pts[0] = {x: x, y: y};
		pts[1] = {x: x1, y: y1};
		pts[2] = {x: x2, y: y2};
		pts[3] = {x: x3, y: y3};

		var d01 = this.XYZDist(pts[0], pts[1]);
		var d12 = this.XYZDist(pts[1], pts[2]);
		var d23 = this.XYZDist(pts[2], pts[3]);
		var d02 = this.XYZDist(pts[0], pts[2]);
		var d13 = this.XYZDist(pts[1], pts[3]);

		bz[0] = pts[1];

		if ((d02 / 6 < d12 / 2) && (d13 / 6 < d12 / 2))
		{
			var f;
			if (x !== x1)
				f = 1 / 6;
			else
				f = 1 / 3;

			bz[1] = this.XYZAdd(pts[1], this.XYZMult(this.XYZSub(pts[2], pts[0]), f));

			if (x2 !== x3)
				f = 1 / 6;
			else
				f = 1 / 3;

			bz[2] = this.XYZAdd(pts[2], this.XYZMult(this.XYZSub(pts[1], pts[3]), f))
		}

		else if ((d02 / 6 >= d12 / 2) && (d13 / 6 >= d12 / 2))
		{
			bz[1] = this.XYZAdd(pts[1], this.XYZMult(this.XYZSub(pts[2], pts[0]), d12 / 2 / d02))
			bz[2] = this.XYZAdd(pts[2], this.XYZMult(this.XYZSub(pts[1], pts[3]), d12 / 2 / d13))
		}
		else if((d02 / 6 >= d12 / 2))
		{
			bz[1] = this.XYZAdd(pts[1], this.XYZMult(this.XYZSub(pts[2], pts[0]), d12 / 2 / d02))
			bz[2] = this.XYZAdd(pts[2], this.XYZMult(this.XYZSub(pts[1], pts[3]), d12 / 2 / d13 * (d13 / d02)))
		}
		else
		{
			bz[1] = this.XYZAdd(pts[1], this.XYZMult(this.XYZSub(pts[2], pts[0]), d12 / 2 / d02 * (d02 / d13)))
			bz[2] = this.XYZAdd(pts[2], this.XYZMult(this.XYZSub(pts[1], pts[3]), d12 / 2 / d13))
		}

		bz[3] = pts[2];

		var pt = this._bezier4(bz[0], bz[1], bz[2], bz[3], t);

		return [pt.x, pt.y];
	},

	_bezier4: function(p1, p2, p3, p4, t)
	{
		var mum1, mum13, t3, mum12, t2;
		var p = {};

		mum1 = 1 - t;
		mum13 = mum1 * mum1 * mum1;
		mum12 = mum1 * mum1;
		t2 = t * t;
		t3 = t * t * t;

		p.x = mum13 * p1.x + 3 * t * mum12 * p2.x + 3 * t2 * mum1 * p3.x + t3 * p4.x;
		p.y = mum13 * p1.y + 3 * t * mum12 * p2.y + 3 * t2 * mum1 * p3.y + t3 * p4.y;

		return p;
	},

	XYZAdd: function(a, b)
	{
		return {x: a.x + b.x, y: a.y + b.y};
	},

	XYZSub: function(a, b)
	{
		return {x: a.x - b.x, y: a.y - b.y};
	},

	XYZMult: function(a, b)
	{
		return {x: a.x * b, y: a.y * b};
	},

	XYZDist: function(a, b)
	{
		return Math.pow((Math.pow((a.x - b.x), 2) + Math.pow((a.y - b.y), 2)), 0.5);
	},
	
	calculateCountSeries: function(chart)
	{
		var series = chart.series;
		var typeChart = chart.getObjectType();
		var counter = 0, numCache, seriaVal, ptCount;
		for(var i = 0; i < series.length; i++)
		{
			seriaVal = series[i].val ? series[i].val : series[i].yVal;
			numCache = this.getNumCache(seriaVal);
			if(!series[i].isHidden)
			{
				if (AscDFH.historyitem_type_PieChart === typeChart) {
					ptCount = 1;
				} else {
					if (numCache && (ptCount === undefined || ptCount < numCache.ptCount)) {
						ptCount = numCache.ptCount;
					}
				}

				counter++;
			}
			else if(3 === this.nDimensionCount)
			{
				counter++;
			}
		}
		
		if(AscDFH.historyitem_type_PieChart === typeChart)
		{
			counter = 1;
		}
		
		return {series: counter, points: ptCount};
	},
	
	//вспомогательные функции работающие с тремя координатами
	//получаем к-ты уравнения прямой по 2 точкам
	getLineEquation: function(point1, point2)
	{
		var x0 = point1.x, y0 = point1.y, z0 = point1.z;
		var x1 = point2.x, y1 = point2.y, z1 = point2.z;
		
		
		/*x - x0 	 =  	y - y0 	 =  	z - z0
		x1 - x0 			y1 - y0 		z1 - z0
		
			l 					m 				n
		*/
		
		var l = x1 - x0;
		var m = y1 - y0;
		var n = z1 - z0;
		
		//check line
		/*var x123 = (point1.x - x0) / (x1 - x0);
		var y123 = (point1.y - y0) / (y1 - y0);
		var z123 = (point1.z - z0) / (z1 - z0);
		
		var x321 = (point2.x - x0) / (x1 - x0);
		var y321 = (point2.y - y0) / (y1 - y0);
		var z321 = (point2.z - z0) / (z1 - z0);*/
		
		return {l: l, m: m, n: n, x1: x0, y1: y0, z1: z0};
	},
	
	getLineEquation2d: function(point1, point2)
	{
		var x1 = point1.x, y1 = point1.y;
		var x2 = point2.x, y2 = point2.y;
		
		//y = kx + b
		var k = (y2 - y1) / (x2 - x1);
		var b = y1 - k * x1;
		
		return {k: k, b: b};
	},
	
	isIntersectionLineAndLine: function(equation1, equation2)
	{
		var xo = equation1.x1;
		var yo = equation1.y1;
		var zo = equation1.z1;
		var p = equation1.l;
		var q = equation1.m;
		var r = equation1.n;
		
		var x1 = equation2.x1;
		var y1 = equation2.y1;
		var z1 = equation2.z1;
		var p1 = equation2.l;
		var q1 = equation2.m;
		var r1 = equation2.n;
		
		var x = (xo*q*p1-x1*q1*p-yo*p*p1+y1*p*p1) / (q*p1-q1*p);
		var y = (yo*p*q1-y1*p1*q-xo*q*q1+x1*q*q1) / (p*q1-p1*q);
		var z = (zo*q*r1-z1*q1*r-yo*r*r1+y1*r*r1) / (q*r1-q1*r);
		
		return {x: x, y: y, z: z};
	},
	
	//поиск точки пересечения плоскости и прямой
	isIntersectionPlainAndLine: function(plainEquation, lineEquation)
	{
		var A = plainEquation.a;
		var B = plainEquation.b;
		var C = plainEquation.c;
		var D = plainEquation.d;
		
		var l = lineEquation.l;
		var m = lineEquation.m;
		var n = lineEquation.n;
		var x1 = lineEquation.x1;
		var y1 = lineEquation.y1;
		var z1 = lineEquation.z1;
		
		
		//x - x1		y - y1		z - z1
		//			=			=			t
		//  l			  m		 	  n
		
		/*x = t * l + x1
		y = t * m + y1
		z = t * n + z1*/
		
		
		/*A * x + B * y + C * z + D = 0
		
		A * (t * l + x1) + B * (t * m + y1) + C * (t * n + z1) + D = 0;
		
		A * t * l + A * x1 + B * t * m + B * y1 + C * t * n + C * z1 + D
		
		A * t * l + B * t * m + C * t * n       + A * x1 + B * y1 + C * z1 + D*/
		
		var t = -(A * x1 + B * y1 + C * z1 + D) / (A * l + B * m + C * n); 
		
		var x = t * l + x1;
		var y = t * m + y1;
		var z = t * n + z1;
		
		return {x: x, y: y, z: z};
	},
	
	isIntersectionPlainAndLineSegment: function(plainEquation, point1, point2, projPoint1, projPoint2)
	{
		var res = null;
		var lineEquation = this.getLineEquation(point1, point2);
		
		var intersection = this.isIntersectionPlainAndLine(plainEquation, lineEquation);
		var convertResult = this._convertAndTurnPoint(intersection.x, intersection.y, intersection.z);
		var isBetweenX = (convertResult.x >= projPoint1.x && convertResult.x <= projPoint2.x) || (convertResult.x <= projPoint1.x && convertResult.x >= projPoint2.x);
		var isBetweenY = (convertResult.y >= projPoint1.y && convertResult.y <= projPoint2.y) || (convertResult.y <= projPoint1.y && convertResult.y >= projPoint2.y);
		
		//принадлежит ли даная точка отрезку
		if(isBetweenX && isBetweenY)
		{
			var vectorMultiplication = ((convertResult.x - projPoint1.x) * (projPoint2.y - projPoint1.y)) - ((convertResult.y - projPoint1.y) * (projPoint2.x - projPoint1.x));
			if(Math.round(vectorMultiplication) === 0)
			{
				res = convertResult;
			}
		}
		
		return res;
	},
	
	isPoint2DLieOnLine: function(lineEquation, point)
	{
		return Math.round(point.y * 1000) / 1000 === Math.round((lineEquation.k * point.x + lineEquation.b) * 1000) / 1000;
	},
	
	isPointLieIntoPlane: function(planeEquation, point)
	{
		var resEquation = planeEquation.a * point.x + planeEquation.b * point.y + planeEquation.c * point.z + planeEquation.d;
		return Math.round(resEquation) === 0;
	},
	
	isPointsLieIntoOnePlane2: function(point1, point2, point3, point4)
	{
		var bRes = false;
		
		var plain1 = this.getPlainEquation(point1, point2, point3);
		var plain2 = this.getPlainEquation(point3, point4, point1);
		
		//todo пересмотреть округление
		if(Math.round(plain1.a) === Math.round(plain2.a) && Math.round(plain1.b) === Math.round(plain2.b) && Math.round(plain1.c) === Math.round(plain2.c) && Math.round(plain1.d) === Math.round(plain2.d))
		{
			bRes = true;
		}
		
		return bRes;
	},
	
	isPointsLieIntoOnePlane: function(point1, point2, point3, point4)
	{
		var bRes = false;
		
		var plain1 = this.getPlainEquation(point1, point2, point3);
		
		if(this.isPointLieIntoPlane(plain1, point4))
		{
			bRes = true;
		}
		
		return bRes;
	},
	
	isPointsLieIntoOnePlane3: function(point1, point2, point3, point4)
	{
		/*var vector1 = Math.sqrt(Math.pow(point4.x - point1.x, 2) + Math.pow(point4.y - point1.y, 2) + Math.pow(point4.z - point1.z, 2));//DA
		var vector2 = Math.sqrt(Math.pow(point4.x - point2.x, 2) + Math.pow(point4.y - point2.y, 2) + Math.pow(point4.z - point2.z, 2));//DB
		var vector2 = Math.sqrt(Math.pow(point4.x - point3.x, 2) + Math.pow(point4.y - point3.y, 2) + Math.pow(point4.z - point3.z, 2));//DC*/
		
		var vector1 = {x: point4.x - point1.x, y: point4.y - point1.y, z: point4.z - point1.z};//DA
		var vector2 = {x: point4.x - point2.x, y: point4.y - point2.y, z: point4.z - point2.z};//DB
		var vector3 = {x: point4.x - point3.x, y: point4.y - point3.y, z: point4.z - point3.z};//DC
		
		var a1 = vector1.x;
		var b1 = vector1.y;
		var c1 = vector1.z;
		var a2 = vector2.x;
		var b2 = vector2.y;
		var c2 = vector2.z;
		var a3 = vector3.x;
		var b3 = vector3.y;
		var c3 = vector3.z;
		
		var res = a1 * b2 * c3 + a3 * b1 * c2 + a2 * b3 * c1 - a3 * b2 * c1 - a1 * b3 * c2 - a2 * b1 * c3;
		
		return res;
	},
	
	//получаем площадь произвольного выпуклого четырехугольника
	getAreaQuadrilateral: function(point0, point1, point2, point3)
	{
		//длины сторон
		var a = Math.sqrt(Math.pow(point3.x - point0.x, 2) + Math.pow(point3.y - point0.y, 2));
		var b = Math.sqrt(Math.pow(point1.x - point0.x, 2) + Math.pow(point1.y - point0.y, 2));
		var c = Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));
		var d = Math.sqrt(Math.pow(point3.x - point2.x, 2) + Math.pow(point3.y - point2.y, 2));
		
		//длины диагоналей
		var e = Math.sqrt(Math.pow(point3.x - point1.x, 2) + Math.pow(point3.y - point1.y, 2));
		var f = Math.sqrt(Math.pow(point0.x - point2.x, 2) + Math.pow(point0.y - point2.y, 2));
		
		//полупериметр
		var p = (a + b + c + d) / 2;
		
		
		var res = Math.sqrt((p - a) * (p - b) * (p - c) * (p - d) + (1/4) * ((e * f + a * c + b * d) * (e * f - a * c - b * d)));
		
		return res;
	},
	
	//получаем площадь произвольного трехугольника
	getAreaTriangle: function(point0, point1, point2)
	{
		//длины сторон
		var a = Math.sqrt(Math.pow(point1.x - point0.x, 2) + Math.pow(point1.y - point0.y, 2));
		var b = Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));
		var c = Math.sqrt(Math.pow(point2.x - point0.x, 2) + Math.pow(point2.y - point0.y, 2));
		
		//полупериметр
		var p = (a + b + c ) / 2;

		return Math.sqrt(p * (p - a) * (p - b) * (p - c));
	},
	
	//из массива точек получаем минимальные/максимальные x,y,z
	getMinMaxPoints: function(points)
	{
		var minX, maxX, minY, maxY, minZ, maxZ;
		
		for(var n = 0; n < points.length; n++)
		{
			if(0 === n)
			{
				minX = points[0].x;
				maxX = points[0].x;
				minY = points[0].y;
				maxY = points[0].y;
				minZ = points[0].z;
				maxZ = points[0].z;
			}
			else
			{
				if(points[n].x < minX)
				{
					minX = points[n].x;
				}
				
				if(points[n].x > maxX)
				{
					maxX = points[n].x;
				}
				
				if(points[n].y < minY)
				{
					minY = points[n].y;
				}
				
				if(points[n].y > maxY)
				{
					maxY = points[n].y;
				}
				
				if(points[n].z < minZ)
				{
					minZ = points[n].z;
				}
				
				if(points[n].z > maxZ)
				{
					maxZ = points[n].z;
				}
			}
		}
		
		return {minX: minX, maxX: maxX, minY : minY, maxY: maxY, minZ: minZ, maxZ: maxZ};
	},
	
	//TODO временная функция для теста результата значений
	getPlainEquation3: function(point1, point2, point3)
	{
		var a1 = point1.x, b1 = point1.y, c1 = point1.z, a2 = point2.x, b2 = point2.y, c2 = point2.z, a3 = point3.x, b3 = point3.y, c3 = point3.z;
		
		var subMatrix = function(oldmat, row, col) 
		{
			var i;
			var j;
			var m = 0;
			var k = 0;
			var len = oldmat.length;
			var retmat = [];

			if ((len <= row) || (len <= col)) return 0;

			for (j = 0; j < len; j++) {
				if (j !== row) {
					retmat[k] = [];
					for (i = 0; i < len; i++) {
						if (i !== col) {
							retmat[k][m] = oldmat[j][i];
							m++;
						}
					}
					k++;
				}
				m = 0;
			}
			return retmat;
		};
		
		var determinant = function(mat) 
		{
			var i;
			var tmpVal = 0;
			var row = mat.length;
			var newDet = [];
			newDet[0] = [];

			switch (row) {
				case 1:
					return mat[0][0];
				case 2:
					return (mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0]);
				default:
					for (i = 0; i < row; i++) {
						if (mat[0][i] === 0) i++;
						if (i < row) {
							newDet = subMatrix(mat, 0, i);
							if (!isNaN(mat[0][i]))
								tmpVal += parseFloat(mat[0][i]) * Math.pow(-1, i) * determinant(newDet);
						}
					}
					return tmpVal;
			}
		};
		
		var replaceCol = function(mat, col, vec) 
		{
			var i = 0;
			var j = 0;
			var tmp = [];

			for (i = 0; i < mat.length; i++) {
				tmp[i] = [];

				for (j = 0; j < mat.length; j++) {
					if (col === j)
						tmp[i][col] = vec[i];
					else
						tmp[i][j] = mat[i][j]; 

				}
			}
			return tmp;
		};

		
		var mat = [];
		mat[0] = []; mat[1] = []; mat[2] = [];
		mat[0][0] = a1; mat[0][1] = b1; mat[0][2] = c1;
		mat[1][0] = a2; mat[1][1] = b2; mat[1][2] = c2;
		mat[2][0] = a3; mat[2][1] = b3; mat[2][2] = c3;

		var det = determinant(mat);
		
		var vec = [-1, -1, -1];
		var factor;

		var a = determinant(replaceCol(mat, 0, vec));
		if (a < 0) 
		{
			factor = -1;
		}
		else 
		{
			factor = 1;
		}
		a *= factor;
		
		var b = determinant(replaceCol(mat, 1, vec)) * factor;
		var c = determinant(replaceCol(mat, 2, vec)) * factor;
		var d = det * factor;

		return {a: a, b: b, c: c, d: d};
	},
	
	//TODO если будет проблема при отрисовке граней(перекрытие друг другом), вернуть протестированную функцию  - getPlainEquation3
	getPlainEquation: function(point1, point2, point3)
	{
		var x1 = point1.x, y1 = point1.y, z1 = point1.z;
		var x2 = point2.x, y2 = point2.y, z2 = point2.z;
		var x3 = point3.x, y3 = point3.y, z3 = point3.z;
		
		var a = x2 - x1;
		var b = y2 - y1;
		var c = z2 - z1;
		var d = x3 - x1;
		var e = y3 - y1;
		var f = z3 - z1;
		
		var xK = b*f - e*c;
		var yK = -(a*f - d*c);
		var zK = a*e - d*b;
		
		var a1 = -xK;
		var b1 = -yK;
		var c1 = -zK;
		var d1 = -(-y1 * yK - x1*xK - z1 * zK);
		
		return {a: a1, b: b1, c: c1, d: d1};
	},
	
	//уравнение плоскости
	getPlainEquation2: function(point1, point2, point3)
	{
		var x1 = point1.x, y1 = point1.y, z1 = point1.z;
		var x2 = point2.x, y2 = point2.y, z2 = point2.z;
		var x3 = point3.x, y3 = point3.y, z3 = point3.z;
		
		var x21 = x2 - x1;
		var y21 = y2 - y1;
		var z21 = z2 - z1;
		
		var x31 = x3 - x1;
		var y31 = y3 - y1;
		var z31 = z3 - z1;
			
		//(x - x1)*(y21 * z31 - x21 * y31) - (y - y1)*(x21 * z31 - z21 * x31) + (z - z1)(x21 * y31 - y21 * x31) 
		
		var tempA = y21 * z31 - z21 * y31;
		
		var tempB = x21 * z31 - z21 * x31;
		
		var tempC = x21 * y31 - y21 * x31;
		
		//(x - x1)*(tempA) - (y - y1)*(tempB) + (z - z1)(tempC)
		
		//x * tempA - x1 * tempA - y * tempB + y1 * tempB + z * tempC - z1 * tempC
		
		var a = tempA;
		var b = tempB;
		var c = tempC;
		var d =  y1 * tempB - x1 * tempA - z1 * tempC;
			
		return {a: a, b: b, c: c, d: d};
	},


	//******calculate graphic objects for 3d*******
	calculateRect3D : function(points, val, isNotDrawDownVerge, isNotOnlyFrontFaces)
	{
		var res;

		var point1 = points[0];
		var point2 = points[1];
		var point3 = points[2];
		var point4 = points[3];
		var point5 = points[4];
		var point6 = points[5];
		var point7 = points[6];
		var point8 = points[7];

		var frontPaths = [];
		var darkPaths = [];

		var addPathToArr = function(isFront, face, index)
		{
			frontPaths[index] = null;
			darkPaths[index] = null;

			if(isFront)
			{
				frontPaths[index] = face;
			}
			else
			{
				darkPaths[index] = face;
			}
		};

		var face;
		//front
		face = this._calculatePathFace(point1, point5, point8, point4, true);
		addPathToArr(this._isVisibleVerge3D(point5, point1, point4, val), face, 0);

		//down
		if(val === 0 && this.calcProp.type === c_oChartTypes.Bar)
		{
			face = this._calculatePathFace(point1, point2, point3, point4, true);
			addPathToArr(true, face, 1);
		}
		else
		{
			face = this._calculatePathFace(point1, point2, point3, point4, true);
			addPathToArr(this._isVisibleVerge3D(point4, point1, point2, val), face, 1);
		}


		//left
		if(val === 0 && this.calcProp.type === c_oChartTypes.HBar)
		{
			face = this._calculatePathFace(point1, point5, point6, point2, true);
			addPathToArr(!isNotDrawDownVerge , face, 2);
		}
		else
		{
			face = this._calculatePathFace(point1, point5, point6, point2, true);
			addPathToArr((!isNotDrawDownVerge && this._isVisibleVerge3D(point2, point1, point5, val)), face, 2);
		}

		//right
		if(val === 0 && this.calcProp.type === c_oChartTypes.HBar)
		{
			face = this._calculatePathFace(point4, point8, point7, point3, true);
			addPathToArr(true, face, 3);
		}
		else
		{
			face = this._calculatePathFace(point4, point8, point7, point3, true);
			addPathToArr(this._isVisibleVerge3D(point8, point4, point3, val), face, 3);
		}

		//up
		if(val === 0 && this.calcProp.type === c_oChartTypes.Bar)
		{
			face = this._calculatePathFace(point5, point6, point7, point8, true);
			addPathToArr(true, face, 4);
		}
		else
		{
			face = this._calculatePathFace(point5, point6, point7, point8, true);
			addPathToArr(this._isVisibleVerge3D(point6, point5, point8, val), face, 4);
		}

		//unfront
		face = this._calculatePathFace(point2, point6, point7, point3, true);
		addPathToArr(this._isVisibleVerge3D(point3, point2, point6, val), face, 5);

		if(!isNotOnlyFrontFaces)
		{
			res = frontPaths;
		}
		else
		{
			res = {frontPaths: frontPaths, darkPaths: darkPaths};
		}

		return res;
	},

	_calculatePathFace: function(point1, point2, point3, point4, isConvertPxToMM)
	{
		var pxToMm = 1;
		if(isConvertPxToMM)
		{
			pxToMm = this.calcProp.pxToMM;
		} 

		var pathId = this.cChartSpace.AllocPath();
		var path  = this.cChartSpace.GetPath(pathId);
		
		var pathH = this.calcProp.pathH;
		var pathW = this.calcProp.pathW;

		path.moveTo(point1.x / pxToMm * pathW, point1.y / pxToMm * pathH);
		path.lnTo(point2.x / pxToMm * pathW, point2.y / pxToMm * pathH);
		path.lnTo(point3.x / pxToMm * pathW, point3.y / pxToMm * pathH);
		path.lnTo(point4.x / pxToMm * pathW, point4.y / pxToMm * pathH);
		path.lnTo(point1.x / pxToMm * pathW, point1.y / pxToMm * pathH);

		return pathId;
	},
	
	calculatePathFacesArray: function(faceArr, isConvertPxToMM)
	{
		var pxToMm = 1;
		if(isConvertPxToMM)
		{
			pxToMm = this.calcProp.pxToMM;
		} 

		var pathId = this.cChartSpace.AllocPath();
		var path  = this.cChartSpace.GetPath(pathId);
		
		var pathH = this.calcProp.pathH;
		var pathW = this.calcProp.pathW;
		
		var firstPoint = null;
		for(var i = 0; i < faceArr.length; i++)
		{
			if(faceArr[i] && faceArr[i].point)
			{
				if(null === firstPoint)
				{
					path.moveTo(faceArr[i].point.x / pxToMm * pathW, faceArr[i].point.y / pxToMm * pathH);
					firstPoint = faceArr[i].point;
				}
				else
				{
					path.lnTo(faceArr[i].point.x / pxToMm * pathW, faceArr[i].point.y / pxToMm * pathH);
				}
			}
		}
		
		if(null !== firstPoint)
		{
			path.lnTo(firstPoint.x / pxToMm * pathW, firstPoint.y / pxToMm * pathH);
		}

		return pathId;
	},
	
	_isVisibleVerge3D: function(k, n, m, val)
	{
		//roberts method - calculate normal
		var aX = n.x * m.y - m.x * n.y;
		var bY = - (k.x * m.y - m.x * k.y);
		var cZ = k.x * n.y - n.x * k.y;
		var visible = aX + bY + cZ;
		
		var result;
		if(this.calcProp.type === c_oChartTypes.Bar)
		{
			result = val > 0 && visible < 0 || val < 0 && visible > 0;
			if(!(this.calcProp.subType === "stacked") && !(this.calcProp.subType === "stackedPer") && this.cChartSpace.chart.plotArea.valAx.scaling.orientation !== ORIENTATION_MIN_MAX)
				result = !result;
		}
		else if(this.calcProp.type === c_oChartTypes.Line)
		{
			result = visible < 0;
		}
		else if(this.calcProp.type === c_oChartTypes.HBar)
		{
			result = val < 0 && visible < 0 || val > 0 && visible > 0;
			
			if(!(this.calcProp.subType === "stacked") && !(this.calcProp.subType === "stackedPer") && this.cChartSpace.chart.plotArea.valAx.scaling.orientation !== ORIENTATION_MIN_MAX)
				result = !result;
		}
		
		return result;
	},
	
	calculatePolygon: function(array)
	{
		if(!array)
			return null;

		var pathId = this.cChartSpace.AllocPath();
		var path  = this.cChartSpace.GetPath(pathId);
		
		var pathH = this.calcProp.pathH;
		var pathW = this.calcProp.pathW;

		
		for(var i = 0; i < array.length; i++)
		{
			var point = array[i];
			if(i === 0)
			{
				path.moveTo(point.x * pathW, point.y * pathH);
			}
			else
			{
				path.lnTo(point.x * pathW, point.y * pathH);
			}
			
			if(i === array.length - 1)
			{
				path.lnTo(array[0].x * pathW, array[0].y * pathH);
			}
		}
		

		return pathId;
	},

	_isSwitchCurrent3DChart: function (chartSpace) {
		var res = false;

		var chart = chartSpace && chartSpace.chart ? chartSpace.chart.plotArea.charts[0] : null;
		var typeChart = chart ? chart.getObjectType() : null;
		var oView3D = chartSpace && chartSpace.chart && chartSpace.chart.getView3d();
		if (isTurnOn3DCharts && oView3D) {
			var isPerspective = !oView3D.getRAngAx();

			var isBar = typeChart === AscDFH.historyitem_type_BarChart && chart && chart.barDir !== AscFormat.BAR_DIR_BAR;
			var isHBar = typeChart === AscDFH.historyitem_type_BarChart && chart && chart.barDir === AscFormat.BAR_DIR_BAR;
			var isLine = typeChart === AscDFH.historyitem_type_LineChart;
			var isPie = typeChart === AscDFH.historyitem_type_PieChart;
			var isArea = typeChart === AscDFH.historyitem_type_AreaChart;
			var isSurface = typeChart === AscDFH.historyitem_type_SurfaceChart;

			if (!isPerspective && (isBar || isLine || isHBar || isPie || isArea || isSurface)) {
				res = true;
			} else if (isPerspective && (isBar || isLine || isHBar || isArea || isPie || isSurface)) {
				res = true;
			}
		}

		return res;
	},

	getNumCache: function (val) {
		var res = null;

		if (val) {
			if (val.numRef && val.numRef.numCache) {
				res = val.numRef.numCache;
			} else if (val.numLit) {
				res = val.numLit;
			}
		}

		return res;
	},

	getHorizontalPoints: function (chartSpace) {
		var res = null;

		if(!chartSpace) {
			chartSpace = this.cChartSpace;
		}

		var plotArea = chartSpace.chart.plotArea;
		if (plotArea.valAx && plotArea.valAx.xPoints) {
			res = plotArea.valAx.xPoints;
		} else if (plotArea.catAx && plotArea.catAx.xPoints) {
			res = plotArea.catAx.xPoints;
		}

		return res;
	},

	getVerticalPoints: function (chartSpace) {
		var res = null;

		if(!chartSpace) {
			chartSpace = this.cChartSpace;
		}

		var plotArea = chartSpace.chart.plotArea;
		if (plotArea.valAx && plotArea.valAx.yPoints) {
			res = plotArea.valAx.yPoints;
		} else if (plotArea.catAx && plotArea.catAx.yPoints) {
			res = plotArea.catAx.yPoints;
		}

		return res;
	},

	getPlotAreaPoints: function (chartSpace) {
		if(!chartSpace) {
			chartSpace = this.cChartSpace;
		}

		var xPoints = this.getHorizontalPoints(chartSpace);
		var yPoints = this.getVerticalPoints(chartSpace);
		var pxToMm = this.calcProp.pxToMM;
		var plotArea = chartSpace.chart.plotArea;
		var left, right, bottom, top;
		var t = this;

		var defaultCalculate = function() {
			var widthGraph = t.calcProp.widthCanvas;
			var heightGraph = t.calcProp.heightCanvas;
			var leftMargin = t.calcProp.chartGutter._left;
			var rightMargin = t.calcProp.chartGutter._right;
			var topMargin = t.calcProp.chartGutter._top;
			var bottomMargin = t.calcProp.chartGutter._bottom;

			left = leftMargin / pxToMm;
			right = (widthGraph - rightMargin) / pxToMm;
			bottom = (heightGraph - bottomMargin) / pxToMm;
			top = (topMargin) / pxToMm;
		};

		if (xPoints && yPoints) {
			var crossBetweenX = chartSpace.getValAxisCrossType();
			var crossDiffX = 0;
			if (crossBetweenX === AscFormat.CROSS_BETWEEN_BETWEEN && plotArea.valAx.posX && this.calcProp.type !== c_oChartTypes.HBar) {
				crossDiffX = xPoints[1] ? Math.abs((xPoints[1].pos - xPoints[0].pos) / 2) : Math.abs(xPoints[0].pos - plotArea.valAx.posX);
			}
			left = xPoints[0].pos - crossDiffX;
			right = xPoints[xPoints.length - 1].pos + crossDiffX;

			var crossBetweenY = chartSpace.getValAxisCrossType();
			var crossDiffY = 0;
			if (crossBetweenY === AscFormat.CROSS_BETWEEN_BETWEEN && plotArea.valAx.posY) {
				crossDiffY = yPoints[1] ? Math.abs((yPoints[1].pos - yPoints[0].pos) / 2) : Math.abs(yPoints[0].pos - plotArea.valAx.posY);
			}
			bottom = yPoints[0].pos + crossDiffY;
			top = yPoints[yPoints.length - 1].pos - crossDiffY;
		} else {
			defaultCalculate();
		}

		if(isNaN(left) || isNaN(top) || isNaN(bottom) || isNaN(right)) {
			defaultCalculate();
		}

		return {left: left, right: right, bottom: bottom, top: top};
	},

	//common functions for grid
	getHorizontalGridLines: function (axis, isCatAxis) {
		var t = this;
		var gridLines, minorGridLines;
		var crossBetween = this.cChartSpace.getValAxisCrossType();
		var points = axis.yPoints;

		if(!points) {
			return;
		}

		var widthLine = this.calcProp.widthCanvas - (this.calcProp.chartGutter._left + this.calcProp.chartGutter._right);
		var bottomMargin = this.calcProp.heightCanvas - this.calcProp.chartGutter._bottom;
		var posX = this.calcProp.chartGutter._left;
		var posMinorY, posY, crossDiff;

		if (crossBetween === AscFormat.CROSS_BETWEEN_BETWEEN && isCatAxis) {
			var posAxis = (this.calcProp.heightCanvas - this.calcProp.chartGutter._bottom)/this.calcProp.pxToMM;
			crossDiff = points[1] ? Math.abs((points[1].pos - points[0].pos) / 2) : Math.abs(points[0].pos - posAxis);
		}

		//TODO пересмотреть отрисовку сетки для Radar, не использовать numCache!
		var numCache, tempAngle, trueHeight, trueWidth, xDiff, xCenter, yCenter;
		if(this.calcProp.type === c_oChartTypes.Radar) {
			numCache = this.getNumCache(this.calcProp.series[0].val);
			if(numCache) {
				tempAngle = 2 * Math.PI / numCache.length;
				trueHeight = this.calcProp.trueHeight;
				trueWidth = this.calcProp.trueWidth;
				xDiff = ((trueHeight / 2) / points.length) / this.calcProp.pxToMM;
				xCenter = (this.calcProp.chartGutter._left + trueWidth/2) / this.calcProp.pxToMM;
				yCenter = (this.calcProp.chartGutter._top + trueHeight/2) / this.calcProp.pxToMM;
			}
		}

		var calculateRadarGridLines = function () {
			var y, x, radius, xFirst, yFirst;
			var pathId = t.cChartSpace.AllocPath();
			var path = t.cChartSpace.GetPath(pathId);

			for (var k = 0; k < numCache.length; k++) {
				y = i * xDiff;
				x = xCenter;

				radius = y;

				y = yCenter - radius * Math.cos(k * tempAngle);
				x = x + radius * Math.sin(k * tempAngle);

				var pathH = t.calcProp.pathH;
				var pathW = t.calcProp.pathW;

				path.stroke = true;
				if (k === 0) {
					xFirst = x;
					yFirst = y;
					path.moveTo(x * pathW, y * pathH);
				} else {
					if (k === numCache.length - 1) {
						path.lnTo(x * pathW, y * pathH);
						path.lnTo(xFirst * pathW, yFirst * pathH);
					} else {
						path.lnTo(x * pathW, y * pathH);
					}
				}
			}

			if (!gridLines) {
				gridLines = [];
			}
			gridLines[i] = pathId;
		};

		var minorLinesCount = isCatAxis ? 2 : 5;
		var stepY = points[1] ? Math.abs(points[1].pos - points[0].pos) : Math.abs(points[0].pos - axis.posY) * 2;
		var minorStep = (stepY / minorLinesCount) * this.calcProp.pxToMM;

		for (var i = 0; i < points.length; i++) {
			if(this.calcProp.type === c_oChartTypes.Radar) {
				if(numCache) {
					calculateRadarGridLines();
				}
			} else {
				if(isCatAxis && points[i].val < 0) {
					continue;
				}

				if (crossDiff) {
					posY = (points[i].pos + crossDiff) * this.calcProp.pxToMM;
				} else {
					posY = points[i].pos * this.calcProp.pxToMM;
				}

				if (!gridLines) {
					gridLines = [];
				}
				gridLines[i] = this._calculateGridLine(posX, posY, posX + widthLine, posY, i);

				//промежуточные линии
				for (var n = 0; n < minorLinesCount; n++) {
					posMinorY = posY + n * minorStep;

					if (posMinorY < this.calcProp.chartGutter._top || posMinorY > bottomMargin) {
						break;
					}

					if (!minorGridLines) {
						minorGridLines = [];
					}
					if (!minorGridLines[i]) {
						minorGridLines[i] = [];
					}

					minorGridLines[i][n] = this._calculateGridLine(posX, posMinorY, posX + widthLine, posMinorY);
				}


				if (crossDiff && i === points.length - 1) {
					if (crossDiff) {
						posY = (points[i].pos - crossDiff) * this.calcProp.pxToMM;
					}

					i++;
					if (!gridLines) {
						gridLines = [];
					}
					gridLines[i] = this._calculateGridLine(posX, posY, posX + widthLine, posY);
				}
			}
		}

		return {gridLines: gridLines, minorGridLines: minorGridLines};
	},

	getVerticalGridLines: function (axis, isCatAxis) {
		var gridLines, minorGridLines;

		var crossBetween = this.cChartSpace.getValAxisCrossType();
		if(null === crossBetween && isCatAxis) {
			crossBetween = axis.crossAx ? axis.crossAx.crossBetween : null;
		}

		var heightLine = this.calcProp.heightCanvas - (this.calcProp.chartGutter._bottom + this.calcProp.chartGutter._top);
		var rightMargin = this.calcProp.widthCanvas - this.calcProp.chartGutter._right;
		var posY = this.calcProp.chartGutter._top;
		var posMinorX;
		var points = axis.xPoints;

		if (!points) {
			return;
		}

		var minorLinesCount = isCatAxis ? 2 : 5;

		var posAxis = this.calcProp.chartGutter._left / this.calcProp.pxToMM;
		var stepX = points[1] ? Math.abs((points[1].pos - points[0].pos)) : (Math.abs(points[0].pos - posAxis) * 2);
		var minorStep = (stepX * this.calcProp.pxToMM) / minorLinesCount;
		var posX, crossDiff;

		if (crossBetween === AscFormat.CROSS_BETWEEN_BETWEEN && isCatAxis) {
			crossDiff = points[1] ? Math.abs((points[1].pos - points[0].pos) / 2) : Math.abs(points[0].pos - posAxis);
		}

		for (var i = 0; i < points.length; i++) {
			if(isCatAxis && points[i].val < 0) {
				continue;
			}

			if (crossDiff) {
				posX = (points[i].pos - crossDiff) * this.calcProp.pxToMM;
			} else {
				posX = points[i].pos * this.calcProp.pxToMM;
			}

			if (!gridLines) {
				gridLines = [];
			}
			gridLines[i] = this._calculateGridLine(posX, posY, posX, posY + heightLine, i);

			//промежуточные линии
			for (var n = 0; n <= minorLinesCount; n++) {
				posMinorX = posX + n * minorStep;

				if (posMinorX < this.calcProp.chartGutter._left || posMinorX > rightMargin) {
					break;
				}

				if (!minorGridLines) {
					minorGridLines = [];
				}
				if (!minorGridLines[i]) {
					minorGridLines[i] = [];
				}

				minorGridLines[i][n] = this._calculateGridLine(posMinorX, posY, posMinorX, posY + heightLine);
			}

			if (crossDiff && i === points.length - 1) {
				if (crossDiff) {
					posX = (points[i].pos + crossDiff) * this.calcProp.pxToMM;
				}

				i++;
				if (!gridLines) {
					gridLines = [];
				}
				gridLines[i] = this._calculateGridLine(posX, posY, posX, posY + heightLine);
			}
		}

		return {gridLines: gridLines, minorGridLines: minorGridLines};
	},

	_calculateGridLine: function (x, y, x1, y1) {
		var t = this;

		var calculate2DLine = function (x, y, x1, y1) {

			var pathId = t.cChartSpace.AllocPath();
			var path = t.cChartSpace.GetPath(pathId);
			var pathH = t.calcProp.pathH;
			var pathW = t.calcProp.pathW;

			path.stroke = true;
			var pxToMm = t.calcProp.pxToMM;
			path.moveTo(x / pxToMm * pathW, y / pxToMm * pathH);
			path.lnTo(x1 / pxToMm * pathW, y1 / pxToMm * pathH);

			return pathId;
		};

		var calculate3DLine = function (x, y, x1, y1, x2, y2, x3, y3) {

			var pathId = t.cChartSpace.AllocPath();
			var path = t.cChartSpace.GetPath(pathId);

			var pathH = t.calcProp.pathH;
			var pathW = t.calcProp.pathW;

			path.stroke = true;
			var pxToMm = t.calcProp.pxToMM;
			path.moveTo(x / pxToMm * pathW, y / pxToMm * pathH);
			path.lnTo(x1 / pxToMm * pathW, y1 / pxToMm * pathH);
			path.lnTo(x2 / pxToMm * pathW, y2 / pxToMm * pathH);
			if (x3 !== undefined && y3 !== undefined) {
				path.lnTo(x3 / pxToMm * pathW, y3 / pxToMm * pathH);
				path.lnTo(x / pxToMm * pathW, y / pxToMm * pathH);
			}

			return pathId;
		};

		var path;
		if (this.nDimensionCount === 3) {
			var view3DProp = this.cChartSpace.chart.getView3d();
			var angleOx = view3DProp && view3DProp.rotX ? (-view3DProp.rotX / 360) * (Math.PI * 2) : 0;
			var angleOy = view3DProp && view3DProp.rotY ? (-view3DProp.rotY / 360) * (Math.PI * 2) : 0;
			var perspectiveDepth = this.processor3D.depthPerspective;
			var angleOz = 0;

			var rAngAx = this.processor3D.view3D.getRAngAx();
			var isVertLine = x === x1;

			var convertResult = this._convertAndTurnPoint(x, y, 0);
			var x1n = convertResult.x;
			var y1n = convertResult.y;
			convertResult = this._convertAndTurnPoint(x, y, perspectiveDepth);
			var x2n = convertResult.x;
			var y2n = convertResult.y;
			convertResult = this._convertAndTurnPoint(x1, y1, perspectiveDepth);
			var x3n = convertResult.x;
			var y3n = convertResult.y;
			convertResult = this._convertAndTurnPoint(x1, y1, 0);
			var x4n = convertResult.x;
			var y4n = convertResult.y;

			if (!isVertLine) {
				if (rAngAx) {
					path = calculate3DLine(x1n, y1n, x2n, y2n, x3n, y3n);
				} else {
					var angleOyAbs = Math.abs(angleOy);
					if (angleOyAbs >= 0 && angleOyAbs < Math.PI / 2) {
						path = calculate3DLine(x1n, y1n, x2n, y2n, x3n, y3n);
					} else if (angleOyAbs >= Math.PI / 2 && angleOyAbs < Math.PI) {
						path = calculate3DLine(x4n, y4n, x1n, y1n, x2n, y2n);
					} else if (angleOyAbs >= Math.PI && angleOyAbs < 3 * Math.PI / 2) {
						path = calculate3DLine(x1n, y1n, x4n, y4n, x3n, y3n);
					} else {
						path = calculate3DLine(x2n, y2n, x3n, y3n, x4n, y4n);
					}
				}
			} else {
				if (rAngAx) {
					path = calculate3DLine(x2n, y2n, x3n, y3n, x4n, y4n);
				} else {
					path = calculate3DLine(x2n, y2n, x3n, y3n, x4n, y4n);
				}
			}

		} else {
			path = calculate2DLine(x, y, x1, y1);
		}

		return path;
	},

	getAxisFromAxId: function(axId, type) {
		var res = null;
		for(var i = 0; i < axId.length; i++) {
			if(axId[i].getObjectType() === type) {
				res = this._searchChangedAxis(axId[i]);
				break;
			}
		}
		return res;
	},

	getPositionZero: function(axis) {
		var res = null;

		var points = axis.xPoints ? axis.xPoints : axis.yPoints;
		if(points) {
			for(var i = 0; i < points.length; i++) {
				if(0 === points[i].val) {
					res = points[i].pos * this.calcProp.pxToMM;
					break;
				}
			}

			if(null === res) {
				if(points[0].val < 0) {
					res = points[points.length - 1].pos * this.calcProp.pxToMM;
				} else {
					res = points[0].pos * this.calcProp.pxToMM;
				}
			}
		}

		return res;
	},

	calculateSplineLine: function (x, y, x1, y1, x2, y2, x3, y3, catAx, valAx) {
		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.calcProp.pathH;
		var pathW = this.calcProp.pathW;

		var startCoords;
		var endCoords;

		for (var i = 0; i <= 1;) {
			var splineCoords = this.calculate_Bezier(x, y, x1, y1, x2, y2, x3, y3, i);

			if (i === 0) {
				startCoords = {
					x: this.getYPosition(splineCoords[0], catAx),
					y: this.getYPosition(splineCoords[1], valAx)
				};
			}

			endCoords = {
				x: this.getYPosition(splineCoords[0], catAx),
				y: this.getYPosition(splineCoords[1], valAx)
			};

			if (i === 0) {
				path.moveTo(startCoords.x * pathW, startCoords.y * pathH);
			}
			path.lnTo(endCoords.x * pathW, endCoords.y * pathH);

			i = i + 0.1;
		}

		return pathId;
	}
};


/** @constructor */
function drawBarChart(chart, chartsDrawer) {
	this.chartProp = chartsDrawer.calcProp;
	this.cChartDrawer = chartsDrawer;
	this.cChartSpace = chartsDrawer.cChartSpace;

	this.chart = chart;
	this.catAx = null;
	this.valAx = null;
	this.ptCount = null;
	this.seriesCount = null;
	this.subType = null;

	this.paths = {};
	this.sortZIndexPaths = [];
	this.summBarVal = [];

	this.temp = [];
	this.temp2 = [];
}

drawBarChart.prototype = {
	constructor: drawBarChart,

	recalculate: function () {
		this.paths = {};
		this.summBarVal = [];

		this.sortZIndexPaths = [];

		var countSeries = this.cChartDrawer.calculateCountSeries(this.chart);
		this.seriesCount = countSeries.series;
		this.ptCount = countSeries.points;
		this.subType = this.cChartDrawer.getChartGrouping(this.chart);
		this.catAx = this.cChartDrawer.getAxisFromAxId(this.chart.axId, AscDFH.historyitem_type_CatAx);
		if(!this.catAx) {
			this.catAx = this.cChartDrawer.getAxisFromAxId(this.chart.axId, AscDFH.historyitem_type_DateAx);
		}
		this.valAx = this.cChartDrawer.getAxisFromAxId(this.chart.axId, AscDFH.historyitem_type_ValAx);

		this._recalculateBars();
	},

	draw: function () {
		if (this.cChartDrawer.nDimensionCount === 3) {
			this._DrawBars3D();
		} else {
			this._DrawBars();
		}
	},

	_DrawBars: function () {
		this.cChartDrawer.cShapeDrawer.Graphics.SaveGrState();

		var left = (this.chartProp.chartGutter._left - 1) / this.chartProp.pxToMM;
		var top = (this.chartProp.chartGutter._top - 1) / this.chartProp.pxToMM;
		var right = this.chartProp.trueWidth / this.chartProp.pxToMM;
		var bottom = this.chartProp.trueHeight / this.chartProp.pxToMM;
		this.cChartDrawer.cShapeDrawer.Graphics.AddClipRect(left, top, right, bottom);

		this.cChartDrawer.drawPaths(this.paths, this.chart.series);
		this.cChartDrawer.cShapeDrawer.Graphics.RestoreGrState();
	},

	_recalculateBars: function (/*isSkip*/) {
		var xPoints = this.catAx.xPoints;
		var yPoints = this.valAx.yPoints;

		var scaleAxis = this.valAx.scale;
		var axisMin = scaleAxis[0] < scaleAxis[scaleAxis.length - 1] ? scaleAxis[0] : scaleAxis[scaleAxis.length - 1];
		var axisMax = scaleAxis[0] < scaleAxis[scaleAxis.length - 1] ? scaleAxis[scaleAxis.length - 1] : scaleAxis[0];

		if(!xPoints || !yPoints) {
			return;
		}

		var widthGraph = this.chartProp.widthCanvas - this.chartProp.chartGutter._left - this.chartProp.chartGutter._right;

		var defaultOverlap = (this.subType === "stacked" || this.subType === "stackedPer" || this.subType === "standard") ? 100 : 0;
		var overlap = AscFormat.isRealNumber(this.chart.overlap) ? this.chart.overlap : defaultOverlap;
		var numCache = this.cChartDrawer.getNumCache(this.chart.series[0].val);
		var width = widthGraph / xPoints.length;
		if (this.cChartSpace.getValAxisCrossType() && numCache) {
			width = widthGraph / (xPoints.length - 1);
		}

		var gapWidth = AscFormat.isRealNumber(this.chart.gapWidth) ? this.chart.gapWidth : 150;

		var individualBarWidth = width / (this.seriesCount - (this.seriesCount - 1) * (overlap / 100) + gapWidth / 100);
		var widthOverLap = individualBarWidth * (overlap / 100);
		var hmargin = (gapWidth / 100 * individualBarWidth) / 2;

		var nullPositionOX = this.catAx.posY * this.chartProp.pxToMM;

		var height, startX, startY, val, paths, seriesHeight = [], tempValues = [], seria, startYColumnPosition, startXPosition, prevVal, idx, seriesCounter = 0;
		var cubeCount = 0;
		for (var i = 0; i < this.chart.series.length; i++) {
			numCache = this.cChartDrawer.getNumCache(this.chart.series[i].val);
			seria = numCache ? numCache.pts : [];
			seriesHeight[i] = [];
			tempValues[i] = [];

			if (numCache == null || this.chart.series[i].isHidden) {
				continue;
			}

			var isValMoreZero = false;
			var isValLessZero = 0;

			for (var j = 0; j < seria.length; j++) {

				//for 3d charts
				if (val > 0) {
					isValMoreZero = true;
				} else if (val < 0) {
					isValLessZero++;
				}

				//стартовая позиция колонки Y(+ высота с учётом поправок на накопительные диаграммы)
				val = parseFloat(seria[j].val);
				idx = seria[j].idx != null ? seria[j].idx : j;

				prevVal = 0;
				if (this.subType === "stacked" || this.subType === "stackedPer") {
					for (var k = 0; k < tempValues.length; k++) {
						if (tempValues[k][idx] && tempValues[k][idx] > 0) {
							prevVal += tempValues[k][idx];
						}
					}
				}


				tempValues[i][idx] = val;

				startYColumnPosition = this._getStartYColumnPosition(seriesHeight, i, idx, val, yPoints, prevVal);
				startY = startYColumnPosition.startY;
				height = startYColumnPosition.height;

				seriesHeight[i][idx] = height;

				//стартовая позиция колонки X
				if (this.catAx.scaling.orientation === ORIENTATION_MIN_MAX) {
					if (xPoints[1] && xPoints[1].pos && xPoints[j]) {
						startXPosition = xPoints[j].pos - Math.abs((xPoints[1].pos - xPoints[0].pos) / 2);
					} else if(xPoints[j]){
						startXPosition = xPoints[j].pos - Math.abs(xPoints[0].pos - this.valAx.posX);
					} else {
						startXPosition = xPoints[0].pos - Math.abs(xPoints[0].pos - this.valAx.posX);
					}
				} else {
					if (xPoints[1] && xPoints[1].pos && xPoints[j]) {
						startXPosition = xPoints[j].pos + Math.abs((xPoints[1].pos - xPoints[0].pos) / 2);
					} else if(xPoints[j]){
						startXPosition = xPoints[j].pos + Math.abs(xPoints[0].pos - this.valAx.posX);
					} else {
						startXPosition = xPoints[0].pos + Math.abs(xPoints[0].pos - this.valAx.posX);
					}
				}


				if (this.catAx.scaling.orientation === ORIENTATION_MIN_MAX) {
					if (seriesCounter === 0) {
						startX =
							startXPosition * this.chartProp.pxToMM + hmargin + seriesCounter * (individualBarWidth);
					} else {
						startX = startXPosition * this.chartProp.pxToMM + hmargin +
							(seriesCounter * individualBarWidth - seriesCounter * widthOverLap);
					}
				} else {
					if (i === 0) {
						startX =
							startXPosition * this.chartProp.pxToMM - hmargin - seriesCounter * (individualBarWidth);
					} else {
						startX = startXPosition * this.chartProp.pxToMM - hmargin -
							(seriesCounter * individualBarWidth - seriesCounter * widthOverLap);
					}
				}


				if (this.catAx.scaling.orientation !== ORIENTATION_MIN_MAX) {
					startX = startX - individualBarWidth;
				}

				if (this.valAx.scaling.orientation !== ORIENTATION_MIN_MAX &&
					(this.subType === "stackedPer" || this.subType === "stacked")) {
					startY = startY + height;
				}

				//for 3d charts
				if (this.cChartDrawer.nDimensionCount === 3) {
					paths = this._calculateRect3D(startX, startY, individualBarWidth, height, val, isValMoreZero, isValLessZero, i);

					//расскомментируем, чтобы включить старую схему отрисовки(+ переименовать функции _DrawBars3D -> _DrawBars3D2)
					//this.sortZIndexPaths.push({seria: i, point: idx, paths: paths.paths, x: paths.x, y: paths.y, zIndex: paths.zIndex});

					for (var k = 0; k < paths.paths.length; k++) {
						this.sortZIndexPaths.push({
							seria: i,
							point: idx,
							verge: k,
							paths: paths.paths[k],
							x: paths.sortPaths[k].x,
							y: paths.sortPaths[k].y,
							zIndex: paths.sortPaths[k].z
						});
					}

					paths = paths.paths;

					var testHeight;
					if ((axisMax > 0 && axisMin > 0) || (axisMax < 0 && axisMin < 0)) {
						testHeight = Math.abs(yPoints[0].pos - yPoints[yPoints.length - 1].pos) * this.chartProp.pxToMM;
					} else {
						var endBlockPosition, startBlockPosition;
						if (val > 0) {
							endBlockPosition = this.cChartDrawer.getYPosition(axisMax, this.valAx) * this.chartProp.pxToMM;
							startBlockPosition = prevVal ? this.cChartDrawer.getYPosition(0, this.valAx) * this.chartProp.pxToMM : nullPositionOX;
							testHeight = startBlockPosition - endBlockPosition;
						} else {
							endBlockPosition = this.cChartDrawer.getYPosition(axisMin, this.valAx) * this.chartProp.pxToMM;
							startBlockPosition = prevVal ? this.cChartDrawer.getYPosition(0, this.valAx) * this.chartProp.pxToMM : nullPositionOX;
							testHeight = startBlockPosition - endBlockPosition;
						}
					}

					this.calculateParallalepiped(startX, startY, individualBarWidth, testHeight, val, isValMoreZero, isValLessZero, i, idx, cubeCount, this.temp2);
					this.calculateParallalepiped(startX, startY, individualBarWidth, height, val, isValMoreZero, isValLessZero, i, idx, cubeCount, this.temp);

					cubeCount++;
				} else {
					paths = this._calculateRect(startX, startY, individualBarWidth, height);
				}

				if (!this.paths.series) {
					this.paths.series = [];
				}
				if (!this.paths.series[i]) {
					this.paths.series[i] = [];
				}
				this.paths.series[i][idx] = paths;

			}

			if (seria.length) {
				seriesCounter++;
			}
		}

		var cSortFaces;
		if (this.cChartDrawer.nDimensionCount === 3) {
			if (this.subType === "stacked" || this.subType === "stackedPer") {
				//если будут найдены проблемы при отрисовке stacked rAngAx - раскомментировать ветку
				/*if(this.cChartDrawer.processor3D.view3D.rAngAx)
				 {
				 var angle = this.cChartDrawer.processor3D.angleOx;
				 this.temp.sort (function sortArr(a, b)
				 {
				 if(angle > 0)
				 {
				 if(Math.abs(angle) < Math.PI)
				 {
				 return  a.y - b.y;
				 }
				 else
				 {
				 return  b.y - a.y;
				 }
				 }
				 else
				 {
				 if(Math.abs(angle) < Math.PI)
				 {
				 return  b.y - a.y;
				 }
				 else
				 {
				 return  a.y - b.y;
				 }
				 }
				 })
				 }*/

				cSortFaces = new window['AscFormat'].CSortFaces(this.cChartDrawer);
				this.sortParallelepipeds = cSortFaces.sortParallelepipeds(this.temp);
			} else if ("normal" === this.subType) {
				cSortFaces = new window['AscFormat'].CSortFaces(this.cChartDrawer);
				this.sortParallelepipeds = cSortFaces.sortParallelepipeds(this.temp2);
			} else {
				this.sortZIndexPaths.sort(function sortArr(a, b) {
					if (b.zIndex == a.zIndex) {
						return b.y - a.y;
					} else {
						return b.zIndex - a.zIndex;
					}
				});
			}
		}
	},

	_getStartYColumnPosition: function (seriesHeight, i, j, val, yPoints) {
		var startY, height, curVal, prevVal, endBlockPosition, startBlockPosition;
		var nullPositionOX = this.subType === "stacked" ? this.cChartDrawer.getPositionZero(this.valAx) : this.catAx.posY * this.chartProp.pxToMM;

		if (this.subType === "stacked") {
			curVal = this._getStackedValue(this.chart.series, i, j, val);
			prevVal = this._getStackedValue(this.chart.series, i - 1, j, val);

			endBlockPosition = this.cChartDrawer.getYPosition(curVal, this.valAx) * this.chartProp.pxToMM;
			startBlockPosition = prevVal ? this.cChartDrawer.getYPosition(prevVal, this.valAx) * this.chartProp.pxToMM : nullPositionOX;

			startY = startBlockPosition;
			height = startBlockPosition - endBlockPosition;

			if (this.valAx.scaling.orientation != ORIENTATION_MIN_MAX) {
				height = -height;
			}
		} else if (this.subType === "stackedPer") {
			this._calculateSummStacked(j);

			curVal = this._getStackedValue(this.chart.series, i, j, val);
			prevVal = this._getStackedValue(this.chart.series, i - 1, j, val);

			endBlockPosition = this.cChartDrawer.getYPosition((curVal / this.summBarVal[j]), this.valAx) * this.chartProp.pxToMM;
			startBlockPosition = this.summBarVal[j] ? this.cChartDrawer.getYPosition((prevVal / this.summBarVal[j]), this.valAx) * this.chartProp.pxToMM : nullPositionOX;

			startY = startBlockPosition;
			height = startBlockPosition - endBlockPosition;

			if (this.valAx.scaling.orientation !== ORIENTATION_MIN_MAX) {
				height = -height;
			}
		} else {
			startY = nullPositionOX;
			if (this.valAx && this.valAx.scaling.logBase)//исключение для логарифмической шкалы
			{
				height = nullPositionOX - this.cChartDrawer.getYPosition(val, this.valAx) * this.chartProp.pxToMM;
			} else {
				height = nullPositionOX - this.cChartDrawer.getYPosition(val, this.valAx) * this.chartProp.pxToMM;
			}
		}

		return {startY: startY, height: height};
	},

	calculateParallalepiped: function (startX, startY, individualBarWidth, height, val, isValMoreZero, isValLessZero, i, idx, cubeCount, arr) {
		//параметр r и глубина по OZ
		var perspectiveDepth = this.cChartDrawer.processor3D.depthPerspective;

		//сдвиг по OZ в глубину
		var gapDepth = this.chart.gapDepth != null ? this.chart.gapDepth : globalGapDepth;
		if (this.subType === "standard") {
			perspectiveDepth = (perspectiveDepth / (gapDepth / 100 + 1)) / this.seriesCount;
		} else {
			perspectiveDepth = perspectiveDepth / (gapDepth / 100 + 1);
		}
		var DiffGapDepth = perspectiveDepth * (gapDepth / 2) / 100;

		if (this.subType === "standard") {
			gapDepth = (perspectiveDepth + DiffGapDepth + DiffGapDepth) * i + DiffGapDepth;
		} else {
			gapDepth = DiffGapDepth;
		}

		//рассчитываем 8 точек для каждого столбца
		var x1 = startX, y1 = startY, z1 = 0 + gapDepth;
		var x2 = startX, y2 = startY, z2 = perspectiveDepth + gapDepth;
		var x3 = startX + individualBarWidth, y3 = startY, z3 = perspectiveDepth + gapDepth;
		var x4 = startX + individualBarWidth, y4 = startY, z4 = 0 + gapDepth;
		var x5 = startX, y5 = startY - height, z5 = 0 + gapDepth;
		var x6 = startX, y6 = startY - height, z6 = perspectiveDepth + gapDepth;
		var x7 = startX + individualBarWidth, y7 = startY - height, z7 = perspectiveDepth + gapDepth;
		var x8 = startX + individualBarWidth, y8 = startY - height, z8 = 0 + gapDepth;


		//поворот относительно осей
		var point1 = this.cChartDrawer._convertAndTurnPoint(x1, y1, z1);
		var point2 = this.cChartDrawer._convertAndTurnPoint(x2, y2, z2);
		var point3 = this.cChartDrawer._convertAndTurnPoint(x3, y3, z3);
		var point4 = this.cChartDrawer._convertAndTurnPoint(x4, y4, z4);
		var point5 = this.cChartDrawer._convertAndTurnPoint(x5, y5, z5);
		var point6 = this.cChartDrawer._convertAndTurnPoint(x6, y6, z6);
		var point7 = this.cChartDrawer._convertAndTurnPoint(x7, y7, z7);
		var point8 = this.cChartDrawer._convertAndTurnPoint(x8, y8, z8);

		var points = [point1, point2, point3, point4, point5, point6, point7, point8];
		var paths = this.cChartDrawer.calculateRect3D(points, val, null, true);

		//не проецируем на плоскость
		var point11 = this.cChartDrawer._convertAndTurnPoint(x1, y1, z1, null, null, true);
		var point22 = this.cChartDrawer._convertAndTurnPoint(x2, y2, z2, null, null, true);
		var point33 = this.cChartDrawer._convertAndTurnPoint(x3, y3, z3, null, null, true);
		var point44 = this.cChartDrawer._convertAndTurnPoint(x4, y4, z4, null, null, true);
		var point55 = this.cChartDrawer._convertAndTurnPoint(x5, y5, z5, null, null, true);
		var point66 = this.cChartDrawer._convertAndTurnPoint(x6, y6, z6, null, null, true);
		var point77 = this.cChartDrawer._convertAndTurnPoint(x7, y7, z7, null, null, true);
		var point88 = this.cChartDrawer._convertAndTurnPoint(x8, y8, z8, null, null, true);


		var arrPoints = [[point1, point4, point8, point5], [point1, point2, point3, point4],
			[point1, point2, point6, point5], [point4, point8, point7, point3], [point5, point6, point7, point8],
			[point6, point2, point3, point7]];

		var arrPoints2 = [[point11, point44, point88, point55], [point11, point22, point33, point44],
			[point11, point22, point66, point55], [point44, point88, point77, point33],
			[point55, point66, point77, point88], [point66, point22, point33, point77]];


		if (!arr) {
			arr = [];
		}
		if (!arr[cubeCount]) {
			arr[cubeCount] = {};
		}
		if (!arr[cubeCount].faces) {
			arr[cubeCount].faces = [];
			arr[cubeCount].arrPoints = [point11, point22, point33, point44, point55, point66, point77, point88];
			arr[cubeCount].z = point11.z;
			arr[cubeCount].y = point11.y;
		}

		for (var k = 0; k < paths.frontPaths.length; k++) {
			if (null === paths.frontPaths[k] && null === paths.darkPaths[k]) {
				continue;
			}

			//this.sortZIndexPaths.push({seria: i, point: idx, verge: k, paths: paths[k], points: arrPoints2[k], points2: arrPoints[k], plainEquation: plainEquation});

			var plainEquation = this.cChartDrawer.getPlainEquation(arrPoints2[k][0], arrPoints2[k][1], arrPoints2[k][2], arrPoints2[k][3]);
			var plainArea = this.cChartDrawer.getAreaQuadrilateral(arrPoints[k][0], arrPoints[k][1], arrPoints[k][2], arrPoints[k][3]);
			arr[cubeCount].faces.push({
				seria: i,
				point: idx,
				verge: k,
				frontPaths: paths.frontPaths[k],
				darkPaths: paths.darkPaths[k],
				points: arrPoints2[k],
				points2: arrPoints[k],
				plainEquation: plainEquation,
				plainArea: plainArea
			});
		}

		return paths;
	},

	_calculateSummStacked: function (j) {
		if (!this.summBarVal[j]) {
			var curVal;
			var temp = 0;
			var idxPoint;
			for (var k = 0; k < this.chart.series.length; k++) {
				idxPoint = this.cChartDrawer.getIdxPoint(this.chart.series[k], j);
				curVal = idxPoint ? parseFloat(idxPoint.val) : 0;

				if (curVal) {
					temp += Math.abs(curVal);
				}
			}

			this.summBarVal[j] = temp;
		}
	},

	_getStackedValue: function (series, i, j, val) {
		var result = 0, curVal, idxPoint;
		for (var k = 0; k <= i; k++) {
			idxPoint = this.cChartDrawer.getIdxPoint(this.chart.series[k], j);
			curVal = idxPoint ? idxPoint.val : 0;

			if (idxPoint && val > 0 && curVal > 0) {
				result += parseFloat(curVal);
			} else if (idxPoint && val < 0 &&
				curVal < 0) {
				result += parseFloat(curVal);
			}
		}

		return result;
	},

	_calculateDLbl: function (chartSpace, ser, val) {
		var point = this.cChartDrawer.getIdxPoint(this.chart.series[ser], val);
		if (!this.paths.series[ser][val] || !point || !point.compiledDlb) {
			return;
		}

		var path = this.paths.series[ser][val];
		//ToDo пересмотреть для 3d диаграмм
		if (this.cChartDrawer.nDimensionCount === 3) {
			if (AscFormat.isRealNumber(this.paths.series[ser][val][0])) {
				path = this.paths.series[ser][val][0];
			} else if (AscFormat.isRealNumber(this.paths.series[ser][val][5])) {
				path = this.paths.series[ser][val][5];
			} else if (AscFormat.isRealNumber(this.paths.series[ser][val][2])) {
				path = this.paths.series[ser][val][2];
			} else if (AscFormat.isRealNumber(this.paths.series[ser][val][3])) {
				path = this.paths.series[ser][val][3];
			}
		}

		if (!AscFormat.isRealNumber(path)) {
			return;
		}
		var oPath = this.cChartSpace.GetPath(path);
		var oCommand0 = oPath.getCommandByIndex(0);
		var oCommand1 = oPath.getCommandByIndex(1);
		var oCommand2 = oPath.getCommandByIndex(2);

		var x = oCommand0.X;
		var y = oCommand0.Y;

		var h = oCommand0.Y - oCommand1.Y;
		var w = oCommand2.X - oCommand1.X;

		var pxToMm = this.chartProp.pxToMM;

		var width = point.compiledDlb.extX;
		var height = point.compiledDlb.extY;

		var centerX, centerY;

		switch (point.compiledDlb.dLblPos) {
			case c_oAscChartDataLabelsPos.bestFit: {
				break;
			}
			case c_oAscChartDataLabelsPos.ctr: {
				centerX = x + w / 2 - width / 2;
				centerY = y - h / 2 - height / 2;
				break;
			}
			case c_oAscChartDataLabelsPos.inBase: {
				centerX = x + w / 2 - width / 2;
				centerY = y;
				if (point.val > 0) {
					centerY = y - height;
				}
				break;
			}
			case c_oAscChartDataLabelsPos.inEnd: {
				centerX = x + w / 2 - width / 2;
				centerY = y - h;
				if (point.val < 0) {
					centerY = centerY - height;
				}
				break;
			}
			case c_oAscChartDataLabelsPos.outEnd: {
				centerX = x + w / 2 - width / 2;
				centerY = y - h - height;
				if (point.val < 0) {
					centerY = centerY + height;
				}
				break;
			}
		}
		if (centerX < 0) {
			centerX = 0;
		}
		if (centerX + width > this.chartProp.widthCanvas / pxToMm) {
			centerX = this.chartProp.widthCanvas / pxToMm - width;
		}

		if (centerY < 0) {
			centerY = 0;
		}
		if (centerY + height > this.chartProp.heightCanvas / pxToMm) {
			centerY = this.chartProp.heightCanvas / pxToMm - height;
		}

		return {x: centerX, y: centerY};
	},

	_calculateRect: function (x, y, w, h) {
		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;


		var pxToMm = this.chartProp.pxToMM;

		path.moveTo(x / pxToMm * pathW, y / pxToMm * pathH);
		path.lnTo(x / pxToMm * pathW, (y - h) / pxToMm * pathH);
		path.lnTo((x + w) / pxToMm * pathW, (y - h) / pxToMm * pathH);
		path.lnTo((x + w) / pxToMm * pathW, y / pxToMm * pathH);
		path.lnTo(x / pxToMm * pathW, y / pxToMm * pathH);

		return pathId;
	},


	//TODO delete after test
	_DrawBars3D2: function () {
		var t = this;
		var processor3D = this.cChartDrawer.processor3D;

		var verges = {
			front: 0, down: 1, left: 2, right: 3, up: 4, unfront: 5
		};

		var drawVerges = function (i, j, paths, onlyLessNull, start, stop) {
			var brush, pen, options;
			options = t._getOptionsForDrawing(i, j, onlyLessNull);
			if (options !== null) {
				pen = options.pen;
				brush = options.brush;

				for (var k = start; k <= stop; k++) {
					t._drawBar3D(paths[k], pen, brush, k);
				}
			}
		};

		var draw = function (onlyLessNull, start, stop) {
			for (var i = 0; i < t.sortZIndexPaths.length; i++) {
				drawVerges(t.sortZIndexPaths[i].seria, t.sortZIndexPaths[i].point, t.sortZIndexPaths[i].paths,
					onlyLessNull, start, stop);
			}
		};

		if (this.subType === "standard") {
			draw(true, verges.front, verges.unfront);
			draw(false, verges.front, verges.unfront);
		} else {
			draw(true, verges.down, verges.up);
			draw(false, verges.down, verges.up);

			draw(true, verges.unfront, verges.unfront);
			draw(false, verges.unfront, verges.unfront);

			draw(true, verges.front, verges.front);
			draw(false, verges.front, verges.front);
		}
	},

	_DrawBars3D: function () {
		var t = this;

		var drawVerges = function (i, j, paths, onlyLessNull, k, isNotPen, isNotBrush) {
			var brush = null, pen = null, options;
			options = t._getOptionsForDrawing(i, j, onlyLessNull);
			if (paths !== null && options !== null) {
				if (!isNotPen) {
					pen = options.pen;
				}
				if (!isNotBrush) {
					brush = options.brush;
				}

				t._drawBar3D(paths, pen, brush, k, options.val);
			}
		};

		var index, faces, face;
		if (this.subType === "stacked" || this.subType === "stackedPer") {
			//если будут найдены проблемы при отрисовке stacked rAngAx - раскомментировать ветку
			/*if(this.cChartDrawer.processor3D.view3D.rAngAx)
			 {
			 for(var i = 0; i < this.temp.length; i++)
			 {
			 var faces = this.temp[i].faces;
			 for(var j = 0; j < faces.length; j++)
			 {
			 var face = faces[j];
			 drawVerges(face.seria, face.point, face.paths, null, face.verge);
			 }
			 }
			 }*/

			for (var i = 0; i < this.sortParallelepipeds.length; i++) {
				index = this.sortParallelepipeds[i].nextIndex;
				faces = this.temp[index].faces;
				for (var j = 0; j < faces.length; j++) {
					face = faces[j];
					drawVerges(face.seria, face.point, face.darkPaths, null, face.verge, null, true);
				}
			}

			for (var i = 0; i < this.sortParallelepipeds.length; i++) {
				index = this.sortParallelepipeds[i].nextIndex;
				faces = this.temp[index].faces;
				for (var j = 0; j < faces.length; j++) {
					face = faces[j];
					drawVerges(face.seria, face.point, face.frontPaths, null, face.verge);
				}
			}
		} else if ("normal" === this.subType) {
			for (var i = 0; i < this.sortParallelepipeds.length; i++) {
				index = this.sortParallelepipeds[i].nextIndex;
				faces = this.temp[index].faces;
				for (var j = 0; j < faces.length; j++) {
					face = faces[j];
					drawVerges(face.seria, face.point, face.darkPaths, null, face.verge, null, true);
				}
			}

			for (var i = 0; i < this.sortParallelepipeds.length; i++) {
				index = this.sortParallelepipeds[i].nextIndex;
				faces = this.temp[index].faces;
				for (var j = 0; j < faces.length; j++) {
					face = faces[j];
					drawVerges(face.seria, face.point, face.frontPaths, null, face.verge);
				}
			}
		} else {
			for (var i = 0; i < this.sortZIndexPaths.length; i++) {
				drawVerges(this.sortZIndexPaths[i].seria, this.sortZIndexPaths[i].point,
					this.sortZIndexPaths[i].paths, true, this.sortZIndexPaths[i].verge);
			}

			for (var i = 0; i < this.sortZIndexPaths.length; i++) {
				drawVerges(this.sortZIndexPaths[i].seria, this.sortZIndexPaths[i].point,
					this.sortZIndexPaths[i].paths, false, this.sortZIndexPaths[i].verge);
			}
		}
	},

	_getOptionsForDrawing: function (ser, point, onlyLessNull) {
		var seria = this.chart.series[ser];
		var numCache = this.cChartDrawer.getNumCache(seria.val);
		if(!numCache) {
			return null;
		}

		var pt = numCache.getPtByIndex(point);
		if(!seria || !this.paths.series[ser] || !this.paths.series[ser][point] || !pt) {
			return null;
		}

		var brush = seria.brush;
		var pen = seria.pen;

		if ((pt.val > 0 && onlyLessNull === true) || (pt.val < 0 && onlyLessNull === false)) {
			return null;
		}

		if (pt.pen) {
			pen = pt.pen;
		}
		if (pt.brush) {
			brush = pt.brush;
		}

		return {pen: pen, brush: brush, val: pt.val}
	},

	_drawBar3D: function (path, pen, brush, k, val) {
		//затемнение боковых сторон
		//в excel всегда темные боковые стороны, лицевая и задняя стороны светлые
		//TODO пересмотреть получения pen
		if (null === pen || (null !== pen && null === pen.Fill) ||
			(null !== pen && null !== pen.Fill && null === pen.Fill.fill)) {
			pen = AscFormat.CreatePenFromParams(brush, undefined, undefined, undefined, undefined, 0.1);
		}

		if (k !== 5 && k !== 0) {
			var props = this.cChartSpace.getParentObjects();
			var duplicateBrush = brush;
			if (null !== brush) {
				duplicateBrush = brush.createDuplicate();
				var cColorMod = new AscFormat.CColorMod;

				if (k === 1 || k === 4) {
					//для градиентной заливки верхнюю и нижнюю грань закрашиываем первым и последним цветом соотвенственно
					if (duplicateBrush.fill &&
						AscDFH.historyitem_type_GradFill === duplicateBrush.fill.getObjectType()) {
						var colors = duplicateBrush.fill.colors;
						//ToDo проверить stacked charts!
						var color;
						var valAxOrientation = this.valAx.scaling.orientation;
						if ((val > 0 && valAxOrientation === ORIENTATION_MIN_MAX) ||
							(val < 0 && valAxOrientation !== ORIENTATION_MIN_MAX)) {
							if (k === 4 && colors && colors[0] && colors[0].color) {
								color = colors[0].color;
							} else if (k === 1 && colors[colors.length - 1] && colors[colors.length - 1].color) {
								color = colors[colors.length - 1].color;
							}
						} else {
							if (k === 4 && colors && colors[0] && colors[0].color) {
								color = colors[colors.length - 1].color;
							} else if (k === 1 && colors[colors.length - 1] && colors[colors.length - 1].color) {
								color = colors[0].color;
							}
						}

						var tempColor = new AscFormat.CUniFill();
						tempColor.setFill(new AscFormat.CSolidFill());
						tempColor.fill.setColor(color);
						duplicateBrush = tempColor;
					}

					cColorMod.val = 45000;
				} else {
					cColorMod.val = 35000;
				}

				cColorMod.name = "shade";
				duplicateBrush.addColorMod(cColorMod);
				duplicateBrush.calculate(props.theme, props.slide, props.layout, props.master, new AscFormat.CUniColor().RGBA, this.cChartSpace.clrMapOvr);

				if (null === pen) {
					pen.setFill(duplicateBrush);
				}
			}

			this.cChartDrawer.drawPath(path, pen, duplicateBrush);
		} else {
			this.cChartDrawer.drawPath(path, pen, brush);
		}
	},

	_calculateRect3D: function (startX, startY, individualBarWidth, height, val, isValMoreZero, isValLessZero, serNum) {
		//параметр r и глубина по OZ
		var perspectiveDepth = this.cChartDrawer.processor3D.depthPerspective;

		//сдвиг по OZ в глубину
		var gapDepth = this.chart.gapDepth != null ? this.chart.gapDepth : globalGapDepth;
		if (this.subType === "standard") {
			perspectiveDepth = (perspectiveDepth / (gapDepth / 100 + 1)) / this.seriesCount;
		} else {
			perspectiveDepth = perspectiveDepth / (gapDepth / 100 + 1);
		}

		var DiffGapDepth = perspectiveDepth * (gapDepth / 2) / 100;
		if (this.subType === "standard") {
			gapDepth = (perspectiveDepth + DiffGapDepth + DiffGapDepth) * serNum + DiffGapDepth;
		} else {
			gapDepth = DiffGapDepth;
		}

		//рассчитываем 8 точек для каждого столбца
		var x1 = startX, y1 = startY, z1 = 0 + gapDepth;
		var x2 = startX, y2 = startY, z2 = perspectiveDepth + gapDepth;
		var x3 = startX + individualBarWidth, y3 = startY, z3 = perspectiveDepth + gapDepth;
		var x4 = startX + individualBarWidth, y4 = startY, z4 = 0 + gapDepth;
		var x5 = startX, y5 = startY - height, z5 = 0 + gapDepth;
		var x6 = startX, y6 = startY - height, z6 = perspectiveDepth + gapDepth;
		var x7 = startX + individualBarWidth, y7 = startY - height, z7 = perspectiveDepth + gapDepth;
		var x8 = startX + individualBarWidth, y8 = startY - height, z8 = 0 + gapDepth;


		//поворот относительно осей
		var point1 = this.cChartDrawer._convertAndTurnPoint(x1, y1, z1);
		var point2 = this.cChartDrawer._convertAndTurnPoint(x2, y2, z2);
		var point3 = this.cChartDrawer._convertAndTurnPoint(x3, y3, z3);
		var point4 = this.cChartDrawer._convertAndTurnPoint(x4, y4, z4);
		var point5 = this.cChartDrawer._convertAndTurnPoint(x5, y5, z5);
		var point6 = this.cChartDrawer._convertAndTurnPoint(x6, y6, z6);
		var point7 = this.cChartDrawer._convertAndTurnPoint(x7, y7, z7);
		var point8 = this.cChartDrawer._convertAndTurnPoint(x8, y8, z8);


		//down verge of minus values don't must draw(in stacked and stackedPer)
		var isNotDrawDownVerge;
		/*if((this.subType == "stacked" || this.subType == "stackedPer") && val < 0 && (isValMoreZero || (!isValMoreZero && isValLessZero !== 1)))
		 isNotDrawDownVerge = true;*/

		var points = [point1, point2, point3, point4, point5, point6, point7, point8];
		var paths = this.cChartDrawer.calculateRect3D(points, val, isNotDrawDownVerge);

		height = this.chartProp.heightCanvas - this.chartProp.chartGutter._top - this.chartProp.chartGutter._bottom;
		var controlPoint1 = this.cChartDrawer._convertAndTurnPoint(x1 + individualBarWidth / 2, y1 - height / 2, z1);
		var controlPoint2 = this.cChartDrawer._convertAndTurnPoint(x1 + individualBarWidth / 2, y1, z1 + perspectiveDepth / 2);
		var controlPoint3 = this.cChartDrawer._convertAndTurnPoint(x1, y1 - height / 2, z1 + perspectiveDepth / 2);
		var controlPoint4 = this.cChartDrawer._convertAndTurnPoint(x4, y4 - height / 2, z4 + perspectiveDepth / 2);
		var controlPoint5 = this.cChartDrawer._convertAndTurnPoint(x5 + individualBarWidth / 2, y5, z5 + perspectiveDepth / 2);
		var controlPoint6 = this.cChartDrawer._convertAndTurnPoint(x2 + individualBarWidth / 2, y2 - height / 2, z2);

		var sortPaths = [controlPoint1, controlPoint2, controlPoint3, controlPoint4, controlPoint5, controlPoint6];

		return {paths: paths, x: point1.x, y: point1.y, zIndex: point1.z, sortPaths: sortPaths};
	}
};


/** @constructor */
function drawLineChart(chart, chartsDrawer) {
	this.chartProp = chartsDrawer.calcProp;
	this.cChartDrawer = chartsDrawer;
	this.cChartSpace = chartsDrawer.cChartSpace;

	this.chart = chart;
	this.catAx = null;
	this.valAx = null;
	this.ptCount = null;
	this.seriesCount = null;
	this.subType = null;

	this.paths = {};
}

drawLineChart.prototype = {
	constructor: drawLineChart,

	draw: function () {
		if (this.cChartDrawer.nDimensionCount === 3) {
			this._drawLines3D();
		} else {
			this._drawLines();
		}
	},

	recalculate: function () {
		this.paths = {};

		var countSeries = this.cChartDrawer.calculateCountSeries(this.chart);
		this.seriesCount = countSeries.series;
		this.ptCount = countSeries.points;
		this.subType = this.cChartDrawer.getChartGrouping(this.chart);
		this.catAx = this.cChartDrawer.getAxisFromAxId(this.chart.axId, AscDFH.historyitem_type_CatAx);
		if(!this.catAx) {
			this.catAx = this.cChartDrawer.getAxisFromAxId(this.chart.axId, AscDFH.historyitem_type_DateAx);
		}
		this.valAx = this.cChartDrawer.getAxisFromAxId(this.chart.axId, AscDFH.historyitem_type_ValAx);

		this._calculateLines();
	},

	_calculateLines: function () {
		var xPoints = this.catAx.xPoints;
		var yPoints = this.valAx.yPoints;

		if(!xPoints || !yPoints) {
			return;
		}

		var points, y, x, val, seria, dataSeries, compiledMarkerSize, compiledMarkerSymbol, idx, numCache, idxPoint;
		for (var i = 0; i < this.chart.series.length; i++) {

			seria = this.chart.series[i];
			numCache = this.cChartDrawer.getNumCache(seria.val);

			if (!numCache) {
				continue;
			}

			dataSeries = numCache.pts;

			for (var n = 0; n < numCache.ptCount; n++) {
				idx = dataSeries[n] && dataSeries[n].idx != null ? dataSeries[n].idx : n;

				//рассчитываем значения
				val = this._getYVal(n, i);

				x = this.catAx ? this.cChartDrawer.getYPosition(n + 1, this.catAx) : xPoints[n].pos;
				y = this.cChartDrawer.getYPosition(val, this.valAx);

				if (!this.paths.points) {
					this.paths.points = [];
				}
				if (!this.paths.points[i]) {
					this.paths.points[i] = [];
				}

				if (!points) {
					points = [];
				}
				if (!points[i]) {
					points[i] = [];
				}

				idxPoint = this.cChartDrawer.getIdxPoint(seria, n);
				compiledMarkerSize = idxPoint && idxPoint.compiledMarker && idxPoint.compiledMarker.size ? idxPoint.compiledMarker.size : null;
				compiledMarkerSymbol = idxPoint && idxPoint.compiledMarker && AscFormat.isRealNumber(idxPoint.compiledMarker.symbol) ? idxPoint.compiledMarker.symbol : null;

				if (val != null) {
					this.paths.points[i][n] = this.cChartDrawer.calculatePoint(x, y, compiledMarkerSize, compiledMarkerSymbol);
					points[i][n] = {x: x, y: y};
				} else {
					this.paths.points[i][n] = null;
					points[i][n] = null;
				}
			}
		}

		this._calculateAllLines(points);
	},

	_calculateAllLines: function (points) {
		if(!points) {
			return;
		}

		var xPoints = this.catAx.xPoints;
		var yPoints = this.valAx.yPoints;

		if (this.cChartDrawer.nDimensionCount === 3) {
			//сдвиг по OZ в глубину
			var perspectiveDepth = this.cChartDrawer.processor3D.depthPerspective;
			var seriaDiff = perspectiveDepth / this.seriesCount;
			var gapDepth = this.chart.gapDepth != null ? this.chart.gapDepth : globalGapDepth;
			var depthSeria = seriaDiff / ((gapDepth / 100) + 1);
			var DiffGapDepth = (depthSeria * (gapDepth / 100)) / 2;
			depthSeria = (perspectiveDepth / this.seriesCount - 2 * DiffGapDepth);
		}

		var x, y, x1, y1, x2, y2, x3, y3, isSplineLine;
		for (var i = 0; i < points.length; i++) {
			isSplineLine = this.chart.series[i].smooth !== false;

			if (!points[i]) {
				continue;
			}

			for (var n = 0; n < points[i].length; n++) {
				if (!this.paths.series) {
					this.paths.series = [];
				}
				if (!this.paths.series[i]) {
					this.paths.series[i] = [];
				}

				if (points[i][n] != null && points[i][n + 1] != null) {
					if (this.cChartDrawer.nDimensionCount === 3) {
						x = points[i][n].x * this.chartProp.pxToMM;
						y = points[i][n].y * this.chartProp.pxToMM;

						x1 = points[i][n + 1].x * this.chartProp.pxToMM;
						y1 = points[i][n + 1].y * this.chartProp.pxToMM;

						if (!this.paths.series) {
							this.paths.series = [];
						}
						if (!this.paths.series[i]) {
							this.paths.series[i] = [];
						}

						var point1, point2, point3, point4, point5, point6, point7, point8, widthLine = 0.5;
						point1 = this.cChartDrawer._convertAndTurnPoint(x, y - widthLine, DiffGapDepth + seriaDiff * i);
						point2 = this.cChartDrawer._convertAndTurnPoint(x1, y1 - widthLine, DiffGapDepth + seriaDiff * i);
						point3 = this.cChartDrawer._convertAndTurnPoint(x1, y1 - widthLine, DiffGapDepth + depthSeria + seriaDiff * i);
						point4 = this.cChartDrawer._convertAndTurnPoint(x, y - widthLine, DiffGapDepth + depthSeria + seriaDiff * i);


						point5 = this.cChartDrawer._convertAndTurnPoint(x, y + widthLine, DiffGapDepth + seriaDiff * i);
						point6 = this.cChartDrawer._convertAndTurnPoint(x1, y1 + widthLine, DiffGapDepth + seriaDiff * i);
						point7 = this.cChartDrawer._convertAndTurnPoint(x1, y1 + widthLine, DiffGapDepth + depthSeria + seriaDiff * i);
						point8 = this.cChartDrawer._convertAndTurnPoint(x, y + widthLine, DiffGapDepth + depthSeria + seriaDiff * i);

						this.paths.series[i][n] = this.cChartDrawer.calculateRect3D([point1, point2, point3, point4, point5, point6, point7, point8]);
					} else if (isSplineLine) {
						x = points[i][n - 1] ? n - 1 : 0;
						y = this._getYVal(x, i);

						x1 = n;
						y1 = this._getYVal(x1, i);

						x2 = points[i][n + 1] ? n + 1 : n;
						y2 = this._getYVal(x2, i);

						x3 = points[i][n + 2] ? n + 2 : points[i][n + 1] ? n + 1 : n;
						y3 = this._getYVal(x3, i);

						this.paths.series[i][n] = this.cChartDrawer.calculateSplineLine(x + 1, y, x1 + 1, y1, x2 + 1, y2, x3 + 1, y3, this.catAx, this.valAx);
					} else {
						this.paths.series[i][n] = this._calculateLine(points[i][n].x, points[i][n].y, points[i][n + 1].x, points[i][n + 1].y);
					}
				}
			}
		}
	},

	_calculateDLbl: function (chartSpace, ser, val) {
		var point = this.cChartDrawer.getIdxPoint(this.chart.series[ser], val);
		var path;

		var commandIndex = 0;
		if (this.cChartDrawer.nDimensionCount === 3) {
			var curSer = this.paths.series[ser];
			if (val === curSer.length && curSer[val - 1]) {
				if (AscFormat.isRealNumber(curSer[val - 1][5])) {
					path = curSer[val - 1][5];
				} else if (AscFormat.isRealNumber(curSer[val - 1][2])) {
					path = curSer[val - 1][2];
				}
				commandIndex = 3;
			} else if (curSer[val] && AscFormat.isRealNumber(curSer[val][3]))//reverse
			{
				path = curSer[val][3];
			} else if (curSer[val] && AscFormat.isRealNumber(curSer[val][2])) {
				path = curSer[val][2];
			}
		} else {
			if(this.paths.points[ser] && this.paths.points[ser][val]){
				path = this.paths.points[ser][val].path;
			}
		}

		if (!AscFormat.isRealNumber(path)) {
			return;
		}

		var oPath = this.cChartSpace.GetPath(path);
		var oCommand0 = oPath.getCommandByIndex(commandIndex);
		var x = oCommand0.X;
		var y = oCommand0.Y;

		var pxToMm = this.chartProp.pxToMM;
		var constMargin = 5 / pxToMm;

		var width = point.compiledDlb.extX;
		var height = point.compiledDlb.extY;

		var centerX = x - width / 2;
		var centerY = y - height / 2;

		switch (point.compiledDlb.dLblPos) {
			case c_oAscChartDataLabelsPos.b: {
				centerY = centerY + height / 2 + constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.bestFit: {
				break;
			}
			case c_oAscChartDataLabelsPos.ctr: {
				break;
			}
			case c_oAscChartDataLabelsPos.l: {
				centerX = centerX - width / 2 - constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.r: {
				centerX = centerX + width / 2 + constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.t: {
				centerY = centerY - height / 2 - constMargin;
				break;
			}
		}

		if (centerX < 0) {
			centerX = 0;
		}
		if (centerX + width > this.chartProp.widthCanvas / pxToMm) {
			centerX = this.chartProp.widthCanvas / pxToMm - width;
		}

		if (centerY < 0) {
			centerY = 0;
		}
		if (centerY + height > this.chartProp.heightCanvas / pxToMm) {
			centerY = this.chartProp.heightCanvas / pxToMm - height;
		}

		return {x: centerX, y: centerY};
	},

	_drawLines: function (/*isSkip*/) {
		//TODO для того, чтобы верхняя линия рисовалась. пересмотреть!
		var diffPen = 3;
		var leftRect = this.chartProp.chartGutter._left / this.chartProp.pxToMM;
		var topRect = (this.chartProp.chartGutter._top - diffPen) / this.chartProp.pxToMM;
		var rightRect = this.chartProp.trueWidth / this.chartProp.pxToMM;
		var bottomRect = (this.chartProp.trueHeight + diffPen) / this.chartProp.pxToMM;

		this.cChartDrawer.cShapeDrawer.Graphics.SaveGrState();
		this.cChartDrawer.cShapeDrawer.Graphics.AddClipRect(leftRect, topRect, rightRect, bottomRect);
		this.cChartDrawer.drawPaths(this.paths, this.chart.series, true);
		this.cChartDrawer.cShapeDrawer.Graphics.RestoreGrState();

		this.cChartDrawer.drawPathsPoints(this.paths, this.chart.series);
	},

	_getYVal: function (n, i) {
		var tempVal;
		var val = 0;
		var idxPoint;

		if (this.subType === "stacked") {
			for (var k = 0; k <= i; k++) {
				idxPoint = this.cChartDrawer.getPointByIndex(this.chart.series[k], n);
				tempVal = idxPoint ? parseFloat(idxPoint.val) : 0;
				if (tempVal) {
					val += tempVal;
				}
			}
		} else if (this.subType === "stackedPer") {
			var summVal = 0;
			for (var k = 0; k < this.chart.series.length; k++) {
				idxPoint = this.cChartDrawer.getPointByIndex(this.chart.series[k], n);
				tempVal = idxPoint ? parseFloat(idxPoint.val) : 0;
				if (tempVal) {
					if (k <= i) {
						val += tempVal;
					}
					summVal += Math.abs(tempVal);
				}
			}
			val = val / summVal;
		} else {
			idxPoint = this.cChartDrawer.getPointByIndex(this.chart.series[i], n);
			val = idxPoint ? parseFloat(idxPoint.val) : null;
		}
		return val;
	},

	_calculateLine: function (x, y, x1, y1) {
		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;


		path.moveTo(x * pathW, y * pathH);
		path.lnTo(x1 * pathW, y1 * pathH);


		return pathId;
	},

	//TODO пока включаю функцию _calculateSplineLine. с _calculateSplineLine2 отрисовается неверно. проверить!
	_calculateSplineLine2: function (x, y, x1, y1, x2, y2, x3, y3, xPoints, yPoints) {
		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;


		var splineCoords = this.cChartDrawer.calculate_Bezier(x, y, x1, y1, x2, y2, x3, y3);

		x = this.cChartDrawer.getYPosition(splineCoords[0].x, this.catAx);
		y = this.cChartDrawer.getYPosition(splineCoords[0].y, this.valAx);

		x1 = this.cChartDrawer.getYPosition(splineCoords[1].x, this.catAx);
		y1 = this.cChartDrawer.getYPosition(splineCoords[1].y, this.valAx);

		x2 = this.cChartDrawer.getYPosition(splineCoords[2].x, this.catAx);
		y2 = this.cChartDrawer.getYPosition(splineCoords[2].y, this.valAx);

		x3 = this.cChartDrawer.getYPosition(splineCoords[3].x, this.catAx);
		y3 = this.cChartDrawer.getYPosition(splineCoords[3].y, this.valAx);

		path.moveTo(x * pathW, y * pathH);
		path.cubicBezTo(x1 * pathW, y1 * pathH, x2 * pathW, y2 * pathH, x3 * pathW, y3 * pathH);

		return pathId;
	},

	_drawLines3D: function () {
		var t = this;

		var drawVerges = function (j, i) {
			var brush, pen, seria;

			seria = t.chart.series[j];
			brush = seria.brush;
			pen = seria.pen;

			if (!(!t.paths.series[j] || !t.paths.series[j][i] || !seria.val.numRef.numCache.pts[i])) {
				if (seria.val.numRef.numCache && seria.val.numRef.numCache.pts[i].pen) {
					pen = seria.val.numRef.numCache.pts[i].pen;
				}
				if (seria.val.numRef.numCache && seria.val.numRef.numCache.pts[i].brush) {
					brush = seria.val.numRef.numCache.pts[i].brush;
				}

				for (var k = 0; k < t.paths.series[j][i].length; k++) {
					t._drawLine3D(t.paths.series[j][i][k], pen, brush, k);
				}
			}
		};


		//рисуем по сериям
		var onSeries = function (onlyLessNull) {
			var drawNeedVerge = function () {
				for (var j = 0; j < t.paths.series.length; j++) {
					for (var i = 0; i < t.ptCount; i++) {
						drawVerges(j, i, onlyLessNull);
					}
				}
			};

			drawNeedVerge();
		};


		var reverseSeriesOnSeries = function (onlyLessNull) {
			var drawNeedVerge = function () {
				for (var j = t.paths.series.length - 1; j >= 0; j--) {
					if (!t.paths.series) {
						return;
					}

					for (var i = 0; i < t.ptCount; i++) {
						drawVerges(j, i, onlyLessNull);
					}
				}
			};

			drawNeedVerge();
		};


		if (!this.cChartDrawer.processor3D.view3D.getRAngAx()) {
			var angle = Math.abs(this.cChartDrawer.processor3D.angleOy);
			if (angle > Math.PI / 2 && angle < 3 * Math.PI / 2) {
				onSeries();
			} else {
				reverseSeriesOnSeries();
			}
		} else {
			reverseSeriesOnSeries();
		}
	},

	_drawLine3D: function (path, pen, brush, k) {
		//затемнение боковых сторон
		//в excel всегда темные боковые стороны, лицевая и задняя стороны светлые

		//todo возможно стоит проверить fill.type на FILL_TYPE_NOFILL и рисовать отдельно границы, если они заданы!
		//brush = pen.Fill;

		if (k !== 2) {
			var props = this.cChartSpace.getParentObjects();
			var duplicateBrush = brush.createDuplicate();
			var cColorMod = new AscFormat.CColorMod;

			cColorMod.name = "shade";
			if (k === 1 || k === 4) {
				cColorMod.val = 45000;
			} else {
				cColorMod.val = 35000;
			}

			this._addColorMods(cColorMod, duplicateBrush);

			duplicateBrush.calculate(props.theme, props.slide, props.layout, props.master, new AscFormat.CUniColor().RGBA, this.cChartSpace.clrMapOvr);
			pen = AscFormat.CreatePenFromParams(duplicateBrush, undefined, undefined, undefined, undefined, 0.1);

			this.cChartDrawer.drawPath(path, pen, duplicateBrush);
		} else {
			pen = AscFormat.CreatePenFromParams(brush, undefined, undefined, undefined, undefined, 0.1);
			this.cChartDrawer.drawPath(path, pen, brush);
		}
	},

	_addColorMods: function (cColorMod, duplicateBrush) {
		if (duplicateBrush) {
			duplicateBrush.addColorMod(cColorMod);
		}
	}
};


/** @constructor */
function drawAreaChart(chart, chartsDrawer) {
	this.chartProp = chartsDrawer.calcProp;
	this.cChartDrawer = chartsDrawer;
	this.cChartSpace = chartsDrawer.cChartSpace;

	this.chart = chart;
	this.catAx = null;
	this.valAx = null;
	this.ptCount = null;
	this.seriesCount = null;
	this.subType = null;

	this.points = null;
	this.paths = {};
	this.upFaces = [];
	this.downFaces = [];

	this.sortZIndexPaths = [];
	this.sortZIndexPathsFront = [];
	this.sortZIndexPathsBack = [];
	this.sortZIndexPathsRight = [];
	this.sortZIndexPathsLeft = [];

	this.intersections = [];
	this.intersectionsFar = [];

	this.xPoints = null;
	this.yPoints = null;

	//for 3d
	this.darkFaces = null;
	this.gapDepth = null;
	this.perspectiveDepth = null;
}

drawAreaChart.prototype = {
	constructor: drawAreaChart,

	draw: function () {
		if (this.cChartDrawer.nDimensionCount === 3) {
			this._drawBars3D();
		} else {
			this._drawLines();
		}
	},

	recalculate: function () {
		this.paths = {};
		this.points = null;

		var countSeries = this.cChartDrawer.calculateCountSeries(this.chart);
		this.seriesCount = countSeries.series;
		this.ptCount = countSeries.points;
		this.subType = this.cChartDrawer.getChartGrouping(this.chart);
		this.catAx = this.cChartDrawer.getAxisFromAxId(this.chart.axId, AscDFH.historyitem_type_CatAx);
		if(!this.catAx) {
			this.catAx = this.cChartDrawer.getAxisFromAxId(this.chart.axId, AscDFH.historyitem_type_DateAx);
		}
		this.valAx = this.cChartDrawer.getAxisFromAxId(this.chart.axId, AscDFH.historyitem_type_ValAx);

		this._calculateProps();
		this._calculate();
	},

	_calculateProps: function () {
		if (this.cChartDrawer.nDimensionCount === 3) {
			var gapDepth = this.chart.gapDepth != null ? this.chart.gapDepth : globalGapDepth;
			var perspectiveDepth = this.cChartDrawer.processor3D.depthPerspective;
			perspectiveDepth = this.subType === "normal" ? (perspectiveDepth / (gapDepth / 100 + 1)) / this.seriesCount : perspectiveDepth / (gapDepth / 100 + 1);
			var DiffGapDepth = perspectiveDepth * (gapDepth / 2) / 100;

			this.perspectiveDepth = perspectiveDepth;
			if (this.subType === "normal") {
				this.gapDepth = [];

				for (var i = 0; i < this.seriesCount; i++) {
					this.gapDepth[i] = (this.perspectiveDepth + DiffGapDepth + DiffGapDepth) * i + DiffGapDepth;
				}
			} else {
				this.gapDepth = DiffGapDepth;
			}
		}

		this.xPoints = this.catAx.xPoints;
		this.yPoints = this.valAx.yPoints;
	},

	_calculate: function () {
		var y, x, val, seria, dataSeries, numCache;
		var pxToMm = this.chartProp.pxToMM;
		var nullPositionOX = this.catAx.posY;

		for (var i = 0; i < this.chart.series.length; i++) {

			seria = this.chart.series[i];
			numCache = this.cChartDrawer.getNumCache(seria.val);

			if (!numCache) {
				continue;
			}

			dataSeries = numCache.pts;

			for (var n = 0; n < numCache.ptCount; n++) {
				//рассчитываем значения
				val = this._getYVal(n, i);

				x = this.xPoints[n].pos;
				y = this.cChartDrawer.getYPosition(val, this.valAx);

				if (!this.points) {
					this.points = [];
				}
				if (!this.points[i]) {
					this.points[i] = [];
				}

				if (val != null) {
					this.points[i][n] = {x: x, y: y, val: val};
				} else {
					this.points[i][n] = {x: x, y: nullPositionOX, val: val};
				}
			}

			if (this.cChartDrawer.nDimensionCount === 3) {
				//для normal рассчитываем видимые/невидимые грани для каждой серии
				if (this.subType === "normal") {
					this._calculateDarkSideOfTheFace(i);
				} else if (this.darkFaces === null) {
					this._calculateDarkSideOfTheFace(null);
				}
			}
		}


		if (this.cChartDrawer.nDimensionCount === 3) {
			this._calculatePaths3D();

			//var cSortFaces = new CSortFaces(this.cChartDrawer);
			//this.upFaces = cSortFaces.sortFaces(this.upFaces);

			var upDownFaces = this.upFaces.concat(this.downFaces);

			//более быстрая сортировка
			var angle = this.cChartDrawer.processor3D.angleOx;
			if (angle < 0) {
				upDownFaces.sort(function sortArr(a, b) {
					if (b.midY === a.midY) {
						return a.seria - b.seria;
					} else {
						return b.midY - a.midY;
					}
				});
			} else {
				upDownFaces.sort(function sortArr(a, b) {
					if (b.midY === a.midY) {
						return a.seria - b.seria;
					} else {
						return a.midY - b.midY;
					}
				});
			}

			var anotherFaces = this.sortZIndexPathsFront.concat(this.sortZIndexPathsBack).concat(this.sortZIndexPathsLeft).concat(this.sortZIndexPathsRight);
			this.sortZIndexPaths = upDownFaces.concat(anotherFaces);

			//медленная, но более качественный сортировка
			//var anotherFaces = this.sortZIndexPathsFront.concat(this.sortZIndexPathsBack).concat(this.sortZIndexPathsLeft).concat(this.sortZIndexPathsRight);
			//this.sortZIndexPaths = this.upFaces.concat(anotherFaces);
			//this.sortZIndexPaths = this.downFaces.concat(this.sortZIndexPaths)
			//this.sortZIndexPaths = cSortFaces.sortFaces(this.sortZIndexPaths);
		} else {
			this._calculatePaths();
		}
	},

	_calculatePaths: function () {
		var points = this.points;
		var prevPoints;
		var isStacked = this.subType === "stackedPer" || this.subType === "stacked";

		for (var i = 0; i < points.length; i++) {
			if (!this.paths.series) {
				this.paths.series = [];
			}
			prevPoints = isStacked ? this._getPrevSeriesPoints(points, i) : null;
			if (points[i]) {
				this.paths.series[i] = this._calculateLine(points[i], prevPoints);
			}
		}
	},

	_calculatePaths3D: function () {
		var points = this.points;
		var prevPoints;
		var isStacked = this.subType === "stackedPer" || this.subType === "stacked";

		if (isStacked) {
			this._calculateAllIntersection();
		}

		for (var i = 0; i < points.length; i++) {
			if (!this.paths.series) {
				this.paths.series = [];
			}

			prevPoints = isStacked ? this._getPrevSeriesPoints(points, i) : null;

			if (points[i]) {
				if (isStacked) {
					this.paths.series[i] = this._calculateStacked3D(prevPoints, i, points);
				} else {
					this.paths.series[i] = this._calculateLine3D(points[i], i, points);
				}
			}
		}
	},

	_calculateLine: function (points, prevPoints) {
		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;


		var point;
		var pxToMm = this.chartProp.pxToMM;

		//точки данной серии
		for (var i = 0; i < points.length; i++) {
			point = points[i];
			if (i === 0) {
				path.moveTo(point.x * pathW, point.y * pathH);
			} else {
				path.lnTo(point.x * pathW, point.y * pathH);
			}
		}

		//точки предыдущей серии
		var nullPositionOX = this.catAx.posY * this.chartProp.pxToMM;
		if (prevPoints != null) {
			for (var i = prevPoints.length - 1; i >= 0; i--) {
				point = prevPoints[i];
				path.lnTo(point.x * pathW, point.y * pathH);

				if (i === 0) {
					path.lnTo(points[0].x * pathW, points[0].y * pathH);
				}
			}
		} else {
			path.lnTo(points[points.length - 1].x * pathW, nullPositionOX / pxToMm * pathH);
			path.lnTo(points[0].x * pathW, nullPositionOX / pxToMm * pathH);
			path.lnTo(points[0].x * pathW, points[0].y * pathH);
		}

		return pathId;
	},

	_calculateLine3D: function (points, seriaNum) {
		//pointsIn3D[0] - верхняя кривая ближней стороны, pointsIn3D[1] - нижняя кривая ближней стороны, pointsIn3D[2] - верхняя кривая дальней стороны, pointsIn3D[3] - нижняя кривая дальней стороны
		var pointsIn3D = [], t = this, pxToMm = this.chartProp.pxToMM;
		var nullPosition = this.catAx.posY * this.chartProp.pxToMM;

		//сдвиг по OZ в глубину
		var gapDepth = this.gapDepth[seriaNum];

		var getProjectPoints = function (currentZ, startN) {
			pointsIn3D[startN] = [];
			pointsIn3D[startN + 1] = [];
			for (var i = 0; i < points.length; i++) {
				pointsIn3D[startN][i] = t.cChartDrawer._convertAndTurnPoint(points[i].x * pxToMm, points[i].y * pxToMm, currentZ + gapDepth);
				pointsIn3D[startN + 1][i] = t.cChartDrawer._convertAndTurnPoint(points[i].x * pxToMm, nullPosition, currentZ + gapDepth);
			}
		};

		var zNear = 0;
		var zFar = this.perspectiveDepth;
		//рассчитываем ближние и дальние точки конкретной серии
		getProjectPoints(zNear, 0);
		getProjectPoints(zFar, 2);

		return this._calculateRect3D(pointsIn3D, seriaNum);
	},

	_calculateStacked3D: function (prevPoints, seria, allPoints) {
		var points = allPoints[seria];
		var t = this, nullPositionOX = this.catAx.posY * this.chartProp.pxToMM, pxToMm = this.chartProp.pxToMM, res = [];

		for (var i = 0; i < points.length - 1; i++) {
			var x = points[i].x * pxToMm;
			var y = points[i].y * pxToMm;
			var x1 = points[i + 1].x * pxToMm;
			var y1 = points[i + 1].y * pxToMm;

			//рассчитываем 8 точек для каждого ректа
			var prevX = prevPoints ? prevPoints[i].x * pxToMm : x;
			var prevY = prevPoints ? prevPoints[i].y * pxToMm : nullPositionOX;
			var prevX1 = prevPoints ? prevPoints[i + 1].x * pxToMm : x1;
			var prevY1 = prevPoints ? prevPoints[i + 1].y * pxToMm : nullPositionOX;


			if (prevY < y && prevY1 < y1) {
				var temp = y;
				y = prevY;
				prevY = temp;

				var temp1 = y1;
				y1 = prevY1;
				prevY1 = temp1;

				temp = x;
				x = prevX;
				prevX = temp;

				temp1 = x1;
				x1 = prevX1;
				prevX1 = temp1;
			}

			if (!this.prevPoints) {
				this.prevPoints = [];
			}

			if (!this.prevPoints[i]) {
				this.prevPoints[i] = [];
			}


			//начальные точки, без проекции и без поворота
			var p1 = {x: x, y: y, z: this.gapDepth};
			var p2 = {x: x, y: y, z: this.gapDepth + this.perspectiveDepth};
			var p3 = {x: x1, y: y1, z: this.gapDepth + this.perspectiveDepth};
			var p4 = {x: x1, y: y1, z: this.gapDepth};
			var p5 = {x: prevX, y: prevY, z: this.gapDepth};
			var p6 = {x: prevX, y: prevY, z: this.gapDepth + this.perspectiveDepth};
			var p7 = {x: prevX1, y: prevY1, z: this.gapDepth + this.perspectiveDepth};
			var p8 = {x: prevX1, y: prevY1, z: this.gapDepth};
			var arrNotRotatePoints = [p1, p2, p3, p4, p5, p6, p7, p8];

			//повернутые, но без проекции
			var point11 = t.cChartDrawer._convertAndTurnPoint(p1.x, p1.y, p1.z, null, null, true);
			var point22 = t.cChartDrawer._convertAndTurnPoint(p2.x, p2.y, p2.z, null, null, true);
			var point33 = t.cChartDrawer._convertAndTurnPoint(p3.x, p3.y, p3.z, null, null, true);
			var point44 = t.cChartDrawer._convertAndTurnPoint(p4.x, p4.y, p4.z, null, null, true);
			var point55 = t.cChartDrawer._convertAndTurnPoint(p5.x, p5.y, p5.z, null, null, true);
			var point66 = t.cChartDrawer._convertAndTurnPoint(p6.x, p6.y, p6.z, null, null, true);
			var point77 = t.cChartDrawer._convertAndTurnPoint(p7.x, p7.y, p7.z, null, null, true);
			var point88 = t.cChartDrawer._convertAndTurnPoint(p8.x, p8.y, p8.z, null, null, true);
			var arrPoints = [point11, point22, point33, point44, point55, point66, point77, point88];

			//спроецированные и повернутые точки
			var point1 = t.cChartDrawer._convertAndTurnPoint(p1.x, p1.y, p1.z);
			var point2 = t.cChartDrawer._convertAndTurnPoint(p2.x, p2.y, p2.z);
			var point3 = t.cChartDrawer._convertAndTurnPoint(p3.x, p3.y, p3.z);
			var point4 = t.cChartDrawer._convertAndTurnPoint(p4.x, p4.y, p4.z);
			var point5 = t.cChartDrawer._convertAndTurnPoint(p5.x, p5.y, p5.z);
			var point6 = t.cChartDrawer._convertAndTurnPoint(p6.x, p6.y, p6.z);
			var point7 = t.cChartDrawer._convertAndTurnPoint(p7.x, p7.y, p7.z);
			var point8 = t.cChartDrawer._convertAndTurnPoint(p8.x, p8.y, p8.z);
			var arrPointsProject = [point1, point2, point3, point4, point5, point6, point7, point8];

			var paths = this._calculateRect3DStacked(arrPoints, arrPointsProject, arrNotRotatePoints, i, seria);
			res.push(paths);
		}

		return res;
	},

	_calculateDarkSideOfTheFace: function (seria) {
		var pxToMm = this.chartProp.pxToMM;

		var minX = this.xPoints[0].pos < this.xPoints[this.xPoints.length - 1].pos ? this.xPoints[0].pos * pxToMm : this.xPoints[this.xPoints.length - 1].pos * pxToMm;
		var maxX = this.xPoints[0].pos < this.xPoints[this.xPoints.length - 1].pos ? this.xPoints[this.xPoints.length - 1].pos * pxToMm : this.xPoints[0].pos * pxToMm;

		var minValue = this.valAx.min;
		var maxValue = this.valAx.max;
		if (this.subType === "stackedPer") {
			minValue = minValue / 100;
			maxValue = maxValue / 100;
		}

		var maxY = this.cChartDrawer.getYPosition(minValue, this.valAx) * pxToMm;
		var minY = this.cChartDrawer.getYPosition(maxValue, this.valAx) * pxToMm;

		var gapDepth = seria === null ? this.gapDepth : this.gapDepth[seria];

		var point1 = this.cChartDrawer._convertAndTurnPoint(minX, maxY, gapDepth);
		var point2 = this.cChartDrawer._convertAndTurnPoint(minX, maxY, gapDepth + this.perspectiveDepth);
		var point3 = this.cChartDrawer._convertAndTurnPoint(maxX, maxY, gapDepth + this.perspectiveDepth);
		var point4 = this.cChartDrawer._convertAndTurnPoint(maxX, maxY, gapDepth);

		var point5 = this.cChartDrawer._convertAndTurnPoint(minX, minY, gapDepth);
		var point6 = this.cChartDrawer._convertAndTurnPoint(minX, minY, gapDepth + this.perspectiveDepth);
		var point7 = this.cChartDrawer._convertAndTurnPoint(maxX, minY, gapDepth + this.perspectiveDepth);
		var point8 = this.cChartDrawer._convertAndTurnPoint(maxX, minY, gapDepth);

		var darkFaces;
		if (seria === null) {
			this.darkFaces = {};
			darkFaces = this.darkFaces;
		} else {
			if (null === this.darkFaces) {
				this.darkFaces = [];
			}
			this.darkFaces[seria] = {};
			darkFaces = this.darkFaces[seria];
		}


		//front
		darkFaces["front"] = null;
		if (this._isVisibleVerge3D(point5, point1, point4)) {
			darkFaces["front"] = 1;
		}

		//down
		darkFaces["down"] = null;
		if (this._isVisibleVerge3D(point4, point1, point2)) {
			darkFaces["down"] = 1;
		}

		//left
		darkFaces["left"] = null;
		if (this._isVisibleVerge3D(point2, point1, point5)) {
			darkFaces["left"] = 1;
		}

		//right
		darkFaces["right"] = null;
		if (this._isVisibleVerge3D(point8, point4, point3)) {
			darkFaces["right"] = 1;
		}

		//up
		darkFaces["up"] = null;
		if (this._isVisibleVerge3D(point6, point5, point8)) {
			darkFaces["up"] = 1;
		}

		//unfront
		darkFaces["unfront"] = null;
		if (this._isVisibleVerge3D(point3, point2, point6)) {
			darkFaces["unfront"] = 1;
		}
	},

	_calculateRect3D: function (pointsIn3D, seriaNum) {
		var path, pathId;
		var pxToMm = this.chartProp.pxToMM;
		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;

		var oThis = this;

		var calculateFace = function (number, isReverse, isFirstPoint) {
			if (!isReverse) {
				for (var i = 0; i < pointsIn3D[number].length; i++) {
					if (i === 0 && isFirstPoint) {
						path.moveTo(pointsIn3D[number][i].x / pxToMm * pathW,
							pointsIn3D[number][i].y / pxToMm * pathH);
					} else {
						path.lnTo(pointsIn3D[number][i].x / pxToMm * pathW,
							pointsIn3D[number][i].y / pxToMm * pathH);
					}
				}
			} else {
				for (var i = pointsIn3D[number].length - 1; i >= 0; i--) {
					if (i === pointsIn3D[number].length - 1 && isFirstPoint) {
						path.moveTo(pointsIn3D[number][i].x / pxToMm * pathW,
							pointsIn3D[number][i].y / pxToMm * pathH);
					} else {
						path.lnTo(pointsIn3D[number][i].x / pxToMm * pathW,
							pointsIn3D[number][i].y / pxToMm * pathH);
					}
				}
			}
		};

		var calculateRect = function (p1, p2, p3, p4) {
			var pathId = oThis.cChartSpace.AllocPath();
			var path = oThis.cChartSpace.GetPath(pathId);

			path.moveTo(p1.x / pxToMm * pathW, p1.y / pxToMm * pathH);
			path.lnTo(p2.x / pxToMm * pathW, p2.y / pxToMm * pathH);
			path.lnTo(p3.x / pxToMm * pathW, p3.y / pxToMm * pathH);
			path.lnTo(p4.x / pxToMm * pathW, p4.y / pxToMm * pathH);
			path.lnTo(p1.x / pxToMm * pathW, p1.y / pxToMm * pathH);

			return pathId;
		};

		var calculateUpDownFace = function (isDown) {
			var arrayPaths = [];
			for (var i = 0; i < pointsIn3D[0].length - 1; i++) {
				var point1Up = pointsIn3D[0][i];
				var point2Up = pointsIn3D[0][i + 1];

				var point1UpFar = pointsIn3D[2][i];
				var point2UpFar = pointsIn3D[2][i + 1];

				var point1Down = pointsIn3D[1][i];
				var point2Down = pointsIn3D[1][i + 1];

				var point1DownFar = pointsIn3D[3][i];
				var point2DownFar = pointsIn3D[3][i + 1];

				var path = null;

				if (!isDown) {
					if (point1Up.y > point1Down.y && point2Up.y < point2Down.y) {
						path = calculateRect(point1Up, point1UpFar, point2UpFar, point2Up);
						arrayPaths.push(path);
						path = calculateRect(point1Down, point1DownFar, point2DownFar, point2Down);
						arrayPaths.push(path);
					} else if (point1Up.y < point1Down.y && point2Up.y > point2Down.y) {
						path = calculateRect(point1Down, point1DownFar, point2DownFar, point2Down);
						arrayPaths.push(path);
						path = calculateRect(point1Up, point1UpFar, point2UpFar, point2Up);
						arrayPaths.push(path);
					} else {
						path = calculateRect(point1Up, point1UpFar, point2UpFar, point2Up);
						arrayPaths.push(path);
					}
				} else {
					if (point1Up.y > point1Down.y && point2Up.y < point2Down.y) {
						path = calculateRect(point1Up, point1UpFar, point2UpFar, point2Up);
						arrayPaths.push(path);
						path = calculateRect(point1Down, point1DownFar, point2DownFar, point2Down);
						arrayPaths.push(path);
					} else if (point1Up.y < point1Down.y && point2Up.y > point2Down.y) {
						path = calculateRect(point1Up, point1UpFar, point2UpFar, point2Up);
						arrayPaths.push(path);
						path = calculateRect(point1Down, point1DownFar, point2DownFar, point2Down);
						arrayPaths.push(path);
					} else {
						path = calculateRect(point1Down, point1DownFar, point2DownFar, point2Down);
						arrayPaths.push(path);
					}
				}
			}

			return arrayPaths;
		};

		var paths = [];
		var upNear = 0, downNear = 1, upFar = 2, downFar = 3;

		//for define VisibleVerge, as in bar charts
		var point1 = pointsIn3D[downNear][0];
		var point2 = pointsIn3D[downFar][0];
		var point3 = pointsIn3D[downFar][pointsIn3D[downFar].length - 1];
		var point4 = pointsIn3D[downNear][pointsIn3D[downNear].length - 1];

		var point5 = pointsIn3D[upNear][0];
		var point6 = pointsIn3D[upFar][0];
		var point7 = pointsIn3D[upFar][pointsIn3D[upFar].length - 1];
		var point8 = pointsIn3D[upNear][pointsIn3D[upNear].length - 1];


		//front
		paths[0] = null;
		if (this.darkFaces[seriaNum]["front"]) {
			pathId = this.cChartSpace.AllocPath();
			path = this.cChartSpace.GetPath(pathId);


			calculateFace(upNear, false, true);
			calculateFace(downNear, true);
			path.lnTo(point5.x / pxToMm * pathW, point5.y / pxToMm * pathH);

			paths[0] = pathId;
		}

		//down
		paths[1] = null;
		var arrayPaths = calculateUpDownFace(true);
		paths[1] = arrayPaths;

		//left
		paths[2] = null;
		if (this.darkFaces[seriaNum]["left"]) {
			arrayPaths = calculateRect(pointsIn3D[0][0], pointsIn3D[1][0], pointsIn3D[3][0], pointsIn3D[2][0]);
			paths[2] = arrayPaths;
		}

		//right
		paths[3] = null;
		if (this.darkFaces[seriaNum]["right"]) {
			arrayPaths = calculateRect(pointsIn3D[0][pointsIn3D[0].length - 1], pointsIn3D[1][pointsIn3D[1].length - 1], pointsIn3D[3][pointsIn3D[3].length - 1], pointsIn3D[2][pointsIn3D[2].length - 1]);
			paths[3] = arrayPaths;
		}

		//up
		paths[4] = null;
		//if(this.darkFaces[seriaNum]["up"])
		//{
		arrayPaths = calculateUpDownFace();
		paths[4] = arrayPaths;
		//}

		//unfront
		paths[5] = null;
		if (this.darkFaces[seriaNum]["unfront"]) {
			pathId = this.cChartSpace.AllocPath();
			path = this.cChartSpace.GetPath(pathId);
			calculateFace(upFar, false, true);
			calculateFace(downFar, true);
			path.lnTo(pointsIn3D[upFar][0].x / pxToMm * pathW, pointsIn3D[upFar][0].y / pxToMm * pathH);
			paths[5] = pathId;
		}

		return paths;
	},

	_calculateRect3DStacked: function (arrPoints, arrPointsProject, arrNotRotatePoints, point, seria) {
		var pxToMm = this.chartProp.pxToMM, t = this;

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;

		//for define VisibleVerge, as in bar charts
		var p1 = arrNotRotatePoints[0];
		var p2 = arrNotRotatePoints[1];
		var p3 = arrNotRotatePoints[2];
		var p4 = arrNotRotatePoints[3];
		var p5 = arrNotRotatePoints[4];
		var p6 = arrNotRotatePoints[5];
		var p7 = arrNotRotatePoints[6];
		var p8 = arrNotRotatePoints[7];

		var point1 = arrPointsProject[0];
		var point2 = arrPointsProject[1];
		var point3 = arrPointsProject[2];
		var point4 = arrPointsProject[3];
		var point5 = arrPointsProject[4];
		var point6 = arrPointsProject[5];
		var point7 = arrPointsProject[6];
		var point8 = arrPointsProject[7];

		var point11 = arrPoints[0];
		var point22 = arrPoints[1];
		var point33 = arrPoints[2];
		var point44 = arrPoints[3];
		var point55 = arrPoints[4];
		var point66 = arrPoints[5];
		var point77 = arrPoints[6];
		var point88 = arrPoints[7];

		var oThis = this;
		var generateFace = function (p11, p22, p33, p44, p111, p222, p333, p444, p1111, p2222, p3333, p4444,
									 faceIndex, ser) {
			if (ser === undefined) {
				ser = seria;
			}

			var pathId = oThis.cChartSpace.AllocPath();
			var path = oThis.cChartSpace.GetPath(pathId);

			path.moveTo(p11.x / pxToMm * pathW, p11.y / pxToMm * pathH);
			path.lnTo(p22.x / pxToMm * pathW, p22.y / pxToMm * pathH);
			path.lnTo(p33.x / pxToMm * pathW, p33.y / pxToMm * pathH);
			path.lnTo(p44.x / pxToMm * pathW, p44.y / pxToMm * pathH);
			path.lnTo(p11.x / pxToMm * pathW, p11.y / pxToMm * pathH);

			var arrPoints = [p11, p22, p33, p44];
			var arrPoints2 = [p111, p222, p333, p444];
			var plainEquation = t.cChartDrawer.getPlainEquation(p111, p222, p333);
			var plainArea = t.cChartDrawer.getAreaQuadrilateral(p11, p22, p33, p44);

			var arrPointsNotRotate = [p1111, p2222, p3333, p4444];
			var midY = (p1111.y + p2222.y + p3333.y + p4444.y) / 4;

			return {
				seria: ser,
				point: 0,
				verge: faceIndex,
				paths: pathId,
				points: arrPoints2,
				points2: arrPoints,
				plainEquation: plainEquation,
				plainArea: plainArea,
				arrPointsNotRotate: arrPointsNotRotate,
				midY: midY
			};
		};

		//рассчитываем все грани, кроме верхних и нижних
		this._calculateSimpleRect(arrPoints, arrPointsProject, point, seria);

		//находим пересечение грани с предыдущими гранями. если есть, то делим грани
		var breakFaces = this.intersections[point] && this.intersections[point][seria] ? this.intersections[point][seria] : null;

		if (breakFaces && breakFaces.up && breakFaces.up.length) {
			//сортируем грани одной точки
			breakFaces.up = breakFaces.up.sort(function sortArr(a, b) {
				return a.x - b.x;
			});

			var prevNear, prevFar, prevNearProject, prevFarProject, prevNotRotateNear, prevNotRotateFar, prevPoint;
			var near, far, nearProject, farProject, notRotateNear, notRotateFar, face;
			for (var i = 0; i < breakFaces.up.length - 1; i++) {

				prevPoint = breakFaces.up[i];
				prevNearProject = t.cChartDrawer._convertAndTurnPoint(prevPoint.x, prevPoint.y, this.gapDepth /*+ DiffGapDepth*/);
				prevFarProject = t.cChartDrawer._convertAndTurnPoint(prevPoint.x, prevPoint.y, this.gapDepth + this.perspectiveDepth);

				prevNear = t.cChartDrawer._convertAndTurnPoint(prevPoint.x, prevPoint.y, this.gapDepth /*+ DiffGapDepth*/, null, null, true);
				prevFar = t.cChartDrawer._convertAndTurnPoint(prevPoint.x, prevPoint.y, this.gapDepth + this.perspectiveDepth, null, null, true);

				prevNotRotateNear = {x: prevPoint.x, y: prevPoint.y, z: this.gapDepth};
				prevNotRotateFar = {x: prevPoint.x, y: prevPoint.y, z: this.gapDepth + this.perspectiveDepth};

				point = breakFaces.up[i + 1];
				nearProject = t.cChartDrawer._convertAndTurnPoint(point.x, point.y, this.gapDepth /*+ DiffGapDepth*/);
				farProject = t.cChartDrawer._convertAndTurnPoint(point.x, point.y, this.gapDepth + this.perspectiveDepth);

				near = t.cChartDrawer._convertAndTurnPoint(point.x, point.y, this.gapDepth /*+ DiffGapDepth*/, null, null, true);
				far = t.cChartDrawer._convertAndTurnPoint(point.x, point.y, this.gapDepth + this.perspectiveDepth, null, null, true);

				notRotateNear = {x: point.x, y: point.y, z: this.gapDepth};
				notRotateFar = {x: point.x, y: point.y, z: this.gapDepth + this.perspectiveDepth};


				face = generateFace(prevNearProject, prevFarProject, farProject, nearProject, prevNear, prevFar, far, near, prevNotRotateNear, prevNotRotateFar, notRotateNear, notRotateFar, 1);
				this.upFaces.push(face);
			}
		}

		if (breakFaces && breakFaces.down && breakFaces.down.length) {
			//сортируем грани одной точки
			breakFaces.down = breakFaces.down.sort(function sortArr(a, b) {
				return a.x - b.x;
			});

			for (var i = 0; i < breakFaces.down.length - 1; i++) {
				prevPoint = breakFaces.down[i];
				prevNearProject =
					t.cChartDrawer._convertAndTurnPoint(prevPoint.x, prevPoint.y, this.gapDepth /*+ DiffGapDepth*/);
				prevFarProject = t.cChartDrawer._convertAndTurnPoint(prevPoint.x, prevPoint.y,
					this.gapDepth + this.perspectiveDepth);

				prevNear =
					t.cChartDrawer._convertAndTurnPoint(prevPoint.x, prevPoint.y, this.gapDepth /*+ DiffGapDepth*/,
						null, null, true);
				prevFar = t.cChartDrawer._convertAndTurnPoint(prevPoint.x, prevPoint.y,
					this.gapDepth + this.perspectiveDepth, null, null, true);

				prevNotRotateNear = {x: prevPoint.x, y: prevPoint.y, z: this.gapDepth};
				prevNotRotateFar = {x: prevPoint.x, y: prevPoint.y, z: this.gapDepth + this.perspectiveDepth};

				point = breakFaces.down[i + 1];
				nearProject =
					t.cChartDrawer._convertAndTurnPoint(point.x, point.y, this.gapDepth /*+ DiffGapDepth*/);
				farProject =
					t.cChartDrawer._convertAndTurnPoint(point.x, point.y, this.gapDepth + this.perspectiveDepth);

				near = t.cChartDrawer._convertAndTurnPoint(point.x, point.y, this.gapDepth /*+ DiffGapDepth*/, null,
					null, true);
				far = t.cChartDrawer._convertAndTurnPoint(point.x, point.y, this.gapDepth + this.perspectiveDepth,
					null, null, true);

				notRotateNear = {x: point.x, y: point.y, z: this.gapDepth};
				notRotateFar = {x: point.x, y: point.y, z: this.gapDepth + this.perspectiveDepth};


				face = generateFace(prevNearProject, prevFarProject, farProject, nearProject, prevNear, prevFar, far, near, prevNotRotateNear, prevNotRotateFar, notRotateNear, notRotateFar, 1);
				this.downFaces.push(face);
			}
		} else {
			//TODO проверить и убрать
			face = generateFace(point1, point2, point3, point4, point11, point22, point33, point44, p1, p2, p3, p4, 1);
			this.downFaces.push(face);
		}

		return [];
	},

	_calculateAllIntersection: function () {
		var allPoints = this.points;
		var prevPoints;
		var nullPositionOX = this.catAx.posY * this.chartProp.pxToMM;
		var pxToMm = this.chartProp.pxToMM;

		for (var seria = 0; seria < allPoints.length; seria++) {
			var points = allPoints[seria];
			for (var i = 0; i < points.length - 1; i++) {
				var x = points[i].x * pxToMm;
				var y = points[i].y * pxToMm;
				var x1 = points[i + 1].x * pxToMm;
				var y1 = points[i + 1].y * pxToMm;

				prevPoints = this._getPrevSeriesPoints(allPoints, seria);

				//рассчитываем 8 точек для каждого ректа
				var prevX = prevPoints ? prevPoints[i].x * pxToMm : x;
				var prevY = prevPoints ? prevPoints[i].y * pxToMm : nullPositionOX;
				var prevX1 = prevPoints ? prevPoints[i + 1].x * pxToMm : x1;
				var prevY1 = prevPoints ? prevPoints[i + 1].y * pxToMm : nullPositionOX;

				if (!this.prevPoints) {
					this.prevPoints = [];
				}

				if (!this.prevPoints[i]) {
					this.prevPoints[i] = [];
				}


				var curRect = {
					point1: {x: x, y: y, z: this.gapDepth},
					point2: {x: x1, y: y1, z: this.gapDepth},
					prevPoint1: {x: prevX, y: prevY, z: this.gapDepth},
					prevPoint2: {x: prevX1, y: prevY1, z: this.gapDepth}
				};

				this._checkIntersection(curRect, i, seria);
				this.prevPoints[i][seria] = curRect;
			}
		}
	},

	_checkIntersection: function (curRect, pointIndex, seriaIndex) {
		var t = this;

		var curPoint1 = curRect.point1;
		var curPoint2 = curRect.point2;
		var curPoint3 = curRect.prevPoint1;
		var curPoint4 = curRect.prevPoint2;

		if (curPoint1.y > curPoint3.y) {
			curPoint1 = curRect.prevPoint1;
			curPoint2 = curRect.prevPoint2;
			curPoint3 = curRect.point1;
			curPoint4 = curRect.point2;
		}

		var addToArr = function (point, seria, isDown, elem) {
			if (!t.intersections[point]) {
				t.intersections[point] = [];
			}

			if (!t.intersections[point][seria]) {
				t.intersections[point][seria] = {};
			}

			if (isDown && !t.intersections[point][seria].down) {
				t.intersections[point][seria].down = [];
			}
			if (!isDown && !t.intersections[point][seria].up) {
				t.intersections[point][seria].up = [];
			}

			var arr = isDown ? t.intersections[point][seria].down : t.intersections[point][seria].up;
			arr.push(elem);
		};

		//текущая верхняя и нижняя прямая и их пересечение
		var curLine1 = this.cChartDrawer.getLineEquation(curPoint1, curPoint2);
		var curLine2 = this.cChartDrawer.getLineEquation(curPoint3, curPoint4);
		var curTempIntersection = this.cChartDrawer.isIntersectionLineAndLine(curLine1, curLine2);

		var curDown = [{start: curPoint3, end: curPoint4, eq: curLine2}];
		//если пересечения текущих прямых вписывается в границы диаграммы
		var curIntersection = null;
		if (curTempIntersection && curTempIntersection.x > curPoint3.x && curTempIntersection.x < curPoint4.x) {
			curIntersection = curTempIntersection;

			curDown[0] = {start: curPoint3, end: curIntersection, eq: curLine2};
			curDown[1] = {start: curIntersection, end: curPoint4, eq: curLine1};
		}

		var curUp = [{start: curPoint1, end: curPoint2, eq: curLine1}];
		//если пересечения текущих прямых вписывается в границы диаграммы
		curIntersection = null;
		if (curTempIntersection && curTempIntersection.x > curPoint1.x && curTempIntersection.x < curPoint2.x) {
			curIntersection = curTempIntersection;

			curUp[0] = {start: curPoint1, end: curIntersection, eq: curLine1};
			curUp[1] = {start: curIntersection, end: curPoint2, eq: curLine2};
		}


		//первая/последняя точка текущей грани, пересечение текущей грани
		if (!this.prevPoints[pointIndex].length ||
			(this.prevPoints[pointIndex].length && !this.prevPoints[pointIndex][seriaIndex])) {
			//заносим первую точку грани - ПЕРЕПРОВеРИТЬ
			addToArr(pointIndex, seriaIndex, true, curPoint3);
			addToArr(pointIndex, seriaIndex, null, curPoint1);

			//заносим текущее пересечение
			if (curIntersection) {
				addToArr(pointIndex, seriaIndex, true, curIntersection);
				addToArr(pointIndex, seriaIndex, null, curIntersection);

				//сразу заносим последнюю точку грани
				addToArr(pointIndex, seriaIndex, true, curPoint2);
				addToArr(pointIndex, seriaIndex, null, curPoint4);
			} else {
				//сразу заносим последнюю точку грани
				addToArr(pointIndex, seriaIndex, true, curPoint4);
				addToArr(pointIndex, seriaIndex, null, curPoint2);
			}
		}

		//пересечения с прямыми предыдущих серий
		var line1, line2, intersection;
		if (this.prevDown && this.prevDown[pointIndex]) {
			for (var i = 0; i < this.prevDown[pointIndex].length; i++) {
				var prevDown = this.prevDown[pointIndex][i];

				for (var j = 0; j < this.prevDown[pointIndex][i].length; j++) {
					for (var k = 0; k < curDown.length; k++) {
						line1 = this.prevDown[pointIndex][i][j];
						line2 = curDown[k];
						intersection = this.cChartDrawer.isIntersectionLineAndLine(line1.eq, line2.eq);

						if (intersection) {
							//предыдущая - i
							if (intersection.x > line1.start.x && intersection.x < line1.end.x) {
								addToArr(pointIndex, i, true, intersection);
							}

							//текущая серия
							if (intersection.x > line2.start.x && intersection.x < line2.end.x) {
								addToArr(pointIndex, seriaIndex, true, intersection);
							}
						}

					}
				}
			}
		}

		//пересечения с прямыми предыдущих серий
		if (this.prevUp && this.prevUp[pointIndex]) {
			for (var i = 0; i < this.prevUp[pointIndex].length; i++) {
				var prevUp = this.prevUp[pointIndex][i];

				for (var j = 0; j < this.prevUp[pointIndex][i].length; j++) {
					for (var k = 0; k < curUp.length; k++) {
						line1 = this.prevUp[pointIndex][i][j];
						line2 = curUp[k];
						intersection = this.cChartDrawer.isIntersectionLineAndLine(line1.eq, line2.eq);

						if (intersection) {
							//предыдущая - i
							if (intersection.x > line1.start.x && intersection.x < line1.end.x) {
								addToArr(pointIndex, i, null, intersection);
							}

							//текущая серия
							if (intersection.x > line2.start.x && intersection.x < line2.end.x) {
								addToArr(pointIndex, seriaIndex, null, intersection);
							}
						}

					}
				}
			}
		}

		if (!this.prevDown) {
			this.prevDown = [];
		}
		if (!this.prevDown[pointIndex]) {
			this.prevDown[pointIndex] = [];
		}

		this.prevDown[pointIndex][seriaIndex] = curDown;

		if (!this.prevUp) {
			this.prevUp = [];
		}
		if (!this.prevUp[pointIndex]) {
			this.prevUp[pointIndex] = [];
		}

		this.prevUp[pointIndex][seriaIndex] = curUp;
	},

	_calculateSimpleRect: function (arrPoints, arrPointsProject, point, seria) {
		var pxToMm = this.chartProp.pxToMM, t = this, paths = [];
		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;


		var point1 = arrPointsProject[0];
		var point2 = arrPointsProject[1];
		var point3 = arrPointsProject[2];
		var point4 = arrPointsProject[3];
		var point5 = arrPointsProject[4];
		var point6 = arrPointsProject[5];
		var point7 = arrPointsProject[6];
		var point8 = arrPointsProject[7];

		var point11 = arrPoints[0];
		var point22 = arrPoints[1];
		var point33 = arrPoints[2];
		var point44 = arrPoints[3];
		var point55 = arrPoints[4];
		var point66 = arrPoints[5];
		var point77 = arrPoints[6];
		var point88 = arrPoints[7];

		var insidePoint = {};
		insidePoint.x =
			(point11.x + point22.x + point33.x + point44.x + point55.x + point66.x + point77.x + point88.x) / 8;
		insidePoint.y =
			(point11.y + point22.y + point33.y + point44.y + point55.y + point66.y + point77.y + point88.y) / 8;
		insidePoint.z =
			(point11.z + point22.z + point33.z + point44.z + point55.z + point66.z + point77.z + point88.z) / 8;

		var oThis = this;
		var calculateSimpleFace = function (p1, p2, p3, p4, p11, p22, p33, p44, faceIndex) {
			var pathId = oThis.cChartSpace.AllocPath();
			var path = oThis.cChartSpace.GetPath(pathId);

			path.pathH = pathH;
			path.pathW = pathW;

			path.moveTo(p1.x / pxToMm * pathW, p1.y / pxToMm * pathH);
			path.lnTo(p2.x / pxToMm * pathW, p2.y / pxToMm * pathH);
			path.lnTo(p3.x / pxToMm * pathW, p3.y / pxToMm * pathH);
			path.lnTo(p4.x / pxToMm * pathW, p4.y / pxToMm * pathH);
			path.lnTo(p1.x / pxToMm * pathW, p1.y / pxToMm * pathH);


			var arrPoints = [p1, p2, p3, p4];
			var arrPoints2 = [p11, p22, p33, p44];
			var plainEquation = t.cChartDrawer.getPlainEquation(p11, p22, p33);
			var plainArea = t.cChartDrawer.getAreaQuadrilateral(p1, p2, p3, p4);

			if (faceIndex === 0) {
				t.sortZIndexPathsFront.push({
					seria: seria,
					point: 0,
					verge: faceIndex,
					paths: pathId,
					points: arrPoints2,
					points2: arrPoints,
					plainEquation: plainEquation,
					plainArea: plainArea,
					z: insidePoint.z
				});
			} else if (faceIndex === 5) {
				t.sortZIndexPathsBack.push({
					seria: seria,
					point: 0,
					verge: faceIndex,
					paths: pathId,
					points: arrPoints2,
					points2: arrPoints,
					plainEquation: plainEquation,
					plainArea: plainArea,
					z: insidePoint.z
				});
			} else if (faceIndex === 2) {
				t.sortZIndexPathsLeft.push({
					seria: seria,
					point: 0,
					verge: faceIndex,
					paths: pathId,
					points: arrPoints2,
					points2: arrPoints,
					plainEquation: plainEquation,
					plainArea: plainArea,
					z: insidePoint.z
				});
			} else if (faceIndex === 3) {
				t.sortZIndexPathsRight.push({
					seria: seria,
					point: 0,
					verge: faceIndex,
					paths: pathId,
					points: arrPoints2,
					points2: arrPoints,
					plainEquation: plainEquation,
					plainArea: plainArea,
					z: insidePoint.z
				});
			}

			return pathId;
		};

		//left
		paths[2] = null;
		if (this.darkFaces["left"] && point === 0) {
			paths[2] = calculateSimpleFace(point1, point2, point6, point5, point11, point22, point66, point55, 2);
		}

		//right
		paths[3] = null;
		if (this.darkFaces["right"] && point === t.cChartDrawer.calcProp.ptCount - 2) {
			paths[3] = calculateSimpleFace(point4, point8, point7, point3, point44, point88, point77, point33, 3);
		}

		//front
		if (this.darkFaces["front"]) {
			paths[0] = calculateSimpleFace(point1, point5, point8, point4, point11, point55, point88, point44, 0);
		}

		if (this.darkFaces["unfront"]) {
			paths[5] = calculateSimpleFace(point2, point6, point7, point3, point22, point66, point77, point33, 5);
		}
	},

	_getPrevSeriesPoints: function (points, i) {
		var prevPoints = null;

		for (var p = i - 1; p >= 0; p--) {
			if (points[p]) {
				prevPoints = points[p];
				break;
			}
		}

		return prevPoints;
	},

	_calculateDLbl: function (chartSpace, ser, val) {
		var pxToMm = this.chartProp.pxToMM;

		var point = this.cChartDrawer.getIdxPoint(this.chart.series[ser], val);
		var path;

		path = this.points[ser][val];

		if (!path) {
			return;
		}

		var x = path.x;
		var y = path.y;

		if (this.cChartDrawer.nDimensionCount === 3) {
			var gapDepth = this.gapDepth;
			if (this.subType === "normal") {
				gapDepth = this.gapDepth[ser];
			}

			var turnPoint = this.cChartDrawer._convertAndTurnPoint(x * pxToMm, y * pxToMm, gapDepth);
			x = turnPoint.x / pxToMm;
			y = turnPoint.y / pxToMm;
		}


		var constMargin = 5 / pxToMm;

		var width = point.compiledDlb.extX;
		var height = point.compiledDlb.extY;

		var centerX = x - width / 2;
		var centerY = y - height / 2;

		switch (point.compiledDlb.dLblPos) {
			case c_oAscChartDataLabelsPos.b: {
				centerY = centerY + height / 2 + constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.bestFit: {
				break;
			}
			case c_oAscChartDataLabelsPos.ctr: {
				break;
			}
			case c_oAscChartDataLabelsPos.l: {
				centerX = centerX - width / 2 - constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.r: {
				centerX = centerX + width / 2 + constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.t: {
				centerY = centerY - height / 2 - constMargin;
				break;
			}
		}

		if (centerX < 0) {
			centerX = 0;
		}
		if (centerX + width > this.chartProp.widthCanvas / pxToMm) {
			centerX = this.chartProp.widthCanvas / pxToMm - width;
		}

		if (centerY < 0) {
			centerY = 0;
		}
		if (centerY + height > this.chartProp.heightCanvas / pxToMm) {
			centerY = this.chartProp.heightCanvas / pxToMm - height;
		}

		return {x: centerX, y: centerY};
	},

	_drawLines: function (/*isSkip*/) {
		//ширина линии
		var brush;
		var pen;
		var seria, dataSeries, numCache;

		this.cChartDrawer.cShapeDrawer.Graphics.SaveGrState();
		this.cChartDrawer.cShapeDrawer.Graphics.AddClipRect(
			this.chartProp.chartGutter._left / this.chartProp.pxToMM,
			(this.chartProp.chartGutter._top - 1) / this.chartProp.pxToMM,
			this.chartProp.trueWidth / this.chartProp.pxToMM, this.chartProp.trueHeight / this.chartProp.pxToMM);

		for (var i = 0; i < this.chart.series.length; i++) {
			seria = this.chart.series[i];
			numCache = this.cChartDrawer.getNumCache(seria.val);
			dataSeries = numCache && numCache.pts ? numCache.pts : null;

			if (!dataSeries) {
				continue;
			}

			if (dataSeries[0] && dataSeries[0].pen) {
				pen = dataSeries[0].pen;
			}
			if (dataSeries[0] && dataSeries[0].brush) {
				brush = dataSeries[0].brush;
			}

			if (this.cChartDrawer.nDimensionCount === 3) {
				for (var j = 0; j < this.paths.series[i].length; j++) {
					this.cChartDrawer.drawPath(this.paths.series[i][j], pen, brush);
				}
			} else {
				this.cChartDrawer.drawPath(this.paths.series[i], pen, brush);
			}
		}

		this.cChartDrawer.cShapeDrawer.Graphics.RestoreGrState();
	},

	_getYVal: function (n, i) {
		var tempVal;
		var val = 0;
		var idxPoint;

		if (this.subType === "stacked") {
			for (var k = 0; k <= i; k++) {
				idxPoint = this.cChartDrawer.getPointByIndex(this.chart.series[k], n);
				tempVal = idxPoint ? parseFloat(idxPoint.val) : 0;
				if (tempVal) {
					val += tempVal;
				}
			}
		} else if (this.subType === "stackedPer") {
			var summVal = 0;
			for (var k = 0; k < this.chart.series.length; k++) {
				idxPoint = this.cChartDrawer.getPointByIndex(this.chart.series[k], n);
				tempVal = idxPoint ? parseFloat(idxPoint.val) : 0;
				if (tempVal) {
					if (k <= i) {
						val += tempVal;
					}
					summVal += Math.abs(tempVal);
				}
			}
			val = val / summVal;
		} else {
			idxPoint = this.cChartDrawer.getPointByIndex(this.chart.series[i], n);
			val = idxPoint ? parseFloat(idxPoint.val) : null;
		}
		return val;
	},

	_drawLines3D: function (/*isSkip*/) {
		//ширина линии
		var brush;
		var pen;
		var seria, dataSeries, numCache;

		this.cChartDrawer.cShapeDrawer.Graphics.SaveGrState();
		this.cChartDrawer.cShapeDrawer.Graphics.AddClipRect(
			this.chartProp.chartGutter._left / this.chartProp.pxToMM,
			(this.chartProp.chartGutter._top - 1) / this.chartProp.pxToMM,
			this.chartProp.trueWidth / this.chartProp.pxToMM, this.chartProp.trueHeight / this.chartProp.pxToMM);

		for (var i = 0; i < this.chart.series.length; i++) {

			//в случае накопительных дигарамм, рисуем в обратном порядке
			/*if(this.chartProp.subType == "stackedPer" || this.chartProp.subType == "stacked")
			 seria = this.chartProp.series[this.chartProp.series.length - 1 - i];
			 else*/
			seria = this.chart.series[i];
			numCache = this.cChartDrawer.getNumCache(seria.val);
			dataSeries = numCache && numCache.pts ? numCache.pts : null;

			if (!dataSeries) {
				continue;
			}

			if (dataSeries[0] && dataSeries[0].pen) {
				pen = dataSeries[0].pen;
			}
			if (dataSeries[0] && dataSeries[0].brush) {
				brush = dataSeries[0].brush;
			}

			for (var j = 0; j < this.paths.series[i].length; j++) {
				this.cChartDrawer.drawPath(this.paths.series[i][j], pen, brush);
			}
		}

		this.cChartDrawer.cShapeDrawer.Graphics.RestoreGrState();
	},

	_drawBar3D: function (path, pen, brush, k) {
		//затемнение боковых сторон
		//в excel всегда темные боковые стороны, лицевая и задняя стороны светлые
		//pen = this.cChartSpace.chart.plotArea.valAx.compiledMajorGridLines;
		//pen.setFill(brush);
		pen = AscFormat.CreatePenFromParams(brush, undefined, undefined, undefined, undefined, 0.2);
		if (k !== 5 && k !== 0) {
			var props = this.cChartSpace.getParentObjects();

			if (brush.fill.type === Asc.c_oAscFill.FILL_TYPE_NOFILL) {
				return;
			}

			var duplicateBrush = brush.createDuplicate();
			var cColorMod = new AscFormat.CColorMod;
			if (k === 1 || k === 4) {
				cColorMod.val = 45000;
			} else {
				cColorMod.val = 35000;
			}
			cColorMod.name = "shade";
			duplicateBrush.fill.color.Mods.addMod(cColorMod);
			duplicateBrush.calculate(props.theme, props.slide, props.layout, props.master,
				new AscFormat.CUniColor().RGBA, this.cChartSpace.clrMapOvr);

			pen.setFill(duplicateBrush);
			if (path && path.length) {
				for (var i = 0; i < path.length; i++) {
					this.cChartDrawer.drawPath(path[i], pen, duplicateBrush);
				}
			} else {
				this.cChartDrawer.drawPath(path, pen, duplicateBrush);
			}
		} else {
			if (path && path.length) {
				for (var i = 0; i < path.length; i++) {
					this.cChartDrawer.drawPath(path[i], pen, brush);
				}
			} else {
				this.cChartDrawer.drawPath(path, pen, brush);
			}
		}
	},

	_drawBars3D: function () {
		var t = this;
		var isStacked = this.subType === "stackedPer" || this.subType === "stacked";

		if (!isStacked) {
			var angle = Math.abs(this.cChartDrawer.processor3D.angleOy);
			var seria, brush, pen, numCache;
			if (!this.cChartDrawer.processor3D.view3D.getRAngAx() && angle > Math.PI / 2 &&
				angle < 3 * Math.PI / 2) {
				for (var j = 0; j < this.paths.series.length; j++) {
					seria = this.chart.series[j];
					brush = seria.brush;
					pen = seria.pen;

					numCache = this.cChartDrawer.getNumCache(seria.val);
					if (numCache && numCache.pts[0].pen) {
						pen = numCache.pts[0].pen;
					}
					if (numCache && numCache.pts[0].brush) {
						brush = numCache.pts[0].brush;
					}

					this._drawBar3D(this.paths.series[j][1], pen, brush, 1);
					this._drawBar3D(this.paths.series[j][4], pen, brush, 4);
					this._drawBar3D(this.paths.series[j][2], pen, brush, 2);
					this._drawBar3D(this.paths.series[j][3], pen, brush, 3);
					this._drawBar3D(this.paths.series[j][5], pen, brush, 5);
					this._drawBar3D(this.paths.series[j][0], pen, brush, 0);
				}
			} else {
				for (var j = this.paths.series.length - 1; j >= 0; j--) {
					seria = this.chart.series[j];
					brush = seria.brush;
					pen = seria.pen;

					numCache = this.cChartDrawer.getNumCache(seria.val);
					if (numCache.pts[0].pen) {
						pen = numCache.pts[0].pen;
					}
					if (numCache.pts[0].brush) {
						brush = numCache.pts[0].brush;
					}

					this._drawBar3D(this.paths.series[j][1], pen, brush, 1);
					this._drawBar3D(this.paths.series[j][4], pen, brush, 4);
					this._drawBar3D(this.paths.series[j][2], pen, brush, 2);
					this._drawBar3D(this.paths.series[j][3], pen, brush, 3);
					this._drawBar3D(this.paths.series[j][5], pen, brush, 5);
					this._drawBar3D(this.paths.series[j][0], pen, brush, 0);
				}
			}


		} else {
			var drawVerges = function (i, j, paths, onlyLessNull, k) {
				var brush, pen, options;
				options = t._getOptionsForDrawing(i, j, onlyLessNull);
				if (paths !== null && options !== null) {
					pen = options.pen;
					brush = options.brush;

					t._drawBar3D(paths, pen, brush, k);
				}
			};

			//if(this.cChartDrawer.processor3D.view3D.rAngAx)
			//{
			for (var i = 0; i < this.sortZIndexPaths.length; i++) {
				drawVerges(this.sortZIndexPaths[i].seria, this.sortZIndexPaths[i].point, this.sortZIndexPaths[i].paths, null, this.sortZIndexPaths[i].verge);
			}
			//}
		}
	},

	_getOptionsForDrawing: function (ser, point, onlyLessNull) {
		var seria = this.chart.series[ser];
		var numCache = this.cChartDrawer.getNumCache(seria.val);
		if(!numCache) {
			return null;
		}

		var pt = numCache.getPtByIndex(point);
		if (!seria || !this.paths.series[ser] || !this.paths.series[ser][point] || !pt) {
			return null;
		}

		var brush = seria.brush;
		var pen = seria.pen;

		if ((pt.val > 0 && onlyLessNull === true) || (pt.val < 0 && onlyLessNull === false)) {
			return null;
		}

		if (pt.pen) {
			pen = pt.pen;
		}
		if (pt.brush) {
			brush = pt.brush;
		}

		return {pen: pen, brush: brush}
	},

	_isVisibleVerge3D: function (k, n, m) {
		//roberts method - calculate normal
		var aX = n.x * m.y - m.x * n.y;
		var bY = -(k.x * m.y - m.x * k.y);
		var cZ = k.x * n.y - n.x * k.y;
		var visible = aX + bY + cZ;

		return visible < 0;
	},

	_getIntersectionLines: function (line1Point1, line1Point2, line2Point1, line2Point2) {
		var chartHeight = this.chartProp.trueHeight;
		var top = this.chartProp.chartGutter._top;

		var x1 = line1Point1.x;
		var x2 = line1Point2.x;
		var y1 = line1Point1.y;
		var y2 = line1Point2.y;

		var x3 = line2Point1.x;
		var x4 = line2Point2.x;
		var y3 = line2Point1.y;
		var y4 = line2Point2.y;

		var x = ((x1 * y2 - x2 * y1) * (x4 - x3) - (x3 * y4 - x4 * y3) * (x2 - x1)) /
			((y1 - y2) * (x4 - x3) - (y3 - y4) * (x2 - x1));
		var y = ((y3 - y4) * x - (x3 * y4 - x4 * y3)) / (x4 - x3);

		x = -x;

		var res = null;

		if (y < top + chartHeight && y > top && x > line1Point1.x && x < line1Point2.x) {
			res = {x: x, y: y};
		}

		return res;
	}
};


/** @constructor */
function drawHBarChart(chart, chartsDrawer) {
	this.chartProp = chartsDrawer.calcProp;
	this.cChartDrawer = chartsDrawer;
	this.cChartSpace = chartsDrawer.cChartSpace;

	this.chart = chart;
	this.catAx = null;
	this.valAx = null;
	this.ptCount = null;
	this.seriesCount = null;
	this.subType = null;

	this.paths = {};
	this.sortZIndexPaths = [];

	this.summBarVal = [];
}

drawHBarChart.prototype = {
	constructor: drawHBarChart,

	recalculate: function () {
		this.paths = {};
		this.summBarVal = [];

		this.sortZIndexPaths = [];

		var countSeries = this.cChartDrawer.calculateCountSeries(this.chart);
		this.seriesCount = countSeries.series;
		this.ptCount = countSeries.points;
		this.subType = this.cChartDrawer.getChartGrouping(this.chart);
		this.catAx = this.cChartDrawer.getAxisFromAxId(this.chart.axId, AscDFH.historyitem_type_CatAx);
		if(!this.catAx) {
			this.catAx = this.cChartDrawer.getAxisFromAxId(this.chart.axId, AscDFH.historyitem_type_DateAx);
		}
		this.valAx = this.cChartDrawer.getAxisFromAxId(this.chart.axId, AscDFH.historyitem_type_ValAx);

		this._recalculateBars();
	},

	draw: function () {
		if (this.cChartDrawer.nDimensionCount === 3) {
			this._DrawBars3D();
		} else {
			this._drawBars();
		}
	},

	_recalculateBars: function (/*isSkip*/) {
		//соответствует подписям оси категорий(OX)
		var xPoints = this.valAx.xPoints;
		var yPoints = this.catAx.yPoints;

		var heightGraph = this.chartProp.heightCanvas - this.chartProp.chartGutter._top - this.chartProp.chartGutter._bottom;

		var defaultOverlap = (this.subType === "stacked" || this.subType === "stackedPer") ? 100 : 0;
		var overlap = AscFormat.isRealNumber(this.chart.overlap) ? this.chart.overlap : defaultOverlap;
		var ptCount = this.cChartDrawer.getPtCount(this.chart.series);
		var height = heightGraph / ptCount;
		var crossBetween = this.cChartSpace.getValAxisCrossType();
		if (crossBetween) {
			height = heightGraph / (ptCount - 1);
		}

		var gapWidth = AscFormat.isRealNumber(this.chart.gapWidth) ? this.chart.gapWidth : 150;

		var individualBarHeight = height /
			(this.seriesCount - (this.seriesCount - 1) * (overlap / 100) + gapWidth / 100);
		var widthOverLap = individualBarHeight * (overlap / 100);
		var hmargin = (gapWidth / 100 * individualBarHeight) / 2;

		var width, startX, startY, val, paths, seriesHeight = [], seria, startXColumnPosition, startYPosition, newStartX, newStartY, idx, seriesCounter = 0, numCache;

		//for 3d
		var perspectiveDepth, gapDepth, DiffGapDepth;
		if (this.cChartDrawer.nDimensionCount === 3) {
			perspectiveDepth = this.cChartDrawer.processor3D.depthPerspective;
			//сдвиг по OZ в глубину
			gapDepth = this.chart.gapDepth != null ? this.chart.gapDepth : globalGapDepth;
			perspectiveDepth = perspectiveDepth / (gapDepth / 100 + 1);
			DiffGapDepth = perspectiveDepth * (gapDepth / 2) / 100;
		}

		var cubeCount = 0;
		for (var i = 0; i < this.chart.series.length; i++) {
			numCache = this.cChartDrawer.getNumCache(this.chart.series[i].val);

			if (!numCache || this.chart.series[i].isHidden) {
				continue;
			}

			seria = numCache.pts;
			seriesHeight[i] = [];


			var isValMoreZero = false;
			var isValLessZero = 0;
			for (var j = 0; j < seria.length; j++) {
				//стартовая позиция колонки Y(+ высота с учётом поправок на накопительные диаграммы)
				val = parseFloat(seria[j].val);

				if (val > 0) {
					isValMoreZero = true;
				} else if (val < 0) {
					isValLessZero++;
				}

				if (this.valAx && this.valAx.scaling.logBase) {
					val = this.cChartDrawer.getLogarithmicValue(val, this.valAx.scaling.logBase, xPoints);
				}
				idx = seria[j].idx != null ? seria[j].idx : j;


				startXColumnPosition = this._getStartYColumnPosition(seriesHeight, idx, i, val, xPoints);
				startX = startXColumnPosition.startY / this.chartProp.pxToMM;
				width = startXColumnPosition.width / this.chartProp.pxToMM;

				seriesHeight[i][idx] = startXColumnPosition.width;


				//стартовая позиция колонки Y
				if (this.catAx.scaling.orientation === ORIENTATION_MIN_MAX) {
					if (yPoints[1] && yPoints[1].pos && yPoints[j]) {
						startYPosition = yPoints[j].pos + Math.abs((yPoints[1].pos - yPoints[0].pos) / 2);
					} else if(yPoints[j]){
						startYPosition = yPoints[j].pos + Math.abs(yPoints[0].pos - this.valAx.posY);
					} else {
						startYPosition = yPoints[0].pos + Math.abs(yPoints[0].pos - this.valAx.posY);
					}
				} else {
					if (yPoints[1] && yPoints[1].pos && yPoints[j]) {
						startYPosition = yPoints[j].pos - Math.abs((yPoints[1].pos - yPoints[0].pos) / 2);
					} else if(yPoints[j]){
						startYPosition = yPoints[j].pos - Math.abs(yPoints[0].pos - this.valAx.posY);
					} else {
						startYPosition = yPoints[0].pos - Math.abs(yPoints[0].pos - this.valAx.posY);
					}
				}


				if (this.catAx.scaling.orientation === ORIENTATION_MIN_MAX) {
					if (seriesCounter === 0) {
						startY = startYPosition * this.chartProp.pxToMM - hmargin - seriesCounter * (individualBarHeight);
					} else {
						startY = startYPosition * this.chartProp.pxToMM - hmargin - (seriesCounter * individualBarHeight - seriesCounter * widthOverLap);
					}
				} else {
					if (i === 0) {
						startY = startYPosition * this.chartProp.pxToMM + hmargin + seriesCounter * (individualBarHeight);
					} else {
						startY = startYPosition * this.chartProp.pxToMM + hmargin + (seriesCounter * individualBarHeight - seriesCounter * widthOverLap);
					}
				}

				newStartY = startY;
				if (this.catAx.scaling.orientation !== ORIENTATION_MIN_MAX) {
					newStartY = startY + individualBarHeight;
				}

				newStartX = startX;
				if (this.valAx.scaling.orientation !== ORIENTATION_MIN_MAX &&
					(this.subType === "stackedPer" || this.subType === "stacked")) {
					newStartX = startX - width;
				}

				if (this.cChartDrawer.nDimensionCount === 3) {
					paths = this.calculateParallalepiped(newStartX, newStartY, val, width, DiffGapDepth, perspectiveDepth, individualBarHeight, seriesHeight, i, idx, cubeCount);
					cubeCount++;
				} else {
					paths = this._calculateRect(newStartX, newStartY / this.chartProp.pxToMM, width, individualBarHeight / this.chartProp.pxToMM);
				}


				if (!this.paths.series) {
					this.paths.series = [];
				}
				if (!this.paths.series[i]) {
					this.paths.series[i] = [];
				}

				if (height !== 0) {
					this.paths.series[i][idx] = paths;
				}
			}

			if (seria.length) {
				seriesCounter++;
			}
		}

		if (this.cChartDrawer.nDimensionCount === 3) {
			if (this.cChartDrawer.processor3D.view3D.getRAngAx()) {
				var angle = Math.abs(this.cChartDrawer.processor3D.angleOy);
				this.sortZIndexPaths.sort(function sortArr(a, b) {
					if (b.zIndex === a.zIndex) {
						if (angle < Math.PI) {
							return a.x - b.x;
						} else {
							return b.x - a.x;
						}
					} else {
						return b.zIndex - a.zIndex;
					}
				});
			} else {
				var cSortFaces = new window['AscFormat'].CSortFaces(this.cChartDrawer);
				//this.sortZIndexPaths = cSortFaces.sortFaces(this.sortZIndexPaths);
				this.sortParallelepipeds = cSortFaces.sortParallelepipeds(this.temp, this.sortZIndexPaths);
			}
		}
	},

	_calculateLine: function (x, y, x1, y1) {
		var pxToMm = this.chartProp.pxToMM;

		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;

		path.moveTo(x / pxToMm * pathW, y / pxToMm * pathH);
		path.lnTo(x1 / pxToMm * pathW, y1 / pxToMm * pathH);

		return pathId;
	},

	_getOptionsForDrawing: function (ser, point, onlyLessNull) {
		var seria = this.chart.series[ser];
		var numCache = this.cChartDrawer.getNumCache(seria.val);
		if(!numCache) {
			return null;
		}

		var pt = numCache.getPtByIndex(point);
		if (!seria || !this.paths.series[ser] || !this.paths.series[ser][point] || !pt) {
			return null;
		}

		var brush = seria.brush;
		var pen = seria.pen;

		if ((pt.val > 0 && onlyLessNull === true) || (pt.val < 0 && onlyLessNull === false)) {
			return null;
		}

		if (pt.pen) {
			pen = pt.pen;
		}
		if (pt.brush) {
			brush = pt.brush;
		}

		return {pen: pen, brush: brush}
	},

	_getStartYColumnPosition: function (seriesHeight, j, i, val, xPoints) {
		var startY, width, curVal, prevVal, endBlockPosition, startBlockPosition;
		var catAx = this.catAx;

		var axisMin = xPoints[0].val < xPoints[xPoints.length - 1].val ? xPoints[0].val : xPoints[xPoints.length - 1].val;
		var axisMax = xPoints[0].val < xPoints[xPoints.length - 1].val ? xPoints[xPoints.length - 1].val : xPoints[0].val;

		//в ms отрисовка сделана следующим образом: если диаграмма типа normal, то стартовую точку отрисовки столбцов берем позицию X оси категорий(posX)
		//если диаграмма типа stacked то рисуем от позиции X ноля оси категорий - getPositionZero(позиция ноля и оси могут отличиться в зависимости от настроек)
		var nullPositionOX = this.subType === "stacked" ? this.cChartDrawer.getPositionZero(this.valAx) : catAx.posX * this.chartProp.pxToMM;

		if (this.subType === "stacked" || this.subType === "stackedPer") {
			curVal = this._getStackedValue(this.chart.series, i, j, val);
			prevVal = this._getStackedValue(this.chart.series, i - 1, j, val);

			if (this.subType === "stacked") {
				//если максимальное значение задано вручную, и присутвуют точки, которые больше этого значения
				if (curVal > axisMax) {
					curVal = axisMax;
				}
				if (curVal < axisMin) {
					curVal = axisMin;
				}

				endBlockPosition = this.cChartDrawer.getYPosition(curVal, this.valAx) * this.chartProp.pxToMM;
				startBlockPosition = prevVal ? this.cChartDrawer.getYPosition(prevVal, this.valAx) * this.chartProp.pxToMM : nullPositionOX;
			} else {
				this._calculateSummStacked(j);

				var test = this.summBarVal[j];

				//если максимальное значение задано вручную, и присутвуют точки, которые больше этого значения
				if (curVal / test > axisMax) {
					curVal = axisMax * test;
				}
				if (curVal / test < axisMin) {
					curVal = axisMin * test;
				}

				if (prevVal / test > axisMax) {
					prevVal = axisMax * test;
				}
				if (prevVal / test < axisMin) {
					prevVal = axisMin * test;
				}

				endBlockPosition = this.cChartDrawer.getYPosition((curVal / test), this.valAx) * this.chartProp.pxToMM;
				startBlockPosition = test ? this.cChartDrawer.getYPosition((prevVal / test), this.valAx) * this.chartProp.pxToMM : nullPositionOX;
			}

			startY = startBlockPosition;
			width = endBlockPosition - startBlockPosition;

			if (this.valAx.scaling.orientation !== ORIENTATION_MIN_MAX) {
				width = -width;
			}
		} else {
			width = this.cChartDrawer.getYPosition(val, this.valAx) * this.chartProp.pxToMM - nullPositionOX;
			startY = nullPositionOX;
		}

		return {startY: startY, width: width};
	},

	_calculateSummStacked: function (j) {
		if (!this.summBarVal[j]) {
			var curVal;
			var temp = 0, idxPoint;
			for (var k = 0; k < this.chart.series.length; k++) {
				idxPoint = this.cChartDrawer.getIdxPoint(this.chart.series[k], j);
				curVal = idxPoint ? parseFloat(idxPoint.val) : 0;

				if (curVal) {
					temp += Math.abs(curVal);
				}
			}
			this.summBarVal[j] = temp;
		}
	},

	_getStackedValue: function (series, i, j, val) {
		var result = 0, curVal, idxPoint;
		for (var k = 0; k <= i; k++) {
			idxPoint = this.cChartDrawer.getIdxPoint(series[k], j);
			curVal = idxPoint ? idxPoint.val : 0;

			if (idxPoint && val > 0 && curVal > 0) {
				result += parseFloat(curVal);
			} else if (idxPoint && val < 0 &&
				curVal < 0) {
				result += parseFloat(curVal);
			}
		}

		return result;
	},

	_drawBars: function () {
		this.cChartDrawer.cShapeDrawer.Graphics.SaveGrState();
		this.cChartDrawer.cShapeDrawer.Graphics.AddClipRect((this.chartProp.chartGutter._left - 1) / this.chartProp.pxToMM, (this.chartProp.chartGutter._top - 1) / this.chartProp.pxToMM, this.chartProp.trueWidth / this.chartProp.pxToMM, this.chartProp.trueHeight / this.chartProp.pxToMM);
		this.cChartDrawer.drawPaths(this.paths, this.chart.series);
		this.cChartDrawer.cShapeDrawer.Graphics.RestoreGrState();
	},

	_calculateDLbl: function (chartSpace, ser, val) {
		var point = this.cChartDrawer.getIdxPoint(this.chart.series[ser], val);
		var path = this.paths.series[ser][val];

		if (this.cChartDrawer.nDimensionCount === 3 && this.paths.series[ser][val].frontPaths) {
			var frontPaths = this.paths.series[ser][val].frontPaths;
			if (this.cChartDrawer.nDimensionCount === 3) {
				if (AscFormat.isRealNumber(frontPaths[0])) {
					path = frontPaths[0];
				} else if (AscFormat.isRealNumber(frontPaths[5])) {
					path = frontPaths[5];
				} else if (AscFormat.isRealNumber(frontPaths[2])) {
					path = frontPaths[2];
				} else if (AscFormat.isRealNumber(frontPaths[3])) {
					path = frontPaths[3];
				}
			}
		}

		if (!AscFormat.isRealNumber(path)) {
			return;
		}
		var oPath = this.cChartSpace.GetPath(path);
		var oCommand0 = oPath.getCommandByIndex(0);
		var oCommand1 = oPath.getCommandByIndex(1);
		var oCommand2 = oPath.getCommandByIndex(2);


		var x = oCommand0.X;
		var y = oCommand0.Y;

		var h = oCommand0.Y - oCommand1.Y;
		var w = oCommand2.X - oCommand1.X;

		var pxToMm = this.chartProp.pxToMM;

		var width = point.compiledDlb.extX;
		var height = point.compiledDlb.extY;

		var centerX, centerY;

		switch (point.compiledDlb.dLblPos) {
			case c_oAscChartDataLabelsPos.bestFit: {
				break;
			}
			case c_oAscChartDataLabelsPos.ctr: {
				centerX = x + w / 2 - width / 2;
				centerY = y - h / 2 - height / 2;
				break;
			}
			case c_oAscChartDataLabelsPos.inBase: {
				centerX = x;
				centerY = y - h / 2 - height / 2;
				if (point.val < 0) {
					centerX = x - width;
				}
				break;
			}
			case c_oAscChartDataLabelsPos.inEnd: {
				centerX = x + w - width;
				centerY = y - h / 2 - height / 2;
				if (point.val < 0) {
					centerX = x + w;
				}
				break;
			}
			case c_oAscChartDataLabelsPos.outEnd: {
				centerX = x + w;
				centerY = y - h / 2 - height / 2;
				if (point.val < 0) {
					centerX = x + w - width;
				}
				break;
			}
		}

		if (centerX < 0) {
			centerX = 0;
		}
		if (centerX + width > this.chartProp.widthCanvas / pxToMm) {
			centerX = this.chartProp.widthCanvas / pxToMm - width;
		}

		if (centerY < 0) {
			centerY = 0;
		}
		if (centerY + height > this.chartProp.heightCanvas / pxToMm) {
			centerY = this.chartProp.heightCanvas / pxToMm - height;
		}

		return {x: centerX, y: centerY};
	},

	_calculateRect: function (x, y, w, h) {
		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;

		path.moveTo(x * pathW, y * pathH);
		path.lnTo(x * pathW, (y - h) * pathH);
		path.lnTo((x + w) * pathW, (y - h) * pathH);
		path.lnTo((x + w) * pathW, y * pathH);
		path.lnTo(x * pathW, y * pathH);
		return pathId;
	},

	calculateParallalepiped: function (newStartX, newStartY, val, width, DiffGapDepth, perspectiveDepth,
									   individualBarHeight, seriesHeight, i, idx, cubeCount) {
		var paths;
		var point1, point2, point3, point4, point5, point6, point7, point8;
		var x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, x5, y5, z5, x6, y6, z6, x7, y7, z7, x8, y8, z8;
		var xPoints = this.valAx.xPoints;

		var scaleAxis = this.valAx.scale;
		var axisMax = scaleAxis[0] < scaleAxis[scaleAxis.length - 1] ? scaleAxis[scaleAxis.length - 1] : scaleAxis[0];

		width = width * this.chartProp.pxToMM;
		newStartX = newStartX * this.chartProp.pxToMM;
		newStartY = newStartY - individualBarHeight;

		//рассчитываем 8 точек для каждого столбца
		x1 = newStartX, y1 = newStartY, z1 = DiffGapDepth;
		x2 = newStartX, y2 = newStartY, z2 = perspectiveDepth + DiffGapDepth;
		x3 = newStartX + width, y3 = newStartY, z3 = perspectiveDepth + DiffGapDepth;
		x4 = newStartX + width, y4 = newStartY, z4 = DiffGapDepth;
		x5 = newStartX, y5 = newStartY + individualBarHeight, z5 = DiffGapDepth;
		x6 = newStartX, y6 = newStartY + individualBarHeight, z6 = perspectiveDepth + DiffGapDepth;
		x7 = newStartX + width, y7 = newStartY + individualBarHeight, z7 = perspectiveDepth + DiffGapDepth;
		x8 = newStartX + width, y8 = newStartY + individualBarHeight, z8 = DiffGapDepth;

		//поворот относительно осей
		point1 = this.cChartDrawer._convertAndTurnPoint(x1, y1, z1);
		point2 = this.cChartDrawer._convertAndTurnPoint(x2, y2, z2);
		point3 = this.cChartDrawer._convertAndTurnPoint(x3, y3, z3);
		point4 = this.cChartDrawer._convertAndTurnPoint(x4, y4, z4);
		point5 = this.cChartDrawer._convertAndTurnPoint(x5, y5, z5);
		point6 = this.cChartDrawer._convertAndTurnPoint(x6, y6, z6);
		point7 = this.cChartDrawer._convertAndTurnPoint(x7, y7, z7);
		point8 = this.cChartDrawer._convertAndTurnPoint(x8, y8, z8);

		var points = [point1, point2, point3, point4, point5, point6, point7, point8];
		paths = this.cChartDrawer.calculateRect3D(points, val, null, true);

		if (this.cChartDrawer.processor3D.view3D.getRAngAx()) {
			var controlPoint1 = this.cChartDrawer._convertAndTurnPoint(x5 + width / 2, y5 - individualBarHeight / 2,
				z5);
			var controlPoint2 = this.cChartDrawer._convertAndTurnPoint(x5 + width / 2, y5,
				z5 + perspectiveDepth / 2);
			var controlPoint3 = this.cChartDrawer._convertAndTurnPoint(x5, y5 - individualBarHeight / 2,
				z5 + perspectiveDepth / 2);
			var controlPoint4 = this.cChartDrawer._convertAndTurnPoint(x8, y8 - individualBarHeight / 2,
				z8 + perspectiveDepth / 2);
			var controlPoint5 = this.cChartDrawer._convertAndTurnPoint(x1 + width / 2, y1,
				z1 + perspectiveDepth / 2);
			var controlPoint6 = this.cChartDrawer._convertAndTurnPoint(x6 + width / 2, y6 - individualBarHeight / 2,
				z6);

			var sortPaths = [controlPoint1, controlPoint2, controlPoint3, controlPoint4, controlPoint5,
				controlPoint6];

			for (var k = 0; k < paths.frontPaths.length; k++) {
				this.sortZIndexPaths.push({
					seria: i,
					point: idx,
					verge: k,
					frontPaths: paths.frontPaths[k],
					darkPaths: paths.darkPaths[k],
					x: sortPaths[k].x,
					y: sortPaths[k].y,
					zIndex: sortPaths[k].z
				});
			}
		} else {
			//рассчитываем 8 точек для каждого столбца одинакового размера для рассчета положения столбцов
			if (this.subType === "normal") {
				var startXColumnPosition = this._getStartYColumnPosition(seriesHeight, idx, i, axisMax, xPoints);
				width = startXColumnPosition.width / this.chartProp.pxToMM;

				x3 = newStartX + width, y3 = newStartY, z3 = perspectiveDepth + DiffGapDepth;
				x4 = newStartX + width, y4 = newStartY, z4 = DiffGapDepth;
				x7 = newStartX + width, y7 = newStartY + individualBarHeight, z7 = perspectiveDepth + DiffGapDepth;
				x8 = newStartX + width, y8 = newStartY + individualBarHeight, z8 = DiffGapDepth;

				point3 = this.cChartDrawer._convertAndTurnPoint(x3, y3, z3);
				point4 = this.cChartDrawer._convertAndTurnPoint(x4, y4, z4);
				point7 = this.cChartDrawer._convertAndTurnPoint(x7, y7, z7);
				point8 = this.cChartDrawer._convertAndTurnPoint(x8, y8, z8);
			}

			//не проецируем на плоскость
			var point11 = this.cChartDrawer._convertAndTurnPoint(x1, y1, z1, null, null, true);
			var point22 = this.cChartDrawer._convertAndTurnPoint(x2, y2, z2, null, null, true);
			var point33 = this.cChartDrawer._convertAndTurnPoint(x3, y3, z3, null, null, true);
			var point44 = this.cChartDrawer._convertAndTurnPoint(x4, y4, z4, null, null, true);
			var point55 = this.cChartDrawer._convertAndTurnPoint(x5, y5, z5, null, null, true);
			var point66 = this.cChartDrawer._convertAndTurnPoint(x6, y6, z6, null, null, true);
			var point77 = this.cChartDrawer._convertAndTurnPoint(x7, y7, z7, null, null, true);
			var point88 = this.cChartDrawer._convertAndTurnPoint(x8, y8, z8, null, null, true);


			var arrPoints = [[point1, point4, point8, point5], [point1, point2, point3, point4],
				[point1, point2, point6, point5], [point4, point8, point7, point3],
				[point5, point6, point7, point8], [point6, point2, point3, point7]];

			var arrPoints2 = [[point11, point44, point88, point55], [point11, point22, point33, point44],
				[point11, point22, point66, point55], [point44, point88, point77, point33],
				[point55, point66, point77, point88], [point66, point22, point33, point77]];


			if (!this.temp) {
				this.temp = [];
			}
			if (!this.temp[cubeCount]) {
				this.temp[cubeCount] = {};
			}
			if (!this.temp[cubeCount].faces) {
				this.temp[cubeCount].faces = [];
				this.temp[cubeCount].arrPoints =
					[point11, point22, point33, point44, point55, point66, point77, point88];
				this.temp[cubeCount].z = point11.z;
			}

			for (var k = 0; k < paths.frontPaths.length; k++) {
				if (null === paths.frontPaths[k] && null === paths.darkPaths[k]) {
					continue;
				}

				//this.sortZIndexPaths.push({seria: i, point: idx, verge: k, paths: paths[k], points: arrPoints2[k], points2: arrPoints[k], plainEquation: plainEquation});

				var plainEquation = this.cChartDrawer.getPlainEquation(arrPoints2[k][0], arrPoints2[k][1], arrPoints2[k][2], arrPoints2[k][3]);
				var plainArea = this.cChartDrawer.getAreaQuadrilateral(arrPoints[k][0], arrPoints[k][1], arrPoints[k][2], arrPoints[k][3]);
				this.temp[cubeCount].faces.push({
					seria: i,
					point: idx,
					verge: k,
					frontPaths: paths.frontPaths[k],
					darkPaths: paths.darkPaths[k],
					points: arrPoints2[k],
					points2: arrPoints[k],
					plainEquation: plainEquation,
					plainArea: plainArea
				});
			}
		}

		return paths;
	},

	//TODO delete after test
	_DrawBars3D2: function () {
		var t = this;
		var draw = function (onlyLessNull) {
			var brush, pen, options;
			for (var i = 0; i < t.ptCount; i++) {
				if (!t.paths.series) {
					return;
				}

				for (var j = 0; j < t.paths.series.length; ++j) {
					options = t._getOptionsForDrawing(j, i, onlyLessNull);
					if (options !== null) {
						pen = options.pen;
						brush = options.brush;
					} else {
						continue;
					}

					for (var k = 0; k < t.paths.series[j][i].length; k++) {
						t._drawBar3D(t.paths.series[j][i][k], pen, brush, k);
					}
				}
			}
		};

		var drawReverse = function (onlyLessNull) {
			var brush, pen, options;
			for (var i = 0; i < t.ptCount; i++) {
				if (!t.paths.series) {
					return;
				}

				for (var j = t.paths.series.length - 1; j >= 0; --j) {
					options = t._getOptionsForDrawing(j, i, onlyLessNull);
					if (options !== null) {
						pen = options.pen;
						brush = options.brush;
					} else {
						continue;
					}

					for (var k = 0; k < t.paths.series[j][i].length; k++) {
						t._drawBar3D(t.paths.series[j][i][k], pen, brush, k);
					}
				}
			}
		};

		if (this.subType === "stacked" || this.subType === "stackedPer") {
			if (this.valAx.scaling.orientation === ORIENTATION_MIN_MAX) {
				drawReverse(true);
				draw(false);
			} else {
				drawReverse(false);
				draw(true);
			}
		} else {
			if (this.catAx.scaling.orientation === ORIENTATION_MIN_MAX) {
				draw();
			} else {
				drawReverse();
			}
		}
	},


	_DrawBars3D3: function () {
		var t = this;

		var verges = {
			front: 0, down: 1, left: 2, right: 3, up: 4, unfront: 5
		};

		var drawVerges = function (i, j, paths, onlyLessNull, start, stop) {
			var brush, pen, options;
			options = t._getOptionsForDrawing(i, j, onlyLessNull);
			if (options !== null) {
				pen = options.pen;
				brush = options.brush;

				for (var k = start; k <= stop; k++) {
					t._drawBar3D(paths[k], pen, brush, k);
				}
			}
		};

		var draw = function (onlyLessNull, start, stop) {
			for (var i = 0; i < t.sortZIndexPaths.length; i++) {
				drawVerges(t.sortZIndexPaths[i].seria, t.sortZIndexPaths[i].point, t.sortZIndexPaths[i].paths,
					onlyLessNull, start, stop);
			}
		};

		if (this.subType === "standard") {
			draw(true, verges.front, verges.unfront);
			draw(false, verges.front, verges.unfront);
		} else {
			draw(true, verges.down, verges.up);
			draw(false, verges.down, verges.up);

			draw(true, verges.unfront, verges.unfront);
			draw(false, verges.unfront, verges.unfront);

			draw(true, verges.front, verges.front);
			draw(false, verges.front, verges.front);
		}
	},

	_DrawBars3D1: function () {
		var t = this;
		var processor3D = this.cChartDrawer.processor3D;

		var drawVerges = function (i, j, paths, onlyLessNull, k) {
			var brush, pen, options;
			options = t._getOptionsForDrawing(i, j, onlyLessNull);
			if (paths !== null && options !== null) {
				pen = options.pen;
				brush = options.brush;

				t._drawBar3D(paths, pen, brush, k);
			}
		};

		for (var i = 0; i < this.sortZIndexPaths.length; i++) {
			if (this.sortZIndexPaths[i].seria !== undefined) {
				drawVerges(this.sortZIndexPaths[i].seria, this.sortZIndexPaths[i].point,
					this.sortZIndexPaths[i].paths, null, this.sortZIndexPaths[i].verge);
			} else {
				//if(options !== null)
				//{
				var pen = t.valAx.compiledMajorGridLines;
				var brush = null;

				this.cChartDrawer.drawPath(this.sortZIndexPaths[i].paths, pen, brush);
				//}
			}

		}
	},

	_DrawBars3D: function () {
		var t = this;

		var drawVerges = function (i, j, paths, onlyLessNull, k, isNotPen, isNotBrush) {
			var brush, pen, options;
			options = t._getOptionsForDrawing(i, j, onlyLessNull);
			if (paths !== null && options !== null) {
				if (!isNotPen) {
					pen = options.pen;
				}
				if (!isNotBrush) {
					brush = options.brush;
				}

				t._drawBar3D(paths, pen, brush, k);
			}
		};

		var index, faces, face;
		if (this.cChartDrawer.processor3D.view3D.getRAngAx()) {
			for (var i = 0; i < this.sortZIndexPaths.length; i++) {
				drawVerges(this.sortZIndexPaths[i].seria, this.sortZIndexPaths[i].point,
					this.sortZIndexPaths[i].darkPaths, null, this.sortZIndexPaths[i].verge, null, true);
			}

			for (var i = 0; i < this.sortZIndexPaths.length; i++) {
				drawVerges(this.sortZIndexPaths[i].seria, this.sortZIndexPaths[i].point,
					this.sortZIndexPaths[i].frontPaths, null, this.sortZIndexPaths[i].verge);
			}
		} else {
			for (var i = 0; i < this.sortParallelepipeds.length; i++) {
				index = this.sortParallelepipeds[i].nextIndex;
				faces = this.temp[index].faces;
				for (var j = 0; j < faces.length; j++) {
					face = faces[j];
					drawVerges(face.seria, face.point, face.darkPaths, null, face.verge, null, true);
				}
			}

			for (var i = 0; i < this.sortParallelepipeds.length; i++) {
				index = this.sortParallelepipeds[i].nextIndex;
				faces = this.temp[index].faces;
				for (var j = 0; j < faces.length; j++) {
					face = faces[j];
					drawVerges(face.seria, face.point, face.frontPaths, null, face.verge);
				}
			}
		}
	},

	_drawBar3D: function (path, pen, brush, k) {
		//затемнение боковых сторон
		var fill = this._getFill(pen, brush, k);
		var newBrush = fill.brush;
		var newPen = fill.pen;
		this.cChartDrawer.drawPath(path, newPen, newBrush);
	},

	_getFill: function (pen, brush, face) {
		//k: 0 - передняя, 1 - верхняя, 2 - левая, 3 - правая, 4 - нижняя, 5 - задняя
		var shade = "shade";
		var shadeValue1 = 35000;
		var shadeValue2 = 45000;

		var newBrush = brush;
		var newPen = pen;
		var t = this;

		/*if(null === pen || (null !== pen && null === pen.Fill) || (null !== pen && null !== pen.Fill && null === pen.Fill.fill))
		 {
		 pen = AscFormat.CreatePenFromParams(brush, undefined, undefined, undefined, undefined, 0.1);
		 }*/

		//TODO будет время - сделать градиентную заливку в зависимости от угла!!!!
		var color;
		if (brush && brush.fill && AscDFH.historyitem_type_GradFill === brush.fill.getObjectType()) {
			switch (face) {
				case c_oChartBar3dFaces.front:
				case c_oChartBar3dFaces.back: {
					break;
				}
				case c_oChartBar3dFaces.up: {
					color = this._getGradFill(brush, pen, c_oChartBar3dFaces.up);
					newBrush = color.brush;
					newPen = color.pen;

					break;
				}
				case c_oChartBar3dFaces.left: {
					color = this._getGradFill(brush, pen, c_oChartBar3dFaces.left);
					newBrush = color.brush;
					newPen = color.pen;

					break;
				}
				case c_oChartBar3dFaces.right: {
					color = this._getGradFill(brush, pen, c_oChartBar3dFaces.right);
					newBrush = color.brush;
					newPen = color.pen;

					break;
				}
				case c_oChartBar3dFaces.down: {
					color = this._getGradFill(brush, pen, c_oChartBar3dFaces.down);
					newBrush = color.brush;
					newPen = color.pen;

					break;
				}
			}
		} else if (brush && brush.fill) {
			switch (face) {
				case c_oChartBar3dFaces.front:
				case c_oChartBar3dFaces.back: {
					break;
				}
				case c_oChartBar3dFaces.up:
				case c_oChartBar3dFaces.down: {
					newBrush = this._applyColorModeByBrush(brush, shadeValue1);
					if (null === pen) {
						newPen = pen.setFill(newBrush);
					}
					break;
				}
				case c_oChartBar3dFaces.left:
				case c_oChartBar3dFaces.right: {
					newBrush = this._applyColorModeByBrush(brush, shadeValue2);
					if (null === pen) {
						newPen = pen.setFill(newBrush);
					}
					break;
				}
			}
		}

		return {brush: newBrush, pen: newPen};
	},

	_getGradFill: function (brushFill, penFill, faceIndex) {
		var gradientPen = penFill;
		var gradientBrush = brushFill;

		var angleKf = 60000;
		var shade = "shade";
		var shadeValue1 = 35000;
		var t = this;

		if (brushFill.fill.lin && null !== brushFill.fill.lin.angle) {
			var getCSolidColor = function (color, colorMod) {
				var duplicateBrush = brushFill.createDuplicate();
				var tempColor = new AscFormat.CUniFill();
				tempColor.setFill(new AscFormat.CSolidFill());
				tempColor.fill.setColor(color);
				if (colorMod) {
					tempColor = t._applyColorModeByBrush(tempColor, colorMod);
				}

				return tempColor;
			};

			var angle = brushFill.fill.lin.angle / angleKf;
			var colors = brushFill.fill.colors;

			if (angle >= 0 && angle < 45) {
				if (faceIndex === c_oChartBar3dFaces.up || faceIndex === c_oChartBar3dFaces.down) {
					gradientBrush = this._applyColorModeByBrush(brushFill, shadeValue1);
				} else if (faceIndex === c_oChartBar3dFaces.left) {
					gradientBrush = getCSolidColor(colors[0].color);
				} else if (faceIndex === c_oChartBar3dFaces.right) {
					gradientBrush = getCSolidColor(colors[colors.length - 1].color);
				}
			} else if (angle >= 45 && angle < 90) {
				if (faceIndex === c_oChartBar3dFaces.up || faceIndex === c_oChartBar3dFaces.left) {
					gradientBrush = getCSolidColor(colors[0].color, shadeValue1);
				} else if (faceIndex === c_oChartBar3dFaces.right) {
					gradientBrush = this._applyColorModeByBrush(brushFill, shadeValue1);
				} else if (faceIndex === c_oChartBar3dFaces.down) {
					gradientBrush = getCSolidColor(colors[colors.length - 1].color);
				}
			} else if (angle >= 90 && angle < 135) {
				if (faceIndex === c_oChartBar3dFaces.up || faceIndex === c_oChartBar3dFaces.left) {
					gradientBrush = getCSolidColor(colors[0].color, shadeValue1);
				} else if (faceIndex === c_oChartBar3dFaces.right) {
					gradientBrush = this._applyColorModeByBrush(brushFill, shadeValue1);
				} else if (faceIndex === c_oChartBar3dFaces.down) {
					gradientBrush = getCSolidColor(colors[colors.length - 1].color);
				}
			} else if (angle >= 135 && angle < 180) {
				if (faceIndex === c_oChartBar3dFaces.up || faceIndex === c_oChartBar3dFaces.left ||
					faceIndex === c_oChartBar3dFaces.right) {
					gradientBrush = getCSolidColor(colors[0].color, shadeValue1);
				} else if (faceIndex === c_oChartBar3dFaces.down) {
					gradientBrush = this._applyColorModeByBrush(brushFill, shadeValue1);
				}
			} else if (angle >= 180 && angle < 225) {
				if (faceIndex === c_oChartBar3dFaces.up || faceIndex === c_oChartBar3dFaces.down) {
					gradientBrush = this._applyColorModeByBrush(brushFill, shadeValue1);
				} else if (faceIndex === c_oChartBar3dFaces.right) {
					gradientBrush = getCSolidColor(colors[0].color, shadeValue1);
				} else if (faceIndex === c_oChartBar3dFaces.left) {
					gradientBrush = getCSolidColor(colors[colors.length - 1].color, shadeValue1);
				}
			} else if (angle >= 225 && angle < 270) {
				if (faceIndex === c_oChartBar3dFaces.up) {
					gradientBrush = this._applyColorModeByBrush(brushFill, shadeValue1);
				} else if (faceIndex === c_oChartBar3dFaces.left || faceIndex === c_oChartBar3dFaces.down ||
					faceIndex === c_oChartBar3dFaces.right) {
					gradientBrush = getCSolidColor(colors[0].color, shadeValue1);
				}
			} else if (angle >= 270 && angle < 315) {
				if (faceIndex === c_oChartBar3dFaces.up) {
					gradientBrush = getCSolidColor(colors[colors.length - 1].color);
				} else if (faceIndex === c_oChartBar3dFaces.left || faceIndex === c_oChartBar3dFaces.down) {
					gradientBrush = getCSolidColor(colors[0].color, shadeValue1);
				} else if (faceIndex === c_oChartBar3dFaces.right) {
					gradientBrush = this._applyColorModeByBrush(brushFill, shadeValue1);
				}
			} else if (angle >= 315 && angle <= 360) {
				if (faceIndex === c_oChartBar3dFaces.up || faceIndex === c_oChartBar3dFaces.right) {
					gradientBrush = this._applyColorModeByBrush(brushFill, shadeValue1);
				} else if (faceIndex === c_oChartBar3dFaces.left || faceIndex === c_oChartBar3dFaces.down) {
					gradientBrush = getCSolidColor(colors[0].color, shadeValue1);
				}
			}
		}

		return {pen: gradientPen, brush: gradientBrush};
	},

	_applyColorModeByBrush: function (brushFill, val) {
		var props = this.cChartSpace.getParentObjects();
		var duplicateBrush = brushFill.createDuplicate();
		var cColorMod = new AscFormat.CColorMod;
		cColorMod.val = val;

		cColorMod.name = "shade";
		duplicateBrush.addColorMod(cColorMod);
		duplicateBrush.calculate(props.theme, props.slide, props.layout, props.master, new AscFormat.CUniColor().RGBA, this.cChartSpace.clrMapOvr);

		return duplicateBrush;
	}

};

/** @constructor */
function drawPieChart(chart, chartsDrawer) {
	this.chartProp = chartsDrawer.calcProp;
	this.cChartDrawer = chartsDrawer;
	this.cChartSpace = chartsDrawer.cChartSpace;

	this.chart = chart;

	this.tempAngle = null;
	this.paths = {};
	this.cX = null;
	this.cY = null;
	this.angleFor3D = null;
	this.properties3d = null;
	this.usually3dPropsCalc = [];

	this.tempDrawOrder = null;
}

drawPieChart.prototype = {
	constructor: drawPieChart,

	draw: function () {
		if (this.cChartDrawer.nDimensionCount === 3) {
			this._drawPie3D();
		} else {
			this._drawPie();
		}
	},

	recalculate: function () {
		this.tempAngle = null;
		this.paths = {};

		if (this.cChartDrawer.nDimensionCount === 3) {
			if (this.cChartDrawer.processor3D.view3D.getRAngAx()) {
				this.properties3d = this.cChartDrawer.processor3D.calculatePropertiesForPieCharts();
				this._recalculatePie3D();
			} else {
				this._recalculatePie3DPerspective();
			}
		} else {
			this._recalculatePie();
		}
	},

	_drawPie: function () {
		var numCache = this._getFirstRealNumCache();
		if(!numCache) {
			return;
		}

		var brush, pen, val;
		var path;
		for (var i = 0, len = numCache.length; i < len; i++) {
			val = numCache[i];
			brush = val.brush;
			pen = val.pen;
			path = this.paths.series[i];

			this.cChartDrawer.drawPath(path, pen, brush);
		}
	},

	_recalculatePie: function () {
		var trueWidth = this.chartProp.trueWidth;
		var trueHeight = this.chartProp.trueHeight;

		var numCache = this._getFirstRealNumCache();
		if(!numCache) {
			return;
		}

		var sumData = this.cChartDrawer._getSumArray(numCache, true);

		var radius = Math.min(trueHeight, trueWidth) / 2;
		var xCenter = this.chartProp.chartGutter._left + trueWidth / 2;
		var yCenter = this.chartProp.chartGutter._top + trueHeight / 2;

		var firstSliceAng = this.chart && this.chart.firstSliceAng ? this.chart.firstSliceAng : 0;
		this.tempAngle = Math.PI / 2 - (firstSliceAng / 180) * Math.PI;
		//рисуем против часовой стрелки, поэтому цикл с конца
		var angle;
		for (var i = numCache.length - 1; i >= 0; i--) {
			angle = Math.abs((parseFloat(numCache[i].val / sumData)) * (Math.PI * 2));
			//правка связана с реализацией arcTo, где swAng зануляется и приравнивается к значению
			if(angle < 10e-16) {
				angle = 0;
			}

			if (!this.paths.series) {
				this.paths.series = [];
			}
			if (sumData === 0)//TODO стоит пересмотреть
			{
				this.paths.series[i] = this._calculateEmptySegment(radius, xCenter, yCenter);
			} else {
				this.paths.series[i] = this._calculateSegment(angle, radius, xCenter, yCenter);
			}
		}
	},

	_getFirstRealNumCache: function () {
		var series = this.chart.series;

		//todo use getNumCache
		var numCache;
		for (var i = 0; i < series.length; i++) {
			numCache = series[i].val.numRef && series[i].val.numRef.numCache ? series[i].val.numRef.numCache.pts : series[i].val.numLit.pts;
			if (numCache && numCache.length) {
				return numCache;
			}
		}

		return series[0].val.numRef && series[0].val.numRef.numCache ? series[0].val.numRef.numCache.pts : series[0].val.numLit.pts;
	},

	_calculateSegment: function (angle, radius, xCenter, yCenter) {
		if (isNaN(angle)) {
			return null;
		}

		var startAngle = (this.tempAngle);
		var endAngle = angle;

		if (radius < 0) {
			radius = 0;
		}
		var path = this._calculateArc(radius, startAngle, endAngle, xCenter, yCenter);

		this.tempAngle += angle;

		return path;
	},

	_calculateEmptySegment: function (radius, xCenter, yCenter) {

		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;

		var pxToMm = this.chartProp.pxToMM;

		var x0 = xCenter + radius * Math.cos(this.tempAngle);
		var y0 = yCenter - radius * Math.sin(this.tempAngle);

		path.moveTo(xCenter / pxToMm * pathW, yCenter / pxToMm * pathH);
		path.lnTo(x0 / pxToMm * pathW, y0 / pxToMm * pathH);
		path.arcTo(radius / pxToMm * pathW, radius / pxToMm * pathH, this.tempAngle, this.tempAngle);
		path.lnTo(xCenter / pxToMm * pathW, yCenter / pxToMm * pathH);

		return pathId;
	},

	_calculateArc: function (radius, stAng, swAng, xCenter, yCenter) {

		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;


		var pxToMm = this.chartProp.pxToMM;

		var x0 = xCenter + radius * Math.cos(stAng);
		var y0 = yCenter - radius * Math.sin(stAng);

		path.moveTo(xCenter / pxToMm * pathW, yCenter / pxToMm * pathH);
		path.lnTo(x0 / pxToMm * pathW, y0 / pxToMm * pathH);
		path.arcTo(radius / pxToMm * pathW, radius / pxToMm * pathH, -1 * stAng * cToDeg, -1 * swAng * cToDeg);
		path.lnTo(xCenter / pxToMm * pathW, yCenter / pxToMm * pathH);

		return pathId;
	},

	_changeAngle: function (radius, stAng, swAng, xCenter, yCenter, depth, radius1, radius2) {
		//корректируем центр
		yCenter = yCenter - depth / 2;

		var x0 = xCenter + radius * Math.cos(stAng);
		var y0 = yCenter - radius * Math.sin(stAng);
		var kFX = radius / radius1;
		var kFY = radius / radius2;

		var cX;
		//if(this.cX !== null)
		//cX = this.cX;
		if (x0 < xCenter) {
			cX = xCenter - (xCenter - x0) / kFX;
		} else if (x0 > xCenter) {
			cX = xCenter + (x0 - xCenter) / kFX;
		} else {
			cX = xCenter;
		}

		var cY;
		//if(this.cY !== null)
		//cY = this.cY;
		if (y0 < yCenter) {
			cY = yCenter - (yCenter - y0) / kFY;
		} else if (y0 > yCenter) {
			cY = yCenter + (y0 - yCenter) / kFY;
		} else {
			cY = yCenter;
		}


		var x01 = xCenter + radius * Math.cos(stAng + swAng);
		var y01 = yCenter - radius * Math.sin(stAng + swAng);

		var aX;
		if (x01 < xCenter) {
			aX = xCenter - (xCenter - x01) / kFX;
		} else if (x01 > xCenter) {
			aX = xCenter + (x01 - xCenter) / kFX;
		} else {
			aX = xCenter;
		}


		var aY;
		if (y01 < yCenter) {
			aY = yCenter - (yCenter - y01) / kFY;
		} else if (y01 > yCenter) {
			aY = yCenter + (y01 - yCenter) / kFY;
		} else {
			aY = yCenter;
		}

		this.cX = aX;
		this.cY = aY;

		var a = Math.sqrt(Math.pow(cX - xCenter, 2) + Math.pow(cY - yCenter, 2));
		var b = Math.sqrt(Math.pow(aX - cX, 2) + Math.pow(aY - cY, 2));
		var c = Math.sqrt(Math.pow(aX - xCenter, 2) + Math.pow(aY - yCenter, 2));

		var cosNewAngle = (Math.pow(c, 2) + Math.pow(a, 2) - Math.pow(b, 2)) / (2 * c * a);
		if (cosNewAngle > 1) {
			cosNewAngle = 1;
		}

		if (cosNewAngle < -1) {
			cosNewAngle = -1;
		}

		var res;
		if (Math.abs(swAng) > Math.PI) {
			res = 2 * Math.PI - Math.acos(cosNewAngle);
		} else {
			res = Math.acos(cosNewAngle);
		}

		return res;
	},

	_calculateDLbl: function (chartSpace, ser, val, bLayout) {
		var pxToMm = this.chartProp.pxToMM;

		//TODO сделать через idx как у drawDoughnutChart!!!
		if (!this.paths.series[val]) {
			return;
		}

		var path;
		if (this.cChartDrawer.nDimensionCount === 3) {
			if (this.paths.series[val][ser] && this.paths.series[val][ser].upPath) {
				path = this.paths.series[val][ser].upPath;
			}
		} else {
			path = this.paths.series[val];
		}

		if (!AscFormat.isRealNumber(path)) {
			return;
		}

		var getEllipseRadius = function (radius1, radius2, alpha) {
			var a = radius1 * radius2;
			var b = Math.sqrt(Math.pow(radius2, 2) * Math.pow(Math.cos(alpha), 2) +
				Math.pow(radius1, 2) * Math.pow(Math.sin(alpha), 2));
			var res = a / b;

			return res;
		};

		var oPath = this.cChartSpace.GetPath(path);
		var oCommand0 = oPath.getCommandByIndex(0);
		var oCommand1 = oPath.getCommandByIndex(1);
		var oCommand2 = oPath.getCommandByIndex(2);

		var centerX = oCommand0.X;
		var centerY = oCommand0.Y;

		var radius = oCommand2.hR;
		var stAng = oCommand2.stAng;
		var swAng = oCommand2.swAng;

		if (this.cChartDrawer.nDimensionCount === 3 && oCommand2.wR) {
			radius = getEllipseRadius(oCommand2.hR, oCommand2.wR, -1 * stAng - swAng / 2 - Math.PI / 2);
		}

		var point = this.chart.series[0].val.numRef ? this.chart.series[0].val.numRef.numCache.pts[val] :
			this.chart.series[0].val.numLit.pts[val];

		if (!point || !point.compiledDlb) {
			return;
		}

		var width = point.compiledDlb.extX;
		var height = point.compiledDlb.extY;

		var tempCenterX, tempCenterY;

		//TODO высчитать позиции, как в екселе +  ограничения
		var oPos;
		switch (point.compiledDlb.dLblPos) {
			case c_oAscChartDataLabelsPos.bestFit: {
				oPos = this._calculateBestFitPosition(stAng, swAng, radius, width, height, centerX, centerY, bLayout);
				if (!oPos.bError) {
					centerX = oPos.fX;
					centerY = oPos.fY;
				} else {
					centerX = centerX + (radius / 2) * Math.cos(-1 * stAng - swAng / 2) - width / 2;
					centerY = centerY - (radius / 2) * Math.sin(-1 * stAng - swAng / 2) - height / 2;
				}
				break;
			}
			case c_oAscChartDataLabelsPos.ctr: {
				centerX = centerX + (radius / 2) * Math.cos(-1 * stAng - swAng / 2) - width / 2;
				centerY = centerY - (radius / 2) * Math.sin(-1 * stAng - swAng / 2) - height / 2;
				break;
			}
			case c_oAscChartDataLabelsPos.inBase: {
				centerX = centerX + (radius / 2) * Math.cos(-1 * stAng - swAng / 2) - width / 2;
				centerY = centerY - (radius / 2) * Math.sin(-1 * stAng - swAng / 2) - height / 2;
				break;
			}
			case c_oAscChartDataLabelsPos.inEnd: {
				oPos = this._calculateInEndDLblPosition(stAng, swAng, radius, width, height, centerX, centerY);
				if (!oPos.bError) {
					centerX = oPos.fX;
					centerY = oPos.fY;
					break;
				}
				tempCenterX = centerX + (radius) * Math.cos(-1 * stAng - swAng / 2);
				tempCenterY = centerY - (radius) * Math.sin(-1 * stAng - swAng / 2);

				if (tempCenterX < centerX && tempCenterY < centerY) {
					centerX = tempCenterX;
					centerY = tempCenterY;
				} else if (tempCenterX > centerX && tempCenterY < centerY) {
					centerX = tempCenterX - width;
					centerY = tempCenterY;
				} else if (tempCenterX < centerX && tempCenterY > centerY) {
					centerX = tempCenterX;
					centerY = tempCenterY - height;
				} else {
					centerX = tempCenterX - width;
					centerY = tempCenterY - height;
				}
				break;
			}
			case c_oAscChartDataLabelsPos.outEnd: {
				tempCenterX = centerX + (radius) * Math.cos(-1 * stAng - swAng / 2);
				tempCenterY = centerY - (radius) * Math.sin(-1 * stAng - swAng / 2);

				if (tempCenterX < centerX && tempCenterY < centerY) {
					centerX = tempCenterX - width;
					centerY = tempCenterY - height;
				} else if (tempCenterX > centerX && tempCenterY < centerY) {
					centerX = tempCenterX;
					centerY = tempCenterY - height;
				} else if (tempCenterX < centerX && tempCenterY > centerY) {
					centerX = tempCenterX - width;
					centerY = tempCenterY;
				} else {
					centerX = tempCenterX;
					centerY = tempCenterY;
				}
				break;
			}
		}
		if (centerX < 0) {
			centerX = 0;
		}
		if (centerX + width > this.chartProp.widthCanvas / pxToMm) {
			centerX = this.chartProp.widthCanvas / pxToMm - width;
		}

		if (centerY < 0) {
			centerY = 0;
		}
		if (centerY + height > this.chartProp.heightCanvas / pxToMm) {
			centerY = this.chartProp.heightCanvas / pxToMm - height;
		}

		return {x: centerX, y: centerY};
	},

	//****fast calulate and drawing(for switch on slow drawing: change name function _Slow)
	_recalculatePie3D: function () {
		var trueWidth = this.chartProp.trueWidth;
		var trueHeight = this.chartProp.trueHeight;

		var numCache = this._getFirstRealNumCache();
		if(!numCache) {
			return;
		}

		var sumData = this.cChartDrawer._getSumArray(numCache, true);

		var radius = Math.min(trueHeight, trueWidth) / 2;
		if (radius < 0) {
			radius = 0;
		}

		var xCenter = this.chartProp.chartGutter._left + trueWidth / 2;
		var yCenter = this.chartProp.chartGutter._top + trueHeight / 2;

		var startAngle = this.cChartDrawer.processor3D.angleOy ? this.cChartDrawer.processor3D.angleOy : 0;
		var startAngle3D = startAngle !== 0 && startAngle !== undefined ? this._changeAngle(radius, Math.PI / 2, startAngle, xCenter, yCenter, this.properties3d.depth, this.properties3d.radius1, this.properties3d.radius2) : 0;

		this.angleFor3D = Math.PI / 2 - startAngle3D;
		startAngle = startAngle + Math.PI / 2;

		for (var i = numCache.length - 1; i >= 0; i--) {
			var partOfSum = numCache[i].val / sumData;
			var swapAngle = Math.abs((parseFloat(partOfSum)) * (Math.PI * 2));

			if (!this.paths.series) {
				this.paths.series = [];
			}

			this.paths.series[i] = this._calculateSegment3D(startAngle, swapAngle, radius, xCenter, yCenter);

			startAngle += swapAngle;
		}
	},

	_recalculatePie3DPerspective: function () {
		var left = this.chartProp.chartGutter._left;
		var right = this.chartProp.chartGutter._right;
		var top = this.chartProp.chartGutter._top;
		var bottom = this.chartProp.chartGutter._bottom;

		var trueWidth = this.chartProp.trueWidth;

		var widthCanvas = this.chartProp.widthCanvas;
		var heightCanvas = this.chartProp.heightCanvas;

		var height = heightCanvas - (top + bottom);
		var width = widthCanvas - (left + right);

		var tempDepth = this.cChartDrawer.processor3D.depthPerspective;

		var x1 = left, y1 = top + height, z1 = 0;
		var x2 = left, y2 = top, z2 = 0;
		var x3 = left + width, y3 = top, z3 = 0;
		var x4 = left + width, y4 = top + height, z4 = 0;

		var x5 = left, y5 = top + height, z5 = tempDepth;
		var x6 = left, y6 = top, z6 = tempDepth;
		var x7 = left + width, y7 = top, z7 = tempDepth;
		var x8 = left + width, y8 = top + height, z8 = tempDepth;

		var point1 = this.cChartDrawer._convertAndTurnPoint(x1, y1, z1);
		var point2 = this.cChartDrawer._convertAndTurnPoint(x2, y2, z2);
		//var point3 = this.cChartDrawer._convertAndTurnPoint(x3, y3, z3);
		//var point4 = this.cChartDrawer._convertAndTurnPoint(x4, y4, z4);

		var point5 = this.cChartDrawer._convertAndTurnPoint(x5, y5, z5);
		var point6 = this.cChartDrawer._convertAndTurnPoint(x6, y6, z6);
		//var point7 = this.cChartDrawer._convertAndTurnPoint(x7, y7, z7);
		//var point8 = this.cChartDrawer._convertAndTurnPoint(x8, y8, z8);


		var radius3D1 = (z6 - z2) / 2;
		var radius3D2 = (z5 - z1) / 2;

		var center3D1 = new Point3D(x2 + ((x3 - x2) / 2), y2, z2 + (radius3D1));
		var center3D2 = new Point3D(x1 + ((x4 - x1) / 2), y1, z1 + (radius3D2));

		var pointCenter1 = this.cChartDrawer._convertAndTurnPoint(center3D1.x, center3D1.y, center3D1.z);
		var pointCenter2 = this.cChartDrawer._convertAndTurnPoint(center3D2.x, center3D2.y, center3D2.z);

		//TEST DRAW FRAME
		//this._calculateTestFrame(point1, point2, point3, point4, point5, point6, point7, point8);

		var test1 = this.cChartDrawer._convertAndTurnPoint(x2, y2, center3D1.z);
		var test2 = this.cChartDrawer._convertAndTurnPoint(x3, y3, center3D1.z);

		var test11 = this.cChartDrawer._convertAndTurnPoint(x4, y4, center3D2.z);
		var test22 = this.cChartDrawer._convertAndTurnPoint(x1, y1, center3D2.z);

		var radius11 = Math.abs((test2.x - test1.x) / 2);
		var radius12 = Math.abs((point6.y - point2.y) / 2);
		var radius21 = Math.abs((test22.x - test11.x) / 2);
		var radius22 = Math.abs((point5.y - point1.y) / 2);

		var center1 = {
			x: this.chartProp.chartGutter._left + trueWidth / 2,
			y: (point2.y - point6.y) / 2 + point6.y
		};
		var center2 = {
			x: this.chartProp.chartGutter._left + trueWidth / 2,
			y: (point1.y - point5.y) / 2 + point5.y
		};

		var angles1 = this._calculateAngles3DPerspective(center1.x, center1.y, radius11, radius12, radius3D1,
			center3D1);
		var angles2 = this._calculateAngles3DPerspective(center2.x, center2.y, radius21, radius22, radius3D2,
			center3D2);

		if (!this.paths.series) {
			this.paths.series = [];
		}

		for (var i = 0; i < angles1.length; i++) {
			var start = angles1[i].start;
			var start1 = angles2[i].start;

			if (i === angles1.length - 1) {
				var end = angles1[0].start + 2 * Math.PI;
				angles1[i].swap = end - start;

				var end1 = angles2[0].start + 2 * Math.PI;
				angles2[i].swap = end1 - start1;
			}

			var paths = this._calculateSegment3DPerspective(radius11, radius12, radius21, radius22, angles1[i],
				angles2[i], center1, center2, pointCenter1, pointCenter2, Math.sign(point2.y - point6.y));

			if (null === this.tempDrawOrder) {
				this.tempDrawOrder = Math.sign(point2.y - point6.y) < 0 ? true : null;
			}

			if (!this.paths.series[angles1.length - i - 1]) {
				this.paths.series[angles1.length - i - 1] = [];
			}

			this.paths.series[angles1.length - i - 1].push(paths);
		}
	},

	_calculateAngles3DPerspective: function (xCenter, yCenter, radius1, radius2, radius3D1, center3D1) {
		var t = this;
		var widthCanvas = this.chartProp.widthCanvas;

		var numCache = this._getFirstRealNumCache();
		if(!numCache) {
			return;
		}

		var sumData = this.cChartDrawer._getSumArray(numCache, true);

		var startAngle = Math.PI / 2;
		var newStartAngle = startAngle;

		var oView3D = this.cChartSpace.chart.getView3d();
		var firstAngle = oView3D && oView3D.rotY ? (-oView3D.rotY / 360) * (Math.PI * 2) : 0;


		var getAngleByCoordsSidesTriangle = function (aC, bC, cC) {
			var res;

			var a = Math.sqrt(Math.pow(aC.x, 2) + Math.pow(aC.y, 2));
			var b = Math.sqrt(Math.pow(bC.x, 2) + Math.pow(bC.y, 2));
			var c = Math.sqrt(Math.pow(cC.x, 2) + Math.pow(cC.y, 2));
			res = Math.acos((Math.pow(b, 2) + Math.pow(c, 2) - Math.pow(a, 2)) / (2 * b * c));

			return res;
		};

		var getPointsByAngle = function (angle) {
			var point1 = t.cChartDrawer._convertAndTurnPoint(center3D1.x + radius3D1 * Math.cos(angle), center3D1.y,
				center3D1.z + radius3D1 * Math.sin(angle));

			var y11 = point1.y;
			var x11 = Math.sqrt(
				Math.abs(Math.pow(radius1, 2) * (1 - (Math.pow(y11 - (yCenter), 2) / Math.pow(radius2, 2)))));

			var x111;
			if ((angle <= 3 * Math.PI / 2 && angle >= Math.PI / 2) || (angle >= -3 * Math.PI / 2 && angle <= -Math.PI / 2)) {
				x111 = xCenter - x11;
			} else {
				x111 = widthCanvas - (xCenter - x11)
			}

			return {x: x111, y: y11};
		};

		var angles = [];
		for (var i = numCache.length; i >= 0; i--) {
			//рассчитываем угол
			var swapAngle;
			if (i === numCache.length) {
				swapAngle = firstAngle
			} else {
				var partOfSum = numCache[i].val / sumData;
				swapAngle = Math.abs((parseFloat(partOfSum)) * (Math.PI * 2));
			}


			var tempSwapAngle = 0, newSwapAngle = 0, tempStartAngle = startAngle;
			while (true) {
				if (i === numCache.length && swapAngle < 0) {
					if (tempStartAngle - Math.PI / 2 > startAngle + swapAngle) {
						tempSwapAngle = -Math.PI / 2;
					} else {
						tempSwapAngle = (startAngle + swapAngle) - tempStartAngle;
					}
				} else {
					if (tempStartAngle + Math.PI / 2 < startAngle + swapAngle) {
						tempSwapAngle = Math.PI / 2;
					} else {
						tempSwapAngle = (startAngle + swapAngle) - tempStartAngle;
					}
				}


				var p1 = getPointsByAngle(tempStartAngle);
				var p2 = getPointsByAngle(tempStartAngle + tempSwapAngle);
				newSwapAngle += getAngleByCoordsSidesTriangle({x: p2.x - p1.x, y: p2.y - p1.y},
					{x: xCenter - p1.x, y: yCenter - p1.y}, {x: xCenter - p2.x, y: yCenter - p2.y});


				if (i === numCache.length && swapAngle < 0) {
					if (tempStartAngle - Math.PI / 2 > startAngle + swapAngle) {
						tempStartAngle -= Math.PI / 2;
					} else {
						if (i !== numCache.length) {
							angles.push(
								{start: newStartAngle, swap: newSwapAngle, end: newStartAngle + newSwapAngle});
						}

						break;
					}
				} else {
					if (tempStartAngle + Math.PI / 2 < startAngle + swapAngle) {
						tempStartAngle += Math.PI / 2;
					} else {
						if (i !== numCache.length) {
							angles.push(
								{start: newStartAngle, swap: newSwapAngle, end: newStartAngle + newSwapAngle});
						}

						break;
					}
				}

			}

			startAngle += swapAngle;
			if (i === numCache.length) {
				if (swapAngle < 0) {
					newStartAngle -= newSwapAngle;
				} else {
					newStartAngle += newSwapAngle;
				}

			} else {
				newStartAngle += newSwapAngle;
			}
		}

		return angles;
	},

	_calculateArc3D: function (radius, stAng, swAng, xCenter, yCenter, bIsNotDrawFrontFace, depth, radius1,
							   radius2) {
		var properties = this.cChartDrawer.processor3D.calculatePropertiesForPieCharts();
		var oChartSpace = this.cChartSpace;

		depth = !depth ? properties.depth : depth;
		radius1 = !radius1 ? properties.radius1 : radius1;
		radius2 = !radius2 ? properties.radius2 : radius2;


		var pxToMm = this.chartProp.pxToMM;
		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;


		swAng = this._changeAngle(radius, stAng, swAng, xCenter, yCenter, depth, radius1, radius2);
		stAng = this.angleFor3D;
		//корректируем центр
		yCenter = yCenter - depth / 2;


		var getSegmentPoints = function (startAng, endAng) {
			var radiusSpec = (radius1 * radius2) / Math.sqrt(
					Math.pow(radius2, 2) * Math.pow((Math.cos(startAng)), 2) +
					Math.pow(radius1, 2) * Math.pow(Math.sin(startAng), 2));
			var radiusSpec2 = (radius1 * radius2) / Math.sqrt(
					Math.pow(radius2, 2) * Math.pow((Math.cos(endAng)), 2) +
					Math.pow(radius1, 2) * Math.pow(Math.sin(endAng), 2));

			var x0 = (xCenter + radiusSpec * Math.cos(startAng));
			var y0 = (yCenter - radiusSpec * Math.sin(startAng));

			var x1 = (xCenter + radiusSpec * Math.cos(startAng));
			var y1 = ((yCenter + depth) - radiusSpec * Math.sin(startAng));

			var x2 = (xCenter + radiusSpec2 * Math.cos(endAng));
			var y2 = (yCenter - radiusSpec2 * Math.sin(endAng));

			var x3 = (xCenter + radiusSpec2 * Math.cos(endAng));
			var y3 = ((yCenter + depth) - radiusSpec2 * Math.sin(endAng));

			return {x0: x0, y0: y0, x1: x1, y1: y1, x2: x2, y2: y2, x3: x3, y3: y3};
		};

		var breakAng = function (startAng, swapAng) {
			var res = [];
			var endAng = startAng + swapAng;

			res.push({angle: startAng});
			if (startAng < -2 * Math.PI && endAng > -2 * Math.PI) {
				res.push({angle: -2 * Math.PI});
			}
			/*if(startAng < -3/2*Math.PI && endAng > -3/2*Math.PI)
			 {
			 res.push({angle: -3/2*Math.PI});
			 }*/
			if (startAng < -Math.PI && endAng > -Math.PI) {
				res.push({angle: -Math.PI});
			}
			/*if(startAng < -Math.PI/2 && endAng > -Math.PI/2)
			 {
			 res.push({angle: -Math.PI/2});
			 }*/
			if (startAng < 0 && endAng > 0) {
				res.push({angle: 0});
			}
			/*if(startAng < Math.PI/2 && endAng > Math.PI/2)
			 {
			 res.push({angle: Math.PI/2});
			 }*/
			if (startAng < Math.PI && endAng > Math.PI) {
				res.push({angle: Math.PI});
			}
			/*if(startAng < 3/2*Math.PI && endAng > 3/2*Math.PI)
			 {
			 res.push({angle: 3/2*Math.PI});
			 }*/
			if (startAng < 2 * Math.PI && endAng > 2 * Math.PI) {
				res.push({angle: 2 * Math.PI});
			}
			res.push({angle: endAng});

			return res;
		};

		var calculateInsideFaces = function (startAng, swapAng) {

			var pathId = oChartSpace.AllocPath();
			var path = oChartSpace.GetPath(pathId);

			var endAng = startAng + swapAng;
			var p = getSegmentPoints(startAng, endAng);

			path.moveTo(xCenter / pxToMm * pathW, yCenter / pxToMm * pathH);
			path.lnTo(p.x0 / pxToMm * pathW, p.y0 / pxToMm * pathH);
			path.lnTo(p.x1 / pxToMm * pathW, p.y1 / pxToMm * pathH);
			path.lnTo(xCenter / pxToMm * pathW, (yCenter + depth) / pxToMm * pathH);

			path.moveTo(xCenter / pxToMm * pathW, yCenter / pxToMm * pathH);
			path.lnTo(p.x2 / pxToMm * pathW, p.y2 / pxToMm * pathH);
			path.lnTo(p.x3 / pxToMm * pathW, p.y3 / pxToMm * pathH);
			path.lnTo(xCenter / pxToMm * pathW, (yCenter + depth) / pxToMm * pathH);


			return pathId;
		};

		var calculateFrontFace = function (startAng, swapAng) {

			var pathId = oChartSpace.AllocPath();
			var path = oChartSpace.GetPath(pathId);

			var endAng = startAng + swapAng;
			var p = getSegmentPoints(startAng, endAng);

			path.moveTo(p.x0 / pxToMm * pathW, p.y0 / pxToMm * pathH);
			path.arcTo(radius1 / pxToMm * pathW, radius2 / pxToMm * pathH, -1 * startAng * cToDeg, -1 * swapAng * cToDeg);
			path.lnTo(p.x3 / pxToMm * pathW, p.y3 / pxToMm * pathH);
			path.arcTo(radius1 / pxToMm * pathW, radius2 / pxToMm * pathH, -1 * startAng * cToDeg - 1 * swapAng * cToDeg, 1 * swapAng * cToDeg);
			path.lnTo(p.x0 / pxToMm * pathW, p.y0 / pxToMm * pathH);

			return pathId;
		};

		var calculateUpFace = function (startAng, swapAng) {

			var pathId = oChartSpace.AllocPath();
			var path = oChartSpace.GetPath(pathId);

			var endAng = startAng + swapAng;
			var p = getSegmentPoints(startAng, endAng);

			path.moveTo(xCenter / pxToMm * pathW, yCenter / pxToMm * pathH);
			path.lnTo(p.x0 / pxToMm * pathW, p.y0 / pxToMm * pathH);
			path.arcTo(radius1 / pxToMm * pathW, radius2 / pxToMm * pathH, -1 * stAng * cToDeg, -1 * swapAng * cToDeg);
			path.lnTo(xCenter / pxToMm * pathW, yCenter / pxToMm * pathH);

			return pathId;
		};

		var calculateDownFace = function (startAng, swapAng) {
			var pathId = oChartSpace.AllocPath();
			var path = oChartSpace.GetPath(pathId);

			var endAng = startAng + swapAng;
			var p = getSegmentPoints(startAng, endAng);

			path.moveTo(xCenter / pxToMm * pathW, (yCenter + depth) / pxToMm * pathH);
			path.lnTo(p.x0 / pxToMm * pathW, (p.y0 + depth) / pxToMm * pathH);
			path.arcTo(radius1 / pxToMm * pathW, radius2 / pxToMm * pathH, -1 * stAng * cToDeg,
				-1 * swapAng * cToDeg);
			path.lnTo(xCenter / pxToMm * pathW, (yCenter + depth) / pxToMm * pathH);


			return pathId;
		};

		//FRONT FACES
		//break front faces
		var arrAngles = breakAng(stAng, swAng);
		var frontPath = [];
		for (var i = 1; i < arrAngles.length; i++) {
			var start = arrAngles[i - 1].angle;
			var end = arrAngles[i].angle;
			var swap = end - start;

			if ((start >= 0 && start >= Math.PI && start <= 2 * Math.PI) || (start < 0 && start >= -Math.PI && start <= 0)) {
				frontPath.push(calculateFrontFace(start, swap));
			}
		}

		//INSIDE FACES
		var insidePath = calculateInsideFaces(stAng, swAng);

		//UP FACE
		var upPath = calculateUpFace(stAng, swAng);

		//DOWN FACE
		var downPath = calculateDownFace(stAng, swAng);

		this.angleFor3D += swAng;

		return {frontPath: frontPath, upPath: upPath, insidePath: insidePath, downPath: downPath};
	},

	_calculateSegment3D: function (startAngle, swapAngle, radius, xCenter, yCenter) {
		if (isNaN(swapAngle)) {
			return null;
		}

		if (radius < 0) {
			radius = 0;
		}

		var path = [];
		path.push(this._calculateArc3D(radius, startAngle, swapAngle, xCenter, yCenter));

		return path;
	},

	_calculateSegment3DPerspective: function (radiusUp1, radiusUp2, radiusDown1, radiusDown2, angles1, angles2, center1, center2, pointCenter1, pointCenter2, upFaceSign) {
		var xCenter = center1.x, yCenter = center1.y, xCenter1 = center2.x, yCenter1 = center2.y;
		var startAngle1 = angles1.start, swapAngle1 = angles1.swap, startAngle2 = angles2.start, swapAngle2 = angles2.swap;

		var pxToMm = this.chartProp.pxToMM;
		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;

		var oThis = this;


		var getSegmentPoints = function (startAng, endAng, startAng2, endAng2) {
			var radiusSpec = (radiusUp1 * radiusUp2) / Math.sqrt(Math.pow(radiusUp2, 2) * Math.pow((Math.cos(startAng)), 2) + Math.pow(radiusUp1, 2) * Math.pow(Math.sin(startAng), 2));
			var radiusSpec2 = (radiusUp1 * radiusUp2) / Math.sqrt(Math.pow(radiusUp2, 2) * Math.pow((Math.cos(endAng)), 2) + Math.pow(radiusUp1, 2) * Math.pow(Math.sin(endAng), 2));

			var radiusSpec11 = (radiusDown1 * radiusDown2) / Math.sqrt(Math.pow(radiusDown2, 2) * Math.pow((Math.cos(startAng2)), 2) + Math.pow(radiusDown1, 2) * Math.pow(Math.sin(startAng2), 2));
			var radiusSpec12 = (radiusDown1 * radiusDown2) / Math.sqrt(Math.pow(radiusDown2, 2) * Math.pow((Math.cos(endAng2)), 2) + Math.pow(radiusDown1, 2) * Math.pow(Math.sin(endAng2), 2));

			var x0 = (xCenter + radiusSpec * Math.cos(startAng));
			var y0 = (yCenter - radiusSpec * Math.sin(startAng));

			var x1 = (xCenter1 + radiusSpec11 * Math.cos(startAng2));
			var y1 = ((yCenter1) - radiusSpec11 * Math.sin(startAng2));

			var x2 = (xCenter + radiusSpec2 * Math.cos(endAng));
			var y2 = (yCenter - radiusSpec2 * Math.sin(endAng));

			var x3 = (xCenter1 + radiusSpec12 * Math.cos(endAng2));
			var y3 = ((yCenter1) - radiusSpec12 * Math.sin(endAng2));

			return {x0: x0, y0: y0, x1: x1, y1: y1, x2: x2, y2: y2, x3: x3, y3: y3};
		};

		var breakAng = function (startAng, swapAng) {
			var res = [];
			var endAng = startAng + swapAng;

			res.push({angle: startAng});

			var tempStartAng = startAng;
			var tempEndAng = endAng;
			var tempPI = Math.PI;

			if (tempStartAng <= -2 * tempPI && tempEndAng > -2 * tempPI) {
				res.push({angle: -2 * Math.PI});
			}
			if (tempStartAng <= -tempPI && tempEndAng > -tempPI) {
				res.push({angle: -Math.PI});
			}
			if (tempStartAng <= 0 && tempEndAng > 0) {
				res.push({angle: 0});
			}
			if (tempStartAng <= tempPI && tempEndAng > tempPI) {
				res.push({angle: Math.PI});
			}
			if (tempStartAng <= 2 * tempPI && tempEndAng > 2 * tempPI) {
				res.push({angle: 2 * Math.PI});
			}
			res.push({angle: endAng});

			return res;
		};

		var calculateInsideFaces = function (startAng1, swapAng1, startAng2, swapAng2) {

			var pathId = oThis.cChartSpace.AllocPath();
			var path = oThis.cChartSpace.GetPath(pathId);

			var endAng1 = startAng1 + swapAng1;
			var endAng2 = startAng2 + swapAng2;
			var p = getSegmentPoints(startAng1, endAng1, startAng2, endAng2);

			path.moveTo(pointCenter1.x / pxToMm * pathW, pointCenter1.y / pxToMm * pathH);
			path.lnTo(p.x0 / pxToMm * pathW, p.y0 / pxToMm * pathH);
			path.lnTo(p.x1 / pxToMm * pathW, p.y1 / pxToMm * pathH);
			path.lnTo(pointCenter2.x / pxToMm * pathW, (pointCenter2.y) / pxToMm * pathH);

			path.moveTo(pointCenter1.x / pxToMm * pathW, pointCenter1.y / pxToMm * pathH);
			path.lnTo(p.x2 / pxToMm * pathW, p.y2 / pxToMm * pathH);
			path.lnTo(p.x3 / pxToMm * pathW, p.y3 / pxToMm * pathH);
			path.lnTo(pointCenter2.x / pxToMm * pathW, (pointCenter2.y) / pxToMm * pathH);

			return pathId;
		};

		var calculateFrontFace = function (startAng, swapAng, startAng2, swapAng2) {

			var pathId = oThis.cChartSpace.AllocPath();
			var path = oThis.cChartSpace.GetPath(pathId);

			var endAng = startAng + swapAng;
			var endAng2 = startAng2 + swapAng2;

			var p = getSegmentPoints(startAng, endAng, startAng2, endAng2);
			//var p2 = getSegmentPoints(startAng2, endAng2);

			path.moveTo(p.x0 / pxToMm * pathW, p.y0 / pxToMm * pathH);
			path.arcTo(radiusUp1 / pxToMm * pathW, radiusUp2 / pxToMm * pathH, -1 * startAng * cToDeg, -1 * swapAng * cToDeg);
			path.lnTo(p.x3 / pxToMm * pathW, p.y3 / pxToMm * pathH);
			path.arcTo(radiusDown1 / pxToMm * pathW, radiusDown2 / pxToMm * pathH, -1 * startAng2 * cToDeg - 1 * swapAng2 * cToDeg, 1 * swapAng2 * cToDeg);
			path.lnTo(p.x0 / pxToMm * pathW, p.y0 / pxToMm * pathH);


			return pathId;
		};

		var calculateUpFace = function (startAng, swapAng) {

			var pathId = oThis.cChartSpace.AllocPath();
			var path = oThis.cChartSpace.GetPath(pathId);

			var radiusSpec = (radiusUp1 * radiusUp2) / Math.sqrt(Math.pow(radiusUp2, 2) * Math.pow((Math.cos(startAng)), 2) + Math.pow(radiusUp1, 2) * Math.pow(Math.sin(startAng), 2));

			var x0 = (xCenter + radiusSpec * Math.cos(startAng));
			var y0 = (yCenter - radiusSpec * Math.sin(startAng));

			path.moveTo(pointCenter1.x / pxToMm * pathW, pointCenter1.y / pxToMm * pathH);
			path.lnTo(x0 / pxToMm * pathW, y0 / pxToMm * pathH);
			path.arcTo(radiusUp1 / pxToMm * pathW, radiusUp2 / pxToMm * pathH, -1 * startAng * cToDeg, -1 * swapAng * cToDeg);
			path.lnTo(pointCenter1.x / pxToMm * pathW, pointCenter1.y / pxToMm * pathH);


			return pathId;
		};

		var calculateDownFace = function (startAng, swapAng) {

			var pathId = oThis.cChartSpace.AllocPath();
			var path = oThis.cChartSpace.GetPath(pathId);

			var radiusSpec = (radiusDown1 * radiusDown2) / Math.sqrt(Math.pow(radiusDown2, 2) * Math.pow((Math.cos(startAng)), 2) + Math.pow(radiusDown1, 2) * Math.pow(Math.sin(startAng), 2));
			//var radiusSpec2 = (radius11 * radius2) /  Math.sqrt(Math.pow(radius2, 2) * Math.pow((Math.cos(endAng)), 2) + Math.pow(radius11, 2) * Math.pow(Math.sin(endAng),2))

			var x = (xCenter1 + radiusSpec * Math.cos(startAng));
			var y = (yCenter1 - radiusSpec * Math.sin(startAng));

			path.moveTo(pointCenter2.x / pxToMm * pathW, (pointCenter2.y) / pxToMm * pathH);
			path.lnTo(x / pxToMm * pathW, y / pxToMm * pathH);
			path.arcTo(radiusDown1 / pxToMm * pathW, radiusDown2 / pxToMm * pathH, -1 * startAng * cToDeg, -1 * swapAng * cToDeg);
			path.lnTo(pointCenter2.x / pxToMm * pathW, (pointCenter2.y) / pxToMm * pathH);


			return pathId;
		};

		//FRONT FACES
		//break front faces
		var arrAngles = breakAng(startAngle1, swapAngle1);
		var arrAngles2 = breakAng(startAngle2, swapAngle2);
		var frontPath = [];
		for (var i = 1; i < arrAngles.length; i++) {
			var start = arrAngles[i - 1].angle;
			var end = arrAngles[i].angle;
			var swap = end - start;

			var start2 = arrAngles2[i - 1].angle;
			var end2;
			if (!arrAngles2[i]) {
				end2 = arrAngles2[i - 1].angle;
			} else {
				end2 = arrAngles2[i].angle;
			}

			var swap2 = end2 - start2;

			if ((start >= 0 && start >= Math.PI && start <= 2 * Math.PI) || (start < 0 && start >= -Math.PI && start <= 0)) {
				frontPath.push(calculateFrontFace(upFaceSign * start, upFaceSign * swap, start2, swap2));
			}
		}

		//INSIDE FACES
		var insidePath = calculateInsideFaces(upFaceSign * startAngle1, upFaceSign * swapAngle1, startAngle2,
			swapAngle2);

		//UP FACE
		var upPath = calculateUpFace(upFaceSign * startAngle1, upFaceSign * swapAngle1);

		//DOWN FACE
		var downPath = calculateDownFace(startAngle2, swapAngle2);

		return {frontPath: frontPath, upPath: upPath, insidePath: insidePath, downPath: downPath};
	},


	_drawPie3D: function () {
		var numCache = this._getFirstRealNumCache();
		var t = this;
		var shade = "shade";
		var shadeValue = 35000;

		var drawPath = function (path, pen, brush, isShadePen, isShadeBrush) {
			if (path) {
				if (brush) {
					var props = t.cChartSpace.getParentObjects();
					var duplicateBrush = brush.createDuplicate();
					var cColorMod = new AscFormat.CColorMod;

					cColorMod.val = shadeValue;
					cColorMod.name = shade;

					if (duplicateBrush) {
						duplicateBrush.addColorMod(cColorMod);
						duplicateBrush.calculate(props.theme, props.slide, props.layout, props.master, new AscFormat.CUniColor().RGBA, t.cChartSpace.clrMapOvr);
					}
					if (isShadePen) {
						pen = AscFormat.CreatePenFromParams(duplicateBrush, undefined, undefined, undefined,
							undefined, 0);
					}
					if (isShadeBrush) {
						brush = duplicateBrush;
					}
				}

				t.cChartDrawer.drawPath(path, pen, brush);
			}

		};

		var pen = numCache[0].pen;
		drawPath(this.paths.test, pen, null);

		var sides = {down: 0, inside: 1, up: 2, front: 3};
		var drawPaths = function (side) {
			for (var i = 0, len = numCache.length; i < len; i++) {
				var val = numCache[i];
				var brush = val.brush;
				var pen = val.pen;
				var path = t.paths.series[i];

				if (path) {
					for (var j = path.length - 1; j >= 0; j--) {
						if (side === sides.down) {
							drawPath(path[j].downPath, pen, null);
						} else if (side === sides.inside) {
							//выставляю закругленные соединения
							if (pen && pen.Join) {
								pen = pen.createDuplicate();
								pen.Join.type = Asc['c_oAscLineJoinType'].Round;
							}

							drawPath(path[j].insidePath, pen, brush, null, true);
						} else if (side === sides.up) {
							drawPath(path[j].upPath, pen, brush);
						} else if (side === sides.frontPath) {
							for (var k = 0; k < path[j].frontPath.length; k++) {
								drawPath(path[j].frontPath[k], pen, brush, true, true);
							}
						}
					}
				}
			}
		};

		drawPaths(sides.down);
		drawPaths(sides.inside);
		if (this.tempDrawOrder !== null) {
			drawPaths(sides.up);
			drawPaths(sides.frontPath);
		} else {
			drawPaths(sides.frontPath);
			drawPaths(sides.up);
		}
	},

	//best fit DLbl
	_calculateBestFitPosition: function (fStartAngle, fSweepAngle, fRadius, fWidth, fHeight, fCenterX, fCenterY, bLayout) {
		var fStartAngle_ = fStartAngle;
		var fEndAngle = fStartAngle + fSweepAngle;
		if (bLayout) {
			return this._calculateBestFitPositionOuter(fStartAngle_, fEndAngle, fRadius, fWidth, fHeight, fCenterX, fCenterY);
		}
		var oRet = this._calculateBestFitPositionInner(fStartAngle_, fEndAngle, fRadius, fWidth, fHeight, fCenterX, fCenterY);
		if (!oRet.bError) {
			if (AscFormat.fCheckBoxIntersectionSegment(oRet.fX, oRet.fY, fWidth, fHeight, fCenterX, fCenterY, fCenterX + fRadius * Math.cos(fStartAngle_), fCenterY + fRadius * Math.sin(fStartAngle_)) || AscFormat.fCheckBoxIntersectionSegment(oRet.fX, oRet.fY, fWidth, fHeight, fCenterX, fCenterY, fCenterX + fRadius * Math.cos(fEndAngle), fCenterY + fRadius * Math.sin(fEndAngle))) {
				oRet.bError = true;
			}
		}
		if (oRet.bError) {
			return this._calculateBestFitPositionOuter(fStartAngle_, fEndAngle, fRadius, fWidth, fHeight, fCenterX, fCenterY);
		}
		return oRet;
	},

	_calculateBestFitPositionInner: function(fStartAngle, fEndAngle, fPieRadius, fLabelWidth, fLabelHeight, fCenterX, fCenterY){
		var oResult = {bError: true};
		var fBisectAngle = AscFormat.normalizeRotate((fStartAngle + fEndAngle)/2.0);
		
		if(AscFormat.fApproxEqual(fBisectAngle, 0) || AscFormat.fApproxEqual(fBisectAngle, Math.PI/2) || AscFormat.fApproxEqual(fBisectAngle, Math.PI) || AscFormat.fApproxEqual(fBisectAngle, 3*Math.PI/2)){
			return this._calculateInEndDLblPosition(fStartAngle, fEndAngle - fStartAngle, fPieRadius, fLabelWidth, fLabelHeight, fCenterX, fCenterY);
		}
		var fBisectAngle2 = AscFormat.normalizeRotate(fBisectAngle + Math.PI/4) - Math.PI/4; 
		var nIndexArea = ((fBisectAngle2 + Math.PI/4)/(Math.PI/2)) >> 0;
				
		
		var fLengthCoeff =  ((fBisectAngle2 + Math.PI/4) - (Math.PI/2)*nIndexArea)/(Math.PI/2);		
				
		var fXs = fCenterX + fPieRadius*Math.cos(fBisectAngle);
		var fYs = fCenterY + fPieRadius*Math.sin(fBisectAngle);
		var fDeltaX, fDeltaY, oSolvation;

        switch(nIndexArea){
            case 0:{
                if(fBisectAngle2 < 0){
                    fDeltaX = fLabelWidth;
                    fDeltaY = -(1 - fLengthCoeff)*fLabelHeight;
                }
                else{
                    fDeltaX = fLabelWidth;
                    fDeltaY = fLabelHeight*fLengthCoeff;
                }
                oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
                if(!oSolvation.bError){
                    if(oSolvation.x1 > 0 && oSolvation.x1 < 1){
                        oResult.bError = false;
                        oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX);
                        oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
                    }
                    else if(oSolvation.x2 > 0 && oSolvation.x2 < 1){
                        oResult.bError = false;
                        oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX);
                        oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
                    }
                }
                break;
            }
            case 1:{
                if(fBisectAngle < Math.PI/2){
                    fDeltaX = (1 - fLengthCoeff)*fLabelWidth;
                    fDeltaY = fLabelHeight;
                }
                else{
                    fDeltaX = - fLengthCoeff*fLabelWidth;
                    fDeltaY = fLabelHeight;
                }
                oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
                if(!oSolvation.bError){
                    if(oSolvation.x1 > 0 && oSolvation.x1 < 1){
                        oResult.bError = false;
                        oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
                        oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY);
                    }
                    else if(oSolvation.x2 > 0 && oSolvation.x2 < 1){
                        oResult.bError = false;
                        oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
                        oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY);
                    }
                }
                break;
            }
            case 2:{
                if(fBisectAngle < Math.PI){
                    fDeltaX = -fLabelWidth;
                    fDeltaY = (1 - fLengthCoeff)*fLabelHeight;
                }
                else{
                    fDeltaX = -fLabelWidth;
                    fDeltaY = - fLengthCoeff*fLabelHeight;
                }
                oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
                if(!oSolvation.bError){
                    if(oSolvation.x1 > 0 && oSolvation.x1 < 1){
                        oResult.bError = false;
                        oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth;
                        oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight*fLengthCoeff;

                    }
                    else if(oSolvation.x2 > 0 && oSolvation.x2 < 1){
                        oResult.bError = false;
                        oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth;
                        oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight*fLengthCoeff;
                    }
                }
                break;
            }
            case 3:{
                fLengthCoeff = 1 - fLengthCoeff;
                if(fBisectAngle < 3*Math.PI/2){
                    fDeltaX = -fLabelWidth*fLengthCoeff;
                    fDeltaY = -fLabelHeight;
                }
                else{
                    fDeltaX = (1 - fLengthCoeff)*fLabelWidth;
                    fDeltaY = -fLabelHeight;
                }
                oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
                if(!oSolvation.bError){
                    if(oSolvation.x1 > 0 && oSolvation.x1 < 1){
                        oResult.bError = false;
                        oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
                        oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight;
                    }
                    else if(oSolvation.x2 > 0 && oSolvation.x2 < 1){
                        oResult.bError = false;
                        oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
                        oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight;
                    }
                }
                break;
            }
        }
		return oResult;
	},

	_calculateBestFitPositionOuter: function(fStartAngle, fEndAngle, fPieRadius, fLabelWidth, fLabelHeight, fCenterX, fCenterY){
        var oResult = {bError: true};
        var fBisectAngle = AscFormat.normalizeRotate((fStartAngle + fEndAngle)/2.0);
        var fBisectAngle2 = AscFormat.normalizeRotate(fBisectAngle + Math.PI/4) - Math.PI/4;
        var nIndexArea = ((fBisectAngle2 + Math.PI/4)/(Math.PI/2)) >> 0;


        var fLengthCoeff =  ((fBisectAngle2 + Math.PI/4) - (Math.PI/2)*nIndexArea)/(Math.PI/2);

        var fXs = fCenterX + fPieRadius*Math.cos(fBisectAngle);
        var fYs = fCenterY + fPieRadius*Math.sin(fBisectAngle);
        var fDeltaX, fDeltaY, oSolvation;

        var fAngleApproxDelta = 1e-4;
        switch(nIndexArea){
            case 0:{
                if(AscFormat.fApproxEqual(fBisectAngle2, 0, fAngleApproxDelta)){
                    fDeltaX = 0;
                    fDeltaY = 0;
                }
                else if(fBisectAngle2 < 0){
                    fDeltaX = 0;
                    fDeltaY = fLengthCoeff*fLabelHeight;
                }
                else{
                    fDeltaX = 0;
                    fDeltaY = -(1 - fLengthCoeff)*fLabelHeight;
                }
                oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
                if(!oSolvation.bError){
                    if(oSolvation.x1 >= 1){
                        oResult.bError = false;
                        oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX);
                        oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
                    }
                    else if(oSolvation.x2 >= 1){
                        oResult.bError = false;
                        oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX);
                        oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
                    }
                    else if(oSolvation.x1 >= 0){
						oResult.bError = false;
						oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX);
						oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
					}
					else if(oSolvation.x2 >= 0){
						oResult.bError = false;
						oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX);
						oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
					}
                }
                break;
            }
            case 1:{
                if(AscFormat.fApproxEqual(fBisectAngle, Math.PI/2, fAngleApproxDelta)){
                    fDeltaX = 0;
                    fDeltaY = 0;
                }
                else if(fBisectAngle < Math.PI/2){
                    fDeltaX = -fLengthCoeff*fLabelWidth;
                    fDeltaY = 0;
                }
                else{
                    fDeltaX = (1 - fLengthCoeff)*fLabelWidth;
                    fDeltaY = 0;
                }
                oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
                if(!oSolvation.bError){
                    if(oSolvation.x1 >= 1){
                        oResult.bError = false;
                        oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
                        oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY);
                    }
                    else if(oSolvation.x2 >= 1){
                        oResult.bError = false;
                        oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
                        oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY);
                    }
                    else if(oSolvation.x1 >= 0){
						oResult.bError = false;
						oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
						oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY);
					}
					else if(oSolvation.x2 >= 0){
						oResult.bError = false;
						oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
						oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY);
					}
                }
                break;
            }
            case 2:{
                if(AscFormat.fApproxEqual(fBisectAngle, Math.PI, fAngleApproxDelta)){
                    fDeltaX = 0;
                    fDeltaY = 0;
                }
                else if(fBisectAngle < Math.PI){
                    fDeltaX = 0;
                    fDeltaY = -fLengthCoeff*fLabelHeight;
                }
                else{
                    fDeltaX = 0;
                    fDeltaY = (1 - fLengthCoeff)*fLabelHeight;
                }
                oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
                if(!oSolvation.bError){
                    if(oSolvation.x1 >= 1){
                        oResult.bError = false;
                        oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth;
                        oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight*fLengthCoeff;

                    }
                    else if(oSolvation.x2 >= 1){
                        oResult.bError = false;
                        oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth;
                        oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight*fLengthCoeff;
                    }
                    else if(oSolvation.x1 >= 0){
						oResult.bError = false;
						oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth;
						oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight*fLengthCoeff;

					}
					else if(oSolvation.x2 >= 0){
						oResult.bError = false;
						oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth;
						oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight*fLengthCoeff;
					}
                }
                break;
            }
            case 3:{
                if(fBisectAngle < 3*Math.PI/2){
                    fDeltaX = fLabelWidth*fLengthCoeff;
                    fDeltaY = 0;
                }
                else{
                    fDeltaX = -(1 - fLengthCoeff)*fLabelWidth;
                    fDeltaY = 0;
                }
                oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
                if(!oSolvation.bError){
                    if(oSolvation.x1 >= 1){
                        oResult.bError = false;
                        oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - (1 - fLengthCoeff)*fLabelWidth;
                        oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight;
                    }
                    else if(oSolvation.x2 >= 1){
                        oResult.bError = false;
                        oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - (1 - fLengthCoeff)*fLabelWidth;
                        oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight;
                    }
					else if(oSolvation.x1 >= 0){
						oResult.bError = false;
						oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - (1 - fLengthCoeff)*fLabelWidth;
						oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight;
					}
					else if(oSolvation.x2 >= 0){
						oResult.bError = false;
						oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - (1 - fLengthCoeff)*fLabelWidth;
						oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight;
					}
                }
                break;
            }
        }
        return oResult;
	},

    _calculateInEndDLblPosition: function(fStartAngle, fSweepAngle, fPieRadius, fLabelWidth, fLabelHeight, fCenterX, fCenterY){
        var fEndAngle = fStartAngle + fSweepAngle;
        var oResult = {bError: true, fX: 0.0, fY: 0.0};
        var fBisectAngle = AscFormat.normalizeRotate((fStartAngle + fEndAngle)/2);
        var nQuadrantIndex = (2.0*fBisectAngle/Math.PI) >> 0;
        var fHalfRectWidthVector = fLabelWidth/ 2, fHalfRectHeightVector = fLabelHeight/2;
        if(nQuadrantIndex === 1 || nQuadrantIndex == 2){
            fHalfRectWidthVector = -fHalfRectWidthVector;
        }
        if(nQuadrantIndex === 2 || nQuadrantIndex == 3){
            fHalfRectHeightVector = -fHalfRectHeightVector;
        }

        var fXs = fCenterX + fPieRadius*Math.cos(fBisectAngle), fYs = fCenterY + fPieRadius*Math.sin(fBisectAngle);
        var a = fPieRadius*fPieRadius, b = 2*( (fXs - fCenterX)*fHalfRectWidthVector + (fYs - fCenterY)*fHalfRectHeightVector), c = fHalfRectWidthVector*fHalfRectWidthVector + fHalfRectHeightVector*fHalfRectHeightVector - fPieRadius*fPieRadius;
        var oSolution = AscFormat.fSolveQuadraticEquation(a, b, c);
		if(oSolution.bError){
			return oResult;
		}
		var D = b*b - 4*a*c;
        if(D < 0){
            return oResult;
        }
        var t1 = oSolution.x1, t2 = oSolution.x2;
        if(t1 > 0 && t1 < 1){
            oResult.bError = false;
            oResult.fX = fCenterX + t1*(fXs - fCenterX) - fLabelWidth/2;
            oResult.fY = fCenterY + t1*(fYs - fCenterY) - fLabelHeight/2;
            return oResult
        }
        if(t2 > 0 && t2 < 1){
            oResult.bError = false;
            oResult.fX = fCenterX + t2*(fXs - fCenterX) - fLabelWidth/2;
            oResult.fY = fCenterY + t2*(fYs - fCenterY) - fLabelHeight/2;
            return oResult
        }
        return oResult;
    },

	//For test
	_calculateTestFrame: function (point1, point2, point3, point4, point5, point6, point7, point8) {
		var pxToMm = this.chartProp.pxToMM;
		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;

		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		path.moveTo(point1.x / pxToMm * pathW, point1.y / pxToMm * pathH);
		path.lnTo(point2.x / pxToMm * pathW, point2.y / pxToMm * pathH);
		path.lnTo(point3.x / pxToMm * pathW, point3.y / pxToMm * pathH);
		path.lnTo(point4.x / pxToMm * pathW, point4.y / pxToMm * pathH);
		path.lnTo(point1.x / pxToMm * pathW, point1.y / pxToMm * pathH);

		path.moveTo(point5.x / pxToMm * pathW, point5.y / pxToMm * pathH);
		path.lnTo(point6.x / pxToMm * pathW, point6.y / pxToMm * pathH);
		path.lnTo(point7.x / pxToMm * pathW, point7.y / pxToMm * pathH);
		path.lnTo(point8.x / pxToMm * pathW, point8.y / pxToMm * pathH);
		path.lnTo(point5.x / pxToMm * pathW, point5.y / pxToMm * pathH);

		path.moveTo(point1.x / pxToMm * pathW, point1.y / pxToMm * pathH);
		path.lnTo(point5.x / pxToMm * pathW, point5.y / pxToMm * pathH);

		path.moveTo(point2.x / pxToMm * pathW, point2.y / pxToMm * pathH);
		path.lnTo(point6.x / pxToMm * pathW, point6.y / pxToMm * pathH);

		path.moveTo(point3.x / pxToMm * pathW, point3.y / pxToMm * pathH);
		path.lnTo(point7.x / pxToMm * pathW, point7.y / pxToMm * pathH);

		path.moveTo(point4.x / pxToMm * pathW, point4.y / pxToMm * pathH);
		path.lnTo(point8.x / pxToMm * pathW, point8.y / pxToMm * pathH);


		this.paths.test = pathId;
	},

	//TODO delete after test
	_recalculatePie3D_Slow: function () {
		var trueWidth = this.chartProp.trueWidth;
		var trueHeight = this.chartProp.trueHeight;

		var numCache = this._getFirstRealNumCache();
		if(!numCache) {
			return;
		}

		var sumData = this.cChartDrawer._getSumArray(numCache, true);

		var radius = Math.min(trueHeight, trueWidth) / 2;
		if (radius < 0) {
			radius = 0;
		}

		var xCenter = this.chartProp.chartGutter._left + trueWidth / 2;
		var yCenter = this.chartProp.chartGutter._top + trueHeight / 2;

		var startAngle = this.cChartDrawer.processor3D.angleOy ? this.cChartDrawer.processor3D.angleOy : 0;
		var startAngle3D = startAngle !== 0 && startAngle !== undefined ? this._changeAngle(radius, Math.PI / 2, startAngle, xCenter, yCenter, this.properties3d) : 0;

		this.tempAngle = Math.PI / 2 + startAngle;
		this.angleFor3D = Math.PI / 2 - startAngle3D;

		//рисуем против часовой стрелки, поэтому цикл с конца
		var depth = this.properties3d.depth;
		for (var n = 0; n < depth; n++) {
			if (!this.paths.series) {
				this.paths.series = [];
			}

			for (var i = numCache.length - 1; i >= 0; i--) {
				var angle = Math.abs((parseFloat(numCache[i].val / sumData)) * (Math.PI * 2));
				if (!this.paths.series[n]) {
					this.paths.series[n] = [];
				}

				if (sumData === 0)//TODO стоит пересмотреть
				{
					this.paths.series[n][i] = this._calculateEmptySegment(radius, xCenter, yCenter);
				} else {
					this.paths.series[n][i] = this._calculateSegment3D(angle, radius, xCenter, yCenter, n, i);
				}
			}
		}

	},

	_calculateSegment3D_Slow: function (angle, radius, xCenter, yCenter, depth, i) {
		if (isNaN(angle)) {
			return null;
		}

		var startAngle = (this.tempAngle);
		var path = this._calculateArc3D(radius, startAngle, angle, xCenter, yCenter, depth, i);
		this.tempAngle += angle;

		return path;
	},

	_calculateArc3D_Slow: function (radius, stAng, swAng, xCenter, yCenter, depth, seriaNum) {
		var radius1 = this.properties3d.radius1;
		var radius2 = this.properties3d.radius2;
		var pxToMm = this.chartProp.pxToMM;
		var t = this;

		var x0, y0, radiusSpec;
		var calculateProps = function () {
			if (t.usually3dPropsCalc && t.usually3dPropsCalc[seriaNum]) {
				swAng = t.usually3dPropsCalc[seriaNum].swAng;
				stAng = t.usually3dPropsCalc[seriaNum].stAng;
				radiusSpec = t.usually3dPropsCalc[seriaNum].radiusSpec;
				x0 = t.usually3dPropsCalc[seriaNum].x0;

				yCenter = yCenter + t.properties3d.depth / 2 - depth;
				y0 = (yCenter - radiusSpec * Math.sin(stAng));
			} else {
				swAng = t._changeAngle(radius, stAng, swAng, xCenter, yCenter, t.properties3d);
				stAng = t.angleFor3D;

				//корректируем центр
				yCenter = yCenter + t.properties3d.depth / 2 - depth;

				radiusSpec = (radius1 * radius2) / Math.sqrt(Math.pow(radius2, 2) * Math.pow((Math.cos(stAng)), 2) + Math.pow(radius1, 2) * Math.pow(Math.sin(stAng), 2));

				x0 = (xCenter + radiusSpec * Math.cos(stAng));
				y0 = (yCenter - radiusSpec * Math.sin(stAng));
			}
		};


		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;


		calculateProps();

		path.moveTo(xCenter / pxToMm * pathW, yCenter / pxToMm * pathH);
		path.lnTo(x0 / pxToMm * pathW, y0 / pxToMm * pathH);
		path.arcTo(radius1 / pxToMm * pathW, radius2 / pxToMm * pathH, -1 * stAng * cToDeg, -1 * swAng * cToDeg);
		path.lnTo(xCenter / pxToMm * pathW, yCenter / pxToMm * pathH);


		this.angleFor3D += swAng;
		if (!this.usually3dPropsCalc[seriaNum]) {
			this.usually3dPropsCalc[seriaNum] = {swAng: swAng, stAng: stAng, xCenter: xCenter, x0: x0, radiusSpec: radiusSpec};
		}

		return pathId;
	},

	_drawPie3D_Slow: function () {
		var numCache = this._getFirstRealNumCache();
		if(!numCache) {
			return;
		}

		var props = this.cChartSpace.getParentObjects();
		var brush, pen, val;
		var path;
		for (var n = 0; n < this.paths.series.length; n++) {
			for (var i = 0, len = numCache.length; i < len; i++) {
				val = numCache[i];
				brush = val.brush;

				if (n === 0 || n === this.paths.series.length - 1) {
					pen = val.pen;
				} else {
					pen = null;
				}

				path = this.paths.series[n][i];

				var duplicateBrush = brush;
				if (n !== this.paths.series.length - 1) {
					duplicateBrush = brush.createDuplicate();
					var cColorMod = new AscFormat.CColorMod;

					cColorMod.val = 35000;
					cColorMod.name = "shade";

					duplicateBrush.addColorMod(cColorMod);
					duplicateBrush.calculate(props.theme, props.slide, props.layout, props.master, new AscFormat.CUniColor().RGBA, this.cChartSpace.clrMapOvr);
				}

				this.cChartDrawer.drawPath(path, pen, duplicateBrush);
			}
		}

	}
};


	/** @constructor */
function drawDoughnutChart(chart, chartsDrawer) {
	this.chartProp = chartsDrawer.calcProp;
	this.cChartDrawer = chartsDrawer;
	this.cChartSpace = chartsDrawer.cChartSpace;

	this.chart = chart;

	this.tempAngle = null;
	this.paths = {};
}

drawDoughnutChart.prototype = {
	constructor: drawDoughnutChart,

	draw: function () {
		this._drawPie();
	},

	recalculate: function () {
		var countSeries = this.cChartDrawer.calculateCountSeries(this.chart);
		this.seriesCount = countSeries.series;

		this.tempAngle = null;
		this.paths = {};
		this._reCalculatePie();
	},

	_drawPie: function () {
		var brush, pen;
		var path;
		var idxPoint, numCache;

		for (var n = 0; n < this.chart.series.length; n++) {
			numCache = this.cChartDrawer.getNumCache(this.chart.series[n].val);

			if (!numCache) {
				continue;
			}

			for (var k = 0; k < numCache.ptCount; k++) {
				
				if(!this.paths.series[n] || !this.paths.series[n][k]) {
					continue;
				}

				idxPoint = this.cChartDrawer.getPointByIndex(this.chart.series[n], k);

				brush = idxPoint ? idxPoint.brush : null;
				pen = idxPoint ? idxPoint.pen : null;
				path = this.paths.series[n][k];

				this.cChartDrawer.drawPath(path, pen, brush);
			}
		}
	},

	_reCalculatePie: function () {
		var trueWidth = this.chartProp.trueWidth;
		var trueHeight = this.chartProp.trueHeight;

		var sumData;
		var outRadius = Math.min(trueHeight, trueWidth) / 2;

		//% from out radius
		var defaultSize = 50;
		var holeSize = this.chart.holeSize ? this.chart.holeSize : defaultSize;

		//first ang
		var firstSliceAng = this.chart.firstSliceAng ? this.chart.firstSliceAng : 0;
		firstSliceAng = (firstSliceAng / 360) * (Math.PI * 2);

		//inner radius
		var radius = outRadius * (holeSize / 100);
		var step = (outRadius - radius) / this.seriesCount;

		var xCenter = this.chartProp.chartGutter._left + trueWidth / 2;
		var yCenter = this.chartProp.chartGutter._top + trueHeight / 2;

		var numCache, idxPoint, angle, curVal, seriesCounter = 0;
		for (var n = 0; n < this.chart.series.length; n++) {
			this.tempAngle = Math.PI / 2;
			numCache = this.cChartDrawer.getNumCache(this.chart.series[n].val);
			if (!numCache || this.chart.series[n].isHidden) {
				continue;
			}

			sumData = this.cChartDrawer._getSumArray(numCache.pts, true);

			//рисуем против часовой стрелки, поэтому цикл с конца
			for (var k = numCache.ptCount - 1; k >= 0; k--) {

				idxPoint = this.cChartDrawer.getPointByIndex(this.chart.series[n], k);
				curVal = idxPoint ? idxPoint.val : 0;
				angle = Math.abs((parseFloat(curVal / sumData)) * (Math.PI * 2));

				//правка связана с реализацией arcTo, где swAng зануляется и приравнивается к значению
				if(angle < 10e-16) {
					angle = 0;
				}

				if (!this.paths.series) {
					this.paths.series = [];
				}
				if (!this.paths.series[n]) {
					this.paths.series[n] = [];
				}

				if (angle) {
					this.paths.series[n][k] =
						this._calculateSegment(angle, radius, xCenter, yCenter, radius + step * (seriesCounter + 1), radius + step * seriesCounter, firstSliceAng);
				} else {
					this.paths.series[n][k] = null;
				}
			}

			if (numCache.pts.length) {
				seriesCounter++;
			}

		}
	},

	_calculateSegment: function (angle, radius, xCenter, yCenter, radius1, radius2, firstSliceAng) {
		var startAngle = this.tempAngle - firstSliceAng;
		var endAngle = angle;

		if (radius < 0) {
			radius = 0;
		}
		var path = this._calculateArc(radius, startAngle, endAngle, xCenter, yCenter, radius1, radius2);

		this.tempAngle += angle;

		return path;
	},

	_calculateArc: function (radius, stAng, swAng, xCenter, yCenter, radius1, radius2) {

		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;


		var pxToMm = this.chartProp.pxToMM;

		var x2 = xCenter + radius1 * Math.cos(stAng);
		var y2 = yCenter - radius1 * Math.sin(stAng);

		var x1 = xCenter + radius2 * Math.cos(stAng);
		var y1 = yCenter - radius2 * Math.sin(stAng);

		//var x3 = xCenter + radius1*Math.cos(stAng + swAng);
		//var y3 = yCenter - radius1*Math.sin(stAng + swAng);

		var x4 = xCenter + radius2 * Math.cos(stAng + swAng);
		var y4 = yCenter - radius2 * Math.sin(stAng + swAng);

		path.moveTo(x1 / pxToMm * pathW, y1 / pxToMm * pathH);
		path.lnTo(x2 / pxToMm * pathW, y2 / pxToMm * pathH);
		path.arcTo(radius1 / pxToMm * pathW, radius1 / pxToMm * pathH, -1 * stAng * cToDeg, -1 * swAng * cToDeg);
		path.lnTo(x4 / pxToMm * pathW, y4 / pxToMm * pathH);
		path.arcTo(radius2 / pxToMm * pathW, radius2 / pxToMm * pathH, -1 * stAng * cToDeg - swAng * cToDeg, swAng * cToDeg);
		path.moveTo(xCenter / pxToMm * pathW, yCenter / pxToMm * pathH);


		return pathId;
	},

	_calculateDLbl: function (chartSpace, ser, val) {
		if (!AscFormat.isRealNumber(this.paths.series[ser][val])) {
			return;
		}

		var path = this.paths.series[ser][val];
		var oPath = this.cChartSpace.GetPath(path);

		var oCommand2 = oPath.getCommandByIndex(2);
		var oCommand4 = oPath.getCommandByIndex(4);
		var oCommand5 = oPath.getCommandByIndex(5);

		var radius1 = oCommand2.hR;
		var stAng = oCommand2.stAng;
		var swAng = oCommand2.swAng;

		var radius2 = oCommand4.hR;
		var xCenter = oCommand5.X;
		var yCenter = oCommand5.Y;


		var newRadius = radius2 + (radius1 - radius2) / 2;
		var centerX = xCenter + newRadius * Math.cos(-1 * stAng - swAng / 2);
		var centerY = yCenter - newRadius * Math.sin(-1 * stAng - swAng / 2);

		var numCache = this.cChartDrawer.getNumCache(this.chart.series[ser].val);
		var point = null;
		if(numCache){
			point = numCache.pts[val];
		}
		if (!point) {
			return;
		}

		var width = point.compiledDlb.extX;
		var height = point.compiledDlb.extY;

		switch (point.compiledDlb.dLblPos) {
			case c_oAscChartDataLabelsPos.ctr: {
				centerX = centerX - width / 2;
				centerY = centerY - height / 2;
				break;
			}
			case c_oAscChartDataLabelsPos.inBase: {
				centerX = centerX - width / 2;
				centerY = centerY - height / 2;
				break;
			}
		}
		if (centerX < 0) {
			centerX = 0;
		}
		if (centerY < 0) {
			centerY = 0;
		}

		return {x: centerX, y: centerY};
	}
};


/** @constructor */
function drawRadarChart(chart, chartsDrawer) {
	this.chartProp = chartsDrawer.calcProp;
	this.cChartDrawer = chartsDrawer;
	this.cChartSpace = chartsDrawer.cChartSpace;

	this.chart = chart;
	this.subType = null;
	this.valAx = null;

	this.paths = {};
}

drawRadarChart.prototype = {
	constructor: drawRadarChart,

	draw: function () {
		this._drawLines();
	},

	recalculate: function () {
		this.paths = {};
		this.subType = this.cChartDrawer.getChartGrouping(this.chart);
		this.valAx = this.cChartDrawer.getAxisFromAxId(this.chart.axId, AscDFH.historyitem_type_ValAx);

		this._calculateLines();
	},

	_calculateLines: function () {
		//соответствует подписям оси значений(OY)
		var yPoints = this.valAx.yPoints;

		var trueWidth = this.chartProp.trueWidth;
		var trueHeight = this.chartProp.trueHeight;

		var xCenter = (this.chartProp.chartGutter._left + trueWidth / 2) / this.chartProp.pxToMM;
		var yCenter = (this.chartProp.chartGutter._top + trueHeight / 2) / this.chartProp.pxToMM;

		var y, y1, x, x1, val, nextVal, seria, dataSeries;
		var numCache = this.cChartDrawer.getNumCache(this.chart.series[0].val).pts;
		if(!numCache) {
			return;
		}

		var tempAngle = 2 * Math.PI / numCache.length;
		var xDiff = ((trueHeight / 2) / yPoints.length) / this.chartProp.pxToMM;
		var radius, radius1, xFirst, yFirst;

		for (var i = 0; i < this.chart.series.length; i++) {

			seria = this.chart.series[i];

			dataSeries = this.cChartDrawer.getNumCache(seria.val);
			if(!dataSeries) {
				continue;
			}

			if (dataSeries.length === 1) {
				n = 0;
				//рассчитываем значения
				val = this._getYVal(n, i);

				//точки находятся внутри диапазона
				y = val * xDiff;
				x = xCenter;

				radius = y;

				y = yCenter - radius * Math.cos(n * tempAngle);
				x = x + radius * Math.sin(n * tempAngle);

				if (!this.paths.points) {
					this.paths.points = [];
				}
				if (!this.paths.points[i]) {
					this.paths.points[i] = [];
				}

				this.paths.points[i][n] = this.cChartDrawer.calculatePoint(x, y, dataSeries[n].compiledMarker.size, dataSeries[n].compiledMarker.symbol);
			} else {
				for (var n = 0; n < dataSeries.length - 1; n++) {
					//рассчитываем значения
					val = this._getYVal(n, i);
					nextVal = this._getYVal(n + 1, i);

					//точки находятся внутри диапазона

					y = val * xDiff;
					y1 = nextVal * xDiff;

					x = xCenter;
					x1 = xCenter;

					radius = y;
					radius1 = y1;

					y = yCenter - radius * Math.cos(n * tempAngle);
					y1 = yCenter - radius1 * Math.cos((n + 1) * tempAngle);

					x = x + radius * Math.sin(n * tempAngle);
					x1 = x1 + radius1 * Math.sin((n + 1) * tempAngle);


					if (!this.paths.series) {
						this.paths.series = [];
					}
					if (!this.paths.series[i]) {
						this.paths.series[i] = [];
					}

					this.paths.series[i][n] = this._calculateLine(x, y, x1, y1);

					if (n === 0) {
						xFirst = x;
						yFirst = y;
					}


					if (n === dataSeries.length - 2) {
						this.paths.series[i][n + 1] = this._calculateLine(x1, y1, xFirst, yFirst);
					}

					if (!this.paths.points) {
						this.paths.points = [];
					}
					if (!this.paths.points[i]) {
						this.paths.points[i] = [];
					}

					if (dataSeries[n].compiledMarker) {
						if (n === 0) {
							this.paths.points[i][n] = this.cChartDrawer.calculatePoint(x, y, dataSeries[n].compiledMarker.size, dataSeries[n].compiledMarker.symbol);
							this.paths.points[i][n + 1] = this.cChartDrawer.calculatePoint(x1, y1, dataSeries[n + 1].compiledMarker.size, dataSeries[n + 1].compiledMarker.symbol);
						} else {
							this.paths.points[i][n + 1] = this.cChartDrawer.calculatePoint(x1, y1, dataSeries[n + 1].compiledMarker.size, dataSeries[n + 1].compiledMarker.symbol);
						}
					}
				}
			}
		}
	},

	_calculateDLbl: function (chartSpace, ser, val) {
		var numCache = this.cChartDrawer.getNumCache(chart.series[ser].val);
		if(!numCache) {
			return;
		}

		var point = numCache.pts[val];
		var path;

		var oCommand, oPath;
		if (this.paths.series) {
			if (val === numCache.pts.length - 1) {
				oPath = this.cChartSpace.GetPath(this.paths.series[ser][val - 1]);
				oCommand = oPath.getCommandByIndex(1);
			} else {
				oPath = this.cChartSpace.GetPath(this.paths.series[ser][val]);
				oCommand = oPath.getCommandByIndex(0);
			}
		} else if (this.paths.points) {
			if(this.paths.points[ser] && this.paths.points[ser][val]) {
				oPath = this.cChartSpace.GetPath(this.paths.points[ser][val].path);
				oCommand = oPath.getCommandByIndex(0);
			}
		}

		if (!oCommand) {
			return;
		}

		var x = oCommand.X;
		var y = oCommand.Y;

		var pxToMm = this.chartProp.pxToMM;
		var constMargin = 5 / pxToMm;

		var width = point.compiledDlb.extX;
		var height = point.compiledDlb.extY;

		var centerX = x - width / 2;
		var centerY = y - height / 2;

		switch (point.compiledDlb.dLblPos) {
			case c_oAscChartDataLabelsPos.b: {
				centerY = centerY + height / 2 + constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.bestFit: {
				break;
			}
			case c_oAscChartDataLabelsPos.ctr: {
				break;
			}
			case c_oAscChartDataLabelsPos.l: {
				centerX = centerX - width / 2 - constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.r: {
				centerX = centerX + width / 2 + constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.t: {
				centerY = centerY - height / 2 - constMargin;
				break;
			}
		}

		if (centerX < 0) {
			centerX = 0;
		}
		if (centerX + width > this.chartProp.widthCanvas / pxToMm) {
			centerX = this.chartProp.widthCanvas / pxToMm - width;
		}

		if (centerY < 0) {
			centerY = 0;
		}
		if (centerY + height > this.chartProp.heightCanvas / pxToMm) {
			centerY = this.chartProp.heightCanvas / pxToMm - height;
		}

		return {x: centerX, y: centerY};
	},

	_drawLines: function () {
		var brush, pen, dataSeries, seria, markerBrush, markerPen, numCache;

		//this.cShapeDrawer.Graphics.SaveGrState();
		//this.cShapeDrawer.Graphics.AddClipRect(this.chartProp.chartGutter._left / this.chartProp.pxToMM, this.chartProp.chartGutter._top / this.chartProp.pxToMM, this.chartProp.trueWidth / this.chartProp.pxToMM, this.chartProp.trueHeight / this.chartProp.pxToMM);
		for (var i = 0; i < this.chart.series.length; i++) {
			seria = this.chart.series[i];
			brush = seria.brush;
			pen = seria.pen;

			numCache = this.cChartDrawer.getNumCache(seria.val);
			if(!numCache) {
				continue;
			}

			dataSeries = numCache.pts;
			for (var n = 0; n < dataSeries.length - 1; n++) {
				if (numCache.pts[n].pen) {
					pen = numCache.pts[n].pen;
				}
				if (numCache.pts[n].brush) {
					brush = numCache.pts[n].brush;
				}

				this.cChartDrawer.drawPath(this.paths.series[i][n], pen, brush);
				if (n === dataSeries.length - 2 && this.paths.series[i][n + 1]) {
					this.cChartDrawer.drawPath(this.paths.series[i][n + 1], pen, brush);
				}
			}

			//draw point
			for (var k = 0; k < this.paths.points[i].length; k++) {
				markerBrush = numCache.pts[k].compiledMarker.brush;
				markerPen = numCache.pts[k].compiledMarker.pen;

				//frame of point
				if (this.paths.points[i][0].framePaths) {
					this.cChartDrawer.drawPath(this.paths.points[i][k].framePaths, markerPen, markerBrush, false);
				}
				//point
				this.cChartDrawer.drawPath(this.paths.points[i][k].path, markerPen, markerBrush, true);
			}
		}
		//this.cShapeDrawer.Graphics.RestoreGrState();
	},

	_getYVal: function (n, i) {
		var tempVal;
		var val = 0;
		var numCache;
		if (this.subType === "stacked") {
			for (var k = 0; k <= i; k++) {
				numCache = this.cChartDrawer.getNumCache(this.chart.series[k].val);
				if(!numCache) {
					continue;
				}

				tempVal = parseFloat(numCache.pts[n].val);
				if (tempVal) {
					val += tempVal;
				}
			}
		} else if (this.subType === "stackedPer") {
			var summVal = 0;
			for (var k = 0; k < this.chart.series.length; k++) {
				numCache = this.cChartDrawer.getNumCache(this.chart.series[k].val);
				if(!numCache) {
					continue;
				}

				tempVal = parseFloat(numCache.pts[n].val);
				if (tempVal) {
					if (k <= i) {
						val += tempVal;
					}
					summVal += Math.abs(tempVal);
				}
			}
			val = val / summVal;
		} else {
			numCache = this.cChartDrawer.getNumCache(this.chart.series[i].val);
			if(!numCache) {
				return;
			}

			val = parseFloat(numCache.pts[n].val);
		}
		return val;
	},

	_calculateLine: function (x, y, x1, y1) {

		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;

		path.moveTo(x * pathW, y * pathH);
		path.lnTo(x1 * pathW, y1 * pathH);


		return pathId;
	}
};


/** @constructor */
function drawScatterChart(chart, chartsDrawer) {
	this.chartProp = chartsDrawer.calcProp;
	this.cChartDrawer = chartsDrawer;
	this.cChartSpace = chartsDrawer.cChartSpace;

	this.chart = chart;
	this.catAx = null;
	this.valAx = null;

	this.paths = {};
}

drawScatterChart.prototype = {
	constructor: drawScatterChart,

	recalculate: function () {
		this.paths = {};

		this.catAx = this.chart.axId[0].xPoints ? this.chart.axId[0] : this.chart.axId[1];
		this.catAx = this.cChartDrawer._searchChangedAxis(this.catAx);
		this.valAx = this.chart.axId[0].yPoints ? this.chart.axId[0] : this.chart.axId[1];
		this.valAx = this.cChartDrawer._searchChangedAxis(this.valAx);

		this._recalculateScatter();
	},

	draw: function () {
		this._drawScatter();
	},

	_recalculateScatter: function () {
		var xPoints = this.catAx.xPoints;
		var yPoints = this.valAx.yPoints;
		var betweenAxisCross = this.valAx.crossBetween === AscFormat.CROSS_BETWEEN_BETWEEN;

		var seria, yVal, xVal, points, yNumCache, compiledMarkerSize, compiledMarkerSymbol, yPoint, idx, xPoint;
		for (var i = 0; i < this.chart.series.length; i++) {
			seria = this.chart.series[i];
			yNumCache = this.cChartDrawer.getNumCache(seria.yVal);

			if (!yNumCache) {
				continue;
			}

			for (var n = 0; n < yNumCache.ptCount; n++) {
				//idx - индекс точки по оси OY
				idx = yNumCache.pts && undefined !== yNumCache.pts[n] ? yNumCache.pts[n].idx : null;
				if(null === idx) {
					continue;
				}

				//вычисляем yVal
				//пытаемся вычислить xVal  в зависимости от idx точки по OY
				yVal = this._getYVal(n, i);
				xPoint = this.cChartDrawer.getIdxPoint(seria, idx, true);
				if (xPoint) {
					xVal = xPoint.val;
					if (!isNaN(parseFloat(xVal))) {
						xVal = parseFloat(xVal);
					} else {
						xVal = n + 1;
					}
				} else {
					//xVal = betweenAxisCross ? n : n + 1;
					//xVal = this.catAx instanceof AscFormat.CCatAx ? n : n + 1;
					xVal = n + 1;
				}


				yPoint = this.cChartDrawer.getIdxPoint(seria, idx);
				compiledMarkerSize = yPoint && yPoint.compiledMarker ? yPoint.compiledMarker.size : null;
				compiledMarkerSymbol = yPoint && yPoint.compiledMarker ? yPoint.compiledMarker.symbol : null;


				if (!this.paths.points) {
					this.paths.points = [];
				}
				if (!this.paths.points[i]) {
					this.paths.points[i] = [];
				}

				if (!points) {
					points = [];
				}
				if (!points[i]) {
					points[i] = [];
				}

				if (yVal != null) {
					this.paths.points[i][n] = this.cChartDrawer.calculatePoint(this.cChartDrawer.getYPosition(xVal, this.catAx, true), this.cChartDrawer.getYPosition(yVal, this.valAx), compiledMarkerSize, compiledMarkerSymbol);
					points[i][n] = {x: xVal, y: yVal};
				} else {
					this.paths.points[i][n] = null;
					points[i][n] = null;
				}
			}
		}

		this._calculateAllLines(points);
	},


	_recalculateScatter2: function () {
		var xPoints = this.catAx.xPoints;
		var yPoints = this.valAx.yPoints;
		var betweenAxisCross = this.valAx.crossBetween === AscFormat.CROSS_BETWEEN_BETWEEN;

		var seria, yVal, xVal, points, yNumCache, compiledMarkerSize, compiledMarkerSymbol, yPoint, idx, xPoint;
		for (var i = 0; i < this.chart.series.length; i++) {
			seria = this.chart.series[i];
			yNumCache = this.cChartDrawer.getNumCache(seria.yVal);

			if (!yNumCache) {
				continue;
			}

			for (var n = 0; n < yNumCache.ptCount; n++) {
				//idx - индекс точки по оси OY
				idx = yNumCache.pts && undefined !== yNumCache.pts[n] ? yNumCache.pts[n].idx : null;
				if(null === idx) {
					continue;
				}

				//вычисляем yVal
				//пытаемся вычислить xVal  в зависимости от idx точки по OY
				yVal = this._getYVal(n, i);
				xPoint = this.cChartDrawer.getIdxPoint(seria, idx, true);
				if (xPoint) {
					xVal = xPoint.val;
					if (!isNaN(parseFloat(xVal))) {
						xVal = parseFloat(xVal);
					} else {
						xVal = n + 1;
					}
				} else {
					//xVal = betweenAxisCross ? n : n + 1;
					//xVal = this.catAx instanceof AscFormat.CCatAx ? n : n + 1;
					xVal = n + 1;
				}


				yPoint = this.cChartDrawer.getIdxPoint(seria, idx);
				compiledMarkerSize = yPoint && yPoint.compiledMarker ? yPoint.compiledMarker.size : null;
				compiledMarkerSymbol = yPoint && yPoint.compiledMarker ? yPoint.compiledMarker.symbol : null;


				if (!this.paths.points) {
					this.paths.points = [];
				}
				if (!this.paths.points[i]) {
					this.paths.points[i] = [];
				}

				if (!points) {
					points = [];
				}
				if (!points[i]) {
					points[i] = [];
				}

				if (yVal != null) {
					this.paths.points[i][n] = this.cChartDrawer.calculatePoint(this.cChartDrawer.getYPosition(xVal, this.catAx, true), this.cChartDrawer.getYPosition(yVal, this.valAx), compiledMarkerSize, compiledMarkerSymbol);
					points[i][n] = {x: xVal, y: yVal};
				} else {
					this.paths.points[i][n] = null;
					points[i][n] = null;
				}
			}
		}

		this._calculateAllLines(points);
	},

	_calculateAllLines: function (points) {
		var xPoints = this.catAx.xPoints;
		var yPoints = this.valAx.yPoints;

		var x, y, x1, y1, isSplineLine;

		if(!points) {
			return;
		}

		for (var i = 0; i < points.length; i++) {
			isSplineLine = this.chart.series[i].smooth !== false;

			if (!points[i]) {
				continue;
			}

			for (var n = 0; n < points[i].length; n++) {
				if (!this.paths.series) {
					this.paths.series = [];
				}
				if (!this.paths.series[i]) {
					this.paths.series[i] = [];
				}

				if (points[i][n] != null && points[i][n + 1] != null) {
					if (isSplineLine) {

						var x = points[i][n - 1] ? points[i][n - 1].x : points[i][n].x;
						var y = points[i][n - 1] ? points[i][n - 1].y : points[i][n].y;

						var x1 = points[i][n].x;
						var y1 = points[i][n].y;

						var x2 = points[i][n + 1] ? points[i][n + 1].x : points[i][n].x;
						var y2 = points[i][n + 1] ? points[i][n + 1].y : points[i][n].y;

						var x3 = points[i][n + 2] ? points[i][n + 2].x : points[i][n + 1] ? points[i][n + 1].x : points[i][n].x;
						var y3 = points[i][n + 2] ? points[i][n + 2].y : points[i][n + 1] ? points[i][n + 1].y : points[i][n].y;

						//this.paths.series[i][n] = {path: this.cChartDrawer.calculateSplineLine(x, y, x1, y1, x2, y2, x3, y3, this.catAx, this.valAx), idx: points[i][n].idx};
						this.paths.series[i][n] = this.cChartDrawer.calculateSplineLine(x, y, x1, y1, x2, y2, x3, y3, this.catAx, this.valAx);
					} else {
						x = this.cChartDrawer.getYPosition(points[i][n].x, this.catAx);
						y = this.cChartDrawer.getYPosition(points[i][n].y, this.valAx);

						x1 = this.cChartDrawer.getYPosition(points[i][n + 1].x, this.catAx);
						y1 = this.cChartDrawer.getYPosition(points[i][n + 1].y, this.valAx);

						//this.paths.series[i][n] = {path: this._calculateLine(x, y, x1, y1), idx: points[i][n].idx};
						this.paths.series[i][n] = this._calculateLine(x, y, x1, y1);
					}
				}
			}
		}
	},

	_getYVal: function (n, i) {
		var idxPoint = this.cChartDrawer.getPointByIndex(this.chart.series[i], n);
		return idxPoint ? parseFloat(idxPoint.val) : null;
	},

	_drawScatter: function () {
		//TODO 2 раза проходимся по сериям!
		//add clip rect
		var diffPen = 2;
		var leftRect = this.chartProp.chartGutter._left / this.chartProp.pxToMM;
		var topRect = (this.chartProp.chartGutter._top - diffPen) / this.chartProp.pxToMM;
		var rightRect = this.chartProp.trueWidth / this.chartProp.pxToMM;
		var bottomRect = (this.chartProp.trueHeight + diffPen) / this.chartProp.pxToMM;

		this.cChartDrawer.cShapeDrawer.Graphics.SaveGrState();
		this.cChartDrawer.cShapeDrawer.Graphics.AddClipRect(leftRect, topRect, rightRect, bottomRect);
		//draw lines
		//this.cChartDrawer.drawPathsByIdx(this.paths, this.chart.series, true, true);
		this.cChartDrawer.drawPaths(this.paths, this.chart.series, true, true);
		//end clip rect
		this.cChartDrawer.cShapeDrawer.Graphics.RestoreGrState();

		this.cChartDrawer.drawPathsPoints(this.paths, this.chart.series, true);
	},

	_calculateLine: function (x, y, x1, y1) {
		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;

		path.moveTo(x * pathH, y * pathW);
		path.lnTo(x1 * pathH, y1 * pathW);

		return pathId;
	},

	_calculateDLbl: function (chartSpace, ser, val) {
		var point = this.cChartDrawer.getIdxPoint(this.chart.series[ser], val);

		var path;

		if (this.paths.points) {
			if (this.paths.points[ser] && this.paths.points[ser][val]) {
				var oPath = this.cChartSpace.GetPath(this.paths.points[ser][val].path);
				path = oPath.getCommandByIndex(0);
			}
		}

		if (!path) {
			return;
		}

		var x = path.X;
		var y = path.Y;

		var pxToMm = this.chartProp.pxToMM;
		var constMargin = 5 / pxToMm;

		var width = point.compiledDlb.extX;
		var height = point.compiledDlb.extY;

		var centerX = x - width / 2;
		var centerY = y - height / 2;

		switch (point.compiledDlb.dLblPos) {
			case c_oAscChartDataLabelsPos.b: {
				centerY = centerY + height / 2 + constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.bestFit: {
				break;
			}
			case c_oAscChartDataLabelsPos.ctr: {
				break;
			}
			case c_oAscChartDataLabelsPos.l: {
				centerX = centerX - width / 2 - constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.r: {
				centerX = centerX + width / 2 + constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.t: {
				centerY = centerY - height / 2 - constMargin;
				break;
			}
		}

		if (centerX < 0) {
			centerX = 0;
		}
		if (centerX + width > this.chartProp.widthCanvas / pxToMm) {
			centerX = this.chartProp.widthCanvas / pxToMm - width;
		}

		if (centerY < 0) {
			centerY = 0;
		}
		if (centerY + height > this.chartProp.heightCanvas / pxToMm) {
			centerY = this.chartProp.heightCanvas / pxToMm - height;
		}

		return {x: centerX, y: centerY};
	},

	//TODO пока включаю функцию _calculateSplineLine. с _calculateSplineLine2 отрисовается неверно. проверить!
	_calculateSplineLine2: function (points, k, xPoints, yPoints) {

		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;

		var x = points[k - 1] ? points[k - 1].x : points[k].x;
		var y = points[k - 1] ? points[k - 1].y : points[k].y;

		var x1 = points[k].x;
		var y1 = points[k].y;

		var x2 = points[k + 1] ? points[k + 1].x : points[k].x;
		var y2 = points[k + 1] ? points[k + 1].y : points[k].y;

		var x3 = points[k + 2] ? points[k + 2].x : points[k + 1] ? points[k + 1].x : points[k].x;
		var y3 = points[k + 2] ? points[k + 2].y : points[k + 1] ? points[k + 1].y : points[k].y;


		var splineCoords = this.cChartDrawer.calculate_Bezier(x, y, x1, y1, x2, y2, x3, y3);

		x = this.cChartDrawer.getYPosition(splineCoords[0].x, this.catAx);
		y = this.cChartDrawer.getYPosition(splineCoords[0].y, this.valAx);

		x1 = this.cChartDrawer.getYPosition(splineCoords[1].x, this.catAx);
		y1 = this.cChartDrawer.getYPosition(splineCoords[1].y, this.valAx);

		x2 = this.cChartDrawer.getYPosition(splineCoords[2].x, this.catAx);
		y2 = this.cChartDrawer.getYPosition(splineCoords[2].y, this.valAx);

		x3 = this.cChartDrawer.getYPosition(splineCoords[3].x, this.catAx);
		y3 = this.cChartDrawer.getYPosition(splineCoords[3].y, this.valAx);

		path.moveTo(x * pathW, y * pathH);
		path.cubicBezTo(x1 * pathW, y1 * pathH, x2 * pathW, y2 * pathH, x3 * pathW, y3 * pathH);


		return pathId;
	}
};


/** @constructor */
function drawStockChart(chart, chartsDrawer) {
	this.chartProp = chartsDrawer.calcProp;
	this.cChartDrawer = chartsDrawer;
	this.cChartSpace = chartsDrawer.cChartSpace;

	this.chart = chart;
	this.catAx = null;
	this.valAx = null;

	this.paths = {};
}

drawStockChart.prototype = {
	constructor: drawStockChart,

	draw: function () {
		this._drawLines();
	},

	recalculate: function () {
		this.paths = {};

		this.catAx = this.chart.axId[0].xPoints ? this.chart.axId[0] : this.chart.axId[1];
		this.catAx = this.cChartDrawer._searchChangedAxis(this.catAx);
		this.valAx = this.chart.axId[0].yPoints ? this.chart.axId[0] : this.chart.axId[1];
		this.valAx = this.cChartDrawer._searchChangedAxis(this.valAx);

		this._calculateLines();
	},

	_calculateLines: function () {
		var xPoints = this.catAx.xPoints;
		var yPoints = this.valAx.yPoints;

		var trueWidth = this.chartProp.trueWidth;

		var numCache = this.cChartDrawer.getNumCache(this.chart.series[0].val);
		if(!numCache) {
			return;
		}

		var koffX = trueWidth / numCache.pts.length;

		var gapWidth = this.chart.upDownBars && AscFormat.isRealNumber(this.chart.upDownBars.gapWidth) ? this.chart.upDownBars.gapWidth : 150;

		var widthBar = koffX / (1 + gapWidth / 100);

		var val1, val2, val3, val4, xVal, yVal1, yVal2, yVal3, yVal4, curNumCache, lastNamCache;
		for (var i = 0; i < numCache.pts.length; i++) {

			val1 = null, val2 = null, val3 = null, val4 = null;
			val1 = numCache.pts[i].val;

			lastNamCache = this.cChartDrawer.getNumCache(this.chart.series[this.chart.series.length - 1].val).pts;
			val4 = lastNamCache && lastNamCache[i] ? lastNamCache[i].val : null;

			for (var k = 1; k < this.chart.series.length - 1; k++) {
				curNumCache = this.cChartDrawer.getNumCache(this.chart.series[k].val);
				if (curNumCache && curNumCache.pts[i]) {
					if (k === 1) {
						val2 = curNumCache.pts[i].val;
						val3 = curNumCache.pts[i].val;
					} else {
						if (parseFloat(val2) > parseFloat(curNumCache.pts[i].val)) {
							val2 = curNumCache.pts[i].val;
						}
						if (parseFloat(val3) < parseFloat(curNumCache.pts[i].val)) {
							val3 = curNumCache.pts[i].val;
						}
					}
				}
			}

			if (!this.paths.values) {
				this.paths.values = [];
			}
			if (!this.paths.values[i]) {
				this.paths.values[i] = {};
			}

			xVal = this.cChartDrawer.getYPosition(i + 1, this.catAx);
			yVal1 = this.cChartDrawer.getYPosition(val1, this.valAx);
			yVal2 = this.cChartDrawer.getYPosition(val2, this.valAx);
			yVal3 = this.cChartDrawer.getYPosition(val3, this.valAx);
			yVal4 = this.cChartDrawer.getYPosition(val4, this.valAx);

			if (val2 !== null && val1 !== null) {
				this.paths.values[i].lowLines = this._calculateLine(xVal, yVal2, xVal, yVal1);
			}
			if (val3 && val4) {
				this.paths.values[i].highLines = this._calculateLine(xVal, yVal4, xVal, yVal3);
			}

			if (val1 !== null && val4 !== null) {
				if (parseFloat(val1) > parseFloat(val4)) {
					this.paths.values[i].downBars = this._calculateUpDownBars(xVal, yVal1, xVal, yVal4, widthBar / this.chartProp.pxToMM);
				} else if (val1 && val4) {
					this.paths.values[i].upBars = this._calculateUpDownBars(xVal, yVal1, xVal, yVal4, widthBar / this.chartProp.pxToMM);
				}
			}
		}
	},

	_drawLines: function () {
		var brush;
		var pen;
		var numCache = this.cChartDrawer.getNumCache(this.chart.series[0].val);
		if(!numCache) {
			return;
		}

		for (var i = 0; i < numCache.pts.length; i++) {

			pen = this.chart.calculatedHiLowLines;

			this.cChartDrawer.drawPath(this.paths.values[i].lowLines, pen, brush);
			this.cChartDrawer.drawPath(this.paths.values[i].highLines, pen, brush);

			if (this.paths.values[i].downBars) {
				brush = this.chart.upDownBars ? this.chart.upDownBars.downBarsBrush : null;
				pen = this.chart.upDownBars ? this.chart.upDownBars.downBarsPen : null;
				this.cChartDrawer.drawPath(this.paths.values[i].downBars, pen, brush);
			} else {
				brush = this.chart.upDownBars ? this.chart.upDownBars.upBarsBrush : null;
				pen = this.chart.upDownBars ? this.chart.upDownBars.upBarsPen : null;
				this.cChartDrawer.drawPath(this.paths.values[i].upBars, pen, brush);
			}
		}
	},

	_calculateLine: function (x, y, x1, y1) {

		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;


		path.moveTo(x * pathW, y * pathH);
		path.lnTo(x1 * pathW, y1 * pathH);

		return pathId;
	},

	_calculateDLbl: function (chartSpace, ser, val) {
		var pxToMm = this.chartProp.pxToMM;
		var min = this.valAx.scale[0];
		var max = this.valAx.scale[this.valAx.scale.length - 1];

		var digHeight = Math.abs(max - min);

		if (/*this.chartProp.min < 0 && this.chartProp.max <= 0*/min < 0 && max <= 0) {
			min = -1 * max;
		}

		var numCache = this.cChartDrawer.getNumCache(this.chart.series[0].val);
		if(!numCache) {
			return {x: null, y: null};
		}

		var koffX = this.chartProp.trueWidth / numCache.pts.length;
		var koffY = this.chartProp.trueHeight / digHeight;

		var point = this.chart.series[ser].val.numRef ? this.chart.series[ser].val.numRef.numCache.pts[val] : this.chart.series[ser].val.numLit.pts[val];

		var x = this.chartProp.chartGutter._left + (val) * koffX + koffX / 2;
		var y = this.chartProp.trueHeight - (point.val - min) * koffY + this.chartProp.chartGutter._top;

		var width = point.compiledDlb.extX;
		var height = point.compiledDlb.extY;

		var centerX = x / pxToMm - width / 2;
		var centerY = y / pxToMm - height / 2;
		var constMargin = 5 / pxToMm;

		switch (point.compiledDlb.dLblPos) {
			case c_oAscChartDataLabelsPos.b: {
				centerY = centerY + height / 2 + constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.bestFit: {
				break;
			}
			case c_oAscChartDataLabelsPos.ctr: {
				break;
			}
			case c_oAscChartDataLabelsPos.l: {
				centerX = centerX - width / 2 - constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.r: {
				centerX = centerX + width / 2 + constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.t: {
				centerY = centerY - height / 2 - constMargin;
				break;
			}
		}

		if (centerX < 0) {
			centerX = 0;
		}
		if (centerX + width > this.chartProp.widthCanvas / pxToMm) {
			centerX = this.chartProp.widthCanvas / pxToMm - width;
		}

		if (centerY < 0) {
			centerY = 0;
		}
		if (centerY + height > this.chartProp.heightCanvas / pxToMm) {
			centerY = this.chartProp.heightCanvas / pxToMm - height;
		}

		return {x: centerX, y: centerY};
	},

	_calculateUpDownBars: function (x, y, x1, y1, width) {
		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;

		path.moveTo((x - width / 2) * pathW, y * pathH);
		path.lnTo((x - width / 2) * pathW, y1 * pathH);
		path.lnTo((x + width / 2) * pathW, y1 * pathH);
		path.lnTo((x + width / 2) * pathW, y * pathH);
		path.lnTo((x - width / 2) * pathW, y * pathH);

		return pathId;
	}
};

/** @constructor */
function drawBubbleChart(chart, chartsDrawer) {
	this.chartProp = chartsDrawer.calcProp;
	this.cChartDrawer = chartsDrawer;
	this.cChartSpace = chartsDrawer.cChartSpace;

	this.chart = chart;
	this.catAx = null;
	this.valAx = null;

	this.paths = {};
}

drawBubbleChart.prototype = {
	constructor: drawBubbleChart,

	recalculate: function () {
		this.paths = {};

		this.catAx = this.chart.axId[0].xPoints ? this.chart.axId[0] : this.chart.axId[1];
		this.catAx = this.cChartDrawer._searchChangedAxis(this.catAx);
		this.valAx = this.chart.axId[0].yPoints ? this.chart.axId[0] : this.chart.axId[1];
		this.valAx = this.cChartDrawer._searchChangedAxis(this.valAx);

		this._recalculateScatter();
	},

	draw: function () {
		this._drawScatter();
	},

	_recalculateScatter: function () {
		var xPoints = this.catAx.xPoints;
		var yPoints = this.valAx.yPoints;

		var seria, yVal, xVal, points, x, y, yNumCache, xNumCache;
		for (var i = 0; i < this.chart.series.length; i++) {
			seria = this.chart.series[i];
			points = [];
			yNumCache = this.cChartDrawer.getNumCache(seria.yVal);
			if(!yNumCache) {
				continue;
			}

			for (var n = 0; n < yNumCache.pts.length; n++) {
				yVal = parseFloat(yNumCache.pts[n].val);

				xNumCache = this.cChartDrawer.getNumCache(seria.xVal);
				if (xNumCache && xNumCache.pts[n] && xNumCache.pts[n].val) {
					if (!isNaN(parseFloat(xNumCache.pts[n].val))) {
						xVal = parseFloat(xNumCache.pts[n].val);
					} else {
						xVal = n + 1;
					}
				} else {
					xVal = n + 1;
				}

				points[n] = {x: xVal, y: yVal}
			}

			for (var k = 0; k < points.length; k++) {
				y = this.cChartDrawer.getYPosition(points[k].y, this.valAx);
				x = this.cChartDrawer.getYPosition(points[k].x, this.catAx);


				if (!this.paths.points) {
					this.paths.points = [];
				}
				if (!this.paths.points[i]) {
					this.paths.points[i] = [];
				}

				this.paths.points[i][k] = this._calculateBubble(x, y, seria.bubbleSize, k);
			}
		}
	},

	_drawScatter: function () {
		var seria, brush, pen, markerBrush, markerPen, yNumCache;
		for (var i = 0; i < this.chart.series.length; i++) {
			seria = this.chart.series[i];
			brush = seria.brush;
			pen = seria.pen;

			//draw bubble
			if (this.paths.points && this.paths.points[i]) {
				for (var k = 0; k < this.paths.points[i].length; k++) {
					yNumCache = this.cChartDrawer.getNumCache(this.chart.series[i].yVal);
					if(!yNumCache) {
						continue;
					}

					markerBrush = yNumCache.pts[k].compiledMarker.brush;
					markerPen = yNumCache.pts[k].compiledMarker.pen;

					//point
					this.cChartDrawer.drawPath(this.paths.points[i][k], markerPen, markerBrush, true);
				}
			}
		}
	},

	_calculateDLbl: function (chartSpace, ser, val) {
		var point;
		if (this.chart.series[ser - 1]) {
			//point = this.chart.series[ser - 1].yVal.numRef ? this.chart.series[ser - 1].yVal.numRef.numCache.pts[val] : this.chart.series[ser - 1].yVal.numLit.pts[val]
			point = this.cChartDrawer.getNumCache(this.chart.series[ser - 1].yVal);
		} else {
			//point = this.chart.series[ser].yVal.numRef ? this.chart.series[ser].yVal.numRef.numCache.pts[val] : this.chart.series[ser].yVal.numLit.pts[val];
			point = this.cChartDrawer.getNumCache(this.chart.series[ser].yVal);
		}
		if(!point) {
			return {x: null, y: null};
		}

		var path;

		if (this.paths.points) {
			if (this.paths.points[ser] && this.paths.points[ser][val]) {
				var oPath = this.cChartSpace.GetPath(this.paths.points[ser][val].path);
				path = oPath.getCommandByIndex(0);
			}

		}

		if (!path) {
			return;
		}

		var x = path.X;
		var y = path.Y;

		var pxToMm = this.chartProp.pxToMM;
		var constMargin = 5 / pxToMm;

		var width = point.compiledDlb.extX;
		var height = point.compiledDlb.extY;

		var centerX = x - width / 2;
		var centerY = y - height / 2;

		switch (point.compiledDlb.dLblPos) {
			case c_oAscChartDataLabelsPos.b: {
				centerY = centerY + height / 2 + constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.bestFit: {
				break;
			}
			case c_oAscChartDataLabelsPos.ctr: {
				break;
			}
			case c_oAscChartDataLabelsPos.l: {
				centerX = centerX - width / 2 - constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.r: {
				centerX = centerX + width / 2 + constMargin;
				break;
			}
			case c_oAscChartDataLabelsPos.t: {
				centerY = centerY - height / 2 - constMargin;
				break;
			}
		}

		if (centerX < 0) {
			centerX = 0;
		}
		if (centerX + width > this.chartProp.widthCanvas / pxToMm) {
			centerX = this.chartProp.widthCanvas / pxToMm - width;
		}

		if (centerY < 0) {
			centerY = 0;
		}
		if (centerY + height > this.chartProp.heightCanvas / pxToMm) {
			centerY = this.chartProp.heightCanvas / pxToMm - height;
		}

		return {x: centerX, y: centerY};
	},

	_calculateBubble: function (x, y, bubbleSize, k) {
		var defaultSize = 4;

		if (bubbleSize) {
			var maxSize, curSize, yPoints, maxDiamBubble, diffSize, maxArea;


			maxSize = this.cChartDrawer._getMaxMinValueArray(bubbleSize).max;
			curSize = bubbleSize[k].val;

			yPoints = this.valAx.yPoints ? this.valAx.yPoints : this.catAx.yPoints;
			maxDiamBubble = Math.abs(yPoints[1].pos - yPoints[0].pos) * 2;

			diffSize = maxSize / curSize;

			var isDiam = false;

			if (isDiam) {
				defaultSize = (maxDiamBubble / diffSize) / 2;
			} else {
				maxArea = 1 / 4 * (Math.PI * (maxDiamBubble * maxDiamBubble));
				defaultSize = Math.sqrt((maxArea / diffSize) / Math.PI);
			}
		}


		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;

		path.moveTo((x + defaultSize) * pathW, y * pathH);
		path.arcTo(defaultSize * pathW, defaultSize * pathW, 0, Math.PI * 2 * cToDeg);

		return pathId;
	}
};


/** @constructor */
function drawSurfaceChart(chart, chartsDrawer) {
	this.chartProp = chartsDrawer.calcProp;
	this.cChartDrawer = chartsDrawer;
	this.cChartSpace = chartsDrawer.cChartSpace;

	this.chart = chart;
	this.catAx = null;
	this.valAx = null;

	this.paths = {};
}

drawSurfaceChart.prototype = {
	constructor: drawSurfaceChart,

	recalculate: function () {
		this.paths = {};

		var countSeries = this.cChartDrawer.calculateCountSeries(this.chart);
		this.ptCount = countSeries.points;
		this.catAx = this.cChartDrawer.getAxisFromAxId(this.chart.axId, AscDFH.historyitem_type_CatAx);
		if(!this.catAx) {
			this.catAx = this.cChartDrawer.getAxisFromAxId(this.chart.axId, AscDFH.historyitem_type_DateAx);
		}
		this.valAx = this.cChartDrawer.getAxisFromAxId(this.chart.axId, AscDFH.historyitem_type_ValAx);

		this._recalculate();
	},

	draw: function () {
		this._draw();
	},

	_recalculate: function () {
		var yPoints = this.valAx.yPoints;
		var xPoints = this.catAx.xPoints;
		var perspectiveDepth = this.cChartDrawer.processor3D.depthPerspective;

		var y, x, z, val, seria, dataSeries, idx, numCache, idxPoint, points = [], points3d = [], idx2, val2;
		for (var i = 0; i < this.chart.series.length; i++) {
			seria = this.chart.series[i];
			numCache = this.cChartDrawer.getNumCache(seria.val);

			if (!numCache) {
				continue;
			}

			dataSeries = numCache.pts;
			for (var n = 0; n < this.ptCount; n++) {
				//рассчитываем значения
				idx = dataSeries[n] && dataSeries[n].idx != null ? dataSeries[n].idx : n;

				//TODO временно заменил idx на n. позже нужно использовать idx  -> val = this._getYVal(idx, i);
				val = this._getYVal(n, i);
				if (null === val) {
					val = 0;
				}

				x = xPoints[n].pos * this.chartProp.pxToMM;
				y = this.cChartDrawer.getYPosition(val, this.valAx) * this.chartProp.pxToMM;
				z = (perspectiveDepth / (this.chart.series.length - 1)) * (i);

				//рассчитываем значения
				idx2 = dataSeries[n + 1] && dataSeries[n + 1].idx != null ? dataSeries[n + 1].idx : null;

				//TODO временно заменил idx на n. позже нужно использовать idx
				//var val2 = Math.round(this._getYVal(n + 1, i) * roundInt) / roundInt;
				val2 = this._getYVal(n + 1, i);
				if (null === val2) {
					val2 = 0;
				}

				if (!points) {
					points = [];
				}
				if (!points[i]) {
					points[i] = [];
				}

				if (!points3d) {
					points3d = [];
				}
				if (!points3d[i]) {
					points3d[i] = [];
				}

				if (val != null) {
					points3d[i][n] = {x: x, y: y, z: z, val: val};
					var convertResult = this.cChartDrawer._convertAndTurnPoint(x, y, z);
					var x1 = convertResult.x;
					var y1 = convertResult.y;
					points[i][n] = {x: x1, y: y1, val: val};
				} else {
					points[i][n] = null;
				}
			}
		}

		this._calculateAllFaces(points, points3d);
	},


	_calculateAllFaces: function (points, points3d) {
		if (!this.paths.test) {
			this.paths.test = [];
		}
		if (!this.paths.test2) {
			this.paths.test2 = [];
		}

		for (var i = 0; i < points.length - 1; i++) {
			for (var j = 0; j < points[i].length - 1; j++) {
				var p1 = points[i][j];
				var p2 = points[i + 1][j];
				var p3 = points[i][j + 1];
				var p4 = points[i + 1][j + 1];

				this.paths.test.push(this.cChartDrawer._calculatePathFace(p1, p3, p4, p2, true));

				var p13d = points3d[i][j];
				var p23d = points3d[i + 1][j];
				var p33d = points3d[i][j + 1];
				var p43d = points3d[i + 1][j + 1];

				//рассчитываем отдельный сегмент - смотрим, может ли он располагаться в одной плоскости + делим его плоскостями сетки
				//p, p2, p21, p1 - точки данного сегмента
				//  p1-----p21
				//  |       |
				//  |       |
				//  p-------p2
				this._calculateFace(p1, p2, p3, p4, p13d, p23d, p33d, p43d);
			}
		}
	},

	_calculateFace: function (p, p1, p2, p21, p3d, p13d, p23d, p213d) {
		var t = this;

		//все стороны сегмента
		var lines = [];
		lines[0] = {p1: p3d, p2: p23d, p111: p, p222: p2};
		lines[1] = {p1: p13d, p2: p213d, p111: p1, p222: p21};
		lines[2] = {p1: p3d, p2: p13d, p111: p, p222: p1};
		lines[3] = {p1: p23d, p2: p213d, p111: p2, p222: p21};


		var pointsValue = [p1, p2, p21, p];
		if (this.cChartDrawer.isPointsLieIntoOnePlane(p3d, p13d, p213d, p23d))//не делим диагональю данный сегмент
		{
			this._getIntersectionPlanesAndLines(lines, pointsValue, true);
		} else//делим диагональю данный сегмент
		{
			var max = p.val;
			var maxIndex = 0;
			var arrVal = [p, p1, p2, p21];
			for (var m = 0; m < arrVal.length; m++) {
				if (arrVal[m].val > max) {
					max = arrVal[m].val;
					maxIndex = m;
				}
			}

			//разбиваем диагональю данный сегмент на два сегмента
			var lines1, pointsValue1, lines2, pointsValue2;
			if (p1.val + p2.val < p21.val + p.val) {
				//добавляем диагональ
				lines.push({p1: p213d, p2: p3d, p111: p21, p222: p});
				//this.paths.test.push(this._calculatePath(p21.x, p21.y, p.x, p.y));

				lines1 = [lines[0], lines[3], lines[4]];
				pointsValue1 = [p, p21, p2];
				lines2 = [lines[2], lines[1], lines[4]];
				pointsValue2 = [p, p1, p21];
			} else {
				//добавляем диагональ
				lines.push({p1: p13d, p2: p23d, p111: p1, p222: p2});
				//this.paths.test.push(this._calculatePath(p2.x, p2.y, p1.x, p1.y));

				lines1 = [lines[2], lines[0], lines[4]];
				pointsValue1 = [p, p1, p2];
				lines2 = [lines[4], lines[1], lines[3]];
				pointsValue2 = [p2, p1, p21];
			}

			//для поверхностных диаграмм без заливки
			var bIsWireframeChart = false;

			//находим пересечение двух сегментов с плоскостями сетки
			var pointsFace1 = this._getIntersectionPlanesAndLines(lines1, pointsValue1, !bIsWireframeChart);
			var pointsFace2 = this._getIntersectionPlanesAndLines(lines2, pointsValue2, !bIsWireframeChart);

			if (bIsWireframeChart) {
				var lengthFaces = Math.max(pointsFace1.length, pointsFace2.length);
				for (var l = 0; l < lengthFaces; l++) {
					var newPath = null;
					if (pointsFace1[l] && pointsFace2[l]) {
						var cleanPoints1 = this._getArrayWithoutRepeatePoints(pointsFace1[l]);
						var cleanPoints2 = this._getArrayWithoutRepeatePoints(pointsFace2[l]);

						if (cleanPoints1.length >= 3 && cleanPoints2.length >= 3) {
							newPath = cleanPoints1.concat(cleanPoints2);
						}
					} else if (pointsFace1[l]) {
						newPath = pointsFace1[l];
					} else if (pointsFace2[l]) {
						newPath = pointsFace2[l];
					}


					if (newPath) {
						if (!t.paths.test2[l]) {
							t.paths.test2[l] = [];
						}

						var path2 = t._calculateTempFace(newPath);
						t.paths.test2[l].push(path2);
					}
				}
			}

			//TODO временно убираю. если будут проблемы в отрисовке - раскомментировать!
			/*var lengthFaces = Math.max(pointsFace1.length, pointsFace2.length);
			 for(var l = 0; l < lengthFaces; l++)
			 {
			 if(pointsFace1[l] && pointsFace2[l])
			 {
			 //находим две точки, принадлежащие диагональной прямой. у обоих сегментов они должны быть
			 var lineEquation = t.cChartDrawer.getLineEquation2d(lines[4].p111, lines[4].p222);

			 var points1 = [];
			 for(var s = 0; s < pointsFace1[l].length; s++)
			 {
			 if(null === this._isEqualPoints(points1, pointsFace1[l][s]) && t.cChartDrawer.isPoint2DLieOnLine(lineEquation, pointsFace1[l][s]))
			 {
			 points1.push(pointsFace1[l][s]);
			 }
			 }

			 var points2 = []
			 for(var s = 0; s < pointsFace2[l].length; s++)
			 {
			 if(null === this._isEqualPoints(points2, pointsFace2[l][s]) && t.cChartDrawer.isPoint2DLieOnLine(lineEquation, pointsFace2[l][s]))
			 {
			 points2.push(pointsFace2[l][s]);
			 }
			 }

			 if(points1.length < 2 && points2.length === 2)
			 {
			 pointsFace1[l].push(points2[0]);
			 pointsFace1[l].push(points2[1]);
			 }
			 else if(points2.length < 2 && points1.length === 2)
			 {
			 pointsFace2[l].push(points1[0]);
			 pointsFace2[l].push(points1[1]);
			 }
			 }


			 if(!t.paths.test2[l])
			 {
			 t.paths.test2[l] = [];
			 }
			 if(pointsFace1[l])
			 {
			 var path1 = t._calculateTempFace(pointsFace1[l]);
			 t.paths.test2[l].push(path1);
			 }
			 if(pointsFace2[l])
			 {
			 var path2 = t._calculateTempFace(pointsFace2[l]);
			 t.paths.test2[l].push(path2);
			 }
			 }*/
		}
	},


	_getIntersectionPlanesAndLines: function (lines, pointsValue, bIsAddIntoPaths) {
		var t = this;
		var yPoints = this.valAx.yPoints;
		var xPoints = this.catAx.xPoints;
		var perspectiveDepth = this.cChartDrawer.processor3D.depthPerspective;

		var getGridPlain = function (index) {
			var gridX1 = xPoints[0].pos * t.chartProp.pxToMM;
			var gridX2 = xPoints[xPoints.length - 1].pos * t.chartProp.pxToMM;

			var gridY1 = yPoints[index].pos * t.chartProp.pxToMM;
			var gridY2 = yPoints[index].pos * t.chartProp.pxToMM;
			var gridPlain = t.cChartDrawer.getPlainEquation({x: gridX1, y: gridY1, z: 0}, {x: gridX2, y: gridY2, z: 0}, {x: gridX2, y: gridY2, z: perspectiveDepth});

			return gridPlain;
		};

		var getMinMaxValArray = function (pointsValue) {
			var min, max;
			if (pointsValue.length === 4) {
				min = Math.min(pointsValue[0].val, pointsValue[1].val, pointsValue[2].val, pointsValue[3].val);
				max = Math.max(pointsValue[0].val, pointsValue[1].val, pointsValue[2].val, pointsValue[3].val);
			} else {
				min = Math.min(pointsValue[0].val, pointsValue[1].val, pointsValue[2].val);
				max = Math.max(pointsValue[0].val, pointsValue[1].val, pointsValue[2].val);
			}
			return {min: min, max: max}
		};

		var calculateFaceBetween2GridLines = function (minVal, maxVal, k, pointsValue, res) {
			var result = false;

			if (yPoints[k - 1] && minVal >= yPoints[k - 1].val && maxVal <= yPoints[k].val) {
				var p1 = pointsValue[0];
				var p2 = pointsValue[1];
				var p3 = pointsValue[2];
				var p4 = pointsValue[3] ? pointsValue[3] : pointsValue[2];

				var path = t._calculateTempFace([p1, p2, p3, p4]);

				var addIndex = k;
				if (minVal === maxVal && yPoints[k] && minVal === yPoints[k].val) {
					addIndex = k + 1;
				}

				if (bIsAddIntoPaths) {
					if (!t.paths.test2[addIndex]) {
						t.paths.test2[addIndex] = [];
					}
					t.paths.test2[addIndex].push(path);
				}

				res[k] = [p1, p2, p3, p4];
				result = true;
			}

			return result;
		};

		var minMaxVal = getMinMaxValArray(pointsValue);
		var minVal = minMaxVal.min;
		var maxVal = minMaxVal.max;

		var res = [];

		var prevPoints = null;
		for (var k = 0; k < yPoints.length; k++) {
			//если сегмент весь находится между двумя соседними плоскостями сетки, то есть ни с одной из них не имеет пересечений
			if (calculateFaceBetween2GridLines(minVal, maxVal, k, pointsValue, res)) {
				break;
			}
			//если значение сетки больше максимального значения сегмента
			if (yPoints[k - 1] && yPoints[k].val > maxVal && yPoints[k - 1].val >= maxVal) {
				break;
			}

			//точки, которые находятся между данными плоскостями сетки(или лежат на них), обязательно должны войти в сегмент
			var pointNeedAddIntoFace = null;
			if (yPoints[k - 1]) {
				for (var i = 0; i < pointsValue.length; i++) {
					if (yPoints[k - 1].val <= pointsValue[i].val && yPoints[k].val >= pointsValue[i].val) {
						if (null === pointNeedAddIntoFace) {
							pointNeedAddIntoFace = [];
						}

						pointNeedAddIntoFace.push(pointsValue[i]);
					}
				}
			}


			var isCalculatePrevPoints = false;
			if (null === prevPoints) {
				for (var j = 0; j < pointsValue.length; j++) {
					if (pointsValue[j].val <= yPoints[k].val) {
						if (!prevPoints) {
							prevPoints = [];
						}
						prevPoints.push(pointsValue[j]);
						isCalculatePrevPoints = true;
					}
				}
			}

			//находим точки пересечения с текущей плоскостью сетки
			var gridPlane = getGridPlain(k);
			var points = this._getIntersectionPlaneAndLines(gridPlane, lines, pointsValue);

			if (!isCalculatePrevPoints && null === points && prevPoints) {
				for (var j = 0; j < pointsValue.length; j++) {
					if (pointsValue[j].val >= yPoints[k - 1].val) {
						if (!points) {
							points = [];
						}
						points.push(pointsValue[j]);
						isCalculatePrevPoints = true;
					}
				}
			}

			var arrPoints = null, p1, p2, p3, p4;
			if (null !== points && prevPoints) {
				p1 = prevPoints[0];
				p2 = prevPoints[1] ? prevPoints[1] : prevPoints[0];
				p3 = points[0];
				p4 = points[1] ? points[1] : points[0];

				arrPoints = [p1, p2, p3, p4];
				if (points[2]) {
					arrPoints.push(points[2]);
				}
				res[k] = arrPoints;
			} else if (prevPoints && prevPoints.length === 3 && !points && isCalculatePrevPoints) {
				p1 = prevPoints[0];
				p2 = prevPoints[1];
				p3 = prevPoints[2];
				p4 = prevPoints[3] ? prevPoints[3] : prevPoints[2];

				arrPoints = [p1, p2, p3, p4];
				res[k] = arrPoints;
			}

			//добавляем точки, которые обязательно должны присутвовать в сегменте
			if (arrPoints && null !== pointNeedAddIntoFace) {
				for (var i = 0; i < pointNeedAddIntoFace.length; i++) {
					arrPoints.push(pointNeedAddIntoFace[i]);
				}
			}

			//add to path array
			if (arrPoints && bIsAddIntoPaths) {
				var path = t._calculateTempFace(arrPoints);
				if (!t.paths.test2[k]) {
					t.paths.test2[k] = [];
				}
				t.paths.test2[k].push(path);
			}

			if (points !== null) {
				prevPoints = points;
			}
		}

		return res;
	},

	_getIntersectionPlaneAndLines: function (gridPlain, lines, pointsValue) {
		var res = null;

		var clearIntersectionPoints = [];
		var segmentIntersectionPoints = [];

		//n --> lines --> 0 - down, 1 - up, 2 - left, 3 - right, 4 - diagonal
		for (var n = 0; n < lines.length; n++) {
			var convertResult = this.cChartDrawer.isIntersectionPlainAndLineSegment(gridPlain, lines[n].p1, lines[n].p2, lines[n].p111, lines[n].p222);
			if (!convertResult) {
				continue;
			}

			if (null === this._isEqualPoints(pointsValue, convertResult)) {
				clearIntersectionPoints.push(convertResult);
			} else {
				if (null === this._isEqualPoints(segmentIntersectionPoints, convertResult)) {
					segmentIntersectionPoints.push(convertResult);
				}
			}
		}

		var p1, p2;
		if (!segmentIntersectionPoints.length) {
			if (clearIntersectionPoints.length === 2)//две точки, не равняющиеся ни одной точке сегмента
			{
				p1 = clearIntersectionPoints[0];
				p2 = clearIntersectionPoints[1];

				res = [p1, p2];
			} else if (clearIntersectionPoints.length === 1)//одна точка, не равняющиеся ни одной точке сегмента
			{
				p1 = clearIntersectionPoints[0];

				res = [p1];
			}
		} else if (segmentIntersectionPoints.length && clearIntersectionPoints.length) {
			if (1 === segmentIntersectionPoints.length && 1 === clearIntersectionPoints.length) {
				p1 = segmentIntersectionPoints[0];
				p2 = clearIntersectionPoints[0];

				res = [p1, p2];
			}
		} else if (segmentIntersectionPoints.length) {
			if (2 === segmentIntersectionPoints.length) {
				p1 = segmentIntersectionPoints[0];
				p2 = segmentIntersectionPoints[1];

				res = [p1, p2];
			} else if (1 === segmentIntersectionPoints.length) {
				p1 = segmentIntersectionPoints[0];

				res = [p1];
			}
		}

		return res;
	},

	_isEqualPoints: function (arr, point) {
		var res = null;

		for (var p = 0; p < arr.length; p++) {
			if (arr[p] && parseInt(point.x) === parseInt(arr[p].x) && parseInt(point.y) === parseInt(arr[p].y)) {
				res = p;
				break;
			}
		}

		return res;
	},

	_getArrayWithoutRepeatePoints: function (arr) {
		var newArray = [];

		for (var i = 0; i < arr.length; i++) {
			if (null === this._isEqualPoints(newArray, arr[i])) {
				newArray.push(arr[i]);
			}
		}

		return newArray;
	},

	_calculateTempFace: function (points) {
		var summX = 0;
		var summY = 0;
		for (var i = 0; i < points.length; i++) {
			summX += points[i].x;
			summY += points[i].y;
		}
		var x = 1 / (points.length) * (summX);
		var y = 1 / (points.length) * (summY);

		var sortArray = [];
		var repeatePoint = [];
		var nIndividualPoints = 0;
		for (var i = 0; i < points.length; i++) {
			var tan = Math.atan2(points[i].x - x, points[i].y - y);
			if (!repeatePoint[tan]) {
				sortArray[i] = {tan: tan, point: points[i]};
				repeatePoint[tan] = 1;
				nIndividualPoints++;
			}
		}

		var path = null
		if (nIndividualPoints > 2) {
			sortArray.sort(function sortArr(a, b) {
				return b.tan - a.tan;
			});

			path = this.cChartDrawer.calculatePathFacesArray(sortArray, true);
		}

		return path
	},


	_getYVal: function (n, i) {
		var idxPoint = this.cChartDrawer.getIdxPoint(this.chart.series[i], n);
		var val = idxPoint ? parseFloat(idxPoint.val) : null;

		return val;
	},

	_calculatePath: function (x, y, x1, y1) {
		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pxToMm = this.chartProp.pxToMM;

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;
		var gdLst = [];

		path.pathH = pathH;
		path.pathW = pathW;
		gdLst["w"] = 1;
		gdLst["h"] = 1;

		path.moveTo(x / pxToMm * pathW, y / pxToMm * pathH);
		path.lnTo(x1 / pxToMm * pathW, y1 / pxToMm * pathH);

		return pathId;
	},

	_draw: function () {
		var style = AscFormat.CHART_STYLE_MANAGER.getStyleByIndex(this.cChartSpace.style);

		for (var i = 0; i < this.paths.test2.length; i++) {
			if (!this.paths.test2[i]) {
				continue;
			}

			for (var j = 0; j < this.paths.test2[i].length; j++) {
				style = this.chart.compiledBandFormats[i - 1];
				var brush = style && style.spPr ? style.spPr.Fill : null;
				var pen = style && style.spPr ? style.spPr.ln : null;

				//линии пока делаю по цвету как и заливку
				if (!pen || (pen && 0 === pen.w)) {
					pen = AscFormat.CreatePenFromParams(brush, undefined, undefined, undefined, undefined, 0.13);
				}

				this.cChartDrawer.drawPath(this.paths.test2[i][j], pen, brush);
			}
		}
	}
};


/** @constructor */
function catAxisChart() {
	this.chartProp = null;
	this.cChartSpace = null;
	this.cChartDrawer = null;
	this.catAx = null;

	this.paths = {};
}

catAxisChart.prototype = {
	constructor: catAxisChart,

	draw: function (chartsDrawer, catAx, isDrawGrid) {
		this.chartProp = chartsDrawer.calcProp;
		this.cChartSpace = chartsDrawer.cChartSpace;
		this.cChartDrawer = chartsDrawer;

		if (catAx) {
			this.catAx = catAx;
		}

		if(isDrawGrid) {
			this._drawGridLines();
		} else {
			this._drawAxis();
			this._drawTickMark();
		}
	},

	recalculate: function (chartsDrawer, catAx) {
		this.chartProp = chartsDrawer.calcProp;
		this.cChartSpace = chartsDrawer.cChartSpace;
		this.cChartDrawer = chartsDrawer;
		this.catAx = catAx;

		this.paths = {};

		this._calculateGridLines();
		if (this.catAx.bDelete !== true) {
			this._calculateAxis();
			this._calculateTickMark();
		}
	},

	_calculateGridLines: function () {

		var paths;
		if (this.catAx.axPos === window['AscFormat'].AX_POS_L || this.catAx.axPos === window['AscFormat'].AX_POS_R) {
			//ось слева или справа, линии горизонтальные
			paths = this.cChartDrawer.getHorizontalGridLines(this.catAx, true);
		} else {
			paths = this.cChartDrawer.getVerticalGridLines(this.catAx, true);
		}
		this.paths.gridLines = paths ? paths.gridLines : null;
		this.paths.minorGridLines = paths ? paths.minorGridLines : null;
	},

	_calculateAxis: function () {
		var axisPos;
		var left = this.chartProp.chartGutter._left / this.chartProp.pxToMM;
		var right = (this.chartProp.widthCanvas - this.chartProp.chartGutter._right) / this.chartProp.pxToMM;
		var top = this.chartProp.chartGutter._top / this.chartProp.pxToMM;
		var bottom = (this.chartProp.heightCanvas - this.chartProp.chartGutter._bottom) / this.chartProp.pxToMM;

		if (this.catAx.axPos === window['AscFormat'].AX_POS_R || this.catAx.axPos === window['AscFormat'].AX_POS_L) {
			axisPos = this.catAx.posX;
			this.paths.axisLine = this._calculateLine(axisPos, top, axisPos, bottom);
		} else {
			//TODO сделать по аналогии с HBAR
			axisPos = this.catAx.posY;
			this.paths.axisLine = this._calculateLine(left, axisPos, right, axisPos);
		}
	},

	_calculateTickMark: function () {
		var widthLine = 0, widthMinorLine = 0;
		var crossMajorStep = 0, crossMinorStep = 0;

		switch (this.catAx.majorTickMark) {
			case c_oAscTickMark.TICK_MARK_CROSS: {
				widthLine = 5;
				crossMajorStep = 5;
				break;
			}
			case c_oAscTickMark.TICK_MARK_IN: {
				widthLine = -5;
				break;
			}
			case c_oAscTickMark.TICK_MARK_NONE: {
				widthLine = 0;
				break;
			}
			case c_oAscTickMark.TICK_MARK_OUT: {
				widthLine = 5;
				break;
			}
		}

		switch (this.catAx.minorTickMark) {
			case c_oAscTickMark.TICK_MARK_CROSS: {
				widthMinorLine = 3;
				crossMinorStep = 3;
				break;
			}
			case c_oAscTickMark.TICK_MARK_IN: {
				widthMinorLine = -3;
				break;
			}
			case c_oAscTickMark.TICK_MARK_NONE: {
				widthMinorLine = 0;
				break;
			}
			case c_oAscTickMark.TICK_MARK_OUT: {
				widthMinorLine = 3;
				break;
			}
		}

		//TODO необходимо при смене ориентации оси категорий менять axPos!!!
		//var orientation = this.cChartSpace && this.cChartSpace.chart.plotArea.valAx ? this.cChartSpace.chart.plotArea.valAx.scaling.orientation : ORIENTATION_MIN_MAX;
		var axPos = this.catAx.axPos;
		if (axPos === window['AscFormat'].AX_POS_T || axPos === window['AscFormat'].AX_POS_L) {
			widthMinorLine = -widthMinorLine;
			widthLine = -widthLine;
			crossMajorStep = -crossMajorStep;
			crossMinorStep = -crossMinorStep;
		}

		if (!(widthLine === 0 && widthMinorLine === 0)) {
			this._calculateTickMarks(widthLine, widthMinorLine, crossMajorStep, crossMinorStep);
		}
	},

	_calculateTickMarks: function(widthLine, widthMinorLine, crossMajorStep, crossMinorStep) {
		var orientation = this.catAx ? this.catAx.scaling.orientation : ORIENTATION_MIN_MAX;
		var minorStep, posX, posY, k, firstDiff = 0;
		var tickMarkSkip = this.catAx.tickMarkSkip ? this.catAx.tickMarkSkip : 1;

		var minorLinesCount = 2;
		if (this.catAx.axPos === window['AscFormat'].AX_POS_R || this.catAx.axPos === window['AscFormat'].AX_POS_L) {
			var yPoints = this.catAx.yPoints;

			if(!yPoints) {
				return;
			}

			var stepY = yPoints[1] ? Math.abs(yPoints[1].pos - yPoints[0].pos) : Math.abs(yPoints[0].pos - this.chartProp.chartGutter._bottom / this.chartProp.pxToMM);
			minorStep = stepY / minorLinesCount;
			posX = this.catAx.posX;

			//сдвиг, если положение оси - между делениями
			if (this.catAx.crossAx.crossBetween === AscFormat.CROSS_BETWEEN_BETWEEN) {
				//TODO избавиться от использовения параметров лругой оси!!!
				firstDiff = yPoints[1] ? Math.abs(yPoints[1].pos - yPoints[0].pos) : Math.abs(yPoints[0].pos - this.cChartSpace.chart.plotArea.valAx.posY) * 2;
			}

			if (orientation !== ORIENTATION_MIN_MAX) {
				minorStep = -minorStep;
				firstDiff = -firstDiff;
			}

			for (var i = 0; i < yPoints.length; i++) {
				k = i * tickMarkSkip;
				if (k >= yPoints.length) {
					break;
				}

				if(yPoints[k].val < 0) {
					continue;
				}
				//основные линии
				posY = yPoints[k].pos + firstDiff / 2;

				if (!this.paths.tickMarks) {
					this.paths.tickMarks = [];
				}
				this.paths.tickMarks[i] = this._calculateLine(posX, posY, posX + widthLine / this.chartProp.pxToMM, posY);

				if (((i + 1) * tickMarkSkip) === yPoints.length)//если последняя основная линия, то рисуем её
				{
					var posYtemp = yPoints[yPoints.length - 1].pos - firstDiff / 2;
					this.paths.tickMarks[i + 1] =
						this._calculateLine(posX - crossMajorStep / this.chartProp.pxToMM, posYtemp, posX + widthLine / this.chartProp.pxToMM, posYtemp);
				}


				//промежуточные линии
				if (widthMinorLine !== 0) {
					for (var n = 1; n < minorLinesCount; n++) {
						var posMinorY = posY - n * minorStep * tickMarkSkip;

						if (((posMinorY < yPoints[yPoints.length - 1].pos - firstDiff / 2) &&
							orientation === ORIENTATION_MIN_MAX) ||
							((posMinorY > yPoints[yPoints.length - 1].pos - firstDiff / 2) &&
							orientation !== ORIENTATION_MIN_MAX)) {
							break;
						}

						if (!this.paths.minorTickMarks) {
							this.paths.minorTickMarks = [];
						}
						if (!this.paths.minorTickMarks[i]) {
							this.paths.minorTickMarks[i] = [];
						}

						this.paths.minorTickMarks[i][n] = this._calculateLine(posX - crossMinorStep / this.chartProp.pxToMM, posMinorY, posX + widthMinorLine / this.chartProp.pxToMM, posMinorY);
					}
				}
			}
		} else {
			var xPoints = this.catAx.xPoints;

			if(!xPoints) {
				return;
			}

			var stepX = xPoints[1] ? Math.abs(xPoints[1].pos - xPoints[0].pos) : Math.abs(xPoints[0].pos - this.catAx.posX) * 2;
			minorStep = stepX / minorLinesCount;
			posY = this.catAx.posY;

			var posMinorX;
			if (this.catAx.crossAx.crossBetween === AscFormat.CROSS_BETWEEN_BETWEEN) {
				if (xPoints[1]) {
					firstDiff = Math.abs(xPoints[1].pos - xPoints[0].pos);
				} else if (this.cChartSpace.chart.plotArea.valAx.posX) {
					firstDiff = Math.abs(this.cChartSpace.chart.plotArea.valAx.posX - xPoints[0].pos) * 2;
				}
			}

			if (orientation !== ORIENTATION_MIN_MAX) {
				minorStep = -minorStep;
				firstDiff = -firstDiff;
			}

			//сам рассчёт основных и промежуточных линий
			for (var i = 0; i < xPoints.length; i++) {
				k = i * tickMarkSkip;
				if (k >= xPoints.length) {
					break;
				}

				if(xPoints[k].val < 0) {
					continue;
				}

				posX = xPoints[k].pos - firstDiff / 2;
				if (!this.paths.tickMarks) {
					this.paths.tickMarks = [];
				}
				this.paths.tickMarks[i] = this._calculateLine(posX, posY - crossMajorStep / this.chartProp.pxToMM, posX, posY + widthLine / this.chartProp.pxToMM);

				if (((i + 1) * tickMarkSkip) === xPoints.length)//если последняя основная линия, то рисуем её
				{
					var posXtemp = xPoints[xPoints.length - 1].pos + firstDiff / 2;
					this.paths.tickMarks[i + 1] = this._calculateLine(posXtemp, posY - crossMajorStep / this.chartProp.pxToMM, posXtemp, posY + widthLine / this.chartProp.pxToMM);
				}

				//промежуточные линии
				if (widthMinorLine !== 0) {
					for (var n = 1; n < minorLinesCount; n++) {
						posMinorX = posX + n * minorStep * tickMarkSkip;

						if (((posMinorX > xPoints[xPoints.length - 1].pos + firstDiff / 2) &&
							orientation === ORIENTATION_MIN_MAX) ||
							((posMinorX < xPoints[xPoints.length - 1].pos + firstDiff / 2) &&
							orientation !== ORIENTATION_MIN_MAX)) {
							break;
						}

						if (!this.paths.minorTickMarks) {
							this.paths.minorTickMarks = [];
						}
						if (!this.paths.minorTickMarks[i]) {
							this.paths.minorTickMarks[i] = [];
						}

						this.paths.minorTickMarks[i][n] =
							this._calculateLine(posMinorX, posY - crossMinorStep / this.chartProp.pxToMM, posMinorX, posY + widthMinorLine / this.chartProp.pxToMM);
					}
				}
			}
		}
	},


	_calculateLine: function (x, y, x1, y1) {

		if (this.cChartDrawer.nDimensionCount === 3) {
			var view3DProp = this.cChartSpace.chart.getView3d();

			var z = this.cChartDrawer.processor3D.calculateZPositionCatAxis();

			var convertResult = this.cChartDrawer._convertAndTurnPoint(x * this.chartProp.pxToMM,
				y * this.chartProp.pxToMM, z);
			x = convertResult.x / this.chartProp.pxToMM;
			y = convertResult.y / this.chartProp.pxToMM;
			convertResult =
				this.cChartDrawer._convertAndTurnPoint(x1 * this.chartProp.pxToMM, y1 * this.chartProp.pxToMM, z);
			x1 = convertResult.x / this.chartProp.pxToMM;
			y1 = convertResult.y / this.chartProp.pxToMM;
		}

		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;


		path.moveTo(x * pathW, y * pathH);
		path.lnTo(x1 * pathW, y1 * pathH);


		return pathId;
	},

	_drawGridLines: function () {
		var pen;
		var path;

		if (!this.paths.gridLines) {
			return;
		}

		for (var i = 0; i < this.paths.gridLines.length; i++) {
			//промежуточные линии
			if (this.paths.minorGridLines && this.paths.minorGridLines[i]) {
				for (var n = 0; n < this.paths.minorGridLines[i].length; n++) {
					path = this.paths.minorGridLines[i][n];
					pen = this.catAx.compiledMinorGridLines;
					this.cChartDrawer.drawPath(path, pen);
				}
			}

			pen = this.catAx.compiledMajorGridLines;

			path = this.paths.gridLines[i];
			this.cChartDrawer.drawPath(path, pen);
		}
	},

	_drawAxis: function () {
		var pen;
		var path;

		pen = this.catAx.compiledLn;
		path = this.paths.axisLine;

		this.cChartDrawer.drawPath(path, pen);
	},

	_drawTickMark: function () {
		var pen, path;
		if (this.paths.tickMarks) {
			for (var i = 0; i < this.paths.tickMarks.length; i++) {
				pen = this.catAx.compiledTickMarkLn;

				path = this.paths.tickMarks[i];
				this.cChartDrawer.drawPath(path, pen);

				//промежуточные линии
				if (this.paths.minorTickMarks && this.paths.minorTickMarks[i]) {
					for (var n = 0; n < this.paths.minorTickMarks[i].length; n++) {
						path = this.paths.minorTickMarks[i][n];
						this.cChartDrawer.drawPath(path, pen);
					}
				}
			}
		}
	}
};


/** @constructor */
function valAxisChart() {
	this.chartProp = null;
	this.cChartSpace = null;
	this.cChartDrawer = null;
	this.valAx = null;

	this.paths = {};
}

valAxisChart.prototype = {
	constructor: valAxisChart,

	draw: function (chartsDrawer, valAx, isDrawGrid) {
		this.chartProp = chartsDrawer.calcProp;
		this.cChartSpace = chartsDrawer.cChartSpace;
		this.cChartDrawer = chartsDrawer;
		if (valAx) {
			this.valAx = valAx;
		}

		if(isDrawGrid) {
			this._drawGridLines();
		} else {
			this._drawAxis();
			this._drawTickMark();
		}
	},

	recalculate: function (chartsDrawer, valAx) {
		this.chartProp = chartsDrawer.calcProp;
		this.cChartSpace = chartsDrawer.cChartSpace;
		this.cChartDrawer = chartsDrawer;
		this.valAx = valAx;

		this.paths = {};

		this._calculateGridLines();
		if (this.valAx.bDelete !== true) {
			this._calculateAxis();
			this._calculateTickMark();
		}
	},

	_calculateGridLines: function () {

		var paths;
		if (this.valAx.axPos === window['AscFormat'].AX_POS_L || this.valAx.axPos === window['AscFormat'].AX_POS_R) {
			//ось слева или справа, линии горизонтальные
			paths = this.cChartDrawer.getHorizontalGridLines(this.valAx);
		} else {
			paths = this.cChartDrawer.getVerticalGridLines(this.valAx);
		}
		this.paths.gridLines = paths ? paths.gridLines : null;
		this.paths.minorGridLines = paths ? paths.minorGridLines : null;
	},

	_calculateAxis: function () {
		var nullPosition = this.valAx.posX;
		var left = this.chartProp.chartGutter._left / this.chartProp.pxToMM;
		var right = (this.chartProp.widthCanvas - this.chartProp.chartGutter._right) / this.chartProp.pxToMM;
		var top = this.chartProp.chartGutter._top / this.chartProp.pxToMM;
		var bottom = (this.chartProp.heightCanvas - this.chartProp.chartGutter._bottom) / this.chartProp.pxToMM;

		if (this.valAx.axPos === window['AscFormat'].AX_POS_T || this.valAx.axPos === window['AscFormat'].AX_POS_B) {
			nullPosition = this.valAx.posY;
			this.paths.axisLine = this._calculateLine(left, nullPosition, right, nullPosition);
		} else {
			this.paths.axisLine = this._calculateLine(nullPosition, top, nullPosition, bottom);
		}
	},

	_calculateTickMark: function () {
		var widthLine = 0, widthMinorLine = 0;
		var crossMajorStep = 0;
		var crossMinorStep = 0;
		switch (this.valAx.majorTickMark) {
			case c_oAscTickMark.TICK_MARK_CROSS: {
				widthLine = 5;
				crossMajorStep = 5;
				break;
			}
			case c_oAscTickMark.TICK_MARK_IN: {
				widthLine = 5;
				break;
			}
			case c_oAscTickMark.TICK_MARK_NONE: {
				widthLine = 0;
				break;
			}
			case c_oAscTickMark.TICK_MARK_OUT: {
				widthLine = -5;
				break;
			}
		}

		switch (this.valAx.minorTickMark) {
			case c_oAscTickMark.TICK_MARK_CROSS: {
				widthMinorLine = 3;
				crossMinorStep = 3;
				break;
			}
			case c_oAscTickMark.TICK_MARK_IN: {
				widthMinorLine = 3;
				break;
			}
			case c_oAscTickMark.TICK_MARK_NONE: {
				widthMinorLine = 0;
				break;
			}
			case c_oAscTickMark.TICK_MARK_OUT: {
				widthMinorLine = -3;
				break;
			}
		}

		//TODO необходимо при смене ориентации оси категорий менять axPos!!!
		//var orientation = this.cChartSpace && this.cChartSpace.chart.plotArea.catAx ? this.cChartSpace.chart.plotArea.catAx.scaling.orientation : ORIENTATION_MIN_MAX;
		var minorLinesCount = 5;
		var axPos = this.valAx.axPos;
		if (axPos !== window['AscFormat'].AX_POS_L && axPos !== window['AscFormat'].AX_POS_T) {
			widthMinorLine = -widthMinorLine;
			widthLine = -widthLine;
			crossMajorStep = -crossMajorStep;
			crossMinorStep = -crossMinorStep;
		}

		if (!(widthLine === 0 && widthMinorLine === 0)) {
			var points, minorStep, posY, posX;
			if (axPos === window['AscFormat'].AX_POS_T || axPos === window['AscFormat'].AX_POS_B) {
				points = this.valAx.xPoints;
				if(!points) {
					return;
				}

				var stepX = points[1] ? Math.abs(points[1].pos - points[0].pos) : Math.abs(points[1].pos - this.chartProp.chartGutter._bottom / this.chartProp.pxToMM);
				minorStep = stepX / minorLinesCount;
				posY = this.valAx.posY;

				var posMinorX;
				for (var i = 0; i < points.length; i++) {
					posX = points[i].pos;
					if (!this.paths.tickMarks) {
						this.paths.tickMarks = [];
					}
					this.paths.tickMarks[i] = this._calculateLine(posX, posY - crossMajorStep / this.chartProp.pxToMM, posX, posY + widthLine / this.chartProp.pxToMM);

					//промежуточные линии
					if (widthMinorLine !== 0) {
						for (var n = 0; n < minorLinesCount; n++) {
							posMinorX = posX + n * minorStep;
							if (!this.paths.minorTickMarks) {
								this.paths.minorTickMarks = [];
							}
							if (!this.paths.minorTickMarks[i]) {
								this.paths.minorTickMarks[i] = [];
							}

							this.paths.minorTickMarks[i][n] = this._calculateLine(posMinorX, posY - crossMinorStep / this.chartProp.pxToMM, posMinorX, posY + widthMinorLine / this.chartProp.pxToMM);
						}
					}
				}
			} else {
				points = this.valAx.yPoints;
				if(!points) {
					return;
				}

				var stepY = points[1] ? Math.abs(points[1].pos - points[0].pos) : Math.abs(points[0].pos - this.chartProp.chartGutter._bottom / this.chartProp.pxToMM);
				minorStep = stepY / minorLinesCount;
				posX = this.valAx.posX;

				var posMinorY;
				for (var i = 0; i < points.length; i++) {
					//основные линии
					posY = points[i].pos;

					if (!this.paths.tickMarks) {
						this.paths.tickMarks = [];
					}
					this.paths.tickMarks[i] = this._calculateLine(posX - crossMajorStep / this.chartProp.pxToMM, posY, posX + widthLine / this.chartProp.pxToMM, posY);

					//промежуточные линии
					if (widthMinorLine !== 0) {
						for (var n = 0; n < minorLinesCount; n++) {
							posMinorY = posY - n * minorStep;
							if (!this.paths.minorTickMarks) {
								this.paths.minorTickMarks = [];
							}
							if (!this.paths.minorTickMarks[i]) {
								this.paths.minorTickMarks[i] = [];
							}

							this.paths.minorTickMarks[i][n] = this._calculateLine(posX - crossMinorStep / this.chartProp.pxToMM, posMinorY, posX + widthMinorLine / this.chartProp.pxToMM, posMinorY);
						}
					}
				}
			}
		}
	},

	_calculateLine: function (x, y, x1, y1) {

		if (this.cChartDrawer.nDimensionCount === 3) {
			var z = this.cChartDrawer.processor3D.calculateZPositionValAxis();

			var convertResult = this.cChartDrawer._convertAndTurnPoint(x * this.chartProp.pxToMM, y * this.chartProp.pxToMM, z);
			x = convertResult.x / this.chartProp.pxToMM;
			y = convertResult.y / this.chartProp.pxToMM;
			convertResult = this.cChartDrawer._convertAndTurnPoint(x1 * this.chartProp.pxToMM, y1 * this.chartProp.pxToMM, z);
			x1 = convertResult.x / this.chartProp.pxToMM;
			y1 = convertResult.y / this.chartProp.pxToMM;
		}

		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;

		path.moveTo(x * pathW, y * pathH);
		path.lnTo(x1 * pathW, y1 * pathH);

		return pathId;
	},

	_drawGridLines: function () {
		var pen;
		var path;

		if (!this.paths.gridLines) {
			return;
		}

		for (var i = 0; i < this.paths.gridLines.length; i++) {
			//промежуточные линии
			if (this.paths.minorGridLines && this.paths.minorGridLines[i]) {
				for (var n = 0; n < this.paths.minorGridLines[i].length; n++) {
					path = this.paths.minorGridLines[i][n];
					pen = this.valAx.compiledMinorGridLines;
					this.cChartDrawer.drawPath(path, pen);
				}
			}

			pen = this.valAx.compiledMajorGridLines;

			path = this.paths.gridLines[i];
			this.cChartDrawer.drawPath(path, pen);
		}
	},

	_drawAxis: function () {
		var pen;
		var path;

		pen = this.valAx.compiledLn;
		path = this.paths.axisLine;
		this.cChartDrawer.drawPath(path, pen);
	},

	_drawTickMark: function () {
		var pen, path;
		if (!this.paths.tickMarks) {
			return;
		}

		for (var i = 0; i < this.paths.tickMarks.length; i++) {
			pen = this.valAx.compiledTickMarkLn;

			path = this.paths.tickMarks[i];
			this.cChartDrawer.drawPath(path, pen);

			//промежуточные линии
			if (i !== (this.paths.tickMarks.length - 1) && this.paths.minorTickMarks) {
				for (var n = 0; n < this.paths.minorTickMarks[i].length; n++) {
					path = this.paths.minorTickMarks[i][n];
					this.cChartDrawer.drawPath(path, pen);
				}
			}
		}
	}
};

/** @constructor */
function serAxisChart() {
	this.chartProp = null;
	this.cChartSpace = null;
	this.cChartDrawer = null;
	this.serAx = null;

	this.paths = {};
}

serAxisChart.prototype = {
	constructor: serAxisChart,

	draw: function (chartsDrawer, serAx) {
		this.chartProp = chartsDrawer.calcProp;
		this.cChartSpace = chartsDrawer.cChartSpace;
		this.cChartDrawer = chartsDrawer;
		if (serAx) {
			this.serAx = serAx;
		}

		this._drawAxis();
		this._drawTickMark();
	},

	recalculate: function (chartsDrawer, serAx) {
		this.chartProp = chartsDrawer.calcProp;
		this.cChartSpace = chartsDrawer.cChartSpace;
		this.cChartDrawer = chartsDrawer;
		this.serAx = serAx;

		this.paths = {};
		if (this.cChartSpace.chart.plotArea.serAx && this.cChartSpace.chart.plotArea.serAx.bDelete !== true) {
			this._calculateAxis();
			this._calculateTickMark();
		}
	},

	_calculateAxis: function () {
		//TODO заменить nullPositionOX!!!
		var nullPositionOx = this.chartProp.nullPositionOX;

		var perspectiveDepth = this.cChartDrawer.processor3D.depthPerspective;

		//var z = this.cChartDrawer.processor3D.calculateZPositionValAxis();

		var x = this.chartProp.widthCanvas - this.chartProp.chartGutter._right;
		var y = nullPositionOx;
		var convertResult = this.cChartDrawer._convertAndTurnPoint(x, y, 0);
		x = convertResult.x / this.chartProp.pxToMM;
		y = convertResult.y / this.chartProp.pxToMM;

		var x1 = this.chartProp.widthCanvas - this.chartProp.chartGutter._right;
		var y1 = nullPositionOx;
		convertResult = this.cChartDrawer._convertAndTurnPoint(x1, y1, perspectiveDepth);
		x1 = convertResult.x / this.chartProp.pxToMM;
		y1 = convertResult.y / this.chartProp.pxToMM;


		this.paths.axisLine = this._calculateLine(x, y, x1, y1);
	},

	_calculateTickMark: function () {
		//TODO заменить nullPositionOX!!!
		var perspectiveDepth = this.cChartDrawer.processor3D.depthPerspective;
		var tickmarksProps = this._getTickmarksProps();
		var widthLine = tickmarksProps.widthLine;

		if (widthLine !== 0) {
			var stepY = perspectiveDepth / this.chartProp.seriesCount;
			var startX = this.chartProp.widthCanvas - this.chartProp.chartGutter._right;
			var startY = this.chartProp.nullPositionOX;

			for (var i = 0; i <= this.chartProp.seriesCount; i++) {
				//основные линии
				if (!this.paths.tickMarks) {
					this.paths.tickMarks = [];
				}

				var convertResult = this.cChartDrawer._convertAndTurnPoint(startX, startY, i * stepY);
				var x = convertResult.x / this.chartProp.pxToMM;
				var y = convertResult.y / this.chartProp.pxToMM;

				this.paths.tickMarks[i] = this._calculateLine(x, y, x + widthLine / this.chartProp.pxToMM, y);
			}
		}
	},

	_getTickmarksProps: function () {
		var widthLine = 0;
		var crossMajorStep = 0;

		switch (this.serAx.majorTickMark) {
			case c_oAscTickMark.TICK_MARK_CROSS: {
				widthLine = -5;
				crossMajorStep = 5;
				break;
			}
			case c_oAscTickMark.TICK_MARK_IN: {
				widthLine = -5;
				break;
			}
			case c_oAscTickMark.TICK_MARK_NONE: {
				widthLine = 0;
				break;
			}
			case c_oAscTickMark.TICK_MARK_OUT: {
				widthLine = 5;
				break;
			}
		}

		//var orientation = this.cChartSpace && this.cChartSpace.chart.plotArea.catAx ? this.cChartSpace.chart.plotArea.catAx.scaling.orientation : ORIENTATION_MIN_MAX;
		if (this.serAx.axPos === window['AscFormat'].AX_POS_B) {
			widthLine = -widthLine;
			crossMajorStep = -crossMajorStep;
		}

		return {widthLine: widthLine, crossMajorStep: crossMajorStep};
	},

	_calculateLine: function (x, y, x1, y1) {
		var pathId = this.cChartSpace.AllocPath();
		var path = this.cChartSpace.GetPath(pathId);

		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;


		path.moveTo(x * pathW, y * pathH);
		path.lnTo(x1 * pathW, y1 * pathH);

		return pathId;
	},

	_drawAxis: function () {
		//TODO добавлять compiledLn, как в случае с другими осями
		var pen = this.serAx ? this.serAx.compiledLn : null;
		var path = this.paths.axisLine;

		this.cChartDrawer.drawPath(path, pen);
	},

	_drawTickMark: function () {
		var pen, path;
		if (!this.paths.tickMarks) {
			return;
		}

		for (var i = 0; i < this.paths.tickMarks.length; i++) {
			pen = this.serAx ? this.serAx.compiledTickMarkLn : null;

			path = this.paths.tickMarks[i];
			this.cChartDrawer.drawPath(path, pen);
		}
	}
};

	/** @constructor */
function floor3DChart()
{
	this.chartProp = null;
	this.cChartSpace = null;
	this.cChartDrawer = null;
	
	this.paths = {};
}

floor3DChart.prototype =
{
    constructor: floor3DChart,
	
	draw : function(chartsDrawer)
    {
		this.chartProp = chartsDrawer.calcProp;
		this.cChartSpace = chartsDrawer.cChartSpace;
		this.cChartDrawer = chartsDrawer;
		
		this._draw();
	},
	
	recalculate: function(chartsDrawer)
	{
		this.chartProp = chartsDrawer.calcProp;
		this.cChartSpace = chartsDrawer.cChartSpace;
		this.cChartDrawer = chartsDrawer;
		
		this.paths = {};
		this._calculate();
	},
	
	_calculate : function()
	{
		var nullPositionOy = this.chartProp.heightCanvas - this.chartProp.chartGutter._bottom;	
		var maxPositionOy = this.chartProp.chartGutter._top;
		var yPoints = this.cChartSpace.chart.plotArea.valAx ? this.cChartSpace.chart.plotArea.valAx.yPoints : null;
		if(yPoints && yPoints[0] && yPoints[yPoints.length - 1])
		{
			nullPositionOy = yPoints[0].pos > yPoints[yPoints.length - 1].pos ? yPoints[0].pos * this.chartProp.pxToMM : yPoints[yPoints.length - 1].pos * this.chartProp.pxToMM;
			maxPositionOy = yPoints[0].pos < yPoints[yPoints.length - 1].pos ? yPoints[0].pos * this.chartProp.pxToMM : yPoints[yPoints.length - 1].pos * this.chartProp.pxToMM;
		}
		
		var pxToMm = this.chartProp.pxToMM;
		var poisition = this.cChartDrawer.processor3D.calculateFloorPosition();
		var perspectiveDepth = this.cChartDrawer.processor3D.depthPerspective;
		var point1, point2, point3, point4;
		
		switch(poisition)
		{
			case AscCommon.c_oChartFloorPosition.Left:
			{
				point1 = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, nullPositionOy, 0);
				point2 = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, maxPositionOy, 0);
				point3 = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, maxPositionOy, perspectiveDepth);
				point4 = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, nullPositionOy, perspectiveDepth);

				break;
			}
			case AscCommon.c_oChartFloorPosition.Right:
			{
				point1 = this.cChartDrawer._convertAndTurnPoint(this.chartProp.widthCanvas - this.chartProp.chartGutter._right, nullPositionOy, 0);
				point2 = this.cChartDrawer._convertAndTurnPoint(this.chartProp.widthCanvas - this.chartProp.chartGutter._right, maxPositionOy, 0);
				point3 = this.cChartDrawer._convertAndTurnPoint(this.chartProp.widthCanvas - this.chartProp.chartGutter._right, maxPositionOy, perspectiveDepth);
				point4 = this.cChartDrawer._convertAndTurnPoint(this.chartProp.widthCanvas - this.chartProp.chartGutter._right, nullPositionOy, perspectiveDepth);
				
				break;
			}
			case AscCommon.c_oChartFloorPosition.Bottom:
			{
				point1 = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, nullPositionOy, 0);
				point2 = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, nullPositionOy, perspectiveDepth);
				point3 = this.cChartDrawer._convertAndTurnPoint(this.chartProp.widthCanvas - this.chartProp.chartGutter._right, nullPositionOy, perspectiveDepth);
				point4 = this.cChartDrawer._convertAndTurnPoint(this.chartProp.widthCanvas - this.chartProp.chartGutter._right, nullPositionOy, 0);
			
				break;
			}
			case AscCommon.c_oChartFloorPosition.Top:
			{
				point1 = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, maxPositionOy, 0);
				point2 = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, maxPositionOy, perspectiveDepth);
				point3 = this.cChartDrawer._convertAndTurnPoint(this.chartProp.widthCanvas - this.chartProp.chartGutter._right, maxPositionOy, perspectiveDepth);
				point4 = this.cChartDrawer._convertAndTurnPoint(this.chartProp.widthCanvas - this.chartProp.chartGutter._right, maxPositionOy, 0);
				
				break;
			}
		}
		
		if(point1)
		{
			this.paths.chartFloor = this.cChartDrawer.calculatePolygon([{x: point1.x / pxToMm, y: point1.y / pxToMm}, {x: point2.x / pxToMm, y: point2.y / pxToMm}, {x: point3.x / pxToMm, y: point3.y / pxToMm}, {x: point4.x / pxToMm, y: point4.y / pxToMm}]);
		}
	},
		
	_draw: function()
	{
		//TODO цвет заливки неправильно выставляется при чтении. поэтому использую пока цвет сетки
		var brush = this.cChartSpace.chart.floor ? this.cChartSpace.chart.floor.brush : null;
		var pen = this.cChartSpace.chart.floor ? this.cChartSpace.chart.floor.pen : null;
		var path = this.paths.chartFloor;
		
		this.cChartDrawer.drawPath(path, pen, brush);
	}

};

	/** @constructor */
function sideWall3DChart()
{
	this.chartProp = null;
	this.cChartSpace = null;
	this.cChartDrawer = null;
	
	this.paths = {};
}

sideWall3DChart.prototype =
{
	constructor: sideWall3DChart,
	
	draw : function(chartsDrawer)
    {
		this.chartProp = chartsDrawer.calcProp;
		this.cChartSpace = chartsDrawer.cChartSpace;
		this.cChartDrawer = chartsDrawer;
		
		this._draw();
	},
	
	recalculate: function(chartsDrawer)
	{
		this.chartProp = chartsDrawer.calcProp;
		this.cChartSpace = chartsDrawer.cChartSpace;
		this.cChartDrawer = chartsDrawer;
		
		this.paths = {};
		this._calculate();
	},
	
	_calculate : function()
	{
		var nullPositionOy = this.chartProp.heightCanvas - this.chartProp.chartGutter._bottom;	
		var maxPositionOy = this.chartProp.chartGutter._top;
		var yPoints = this.cChartSpace.chart.plotArea.valAx ? this.cChartSpace.chart.plotArea.valAx.yPoints : null;
		if(yPoints && yPoints[0] && yPoints[yPoints.length - 1])
		{
			nullPositionOy = yPoints[0].pos > yPoints[yPoints.length - 1].pos ? yPoints[0].pos * this.chartProp.pxToMM : yPoints[yPoints.length - 1].pos * this.chartProp.pxToMM;
			maxPositionOy = yPoints[0].pos < yPoints[yPoints.length - 1].pos ? yPoints[0].pos * this.chartProp.pxToMM : yPoints[yPoints.length - 1].pos * this.chartProp.pxToMM;
		}
		
		var perspectiveDepth = this.cChartDrawer.processor3D.depthPerspective;
		var convertResult, x1n, y1n, x2n, y2n, x3n, y3n, x4n, y4n;
		if(this.chartProp.type === c_oChartTypes.HBar)
		{
			convertResult = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, nullPositionOy, 0);
			x1n = convertResult.x / this.chartProp.pxToMM;
			y1n = convertResult.y / this.chartProp.pxToMM;
			convertResult = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, nullPositionOy, perspectiveDepth);
			x2n = convertResult.x / this.chartProp.pxToMM;
			y2n = convertResult.y / this.chartProp.pxToMM;
			convertResult = this.cChartDrawer._convertAndTurnPoint(this.chartProp.widthCanvas - this.chartProp.chartGutter._right, nullPositionOy, perspectiveDepth);
			x3n = convertResult.x / this.chartProp.pxToMM;
			y3n = convertResult.y / this.chartProp.pxToMM;
			convertResult = this.cChartDrawer._convertAndTurnPoint(this.chartProp.widthCanvas - this.chartProp.chartGutter._right, nullPositionOy, 0);
			x4n = convertResult.x / this.chartProp.pxToMM;
			y4n = convertResult.y / this.chartProp.pxToMM;
		}
		else
		{
			convertResult = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, nullPositionOy, 0);
			x1n = convertResult.x / this.chartProp.pxToMM;
			y1n = convertResult.y / this.chartProp.pxToMM;
			convertResult = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, this.chartProp.chartGutter._top, 0);
			x2n = convertResult.x / this.chartProp.pxToMM;
			y2n = convertResult.y / this.chartProp.pxToMM;
			convertResult = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, this.chartProp.chartGutter._top, perspectiveDepth);
			x3n = convertResult.x / this.chartProp.pxToMM;
			y3n = convertResult.y / this.chartProp.pxToMM;
			convertResult = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, nullPositionOy, perspectiveDepth);
			x4n = convertResult.x / this.chartProp.pxToMM;
			y4n = convertResult.y / this.chartProp.pxToMM;
		}
		
		this.paths = this.cChartDrawer.calculatePolygon([{x: x1n, y: y1n}, {x: x2n, y: y2n}, {x: x3n, y: y3n}, {x: x4n, y: y4n}]);
	},
		
	_draw: function()
	{
		//TODO цвет заливки неправильно выставляется при чтении. поэтому использую пока цвет сетки
		var brush = this.cChartSpace.chart.sideWall ? this.cChartSpace.chart.sideWall.brush : null;
		var pen = this.cChartSpace.chart.sideWall ? this.cChartSpace.chart.sideWall.pen : null;
		var path = this.paths;
		
		this.cChartDrawer.drawPath(path, pen, brush);
	}
};

	/** @constructor */
function backWall3DChart()
{
	this.chartProp = null;
	this.cChartSpace = null;
	this.cChartDrawer = null;
	
	this.paths = {};
}

backWall3DChart.prototype =
{
	constructor: backWall3DChart,
	
	draw : function(chartsDrawer)
    {
		this.chartProp = chartsDrawer.calcProp;
		this.cChartSpace = chartsDrawer.cChartSpace;
		this.cChartDrawer = chartsDrawer;
		
		this._draw();
	},
	
	recalculate: function(chartsDrawer)
	{
		this.chartProp = chartsDrawer.calcProp;
		this.cChartSpace = chartsDrawer.cChartSpace;
		this.cChartDrawer = chartsDrawer;
		
		this.paths = {};
		this._calculate();
	},
	
	_calculate : function()
	{
		var nullPositionOy = this.chartProp.heightCanvas - this.chartProp.chartGutter._bottom;	
		var maxPositionOy = this.chartProp.chartGutter._top;
		var yPoints = this.cChartSpace.chart.plotArea.valAx ? this.cChartSpace.chart.plotArea.valAx.yPoints : null;
		if(yPoints && yPoints[0] && yPoints[yPoints.length - 1])
		{
			nullPositionOy = yPoints[0].pos > yPoints[yPoints.length - 1].pos ? yPoints[0].pos * this.chartProp.pxToMM : yPoints[yPoints.length - 1].pos * this.chartProp.pxToMM;
			maxPositionOy = yPoints[0].pos < yPoints[yPoints.length - 1].pos ? yPoints[0].pos * this.chartProp.pxToMM : yPoints[yPoints.length - 1].pos * this.chartProp.pxToMM;
		}
		
		var perspectiveDepth = this.cChartDrawer.processor3D.depthPerspective;
		var convertResult, x1n, y1n, x2n, y2n, x3n, y3n, x4n, y4n;
		if(this.chartProp.type === c_oChartTypes.HBar)
		{
			convertResult = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, nullPositionOy, perspectiveDepth);
			x1n = convertResult.x / this.chartProp.pxToMM;
			y1n = convertResult.y / this.chartProp.pxToMM;
			convertResult = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, this.chartProp.chartGutter._top, perspectiveDepth);
			x2n = convertResult.x / this.chartProp.pxToMM;
			y2n = convertResult.y / this.chartProp.pxToMM;
			convertResult = this.cChartDrawer._convertAndTurnPoint(this.chartProp.widthCanvas - this.chartProp.chartGutter._right, this.chartProp.chartGutter._top, perspectiveDepth);
			x3n = convertResult.x / this.chartProp.pxToMM;
			y3n = convertResult.y / this.chartProp.pxToMM;
			convertResult = this.cChartDrawer._convertAndTurnPoint(this.chartProp.widthCanvas - this.chartProp.chartGutter._right, nullPositionOy, perspectiveDepth);
			x4n = convertResult.x / this.chartProp.pxToMM;
			y4n = convertResult.y / this.chartProp.pxToMM;
		}
		else
		{
			convertResult = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, nullPositionOy, perspectiveDepth);
			x1n = convertResult.x / this.chartProp.pxToMM;
			y1n = convertResult.y / this.chartProp.pxToMM;
			convertResult = this.cChartDrawer._convertAndTurnPoint(this.chartProp.chartGutter._left, this.chartProp.chartGutter._top, perspectiveDepth);
			x2n = convertResult.x / this.chartProp.pxToMM;
			y2n = convertResult.y / this.chartProp.pxToMM;
			convertResult = this.cChartDrawer._convertAndTurnPoint(this.chartProp.widthCanvas - this.chartProp.chartGutter._right, this.chartProp.chartGutter._top, perspectiveDepth);
			x3n = convertResult.x / this.chartProp.pxToMM;
			y3n = convertResult.y / this.chartProp.pxToMM;
			convertResult = this.cChartDrawer._convertAndTurnPoint(this.chartProp.widthCanvas - this.chartProp.chartGutter._right, nullPositionOy, perspectiveDepth);
			x4n = convertResult.x / this.chartProp.pxToMM;
			y4n = convertResult.y / this.chartProp.pxToMM;
		}
		
		this.paths = this.cChartDrawer.calculatePolygon([{x: x1n, y: y1n}, {x: x2n, y: y2n}, {x: x3n, y: y3n}, {x: x4n, y: y4n}]);
	},
		
	_draw: function()
	{
		//TODO цвет заливки неправильно выставляется при чтении. поэтому использую пока цвет сетки
		var brush = this.cChartSpace.chart.backWall ? this.cChartSpace.chart.backWall.brush : null;
		var pen = this.cChartSpace.chart.backWall ? this.cChartSpace.chart.backWall.pen : null;
		var path = this.paths;
		
		this.cChartDrawer.drawPath(path, pen, brush);
	}
};


	/** @constructor */
function areaChart()
{
	this.chartProp = null;
	this.cChartSpace = null;
	this.cChartDrawer = null;
	
	this.paths = null;
}

areaChart.prototype =
{
    constructor: areaChart,
	
	draw : function(chartsDrawer)
    {
		this.chartProp = chartsDrawer.calcProp;
		this.cChartSpace = chartsDrawer.cChartSpace;
		this.cChartDrawer = chartsDrawer;
		
		this._drawArea();
	},
	
	recalculate: function(chartsDrawer)
	{
		this.chartProp = chartsDrawer.calcProp;
		this.cChartSpace = chartsDrawer.cChartSpace;
		this.cChartDrawer = chartsDrawer;
		
		this.paths = null;
		this._calculateArea();
	},
	
	_calculateArea: function()
	{
        var pathId = this.cChartSpace.AllocPath();
        var path  = this.cChartSpace.GetPath(pathId);
		
		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;

		var pxToMm = this.chartProp.pxToMM;
		
		path.moveTo(0, 0);
		path.lnTo(0 / pxToMm * pathW, this.chartProp.heightCanvas / pxToMm * pathH);
		path.lnTo(this.chartProp.widthCanvas / pxToMm * pathW, this.chartProp.heightCanvas / pxToMm * pathH);
		path.lnTo(this.chartProp.widthCanvas / pxToMm * pathW, 0 / pxToMm * pathH);
		path.lnTo(0, 0);

		this.paths = pathId;
	},
	
	_drawArea: function()
	{
		var pen = this.cChartSpace.pen;
		var brush = this.cChartSpace.brush;
		this.cChartDrawer.drawPath(this.paths, pen, brush);
	}
};

	/** @constructor */
function plotAreaChart()
{
	this.chartProp = null;
	this.cChartSpace = null;
	this.cChartDrawer = null;
	
	this.paths = null;
}

plotAreaChart.prototype =
{
    constructor: plotAreaChart,
	
	draw: function(chartsDrawer, ignorePen, ignoreBrush)
	{
		this.chartProp = chartsDrawer.calcProp;
		this.cChartSpace = chartsDrawer.cChartSpace;
		this.cChartDrawer = chartsDrawer;
		
		this._drawArea(ignorePen, ignoreBrush);
	},
	
	recalculate: function(chartsDrawer)
	{
		this.chartProp = chartsDrawer.calcProp;
		this.cChartSpace = chartsDrawer.cChartSpace;
		this.cChartDrawer = chartsDrawer;
		
		this.paths = null;
		
		if(this.cChartDrawer.nDimensionCount === 3 && this.chartProp.type !== c_oChartTypes.Pie)
			this._calculateArea3D();
		else
			this._calculateArea();
	},
	
	_calculateArea: function()
	{
        var pathId = this.cChartSpace.AllocPath();
        var path  = this.cChartSpace.GetPath(pathId);
		
		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;

		//смещаем на px все точки, посольку рисуем прямоугольную область
		var px = 1/this.chartProp.pxToMM;
		var plotAreaPoints = this.cChartDrawer.getPlotAreaPoints();
		var left = plotAreaPoints.left - px;
		var right = plotAreaPoints.right - px;
		var top = plotAreaPoints.top - px;
		var bottom = plotAreaPoints.bottom - px;
		
		path.moveTo(left * pathW, bottom * pathH);
		path.lnTo(right * pathW, bottom * pathH);
		path.lnTo(right * pathW, top * pathH);
		path.lnTo(left * pathW, top * pathH);
		path.lnTo(left * pathW, bottom * pathH);

		this.paths = pathId;
	},
	
	_calculateArea3D: function()
	{
        var pathId = this.cChartSpace.AllocPath();
        var path  = this.cChartSpace.GetPath(pathId);
		
		var pathH = this.chartProp.pathH;
		var pathW = this.chartProp.pathW;
		
		var pxToMm = this.chartProp.pxToMM;

		var plotAreaPoints = this.cChartDrawer.getPlotAreaPoints();
		var left = plotAreaPoints.left * pxToMm - 1;
		var right = plotAreaPoints.right * pxToMm - 1;
		var top = plotAreaPoints.top * pxToMm - 1;
		var bottom = plotAreaPoints.bottom * pxToMm - 1;

		var perspectiveDepth = this.cChartDrawer.processor3D.depthPerspective;
		
		var convertResult = this.cChartDrawer._convertAndTurnPoint(left, bottom, perspectiveDepth);
		var x1n = convertResult.x;
		var y1n = convertResult.y;
		convertResult = this.cChartDrawer._convertAndTurnPoint(right, bottom, perspectiveDepth);
		var x2n = convertResult.x;
		var y2n = convertResult.y;
		convertResult = this.cChartDrawer._convertAndTurnPoint(right, top, perspectiveDepth);
		var x3n = convertResult.x;
		var y3n = convertResult.y;
		convertResult = this.cChartDrawer._convertAndTurnPoint(left, top, perspectiveDepth);
		var x4n = convertResult.x;
		var y4n = convertResult.y;
		convertResult = this.cChartDrawer._convertAndTurnPoint(left, bottom, perspectiveDepth);
		var x5n = convertResult.x;
		var y5n = convertResult.y;

		
		path.moveTo(x1n / pxToMm * pathW, y1n / pxToMm * pathH);
		path.lnTo(x2n  / pxToMm * pathW, y2n / pxToMm * pathH);
		path.lnTo(x3n / pxToMm * pathW, y3n / pxToMm * pathH);
		path.lnTo(x4n / pxToMm * pathW, y4n / pxToMm * pathH);
		path.moveTo(x5n / pxToMm * pathW, y5n / pxToMm * pathH);

		this.paths = pathId;
	},
	
	_drawArea: function(ignorePen, ignoreBrush)
	{
		var pen = ignorePen ? null : this.cChartSpace.chart.plotArea.pen;
		var brush = ignoreBrush ? null : this.cChartSpace.chart.plotArea.brush;
		this.cChartDrawer.drawPath(this.paths, pen, brush);
	}
};

	/** @constructor */
function CGeometry2()
{
    this.pathLst = [];
	this.isLine = false;
	this.gdLst = [];
}

CGeometry2.prototype =
{
    constructor: CGeometry2,
	
	canFill: function()
    {
        if(this.preset === "line")
            return false;
        for(var i = 0; i < this.pathLst.length; ++i)
        {
            if(this.pathLst[i].fill !== "none")
                return true;
        }
        return  false;
    },

    AddPath: function(path)
    {
        this.pathLst.push(path);
    },
	
    AddRect: function(l, t, r, b)
    {
        this.rectS = {};
        this.rectS.l = l;
        this.rectS.t = t;
        this.rectS.r = r;
        this.rectS.b = b;
    },

    draw: function(shape_drawer)
    {
        for (var i=0, n=this.pathLst.length; i<n;++i)
            this.pathLst[i].drawSmart(shape_drawer);
    },
	
	check_bounds: function(checker)
    {

        for(var i=0, n=this.pathLst.length; i<n;++i)

            this.pathLst[i].check_bounds(checker);

    }
};

	/** @constructor */
function CColorObj(pen, brush, geometry)
{
    this.pen = pen;
	this.brush = brush;
	this.geometry = geometry;
}

CColorObj.prototype =
{
	constructor: CColorObj,
	
	check_bounds: function (checker) {
		if (this.geometry) {
			this.geometry.check_bounds(checker);
		}
	}
};

	//----------------------------------------------------------export----------------------------------------------------
	window['AscFormat'] = window['AscFormat'] || {};
	window['AscFormat'].CChartsDrawer = CChartsDrawer;
	window["AscFormat"].c_oChartTypes = c_oChartTypes;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

function XYAdjustmentTrack(originalShape, adjIndex, bTextWarp)
{
    AscFormat.ExecuteNoHistory(function(){
        this.originalShape = originalShape;
        this.bIsTracked = false;

        var oPen, oBrush;
        if(bTextWarp !== true)
        {
            if(originalShape.spPr && originalShape.spPr.geometry){
                this.geometry = originalShape.spPr.geometry.createDuplicate();
            }
            else if(originalShape.calcGeometry){
                this.geometry = originalShape.calcGeometry.createDuplicate();
            }
            this.shapeWidth = originalShape.extX;
            this.shapeHeight = originalShape.extY;
            this.transform = originalShape.transform.CreateDublicate();
            this.invertTransform = originalShape.invertTransform;
            oPen = originalShape.pen;
            oBrush = originalShape.brush;
        }
        else
        {
            this.geometry = originalShape.recalcInfo.warpGeometry.createDuplicate();
            this.shapeWidth = originalShape.recalcInfo.warpGeometry.gdLst["w"];
            this.shapeHeight = originalShape.recalcInfo.warpGeometry.gdLst["h"];
            this.transform = originalShape.transformTextWordArt;
            this.invertTransform = originalShape.invertTransformTextWordArt;
            oPen = null;
            oBrush = null;
        }
        this.bTextWarp = bTextWarp === true;
        this.geometry.Recalculate(this.shapeWidth, this.shapeHeight);
        this.adjastment = this.geometry.ahXYLst[adjIndex];

        this.xFlag = false;
        this.yFlag = false;

        this.refX = null;
        this.refY = null;

        this.originalObject= originalShape;

        if(this.adjastment !== null && typeof this.adjastment === "object")
        {
            var _ref_x = this.adjastment.gdRefX;
            var  _gd_lst = this.geometry.gdLst;
            if(typeof _ref_x === "string" && typeof _gd_lst[_ref_x] === "number"
                && typeof this.adjastment.minX === "number" && typeof this.adjastment.maxX === "number")
            {
                _gd_lst[_ref_x] = this.adjastment.minX;
                this.geometry.Recalculate(this.shapeWidth, this.shapeHeight);

                this.minRealX = this.adjastment.posX;

                _gd_lst[_ref_x] = this.adjastment.maxX;
                this.geometry.Recalculate(this.shapeWidth, this.shapeHeight);

                this.maxRealX = this.adjastment.posX;
                this.maximalRealX = Math.max(this.maxRealX, this.minRealX);
                this.minimalRealX = Math.min(this.maxRealX, this.minRealX);

                this.minimalRealativeX = Math.min(this.adjastment.minX, this.adjastment.maxX);
                this.maximalRealativeX = Math.max(this.adjastment.minX, this.adjastment.maxX);

                if(this.maximalRealX - this.minimalRealX > 0)
                {
                    this.coeffX = (this.adjastment.maxX - this.adjastment.minX)/(this.maxRealX - this.minRealX);
                    this.xFlag = true;
                }
            }

            var _ref_y = this.adjastment.gdRefY;
            if(typeof _ref_y === "string" && typeof _gd_lst[_ref_y] === "number"
                && typeof this.adjastment.minY === "number" && typeof this.adjastment.maxY === "number")
            {
                _gd_lst[_ref_y] = this.adjastment.minY;
                this.geometry.Recalculate(this.shapeWidth, this.shapeHeight);

                this.minRealY = this.adjastment.posY;

                _gd_lst[_ref_y] = this.adjastment.maxY;
                this.geometry.Recalculate(this.shapeWidth, this.shapeHeight);

                this.maxRealY = this.adjastment.posY;


                this.maximalRealY = Math.max(this.maxRealY, this.minRealY);
                this.minimalRealY = Math.min(this.maxRealY, this.minRealY);

                this.minimalRealativeY = Math.min(this.adjastment.minY, this.adjastment.maxY);
                this.maximalRealativeY = Math.max(this.adjastment.minY, this.adjastment.maxY);

                if(this.maximalRealY - this.minimalRealY > 0)
                {
                    this.coeffY = (this.adjastment.maxY - this.adjastment.minY)/(this.maxRealY - this.minRealY);
                    this.yFlag = true;
                }
            }
            if(this.xFlag)
            {
                this.refX = _ref_x;
            }
            if(this.yFlag)
            {
                this.refY = _ref_y;
            }
        }
        this.overlayObject = new AscFormat.OverlayObject(this.geometry, this.shapeWidth, this.shapeHeight, oBrush, oPen, this.transform);


    }, this, []);
}

XYAdjustmentTrack.prototype.getBounds = function()
{
    var bounds_checker = new  AscFormat.CSlideBoundsChecker();
    bounds_checker.init(Page_Width, Page_Height, Page_Width, Page_Height);
    this.draw(bounds_checker);
    var tr = this.originalShape.transform;
    var arr_p_x = [];
    var arr_p_y = [];
    arr_p_x.push(tr.TransformPointX(0,0));
    arr_p_y.push(tr.TransformPointY(0,0));
    arr_p_x.push(tr.TransformPointX(this.originalShape.extX,0));
    arr_p_y.push(tr.TransformPointY(this.originalShape.extX,0));
    arr_p_x.push(tr.TransformPointX(this.originalShape.extX,this.originalShape.extY));
    arr_p_y.push(tr.TransformPointY(this.originalShape.extX,this.originalShape.extY));
    arr_p_x.push(tr.TransformPointX(0,this.originalShape.extY));
    arr_p_y.push(tr.TransformPointY(0,this.originalShape.extY));

    arr_p_x.push(bounds_checker.Bounds.min_x);
    arr_p_x.push(bounds_checker.Bounds.max_x);
    arr_p_y.push(bounds_checker.Bounds.min_y);
    arr_p_y.push(bounds_checker.Bounds.max_y);

    bounds_checker.Bounds.min_x = Math.min.apply(Math, arr_p_x);
    bounds_checker.Bounds.max_x = Math.max.apply(Math, arr_p_x);
    bounds_checker.Bounds.min_y = Math.min.apply(Math, arr_p_y);
    bounds_checker.Bounds.max_y = Math.max.apply(Math, arr_p_y);

    bounds_checker.Bounds.posX = this.originalShape.x;
    bounds_checker.Bounds.posY = this.originalShape.y;
    bounds_checker.Bounds.extX = this.originalShape.extX;
    bounds_checker.Bounds.extY = this.originalShape.extY;

    return bounds_checker.Bounds;
};

XYAdjustmentTrack.prototype.draw = function(overlay)
{
    if(AscFormat.isRealNumber(this.originalShape.selectStartPage) && overlay.SetCurrentPage)
    {
        overlay.SetCurrentPage(this.originalShape.selectStartPage);
    }
    this.overlayObject.draw(overlay);
};

XYAdjustmentTrack.prototype.track = function(posX, posY)
{
    this.bIsTracked = true;
    var invert_transform = this.invertTransform;
    var _relative_x = invert_transform.TransformPointX(posX, posY);
    var _relative_y = invert_transform.TransformPointY(posX, posY);

    var bRecalculate = false;

    if(this.xFlag)
    {
        var _new_x = this.adjastment.minX + this.coeffX*(_relative_x - this.minRealX);

        if(_new_x <= this.maximalRealativeX && _new_x >= this.minimalRealativeX)
        {
            if(this.geometry.gdLst[this.adjastment.gdRefX] !== _new_x)
                bRecalculate = true;
            this.geometry.gdLst[this.adjastment.gdRefX] = _new_x;
        }
        else if( _new_x > this.maximalRealativeX)
        {
            if(this.geometry.gdLst[this.adjastment.gdRefX] !== this.maximalRealativeX)
                bRecalculate = true;
            this.geometry.gdLst[this.adjastment.gdRefX] = this.maximalRealativeX;
        }
        else
        {
            if(this.geometry.gdLst[this.adjastment.gdRefX] !== this.minimalRealativeX)
                bRecalculate = true;
            this.geometry.gdLst[this.adjastment.gdRefX] = this.minimalRealativeX;
        }
    }

    if(this.yFlag)
    {
        var _new_y = this.adjastment.minY + this.coeffY*(_relative_y - this.minRealY);

        if(_new_y <= this.maximalRealativeY && _new_y >= this.minimalRealativeY)
        {
            if(this.geometry.gdLst[this.adjastment.gdRefY] !== _new_y)
                bRecalculate = true;
            this.geometry.gdLst[this.adjastment.gdRefY] = _new_y;
        }
        else if(_new_y > this.maximalRealativeY)
        {
            if(this.geometry.gdLst[this.adjastment.gdRefY] !== this.maximalRealativeY)
                bRecalculate = true;
            this.geometry.gdLst[this.adjastment.gdRefY] = this.maximalRealativeY;
        }
        else
        {
            if(this.geometry.gdLst[this.adjastment.gdRefY] !== this.minimalRealativeY)
                bRecalculate = true;
            this.geometry.gdLst[this.adjastment.gdRefY] = this.minimalRealativeY;
        }
    }
    if(bRecalculate)
        this.geometry.Recalculate(this.shapeWidth, this.shapeHeight);
};

XYAdjustmentTrack.prototype.trackEnd = function()
{
    if(!this.bIsTracked){
        return;
    }
    var oGeometryToSet;
    if(!this.bTextWarp)
    {
        if(!this.originalShape.spPr.geometry){
            this.originalShape.spPr.setGeometry(this.geometry.createDuplicate());
        }
        oGeometryToSet =  this.originalShape.spPr.geometry;
        if(this.xFlag)
        {
            oGeometryToSet.setAdjValue(this.refX, this.geometry.gdLst[this.adjastment.gdRefX]+"");
        }
        if(this.yFlag)
        {
            oGeometryToSet.setAdjValue(this.refY, this.geometry.gdLst[this.adjastment.gdRefY]+"");
        }
    }
    else
    {
        var new_body_pr = this.originalShape.getBodyPr();
        if (new_body_pr) {
            oGeometryToSet = AscFormat.ExecuteNoHistory(function(){
                var oGeom = this.geometry.createDuplicate();
                if(this.xFlag)
                {
                    oGeom.setAdjValue(this.refX, this.geometry.gdLst[this.adjastment.gdRefX]+"");
                }
                if(this.yFlag)
                {
                    oGeom.setAdjValue(this.refY, this.geometry.gdLst[this.adjastment.gdRefY]+"");
                }
                return oGeom;
            }, this, []);

            new_body_pr = new_body_pr.createDuplicate();
            new_body_pr.prstTxWarp = oGeometryToSet;
            if (this.originalShape.bWordShape) {
                this.originalShape.setBodyPr(new_body_pr);
            }
            else {
                if (this.originalShape.txBody) {
                    this.originalShape.txBody.setBodyPr(new_body_pr);
                }
            }
        }

    }
};

function PolarAdjustmentTrack(originalShape, adjIndex, bTextWarp)
{
    AscFormat.ExecuteNoHistory(function(){
        this.bIsTracked = false;
        this.originalShape = originalShape;



        var oPen, oBrush;
        if(bTextWarp !== true)
        {
            if(originalShape.spPr && originalShape.spPr.geometry){
                this.geometry = originalShape.spPr.geometry.createDuplicate();
            }
            else if(originalShape.calcGeometry){
                this.geometry = originalShape.calcGeometry.createDuplicate();
            }
            this.shapeWidth = originalShape.extX;
            this.shapeHeight = originalShape.extY;
            this.transform = originalShape.transform;
            this.invertTransform = originalShape.invertTransform;
            oPen = originalShape.pen;
            oBrush = originalShape.brush;
        }
        else
        {
            this.geometry = originalShape.recalcInfo.warpGeometry.createDuplicate();
            this.shapeWidth = originalShape.recalcInfo.warpGeometry.gdLst["w"];
            this.shapeHeight = originalShape.recalcInfo.warpGeometry.gdLst["h"];
            this.transform = originalShape.transformTextWordArt;
            this.invertTransform = originalShape.invertTransformTextWordArt;
            oPen = null;
            oBrush = null;
        }

        this.geometry.Recalculate(this.shapeWidth, this.shapeHeight);
        this.adjastment = this.geometry.ahPolarLst[adjIndex];
        this.bTextWarp = bTextWarp === true;

        this.radiusFlag = false;
        this.angleFlag = false;


        this.originalObject = originalShape;

        if(this.adjastment !== null && typeof this.adjastment === "object")
        {
            var _ref_r = this.adjastment.gdRefR;
            var  _gd_lst = this.geometry.gdLst;
            if(typeof _ref_r === "string" && typeof _gd_lst[_ref_r] === "number"
                && typeof this.adjastment.minR === "number" && typeof this.adjastment.maxR === "number")
            {
                _gd_lst[_ref_r] = this.adjastment.minR;
                this.geometry.Recalculate(this.shapeWidth, this.shapeHeight);
                var _dx = this.adjastment.posX - this.shapeWidth*0.5;
                var _dy = this.adjastment.posY - this.shapeWidth*0.5;
                this.minRealR = Math.sqrt(_dx*_dx + _dy*_dy);

                _gd_lst[_ref_r] = this.adjastment.maxR;
                this.geometry.Recalculate(this.shapeWidth, this.shapeHeight);
                _dx = this.adjastment.posX - this.shapeWidth*0.5;
                _dy = this.adjastment.posY - this.shapeHeight*0.5;
                this.maxRealR = Math.sqrt(_dx*_dx + _dy*_dy);



                this.maximalRealRadius = Math.max(this.maxRealR, this.minRealR);
                this.minimalRealRadius = Math.min(this.maxRealR, this.minRealR);

                this.minimalRealativeRadius = Math.min(this.adjastment.minR, this.adjastment.maxR);
                this.maximalRealativeRadius = Math.max(this.adjastment.minR, this.adjastment.maxR);

                if(this.maximalRealRadius - this.minimalRealRadius > 0)
                {
                    this.coeffR = (this.adjastment.maxR - this.adjastment.minR)/(this.maxRealR - this.minRealR);
                    this.radiusFlag = true;
                }
            }

            var _ref_ang = this.adjastment.gdRefAng;
            if(typeof _ref_ang === "string" && typeof _gd_lst[_ref_ang] === "number"
                && typeof this.adjastment.minAng === "number" && typeof  this.adjastment.maxAng === "number")
            {
                this.angleFlag = true;
                this.minimalAngle = Math.min(this.adjastment.minAng, this.adjastment.maxAng);
                this.maximalAngle = Math.max(this.adjastment.minAng, this.adjastment.maxAng);
            }

        }

        this.overlayObject = new AscFormat.OverlayObject(this.geometry, this.shapeWidth, this.shapeHeight, oBrush, oPen, this.transform);

    }, this, []);

    this.draw = function(overlay)
    {
        if(this.originalShape.parent && AscFormat.isRealNumber(this.originalShape.selectStartPage) && overlay.SetCurrentPage)
        {
            overlay.SetCurrentPage(this.originalShape.selectStartPage);
        }
        this.overlayObject.draw(overlay);
    };

    this.track = function(posX, posY)
    {
        this.bIsTracked = true;
        var invert_transform = this.invertTransform;
        var _relative_x = invert_transform.TransformPointX(posX, posY);
        var _relative_y = invert_transform.TransformPointY(posX, posY);



        var _pos_x_relative_center = _relative_x - this.shapeWidth*0.5;
        var _pos_y_relative_center = _relative_y - this.shapeHeight*0.5;
        if(this.radiusFlag)
        {
            var _radius = Math.sqrt(_pos_x_relative_center*_pos_x_relative_center + _pos_y_relative_center*_pos_y_relative_center);
            var _new_radius = this.adjastment.minR + this.coeffR*(_radius - this.minRealR);

            if(_new_radius <= this.maximalRealativeRadius && _new_radius >= this.minimalRealativeRadius)
            {
                this.geometry.gdLst[this.adjastment.gdRefR] = _new_radius;
            }
            else if( _new_radius > this.maximalRealativeRadius)
            {
                this.geometry.gdLst[this.adjastment.gdRefR] = this.maximalRealativeRadius;
            }
            else
            {
                this.geometry.gdLst[this.adjastment.gdRefR] = this.minimalRealativeRadius;
            }
        }

        if(this.angleFlag)
        {
            if(this.geometry.preset === "mathNotEqual"){
                _pos_y_relative_center = -_pos_y_relative_center;
                _pos_x_relative_center = -_pos_x_relative_center;
            }
            var _angle = Math.atan2(_pos_y_relative_center, _pos_x_relative_center);
            while(_angle < 0)
                _angle += 2*Math.PI;
            while(_angle >= 2*Math.PI)
                _angle -= 2*Math.PI;

            _angle *= AscFormat.cToDeg;
            if(_angle >= this.minimalAngle && _angle <= this.maximalAngle)
            {
                this.geometry.gdLst[this.adjastment.gdRefAng]= _angle;
            }
            else if(_angle >= this.maximalAngle)
            {
                this.geometry.gdLst[this.adjastment.gdRefAng] = this.maximalAngle;
            }
            else if(_angle <= this.minimalAngle)
            {
                this.geometry.gdLst[this.adjastment.gdRefAng] = this.minimalAngle;
            }
        }
        this.geometry.Recalculate(this.shapeWidth, this.shapeHeight);
    };

    this.trackEnd = function()
    {
        if(!this.bIsTracked){
            return;
        }
        var oGeometryToSet;
        if(!this.bTextWarp)
        {
            if(!this.originalShape.spPr.geometry){
                this.originalShape.spPr.setGeometry(this.geometry.createDuplicate());
            }
            oGeometryToSet =  this.originalShape.spPr.geometry;
            if(this.radiusFlag)
            {
                oGeometryToSet.setAdjValue(this.adjastment.gdRefR, this.geometry.gdLst[this.adjastment.gdRefR]+"");
            }
            if(this.angleFlag)
            {
                oGeometryToSet.setAdjValue(this.adjastment.gdRefAng, this.geometry.gdLst[this.adjastment.gdRefAng]+"");
            }

        }
        else
        {
            var new_body_pr = this.originalShape.getBodyPr();
            if (new_body_pr) {
                oGeometryToSet = AscFormat.ExecuteNoHistory(function(){
                    var oGeom = this.geometry.createDuplicate();
                    if(this.radiusFlag)
                    {
                        oGeom.setAdjValue(this.adjastment.gdRefR, this.geometry.gdLst[this.adjastment.gdRefR]+"");
                    }
                    if(this.angleFlag)
                    {
                        oGeom.setAdjValue(this.adjastment.gdRefAng, this.geometry.gdLst[this.adjastment.gdRefAng]+"");
                    }
                    return oGeom;
                }, this, []);

                new_body_pr = new_body_pr.createDuplicate();
                new_body_pr.prstTxWarp = oGeometryToSet;
                if (this.originalShape.bWordShape) {
                    this.originalShape.setBodyPr(new_body_pr);
                }
                else {
                    if (this.originalShape.txBody) {
                        this.originalShape.txBody.setBodyPr(new_body_pr);
                    }
                }
            }

        }
    };
}
PolarAdjustmentTrack.prototype.getBounds = XYAdjustmentTrack.prototype.getBounds;

    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].XYAdjustmentTrack = XYAdjustmentTrack;
    window['AscFormat'].PolarAdjustmentTrack = PolarAdjustmentTrack;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){
    // Import
    var CMatrix = AscCommon.CMatrix;
    var global_MatrixTransformer = AscCommon.global_MatrixTransformer;

function MoveShapeImageTrack(originalObject)
{
    this.bIsTracked = false;
    this.originalObject = originalObject;
    this.transform = new CMatrix();
    this.x = null;
    this.y = null;
    this.pageIndex = null;
    this.originalShape = originalObject;
    this.lastDx = 0;
    this.lastDy = 0;

    if(!originalObject.isChart())
    {
        if(originalObject.blipFill)
        {
            this.brush = new AscFormat.CUniFill();
            this.brush.fill = originalObject.blipFill;
        }
        else
        {
            this.brush = originalObject.brush;
        }
        this.pen = originalObject.pen;
    }
    else
    {
        var pen_brush = AscFormat.CreatePenBrushForChartTrack();
        this.brush = pen_brush.brush;
        this.pen = pen_brush.pen;
    }
    this.overlayObject = new AscFormat.OverlayObject(originalObject.getGeom(), this.originalObject.extX, this.originalObject.extY, this.brush, this.pen, this.transform);

    this.groupInvertMatrix = null;
    if(this.originalObject.group)
    {
        this.groupInvertMatrix = this.originalObject.group.invertTransform.CreateDublicate();
        this.groupInvertMatrix.tx = 0;
        this.groupInvertMatrix.ty = 0;
    }

    this.track = function(dx, dy, pageIndex)
    {
        this.bIsTracked = true;
        this.lastDx = dx;
        this.lastDy = dy;
        var original = this.originalObject;
        var dx2, dy2;
        if(this.groupInvertMatrix)
        {
            dx2 = this.groupInvertMatrix.TransformPointX(dx, dy);
            dy2 = this.groupInvertMatrix.TransformPointY(dx, dy);
        }
        else
        {
            dx2 = dx;
            dy2 = dy;
        }

        this.x = original.x + dx2;
        this.y = original.y + dy2;
        this.transform.Reset();
        var hc = original.extX*0.5;
        var vc = original.extY*0.5;

        global_MatrixTransformer.TranslateAppend(this.transform, -hc, -vc);
        if(original.flipH)
            global_MatrixTransformer.ScaleAppend(this.transform, -1, 1);
        if(original.flipV)
            global_MatrixTransformer.ScaleAppend(this.transform, 1, -1);
        global_MatrixTransformer.RotateRadAppend(this.transform, -original.rot);
        global_MatrixTransformer.TranslateAppend(this.transform, this.x + hc, this.y + vc);
        if(this.originalObject.group)
        {
            global_MatrixTransformer.MultiplyAppend(this.transform, this.originalObject.group.transform);
        }
        if(AscFormat.isRealNumber(pageIndex))
            this.pageIndex = pageIndex;
    };

    this.draw = function(overlay)
    {
        if(AscFormat.isRealNumber(this.pageIndex) && overlay.SetCurrentPage)
        {
            overlay.SetCurrentPage(this.pageIndex);
        }
        this.overlayObject.draw(overlay);
    };

    this.trackEnd = function(bWord, bNoResetCnx)
    {
        if(!this.bIsTracked){
            return;
        }
        if(bWord)
        {
            if(this.originalObject.selectStartPage !== this.pageIndex)
                this.originalObject.selectStartPage = this.pageIndex;
        }
        var scale_coefficients, ch_off_x, ch_off_y;
        AscFormat.CheckSpPrXfrm(this.originalObject);
        if(this.originalObject.group)
        {
            scale_coefficients = this.originalObject.group.getResultScaleCoefficients();
            ch_off_x = this.originalObject.group.spPr.xfrm.chOffX;
            ch_off_y = this.originalObject.group.spPr.xfrm.chOffY;
        }
        else
        {
            if(bWord)
            {
                if(this.originalObject.spPr.xfrm.offX === 0 && this.originalObject.spPr.xfrm.offY === 0)
                    return;
            }
            scale_coefficients = {cx: 1, cy: 1};
            ch_off_x = 0;
            ch_off_y = 0;
            if(bWord)
            {
                this.x = 0;
                this.y = 0;
            }
        }
        var _xfrm = this.originalObject.spPr.xfrm;
        var _x = _xfrm.offX;
        var _y = _xfrm.offY;
        this.originalObject.spPr.xfrm.setOffX(this.x/scale_coefficients.cx + ch_off_x);
        this.originalObject.spPr.xfrm.setOffY(this.y/scale_coefficients.cy + ch_off_y);

        if(this.originalObject.getObjectType() === AscDFH.historyitem_type_Cnx){
            if(!AscFormat.fApproxEqual(_x, _xfrm.offX) || !AscFormat.fApproxEqual(_y, _xfrm.offY)){
                var nvUniSpPr = this.originalObject.nvSpPr.nvUniSpPr;

                var bResetBegin = false, bResetEnd = false;
                var oBeginShape = AscCommon.g_oTableId.Get_ById(nvUniSpPr.stCnxId);
                var oEndShape = AscCommon.g_oTableId.Get_ById(nvUniSpPr.endCnxId);
                if(oBeginShape){
                    if(oBeginShape.bDeleted){
                        bResetBegin = true;
                    }
                    else{
                        if(!oBeginShape.selected){
                            bResetBegin = true;
                        }
                    }
                }
                if(oEndShape){
                    if(oEndShape.bDeleted){
                        bResetEnd = true;
                    }
                    else{
                        if(!oEndShape.selected){
                            bResetEnd = true;
                        }
                    }
                }

                if((bResetEnd || bResetBegin) && (bNoResetCnx !== false)){
                    var _copy_nv_sp_pr = nvUniSpPr.copy();
                    if(bResetBegin){
                        _copy_nv_sp_pr.stCnxId = null;
                        _copy_nv_sp_pr.stCnxIdx = null;
                    }
                    if(bResetEnd){
                        _copy_nv_sp_pr.endCnxId = null;
                        _copy_nv_sp_pr.endCnxIdx = null;
                    }
                    this.originalObject.nvSpPr.setUniSpPr(_copy_nv_sp_pr);
                }
            }
        }
        this.originalObject.checkDrawingBaseCoords();
    };
}

MoveShapeImageTrack.prototype.getBounds = function()
{
    var boundsChecker = new  AscFormat.CSlideBoundsChecker();
    this.draw(boundsChecker);
    var tr = this.transform;
    var arr_p_x = [];
    var arr_p_y = [];
    arr_p_x.push(tr.TransformPointX(0,0));
    arr_p_y.push(tr.TransformPointY(0,0));
    arr_p_x.push(tr.TransformPointX(this.originalObject.extX,0));
    arr_p_y.push(tr.TransformPointY(this.originalObject.extX,0));
    arr_p_x.push(tr.TransformPointX(this.originalObject.extX,this.originalObject.extY));
    arr_p_y.push(tr.TransformPointY(this.originalObject.extX,this.originalObject.extY));
    arr_p_x.push(tr.TransformPointX(0,this.originalObject.extY));
    arr_p_y.push(tr.TransformPointY(0,this.originalObject.extY));

    arr_p_x.push(boundsChecker.Bounds.min_x);
    arr_p_x.push(boundsChecker.Bounds.max_x);
    arr_p_y.push(boundsChecker.Bounds.min_y);
    arr_p_y.push(boundsChecker.Bounds.max_y);

    boundsChecker.Bounds.min_x = Math.min.apply(Math, arr_p_x);
    boundsChecker.Bounds.max_x = Math.max.apply(Math, arr_p_x);
    boundsChecker.Bounds.min_y = Math.min.apply(Math, arr_p_y);
    boundsChecker.Bounds.max_y = Math.max.apply(Math, arr_p_y);
    boundsChecker.Bounds.posX = this.x;
    boundsChecker.Bounds.posY = this.y;
    boundsChecker.Bounds.extX =  this.originalObject.extX;
    boundsChecker.Bounds.extY =  this.originalObject.extY;
    return boundsChecker.Bounds;
};

function MoveGroupTrack(originalObject)
{
    this.bIsTracked = false;
    this.x = null;
    this.y = null;
    this.originalObject = originalObject;
    this.transform = new CMatrix();

    this.pageIndex = null;
    this.overlayObjects = [];

    this.arrTransforms2 = [];
    var arr_graphic_objects = originalObject.getArrGraphicObjects();
    var group_invert_transform = originalObject.invertTransform;
    for(var i = 0; i < arr_graphic_objects.length; ++i)
    {
        var gr_obj_transform_copy = arr_graphic_objects[i].transform.CreateDublicate();
        global_MatrixTransformer.MultiplyAppend(gr_obj_transform_copy, group_invert_transform);
        this.arrTransforms2[i] = gr_obj_transform_copy;
        this.overlayObjects[i] = new AscFormat.OverlayObject(arr_graphic_objects[i].getGeom(), arr_graphic_objects[i].extX, arr_graphic_objects[i].extY,
            arr_graphic_objects[i].brush,  arr_graphic_objects[i].pen, new CMatrix());
    }



    this.track = function(dx, dy, pageIndex)
    {
        this.bIsTracked = true;
        this.pageIndex = pageIndex;
        var original = this.originalObject;
        this.x = original.x + dx;
        this.y = original.y + dy;
        this.transform.Reset();
        var hc = original.extX*0.5;
        var vc = original.extY*0.5;

        global_MatrixTransformer.TranslateAppend(this.transform, -hc, -vc);
        if(original.flipH)
            global_MatrixTransformer.ScaleAppend(this.transform, -1, 1);
        if(original.flipV)
            global_MatrixTransformer.ScaleAppend(this.transform, 1, -1);
        global_MatrixTransformer.RotateRadAppend(this.transform, -original.rot);
        global_MatrixTransformer.TranslateAppend(this.transform, this.x + hc, this.y + vc);

        for(var i = 0; i < this.overlayObjects.length; ++i)
        {
            var new_transform = this.arrTransforms2[i].CreateDublicate();
            global_MatrixTransformer.MultiplyAppend(new_transform, this.transform);
            this.overlayObjects[i].updateTransformMatrix(new_transform);
        }
    };

    this.draw = function(overlay)
    {
        if(AscFormat.isRealNumber(this.pageIndex) && overlay.SetCurrentPage)
        {
            overlay.SetCurrentPage(this.pageIndex);
        }
        for(var i = 0; i < this.overlayObjects.length; ++i)
        {
            this.overlayObjects[i].draw(overlay);
        }
    };

    this.getBounds = function()
    {
        var bounds_checker = new AscFormat.CSlideBoundsChecker();
        for(var i = 0; i < this.overlayObjects.length; ++i)
        {
            this.overlayObjects[i].draw(bounds_checker);
        }
        bounds_checker.Bounds.posX = this.x;
        bounds_checker.Bounds.posY = this.y;
        bounds_checker.Bounds.extX = this.originalObject.extX;
        bounds_checker.Bounds.extY = this.originalObject.extY;
        return bounds_checker.Bounds;
    };

    this.trackEnd = function(bWord)
    {
        if(!this.bIsTracked){
            return;
        }
        if(bWord)
        {
            this.x = 0;
            this.y = 0;
        }
        AscFormat.CheckSpPrXfrm3(this.originalObject);
        var xfrm = this.originalObject.spPr.xfrm;


        xfrm.setOffX(this.x);
        xfrm.setOffY(this.y);

        if(bWord)
        {
            if(this.originalObject.selectStartPage !== this.pageIndex)
                this.originalObject.selectStartPage = this.pageIndex;
        }
        this.originalObject.checkDrawingBaseCoords();
    };
}

function MoveComment(comment)
{
    this.bIsTracked = false;
    this.comment = comment;
    this.x = comment.x;
    this.y = comment.y;

    this.track = function(dx, dy)
    {
        this.bIsTracked = true;
        var original = this.comment;
        this.x = original.x + dx;
        this.y = original.y + dy;
    };

    this.draw = function(overlay)
    {

        var Flags = 0;
        Flags |= 1;
        if(this.comment.Data.m_aReplies.length > 0)
        {
            Flags |= 2;
        }
        var dd = editor.WordControl.m_oDrawingDocument;
        overlay.DrawPresentationComment(Flags, this.x, this.y, dd.GetCommentWidth(Flags), dd.GetCommentHeight(Flags))
    };

    this.trackEnd = function()
    {
        if(!this.bIsTracked){
            return;
        }
        this.comment.setPosition(this.x, this.y);
    };
}

    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].MoveShapeImageTrack = MoveShapeImageTrack;
    window['AscFormat'].MoveGroupTrack = MoveGroupTrack;
    window['AscFormat'].MoveComment = MoveComment;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

    var MIN_SHAPE_SIZE = 1.27;//размер меньше которого нельзя уменшить автофигуру или картинку по горизонтали или вертикали
    var MIN_SHAPE_SIZE_DIV2 = MIN_SHAPE_SIZE/2.0;

    var SHAPE_ASPECTS = {};
    SHAPE_ASPECTS["can"] = 3616635/4810125;
    SHAPE_ASPECTS["moon"] = 457200/914400;
    SHAPE_ASPECTS["leftBracket"] = 73152/914400;
    SHAPE_ASPECTS["rightBracket"] = 73152/914400;
    SHAPE_ASPECTS["leftBrace"] = 155448/914400;
    SHAPE_ASPECTS["rightBrace"] = 155448/914400;
    SHAPE_ASPECTS["triangle"] = 1060704/914400;
    SHAPE_ASPECTS["parallelogram"] = 1216152/914400;
    SHAPE_ASPECTS["trapezoid"] = 914400/1216152;
    SHAPE_ASPECTS["pentagon"] = 960120/914400;
    SHAPE_ASPECTS["hexagon"] = 1060704/914400;
    SHAPE_ASPECTS["bracePair"] = 1069848/914400;
    SHAPE_ASPECTS["rightArrow"] = 978408/484632;
    SHAPE_ASPECTS["leftArrow"] = 978408/484632;
    SHAPE_ASPECTS["upArrow"] = 484632/978408;
    SHAPE_ASPECTS["downArrow"] = 484632/978408;
    SHAPE_ASPECTS["leftRightArrow"] = 1216152/484632;
    SHAPE_ASPECTS["upDownArrow"] = 484632/1216152;
    SHAPE_ASPECTS["bentArrow"] = 813816/868680;
    SHAPE_ASPECTS["uturnArrow"] = 886968/877824;
    SHAPE_ASPECTS["bentUpArrow"] = 850392/731520;
    SHAPE_ASPECTS["curvedRightArrow"] = 731520/1216152;
    SHAPE_ASPECTS["curvedLeftArrow"] = 731520/1216152;
    SHAPE_ASPECTS["curvedUpArrow"] = 1216152/731520;
    SHAPE_ASPECTS["curvedDownArrow"] = 1216152/731520;
    SHAPE_ASPECTS["stripedRightArrow"] = 978408/484632;
    SHAPE_ASPECTS["notchedRightArrow"] = 978408/484632;
    SHAPE_ASPECTS["homePlate"] = 978408/484632;
    SHAPE_ASPECTS["leftRightArrowCallout"] = 1216152/576072;
    SHAPE_ASPECTS["flowChartProcess"] = 914400/612648;
    SHAPE_ASPECTS["flowChartAlternateProcess"] = 914400/612648;
    SHAPE_ASPECTS["flowChartDecision"] = 914400/612648;
    SHAPE_ASPECTS["flowChartInputOutput"] = 914400/612648;
    SHAPE_ASPECTS["flowChartPredefinedProcess"] = 914400/612648;
    SHAPE_ASPECTS["flowChartDocument"] = 914400/612648;
    SHAPE_ASPECTS["flowChartMultidocument"] = 1060704/758952;
    SHAPE_ASPECTS["flowChartTerminator"] = 914400/301752;
    SHAPE_ASPECTS["flowChartPreparation"] = 1060704/612648;
    SHAPE_ASPECTS["flowChartManualInput"] = 914400/457200;
    SHAPE_ASPECTS["flowChartManualOperation"] = 914400/612648;
    SHAPE_ASPECTS["flowChartPunchedCard"] = 914400/804672;
    SHAPE_ASPECTS["flowChartPunchedTape"] = 914400/804672;
    SHAPE_ASPECTS["flowChartPunchedTape"] = 457200/914400;
    SHAPE_ASPECTS["flowChartSort"] = 457200/914400;
    SHAPE_ASPECTS["flowChartOnlineStorage"] = 914400/612648;
    SHAPE_ASPECTS["flowChartMagneticDisk"] = 914400/612648;
    SHAPE_ASPECTS["flowChartMagneticDrum"] = 914400/685800;
    SHAPE_ASPECTS["flowChartDisplay"] = 914400/612648;
    SHAPE_ASPECTS["ribbon2"] = 1216152/612648;
    SHAPE_ASPECTS["ribbon"] = 1216152/612648;
    SHAPE_ASPECTS["ellipseRibbon2"] = 1216152/758952;
    SHAPE_ASPECTS["ellipseRibbon"] = 1216152/758952;
    SHAPE_ASPECTS["verticalScroll"] = 1033272/1143000;
    SHAPE_ASPECTS["horizontalScroll"] = 1143000/1033272;
    SHAPE_ASPECTS["wedgeRectCallout"] = 914400/612648;
    SHAPE_ASPECTS["wedgeRoundRectCallout"] = 914400/612648;
    SHAPE_ASPECTS["wedgeEllipseCallout"] = 914400/612648;
    SHAPE_ASPECTS["cloudCallout"] = 914400/612648;
    SHAPE_ASPECTS["borderCallout1"] = 914400/612648;
    SHAPE_ASPECTS["borderCallout2"] = 914400/612648;
    SHAPE_ASPECTS["borderCallout3"] = 914400/612648;
    SHAPE_ASPECTS["accentCallout1"] = 914400/612648;
    SHAPE_ASPECTS["accentCallout2"] = 914400/612648;
    SHAPE_ASPECTS["accentCallout3"] = 914400/612648;
    SHAPE_ASPECTS["callout1"] = 914400/612648;
    SHAPE_ASPECTS["callout2"] = 914400/612648;
    SHAPE_ASPECTS["callout3"] = 914400/612648;
    SHAPE_ASPECTS["accentBorderCallout1"] = 914400/612648;
    SHAPE_ASPECTS["accentBorderCallout2"] = 914400/612648;
    SHAPE_ASPECTS["accentBorderCallout3"] = 914400/612648;

function NewShapeTrack(presetGeom, startX, startY, theme, master, layout, slide, pageIndex, drawingsController)
{
    this.presetGeom = presetGeom;
    this.startX = startX;
    this.startY = startY;

    this.x = null;
    this.y = null;
    this.extX = null;
    this.extY = null;
    this.rot = 0;
    this.arrowsCount = 0;
    this.transform = new AscCommon.CMatrix();
    this.pageIndex = pageIndex;
    this.theme = theme;
    this.drawingsController = drawingsController;

    //for connectors
    this.bConnector = false;
    this.startConnectionInfo = null;
    this.oShapeDrawConnectors = null;
    this.lastSpPr = null;

    this.startShape = null;
    this.endShape = null;
    this.endConnectionInfo = null;

    AscFormat.ExecuteNoHistory(function(){

        if(this.drawingsController){
            this.bConnector = AscFormat.isConnectorPreset(presetGeom);
            if(this.bConnector){

                var aSpTree = [];
                this.drawingsController.getAllSingularDrawings(this.drawingsController.getDrawingArray(), aSpTree);
                var oConnector = null;
                for(var i = aSpTree.length - 1; i > -1; --i){
                    oConnector = aSpTree[i].findConnector(startX, startY);
                    if(oConnector){
                        this.startConnectionInfo = oConnector;
                        this.startX = oConnector.x;
                        this.startY = oConnector.y;
                        this.startShape = aSpTree[i];
                        break;
                    }
                }
            }
        }


        var style;

        if(presetGeom.indexOf("WithArrow") > -1)
        {
            presetGeom = presetGeom.substr(0, presetGeom.length - 9);
            this.presetGeom = presetGeom;
            this.arrowsCount = 1;
        }
        if(presetGeom.indexOf("WithTwoArrows") > -1)
        {
            presetGeom = presetGeom.substr(0, presetGeom.length - 13);
            this.presetGeom = presetGeom;
            this.arrowsCount = 2;
        }

        var spDef = theme.spDef;
        if(presetGeom !== "textRect")
        {
            if(spDef && spDef.style)
            {
                style = spDef.style.createDuplicate();
            }
            else
            {
                style = AscFormat.CreateDefaultShapeStyle(this.presetGeom);
            }
        }
        else
            style = AscFormat.CreateDefaultTextRectStyle();
        var brush = theme.getFillStyle(style.fillRef.idx);
        style.fillRef.Color.Calculate(theme, slide, layout, master, {R:0, G: 0, B:0, A:255});
        var RGBA = style.fillRef.Color.RGBA;
        if (style.fillRef.Color.color)
        {
            if (brush.fill && (brush.fill.type === Asc.c_oAscFill.FILL_TYPE_SOLID))
            {
                brush.fill.color = style.fillRef.Color.createDuplicate();
            }
        }
        var pen = theme.getLnStyle(style.lnRef.idx, style.lnRef.Color);
        style.lnRef.Color.Calculate(theme, slide, layout, master);
        RGBA = style.lnRef.Color.RGBA;

        if(presetGeom === "textRect")
        {
            var ln, fill;
            ln = new AscFormat.CLn();
            ln.w = 6350;
            ln.Fill = new AscFormat.CUniFill();
            ln.Fill.fill = new AscFormat.CSolidFill();
            ln.Fill.fill.color = new AscFormat.CUniColor();
            ln.Fill.fill.color.color  = new AscFormat.CPrstColor();
            ln.Fill.fill.color.color.id = "black";

            fill = new AscFormat.CUniFill();
            fill.fill = new AscFormat.CSolidFill();
            fill.fill.color = new AscFormat.CUniColor();
            fill.fill.color.color  = new AscFormat.CSchemeColor();
            fill.fill.color.color.id = 12;
            pen.merge(ln);
            brush.merge(fill);
            if(slide)
            {
                brush = AscFormat.CreateNoFillUniFill();
                pen = AscFormat.CreateNoFillLine();
            }
        }

        if(this.arrowsCount > 0)
        {
            pen.setTailEnd(new AscFormat.EndArrow());
            pen.tailEnd.setType(AscFormat.LineEndType.Arrow);
            pen.tailEnd.setLen(AscFormat.LineEndSize.Mid);
            if(this.arrowsCount === 2)
            {
                pen.setHeadEnd(new AscFormat.EndArrow());
                pen.headEnd.setType(AscFormat.LineEndType.Arrow);
                pen.headEnd.setLen(AscFormat.LineEndSize.Mid);
            }
        }
        if(presetGeom !== "textRect")
        {
            if(spDef && spDef.spPr )
            {
                if(spDef.spPr.Fill )
                {
                    brush.merge(spDef.spPr.Fill);
                }

                if(spDef.spPr.ln )
                {
                    pen.merge(spDef.spPr.ln);
                }
            }
        }

        var geometry = AscFormat.CreateGeometry(presetGeom !== "textRect" ? presetGeom : "rect");

        this.startGeom = geometry;
        if(pen.Fill)
        {
            pen.Fill.calculate(theme, slide, layout, master, RGBA);
        }
        brush.calculate(theme, slide, layout, master, RGBA);

        this.isLine = this.presetGeom === "line";

        this.overlayObject = new AscFormat.OverlayObject(geometry, 5, 5, brush, pen, this.transform);
        this.shape = null;

    }, this, []);

    this.track = function(e, x, y)
    {
        var bConnectorHandled = false;
        this.oShapeDrawConnectors = null;
        this.lastSpPr = null;

        this.endShape  = null;
        this.endConnectionInfo = null;

        if(this.bConnector){
            var aSpTree = [];
            this.drawingsController.getAllSingularDrawings(this.drawingsController.getDrawingArray(), aSpTree);
            var oConnector = null;
            var oEndConnectionInfo = null;
            for(var i = aSpTree.length - 1; i > -1; --i){
                oConnector = aSpTree[i].findConnector(x, y);
                if(oConnector){
                    oEndConnectionInfo = oConnector;
                    this.oShapeDrawConnectors = aSpTree[i];
                    this.endShape = aSpTree[i];
                    this.endConnectionInfo = oEndConnectionInfo;
                    break;
                }
            }
            if(this.startConnectionInfo || oEndConnectionInfo){

                var _startInfo = this.startConnectionInfo;
                var _endInfo = oEndConnectionInfo;
                if(!_startInfo){
                    _startInfo = AscFormat.fCalculateConnectionInfo(_endInfo, this.startX, this.startY);
                }
                else if(!_endInfo){
                    _endInfo = AscFormat.fCalculateConnectionInfo(_startInfo, x, y);
                }
                var oSpPr = AscFormat.fCalculateSpPr(_startInfo, _endInfo, this.presetGeom, this.overlayObject.pen.w);
                this.flipH = oSpPr.xfrm.flipH === true;
                this.flipV = oSpPr.xfrm.flipV === true;
                this.rot = AscFormat.isRealNumber(oSpPr.xfrm.rot) ? oSpPr.xfrm.rot : 0;
                this.extX = oSpPr.xfrm.extX;
                this.extY = oSpPr.xfrm.extY;
                this.x = oSpPr.xfrm.offX;
                this.y = oSpPr.xfrm.offY;
                this.overlayObject = new AscFormat.OverlayObject(oSpPr.geometry, 5, 5, this.overlayObject.brush, this.overlayObject.pen, this.transform);
                bConnectorHandled = true;
                this.lastSpPr = oSpPr;
            }
            if(!this.oShapeDrawConnectors){
                for(var i = aSpTree.length - 1; i > -1; --i){
                    var oCs = aSpTree[i].findConnectionShape(x, y);
                    if(oCs ){
                        oEndConnectionInfo = oConnector;
                        this.oShapeDrawConnectors = oCs;
                        break;
                    }
                }
            }
            if(false === bConnectorHandled){
                this.overlayObject = new AscFormat.OverlayObject(this.startGeom, 5, 5, this.overlayObject.brush, this.overlayObject.pen, this.transform);
            }
        }

        if(false === bConnectorHandled){
            var real_dist_x = x - this.startX;
            var abs_dist_x = Math.abs(real_dist_x);
            var real_dist_y = y - this.startY;
            var abs_dist_y = Math.abs(real_dist_y);
            this.flipH = false;
            this.flipV = false;
            this.rot = 0;

            if(this.isLine || this.bConnector)
            {
                if(x < this.startX)
                {
                    this.flipH = true;
                }
                if(y < this.startY)
                {
                    this.flipV = true;
                }
            }
            if(!(e.CtrlKey || e.ShiftKey) || (e.CtrlKey && !e.ShiftKey && this.isLine))
            {
                this.extX = abs_dist_x >= MIN_SHAPE_SIZE  ? abs_dist_x : (this.isLine ? 0 : MIN_SHAPE_SIZE);
                this.extY = abs_dist_y >= MIN_SHAPE_SIZE  ? abs_dist_y : (this.isLine ? 0 : MIN_SHAPE_SIZE);
                if(real_dist_x >= 0)
                {
                    this.x = this.startX;
                }
                else
                {
                    this.x = abs_dist_x >= MIN_SHAPE_SIZE  ? x : this.startX - this.extX;
                }

                if(real_dist_y >= 0)
                {
                    this.y = this.startY;
                }
                else
                {
                    this.y = abs_dist_y >= MIN_SHAPE_SIZE  ? y : this.startY - this.extY;
                }
            }
            else if(e.CtrlKey && !e.ShiftKey)
            {
                if(abs_dist_x >= MIN_SHAPE_SIZE_DIV2 )
                {
                    this.x = this.startX - abs_dist_x;
                    this.extX = 2*abs_dist_x;
                }
                else
                {
                    this.x = this.startX - MIN_SHAPE_SIZE_DIV2;
                    this.extX = MIN_SHAPE_SIZE;
                }

                if(abs_dist_y >= MIN_SHAPE_SIZE_DIV2 )
                {
                    this.y = this.startY - abs_dist_y;
                    this.extY = 2*abs_dist_y;
                }
                else
                {
                    this.y = this.startY - MIN_SHAPE_SIZE_DIV2;
                    this.extY = MIN_SHAPE_SIZE;
                }
            }
            else if(!e.CtrlKey && e.ShiftKey)
            {

                var new_width, new_height;
                var prop_coefficient = (typeof AscFormat.SHAPE_ASPECTS[this.presetGeom] === "number" ? AscFormat.SHAPE_ASPECTS[this.presetGeom] : 1);
                if(abs_dist_y === 0)
                {
                    new_width = abs_dist_x > MIN_SHAPE_SIZE ? abs_dist_x : MIN_SHAPE_SIZE;
                    new_height = abs_dist_x/prop_coefficient;
                }
                else
                {
                    var new_aspect = abs_dist_x/abs_dist_y;
                    if (new_aspect >= prop_coefficient)
                    {
                        new_width = abs_dist_x;
                        new_height = abs_dist_x/prop_coefficient;
                    }
                    else
                    {
                        new_height = abs_dist_y;
                        new_width = abs_dist_y*prop_coefficient;
                    }
                }

                if(new_width < MIN_SHAPE_SIZE || new_height < MIN_SHAPE_SIZE)
                {
                    var k_wh = new_width/new_height;
                    if(new_height < MIN_SHAPE_SIZE && new_width < MIN_SHAPE_SIZE)
                    {
                        if(new_height < new_width)
                        {
                            new_height = MIN_SHAPE_SIZE;
                            new_width = new_height*k_wh;
                        }
                        else
                        {
                            new_width = MIN_SHAPE_SIZE;
                            new_height = new_width/k_wh;
                        }
                    }
                    else if(new_height < MIN_SHAPE_SIZE)
                    {
                        new_height = MIN_SHAPE_SIZE;
                        new_width = new_height*k_wh;
                    }
                    else
                    {
                        new_width = MIN_SHAPE_SIZE;
                        new_height = new_width/k_wh;
                    }
                }
                this.extX = new_width;
                this.extY = new_height;
                if(real_dist_x >= 0)
                    this.x = this.startX;
                else
                    this.x = this.startX - this.extX;

                if(real_dist_y >= 0)
                    this.y = this.startY;
                else
                    this.y = this.startY - this.extY;

                if(this.isLine)
                {
                    var angle = Math.atan2(real_dist_y, real_dist_x);
                    if(angle >=0 && angle <= Math.PI/8
                        || angle <= 0 && angle >= -Math.PI/8
                        || angle >= 7*Math.PI/8 && angle <= Math.PI )
                    {
                        this.extY = 0;
                        this.y = this.startY;
                    }
                    else if(angle >= 3*Math.PI/8 && angle <= 5*Math.PI/8
                        || angle <= -3*Math.PI/8 && angle >= -5*Math.PI/8)
                    {
                        this.extX = 0;
                        this.x = this.startX;
                    }
                }
            }
            else
            {
                var new_width, new_height;
                var prop_coefficient = (typeof AscFormat.SHAPE_ASPECTS[this.presetGeom] === "number" ? AscFormat.SHAPE_ASPECTS[this.presetGeom] : 1);
                if(abs_dist_y === 0)
                {
                    new_width = abs_dist_x > MIN_SHAPE_SIZE_DIV2 ? abs_dist_x*2 : MIN_SHAPE_SIZE;
                    new_height = new_width/prop_coefficient;
                }
                else
                {
                    var new_aspect = abs_dist_x/abs_dist_y;
                    if (new_aspect >= prop_coefficient)
                    {
                        new_width = abs_dist_x*2;
                        new_height = new_width/prop_coefficient;
                    }
                    else
                    {
                        new_height = abs_dist_y*2;
                        new_width = new_height*prop_coefficient;
                    }
                }

                if(new_width < MIN_SHAPE_SIZE || new_height < MIN_SHAPE_SIZE)
                {
                    var k_wh = new_width/new_height;
                    if(new_height < MIN_SHAPE_SIZE && new_width < MIN_SHAPE_SIZE)
                    {
                        if(new_height < new_width)
                        {
                            new_height = MIN_SHAPE_SIZE;
                            new_width = new_height*k_wh;
                        }
                        else
                        {
                            new_width = MIN_SHAPE_SIZE;
                            new_height = new_width/k_wh;
                        }
                    }
                    else if(new_height < MIN_SHAPE_SIZE)
                    {
                        new_height = MIN_SHAPE_SIZE;
                        new_width = new_height*k_wh;
                    }
                    else
                    {
                        new_width = MIN_SHAPE_SIZE;
                        new_height = new_width/k_wh;
                    }
                }
                this.extX = new_width;
                this.extY = new_height;
                this.x = this.startX - this.extX*0.5;
                this.y = this.startY - this.extY*0.5;
            }
        }

        this.overlayObject.updateExtents(this.extX, this.extY);
        this.transform.Reset();
        var hc = this.extX * 0.5;
        var vc = this.extY * 0.5;
        AscCommon.global_MatrixTransformer.TranslateAppend(this.transform, -hc, -vc);
        if (this.flipH)
            AscCommon.global_MatrixTransformer.ScaleAppend(this.transform, -1, 1);
        if (this.flipV)
            AscCommon.global_MatrixTransformer.ScaleAppend(this.transform, 1, -1);

        AscCommon.global_MatrixTransformer.RotateRadAppend(this.transform, -this.rot);
        AscCommon.global_MatrixTransformer.TranslateAppend(this.transform, this.x + hc, this.y + vc);
    };

    this.draw = function(overlay)
    {
        if(AscFormat.isRealNumber(this.pageIndex) && overlay.SetCurrentPage)
        {
            overlay.SetCurrentPage(this.pageIndex);
        }
        if(this.oShapeDrawConnectors){
            this.oShapeDrawConnectors.drawConnectors(overlay);
        }
        this.overlayObject.draw(overlay);
    };

    this.getShape = function(bFromWord, DrawingDocument, drawingObjects)
    {
        var _sp_pr, shape;
        if(this.bConnector){

            shape = new AscFormat.CConnectionShape();
            if(drawingObjects)
            {
                shape.setDrawingObjects(drawingObjects);
            }
            if(this.lastSpPr){
                _sp_pr = this.lastSpPr.createDuplicate();
            }
            else{
                _sp_pr = new AscFormat.CSpPr();
                _sp_pr.setXfrm(new AscFormat.CXfrm());
                var xfrm = _sp_pr.xfrm;
                xfrm.setParent(_sp_pr);
                var x, y;
                if(bFromWord)
                {
                    x = 0;
                    y = 0;
                }
                else
                {
                    x = this.x;
                    y = this.y;
                }
                xfrm.setOffX(x);
                xfrm.setOffY(y);
                xfrm.setExtX(this.extX);
                xfrm.setExtY(this.extY);
                xfrm.setFlipH(this.flipH);
                xfrm.setFlipV(this.flipV);
            }

            shape.setSpPr(_sp_pr);
            _sp_pr.setParent(shape);

            var nv_sp_pr = new AscFormat.UniNvPr();
            nv_sp_pr.cNvPr.setId(0);
            shape.setNvSpPr(nv_sp_pr);

            var nvUniSpPr = new AscFormat.CNvUniSpPr();
            if(this.startShape && this.startConnectionInfo)
            {
                nvUniSpPr.stCnxIdx = this.startConnectionInfo.idx;
                nvUniSpPr.stCnxId  = this.startShape.Id;
            }
            if(this.endShape && this.endConnectionInfo)
            {
                nvUniSpPr.endCnxIdx = this.endConnectionInfo.idx;
                nvUniSpPr.endCnxId  = this.endShape.Id;
            }
            shape.nvSpPr.setUniSpPr(nvUniSpPr);
        }
        else{
            shape = new AscFormat.CShape();
            if(drawingObjects)
            {
                shape.setDrawingObjects(drawingObjects);
            }
            shape.setSpPr(new AscFormat.CSpPr());
            shape.spPr.setParent(shape);
            if(bFromWord)
            {
                shape.setWordShape(true);
            }
            var x, y;
            if(bFromWord)
            {
                x = 0;
                y = 0;
            }
            else
            {
                x = this.x;
                y = this.y;
            }

            shape.spPr.setXfrm(new AscFormat.CXfrm());
            var xfrm = shape.spPr.xfrm;
            xfrm.setParent(shape.spPr);
            xfrm.setOffX(x);
            xfrm.setOffY(y);
            xfrm.setExtX(this.extX);
            xfrm.setExtY(this.extY);
            xfrm.setFlipH(this.flipH);
            xfrm.setFlipV(this.flipV);
        }

        shape.setBDeleted(false);

        if(this.presetGeom === "textRect")
        {
            shape.spPr.setGeometry(AscFormat.CreateGeometry("rect"));
            var fill, ln;
            if(!drawingObjects || !drawingObjects.cSld)
            {
                shape.setStyle(AscFormat.CreateDefaultTextRectStyle());

                fill = new AscFormat.CUniFill();
                fill.setFill(new AscFormat.CSolidFill());
                fill.fill.setColor(new AscFormat.CUniColor());
                fill.fill.color.setColor(new AscFormat.CSchemeColor());
                fill.fill.color.color.setId(12);
                shape.spPr.setFill(fill);

                ln = new AscFormat.CLn();
                ln.setW(6350);
                ln.setFill(new AscFormat.CUniFill());
                ln.Fill.setFill(new AscFormat.CSolidFill());
                ln.Fill.fill.setColor(new AscFormat.CUniColor());
                ln.Fill.fill.color.setColor(new AscFormat.CPrstColor());
                ln.Fill.fill.color.color.setId("black");
                shape.spPr.setLn(ln);
            }
            else
            {
                fill = new AscFormat.CUniFill();
                fill.setFill(new AscFormat.CNoFill());
                shape.spPr.setFill(fill);
            }
            if(bFromWord)
            {
                shape.setTextBoxContent(new CDocumentContent(shape, DrawingDocument, 0, 0, 0, 0, false, false, false));
                var body_pr = new AscFormat.CBodyPr();
                body_pr.setDefault();
                shape.setBodyPr(body_pr);
            }
            else
            {
                shape.setTxBody(new AscFormat.CTextBody());
                var content = new AscFormat.CDrawingDocContent(shape.txBody, DrawingDocument, 0, 0, 0, 0, false, false, true);
                shape.txBody.setParent(shape);
                shape.txBody.setContent(content);
                var body_pr = new AscFormat.CBodyPr();
                body_pr.setDefault();
                var bNeedCheckExtents = false;
                if(drawingObjects){
                    if(!drawingObjects.cSld){
                        body_pr.vertOverflow = AscFormat.nOTClip;
                    }
                    else{
                        body_pr.textFit = new AscFormat.CTextFit();
                        body_pr.textFit.type = AscFormat.text_fit_Auto;
                        body_pr.wrap = AscFormat.nTWTSquare;
                       bNeedCheckExtents = true;
                    }
                }
                shape.txBody.setBodyPr(body_pr);
                if(bNeedCheckExtents){
                    var dOldX = shape.spPr.xfrm.offX;
                    var dOldY = shape.spPr.xfrm.offY;
                    shape.setParent(drawingObjects);
                    shape.recalculateContent();
                    shape.checkExtentsByDocContent(true, true);
                    shape.spPr.xfrm.setExtX(this.extX);
                    shape.spPr.xfrm.setOffX(dOldX);
                    shape.spPr.xfrm.setOffY(dOldY);
                }
            }
        }
        else
        {
            if(!shape.spPr.geometry){
                shape.spPr.setGeometry(AscFormat.CreateGeometry(this.presetGeom));
            }
            shape.setStyle(AscFormat.CreateDefaultShapeStyle(this.presetGeom));
            if(this.arrowsCount > 0)
            {
                var ln = new AscFormat.CLn();
                ln.setTailEnd(new AscFormat.EndArrow());
                ln.tailEnd.setType(AscFormat.LineEndType.Arrow);
                ln.tailEnd.setLen(AscFormat.LineEndSize.Mid);
                if(this.arrowsCount === 2)
                {
                    ln.setHeadEnd(new AscFormat.EndArrow());
                    ln.headEnd.setType(AscFormat.LineEndType.Arrow);
                    ln.headEnd.setLen(AscFormat.LineEndSize.Mid);
                }
                shape.spPr.setLn(ln);
            }
            var spDef = this.theme && this.theme.spDef;
            if(spDef)
            {
                if(spDef.style)
                {
                    shape.setStyle(spDef.style.createDuplicate());
                }
                if(spDef.spPr)
                {
                    if(spDef.spPr.Fill)
                    {
                        shape.spPr.setFill(spDef.spPr.Fill.createDuplicate());
                    }
                    if(spDef.spPr.ln)
                    {
                        if(shape.spPr.ln)
                        {
                            shape.spPr.ln.merge(spDef.spPr.ln);
                        }
                        else
                        {
                            shape.spPr.setLn(spDef.spPr.ln.createDuplicate());
                        }
                    }
                }
            }
        }
        shape.x = this.x;
        shape.y = this.y;
        return shape;
    };


    this.getBounds = function()
    {
        var boundsChecker = new  AscFormat.CSlideBoundsChecker();
        this.draw(boundsChecker);
        var tr = this.transform;
        var arr_p_x = [];
        var arr_p_y = [];
        arr_p_x.push(tr.TransformPointX(0,0));
        arr_p_y.push(tr.TransformPointY(0,0));
        arr_p_x.push(tr.TransformPointX(this.extX,0));
        arr_p_y.push(tr.TransformPointY(this.extX,0));
        arr_p_x.push(tr.TransformPointX(this.extX,this.extY));
        arr_p_y.push(tr.TransformPointY(this.extX,this.extY));
        arr_p_x.push(tr.TransformPointX(0,this.extY));
        arr_p_y.push(tr.TransformPointY(0,this.extY));

        arr_p_x.push(boundsChecker.Bounds.min_x);
        arr_p_x.push(boundsChecker.Bounds.max_x);
        arr_p_y.push(boundsChecker.Bounds.min_y);
        arr_p_y.push(boundsChecker.Bounds.max_y);

        boundsChecker.Bounds.min_x = Math.min.apply(Math, arr_p_x);
        boundsChecker.Bounds.max_x = Math.max.apply(Math, arr_p_x);
        boundsChecker.Bounds.min_y = Math.min.apply(Math, arr_p_y);
        boundsChecker.Bounds.max_y = Math.max.apply(Math, arr_p_y);
        boundsChecker.Bounds.posX = this.x;
        boundsChecker.Bounds.posY = this.y;
        boundsChecker.Bounds.extX = this.extX;
        boundsChecker.Bounds.extY = this.extY;
        return boundsChecker.Bounds;
    }
}
    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].SHAPE_ASPECTS = SHAPE_ASPECTS;
    window['AscFormat'].NewShapeTrack = NewShapeTrack;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

function PolyLine (drawingObjects, theme, master, layout, slide, pageIndex)
{

    AscFormat.ExecuteNoHistory(function(){

        this.drawingObjects = drawingObjects;
        this.arrPoint = [];
        this.Matrix = new AscCommon.CMatrixL();
        this.TransformMatrix = new AscCommon.CMatrixL();

        this.pageIndex = pageIndex;
        this.style  = AscFormat.CreateDefaultShapeStyle();
        var style = this.style;
        style.fillRef.Color.Calculate(theme, slide, layout, master, {R:0, G: 0, B:0, A:255});
        var RGBA = style.fillRef.Color.RGBA;
        var pen = theme.getLnStyle(style.lnRef.idx, style.lnRef.Color);
        style.lnRef.Color.Calculate(theme, slide, layout, master);
        RGBA = style.lnRef.Color.RGBA;

        if(pen.Fill)
        {
            pen.Fill.calculate(theme, slide, layout, master, RGBA);
        }

        this.pen = pen;

        this.polylineForDrawer = new PolylineForDrawer(this);

    }, this, []);

    this.Draw = function(graphics)
    {
        graphics.SetIntegerGrid(false);
        graphics.transform3(this.Matrix);

        var shape_drawer = new AscCommon.CShapeDrawer();
        shape_drawer.fromShape(this, graphics);
        shape_drawer.draw(this);
    };
    this.draw = function(g)
    {
        if(AscFormat.isRealNumber(this.pageIndex) && g.SetCurrentPage)
        {
            g.SetCurrentPage(this.pageIndex);
        }
        this.polylineForDrawer.Draw(g);
        return;
        if(this.arrPoint.length < 2)
        {
            return;
        }
        g._m(this.arrPoint[0].x, this.arrPoint[0].y);
        for(var i = 1; i < this.arrPoint.length; ++i)
        {
            g._l(this.arrPoint[i].x, this.arrPoint[i].y);
        }
        g.ds();
    };

    this.getBounds = function()
    {
        var boundsChecker = new  AscFormat.CSlideBoundsChecker();
        this.draw(boundsChecker);
        boundsChecker.Bounds.posX = boundsChecker.Bounds.min_x;
        boundsChecker.Bounds.posY = boundsChecker.Bounds.min_y;
        boundsChecker.Bounds.extX = boundsChecker.Bounds.max_x - boundsChecker.Bounds.min_x;
        boundsChecker.Bounds.extY = boundsChecker.Bounds.max_y - boundsChecker.Bounds.min_y;
        return boundsChecker.Bounds;
    };

    
    this.getShape =  function(bWord, drawingDocument, drawingObjects)
    {
        var xMax = this.arrPoint[0].x, yMax = this.arrPoint[0].y, xMin = xMax, yMin = yMax;
        var i;

        var bClosed = false;
        var min_dist;
        if(drawingObjects)
        {
            min_dist = drawingObjects.convertPixToMM(3);
        }
        else
        {
            min_dist = editor.WordControl.m_oDrawingDocument.GetMMPerDot(3)
        }
        if(this.arrPoint.length > 2)
        {
            var dx = this.arrPoint[0].x - this.arrPoint[this.arrPoint.length-1].x;
            var dy = this.arrPoint[0].y - this.arrPoint[this.arrPoint.length-1].y;
            if(Math.sqrt(dx*dx +dy*dy) < min_dist)
            {
                bClosed = true;
            }
        }
        var _n = bClosed ? this.arrPoint.length - 1 : this.arrPoint.length;
        for( i = 1; i<_n; ++i)
        {
            if(this.arrPoint[i].x > xMax)
            {
                xMax = this.arrPoint[i].x;
            }
            if(this.arrPoint[i].y > yMax)
            {
                yMax = this.arrPoint[i].y;
            }

            if(this.arrPoint[i].x < xMin)
            {
                xMin = this.arrPoint[i].x;
            }

            if(this.arrPoint[i].y < yMin)
            {
                yMin = this.arrPoint[i].y;
            }
        }




        var shape = new AscFormat.CShape();

     //  if(drawingObjects)
     //  {
     //      shape.setWorksheet(drawingObjects.getWorksheetModel());
     //      shape.addToDrawingObjects();
     //  }
        shape.setSpPr(new AscFormat.CSpPr());
        shape.spPr.setParent(shape);
        shape.spPr.setXfrm(new AscFormat.CXfrm());
        shape.spPr.xfrm.setParent(shape.spPr);
        if(!bWord)
        {
            shape.spPr.xfrm.setOffX(xMin);
            shape.spPr.xfrm.setOffY(yMin);
        }
        else
        {
            shape.setWordShape(true);
            shape.spPr.xfrm.setOffX(0);
            shape.spPr.xfrm.setOffY(0);
        }
        shape.spPr.xfrm.setExtX(xMax-xMin);
        shape.spPr.xfrm.setExtY(yMax - yMin);
        shape.setStyle(AscFormat.CreateDefaultShapeStyle());
        var geometry = new AscFormat.Geometry();


        var w = xMax - xMin, h = yMax-yMin;
        var kw, kh, pathW, pathH;
        if(w > 0)
        {
            pathW = 43200;
            kw = 43200/ w
        }
        else
        {
            pathW = 0;
            kw = 0;
        }
        if(h > 0)
        {
            pathH = 43200;
            kh = 43200 / h;
        }
        else
        {
            pathH = 0;
            kh = 0;
        }
        geometry.AddPathCommand(0, undefined, bClosed ? "norm": "none", undefined, pathW, pathH);
        geometry.AddRect("l", "t", "r", "b");
        geometry.AddPathCommand(1, (((this.arrPoint[0].x - xMin) * kw) >> 0) + "", (((this.arrPoint[0].y - yMin) * kh) >> 0) + "");
        for(i = 1;  i< _n; ++i)
        {
            geometry.AddPathCommand(2, (((this.arrPoint[i].x - xMin) * kw) >> 0) + "", (((this.arrPoint[i].y - yMin) * kh) >> 0) + "");
        }
        if(bClosed)
        {
            geometry.AddPathCommand(6);
        }

        shape.spPr.setGeometry(geometry);
        shape.setBDeleted(false);
        shape.recalculate();
        shape.x = xMin;
        shape.y = yMin;
        return shape;
    }
}

function PolylineForDrawer(polyline)
{
    this.polyline = polyline;
    this.pen = polyline.pen;
    this.brush = polyline.brush;
    this.TransformMatrix = polyline.TransformMatrix;
    this.Matrix = polyline.Matrix;

    this.Draw = function(graphics)
    {
        graphics.SetIntegerGrid(false);
        graphics.transform3(this.Matrix);

        var shape_drawer = new AscCommon.CShapeDrawer();
        shape_drawer.fromShape(this, graphics);
        shape_drawer.draw(this);
    };
    this.draw = function(g)
    {
        g._e();
        if(this.polyline.arrPoint.length < 2)
        {
            return;
        }
        g._m(this.polyline.arrPoint[0].x, this.polyline.arrPoint[0].y);
        for(var i = 1; i < this.polyline.arrPoint.length; ++i)
        {
            g._l(this.polyline.arrPoint[i].x, this.polyline.arrPoint[i].y);
        }
        g.ds();
    };
}

    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].PolyLine = PolyLine;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){
    // Import
    var global_MatrixTransformer = AscCommon.global_MatrixTransformer;

var TRANSLATE_HANDLE_NO_FLIP = [];
TRANSLATE_HANDLE_NO_FLIP[0] = 0;
TRANSLATE_HANDLE_NO_FLIP[1] = 1;
TRANSLATE_HANDLE_NO_FLIP[2] = 2;
TRANSLATE_HANDLE_NO_FLIP[3] = 3;
TRANSLATE_HANDLE_NO_FLIP[4] = 4;
TRANSLATE_HANDLE_NO_FLIP[5] = 5;
TRANSLATE_HANDLE_NO_FLIP[6] = 6;
TRANSLATE_HANDLE_NO_FLIP[7] = 7;

var TRANSLATE_HANDLE_FLIP_H = [];
TRANSLATE_HANDLE_FLIP_H[0] = 2;
TRANSLATE_HANDLE_FLIP_H[1] = 1;
TRANSLATE_HANDLE_FLIP_H[2] = 0;
TRANSLATE_HANDLE_FLIP_H[3] = 7;
TRANSLATE_HANDLE_FLIP_H[4] = 6;
TRANSLATE_HANDLE_FLIP_H[5] = 5;
TRANSLATE_HANDLE_FLIP_H[6] = 4;
TRANSLATE_HANDLE_FLIP_H[7] = 3;

var TRANSLATE_HANDLE_FLIP_V = [];
TRANSLATE_HANDLE_FLIP_V[0] = 6;
TRANSLATE_HANDLE_FLIP_V[1] = 5;
TRANSLATE_HANDLE_FLIP_V[2] = 4;
TRANSLATE_HANDLE_FLIP_V[3] = 3;
TRANSLATE_HANDLE_FLIP_V[4] = 2;
TRANSLATE_HANDLE_FLIP_V[5] = 1;
TRANSLATE_HANDLE_FLIP_V[6] = 0;
TRANSLATE_HANDLE_FLIP_V[7] = 7;

var TRANSLATE_HANDLE_FLIP_H_AND_FLIP_V = [];
TRANSLATE_HANDLE_FLIP_H_AND_FLIP_V[0] = 4;
TRANSLATE_HANDLE_FLIP_H_AND_FLIP_V[1] = 5;
TRANSLATE_HANDLE_FLIP_H_AND_FLIP_V[2] = 6;
TRANSLATE_HANDLE_FLIP_H_AND_FLIP_V[3] = 7;
TRANSLATE_HANDLE_FLIP_H_AND_FLIP_V[4] = 0;
TRANSLATE_HANDLE_FLIP_H_AND_FLIP_V[5] = 1;
TRANSLATE_HANDLE_FLIP_H_AND_FLIP_V[6] = 2;
TRANSLATE_HANDLE_FLIP_H_AND_FLIP_V[7] = 3;

var SHAPE_EXT = {};
SHAPE_EXT["can"] = 3616635/36000;
SHAPE_EXT["moon"] = 457200/36000;
SHAPE_EXT["leftBracket"] = 73152/36000;
SHAPE_EXT["rightBracket"] = 73152/36000;
SHAPE_EXT["leftBrace"] = 155448/36000;
SHAPE_EXT["rightBrace"] = 155448/36000;
SHAPE_EXT["triangle"] = 1060704/36000;
SHAPE_EXT["parallelogram"] = 1216152/36000;
SHAPE_EXT["trapezoid"] = 914400/36000;
SHAPE_EXT["pentagon"] = 960120/36000;
SHAPE_EXT["hexagon"] = 1060704/36000;
SHAPE_EXT["bracePair"] = 1069848/36000;
SHAPE_EXT["rightArrow"] = 978408/36000;
SHAPE_EXT["leftArrow"] = 978408/36000;
SHAPE_EXT["upArrow"] = 484632/36000;
SHAPE_EXT["downArrow"] = 484632/36000;
SHAPE_EXT["leftRightArrow"] = 1216152/36000;
SHAPE_EXT["upDownArrow"] = 484632/36000;
SHAPE_EXT["bentArrow"] = 813816/36000;
SHAPE_EXT["uturnArrow"] = 886968/36000;
SHAPE_EXT["bentUpArrow"] = 850392/36000;
SHAPE_EXT["curvedRightArrow"] = 731520/36000;
SHAPE_EXT["curvedLeftArrow"] = 731520/36000;
SHAPE_EXT["curvedUpArrow"] = 1216152/36000;
SHAPE_EXT["curvedDownArrow"] = 1216152/36000;
SHAPE_EXT["stripedRightArrow"] = 978408/36000;
SHAPE_EXT["notchedRightArrow"] = 978408/36000;
SHAPE_EXT["homePlate"] = 978408/36000;
SHAPE_EXT["leftRightArrowCallout"] = 1216152/36000;
SHAPE_EXT["flowChartProcess"] = 914400/36000;
SHAPE_EXT["flowChartAlternateProcess"] = 914400/36000;
SHAPE_EXT["flowChartDecision"] = 914400/36000;
SHAPE_EXT["flowChartInputOutput"] = 914400/36000;
SHAPE_EXT["flowChartPredefinedProcess"] = 914400/36000;
SHAPE_EXT["flowChartDocument"] = 914400/36000;
SHAPE_EXT["flowChartMultidocument"] = 1060704/36000;
SHAPE_EXT["flowChartTerminator"] = 914400/36000;
SHAPE_EXT["flowChartPreparation"] = 1060704/36000;
SHAPE_EXT["flowChartManualInput"] = 914400/36000;
SHAPE_EXT["flowChartManualOperation"] = 914400/36000;
SHAPE_EXT["flowChartPunchedCard"] = 914400/36000;
SHAPE_EXT["flowChartPunchedTape"] = 914400/36000;
SHAPE_EXT["flowChartPunchedTape"] = 457200/36000;
SHAPE_EXT["flowChartSort"] = 457200/36000;
SHAPE_EXT["flowChartOnlineStorage"] = 914400/36000;
SHAPE_EXT["flowChartMagneticDisk"] = 914400/36000;
SHAPE_EXT["flowChartMagneticDrum"] = 914400/36000;
SHAPE_EXT["flowChartDisplay"] = 914400/36000;
SHAPE_EXT["ribbon2"] = 1216152/36000;
SHAPE_EXT["ribbon"] = 1216152/36000;
SHAPE_EXT["ellipseRibbon2"] = 1216152/36000;
SHAPE_EXT["ellipseRibbon"] = 1216152/36000;
SHAPE_EXT["verticalScroll"] = 1033272/36000;
SHAPE_EXT["horizontalScroll"] = 1143000/36000;
SHAPE_EXT["wedgeRectCallout"] = 914400/36000;
SHAPE_EXT["wedgeRoundRectCallout"] = 914400/36000;
SHAPE_EXT["wedgeEllipseCallout"] = 914400/36000;
SHAPE_EXT["cloudCallout"] = 914400/36000;
SHAPE_EXT["borderCallout1"] = 914400/36000;
SHAPE_EXT["borderCallout2"] = 914400/36000;
SHAPE_EXT["borderCallout3"] = 914400/36000;
SHAPE_EXT["accentCallout1"] = 914400/36000;
SHAPE_EXT["accentCallout2"] = 914400/36000;
SHAPE_EXT["accentCallout3"] = 914400/36000;
SHAPE_EXT["callout1"] = 914400/36000;
SHAPE_EXT["callout2"] = 914400/36000;
SHAPE_EXT["callout3"] = 914400/36000;
SHAPE_EXT["accentBorderCallout1"] = 914400/36000;
SHAPE_EXT["accentBorderCallout2"] = 914400/36000;
SHAPE_EXT["accentBorderCallout3"] = 914400/36000;
SHAPE_EXT["cube"] = 1216152/36000;
SHAPE_EXT["bevel"] = 1042416/36000;
SHAPE_EXT["quadArrow"] = 1216152/36000;
SHAPE_EXT["leftUpArrow"] = 850392/36000;
SHAPE_EXT["chevron"] = 484632/36000;
SHAPE_EXT["quadArrowCallout"] = 1216152/36000;
SHAPE_EXT["circularArrow"] = 978408/36000;
SHAPE_EXT["flowChartInternalStorage"] = 612648/36000;
SHAPE_EXT["flowChartConnector"] = 457200/36000;
SHAPE_EXT["flowChartOffpageConnector"] = 612648/36000;
SHAPE_EXT["flowChartSummingJunction"] = 612648/36000;
SHAPE_EXT["flowChartOr"] = 612648/36000;
SHAPE_EXT["flowChartExtract"] = 685800/36000;
SHAPE_EXT["flowChartMerge"] = 685800/36000;
SHAPE_EXT["flowChartDelay"] = 612648/36000;
SHAPE_EXT["flowChartMagneticTape"] = 612648/36000;
SHAPE_EXT["actionButtonHome"] = 1042416/36000;

var MIN_SHAPE_SIZE = 1.27;//размер меньше которого нельзя уменшить автофигуру или картинку по горизонтали или вертикали

function CreatePenBrushForChartTrack()
{
    return AscFormat.ExecuteNoHistory(function()
        {
            var brush = new AscFormat.CUniFill();
            brush.setFill(new AscFormat.CSolidFill());
            brush.fill.setColor(new AscFormat.CUniColor());
            brush.fill.color.RGBA = {R:255, G:255, B:255, A:255};
            brush.fill.color.setColor(new AscFormat.CRGBColor());
            brush.fill.color.color.RGBA = {R:255, G:255, B:255, A:255};
            var pen = new AscFormat.CLn();
            pen.setFill(new AscFormat.CUniFill());
            pen.Fill.setFill(new AscFormat.CSolidFill());
            pen.Fill.fill.setColor(new AscFormat.CUniColor());
            pen.Fill.fill.color.setColor(new AscFormat.CRGBColor());
            return {brush: brush, pen: pen};
        },
        this, []);
}

function ResizeTrackShapeImage(originalObject, cardDirection, drawingsController)
{
    AscFormat.ExecuteNoHistory(function()
    {
        this.bLastCenter = false;
        this.bIsTracked = false;
        this.originalObject = originalObject;
        this.numberHandle = originalObject.getNumByCardDirection(cardDirection);
        this.lastSpPr = null;
        this.startShape = null;
        this.endShape = null;

        this.beginShapeId = null;
        this.beginShapeIdx = null;

        this.endShapeId = null;
        this.endShapeIdx = null;
        if(drawingsController && drawingsController.selectedObjects.length === 1){
            if(originalObject.getObjectType() === AscDFH.historyitem_type_Cnx){
                this.drawingsController = drawingsController;
                var stId = originalObject.nvSpPr.nvUniSpPr.stCnxId;
                var endId = originalObject.nvSpPr.nvUniSpPr.endCnxId;
                this.startShape  = AscCommon.g_oTableId.Get_ById(stId);
                this.endShape = AscCommon.g_oTableId.Get_ById(endId);
                this.bConnector = true;
               // if(this.startShape || this.endShape){
               //     this.bConnector = true;
               // }
            }
        }

        this.pageIndex = null;
        var numberHandle = this.numberHandle;
        this.flipH = originalObject.flipH;
        this.flipV = originalObject.flipV;
        var _flip_h = originalObject.flipH;
        var _flip_v = originalObject.flipV;
        var _half_height = originalObject.extY*0.5;
        var _half_width = originalObject.extX*0.5;

        var _sin = Math.sin(originalObject.rot);
        var _cos = Math.cos(originalObject.rot);

        var _translated_num_handle;

        if(!_flip_h && !_flip_v)
        {
            _translated_num_handle = numberHandle;
        }
        else if(_flip_h && !_flip_v)
        {
            _translated_num_handle = TRANSLATE_HANDLE_FLIP_H[numberHandle];
        }
        else if(!_flip_h && _flip_v)
        {
            _translated_num_handle = TRANSLATE_HANDLE_FLIP_V[numberHandle];
        }
        else
        {
            _translated_num_handle = TRANSLATE_HANDLE_FLIP_H_AND_FLIP_V[numberHandle];
        }

        this.bAspect = numberHandle % 2 === 0;
        this.aspect = this.bAspect === true ? this.originalObject.getAspect(_translated_num_handle) : 0;

        this.sin = _sin;
        this.cos = _cos;
        this.translatetNumberHandle = _translated_num_handle;

        switch (_translated_num_handle)
        {
            case 0:
            case 1:
            {
                this.fixedPointX = (_half_width*_cos - _half_height*_sin) + _half_width + originalObject.x;
                this.fixedPointY = (_half_width*_sin + _half_height*_cos) + _half_height + originalObject.y;
                break;
            }
            case 2:
            case 3:
            {
                this.fixedPointX = (-_half_width*_cos - _half_height*_sin) + _half_width + originalObject.x;
                this.fixedPointY = (-_half_width*_sin + _half_height*_cos) + _half_height + originalObject.y;
                break;
            }
            case 4:
            case 5:
            {
                this.fixedPointX = (-_half_width*_cos + _half_height*_sin) + _half_width + originalObject.x;
                this.fixedPointY = (-_half_width*_sin - _half_height*_cos) + _half_height + originalObject.y;
                break;
            }
            case 6:
            case 7:
            {
                this.fixedPointX = (_half_width*_cos + _half_height*_sin) + _half_width + originalObject.x;
                this.fixedPointY = (_half_width*_sin - _half_height*_cos) + _half_height + originalObject.y;
                break;
            }
        }

        this.mod = this.translatetNumberHandle % 4;
        this.centerPointX = originalObject.x + _half_width;
        this.centerPointY = originalObject.y + _half_height;

        //this.lineFlag = originalObject.checkLine();

        this.originalExtX = originalObject.extX;
        this.originalExtY = originalObject.extY;
        this.originalFlipH = _flip_h;
        this.originalFlipV = _flip_v;

        this.usedExtX =  this.originalExtX === 0 ? (/*this.lineFlag ? this.originalExtX :*/ 0.01) : this.originalExtX;
        this.usedExtY =  this.originalExtY === 0 ? (/*this.lineFlag ? this.originalExtY :*/ 0.01) : this.originalExtY;

        this.resizedExtX = this.originalExtX;
        this.resizedExtY = this.originalExtY;
        this.resizedflipH = _flip_h;
        this.resizedflipV = _flip_v;
        this.resizedPosX = originalObject.x;
        this.resizedPosY = originalObject.y;
        this.resizedRot = originalObject.rot;

        this.transform = originalObject.transform.CreateDublicate();
        this.geometry = AscFormat.ExecuteNoHistory(function(){ return originalObject.getGeom().createDuplicate();}, this, []);

        if(!originalObject.isChart())
        {
            if(originalObject.blipFill)
            {
                this.brush = new AscFormat.CUniFill();
                this.brush.fill = originalObject.blipFill;
            }
            else
            {
                this.brush = originalObject.brush;
            }
            this.pen = originalObject.pen;
        }
        else
        {
            var pen_brush = CreatePenBrushForChartTrack();
            this.brush = pen_brush.brush;
            this.pen = pen_brush.pen;
        }


        this.isLine = originalObject.spPr && originalObject.spPr.geometry && originalObject.spPr.geometry.preset === "line";
        this.bChangeCoef = this.translatetNumberHandle % 2 === 0 && this.originalFlipH !== this.originalFlipV;

        this.overlayObject = new AscFormat.OverlayObject(this.geometry, this.resizedExtX, this.resizedExtY, this.brush, this.pen, this.transform);


        this.resizeConnector = function(kd1, kd2, e, x, y){

            var oConnectorInfo = this.originalObject.nvSpPr.nvUniSpPr;
            var oBeginShape =  AscCommon.g_oTableId.Get_ById(oConnectorInfo.stCnxId);
            if(oBeginShape && oBeginShape.bDeleted){
                oBeginShape = null;
            }
            var oEndShape = AscCommon.g_oTableId.Get_ById(oConnectorInfo.endCnxId);
            if(oEndShape && oEndShape.bDeleted){
                oEndShape = null;
            }
            var aDrawings = [];
            this.drawingsController.getAllSingularDrawings(this.drawingsController.getDrawingArray(), aDrawings);
            var oConnectionInfo = null;
            var oNewShape = null;
            this.oNewShape = null;
            this.beginShapeId = null;
            this.beginShapeIdx = null;

            this.endShapeId = null;
            this.endShapeIdx = null;
            for(var i = aDrawings.length-1; i > -1; --i) {
                if(aDrawings[i] === this.originalObject){
                    continue;
                }
                oConnectionInfo = aDrawings[i].findConnector(x, y);
                if (oConnectionInfo) {
                    oNewShape = aDrawings[i];
                    this.oNewShape = oNewShape;
                    break;
                }
            }
            if(!this.oNewShape){
                for(var i = aDrawings.length - 1; i > -1; --i){
                    if(aDrawings[i] === this.originalObject){
                        continue;
                    }
                    var oCs = aDrawings[i].findConnectionShape(x, y);
                    if(oCs ){
                        this.oNewShape = oCs;
                        break;
                    }
                }
            }

            var _beginConnectionInfo, _endConnectionInfo;
            if(this.numberHandle === 0){
                if(oEndShape){
                    var oConectionObject = oEndShape.getGeom().cnxLst[oConnectorInfo.endCnxIdx];
                    var g_conn_info =  {idx: oConnectorInfo.endCnxIdx, ang: oConectionObject.ang, x: oConectionObject.x, y: oConectionObject.y};
                    var _flipH = oEndShape.flipH;
                    var _flipV = oEndShape.flipV;
                    var _rot   = oEndShape.rot;

                    if(oEndShape.group){
                        _rot = AscFormat.normalizeRotate(oEndShape.group.getFullRotate() + _rot);
                        if(oEndShape.group.getFullFlipH()){
                            _flipH = !_flipH;
                        }
                        if(oEndShape.group.getFullFlipV()){
                            _flipV = !_flipV;
                        }
                    }
                    _endConnectionInfo = oEndShape.convertToConnectionParams(_rot, _flipH, _flipV, oEndShape.transform, oEndShape.bounds, g_conn_info);
                }
                _beginConnectionInfo = oConnectionInfo;
                if(_beginConnectionInfo){
                    this.beginShapeId = this.oNewShape.Id;
                    this.beginShapeIdx = _beginConnectionInfo.idx;
                }
            }
            else{
                if(oBeginShape){
                    var oConectionObject = oBeginShape.getGeom().cnxLst[oConnectorInfo.stCnxIdx];
                    var g_conn_info =  {idx: oConnectorInfo.stCnxIdx, ang: oConectionObject.ang, x: oConectionObject.x, y: oConectionObject.y};
                    var _flipH = oBeginShape.flipH;
                    var _flipV = oBeginShape.flipV;
                    var _rot   = oBeginShape.rot;
                    if(oBeginShape.group){
                        _rot = AscFormat.normalizeRotate(oBeginShape.group.getFullRotate() + _rot);
                        if(oBeginShape.group.getFullFlipH()){
                            _flipH = !_flipH;
                        }
                        if(oBeginShape.group.getFullFlipV()){
                            _flipV = !_flipV;
                        }
                    }
                    _beginConnectionInfo = oBeginShape.convertToConnectionParams(_rot, _flipH, _flipV, oBeginShape.transform, oBeginShape.bounds, g_conn_info);
                }
                _endConnectionInfo = oConnectionInfo;

                if(_endConnectionInfo){
                    this.endShapeId = this.oNewShape.Id;
                    this.endShapeIdx = _endConnectionInfo.idx;
                }
            }
            var _x, _y;
            if(_beginConnectionInfo || _endConnectionInfo){

                if(!_beginConnectionInfo){
                    if(this.numberHandle === 0){
                        _beginConnectionInfo = AscFormat.fCalculateConnectionInfo(_endConnectionInfo, x, y);
                    }
                    else{
                        _x = this.originalObject.transform.TransformPointX(0, 0);
                        _y = this.originalObject.transform.TransformPointY(0, 0);
                        _beginConnectionInfo = AscFormat.fCalculateConnectionInfo(_endConnectionInfo, _x, _y);
                    }
                }
                if(!_endConnectionInfo){
                    if(this.numberHandle === 0){
                        _x = this.originalObject.transform.TransformPointX(this.originalObject.extX, this.originalObject.extY);
                        _y = this.originalObject.transform.TransformPointY(this.originalObject.extX, this.originalObject.extY);
                        _endConnectionInfo = AscFormat.fCalculateConnectionInfo(_beginConnectionInfo, _x, _y);

                    }
                    else{
                        _endConnectionInfo = AscFormat.fCalculateConnectionInfo(_beginConnectionInfo, x, y);
                    }
                }
            }

            if(_beginConnectionInfo && _endConnectionInfo){
                this.oSpPr = AscFormat.fCalculateSpPr(_beginConnectionInfo, _endConnectionInfo, this.originalObject.spPr.geometry.preset, this.overlayObject.pen.w);

                if(this.originalObject.group){
                    var _xc = this.oSpPr.xfrm.offX + this.oSpPr.xfrm.extX / 2.0;
                    var _yc = this.oSpPr.xfrm.offY + this.oSpPr.xfrm.extY / 2.0;
                    var xc = this.originalObject.group.invertTransform.TransformPointX(_xc, _yc);
                    var yc = this.originalObject.group.invertTransform.TransformPointY(_xc, _yc);
                    this.oSpPr.xfrm.setOffX(xc - this.oSpPr.xfrm.extX / 2.0);
                    this.oSpPr.xfrm.setOffY(yc - this.oSpPr.xfrm.extY / 2.0);
                    this.oSpPr.xfrm.setFlipH(this.originalObject.group.getFullFlipH() ? !this.oSpPr.xfrm.flipH : this.oSpPr.xfrm.flipH);
                    this.oSpPr.xfrm.setFlipV(this.originalObject.group.getFullFlipV() ? !this.oSpPr.xfrm.flipV : this.oSpPr.xfrm.flipV);
                    this.oSpPr.xfrm.setRot(AscFormat.normalizeRotate(this.oSpPr.xfrm.rot - this.originalObject.group.getFullRotate()));
                }

                var _xfrm = this.oSpPr.xfrm;
                this.resizedExtX = _xfrm.extX;
                this.resizedExtY = _xfrm.extY;
                this.resizedflipH = _xfrm.flipH;
                this.resizedflipV = _xfrm.flipV;
                this.resizedPosX = _xfrm.offX;
                this.resizedPosY = _xfrm.offY;
                this.resizedRot = _xfrm.rot;
                this.recalculateTransform();
                this.geometry = this.oSpPr.geometry;
                this.overlayObject.geometry = this.geometry;
                this.geometry.Recalculate(this.oSpPr.xfrm.extX, this.oSpPr.xfrm.extY);

            }
            else{
                this.oSpPr = null;
                this.resizedRot = this.originalObject.rot;
                this.geometry = AscFormat.ExecuteNoHistory(function(){
                    return originalObject.spPr.geometry.createDuplicate();
                }, this, []);
                this.overlayObject.geometry = this.geometry;
                this.resize(kd1, kd2, e.ShiftKey);
            }
        };

        this.track = function(kd1, kd2, e, x, y){
            AscFormat.ExecuteNoHistory(function () {
                this.bIsTracked = true;
                if(this.bConnector){
                    this.resizeConnector(kd1, kd2, e, x, y);
                }
                else if(!e.CtrlKey){
                    this.resize(kd1, kd2, e.ShiftKey);
                }
                else{
                    this.resizeRelativeCenter(kd1, kd2, e.ShiftKey)
                }
            }, this, []);
        };

        this.resize = function(kd1, kd2, ShiftKey)
        {
            this.bLastCenter = false;
            var _cos = this.cos;
            var _sin = this.sin;

            var _real_height, _real_width;
            var _abs_height, _abs_width;
            var _new_resize_half_width;
            var _new_resize_half_height;
            var _new_used_half_width;
            var _new_used_half_height;
            var _temp;

           if(this.originalObject.getObjectType && this.originalObject.getObjectType() === AscDFH.historyitem_type_GraphicFrame){
               if(kd1 < 0){
                   kd1 = 0;
               }
               if(kd2 < 0){
                   kd2 = 0;
               }
           }

            if((ShiftKey === true || window.AscAlwaysSaveAspectOnResizeTrack === true || this.originalObject.getNoChangeAspect()) && this.bAspect === true)
            {
                var _new_aspect = this.aspect*(Math.abs(kd1/ kd2));

                if (_new_aspect >= this.aspect)
                    kd2 = Math.abs(kd1)*(kd2 >= 0 ? 1 : -1 );
                else
                    kd1 = Math.abs(kd2)*(kd1 >= 0 ? 1 : -1);
            }

            if(this.bChangeCoef)
            {
                _temp = kd1;
                kd1 = kd2;
                kd2 = _temp;
            }
            switch (this.translatetNumberHandle)
            {
                case 0:
                case 1:
                {
                    if(this.translatetNumberHandle === 0)
                    {
                        _real_width = this.usedExtX*kd1;
                        _abs_width = Math.abs(_real_width);
                        if(!this.isLine)
                        {
                            this.resizedExtX = _abs_width >= MIN_SHAPE_SIZE  ? _abs_width : MIN_SHAPE_SIZE;
                        }
                        else
                        {
                            this.resizedExtX = _abs_width >= MIN_SHAPE_SIZE  ? _abs_width : 0;
                        }
                        if(_real_width < 0 )
                        {
                            this.resizedflipH = !this.originalFlipH;
                        }
                        else
                            this.resizedflipH = this.originalFlipH;
                    }
                    if(this.translatetNumberHandle === 1)
                    {
                        _temp = kd1;
                        kd1 = kd2;
                        kd2 = _temp;
                    }

                    _real_height = this.usedExtY*kd2;
                    _abs_height = Math.abs(_real_height);

                    if(!this.isLine)
                    {
                        this.resizedExtY = _abs_height >= MIN_SHAPE_SIZE  ? _abs_height : MIN_SHAPE_SIZE;
                    }
                    else
                    {
                        this.resizedExtY = _abs_height >= MIN_SHAPE_SIZE  ? _abs_height : 0;
                    }

                    this.resizedExtY = _abs_height >= MIN_SHAPE_SIZE  || this.isLine  ? _abs_height : MIN_SHAPE_SIZE;
                    if(_real_height < 0 )
                    {
                        this.resizedflipV = !this.originalFlipV;
                        if(this.isLine && ShiftKey)
                        {
                            this.resizedflipH = !this.originalFlipH;
                        }
                    }
                    else
                    {
                        this.resizedflipV = this.originalFlipV;
                        if(this.isLine && ShiftKey && this.resizedflipH !== this.originalFlipH)
                        {
                            this.resizedflipV = !this.originalFlipV;
                        }
                    }


                    _new_resize_half_width = this.resizedExtX*0.5;
                    _new_resize_half_height = this.resizedExtY*0.5;
                    if(this.resizedflipH !== this.originalFlipH)
                    {
                        _new_used_half_width = -_new_resize_half_width;
                    }
                    else
                    {
                        _new_used_half_width = _new_resize_half_width;
                    }

                    if(this.resizedflipV !== this.originalFlipV)
                    {
                        _new_used_half_height = -_new_resize_half_height;
                    }
                    else
                    {
                        _new_used_half_height = _new_resize_half_height;
                    }

                    this.resizedPosX = this.fixedPointX + (-_new_used_half_width*_cos + _new_used_half_height*_sin) - _new_resize_half_width;
                    this.resizedPosY = this.fixedPointY + (-_new_used_half_width*_sin - _new_used_half_height*_cos) - _new_resize_half_height;
                    break;
                }
                case 2:
                case 3:
                {
                    if(this.translatetNumberHandle === 2)
                    {
                        _temp = kd2;
                        kd2 = kd1;
                        kd1 = _temp;
                        _real_height = this.usedExtY*kd2;
                        _abs_height = Math.abs(_real_height);
                        this.resizedExtY = _abs_height >= MIN_SHAPE_SIZE  ? _abs_height : (this.isLine ? 0 : MIN_SHAPE_SIZE);
                        if(_real_height < 0 )
                            this.resizedflipV = !this.originalFlipV;
                        else
                            this.resizedflipV = this.originalFlipV;
                    }

                    _real_width = this.usedExtX*kd1;
                    _abs_width = Math.abs(_real_width);
                    this.resizedExtX = _abs_width >= MIN_SHAPE_SIZE  ? _abs_width : (this.isLine ? 0 : MIN_SHAPE_SIZE);
                    if(_real_width < 0 )
                    {
                        this.resizedflipH = !this.originalFlipH;
                        if(this.isLine && ShiftKey)
                        {
                            this.resizedflipV = !this.originalFlipV;
                        }
                    }
                    else
                    {
                        this.resizedflipH = this.originalFlipH;
                        if(this.isLine && ShiftKey && this.resizedflipV !== this.originalFlipV)
                        {
                            this.resizedflipH = !this.originalFlipH;
                        }
                    }


                    _new_resize_half_width = this.resizedExtX*0.5;
                    _new_resize_half_height = this.resizedExtY*0.5;
                    if(this.resizedflipH !== this.originalFlipH)
                    {
                        _new_used_half_width = -_new_resize_half_width;
                    }

                    else
                    {
                        _new_used_half_width = _new_resize_half_width;
                    }

                    if(this.resizedflipV !== this.originalFlipV)
                    {
                        _new_used_half_height = -_new_resize_half_height;
                    }
                    else
                    {
                        _new_used_half_height = _new_resize_half_height;
                    }

                    this.resizedPosX = this.fixedPointX + (_new_used_half_width*_cos + _new_used_half_height*_sin) - _new_resize_half_width;
                    this.resizedPosY = this.fixedPointY + (_new_used_half_width*_sin - _new_used_half_height*_cos) - _new_resize_half_height;
                    break;
                }

                case 4:
                case 5:
                {
                    if(this.translatetNumberHandle === 4)
                    {
                        _real_width = this.usedExtX*kd1;
                        _abs_width = Math.abs(_real_width);
                        this.resizedExtX = _abs_width >= MIN_SHAPE_SIZE   ? _abs_width : (this.isLine ? 0 :MIN_SHAPE_SIZE);
                        if(_real_width < 0 )
                            this.resizedflipH = !this.originalFlipH;
                        else
                            this.resizedflipH = this.originalFlipH;
                    }
                    else
                    {
                        _temp = kd2;
                        kd2 = kd1;
                        kd1 = _temp;
                    }

                    _real_height = this.usedExtY*kd2;
                    _abs_height = Math.abs(_real_height);
                    this.resizedExtY = _abs_height >= MIN_SHAPE_SIZE  ? _abs_height :  (this.isLine ? 0 : MIN_SHAPE_SIZE);
                    if(_real_height < 0 )
                    {
                        this.resizedflipV = !this.originalFlipV;
                        if(this.isLine && ShiftKey)
                        {
                            this.resizedflipH = !this.originalFlipH;
                        }
                    }
                    else
                    {
                        this.resizedflipV = this.originalFlipV;
                        if(this.isLine && ShiftKey && this.resizedflipH !== this.originalFlipH)
                        {
                            this.resizedflipV = !this.originalFlipV;
                        }
                    }

                    _new_resize_half_width = this.resizedExtX*0.5;
                    _new_resize_half_height = this.resizedExtY*0.5;
                    if(this.resizedflipH !== this.originalFlipH)
                    {
                        _new_used_half_width = -_new_resize_half_width;
                    }
                    else
                    {
                        _new_used_half_width = _new_resize_half_width;
                    }

                    if(this.resizedflipV !== this.originalFlipV)
                    {
                        _new_used_half_height = -_new_resize_half_height;
                    }
                    else
                    {
                        _new_used_half_height = _new_resize_half_height;
                    }

                    this.resizedPosX = this.fixedPointX + (_new_used_half_width*_cos - _new_used_half_height*_sin) - _new_resize_half_width;
                    this.resizedPosY = this.fixedPointY + (_new_used_half_width*_sin + _new_used_half_height*_cos) - _new_resize_half_height;

                    break;
                }

                case 6:
                case 7:
                {
                    if(this.translatetNumberHandle === 6)
                    {
                        _real_height = this.usedExtY*kd1;
                        _abs_height = Math.abs(_real_height);
                        this.resizedExtY = _abs_height >= MIN_SHAPE_SIZE   ? _abs_height : (this.isLine ? 0 : MIN_SHAPE_SIZE);
                        if(_real_height < 0 )
                            this.resizedflipV = !this.originalFlipV;
                        else
                            this.resizedflipV = this.originalFlipV;
                    }
                    else
                    {
                        _temp = kd2;
                        kd2 = kd1;
                        kd1 = _temp;
                    }

                    _real_width = this.usedExtX*kd2;
                    _abs_width = Math.abs(_real_width);
                    this.resizedExtX = _abs_width >= MIN_SHAPE_SIZE   ? _abs_width : (this.isLine ? 0 : MIN_SHAPE_SIZE);
                    if(_real_width < 0 )
                    {
                        this.resizedflipH = !this.originalFlipH;
                        if(this.isLine && ShiftKey)
                        {
                            this.resizedflipV = !this.originalFlipV;
                        }
                    }
                    else
                    {
                        this.resizedflipH = this.originalFlipH;
                        if(this.isLine && ShiftKey && this.resizedflipV !== this.originalFlipV)
                        {
                            this.resizedflipH = !this.originalFlipH;
                        }
                    }

                    _new_resize_half_width = this.resizedExtX*0.5;
                    _new_resize_half_height = this.resizedExtY*0.5;
                    if(this.resizedflipH !== this.originalFlipH)
                    {
                        _new_used_half_width = -_new_resize_half_width;
                    }
                    else
                    {
                        _new_used_half_width = _new_resize_half_width;
                    }

                    if(this.resizedflipV !== this.originalFlipV)
                    {
                        _new_used_half_height = -_new_resize_half_height;
                    }
                    else
                    {
                        _new_used_half_height = _new_resize_half_height;
                    }

                    this.resizedPosX = this.fixedPointX + (-_new_used_half_width*_cos - _new_used_half_height*_sin) - _new_resize_half_width;
                    this.resizedPosY = this.fixedPointY + (-_new_used_half_width*_sin + _new_used_half_height*_cos) - _new_resize_half_height;
                    break;
                }
            }

            this.geometry.Recalculate(this.resizedExtX, this.resizedExtY);
            this.overlayObject.updateExtents(this.resizedExtX, this.resizedExtY);

            this.recalculateTransform();

            if(this.bConnector){
                if(this.numberHandle === 0){
                    this.beginShapeIdx = null;
                    this.beginShapeId = null;
                }
                else{
                    this.endShapeIdx = null;
                    this.endShapeId = null;
                }
            }
        };

        this.resizeRelativeCenter = function(kd1, kd2, ShiftKey)
        {
            if(this.isLine)
            {
                this.resize(kd1, kd2, ShiftKey);
                return;
            }
            this.bLastCenter = true;
            kd1 = 2*kd1 - 1;
            kd2 = 2*kd2 - 1;

            if(this.originalObject.getObjectType && this.originalObject.getObjectType() === AscDFH.historyitem_type_GraphicFrame){
                if(kd1 < 0){
                    kd1 = 0;
                }
                if(kd2 < 0){
                    kd2 = 0;
                }
            }
            var _real_height, _real_width;
            var _abs_height, _abs_width;

            if((ShiftKey === true || window.AscAlwaysSaveAspectOnResizeTrack === true || this.originalObject.getNoChangeAspect()) && this.bAspect === true)
            {
                var _new_aspect = this.aspect*(Math.abs(kd1/ kd2));

                if (_new_aspect >= this.aspect)
                    kd2 = Math.abs(kd1)*(kd2 >= 0 ? 1 : -1 );
                else
                    kd1 = Math.abs(kd2)*(kd1 >= 0 ? 1 : -1);
            }

            var _temp;
            if(this.bChangeCoef)
            {
                _temp = kd1;
                kd1 = kd2;
                kd2 = _temp;
            }
            if(this.mod === 0 || this.mod === 1)
            {
                if(this.mod === 0)
                {
                    _real_width = this.usedExtX*kd1;
                    _abs_width = Math.abs(_real_width);
                    this.resizedExtX = _abs_width >= MIN_SHAPE_SIZE  || this.isLine ? _abs_width : MIN_SHAPE_SIZE;
                    this.resizedflipH  = _real_width < 0 ? !this.originalFlipH : this.originalFlipH;

                }
                else
                {
                    _temp = kd1;
                    kd1 = kd2;
                    kd2 = _temp;
                }

                _real_height = this.usedExtY*kd2;
                _abs_height = Math.abs(_real_height);
                this.resizedExtY = _abs_height >= MIN_SHAPE_SIZE  || this.isLine ? _abs_height : MIN_SHAPE_SIZE;
                this.resizedflipV  = _real_height < 0 ? !this.originalFlipV : this.originalFlipV;


            }
            else
            {
                if(this.mod === 2)
                {
                    _temp = kd1;
                    kd1 = kd2;
                    kd2 = _temp;

                    _real_height = this.usedExtY*kd2;
                    _abs_height = Math.abs(_real_height);
                    this.resizedExtY = _abs_height >= MIN_SHAPE_SIZE  || this.isLine ? _abs_height : MIN_SHAPE_SIZE;
                    this.resizedflipV  = _real_height < 0 ? !this.originalFlipV : this.originalFlipV;

                }
                _real_width = this.usedExtX*kd1;
                _abs_width = Math.abs(_real_width);
                this.resizedExtX = _abs_width >= MIN_SHAPE_SIZE  || this.isLine ? _abs_width : MIN_SHAPE_SIZE;
                this.resizedflipH  = _real_width < 0 ? !this.originalFlipH : this.originalFlipH;

            }

            this.resizedPosX = this.centerPointX - this.resizedExtX*0.5;
            this.resizedPosY = this.centerPointY - this.resizedExtY*0.5;

            this.geometry.Recalculate(this.resizedExtX, this.resizedExtY);
            this.overlayObject.updateExtents(this.resizedExtX, this.resizedExtY);

            this.recalculateTransform();
        };

        this.recalculateTransform = function(){
            var _transform = this.transform;
            _transform.Reset();

            var _horizontal_center = this.resizedExtX*0.5;
            var _vertical_center = this.resizedExtY*0.5;
            global_MatrixTransformer.TranslateAppend(_transform, -_horizontal_center, -_vertical_center);

            if(this.resizedflipH)
            {
                global_MatrixTransformer.ScaleAppend(_transform, -1, 1);
            }
            if(this.resizedflipV)
            {
                global_MatrixTransformer.ScaleAppend(_transform, 1, -1);
            }

            global_MatrixTransformer.RotateRadAppend(_transform, -this.resizedRot);


            global_MatrixTransformer.TranslateAppend(_transform, this.resizedPosX, this.resizedPosY);
            global_MatrixTransformer.TranslateAppend(_transform, _horizontal_center, _vertical_center);
            if(this.originalObject.group)
            {
                global_MatrixTransformer.MultiplyAppend(_transform, this.originalObject.group.transform);
            }

            if(this.originalObject.parent)
            {
                var parent_transform = this.originalObject.parent.Get_ParentTextTransform && this.originalObject.parent.Get_ParentTextTransform();
                if(parent_transform)
                {
                    global_MatrixTransformer.MultiplyAppend(_transform, parent_transform);
                }

            }
        };

        this.draw = function(overlay, transform)
        {
            if(AscFormat.isRealNumber(this.originalObject.selectStartPage) && overlay.SetCurrentPage)
            {
                overlay.SetCurrentPage(this.originalObject.selectStartPage);
            }

            if(this.oNewShape){
                this.oNewShape.drawConnectors(overlay);
            }
            this.overlayObject.draw(overlay, transform);
        };

        this.getBounds = function()
        {
            var boundsChecker = new  AscFormat.CSlideBoundsChecker();
            var tr = null;
            if(this.originalObject && this.originalObject.parent)
            {
                var parent_transform = this.originalObject.parent.Get_ParentTextTransform && this.originalObject.parent.Get_ParentTextTransform();
                if(parent_transform)
                {
                    tr = this.transform.CreateDublicate();
                    global_MatrixTransformer.MultiplyAppend(tr, global_MatrixTransformer.Invert(parent_transform));
                }

            }
            this.draw(boundsChecker, tr ? tr : null);
            tr = this.transform;
            var arr_p_x = [];
            var arr_p_y = [];
            arr_p_x.push(tr.TransformPointX(0,0));
            arr_p_y.push(tr.TransformPointY(0,0));
            arr_p_x.push(tr.TransformPointX(this.resizedExtX,0));
            arr_p_y.push(tr.TransformPointY(this.resizedExtX,0));
            arr_p_x.push(tr.TransformPointX(this.resizedExtX,this.resizedExtY));
            arr_p_y.push(tr.TransformPointY(this.resizedExtX,this.resizedExtY));
            arr_p_x.push(tr.TransformPointX(0,this.resizedExtY));
            arr_p_y.push(tr.TransformPointY(0,this.resizedExtY));

            arr_p_x.push(boundsChecker.Bounds.min_x);
            arr_p_x.push(boundsChecker.Bounds.max_x);
            arr_p_y.push(boundsChecker.Bounds.min_y);
            arr_p_y.push(boundsChecker.Bounds.max_y);

            boundsChecker.Bounds.min_x = Math.min.apply(Math, arr_p_x);
            boundsChecker.Bounds.max_x = Math.max.apply(Math, arr_p_x);
            boundsChecker.Bounds.min_y = Math.min.apply(Math, arr_p_y);
            boundsChecker.Bounds.max_y = Math.max.apply(Math, arr_p_y);

            boundsChecker.Bounds.posX = this.resizedPosX;
            boundsChecker.Bounds.posY = this.resizedPosY;
            boundsChecker.Bounds.extX = this.resizedExtX;
            boundsChecker.Bounds.extY = this.resizedExtY;
            return boundsChecker.Bounds;
        };


        this.trackEnd = function(bWord)
        {
            if(!this.bIsTracked){
                return;
            }
            if(!this.bConnector || !this.oSpPr){
                var scale_coefficients, ch_off_x, ch_off_y;
                if(this.originalObject.group)
                {
                    scale_coefficients = this.originalObject.group.getResultScaleCoefficients();
                    ch_off_x = this.originalObject.group.spPr.xfrm.chOffX;
                    ch_off_y = this.originalObject.group.spPr.xfrm.chOffY;
                }
                else
                {
                    scale_coefficients = {cx: 1, cy: 1};
                    ch_off_x = 0;
                    ch_off_y = 0;
                    if(bWord)
                    {
                        this.resizedPosX = 0;
                        this.resizedPosY = 0;
                    }
                }
                AscFormat.CheckSpPrXfrm(this.originalObject);
                var xfrm = this.originalObject.spPr.xfrm;

                if(this.originalObject.getObjectType() !== AscDFH.historyitem_type_GraphicFrame)
                {
                    xfrm.setOffX(this.resizedPosX/scale_coefficients.cx + ch_off_x);
                    xfrm.setOffY(this.resizedPosY/scale_coefficients.cy + ch_off_y);
                    xfrm.setExtX(this.resizedExtX/scale_coefficients.cx);
                    xfrm.setExtY(this.resizedExtY/scale_coefficients.cy);
                }
                else
                {
                    var oldX = xfrm.offX;
                    var oldY = xfrm.offY;
                    var newX = this.resizedPosX/scale_coefficients.cx + ch_off_x;
                    var newY = this.resizedPosY/scale_coefficients.cy + ch_off_y;
                    this.originalObject.graphicObject.Resize(this.resizedExtX, this.resizedExtY);
                    this.originalObject.recalculateTable();
                    this.originalObject.recalculateSizes();
                    if(!this.bLastCenter){
                        if(!AscFormat.fApproxEqual(oldX, newX, 0.5)){
                            xfrm.setOffX(this.resizedPosX/scale_coefficients.cx + ch_off_x - this.originalObject.extX + this.resizedExtX);
                        }
                        if(!AscFormat.fApproxEqual(oldY, newY, 0.5)){
                            xfrm.setOffY(this.resizedPosY/scale_coefficients.cy + ch_off_y - this.originalObject.extY + this.resizedExtY);
                        }
                    }
                    else{
                        xfrm.setOffX(this.resizedPosX + this.resizedExtX/2.0  - this.originalObject.extX/2);
                        xfrm.setOffY(this.resizedPosY + this.resizedExtY/2.0  - this.originalObject.extY/2);
                    }
                }
                if(this.originalObject.getObjectType() !== AscDFH.historyitem_type_ChartSpace && this.originalObject.getObjectType() !== AscDFH.historyitem_type_GraphicFrame)
                {
                    xfrm.setFlipH(this.resizedflipH);
                    xfrm.setFlipV(this.resizedflipV);
                }
                if(this.originalObject.getObjectType && this.originalObject.getObjectType() === AscDFH.historyitem_type_OleObject)
                {
                    var api = window.editor || window["Asc"]["editor"];
                    if(api)
                    {
                        var pluginData = new Asc.CPluginData();
                        pluginData.setAttribute("data", this.originalObject.m_sData);
                        pluginData.setAttribute("guid", this.originalObject.m_sApplicationId);
                        pluginData.setAttribute("width", xfrm.extX);
                        pluginData.setAttribute("height", xfrm.extY);
                        pluginData.setAttribute("objectId", this.originalObject.Get_Id());
                        api.asc_pluginResize(pluginData);
                    }
                }

                if(this.bConnector){
                    var nvUniSpPr = this.originalObject.nvSpPr.nvUniSpPr.copy();
                    if(this.numberHandle === 0){
                        nvUniSpPr.stCnxIdx = this.beginShapeIdx;
                        nvUniSpPr.stCnxId  = this.beginShapeId;
                        this.originalObject.nvSpPr.setUniSpPr(nvUniSpPr);
                    }
                    else{
                        nvUniSpPr.endCnxIdx = this.endShapeIdx;
                        nvUniSpPr.endCnxId  = this.endShapeId;
                        this.originalObject.nvSpPr.setUniSpPr(nvUniSpPr);
                    }
                }

            }
            else{
                var _xfrm = this.originalObject.spPr.xfrm;
                var _xfrm2 = this.oSpPr.xfrm;
                _xfrm.setOffX(_xfrm2.offX);
                _xfrm.setOffY(_xfrm2.offY);
                _xfrm.setExtX(_xfrm2.extX);
                _xfrm.setExtY(_xfrm2.extY);
                _xfrm.setFlipH(_xfrm2.flipH);
                _xfrm.setFlipV(_xfrm2.flipV);
                _xfrm.setRot(_xfrm2.rot);
                this.originalObject.spPr.setGeometry(this.oSpPr.geometry.createDuplicate());


                var nvUniSpPr = this.originalObject.nvSpPr.nvUniSpPr.copy();
                if(this.numberHandle === 0){
                    nvUniSpPr.stCnxIdx = this.beginShapeIdx;
                    nvUniSpPr.stCnxId  = this.beginShapeId;
                    this.originalObject.nvSpPr.setUniSpPr(nvUniSpPr);
                }
                else{
                    nvUniSpPr.endCnxIdx = this.endShapeIdx;
                    nvUniSpPr.endCnxId  = this.endShapeId;
                    this.originalObject.nvSpPr.setUniSpPr(nvUniSpPr);
                }
            }
            AscFormat.CheckShapeBodyAutoFitReset(this.originalObject);
            this.originalObject.checkDrawingBaseCoords();
        };
    }, this, []);
}

function ResizeTrackGroup(originalObject, cardDirection, parentTrack)
{
    AscFormat.ExecuteNoHistory(function()
    {
        this.bIsTracked = false;
        this.original = originalObject;

        this.originalObject = originalObject;
        this.parentTrack = parentTrack;
        var numberHandle;
        if(AscFormat.isRealNumber(cardDirection))
        {
            this.numberHandle = originalObject.getNumByCardDirection(cardDirection);
            numberHandle =  this.numberHandle;
        }
        this.x = originalObject.x;
        this.y = originalObject.y;

        this.extX = originalObject.extX;
        this.extY = originalObject.extY;
        this.rot = originalObject.rot;
        this.flipH = originalObject.flipH;
        this.flipV = originalObject.flipV;
        this.transform = originalObject.transform.CreateDublicate();
        this.bSwapCoef = !(AscFormat.checkNormalRotate(this.rot));
        this.childs = [];
        var a = originalObject.spTree;
        for(var i = 0; i < a.length; ++i)
        {
            if(a[i].isGroup())
                this.childs[i] = new ResizeTrackGroup(a[i], null, this);
            else
                this.childs[i] = new ShapeForResizeInGroup(a[i], this);
        }
        if(typeof numberHandle === "number")
        {
            var _translated_num_handle;
            var _flip_h = this.flipH;
            var _flip_v = this.flipV;
            var _sin = Math.sin(this.rot);
            var _cos = Math.cos(this.rot);
            var _half_width = this.extX*0.5;
            var _half_height = this.extY*0.5;
            if(!_flip_h && !_flip_v)
            {
                _translated_num_handle = numberHandle;
            }
            else if(_flip_h && !_flip_v)
            {
                _translated_num_handle = TRANSLATE_HANDLE_FLIP_H[numberHandle];
            }
            else if(!_flip_h && _flip_v)
            {
                _translated_num_handle = TRANSLATE_HANDLE_FLIP_V[numberHandle];
            }
            else
            {
                _translated_num_handle = TRANSLATE_HANDLE_FLIP_H_AND_FLIP_V[numberHandle];
            }

            this.bAspect = numberHandle % 2 === 0;
            this.aspect = this.bAspect === true ? this.original.getAspect(_translated_num_handle) : 0;

            this.sin = _sin;
            this.cos = _cos;
            this.translatetNumberHandle = _translated_num_handle;

            switch (_translated_num_handle)
            {
                case 0:
                case 1:
                {
                    this.fixedPointX = (_half_width*_cos - _half_height*_sin) + _half_width + this.x;
                    this.fixedPointY = (_half_width*_sin + _half_height*_cos) + _half_height + this.y;
                    break;
                }
                case 2:
                case 3:
                {
                    this.fixedPointX = (-_half_width*_cos - _half_height*_sin) + _half_width + this.x;
                    this.fixedPointY = (-_half_width*_sin + _half_height*_cos) + _half_height + this.y;
                    break;
                }
                case 4:
                case 5:
                {
                    this.fixedPointX = (-_half_width*_cos + _half_height*_sin) + _half_width + this.x;
                    this.fixedPointY = (-_half_width*_sin - _half_height*_cos) + _half_height + this.y;
                    break;
                }
                case 6:
                case 7:
                {
                    this.fixedPointX = (_half_width*_cos + _half_height*_sin) + _half_width + this.x;
                    this.fixedPointY = (_half_width*_sin - _half_height*_cos) + _half_height + this.y;
                    break;
                }
            }

            this.mod = this.translatetNumberHandle % 4;
            this.centerPointX = this.x + _half_width;
            this.centerPointY = this.y + _half_height;

            this.lineFlag = false;

            this.originalExtX = this.extX;
            this.originalExtY = this.extY;
            this.originalFlipH = _flip_h;
            this.originalFlipV = _flip_v;

            this.usedExtX =  this.originalExtX === 0 ? (/*this.lineFlag ? this.originalExtX :*/ 0.01) : this.originalExtX;
            this.usedExtY =  this.originalExtY === 0 ? (/*this.lineFlag ? this.originalExtY :*/ 0.01) : this.originalExtY;

            this.resizedExtX = this.originalExtX;
            this.resizedExtY = this.originalExtY;
            this.resizedflipH = _flip_h;
            this.resizedflipV = _flip_v;
            this.resizedPosX = this.x;
            this.resizedPosY = this.y;
            this.resizedRot = this.rot;

            this.bChangeCoef = this.translatetNumberHandle % 2 === 0 && this.originalFlipH !== this.originalFlipV;


        }

        if(this.parentTrack)
        {
            this.centerDistX = this.x + this.extX*0.5 - this.parentTrack.extX*0.5;
            this.centerDistY = this.y + this.extY*0.5 - this.parentTrack.extY*0.5;
        }

        this.track = function(kd1, kd2, e)
        {
            AscFormat.ExecuteNoHistory(function () {

                this.bIsTracked = true;
                if(!e.CtrlKey)
                    this.resize(kd1, kd2, e.ShiftKey);
                else
                    this.resizeRelativeCenter(kd1, kd2, e.ShiftKey)
            }, this, [])
        };

        this.resize = function(kd1, kd2, ShiftKey)
        {
            var _cos = this.cos;
            var _sin = this.sin;

            var _real_height, _real_width;
            var _abs_height, _abs_width;
            var _new_resize_half_width;
            var _new_resize_half_height;
            var _new_used_half_width;
            var _new_used_half_height;
            var _temp;

            if((ShiftKey === true || window.AscAlwaysSaveAspectOnResizeTrack === true || this.originalObject.getNoChangeAspect()) && this.bAspect === true)
            {
                var _new_aspect = this.aspect*(Math.abs(kd1/ kd2));

                if (_new_aspect >= this.aspect)
                    kd2 = Math.abs(kd1)*(kd2 >= 0 ? 1 : -1 );
                else
                    kd1 = Math.abs(kd2)*(kd1 >= 0 ? 1 : -1);
            }

            if(this.bChangeCoef)
            {
                _temp = kd1;
                kd1 = kd2;
                kd2 = _temp;
            }
            switch (this.translatetNumberHandle)
            {
                case 0:
                case 1:
                {
                    if(this.translatetNumberHandle === 0)
                    {
                        _real_width = this.usedExtX*kd1;
                        _abs_width = Math.abs(_real_width);
                        this.resizedExtX = _abs_width >= MIN_SHAPE_SIZE || this.lineFlag ? _abs_width : MIN_SHAPE_SIZE;
                        if(_real_width < 0)
                            this.resizedflipH = !this.originalFlipH;
                        else
                            this.resizedflipH = this.originalFlipH;
                    }
                    if(this.translatetNumberHandle === 1)
                    {
                        _temp = kd1;
                        kd1 = kd2;
                        kd2 = _temp;
                    }

                    _real_height = this.usedExtY*kd2;
                    _abs_height = Math.abs(_real_height);
                    this.resizedExtY = _abs_height >= MIN_SHAPE_SIZE || this.lineFlag ? _abs_height : MIN_SHAPE_SIZE;
                    if(_real_height < 0)
                        this.resizedflipV = !this.originalFlipV;
                    else
                        this.resizedflipV = this.originalFlipV;


                    _new_resize_half_width = this.resizedExtX*0.5;
                    _new_resize_half_height = this.resizedExtY*0.5;
                    if(this.resizedflipH !== this.originalFlipH)
                    {
                        _new_used_half_width = -_new_resize_half_width;
                    }
                    else
                    {
                        _new_used_half_width = _new_resize_half_width;
                    }

                    if(this.resizedflipV !== this.originalFlipV)
                    {
                        _new_used_half_height = -_new_resize_half_height;
                    }
                    else
                    {
                        _new_used_half_height = _new_resize_half_height;
                    }

                    this.resizedPosX = this.fixedPointX + (-_new_used_half_width*_cos + _new_used_half_height*_sin) - _new_resize_half_width;
                    this.resizedPosY = this.fixedPointY + (-_new_used_half_width*_sin - _new_used_half_height*_cos) - _new_resize_half_height;
                    break;
                }
                case 2:
                case 3:
                {
                    if(this.translatetNumberHandle === 2)
                    {
                        _temp = kd2;
                        kd2 = kd1;
                        kd1 = _temp;
                        _real_height = this.usedExtY*kd2;
                        _abs_height = Math.abs(_real_height);
                        this.resizedExtY = _abs_height >= MIN_SHAPE_SIZE || this.lineFlag ? _abs_height : MIN_SHAPE_SIZE;
                        if(_real_height < 0)
                            this.resizedflipV = !this.originalFlipV;
                        else
                            this.resizedflipV = this.originalFlipV;
                    }

                    _real_width = this.usedExtX*kd1;
                    _abs_width = Math.abs(_real_width);
                    this.resizedExtX = _abs_width >= MIN_SHAPE_SIZE || this.lineFlag ? _abs_width : MIN_SHAPE_SIZE;
                    if(_real_width < 0)
                        this.resizedflipH = !this.originalFlipH;
                    else
                        this.resizedflipH = this.originalFlipH;


                    _new_resize_half_width = this.resizedExtX*0.5;
                    _new_resize_half_height = this.resizedExtY*0.5;
                    if(this.resizedflipH !== this.originalFlipH)
                    {
                        _new_used_half_width = -_new_resize_half_width;
                    }

                    else
                    {
                        _new_used_half_width = _new_resize_half_width;
                    }

                    if(this.resizedflipV !== this.originalFlipV)
                    {
                        _new_used_half_height = -_new_resize_half_height;
                    }
                    else
                    {
                        _new_used_half_height = _new_resize_half_height;
                    }

                    this.resizedPosX = this.fixedPointX + (_new_used_half_width*_cos + _new_used_half_height*_sin) - _new_resize_half_width;
                    this.resizedPosY = this.fixedPointY + (_new_used_half_width*_sin - _new_used_half_height*_cos) - _new_resize_half_height;
                    break;
                }

                case 4:
                case 5:
                {
                    if(this.translatetNumberHandle === 4)
                    {
                        _real_width = this.usedExtX*kd1;
                        _abs_width = Math.abs(_real_width);
                        this.resizedExtX = _abs_width >= MIN_SHAPE_SIZE || this.lineFlag ? _abs_width : MIN_SHAPE_SIZE;
                        if(_real_width < 0)
                            this.resizedflipH = !this.originalFlipH;
                        else
                            this.resizedflipH = this.originalFlipH;
                    }
                    else
                    {
                        _temp = kd2;
                        kd2 = kd1;
                        kd1 = _temp;
                    }

                    _real_height = this.usedExtY*kd2;
                    _abs_height = Math.abs(_real_height);
                    this.resizedExtY = _abs_height >= MIN_SHAPE_SIZE || this.lineFlag ? _abs_height : MIN_SHAPE_SIZE;
                    if(_real_height < 0)
                        this.resizedflipV = !this.originalFlipV;
                    else
                        this.resizedflipV = this.originalFlipV;

                    _new_resize_half_width = this.resizedExtX*0.5;
                    _new_resize_half_height = this.resizedExtY*0.5;
                    if(this.resizedflipH !== this.originalFlipH)
                    {
                        _new_used_half_width = -_new_resize_half_width;
                    }
                    else
                    {
                        _new_used_half_width = _new_resize_half_width;
                    }

                    if(this.resizedflipV !== this.originalFlipV)
                    {
                        _new_used_half_height = -_new_resize_half_height;
                    }
                    else
                    {
                        _new_used_half_height = _new_resize_half_height;
                    }

                    this.resizedPosX = this.fixedPointX + (_new_used_half_width*_cos - _new_used_half_height*_sin) - _new_resize_half_width;
                    this.resizedPosY = this.fixedPointY + (_new_used_half_width*_sin + _new_used_half_height*_cos) - _new_resize_half_height;

                    break;
                }

                case 6:
                case 7:
                {
                    if(this.translatetNumberHandle === 6)
                    {
                        _real_height = this.usedExtY*kd1;
                        _abs_height = Math.abs(_real_height);
                        this.resizedExtY = _abs_height >= MIN_SHAPE_SIZE || this.lineFlag ? _abs_height : MIN_SHAPE_SIZE;
                        if(_real_height < 0)
                            this.resizedflipV = !this.originalFlipV;
                        else
                            this.resizedflipV = this.originalFlipV;
                    }
                    else
                    {
                        _temp = kd2;
                        kd2 = kd1;
                        kd1 = _temp;
                    }

                    _real_width = this.usedExtX*kd2;
                    _abs_width = Math.abs(_real_width);
                    this.resizedExtX = _abs_width >= MIN_SHAPE_SIZE || this.lineFlag ? _abs_width : MIN_SHAPE_SIZE;
                    if(_real_width < 0)
                        this.resizedflipH = !this.originalFlipH;
                    else
                        this.resizedflipH = this.originalFlipH;

                    _new_resize_half_width = this.resizedExtX*0.5;
                    _new_resize_half_height = this.resizedExtY*0.5;
                    if(this.resizedflipH !== this.originalFlipH)
                    {
                        _new_used_half_width = -_new_resize_half_width;
                    }
                    else
                    {
                        _new_used_half_width = _new_resize_half_width;
                    }

                    if(this.resizedflipV !== this.originalFlipV)
                    {
                        _new_used_half_height = -_new_resize_half_height;
                    }
                    else
                    {
                        _new_used_half_height = _new_resize_half_height;
                    }

                    this.resizedPosX = this.fixedPointX + (-_new_used_half_width*_cos - _new_used_half_height*_sin) - _new_resize_half_width;
                    this.resizedPosY = this.fixedPointY + (-_new_used_half_width*_sin + _new_used_half_height*_cos) - _new_resize_half_height;
                    break;
                }
            }


            this.x = this.resizedPosX;
            this.y = this.resizedPosY;
            this.extX = this.resizedExtX;
            this.extY = this.resizedExtY;
            this.flipH = this.resizedflipH;
            this.flipV = this.resizedflipV;
            var _transform = this.transform;
            _transform.Reset();

            var _horizontal_center = this.resizedExtX*0.5;
            var _vertical_center = this.resizedExtY*0.5;
            global_MatrixTransformer.TranslateAppend(_transform, -_horizontal_center, -_vertical_center);

            if(this.resizedflipH)
            {
                global_MatrixTransformer.ScaleAppend(_transform, -1, 1);
            }
            if(this.resizedflipV)
            {
                global_MatrixTransformer.ScaleAppend(_transform, 1, -1);
            }

            global_MatrixTransformer.RotateRadAppend(_transform, -this.resizedRot);


            global_MatrixTransformer.TranslateAppend(_transform, this.resizedPosX, this.resizedPosY);
            global_MatrixTransformer.TranslateAppend(_transform, _horizontal_center, _vertical_center);




            var originalExtX, originalExtY;
            if(AscFormat.isRealNumber(this.original.extX) && AscFormat.isRealNumber(this.original.extY)){
                originalExtX = this.original.extX;
                originalExtY = this.original.extY;
                if(AscFormat.fApproxEqual(0.0, originalExtX)){
                    originalExtX = 1;
                }
                if(AscFormat.fApproxEqual(0.0, originalExtY)){
                    originalExtY = 1;
                }
            }
            else {
                var xfrm = this.original.spPr.xfrm;
                if(xfrm){
                    originalExtX = xfrm.extX;
                    originalExtY = xfrm.extY;
                }

                if(!AscFormat.isRealNumber(originalExtX)){
                    originalExtX = 1;
                }
                if(!AscFormat.isRealNumber(originalExtY)){
                    originalExtY = 1;
                }
            }

            if(AscFormat.fApproxEqual(0.0, originalExtX)){
                originalExtX = 1;
            }
            if(AscFormat.fApproxEqual(0.0, originalExtY)){
                originalExtY = 1;
            }
            var kw = this.resizedExtX/originalExtX;
            var kh = this.resizedExtY/originalExtY;
            for(var i = 0; i < this.childs.length; ++i)
            {
                var cur_child = this.childs[i];
                cur_child.updateSize(kw, kh);
            }

        };

        this.resizeRelativeCenter = function(kd1, kd2, ShiftKey)
        {
            kd1 = 2*kd1 - 1;
            kd2 = 2*kd2 - 1;
            var _real_height, _real_width;
            var _abs_height, _abs_width;

            if((ShiftKey === true || window.AscAlwaysSaveAspectOnResizeTrack === true || this.originalObject.getNoChangeAspect()) && this.bAspect === true)
            {
                var _new_aspect = this.aspect*(Math.abs(kd1/ kd2));

                if (_new_aspect >= this.aspect)
                    kd2 = Math.abs(kd1)*(kd2 >= 0 ? 1 : -1 );
                else
                    kd1 = Math.abs(kd2)*(kd1 >= 0 ? 1 : -1);
            }

            var _temp;
            if(this.bChangeCoef)
            {
                _temp = kd1;
                kd1 = kd2;
                kd2 = _temp;
            }
            if(this.mod === 0 || this.mod === 1)
            {
                if(this.mod === 0)
                {
                    _real_width = this.usedExtX*kd1;
                    _abs_width = Math.abs(_real_width);
                    this.resizedExtX = _abs_width >= MIN_SHAPE_SIZE || this.lineFlag ? _abs_width : MIN_SHAPE_SIZE;
                    this.resizedflipH  = _real_width < 0 ? !this.originalFlipH : this.originalFlipH;

                }
                else
                {
                    _temp = kd1;
                    kd1 = kd2;
                    kd2 = _temp;
                }

                _real_height = this.usedExtY*kd2;
                _abs_height = Math.abs(_real_height);
                this.resizedExtY = _abs_height >= MIN_SHAPE_SIZE || this.lineFlag ? _abs_height : MIN_SHAPE_SIZE;
                this.resizedflipV  = _real_height < 0 ? !this.originalFlipV : this.originalFlipV;


            }
            else
            {
                if(this.mod === 2)
                {
                    _temp = kd1;
                    kd1 = kd2;
                    kd2 = _temp;

                    _real_height = this.usedExtY*kd2;
                    _abs_height = Math.abs(_real_height);
                    this.resizedExtY = _abs_height >= MIN_SHAPE_SIZE || this.lineFlag ? _abs_height : MIN_SHAPE_SIZE;
                    this.resizedflipV  = _real_height < 0 ? !this.originalFlipV : this.originalFlipV;

                }
                _real_width = this.usedExtX*kd1;
                _abs_width = Math.abs(_real_width);
                this.resizedExtX = _abs_width >= MIN_SHAPE_SIZE || this.lineFlag ? _abs_width : MIN_SHAPE_SIZE;
                this.resizedflipH  = _real_width < 0 ? !this.originalFlipH : this.originalFlipH;

            }

            this.resizedPosX = this.centerPointX - this.resizedExtX*0.5;
            this.resizedPosY = this.centerPointY - this.resizedExtY*0.5;


            this.x = this.resizedPosX;
            this.y = this.resizedPosY;
            this.extX = this.resizedExtX;
            this.extY = this.resizedExtY;
            this.flipH = this.resizedflipH;
            this.flipV = this.resizedflipV;

            var _transform = this.transform;
            _transform.Reset();

            var _horizontal_center = this.resizedExtX*0.5;
            var _vertical_center = this.resizedExtY*0.5;
            global_MatrixTransformer.TranslateAppend(_transform, -_horizontal_center, -_vertical_center);

            if(this.resizedflipH)
            {
                global_MatrixTransformer.ScaleAppend(_transform, -1, 1);
            }
            if(this.resizedflipV)
            {
                global_MatrixTransformer.ScaleAppend(_transform, 1, -1);
            }

            global_MatrixTransformer.RotateRadAppend(_transform, -this.resizedRot);


            global_MatrixTransformer.TranslateAppend(_transform, this.resizedPosX, this.resizedPosY);
            global_MatrixTransformer.TranslateAppend(_transform, _horizontal_center, _vertical_center);


            var xfrm = this.original.spPr.xfrm;
            var kw = this.resizedExtX/xfrm.extX;
            var kh = this.resizedExtY/xfrm.extY;
            for(var  i = 0; i< this.childs.length; ++i)
            {
                this.childs[i].updateSize(kw, kh);
            }
        };

        this.updateSize = function(kw, kh)
        {
            this.bIsTracked = true;
            var _kw, _kh;
            if(this.bSwapCoef)
            {
                _kw = kh;
                _kh = kw;
            }
            else
            {
                _kw = kw;
                _kh = kh;
            }
            var xfrm = this.original.spPr.xfrm;
            this.extX = xfrm.extX*_kw;
            this.extY = xfrm.extY*_kh;

            this.x = this.centerDistX*kw + this.parentTrack.extX*0.5 - this.extX*0.5;
            this.y = this.centerDistY*kh + this.parentTrack.extY*0.5 - this.extY*0.5;

            this.transform.Reset();
            var t = this.transform;

            global_MatrixTransformer.TranslateAppend(t, -this.extX*0.5, -this.extY*0.5);
            if(xfrm.flipH == null ? false : xfrm.flipH)
            {
                global_MatrixTransformer.ScaleAppend(t, -1, 1);
            }
            if(xfrm.flipV == null ? false : xfrm.flipV)
            {
                global_MatrixTransformer.ScaleAppend(t, 1, -1);
            }
            global_MatrixTransformer.RotateRadAppend(t, xfrm.rot == null ? 0 : -xfrm.rot);
            global_MatrixTransformer.TranslateAppend(t, this.x + this.extX*0.5, this.y+this.extY*0.5);
            global_MatrixTransformer.MultiplyAppend(t, this.parentTrack.transform);
            for(var i = 0; i < this.childs.length; ++i)
            {
                this.childs[i].updateSize(_kw, _kh);
            }
        };

        this.draw = function(graphics)
        {
            if( AscFormat.isRealNumber(this.originalObject.selectStartPage) && graphics.SetCurrentPage)
            {
                graphics.SetCurrentPage(this.originalObject.selectStartPage);
            }
            for(var  i = 0; i < this.childs.length; ++i)
            {
                this.childs[i].draw(graphics);
            }
        };
        this.getBounds = function()
        {
            var boundsChecker = new  AscFormat.CSlideBoundsChecker();
            this.draw(boundsChecker);
            var tr = this.transform;
            var arr_p_x = [];
            var arr_p_y = [];
            arr_p_x.push(tr.TransformPointX(0,0));
            arr_p_y.push(tr.TransformPointY(0,0));
            arr_p_x.push(tr.TransformPointX(this.resizedExtX,0));
            arr_p_y.push(tr.TransformPointY(this.resizedExtX,0));
            arr_p_x.push(tr.TransformPointX(this.resizedExtX,this.resizedExtY));
            arr_p_y.push(tr.TransformPointY(this.resizedExtX,this.resizedExtY));
            arr_p_x.push(tr.TransformPointX(0,this.resizedExtY));
            arr_p_y.push(tr.TransformPointY(0,this.resizedExtY));

            arr_p_x.push(boundsChecker.Bounds.min_x);
            arr_p_x.push(boundsChecker.Bounds.max_x);
            arr_p_y.push(boundsChecker.Bounds.min_y);
            arr_p_y.push(boundsChecker.Bounds.max_y);

            boundsChecker.Bounds.min_x = Math.min.apply(Math, arr_p_x);
            boundsChecker.Bounds.max_x = Math.max.apply(Math, arr_p_x);
            boundsChecker.Bounds.min_y = Math.min.apply(Math, arr_p_y);
            boundsChecker.Bounds.max_y = Math.max.apply(Math, arr_p_y);


            boundsChecker.Bounds.posX = this.resizedPosX;
            boundsChecker.Bounds.posY = this.resizedPosY;

            boundsChecker.Bounds.extX = this.resizedExtX;
            boundsChecker.Bounds.extY = this.resizedExtY;

            return boundsChecker.Bounds;
        };



        this.trackEnd = function(bWord)
        {
            if(!this.bIsTracked){
                return;
            }
            if(!AscCommon.isRealObject(this.original.group))
            {
                this.original.normalize();
            }

            if(!this.original.spPr)
            {
                this.original.setSpPr(new AscFormat.CSpPr());
            }
            if(!this.original.spPr.xfrm)
            {
                this.original.spPr.setXfrm(new AscFormat.CXfrm());
                this.original.spPr.xfrm.setParent(this.original.spPr);
            }
            var xfrm = this.original.spPr.xfrm;

            if(bWord)
            {
                this.x = 0;
                this.y = 0;
            }
            xfrm.setOffX(this.x);
            xfrm.setOffY(this.y);
            xfrm.setExtX(this.extX);
            xfrm.setExtY(this.extY);
            xfrm.setChExtX(this.extX);
            xfrm.setChExtY(this.extY);
            xfrm.setFlipH(this.flipH);
            xfrm.setFlipV(this.flipV);
            for(var i = 0; i < this.childs.length; ++i)
            {
                this.childs[i].trackEnd();
            }
            this.original.checkDrawingBaseCoords();

            AscFormat.CheckShapeBodyAutoFitReset(this.original);


        };
    }, this, []);


}

function ShapeForResizeInGroup(originalObject, parentTrack)
{
    AscFormat.ExecuteNoHistory(function()
    {
        this.originalObject = originalObject;
        this.parentTrack = parentTrack;
        this.x = originalObject.x;
        this.y = originalObject.y;
        this.extX = originalObject.extX;
        this.extY = originalObject.extY;
        this.rot = originalObject.rot;
        this.flipH = originalObject.flipH;
        this.flipV = originalObject.flipV;
        this.transform = originalObject.transform.CreateDublicate();
        this.bSwapCoef = !(AscFormat.checkNormalRotate(this.rot));
        this.centerDistX = this.x + this.extX*0.5 - this.parentTrack.extX*0.5;
        this.centerDistY = this.y + this.extY*0.5 - this.parentTrack.extY*0.5;

        this.geometry = AscFormat.ExecuteNoHistory(function(){ return originalObject.getGeom().createDuplicate();}, this, []);
        if(this.geometry)
        {
            this.geometry.Recalculate(this.extX, this.extY);
        }
        var brush;
        if(originalObject.blipFill)
        {
            brush = new AscFormat.CUniFill();
            brush.fill = originalObject.blipFill;
        }
        else
        {
            brush = originalObject.brush;
        }
        this.overlayObject = new AscFormat.OverlayObject(this.geometry, this.extX, this.extY, brush, originalObject.pen, this.transform);
        this.updateSize = function(kw, kh)
        {
            var _kw, _kh;
            if(this.bSwapCoef)
            {
                _kw = kh;
                _kh = kw;
            }
            else
            {
                _kw = kw;
                _kh = kh;
            }

            this.extX = this.originalObject.extX*_kw;
            this.extY = this.originalObject.extY*_kh;

            this.x = this.centerDistX*kw + this.parentTrack.extX*0.5 - this.extX*0.5;
            this.y = this.centerDistY*kh + this.parentTrack.extY*0.5 - this.extY*0.5;

           //if(this.geometry)
           //{
           //    this.geometry.Recalculate(this.extX, this.extY);
           //}
            this.overlayObject.updateExtents(this.extX, this.extY);
            this.transform.Reset();
            var t = this.transform;

            global_MatrixTransformer.TranslateAppend(t, -this.extX*0.5, -this.extY*0.5);
            if(this.flipH)
            {
                global_MatrixTransformer.ScaleAppend(t, -1, 1);
            }
            if(this.flipV)
            {
                global_MatrixTransformer.ScaleAppend(t, 1, -1);
            }
            global_MatrixTransformer.RotateRadAppend(t, -this.rot);
            global_MatrixTransformer.TranslateAppend(t, this.x + this.extX*0.5, this.y+this.extY*0.5);
            global_MatrixTransformer.MultiplyAppend(t, this.parentTrack.transform);
        };

        this.draw = function(overlay)
        {
            this.overlayObject.draw(overlay);
        };

        this.getBounds = function()
        {
            var bounds_checker = new  AscFormat.CSlideBoundsChecker();
            bounds_checker.init(Page_Width, Page_Height, Page_Width, Page_Height);
            this.draw(bounds_checker);
            return {l: bounds_checker.Bounds.min_x, t: bounds_checker.Bounds.min_y, r: bounds_checker.Bounds.max_x , b: bounds_checker.Bounds.max_y};
        };

        this.trackEnd = function()
        {

            if(!this.originalObject.spPr.xfrm)
            {
                this.originalObject.spPr.setXfrm(new AscFormat.CXfrm());
                this.originalObject.spPr.xfrm.setParent(this.originalObject.spPr);
            }
            var xfrm = this.originalObject.spPr.xfrm;
            xfrm.setOffX(this.x);
            xfrm.setOffY(this.y);
            xfrm.setExtX(this.extX);
            xfrm.setExtY(this.extY);

            AscFormat.CheckShapeBodyAutoFitReset(this.originalObject);
        };

        this.updateTransform = function()
        {
            this.transform.Reset();
            var t = this.transform;

            global_MatrixTransformer.TranslateAppend(t, -this.extX*0.5, -this.extY*0.5);
            if(this.flipH)
            {
                global_MatrixTransformer.ScaleAppend(t, -1, 1);
            }
            if(this.flipV)
            {
                global_MatrixTransformer.ScaleAppend(t, 1, -1);
            }
            global_MatrixTransformer.RotateRadAppend(t, -this.rot);
            global_MatrixTransformer.TranslateAppend(t, this.x + this.extX*0.5, this.y+this.extY*0.5);
            if(this.parentTrack)
                global_MatrixTransformer.MultiplyAppend(t, this.parentTrack.transform);
        };
    }, this, []);
}

    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].SHAPE_EXT = SHAPE_EXT;
    window['AscFormat'].CreatePenBrushForChartTrack = CreatePenBrushForChartTrack;
    window['AscFormat'].ResizeTrackShapeImage = ResizeTrackShapeImage;
    window['AscFormat'].ResizeTrackGroup = ResizeTrackGroup;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

// Import
var CMatrix = AscCommon.CMatrix;
var global_MatrixTransformer = AscCommon.global_MatrixTransformer;
    
var c_oAscFill = Asc.c_oAscFill;

var MIN_ANGLE = 0.07;


function OverlayObject(geometry, extX, extY, brush, pen, transform )
{
    this.geometry = geometry;
    this.ext = {};
    this.ext.cx = extX;
    this.ext.cy = extY;
    this.extX = extX;
    this.extY = extY;

    var _brush, _pen;
    if((!brush || !brush.fill || brush.fill.type === c_oAscFill.FILL_TYPE_NOFILL) &&
        (!pen || !pen.Fill || !pen.Fill || !pen.Fill.fill || pen.Fill.fill.type === c_oAscFill.FILL_TYPE_NOFILL || pen.w === 0))
    {
        var penBrush = AscFormat.CreatePenBrushForChartTrack();
        _brush = penBrush.brush;
        _pen = penBrush.pen;
    }
    else
    {
        _brush = brush;
        _pen = pen;
    }

    this.brush = _brush;
    this.pen = _pen;
    this.TransformMatrix = transform;
    this.shapeDrawer = new AscCommon.CShapeDrawer();

    this.updateTransform = function(extX, extY, transform)
    {
        this.ext.cx = extX;
        this.ext.cy = extY;
        this.extX = extX;
        this.extY = extY;
        this.transform = transform;
    };

    this.updateExtents = function(extX, extY)
    {
        this.ext.cx = extX;
        this.ext.cy = extY;
        this.extX = extX;
        this.extY = extY;
        this.geometry && this.geometry.Recalculate(extX, extY);
    };

    this.updateTransformMatrix = function(transform)
    {
        this.TransformMatrix = transform;
    };


    this.draw = function(overlay, transform)
    {
        var oldTransform = this.TransformMatrix;
        if(transform)
        {
            this.updateTransformMatrix(transform);
        }
        if(this.checkDrawGeometry())
        {
            overlay.SaveGrState();
            overlay.SetIntegerGrid(false);
            overlay.transform3(this.TransformMatrix, false);
            this.shapeDrawer.fromShape2(this, overlay, this.geometry);
            this.shapeDrawer.draw(this.geometry);
            overlay.RestoreGrState();
        }
        else
        {
            if (window["NATIVE_EDITOR_ENJINE"] === true)
            {
                var _shape = new AscFormat.CShape();
				_shape.extX = this.ext.cx;
				_shape.extY = this.ext.cy;
				
				_shape.brush = AscFormat.CreateSolidFillRGBA(255, 255, 255, 128);
				_shape.pen = new AscFormat.CLn();
				_shape.pen.Fill = AscFormat.CreateSolidFillRGBA(0, 0, 0, 160);
				_shape.pen.w = 18000;
				
				overlay.SaveGrState();
	            overlay.SetIntegerGrid(false);
	            overlay.transform3(this.TransformMatrix, false);
	            this.shapeDrawer.fromShape2(_shape, overlay, null);
	            this.shapeDrawer.draw(null);
	            overlay.RestoreGrState();
            }
            else
            {
                overlay.SaveGrState();
                overlay.SetIntegerGrid(false);
                overlay.transform3(this.TransformMatrix);
                overlay._s();
                overlay._m(0, 0);
                overlay._l(this.ext.cx, 0);
                overlay._l(this.ext.cx, this.ext.cy);
                overlay._l(0, this.ext.cy);
                overlay._z();
                overlay.p_color(0,0,0,160);
                overlay.p_width(500);
                overlay.ds();
                overlay.b_color1(255,255,255,128);
                overlay.df();
                overlay._e();
                overlay.RestoreGrState();
				
				if (overlay.m_oOverlay)
					overlay.m_oOverlay.ClearAll = true;
            }
        }
        if(transform)
        {
            this.updateTransformMatrix(oldTransform);
        }
    };

    this.checkDrawGeometry = function()
    {
        return this.geometry &&
            ( (this.pen && this.pen.Fill && this.pen.Fill.fill
                && this.pen.Fill.fill.type != c_oAscFill.FILL_TYPE_NOFILL && this.pen.Fill.fill.type != c_oAscFill.FILL_TYPE_NONE)
                || (this.brush && this.brush.fill && this.brush.fill
                && this.brush.fill.type != c_oAscFill.FILL_TYPE_NOFILL && this.brush.fill.type != c_oAscFill.FILL_TYPE_NONE) );
    };


    this.check_bounds = function(boundsChecker)
    {
        if(this.geometry )
        {
            this.geometry.check_bounds(boundsChecker);
        }
        else
        {
            boundsChecker._s();
            boundsChecker._m(0, 0);
            boundsChecker._l(this.ext.cx, 0);
            boundsChecker._l(this.ext.cx, this.ext.cy);
            boundsChecker._l(0, this.ext.cy);
            boundsChecker._z();
            boundsChecker._e();
        }
    };
}

function ObjectToDraw(brush, pen, extX, extY, geometry, transform, x, y, oComment)
{
    this.extX = extX;
    this.extY = extY;
    this.transform = transform;
    this.TransformMatrix = transform;
    this.geometry = geometry;
    this.parentShape = null;
    this.Comment = oComment;
    this.pen = pen;
    this.brush = brush;

	/*позиция символа*/
    this.x = x;
    this.y = y;
}
ObjectToDraw.prototype =
{
    check_bounds: function(boundsChecker)
    {
        if(this.geometry)
        {
            this.geometry.check_bounds(boundsChecker);
        }
        else
        {
            boundsChecker._s();
            boundsChecker._m(0, 0);
            boundsChecker._l(this.extX, 0);
            boundsChecker._l(this.extX, this.extY);
            boundsChecker._l(0, this.extY);
            boundsChecker._z();
            boundsChecker._e();
        }
    },

    resetBrushPen: function(brush, pen, x, y)
    {
        this.brush = brush;
        this.pen = pen;

        if(AscFormat.isRealNumber(x) && AscFormat.isRealNumber(y))
        {
            this.x = x;
            this.y = y;
        }
    },

    Recalculate: function(oTheme, oColorMap, dWidth, dHeight, oShape, bResetPathsInfo)
    {
       // if(AscFormat.isRealNumber(this.x) && AscFormat.isRealNumber(this.y))
       // {
       //     if(Math.abs(dWidth - this.extX) > MOVE_DELTA || Math.abs(dHeight - this.extY))
       //     {
       //         this.x*=dWidth/this.extX;
       //         this.y*=dHeight/this.extY;
       //     }
       // }
        if(this.brush)
        {
            this.brush.check(oTheme, oColorMap);
        }
        if(this.pen && this.pen.Fill)
        {
            this.pen.Fill.check(oTheme, oColorMap);
        }
        if(this.geometry)
        {
            this.geometry.Recalculate(dWidth, dHeight, bResetPathsInfo);
        }
        this.parentShape = oShape;
    },

    getTransform: function(oTransformMatrix, bNoParentShapeTransform)
    {

        var oTransform;
        if(oTransformMatrix)
        {
            oTransform = oTransformMatrix;
        }
        else
        {
            if(this.parentShape && !(bNoParentShapeTransform === true))
            {
                oTransform = this.parentShape.transformText;
            }
            else
            {
                oTransform = this.TransformMatrix;
            }
        }
        return oTransform;
    },

    drawComment2: function(graphics, bNoParentShapeTransform, oTransformMatrix)
    {
        var oTransform = this.getTransform(oTransformMatrix, bNoParentShapeTransform);
        this.DrawComment(graphics, oTransform);
    },

    DrawComment : function(graphics, oTransform)
    {
        if(this.Comment)
        {
            var oComment = AscCommon.g_oTableId.Get_ById(this.Comment.Additional.CommentId);
            if(oComment)
            {
                var Para = AscCommon.g_oTableId.Get_ById( oComment.StartId );
                if( editor && editor.WordControl && editor.WordControl.m_oLogicDocument && editor.WordControl.m_oLogicDocument.Comments &&
                    (graphics instanceof AscCommon.CGraphics) && ( editor.WordControl.m_oLogicDocument.Comments.Is_Use() && true != editor.isViewMode))
                {
                    if(this.Comment.Additional.CommentId === editor.WordControl.m_oLogicDocument.Comments.Get_CurrentId())
                    {
                        this.brush = AscFormat.G_O_ACTIVE_COMMENT_BRUSH;
                    }
                    else
                    {
                        this.brush = AscFormat.G_O_NO_ACTIVE_COMMENT_BRUSH;
                    }
                    var oComm = this.Comment;
                    Para && editor.WordControl.m_oLogicDocument.Comments.Add_DrawingRect(oComm.x0, oComm.y0, oComm.x1 - oComm.x0, oComm.y1 - oComm.y0, graphics.PageNum, this.Comment.Additional.CommentId, global_MatrixTransformer.Invert(oTransform));
                }
            }
        }
    },

    draw: function(graphics, bNoParentShapeTransform, oTransformMatrix, oTheme, oColorMap)
    {
        var oTransform = this.getTransform(oTransformMatrix, bNoParentShapeTransform);
        this.DrawComment(graphics, oTransform);
        if(oTheme && oColorMap)
        {
            if(this.brush)
            {
                this.brush.check(oTheme, oColorMap);
            }
            if(this.pen && this.pen.Fill)
            {
                this.pen.Fill.check(oTheme, oColorMap);
            }
        }
        graphics.SaveGrState();
        graphics.SetIntegerGrid(false);
        graphics.transform3(oTransform, false);
        var shape_drawer = new AscCommon.CShapeDrawer();
        shape_drawer.fromShape2(this, graphics, this.geometry);
        if(graphics.IsSlideBoundsCheckerType)
        {
            shape_drawer.bIsNoFillAttack = false;
        }
        shape_drawer.draw(this.geometry);
        graphics.RestoreGrState();
    },

    createDuplicate: function()
    {
    }
};
function RotateTrackShapeImage(originalObject)
{
    this.bIsTracked = false;
    this.originalObject = originalObject;
    this.transform = new CMatrix();
    var brush;
    if(originalObject.blipFill)
    {
        brush = new AscFormat.CUniFill();
        brush.fill = originalObject.blipFill;
    }
    else
    {
        brush = originalObject.brush;
    }
    this.overlayObject = new OverlayObject(originalObject.getGeom(), originalObject.extX, originalObject.extY, brush, originalObject.pen, this.transform);

    this.angle = originalObject.rot;
    var full_flip_h = this.originalObject.getFullFlipH();
    var full_flip_v = this.originalObject.getFullFlipV();
    this.signum = !full_flip_h && !full_flip_v || full_flip_h && full_flip_v ? 1 : -1;
    this.draw = function(overlay, transform)
    {
        if(AscFormat.isRealNumber(this.originalObject.selectStartPage) && overlay.SetCurrentPage)
        {
            overlay.SetCurrentPage(this.originalObject.selectStartPage);
        }
        this.overlayObject.draw(overlay, transform);
    };

    this.track = function(angle, e)
    {
        this.bIsTracked = true;
        var new_rot = angle + this.originalObject.rot;
        while(new_rot < 0)
            new_rot += 2*Math.PI;
        while(new_rot >= 2*Math.PI)
            new_rot -= 2*Math.PI;

        if(new_rot < MIN_ANGLE || new_rot > 2*Math.PI - MIN_ANGLE)
            new_rot = 0;

        if(Math.abs(new_rot-Math.PI*0.5) < MIN_ANGLE)
            new_rot = Math.PI*0.5;

        if(Math.abs(new_rot-Math.PI) < MIN_ANGLE)
            new_rot = Math.PI;

        if(Math.abs(new_rot-1.5*Math.PI) < MIN_ANGLE)
            new_rot = 1.5*Math.PI;

        if(e.ShiftKey)
            new_rot = (Math.PI/12)*Math.floor(12*new_rot/(Math.PI));
        this.angle = new_rot;

        var hc, vc;
        hc = this.originalObject.extX*0.5;
        vc = this.originalObject.extY*0.5;
        this.transform.Reset();
        global_MatrixTransformer.TranslateAppend(this.transform, -hc, -vc);
        if(this.originalObject.flipH)
            global_MatrixTransformer.ScaleAppend(this.transform, -1, 1);
        if(this.originalObject.flipV)
            global_MatrixTransformer.ScaleAppend(this.transform, 1, -1);
        global_MatrixTransformer.RotateRadAppend(this.transform, -this.angle);
        global_MatrixTransformer.TranslateAppend(this.transform, this.originalObject.x + hc, this.originalObject.y + vc);
        if(this.originalObject.group)
        {
            global_MatrixTransformer.MultiplyAppend(this.transform, this.originalObject.group.transform);
        }
        if(this.originalObject.parent)
        {
            var parent_transform = this.originalObject.parent.Get_ParentTextTransform && this.originalObject.parent.Get_ParentTextTransform();
            if(parent_transform)
            {
                global_MatrixTransformer.MultiplyAppend(this.transform, parent_transform);
            }
        }

    };

    this.trackEnd = function()
    {
        if(!this.bIsTracked){
            return;
        }
        AscFormat.CheckSpPrXfrm(this.originalObject);
        this.originalObject.spPr.xfrm.setRot(this.angle);
    };

    this.getBounds = function()
    {
        var boundsChecker = new  AscFormat.CSlideBoundsChecker();
        var tr = null;
        if(this.originalObject && this.originalObject.parent)
        {
            var parent_transform = this.originalObject.parent.Get_ParentTextTransform && this.originalObject.parent.Get_ParentTextTransform();
            if(parent_transform)
            {
                tr = this.transform.CreateDublicate();
                global_MatrixTransformer.MultiplyAppend(tr, global_MatrixTransformer.Invert(parent_transform));
            }

        }
        this.draw(boundsChecker, tr ? tr : null);
        tr = this.transform;
        var arr_p_x = [];
        var arr_p_y = [];
        arr_p_x.push(tr.TransformPointX(0,0));
        arr_p_y.push(tr.TransformPointY(0,0));
        arr_p_x.push(tr.TransformPointX(this.originalObject.extX,0));
        arr_p_y.push(tr.TransformPointY(this.originalObject.extX,0));
        arr_p_x.push(tr.TransformPointX(this.originalObject.extX,this.originalObject.extY));
        arr_p_y.push(tr.TransformPointY(this.originalObject.extX,this.originalObject.extY));
        arr_p_x.push(tr.TransformPointX(0,this.originalObject.extY));
        arr_p_y.push(tr.TransformPointY(0,this.originalObject.extY));

        arr_p_x.push(boundsChecker.Bounds.min_x);
        arr_p_x.push(boundsChecker.Bounds.max_x);
        arr_p_y.push(boundsChecker.Bounds.min_y);
        arr_p_y.push(boundsChecker.Bounds.max_y);

        boundsChecker.Bounds.min_x = Math.min.apply(Math, arr_p_x);
        boundsChecker.Bounds.max_x = Math.max.apply(Math, arr_p_x);
        boundsChecker.Bounds.min_y = Math.min.apply(Math, arr_p_y);
        boundsChecker.Bounds.max_y = Math.max.apply(Math, arr_p_y);

        boundsChecker.Bounds.posX = this.originalObject.x;
        boundsChecker.Bounds.posY = this.originalObject.y;
        boundsChecker.Bounds.extX = this.originalObject.extX;
        boundsChecker.Bounds.extY = this.originalObject.extY;
        return boundsChecker.Bounds;
    }
}

function RotateTrackGroup(originalObject)
{
    this.bIsTracked = false;
    this.originalObject = originalObject;
    this.transform = new CMatrix();

    this.overlayObjects = [];


    this.arrTransforms = [];
    this.arrTransforms2 = [];
    var arr_graphic_objects = originalObject.getArrGraphicObjects();
    var group_invert_transform = originalObject.getInvertTransform();
    for(var i = 0; i < arr_graphic_objects.length; ++i)
    {
        var gr_obj_transform_copy = arr_graphic_objects[i].getTransformMatrix().CreateDublicate();
        global_MatrixTransformer.MultiplyAppend(gr_obj_transform_copy, group_invert_transform);
        this.arrTransforms2[i] = gr_obj_transform_copy;
        this.overlayObjects[i] = new OverlayObject(arr_graphic_objects[i].getGeom(), arr_graphic_objects[i].extX, arr_graphic_objects[i].extY,
            arr_graphic_objects[i].brush,  arr_graphic_objects[i].pen, new CMatrix());
    }


    this.angle = originalObject.rot;

    this.draw = function(overlay)
    {
        if(AscFormat.isRealNumber(this.originalObject.selectStartPage) && overlay.SetCurrentPage)
        {
            overlay.SetCurrentPage(this.originalObject.selectStartPage);
        }
        for(var i = 0; i < this.overlayObjects.length; ++i)
        {
            this.overlayObjects[i].draw(overlay);
        }
    };

    this.getBounds = function()
    {
        var boundsChecker = new  AscFormat.CSlideBoundsChecker();
        this.draw(boundsChecker);
        var tr = this.transform;
        var arr_p_x = [];
        var arr_p_y = [];
        arr_p_x.push(tr.TransformPointX(0,0));
        arr_p_y.push(tr.TransformPointY(0,0));
        arr_p_x.push(tr.TransformPointX(this.originalObject.extX,0));
        arr_p_y.push(tr.TransformPointY(this.originalObject.extX,0));
        arr_p_x.push(tr.TransformPointX(this.originalObject.extX,this.originalObject.extY));
        arr_p_y.push(tr.TransformPointY(this.originalObject.extX,this.originalObject.extY));
        arr_p_x.push(tr.TransformPointX(0,this.originalObject.extY));
        arr_p_y.push(tr.TransformPointY(0,this.originalObject.extY));

        arr_p_x.push(boundsChecker.Bounds.min_x);
        arr_p_x.push(boundsChecker.Bounds.max_x);
        arr_p_y.push(boundsChecker.Bounds.min_y);
        arr_p_y.push(boundsChecker.Bounds.max_y);

        boundsChecker.Bounds.min_x = Math.min.apply(Math, arr_p_x);
        boundsChecker.Bounds.max_x = Math.max.apply(Math, arr_p_x);
        boundsChecker.Bounds.min_y = Math.min.apply(Math, arr_p_y);
        boundsChecker.Bounds.max_y = Math.max.apply(Math, arr_p_y);
        boundsChecker.Bounds.posX = this.originalObject.x;
        boundsChecker.Bounds.posY = this.originalObject.y;
        boundsChecker.Bounds.extX = this.originalObject.extX;
        boundsChecker.Bounds.extY = this.originalObject.extY;
        return boundsChecker.Bounds;
    };

    this.track = function(angle, e)
    {
        this.bIsTracked = true;
        var new_rot = angle + this.originalObject.rot;
        while(new_rot < 0)
            new_rot += 2*Math.PI;
        while(new_rot >= 2*Math.PI)
            new_rot -= 2*Math.PI;

        if(new_rot < MIN_ANGLE || new_rot > 2*Math.PI - MIN_ANGLE)
            new_rot = 0;

        if(Math.abs(new_rot-Math.PI*0.5) < MIN_ANGLE)
            new_rot = Math.PI*0.5;

        if(Math.abs(new_rot-Math.PI) < MIN_ANGLE)
            new_rot = Math.PI;

        if(Math.abs(new_rot-1.5*Math.PI) < MIN_ANGLE)
            new_rot = 1.5*Math.PI;

        if(e.ShiftKey)
            new_rot = (Math.PI/12)*Math.floor(12*new_rot/(Math.PI));
        this.angle = new_rot;

        var hc, vc;
        hc = this.originalObject.extX*0.5;
        vc = this.originalObject.extY*0.5;
        this.transform.Reset();
        global_MatrixTransformer.TranslateAppend(this.transform, -hc, -vc);
        if(this.originalObject.flipH)
            global_MatrixTransformer.ScaleAppend(this.transform, -1, 1);
        if(this.originalObject.flipV)
            global_MatrixTransformer.ScaleAppend(this.transform, 1, -1);
        global_MatrixTransformer.RotateRadAppend(this.transform, -this.angle);
        global_MatrixTransformer.TranslateAppend(this.transform, this.originalObject.x + hc, this.originalObject.y + vc);
        for(var i = 0; i < this.overlayObjects.length; ++i)
        {
            var new_transform = this.arrTransforms2[i].CreateDublicate();
            global_MatrixTransformer.MultiplyAppend(new_transform, this.transform);
            this.overlayObjects[i].updateTransformMatrix(new_transform);
        }
    };

    this.trackEnd = function(bWord)
    {
        if(!this.bIsTracked){
            return;
        }
        var x = this.originalObject.x;
        var y = this.originalObject.y;
        if(bWord){
            this.originalObject.x = 0;
            this.originalObject.y = 0;
        }
        AscFormat.CheckSpPrXfrm3(this.originalObject);
        if(bWord){
            this.originalObject.x = x;
            this.originalObject.y = y;
        }
        this.originalObject.spPr.xfrm.setRot(this.angle);
    }
}

function Chart3dAdjustTrack(oChartSpace, numHandle, startX, startY)
{
    this.bIsTracked = false;
    this.chartSpace = oChartSpace;



    this.originalObject = oChartSpace;
    this.originalShape = oChartSpace;

    this.transform = this.originalObject.transform;
    this.processor3D = oChartSpace.chartObj.processor3D;
    this.depthPerspective = oChartSpace.chartObj.processor3D.depthPerspective;

    this.startX = oChartSpace.invertTransform.TransformPointX(startX, startY);
    this.startY = oChartSpace.invertTransform.TransformPointY(startX, startY);

    this.bChartTrack = false;
    var oChartObj = oChartSpace.chart.plotArea.charts[0];
    if(oChartObj){
        var nPointsCount = 0;
        if(oChartObj.getObjectType() === AscDFH.historyitem_type_PieChart || oChartObj.getObjectType() === AscDFH.historyitem_type_PieChart){
            if(oChartObj.series[0]){
                nPointsCount = AscFormat.getPtsFromSeries(oChartObj.series[0]).length;
            }
        }
        else{
            for(var i = 0; i < oChartObj.series.length; ++i){
                nPointsCount += AscFormat.getPtsFromSeries(oChartObj.series[i]).length;
            }
        }


        if(nPointsCount < 30){
            this.bChartTrack = true;
        }
    }


    AscFormat.ExecuteNoHistory(function(){
        this.view3D = oChartSpace.chart.getView3d();
        this.chartSizes = this.chartSpace.getChartSizes();

        this.cX = this.chartSizes.startX + this.chartSizes.w/2;
        this.cY = this.chartSizes.startY + this.chartSizes.h/2;
        this.geometry = new AscFormat.Geometry();
        var oPen = new AscFormat.CLn();
        oPen.w = 15000;
        oPen.Fill = AscFormat.CreateSolidFillRGBA(255, 255, 255, 255);
        this.objectToDraw = new OverlayObject(this.geometry, oChartSpace.extX, oChartSpace.extY, null, oPen, oChartSpace.transform );

        var oPen2 = new AscFormat.CLn();
        oPen2.w = 15000;
        oPen2.Fill = AscFormat.CreateSolidFillRGBA(0x61, 0x9e, 0xde, 255);
        oPen2.prstDash = 0;
        this.objectToDraw2 = new OverlayObject(this.geometry, oChartSpace.extX, oChartSpace.extY, null, oPen2, oChartSpace.transform );


        var pxToMM = this.chartSpace.chartObj.calcProp.pxToMM;
        var oChSz = this.chartSizes;
        this.centerPoint = this.processor3D.convertAndTurnPoint((oChSz.startX + oChSz.w/2)*pxToMM, (oChSz.startY + oChSz.h/2)*pxToMM, this.depthPerspective/2);
    }, this, []);


   /* this.draw = function(overlay, transform)
    {
        if(AscFormat.isRealNumber(this.chartSpace.selectStartPage) && overlay.SetCurrentPage)
        {
            overlay.SetCurrentPage(this.chartSpace.selectStartPage);
        }
        var dOldAlpha = null;
        var oGraphics = overlay.Graphics ? overlay.Graphics : overlay;
        if(AscFormat.isRealNumber(oGraphics.globalAlpha) && oGraphics.put_GlobalAlpha){

            var graphics = oGraphics;
            graphics.SaveGrState();
            graphics.SetIntegerGrid(false);
            graphics.transform3(oChartSpace.transform, false);
            oChartSpace.chartObj.draw(oChartSpace, graphics);
            graphics.RestoreGrState();
        }
    };*/

    this.draw = function(overlay, transform)
    {

        if(this.bChartTrack){
            if(AscFormat.isRealNumber(this.chartSpace.selectStartPage) && overlay.SetCurrentPage)
            {
                overlay.SetCurrentPage(this.chartSpace.selectStartPage);
            }
            var dOldAlpha = null;
            var oGraphics = overlay.Graphics ? overlay.Graphics : overlay;
            if(AscFormat.isRealNumber(oGraphics.globalAlpha) && oGraphics.put_GlobalAlpha){

                var graphics = oGraphics;
                graphics.SaveGrState();
                graphics.SetIntegerGrid(false);
                graphics.transform3(oChartSpace.transform, false);
                oChartSpace.chartObj.draw(oChartSpace, graphics);
                graphics.RestoreGrState();
            }
        }
        else{
            if(AscFormat.isRealNumber(this.chartSpace.selectStartPage) && overlay.SetCurrentPage)
            {
                overlay.SetCurrentPage(this.chartSpace.selectStartPage);
            }
            var dOldAlpha = null;
            var oGraphics = overlay.Graphics ? overlay.Graphics : overlay;
            if(AscFormat.isRealNumber(oGraphics.globalAlpha) && oGraphics.put_GlobalAlpha){
                dOldAlpha = oGraphics.globalAlpha;
                oGraphics.put_GlobalAlpha(false, 1);
            }
            this.objectToDraw.draw(overlay, transform);
            this.objectToDraw2.draw(overlay, transform);
            if(AscFormat.isRealNumber(dOldAlpha) && oGraphics.put_GlobalAlpha){
                oGraphics.put_GlobalAlpha(true, dOldAlpha);
            }
        }

    };


    this.calculateGeometry = function()
    {
        AscFormat.ExecuteNoHistory(function(){

            this.geometry.pathLst.length = 0;
            var path = new AscFormat.Path();
            path.pathW = this.chartSpace.extX;
            path.pathH = this.chartSpace.extY;
            path.stroke  = true;
            var pxToMM = this.chartSpace.chartObj.calcProp.pxToMM;
            this.geometry.pathLst.push(path);
            var oChSz = this.chartSizes;
            var processor3D = this.chartSpace.chartObj.processor3D;



            var centerPoint2 = this.processor3D.convertAndTurnPoint((oChSz.startX + oChSz.w/2)*pxToMM, (oChSz.startY + oChSz.h/2)*pxToMM, this.depthPerspective/2);

            var deltaX = (this.centerPoint.x - centerPoint2.x)/pxToMM;
            var deltaY = (this.centerPoint.y - centerPoint2.y)/pxToMM;

            var point1 = processor3D.convertAndTurnPoint(oChSz.startX*pxToMM, oChSz.startY*pxToMM, 0);
            path.moveTo(point1.x/pxToMM + deltaX, point1.y/pxToMM + deltaY);
            var point2 = processor3D.convertAndTurnPoint((oChSz.startX + oChSz.w) *pxToMM, oChSz.startY*pxToMM, 0);
            path.lnTo(point2.x/pxToMM + deltaX, point2.y/pxToMM + deltaY);
            var point3 = processor3D.convertAndTurnPoint((oChSz.startX + oChSz.w)*pxToMM, (oChSz.startY + oChSz.h)*pxToMM, 0);
            path.lnTo(point3.x/pxToMM + deltaX, point3.y/pxToMM + deltaY);
            var point4 = processor3D.convertAndTurnPoint((oChSz.startX)*pxToMM, (oChSz.startY + oChSz.h)*pxToMM, 0);
            path.lnTo(point4.x/pxToMM + deltaX, point4.y/pxToMM + deltaY);
            path.close();

            var point1d = processor3D.convertAndTurnPoint(oChSz.startX*pxToMM, oChSz.startY*pxToMM, this.depthPerspective);
            path.moveTo(point1d.x/pxToMM + deltaX, point1d.y/pxToMM + deltaY);
            var point2d = processor3D.convertAndTurnPoint((oChSz.startX + oChSz.w) *pxToMM, oChSz.startY*pxToMM, this.depthPerspective);
            path.lnTo(point2d.x/pxToMM + deltaX, point2d.y/pxToMM + deltaY);
            var point3d = processor3D.convertAndTurnPoint((oChSz.startX + oChSz.w)*pxToMM, (oChSz.startY + oChSz.h)*pxToMM, this.depthPerspective);
            path.lnTo(point3d.x/pxToMM + deltaX, point3d.y/pxToMM + deltaY);
            var point4d = processor3D.convertAndTurnPoint((oChSz.startX)*pxToMM, (oChSz.startY + oChSz.h)*pxToMM, this.depthPerspective);
            path.lnTo(point4d.x/pxToMM + deltaX, point4d.y/pxToMM + deltaY);
            path.close();

            path.moveTo(point1.x/pxToMM + deltaX, point1.y/pxToMM + deltaY);
            path.lnTo(point1d.x/pxToMM + deltaX, point1d.y/pxToMM + deltaY);
            path.moveTo(point2.x/pxToMM + deltaX, point2.y/pxToMM + deltaY);
            path.lnTo(point2d.x/pxToMM + deltaX, point2d.y/pxToMM + deltaY);
            path.moveTo(point3.x/pxToMM + deltaX, point3.y/pxToMM + deltaY);
            path.lnTo(point3d.x/pxToMM + deltaX, point3d.y/pxToMM + deltaY);
            path.moveTo(point4.x/pxToMM + deltaX, point4.y/pxToMM + deltaY);
            path.lnTo(point4d.x/pxToMM + deltaX, point4d.y/pxToMM + deltaY);

            this.geometry.Recalculate(this.chartSpace.extX, this.chartSpace.extY);
        }, this, []);

    };

    this.getBounds = function()
    {
        var boundsChecker = new  AscFormat.CSlideBoundsChecker();
        //this.draw(boundsChecker);
        var tr = this.transform;
        var arr_p_x = [];
        var arr_p_y = [];
        arr_p_x.push(tr.TransformPointX(0,0));
        arr_p_y.push(tr.TransformPointY(0,0));
        arr_p_x.push(tr.TransformPointX(this.originalObject.extX,0));
        arr_p_y.push(tr.TransformPointY(this.originalObject.extX,0));
        arr_p_x.push(tr.TransformPointX(this.originalObject.extX,this.originalObject.extY));
        arr_p_y.push(tr.TransformPointY(this.originalObject.extX,this.originalObject.extY));
        arr_p_x.push(tr.TransformPointX(0,this.originalObject.extY));
        arr_p_y.push(tr.TransformPointY(0,this.originalObject.extY));

        arr_p_x.push(boundsChecker.Bounds.min_x);
        arr_p_x.push(boundsChecker.Bounds.max_x);
        arr_p_y.push(boundsChecker.Bounds.min_y);
        arr_p_y.push(boundsChecker.Bounds.max_y);

        boundsChecker.Bounds.min_x = Math.min.apply(Math, arr_p_x);
        boundsChecker.Bounds.max_x = Math.max.apply(Math, arr_p_x);
        boundsChecker.Bounds.min_y = Math.min.apply(Math, arr_p_y);
        boundsChecker.Bounds.max_y = Math.max.apply(Math, arr_p_y);
        boundsChecker.Bounds.posX = this.originalObject.x;
        boundsChecker.Bounds.posY = this.originalObject.y;
        boundsChecker.Bounds.extX = this.originalObject.extX;
        boundsChecker.Bounds.extY = this.originalObject.extY;
        return boundsChecker.Bounds;
    };

    this.track = function(x, y)
    {
        this.bIsTracked = true;

        var tx = this.chartSpace.invertTransform.TransformPointX(x, y);
        var ty = this.chartSpace.invertTransform.TransformPointY(x, y);

        var _view3d = oChartSpace.chart.getView3d();
        var StratRotY = _view3d && _view3d.rotY ? _view3d.rotY : 0;
        var deltaAng = -90*(tx - this.startX)/(this.chartSizes.w/2);
        this.view3D.rotY = StratRotY + deltaAng;

        if(_view3d.getRAngAx()){
            if(this.view3D.rotY < 0){
                this.view3D.rotY = 0;
            }
            if(this.view3D.rotY > 90){
                this.view3D.rotY = 90;
            }
        }
        while(this.view3D.rotY < 0){
            this.view3D.rotY += 360;
        }
        while(this.view3D.rotY >= 360){
            this.view3D.rotY -= 360;
        }

        var StratRotX = _view3d && _view3d.rotX ? _view3d.rotX : 0;
        deltaAng = 90*(ty - this.startY)/(this.chartSizes.h/2);
        this.view3D.rotX = StratRotX + deltaAng;

		if(oChartSpace.chart.plotArea && oChartSpace.chart.plotArea.charts[0] && oChartSpace.chart.plotArea.charts[0].getObjectType() === AscDFH.historyitem_type_PieChart){
			if(this.view3D.rotX < 0){
                this.view3D.rotX = 0;
            }
		}
		
        if(this.view3D.rotX < -90){
            this.view3D.rotX = -90;
        }

        if(this.view3D.rotX > 90){
            this.view3D.rotX = 90;
        }


        var OldView = oChartSpace.chart.view3D;
        if(this.bChartTrack){
            oChartSpace.chart.view3D = this.view3D;
            oChartSpace.recalcInfo.recalculateChart = true;
            oChartSpace.recalculate();
            oChartSpace.chart.view3D = OldView;
        }
        else{
            oChartSpace.chart.view3D = this.view3D;
            oChartSpace.chartObj.recalculateOnly3dProps(oChartSpace);
            oChartSpace.chart.view3D = OldView;
            this.calculateGeometry();
        }
    };

    this.trackEnd = function()
    {
        if(!this.bIsTracked){
            return;
        }
        oChartSpace.chart.setView3D(this.view3D.createDuplicate());
        oChartSpace.setRecalculateInfo();
    }
}

    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].OverlayObject = OverlayObject;
    window['AscFormat'].ObjectToDraw = ObjectToDraw;
    window['AscFormat'].RotateTrackShapeImage = RotateTrackShapeImage;
    window['AscFormat'].RotateTrackGroup = RotateTrackGroup;
    window['AscFormat'].Chart3dAdjustTrack = Chart3dAdjustTrack;
})(window);
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

function SplineCommandMoveTo(x, y)
{
    this.id = 0;
    this.x = x;
    this.y = y;
}

function SplineCommandLineTo(x, y)
{
    this.id = 1;
    this.x = x;
    this.y = y;
    this.changeLastPoint = function(x, y)
    {
        this.x = x;
        this.y = y;
    }
}

function SplineCommandBezier(x1, y1, x2, y2, x3, y3)
{
    this.id = 2;
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;
    this.x3 = x3;
    this.y3 = y3;

    this.changeLastPoint = function(x, y)
    {
        this.x3 = x;
        this.y3 = y;
        this.x2 = this.x1 + (this.x3 - this.x1)*0.5;
        this.y2 = this.y1 + (this.y3 - this.y1)*0.5;
    }
}

function Spline(drawingObjects, theme, master, layout, slide, pageIndex)
{

    AscFormat.ExecuteNoHistory(function(){
        this.pageIndex = pageIndex;
        this.path = [];

        this.drawingObjects = drawingObjects;

        this.Matrix = new AscCommon.CMatrix();
        this.TransformMatrix = new AscCommon.CMatrix();

        this.style  = AscFormat.CreateDefaultShapeStyle();

        var style = this.style;
        style.fillRef.Color.Calculate(theme, slide, layout, master, {R:0, G: 0, B:0, A:255});
        var RGBA = style.fillRef.Color.RGBA;
        var pen = theme.getLnStyle(style.lnRef.idx, style.lnRef.Color);
        style.lnRef.Color.Calculate(theme, slide, layout, master);
        RGBA = style.lnRef.Color.RGBA;

        if(pen.Fill)
        {
            pen.Fill.calculate(theme, slide, layout, master, RGBA);
        }

        this.pen = pen;
        this.splineForDraw = new SplineForDrawer(this);
    }, this, []);
    this.Draw = function(graphics)
    {
        graphics.SetIntegerGrid(false);
        graphics.transform3(this.Matrix);

        var shape_drawer = new AscCommon.CShapeDrawer();
        shape_drawer.fromShape(this, graphics);
        shape_drawer.draw(this);
    };
    this.draw = function(g)
    {
        if(AscFormat.isRealNumber(this.pageIndex) && g.SetCurrentPage)
        {
            g.SetCurrentPage(this.pageIndex);
        }
        this.splineForDraw.Draw(g);
        return;
        for(var i = 0; i < this.path.length; ++i)
        {
            var lastX, lastY;
            switch (this.path[i].id )
            {
                case 0 :
                {
                    g._m(this.path[i].x, this.path[i].y);
                    lastX = this.path[i].x;
                    lastY = this.path[i].y;
                    break;
                }
                case 1 :
                {
                    g._l(this.path[i].x, this.path[i].y);
                    lastX = this.path[i].x;
                    lastY = this.path[i].y;
                    break;
                }
                case 2 :
                {
                    g._c(this.path[i].x1, this.path[i].y1, this.path[i].x2, this.path[i].y2, this.path[i].x3, this.path[i].y3);
                    lastX = this.path[i].x3;
                    lastY = this.path[i].y3;
                    break;
                }
            }
        }
        g.ds();
    };

    this.getShape =  function(bWord, drawingDocument, drawingObjects)
    {
        var xMax = this.path[0].x, yMax = this.path[0].y, xMin = xMax, yMin = yMax;
        var i;

        var bClosed = false;
        if(this.path.length > 2)
        {
            var dx = this.path[0].x - this.path[this.path.length-1].x3;
            var dy = this.path[0].y - this.path[this.path.length-1].y3;
            if(Math.sqrt(dx*dx +dy*dy) < 3)
            {
                bClosed = true;
                this.path[this.path.length-1].x3 = this.path[0].x;
                this.path[this.path.length-1].y3 = this.path[0].y;
                if(this.path.length > 3)
                {
                    var vx = (this.path[1].x3 - this.path[this.path.length-2].x3)/6;
                    var vy = (this.path[1].y3 - this.path[this.path.length-2].y3)/6;
                }
                else
                {
                    vx = -(this.path[1].y3 - this.path[0].y)/6;
                    vy = (this.path[1].x3 - this.path[0].x)/6;
                }


                this.path[1].x1 = this.path[0].x +vx;
                this.path[1].y1 = this.path[0].y +vy;
                this.path[this.path.length-1].x2 = this.path[0].x -vx;
                this.path[this.path.length-1].y2 = this.path[0].y -vy;
            }
        }

        var min_x = this.path[0].x;
        var max_x = min_x;
        var min_y = this.path[0].y;
        var max_y = min_y;
        var last_x = this.path[0].x, last_y = this.path[0].y;
        for(var index = 1; index < this.path.length; ++index)
        {
            var path_command = this.path[index];
            if(path_command.id === 1)
            {
                if(min_x > path_command.x)
                    min_x = path_command.x;
                if(max_x < path_command.x)
                    max_x = path_command.x;
                if(min_y > path_command.y)
                    min_y = path_command.y;
                if(max_y < path_command.y)
                    max_y = path_command.y;

                last_x = path_command.x;
                last_y = path_command.y;
            }
            else
            {
                var bezier_polygon = AscFormat.partition_bezier4(last_x, last_y, path_command.x1, path_command.y1, path_command.x2, path_command.y2, path_command.x3, path_command.y3, AscFormat.APPROXIMATE_EPSILON);
                for(var point_index = 1; point_index < bezier_polygon.length; ++point_index)
                {
                    var cur_point = bezier_polygon[point_index];
                    if(min_x > cur_point.x)
                        min_x = cur_point.x;
                    if(max_x < cur_point.x)
                        max_x = cur_point.x;
                    if(min_y > cur_point.y)
                        min_y = cur_point.y;
                    if(max_y < cur_point.y)
                        max_y = cur_point.y;

                    last_x = path_command.x3;
                    last_y = path_command.y3;
                }
            }
        }

        xMin = min_x;
        xMax = max_x;
        yMin = min_y;
        yMax = max_y;
        var shape = new AscFormat.CShape();
        //if(drawingObjects)
        //{
        //    shape.setWorksheet(drawingObjects.getWorksheetModel());
        //    shape.addToDrawingObjects();
        //}
        shape.setSpPr(new AscFormat.CSpPr());
        shape.spPr.setParent(shape);
        shape.spPr.setXfrm(new AscFormat.CXfrm());
        shape.spPr.xfrm.setParent(shape.spPr);
        if(!bWord)
        {
            shape.spPr.xfrm.setOffX(xMin);
            shape.spPr.xfrm.setOffY(yMin);
        }
        else
        {
            shape.setWordShape(true);
            shape.spPr.xfrm.setOffX(0);
            shape.spPr.xfrm.setOffY(0);
        }
        shape.spPr.xfrm.setExtX(xMax-xMin);
        shape.spPr.xfrm.setExtY(yMax - yMin);
        shape.setStyle(AscFormat.CreateDefaultShapeStyle());

        var geometry = new AscFormat.Geometry();
        var w = xMax - xMin, h = yMax-yMin;
        var kw, kh, pathW, pathH;
        if(w > 0)
        {
            pathW = 43200;
            kw = 43200/ w
        }
        else
        {
            pathW = 0;
            kw = 0;
        }
        if(h > 0)
        {
            pathH = 43200;
            kh = 43200 / h;
        }
        else
        {
            pathH = 0;
            kh = 0;
        }
        geometry.AddPathCommand(0, undefined, bClosed ? "norm": "none", undefined, pathW, pathH);
        geometry.AddRect("l", "t", "r", "b");
        for(i = 0;  i< this.path.length; ++i)
        {
            switch (this.path[i].id)
            {
                case 0 :
                {
                    geometry.AddPathCommand(1, (((this.path[i].x - xMin) * kw) >> 0) + "", (((this.path[i].y - yMin) * kh) >> 0) + "");
                    break;
                }
                case 1 :
                {
                    geometry.AddPathCommand(2, (((this.path[i].x - xMin) * kw) >> 0) + "", (((this.path[i].y - yMin) * kh) >> 0) + "");
                    break;
                }
                case 2:
                {
                    geometry.AddPathCommand(5, (((this.path[i].x1 - xMin) * kw) >> 0) + "", (((this.path[i].y1 - yMin) * kh) >> 0) + "", (((this.path[i].x2 - xMin)* kw) >> 0) + "", (((this.path[i].y2 - yMin) * kh) >> 0) + "", (((this.path[i].x3 - xMin) * kw) >> 0) + "", (((this.path[i].y3 - yMin) * kh) >> 0) + "");
                    break;
                }
            }
        }
        if(bClosed)
        {
            geometry.AddPathCommand(6);
        }
        shape.spPr.setGeometry(geometry);
        shape.setBDeleted(false);
        shape.recalculate();
        shape.x = xMin;
        shape.y = yMin;
        return shape;
    };

    this.addPathCommand = function(pathCommand)
    {
        this.path.push(pathCommand);
    };
    this.getBounds = function()
    {
        var boundsChecker = new  AscFormat.CSlideBoundsChecker();
        this.draw(boundsChecker);
        boundsChecker.Bounds.posX = boundsChecker.Bounds.min_x;
        boundsChecker.Bounds.posY = boundsChecker.Bounds.min_y;
        boundsChecker.Bounds.extX = boundsChecker.Bounds.max_x - boundsChecker.Bounds.min_x;
        boundsChecker.Bounds.extY = boundsChecker.Bounds.max_y - boundsChecker.Bounds.min_y;
        return boundsChecker.Bounds;
    };
}

function SplineForDrawer(spline)
{
    this.spline = spline;
    this.pen = spline.pen;
    this.brush = spline.brush;
    this.TransformMatrix = spline.TransformMatrix;
    this.Matrix = spline.Matrix;

    this.Draw = function(graphics)
    {
        graphics.SetIntegerGrid(false);
        graphics.transform3(this.Matrix);

        var shape_drawer = new AscCommon.CShapeDrawer();
        shape_drawer.fromShape(this, graphics);
        shape_drawer.draw(this);
    };

    this.draw = function(g)
    {
        g._e();
        for(var i = 0; i < this.spline.path.length; ++i)
        {
            var lastX, lastY;
            switch (this.spline.path[i].id )
            {
                case 0 :
                {
                    g._m(this.spline.path[i].x, this.spline.path[i].y);
                    lastX = this.spline.path[i].x;
                    lastY = this.spline.path[i].y;
                    break;
                }
                case 1 :
                {
                    g._l(this.spline.path[i].x, this.spline.path[i].y);
                    lastX = this.spline.path[i].x;
                    lastY = this.spline.path[i].y;
                    break;
                }
                case 2 :
                {
                    g._c(this.spline.path[i].x1, this.spline.path[i].y1, this.spline.path[i].x2, this.spline.path[i].y2, this.spline.path[i].x3, this.spline.path[i].y3);
                    lastX = this.spline.path[i].x3;
                    lastY = this.spline.path[i].y3;
                    break;
                }
            }
        }
        g.ds();
    }
}

    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].SplineCommandMoveTo = SplineCommandMoveTo;
    window['AscFormat'].SplineCommandLineTo = SplineCommandLineTo;
    window['AscFormat'].SplineCommandBezier = SplineCommandBezier;
    window['AscFormat'].Spline = Spline;
})(window);

/**
 * Created by Sergey.Luzyanin on 5/11/2017.
 */

(function () {
    function CConnectorTrack(oConnector, oBeginTrack, oEndTrack, oBeginShape, oEndShape){
        this.originalObject = oConnector;
        this.beginTrack = oBeginTrack;
        this.endTrack = oEndTrack;

        this.beginShape = oBeginShape;
        this.endShape = oEndShape;


        this.startX = this.originalObject.transform.TransformPointX(0, 0);
        this.startY = this.originalObject.transform.TransformPointY(0, 0);

        if(this.originalObject.group){
          //  var oInvertTransform = this.originalObject.group.invertTransform;
          //  var _stX =  oInvertTransform.TransformPointX(this.startX, this.startY);
          //  var _stY =  oInvertTransform.TransformPointY(this.startX, this.startY);
          //  this.startX = _stX;
          //  this.startY = _stY;
        }


        this.endX = this.originalObject.transform.TransformPointX(this.originalObject.extX, this.originalObject.extY);
        this.endY = this.originalObject.transform.TransformPointY(this.originalObject.extX, this.originalObject.extY);


        this.oSpPr = AscFormat.ExecuteNoHistory(function () {
            return oConnector.spPr.createDuplicate();
        }, this, []);
        AscFormat.XYAdjustmentTrack.call(this, oConnector, -1, false);

    }
    CConnectorTrack.prototype = Object.create(AscFormat.XYAdjustmentTrack.prototype);
    CConnectorTrack.prototype.track = function () {
        AscFormat.ExecuteNoHistory(function () {
            return this.track_();
        }, this, []);
    };
    CConnectorTrack.prototype.track_ = function()
    {

        var oConnectorInfo = this.originalObject.nvSpPr.nvUniSpPr;
        var _rot, track_bounds, g_conn_info, oConnectionObject, _flipH, _flipV, _bounds, _transform;
        var _startConnectionParams = null;
        var _endConnectionParams = null;
        var _group = null;
        if(this.originalObject.group) {
            _group = this.originalObject.group;
        }
        if(this.beginTrack){
            track_bounds = this.convertTrackBounds(this.beginTrack.getBounds());
            _rot = AscFormat.isRealNumber(this.beginTrack.angle) ? this.beginTrack.angle : this.beginTrack.originalObject.rot;
            _flipH =  AscFormat.isRealBool(this.beginTrack.resizedflipH) ? this.beginTrack.resizedflipH : this.beginTrack.originalObject.flipH;
            _flipV =  AscFormat.isRealBool(this.beginTrack.resizedflipV) ? this.beginTrack.resizedflipV : this.beginTrack.originalObject.flipV;
            if(this.beginTrack.originalObject.group){
                _rot = AscFormat.normalizeRotate(this.beginTrack.originalObject.group.getFullRotate() + _rot);
                if(this.beginTrack.originalObject.group.getFullFlipH()){
                    _flipH = !_flipH;
                }
                if(this.beginTrack.originalObject.group.getFullFlipV()){
                    _flipV = !_flipV;
                }
            }
            _bounds = track_bounds;
            _transform = this.beginTrack.overlayObject.TransformMatrix;
            //if(_group){
            //    _rot = AscFormat.normalizeRotate((this.beginTrack.originalObject.group ? this.beginTrack.originalObject.group.getFullRotate() : 0) + _rot - _group.getFullRotate());
            //    if(_group.getFullFlipH()){
            //        _flipH = !_flipH;
            //    }
            //    if(_group.getFullFlipV()){
            //        _flipV = !_flipV;
            //    }
            //    _bounds = _bounds.copy();
            //    _bounds.transform(_group.invertTransform);
            //    _transform = _transform.CreateDublicate();
            //    AscCommon.global_MatrixTransformer.MultiplyAppend(_transform, _group.invertTransform);
            //}
            oConnectionObject = this.beginTrack.overlayObject.geometry.cnxLst[oConnectorInfo.stCnxIdx];
            g_conn_info =  {idx: oConnectorInfo.stCnxIdx, ang: oConnectionObject.ang, x: oConnectionObject.x, y: oConnectionObject.y};
            _startConnectionParams = this.originalObject.convertToConnectionParams(_rot, _flipH, _flipV, _transform, _bounds, g_conn_info);
        }
        if(this.endTrack){
            track_bounds = this.convertTrackBounds(this.endTrack.getBounds());
            _rot = AscFormat.isRealNumber(this.endTrack.angle) ? this.endTrack.angle : this.endTrack.originalObject.rot;
            _flipH =  AscFormat.isRealBool(this.endTrack.resizedflipH) ? this.endTrack.resizedflipH : this.endTrack.originalObject.flipH;
            _flipV =  AscFormat.isRealBool(this.endTrack.resizedflipV) ? this.endTrack.resizedflipV : this.endTrack.originalObject.flipV;
            if(this.endTrack.originalObject.group){
                _rot = AscFormat.normalizeRotate(this.endTrack.originalObject.group.getFullRotate() + _rot);
                if(this.endTrack.originalObject.group.getFullFlipH()){
                    _flipH = !_flipH;
                }
                if(this.endTrack.originalObject.group.getFullFlipV()){
                    _flipV = !_flipV;
                }
            }
            _bounds = track_bounds;
            _transform = this.endTrack.overlayObject.TransformMatrix;
            //if(_group){
            //    _rot = AscFormat.normalizeRotate((this.endTrack.originalObject.group ? this.endTrack.originalObject.group.getFullRotate() : 0) + _rot - _group.getFullRotate());
            //    if(_group.getFullFlipH()){
            //        _flipH = !_flipH;
            //    }
            //    if(_group.getFullFlipV()){
            //        _flipV = !_flipV;
            //    }
            //    _bounds = _bounds.copy();
            //    _bounds.transform(_group.invertTransform);
            //    _transform = _transform.CreateDublicate();
            //    AscCommon.global_MatrixTransformer.MultiplyAppend(_transform, _group.invertTransform);
            //}
            oConnectionObject = this.endTrack.overlayObject.geometry.cnxLst[oConnectorInfo.endCnxIdx];
            g_conn_info =  {idx: oConnectorInfo.endCnxIdx, ang: oConnectionObject.ang, x: oConnectionObject.x, y: oConnectionObject.y};
            _endConnectionParams = this.originalObject.convertToConnectionParams(_rot, _flipH, _flipV, _transform, _bounds, g_conn_info);
        }
        if(_startConnectionParams || _endConnectionParams){
            var bMoveInGroup = false;

            if(!_startConnectionParams){
                if(this.beginShape && oConnectorInfo.stCnxIdx !== null){
                    _startConnectionParams = this.beginShape.getConnectionParams(oConnectorInfo.stCnxIdx, null);
                }
                else{
                    if((this.endTrack instanceof AscFormat.MoveShapeImageTrack)){
                        var _dx,_dy;
                        if(this.originalObject.group){
                            bMoveInGroup = true;
                            var _oCopyMatrix = this.originalObject.group.invertTransform.CreateDublicate();
                            _oCopyMatrix.tx = 0;
                            _oCopyMatrix.ty = 0;
                            _dx = _oCopyMatrix.TransformPointX(this.endTrack.lastDx, this.endTrack.lastDy);
                            _dy = _oCopyMatrix.TransformPointY(this.endTrack.lastDx, this.endTrack.lastDy);
                        }
                        else{
                            _dx = this.endTrack.lastDx;
                            _dy = this.endTrack.lastDy;
                        }
                        this.oSpPr = AscFormat.ExecuteNoHistory(function(){return this.originalObject.spPr.createDuplicate()}, this, []);
                        this.oSpPr.xfrm.offX += _dx;
                        this.oSpPr.xfrm.offY += _dy;
                        this.geometry = this.oSpPr.geometry;
                        this.overlayObject.geometry = this.geometry;
                        this.calculateTransform();
                        return;
                    }
                }
                if(!_startConnectionParams){
                    _startConnectionParams = AscFormat.fCalculateConnectionInfo(_endConnectionParams, this.startX, this.startY);
                }
            }

            if(!_endConnectionParams){
                if(this.endShape && oConnectorInfo.endCnxIdx !== null){
                    _endConnectionParams = this.endShape.getConnectionParams(oConnectorInfo.endCnxIdx, null);
                }
                else{
                    if((this.beginTrack instanceof AscFormat.MoveShapeImageTrack)){
                        var _dx,_dy;
                        if(this.originalObject.group){
                            bMoveInGroup = true;
                             var _oCopyMatrix = this.originalObject.group.invertTransform.CreateDublicate();
                             _oCopyMatrix.tx = 0;
                             _oCopyMatrix.ty = 0;
                            _dx = _oCopyMatrix.TransformPointX(this.beginTrack.lastDx, this.beginTrack.lastDy);
                            _dy = _oCopyMatrix.TransformPointY(this.beginTrack.lastDx, this.beginTrack.lastDy);
                        }
                        else{
                            _dx = this.beginTrack.lastDx;
                            _dy = this.beginTrack.lastDy;
                        }
                        this.oSpPr = AscFormat.ExecuteNoHistory(function(){return this.originalObject.spPr.createDuplicate()}, this, []);
                        this.oSpPr.xfrm.offX += _dx;
                        this.oSpPr.xfrm.offY += _dy;
                        this.geometry = this.oSpPr.geometry;
                        this.overlayObject.geometry = this.geometry;

                        if(!this.originalObject.group || bMoveInGroup){
                            this.oSpPr.xfrm.setOffX(this.oSpPr.xfrm.offX);
                            this.oSpPr.xfrm.setOffY(this.oSpPr.xfrm.offY);
                            this.oSpPr.xfrm.setFlipH(this.oSpPr.xfrm.flipH);
                            this.oSpPr.xfrm.setFlipV(this.oSpPr.xfrm.flipV);
                            this.oSpPr.xfrm.setRot(this.oSpPr.xfrm.rot);
                        }
                        else{

                            var _xc = this.oSpPr.xfrm.offX + this.oSpPr.xfrm.extX / 2.0;
                            var _yc = this.oSpPr.xfrm.offY + this.oSpPr.xfrm.extY / 2.0;
                            var xc = this.originalObject.group.invertTransform.TransformPointX(_xc, _yc);
                            var yc = this.originalObject.group.invertTransform.TransformPointY(_xc, _yc);
                            this.oSpPr.xfrm.setOffX(xc - this.oSpPr.xfrm.extX / 2.0);
                            this.oSpPr.xfrm.setOffY(yc - this.oSpPr.xfrm.extY / 2.0);
                            this.oSpPr.xfrm.setFlipH(this.originalObject.group.getFullFlipH() ? !this.oSpPr.xfrm.flipH : this.oSpPr.xfrm.flipH);
                            this.oSpPr.xfrm.setFlipV(this.originalObject.group.getFullFlipV() ? !this.oSpPr.xfrm.flipV : this.oSpPr.xfrm.flipV);
                            this.oSpPr.xfrm.setRot(AscFormat.normalizeRotate(this.oSpPr.xfrm.rot - this.originalObject.group.getFullRotate()));
                        }

                        this.calculateTransform();
                        return;
                    }
                }
                if(!_endConnectionParams){
                    _endConnectionParams = AscFormat.fCalculateConnectionInfo(_startConnectionParams, this.endX, this.endY);
                }
            }
            this.oSpPr = AscFormat.fCalculateSpPr(_startConnectionParams, _endConnectionParams, this.originalObject.spPr.geometry.preset, this.overlayObject.pen.w);
            if(!this.originalObject.group){
                this.oSpPr.xfrm.setOffX(this.oSpPr.xfrm.offX);
                this.oSpPr.xfrm.setOffY(this.oSpPr.xfrm.offY);
                this.oSpPr.xfrm.setFlipH(this.oSpPr.xfrm.flipH);
                this.oSpPr.xfrm.setFlipV(this.oSpPr.xfrm.flipV);
                this.oSpPr.xfrm.setRot(this.oSpPr.xfrm.rot);
            }
            else{

                var _xc = this.oSpPr.xfrm.offX + this.oSpPr.xfrm.extX / 2.0;
                var _yc = this.oSpPr.xfrm.offY + this.oSpPr.xfrm.extY / 2.0;
                var xc = this.originalObject.group.invertTransform.TransformPointX(_xc, _yc);
                var yc = this.originalObject.group.invertTransform.TransformPointY(_xc, _yc);
                this.oSpPr.xfrm.setOffX(xc - this.oSpPr.xfrm.extX / 2.0);
                this.oSpPr.xfrm.setOffY(yc - this.oSpPr.xfrm.extY / 2.0);
                this.oSpPr.xfrm.setFlipH(this.originalObject.group.getFullFlipH() ? !this.oSpPr.xfrm.flipH : this.oSpPr.xfrm.flipH);
                this.oSpPr.xfrm.setFlipV(this.originalObject.group.getFullFlipV() ? !this.oSpPr.xfrm.flipV : this.oSpPr.xfrm.flipV);
                this.oSpPr.xfrm.setRot(AscFormat.normalizeRotate(this.oSpPr.xfrm.rot - this.originalObject.group.getFullRotate()));
            }

            this.geometry = this.oSpPr.geometry;
            this.overlayObject.geometry = this.geometry;
            this.calculateTransform();
        }


    };

    CConnectorTrack.prototype.calculateTransform = function(){
        this.geometry.Recalculate(this.oSpPr.xfrm.extX, this.oSpPr.xfrm.extY);
        var _transform = this.transform;
        _transform.Reset();

        var _horizontal_center = this.oSpPr.xfrm.extX*0.5;
        var _vertical_center = this.oSpPr.xfrm.extY*0.5;
        global_MatrixTransformer.TranslateAppend(_transform, -_horizontal_center, -_vertical_center);
        if(this.oSpPr.xfrm.flipH)
        {
            global_MatrixTransformer.ScaleAppend(_transform, -1, 1);
        }
        if(this.oSpPr.xfrm.flipV)
        {
            global_MatrixTransformer.ScaleAppend(_transform, 1, -1);
        }
        global_MatrixTransformer.RotateRadAppend(_transform, -(AscFormat.isRealNumber(this.oSpPr.xfrm.rot) ? this.oSpPr.xfrm.rot : 0 ));
        global_MatrixTransformer.TranslateAppend(_transform, this.oSpPr.xfrm.offX, this.oSpPr.xfrm.offY);
        global_MatrixTransformer.TranslateAppend(_transform, _horizontal_center, _vertical_center);
        if(this.originalObject.group)
        {
            global_MatrixTransformer.MultiplyAppend(_transform, this.originalObject.group.transform);
        }
    };

    CConnectorTrack.prototype.trackEnd = function()
    {
        var _xfrm = this.originalObject.spPr.xfrm;
        var _xfrm2 = this.oSpPr.xfrm;
        _xfrm.setOffX(_xfrm2.offX);
        _xfrm.setOffY(_xfrm2.offY);
        _xfrm.setExtX(_xfrm2.extX);
        _xfrm.setExtY(_xfrm2.extY);
        _xfrm.setFlipH(_xfrm2.flipH);
        _xfrm.setFlipV(_xfrm2.flipV);
        _xfrm.setRot(_xfrm2.rot);
        this.originalObject.spPr.setGeometry(this.oSpPr.geometry.createDuplicate());

        this.originalObject.checkDrawingBaseCoords();
    };
    CConnectorTrack.prototype.convertTrackBounds = function(trackBounds)
    {
        return new AscFormat.CGraphicBounds(trackBounds.min_x, trackBounds.min_y, trackBounds.max_x, trackBounds.max_y);
    };

    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].CConnectorTrack = CConnectorTrack;
})();

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

// Import
var HANDLE_EVENT_MODE_HANDLE = AscFormat.HANDLE_EVENT_MODE_HANDLE;

function CheckCoordsNeedPage(x, y, pageIndex, needPageIndex, drawingDocument)
{
    if(pageIndex === needPageIndex)
        return {x:x, y:y};
    else
    {
        var  t = drawingDocument.ConvertCoordsToAnotherPage(x,y, pageIndex, needPageIndex);
        return {x: t.X, y: t.Y};
    }
}


function handleSelectedObjects(drawingObjectsController, e, x, y, group, pageIndex, bWord)
{
    var selected_objects = group ? group.selectedObjects : drawingObjectsController.getSelectedObjects();
    var tx, ty, t;
    var ret = null;
    var drawing = null;
    if(selected_objects.length === 1)
    {
        if(bWord && pageIndex !== selected_objects[0].selectStartPage)
        {
            t = drawingObjectsController.drawingDocument.ConvertCoordsToAnotherPage(x, y, pageIndex, selected_objects[0].selectStartPage);
            tx = t.X;
            ty = t.Y;
        }
        else
        {
            tx = x;
            ty = y;
        }
        var hit_to_adj = selected_objects[0].hitToAdjustment(tx, ty);
        if(hit_to_adj.hit)
        {
            ret = drawingObjectsController.handleAdjustmentHit(hit_to_adj, selected_objects[0], group, pageIndex);
            drawing = selected_objects[0];
        }
    }

    if(!ret)
    {
        for(var i = selected_objects.length - 1; i > -1; --i)
        {
            if(bWord && pageIndex !== selected_objects[i].selectStartPage)
            {
                t = drawingObjectsController.drawingDocument.ConvertCoordsToAnotherPage(x, y, pageIndex, selected_objects[i].selectStartPage);
                tx = t.X;
                ty = t.Y;
            }
            else
            {
                tx = x;
                ty = y;
            }

            if(selected_objects[i].getObjectType() === AscDFH.historyitem_type_ChartSpace)
            {
                ret = handleInternalChart(selected_objects[i], drawingObjectsController, e, tx, ty, group, pageIndex, bWord);
                if(ret)
                {
                    drawing = selected_objects[i];
                    break;
                }
            }
            if(!ret)
            {
                var hit_to_handles = selected_objects[i].hitToHandles(tx, ty);
                if(hit_to_handles > -1)
                {
                    ret = drawingObjectsController.handleHandleHit(hit_to_handles, selected_objects[i], group);
                    drawing = selected_objects[i];
                    break;
                }
            }
        }
    }

    if(!ret)
    {
        for(i = selected_objects.length - 1; i > -1; --i)
        {
            if(bWord && pageIndex !== selected_objects[i].selectStartPage)
            {
                t = drawingObjectsController.drawingDocument.ConvertCoordsToAnotherPage(x, y, pageIndex, selected_objects[i].selectStartPage);
                tx = t.X;
                ty = t.Y;
            }
            else
            {
                tx = x;
                ty = y;
            }
            if(selected_objects[i].getObjectType() === AscDFH.historyitem_type_ChartSpace)
            {
                ret = handleInternalChart(selected_objects[i], drawingObjectsController, e, tx, ty, group, pageIndex, bWord);
                drawing = selected_objects[i];
            }
            if(!ret)
            {
                if(selected_objects[i].hitInBoundingRect(tx, ty) /*&& (!selected_objects[i].hitInTextRect || !selected_objects[i].hitInTextRect(tx, ty))*/)
                {
                    if(bWord && selected_objects[i].parent && selected_objects[i].parent.Is_Inline())
                        ret = handleInlineHitNoText(selected_objects[i], drawingObjectsController, e, tx, ty, pageIndex, true);
                    else
                        ret = drawingObjectsController.handleMoveHit(selected_objects[i], e, tx, ty, group, true, selected_objects[i].selectStartPage, true);

                }
            }
            if(ret)
            {
                drawing = selected_objects[i];
                break;
            }
        }
    }
    if(ret && drawing)
    {
        if(drawingObjectsController.handleEventMode === AscFormat.HANDLE_EVENT_MODE_CURSOR  && drawingObjectsController &&
            drawingObjectsController.drawingObjects && drawingObjectsController.drawingObjects.cSld)
        {
            if(drawing.Lock.Is_Locked())
            {
                var MMData              = new AscCommon.CMouseMoveData();
                var Coords              =  drawingObjectsController.getDrawingDocument().ConvertCoordsToCursorWR(drawing.bounds.x, drawing.bounds.y, pageIndex, null);
                MMData.X_abs            = Coords.X - 5;
                MMData.Y_abs            = Coords.Y;
                MMData.Type             = AscCommon.c_oAscMouseMoveDataTypes.LockedObject;
                MMData.UserId           = drawing.Lock.Get_UserId();
                MMData.HaveChanges      = drawing.Lock.Have_Changes();
                editor.sync_MouseMoveCallback(MMData);
            }
        }
    }
    return ret;
}


function handleFloatObjects(drawingObjectsController, drawingArr, e, x, y, group, pageIndex, bWord)
{
    var ret = null, drawing;
    for(var i = drawingArr.length-1; i > -1; --i)
    {
        drawing = drawingArr[i];
        switch(drawing.getObjectType())
        {
            case AscDFH.historyitem_type_Shape:
            case AscDFH.historyitem_type_ImageShape:
            case AscDFH.historyitem_type_OleObject:
            case AscDFH.historyitem_type_Cnx:
            {
                ret = handleShapeImage(drawing, drawingObjectsController, e, x, y, group, pageIndex, bWord);
                break;
            }
            case AscDFH.historyitem_type_ChartSpace:
            {
                ret = handleChart(drawing, drawingObjectsController, e, x, y, group, pageIndex, bWord);
                break;
            }
            case AscDFH.historyitem_type_GroupShape:
            {
                ret = handleGroup(drawing, drawingObjectsController, e, x, y, group, pageIndex, bWord);
                break;
            }
            case AscDFH.historyitem_type_GraphicFrame:
            {
                ret = handleFloatTable(drawing, drawingObjectsController, e, x, y, group, pageIndex);
                break;
            }
        }

        if(ret)
        {
            if(drawingObjectsController.handleEventMode === AscFormat.HANDLE_EVENT_MODE_CURSOR  && drawingObjectsController &&
                drawingObjectsController.drawingObjects && drawingObjectsController.drawingObjects.cSld)
            {
                if(drawing.Lock.Is_Locked())
                {
                    var MMData              = new AscCommon.CMouseMoveData();
                    var Coords              =  drawingObjectsController.getDrawingDocument().ConvertCoordsToCursorWR(drawing.bounds.x, drawing.bounds.y, pageIndex, null);
                    MMData.X_abs            = Coords.X - 5;
                    MMData.Y_abs            = Coords.Y;
                    MMData.Type             = AscCommon.c_oAscMouseMoveDataTypes.LockedObject;
                    MMData.UserId           = drawing.Lock.Get_UserId();
                    MMData.HaveChanges      = drawing.Lock.Have_Changes();
                    editor.sync_MouseMoveCallback(MMData);
                }
            }
            return ret;
        }
    }
    return ret;
}

function handleShapeImage(drawing, drawingObjectsController, e, x, y, group, pageIndex, bWord)
{
    var hit_in_inner_area = drawing.hitInInnerArea(x, y);
    var hit_in_path = drawing.hitInPath(x, y);
    var hit_in_text_rect = drawing.hitInTextRect(x, y);
    if(hit_in_inner_area || hit_in_path)
    {
        if(drawingObjectsController.checkDrawingHyperlink){
            var ret =  drawingObjectsController.checkDrawingHyperlink(drawing, e, hit_in_text_rect, x, y, pageIndex);
            if(ret){
                return ret;
            }
        }
    }
    if(!hit_in_text_rect && (hit_in_inner_area || hit_in_path))
    {
        return drawingObjectsController.handleMoveHit(drawing, e, x, y, group, false, pageIndex, bWord);
    }
    else if(hit_in_text_rect)
    {
        if(bWord/* && (!drawing.txWarpStruct || drawingObjectsController.curState.startTargetTextObject === drawing || drawing.haveSelectedDrawingInContent && drawing.haveSelectedDrawingInContent())*/)
        {
            var all_drawings = drawing.getDocContent().GetAllDrawingObjects();
            var drawings2 = [];
            for(var i = 0; i < all_drawings.length; ++i)
            {
                drawings2.push(all_drawings[i].GraphicObj);
            }
            var ret = handleInlineObjects(drawingObjectsController, drawings2, e, x, y, pageIndex, bWord);
            if(ret)
                return ret;
        }
        return drawingObjectsController.handleTextHit(drawing, e, x, y, group, pageIndex, bWord);
    }
    return false;
}


function handleShapeImageInGroup(drawingObjectsController, drawing, shape, e, x, y, pageIndex, bWord)
{
    var hit_in_inner_area = shape.hitInInnerArea && shape.hitInInnerArea(x, y);
    var hit_in_path = shape.hitInPath && shape.hitInPath(x, y);
    var hit_in_text_rect = shape.hitInTextRect && shape.hitInTextRect(x, y);
    var ret;
    if(hit_in_inner_area || hit_in_path)
    {
        if(drawingObjectsController.checkDrawingHyperlink){
            var ret =  drawingObjectsController.checkDrawingHyperlink(shape, e, hit_in_text_rect, x, y, pageIndex);
            if(ret){
                return ret;
            }
        }
    }
    if(!hit_in_text_rect && (hit_in_inner_area || hit_in_path))
    {
        return drawingObjectsController.handleMoveHit(drawing, e, x, y, null, false, pageIndex, true);
    }
    else if(hit_in_text_rect)
    {
        if(bWord/* &&
            (!shape.txWarpStruct || drawingObjectsController.curState.startTargetTextObject === shape || shape.haveSelectedDrawingInContent && shape.haveSelectedDrawingInContent())*/) {
            var all_drawings = shape.getDocContent().GetAllDrawingObjects();
            var drawings2 = [];
            for (var i = 0; i < all_drawings.length; ++i) {
                drawings2.push(all_drawings[i].GraphicObj);
            }
            ret = handleInlineObjects(drawingObjectsController, drawings2, e, x, y, pageIndex, true);
            if (ret)
                return ret;
        }
        return drawingObjectsController.handleTextHit(shape, e, x, y, drawing, pageIndex, bWord);
    }
}

function handleGroup(drawing, drawingObjectsController, e, x, y, group, pageIndex, bWord)
{
    var grouped_objects = drawing.getArrGraphicObjects();
    var ret;
    for(var j = grouped_objects.length - 1; j > -1; --j)
    {
        var cur_grouped_object = grouped_objects[j];
        switch (cur_grouped_object.getObjectType())
        {
            case AscDFH.historyitem_type_Shape:
            case AscDFH.historyitem_type_ImageShape:
            case AscDFH.historyitem_type_OleObject:
            case AscDFH.historyitem_type_Cnx:
            {
                ret = handleShapeImageInGroup(drawingObjectsController, drawing, cur_grouped_object, e, x, y, pageIndex, bWord);
                if(ret)
                    return ret;
                break;
            }
            case AscDFH.historyitem_type_ChartSpace:
            {
                var ret, i, title;
                if(cur_grouped_object.hit(x, y))
                {
                    var chart_titles = cur_grouped_object.getAllTitles();
                    for(i = 0; i < chart_titles.length; ++i)
                    {
                        title = chart_titles[i];
                        var hit_in_inner_area = title.hitInInnerArea(x, y);
                        var hit_in_path = title.hitInPath(x, y);
                        var hit_in_text_rect = title.hitInTextRect(x, y);
                        if(hit_in_inner_area && !hit_in_text_rect || hit_in_path)
                        {
                            if(drawingObjectsController.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                            {
                                drawingObjectsController.checkChartTextSelection();
                                drawingObjectsController.resetSelection();
                                drawingObjectsController.selectObject(drawing, pageIndex);
                                drawingObjectsController.selection.groupSelection = drawing;
                                drawing.selectObject(cur_grouped_object, pageIndex);
                                drawing.chartSelection = cur_grouped_object;
                                drawing.selection.title = title;
                                cur_grouped_object.selectTitle(title, pageIndex);
                                drawingObjectsController.updateSelectionState();
                                return true;
                            }
                            else
                            {
                                return {objectId: drawing.Get_Id(), cursorType: "move", bMarker: false};
                            }
                        }
                        else if(hit_in_text_rect)
                        {
                            if(drawingObjectsController.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                            {
                                drawingObjectsController.checkChartTextSelection();
                                drawingObjectsController.resetSelection();
                                drawingObjectsController.selectObject(drawing, pageIndex);
                                drawingObjectsController.selection.groupSelection = drawing;
                                drawing.selectObject(cur_grouped_object, pageIndex);
                                drawing.selection.chartSelection = cur_grouped_object;
                                cur_grouped_object.selectTitle(title, pageIndex);
                                cur_grouped_object.selection.textSelection = title;
                                title.selectionSetStart(e, x, y, pageIndex);
                                drawingObjectsController.changeCurrentState(new AscFormat.TextAddState(drawingObjectsController, title, x, y));
                                if(e.ClickCount <= 1)
                                {
                                    drawingObjectsController.updateSelectionState();
                                }
                                return true;
                            }
                            else
                            {
                                if(drawingObjectsController.document)
                                {
                                    var content = title.getDocContent();
                                    var invert_transform_text = title.invertTransformText, tx, ty;
                                    if(content && invert_transform_text)
                                    {
                                        tx = invert_transform_text.TransformPointX(x, y);
                                        ty = invert_transform_text.TransformPointY(x, y);
                                        content.UpdateCursorType(tx, ty, 0);
                                    }
                                }
                                return {objectId: drawing.Get_Id(), cursorType: "text"};
                            }
                        }
                    }
                }
                ret = handleShapeImageInGroup(drawingObjectsController, drawing, cur_grouped_object, e, x, y, pageIndex, bWord);
                if(ret)
                    return ret;
                break;
            }
        }
    }
    return false;
}

function handleInternalChart(drawing, drawingObjectsController, e, x, y, group, pageIndex, bWord)
{
    if(e.CtrlKey || (e.Button === AscCommon.g_mouse_button_right && drawingObjectsController.selectedObjects.length > 1)){
        return false;
    }
    var ret = false, i, title;
    if(drawing.hit(x, y))
    {
        var bClickFlag = drawingObjectsController.handleEventMode === AscFormat.HANDLE_EVENT_MODE_CURSOR || e.ClickCount < 2;
        var selector = group ? group : drawingObjectsController;
        var legend = drawing.getLegend();
        if(legend && !window["NATIVE_EDITOR_ENJINE"] && legend.hit(x, y) && bClickFlag)
        {
            if(drawing.selection.legend != legend)
            {
                if(drawingObjectsController.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                {
                    drawingObjectsController.checkChartTextSelection();
                    selector.resetSelection();
                    selector.selectObject(drawing, pageIndex);
                    selector.selection.chartSelection = drawing;
                    drawing.selection.legend = legend;
                    drawingObjectsController.updateSelectionState();
                    drawingObjectsController.updateOverlay();
                    return true;
                }
                else
                {
                    return {objectId: drawing.Get_Id(), cursorType: "move", bMarker: false};
                }
            }
            else
            {
                var aCalcEntries = legend.calcEntryes;
                for(var i = 0; i < aCalcEntries.length; ++i)
                {
                    if(aCalcEntries[i].hit(x, y))
                    {
                        if(drawingObjectsController.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                        {
                            drawingObjectsController.checkChartTextSelection();
                            selector.resetSelection();
                            selector.selectObject(drawing, pageIndex);
                            selector.selection.chartSelection = drawing;
                            drawing.selection.legend = legend;
                            drawing.selection.legendEntry = aCalcEntries[i].idx;
                            drawingObjectsController.updateSelectionState();
                            drawingObjectsController.updateOverlay();
                            return true;
                        }
                        else
                        {
                            return {objectId: drawing.Get_Id(), cursorType: "default", bMarker: false};
                        }
                    }
                }
                if(drawingObjectsController.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                {
                    if(AscFormat.isRealNumber(drawing.selection.legendEntry))
                    {
                        drawing.selection.legendEntry = null;
                        drawingObjectsController.updateSelectionState();
                        drawingObjectsController.updateOverlay();
                    }
                    return true;
                }
                else
                {
                    return {objectId: drawing.Get_Id(), cursorType: "move", bMarker: false};
                }
            }
        }

        var oLabels;
        var aAxes = drawing.chart.plotArea.axId;
        for(var i = 0; i < aAxes.length; ++i){
            if(aAxes[i].labels){
                oLabels = aAxes[i].labels;
                if(oLabels.hit(x, y))
                {
                    if(drawingObjectsController.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                    {
                        drawingObjectsController.checkChartTextSelection();
                        selector.resetSelection();
                        selector.selectObject(drawing, pageIndex);
                        selector.selection.chartSelection = drawing;
                        drawing.selection.axisLbls = oLabels.axis;
                        drawingObjectsController.updateSelectionState();
                        drawingObjectsController.updateOverlay();
                        return true;
                    }
                    else
                    {
                        return {objectId: drawing.Get_Id(), cursorType: "default", bMarker: false};
                    }
                }
            }
        }

        if(!window["NATIVE_EDITOR_ENJINE"] && bClickFlag){

            var aCharts = drawing.chart.plotArea.charts;
            var series = drawing.getAllSeries();
            var _len = aCharts.length === 1 && aCharts[0].getObjectType() === AscDFH.historyitem_type_PieChart ? 1 : series.length;
            for(var i = _len - 1; i > -1; --i)
            {
                var ser = series[i];
                var pts = AscFormat.getPtsFromSeries(ser);
                for(var j = 0; j < pts.length; ++j)
                {
                    if(pts[j].compiledDlb)
                    {
                        if(pts[j].compiledDlb.hit(x, y))
                        {
                            var nDlbl = drawing.selection.dataLbls;
                            if(drawingObjectsController.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                            {
                                drawingObjectsController.checkChartTextSelection();
                                selector.resetSelection();
                                selector.selectObject(drawing, pageIndex);
                                selector.selection.chartSelection = drawing;
                                drawing.selection.dataLbls = i;
                                if(nDlbl === i)
                                {
                                    drawing.selection.dataLbl = j;
                                }
                                drawingObjectsController.updateSelectionState();
                                drawingObjectsController.updateOverlay();
                                return true;
                            }
                            else
                            {
                                return {objectId: drawing.Get_Id(), cursorType: "default", bMarker: false};
                            }
                        }
                    }

                }
            }

        }

        var chart_titles = drawing.getAllTitles();
        var oApi = editor || Asc['editor'];
        var bIsMobileVersion = oApi && oApi.isMobileVersion;
        for(i = 0; i < chart_titles.length; ++i)
        {
            title = chart_titles[i];
            var hit_in_inner_area = title.hitInInnerArea(x, y);
            var hit_in_path = title.hitInPath(x, y);
            var hit_in_text_rect = title.hitInTextRect(x, y);
            if((hit_in_inner_area && (!hit_in_text_rect || drawing.selection.title !== title) || (hit_in_path && bIsMobileVersion !== true)) && !window["NATIVE_EDITOR_ENJINE"])
            {
                if(drawingObjectsController.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                {
                    var is_selected =  drawing.selected;
                    drawingObjectsController.checkChartTextSelection();
                    selector.resetSelection();
                    selector.selectObject(drawing, pageIndex);
                    selector.selection.chartSelection = drawing;
                    drawing.selectTitle(title, pageIndex);
                    drawingObjectsController.updateSelectionState();
                    drawingObjectsController.updateOverlay();

                    if(Asc["editor"] && Asc["editor"].wb)
                    {
                        var ws = Asc["editor"].wb.getWorksheet();
                        if(ws){
                            var ct = ws.getCursorTypeFromXY(ws.objectRender.lastX, ws.objectRender.lastY);
                            if(ct){
                                Asc["editor"].wb._onUpdateCursor(ct.cursor);
                            }
                        }
                    }

                    return true;
                }
                else
                {
                    return {objectId: drawing.Get_Id(), cursorType: "move", bMarker: false};
                }
            }
            else if(hit_in_text_rect)
            {
                if(drawingObjectsController.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                {
                    var oTargetTextObject = AscFormat.getTargetTextObject(drawingObjectsController);
                    if(title !== oTargetTextObject)
                    {
                        drawingObjectsController.checkChartTextSelection();
                        selector.resetSelection();
                        selector.selectObject(drawing, pageIndex);
                        selector.selection.chartSelection = drawing;
                        drawing.selectTitle(title, pageIndex);
                        drawing.selection.textSelection = title;
                    }
                    title.selectionSetStart(e, x, y, pageIndex);
                    drawingObjectsController.changeCurrentState(new AscFormat.TextAddState(drawingObjectsController, title, x, y));
                    if(e.ClickCount <= 1)
                    {
                        drawingObjectsController.updateSelectionState();
                    }
                    return true;
                }
                else
                {
                    if(drawingObjectsController.document)
                    {
                        var content = title.getDocContent();
                        var invert_transform_text = title.invertTransformText, tx, ty;
                        if(content && invert_transform_text)
                        {
                            tx = invert_transform_text.TransformPointX(x, y);
                            ty = invert_transform_text.TransformPointY(x, y);
                            content.UpdateCursorType(tx, ty, 0);
                        }
                    }
                    return {objectId: drawing.Get_Id(), cursorType: "text", title: title};
                }
            }
        }

        //todo gridlines

        //plotArea
        if(bClickFlag ){
            var oChartSizes = drawing.getChartSizes(true);
            var oInvertTransform = drawing.invertTransform;
            var dTx = oInvertTransform.TransformPointX(x, y);
            var dTy = oInvertTransform.TransformPointY(x, y);
            if(dTx >= oChartSizes.startX && dTx <= oChartSizes.startX + oChartSizes.w
                && dTy >= oChartSizes.startY && dTy <= oChartSizes.startY + oChartSizes.h)
            {
                if(drawingObjectsController.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
                {
                    if(drawing.selection.plotArea == null || !AscFormat.CChartsDrawer.prototype._isSwitchCurrent3DChart(drawing) || !drawing.chartObj  || !drawing.chartObj.processor3D || !drawingObjectsController.canEdit())
                    {
                        drawingObjectsController.checkChartTextSelection();
                        selector.resetSelection();
                        selector.selectObject(drawing, pageIndex);
                        selector.selection.chartSelection = drawing;
                        drawing.selection.plotArea = drawing.chart.plotArea;
                    }
                    else
                    {
                        drawing.selection.plotArea = drawing.chart.plotArea;
                        drawing.selection.rotatePlotArea = true;

                        drawingObjectsController.updateSelectionState();
                        drawingObjectsController.updateOverlay();

                        drawingObjectsController.arrPreTrackObjects.length = 0;
                        drawingObjectsController.arrPreTrackObjects.push(new AscFormat.Chart3dAdjustTrack(drawing, 0, x, y));
                        if(!isRealObject(group))
                        {
                            drawingObjectsController.changeCurrentState(new AscFormat.PreChangeAdjState(drawingObjectsController, drawing));
                        }
                        else
                        {
                            drawingObjectsController.changeCurrentState(new AscFormat.PreChangeAdjInGroupState(drawingObjectsController, group));
                        }
                        var bOldIsLocked = e.IsLocked;
                        e.IsLocked = true;
                        drawingObjectsController.OnMouseMove(e, x, y, pageIndex);
                        e.IsLocked = bOldIsLocked;
                        return true;
                    }



                    drawingObjectsController.updateSelectionState();
                    drawingObjectsController.updateOverlay();
                    return true;
                }
                else
                {
                    return {objectId: drawing.Get_Id(), cursorType: "default", bMarker: false};
                }
            }
        }
    }
    return ret;
}

function handleChart(drawing, drawingObjectsController, e, x, y, group, pageIndex, bWord)
{
    var ret = handleInternalChart(drawing, drawingObjectsController, e, x, y, group, pageIndex, bWord);
    if(ret)
    {
        return ret;
    }
    ret = handleShapeImage(drawing, drawingObjectsController, e, x, y, group, pageIndex, bWord);
    if(ret)
        return ret;
    return false;
}


function handleInlineShapeImage(drawing, drawingObjectsController, e, x, y, pageIndex)
{
    var _hit = drawing.hit && drawing.hit(x, y);
    var _hit_to_path = drawing.hitInPath && drawing.hitInPath(x, y);
    var b_hit_to_text = drawing.hitInTextRect && drawing.hitInTextRect(x, y);
    if((_hit && !b_hit_to_text) || _hit_to_path)
    {
        return handleInlineHitNoText(drawing, drawingObjectsController, e, x, y, pageIndex, false);
    }
    else if(b_hit_to_text)
    {
        if(drawing.bWordShape /*&& (!drawing.txWarpStruct || drawingObjectsController.curState.startTargetTextObject === drawing || drawing.haveSelectedDrawingInContent && drawing.haveSelectedDrawingInContent())*/)
        {
            var all_drawings = drawing.getDocContent().GetAllDrawingObjects();
            var drawings2 = [];
            for(var i = 0; i < all_drawings.length; ++i)
            {
                drawings2.push(all_drawings[i].GraphicObj);
            }
            var ret = handleInlineObjects(drawingObjectsController, drawings2, e, x, y, pageIndex, true);
            if(ret)
                return ret;
        }
        return drawingObjectsController.handleTextHit(drawing, e, x, y, null, pageIndex, true);
    }
}

function handleInlineChart(drawing, drawingObjectsController, e, x, y, pageIndex)
{
    var ret = handleInternalChart(drawing, drawingObjectsController, e, x, y, null, pageIndex, true);
    if(ret)
    {
        return ret;
    }
    return handleInlineShapeImage(drawing, drawingObjectsController, e, x, y, pageIndex);
}

function handleInlineHitNoText(drawing, drawingObjects, e, x, y, pageIndex, bInSelect)
{
    var selected_objects = drawingObjects.selectedObjects;
    if(!(e.CtrlKey || e.ShiftKey)
        || selected_objects.length === 0 ||
        selected_objects.length === 1 && selected_objects[0] === drawing)
    {
        if(drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
        {
            var bIsSelected = drawing.selected;
            drawingObjects.checkChartTextSelection();
            drawingObjects.resetSelection();
            drawing.select(drawingObjects, pageIndex);
            drawingObjects.changeCurrentState(new AscFormat.PreMoveInlineObject(drawingObjects, drawing, bIsSelected, !bInSelect, pageIndex, x, y));
            if(e.ClickCount > 1 && !e.ShiftKey && !e.CtrlKey && ((drawingObjects.selection.groupSelection && drawingObjects.selection.groupSelection.selectedObjects.length === 1) || drawingObjects.selectedObjects.length === 1))
            {
                if (drawing.getObjectType() === AscDFH.historyitem_type_ChartSpace && drawingObjects.handleChartDoubleClick)
                    drawingObjects.handleChartDoubleClick(drawing.parent, drawing, e, x, y, pageIndex);
                else if (drawing.getObjectType() === AscDFH.historyitem_type_OleObject && drawingObjects.handleChartDoubleClick){
                    drawingObjects.handleOleObjectDoubleClick(drawing.parent, drawing, e, x, y, pageIndex);
                }
                else if (drawing.signatureLine && drawingObjects.handleSignatureDblClick){
                    drawingObjects.handleSignatureDblClick(drawing.signatureLine.id, drawing.extX, drawing.extY);
                }
                else if (2 == e.ClickCount && drawing.parent instanceof ParaDrawing && drawing.parent.Is_MathEquation())
                    drawingObjects.handleMathDrawingDoubleClick(drawing.parent, e, x, y, pageIndex);

            }
            drawingObjects.updateOverlay();
            return true;
        }
        else
        {
            return {objectId: drawing.Get_Id(), cursorType:"move"};
        }
    }
    if(drawingObjects.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
    {
        return {objectId: drawing.Get_Id(), cursorType:"move"};
    }
    return false;
}
function handleInlineObjects(drawingObjectsController, drawingArr, e, x, y, pageIndex, bWord)
{
    var i;
    var drawing, ret;
    for(i = drawingArr.length-1; i > -1; --i)
    {
        drawing = drawingArr[i];

        if(drawing.parent && AscFormat.isRealNumber(drawing.parent.LineTop) && AscFormat.isRealNumber(drawing.parent.LineBottom))
        {
            if(y < drawing.parent.LineTop || y > drawing.parent.LineBottom)
            {
                continue;
            }
        }
        switch(drawing.getObjectType())
        {
            case AscDFH.historyitem_type_Shape:
            case AscDFH.historyitem_type_ImageShape:
            case AscDFH.historyitem_type_OleObject:
            case AscDFH.historyitem_type_Cnx:
            {
                ret = handleInlineShapeImage(drawing, drawingObjectsController, e, x, y, pageIndex);
                if(ret)
                    return ret;
                break;
            }
            case AscDFH.historyitem_type_ChartSpace:
            {
                ret  = handleInlineChart(drawing, drawingObjectsController, e, x, y, pageIndex);
                if(ret)
                    return ret;
                break;
            }
            case AscDFH.historyitem_type_GroupShape:
            {
                ret = handleGroup(drawing, drawingObjectsController, e, x, y, null, pageIndex, bWord);
                if(ret)
                    return ret;
                break;
            }
        }
    }
    return false;
}

function handleMouseUpPreMoveState(drawingObjects, e, x, y, pageIndex, bWord)
{
    var state = drawingObjects.curState;
    state.drawingObjects.clearPreTrackObjects();
    state.drawingObjects.changeCurrentState(new AscFormat.NullState(state.drawingObjects));
    var bHandle = false;
    if(!state.shift && !state.ctrl && state.bInside && state.majorObjectIsSelected && e.Button !== AscCommon.g_mouse_button_right)
    {
        switch (state.majorObject.getObjectType())
        {
            case AscDFH.historyitem_type_GroupShape:
            {
                state.drawingObjects.checkChartTextSelection();
                state.drawingObjects.resetSelection();
                state.drawingObjects.selectObject(state.majorObject, pageIndex);
                state.drawingObjects.selection.groupSelection = state.majorObject;
                state.drawingObjects.OnMouseDown(e,x, y,pageIndex);
                state.drawingObjects.OnMouseUp(e, x, y, pageIndex);
                state.drawingObjects.drawingObjects && state.drawingObjects.drawingObjects.sendGraphicObjectProps &&  state.drawingObjects.drawingObjects.sendGraphicObjectProps();
                state.drawingObjects.document && state.drawingObjects.document.Document_UpdateInterfaceState();
                bHandle = true;
                break;
            }
            case AscDFH.historyitem_type_ChartSpace:
            {
                break;
            }
        }
    }
    if(!bHandle)
    {
        if(e.CtrlKey && state.majorObjectIsSelected)
        {
            drawingObjects.deselectObject(state.majorObject);
            state.drawingObjects.drawingObjects && state.drawingObjects.drawingObjects.sendGraphicObjectProps &&  state.drawingObjects.drawingObjects.sendGraphicObjectProps();
            state.drawingObjects.document && state.drawingObjects.document.Document_UpdateInterfaceState();
            drawingObjects.updateOverlay();
        }
    }
}

function handleFloatTable(drawing, drawingObjectsController, e, x, y, group, pageIndex)
{
    if(drawing.hitInBoundingRect(x, y))
    {
        return drawingObjectsController.handleMoveHit(drawing, e, x, y, group, false, pageIndex, false);
    }
    else
    {
        if(drawing.hitInInnerArea(x, y))
        {
            var content, invert_transform_text, tx, ty, hit_paragraph, par, check_hyperlink;
            if(drawingObjectsController.handleEventMode === HANDLE_EVENT_MODE_HANDLE)
            {
                drawingObjectsController.resetSelection(true);
                (group ? group : drawingObjectsController).selectObject(drawing,pageIndex);
                if(!group)
                {
                    drawingObjectsController.selection.textSelection = drawing;
                    drawing.selectionSetStart(e, x, y, pageIndex);
                }
                else
                {
                    group.selection.textSelection = drawing;
                    drawing.selectionSetStart(e, x, y, pageIndex);
                    drawingObjectsController.selectObject(group, pageIndex);
                    drawingObjectsController.selection.groupSelection = group;
                }
                drawingObjectsController.changeCurrentState(new AscFormat.TextAddState(drawingObjectsController, drawing, x, y));
                return true;
            }
            else
            {
                drawing.updateCursorType(x, y, e);
                return {objectId: drawing.Get_Id(), cursorType: "text", updated: true};
            }
        }
    }
    return false;
}

    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].CheckCoordsNeedPage = CheckCoordsNeedPage;
    window['AscFormat'].handleSelectedObjects = handleSelectedObjects;
    window['AscFormat'].handleFloatObjects = handleFloatObjects;
    window['AscFormat'].handleInlineObjects = handleInlineObjects;
    window['AscFormat'].handleMouseUpPreMoveState = handleMouseUpPreMoveState;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

// Import
var g_fontApplication = AscFonts.g_fontApplication;

var g_oTextMeasurer = AscCommon.g_oTextMeasurer;
    
var Geometry = AscFormat.Geometry;
var EPSILON_TEXT_AUTOFIT = AscFormat.EPSILON_TEXT_AUTOFIT;
var ObjectToDraw = AscFormat.ObjectToDraw;

var PATH_DIV_EPSILON = 0.1;
var UNDERLINE_DIV_EPSILON = 3;


function ParaDrawingStruct(nPageIndex, pDrawing)
{
    this.oDrawing = pDrawing;
    this.nPageIndex = nPageIndex;
}
ParaDrawingStruct.prototype.Draw = function(pGraphics)
{
    if(this.oDrawing)
    {
        this.oDrawing.Draw( 0, 0, pGraphics, this.nPageIndex, 0)
    }
};

function CDocContentStructure()
{
    this.m_nType = DRAW_COMMAND_CONTENT;
    this.m_aContent = [];
    this.m_aByLines = null;
    this.m_aDrawingsStruct = [];
    this.m_aBackgrounds = [];
    this.m_aBorders = [];
    this.m_aParagraphBackgrounds = [];
    this.m_oBoundsRect1 = null;
    this.m_oBoundsRect2 = null;
    this.m_aComments = [];
}

CDocContentStructure.prototype.Recalculate = function(oTheme, oColorMap, dWidth, dHeight, oShape)
{
    for(var i = 0; i < this.m_aContent.length; ++i)
    {
        this.m_aContent[i].Recalculate(oTheme, oColorMap, dWidth, dHeight, oShape);
    }
};
CDocContentStructure.prototype.CheckContentStructs = function(aContentStructs)
{
    for(var i = 0; i < this.m_aContent.length; ++i)
    {
        this.m_aContent[i].CheckContentStructs(aContentStructs);
    }
};
CDocContentStructure.prototype.draw = function(graphics, transform, oTheme, oColorMap)
{
    var i;
    for(i = 0; i < this.m_aDrawingsStruct.length; ++i)
    {
        this.m_aDrawingsStruct[i].Draw(graphics);
    }

    for(i = 0; i < this.m_aParagraphBackgrounds.length; ++i)
    {
        this.m_aParagraphBackgrounds[i].draw(graphics, undefined, transform, oTheme, oColorMap);
    }
    for(i = 0; i < this.m_aBorders.length; ++i)
    {
        this.m_aBorders[i].draw(graphics);
    }
    for(i = 0; i < this.m_aBackgrounds.length; ++i)
    {
        this.m_aBackgrounds[i].draw(graphics, undefined, transform, oTheme, oColorMap);
    }
    for(i = 0; i < this.m_aContent.length; ++i)
    {
        this.m_aContent[i].draw(graphics, transform, oTheme, oColorMap);
    }
};
CDocContentStructure.prototype.drawComments = function(graphics, transform)
{
    var i;
    for(i = 0; i < this.m_aComments.length; ++i)
    {
        this.m_aComments[i].drawComment2(graphics, undefined, transform);
    }
};
CDocContentStructure.prototype.checkByWarpStruct = function(oWarpStruct, dWidth, dHeight, oTheme, oColorMap, oShape, dOneLineWidth, XLimit, dContentHeight, dKoeff)
{
    var i, j, t, aByPaths,  aWarpedObjects = [];
    var bOddPaths = oWarpStruct.pathLst.length / 2 - ((oWarpStruct.pathLst.length / 2) >> 0) > 0;
    var nDivCount = bOddPaths ? oWarpStruct.pathLst.length : oWarpStruct.pathLst.length >> 1, oNextPointOnPolygon, oObjectToDrawNext, oMatrix = new AscCommon.CMatrix();
    aByPaths = oWarpStruct.getArrayPolygonsByPaths(PATH_DIV_EPSILON);
    var nLastIndex = 0, dTmp, oBoundsChecker, oTemp, nIndex, aWarpedObjects2 = [];
    oBoundsChecker = new AscFormat.CSlideBoundsChecker();
    oBoundsChecker.init(100, 100, 100, 100);
    var dMinX, dMaxX;
    for(j = 0; j < this.m_aByLines.length; ++j)
    {
        oTemp = this.m_aByLines[j];
        for(t = 0; t < oTemp.length; ++t)
        {
            oTemp[t].GetAllWarped(aWarpedObjects2);
            oTemp[t].CheckBoundsWarped(oBoundsChecker);
        }
    }
    dMinX = oBoundsChecker.Bounds.min_x;
    dMaxX = oBoundsChecker.Bounds.max_x;
    for( i = 0; i < nDivCount; ++i)
    {
        dTmp = (this.m_aByLines.length - nLastIndex)/(nDivCount - i);
        nIndex = nLastIndex + (dTmp >> 0) + ((dTmp - (dTmp >> 0)) > 0 ? 1 : 0);
        aWarpedObjects.length = 0;
        oBoundsChecker.Bounds.ClearNoAttack();
        for(j = nLastIndex; j < nIndex; ++j)
        {
            oTemp = this.m_aByLines[j];
            for(t = 0; t < oTemp.length; ++t)
            {
                oTemp[t].GetAllWarped(aWarpedObjects);
                oTemp[t].CheckBoundsWarped(oBoundsChecker);
            }
        }
        if(oBoundsChecker.Bounds.min_x > dMinX)
        {
            oBoundsChecker.Bounds.min_x = dMinX;
        }
        if(oBoundsChecker.Bounds.max_x < dMaxX)
        {
            oBoundsChecker.Bounds.max_x = dMaxX;
        }
        if(!bOddPaths)
        {
            ObjectsToDrawBetweenTwoPolygons(aWarpedObjects, oBoundsChecker.Bounds, new PolygonWrapper(aByPaths[i << 1]), new PolygonWrapper(aByPaths[(i << 1) + 1]));
        }
        else
        {
            oNextPointOnPolygon = null;
            oObjectToDrawNext = null;
            var oPolygon = new PolygonWrapper(aByPaths[i]);
            for(t = 0; t < aWarpedObjects.length; ++t)
            {
                var oWarpedObject = aWarpedObjects[t];
                var bArcDown = "textArchDown" !== oWarpStruct.preset && i < 1;
                if(!AscFormat.isRealNumber(oWarpedObject.x) || !AscFormat.isRealNumber(oWarpedObject.y) )
                {
                    CheckGeometryByPolygon(oWarpedObject, oPolygon, bArcDown, XLimit*dKoeff, dContentHeight, dKoeff, nDivCount > 1 ? oBoundsChecker.Bounds : null);
                }
                else
                {
                    oNextPointOnPolygon = this.checkTransformByOddPath(oMatrix, oWarpedObject, aWarpedObjects[t+1], oNextPointOnPolygon, dContentHeight, dKoeff, bArcDown, oPolygon, XLimit);
                    TransformGeometry(oWarpedObject, oMatrix);
                }
            }
        }
        nLastIndex = nIndex;
    }
    this.checkUnionPaths(aWarpedObjects2);
};



CDocContentStructure.prototype.checkContentReduct = function(oWarpStruct, dWidth, dHeight, oTheme, oColorMap, oShape, dOneLineWidth, XLimit, dContentHeight, dKoeff)
{
    var i, j, t, aByPaths,  aWarpedObjects = [];
    var bOddPaths = oWarpStruct.pathLst.length / 2 - ((oWarpStruct.pathLst.length / 2) >> 0) > 0;
    var nDivCount = bOddPaths ? oWarpStruct.pathLst.length : oWarpStruct.pathLst.length >> 1, oNextPointOnPolygon, oObjectToDrawNext, oMatrix;
    aByPaths = oWarpStruct.getArrayPolygonsByPaths(PATH_DIV_EPSILON);
    var nLastIndex = 0, dTmp, oBoundsChecker, oTemp, nIndex, aWarpedObjects2 = [];
    oBoundsChecker = new AscFormat.CSlideBoundsChecker();
    oBoundsChecker.init(100, 100, 100, 100);
    for(j = 0; j < this.m_aByLines.length; ++j)
    {
        oTemp = this.m_aByLines[j];
        for(t = 0; t < oTemp.length; ++t)
        {
            oTemp[t].GetAllWarped(aWarpedObjects2);
            oTemp[t].CheckBoundsWarped(oBoundsChecker);
        }
    }
    var aBounds = [];
    var oRet = {maxDx: 0, maxDy: 0};
    for( i = 0; i < nDivCount; ++i)
    {
        dTmp = (this.m_aByLines.length - nLastIndex)/(nDivCount - i);
        nIndex = nLastIndex + (dTmp >> 0) + ((dTmp - (dTmp >> 0)) > 0 ? 1 : 0);
        aWarpedObjects.length = 0;
        for(j = nLastIndex; j < nIndex; ++j)
        {
            oTemp = this.m_aByLines[j];
            for(t = 0; t < oTemp.length; ++t)
            {
                oTemp[t].GetAllWarped(aWarpedObjects);
            }
        }
        var bArcDown = "textArchDown" !== oWarpStruct.preset && i < 1;
        if(bOddPaths)
        {
            oNextPointOnPolygon = null;
            oObjectToDrawNext = null;
            var oPolygon = new PolygonWrapper(aByPaths[i]);
            for(t = 0; t < aWarpedObjects.length; ++t)
            {
                var oWarpedObject = aWarpedObjects[t];
                if(AscFormat.isRealNumber(oWarpedObject.x) && AscFormat.isRealNumber(oWarpedObject.y) )
                {
                    oMatrix = new AscCommon.CMatrix();
                    oBoundsChecker.Bounds.ClearNoAttack();
                    oNextPointOnPolygon = this.checkTransformByOddPath(oMatrix, oWarpedObject, aWarpedObjects[t+1], oNextPointOnPolygon, dContentHeight, dKoeff, bArcDown, oPolygon, XLimit);
                    oWarpedObject.draw(oBoundsChecker);

                    var oBounds = new AscFormat.CBoundsController();
//                    oBounds.fromBounds(oBoundsChecker.Bounds);
                    for(var k = 0; k < aBounds.length; ++k)
                    {
                        var oIntersection = this.checkIntersectionBounds( aBounds[k].Bounds, aBounds[k].Transform, oBounds, oMatrix, aBounds.length - k);
                        if(oIntersection.DX > oRet.maxDx)
                        {
                            oRet.maxDx = oIntersection.DX;
                        }
                        if(oIntersection.DY < oRet.maxDy)
                        {
                            oRet.maxDy = oIntersection.DY;
                        }
                    }
                    aBounds.push({Bounds: oBounds, Transform: oMatrix});
                }
            }
        }
        nLastIndex = nIndex;
    }
    return oRet;
};

CDocContentStructure.prototype.getAllBackgroundsBorders = function(aParaBackgrounds, aBackgrounds, aBorders, aComments)
{
    for(var i = 0; i < this.m_aContent.length; ++i)
    {
        this.m_aContent[i].getAllBackgroundsBorders(aParaBackgrounds, aBackgrounds, aBorders, aComments);
    }
}

function CheckIntervalIntersection(X1, Y1, X2, Y2, X3, Y3, X4, Y4)
{
    return  (((X3-X1)*(Y2-Y1) - (Y3-Y1)*(X2-X1)) *
        ((X4-X1)*(Y2-Y1) - (Y4-Y1)*(X2-X1)) >= 0)&&
        (((X1-X3)*(Y4-Y3) - (Y1-Y3)*(X4-X3)) *
            ((X2-X3)*(Y4-Y3) - (Y2-Y3)*(X4-X3)) >= 0);
}

function BoundsRect()
{
    this.arrBounds = [
        {X0:0, Y0: 0, X1: 0, Y1:0},
        {X0:0, Y0: 0, X1: 0, Y1:0},
        {X0:0, Y0: 0, X1: 0, Y1:0},
        {X0:0, Y0: 0, X1: 0, Y1:0}
    ]
}

BoundsRect.prototype.fromBoundsAndTransform = function(oBounds, oTransform)
{
    this.arrBounds[0].X0 = oTransform.TransformPointX(oBounds.min_x, oBounds.min_y);
    this.arrBounds[0].Y0 = oTransform.TransformPointY(oBounds.min_x, oBounds.min_y);
    this.arrBounds[0].X1 = oTransform.TransformPointX(oBounds.max_x, oBounds.min_y);
    this.arrBounds[0].Y1 = oTransform.TransformPointY(oBounds.max_x, oBounds.min_y);

    this.arrBounds[1].X0 = oTransform.TransformPointX(oBounds.max_x, oBounds.max_y);
    this.arrBounds[1].Y0 = oTransform.TransformPointY(oBounds.max_x, oBounds.max_y);
    this.arrBounds[1].X1 = oTransform.TransformPointX(oBounds.max_x, oBounds.min_y);
    this.arrBounds[1].Y1 = oTransform.TransformPointY(oBounds.max_x, oBounds.min_y);

    this.arrBounds[2].X0 = oTransform.TransformPointX(oBounds.max_x, oBounds.max_y);
    this.arrBounds[2].Y0 = oTransform.TransformPointY(oBounds.max_x, oBounds.max_y);
    this.arrBounds[2].X1 = oTransform.TransformPointX(oBounds.min_x, oBounds.max_y);
    this.arrBounds[2].Y1 = oTransform.TransformPointY(oBounds.min_x, oBounds.max_y);

    this.arrBounds[3].X0 = oTransform.TransformPointX(oBounds.min_x, oBounds.max_y);
    this.arrBounds[3].Y0 = oTransform.TransformPointY(oBounds.min_x, oBounds.max_y);
    this.arrBounds[3].X1 = oTransform.TransformPointX(oBounds.min_x, oBounds.min_y);
    this.arrBounds[3].Y1 = oTransform.TransformPointY(oBounds.min_x, oBounds.min_y);
};



BoundsRect.prototype.checkIntersection = function(oBoundsRect)
{
    var i, j, oCurBound1, oCurBound2;
    for(i = 0; i < 4; ++i)
    {
        oCurBound1 = this.arrBounds[i];
        for(j = 0; j < 4; ++j)
        {
            oCurBound2 = oBoundsRect[j];
            if(CheckIntervalIntersection(oCurBound1.X0, oCurBound1.Y0, oCurBound1.X1, oCurBound1.Y1, oCurBound2.X0, oCurBound2.Y0, oCurBound2.X1, oCurBound2.Y1))
            {
                return true;
            }
        }
    }
    return false;
};

BoundsRect.prototype.getParamValueProjection = function(x0, y0, x1, y1, x, y)
{
    var dX = (x1-x0), dY = (y1 - y0);

    if(Math.abs(dX) > 0 )
    {
        var dXSq = dX*dX;
        var xi = (x*dXSq + dX*dY*y - dY*(x1*y0-x0*y1))/(dXSq + dY*dY);
        return (xi - x1)/dX;
    }
    else if(Math.abs(dY) > 0)
    {
        var dYSq = dY*dY;
        var yi = (y*dYSq + dX*dY*x + dX*(x1*y0 - x0*y1))/(dX*dX + dYSq);
        return (yi - y1)/dY;
    }
    return -1;
};

BoundsRect.prototype.checkIntervalProjection = function(oInterval1, oInterval2)
{
    var param0  = this.getParamValueProjection(oInterval1.X0, oInterval1.Y0, oInterval1.X1, oInterval1.Y1, oInterval2.X0, oInterval2.Y0);
    var param1  = this.getParamValueProjection(oInterval1.X0, oInterval1.Y0, oInterval1.X1, oInterval1.Y1, oInterval2.X1, oInterval2.Y1);
    if(Math.abs(param0 - 0.5) <= 0.5 || Math.abs(param1 - 0.5) <= 0.5)
    {
        var dX = (oInterval1.X0 - oInterval1.X1), dY = (oInterval1.Y0 - oInterval1.Y1);
        var dLen = Math.sqrt(dX*dX + dY*dY);
        return ((param1 > 1  ? 1 : (param1 < 0 ? 0 : param1)) - (param0 > 1  ? 1 : (param0 < 0 ? 0 : param0)))*dLen;
    }
    else
    {
        return 0;
    }
};


BoundsRect.prototype.checkBoundsRectProjection = function(oBoundsRect)
{
    var dX = 0, dY = 0, dLTemp;

    dLTemp = this.checkIntervalProjection(this.arrBounds[1], oBoundsRect.arrBounds[1]);
    if(dLTemp < dY)
    {
        dY = dLTemp;
    }
    dLTemp = this.checkIntervalProjection(this.arrBounds[1], oBoundsRect.arrBounds[3]);
    if(dLTemp < dY)
    {
        dY = dLTemp;
    }
    dLTemp = this.checkIntervalProjection(this.arrBounds[3], oBoundsRect.arrBounds[1]);
    if(dLTemp < dY)
    {
        dY = dLTemp;
    }
    dLTemp = this.checkIntervalProjection(this.arrBounds[3], oBoundsRect.arrBounds[3]);
    if(dLTemp < dY)
    {
        dY = dLTemp;
    }

    dLTemp = this.checkIntervalProjection(this.arrBounds[2], oBoundsRect.arrBounds[1]);
    if(Math.abs(dLTemp) > dX)
    {
        dX = Math.abs(dLTemp);
    }

    dLTemp = this.checkIntervalProjection(this.arrBounds[2], oBoundsRect.arrBounds[3]);
    if(Math.abs(dLTemp) > dX)
    {
        dX = Math.abs(dLTemp);
    }

    dLTemp = this.checkIntervalProjection(this.arrBounds[0], oBoundsRect.arrBounds[1]);
    if(Math.abs(dLTemp) > dX)
    {
        dX = Math.abs(dLTemp);
    }

    dLTemp = this.checkIntervalProjection(this.arrBounds[0], oBoundsRect.arrBounds[3]);
    if(Math.abs(dLTemp) > dX)
    {
        dX = Math.abs(dLTemp);
    }

    return {DX: dX, DY: dY};
};

CDocContentStructure.prototype.checkIntersectionBounds = function(oBounds1, oTransform1, oBounds2, oTransform2, nDist)
{
    if(!this.m_oBoundsRect1)
    {
        this.m_oBoundsRect1 = new BoundsRect();
        this.m_oBoundsRect2 = new BoundsRect();
    }
    this.m_oBoundsRect1.fromBoundsAndTransform(oBounds1, oTransform1);
    this.m_oBoundsRect2.fromBoundsAndTransform(oBounds2, oTransform2);
    if(this.m_oBoundsRect1.checkIntersection(this.m_oBoundsRect2.arrBounds))
    {
        var oBounds = this.m_oBoundsRect1.checkBoundsRectProjection(this.m_oBoundsRect2);
        oBounds.DX/=nDist;
        return oBounds;
    }
    return {DX: 0, DY: 0};
};

CDocContentStructure.prototype.checkTransformByOddPath = function(oMatrix, oWarpedObject, oObjectToDrawNext, oNextPointOnPolygon, dContentHeight, dKoeff, bArcDown, oPolygon, XLimit)
{
    var x0, y0, x1, y1, x0t, y0t, x1t, y1t, cX, cX2, dX, dY, dX2, dY2, dNorm, oPointOnPolygon;
    x0 = oWarpedObject.x*dKoeff;
    y0 = oWarpedObject.y*dKoeff;
    x1 = x0;
    if(bArcDown)
    {
        y1 = 0;
    }
    else
    {
        y1 = dContentHeight*dKoeff;
    }
    cX = oWarpedObject.x/XLimit;
    var oRet = null;
    if(oNextPointOnPolygon)
    {
        oPointOnPolygon = oNextPointOnPolygon;
    }
    else
    {
        oPointOnPolygon = oPolygon.getPointOnPolygon(cX, true);
    }
    x1t = oPointOnPolygon.x;
    y1t = oPointOnPolygon.y;
    dX = oPointOnPolygon.oP2.x - oPointOnPolygon.oP1.x;
    dY = oPointOnPolygon.oP2.y - oPointOnPolygon.oP1.y;

    if(bArcDown)
    {
        dX = -dX;
        dY = -dY;
    }
    if(oObjectToDrawNext && AscFormat.isRealNumber(oObjectToDrawNext.x) && AscFormat.isRealNumber(oObjectToDrawNext.y) && oObjectToDrawNext.x > oWarpedObject.x)
    {
        cX2 = (oObjectToDrawNext.x)/XLimit;
        oRet = oPolygon.getPointOnPolygon(cX2, true);
        dX2 = oRet.oP2.x - oRet.oP1.x;
        dY2 = oRet.oP2.y - oRet.oP1.y;
        if(bArcDown)
        {
            dX2 = -dX2;
            dY2 = -dY2;
        }
        dX = dX + dX2;
        dY = dY + dY2;
    }
    else
    {
        oRet = null;
    }
    dNorm = Math.sqrt(dX*dX + dY*dY);

    if(bArcDown)
    {
        x0t = x1t + (dY/dNorm)*(y0);
        y0t = y1t - (dX/dNorm)*(y0);
    }
    else
    {
        x0t = x1t + (dY/dNorm)*(dContentHeight*dKoeff - y0);
        y0t = y1t - (dX/dNorm)*(dContentHeight*dKoeff - y0);
    }
    oMatrix.shx = (x1t - x0t)/(y1 - y0);
    oMatrix.sy = (y1t - y0t)/(y1 - y0);
    oMatrix.sx = oMatrix.sy;
    oMatrix.shy = -oMatrix.shx;
    oMatrix.tx = x0t - x0*oMatrix.sx - y0*oMatrix.shx;
    oMatrix.ty = y0t - x0*oMatrix.shy - y0*oMatrix.sy;
    return oRet;
};

CDocContentStructure.prototype.checkUnionPaths = function(aWarpedObjects)
{
    var aToCheck = [];
    var aWarpedObjects2, i, j, k;
    if(Array.isArray(aWarpedObjects))
    {
        aToCheck.push(aWarpedObjects);
    }
    else
    {
		for(j = 0; j < this.m_aByLines.length; ++j)
		{
            aWarpedObjects2 = [];
			var oTemp = this.m_aByLines[j];
			for(var t = 0; t < oTemp.length; ++t)
			{
				oTemp[t].GetAllWarped(aWarpedObjects2);
			}
            aToCheck.push(aWarpedObjects2);
		}
    }
    for(j = 0; j < aToCheck.length; ++j)
    {
        var aByProps = [], oCurObjectToDraw;
        aWarpedObjects2 = aToCheck[j];
        for(i = 0; i < aWarpedObjects2.length; ++i)
        {
            oCurObjectToDraw = aWarpedObjects2[i];
            for(k = 0; k < aByProps.length; ++k)
            {
                var oObjToDraw = aByProps[k];
                if(CompareBrushes(oObjToDraw.brush, oCurObjectToDraw.brush) && ComparePens(oObjToDraw.pen, oCurObjectToDraw.pen) && !oCurObjectToDraw.Comment && !oObjToDraw.Comment
                    && !oCurObjectToDraw.geometry.bDrawSmart && !oObjToDraw.geometry.bDrawSmart)
                {
                    oObjToDraw.geometry.pathLst = oObjToDraw.geometry.pathLst.concat(oCurObjectToDraw.geometry.pathLst);
                    oCurObjectToDraw.geometry.pathLst.length = 0;
                    break;
                }
            }
            if(k === aByProps.length)
            {
                aByProps.push(oCurObjectToDraw);
            }
        }
    }
    this.m_aBackgrounds.length = 0;
    this.m_aBorders.length = 0;
    this.getAllBackgroundsBorders(this.m_aParagraphBackgrounds, this.m_aBackgrounds, this.m_aBorders, this.m_aComments);
};




function CParagraphStructure()
{
    this.m_nType = DRAW_COMMAND_PARAGRAPH;
    this.m_aContent = [];
}

CParagraphStructure.prototype.Recalculate = function(oTheme, oColorMap, dWidth, dHeight, oShape)
{
    var i;
    for(i = 0; i < this.m_aContent.length; ++i)
    {
        this.m_aContent[i].Recalculate(oTheme, oColorMap, dWidth, dHeight, oShape);
    }
};

CParagraphStructure.prototype.CheckContentStructs = function(aContentStructs)
{
    var i;
    for(i = 0; i < this.m_aContent.length; ++i)
    {
        this.m_aContent[i].CheckContentStructs(aContentStructs);
    }
};
CParagraphStructure.prototype.draw = function(graphics, transform, oTheme, oColorMap)
{
    var i;
    for(i = 0; i < this.m_aContent.length; ++i)
    {
        this.m_aContent[i].draw(graphics, transform, oTheme, oColorMap);
    }
};

CParagraphStructure.prototype.getAllBackgroundsBorders = function(aParaBackgrounds, aBackgrounds, aBorders, aComments)
{
    var i;
    for(i = 0; i < this.m_aContent.length; ++i)
    {
        this.m_aContent[i].getAllBackgroundsBorders(aParaBackgrounds, aBackgrounds, aBorders, aComments);
    }
};


function CTableStructure()
{
    this.m_nType = DRAW_COMMAND_TABLE;
    this.m_aContent = [];
    this.m_aBorders = [];
}

CTableStructure.prototype.Recalculate = function(oTheme, oColorMap, dWidth, dHeight, oShape)
{
    var i;
    for(i = 0; i < this.m_aContent.length; ++i)
    {
        this.m_aContent[i].Recalculate(oTheme, oColorMap, dWidth, dHeight, oShape, true);
    }

    for(i = 0; i < this.m_aBorders.length; ++i)
    {
        this.m_aBorders[i].Recalculate(oTheme, oColorMap, dWidth, dHeight, oShape, true);
    }
};
CTableStructure.prototype.CheckContentStructs = function(aContentStructs)
{
    var i;
    for(i = 0; i < this.m_aContent.length; ++i)
    {
        this.m_aContent[i].CheckContentStructs(aContentStructs);
    }
};
CTableStructure.prototype.draw = function(graphics, transform, oTheme, oColorMap)
{
    var i;
    for(i = 0; i < this.m_aContent.length; ++i)
    {
        this.m_aContent[i].draw(graphics, transform, oTheme, oColorMap);
    }
};

CTableStructure.prototype.getAllBackgroundsBorders = function(aParaBackgrounds, aBackgrounds, aBorders, aComments)
{
    var i;
    for(i = 0; i < this.m_aBorders.length; ++i)
    {
        aBorders.push(this.m_aBorders[i]);
    }
    for(i = 0; i < this.m_aContent.length; ++i)
    {
        this.m_aContent[i].getAllBackgroundsBorders(aParaBackgrounds, aBackgrounds, aBorders, aComments);
    }
};



function CLineStructure(oLine)
{
    this.m_nType = DRAW_COMMAND_LINE;
    this.m_oLine = oLine;
    this.m_aContent = [];//ObjectToDraw
    this.m_aBorders = [];
    this.m_aBackgrounds = [];
    this.m_aUnderlinesStrikeouts = [];
    this.m_aParagraphBackgrounds = [];
    this.m_nDrawType = 0;// 0 - content, 1 - borders, 2 - backgrounds, 3 - underlinestrikeouts, 4 - paragraphbackrounds
}

CLineStructure.prototype.Recalculate = function(oTheme, oColorMap, dWidth, dHeight, oShape)
{
    var i;
    for(i = 0; i < this.m_aContent.length; ++i)
    {
        this.m_aContent[i].Recalculate(oTheme, oColorMap, dWidth, dHeight, oShape, true);
    }
    for(i = 0; i < this.m_aBorders.length; ++i)
    {
        this.m_aBorders[i].Recalculate(oTheme, oColorMap, dWidth, dHeight, oShape, true);
    }
    for(i = 0; i < this.m_aBackgrounds.length; ++i)
    {
        this.m_aBackgrounds[i].Recalculate(oTheme, oColorMap, dWidth, dHeight, oShape, true);
    }
    for(i = 0; i < this.m_aUnderlinesStrikeouts.length; ++i)
    {
        this.m_aUnderlinesStrikeouts[i].Recalculate(oTheme, oColorMap, dWidth, dHeight, oShape, true);
    }
    for(i = 0; i < this.m_aParagraphBackgrounds.length; ++i)
    {
        this.m_aParagraphBackgrounds[i].Recalculate(oTheme, oColorMap, dWidth, dHeight, oShape, true);
    }
};

CLineStructure.prototype.CheckContentStructs = function(aContentStructs)
{
    var i;
    for(i = 0; i < this.m_aContent.length; ++i)
    {
        aContentStructs.push(this.m_aContent[i]);
    }
};
CLineStructure.prototype.GetAllWarped = function(aWarpedObjects)
{
    var i;
    for(i = 0; i < this.m_aContent.length; ++i)
    {
        aWarpedObjects.push(this.m_aContent[i]);
    }
    for(i = 0; i < this.m_aBackgrounds.length; ++i)
    {
        aWarpedObjects.push(this.m_aBackgrounds[i]);
    }
    for(i = 0; i < this.m_aUnderlinesStrikeouts.length; ++i)
    {
        aWarpedObjects.push(this.m_aUnderlinesStrikeouts[i]);
    }
};
CLineStructure.prototype.CheckBoundsWarped = function(graphics)
{
    var i;
    for(i = 0; i < this.m_aContent.length; ++i)
    {
        this.m_aContent[i].draw(graphics, true);
    }
    for(i = 0; i < this.m_aBackgrounds.length; ++i)
    {
        this.m_aBackgrounds[i].draw(graphics, true);
    }
    for(i = 0; i < this.m_aUnderlinesStrikeouts.length; ++i)
    {
        this.m_aUnderlinesStrikeouts[i].draw(graphics, true);
    }
};
CLineStructure.prototype.draw = function(graphics, transform, oTheme, oColorMap)
{
    var i;
  // for(i = 0; i < this.m_aParagraphBackgrounds.length; ++i)
  // {
  //     this.m_aParagraphBackgrounds[i].draw(graphics, undefined, transform, oTheme, oColorMap);
  // }
  //  for(i = 0; i < this.m_aBorders.length; ++i)
  //  {
  //      this.m_aBorders[i].draw(graphics);
  //  }
 //   for(i = 0; i < this.m_aBackgrounds.length; ++i)
 //   {
 //       this.m_aBackgrounds[i].draw(graphics, undefined, transform, oTheme, oColorMap);
 //   }
    for(i = 0; i < this.m_aContent.length; ++i)
    {
        this.m_aContent[i].draw(graphics, undefined, transform, oTheme, oColorMap);
    }
    for(i = 0; i < this.m_aUnderlinesStrikeouts.length; ++i)
    {
        this.m_aUnderlinesStrikeouts[i].draw(graphics, undefined, transform, oTheme, oColorMap);
    }
};

CLineStructure.prototype.getAllBackgroundsBorders = function(aParaBackgrounds, aBackgrounds, aBorders, aComments)
{
    var i;
    for(i = 0; i < this.m_aParagraphBackgrounds.length; ++i)
    {
        aParaBackgrounds.push(this.m_aParagraphBackgrounds[i]);
    }
    for(i = 0; i < this.m_aBackgrounds.length; ++i)
    {
        aBackgrounds.push(this.m_aBackgrounds[i]);
        if(this.m_aBackgrounds[i].Comment)
        {
            aComments.push(this.m_aBackgrounds[i])
        }
    }
    for(i = 0; i < this.m_aBorders.length; ++i)
    {
        aBorders.push(this.m_aBorders[i]);
    }
};


var DRAW_COMMAND_TABLE = 0x01;
var DRAW_COMMAND_CONTENT = 0x02;
var DRAW_COMMAND_PARAGRAPH = 0x03;
var DRAW_COMMAND_LINE = 0x04;
var DRAW_COMMAND_DRAWING = 0x05;
var DRAW_COMMAND_HIDDEN_ELEM = 0x06;
var DRAW_COMMAND_NO_CREATE_GEOM = 0x07;
var DRAW_COMMAND_TABLE_ROW = 0x08;

function GetConstDescription(nConst)
{
    switch (nConst)
    {
        case DRAW_COMMAND_TABLE:
        {
            return "DRAW_COMMAND_TABLE";
        }
        case DRAW_COMMAND_CONTENT:
        {
            return "DRAW_COMMAND_CONTENT";
        }
        case DRAW_COMMAND_PARAGRAPH:
        {
            return "DRAW_COMMAND_PARAGRAPH";
        }
        case DRAW_COMMAND_LINE:
        {
            return "DRAW_COMMAND_LINE";
        }
        case DRAW_COMMAND_DRAWING:
        {
            return "DRAW_COMMAND_DRAWING";
        }
        case DRAW_COMMAND_HIDDEN_ELEM:
        {
            return "DRAW_COMMAND_HIDDEN_ELEM";
        }
        case DRAW_COMMAND_NO_CREATE_GEOM:
        {
            return "DRAW_COMMAND_NO_CREATE_GEOM";
        }
        case DRAW_COMMAND_TABLE_ROW:
        {
            return "DRAW_COMMAND_TABLE_ROW";
        }
        default :
        {
            return "Unknown";
        }
    }
}

function CreatePenFromParams(oUnifill, nStyle, nLineCap, nLineJoin, dLineWidth, dSize)
{
    var oLine = new AscFormat.CLn();
    oLine.setW(dSize * 36000 >> 0);
    oLine.setFill(oUnifill);


    //TODO
    // this.Color      = { R : 255, G : 255, B : 255, A : 255 };
    // this.Style      = 0;
    // this.LineCap    = 0;
    // this.LineJoin   = 0;
//
    // this.LineWidth  = 1;

    return oLine;
}

function CTextDrawer(dWidth, dHeight, bDivByLInes, oTheme, bDivGlyphs)
{
    this.m_oFont =
    {
        Name     : "",
        FontSize : -1,
        Style    : -1
    };

    this.m_oTheme = oTheme;
    this.Width = dWidth;
    this.Height = dHeight;
    this.m_oTransform = new AscCommon.CMatrix();
    this.pathW = 43200;
    this.pathH = 43200;

    this.xKoeff = this.pathW/this.Width;
    this.yKoeff = this.pathH/this.Height;

    this.m_aStack = [];
    this.m_oDocContentStructure = null;
    this.m_aCommands = [];
    this.m_aDrawings = [];
    // RFonts
    this.m_oTextPr      = null;
    this.m_oGrFonts     = new AscCommon.CGrRFonts();
    this.m_oCurComment     = null;

    this.m_oPen     = new AscCommon.CPen();
    this.m_oBrush   = new AscCommon.CBrush();

    this.m_oLine = null;
    this.m_oFill = null;


    // чтобы выставилось в первый раз
    this.m_oPen.Color.R     = -1;
    this.m_oBrush.Color1.R  = -1;
    this.m_oBrush.Color2.R  = -1;

    // просто чтобы не создавать каждый раз
    this.m_oFontSlotFont = new AscCommon.CFontSetup();
    this.LastFontOriginInfo = { Name : "", Replace : null };

    this.GrState = new AscCommon.CGrState();
    this.GrState.Parent = this;

    this.m_bDivByLines = bDivByLInes === true;
    this.m_bDivGlyphs  = bDivGlyphs === true;
    this.m_aByLines = null;
    this.m_nCurLineIndex = -1;
    this.m_aStackLineIndex = null;
    this.m_aStackCurRowMaxIndex = null;
    this.m_aByParagraphs = null;

    this.m_oObjectToDraw = null;

    this.m_bTurnOff = false;

    this.bCheckLines = false;
    this.lastX = null;
    this.lastY = null;
    if(this.m_bDivByLines)
    {
        this.m_aByLines = [];
        this.m_aStackLineIndex = [];
        this.m_aStackCurRowMaxIndex = [];
    }
    else
    {
        this.m_aByParagraphs = [];
    }
}

CTextDrawer.prototype =
{
    SetObjectToDraw: function(oObjectToDraw)
    {
        this.m_oObjectToDraw = oObjectToDraw;
    },
    // pen methods
    p_color : function(r,g,b,a)
    {
        if (this.m_oPen.Color.R != r || this.m_oPen.Color.G != g || this.m_oPen.Color.B != b)
        {
            this.m_oPen.Color.R = r;
            this.m_oPen.Color.G = g;
            this.m_oPen.Color.B = b;
        }
        if (this.m_oPen.Color.A != a)
        {
            this.m_oPen.Color.A = a;
        }
        this.Get_PathToDraw(false, true);
    },
    AddSmartRect: function()
    {},
    p_width : function(w)
    {
        var val = w / 1000;
        if (this.m_oPen.Size != val)
        {
            this.m_oPen.Size = val;
        }
        this.Get_PathToDraw(false, true);
    },
    p_dash : function(w)
    {
    },
    // brush methods
    b_color1 : function(r,g,b,a)
    {
        if (this.m_oBrush.Color1.R != r || this.m_oBrush.Color1.G != g || this.m_oBrush.Color1.B != b)
        {
            this.m_oBrush.Color1.R = r;
            this.m_oBrush.Color1.G = g;
            this.m_oBrush.Color1.B = b;
        }
        if (this.m_oBrush.Color1.A != a)
        {
            this.m_oBrush.Color1.A = a;
        }
        this.Get_PathToDraw(false, true);
    },

    set_fillColor: function(R, G, B)
    {
        this.m_oFill = AscFormat.CreateUniFillByUniColor(AscFormat.CreateUniColorRGB(R, G, B));
        this.Get_PathToDraw(false, true);
    },

    b_color2 : function(r,g,b,a)
    {
        if (this.m_oBrush.Color2.R != r || this.m_oBrush.Color2.G != g || this.m_oBrush.Color2.B != b)
        {
            this.m_oBrush.Color2.R = r;
            this.m_oBrush.Color2.G = g;
            this.m_oBrush.Color2.B = b;
        }
        if (this.m_oBrush.Color2.A != a)
        {
            this.m_oBrush.Color2.A = a;
        }
        this.Get_PathToDraw(false, true);
    },

    put_brushTexture : function(src, mode)
    {
        this.m_oBrush.Color1.R = -1;
        this.m_oBrush.Color1.G = -1;
        this.m_oBrush.Color1.B = -1;
        this.m_oBrush.Color1.A = -1;
        this.Get_PathToDraw(false, true);
    },

    SetShd: function(oShd)
    {
        if(oShd)
        {
            if (oShd.Value !== Asc.c_oAscShdNil)
            {
                if(oShd.Unifill)
                {
                    this.m_oFill = oShd.Unifill;
                }
                else
                {
                    if(oShd.Color)
                    {
                        this.m_oFill = AscFormat.CreateUnfilFromRGB(oShd.Color.r, oShd.Color.g, oShd.Color.b);
                    }
                    else
                    {
                        this.m_oFill = null;
                    }
                }
            }
            else
            {
                this.m_oFill = null;
            }
        }
        else
        {
            this.m_oFill = null;
        }
        this.Get_PathToDraw(false, true);
    },


    SetBorder: function(oBorder)
    {
        if(oBorder && oBorder.Value !== border_None)
        {
            this.m_oLine = CreatePenFromParams(oBorder.Unifill ? oBorder.Unifill : AscFormat.CreateUnfilFromRGB(oBorder.Color.r, oBorder.Color.g, oBorder.Color.b), this.m_oPen.Style, this.m_oPen.LineCap, this.m_oPen.LineJoin, this.m_oPen.LineWidth, this.m_oPen.Size);
        }
        else
        {
            this.m_oLine = null;
        }
        //TODO
    },

    SetAdditionalProps: function(oProps)
    {
        oProps && this.SetTextPr(oProps, this.m_oTheme);
    },

    put_BrushTextureAlpha : function(alpha)
    {
    },

    put_BrushGradient : function(gradFill, points, transparent)
    {
    },

    StartCheckTableDraw: function()
    {
        this.Start_Command(DRAW_COMMAND_TABLE);
    },

    EndCheckTableDraw: function()
    {
        this.End_Command();
    },

    Start_Command : function(commandId, param, index, nType)
    {
        this.m_aCommands.push(commandId);
        var oNewStructure = null;
        switch(commandId)
        {
            case DRAW_COMMAND_NO_CREATE_GEOM:
            {
                break;
            }
            case DRAW_COMMAND_CONTENT:
            {
                oNewStructure = new CDocContentStructure();
                this.m_aStackLineIndex.push(this.m_nCurLineIndex);
                break;
            }
            case DRAW_COMMAND_PARAGRAPH:
            {
                oNewStructure = new CParagraphStructure();
                if(!this.m_bDivByLines)
                {
                    this.m_aByParagraphs[this.m_aByParagraphs.length] = [];
                }
                break;
            }
            case DRAW_COMMAND_LINE:
            {
                var oPrevStruct = this.m_aStack[this.m_aStack.length - 1];
                if(oPrevStruct.m_nType === DRAW_COMMAND_PARAGRAPH && oPrevStruct.m_aContent[index])
                {
                    oPrevStruct.m_aContent[index].m_nDrawType = nType;
                    this.m_aStack.push(oPrevStruct.m_aContent[index]);
                }
                else
                {
                    oNewStructure = new CLineStructure(param);
                    oNewStructure.m_nDrawType = nType;
                    if(this.m_bDivByLines)
                    {
                        ++this.m_nCurLineIndex;
                        if(!Array.isArray(this.m_aByLines[this.m_nCurLineIndex]))
                        {
                            this.m_aByLines[this.m_nCurLineIndex] = [];
                        }
                        this.m_aByLines[this.m_nCurLineIndex].push(oNewStructure);
                        if(this.m_aStackCurRowMaxIndex[this.m_aStackCurRowMaxIndex.length - 1] < this.m_nCurLineIndex)
                        {
                            this.m_aStackCurRowMaxIndex[this.m_aStackCurRowMaxIndex.length - 1] = this.m_nCurLineIndex;
                        }
                    }
                    else
                    {
                        this.m_aByParagraphs[this.m_aByParagraphs.length - 1].push(oNewStructure);
                    }
                }
                break;
            }
            case DRAW_COMMAND_TABLE:
            {
                oNewStructure = new CTableStructure();
                break;
            }
            case DRAW_COMMAND_DRAWING:
            {
                break;
            }
            case DRAW_COMMAND_HIDDEN_ELEM:
            {
                break;
            }
            case DRAW_COMMAND_TABLE_ROW:
            {
                this.m_aStackCurRowMaxIndex[this.m_aStackCurRowMaxIndex.length] = -1;
                break;
            }
        }
        if(oNewStructure)
        {
            if(this.m_aStack[this.m_aStack.length - 1])
            {
                this.m_aStack[this.m_aStack.length - 1].m_aContent.push(oNewStructure);
            }
            this.m_aStack.push(oNewStructure);
        }
    },

    End_Command : function()
    {
        var nCommandId = this.m_aCommands.pop();
        switch(nCommandId)
        {
            case DRAW_COMMAND_NO_CREATE_GEOM:
            {
                break;
            }
            case DRAW_COMMAND_CONTENT:
            {
                var oDocContentStructure = this.m_aStack.pop();
                if(this.m_aStack.length === 0)
                {
                    this.m_oDocContentStructure = oDocContentStructure;
                    this.m_oDocContentStructure.m_aByLines = this.m_aByLines;
                    this.m_oDocContentStructure.m_aByParagraphs = this.m_aByParagraphs;
                    this.m_oDocContentStructure.m_aDrawingsStruct = this.m_aDrawings;
                    this.m_aByLines = [];
                    this.m_aByParagraphs = [];
                    this.m_aDrawings = [];
                }
                if(this.m_bDivByLines)
                {
                    this.m_nCurLineIndex = this.m_aStackLineIndex.pop();
                }
                break;
            }
            case DRAW_COMMAND_PARAGRAPH:
            {
                this.m_aStack.pop();
                break;
            }
            case DRAW_COMMAND_LINE:
            {
                this.m_aStack.pop();
                break;
            }
            case DRAW_COMMAND_TABLE:
            {
                this.m_aStack.pop();
                break;
            }
            case DRAW_COMMAND_DRAWING:
            {
                break;
            }
            case DRAW_COMMAND_HIDDEN_ELEM:
            {
                break;
            }
            case DRAW_COMMAND_TABLE_ROW:
            {
                this.m_nCurLineIndex = this.m_aStackCurRowMaxIndex.pop();
                break;
            }
        }
    },

    Get_PathToDraw : function(bStart, bStart2, x, y)
    {
        var oPath = null;
        var oLastCommand = this.m_aStack[this.m_aStack.length - 1];
        var oLastObjectToDraw, oBrushColor = this.m_oBrush.Color1, oPenColor = this.m_oPen.Color;
        if(oLastCommand)
        {
            switch(oLastCommand.m_nType)
            {
                case DRAW_COMMAND_LINE:
                {
                    switch(oLastCommand.m_nDrawType)
                    {
                        case 0://content
                        {
                            if(oLastCommand.m_aContent.length === 0)
                            {
                                oLastCommand.m_aContent.push(new ObjectToDraw(this.GetFillFromTextPr(this.m_oTextPr), this.GetPenFromTextPr(this.m_oTextPr), this.Width, this.Height, new Geometry(), this.m_oTransform, x, y, this.m_oCurComment));
                            }
                            oLastObjectToDraw = oLastCommand.m_aContent[oLastCommand.m_aContent.length - 1];

                            if(bStart2)
                            {
                                if(oLastObjectToDraw.geometry.pathLst.length === 0 || (oLastObjectToDraw.geometry.pathLst.length === 1 && oLastObjectToDraw.geometry.pathLst[0].ArrPathCommandInfo.length === 0))
                                {
                                    oLastObjectToDraw.resetBrushPen(this.GetFillFromTextPr(this.m_oTextPr), this.GetPenFromTextPr(this.m_oTextPr), x, y)
                                }
                                else
                                {
                                    oLastCommand.m_aContent.push(new ObjectToDraw(this.GetFillFromTextPr(this.m_oTextPr), this.GetPenFromTextPr(this.m_oTextPr), this.Width, this.Height, new Geometry(), this.m_oTransform, x, y));
                                    oLastObjectToDraw = oLastCommand.m_aContent[oLastCommand.m_aContent.length - 1];
                                }
                            }
                            break;
                        }
                        case 1://borders
                        {
                            if(oLastCommand.m_aBorders.length === 0)
                            {
                                oLastCommand.m_aBorders.push(new ObjectToDraw(this.m_oFill, this.m_oLine, this.Width, this.Height, new Geometry(), this.m_oTransform, x, y))
                            }
                            oLastObjectToDraw = oLastCommand.m_aBorders[oLastCommand.m_aBorders.length - 1];

                            if(bStart2)
                            {
                                if(oLastObjectToDraw.geometry.pathLst.length === 0 || (oLastObjectToDraw.geometry.pathLst.length === 1 && oLastObjectToDraw.geometry.pathLst[0].ArrPathCommandInfo.length === 0))
                                {
                                    oLastObjectToDraw.resetBrushPen(this.m_oFill, this.m_oLine, x, y);
                                }
                                else
                                {
                                    oLastCommand.m_aBorders.push(new ObjectToDraw(this.m_oFill, this.m_oLine, this.Width, this.Height, new Geometry(), this.m_oTransform, x, y));
                                    oLastObjectToDraw = oLastCommand.m_aBorders[oLastCommand.m_aBorders.length - 1];
                                }
                            }
                            break;
                        }
                        case 2://backgrounds
                        {
                            if(oLastCommand.m_aBackgrounds.length === 0)
                            {
                                oLastCommand.m_aBackgrounds.push(new ObjectToDraw(this.m_oFill, this.m_oLine, this.Width, this.Height, new Geometry(), this.m_oTransform, x, y))
                            }
                            oLastObjectToDraw = oLastCommand.m_aBackgrounds[oLastCommand.m_aBackgrounds.length - 1];

                            if(bStart2)
                            {
                                if(oLastObjectToDraw.geometry.pathLst.length === 0 || (oLastObjectToDraw.geometry.pathLst.length === 1 && oLastObjectToDraw.geometry.pathLst[0].ArrPathCommandInfo.length === 0))
                                {
                                    oLastObjectToDraw.resetBrushPen(this.m_oFill, this.m_oLine, x, y);
                                }
                                else
                                {
                                    oLastCommand.m_aBackgrounds.push(new ObjectToDraw(this.m_oFill, this.m_oLine, this.Width, this.Height, new Geometry(), this.m_oTransform, x, y));
                                    oLastObjectToDraw = oLastCommand.m_aBackgrounds[oLastCommand.m_aBackgrounds.length - 1];
                                }
                            }
                            break;
                        }
                        case 3://Underliens & Strikeouts
                        {
                            if(oLastCommand.m_aUnderlinesStrikeouts.length === 0)
                            {
                                oBrushColor = this.m_oBrush.Color1;
                                oPenColor = this.m_oPen.Color;
                                oLastCommand.m_aUnderlinesStrikeouts.push(new ObjectToDraw(this.GetFillFromTextPr(this.m_oTextPr), this.GetPenFromTextPr(this.m_oTextPr), this.Width, this.Height, new Geometry(), this.m_oTransform, x, y))
                            }
                            oLastObjectToDraw = oLastCommand.m_aUnderlinesStrikeouts[oLastCommand.m_aUnderlinesStrikeouts.length - 1];

                            if(bStart2)
                            {
                                if(oLastObjectToDraw.geometry.pathLst.length === 0 || (oLastObjectToDraw.geometry.pathLst.length === 1 && oLastObjectToDraw.geometry.pathLst[0].ArrPathCommandInfo.length === 0))
                                {
                                    oLastObjectToDraw.resetBrushPen(this.GetFillFromTextPr(this.m_oTextPr), this.GetPenFromTextPr(this.m_oTextPr), x, y);
                                }
                                else
                                {
                                    oLastCommand.m_aUnderlinesStrikeouts.push(new ObjectToDraw(this.GetFillFromTextPr(this.m_oTextPr), this.GetPenFromTextPr(this.m_oTextPr), this.Width, this.Height, new Geometry(), this.m_oTransform, x, y));
                                    oLastObjectToDraw = oLastCommand.m_aUnderlinesStrikeouts[oLastCommand.m_aUnderlinesStrikeouts.length - 1];
                                }
                            }
                            break;
                        }
                        case 4:
                        {
                            if(oLastCommand.m_aParagraphBackgrounds.length === 0)
                            {
                                oLastCommand.m_aParagraphBackgrounds.push(new ObjectToDraw(this.m_oFill, this.m_oLine, this.Width, this.Height, new Geometry(), this.m_oTransform, x, y))
                            }
                            oLastObjectToDraw = oLastCommand.m_aParagraphBackgrounds[oLastCommand.m_aParagraphBackgrounds.length - 1];

                            if(bStart2)
                            {
                                if(oLastObjectToDraw.geometry.pathLst.length === 0 || (oLastObjectToDraw.geometry.pathLst.length === 1 && oLastObjectToDraw.geometry.pathLst[0].ArrPathCommandInfo.length === 0))
                                {
                                    oLastObjectToDraw.resetBrushPen(this.m_oFill, this.m_oLine, x, y);
                                }
                                else
                                {
                                    oLastCommand.m_aParagraphBackgrounds.push(new ObjectToDraw(this.m_oFill, this.m_oLine, this.Width, this.Height, new Geometry(), this.m_oTransform, x, y));
                                    oLastObjectToDraw = oLastCommand.m_aParagraphBackgrounds[oLastCommand.m_aParagraphBackgrounds.length - 1];
                                }
                            }
                            break;
                        }
                    }
                    break;
                }
                case DRAW_COMMAND_TABLE:
                {
                    if(oLastCommand.m_aBorders.length === 0 || bStart2)
                    {
                        oBrushColor = this.m_oBrush.Color1;
                        oPenColor = this.m_oPen.Color;
                        oLastCommand.m_aBorders.push(new ObjectToDraw(this.m_oFill, this.m_oLine, this.Width, this.Height, new Geometry(), this.m_oTransform, x, y));
                    }
                    oLastObjectToDraw = oLastCommand.m_aBorders[oLastCommand.m_aBorders.length - 1];

                    if(bStart2)
                    {
                        if(oLastObjectToDraw.geometry.pathLst.length === 0 || (oLastObjectToDraw.geometry.pathLst.length === 1 && oLastObjectToDraw.geometry.pathLst[0].ArrPathCommandInfo.length === 0))
                        {
                            oLastObjectToDraw.resetBrushPen(this.m_oFill, this.m_oLine, x, y);
                        }
                        else
                        {
                            oLastCommand.m_aBorders.push(new ObjectToDraw(this.m_oFill, this.m_oLine, this.Width, this.Height, new Geometry(), this.m_oTransform, x, y));
                            oLastObjectToDraw = oLastCommand.m_aBorders[oLastCommand.m_aBorders.length - 1];
                        }
                    }
                    oLastObjectToDraw.geometry.bDrawSmart = true;
                    break;
                }
                case DRAW_COMMAND_PARAGRAPH:
                {
                    break;
                }
            }
        }
        else
        {
            if(this.m_oObjectToDraw)
            {
                oLastObjectToDraw = this.m_oObjectToDraw;
            }
        }

        if(oLastObjectToDraw && oLastObjectToDraw.geometry)
        {
            oLastObjectToDraw.Comment = this.m_oCurComment;
            if(oLastObjectToDraw.geometry.pathLst.length === 0 || bStart)
            {
                oPath = new AscFormat.Path();
                oPath.setPathW(this.pathW);
                oPath.setPathH(this.pathH);
                oPath.setExtrusionOk(false);
                oPath.setFill("none");
                oPath.setStroke(true);
                oLastObjectToDraw.geometry.AddPath(oPath)
            }
            else
            {
                oPath = oLastObjectToDraw.geometry.pathLst[oLastObjectToDraw.geometry.pathLst.length-1];
            }
        }
        return oPath;
    },


    transform : function(sx,shy,shx,sy,tx,ty)
    {
        if (this.m_oTransform.sx    != sx || this.m_oTransform.shx   != shx || this.m_oTransform.shy   != shy ||
            this.m_oTransform.sy    != sy || this.m_oTransform.tx    != tx || this.m_oTransform.ty    != ty)
        {
            this.m_oTransform.sx    = sx;
            this.m_oTransform.shx   = shx;
            this.m_oTransform.shy   = shy;
            this.m_oTransform.sy    = sy;
            this.m_oTransform.tx    = tx;
            this.m_oTransform.ty    = ty;
        }
    },
    // path commands
    _s : function()
    {
        if(this.m_bTurnOff)
            return;
        this.Get_PathToDraw(true);
    },
    _e : function()
    {
    },
    _z : function()
    {
        var oPathToDraw = this.Get_PathToDraw();
        if(oPathToDraw)
        {
            oPathToDraw.close();
        }
    },
    _m : function(x,y)
    {
        if(this.m_bTurnOff)
            return;
        var oPathToDraw = this.Get_PathToDraw();
        if(oPathToDraw)
        {
            oPathToDraw.moveTo(this.xKoeff*x, this.yKoeff*y);
        }
        this.lastX = x;
        this.lastY = y;
    },
    _l : function(x,y)
    {

        if(this.m_bTurnOff)
            return;
        if(this.bCheckLines)
        {
            if(Math.abs(x - this.lastX) < EPSILON_TEXT_AUTOFIT && Math.abs(x - this.lastX) < Math.abs(y - this.lastY))
            {
                this.checkCurveBezier(this.lastX, this.lastY, this.lastX, this.lastY  + (y - this.lastY)/3, this.lastX, this.lastY + 2*(y - this.lastY)/3, x, y, PATH_DIV_EPSILON);
                this.lastX = x;
                this.lastY = y;
                return;
            }
            else if(Math.abs(y - this.lastY) < EPSILON_TEXT_AUTOFIT && Math.abs(y - this.lastY) < Math.abs(x - this.lastX))
            {
                this.checkCurveBezier(this.lastX, this.lastY, this.lastX + (x - this.lastX)/3, this.lastY, this.lastX + 2*(x - this.lastX)/3, this.lastY, x, y, PATH_DIV_EPSILON);
                this.lastX = x;
                this.lastY = y;
                return;
            }
        }
        var oPathToDraw = this.Get_PathToDraw();
        if(oPathToDraw)
        {
            oPathToDraw.lnTo(this.xKoeff*x, this.yKoeff*y);
        }
        this.lastX = x;
        this.lastY = y;
    },
    _c : function(x1,y1,x2,y2,x3,y3)
    {
        var oPathToDraw = this.Get_PathToDraw();
        if(oPathToDraw)
        {
            oPathToDraw.cubicBezTo(this.xKoeff*x1, this.yKoeff*y1, this.xKoeff*x2, this.yKoeff*y2, this.xKoeff*x3, this.yKoeff*y3);
        }
        this.lastX = x3;
        this.lastY = y3;
    },
    _c2 : function(x1,y1,x2,y2)
    {
        var oPathToDraw = this.Get_PathToDraw();
        if(oPathToDraw)
        {
            oPathToDraw.quadBezTo(this.xKoeff*x1, this.yKoeff*y1, this.xKoeff*x2, this.yKoeff*y2);
        }
        this.lastX = x2;
        this.lastY = y2;
    },
    ds : function()
    {
    },
    df : function()
    {
        var oPathToDraw = this.Get_PathToDraw();
        oPathToDraw.setFill("norm");
    },

    drawpath : function(type)
    {
    },

    // canvas state
    save : function()
    {
    },
    restore : function()
    {
    },
    clip : function()
    {
    },

    SetIntegerGrid: function()
    {
    },

    // images
    drawImage : function(img,x,y,w,h)
    {
    },

    SetFont : function(font)
    {
        if (null == font)
            return;

        var style = 0;
        if (font.Italic == true)
            style += 2;
        if (font.Bold == true)
            style += 1;

        var fontinfo = g_fontApplication.GetFontInfo(font.FontFamily.Name, style, this.LastFontOriginInfo);
        style = fontinfo.GetBaseStyle(style);

        if (this.m_oFont.Name != fontinfo.Name)
        {
            this.m_oFont.Name = fontinfo.Name;
        }
        if (this.m_oFont.FontSize != font.FontSize)
        {
            this.m_oFont.FontSize = font.FontSize;
        }
        if (this.m_oFont.Style != style)
        {
            this.m_oFont.Style = style;
        }
    },
    FillText : function(x,y,text)
    {
        this.FillTextCode(x, y, text.charCodeAt(0));
    },
    FillTextCode : function(x,y,code)
    {
        //var _is_face_index_no_0 = (_font_info.faceIndexR <= 0 && _font_info.faceIndexI <= 0 && _font_info.faceIndexB <= 0 && _font_info.faceIndexBI <= 0);
//
        //if (code < 0xFFFF && (_is_face_index_no_0 || window["native"] !== undefined))
        //    return;

        if(this.m_bDivGlyphs === true)
        {
            this.Get_PathToDraw(false, true, x, y);
        }
        AscCommon.g_oTextMeasurer.SetFontInternal(this.m_oFont.Name, this.m_oFont.FontSize, Math.max(this.m_oFont.Style, 0));

        if (null != this.LastFontOriginInfo.Replace)
        {
            code = g_fontApplication.GetReplaceGlyph(code, this.LastFontOriginInfo.Replace);
        }

        if (AscCommon.g_oTextMeasurer.m_oManager)
            AscCommon.g_oTextMeasurer.m_oManager.LoadStringPathCode(code, false, x, y, this);
    },
    tg : function(gid,x,y)
    {
        g_oTextMeasurer.SetFontInternal(this.m_oFont.Name, this.m_oFont.FontSize, Math.max(this.m_oFont.Style, 0));
        g_oTextMeasurer.m_oManager.LoadStringPathCode(gid, true, x, y, this);
    },
    charspace : function(space)
    {
    },

    beginCommand : function(command)
    {
    },
    endCommand : function(command)
    {
    },

    put_PenLineJoin : function(_join)
    {
    },
    put_TextureBounds : function(x, y, w, h)
    {
    },
    put_TextureBoundsEnabled : function(bIsEnabled)
    {
    },

    SetFontSlot : function(slot, fontSizeKoef)
    {
        var _rfonts = this.m_oGrFonts;
        var _lastFont = this.m_oFontSlotFont;

        switch (slot)
        {
            case fontslot_ASCII:
            {
                _lastFont.Name   = _rfonts.Ascii.Name;
                _lastFont.Size = this.m_oTextPr.FontSize;
                _lastFont.Bold = this.m_oTextPr.Bold;
                _lastFont.Italic = this.m_oTextPr.Italic;

                break;
            }
            case fontslot_CS:
            {
                _lastFont.Name   = _rfonts.CS.Name;
                _lastFont.Size = this.m_oTextPr.FontSizeCS;
                _lastFont.Bold = this.m_oTextPr.BoldCS;
                _lastFont.Italic = this.m_oTextPr.ItalicCS;

                break;
            }
            case fontslot_EastAsia:
            {
                _lastFont.Name   = _rfonts.EastAsia.Name;
                _lastFont.Size = this.m_oTextPr.FontSize;
                _lastFont.Bold = this.m_oTextPr.Bold;
                _lastFont.Italic = this.m_oTextPr.Italic;

                break;
            }
            case fontslot_HAnsi:
            default:
            {
                _lastFont.Name   = _rfonts.HAnsi.Name;
                _lastFont.Size = this.m_oTextPr.FontSize;
                _lastFont.Bold = this.m_oTextPr.Bold;
                _lastFont.Italic = this.m_oTextPr.Italic;

                break;
            }
        }
        if (undefined !== fontSizeKoef)
            _lastFont.Size *= fontSizeKoef;

        var style = 0;
        if (_lastFont.Italic == true)
            style += 2;
        if (_lastFont.Bold == true)
            style += 1;

        var fontinfo = g_fontApplication.GetFontInfo(_lastFont.Name, style, this.LastFontOriginInfo);
        style = fontinfo.GetBaseStyle(style);

        if (this.m_oFont.Name != fontinfo.Name)
        {
            this.m_oFont.Name = fontinfo.Name;
        }
        if (this.m_oFont.FontSize != _lastFont.Size)
        {
            this.m_oFont.FontSize = _lastFont.Size;
        }
        if (this.m_oFont.Style != style)
        {
            this.m_oFont.Style = style;
        }
    },

    BeginPage : function(width,height)
    {
    },
    EndPage : function()
    {
    },

    transform3 : function(m)
    {
        this.transform(m.sx, m.shy, m.shx, m.sy, m.tx, m.ty);
    },
    reset : function()
    {
        this.transform(1, 0, 0, 1, 0, 0);
    },

    FillText2 : function(x,y,text)
    {
        this.FillText(x,y,text);
    },
    GetIntegerGrid : function()
    {
    },
    GetFont : function()
    {
        return this.m_oFont;
    },
    put_GlobalAlpha : function(enable, alpha)
    {
    },

    Start_GlobalAlpha : function()
    {
    },

    End_GlobalAlpha : function()
    {
    },

    DrawHeaderEdit : function(yPos)
    {
    },

    DrawFooterEdit : function(yPos)
    {
    },

    drawCollaborativeChanges : function(x, y, w, h)
    {
    },

    drawSearchResult : function(x, y, w, h)
    {
    },

    DrawEmptyTableLine : function(x1,y1,x2,y2)
    {
        // эта функция не для печати или сохранения вообще
    },
    DrawLockParagraph : function(lock_type, x, y1, y2)
    {
        // эта функция не для печати или сохранения вообще
    },

    DrawLockObjectRect : function(lock_type, x, y, w, h)
    {
        // эта функция не для печати или сохранения вообще
    },

    DrawSpellingLine : function(y0, x0, x1, w)
    {
    },

    checkCurveBezier: function(x0, y0, x1, y1, x2, y2, x3, y3, dEpsilon)
    {
        var _epsilon = dEpsilon ? dEpsilon : UNDERLINE_DIV_EPSILON;
        var arr_point = AscFormat.partition_bezier4(x0, y0, x1, y1, x2, y2, x3, y3, _epsilon), i, count = arr_point.length >> 2;
        for(i = 0; i < count; ++i)
        {
            var k = 4*i;
            this._c(arr_point[k + 1].x, arr_point[k + 1].y, arr_point[k + 2].x, arr_point[k + 2].y, arr_point[k + 3].x, arr_point[k + 3].y);
        }
    },
    // smart methods for horizontal / vertical lines
    drawHorLine : function(align, y, x, r, penW, bMath)
    {
        if(bMath)
        {
            var oTextPr = this.GetTextPr();
            var oCopyTextPr;
            if(oTextPr)
            {
                oCopyTextPr = oTextPr.Copy();
                oCopyTextPr.TextOutline = new AscFormat.CLn();
                oCopyTextPr.TextOutline.w = 36000.0 * penW >> 0;
                var oUnifill = oCopyTextPr.TextFill ? oCopyTextPr.TextFill : oCopyTextPr.Unifill;
                if((!oUnifill || !oUnifill.fill ||!oUnifill.fill.type === Asc.c_oAscFill._SOLID || !oUnifill.fill.color) && oCopyTextPr.Color)
                {
                    oUnifill = AscFormat.CreateUniFillByUniColor(AscFormat.CreateUniColorRGB(oCopyTextPr.Color.r, oCopyTextPr.Color.g, oCopyTextPr.Color.b))
                }
                if(oUnifill)
                {
                    oCopyTextPr.TextOutline.Fill = oUnifill;
                }
                this.SetTextPr(oCopyTextPr, this.m_oTheme);
            }
            this._s();
            this._m(x, y);
            this._l(r, y);
            this.ds();
            if(oCopyTextPr)
            {
                this.SetTextPr(oTextPr, this.m_oTheme);
            }
            return;
        }

        this._s();
        this._m(x, y);

        this.checkCurveBezier(x, y, x + ((r-x)/3), y, x + (2/3) * (r - x), y, r, y);// this._l(r, y);
        this._l(r, y + penW);
        this.checkCurveBezier(r, y + penW, x + (2/3) * (r - x), y + penW, x + ((r-x)/3), y + penW, x, y + penW);//this._l(x, y + penW);
        this._z();
        this.ds();
        this.df();
    },



    drawHorLine2 : function(align, y, x, r, penW)
    {

        var _y = y;
        switch (align)
        {
            case 0:
            {
                _y = y + penW / 2;
                break;
            }
            case 1:
            {
                break;
            }
            case 2:
            {
                _y = y - penW / 2;
                break;
            }
        }
       // if(!AdditionalData)
       // {
       //     this.p_width(1000 * penW);
//
//
       //     this._s();
       //     this._m(x, (_y - penW));
       //     this._l(r, (_y - penW));
       //     this.ds();
//
       //     this._s();
       //     this._m(x, (_y + penW));
       //     this._l(r, (_y + penW));
       //     this.ds();
//
       //     this._e();
       // }
       // else
        {

            this._s();
            this._m(x, (_y - penW ));

            this.checkCurveBezier(x, _y - penW, x + ((r-x)/3), _y - penW, x + (2/3) * (r - x), _y - penW, r, _y - penW);//this._l(r, (_y - penW ));
            this._l(r, _y);
            this.checkCurveBezier(r, _y, x + (2/3) * (r - x), _y, x + ((r-x)/3), _y, x, _y);//this._l(x, (_y - penW + penW));
            this._z();
            this.ds();
            this.df();

            this._s();
            this._m(x, (_y + penW ));
            this.checkCurveBezier(x, _y + penW, x + ((r-x)/3), _y + penW, x + (2/3) * (r - x), _y + penW, r, _y + penW);//this._l(r, (_y + penW ));
            this._l(r, (_y + penW + penW));
            this.checkCurveBezier(r, (_y + penW + penW), x + (2/3) * (r - x), _y + penW + penW, x + ((r-x)/3), _y + penW + penW,  x, _y + penW + penW);//this._l(x, (_y + penW + penW));
            this._z();
            this.ds();

            this._e();
        }
    },

    drawVerLine : function(align, x, y, b, penW, bMath)
    {
        if(bMath)
        {
            var oTextPr = this.GetTextPr();
            var oCopyTextPr;
            if(oTextPr)
            {
                oCopyTextPr = oTextPr.Copy();
                oCopyTextPr.TextOutline = new AscFormat.CLn();
                oCopyTextPr.TextOutline.w = 36000.0 * penW >> 0;
                var oUnifill = oCopyTextPr.TextFill ? oCopyTextPr.TextFill : oCopyTextPr.Unifill;
                if((!oUnifill || !oUnifill.fill ||!oUnifill.fill.type === Asc.c_oAscFill.FILL_TYPE_SOLID || !oUnifill.fill.color) && oCopyTextPr.Color)
                {
                    oUnifill = AscFormat.CreateUniFillByUniColor(AscFormat.CreateUniColorRGB(oCopyTextPr.Color.r, oCopyTextPr.Color.g, oCopyTextPr.Color.b))
                }
                if(oUnifill)
                {
                    oCopyTextPr.TextOutline.Fill = oUnifill;
                }
                this.SetTextPr(oCopyTextPr, this.m_oTheme);
            }
            this._s();

            var _x = x;
            switch (align)
            {
                case 0:
                {
                    _x = x + penW / 2;
                    break;
                }
                case 1:
                {
                    break;
                }
                case 2:
                {
                    _x = x - penW / 2;
                }
            }
            this._m(_x, y);
            this._l(_x, b);

            this.ds();
            if(oCopyTextPr)
            {
                this.SetTextPr(oTextPr, this.m_oTheme);
            }
            return;
        }

        var nLastCommand = this.m_aCommands[this.m_aCommands.length -1], bOldVal;
        if(nLastCommand === DRAW_COMMAND_TABLE)
        {
            bOldVal = this.bCheckLines;
            this.bCheckLines = false;
        }
        this.p_width(1000 * penW);
        this._s();

        var _x = x;
        switch (align)
        {
            case 0:
            {
                _x = x + penW / 2;
                break;
            }
            case 1:
            {
                break;
            }
            case 2:
            {
                _x = x - penW / 2;
            }
        }
        this._m(_x, y);
        this._l(_x, b);

        this.ds();
        if(nLastCommand === DRAW_COMMAND_TABLE)
        {
            this.bCheckLines = bOldVal;
        }
    },

    drawHorLineExt : function(align, y, x, r, penW, leftMW, rightMW)
    {
        var nLastCommand = this.m_aCommands[this.m_aCommands.length -1];
        if(nLastCommand === DRAW_COMMAND_TABLE)
        {
            var bOldVal = this.bCheckLines;
            this.bCheckLines = false;
            this.p_width(penW * 1000);
            this._s();
            this._m(x, y);
            this._l(r, y);
            this.ds();
            this.bCheckLines = bOldVal;
        }
        else
        {
            this.drawHorLine(align, y, x + leftMW, r + rightMW, penW);
        }
    },

    DrawTextArtComment : function(Element)
    {
        this.m_oCurComment = Element;
        this.rect(Element.x0, Element.y0, Element.x1 - Element.x0, Element.y1 - Element.y0);
        this.df();
        this.m_oCurComment = null;
    },

    rect : function(x,y,w,h)
    {
        if(this.m_bTurnOff)
            return;
        var oLastCommand = this.m_aStack[this.m_aStack.length - 1];
        if(oLastCommand && (oLastCommand.m_nDrawType === 2 || oLastCommand.m_nDrawType === 4))
        {
            this.Get_PathToDraw(true, true);
            this._m(x, y);

            this.checkCurveBezier(x, y, x + (w/3), y, x + (2/3) *w, y, x+w, y);// this._l(r, y);
            this._l(x+w, y + h);
            this.checkCurveBezier(x + w, y + h, x + (2/3) * (w), y + h, x + (w/3), y + h, x, y + h);//this._l(x, y + penW);
            this._z();
            this.ds();
        }
        else
        {
            var _x = x;
            var _y = y;
            var _r = (x + w);
            var _b = (y + h);

            this.Get_PathToDraw(true, true);
            this._m(_x, _y);
            this._l(_r, _y);
            this._l(_r, _b);
            this._l(_x, _b);
            this._l(_x, _y);
        }
    },

    TableRect : function(x,y,w,h)
    {
        this.rect(x,y,w,h);
        this.df();
    },

    // функции клиппирования
    AddClipRect : function(x, y, w, h)
    {
        /*
         this.b_color1(0, 0, 0, 255);
         this.rect(x, y, w, h);
         this.df();
         return;
         */

        var __rect = new AscCommon._rect();
        __rect.x = x;
        __rect.y = y;
        __rect.w = w;
        __rect.h = h;
        this.GrState.AddClipRect(__rect);
    },

    RemoveClipRect : function()
    {
        //this.ClipManager.RemoveRect();
    },

    SetClip : function(r)
    {
        //this._s();
    },

    RemoveClip : function()
    {
    },

    GetTransform : function()
    {
        return this.m_oTransform;
    },
    GetLineWidth : function()
    {
        return 0;
    },
    GetPen : function()
    {
        return 0;
    },
    GetBrush : function()
    {
        return 0;
    },

    drawFlowAnchor : function(x, y)
    {
    },

    SavePen : function()
    {
        this.GrState.SavePen();
    },
    RestorePen : function()
    {
        this.GrState.RestorePen();
    },

    SaveBrush : function()
    {
        this.GrState.SaveBrush();
    },

    RestoreBrush : function()
    {
        this.GrState.RestoreBrush();
    },

    SavePenBrush : function()
    {
        this.GrState.SavePenBrush();
    },
    RestorePenBrush : function()
    {
        this.GrState.RestorePenBrush();
    },

    SaveGrState : function()
    {
        this.GrState.SaveGrState();
    },
    RestoreGrState : function()
    {
        this.GrState.RestoreGrState();
    },

    StartClipPath : function()
    {
        this.m_bTurnOff = true;
    },

    EndClipPath : function()
    {
        this.m_bTurnOff = false;
    },

    SetTextPr : function(textPr, theme)
    {
        var bNeedGetPath = false;
        if(!this.CheckCompareFillBrush(textPr, this.m_oTextPr))
        {
            bNeedGetPath = true;
        }
        this.m_oTextPr = textPr;
        if(bNeedGetPath)
        {
            this.Get_PathToDraw(false, true);
        }
        if (theme)
            this.m_oGrFonts.checkFromTheme(theme.themeElements.fontScheme, this.m_oTextPr.RFonts);
        else
            this.m_oGrFonts = this.m_oTextPr.RFonts;
    },

    CheckCompareFillBrush: function(oTextPr1, oTextPr2)
    {
        if(!oTextPr1 && oTextPr2 || oTextPr1 && !oTextPr2)
            return false;
        if(oTextPr1 && oTextPr2)
        {
            var oFill1 = this.GetFillFromTextPr(oTextPr1);
            var oFill2 = this.GetFillFromTextPr(oTextPr2);
            if(!CompareBrushes(oFill1, oFill2))
                return false;
            var oPen1 = this.GetPenFromTextPr(oTextPr1);
            var oPen2 = this.GetPenFromTextPr(oTextPr2);
            if(!CompareBrushes(oPen1, oPen2))
                return false;
        }
        return true;
    },

    GetFillFromTextPr: function(oTextPr)
    {
        if(oTextPr)
        {
            if(oTextPr.TextFill)
            {
                if(AscFormat.isRealNumber(oTextPr.TextFill.transparent) && oTextPr.TextFill.transparent < 254.5){
                    var oRetFill = oTextPr.TextFill.createDuplicate();
                    //oRetFill.transparent = 255.0 - oTextPr.TextFill.transparent;
                    return oRetFill;
                }
                return oTextPr.TextFill;
            }
            if(oTextPr.Unifill)
            {
                return oTextPr.Unifill;
            }
            if(oTextPr.Color)
            {
                return AscFormat.CreateUnfilFromRGB(oTextPr.Color.r, oTextPr.Color.g, oTextPr.Color.b)
            }
            return null;
        }
        else
        {
            if(this.m_oBrush.Color1.R !== -1)
            {
                var Color = this.m_oBrush.Color1;
                return AscFormat.CreateUniFillByUniColor(AscFormat.CreateUniColorRGB(Color.R, Color.G, Color.B));
            }
            else
            {
                return AscFormat.CreateUniFillByUniColor(AscFormat.CreateUniColorRGB(0, 0, 0));
            }
        }
    },

    GetPenFromTextPr: function(oTextPr)
    {
        if(oTextPr)
        {
            return oTextPr.TextOutline;
        }
        return null;
    },

    GetTextPr : function()
    {
        return this.m_oTextPr;
    },

    DrawPresentationComment : function(type, x, y, w, h)
    {
    },

    private_removeVectors : function()
    {
    },

    private_restoreVectors : function()
    {
    },

	drawMailMergeField : function(x, y, w, h)
	{
	}
};


function PolygonWrapper(oPolygon)
{
    this.oPolygon = oPolygon;
    var dCurLen = 0;
    this.aLength = [];
    this.aLength[0] = 0;
    var oPrevPoint = oPolygon[0], oCurPoint, dDX, dDY;
    for(var i = 1; i < oPolygon.length; ++i)
    {
        oCurPoint = oPolygon[i];
        dDX = oCurPoint.x - oPrevPoint.x;
        dDY = oCurPoint.y - oPrevPoint.y;
        dCurLen += Math.sqrt(dDX* dDX + dDY*dDY);
        this.aLength[i] = dCurLen;
        oPrevPoint = oCurPoint;
    }
    this.dLen = dCurLen;
    this.nPointsCount = this.aLength.length;
}

PolygonWrapper.prototype.getPointOnPolygon = function(dCT, bNeedPoints)
{
    var dFindLen = this.dLen * dCT;
    var nIndex = this.nPointsCount >> 1;
    var nStartIndex = 0, nDelta = nIndex - nStartIndex, dNextBool, nTempIndex;
    nTempIndex = nIndex + 1;
    dNextBool = (nTempIndex < this.nPointsCount) && (this.aLength[nTempIndex] <= dFindLen);
    while(nDelta > 0 && (this.aLength[nIndex] > dFindLen || dNextBool))
    {
        if(dNextBool)
        {
            nStartIndex = nIndex;
        }
        nIndex  = nStartIndex + (nDelta >> 1);
        nTempIndex = nIndex + 1;
        dNextBool = (nTempIndex < this.nPointsCount) && (this.aLength[nTempIndex] <= dFindLen);
        nDelta = nIndex - nStartIndex;
    }
    if(nTempIndex === this.nPointsCount)
    {
        --nTempIndex;
        --nIndex;
    }
    var t;
    var dDiv = this.aLength[nTempIndex] - this.aLength[nIndex];
    if(dDiv !== 0)
    {
        t = (dFindLen - this.aLength[nIndex])/dDiv;
    }
    else
    {
        t = 0;
    }

    var oPoint1 = this.oPolygon[nIndex], oPoint2 = this.oPolygon[nTempIndex];
    var oRetPoint1 = oPoint1, oRetPoint2 = oPoint2;
    if(bNeedPoints)
    {
        var nRightIndex = nTempIndex, nLeftIndex = nIndex;
        var oLeftPoint = oPoint1, oRightPoint = oPoint2;
        var dx = oPoint1.x - oPoint2.x, dy = oPoint1.y - oPoint2.y;
        while(nRightIndex + 1 < this.oPolygon.length && Math.abs(dx) < EPSILON_TEXT_AUTOFIT && Math.abs(dy) < EPSILON_TEXT_AUTOFIT)
        {

            dx =  oRightPoint.x - oLeftPoint.x;
            dy =  oRightPoint.y - oLeftPoint.y;
            oRightPoint = this.oPolygon[++nRightIndex]
        }
        while(nLeftIndex > 0 && Math.abs(dx) < EPSILON_TEXT_AUTOFIT && Math.abs(dy) < EPSILON_TEXT_AUTOFIT)
        {
            dx =  oRightPoint.x - oLeftPoint.x;
            dy =  oRightPoint.y - oLeftPoint.y;
            oLeftPoint = this.oPolygon[--nLeftIndex];
        }
        if(Math.abs(dx) < EPSILON_TEXT_AUTOFIT && Math.abs(dy) < EPSILON_TEXT_AUTOFIT)
        {
            oRetPoint1 = {x: oRetPoint1.x + EPSILON_TEXT_AUTOFIT, y: oRetPoint1.y};
        }
        else
        {
            oRetPoint1 = oLeftPoint;
            oRetPoint2 = oRightPoint;
        }
    }
    return {x: oPoint1.x + t*(oPoint2.x - oPoint1.x ), y: oPoint1.y + t*(oPoint2.y - oPoint1.y ), oP1: oRetPoint1, oP2: oRetPoint2};
};

function CheckPointByPaths(dX, dY, dWidth, dHeight, dMinX, dMinY, oPolygonWrapper1, oPolygonWrapper2)
{
    var cX, cY, point, topX, topY, bottomX, bottomY;
    cX = (dX - dMinX)/dWidth;
    cY = (dY - dMinY)/dHeight;
    if(cX > 1)
    {
        cX = 1;
    }
    if(cX < 0)
    {
        cX = 0;
    }
    point = oPolygonWrapper1.getPointOnPolygon(cX);
    topX = point.x;
    topY = point.y;
    point = oPolygonWrapper2.getPointOnPolygon(cX);
    bottomX = point.x;
    bottomY = point.y;
    return {x: topX + cY*(bottomX - topX), y: topY + cY*(bottomY - topY)};
}
function ObjectsToDrawBetweenTwoPolygons(aObjectsToDraw, oBoundsController, oPolygonWrapper1, oPolygonWrapper2)
{
    var i, j, t, dMinX = oBoundsController.min_x, dMinY = oBoundsController.min_y, aPathLst, dWidth = oBoundsController.max_x - oBoundsController.min_x, dHeight = oBoundsController.max_y - oBoundsController.min_y;
    var oCommand, oPoint, oPath;
    for(i = 0; i < aObjectsToDraw.length; ++i)
    {
        aPathLst = aObjectsToDraw[i].geometry.pathLst;
        for(t = 0; t < aPathLst.length; ++t)
        {
            oPath = aPathLst[t];
            for(j = 0; j < oPath.ArrPathCommand.length; ++j)
            {
                oCommand = oPath.ArrPathCommand[j];
                switch(oCommand.id)
                {
                    case AscFormat.moveTo:
                    case AscFormat.lineTo:
                    {
                        oPoint = CheckPointByPaths(oCommand.X, oCommand.Y, dWidth, dHeight, dMinX, dMinY, oPolygonWrapper1, oPolygonWrapper2);
                        oCommand.X = oPoint.x;
                        oCommand.Y = oPoint.y;
                        break;
                    }

                    case AscFormat.bezier3:
                    {
                        oPoint = CheckPointByPaths(oCommand.X0, oCommand.Y0, dWidth, dHeight, dMinX, dMinY, oPolygonWrapper1, oPolygonWrapper2);
                        oCommand.X0 = oPoint.x;
                        oCommand.Y0 = oPoint.y;
                        oPoint = CheckPointByPaths(oCommand.X1, oCommand.Y1, dWidth, dHeight, dMinX, dMinY, oPolygonWrapper1, oPolygonWrapper2);
                        oCommand.X1 = oPoint.x;
                        oCommand.Y1 = oPoint.y;
                        break;
                    }
                    case AscFormat.bezier4:
                    {
                        oPoint = CheckPointByPaths(oCommand.X0, oCommand.Y0, dWidth, dHeight, dMinX, dMinY, oPolygonWrapper1, oPolygonWrapper2);
                        oCommand.X0 = oPoint.x;
                        oCommand.Y0 = oPoint.y;
                        oPoint = CheckPointByPaths(oCommand.X1, oCommand.Y1, dWidth, dHeight, dMinX, dMinY, oPolygonWrapper1, oPolygonWrapper2);
                        oCommand.X1 = oPoint.x;
                        oCommand.Y1 = oPoint.y;
                        oPoint = CheckPointByPaths(oCommand.X2, oCommand.Y2, dWidth, dHeight, dMinX, dMinY, oPolygonWrapper1, oPolygonWrapper2);
                        oCommand.X2 = oPoint.x;
                        oCommand.Y2 = oPoint.y;
                        break;
                    }
                    case AscFormat.arcTo:
                    {
                        break;
                    }
                    case AscFormat.close:
                    {
                        break;
                    }
                }
            }
        }
    }
}

function TransformPointGeometry(x, y, oTransform)
{
    var oRet = {x: 0, y: 0};
    oRet.x = oTransform.TransformPointX(x,y);
    oRet.y = oTransform.TransformPointY(x,y);
    return oRet;
}


function TransformGeometry(oObjectToDraw, oTransform)
{
    var oCommand, oPoint, oPath, t, j, aPathLst;
    aPathLst = oObjectToDraw.geometry.pathLst;
    for(t = 0; t < aPathLst.length; ++t)
    {
        oPath = aPathLst[t];
        for(j = 0; j < oPath.ArrPathCommand.length; ++j)
        {
            oCommand = oPath.ArrPathCommand[j];
            switch(oCommand.id)
            {
                case AscFormat.moveTo:
                case AscFormat.lineTo:
                {
                    oPoint = TransformPointGeometry(oCommand.X, oCommand.Y, oTransform);
                    oCommand.X = oPoint.x;
                    oCommand.Y = oPoint.y;
                    break;
                }

                case AscFormat.bezier3:
                {
                    oPoint = TransformPointGeometry(oCommand.X0, oCommand.Y0, oTransform);
                    oCommand.X0 = oPoint.x;
                    oCommand.Y0 = oPoint.y;
                    oPoint = TransformPointGeometry(oCommand.X1, oCommand.Y1, oTransform);
                    oCommand.X1 = oPoint.x;
                    oCommand.Y1 = oPoint.y;
                    break;
                }
                case AscFormat.bezier4:
                {
                    oPoint = TransformPointGeometry(oCommand.X0, oCommand.Y0, oTransform);
                    oCommand.X0 = oPoint.x;
                    oCommand.Y0 = oPoint.y;
                    oPoint = TransformPointGeometry(oCommand.X1, oCommand.Y1, oTransform);
                    oCommand.X1 = oPoint.x;
                    oCommand.Y1 = oPoint.y;
                    oPoint = TransformPointGeometry(oCommand.X2, oCommand.Y2, oTransform);
                    oCommand.X2 = oPoint.x;
                    oCommand.Y2 = oPoint.y;
                    break;
                }
                case AscFormat.arcTo:
                {
                    break;
                }
                case AscFormat.close:
                {
                    break;
                }
            }
        }

    }
}

function TransformPointPolygon(x, y, oPolygon, bFlag, XLimit, ContentHeight, dKoeff, oBounds)
{
    var oRet = {x: 0, y: 0}, y0, y1, cX, oPointOnPolygon, x1t, y1t, dX, dY, x0t, y0t;
    y0 = y;//dKoeff;
    if(bFlag)
    {
        y1 = 0;
		if(oBounds)
		{
			y0 -= oBounds.min_y;
		}
    }
    else
    {
        y1 = ContentHeight*dKoeff;
        if(oBounds)
        {
            y1 = (oBounds.max_y - oBounds.min_y);
			y0 -= oBounds.min_y;
        }
    }
    cX = x/XLimit;
    oPointOnPolygon = oPolygon.getPointOnPolygon(cX, true);
    x1t = oPointOnPolygon.x;
    y1t = oPointOnPolygon.y;
    dX = oPointOnPolygon.oP2.x - oPointOnPolygon.oP1.x;
    dY = oPointOnPolygon.oP2.y - oPointOnPolygon.oP1.y;

    if(bFlag)
    {
        dX = -dX;
        dY = -dY;
    }
    var dNorm = Math.sqrt(dX*dX + dY*dY);

    if(bFlag)
    {
        x0t = x1t + (dY/dNorm)*(y0);
        y0t = y1t - (dX/dNorm)*(y0);
    }
    else
    {

        x0t = x1t + (dY/dNorm)*(y1 - y0);
        y0t = y1t - (dX/dNorm)*(y1 - y0);
    }
    oRet.x = x0t;
    oRet.y = y0t;
    return oRet;
}

function CheckGeometryByPolygon(oObjectToDraw, oPolygon, bFlag, XLimit, ContentHeight, dKoeff, oBounds)
{
    var oCommand, oPoint, oPath, t, j, aPathLst;
    aPathLst = oObjectToDraw.geometry.pathLst;
    for(t = 0; t < aPathLst.length; ++t)
    {
        oPath = aPathLst[t];
        for(j = 0; j < oPath.ArrPathCommand.length; ++j)
        {
            oCommand = oPath.ArrPathCommand[j];
            switch(oCommand.id)
            {
                case AscFormat.moveTo:
                case AscFormat.lineTo:
                {
                    oPoint = TransformPointPolygon(oCommand.X, oCommand.Y, oPolygon, bFlag, XLimit, ContentHeight, dKoeff, oBounds);
                    oCommand.X = oPoint.x;
                    oCommand.Y = oPoint.y;
                    break;
                }

                case AscFormat.bezier3:
                {
                    oPoint = TransformPointPolygon(oCommand.X0, oCommand.Y0, oPolygon, bFlag, XLimit, ContentHeight, dKoeff, oBounds);
                    oCommand.X0 = oPoint.x;
                    oCommand.Y0 = oPoint.y;
                    oPoint = TransformPointPolygon(oCommand.X1, oCommand.Y1, oPolygon, bFlag, XLimit, ContentHeight, dKoeff, oBounds);
                    oCommand.X1 = oPoint.x;
                    oCommand.Y1 = oPoint.y;
                    break;
                }
                case AscFormat.bezier4:
                {
                    oPoint = TransformPointPolygon(oCommand.X0, oCommand.Y0, oPolygon, bFlag, XLimit, ContentHeight, dKoeff, oBounds);
                    oCommand.X0 = oPoint.x;
                    oCommand.Y0 = oPoint.y;
                    oPoint = TransformPointPolygon(oCommand.X1, oCommand.Y1, oPolygon, bFlag, XLimit, ContentHeight, dKoeff, oBounds);
                    oCommand.X1 = oPoint.x;
                    oCommand.Y1 = oPoint.y;
                    oPoint = TransformPointPolygon(oCommand.X2, oCommand.Y2, oPolygon, bFlag, XLimit, ContentHeight, dKoeff, oBounds);
                    oCommand.X2 = oPoint.x;
                    oCommand.Y2 = oPoint.y;
                    break;
                }
                case AscFormat.arcTo:
                {
                    break;
                }
                case AscFormat.close:
                {
                    break;
                }
            }
        }

    }
}

function CompareBrushes(oFill1, oFill2)
{
    if(oFill1 && !oFill2 || !oFill1 && oFill2 || (oFill1 && oFill2 && !oFill1.IsIdentical(oFill2)))
        return false;
    return true;
}
function ComparePens(oPen1, oPen2)
{
    if(oPen1 && !oPen2 || !oPen1 && oPen2 || (oPen1 && oPen2 && !oPen1.IsIdentical(oPen2)))
        return false;
    return true;
}


function GetRectContentWidth(oContent, dMaxWidth)
{
    var _maxWidth = AscFormat.isRealNumber(dMaxWidth) ? dMaxWidth : 100000;

    oContent.Reset(0, 0, _maxWidth, 100000);
    oContent.Recalculate_Page(0, true);
    var max_width = 0;
    for(var i = 0; i < oContent.Content.length; ++i)
    {
        var par = oContent.Content[i];

        if(par instanceof Paragraph)
        {
            for(var j = 0; j < par.Lines.length; ++j)
            {
                if(par.Lines[j].Ranges[0].W  > max_width)
                {
                    max_width = par.Lines[j].Ranges[0].W;
                }
            }
        }
    }
    return max_width + 2;
}

    //--------------------------------------------------------export----------------------------------------------------
    window['AscFormat'] = window['AscFormat'] || {};
    window['AscFormat'].PATH_DIV_EPSILON = PATH_DIV_EPSILON;
    window['AscFormat'].ParaDrawingStruct = ParaDrawingStruct;
    window['AscFormat'].DRAW_COMMAND_TABLE = DRAW_COMMAND_TABLE;
    window['AscFormat'].DRAW_COMMAND_CONTENT = DRAW_COMMAND_CONTENT;
    window['AscFormat'].DRAW_COMMAND_PARAGRAPH = DRAW_COMMAND_PARAGRAPH;
    window['AscFormat'].DRAW_COMMAND_LINE = DRAW_COMMAND_LINE;
    window['AscFormat'].DRAW_COMMAND_DRAWING = DRAW_COMMAND_DRAWING;
    window['AscFormat'].DRAW_COMMAND_HIDDEN_ELEM = DRAW_COMMAND_HIDDEN_ELEM;
    window['AscFormat'].DRAW_COMMAND_NO_CREATE_GEOM = DRAW_COMMAND_NO_CREATE_GEOM;
    window['AscFormat'].DRAW_COMMAND_TABLE_ROW = DRAW_COMMAND_TABLE_ROW;
    window['AscFormat'].CreatePenFromParams = CreatePenFromParams;
    window['AscFormat'].CTextDrawer = CTextDrawer;
    window['AscFormat'].PolygonWrapper = PolygonWrapper;
    window['AscFormat'].GetRectContentWidth = GetRectContentWidth;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, document){

// Import
var FontStyle = AscFonts.FontStyle;
var DecodeBase64Char = AscFonts.DecodeBase64Char;
var b64_decode = AscFonts.b64_decode;
var FT_Stream = AscFonts.FT_Stream;

var g_map_font_index = {};
var g_fonts_streams = [];

function ZBase32Encoder()
{
    this.EncodingTable = "ybndrfg8ejkmcpqxot1uwisza345h769";
    this.DecodingTable = ("undefined" == typeof Uint8Array) ? new Array(128) : new Uint8Array(128);

    var ii =  0;
    for (ii = 0; ii < 128; ii++)
        this.DecodingTable[ii] = 255;

    var _len_32 = this.EncodingTable.length;
    for (ii = 0; ii < _len_32; ii++)
    {
        this.DecodingTable[this.EncodingTable.charCodeAt(ii)] = ii;
    }

    this.GetUTF16_fromUnicodeChar = function(code)
    {
        if (code < 0x10000)
            return String.fromCharCode(code);
        else
        {
            code -= 0x10000;
            return String.fromCharCode(0xD800 | ((code >> 10) & 0x03FF)) + String.fromCharCode(0xDC00 | (code & 0x03FF));
        }
    };

    this.GetUTF16_fromUTF8 = function(pBuffer)
    {
        var _res = "";

        var lIndex = 0;
        var lCount = pBuffer.length;
        var val = 0;
        while (lIndex < lCount)
        {
            var byteMain = pBuffer[lIndex];
            if (0x00 == (byteMain & 0x80))
            {
                // 1 byte
                _res += this.GetUTF16_fromUnicodeChar(byteMain);
                ++lIndex;
            }
            else if (0x00 == (byteMain & 0x20))
            {
                // 2 byte
                val = (((byteMain & 0x1F) << 6) |
                            (pBuffer[lIndex + 1] & 0x3F));
                _res += this.GetUTF16_fromUnicodeChar(val);
                lIndex += 2;
            }
            else if (0x00 == (byteMain & 0x10))
            {
                // 3 byte
                val = (((byteMain & 0x0F) << 12) |
                            ((pBuffer[lIndex + 1] & 0x3F) << 6) |
                            (pBuffer[lIndex + 2] & 0x3F));

                _res += this.GetUTF16_fromUnicodeChar(val);
                lIndex += 3;
            }
            else if (0x00 == (byteMain & 0x08))
            {
                // 4 byte
                val = (((byteMain & 0x07) << 18) |
                            ((pBuffer[lIndex + 1] & 0x3F) << 12) |
                            ((pBuffer[lIndex + 2] & 0x3F) << 6) |
                            (pBuffer[lIndex + 3] & 0x3F));

                _res += this.GetUTF16_fromUnicodeChar(val);
                lIndex += 4;
            }
            else if (0x00 == (byteMain & 0x04))
            {
                // 5 byte
                val = (((byteMain & 0x03) << 24) |
                            ((pBuffer[lIndex + 1] & 0x3F) << 18) |
                            ((pBuffer[lIndex + 2] & 0x3F) << 12) |
                            ((pBuffer[lIndex + 3] & 0x3F) << 6) |
                            (pBuffer[lIndex + 4] & 0x3F));

                _res += this.GetUTF16_fromUnicodeChar(val);
                lIndex += 5;
            }
            else
            {
                // 6 byte
                val = (((byteMain & 0x01) << 30) |
                            ((pBuffer[lIndex + 1] & 0x3F) << 24) |
                            ((pBuffer[lIndex + 2] & 0x3F) << 18) |
                            ((pBuffer[lIndex + 3] & 0x3F) << 12) |
                            ((pBuffer[lIndex + 4] & 0x3F) << 6) |
                            (pBuffer[lIndex + 5] & 0x3F));

                _res += this.GetUTF16_fromUnicodeChar(val);
                lIndex += 5;
            }
        }

        return _res;
    };

    this.GetUTF8_fromUTF16 = function(sData)
    {
        var pCur = 0;
        var pEnd = sData.length;

        var result = [];
        while (pCur < pEnd)
        {
            var code = sData.charCodeAt(pCur++);
            if (code >= 0xD800 && code <= 0xDFFF && pCur < pEnd)
            {
                code = 0x10000 + (((code & 0x3FF) << 10) | (0x03FF & sData.charCodeAt(pCur++)));
            }

            if (code < 0x80)
            {
                result.push(code);
            }
            else if (code < 0x0800)
            {
                result.push(0xC0 | (code >> 6));
                result.push(0x80 | (code & 0x3F));
            }
            else if (code < 0x10000)
            {
                result.push(0xE0 | (code >> 12));
                result.push(0x80 | ((code >> 6) & 0x3F));
                result.push(0x80 | (code & 0x3F));
            }
            else if (code < 0x1FFFFF)
            {
                result.push(0xF0 | (code >> 18));
                result.push(0x80 | ((code >> 12) & 0x3F));
                result.push(0x80 | ((code >> 6) & 0x3F));
                result.push(0x80 | (code & 0x3F));
            }
            else if (code < 0x3FFFFFF)
            {
                result.push(0xF8 | (code >> 24));
                result.push(0x80 | ((code >> 18) & 0x3F));
                result.push(0x80 | ((code >> 12) & 0x3F));
                result.push(0x80 | ((code >> 6) & 0x3F));
                result.push(0x80 | (code & 0x3F));
            }
            else if (code < 0x7FFFFFFF)
            {
                result.push(0xFC | (code >> 30));
                result.push(0x80 | ((code >> 24) & 0x3F));
                result.push(0x80 | ((code >> 18) & 0x3F));
                result.push(0x80 | ((code >> 12) & 0x3F));
                result.push(0x80 | ((code >> 6) & 0x3F));
                result.push(0x80 | (code & 0x3F));
            }
        }

        return result;
    };

    this.Encode = function(sData)
    {
        return encodeURIComponent(sData);

        var data = this.GetUTF8_fromUTF16(sData);

        var encodedResult = "";
        var len = data.length;
        for (var i = 0; i < len; i += 5)
        {
            var byteCount = Math.min(5, len - i);

            var buffer = 0;
            for (var j = 0; j < byteCount; ++j)
            {
                buffer *= 256;
                buffer += data[i + j];
            }

            var bitCount = byteCount * 8;
            while (bitCount > 0)
            {
                var index = 0;
                if (bitCount >= 5)
                {
                    var _del = Math.pow(2, bitCount - 5);
                    //var _del = 1 << (bitCount - 5);
                    index = (buffer / _del) & 0x1f;
                }
                else
                {
                    index = (buffer & (0x1f >> (5 - bitCount)));
                    index <<= (5 - bitCount);
                }

                encodedResult += this.EncodingTable.charAt(index);
                bitCount -= 5;
            }
        }

        return encodedResult;
    };

    this.Decode = function(data)
    {
        var result = [];

        var _len = data.length;
        var obj = { data: data, index : new Array(8) };

        var cur = 0;
        while (cur < _len)
        {
            cur = this.CreateIndexByOctetAndMovePosition(obj, cur);

            var shortByteCount = 0;
            var buffer = 0;
            for (var j = 0; j < 8 && obj.index[j] != -1; ++j)
            {
                buffer *= 32;
                buffer += (this.DecodingTable[obj.index[j]] & 0x1f);
                shortByteCount++;
            }

            var bitCount = shortByteCount * 5;
            while (bitCount >= 8)
            {
                //var _del = 1 << (bitCount - 8);
                var _del = Math.pow(2, bitCount - 8);
                var _res = (buffer / _del) & 0xff;
                result.push(_res);
                bitCount -= 8;
            }
        }

        this.GetUTF16_fromUTF8(result);
    };

    this.CreateIndexByOctetAndMovePosition = function(obj, currentPosition)
    {
        var j = 0;
        while (j < 8)
        {
            if (currentPosition >= obj.data.length)
            {
                obj.index[j++] = -1;
                continue;
            }

            if (this.IgnoredSymbol(obj.data.charCodeAt(currentPosition)))
            {
                currentPosition++;
                continue;
            }

            obj.index[j] = obj.data[currentPosition];
            j++;
            currentPosition++;
        }

        return currentPosition;
    };

    this.IgnoredSymbol = function(checkedSymbol)
    {
        return (checkedSymbol >= 128 || this.DecodingTable[checkedSymbol] == 255);
    };
}

var bIsLocalFontsUse = false;

function _is_support_cors()
{
    if (window["NATIVE_EDITOR_ENJINE"] === true)
        return false;
        
    var xhrSupported = new XMLHttpRequest();
    return !!xhrSupported && ("withCredentials" in xhrSupported);
}
var bIsSupportOriginalFormatFonts = _is_support_cors();

function postLoadScript(scriptName)
{
    window.postMessage({type: "FROM_PAGE_LOAD_SCRIPT", text: scriptName}, "*");
}

/*window.addEventListener("message", function(event) {
    // We only accept messages from ourselves
    if (event.source != window)
        return;

    if (event.data.type && (event.data.type == "FROM_SCRIPT_LOAD_SCRIPT"))
    {
        var _mess = event.data.text;
        var _files = window.g_font_files;

        // потом сделать мап, при первом обращении
        for (var i = 0; i < _files.length; i++)
        {
            if (_files[i].Id == _mess)
            {
                var bIsUseOrigF = false;
                if (_files[i].CanUseOriginalFormat && // false if load embedded fonts
                    bIsSupportOriginalFormatFonts) // false if work on ie9
                    bIsUseOrigF = true;

                if (!bIsUseOrigF)
                {
                    _files[i]._callback_font_load();
                }
                else
                {
                    bIsLocalFontsUse = false;
                    _files[i].LoadFontAsync(event.data.src, null);
                    bIsLocalFontsUse = true;
                }

                break;
            }

        }
    }
    else if (event.data.type && (event.data.type == "FROM_SCRIPT_IS_EXIST"))
    {
        bIsLocalFontsUse = true;
    }
}, false);*/

function CFontFileLoader(id)
{
    this.Id         = id;
    this.Status     = -1;  // -1 - notloaded, 0 - loaded, 1 - error, 2 - loading
    this.stream_index = -1;
    this.callback = null;
    this.IsNeedAddJSToFontPath = true;

    this.CanUseOriginalFormat = true;

    var oThis = this;

    this.CheckLoaded = function()
    {
        return (0 == this.Status || 1 == this.Status);
    }

    this._callback_font_load = function()
    {
        if (!window[oThis.Id])
            oThis.Status = 1;

        var __font_data_idx = g_fonts_streams.length;
        g_fonts_streams[__font_data_idx] = AscFonts.CreateFontData4(window[oThis.Id]);
        oThis.SetStreamIndex(__font_data_idx);

        oThis.Status = 0;

        // удаляем строку
        delete window[oThis.Id];

        if (null != oThis.callback)
            oThis.callback();
    }

    this.LoadFontAsync2 = function(basePath, _callback)
    {
        this.callback = _callback;
        if (-1 != this.Status)
            return true;

        if (bIsLocalFontsUse)
        {
            postLoadScript(this.Id);
            return;
        }
        this.Status = 2;

        var xhr = new XMLHttpRequest();

        xhr.open('GET', basePath + this.Id, true); // TODO:

        if (typeof ArrayBuffer !== 'undefined' && !window.opera)
            xhr.responseType = 'arraybuffer';

        if (xhr.overrideMimeType)
            xhr.overrideMimeType('text/plain; charset=x-user-defined');
        else
            xhr.setRequestHeader('Accept-Charset', 'x-user-defined');

        xhr.onload = function()
        {
            if (this.status != 200)
            {
                oThis.Status = 1;
                return;
            }

            oThis.Status = 0;

            if (typeof ArrayBuffer !== 'undefined' && !window.opera && this.response)
            {
                var __font_data_idx = g_fonts_streams.length;
                var _uintData = new Uint8Array(this.response);
                g_fonts_streams[__font_data_idx] = new FT_Stream(_uintData, _uintData.length);
                oThis.SetStreamIndex(__font_data_idx);
            }
            else if (AscCommon.AscBrowser.isIE)
            {
                var _response = new VBArray(this["responseBody"]).toArray();

                var srcLen = _response.length;
                var pointer = g_memory.Alloc(srcLen);
                var stream = new FT_Stream(pointer.data, srcLen);
                stream.obj = pointer.obj;

                var dstPx = stream.data;
                var index = 0;

                while (index < srcLen)
                {
                    dstPx[index] = _response[index];
                    index++;
                }

                var __font_data_idx = g_fonts_streams.length;
                g_fonts_streams[__font_data_idx] = stream;
                oThis.SetStreamIndex(__font_data_idx);
            }
            else
            {
                var __font_data_idx = g_fonts_streams.length;
                g_fonts_streams[__font_data_idx] = AscFonts.CreateFontData3(this.responseText);
                oThis.SetStreamIndex(__font_data_idx);
            }

            // decode
            var guidOdttf = [0xA0, 0x66, 0xD6, 0x20, 0x14, 0x96, 0x47, 0xfa, 0x95, 0x69, 0xB8, 0x50, 0xB0, 0x41, 0x49, 0x48];
            var _stream = g_fonts_streams[g_fonts_streams.length - 1];
            var _data = _stream.data;

            /*
            // CRYPTPAD: deactivating decoding so that we use native ttf files
            var _count_decode = Math.min(32, _stream.size);
            for (var i = 0; i < _count_decode; ++i)
                _data[i] ^= guidOdttf[i % 16];
            */
        };

        xhr.send(null);
    }
    
    this.LoadFontNative = function()
    {
		if (window["use_native_fonts_only"] === true)
		{
			// all font engine now native
			this.Status = 0;
			return;
		}
		
        var __font_data_idx = g_fonts_streams.length;
        var _data = window["native"]["GetFontBinary"](this.Id);
        g_fonts_streams[__font_data_idx] = new FT_Stream(_data, _data.length);
        this.SetStreamIndex(__font_data_idx);
        this.Status = 0;
    }
}

CFontFileLoader.prototype.SetStreamIndex = function(index)
{
	this.stream_index = index;
};
CFontFileLoader.prototype.LoadFontAsync = function(basePath, _callback, isEmbed)
{
	var oThis = this;
	if (window["AscDesktopEditor"] !== undefined && this.CanUseOriginalFormat)
	{
		if (-1 != this.Status)
			return true;

		this.callback = null;
		this.Status = 2;
		window["AscDesktopEditor"]["LoadFontBase64"](this.Id);
		this._callback_font_load();
		return;
	}

	if (this.CanUseOriginalFormat && // false if load embedded fonts
		bIsSupportOriginalFormatFonts) // false if work on ie9
	{
		this.LoadFontAsync2(basePath, _callback);
		return;
	}

	this.callback = _callback;
	if (-1 != this.Status)
		return true;

	this.Status = 2;
	if (bIsLocalFontsUse)
	{
		postLoadScript(this.Id);
		return;
	}

	var scriptElem = document.createElement('script');

	if (scriptElem.readyState && false)
	{
		scriptElem.onreadystatechange = function () {
			if (this.readyState == 'complete' || this.readyState == 'loaded')
			{
				scriptElem.onreadystatechange = null;
				setTimeout(oThis._callback_font_load, 0);
			}
		}
	}
	scriptElem.onload = scriptElem.onerror = oThis._callback_font_load;

	var src = basePath + this.Id + ".js";
	if(isEmbed)
		src = AscCommon.g_oDocumentUrls.getUrl(src);
	scriptElem.setAttribute('src', src);
	scriptElem.setAttribute('type','text/javascript');
	document.getElementsByTagName('head')[0].appendChild(scriptElem);
	return false;
};

var FONT_TYPE_ADDITIONAL = 0;
var FONT_TYPE_STANDART = 1;
var FONT_TYPE_EMBEDDED = 2;
var FONT_TYPE_ADDITIONAL_CUT = 3;

var fontstyle_mask_regular = 1;
var fontstyle_mask_italic = 2;
var fontstyle_mask_bold = 4;
var fontstyle_mask_bolditalic = 8;

function GenerateMapId(api, name, style, size)
{
    var fontInfo = api.FontLoader.fontInfos[api.FontLoader.map_font_index[name]];
    var index = -1;

	// подбираем шрифт по стилю
    var bNeedBold   = false;
    var bNeedItalic = false;

    var index       = -1;
    var faceIndex   = 0;

    var bSrcItalic  = false;
    var bSrcBold    = false;

    switch (style)
    {
        case FontStyle.FontStyleBoldItalic:
        {
            bSrcItalic  = true;
            bSrcBold    = true;

            bNeedBold   = true;
            bNeedItalic = true;
            if (-1 != fontInfo.indexBI)
            {
                index = fontInfo.indexBI;
                faceIndex = fontInfo.faceIndexBI;
                bNeedBold   = false;
                bNeedItalic = false;
            }
            else if (-1 != fontInfo.indexB)
            {
                index = fontInfo.indexB;
                faceIndex = fontInfo.faceIndexB;
                bNeedBold = false;
            }
            else if (-1 != fontInfo.indexI)
            {
                index = fontInfo.indexI;
                faceIndex = fontInfo.faceIndexI;
                bNeedItalic = false;
            }
            else
            {
                index = fontInfo.indexR;
                faceIndex = fontInfo.faceIndexR;
            }
            break;
        }
        case FontStyle.FontStyleBold:
        {
            bSrcBold    = true;

            bNeedBold   = true;
            bNeedItalic = false;
            if (-1 != fontInfo.indexB)
            {
                index = fontInfo.indexB;
                faceIndex = fontInfo.faceIndexB;
                bNeedBold = false;
            }
            else if (-1 != fontInfo.indexR)
            {
                index = fontInfo.indexR;
                faceIndex = fontInfo.faceIndexR;
            }
            else if (-1 != fontInfo.indexBI)
            {
                index = fontInfo.indexBI;
                faceIndex = fontInfo.faceIndexBI;
                bNeedBold = false;
            }
            else
            {
                index = fontInfo.indexI;
                faceIndex = fontInfo.faceIndexI;
            }
            break;
        }
        case FontStyle.FontStyleItalic:
        {
            bSrcItalic  = true;

            bNeedBold   = false;
            bNeedItalic = true;
            if (-1 != fontInfo.indexI)
            {
                index = fontInfo.indexI;
                faceIndex = fontInfo.faceIndexI;
                bNeedItalic = false;
            }
            else if (-1 != fontInfo.indexR)
            {
                index = fontInfo.indexR;
                faceIndex = fontInfo.faceIndexR;
            }
            else if (-1 != fontInfo.indexBI)
            {
                index = fontInfo.indexBI;
                faceIndex = fontInfo.faceIndexBI;
                bNeedItalic = false;
            }
            else
            {
                index = fontInfo.indexB;
                faceIndex = fontInfo.faceIndexB;
            }
            break;
        }
        case FontStyle.FontStyleRegular:
        {
            bNeedBold   = false;
            bNeedItalic = false;
            if (-1 != fontInfo.indexR)
            {
                index = fontInfo.indexR;
                faceIndex = fontInfo.faceIndexR;
            }
            else if (-1 != fontInfo.indexI)
            {
                index = fontInfo.indexI;
                faceIndex = fontInfo.faceIndexI;
            }
            else if (-1 != fontInfo.indexB)
            {
                index = fontInfo.indexB;
                faceIndex = fontInfo.faceIndexB;
            }
            else
            {
                index = fontInfo.indexBI;
                faceIndex = fontInfo.faceIndexBI;
            }
        }
    }

    var _ext = "";
    if (bNeedBold)
        _ext += "nbold";
    if (bNeedItalic)
        _ext += "nitalic";

    // index != -1 (!!!)
    var fontfile = api.FontLoader.fontFiles[index];
    return fontfile.Id + faceIndex + size + _ext;
}

function CFontInfo(sName, thumbnail, type, indexR, faceIndexR, indexI, faceIndexI, indexB, faceIndexB, indexBI, faceIndexBI)
{
    this.Name = sName;
    this.Thumbnail = thumbnail;
    this.Type = type;
    this.NeedStyles = 0;

    this.indexR     = indexR;
    this.faceIndexR = faceIndexR;
    this.needR      = false;

    this.indexI     = indexI;
    this.faceIndexI = faceIndexI;
    this.needI      = false;

    this.indexB     = indexB;
    this.faceIndexB = faceIndexB;
    this.needB      = false;

    this.indexBI    = indexBI;
    this.faceIndexBI= faceIndexBI;
    this.needBI     = false;
}

CFontInfo.prototype =
{
    CheckFontLoadStyles : function(global_loader)
    {
        if ((this.NeedStyles & 0x0F) == 0x0F)
        {
            this.needR = true;
            this.needI = true;
            this.needB = true;
            this.needBI = true;
        }
        else
        {
            if ((this.NeedStyles & 1) != 0)
            {
				// нужен стиль regular
                if (false === this.needR)
                {
                    this.needR = true;
                    if (-1 == this.indexR)
                    {
                        if (-1 != this.indexI)
                        {
                            this.needI = true;
                        }
                        else if (-1 != this.indexB)
                        {
                            this.needB = true;
                        }
                        else
                        {
                            this.needBI = true;
                        }
                    }
                }
            }
            if ((this.NeedStyles & 2) != 0)
            {
				// нужен стиль italic
                if (false === this.needI)
                {
                    this.needI = true;
                    if (-1 == this.indexI)
                    {
                        if (-1 != this.indexR)
                        {
                            this.needR = true;
                        }
                        else if (-1 != this.indexBI)
                        {
                            this.needBI = true;
                        }
                        else
                        {
                            this.needB = true;
                        }
                    }
                }
            }
            if ((this.NeedStyles & 4) != 0)
            {
                // нужен стиль bold
                if (false === this.needB)
                {
                    this.needB = true;
                    if (-1 == this.indexB)
                    {
                        if (-1 != this.indexR)
                        {
                            this.needR = true;
                        }
                        else if (-1 != this.indexBI)
                        {
                            this.needBI = true;
                        }
                        else
                        {
                            this.needI = true;
                        }
                    }
                }
            }
            if ((this.NeedStyles & 8) != 0)
            {
                // нужен стиль bold
                if (false === this.needBI)
                {
                    this.needBI = true;
                    if (-1 == this.indexBI)
                    {
                        if (-1 != this.indexB)
                        {
                            this.needB = true;
                        }
                        else if (-1 != this.indexI)
                        {
                            this.needI = true;
                        }
                        else
                        {
                            this.needR = true;
                        }
                    }
                }
            }
        }

		var isEmbed = (FONT_TYPE_EMBEDDED == this.Type);
        var fonts = isEmbed ? global_loader.embeddedFontFiles : global_loader.fontFiles;
        var basePath = isEmbed ? global_loader.embeddedFilesPath : global_loader.fontFilesPath;
        var isNeed = false;
        if ((this.needR === true) && (-1 != this.indexR) && (fonts[this.indexR].CheckLoaded() === false))
        {
            fonts[this.indexR].LoadFontAsync(basePath, null, isEmbed);
            isNeed = true;
        }
        if ((this.needI === true) && (-1 != this.indexI) && (fonts[this.indexI].CheckLoaded() === false))
        {
            fonts[this.indexI].LoadFontAsync(basePath, null, isEmbed);
            isNeed = true;
        }
        if ((this.needB === true) && (-1 != this.indexB) && (fonts[this.indexB].CheckLoaded() === false))
        {
            fonts[this.indexB].LoadFontAsync(basePath, null, isEmbed);
            isNeed = true;
        }
        if ((this.needBI === true) && (-1 != this.indexBI) && (fonts[this.indexBI].CheckLoaded() === false))
        {
            fonts[this.indexBI].LoadFontAsync(basePath, null, isEmbed);
            isNeed = true;
        }

        return isNeed;
    },

    CheckFontLoadStylesNoLoad : function(global_loader)
    {
        var fonts = (FONT_TYPE_EMBEDDED == this.Type) ? global_loader.embeddedFontFiles : global_loader.fontFiles;
        var _isNeed = false;
        if ((-1 != this.indexR) && (fonts[this.indexR].CheckLoaded() === false))
        {
            _isNeed = true;
        }
        if ((-1 != this.indexI) && (fonts[this.indexI].CheckLoaded() === false))
        {
            _isNeed = true;
        }
        if ((-1 != this.indexB) && (fonts[this.indexB].CheckLoaded() === false))
        {
            _isNeed = true;
        }
        if ((-1 != this.indexBI) && (fonts[this.indexBI].CheckLoaded() === false))
        {
            _isNeed = true;
        }

        return _isNeed;
    },

    LoadFontsFromServer : function(global_loader)
    {
        var fonts = global_loader.fontFiles;
        var basePath = global_loader.fontFilesPath;
        if ((-1 != this.indexR) && (fonts[this.indexR].CheckLoaded() === false))
        {
            fonts[this.indexR].LoadFontAsync(basePath, null);
        }
        if ((-1 != this.indexI) && (fonts[this.indexI].CheckLoaded() === false))
        {
            fonts[this.indexI].LoadFontAsync(basePath, null);
        }
        if ((-1 != this.indexB) && (fonts[this.indexB].CheckLoaded() === false))
        {
            fonts[this.indexB].LoadFontAsync(basePath, null);
        }
        if ((-1 != this.indexBI) && (fonts[this.indexBI].CheckLoaded() === false))
        {
            fonts[this.indexBI].LoadFontAsync(basePath, null);
        }
    },

    LoadFont : function(font_loader, fontManager, fEmSize, lStyle, dHorDpi, dVerDpi, transform, isNoSetupToManager)
    {
        // подбираем шрифт по стилю
        var sReturnName = this.Name;
        var bNeedBold   = false;
        var bNeedItalic = false;

        var index       = -1;
        var faceIndex   = 0;

        var bSrcItalic  = false;
        var bSrcBold    = false;

        switch (lStyle)
        {
            case FontStyle.FontStyleBoldItalic:
            {
                bSrcItalic  = true;
                bSrcBold    = true;

                bNeedBold   = true;
                bNeedItalic = true;
                if (-1 != this.indexBI)
                {
                    index = this.indexBI;
                    faceIndex = this.faceIndexBI;
                    bNeedBold   = false;
                    bNeedItalic = false;
                }
                else if (-1 != this.indexB)
                {
                    index = this.indexB;
                    faceIndex = this.faceIndexB;
                    bNeedBold = false;
                }
                else if (-1 != this.indexI)
                {
                    index = this.indexI;
                    faceIndex = this.faceIndexI;
                    bNeedItalic = false;
                }
                else
                {
                    index = this.indexR;
                    faceIndex = this.faceIndexR;
                }
                break;
            }
            case FontStyle.FontStyleBold:
            {
                bSrcBold    = true;

                bNeedBold   = true;
                bNeedItalic = false;
                if (-1 != this.indexB)
                {
                    index = this.indexB;
                    faceIndex = this.faceIndexB;
                    bNeedBold = false;
                }
                else if (-1 != this.indexR)
                {
                    index = this.indexR;
                    faceIndex = this.faceIndexR;
                }
                else if (-1 != this.indexBI)
                {
                    index = this.indexBI;
                    faceIndex = this.faceIndexBI;
                    bNeedBold = false;
                }
                else
                {
                    index = this.indexI;
                    faceIndex = this.faceIndexI;
                }
                break;
            }
            case FontStyle.FontStyleItalic:
            {
                bSrcItalic  = true;

                bNeedBold   = false;
                bNeedItalic = true;
                if (-1 != this.indexI)
                {
                    index = this.indexI;
                    faceIndex = this.faceIndexI;
                    bNeedItalic = false;
                }
                else if (-1 != this.indexR)
                {
                    index = this.indexR;
                    faceIndex = this.faceIndexR;
                }
                else if (-1 != this.indexBI)
                {
                    index = this.indexBI;
                    faceIndex = this.faceIndexBI;
                    bNeedItalic = false;
                }
                else
                {
                    index = this.indexB;
                    faceIndex = this.faceIndexB;
                }
                break;
            }
            case FontStyle.FontStyleRegular:
            {
                bNeedBold   = false;
                bNeedItalic = false;
                if (-1 != this.indexR)
                {
                    index = this.indexR;
                    faceIndex = this.faceIndexR;
                }
                else if (-1 != this.indexI)
                {
                    index = this.indexI;
                    faceIndex = this.faceIndexI;
                }
                else if (-1 != this.indexB)
                {
                    index = this.indexB;
                    faceIndex = this.faceIndexB;
                }
                else
                {
                    index = this.indexBI;
                    faceIndex = this.faceIndexBI;
                }
            }
        }

        // index != -1 (!!!)
        var fontfile = null;
        if (this.Type == FONT_TYPE_EMBEDDED)
            fontfile = font_loader.embeddedFontFiles[index];
        else
            fontfile = font_loader.fontFiles[index];

        if (window["NATIVE_EDITOR_ENJINE"] && fontfile.Status != 0)
        {
			fontfile.LoadFontNative();
        }        

        var pFontFile = fontManager.LoadFont(fontfile, faceIndex, fEmSize, bSrcBold, bSrcItalic, bNeedBold, bNeedItalic, isNoSetupToManager);

        if (pFontFile && (true !== isNoSetupToManager))
        {
            var newEmSize = fontManager.UpdateSize(fEmSize, dVerDpi, dVerDpi);
            pFontFile.SetSizeAndDpi(newEmSize, dHorDpi, dVerDpi);

            if (undefined !== transform)
            {
                fontManager.SetTextMatrix2(transform.sx,transform.shy,transform.shx,transform.sy,transform.tx,transform.ty);
            }
            else
            {
                fontManager.SetTextMatrix(1, 0, 0, 1, 0, 0);
            }
        }

        return pFontFile;
    },

    GetFontID : function(font_loader, lStyle)
    {
        // подбираем шрифт по стилю
        var sReturnName = this.Name;
        var bNeedBold   = false;
        var bNeedItalic = false;

        var index       = -1;
        var faceIndex   = 0;

        var bSrcItalic  = false;
        var bSrcBold    = false;

        switch (lStyle)
        {
            case FontStyle.FontStyleBoldItalic:
            {
                bSrcItalic  = true;
                bSrcBold    = true;

                bNeedBold   = true;
                bNeedItalic = true;
                if (-1 != this.indexBI)
                {
                    index = this.indexBI;
                    faceIndex = this.faceIndexBI;
                    bNeedBold   = false;
                    bNeedItalic = false;
                }
                else if (-1 != this.indexB)
                {
                    index = this.indexB;
                    faceIndex = this.faceIndexB;
                    bNeedBold = false;
                }
                else if (-1 != this.indexI)
                {
                    index = this.indexI;
                    faceIndex = this.faceIndexI;
                    bNeedItalic = false;
                }
                else
                {
                    index = this.indexR;
                    faceIndex = this.faceIndexR;
                }
                break;
            }
            case FontStyle.FontStyleBold:
            {
                bSrcBold    = true;

                bNeedBold   = true;
                bNeedItalic = false;
                if (-1 != this.indexB)
                {
                    index = this.indexB;
                    faceIndex = this.faceIndexB;
                    bNeedBold = false;
                }
                else if (-1 != this.indexR)
                {
                    index = this.indexR;
                    faceIndex = this.faceIndexR;
                }
                else if (-1 != this.indexBI)
                {
                    index = this.indexBI;
                    faceIndex = this.faceIndexBI;
                    bNeedBold = false;
                }
                else
                {
                    index = this.indexI;
                    faceIndex = this.faceIndexI;
                }
                break;
            }
            case FontStyle.FontStyleItalic:
            {
                bSrcItalic  = true;

                bNeedBold   = false;
                bNeedItalic = true;
                if (-1 != this.indexI)
                {
                    index = this.indexI;
                    faceIndex = this.faceIndexI;
                    bNeedItalic = false;
                }
                else if (-1 != this.indexR)
                {
                    index = this.indexR;
                    faceIndex = this.faceIndexR;
                }
                else if (-1 != this.indexBI)
                {
                    index = this.indexBI;
                    faceIndex = this.faceIndexBI;
                    bNeedItalic = false;
                }
                else
                {
                    index = this.indexB;
                    faceIndex = this.faceIndexB;
                }
                break;
            }
            case FontStyle.FontStyleRegular:
            {
                bNeedBold   = false;
                bNeedItalic = false;
                if (-1 != this.indexR)
                {
                    index = this.indexR;
                    faceIndex = this.faceIndexR;
                }
                else if (-1 != this.indexI)
                {
                    index = this.indexI;
                    faceIndex = this.faceIndexI;
                }
                else if (-1 != this.indexB)
                {
                    index = this.indexB;
                    faceIndex = this.faceIndexB;
                }
                else
                {
                    index = this.indexBI;
                    faceIndex = this.faceIndexBI;
                }
            }
        }

        // index != -1 (!!!)
        var fontfile = (this.Type == FONT_TYPE_EMBEDDED) ? font_loader.embeddedFontFiles[index] : font_loader.fontFiles[index];
        return { id: fontfile.Id, faceIndex : faceIndex, file : fontfile };
    },

    GetBaseStyle : function(lStyle)
    {
        switch (lStyle)
        {
            case FontStyle.FontStyleBoldItalic:
            {
                if (-1 != this.indexBI)
                {
                    return FontStyle.FontStyleBoldItalic;
                }
                else if (-1 != this.indexB)
                {
                    return FontStyle.FontStyleBold;
                }
                else if (-1 != this.indexI)
                {
                    return FontStyle.FontStyleItalic;
                }
                else
                {
                    return FontStyle.FontStyleRegular;
                }
                break;
            }
            case FontStyle.FontStyleBold:
            {
                if (-1 != this.indexB)
                {
                    return FontStyle.FontStyleBold;
                }
                else if (-1 != this.indexR)
                {
                    return FontStyle.FontStyleRegular;
                }
                else if (-1 != this.indexBI)
                {
                    return FontStyle.FontStyleBoldItalic;
                }
                else
                {
                    return FontStyle.FontStyleItalic;
                }
                break;
            }
            case FontStyle.FontStyleItalic:
            {
                if (-1 != this.indexI)
                {
                    return FontStyle.FontStyleItalic;
                }
                else if (-1 != this.indexR)
                {
                    return FontStyle.FontStyleRegular;
                }
                else if (-1 != this.indexBI)
                {
                    return FontStyle.FontStyleBoldItalic;
                }
                else
                {
                    return FontStyle.FontStyleBold;
                }
                break;
            }
            case FontStyle.FontStyleRegular:
            {
                if (-1 != this.indexR)
                {
                    return FontStyle.FontStyleRegular;
                }
                else if (-1 != this.indexI)
                {
                    return FontStyle.FontStyleItalic;
                }
                else if (-1 != this.indexB)
                {
                    return FontStyle.FontStyleBold;
                }
                else
                {
                    return FontStyle.FontStyleBoldItalic;
                }
            }
        }
        return FontStyle.FontStyleRegular;
    }
};

// здесь если type == FONT_TYPE_EMBEDDED, то thumbnail - это base64 картинка,
// иначе - это позиция (y) в общем табнейле всех шрифтов (ADDITIONAL и STANDART)
function CFont(name, id, type, thumbnail, style)
{
    this.name = name;
    this.id = id;
    this.type = type;
    this.thumbnail = thumbnail;
    if(null != style)
        this.NeedStyles = style;
    else
        this.NeedStyles = fontstyle_mask_regular | fontstyle_mask_italic | fontstyle_mask_bold | fontstyle_mask_bolditalic;
}
CFont.prototype.asc_getFontId = function() { return this.id; };
CFont.prototype.asc_getFontName = function() { return this.name; };
CFont.prototype.asc_getFontThumbnail = function() { return this.thumbnail; };
CFont.prototype.asc_getFontType = function() { return this.type; };

var ImageLoadStatus =
{
    Loading : 0,
    Complete : 1
};

function CImage(src)
{
    this.src    = src;
    this.Image  = null;
    this.Status = ImageLoadStatus.Complete;
}

function DecodeBase64(imData, szSrc)
{
    var srcLen = szSrc.length;
    var nWritten = 0;

    var dstPx = imData.data;
    var index = 0;

    if (window.chrome)
    {
        while (index < srcLen)
        {
            var dwCurr = 0;
            var i;
            var nBits = 0;
            for (i=0; i<4; i++)
            {
                if (index >= srcLen)
                    break;
                var nCh = DecodeBase64Char(szSrc.charCodeAt(index++));
                if (nCh == -1)
                {
                    i--;
                    continue;
                }
                dwCurr <<= 6;
                dwCurr |= nCh;
                nBits += 6;
            }

            dwCurr <<= 24-nBits;
            for (i=0; i<nBits/8; i++)
            {
                dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
                dwCurr <<= 8;
            }
        }
    }
    else
    {
        var p = b64_decode;
        while (index < srcLen)
        {
            var dwCurr = 0;
            var i;
            var nBits = 0;
            for (i=0; i<4; i++)
            {
                if (index >= srcLen)
                    break;
                var nCh = p[szSrc.charCodeAt(index++)];
                if (nCh == undefined)
                {
                    i--;
                    continue;
                }
                dwCurr <<= 6;
                dwCurr |= nCh;
                nBits += 6;
            }

            dwCurr <<= 24-nBits;
            for (i=0; i<nBits/8; i++)
            {
                dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
                dwCurr <<= 8;
            }
        }
    }
}

	var g_font_files, g_font_infos;
	(function(){
		// ALL_FONTS_PART -------------------------------------------------------------

        var i, l;
        var files = window["__fonts_files"];
		if (!files && window["native"] && window["native"]["GenerateAllFonts"])
		{
			// тогда должны быть глобальные переменные такие, без window
			window["native"]["GenerateAllFonts"]();
		}

		files = window["__fonts_files"];
		l = files ? files.length : 0;
		g_font_files = new Array(l);
		for (i = 0; i < l; i++)
		{
			g_font_files[i] = new CFontFileLoader(files[i]);
		}

		files = window["__fonts_infos"];
		l = files ? files.length : 0;
		g_font_infos = new Array(l);
		for (i = 0; i < l; i++)
		{
			var _info = files[i];
			g_font_infos[i] = new CFontInfo(_info[0], i, 0, _info[1], _info[2], _info[3], _info[4], _info[5], _info[6], _info[7], _info[8]);
			g_map_font_index[_info[0]] = i;
		}

		/////////////////////////////////////////////////////////////////////
		// а вот это наш шрифт - аналог wingdings3
		var _wngds3 = new CFontFileLoader("ASC.ttf");
		_wngds3.Status = 0;
		l = g_fonts_streams.length;
		g_fonts_streams[l] = AscFonts.CreateFontData2(" ");
		_wngds3.SetStreamIndex(l);
		g_font_files.push(_wngds3);

		l = g_font_infos.length;
		g_font_infos[l] = new CFontInfo("ASCW3", 0, FONT_TYPE_ADDITIONAL, g_font_files.length - 1, 0, -1, -1, -1, -1, -1, -1);
		g_map_font_index["ASCW3"] = l;
		/////////////////////////////////////////////////////////////////////

        if (AscFonts.FontPickerByCharacter)
            AscFonts.FontPickerByCharacter.init(window["__fonts_infos"]);

		// удаляем временные переменные
		delete window["__fonts_files"];
		delete window["__fonts_infos"];
	})();

    //------------------------------------------------------export------------------------------------------------------
    var prot;
    window['AscFonts'] = window['AscFonts'] || {};
    window['AscFonts'].g_font_files = g_font_files;
    window['AscFonts'].g_font_infos = g_font_infos;
    window['AscFonts'].g_map_font_index = g_map_font_index;
    window['AscFonts'].g_fonts_streams = g_fonts_streams;

    window['AscFonts'].FONT_TYPE_ADDITIONAL = FONT_TYPE_ADDITIONAL;
    window['AscFonts'].FONT_TYPE_STANDART = FONT_TYPE_STANDART;
    window['AscFonts'].FONT_TYPE_EMBEDDED = FONT_TYPE_EMBEDDED;
    window['AscFonts'].FONT_TYPE_ADDITIONAL_CUT = FONT_TYPE_ADDITIONAL_CUT;

    window['AscFonts'].CFontFileLoader = CFontFileLoader;
    window['AscFonts'].GenerateMapId = GenerateMapId;
    window['AscFonts'].CFontInfo = CFontInfo;
    window['AscFonts'].CFont = CFont;
    prot = CFont.prototype;
    prot['asc_getFontId'] = prot.asc_getFontId;
    prot['asc_getFontName'] = prot.asc_getFontName;
    prot['asc_getFontThumbnail'] = prot.asc_getFontThumbnail;
    prot['asc_getFontType'] = prot.asc_getFontType;
    window['AscFonts'].ImageLoadStatus = ImageLoadStatus;
    window['AscFonts'].CImage = CImage;
    window['AscFonts'].DecodeBase64 = DecodeBase64;

})(window, window.document);

// сначала хотел писать "вытеснение" из этого мапа.
// но тогда нужно хранить base64 строки. Это не круто. По памяти - даже
// выигрыш будет. Не особо то шрифты жмутся lzw или deflate
// поэтому лучше из памяти будем удалять base64 строки
// ----------------------------------------------------------------------------

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, document){
    // Import
    var g_fontApplication = AscFonts.g_fontApplication;
    var CFontFileLoader = AscFonts.CFontFileLoader;
    var FONT_TYPE_EMBEDDED = AscFonts.FONT_TYPE_EMBEDDED;
    var CFontInfo = AscFonts.CFontInfo;
    var ImageLoadStatus = AscFonts.ImageLoadStatus;
    var CImage = AscFonts.CImage;

    function CGlobalFontLoader()
    {
        // сначала хотел писать "вытеснение" из этого мапа.
        // но тогда нужно хранить base64 строки. Это не круто. По памяти - даже
        // выигрыш будет. Не особо то шрифты жмутся lzw или deflate
        // поэтому лучше из памяти будем удалять base64 строки
        this.fonts_streams = [];

        // теперь вся информация о всех возможных шрифтах. Они во всех редакторах должны быть одни и те же
        this.fontFilesPath = "../../../../fonts/";
        this.fontFiles = AscFonts.g_font_files;
        this.fontInfos = AscFonts.g_font_infos;
        this.map_font_index = AscFonts.g_map_font_index;

        // теперь вся информация о всех встроенных шрифтах. Они должны удаляться при подгрузке нового файла
        this.embeddedFilesPath = "";
        this.embeddedFontFiles = [];
        this.embeddedFontInfos = [];

        // динамическая подгрузка шрифтов
        this.ThemeLoader = null;
        this.Api = null;
        this.fonts_loading = [];
        this.fonts_loading_after_style = [];
        this.bIsLoadDocumentFirst = false;
        this.currentInfoLoaded = null;

        this.loadFontCallBack     = null;
        this.loadFontCallBackArgs = null;

        this.IsLoadDocumentFonts2 = false;

        this.put_Api = function(_api)
        {
            this.Api = _api;
        };
                
        this.LoadEmbeddedFonts = function(url, _fonts)
        {
            this.embeddedFilesPath = url;

            var _count = _fonts.length;

            if (0 == _count)
                return;

            this.embeddedFontInfos = new Array(_count);

            var map_files = {};
            for (var i = 0; i < _count; i++)
                map_files[_fonts[i].id] = _fonts[i].id;

            var index = 0;
            for (var i in map_files)
            {
                this.embeddedFontFiles[index] = new CFontFileLoader(map_files[i]);
                this.embeddedFontFiles[index].CanUseOriginalFormat = false;
                this.embeddedFontFiles[index].IsNeedAddJSToFontPath = false;
                map_files[i] = index++;
            }

            for (var i = 0; i < _count; i++)
            {
                var lStyle = 0;//_fonts[i].Style;
                if (0 == lStyle)
                    this.embeddedFontInfos[i] = new CFontInfo(_fonts[i].name, "", FONT_TYPE_EMBEDDED, map_files[_fonts[i].id], 0, -1, -1, -1, -1, -1, -1);
                else if (2 == lStyle)
                    this.embeddedFontInfos[i] = new CFontInfo(_fonts[i].name, "", FONT_TYPE_EMBEDDED, -1, -1, map_files[_fonts[i].id], _fonts[i].faceindex, -1, -1, -1, -1);
                else if (1 == lStyle)
                    this.embeddedFontInfos[i] = new CFontInfo(_fonts[i].name, "", FONT_TYPE_EMBEDDED, -1, -1, -1, -1, map_files[_fonts[i].id], _fonts[i].faceindex, -1, -1);
                else
                    this.embeddedFontInfos[i] = new CFontInfo(_fonts[i].name, "", FONT_TYPE_EMBEDDED, -1, -1, -1, -1, -1, -1, map_files[_fonts[i].id], _fonts[i].faceindex);
            }

            var _count_infos_ = this.fontInfos.length;
            for (var i = 0; i < _count; i++)
            {
                this.map_font_index[_fonts[i].name] = i + _count_infos_;
                this.fontInfos[i + _count_infos_] = this.embeddedFontInfos[i];
            }
        };

        this.SetStandartFonts = function()
        {
            //В стандартных шрифтах закоментированы те шрифты, которые были добавлены на docs.teamlab.com
            var standarts = window["standarts"];

            if (undefined == standarts)
            {
                standarts = [];
                for (var i = 0; i < this.fontInfos.length; i++)
                {
                    if (this.fontInfos[i].Name != "ASCW3")
                        standarts.push(this.fontInfos[i].Name);
                }
            }

            var _count = standarts.length;
            var _infos = this.fontInfos;
            var _map = this.map_font_index;
            for (var i = 0; i < _count; i++)
            {
                _infos[_map[standarts[i]]].Type = AscFonts.FONT_TYPE_STANDART;
            }
        };

        this.AddLoadFonts = function(name, need_styles)
        {
            var fontinfo = g_fontApplication.GetFontInfo(name);

            this.fonts_loading[this.fonts_loading.length] = fontinfo;
            this.fonts_loading[this.fonts_loading.length - 1].NeedStyles = (need_styles == undefined) ? 0x0F : need_styles;
			return fontinfo;
        };

        this.AddLoadFontsNotPick = function(info, need_styles)
        {
            this.fonts_loading[this.fonts_loading.length] = info;
            this.fonts_loading[this.fonts_loading.length - 1].NeedStyles = (need_styles == undefined) ? 0x0F : need_styles;
        };

        this.LoadDocumentFonts = function(_fonts, is_default)
        {
            if (this.IsLoadDocumentFonts2)
                return this.LoadDocumentFonts2(_fonts);

            // в конце метода нужно отдать список шрифтов
            var gui_fonts = [];
            var gui_count = 0;
            for (var i = 0; i < this.fontInfos.length; i++)
            {
                var info = this.fontInfos[i];
                if (AscFonts.FONT_TYPE_STANDART == info.Type)
                {
                    var __font = new AscFonts.CFont(info.Name, "", info.Type, info.Thumbnail);
                    gui_fonts[gui_count++] = __font;
                }
            }

            // сначала заполняем массив this.fonts_loading объекстами fontinfo
            for (var i in _fonts)
            {
                if (_fonts[i].type != FONT_TYPE_EMBEDDED)
                {
                    var info = this.AddLoadFonts(_fonts[i].name, _fonts[i].NeedStyles);

                    if (info.Type == AscFonts.FONT_TYPE_ADDITIONAL)
                    {
                        if (info.name != "ASCW3")
                        {
                            var __font = new AscFonts.CFont(info.Name, "", info.Type, info.Thumbnail);
                            gui_fonts[gui_count++] = __font;
                        }
                    }
                }
                else
                {
                    var ind = -1;
                    for (var j = 0; j < this.embeddedFontInfos.length; j++)
                    {
                        if (this.embeddedFontInfos[j].Name == _fonts[i].name)
                        {
                            this.AddLoadFontsNotPick(this.embeddedFontInfos[j], 0x0F);
                            break;
                        }
                    }
                }
            }

            this.Api.sync_InitEditorFonts(gui_fonts);

            // но только если редактор!!!
            if (this.Api.IsNeedDefaultFonts())
            {
                // теперь добавим шрифты, без которых редактор как без рук (спецсимволы + дефолтовые стили документа)
                this.AddLoadFonts("Arial", 0x0F);
                this.AddLoadFonts("Symbol", 0x0F);
                this.AddLoadFonts("Wingdings", 0x0F);
                this.AddLoadFonts("Courier New", 0x0F);
                this.AddLoadFonts("Times New Roman", 0x0F);
            }

            this.Api.asyncFontsDocumentStartLoaded();

            this.bIsLoadDocumentFirst = true;

            this.CheckFontsNeedLoadingLoad();
            this._LoadFonts();
        };

        this.CheckFontsNeedLoadingLoad = function()
        {
            var _fonts = this.fonts_loading;
            var _fonts_len = _fonts.length;

            var _need = false;
            for (var i = 0; i < _fonts_len; i++)
            {
                if (true == _fonts[i].CheckFontLoadStyles(this))
                    _need = true;
            }
            return _need;
        };

        this.CheckFontsNeedLoading = function(_fonts)
        {
            for (var i in _fonts)
            {
                var info = g_fontApplication.GetFontInfo(_fonts[i].name);
                var _isNeed = info.CheckFontLoadStylesNoLoad(this);
                if (_isNeed === true)
                    return true;
            }
            return false;
        };

        this.LoadDocumentFonts2 = function(_fonts)
        {
            // сначала заполняем массив this.fonts_loading объекстами fontinfo
            for (var i in _fonts)
            {
                this.AddLoadFonts(_fonts[i].name, 0x0F);
            }

            if (null == this.ThemeLoader)
                this.Api.asyncFontsDocumentStartLoaded();
            else
                this.ThemeLoader.asyncFontsStartLoaded();

            this.CheckFontsNeedLoadingLoad();
            this._LoadFonts();
        };

        var oThis = this;
        this._LoadFonts = function()
        {
            if (0 == this.fonts_loading.length)
            {
                if (null == this.ThemeLoader)
                    this.Api.asyncFontsDocumentEndLoaded();
                else
                    this.ThemeLoader.asyncFontsEndLoaded();

                if (this.bIsLoadDocumentFirst === true)
                {
                    var _count = this.fonts_loading_after_style.length;
                    for (var i = 0; i < _count; i++)
                    {
                        var _info = this.fonts_loading_after_style[i];
                        _info.NeedStyles = 0x0F;
                        _info.CheckFontLoadStyles(this);
                    }
                    this.fonts_loading_after_style.splice(0, this.fonts_loading_after_style.length);

                    this.bIsLoadDocumentFirst = false;
                }
                return;
            }

            var fontinfo = this.fonts_loading[0];
            var IsNeed = fontinfo.CheckFontLoadStyles(this);

            if (IsNeed)
            {
                setTimeout(oThis._check_loaded, 50);
                //setTimeout(__global_check_load_fonts, 50);
            }
            else
            {
                if (this.bIsLoadDocumentFirst === true)
                {
                    this.Api.OpenDocumentProgress.CurrentFont++;
                    this.Api.SendOpenProgress();
                }

                this.fonts_loading_after_style[this.fonts_loading_after_style.length] = this.fonts_loading[0];
                this.fonts_loading.shift();
                this._LoadFonts();
            }
        };

        this._check_loaded = function()
        {
            var IsNeed = false;

            if (0 == oThis.fonts_loading.length)
            {
                // значит асинхронно удалилось
                oThis._LoadFonts();
                return;
            }

            var current = oThis.fonts_loading[0];
            var IsNeed = current.CheckFontLoadStyles(oThis);
            if (true === IsNeed)
            {
                setTimeout(oThis._check_loaded, 50);
            }
            else
            {
                if (oThis.bIsLoadDocumentFirst === true)
                {
                    oThis.Api.OpenDocumentProgress.CurrentFont++;
                    oThis.Api.SendOpenProgress();
                }
                
                oThis.fonts_loading_after_style[oThis.fonts_loading_after_style.length] = oThis.fonts_loading[0];
                oThis.fonts_loading.shift();
                oThis._LoadFonts();
            }
        };

        this.LoadFont = function(fontinfo, loadFontCallBack, loadFontCallBackArgs)
        {
            this.currentInfoLoaded = fontinfo;

            this.currentInfoLoaded = fontinfo;
            this.currentInfoLoaded.NeedStyles = 15; // все стили

            var IsNeed = this.currentInfoLoaded.CheckFontLoadStyles(this);

            if ( undefined === loadFontCallBack )
            {
                this.loadFontCallBack     = this.Api.asyncFontEndLoaded;
                this.loadFontCallBackArgs = this.currentInfoLoaded;
            }
            else
            {
                this.loadFontCallBack     = loadFontCallBack;
                this.loadFontCallBackArgs = loadFontCallBackArgs;
            }

            if (IsNeed)
            {
                this.Api.asyncFontStartLoaded();
                setTimeout(this.check_loaded, 20);
                return true;
            }
            else
            {
                this.currentInfoLoaded = null;
                return false;
            }
        };
        this.check_loaded = function()
        {
            var current = oThis.currentInfoLoaded;

            if (null == current)
                return;

            var IsNeed = current.CheckFontLoadStyles(oThis);
            if (IsNeed)
            {
                setTimeout(oThis.check_loaded, 50);
            }
            else
            {
                oThis.loadFontCallBack.call( oThis.Api, oThis.loadFontCallBackArgs );
                oThis.currentInfoLoaded = null;
            }
        };

        this.LoadFontsFromServer = function(_fonts)
        {
            var _count = _fonts.length;
            for (var i = 0; i < _count; i++)
            {
                var _info = g_fontApplication.GetFontInfo(_fonts[i]);
                if (undefined !== _info)
                {
                    _info.LoadFontsFromServer(this);
                }
            }
        }
    }
	CGlobalFontLoader.prototype.SetStreamIndexEmb = function(font_index, stream_index)
	{
		this.embeddedFontFiles[font_index].SetStreamIndex(stream_index);
	};
	
    function CGlobalImageLoader()
    {
        this.map_image_index = {};

        // loading
        this.Api = null;
        this.ThemeLoader = null;
        this.images_loading = null;

        this.bIsLoadDocumentFirst = false;

        this.bIsAsyncLoadDocumentImages = false;

        this.bIsLoadDocumentImagesNoByOrder = true;
        this.nNoByOrderCounter = 0;

        this.loadImageCallBackCounter = 0;
        this.loadImageCallBackCounterMax = 0;
        this.loadImageCallBack = null;
        this.loadImageCallBackArgs = null;

        this.isBlockchainSupport = false;
        var oThis = this;

        if (window["AscDesktopEditor"] &&
            window["AscDesktopEditor"]["IsLocalFile"] &&
            window["AscDesktopEditor"]["isBlockchainSupport"])
        {
            this.isBlockchainSupport = (window["AscDesktopEditor"]["isBlockchainSupport"]() && !window["AscDesktopEditor"]["IsLocalFile"]());

            if (this.isBlockchainSupport)
            {
                Image.prototype.preload_crypto = function(_url)
                {
                    window["crypto_images_map"] = window["crypto_images_map"] || {};
                    if (!window["crypto_images_map"][_url])
                        window["crypto_images_map"][_url] = [];
                    window["crypto_images_map"][_url].push(this);

                    window["AscDesktopEditor"]["PreloadCryptoImage"](_url, AscCommon.g_oDocumentUrls.getLocal(_url));

                    oThis.Api.sync_StartAction(Asc.c_oAscAsyncActionType.BlockInteraction, Asc.c_oAscAsyncAction.UploadImage);
                };

                Image.prototype["onload_crypto"] = function(_src, _crypto_data)
                {
                    if (_crypto_data && AscCommon.EncryptionWorker && AscCommon.EncryptionWorker.isCryptoImages())
                    {
                        // TODO: send to plugin for decryption & call this method with empty _crypto_data
                        AscCommon.EncryptionWorker.decryptImage(_src, this, _crypto_data);
                        return;
                    }
                    this.src = _src;
                    oThis.Api.sync_EndAction(Asc.c_oAscAsyncActionType.BlockInteraction, Asc.c_oAscAsyncAction.UploadImage);
                };
            }
        }

        this.put_Api = function(_api)
        {
            this.Api = _api;

            if (this.Api.IsAsyncOpenDocumentImages !== undefined)
            {
                this.bIsAsyncLoadDocumentImages = this.Api.IsAsyncOpenDocumentImages();
                if (this.bIsAsyncLoadDocumentImages)
                {
                    if (undefined === this.Api.asyncImageEndLoadedBackground)
                        this.bIsAsyncLoadDocumentImages = false;
                }
            }
        };
        
        this.LoadDocumentImages = function(_images, isUrl)
        {
            // сначала заполним массив
            if (this.ThemeLoader == null)
                this.Api.asyncImagesDocumentStartLoaded();
            else
                this.ThemeLoader.asyncImagesStartLoaded();

            this.images_loading = [];

            for (var id in _images)
            {
                this.images_loading[this.images_loading.length] = AscCommon.getFullImageSrc2(_images[id]);
            }

            if (!this.bIsAsyncLoadDocumentImages)
            {
				this.nNoByOrderCounter = 0;
                this._LoadImages();
            }
            else
            {
                var _len = this.images_loading.length;
                for (var i = 0; i < _len; i++)
                {
                    this.LoadImageAsync(i);
                }

                this.images_loading.splice(0, _len);

                if (this.ThemeLoader == null)
                    this.Api.asyncImagesDocumentEndLoaded();
                else
                    this.ThemeLoader.asyncImagesEndLoaded();
            }
        };

        this.loadImageByUrl = function(_image, _url)
        {
            if (this.isBlockchainSupport)
                _image.preload_crypto(_url);
            else
                _image.src = _url;
        };

        this._LoadImages = function()
        {
			var _count_images = this.images_loading.length;

            if (0 == _count_images)
            {
				this.nNoByOrderCounter = 0;

                if (this.ThemeLoader == null)
                    this.Api.asyncImagesDocumentEndLoaded();
                else
                    this.ThemeLoader.asyncImagesEndLoaded();

                return;
            }

            for (var i = 0; i < _count_images; i++)
			{
				var _id = this.images_loading[i];
				var oImage = new CImage(_id);
				oImage.Status = ImageLoadStatus.Loading;
				oImage.Image = new Image();
				oThis.map_image_index[oImage.src] = oImage;
				oImage.Image.parentImage = oImage;
				oImage.Image.onload = function ()
				{
					this.parentImage.Status = ImageLoadStatus.Complete;
					oThis.nNoByOrderCounter++;

					if (oThis.bIsLoadDocumentFirst === true)
					{
						oThis.Api.OpenDocumentProgress.CurrentImage++;
						oThis.Api.SendOpenProgress();
					}

					if (!oThis.bIsLoadDocumentImagesNoByOrder)
					{
						oThis.images_loading.shift();
						oThis._LoadImages();
					}
					else if (oThis.nNoByOrderCounter == oThis.images_loading.length)
                    {
						oThis.images_loading = [];
						oThis._LoadImages();
                    }
				};
				oImage.Image.onerror = function ()
				{
					this.parentImage.Status = ImageLoadStatus.Complete;
					this.parentImage.Image = null;
					oThis.nNoByOrderCounter++;

					if (oThis.bIsLoadDocumentFirst === true)
					{
						oThis.Api.OpenDocumentProgress.CurrentImage++;
						oThis.Api.SendOpenProgress();
					}

					if (!oThis.bIsLoadDocumentImagesNoByOrder)
					{
						oThis.images_loading.shift();
						oThis._LoadImages();
					}
					else if (oThis.nNoByOrderCounter == oThis.images_loading.length)
					{
						oThis.images_loading = [];
						oThis._LoadImages();
					}
				};
				//oImage.Image.crossOrigin = 'anonymous';
				oThis.loadImageByUrl(oImage.Image, oImage.src);

				if (!oThis.bIsLoadDocumentImagesNoByOrder)
                    return;
			}
        };

        this.LoadImage = function(src, Type)
        {
            var _image = this.map_image_index[src];
            if (undefined != _image)
                return _image;

            this.Api.asyncImageStartLoaded();

            var oImage = new CImage(src);
            oImage.Type = Type;
            oImage.Image = new Image();
            oImage.Status = ImageLoadStatus.Loading;
            oThis.map_image_index[oImage.src] = oImage;

            oImage.Image.onload = function(){
                oImage.Status = ImageLoadStatus.Complete;
                oThis.Api.asyncImageEndLoaded(oImage);
            };
            oImage.Image.onerror = function(){
                oImage.Image = null;
                oImage.Status = ImageLoadStatus.Complete;
                oThis.Api.asyncImageEndLoaded(oImage);
            };
            //oImage.Image.crossOrigin = 'anonymous';
            this.loadImageByUrl(oImage.Image, oImage.src);
            return null;
        };

        this.LoadImageAsync = function(i)
        {
            var _id = oThis.images_loading[i];
            var oImage = new CImage(_id);
            oImage.Status = ImageLoadStatus.Loading;
            oImage.Image = new Image();
            oThis.map_image_index[oImage.src] = oImage;
            oImage.Image.onload = function(){
                oImage.Status = ImageLoadStatus.Complete;
                oThis.Api.asyncImageEndLoadedBackground(oImage);
            };
            oImage.Image.onerror = function(){
                oImage.Status = ImageLoadStatus.Complete;
                oImage.Image = null;
                oThis.Api.asyncImageEndLoadedBackground(oImage);
            };
            //oImage.Image.crossOrigin = 'anonymous';
            oThis.loadImageByUrl(oImage.Image, oImage.src);
        };

        this.LoadImagesWithCallback = function(arr, loadImageCallBack, loadImageCallBackArgs)
        {
            var arrAsync = [];
            var i = 0;
            for (i = 0; i < arr.length; i++)
            {
                if (this.map_image_index[arr[i]] === undefined)
                    arrAsync.push(arr[i]);
            }

            if (arrAsync.length == 0)
            {
				loadImageCallBack.call(this.Api, loadImageCallBackArgs);
                return;
            }

			this.loadImageCallBackCounter = 0;
            this.loadImageCallBackCounterMax = arrAsync.length;
			this.loadImageCallBack = loadImageCallBack;
			this.loadImageCallBackArgs = loadImageCallBackArgs;

			for (i = 0; i < arrAsync.length; i++)
			{
				var oImage = new CImage(arrAsync[i]);
				oImage.Image = new Image();
				oImage.Image.parentImage = oImage;
				oImage.Status = ImageLoadStatus.Loading;
				this.map_image_index[oImage.src] = oImage;

				oImage.Image.onload = function ()
				{
					this.parentImage.Status = ImageLoadStatus.Complete;
					oThis.loadImageCallBackCounter++;

					if (oThis.loadImageCallBackCounter == oThis.loadImageCallBackCounterMax)
					    oThis.LoadImagesWithCallbackEnd();
				};
				oImage.Image.onerror = function ()
				{
					this.parentImage.Image = null;
					this.parentImage.Status = ImageLoadStatus.Complete;

					if (oThis.loadImageCallBackCounter == oThis.loadImageCallBackCounterMax)
						oThis.LoadImagesWithCallbackEnd();
				};
				//oImage.Image.crossOrigin = 'anonymous';
                this.loadImageByUrl(oImage.Image, oImage.src);
			}
        };

        this.LoadImagesWithCallbackEnd = function()
        {
			this.loadImageCallBack.call(this.Api, this.loadImageCallBackArgs);
			this.loadImageCallBack = null;
			this.loadImageCallBackArgs = null;
			this.loadImageCallBackCounterMax = 0;
			this.loadImageCallBackCounter = 0;
        };
    }

    var g_flow_anchor = new Image();
    g_flow_anchor.asc_complete = false;
    g_flow_anchor.onload = function(){
        g_flow_anchor.asc_complete = true;
    };
    g_flow_anchor.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAPBAMAAADNDVhEAAAAIVBMVEUAAAANDQ0NDQ0NDQ0NDQ0NDQ0AAAANDQ0NDQ0NDQ0NDQ1jk7YPAAAACnRSTlMAGkD4mb9c5s9TDghpXQAAAFZJREFUCNdjYGBgW8YABlxcIBLBZ1gAEfZa5QWiGRkWMAIpAaA4iHQE0YwODEtANMsChkIwv4BBWQBICyswMC1iWADEDAzKoUuDFUAGNC9uABvIaQkkABpxD6lFb9lRAAAAAElFTkSuQmCC";

    var g_flow_anchor2 = new Image();
    g_flow_anchor2.asc_complete = false;
    g_flow_anchor2.onload = function(){
        g_flow_anchor2.asc_complete = true;
    };
    g_flow_anchor2.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAeCAMAAAAFBf7qAAAAOVBMVEUAAAAAAAAAAAAAAAAJCQkAAAAJCQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJCQknI0ZQAAAAEnRSTlMAx9ITlAfyPHxn68yecTAl5qt6y0BvAAAAt0lEQVQoz8WS0QrDIAxFk0ajtlXb+/8fuzAprltg7Gnn4aIcvAgJTSSoBiGPoIAGV60qoquvIIL110IJgPONmKIlMI73MiwGRoZvahbKVSizcDKU8QeVPDXEIr6ShVB9VUEn2FOMkwL8VwjUtuypvDWiHeVTFeyWkZHfVQZHGm4XMhKQyJB9GKMxuHQSBlioF7u2q7kzgO2AcWwW3F8mWRmGKgyu91mK1Tzh4ixVVkBzJI/EnGjyACbfCaO3eIWRAAAAAElFTkSuQmCC";

    //---------------------------------------------------------export---------------------------------------------------
    window['AscCommon'] = window['AscCommon'] || {};
    window['AscCommon'].g_font_loader = new CGlobalFontLoader();
    window['AscCommon'].g_image_loader = new CGlobalImageLoader();
    window['AscCommon'].g_flow_anchor = g_flow_anchor;
    window['AscCommon'].g_flow_anchor2 = g_flow_anchor2;
})(window, window.document);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){
    // Import
    var g_dKoef_mm_to_pix = AscCommon.g_dKoef_mm_to_pix;

function CBounds()
{
    this.L      = 0;    // левая граница
    this.T      = 0;    // верхняя граница
    this.R      = 0;    // правая граница (если поднят флаг isAbsR, то это расстояние справа, а не R)
    this.B      = 0;    // верхняя граница (если поднят флаг isAbsB, то это расстояние справа, а не B)

    this.isAbsL = false;
    this.isAbsT = false;
    this.isAbsR = false;
    this.isAbsB = false;

    this.AbsW   = -1;
    this.AbsH   = -1;

    this.SetParams = function(_l,_t,_r,_b,abs_l,abs_t,abs_r,abs_b,absW,absH)
    {
        this.L = _l;
        this.T = _t;
        this.R = _r;
        this.B = _b;

        this.isAbsL = abs_l;
        this.isAbsT = abs_t;
        this.isAbsR = abs_r;
        this.isAbsB = abs_b;

        this.AbsW   = absW;
        this.AbsH   = absH;
    }
}

function CAbsolutePosition()
{
    this.L  = 0;
    this.T  = 0;
    this.R  = 0;
    this.B  = 0;
}

var g_anchor_left       = 1;
var g_anchor_top        = 2;
var g_anchor_right      = 4;
var g_anchor_bottom     = 8;

function CControl()
{
    this.Bounds         = new CBounds();

    this.Anchor         = g_anchor_left | g_anchor_top;

    this.Name           = null;
    this.Parent         = null;
    this.TabIndex       = null;

    this.HtmlElement    = null;

    this.AbsolutePosition = new CBounds();
	
	this.Resize = function(_width,_height,api)
	{
		if ((null == this.Parent) || (null == this.HtmlElement))
			return;

        var _x = 0;
        var _y = 0;
        var _r = 0;
        var _b = 0;

        var hor_anchor = (this.Anchor & 0x05);
        var ver_anchor = (this.Anchor & 0x0A);

        if (g_anchor_left == hor_anchor)
        {
            if (this.Bounds.isAbsL)
                _x = this.Bounds.L;
            else
                _x = (this.Bounds.L * _width / 1000);

            if (-1 != this.Bounds.AbsW)
                _r = _x + this.Bounds.AbsW;
            else
            {
                if (this.Bounds.isAbsR)
                    _r = (_width - this.Bounds.R);
                else
                    _r = this.Bounds.R * _width / 1000;
            }
        }
        else if (g_anchor_right == hor_anchor)
        {
            if (this.Bounds.isAbsR)
                _r = (_width - this.Bounds.R);
            else
                _r = (this.Bounds.R * _width / 1000);

            if (-1 != this.Bounds.AbsW)
                _x = _r - this.Bounds.AbsW;
            else
            {
                if (this.Bounds.isAbsL)
                    _x = this.Bounds.L;
                else
                    _x = this.Bounds.L * _width / 1000;
            }
        }
        else if ((g_anchor_left | g_anchor_right) == hor_anchor)
        {
            if (this.Bounds.isAbsL)
                _x = this.Bounds.L;
            else
                _x = (this.Bounds.L * _width / 1000);

            if (this.Bounds.isAbsR)
                _r = (_width - this.Bounds.R);
            else
                _r = (this.Bounds.R * _width / 1000);
        }
        else
        {
            _x = this.Bounds.L;
            _r = this.Bounds.R;
        }

        if (g_anchor_top == ver_anchor)
        {
            if (this.Bounds.isAbsT)
                _y = this.Bounds.T;
            else
                _y = (this.Bounds.T * _height / 1000);

            if (-1 != this.Bounds.AbsH)
                _b = _y + this.Bounds.AbsH;
            else
            {
                if (this.Bounds.isAbsB)
                    _b = (_height - this.Bounds.B);
                else
                    _b = this.Bounds.B * _height / 1000;
            }
        }
        else if (g_anchor_bottom == ver_anchor)
        {
            if (this.Bounds.isAbsB)
                _b = (_height - this.Bounds.B);
            else
                _b = (this.Bounds.B * _height / 1000);

            if (-1 != this.Bounds.AbsH)
                _y = _b - this.Bounds.AbsH;
            else
            {
                if (this.Bounds.isAbsT)
                    _y = this.Bounds.T;
                else
                    _y = this.Bounds.T * _height / 1000;
            }
        }
        else if ((g_anchor_top | g_anchor_bottom) == ver_anchor)
        {
            if (this.Bounds.isAbsT)
                _y = this.Bounds.T;
            else
                _y = (this.Bounds.T * _height / 1000);

            if (this.Bounds.isAbsB)
                _b = (_height - this.Bounds.B);
            else
                _b = (this.Bounds.B * _height / 1000);
        }
        else
        {
            _y = this.Bounds.T;
            _b = this.Bounds.B;
        }

        if (_r < _x)
            _r = _x;
        if (_b < _y)
            _b = _y;

        this.AbsolutePosition.L = _x;
        this.AbsolutePosition.T = _y;
        this.AbsolutePosition.R = _r;
        this.AbsolutePosition.B = _b;

        this.HtmlElement.style.left 	= ((_x * g_dKoef_mm_to_pix + 0.5) >> 0) + "px";
        this.HtmlElement.style.top 		= ((_y * g_dKoef_mm_to_pix + 0.5) >> 0) + "px";
        this.HtmlElement.style.width 	= (((_r - _x) * g_dKoef_mm_to_pix + 0.5) >> 0) + "px";
        this.HtmlElement.style.height 	= (((_b - _y) * g_dKoef_mm_to_pix + 0.5) >> 0) + "px";

        if (api !== undefined && api.CheckRetinaElement && api.CheckRetinaElement(this.HtmlElement))
        {
            var _W = ((_r - _x) * g_dKoef_mm_to_pix + 0.5) >> 0;
            var _H = ((_b - _y) * g_dKoef_mm_to_pix + 0.5) >> 0;

            this.HtmlElement.width 	= AscCommon.AscBrowser.convertToRetinaValue(_W, true);
            this.HtmlElement.height = AscCommon.AscBrowser.convertToRetinaValue(_H, true);
        }
        else
        {
            this.HtmlElement.width 	= ((_r - _x) * g_dKoef_mm_to_pix + 0.5) >> 0;
            this.HtmlElement.height = ((_b - _y) * g_dKoef_mm_to_pix + 0.5) >> 0;
        }
	};

    this.GetCSS_width = function()
    {
        return ((this.AbsolutePosition.R - this.AbsolutePosition.L) * g_dKoef_mm_to_pix + 0.5) >> 0;
    };
    this.GetCSS_height = function()
    {
        return ((this.AbsolutePosition.B - this.AbsolutePosition.T) * g_dKoef_mm_to_pix + 0.5) >> 0;
    };
}

function CControlContainer()
{
    this.Bounds         = new CBounds();
    this.Anchor         = g_anchor_left | g_anchor_top;

    this.Name           = null;
    this.Parent         = null;
    this.TabIndex       = null;

    this.HtmlElement    = null;

    this.AbsolutePosition = new CBounds();
	
    this.Controls       = [];

    this.AddControl = function(ctrl)
    {
        ctrl.Parent = this;
        this.Controls[this.Controls.length] = ctrl;
    };
	
	this.Resize = function(_width,_height,api)
	{
		if (null == this.Parent)
        {
            this.AbsolutePosition.L = 0;
            this.AbsolutePosition.T = 0;
            this.AbsolutePosition.R = _width;
            this.AbsolutePosition.B = _height;

            if (null != this.HtmlElement)
            {
                var lCount = this.Controls.length;
                for (var i = 0; i < lCount; i++)
                {
                    this.Controls[i].Resize(_width,_height,api);
                }
            }
            return;
        }

        var _x = 0;
        var _y = 0;
        var _r = 0;
        var _b = 0;

        var hor_anchor = (this.Anchor & 0x05);
		var ver_anchor = (this.Anchor & 0x0A);

        if (g_anchor_left == hor_anchor)
        {
            if (this.Bounds.isAbsL)
                _x = this.Bounds.L;
            else
                _x = (this.Bounds.L * _width / 1000);

            if (-1 != this.Bounds.AbsW)
                _r = _x + this.Bounds.AbsW;
            else
            {
                if (this.Bounds.isAbsR)
                    _r = (_width - this.Bounds.R);
                else
                    _r = this.Bounds.R * _width / 1000;
            }
        }
        else if (g_anchor_right == hor_anchor)
        {
            if (this.Bounds.isAbsR)
                _r = (_width - this.Bounds.R);
            else
                _r = (this.Bounds.R * _width / 1000);

            if (-1 != this.Bounds.AbsW)
                _x = _r - this.Bounds.AbsW;
            else
            {
                if (this.Bounds.isAbsL)
                    _x = this.Bounds.L;
                else
                    _x = this.Bounds.L * _width / 1000;
            }
        }
        else if ((g_anchor_left | g_anchor_right) == hor_anchor)
        {
            if (this.Bounds.isAbsL)
                _x = this.Bounds.L;
            else
                _x = (this.Bounds.L * _width / 1000);

            if (this.Bounds.isAbsR)
                _r = (_width - this.Bounds.R);
            else
                _r = (this.Bounds.R * _width / 1000);
        }
        else
        {
            _x = this.Bounds.L;
            _r = this.Bounds.R;
        }

        if (g_anchor_top == ver_anchor)
        {
            if (this.Bounds.isAbsT)
                _y = this.Bounds.T;
            else
                _y = (this.Bounds.T * _height / 1000);

            if (-1 != this.Bounds.AbsH)
                _b = _y + this.Bounds.AbsH;
            else
            {
                if (this.Bounds.isAbsB)
                    _b = (_height - this.Bounds.B);
                else
                    _b = this.Bounds.B * _height / 1000;
            }
        }
        else if (g_anchor_bottom == ver_anchor)
        {
            if (this.Bounds.isAbsB)
                _b = (_height - this.Bounds.B);
            else
                _b = (this.Bounds.B * _height / 1000);

            if (-1 != this.Bounds.AbsH)
                _y = _b - this.Bounds.AbsH;
            else
            {
                if (this.Bounds.isAbsT)
                    _y = this.Bounds.T;
                else
                    _y = this.Bounds.T * _height / 1000;
            }
        }
        else if ((g_anchor_top | g_anchor_bottom) == ver_anchor)
        {
            if (this.Bounds.isAbsT)
                _y = this.Bounds.T;
            else
                _y = (this.Bounds.T * _height / 1000);

            if (this.Bounds.isAbsB)
                _b = (_height - this.Bounds.B);
            else
                _b = (this.Bounds.B * _height / 1000);
        }
        else
        {
            _y = this.Bounds.T;
            _b = this.Bounds.B;
        }

        if (_r < _x)
            _r = _x;
        if (_b < _y)
            _b = _y;

        this.AbsolutePosition.L = _x;
        this.AbsolutePosition.T = _y;
        this.AbsolutePosition.R = _r;
        this.AbsolutePosition.B = _b;

        this.HtmlElement.style.left 	= ((_x * g_dKoef_mm_to_pix + 0.5) >> 0) + "px";
        this.HtmlElement.style.top 		= ((_y * g_dKoef_mm_to_pix + 0.5) >> 0) + "px";
        this.HtmlElement.style.width 	= (((_r - _x) * g_dKoef_mm_to_pix + 0.5) >> 0) + "px";
        this.HtmlElement.style.height 	= (((_b - _y) * g_dKoef_mm_to_pix + 0.5) >> 0) + "px";

		var lCount = this.Controls.length;
		for (var i = 0; i < lCount; i++)
		{
			this.Controls[i].Resize(_r - _x,_b - _y, api);
		}
	};

    this.GetCSS_width = function()
    {
        return ((this.AbsolutePosition.R - this.AbsolutePosition.L) * g_dKoef_mm_to_pix + 0.5) >> 0;
    };
    this.GetCSS_height = function()
    {
        return ((this.AbsolutePosition.B - this.AbsolutePosition.T) * g_dKoef_mm_to_pix + 0.5) >> 0;
    };
}

function CreateControlContainer(name)
{
    var ctrl = new CControlContainer();
    ctrl.Name = name;
    ctrl.HtmlElement = document.getElementById(name);
    return ctrl;
}
function CreateControl(name)
{
    var ctrl = new CControl();
    ctrl.Name = name;
    ctrl.HtmlElement = document.getElementById(name);
    return ctrl;
}

    //--------------------------------------------------------export----------------------------------------------------
    window['AscCommon'] = window['AscCommon'] || {};
    window['AscCommon'].g_anchor_left = g_anchor_left;
    window['AscCommon'].g_anchor_top = g_anchor_top;
    window['AscCommon'].g_anchor_right = g_anchor_right;
    window['AscCommon'].g_anchor_bottom = g_anchor_bottom;
    window['AscCommon'].CreateControlContainer = CreateControlContainer;
    window['AscCommon'].CreateControl = CreateControl;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){
    var AscBrowser = AscCommon.AscBrowser;

var TRACK_CIRCLE_RADIUS     = 5;
var TRACK_RECT_SIZE2        = 4;
var TRACK_RECT_SIZE         = 8;
var TRACK_RECT_SIZE_CT      = 6;
var TRACK_DISTANCE_ROTATE   = 25;
var TRACK_DISTANCE_ROTATE2  = 25;
var TRACK_ADJUSTMENT_SIZE   = 10;
var TRACK_WRAPPOINTS_SIZE   = 6;
var IMAGE_ROTATE_TRACK_W    = 21;

var bIsUseImageRotateTrack  = true;
if (bIsUseImageRotateTrack)
{
    window.g_track_rotate_marker = new Image();
	window.g_track_rotate_marker;
    window.g_track_rotate_marker.asc_complete = false;
    window.g_track_rotate_marker.onload = function(){
        window.g_track_rotate_marker.asc_complete = true;
    };
    window.g_track_rotate_marker.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAMAAACeyVWkAAAAVFBMVEUAAAD///////////////////////////////////////////////////////98fHy2trb09PTT09OysrKqqqqJiYng4ODr6+uamprGxsbi4uKGhoYjgM0eAAAADnRSTlMAy00k7/z0jbeuMzDljsugwZgAAACpSURBVBjTdZHbEoMgDESDAl6bgIqX9v//s67UYpm6D0xyYMImoaiuUr3pVdVRUtnwqaY8YaE5SRcfaPgqc+DSIh7WIGGaEVoUqRGN4oZlcDIiqYlaPjQz5CNu6cFJwLiuSO3nlLBDrKhn3l4rcnH4NcAdGd5EZMfCsoMFBxM6CD57G+u6vC48PMVnHtrYhP/x+7+3cw7zdJnD3cyA7QXa4nYXaW+a9Xdvb6zqE5Jb7LmzAAAAAElFTkSuQmCC";

    window.g_track_rotate_marker2 = new Image();
	window.g_track_rotate_marker2;
    window.g_track_rotate_marker2.asc_complete = false;
    window.g_track_rotate_marker2.onload = function(){
        window.g_track_rotate_marker2.asc_complete = true;
    };
    window.g_track_rotate_marker2.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAeFBMVEUAAAD///////////////////////////////////////////////////////////////////////////+Tk5Obm5v8/PzAwMD5+fmWlpbt7e3k5OSfn5/z8/PLy8vn5+fExMSsrKyqqqrf39+vr6+9vb2urq7c3NxSmuRpAAAAE3RSTlMA+u2XA+PTrId4WBwTN7EKtLY4iqQP6AAAAWhJREFUOMudVe2SgjAMLN+goN51CxTLp3r3/m943BAqIJTR/RU6O02yTRY2g5tEgW9blu0HUeKyLRxDj0/ghcdVWuxYfAHLiV95B5uvwD4saK7DN+DMSj1f+CYu58l9J27A6XnnJG9R3ZWU6l4Vk+y6D310baHRXvUxdRSP/aYZILJbmebFLRNAlo69x7PEeQdZ5Xz8qiS6fJr8aOnEquATFApdSsr/v1HINUo+Q6nwoDDspfH4JmoJ6shzWcINaNBSlLCI6uvLfyXmAlR2xIKBB/A1ZKiGIGA+8QCtphBawRt+hsBnNvE0M0OPZmwcijRnFvE0U6CuIcbrIUlJRnJL9L0YifTQCgU3p/aH4I7fnWaCIajwMMszCl5A7Aj+TWctGuMT6qG4QtbGodBj9oAyjpke3LSDYXCXq9A8V6GZrsLGcqXlcrneW9elAQgpxdwA3rcUdv4ymdQHtrdvpPvW/LHZ7/8+/gBTWGFPbAkGiAAAAABJRU5ErkJggg==";


    TRACK_DISTANCE_ROTATE2 = 18;
}


function COverlay()
{
    this.m_oControl = null;
    this.m_oContext = null;

    this.min_x = 0xFFFF;
    this.min_y = 0xFFFF;
    this.max_x = -0xFFFF;
    this.max_y = -0xFFFF;

    this.m_bIsShow = false;
    this.m_bIsAlwaysUpdateOverlay = false;

    this.m_oHtmlPage = null;

    this.DashLineColor = "#000000";
    this.ClearAll = false;

    this.IsRetina = false;
    this.IsCellEditor = false;
}

COverlay.prototype =
{
    init : function(context, controlName, x, y, w_pix, h_pix, w_mm, h_mm)
    {
        this.m_oContext = context;
        this.m_oControl = AscCommon.CreateControl(controlName);

        this.m_oHtmlPage = new AscCommon.CHtmlPage();
        this.m_oHtmlPage.init(x, y, w_pix, h_pix, w_mm, h_mm);
    },

    Clear : function()
    {
        if (null == this.m_oContext)
        {
            this.m_oContext = this.m_oControl.HtmlElement.getContext('2d');

            this.m_oContext.imageSmoothingEnabled = false;
            this.m_oContext.mozImageSmoothingEnabled = false;
            this.m_oContext.oImageSmoothingEnabled = false;
            this.m_oContext.webkitImageSmoothingEnabled = false;
        }

        this.SetBaseTransform();

        this.m_oContext.beginPath();
        if (this.max_x != -0xFFFF && this.max_y != -0xFFFF)
        {
            if (this.ClearAll === true)
            {
                this.m_oContext.clearRect(0, 0, this.m_oControl.HtmlElement.width, this.m_oControl.HtmlElement.height);
                this.ClearAll = false;
            }
            else
            {
                var _eps = 5;
                this.m_oContext.clearRect(this.min_x - _eps, this.min_y - _eps, this.max_x - this.min_x + 2*_eps, this.max_y - this.min_y + 2*_eps);
            }
        }
        this.min_x = 0xFFFF;
        this.min_y = 0xFFFF;
        this.max_x = -0xFFFF;
        this.max_y = -0xFFFF;
    },

    GetImageTrackRotationImage : function()
    {
        return this.IsRetina ? window.g_track_rotate_marker2 : window.g_track_rotate_marker;
    },

    SetTransform : function(sx, shy, shx, sy, tx, ty)
    {
        this.SetBaseTransform();
        this.m_oContext.setTransform(sx, shy, shx, sy, tx, ty);

    },

    SetBaseTransform : function()
    {
        if (this.IsRetina)
            this.m_oContext.setTransform(AscCommon.AscBrowser.retinaPixelRatio, 0, 0, AscCommon.AscBrowser.retinaPixelRatio, 0, 0);
        else
            this.m_oContext.setTransform(1, 0, 0, 1, 0, 0);
    },

    Show : function()
    {
        if (this.m_bIsShow)
            return;

        this.m_bIsShow = true;
        this.m_oControl.HtmlElement.style.display = "block";
    },
    UnShow : function()
    {
        if (!this.m_bIsShow)
            return;

        this.m_bIsShow = false;
        this.m_oControl.HtmlElement.style.display = "none";
    },

    VertLine : function(position, bIsSimpleAdd)
    {
        if (bIsSimpleAdd !== true)
        {
            this.Clear();
            if (this.m_bIsAlwaysUpdateOverlay || true/*мало ли что есть на оверлее*/)
            {
                if (!editor.WordControl.OnUpdateOverlay())
                {
                    editor.WordControl.EndUpdateOverlay();
                }
            }
        }

        if (this.min_x > position)
            this.min_x = position;
        if (this.max_x < position)
            this.max_x = position;

        //this.min_x = position;
        //this.max_x = position;
        this.min_y = 0;
        this.max_y = this.m_oControl.HtmlElement.height;

        this.m_oContext.lineWidth = 1;

        var x = ((position + 0.5) >> 0) + 0.5;
        var y = 0;

        this.m_oContext.strokeStyle = this.DashLineColor;
        this.m_oContext.beginPath();

        while (y < this.max_y)
        {
            this.m_oContext.moveTo(x, y); y++;
            this.m_oContext.lineTo(x, y); y+=1;
            this.m_oContext.moveTo(x, y); y++;
            this.m_oContext.lineTo(x, y); y+=1;
            this.m_oContext.moveTo(x, y); y++;
            this.m_oContext.lineTo(x, y); y++;

            y += 5;
        }

        this.m_oContext.stroke();

        y = 1;
        this.m_oContext.strokeStyle = "#FFFFFF";
        this.m_oContext.beginPath();

        while (y < this.max_y)
        {
            this.m_oContext.moveTo(x, y); y++;
            this.m_oContext.lineTo(x, y); y+=1;
            this.m_oContext.moveTo(x, y); y++;
            this.m_oContext.lineTo(x, y); y+=1;
            this.m_oContext.moveTo(x, y); y++;
            this.m_oContext.lineTo(x, y); y++;

            y += 5;
        }

        this.m_oContext.stroke();
        this.Show();
    },

    VertLine2 : function(position)
    {
        if (this.min_x > position)
            this.min_x = position;
        if (this.max_x < position)
            this.max_x = position;

        var _old_global = this.m_oContext.globalAlpha;
        this.m_oContext.globalAlpha = 1;

        this.min_y = 0;
        this.max_y = this.m_oControl.HtmlElement.height;

        this.m_oContext.lineWidth = 1;

        var x = ((position + 0.5) >> 0) + 0.5;
        var y = 0;

        /*
        this.m_oContext.strokeStyle = "#FFFFFF";
        this.m_oContext.beginPath();
        this.m_oContext.moveTo(x, y);
        this.m_oContext.lineTo(x, this.max_y);
        this.m_oContext.stroke();
        */

        this.m_oContext.strokeStyle = this.DashLineColor;
        this.m_oContext.beginPath();

        var dist = 1;

        while (y < this.max_y)
        {
            this.m_oContext.moveTo(x, y);
            y += dist;
            this.m_oContext.lineTo(x, y);
            y += dist;
        }

        this.m_oContext.stroke();
        this.m_oContext.beginPath();
        this.Show();

        this.m_oContext.globalAlpha = _old_global;
    },

    HorLine : function(position, bIsSimpleAdd)
    {
        if (bIsSimpleAdd !== true)
        {
            this.Clear();
            if (this.m_bIsAlwaysUpdateOverlay || true/*мало ли что есть на оверлее*/)
            {
                if (!editor.WordControl.OnUpdateOverlay())
                {
                    editor.WordControl.EndUpdateOverlay();
                }
            }
        }

        this.min_x = 0;
        this.max_x = this.m_oControl.HtmlElement.width;

        if (this.min_y > position)
            this.min_y = position;
        if (this.max_y < position)
            this.max_y = position;

        this.m_oContext.lineWidth = 1;

        var y = ((position + 0.5) >> 0) + 0.5;
        var x = 0;

        this.m_oContext.strokeStyle = this.DashLineColor;
        this.m_oContext.beginPath();

        while (x < this.max_x)
        {
            this.m_oContext.moveTo(x, y); x++;
            this.m_oContext.lineTo(x, y); x+=1;
            this.m_oContext.moveTo(x, y); x++;
            this.m_oContext.lineTo(x, y); x+=1;
            this.m_oContext.moveTo(x, y); x++;
            this.m_oContext.lineTo(x, y); x++;

            x += 5;
        }

        this.m_oContext.stroke();

        x = 1;
        this.m_oContext.strokeStyle = "#FFFFFF";
        this.m_oContext.beginPath();

        while (x < this.max_x)
        {
            this.m_oContext.moveTo(x, y); x++;
            this.m_oContext.lineTo(x, y); x+=1;
            this.m_oContext.moveTo(x, y); x++;
            this.m_oContext.lineTo(x, y); x+=1;
            this.m_oContext.moveTo(x, y); x++;
            this.m_oContext.lineTo(x, y); x++;

            x += 5;
        }

        this.m_oContext.stroke();
        this.Show();
    },

    HorLine2 : function(position)
    {
        if (this.min_y > position)
            this.min_y = position;
        if (this.max_y < position)
            this.max_y = position;

        var _old_global = this.m_oContext.globalAlpha;
        this.m_oContext.globalAlpha = 1;

        this.min_x = 0;
        this.max_x = this.m_oControl.HtmlElement.width;

        this.m_oContext.lineWidth = 1;

        var y = ((position + 0.5) >> 0) + 0.5;
        var x = 0;

        /*
        this.m_oContext.strokeStyle = "#FFFFFF";
        this.m_oContext.beginPath();
        this.m_oContext.moveTo(x, y);
        this.m_oContext.lineTo(this.max_x, y);
        this.m_oContext.stroke();
        */

        this.m_oContext.strokeStyle = this.DashLineColor;
        this.m_oContext.beginPath();

        var dist = 1;

        while (x < this.max_x)
        {
            this.m_oContext.moveTo(x, y);
            x += dist;
            this.m_oContext.lineTo(x, y);
            x += dist;
        }

        this.m_oContext.stroke();
        this.m_oContext.beginPath();
        this.Show();

        this.m_oContext.globalAlpha = _old_global;
    },

    CheckPoint1 : function(x,y)
    {
        if (x < this.min_x)
            this.min_x = x;
        if (y < this.min_y)
            this.min_y = y;
    },
    CheckPoint2 : function(x,y)
    {
        if (x > this.max_x)
            this.max_x = x;
        if (y > this.max_y)
            this.max_y = y;
    },
    CheckPoint : function(x,y)
    {
        if (x < this.min_x)
            this.min_x = x;
        if (y < this.min_y)
            this.min_y = y;
        if (x > this.max_x)
            this.max_x = x;
        if (y > this.max_y)
            this.max_y = y;
    },

    AddRect2 : function(x,y,r)
    {
        var _x = x - ((r / 2) >> 0);
        var _y = y - ((r / 2) >> 0);
        this.CheckPoint1(_x,_y);
        this.CheckPoint2(_x+r,_y+r);

        this.m_oContext.moveTo(_x,_y);
        this.m_oContext.rect(_x,_y,r,r);
    },

    AddRect3 : function(x,y,r, ex1, ey1, ex2, ey2)
    {
        var _r = r / 2;

        var x1 = x + _r * (ex2 - ex1);
        var y1 = y + _r * (ey2 - ey1);

        var x2 = x + _r * (ex2 + ex1);
        var y2 = y + _r * (ey2 + ey1);

        var x3 = x + _r * (-ex2 + ex1);
        var y3 = y + _r * (-ey2 + ey1);

        var x4 = x + _r * (-ex2 - ex1);
        var y4 = y + _r * (-ey2 - ey1);

        this.CheckPoint(x1,y1);
        this.CheckPoint(x2,y2);
        this.CheckPoint(x3,y3);
        this.CheckPoint(x4,y4);

        var ctx = this.m_oContext;
        ctx.moveTo(x1,y1);
        ctx.lineTo(x2,y2);
        ctx.lineTo(x3,y3);
        ctx.lineTo(x4,y4);
        ctx.closePath();
    },

    AddRect : function(x,y,w,h)
    {
        this.CheckPoint1(x,y);
        this.CheckPoint2(x + w,y + h);

        this.m_oContext.moveTo(x,y);
        this.m_oContext.rect(x,y,w,h);
        //this.m_oContext.closePath();
    },
    CheckRectT : function(x,y,w,h,trans,eps)
    {
        var x1 = trans.TransformPointX(x, y);
        var y1 = trans.TransformPointY(x, y);

        var x2 = trans.TransformPointX(x+w, y);
        var y2 = trans.TransformPointY(x+w, y);

        var x3 = trans.TransformPointX(x+w, y+h);
        var y3 = trans.TransformPointY(x+w, y+h);

        var x4 = trans.TransformPointX(x, y+h);
        var y4 = trans.TransformPointY(x, y+h);

        this.CheckPoint(x1, y1);
        this.CheckPoint(x2, y2);
        this.CheckPoint(x3, y3);
        this.CheckPoint(x4, y4);

        if (eps !== undefined)
        {
            this.min_x -= eps;
            this.min_y -= eps;
            this.max_x += eps;
            this.max_y += eps;
        }
    },
    CheckRect : function(x,y,w,h)
    {
        this.CheckPoint1(x,y);
        this.CheckPoint2(x + w,y + h);
    },
    AddEllipse : function(x,y,r)
    {
        this.CheckPoint1(x-r,y-r);
        this.CheckPoint2(x+r,y+r);

        this.m_oContext.moveTo(x+r,y);
        this.m_oContext.arc(x,y,r,0,Math.PI*2,false);
        //this.m_oContext.closePath();
    },

	AddDiamond : function(x,y,r)
	{
		this.CheckPoint1(x-r,y-r);
		this.CheckPoint2(x+r,y+r);

		this.m_oContext.moveTo(x-r,y);
		this.m_oContext.lineTo(x, y-r);
		this.m_oContext.lineTo(x+r, y);
		this.m_oContext.lineTo(x, y+r);
		this.m_oContext.lineTo(x-r, y);
		//this.m_oContext.closePath();
	},

    AddRoundRect : function(x, y, w, h, r)
    {
        if (w < (2 * r) || h < (2 * r))
            return this.AddRect(x, y, w, h);

        this.CheckPoint1(x,y);
        this.CheckPoint2(x + w,y + h);

        var _ctx = this.m_oContext;
        _ctx.moveTo(x + r, y);
        _ctx.lineTo(x + w - r, y);
        _ctx.quadraticCurveTo(x + w, y, x + w, y + r);
        _ctx.lineTo(x + w, y + h - r);
        _ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
        _ctx.lineTo(x + r, y + h);
        _ctx.quadraticCurveTo(x, y + h, x, y + h - r);
        _ctx.lineTo(x, y + r);
        _ctx.quadraticCurveTo(x, y, x + r, y);
    },

    AddRoundRectCtx : function(ctx, x, y, w, h, r)
    {
        if (w < (2 * r) || h < (2 * r))
            return ctx.rect(x, y, w, h);

        var _ctx = this.m_oContext;
        _ctx.moveTo(x + r, y);
        _ctx.lineTo(x + w - r, y);
        _ctx.quadraticCurveTo(x + w, y, x + w, y + r);
        _ctx.lineTo(x + w, y + h - r);
        _ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
        _ctx.lineTo(x + r, y + h);
        _ctx.quadraticCurveTo(x, y + h, x, y + h - r);
        _ctx.lineTo(x, y + r);
        _ctx.quadraticCurveTo(x, y, x + r, y);
    }
};

function CAutoshapeTrack()
{
    this.m_oContext = null;
    this.m_oOverlay = null;

    this.Graphics = null;

    this.MaxEpsLine = 0;
    this.IsTrack = true;

    this.PageIndex = -1;
    this.CurrentPageInfo = null;
}

CAutoshapeTrack.prototype =
{
    SetFont : function(font)
    {
    },

    init : function(overlay, x, y, r, b, w_mm, h_mm)
    {
        this.m_oOverlay = overlay;
        this.m_oContext = this.m_oOverlay.m_oContext;

        this.Graphics = new AscCommon.CGraphics();

        var _scale = this.m_oOverlay.IsRetina? AscCommon.AscBrowser.retinaPixelRatio : 1;

        this.Graphics.init(this.m_oContext, _scale * (r - x), _scale * (b - y), w_mm, h_mm);

        this.Graphics.m_oCoordTransform.tx = _scale * x;
        this.Graphics.m_oCoordTransform.ty = _scale * y;

        this.Graphics.SetIntegerGrid(false);


        this.Graphics.globalAlpha = 0.5;
        this.m_oContext.globalAlpha = 0.5;
    },
    SetIntegerGrid : function(b)
    {
    },
    // draw styles
    p_color : function(r,g,b,a)
    {
        this.Graphics.p_color(r, g, b, a);
    },
    p_width : function(w)
    {
        this.Graphics.p_width(w);

        var xx1 = 0;
        var yy1 = 0;
        var xx2 = 1;
        var yy2 = 1;

        var xxx1 = this.Graphics.m_oFullTransform.TransformPointX(xx1, yy1);
        var yyy1 = this.Graphics.m_oFullTransform.TransformPointY(xx1, yy1);
        var xxx2 = this.Graphics.m_oFullTransform.TransformPointX(xx2, yy2);
        var yyy2 = this.Graphics.m_oFullTransform.TransformPointY(xx2, yy2);

        var _len2 = ((xxx2 - xxx1)*(xxx2 - xxx1) + (yyy2 - yyy1)*(yyy2 - yyy1));
        var koef = Math.sqrt(_len2 / 2);

        var _EpsLine = (w * koef / 1000) >> 0;
        _EpsLine += 5;

        if (_EpsLine > this.MaxEpsLine)
            this.MaxEpsLine = _EpsLine;
    },
    p_dash : function(params)
    {
        this.Graphics.p_dash(params);
    },
    b_color1 : function(r,g,b,a)
    {
        this.Graphics.b_color1(r,g,b,a);
    },

    // path commands
    _s : function()
    {
        this.Graphics._s();
    },
    _e : function()
    {
        this.Graphics._e();
    },
    _z : function()
    {
        this.Graphics._z();
    },
    _m : function(x,y)
    {
        this.Graphics._m(x,y);

        var _x = this.Graphics.m_oFullTransform.TransformPointX(x,y);
        var _y = this.Graphics.m_oFullTransform.TransformPointY(x,y);
        this.m_oOverlay.CheckPoint(_x, _y);
    },
    _l : function(x,y)
    {
        this.Graphics._l(x,y);

        var _x = this.Graphics.m_oFullTransform.TransformPointX(x,y);
        var _y = this.Graphics.m_oFullTransform.TransformPointY(x,y);
        this.m_oOverlay.CheckPoint(_x, _y);
    },
    _c : function(x1,y1,x2,y2,x3,y3)
    {
        this.Graphics._c(x1,y1,x2,y2,x3,y3);

        var _x1 = this.Graphics.m_oFullTransform.TransformPointX(x1,y1);
        var _y1 = this.Graphics.m_oFullTransform.TransformPointY(x1,y1);

        var _x2 = this.Graphics.m_oFullTransform.TransformPointX(x2,y2);
        var _y2 = this.Graphics.m_oFullTransform.TransformPointY(x2,y2);

        var _x3 = this.Graphics.m_oFullTransform.TransformPointX(x3,y3);
        var _y3 = this.Graphics.m_oFullTransform.TransformPointY(x3,y3);

        this.m_oOverlay.CheckPoint(_x1, _y1);
        this.m_oOverlay.CheckPoint(_x2, _y2);
        this.m_oOverlay.CheckPoint(_x3, _y3);
    },
    _c2 : function(x1,y1,x2,y2)
    {
        this.Graphics._c2(x1,y1,x2,y2);

        var _x1 = this.Graphics.m_oFullTransform.TransformPointX(x1,y1);
        var _y1 = this.Graphics.m_oFullTransform.TransformPointY(x1,y1);

        var _x2 = this.Graphics.m_oFullTransform.TransformPointX(x2,y2);
        var _y2 = this.Graphics.m_oFullTransform.TransformPointY(x2,y2);

        this.m_oOverlay.CheckPoint(_x1, _y1);
        this.m_oOverlay.CheckPoint(_x2, _y2);
    },
    ds : function()
    {
        this.Graphics.ds();
    },
    df : function()
    {
        this.Graphics.df();
    },

    // canvas state
    save : function()
    {
        this.Graphics.save();
    },
    restore : function()
    {
        this.Graphics.restore();
    },
    clip : function()
    {
        this.Graphics.clip();
    },

    // transform
    reset : function()
    {
        this.Graphics.reset();
    },
    transform3 : function(m)
    {
        this.Graphics.transform3(m);
    },
    transform : function(sx,shy,shx,sy,tx,ty)
    {
        this.Graphics.transform(sx,shy,shx,sy,tx,ty);
    },
    drawImage : function(image, x, y, w, h, alpha, srcRect, nativeImage)
    {
        this.Graphics.drawImage(image, x, y, w, h, undefined, srcRect, nativeImage);

        var _x1 = this.Graphics.m_oFullTransform.TransformPointX(x,y);
        var _y1 = this.Graphics.m_oFullTransform.TransformPointY(x,y);

        var _x2 = this.Graphics.m_oFullTransform.TransformPointX(x+w,y);
        var _y2 = this.Graphics.m_oFullTransform.TransformPointY(x+w,y);

        var _x3 = this.Graphics.m_oFullTransform.TransformPointX(x+w,(y+h));
        var _y3 = this.Graphics.m_oFullTransform.TransformPointY(x+w,(y+h));

        var _x4 = this.Graphics.m_oFullTransform.TransformPointX(x,(y+h));
        var _y4 = this.Graphics.m_oFullTransform.TransformPointY(x,(y+h));

        this.m_oOverlay.CheckPoint(_x1, _y1);
        this.m_oOverlay.CheckPoint(_x2, _y2);
        this.m_oOverlay.CheckPoint(_x3, _y3);
        this.m_oOverlay.CheckPoint(_x4, _y4);
    },
    CorrectOverlayBounds : function()
    {
        this.m_oOverlay.SetBaseTransform();

        this.m_oOverlay.min_x -= this.MaxEpsLine;
        this.m_oOverlay.min_y -= this.MaxEpsLine;
        this.m_oOverlay.max_x += this.MaxEpsLine;
        this.m_oOverlay.max_y += this.MaxEpsLine;
    },

    SetCurrentPage : function(nPageIndex)
    {
        if (nPageIndex == this.PageIndex)
            return;

        var oPage = this.m_oOverlay.m_oHtmlPage.GetDrawingPageInfo(nPageIndex);
        this.PageIndex = nPageIndex;

        var drawPage = oPage.drawingPage;

        this.Graphics = new AscCommon.CGraphics();

        var _scale = this.m_oOverlay.IsRetina? AscCommon.AscBrowser.retinaPixelRatio : 1;

        this.Graphics.init(this.m_oContext, _scale * (drawPage.right - drawPage.left), _scale * (drawPage.bottom - drawPage.top), oPage.width_mm, oPage.height_mm);

        this.Graphics.m_oCoordTransform.tx = _scale * drawPage.left;
        this.Graphics.m_oCoordTransform.ty = _scale * drawPage.top;

        this.Graphics.SetIntegerGrid(false);

        this.Graphics.globalAlpha = 0.5;
        this.m_oContext.globalAlpha = 0.5;
    },

    init2 : function(overlay)
    {
        this.m_oOverlay = overlay;
        this.m_oContext = this.m_oOverlay.m_oContext;
        this.PageIndex = -1;
    },

    SetClip : function(r)
    {
    },
    RemoveClip : function()
    {
    },

    SavePen : function()
    {
        this.Graphics.SavePen();
    },
    RestorePen : function()
    {
        this.Graphics.RestorePen();
    },

    SaveBrush : function()
    {
        this.Graphics.SaveBrush();
    },
    RestoreBrush : function()
    {
        this.Graphics.RestoreBrush();
    },

    SavePenBrush : function()
    {
        this.Graphics.SavePenBrush();
    },
    RestorePenBrush : function()
    {
        this.Graphics.RestorePenBrush();
    },

    SaveGrState : function()
    {
        this.Graphics.SaveGrState();
    },
    RestoreGrState : function()
    {
        this.Graphics.RestoreGrState();
    },

    StartClipPath : function()
    {
        this.Graphics.StartClipPath();
    },

    EndClipPath : function()
    {
        this.Graphics.EndClipPath();
    },

    /*************************************************************************/
    /******************************** TRACKS *********************************/
    /*************************************************************************/
    DrawTrack : function(type, matrix, left, top, width, height, isLine, isCanRotate, isNoMove)
    {
		if (true === isNoMove)
			return;

		var _retina = this.m_oOverlay.IsRetina;

		if (!_retina && this.m_oOverlay.IsCellEditor && AscCommon.AscBrowser.isRetina)
        {
			this.m_oOverlay.IsRetina = true;
            this.m_oOverlay.m_oContext.setTransform(1, 0, 0, 1, 0, 0);

            left    /= AscCommon.AscBrowser.retinaPixelRatio;
            top     /= AscCommon.AscBrowser.retinaPixelRatio;
            width   /= AscCommon.AscBrowser.retinaPixelRatio;
            height  /= AscCommon.AscBrowser.retinaPixelRatio;

            if (matrix)
			{
				matrix.tx /= AscCommon.AscBrowser.retinaPixelRatio;
				matrix.ty /= AscCommon.AscBrowser.retinaPixelRatio;
			}

			this.m_oOverlay.m_oContext.translate(this.Graphics.m_oCoordTransform.tx, this.Graphics.m_oCoordTransform.ty);
            this.m_oOverlay.m_oContext.scale(AscCommon.AscBrowser.retinaPixelRatio, AscCommon.AscBrowser.retinaPixelRatio);
			this.m_oOverlay.m_oContext.translate(-this.Graphics.m_oCoordTransform.tx, -this.Graphics.m_oCoordTransform.ty);
        }

        // с самого начала нужно понять, есть ли поворот. Потому что если его нет, то можно
        // (и нужно!) рисовать все по-умному
        var overlay = this.m_oOverlay;
        overlay.Show();

        var bIsClever = false;
        this.CurrentPageInfo = overlay.m_oHtmlPage.GetDrawingPageInfo(this.PageIndex);

        var drPage = this.CurrentPageInfo.drawingPage;

        var xDst = drPage.left;
        var yDst = drPage.top;
        var wDst = drPage.right - drPage.left;
        var hDst = drPage.bottom - drPage.top;

        var dKoefX = wDst / this.CurrentPageInfo.width_mm;
        var dKoefY = hDst / this.CurrentPageInfo.height_mm;

        var r = left + width;
        var b = top + height;

        // (x1,y1) --------- (x2,y2)
        //    |                 |
        //    |                 |
        // (x3,y3) --------- (x4,y4)

        var dx1 = xDst + dKoefX * (matrix.TransformPointX(left, top));
        var dy1 = yDst + dKoefY * (matrix.TransformPointY(left, top));

        var dx2 = xDst + dKoefX * (matrix.TransformPointX(r, top));
        var dy2 = yDst + dKoefY * (matrix.TransformPointY(r, top));

        var dx3 = xDst + dKoefX * (matrix.TransformPointX(left, b));
        var dy3 = yDst + dKoefY * (matrix.TransformPointY(left, b));

        var dx4 = xDst + dKoefX * (matrix.TransformPointX(r, b));
        var dy4 = yDst + dKoefY * (matrix.TransformPointY(r, b));

        var x1 = dx1 >> 0;
        var y1 = dy1 >> 0;

        var x2 = dx2 >> 0;
        var y2 = dy2 >> 0;

        var x3 = dx3 >> 0;
        var y3 = dy3 >> 0;

        var x4 = dx4 >> 0;
        var y4 = dy4 >> 0;

        var _eps = 0.001;
        if (Math.abs(dx1 - dx3) < _eps &&
            Math.abs(dx2 - dx4) < _eps &&
            Math.abs(dy1 - dy2) < _eps &&
            Math.abs(dy3 - dy4) < _eps &&
            x1 < x2 && y1 < y3)
        {
            x3 = x1;
            x4 = x2;
            y2 = y1;
            y4 = y3;
            bIsClever = true;
        }

        var nIsCleverWithTransform = bIsClever;
        var nType = 0;
        if (!nIsCleverWithTransform &&
            Math.abs(dx1 - dx3) < _eps &&
            Math.abs(dx2 - dx4) < _eps &&
            Math.abs(dy1 - dy2) < _eps &&
            Math.abs(dy3 - dy4) < _eps)
        {
            x3 = x1;
            x4 = x2;
            y2 = y1;
            y4 = y3;
            nIsCleverWithTransform = true;
            nType = 1;
        }
        if (!nIsCleverWithTransform &&
            Math.abs(dx1 - dx2) < _eps &&
            Math.abs(dx3 - dx4) < _eps &&
            Math.abs(dy1 - dy3) < _eps &&
            Math.abs(dy2 - dy4) < _eps)
        {
            x2 = x1;
            x4 = x3;
            y3 = y1;
            y4 = y2;
            nIsCleverWithTransform = true;
            nType = 2;
        }

        /*
        if (x1 == x3 && x2 == x4 && y1 == y2 && y3 == y4 && x1 < x2 && y1 < y3)
            bIsClever = true;

        var nIsCleverWithTransform = bIsClever;
        var nType = 0;
        if (!nIsCleverWithTransform && x1 == x3 && x2 == x4 && y1 == y2 && y3 == y4)
        {
            nIsCleverWithTransform = true;
            nType = 1;
        }
        if (!nIsCleverWithTransform && x1 == x2 && x3 == x4 && y1 == y3 && y2 == y4)
        {
            nIsCleverWithTransform = true;
            nType = 2;
        }
        */

        var ctx = overlay.m_oContext;

        var bIsEllipceCorner = false;
        //var _style_blue = "#4D7399";
        //var _style_blue = "#B2B2B2";
        var _style_blue = "#939393";
        var _style_green = "#84E036";
        var _style_white = "#FFFFFF";

        var _len_x = Math.sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
        var _len_y = Math.sqrt((x1 - x3)*(x1 - x3) + (y1 - y3)*(y1 - y3));

        if (_len_x < 1)
            _len_x = 1;
        if (_len_y < 1)
            _len_y = 1;

        var bIsRectsTrackX = (_len_x >= 30) ? true : false;
        var bIsRectsTrackY = (_len_y >= 30) ? true : false;
        var bIsRectsTrack = (bIsRectsTrackX || bIsRectsTrackY) ? true : false;

        if (bIsRectsTrack && (type == AscFormat.TYPE_TRACK.CHART_TEXT))
            bIsRectsTrack = false;

		if (nType == 2)
		{
			var _tmp = bIsRectsTrackX;
			bIsRectsTrackX = bIsRectsTrackY;
			bIsRectsTrackY = _tmp;
		}

        ctx.lineWidth = 1;
        ctx.beginPath();

        var _oldGlobalAlpha = ctx.globalAlpha;
        ctx.globalAlpha = 1;

        switch (type)
        {
            case AscFormat.TYPE_TRACK.SHAPE:
            case AscFormat.TYPE_TRACK.GROUP:
            case AscFormat.TYPE_TRACK.CHART_TEXT:
            {
                if (bIsClever)
                {
                    overlay.CheckRect(x1, y1, x4 - x1, y4 - y1);
                    ctx.strokeStyle = _style_blue;

                    if (!isLine)
                    {
                        ctx.rect(x1 + 0.5, y2 + 0.5, x4 - x1, y4 - y1);
                        ctx.stroke();
                        ctx.beginPath();
                    }

                    var xC = ((x1 + x2) / 2) >> 0;

                    if (!isLine && isCanRotate)
                    {
                        if (!bIsUseImageRotateTrack)
                        {
                            ctx.beginPath();
                            overlay.AddEllipse(xC, y1 - TRACK_DISTANCE_ROTATE, TRACK_CIRCLE_RADIUS);

                            ctx.fillStyle = _style_green;
                            ctx.fill();
                            ctx.stroke();
                        }
                        else
                        {
                            var _image_track_rotate = overlay.GetImageTrackRotationImage();
                            if (_image_track_rotate.asc_complete)
                            {
                                var _w = IMAGE_ROTATE_TRACK_W;
                                var _xI = (xC + 0.5 - _w / 2) >> 0;
                                var _yI = y1 - TRACK_DISTANCE_ROTATE - (_w >> 1);

                                overlay.CheckRect(_xI, _yI, _w, _w);
                                ctx.drawImage(_image_track_rotate, _xI, _yI, _w, _w);
                            }
                        }

                        ctx.beginPath();
                        ctx.moveTo(xC + 0.5, y1);
                        ctx.lineTo(xC + 0.5, y1 - TRACK_DISTANCE_ROTATE2);
                        ctx.stroke();

                        ctx.beginPath();
                    }

                    ctx.fillStyle = (type != AscFormat.TYPE_TRACK.CHART_TEXT) ? _style_white : _style_blue;
                    var TRACK_RECT_SIZE_CUR = (type != AscFormat.TYPE_TRACK.CHART_TEXT) ? TRACK_RECT_SIZE : TRACK_RECT_SIZE_CT;
                    if (type == AscFormat.TYPE_TRACK.CHART_TEXT)
                        ctx.strokeStyle = _style_white;

                    if (bIsEllipceCorner)
                    {
                        overlay.AddEllipse(x1, y1, TRACK_CIRCLE_RADIUS);
                        if (!isLine)
                        {
                            overlay.AddEllipse(x2, y2, TRACK_CIRCLE_RADIUS);
                            overlay.AddEllipse(x3, y3, TRACK_CIRCLE_RADIUS);
                        }
                        overlay.AddEllipse(x4, y4, TRACK_CIRCLE_RADIUS);
                    }
                    else
                    {
                        overlay.AddRect2(x1 + 0.5, y1 + 0.5, TRACK_RECT_SIZE_CUR);
                        if (!isLine)
                        {
                            overlay.AddRect2(x2 + 0.5, y2 + 0.5, TRACK_RECT_SIZE_CUR);
                            overlay.AddRect2(x3 + 0.5, y3 + 0.5, TRACK_RECT_SIZE_CUR);
                        }
                        overlay.AddRect2(x4 + 0.5, y4 + 0.5, TRACK_RECT_SIZE_CUR);
                    }

                    if (bIsRectsTrack && !isLine)
                    {
                        var _xC = (((x1 + x2) / 2) >> 0) + 0.5;
                        var _yC = (((y1 + y3) / 2) >> 0) + 0.5;

                        if (bIsRectsTrackX)
                        {
                            overlay.AddRect2(_xC, y1+0.5, TRACK_RECT_SIZE);
                            overlay.AddRect2(_xC, y3+0.5, TRACK_RECT_SIZE);
                        }

                        if (bIsRectsTrackY)
                        {
                            overlay.AddRect2(x2+0.5, _yC, TRACK_RECT_SIZE);
                            overlay.AddRect2(x1+0.5, _yC, TRACK_RECT_SIZE);
                        }
                    }

                    ctx.fill();
                    ctx.stroke();

                    ctx.beginPath();
                }
                else
                {
					var _x1 = x1;
					var _y1 = y1;
					var _x2 = x2;
					var _y2 = y2;
					var _x3 = x3;
					var _y3 = y3;
					var _x4 = x4;
					var _y4 = y4;

					if (nIsCleverWithTransform)
					{
						var _x1 = x1;
						if (x2 < _x1)
							_x1 = x2;
						if (x3 < _x1)
							_x1 = x3;
						if (x4 < _x1)
							_x1 = x4;

						var _x4 = x1;
						if (x2 > _x4)
							_x4 = x2;
						if (x3 > _x4)
							_x4 = x3;
						if (x4 > _x4)
							_x4 = x4;

						var _y1 = y1;
						if (y2 < _y1)
							_y1 = y2;
						if (y3 < _y1)
							_y1 = y3;
						if (y4 < _y1)
							_y1 = y4;

						var _y4 = y1;
						if (y2 > _y4)
							_y4 = y2;
						if (y3 > _y4)
							_y4 = y3;
						if (y4 > _y4)
							_y4 = y4;

						_x2 = _x4;
						_y2 = _y1;
						_x3 = _x1;
						_y3 = _y4;
					}

                    ctx.strokeStyle = _style_blue;

                    if (!isLine)
                    {
                        if (nIsCleverWithTransform)
                        {
                            ctx.rect(_x1 + 0.5, _y2 + 0.5, _x4 - _x1, _y4 - _y1);
                            ctx.stroke();
                            ctx.beginPath();
                        }
                        else
                        {
                            ctx.moveTo(x1, y1);
                            ctx.lineTo(x2, y2);
                            ctx.lineTo(x4, y4);
                            ctx.lineTo(x3, y3);
                            ctx.closePath();
                            ctx.stroke();
                        }
                    }

                    overlay.CheckPoint(x1, y1);
                    overlay.CheckPoint(x2, y2);
                    overlay.CheckPoint(x3, y3);
                    overlay.CheckPoint(x4, y4);

                    var ex1 = (x2 - x1) / _len_x;
                    var ey1 = (y2 - y1) / _len_x;
                    var ex2 = (x1 - x3) / _len_y;
                    var ey2 = (y1 - y3) / _len_y;

                    var _bAbsX1 = Math.abs(ex1) < 0.01;
                    var _bAbsY1 = Math.abs(ey1) < 0.01;
                    var _bAbsX2 = Math.abs(ex2) < 0.01;
                    var _bAbsY2 = Math.abs(ey2) < 0.01;

                    if (_bAbsX2 && _bAbsY2)
                    {
                        if (_bAbsX1 && _bAbsY1)
                        {
                            ex1 = 1;
                            ey1 = 0;
                            ex2 = 0;
                            ey2 = 1;
                        }
                        else
                        {
                            ex2 = -ey1;
                            ey2 = ex1;
                        }
                    }
                    else if (_bAbsX1 && _bAbsY1)
                    {
                        ex1 = ey2;
                        ey1 = -ex2;
                    }

                    var xc1 = (x1 + x2) / 2;
                    var yc1 = (y1 + y2) / 2;

                    ctx.beginPath();

                    if (!isLine && isCanRotate)
                    {
                        if (!bIsUseImageRotateTrack)
                        {
                            ctx.beginPath();
                            overlay.AddEllipse(xc1 + ex2 * TRACK_DISTANCE_ROTATE, yc1 + ey2 * TRACK_DISTANCE_ROTATE, TRACK_CIRCLE_RADIUS);

                            ctx.fillStyle = _style_green;
                            ctx.fill();
                            ctx.stroke();
                        }
                        else
                        {
                            var _image_track_rotate = overlay.GetImageTrackRotationImage();
                            if (_image_track_rotate.asc_complete)
                            {
                                var _xI = xc1 + ex2 * TRACK_DISTANCE_ROTATE;
                                var _yI = yc1 + ey2 * TRACK_DISTANCE_ROTATE;
                                var _w = IMAGE_ROTATE_TRACK_W;
                                var _w2 = IMAGE_ROTATE_TRACK_W / 2;

								if (nIsCleverWithTransform)
								{
									_xI >>= 0;
									_yI >>= 0;
									_w2 >>= 0;
									_w2 += 1;
								}

								//ctx.setTransform(ex1, ey1, -ey1, ex1, _xI, _yI);

								var _matrix = matrix.CreateDublicate();
								_matrix.tx = 0;
								_matrix.ty = 0;
								var _xx = _matrix.TransformPointX(0, 1);
								var _yy = _matrix.TransformPointY(0, 1);
								var _angle = Math.atan2(_xx, -_yy) - Math.PI;
								var _px = Math.cos(_angle);
								var _py = Math.sin(_angle);

								ctx.save();

								ctx.translate(_xI, _yI);
								ctx.transform(_px, _py, -_py, _px, 0, 0);
                                ctx.drawImage(_image_track_rotate, -_w2, -_w2, _w, _w);

                                ctx.restore();

                                overlay.CheckRect(_xI - _w2, _yI - _w2, _w, _w);
                            }
                        }

                        ctx.beginPath();

						if (!nIsCleverWithTransform)
						{
							ctx.moveTo(xc1, yc1);
							ctx.lineTo(xc1 + ex2 * TRACK_DISTANCE_ROTATE2, yc1 + ey2 * TRACK_DISTANCE_ROTATE2);
						}
						else
						{
							ctx.moveTo((xc1 >> 0) + 0.5, (yc1 >> 0) + 0.5);
							ctx.lineTo(((xc1 + ex2 * TRACK_DISTANCE_ROTATE2) >> 0) + 0.5, ((yc1 + ey2 * TRACK_DISTANCE_ROTATE2) >> 0) + 0.5);
						}

                        ctx.stroke();

                        ctx.beginPath();
                    }

                    ctx.fillStyle = (type != AscFormat.TYPE_TRACK.CHART_TEXT) ? _style_white : _style_blue;
                    var TRACK_RECT_SIZE_CUR = (type != AscFormat.TYPE_TRACK.CHART_TEXT) ? TRACK_RECT_SIZE : TRACK_RECT_SIZE_CT;
                    if (type == AscFormat.TYPE_TRACK.CHART_TEXT)
                        ctx.strokeStyle = _style_white;

					if (!nIsCleverWithTransform)
					{
						if (bIsEllipceCorner)
						{
							overlay.AddEllipse(x1, y1, TRACK_CIRCLE_RADIUS);
							if (!isLine)
							{
								overlay.AddEllipse(x2, y2, TRACK_CIRCLE_RADIUS);
								overlay.AddEllipse(x3, y3, TRACK_CIRCLE_RADIUS);
							}
							overlay.AddEllipse(x4, y4, TRACK_CIRCLE_RADIUS);
						}
						else
						{
							overlay.AddRect3(x1, y1, TRACK_RECT_SIZE_CUR, ex1, ey1, ex2, ey2);
							if (!isLine)
							{
								overlay.AddRect3(x2, y2, TRACK_RECT_SIZE_CUR, ex1, ey1, ex2, ey2);
								overlay.AddRect3(x3, y3, TRACK_RECT_SIZE_CUR, ex1, ey1, ex2, ey2);
							}
							overlay.AddRect3(x4, y4, TRACK_RECT_SIZE_CUR, ex1, ey1, ex2, ey2);
						}
					}
					else
					{
						if (bIsEllipceCorner)
						{
							overlay.AddEllipse(_x1, _y1, TRACK_CIRCLE_RADIUS);
							if (!isLine)
							{
								overlay.AddEllipse(_x2, _y2, TRACK_CIRCLE_RADIUS);
								overlay.AddEllipse(_x3, _y3, TRACK_CIRCLE_RADIUS);
							}
							overlay.AddEllipse(_x4, _y4, TRACK_CIRCLE_RADIUS);
						}
						else
						{
                            if (!isLine)
                            {
                                overlay.AddRect2(_x1 + 0.5, _y1 + 0.5, TRACK_RECT_SIZE_CUR);
                                overlay.AddRect2(_x2 + 0.5, _y2 + 0.5, TRACK_RECT_SIZE_CUR);
                                overlay.AddRect2(_x3 + 0.5, _y3 + 0.5, TRACK_RECT_SIZE_CUR);
                                overlay.AddRect2(_x4 + 0.5, _y4 + 0.5, TRACK_RECT_SIZE_CUR);
                            }
                            else
                            {
                                overlay.AddRect2(x1 + 0.5, y1 + 0.5, TRACK_RECT_SIZE_CUR);
                                overlay.AddRect2(x4 + 0.5, y4 + 0.5, TRACK_RECT_SIZE_CUR);
                            }
						}
					}

                    if (!isLine)
                    {
                        if (!nIsCleverWithTransform)
                        {
                            if (bIsRectsTrack)
                            {
                                if (bIsRectsTrackX)
                                {
                                    overlay.AddRect3((x1 + x2) / 2, (y1 + y2) / 2, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
                                    overlay.AddRect3((x3 + x4) / 2, (y3 + y4) / 2, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
                                }
                                if (bIsRectsTrackY)
                                {
                                    overlay.AddRect3((x2 + x4) / 2, (y2 + y4) / 2, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
                                    overlay.AddRect3((x3 + x1) / 2, (y3 + y1) / 2, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
                                }
                            }
                        }
                        else
                        {
                            var _xC = (((_x1 + _x2) / 2) >> 0) + 0.5;
                            var _yC = (((_y1 + _y3) / 2) >> 0) + 0.5;

                            if (bIsRectsTrackX)
                            {
                                overlay.AddRect2(_xC, _y1+0.5, TRACK_RECT_SIZE);
                                overlay.AddRect2(_xC, _y3+0.5, TRACK_RECT_SIZE);
                            }

                            if (bIsRectsTrackY)
                            {
                                overlay.AddRect2(_x2+0.5, _yC, TRACK_RECT_SIZE);
                                overlay.AddRect2(_x1+0.5, _yC, TRACK_RECT_SIZE);
                            }
                        }
                    }

                    ctx.fill();
                    ctx.stroke();

                    ctx.beginPath();
                }

                break;
            }
            case AscFormat.TYPE_TRACK.TEXT:
            case AscFormat.TYPE_TRACK.GROUP_PASSIVE:
            {
                if (bIsClever)
                {
                    overlay.CheckRect(x1, y1, x4 - x1, y4 - y1);
                    ctx.strokeStyle = _style_blue;

                    this.AddRectDashClever(ctx, x1, y1, x4, y4, 8, 3, true);

                    ctx.beginPath();

                    if (isCanRotate)
                    {
                        var xC = ((x1 + x2) / 2) >> 0;

                        if (!bIsUseImageRotateTrack)
                        {
                            ctx.beginPath();
                            overlay.AddEllipse(xC, y1 - TRACK_DISTANCE_ROTATE, TRACK_CIRCLE_RADIUS);

                            ctx.fillStyle = _style_green;
                            ctx.fill();
                            ctx.stroke();
                        }
                        else
                        {
                            var _image_track_rotate = overlay.GetImageTrackRotationImage();
                            if (_image_track_rotate.asc_complete)
                            {
                                var _w = IMAGE_ROTATE_TRACK_W;
                                var _xI = (xC + 0.5 - _w / 2) >> 0;
                                var _yI = y1 - TRACK_DISTANCE_ROTATE - (_w >> 1);

                                overlay.CheckRect(_xI, _yI, _w, _w);
                                ctx.drawImage(_image_track_rotate, _xI, _yI, _w, _w);
                            }
                        }

                        ctx.beginPath();

                        ctx.moveTo(xC + 0.5, y1);
                        ctx.lineTo(xC + 0.5, y1 - TRACK_DISTANCE_ROTATE2);
                        ctx.stroke();

                        ctx.beginPath();
                    }

                    ctx.fillStyle = _style_white;

                    if (bIsEllipceCorner)
                    {
                        overlay.AddEllipse(x1, y1, TRACK_CIRCLE_RADIUS);
                        overlay.AddEllipse(x2, y2, TRACK_CIRCLE_RADIUS);
                        overlay.AddEllipse(x3, y3, TRACK_CIRCLE_RADIUS);
                        overlay.AddEllipse(x4, y4, TRACK_CIRCLE_RADIUS);
                    }
                    else
                    {
                        overlay.AddRect2(x1 + 0.5, y1 + 0.5, TRACK_RECT_SIZE);
                        overlay.AddRect2(x2 + 0.5, y2 + 0.5, TRACK_RECT_SIZE);
                        overlay.AddRect2(x3 + 0.5, y3 + 0.5, TRACK_RECT_SIZE);
                        overlay.AddRect2(x4 + 0.5, y4 + 0.5, TRACK_RECT_SIZE);
                    }

                    if (bIsRectsTrack)
                    {
                        var _xC = (((x1 + x2) / 2) >> 0) + 0.5;
                        var _yC = (((y1 + y3) / 2) >> 0) + 0.5;

                        if (bIsRectsTrackX)
                        {
                            overlay.AddRect2(_xC, y1+0.5, TRACK_RECT_SIZE);
                            overlay.AddRect2(_xC, y3+0.5, TRACK_RECT_SIZE);
                        }
                        if (bIsRectsTrackY)
                        {
                            overlay.AddRect2(x2+0.5, _yC, TRACK_RECT_SIZE);
                            overlay.AddRect2(x1+0.5, _yC, TRACK_RECT_SIZE);
                        }
                    }

                    ctx.fill();
                    ctx.stroke();

                    ctx.beginPath();
                }
                else
                {
					var _x1 = x1;
					var _y1 = y1;
					var _x2 = x2;
					var _y2 = y2;
					var _x3 = x3;
					var _y3 = y3;
					var _x4 = x4;
					var _y4 = y4;

					if (nIsCleverWithTransform)
					{
						var _x1 = x1;
						if (x2 < _x1)
							_x1 = x2;
						if (x3 < _x1)
							_x1 = x3;
						if (x4 < _x1)
							_x1 = x4;

						var _x4 = x1;
						if (x2 > _x4)
							_x4 = x2;
						if (x3 > _x4)
							_x4 = x3;
						if (x4 > _x4)
							_x4 = x4;

						var _y1 = y1;
						if (y2 < _y1)
							_y1 = y2;
						if (y3 < _y1)
							_y1 = y3;
						if (y4 < _y1)
							_y1 = y4;

						var _y4 = y1;
						if (y2 > _y4)
							_y4 = y2;
						if (y3 > _y4)
							_y4 = y3;
						if (y4 > _y4)
							_y4 = y4;

						_x2 = _x4;
						_y2 = _y1;
						_x3 = _x1;
						_y3 = _y4;
					}

                    overlay.CheckPoint(x1, y1);
                    overlay.CheckPoint(x2, y2);
                    overlay.CheckPoint(x3, y3);
                    overlay.CheckPoint(x4, y4);

                    ctx.strokeStyle = _style_blue;
					if (!nIsCleverWithTransform)
					{
						this.AddRectDash(ctx, x1, y1, x2, y2, x3, y3, x4, y4, 8, 3, true);
					}
					else
					{
						this.AddRectDashClever(ctx, _x1, _y1, _x4, _y4, 8, 3, true);
					}

                    var ex1 = (x2 - x1) / _len_x;
                    var ey1 = (y2 - y1) / _len_x;
                    var ex2 = (x1 - x3) / _len_y;
                    var ey2 = (y1 - y3) / _len_y;

                    var _bAbsX1 = Math.abs(ex1) < 0.01;
                    var _bAbsY1 = Math.abs(ey1) < 0.01;
                    var _bAbsX2 = Math.abs(ex2) < 0.01;
                    var _bAbsY2 = Math.abs(ey2) < 0.01;

                    if (_bAbsX2 && _bAbsY2)
                    {
                        if (_bAbsX1 && _bAbsY1)
                        {
                            ex1 = 1;
                            ey1 = 0;
                            ex2 = 0;
                            ey2 = 1;
                        }
                        else
                        {
                            ex2 = -ey1;
                            ey2 = ex1;
                        }
                    }
                    else if (_bAbsX1 && _bAbsY1)
                    {
                        ex1 = ey2;
                        ey1 = -ex2;
                    }

                    var xc1 = (x1 + x2) / 2;
                    var yc1 = (y1 + y2) / 2;

                    ctx.beginPath();

                    if (isCanRotate)
                    {
                        if (!bIsUseImageRotateTrack)
                        {
                            ctx.beginPath();
                            overlay.AddEllipse(xc1 + ex2 * TRACK_DISTANCE_ROTATE, yc1 + ey2 * TRACK_DISTANCE_ROTATE, TRACK_CIRCLE_RADIUS);

                            ctx.fillStyle = _style_green;
                            ctx.fill();
                            ctx.stroke();
                        }
                        else
                        {
                            var _image_track_rotate = overlay.GetImageTrackRotationImage();
                            if (_image_track_rotate.asc_complete)
                            {
                                var _xI = xc1 + ex2 * TRACK_DISTANCE_ROTATE;
                                var _yI = yc1 + ey2 * TRACK_DISTANCE_ROTATE;
                                var _w = IMAGE_ROTATE_TRACK_W;
                                var _w2 = IMAGE_ROTATE_TRACK_W / 2;

								if (nIsCleverWithTransform)
								{
									_xI >>= 0;
									_yI >>= 0;
									_w2 >>= 0;
									_w2 += 1;
								}

								//ctx.setTransform(ex1, ey1, -ey1, ex1, _xI, _yI);

								var _matrix = matrix.CreateDublicate();
								_matrix.tx = 0;
								_matrix.ty = 0;
								var _xx = _matrix.TransformPointX(0, 1);
								var _yy = _matrix.TransformPointY(0, 1);
								var _angle = Math.atan2(_xx, -_yy) - Math.PI;
								var _px = Math.cos(_angle);
								var _py = Math.sin(_angle);

								ctx.save();

								ctx.translate(_xI, _yI);
								ctx.transform(_px, _py, -_py, _px, 0, 0);
								ctx.drawImage(_image_track_rotate, -_w2, -_w2, _w, _w);

                                ctx.restore();

                                overlay.CheckRect(_xI - _w2, _yI - _w2, _w, _w);
                            }
                        }

                        ctx.beginPath();

						if (!nIsCleverWithTransform)
						{
							ctx.moveTo(xc1, yc1);
							ctx.lineTo(xc1 + ex2 * TRACK_DISTANCE_ROTATE2, yc1 + ey2 * TRACK_DISTANCE_ROTATE2);
						}
						else
						{
							ctx.moveTo((xc1 >> 0) + 0.5, (yc1 >> 0) + 0.5);
							ctx.lineTo(((xc1 + ex2 * TRACK_DISTANCE_ROTATE2) >> 0) + 0.5, ((yc1 + ey2 * TRACK_DISTANCE_ROTATE2) >> 0) + 0.5);
						}

                        ctx.stroke();

                        ctx.beginPath();

                    }

                    ctx.fillStyle = _style_white;

					if (!nIsCleverWithTransform)
					{
						if (bIsEllipceCorner)
						{
							overlay.AddEllipse(x1, y1, TRACK_CIRCLE_RADIUS);
							overlay.AddEllipse(x2, y2, TRACK_CIRCLE_RADIUS);
							overlay.AddEllipse(x3, y3, TRACK_CIRCLE_RADIUS);
							overlay.AddEllipse(x4, y4, TRACK_CIRCLE_RADIUS);
						}
						else
						{
							overlay.AddRect3(x1, y1, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
							overlay.AddRect3(x2, y2, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
							overlay.AddRect3(x3, y3, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
							overlay.AddRect3(x4, y4, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
						}
					}
					else
					{
						if (bIsEllipceCorner)
						{
							overlay.AddEllipse(x1, y1, TRACK_CIRCLE_RADIUS);
							overlay.AddEllipse(x2, y2, TRACK_CIRCLE_RADIUS);
							overlay.AddEllipse(x3, y3, TRACK_CIRCLE_RADIUS);
							overlay.AddEllipse(x4, y4, TRACK_CIRCLE_RADIUS);
						}
						else
						{
							overlay.AddRect2(_x1 + 0.5, _y1 + 0.5, TRACK_RECT_SIZE);
							overlay.AddRect2(_x2 + 0.5, _y2 + 0.5, TRACK_RECT_SIZE);
							overlay.AddRect2(_x3 + 0.5, _y3 + 0.5, TRACK_RECT_SIZE);
							overlay.AddRect2(_x4 + 0.5, _y4 + 0.5, TRACK_RECT_SIZE);
						}
					}

					if (!nIsCleverWithTransform)
					{
						if (bIsRectsTrack)
						{
							if (bIsRectsTrackX)
							{
								overlay.AddRect3((x1 + x2) / 2, (y1 + y2) / 2, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
								overlay.AddRect3((x3 + x4) / 2, (y3 + y4) / 2, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
							}
							if (bIsRectsTrackY)
							{
								overlay.AddRect3((x2 + x4) / 2, (y2 + y4) / 2, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
								overlay.AddRect3((x3 + x1) / 2, (y3 + y1) / 2, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
							}
						}
					}
					else
					{
						if (bIsRectsTrack)
						{
							var _xC = (((_x1 + _x2) / 2) >> 0) + 0.5;
							var _yC = (((_y1 + _y3) / 2) >> 0) + 0.5;

							if (bIsRectsTrackX)
							{
								overlay.AddRect2(_xC, _y1+0.5, TRACK_RECT_SIZE);
								overlay.AddRect2(_xC, _y3+0.5, TRACK_RECT_SIZE);
							}
							if (bIsRectsTrackY)
							{
								overlay.AddRect2(_x2+0.5, _yC, TRACK_RECT_SIZE);
								overlay.AddRect2(_x1+0.5, _yC, TRACK_RECT_SIZE);
							}
						}
					}

                    ctx.fill();
                    ctx.stroke();

                    ctx.beginPath();
                }

                break;
            }
            case AscFormat.TYPE_TRACK.EMPTY_PH:
            {
                if (bIsClever)
                {
                    overlay.CheckRect(x1, y1, x4 - x1, y4 - y1);
                    ctx.rect(x1 + 0.5, y2 + 0.5, x4 - x1 + 1, y4 - y1);
                    ctx.fillStyle = _style_white;
                    ctx.stroke();

                    ctx.beginPath();

                    ctx.strokeStyle = _style_blue;
                    this.AddRectDashClever(ctx, x1, y1, x4, y4, 8, 3, true);

                    ctx.beginPath();

                    var xC = ((x1 + x2) / 2) >> 0;

                    if (!bIsUseImageRotateTrack)
                    {
                        ctx.beginPath();
                        overlay.AddEllipse(xC, y1 - TRACK_DISTANCE_ROTATE);

                        ctx.fillStyle = _style_green;
                        ctx.fill();
                        ctx.stroke();
                    }
                    else
                    {
                        var _image_track_rotate = overlay.GetImageTrackRotationImage();
                        if (_image_track_rotate.asc_complete)
                        {
                            var _w = IMAGE_ROTATE_TRACK_W;
                            var _xI = (xC + 0.5 - _w / 2) >> 0;
                            var _yI = y1 - TRACK_DISTANCE_ROTATE - (_w >> 1);

                            overlay.CheckRect(_xI, _yI, _w, _w);
                            ctx.drawImage(_image_track_rotate, _xI, _yI, _w, _w);
                        }
                    }

                    ctx.beginPath();
                    ctx.moveTo(xC + 0.5, y1);
                    ctx.lineTo(xC + 0.5, y1 - TRACK_DISTANCE_ROTATE2);
                    ctx.stroke();

                    ctx.beginPath();

                    ctx.fillStyle = _style_white;

                    if (bIsEllipceCorner)
                    {
                        overlay.AddEllipse(x1, y1, TRACK_CIRCLE_RADIUS);
                        overlay.AddEllipse(x2, y2, TRACK_CIRCLE_RADIUS);
                        overlay.AddEllipse(x3, y3, TRACK_CIRCLE_RADIUS);
                        overlay.AddEllipse(x4, y4, TRACK_CIRCLE_RADIUS);
                    }
                    else
                    {
                        overlay.AddRect2(x1 + 0.5, y1 + 0.5, TRACK_RECT_SIZE);
                        overlay.AddRect2(x2 + 0.5, y2 + 0.5, TRACK_RECT_SIZE);
                        overlay.AddRect2(x3 + 0.5, y3 + 0.5, TRACK_RECT_SIZE);
                        overlay.AddRect2(x4 + 0.5, y4 + 0.5, TRACK_RECT_SIZE);
                    }

                    if (bIsRectsTrack && false)
                    {
                        var _xC = (((x1 + x2) / 2) >> 0) + 0.5;
                        var _yC = (((y1 + y3) / 2) >> 0) + 0.5;

                        overlay.AddRect2(_xC, y1+0.5, TRACK_RECT_SIZE);
                        overlay.AddRect2(x2+0.5, _yC, TRACK_RECT_SIZE);
                        overlay.AddRect2(_xC, y3+0.5, TRACK_RECT_SIZE);
                        overlay.AddRect2(x1+0.5, _yC, TRACK_RECT_SIZE);
                    }

                    ctx.fill();
                    ctx.stroke();

                    ctx.beginPath();
                }
                else
                {
                    overlay.CheckPoint(x1, y1);
                    overlay.CheckPoint(x2, y2);
                    overlay.CheckPoint(x3, y3);
                    overlay.CheckPoint(x4, y4);

                    ctx.moveTo(x1, y1);
                    ctx.lineTo(x2, y2);
                    ctx.lineTo(x3, y3);
                    ctx.lineTo(x4, y4);
                    ctx.closePath();

                    overlay.CheckPoint(x1, y1);
                    overlay.CheckPoint(x2, y2);
                    overlay.CheckPoint(x3, y3);
                    overlay.CheckPoint(x4, y4);

                    ctx.strokeStyle = _style_white;
                    ctx.stroke();

                    ctx.beginPath();

					ctx.strokeStyle = _style_blue;
                    this.AddRectDash(ctx, x1, y1, x2, y2, x3, y3, x4, y4, 8, 3, true);

                    ctx.beginPath();

                    var ex1 = (x2 - x1) / _len_x;
                    var ey1 = (y2 - y1) / _len_x;
                    var ex2 = (x1 - x3) / _len_y;
                    var ey2 = (y1 - y3) / _len_y;

                    var _bAbsX1 = Math.abs(ex1) < 0.01;
                    var _bAbsY1 = Math.abs(ey1) < 0.01;
                    var _bAbsX2 = Math.abs(ex2) < 0.01;
                    var _bAbsY2 = Math.abs(ey2) < 0.01;

                    if (_bAbsX2 && _bAbsY2)
                    {
                        if (_bAbsX1 && _bAbsY1)
                        {
                            ex1 = 1;
                            ey1 = 0;
                            ex2 = 0;
                            ey2 = 1;
                        }
                        else
                        {
                            ex2 = -ey1;
                            ey2 = ex1;
                        }
                    }
                    else if (_bAbsX1 && _bAbsY1)
                    {
                        ex1 = ey2;
                        ey1 = -ex2;
                    }

                    var xc1 = (x1 + x2) / 2;
                    var yc1 = (y1 + y2) / 2;

                    ctx.beginPath();

                    if (!bIsUseImageRotateTrack)
                    {
                        ctx.beginPath();
                        overlay.AddEllipse(xc1 + ex2 * TRACK_DISTANCE_ROTATE, yc1 + ey2 * TRACK_DISTANCE_ROTATE, TRACK_DISTANCE_ROTATE);

                        ctx.fillStyle = _style_green;
                        ctx.fill();
                        ctx.stroke();
                    }
                    else
                    {
                        var _image_track_rotate = overlay.GetImageTrackRotationImage();
                        if (_image_track_rotate.asc_complete)
                        {
                            var _xI = xc1 + ex2 * TRACK_DISTANCE_ROTATE;
                            var _yI = yc1 + ey2 * TRACK_DISTANCE_ROTATE;
                            var _w = IMAGE_ROTATE_TRACK_W;
                            var _w2 = IMAGE_ROTATE_TRACK_W / 2;

                            ctx.save();

                            overlay.transform(ex1, ey1, -ey1, ex1, _xI, _yI);
                            ctx.drawImage(_image_track_rotate, -_w2, -_w2, _w, _w);
                            overlay.SetBaseTransform();

                            ctx.restore();

                            overlay.CheckRect(_xI - _w2, _yI - _w2, _w, _w);
                        }
                    }

                    ctx.beginPath();
                    ctx.moveTo(xc1, yc1);
                    ctx.lineTo(xc1 + ex2 * TRACK_DISTANCE_ROTATE2, yc1 + ey2 * TRACK_DISTANCE_ROTATE2);
                    ctx.stroke();

                    ctx.beginPath();

                    ctx.fillStyle = _style_white;

                    if (bIsEllipceCorner)
                    {
                        overlay.AddEllipse(x1, y1, TRACK_CIRCLE_RADIUS);
                        overlay.AddEllipse(x2, y2, TRACK_CIRCLE_RADIUS);
                        overlay.AddEllipse(x3, y3, TRACK_CIRCLE_RADIUS);
                        overlay.AddEllipse(x4, y4, TRACK_CIRCLE_RADIUS);
                    }
                    else
                    {
                        overlay.AddRect3(x1, y1, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
                        overlay.AddRect3(x2, y2, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
                        overlay.AddRect3(x3, y3, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
                        overlay.AddRect3(x4, y4, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
                    }

                    if (bIsRectsTrack)
                    {
                        overlay.AddRect3((x1 + x2) / 2, (y1 + y2) / 2, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
                        overlay.AddRect3((x2 + x4) / 2, (y2 + y4) / 2, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
                        overlay.AddRect3((x3 + x4) / 2, (y3 + y4) / 2, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
                        overlay.AddRect3((x3 + x1) / 2, (y3 + y1) / 2, TRACK_RECT_SIZE, ex1, ey1, ex2, ey2);
                    }

                    ctx.fill();
                    ctx.stroke();

                    ctx.beginPath();
                }

                break;
            }

            default:
                break;
        }

        ctx.globalAlpha = _oldGlobalAlpha;

		if (!_retina && this.m_oOverlay.IsCellEditor && AscCommon.AscBrowser.isRetina)
		{
			this.m_oOverlay.IsRetina = false;
			this.m_oOverlay.SetBaseTransform();

			if (matrix)
			{
				matrix.tx *= AscCommon.AscBrowser.retinaPixelRatio;
				matrix.ty *= AscCommon.AscBrowser.retinaPixelRatio;
			}
		}
    },

    DrawTrackSelectShapes : function(x, y, w, h)
    {
        var overlay = this.m_oOverlay;
        overlay.Show();

        this.CurrentPageInfo = overlay.m_oHtmlPage.GetDrawingPageInfo(this.PageIndex);

        var drPage = this.CurrentPageInfo.drawingPage;

        var xDst = drPage.left;
        var yDst = drPage.top;
        var wDst = drPage.right - drPage.left;
        var hDst = drPage.bottom - drPage.top;

        var dKoefX = wDst / this.CurrentPageInfo.width_mm;
        var dKoefY = hDst / this.CurrentPageInfo.height_mm;

        var x1 = (xDst + dKoefX * x) >> 0;
        var y1 = (yDst + dKoefY * y) >> 0;

        var x2 = (xDst + dKoefX * (x + w)) >> 0;
        var y2 = (yDst + dKoefY * (y + h)) >> 0;

        if (x1 > x2)
        {
            var tmp = x1;
            x1 = x2;
            x2 = tmp;
        }
        if (y1 > y2)
        {
            var tmp = y1;
            y1 = y2;
            y2 = tmp;
        }

        overlay.CheckRect(x1, y1, x2 - x1, y2 - y1);
        var ctx = overlay.m_oContext;
        overlay.SetBaseTransform();

        var globalAlphaOld = ctx.globalAlpha;
        ctx.globalAlpha = 0.5;
        ctx.beginPath();
        ctx.fillStyle = "rgba(51,102,204,255)";
        ctx.strokeStyle = "#9ADBFE";
        ctx.lineWidth = 1;
        ctx.fillRect(x1, y1, x2 - x1, y2 - y1);
        ctx.beginPath();
        ctx.strokeRect(x1 - 0.5, y1 - 0.5, x2 - x1 + 1, y2 - y1 + 1);
        ctx.globalAlpha = globalAlphaOld;
    },

    AddRect : function(ctx, x, y, r, b, bIsClever)
    {
        if (bIsClever)
            ctx.rect(x + 0.5, y + 0.5, r - x + 1, b - y + 1);
        else
        {
            ctx.moveTo(x,y);
            ctx.rect(x, y, r - x + 1, b - y + 1);
        }
    },

    AddRectDashClever : function(ctx, x, y, r, b, w_dot, w_dist, bIsStrokeAndCanUseNative)
    {
        var _support_native_dash = (undefined !== ctx.setLineDash);

        // здесь расчитано на толщину линии в один пиксел!
        var _x = x + 0.5;
        var _y = y + 0.5;
        var _r = r + 0.5;
        var _b = b + 0.5;

        if (_support_native_dash && bIsStrokeAndCanUseNative === true)
        {
            ctx.setLineDash([w_dot, w_dist]);

            //ctx.rect(x + 0.5, y + 0.5, r - x, b - y);
            ctx.moveTo(x, _y);
            ctx.lineTo(r - 1, _y);

            ctx.moveTo(_r, y);
            ctx.lineTo(_r, b - 1);

            ctx.moveTo(r + 1, _b);
            ctx.lineTo(x + 2, _b);

            ctx.moveTo(_x, b + 1);
            ctx.lineTo(_x, y + 2);

            ctx.stroke();
            ctx.setLineDash([]);
            return;
        }

        for (var i = x; i < r; i += w_dist)
        {
            ctx.moveTo(i, _y);
            i += w_dot;

            if (i > (r - 1))
                i = r - 1;

            ctx.lineTo(i, _y);
        }
        for (var i = y; i < b; i += w_dist)
        {
            ctx.moveTo(_r, i);
            i += w_dot;

            if (i > (b - 1))
                i = b - 1;

            ctx.lineTo(_r, i);
        }
        for (var i = r + 1; i > (x + 1); i -= w_dist)
        {
            ctx.moveTo(i, _b);
            i -= w_dot;

            if (i < (x + 2))
                i = x + 2;

            ctx.lineTo(i, _b);
        }
        for (var i = b + 1; i > (y + 1); i -= w_dist)
        {
            ctx.moveTo(_x, i);
            i -= w_dot;

            if (i < (y + 2))
                i = y + 2;

            ctx.lineTo(_x, i);
        }

        if (bIsStrokeAndCanUseNative)
            ctx.stroke();
    },

    AddLineDash : function(ctx, x1, y1, x2, y2, w_dot, w_dist)
    {
        var len = Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
        if (len < 1)
            len = 1;

        var len_x1 = Math.abs(w_dot*(x2-x1)/len);
        var len_y1 = Math.abs(w_dot*(y2-y1)/len);
        var len_x2 = Math.abs(w_dist*(x2-x1)/len);
        var len_y2 = Math.abs(w_dist*(y2-y1)/len);

		if (len_x1 < 0.01 && len_y1 < 0.01)
			return;
		if (len_x2 < 0.01 && len_y2 < 0.01)
			return;

        if (x1 <= x2 && y1 <= y2)
        {
            for (var i = x1, j = y1; i <= x2 && j <= y2; i += len_x2, j += len_y2)
            {
                ctx.moveTo(i, j);

                i += len_x1;
                j += len_y1;

                if (i > x2)
                    i = x2;
                if (j > y2)
                    j = y2;

                ctx.lineTo(i, j);
            }
        }
        else if (x1 <= x2 && y1 > y2)
        {
            for (var i = x1, j = y1; i <= x2 && j >= y2; i += len_x2, j -= len_y2)
            {
                ctx.moveTo(i, j);

                i += len_x1;
                j -= len_y1;

                if (i > x2)
                    i = x2;
                if (j < y2)
                    j = y2;

                ctx.lineTo(i, j);
            }
        }
        else if (x1 > x2 && y1 <= y2)
        {
            for (var i = x1, j = y1; i >= x2 && j <= y2; i -= len_x2, j += len_y2)
            {
                ctx.moveTo(i, j);

                i -= len_x1;
                j += len_y1;

                if (i < x2)
                    i = x2;
                if (j > y2)
                    j = y2;

                ctx.lineTo(i, j);
            }
        }
        else
        {
            for (var i = x1, j = y1; i >= x2 && j >= y2; i -= len_x2, j -= len_y2)
            {
                ctx.moveTo(i, j);

                i -= len_x1;
                j -= len_y1;

                if (i < x2)
                    i = x2;
                if (j < y2)
                    j = y2;

                ctx.lineTo(i, j);
            }
        }
    },

    AddRectDash : function(ctx, x1, y1, x2, y2, x3, y3, x4, y4, w_dot, w_dist, bIsStrokeAndCanUseNative)
    {
        var _support_native_dash = (undefined !== ctx.setLineDash);

        if (_support_native_dash && bIsStrokeAndCanUseNative === true)
        {
            ctx.setLineDash([w_dot, w_dist]);

            ctx.moveTo(x1, y1);
            ctx.lineTo(x2, y2);
            ctx.lineTo(x4, y4);
            ctx.lineTo(x3, y3);
            ctx.closePath();

            ctx.stroke();
            ctx.setLineDash([]);
            return;
        }

        this.AddLineDash(ctx, x1, y1, x2, y2, w_dot, w_dist);
        this.AddLineDash(ctx, x2, y2, x4, y4, w_dot, w_dist);
        this.AddLineDash(ctx, x4, y4, x3, y3, w_dot, w_dist);
        this.AddLineDash(ctx, x3, y3, x1, y1, w_dot, w_dist);

        if (bIsStrokeAndCanUseNative)
            ctx.stroke();
    },

    DrawAdjustment : function(matrix, x, y, bTextWarp)
    {
        var overlay = this.m_oOverlay;
        this.CurrentPageInfo = overlay.m_oHtmlPage.GetDrawingPageInfo(this.PageIndex);

        var drPage = this.CurrentPageInfo.drawingPage;

        var xDst = drPage.left;
        var yDst = drPage.top;
        var wDst = drPage.right - drPage.left;
        var hDst = drPage.bottom - drPage.top;

        var dKoefX = wDst / this.CurrentPageInfo.width_mm;
        var dKoefY = hDst / this.CurrentPageInfo.height_mm;

        var cx = (xDst + dKoefX * (matrix.TransformPointX(x, y))) >> 0;
        var cy = (yDst + dKoefY * (matrix.TransformPointY(x, y))) >> 0;

        var _style_blue = "#4D7399";
        var _style_yellow = "#FDF54A";
        var _style_text_adj = "#F888FF";

        var ctx = overlay.m_oContext;

        var dist = TRACK_ADJUSTMENT_SIZE / 2;

        if (!overlay.IsRetina && overlay.IsCellEditor && AscCommon.AscBrowser.isRetina)
            dist *= AscCommon.AscBrowser.retinaPixelRatio;

        ctx.moveTo(cx - dist, cy);
        ctx.lineTo(cx, cy - dist);
        ctx.lineTo(cx + dist, cy);
        ctx.lineTo(cx, cy + dist);
        ctx.closePath();

        overlay.CheckRect(cx - dist, cy - dist, TRACK_ADJUSTMENT_SIZE, TRACK_ADJUSTMENT_SIZE);


        if(bTextWarp === true)
        {
            ctx.fillStyle = _style_text_adj;
        }
        else
        {
            ctx.fillStyle = _style_yellow;
        }
        ctx.strokeStyle = _style_blue;

        ctx.fill();
        ctx.stroke();
        ctx.beginPath();
    },

    DrawEditWrapPointsPolygon : function(points, matrix)
    {
        var _len = points.length;
        if (0 == _len)
            return;

        var overlay = this.m_oOverlay;
        var ctx = overlay.m_oContext;

        this.CurrentPageInfo = overlay.m_oHtmlPage.GetDrawingPageInfo(this.PageIndex);

        var drPage = this.CurrentPageInfo.drawingPage;

        var xDst = drPage.left;
        var yDst = drPage.top;
        var wDst = drPage.right - drPage.left;
        var hDst = drPage.bottom - drPage.top;

        var dKoefX = wDst / this.CurrentPageInfo.width_mm;
        var dKoefY = hDst / this.CurrentPageInfo.height_mm;

        var _tr_points_x = new Array(_len);
        var _tr_points_y = new Array(_len);
        for (var i = 0; i < _len; i++)
        {
            _tr_points_x[i] = (xDst + dKoefX * (matrix.TransformPointX(points[i].x, points[i].y))) >> 0;
            _tr_points_y[i] = (yDst + dKoefY * (matrix.TransformPointY(points[i].x, points[i].y))) >> 0;
        }

        ctx.beginPath();
        for (var i = 0; i < _len; i++)
        {
            if (0 == i)
                ctx.moveTo(_tr_points_x[i], _tr_points_y[i]);
            else
                ctx.lineTo(_tr_points_x[i], _tr_points_y[i]);

            overlay.CheckPoint(_tr_points_x[i], _tr_points_y[i]);
        }

        ctx.closePath();
        ctx.lineWidth = 1;
        ctx.strokeStyle = "#FF0000";
        ctx.stroke();

        ctx.beginPath();
        for (var i = 0; i < _len; i++)
        {
            overlay.AddRect2(_tr_points_x[i] + 0.5, _tr_points_y[i] + 0.5, TRACK_WRAPPOINTS_SIZE);
        }
        ctx.strokeStyle = "#FFFFFF";
        ctx.fillStyle = "#000000";
        ctx.fill();
        ctx.stroke();

        ctx.beginPath();
    },

    DrawEditWrapPointsTrackLines : function(points, matrix)
    {
        var _len = points.length;
        if (0 == _len)
            return;

        var overlay = this.m_oOverlay;
        var ctx = overlay.m_oContext;

        this.CurrentPageInfo = overlay.m_oHtmlPage.GetDrawingPageInfo(this.PageIndex);

        var drPage = this.CurrentPageInfo.drawingPage;

        var xDst = drPage.left;
        var yDst = drPage.top;
        var wDst = drPage.right - drPage.left;
        var hDst = drPage.bottom - drPage.top;

        var dKoefX = wDst / this.CurrentPageInfo.width_mm;
        var dKoefY = hDst / this.CurrentPageInfo.height_mm;

        var _tr_points_x = new Array(_len);
        var _tr_points_y = new Array(_len);
        for (var i = 0; i < _len; i++)
        {
            _tr_points_x[i] = (xDst + dKoefX * (matrix.TransformPointX(points[i].x, points[i].y))) >> 0;
            _tr_points_y[i] = (yDst + dKoefY * (matrix.TransformPointY(points[i].x, points[i].y))) >> 0;
        }

        var globalAlpha = ctx.globalAlpha;
        ctx.globalAlpha = 1.0;

        ctx.beginPath();
        for (var i = 0; i < _len; i++)
        {
            if (0 == i)
                ctx.moveTo(_tr_points_x[i], _tr_points_y[i]);
            else
                ctx.lineTo(_tr_points_x[i], _tr_points_y[i]);

            overlay.CheckPoint(_tr_points_x[i], _tr_points_y[i]);
        }
        ctx.lineWidth = 1;
        ctx.strokeStyle = "#FFFFFF";
        ctx.stroke();

        ctx.beginPath();
        for (var i = 1; i < _len; i++)
        {
            this.AddLineDash(ctx, _tr_points_x[i-1], _tr_points_y[i-1], _tr_points_x[i], _tr_points_y[i], 4, 4);
        }
        ctx.lineWidth = 1;
        ctx.strokeStyle = "#000000";
        ctx.stroke();

        ctx.beginPath();

        ctx.globalAlpha = globalAlpha;
    },

    DrawInlineMoveCursor : function(x, y, h, matrix)
    {
        var overlay = this.m_oOverlay;
        this.CurrentPageInfo = overlay.m_oHtmlPage.GetDrawingPageInfo(this.PageIndex);

        var drPage = this.CurrentPageInfo.drawingPage;

        var xDst = drPage.left;
        var yDst = drPage.top;
        var wDst = drPage.right - drPage.left;
        var hDst = drPage.bottom - drPage.top;

        var dKoefX = wDst / this.CurrentPageInfo.width_mm;
        var dKoefY = hDst / this.CurrentPageInfo.height_mm;

        var bIsIdentMatr = true;
        if (matrix !== undefined && matrix != null)
        {
            if (matrix.IsIdentity2())
            {
                x += matrix.tx;
                y += matrix.ty;
            }
            else
            {
                bIsIdentMatr = false;
            }
        }

        overlay.SetBaseTransform();

        if (bIsIdentMatr)
        {
            var __x = (xDst + dKoefX * x) >> 0;
            var __y = (yDst + dKoefY * y) >> 0;
            var __h = (h * dKoefY) >> 0;

            overlay.CheckRect(__x,__y,2,__h);

            var ctx = overlay.m_oContext;

            var _oldAlpha = ctx.globalAlpha;
            ctx.globalAlpha = 1;

            ctx.lineWidth = 1;
            ctx.strokeStyle = "#000000";
            for (var i = 0; i < __h; i+=2)
            {
                ctx.moveTo(__x,__y+i+0.5);
                ctx.lineTo(__x+2,__y+i+0.5);
            }
            ctx.stroke();

            ctx.beginPath();
            ctx.strokeStyle = "#FFFFFF";
            for (var i = 1; i < __h; i+=2)
            {
                ctx.moveTo(__x,__y+i+0.5);
                ctx.lineTo(__x+2,__y+i+0.5);
            }
            ctx.stroke();

            ctx.globalAlpha = _oldAlpha;
        }
        else
        {
            var _x1 = matrix.TransformPointX(x, y);
            var _y1 = matrix.TransformPointY(x, y);

            var _x2 = matrix.TransformPointX(x, y + h);
            var _y2 = matrix.TransformPointY(x, y + h);

            _x1 = xDst + dKoefX * _x1;
            _y1 = yDst + dKoefY * _y1;

            _x2 = xDst + dKoefX * _x2;
            _y2 = yDst + dKoefY * _y2;

            overlay.CheckPoint(_x1, _y1);
            overlay.CheckPoint(_x2, _y2);

            var ctx = overlay.m_oContext;

            var _oldAlpha = ctx.globalAlpha;
            ctx.globalAlpha = 1;

            ctx.lineWidth = 2;
            ctx.beginPath();
            ctx.strokeStyle = "#FFFFFF";
            ctx.moveTo(_x1, _y1);
            ctx.lineTo(_x2, _y2);
            ctx.stroke();
            ctx.beginPath();

            ctx.strokeStyle = "#000000";

            var _vec_len = Math.sqrt((_x2 - _x1)*(_x2 - _x1) + (_y2 - _y1)*(_y2 - _y1));
            var _dx = (_x2 - _x1) / _vec_len;
            var _dy = (_y2 - _y1) / _vec_len;

            var __x = _x1;
            var __y = _y1;
            for (var i = 0; i < _vec_len; i += 2)
            {
                ctx.moveTo(__x, __y);

                __x += _dx;
                __y += _dy;

                ctx.lineTo(__x, __y);

                __x += _dx;
                __y += _dy;
            }
            ctx.stroke();

            ctx.globalAlpha = _oldAlpha;
        }
    },

    drawFlowAnchor : function(x, y)
    {
        var _flow_anchor = this.m_oOverlay.IsRetina ? AscCommon.g_flow_anchor2 : AscCommon.g_flow_anchor;
        if (!_flow_anchor || !_flow_anchor.asc_complete || (!editor || !editor.ShowParaMarks))
            return;

        var overlay = this.m_oOverlay;
        this.CurrentPageInfo = overlay.m_oHtmlPage.GetDrawingPageInfo(this.PageIndex);

        var drPage = this.CurrentPageInfo.drawingPage;

        var xDst = drPage.left;
        var yDst = drPage.top;
        var wDst = drPage.right - drPage.left;
        var hDst = drPage.bottom - drPage.top;

        var dKoefX = wDst / this.CurrentPageInfo.width_mm;
        var dKoefY = hDst / this.CurrentPageInfo.height_mm;

        var __x = (xDst + dKoefX * x) >> 0;
        var __y = (yDst + dKoefY * y) >> 0;

        __x -= 8;

        overlay.CheckRect(__x,__y,13,15);

        var ctx = overlay.m_oContext;
        var _oldAlpha = ctx.globalAlpha;
        ctx.globalAlpha = 1;

        overlay.SetBaseTransform();

        ctx.drawImage(_flow_anchor, __x, __y, 13, 15);
        ctx.globalAlpha = _oldAlpha;
    },

    DrawPresentationComment : function(type, x, y, w, h)
    {
        if (!window.g_comment_image || !window.g_comment_image.asc_complete)
            return;

        var overlay = this.m_oOverlay;
        this.CurrentPageInfo = overlay.m_oHtmlPage.GetDrawingPageInfo(this.PageIndex);

        var drPage = this.CurrentPageInfo.drawingPage;

        var xDst = drPage.left;
        var yDst = drPage.top;
        var wDst = drPage.right - drPage.left;
        var hDst = drPage.bottom - drPage.top;

        var dKoefX = wDst / this.CurrentPageInfo.width_mm;
        var dKoefY = hDst / this.CurrentPageInfo.height_mm;

        var __x = (xDst + dKoefX * x) >> 0;
        var __y = (yDst + dKoefY * y) >> 0;

        var ctx = overlay.m_oContext;
        var _oldAlpha = ctx.globalAlpha;
        ctx.globalAlpha = 0.5;

        overlay.SetBaseTransform();

        var _index = 0;
        if ((type & 0x02) == 0x02)
            _index = 2;
        if ((type & 0x01) == 0x01)
            _index += 1;

        var _offset = g_comment_image_offsets[_index];
        overlay.CheckRect(__x, __y, _offset[2], _offset[3]);

        this.m_oContext.drawImage(window.g_comment_image, _offset[0], _offset[1], _offset[2], _offset[3], __x, __y, _offset[2], _offset[3]);

        ctx.globalAlpha = _oldAlpha;
    }
};

	function DrawTextByCenter() // this!
	{
		var shape = new AscFormat.CShape();
		shape.setTxBody(AscFormat.CreateTextBodyFromString("", this, shape));
		var par = shape.txBody.content.Content[0];
		par.Reset(0, 0, 1000, 1000, 0);
		par.MoveCursorToStartPos();
		var _paraPr = new CParaPr();
		par.Pr = _paraPr;
		var _textPr = new CTextPr();
		_textPr.FontFamily = { Name : this.Font, Index : -1 };
		_textPr.RFonts.Ascii = { Name : this.Font, Index : -1 };
		_textPr.RFonts.EastAsia = { Name : this.Font, Index : -1 };
		_textPr.RFonts.CS = { Name : this.Font, Index : -1 };
		_textPr.RFonts.HAnsi = { Name : this.Font, Index : -1 };

		_textPr.Bold = this.Bold;
		_textPr.Italic = this.Italic;

		_textPr.FontSize = this.Size;
		_textPr.FontSizeCS = this.Size;

		var parRun = new ParaRun(par); var Pos = 0;
		parRun.Set_Pr(_textPr);
		parRun.AddText(this.Text);
		par.AddToContent(0, parRun);

		par.Recalculate_Page(0);
		par.Recalculate_Page(0);

		var _bounds = par.Get_PageBounds(0);

        var _canvas = this.getCanvas();
		var _ctx = _canvas.getContext('2d');
		var _wPx = _canvas.width;
		var _hPx = _canvas.height;

		var _wMm = _wPx * AscCommon.g_dKoef_pix_to_mm;
		var _hMm = _hPx * AscCommon.g_dKoef_pix_to_mm;

		_ctx.clearRect(0, 0, _wPx, _hPx);

		var _pxBoundsW = par.Lines[0].Ranges[0].W * AscCommon.g_dKoef_mm_to_pix;//(_bounds.Right - _bounds.Left) * g_dKoef_mm_to_pix;
		var _pxBoundsH = (_bounds.Bottom - _bounds.Top) * AscCommon.g_dKoef_mm_to_pix;

		var _yOffset = (_hPx - _pxBoundsH) >> 1;
		var _xOffset = (_wPx - _pxBoundsW) >> 1;

		var graphics = new AscCommon.CGraphics();
		graphics.init(_ctx, _wPx, _hPx, _wMm, _hMm);
		graphics.m_oFontManager = AscCommon.g_fontManager;

		graphics.m_oCoordTransform.tx = _xOffset;
		graphics.m_oCoordTransform.ty = _yOffset;

		graphics.transform(1,0,0,1,0,0);

		par.Draw(0, graphics);
	}

    //--------------------------------------------------------export----------------------------------------------------
    window['AscCommon'] = window['AscCommon'] || {};
    window['AscCommon'].TRACK_CIRCLE_RADIUS = TRACK_CIRCLE_RADIUS;
    window['AscCommon'].TRACK_DISTANCE_ROTATE = TRACK_DISTANCE_ROTATE;
    window['AscCommon'].COverlay = COverlay;
    window['AscCommon'].CAutoshapeTrack = CAutoshapeTrack;

    window['AscCommon'].DrawTextByCenter = DrawTextByCenter;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

var global_hatch_data = [
    /* cross */
    0,0,0,0,0,0,0,0,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,0,0,0,0,0,0,0,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,

    /* dashDnDiag */
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    0,1,1,1,0,1,1,1,
    1,0,1,1,1,0,1,1,
    1,1,0,1,1,1,0,1,
    1,1,1,0,1,1,1,0,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,

    /* dashHorz */
    0,0,0,0,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,0,0,0,0,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,

    /* dashUpDiag */
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,0,1,1,1,0,
    1,1,0,1,1,1,0,1,
    1,0,1,1,1,0,1,1,
    0,1,1,1,0,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,

    /* dashVert */
    0,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    1,1,1,1,0,1,1,1,
    1,1,1,1,0,1,1,1,
    1,1,1,1,0,1,1,1,
    1,1,1,1,0,1,1,1,

    /* diagBrick */
    1,1,1,1,1,1,1,0,
    1,1,1,1,1,1,0,1,
    1,1,1,1,1,0,1,1,
    1,1,1,1,0,1,1,1,
    1,1,1,0,0,1,1,1,
    1,1,0,1,1,0,1,1,
    1,0,1,1,1,1,0,1,
    0,1,1,1,1,1,1,0,

    /* diagCross */
    0,1,1,1,1,1,0,1,
    1,0,1,1,1,0,1,1,
    1,1,0,1,0,1,1,1,
    1,1,1,0,1,1,1,1,
    1,1,0,1,0,1,1,1,
    1,0,1,1,1,0,1,1,
    0,1,1,1,1,1,0,1,
    1,1,1,1,1,1,1,0,

    /* divot */
    1,1,1,1,1,1,1,1,
    1,1,1,0,1,1,1,1,
    1,1,1,1,0,1,1,1,
    1,1,1,0,1,1,1,1,
    1,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,0,
    0,1,1,1,1,1,1,1,

    /* dkDnDiag */
    0,0,1,1,0,0,1,1,
    1,0,0,1,1,0,0,1,
    1,1,0,0,1,1,0,0,
    0,1,1,0,0,1,1,0,
    0,0,1,1,0,0,1,1,
    1,0,0,1,1,0,0,1,
    1,1,0,0,1,1,0,0,
    0,1,1,0,0,1,1,0,

    /* dkHorz */
    0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,

    /* dkUpDiag */
    1,1,0,0,1,1,0,0,
    1,0,0,1,1,0,0,1,
    0,0,1,1,0,0,1,1,
    0,1,1,0,0,1,1,0,
    1,1,0,0,1,1,0,0,
    1,0,0,1,1,0,0,1,
    0,0,1,1,0,0,1,1,
    0,1,1,0,0,1,1,0,

    /* dkVert */
    0,0,1,1,0,0,1,1,
    0,0,1,1,0,0,1,1,
    0,0,1,1,0,0,1,1,
    0,0,1,1,0,0,1,1,
    0,0,1,1,0,0,1,1,
    0,0,1,1,0,0,1,1,
    0,0,1,1,0,0,1,1,
    0,0,1,1,0,0,1,1,

    /* dnDiag */
    0,1,1,1,0,1,1,1,
    1,0,1,1,1,0,1,1,
    1,1,0,1,1,1,0,1,
    1,1,1,0,1,1,1,0,
    0,1,1,1,0,1,1,1,
    1,0,1,1,1,0,1,1,
    1,1,0,1,1,1,0,1,
    1,1,1,0,1,1,1,0,

    /* dotDmnd */
    0,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,0,1,1,1,0,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,0,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,0,1,1,1,0,1,
    1,1,1,1,1,1,1,1,

    /* dotGrid */
    0,1,0,1,0,1,0,1,
    1,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,

    /* horz */
    0,0,0,0,0,0,0,0,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    0,0,0,0,0,0,0,0,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,

    /* horzBrick */
    0,0,0,0,0,0,0,0,
    0,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    0,0,0,0,0,0,0,0,
    1,1,1,1,0,1,1,1,
    1,1,1,1,0,1,1,1,
    1,1,1,1,0,1,1,1,

    /* lgCheck */
    0,0,0,0,1,1,1,1,
    0,0,0,0,1,1,1,1,
    0,0,0,0,1,1,1,1,
    0,0,0,0,1,1,1,1,
    1,1,1,1,0,0,0,0,
    1,1,1,1,0,0,0,0,
    1,1,1,1,0,0,0,0,
    1,1,1,1,0,0,0,0,

    /* lgConfetti */
    0,1,0,0,1,1,1,0,
    1,1,0,0,1,1,1,1,
    1,1,1,1,1,1,0,0,
    1,1,1,0,0,1,0,0,
    0,0,1,0,0,1,1,1,
    0,0,1,1,1,1,1,1,
    1,1,1,1,0,0,1,1,
    0,1,1,1,0,0,1,0,

    /* lgGrid */
    0,0,0,0,0,0,0,0,
    0,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,

    /* ltDnDiag */
    0,1,1,1,0,1,1,1,
    1,0,1,1,1,0,1,1,
    1,1,0,1,1,1,0,1,
    1,1,1,0,1,1,1,0,
    0,1,1,1,0,1,1,1,
    1,0,1,1,1,0,1,1,
    1,1,0,1,1,1,0,1,
    1,1,1,0,1,1,1,0,

    /* ltHorz */
    0,0,0,0,0,0,0,0,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    0,0,0,0,0,0,0,0,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,

    /* ltUpDiag */
    1,1,1,0,1,1,1,0,
    1,1,0,1,1,1,0,1,
    1,0,1,1,1,0,1,1,
    0,1,1,1,0,1,1,1,
    1,1,1,0,1,1,1,0,
    1,1,0,1,1,1,0,1,
    1,0,1,1,1,0,1,1,
    0,1,1,1,0,1,1,1,

    /* ltVert */
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,

    /* narHorz */
    0,0,0,0,0,0,0,0,
    1,1,1,1,1,1,1,1,
    0,0,0,0,0,0,0,0,
    1,1,1,1,1,1,1,1,
    0,0,0,0,0,0,0,0,
    1,1,1,1,1,1,1,1,
    0,0,0,0,0,0,0,0,
    1,1,1,1,1,1,1,1,

    /* narVert */
    1,0,1,0,1,0,1,0,
    1,0,1,0,1,0,1,0,
    1,0,1,0,1,0,1,0,
    1,0,1,0,1,0,1,0,
    1,0,1,0,1,0,1,0,
    1,0,1,0,1,0,1,0,
    1,0,1,0,1,0,1,0,
    1,0,1,0,1,0,1,0,

    /* openDmnd */
    0,1,1,1,1,1,0,1,
    1,0,1,1,1,0,1,1,
    1,1,0,1,0,1,1,1,
    1,1,1,0,1,1,1,1,
    1,1,0,1,0,1,1,1,
    1,0,1,1,1,0,1,1,
    0,1,1,1,1,1,0,1,
    1,1,1,1,1,1,1,0,

    /* pct10 */
    0,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,0,1,1,1,
    1,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,0,1,1,1,
    1,1,1,1,1,1,1,1,

    /* pct20 */
    0,1,1,1,0,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,0,1,1,1,0,1,
    1,1,1,1,1,1,1,1,
    0,1,1,1,0,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,0,1,1,1,0,1,
    1,1,1,1,1,1,1,1,

    /* pct25 */
    0,1,1,1,0,1,1,1,
    1,1,0,1,1,1,0,1,
    0,1,1,1,0,1,1,1,
    1,1,0,1,1,1,0,1,
    0,1,1,1,0,1,1,1,
    1,1,0,1,1,1,0,1,
    0,1,1,1,0,1,1,1,
    1,1,0,1,1,1,0,1,

    /* pct30 */
    0,1,0,1,0,1,0,1,
    1,0,1,1,1,0,1,1,
    0,1,0,1,0,1,0,1,
    1,1,1,0,1,1,1,0,
    0,1,0,1,0,1,0,1,
    1,0,1,1,1,0,1,1,
    0,1,0,1,0,1,0,1,
    1,1,1,0,1,1,1,0,

    /* pct40 */
    0,1,0,1,0,1,0,1,
    1,0,1,0,1,0,1,0,
    0,1,0,1,0,1,0,1,
    1,0,1,0,1,1,1,0,
    0,1,0,1,0,1,0,1,
    1,0,1,0,1,0,1,0,
    0,1,0,1,0,1,0,1,
    1,1,1,0,1,0,1,0,

    /* pct5 */
    0,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,0,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,

    /* pct50 */
    0,1,0,1,0,1,0,1,
    1,0,1,0,1,0,1,0,
    0,1,0,1,0,1,0,1,
    1,0,1,0,1,0,1,0,
    0,1,0,1,0,1,0,1,
    1,0,1,0,1,0,1,0,
    0,1,0,1,0,1,0,1,
    1,0,1,0,1,0,1,0,

    /* pct60 */
    0,0,0,1,0,0,0,1,
    1,0,1,0,1,0,1,0,
    0,1,0,0,0,1,0,0,
    1,0,1,0,1,0,1,0,
    0,0,0,1,0,0,0,1,
    1,0,1,0,1,0,1,0,
    0,1,0,0,0,1,0,0,
    1,0,1,0,1,0,1,0,

    /* pct70 */
    1,0,0,0,1,0,0,0,
    0,0,1,0,0,0,1,0,
    1,0,0,0,1,0,0,0,
    0,0,1,0,0,0,1,0,
    1,0,0,0,1,0,0,0,
    0,0,1,0,0,0,1,0,
    1,0,0,0,1,0,0,0,
    0,0,1,0,0,0,1,0,

    /* pct75 */
    1,0,0,0,1,0,0,0,
    0,0,0,0,0,0,0,0,
    0,0,1,0,0,0,1,0,
    0,0,0,0,0,0,0,0,
    1,0,0,0,1,0,0,0,
    0,0,0,0,0,0,0,0,
    0,0,1,0,0,0,1,0,
    0,0,0,0,0,0,0,0,

    /* pct80 */
    0,0,0,1,0,0,0,0,
    0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,1,
    0,0,0,0,0,0,0,0,
    0,0,0,1,0,0,0,0,
    0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,1,
    0,0,0,0,0,0,0,0,

    /* pct90 */
    0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,
    0,0,0,0,1,0,0,0,
    0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,
    1,0,0,0,0,0,0,0,

    /* plaid */
    0,1,0,1,0,1,0,1,
    1,0,1,0,1,0,1,0,
    0,1,0,1,0,1,0,1,
    1,0,1,0,1,0,1,0,
    0,0,0,0,1,1,1,1,
    0,0,0,0,1,1,1,1,
    0,0,0,0,1,1,1,1,
    0,0,0,0,1,1,1,1,

    /* shingle */
    1,1,1,1,1,1,0,0,
    0,1,1,1,1,0,1,1,
    1,0,1,1,0,1,1,1,
    1,1,0,0,1,1,1,1,
    1,1,1,1,0,0,1,1,
    1,1,1,1,1,1,0,1,
    1,1,1,1,1,1,1,0,
    1,1,1,1,1,1,1,0,

    /* smCheck */
    0,1,1,0,0,1,1,0,
    1,0,0,1,1,0,0,1,
    1,0,0,1,1,0,0,1,
    0,1,1,0,0,1,1,0,
    0,1,1,0,0,1,1,0,
    1,0,0,1,1,0,0,1,
    1,0,0,1,1,0,0,1,
    0,1,1,0,0,1,1,0,

    /* smConfetti */
    0,1,1,1,1,1,1,1,
    1,1,1,1,0,1,1,1,
    1,0,1,1,1,1,1,1,
    1,1,1,1,1,1,0,1,
    1,1,1,0,1,1,1,1,
    1,1,1,1,1,1,1,0,
    1,1,0,1,1,1,1,1,
    1,1,1,1,1,0,1,1,

    /* smGrid */
    0,0,0,0,0,0,0,0,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,0,0,0,0,0,0,0,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,

    /* solidDmnd */
    1,1,1,0,1,1,1,1,
    1,1,0,0,0,1,1,1,
    1,0,0,0,0,0,1,1,
    0,0,0,0,0,0,0,1,
    1,0,0,0,0,0,1,1,
    1,1,0,0,0,1,1,1,
    1,1,1,0,1,1,1,1,
    1,1,1,1,1,1,1,1,

    /* sphere */
    1,0,0,0,1,0,0,0,
    0,1,1,1,0,1,1,0,
    0,1,1,1,0,0,0,0,
    0,1,1,1,0,0,0,0,
    1,0,0,0,1,0,0,0,
    0,1,1,0,0,1,1,1,
    0,0,0,0,0,1,1,1,
    0,0,0,0,0,1,1,1,

    /* trellis */
    0,0,0,0,0,0,0,0,
    1,0,0,1,1,0,0,1,
    0,0,0,0,0,0,0,0,
    0,1,1,0,0,1,1,0,
    0,0,0,0,0,0,0,0,
    1,0,0,1,1,0,0,1,
    0,0,0,0,0,0,0,0,
    0,1,1,0,0,1,1,0,

    /* upDiag */
    1,1,0,0,1,1,0,0,
    1,0,0,1,1,0,0,1,
    0,0,1,1,0,0,1,1,
    0,1,1,0,0,1,1,0,
    1,1,0,0,1,1,0,0,
    1,0,0,1,1,0,0,1,
    0,0,1,1,0,0,1,1,
    0,1,1,0,0,1,1,0,

    /* vert */
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,
    0,1,1,1,0,1,1,1,

    /* wave */
    1,1,1,1,1,1,1,1,
    1,1,1,0,0,1,1,1,
    1,1,0,1,1,0,1,0,
    0,0,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,0,0,1,1,1,
    1,1,0,1,1,0,1,0,
    0,0,1,1,1,1,1,1,

    /* wdDnDiag */
    0,0,1,1,1,1,1,0,
    0,0,0,1,1,1,1,1,
    1,0,0,0,1,1,1,1,
    1,1,0,0,0,1,1,1,
    1,1,1,0,0,0,1,1,
    1,1,1,1,0,0,0,1,
    1,1,1,1,1,0,0,0,
    0,1,1,1,1,1,0,0,

    /* wdUpDiag */
    0,1,1,1,1,1,0,0,
    1,1,1,1,1,0,0,0,
    1,1,1,1,0,0,0,1,
    1,1,1,0,0,0,1,1,
    1,1,0,0,0,1,1,1,
    1,0,0,0,1,1,1,1,
    0,0,0,1,1,1,1,1,
    0,0,1,1,1,1,1,0,

    /* weave */
    0,1,1,1,0,1,1,1,
    1,0,1,0,1,0,1,1,
    1,1,0,1,1,1,0,1,
    1,0,1,1,1,0,1,1,
    0,1,1,1,0,1,1,1,
    1,1,1,0,1,0,1,1,
    1,1,0,1,1,1,0,1,
    1,0,1,0,1,1,1,0,

    /* zigZag */
    0,1,1,1,1,1,1,0,
    1,0,1,1,1,1,0,1,
    1,1,0,1,1,0,1,1,
    1,1,1,0,0,1,1,1,
    0,1,1,1,1,1,1,0,
    1,0,1,1,1,1,0,1,
    1,1,0,1,1,0,1,1,
    1,1,1,0,0,1,1,1
];

var HATCH_TX_SIZE = 8;

var global_hatch_offsets = {};
global_hatch_offsets["cross"]       = 0;
global_hatch_offsets["dashDnDiag"]  = 1;
global_hatch_offsets["dashHorz"]    = 2;
global_hatch_offsets["dashUpDiag"]  = 3;
global_hatch_offsets["dashVert"]    = 4;
global_hatch_offsets["diagBrick"]   = 5;
global_hatch_offsets["diagCross"]   = 6;
global_hatch_offsets["divot"]       = 7;
global_hatch_offsets["dkDnDiag"]    = 8;
global_hatch_offsets["dkHorz"]      = 9;
global_hatch_offsets["dkUpDiag"]    = 10;
global_hatch_offsets["dkVert"]      = 11;
global_hatch_offsets["dnDiag"]      = 12;
global_hatch_offsets["dotDmnd"]     = 13;
global_hatch_offsets["dotGrid"]     = 14;
global_hatch_offsets["horz"]        = 15;
global_hatch_offsets["horzBrick"]   = 16;
global_hatch_offsets["lgCheck"]     = 17;
global_hatch_offsets["lgConfetti"]  = 18;
global_hatch_offsets["lgGrid"]      = 19;
global_hatch_offsets["ltDnDiag"]    = 20;
global_hatch_offsets["ltHorz"]      = 21;
global_hatch_offsets["ltUpDiag"]    = 22;
global_hatch_offsets["ltVert"]      = 23;
global_hatch_offsets["narHorz"]     = 24;
global_hatch_offsets["narVert"]     = 25;
global_hatch_offsets["openDmnd"]    = 26;
global_hatch_offsets["pct10"]       = 27;
global_hatch_offsets["pct20"]       = 28;
global_hatch_offsets["pct25"]       = 29;
global_hatch_offsets["pct30"]       = 30;
global_hatch_offsets["pct40"]       = 31;
global_hatch_offsets["pct5"]        = 32;
global_hatch_offsets["pct50"]       = 33;
global_hatch_offsets["pct60"]       = 34;
global_hatch_offsets["pct70"]       = 35;
global_hatch_offsets["pct75"]       = 36;
global_hatch_offsets["pct80"]       = 37;
global_hatch_offsets["pct90"]       = 38;
global_hatch_offsets["plaid"]       = 39;
global_hatch_offsets["shingle"]     = 40;
global_hatch_offsets["smCheck"]     = 41;
global_hatch_offsets["smConfetti"]  = 42;
global_hatch_offsets["smGrid"]      = 43;
global_hatch_offsets["solidDmnd"]   = 44;
global_hatch_offsets["sphere"]      = 45;
global_hatch_offsets["trellis"]     = 46;
global_hatch_offsets["upDiag"]      = 47;
global_hatch_offsets["vert"]        = 48;
global_hatch_offsets["wave"]        = 49;
global_hatch_offsets["wdDnDiag"]    = 50;
global_hatch_offsets["wdUpDiag"]    = 51;
global_hatch_offsets["weave"]       = 52;
global_hatch_offsets["zigZag"]      = 53;

var global_hatch_names = [
"cross",
"dashDnDiag",
"dashHorz",
"dashUpDiag",
"dashVert",
"diagBrick",
"diagCross",
"divot",
"dkDnDiag",
"dkHorz",
"dkUpDiag",
"dkVert",
"dnDiag",
"dotDmnd",
"dotGrid",
"horz",
"horzBrick",
"lgCheck",
"lgConfetti",
"lgGrid",
"ltDnDiag",
"ltHorz",
"ltUpDiag",
"ltVert",
"narHorz",
"narVert",
"openDmnd",
"pct10",
"pct20",
"pct25",
"pct30",
"pct40",
"pct5",
"pct50",
"pct60",
"pct70",
"pct75",
"pct80",
"pct90",
"plaid",
"shingle",
"smCheck",
"smConfetti",
"smGrid",
"solidDmnd",
"sphere",
"trellis",
"upDiag",
"vert",
"wave",
"wdDnDiag",
"wdUpDiag",
"weave",
"zigZag"];

var global_hatch_offsets_count = 54;

var global_hatch_brushes = {};

function CHatchBrush()
{
    this.Name   = "";
    this.Canvas = null;
    this.Ctx    = null;
    this.Data   = null;

    this.fgClr = { R : -1, G : -1, B : -1, A : 255 };
    this.bgClr = { R : -1, G : -1, B : -1, A : 255 };
}
CHatchBrush.prototype =
{
    Create : function(name)
    {
        this.Name = name;

        if (undefined === global_hatch_offsets[name])
            this.Name = "cross";

        if (!window["NATIVE_EDITOR_ENJINE"])
        {
            this.Canvas = document.createElement('canvas');
            this.Canvas.width = HATCH_TX_SIZE;
            this.Canvas.height = HATCH_TX_SIZE;

            this.Ctx = this.Canvas.getContext('2d');
            this.Data = this.Ctx.createImageData(HATCH_TX_SIZE, HATCH_TX_SIZE);
        }
        else
        {
            this.Data = new Uint8Array(4 * HATCH_TX_SIZE * HATCH_TX_SIZE);
        }
    },

    CheckColors : function(r,g,b,a,br,bg,bb,ba)
    {
        if (null == this.Data)
            return;

        if (this.fgClr.R == r && this.fgClr.G == g && this.fgClr.B == b && this.fgClr.A == a &&
            this.bgClr.R == br && this.bgClr.G == bg && this.bgClr.B == bb && this.bgClr.A == ba)
            return;

        this.fgClr.R = r;
        this.fgClr.G = g;
        this.fgClr.B = b;
        this.fgClr.A = a;

        this.bgClr.R = br;
        this.bgClr.G = bg;
        this.bgClr.B = bb;
        this.bgClr.A = ba;

        var _len = HATCH_TX_SIZE * HATCH_TX_SIZE;
        var _src_data_offset = global_hatch_offsets[this.Name] * _len;
        var _src_data = global_hatch_data;
        var _dst_data = this.Canvas ? this.Data.data : this.Data;
        var _ind = 0;

        for (var i = 0; i < _len; i++)
        {
            if (_src_data[_src_data_offset + i] == 0)
            {
                _dst_data[_ind++] = r;
                _dst_data[_ind++] = g;
                _dst_data[_ind++] = b;
                _dst_data[_ind++] = a;
            }
            else
            {
                _dst_data[_ind++] = br;
                _dst_data[_ind++] = bg;
                _dst_data[_ind++] = bb;
                _dst_data[_ind++] = ba;
            }
        }

        if (this.Canvas)
            this.Ctx.putImageData(this.Data, 0, 0);
    },

    toDataURL : function()
    {
        if (this.Canvas)
            return this.Canvas.toDataURL("image/png");

        return "data:onlyoffice_hatch," + AscCommon.Base64Encode(this.Data, 4 * HATCH_TX_SIZE * HATCH_TX_SIZE);
    }
};

function GetHatchBrush(name, r, g, b, a, br, bg, bb, ba)
{
    var _brush = global_hatch_brushes[name];
    if (_brush !== undefined)
    {
        _brush.CheckColors(r, g, b, a, br, bg, bb, ba);
        return _brush;
    }

    _brush = new CHatchBrush();
    _brush.Create(name);
    _brush.CheckColors(r, g, b, a, br, bg, bb, ba);
    global_hatch_brushes[name] = _brush;
    return _brush;
}

    //--------------------------------------------------------export----------------------------------------------------
    window['AscCommon'] = window['AscCommon'] || {};
    window['AscCommon'].global_hatch_names = global_hatch_names;
    window['AscCommon'].global_hatch_offsets = global_hatch_offsets;
    window['AscCommon'].GetHatchBrush = GetHatchBrush;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(	/**
* @param {Window} window
* @param {undefined} undefined
*/
function (window, undefined) {

    var AscBrowser = window['AscCommon'].AscBrowser;

var debug = false;

var ScrollArrowType = {
    ARROW_TOP:0,
    ARROW_RIGHT:1,
    ARROW_BOTTOM:2,
    ARROW_LEFT:3
};
var ScrollOverType = {
    NONE:0,
    OVER:1,
    ACTIVE:2,
    STABLE:3,
    LAYER:4
};

var ArrowStatus = {
    upLeftArrowHover_downRightArrowNonActive:0,
    upLeftArrowActive_downRightArrowNonActive:1,
    upLeftArrowNonActive_downRightArrowHover:2,
    upLeftArrowNonActive_downRightArrowActive:3,
    upLeftArrowNonActive_downRightArrowNonActive:4,
    arrowHover:5
};

function GetClientWidth( elem ) {
    var _w = elem.clientWidth;
    if ( 0 != _w )
        return _w;

    var _string_w = "" + elem.style.width;
    if ( -1 < _string_w.indexOf( "%" ) )
        return 0;

    var _intVal = parseInt( _string_w );
    if ( !isNaN( _intVal ) && 0 < _intVal )
        return _intVal;

    return 0;
}
function GetClientHeight( elem ) {
    var _w = elem.clientHeight;
    if ( 0 != _w )
        return _w;

    var _string_w = "" + elem.style.height;
    if ( -1 < _string_w.indexOf( "%" ) )
        return 0;

    var _intVal = parseInt( _string_w );
    if ( !isNaN( _intVal ) && 0 < _intVal )
        return _intVal;

    return 0;
}

function CArrowDrawer( settings ) {
    // размер квадратика в пикселах
    this.Size = 16;
    this.SizeW = 16;
    this.SizeH = 16;

    this.SizeNaturalW = this.SizeW;
    this.SizeNaturalH = this.SizeH;

    this.IsRetina = false;

    // просто рисовать - неправильно. рисуется с антиалиазингом - и получается некрасиво
    /*this.ColorGradStart = {R:69, G:70, B:71};
     this.ColorGradEnd = {R:116, G:117, B:118};*/

    function HEXTORGB( colorHEX ) {
        return {
            R:parseInt( colorHEX.substring( 1, 3 ), 16 ),
            G:parseInt( colorHEX.substring( 3, 5 ), 16 ),
            B:parseInt( colorHEX.substring( 5, 7 ), 16 )
        }
    }

    this.ColorGradStart = [];
    this.ColorGradEnd = [];

    this.ColorGradStart[ScrollOverType.NONE] = HEXTORGB( settings.arrowColor );
    this.ColorGradEnd[ScrollOverType.NONE] = HEXTORGB( settings.arrowColor );

    this.ColorGradStart[ScrollOverType.STABLE] = HEXTORGB( settings.arrowStableColor );
    this.ColorGradEnd[ScrollOverType.STABLE] = HEXTORGB( settings.arrowStableColor );

    this.ColorGradStart[ScrollOverType.OVER] = HEXTORGB( settings.arrowOverColor );
    this.ColorGradEnd[ScrollOverType.OVER] = HEXTORGB( settings.arrowOverColor );

    this.ColorGradStart[ScrollOverType.ACTIVE] = HEXTORGB( settings.arrowActiveColor );
    this.ColorGradEnd[ScrollOverType.ACTIVE] = HEXTORGB( settings.arrowActiveColor );

    this.ColorBorderNone = settings.arrowBorderColor;
    this.ColorBorderStable = settings.arrowStableBorderColor;
    this.ColorBorderOver = settings.arrowOverBorderColor;
    this.ColorBorderActive = settings.arrowActiveBorderColor;

    this.ColorBackNone = settings.arrowBackgroundColor;
    this.ColorBackStable = settings.arrowStableBackgroundColor;
    this.ColorBackOver = settings.arrowOverBackgroundColor;
    this.ColorBackActive = settings.arrowActiveBackgroundColor;

    // вот такие мега настройки для кастомизации)
    this.IsDrawBorderInNoneMode = false;
    this.IsDrawBorders = true;

    // имя - направление стрелки
    this.ImageLeft = null;
    this.ImageTop = null;
    this.ImageRight = null;
    this.ImageBottom = null;

    this.IsNeedInvertOnActive = settings.isNeedInvertOnActive;

    this.lastArrowStatus1 = -1;
    this.lastArrowStatus2 = -1;
    this.startColorFadeInOutStart1 = {R:-1,G:-1,B:-1};
    this.startColorFadeInOutStart2 = {R:-1,G:-1,B:-1};

    this.fadeInTimeoutFirst = -1;
    this.fadeOutTimeoutFirst = -1;

    this.fadeInTimeout1 = -1;
    this.fadeOutTimeout1 = -1;
    this.fadeInTimeout2 = -1;
    this.fadeOutTimeout2 = -1;


    this.fadeInActive1 = false;
    this.fadeOutActive1 = false;

    this.fadeInActive2 = false;
    this.fadeOutActive2 = false;

    this.fadeInFadeOutDelay = settings.fadeInFadeOutDelay || 30;

}
CArrowDrawer.prototype.InitSize = function ( sizeW, sizeH, is_retina ) {
    if ( ( sizeH == this.SizeH || sizeW == this.SizeW ) && is_retina == this.IsRetina && null != this.ImageLeft )
        return;

    this.SizeW = Math.max( sizeW, 1 );
    this.SizeH = Math.max( sizeH, 1 );
    this.IsRetina = is_retina;

    this.SizeNaturalW = this.SizeW;
    this.SizeNaturalH = this.SizeH;

    if ( this.IsRetina ) {
        this.SizeW <<= 1;
        this.SizeH <<= 1;

        this.SizeNaturalW <<= 1;
        this.SizeNaturalH <<= 1;
    }

    if (null == this.ImageLeft || null == this.ImageTop || null == this.ImageRight || null == this.ImageBottom)
	{
		this.ImageLeft = [document.createElement('canvas'), document.createElement('canvas'), document.createElement('canvas'), document.createElement('canvas')];
		this.ImageTop = [document.createElement('canvas'), document.createElement('canvas'), document.createElement('canvas'), document.createElement('canvas')];
		this.ImageRight = [document.createElement('canvas'), document.createElement('canvas'), document.createElement('canvas'), document.createElement('canvas')];
		this.ImageBottom = [document.createElement('canvas'), document.createElement('canvas'), document.createElement('canvas'), document.createElement('canvas')];
	}

    this.ImageLeft[ScrollOverType.NONE].width = this.SizeW;
    this.ImageLeft[ScrollOverType.NONE].height = this.SizeH;
    this.ImageLeft[ScrollOverType.STABLE].width = this.SizeW;
    this.ImageLeft[ScrollOverType.STABLE].height = this.SizeH;
    this.ImageLeft[ScrollOverType.OVER].width = this.SizeW;
    this.ImageLeft[ScrollOverType.OVER].height = this.SizeH;
    this.ImageLeft[ScrollOverType.ACTIVE].width = this.SizeW;
    this.ImageLeft[ScrollOverType.ACTIVE].height = this.SizeH;

    this.ImageTop[ScrollOverType.NONE].width = this.SizeW;
    this.ImageTop[ScrollOverType.NONE].height = this.SizeH;
    this.ImageTop[ScrollOverType.STABLE].width = this.SizeW;
    this.ImageTop[ScrollOverType.STABLE].height = this.SizeH;
    this.ImageTop[ScrollOverType.OVER].width = this.SizeW;
    this.ImageTop[ScrollOverType.OVER].height = this.SizeH;
    this.ImageTop[ScrollOverType.ACTIVE].width = this.SizeW;
    this.ImageTop[ScrollOverType.ACTIVE].height = this.SizeH;

    this.ImageRight[ScrollOverType.NONE].width = this.SizeW;
    this.ImageRight[ScrollOverType.NONE].height = this.SizeH;
    this.ImageRight[ScrollOverType.STABLE].width = this.SizeW;
    this.ImageRight[ScrollOverType.STABLE].height = this.SizeH;
    this.ImageRight[ScrollOverType.OVER].width = this.SizeW;
    this.ImageRight[ScrollOverType.OVER].height = this.SizeH;
    this.ImageRight[ScrollOverType.ACTIVE].width = this.SizeW;
    this.ImageRight[ScrollOverType.ACTIVE].height = this.SizeH;

    this.ImageBottom[ScrollOverType.NONE].width = this.SizeW;
    this.ImageBottom[ScrollOverType.NONE].height = this.SizeH;
    this.ImageBottom[ScrollOverType.STABLE].width = this.SizeW;
    this.ImageBottom[ScrollOverType.STABLE].height = this.SizeH;
    this.ImageBottom[ScrollOverType.OVER].width = this.SizeW;
    this.ImageBottom[ScrollOverType.OVER].height = this.SizeH;
    this.ImageBottom[ScrollOverType.ACTIVE].width = this.SizeW;
    this.ImageBottom[ScrollOverType.ACTIVE].height = this.SizeH;


    var len = 6;
    if ( this.SizeH < 6 )
        return;

    if (this.IsRetina)
        len <<= 1;

//        else (this.SizeH > 12)
//        len = this.Size - 8;

    // теперь делаем нечетную длину
    if ( 0 == (len & 1) )
        len += 1;

    var countPart = (len + 1) >> 1,
        plusColor, _data, px,
        _x = ((this.SizeW - len) >> 1),
        _y = this.SizeH - ((this.SizeH - countPart) >> 1),
        _radx = _x + (len >> 1),
        _rady = _y - (countPart >> 1),
        ctx_lInactive, ctx_tInactive, ctx_rInactive, ctx_bInactive,
        r, g, b;

    for ( var index = 0; index < this.ImageTop.length; index++ ) {
        var __x = _x, __y = _y, _len = len;
        r = this.ColorGradStart[index].R;
        g = this.ColorGradStart[index].G;
        b = this.ColorGradStart[index].B;

        ctx_tInactive = this.ImageTop[index].getContext( '2d' );
        ctx_lInactive = this.ImageLeft[index].getContext( '2d' );
        ctx_rInactive = this.ImageRight[index].getContext( '2d' );
        ctx_bInactive = this.ImageBottom[index].getContext( '2d' );

        plusColor = (this.ColorGradEnd[index].R - this.ColorGradStart[index].R) / countPart;

        _data = ctx_tInactive.createImageData( this.SizeW, this.SizeH );
        px = _data.data;

        while ( _len > 0 ) {
            var ind = 4 * ( this.SizeW * __y + __x );
            for ( var i = 0; i < _len; i++ ) {
                px[ind++] = r;
                px[ind++] = g;
                px[ind++] = b;
                px[ind++] = 255;
            }

            r = (r + plusColor) >> 0;
            g = (g + plusColor) >> 0;
            b = (b + plusColor) >> 0;

            __x += 1;
            __y -= 1;
            _len -= 2;
        }

        ctx_tInactive.putImageData( _data, 0, -1 );

        ctx_lInactive.translate( _radx, _rady + 1 );
        ctx_lInactive.rotate( -Math.PI / 2 );
        ctx_lInactive.translate( -_radx, -_rady );
        ctx_lInactive.drawImage( this.ImageTop[index], 0, 0 );

        ctx_rInactive.translate( _radx + 1, _rady );
        ctx_rInactive.rotate( Math.PI / 2 );
        ctx_rInactive.translate( -_radx, -_rady );
        ctx_rInactive.drawImage( this.ImageTop[index], 0, 0 );

        ctx_bInactive.translate( _radx + 1, _rady + 1 );
        ctx_bInactive.rotate( Math.PI );
        ctx_bInactive.translate( -_radx, -_rady );
        ctx_bInactive.drawImage( this.ImageTop[index], 0, 0 );

    }

    if ( this.IsRetina ) {
        this.SizeW >>= 1;
        this.SizeH >>= 1;
    }
};
CArrowDrawer.prototype.drawArrow = function ( type, mode, ctx, w, h ) {

    ctx.beginPath();

    var startColorFadeIn = _HEXTORGB_( this.ColorBackNone ),
        startColorFadeOut = _HEXTORGB_( this.ColorBackOver ),
        that = this,
        img = this.ImageTop[mode],
        x = 0, y = 0, is_vertical = true,
        bottomRightDelta = 1,
        xDeltaIMG = 0, yDeltaIMG = 0, xDeltaBORDER = 0.5, yDeltaBORDER = 1.5,
        tempIMG1 = document.createElement( 'canvas' ),
        tempIMG2 = document.createElement( 'canvas' );

    tempIMG1.width = this.SizeNaturalW;
    tempIMG1.height = this.SizeNaturalH;
    tempIMG2.width = this.SizeNaturalW;
    tempIMG2.height = this.SizeNaturalH;

    var ctx1 = tempIMG1.getContext('2d'),
        ctx2 = tempIMG2.getContext('2d');

    if (this.IsRetina)
    {
        ctx1.setTransform(2, 0, 0, 2, 0, 0);
        ctx2.setTransform(2, 0, 0, 2, 0, 0);
    }

    function fadeIn(){

        ctx1.fillStyle = "rgb(" + that.startColorFadeInOutStart1.R + "," +
                                 that.startColorFadeInOutStart1.G + "," +
                                 that.startColorFadeInOutStart1.B + ")";

        startColorFadeIn.R -= 2;
        startColorFadeIn.G -= 2;
        startColorFadeIn.B -= 2;

        ctx1.rect( x + xDeltaBORDER, y + yDeltaBORDER, strokeW, strokeH );
        ctx1.fill();

        if ( that.IsDrawBorders ) {
            ctx.strokeStyle = that.ColorBorderOver;
            ctx.stroke();
        }

        ctx1.drawImage( img, x + xDeltaIMG, y + yDeltaIMG, that.SizeW, that.SizeH );

        if ( startColorFadeIn.R >= 207 ) {
            that.startColorFadeInOutStart1 = startColorFadeIn;
            that.fadeInTimeout = setTimeout( fadeIn, that.fadeInFadeOutDelay );
        }
        else {
            clearTimeout( that.fadeInTimeout );
            that.fadeInTimeout = null;
            that.fadeInActiveFirst = false;
            startColorFadeIn.R += 2;
            startColorFadeIn.G += 2;
            startColorFadeIn.B += 2;
            that.startColorFadeInOutStart1 = startColorFadeIn;
        }

    }

    function fadeOut(){

        ctx.fillStyle = "rgb(" + that.startColorFadeInOutStart1.R + "," +
                                 that.startColorFadeInOutStart1.G + "," +
                                 that.startColorFadeInOutStart1.B + ")";

        startColorFadeOut.R += 2;
        startColorFadeOut.G += 2;
        startColorFadeOut.B += 2;

        ctx.rect( x + xDeltaBORDER, y + yDeltaBORDER, strokeW, strokeH );
        ctx.fill();

        if ( that.IsDrawBorders ) {
            ctx.strokeStyle = that.ColorBorderOver;
            ctx.stroke();
        }

        ctx.drawImage( img, x + xDeltaIMG, y + yDeltaIMG, that.SizeW, that.SizeH );

        if ( startColorFadeOut.R <= 241 ) {
            that.startColorFadeInOutStart1 = startColorFadeOut;
            that.fadeOutTimeout = setTimeout( fadeOut, that.fadeInFadeOutDelay );
        }
        else {
            clearTimeout( that.fadeOutTimeout );
            that.fadeOutTimeout = null;
            that.fadeOutActiveFirst = false;
            startColorFadeOut.R -= 2;
            startColorFadeOut.G -= 2;
            startColorFadeOut.B -= 2;
            that.startColorFadeInOutStart1 = startColorFadeOut;
        }

    }

    if ( mode === null || mode === undefined ) {
        mode = ScrollOverType.NONE;
    }

    switch ( type ) {
        case ScrollArrowType.ARROW_LEFT:
        {
            x = 1;
            y = -1;
            is_vertical = false;
            img = this.ImageLeft[mode];
            break;
        }
        case ScrollArrowType.ARROW_RIGHT:
        {
            is_vertical = false;
            x = w - this.SizeW - bottomRightDelta;
            y = -1;
            img = this.ImageRight[mode];
            break;
        }
        case ScrollArrowType.ARROW_BOTTOM:
        {
            y = h - this.SizeH - bottomRightDelta - 1;
            img = this.ImageBottom[mode];
            break;
        }
        default:{
            y = 0;
            break;
        }
    }

    ctx.lineWidth = 1;
    var strokeW = is_vertical ? this.SizeW - 1 : this.SizeW - 1;
    var strokeH = is_vertical ? this.SizeH - 1 : this.SizeH - 1;

    switch ( mode ) {
        case ScrollOverType.NONE:
        {
            if ( this.lastArrowStatus1 == ScrollOverType.OVER ) {

                clearTimeout( this.fadeInTimeout );
                this.fadeInTimeout = null;
                clearTimeout( this.fadeOutTimeout );
                this.fadeOutTimeout = null;

                this.lastArrowStatus1 = mode;
                this.startColorFadeInOutStart1 = this.startColorFadeInOutStart1.R < 0 ? startColorFadeOut : this.startColorFadeInOutStart1;
                this.fadeOutActiveFirst = true;
                fadeOut();
            }
            else{
                ctx.fillStyle = this.ColorBackNone;
				ctx.fillRect( x1 + xDeltaBORDER >> 0, y1 + yDeltaBORDER >> 0, strokeW, strokeH );
                ctx.beginPath();
                ctx.drawImage( img, x + xDeltaIMG, y + yDeltaIMG, this.SizeW, this.SizeH );
                if ( this.IsDrawBorders ) {
                    ctx.strokeStyle = this.ColorBorderNone;
                    ctx.rect( x + xDeltaBORDER, y + yDeltaBORDER, strokeW, strokeH );
                    ctx.stroke();
                }
            }
            break;
        }
        case ScrollOverType.STABLE:
        {
            if ( this.lastArrowStatus1 == ScrollOverType.OVER ) {

                clearTimeout( this.fadeInTimeout );
                this.fadeInTimeout = null;
                clearTimeout( this.fadeOutTimeout );
                this.fadeOutTimeout = null;

                this.lastArrowStatus1 = mode;
                this.startColorFadeInOutStart1 = this.startColorFadeInOutStart1.R < 0 ? startColorFadeOut : this.startColorFadeInOutStart1;
                this.fadeOutActiveFirst = true;
                fadeOut();
            }
            else{
                ctx.fillStyle = this.ColorBackStable;
				ctx.fillRect( x1 + xDeltaBORDER >> 0, y1 + yDeltaBORDER >> 0, strokeW, strokeH );
                ctx.beginPath();
                ctx.drawImage( img, x + xDeltaIMG, y + yDeltaIMG, this.SizeW, this.SizeH );
                ctx.strokeStyle = this.ColorBackStable;
                if ( this.IsDrawBorders ) {
                    ctx.strokeStyle = this.ColorBorderStable;
                    ctx.rect( x + xDeltaBORDER, y + yDeltaBORDER, strokeW, strokeH );
                    ctx.stroke();
                }
            }
            break;
        }
        case ScrollOverType.OVER:
        {

            if ( this.lastArrowStatus1 == ScrollOverType.NONE || this.lastArrowStatus1 == ScrollOverType.STABLE ) {

                clearTimeout( this.fadeInTimeout );
                this.fadeInTimeout = null;
                clearTimeout( this.fadeOutTimeout );
                this.fadeOutTimeout = null;

                this.lastArrowStatus1 = mode;
                this.startColorFadeInOutStart1 = this.startColorFadeInOutStart1.R < 0 ? startColorFadeIn : this.startColorFadeInOutStart1;
                this.fadeInActiveFirst = true;
                fadeIn();
            }
            else{
                ctx.beginPath();
                ctx.fillStyle = this.ColorBackOver;

				ctx.fillRect( x1 + xDeltaBORDER >> 0, y1 + yDeltaBORDER >> 0, strokeW, strokeH );
                ctx.drawImage( img, x + xDeltaIMG, y + yDeltaIMG, this.SizeW, this.SizeH );
                if ( this.IsDrawBorders ) {
                    ctx.strokeStyle = this.ColorBorderOver;
                    ctx.rect( x + xDeltaBORDER, y + yDeltaBORDER, strokeW, strokeH );
                    ctx.stroke();
                }

            }
            break;
        }
        case ScrollOverType.ACTIVE:
        {
            ctx.beginPath();
            ctx.fillStyle = this.ColorBackActive;
			ctx.fillRect( x1 + xDeltaBORDER >> 0, y1 + yDeltaBORDER >> 0, strokeW, strokeH );

            if ( !this.IsNeedInvertOnActive ) {
                ctx.drawImage( img, x + xDeltaIMG, y + yDeltaIMG, this.SizeW, this.SizeH );
            }
            else {
                // slow method
                var _ctx = img.getContext( "2d" );

                var _data = _ctx.getImageData( 0, 0, this.SizeNaturalW, this.SizeNaturalH );
                var _data2 = _ctx.getImageData( 0, 0, this.SizeNaturalW, this.SizeNaturalH );

                var _len = 4 * this.SizeNaturalW * this.SizeNaturalH;
                for ( var i = 0; i < _len; i += 4 ) {
                    if ( _data.data[i + 3] == 255 ) {
                        _data.data[i] = 255;// - _data.data[i];
                        _data.data[i + 1] = 255;// - _data.data[i + 1];
                        _data.data[i + 2] = 255;// - _data.data[i + 2];
                    }
                }

                _ctx.putImageData( _data, 0, 0 );
                ctx.drawImage( img, x + xDeltaIMG, y + yDeltaIMG, this.SizeW, this.SizeH );

                for ( var i = 0; i < _len; i += 4 ) {
                    if ( _data.data[i + 3] == 255 ) {
                        _data.data[i] = 255 - _data.data[i];
                        _data.data[i + 1] = 255 - _data.data[i + 1];
                        _data.data[i + 2] = 255 - _data.data[i + 2];
                    }
                }
                _ctx.putImageData( _data2, 0, 0 );

                _data = null;
                _data2 = null;
            }
            if ( this.IsDrawBorders ) {
                ctx.strokeStyle = this.ColorBorderActive;
                ctx.rect( x + xDeltaBORDER, y + yDeltaBORDER, strokeW, strokeH );
                ctx.stroke();
            }
            break;
        }
        default:{
            break;
        }
    }

    this.lastArrowStatus1 = mode;

};
CArrowDrawer.prototype.drawTopLeftArrow = function(type,mode,ctx,w,h){

    clearTimeout( this.fadeInTimeout1 );
    this.fadeInTimeout1 = null;
    clearTimeout( this.fadeOutTimeout1 );
    this.fadeOutTimeout1 = null;

    ctx.beginPath();

    var startColorFadeIn = this.startColorFadeInOutStart1.R < 0 ? _HEXTORGB_( this.ColorBackNone ) :  this.startColorFadeInOutStart1,
        startColorFadeOut = this.startColorFadeInOutStart1.R < 0 ? _HEXTORGB_( this.ColorBackOver ) : this.startColorFadeInOutStart1,
        that = this,
        img1 = this.ImageTop[mode],
        x1 = 0, y1 = 0,
        is_vertical = true,
        xDeltaIMG = 0, yDeltaIMG = 0, xDeltaBORDER = 0.5, yDeltaBORDER = 1.5,
        tempIMG1 = document.createElement( 'canvas' );

    tempIMG1.width = this.SizeNaturalW;
    tempIMG1.height = this.SizeNaturalH;

    var ctx1 = tempIMG1.getContext('2d');
    if (this.IsRetina)
    {
        ctx1.setTransform(2, 0, 0, 2, 0, 0);
    }

    function fadeIn(){

        var ctx_piperImg, px, _len;

        ctx1.fillStyle = "rgb(" + that.startColorFadeInOutStart1.R + "," +
                                  that.startColorFadeInOutStart1.G + "," +
                                  that.startColorFadeInOutStart1.B + ")";

        startColorFadeIn.R -= 2;
        startColorFadeIn.G -= 2;
        startColorFadeIn.B -= 2;

        ctx1.rect( 0.5, 1.5, strokeW, strokeH );
        ctx1.fill();

        if ( that.IsDrawBorders ) {
            ctx1.strokeStyle = that.ColorBorderOver;
            ctx1.stroke();
        }

        ctx_piperImg = img1.getContext( '2d' );
        _data = ctx_piperImg.getImageData( 0, 0, img1.width, img1.height );
        px = _data.data;

        _len = px.length;

        for ( var i = 0; i < _len; i += 4 ) {
            if ( px[i + 3] == 255 ) {
                px[i] += 4;
                px[i + 1] += 4;
                px[i + 2] += 4;
            }
        }
        ctx_piperImg.putImageData( _data, 0, 0 );

        ctx1.drawImage( img1, 0, 0, that.SizeW, that.SizeH );

        if ( startColorFadeIn.R >= 207 ) {
            that.startColorFadeInOutStart1 = startColorFadeIn;
            ctx.drawImage(tempIMG1,x1 + xDeltaIMG,y1 + yDeltaIMG, that.SizeW, that.SizeH);
            that.fadeInTimeout1 = setTimeout( fadeIn, that.fadeInFadeOutDelay );
        }
        else {
            clearTimeout( that.fadeInTimeout1 );
            that.fadeInTimeout1 = null;
            that.fadeInActive1 = false;
            startColorFadeIn.R += 2;
            startColorFadeIn.G += 2;
            startColorFadeIn.B += 2;
            that.startColorFadeInOutStart1 = startColorFadeIn;

            ctx_piperImg = img1.getContext( '2d' );
            _data = ctx_piperImg.getImageData( 0, 0, img1.width, img1.height );
            px = _data.data;

            _len = px.length;

            for ( var i = 0; i < _len; i += 4 ) {
                if ( px[i + 3] == 255 ) {
                    px[i] -= 4;
                    px[i + 1] -= 4;
                    px[i + 2] -= 4;
                }
            }
            ctx_piperImg.putImageData( _data, 0, 0 );
        }

    }

    function fadeOut(){

        var ctx_piperImg, px, _len;

        ctx1.fillStyle = "rgb(" + that.startColorFadeInOutStart1.R + "," +
                                  that.startColorFadeInOutStart1.G + "," +
                                  that.startColorFadeInOutStart1.B + ")";

        startColorFadeOut.R += 2;
        startColorFadeOut.G += 2;
        startColorFadeOut.B += 2;

        ctx1.rect( 0.5, 1.5, strokeW, strokeH  );
        ctx1.fill();

        if ( that.IsDrawBorders ) {
            ctx1.strokeStyle = that.ColorBorderOver;
            ctx1.stroke();
        }

        ctx_piperImg = img1.getContext( '2d' );
        _data = ctx_piperImg.getImageData( 0, 0, img1.width, img1.height );
        px = _data.data;

        _len = px.length;

        for ( var i = 0; i < _len; i += 4 ) {
            if ( px[i + 3] == 255 ) {
//                console.log("3 " + i + " " +  " " + px[i])
                px[i] -= 4;
                px[i + 1] -= 4;
                px[i + 2] -= 4;
            }
        }
        ctx_piperImg.putImageData( _data, 0, 0 );

        ctx1.drawImage( img1, 0, 0, that.SizeW, that.SizeH );

        if ( startColorFadeOut.R <= 241 ) {
            that.startColorFadeInOutStart1 = startColorFadeOut;
            ctx.drawImage(tempIMG1,x1 + xDeltaIMG,y1 + yDeltaIMG, that.SizeW, that.SizeH);
            that.fadeOutTimeout1 = setTimeout( fadeOut, that.fadeInFadeOutDelay );
        }
        else {
            clearTimeout( that.fadeOutTimeout1 );
            that.fadeOutTimeout1 = null;
            that.fadeOutActive1 = false;
            startColorFadeOut.R -= 2;
            startColorFadeOut.G -= 2;
            startColorFadeOut.B -= 2;
            that.startColorFadeInOutStart1 = startColorFadeOut;

            ctx_piperImg = img1.getContext( '2d' );
            _data = ctx_piperImg.getImageData( 0, 0, img1.width, img1.height );
            px = _data.data;

            _len = px.length;

            for ( var i = 0; i < _len; i += 4 ) {
                if ( px[i + 3] == 255 ) {
                    px[i] += 4;
                    px[i + 1] += 4;
                    px[i + 2] += 4;
                }
            }
            ctx_piperImg.putImageData( _data, 0, 0 );
        }

    }

    if ( mode === null || mode === undefined ) {
        mode = ScrollOverType.NONE;
    }

    switch ( type ) {
        case ScrollArrowType.ARROW_LEFT:
        {
            x1 = 1;
            y1 = -1;
            is_vertical = false;
            img1 = this.ImageLeft[mode];
            break;
        }
        default:
        {
            y1 = 0;
            img1 = this.ImageTop[mode];
            break;
        }
    }

    ctx.lineWidth = 1;
    var strokeW = is_vertical ? this.SizeW - 1 : this.SizeW - 1;
    var strokeH = is_vertical ? this.SizeH - 1 : this.SizeH - 1;

    switch ( mode ) {
        case ScrollOverType.NONE:
        {
            if ( this.lastArrowStatus1 == ScrollOverType.OVER ) {

                switch ( type ) {
                    case ScrollArrowType.ARROW_LEFT:
                    {
                        img1 = this.ImageLeft[ScrollOverType.STABLE];
                        break;
                    }
                    default:
                    {
                        img1 = this.ImageTop[ScrollOverType.STABLE];
                        break;
                    }
                }

                this.lastArrowStatus1 = mode;
                this.startColorFadeInOutStart1 = this.startColorFadeInOutStart1.R < 0 ? startColorFadeOut : this.startColorFadeInOutStart1;
                this.fadeOutActive1 = true;
                fadeOut();
            }
            else{

                if ( this.lastArrowStatus1 == ScrollOverType.ACTIVE ) {

                    var im, ctx_im, px, _data, c = this.ColorGradStart[ScrollOverType.STABLE];

                    switch ( type ) {
                        case ScrollArrowType.ARROW_LEFT:
                        {
                            im = this.ImageLeft[ScrollOverType.STABLE];
                            break;
                        }
                        default:
                        {
                            im = this.ImageTop[ScrollOverType.STABLE];
                            break;
                        }
                    }

                    ctx_im = im.getContext( '2d' );
                    _data = ctx_im.getImageData( 0, 0, img1.width, img1.height );
                    px = _data.data;

                    _len = px.length;

                    for ( var i = 0; i < _len; i += 4 ) {
                        if ( px[i + 3] == 255 ) {
                            px[i] = c.R;
                            px[i + 1] = c.G;
                            px[i + 2] = c.B;
                        }
                    }

                    this.startColorFadeInOutStart1 = {R:-1,G:-1,B:-1};

                    ctx_im.putImageData( _data, 0, 0 )

                }

                ctx.beginPath();
                ctx.fillStyle = this.ColorBackNone;
                ctx.fillRect( x1 + xDeltaBORDER >> 0, y1 + yDeltaBORDER >> 0, strokeW, strokeH );
                ctx.drawImage( img1, x1 + xDeltaIMG, y1 + yDeltaIMG, this.SizeW, this.SizeH );
                if ( this.IsDrawBorders ) {
                    ctx.strokeStyle = this.ColorBorderNone;
                    ctx.rect( x1 + xDeltaBORDER, y1 + yDeltaBORDER, strokeW, strokeH );
                    ctx.stroke();
                }
            }
            break;
        }
        case ScrollOverType.STABLE:
        {
            if ( this.lastArrowStatus1 == ScrollOverType.OVER ) {

                switch ( type ) {
                    case ScrollArrowType.ARROW_LEFT:
                    {
                        img1 = this.ImageLeft[ScrollOverType.STABLE];
                        break;
                    }
                    default:
                    {
                        img1 = this.ImageTop[ScrollOverType.STABLE];
                        break;
                    }
                }

                this.lastArrowStatus1 = mode;
                this.startColorFadeInOutStart1 = this.startColorFadeInOutStart1.R < 0 ? startColorFadeOut : this.startColorFadeInOutStart1;
                this.fadeOutActive1 = true;
                fadeOut();
            }
            else{

                if ( this.lastArrowStatus1 != ScrollOverType.STABLE ) {

                    var im, ctx_im, px, _data, c = this.ColorGradStart[ScrollOverType.STABLE];

                    switch ( type ) {
                        case ScrollArrowType.ARROW_LEFT:
                        {
                            im = this.ImageLeft[ScrollOverType.STABLE];
                            break;
                        }
                        default:
                        {
                            im = this.ImageTop[ScrollOverType.STABLE];
                            break;
                        }
                    }

                    ctx_im = im.getContext( '2d' );
                    _data = ctx_im.getImageData( 0, 0, img1.width, img1.height );
                    px = _data.data;

                    _len = px.length;

                    for ( var i = 0; i < _len; i += 4 ) {
                        if ( px[i + 3] == 255 ) {
                            px[i] = c.R;
                            px[i + 1] = c.G;
                            px[i + 2] = c.B;
                        }
                    }

                    this.startColorFadeInOutStart1 = {R:-1,G:-1,B:-1};

                    ctx_im.putImageData( _data, 0, 0 )

                }

                ctx.beginPath();
                ctx.fillStyle = this.ColorBackStable;
                ctx.fillRect( x1 + xDeltaBORDER >> 0, y1 + yDeltaBORDER >> 0, strokeW, strokeH );
                ctx.drawImage( img1, x1 + xDeltaIMG, y1 + yDeltaIMG, this.SizeW, this.SizeH );
                if ( this.IsDrawBorders ) {
                    ctx.strokeStyle = this.ColorBorderStable;
                    ctx.rect( x1 + xDeltaBORDER, y1 + yDeltaBORDER, strokeW, strokeH );
                    ctx.stroke();
                }
            }
            break;
        }
        case ScrollOverType.OVER:
        {
            if ( this.lastArrowStatus1 == ScrollOverType.NONE || this.lastArrowStatus1 == ScrollOverType.STABLE ) {

                switch ( type ) {
                    case ScrollArrowType.ARROW_LEFT:
                    {
                        img1 = this.ImageLeft[ScrollOverType.STABLE];
                        break;
                    }
                    default:
                    {
                        img1 = this.ImageTop[ScrollOverType.STABLE];
                        break;
                    }
                }

                this.lastArrowStatus1 = mode;
                this.startColorFadeInOutStart1 = this.startColorFadeInOutStart1.R < 0 ? startColorFadeIn : this.startColorFadeInOutStart1;
                this.fadeInActive1 = true;
                fadeIn();
            }
            else{
                ctx.beginPath();
                ctx.fillStyle = this.ColorBackOver;
                ctx.fillRect( x1 + xDeltaBORDER >> 0, y1 + yDeltaBORDER >> 0, strokeW, strokeH );
                ctx.drawImage( img1, x1 + xDeltaIMG, y1 + yDeltaIMG, this.SizeW, this.SizeH );
                if ( this.IsDrawBorders ) {
                    ctx.strokeStyle = this.ColorBorderOver;
                    ctx.rect( x1 + xDeltaBORDER, y1 + yDeltaBORDER, strokeW, strokeH );
                    ctx.stroke();
                }
            }
            break;
        }
        case ScrollOverType.ACTIVE:
        {
            ctx.beginPath();
            ctx.fillStyle = this.ColorBackActive;
			ctx.fillRect( x1 + xDeltaBORDER >> 0, y1 + yDeltaBORDER >> 0, strokeW, strokeH );

            if ( !this.IsNeedInvertOnActive ) {
                ctx.drawImage( img1, x1 + xDeltaIMG, y1 + yDeltaIMG, this.SizeW, this.SizeH );
            }
            else {
                // slow method
                var _ctx = img1.getContext( "2d" );

                var _data = _ctx.getImageData( 0, 0, this.SizeW, this.SizeH );
                var _data2 = _ctx.getImageData( 0, 0, this.SizeW, this.SizeH );

                var _len = 4 * this.SizeW * this.SizeH;
                for ( var i = 0; i < _len; i += 4 ) {
                    if ( _data.data[i + 3] == 255 ) {
                        _data.data[i] = 255;// - _data.data[i];
                        _data.data[i + 1] = 255;// - _data.data[i + 1];
                        _data.data[i + 2] = 255;// - _data.data[i + 2];
                    }
                }

                _ctx.putImageData( _data, 0, 0 );
                ctx.drawImage( img1, x1 + xDeltaIMG, y1 + yDeltaIMG, this.SizeW, this.SizeH );

                for ( var i = 0; i < _len; i += 4 ) {
                    if ( _data.data[i + 3] == 255 ) {
                        _data.data[i] = 255 - _data.data[i];
                        _data.data[i + 1] = 255 - _data.data[i + 1];
                        _data.data[i + 2] = 255 - _data.data[i + 2];
                    }
                }
                _ctx.putImageData( _data2, 0, 0 );

                _data = null;
                _data2 = null;
            }
            if ( this.IsDrawBorders ) {
                ctx.strokeStyle = this.ColorBorderActive;
                ctx.rect( x1 + xDeltaBORDER, y1 + yDeltaBORDER, strokeW, strokeH );
                ctx.stroke();
            }
            break;
        }
        default:{
            break;
        }
    }

    this.lastArrowStatus1 = mode;

};
CArrowDrawer.prototype.drawBottomRightArrow = function(type,mode,ctx,w,h){

    clearTimeout( this.fadeInTimeout2 );
    this.fadeInTimeout2 = null;
    clearTimeout( this.fadeOutTimeout2 );
    this.fadeOutTimeout2 = null;

    ctx.beginPath();

    var startColorFadeIn = this.startColorFadeInOutStart2.R < 0 ? _HEXTORGB_( this.ColorBackNone ) :  this.startColorFadeInOutStart2,
        startColorFadeOut =  this.startColorFadeInOutStart2.R < 0 ? _HEXTORGB_( this.ColorBackOver ) : this.startColorFadeInOutStart2,
        that = this,
        img1 = this.ImageTop[mode],
        x1 = 0, y1 = 0,
        is_vertical = true,
        bottomRightDelta = 1,
        xDeltaIMG = 0, yDeltaIMG = 0, xDeltaBORDER = 0.5, yDeltaBORDER = 1.5,
        tempIMG1 = document.createElement( 'canvas' );

    tempIMG1.width = this.SizeNaturalW;
    tempIMG1.height = this.SizeNaturalH;

    var ctx1 = tempIMG1.getContext('2d');

    if (this.IsRetina)
    {
        ctx1.setTransform(2, 0, 0, 2, 0, 0);
    }

    function fadeIn(){

        var ctx_piperImg, px, _len;

        ctx1.fillStyle = "rgb(" + that.startColorFadeInOutStart2.R + "," +
                                  that.startColorFadeInOutStart2.G + "," +
                                  that.startColorFadeInOutStart2.B + ")";

        startColorFadeIn.R -= 2;
        startColorFadeIn.G -= 2;
        startColorFadeIn.B -= 2;

        ctx1.rect( .5, 1.5, strokeW, strokeH );
        ctx1.fill();

        if ( that.IsDrawBorders ) {
            ctx1.strokeStyle = that.ColorBorderOver;
            ctx1.stroke();
        }

        ctx_piperImg = img1.getContext( '2d' );
        _data = ctx_piperImg.getImageData( 0, 0, img1.width, img1.height );
        px = _data.data;

        _len = px.length;

        for ( var i = 0; i < _len; i += 4 ) {
            if ( px[i + 3] == 255 ) {
                px[i] += 4;
                px[i + 1] += 4;
                px[i + 2] += 4;
            }
        }
        ctx_piperImg.putImageData( _data, 0, 0 );

        ctx1.drawImage( img1, 0, 0, that.SizeW, that.SizeH );

        if ( startColorFadeIn.R >= 207 ) {
            that.startColorFadeInOutStart2 = startColorFadeIn;
            ctx.drawImage(tempIMG1,x1 + xDeltaIMG,y1 + yDeltaIMG, that.SizeW, that.SizeH);
            that.fadeInTimeout2 = setTimeout( fadeIn, that.fadeInFadeOutDelay );
        }
        else {
            clearTimeout( that.fadeInTimeout2 );
            that.fadeInTimeout2 = null;
            that.fadeInActive2 = false;
            startColorFadeIn.R += 2;
            startColorFadeIn.G += 2;
            startColorFadeIn.B += 2;
            that.startColorFadeInOutStart2 = startColorFadeIn;

            ctx_piperImg = img1.getContext( '2d' );
            _data = ctx_piperImg.getImageData( 0, 0, img1.width, img1.height );
            px = _data.data;

            _len = px.length;

            for ( var i = 0; i < _len; i += 4 ) {
                if ( px[i + 3] == 255 ) {
                    px[i] -= 4;
                    px[i + 1] -= 4;
                    px[i + 2] -= 4;
                }
            }
            ctx_piperImg.putImageData( _data, 0, 0 );

        }

    }

    function fadeOut(){

        var ctx_piperImg, px, _len;

        ctx1.fillStyle = "rgb(" + that.startColorFadeInOutStart2.R + "," +
                                  that.startColorFadeInOutStart2.G + "," +
                                  that.startColorFadeInOutStart2.B + ")";

        startColorFadeOut.R += 2;
        startColorFadeOut.G += 2;
        startColorFadeOut.B += 2;

        ctx1.rect( .5, 1.5, strokeW, strokeH  );
        ctx1.fill();

        if ( that.IsDrawBorders ) {
            ctx1.strokeStyle = that.ColorBorderOver;
            ctx1.stroke();
        }

        ctx_piperImg = img1.getContext( '2d' );
        _data = ctx_piperImg.getImageData( 0, 0, img1.width, img1.height );
        px = _data.data;
        _len = px.length;

        for ( var i = 0; i < _len; i += 4 ) {
            if ( px[i + 3] == 255 ) {
                px[i] -= 4;
                px[i + 1] -= 4;
                px[i + 2] -= 4;
            }
        }

        ctx_piperImg.putImageData( _data, 0, 0 );

        ctx1.drawImage( img1, 0, 0, that.SizeW, that.SizeH );

        if ( startColorFadeOut.R <= 241 ) {
            that.startColorFadeInOutStart2 = startColorFadeOut;
            ctx.drawImage(tempIMG1,x1 + xDeltaIMG,y1 + yDeltaIMG, that.SizeW, that.SizeH);
            that.fadeOutTimeout2 = setTimeout( fadeOut, that.fadeInFadeOutDelay );
        }
        else {
            clearTimeout( that.fadeOutTimeout2 );
            that.fadeOutTimeout2 = null;
            that.fadeOutActive2 = false;
            startColorFadeOut.R -= 2;
            startColorFadeOut.G -= 2;
            startColorFadeOut.B -= 2;
            that.startColorFadeInOutStart2 = startColorFadeOut;

            ctx_piperImg = img1.getContext( '2d' );
            _data = ctx_piperImg.getImageData( 0, 0, img1.width, img1.height );
            px = _data.data;

            _len = px.length;

            for ( var i = 0; i < _len; i += 4 ) {
                if ( px[i + 3] == 255 ) {
                    px[i] += 4;
                    px[i + 1] += 4;
                    px[i + 2] += 4;
                }
            }
            ctx_piperImg.putImageData( _data, 0, 0 );

        }

    }

    if ( mode === null || mode === undefined ) {
        mode = ScrollOverType.NONE;
    }

    switch ( type ) {
        case ScrollArrowType.ARROW_RIGHT:
        {
            is_vertical = false;
            x1 = w - this.SizeW - bottomRightDelta;
            y1 = -1;
            img1 = this.ImageRight[mode];

            break;
        }
        case ScrollArrowType.ARROW_BOTTOM:
        {
            y1 = h - this.SizeH - bottomRightDelta - 1;
            img1 = this.ImageBottom[mode];

            break;
        }
    }

    ctx.lineWidth = 1;
    var strokeW = is_vertical ? this.SizeW - 1 : this.SizeW - 1;
    var strokeH = is_vertical ? this.SizeH - 1 : this.SizeH - 1;

    switch ( mode ) {
        case ScrollOverType.NONE:
        {
            if ( this.lastArrowStatus2 == ScrollOverType.OVER ) {

                switch ( type ) {
                    case ScrollArrowType.ARROW_RIGHT:
                    {
                        img1 = this.ImageRight[ScrollOverType.STABLE];
                        break;
                    }
                    default:
                    {
                        img1 = this.ImageBottom[ScrollOverType.STABLE];
                        break;
                    }
                }

                this.lastArrowStatus2 = mode;
                this.startColorFadeInOutStart2 = this.startColorFadeInOutStart2.R < 0 ? startColorFadeOut : this.startColorFadeInOutStart2;
                this.fadeOutActive2 = true;
                fadeOut();
            }
            else{

                if ( this.lastArrowStatus2 == ScrollOverType.ACTIVE ) {

                    var im, ctx_im, px, _data, c = this.ColorGradStart[ScrollOverType.STABLE];

                    switch ( type ) {
                        case ScrollArrowType.ARROW_RIGHT:
                        {
                            im = this.ImageRight[ScrollOverType.STABLE];
                            break;
                        }
                        default:
                        {
                            im = this.ImageBottom[ScrollOverType.STABLE];
                            break;
                        }
                    }

                    ctx_im = im.getContext( '2d' );
                    _data = ctx_im.getImageData( 0, 0, img1.width, img1.height );
                    px = _data.data;

                    _len = px.length;

                    for ( var i = 0; i < _len; i += 4 ) {
                        if ( px[i + 3] == 255 ) {
                            px[i] = c.R;
                            px[i + 1] = c.G;
                            px[i + 2] = c.B;
                        }
                    }

                    this.startColorFadeInOutStart2 = {R:-1,G:-1,B:-1};

                    ctx_im.putImageData( _data, 0, 0 )

                }

                ctx.beginPath();
                ctx.fillStyle = this.ColorBackNone;
                ctx.fillRect( x1 + xDeltaBORDER >> 0, y1 + yDeltaBORDER >> 0, strokeW, strokeH );
                ctx.drawImage( img1, x1 + xDeltaIMG, y1 + yDeltaIMG, this.SizeW, this.SizeH );
                if ( this.IsDrawBorders ) {
                    ctx.strokeStyle = this.ColorBorderNone;
                    ctx.rect( x1 + xDeltaBORDER, y1 + yDeltaBORDER, strokeW, strokeH );
                    ctx.stroke();
                }
            }
            break;
        }
        case ScrollOverType.STABLE:
        {
            if ( this.lastArrowStatus2 == ScrollOverType.OVER ) {

                switch ( type ) {
                    case ScrollArrowType.ARROW_RIGHT:
                    {
                        img1 = this.ImageRight[ScrollOverType.STABLE];
                        break;
                    }
                    default:
                    {
                        img1 = this.ImageBottom[ScrollOverType.STABLE];
                        break;
                    }
                }

                this.lastArrowStatus2 = mode;
                this.startColorFadeInOutStart2 = this.startColorFadeInOutStart2.R < 0 ? startColorFadeOut : this.startColorFadeInOutStart2;
                this.fadeOutActive2 = true;
                fadeOut();
            }
            else{

                if ( this.lastArrowStatus2 != ScrollOverType.STABLE ) {

                    var im, ctx_im, px, _data, c = this.ColorGradStart[ScrollOverType.STABLE];

                    switch ( type ) {
                        case ScrollArrowType.ARROW_RIGHT:
                        {
                            im = this.ImageRight[ScrollOverType.STABLE];
                            break;
                        }
                        default:
                        {
                            im = this.ImageBottom[ScrollOverType.STABLE];
                            break;
                        }
                    }

                    ctx_im = im.getContext( '2d' );
                    _data = ctx_im.getImageData( 0, 0, img1.width, img1.height );
                    px = _data.data;

                    _len = px.length;

                    for ( var i = 0; i < _len; i += 4 ) {
                        if ( px[i + 3] == 255 ) {
                            px[i] = c.R;
                            px[i + 1] = c.G;
                            px[i + 2] = c.B;
                        }
                    }

                    this.startColorFadeInOutStart2 = {R:-1,G:-1,B:-1};

                    ctx_im.putImageData( _data, 0, 0 )

                }

                ctx.beginPath();
                ctx.fillStyle = this.ColorBackStable;
				ctx.fillRect( x1 + xDeltaBORDER >> 0, y1 + yDeltaBORDER >> 0, strokeW, strokeH );
                ctx.drawImage( img1, x1 + xDeltaIMG, y1 + yDeltaIMG, this.SizeW, this.SizeH );
                ctx.strokeStyle = this.ColorBackStable;
                if ( this.IsDrawBorders ) {
                    ctx.strokeStyle = this.ColorBorderStable;
                    ctx.rect( x1 + xDeltaBORDER, y1 + yDeltaBORDER, strokeW, strokeH );
                    ctx.stroke();
                }
            }
            break;
        }
        case ScrollOverType.OVER:
        {

            if ( this.lastArrowStatus2 == ScrollOverType.NONE || this.lastArrowStatus2 == ScrollOverType.STABLE ) {

                switch ( type ) {
                    case ScrollArrowType.ARROW_RIGHT:
                    {
                        img1 = this.ImageRight[ScrollOverType.STABLE];
                        break;
                    }
                    default:
                    {
                        img1 = this.ImageBottom[ScrollOverType.STABLE];
                        break;
                    }
                }

                this.lastArrowStatus2 = mode;
                this.startColorFadeInOutStart2 = this.startColorFadeInOutStart2.R < 0 ? startColorFadeIn : this.startColorFadeInOutStart2;
                this.fadeInActive2 = true;
                fadeIn();
            }
            else{
                ctx.beginPath();
                ctx.fillStyle = this.ColorBackOver;
				ctx.fillRect( x1 + xDeltaBORDER >> 0, y1 + yDeltaBORDER >> 0, strokeW, strokeH );
                ctx.drawImage( img1, x1 + xDeltaIMG, y1 + yDeltaIMG, this.SizeW, this.SizeH );
                if ( this.IsDrawBorders ) {
                    ctx.strokeStyle = this.ColorBorderOver;
                    ctx.rect( x1 + xDeltaBORDER, y1 + yDeltaBORDER, strokeW, strokeH );
                    ctx.stroke();
                }

            }
            break;
        }
        case ScrollOverType.ACTIVE:
        {
            ctx.beginPath();
            ctx.fillStyle = this.ColorBackActive;
			ctx.fillRect( x1 + xDeltaBORDER >> 0, y1 + yDeltaBORDER >> 0, strokeW, strokeH );

            if ( !this.IsNeedInvertOnActive ) {
                ctx.drawImage( img1, x1 + xDeltaIMG, y1 + yDeltaIMG, this.SizeW, this.SizeH );
            }
            else {
                // slow method
                var _ctx = img1.getContext( "2d" );

                var _data = _ctx.getImageData( 0, 0, this.SizeW, this.SizeH );
                var _data2 = _ctx.getImageData( 0, 0, this.SizeW, this.SizeH );

                var _len = 4 * this.SizeW * this.SizeH;
                for ( var i = 0; i < _len; i += 4 ) {
                    if ( _data.data[i + 3] == 255 ) {
                        _data.data[i] = 255;// - _data.data[i];
                        _data.data[i + 1] = 255;// - _data.data[i + 1];
                        _data.data[i + 2] = 255;// - _data.data[i + 2];
                    }
                }

                _ctx.putImageData( _data, 0, 0 );
                ctx.drawImage( img1, x1 + xDeltaIMG, y1 + yDeltaIMG, this.SizeW, this.SizeH );

                for ( var i = 0; i < _len; i += 4 ) {
                    if ( _data.data[i + 3] == 255 ) {
                        _data.data[i] = 255 - _data.data[i];
                        _data.data[i + 1] = 255 - _data.data[i + 1];
                        _data.data[i + 2] = 255 - _data.data[i + 2];
                    }
                }
                _ctx.putImageData( _data2, 0, 0 );

                _data = null;
                _data2 = null;
            }
            if ( this.IsDrawBorders ) {
                ctx.strokeStyle = this.ColorBorderActive;
                ctx.rect( x1 + xDeltaBORDER, y1 + yDeltaBORDER, strokeW, strokeH );
                ctx.stroke();
            }
            break;
        }
        default:{
            break;
        }
    }

    this.lastArrowStatus2 = mode;
};

function _HEXTORGB_( colorHEX ) {
    return {
        R:parseInt( colorHEX.substring( 1, 3 ), 16 ),
        G:parseInt( colorHEX.substring( 3, 5 ), 16 ),
        B:parseInt( colorHEX.substring( 5, 7 ), 16 )
    }
}

	/**
	 * @constructor
	 */
	function ScrollSettings() {
		this.showArrows = true;
		this.screenW = -1;
		this.screenH = -1;
		this.screenAddH = 0;
		this.contentH = undefined;
		this.contentW = undefined;
		this.scrollerMinHeight = 34;
		this.scrollerMaxHeight = 99999;
		this.scrollerMinWidth = 34;
		this.scrollerMaxWidth = 99999;
		this.initialDelay = 300;
		this.arrowRepeatFreq = 50;
		this.trackClickRepeatFreq = 70;
		this.scrollPagePercent = 1. / 8;
		this.arrowDim = 13;
		this.marginScroller = 4;
		this.scrollerColor = "#f1f1f1";
		this.scrollerColorOver = "#cfcfcf";
		this.scrollerColorLayerOver = "#cfcfcf";
		this.scrollerColorActive = "#ADADAD";
		this.scrollBackgroundColor = "#f4f4f4";
		this.scrollBackgroundColorHover = "#f4f4f4";
		this.scrollBackgroundColorActive = "#f4f4f4";
		this.strokeStyleNone = "#cfcfcf";
		this.strokeStyleOver = "#cfcfcf";
		this.strokeStyleActive = "#ADADAD";
		this.vscrollStep = 10;
		this.hscrollStep = 10;
		this.wheelScrollLines = 1;
		this.arrowColor = "#ADADAD";
		this.arrowBorderColor = "#cfcfcf";
		this.arrowBackgroundColor = "#F1F1F1";
		this.arrowStableColor = "#ADADAD";
		this.arrowStableBorderColor = "#cfcfcf";
		this.arrowStableBackgroundColor = "#F1F1F1";
		this.arrowOverColor = "#f1f1f1";
		this.arrowOverBorderColor = "#cfcfcf";
		this.arrowOverBackgroundColor = "#cfcfcf";
		this.arrowActiveColor = "#f1f1f1";
		this.arrowActiveBorderColor = "#ADADAD";
		this.arrowActiveBackgroundColor = "#ADADAD";
		this.fadeInFadeOutDelay = 20;
		this.piperColor = "#cfcfcf";
		this.piperColorHover = "#f1f1f1";
		this.arrowSizeW = 13;
		this.arrowSizeH = 13;
		this.cornerRadius = 0;
		this.slimScroll = false;
		this.alwaysVisible = false;
		this.isNeedInvertOnActive = false;
	}

	/**
	 * @constructor
	 */
	function ScrollObject( elemID, settings, dbg ) {
		if ( dbg )
			debug = dbg;
		this.that = this;

		this.settings = settings;
		this.ArrowDrawer = new CArrowDrawer( this.settings );

		this.mouseUp = false;
		this.mouseDown = false;

		this.that.mouseover = false;

		this.that.mouseOverOut = -1;

		this.scrollerMouseDown = false;
		this.scrollerStatus = ScrollOverType.NONE;
		this.lastScrollerStatus = this.scrollerStatus;

		this.moveble = false;
		this.lock = false;
		this.scrollTimeout = null;

		this.StartMousePosition = {x:0, y:0};
		this.EndMousePosition = {x:0, y:0};

		this.dragMinY = 0;
		this.dragMaxY = 0;

		this.scrollVCurrentY = 0;
		this.scrollHCurrentX = 0;
		this.arrowPosition = 0;

		this.verticalTrackHeight = 0;
		this.horizontalTrackWidth = 0;

		this.paneHeight = 0;
		this.paneWidth = 0;

		this.maxScrollY = 0;
		this.maxScrollX = 0;
		this.maxScrollY2 = 0;
		this.maxScrollX2 = 0;

		this.scrollCoeff = 0;

		this.scroller = {x:0, y:1, h:0, w:0};

		this.canvas = null;
		this.context = null;

		this.eventListeners = [];

		this.IsRetina = false;
		this.canvasW = 1;
		this.canvasH = 1;

		this.ScrollOverType1 = -1;
		this.ScrollOverType2 = -1;

		this.fadeInActive = false;
		this.fadeOutActive = false;
		this.fadeInTimeout = null;
		this.fadeOutTimeout = null;
		this.startColorFadeInStart = _HEXTORGB_(this.settings.scrollerColor).R;
		this.startColorFadeOutStart = _HEXTORGB_(this.settings.scrollerColorOver).R;
		this.startColorFadeInOutStart = -1;

		this.IsRetina = AscBrowser.isRetina;

		this.piperImgVert = [document.createElement( 'canvas' ), document.createElement( 'canvas' )];
		this.piperImgHor = [document.createElement( 'canvas' ), document.createElement( 'canvas' )];

		this.piperImgVert[0].height = 13;
		this.piperImgVert[1].height = 13;
		this.piperImgVert[0].width = 5;
		this.piperImgVert[1].width = 5;

		this.piperImgHor[0].width = 13;
		this.piperImgHor[1].width = 13;
		this.piperImgHor[0].height = 5;
		this.piperImgHor[1].height = 5;

		if(this.settings.slimScroll){
			this.piperImgVert[0].width =
				this.piperImgVert[1].width =
					this.piperImgHor[0].height =
						this.piperImgHor[1].height = 3;
		}

		var r, g, b, ctx_piperImg, _data, px, k;
		r = _HEXTORGB_( this.settings.piperColor );
		g = r.G;
		b = r.B;
		r = r.R;

		k = this.piperImgVert[0].width * 4;

		for ( var index = 0; index < this.piperImgVert.length; index++ ) {
			ctx_piperImg = this.piperImgVert[index].getContext( '2d' );
			_data = ctx_piperImg.createImageData( this.piperImgVert[index].width, this.piperImgVert[index].height );
			px = _data.data;

			for ( var i = 0; i < this.piperImgVert[index].width * this.piperImgVert[index].height * 4; ) {
				px[i++] = r;
				px[i++] = g;
				px[i++] = b;
				px[i++] = 255;
				i = ( i % k === 0 ) ? i + k : i
			}

			ctx_piperImg.putImageData( _data, 0, 0 );

			ctx_piperImg = this.piperImgHor[index].getContext( '2d' );

			_data = ctx_piperImg.createImageData( this.piperImgHor[index].width, this.piperImgHor[index].height );
			px = _data.data;

			for ( var i = 0; i < this.piperImgHor[index].width * this.piperImgHor[index].height * 4; ) {
				px[i++] = r;
				px[i++] = g;
				px[i++] = b;
				px[i++] = 255;
				i = ( i % 4 === 0 && i % 52 !== 0 ) ? i + 4 : i
			}

			ctx_piperImg.putImageData( _data, 0, 0 )

			r = _HEXTORGB_( this.settings.piperColorHover );
			g = r.G;
			b = r.B;
			r = r.R;

		}

		this._init( elemID );
	}

	ScrollObject.prototype._init = function ( elemID ) {
		if ( !elemID ) return false;

		var holder = document.getElementById( elemID );

		if ( holder.getElementsByTagName( 'canvas' ).length == 0 ){
			this.canvas = holder.appendChild( document.createElement( "CANVAS" ) );
		}
		else {
			this.canvas = holder.children[1];
		}

		this.canvas.style.width = "100%";
		this.canvas.style.height = "100%";

		this.canvas.that = this;
		this.canvas.style.zIndex = 100;
		this.canvas.style.position = "absolute";
		this.canvas.style.top = "0px";
		this.canvas.style["msTouchAction"] = "none";
		if ( navigator.userAgent.toLowerCase().indexOf( "webkit" ) != -1 ){
			this.canvas.style.webkitUserSelect = "none";
		}

		this.context = this.canvas.getContext( '2d' );
		if ( !this.IsRetina ){
			this.context.setTransform( 1, 0, 0, 1, 0, 0 );
		}
		else{
			this.context.setTransform( 2, 0, 0, 2, 0, 0 );
		}

		if ( this.settings.showArrows ){
			this.arrowPosition = this.settings.arrowDim + 2;
		}
		else{
			this.arrowPosition = this.settings.marginScroller;
		}

		this._setDimension( holder.clientHeight, holder.clientWidth );
		this.maxScrollY = this.maxScrollY2 = holder.firstElementChild.clientHeight - this.settings.screenH > 0 ? holder.firstElementChild.clientHeight - this.settings.screenH : 0;
		this.maxScrollX = this.maxScrollX2 = holder.firstElementChild.clientWidth - this.settings.screenW > 0 ? holder.firstElementChild.clientWidth - this.settings.screenW : 0;

		this.isVerticalScroll = holder.firstElementChild.clientHeight / Math.max( this.canvasH, 1 ) > 1;
		this.isHorizontalScroll = holder.firstElementChild.clientWidth / Math.max( this.canvasW, 1 ) > 1;

		this._setScrollerHW();

		this.paneHeight = this.canvasH - this.arrowPosition * 2;
		this.paneWidth = this.canvasW - this.arrowPosition * 2;

		this.RecalcScroller();

		this.canvas.onmousemove = this.evt_mousemove;
		this.canvas.onmouseout = this.evt_mouseout;
		this.canvas.onmouseup = this.evt_mouseup;
		this.canvas.onmousedown = this.evt_mousedown;
		this.canvas.onmousewheel = this.evt_mousewheel;
		this.canvas.onmouseover = this.evt_mouseover;

		var _that = this;
		this.canvas.ontouchstart = function ( e ) {
			_that.evt_mousedown( e.touches[0] );
			return false;
		};
		this.canvas.ontouchmove = function ( e ) {
			_that.evt_mousemove( e.touches[0] );
			return false;
		};
		this.canvas.ontouchend = function ( e ) {
			_that.evt_mouseup( e.changedTouches[0] );
			return false;
		};

		if ( this.canvas.addEventListener ){
			this.canvas.addEventListener( 'DOMMouseScroll', this.evt_mousewheel, false );
		}

		this.context.fillStyle = this.settings.scrollBackgroundColor;
		this.context.fillRect(0,0,this.canvasW,this.canvasH);

		this._drawArrow();
		this._draw();

		return true;
	};
	ScrollObject.prototype.getMousePosition = function ( evt ) {
		// get canvas position
		var obj = this.canvas;
		var top = 0;
		var left = 0;
		while ( obj && obj.tagName != 'BODY' ) {
			top += obj.offsetTop;
			left += obj.offsetLeft;
			obj = obj.offsetParent;
		}

		// return relative mouse position
		var mouseX = ((evt.clientX * AscBrowser.zoom) >> 0) - left + window.pageXOffset;
		var mouseY = ((evt.clientY * AscBrowser.zoom) >> 0) - top + window.pageYOffset;

		return {
			x:mouseX,
			y:mouseY
		};
	};
	ScrollObject.prototype.RecalcScroller = function ( startpos ) {
		if ( this.isVerticalScroll ) {
			if ( this.settings.showArrows ) {
				this.verticalTrackHeight = this.canvasH - this.arrowPosition * 2;
				this.scroller.y = this.arrowPosition;
			}
			else {
				this.verticalTrackHeight = this.canvasH;
				this.scroller.y = 1;
			}
			var percentInViewV;

			percentInViewV = (this.maxScrollY + this.paneHeight ) / this.paneHeight;
			this.scroller.h = Math.ceil( 1 / percentInViewV * this.verticalTrackHeight );

			if ( this.scroller.h < this.settings.scrollerMinHeight )
				this.scroller.h = this.settings.scrollerMinHeight;
			else if ( this.scroller.h > this.settings.scrollerMaxHeight )
				this.scroller.h = this.settings.scrollerMaxHeight;
			this.scrollCoeff = this.maxScrollY / Math.max( 1, this.paneHeight - this.scroller.h );
			if ( startpos ) {
				this.scroller.y = startpos / this.scrollCoeff + this.arrowPosition;
			}
			this.dragMaxY = this.canvasH - this.arrowPosition - this.scroller.h + 1;
			this.dragMinY = this.arrowPosition;
		}

		if ( this.isHorizontalScroll ) {
			if ( this.settings.showArrows ) {
				this.horizontalTrackWidth = this.canvasW - this.arrowPosition * 2;
				this.scroller.x = this.arrowPosition + 1;
			}
			else {
				this.horizontalTrackWidth = this.canvasW;
				this.scroller.x = 1;
			}
			var percentInViewH;
			percentInViewH = ( this.maxScrollX + this.paneWidth ) / this.paneWidth;
			this.scroller.w = Math.ceil( 1 / percentInViewH * this.horizontalTrackWidth );

			if ( this.scroller.w < this.settings.scrollerMinWidth )
				this.scroller.w = this.settings.scrollerMinWidth;
			else if ( this.scroller.w > this.settings.scrollerMaxWidth )
				this.scroller.w = this.settings.scrollerMaxWidth;
			this.scrollCoeff = this.maxScrollX / Math.max( 1, this.paneWidth - this.scroller.w );
			if ( typeof startpos !== "undefined" ) {
				this.scroller.x = startpos / this.scrollCoeff + this.arrowPosition;
			}
			this.dragMaxX = this.canvasW - this.arrowPosition - this.scroller.w;
			this.dragMinX = this.arrowPosition;
		}
	};
	ScrollObject.prototype.Repos = function ( settings, bIsHorAttack, bIsVerAttack ) {
		if (this.IsRetina != AscBrowser.isRetina)
		{
			this.IsRetina = AscBrowser.isRetina;
			this.ArrowDrawer.InitSize(this.settings.arrowSizeH, this.settings.arrowSizeW, this.IsRetina);
		}

		if (bIsVerAttack)
		{
			var _canvasH = settings.screenH;
			if (undefined !== _canvasH && settings.screenAddH)
				_canvasH += settings.screenAddH;

			if (_canvasH == this.canvasH && undefined !== settings.contentH)
			{
				var _maxScrollY = settings.contentH - settings.screenH > 0 ? settings.contentH - settings.screenH : 0;
				if (_maxScrollY == this.maxScrollY)
					return;
			}
		}
		if (bIsHorAttack)
		{
			if (settings.screenW == this.canvasW && undefined !== settings.contentW)
			{
				var _maxScrollX = settings.contentW - settings.screenW > 0 ? settings.contentW - settings.screenW : 0;
				if (_maxScrollX == this.maxScrollX)
					return;
			}
		}

		var _parentClientW = GetClientWidth( this.canvas.parentNode );
		var _parentClientH = GetClientHeight( this.canvas.parentNode );

		var _firstChildW = GetClientWidth( this.canvas.parentNode.firstElementChild );
		var _firstChildH = GetClientHeight( this.canvas.parentNode.firstElementChild );

		this._setDimension( _parentClientH, _parentClientW );
		this.maxScrollY = this.maxScrollY2 = _firstChildH - settings.screenH > 0 ? _firstChildH - settings.screenH : 0;
		this.maxScrollX = this.maxScrollX2 = _firstChildW - settings.screenW > 0 ? _firstChildW - settings.screenW : 0;

		this.isVerticalScroll = _firstChildH / Math.max( this.canvasH, 1 ) > 1 || this.isVerticalScroll || (true === bIsVerAttack);
		this.isHorizontalScroll = _firstChildW / Math.max( this.canvasW, 1 ) > 1 || this.isHorizontalScroll || (true === bIsHorAttack);
		this._setScrollerHW();

		this.paneHeight = this.canvasH - this.arrowPosition * 2;
		this.paneWidth = this.canvasW - this.arrowPosition * 2;
		this.RecalcScroller();
		if ( this.isVerticalScroll && !this.settings.alwaysVisible) {

			if (this.scrollVCurrentY > this.maxScrollY)
				this.scrollVCurrentY = this.maxScrollY;

			this.scrollToY( this.scrollVCurrentY );
			if(this.maxScrollY == 0){
				this.canvas.style.display = "none";
			}
			else{
				this.canvas.style.display = "";
			}
		}
		else if ( this.isHorizontalScroll ) {

			if (this.scrollHCurrentX > this.maxScrollX)
				this.scrollHCurrentX = this.maxScrollX;

			this.scrollToX( this.scrollHCurrentX );
			if(this.maxScrollX == 0 && !this.settings.alwaysVisible){
				this.canvas.style.display = "none";
			}
			else{
				this.canvas.style.display = "";
			}
		}

		this._drawArrow();
		this._draw();
	};
	ScrollObject.prototype.Reinit = function ( settings, pos ) {
	    var size;
		this._setDimension( this.canvas.parentNode.clientHeight, this.canvas.parentNode.clientWidth );

		size = this.canvas.parentNode.firstElementChild.clientHeight - (settings.screenH || this.canvas.parentNode.offsetHeight);
		this.maxScrollY = this.maxScrollY2 = 0 < size ? size : 0;

		size = this.canvas.parentNode.firstElementChild.clientWidth - (settings.screenH || this.canvas.parentNode.offsetWidth);
		this.maxScrollX = this.maxScrollX2 = 0 < size ? size : 0;

		this.isVerticalScroll = this.canvas.parentNode.firstElementChild.clientHeight / Math.max( this.canvasH, 1 ) > 1 || this.isVerticalScroll;
		this.isHorizontalScroll = this.canvas.parentNode.firstElementChild.clientWidth / Math.max( this.canvasW, 1 ) > 1 || this.isHorizontalScroll;
		this._setScrollerHW();

		this.paneHeight = this.canvasH - this.arrowPosition * 2;
		this.paneWidth = this.canvasW - this.arrowPosition * 2;
		this.RecalcScroller();
		this.reinit = true;
		if ( this.isVerticalScroll ) {
			pos !== undefined ? this.scrollByY( pos - this.scrollVCurrentY ) : this.scrollToY( this.scrollVCurrentY );
		}

		if ( this.isHorizontalScroll ) {
			pos !== undefined ? this.scrollByX( pos - this.scrollHCurrentX ) : this.scrollToX( this.scrollHCurrentX );
		}
		this.reinit = false;
		this._drawArrow();
		this._draw();
	};
	ScrollObject.prototype._scrollV = function ( that, evt, pos, isTop, isBottom, bIsAttack ) {
		if ( !this.isVerticalScroll ) {
			return;
		}

		if ( that.scrollVCurrentY !== pos || bIsAttack === true ) {
			that.scrollVCurrentY = pos;
			evt.scrollD = evt.scrollPositionY = that.scrollVCurrentY;
			evt.maxScrollY = that.maxScrollY;
			that._draw();
			that.handleEvents( "onscrollvertical", evt );
		}
		else if ( that.scrollVCurrentY === pos && pos > 0 && !this.reinit && !this.moveble && !this.lock ) {
			evt.pos = pos;
			that.handleEvents( "onscrollVEnd", evt );
		}
	};
	ScrollObject.prototype._correctScrollV = function ( that, yPos ) {
		if ( !this.isVerticalScroll )
			return null;

		var events = that.eventListeners["oncorrectVerticalScroll"];
		if ( events ) {
			if ( events.length != 1 )
				return null;

			return events[0].handler.apply( that, [yPos] );
		}
		return null;
	};
	ScrollObject.prototype._correctScrollByYDelta = function ( that, delta ) {
		if ( !this.isVerticalScroll )
			return null;

		var events = that.eventListeners["oncorrectVerticalScrollDelta"];
		if ( events ) {
			if ( events.length != 1 )
				return null;

			return events[0].handler.apply( that, [delta] );
		}
		return null;
	};
	ScrollObject.prototype._scrollH = function ( that, evt, pos, isTop, isBottom ) {
		if ( !this.isHorizontalScroll ) {
			return;
		}
		if ( that.scrollHCurrentX !== pos ) {
			that.scrollHCurrentX = pos;
			evt.scrollD = evt.scrollPositionX = that.scrollHCurrentX;
			evt.maxScrollX = that.maxScrollX;

//            that._drawArrow();
			that._draw();
			that.handleEvents( "onscrollhorizontal", evt );
		}
		else if ( that.scrollHCurrentX === pos && pos > 0 && !this.reinit && !this.moveble && !this.lock ) {
			evt.pos = pos;
			that.handleEvents( "onscrollHEnd", evt );
		}

	};
	ScrollObject.prototype.scrollByY = function ( delta, bIsAttack ) {
		if ( !this.isVerticalScroll ) {
			return;
		}

		var result = this._correctScrollByYDelta( this, delta );
		if ( result != null && result.isChange === true )
			delta = result.Pos;

		var destY = this.scrollVCurrentY + delta, isTop = false, isBottom = false, vend = false;

		if ( destY < 0 ) {
			destY = 0;
			isTop = true;
			isBottom = false;
		}
		else if ( destY > this.maxScrollY2 ) {
			this.handleEvents( "onscrollVEnd", destY - this.maxScrollY );
			vend = true;
			destY = this.maxScrollY2;
			isTop = false;
			isBottom = true;
		}

		this.scroller.y = destY / Math.max( 1, this.scrollCoeff ) + this.arrowPosition;
		if ( this.scroller.y < this.dragMinY )
			this.scroller.y = this.dragMinY + 1;
		else if ( this.scroller.y > this.dragMaxY )
			this.scroller.y = this.dragMaxY;

		var arrow = this.settings.showArrows ? this.arrowPosition : 0;
		if ( this.scroller.y + this.scroller.h > this.canvasH - arrow ) {
			this.scroller.y -= Math.abs( this.canvasH - arrow - this.scroller.y - this.scroller.h );
		}

		this.scroller.y = Math.round(this.scroller.y);

		if ( vend ) {
			this.moveble = true;
		}
		this._scrollV( this, {}, destY, isTop, isBottom, bIsAttack );
		if ( vend ) {
			this.moveble = false;
		}
	};
	ScrollObject.prototype.scrollToY = function ( destY ) {
		if ( !this.isVerticalScroll ) {
			return;
		}

		this.scroller.y = destY / Math.max( 1, this.scrollCoeff ) + this.arrowPosition;
		if ( this.scroller.y < this.dragMinY )
			this.scroller.y = this.dragMinY + 1;
		else if ( this.scroller.y > this.dragMaxY )
			this.scroller.y = this.dragMaxY;

		var arrow = this.settings.showArrows ? this.arrowPosition : 0;
		if ( this.scroller.y + this.scroller.h > this.canvasH - arrow ) {
			this.scroller.y -= Math.abs( this.canvasH - arrow - this.scroller.y - this.scroller.h );
		}

		this.scroller.y = Math.round(this.scroller.y);

		this._scrollV( this, {}, destY, false, false );
	};
	ScrollObject.prototype.scrollByX = function ( delta ) {
		if ( !this.isHorizontalScroll ) {
			return;
		}
		var destX = this.scrollHCurrentX + delta, isTop = false, isBottom = false, hend = false;

		if ( destX < 0 ) {
			destX = 0;
			isTop = true;
			isBottom = false;
		}
		else if ( destX > this.maxScrollX2 ) {
			this.handleEvents( "onscrollHEnd", destX - this.maxScrollX );
			hend = true;
			destX = this.maxScrollX2;
			isTop = false;
			isBottom = true;
		}

		this.scroller.x = destX / Math.max( 1, this.scrollCoeff ) + this.arrowPosition;
		if ( this.scroller.x < this.dragMinX )
			this.scroller.x = this.dragMinX + 1;
		else if ( this.scroller.x > this.dragMaxX )
			this.scroller.x = this.dragMaxX;

		var arrow = this.settings.showArrows ? this.arrowPosition : 0;
		if ( this.scroller.x + this.scroller.w > this.canvasW - arrow ) {
			this.scroller.x -= Math.abs( this.canvasW - arrow - this.scroller.x - this.scroller.w );
		}

		this.scroller.x = Math.round(this.scroller.x);

		if ( hend ) {
			this.moveble = true;
		}
		this._scrollH( this, {}, destX, isTop, isBottom );
		if ( hend ) {
			this.moveble = true;
		}
	};
	ScrollObject.prototype.scrollToX = function ( destX ) {
		if ( !this.isHorizontalScroll ) {
			return;
		}

		this.scroller.x = destX / Math.max( 1, this.scrollCoeff ) + this.arrowPosition;
		if ( this.scroller.x < this.dragMinX )
			this.scroller.x = this.dragMinX + 1;
		else if ( this.scroller.x > this.dragMaxX )
			this.scroller.x = this.dragMaxX;

		var arrow = this.settings.showArrows ? this.arrowPosition : 0;
		if ( this.scroller.x + this.scroller.w > this.canvasW - arrow ) {
			this.scroller.x -= Math.abs( this.canvasW - arrow - this.scroller.x - this.scroller.w );
		}

		this.scroller.x = Math.round(this.scroller.x);

		this._scrollH( this, {}, destX, false, false );
	};
	ScrollObject.prototype.scrollTo = function ( destX, destY ) {
		this.scrollToX( destX );
		this.scrollToY( destY );
	};
	ScrollObject.prototype.scrollBy = function ( deltaX, deltaY ) {
		this.scrollByX( deltaX );
		this.scrollByY( deltaY );
	};

	ScrollObject.prototype.roundRect = function ( x, y, width, height, radius ) {
		if ( typeof radius === "undefined" ) {
			radius = 1;
		}
		this.context.beginPath();
		this.context.moveTo( x + radius, y );
		this.context.lineTo( x + width - radius, y );
		this.context.quadraticCurveTo( x + width, y, x + width, y + radius );
		this.context.lineTo( x + width, y + height - radius );
		this.context.quadraticCurveTo( x + width, y + height, x + width - radius, y + height );
		this.context.lineTo( x + radius, y + height );
		this.context.quadraticCurveTo( x, y + height, x, y + height - radius );
		this.context.lineTo( x, y + radius );
		this.context.quadraticCurveTo( x, y, x + radius, y );
		this.context.closePath();
	};

	ScrollObject.prototype._clearContent = function () {
		this.context.clearRect( 0, 0, this.canvasW, this.canvasH );
	};
	ScrollObject.prototype._draw = function () {
		// очистку не нужно делать - если потом рисовать рект такой же
		//this._clearContent();
		var piperImgIndex = 0, that = this,
			startColorFadeIn = this.startColorFadeInOutStart < 0 ? this.startColorFadeInStart : this.startColorFadeInOutStart,
			startColorFadeOut = this.startColorFadeInOutStart < 0 ? this.startColorFadeOutStart : this.startColorFadeInOutStart;

		function fadeIn() {

			clearTimeout( that.fadeInTimeout );
			that.fadeInTimeout = null;
			clearTimeout( that.fadeOutTimeout );
			that.fadeOutTimeout = null;

			var x, y, img, ctx_piperImg, _data, px;

			that.context.beginPath();

			drawScroller();

			that.context.fillStyle = "rgb(" + that.startColorFadeInOutStart + "," + that.startColorFadeInOutStart + "," + that.startColorFadeInOutStart + ")";
			that.context.strokeStyle = that.settings.strokeStyleOver;

			that.context.fill();
			that.context.stroke();

			startColorFadeIn -= 2;

			if ( that._checkPiperImagesV() ) {
				x = that.scroller.x + (that.settings.slimScroll ? 2 : 3);
				y = (that.scroller.y >> 0) + Math.floor( that.scroller.h / 2 ) - 6;

				ctx_piperImg = that.piperImgVert[0].getContext( '2d' );
				_data = ctx_piperImg.getImageData( 0, 0, that.piperImgVert[0].width, that.piperImgVert[0].height );
				px = _data.data;

				for ( var i = 0; i < that.piperImgVert[0].width * that.piperImgVert[0].height * 4; i += 4 ) {
					if ( px[i + 3] == 255 ) {
						px[i] += 2;
						px[i + 1] += 2;
						px[i + 2] += 2;
					}
				}

				ctx_piperImg.putImageData( _data, 0, 0 );

				img = that.piperImgVert[0];
			}
			else if ( that._checkPiperImagesH() ) {
				x = (that.scroller.x >> 0) + Math.floor( that.scroller.w / 2 ) - 6;
				y = that.scroller.y + (that.settings.slimScroll ? 2 : 3);

				ctx_piperImg = that.piperImgHor[0].getContext( '2d' );
				_data = ctx_piperImg.getImageData( 0, 0, that.piperImgHor[0].width, that.piperImgHor[0].height );
				px = _data.data;

				for ( var i = 0; i < that.piperImgHor[0].width * that.piperImgHor[0].height * 4; i += 4) {
					if ( px[i + 3] == 255 ) {
						px[i] += 2;
						px[i + 1] += 2;
						px[i + 2] += 2;
					}
				}

				ctx_piperImg.putImageData( _data, 0, 0 );

				img = that.piperImgHor[0];
			}

			if ( startColorFadeIn >= _HEXTORGB_(that.settings.scrollerColorOver).R ) {
				that.startColorFadeInOutStart = startColorFadeIn;
				that.fadeInTimeout = setTimeout( fadeIn, that.settings.fadeInFadeOutDelay );
			}
			else {
				clearTimeout( that.fadeInTimeout );
				that.fadeInTimeout = null;
				that.fadeInActive = false;
				that.startColorFadeInOutStart = startColorFadeIn + 2;

				if ( that._checkPiperImagesV() ) {

					ctx_piperImg = that.piperImgVert[0].getContext( '2d' );
					_data = ctx_piperImg.getImageData( 0, 0, that.piperImgVert[0].width, that.piperImgVert[0].height );
					px = _data.data;

					for ( var i = 0; i < that.piperImgVert[0].width * that.piperImgVert[0].height * 4; i += 4 ) {
						if ( px[i + 3] == 255 ) {
							px[i] -= 2;
							px[i + 1] -= 2;
							px[i + 2] -= 2;
						}
					}

					ctx_piperImg.putImageData( _data, 0, 0 );

					img = that.piperImgVert[0];

				}
				else if ( that._checkPiperImagesH() ) {

					ctx_piperImg = that.piperImgHor[0].getContext( '2d' );
					_data = ctx_piperImg.getImageData( 0, 0, that.piperImgHor[0].width, that.piperImgHor[0].height );
					px = _data.data;

					for ( var i = 0; i < that.piperImgHor[0].width * that.piperImgHor[0].height * 4; i += 4) {
						if ( px[i + 3] == 255 ) {
							px[i] -= 2;
							px[i + 1] -= 2;
							px[i + 2] -= 2;
						}
					}

					ctx_piperImg.putImageData( _data, 0, 0 )

					img = that.piperImgHor[0];

				}
			}

			if(img){
				that.context.drawImage( img, x, y );
			}

		}

		function fadeOut() {

			clearTimeout( that.fadeInTimeout );
			that.fadeInTimeout = null;
			clearTimeout( that.fadeOutTimeout );
			that.fadeOutTimeout = null;

			var x, y, img, ctx_piperImg, _data, px;

			that.context.beginPath();

			drawScroller();

			that.context.fillStyle = "rgb(" + that.startColorFadeInOutStart + "," + that.startColorFadeInOutStart + "," + that.startColorFadeInOutStart + ")";
			that.context.strokeStyle = that.settings.strokeStyleOver;

			that.context.fill();
			that.context.stroke();

			startColorFadeOut += 2;

			if ( that._checkPiperImagesV() ) {
				x = that.scroller.x + (that.settings.slimScroll ? 2 : 3);
				y = (that.scroller.y >> 0) + Math.floor( that.scroller.h / 2 ) - 6;

				ctx_piperImg = that.piperImgVert[0].getContext( '2d' );
				_data = ctx_piperImg.getImageData( 0, 0, that.piperImgVert[0].width, that.piperImgVert[0].height );
				px = _data.data;

				for ( var i = 0; i < that.piperImgVert[0].width * that.piperImgVert[0].height * 4; i += 4) {

					if ( px[i + 3] == 255 ) {
						px[i] -= 2;
						px[i + 1] -= 2;
						px[i + 2] -= 2;
					}
				}

				ctx_piperImg.putImageData( _data, 0, 0 );

				img = that.piperImgVert[0];

			}
			else if ( that._checkPiperImagesH() ) {
				x = (that.scroller.x >> 0) + Math.floor( that.scroller.w / 2 ) - 6;
				y = that.scroller.y + (that.settings.slimScroll ? 2 : 3);

				ctx_piperImg = that.piperImgHor[0].getContext( '2d' );
				_data = ctx_piperImg.getImageData( 0, 0, that.piperImgHor[0].width, that.piperImgHor[0].height );
				px = _data.data;

				for ( var i = 0; i < that.piperImgHor[0].width * that.piperImgHor[0].height * 4; i+=4 ) {
					if ( px[i + 3] == 255 ) {
						px[i] -= 2;
						px[i + 1] -= 2;
						px[i + 2] -= 2;
					}
				}

				ctx_piperImg.putImageData( _data, 0, 0 )

				img = that.piperImgHor[0];
			}

			if ( startColorFadeOut <= _HEXTORGB_(that.settings.scrollerColor).R ) {
				that.startColorFadeInOutStart = startColorFadeOut;
				that.fadeOutTimeout = setTimeout( fadeOut, that.settings.fadeInFadeOutDelay );
			}
			else {
				clearTimeout( that.fadeOutTimeout );
				that.fadeOutTimeout = null;
				that.startColorFadeInOutStart = startColorFadeOut - 2;
				that.fadeOutActive = false;

				if ( that._checkPiperImagesV() ) {

					ctx_piperImg = that.piperImgVert[0].getContext( '2d' );
					_data = ctx_piperImg.getImageData( 0, 0, that.piperImgVert[0].width, that.piperImgVert[0].height );
					px = _data.data;

					for ( var i = 0; i < that.piperImgVert[0].width * that.piperImgVert[0].height * 4; i+= 4 ) {
						if ( px[i + 3] == 255 ) {
							px[i] += 2;
							px[i + 1] += 2;
							px[i + 2] += 2;
						}
					}

					ctx_piperImg.putImageData( _data, 0, 0 );

					img = that.piperImgVert[0];

				}
				else if ( that._checkPiperImagesH() ) {
					x = (that.scroller.x >> 0) + Math.floor( that.scroller.w / 2 ) - 6;
					y = that.scroller.y + 3;

					ctx_piperImg = that.piperImgHor[0].getContext( '2d' );
					_data = ctx_piperImg.getImageData( 0, 0, that.piperImgHor[0].width, that.piperImgHor[0].height );
					px = _data.data;

					for ( var i = 0; i < that.piperImgHor[0].width * that.piperImgHor[0].height * 4; i+=4 ) {
						if ( px[i + 3] == 255 ) {
							px[i] += 2;
							px[i + 1] += 2;
							px[i + 2] += 2;
						}
					}

					ctx_piperImg.putImageData( _data, 0, 0 )

					img = that.piperImgHor[0];
				}
			}

			if(img){
				that.context.drawImage( img, x, y );
			}
		}

		function drawScroller() {

			that.context.beginPath();

			if ( that.isVerticalScroll ) {
				var _y = that.settings.showArrows ? that.arrowPosition : 0,
					_h = that.canvasH - (_y << 1);

				if ( _h > 0 ) {
					that.context.rect( 0, _y, that.canvasW, _h );
				}
			}
			else if ( that.isHorizontalScroll ) {
				var _x = that.settings.showArrows ? that.arrowPosition : 0,
					_w = that.canvasW - (_x << 1);

				if ( _w > 0 ) {
					that.context.rect( _x, 0, _w, that.canvasH );
				}
			}

			switch ( that.scrollerStatus ) {

				case ScrollOverType.OVER:
				{
					that.context.fillStyle = that.settings.scrollBackgroundColorHover;
					break;
				}
				case ScrollOverType.ACTIVE:
				{
					that.context.fillStyle = that.settings.scrollBackgroundColorActive;
					break;
				}
				case ScrollOverType.NONE:
				default:
				{
					that.context.fillStyle = that.settings.scrollBackgroundColor;
					break;
				}

			}

			that.context.fill();
			that.context.beginPath();

			if ( that.isVerticalScroll && that.maxScrollY != 0 ) {
				var _y = that.scroller.y >> 0, arrow = that.settings.showArrows ? that.arrowPosition : 0;
				if ( _y < arrow ) {
					_y = arrow;
				}
				var _b = Math.round(that.scroller.y + that.scroller.h);// >> 0;
				if ( _b > (that.canvasH - arrow - 1) ) {
					_b = that.canvasH - arrow - 1;
				}

				if ( _b > _y ) {
					that.roundRect( that.scroller.x - 0.5, _y + 0.5, that.scroller.w - 1, that.scroller.h - 1, that.settings.cornerRadius );
				}
			}
			else if ( that.isHorizontalScroll && that.maxScrollX != 0 ) {
				var _x = that.scroller.x >> 0, arrow = that.settings.showArrows ? that.arrowPosition : 0;
				if ( _x < arrow ) {
					_x = arrow;
				}
				var _r = (that.scroller.x + that.scroller.w) >> 0;
				if ( _r > (that.canvasW - arrow - 2) ) {
					_r = that.canvasW - arrow - 1;
				}

				if ( _r > _x ) {
					that.roundRect( _x + 0.5, that.scroller.y - 0.5, that.scroller.w - 1, that.scroller.h - 1, that.settings.cornerRadius );
				}
			}
		}

		if ( this.fadeInActive && this.lastScrollerStatus == ScrollOverType.OVER && this.scrollerStatus == ScrollOverType.OVER ) {
			return;
		}

		clearTimeout( this.fadeInTimeout );
		this.fadeInTimeout = null;
		clearTimeout( this.fadeOutTimeout );
		this.fadeOutTimeout = null;

		this.fadeInActive = false;
		this.fadeOutActive = false;

		drawScroller();

		this.context.lineWidth = 1;
		switch ( this.scrollerStatus ) {

			case ScrollOverType.LAYER:
			case ScrollOverType.OVER:
			{
				if ( this.lastScrollerStatus == ScrollOverType.NONE ) {
					this.lastScrollerStatus = this.scrollerStatus;
					this.startColorFadeInOutStart = this.startColorFadeInOutStart < 0 ? startColorFadeIn : this.startColorFadeInOutStart;
					this.fadeInActive = true;
					fadeIn();
				}
				else{
					this.context.fillStyle = this.settings.scrollerColorOver;
					this.context.strokeStyle = this.settings.strokeStyleOver;
					piperImgIndex = 1;
				}
				break;
			}
			case ScrollOverType.ACTIVE:
			{
				this.context.fillStyle = this.settings.scrollerColorActive;
				this.context.strokeStyle = this.settings.strokeStyleActive;
				piperImgIndex = 1;
				break;
			}
			case ScrollOverType.NONE:
			default:
			{
				if ( this.lastScrollerStatus == ScrollOverType.OVER ) {
					this.lastScrollerStatus = this.scrollerStatus;
					this.startColorFadeInOutStart = this.startColorFadeInOutStart < 0 ? startColorFadeOut : this.startColorFadeInOutStart;
					this.fadeOutActive = true;
					fadeOut();
				}
				else{
					this.context.fillStyle = this.settings.scrollerColor;
					this.context.strokeStyle = this.settings.strokeStyleNone;

					this.startColorFadeInOutStart = this.startColorFadeInStart = _HEXTORGB_(this.settings.scrollerColor).R;
					this.startColorFadeOutStart = _HEXTORGB_(this.settings.scrollerColorOver).R;

					piperImgIndex = 0;

					var r, g, b, ctx_piperImg, _data, px, _len;
					r = _HEXTORGB_( this.settings.piperColor );
					g = r.G;
					b = r.B;
					r = r.R;

					if ( this.isVerticalScroll ) {
						ctx_piperImg = this.piperImgVert[piperImgIndex].getContext( '2d' );
						_data = ctx_piperImg.getImageData( 0, 0, this.piperImgVert[piperImgIndex].width, this.piperImgVert[piperImgIndex].height );
					}
					else if ( this.isHorizontalScroll ) {
						ctx_piperImg = this.piperImgHor[piperImgIndex].getContext( '2d' );
						_data = ctx_piperImg.getImageData( 0, 0, this.piperImgHor[piperImgIndex].width, this.piperImgHor[piperImgIndex].height );
					}

					if( this.isVerticalScroll || this.isHorizontalScroll ){

						px = _data.data;
						_len = px.length;

						for ( var i = 0; i < _len; i += 4 ) {
							if ( px[i + 3] == 255 ) {
								px[i] = r;
								px[i + 1] = g;
								px[i + 2] = b;
							}
						}

						ctx_piperImg.putImageData( _data, 0, 0 );

					}

				}
				break;
			}

		}

		if ( !this.fadeInActive && !this.fadeOutActive ) {
			this.context.fill();
			this.context.stroke();

			if ( this._checkPiperImagesV() ) {
				this.context.drawImage( this.piperImgVert[piperImgIndex], this.scroller.x + (this.settings.slimScroll ? 2 : 3), (this.scroller.y >> 0) + Math.floor( this.scroller.h / 2 ) - 6 );
			}
			else if ( this._checkPiperImagesH() ) {
				this.context.drawImage( this.piperImgHor[piperImgIndex], (this.scroller.x >> 0) + Math.floor( this.scroller.w / 2 ) - 6, this.scroller.y + (this.settings.slimScroll ? 2 : 3) );
			}

		}

		this.lastScrollerStatus = this.scrollerStatus;

	};

	ScrollObject.prototype._checkPiperImagesV = function() {
		if ( this.isVerticalScroll && this.maxScrollY != 0 && this.scroller.h >= 13 )
			return true;
		return false;
	};
	ScrollObject.prototype._checkPiperImagesH = function() {
		if ( this.isHorizontalScroll && this.maxScrollX != 0 && this.scroller.w >= 13 )
			return true;
		return false;
	};

	ScrollObject.prototype._drawArrow = function ( type ) {
		if ( this.settings.showArrows ) {
			var w = this.canvasW;
			var h = this.canvasH;
			if ( this.isVerticalScroll ) {
				switch ( type ) {
					case ArrowStatus.upLeftArrowHover_downRightArrowNonActive://upArrow mouse hover, downArrow stable
						if ( ScrollOverType.OVER != this.ScrollOverType1 ) {
							this.ArrowDrawer.drawTopLeftArrow(ScrollArrowType.ARROW_TOP, ScrollOverType.OVER, this.context, w, h);
							this.ScrollOverType1 = ScrollOverType.OVER;
						}
						if ( ScrollOverType.STABLE != this.ScrollOverType2 ) {
							this.ArrowDrawer.drawBottomRightArrow( ScrollArrowType.ARROW_BOTTOM, ScrollOverType.STABLE, this.context, w, h );
							this.ScrollOverType2 = ScrollOverType.STABLE;
						}
						break;
					case ArrowStatus.upLeftArrowActive_downRightArrowNonActive://upArrow mouse down, downArrow stable
						if ( ScrollOverType.ACTIVE != this.ScrollOverType1 ) {
							this.ArrowDrawer.drawTopLeftArrow(ScrollArrowType.ARROW_TOP, ScrollOverType.ACTIVE, this.context, w, h);
							this.ScrollOverType1 = ScrollOverType.ACTIVE;
						}
						if ( ScrollOverType.STABLE != this.ScrollOverType2 ) {
							this.ArrowDrawer.drawBottomRightArrow(ScrollArrowType.ARROW_BOTTOM, ScrollOverType.STABLE, this.context, w, h);
							this.ScrollOverType2 = ScrollOverType.STABLE;
						}
						break;
					case ArrowStatus.upLeftArrowNonActive_downRightArrowHover://upArrow stable, downArrow mouse hover
						if ( ScrollOverType.STABLE != this.ScrollOverType1 ) {
							this.ArrowDrawer.drawTopLeftArrow(ScrollArrowType.ARROW_TOP, ScrollOverType.STABLE, this.context, w, h);
							this.ScrollOverType1 = ScrollOverType.STABLE;
						}
						if ( ScrollOverType.OVER != this.ScrollOverType2 ) {
							this.ArrowDrawer.drawBottomRightArrow(ScrollArrowType.ARROW_BOTTOM, ScrollOverType.OVER, this.context, w, h);
							this.ScrollOverType2 = ScrollOverType.OVER;
						}
						break;
					case ArrowStatus.upLeftArrowNonActive_downRightArrowActive://upArrow stable, downArrow mouse down
						if ( ScrollOverType.STABLE != this.ScrollOverType1 ) {
							this.ArrowDrawer.drawTopLeftArrow(ScrollArrowType.ARROW_TOP, ScrollOverType.STABLE, this.context, w, h);
							this.ScrollOverType1 = ScrollOverType.STABLE;
						}
						if ( ScrollOverType.ACTIVE != this.ScrollOverType2 ) {
							this.ArrowDrawer.drawBottomRightArrow(ScrollArrowType.ARROW_BOTTOM, ScrollOverType.ACTIVE, this.context, w, h);
							this.ScrollOverType2 = ScrollOverType.ACTIVE;
						}
						break;
					case ArrowStatus.arrowHover://upArrow stable, downArrow mouse down
						if ( ScrollOverType.STABLE != this.ScrollOverType1 ) {
							this.ArrowDrawer.drawTopLeftArrow(ScrollArrowType.ARROW_TOP, ScrollOverType.STABLE, this.context, w, h);
							this.ScrollOverType1 = ScrollOverType.STABLE;
						}
						if ( ScrollOverType.STABLE != this.ScrollOverType2 ) {
							this.ArrowDrawer.drawBottomRightArrow(ScrollArrowType.ARROW_BOTTOM, ScrollOverType.STABLE, this.context, w, h);
							this.ScrollOverType2 = ScrollOverType.STABLE;
						}
						break;
					default ://upArrow stable, downArrow stable
						if ( ScrollOverType.NONE != this.ScrollOverType1 ) {
							this.ArrowDrawer.drawTopLeftArrow(ScrollArrowType.ARROW_TOP, ScrollOverType.NONE, this.context, w, h);
							this.ScrollOverType1 = ScrollOverType.NONE;
						}
						if ( ScrollOverType.NONE != this.ScrollOverType2 ) {
							this.ArrowDrawer.drawBottomRightArrow(ScrollArrowType.ARROW_BOTTOM, ScrollOverType.NONE, this.context, w, h);
							this.ScrollOverType2 = ScrollOverType.NONE;
						}
						break;
				}
			}
			if ( this.isHorizontalScroll ) {
				switch ( type ) {
					case ArrowStatus.upLeftArrowHover_downRightArrowNonActive://leftArrow mouse hover, rightArrow stable
						if ( ScrollOverType.OVER != this.ScrollOverType1 ) {
							this.ArrowDrawer.drawTopLeftArrow(ScrollArrowType.ARROW_LEFT, ScrollOverType.OVER, this.context, w, h);
							this.ScrollOverType1 = ScrollOverType.OVER;
						}
						if ( ScrollOverType.STABLE != this.ScrollOverType2 ) {
							this.ArrowDrawer.drawBottomRightArrow(ScrollArrowType.ARROW_RIGHT, ScrollOverType.STABLE, this.context, w, h);
							this.ScrollOverType2 = ScrollOverType.STABLE;
						}
						break;
					case ArrowStatus.upLeftArrowActive_downRightArrowNonActive://leftArrow mouse down, rightArrow stable
						if ( ScrollOverType.ACTIVE != this.ScrollOverType1 ) {
							this.ArrowDrawer.drawTopLeftArrow(ScrollArrowType.ARROW_LEFT, ScrollOverType.ACTIVE, this.context, w, h);
							this.ScrollOverType1 = ScrollOverType.ACTIVE;
						}
						if ( ScrollOverType.STABLE != this.ScrollOverType2 ) {
//                            this.ArrowDrawer.drawArrow( ScrollArrowType.ARROW_RIGHT, ScrollOverType.STABLE, this.context, w, h );
							this.ArrowDrawer.drawBottomRightArrow(ScrollArrowType.ARROW_RIGHT, ScrollOverType.STABLE, this.context, w, h);
							this.ScrollOverType2 = ScrollOverType.STABLE;
						}
						break;
					case ArrowStatus.upLeftArrowNonActive_downRightArrowHover://leftArrow stable, rightArrow mouse hover
						if ( ScrollOverType.STABLE != this.ScrollOverType1 ) {
							this.ArrowDrawer.drawTopLeftArrow(ScrollArrowType.ARROW_LEFT, ScrollOverType.STABLE, this.context, w, h);
							this.ScrollOverType1 = ScrollOverType.STABLE;
						}
						if ( ScrollOverType.OVER != this.ScrollOverType2 ) {
							this.ArrowDrawer.drawBottomRightArrow(ScrollArrowType.ARROW_RIGHT, ScrollOverType.OVER, this.context, w, h);
							this.ScrollOverType2 = ScrollOverType.OVER;
						}
						break;
					case ArrowStatus.upLeftArrowNonActive_downRightArrowActive://leftArrow stable, rightArrow mouse down
						if ( ScrollOverType.STABLE != this.ScrollOverType1 ) {
							this.ArrowDrawer.drawTopLeftArrow(ScrollArrowType.ARROW_LEFT, ScrollOverType.STABLE, this.context, w, h);
							this.ScrollOverType1 = ScrollOverType.STABLE;
						}
						if ( ScrollOverType.ACTIVE != this.ScrollOverType2 ) {
							this.ArrowDrawer.drawBottomRightArrow(ScrollArrowType.ARROW_RIGHT, ScrollOverType.ACTIVE, this.context, w, h);
							this.ScrollOverType2 = ScrollOverType.ACTIVE;
						}
						break;
					case ArrowStatus.arrowHover://upArrow stable, downArrow mouse down
						if ( ScrollOverType.STABLE != this.ScrollOverType1 ) {
							this.ArrowDrawer.drawTopLeftArrow(ScrollArrowType.ARROW_LEFT, ScrollOverType.STABLE, this.context, w, h);
							this.ScrollOverType1 = ScrollOverType.STABLE;
						}
						if ( ScrollOverType.STABLE != this.ScrollOverType2 ) {
							this.ArrowDrawer.drawBottomRightArrow(ScrollArrowType.ARROW_RIGHT, ScrollOverType.STABLE, this.context, w, h);
							this.ScrollOverType2 = ScrollOverType.STABLE;
						}
						break;
					default ://leftArrow stable, rightArrow stable
						if ( ScrollOverType.NONE != this.ScrollOverType1 ) {
							this.ArrowDrawer.drawTopLeftArrow(ScrollArrowType.ARROW_LEFT, ScrollOverType.NONE, this.context, w, h);
							this.ScrollOverType1 = ScrollOverType.NONE;
						}
						if ( ScrollOverType.NONE != this.ScrollOverType2 ) {
							this.ArrowDrawer.drawBottomRightArrow(ScrollArrowType.ARROW_RIGHT, ScrollOverType.NONE, this.context, w, h);
							this.ScrollOverType2 = ScrollOverType.NONE;
						}
						break;
				}
			}
		}
	};

	ScrollObject.prototype._setDimension = function ( h, w ) {

		if ( w == this.canvasW && h == this.canvasH )
			return;

		this.ScrollOverType1 = -1;
		this.ScrollOverType2 = -1;

		this.canvasW = w;
		this.canvasH = h;

		if ( !this.IsRetina ) {
			this.canvas.height = h;
			this.canvas.width = w;

			this.context.setTransform( 1, 0, 0, 1, 0, 0 );
		}
		else {
			this.canvas.height = h << 1;
			this.canvas.width = w << 1;

			this.context.setTransform( 2, 0, 0, 2, 0, 0 );
		}
	};
	ScrollObject.prototype._setScrollerHW = function () {
		if ( this.isVerticalScroll ) {
			this.scroller.x = 1;//0;
			this.scroller.w = this.canvasW - 1;
			if ( this.settings.showArrows )
				this.ArrowDrawer.InitSize( this.settings.arrowSizeW, this.settings.arrowSizeH, this.IsRetina );
		}
		else if ( this.isHorizontalScroll ) {
			this.scroller.y = 1;//0;
			this.scroller.h = this.canvasH - 1;
			if ( this.settings.showArrows )
				this.ArrowDrawer.InitSize( this.settings.arrowSizeH, this.settings.arrowSizeW, this.IsRetina );
		}
	};
	ScrollObject.prototype._MouseHoverOnScroller = function ( mp ) {
		if ( mp.x >= this.scroller.x && mp.x <= this.scroller.x + this.scroller.w &&
			mp.y >= this.scroller.y && mp.y <= this.scroller.y + this.scroller.h ) {
			return true;
		}
		else {
			return false;
		}
	};
	ScrollObject.prototype._MouseHoverOnArrowUp = function ( mp ) {
		if ( this.isVerticalScroll ) {
			if (
				mp.x >= 0 &&
				mp.x <= this.canvasW &&
				mp.y >= 0 &&
				mp.y <= this.settings.arrowDim
			) {
				return true;
			}
			else return false;
		}
		if ( this.isHorizontalScroll ) {
			if (
				mp.x >= 0 &&
				mp.x <= this.settings.arrowDim &&
				mp.y >= 0 &&
				mp.y <= this.canvasH
			) {
				return true;
			}
			else return false;
		}
	};
	ScrollObject.prototype._MouseHoverOnArrowDown = function ( mp ) {
		if ( this.isVerticalScroll ) {
			if (
				mp.x >= 0 &&
				mp.x <= this.canvasW &&
				mp.y >= this.canvasH - this.settings.arrowDim &&
				mp.y <= this.canvasH
			) {
				return true;
			}
			else return false;
		}
		if ( this.isHorizontalScroll ) {
			if (
				mp.x >= this.canvasW - this.settings.arrowDim &&
				mp.x <= this.canvasW &&
				mp.y >= 0 &&
				mp.y <= this.canvasH
			) {
				return true;
			}
			else return false;
		}
	};

	ScrollObject.prototype._arrowDownMouseDown = function () {
		var that = this, scrollTimeout, isFirst = true,
			doScroll = function () {
				if ( that.isVerticalScroll )
					that.scrollByY( that.settings.vscrollStep );
				else if ( that.isHorizontalScroll )
					that.scrollByX( that.settings.hscrollStep );
				that._drawArrow( ArrowStatus.upLeftArrowNonActive_downRightArrowActive );
				scrollTimeout = setTimeout( doScroll, isFirst ? that.settings.initialDelay : that.settings.arrowRepeatFreq );
				isFirst = false;
			};
		doScroll();
		this.bind( "mouseup.main mouseout", function () {
			scrollTimeout && clearTimeout( scrollTimeout );
			scrollTimeout = null;
		} );
	};
	ScrollObject.prototype._arrowUpMouseDown = function () {
		var that = this, scrollTimeout, isFirst = true,
			doScroll = function () {
				if ( that.isVerticalScroll )
					that.scrollByY( -that.settings.vscrollStep );
				else if ( that.isHorizontalScroll )
					that.scrollByX( -that.settings.hscrollStep );
				that._drawArrow( ArrowStatus.upLeftArrowActive_downRightArrowNonActive );
				scrollTimeout = setTimeout( doScroll, isFirst ? that.settings.initialDelay : that.settings.arrowRepeatFreq );
				isFirst = false;
			};
		doScroll();
		this.bind( "mouseup.main mouseout", function () {
			scrollTimeout && clearTimeout( scrollTimeout );
			scrollTimeout = null;
		} )
	};

	ScrollObject.prototype.getCurScrolledX = function () {
		return this.scrollHCurrentX;
	};
	ScrollObject.prototype.getCurScrolledY = function () {
		return this.scrollVCurrentY;
	};
	ScrollObject.prototype.getMaxScrolledY = function () {
		return this.maxScrollY;
	};
	ScrollObject.prototype.getMaxScrolledX = function () {
		return this.maxScrollX;
	};
	ScrollObject.prototype.getIsLockedMouse = function () {
		return (this.that.mouseDownArrow || this.that.mouseDown);
	};
	/************************************************************************/
	/*events*/
	ScrollObject.prototype.evt_mousemove = function ( e ) {

        if (this.style)
            this.style.cursor = "default";

        var arrowStat = ArrowStatus.arrowHover;
        var evt = e || window.event;

		if ( evt.preventDefault )
			evt.preventDefault();
		else
			evt.returnValue = false;

		var mousePos = this.that.getMousePosition( evt );
		this.that.EndMousePosition.x = mousePos.x;
		this.that.EndMousePosition.y = mousePos.y;
		var downHover = this.that._MouseHoverOnArrowDown( mousePos ),
			upHover = this.that._MouseHoverOnArrowUp( mousePos ),
			scrollerHover = this.that._MouseHoverOnScroller( mousePos );

		if ( scrollerHover ) {
			this.that.scrollerStatus = ScrollOverType.OVER;
			arrowStat = ArrowStatus.arrowHover;
		}
		else if ( this.that.settings.showArrows && (downHover || upHover) ) {
			this.that.scrollerStatus = ScrollOverType.OVER;
			if ( !this.that.mouseDownArrow ) {
				if ( upHover ) {
					arrowStat = ArrowStatus.upLeftArrowHover_downRightArrowNonActive;
				}
				else if ( downHover ) {
					arrowStat = ArrowStatus.upLeftArrowNonActive_downRightArrowHover
				}
			}
		}
		else {
			if ( this.that.mouseover ) {
				arrowStat = ArrowStatus.arrowHover;
			}
			this.that.scrollerStatus = ScrollOverType.OVER;
		}
		if ( this.that.mouseDown && this.that.scrollerMouseDown ) {
			this.that.moveble = true;
		}
		else {
			this.that.moveble = false;
		}

		if ( this.that.isVerticalScroll ) {
			if ( this.that.moveble && this.that.scrollerMouseDown ) {
				var isTop = false, isBottom = false;
				this.that.scrollerStatus = ScrollOverType.ACTIVE;
				var _dlt = this.that.EndMousePosition.y - this.that.StartMousePosition.y;
				if ( this.that.EndMousePosition.y == this.that.StartMousePosition.y ) {
					return;
				}
				else if ( this.that.EndMousePosition.y < this.that.arrowPosition ) {
					this.that.EndMousePosition.y = this.that.arrowPosition;
					_dlt = 0;
					this.that.scroller.y = this.that.arrowPosition;
				}
				else if ( this.that.EndMousePosition.y > this.that.canvasH - this.that.arrowPosition ) {
					this.that.EndMousePosition.y = this.that.canvasH - this.that.arrowPosition;
					_dlt = 0;
					this.that.scroller.y = this.that.canvasH - this.that.arrowPosition - this.that.scroller.h;
				}
				else {
					if ( (_dlt > 0 && this.that.scroller.y + _dlt + this.that.scroller.h <= this.that.canvasH - this.that.arrowPosition ) ||
						(_dlt < 0 && this.that.scroller.y + _dlt >= this.that.arrowPosition) ) {
						this.that.scroller.y += _dlt;
					}
				}

				var destY = (this.that.scroller.y - this.that.arrowPosition) * this.that.scrollCoeff;
				//var result = editor.WordControl.CorrectSpeedVerticalScroll(destY);
				var result = this.that._correctScrollV( this.that, destY );
				if ( result != null && result.isChange === true ) {
					destY = result.Pos;
				}

				this.that._scrollV( this.that, evt, destY, isTop, isBottom );
				this.that.moveble = false;
				this.that.StartMousePosition.x = this.that.EndMousePosition.x;
				this.that.StartMousePosition.y = this.that.EndMousePosition.y;
			}
		}
		else if ( this.that.isHorizontalScroll ) {
			if ( this.that.moveble && this.that.scrollerMouseDown ) {

				var isTop = false, isBottom = false;
				this.that.scrollerStatus = ScrollOverType.ACTIVE;
				var _dlt = this.that.EndMousePosition.x - this.that.StartMousePosition.x;
				if ( this.that.EndMousePosition.x == this.that.StartMousePosition.x )
					return;
				else if ( this.that.EndMousePosition.x < this.that.arrowPosition ) {
					this.that.EndMousePosition.x = this.that.arrowPosition;
					_dlt = 0;
					this.that.scroller.x = this.that.arrowPosition;
				}
				else if ( this.that.EndMousePosition.x > this.that.canvasW - this.that.arrowPosition ) {
					this.that.EndMousePosition.x = this.that.canvasW - this.that.arrowPosition;
					_dlt = 0;
					this.that.scroller.x = this.that.canvasW - this.that.arrowPosition - this.that.scroller.w;
				}
				else {
					if ( (_dlt > 0 && this.that.scroller.x + _dlt + this.that.scroller.w <= this.that.canvasW - this.that.arrowPosition ) ||
						(_dlt < 0 && this.that.scroller.x + _dlt >= this.that.arrowPosition) )
						this.that.scroller.x += _dlt;
				}
				var destX = (this.that.scroller.x - this.that.arrowPosition) * this.that.scrollCoeff

				this.that._scrollH( this.that, evt, destX, isTop, isBottom );
				this.that.moveble = false;

				this.that.StartMousePosition.x = this.that.EndMousePosition.x;
				this.that.StartMousePosition.y = this.that.EndMousePosition.y;
			}
		}

		if ( !this.that.mouseDownArrow ) {
			this.that._drawArrow( arrowStat );
		}
		if ( this.that.lastScrollerStatus != this.that.scrollerStatus ) {
			this.that._draw();
		}

	};
	ScrollObject.prototype.evt_mouseout = function ( e ) {

		var evt = e || window.event;

		if ( this.that.settings.showArrows ) {
			this.that.mouseDownArrow = false;
			this.that.handleEvents( "onmouseout", evt );
		}

		if ( !this.that.moveble ) {
			this.that.scrollerStatus = ScrollOverType.NONE;
			this.that._drawArrow();
		}

		if ( this.that.lastScrollerStatus != this.that.scrollerStatus ) {
			this.that._draw();
		}

	};
	ScrollObject.prototype.evt_mouseover = function ( e ) {

		this.that.mouseover = true;

	};
	ScrollObject.prototype.evt_mouseup = function ( e ) {
		var evt = e || window.event;

		this.that.handleEvents( "onmouseup", evt );

		// prevent pointer events on all iframes (while only plugin!)
		if (window.g_asc_plugins)
			window.g_asc_plugins.enablePointerEvents();

		if ( evt.preventDefault )
			evt.preventDefault();
		else
			evt.returnValue = false;

		var mousePos = this.that.getMousePosition( evt );
		this.that.scrollTimeout && clearTimeout( this.that.scrollTimeout );
		this.that.scrollTimeout = null;
		if ( this.that.scrollerMouseDown ) {
			this.that.mouseDown = false;
			this.that.mouseUp = true;
			this.that.scrollerMouseDown = false;
			this.that.mouseDownArrow = false;
			if ( this.that._MouseHoverOnScroller( mousePos ) ) {
				this.that.scrollerStatus = ScrollOverType.OVER;
			}
			else {
				this.that.scrollerStatus = ScrollOverType.NONE;
			}
			this.that._drawArrow();
			this.that._draw();
		} else {
			if ( this.that.settings.showArrows && this.that._MouseHoverOnArrowDown( mousePos ) ) {
				this.that._drawArrow( ArrowStatus.upLeftArrowNonActive_downRightArrowHover );
			}
			else if ( this.that.settings.showArrows && this.that._MouseHoverOnArrowUp( mousePos ) ) {
				this.that._drawArrow( ArrowStatus.upLeftArrowHover_downRightArrowNonActive );
			}
			this.that.mouseDownArrow = false;
		}

		//for unlock global mouse event
		if ( this.that.onLockMouse && this.that.offLockMouse ) {
			this.that.offLockMouse( evt );
		}
	};
	ScrollObject.prototype.evt_mousedown = function ( e ) {
		var evt = e || window.event;

		// prevent pointer events on all iframes (while only plugin!)
		if (window.g_asc_plugins)
			window.g_asc_plugins.disablePointerEvents();

		// если сделать превент дефолт - перестанет приходить mousemove от window
		/*
		 if (evt.preventDefault)
		 evt.preventDefault();
		 else
		 evt.returnValue = false;
		 */

		var mousePos = this.that.getMousePosition( evt ),
			downHover = this.that._MouseHoverOnArrowDown( mousePos ),
			upHover = this.that._MouseHoverOnArrowUp( mousePos );

		if ( this.that.settings.showArrows && downHover ) {
			this.that.mouseDownArrow = true;
			this.that._arrowDownMouseDown();
		}
		else if ( this.that.settings.showArrows && upHover ) {
			this.that.mouseDownArrow = true;
			this.that._arrowUpMouseDown();
		}
		else {
			this.that.mouseDown = true;
			this.that.mouseUp = false;

			if ( this.that._MouseHoverOnScroller( mousePos ) ) {
				this.that.scrollerMouseUp = false;
				this.that.scrollerMouseDown = true;

				if ( this.that.onLockMouse ) {
					this.that.onLockMouse( evt );
				}
				this.that.StartMousePosition.x = mousePos.x;
				this.that.StartMousePosition.y = mousePos.y;
				this.that.scrollerStatus = ScrollOverType.ACTIVE;
				this.that._draw();
			}
			else {
				if ( this.that.isVerticalScroll ) {
					var _tmp = this,
						direction = mousePos.y - this.that.scroller.y - this.that.scroller.h / 2,
						step = this.that.paneHeight * this.that.settings.scrollPagePercent,
//                        verticalDragPosition = this.that.scroller.y,
						isFirst = true,
						doScroll = function () {
							_tmp.that.lock = true;
							if ( direction > 0 ) {
								if ( _tmp.that.scroller.y + _tmp.that.scroller.h / 2 + step < mousePos.y ) {
									_tmp.that.scrollByY( step * _tmp.that.scrollCoeff );
								}
								else {
									var _step = Math.abs( _tmp.that.scroller.y + _tmp.that.scroller.h / 2 - mousePos.y );
									_tmp.that.scrollByY( _step * _tmp.that.scrollCoeff );
									cancelClick();
									return;
								}
							}
							else if ( direction < 0 ) {
								if ( _tmp.that.scroller.y + _tmp.that.scroller.h / 2 - step > mousePos.y ) {
									_tmp.that.scrollByY( -step * _tmp.that.scrollCoeff );
								}
								else {
									var _step = Math.abs( _tmp.that.scroller.y + _tmp.that.scroller.h / 2 - mousePos.y );
									_tmp.that.scrollByY( -_step * _tmp.that.scrollCoeff );
									cancelClick();
									return;
								}
							}
							_tmp.that.scrollTimeout = setTimeout( doScroll, isFirst ? _tmp.that.settings.initialDelay : _tmp.that.settings.trackClickRepeatFreq );
							isFirst = false;
							_tmp.that._drawArrow( ArrowStatus.arrowHover );
						},
						cancelClick = function () {
							_tmp.that.scrollTimeout && clearTimeout( _tmp.that.scrollTimeout );
							_tmp.that.scrollTimeout = null;
							_tmp.that.unbind( "mouseup.main", cancelClick );
							_tmp.that.lock = false;
						};

					if ( this.that.onLockMouse ) {
						this.that.onLockMouse( evt );
					}

					doScroll();
					this.that.bind( "mouseup.main", cancelClick );
				}
				if ( this.that.isHorizontalScroll ) {
					var _tmp = this,
						direction = mousePos.x - this.that.scroller.x - this.that.scroller.w / 2,
						step = this.that.paneWidth * this.that.settings.scrollPagePercent,
//                        horizontalDragPosition = this.that.scroller.x,
						isFirst = true,
						doScroll = function () {
							_tmp.that.lock = true;
							if ( direction > 0 ) {
								if ( _tmp.that.scroller.x + _tmp.that.scroller.w / 2 + step < mousePos.x ) {
									_tmp.that.scrollByX( step * _tmp.that.scrollCoeff );
								}
								else {
									var _step = Math.abs( _tmp.that.scroller.x + _tmp.that.scroller.w / 2 - mousePos.x );
									_tmp.that.scrollByX( _step * _tmp.that.scrollCoeff );
									cancelClick();
									return;
								}
							}
							else if ( direction < 0 ) {
								if ( _tmp.that.scroller.x + _tmp.that.scroller.w / 2 - step > mousePos.x ) {
									_tmp.that.scrollByX( -step * _tmp.that.scrollCoeff );
								}
								else {
									var _step = Math.abs( _tmp.that.scroller.x + _tmp.that.scroller.w / 2 - mousePos.x );
									_tmp.that.scrollByX( -_step * _tmp.that.scrollCoeff );
									cancelClick();
									return;
								}
							}
							_tmp.that.scrollTimeout = setTimeout( doScroll, isFirst ? _tmp.that.settings.initialDelay : _tmp.that.settings.trackClickRepeatFreq );
							isFirst = false;
							_tmp.that._drawArrow( ArrowStatus.arrowHover );
						},
						cancelClick = function () {
							_tmp.that.scrollTimeout && clearTimeout( _tmp.that.scrollTimeout );
							_tmp.that.scrollTimeout = null;
							_tmp.that.unbind( "mouseup.main", cancelClick );
							_tmp.that.lock = false;
						};

					if ( this.that.onLockMouse ) {
						this.that.onLockMouse( evt );
					}

					doScroll();
					this.that.bind( "mouseup.main", cancelClick );
				}
			}
		}
	};
	ScrollObject.prototype.evt_mousewheel = function ( e ) {
		var evt = e || window.event;
		/* if ( evt.preventDefault )
		 evt.preventDefault();
		 else
		 evt.returnValue = false;*/

		var delta = 1;
		if ( this.that.isHorizontalScroll ) return;
		if ( undefined != evt.wheelDelta )
			delta = (evt.wheelDelta > 0) ? -this.that.settings.vscrollStep : this.that.settings.vscrollStep;
		else
			delta = (evt.detail > 0) ? this.that.settings.vscrollStep : -this.that.settings.vscrollStep;
		delta *= this.that.settings.wheelScrollLines;
		this.that.scroller.y += delta;
		if ( this.that.scroller.y < 0 ) {
			this.that.scroller.y = 0;
		}
		else if ( this.that.scroller.y + this.that.scroller.h > this.that.canvasH ) {
			this.that.scroller.y = this.that.canvasH - this.that.arrowPosition - this.that.scroller.h;
		}
		this.that.scrollByY( delta )
	};
	ScrollObject.prototype.evt_click = function ( e ) {
		var evt = e || window.event;
		var mousePos = this.that.getMousePosition( evt );
		if ( this.that.isHorizontalScroll ) {
			if ( mousePos.x > this.arrowPosition && mousePos.x < this.that.canvasW - this.that.arrowPosition ) {
				if ( this.that.scroller.x > mousePos.x ) {
					this.that.scrollByX( -this.that.settings.vscrollStep );
				}
				if ( this.that.scroller.x < mousePos.x && this.that.scroller.x + this.that.scroller.w > mousePos.x ) {
					return false;
				}
				if ( this.that.scroller.x + this.that.scroller.w < mousePos.x ) {
					this.that.scrollByX( this.that.settings.hscrollStep );
				}
			}
		}
		if ( this.that.isVerticalScroll ) {
			if ( mousePos.y > this.that.arrowPosition && mousePos.y < this.that.canvasH - this.that.arrowPosition ) {
				if ( this.that.scroller.y > mousePos.y ) {
					this.that.scrollByY( -this.that.settings.vscrollStep );
				}
				if ( this.that.scroller.y < mousePos.y && this.that.scroller.y + this.that.scroller.h > mousePos.y ) {
					return false;
				}
				if ( this.that.scroller.y + this.that.scroller.h < mousePos.y ) {
					this.that.scrollByY( this.that.settings.hscrollStep );
				}
			}
		}
	};

	/************************************************************************/
	/*for events*/
	ScrollObject.prototype.bind = function ( typesStr, handler ) {
		var types = typesStr.split( " " );
		/*
		 * loop through types and attach event listeners to
		 * each one.  eg. "click mouseover.namespace mouseout"
		 * will create three event bindings
		 */
		for ( var n = 0; n < types.length; n++ ) {
			var type = types[n];
			var event = (type.indexOf( 'touch' ) == -1) ? 'on' + type : type;
			var parts = event.split( "." );
			var baseEvent = parts[0];
			var name = parts.length > 1 ? parts[1] : "";

			if ( !this.eventListeners[baseEvent] ) {
				this.eventListeners[baseEvent] = [];
			}

			this.eventListeners[baseEvent].push( {
				name:name,
				handler:handler
			} );
		}
	};
	ScrollObject.prototype.unbind = function ( typesStr ) {
		var types = typesStr.split( " " );

		for ( var n = 0; n < types.length; n++ ) {
			var type = types[n];
			var event = (type.indexOf( 'touch' ) == -1) ? 'on' + type : type;
			var parts = event.split( "." );
			var baseEvent = parts[0];

			if ( this.eventListeners[baseEvent] && parts.length > 1 ) {
				var name = parts[1];

				for ( var i = 0; i < this.eventListeners[baseEvent].length; i++ ) {
					if ( this.eventListeners[baseEvent][i].name == name ) {
						this.eventListeners[baseEvent].splice( i, 1 );
						if ( this.eventListeners[baseEvent].length === 0 ) {
							this.eventListeners[baseEvent] = undefined;
						}
						break;
					}
				}
			}
			else {
				this.eventListeners[baseEvent] = undefined;
			}
		}
	};
	ScrollObject.prototype.handleEvents = function ( eventType, evt, p ) {
		var that = this;
		// generic events handler
		function handle( obj ) {
			var el = obj.eventListeners;
			if ( el[eventType] ) {
				var events = el[eventType];
				for ( var i = 0; i < events.length; i++ ) {
					events[i].handler.apply( obj, [evt] );
				}
			}
		}

		/*
		 * simulate bubbling by handling shape events
		 * first, followed by group events, followed
		 * by layer events
		 */
		handle( that );
	};

    //---------------------------------------------------------export---------------------------------------------------
	window["AscCommon"].ScrollSettings = ScrollSettings;
    window["AscCommon"].ScrollObject = ScrollObject;
})(window);

/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */
(function (window, document, Math) {
var rAF = window.requestAnimationFrame	||
	window.webkitRequestAnimationFrame	||
	window.mozRequestAnimationFrame		||
	window.oRequestAnimationFrame		||
	window.msRequestAnimationFrame		||
	function (callback) { window.setTimeout(callback, 1000 / 60); };

var utils = (function () {
	var me = {};

	var _elementStyle = document.createElement('div').style;
	var _vendor = (function () {
		var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
			transform,
			i = 0,
			l = vendors.length;

		for ( ; i < l; i++ ) {
			transform = vendors[i] + 'ransform';
			if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);
		}

		return false;
	})();

	function _prefixStyle (style) {
		if ( _vendor === false ) return false;
		if ( _vendor === '' ) return style;
		return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
	}

	me.getTime = Date.now || function getTime () { return new Date().getTime(); };

	me.extend = function (target, obj) {
		for ( var i in obj ) {
			target[i] = obj[i];
		}
	};

	me.addEvent = function (el, type, fn, capture) {
		el.addEventListener(type, fn, !!capture);
	};

	me.removeEvent = function (el, type, fn, capture) {
		el.removeEventListener(type, fn, !!capture);
	};

	me.prefixPointerEvent = function (pointerEvent) {
		return window.MSPointerEvent ?
			'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8):
			pointerEvent;
	};

	me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {
		var distance = current - start,
			speed = Math.abs(distance) / time,
			destination,
			duration;

		deceleration = deceleration === undefined ? 0.0006 : deceleration;

		destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
		duration = speed / deceleration;

		if ( destination < lowerMargin ) {
			destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
			distance = Math.abs(destination - current);
			duration = distance / speed;
		} else if ( destination > 0 ) {
			destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
			distance = Math.abs(current) + destination;
			duration = distance / speed;
		}

		return {
			destination: Math.round(destination),
			duration: duration
		};
	};

	var _transform = _prefixStyle('transform');

	me.extend(me, {
		hasTransform: _transform !== false,
		hasPerspective: _prefixStyle('perspective') in _elementStyle,
		hasTouch: 'ontouchstart' in window,
		//hasPointer: false,//(!('ontouchstart' in window)) &&  (!!(window.PointerEvent || window.MSPointerEvent)), // IE10 is prefixed
		hasPointer: AscCommon.AscBrowser.isIE ? ((!('ontouchstart' in window)) &&  (!!(window.PointerEvent || window.MSPointerEvent))) : false,
		hasTransition: _prefixStyle('transition') in _elementStyle
	});

	/*
	This should find all Android browsers lower than build 535.19 (both stock browser and webview)
	- galaxy S2 is ok
    - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1`
    - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
   - galaxy S3 is badAndroid (stock brower, webview)
     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
   - galaxy S4 is badAndroid (stock brower, webview)
     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
   - galaxy S5 is OK
     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
   - galaxy S6 is OK
     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
  */
	me.isBadAndroid = (function() {
		var appVersion = window.navigator.appVersion;
		// Android browser is not a chrome browser.
		if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) {
			var safariVersion = appVersion.match(/Safari\/(\d+.\d)/);
			if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) {
				return parseFloat(safariVersion[1]) < 535.19;
			} else {
				return true;
			}
		} else {
			return false;
		}
	})();

	me.extend(me.style = {}, {
		transform: _transform,
		transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
		transitionDuration: _prefixStyle('transitionDuration'),
		transitionDelay: _prefixStyle('transitionDelay'),
		transformOrigin: _prefixStyle('transformOrigin')
	});

	me.hasClass = function (e, c) {
		var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
		return re.test(e.className);
	};

	me.addClass = function (e, c) {
		if ( me.hasClass(e, c) ) {
			return;
		}

		var newclass = e.className.split(' ');
		newclass.push(c);
		e.className = newclass.join(' ');
	};

	me.removeClass = function (e, c) {
		if ( !me.hasClass(e, c) ) {
			return;
		}

		var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
		e.className = e.className.replace(re, ' ');
	};

	me.offset = function (el) {
		var left = -el.offsetLeft,
			top = -el.offsetTop;

		// jshint -W084
		while (el = el.offsetParent) {
			left -= el.offsetLeft;
			top -= el.offsetTop;
		}
		// jshint +W084

		return {
			left: left,
			top: top
		};
	};

	me.preventDefaultException = function (el, exceptions) {
		for ( var i in exceptions ) {
			if ( exceptions[i].test(el[i]) ) {
				return true;
			}
		}

		return false;
	};

	me.extend(me.eventType = {}, {
		touchstart: 1,
		touchmove: 1,
		touchend: 1,

		mousedown: 2,
		mousemove: 2,
		mouseup: 2,

		pointerdown: 3,
		pointermove: 3,
		pointerup: 3,

		MSPointerDown: 3,
		MSPointerMove: 3,
		MSPointerUp: 3
	});

	me.extend(me.ease = {}, {
		quadratic: {
			style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
			fn: function (k) {
				return k * ( 2 - k );
			}
		},
		circular: {
			style: 'cubic-bezier(0.1, 0.57, 0.1, 1)',	// Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1)
			fn: function (k) {
				return Math.sqrt( 1 - ( --k * k ) );
			}
		},
		back: {
			style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
			fn: function (k) {
				var b = 4;
				return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
			}
		},
		bounce: {
			style: '',
			fn: function (k) {
				if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
					return 7.5625 * k * k;
				} else if ( k < ( 2 / 2.75 ) ) {
					return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
				} else if ( k < ( 2.5 / 2.75 ) ) {
					return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
				} else {
					return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
				}
			}
		},
		elastic: {
			style: '',
			fn: function (k) {
				var f = 0.22,
					e = 0.4;

				if ( k === 0 ) { return 0; }
				if ( k == 1 ) { return 1; }

				return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
			}
		}
	});

	me.tap = function (e, eventName) {
		var ev = document.createEvent('Event');
		ev.initEvent(eventName, true, true);
		ev.pageX = e.pageX;
		ev.pageY = e.pageY;
		e.target.dispatchEvent(ev);
	};

	me.click = function (e) {
		var target = e.target,
			ev;

		if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) {
			// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent
			// initMouseEvent is deprecated.
			ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event');
			ev.initEvent('click', true, true);
			ev.view = e.view || window;
			ev.detail = 1;
			ev.screenX = target.screenX || 0;
			ev.screenY = target.screenY || 0;
			ev.clientX = target.clientX || 0;
			ev.clientY = target.clientY || 0;
			ev.ctrlKey = !!e.ctrlKey;
			ev.altKey = !!e.altKey;
			ev.shiftKey = !!e.shiftKey;
			ev.metaKey = !!e.metaKey;
			ev.button = 0;
			ev.relatedTarget = null;
			ev._constructed = true;
			target.dispatchEvent(ev);
		}
	};

	return me;
})();
function IScroll (el, options) {
	this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;
	this.scroller = (typeof options.scroller_id == 'string') ? document.getElementById(options.scroller_id) : this.wrapper.children[0];
	this.scrollerStyle = this.scroller.style;		// cache style for better performance
	this.eventsElement = options.eventsElement;

	this.options = {

		resizeScrollbars: true,

		mouseWheelSpeed: 20,

		snapThreshold: 0.334,

// INSERT POINT: OPTIONS
		disablePointer : !utils.hasPointer,
		disableTouch : utils.hasPointer || !utils.hasTouch,
		disableMouse : utils.hasPointer || utils.hasTouch,
		startX: 0,
		startY: 0,
		scrollY: true,
		directionLockThreshold: 5,
		momentum: true,

		bounce: true,
		bounceTime: 600,
		bounceEasing: '',

		preventDefault: true,
		preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/ },

		HWCompositing: true,
		useTransition: true,
		useTransform: true,
		bindToWrapper: typeof window.onmousedown === "undefined"
	};

	for ( var i in options ) {
		this.options[i] = options[i];
	}

	// Normalize options
	this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';

	this.options.useTransition = utils.hasTransition && this.options.useTransition;
	this.options.useTransform = utils.hasTransform && this.options.useTransform;

	this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;
	this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;

	// If you want eventPassthrough I have to lock one of the axes
	this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;
	this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;

	// With eventPassthrough we also need lockDirection mechanism
	this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
	this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;

	this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;

	this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;

	if ( this.options.tap === true ) {
		this.options.tap = 'tap';
	}

	// https://github.com/cubiq/iscroll/issues/1029
	if (!this.options.useTransition && !this.options.useTransform) {
		if(!(/relative|absolute/i).test(this.scrollerStyle.position)) {
			this.scrollerStyle.position = "relative";
		}
	}

	if ( this.options.shrinkScrollbars == 'scale' ) {
		this.options.useTransition = false;
	}

	this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1;

// INSERT POINT: NORMALIZATION

	// Some defaults
	this.x = 0;
	this.y = 0;
	this.directionX = 0;
	this.directionY = 0;
	this._events = {};

// INSERT POINT: DEFAULTS

	this._init();
	this.refresh();

	this.scrollTo(this.options.startX, this.options.startY);
	this.enable();

	this.isDown = false;
}

IScroll.prototype = {
	version: '5.2.0',

	_init: function () {
		this._initEvents();

		if ( this.options.scrollbars || this.options.indicators ) {
			this._initIndicators();
		}

		if ( this.options.mouseWheel ) {
			this._initWheel();
		}

		if ( this.options.snap ) {
			this._initSnap();
		}

		if ( this.options.keyBindings ) {
			this._initKeys();
		}

// INSERT POINT: _init

	},

	destroy: function () {
		this._initEvents(true);
		clearTimeout(this.resizeTimeout);
 		this.resizeTimeout = null;
		this._execEvent('destroy');
	},

	_transitionEnd: function (e) {
		if ( e.target != this.scroller || !this.isInTransition ) {
			return;
		}

		this._transitionTime();
		if ( !this.resetPosition(this.options.bounceTime) ) {
			this.isInTransition = false;
			this._execEvent('scrollEnd');
		}
	},

	_start: function (e) {
		// React to left mouse button only
		if ( utils.eventType[e.type] != 1 ) {
		  // for button property
		  // http://unixpapa.com/js/mouse.html
		  var button;
	    if (!e.which) {
	      /* IE case */
	      button = (e.button < 2) ? 0 :
	               ((e.button == 4) ? 1 : 2);
	    } else {
	      /* All others */
	      button = e.button;
	    }
			if ( button !== 0 ) {
				return;
			}
		}

		if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {
			return;
		}

		if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
			e.preventDefault();
		}

		var point = e.touches ? e.touches[0] : e,
			pos;

		this.initiated	= utils.eventType[e.type];
		this.moved		= false;
		this.distX		= 0;
		this.distY		= 0;
		this.directionX = 0;
		this.directionY = 0;
		this.directionLocked = 0;

		this.startTime = utils.getTime();

		if ( this.options.useTransition && this.isInTransition ) {
			this._transitionTime();
			this.isInTransition = false;
			pos = this.getComputedPosition();
			this._translate(Math.round(pos.x), Math.round(pos.y));
			this._execEvent('scrollEnd');
		} else if ( !this.options.useTransition && this.isAnimating ) {
			this.isAnimating = false;
			this._execEvent('scrollEnd');
		}

		this.startX    = this.x;
		this.startY    = this.y;
		this.absStartX = this.x;
		this.absStartY = this.y;
		this.pointX    = point.pageX;
		this.pointY    = point.pageY;

		this._execEvent('beforeScrollStart');
	},

	_move: function (e) {
		if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
			return;
		}

		if ( this.options.preventDefault ) {	// increases performance on Android? TODO: check!
			e.preventDefault();
		}

		var point		= e.touches ? e.touches[0] : e,
			deltaX		= point.pageX - this.pointX,
			deltaY		= point.pageY - this.pointY,
			timestamp	= utils.getTime(),
			newX, newY,
			absDistX, absDistY;

		this.pointX		= point.pageX;
		this.pointY		= point.pageY;

		this.distX		+= deltaX;
		this.distY		+= deltaY;
		absDistX		= Math.abs(this.distX);
		absDistY		= Math.abs(this.distY);

		// We need to move at least 10 pixels for the scrolling to initiate
		if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {
			return;
		}

		// If you are scrolling in one direction lock the other
		if ( !this.directionLocked && !this.options.freeScroll ) {
			if ( absDistX > absDistY + this.options.directionLockThreshold ) {
				this.directionLocked = 'h';		// lock horizontally
			} else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {
				this.directionLocked = 'v';		// lock vertically
			} else {
				this.directionLocked = 'n';		// no lock
			}
		}

		if ( this.directionLocked == 'h' ) {
			if ( this.options.eventPassthrough == 'vertical' ) {
				e.preventDefault();
			} else if ( this.options.eventPassthrough == 'horizontal' ) {
				this.initiated = false;
				return;
			}

			deltaY = 0;
		} else if ( this.directionLocked == 'v' ) {
			if ( this.options.eventPassthrough == 'horizontal' ) {
				e.preventDefault();
			} else if ( this.options.eventPassthrough == 'vertical' ) {
				this.initiated = false;
				return;
			}

			deltaX = 0;
		}

		deltaX = this.hasHorizontalScroll ? deltaX : 0;
		deltaY = this.hasVerticalScroll ? deltaY : 0;

		newX = this.x + deltaX;
		newY = this.y + deltaY;

		// Slow down if outside of the boundaries
		if ( newX > 0 || newX < this.maxScrollX ) {
			newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
		}
		if ( newY > 0 || newY < this.maxScrollY ) {
			newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
		}

		this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
		this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;

		if ( !this.moved ) {
			this._execEvent('scrollStart');
		}

		this.moved = true;

		this._translate(newX, newY);

/* REPLACE START: _move */

		if ( timestamp - this.startTime > 300 ) {
			this.startTime = timestamp;
			this.startX = this.x;
			this.startY = this.y;
		}
		
		// !!!
		this._execEvent('scroll');

/* REPLACE END: _move */

	},

	_end: function (e) {
		if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
			return;
		}

		if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
			e.preventDefault();
		}

		var point = e.changedTouches ? e.changedTouches[0] : e,
			momentumX,
			momentumY,
			duration = utils.getTime() - this.startTime,
			newX = Math.round(this.x),
			newY = Math.round(this.y),
			distanceX = Math.abs(newX - this.startX),
			distanceY = Math.abs(newY - this.startY),
			time = 0,
			easing = '';

		this.isInTransition = 0;
		this.initiated = 0;
		this.endTime = utils.getTime();

		// reset if we are outside of the boundaries
		if ( this.resetPosition(this.options.bounceTime) ) {
			return;
		}

		this.scrollTo(newX, newY);	// ensures that the last position is rounded

		// we scrolled less than 10 pixels
		if ( !this.moved ) {
			if ( this.options.tap ) {
				utils.tap(e, this.options.tap);
			}

			if ( this.options.click ) {
				utils.click(e);
			}

			this._execEvent('scrollCancel');
			return;
		}

		if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) {
			this._execEvent('flick');
			return;
		}

		// start momentum animation if needed
		if ( this.options.momentum && duration < 300 ) {
			momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options.deceleration) : { destination: newX, duration: 0 };
			momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : { destination: newY, duration: 0 };
			newX = momentumX.destination;
			newY = momentumY.destination;
			time = Math.max(momentumX.duration, momentumY.duration);
			this.isInTransition = 1;
		}


		if ( this.options.snap ) {
			var snap = this._nearestSnap(newX, newY);
			this.currentPage = snap;
			time = this.options.snapSpeed || Math.max(
					Math.max(
						Math.min(Math.abs(newX - snap.x), 1000),
						Math.min(Math.abs(newY - snap.y), 1000)
					), 300);
			newX = snap.x;
			newY = snap.y;

			this.directionX = 0;
			this.directionY = 0;
			easing = this.options.bounceEasing;
		}

// INSERT POINT: _end

		if ( newX != this.x || newY != this.y ) {
			// change easing function when scroller goes out of the boundaries
			if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) {
				easing = utils.ease.quadratic;
			}

			this.scrollTo(newX, newY, time, easing);
			return;
		}

		this._execEvent('scrollEnd');
	},

	_resize: function () {
		var that = this;

		clearTimeout(this.resizeTimeout);

		this.resizeTimeout = setTimeout(function () {
			that.refresh();
		}, this.options.resizePolling);
	},

	resetPosition: function (time) {
		var x = this.x,
			y = this.y;

		time = time || 0;

		if ( !this.hasHorizontalScroll || this.x > 0 ) {
			x = 0;
		} else if ( this.x < this.maxScrollX ) {
			x = this.maxScrollX;
		}

		if ( !this.hasVerticalScroll || this.y > 0 ) {
			y = 0;
		} else if ( this.y < this.maxScrollY ) {
			y = this.maxScrollY;
		}

		if ( x == this.x && y == this.y ) {
			return false;
		}

		this.scrollTo(x, y, time, this.options.bounceEasing);

		return true;
	},

	disable: function () {
		this.enabled = false;
	},

	enable: function () {
		this.enabled = true;
	},

	refresh: function (_position) {
		var rf = this.wrapper.offsetHeight;		// Force reflow

		this.wrapperWidth	= this.wrapper.clientWidth;
		this.wrapperHeight	= this.wrapper.clientHeight;

/* REPLACE START: refresh */

		this.scrollerWidth	= this.scroller.offsetWidth;
		this.scrollerHeight	= this.scroller.offsetHeight;

		this.maxScrollX		= this.wrapperWidth - this.scrollerWidth;
		this.maxScrollY		= this.wrapperHeight - this.scrollerHeight;

/* REPLACE END: refresh */

		this.hasHorizontalScroll	= this.options.scrollX && this.maxScrollX < 0;
		this.hasVerticalScroll		= this.options.scrollY && this.maxScrollY < 0;

		if ( !this.hasHorizontalScroll ) {
			this.maxScrollX = 0;
			this.scrollerWidth = this.wrapperWidth;
		}

		if ( !this.hasVerticalScroll ) {
			this.maxScrollY = 0;
			this.scrollerHeight = this.wrapperHeight;
		}

		this.endTime = 0;
		this.directionX = 0;
		this.directionY = 0;

		this.wrapperOffset = utils.offset(this.wrapper);

		this._execEvent('refresh');

		if (_position)
		{
			this.x = _position.X;
			this.y = _position.Y;
		}

		this.resetPosition();

// INSERT POINT: _refresh

	},

	on: function (type, fn) {
		if ( !this._events[type] ) {
			this._events[type] = [];
		}

		this._events[type].push(fn);
	},

	off: function (type, fn) {
		if ( !this._events[type] ) {
			return;
		}

		var index = this._events[type].indexOf(fn);

		if ( index > -1 ) {
			this._events[type].splice(index, 1);
		}
	},

	_execEvent: function (type) {
		if ( !this._events[type] ) {
			return;
		}

		var i = 0,
			l = this._events[type].length;

		if ( !l ) {
			return;
		}

		for ( ; i < l; i++ ) {
			this._events[type][i].apply(this, [].slice.call(arguments, 1));
		}
	},

	scrollBy: function (x, y, time, easing) {
		x = this.x + x;
		y = this.y + y;
		time = time || 0;

		this.scrollTo(x, y, time, easing);
	},

	scrollTo: function (x, y, time, easing) {
		easing = easing || utils.ease.circular;

		this.isInTransition = this.options.useTransition && time > 0;
		var transitionType = this.options.useTransition && easing.style;
		if ( !time || transitionType ) {
				if(transitionType) {
					this._transitionTimingFunction(easing.style);
					this._transitionTime(time);
				}
			this._translate(x, y);
		} else {
			this._animate(x, y, time, easing.fn);
		}
	},

	scrollToElement: function (el, time, offsetX, offsetY, easing) {
		el = el.nodeType ? el : this.scroller.querySelector(el);

		if ( !el ) {
			return;
		}

		var pos = utils.offset(el);

		pos.left -= this.wrapperOffset.left;
		pos.top  -= this.wrapperOffset.top;

		// if offsetX/Y are true we center the element to the screen
		if ( offsetX === true ) {
			offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2);
		}
		if ( offsetY === true ) {
			offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2);
		}

		pos.left -= offsetX || 0;
		pos.top  -= offsetY || 0;

		pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;
		pos.top  = pos.top  > 0 ? 0 : pos.top  < this.maxScrollY ? this.maxScrollY : pos.top;

		time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time;

		this.scrollTo(pos.left, pos.top, time, easing);
	},

	_transitionTime: function (time) {
		if (!this.options.useTransition) {
			return;
		}
		time = time || 0;
		var durationProp = utils.style.transitionDuration;
		if(!durationProp) {
			return;
		}

		this.scrollerStyle[durationProp] = time + 'ms';

		if ( !time && utils.isBadAndroid ) {
			this.scrollerStyle[durationProp] = '0.0001ms';
			// remove 0.0001ms
			var self = this;
			rAF(function() {
				if(self.scrollerStyle[durationProp] === '0.0001ms') {
					self.scrollerStyle[durationProp] = '0s';
				}
			});
		}


		if ( this.indicators ) {
			for ( var i = this.indicators.length; i--; ) {
				this.indicators[i].transitionTime(time);
			}
		}


// INSERT POINT: _transitionTime

	},

	_transitionTimingFunction: function (easing) {
		this.scrollerStyle[utils.style.transitionTimingFunction] = easing;


		if ( this.indicators ) {
			for ( var i = this.indicators.length; i--; ) {
				this.indicators[i].transitionTimingFunction(easing);
			}
		}


// INSERT POINT: _transitionTimingFunction

	},

	_translate: function (x, y) {
		if ( this.options.useTransform ) {

/* REPLACE START: _translate */

			this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;

/* REPLACE END: _translate */

		} else {
			x = Math.round(x);
			y = Math.round(y);
			this.scrollerStyle.left = x + 'px';
			this.scrollerStyle.top = y + 'px';
		}

		this.x = x;
		this.y = y;


	if ( this.indicators ) {
		for ( var i = this.indicators.length; i--; ) {
			this.indicators[i].updatePosition();
		}
	}


// INSERT POINT: _translate

	},

	_initEvents: function (remove) {

		if (typeof this.eventsElement == "string")
		{
			var _element = document.getElementById(this.eventsElement);
			if (!_element)
				return;
			this.eventsElement = _element;
		}

		var eventType = remove ? utils.removeEvent : utils.addEvent,
			target = this.options.bindToWrapper ? (this.eventsElement ? this.eventsElement : this.wrapper) : window;

		var _wrapper = this.eventsElement ? this.eventsElement : this.wrapper;

		if (this.options.resizeDetect)
		{
			eventType(window, 'orientationchange', this);
			eventType(window, 'resize', this);
		}

		if ( this.options.click ) {
			eventType(_wrapper, 'click', this, true);
		}

		if ( !this.options.disableMouse ) {
			eventType(_wrapper, 'mousedown', this);
			eventType(target, 'mousemove', this);
			eventType(target, 'mousecancel', this);
			eventType(target, 'mouseup', this);
		}

		if ( utils.hasPointer && !this.options.disablePointer ) {
			eventType(_wrapper, utils.prefixPointerEvent('pointerdown'), this);
			eventType(target, utils.prefixPointerEvent('pointermove'), this);
			eventType(target, utils.prefixPointerEvent('pointercancel'), this);
			eventType(target, utils.prefixPointerEvent('pointerup'), this);
		}

		if ( utils.hasTouch && !this.options.disableTouch ) {
			eventType(_wrapper, 'touchstart', this);
			eventType(target, 'touchmove', this);
			eventType(target, 'touchcancel', this);
			eventType(target, 'touchend', this);
		}

		eventType(this.scroller, 'transitionend', this);
		eventType(this.scroller, 'webkitTransitionEnd', this);
		eventType(this.scroller, 'oTransitionEnd', this);
		eventType(this.scroller, 'MSTransitionEnd', this);
	},

	getComputedPosition: function () {
		var matrix = window.getComputedStyle(this.scroller, null),
			x, y;

		if ( this.options.useTransform ) {
			matrix = matrix[utils.style.transform].split(')')[0].split(', ');
			x = +(matrix[12] || matrix[4]);
			y = +(matrix[13] || matrix[5]);
		} else {
			x = +matrix.left.replace(/[^-\d.]/g, '');
			y = +matrix.top.replace(/[^-\d.]/g, '');
		}

		return { x: x, y: y };
	},
	_initIndicators: function () {
		var interactive = this.options.interactiveScrollbars,
			customStyle = typeof this.options.scrollbars != 'string',
			indicators = [],
			indicator;

		var that = this;

		this.indicators = [];

		if ( this.options.scrollbars ) {
			// Vertical scrollbar
			if ( this.options.scrollY ) {
				indicator = {
					el: createDefaultScrollbar('v', interactive, this.options.scrollbars),
					interactive: interactive,
					defaultScrollbars: true,
					customStyle: customStyle,
					resize: this.options.resizeScrollbars,
					shrink: this.options.shrinkScrollbars,
					fade: this.options.fadeScrollbars,
					listenX: false
				};

				this.wrapper.appendChild(indicator.el);
				indicators.push(indicator);
			}

			// Horizontal scrollbar
			if ( this.options.scrollX ) {
				indicator = {
					el: createDefaultScrollbar('h', interactive, this.options.scrollbars),
					interactive: interactive,
					defaultScrollbars: true,
					customStyle: customStyle,
					resize: this.options.resizeScrollbars,
					shrink: this.options.shrinkScrollbars,
					fade: this.options.fadeScrollbars,
					listenY: false
				};

				this.wrapper.appendChild(indicator.el);
				indicators.push(indicator);
			}
		}

		if ( this.options.indicators ) {
			// TODO: check concat compatibility
			indicators = indicators.concat(this.options.indicators);
		}

		for ( var i = indicators.length; i--; ) {
			this.indicators.push( new Indicator(this, indicators[i]) );
		}

		// TODO: check if we can use array.map (wide compatibility and performance issues)
		function _indicatorsMap (fn) {
			if (that.indicators) {
				for ( var i = that.indicators.length; i--; ) {
					fn.call(that.indicators[i]);
				}
			}
		}

		if ( this.options.fadeScrollbars ) {
			this.on('scrollEnd', function () {
				_indicatorsMap(function () {
					this.fade();
				});
			});

			this.on('scrollCancel', function () {
				_indicatorsMap(function () {
					this.fade();
				});
			});

			this.on('scrollStart', function () {
				_indicatorsMap(function () {
					this.fade(1);
				});
			});

			this.on('beforeScrollStart', function () {
				_indicatorsMap(function () {
					this.fade(1, true);
				});
			});
		}


		this.on('refresh', function () {
			_indicatorsMap(function () {
				this.refresh();
			});
		});

		this.on('destroy', function () {
			_indicatorsMap(function () {
				this.destroy();
			});

			delete this.indicators;
		});
	},

	_initWheel: function () {
		utils.addEvent(this.wrapper, 'wheel', this);
		utils.addEvent(this.wrapper, 'mousewheel', this);
		utils.addEvent(this.wrapper, 'DOMMouseScroll', this);

		this.on('destroy', function () {
			clearTimeout(this.wheelTimeout);
			this.wheelTimeout = null;
			utils.removeEvent(this.wrapper, 'wheel', this);
			utils.removeEvent(this.wrapper, 'mousewheel', this);
			utils.removeEvent(this.wrapper, 'DOMMouseScroll', this);
		});
	},

	_wheel: function (e) {
		if ( !this.enabled ) {
			return;
		}

		e.preventDefault();

		var wheelDeltaX, wheelDeltaY,
			newX, newY,
			that = this;

		if ( this.wheelTimeout === undefined ) {
			that._execEvent('scrollStart');
		}

		// Execute the scrollEnd event after 400ms the wheel stopped scrolling
		clearTimeout(this.wheelTimeout);
		this.wheelTimeout = setTimeout(function () {
			if(!that.options.snap) {
				that._execEvent('scrollEnd');
			}
			that.wheelTimeout = undefined;
		}, 400);

		if ( 'deltaX' in e ) {
			if (e.deltaMode === 1) {
				wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed;
				wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed;
			} else {
				wheelDeltaX = -e.deltaX;
				wheelDeltaY = -e.deltaY;
			}
		} else if ( 'wheelDeltaX' in e ) {
			wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed;
			wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed;
		} else if ( 'wheelDelta' in e ) {
			wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed;
		} else if ( 'detail' in e ) {
			wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed;
		} else {
			return;
		}

		wheelDeltaX *= this.options.invertWheelDirection;
		wheelDeltaY *= this.options.invertWheelDirection;

		if ( !this.hasVerticalScroll ) {
			wheelDeltaX = wheelDeltaY;
			wheelDeltaY = 0;
		}

		if ( this.options.snap ) {
			newX = this.currentPage.pageX;
			newY = this.currentPage.pageY;

			if ( wheelDeltaX > 0 ) {
				newX--;
			} else if ( wheelDeltaX < 0 ) {
				newX++;
			}

			if ( wheelDeltaY > 0 ) {
				newY--;
			} else if ( wheelDeltaY < 0 ) {
				newY++;
			}

			this.goToPage(newX, newY);

			return;
		}

		newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0);
		newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0);

		this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0;
		this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0;

		if ( newX > 0 ) {
			newX = 0;
		} else if ( newX < this.maxScrollX ) {
			newX = this.maxScrollX;
		}

		if ( newY > 0 ) {
			newY = 0;
		} else if ( newY < this.maxScrollY ) {
			newY = this.maxScrollY;
		}

		this.scrollTo(newX, newY, 0);

// INSERT POINT: _wheel

		// !!!
		this._execEvent('scroll');
	},

	_initSnap: function () {
		this.currentPage = {};

		if ( typeof this.options.snap == 'string' ) {
			this.options.snap = this.scroller.querySelectorAll(this.options.snap);
		}

		this.on('refresh', function () {
			var i = 0, l,
				m = 0, n,
				cx, cy,
				x = 0, y,
				stepX = this.options.snapStepX || this.wrapperWidth,
				stepY = this.options.snapStepY || this.wrapperHeight,
				el;

			this.pages = [];

			if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) {
				return;
			}

			if ( this.options.snap === true ) {
				cx = Math.round( stepX / 2 );
				cy = Math.round( stepY / 2 );

				while ( x > -this.scrollerWidth ) {
					this.pages[i] = [];
					l = 0;
					y = 0;

					while ( y > -this.scrollerHeight ) {
						this.pages[i][l] = {
							x: Math.max(x, this.maxScrollX),
							y: Math.max(y, this.maxScrollY),
							width: stepX,
							height: stepY,
							cx: x - cx,
							cy: y - cy
						};

						y -= stepY;
						l++;
					}

					x -= stepX;
					i++;
				}
			} else {
				el = this.options.snap;
				l = el.length;
				n = -1;

				for ( ; i < l; i++ ) {
					if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) {
						m = 0;
						n++;
					}

					if ( !this.pages[m] ) {
						this.pages[m] = [];
					}

					x = Math.max(-el[i].offsetLeft, this.maxScrollX);
					y = Math.max(-el[i].offsetTop, this.maxScrollY);
					cx = x - Math.round(el[i].offsetWidth / 2);
					cy = y - Math.round(el[i].offsetHeight / 2);

					this.pages[m][n] = {
						x: x,
						y: y,
						width: el[i].offsetWidth,
						height: el[i].offsetHeight,
						cx: cx,
						cy: cy
					};

					if ( x > this.maxScrollX ) {
						m++;
					}
				}
			}

			this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0);

			// Update snap threshold if needed
			if ( this.options.snapThreshold % 1 === 0 ) {
				this.snapThresholdX = this.options.snapThreshold;
				this.snapThresholdY = this.options.snapThreshold;
			} else {
				this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold);
				this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold);
			}
		});

		this.on('flick', function () {
			var time = this.options.snapSpeed || Math.max(
					Math.max(
						Math.min(Math.abs(this.x - this.startX), 1000),
						Math.min(Math.abs(this.y - this.startY), 1000)
					), 300);

			this.goToPage(
				this.currentPage.pageX + this.directionX,
				this.currentPage.pageY + this.directionY,
				time
			);
		});
	},

	_nearestSnap: function (x, y) {
		if ( !this.pages.length ) {
			return { x: 0, y: 0, pageX: 0, pageY: 0 };
		}

		var i = 0,
			l = this.pages.length,
			m = 0;

		// Check if we exceeded the snap threshold
		if ( Math.abs(x - this.absStartX) < this.snapThresholdX &&
			Math.abs(y - this.absStartY) < this.snapThresholdY ) {
			return this.currentPage;
		}

		if ( x > 0 ) {
			x = 0;
		} else if ( x < this.maxScrollX ) {
			x = this.maxScrollX;
		}

		if ( y > 0 ) {
			y = 0;
		} else if ( y < this.maxScrollY ) {
			y = this.maxScrollY;
		}

		for ( ; i < l; i++ ) {
			if ( x >= this.pages[i][0].cx ) {
				x = this.pages[i][0].x;
				break;
			}
		}

		l = this.pages[i].length;

		for ( ; m < l; m++ ) {
			if ( y >= this.pages[0][m].cy ) {
				y = this.pages[0][m].y;
				break;
			}
		}

		if ( i == this.currentPage.pageX ) {
			i += this.directionX;

			if ( i < 0 ) {
				i = 0;
			} else if ( i >= this.pages.length ) {
				i = this.pages.length - 1;
			}

			x = this.pages[i][0].x;
		}

		if ( m == this.currentPage.pageY ) {
			m += this.directionY;

			if ( m < 0 ) {
				m = 0;
			} else if ( m >= this.pages[0].length ) {
				m = this.pages[0].length - 1;
			}

			y = this.pages[0][m].y;
		}

		return {
			x: x,
			y: y,
			pageX: i,
			pageY: m
		};
	},

	goToPage: function (x, y, time, easing) {
		easing = easing || this.options.bounceEasing;

		if ( x >= this.pages.length ) {
			x = this.pages.length - 1;
		} else if ( x < 0 ) {
			x = 0;
		}

		if ( y >= this.pages[x].length ) {
			y = this.pages[x].length - 1;
		} else if ( y < 0 ) {
			y = 0;
		}

		var posX = this.pages[x][y].x,
			posY = this.pages[x][y].y;

		time = time === undefined ? this.options.snapSpeed || Math.max(
			Math.max(
				Math.min(Math.abs(posX - this.x), 1000),
				Math.min(Math.abs(posY - this.y), 1000)
			), 300) : time;

		this.currentPage = {
			x: posX,
			y: posY,
			pageX: x,
			pageY: y
		};

		this.scrollTo(posX, posY, time, easing);
	},

	next: function (time, easing) {
		var x = this.currentPage.pageX,
			y = this.currentPage.pageY;

		x++;

		if ( x >= this.pages.length && this.hasVerticalScroll ) {
			x = 0;
			y++;
		}

		this.goToPage(x, y, time, easing);
	},

	prev: function (time, easing) {
		var x = this.currentPage.pageX,
			y = this.currentPage.pageY;

		x--;

		if ( x < 0 && this.hasVerticalScroll ) {
			x = 0;
			y--;
		}

		this.goToPage(x, y, time, easing);
	},

	_initKeys: function (e) {
		// default key bindings
		var keys = {
			pageUp: 33,
			pageDown: 34,
			end: 35,
			home: 36,
			left: 37,
			up: 38,
			right: 39,
			down: 40
		};
		var i;

		// if you give me characters I give you keycode
		if ( typeof this.options.keyBindings == 'object' ) {
			for ( i in this.options.keyBindings ) {
				if ( typeof this.options.keyBindings[i] == 'string' ) {
					this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCodeAt(0);
				}
			}
		} else {
			this.options.keyBindings = {};
		}

		for ( i in keys ) {
			this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i];
		}

		utils.addEvent(window, 'keydown', this);

		this.on('destroy', function () {
			utils.removeEvent(window, 'keydown', this);
		});
	},

	_key: function (e) {
		if ( !this.enabled ) {
			return;
		}

		var snap = this.options.snap,	// we are using this alot, better to cache it
			newX = snap ? this.currentPage.pageX : this.x,
			newY = snap ? this.currentPage.pageY : this.y,
			now = utils.getTime(),
			prevTime = this.keyTime || 0,
			acceleration = 0.250,
			pos;

		if ( this.options.useTransition && this.isInTransition ) {
			pos = this.getComputedPosition();

			this._translate(Math.round(pos.x), Math.round(pos.y));
			this.isInTransition = false;
		}

		this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0;

		switch ( e.keyCode ) {
			case this.options.keyBindings.pageUp:
				if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
					newX += snap ? 1 : this.wrapperWidth;
				} else {
					newY += snap ? 1 : this.wrapperHeight;
				}
				break;
			case this.options.keyBindings.pageDown:
				if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
					newX -= snap ? 1 : this.wrapperWidth;
				} else {
					newY -= snap ? 1 : this.wrapperHeight;
				}
				break;
			case this.options.keyBindings.end:
				newX = snap ? this.pages.length-1 : this.maxScrollX;
				newY = snap ? this.pages[0].length-1 : this.maxScrollY;
				break;
			case this.options.keyBindings.home:
				newX = 0;
				newY = 0;
				break;
			case this.options.keyBindings.left:
				newX += snap ? -1 : 5 + this.keyAcceleration>>0;
				break;
			case this.options.keyBindings.up:
				newY += snap ? 1 : 5 + this.keyAcceleration>>0;
				break;
			case this.options.keyBindings.right:
				newX -= snap ? -1 : 5 + this.keyAcceleration>>0;
				break;
			case this.options.keyBindings.down:
				newY -= snap ? 1 : 5 + this.keyAcceleration>>0;
				break;
			default:
				return;
		}

		if ( snap ) {
			this.goToPage(newX, newY);
			return;
		}

		if ( newX > 0 ) {
			newX = 0;
			this.keyAcceleration = 0;
		} else if ( newX < this.maxScrollX ) {
			newX = this.maxScrollX;
			this.keyAcceleration = 0;
		}

		if ( newY > 0 ) {
			newY = 0;
			this.keyAcceleration = 0;
		} else if ( newY < this.maxScrollY ) {
			newY = this.maxScrollY;
			this.keyAcceleration = 0;
		}

		this.scrollTo(newX, newY, 0);

		this.keyTime = now;
	},

	_animate: function (destX, destY, duration, easingFn) {
		var that = this,
			startX = this.x,
			startY = this.y,
			startTime = utils.getTime(),
			destTime = startTime + duration;

		function step () {
			var now = utils.getTime(),
				newX, newY,
				easing;

			if ( now >= destTime ) {
				that.isAnimating = false;
				that._translate(destX, destY);

				if ( !that.resetPosition(that.options.bounceTime) ) {
					that._execEvent('scrollEnd');
				}

				return;
			}

			now = ( now - startTime ) / duration;
			easing = easingFn(now);
			newX = ( destX - startX ) * easing + startX;
			newY = ( destY - startY ) * easing + startY;
			that._translate(newX, newY);

			if ( that.isAnimating ) {
				rAF(step);
			}
			
			// !!!
			that._execEvent('scroll');
		}

		this.isAnimating = true;
		step();
	},
	handleEvent: function (e) {
		switch ( e.type )
		{
			case 'touchstart':
			case 'pointerdown':
			case 'MSPointerDown':
			case 'mousedown':
				this.isDown = true;
				this.eventsElement ? this.manager.mainOnTouchStart(e) : this._start(e);
				break;
			case 'touchmove':
			case 'pointermove':
			case 'MSPointerMove':
			case 'mousemove':
				if (this.isDown || e.srcElement == this.eventsElement)
				{
					this.eventsElement ? this.manager.mainOnTouchMove(e) : (e);
				}
				break;
			case 'touchend':
			case 'pointerup':
			case 'MSPointerUp':
			case 'mouseup':
			case 'touchcancel':
			case 'pointercancel':
			case 'MSPointerCancel':
			case 'mousecancel':
				if (this.isDown || e.srcElement == this.eventsElement)
				{
					this.eventsElement ? this.manager.mainOnTouchEnd(e) : this._end(e);
				}
				this.isDown = false;
				break;
			case 'orientationchange':
			case 'resize':
				this._resize();
				break;
			case 'transitionend':
			case 'webkitTransitionEnd':
			case 'oTransitionEnd':
			case 'MSTransitionEnd':
				this._transitionEnd(e);
				break;
			case 'wheel':
			case 'DOMMouseScroll':
			case 'mousewheel':
				this._wheel(e);
				break;
			case 'keydown':
				this._key(e);
				break;
			case 'click':
				if ( this.enabled && !e._constructed ) {
					e.preventDefault();
					e.stopPropagation();
				}
				break;
		}
	}
};
function createDefaultScrollbar (direction, interactive, type) {
	var scrollbar = document.createElement('div'),
		indicator = document.createElement('div');

	if ( type === true ) {
		scrollbar.style.cssText = 'position:absolute;z-index:9999';
		indicator.style.cssText = '-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px';
	}

	indicator.className = 'iScrollIndicator';

	if ( direction == 'h' ) {
		if ( type === true ) {
			scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
			indicator.style.height = '100%';
		}
		scrollbar.className = 'iScrollHorizontalScrollbar';
	} else {
		if ( type === true ) {
			scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
			indicator.style.width = '100%';
		}
		scrollbar.className = 'iScrollVerticalScrollbar';
	}

	scrollbar.style.cssText += ';overflow:hidden';

	if ( !interactive ) {
		scrollbar.style.pointerEvents = 'none';
	}

	scrollbar.appendChild(indicator);

	return scrollbar;
}

function Indicator (scroller, options) {
	this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el;
	this.wrapperStyle = this.wrapper.style;
	this.indicator = this.wrapper.children[0];
	this.indicatorStyle = this.indicator.style;
	this.scroller = scroller;

	this.options = {
		listenX: true,
		listenY: true,
		interactive: false,
		resize: true,
		defaultScrollbars: false,
		shrink: false,
		fade: false,
		speedRatioX: 0,
		speedRatioY: 0
	};

	for ( var i in options ) {
		this.options[i] = options[i];
	}

	this.sizeRatioX = 1;
	this.sizeRatioY = 1;
	this.maxPosX = 0;
	this.maxPosY = 0;

	if ( this.options.interactive ) {
		if ( !this.options.disableTouch ) {
			utils.addEvent(this.indicator, 'touchstart', this);
			utils.addEvent(window, 'touchend', this);
		}
		if ( !this.options.disablePointer ) {
			utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
			utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this);
		}
		if ( !this.options.disableMouse ) {
			utils.addEvent(this.indicator, 'mousedown', this);
			utils.addEvent(window, 'mouseup', this);
		}
	}

	if ( this.options.fade ) {
		this.wrapperStyle[utils.style.transform] = this.scroller.translateZ;
		var durationProp = utils.style.transitionDuration;
		if(!durationProp) {
			return;
		}
		this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms';
		// remove 0.0001ms
		var self = this;
		if(utils.isBadAndroid) {
			rAF(function() {
				if(self.wrapperStyle[durationProp] === '0.0001ms') {
					self.wrapperStyle[durationProp] = '0s';
				}
			});
		}
		this.wrapperStyle.opacity = '0';
	}
}

Indicator.prototype = {
	handleEvent: function (e) {
		switch ( e.type ) {
			case 'touchstart':
			case 'pointerdown':
			case 'MSPointerDown':
			case 'mousedown':
				this._start(e);
				break;
			case 'touchmove':
			case 'pointermove':
			case 'MSPointerMove':
			case 'mousemove':
				this._move(e);
				break;
			case 'touchend':
			case 'pointerup':
			case 'MSPointerUp':
			case 'mouseup':
			case 'touchcancel':
			case 'pointercancel':
			case 'MSPointerCancel':
			case 'mousecancel':
				this._end(e);
				break;
		}
	},

	destroy: function () {
		if ( this.options.fadeScrollbars ) {
			clearTimeout(this.fadeTimeout);
			this.fadeTimeout = null;
		}
		if ( this.options.interactive ) {
			utils.removeEvent(this.indicator, 'touchstart', this);
			utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
			utils.removeEvent(this.indicator, 'mousedown', this);

			utils.removeEvent(window, 'touchmove', this);
			utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
			utils.removeEvent(window, 'mousemove', this);

			utils.removeEvent(window, 'touchend', this);
			utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this);
			utils.removeEvent(window, 'mouseup', this);
		}

		if ( this.options.defaultScrollbars ) {
			this.wrapper.parentNode.removeChild(this.wrapper);
		}
	},

	_start: function (e) {
		var point = e.touches ? e.touches[0] : e;

		e.preventDefault();
		e.stopPropagation();

		this.transitionTime();

		this.initiated = true;
		this.moved = false;
		this.lastPointX	= point.pageX;
		this.lastPointY	= point.pageY;

		this.startTime	= utils.getTime();

		if ( !this.options.disableTouch ) {
			utils.addEvent(window, 'touchmove', this);
		}
		if ( !this.options.disablePointer ) {
			utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this);
		}
		if ( !this.options.disableMouse ) {
			utils.addEvent(window, 'mousemove', this);
		}

		this.scroller._execEvent('beforeScrollStart');
	},

	_move: function (e) {
		var point = e.touches ? e.touches[0] : e,
			deltaX, deltaY,
			newX, newY,
			timestamp = utils.getTime();

		if ( !this.moved ) {
			this.scroller._execEvent('scrollStart');
		}

		this.moved = true;

		deltaX = point.pageX - this.lastPointX;
		this.lastPointX = point.pageX;

		deltaY = point.pageY - this.lastPointY;
		this.lastPointY = point.pageY;

		newX = this.x + deltaX;
		newY = this.y + deltaY;

		this._pos(newX, newY);

// INSERT POINT: indicator._move

		e.preventDefault();
		e.stopPropagation();
	},

	_end: function (e) {
		if ( !this.initiated ) {
			return;
		}

		this.initiated = false;

		e.preventDefault();
		e.stopPropagation();

		utils.removeEvent(window, 'touchmove', this);
		utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
		utils.removeEvent(window, 'mousemove', this);

		if ( this.scroller.options.snap ) {
			var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y);

			var time = this.options.snapSpeed || Math.max(
					Math.max(
						Math.min(Math.abs(this.scroller.x - snap.x), 1000),
						Math.min(Math.abs(this.scroller.y - snap.y), 1000)
					), 300);

			if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) {
				this.scroller.directionX = 0;
				this.scroller.directionY = 0;
				this.scroller.currentPage = snap;
				this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing);
			}
		}

		if ( this.moved ) {
			this.scroller._execEvent('scrollEnd');
		}
	},

	transitionTime: function (time) {
		time = time || 0;
		var durationProp = utils.style.transitionDuration;
		if(!durationProp) {
			return;
		}

		this.indicatorStyle[durationProp] = time + 'ms';

		if ( !time && utils.isBadAndroid ) {
			this.indicatorStyle[durationProp] = '0.0001ms';
			// remove 0.0001ms
			var self = this;
			rAF(function() {
				if(self.indicatorStyle[durationProp] === '0.0001ms') {
					self.indicatorStyle[durationProp] = '0s';
				}
			});
		}
	},

	transitionTimingFunction: function (easing) {
		this.indicatorStyle[utils.style.transitionTimingFunction] = easing;
	},

	refresh: function () {
		this.transitionTime();

		if ( this.options.listenX && !this.options.listenY ) {
			this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none';
		} else if ( this.options.listenY && !this.options.listenX ) {
			this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none';
		} else {
			this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none';
		}

		if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) {
			utils.addClass(this.wrapper, 'iScrollBothScrollbars');
			utils.removeClass(this.wrapper, 'iScrollLoneScrollbar');

			if ( this.options.defaultScrollbars && this.options.customStyle ) {
				if ( this.options.listenX ) {
					this.wrapper.style.right = '8px';
				} else {
					this.wrapper.style.bottom = '8px';
				}
			}
		} else {
			utils.removeClass(this.wrapper, 'iScrollBothScrollbars');
			utils.addClass(this.wrapper, 'iScrollLoneScrollbar');

			if ( this.options.defaultScrollbars && this.options.customStyle ) {
				if ( this.options.listenX ) {
					this.wrapper.style.right = '2px';
				} else {
					this.wrapper.style.bottom = '2px';
				}
			}
		}

		var r = this.wrapper.offsetHeight;	// force refresh

		if ( this.options.listenX ) {
			this.wrapperWidth = this.wrapper.clientWidth;
			if ( this.options.resize ) {
				this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8);
				this.indicatorStyle.width = this.indicatorWidth + 'px';
			} else {
				this.indicatorWidth = this.indicator.clientWidth;
			}

			this.maxPosX = this.wrapperWidth - this.indicatorWidth;

			if ( this.options.shrink == 'clip' ) {
				this.minBoundaryX = -this.indicatorWidth + 8;
				this.maxBoundaryX = this.wrapperWidth - 8;
			} else {
				this.minBoundaryX = 0;
				this.maxBoundaryX = this.maxPosX;
			}

			this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX));
		}

		if ( this.options.listenY ) {
			this.wrapperHeight = this.wrapper.clientHeight;
			if ( this.options.resize ) {
				this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8);
				this.indicatorStyle.height = this.indicatorHeight + 'px';
			} else {
				this.indicatorHeight = this.indicator.clientHeight;
			}

			this.maxPosY = this.wrapperHeight - this.indicatorHeight;

			if ( this.options.shrink == 'clip' ) {
				this.minBoundaryY = -this.indicatorHeight + 8;
				this.maxBoundaryY = this.wrapperHeight - 8;
			} else {
				this.minBoundaryY = 0;
				this.maxBoundaryY = this.maxPosY;
			}

			this.maxPosY = this.wrapperHeight - this.indicatorHeight;
			this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY));
		}

		this.updatePosition();
	},

	updatePosition: function () {
		var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0,
			y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0;

		if ( !this.options.ignoreBoundaries ) {
			if ( x < this.minBoundaryX ) {
				if ( this.options.shrink == 'scale' ) {
					this.width = Math.max(this.indicatorWidth + x, 8);
					this.indicatorStyle.width = this.width + 'px';
				}
				x = this.minBoundaryX;
			} else if ( x > this.maxBoundaryX ) {
				if ( this.options.shrink == 'scale' ) {
					this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8);
					this.indicatorStyle.width = this.width + 'px';
					x = this.maxPosX + this.indicatorWidth - this.width;
				} else {
					x = this.maxBoundaryX;
				}
			} else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) {
				this.width = this.indicatorWidth;
				this.indicatorStyle.width = this.width + 'px';
			}

			if ( y < this.minBoundaryY ) {
				if ( this.options.shrink == 'scale' ) {
					this.height = Math.max(this.indicatorHeight + y * 3, 8);
					this.indicatorStyle.height = this.height + 'px';
				}
				y = this.minBoundaryY;
			} else if ( y > this.maxBoundaryY ) {
				if ( this.options.shrink == 'scale' ) {
					this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8);
					this.indicatorStyle.height = this.height + 'px';
					y = this.maxPosY + this.indicatorHeight - this.height;
				} else {
					y = this.maxBoundaryY;
				}
			} else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) {
				this.height = this.indicatorHeight;
				this.indicatorStyle.height = this.height + 'px';
			}
		}

		this.x = x;
		this.y = y;

		if ( this.scroller.options.useTransform ) {
			this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ;
		} else {
			this.indicatorStyle.left = x + 'px';
			this.indicatorStyle.top = y + 'px';
		}
	},

	_pos: function (x, y) {
		if ( x < 0 ) {
			x = 0;
		} else if ( x > this.maxPosX ) {
			x = this.maxPosX;
		}

		if ( y < 0 ) {
			y = 0;
		} else if ( y > this.maxPosY ) {
			y = this.maxPosY;
		}

		x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x;
		y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y;

		this.scroller.scrollTo(x, y);
	},

	fade: function (val, hold) {
		if ( hold && !this.visible ) {
			return;
		}

		clearTimeout(this.fadeTimeout);
		this.fadeTimeout = null;

		var time = val ? 250 : 500,
			delay = val ? 0 : 300;

		val = val ? '1' : '0';

		this.wrapperStyle[utils.style.transitionDuration] = time + 'ms';

		this.fadeTimeout = setTimeout((function (val) {
			this.wrapperStyle.opacity = val;
			this.visible = +val;
		}).bind(this, val), delay);
	}
};

IScroll.utils = utils;
IScroll.prototype["handleEvent"] = IScroll.prototype.handleEvent;
Indicator.prototype["handleEvent"] = Indicator.prototype.handleEvent;

window.IScroll = IScroll;

})(window, document, Math);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined)
{
	// define after window['AscCommon']
	var AscCommon = window['AscCommon'];
	var global_mouseEvent = AscCommon.global_mouseEvent;

	AscCommon.MobileTouchMode =
		{
			None       : 0,
			Scroll     : 1,
			Zoom       : 2,
			Select     : 3,
			InlineObj  : 4,
			FlowObj    : 5,
			Cursor     : 6,
			TableMove  : 7,
			TableRuler : 8,
			SelectTrack : 9
		};

	AscCommon.MobileTouchContextMenuType =
		{
			None		: 0,
			Target		: 1,
			Select		: 2,
			Object		: 3,
			Slide		: 4
		};

	function MobileTouchContextMenuLastInfo()
	{
		this.targetPos 				= null;
		this.selectText 			= null;
		this.selectCell 			= null;
		this.objectBounds 			= null;
		this.objectSlideThumbnail 	= null;
	}
	MobileTouchContextMenuLastInfo.prototype =
	{
		Clear : function()
		{
			this.targetPos 				= null;
			this.selectText 			= null;
			this.selectCell 			= null;
			this.objectBounds 			= null;
			this.objectSlideThumbnail 	= null;
		},
		CopyTo : function(dst)
		{
			dst.targetPos 				= this.targetPos;
			dst.selectText 				= this.selectText;
			dst.selectCell 				= this.selectCell;
			dst.objectBounds 			= this.objectBounds;
			dst.objectSlideThumbnail 	= this.objectSlideThumbnail;
		}
	};

	AscCommon.MobileTouchContextMenuLastInfo = MobileTouchContextMenuLastInfo;

	AscCommon.MOBILE_SELECT_TRACK_ROUND = 14;
	AscCommon.MOBILE_TABLE_RULER_DIAMOND = 7;

	/*
	config : {
		isSelection : true,
		isTableTrack : true,
		isZoomEnabled : true
	}
	delegate : {
	onTouchDown : function() {},
	onTouchMove : function() {},
	onTouchEnd : function() {}
	*/

	function CMobileDelegateSimple(_manager)
	{
		this.Manager = _manager;
		this.Api = _manager.Api;
	}

	CMobileDelegateSimple.prototype.Init = function()
	{
		this.Manager.iScroll.manager = this.Manager;

		this.Manager.iScroll.on('scroll', function()
		{
			this.manager.delegate.ScrollTo(this);
		});
		this.Manager.iScroll.on('scrollEnd', function()
		{
			this.manager.delegate.ScrollEnd(this);
		});
	};

	CMobileDelegateSimple.prototype.Resize = function()
	{
		return null;
	};
	CMobileDelegateSimple.prototype.GetSelectionTransform = function()
	{
		return null;
	};
	CMobileDelegateSimple.prototype.ConvertCoordsToCursor = function(x, y, page, isCanvas /* делать ли сдвиги на сам редактор */)
	{
		return null;
	};
	CMobileDelegateSimple.prototype.ConvertCoordsFromCursor = function(x, y)
	{
		return null;
	};
	CMobileDelegateSimple.prototype.GetElementOffset = function()
	{
		return null;
	};
	CMobileDelegateSimple.prototype.GetTableDrawing = function()
	{
		return null;
	};
	CMobileDelegateSimple.prototype.GetZoom = function()
	{
		return null;
	};
	CMobileDelegateSimple.prototype.SetZoom = function(_value)
	{
	};
	CMobileDelegateSimple.prototype.GetObjectTrack = function(x, y, page, bSelected, bText)
	{
		return false;
	};
	CMobileDelegateSimple.prototype.GetContextMenuType = function()
	{
		return AscCommon.MobileTouchContextMenuType.None;
	};
	CMobileDelegateSimple.prototype.GetContextMenuInfo = function(info)
	{
		info.Clear();
	};
	CMobileDelegateEditor.prototype.GetContextMenuPosition = function()
	{
		return null;
	};
	CMobileDelegateSimple.prototype.GetZoomFit = function()
	{
		return 100;
	};
	CMobileDelegateSimple.prototype.GetScrollerParent = function()
	{
		return null;
	};
	CMobileDelegateSimple.prototype.GetScrollerSize = function()
	{
		return { W : 100, H : 100 };
	};
	CMobileDelegateSimple.prototype.GetScrollPosition = function()
	{
		return null;
	};
	CMobileDelegateSimple.prototype.ScrollTo = function(_scroll)
	{
		return;
	};
	CMobileDelegateSimple.prototype.ScrollEnd = function(_scroll)
	{
		return;
	};
	CMobileDelegateSimple.prototype.GetSelectionRectsBounds = function()
	{
		return this.LogicDocument.GetSelectionBounds();
	};
	CMobileDelegateSimple.prototype.IsReader = function()
	{
		return false;
	};

	/**
	 * @extends {CMobileDelegateSimple}
	 */
	function CMobileDelegateEditor(_manager)
	{
		CMobileDelegateSimple.call(this, _manager);

		this.HtmlPage 			= this.Api.WordControl;
		this.LogicDocument		= this.Api.WordControl.m_oLogicDocument;
		this.DrawingDocument 	= this.Api.WordControl.m_oDrawingDocument;
	}

	CMobileDelegateEditor.prototype = Object.create(CMobileDelegateSimple.prototype);
	CMobileDelegateEditor.prototype.constructor = CMobileDelegateEditor;

	CMobileDelegateEditor.prototype.GetSelectionTransform = function()
	{
		return this.DrawingDocument.SelectionMatrix;
	};
	CMobileDelegateEditor.prototype.ConvertCoordsToCursor = function(x, y, page, isGlobal)
	{
		return this.DrawingDocument.ConvertCoordsToCursor3(x, y, page, (isGlobal !== false));
	};
	CMobileDelegateEditor.prototype.ConvertCoordsFromCursor = function(x, y)
	{
		return this.DrawingDocument.ConvertCoordsFromCursor2(x, y);
	};
	CMobileDelegateEditor.prototype.GetElementOffset = function()
	{
		var _xOffset = this.HtmlPage.X;
		var _yOffset = this.HtmlPage.Y;

		if (true === this.HtmlPage.m_bIsRuler)
		{
			_xOffset += (5 * g_dKoef_mm_to_pix);
			_yOffset += (7 * g_dKoef_mm_to_pix);
		}

		return { X : _xOffset, Y : _yOffset };
	};
	CMobileDelegateEditor.prototype.GetTableDrawing = function()
	{
		return this.DrawingDocument.TableOutlineDr;
	};
	CMobileDelegateEditor.prototype.GetZoom = function()
	{
		return this.HtmlPage.m_nZoomValue;
	};
	CMobileDelegateEditor.prototype.SetZoom = function(_value)
	{
		this.HtmlPage.m_oApi.zoom(_value);
	};
	CMobileDelegateEditor.prototype.GetObjectTrack = function(x, y, page, bSelected, bText)
	{
		return this.LogicDocument.DrawingObjects.isPointInDrawingObjects3(x, y, page, bSelected, bText);
	};
	CMobileDelegateEditor.prototype.GetContextMenuType = function()
	{
		var _mode = AscCommon.MobileTouchContextMenuType.None;

		if (!this.LogicDocument.IsSelectionUse())
			_mode = AscCommon.MobileTouchContextMenuType.Target;

		if (this.LogicDocument.GetSelectionBounds())
			_mode = AscCommon.MobileTouchContextMenuType.Select;

		if (_mode == 0 && this.LogicDocument.DrawingObjects.getSelectedObjectsBounds())
			_mode = AscCommon.MobileTouchContextMenuType.Object;

		return _mode;
	};
	CMobileDelegateEditor.prototype.GetContextMenuInfo = function(info)
	{
		info.Clear();
		var _info = null;
		var _transform = null;

		var _x = 0;
		var _y = 0;

		var _target = this.LogicDocument.IsSelectionUse();
		if (_target === false)
		{
			/*
			_info = {
				X : this.DrawingDocument.m_dTargetX,
				Y : this.DrawingDocument.m_dTargetY,
				Page : this.DrawingDocument.m_lTargetPage
			};
			*/
			_info = {
				X : this.LogicDocument.TargetPos.X,
				Y : this.LogicDocument.TargetPos.Y,
				Page : this.LogicDocument.TargetPos.PageNum
			};

			_transform = this.DrawingDocument.TextMatrix;
			if (_transform)
			{
				_x = _transform.TransformPointX(_info.X, _info.Y);
				_y = _transform.TransformPointY(_info.X, _info.Y);

				_info.X = _x;
				_info.Y = _y;
			}
			info.targetPos = _info;
			return;
		}

		var _select = this.LogicDocument.GetSelectionBounds();
		if (_select)
		{
			var _rect1 = _select.Start;
			var _rect2 = _select.End;

			_info = {
				X1 : _rect1.X,
				Y1 : _rect1.Y,
				Page1 : _rect1.Page,
				X2 : _rect2.X + _rect2.W,
				Y2 : _rect2.Y + _rect2.H,
				Page2 : _rect2.Page
			};

			_transform = this.DrawingDocument.SelectionMatrix;

			if (_transform)
			{
				_x = _transform.TransformPointX(_info.X1, _info.Y1);
				_y = _transform.TransformPointY(_info.X1, _info.Y1);
				_info.X1 = _x;
				_info.Y1 = _y;

				_x = _transform.TransformPointX(_info.X2, _info.Y2);
				_y = _transform.TransformPointY(_info.X2, _info.Y2);
				_info.X2 = _x;
				_info.Y2 = _y;
			}

			info.selectText = _info;
			return;
		}

		var _object_bounds = this.LogicDocument.DrawingObjects.getSelectedObjectsBounds();
		if (_object_bounds)
		{
			info.objectBounds = {
				X : _object_bounds.minX,
				Y : _object_bounds.minY,
				R : _object_bounds.maxX,
				B : _object_bounds.maxY,
				Page : _object_bounds.pageIndex
			};
		}
	};
	CMobileDelegateEditor.prototype.GetContextMenuPosition = function()
	{
		var _posX = 0;
		var _posY = 0;
		var _page = 0;
		var _transform = null;
		var tmpX, tmpY, tmpX2, tmpY2;
		var _pos = null;

		var _mode = 0;

		var _target = this.LogicDocument.IsSelectionUse();
		if (_target === false)
		{
			_posX = this.DrawingDocument.m_dTargetX;
			_posY = this.DrawingDocument.m_dTargetY;
			_page = this.DrawingDocument.m_lTargetPage;
			_transform = this.DrawingDocument.TextMatrix;

			if (_transform)
			{
				tmpX = _transform.TransformPointX(_posX, _posY);
				tmpY = _transform.TransformPointY(_posX, _posY);
			}
			else
			{
				tmpX = _posX;
				tmpY = _posY;
			}

			_pos = this.DrawingDocument.ConvertCoordsToCursorWR(tmpX, tmpY, _page);
			_posX = _pos.X;
			_posY = _pos.Y;

			_mode = 1;
		}

		var _select = this.LogicDocument.GetSelectionBounds();
		if (_select)
		{
			var _rect1 = _select.Start;
			var _rect2 = _select.End;

			tmpX = _rect1.X;
			tmpY = _rect1.Y;
			tmpX2 = _rect2.X + _rect2.W;
			tmpY2 = _rect2.Y + _rect2.H;

			_transform = this.DrawingDocument.SelectionMatrix;

			if (_transform)
			{
				_posX = _transform.TransformPointX(tmpX, tmpY);
				_posY = _transform.TransformPointY(tmpX, tmpY);

				tmpX = _posX;
				tmpY = _posY;

				_posX = _transform.TransformPointX(tmpX2, tmpY2);
				_posY = _transform.TransformPointY(tmpX2, tmpY2);

				tmpX2 = _posX;
				tmpY2 = _posY;
			}

			_pos = this.DrawingDocument.ConvertCoordsToCursorWR(tmpX, tmpY, _rect1.Page);
			_posX = _pos.X;
			_posY = _pos.Y;

			_pos = this.DrawingDocument.ConvertCoordsToCursorWR(tmpX2, tmpY2, _rect2.Page);
			_posX += _pos.X;
			_posX = _posX >> 1;

			_mode = 2;
		}

		var _object_bounds = this.LogicDocument.DrawingObjects.getSelectedObjectsBounds(true);
		if (_object_bounds)
		{
			_pos = this.DrawingDocument.ConvertCoordsToCursorWR(_object_bounds.minX, _object_bounds.minY, _object_bounds.pageIndex);
			_posX = _pos.X;
			_posY = _pos.Y;

			_pos = this.DrawingDocument.ConvertCoordsToCursorWR(_object_bounds.maxX, _object_bounds.maxY, _object_bounds.pageIndex);
			_posX += _pos.X;
			_posX = _posX >> 1;

			_mode = 3;
		}

		return { X : _posX, Y : _posY, Mode : _mode };
	};
	CMobileDelegateEditor.prototype.GetZoomFit = function()
	{
		var Zoom = 100;

		var w = this.HtmlPage.m_oEditor.AbsolutePosition.R - this.HtmlPage.m_oEditor.AbsolutePosition.L;

		if (0 != this.HtmlPage.m_dDocumentPageWidth)
		{
			Zoom = 100 * (w - 10) / this.HtmlPage.m_dDocumentPageWidth;

			if (Zoom < 5)
				Zoom = 5;

			if (this.HtmlPage.m_oApi.isMobileVersion)
			{
				var _w = this.HtmlPage.m_oEditor.HtmlElement.width;
				if (this.HtmlPage.bIsRetinaSupport)
				{
					_w /= AscCommon.AscBrowser.retinaPixelRatio;
				}
				Zoom = 100 * _w * AscCommon.g_dKoef_pix_to_mm / this.HtmlPage.m_dDocumentPageWidth;
			}
		}

		return (Zoom - 0.5) >> 0;
	};
	CMobileDelegateEditor.prototype.GetScrollerParent = function()
	{
		return this.HtmlPage.m_oMainView.HtmlElement;
	};
	CMobileDelegateEditor.prototype.GetScrollerSize = function()
	{
		return { W : this.HtmlPage.m_dDocumentWidth, H : this.HtmlPage.m_dDocumentHeight };
	};
	CMobileDelegateEditor.prototype.ScrollTo = function(_scroll)
	{
		this.HtmlPage.NoneRepaintPages = (true === _scroll.isAnimating) ? true : false;
		if (_scroll.directionLocked == "v")
		{
			this.HtmlPage.m_oScrollVerApi.scrollToY(-_scroll.y);
		}
		else if (_scroll.directionLocked == "h")
		{
			this.HtmlPage.m_oScrollHorApi.scrollToX(-_scroll.x);
		}
		else if (_scroll.directionLocked == "n")
		{
			this.HtmlPage.m_oScrollHorApi.scrollToX(-_scroll.x);
			this.HtmlPage.m_oScrollVerApi.scrollToY(-_scroll.y);
		}
	};
	CMobileDelegateEditor.prototype.ScrollEnd = function(_scroll)
	{
		this.HtmlPage.NoneRepaintPages = (true === _scroll.isAnimating) ? true : false;
		this.HtmlPage.OnScroll();
		_scroll.manager.OnScrollAnimationEnd();
	};
	CMobileDelegateEditor.prototype.GetSelectionRectsBounds = function()
	{
		return this.LogicDocument.GetSelectionBounds();
	};
	CMobileDelegateEditor.prototype.IsReader = function()
	{
		return (null != this.DrawingDocument.m_oDocumentRenderer);
	};

	CMobileDelegateEditor.prototype.Logic_GetNearestPos = function(x, y, page)
	{
		return this.LogicDocument.Get_NearestPos(page, x, y);
	};
	CMobileDelegateEditor.prototype.Logic_OnMouseDown = function(e, x, y, page)
	{
		return this.LogicDocument.OnMouseDown(e, x, y, page);
	};
	CMobileDelegateEditor.prototype.Logic_OnMouseMove = function(e, x, y, page)
	{
		return this.LogicDocument.OnMouseMove(e, x, y, page);
	};
	CMobileDelegateEditor.prototype.Logic_OnMouseUp = function(e, x, y, page)
	{
		return this.LogicDocument.OnMouseUp(e, x, y, page);
	};
	CMobileDelegateEditor.prototype.Drawing_OnMouseDown = function(e)
	{
		return this.HtmlPage.onMouseDown(e);
	};
	CMobileDelegateEditor.prototype.Drawing_OnMouseMove = function(e)
	{
		return this.HtmlPage.onMouseMove(e);
	};
	CMobileDelegateEditor.prototype.Drawing_OnMouseUp = function(e)
	{
		return this.HtmlPage.onMouseUp(e);
	};

	function CMobileTouchManagerBase(_config)
	{
		this.Api			= null;
		this.Mode 			= AscCommon.MobileTouchMode.None;

		this.IsTouching		= false;

		this.ReadingGlassTime  = 750;
		this.TimeDown          = 0;
		this.DownPoint         = null;
		this.DownPointOriginal = {X : 0, Y : 0};
		this.MoveAfterDown     = false;
		this.MoveMinDist       = 10;

		/* select text */
		this.SelectEnabled = (_config.isSelection !== false);
		this.RectSelect1 = null;
		this.RectSelect2 = null;
		this.PageSelect1 = 0;
		this.PageSelect2 = 0;
		this.RectSelectType = 0; // excel

		this.TrackTargetEps = 20;

		/* zoom */
		this.ZoomEnabled  = (_config.isZoomEnabled !== false);
		this.ZoomDistance = 0;
		this.ZoomValue    = 100;
		this.ZoomValueMin = 50;
		this.ZoomValueMax = 300;

		/* table track */
		this.TableTrackEnabled 	   = (_config.isTableTrack !== false);
		this.TableMovePoint        = null;
		this.TableHorRulerPoints   = null;
		this.TableVerRulerPoints   = null;
		this.TableStartTrack_Check = false;

		this.TableRulersRectOffset = 5;
		this.TableRulersRectSize   = 20;

		this.TableCurrentMoveDir      = -1;
		this.TableCurrentMovePos      = -1;
		this.TableCurrentMoveValue    = 0;
		this.TableCurrentMoveValueOld = 0;

		this.TableCurrentMoveValueMin = null;
		this.TableCurrentMoveValueMax = null;

		/* context menu */
		this.ContextMenuLastMode 		= AscCommon.MobileTouchContextMenuType.None;
		this.ContextMenuLastInfo 		= new AscCommon.MobileTouchContextMenuLastInfo();
		this.ContextMenuLastShow		= false;

		this.ContextMenuLastModeCounter = 0;
		this.ContextMenuShowTimerId 	= -1;

		/* scroll object */
		this.iScroll = null;
		this.iScrollElement	= "mobile_scroller_id";

		/* delegate */
		this.delegate = null;

		/* eventsElement */
		this.eventsElement = _config.eventsElement;

		this.pointerTouchesCoords = {};

		this.IsZoomCheckFit = false;

		this.isShowingContextMenu = false;
		this.isMobileContextMenuShowResize = false;
	}

	CMobileTouchManagerBase.prototype.initEvents = function(_id)
	{
		this.eventsElement = _id;
		this.iScroll.eventsElement = this.eventsElement;
		this.iScroll._initEvents();
	};

	// создание вспомогательного элемента, для прокрутки. по идее потом можно изменить
	// просто на сдвиги. но пока так
	CMobileTouchManagerBase.prototype.CreateScrollerDiv = function(_wrapper)
	{
		var _scroller = document.createElement('div');
		var _style = "position: absolute; z-index: 0; margin: 0; padding: 0; -webkit-tap-highlight-color: rgba(0,0,0,0); width: 100%; heigth: 100%; display: block;";
		_style += "-webkit-transform: translateZ(0); -moz-transform: translateZ(0); -ms-transform: translateZ(0); -o-transform: translateZ(0); transform: translateZ(0);";
		_style += "-webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none;";
		_style += "-webkit-text-size-adjust: none; -moz-text-size-adjust: none; -ms-text-size-adjust: none; -o-text-size-adjust: none; text-size-adjust: none;";
		_scroller.setAttribute("style", _style);

		_scroller.id = this.iScrollElement;
		_wrapper.appendChild(_scroller);
	};

	// здесь загрузка нужных картинок. пока только для таблицы (движение)
	// грузим в конструкторе, используем тогда, когда загружено (asc_complete)
	CMobileTouchManagerBase.prototype.LoadMobileImages = function()
	{
		window.g_table_track_mobile_move = document.createElement("canvas");

		if (AscCommon.AscBrowser.isRetina)
		{
			window.g_table_track_mobile_move.width = (20 * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
			window.g_table_track_mobile_move.height = (20 * AscCommon.AscBrowser.retinaPixelRatio) >> 0;

		}
		else
		{
			window.g_table_track_mobile_move.width = 20;
			window.g_table_track_mobile_move.height = 20;
		}
		window.g_table_track_mobile_move.asc_complete = true;
		window.g_table_track_mobile_move.size = 20;

		var _ctx = window.g_table_track_mobile_move.getContext("2d");
		if (AscCommon.AscBrowser.isRetina)
			_ctx.setTransform(2, 0, 0, 2, 0, 0);

		_ctx.lineWidth = 1;

		var r = 4;
		var w = 19;
		var h = 19;
		var x = 0.5;
		var y = 0.5;

		_ctx.moveTo(x + r, y);
		_ctx.lineTo(x + w - r, y);
		_ctx.quadraticCurveTo(x + w, y, x + w, y + r);
		_ctx.lineTo(x + w, y + h - r);
		_ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
		_ctx.lineTo(x + r, y + h);
		_ctx.quadraticCurveTo(x, y + h, x, y + h - r);
		_ctx.lineTo(x, y + r);
		_ctx.quadraticCurveTo(x, y, x + r, y);

		_ctx.strokeStyle = "#747474";
		_ctx.fillStyle = "#DFDFDF";
		_ctx.fill();
		_ctx.stroke();
		_ctx.beginPath();

		_ctx.moveTo(2, 10);
		_ctx.lineTo(10, 2);
		_ctx.lineTo(18, 10);
		_ctx.lineTo(10, 18);
		_ctx.closePath();

		_ctx.fillStyle = "#146FE1";
		_ctx.fill();
		_ctx.beginPath();

		_ctx.fillStyle = "#DFDFDF";
		_ctx.fillRect(6, 6, 8, 8);
		_ctx.beginPath();
	};

	// onTouchStart => попали ли в якорьки селекта, чтобы не начинать скроллы/зумы
	CMobileTouchManagerBase.prototype.CheckSelectTrack = function()
	{
		if (!this.SelectEnabled)
			return false;

		var _matrix = this.delegate.GetSelectionTransform();
		if (_matrix && global_MatrixTransformer.IsIdentity(_matrix))
			_matrix = null;

		// проверим на попадание в селект - это может произойти на любом mode
		if (null != this.RectSelect1 && null != this.RectSelect2)
		{
			var pos1 = null;
			var pos4 = null;

			if (!_matrix)
			{
				pos1 = this.delegate.ConvertCoordsToCursor(this.RectSelect1.x, this.RectSelect1.y, this.PageSelect1);
				pos4 = this.delegate.ConvertCoordsToCursor(this.RectSelect2.x + this.RectSelect2.w, this.RectSelect2.y + this.RectSelect2.h, this.PageSelect2);
			}
			else
			{
				var _xx1 = _matrix.TransformPointX(this.RectSelect1.x, this.RectSelect1.y);
				var _yy1 = _matrix.TransformPointY(this.RectSelect1.x, this.RectSelect1.y);

				var _xx2 = _matrix.TransformPointX(this.RectSelect2.x + this.RectSelect2.w, this.RectSelect2.y + this.RectSelect2.h);
				var _yy2 = _matrix.TransformPointY(this.RectSelect2.x + this.RectSelect2.w, this.RectSelect2.y + this.RectSelect2.h);

				pos1 = this.delegate.ConvertCoordsToCursor(_xx1, _yy1, this.PageSelect1);
				pos4 = this.delegate.ConvertCoordsToCursor(_xx2, _yy2, this.PageSelect2);
			}

			if (Math.abs(pos1.X - global_mouseEvent.X) < this.TrackTargetEps && Math.abs(pos1.Y - global_mouseEvent.Y) < this.TrackTargetEps)
			{
				this.Mode       = AscCommon.MobileTouchMode.Select;
				this.DragSelect = 1;
			}
			else if (Math.abs(pos4.X - global_mouseEvent.X) < this.TrackTargetEps && Math.abs(pos4.Y - global_mouseEvent.Y) < this.TrackTargetEps)
			{
				this.Mode       = AscCommon.MobileTouchMode.Select;
				this.DragSelect = 2;
			}
		}

		return (this.Mode == AscCommon.MobileTouchMode.Select);
	};

	// onTouchStart => попали ли в якорьки таблицы, чтобы не начинать скроллы/зумы
	CMobileTouchManagerBase.prototype.CheckTableTrack = function()
	{
		if (!this.TableTrackEnabled)
			return false;

		var _eps     = this.TrackTargetEps;
		var bIsTable = false;

		var _table_outline_dr = this.delegate.GetTableDrawing();
		if (this.TableMovePoint != null && _table_outline_dr)
		{
			var _Transform = _table_outline_dr.TableMatrix;
			var _PageNum   = _table_outline_dr.CurrentPageIndex;

			var _PageNumOrigin = _PageNum;

			if (_table_outline_dr.TableOutline)
				_PageNumOrigin = _table_outline_dr.TableOutline.PageNum;

			if (!_Transform || global_MatrixTransformer.IsIdentity(_Transform))
			{
				var _x = global_mouseEvent.X;
				var _y = global_mouseEvent.Y;

				var posLT   = this.delegate.ConvertCoordsToCursor(this.TableMovePoint.X, this.TableMovePoint.Y, _PageNum);
				var _offset = this.TableRulersRectSize + this.TableRulersRectOffset;

				if (_x > (posLT.X - _offset - _eps) && _x < (posLT.X - this.TableRulersRectOffset + _eps) &&
					_y > (posLT.Y - _offset - _eps) && _y < (posLT.Y - this.TableRulersRectOffset + _eps) && (_PageNumOrigin == _PageNum))
				{
					this.Mode = AscCommon.MobileTouchMode.TableMove;
					bIsTable  = true;
				}

				if (!bIsTable)
				{
					if (_y > (posLT.Y - _offset - _eps) && _y < (posLT.Y - this.TableRulersRectOffset + _eps))
					{
						var _len    = this.TableHorRulerPoints.length;
						var _indexF = -1;
						var _minF   = 1000000;
						for (var i = 0; i < _len; i++)
						{
							var posM1 = this.delegate.ConvertCoordsToCursor(this.TableHorRulerPoints[i].C, this.TableMovePoint.Y, _PageNum);
							var _dist = Math.abs(_x - posM1.X);
							if (_minF > _dist)
							{
								_indexF = i;
								_minF   = _dist;
							}
						}

						if (_minF < _eps)
						{
							var _p = this.TableHorRulerPoints[_indexF];

							this.TableCurrentMoveDir = 0;
							this.TableCurrentMovePos = _indexF;

							this.TableCurrentMoveValue    = _p.X;
							this.TableCurrentMoveValueOld = this.TableCurrentMoveValue;
							this.Mode                     = AscCommon.MobileTouchMode.TableRuler;

							if (_indexF == 0)
							{
								this.TableCurrentMoveValueMin = this.TableMovePoint.X;
							}
							else
							{
								this.TableCurrentMoveValueMin = this.TableHorRulerPoints[_indexF - 1].X + this.TableHorRulerPoints[_indexF - 1].W;
							}

							if (_indexF < (_len - 1))
							{
								this.TableCurrentMoveValueMax = this.TableHorRulerPoints[_indexF + 1].X;
							}
							else
							{
								this.TableCurrentMoveValueMax = null;
							}

							bIsTable = true;
						}
					}

					if (!bIsTable && _x >= (posLT.X - _offset - _eps) && _x <= (posLT.X - this.TableRulersRectOffset + _eps))
					{
						var _len    = this.TableVerRulerPoints.length;
						var _indexF = -1;
						var _minF   = 1000000;
						for (var i = 0; i < _len; i++)
						{
							var posM1 = this.delegate.ConvertCoordsToCursor(this.TableMovePoint.X, this.TableVerRulerPoints[i].Y, _PageNum);
							var posM2 = this.delegate.ConvertCoordsToCursor(this.TableMovePoint.X, this.TableVerRulerPoints[i].Y + this.TableVerRulerPoints[i].H, _PageNum);

							if (_y >= (posM1.Y - _eps) && _y <= (posM2.Y + _eps))
							{
								var _dist = Math.abs(_y - ((posM1.Y + posM2.Y) / 2));
								if (_minF > _dist)
								{
									_indexF = i;
									_minF   = _dist;
								}
							}
						}

						if (_indexF != -1)
						{
							var _p = this.TableVerRulerPoints[_indexF];

							this.TableCurrentMoveDir = 1;
							this.TableCurrentMovePos = _indexF;

							this.TableCurrentMoveValue    = _p.Y;
							this.TableCurrentMoveValueOld = this.TableCurrentMoveValue;
							this.Mode                     = AscCommon.MobileTouchMode.TableRuler;

							if (_indexF == 0)
							{
								this.TableCurrentMoveValueMin = this.TableMovePoint.Y;
							}
							else
							{
								this.TableCurrentMoveValueMin = this.TableVerRulerPoints[_indexF - 1].Y + this.TableVerRulerPoints[_indexF - 1].H;
							}

							if (_indexF < (_len - 1))
							{
								this.TableCurrentMoveValueMax = this.TableVerRulerPoints[_indexF + 1].Y;
							}
							else
							{
								this.TableCurrentMoveValueMax = null;
							}

							bIsTable = true;
						}
					}
				}
			}
			else
			{
				var pos = this.delegate.ConvertCoordsFromCursor(global_mouseEvent.X, global_mouseEvent.Y);
				if (pos.Page == _PageNum)
				{
					var _invert = global_MatrixTransformer.Invert(_Transform);
					var _posx   = _invert.TransformPointX(pos.X, pos.Y);
					var _posy   = _invert.TransformPointY(pos.X, pos.Y);

					var _koef = AscCommon.g_dKoef_pix_to_mm * 100 / this.delegate.GetZoom();
					var _eps1 = this.TrackTargetEps * _koef;

					var _offset1 = this.TableRulersRectOffset * _koef;
					var _offset2 = _offset1 + this.TableRulersRectSize * _koef;
					if ((_posx >= (this.TableMovePoint.X - _offset2 - _eps1)) && (_posx <= (this.TableMovePoint.X - _offset1 + _eps1)) &&
						(_posy >= (this.TableMovePoint.Y - _offset2 - _eps1)) && (_posy <= (this.TableMovePoint.Y - _offset1 + _eps1)))
					{
						this.Mode = AscCommon.MobileTouchMode.TableMove;
						bIsTable  = true;
					}

					if (!bIsTable)
					{
						if (_posy > (this.TableMovePoint.Y - _offset2 - _eps1) && _posy < (this.TableMovePoint.Y - _offset1 + _eps1))
						{
							var _len = this.TableHorRulerPoints.length;
							for (var i = 0; i < _len; i++)
							{
								var _p = this.TableHorRulerPoints[i];

								if (_posx > (_p.X - _eps1) && _posx < (_p.X + _p.W + _eps1))
								{
									this.TableCurrentMoveDir = 0;
									this.TableCurrentMovePos = i;

									this.TableCurrentMoveValue    = this.TableHorRulerPoints[i].X;
									this.TableCurrentMoveValueOld = this.TableCurrentMoveValue;
									this.Mode                     = AscCommon.MobileTouchMode.TableRuler;

									if (i == 0)
									{
										this.TableCurrentMoveValueMin = this.TableMovePoint.X;
									}
									else
									{
										this.TableCurrentMoveValueMin = this.TableHorRulerPoints[i - 1].X + this.TableHorRulerPoints[i - 1].W;
									}

									if (i < (_len - 1))
									{
										this.TableCurrentMoveValueMax = this.TableHorRulerPoints[i + 1].X;
									}
									else
									{
										this.TableCurrentMoveValueMax = null;
									}

									bIsTable = true;
									break;
								}
							}
						}

						if (!bIsTable && _posx >= (this.TableMovePoint.X - _offset2 - _eps1) && _posx <= (this.TableMovePoint.X - _offset1 + _eps1))
						{
							var _len = this.TableVerRulerPoints.length;
							for (var i = 0; i < _len; i++)
							{
								var _p = this.TableVerRulerPoints[i];

								if (_posy >= (_p.Y - _eps1) && _posy <= (_p.Y + _p.H + _eps1))
								{
									this.TableCurrentMoveDir = 1;
									this.TableCurrentMovePos = i;

									this.TableCurrentMoveValue    = this.TableVerRulerPoints[i].Y;
									this.TableCurrentMoveValueOld = this.TableCurrentMoveValue;
									this.Mode                     = AscCommon.MobileTouchMode.TableRuler;

									if (i == 0)
									{
										this.TableCurrentMoveValueMin = this.TableMovePoint.Y;
									}
									else
									{
										this.TableCurrentMoveValueMin = this.TableVerRulerPoints[i - 1].Y + this.TableVerRulerPoints[i - 1].H;
									}

									if (i < (_len - 1))
									{
										this.TableCurrentMoveValueMax = this.TableVerRulerPoints[i + 1].Y;
									}
									else
									{
										this.TableCurrentMoveValueMax = null;
									}

									bIsTable = true;
									break;
								}
							}
						}
					}
				}
			}
		}

		return bIsTable;
	};

	// onTouchStart => попали ли в якорьки трека объекта (шейп, картинка), чтобы не начинать скроллы/зумы
	CMobileTouchManagerBase.prototype.CheckObjectTrack = function()
	{
		var pos = this.delegate.ConvertCoordsFromCursor(global_mouseEvent.X, global_mouseEvent.Y);
		global_mouseEvent.KoefPixToMM = 5;
		if (this.delegate.GetObjectTrack(pos.X, pos.Y, pos.Page, true))
		{
			this.Mode      = AscCommon.MobileTouchMode.FlowObj;
		}
		else
		{
			this.Mode = AscCommon.MobileTouchMode.None;
		}
		global_mouseEvent.KoefPixToMM = 1;

		return (AscCommon.MobileTouchMode.FlowObj == this.Mode);
	};

	CMobileTouchManagerBase.prototype.CheckObjectTrackBefore = function()
	{
		var pos = this.delegate.ConvertCoordsFromCursor(global_mouseEvent.X, global_mouseEvent.Y);
		global_mouseEvent.KoefPixToMM = 5;
		var bResult = this.delegate.GetObjectTrack(pos.X, pos.Y, pos.Page, false);
		global_mouseEvent.KoefPixToMM = 1;
		return bResult;
	};
	CMobileTouchManagerBase.prototype.CheckObjectText = function()
	{
		var pos = this.delegate.ConvertCoordsFromCursor(global_mouseEvent.X, global_mouseEvent.Y);
		global_mouseEvent.KoefPixToMM = 5;
		var bResult = this.delegate.GetObjectTrack(pos.X, pos.Y, pos.Page, false, true);
		global_mouseEvent.KoefPixToMM = 1;
		return bResult;
	};

	// в мобильной версии - меньше, чем "по ширине" - не делаем
	CMobileTouchManagerBase.prototype.CheckZoomCriticalValues = function(zoomMin)
	{
		if (zoomMin !== undefined)
		{
			this.ZoomValueMin = zoomMin;
			return;
		}

		var _new_value = this.delegate.GetZoomFit();

		this.ZoomValueMin = _new_value;
		if (this.ZoomValue < this.ZoomValueMin)
		{
			this.ZoomValue = this.ZoomValueMin;
			this.delegate.SetZoom(this.ZoomValue);
		}
	};

	CMobileTouchManagerBase.prototype.BeginZoomCheck = function()
	{
		var _zoomCurrent = this.delegate.GetZoom();
		var _zoomFit = this.delegate.GetZoomFit();
		this.IsZoomCheckFit = (_zoomCurrent == _zoomFit) ? true : false;

	};
	CMobileTouchManagerBase.prototype.EndZoomCheck = function()
	{
		var _zoomCurrent = this.delegate.GetZoom();
		var _zoomFit = this.delegate.GetZoomFit();

		if (this.IsZoomCheckFit || _zoomCurrent < _zoomFit)
			this.delegate.SetZoom(this.delegate.GetZoomFit());
		this.IsZoomCheckFit = false;
	};

	// изменился размер документа/экрана => нужно перескитать вспомогательный элемент для скролла
	CMobileTouchManagerBase.prototype.Resize = function()
	{
		this.delegate.Resize();
		this.CheckZoomCriticalValues();
		if (this.iScroll != null)
		{
			var _size = this.delegate.GetScrollerSize();
			this.iScroll.scroller.style.width = _size.W + "px";
			this.iScroll.scroller.style.height = _size.H + "px";

			var _position = this.delegate.GetScrollPosition();
			this.iScroll.refresh(_position);
		}

		if (this.isMobileContextMenuShowResize)
			this.SendShowContextMenu();
	};

	CMobileTouchManagerBase.prototype.Resize_Before = function()
	{
		this.isMobileContextMenuShowResize = this.isShowingContextMenu;
	};
	CMobileTouchManagerBase.prototype.Resize_After = function()
	{
		if (this.isMobileContextMenuShowResize)
			this.SendShowContextMenu();
		this.isMobileContextMenuShowResize = false;
	};

	// есть ли тач или анимационный скролл/зум
	CMobileTouchManagerBase.prototype.IsWorkedPosition = function()
	{
		if (this.IsTouching)
			return true;

		if (this.iScroll && this.iScroll.isAnimating)
			return true;

		return false;
	};

	// удаление вспомогательного элемента
	CMobileTouchManagerBase.prototype.Destroy = function()
	{
		var _scroller = document.getElementById(this.iScrollElement);
		this.delegate.GetScrollerParent().removeChild(_scroller);

		if (this.iScroll != null)
			this.iScroll.destroy();
	};

	/* contect menu */
	CMobileTouchManagerBase.prototype.SendShowContextMenu = function()
	{
		if (-1 != this.ContextMenuShowTimerId)
			clearTimeout(this.ContextMenuShowTimerId);

		this.isShowingContextMenu = true;

		var that             = this;
		this.ContextMenuShowTimerId = setTimeout(function()
		{
			that.ContextMenuShowTimerId = -1;
			var _pos = that.delegate.GetContextMenuPosition();
			that.Api.sendEvent("asc_onShowPopMenu", _pos.X, _pos.Y, (_pos.Mode > 1) ? true : false);
		}, 500);
	};

	CMobileTouchManagerBase.prototype.CheckContextMenuTouchEndOld = function(isCheck, isSelectTouch, isGlassTouch, isTableRuler)
	{
		// isCheck: если пришли сюда после скролла или зума (или их анимации) - то не нужно проверять состояние редактора.
		// Нужно проверять последнее сохраненной состояние

		if (isCheck)
		{
			var _mode = this.delegate.GetContextMenuType();
			if (_mode == this.ContextMenuLastMode)
			{
				this.ContextMenuLastModeCounter++;
				this.ContextMenuLastModeCounter &= 0x01;
			}
			else
			{
				this.ContextMenuLastModeCounter = 0;
			}

			this.ContextMenuLastMode = _mode;
		}

		if (this.ContextMenuLastMode > AscCommon.MobileTouchContextMenuType.None && 1 == this.ContextMenuLastModeCounter)
			this.SendShowContextMenu();
	};

	CMobileTouchManagerBase.prototype.CheckContextMenuTouchEnd = function(isCheck, isSelectTouch, isGlassTouch, isTableRuler)
	{
		// isCheck: если пришли сюда после скролла или зума (или их анимации) - то не нужно проверять состояние редактора.
		// Нужно проверять последнее сохраненной состояние

		var isShowContextMenu = false;
		var isSelectCell = false;
		if (isCheck)
		{
			var oldLastInfo = new AscCommon.MobileTouchContextMenuLastInfo();
			this.ContextMenuLastInfo.CopyTo(oldLastInfo);

			var oldLasdMode = this.ContextMenuLastMode;

			this.ContextMenuLastMode = this.delegate.GetContextMenuType();
			this.delegate.GetContextMenuInfo(this.ContextMenuLastInfo);

			isSelectCell = (this.ContextMenuLastInfo.selectCell != null);

			var _data1 = null;
			var _data2 = null;

			if (this.ContextMenuLastMode == oldLasdMode)
			{
				var isEqual = false;
				switch (this.ContextMenuLastMode)
				{
					case AscCommon.MobileTouchContextMenuType.Target:
					{
						_data1 = this.ContextMenuLastInfo.targetPos;
						_data2 = oldLastInfo.targetPos;

						if (_data1 && _data2)
						{
							if (_data1.Page == _data1.Page &&
								Math.abs(_data1.X - _data2.X) < 10 &&
								Math.abs(_data1.Y - _data2.Y) < 10)
							{
								isEqual = true;
							}
						}

						break;
					}
					case AscCommon.MobileTouchContextMenuType.Select:
					{
						_data1 = this.ContextMenuLastInfo.selectText;
						_data2 = oldLastInfo.selectText;

						if (_data1 && _data2)
						{
							if (_data1.Page1 == _data2.Page1 && _data1.Page2 == _data2.Page2 &&
								Math.abs(_data1.X1 - _data2.X1) < 0.1 &&
								Math.abs(_data1.Y1 - _data2.Y1) < 0.1 &&
								Math.abs(_data1.X2 - _data2.X2) < 0.1 &&
								Math.abs(_data1.Y2 - _data2.Y2) < 0.1)
							{
								isEqual = true;
							}
						}
						else
						{
							_data1 = this.ContextMenuLastInfo.selectCell;
							_data2 = oldLastInfo.selectCell;

							if (_data1 && _data2)
							{
								if (Math.abs(_data1.X - _data2.X) < 0.1 &&
									Math.abs(_data1.Y - _data2.Y) < 0.1 &&
									Math.abs(_data1.W - _data2.W) < 0.1 &&
									Math.abs(_data1.H - _data2.H) < 0.1)
								{
									isEqual = true;
								}
							}
						}

						break;
					}
					case AscCommon.MobileTouchContextMenuType.Object:
					{
						_data1 = this.ContextMenuLastInfo.objectBounds;
						_data2 = oldLastInfo.objectBounds;

						if (_data1 && _data2)
						{
							if (_data1.Page == _data2.Page &&
								Math.abs(_data1.X - _data2.X) < 0.1 &&
								Math.abs(_data1.Y - _data2.Y) < 0.1 &&
								Math.abs(_data1.R - _data2.R) < 0.1 &&
								Math.abs(_data1.B - _data2.B) < 0.1)
							{
								isEqual = true;
							}
						}

						break;
					}
					case AscCommon.MobileTouchContextMenuType.Slide:
					{
						_data1 = this.ContextMenuLastInfo.objectSlideThumbnail;
						_data2 = oldLastInfo.objectSlideThumbnail;

						if (_data1 && _data2)
						{
							if (_data1.Slide == _data2.Slide)
								isEqual = true;
						}
						else
						{
							isEqual = true;
						}

						break;
					}
					default:
						break;
				}
			}

			// после таблиц не показываем меню
			if (isTableRuler)
				isEqual = false;

			if (this.ContextMenuLastMode == oldLasdMode && isEqual)
			{
				this.ContextMenuLastModeCounter++;
				this.ContextMenuLastModeCounter &= 0x01;
			}
			else
			{
				this.ContextMenuLastModeCounter = 0;
			}

			switch (this.ContextMenuLastMode)
			{
				case AscCommon.MobileTouchContextMenuType.Target:
				{
					isShowContextMenu = (1 == this.ContextMenuLastModeCounter);
					break;
				}
				case AscCommon.MobileTouchContextMenuType.Select:
				{
					if (isSelectCell)
						isShowContextMenu = (1 == this.ContextMenuLastModeCounter);
					else
						isShowContextMenu = true;
					break;
				}
				case AscCommon.MobileTouchContextMenuType.Object:
				{
					isShowContextMenu = (0 == this.ContextMenuLastModeCounter);
					break;
				}
				case AscCommon.MobileTouchContextMenuType.Slide:
				{
					isShowContextMenu = (1 == this.ContextMenuLastModeCounter);
					break;
				}
				default:
				{
					isShowContextMenu = (1 == this.ContextMenuLastModeCounter);
					break;
				}
			}
		}
		else
		{
			// меню для текстового селекта показываем всегда
			isSelectCell = (this.ContextMenuLastInfo && (this.ContextMenuLastInfo.selectCell != null)) ? true : false;
			isShowContextMenu = (!isSelectCell && (this.ContextMenuLastMode == AscCommon.MobileTouchContextMenuType.Select));

			if (this.ContextMenuLastShow || isTableRuler)
			{
				// эмулируем пропажу меню (клик туда же)
				switch (this.ContextMenuLastMode)
				{
					case AscCommon.MobileTouchContextMenuType.Target:
					case AscCommon.MobileTouchContextMenuType.Select:
					{
						this.ContextMenuLastModeCounter = 0;
						break;
					}
					case AscCommon.MobileTouchContextMenuType.Object:
					{
						this.ContextMenuLastModeCounter = 1;
						break;
					}
					case AscCommon.MobileTouchContextMenuType.Slide:
					{
						this.ContextMenuLastModeCounter = 0;
						break;
					}
					default:
					{
						break;
					}
				}
			}
		}

		if (isSelectTouch)
			isShowContextMenu = true;
		if (isGlassTouch)
			isShowContextMenu = true;

		if (this.ContextMenuLastMode > AscCommon.MobileTouchContextMenuType.None && isShowContextMenu)
		{
			this.ContextMenuLastShow = true;
			this.SendShowContextMenu();
		}
		else
		{
			this.ContextMenuLastShow = false;
		}
	};

	CMobileTouchManagerBase.prototype.ClearContextMenu = function()
	{
		//this.ContextMenuLastMode 		= AscCommon.MobileTouchContextMenuType.None;
		//this.ContextMenuLastModeCounter = 0;

		if (this.ContextMenuShowTimerId != -1)
			clearTimeout(this.ContextMenuShowTimerId);

		this.isShowingContextMenu = false;
		this.Api.sendEvent("asc_onHidePopMenu");
	};

	// закончился скролл
	CMobileTouchManagerBase.prototype.OnScrollAnimationEnd = function()
	{
		if (this.Api.isViewMode)
			return;

		this.CheckContextMenuTouchEnd(false);
	};

	// обновление ректов для селекта текстового
	CMobileTouchManagerBase.prototype.CheckSelectRects = function()
	{
		this.RectSelect1 = null;
		this.RectSelect2 = null;

		var _select = this.delegate.GetSelectionRectsBounds();
		if (!_select)
			return;

		this.RectSelectType = (_select.Type === undefined) ? 0 : _select.Type;

		var _rect1 = _select.Start;
		var _rect2 = _select.End;

		if (!_rect1 || !_rect2)
			return;

		if (0 == _rect1.W && 0 == _rect1.H && _rect2.W == 0 && _rect2.H == 0)
			return;

		this.RectSelect1 	= new AscCommon._rect();
		this.RectSelect1.x 	= _rect1.X;
		this.RectSelect1.y 	= _rect1.Y;
		this.RectSelect1.w 	= _rect1.W;
		this.RectSelect1.h 	= _rect1.H;
		this.PageSelect1 	= _rect1.Page;

		this.RectSelect2 	= new AscCommon._rect();
		this.RectSelect2.x 	= _rect2.X;
		this.RectSelect2.y 	= _rect2.Y;
		this.RectSelect2.w 	= _rect2.W;
		this.RectSelect2.h 	= _rect2.H;
		this.PageSelect2 	= _rect2.Page;
	};

	// отрисовка текстового селекта
	CMobileTouchManagerBase.prototype.CheckSelect = function(overlay)
	{
		if (!this.SelectEnabled)
			return;

		this.CheckSelectRects();
		if (null == this.RectSelect1 || null == this.RectSelect2)
			return;

		var _matrix = this.delegate.GetSelectionTransform();
		var ctx         = overlay.m_oContext;
		ctx.strokeStyle = "#146FE1";
		ctx.fillStyle 	= "#146FE1";

		var _oldGlobalAlpha = ctx.globalAlpha;
		ctx.globalAlpha = 1.0;

		if (!_matrix || global_MatrixTransformer.IsIdentity(_matrix))
		{
			var pos1 = this.delegate.ConvertCoordsToCursor(this.RectSelect1.x, this.RectSelect1.y, this.PageSelect1, false);
			var pos2 = this.delegate.ConvertCoordsToCursor(this.RectSelect1.x, this.RectSelect1.y + this.RectSelect1.h, this.PageSelect1, false);

			var pos3 = this.delegate.ConvertCoordsToCursor(this.RectSelect2.x + this.RectSelect2.w, this.RectSelect2.y, this.PageSelect2, false);
			var pos4 = this.delegate.ConvertCoordsToCursor(this.RectSelect2.x + this.RectSelect2.w, this.RectSelect2.y + this.RectSelect2.h, this.PageSelect2, false);

			ctx.beginPath();

			ctx.moveTo(pos1.X >> 0, pos1.Y >> 0);
			ctx.lineTo(pos2.X >> 0, pos2.Y >> 0);

			ctx.moveTo(pos3.X >> 0, pos3.Y >> 0);
			ctx.lineTo(pos4.X >> 0, pos4.Y >> 0);

			ctx.lineWidth = 2;
			ctx.stroke();

			ctx.beginPath();

			overlay.AddEllipse(pos1.X, pos1.Y - 5, AscCommon.MOBILE_SELECT_TRACK_ROUND / 2);
			overlay.AddEllipse(pos4.X, pos4.Y + 5, AscCommon.MOBILE_SELECT_TRACK_ROUND / 2);
			ctx.fill();

			ctx.beginPath();
		}
		else
		{
			var _xx11 = _matrix.TransformPointX(this.RectSelect1.x, this.RectSelect1.y);
			var _yy11 = _matrix.TransformPointY(this.RectSelect1.x, this.RectSelect1.y);

			var _xx12 = _matrix.TransformPointX(this.RectSelect1.x, this.RectSelect1.y + this.RectSelect1.h);
			var _yy12 = _matrix.TransformPointY(this.RectSelect1.x, this.RectSelect1.y + this.RectSelect1.h);

			var _xx21 = _matrix.TransformPointX(this.RectSelect2.x + this.RectSelect2.w, this.RectSelect2.y);
			var _yy21 = _matrix.TransformPointY(this.RectSelect2.x + this.RectSelect2.w, this.RectSelect2.y);

			var _xx22 = _matrix.TransformPointX(this.RectSelect2.x + this.RectSelect2.w, this.RectSelect2.y + this.RectSelect2.h);
			var _yy22 = _matrix.TransformPointY(this.RectSelect2.x + this.RectSelect2.w, this.RectSelect2.y + this.RectSelect2.h);

			var pos1 = this.delegate.ConvertCoordsToCursor(_xx11, _yy11, this.PageSelect1, false);
			var pos2 = this.delegate.ConvertCoordsToCursor(_xx12, _yy12, this.PageSelect1, false);

			var pos3 = this.delegate.ConvertCoordsToCursor(_xx21, _yy21, this.PageSelect2, false);
			var pos4 = this.delegate.ConvertCoordsToCursor(_xx22, _yy22, this.PageSelect2, false);

			ctx.beginPath();

			ctx.moveTo(pos1.X, pos1.Y);
			ctx.lineTo(pos2.X, pos2.Y);

			ctx.moveTo(pos3.X, pos3.Y);
			ctx.lineTo(pos4.X, pos4.Y);

			ctx.lineWidth = 2;
			ctx.stroke();

			ctx.beginPath();

			var ex01 = _matrix.TransformPointX(0, 0);
			var ey01 = _matrix.TransformPointY(0, 0);

			var ex11 = _matrix.TransformPointX(0, 1);
			var ey11 = _matrix.TransformPointY(0, 1);

			var _len = Math.sqrt((ex11 - ex01) * (ex11 - ex01) + (ey11 - ey01) * (ey11 - ey01));
			if (_len == 0)
				_len = 0.01;

			var ex = 5 * (ex11 - ex01) / _len;
			var ey = 5 * (ey11 - ey01) / _len;

			var _x1 = (pos1.X - ex) >> 0;
			var _y1 = (pos1.Y - ey) >> 0;

			var _x2 = (pos4.X + ex) >> 0;
			var _y2 = (pos4.Y + ey) >> 0;

			overlay.AddEllipse(_x1, _y1, AscCommon.MOBILE_SELECT_TRACK_ROUND / 2);
			overlay.AddEllipse(_x2, _y2, AscCommon.MOBILE_SELECT_TRACK_ROUND / 2);
			ctx.fill();

			ctx.beginPath();
		}

		ctx.globalAlpha = _oldGlobalAlpha;
	};

	// отрисовка табличного селекта
	// заточка на определенного делегата
	CMobileTouchManagerBase.prototype.CheckTableRules = function(overlay)
	{
		if (this.Api.isViewMode || !this.TableTrackEnabled)
			return;

		var HtmlPage = this.delegate.HtmlPage;
		var DrawingDocument = this.delegate.DrawingDocument;

		var horRuler = HtmlPage.m_oHorRuler;
		var verRuler = HtmlPage.m_oVerRuler;

		var _table_outline_dr = this.delegate.GetTableDrawing();
		var _tableOutline     = _table_outline_dr.TableOutline;

		if (horRuler.CurrentObjectType != RULER_OBJECT_TYPE_TABLE || verRuler.CurrentObjectType != RULER_OBJECT_TYPE_TABLE || !_tableOutline)
		{
			this.TableMovePoint      = null;
			this.TableHorRulerPoints = null;
			this.TableVerRulerPoints = null;
			return;
		}

		if (!window.g_table_track_mobile_move.asc_complete)
			return;

		var _table_markup = horRuler.m_oTableMarkup;
		if (_table_markup.Rows.length == 0)
			return;

		HtmlPage.CheckShowOverlay();

		var _epsRects  = this.TableRulersRectOffset;
		var _rectWidth = this.TableRulersRectSize;

		var ctx = overlay.m_oContext;
		ctx.strokeStyle = "#616161";
		ctx.lineWidth   = 1;

		var _tableW = 0;
		var _cols   = _table_markup.Cols;
		for (var i = 0; i < _cols.length; i++)
		{
			_tableW += _cols[i];
		}

		//var _mainFillStyle = "#DFDFDF";
		var _mainFillStyle = "rgba(223, 223, 223, 0.5)";

		var _drawingPage = null;
		if (DrawingDocument.m_arrPages)
			_drawingPage =  DrawingDocument.m_arrPages[DrawingDocument.m_lCurrentPage].drawingPage;
		else
			_drawingPage = DrawingDocument.SlideCurrectRect;

		var _posMoveX = 0;
		var _posMoveY = 0;

		var _PageNum = _table_outline_dr.CurrentPageIndex;

		if (!_table_outline_dr.TableMatrix || global_MatrixTransformer.IsIdentity(_table_outline_dr.TableMatrix))
		{
			this.TableMovePoint = {X : _tableOutline.X, Y : _tableOutline.Y};

			var pos1 = DrawingDocument.ConvertCoordsToCursorWR(_tableOutline.X, _tableOutline.Y, _tableOutline.PageNum);
			var pos2 = DrawingDocument.ConvertCoordsToCursorWR(_tableOutline.X + _tableW, _tableOutline.Y, _tableOutline.PageNum);

			ctx.beginPath();

			var TableMoveRect_x = (pos1.X >> 0) + 0.5 - (_epsRects + _rectWidth);
			var TableMoveRect_y = (pos1.Y >> 0) + 0.5 - (_epsRects + _rectWidth);

			overlay.CheckPoint(TableMoveRect_x, TableMoveRect_y);
			overlay.CheckPoint(TableMoveRect_x + _rectWidth, TableMoveRect_y + _rectWidth);

			if (this.delegate.Name != "slide")
				ctx.drawImage(window.g_table_track_mobile_move, TableMoveRect_x, TableMoveRect_y, window.g_table_track_mobile_move.size, window.g_table_track_mobile_move.size);

			ctx.fillStyle = _mainFillStyle;

			overlay.AddRoundRect((pos1.X >> 0) + 0.5, TableMoveRect_y, (pos2.X - pos1.X) >> 0, _rectWidth, 4);

			ctx.fill();
			ctx.stroke();

			ctx.beginPath();

			var _count = _table_markup.Rows.length;
			var _y1    = 0;
			var _y2    = 0;
			for (var i = 0; i < _count; i++)
			{
				if (i == 0)
					_y1 = _table_markup.Rows[i].Y;

				_y2 = _table_markup.Rows[i].Y;
				_y2 += _table_markup.Rows[i].H;
			}

			var pos3 = DrawingDocument.ConvertCoordsToCursorWR(_tableOutline.X, _y1, DrawingDocument.m_lCurrentPage);
			var pos4 = DrawingDocument.ConvertCoordsToCursorWR(_tableOutline.X, _y2, DrawingDocument.m_lCurrentPage);

			var _ttX = (pos1.X >> 0) + 0.5 - (_epsRects + _rectWidth);

			ctx.fillStyle = _mainFillStyle;

			overlay.AddRoundRect((pos1.X >> 0) + 1.5 - (_epsRects + _rectWidth), (pos3.Y >> 0) + 0.5, _rectWidth - 1, (pos4.Y - pos3.Y) >> 0, 4);

			ctx.fill();
			ctx.stroke();

			ctx.beginPath();

			var dKoef = (HtmlPage.m_nZoomValue * g_dKoef_mm_to_pix / 100);
			var xDst  = _drawingPage.left;
			var yDst  = _drawingPage.top;

			var _oldY = _table_markup.Rows[0].Y + _table_markup.Rows[0].H;

			this.TableVerRulerPoints = [];
			var _rectIndex           = 0;
			var _x                   = (pos1.X - _epsRects - _rectWidth) >> 0;

			ctx.fillStyle = "#146FE1";
			for (var i = 1; i <= _count; i++)
			{
				var _newPos = (i != _count) ? _table_markup.Rows[i].Y : _oldY;

				var _p = {Y : _oldY, H : (_newPos - _oldY)};
				var _y = DrawingDocument.ConvertCoordsToCursorWR(0, _oldY, _PageNum);

				ctx.beginPath();
				overlay.AddDiamond(_x + 1.5 + (_rectWidth >> 1), _y.Y, AscCommon.MOBILE_TABLE_RULER_DIAMOND);
				ctx.fill();
				ctx.beginPath();

				this.TableVerRulerPoints[_rectIndex++] = _p;

				if (i != _count)
					_oldY = _table_markup.Rows[i].Y + _table_markup.Rows[i].H;
			}

			this.TableHorRulerPoints = [];
			_rectIndex               = 0;
			var _col                 = _table_markup.X;
			for (var i = 1; i <= _cols.length; i++)
			{
				_col += _cols[i - 1];
				var _x = _col - _table_markup.Margins[i - 1].Right;
				var _r = _col + ((i == _cols.length) ? 0 : _table_markup.Margins[i].Left);

				var __c = ((xDst + dKoef * _col) >> 0) + 0.5;

				ctx.beginPath();
				overlay.AddDiamond(__c, TableMoveRect_y +_rectWidth / 2, AscCommon.MOBILE_TABLE_RULER_DIAMOND);
				ctx.fill();
				ctx.beginPath();

				this.TableHorRulerPoints[_rectIndex++] = {X : _x, W : _r - _x, C : _col};
			}

			ctx.beginPath();
			if (this.Mode == AscCommon.MobileTouchMode.TableRuler)
			{
				if (0 == this.TableCurrentMoveDir)
				{
					var _pos = this.delegate.ConvertCoordsToCursor(this.TableCurrentMoveValue, 0, _table_outline_dr.CurrentPageIndex, false);
					overlay.VertLine(_pos.X, true);
				}
				else
				{
					var _pos = this.delegate.ConvertCoordsToCursor(0, this.TableCurrentMoveValue, _table_outline_dr.CurrentPageIndex, false);
					overlay.HorLine(_pos.Y, true);
				}
			}
		}
		else
		{
			var dKoef = (HtmlPage.m_nZoomValue * g_dKoef_mm_to_pix / 100);

			var xDst  = _drawingPage.left;
			var yDst  = _drawingPage.top;

			ctx.lineWidth = 1 / dKoef;

			if (overlay.IsRetina)
				dKoef *= AscCommon.AscBrowser.retinaPixelRatio;

			var _coord_transform = new AscCommon.CMatrix();
			_coord_transform.sx  = dKoef;
			_coord_transform.sy  = dKoef;
			_coord_transform.tx  = xDst;
			_coord_transform.ty  = yDst;

			var _diamond_size = AscCommon.MOBILE_TABLE_RULER_DIAMOND;
			if (overlay.IsRetina)
			{
				_coord_transform.tx *= AscCommon.AscBrowser.retinaPixelRatio;
				_coord_transform.ty *= AscCommon.AscBrowser.retinaPixelRatio;

				_diamond_size *= AscCommon.AscBrowser.retinaPixelRatio;
			}

			ctx.save();

			_coord_transform.Multiply(_table_outline_dr.TableMatrix, AscCommon.MATRIX_ORDER_PREPEND);
			ctx.setTransform(_coord_transform.sx, _coord_transform.shy, _coord_transform.shx, _coord_transform.sy, _coord_transform.tx, _coord_transform.ty);

			this.TableMovePoint = {X : _tableOutline.X, Y : _tableOutline.Y};

			ctx.beginPath();

			var _rectW  = _rectWidth / dKoef;
			var _offset = (_epsRects + _rectWidth) / dKoef;
			if (overlay.IsRetina)
			{
				_rectW *= AscCommon.AscBrowser.retinaPixelRatio;
				_offset *= AscCommon.AscBrowser.retinaPixelRatio;
			}

			if (this.delegate.Name != "slide")
				ctx.drawImage(window.g_table_track_mobile_move, this.TableMovePoint.X - _offset, this.TableMovePoint.Y - _offset, _rectW, _rectW);

			ctx.fillStyle = _mainFillStyle;

			overlay.AddRoundRectCtx(ctx, this.TableMovePoint.X, this.TableMovePoint.Y - _offset, _tableW, _rectW, 5 / dKoef);

			ctx.fill();
			ctx.stroke();

			ctx.beginPath();

			var _count = _table_markup.Rows.length;
			var _y1    = 0;
			var _y2    = 0;
			for (var i = 0; i < _count; i++)
			{
				if (i == 0)
					_y1 = _table_markup.Rows[i].Y;

				_y2 = _table_markup.Rows[i].Y;
				_y2 += _table_markup.Rows[i].H;
			}

			ctx.fillStyle = _mainFillStyle;

			overlay.AddRoundRectCtx(ctx, this.TableMovePoint.X - _offset, this.TableMovePoint.Y, _rectW, _y2 - _y1, 5 / dKoef);

			overlay.CheckRectT(this.TableMovePoint.X, this.TableMovePoint.Y, _tableW, _y2 - _y1, _coord_transform, 2 * (_epsRects + _rectWidth));

			ctx.fill();
			ctx.stroke();

			ctx.beginPath();

			var _oldY = _table_markup.Rows[0].Y + _table_markup.Rows[0].H;
			_oldY -= _table_outline_dr.TableMatrix.ty;

			ctx.fillStyle = "#146FE1";
			this.TableVerRulerPoints = [];
			var _rectIndex           = 0;
			var _xx                  = this.TableMovePoint.X - _offset;
			for (var i = 1; i <= _count; i++)
			{
				var _newPos = (i != _count) ? (_table_markup.Rows[i].Y - _table_outline_dr.TableMatrix.ty) : _oldY;

				var _p = {Y : _oldY, H : (_newPos - _oldY)};

				var ___y = (_p.Y + (_p.H / 2));
				ctx.beginPath();
				overlay.AddDiamond(_xx + _rectW / 2, ___y, _diamond_size / dKoef);
				ctx.fill();
				ctx.beginPath();

				this.TableVerRulerPoints[_rectIndex++] = _p;

				if (i != _count)
				{
					_oldY = _table_markup.Rows[i].Y + _table_markup.Rows[i].H;
					_oldY -= _table_outline_dr.TableMatrix.ty;
				}
			}

			this.TableHorRulerPoints = [];
			_rectIndex               = 0;
			var _col                 = this.TableMovePoint.X;
			for (var i = 1; i <= _cols.length; i++)
			{
				_col += _cols[i - 1];
				var _x = _col - _table_markup.Margins[i - 1].Right;
				var _r = _col + ((i == _cols.length) ? 0 : _table_markup.Margins[i].Left);

				ctx.beginPath();
				overlay.AddDiamond(_col, this.TableMovePoint.Y - _offset + _rectW / 2, _diamond_size / dKoef);
				ctx.fill();
				ctx.beginPath();

				this.TableHorRulerPoints[_rectIndex++] = {X : _x, W : _r - _x, C : _col};
			}

			ctx.restore();

			ctx.beginPath();
			if (this.Mode == AscCommon.MobileTouchMode.TableRuler)
			{
				if (0 == this.TableCurrentMoveDir)
				{
					_posMoveX = _table_outline_dr.TableMatrix.TransformPointX(this.TableCurrentMoveValue, 0);
					_posMoveY = _table_outline_dr.TableMatrix.TransformPointY(this.TableCurrentMoveValue, 0);

					var _pos = this.delegate.ConvertCoordsToCursor(_posMoveX, _posMoveY, _table_outline_dr.CurrentPageIndex, false);
					overlay.VertLine(_pos.X, true);
				}
				else
				{
					_posMoveX = _table_outline_dr.TableMatrix.TransformPointX(0, this.TableCurrentMoveValue);
					_posMoveY = _table_outline_dr.TableMatrix.TransformPointY(0, this.TableCurrentMoveValue);

					var _pos = this.delegate.ConvertCoordsToCursor(_posMoveX, _posMoveY, _table_outline_dr.CurrentPageIndex, false);
					overlay.HorLine(_pos.Y, true);
				}
			}
		}
	};

	/* document renderer mode (заточка на делегата) */
	CMobileTouchManagerBase.prototype.onTouchStart_renderer = function(e)
	{
		AscCommon.check_MouseDownEvent(e.touches ? e.touches[0] : e, true);
		global_mouseEvent.LockMouse();

		this.MoveAfterDown = false;

		if ((e.touches && 2 == e.touches.length) || (2 == this.getPointerCount()))
		{
			this.Mode = AscCommon.MobileTouchMode.Zoom;
		}

		switch (this.Mode)
		{
			case AscCommon.MobileTouchMode.None:
			{
				this.Mode      = AscCommon.MobileTouchMode.Scroll;
				this.DownPoint = this.delegate.ConvertCoordsFromCursor(global_mouseEvent.X, global_mouseEvent.Y);

				this.DownPointOriginal.X = global_mouseEvent.X;
				this.DownPointOriginal.Y = global_mouseEvent.Y;

				this.iScroll._start(e);

				break;
			}
			case AscCommon.MobileTouchMode.Scroll:
			{
				// ничего не меняем, просто перемещаем точку
				this.DownPoint           = this.delegate.ConvertCoordsFromCursor(global_mouseEvent.X, global_mouseEvent.Y);
				this.DownPointOriginal.X = global_mouseEvent.X;
				this.DownPointOriginal.Y = global_mouseEvent.Y;

				this.iScroll._start(e);

				break;
			}
			case AscCommon.MobileTouchMode.Zoom:
			{
				this.delegate.HtmlPage.NoneRepaintPages = true;

				this.ZoomDistance = this.getPointerDistance(e);
				this.ZoomValue    = this.delegate.GetZoom();

				break;
			}
		}

		AscCommon.stopEvent(e);
		return false;
	};
	CMobileTouchManagerBase.prototype.onTouchMove_renderer  = function(e)
	{
		AscCommon.check_MouseMoveEvent(e.touches ? e.touches[0] : e);

		if (!this.MoveAfterDown)
		{
			if (Math.abs(this.DownPointOriginal.X - global_mouseEvent.X) > this.MoveMinDist ||
				Math.abs(this.DownPointOriginal.Y - global_mouseEvent.Y) > this.MoveMinDist)
			{
				this.MoveAfterDown = true;
			}
		}

		switch (this.Mode)
		{
			case AscCommon.MobileTouchMode.Scroll:
			{
				var _offsetX = global_mouseEvent.X - this.DownPointOriginal.X;
				var _offsetY = global_mouseEvent.Y - this.DownPointOriginal.Y;

				this.iScroll._move(e);
				break;
			}
			case AscCommon.MobileTouchMode.Zoom:
			{
				var isTouch2 = ((e.touches && 2 == e.touches.length) || (2 == this.getPointerCount()));
				if (!isTouch2)
				{
					this.Mode = AscCommon.MobileTouchMode.None;
					return;
				}

				var zoomCurrentDist = this.getPointerDistance(e);

				if (zoomCurrentDist == 0)
					zoomCurrentDist = 1;

				var _zoomFix = this.ZoomValue / 100;
				var _zoomCur = _zoomFix * (zoomCurrentDist / this.ZoomDistance);

				_zoomCur = (_zoomCur * 100) >> 0;
				if (_zoomCur < this.ZoomValueMin)
					_zoomCur = this.ZoomValueMin;
				else if (_zoomCur > this.ZoomValueMax)
					_zoomCur = this.ZoomValueMax;

				this.delegate.SetZoom(_zoomCur);

				break;
			}
			default:
				break;
		}

		AscCommon.stopEvent(e);
		return false;
	};
	CMobileTouchManagerBase.prototype.onTouchEnd_renderer   = function(e)
	{
		AscCommon.check_MouseUpEvent(e.changedTouches ? e.changedTouches[0] : e);

		switch (this.Mode)
		{
			case AscCommon.MobileTouchMode.Scroll:
			{
				this.iScroll._end(e);
				this.Mode = AscCommon.MobileTouchMode.None;

				if (!this.MoveAfterDown)
				{
					this.Api.sendEvent("asc_onTapEvent", e);
				}
				break;
			}
			case AscCommon.MobileTouchMode.Zoom:
			{
				// здесь нужно запускать отрисовку, если есть анимация зума
				this.delegate.HtmlPage.NoneRepaintPages = false;
				this.delegate.HtmlPage.m_bIsFullRepaint = true;
				this.delegate.HtmlPage.OnScroll();

				this.Mode = AscCommon.MobileTouchMode.None;
				break;
			}
			default:
				break;
		}

		if (!AscCommon.AscBrowser.isAndroid)
			AscCommon.stopEvent(e);
		return false;
	};

	/* перемещение курсора (именно курсора!) до ближайщей позиции. заточка на делегата */
	CMobileTouchManagerBase.prototype.MoveCursorToPoint = function(isHalfHeight)
	{
		var pos = this.delegate.ConvertCoordsFromCursor(global_mouseEvent.X, global_mouseEvent.Y);

		var old_click_count          = global_mouseEvent.ClickCount;
		global_mouseEvent.ClickCount = 1;

		var nearPos = this.delegate.Logic_GetNearestPos(pos.X, pos.Y, pos.Page);
		if (!nearPos)
			return;

		this.delegate.DrawingDocument.NeedScrollToTargetFlag = true;
		var y = nearPos.Y;

		nearPos.Paragraph.Parent.MoveCursorToNearestPos(nearPos);
        this.delegate.LogicDocument.Document_UpdateSelectionState();
		this.delegate.DrawingDocument.NeedScrollToTargetFlag = false;

		global_mouseEvent.ClickCount = old_click_count;
	};

	CMobileTouchManagerBase.prototype.onTouchStart = function(e)
	{
		AscCommon.stopEvent(e);
		return false;
	};
	CMobileTouchManagerBase.prototype.onTouchMove = function(e)
	{
		AscCommon.stopEvent(e);
		return false;
	};
	CMobileTouchManagerBase.prototype.onTouchEnd = function(e)
	{
		AscCommon.stopEvent(e);
		return false;
	};

	CMobileTouchManagerBase.prototype.mainOnTouchStart = function(e)
	{
		AscCommon.stopEvent(e);
		return false;
	};
	CMobileTouchManagerBase.prototype.mainOnTouchMove = function(e)
	{
		AscCommon.stopEvent(e);
		return false;
	};
	CMobileTouchManagerBase.prototype.mainOnTouchEnd = function(e)
	{
		AscCommon.stopEvent(e);
		return false;
	};

	CMobileTouchManagerBase.prototype.checkPointerMultiTouchAdd = function(e)
	{
		if (!this.checkPointerEvent(e))
			return;

		this.pointerTouchesCoords[e["pointerId"]] = {X:e.pageX, Y:e.pageY};
	};
	CMobileTouchManagerBase.prototype.checkPointerMultiTouchRemove = function(e)
	{
		if (!this.checkPointerEvent(e))
			return;

		//delete this.pointerTouchesCoords[e["pointerId"]];

		// на всякий случай - удаляем все.
		this.pointerTouchesCoords = {};
	};
	CMobileTouchManagerBase.prototype.checkPointerEvent = function(e)
	{
		if (!AscCommon.AscBrowser.isIE)
			return false;

		var _type = e.type;
		if (_type.toLowerCase)
			_type = _type.toLowerCase();

		if (-1 == _type.indexOf("pointer"))
			return -1;

		if (undefined == e["pointerId"])
			return false;

		return true;
	};
	CMobileTouchManagerBase.prototype.getPointerDistance = function(e)
	{
		var isPointers = this.checkPointerEvent(e);
		if (e.touches && (e.touches.length > 1) && !isPointers)
		{
			var _x1 = (e.touches[0].pageX !== undefined) ? e.touches[0].pageX : e.touches[0].clientX;
			var _y1 = (e.touches[0].pageY !== undefined) ? e.touches[0].pageY : e.touches[0].clientY;

			var _x2 = (e.touches[1].pageX !== undefined) ? e.touches[1].pageX : e.touches[1].clientX;
			var _y2 = (e.touches[1].pageY !== undefined) ? e.touches[1].pageY : e.touches[1].clientY;

			return Math.sqrt((_x1 - _x2) * (_x1 - _x2) + (_y1 - _y2) * (_y1 - _y2));
		}
		else if (isPointers)
		{
			var _touch1 = {X : 0, Y : 0};
			var _touch2 = {X : 0, Y : 0};
			var _counter = 0;

			for (var i in this.pointerTouchesCoords)
			{
				if (_counter == 0)
					_touch1 = this.pointerTouchesCoords[i];
				else
					_touch2 = this.pointerTouchesCoords[i];
				++_counter;
				if (_counter > 1)
					break;
			}

			return Math.sqrt((_touch1.X - _touch2.X) * (_touch1.X - _touch2.X) + (_touch1.Y - _touch2.Y) * (_touch1.Y - _touch2.Y));
		}

		return 0;
	};

	CMobileTouchManagerBase.prototype.getPointerCount = function(e)
	{
		var _count = 0;

		for (var i in this.pointerTouchesCoords)
			++_count;

		return _count;
	};

	CMobileTouchManagerBase.prototype.showKeyboard = function()
	{
		if (AscCommon.g_inputContext)
		{
			if (this.ContextMenuLastMode ==  AscCommon.MobileTouchContextMenuType.Target)
				AscCommon.g_inputContext.HtmlArea.focus();
		}
	};

	CMobileTouchManagerBase.prototype.scrollTo = function(x, y)
	{
		if (this.iScroll)
		{
			this.iScroll.scrollTo(-x, -y);
			this.iScroll._execEvent('scroll');
		}
	};
	CMobileTouchManagerBase.prototype.scrollBy = function(x, y)
	{
		if (this.iScroll)
		{
			this.iScroll.scrollBy(-x, -y);
			this.iScroll._execEvent('scroll');
		}
	};

	//--------------------------------------------------------export----------------------------------------------------
	AscCommon.CMobileDelegateSimple = CMobileDelegateSimple;
	AscCommon.CMobileTouchManagerBase = CMobileTouchManagerBase;
	AscCommon.CMobileDelegateEditor = CMobileDelegateEditor;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined)
{
	var global_MatrixTransformer = AscCommon.global_MatrixTransformer;
	var g_dKoef_mm_to_pix        = AscCommon.g_dKoef_mm_to_pix;

	var global_mouseEvent    = AscCommon.global_mouseEvent;
	var global_keyboardEvent = AscCommon.global_keyboardEvent;

	/**
	 * @extends {AscCommon.CMobileTouchManagerBase}
	 */
	function CMobileTouchManager(_config)
	{
		this.Name = "word";
		AscCommon.CMobileTouchManagerBase.call(this, _config || {});
	}
	CMobileTouchManager.prototype = Object.create(AscCommon.CMobileTouchManagerBase.prototype);
	CMobileTouchManager.prototype.constructor = CMobileTouchManager;

	CMobileTouchManager.prototype.Init = function(_api)
	{
		this.Api = _api;

		// создаем делегата. инициализация его - ПОСЛЕ создания iScroll
		this.delegate = new AscCommon.CMobileDelegateEditor(this);
		var _element = this.delegate.GetScrollerParent();
		this.CreateScrollerDiv(_element);

		this.iScroll = new window.IScroll(_element, {
			scrollbars: true,
			mouseWheel: true,
			interactiveScrollbars: true,
			shrinkScrollbars: 'scale',
			fadeScrollbars: true,
			scrollX : true,
			scroller_id : this.iScrollElement,
			bounce : false,
			eventsElement : this.eventsElement,
			click : false
		});

		this.delegate.Init();

		if (this.TableTrackEnabled)
			this.LoadMobileImages();
	};

	CMobileTouchManager.prototype.onTouchStart = function(e)
	{
		this.IsTouching = true;
		AscCommon.g_inputContext.enableVirtualKeyboard();

		this.checkPointerMultiTouchAdd(e);

		if (this.delegate.IsReader())
			return this.onTouchStart_renderer(e);

		global_mouseEvent.KoefPixToMM = 5;
		AscCommon.check_MouseDownEvent(e.touches ? e.touches[0] : e, true);
		global_mouseEvent.KoefPixToMM = 1;
		global_mouseEvent.LockMouse();

		this.ClearContextMenu();

		this.TableCurrentMoveValueMin = null;
		this.TableCurrentMoveValueMax = null;

		this.MoveAfterDown = false;
		this.TimeDown      = new Date().getTime();

		var bIsKoefPixToMM = false;
		var _matrix        = this.delegate.GetSelectionTransform();
		if (_matrix && global_MatrixTransformer.IsIdentity(_matrix))
			_matrix = null;

		if (!this.CheckSelectTrack())
		{
			if (!this.CheckTableTrack())
			{
				bIsKoefPixToMM = this.CheckObjectTrack();
			}
		}

		if ((e.touches && 2 == e.touches.length) || (2 == this.getPointerCount()))
		{
			this.Mode = AscCommon.MobileTouchMode.Zoom;
		}

		// если не используем этот моус даун - то уменьшаем количество кликов
		switch (this.Mode)
		{
			case AscCommon.MobileTouchMode.None:
			case AscCommon.MobileTouchMode.Scroll:
			case AscCommon.MobileTouchMode.InlineObj:
			case AscCommon.MobileTouchMode.FlowObj:
			case AscCommon.MobileTouchMode.Zoom:
			case AscCommon.MobileTouchMode.Cursor:
			case AscCommon.MobileTouchMode.TableMove:
			{
				// так как был уже check, нужно уменьшить количество кликов
				if (global_mouseEvent.ClickCount > 0)
					global_mouseEvent.ClickCount--;
				break;
			}
			default:
				break;
		}

		var isPreventDefault = false;
		switch (this.Mode)
		{
			case AscCommon.MobileTouchMode.InlineObj:
			case AscCommon.MobileTouchMode.FlowObj:
			case AscCommon.MobileTouchMode.Zoom:
			case AscCommon.MobileTouchMode.TableMove:
			{
				isPreventDefault = true;
				break;
			}
			case AscCommon.MobileTouchMode.None:
			case AscCommon.MobileTouchMode.Scroll:
			{
				isPreventDefault = this.CheckObjectTrackBefore();
				break;
			}
			default:
			{
				break;
			}
		}

		switch (this.Mode)
		{
			case AscCommon.MobileTouchMode.None:
			{
				this.Mode      = AscCommon.MobileTouchMode.Scroll;
				this.DownPoint = this.delegate.ConvertCoordsFromCursor(global_mouseEvent.X, global_mouseEvent.Y);

				this.DownPointOriginal.X = global_mouseEvent.X;
				this.DownPointOriginal.Y = global_mouseEvent.Y;

				this.iScroll._start(e);

				break;
			}
			case AscCommon.MobileTouchMode.Scroll:
			{
				// ничего не меняем, просто перемещаем точку
				this.DownPoint           = this.delegate.ConvertCoordsFromCursor(global_mouseEvent.X, global_mouseEvent.Y);
				this.DownPointOriginal.X = global_mouseEvent.X;
				this.DownPointOriginal.Y = global_mouseEvent.Y;

				this.iScroll._start(e);

				break;
			}
			case AscCommon.MobileTouchMode.Select:
			{
				var _x1 = this.RectSelect1.x;
				var _y1 = this.RectSelect1.y + this.RectSelect1.h / 2;

				var _x2 = this.RectSelect2.x + this.RectSelect2.w;
				var _y2 = this.RectSelect2.y + this.RectSelect2.h / 2;

				this.delegate.LogicDocument.RemoveSelection();
				if (1 == this.DragSelect)
				{
					global_mouseEvent.Button = 0;

					if (!_matrix)
					{
						this.delegate.Logic_OnMouseDown(global_mouseEvent, _x2, _y2, this.PageSelect2);
					}
					else
					{
						var __X = _matrix.TransformPointX(_x2, _y2);
						var __Y = _matrix.TransformPointY(_x2, _y2);

						this.delegate.Logic_OnMouseDown(global_mouseEvent, __X, __Y, this.PageSelect2);
					}

					var pos1 = this.delegate.ConvertCoordsFromCursor(global_mouseEvent.X, global_mouseEvent.Y);
					this.delegate.Logic_OnMouseMove(global_mouseEvent, pos1.X, pos1.Y, pos1.Page);
				}
				else if (2 == this.DragSelect)
				{
					global_mouseEvent.Button = 0;

					if (!_matrix)
					{
						this.delegate.Logic_OnMouseDown(global_mouseEvent, _x1, _y1, this.PageSelect1);
					}
					else
					{
						var __X = _matrix.TransformPointX (_x1, _y1);
						var __Y = _matrix.TransformPointY(_x1, _y1);

						this.delegate.Logic_OnMouseDown(global_mouseEvent, __X, __Y, this.PageSelect1);
					}

					var pos4 = this.delegate.ConvertCoordsFromCursor(global_mouseEvent.X, global_mouseEvent.Y);
					this.delegate.Logic_OnMouseMove(global_mouseEvent, pos4.X, pos4.Y, pos4.Page);
				}
				break;
			}
			case AscCommon.MobileTouchMode.InlineObj:
			{
				break;
			}
			case AscCommon.MobileTouchMode.FlowObj:
			{
				if (bIsKoefPixToMM)
				{
					global_mouseEvent.KoefPixToMM = 5;
				}
				this.delegate.Drawing_OnMouseDown(e.touches ? e.touches[0] : e);
				global_mouseEvent.KoefPixToMM = 1;
				break;
			}
			case AscCommon.MobileTouchMode.Zoom:
			{
				this.delegate.HtmlPage.NoneRepaintPages = true;

				this.ZoomDistance = this.getPointerDistance(e);
				this.ZoomValue    = this.delegate.GetZoom();

				break;
			}
			case AscCommon.MobileTouchMode.Cursor:
			{
				this.Mode      = AscCommon.MobileTouchMode.Scroll;
				this.DownPoint = this.delegate.ConvertCoordsFromCursor(global_mouseEvent.X, global_mouseEvent.Y);
				break;
			}
			case AscCommon.MobileTouchMode.TableMove:
			{
				this.delegate.Drawing_OnMouseDown(e.touches ? e.touches[0] : e);
				break;
			}
			case AscCommon.MobileTouchMode.TableRuler:
			{
				this.delegate.HtmlPage.OnUpdateOverlay();
				break;
			}
		}

		if (AscCommon.AscBrowser.isAndroid)
			isPreventDefault = false;

		if (this.Api.isViewMode || isPreventDefault)
			AscCommon.stopEvent(e);

		return false;
	};
	CMobileTouchManager.prototype.onTouchMove  = function(e)
	{
		this.checkPointerMultiTouchAdd(e);

		if (this.delegate.IsReader())
			return this.onTouchMove_renderer(e);

		if (this.Mode != AscCommon.MobileTouchMode.FlowObj && this.Mode != AscCommon.MobileTouchMode.TableMove)
			AscCommon.check_MouseMoveEvent(e.touches ? e.touches[0] : e);

		if (!this.MoveAfterDown)
		{
			if (Math.abs(this.DownPointOriginal.X - global_mouseEvent.X) > this.MoveMinDist ||
				Math.abs(this.DownPointOriginal.Y - global_mouseEvent.Y) > this.MoveMinDist)
			{
				this.MoveAfterDown = true;
			}
		}

		switch (this.Mode)
		{
			case AscCommon.MobileTouchMode.Cursor:
			{
				this.MoveCursorToPoint(true);
				break;
			}
			case AscCommon.MobileTouchMode.Scroll:
			{
				var _newTime = new Date().getTime();
				if ((_newTime - this.TimeDown) > this.ReadingGlassTime && !this.MoveAfterDown)
				{
					this.Mode = AscCommon.MobileTouchMode.Cursor;
					this.MoveCursorToPoint(false);
				}
				else
				{
					this.iScroll._move(e);
					AscCommon.stopEvent(e);
				}
				break;
			}
			case AscCommon.MobileTouchMode.Zoom:
			{
				var isTouch2 = ((e.touches && 2 == e.touches.length) || (2 == this.getPointerCount()));
				if (!isTouch2)
				{
					this.Mode = AscCommon.MobileTouchMode.None;
					return;
				}

				var zoomCurrentDist = this.getPointerDistance(e);

				if (zoomCurrentDist == 0)
					zoomCurrentDist = 1;

				var _zoomFix = this.ZoomValue / 100;
				var _zoomCur = _zoomFix * (zoomCurrentDist / this.ZoomDistance);

				_zoomCur = (_zoomCur * 100) >> 0;
				if (_zoomCur < this.ZoomValueMin)
					_zoomCur = this.ZoomValueMin;
				else if (_zoomCur > this.ZoomValueMax)
					_zoomCur = this.ZoomValueMax;

				this.delegate.SetZoom(_zoomCur);
				AscCommon.stopEvent(e);
				break;
			}
			case AscCommon.MobileTouchMode.InlineObj:
			{
				break;
			}
			case AscCommon.MobileTouchMode.FlowObj:
			{
				this.delegate.Drawing_OnMouseMove(e.touches ? e.touches[0] : e);
				AscCommon.stopEvent(e);
				break;
			}
			case AscCommon.MobileTouchMode.Select:
			{
				// во время движения может смениться порядок ректов
				global_mouseEvent.ClickCount = 1;
				var pos                      = this.delegate.ConvertCoordsFromCursor(global_mouseEvent.X, global_mouseEvent.Y);
				this.delegate.Logic_OnMouseMove(global_mouseEvent, pos.X, pos.Y, pos.Page);
				AscCommon.stopEvent(e);
				break;
			}
			case AscCommon.MobileTouchMode.TableMove:
			{
				this.delegate.Drawing_OnMouseMove(e.touches ? e.touches[0] : e);
				AscCommon.stopEvent(e);
				break;
			}
			case AscCommon.MobileTouchMode.TableRuler:
			{
				var DrawingDocument = this.delegate.DrawingDocument;
				var pos = DrawingDocument.ConvertCoordsFromCursorPage(global_mouseEvent.X, global_mouseEvent.Y, DrawingDocument.TableOutlineDr.CurrentPageIndex);

				var _Transform = null;
				if (DrawingDocument.TableOutlineDr)
					_Transform = DrawingDocument.TableOutlineDr.TableMatrix;

				if (_Transform && !global_MatrixTransformer.IsIdentity(_Transform))
				{
					var _invert = _Transform.CreateDublicate();
					_invert.Invert();

					var __x = _invert.TransformPointX(pos.X, pos.Y);
					var __y = _invert.TransformPointY(pos.X, pos.Y);

					pos.X = __x;
					pos.Y = __y;
				}

				if (this.TableCurrentMoveDir == 0)
				{
					this.TableCurrentMoveValue = pos.X;

					if (null != this.TableCurrentMoveValueMin)
					{
						if (this.TableCurrentMoveValueMin > this.TableCurrentMoveValue)
							this.TableCurrentMoveValue = this.TableCurrentMoveValueMin;
					}
					if (null != this.TableCurrentMoveValueMax)
					{
						if (this.TableCurrentMoveValueMax < this.TableCurrentMoveValue)
							this.TableCurrentMoveValue = this.TableCurrentMoveValueMax;
					}
				}
				else
				{
					this.TableCurrentMoveValue = pos.Y;

					if (null != this.TableCurrentMoveValueMin)
					{
						if (this.TableCurrentMoveValueMin > this.TableCurrentMoveValue)
							this.TableCurrentMoveValue = this.TableCurrentMoveValueMin;
					}
					if (null != this.TableCurrentMoveValueMax)
					{
						if (this.TableCurrentMoveValueMax < this.TableCurrentMoveValue)
							this.TableCurrentMoveValue = this.TableCurrentMoveValueMax;
					}
				}
				this.delegate.HtmlPage.OnUpdateOverlay();

				AscCommon.stopEvent(e);
				break;
			}
			default:
				break;
		}
	};
	CMobileTouchManager.prototype.onTouchEnd   = function(e)
	{
		this.IsTouching = false;

		if (this.delegate.IsReader())
		{
			this.checkPointerMultiTouchRemove(e);
			AscCommon.g_inputContext.preventVirtualKeyboard(e);
			return this.onTouchEnd_renderer(e);
		}

		var _e = e.changedTouches ? e.changedTouches[0] : e;
		if (this.Mode != AscCommon.MobileTouchMode.FlowObj && this.Mode != AscCommon.MobileTouchMode.TableMove)
		{
			AscCommon.check_MouseUpEvent(_e);
		}

		var isCheckContextMenuMode = true;

		var isCheckContextMenuSelect = false;
		var isCheckContextMenuCursor = (this.Mode == AscCommon.MobileTouchMode.Cursor);
		var isCheckContextMenuTableRuler = false;

		var isPreventDefault = false;
		switch (this.Mode)
		{
			case AscCommon.MobileTouchMode.Scroll:
			case AscCommon.MobileTouchMode.InlineObj:
			case AscCommon.MobileTouchMode.FlowObj:
			case AscCommon.MobileTouchMode.Zoom:
			case AscCommon.MobileTouchMode.TableMove:
			{
				isPreventDefault = true;
				break;
			}
			default:
			{
				break;
			}
		}

		switch (this.Mode)
		{
			case AscCommon.MobileTouchMode.Cursor:
			{
				// ничего не делаем. курсор уже установлен
				this.Mode = AscCommon.MobileTouchMode.None;
				break;
			}
			case AscCommon.MobileTouchMode.Scroll:
			{
				if (!this.MoveAfterDown)
				{
					global_mouseEvent.Button = 0;
					this.delegate.Drawing_OnMouseDown(_e);
					this.delegate.Drawing_OnMouseUp(_e);
					this.Api.sendEvent("asc_onTapEvent", e);

					var typeMenu = this.delegate.GetContextMenuType();
					if (typeMenu == AscCommon.MobileTouchContextMenuType.Target ||
						typeMenu == AscCommon.MobileTouchContextMenuType.Select)
						isPreventDefault = false;
				}
				else
				{
					// нужно запускать анимацию скролла, если она есть
					// TODO:
					isCheckContextMenuMode = false;
					this.iScroll._end(e);
				}

				this.Mode = AscCommon.MobileTouchMode.None;
				break;
			}
			case AscCommon.MobileTouchMode.Zoom:
			{
				// здесь нужно запускать отрисовку, если есть анимация зума
				this.delegate.HtmlPage.NoneRepaintPages = false;
				this.delegate.HtmlPage.m_bIsFullRepaint = true;
				this.delegate.HtmlPage.OnScroll();

				this.Mode = AscCommon.MobileTouchMode.None;
				isCheckContextMenuMode = false;
				break;
			}
			case AscCommon.MobileTouchMode.InlineObj:
			{
				// TODO:
				break;
			}
			case AscCommon.MobileTouchMode.FlowObj:
			{
				// TODO:
				this.delegate.Drawing_OnMouseUp(e.changedTouches ? e.changedTouches[0] : e);
				this.Mode = AscCommon.MobileTouchMode.None;
				break;
			}
			case AscCommon.MobileTouchMode.Select:
			{
				// ничего не нужно делать
				this.DragSelect = 0;
				this.Mode       = AscCommon.MobileTouchMode.None;
				var pos         = this.delegate.ConvertCoordsFromCursor(global_mouseEvent.X, global_mouseEvent.Y);
				this.delegate.Logic_OnMouseUp(global_mouseEvent, pos.X, pos.Y, pos.Page);
				AscCommon.stopEvent(e);
				isCheckContextMenuSelect = true;
				break;
			}
			case AscCommon.MobileTouchMode.TableMove:
			{
				this.delegate.Drawing_OnMouseUp(e.changedTouches ? e.changedTouches[0] : e);
				this.Mode = AscCommon.MobileTouchMode.None;
				break;
			}
			case AscCommon.MobileTouchMode.TableRuler:
			{
				isCheckContextMenuTableRuler = true;

				var HtmlPage = this.delegate.HtmlPage;
				var DrawingDocument = this.delegate.DrawingDocument;

				HtmlPage.StartUpdateOverlay();

				this.Mode = AscCommon.MobileTouchMode.None;

				var _xOffset = HtmlPage.X;
				var _yOffset = HtmlPage.Y;

				if (true === HtmlPage.m_bIsRuler)
				{
					_xOffset += (5 * g_dKoef_mm_to_pix);
					_yOffset += (7 * g_dKoef_mm_to_pix);
				}

				var pos = DrawingDocument.ConvertCoordsFromCursorPage(global_mouseEvent.X, global_mouseEvent.Y, DrawingDocument.TableOutlineDr.CurrentPageIndex);

				var _Transform = null;
				if (DrawingDocument.TableOutlineDr)
					_Transform = DrawingDocument.TableOutlineDr.TableMatrix;

				if (_Transform && !global_MatrixTransformer.IsIdentity(_Transform))
				{
					var _invert = _Transform.CreateDublicate();
					_invert.Invert();

					var __x = _invert.TransformPointX(pos.X, pos.Y);
					var __y = _invert.TransformPointY(pos.X, pos.Y);

					pos.X = __x;
					pos.Y = __y;
				}

				if (this.TableCurrentMoveDir == 0)
				{
					this.TableCurrentMoveValue = pos.X;

					if (null != this.TableCurrentMoveValueMin)
					{
						if (this.TableCurrentMoveValueMin > this.TableCurrentMoveValue)
							this.TableCurrentMoveValue = this.TableCurrentMoveValueMin;
					}
					if (null != this.TableCurrentMoveValueMax)
					{
						if (this.TableCurrentMoveValueMax < this.TableCurrentMoveValue)
							this.TableCurrentMoveValue = this.TableCurrentMoveValueMax;
					}

					var _markup                            = HtmlPage.m_oHorRuler.m_oTableMarkup;
					_markup.Cols[this.TableCurrentMovePos] += (this.TableCurrentMoveValue - this.TableCurrentMoveValueOld);
					_markup.Cols[this.TableCurrentMovePos] = Math.max(_markup.Cols[this.TableCurrentMovePos], 1);

					if ( false === HtmlPage.m_oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_Table_Properties) )
					{
						HtmlPage.m_oLogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetTableMarkup_Hor);
						_markup.Table.Update_TableMarkupFromRuler(_markup, true, this.TableCurrentMovePos + 1);
						HtmlPage.m_oLogicDocument.Document_UpdateInterfaceState();
					}
				}
				else
				{
					this.TableCurrentMoveValue = pos.Y;

					if (null != this.TableCurrentMoveValueMin)
					{
						if (this.TableCurrentMoveValueMin > this.TableCurrentMoveValue)
							this.TableCurrentMoveValue = this.TableCurrentMoveValueMin;
					}
					if (null != this.TableCurrentMoveValueMax)
					{
						if (this.TableCurrentMoveValueMax < this.TableCurrentMoveValue)
							this.TableCurrentMoveValue = this.TableCurrentMoveValueMax;
					}

					var _markup = HtmlPage.m_oHorRuler.m_oTableMarkup;
					_markup.Rows[this.TableCurrentMovePos].H += (this.TableCurrentMoveValue - this.TableCurrentMoveValueOld);

					if ( false === this.delegate.HtmlPage.m_oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_Table_Properties) )
					{
						HtmlPage.m_oLogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetTableMarkup_Hor);
						_markup.Table.Update_TableMarkupFromRuler(_markup, false, this.TableCurrentMovePos + 1);
						HtmlPage.m_oLogicDocument.Document_UpdateInterfaceState();
					}
				}

				HtmlPage.OnUpdateOverlay();
				HtmlPage.EndUpdateOverlay();

				break;
			}
			default:
				break;
		}

		this.checkPointerMultiTouchRemove(e);

		if (this.Api.isViewMode || isPreventDefault)
			AscCommon.g_inputContext.preventVirtualKeyboard(e);

		if (true !== this.iScroll.isAnimating)
			this.CheckContextMenuTouchEnd(isCheckContextMenuMode, isCheckContextMenuSelect, isCheckContextMenuCursor, isCheckContextMenuTableRuler);

		return false;
	};

	CMobileTouchManager.prototype.mainOnTouchStart = function(e)
	{
		if (AscCommon.g_inputContext && AscCommon.g_inputContext.externalChangeFocus())
			return;

		if (!this.Api.asc_IsFocus())
			this.Api.asc_enableKeyEvents(true);

		var oWordControl = this.Api.WordControl;

		oWordControl.IsUpdateOverlayOnlyEndReturn = true;
		oWordControl.StartUpdateOverlay();
		var ret = this.onTouchStart(e);
		oWordControl.IsUpdateOverlayOnlyEndReturn = false;
		oWordControl.EndUpdateOverlay();
		return ret;
	};
	CMobileTouchManager.prototype.mainOnTouchMove = function(e)
	{
		var oWordControl = this.Api.WordControl;
		oWordControl.IsUpdateOverlayOnlyEndReturn = true;
		oWordControl.StartUpdateOverlay();
		var ret = this.onTouchMove(e);
		oWordControl.IsUpdateOverlayOnlyEndReturn = false;
		oWordControl.EndUpdateOverlay();
		return ret;
	};
	CMobileTouchManager.prototype.mainOnTouchEnd = function(e)
	{
		var oWordControl = this.Api.WordControl;
		oWordControl.IsUpdateOverlayOnlyEndReturn = true;
		oWordControl.StartUpdateOverlay();
		var ret = this.onTouchEnd(e);
		oWordControl.IsUpdateOverlayOnlyEndReturn = false;
		oWordControl.EndUpdateOverlay();
		return ret;
	};

	/*************************************** READER ******************************************/
	/**
	 * @extends {AscCommon.CMobileDelegateSimple}
	 */
	function CMobileDelegateEditorReader(_manager)
	{
		AscCommon.CMobileDelegateSimple.call(this, _manager);

		this.HtmlPage 			= this.Api.WordControl;
	}
	CMobileDelegateEditorReader.prototype = Object.create(AscCommon.CMobileDelegateSimple.prototype);
	CMobileDelegateEditorReader.prototype.constructor = CMobileDelegateEditorReader;

	CMobileDelegateEditorReader.prototype.GetZoom = function()
	{
		return this.HtmlPage.m_nZoomValue;
	};
	CMobileDelegateEditorReader.prototype.SetZoom = function(_value)
	{
		this.HtmlPage.m_oApi.zoom(_value);
	};
	CMobileDelegateEditorReader.prototype.GetScrollerParent = function()
	{
		return this.HtmlPage.m_oMainView.HtmlElement;
	};

	/**
	 * @extends {AscCommon.CMobileTouchManagerBase}
	 */
	function CReaderTouchManager(_config)
	{
		AscCommon.CMobileTouchManagerBase.call(this, _config || {});

		this.SelectEnabled = false;
		this.TableTrackEnabled = false;

		this.bIsLock          = false;
		this.bIsMoveAfterDown = false;
	}
	CReaderTouchManager.prototype = Object.create(AscCommon.CMobileTouchManagerBase.prototype);
	CReaderTouchManager.prototype.constructor = CReaderTouchManager;

	CReaderTouchManager.prototype.Init = function(_api)
	{
		this.Api = _api;
		this.iScrollElement = "reader_id";

		// создаем делегата. инициализация его - ПОСЛЕ создания iScroll
		this.delegate = new CMobileDelegateEditorReader(this);

		this.iScroll = new window.IScroll(this.delegate.GetScrollerParent(), {
			scrollbars: true,
			mouseWheel: true,
			interactiveScrollbars: true,
			shrinkScrollbars: 'scale',
			fadeScrollbars: true,
			scrollX : true,
			scroller_id : this.iScrollElement,
			bounce : true
		});

		// создаем делегата. инициализация его - ПОСЛЕ создания iScroll
		this.delegate.Init(this);

		this.ClearContextMenu();
	};

	CReaderTouchManager.prototype.onTouchStart = function(e)
	{
		this.iScroll._start(e);
		this.bIsLock          = true;
		this.bIsMoveAfterDown = false;
	};
	CReaderTouchManager.prototype.onTouchMove  = function(e)
	{
		if (!this.bIsLock)
			return;
		this.iScroll._move(e);
		this.bIsMoveAfterDown = true;
	};
	CReaderTouchManager.prototype.onTouchEnd   = function(e)
	{
		this.iScroll._end(e);
		this.bIsLock = false;

		if (this.bIsMoveAfterDown === false)
		{
			this.Api.sendEvent("asc_onTapEvent", e);
		}
	};

	CReaderTouchManager.prototype.Resize = function()
	{
		var HtmlPage = this.delegate.HtmlPage;
		HtmlPage.ReaderModeDivWrapper.style.width  = HtmlPage.m_oMainView.HtmlElement.style.width;
		HtmlPage.ReaderModeDivWrapper.style.height = HtmlPage.m_oMainView.HtmlElement.style.height;

		if (this.iScroll != null)
			this.iScroll.refresh();
	};

	CReaderTouchManager.prototype.ChangeFontSize = function()
	{
		if (this.iScroll != null)
			this.iScroll.refresh();
	};

	CReaderTouchManager.prototype.Destroy = function()
	{
		if (this.iScroll != null)
			this.iScroll.destroy();
	};

	//--------------------------------------------------------export----------------------------------------------------
	window['AscCommon']                          = window['AscCommon'] || {};
	window['AscCommon'].CMobileTouchManager      = CMobileTouchManager;
	window['AscCommon'].CReaderTouchManager      = CReaderTouchManager;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(/**
* @param {Window} window
* @param {undefined} undefined
*/
function(window, undefined) {

// Import
var prot;
var g_fontApplication = AscFonts.g_fontApplication;
var CFont = AscFonts.CFont;
  
var AscBrowser = AscCommon.AscBrowser;
var align_Right = AscCommon.align_Right;
var align_Left = AscCommon.align_Left;
var align_Center = AscCommon.align_Center;
var align_Justify = AscCommon.align_Justify;
var g_oDocumentUrls = AscCommon.g_oDocumentUrls;
var History = AscCommon.History;
var pptx_content_loader = AscCommon.pptx_content_loader;
var pptx_content_writer = AscCommon.pptx_content_writer;
var g_dKoef_pix_to_mm = AscCommon.g_dKoef_pix_to_mm;
var g_dKoef_mm_to_pix = AscCommon.g_dKoef_mm_to_pix;

var CShape = AscFormat.CShape;
var CGraphicFrame = AscFormat.CGraphicFrame;

var c_oAscError = Asc.c_oAscError;
var c_oAscShdClear = Asc.c_oAscShdClear;
var c_oAscShdNil = Asc.c_oAscShdNil;
var c_oAscXAlign = Asc.c_oAscXAlign;

function CDocumentReaderMode()
{
    this.DefaultFontSize = 12;

    this.CorrectDefaultFontSize = function(size)
    {
        if (size < 6)
            return;

        this.DefaultFontSize = size;
    };

    this.CorrectFontSize = function(size)
    {
        var dRes = size / this.DefaultFontSize;
        dRes = (1 + dRes) / 2;
        dRes = (100 * dRes) >> 0;
        dRes /= 100;

        return "" + dRes + "em";
    };
}

function GetObjectsForImageDownload(aBuilderImages, bSameDoc)
{
    var oMapImages = {}, aBuilderImagesByUrl = [], aUrls =[];
    for(var i = 0; i < aBuilderImages.length; ++i)
    {
        if(!g_oDocumentUrls.getImageLocal(aBuilderImages[i].Url))
        {
            if(!Array.isArray(oMapImages[aBuilderImages[i].Url]))
            {
                oMapImages[aBuilderImages[i].Url] = [];
            }
            oMapImages[aBuilderImages[i].Url].push(aBuilderImages[i]);
        }
    }
    for(var key in oMapImages)
    {
        if(oMapImages.hasOwnProperty(key))
        {
            aUrls.push(key);
            aBuilderImagesByUrl.push(oMapImages[key]);
        }
    }
    if(bSameDoc !== true){
        //в конце добавляем ссылки на wmf, ole
        for(var i = 0; i < aBuilderImages.length; ++i)
        {
            var oBuilderImage = aBuilderImages[i];
            if (!g_oDocumentUrls.getImageLocal(oBuilderImage.Url))
            {
                if (oBuilderImage.AdditionalUrls) {
                    for (var j = 0; j < oBuilderImage.AdditionalUrls.length; ++j) {
                        aUrls.push(oBuilderImage.AdditionalUrls[j]);
                    }
                }
            }
        }

    }
    return {aUrls: aUrls, aBuilderImagesByUrl: aBuilderImagesByUrl};
}

function ResetNewUrls(data, aUrls, aBuilderImagesByUrl, oImageMap)
{
    for (var i = 0, length = Math.min(data.length, aBuilderImagesByUrl.length); i < length; ++i)
    {
        var elem = data[i];
        if (null != elem.url)
        {
            var name = g_oDocumentUrls.imagePath2Local(elem.path);
            var aImageElem = aBuilderImagesByUrl[i];
            if(Array.isArray(aImageElem))
            {
                for(var j = 0; j < aImageElem.length; ++j)
                {
                    var imageElem = aImageElem[j];
                    if (null != imageElem)
                    {
                        imageElem.SetUrl(name);
                    }
                }
            }
            oImageMap[i] = name;
        }
        else
        {
            oImageMap[i] = aUrls[i];
        }
    }
}


var PasteElementsId = {
  copyPasteUseBinary : true,
  g_bIsDocumentCopyPaste : true
};
function CopyElement(sName, bText){
	this.sName = sName;
	this.oAttributes = {};
	this.aChildren = [];
	this.bText = bText;
}
CopyElement.prototype.addChild = function(child){
	if(child.bText && this.aChildren.length > 0 && this.aChildren[this.aChildren.length - 1].bText)
		this.aChildren[this.aChildren.length - 1].sName += child.sName;//обьединяем текст, потому что есть места где мы определяем количество child и будет неправильное значение, потому на getOuterHtml тест обьединится в один
	else
		this.aChildren.push(child);
};
CopyElement.prototype.wrapChild = function(child){
	for(var i = 0; i < this.aChildren.length; ++i)
		child.addChild(this.aChildren[i]);
	this.aChildren = [child];
};
CopyElement.prototype.isEmptyChild = function(){
	return 0 === this.aChildren.length;
};
CopyElement.prototype.getInnerText = function(){
	if(this.bText)
		return this.sName;
	else{
		var sRes = "";
		for(var i = 0; i < this.aChildren.length; ++i)
			sRes += this.aChildren[i].getInnerText();
		return sRes;
	}
};
CopyElement.prototype.getInnerHtml = function(){
	if(this.bText)
		return this.sName;
	else{
		var sRes = "";
		for(var i = 0; i < this.aChildren.length; ++i)
			sRes += this.aChildren[i].getOuterHtml();
		return sRes;
	}
};
CopyElement.prototype.getOuterHtml = function(){
	if(this.bText)
		return this.sName;
	else{
		var sRes = "<" + this.sName;
		for(var i in this.oAttributes)
			sRes += " " + i + "=\"" + this.oAttributes[i] + "\"";
		var sInner = this.getInnerHtml();
		if(sInner.length > 0)
			sRes += ">" + sInner + "</" + this.sName + ">";
		else
			sRes += "/>";
		return sRes;
	}
};
function CopyProcessor(api, onlyBinaryCopy)
{
	this.api = api;
    this.oDocument = api.WordControl.m_oLogicDocument;
	this.onlyBinaryCopy = onlyBinaryCopy;
	
	this.oBinaryFileWriter = new AscCommonWord.BinaryFileWriter(this.oDocument);
	this.oPresentationWriter = new AscCommon.CBinaryFileWriter();
    this.oPresentationWriter.Start_UseFullUrl();
    if (this.api.ThemeLoader) {
        this.oPresentationWriter.Start_UseDocumentOrigin(this.api.ThemeLoader.ThemesUrlAbs);
    }
	
	this.oRoot = new CopyElement("root");
}
CopyProcessor.prototype =
{
    getInnerHtml : function()
    {
        return this.oRoot.getInnerHtml();
    },
    getInnerText : function()
    {
        return this.oRoot.getInnerText();
    },
    RGBToCSS : function(rgb, unifill)
    {
        if (null == rgb && null != unifill) {
            unifill.check(this.oDocument.Get_Theme(), this.oDocument.Get_ColorMap());
            var RGBA = unifill.getRGBAColor();
            rgb = new CDocumentColor(RGBA.R, RGBA.G, RGBA.B);
        }
        var sResult = "#";
        var sR = rgb.r.toString(16);
        if(sR.length === 1)
            sR = "0" + sR;
        var sG = rgb.g.toString(16);
        if(sG.length === 1)
            sG = "0" + sG;
        var sB = rgb.b.toString(16);
        if(sB.length === 1)
            sB = "0" + sB;
        return "#" + sR + sG + sB;
    },
    Commit_pPr : function(Item, Para)
    {
        //pPr
        var apPr = [];
        var Def_pPr = this.oDocument.Styles ? this.oDocument.Styles.Default.ParaPr : null;
        var Item_pPr = Item.CompiledPr && Item.CompiledPr.Pr && Item.CompiledPr.Pr.ParaPr ? Item.CompiledPr.Pr.ParaPr : Item.Pr;
        if(Item_pPr && Def_pPr)
        {
            //Ind
            if(Def_pPr.Ind.Left !== Item_pPr.Ind.Left)
                apPr.push("margin-left:" + (Item_pPr.Ind.Left * g_dKoef_mm_to_pt) + "pt");
            if(Def_pPr.Ind.Right !== Item_pPr.Ind.Right)
                apPr.push("margin-right:" + ( Item_pPr.Ind.Right * g_dKoef_mm_to_pt) + "pt");
            if(Def_pPr.Ind.FirstLine !== Item_pPr.Ind.FirstLine)
                apPr.push("text-indent:" + (Item_pPr.Ind.FirstLine * g_dKoef_mm_to_pt) + "pt");
            //Jc
            if(Def_pPr.Jc !== Item_pPr.Jc){
                switch(Item_pPr.Jc)
                {
                    case align_Left: apPr.push("text-align:left");break;
                    case align_Center: apPr.push("text-align:center");break;
                    case align_Right: apPr.push("text-align:right");break;
                    case align_Justify: apPr.push("text-align:justify");break;
                }
            }
            //KeepLines , WidowControl
            if(Def_pPr.KeepLines !== Item_pPr.KeepLines || Def_pPr.WidowControl !== Item_pPr.WidowControl)
            {
                if(Def_pPr.KeepLines !== Item_pPr.KeepLines && Def_pPr.WidowControl !== Item_pPr.WidowControl)
                    apPr.push("mso-pagination:none lines-together");
                else if(Def_pPr.KeepLines !== Item_pPr.KeepLines)
                    apPr.push("mso-pagination:widow-orphan lines-together");
                else if(Def_pPr.WidowControl !== Item_pPr.WidowControl)
                    apPr.push("mso-pagination:none");
            }
            //KeepNext
            if(Def_pPr.KeepNext !== Item_pPr.KeepNext)
                apPr.push("page-break-after:avoid");
            //PageBreakBefore
            if(Def_pPr.PageBreakBefore !== Item_pPr.PageBreakBefore)
                apPr.push("page-break-before:always");
            //Spacing
            if(Def_pPr.Spacing.Line !== Item_pPr.Spacing.Line)
            {
                if(Asc.linerule_AtLeast === Item_pPr.Spacing.LineRule)
                    apPr.push("line-height:"+(Item_pPr.Spacing.Line * g_dKoef_mm_to_pt)+"pt");
                else if( Asc.linerule_Auto === Item_pPr.Spacing.LineRule)
                {
                    if(1 === Item_pPr.Spacing.Line)
                        apPr.push("line-height:normal");
                    else
                        apPr.push("line-height:"+parseInt(Item_pPr.Spacing.Line * 100)+"%");
                }
            }
            if(Def_pPr.Spacing.LineRule !== Item_pPr.Spacing.LineRule)
            {
                if(Asc.linerule_Exact === Item_pPr.Spacing.LineRule)
                    apPr.push("mso-line-height-rule:exactly");
            }
			//TODO при вставке в EXCEL(внутрь ячейки) появляются лишние пустые строки из-за того, что в HTML пишутся отступы - BUG #14663
			//При вставке в word лучше чтобы эти значения выставлялись всегда
            //if(Def_pPr.Spacing.Before != Item_pPr.Spacing.Before)
            apPr.push("margin-top:" + (Item_pPr.Spacing.Before * g_dKoef_mm_to_pt) + "pt");
            //if(Def_pPr.Spacing.After != Item_pPr.Spacing.After)
            apPr.push("margin-bottom:" + (Item_pPr.Spacing.After * g_dKoef_mm_to_pt) + "pt");
            //Shd
            if (null != Item_pPr.Shd && c_oAscShdNil !== Item_pPr.Shd.Value && (null != Item_pPr.Shd.Color || null != Item_pPr.Shd.Unifill))
                apPr.push("background-color:" + this.RGBToCSS(Item_pPr.Shd.Color, Item_pPr.Shd.Unifill));
            //Tabs
            if(Item_pPr.Tabs.Get_Count() > 0)
            {
                var sTabs = "";
                //tab-stops:1.0cm 3.0cm 5.0cm
                for(var i = 0, length = Item_pPr.Tabs.Get_Count(); i < length; i++)
                {
                    if(0 !== i)
                        sTabs += " ";
                    sTabs += Item_pPr.Tabs.Get(i).Pos / 10 + "cm";
                }
                apPr.push("tab-stops:" + sTabs);
            }
            //Border
            if(null != Item_pPr.Brd)
            {
                apPr.push("border:none");
                var borderStyle = this._BordersToStyle(Item_pPr.Brd, false, true, "mso-", "-alt");
                if(null != borderStyle)
                {
                    var nborderStyleLength = borderStyle.length;
                    if(nborderStyleLength> 0)
                        borderStyle = borderStyle.substring(0, nborderStyleLength - 1);
                    apPr.push(borderStyle);
                }
            }
        }
        if(apPr.length > 0)
            Para.oAttributes["style"] = apPr.join(';');
    },
    parse_para_TextPr : function(Value, oTarget)
    {
        var aProp = [];
        if (null != Value.RFonts) {
            var sFontName = null;
            if (null != Value.RFonts.Ascii)
                sFontName = Value.RFonts.Ascii.Name;
            else if (null != Value.RFonts.HAnsi)
                sFontName = Value.RFonts.HAnsi.Name;
            else if (null != Value.RFonts.EastAsia)
                sFontName = Value.RFonts.EastAsia.Name;
            else if (null != Value.RFonts.CS)
                sFontName = Value.RFonts.CS.Name;
            if (null != sFontName){
                var oTheme = this.oDocument && this.oDocument.Get_Theme && this.oDocument.Get_Theme();
                if(oTheme && oTheme.themeElements && oTheme.themeElements.fontScheme){
                    sFontName = oTheme.themeElements.fontScheme.checkFont(sFontName)
                }
                aProp.push("font-family:" + "'" + CopyPasteCorrectString(sFontName) + "'");
            }

        }
        if (null != Value.FontSize) {
            if (!this.api.DocumentReaderMode)
                aProp.push("font-size:" + Value.FontSize + "pt");//font-size в pt все остальные метрики в mm
            else
                aProp.push("font-size:" + this.api.DocumentReaderMode.CorrectFontSize(Value.FontSize));
        }
        if (true == Value.Bold)
			oTarget.wrapChild(new CopyElement("b"));
        if (true == Value.Italic)
			oTarget.wrapChild(new CopyElement("i"));
		if (true == Value.Underline)
			oTarget.wrapChild(new CopyElement("u"));
        if (true == Value.Strikeout)
			oTarget.wrapChild(new CopyElement("s"));
		 if (true == Value.DStrikeout)
			 oTarget.wrapChild(new CopyElement("s"));
        if (null != Value.Shd && c_oAscShdNil !== Value.Shd.Value && (null != Value.Shd.Color || null != Value.Shd.Unifill))
            aProp.push("background-color:" + this.RGBToCSS(Value.Shd.Color, Value.Shd.Unifill));
        else if (null != Value.HighLight && highlight_None !== Value.HighLight)
            aProp.push("background-color:" + this.RGBToCSS(Value.HighLight, null));
        if (null != Value.Color || null != Value.Unifill) {
			var color;
			//TODO правка того, что в полученной html цвет текста всегда чёрный. стоит пересмотреть.
			if(null != Value.Unifill)
				color = this.RGBToCSS(null, Value.Unifill);
			else
				color = this.RGBToCSS(Value.Color, Value.Unifill);
   
            aProp.push("color:" + color);
            aProp.push("mso-style-textfill-fill-color:" + color);
        }
        if (null != Value.VertAlign) {
            if(AscCommon.vertalign_SuperScript === Value.VertAlign)
                aProp.push("vertical-align:super");
            else if(AscCommon.vertalign_SubScript === Value.VertAlign)
                aProp.push("vertical-align:sub");
        }
		if(aProp.length > 0)
			oTarget.oAttributes["style"] = aProp.join(';');
    },
    ParseItem : function(ParaItem, oTarget, nextParaItem, lengthContent)
    {
        switch ( ParaItem.Type )
        {
            case para_Text:
				//экранируем спецсимволы
                var sValue = AscCommon.encodeSurrogateChar(ParaItem.Value);
                if(sValue)
					oTarget.addChild(new CopyElement(CopyPasteCorrectString(sValue), true));
                break;
            case para_Space:
				//TODO пересмотреть обработку пробелов - возможно стоит всегда копировать неразрывный пробел!!!!!
				//в случае нескольких пробелов друг за другом добавляю неразрывный пробел, иначе добавиться только один
				//lengthContent - если в элемент добавляется только один пробел, этот элемент не записывается в буфер, поэтому добавляем неразрывный пробел
				if((nextParaItem && nextParaItem.Type === para_Space) || lengthContent === 1)
					oTarget.addChild(new CopyElement("&nbsp;", true));
				else
					oTarget.addChild(new CopyElement(" ", true));	
				break;
			case para_Tab:
				var oSpan = new CopyElement("span");
				oSpan.oAttributes["style"] = "white-space:pre;";
				oSpan.oAttributes["style"] = "mso-tab-count:1;";
				oSpan.addChild(new CopyElement(String.fromCharCode(0x09), true));
				oTarget.addChild(oSpan);
				break;
            case para_NewLine:
				var oBr = new CopyElement("br");
                if( break_Page === ParaItem.BreakType)
                {
					oBr.oAttributes["clear"] = "all";
					oBr.oAttributes["style"] = "mso-special-character:line-break;page-break-before:always;";
                }
                else
					oBr.oAttributes["style"] = "mso-special-character:line-break;";
				oTarget.addChild(oBr);
				//todo закончить этот параграф и начать новый
				//добавил неразрвной пробел для того, чтобы информация попадала в буфер обмена
				var oSpan = new CopyElement("span");
				oSpan.addChild(new CopyElement("&nbsp;", true));
				oTarget.addChild(oSpan);
                break;
            case para_Drawing:
                var oGraphicObj = ParaItem.GraphicObj;
                var sSrc = oGraphicObj.getBase64Img();
                if(sSrc.length > 0)
                {
					var _h, _w;
					if(oGraphicObj.cachedPixH)
						_h = oGraphicObj.cachedPixH;
					else
						_h = ParaItem.Extent.H * g_dKoef_mm_to_pix;
					
					if(oGraphicObj.cachedPixW)
						_w = oGraphicObj.cachedPixW;
					else
						_w = ParaItem.Extent.W * g_dKoef_mm_to_pix;
						
					var oImg = new CopyElement("img");
					oImg.oAttributes["style"] = "max-width:100%;";
					oImg.oAttributes["width"] = Math.round(_w);
					oImg.oAttributes["height"] = Math.round(_h);
					oImg.oAttributes["src"] = sSrc;
					oTarget.addChild(oImg);
                    break;
                }
                // var _canvas     = document.createElement('canvas');
                // var w = img.width;
                // var h = img.height;

                // _canvas.width   = w;
                // _canvas.height  = h;

                // var _ctx        = _canvas.getContext('2d');
                // _ctx.globalCompositeOperation = "copy";
                // _ctx.drawImage(img, 0, 0);

                // var _data = _ctx.getImageData(0, 0, w, h);
                // _ctx = null;
                // delete _canvas;
                break;
			case para_PageNum:
				if(null != ParaItem.String && "string" === typeof(ParaItem.String))
					oTarget.addChild(new CopyElement(CopyPasteCorrectString(ParaItem.String), true));
				break;
        }
    },
    CopyRun: function (Item, oTarget) {
        for (var i = 0; i < Item.Content.length; i++)
            this.ParseItem(Item.Content[i], oTarget, Item.Content[i + 1], Item.Content.length);
    },
    CopyRunContent: function (Container, oTarget, bOmitHyperlink) {
        for (var i = 0; i < Container.Content.length; i++) {
            var item = Container.Content[i];
            if (para_Run === item.Type) {
				var oSpan = new CopyElement("span");
                this.CopyRun(item, oSpan);
                if(!oSpan.isEmptyChild()){
					this.parse_para_TextPr(item.Get_CompiledTextPr(), oSpan);
					oTarget.addChild(oSpan);
				}
            }
            else if (para_Hyperlink === item.Type) {
                if (!bOmitHyperlink) {
					var oHyperlink = new CopyElement("a");
                    var sValue = item.GetValue();
                    var sToolTip = item.GetToolTip();
					oHyperlink.oAttributes["href"] = CopyPasteCorrectString(sValue);
					oHyperlink.oAttributes["title"] = CopyPasteCorrectString(sToolTip);
					//вложенные ссылки в html запрещены.
					this.CopyRunContent(item, oHyperlink, true);
					oTarget.addChild(oHyperlink);
                }
				else
					this.CopyRunContent(item, oTarget, true);
            }
			else if(para_Math === item.Type){
                var sSrc = item.MathToImageConverter();
				if (null != sSrc && null != sSrc.ImageUrl){
					var oImg = new CopyElement("img");
					if (sSrc.w_px > 0) {
						oImg.oAttributes["width"] = sSrc.w_px;
					}
					if (sSrc.h_px > 0) {
						oImg.oAttributes["height"] = sSrc.h_px;
					}
					oImg.oAttributes["src"] = sSrc.ImageUrl;
					oTarget.addChild(oImg);
				}
			}
			else if(para_Field === item.Type)
				this.CopyRunContent(item, oTarget);
        }
    },
    CopyParagraph : function(oDomTarget, Item, selectedAll)
    {
        var oDocument = this.oDocument;
		var Para = null;
		//Для heading пишем в h1
        var styleId = Item.Style_Get();
        if(styleId)
        {
            var styleName = oDocument.Styles.Get_Name( styleId ).toLowerCase();
			//шаблон "heading n" (n=1:6)
            if(0 === styleName.indexOf("heading"))
            {
                var nLevel = parseInt(styleName.substring("heading".length));
                if(1 <= nLevel && nLevel <= 6)
                    Para = new CopyElement("h" + nLevel);
            }
        }
        if(null == Para)
            Para = new CopyElement("p");

        var oNumPr;
        var bIsNullNumPr = false;
        if(PasteElementsId.g_bIsDocumentCopyPaste)
        {
            oNumPr = Item.GetNumPr();
            bIsNullNumPr = (null == oNumPr || 0 == oNumPr.NumId);
        }
        else
        {
            oNumPr = Item.PresentationPr.Bullet;
            bIsNullNumPr = (0 == oNumPr.m_nType);
        }
		var bBullet = false;
        var sListStyle = "";
        if(!bIsNullNumPr)
        {
            if(PasteElementsId.g_bIsDocumentCopyPaste)
			{
				var oNum = this.oDocument.GetNumbering().GetNum(oNumPr.NumId);
				if (oNum)
				{
					var oNumberingLvl = oNum.GetLvl(oNumPr.Lvl);
					if (oNumberingLvl)
					{
						switch (oNumberingLvl.GetFormat())
						{
							case Asc.c_oAscNumberingFormat.Decimal:
								sListStyle = "decimal";
								break;
							case Asc.c_oAscNumberingFormat.LowerRoman:
								sListStyle = "lower-roman";
								break;
							case Asc.c_oAscNumberingFormat.UpperRoman:
								sListStyle = "upper-roman";
								break;
							case Asc.c_oAscNumberingFormat.LowerLetter:
								sListStyle = "lower-alpha";
								break;
							case Asc.c_oAscNumberingFormat.UpperLetter:
								sListStyle = "upper-alpha";
								break;
							default:
								sListStyle = "disc";
								bBullet    = true;
								break;
						}
					}
				}
			}
            else
            {
                var _presentation_bullet = Item.PresentationPr.Bullet;
                switch(_presentation_bullet.m_nType)
                {
                    case numbering_presentationnumfrmt_ArabicPeriod:
                    case numbering_presentationnumfrmt_ArabicParenR:
                    {
                        sListStyle = "decimal";
                        break;
                    }
                    case numbering_presentationnumfrmt_RomanLcPeriod: sListStyle = "lower-roman";break;
                    case numbering_presentationnumfrmt_RomanUcPeriod: sListStyle = "upper-roman";break;

                    case numbering_presentationnumfrmt_AlphaLcParenR:
                    case numbering_presentationnumfrmt_AlphaLcPeriod:
                    {
                        sListStyle = "lower-alpha";
                        break;
                    }
                    case numbering_presentationnumfrmt_AlphaUcParenR:
                    case numbering_presentationnumfrmt_AlphaUcPeriod:
                    {
                        sListStyle = "upper-alpha";
                        break;
                    }

                    default:
                        sListStyle = "disc";
                        bBullet = true;
                        break;
                }
            }
        }
        //pPr
        this.Commit_pPr(Item, Para);

        if(false === selectedAll)
        {
			//если последний элемент в выделении неполностью выделенный параграф, то он копируется как обычный текст без настроек параграфа и списков
			this.CopyRunContent(Item, oDomTarget, false);
        }
        else
        {
			this.CopyRunContent(Item, Para, false);
			//добавляем &nbsp; потому что параграфы без содержимого не копируются
            if(Para.isEmptyChild())
                Para.addChild(new CopyElement("&nbsp;", true));
            if(bIsNullNumPr)
                oDomTarget.addChild( Para );
			else{
				var Li = new CopyElement( "li" );
				Li.oAttributes["style"] = "list-style-type: " + sListStyle;
				Li.addChild( Para );
				//пробуем добавить в предыдущий список
				var oTargetList = null;
				if(oDomTarget.aChildren.length > 0){
					var oPrevElem = oDomTarget.aChildren[oDomTarget.aChildren.length - 1];
					if((bBullet && "ul" === oPrevElem.sName) || (!bBullet && "ol" === oPrevElem.sName))
						oTargetList = oPrevElem;
				}
				if(null == oTargetList){
					if(bBullet)
						oTargetList = new CopyElement("ul");
					else
						oTargetList = new CopyElement("ol");
					oTargetList.oAttributes["style"] = "padding-left:40px";
					oDomTarget.addChild(oTargetList);
				}
				oTargetList.addChild(Li);
			}
        }
    },
    _BorderToStyle : function(border, name)
    {
        var res = "";
        if(border_None === border.Value)
            res += name + ":none;";
        else
        {
            var size = 0.5;
            var color = border.Color;
            var unifill = border.Unifill;
            if(null != border.Size)
                size = border.Size * g_dKoef_mm_to_pt;
            if (null == color)
                color = { r: 0, g: 0, b: 0 };
            res += name + ":" + size + "pt solid " + this.RGBToCSS(color, unifill) + ";";
        }
        return res;
    },
    _MarginToStyle : function(margins, styleName)
    {
        var res = "";
        var nMarginLeft = 1.9;
        var nMarginTop = 0;
        var nMarginRight = 1.9;
        var nMarginBottom = 0;
        if(null != margins.Left && tblwidth_Mm === margins.Left.Type && null != margins.Left.W)
            nMarginLeft = margins.Left.W;
        if(null != margins.Top && tblwidth_Mm === margins.Top.Type && null != margins.Top.W)
            nMarginTop = margins.Top.W;
        if(null != margins.Right && tblwidth_Mm === margins.Right.Type && null != margins.Right.W)
            nMarginRight = margins.Right.W;
        if(null != margins.Bottom && tblwidth_Mm === margins.Bottom.Type && null != margins.Bottom.W)
            nMarginBottom = margins.Bottom.W;
        res = styleName + ":"+(nMarginTop * g_dKoef_mm_to_pt)+"pt "+(nMarginRight * g_dKoef_mm_to_pt)+"pt "+(nMarginBottom * g_dKoef_mm_to_pt)+"pt "+(nMarginLeft * g_dKoef_mm_to_pt)+"pt;";
        return res;
    },
    _BordersToStyle : function(borders, bUseInner, bUseBetween, mso, alt)
    {
        var res = "";
        if(null == mso)
            mso = "";
        if(null == alt)
            alt = "";
        if(null != borders.Left)
            res += this._BorderToStyle(borders.Left, mso + "border-left" + alt);
        if(null != borders.Top)
            res += this._BorderToStyle(borders.Top, mso + "border-top" + alt);
        if(null != borders.Right)
            res += this._BorderToStyle(borders.Right, mso + "border-right" + alt);
        if(null != borders.Bottom)
            res += this._BorderToStyle(borders.Bottom, mso + "border-bottom" + alt);
		if(bUseInner)
		{
			if(null != borders.InsideV)
				res += this._BorderToStyle(borders.InsideV, "mso-border-insidev");
			if(null != borders.InsideH)
				res += this._BorderToStyle(borders.InsideH, "mso-border-insideh");
		}
		if(bUseBetween)
		{
			if(null != borders.Between)
				res += this._BorderToStyle(borders.Between, "mso-border-between");
		}
        return res;
    },
    _MergeProp : function(elem1, elem2)
    {
        if( !elem1 || !elem2 )
        {
            return;
        }

        var p, v;
        for(p in elem2)
        {
            if(elem2.hasOwnProperty(p) && !elem1.hasOwnProperty(p))
            {
                v = elem2[p];
                if(null != v)
                    elem1[p] = v;
            }
        }
    },
    CopyCell : function(tr, cell, tablePr, width, rowspan)
    {
        var tc = new CopyElement("td");
        //Pr
        var tcStyle = "";
        if(width > 0)
        {
            tc.oAttributes["width"] = Math.round(width * g_dKoef_mm_to_pix);
            tcStyle += "width:"+(width * g_dKoef_mm_to_pt)+"pt;";
        }
        if(rowspan > 1)
            tc.oAttributes["rowspan"] = rowspan;
        var cellPr = null;
		
		var tablePr = null;
        if(!PasteElementsId.g_bIsDocumentCopyPaste && editor.WordControl.m_oLogicDocument && null != cell.CompiledPr && null != cell.CompiledPr.Pr)
		{
			var presentation = editor.WordControl.m_oLogicDocument;
			var curSlide = presentation.Slides[presentation.CurPage];
			if(presentation && curSlide && curSlide.Layout && curSlide.Layout.Master && curSlide.Layout.Master.Theme)
        AscFormat.checkTableCellPr(cell.CompiledPr.Pr, curSlide, curSlide.Layout, curSlide.Layout.Master, curSlide.Layout.Master.Theme);	
		}
		
		if(null != cell.CompiledPr && null != cell.CompiledPr.Pr)
        {
            cellPr = cell.CompiledPr.Pr;
			//Для первых и послених ячеек выставляются margin а не colspan
            if(null != cellPr.GridSpan && cellPr.GridSpan > 1)
				tc.oAttributes["colspan"] = cellPr.GridSpan;
        }
        if(null != cellPr && null != cellPr.Shd)
        {
            if (c_oAscShdNil !== cellPr.Shd.Value && (null != cellPr.Shd.Color || null != cellPr.Shd.Unifill))
                tcStyle += "background-color:" + this.RGBToCSS(cellPr.Shd.Color, cellPr.Shd.Unifill) + ";";
        }
        else if(null != tablePr && null != tablePr.Shd)
        {
            if (c_oAscShdNil !== tablePr.Shd.Value && (null != tablePr.Shd.Color || null != tablePr.Shd.Unifill))
                tcStyle += "background-color:" + this.RGBToCSS(tablePr.Shd.Color, tablePr.Shd.Unifill) + ";";
        }
        var oCellMar = {};
        if(null != cellPr && null != cellPr.TableCellMar)
            this._MergeProp(oCellMar, cellPr.TableCellMar);
        if(null != tablePr && null != tablePr.TableCellMar)
            this._MergeProp(oCellMar, tablePr.TableCellMar);
        tcStyle += this._MarginToStyle(oCellMar, "padding");

        var oCellBorder = cell.Get_Borders();
        tcStyle += this._BordersToStyle(oCellBorder, false, false);

        if("" != tcStyle)
            tc.oAttributes["style"] = tcStyle;
        //Content
        this.CopyDocument2(tc, cell.Content);

        tr.addChild(tc);
    },
    CopyRow : function(oDomTarget, table, nCurRow, elems, nMaxRow)
    {
        var row = table.Content[nCurRow];
		if(null == elems)
			elems = {gridStart: 0, gridEnd: table.TableGrid.length - 1, indexStart: null, indexEnd: null, after: null, before: null, cells: row.Content};
        var tr = new CopyElement("tr");
        //Pr
		table.Recalculate_Grid();
		var gridSum = table.TableSumGrid;
        var trStyle = "";
        var nGridBefore = 0;
		var rowPr = null;
		
		var CompiledPr = row.Get_CompiledPr();
		if(null != CompiledPr)
			rowPr = CompiledPr;
        if(null != rowPr)
        {
			if(null == elems.before && null != rowPr.GridBefore && rowPr.GridBefore > 0)
			{
                elems.before = rowPr.GridBefore;
				elems.gridStart += rowPr.GridBefore;
			}
			if(null == elems.after && null != rowPr.GridAfter && rowPr.GridAfter > 0)
			{
                elems.after = rowPr.GridAfter;
				elems.gridEnd -= rowPr.GridAfter;
			}
            //height
            if(null != rowPr.Height && Asc.linerule_Auto != rowPr.Height.HRule && null != rowPr.Height.Value)
            {
                trStyle += "height:"+(rowPr.Height.Value * g_dKoef_mm_to_pt)+"pt;";
            }
        }
		//WBefore
        if(null != elems.before)
        {
            if(elems.before > 0)
            {
                nGridBefore = elems.before;
                var nWBefore = gridSum[elems.gridStart - 1] - gridSum[elems.gridStart - nGridBefore - 1];
				//Записываем margin
                trStyle += "mso-row-margin-left:"+(nWBefore * g_dKoef_mm_to_pt)+"pt;";
				//добавляем td для тех кто не понимает mso-row-margin-left
                var oNewTd = new CopyElement("td");
                oNewTd.oAttributes["style"] = "mso-cell-special:placeholder;border:none;padding:0cm 0cm 0cm 0cm";
                oNewTd.oAttributes["width"] = Math.round(nWBefore * g_dKoef_mm_to_pix);
                if(nGridBefore > 1)
                    oNewTd.oAttributes["colspan"] = nGridBefore;
                var oNewP = new CopyElement("p");
				oNewP.oAttributes["style"] = "margin:0cm";
                oNewP.addChild(new CopyElement("&nbsp;", true));
                oNewTd.addChild(oNewP);
                tr.addChild(oNewTd);
            }
        }
		
		var tablePr = null;
		var compiledTablePr = table.Get_CompiledPr();
		if(null != compiledTablePr && null != compiledTablePr.TablePr)
			tablePr = compiledTablePr.TablePr;
        //tc
        for(var i in elems.cells)
        {
            var cell = row.Content[i];
			if(vmerge_Continue !== cell.GetVMerge())
			{
				var StartGridCol = cell.Metrics.StartGridCol;
				var GridSpan = cell.Get_GridSpan();
				var width = gridSum[StartGridCol + GridSpan - 1] - gridSum[StartGridCol - 1];
				//вычисляем rowspan
				var nRowSpan = table.Internal_GetVertMergeCount(nCurRow, StartGridCol, GridSpan);
				if(nCurRow + nRowSpan - 1 > nMaxRow)
				{
					nRowSpan = nMaxRow - nCurRow + 1;
					if(nRowSpan <= 0)
						nRowSpan = 1;
				}
				this.CopyCell(tr, cell, tablePr, width, nRowSpan);
			}
        }
        //WAfter
        if(null != elems.after)
        {
            if(elems.after > 0)
            {
                var nGridAfter = elems.after;
                var nWAfter = gridSum[elems.gridEnd + nGridAfter] - gridSum[elems.gridEnd];
				//Записываем margin
                trStyle += "mso-row-margin-right:"+(nWAfter * g_dKoef_mm_to_pt)+"pt;";
				//добавляем td для тех кто не понимает mso-row-margin-left
                var oNewTd = new CopyElement("td");
                oNewTd.oAttributes["style"] = "mso-cell-special:placeholder;border:none;padding:0cm 0cm 0cm 0cm";
				oNewTd.oAttributes["width"] = Math.round(nWAfter * g_dKoef_mm_to_pix);
                if(nGridAfter > 1)
					oNewTd.oAttributes["colspan"] = nGridAfter;
                var oNewP = new CopyElement("p");
				oNewP.oAttributes["style"] = "margin:0cm";
				oNewP.addChild(new CopyElement("&nbsp;", true));
                oNewTd.addChild(oNewP);
                tr.addChild(oNewTd);
            }
        }
        if("" != trStyle)
            tr.oAttributes["style"] = trStyle;
			
        oDomTarget.addChild(tr);
    },
    CopyTable : function(oDomTarget, table, aRowElems)
    {
        var DomTable = new CopyElement("table");
		
		var compiledPr = table.Get_CompiledPr();
		
        var Pr = null;
        if(compiledPr && null != compiledPr.TablePr)
            Pr = compiledPr.TablePr;
        var tblStyle = "";
        var bBorder = false;
        if(null != Pr)
        {
			var align = "";
            if(true != table.Inline && null != table.PositionH)
			{
				var PositionH = table.PositionH;
				if(true === PositionH.Align)
				{
					switch(PositionH.Value)
					{
						case c_oAscXAlign.Outside:
						case c_oAscXAlign.Right: align = "right";break;
						case c_oAscXAlign.Center: align = "center";break;
					}
				}
				else if(table.TableSumGrid)
				{
					var TableWidth = table.TableSumGrid[ table.TableSumGrid.length - 1 ];
					var nLeft = PositionH.Value;
					var nRight = nLeft + TableWidth;
					var nFromLeft = Math.abs(nLeft - X_Left_Margin);
					var nFromCenter = Math.abs((Page_Width - X_Right_Margin + X_Left_Margin) / 2 - (nLeft + nRight) / 2);
					var nFromRight = Math.abs(Page_Width - nRight - X_Right_Margin);
					if(nFromRight < nFromLeft || nFromCenter < nFromLeft)
					{
						if(nFromRight < nFromCenter)
							align = "right";
						else
							align = "center";
					}
				}
			}
			else if(null != Pr.Jc)
            {
                switch(Pr.Jc)
                {
                    case align_Center:align = "center";break;
                    case align_Right:align = "right";break;
                }
            }
			if("" != align)
				DomTable.oAttributes["align"] = align;
            if(null != Pr.TableInd)
                tblStyle += "margin-left:"+(Pr.TableInd * g_dKoef_mm_to_pt)+"pt;";
            if (null != Pr.Shd && c_oAscShdNil !== Pr.Shd.Value && (null != Pr.Shd.Color || null != Pr.Shd.Unifill))
                tblStyle += "background:" + this.RGBToCSS(Pr.Shd.Color, Pr.Shd.Unifill) + ";";
            if(null != Pr.TableCellMar)
                tblStyle += this._MarginToStyle(Pr.TableCellMar, "mso-padding-alt");
            if(null != Pr.TableBorders)
                tblStyle += this._BordersToStyle(Pr.TableBorders, true, false);
        }
		//ищем cellSpacing
        var bAddSpacing = false;
        if(table.Content.length > 0)
        {
            var firstRow = table.Content[0];
			var rowPr = firstRow.Get_CompiledPr();
            if(null != rowPr && null != rowPr.TableCellSpacing)
            {
                bAddSpacing = true;
                var cellSpacingMM = rowPr.TableCellSpacing;
                tblStyle += "mso-cellspacing:"+(cellSpacingMM * g_dKoef_mm_to_pt)+"pt;";
				DomTable.oAttributes["cellspacing"] = Math.round(cellSpacingMM * g_dKoef_mm_to_pix);
            }
        }
        if(!bAddSpacing)
            DomTable.oAttributes["cellspacing"] = 0;
        DomTable.oAttributes["border"] = false == bBorder ? 0 : 1;
        DomTable.oAttributes["cellpadding"] = 0;
        if("" != tblStyle)
            DomTable.oAttributes["style"] = tblStyle;

        //rows
		if(null == aRowElems)
		{
			for(var i = 0, length = table.Content.length; i < length; i++)
				this.CopyRow(DomTable, table, i , null, table.Content.length - 1);
		}
		else
		{
			var nMaxRow = 0;
			for(var i = 0, length = aRowElems.length; i < length; ++i)
			{
				var elem = aRowElems[i];
				if(elem.row > nMaxRow)
					nMaxRow = elem.row;
			}
			for(var i = 0, length = aRowElems.length; i < length; ++i)
			{
				var elem = aRowElems[i];
				this.CopyRow(DomTable, table, elem.row, elem, nMaxRow);
			}
		}

        oDomTarget.addChild(DomTable);
    },
	
	CopyDocument2 : function(oDomTarget, oDocument, elementsContent, dNotGetBinary)
	{
		if(PasteElementsId.g_bIsDocumentCopyPaste)
		{
			if(!elementsContent && oDocument && oDocument.Content)
				elementsContent = oDocument.Content;
			
			for ( var Index = 0; Index < elementsContent.length; Index++ )
			{
				var Item;
				if(elementsContent[Index].Element)
					Item = elementsContent[Index].Element;
				else
					Item = elementsContent[Index];
				
				if(type_Table === Item.GetType() )
				{
					this.oBinaryFileWriter.copyParams.bLockCopyElems++;
					if(!this.onlyBinaryCopy)
						this.CopyTable(oDomTarget, Item, null);
					this.oBinaryFileWriter.copyParams.bLockCopyElems--;
					
					if(!dNotGetBinary)
						this.oBinaryFileWriter.CopyTable(Item, null);
				}
				else if ( type_Paragraph === Item.GetType() )
				{
					var SelectedAll = Index === elementsContent.length - 1 ? elementsContent[Index].SelectedAll : true;
					//todo может только для верхнего уровня надо Index == End
					if(!dNotGetBinary)
						this.oBinaryFileWriter.CopyParagraph(Item, SelectedAll);
						
					if(!this.onlyBinaryCopy)
						this.CopyParagraph(oDomTarget, Item, SelectedAll);
				}
				else if(type_BlockLevelSdt === Item.GetType() )
				{
					this.oBinaryFileWriter.copyParams.bLockCopyElems++;
					if(!this.onlyBinaryCopy)
					{
						this.CopyDocument2(oDomTarget, oDocument, Item.Content.Content, true);
					}
					this.oBinaryFileWriter.copyParams.bLockCopyElems--;

					if(!dNotGetBinary)
						this.oBinaryFileWriter.CopySdt(Item);
				}
			}
		}
		else//presentation
		{
			this.copyPresentation2(oDomTarget, oDocument, elementsContent);
		}
    },

	copyPresentation2: function(oDomTarget, oDocument, elementsContent){
		//DocContent/ Drawings/ SlideObjects
		var presentation = this.oDocument;

		if(elementsContent && elementsContent.length){
			if(elementsContent[0].DocContent || (elementsContent[0].Drawings && elementsContent[0].Drawings.length) || (elementsContent[0].SlideObjects && elementsContent[0].SlideObjects.length))
			{
				var themeName = elementsContent[0].ThemeName ? elementsContent[0].ThemeName : "";

				this.oPresentationWriter.WriteString2(this.api.documentId);
				this.oPresentationWriter.WriteString2(themeName);
				this.oPresentationWriter.WriteDouble(presentation.Width);
				this.oPresentationWriter.WriteDouble(presentation.Height);
				//флаг о том, что множественный контент в буфере
				this.oPresentationWriter.WriteBool(true);
			}

			//записываем все варианты контента
			//в html записываем первый вариант - конечное форматирование
			//в банарник пишем: 1)конечное форматирование 2)исходное форматирование 3)картинка
			this.oPresentationWriter.WriteULong(elementsContent.length);
			for(var i = 0; i < elementsContent.length; i++)
			{
				if(i === 0)
				{
					this.copyPresentationContent(elementsContent[i], oDomTarget);
				}
				else
				{
					this.copyPresentationContent(elementsContent[i]);
				}
			}
		}
		/*else if(elementsContent)
		{
			//эту ветку оставляю для записи едиственного варианта контента, который используется функцией getSelectedBinary
			if(elementsContent.DocContent || (elementsContent.Drawings && elementsContent.Drawings.length) || (elementsContent.SlideObjects && elementsContent.SlideObjects.length))
			{
				this.oPresentationWriter.WriteString2(this.api.documentId);
				this.oPresentationWriter.WriteDouble(presentation.Width);
				this.oPresentationWriter.WriteDouble(presentation.Height);
			}
			this.copyPresentationContent(elementsContent, oDomTarget);
		}*/
		else
		{
			//для записи внутреннего контента таблицы
			this.copyPresentationContent(oDocument, oDomTarget);
		}
	},

	copyPresentationContent: function (elementsContent, oDomTarget) {

		if(elementsContent instanceof PresentationSelectedContent){
			this._writePresentationSelectedContent(elementsContent, oDomTarget);
		}
		else
		{
			//inner recursive call CopyDocument2 function
			if (elementsContent && elementsContent.Content && elementsContent.Content.length) {//пишем таблицу в html

				for (var Index = 0; Index < elementsContent.Content.length; Index++) {
					var Item = elementsContent.Content[Index];

					if (type_Table === Item.GetType()) {
						this.CopyTable(oDomTarget, Item, null);
					} else if (type_Paragraph === Item.GetType()) {
						this.CopyParagraph(oDomTarget, Item, true);
					}
				}

			}
		}
	},

	_writePresentationSelectedContent: function(elementsContent, oDomTarget){

		var oThis = this;
		var copyDocContent = function(){
			var docContent = elementsContent.DocContent;

			if (docContent.Elements) {
				var elements = docContent.Elements;

				//пишем метку и длины
				oThis.oPresentationWriter.WriteString2("DocContent");
				oThis.oPresentationWriter.WriteDouble(elements.length);

				//пишем контент
				for (var Index = 0; Index < elements.length; Index++) {
					var Item;
					if (elements[Index].Element) {
						Item = elements[Index].Element;
					} else {
						Item = elements[Index];
					}

					if (type_Paragraph === Item.GetType()) {
						oThis.oPresentationWriter.StartRecord(0);
						oThis.oPresentationWriter.WriteParagraph(Item);
						oThis.oPresentationWriter.EndRecord();

						if (oDomTarget) {
							oThis.CopyParagraph(oDomTarget, Item, true);
						}
					}
				}
			}
		};

		var copyDrawings = function(){
			var elements = elementsContent.Drawings;

			//var selected_objects = graphicObjects.State.id === STATES_ID_GROUP ? graphicObjects.State.group.selectedObjects : graphicObjects.selectedObjects;

			//пишем метку и длины
			oThis.oPresentationWriter.WriteString2("Drawings");
			oThis.oPresentationWriter.WriteULong(elements.length);

			pptx_content_writer.Start_UseFullUrl();
			pptx_content_writer.BinaryFileWriter.ClearIdMap();
			for (var i = 0; i < elements.length; ++i) {
				if (!(elements[i].Drawing instanceof CGraphicFrame)) {
					oThis.oPresentationWriter.WriteBool(true);

					oThis.CopyGraphicObject(oDomTarget, elements[i].Drawing, elements[i]);

					oThis.oPresentationWriter.WriteDouble(elements[i].X);
					oThis.oPresentationWriter.WriteDouble(elements[i].Y);
					oThis.oPresentationWriter.WriteDouble(elements[i].ExtX);
					oThis.oPresentationWriter.WriteDouble(elements[i].ExtY);
					oThis.oPresentationWriter.WriteString2(elements[i].ImageUrl);
				} else {
					var isOnlyTable = elements.length === 1;

					oThis.CopyPresentationTableFull(oDomTarget, elements[i].Drawing, isOnlyTable);

					oThis.oPresentationWriter.WriteDouble(elements[i].X);
					oThis.oPresentationWriter.WriteDouble(elements[i].Y);
					oThis.oPresentationWriter.WriteDouble(elements[i].ExtX);
					oThis.oPresentationWriter.WriteDouble(elements[i].ExtY);
					oThis.oPresentationWriter.WriteString2(elements[i].ImageUrl);
				}
			}
			pptx_content_writer.BinaryFileWriter.ClearIdMap();
			pptx_content_writer.End_UseFullUrl();

		};

		var copySlideObjects = function(){
			var selected_slides = elementsContent.SlideObjects;

			oThis.oPresentationWriter.WriteString2("SlideObjects");
			oThis.oPresentationWriter.WriteULong(selected_slides.length);

			var layouts_map = {};
			var layout_count = 0;
			editor.WordControl.m_oLogicDocument.CalculateComments();

			//пишем слайд
			var slide;
			for (var i = 0; i < selected_slides.length; ++i) {
				slide = selected_slides[i];
				if(i === 0){
					oThis.CopySlide(oDomTarget, slide);
				} else{
					oThis.CopySlide(null, slide);
				}
			}
		};

		var copyLayouts = function(){
			var selected_layouts = elementsContent.Layouts;

			oThis.oPresentationWriter.WriteString2("Layouts");
			oThis.oPresentationWriter.WriteULong(selected_layouts.length);

			for (var i = 0; i < selected_layouts.length; ++i) {
				oThis.CopyLayout(selected_layouts[i]);
			}

		};

		var copyMasters = function(){
			var selected_masters = elementsContent.Masters;

			oThis.oPresentationWriter.WriteString2("Masters");
			oThis.oPresentationWriter.WriteULong(selected_masters.length);

			for (var i = 0; i < selected_masters.length; ++i) {
				oThis.oPresentationWriter.WriteSlideMaster(selected_masters[i]);
			}
		};

		var copyNotes = function(){
			var selected_notes = elementsContent.Notes;

			oThis.oPresentationWriter.WriteString2("Notes");
			oThis.oPresentationWriter.WriteULong(selected_notes.length);

			for (var i = 0; i < selected_notes.length; ++i) {
				oThis.oPresentationWriter.WriteSlideNote(selected_notes[i]);
			}
		};

		var copyNoteMasters = function(){
			var selected_note_master = elementsContent.NotesMasters;

			oThis.oPresentationWriter.WriteString2("NotesMasters");
			oThis.oPresentationWriter.WriteULong(selected_note_master.length);

			for (var i = 0; i < selected_note_master.length; ++i) {
				oThis.oPresentationWriter.WriteNoteMaster(selected_note_master[i]);
			}
		};

		var copyNoteTheme = function(){
			var selected_themes = elementsContent.NotesThemes;

			oThis.oPresentationWriter.WriteString2("NotesThemes");
			oThis.oPresentationWriter.WriteULong(selected_themes.length);

			for (var i = 0; i < selected_themes.length; ++i) {
				oThis.oPresentationWriter.WriteTheme(selected_themes[i]);
			}
		};

		var copyTheme = function(){
			var selected_themes = elementsContent.Themes;

			oThis.oPresentationWriter.WriteString2("Themes");
			oThis.oPresentationWriter.WriteULong(selected_themes.length);

			for (var i = 0; i < selected_themes.length; ++i) {
				oThis.oPresentationWriter.WriteTheme(selected_themes[i]);
			}
		};

		var copyIndexes = function(selected_indexes){
			oThis.oPresentationWriter.WriteULong(selected_indexes.length);
			for (var i = 0; i < selected_indexes.length; ++i) {
				oThis.oPresentationWriter.WriteULong(selected_indexes[i]);
			}
		};


		//получаем пишем количество
		var contentCount = 0;
		for(var i in elementsContent){
			if(elementsContent[i] && typeof elementsContent[i] === "object" && elementsContent[i].length){
				contentCount++;
			} else if(null !== elementsContent[i] && elementsContent[i] instanceof CSelectedContent){
				contentCount++;
			}
		}
		oThis.oPresentationWriter.WriteString2("SelectedContent");
        oThis.oPresentationWriter.WriteULong((elementsContent.PresentationWidth * 100000) >> 0);
        oThis.oPresentationWriter.WriteULong((elementsContent.PresentationHeight * 100000) >> 0);
		oThis.oPresentationWriter.WriteULong(contentCount);

		//DocContent
		if (elementsContent.DocContent) {//пишем контент
			copyDocContent();
		}
		//Drawings
		if (elementsContent.Drawings && elementsContent.Drawings.length) {
			copyDrawings();
		}
		//SlideObjects
		if (elementsContent.SlideObjects && elementsContent.SlideObjects.length) {
			copySlideObjects();
		}
		//Layouts
		if (elementsContent.Layouts && elementsContent.Layouts.length) {
			copyLayouts();
		}
		//LayoutsIndexes
		if (elementsContent.LayoutsIndexes && elementsContent.LayoutsIndexes.length) {
			oThis.oPresentationWriter.WriteString2("LayoutsIndexes");
			copyIndexes(elementsContent.LayoutsIndexes);
		}
		//Masters
		if (elementsContent.Masters && elementsContent.Masters.length) {
			copyMasters();
		}
		//MastersIndexes
		if (elementsContent.MastersIndexes && elementsContent.MastersIndexes.length) {
			oThis.oPresentationWriter.WriteString2("MastersIndexes");
			copyIndexes(elementsContent.MastersIndexes);
		}
		//Notes
		if (elementsContent.Notes && elementsContent.Notes.length) {
			//TODO если нет Notes, то Notes должен быть равен null. вместо этого приходится проверять 1 элемент массива
			if(!(elementsContent.Notes.length === 1 && null === elementsContent.Notes[0])){
				copyNotes();
			}
		}
		//NotesMasters
		if (elementsContent.NotesMasters && elementsContent.NotesMasters.length) {
			copyNoteMasters();
		}
		//NotesMastersIndexes
		if (elementsContent.NotesMastersIndexes && elementsContent.NotesMastersIndexes.length) {
			oThis.oPresentationWriter.WriteString2("NotesMastersIndexes");
			copyIndexes(elementsContent.NotesMastersIndexes);
		}
		//NotesThemes
		if (elementsContent.NotesThemes && elementsContent.NotesThemes.length) {
			copyNoteTheme();
		}
		//Themes
		if (elementsContent.Themes && elementsContent.Themes.length) {
			copyTheme();
		}
		//ThemesIndexes
		if (elementsContent.ThemesIndexes && elementsContent.ThemesIndexes.length) {
			oThis.oPresentationWriter.WriteString2("ThemeIndexes");
			copyIndexes(elementsContent.ThemesIndexes);
		}
	},

	getSelectedBinary : function()
	{
		var oDocument = this.oDocument;
		
		if(PasteElementsId.g_bIsDocumentCopyPaste)
		{
			var selectedContent = oDocument.GetSelectedContent();
				
			var elementsContent;
			if(selectedContent && selectedContent.Elements && selectedContent.Elements[0] && selectedContent.Elements[0].Element)
				elementsContent = selectedContent.Elements;
			else 
				return false;
				
			var drawingUrls = [];
			if(selectedContent.DrawingObjects && selectedContent.DrawingObjects.length)
			{
				var url, correctUrl, graphicObj;
				for(var i = 0; i < selectedContent.DrawingObjects.length; i++)
				{
					graphicObj = selectedContent.DrawingObjects[i].GraphicObj;
					if(graphicObj.isImage())
					{
						url = graphicObj.getImageUrl();
						if(window["NativeCorrectImageUrlOnCopy"])
						{
							correctUrl = window["NativeCorrectImageUrlOnCopy"](url);
							
							drawingUrls[i] = correctUrl;
						}
					}	
				}
			}
			
			//подменяем Document для копирования(если не подменить, то commentId будет не соответствовать)
			this.oBinaryFileWriter.Document = elementsContent[0].Element.LogicDocument;
			
			this.oBinaryFileWriter.CopyStart();
			this.CopyDocument2(null, oDocument, elementsContent);
			this.oBinaryFileWriter.CopyEnd();
			
			var sBase64 = this.oBinaryFileWriter.GetResult();
			var text = "";
            if (oDocument.GetSelectedText)
                text = oDocument.GetSelectedText();
			
			return {sBase64: "docData;" + sBase64, text: text, drawingUrls: drawingUrls};
		}
	},
	
    Start : function()
    {
		var oDocument = this.oDocument;
		var bFromPresentation;

		window['AscCommon'].g_specialPasteHelper.SpecialPasteButton_Hide();

		if(PasteElementsId.g_bIsDocumentCopyPaste)
		{
			var selectedContent = oDocument.GetSelectedContent();
			
			var elementsContent;
			if(selectedContent && selectedContent.Elements && selectedContent.Elements[0] && selectedContent.Elements[0].Element)
				elementsContent = selectedContent.Elements;
			else 
				return "";
				
			//TODO заглушка для презентационных параграфов(выделен текст внутри диаграммы) - пока не пишем в бинарник
			if(selectedContent.Elements[0].Element && selectedContent.Elements[0].Element.bFromDocument === false)
			{
				this.oBinaryFileWriter.Document = this.oDocument;
			}
			else
			{
				//подменяем Document для копирования(если не подменить, то commentId будет не соответствовать)
				this.oBinaryFileWriter.Document = elementsContent[0].Element.LogicDocument;
			}
				
			this.oBinaryFileWriter.CopyStart();	
			this.CopyDocument2(this.oRoot, oDocument, elementsContent, bFromPresentation);
			this.oBinaryFileWriter.CopyEnd();
		}
        else
        {
			var selectedContent = oDocument.GetSelectedContent2();
			if(!selectedContent[0].DocContent && (!selectedContent[0].Drawings || (selectedContent[0].Drawings && !selectedContent[0].Drawings.length)) && (!selectedContent[0].SlideObjects || (selectedContent[0].SlideObjects && !selectedContent[0].SlideObjects.length)))
				return false;

			this.CopyDocument2(this.oRoot, oDocument, selectedContent);

            var sBase64 = this.oPresentationWriter.GetBase64Memory();
            sBase64 = "pptData;" + this.oPresentationWriter.pos + ";" + sBase64;
			if(this.oRoot.aChildren && this.oRoot.aChildren.length === 1 && AscBrowser.isSafariMacOs)
			{
				var oElem = this.oRoot.aChildren[0];
				var sStyle = oElem.oAttributes["style"];
				if(null == sStyle)
					oElem.oAttributes["style"] = "font-weight:normal";
				else
					oElem.oAttributes["style"] = sStyle + ";font-weight:normal";//просто добавляем потому что в sStyle не могло быть font-weight, мы всегда пишем <b>
				this.oRoot.wrapChild(new CopyElement("b"));
			}
			if(this.oRoot.aChildren && this.oRoot.aChildren.length  > 0)
				this.oRoot.aChildren[0].oAttributes["class"] = sBase64;
        }
		
		if(PasteElementsId.g_bIsDocumentCopyPaste && PasteElementsId.copyPasteUseBinary && this.oBinaryFileWriter.copyParams.itemCount > 0 && !bFromPresentation)
		{
			var sBase64 = "docData;" + this.oBinaryFileWriter.GetResult();
			if(this.oRoot.aChildren && this.oRoot.aChildren.length == 1 && AscBrowser.isSafariMacOs)
			{
				var oElem = this.oRoot.aChildren[0];
				var sStyle = oElem.oAttributes["style"];
				if(null == sStyle)
					oElem.oAttributes["style"] = "font-weight:normal";
				else
					oElem.oAttributes["style"] = sStyle + ";font-weight:normal";//просто добавляем потому что в sStyle не могло быть font-weight, мы всегда пишем <b>
				this.oRoot.wrapChild(new CopyElement("b"));
			}
			if(this.oRoot.aChildren && this.oRoot.aChildren.length  > 0)
				this.oRoot.aChildren[0].oAttributes["class"] = sBase64;
		}
		
		return sBase64;
    },


    CopySlide: function(oDomTarget, slide)
    {
		if(oDomTarget)
		{
			var sSrc = slide.getBase64Img();
			var _bounds_cheker = new AscFormat.CSlideBoundsChecker();
			slide.draw(_bounds_cheker, 0);
			var oImg = new CopyElement("img");
			oImg.oAttributes["width"] = Math.round((_bounds_cheker.Bounds.max_x - _bounds_cheker.Bounds.min_x + 1) * g_dKoef_mm_to_pix);
			oImg.oAttributes["height"] = Math.round((_bounds_cheker.Bounds.max_y - _bounds_cheker.Bounds.min_y + 1) * g_dKoef_mm_to_pix);
			oImg.oAttributes["src"] = sSrc;
			oDomTarget.addChild(oImg);
		}

		//записываем slide
		this.oPresentationWriter.WriteSlide(slide);

    },

    CopyLayout: function(layout)
    {
        this.oPresentationWriter.WriteSlideLayout(layout);
    },


    CopyPresentationTableCells: function(oDomTarget, graphicFrame)
    {
        var aSelectedRows = [];
        var oRowElems = {};
        var Item = graphicFrame.graphicObject;
        if(Item.Selection.Data.length > 0)
        {
            for(var i = 0, length = Item.Selection.Data.length; i < length; ++i)
            {
                var elem = Item.Selection.Data[i];
                var rowElem = oRowElems[elem.Row];
                if(null == rowElem)
                {
                    rowElem = {row: elem.Row, gridStart: null, gridEnd: null, indexStart: null, indexEnd: null, after: null, before: null, cells: {}};
                    oRowElems[elem.Row] = rowElem;
                    aSelectedRows.push(rowElem);
                }
                if(null == rowElem.indexEnd || elem.Cell > rowElem.indexEnd)
                    rowElem.indexEnd = elem.Cell;
                if(null == rowElem.indexStart || elem.Cell < rowElem.indexStart)
                    rowElem.indexStart = elem.Cell;
                rowElem.cells[elem.Cell] = 1;
            }
        }
        aSelectedRows.sort(function(a,b){
            return a.row - b.row;
        });
        var nMinGrid = null;
        var nMaxGrid = null;
        var nPrevStartGrid = null;
        var nPrevEndGrid = null;
        var nPrevRowIndex = null;
        for(var i = 0, length = aSelectedRows.length; i < length; ++i)
        {
            var elem = aSelectedRows[i];
            var nRowIndex = elem.row;
            if(null != nPrevRowIndex)
            {
                if(nPrevRowIndex + 1 !== nRowIndex)
                {
                    nMinGrid = null;
                    nMaxGrid = null;
                    break;
                }
            }
            nPrevRowIndex = nRowIndex;
            var row = Item.Content[nRowIndex];
            var cellFirst = row.Get_Cell(elem.indexStart);
            var cellLast = row.Get_Cell(elem.indexEnd);
            var nCurStartGrid = cellFirst.Metrics.StartGridCol;
            var nCurEndGrid = cellLast.Metrics.StartGridCol + cellLast.Get_GridSpan() - 1;
            if(null != nPrevStartGrid && null != nPrevEndGrid)
            {
                //учитываем вертикальный merge, раздвигаем границы
                if(nCurStartGrid > nPrevStartGrid)
                {
                    for(var j = elem.indexStart - 1; j >= 0; --j)
                    {
                        var cellCur = row.Get_Cell(j);
                        if(vmerge_Continue === cellCur.GetVMerge())
                        {
                            var nCurGridCol = cellCur.Metrics.StartGridCol;
                            if(nCurGridCol >= nPrevStartGrid)
                            {
                                nCurStartGrid = nCurGridCol;
                                elem.indexStart = j;
                            }
                            else
                                break;
                        }
                        else
                            break;
                    }
                }
                if(nCurEndGrid < nPrevEndGrid)
                {
                    for(var j = elem.indexEnd + 1; j < row.Get_CellsCount(); ++j)
                    {
                        var cellCur = row.Get_Cell(j);
                        if(vmerge_Continue === cellCur.GetVMerge())
                        {
                            var nCurGridCol = cellCur.Metrics.StartGridCol + cellCur.Get_GridSpan() - 1;
                            if(nCurGridCol <= nPrevEndGrid)
                            {
                                nCurEndGrid = nCurGridCol;
                                elem.indexEnd = j;
                            }
                            else
                                break;
                        }
                        else
                            break;
                    }
                }
            }
            elem.gridStart = nPrevStartGrid = nCurStartGrid;
            elem.gridEnd = nPrevEndGrid = nCurEndGrid;
            if(null == nMinGrid || nMinGrid > nCurStartGrid)
                nMinGrid = nCurStartGrid;
            if(null == nMaxGrid || nMaxGrid < nCurEndGrid)
                nMaxGrid = nCurEndGrid;
        }
        if(null != nMinGrid && null != nMaxGrid)
        {
            //выставляем after, before
            for(var i = 0 ,length = aSelectedRows.length; i < length; ++i)
            {
                var elem = aSelectedRows[i];
                elem.before = elem.gridStart - nMinGrid;
                elem.after = nMaxGrid - elem.gridEnd;
            }
            this.CopyTable(oDomTarget, Item, aSelectedRows);
        }
		History.TurnOff();
        var graphic_frame = new CGraphicFrame(graphicFrame.parent);
        var grid = [];

        for(var i = nMinGrid; i <= nMaxGrid; ++i)
        {
            grid.push(graphicFrame.graphicObject.TableGrid[i]);
        }
        var table = new CTable(editor.WordControl.m_oDrawingDocument, graphicFrame, false, aSelectedRows.length, nMaxGrid - nMinGrid+1, grid);
        table.setStyleIndex(graphicFrame.graphicObject.styleIndex);
        graphic_frame.setGraphicObject(table);
        graphic_frame.setXfrm(0, 0, 20, 30, 0, false, false);
        var  b_style_index = false;
        if(AscFormat.isRealNumber(graphic_frame.graphicObject.styleIndex) && graphic_frame.graphicObject.styleIndex > -1)
        {
            b_style_index = true;
        }

        this.oPresentationWriter.WriteULong(1);
        this.oPresentationWriter.WriteBool(false);
        this.oPresentationWriter.WriteBool(b_style_index);
        if(b_style_index)
        {
            this.oPresentationWriter.WriteULong(graphic_frame.graphicObject.styleIndex);
        }
        var old_style_index = graphic_frame.graphicObject.styleIndex;
        graphic_frame.graphicObject.styleIndex = -1;
        this.oPresentationWriter.WriteTable(graphic_frame);
        graphic_frame.graphicObject.styleIndex = old_style_index;

		History.TurnOn();

        this.oBinaryFileWriter.copyParams.itemCount = 0;
    },

    CopyPresentationTableFull: function(oDomTarget, graphicFrame, isOnlyTable)
    {
        var aSelectedRows = [];
        var oRowElems = {};
        var Item = graphicFrame.graphicObject;
		
        var b_style_index = false;
        if(Item.TableStyle)
        {
            b_style_index = true;
        }
		
		var presentation = editor.WordControl.m_oLogicDocument;
		for(var key in presentation.TableStylesIdMap)
        {
            if(presentation.TableStylesIdMap.hasOwnProperty(key))
            {
                this.oPresentationWriter.tableStylesGuides[key] = "{" + AscCommon.GUID() + "}"
            }
        }

		
        this.oPresentationWriter.WriteBool(!b_style_index);
        if(b_style_index)
        {
            var tableStyle = presentation.globalTableStyles.Style[Item.TableStyle];
			this.oPresentationWriter.WriteBool(true);
			this.oPresentationWriter.WriteTableStyle(Item.TableStyle, tableStyle);
			this.oPresentationWriter.WriteBool(true);
			this.oPresentationWriter.WriteString2(Item.TableStyle);
        }
		
		History.TurnOff();
        this.oPresentationWriter.WriteTable(graphicFrame);
		
		//для случая, когда копируем 1 таблицу из презентаций, в бинарник заносим ещё одну такую же табличку, но со скомпиоированными стилями(для вставки в word / excel)
		if(isOnlyTable)
		{
			this.convertToCompileStylesTable(Item);
			this.oPresentationWriter.WriteTable(graphicFrame);
		}
		History.TurnOn();

		if(oDomTarget)
		{
			this.CopyTable(oDomTarget, Item, null);
		}
    },

	convertToCompileStylesTable: function(table)
	{
		var t = this;
		
		for(var i = 0; i < table.Content.length; i++)
		{
			var row = table.Content[i];
			for(var j = 0; j < row.Content.length; j++)
			{
				var cell = row.Content[j];
				var compilePr = cell.Get_CompiledPr();
				
				cell.Pr = compilePr;
				
				var shd = compilePr.Shd;
				var color = shd.Get_Color2(this.oDocument.Get_Theme(), this.oDocument.Get_ColorMap());
				cell.Pr.Shd.Unifill = AscFormat.CreteSolidFillRGB(color.r, color.g, color.b);
				
				if(compilePr.TableCellBorders.Bottom)
				{
					color = compilePr.TableCellBorders.Bottom.Get_Color2(this.oDocument.Get_Theme(), this.oDocument.Get_ColorMap());
					cell.Pr.TableCellBorders.Bottom.Unifill = AscFormat.CreteSolidFillRGB(color.r, color.g, color.b);
				}
				
				if(compilePr.TableCellBorders.Top)
				{
					color = compilePr.TableCellBorders.Top.Get_Color2(this.oDocument.Get_Theme(), this.oDocument.Get_ColorMap());
					cell.Pr.TableCellBorders.Top.Unifill = AscFormat.CreteSolidFillRGB(color.r, color.g, color.b);
				}
				
				if(compilePr.TableCellBorders.Left)
				{
					color = compilePr.TableCellBorders.Left.Get_Color2(this.oDocument.Get_Theme(), this.oDocument.Get_ColorMap());
					cell.Pr.TableCellBorders.Left.Unifill = AscFormat.CreteSolidFillRGB(color.r, color.g, color.b);
				}
				
				if(compilePr.TableCellBorders.Right)
				{
					color = compilePr.TableCellBorders.Right.Get_Color2(this.oDocument.Get_Theme(), this.oDocument.Get_ColorMap());
					cell.Pr.TableCellBorders.Right.Unifill = AscFormat.CreteSolidFillRGB(color.r, color.g, color.b);
				}
			}
		}
	},
	
    CopyGraphicObject: function(oDomTarget, oGraphicObj, drawingCopyObject)
    {
        var sSrc = drawingCopyObject.ImageUrl;
        if(oDomTarget && sSrc.length > 0)
        {
            var _bounds_cheker = new AscFormat.CSlideBoundsChecker();
            oGraphicObj.draw(_bounds_cheker, 0);

            var width, height;
            if(drawingCopyObject && drawingCopyObject.ExtX)
                width = Math.round(drawingCopyObject.ExtX * g_dKoef_mm_to_pix);
            else
                width = Math.round((_bounds_cheker.Bounds.max_x - _bounds_cheker.Bounds.min_x + 1) * g_dKoef_mm_to_pix);

            if(drawingCopyObject && drawingCopyObject.ExtY)
                height = Math.round(drawingCopyObject.ExtY * g_dKoef_mm_to_pix);
            else
                height = Math.round((_bounds_cheker.Bounds.max_y - _bounds_cheker.Bounds.min_y + 1) * g_dKoef_mm_to_pix);

            var oImg = new CopyElement("img");
            oImg.oAttributes["width"] = width;
            oImg.oAttributes["height"] = height;
            oImg.oAttributes["src"] = sSrc;
            if (this.api.DocumentReaderMode)
                oImg.oAttributes["style"] = "max-width:100%;";
            oDomTarget.addChild(oImg);
        }


        if(oGraphicObj instanceof CShape)
        {
            this.oPresentationWriter.WriteShape(oGraphicObj);
        }
        else if(oGraphicObj instanceof AscFormat.CImageShape)
        {
            this.oPresentationWriter.WriteImage(oGraphicObj);
        }
        else if(oGraphicObj instanceof AscFormat.CGroupShape)
        {
            this.oPresentationWriter.WriteGroupShape(oGraphicObj);
        }
        else if(oGraphicObj instanceof AscFormat.CChartSpace)
        {
            this.oPresentationWriter.WriteChart(oGraphicObj);
        }
        else if(oGraphicObj instanceof CGraphicFrame)
        {
            this.oPresentationWriter.WriteTable(oGraphicObj);
        }
    }
};

function CopyPasteCorrectString(str)
{
    /*
    // эта реализация на порядок быстрее. Перед выпуском не меняю ничего
    var _ret = "";
    var _len = str.length;

    for (var i = 0; i < _len; i++)
    {
        var _symbol = str[i];
        if (_symbol == "&")
            _ret += "&amp;";
        else if (_symbol == "<")
            _ret += "&lt;";
        else if (_symbol == ">")
            _ret += "&gt;";
        else if (_symbol == "'")
            _ret += "&apos;";
        else if (_symbol == "\"")
            _ret += "&quot;";
        else
            _ret += _symbol;
    }

    return _ret;
    */

    var res = str;
    res = res.replace(/&/g,'&amp;');
    res = res.replace(/</g,'&lt;');
    res = res.replace(/>/g,'&gt;');
    res = res.replace(/'/g,'&apos;');
    res = res.replace(/"/g,'&quot;');
    return res;
}

function Editor_Paste_Exec(api, _format, data1, data2, text_data, specialPasteProps)
{
    var oPasteProcessor = new PasteProcessor(api, true, true, false);
	window['AscCommon'].g_specialPasteHelper.endRecalcDocument = false;

	if(undefined === specialPasteProps)
	{
		window['AscCommon'].g_specialPasteHelper.SpecialPasteButton_Hide();
		window['AscCommon'].g_specialPasteHelper.specialPasteData._format = _format;
		window['AscCommon'].g_specialPasteHelper.specialPasteData.data1 = data1;
		window['AscCommon'].g_specialPasteHelper.specialPasteData.data2 = data2;
		window['AscCommon'].g_specialPasteHelper.specialPasteData.text_data = text_data;
	}
	else
	{
		window['AscCommon'].g_specialPasteHelper.specialPasteProps = specialPasteProps;

		_format = window['AscCommon'].g_specialPasteHelper.specialPasteData._format;
		data1 = window['AscCommon'].g_specialPasteHelper.specialPasteData.data1;
		data2 = window['AscCommon'].g_specialPasteHelper.specialPasteData.data2;
		text_data = window['AscCommon'].g_specialPasteHelper.specialPasteData.text_data;

		if(specialPasteProps === Asc.c_oSpecialPasteProps.keepTextOnly && _format !== AscCommon.c_oAscClipboardDataFormat.Text && text_data)
		{
			_format = AscCommon.c_oAscClipboardDataFormat.Text;
			data1 = text_data;
		}
	}

	switch (_format)
	{
		case AscCommon.c_oAscClipboardDataFormat.HtmlElement:
		{
			oPasteProcessor.Start(data1, data2);
			break;
		}
		case AscCommon.c_oAscClipboardDataFormat.Internal:
		{
			oPasteProcessor.Start(null, null, null, data1);
			break;
		}
		case AscCommon.c_oAscClipboardDataFormat.Text:
		{
			oPasteProcessor.Start(null, null, null, null, data1);
			break;
		}
	}
}
function trimString( str ){
    return str.replace(/^\s+|\s+$/g, '') ;
}
function sendImgUrls(api, images, callback, bExcel, bNotShowError) {

  if (window["AscDesktopEditor"])
  {
    // correct local images
    for (var nIndex = images.length - 1; nIndex >= 0; nIndex--)
    {
      if (0 == images[nIndex].indexOf("file:/"))
        images[nIndex] = window["AscDesktopEditor"]["GetImageBase64"](images[nIndex]);
    }
  }

  if (AscCommon.EncryptionWorker && AscCommon.EncryptionWorker.isCryptoImages())
  {
      return AscCommon.EncryptionWorker.addCryproImagesFromUrls(images, callback);
  }

  var rData = {"id": api.documentId, "c": "imgurls", "userid":  api.documentUserId, "saveindex": g_oDocumentUrls.getMaxIndex(), "data": images};
  api.sync_StartAction(Asc.c_oAscAsyncActionType.BlockInteraction, Asc.c_oAscAsyncAction.LoadImage);

  api.fCurCallback = function (input) {
    api.sync_EndAction(Asc.c_oAscAsyncActionType.BlockInteraction, Asc.c_oAscAsyncAction.LoadImage);
    var nError = c_oAscError.ID.No;
    var data;
    if (null != input && "imgurls" == input["type"]) {
      if ("ok" == input["status"]) {
        data = input["data"]["urls"];
        nError = AscCommon.mapAscServerErrorToAscError(input["data"]["error"]);
        var urls = {};
        for (var i = 0, length = data.length; i < length; ++i) {
          var elem = data[i];
          if (null != elem.url) {
            urls[elem.path] = elem.url;
          }
        }
        g_oDocumentUrls.addUrls(urls);
      } else {
        nError = AscCommon.mapAscServerErrorToAscError(parseInt(input["data"]));
      }
    } else {
      nError = c_oAscError.ID.Unknown;
    }
    if ( c_oAscError.ID.No !== nError && !bNotShowError) {
      if(!bExcel)
        api.sendEvent("asc_onError", nError, c_oAscError.Level.NoCritical);
      else
        api.handlers.trigger("asc_onError", nError, c_oAscError.Level.NoCritical);
    }
    if (!data) {
      //todo сделать функцию очистки, чтобы можно было оборвать paste и показать error
      data = [];
      for ( var i = 0; i < images.length; ++i) {
        data.push({'url': 'error', 'path': 'error'});
      }
    }
    callback(data);
  };
  AscCommon.sendCommand(api, null, rData);
}
function PasteProcessor(api, bUploadImage, bUploadFonts, bNested, pasteInExcel)
{
    this.oRootNode = null;
    this.api = api;
    this.bIsDoublePx  = api.WordControl.bIsDoublePx;
    this.oDocument = api.WordControl.m_oLogicDocument;
    this.oLogicDocument = this.oDocument;
    this.oRecalcDocument = this.oDocument;
    this.map_font_index = api.FontLoader.map_font_index;
    this.bUploadImage = bUploadImage;
    this.bUploadFonts = bUploadFonts;
    this.bNested = bNested;//для параграфов в таблицах
    this.oFonts = {};
    this.oImages = {};
	this.aContent = [];
	
	this.pasteInExcel = pasteInExcel;
	this.pasteInPresentationShape = null;
	
	this.maxTableCell = null;

	//для вставки текста в ячейку, при копировании из word в chrome появляются лишние пробелы вне <p>
    this.bIgnoreNoBlockText = false;

    this.oCurRun = null;
    this.oCurRunContentPos = 0;
    this.oCurPar = null;
    this.oCurParContentPos = 0;
    this.oCurHyperlink = null;
    this.oCurHyperlinkContentPos = 0;
    this.oCur_rPr = new CTextPr();

	//Br копятся потомы что есть случаи когда не надо вывобить br, хотя он и присутствует.
    this.nBrCount = 0;
	//bInBlock указывает блочный ли элемент(рассматриваются только элементы дочерние от child)
	//Если после окончания вставки true != this.bInBlock значит последний элемент не параграф и не надо добавлять новый параграф
    this.bInBlock = null;

	//ширина элемента в который вставляем страница или ячейка
    this.dMaxWidth = Page_Width - X_Left_Margin - X_Right_Margin;
	//коэфициент сжатия(например при вставке таблица сжалась, значит при вставке содержимого ячейки к картинкам и таблице будет применен этот коэффициент)
    this.dScaleKoef = 1;
    this.bUseScaleKoef = false;
	this.bIsPlainText = false;
	
	this.defaultImgWidth = 50;
	this.defaultImgHeight = 50;

    this.MsoStyles = {"mso-style-type": 1, "mso-pagination": 1, "mso-line-height-rule": 1, "mso-style-textfill-fill-color": 1, "mso-tab-count": 1,
        "tab-stops": 1, "list-style-type": 1, "mso-special-character": 1, "mso-column-break-before": 1, "mso-break-type": 1, "mso-padding-alt": 1, "mso-border-insidev": 1,
        "mso-border-insideh": 1, "mso-row-margin-left": 1, "mso-row-margin-right": 1, "mso-cellspacing": 1, "mso-border-alt": 1,
        "mso-border-left-alt": 1, "mso-border-top-alt": 1, "mso-border-right-alt": 1, "mso-border-bottom-alt": 1, "mso-border-between": 1, "mso-list": 1};
    this.oBorderCache = {};
	
	this.msoListMap = [];

	//пока ввожу эти параметры для специальной вставки. возможно, нужно будет пересмотреть и убрать их
	this.pasteTypeContent = undefined;
	this.pasteList = undefined;
	this.pasteIntoElem = undefined;//ссылка на элемент контента, который был выделен до вставки

	this.apiEditor = window["Asc"]["editor"] ? window["Asc"]["editor"] : window["editor"];

	this.msoComments = [];
}
PasteProcessor.prototype =
{
    _GetTargetDocument : function(oDocument)
    {
        if(PasteElementsId.g_bIsDocumentCopyPaste)
        {
			var nDocPosType = oDocument.Get_DocPosType();
			if (docpostype_HdrFtr === nDocPosType)
			{
				if (null != oDocument.HdrFtr && null != oDocument.HdrFtr.CurHdrFtr && null != oDocument.HdrFtr.CurHdrFtr.Content)
				{
					oDocument  = oDocument.HdrFtr.CurHdrFtr.Content;
					this.oRecalcDocument = oDocument;
				}
			}
			else if (nDocPosType === docpostype_DrawingObjects)
			{
				var content = oDocument.DrawingObjects.getTargetDocContent(true);
				if (content)
				{
					oDocument = content;
				}
			}
			else if (nDocPosType === docpostype_Footnotes)
			{
				if (oDocument.Footnotes && oDocument.Footnotes.CurFootnote)
					oDocument = oDocument.Footnotes.CurFootnote
			}

			// Отдельно обрабатываем случай, когда курсор находится внутри таблицы
			var Item = oDocument.Content[oDocument.CurPos.ContentPos];
			if (type_Table === Item.GetType() && null != Item.CurCell)
			{
				this.dMaxWidth = this._CalcMaxWidthByCell(Item.CurCell);
				oDocument = this._GetTargetDocument(Item.CurCell.Content);
			}
        }
        else
        {

        }
        return oDocument;
    },
    _CalcMaxWidthByCell : function(cell)
    {
        var row = cell.Row;
        var table = row.Table;
        var grid = table.TableGrid;
        var nGridBefore = 0;
        if(null != row.Pr && null != row.Pr.GridBefore)
            nGridBefore = row.Pr.GridBefore;
        var nCellIndex = cell.Index;
        var nCellGrid = 1;
        if(null != cell.Pr && null != cell.Pr.GridSpan)
            nCellGrid = cell.Pr.GridSpan;
        var nMarginLeft = 0;
        if(null != cell.Pr && null != cell.Pr.TableCellMar && null != cell.Pr.TableCellMar.Left && tblwidth_Mm === cell.Pr.TableCellMar.Left.Type && null != cell.Pr.TableCellMar.Left.W)
            nMarginLeft = cell.Pr.TableCellMar.Left.W;
        else if(null != table.Pr && null != table.Pr.TableCellMar && null != table.Pr.TableCellMar.Left && tblwidth_Mm === table.Pr.TableCellMar.Left.Type && null != table.Pr.TableCellMar.Left.W)
            nMarginLeft = table.Pr.TableCellMar.Left.W;
        var nMarginRight = 0;
        if(null != cell.Pr && null != cell.Pr.TableCellMar && null != cell.Pr.TableCellMar.Right && tblwidth_Mm === cell.Pr.TableCellMar.Right.Type && null != cell.Pr.TableCellMar.Right.W)
            nMarginRight = cell.Pr.TableCellMar.Right.W;
        else if(null != table.Pr && null != table.Pr.TableCellMar && null != table.Pr.TableCellMar.Right && tblwidth_Mm === table.Pr.TableCellMar.Right.Type && null != table.Pr.TableCellMar.Right.W)
            nMarginRight = table.Pr.TableCellMar.Right.W;
        var nPrevSumGrid = nGridBefore;
        for(var i = 0; i < nCellIndex; ++i)
        {
            var oTmpCell = row.Content[i];
            var nGridSpan = 1;
            if(null != cell.Pr && null != cell.Pr.GridSpan)
                nGridSpan = cell.Pr.GridSpan;
            nPrevSumGrid += nGridSpan;
        }
        var dCellWidth = 0;
        for(var i = nPrevSumGrid, length = grid.length; i < nPrevSumGrid + nCellGrid && i < length; ++i)
            dCellWidth += grid[i];

        if(dCellWidth - nMarginLeft - nMarginRight <= 0)
            dCellWidth = 4;
        else
            dCellWidth -= nMarginLeft + nMarginRight;
        return dCellWidth;
    },
    InsertInDocument : function()
    {
        var oDocument = this.oDocument;

		//TODO ориентируюсь при специальной вставке на SelectionState. возможно стоит пересмотреть.
		this.curDocSelection = this.oDocument.GetSelectionState();
		if(this.curDocSelection && this.curDocSelection[1] && this.curDocSelection[1].CurPos)
		{
			this.pasteIntoElem = this.oDocument.Content[this.curDocSelection[1].CurPos.ContentPos];
		}

        var nInsertLength = this.aContent.length;
        if(nInsertLength > 0)
        {
			this.InsertInPlace(oDocument, this.aContent);
			
            if(false === PasteElementsId.g_bIsDocumentCopyPaste)
            {
                oDocument.Recalculate();
                if(oDocument.Parent != null && oDocument.Parent.txBody != null)
                {
                    oDocument.Parent.txBody.recalculate();
                }
            }
        }

        if(false === this.bNested && nInsertLength > 0)
        {
            var bNeedMoveCursor = History.Is_LastPointNeedRecalc();
            this.oRecalcDocument.Recalculate();
            
            if ((oDocument.Get_DocPosType() !== docpostype_DrawingObjects || true === this.oLogicDocument.DrawingObjects.isSelectedText()) && true === bNeedMoveCursor)
            {
                this.oLogicDocument.MoveCursorRight(false, false, true);
            }
            
            this.oLogicDocument.Document_UpdateInterfaceState();
            this.oLogicDocument.Document_UpdateSelectionState();
        }
		
		//for special paste
		this._specialPasteSetShowOptions();
		
		window['AscCommon'].g_specialPasteHelper.Paste_Process_End();
    },
    InsertInPlace : function(oDoc, aNewContent)
    {
        if(!PasteElementsId.g_bIsDocumentCopyPaste)
            return;

		var specialPasteHelper = window['AscCommon'].g_specialPasteHelper;
		var bIsSpecialPaste = specialPasteHelper.specialPasteStart;

        var paragraph = oDoc.GetCurrentParagraph();
        if (null != paragraph) {
            var NearPos = { Paragraph: paragraph, ContentPos: paragraph.Get_ParaContentPos(false, false) };
            paragraph.Check_NearestPos(NearPos);
            //делаем небольшой сдвиг по y, потому что сама точка TargetPos для двухстрочного параграфа определяется как верхняя
            //var NearPos = oDoc.Get_NearestPos(this.oLogicDocument.TargetPos.PageNum, this.oLogicDocument.TargetPos.X, this.oLogicDocument.TargetPos.Y + 0.05);//0.05 == 2pix

			//pasteTypeContent - если все содержимое одного типа
			//TODO пересмотреть pasteTypeContent
			this.pasteTypeContent = null;
			var oSelectedContent = new CSelectedContent();
			var tableSpecialPaste = false;
			if(bIsSpecialPaste){
				if (Asc.c_oSpecialPasteProps.insertAsNestedTable === specialPasteHelper.specialPasteProps ||
					Asc.c_oSpecialPasteProps.overwriteCells === specialPasteHelper.specialPasteProps)
				{
					tableSpecialPaste = true;
					oSelectedContent.SetInsertOptionForTable(specialPasteHelper.specialPasteProps);
				}
			}
            for (var i = 0; i < aNewContent.length; ++i) {
				if(bIsSpecialPaste && !tableSpecialPaste)
				{
					var parseItem = this._specialPasteItemConvert(aNewContent[i]);
					if(parseItem && parseItem.length)
					{
						for(var j = 0; j < parseItem.length; j++)
						{
							if(j === 0)
							{
								aNewContent.splice(i + j, 1, parseItem[j]);
							}
							else
							{
								aNewContent.splice(i + j, 0, parseItem[j]);
							}
						}
					}
				}

				var oSelectedElement = new CSelectedElement();
				oSelectedElement.Element = aNewContent[i];

				var type = this._specialPasteGetElemType(aNewContent[i]);
				if(0 === i)
				{
					this.pasteTypeContent = type;
				}
				else if(type !== this.pasteTypeContent)
				{
					this.pasteTypeContent = null;
				}

                if (i === aNewContent.length - 1 && true != this.bInBlock && type_Paragraph === oSelectedElement.Element.GetType())
                    oSelectedElement.SelectedAll = false;
                else
                    oSelectedElement.SelectedAll = true;
                oSelectedContent.Add(oSelectedElement);
            }
			
			//проверка на возможность втавки в формулу
			//TODO проверку на excel пеерсмотреть!!!!
			oSelectedContent.On_EndCollectElements(this.oLogicDocument, true);
			if(!this.pasteInExcel && !this.oLogicDocument.Can_InsertContent(oSelectedContent, NearPos))
            {
                if(!this.pasteInExcel)
                {
                    this.oLogicDocument.Document_Undo();
                    History.Clear_Redo();
                }
                return;
            }

            var bPasteMath = false;
            if(this.pasteInExcel)
            {
                var Para        = NearPos.Paragraph;
                var ParaNearPos = Para.Get_ParaNearestPos(NearPos);
                var LastClass   = ParaNearPos.Classes[ParaNearPos.Classes.length - 1];
                if (para_Math_Run === LastClass.Type)
                {
                    var MathRun        = LastClass;
                    var NewMathRun     = MathRun.Split(ParaNearPos.NearPos.ContentPos, ParaNearPos.Classes.length - 1);
                    var MathContent    = ParaNearPos.Classes[ParaNearPos.Classes.length - 2];
                    var MathContentPos = ParaNearPos.NearPos.ContentPos.Data[ParaNearPos.Classes.length - 2];
                    var Element        = oSelectedContent.Elements[0].Element;

                    var InsertMathContent = null;
                    for (var nPos = 0, nParaLen = Element.Content.length; nPos < nParaLen; nPos++)
                    {
                        if (para_Math === Element.Content[nPos].Type)
                        {
                            InsertMathContent = Element.Content[nPos];
                            break;
                        }
                    }

                    if(null === InsertMathContent)
                    {
                        //try to convert content to ParaMath in simple cases.
                        InsertMathContent = oSelectedContent.ConvertToMath();
                    }

                    if (null !== InsertMathContent)
                    {
                        MathContent.Add_ToContent(MathContentPos + 1, NewMathRun);
                        MathContent.Insert_MathContent(InsertMathContent.Root, MathContentPos + 1, true);
                        bPasteMath = true;
                    }
                }
            }

            if(!bPasteMath)
            {
                paragraph.Parent.Insert_Content(oSelectedContent, NearPos);
            }

			//если вставляем таблицу в ячейку таблицы
			if (this.pasteIntoElem && 1 === this.aContent.length && type_Table === this.aContent[0].GetType() &&
				this.pasteIntoElem.Parent && this.pasteIntoElem.Parent.Is_InTable() && (!bIsSpecialPaste || (bIsSpecialPaste &&
				Asc.c_oSpecialPasteProps.overwriteCells === specialPasteHelper.specialPasteProps))) {
				var table = this.pasteIntoElem.Parent.Parent.Get_Table();
				specialPasteHelper.showButtonIdParagraph = table.Id;
			} else {
				if(oSelectedContent.Elements.length === 1)
				{
					var curDocSelection = this.oDocument.GetSelectionState();
					if(curDocSelection)
					{
						var selectParagraph = this.oDocument.Content[curDocSelection[1].CurPos.ContentPos];
						specialPasteHelper.showButtonIdParagraph = selectParagraph.Id;

						//TODO пересмотреть для случая когда вставляем таблицу внутри BlockLevelSdt
						if(selectParagraph.GetType && type_BlockLevelSdt === selectParagraph.GetType()) {
							var currentParagraph = this.oDocument.GetCurrentParagraph();
							specialPasteHelper.showButtonIdParagraph = currentParagraph ? currentParagraph.Id : null
						}
					}
				}
				else
				{
					specialPasteHelper.showButtonIdParagraph = oSelectedContent.Elements[oSelectedContent.Elements.length - 1].Element.Id;
				}
			}


            if(this.oLogicDocument && this.oLogicDocument.DrawingObjects)
            {
                var oTargetTextObject = AscFormat.getTargetTextObject(this.oLogicDocument.DrawingObjects);
                oTargetTextObject && oTargetTextObject.checkExtentsByDocContent && oTargetTextObject.checkExtentsByDocContent();
            }

			this._selectShapesBeforeInsert(aNewContent, oDoc);
			
            paragraph.Clear_NearestPosArray(aNewContent);
        }
    },

	//***functions for special paste***
	_specialPasteGetElemType: function(elem)
	{
		var type = elem.GetType();

		if(type_Paragraph === type)
		{
			//проверяем, возможно это графический объект
			for(var i = 0; i < elem.Content.length; i++)
			{
				if(elem.Content[i] && elem.Content[i].Content)
				{
					for(var j = 0; j < elem.Content[i].Content.length; j++)
					{
						var contentElem = elem.Content[i].Content[j];
						if(!(contentElem instanceof ParaEnd))
						{
							var typeElem = contentElem.GetType ? contentElem.GetType() : null;
							if(para_Drawing === typeElem)
							{
								type = para_Drawing;
							}
							else
							{
								if(para_Drawing !== type)
								{
									type = type_Paragraph;
								}
								else
								{
									type = null;
								}

								break;
							}
						}
					}
				}

				if(type_Paragraph === type)
				{
					if(elem.Pr && elem.Pr.NumPr)
					{
						if(undefined === this.pasteList)
						{
							this.pasteList = elem.Pr.NumPr;
						}
						else if(this.pasteList && !elem.Pr.NumPr.Is_Equal(this.pasteList))
						{
							this.pasteList = null;
						}
					}
				}
			}
		}

		return type;
	},

	_specialPasteSetShowOptions: function()
	{
		//специальная вставка:
		//выдаем стандартные параметры всавки(paste, merge, value) во всех ситуация, за исключением:
		//если вставляем единственную таблицу в таблицу - особые параметры вставки(как извне, так и внутри)
		//если вставляем список - должны совпадать типы с уже существующими(как извне, так и внутри)
		//изображения / шейпы

		//отдельно диаграммы - для них есть отдельный пункт. посмотреть, нужно ли это добавлять

		//для формул параметры как и при обычной вставке. но нужно уметь их преобразовывать в текст при вставке только текста
		//особые параметры при вставке таблиц из EXCEL


		//если вставляются только изображения, пока не показываем параметры специальной
		if(para_Drawing === this.pasteTypeContent)
		{
			window['AscCommon'].g_specialPasteHelper.SpecialPasteButton_Hide();
			if(window['AscCommon'].g_specialPasteHelper.buttonInfo)
			{
				window['AscCommon'].g_specialPasteHelper.showButtonIdParagraph = null;
				window['AscCommon'].g_specialPasteHelper.CleanButtonInfo();
			}
			return;
		}

		var specialPasteShowOptions = !window['AscCommon'].g_specialPasteHelper.buttonInfo.isClean() ? window['AscCommon'].g_specialPasteHelper.buttonInfo : null;
		if(!window['AscCommon'].g_specialPasteHelper.specialPasteStart)
		{
			specialPasteShowOptions = window['AscCommon'].g_specialPasteHelper.buttonInfo;

			var sProps = Asc.c_oSpecialPasteProps;
			var aContent = this.aContent;

			var props = null;
			//table into table
			//this.pasteTypeContent и this.pasteList нужны для вставки таблиц/списков и тд
			//TODO пока вставка будет работать только с текстом(форматированный/не форматированный)
			/*if(insertToElem && 1 === aContent.length && type_Table === this.aContent[0].GetType() && type_Table === insertToElem.GetType())
			{
				props = [sProps.paste, sProps.insertAsNestedTable, sProps.uniteIntoTable, sProps.insertAsNewRows, sProps.pasteOnlyValues];
			}
			else if(this.pasteList && insertToElem && type_Paragraph === insertToElem.GetType() && insertToElem.Pr && insertToElem.Pr.NumPr && insertToElem.Pr.NumPr.Is_Equal(this.pasteList))
			{
				//вставка нумерованного списка в нумерованный список
				props = [sProps.paste, sProps.uniteList, sProps.doNotUniteList];
			}*/

			//если вставляем одну таблицу в ячейку другой таблицы
			if (this.pasteIntoElem && 1 === aContent.length && type_Table === this.aContent[0].GetType() &&
				this.pasteIntoElem.Parent && this.pasteIntoElem.Parent.Is_InTable())
			{
				props = [sProps.overwriteCells, sProps.insertAsNestedTable, sProps.keepTextOnly];
			}
			else
			{
				props = [sProps.sourceformatting/*, sProps.mergeFormatting*/, sProps.keepTextOnly];
			}

			if(null !== props)
			{
				specialPasteShowOptions.asc_setOptions(props);
			}
			else
			{
				window['AscCommon'].g_specialPasteHelper.showButtonIdParagraph = null;
				window['AscCommon'].g_specialPasteHelper.CleanButtonInfo();
			}
		}

		if(specialPasteShowOptions)
		{
			//SpecialPasteButtonById_Show вызываю здесь, если пересчет документа завершился раньше, чем мы попали сюда и сгенерировали параметры вставки
			//в противном случае вызываю SpecialPasteButtonById_Show в drawingDocument->OnEndRecalculate
			//TODO пересмотреть проверку на CDrawingDocContent и CShape
			if (window['AscCommon'].g_specialPasteHelper.endRecalcDocument || (this.oDocument.Parent &&
				(this.oDocument.Parent instanceof CShape || this.oDocument.Parent instanceof CHeaderFooter)) ||
				(this.oDocument instanceof AscFormat.CDrawingDocContent)) {
				window['AscCommon'].g_specialPasteHelper.SpecialPasteButtonById_Show();
			}
		}
	},

	_specialPasteItemConvert: function(item)
	{
		//TODO рассмотреть вариант вставки текста ("text/plain")
		//для вставки простого текста, можно было бы использовать ("text/plain")
		//но в данном случае вставка текста будет работать не совсем корретно внутри приложения, поскольку
		//когда мы пишем в буфер текст, функция GetSelectedText отдаёт вместо табуляции пробелы
		//так же некорректно будут вставляться таблицы, поскольку табуляции между ячейками мы потеряем
		//внутренние таблицы мы вообще теряем
		//для реализации необходимо менять функцию GetSelectedText
		//посмотреть, какие браузер могут заменить табуляцию на пробел при занесении текста в буфер обмена

		var res = item;
		var type = item.GetType();
		switch(type)
		{
			case type_Paragraph:
			{
				res = this._specialPasteParagraphConvert(item);
				break;
			}
			case type_Table:
			{
				res = this._specialPasteTableConvert(item);
				break;
			}
		}
		return res;
	},

	_specialPasteTableConvert: function(table)
	{
		//TODO временная функция
		var res = table;

		var props = window['AscCommon'].g_specialPasteHelper.specialPasteProps;
		if(props === Asc.c_oSpecialPasteProps.keepTextOnly)
		{
			res = this._convertTableToText(table);
		}
		else
		{
			for(var i = 0; i < table.Content.length; i++)
			{
				for(var j = 0; j < table.Content[i].Content.length; j++)
				{
					var cDocumentContent = table.Content[i].Content[j].Content;
					for(var n = 0; n < cDocumentContent.Content.length; n++)
					{
						if(cDocumentContent.Content[n] instanceof Paragraph)
						{
							this._specialPasteParagraphConvert(cDocumentContent.Content[n]);
						}
						else if(cDocumentContent.Content[n] instanceof CTable)
						{
							this._specialPasteTableConvert(cDocumentContent.Content[n]);
						}
					}
				}
			}
		}

		return res;
	},

	_specialPasteParagraphConvert: function(paragraph)
	{
		var res = paragraph;
		var props = window['AscCommon'].g_specialPasteHelper.specialPasteProps;

		//стиль текущего параграфа/рана, в который вставляем
		var pasteIntoParagraphPr = this.oDocument.GetDirectParaPr();
		var pasteIntoParaRunPr = this.oDocument.GetDirectTextPr();
		
		switch(props)
		{
			case Asc.c_oSpecialPasteProps.paste:
			{
				break;
			}
			case Asc.c_oSpecialPasteProps.keepTextOnly:
			{
				var numbering =  paragraph.GetNumPr();
				if(numbering)
				{
					//проставляем параграфам NumInfo
					var parentContent = paragraph.Parent instanceof CDocument ? this.aContent : paragraph.Parent.Content;
					for(var i = 0; i < parentContent.length; i++)
					{
						var tempParagraph = parentContent[i];
						var numbering2 =  tempParagraph.GetNumPr ? tempParagraph.GetNumPr() : null;

						if(numbering2)
						{
							var NumberingEngine = new CDocumentNumberingInfoEngine(tempParagraph.Id, numbering2, this.oLogicDocument.Get_Numbering());
							var numInfo2 = tempParagraph.Numbering.Internal.NumInfo;

							if(!numInfo2 || (numInfo2 && !numInfo2[numbering.Lvl]))
							{
								for (var nIndex = 0, nCount = parentContent.length; nIndex < nCount; ++nIndex)
								{
									parentContent[nIndex].GetNumberingInfo(NumberingEngine);
								}

								tempParagraph.Numbering.Internal.NumInfo = NumberingEngine.NumInfo;
							}
						}

					}

					this._checkNumberingText(paragraph, paragraph.Numbering.Internal.NumInfo, numbering);
				}


				if(pasteIntoParagraphPr)
				{
					paragraph.Set_Pr(pasteIntoParagraphPr.Copy());

					if(paragraph.TextPr && pasteIntoParaRunPr)
					{
						paragraph.TextPr.Value = pasteIntoParaRunPr.Copy();
					}
				}
				this._specialPasteParagraphContentConvert(paragraph.Content, pasteIntoParaRunPr);
				
				break;
			}
			case Asc.c_oSpecialPasteProps.mergeFormatting:
			{
				//ms почему-то при merge игнорирует заливку текста
				if(pasteIntoParagraphPr)
				{
					paragraph.Pr.Merge(pasteIntoParagraphPr);
					if(paragraph.TextPr)
					{
						paragraph.TextPr.Value.Merge(pasteIntoParaRunPr);
					}
				}
				this._specialPasteParagraphContentConvert(paragraph.Content, pasteIntoParaRunPr);
				
				break;
			}
		}
		
		return res;
	},

	_specialPasteParagraphContentConvert: function(paragraphContent, pasteIntoParaRunPr)
	{
		var props = window['AscCommon'].g_specialPasteHelper.specialPasteProps;

		var checkInsideDrawings = function(runContent)
		{
			for(var j = 0; j < runContent.length; j++)
			{
				var item = runContent[j];

				switch(item.Type)
				{
					case para_Run:
					{
						checkInsideDrawings(item.Content);
						break;
					}
					case para_Drawing:
					{
						runContent.splice(j, 1);
						break;
					}
				}
			}
		};

		switch(props)
		{
			case Asc.c_oSpecialPasteProps.paste:
			{
				break;
			}
			case Asc.c_oSpecialPasteProps.keepTextOnly:
			{
				//в данному случае мы должны применить к вставленному фрагменту стиль paraRun, в который вставляем
				if(pasteIntoParaRunPr)
				{
					for(var i = 0; i < paragraphContent.length; i++)
					{
						var elem = paragraphContent[i];
						var type = elem.Type;
						switch(type)
						{
							case para_Run:
							{
								//проверить, есть ли внутри изображение
								if(pasteIntoParaRunPr && elem.Set_Pr)
								{
									elem.Set_Pr( pasteIntoParaRunPr.Copy() );
								}

								checkInsideDrawings(elem.Content);

								break;
							}
							case para_Hyperlink:
							{
								//изменить hyperlink на pararun
								//проверить, есть ли внутри изображение

								paragraphContent.splice(i, 1);
								for(var n = 0; n < elem.Content.length; n++)
								{
									paragraphContent.splice(i + n, 0, elem.Content[n]);
								}
								i--;

								break;
							}
							case para_Math:
							{
								//преобразуем в текст
								var mathToParaRun = this._convertParaMathToText(elem);
								if(mathToParaRun)
								{
									paragraphContent.splice(i, 1, mathToParaRun);
									i--;
								}

								break;
							}
							case para_Comment:
							{
								//TODO в дальнейшем лучше удалять коммент а не заменять его
								paragraphContent.splice(i, 1, new ParaRun());
								i--;

								break;
							}
						}
					}
				}

				break;
			}
			case Asc.c_oSpecialPasteProps.mergeFormatting:
			{
				//ms почему-то при merge игнорирует заливку текста
				if(pasteIntoParaRunPr)
				{
					for(var i = 0; i < paragraphContent.length; i++)
					{
						var elem = paragraphContent[j];
						if(pasteIntoParaRunPr && elem.Pr)
						{
							elem.Pr.Merge(pasteIntoParaRunPr);
						}
					}
				}

				break;
			}
		}
	},

	_convertParaMathToText: function(paraMath)
	{
		var res = null;
		var oDoc = this.oLogicDocument;

		var mathText = paraMath.Root.GetTextContent();
		if(mathText && mathText.str)
		{
			var newParaRun = new ParaRun();
			addTextIntoRun(newParaRun, mathText.str);

			res = newParaRun;
		}

		return res;
	},

	_convertTableToText: function(table, obj, newParagraph)
	{
		var oDoc = this.oLogicDocument;
		var t = this;
		if(!obj)
		{
			obj = [];
		}

		//row
		for(var i = 0; i < table.Content.length; i++)
		{
			if(!newParagraph)
			{
				newParagraph = new Paragraph(oDoc.DrawingDocument, oDoc);
			}

			//col
			for(var j = 0; j < table.Content[i].Content.length; j++)
			{
				//content
				var cDocumentContent = table.Content[i].Content[j].Content;

				var createNewParagraph = false;
				var previousTableAdd = false;
				for(var n = 0; n < cDocumentContent.Content.length; n++)
				{
					previousTableAdd = false;
					if(createNewParagraph)
					{
						newParagraph = new Paragraph(oDoc.DrawingDocument, oDoc);
						createNewParagraph = false;
					}

					if(cDocumentContent.Content[n] instanceof Paragraph)
					{
						//TODO пересмотреть обработку. получаем текст из контента, затем делаем контент из текста!
						this._specialPasteParagraphConvert(cDocumentContent.Content[n]);

						var value = cDocumentContent.Content[n].GetText();
						var newParaRun = new ParaRun();

						var bIsAddTabBefore = false;
						if(newParagraph.Content.length > 1)
						{
							bIsAddTabBefore = true;
						}

						addTextIntoRun(newParaRun, value, bIsAddTabBefore, true);

						newParagraph.Internal_Content_Add(newParagraph.Content.length - 1, newParaRun, false);
					}
					else if(cDocumentContent.Content[n] instanceof CTable)
					{
						t._convertTableToText(cDocumentContent.Content[n], obj, newParagraph);
						createNewParagraph = true;
						previousTableAdd = true;
					}

					if(!previousTableAdd && cDocumentContent.Content.length > 1 && n !== cDocumentContent.Content.length - 1)
					{
						obj.push(newParagraph);
						createNewParagraph = true;
					}
				}
			}

			obj.push(newParagraph);
			newParagraph = null;
		}

		return obj;
	},

	_checkNumberingText: function(paragraph, oNumInfo, oNumPr)
	{
		if (oNumPr)
		{
			var oNum = this.oLogicDocument.GetNumbering().GetNum(oNumPr.NumId);
			if (oNum)
			{
				var sNumberingText = oNum.GetText(oNumPr.Lvl, oNumInfo);

				var newParaRun = new ParaRun();
				addTextIntoRun(newParaRun, sNumberingText, false, true, true);
				paragraph.Internal_Content_Add(0, newParaRun, false);
			}
		}
	},

	_getNumberingText: function(Lvl, NumInfo, NumTextPr, LvlPr/*, bAddTabBetween*/)
	{
		var Text = LvlPr.LvlText;

		var Char = "";
		//Context.SetTextPr( NumTextPr, Theme );
		//Context.SetFontSlot( fontslot_ASCII );
		//g_oTextMeasurer.SetTextPr( NumTextPr, Theme );
		//g_oTextMeasurer.SetFontSlot( fontslot_ASCII );

		for ( var Index = 0; Index < Text.length; Index++ )
		{
			switch( Text[Index].Type )
			{
				case numbering_lvltext_Text:
				{
					var Hint = NumTextPr.RFonts.Hint;
					var bCS  = NumTextPr.CS;
					var bRTL = NumTextPr.RTL;
					var lcid = NumTextPr.Lang.EastAsia;

					var FontSlot = g_font_detector.Get_FontClass( Text[Index].Value.charCodeAt(0), Hint, lcid, bCS, bRTL );

					Char += Text[Index].Value;
					//Context.SetFontSlot( FontSlot );
					//g_oTextMeasurer.SetFontSlot( FontSlot );

					//Context.FillText( X, Y, Text[Index].Value );
					//X += g_oTextMeasurer.Measure( Text[Index].Value ).Width;

					break;
				}
				case numbering_lvltext_Num:
				{
					//Context.SetFontSlot( fontslot_ASCII );
					//g_oTextMeasurer.SetFontSlot( fontslot_ASCII );

					var CurLvl = Text[Index].Value;
					switch( LvlPr.Format )
					{
						case Asc.c_oAscNumberingFormat.Bullet:
						{
							break;
						}

						case Asc.c_oAscNumberingFormat.Decimal:
						{
							if ( CurLvl < NumInfo.length )
							{
								var T = "" + ( LvlPr.Start - 1 + NumInfo[CurLvl] );
								for ( var Index2 = 0; Index2 < T.length; Index2++ )
								{
									Char += T.charAt(Index2);
									//Context.FillText( X, Y, Char );
									//X += g_oTextMeasurer.Measure( Char ).Width;
								}
							}
							break;
						}

						case Asc.c_oAscNumberingFormat.DecimalZero:
						{
							if ( CurLvl < NumInfo.length )
							{
								var T = "" + ( LvlPr.Start - 1 + NumInfo[CurLvl] );

								if ( 1 === T.length )
								{
									//Context.FillText( X, Y, '0' );
									//X += g_oTextMeasurer.Measure( '0' ).Width;

									var Char = T.charAt(0);
									//Context.FillText( X, Y, Char );
									//X += g_oTextMeasurer.Measure( Char ).Width;
								}
								else
								{
									for ( var Index2 = 0; Index2 < T.length; Index2++ )
									{
										Char += T.charAt(Index2);
										//Context.FillText( X, Y, Char );
										//X += g_oTextMeasurer.Measure( Char ).Width;
									}
								}
							}
							break;
						}

						case Asc.c_oAscNumberingFormat.LowerLetter:
						case Asc.c_oAscNumberingFormat.UpperLetter:
						{
							if ( CurLvl < NumInfo.length )
							{
								// Формат: a,..,z,aa,..,zz,aaa,...,zzz,...
								var Num = LvlPr.Start - 1 + NumInfo[CurLvl] - 1;

								var Count = (Num - Num % 26) / 26;
								var Ost   = Num % 26;

								var T = "";

								var Letter;
								if ( Asc.c_oAscNumberingFormat.LowerLetter === LvlPr.Format )
									Letter = String.fromCharCode( Ost + 97 );
								else
									Letter = String.fromCharCode( Ost + 65 );

								for ( var Index2 = 0; Index2 < Count + 1; Index2++ )
									T += Letter;

								for ( var Index2 = 0; Index2 < T.length; Index2++ )
								{
									Char += T.charAt(Index2);
									//Context.FillText( X, Y, Char );
									//X += g_oTextMeasurer.Measure( Char ).Width;
								}
							}
							break;
						}

						case Asc.c_oAscNumberingFormat.LowerRoman:
						case Asc.c_oAscNumberingFormat.UpperRoman:
						{
							if ( CurLvl < NumInfo.length )
							{
								var Num = LvlPr.Start - 1 + NumInfo[CurLvl];

								// Переводим число Num в римскую систему исчисления
								var Rims;

								if ( Asc.c_oAscNumberingFormat.LowerRoman === LvlPr.Format )
									Rims = [  'm', 'cm', 'd', 'cd', 'c', 'xc', 'l', 'xl', 'x', 'ix', 'v', 'iv', 'i', ' '];
								else
									Rims = [  'M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I', ' '];

								var Vals = [ 1000,  900, 500,  400, 100,   90,  50,   40,  10,    9,   5,    4,   1,   0];

								var T = "";
								var Index2 = 0;
								while ( Num > 0 )
								{
									while ( Vals[Index2] <= Num )
									{
										T   += Rims[Index2];
										Num -= Vals[Index2];
									}

									Index2++;

									if ( Index2 >= Rims.length )
										break;
								}

								for ( var Index2 = 0; Index2 < T.length; Index2++ )
								{
									Char += T.charAt(Index2);
									//Context.FillText( X, Y, Char );
									//X += g_oTextMeasurer.Measure( T.charAt(Index2) ).Width;
								}
							}
							break;
						}
					}

					break;
				}
			}
		}
		return Char;
	},

	//***end special paste***

	InsertInPlacePresentation: function(aNewContent, isText)
	{
		var presentation = editor.WordControl.m_oLogicDocument;
		
		var presentationSelectedContent = new PresentationSelectedContent();
		presentationSelectedContent.DocContent = new CSelectedContent();
		for (var i = 0, length = aNewContent.length; i < length; ++i) {
			var oSelectedElement = new CSelectedElement();

			if (window['AscCommon'].g_specialPasteHelper.specialPasteStart && !isText) {
				aNewContent[i]= this._specialPasteItemConvert(aNewContent[i]);
			}

			oSelectedElement.Element = aNewContent[i];
			presentationSelectedContent.DocContent.Elements[i] = oSelectedElement;
		}

		presentation.Insert_Content(presentationSelectedContent);
		presentation.Recalculate();
        presentation.Check_CursorMoveRight();
		presentation.Document_UpdateInterfaceState();

		this._setSpecialPasteShowOptionsPresentation();
		window['AscCommon'].g_specialPasteHelper.Paste_Process_End();
	},

	_setSpecialPasteShowOptionsPresentation: function(props){
		var presentation = editor.WordControl.m_oLogicDocument;
		var stateSelection = presentation.GetSelectionState();
		var curPage = stateSelection.CurPage;
		var pos = presentation.GetTargetPosition();
		props = !props ? [Asc.c_oSpecialPasteProps.sourceformatting, Asc.c_oSpecialPasteProps.keepTextOnly] : props;
		var x, y, w, h;
		if (null === pos) {
			pos = presentation.GetSelectedBounds();
			w = pos.w;
			h = pos.h;
			x = pos.x + w;
			y = pos.y + h;
		} else {
			x = pos.X;
			y = pos.Y;
		}
		var screenPos = window["editor"].WordControl.m_oLogicDocument.DrawingDocument.ConvertCoordsToCursorWR(x, y, curPage);

		var specialPasteShowOptions = window['AscCommon'].g_specialPasteHelper.buttonInfo;
		specialPasteShowOptions.asc_setOptions(props);

		var targetDocContent = presentation.Get_TargetDocContent();
		if(targetDocContent && targetDocContent.Id) {
			specialPasteShowOptions.setShapeId(targetDocContent.Id);
		} else {
			specialPasteShowOptions.setShapeId(null);
		}

		var curCoord = new AscCommon.asc_CRect( screenPos.X, screenPos.Y, 0, 0 );
		specialPasteShowOptions.asc_setCellCoord(curCoord);
		specialPasteShowOptions.setFixPosition({x: x, y: y, pageNum: curPage, w: w, h: h});
	},

    insertInPlace2: function(oDoc, aNewContent)
    {
        var nNewContentLength = aNewContent.length;
		//Часть кода из Document.Add_NewParagraph

        for(var i = 0; i < aNewContent.length; ++i)
        {
            aNewContent[i].Clear_TextFormatting();
            aNewContent[i].Clear_Formatting(true);
        }
        oDoc.Remove(1, true, true);
        var Item = oDoc.Content[oDoc.CurPos.ContentPos];
        if( type_Paragraph === Item.GetType() )
        {
            if(/*true != this.bInBlock &&*/ 1 === nNewContentLength && type_Paragraph === aNewContent[0].GetType() && Item.CurPos.ContentPos !== 1)
            {
				//Вставка строки в параграф
                var oInsertPar = aNewContent[0];
                var nContentLength = oInsertPar.Content.length;
                if(nContentLength > 2)
                {
                    var oFindObj = Item.Internal_FindBackward(Item.CurPos.ContentPos, [para_TextPr]);
                    var TextPr = null;
					if ( true === oFindObj.Found && para_TextPr === oFindObj.Type )
						TextPr = Item.Content[oFindObj.LetterPos].Copy();
					else
						TextPr = new ParaTextPr();
                    var nContentPos = Item.CurPos.ContentPos;
                    for(var i = 0; i < nContentLength - 2; ++i)// -2 на спецсимволы конца параграфа
                    {
                        var oCurInsItem = oInsertPar.Content[i];
                        if(para_Numbering !== oCurInsItem.Type)
                        {
                            Item.Internal_Content_Add(nContentPos, oCurInsItem);
                            nContentPos++;
                        }
                    }
                    Item.Internal_Content_Add(nContentPos, TextPr);
                }
                Item.RecalcInfo.Set_Type_0(pararecalc_0_All);
                Item.RecalcInfo.Set_Type_0_Spell(pararecalc_0_Spell_All);
            }
            else
            {
                var LastPos = this.oRecalcDocument.CurPos.ContentPos;
                var LastPosCurDoc = oDoc.CurPos.ContentPos;
				//Нужно разрывать параграф
                var oSourceFirstPar = Item;
                var oSourceLastPar = new Paragraph(oDoc.DrawingDocument, oDoc);
                if(true !== oSourceFirstPar.IsCursorAtEnd() || oSourceFirstPar.IsEmpty())
                    oSourceFirstPar.Split(oSourceLastPar);
                var oInsFirstPar = aNewContent[0];
                var oInsLastPar = null;
                if(nNewContentLength > 1)
                    oInsLastPar = aNewContent[nNewContentLength - 1];

                var nStartIndex = 0;
                var nEndIndex = nNewContentLength - 1;

                if(type_Paragraph === oInsFirstPar.GetType())
                {
					//копируем свойства первого вставляемого параграфа в первый исходный параграф
					//CopyPr_Open - заносим в историю, т.к. этот параграф уже в документе
                    oInsFirstPar.CopyPr_Open( oSourceFirstPar );
					//Копируем содержимое вставляемого параграфа
                    oSourceFirstPar.Concat(oInsFirstPar);
                    if(AscCommon.isRealObject(oInsFirstPar.bullet))
                    {
                        oSourceFirstPar.setPresentationBullet(oInsFirstPar.bullet.createDuplicate());
                    }
					//Сдвигаем стартовый индекс чтобы больше не учитывать этот параграф
                    nStartIndex++;
                }
                else if(type_Table === oInsFirstPar.GetType())
                {
					//если вставляем таблицу в пустой параграф, то не разрываем его
                    if(oSourceFirstPar.IsEmpty())
                    {
                        oSourceFirstPar = null;
                    }
                }
				//Если не скопирован символ конца параграфа, то добавляем содержимое последнего параграфа в начело второй половины разбитого параграфа
                if(null != oInsLastPar && type_Paragraph == oInsLastPar.GetType() && true != this.bInBlock)
                {
                    var nNewContentPos = oInsLastPar.Content.length - 2;
					//копируем свойства последнего исходного параграфа в последний  вставляемый параграф
					//CopyPr - не заносим в историю, т.к. в историю добавится вставка этого параграфа в документ
                    var ind = oInsLastPar.Pr.Ind;
                    if(null != oInsLastPar)
                        oSourceLastPar.CopyPr( oInsLastPar );
                    if(oInsLastPar.bullet)
                    {
                        oInsLastPar.Set_Ind(ind);
                    }
                    oInsLastPar.Concat(oSourceLastPar);
                    oInsLastPar.CurPos.ContentPos = nNewContentPos;
                    oSourceLastPar = oInsLastPar;
                    nEndIndex--;
                }
				//вставляем
                for(var i = nStartIndex; i <= nEndIndex; ++i )
                {
                    var oElemToAdd = aNewContent[i];
                    LastPosCurDoc++;
                    oDoc.Internal_Content_Add(LastPosCurDoc, oElemToAdd);
                }
                if(null != oSourceLastPar)
                {
					//вставляем последний параграф
                    LastPosCurDoc++;
                    oDoc.Internal_Content_Add(LastPosCurDoc, oSourceLastPar);
                }
                if(null == oSourceFirstPar)
                {
					//Удаляем первый параграф, потому что будут ошибки если в документе не будет ни одного параграфа
                    oDoc.Internal_Content_Remove(LastPosCurDoc, 1);
                    LastPosCurDoc--;
                }
                Item.RecalcInfo.Set_Type_0(pararecalc_0_All);
                Item.RecalcInfo.Set_Type_0_Spell(pararecalc_0_Spell_All);
                oDoc.CurPos.ContentPos = LastPosCurDoc;
            }
        }
		
		var content = oDoc.Content;
		for(var  i = 0;  i < content.length; ++i)
		{
            content[i].Recalc_CompiledPr();
			content[i].RecalcInfo.Set_Type_0(pararecalc_0_All);
		}
	},
    ReadFromBinary : function(sBase64, oDocument)
	{
        var oDocumentParams = PasteElementsId.g_bIsDocumentCopyPaste ? this.oDocument : null;
		var openParams = { checkFileSize: false, charCount: 0, parCount: 0, bCopyPaste: true, oDocument: oDocumentParams };
		var doc = oDocument ? oDocument : this.oLogicDocument;
        var oBinaryFileReader = new AscCommonWord.BinaryFileReader(doc, openParams);
        var oRes = oBinaryFileReader.ReadFromString(sBase64, {wordCopyPaste: true});
        this.bInBlock = oRes.bInBlock;

		if(!oRes.content.length && !oRes.aPastedImages.length && !oRes.images.length) {
			oRes = null;
		}

        return oRes;
	},

    SetShortImageId: function(aPastedImages)
    {
        if(!aPastedImages)
			return;
		
		for(var i = 0, length = aPastedImages.length; i < length; ++i)
        {
            var imageElem = aPastedImages[i];
            if(null != imageElem)
            {
                imageElem.SetUrl(imageElem.Url);
            }
        }
    },

	Start : function(node, nodeDisplay, bDuplicate, fromBinary, text)
    {
		//PASTE
		if(text){

            this.oDocument = this._GetTargetDocument(this.oDocument);
            this.oLogicDocument.RemoveBeforePaste();
			this._pasteText(text);
			return;
		}

		var bInsertFromBinary = false;

		if(!node && "" === fromBinary)
		{
			return;
		}
		
		if(PasteElementsId.copyPasteUseBinary)
		{
			//get binary
			var base64FromWord = null, base64FromExcel = null, base64FromPresentation;
			var binaryObj = this._getClassBinaryFromHtml(node, fromBinary);
			base64FromExcel = binaryObj.base64FromExcel;
			base64FromWord = binaryObj.base64FromWord;
			base64FromPresentation = binaryObj.base64FromPresentation;
			
			var bTurnOffTrackRevisions = false;
			if(PasteElementsId.g_bIsDocumentCopyPaste)//document
			{
				var oThis = this;
				//удаляем в начале, иначе может получиться что будем вставлять в элементы, которое потом удалим.
				//todo с удалением в начале есть проблема, что удаляем элементы даже при пустом буфере
				this.oLogicDocument.RemoveBeforePaste();
				this.oDocument = this._GetTargetDocument(this.oDocument);
				
				if(this.oDocument && this.oDocument.bPresentation){
					if(oThis.api.WordControl.m_oLogicDocument.TrackRevisions){
						oThis.api.WordControl.m_oLogicDocument.TrackRevisions = false;
						bTurnOffTrackRevisions = true;
					}
				}
			}
			
			//insert from binary
			if(base64FromExcel)//вставка из редактора таблиц
			{
				if(PasteElementsId.g_bIsDocumentCopyPaste)
				{
					bInsertFromBinary = null !== this._pasteBinaryFromExcelToWord(base64FromExcel);
				}
				else
				{
					bInsertFromBinary = null !== this._pasteBinaryFromExcelToPresentation(base64FromExcel);
				}
			}
			else if(base64FromWord)//вставка из редактора документов
			{
				if(PasteElementsId.g_bIsDocumentCopyPaste)
				{
					bInsertFromBinary = null !== this._pasteBinaryFromWordToWord(base64FromWord, !!(fromBinary));
				}
				else
				{
					bInsertFromBinary = null !== this._pasteBinaryFromWordToPresentation(base64FromWord, !!(fromBinary));
				}
			}
			else if(base64FromPresentation)//вставка из редактора презентаций
			{
				if(PasteElementsId.g_bIsDocumentCopyPaste)
				{
					bInsertFromBinary = null !== this._pasteBinaryFromPresentationToWord(base64FromPresentation, bDuplicate);
				}
				else
				{
					bInsertFromBinary = null !== this._pasteBinaryFromPresentationToPresentation(base64FromPresentation);
				}
			}
		}
		
		if(true === bInsertFromBinary)
		{
			if(bTurnOffTrackRevisions){
				oThis.api.WordControl.m_oLogicDocument.TrackRevisions = true;
			}
		}
		else if(node)
		{
			this._pasteFromHtml(node, bTurnOffTrackRevisions);
		}
		else
		{
			window['AscCommon'].g_specialPasteHelper.CleanButtonInfo();
			window['AscCommon'].g_specialPasteHelper.Paste_Process_End();
		}
    },

	//from EXCEL to WORD
	_pasteBinaryFromExcelToWord: function (base64FromExcel) {
		var oThis = this;

		var fPrepasteCallback = function () {
			if (false === oThis.bNested) {
				oThis.InsertInDocument();
				if (oThis.aContent.bAddNewStyles) {
					oThis.api.GenerateStyles();
				}
			}
		};

		History.TurnOff();
		var aContentExcel = this._readFromBinaryExcel(base64FromExcel);
		History.TurnOn();

		if(null === aContentExcel) {
			return null;
		}

		if (window['AscCommon'].g_specialPasteHelper.specialPasteStart &&
			Asc.c_oSpecialPasteProps.keepTextOnly === window['AscCommon'].g_specialPasteHelper.specialPasteProps) {
			var aContent = oThis._convertExcelBinary(aContentExcel);
			oThis.aContent = aContent.content;
			fPrepasteCallback();
		} else if (aContentExcel.arrImages && aContentExcel.arrImages.length) {
			var oObjectsForDownload = GetObjectsForImageDownload(aContentExcel.arrImages);
			AscCommon.sendImgUrls(oThis.api, oObjectsForDownload.aUrls, function (data) {
				var oImageMap = {};
				ResetNewUrls(data, oObjectsForDownload.aUrls, oObjectsForDownload.aBuilderImagesByUrl, oImageMap);
				var aContent = oThis._convertExcelBinary(aContentExcel);
				oThis.aContent = aContent.content;
				oThis.api.pre_Paste(aContent.fonts, oImageMap, fPrepasteCallback);
			}, null, true);
		} else {
			var aContent = oThis._convertExcelBinary(aContentExcel);
			oThis.aContent = aContent.content;
			oThis.api.pre_Paste(aContent.fonts, aContent.images, fPrepasteCallback);
		}
	},

	//from EXCEL to PRESENTATION
	_pasteBinaryFromExcelToPresentation: function (base64FromExcel) {
		var oThis = this;
		var presentation = editor.WordControl.m_oLogicDocument;

		var excelContent = AscFormat.ExecuteNoHistory(this._readFromBinaryExcel, this, [base64FromExcel]);
		if(null === excelContent) {
			return null;
		}

		var aContentExcel = excelContent.workbook;
		var aPastedImages = excelContent.arrImages;

		//если есть шейпы, то вставляем их из excel
		if (aContentExcel && aContentExcel.aWorksheets && aContentExcel.aWorksheets[0] &&
			aContentExcel.aWorksheets[0].Drawings && aContentExcel.aWorksheets[0].Drawings.length) {
			var paste_callback = function () {
				if (false === oThis.bNested) {
					var oIdMap = {};
					var aCopies = [];

                    var l = null, t = null, r = null, b = null, oXfrm;

					for (var i = 0; i < arr_shapes.length; ++i) {
						shape = arr_shapes[i].graphicObject.copy();
						aCopies.push(shape);
						oIdMap[arr_shapes[i].graphicObject.Id] = shape.Id;
						shape.worksheet = null;
						shape.drawingBase = null;

						arr_shapes[i] = new DrawingCopyObject(shape, 0, 0, 0, 0);
                        if(shape.spPr && shape.spPr.xfrm && AscFormat.isRealNumber(shape.spPr.xfrm.offX) && AscFormat.isRealNumber(shape.spPr.xfrm.offY)
                            && AscFormat.isRealNumber(shape.spPr.xfrm.extX) && AscFormat.isRealNumber(shape.spPr.xfrm.extY)) {
                            oXfrm = shape.spPr.xfrm;
                            if(l === null){
                                l = oXfrm.offX;
                            }
                            else{
                                if(oXfrm.offX < l){
                                    l = oXfrm.offX;
                                }
                            }
                            if(t === null){
                                t = oXfrm.offY;
                            }
                            else{
                                if(oXfrm.offY < t){
                                    t = oXfrm.offY;
                                }
                            }
                            if(r === null){
                                r = oXfrm.offX + oXfrm.extX;
                            }
                            else{
                                if(oXfrm.offX + oXfrm.extX > r){
                                    r = oXfrm.offX + oXfrm.extX;
                                }
                            }
                            if(b === null){
                                b = oXfrm.offY + oXfrm.extY;
                            }
                            else{
                                if(oXfrm.offY + oXfrm.extY > b){
                                    b = oXfrm.offY + oXfrm.extY;
                                }
                            }
                        }
					}
					if(AscFormat.isRealNumber(l) && AscFormat.isRealNumber(t)
                        && AscFormat.isRealNumber(r) && AscFormat.isRealNumber(b)){
                        var fSlideCX = presentation.Width/2.0;
                        var fSlideCY = presentation.Height/2.0;
                        var fBoundsCX = (r+l)/2.0;
                        var fBoundsCY = (t+b)/2.0;
                        var fDiffX =  fBoundsCX - fSlideCX;
                        var fDiffY =  fBoundsCY - fSlideCY;
                        if(!AscFormat.fApproxEqual(fDiffX, 0) || !AscFormat.fApproxEqual(fDiffY, 0)){
                            for (var i = 0; i < arr_shapes.length; ++i) {
                                shape = arr_shapes[i].Drawing;
                                if(shape.spPr && shape.spPr.xfrm && AscFormat.isRealNumber(shape.spPr.xfrm.offX) && AscFormat.isRealNumber(shape.spPr.xfrm.offY)
                                    && AscFormat.isRealNumber(shape.spPr.xfrm.extX) && AscFormat.isRealNumber(shape.spPr.xfrm.extY)) {
                                    shape.spPr.xfrm.setOffX(shape.spPr.xfrm.offX - fDiffX);
                                    shape.spPr.xfrm.setOffY(shape.spPr.xfrm.offY - fDiffY);
                                }
                            }
                        }
                    }
					AscFormat.fResetConnectorsIds(aCopies, oIdMap);

					var presentationSelectedContent = new PresentationSelectedContent();
					presentationSelectedContent.Drawings = arr_shapes;

					presentation.Insert_Content(presentationSelectedContent);
					presentation.Recalculate();

					presentation.Check_CursorMoveRight();
					presentation.Document_UpdateInterfaceState();

					window['AscCommon'].g_specialPasteHelper.Paste_Process_End();
				}
			};


			var arr_shapes = aContentExcel.aWorksheets[0].Drawings;

			var aImagesToDownload = [];
			for (var i = 0; i < aPastedImages.length; i++) {
				aImagesToDownload.push(aPastedImages[i].Url);
			}

			var aContent = {aPastedImages: aPastedImages, images: aImagesToDownload};

			//fonts
			var font_map = {};
			for (var i = 0; i < arr_shapes.length; ++i) {
				var shape = arr_shapes[i].graphicObject;
				shape.getAllFonts(font_map);
			}

			var fonts = [];
			//грузим картинки и фонты
			for (var i in font_map) {
				fonts.push(new CFont(i, 0, "", 0));
			}

			//images
			var images = aContent.images;
			var arrImages = aContent.aPastedImages;
			var oObjectsForDownload = GetObjectsForImageDownload(arrImages);
			if (oObjectsForDownload.aUrls.length > 0) {
				AscCommon.sendImgUrls(oThis.api, oObjectsForDownload.aUrls, function (data) {
					var oImageMap = {};

					History.TurnOff();
					ResetNewUrls(data, oObjectsForDownload.aUrls, oObjectsForDownload.aBuilderImagesByUrl, oImageMap);
					oThis.api.pre_Paste(fonts, oImageMap, paste_callback);
					History.TurnOn();
				}, null, true);
			} else {
				var im_arr = [];
				for (var key  in images) {
					im_arr.push(key);
				}

				this.SetShortImageId(arrImages);
				this.api.pre_Paste(fonts, im_arr, paste_callback);
			}
		} else {
			var presentationSelectedContent = new PresentationSelectedContent();
			presentationSelectedContent.DocContent = new CSelectedContent();

			var aContent = AscFormat.ExecuteNoHistory(this._convertExcelBinary, this, [excelContent]);

			var elements = [], selectedElement, element, drawings = [], pDrawings = [], drawingCopyObject;
			var defaultTableStyleId = presentation.DefaultTableStyleId;
			for (var i = 0; i < aContent.content.length; ++i) {
				selectedElement = new CSelectedElement();
				element = aContent.content[i];

				if (type_Table == element.GetType())//table
				{
					//TODO переделать количество строк и ширину
					var W = 100;
					var Rows = 3;
					var graphic_frame = new CGraphicFrame();
					graphic_frame.setSpPr(new AscFormat.CSpPr());
					graphic_frame.spPr.setParent(graphic_frame);
					graphic_frame.spPr.setXfrm(new AscFormat.CXfrm());
					graphic_frame.spPr.xfrm.setParent(graphic_frame.spPr);
					graphic_frame.spPr.xfrm.setOffX((this.oDocument.Width - W) / 2);
					graphic_frame.spPr.xfrm.setOffY(this.oDocument.Height / 5);
					graphic_frame.spPr.xfrm.setExtX(W);
					graphic_frame.spPr.xfrm.setExtY(7.478268771701388 * Rows);
					graphic_frame.setNvSpPr(new AscFormat.UniNvPr());

					element = this._convertTableToPPTX(element);
					graphic_frame.setGraphicObject(element.Copy(graphic_frame));
					//graphic_frame.graphicObject.Set_TableStyle(presentation.DefaultTableStyleId);

					drawingCopyObject = new DrawingCopyObject();
					drawingCopyObject.Drawing = graphic_frame;
					pDrawings.push(drawingCopyObject);
				}
			}
			presentationSelectedContent.Drawings = pDrawings;

			//вставка
			var paste_callback = function () {
				if (false == oThis.bNested) {
					presentation.Insert_Content(presentationSelectedContent);
					presentation.Recalculate();
					presentation.Check_CursorMoveRight();
					presentation.Document_UpdateInterfaceState();

					var props = [Asc.c_oSpecialPasteProps.destinationFormatting, Asc.c_oSpecialPasteProps.keepTextOnly];
					oThis._setSpecialPasteShowOptionsPresentation(props);

					window['AscCommon'].g_specialPasteHelper.Paste_Process_End();
				}
			};

			oThis.api.pre_Paste(aContent.fonts, null, paste_callback);
		}
	},

	//from WORD to WORD
	_pasteBinaryFromWordToWord: function (base64FromWord, bIsOnlyFromBinary) {
		var oThis = this;
		var aContent = this.ReadFromBinary(base64FromWord);

		if(null === aContent) {
			return null;
		}

		//вставляем в заголовок диаграммы, предварительно конвертируем все параграфы в презентационный формат
		if (aContent && aContent.content && this.oDocument.bPresentation && oThis.oDocument && oThis.oDocument.Parent &&
			oThis.oDocument.Parent.parent && oThis.oDocument.Parent.parent.parent &&
			oThis.oDocument.Parent.parent.parent.getObjectType &&
			oThis.oDocument.Parent.parent.parent.getObjectType() == AscDFH.historyitem_type_Chart) {

			//не грузим изображения при вставке в заголовок диаграммы
			aContent.images = [];
			aContent.aPastedImages = [];

			var newContent = [];
			for (var i = 0; i < aContent.content.length; i++) {
				if (type_Paragraph === aContent.content[i].Get_Type()) {
					newContent.push(
						AscFormat.ConvertParagraphToPPTX(aContent.content[i], this.oDocument.DrawingDocument,
							this.oDocument, false, true));
				}
			}

			aContent.content = newContent;
		}

		var fPrepasteCallback = function () {
			if (false === oThis.bNested) {
				oThis.InsertInDocument();
				if (aContent.bAddNewStyles) {
					oThis.api.GenerateStyles();
				}
				oThis.api.continueInsertDocumentUrls();
			}
		};

		this.aContent = aContent.content;
		//проверяем список фонтов
		aContent.fonts = oThis._checkFontsOnLoad(aContent.fonts);

		var oObjectsForDownload = GetObjectsForImageDownload(aContent.aPastedImages);
		if (window['AscCommon'].g_specialPasteHelper.specialPasteStart &&
			Asc.c_oSpecialPasteProps.keepTextOnly === window['AscCommon'].g_specialPasteHelper.specialPasteProps) {
			oThis.api.pre_Paste([], [], fPrepasteCallback);
		} else if (oObjectsForDownload.aUrls.length > 0) {
			if (bIsOnlyFromBinary && window["NativeCorrectImageUrlOnPaste"]) {
				var url;
				for (var i = 0, length = aContent.aPastedImages.length; i < length; ++i) {
					url = window["NativeCorrectImageUrlOnPaste"](aContent.aPastedImages[i].Url);
					aContent.images[i] = url;

					var imageElem = aContent.aPastedImages[i];
					if (null != imageElem) {
						imageElem.SetUrl(url);
					}
				}
				oThis.api.pre_Paste(aContent.fonts, aContent.images, fPrepasteCallback);
			} else {
				AscCommon.sendImgUrls(oThis.api, oObjectsForDownload.aUrls, function (data) {
					ResetNewUrls(data, oObjectsForDownload.aUrls, oObjectsForDownload.aBuilderImagesByUrl,
						aContent.images);
					oThis.api.pre_Paste(aContent.fonts, aContent.images, fPrepasteCallback);
				}, null, true);
			}
		} else {
			oThis.SetShortImageId(aContent.aPastedImages);
			oThis.api.pre_Paste(aContent.fonts, aContent.images, fPrepasteCallback);
		}
	},

	//from WORD to PRESENTATION
	_pasteBinaryFromWordToPresentation: function (base64FromWord) {
		var oThis = this;
		var presentation = editor.WordControl.m_oLogicDocument;
		var trueDocument = this.oDocument;

		var tempCDocument = function()
		{
			return new CDocument( this.oDocument.DrawingDocument, false);
		};
		//создаём темповый CDocument
		this.oDocument = AscFormat.ExecuteNoHistory(tempCDocument , this, []);

		AscCommon.g_oIdCounter.m_bRead = true;
		var aContent = AscFormat.ExecuteNoHistory(this.ReadFromBinary, this, [base64FromWord, this.oDocument]);
		AscCommon.g_oIdCounter.m_bRead = false;

		if(null === aContent) {
			return null;
		}

		//возврщаем обратно переменные и историю, документ которой заменяется при создании CDocument
		this.oDocument = trueDocument;
		History.Document = trueDocument;

		var presentationSelectedContent = new PresentationSelectedContent();
		presentationSelectedContent.DocContent = new CSelectedContent();

		var parseContent = function(content) {
			for(var i = 0; i < content.length; ++i)
			{
				selectedElement = new CSelectedElement();
				element = content[i];
				//drawings
				element.GetAllDrawingObjects(drawings);
				if(type_Paragraph === element.GetType())//paragraph
				{
					selectedElement.Element = AscFormat.ConvertParagraphToPPTX(element, null, null, true, false);
					elements.push(selectedElement);
				}
				else if(type_Table === element.GetType())//table
				{
					//TODO переделать количество строк и ширину
					var W = 100;
					var Rows = 3;
					var graphic_frame = new CGraphicFrame();
					graphic_frame.setSpPr(new AscFormat.CSpPr());
					graphic_frame.spPr.setParent(graphic_frame);
					graphic_frame.spPr.setXfrm(new AscFormat.CXfrm());
					graphic_frame.spPr.xfrm.setParent(graphic_frame.spPr);
					graphic_frame.spPr.xfrm.setOffX((oThis.oDocument.Width - W)/2);
					graphic_frame.spPr.xfrm.setOffY(oThis.oDocument.Height/5);
					graphic_frame.spPr.xfrm.setExtX(W);
					graphic_frame.spPr.xfrm.setExtY(7.478268771701388 * Rows);
					graphic_frame.setNvSpPr(new AscFormat.UniNvPr());

					element = oThis._convertTableToPPTX(element, true);
					graphic_frame.setGraphicObject(element.Copy(graphic_frame));
					graphic_frame.graphicObject.Set_TableStyle(defaultTableStyleId);

					drawingCopyObject = new DrawingCopyObject();
					drawingCopyObject.Drawing = graphic_frame;
					pDrawings.push(drawingCopyObject);

				}
				else if(type_BlockLevelSdt === element.GetType())//TOC
				{
					parseContent(element.Content.Content);
				}
			}
		};

		var elements = [], selectedElement, element, drawings = [], pDrawings = [], drawingCopyObject;
		var defaultTableStyleId = presentation.DefaultTableStyleId;
		parseContent(aContent.content);

		if(drawings && drawings.length)
		{
			//если массив содержит только изображения
			if(elements && 1 === elements.length && elements[0].Element && type_Paragraph === elements[0].Element.Get_Type())
			{
				if(true === this._isParagraphContainsOnlyDrawing(elements[0].Element))
				{
					elements = [];
				}
			}

			for(var j = 0; j < drawings.length; j++)
			{
				drawingCopyObject = new DrawingCopyObject();
				drawingCopyObject.Drawing = drawings[j].GraphicObj;
				pDrawings.push(drawingCopyObject);
			}
		}
		presentationSelectedContent.DocContent.Elements = elements;
		presentationSelectedContent.Drawings = pDrawings;

		//вставка
		var paste_callback = function()
		{
			if(false === oThis.bNested)
			{
				presentation.Insert_Content(presentationSelectedContent);
				presentation.Recalculate();
				presentation.Check_CursorMoveRight();
				presentation.Document_UpdateInterfaceState();

				var props = [Asc.c_oSpecialPasteProps.destinationFormatting, Asc.c_oSpecialPasteProps.keepTextOnly];
				oThis._setSpecialPasteShowOptionsPresentation(props);

				window['AscCommon'].g_specialPasteHelper.Paste_Process_End();
			}
		};


		var font_map = {};
		var images = [];
		//shape.getAllFonts(font_map);

		//перебираем шрифты
		var fonts = [];
		for(var i in font_map)
			fonts.push(new CFont(i, 0, "", 0));

		var oObjectsForDownload = GetObjectsForImageDownload(aContent.aPastedImages);
		if(oObjectsForDownload.aUrls.length > 0)
		{
			AscCommon.sendImgUrls(oThis.api, oObjectsForDownload.aUrls, function (data){
				var oImageMap = {};
				ResetNewUrls(data, oObjectsForDownload.aUrls, oObjectsForDownload.aBuilderImagesByUrl, oImageMap);
				//ковертим изображения в презентационный формат
				for (var i = 0; i < presentationSelectedContent.Drawings.length; i++)
				{
					if (!(presentationSelectedContent.Drawings[i].Drawing instanceof CGraphicFrame))
					{
						AscFormat.ExecuteNoHistory(function(){
							if (presentationSelectedContent.Drawings[i].Drawing.setBDeleted2)
							{
								presentationSelectedContent.Drawings[i].Drawing.setBDeleted2(true);
							}
							else
							{
								presentationSelectedContent.Drawings[i].Drawing.setBDeleted(true);
							}
						}, this, []);
						presentationSelectedContent.Drawings[i].Drawing = presentationSelectedContent.Drawings[i].Drawing.convertToPPTX(oThis.oDocument.DrawingDocument, undefined, true);
						AscFormat.checkBlipFillRasterImages(presentationSelectedContent.Drawings[i].Drawing);
					}
				}
				oThis.api.pre_Paste(fonts, oImageMap, paste_callback);
			}, null, true);
		}
		else
		{
			//ковертим изображения в презентационный формат
			for(var i = 0; i < presentationSelectedContent.Drawings.length; i++)
			{
				if(!(presentationSelectedContent.Drawings[i].Drawing instanceof CGraphicFrame))
				{
					presentationSelectedContent.Drawings[i].Drawing = presentationSelectedContent.Drawings[i].Drawing.convertToPPTX(oThis.oDocument.DrawingDocument, undefined, true);
					AscFormat.checkBlipFillRasterImages(presentationSelectedContent.Drawings[i].Drawing);
				}
			}

			oThis.api.pre_Paste(aContent.fonts, aContent.images, paste_callback);
		}
	},

	//from PRESENTATION to WORD
	_pasteBinaryFromPresentationToWord: function (base64) {
		var oThis = this;

		var fPrepasteCallback = function () {
			if (false === oThis.bNested) {
				oThis.InsertInDocument();
				if (aContent.bAddNewStyles) {
					oThis.api.GenerateStyles();
				}
			}
		};

		var oSelectedContent2 = this._readPresentationSelectedContent2(base64);
		var selectedContent2 = oSelectedContent2.content;
		var defaultSelectedContent = selectedContent2[1] ? selectedContent2[1] : selectedContent2[0];
		var bSlideObjects = defaultSelectedContent && defaultSelectedContent.content.SlideObjects && defaultSelectedContent.content.SlideObjects.length > 0;
		var pasteObj = bSlideObjects && PasteElementsId.g_bIsDocumentCopyPaste ? selectedContent2[2] : defaultSelectedContent;

		var arr_Images, fonts, content = null, font_map = {};
		if(pasteObj) {
			arr_Images = pasteObj.images;
			fonts = pasteObj.fonts;
			content = pasteObj.content;
		}

		if(null === content) {
			return null;
		}

		if (content && content.DocContent) {

			var elements = content.DocContent.Elements;
			var aContent = [];
			for (var i = 0; i < elements.length; i++) {
				aContent[i] = AscFormat.ConvertParagraphToWord(elements[i].Element, this.oDocument);
			}
			this.aContent = aContent;

			oThis.api.pre_Paste(fonts, arr_Images, fPrepasteCallback);

		} else if (content && content.Drawings) {

			var arr_shapes = content.Drawings;
			var arrImages = pasteObj.images;
            if(!bSlideObjects && content.Drawings.length === selectedContent2[1].content.Drawings.length)
            {
                AscFormat.checkDrawingsTransformBeforePaste(content, selectedContent2[1].content, null);
            }
			//****если записана одна табличка, то вставляем html и поддерживаем все цвета и стили****
			if (!arrImages.length && arr_shapes.length === 1 && arr_shapes[0] && arr_shapes[0].Drawing &&
				arr_shapes[0].Drawing.graphicObject) {

				var drawing = arr_shapes[0].Drawing;

				if (typeof CGraphicFrame !== "undefined" && drawing instanceof CGraphicFrame) {
					var aContent = [];
					var table = AscFormat.ConvertGraphicFrameToWordTable(drawing, this.oLogicDocument);
					table.Document_Get_AllFontNames(font_map);

					//перебираем шрифты
					for (var i in font_map) {
						fonts.push(new CFont(i, 0, "", 0));
					}

					//TODO стиль не прокидывается. в будущем нужно реализовать
					table.TableStyle = null;
					aContent.push(table);

					this.aContent = aContent;
					oThis.api.pre_Paste(fonts, aContent.images, fPrepasteCallback);

					return;
				}
			}


			//если несколько графических объектов, то собираем base64 у таблиц(graphicFrame)
			if (arr_shapes.length > 1) {
				for (var i = 0; i < arr_shapes.length; i++) {
					if (typeof CGraphicFrame !== "undefined" && arr_shapes[i].Drawing instanceof CGraphicFrame) {
						arrImages.push(new AscCommon.CBuilderImages(null, arr_shapes[i].base64, arr_shapes[i], null, null));
					}
				}
			}
			
			var oObjectsForDownload = GetObjectsForImageDownload(arrImages);
			var aImagesToDownload = oObjectsForDownload.aUrls;

			AscCommon.sendImgUrls(oThis.api, aImagesToDownload, function (data) {
				var image_map = {};
				for (var i = 0, length = Math.min(data.length, arrImages.length); i < length; ++i) {
					var elem = data[i];
					if (null != elem.url) {
						var name = g_oDocumentUrls.imagePath2Local(elem.path);
						var imageElem = arrImages[i];
						if (null != imageElem) {
							//для вставки graphicFrame в виде картинки(если было при копировании выделено несколько графических объектов)
							if (imageElem.ImageShape && imageElem.ImageShape.base64) {
								imageElem.ImageShape.base64 = name;
							} else {
								imageElem.SetUrl(name);
							}
						}
						image_map[i] = name;
					} else {
						image_map[i] = aImagesToDownload[i];
					}
				}

				aContent = oThis._convertExcelBinary(null, arr_shapes);
				oThis.aContent = aContent.content;
				oThis.api.pre_Paste(fonts, image_map, fPrepasteCallback);
			}, null, true);
		}
	},

	//from PRESENTATION to PRESENTATION
	_pasteBinaryFromPresentationToPresentation: function (base64, bDuplicate) {
		var oThis = this;
		var presentation = editor.WordControl.m_oLogicDocument;

		var oSelectedContent2 = this._readPresentationSelectedContent2(base64, bDuplicate);
		var p_url = oSelectedContent2.p_url;
		var p_theme = oSelectedContent2.p_theme;
		var selectedContent2 = oSelectedContent2.content;
		var multipleParamsCount = selectedContent2 ? selectedContent2.length : 0;
		if (multipleParamsCount) {
			var aContents = [];
			for(var i = 0; i < multipleParamsCount; i++){
				var curContent = selectedContent2[i];
				aContents.push(curContent.content);
			}

			var specialOptionsArr = [];
			var specialProps = Asc.c_oSpecialPasteProps;
			if(1 === multipleParamsCount) {
				specialOptionsArr = [specialProps.destinationFormatting];
			} else if(2 === multipleParamsCount) {
				specialOptionsArr = [specialProps.destinationFormatting, specialProps.sourceformatting];
			} else if(3 === multipleParamsCount) {
				specialOptionsArr = [specialProps.destinationFormatting, specialProps.sourceformatting, specialProps.picture];
			}

			var pasteObj = selectedContent2[0];
			var nIndex = 0;
			if (window['AscCommon'].g_specialPasteHelper.specialPasteStart) {
				var props = window['AscCommon'].g_specialPasteHelper.specialPasteProps;
				switch (props) {
					case Asc.c_oSpecialPasteProps.destinationFormatting: {
						break;
					}
					case Asc.c_oSpecialPasteProps.sourceformatting: {
						if(selectedContent2[1]){
							pasteObj = selectedContent2[1];
							nIndex = 1;
						}
						break;
					}
					case Asc.c_oSpecialPasteProps.picture: {
						if(selectedContent2[2]){
							pasteObj = selectedContent2[2];
							nIndex = 2;
						}
						break;
					}
					case Asc.c_oSpecialPasteProps.keepTextOnly: {
						//в идеале у этом случае нужно использовать данные plain text из буфера обмена
						//pasteObj = selectedContent2[2];
						break;
					}
				}
			}

			var arr_Images = pasteObj.images;
			var fonts = pasteObj.fonts;
			var presentationSelectedContent = pasteObj.content;

			if(null === presentationSelectedContent) {
				return null;
			}

			if(presentationSelectedContent.Drawings && presentationSelectedContent.Drawings.length > 0) {
				var controller = this.oDocument.GetCurrentController();
				var curTheme = controller ? controller.getTheme() : null;
				if(curTheme && curTheme.name === p_theme) {
					specialOptionsArr.splice(1, 1);
				}
			}

			var paste_callback = function(){
				if (false === oThis.bNested) {
					var bPaste = presentation.Insert_Content2(aContents, nIndex);

					presentation.Recalculate();
                    presentation.Check_CursorMoveRight();
					presentation.Document_UpdateInterfaceState();

					//пока не показываю значок специальной вставки после copy/paste слайдов
					var bSlideObjects = aContents[nIndex] && aContents[nIndex].SlideObjects && aContents[nIndex].SlideObjects.length > 0;
					if (specialOptionsArr.length >= 1 && !bSlideObjects && bPaste) {
						if (presentationSelectedContent && presentationSelectedContent.DocContent) {
							specialOptionsArr.push(Asc.c_oSpecialPasteProps.keepTextOnly);
						}

						oThis._setSpecialPasteShowOptionsPresentation(specialOptionsArr);
					} else {
						window['AscCommon'].g_specialPasteHelper.CleanButtonInfo();
					}

					window['AscCommon'].g_specialPasteHelper.Paste_Process_End();
				}
			};

			var oObjectsForDownload = GetObjectsForImageDownload(arr_Images, p_url === this.api.documentId);
			if (oObjectsForDownload.aUrls.length > 0) {
				AscCommon.sendImgUrls(oThis.api, oObjectsForDownload.aUrls, function (data) {
					var oImageMap = {};
					ResetNewUrls(data, oObjectsForDownload.aUrls, oObjectsForDownload.aBuilderImagesByUrl, oImageMap);
					oThis.api.pre_Paste(fonts, oImageMap, paste_callback);
				}, null, true);
			} else {
				oThis.api.pre_Paste(fonts, {}, paste_callback);
			}
		} else {
			return null;
		}
	},

	_readPresentationSelectedContent2: function(base64, bDuplicate) {
		pptx_content_loader.Clear();

		var _stream = AscFormat.CreateBinaryReader(base64, 0, base64.length);
		var stream = new AscCommon.FileStream(_stream.data, _stream.size);
		var p_url = stream.GetString2();
		var p_theme = stream.GetString2();
		var p_width = stream.GetULong() / 100000;
		var p_height = stream.GetULong() / 100000;

		var bIsMultipleContent = stream.GetBool();
		var selectedContent2 = [];
		if (true === bIsMultipleContent) {
			var multipleParamsCount = stream.GetULong();
			for(var i = 0; i < multipleParamsCount; i++){
				selectedContent2.push(this._readPresentationSelectedContent(stream, bDuplicate));
			}
		}
		return {content: selectedContent2, p_url: p_url, p_theme: p_theme};
	},

	_readPresentationSelectedContent: function(stream, bDuplicate){
	    return AscFormat.ExecuteNoHistory(function(){
            var presentationSelectedContent = null;
            var fonts = [];
            var arr_Images = [];
            var oThis = this;

            var readContent = function () {
                var docContent = oThis.ReadPresentationText(stream);
                if (docContent.length === 0) {
                    return;
                }
                presentationSelectedContent.DocContent = new CSelectedContent();
                presentationSelectedContent.DocContent.Elements = docContent;

                //перебираем шрифты
                for (var i in oThis.oFonts) {
                    fonts.push(new CFont(i, 0, "", 0));
                }

				bIsEmptyContent = false;
            };

            var readDrawings = function () {

                if(PasteElementsId.g_bIsDocumentCopyPaste){
                    History.TurnOff();
                }
                var objects = oThis.ReadPresentationShapes(stream);
                if(PasteElementsId.g_bIsDocumentCopyPaste){
                    History.TurnOn();
                }

                presentationSelectedContent.Drawings = objects.arrShapes;

                var arr_shapes = objects.arrShapes;
                var font_map = {};
                for (var i = 0; i < arr_shapes.length; ++i) {
                    if (arr_shapes[i].Drawing.getAllFonts) {
                        arr_shapes[i].Drawing.getAllFonts(font_map);
                    }
                }

                for (var i in font_map) {
                    fonts.push(new CFont(i, 0, "", 0));
                }

				arr_Images = arr_Images.concat(objects.arrImages);
            };

            var readSlideObjects = function () {
                var arr_slides = [];
                var loader = new AscCommon.BinaryPPTYLoader();
                if (!(bDuplicate === true)) {
                    loader.Start_UseFullUrl();
                }
                loader.stream = stream;
                loader.presentation = editor.WordControl.m_oLogicDocument;

                //read slides
                var slide_count = stream.GetULong();
                //var arr_arrTransforms = [];

                for (var i = 0; i < slide_count; ++i) {
                    if(PasteElementsId.g_bIsDocumentCopyPaste){
                        loader.stream.GetUChar();
                        loader.stream.SkipRecord();
                        arr_slides[i] = null;
                    }else{
                        arr_slides[i] = loader.ReadSlide(0);
                    }
                }

                //images and fonts
                var font_map = {};
                var slideCopyObjects = [];
                for (var i = 0; i < arr_slides.length; ++i) {
                    if (arr_slides[i] && arr_slides[i].getAllFonts) {
                        arr_slides[i].getAllFonts(font_map);
                    }

                    slideCopyObjects[i] = arr_slides[i];
                }

                for (var i in font_map) {
                    fonts.push(new CFont(i, 0, "", 0));
                }

				arr_Images = arr_Images.concat(loader.End_UseFullUrl());

                presentationSelectedContent.SlideObjects = slideCopyObjects;
            };


            var readLayouts = function(){
                var loader = new AscCommon.BinaryPPTYLoader();
				if (!(bDuplicate === true)) {
					loader.Start_UseFullUrl();
				}
                loader.stream = stream;
                loader.presentation = editor.WordControl.m_oLogicDocument;

                var selected_layouts = stream.GetULong();

                var layouts = [];
                for (var i = 0; i < selected_layouts; ++i) {
                    if (PasteElementsId.g_bIsDocumentCopyPaste) {
                        loader.stream.GetUChar();
                        loader.stream.SkipRecord();
                    } else {
                        layouts.push(loader.ReadSlideLayout());
                    }
                }

                /*var font_map = {};
                for (var i = 0; i < layouts.length; ++i) {
                    if (layouts[i].getAllFonts) {
                        layouts[i].getAllFonts(font_map);
                    }
                    if (layouts[i].getAllImages) {
                        layouts[i].getAllImages(images);
                    }
                }
                for (var i in font_map) {
                    fonts.push(new CFont(i, 0, "", 0));
                }*/

				arr_Images = arr_Images.concat(loader.End_UseFullUrl());
                presentationSelectedContent.Layouts = layouts;
            };

            var readMasters = function(){
                var loader = new AscCommon.BinaryPPTYLoader();
				if (!(bDuplicate === true)) {
					loader.Start_UseFullUrl();
				}
                loader.stream = stream;
                loader.presentation = editor.WordControl.m_oLogicDocument;

                var count = stream.GetULong();

                var array = [];
                for (var i = 0; i < count; ++i) {
                    if (PasteElementsId.g_bIsDocumentCopyPaste) {
                        loader.stream.GetUChar();
                        loader.stream.SkipRecord();
                    } else {
                        array.push(loader.ReadSlideMaster());
                    }
                }

				arr_Images = arr_Images.concat(loader.End_UseFullUrl());
                presentationSelectedContent.Masters = array;
            };

            var readNotes = function(){
                var loader = new AscCommon.BinaryPPTYLoader();
                loader.stream = stream;
                loader.presentation = editor.WordControl.m_oLogicDocument;

                var selected_notes = stream.GetULong();

                var notes = [];
                for (var i = 0; i < selected_notes; ++i) {
                    if (PasteElementsId.g_bIsDocumentCopyPaste) {
                        loader.stream.GetUChar();
                        loader.stream.SkipRecord();
                    } else {
                        notes.push(loader.ReadNote());
                    }
                }

                presentationSelectedContent.Notes = notes;
            };

            var readNotesMasters = function(){
                var loader = new AscCommon.BinaryPPTYLoader();
                loader.stream = stream;
                loader.presentation = editor.WordControl.m_oLogicDocument;

                var count = stream.GetULong();

                var array = [];
                for (var i = 0; i < count; ++i) {
                    if (PasteElementsId.g_bIsDocumentCopyPaste) {
                        loader.stream.GetUChar();
                        loader.stream.SkipRecord();
                    } else {
                        array.push(loader.ReadNoteMaster());
                    }
                }

                presentationSelectedContent.NotesMasters = array;
            };

            var readNotesThemes = function(){
                var loader = new AscCommon.BinaryPPTYLoader();
                loader.stream = stream;
                loader.presentation = editor.WordControl.m_oLogicDocument;

                var count = stream.GetULong();

                //TODO возможно стоит пропустить при чтении в документах
                var array = [];
                for (var i = 0; i < count; ++i) {
                    array.push(loader.ReadTheme());
                }

                presentationSelectedContent.NotesThemes = array;
            };

            var readThemes = function(){
                var loader = new AscCommon.BinaryPPTYLoader();
				if (!(bDuplicate === true)) {
					loader.Start_UseFullUrl();
				}
                loader.stream = stream;
                loader.presentation = editor.WordControl.m_oLogicDocument;

                var count = stream.GetULong();

                //TODO возможно стоит пропустить при чтении в документах
                var array = [];
                for (var i = 0; i < count; ++i) {
                    array.push(loader.ReadTheme());
                }

				arr_Images = arr_Images.concat(loader.End_UseFullUrl());
                presentationSelectedContent.Themes = array;
            };

            var readIndexes = function(){
                var count = stream.GetULong();

                var array = [];
                for (var i = 0; i < count; ++i) {
                    array.push(stream.GetULong());
                }

                return array;
            };

			var bIsEmptyContent = true;
            var first_content = stream.GetString2();
            if(first_content === "SelectedContent"){
                var PresentationWidth = stream.GetULong()/100000.0;
                var PresentationHeight = stream.GetULong()/100000.0;
                var countContent = stream.GetULong();
                for(var i = 0; i < countContent; i++){
                    if(null === presentationSelectedContent){
                        presentationSelectedContent = typeof PresentationSelectedContent !== "undefined" ? new PresentationSelectedContent() : {};
                        presentationSelectedContent.PresentationWidth = PresentationWidth;
                        presentationSelectedContent.PresentationHeight = PresentationHeight;
                    }
                    var first_string = stream.GetString2();
					if("DocContent" !== first_string) {
						bIsEmptyContent = false;
					}

                    switch (first_string) {
                        case "DocContent": {
                            readContent();
                            break;
                        }
                        case "Drawings": {
                            readDrawings();
                            break;
                        }
                        case "SlideObjects": {
                            readSlideObjects();
                            break;
                        }
                        case "Layouts": {
                            History.TurnOff();
                            readLayouts();
                            History.TurnOn();
                            break;
                        }
                        case "LayoutsIndexes": {
                            presentationSelectedContent.LayoutsIndexes = readIndexes();
                            break;
                        }
                        case "Masters": {
                            readMasters();
                            break;
                        }
                        case "MastersIndexes": {
                            presentationSelectedContent.MastersIndexes = readIndexes();
                            break;
                        }
                        case "Notes": {
                            readNotes();
                            break;
                        }
                        case "NotesMasters": {
                            History.TurnOff();
                            readNotesMasters();
                            History.TurnOn();
                            break;
                        }
                        case "NotesMastersIndexes": {
                            presentationSelectedContent.NotesMastersIndexes = readIndexes();
                            break;
                        }
                        case "NotesThemes": {
                            readNotesThemes();
                            break;
                        }
                        case "Themes": {
                            readThemes();
                            break;
                        }
                        case "ThemeIndexes": {
                            presentationSelectedContent.ThemeIndexes = readIndexes();
                            break;
                        }
                    }
                }
            }

			if(bIsEmptyContent) {
				presentationSelectedContent = null;
			}

            return {content: presentationSelectedContent, fonts: fonts, images: arr_Images};
        }, this, []);
	},
	
	_pasteFromHtml: function(node, bTurnOffTrackRevisions)
	{
		var oThis = this;
		
		var fPasteHtmlPresentationCallback = function(fonts, images)
		{
			var executePastePresentation = function()
			{
				var oController = presentation.GetCurrentController();
				var targetDocContent =  oController  && oController.getTargetDocContent();
				if(targetDocContent && arrShapes.length === 1 && arrImages.length === 0 && arrTables.length === 0)
				{
                    //не проверяем на лок т. к. это делается в asc_docs_api.prototype.asc_PasteData.
                    // При двух последовательных проверках в совместном редактировании вторая проверка всегда будет возвращать лок
                    var aNewContent = arrShapes[0].Drawing.txBody.content.Content;
                    oThis.InsertInPlacePresentation(aNewContent);
				}
				else
				{
					var presentationSelectedContent = new PresentationSelectedContent();
					presentationSelectedContent.Drawings = arrShapes;

					presentation.Insert_Content(presentationSelectedContent);
					presentation.Recalculate();
					presentation.Check_CursorMoveRight();
					presentation.Document_UpdateInterfaceState();

					oThis._setSpecialPasteShowOptionsPresentation([Asc.c_oSpecialPasteProps.sourceformatting, Asc.c_oSpecialPasteProps.keepTextOnly]);
					window['AscCommon'].g_specialPasteHelper.Paste_Process_End();
				}
			};

			oThis.aContent = [];
			//на время заполнения контента для вставки отключаем историю
			 var arrShapes = [], arrImages = [], arrTables = [];
			var presentation = editor.WordControl.m_oLogicDocument;
			if(presentation.Slides.length === 0)
			{
				presentation.addNextSlide();
			}
			var shape = new CShape();
			shape.setParent(presentation.Slides[presentation.CurPage]);
			shape.setTxBody(AscFormat.CreateTextBodyFromString("", presentation.DrawingDocument, shape));
			arrShapes.push(shape);
			
			oThis._Execute(node, {}, true, true, false, arrShapes, arrImages, arrTables);
			
			//если не добавили даные внутрь arrShapes - удаляем пустой CShape
			if(arrShapes.length === 1 && arrShapes[0].txBody && arrShapes[0].txBody.content && arrShapes[0].txBody.content.Content && arrShapes[0].txBody.content.Content.length === 1)
			{
				var txBodyContent = arrShapes[0].txBody.content.Content[0].Content;
				if(txBodyContent && txBodyContent.length === 2 && txBodyContent[0].Content && txBodyContent[0].Content.length === 0)
				{
					arrShapes = [];
				}
			}	
			
			for(var i = 0; i < arrShapes.length; ++i)
			{
				shape = arrShapes[i];
				
				var txBobyContent = shape.txBody.content.Content;
				if(txBobyContent.length > 1 && txBobyContent[0].Content)
				{
					if(txBobyContent[0].Content.length === 1 || (txBobyContent[0].Content.length === 2 && txBobyContent[0].Content[0].Content && txBobyContent[0].Content[0].Content.length === 0))
					{
						shape.txBody.content.Internal_Content_Remove(0, 1);
					}
				}
				
				var w =  shape.txBody.getRectWidth(presentation.Width*2/3);
				var h = shape.txBody.content.GetSummaryHeight();
				AscFormat.CheckSpPrXfrm(shape);
				shape.spPr.xfrm.setExtX(w);
				shape.spPr.xfrm.setExtY(h);
				shape.spPr.xfrm.setOffX((presentation.Width - w)/2.0);
				shape.spPr.xfrm.setOffY((presentation.Height - h)/2.0);


                var oBodyPr = shape.getBodyPr().createDuplicate();
                oBodyPr.rot = 0;
                oBodyPr.spcFirstLastPara = false;
                oBodyPr.vertOverflow = AscFormat.nOTOwerflow;
                oBodyPr.horzOverflow = AscFormat.nOTOwerflow;
                oBodyPr.vert = AscFormat.nVertTThorz;
                oBodyPr.lIns = 2.54;
                oBodyPr.tIns = 1.27;
                oBodyPr.rIns = 2.54;
                oBodyPr.bIns = 1.27;
                oBodyPr.numCol = 1;
                oBodyPr.spcCol = 0;
                oBodyPr.rtlCol = 0;
                oBodyPr.fromWordArt = false;
                oBodyPr.anchor = 4;
                oBodyPr.anchorCtr = false;
                oBodyPr.forceAA = false;
                oBodyPr.compatLnSpc = true;
                oBodyPr.prstTxWarp = AscFormat.ExecuteNoHistory(function(){return AscFormat.CreatePrstTxWarpGeometry("textNoShape");}, this, []);
                oBodyPr.textFit = new AscFormat.CTextFit();
                oBodyPr.textFit.type = AscFormat.text_fit_Auto;
                shape.txBody.setBodyPr(oBodyPr);
				shape.txBody.content.MoveCursorToEndPos();
				arrShapes[i] = new DrawingCopyObject(shape, 0, 0, w, h);
			}
			
			for(var i = 0; i < arrTables.length; ++i)
			{
				shape = arrTables[i];
			   
				//TODO передалать высоту/ширину!
				//var w =  shape.txBody.getRectWidth(presentation.Width*2/3);
				//var h = shape.txBody.content.GetSummaryHeight();
				var w = 100;
				var h = 100;
				AscFormat.CheckSpPrXfrm(shape);
				shape.spPr.xfrm.setExtX(w);
				shape.spPr.xfrm.setExtY(h);
				shape.spPr.xfrm.setOffX(0);
				shape.spPr.xfrm.setOffY(0);
				
				arrShapes[arrShapes.length] = new DrawingCopyObject(shape, 0, 0, w, h);
			}
			
			for(var i = 0; i < arrImages.length; ++i)
			{
				shape = arrImages[i];

				AscFormat.CheckSpPrXfrm(shape);
				//shape.spPr.xfrm.setExtX(w);
				//shape.spPr.xfrm.setExtY(h);
				shape.spPr.xfrm.setOffX(0);
				shape.spPr.xfrm.setOffY(0);
				
				arrShapes[arrShapes.length] = new DrawingCopyObject(shape, 0, 0, w, h);
			}

			if(!fonts)
			{
				fonts = [];
			}
			if(!images)
			{
				images = [];
			}
			oThis.api.pre_Paste(fonts, images, executePastePresentation);
		};
		
		var fPasteHtmlWordCallback = function(fonts, images)
		{
			var executePasteWord = function()
			{
				if(false === oThis.bNested)
				{
					oThis.InsertInDocument();
				}
				if(bTurnOffTrackRevisions){
					oThis.api.WordControl.m_oLogicDocument.TrackRevisions = true;
				}
			};

			oThis.aContent = [];
			
			//если находимся внутри текстовой области диаграммы, то не вставляем ссылки
			if(oThis.oDocument && oThis.oDocument.Parent && oThis.oDocument.Parent.parent && oThis.oDocument.Parent.parent.parent && oThis.oDocument.Parent.parent.parent.getObjectType && oThis.oDocument.Parent.parent.parent.getObjectType() == AscDFH.historyitem_type_Chart)
			{
				var hyperlinks = node.getElementsByTagName("a");
				if(hyperlinks && hyperlinks.length)
				{
					var newElement;
					for(var i = 0; i < hyperlinks.length; i++)
					{
						newElement = document.createElement("span");

						var cssText = hyperlinks[i].getAttribute('style');
						if(cssText)
							newElement.getAttribute('style', cssText);
						
						$(newElement).append(hyperlinks[i].children);
						
						hyperlinks[i].parentNode.replaceChild(newElement, hyperlinks[i]);
					}
				}
				
				//Todo пока сделал так, чтобы не вставлялись графические объекты в название диаграммы, потом нужно будет сделать так же запутанно, как в MS
				var htmlImages = node.getElementsByTagName("img");
				if(htmlImages && htmlImages.length)
				{
					for(var i = 0; i < htmlImages.length; i++)
					{
						htmlImages[i].parentNode.removeChild(htmlImages[i]);
					}
				}
			}
			if(bTurnOffTrackRevisions){
				oThis.api.WordControl.m_oLogicDocument.TrackRevisions = false;
			}
			//на время заполнения контента для вставки отключаем историю
			oThis._Execute(node, {}, true, true, false);
			oThis._AddNextPrevToContent(oThis.oDocument);

			oThis.api.pre_Paste(fonts, images, executePasteWord);
		};
		
		this.oRootNode = node;

		if(PasteElementsId.g_bIsDocumentCopyPaste)
		{
			this.bIsPlainText = this._CheckIsPlainText(node);

			if(window['AscCommon'].g_specialPasteHelper.specialPasteStart && Asc.c_oSpecialPasteProps.keepTextOnly === window['AscCommon'].g_specialPasteHelper.specialPasteProps)
			{
				fPasteHtmlWordCallback();
			}
			else
			{
				this._Prepeare(node, fPasteHtmlWordCallback);
			}
			
            if(bTurnOffTrackRevisions){
                oThis.api.WordControl.m_oLogicDocument.TrackRevisions = true;
            }
		}
		else
		{
			this.oRootNode = node;
			if(window['AscCommon'].g_specialPasteHelper.specialPasteStart && Asc.c_oSpecialPasteProps.keepTextOnly === window['AscCommon'].g_specialPasteHelper.specialPasteProps)
			{
				fPasteHtmlPresentationCallback();
			}
			else
			{
				this._Prepeare(node, fPasteHtmlPresentationCallback);
			}
		}
	},
	
	_getClassBinaryFromHtml: function(node, onlyBinary)
	{
		var classNode, base64FromExcel = null, base64FromWord = null, base64FromPresentation = null;
		
		if(onlyBinary)
		{
			if(typeof onlyBinary === "object")
			{
				var prefix = String.fromCharCode(onlyBinary[0], onlyBinary[1], onlyBinary[2], onlyBinary[3])

				if("PPTY" === prefix)
				{
					base64FromPresentation = onlyBinary;
				}
				else if("DOCY" === prefix)
				{
					base64FromWord = onlyBinary;
				}
				else if("XLSY" === prefix)
				{
					base64FromExcel = onlyBinary;
				}
			}
			else
			{
				if(onlyBinary.indexOf("pptData;") > -1)
				{
					base64FromPresentation = onlyBinary.split('pptData;')[1];
				}
				else if(onlyBinary.indexOf("docData;") > -1)
				{
					base64FromWord = onlyBinary.split('docData;')[1];
				}
				else if(onlyBinary.indexOf("xslData;") > -1)
				{
					base64FromExcel = onlyBinary.split('xslData;')[1];
				}
			}
		}
		else if(node)
		{
			classNode = searchBinaryClass(node);
			
			if( classNode != null ){
				var cL = classNode.split(" ");
				for (var i = 0; i < cL.length; i++){
					if(cL[i].indexOf("xslData;") > -1)
					{
						base64FromExcel = cL[i].split('xslData;')[1];
					}
					else if(cL[i].indexOf("docData;") > -1)
					{
						base64FromWord = cL[i].split('docData;')[1];
					}
					else if(cL[i].indexOf("pptData;") > -1)
					{
						base64FromPresentation = cL[i].split('pptData;')[1];
					}
				}
			}
		}
			
		return {base64FromExcel: base64FromExcel, base64FromWord: base64FromWord, base64FromPresentation: base64FromPresentation};
	},

	_pasteText: function (text) {
		var oThis = this;

		var fPasteTextWordCallback = function () {
			var executePasteWord = function () {
				if (false === oThis.bNested) {
					oThis.InsertInDocument();
				}
			};

			oThis.aContent = [];
			oThis._getContentFromText(text, true);
			oThis._AddNextPrevToContent(oThis.oDocument);

			oThis.api.pre_Paste([], [], executePasteWord);
		};

		var fPasteTextPresentationCallback = function () {
			var executePastePresentation = function () {
				oThis.InsertInPlacePresentation(oThis.aContent, true);
			};

			var presentation = editor.WordControl.m_oLogicDocument;
			if (presentation.Slides.length === 0) {
				presentation.addNextSlide();
			}
			var shape = new CShape();
			shape.setParent(presentation.Slides[presentation.CurPage]);
			shape.setTxBody(AscFormat.CreateTextBodyFromString("", presentation.DrawingDocument, shape));
			oThis.aContent = shape.txBody.content.Content;

			text = text.replace(/^(\r|\t)+|(\r|\t)+$/g, '');
			//text = text.replace(/(\r|\t)/g, ' ');
			if (text.length > 0) {
				oThis.oDocument = shape.txBody.content;

				var bAddParagraph = false;
				for (var oIterator = text.getUnicodeIterator(); oIterator.check(); oIterator.next()) {
					if (bAddParagraph) {
						shape.txBody.content.AddNewParagraph();
						bAddParagraph = false;
					}

					var nUnicode = oIterator.value();

					if (null !== nUnicode && 13 !== nUnicode) {
						var Item;
						if (0x0A === nUnicode || 0x0D === nUnicode) {
							bAddParagraph = true;
						} else if (0x09 === nUnicode) {
							Item = new ParaTab();
							shape.paragraphAdd(Item, false);
						} else if (0x20 !== nUnicode && 0xA0 !== nUnicode && 0x2009 !== nUnicode) {
							Item = new ParaText(nUnicode);
							shape.paragraphAdd(Item, false);
						} else {
							Item = new ParaSpace();
							shape.paragraphAdd(Item, false);
						}
					}
				}
			}

			var oTextPr = presentation.GetCalculatedTextPr();
			shape.txBody.content.Set_ApplyToAll(true);
			var paraTextPr = new AscCommonWord.ParaTextPr(oTextPr);
			shape.txBody.content.AddToParagraph(paraTextPr);
			shape.txBody.content.Set_ApplyToAll(false);

			oThis.api.pre_Paste([], [], executePastePresentation);
		};

		if (PasteElementsId.g_bIsDocumentCopyPaste) {
			fPasteTextWordCallback();
		} else {
			fPasteTextPresentationCallback();
		}
	},

	_getContentFromText: function(text, getStyleCurSelection){
		var t = this;
		var Count = text.length;

		var pasteIntoParagraphPr = this.oDocument.GetDirectParaPr();
		var pasteIntoParaRunPr = this.oDocument.GetDirectTextPr();
        var bPresentation = false;
        var oCurParagraph = this.oDocument.GetCurrentParagraph();
        var Parent = t.oDocument;
        if(oCurParagraph && !oCurParagraph.bFromDocument)
        {
            bPresentation = true;
            Parent = oCurParagraph.Parent;
        }

		var getNewParagraph = function(){
			var paragraph = new Paragraph(t.oDocument.DrawingDocument, Parent, bPresentation);
			var copyParaPr;
			if(getStyleCurSelection){
				if(pasteIntoParagraphPr)
				{
					copyParaPr = pasteIntoParagraphPr.Copy();
					copyParaPr.NumPr = undefined;
					paragraph.Set_Pr(copyParaPr);

					if(paragraph.TextPr && pasteIntoParaRunPr)
					{
						paragraph.TextPr.Value = pasteIntoParaRunPr.Copy();
					}
				}
			}
			return paragraph;
		};

		var getNewParaRun = function(){
			var paraRun = new ParaRun();
			if(getStyleCurSelection){
				if(pasteIntoParaRunPr && paraRun.Set_Pr)
				{
					paraRun.Set_Pr( pasteIntoParaRunPr.Copy() );
				}
			}
			return paraRun;
		};

		var newParagraph = getNewParagraph();
		var insertText = "";

		for (var oIterator = text.getUnicodeIterator(); oIterator.check(); oIterator.next()) {
			var pos = oIterator.position();
			var _char = text.charAt(pos);
			var _charCode = oIterator.value();
			var newParaRun;
			if(0x0A === _charCode ||  pos === Count - 1){
				if(pos === Count - 1 && 0x0A !== _charCode){
					insertText += _char;
				}
				
				newParaRun = getNewParaRun();
				addTextIntoRun(newParaRun, insertText);
				newParagraph.Internal_Content_Add(newParagraph.Content.length - 1, newParaRun, false);
				this.aContent.push(newParagraph);

				insertText = "";
				newParagraph = getNewParagraph();
			} else if(insertText.length === Asc.c_dMaxParaRunContentLength){//max run length
				insertText += _char;
				newParaRun = getNewParaRun();
				addTextIntoRun(newParaRun, insertText);
				newParagraph.Internal_Content_Add(newParagraph.Content.length - 1, newParaRun, false);
				insertText = "";
			} else if(13 === _charCode){
				continue;
			} else {
				insertText += _char;
			}
		}
	},

	_isParagraphContainsOnlyDrawing: function(par)
	{
		var res = true;
		
		if(par.Content)
		{
			for(var i = 0; i < par.Content.length; i++)
			{	
				if(par.Content[i] && par.Content[i].Content && par.Content[i].Content.length)
				{
					for(var j = 0; j < par.Content[i].Content.length; j++)
					{
						var elem = par.Content[i].Content[j]; 
						if(!(para_Drawing === elem.Get_Type() || para_End === elem.Get_Type()))
						{
							res = false;
						}
					}
				}
			}
		}
		
		return res;
	},
	
	_convertExcelBinary: function(aContentExcel, pDrawings)
	{
		//пока только распознаём только графические объекты
		var aContent = null, tempParagraph = null;
		var imageUrl, isGraphicFrame, extX, extY;
		var fonts = null;
		
		var drawings = pDrawings ? pDrawings : aContentExcel.workbook.aWorksheets[0].Drawings;
		if(drawings && drawings.length)
		{
			var drawing, graphicObj, paraRun, tempParaRun;
			
			aContent = [];
			
			var font_map = {};
			//из excel в word они вставляются в один параграф
			for(var i = 0; i < drawings.length; i++)
			{
				drawing = drawings[i] && drawings[i].Drawing ? drawings[i].Drawing : drawings[i];
				
				//TODO нужна отдельная обработка для таблиц из презентаций
				isGraphicFrame = typeof CTable !== "undefined" && drawing.graphicObject instanceof CTable;
				if(isGraphicFrame && drawings.length > 1 && drawings[i].base64)//если кроме таблички(при вставке из презентаций) содержатся ещё данные, вставляем в виде base64
				{
					if(!tempParagraph)
						tempParagraph = new Paragraph(this.oDocument.DrawingDocument, this.oDocument);
					
					extX = drawings[i].ExtX;
					extY = drawings[i].ExtY;
					imageUrl = drawings[i].base64;
					
					graphicObj = AscFormat.DrawingObjectsController.prototype.createImage(imageUrl, 0, 0, extX, extY);	
					
					tempParaRun = new ParaRun();
					tempParaRun.Paragraph = null;
					tempParaRun.Add_ToContent( 0, new ParaDrawing(), false );

					tempParaRun.Content[0].Set_GraphicObject(graphicObj);
					tempParaRun.Content[0].GraphicObj.setParent(tempParaRun.Content[0]);
					tempParaRun.Content[0].CheckWH();
					
					tempParagraph.Content.splice(tempParagraph.Content.length - 1, 0, tempParaRun);
				}
				else if(isGraphicFrame)
				{
                    drawing.setBDeleted(true);
                    drawing.setWordFlag(false);
					var copyObj = drawing.graphicObject.Copy();
					copyObj.Set_Parent(this.oDocument);
					aContent[aContent.length] = copyObj;
                    drawing.setWordFlag(true);
					
					drawing.getAllFonts(font_map);
				}
				else
				{
					if(!tempParagraph)
						tempParagraph = new Paragraph(this.oDocument.DrawingDocument, this.oDocument);
					
					extX = drawings[i].ExtX;
					extY = drawings[i].ExtY;
					
					drawing.getAllFonts(font_map);
					graphicObj = drawing.graphicObject ? drawing.graphicObject.convertToWord(this.oLogicDocument) : drawing.convertToWord(this.oLogicDocument);
					
					tempParaRun = new ParaRun();
					tempParaRun.Paragraph = null;
					tempParaRun.Add_ToContent( 0, new ParaDrawing(), false );
					
					tempParaRun.Content[0].Set_GraphicObject(graphicObj);
					tempParaRun.Content[0].GraphicObj.setParent(tempParaRun.Content[0]);
                    var oGraphicObj = tempParaRun.Content[0].GraphicObj;
                    if(oGraphicObj.spPr && oGraphicObj.spPr.xfrm)
                    {
                        oGraphicObj.spPr.xfrm.setOffX(0);
                        oGraphicObj.spPr.xfrm.setOffY(0);
                    }
					tempParaRun.Content[0].CheckWH();
					
					tempParagraph.Content.splice(tempParagraph.Content.length - 1, 0, tempParaRun);
				}		
			}
			
			fonts = [];
			for(var i in font_map)
			{
				fonts.push(new CFont(i, 0, "", 0));
			}
			
			if(tempParagraph)
				aContent[aContent.length] = tempParagraph;
		}
		else
		{
		    if(!this.oDocument.bPresentation)
            {
                fonts = this._convertTableFromExcel(aContentExcel);
            }
            else
            {
                fonts = this._convertTableFromExcelForChartTitle(aContentExcel);
            }
            aContent = this.aContent;
        }
		
		return {content: aContent, fonts: fonts};
	},

	_convertTableFromExcel: function (aContentExcel) {
		var worksheet = aContentExcel.workbook.aWorksheets[0];
		var range;
		var tempActiveRef = aContentExcel.activeRange;
		var activeRange = AscCommonExcel.g_oRangeCache.getAscRange(tempActiveRef);
		var t = this;
		var fonts = [];

		var charToMM = function (mcw) {
			var maxDigitWidth = 7;
			var px = Asc.floor(((256 * mcw + Asc.floor(128 / maxDigitWidth)) / 256) * maxDigitWidth);
			return px * g_dKoef_pix_to_mm;
		};

		var convertBorder = function (border) {
			var res = new CDocumentBorder();
			if (border.w) {
				res.Value = border_Single;
				res.Size = border.w * g_dKoef_pix_to_mm;
			}
			res.Color = new CDocumentColor(border.c.getR(), border.c.getG(), border.c.getB());

			return res;
		};

		var addFont = function (fontFamily) {
			if (!t.aContent.fonts) {
				t.aContent.fonts = [];
			}

			if (!t.oFonts) {
				t.oFonts = [];
			}

			t.oFonts[fontFamily] = {Name: fontFamily, Index: -1};
			fonts.push(new CFont(fontFamily, 0, "", 0));
		};

		//grid
		var grid = [];
		var standardWidth = 9;
		for (var i = activeRange.c1; i <= activeRange.c2; i++) {
			if (worksheet.aCols[i]) {
				grid[i - activeRange.c1] = charToMM(worksheet.aCols[i].width);
			} else {
				grid[i - activeRange.c1] = charToMM(standardWidth);
			}
		}

		var table;
		if(editor.WordControl.m_oLogicDocument && editor.WordControl.m_oLogicDocument.Slides) {
			table = this._createNewPresentationTable(grid);
			table.Set_TableStyle(editor.WordControl.m_oLogicDocument.DefaultTableStyleId)
		} else {
			table = new CTable(this.oDocument.DrawingDocument, this.oDocument, true, 0, 0, grid);
		}

		this.aContent.push(table);

		var diffRow = activeRange.r2 - activeRange.r1;
		var diffCol = activeRange.c2 - activeRange.c1;
		for (var i = 0; i <= diffRow; i++) {
			var row = table.Internal_Add_Row(table.Content.length, 0);
			var heightRowPt = worksheet.getRowHeight(i + activeRange.r1);
			row.SetHeight(heightRowPt * g_dKoef_pt_to_mm, linerule_AtLeast);

			for (var j = 0; j <= diffCol; j++) {
				if (!table.Selection.Data) {
					table.Selection.Data = [];
				}

				table.Selection.Data[table.Selection.Data.length] = {Cell: j, Row: i};

				range = worksheet.getCell3(i + activeRange.r1, j + activeRange.c1);
				var oCurCell = row.Add_Cell(row.Get_CellsCount(), row, null, false);

				table.CurCell = oCurCell;

				var isMergedCell = range.hasMerged();
				var gridSpan = 1;
				var vMerge = 1;
				if (isMergedCell) {
					gridSpan = isMergedCell.c2 - isMergedCell.c1 + 1;
					vMerge = isMergedCell.r2 - isMergedCell.r1 + 1;
				}

				//***cell property***
				//set grid
				var sumWidthGrid = 0;
				for (var l = 0; l < gridSpan; l++) {
					sumWidthGrid += grid[j + l];
				}
				oCurCell.Set_W(new CTableMeasurement(tblwidth_Mm, sumWidthGrid));

				//margins
				//left
				oCurCell.Set_Margins({W : 0, Type : tblwidth_Mm}, 3);
				//right
				oCurCell.Set_Margins({W : 0, Type : tblwidth_Mm}, 1);
				//top
				oCurCell.Set_Margins({W : 0, Type : tblwidth_Mm}, 0);
				//bottom
				oCurCell.Set_Margins({W : 0, Type : tblwidth_Mm}, 2);

				//background color
				var background_color = range.getFill();
				if (null != background_color) {
					var Shd = new CDocumentShd();
					Shd.Value = c_oAscShdClear;
					Shd.Color =
						new CDocumentColor(background_color.getR(), background_color.getG(), background_color.getB());
					oCurCell.Set_Shd(Shd);
				}

				//borders
				var borders = range.getBorderFull();
				//left
				var border = convertBorder(borders.l);
				if (null != border) {
					oCurCell.Set_Border(border, 3);
				}
				//top
				border = convertBorder(borders.t);
				if (null != border) {
					oCurCell.Set_Border(border, 0);
				}
				//right
				border = convertBorder(borders.r);
				if (null != border) {
					oCurCell.Set_Border(border, 1);
				}
				//bottom
				border = convertBorder(borders.b);
				if (null != border) {
					oCurCell.Set_Border(border, 2);
				}

				//merge				
				oCurCell.Set_GridSpan(gridSpan);
				if (vMerge != 1) {
					if (isMergedCell.r1 === i + activeRange.r1) {
						oCurCell.SetVMerge(vmerge_Restart);
					} else {
						oCurCell.SetVMerge(vmerge_Continue);
					}
				}

				var oCurPar = oCurCell.Content.Content[0];

				var hyperLink = range.getHyperlink();
				var oCurHyperlink = null;
				if (hyperLink) {
					oCurHyperlink = new ParaHyperlink();
					oCurHyperlink.SetParagraph(this.oCurPar);
					oCurHyperlink.Set_Value(hyperLink.Hyperlink);
					if (hyperLink.Tooltip) {
						oCurHyperlink.SetToolTip(hyperLink.Tooltip);
					}
				}

				var value2 = range.getValue2();
				for (var n = 0; n < value2.length; n++) {
					var oCurRun = new ParaRun(oCurPar);
					var format = value2[n].format;

					//***text property***
					oCurRun.Pr.Bold = format.getBold();
					var fc = format.getColor();
					if (fc) {
						oCurRun.Pr.Color = new CDocumentColor(fc.getR(), fc.getG(), fc.getB());
					}

					//font					
					var font_family = format.getName();
					addFont(font_family);
					oCurRun.Pr.FontFamily = font_family;
					var oFontItem = this.oFonts[font_family];
					if (null != oFontItem && null != oFontItem.Name) {
						oCurRun.Pr.RFonts.Ascii = {Name: oFontItem.Name, Index: oFontItem.Index};
						oCurRun.Pr.RFonts.HAnsi = {Name: oFontItem.Name, Index: oFontItem.Index};
						oCurRun.Pr.RFonts.CS = {Name: oFontItem.Name, Index: oFontItem.Index};
						oCurRun.Pr.RFonts.EastAsia = {Name: oFontItem.Name, Index: oFontItem.Index};
					}

					oCurRun.Pr.FontSize = format.getSize();
					oCurRun.Pr.Italic = format.getItalic();
					oCurRun.Pr.Strikeout = format.getStrikeout();
					oCurRun.Pr.Underline = format.getUnderline() !== 2;

					//text
					var value = value2[n].text;
					for (var oIterator = value.getUnicodeIterator(); oIterator.check(); oIterator.next()) {
						var nUnicode = oIterator.value();

						var Item;
						if (0x20 !== nUnicode && 0xA0 !== nUnicode && 0x2009 !== nUnicode) {
							Item = new ParaText(nUnicode);
						} else {
							Item = new ParaSpace();
						}

						//add text
						oCurRun.AddToContent(-1, Item, false);
					}

					//add run
					if (oCurHyperlink) {
						oCurHyperlink.Add_ToContent(n, oCurRun, false);
					} else {
						oCurPar.Internal_Content_Add(n, oCurRun, false);
					}
				}

				if (oCurHyperlink) {
					oCurPar.Internal_Content_Add(n, oCurHyperlink, false);
				}

				j = j + gridSpan - 1;
			}
		}

		return fonts;
	},

	_convertTableFromExcelForChartTitle: function (aContentExcel) {
		var worksheet = aContentExcel.workbook.aWorksheets[0];
		var range;
		var tempActiveRef = aContentExcel.activeRange;
		var activeRange = AscCommonExcel.g_oRangeCache.getAscRange(tempActiveRef);
		var t = this;
		var fonts = [];

		var addFont = function (fontFamily) {
			if (!t.aContent.fonts) {
				t.aContent.fonts = [];
			}

			if (!t.oFonts) {
				t.oFonts = [];
			}

			t.oFonts[fontFamily] = {Name: fontFamily, Index: -1};
			fonts.push(new CFont(fontFamily, 0, "", 0));
		};

		var paragraph = new Paragraph(this.oDocument.DrawingDocument, this.oDocument, true);
		this.aContent.push(paragraph);

		var diffRow = activeRange.r2 - activeRange.r1;
		var diffCol = activeRange.c2 - activeRange.c1;
		for (var i = 0; i <= diffRow; i++) {
			for (var j = 0; j <= diffCol; j++) {
				range = worksheet.getCell3(i + activeRange.r1, j + activeRange.c1);
				var isMergedCell = range.hasMerged();
				var gridSpan = 1;
				var vMerge = 1;
				if (isMergedCell) {
					gridSpan = isMergedCell.c2 - isMergedCell.c1 + 1;
					vMerge = isMergedCell.r2 - isMergedCell.r1 + 1;
				}

				var hyperLink = range.getHyperlink();
				var oCurHyperlink = null;
				if (hyperLink) {
					oCurHyperlink = new ParaHyperlink();
					oCurHyperlink.SetParagraph(paragraph);
					oCurHyperlink.Set_Value(hyperLink.Hyperlink);
					if (hyperLink.Tooltip) {
						oCurHyperlink.SetToolTip(hyperLink.Tooltip);
					}
				}

				var value2 = range.getValue2();
				for (var n = 0; n < value2.length; n++) {
					var oCurRun = new ParaRun(paragraph);
					var format = value2[n].format;

					//***text property***
					oCurRun.Pr.Bold = format.getBold();
					var fc = format.getColor();
					if (fc) {
						oCurRun.Set_Unifill(AscFormat.CreateUnfilFromRGB(fc.getR(), fc.getG(), fc.getB()), true);
					}

					//font
					var font_family = format.getName();
					addFont(font_family);
					var oFontItem = this.oFonts[font_family];
					if (null != oFontItem && null != oFontItem.Name) {
						oCurRun.Set_RFonts_Ascii({Name: oFontItem.Name, Index: oFontItem.Index});
						oCurRun.Set_RFonts_HAnsi({Name: oFontItem.Name, Index: oFontItem.Index});
						oCurRun.Set_RFonts_CS({Name: oFontItem.Name, Index: oFontItem.Index});
						oCurRun.Set_RFonts_EastAsia({Name: oFontItem.Name, Index: oFontItem.Index});
					}

					oCurRun.Set_FontSize(format.getSize());
					oCurRun.Set_Italic(format.getItalic());
					oCurRun.Set_Strikeout(format.getStrikeout());
					oCurRun.Set_Underline(format.getUnderline() !== 2 ? true : false);

					//text
					var value = value2[n].text;
					for (var oIterator = value.getUnicodeIterator(); oIterator.check(); oIterator.next()) {
						var nUnicode = oIterator.value();

						var Item;
						if (0x20 !== nUnicode && 0xA0 !== nUnicode && 0x2009 !== nUnicode) {
							Item = new ParaText(nUnicode);
						} else {
							Item = new ParaSpace();
						}

						//add text
						oCurRun.AddToContent(-1, Item, false);
					}

					if (i !== diffRow || j !== diffCol) {
						oCurRun.Add_ToContent(oIterator.position(), new ParaSpace(), false);
					}

					//add run
					if (oCurHyperlink) {
						oCurHyperlink.Add_ToContent(n, oCurRun, false);
					} else {
						paragraph.Internal_Content_Add(paragraph.Content.length - 1, oCurRun, false);
					}
				}

				if (oCurHyperlink) {
					paragraph.Internal_Content_Add(paragraph.Content.length - 1, oCurHyperlink, false);
				}

				j = j + gridSpan - 1;
			}
		}

		return fonts;
	},

	_convertTableToPPTX: function(table, isFromWord)
	{
		//TODO пересмотреть обработку для вложенных таблиц(можно сделать так, как при копировании из документов в таблицы)
        var oTable = AscFormat.ExecuteNoHistory(function(){
            var allRows = [];
            this.maxTableCell = 0;
			
			if(isFromWord)
			{
				table = this._replaceInnerTables(table, allRows, true);
			}
            
            //ковертим внутренние параграфы
            table.bPresentation = true;
            for(var i = 0; i < table.Content.length; i++)
            {
                for(var j = 0; j < table.Content[i].Content.length; j++)
                {
                    var cDocumentContent = table.Content[i].Content[j].Content;
                    cDocumentContent.bPresentation = true;
                    var nIndex = 0;
                    for(var n = 0; n < cDocumentContent.Content.length; n++)
                    {
                        if(cDocumentContent.Content[n] instanceof Paragraph)
                        {
                            cDocumentContent.Content[nIndex] = AscFormat.ConvertParagraphToPPTX(cDocumentContent.Content[nIndex], null, null, true, false);
                            ++nIndex;
                        }

                    }
                }
            }
            table.SetTableLayout(tbllayout_Fixed);
            return table;
        }, this, []);
        return oTable;
	},
	
	_replaceInnerTables: function(table, allRows, isRoot)
	{
		//заменяем внутренние таблички
		for(var i = 0; i < table.Content.length; i++)
		{
			allRows[allRows.length] = table.Content[i];
			
			if(this.maxTableCell < table.Content[i].Content.length)
				this.maxTableCell = table.Content[i].Content.length;
			
			for(var j = 0; j < table.Content[i].Content.length; j++)
			{
				var cDocumentContent = table.Content[i].Content[j].Content;
				cDocumentContent.bPresentation = true;
				
				var k = 0;
				for(var n = 0; n < cDocumentContent.Content.length; n++)
				{
					//если нашли внутреннюю табличку
					if(cDocumentContent.Content[n] instanceof CTable)
					{
						this._replaceInnerTables(cDocumentContent.Content[n], allRows);
						cDocumentContent.Content.splice(n, 1);
						n--;
					}
				}
			}
		}
		
		//дополняем пустыми ячейками, строки, где ячеек меньше
		if(isRoot === true)
		{
			for(var row = 0; row < allRows.length; row++)
			{
				var cells = allRows[row].Content;
				if(cells.length < this.maxTableCell)
				{
					for(var cell = cells.length; cell < this.maxTableCell; cell++)
					{
						allRows[row].Add_Cell(allRows[row].Get_CellsCount(), allRows[row], null, false);
					}
				}
			}
			
			table.Content = allRows;
			table.Rows = allRows.length;
		}
		
		return table;
	},

	_createNewPresentationTable: function (grid) {
		var presentation = editor.WordControl.m_oLogicDocument;
		var graphicFrame = new CGraphicFrame(presentation.Slides[presentation.CurPage]);
		var table = new CTable(this.oDocument.DrawingDocument, graphicFrame, true, 0, 0, grid, true);
        table.SetTableLayout(tbllayout_Fixed);
		graphicFrame.setGraphicObject(table);
		graphicFrame.setNvSpPr(new AscFormat.UniNvPr());

		return table;
	},

	_getImagesFromExcelShapes: function(aDrawings, aSpTree, aPastedImages, aUrls)
	{
		//пока только распознаём только графические объекты
		var sImageUrl, nDrawingsCount, oGraphicObj, bDrawings;
        if(Array.isArray(aDrawings))
        {
            nDrawingsCount = aDrawings.length;
            bDrawings = true;
        }
        else if(Array.isArray(aSpTree))
        {
            nDrawingsCount = aSpTree.length;
            bDrawings = false;
        }
        else
        {
            return;
        }
        for(var i = 0; i < nDrawingsCount; i++)
        {
            if(bDrawings)
            {
                oGraphicObj = aDrawings[i].graphicObject;
            }
            else
            {
                oGraphicObj = aSpTree[i];
            }
            if(oGraphicObj)
            {
                if(oGraphicObj.spPr)
                {
                    if(oGraphicObj.spPr.Fill && oGraphicObj.spPr.Fill.fill && typeof oGraphicObj.spPr.Fill.fill.RasterImageId === "string" && oGraphicObj.spPr.Fill.fill.RasterImageId.length > 0)
                    {
                        sImageUrl = oGraphicObj.spPr.Fill.fill.RasterImageId;
                        aPastedImages[aPastedImages.length] = new AscCommon.CBuilderImages(oGraphicObj.spPr.Fill.fill, sImageUrl, null, oGraphicObj.spPr, null);
                        aUrls[aUrls.length] = sImageUrl;
                    }
                    if(oGraphicObj.spPr.ln && oGraphicObj.spPr.ln.Fill && oGraphicObj.spPr.ln.Fill.fill && typeof oGraphicObj.spPr.ln.Fill.fill.RasterImageId === "string" && oGraphicObj.spPr.ln.Fill.fill.RasterImageId.length > 0)
                    {
                        sImageUrl = oGraphicObj.spPr.ln.Fill.fill.RasterImageId;
                        aPastedImages[aPastedImages.length] = new AscCommon.CBuilderImages(oGraphicObj.spPr.ln.Fill.fill, sImageUrl, null, oGraphicObj.spPr, oGraphicObj.spPr.ln.Fill.fill.RasterImageId);
                        aUrls[aUrls.length] = sImageUrl;
                    }
                }
                switch(oGraphicObj.getObjectType())
                {
                    case AscDFH.historyitem_type_ImageShape:
                    {
                        sImageUrl = oGraphicObj.getImageUrl();
                        if(typeof sImageUrl === "string" && sImageUrl.length > 0)
                        {
                            aPastedImages[aPastedImages.length] = new AscCommon.CBuilderImages(oGraphicObj.blipFill, sImageUrl, oGraphicObj, null, null);
                            aUrls[aUrls.length] = sImageUrl;
                        }
                        break;
                    }
                    case AscDFH.historyitem_type_Shape:
                    {
                        break;
                    }
                    case AscDFH.historyitem_type_ChartSpace:
                    {
                        break;
                    }
                    case AscDFH.historyitem_type_GroupShape:
                    {
                        this._getImagesFromExcelShapes(null, oGraphicObj.spTree, aPastedImages, aUrls);
                        break;
                    }
                }
            }
        }
	},

	_selectShapesBeforeInsert: function(aNewContent, oDoc)
	{
		var content, drawingObj, allDrawingObj = [];
		for(var i = 0; i < aNewContent.length; i++)
		{
			content = aNewContent[i];
			drawingObj = content.GetAllDrawingObjects();
			
			if(!drawingObj || (drawingObj && !drawingObj.length) || content.GetType() === type_Table)
			{
				allDrawingObj = null;
				break;
			}
			
			for(var n = 0; n < drawingObj.length; n++)
			{
				allDrawingObj[allDrawingObj.length] = drawingObj[n];
			}
		}
		
		if(allDrawingObj && allDrawingObj.length)
            this.oLogicDocument.Select_Drawings(allDrawingObj, oDoc);
	},
	
	_readFromBinaryExcel: function(base64)
	{
		var oBinaryFileReader = new AscCommonExcel.BinaryFileReader(true);
		var tempWorkbook = new AscCommonExcel.Workbook();
        tempWorkbook.theme = this.oDocument.theme ? this.oDocument.theme : this.oLogicDocument.theme;
		if(!tempWorkbook.theme && this.oLogicDocument.Get_Theme)
			tempWorkbook.theme = this.oLogicDocument.Get_Theme();

		Asc.getBinaryOtherTableGVar(tempWorkbook);
		
		pptx_content_loader.Start_UseFullUrl();
        pptx_content_loader.Reader.ClearConnectorsMaps();
		oBinaryFileReader.Read(base64, tempWorkbook);
        pptx_content_loader.Reader.AssignConnectorsId();

		if(!tempWorkbook.aWorksheets.length) {
			return null;
		}

		return {workbook: tempWorkbook, activeRange: oBinaryFileReader.copyPasteObj.activeRange, arrImages: pptx_content_loader.End_UseFullUrl()};
	},
	
    ReadPresentationText: function(stream)
    {
        var loader = new AscCommon.BinaryPPTYLoader();
        loader.Start_UseFullUrl();
        loader.stream = stream;
        loader.presentation = editor.WordControl.m_oLogicDocument;
        var presentation = editor.WordControl.m_oLogicDocument;
		
		var shape;
		if(presentation.Slides)
			shape = new CShape(presentation.Slides[presentation.CurPage]);
		else	
			shape = new CShape(presentation);
		
        shape.setTxBody(new AscFormat.CTextBody(shape));
		
        var count = stream.GetULong() / 100000;
		
		//читаем контент, здесь только параграфы
		var newDocContent = new AscFormat.CDrawingDocContent(shape.txBody, editor.WordControl.m_oDrawingDocument, 0 , 0, 0, 0, false, false);
		var elements = [], paragraph, selectedElement;
        for(var i = 0; i < count; ++i)
        {
            loader.stream.Skip2(1); // must be 0
			paragraph = loader.ReadParagraph(newDocContent);
			
			//FONTS
			paragraph.Document_Get_AllFontNames(this.oFonts);
			
			selectedElement = new CSelectedElement();
			selectedElement.Element = paragraph;
			elements.push(selectedElement);
        }
        return elements;
    },

    ReadPresentationShapes: function(stream)
    {
        var loader = new AscCommon.BinaryPPTYLoader();
        loader.Start_UseFullUrl();
        loader.ClearConnectorsMaps();
		pptx_content_loader.Reader.Start_UseFullUrl();
		
        loader.stream = stream;
        loader.presentation = editor.WordControl.m_oLogicDocument;
        var presentation = editor.WordControl.m_oLogicDocument;
        var count = stream.GetULong();
        var arr_shapes = [];
        var arr_transforms = [];
		var cStyle;
		var foundTableStylesIdMap = {};
		
        for(var i = 0; i < count; ++i)
        {
            loader.TempMainObject = presentation && presentation.Slides ? presentation.Slides[presentation.CurPage] : presentation;
            var style_index = null;
			
			//читаем флаг о наличии табличного стиля
            if(!loader.stream.GetBool())
            {
                if(loader.stream.GetBool())
                {
					loader.stream.Skip2(1);
					cStyle = loader.ReadTableStyle(true);
					
					loader.stream.GetBool();
					style_index = stream.GetString2();
                }
            }
            
			var drawing = loader.ReadGraphicObject();
			
			//для случая, когда копируем 1 таблицу из презентаций, в бинарник заносим ещё одну такую же табличку, но со скомпилированными стилями(для вставки в word/excel)
			if(count === 1 && typeof AscFormat.CGraphicFrame !== "undefined" && drawing instanceof AscFormat.CGraphicFrame)
			{
				//в презентациях пропускаю чтение ещё раз графического объекта
				if(presentation.Slides)
				{
					loader.stream.Skip2(1);
					loader.stream.SkipRecord();
				}
				else
				{
					drawing = loader.ReadGraphicObject();
				}
			}
			
            var x = stream.GetULong()/100000;
            var y = stream.GetULong()/100000;
            var extX = stream.GetULong()/100000;
            var extY = stream.GetULong()/100000;
			var base64 = stream.GetString2();
			
			if(presentation.Slides)
				arr_shapes[i] = new DrawingCopyObject();
			else
				arr_shapes[i] = {};

			arr_shapes[i].Drawing = drawing;
			arr_shapes[i].X = x;
			arr_shapes[i].Y = y;
			arr_shapes[i].ExtX = extX;
			arr_shapes[i].ExtY = extY;
			if(!presentation.Slides)
				arr_shapes[i].base64 = base64;
			
			if(style_index != null && arr_shapes[i].Drawing.graphicObject && arr_shapes[i].Drawing.graphicObject.Set_TableStyle)
			{
				if(!PasteElementsId.g_bIsDocumentCopyPaste)
				{
					//TODO продумать добавления нового стиля(ReadTableStyle->получуть id нового стиля, сравнить новый стиль со всеми присутвующими.если нет - добавить и сделать Set_TableStyle(id))
					if(foundTableStylesIdMap[style_index])
					{
						arr_shapes[i].Drawing.graphicObject.Set_TableStyle(foundTableStylesIdMap[style_index], true);
					}
					else if(cStyle && presentation.globalTableStyles && presentation.globalTableStyles.Style)
					{
						var isFoundStyle = false;
						for(var j in presentation.globalTableStyles.Style)
						{
							//TODO isEqual - сравнивает ещё и имя стиля. для случая, когда одинаковый контент, но имя стиля разное, не подойдет это сравнение
							if(presentation.globalTableStyles.Style[j].isEqual(cStyle))
							{
								arr_shapes[i].Drawing.graphicObject.Set_TableStyle(j, true);
								foundTableStylesIdMap[style_index] = j;
								isFoundStyle = true;
								break;
							}
						}
						
						//в данном случае добавляем новый стиль
						if(!isFoundStyle)
						{
							//TODO при добавлении нового стиля - падение. пересмотреть!
							/*var newIndexStyle = presentation.globalTableStyles.Add(cStyle);
							presentation.TableStylesIdMap[newIndexStyle] = true;
							arr_shapes[i].Drawing.graphicObject.Set_TableStyle(newIndexStyle, true);
							foundTableStylesIdMap[style_index] = newIndexStyle;*/
						}
					}
					else if(presentation.TableStylesIdMap[style_index])
					{
						arr_shapes[i].Drawing.graphicObject.Set_TableStyle(style_index, true);
					}
				}	
				else if(cStyle)
				{
					//пока не применяем стили, посольку они отличаются
					//this._applyStylesToTable(arr_shapes[i].Drawing.graphicObject, cStyle);
				}
			}
        }

		var chartImages = pptx_content_loader.Reader.End_UseFullUrl();
		var images = loader.End_UseFullUrl();
        loader.AssignConnectorsId();
		var allImages = chartImages.concat(images);
		
        return {arrShapes: arr_shapes, arrImages: allImages, arrTransforms: arr_transforms};
    },

    ReadPresentationSlides: function(stream)
    {
        var loader = new AscCommon.BinaryPPTYLoader();
        loader.Start_UseFullUrl();
        loader.stream = stream;
        loader.presentation = editor.WordControl.m_oLogicDocument;
        var presentation = editor.WordControl.m_oLogicDocument;
        var count = stream.GetULong();
        var arr_slides = [];
		var slide;
        for(var i = 0; i < count; ++i)
        {
            loader.ClearConnectorsMaps();
			slide = loader.ReadSlide(0);
            loader.AssignConnectorsId();
			arr_slides.push(slide);
        }
        return arr_slides;
    },


    ReadSlide: function(stream)
    {
        var loader = new AscCommon.BinaryPPTYLoader();
        loader.Start_UseFullUrl();
        loader.stream = stream;
        loader.presentation = editor.WordControl.m_oLogicDocument;
        var presentation = editor.WordControl.m_oLogicDocument;
        return loader.ReadSlide(0);
    },

    _Prepeare : function(node, fCallback)
    {
		var oThis = this;
        if(true === this.bUploadImage || true === this.bUploadFonts)
        {
			//Пробегаемся по документу собираем список шрифтов и картинок.
            var aPrepeareFonts = this._Prepeare_recursive(node, true, true);

			//TODO пересмотреть все "local" и сделать одинаковые проверки во всех редакторах
			var aImagesToDownload = [];
			var _mapLocal = {};
			for(var image in this.oImages)
            {
				var src = this.oImages[image];
				if (undefined !== window["Native"] && undefined !== window["Native"]["GetImageUrl"])
				{
					this.oImages[image] = window["Native"]["GetImageUrl"](this.oImages[image]);
				}
				else if(0 === src.indexOf("file:") && window["AscDesktopEditor"] !== undefined)
				{
					if (window["AscDesktopEditor"]["LocalFileGetImageUrl"] !== undefined)
					{
						aImagesToDownload.push(src);
					}
					else
					{
						var _base64 = window["AscDesktopEditor"]["GetImageBase64"](src);
						if (_base64 != "")
						{
							aImagesToDownload.push(_base64);
							_mapLocal[_base64] = src;
						}
						else
						{
							this.oImages[image] = "local";
						}
					}
				}
				else if(!g_oDocumentUrls.getImageLocal(src))
					aImagesToDownload.push(src);
			}
			if(aImagesToDownload.length > 0)
			{
				AscCommon.sendImgUrls(oThis.api, aImagesToDownload, function (data) {
				  var image_map = {};
				  for (var i = 0, length = Math.min(data.length, aImagesToDownload.length); i < length; ++i) {
					var elem = data[i];
					var sFrom = aImagesToDownload[i];
					if (null != elem.url) {
					  var name = g_oDocumentUrls.imagePath2Local(elem.path);
					  oThis.oImages[sFrom] = name;
					  image_map[i] = name;
					} else {
					  image_map[i] = sFrom;
					}
				  }
				  fCallback(aPrepeareFonts, image_map);
				}, null, true);
			}
			else
			{
				fCallback(aPrepeareFonts, this.oImages);
			}
        }
        else
		{
			fCallback();
		}
    },
    _Prepeare_recursive : function(node, bIgnoreStyle, isCheckFonts)
    {
		//пробегаемся по всему дереву, собираем все шрифты и картинки
        var nodeName = node.nodeName.toLowerCase();
        var nodeType = node.nodeType;
        if(!bIgnoreStyle)
        {
            if(Node.TEXT_NODE === nodeType)
            {
                var computedStyle = this._getComputedStyle(node.parentNode);
				var fontFamily = CheckDefaultFontFamily(this._getStyle(node.parentNode, computedStyle, "font-family"), this.apiEditor);
				if(fontFamily)
				{
					this.oFonts[fontFamily] = {Name: g_fontApplication.GetFontNameDictionary(fontFamily, true), Index: -1};
				}
            }
            else
            {
                var src = node.getAttribute("src");
                if(src)
                    this.oImages[src] = src;
            }
        }
        for(var i = 0, length = node.childNodes.length; i < length; i++)
        {
            var child = node.childNodes[i];

			//get comment
			var style = child.getAttribute ? child.getAttribute("style") : null;
			if(style && -1 !== style.indexOf("mso-element:comment") && -1 === style.indexOf("mso-element:comment-list")) {
				this._parseMsoElementComment(child);
			}

            var child_nodeType = child.nodeType;
            if(!(Node.ELEMENT_NODE === child_nodeType || Node.TEXT_NODE === child_nodeType))
                continue;
			//попускам элеметы состоящие только из \t,\n,\r
            if( Node.TEXT_NODE === child.nodeType)
            {
                var value = child.nodeValue;
                if(!value)
                    continue;
                value = value.replace(/(\r|\t|\n)/g, '');
                if("" == value)
                    continue;
            }
            this._Prepeare_recursive(child, false);
        }
		
		if(isCheckFonts)
		{
			var aPrepeareFonts = [];
            for(var font_family in this.oFonts)
            {
				//todo подбирать шрифт, хотябы по регистру
                var oFontItem = this.oFonts[font_family];
				//Ищем среди наших шрифтов
                this.oFonts[font_family].Index = -1;
                aPrepeareFonts.push(new CFont(oFontItem.Name, 0, "", 0));
            }
			
			return aPrepeareFonts;
		}
    },
	_parseMsoElementComment: function (node) {
		var msoComment = this._getMsoCommentText(node);
		this.msoComments.push(msoComment);
	},
	_getMsoCommentText: function(node) {
		var res = null;
		var elems = node.getElementsByClassName("MsoCommentText");
		if(elems && elems.length) {
			for(var i = 0; i < elems.length; i++) {
				var child = elems[i];

				if(!(child.getAttribute && child.getAttribute("class")==="MsoCommentReference")) {
					if(res === null) {
						res = "";
					}
					res += child.innerText;
				}
			}
		}
		return res;
	},
	_checkFontsOnLoad: function(fonts)
	{
		if(!fonts)
			return;
		return fonts;
	},
    _IsBlockElem : function(name)
    {
        if( "p" === name || "div" === name || "ul" === name || "ol" === name || "li" === name || "table" === name || "tbody" === name || "tr" === name || "td" === name || "th" === name ||
            "h1" === name || "h2" === name || "h3" === name || "h4" === name || "h5" === name || "h6" === name || "center" === name || "dd" === name || "dt" === name)
            return true;
        return false;
    },
	_getComputedStyle : function(node){
		var computedStyle = null;
		if(null != node && Node.ELEMENT_NODE === node.nodeType)
		{
			var defaultView = node.ownerDocument.defaultView;
			computedStyle = defaultView.getComputedStyle( node, null );
		}
		return computedStyle;
	},
	_getStyle : function(node, computedStyle, styleProp){
		var getStyle = function() {
			var style = null;
			if(computedStyle) {
				style = computedStyle.getPropertyValue(styleProp);
			}
			if(!style) {
				if(node && node.currentStyle) {
					style = node.currentStyle[styleProp];
				}
			}

			return style;
		};

		var res = getStyle();
		var sNodeName = node.nodeName.toLowerCase();
		if(!res) {
			switch(styleProp)
			{
				case "font-family":
				{
					res = node.fontFamily;
					break;
				}
				case "background-color":
				{
					res = node.style.backgroundColor;
					if("td" === sNodeName && !res) {
						res = node.bgColor;
					}
					break;
				}
				case "font-weight":
				{
					res = node.style.fontWeight;
				}
			}
		}

		return res;
	},
    _ValueToMm : function(value)
    {
        var obj = this._ValueToMmType(value);
        if(obj && "%" !== obj.type && "none" !== obj.type)
            return obj.val;
        return null;
    },
    _ValueToMmType : function(value)
    {
        var oVal = parseFloat(value);
        var oType;
        if(!isNaN(oVal))
        {
            if(-1 !== value.indexOf("%"))
            {
                oType = "%";
                oVal /= 100;
            }
            else if(-1 !== value.indexOf("px"))
            {
                oType = "px";
                oVal *= g_dKoef_pix_to_mm;
            }
            else if(-1 !== value.indexOf("in"))
            {
                oType = "in";
                oVal *= g_dKoef_in_to_mm;
            }
            else if(-1 !== value.indexOf("cm"))
            {
                oType = "cm";
                oVal *= 10;
            }
            else if(-1 !== value.indexOf("mm"))
            {
                oType = "mm";
            }
            else if(-1 !== value.indexOf("pt"))
            {
                oType = "pt";
                oVal *= g_dKoef_pt_to_mm;
            }
            else if(-1 !== value.indexOf("pc"))
            {
                oType = "pc";
                oVal *= g_dKoef_pc_to_mm;
            }
            else
                oType = "none";
            return {val: oVal, type: oType};
        }
        return null;
    },
    _ParseColor : function(color)
    {
        if(!color || color.length == 0)
            return null;
        if("transparent" === color)
            return null;
        if("aqua" === color)
            return new CDocumentColor(0, 255, 255);
        else if("black" === color)
            return new CDocumentColor(0, 0, 0);
        else if("blue" === color)
            return new CDocumentColor(0, 0, 255);
        else if("fuchsia" === color)
            return new CDocumentColor(255, 0, 255);
        else if("gray" === color)
            return new CDocumentColor(128, 128, 128);
        else if("green" === color)
            return new CDocumentColor(0, 128, 0);
        else if("lime" === color)
            return new CDocumentColor(0, 255, 0);
        else if("maroon" === color)
            return new CDocumentColor(128, 0, 0);
        else if("navy" === color)
            return new CDocumentColor(0, 0, 128);
        else if("olive" === color)
            return new CDocumentColor(128, 128, 0);
        else if("purple" === color)
            return new CDocumentColor(128, 0, 128);
        else if("red" === color)
            return new CDocumentColor(255, 0, 0);
        else if("silver" === color)
            return new CDocumentColor(192, 192, 192);
        else if("teal" === color)
            return new CDocumentColor(0, 128, 128);
        else if("white" === color)
            return new CDocumentColor(255, 255, 255);
        else if("yellow" === color)
            return new CDocumentColor(255, 255, 0);
        else
        {
            if(0 === color.indexOf("#"))
            {
                var hex = color.substring(1);
                if(hex.length === 3)
                    hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
                if(hex.length === 6)
                {
                    var r = parseInt("0x" + hex.substring(0,2));
                    var g = parseInt("0x" + hex.substring(2,4));
                    var b = parseInt("0x" + hex.substring(4,6));
                    return new CDocumentColor(r, g, b);
                }
            }
            if(0 === color.indexOf("rgb"))
            {
                var nStart = color.indexOf('(');
                var nEnd = color.indexOf(')');
                if(-1 !== nStart && -1 !== nEnd && nStart < nEnd)
                {
                    var temp = color.substring(nStart + 1, nEnd);
                    var aParems = temp.split(',');
                    if(aParems.length >= 3)
                    {
                        if(aParems.length >= 4)
                        {
                            var oA = this._ValueToMmType(aParems[3]);
                            if(0 == oA .val)//полностью прозрачный
                                return null;
                        }
                        var oR = this._ValueToMmType(aParems[0]);
                        var oG = this._ValueToMmType(aParems[1]);
                        var oB = this._ValueToMmType(aParems[2]);
                        var r,g,b;
                        if(oR && "%" === oR.type)
                            r = parseInt(255 * oR.val / 100);
                        else
                            r = oR.val;
                        if(oG && "%" === oG.type)
                            g = parseInt(255 * oG.val / 100);
                        else
                            g = oG.val;
                        if(oB && "%" === oB.type)
                            b = parseInt(255 * oB.val / 100);
                        else
                            b = oB.val;
                        return new CDocumentColor(r, g, b);
                    }
                }
            }
        }
        return null;
    },
    _isEmptyProperty : function(prop)
    {
        var bIsEmpty = true;
        for(var i in prop)
        {
            if(null != prop[i])
            {
                bIsEmpty = false;
                break;
            }
        }
        return bIsEmpty;
    },
    _set_pPr : function(node, Para,  pNoHtmlPr)
    {
		//Пробегаемся вверх по дереву в поисках блочного элемента
		var t = this;
		var sNodeName = node.nodeName.toLowerCase();
        if(node !== this.oRootNode)
        {
            while(false === this._IsBlockElem(sNodeName))
            {
                if(this.oRootNode !== node.parentNode)
				{
                    node = node.parentNode;
					sNodeName = node.nodeName.toLowerCase();
				}
                else
                    break;
            }
        }
		if("td" === sNodeName || "th" === sNodeName)
		{
			//для случая <td>br<span></span></td> без текста в ячейке
			var oNewSpacing = new CParaSpacing();
			oNewSpacing.Set_FromObject({After: 0, Before: 0, Line: Asc.linerule_Auto});
            Para.Set_Spacing(oNewSpacing);
			return;
		}
        var oDocument = this.oDocument;

		//Heading
		//Ранее применялся весь заголовок - Para.Style_Add(oDocument.Styles.Get_Default_Heading(pNoHtmlPr.hLevel));
		if(null != pNoHtmlPr.hLevel && oDocument.Styles)
		{
			Para.SetOutlineLvl(pNoHtmlPr.hLevel);
		}

        var pPr = Para.Pr;

        //Borders
        var oNewBorder = {Left: null, Top: null, Right: null, Bottom: null, Between: null};
        var sBorder = pNoHtmlPr["mso-border-alt"];
        if(null != sBorder)
        {
            var oNewBrd = this._ExecuteParagraphBorder(sBorder);
            oNewBorder.Left = oNewBrd;
            oNewBorder.Top = oNewBrd.Copy();
            oNewBorder.Right = oNewBrd.Copy();
            oNewBorder.Bottom = oNewBrd.Copy();
        }
        else
        {
            sBorder = pNoHtmlPr["mso-border-left-alt"];
            if(null != sBorder)
            {
                var oNewBrd = this._ExecuteParagraphBorder(sBorder);
                oNewBorder.Left = oNewBrd;
            }
            sBorder = pNoHtmlPr["mso-border-top-alt"];
            if(null != sBorder)
            {
                var oNewBrd = this._ExecuteParagraphBorder(sBorder);
                oNewBorder.Top = oNewBrd;
            }
            sBorder = pNoHtmlPr["mso-border-right-alt"];
            if(null != sBorder)
            {
                var oNewBrd = this._ExecuteParagraphBorder(sBorder);
                oNewBorder.Right = oNewBrd;
            }
            sBorder = pNoHtmlPr["mso-border-bottom-alt"];
            if(null != sBorder)
            {
                var oNewBrd = this._ExecuteParagraphBorder(sBorder);
                oNewBorder.Bottom = oNewBrd;
            }
        }
        sBorder = pNoHtmlPr["mso-border-between"];
        if(null != sBorder)
        {
            var oNewBrd = this._ExecuteParagraphBorder(sBorder);
            oNewBorder.Between = oNewBrd;
        }

        var computedStyle = this._getComputedStyle(node);
        if (computedStyle)
        {
			var font_family = CheckDefaultFontFamily(this._getStyle(node, computedStyle, "font-family" ), this.apiEditor);
			if(font_family && "" != font_family)
			{
				var oFontItem = this.oFonts[font_family];
				if(null != oFontItem && null != oFontItem.Name && Para.TextPr && Para.TextPr.Value && Para.TextPr.Value.RFonts)
				{
					Para.TextPr.Value.RFonts.Ascii = {Name: oFontItem.Name, Index: oFontItem.Index};
					Para.TextPr.Value.RFonts.HAnsi = {Name: oFontItem.Name, Index: oFontItem.Index};
					Para.TextPr.Value.RFonts.CS = {Name: oFontItem.Name, Index: oFontItem.Index};
					Para.TextPr.Value.RFonts.EastAsia = {Name: oFontItem.Name, Index: oFontItem.Index};
				}
			}

			var font_size = node.style ? node.style.fontSize : null;
			if(!font_size)
				font_size = this._getStyle(node, computedStyle, "font-size" );
			font_size = CheckDefaultFontSize(font_size, this.apiEditor);
			if(font_size && Para.TextPr && Para.TextPr.Value)
			{
				var obj = this._ValueToMmType(font_size);
				if(obj && "%" !== obj.type && "none" !== obj.type)
				{
					font_size = obj.val;
					//Если браузер не поддерживает нецелые пикселы отсекаем половинные шрифты, они появляются при вставке 8, 11, 14, 20, 26pt
					if("px" === obj.type && false === this.bIsDoublePx)
						font_size = Math.round(font_size * g_dKoef_mm_to_pt);
					else
						font_size = Math.round(2 * font_size * g_dKoef_mm_to_pt) / 2;//половинные значения допустимы.
					
					//TODO use constant
					if(font_size > 300)
						font_size = 300;
					else if(font_size === 0)
						font_size = 1;
						
					Para.TextPr.Value.FontSize = font_size;
				}
			}
			
			//Ind
            var Ind = new CParaInd();
            var margin_left = this._getStyle(node, computedStyle, "margin-left" );
			
			//TODO перепроверить правку с pageColumn
			var curContent = this.oLogicDocument.Content[this.oLogicDocument.CurPos.ContentPos];
			var curIndexColumn = curContent && curContent.Get_CurrentColumn ? curContent.Get_CurrentColumn(this.oLogicDocument.CurPage) : null;
			var curPage = this.oLogicDocument.Pages[this.oLogicDocument.CurPage];
			var pageColumn = null !== curIndexColumn && curPage && curPage.Sections && curPage.Sections[0] && curPage.Sections[0].Columns ? curPage.Sections[0].Columns[curIndexColumn] : null;
            if(margin_left && null != (margin_left = this._ValueToMm(margin_left)))
			{
				if(!pageColumn || (pageColumn && pageColumn.X + margin_left < pageColumn.XLimit))
				{
					Ind.Left = margin_left;
				}
			}
            var margin_right = this._getStyle(node, computedStyle, "margin-right" );
            if(margin_right && null != (margin_right = this._ValueToMm(margin_right)))
			{
				if(!pageColumn || (pageColumn && pageColumn.XLimit - margin_right > pageColumn.X))
				{
					Ind.Right = margin_right;
				}
			}
               
            //scale
            // if(null != pPr.Ind.Left && true == this.bUseScaleKoef)
            // pPr.Ind.Left = pPr.Ind.Left * this.dScaleKoef;
            // if(null != pPr.Ind.Right && true == this.bUseScaleKoef)
            // pPr.Ind.Right = pPr.Ind.Right * this.dScaleKoef;
			//Проверка чтобы правый margin не заходил за левый или не приближался ближе чем на линейке
            if(null != Ind.Left && null != Ind.Right)
            {
				//30 ограничение как и на линейке
                var dif = Page_Width - X_Left_Margin - X_Right_Margin - Ind.Left - Ind.Right;
                if(dif < 30)
                    Ind.Right = Page_Width - X_Left_Margin - X_Right_Margin - Ind.Left - 30;
            }
            var text_indent = this._getStyle(node, computedStyle, "text-indent");
            if(text_indent && null != (text_indent = this._ValueToMm(text_indent)))
                Ind.FirstLine = text_indent;
            // if(null != pPr.Ind.FirstLine && true == this.bUseScaleKoef)
            // pPr.Ind.FirstLine = pPr.Ind.FirstLine * this.dScaleKoef;
            if(false === this._isEmptyProperty(Ind) && !pNoHtmlPr['mso-list'])
                Para.Set_Ind(Ind);
            //Jc
            var text_align = this._getStyle(node, computedStyle, "text-align")
            if(text_align)
            {
				//Может приходить -webkit-right
                var Jc = null;
                if(-1 !== text_align.indexOf('center'))
                    Jc = align_Center;
                else if(-1 !== text_align.indexOf('right'))
                    Jc = align_Right;
                else if(-1 !== text_align.indexOf('justify'))
                    Jc = align_Justify;
                if(null != Jc)
                    Para.Set_Align(Jc, false);
            }
            //Spacing
			var Spacing = new CParaSpacing();
            var margin_top = this._getStyle(node, computedStyle, "margin-top");
            if(margin_top && null != (margin_top = this._ValueToMm(margin_top)) && margin_top >= 0)
                Spacing.Before = margin_top;
            var margin_bottom = this._getStyle(node, computedStyle, "margin-bottom");
            if(margin_bottom && null != (margin_bottom = this._ValueToMm(margin_bottom)) && margin_bottom >= 0)
                Spacing.After = margin_bottom;
			//line height
			//computedStyle возвращает значение в px. мне нужны %(ms записывает именно % в html)
			var line_height = node.style && node.style.lineHeight ? node.style.lineHeight : this._getStyle(node, computedStyle, "line-height");
			if(line_height)
			{
				var oLineHeight = this._ValueToMmType(line_height);
				if(oLineHeight && "%" === oLineHeight.type)
				{
					Spacing.Line = oLineHeight.val;
				}
				else if(line_height && null != (line_height = this._ValueToMm(line_height)) && line_height >= 0)
				{
					Spacing.Line = line_height;
					Spacing.LineRule = Asc.linerule_Exact;
				}
			}
            if(false === this._isEmptyProperty(Spacing))
                Para.Set_Spacing(Spacing);
            //Shd
			//background-color не наследуется остальные свойства, надо смотреть родительские элементы
            var background_color = null;
            var oTempNode = node;
            while(true)
            {
                var tempComputedStyle = this._getComputedStyle(oTempNode);
                if(null == tempComputedStyle)
                    break;
                background_color = this._getStyle(oTempNode, tempComputedStyle, "background-color");
                if(null != background_color && (background_color = this._ParseColor(background_color)))
                    break;
                oTempNode = oTempNode.parentNode;
                if(this.oRootNode === oTempNode || "body" === oTempNode.nodeName.toLowerCase() || true === this._IsBlockElem(oTempNode.nodeName.toLowerCase()))
                    break;
            }
            if(PasteElementsId.g_bIsDocumentCopyPaste)
            {
                if(background_color)
                {
                    var Shd = new CDocumentShd();
                    Shd.Value = c_oAscShdClear;
                    Shd.Color = background_color;
                    Para.Set_Shd(Shd);
                }
            }

            if(null == oNewBorder.Left)
                oNewBorder.Left = this._ExecuteBorder(computedStyle, node, "left", "Left", false);
            if(null == oNewBorder.Top)
                oNewBorder.Top = this._ExecuteBorder(computedStyle, node, "top", "Top", false);
            if(null == oNewBorder.Right)
                oNewBorder.Right = this._ExecuteBorder(computedStyle, node, "left", "Left", false);
            if(null == oNewBorder.Bottom)
                oNewBorder.Bottom = this._ExecuteBorder(computedStyle, node, "bottom", "Bottom", false);
        }
        if(false === this._isEmptyProperty(oNewBorder))
            Para.Set_Borders(oNewBorder);

        //KeepLines , WidowControl
        var pagination = pNoHtmlPr["mso-pagination"];
        if(pagination)
        {
            //todo WidowControl
            if("none" === pagination)
                ;//pPr.WidowControl = !Def_pPr.WidowControl;
            else if(-1 !== pagination.indexOf("widow-orphan") && -1 !== pagination.indexOf("lines-together"))
                Para.Set_KeepLines(true);
            else if(-1 !== pagination.indexOf("none") && -1 !== pagination.indexOf("lines-together"))
            {
                ;//pPr.WidowControl = !Def_pPr.WidowControl;
                Para.Set_KeepLines(true);
            }
        }
        //todo KeepNext
        if("avoid" === pNoHtmlPr["page-break-after"])
            ;//pPr.KeepNext = !Def_pPr.KeepNext;
        //PageBreakBefore
        if("always" === pNoHtmlPr["page-break-before"])
            Para.Set_PageBreakBefore(true);
        //Tabs
        var tab_stops = pNoHtmlPr["tab-stops"];
        if(tab_stops && "" != pNoHtmlPr["tab-stops"])
        {
            var aTabs = tab_stops.split(' ');
            var nTabLen = aTabs.length;
            if(nTabLen > 0)
            {
                var Tabs = new CParaTabs();
                for(var i = 0; i < nTabLen; i++)
                {
                    var val = this._ValueToMm(aTabs[i]);
                    if(val)
                        Tabs.Add(new CParaTab(tab_Left, val));
                }
                Para.Set_Tabs(Tabs);
            }
        }

        //*****num*****
        if(PasteElementsId.g_bIsDocumentCopyPaste)
        {
            if(true === pNoHtmlPr.bNum)
            {
                var setListTextPr = function(oNum)
				{
					//текстовые настройки списка берем по настройкам первого текстового элемента
					var oFirstTextChild = node;
					while(true)
					{
						var bContinue = false;
						for(var i = 0, length = oFirstTextChild.childNodes.length; i < length; i++)
						{
							var child = oFirstTextChild.childNodes[i];
							var nodeType = child.nodeType;

							if(!(Node.ELEMENT_NODE === nodeType || Node.TEXT_NODE === nodeType))
								continue;
							//попускам элеметы состоящие только из \t,\n,\r
							if( Node.TEXT_NODE === child.nodeType)
							{
								var value = child.nodeValue;
								if(!value)
									continue;
								value = value.replace(/(\r|\t|\n)/g, '');
								if("" === value)
									continue;
							}
							if(Node.ELEMENT_NODE === nodeType)
							{
								oFirstTextChild = child;
								bContinue = true;
								break;
							}
						}
						if(false === bContinue)
							break;
					}
					if(node != oFirstTextChild)
					{
						if(!t.bIsPlainText)
						{
							var oLvl = oNum.GetLvl(0);
							var oTextPr = t._read_rPr(oFirstTextChild);
							if(Asc.c_oAscNumberingFormat.Bullet === num)
								oTextPr.RFonts = oLvl.GetTextPr().RFonts.Copy();
								
							//TODO убираю пока при всатвке извне underline/bold/italic у стиля маркера
							oTextPr.Bold = oTextPr.Underline = oTextPr.Italic = undefined;
							if(oFirstTextChild.nodeName.toLowerCase() === "a" && oTextPr.Color)
								oTextPr.Color.Set(0, 0, 0);

							//получаем настройки из node
							oNum.ApplyTextPr(0, oTextPr);
						}
					}
				};
				
				
				if(pNoHtmlPr['mso-list'])
				{	
					var level = 0;
					var listId = null;
					var startIndex;
					if(-1 !== (startIndex = pNoHtmlPr['mso-list'].indexOf("level")))
					{
						level = parseInt(pNoHtmlPr['mso-list'].substr(startIndex + 5, 1)) - 1;
					}
					if(-1 !== (startIndex = pNoHtmlPr['mso-list'].indexOf("lfo")))
					{
						listId = pNoHtmlPr['mso-list'].substr(startIndex, 4);
					}
					
					var NumId = null;
					if(listId && this.msoListMap[listId])//find list id into map
					{
						NumId = this.msoListMap[listId];
					}
					
					//get listId and level from mso-list property
					var msoListIgnoreSymbol = this._getMsoListSymbol(node);
					if(!msoListIgnoreSymbol)
					{
						msoListIgnoreSymbol = "ol" === node.parentElement.nodeName.toLowerCase() ? "1." : ".";
					}

					var listObj = this._getTypeMsoListSymbol(msoListIgnoreSymbol, (null === NumId));
					var num = listObj.type;
					var startPos = listObj.startPos;
					
					if(null == NumId && this.pasteInExcel !== true)//create new NumId
					{
						// Создаем нумерацию
						var oNum = this.oLogicDocument.GetNumbering().CreateNum();
						NumId    = oNum.GetId();

						if (Asc.c_oAscNumberingFormat.Bullet === num)
						{
							oNum.CreateDefault(c_oAscMultiLevelNumbering.Bullet);
							var LvlText = String.fromCharCode(0x00B7);
							var NumTextPr = new CTextPr();
							NumTextPr.RFonts.Set_All("Symbol", -1);

							switch(type)
							{
								case "disc":
								{
									NumTextPr.RFonts.Set_All("Symbol", -1);
									LvlText = String.fromCharCode(0x00B7);
									break;
								}
								case "circle":
								{
									NumTextPr.RFonts.Set_All("Courier New", -1);
									LvlText = "o";
									break;
								}
								case "square":
								{
									NumTextPr.RFonts.Set_All("Wingdings", -1);
									LvlText = String.fromCharCode(0x00A7);
									break;
								}
							}
						}
						else
						{
							oNum.CreateDefault(c_oAscMultiLevelNumbering.Numbered);
						}
						
						switch(num)
						{
							case Asc.c_oAscNumberingFormat.Bullet     : oNum.SetLvlByType(level, c_oAscNumberingLevel.Bullet, LvlText, NumTextPr); break;
							case Asc.c_oAscNumberingFormat.Decimal    : oNum.SetLvlByType(level, c_oAscNumberingLevel.DecimalDot_Left); break;
							case Asc.c_oAscNumberingFormat.LowerRoman : oNum.SetLvlByType(level, c_oAscNumberingLevel.LowerRomanDot_Right); break;
							case Asc.c_oAscNumberingFormat.UpperRoman : oNum.SetLvlByType(level, c_oAscNumberingLevel.UpperRomanDot_Right); break;
							case Asc.c_oAscNumberingFormat.LowerLetter: oNum.SetLvlByType(level, c_oAscNumberingLevel.LowerLetterDot_Left); break;
							case Asc.c_oAscNumberingFormat.UpperLetter: oNum.SetLvlByType(level, c_oAscNumberingLevel.UpperLetterDot_Left); break;
						}
						
						//проставляем начальную позицию
						if(null !== startPos)
						{
							oNum.SetLvlStart(level, startPos);
						}
						
						//setListTextPr(oNum);
					}
					
					//put into map listId
					if(!this.msoListMap[listId])
					{
						this.msoListMap[listId] = NumId;
					}
					
					if(this.pasteInExcel !== true && Para.bFromDocument === true)
					{
						Para.SetNumPr( NumId, level );
					}
				}
				else
				{
					var num = Asc.c_oAscNumberingFormat.Bullet;
					if(null != pNoHtmlPr.numType)
						num = pNoHtmlPr.numType;
					var type = pNoHtmlPr["list-style-type"];
					
					if(type)
					{
						switch(type)
						{
							case "disc"       : num = Asc.c_oAscNumberingFormat.Bullet;break;
							case "decimal"    : num = Asc.c_oAscNumberingFormat.Decimal;break;
							case "lower-roman": num = Asc.c_oAscNumberingFormat.LowerRoman;break;
							case "upper-roman": num = Asc.c_oAscNumberingFormat.UpperRoman;break;
							case "lower-alpha": num = Asc.c_oAscNumberingFormat.LowerLetter;break;
							case "upper-alpha": num = Asc.c_oAscNumberingFormat.UpperLetter;break;
						}
					}
					//Часть кода скопирована из Document.Set_ParagraphNumbering

					//Смотрим передыдущий параграф, если тип списка совпадает, то берем тип списка из предыдущего параграфа
					if(this.aContent.length > 1)
					{
						var prevElem = this.aContent[this.aContent.length - 2];
						if(null != prevElem && type_Paragraph === prevElem.GetType())
						{
							var PrevNumPr = prevElem.GetNumPr();
							if ( null != PrevNumPr && true === this.oLogicDocument.Numbering.CheckFormat( PrevNumPr.NumId, PrevNumPr.Lvl, num ) )
								NumId  = PrevNumPr.NumId;
						}
					}
					if(null == NumId && this.pasteInExcel !== true)
					{
						// Создаем нумерацию
						var oNum = this.oLogicDocument.GetNumbering().CreateNum();
						NumId    = oNum.GetId();
						if (Asc.c_oAscNumberingFormat.Bullet === num)
						{
							oNum.CreateDefault(c_oAscMultiLevelNumbering.Bullet);
							var LvlText = String.fromCharCode(0x00B7);
							var NumTextPr = new CTextPr();
							NumTextPr.RFonts.Set_All("Symbol", -1);

							switch(type)
							{
								case "disc":
								{
									NumTextPr.RFonts.Set_All("Symbol", -1);
									LvlText = String.fromCharCode(0x00B7);
									break;
								}
								case "circle":
								{
									NumTextPr.RFonts.Set_All("Courier New", -1);
									LvlText = "o";
									break;
								}
								case "square":
								{
									NumTextPr.RFonts.Set_All("Wingdings", -1);
									LvlText = String.fromCharCode(0x00A7);
									break;
								}
							}
						}
						else
						{
							oNum.CreateDefault(c_oAscMultiLevelNumbering.Numbered);
						}
						
						for (var iLvl = 0; iLvl <= 8; iLvl++)
						{
							switch(num)
							{
								case Asc.c_oAscNumberingFormat.Bullet     : oNum.SetLvlByType(iLvl, c_oAscNumberingLevel.Bullet, LvlText, NumTextPr); break;
								case Asc.c_oAscNumberingFormat.Decimal    : oNum.SetLvlByType(iLvl, c_oAscNumberingLevel.DecimalDot_Right); break;
								case Asc.c_oAscNumberingFormat.LowerRoman : oNum.SetLvlByType(iLvl, c_oAscNumberingLevel.LowerRomanDot_Right); break;
								case Asc.c_oAscNumberingFormat.UpperRoman : oNum.SetLvlByType(iLvl, c_oAscNumberingLevel.UpperRomanDot_Right); break;
								case Asc.c_oAscNumberingFormat.LowerLetter: oNum.SetLvlByType(iLvl, c_oAscNumberingLevel.LowerLetterDot_Left); break;
								case Asc.c_oAscNumberingFormat.UpperLetter: oNum.SetLvlByType(iLvl, c_oAscNumberingLevel.UpperLetterDot_Left); break;
							}
						}
						
						setListTextPr(oNum);
					}
					
					if(this.pasteInExcel !== true && Para.bFromDocument === true)
					{
						Para.ApplyNumPr(NumId, 0);
					}
				}
            }
            else
            {
                var numPr = Para.GetNumPr();
                if(numPr)
                    Para.RemoveNumPr();
            }
        }
        else
        {
            if(true === pNoHtmlPr.bNum)
            {
                var num = numbering_presentationnumfrmt_Char;
                if(null != pNoHtmlPr.numType)
                    num = pNoHtmlPr.numType;
                var type = pNoHtmlPr["list-style-type"];
                if(type)
                {
                    switch(type)
                    {
                        case "disc": num = numbering_presentationnumfrmt_Char;break;
                        case "decimal": num = numbering_presentationnumfrmt_ArabicPeriod;break;
                        case "lower-roman": num = numbering_presentationnumfrmt_RomanLcPeriod;break;
                        case "upper-roman": num = numbering_presentationnumfrmt_RomanUcPeriod;break;
                        case "lower-alpha": num = numbering_presentationnumfrmt_AlphaLcPeriod;break;
                        case "upper-alpha": num = numbering_presentationnumfrmt_AlphaUcPeriod;break;
                        default:
                        {
                            num = numbering_presentationnumfrmt_Char;
                        }
                    }
                }
                var _bullet = new CPresentationBullet();
                _bullet.m_nType = num;
                if(num === numbering_presentationnumfrmt_Char)
                {
                    _bullet.m_sChar = "•";
                }
                _bullet.m_nStartAt = 1;
                Para.Add_PresentationNumbering2(_bullet );
            }
            else
            {
               Para.Remove_PresentationNumbering();
            }
        }
        Para.CompiledPr.NeedRecalc = true;
    },
    _commit_rPr: function (node, bUseOnlyInherit)
    {
		if(!this.bIsPlainText)
		{
		    var rPr = this._read_rPr(node, bUseOnlyInherit);
			
			//заглушка для вставки в excel внутрь шейпа
			var tempRpr;
			var bSaveExcelFormat = window['AscCommon'].g_clipboardBase.bSaveFormat;
			if (this.pasteInExcel === true && !bSaveExcelFormat && this.oDocument && this.oDocument.Parent &&
				this.oDocument.Parent.parent &&
				this.oDocument.Parent.parent.getObjectType() === AscDFH.historyitem_type_Shape) {
				tempRpr = new CTextPr();
				tempRpr.Underline = rPr.Underline;
				tempRpr.Bold = rPr.Bold;
				tempRpr.Italic = rPr.Italic;
				
				rPr = tempRpr;
			}

			//Если текстовые настройки поменялись добавляем элемент
			if(!this.oCur_rPr.Is_Equal(rPr))
			{
			    this._Set_Run_Pr(rPr);
				this.oCur_rPr = rPr;
			}
		}
    },
    _read_rPr : function(node, bUseOnlyInherit)
    {
        var oDocument = this.oDocument;
        var rPr = new CTextPr();
        if(false == PasteElementsId.g_bIsDocumentCopyPaste)
        {
            rPr.Set_FromObject({
                Bold       : false,
                Italic     : false,
                Underline  : false,
                Strikeout  : false,
				RFonts :
				{
					Ascii: {
						Name  : "Arial",
						Index : -1
					},
					EastAsia: {
						Name  : "Arial",
						Index : -1
					},
					HAnsi: {
						Name  : "Arial",
						Index : -1
					},
					CS: {
						Name  : "Arial",
						Index : -1
					}
				},
                FontSize   : 11,
                Color      :
                {
                    r : 0,
                    g : 0,
                    b : 0
                },
                VertAlign : AscCommon.vertalign_Baseline,
                HighLight : highlight_None
            });
        }
        var computedStyle = this._getComputedStyle(node);
        if ( computedStyle )
        {
            var font_family = CheckDefaultFontFamily(this._getStyle(node, computedStyle, "font-family"), this.apiEditor);
            if(font_family && "" != font_family)
            {
                var oFontItem = this.oFonts[font_family];
                if(null != oFontItem && null != oFontItem.Name)
				{
					rPr.RFonts.Ascii = {Name: oFontItem.Name, Index: oFontItem.Index};
					rPr.RFonts.HAnsi = {Name: oFontItem.Name, Index: oFontItem.Index};
					rPr.RFonts.CS = {Name: oFontItem.Name, Index: oFontItem.Index};
					rPr.RFonts.EastAsia = {Name: oFontItem.Name, Index: oFontItem.Index};
				}
            }
			var font_size = node.style ? node.style.fontSize : null;
			if(!font_size)
				font_size = this._getStyle(node, computedStyle, "font-size");
			font_size = CheckDefaultFontSize(font_size, this.apiEditor);
            if(font_size)
            {
                var obj = this._ValueToMmType(font_size);
                if(obj && "%" !== obj.type && "none" !== obj.type)
                {
                    font_size = obj.val;
					//Если браузер не поддерживает нецелые пикселы отсекаем половинные шрифты, они появляются при вставке 8, 11, 14, 20, 26pt
                    if("px" === obj.type && false === this.bIsDoublePx)
                        font_size = Math.round(font_size * g_dKoef_mm_to_pt);
                    else
                        font_size = Math.round(2 * font_size * g_dKoef_mm_to_pt) / 2;//половинные значения допустимы.
					
					//TODO use constant
					if(font_size > 300)
						font_size = 300;
					else if(font_size === 0)
						font_size = 1;
						
                    rPr.FontSize = font_size;
                }
            }
            var font_weight = this._getStyle(node, computedStyle, "font-weight");
            if(font_weight)
            {
                if("bold" === font_weight || "bolder" === font_weight || 400 < font_weight)
                    rPr.Bold = true;
            }
            var font_style = this._getStyle(node, computedStyle, "font-style");
            if("italic" === font_style)
                rPr.Italic = true;
            var color = this._getStyle(node, computedStyle, "color");
            if(color && (color = this._ParseColor(color)))
            {
                if(PasteElementsId.g_bIsDocumentCopyPaste){
                    rPr.Color = color;
                }
                else{
                    if(color){
                        rPr.Unifill =  AscFormat.CreateUnfilFromRGB(color.r, color.g, color.b);
                    }
                }
            }
			
			var spacing = this._getStyle(node, computedStyle, "letter-spacing");
            if(spacing && null != (spacing = this._ValueToMm(spacing)))
                rPr.Spacing = spacing;

			//Провяем те свойства, которые не наследуется, надо смотреть родительские элементы
            var background_color = null;
            var underline = null;
            var Strikeout = null;
            var vertical_align = null;
            var oTempNode = node;
            while (true !== bUseOnlyInherit && true)
            {
                var tempComputedStyle = this._getComputedStyle(oTempNode);
                if(null == tempComputedStyle)
                    break;
                if(null == underline || null == Strikeout)
                {
                    var text_decoration = this._getStyle(node, tempComputedStyle, "text-decoration");
                    if(text_decoration)
                    {
                        if(-1 !== text_decoration.indexOf("underline"))
                            underline = true;
						else if(-1 !== text_decoration.indexOf("none") && node.parentElement && node.parentElement.nodeName.toLowerCase() === "a")
							underline = false;	
							
                        if(-1 !== text_decoration.indexOf("line-through"))
                            Strikeout = true;
                    }
                }
                if(null == background_color)
                {
                    background_color = this._getStyle(node, tempComputedStyle, "background-color");
                    if(background_color)
                        background_color = this._ParseColor(background_color);
                    else
                        background_color = null;
                }
                if(null == vertical_align || "baseline" === vertical_align)
                {
                    vertical_align = this._getStyle(node, tempComputedStyle, "vertical-align");
                    if(!vertical_align)
                        vertical_align = null;
                }
                if(vertical_align && background_color && Strikeout && underline)
                    break;
                oTempNode = oTempNode.parentNode;
                if(this.oRootNode === oTempNode || "body" === oTempNode.nodeName.toLowerCase()  || true === this._IsBlockElem(oTempNode.nodeName.toLowerCase()))
                    break;
            }
            if(PasteElementsId.g_bIsDocumentCopyPaste)
            {
                if(background_color)
                    rPr.HighLight = background_color;
            }
            else
                delete rPr.HighLight;
            if(null != underline)
                rPr.Underline = underline;
            if(null != Strikeout)
                rPr.Strikeout = Strikeout;
            switch(vertical_align)
            {
                case "sub": rPr.VertAlign = AscCommon.vertalign_SubScript;break;
                case "super": rPr.VertAlign = AscCommon.vertalign_SuperScript;break;
            }
        }
        return rPr;
    },
    _parseCss : function(sStyles, pPr)
    {
        var aStyles = sStyles.split(';');
        if(aStyles)
        {
            for(var i = 0, length = aStyles.length; i < length; i++)
            {
                var style = aStyles[i];
                var aPair = style.split(':');
                if(aPair && aPair.length > 1)
                {
                    var prop_name = trimString(aPair[0]);
                    var prop_value = trimString(aPair[1]);
                    if(null != this.MsoStyles[prop_name])
                        pPr[prop_name] = prop_value;
                }
            }
        }
    },
    _PrepareContent : function()
    {
		//Не допускам чтобы контент заканчивался на таблицу, иначе тяжело вставить параграф после
        if(this.aContent.length > 0)
        {
            var last = this.aContent[this.aContent.length - 1];
            if(type_Table === last.GetType())
            {
                this._Add_NewParagraph();
            }
        }
    },

	_getMsoListSymbol: function (node) {
		var res = null;
		var nodeList = this._getMsoListIgnore(node);
		if (nodeList) {
			var value = nodeList.innerText;
			if (value) {
				for (var pos = value.getUnicodeIterator(); pos.check(); pos.next()) {
					var nUnicode = pos.value();

					if (null !== nUnicode) {
						if (0x20 !== nUnicode && 0xA0 !== nUnicode && 0x2009 !== nUnicode) {
							if (!res) {
								res = "";
							}
							res += value.charAt(pos.position());
						}
					}
				}
			}
		}
		return res;
	},

	_getMsoListIgnore: function(node)
	{
		if(!node || (node && !node.children))
		{
			return null;
		}
		
		for(var i = 0; i < node.children.length; i++)
		{
			var child = node.children[i];
			var style = child.getAttribute("style");
			if(style)
			{
				var pNoHtml = {};
				this._parseCss(style, pNoHtml);
				if("Ignore" === pNoHtml["mso-list"])
				{
					return child;
				}
			}
			
			if(child.children && child.children.length)
			{
				return this._getMsoListIgnore(child);
			}
		}
	},
	_getTypeMsoListSymbol: function(str, getStartPosition)
	{
		var symbolsArr = [
			"ivxlcdm",
			"IVXLCDM",
			"abcdefghijklmnopqrstuvwxyz", 
			"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		];
		
		//TODO пересмотреть функцию перевода из римских чисел
		var romanToIndex = function(text) 
		{
			var arab_number = [1,4,5,9,10,40,50,90,100,400,500,900,1000,4000,5000,9000,10000];
			var rom_number = ["I","IV","V","IX","X","XL","L","XC","C","CD","D","CM","M", "M&#8577;","&#8577;","&#8577;&#8578;","&#8578;"];
			
			var text = text.toUpperCase();
			var result = 0;
			var pos = 0;
			var i = arab_number.length - 1;
			while (i >= 0 && pos < text.length) 
			{
				if (text.substr(pos, rom_number[i].length) === rom_number[i])
				{
					result += arab_number[i];
					pos += rom_number[i].length;
				}
				else
				{
					i--;
				}
			}
			return result;
		};
		
		var latinToIndex = function(text) 
		{
			var text = text.toUpperCase();
			var index = 0;
			for(var i = 0; i < text.length; i++)
			{
				index += symbolsArr[3].indexOf(text[i]) + 1;
			}
			return index;
		};
		
		var getFullListIndex = function(indexStr, str)
		{
			var fullListIndex = "";
			for(var i = 0; i < str.length; i++)
			{
				var symbol = str[i];
				if(-1 !== indexStr.indexOf(symbol))
				{
					fullListIndex += symbol;
				}
				else
				{
					break;
				}
			}
			return fullListIndex;
		};
		
		//TODO пока делаю так, пересмотреть регулярные выражения
		var resType = Asc.c_oAscNumberingFormat.Bullet;
		var number = parseInt(str);
		var startPos = null, fullListIndex;
		if(!isNaN(number))
		{
			resType = Asc.c_oAscNumberingFormat.Decimal;
			startPos = number;
		}
		else if(1 === str.length && -1 !== str.indexOf("o"))
		{
			resType = Asc.c_oAscNumberingFormat.Bullet;
		}
		else
		{
			//1)смотрим на первый символ в строке
			//2)ищем все символы, соответсвующие данному типу
			//3)находим порядковый номер этих символов
			var firstSymbol = str[0];
			if(-1 !== symbolsArr[0].indexOf(firstSymbol))
			{
				if(getStartPosition)
				{
					fullListIndex = getFullListIndex(symbolsArr[0], str);
					startPos = romanToIndex(fullListIndex);
				}
				
				resType = Asc.c_oAscNumberingFormat.LowerRoman;
			}
			else if(-1 !== symbolsArr[1].indexOf(firstSymbol))
			{
				if(getStartPosition)
				{
					fullListIndex = getFullListIndex(symbolsArr[1], str);
					startPos = romanToIndex(fullListIndex);
				}
				
				resType = Asc.c_oAscNumberingFormat.UpperRoman;
			}
			else if(-1 !== symbolsArr[2].indexOf(firstSymbol))
			{
				if(getStartPosition)
				{
					fullListIndex = getFullListIndex(symbolsArr[2], str);
					startPos = latinToIndex(fullListIndex);
				}
				
				resType = Asc.c_oAscNumberingFormat.LowerLetter;
			}
			else if(-1 !== symbolsArr[3].indexOf(firstSymbol))
			{
				if(getStartPosition)
				{
					fullListIndex = getFullListIndex(symbolsArr[3], str);
					startPos = latinToIndex(fullListIndex);
				}
				
				resType = Asc.c_oAscNumberingFormat.UpperLetter;
			}
		}
		
		return {type: resType, startPos: startPos};
	},
    _AddNextPrevToContent : function(oDoc)
    {
        var prev = null;
        for(var i = 0, length = this.aContent.length; i < length; ++i)
        {
            var cur = this.aContent[i];
            cur.Set_DocumentPrev( prev );
            cur.Parent = oDoc;
            if(prev)
                prev.Set_DocumentNext( cur );
            prev = cur;
        }
    },
    _Set_Run_Pr: function (oPr) {
        this._CommitRunToParagraph(false);
        if (null != this.oCurRun) {
            this.oCurRun.Set_Pr(oPr);
        }
    },
    _CommitRunToParagraph: function (bCreateNew) {
        if (bCreateNew || this.oCurRun.Content.length > 0) {
            this.oCurRun = new ParaRun(this.oCurPar);
            this.oCurRunContentPos = 0;
        }
    },
    _CommitElemToParagraph: function (elem) {
        if (null != this.oCurHyperlink) {
            this.oCurHyperlink.Add_ToContent(this.oCurHyperlinkContentPos, elem, false);
            this.oCurHyperlinkContentPos++;
        }
        else {
            this.oCurPar.Internal_Content_Add(this.oCurParContentPos, elem, false);
            this.oCurParContentPos++;
        }
    },
    _AddToParagraph: function (elem)
    {
        if (null != this.oCurRun) {
            if (para_Hyperlink === elem.Type) {
                this._CommitRunToParagraph(true);
                this._CommitElemToParagraph(elem);
            }
            else {
				if(this.oCurRun.Content.length === Asc.c_dMaxParaRunContentLength) {
					//создаём новый paraRun и выставляем ему настройки предыдущего
					//сделано для того, чтобы избежать большого количества данных в paraRun
					if(this.oCurRun && this.oCurRun.Pr && this.oCurRun.Pr.Copy) {
						this._Set_Run_Pr(this.oCurRun.Pr.Copy());
					}
				}

				this.oCurRun.Add_ToContent(this.oCurRunContentPos, elem, false);
                this.oCurRunContentPos++;
                if (1 === this.oCurRun.Content.length)
                    this._CommitElemToParagraph(this.oCurRun);
            }
		}
    },
    _Add_NewParagraph : function()
    {
        var bFromPresentation = false;
		if(this.pasteInPresentationShape)
			bFromPresentation = true;
			
		this.oCurPar = new Paragraph(this.oDocument.DrawingDocument, this.oDocument, this.oDocument.bPresentation === true );
        this.oCurParContentPos = this.oCurPar.CurPos.ContentPos;
        this.oCurRun = new ParaRun(this.oCurPar);
        this.oCurRunContentPos = 0;
        this.aContent.push(this.oCurPar);
		//сбрасываем настройки теста
        this.oCur_rPr = new CTextPr();
    },
    _Execute_AddParagraph : function(node, pPr)
    {
        this._Add_NewParagraph();
		//Устанавливаем стили параграфа
        this._set_pPr(node, this.oCurPar, pPr);
    },
    _Decide_AddParagraph : function(node, pPr, bParagraphAdded, bCommitBr)
    {
		//Игнорируем пустые параграфы(как браузеры, как MS), добавляем параграф только когда придет текст
        if(true == bParagraphAdded)
        {
            if(false != bCommitBr)
                this._Commit_Br(2, node, pPr);//word игнорируем 2 последних br
            this._Execute_AddParagraph(node, pPr);
        }
        else if(false != bCommitBr)
            this._Commit_Br(0, node, pPr);
        return false;
    },
    _Commit_Br : function(nIgnore, node, pPr)
    {
        for(var i = 0, length = this.nBrCount - nIgnore; i < length; i++)
        {
            if ("always" === pPr["mso-column-break-before"])
                this._AddToParagraph(new ParaNewLine(break_Page));
            else{
                if (this.bInBlock)
                    this._AddToParagraph(new ParaNewLine(break_Line));
                else
                    this._Execute_AddParagraph(node, pPr);
            }
        }
        this.nBrCount = 0;
    },
    _StartExecuteTable : function(node, pPr)
    {
        var oDocument = this.oDocument;
        var tableNode = node, newNode, headNode;

		//Ищем если есть tbody
        for(var i = 0, length = node.childNodes.length; i < length; ++i)
        {
			 var nodeName = node.childNodes[i].nodeName.toLowerCase();
			if("tbody" === nodeName)
            {
                if(!newNode)
				{
					newNode = node.childNodes[i];
					if(headNode) {
						for(var j = 0; j < headNode.childNodes.length; j++)
						{
							newNode.insertBefore(headNode.childNodes[0], newNode.childNodes[0]);
						}
					}
				}
				else
				{
					var lengthChild = node.childNodes[i].childNodes.length;
					for(var j = 0; j < lengthChild; j++)
					{
						newNode.appendChild(node.childNodes[i].childNodes[0]);
					}
				}
            }
            else if("thead" === nodeName)
			{
				headNode = node.childNodes[i];
			}
        }

		if(newNode)
		{
			node = newNode;
			tableNode = newNode;
		}

		//валидация талиц. В таблице не может быть строк состоящих из вертикально замерженых ячеек.
        var nRowCount = 0;
        var nMinColCount = 0;
        var nMaxColCount = 0;
        var aColsCountByRow = [];
        var oRowSums = {};
        oRowSums[0] = 0;
        var dMaxSum = 0;
        var nCurColWidth = 0;
        var nCurSum = 0;
		var nAllSum = 0;
        var oRowSpans = {};
		var columnSize = ((!window["Asc"] || (window["Asc"] && window["Asc"]["editor"] === undefined))) && this.oLogicDocument ? this.oLogicDocument.GetColumnSize() : null;
        var fParseSpans = function()
        {
            var spans = oRowSpans[nCurColWidth];
            while(null != spans && spans.row > 0)
            {
                spans.row--;
                nCurColWidth += spans.col;
                nCurSum += spans.width;
                spans = oRowSpans[nCurColWidth];
            }
        };
        for(var i = 0, length = node.childNodes.length; i < length; ++i)
        {
            var tr = node.childNodes[i];
            if("tr" === tr.nodeName.toLowerCase())
            {
                nCurSum = 0;
                nCurColWidth = 0;
                var minRowSpanIndex = null;
                var nMinRowSpanCount = null;//минимальный rowspan ячеек строки
                for(var j = 0, length2 = tr.childNodes.length; j < length2; ++j)
                {
                    var tc = tr.childNodes[j];
                    var tcName = tc.nodeName.toLowerCase();
                    if("td" === tcName || "th" === tcName)
                    {
                        fParseSpans();

                        var dWidth = null;
                        var computedStyle = this._getComputedStyle(tc);
						var computedWidth = this._getStyle(tc, computedStyle, "width");
						if(null != computedWidth && null != (computedWidth = this._ValueToMm(computedWidth)))
							dWidth = computedWidth;

                        if(null == dWidth)
                            dWidth = tc.clientWidth * g_dKoef_pix_to_mm;

                        var nColSpan = tc.getAttribute("colspan");
                        if(null != nColSpan)
                            nColSpan = nColSpan - 0;
                        else
                            nColSpan = 1;
                        var nCurRowSpan = tc.getAttribute("rowspan");
                        if(null != nCurRowSpan)
                        {
                            nCurRowSpan = nCurRowSpan - 0;
							if(null == nMinRowSpanCount)
							{
								nMinRowSpanCount = nCurRowSpan;
								minRowSpanIndex = j;
							}
							else if(nMinRowSpanCount > nCurRowSpan)
							{
								nMinRowSpanCount = nCurRowSpan;
								minRowSpanIndex = j;
							}

                            if(nCurRowSpan > 1)
                                oRowSpans[nCurColWidth] = {row: nCurRowSpan - 1, col: nColSpan, width: dWidth};
                        }
                        else
						{
							nMinRowSpanCount = 0;
							minRowSpanIndex = j;
						}

                        nCurSum += dWidth;
                        if(null == oRowSums[nCurColWidth + nColSpan])
						{
							oRowSums[nCurColWidth + nColSpan] = nCurSum;
						}
						else if(null != oRowSums[nCurColWidth + nColSpan - 1] && oRowSums[nCurColWidth + nColSpan - 1] >= oRowSums[nCurColWidth + nColSpan])
						{
							oRowSums[nCurColWidth + nColSpan] += nCurSum;
						}
                        nCurColWidth += nColSpan;
                    }
                }
				nAllSum += nCurSum;
                fParseSpans();
				//Удаляем лишние rowspan
                if(nMinRowSpanCount > 1)
                {
                    for(var j = 0, length2 = tr.childNodes.length; j < length2; ++j)
                    {
                        var tc = tr.childNodes[j];
                        var tcName = tc.nodeName.toLowerCase();
                        if(minRowSpanIndex !== j && ("td" === tcName || "th" === tcName))
                        {
                            var nCurRowSpan = tc.getAttribute("rowspan");
                            if(null != nCurRowSpan)
                                tc.setAttribute("rowspan", nCurRowSpan - nMinRowSpanCount);
                        }
                    }
                }
                if(dMaxSum < nCurSum)
                    dMaxSum = nCurSum;
				//удаляем пустые tr
                if(0 == nCurColWidth)
				{
                    node.removeChild(tr);
					length--;
					i--;
				}
                else
                {
                    if(0 == nMinColCount || nMinColCount > nCurColWidth)
                        nMinColCount = nCurColWidth;
                    if(nMaxColCount < nCurColWidth)
                        nMaxColCount = nCurColWidth;
                    nRowCount++;
                    aColsCountByRow.push(nCurColWidth);
                }
            }
        }
        if(nMaxColCount != nMinColCount)
        {
            for(var i = 0, length = aColsCountByRow.length; i < length; ++i)
                aColsCountByRow[i] = nMaxColCount - aColsCountByRow[i];
        }
        if(nRowCount > 0 && nMaxColCount > 0)
        {
            var bUseScaleKoef = this.bUseScaleKoef;
            var dScaleKoef = this.dScaleKoef;
            if(dMaxSum * dScaleKoef > this.dMaxWidth)
            {
                dScaleKoef = dScaleKoef * this.dMaxWidth / dMaxSum;
                bUseScaleKoef = true;
            }
			//строим Grid
            var aGrid = [];
            var nPrevIndex = null;
            var nPrevVal = 0;
            for(var i in oRowSums)
            {
                var nCurIndex = i - 0;
                var nCurVal = oRowSums[i];
                var nCurWidth = nCurVal - nPrevVal;
                if(bUseScaleKoef)
                    nCurWidth *= dScaleKoef;
                if(null != nPrevIndex)
                {
                    var nDif = nCurIndex - nPrevIndex;
                    if(1 === nDif)
					{
						if(!nCurWidth && !nAllSum && columnSize)
						{
							aGrid.push(columnSize.W / nMaxColCount);
						}
						else
						{
							aGrid.push(nCurWidth);
						}
					} 
                    else
                    {
                        var nPartVal = nCurWidth / nDif;
                        for(var i = 0; i < nDif; ++i)
                            aGrid.push(nPartVal);
                    }
                }
                nPrevVal = nCurVal;
                nPrevIndex = nCurIndex;
            }
			var CurPage = 0;
            var table = new CTable(oDocument.DrawingDocument, oDocument, true, 0, 0, aGrid);
			//считаем aSumGrid
			var aSumGrid = [];
			aSumGrid[-1] = 0;
			var nSum = 0;
			for(var i = 0, length = aGrid.length; i < length; ++i)
			{
				nSum += aGrid[i];
				aSumGrid[i] = nSum;
			}
			//набиваем content
            this._ExecuteTable(tableNode, node, table, aSumGrid, nMaxColCount !== nMinColCount ? aColsCountByRow : null, pPr, bUseScaleKoef, dScaleKoef);
            table.MoveCursorToStartPos();
            this.aContent.push(table);
        }
    },
    _ExecuteBorder : function(computedStyle, node, type, type2, bAddIfNull, setUnifill)
    {
        var res = null;
        var style = this._getStyle(node, computedStyle, "border-"+type+"-style");
        if(null != style)
        {
            res = new CDocumentBorder();
            if("none" === style || "" === style)
                res.Value = border_None;
            else
            {
                res.Value = border_Single;
                var width = node.style["border"+type2+"Width"];
                if(!width)
					width = this._getStyle(node, computedStyle, "border-"+type+"-width");
                if(null != width && null != (width = this._ValueToMm(width)))
                    res.Size = width;
                var color = this._getStyle(node, computedStyle, "border-"+type+"-color");
                if(null != color && (color = this._ParseColor(color)))
                {
                    if(setUnifill && color)
                    {
                        res.Unifill = AscFormat.CreteSolidFillRGB(color.r, color.g, color.b);
                    }
                    else
                    {
                        res.Color = color;
                    }
                }
            }
        }
        if(bAddIfNull && null == res)
            res = new CDocumentBorder();
        return res;
    },
    _ExecuteParagraphBorder : function(border)
    {
        var res = this.oBorderCache[border];
        if(null != res)
            return res.Copy();
        else
        {
			//сделано через dom чтобы не писать большую функцию разбора строки
			//todo сделать без dom, анализируя текст.
            res = new CDocumentBorder();
            var oTestDiv = document.createElement("div");
            oTestDiv.setAttribute("style", "border-left:"+border);
            document.body.appendChild( oTestDiv );
            var computedStyle = this._getComputedStyle(oTestDiv);
            if(null != computedStyle)
            {
                res = this._ExecuteBorder(computedStyle, oTestDiv, "left", "Left", true);
            }
            document.body.removeChild( oTestDiv );
            this.oBorderCache[border] = res;
            return res;
        }
    },
    _ExecuteTable : function(tableNode, node, table, aSumGrid, aColsCountByRow, pPr, bUseScaleKoef, dScaleKoef)
    {
		table.SetTableLayout(tbllayout_AutoFit);
        //Pr
        var Pr = table.Pr;
		//align смотрим у parent tableNode
		var sTableAlign = null;
		if(null != tableNode.align)
			sTableAlign = tableNode.align;
        else if(null != tableNode.parentNode && this.oRootNode != tableNode.parentNode)
        {
            var computedStyleParent = this._getComputedStyle(tableNode.parentNode);
			sTableAlign = this._getStyle(tableNode.parentNode, computedStyleParent, "text-align");
        }
		if(null != sTableAlign)
		{
			if(-1 !== sTableAlign.indexOf('center'))
				table.Set_TableAlign(align_Center);
			else if(-1 !== sTableAlign.indexOf('right'))
				table.Set_TableAlign(align_Right);
		}
        var spacing = null;
        table.Set_TableBorder_InsideH(new CDocumentBorder());
        table.Set_TableBorder_InsideV(new CDocumentBorder());

        var style = tableNode.getAttribute("style");
        if(style)
        {
            var tblPrMso = {};
            this._parseCss(style, tblPrMso);
            var spacing = tblPrMso["mso-cellspacing"];
            if(null != spacing && null != (spacing = this._ValueToMm(spacing)))
                ;
            var padding = tblPrMso["mso-padding-alt"];
            if(null != padding)
            {
                padding = trimString(padding);
                var aMargins = padding.split(" ");
                if(4 === aMargins.length)
                {
                    var top = aMargins[0];
                    if(null != top && null != (top = this._ValueToMm(top)))
                        ;
                    else
                        top = Pr.TableCellMar.Top.W;
                    var right = aMargins[1];
                    if(null != right && null != (right = this._ValueToMm(right)))
                        ;
                    else
                        right = Pr.TableCellMar.Right.W;
                    var bottom = aMargins[2];
                    if(null != bottom && null != (bottom = this._ValueToMm(bottom)))
                        ;
                    else
                        bottom = Pr.TableCellMar.Bottom.W;
                    var left = aMargins[3];
                    if(null != left && null != (left = this._ValueToMm(left)))
                        ;
                    else
                        left = Pr.TableCellMar.Left.W;
                    table.Set_TableCellMar(left, top, right, bottom);
                }
            }
            var insideh = tblPrMso["mso-border-insideh"];
            if(null != insideh)
                table.Set_TableBorder_InsideH(this._ExecuteParagraphBorder(insideh));
            var insidev = tblPrMso["mso-border-insidev"];
            if(null != insidev)
                table.Set_TableBorder_InsideV(this._ExecuteParagraphBorder(insidev));
        }
		var computedStyle = this._getComputedStyle(tableNode);
		if(align_Left === table.Get_TableAlign())
		{
			var margin_left = this._getStyle(tableNode, computedStyle, "margin-left");
			//todo возможно надо еще учесть ширину таблицы
			if(margin_left && null != (margin_left = this._ValueToMm(margin_left)) && margin_left < Page_Width - X_Left_Margin)
				table.Set_TableInd(margin_left);
		}
		var background_color = this._getStyle(tableNode, computedStyle, "background-color");
		if(null != background_color && (background_color = this._ParseColor(background_color)))
			table.Set_TableShd(c_oAscShdClear, background_color.r, background_color.g, background_color.b);
		var oLeftBorder = this._ExecuteBorder(computedStyle, tableNode, "left", "Left", false);
		if(null != oLeftBorder)
			table.Set_TableBorder_Left(oLeftBorder);
		var oTopBorder = this._ExecuteBorder(computedStyle, tableNode, "top", "Top", false);
		if(null != oTopBorder)
			table.Set_TableBorder_Top(oTopBorder);
		var oRightBorder = this._ExecuteBorder(computedStyle, tableNode, "right", "Right", false);
		if(null != oRightBorder)
			table.Set_TableBorder_Right(oRightBorder);
		var oBottomBorder = this._ExecuteBorder(computedStyle, tableNode, "bottom", "Bottom", false);
		if(null != oBottomBorder)
			table.Set_TableBorder_Bottom(oBottomBorder);

		if(null == spacing)
		{
			spacing = this._getStyle(tableNode, computedStyle, "padding");
			if(!spacing)
				spacing = tableNode.style.padding;
			if(!spacing)
				spacing = null;
			if(spacing && null != (spacing = this._ValueToMm(spacing)))
				;
		}

        //content
        var oRowSpans = {};
        for(var i = 0, length = node.childNodes.length; i < length; ++i)
        {
            var tr = node.childNodes[i];
			//TODO временная правка в условии для того, чтобы избежать ошибки при копировании из excel мерженной ячейки
            if("tr" === tr.nodeName.toLowerCase() && tr.childNodes && tr.childNodes.length)
            {
				var row = table.Internal_Add_Row(table.Content.length, 0);
                this._ExecuteTableRow(tr, row, aSumGrid, spacing, oRowSpans, bUseScaleKoef, dScaleKoef);
            }
        }
    },
    _ExecuteTableRow : function(node, row, aSumGrid, spacing, oRowSpans, bUseScaleKoef, dScaleKoef)
    {
        var oThis = this;
        var table = row.Table;
		var oTableSpacingMinValue = ("undefined" !== typeof tableSpacingMinValue) ? tableSpacingMinValue : 0.02;
        if(null != spacing && spacing >= oTableSpacingMinValue)
            row.Set_CellSpacing(spacing);
        if(node.style.height)
        {
            var height = node.style.height;
            if(!("auto" === height || "inherit" === height || -1 !== height.indexOf("%")) && null != (height = this._ValueToMm(height)))
                row.Set_Height(height, Asc.linerule_AtLeast);
        }
		var bBefore = false;
		var bAfter = false;
        var style = node.getAttribute("style");
        if(null != style)
        {
            var tcPr = {};
            this._parseCss(style, tcPr);
            var margin_left = tcPr["mso-row-margin-left"];
            if(margin_left && null != (margin_left = this._ValueToMm(margin_left)))
                bBefore = true;
            var margin_right = tcPr["mso-row-margin-right"];
            if(margin_right && null != (margin_right = this._ValueToMm(margin_right)))
                bAfter = true;
        }

        //content
        var nCellIndex = 0;
        var nCellIndexSpan = 0;
        var fParseSpans = function()
        {
            var spans = oRowSpans[nCellIndexSpan];
            while(null != spans)
            {
				var oCurCell = row.Add_Cell(row.Get_CellsCount(), row, null, false);
				oCurCell.SetVMerge(vmerge_Continue);
                if(spans.col > 1)
                    oCurCell.Set_GridSpan(spans.col);
                spans.row--;
				if(spans.row <= 0)
					delete oRowSpans[nCellIndexSpan];
                nCellIndexSpan += spans.col;
                spans = oRowSpans[nCellIndexSpan];
            }
        };
		var oBeforeCell = null;
		var oAfterCell = null;
		if(bBefore || bAfter)
		{
			for(var i = 0, length = node.childNodes.length; i < length; ++i)
			{
				var tc = node.childNodes[i];
				var tcName = tc.nodeName.toLowerCase();
				if("td" === tcName || "th" === tcName)
				{
					if(bBefore && null != oBeforeCell)
						oBeforeCell = tc;
					else if(bAfter)
						oAfterCell = tc;
				}
			}
		}
        for(var i = 0, length = node.childNodes.length; i < length; ++i)
        {
			//важно чтобы этот код был после определения td, потому что вертикально замерженые ячейки отсутствуют в dom
            fParseSpans();

            var tc = node.childNodes[i];
            var tcName = tc.nodeName.toLowerCase();
            if("td" === tcName || "th" === tcName)
            {
                var nColSpan = tc.getAttribute("colspan");
                if(null != nColSpan)
                    nColSpan = nColSpan - 0;
                else
                    nColSpan = 1;
				if(tc === oBeforeCell)
					row.Set_Before(nColSpan);
				else if(tc === oAfterCell)
					row.Set_After(nColSpan);
				else
				{
					var oCurCell = row.Add_Cell(row.Get_CellsCount(), row, null, false);
					if(nColSpan > 1)
						oCurCell.Set_GridSpan(nColSpan);
					var width = aSumGrid[nCellIndexSpan + nColSpan - 1] - aSumGrid[nCellIndexSpan - 1];
					oCurCell.Set_W(new CTableMeasurement(tblwidth_Mm, width));
					var nRowSpan = tc.getAttribute("rowspan");
					if(null != nRowSpan)
						nRowSpan = nRowSpan - 0;
					else
						nRowSpan = 1;
					if(nRowSpan > 1)
						oRowSpans[nCellIndexSpan] = {row: nRowSpan - 1, col: nColSpan};
					this._ExecuteTableCell(tc, oCurCell, bUseScaleKoef, dScaleKoef, spacing);
				}
                nCellIndexSpan+=nColSpan;
            }
        }
        fParseSpans();
    },
    _ExecuteTableCell : function(node, cell, bUseScaleKoef, dScaleKoef, spacing)
    {
        //Pr
        var Pr = cell.Pr;
        var bAddIfNull = false;
        if(null != spacing)
            bAddIfNull = true;
		var computedStyle = this._getComputedStyle(node);
		var background_color = this._getStyle(node, computedStyle, "background-color");
		if(null != background_color && (background_color = this._ParseColor(background_color)))
		{
			var Shd = new CDocumentShd();
			Shd.Value = c_oAscShdClear;
			Shd.Color = background_color;
			cell.Set_Shd(Shd);
		}
		var border = this._ExecuteBorder(computedStyle, node, "left", "Left", bAddIfNull);
		if(null != border)
			cell.Set_Border(border, 3);
		var border = this._ExecuteBorder(computedStyle, node, "top", "Top", bAddIfNull);
		if(null != border)
			cell.Set_Border(border, 0);
		var border = this._ExecuteBorder(computedStyle, node, "right", "Right", bAddIfNull);
		if(null != border)
			cell.Set_Border(border, 1);
		var border = this._ExecuteBorder(computedStyle, node, "bottom", "Bottom", bAddIfNull);
		if(null != border)
			cell.Set_Border(border, 2);

		var top = this._getStyle(node, computedStyle, "padding-top");
		if(null != top && null != (top = this._ValueToMm(top)))
			cell.Set_Margins({ W : top, Type : tblwidth_Mm }, 0);
		var right = this._getStyle(node, computedStyle, "padding-right");
		if(null != right && null != (right = this._ValueToMm(right)))
			cell.Set_Margins({ W : right, Type : tblwidth_Mm }, 1);
		var bottom = this._getStyle(node, computedStyle, "padding-bottom");
		if(null != bottom && null != (bottom = this._ValueToMm(bottom)))
			cell.Set_Margins({ W : bottom, Type : tblwidth_Mm }, 2);
		var left = this._getStyle(node, computedStyle, "padding-left");
		if(null != left && null != (left = this._ValueToMm(left)))
			cell.Set_Margins({ W : left, Type : tblwidth_Mm }, 3);

        //content
        var oPasteProcessor = new PasteProcessor(this.api, false, false, true);
        oPasteProcessor.oFonts = this.oFonts;
        oPasteProcessor.oImages = this.oImages;
        oPasteProcessor.oDocument = cell.Content;
        oPasteProcessor.bIgnoreNoBlockText = true;
        oPasteProcessor.dMaxWidth = this._CalcMaxWidthByCell(cell);
        if(true === bUseScaleKoef)
        {
            oPasteProcessor.bUseScaleKoef = bUseScaleKoef;
            oPasteProcessor.dScaleKoef = dScaleKoef;
        }
		oPasteProcessor._Execute(node, {}, true, true, false);
        oPasteProcessor._PrepareContent();
        oPasteProcessor._AddNextPrevToContent(cell.Content);
        if(0 === oPasteProcessor.aContent.length)
        {
            var oDocContent = cell.Content;
            var oNewPar = new Paragraph(oDocContent.DrawingDocument, oDocContent);
			//выставляем единичные настройки - важно для копирования из таблиц и других мест где встречаются пустые ячейки
			var oNewSpacing = new CParaSpacing();
			oNewSpacing.Set_FromObject({After: 0, Before: 0, Line: Asc.linerule_Auto});
            oNewPar.Set_Spacing(oNewSpacing);
            oPasteProcessor.aContent.push(oNewPar);
        }
		//добавляем новый параграфы
        for(var i = 0, length = oPasteProcessor.aContent.length; i < length; ++i)
		{
			if(i === length - 1)
				cell.Content.Internal_Content_Add(i + 1, oPasteProcessor.aContent[i], true);
			else
				cell.Content.Internal_Content_Add(i + 1, oPasteProcessor.aContent[i], false);
		}
		//Удаляем параграф, который создается в таблице по умолчанию
        cell.Content.Internal_Content_Remove(0, 1);
    },
	_CheckIsPlainText : function(node, dNotCheckFirstElem)
	{
		var bIsPlainText = true;

		var checkStyle = function (elem) {
			var res = false;
			var sClass = elem.getAttribute("class");
			var sStyle = elem.getAttribute("style");
			var sHref = elem.getAttribute("href");

			if (sClass || sStyle || sHref) {
				res = true;
			}
			return res;
		};

		//проверяем верхний элемент
		//в случае с плагинами - контент оборачивается в дивку, которая может иметь свои стили
		if ("body" !== node.nodeName.toLowerCase() && !dNotCheckFirstElem) {
			if (Node.ELEMENT_NODE === node.nodeType) {
				if (checkStyle(node)) {
					return false;
				}
			}
		}

		for (var i = 0, length = node.childNodes.length; i < length; i++) {
			var child = node.childNodes[i];
			if (Node.ELEMENT_NODE === child.nodeType) {
				if (checkStyle(child)) {
					bIsPlainText = false;
					break;
				} else if (!this._CheckIsPlainText(child, true)) {
					bIsPlainText = false;
					break;
				}
					
			}
		}
		return bIsPlainText;
	},

	_Execute: function (node, pPr, bRoot, bAddParagraph, bInBlock, arrShapes, arrImages, arrTables) {

		//bAddParagraph флаг влияющий на функцию _Decide_AddParagraph, добавлять параграф или нет.
		//bAddParagraph выставляется в true, когда встретился блочный элемент и по окончанию блочного элемента

		var oThis = this;
		var bRootHasBlock = false;//Если root есть блочный элемент, то надо все child считать параграфами
		//Для Root node не смотрим стили и не добавляем текст
		//var presentation = editor.WordControl.m_oLogicDocument;

		var parseTextNode = function () {
			var value = node.nodeValue;
			if (!value) {
				value = "";
			}

			var whiteSpacing = false;
			if(node.parentNode)
			{
				var computedStyle = oThis._getComputedStyle(node.parentNode);
				whiteSpacing = "pre" === oThis._getStyle(node.parentNode, computedStyle, "white-space");
			}

			//Вначале и конце вырезаем \r|\t|\n, в середине текста заменяем их на пробелы
			//потому что(например иногда chrome при вставке разбивает строки с помощью \n)
			if(!whiteSpacing)
			{
				value = value.replace(/^(\r|\t|\n)+|(\r|\t|\n)+$/g, '');
				value = value.replace(/(\r|\t|\n)/g, ' ');

				//TODO проверить в каких случаях пробелы учитываются, в каких игнорируются
				//пока делаю проверку на div с пробелами
				if(node && node.parentNode && "div" === node.parentNode.nodeName.toLowerCase()) {
					var checkSpaces = value.replace(/(\s)/g, '');
					if(checkSpaces === "") {
						value = "";
					}
				}
			}

			var Item;
			if (value.length > 0) {
				if (bPresentation) {
					oThis.oDocument = shape.txBody.content;
					if (bAddParagraph) {
						shape.txBody.content.AddNewParagraph();
					}
					// bAddParagraph = this._Decide_AddParagraph(node.parentNode, pPr, bAddParagraph);

					//Добавляет элемени стиля если он поменялся
					//this._commit_rPr(node.parentNode);

					if (!oThis.bIsPlainText) {
						var rPr = oThis._read_rPr(node.parentNode);
						Item = new ParaTextPr(rPr);
						shape.paragraphAdd(Item, false);
					}
				} else {
					var oTargetNode = node.parentNode;
					var bUseOnlyInherit = false;
					if (oThis._IsBlockElem(oTargetNode.nodeName.toLowerCase())) {
						bUseOnlyInherit = true;
					}
					bAddParagraph = oThis._Decide_AddParagraph(oTargetNode, pPr, bAddParagraph);

					//Добавляет элемени стиля если он поменялся
					oThis._commit_rPr(oTargetNode, bUseOnlyInherit);
				}

				//TODO поправить проблему с лишними прообелами в начале новой строки при копировании из MS EXCEL ячеек с текстом, разделенным alt+enter
				//bIsPreviousSpace - игнорируем несколько пробелов подряд
				var bIsPreviousSpace = false;

				for (var oIterator = value.getUnicodeIterator(); oIterator.check(); oIterator.next())
				{
					var nUnicode = oIterator.value();

					if (bPresentation)
					{
						if (null !== nUnicode)
						{
							if (0x20 !== nUnicode && 0xA0 !== nUnicode && 0x2009 !== nUnicode)
								Item = new ParaText(nUnicode);
							else
								Item = new ParaSpace();

							shape.paragraphAdd(Item, false);
						}
					}
					else
					{
						if (null != nUnicode)
						{
							if(whiteSpacing && 0xa === nUnicode)
							{
								Item = null;
								bAddParagraph = oThis._Decide_AddParagraph(oTargetNode, pPr, true);
								oThis._commit_rPr(oTargetNode, bUseOnlyInherit);
							}
							else if(whiteSpacing && (0x9 === nUnicode || 0x2009 === nUnicode))
							{
								Item = new ParaTab();
							}
							else if (0x20 !== nUnicode && 0x2009 !== nUnicode)
							{
								Item = new ParaText(nUnicode);
								bIsPreviousSpace = false;
							}
							else
							{
								Item = new ParaSpace();
								if (bIsPreviousSpace)
								{
									continue;
								}
								if (!oThis.bIsPlainText && !whiteSpacing)
								{
									bIsPreviousSpace = true;
								}
							}
							if(null !== Item)
							{
								oThis._AddToParagraph(Item);
							}
						}
					}

				}
			}
		};

		var parseNumbering = function () {
			if ("ul" === sNodeName || "ol" === sNodeName || "li" === sNodeName) {
				if (bPresentation) {
					pPr.bNum = true;
					if (PasteElementsId.g_bIsDocumentCopyPaste) {
						if ("ul" === sNodeName) {
							pPr.numType = Asc.c_oAscNumberingFormat.Bullet;
						} else if ("ol" ===
							sNodeName) {
							pPr.numType = Asc.c_oAscNumberingFormat.Decimal;
						}
					} else {
						if ("ul" === sNodeName) {
							pPr.numType = numbering_presentationnumfrmt_Char;
						} else if ("ol" ===
							sNodeName) {
							pPr.numType = numbering_presentationnumfrmt_ArabicPeriod;
						}
					}
				} else {
					//в данном случае если нет тега li, то списоком не считаем
					if ("li" === sNodeName) {
						pPr.bNum = true;
					}

					if (PasteElementsId.g_bIsDocumentCopyPaste) {
						if ("ul" === sNodeName) {
							pPr.numType = Asc.c_oAscNumberingFormat.Bullet;
						} else if ("ol" ===
							sNodeName) {
							pPr.numType = Asc.c_oAscNumberingFormat.Decimal;
						}
					} else {
						if ("ul" === sNodeName) {
							pPr.numType = numbering_presentationnumfrmt_Char;
						} else if ("ol" ===
							sNodeName) {
							pPr.numType = numbering_presentationnumfrmt_ArabicPeriod;
						}
					}
				}
			} else if (pPr["mso-list"] && !bPresentation) {
				if ("p" === sNodeName) {
					pPr.bNum = true;
				}
			}
		};

		var parseStyle = function () {
			//собираем не html свойства параграфа(те что нельзя получить из getComputedStyle)
			var style = node.getAttribute("style");
			if (style) {
				oThis._parseCss(style, pPr);
			}

			if ("h1" === sNodeName) {
				pPr.hLevel = 0;
			} else if ("h2" === sNodeName) {
				pPr.hLevel = 1;
			} else if ("h3" ===
				sNodeName) {
				pPr.hLevel = 2;
			} else if ("h4" === sNodeName) {
				pPr.hLevel = 3;
			} else if ("h5" ===
				sNodeName) {
				pPr.hLevel = 4;
			} else if ("h6" === sNodeName) {
				pPr.hLevel = 5;
			}
		};

		var parseImage = function () {
			if (bPresentation) {
				//bAddParagraph = oThis._Decide_AddParagraph(node, pPr, bAddParagraph);

				var nWidth = parseInt(node.getAttribute("width"));
				var nHeight = parseInt(node.getAttribute("height"));
				if (!nWidth || !nHeight) {
					var computedStyle = oThis._getComputedStyle(node);
					nWidth = parseInt(oThis._getStyle(node, computedStyle, "width"));
					nHeight = parseInt(oThis._getStyle(node, computedStyle, "height"));
				}
				var sSrc = node.getAttribute("src");
				if (sSrc && (isNaN(nWidth) || isNaN(nHeight) || !(typeof nWidth === "number") ||
					!(typeof nHeight === "number") || nWidth === 0 || nHeight === 0)) {
					var img_prop = new Asc.asc_CImgProperty();
					img_prop.asc_putImageUrl(sSrc);
					var or_sz = img_prop.asc_getOriginSize(editor);
					nWidth = or_sz.Width / g_dKoef_pix_to_mm;
					nHeight = or_sz.Height / g_dKoef_pix_to_mm;
				} else {
					nWidth *= g_dKoef_pix_to_mm;
					nHeight *= g_dKoef_pix_to_mm;
				}
				if (nWidth && nHeight && sSrc) {
					var sSrc = oThis.oImages[sSrc];
					if (sSrc) {
						var image = AscFormat.DrawingObjectsController.prototype.createImage(sSrc, 0, 0, nWidth,
							nHeight);
						arrImages.push(image);
					}
				}
				return bAddParagraph;
			} else {
				if (PasteElementsId.g_bIsDocumentCopyPaste) {
					bAddParagraph = oThis._Decide_AddParagraph(node, pPr, bAddParagraph);

					var nWidth = parseInt(node.getAttribute("width"));
					var nHeight = parseInt(node.getAttribute("height"));
					if (!nWidth || !nHeight) {
						var computedStyle = oThis._getComputedStyle(node);
						nWidth = parseInt(oThis._getStyle(node, computedStyle, "width"));
						nHeight = parseInt(oThis._getStyle(node, computedStyle, "height"));
					}

					//TODO пересмотреть! node.getAttribute("width") в FF возврашает "auto" -> изображения в FF не всталяются
					if ((!nWidth || !nHeight)) {
						if (AscBrowser.isMozilla || AscBrowser.isIE) {
							nWidth = parseInt(node.width);
							nHeight = parseInt(node.height);
						} else if (AscBrowser.isChrome) {
							if (nWidth && !nHeight) {
								nHeight = nWidth;
							} else if (!nWidth && nHeight) {
								nWidth = nHeight;
							} else {
								nWidth = parseInt(node.width);
								nHeight = parseInt(node.height);
							}
						}
					}

					var sSrc = node.getAttribute("src");
					if ((!window["Asc"] || (window["Asc"] && window["Asc"]["editor"] === undefined)) &&
						(isNaN(nWidth) || isNaN(nHeight) || !(typeof nWidth === "number") ||
						!(typeof nHeight === "number")//первое условие - мы не в редакторе таблиц, тогда выполняем
						|| nWidth === 0 || nHeight === 0) && sSrc) {
						var img_prop = new Asc.asc_CImgProperty();
						img_prop.asc_putImageUrl(sSrc);
						var or_sz = img_prop.asc_getOriginSize(editor);
						nWidth = or_sz.Width / g_dKoef_pix_to_mm;
						nHeight = or_sz.Height / g_dKoef_pix_to_mm;
					}

					if (!nWidth) {
						nWidth = oThis.defaultImgWidth / g_dKoef_pix_to_mm;
					}
					if (!nHeight) {
						nHeight = oThis.defaultImgHeight / g_dKoef_pix_to_mm;
					}

					if (nWidth && nHeight && sSrc) {
						var sSrc = oThis.oImages[sSrc];
						if (sSrc) {
							nWidth = nWidth * g_dKoef_pix_to_mm;
							nHeight = nHeight * g_dKoef_pix_to_mm;
							//вписываем в oThis.dMaxWidth
							var bUseScaleKoef = oThis.bUseScaleKoef;
							var dScaleKoef = oThis.dScaleKoef;
							if (nWidth * dScaleKoef > oThis.dMaxWidth) {
								dScaleKoef = dScaleKoef * oThis.dMaxWidth / nWidth;
								bUseScaleKoef = true;
							}
							//закомментировал, потому что при вставке получаем изображения измененного размера
							/*if(bUseScaleKoef)
							 {
							 var dTemp = nWidth;
							 nWidth *= dScaleKoef;
							 nHeight *= dScaleKoef;
							 }*/
							var oTargetDocument = oThis.oDocument;
							var oDrawingDocument = oThis.oDocument.DrawingDocument;
							if (oTargetDocument && oDrawingDocument) {
								//если добавляем изображение в гиперссылку, то кладём его в отдельный ран и делаем не подчёркнутым
								if (oThis.oCurHyperlink) {
									oThis._CommitElemToParagraph(oThis.oCurRun);
									oThis.oCurRun = new ParaRun(oThis.oCurPar);
									oThis.oCurRun.Pr.Underline = false;
								}

								var Drawing = CreateImageFromBinary(sSrc, nWidth, nHeight);
								// oTargetDocument.DrawingObjects.Add( Drawing );

								oThis._AddToParagraph(Drawing);

								if (oThis.oCurHyperlink) {
									oThis.oCurRun = new ParaRun(oThis.oCurPar);
								}

								//oDocument.AddInlineImage(nWidth, nHeight, img);
							}
						}
					}

					return bAddParagraph;
				} else {
					return false;
				}
			}
		};

		var parseLineBreak = function () {
			if (bPresentation) {
				//Добавляем linebreak, если он не разделяет блочные элементы и до этого был блочный элемент
				if ("br" === sNodeName || "always" === node.style.pageBreakBefore) {
					if ("always" === node.style.pageBreakBefore) {
						shape.paragraphAdd(new ParaNewLine(break_Line), false);
					} else {
						shape.paragraphAdd(new ParaNewLine(break_Line), false);
					}
				}
			} else {
				//Добавляем linebreak, если он не разделяет блочные элементы и до этого был блочный элемент
				var bPageBreakBefore = "always" === node.style.pageBreakBefore ||
					"left" === node.style.pageBreakBefore || "right" === node.style.pageBreakBefore;
				if ("br" == sNodeName || bPageBreakBefore) {
					if (bPageBreakBefore) {
						bAddParagraph = oThis._Decide_AddParagraph(node.parentNode, pPr, bAddParagraph);
						bAddParagraph = true;
						oThis._Commit_Br(0, node, pPr);
						oThis._AddToParagraph(new ParaNewLine(break_Page));
					} else {
						bAddParagraph = oThis._Decide_AddParagraph(node.parentNode, pPr, bAddParagraph, false);
						oThis.nBrCount++;//oThis._AddToParagraph( new ParaNewLine( break_Line ) );
						if ("line-break" === pPr["mso-special-character"] ||
							"always" === pPr["mso-column-break-before"]) {
							oThis._Commit_Br(0, node, pPr);
						}
						return bAddParagraph;
					}
				}
			}
			return null;
		};

		var parseTab = function () {
			var nTabCount;
			if (bPresentation) {
				nTabCount = parseInt(pPr["mso-tab-count"] || 0);
				if (nTabCount > 0) {
					if (!oThis.bIsPlainText) {
						var rPr = oThis._read_rPr(node);
						var Item = new ParaTextPr(rPr);
						shape.paragraphAdd(Item, false);
					}
					for (var i = 0; i < nTabCount; i++) {
						shape.paragraphAdd(new ParaTab(), false);
					}
					return;
				}
			} else {
				nTabCount = parseInt(pPr["mso-tab-count"] || 0);
				if (nTabCount > 0) {
					bAddParagraph = oThis._Decide_AddParagraph(node, pPr, bAddParagraph);
					oThis._commit_rPr(node);
					for (var i = 0; i < nTabCount; i++) {
						oThis._AddToParagraph(new ParaTab());
					}
					return bAddParagraph;
				}
			}

			return null;
		};

		var parseChildNodes = function(){
			if (bPresentation) {
				if (!(Node.ELEMENT_NODE === nodeType || Node.TEXT_NODE === nodeType)) {
					return;
				}
				//попускам элеметы состоящие только из \t,\n,\r
				if (Node.TEXT_NODE === child.nodeType) {
					var value = child.nodeValue;
					if (!value) {
						return;
					}
					value = value.replace(/(\r|\t|\n)/g, '');
					if ("" == value) {
						return;
					}
				}
				var sChildNodeName = child.nodeName.toLowerCase();
				var bIsBlockChild = oThis._IsBlockElem(sChildNodeName);
				if (bRoot) {
					oThis.bInBlock = false;
				}
				if (bIsBlockChild) {
					bAddParagraph = true;
					oThis.bInBlock = true;
				}

				var bHyperlink = false;
				var isPasteHyperlink = null;
				if ("a" === sChildNodeName) {
					var href = child.href;
					if (null != href) {
						var sDecoded;
						//decodeURI может выдавать malformed exception, потому что наш сайт в utf8, а некоторые сайты могут кодировать url в своей кодировке(например windows-1251)
						try {
							sDecoded = decodeURI(href);
						} catch (e) {
							sDecoded = href;
						}
						href = sDecoded;
						bHyperlink = true;
						var title = child.getAttribute("title");

						oThis.oDocument = shape.txBody.content;

						var Pos = ( true === oThis.oDocument.Selection.Use ? oThis.oDocument.Selection.StartPos :
							oThis.oDocument.CurPos.ContentPos );
						isPasteHyperlink = node.getElementsByTagName('img');

						var text = null;
						if (isPasteHyperlink && isPasteHyperlink.length) {
							isPasteHyperlink = null;
						} else {
							text = child.innerText ? child.innerText : child.textContent;
						}

						if (isPasteHyperlink) {
							var HyperProps = new Asc.CHyperlinkProperty({Text: text, Value: href, ToolTip: title});
							oThis.oDocument.Content[Pos].AddHyperlink(HyperProps);
						}
					}
				}

				//TODO временная правка. пересмотреть обработку тега math
				if (!child.style && Node.TEXT_NODE !== child.nodeType) {
					child.style = {};
				}

				if (!isPasteHyperlink) {
					bAddParagraph =
						oThis._Execute(child, Common_CopyObj(pPr), false, bAddParagraph, bIsBlockChild || bInBlock,
							arrShapes, arrImages, arrTables);
				}

				if (bIsBlockChild) {
					bAddParagraph = true;
				}
			} else {
				var sChildNodeName = child.nodeName.toLowerCase();
				if (!(Node.ELEMENT_NODE === nodeType || Node.TEXT_NODE === nodeType) || sChildNodeName === "style" ||
					sChildNodeName === "#comment" || sChildNodeName === "script") {
					return;
				}
				//попускам элеметы состоящие только из \t,\n,\r
				if (Node.TEXT_NODE === child.nodeType) {
					var value = child.nodeValue;
					if (!value) {
						return;
					}
					value = value.replace(/(\r|\t|\n)/g, '');
					if ("" == value) {
						return;
					}
				}
				var bIsBlockChild = oThis._IsBlockElem(sChildNodeName);
				if (bRoot) {
					oThis.bInBlock = false;
				}
				if (bIsBlockChild) {
					bAddParagraph = true;
					oThis.bInBlock = true;
				}
				var oOldHyperlink = null;
				var oOldHyperlinkContentPos = null;
				var oHyperlink = null;
				if ("a" === sChildNodeName) {
					var href = child.href;
					if (null != href) {
						var sDecoded;
						//decodeURI может выдавать malformed exception, потому что наш сайт в utf8, а некоторые сайты могут кодировать url в своей кодировке(например windows-1251)
						try {
							sDecoded = decodeURI(href);
						} catch (e) {
							sDecoded = href;
						}
						href = sDecoded;
						if (href && href.length > 0) {
							var title = child.getAttribute("title");

							bAddParagraph = oThis._Decide_AddParagraph(child, pPr, bAddParagraph);
							oHyperlink = new ParaHyperlink();
							oHyperlink.SetParagraph(oThis.oCurPar);
							oHyperlink.Set_Value(href);
							if (null != title) {
								oHyperlink.SetToolTip(title);
							}
							oOldHyperlink = oThis.oCurHyperlink;
							oOldHyperlinkContentPos = oThis.oCurHyperlinkContentPos;
							oThis.oCurHyperlink = oHyperlink;
							oThis.oCurHyperlinkContentPos = 0;
						}
					}
				}

				//TODO временная правка. пересмотреть обработку тега math
				if (!child.style && Node.TEXT_NODE !== child.nodeType) {
					child.style = {};
				}

				bAddParagraph =
					oThis._Execute(child, Common_CopyObj(pPr), false, bAddParagraph, bIsBlockChild || bInBlock);
				if (bIsBlockChild) {
					bAddParagraph = true;
				}
				if ("a" === sChildNodeName && null != oHyperlink) {
					oThis.oCurHyperlink = oOldHyperlink;
					oThis.oCurHyperlinkContentPos = oOldHyperlinkContentPos;
					if (oHyperlink.Content.length > 0) {
						if (oThis.pasteInExcel) {
							var TextPr = new CTextPr();
							TextPr.Unifill = AscFormat.CreateUniFillSchemeColorWidthTint(11, 0);
							TextPr.Underline = true;
							oHyperlink.Apply_TextPr(TextPr, undefined, true);
						}

						//проставляем rStyle
						if (oHyperlink.Content && oHyperlink.Content.length && oHyperlink.Paragraph.bFromDocument) {
							if (oThis.oLogicDocument && oThis.oLogicDocument.Styles &&
								oThis.oLogicDocument.Styles.Default && oThis.oLogicDocument.Styles.Default.Hyperlink &&
								oThis.oLogicDocument.Styles.Style) {
								var hyperLinkStyle = oThis.oLogicDocument.Styles.Default.Hyperlink;

								for (var k = 0; k < oHyperlink.Content.length; k++) {
									if (oHyperlink.Content[k].Type === para_Run) {
										oHyperlink.Content[k].Set_RStyle(hyperLinkStyle);
									}
								}
							}
						}

						oThis._AddToParagraph(oHyperlink);
					}
				}
			}
		};

		var bPresentation = !PasteElementsId.g_bIsDocumentCopyPaste;
		if (bPresentation) {
			var shape = arrShapes[arrShapes.length - 1];
			this.aContent = shape.txBody.content.Content;
		}


		if (true === bRoot) {
			//Если блочных элементов нет, то отменяем флаг
			var bExist = false;
			for (var i = 0, length = node.childNodes.length; i < length; i++) {
				var child = node.childNodes[i];
				var bIsBlockChild = this._IsBlockElem(child.nodeName.toLowerCase());
				if (true === bIsBlockChild) {
					bRootHasBlock = true;
					bExist = true;
					break;
				}
			}
			if (false === bExist && true === this.bIgnoreNoBlockText) {
				this.bIgnoreNoBlockText = false;
			}
		} else {
			//TEXT NODE
			if (Node.TEXT_NODE === node.nodeType) {
				if (false === this.bIgnoreNoBlockText || true === bInBlock) {
					parseTextNode();
				}
				return bPresentation ? false : bAddParagraph;
			}

			//TABLE
			var sNodeName = node.nodeName.toLowerCase();
			if (bPresentation) {
				if ("table" === sNodeName) {
					this._StartExecuteTablePresentation(node, pPr, arrShapes, arrImages, arrTables);
					return;
				}
			} else {
				if ("table" === sNodeName && this.pasteInExcel !== true && this.pasteInPresentationShape !== true) {
					if (PasteElementsId.g_bIsDocumentCopyPaste) {
						this._StartExecuteTable(node, pPr);
						return bAddParagraph;
					} else {
						return false;
					}
				}
			}

			//STYLE
			parseStyle();

			//NUMBERING
			parseNumbering();

			//IMAGE
			if ("img" === sNodeName && (bPresentation || (!bPresentation && this.pasteInExcel !== true))) {
				return parseImage();
			}

			//LINEBREAK
			var lineBreak = parseLineBreak();
			if (null !== lineBreak) {
				return lineBreak;
			}

			//TAB
			if ("span" === sNodeName) {
				var tab = parseTab();
				if (null !== tab) {
					return tab;
				}
			}
		}


		//рекурсивно вызываем для childNodes
		for (var i = 0, length = node.childNodes.length; i < length; i++) {
			var child = node.childNodes[i];
			var nodeType = child.nodeType;
			//При копировании из word может встретиться комментарий со списком
			//Комментарии пропускаем, списки делаем своими
			if (Node.COMMENT_NODE === nodeType) {
				var value = child.nodeValue;
				var bSkip = false;
				if (value) {
					if (-1 !== value.indexOf("supportLists")) {
						//todo распознать тип списка
						pPr.bNum = true;
						bSkip = true;
					}
					if (-1 !== value.indexOf("supportLineBreakNewLine")) {
						bSkip = true;
					}
				}
				if (true === bSkip) {
					//пропускаем все до закрывающегося комментария
					var j = i + 1;
					for (; j < length; j++) {
						var tempNode = node.childNodes[j];
						var tempNodeType = tempNode.nodeType;
						if (Node.COMMENT_NODE === tempNodeType) {
							var tempvalue = tempNode.nodeValue;
							if (tempvalue && -1 !== tempvalue.indexOf("endif")) {
								break;
							}
						}
					}
					i = j;
					continue;
				}
			}

			parseChildNodes();
		}

		if (bRoot && bPresentation) {
			this._Commit_Br(2, node, pPr);//word игнорируем 2 последних br
		}
		return bAddParagraph;
	},

    _StartExecuteTablePresentation : function(node, pPr, arrShapes, arrImages, arrTables)
    {
        var oDocument = this.oDocument;
        var tableNode = node;
		//Ищем если есть tbody
        for(var i = 0, length = node.childNodes.length; i < length; ++i)
        {
            if("tbody" === node.childNodes[i].nodeName.toLowerCase())
            {
                node = node.childNodes[i];
                break;
            }
        }
		//валидация талиц. В таблице не может быть строк состоящих из вертикально замерженых ячеек.
        var nRowCount = 0;
        var nMinColCount = 0;
        var nMaxColCount = 0;
        var aColsCountByRow = [];
        var oRowSums = {};
        oRowSums[0] = 0;
        var dMaxSum = 0;
        var nCurColWidth = 0;
        var nCurSum = 0;
        var oRowSpans = {};
        var fParseSpans = function()
        {
            var spans = oRowSpans[nCurColWidth];
            while(null != spans && spans.row > 0)
            {
                spans.row--;
                nCurColWidth += spans.col;
                nCurSum += spans.width;
                spans = oRowSpans[nCurColWidth];
            }
        };
        for(var i = 0, length = node.childNodes.length; i < length; ++i)
        {
            var tr = node.childNodes[i];
            if("tr" === tr.nodeName.toLowerCase())
            {
                nCurSum = 0;
                nCurColWidth = 0;
                var nMinRowSpanCount = null;//минимальный rowspan ячеек строки
                for(var j = 0, length2 = tr.childNodes.length; j < length2; ++j)
                {
                    var tc = tr.childNodes[j];
                    var tcName = tc.nodeName.toLowerCase();
                    if("td" === tcName || "th" === tcName)
                    {
                        fParseSpans();

                        var dWidth = null;
						var computedStyle = this._getComputedStyle(tc);
						var computedWidth = this._getStyle(tc, computedStyle, "width" );
						if(null != computedWidth && null != (computedWidth = this._ValueToMm(computedWidth)))
							dWidth = computedWidth;

                        if(null == dWidth)
                            dWidth = tc.clientWidth * g_dKoef_pix_to_mm;

                        var nColSpan = tc.getAttribute("colspan");
                        if(null != nColSpan)
                            nColSpan = nColSpan - 0;
                        else
                            nColSpan = 1;
                        var nCurRowSpan = tc.getAttribute("rowspan");
                        if(null != nCurRowSpan)
                        {
                            nCurRowSpan = nCurRowSpan - 0;
                            if(null == nMinRowSpanCount)
                                nMinRowSpanCount = nCurRowSpan;
                            else if(nMinRowSpanCount > nCurRowSpan)
                                nMinRowSpanCount = nCurRowSpan;
                            if(nCurRowSpan > 1)
                                oRowSpans[nCurColWidth] = {row: nCurRowSpan - 1, col: nColSpan, width: dWidth};
                        }
                        else
                            nMinRowSpanCount = 0;

                        nCurSum += dWidth;
                        if(null == oRowSums[nCurColWidth + nColSpan])
                            oRowSums[nCurColWidth + nColSpan] = nCurSum;
                        nCurColWidth += nColSpan;
                    }
                }
                fParseSpans();
				//Удаляем лишние rowspan
                if(nMinRowSpanCount > 1)
                {
                    for(var j = 0, length2 = tr.childNodes.length; j < length2; ++j)
                    {
                        var tc = tr.childNodes[j];
                        var tcName = tc.nodeName.toLowerCase();
                        if("td" === tcName || "th" === tcName)
                        {
                            var nCurRowSpan = tc.getAttribute("rowspan");
                            if(null != nCurRowSpan)
                                tc.setAttribute("rowspan", nCurRowSpan - nMinRowSpanCount);
                        }
                    }
                }
                if(dMaxSum < nCurSum)
                    dMaxSum = nCurSum;
				//удаляем пустые tr
                if(0 === nCurColWidth)
                {
                    node.removeChild(tr);
                    length--;
                    i--;
                }
                else
                {
                    if(0 === nMinColCount || nMinColCount > nCurColWidth)
                        nMinColCount = nCurColWidth;
                    if(nMaxColCount < nCurColWidth)
                        nMaxColCount = nCurColWidth;
                    nRowCount++;
                    aColsCountByRow.push(nCurColWidth);
                }
            }
        }
        if(nMaxColCount != nMinColCount)
        {
            for(var i = 0, length = aColsCountByRow.length; i < length; ++i)
                aColsCountByRow[i] = nMaxColCount - aColsCountByRow[i];
        }
        if(nRowCount > 0 && nMaxColCount > 0)
        {
            var bUseScaleKoef = this.bUseScaleKoef;
            var dScaleKoef = this.dScaleKoef;
            if(dMaxSum * dScaleKoef > this.dMaxWidth)
            {
                dScaleKoef = dScaleKoef * this.dMaxWidth / dMaxSum;
                bUseScaleKoef = true;
            }
			//строим Grid
            var aGrid = [];
            var nPrevIndex = null;
            var nPrevVal = 0;
            for(var i in oRowSums)
            {
                var nCurIndex = i - 0;
                var nCurVal = oRowSums[i];
                var nCurWidth = nCurVal - nPrevVal;
                if(bUseScaleKoef)
                    nCurWidth *= dScaleKoef;
                if(null != nPrevIndex)
                {
                    var nDif = nCurIndex - nPrevIndex;
                    if(1 === nDif)
                        aGrid.push(nCurWidth);
                    else
                    {
                        var nPartVal = nCurWidth / nDif;
                        for(var i = 0; i < nDif; ++i)
                            aGrid.push(nPartVal);
                    }
                }
                nPrevVal = nCurVal;
                nPrevIndex = nCurIndex;
            }

			var table = this._createNewPresentationTable(aGrid);
			var graphicFrame = table.Parent;
			table.Set_TableStyle(0);
            arrTables.push(graphicFrame);
			
			//TODO пересмотреть!!!
            //graphicFrame.setXfrm(dd.GetMMPerDot(node["offsetLeft"]), dd.GetMMPerDot(node["offsetTop"]), dd.GetMMPerDot(node["offsetWidth"]), dd.GetMMPerDot(node["offsetHeight"]), null, null, null);

            //считаем aSumGrid
            var aSumGrid = [];
            aSumGrid[-1] = 0;
            var nSum = 0;
            for(var i = 0, length = aGrid.length; i < length; ++i)
            {
                nSum += aGrid[i];
                aSumGrid[i] = nSum;
            }
			//набиваем content
             this._ExecuteTablePresentation(tableNode, node, table, aSumGrid, nMaxColCount != nMinColCount ? aColsCountByRow : null, pPr, bUseScaleKoef, dScaleKoef, arrShapes, arrImages, arrTables);
            table.MoveCursorToStartPos();
            return;
        }
    },

    _ExecuteTablePresentation : function(tableNode, node, table, aSumGrid, aColsCountByRow, pPr, bUseScaleKoef, dScaleKoef, arrShapes, arrImages, arrTables)
    {
        table.SetTableLayout(tbllayout_AutoFit);
        //Pr
        var Pr = table.Pr;
		//align смотрим у parent tableNode
        var sTableAlign = null;
        if(null != tableNode.align)
            sTableAlign = tableNode.align;
        else if(null != tableNode.parentNode && this.oRootNode !== tableNode.parentNode)
        {
			var computedStyleParent = this._getComputedStyle(tableNode.parentNode);
			sTableAlign = this._getStyle(tableNode.parentNode, computedStyleParent, "text-align");
        }
        if(null != sTableAlign)
        {
            if(-1 !== sTableAlign.indexOf('center'))
                table.Set_TableAlign(align_Center);
            else if(-1 !== sTableAlign.indexOf('right'))
                table.Set_TableAlign(align_Right);
        }
        var spacing = null;
        table.Set_TableBorder_InsideH(new CDocumentBorder());
        table.Set_TableBorder_InsideV(new CDocumentBorder());

        var style = tableNode.getAttribute("style");
        if(style)
        {
            var tblPrMso = {};
            this._parseCss(style, tblPrMso);
            var spacing = tblPrMso["mso-cellspacing"];
            if(null != spacing && null != (spacing = this._ValueToMm(spacing)))
                ;
            var padding = tblPrMso["mso-padding-alt"];
            if(null != padding)
            {
                padding = trimString(padding);
                var aMargins = padding.split(" ");
                if(4 === aMargins.length)
                {
                    var top = aMargins[0];
                    if(null != top && null != (top = this._ValueToMm(top)))
                        ;
                    else
                        top = Pr.TableCellMar.Top.W;
                    var right = aMargins[1];
                    if(null != right && null != (right = this._ValueToMm(right)))
                        ;
                    else
                        right = Pr.TableCellMar.Right.W;
                    var bottom = aMargins[2];
                    if(null != bottom && null != (bottom = this._ValueToMm(bottom)))
                        ;
                    else
                        bottom = Pr.TableCellMar.Bottom.W;
                    var left = aMargins[3];
                    if(null != left && null != (left = this._ValueToMm(left)))
                        ;
                    else
                        left = Pr.TableCellMar.Left.W;
                    table.Set_TableCellMar(left, top, right, bottom);
                }
            }
            var insideh = tblPrMso["mso-border-insideh"];
            if(null != insideh)
                table.Set_TableBorder_InsideH(this._ExecuteParagraphBorder(insideh));
            var insidev = tblPrMso["mso-border-insidev"];
            if(null != insidev)
                table.Set_TableBorder_InsideV(this._ExecuteParagraphBorder(insidev));
        }

        var computedStyle = this._getComputedStyle(tableNode);
		if(align_Left === table.Get_TableAlign())
		{
			var margin_left = this._getStyle(tableNode, computedStyle, "margin-left");
			//todo возможно надо еще учесть ширину таблицы
			if(margin_left && null != (margin_left = this._ValueToMm(margin_left)) && margin_left < Page_Width - X_Left_Margin)
				table.Set_TableInd(margin_left);
		}
		var background_color = this._getStyle(tableNode, computedStyle, "background-color");
		if(null != background_color && (background_color = this._ParseColor(background_color)))
			table.Set_TableShd(c_oAscShdClear, background_color.r, background_color.g, background_color.b);
		var oLeftBorder = this._ExecuteBorder(computedStyle, tableNode, "left", "Left", false, true);
		if(null != oLeftBorder)
			table.Set_TableBorder_Left(oLeftBorder);
		var oTopBorder = this._ExecuteBorder(computedStyle, tableNode, "top", "Top", false, true);
		if(null != oTopBorder)
			table.Set_TableBorder_Top(oTopBorder);
		var oRightBorder = this._ExecuteBorder(computedStyle, tableNode, "right", "Right", false, true);
		if(null != oRightBorder)
			table.Set_TableBorder_Right(oRightBorder);
		var oBottomBorder = this._ExecuteBorder(computedStyle, tableNode, "bottom", "Bottom", false, true);
		if(null != oBottomBorder)
			table.Set_TableBorder_Bottom(oBottomBorder);

		if(null == spacing)
		{
			spacing = this._getStyle(tableNode, computedStyle, "padding");
			if(!spacing)
				spacing = tableNode.style.padding;
			if(!spacing)
				spacing = null;
			if(spacing && null != (spacing = this._ValueToMm(spacing)))
				;
		}

        //content
        var oRowSpans = {};
        for(var i = 0, length = node.childNodes.length; i < length; ++i)
        {
            var tr = node.childNodes[i];
            if("tr" === tr.nodeName.toLowerCase() && tr.children.length !== 0)//в случае, если внутри строки нет ни одной ячейки, не добавляем данную строку
            {
                var row = table.Internal_Add_Row(table.Content.length, 0);
                this._ExecuteTableRowPresentation(tr, row, aSumGrid, spacing, oRowSpans, bUseScaleKoef, dScaleKoef, arrShapes, arrImages, arrTables);
            }
        }
    },
    _ExecuteTableRowPresentation : function(node, row, aSumGrid, spacing, oRowSpans, bUseScaleKoef, dScaleKoef, arrShapes, arrImages, arrTables)
    {
        var oThis = this;
        var table = row.Table;
        if(null != spacing /*&& spacing >= tableSpacingMinValue*/)
            row.Set_CellSpacing(spacing);
        if(node.style.height)
        {
            var height = node.style.height;
            if(!("auto" === height || "inherit" === height || -1 !== height.indexOf("%")) && null != (height = this._ValueToMm(height)))
                row.Set_Height(height, Asc.linerule_AtLeast);
        }
        var bBefore = false;
        var bAfter = false;
        var style = node.getAttribute("style");
        if(null != style)
        {
            var tcPr = {};
            this._parseCss(style, tcPr);
            var margin_left = tcPr["mso-row-margin-left"];
            if(margin_left && null != (margin_left = this._ValueToMm(margin_left)))
                bBefore = true;
            var margin_right = tcPr["mso-row-margin-right"];
            if(margin_right && null != (margin_right = this._ValueToMm(margin_right)))
                bAfter = true;
        }

        //content
        var nCellIndex = 0;
        var nCellIndexSpan = 0;
        var fParseSpans = function()
        {
            var spans = oRowSpans[nCellIndexSpan];
            while(null != spans)
            {
                var oCurCell = row.Add_Cell(row.Get_CellsCount(), row, null, false);
                oCurCell.SetVMerge(vmerge_Continue);
                if(spans.col > 1)
                    oCurCell.Set_GridSpan(spans.col);
                spans.row--;
                if(spans.row <= 0)
                    delete oRowSpans[nCellIndexSpan];
                nCellIndexSpan += spans.col;
                spans = oRowSpans[nCellIndexSpan];
            }
        };
        var oBeforeCell = null;
        var oAfterCell = null;
        if(bBefore || bAfter)
        {
            for(var i = 0, length = node.childNodes.length; i < length; ++i)
            {
                var tc = node.childNodes[i];
                var tcName = tc.nodeName.toLowerCase();
                if("td" === tcName || "th" === tcName)
                {
                    if(bBefore && null != oBeforeCell)
                        oBeforeCell = tc;
                    else if(bAfter)
                        oAfterCell = tc;
                }
            }
        }
        for(var i = 0, length = node.childNodes.length; i < length; ++i)
        {
			//важно чтобы этот код был после определения td, потому что вертикально замерженые ячейки отсутствуют в dom
            fParseSpans();

            var tc = node.childNodes[i];
            var tcName = tc.nodeName.toLowerCase();
            if("td" === tcName || "th" === tcName)
            {
                var nColSpan = tc.getAttribute("colspan");
                if(null != nColSpan)
                    nColSpan = nColSpan - 0;
                else
                    nColSpan = 1;
                if(tc === oBeforeCell)
                    row.Set_Before(nColSpan);
                else if(tc === oAfterCell)
                    row.Set_After(nColSpan);
                else
                {
                    var oCurCell = row.Add_Cell(row.Get_CellsCount(), row, null, false);
                    if(nColSpan > 1)
                        oCurCell.Set_GridSpan(nColSpan);
                    var width = aSumGrid[nCellIndexSpan + nColSpan - 1] - aSumGrid[nCellIndexSpan - 1];
                    oCurCell.Set_W(new CTableMeasurement(tblwidth_Mm, width));
                    var nRowSpan = tc.getAttribute("rowspan");
                    if(null != nRowSpan)
                        nRowSpan = nRowSpan - 0;
                    else
                        nRowSpan = 1;
                    if(nRowSpan > 1)
                        oRowSpans[nCellIndexSpan] = {row: nRowSpan - 1, col: nColSpan};
                    this._ExecuteTableCellPresentation(tc, oCurCell, bUseScaleKoef, dScaleKoef, spacing, arrShapes, arrImages, arrTables);
                }
                nCellIndexSpan+=nColSpan;
            }
        }
        fParseSpans();
    },
    _ExecuteTableCellPresentation : function(node, cell, bUseScaleKoef, dScaleKoef, spacing, arrShapes, arrImages, arrTables)
    {
        //Pr
        var Pr = cell.Pr;
        var bAddIfNull = false;
        if(null != spacing)
            bAddIfNull = true;

		var computedStyle = this._getComputedStyle(node);
		var background_color = this._getStyle(node, computedStyle, "background-color");
		if(null != background_color && (background_color = this._ParseColor(background_color)))
		{
			var Shd = new CDocumentShd();
			Shd.Value = c_oAscShdClear;
			Shd.Unifill = AscFormat.CreteSolidFillRGB(background_color.r,background_color.g, background_color.b);
			cell.Set_Shd(Shd);
		}
		var border = this._ExecuteBorder(computedStyle, node, "left", "Left", bAddIfNull, true);
		if(null != border)
			cell.Set_Border(border, 3);
		border = this._ExecuteBorder(computedStyle, node, "top", "Top", bAddIfNull, true);
		if(null != border)
			cell.Set_Border(border, 0);
		border = this._ExecuteBorder(computedStyle, node, "right", "Right", bAddIfNull, true);
		if(null != border)
			cell.Set_Border(border, 1);
		border = this._ExecuteBorder(computedStyle, node, "bottom", "Bottom", bAddIfNull, true);
		if(null != border)
			cell.Set_Border(border, 2);

		var top = this._getStyle(node, computedStyle, "padding-top");
		if(null != top && null != (top = this._ValueToMm(top)))
			cell.Set_Margins({ W : top, Type : tblwidth_Mm }, 0);
		var right = this._getStyle(node, computedStyle, "padding-right");
		if(null != right && null != (right = this._ValueToMm(right)))
			cell.Set_Margins({ W : right, Type : tblwidth_Mm }, 1);
		var bottom = this._getStyle(node, computedStyle, "padding-bottom");
		if(null != bottom && null != (bottom = this._ValueToMm(bottom)))
			cell.Set_Margins({ W : bottom, Type : tblwidth_Mm }, 2);
		var left = this._getStyle(node, computedStyle, "padding-left");
		if(null != left && null != (left = this._ValueToMm(left)))
			cell.Set_Margins({ W : left, Type : tblwidth_Mm }, 3);

        var arrShapes2 = [], arrImages2 = [], arrTables2 = [];
        var presentation = editor.WordControl.m_oLogicDocument;
        var shape = new CShape();
        shape.setParent(presentation.Slides[presentation.CurPage]);
        shape.setTxBody(AscFormat.CreateTextBodyFromString("", presentation.DrawingDocument, shape));
        arrShapes2.push(shape);
        this._Execute(node, {}, true, true, false, arrShapes2, arrImages2, arrTables);
        if(arrShapes2.length > 0)
        {
            var first_shape = arrShapes2[0];
            var content = first_shape.txBody.content;

			//добавляем новый параграфы
            for(var i = 0, length = content.Content.length; i < length; ++i)
			{
				if(i === length - 1)
					cell.Content.Internal_Content_Add(i + 1, content.Content[i], true);
				else
					cell.Content.Internal_Content_Add(i + 1, content.Content[i], false);
			}
			//Удаляем параграф, который создается в таблице по умолчанию
            cell.Content.Internal_Content_Remove(0, 1);
            arrShapes2.splice(0, 1);
        }
        for(var i = 0;  i< arrShapes2.length; ++i)
        {
            arrShapes.push(arrShapes2[i]);
        }
        for(var i = 0;  i< arrImages2.length; ++i)
        {
            arrImages.push(arrImages2[i]);
        }
        for(var i = 0;  i< arrTables2.length; ++i)
        {
            arrTables.push(arrTables2[i]);
        }
    },
	
	_applyStylesToTable: function(cTable, cStyle)
	{
		if(!cTable || !cStyle || (cTable && !cTable.Content))
			return;
		
		
		var row, tableCell;
		for(var i = 0; i < cTable.Content.length; i++)
		{	
			row = cTable.Content[i];
			
			for(var j = 0; j < row.Content.length; j++)
			{
				tableCell = row.Content[j];
				//пока не заливаю функцию Internal_Compile_Pr(находится в table.js + правки)
				var test = this.Internal_Compile_Pr(cTable, cStyle, tableCell);
				tableCell.Set_Pr(test.CellPr);
				
				//проверка цвета
				/*cStyle.TableFirstRow.TableCellPr.Shd.Unifill.check(cTable.Get_Theme(), cTable.Get_ColorMap());
				var RGBA = cStyle.TableFirstRow.TableCellPr.Shd.Unifill.getRGBAColor();
				var theme = cTable.Get_Theme();*/
			}
		}
	}
};

function CheckDefaultFontFamily(val, api)
{
	return "onlyofficeDefaultFont" === val && api && api.getDefaultFontFamily ? api.getDefaultFontFamily() : val;
}

function CheckDefaultFontSize(val, api)
{
	return "0px" === val && api && api.getDefaultFontSize ? api.getDefaultFontSize() + "pt" : val;
}

function CreateImageFromBinary(bin, nW, nH)
{
    var w, h;

    if (nW === undefined || nH === undefined)
    {
        var _image = editor.ImageLoader.map_image_index[bin];
        if (_image != undefined && _image.Image != null && _image.Status == AscFonts.ImageLoadStatus.Complete)
        {
            var _w = Math.max(1, Page_Width - (X_Left_Margin + X_Right_Margin));
            var _h = Math.max(1, Page_Height - (Y_Top_Margin + Y_Bottom_Margin));

            var bIsCorrect = false;
            if (_image.Image != null)
            {
                var __w = Math.max(parseInt(_image.Image.width * g_dKoef_pix_to_mm), 1);
                var __h = Math.max(parseInt(_image.Image.height * g_dKoef_pix_to_mm), 1);

                var dKoef = Math.max(__w / _w, __h / _h);
                if (dKoef > 1)
                {
                    _w = Math.max(5, __w / dKoef);
                    _h = Math.max(5, __h / dKoef);

                    bIsCorrect = true;
                }
                else
                {
                    _w = __w;
                    _h = __h;
                }
            }

            w = __w;
            h = __h;
        }
        else
        {
            w = 50;
            h = 50;
        }
    }
    else
    {
        w = nW;
        h = nH;
    }
    var para_drawing = new ParaDrawing(w, h, null, editor.WordControl.m_oLogicDocument.DrawingDocument, editor.WordControl.m_oLogicDocument, null);
    var word_image = AscFormat.DrawingObjectsController.prototype.createImage(bin, 0, 0, w, h);
    para_drawing.Set_GraphicObject(word_image);
    word_image.setParent(para_drawing);
    para_drawing.Set_GraphicObject(word_image);
    return para_drawing;
}

function Check_LoadingDataBeforePrepaste(_api, _fonts, _images, _callback)
{
    var aPrepeareFonts = [];
    for (var font_family in _fonts)
    {
        aPrepeareFonts.push(new CFont(font_family, 0, "", 0));
    }
    AscFonts.FontPickerByCharacter.extendFonts(aPrepeareFonts);

    var isDesktopEditor = (window["AscDesktopEditor"] !== undefined) ? true : false;
    var isDesktopEditorLocal = false;

    if (isDesktopEditor)
	{
		if (window["AscDesktopEditor"]["IsLocalFile"] && window["AscDesktopEditor"]["IsLocalFile"]())
			isDesktopEditorLocal = true;
	}

    var aImagesToDownload = [];
    var _mapLocal = {};
    for (var image in _images)
    {
        var src = _images[image];
        if (undefined !== window["Native"] && undefined !== window["Native"]["GetImageUrl"])
        {
            _images[image] = window["Native"]["GetImageUrl"](_images[image]);
        }
        else if (0 == src.indexOf("file:"))
        {
            if (window["AscDesktopEditor"] !== undefined)
            {
                if (window["AscDesktopEditor"]["LocalFileGetImageUrl"] !== undefined)
                {
                    aImagesToDownload.push(src);
                }
                else
                {
                    var _base64 = window["AscDesktopEditor"]["GetImageBase64"](src);
                    if (_base64 != "")
                    {
                        aImagesToDownload.push(_base64);
                        _mapLocal[_base64] = src;
                    }
                    else
                    {
                        _images[image] = "local";
                    }
                }
            }
            else
                _images[image] = "local";
        }
        else if (isDesktopEditorLocal)
		{
			if (!g_oDocumentUrls.getImageLocal(src))
				aImagesToDownload.push(src);
		}
        else if (!g_oDocumentUrls.getImageUrl(src) && !g_oDocumentUrls.getImageLocal(src))
        {
            if (window["AscDesktopEditor"] && (undefined !== window["AscDesktopEditor"]["CryptoMode"]) && (window["AscDesktopEditor"]["CryptoMode"] > 0))
            {
                // local image (open crypto file)
                if (0 != src.indexOf("image"))
                    aImagesToDownload.push(src);
            }
            else
            {
                aImagesToDownload.push(src);
            }
        }
    }
    if (aImagesToDownload.length > 0)
    {
        AscCommon.sendImgUrls(_api, aImagesToDownload, function (data) {
            var image_map = {};
            for (var i = 0, length = Math.min(data.length, aImagesToDownload.length); i < length; ++i)
            {
                var elem = data[i];
                var sFrom = aImagesToDownload[i];
                if (null != elem.url)
                {
                    var name = g_oDocumentUrls.imagePath2Local(elem.path);
                    _images[sFrom] = name;
                    image_map[i] = name;
                }
                else
                {
                    image_map[i] = sFrom;
                }
            }
            _api.pre_Paste(aPrepeareFonts, image_map, _callback);
        }, null, true);
    }
    else
        _api.pre_Paste(aPrepeareFonts, _images, _callback);
}

function addTextIntoRun(oCurRun, value, bIsAddTabBefore, dNotAddLastSpace, bIsAddTabAfter) {
	if (bIsAddTabBefore) {
		oCurRun.AddToContent(-1, new ParaTab(), false);
	}

	for (var oIterator = value.getUnicodeIterator(); oIterator.check(); oIterator.next()) {
		var nUnicode = oIterator.value();

		var bIsSpace = true;
		var Item;
		if (0x2009 === nUnicode || 9 === nUnicode) {
			Item = new ParaTab();
		} else if (0x20 !== nUnicode && 0xA0 !== nUnicode) {
			Item = new ParaText(nUnicode);
			bIsSpace = false;
		} else {
			Item = new ParaSpace();
		}

		//add text
		if (!(dNotAddLastSpace && oIterator.position() === value.length - 1 && bIsSpace)) {
			oCurRun.AddToContent(-1, Item, false);
		}
	}

	if (bIsAddTabAfter) {
		oCurRun.AddToContent(-1, new ParaTab(), false);
	}
}

function searchBinaryClass(node)
{
	var res = null;
	if(node.children[0])
	{
		var child = node.children[0];
		var childClass = child ? child.getAttribute("class") : null;
		if(childClass != null && (childClass.indexOf("xslData;") > -1 || childClass.indexOf("docData;") > -1 || childClass.indexOf("pptData;") > -1))
		{
			return childClass;
		}
		else
		{
			return searchBinaryClass(node.children[0]);
		}
	}
	return res;
}

function SpecialPasteShowOptions()
{
	this.options = null;
	this.cellCoord = null;

	this.range = null;
	this.shapeId = null;
	this.fixPosition = null;
	this.position = null;
}

SpecialPasteShowOptions.prototype = {
	constructor: SpecialPasteShowOptions,

	isClean: function() {
		var res = false;
		if(null === this.options && null === this.cellCoord && null === this.range && null === this.shapeId && null === this.fixPosition) {
			res = true;
		}
		return res;
	},

	clean: function() {
		this.options = null;
		this.cellCoord = null;

		this.range = null;
		this.shapeId = null;
		this.fixPosition = null;
		this.position = null;
	},

	setRange: function(val) {
		this.range = val;
	},
	setShapeId: function(val) {
		this.shapeId = val;
	},
	setFixPosition: function(val) {
		this.fixPosition = val;
	},
	setPosition: function(val) {
		this.position = val;
	},

	asc_setCellCoord: function (val) {
		this.cellCoord = val;
	},
	asc_setOptions: function (val) {
		if(val === null) {
			this.options = [];
		} else {
			this.options = val;
		}
	},
	asc_getCellCoord: function () {
		return this.cellCoord;
	},
	asc_getOptions: function (val) {
		return this.options;
	}
};

  //---------------------------------------------------------export---------------------------------------------------
  window['AscCommon'] = window['AscCommon'] || {};
  window["AscCommon"].Check_LoadingDataBeforePrepaste = Check_LoadingDataBeforePrepaste;
  window["AscCommon"].CDocumentReaderMode = CDocumentReaderMode;
  window["AscCommon"].GetObjectsForImageDownload = GetObjectsForImageDownload;
  window["AscCommon"].ResetNewUrls = ResetNewUrls;
  window["AscCommon"].CopyProcessor = CopyProcessor;
  window["AscCommon"].CopyPasteCorrectString = CopyPasteCorrectString;
  window["AscCommon"].Editor_Paste_Exec = Editor_Paste_Exec;
  window["AscCommon"].sendImgUrls = sendImgUrls;
  window["AscCommon"].PasteProcessor = PasteProcessor;

  window["AscCommon"].addTextIntoRun = addTextIntoRun;
  window["AscCommon"].searchBinaryClass = searchBinaryClass;
  
  window["AscCommon"].PasteElementsId = PasteElementsId;
  window["AscCommon"].CheckDefaultFontFamily = CheckDefaultFontFamily;

  
  window["Asc"]["SpecialPasteShowOptions"] = window["Asc"].SpecialPasteShowOptions = SpecialPasteShowOptions;
  prot									 = SpecialPasteShowOptions.prototype;
  prot["asc_getCellCoord"]				 	= prot.asc_getCellCoord;
  prot["asc_getOptions"]					= prot.asc_getOptions;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
(
	/**
	 * @param {Window} window
	 * @param {undefined} undefined
	 */
	function (window, undefined) {
		// Import
		var gc_nMaxRow0 = AscCommon.gc_nMaxRow0;
		var gc_nMaxCol0 = AscCommon.gc_nMaxCol0;
		var g_oCellAddressUtils = AscCommon.g_oCellAddressUtils;
		var AscBrowser = AscCommon.AscBrowser;

		var c_oAscSelectionType = Asc.c_oAscSelectionType;

		var c_oAscShiftType = {
			None  : 0,
			Move  : 1,
			Change: 2
		};


		/** @const */
		var kLeftLim1 = .999999999999999;
		var MAX_EXCEL_INT = 1e308;
		var MIN_EXCEL_INT = -MAX_EXCEL_INT;

		/** @const */
		var kUndefinedL = "undefined";
		/** @const */
		var kNullL = "null";
		/** @const */
		var kObjectL = "object";
		/** @const */
		var kFunctionL = "function";
		/** @const */
		var kNumberL = "number";
		/** @const */
		var kArrayL = "array";

		var recalcType = {
			recalc	: 0, // без пересчета
			full		: 1, // пересчитываем все
			newLines: 2  // пересчитываем новые строки

		};

		var sizePxinPt = 72 / 96;

		function applyFunction(callback) {
			if (kFunctionL === typeof callback) {
				callback.apply(null, Array.prototype.slice.call(arguments, 1));
			}
		}

		function typeOf(obj) {
			if (obj === undefined) {return kUndefinedL;}
			if (obj === null) {return kNullL;}
			return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
		}

		function lastIndexOf(s, regExp, fromIndex) {
			var end = fromIndex >= 0 && fromIndex <= s.length ? fromIndex : s.length;
			for (var i = end - 1; i >= 0; --i) {
				var j = s.slice(i, end).search(regExp);
				if (j >= 0) {return i + j;}
			}
			return -1;
		}

		function search(arr, fn) {
			for (var i = 0; i < arr.length; ++i) {
				if ( fn(arr[i]) ) {return i;}
			}
			return -1;
		}

		function getUniqueRangeColor (arrRanges, curElem, tmpColors) {
			var colorIndex, j, range = arrRanges[curElem];
			for (j = 0; j < curElem; ++j) {
				if (range.isEqual(arrRanges[j])) {
					colorIndex = tmpColors[j];
					break;
				}
			}
			return colorIndex;
		}

		function getMinValueOrNull (val1, val2) {
			return null === val2 ? val1 : (null === val1 ? val2 : Math.min(val1, val2));
		}


		function round(x) {
			var y = x + (x >= 0 ? .5 : -.5);
			return y | y;
			//return Math.round(x);
		}

		function floor(x) {
			var y = x | x;
			y -= x < 0 && y > x ? 1 : 0;
			return y + (x - y > kLeftLim1 ? 1 : 0); // to fix float number precision caused by binary presentation
			//return Math.floor(x);
		}

		function ceil(x) {
			var y = x | x;
			y += x > 0 && y < x ? 1 : 0;
			return y - (y - x > kLeftLim1 ? 1 : 0); // to fix float number precision caused by binary presentation
			//return Math.ceil(x);
		}

		function incDecFonSize (bIncrease, oValue) {
			// Закон изменения размеров :
			// Результатом должно быть ближайшее из отрезка [8,72] по следующим числам 8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72
			// Если значение меньше или равно 8 и мы уменьшаем, то ничего не меняется
			// Если значение больше или равно 72 и мы увеличиваем, то ничего не меняется

			var aSizes = [8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72];
			var nLength = aSizes.length;
			var i;
			if (true === bIncrease) {
				if (oValue >= aSizes[nLength - 1])
					return null;
				for (i = 0; i < nLength; ++i)
					if (aSizes[i] > oValue)
						break;
			} else {
				if (oValue <= aSizes[0])
					return null;
				for (i = nLength - 1; i >= 0; --i)
					if (aSizes[i] < oValue)
						break;
			}

			return aSizes[i];
		}

		function calcDecades(num) {
			return Math.abs(num) < 10 ? 1 : 1 + calcDecades(floor(num * 0.1));
		}

		function convertPtToPx(value) {
			value = value / sizePxinPt;
			value = value | value;
			if (AscBrowser.isRetina) {
				value = AscBrowser.convertToRetinaValue(value, true);
			}
			return value;
		}
		function convertPxToPt(value) {
			value = value * sizePxinPt;
			if (AscBrowser.isRetina) {
				value = AscBrowser.convertToRetinaValue(value);
			}
			return value;
		}


		// Определяет времени работы функции
		function profileTime(fn/*[, arguments]*/) {
			var start, end, arg = [], i;
			if (arguments.length) {
				if (arguments.length > 1) {
					for (i = 1; i < arguments.length; ++i)
						arg.push(arguments[i]);
					start = new Date();
					fn.apply(window, arg);
					end = new Date();
				} else {
					start = new Date();
					fn();
					end = new Date();
				}
				return end.getTime() - start.getTime();
			}
			return undefined;
		}

		function getMatchingBorder(border1, border2) {
			// ECMA-376 Part 1 17.4.67 tcBorders (Table Cell Borders)
			if (!border1) {
				return border2;
			}
			if (!border2) {
				return border1;
			}

			if (border1.w > border2.w) {
				return border1;
			} else if (border1.w < border2.w) {
				return border2;
			}

			var r1 = border1.c.getR(), g1 = border1.c.getG(), b1 = border1.c.getB();
			var r2 = border2.c.getR(), g2 = border2.c.getG(), b2 = border2.c.getB();
			var Brightness_1_1 = r1 + b1 + 2 * g1;
			var Brightness_1_2 = r2 + b2 + 2 * g2;
			if (Brightness_1_1 < Brightness_1_2) {
				return border1;
			} else if (Brightness_1_1 > Brightness_1_2) {
				return border2;
			}

			var Brightness_2_1 = Brightness_1_1 - r1;
			var Brightness_2_2 = Brightness_1_2 - r2;
			if (Brightness_2_1 < Brightness_2_2) {
				return border1;
			} else if (Brightness_2_1 > Brightness_2_2) {
				return border2;
			}

			var Brightness_3_1 = g1;
			var Brightness_3_2 = g2;
			if (Brightness_3_1 < Brightness_3_2) {
				return border1;
			} else if (Brightness_3_1 > Brightness_3_2) {
				return border2;
			}

			// borders equal
			return border1;
		}

		var referenceType = {
			A: 0,			// Absolute
			ARRC: 1,	// Absolute row; relative column
			RRAC: 2,	// Relative row; absolute column
			R: 3			// Relative
		};

		/**
		 * Rectangle region of cells
		 * @constructor
		 * @memberOf Asc
		 * @param c1 {Number} Left side of range.
		 * @param r1 {Number} Top side of range.
		 * @param c2 {Number} Right side of range (inclusively).
		 * @param r2 {Number} Bottom side of range (inclusively).
		 * @param normalize {Boolean=} Optional. If true, range will be converted to form (left,top) - (right,bottom).
		 * @return {Range}
		 */
		function Range(c1, r1, c2, r2, normalize) {
			if (!(this instanceof Range)) {
				return new Range(c1, r1, c2, r2, normalize);
			}

			/** @type Number */
			this.c1 = c1;
			/** @type Number */
			this.r1 = r1;
			/** @type Number */
			this.c2 = c2;
			/** @type Number */
			this.r2 = r2;
			this.refType1 = referenceType.R;
			this.refType2 = referenceType.R;

			return normalize ? this.normalize() : this;
		}

		Range.prototype.assign = function (c1, r1, c2, r2, normalize) {
			if (typeOf(c1) !== kNumberL || typeOf(c2) !== kNumberL || typeOf(r1) !== kNumberL || typeOf(r2) !== kNumberL) {
				throw "Error: range.assign(" + c1 + "," + r1 + "," + c2 + "," + r2 + ") - numerical args are expected";
			}
			this.c1 = c1;
			this.r1 = r1;
			this.c2 = c2;
			this.r2 = r2;
			return normalize ? this.normalize() : this;
		};
		Range.prototype.assign2 = function (range) {
			this.refType1 = range.refType1;
			this.refType2 = range.refType2;
			return this.assign(range.c1, range.r1, range.c2, range.r2);
		};

		Range.prototype.clone = function (normalize) {
			var oRes = new Range(this.c1, this.r1, this.c2, this.r2, normalize);
			oRes.refType1 = this.refType1;
			oRes.refType2 = this.refType2;
			return oRes;
		};

		Range.prototype.normalize = function () {
			var tmp;
			if (this.c1 > this.c2) {
				tmp = this.c1;
				this.c1 = this.c2;
				this.c2 = tmp;
			}
			if (this.r1 > this.r2) {
				tmp = this.r1;
				this.r1 = this.r2;
				this.r2 = tmp;
			}
			return this;
		};

		Range.prototype.isEqual = function (range) {
			return range && this.c1 === range.c1 && this.r1 === range.r1 && this.c2 === range.c2 && this.r2 === range.r2;
		};

		Range.prototype.isEqualAll = function (range) {
			return this.isEqual(range) && this.refType1 === range.refType1 && this.refType2 === range.refType2;
		};
		Range.prototype.isEqualWithOffsetRow = function (range, offsetRow) {
			return this.c1 === range.c1 && this.c2 === range.c2 &&
				this.isAbsC1() === range.isAbsC1() && this.isAbsC2() === range.isAbsC2() &&
				this.isAbsR1() === range.isAbsR1() && this.isAbsR2() === range.isAbsR2() &&
				(((this.isAbsR1() ? this.r1 === range.r1 : this.r1 + offsetRow === range.r1) &&
				(this.isAbsR2() ? this.r2 === range.r2 : this.r2 + offsetRow === range.r2)) ||
				(this.r1 === 0 && this.r2 === gc_nMaxRow0 && this.r1 === range.r1 && this.r2 === range.r2));
		};

		Range.prototype.contains = function (c, r) {
			return this.c1 <= c && c <= this.c2 && this.r1 <= r && r <= this.r2;
		};
		Range.prototype.contains2 = function (cell) {
			return this.contains(cell.col, cell.row);
		};

		Range.prototype.containsRange = function (range) {
			return this.contains(range.c1, range.r1) && this.contains(range.c2, range.r2);
		};

		Range.prototype.containsFirstLineRange = function (range) {
			return this.contains(range.c1, range.r1) && this.contains(range.c2, range.r1);
		};

		Range.prototype.intersection = function (range) {
			var s1 = this.clone(true), s2 = range instanceof Range ? range.clone(true) :
				new Range(range.c1, range.r1, range.c2, range.r2, true);

			if (s2.c1 > s1.c2 || s2.c2 < s1.c1 || s2.r1 > s1.r2 || s2.r2 < s1.r1) {
				return null;
			}

			return new Range(s2.c1 >= s1.c1 && s2.c1 <= s1.c2 ? s2.c1 : s1.c1, s2.r1 >= s1.r1 && s2.r1 <= s1.r2 ? s2.r1 :
				s1.r1, Math.min(s1.c2, s2.c2), Math.min(s1.r2, s2.r2));
		};

		Range.prototype.intersectionSimple = function (range) {
			var oRes = null;
			var r1 = Math.max(this.r1, range.r1);
			var c1 = Math.max(this.c1, range.c1);
			var r2 = Math.min(this.r2, range.r2);
			var c2 = Math.min(this.c2, range.c2);
			if (r1 <= r2 && c1 <= c2) {
				oRes = new Range(c1, r1, c2, r2);
			}
			return oRes;
		};

		Range.prototype.isIntersect = function (range) {
			var bRes = true;
			if (range.r2 < this.r1 || this.r2 < range.r1) {
				bRes = false;
			} else if (range.c2 < this.c1 || this.c2 < range.c1) {
				bRes = false;
			}
			return bRes;
		};

		Range.prototype.isIntersectForShift = function(range, offset) {
			var isHor = offset && offset.col;
			var isDelete = offset && (offset.col < 0 || offset.row < 0);
			if (isHor) {
				if (this.r1 <= range.r1 && range.r2 <= this.r2 && this.c1 <= range.c2) {
					return (this.c1 < range.c1 || (!isDelete && this.c1 === range.c1 && this.c2 === range.c1)) ?
						c_oAscShiftType.Move : c_oAscShiftType.Change;
				} else if (isDelete && this.c1 <= range.c1 && range.c2 <= this.c2) {
					var topIn = this.r1 <= range.r1 && range.r1 <= this.r2;
					var bottomIn = this.r1 <= range.r2 && range.r2 <= this.r2;
					return topIn || bottomIn;
				}
			} else {
				if (this.c1 <= range.c1 && range.c2 <= this.c2 && this.r1 <= range.r2) {
					return (this.r1 < range.r1 || (!isDelete && this.r1 === range.r1 && this.r2 === range.r1)) ?
						c_oAscShiftType.Move : c_oAscShiftType.Change;
				} else if (isDelete && this.r1 <= range.r1 && range.r2 <= this.r2) {
					var leftIn = this.c1 <= range.c1 && range.c1 <= this.c2;
					var rightIn = this.c1 <= range.c2 && range.c2 <= this.c2;
					return leftIn || rightIn;
				}
			}
			return c_oAscShiftType.None;
		};

		Range.prototype.difference = function(range) {
			var res = [];
			var intersect;
			if (this.r1 > 0) {
				intersect = new Range(0, 0, gc_nMaxCol0, this.r1 - 1).intersectionSimple(range);
				if (intersect) {
					res.push(intersect);
				}
			}
			if (this.c1 > 0) {
				intersect = new Range(0, this.r1, this.c1 - 1, this.r2).intersectionSimple(range);
				if (intersect) {
					res.push(intersect);
				}
			}
			if (this.c2 < gc_nMaxCol0) {
				intersect = new Range(this.c2 + 1, this.r1, gc_nMaxCol0, this.r2).intersectionSimple(range);
				if (intersect) {
					res.push(intersect);
				}
			}
			if (this.r2 < gc_nMaxRow0) {
				intersect = new Range(0, this.r2 + 1, gc_nMaxCol0, gc_nMaxRow0).intersectionSimple(range);
				if (intersect) {
					res.push(intersect);
				}
			}
			return res;
		};
		Range.prototype.isIntersectForShiftCell = function(col, row, offset) {
			var isHor = offset && 0 != offset.col;
			if (isHor) {
				return this.r1 <= row && row <= this.r2 && this.c1 <= col;
			} else {
				return this.c1 <= col && col <= this.c2 && this.r1 <= row;
			}
		};

		Range.prototype.forShift = function(bbox, offset, bUndo) {
			var isNoDelete = true;
			var isHor = 0 != offset.col;
			var toDelete = offset.col < 0 || offset.row < 0;

			if (isHor) {
				if (toDelete) {
					if (this.c1 < bbox.c1) {
						if (this.c2 <= bbox.c2) {
							this.setOffsetLast(new AscCommon.CellBase(0, -(this.c2 - bbox.c1 + 1)));
						} else {
							this.setOffsetLast(offset);
						}
					} else if (this.c1 <= bbox.c2) {
						if (this.c2 <= bbox.c2) {
							if(!bUndo){
								var topIn = bbox.r1 <= this.r1 && this.r1 <= bbox.r2;
								var bottomIn = bbox.r1 <= this.r2 && this.r2 <= bbox.r2;
								if (topIn && bottomIn) {
									isNoDelete = false;
								} else if (topIn) {
									this.setOffsetFirst(new AscCommon.CellBase(bbox.r2 - this.r1 + 1, 0));
								} else if (bottomIn) {
									this.setOffsetLast(new AscCommon.CellBase(bbox.r1 - this.r2 - 1, 0));
								}
							}
						} else {
							this.setOffsetFirst(new AscCommon.CellBase(0, bbox.c1 - this.c1));
							this.setOffsetLast(offset);
						}
					} else {
						this.setOffset(offset);
					}
				} else {
					if (this.c1 < bbox.c1) {
						this.setOffsetLast(offset);
					} else {
						this.setOffset(offset);
					}
				}
			} else {
				if (toDelete) {
					if (this.r1 < bbox.r1) {
						if (this.r2 <= bbox.r2) {
							this.setOffsetLast(new AscCommon.CellBase(-(this.r2 - bbox.r1 + 1), 0));
						} else {
							this.setOffsetLast(offset);
						}
					} else if (this.r1 <= bbox.r2) {
						if (this.r2 <= bbox.r2) {
							if(!bUndo) {
								var leftIn = bbox.c1 <= this.c1 && this.c1 <= bbox.c2;
								var rightIn = bbox.c1 <= this.c2 && this.c2 <= bbox.c2;
								if (leftIn && rightIn) {
									isNoDelete = false;
								} else if (leftIn) {
									this.setOffsetFirst(new AscCommon.CellBase(0, bbox.c2 - this.c1 + 1));
								} else if (rightIn) {
									this.setOffsetLast(new AscCommon.CellBase(0, bbox.c1 - this.c2 - 1));
								}
							}
						} else {
							this.setOffsetFirst(new AscCommon.CellBase(bbox.r1 - this.r1, 0));
							this.setOffsetLast(offset);
						}
					} else {
						this.setOffset(offset);
					}
				} else {
					if (this.r1 < bbox.r1) {
						this.setOffsetLast(offset);
					} else {
						this.setOffset(offset);
					}
				}
			}
			return isNoDelete;
		};

		Range.prototype.isOneCell = function () {
			return this.r1 === this.r2 && this.c1 === this.c2;
		};

		Range.prototype.isOnTheEdge = function (c, r) {
			return this.r1 === r || this.r2 === r || this.c1 === c || this.c2 === c;
		};

		Range.prototype.union = function (range) {
			var s1 = this.clone(true), s2 = range instanceof Range ? range.clone(true) :
				new Range(range.c1, range.r1, range.c2, range.r2, true);

			return new Range(Math.min(s1.c1, s2.c1), Math.min(s1.r1, s2.r1), Math.max(s1.c2, s2.c2), Math.max(s1.r2, s2.r2));
		};

		Range.prototype.union2 = function (range) {
			this.c1 = Math.min(this.c1, range.c1);
			this.c2 = Math.max(this.c2, range.c2);
			this.r1 = Math.min(this.r1, range.r1);
			this.r2 = Math.max(this.r2, range.r2);
		};

		Range.prototype.union3 = function (c, r) {
			this.c1 = Math.min(this.c1, c);
			this.c2 = Math.max(this.c2, c);
			this.r1 = Math.min(this.r1, r);
			this.r2 = Math.max(this.r2, r);
		};
		Range.prototype.setOffsetWithAbs = function(offset, opt_canResize, opt_circle) {
			var temp;
			var row = offset.row;
			var col = offset.col;
			//todo offset A1048576:A1 (row = 1 -> A1:A2; row = -1 -> A1048575:A1048576)
			if (0 === this.r1 && gc_nMaxRow0 === this.r2) {
				//full sheet is 1:1048576 but row is valid for it
				row = 0;
			} else if (0 === this.c1 && gc_nMaxCol0 === this.c2) {
				col = 0;
			}
			var isAbsRow1 = this.isAbsRow(this.refType1);
			var isAbsCol1 = this.isAbsCol(this.refType1);
			var isAbsRow2 = this.isAbsRow(this.refType2);
			var isAbsCol2 = this.isAbsCol(this.refType2);
			if (!isAbsRow1) {
				this.r1 += row;
				if (this.r1 < 0) {
					if (opt_circle) {
						this.r1 += gc_nMaxRow0 + 1;
					} else {
						this.r1 = 0;
						if (!opt_canResize) {
							return false;
						}
					}
				}
				if (this.r1 > gc_nMaxRow0) {
					if (opt_circle) {
						this.r1 -= gc_nMaxRow0 + 1;
					} else {
						this.r1 = gc_nMaxRow0;
						return false;
					}
				}
			}
			if (!isAbsCol1) {
				this.c1 += col;
				if (this.c1 < 0) {
					if (opt_circle) {
						this.c1 += gc_nMaxCol0 + 1;
					} else {
						this.c1 = 0;
						if (!opt_canResize) {
							return false;
						}
					}
				}
				if (this.c1 > gc_nMaxCol0) {
					if (opt_circle) {
						this.c1 -= gc_nMaxCol0 + 1;
					} else {
						this.c1 = gc_nMaxCol0;
						return false;
					}
				}
			}
			if (!isAbsRow2) {
				this.r2 += row;
				if (this.r2 < 0) {
					if (opt_circle) {
						this.r2 += gc_nMaxRow0 + 1;
					} else {
						this.r2 = 0;
						return false;
					}
				}
				if (this.r2 > gc_nMaxRow0) {
					if (opt_circle) {
						this.r2 -= gc_nMaxRow0 + 1;
					} else {
						this.r2 = gc_nMaxRow0;
						if (!opt_canResize) {
							return false;
						}
					}
				}
			}
			if (!isAbsCol2) {
				this.c2 += col;
				if (this.c2 < 0) {
					if (opt_circle) {
						this.c2 += gc_nMaxCol0 + 1;
					} else {
						this.c2 = 0;
						return false;
					}
				}
				if (this.c2 > gc_nMaxCol0) {
					if (opt_circle) {
						this.c2 -= gc_nMaxCol0 + 1;
					} else {
						this.c2 = gc_nMaxCol0;
						if (!opt_canResize) {
							return false;
						}
					}
				}
			}
			//switch abs flag
			if (this.r1 > this.r2) {
				temp = this.r1;
				this.r1 = this.r2;
				this.r2 = temp;
				if (!isAbsRow1 && isAbsRow2) {
					isAbsRow1 = !isAbsRow1;
					isAbsRow2 = !isAbsRow2;
					this.setAbs(isAbsRow1, isAbsCol1, isAbsRow2, isAbsCol2);
				}
			}
			if (this.c1 > this.c2) {
				temp = this.c1;
				this.c1 = this.c2;
				this.c2 = temp;
				if (!isAbsCol1 && isAbsCol2) {
					isAbsCol1 = !isAbsCol1;
					isAbsCol2 = !isAbsCol2;
					this.setAbs(isAbsRow1, isAbsCol1, isAbsRow2, isAbsCol2);
				}
			}
			return true;
		};
		Range.prototype.setOffset = function (offset) {
			if (this.r1 == 0 && this.r2 == gc_nMaxRow0 && offset.row != 0 ||
				this.c1 == 0 && this.c2 == gc_nMaxCol0 && offset.col != 0) {
				return;
			}
			this.setOffsetFirst(offset);
			this.setOffsetLast(offset);
		};

		Range.prototype.setOffsetFirst = function (offset) {
			this.c1 += offset.col;
			if (this.c1 < 0) {
				this.c1 = 0;
			}
			if (this.c1 > gc_nMaxCol0) {
				this.c1 = gc_nMaxCol0;
			}
			this.r1 += offset.row;
			if (this.r1 < 0) {
				this.r1 = 0;
			}
			if (this.r1 > gc_nMaxRow0) {
				this.r1 = gc_nMaxRow0;
			}
		};

		Range.prototype.setOffsetLast = function (offset) {
			this.c2 += offset.col;
			if (this.c2 < 0) {
				this.c2 = 0;
			}
			if (this.c2 > gc_nMaxCol0) {
				this.c2 = gc_nMaxCol0;
			}
			this.r2 += offset.row;
			if (this.r2 < 0) {
				this.r2 = 0;
			}
			if (this.r2 > gc_nMaxRow0) {
				this.r2 = gc_nMaxRow0;
			}
		};

		Range.prototype._getName = function (val, isCol, abs) {
			var isR1C1Mode = AscCommonExcel.g_R1C1Mode;
			val += 1;
			if (isCol && !isR1C1Mode) {
				val = g_oCellAddressUtils.colnumToColstr(val);
			}
			return (isR1C1Mode ? (isCol ? 'C' : 'R') : '') + (abs ? (isR1C1Mode ? val : '$' + val) :
				(isR1C1Mode ? ((0 !== (val = (val - (isCol ? AscCommonExcel.g_ActiveCell.c1 :
					AscCommonExcel.g_ActiveCell.r1) - 1))) ? '[' + val + ']' : '') : val));
		};
		Range.prototype.getName = function (refType) {
			var isR1C1Mode = AscCommonExcel.g_R1C1Mode;
			var c, r, type = this.getType();
			var sRes = "";
			var c1Abs, c2Abs, r1Abs, r2Abs;
			if (referenceType.A === refType) {
				c1Abs = c2Abs = r1Abs = r2Abs = true;
			} else if (referenceType.R === refType) {
				c1Abs = c2Abs = r1Abs = r2Abs = false;
			} else {
				c1Abs = this.isAbsCol(this.refType1);
				c2Abs = this.isAbsCol(this.refType2);
				r1Abs = this.isAbsRow(this.refType1);
				r2Abs = this.isAbsRow(this.refType2);
			}

			if ((c_oAscSelectionType.RangeMax === type || c_oAscSelectionType.RangeRow === type) && c1Abs === c2Abs) {
				sRes = this._getName(this.r1, false, r1Abs);
				if (this.r1 !== this.r2 || r1Abs !== r2Abs || !isR1C1Mode) {
					sRes += ':' + this._getName(this.r2, false, r2Abs);
				}
			} else if ((c_oAscSelectionType.RangeMax === type || c_oAscSelectionType.RangeCol === type) && r1Abs === r2Abs) {
				sRes = this._getName(this.c1, true, c1Abs);
				if (this.c1 !== this.c2 || c1Abs !== c2Abs || !isR1C1Mode) {
					sRes += ':' + this._getName(this.c2, true, c2Abs);
				}
			} else {
				r = this._getName(this.r1, false, r1Abs);
				c = this._getName(this.c1, true, c1Abs);
				sRes = isR1C1Mode ? r + c : c + r;

				if (!this.isOneCell() || r1Abs !== r2Abs || c1Abs !== c2Abs) {
					r = this._getName(this.r2, false, r2Abs);
					c = this._getName(this.c2, true, c2Abs);
					sRes += ':' + (isR1C1Mode ? r + c : c + r);
				}
			}
			return sRes;
		};

		Range.prototype.getAbsName = function () {
			return this.getName(referenceType.A);
		};

		Range.prototype.getType = function () {
			var bRow = 0 === this.c1 && gc_nMaxCol0 === this.c2;
			var bCol = 0 === this.r1 && gc_nMaxRow0 === this.r2;
			var res;
			if (bCol && bRow) {
				res = c_oAscSelectionType.RangeMax;
			} else if (bCol) {
				res = c_oAscSelectionType.RangeCol;
			} else if (bRow) {
				res = c_oAscSelectionType.RangeRow;
			} else {
				res = c_oAscSelectionType.RangeCells;
			}
			return res;
		};

		Range.prototype.getSharedRange = function (sharedRef, c, r) {
			var isAbsR1 = this.isAbsR1();
			var isAbsC1 = this.isAbsC1();
			var isAbsR2 = this.isAbsR2();
			var isAbsC2 = this.isAbsC2();
			if(this.r1 === 0 && this.r2 === gc_nMaxRow0){
				isAbsR1 = isAbsR2 = true;
			}
			if(this.c1 === 0 && this.c2 === gc_nMaxCol0){
				isAbsC1 = isAbsC2 = true;
			}
			var r1 = isAbsR2 ? sharedRef.r1 : Math.max(sharedRef.r2 + (r - this.r2), sharedRef.r1);
			var c1 = isAbsC2 ? sharedRef.c1 : Math.max(sharedRef.c2 + (c - this.c2), sharedRef.c1);
			var r2 = isAbsR1 ? sharedRef.r2 : Math.min(sharedRef.r1 + (r - this.r1), sharedRef.r2);
			var c2 = isAbsC1 ? sharedRef.c2 : Math.min(sharedRef.c1 + (c - this.c1), sharedRef.c2);
			return new Range(c1, r1, c2, r2);
		};
		Range.prototype.getSharedRangeBbox = function(ref, base) {
			var res = this.clone();
			var shiftBase;
			var offset = new AscCommon.CellBase(ref.r1 - base.nRow, ref.c1 - base.nCol);
			if (!offset.isEmpty()) {
				shiftBase = this.clone();
				shiftBase.setOffsetWithAbs(offset, false, false);
			}
			offset.row = ref.r2 - base.nRow;
			offset.col = ref.c2 - base.nCol;
			res.setOffsetWithAbs(offset, false, false);
			res.union2(shiftBase ? shiftBase : this);
			return res;
		};
		Range.prototype.getSharedIntersect = function(sharedRef, bbox) {
			var leftTop = this.getSharedRange(sharedRef, bbox.c1, bbox.r1);
			var rightBottom = this.getSharedRange(sharedRef, bbox.c2, bbox.r2);
			return leftTop.union(rightBottom);
		};
		Range.prototype.setAbs = function (absRow1, absCol1, absRow2, absCol2) {
			this.refType1 = (absRow1 ? 0 : 2) + (absCol1 ? 0 : 1);
			this.refType2 = (absRow2 ? 0 : 2) + (absCol2 ? 0 : 1);
		};
		Range.prototype.isAbsCol = function (refType) {
			return (refType === referenceType.A || refType === referenceType.RRAC);
		};
		Range.prototype.isAbsRow = function (refType) {
			return (refType === referenceType.A || refType === referenceType.ARRC);
		};
		Range.prototype.isAbsR1 = function () {
			return this.isAbsRow(this.refType1);
		};
		Range.prototype.isAbsC1 = function () {
			return this.isAbsCol(this.refType1);
		};
		Range.prototype.isAbsR2 = function () {
			return this.isAbsRow(this.refType2);
		};
		Range.prototype.isAbsC2 = function () {
			return this.isAbsCol(this.refType2);
		};
		Range.prototype.isAbsAll = function () {
			return this.isAbsR1() && this.isAbsC1() && this.isAbsR2() && this.isAbsC2();
		};
		Range.prototype.switchReference = function () {
			this.refType1 = (this.refType1 + 1) % 4;
			this.refType2 = (this.refType2 + 1) % 4;
		};

		/**
		 *
     * @constructor
		 * @extends {Range}
     */
		function Range3D() {
			this.sheet = '';
			this.sheet2 = '';

			if (3 == arguments.length) {
				var range = arguments[0];
				Range.call(this, range.c1, range.r1, range.c2, range.r2);
				// ToDo стоит пересмотреть конструкторы.
				this.refType1 = range.refType1;
				this.refType2 = range.refType2;

				this.sheet = arguments[1];
				this.sheet2 = arguments[2];
			} else if (arguments.length > 1) {
				Range.apply(this, arguments);
			} else {
				Range.call(this, 0, 0, 0, 0);
      }
		}
		Range3D.prototype = Object.create(Range.prototype);
		Range3D.prototype.constructor = Range3D;
		Range3D.prototype.isIntersect = function () {
			var oRes = true;
			
			if (2 == arguments.length) {
				oRes = this.sheet === arguments[1];
			}
			return oRes && Range.prototype.isIntersect.apply(this, arguments);
		};
		Range3D.prototype.clone = function () {
			return new Range3D(Range.prototype.clone.apply(this, arguments), this.sheet, this.sheet2);
		};
		Range3D.prototype.setSheet = function (sheet, sheet2) {
			this.sheet = sheet;
			this.sheet2 = sheet2 ? sheet2 : sheet;
		};
		Range3D.prototype.getName = function () {
			return AscCommon.parserHelp.get3DRef(this.sheet, Range.prototype.getName.apply(this));
		};

		/**
		 * @constructor
		 */
		function SelectionRange(ws) {
			this.ranges = [new Range(0, 0, 0, 0)];
			this.activeCell = new AscCommon.CellBase(0, 0); // Active cell
			this.activeCellId = 0;

			this.worksheet = ws;
		}

		SelectionRange.prototype.clean = function () {
			this.ranges = [new Range(0, 0, 0, 0)];
			this.activeCellId = 0;
			this.activeCell.clean();
		};
		SelectionRange.prototype.contains = function (c, r) {
			return this.ranges.some(function (item) {
				return item.contains(c, r);
			});
		};
		SelectionRange.prototype.contains2 = function (cell) {
			return this.contains(cell.col, cell.row);
		};
		SelectionRange.prototype.inContains = function (ranges) {
			var t = this;
			return this.ranges.every(function (item1) {
				return ranges.some(function (item2) {
					return item2.containsRange(item1);
				});
			});
		};
		SelectionRange.prototype.containsRange = function (range) {
			return this.ranges.some(function (item) {
				return item.containsRange(range);
			});
		};
		SelectionRange.prototype.clone = function (worksheet) {
			var res = new SelectionRange();
			res.ranges = this.ranges.map(function (range) {
				return range.clone();
			});
			res.activeCell = this.activeCell.clone();
			res.activeCellId = this.activeCellId;
			res.worksheet = worksheet || this.worksheet;
			return res;
		};
		SelectionRange.prototype.isEqual = function (range) {
			if (this.activeCellId !== range.activeCellId || !this.activeCell.isEqual(range.activeCell) ||
				this.ranges.length !== range.ranges.length) {
				return false;
			}
			for (var i = 0; i < this.ranges.length; ++i) {
				if (!this.ranges[i].isEqual(range.ranges[i])) {
					return false;
				}
			}
			return true;
		};
		SelectionRange.prototype.addRange = function () {
			this.activeCellId = this.ranges.push(new Range(0, 0, 0, 0)) - 1;
			this.activeCell.clean();
		};
		SelectionRange.prototype.assign2 = function (range) {
			this.clean();
			this.getLast().assign2(range);
			this.update();
		};
		SelectionRange.prototype.union = function (range) {
			var res = this.ranges.some(function (item) {
				var success = false;
				if (item.c1 === range.c1 && item.c2 === range.c2) {
					if (range.r1 === item.r2 + 1) {
						item.r2 = range.r2;
						success = true;
					} else if (range.r2 === item.r1 - 1) {
						item.r1 = range.r1;
						success = true;
					}
				} else if (item.r1 === range.r1 && item.r2 === range.r2) {
					if (range.c1 === item.c2 + 1) {
						item.c2 = range.c2;
						success = true;
					} else if (range.c2 === item.c1 - 1) {
						item.c1 = range.c1;
						success = true;
					}
				}
				return success;
			});
			if (!res) {
				this.addRange();
				this.getLast().assign2(range);
			}
		};
		SelectionRange.prototype.getUnion = function () {
			var result = new SelectionRange(this.worksheet);
			var unionRanges = function (ranges, res) {
				for (var i = 0; i < ranges.length; ++i) {
					if (0 === i) {
						res.assign2(ranges[i]);
					} else {
						res.union(ranges[i]);
					}
				}
			};
			unionRanges(this.ranges, result);

			var isUnion = true, resultTmp;
			while (isUnion && !result.isSingleRange()) {
				resultTmp = new SelectionRange(this.worksheet);
				unionRanges(result.ranges, resultTmp);
				isUnion = result.ranges.length !== resultTmp.ranges.length;
				result = resultTmp;
			}
			return result;
		};
		SelectionRange.prototype.offsetCell = function (dr, dc, changeRange, fCheckSize) {
			var done, curRange, mc, incompleate;
			// Check one cell
			if (1 === this.ranges.length) {
				curRange = this.ranges[this.activeCellId];
				if (curRange.isOneCell()) {
					return 0;
				} else {
					mc = this.worksheet.getMergedByCell(this.activeCell.row, this.activeCell.col);
					if (mc && curRange.isEqual(mc)) {
						return 0;
					}
				}
			}

			var lastRow = this.activeCell.row;
			var lastCol = this.activeCell.col;
			this.activeCell.row += dr;
			this.activeCell.col += dc;

			while (!done) {
				done = true;

				curRange = this.ranges[this.activeCellId];
				if (!curRange.contains2(this.activeCell)) {
					if (dr) {
						if (0 < dr) {
							this.activeCell.row = curRange.r1;
							this.activeCell.col += 1;
						} else {
							this.activeCell.row = curRange.r2;
							this.activeCell.col -= 1;
						}
					} else {
						if (0 < dc) {
							this.activeCell.row += 1;
							this.activeCell.col = curRange.c1;
						} else {
							this.activeCell.row -= 1;
							this.activeCell.col = curRange.c2;
						}
					}

					if (!curRange.contains2(this.activeCell)) {
						if (!changeRange) {
							this.activeCell.row = lastRow;
							this.activeCell.col = lastCol;
							return -1;
						}
						if (0 < dc || 0 < dr) {
							this.activeCellId += 1;
							this.activeCellId = (this.ranges.length > this.activeCellId) ? this.activeCellId : 0;
							curRange = this.ranges[this.activeCellId];

							this.activeCell.row = curRange.r1;
							this.activeCell.col = curRange.c1;
						} else {
							this.activeCellId -= 1;
							this.activeCellId = (0 <= this.activeCellId) ? this.activeCellId : this.ranges.length - 1;
							curRange = this.ranges[this.activeCellId];

							this.activeCell.row = curRange.r2;
							this.activeCell.col = curRange.c2;
						}
					}
				}

				mc = this.worksheet.getMergedByCell(this.activeCell.row, this.activeCell.col);

				if (mc) {
					incompleate = !curRange.containsRange(mc);
					if (dc > 0 && (incompleate || this.activeCell.col > mc.c1 || this.activeCell.row !== mc.r1)) {
						// Движение слева направо
						this.activeCell.col = mc.c2 + 1;
						done = false;
					} else if (dc < 0 && (incompleate || this.activeCell.col < mc.c2 || this.activeCell.row !== mc.r1)) {
						// Движение справа налево
						this.activeCell.col = mc.c1 - 1;
						done = false;
					}
					if (dr > 0 && (incompleate || this.activeCell.row > mc.r1 || this.activeCell.col !== mc.c1)) {
						// Движение сверху вниз
						this.activeCell.row = mc.r2 + 1;
						done = false;
					} else if (dr < 0 && (incompleate || this.activeCell.row < mc.r2 || this.activeCell.col !== mc.c1)) {
						// Движение снизу вверх
						this.activeCell.row = mc.r1 - 1;
						done = false;
					}
				}
				if (!done) {
					continue;
				}

				while (this.activeCell.col >= curRange.c1 && this.activeCell.col <= curRange.c2 && fCheckSize(-1, this.activeCell.col)) {
					this.activeCell.col += dc || (dr > 0 ? +1 : -1);
					done = false;
				}
				if (!done) {
					continue;
				}

				while (this.activeCell.row >= curRange.r1 && this.activeCell.row <= curRange.r2 && fCheckSize(this.activeCell.row, -1)) {
					this.activeCell.row += dr || (dc > 0 ? +1 : -1);
					done = false;
				}

				if (!done) {
					continue;
				}

				break;
			}
			return (lastRow !== this.activeCell.row || lastCol !== this.activeCell.col) ? 1 : -1;
		};
		SelectionRange.prototype.setCell = function (r, c) {
			var res = false;
			this.activeCell.row = r;
			this.activeCell.col = c;
			this.update();

			// Check active cell in merge cell (bug 36708)
			var mc = this.worksheet.getMergedByCell(this.activeCell.row, this.activeCell.col);
			if (this.worksheet.getMergedByCell(this.activeCell.row, this.activeCell.col)) {
				res = -1 === this.offsetCell(1, 0, false, function () {return false;});
				if (res) {
					this.activeCell.row = mc.r1;
					this.activeCell.col = mc.c1;
				}
			}
			return res;
		};
		SelectionRange.prototype.getLast = function () {
			return this.ranges[this.ranges.length - 1];
		};
		SelectionRange.prototype.isSingleRange = function () {
			return 1 === this.ranges.length;
		};
		SelectionRange.prototype.update = function () {
			//меняем выделеную ячейку, если она не входит в диапазон
			//возможно, в будующем придется пределать логику, пока нет примеров, когда это работает плохо
			var range = this.ranges[this.activeCellId];
			if (!range || !range.contains(this.activeCell.col, this.activeCell.row)) {
				range = this.getLast();
				this.activeCell.col = range.c1;
				this.activeCell.row = range.r1;
				this.activeCellId = this.ranges.length - 1;
			}
		};
		SelectionRange.prototype.WriteToBinary = function(w) {
			w.WriteLong(this.ranges.length);
			for (var i = 0; i < this.ranges.length; ++i) {
				var range = this.ranges[i];
				w.WriteLong(range.c1);
				w.WriteLong(range.r1);
				w.WriteLong(range.c2);
				w.WriteLong(range.r2);
			}
			w.WriteLong(this.activeCell.row);
			w.WriteLong(this.activeCell.col);
			w.WriteLong(this.activeCellId);
		};
		SelectionRange.prototype.ReadFromBinary = function(r) {
			this.clean();
			var count = r.GetLong();
			var rangesNew = [];
			for (var i = 0; i < count; ++i) {
				var range = new Asc.Range(r.GetLong(), r.GetLong(), r.GetLong(), r.GetLong());
				rangesNew.push(range);
			}
			if (rangesNew.length > 0) {
				this.ranges = rangesNew;
			}
			this.activeCell.row = r.GetLong();
			this.activeCell.col = r.GetLong();
			this.activeCellId = r.GetLong();
			this.update();
		};
		SelectionRange.prototype.Select = function () {
			this.worksheet.selectionRange = this.clone();
			this.worksheet.workbook.handlers.trigger('updateSelection');
		};

    /**
     *
     * @constructor
     * @extends {Range}
     */
		function ActiveRange(){
			if(1 == arguments.length)
			{
				var range = arguments[0];
				Range.call(this, range.c1, range.r1, range.c2, range.r2);
				// ToDo стоит пересмотреть конструкторы.
				this.refType1 = range.refType1;
				this.refType2 = range.refType2;
			}
			else if(arguments.length > 1)
				Range.apply(this, arguments);
			else
				Range.call(this, 0, 0, 0, 0);
			this.startCol = 0; // Активная ячейка в выделении
			this.startRow = 0; // Активная ячейка в выделении
			this._updateAdditionalData();
		}

		ActiveRange.prototype = Object.create(Range.prototype);
		ActiveRange.prototype.constructor = ActiveRange;
		ActiveRange.prototype.assign = function () {
			Range.prototype.assign.apply(this, arguments);
			this._updateAdditionalData();
			return this;
		};
		ActiveRange.prototype.assign2 = function () {
			Range.prototype.assign2.apply(this, arguments);
			this._updateAdditionalData();
			return this;
		};
		ActiveRange.prototype.clone = function(){
			var oRes = new ActiveRange(Range.prototype.clone.apply(this, arguments));
			oRes.startCol = this.startCol;
			oRes.startRow = this.startRow;
			return oRes;
		};
		ActiveRange.prototype.normalize = function () {
			Range.prototype.normalize.apply(this, arguments);
			this._updateAdditionalData();
			return this;
		};
		ActiveRange.prototype.isEqualAll = function () {
			var bRes = Range.prototype.isEqual.apply(this, arguments);
			if(bRes && arguments.length > 0)
			{
				var range = arguments[0];
				bRes = this.startCol == range.startCol && this.startRow == range.startRow;
			}
			return bRes;
		};
		ActiveRange.prototype.contains = function () {
			return Range.prototype.contains.apply(this, arguments);
		};
		ActiveRange.prototype.containsRange = function () {
			return Range.prototype.containsRange.apply(this, arguments);
		};
		ActiveRange.prototype.containsFirstLineRange = function () {
			return Range.prototype.containsFirstLineRange.apply(this, arguments);
		};
		ActiveRange.prototype.intersection = function () {
			var oRes = Range.prototype.intersection.apply(this, arguments);
			if(null != oRes)
			{
				oRes = new ActiveRange(oRes);
				oRes._updateAdditionalData();
			}
			return oRes;
		};
		ActiveRange.prototype.intersectionSimple = function () {
			var oRes = Range.prototype.intersectionSimple.apply(this, arguments);
			if(null != oRes)
			{
				oRes = new ActiveRange(oRes);
				oRes._updateAdditionalData();
			}
			return oRes;
		};
		ActiveRange.prototype.union = function () {
			var oRes = new ActiveRange(Range.prototype.union.apply(this, arguments));
			oRes._updateAdditionalData();
			return oRes;
		};
		ActiveRange.prototype.union2 = function () {
			Range.prototype.union2.apply(this, arguments);
			this._updateAdditionalData();
			return this;
		};
		ActiveRange.prototype.union3 = function () {
			Range.prototype.union3.apply(this, arguments);
			this._updateAdditionalData();
			return this;
		};
		ActiveRange.prototype.setOffset = function(offset){
			this.setOffsetFirst(offset);
			this.setOffsetLast(offset);
		};
		ActiveRange.prototype.setOffsetFirst = function(offset){
			Range.prototype.setOffsetFirst.apply(this, arguments);
			this._updateAdditionalData();
			return this;
		};
		ActiveRange.prototype.setOffsetLast = function(offset){
			Range.prototype.setOffsetLast.apply(this, arguments);
			this._updateAdditionalData();
			return this;
		};
		ActiveRange.prototype._updateAdditionalData = function(){
			//меняем выделеную ячейку, если она не входит в диапазон
			//возможно, в будующем придется пределать логику, пока нет примеров, когда это работает плохо
			if(!this.contains(this.startCol, this.startRow))
			{
				this.startCol = this.c1;
				this.startRow = this.r1;
			}
		};

    /**
     *
     * @constructor
     * @extends {Range}
     */
		function FormulaRange(){
			if(1 == arguments.length)
			{
				var range = arguments[0];
				Range.call(this, range.c1, range.r1, range.c2, range.r2);
			}
			else if(arguments.length > 1)
				Range.apply(this, arguments);
			else
				Range.call(this, 0, 0, 0, 0);

			this.refType1 = referenceType.R;
			this.refType2 = referenceType.R;
		}

		FormulaRange.prototype = Object.create(Range.prototype);
		FormulaRange.prototype.constructor = FormulaRange;
		FormulaRange.prototype.clone = function () {
			var oRes = new FormulaRange(Range.prototype.clone.apply(this, arguments));
			oRes.refType1 = this.refType1;
			oRes.refType2 = this.refType2;
			return oRes;
		};
		FormulaRange.prototype.intersection = function () {
			var oRes = Range.prototype.intersection.apply(this, arguments);
			if(null != oRes)
				oRes = new FormulaRange(oRes);
			return oRes;
		};
		FormulaRange.prototype.intersectionSimple = function () {
			var oRes = Range.prototype.intersectionSimple.apply(this, arguments);
			if(null != oRes)
				oRes = new FormulaRange(oRes);
			return oRes;
		};
		FormulaRange.prototype.union = function () {
			return new FormulaRange(Range.prototype.union.apply(this, arguments));
		};
		FormulaRange.prototype.getName = function () {
			var sRes = "";
			var c1Abs = this.isAbsCol(this.refType1), c2Abs = this.isAbsCol(this.refType2);
			var r1Abs = this.isAbsRow(this.refType1), r2Abs = this.isAbsRow(this.refType2);

			if(0 == this.c1 && gc_nMaxCol0 == this.c2)
			{
				if(r1Abs)
					sRes += "$";
				sRes += (this.r1 + 1) + ":";
				if(r2Abs)
					sRes += "$";
				sRes += (this.r2 + 1);
			}
			else if(0 == this.r1 && gc_nMaxRow0 == this.r2)
			{
				if(c1Abs)
					sRes += "$";
				sRes += g_oCellAddressUtils.colnumToColstr(this.c1 + 1) + ":";
				if(c2Abs)
					sRes += "$";
				sRes += g_oCellAddressUtils.colnumToColstr(this.c2 + 1);
			}
			else
			{
				if(c1Abs)
					sRes += "$";
				sRes += g_oCellAddressUtils.colnumToColstr(this.c1 + 1);
				if(r1Abs)
					sRes += "$";
				sRes += (this.r1 + 1);
				if(!this.isOneCell())
				{
					sRes += ":";
					if(c2Abs)
						sRes += "$";
					sRes += g_oCellAddressUtils.colnumToColstr(this.c2 + 1);
					if(r2Abs)
						sRes += "$";
					sRes += (this.r2 + 1);
				}
			}
			return sRes;
		};

		function MultiplyRange(ranges) {
			this.ranges = ranges;
		}
		MultiplyRange.prototype.clone = function() {
			return new MultiplyRange(this.ranges.slice());
		};
		MultiplyRange.prototype.union2 = function(multiplyRange) {
			this.ranges = this.ranges.concat(multiplyRange.ranges);
		};
		MultiplyRange.prototype.isIntersect = function(range) {
			for (var i = 0; i < this.ranges.length; ++i) {
				if (range.isIntersect(this.ranges[i])) {
					return true;
				}
			}
			return false;
		};
		MultiplyRange.prototype.contains = function(c, r) {
			for (var i = 0; i < this.ranges.length; ++i) {
				if (this.ranges[i].contains(c, r)) {
					return true;
				}
			}
			return false;
		};

		function VisibleRange(visibleRange, offsetX, offsetY) {
			this.visibleRange = visibleRange;
			this.offsetX = offsetX;
			this.offsetY = offsetY;
		}

		function RangeCache() {
			this.oCache = {};
		}

		RangeCache.prototype.getAscRange = function (sRange) {
			return this._getRange(sRange, 1);
		};
		RangeCache.prototype.getRange3D = function (sRange) {
			var res = AscCommon.parserHelp.parse3DRef(sRange);
			if (!res) {
				return null;
			}
			var range = this._getRange(res.range.toUpperCase(), 1);
			return range ? new Range3D(range, res.sheet, res.sheet2) : null;
		};
		RangeCache.prototype.getActiveRange = function (sRange) {
			return this._getRange(sRange, 2);
		};
		RangeCache.prototype.getActiveRangesFromSqRef = function (sqRef) {
			var res = [];
			var refs = sqRef.split(' ');
			for (var i = 0; i < refs.length; ++i) {
				var ref = AscCommonExcel.g_oRangeCache.getAscRange(refs[i]);
				if (ref) {
					res.push(ref.clone());
				}
			}
			return res;
		};
		RangeCache.prototype.getFormulaRange = function (sRange) {
			return this._getRange(sRange, 3);
		};
		RangeCache.prototype._getRange = function (sRange, type) {
			if (AscCommonExcel.g_R1C1Mode) {
				var o = {
					Formula: sRange, pCurrPos: 0
				};
				if (AscCommon.parserHelp.isArea.call(o, o.Formula, o.pCurrPos)) {
					sRange = o.real_str;
				} else if (AscCommon.parserHelp.isRef.call(o, o.Formula, o.pCurrPos)) {
					sRange = o.real_str;
				}
			}
			var oRes = null;
			var oCacheVal = this.oCache[sRange];
			if (null == oCacheVal) {
				var oFirstAddr, oLastAddr;
				var bIsSingle = true;
				var nIndex = sRange.indexOf(":");
				if (-1 != nIndex) {
					bIsSingle = false;
					oFirstAddr = g_oCellAddressUtils.getCellAddress(sRange.substring(0, nIndex));
					oLastAddr = g_oCellAddressUtils.getCellAddress(sRange.substring(nIndex + 1));
				} else {
					oFirstAddr = oLastAddr = g_oCellAddressUtils.getCellAddress(sRange);
				}
				oCacheVal = {first: null, last: null, ascRange: null, formulaRange: null, activeRange: null};
				//последнее условие, чтобы не распознавалось "A", "1"(должно быть "A:A", "1:1")
				if (oFirstAddr.isValid() && oLastAddr.isValid() &&
					(!bIsSingle || (!oFirstAddr.getIsRow() && !oFirstAddr.getIsCol()))) {
					oCacheVal.first = oFirstAddr;
					oCacheVal.last = oLastAddr;
				}
				this.oCache[sRange] = oCacheVal;
			}
			if (1 == type) {
				oRes = oCacheVal.ascRange;
			} else if (2 == type) {
				oRes = oCacheVal.activeRange;
			} else {
				oRes = oCacheVal.formulaRange;
			}
			if (null == oRes && null != oCacheVal.first && null != oCacheVal.last) {
				var r1 = oCacheVal.first.getRow0(), r2 = oCacheVal.last.getRow0(), c1 = oCacheVal.first.getCol0(), c2 = oCacheVal.last.getCol0();
				var r1Abs = oCacheVal.first.getRowAbs(), r2Abs = oCacheVal.last.getRowAbs(),
					c1Abs = oCacheVal.first.getColAbs(), c2Abs = oCacheVal.last.getColAbs();
				if (oCacheVal.first.getIsRow() && oCacheVal.last.getIsRow()) {
					c1 = 0;
					c2 = gc_nMaxCol0;
				}
				if (oCacheVal.first.getIsCol() && oCacheVal.last.getIsCol()) {
					r1 = 0;
					r2 = gc_nMaxRow0;
				}
				if (r1 > r2) {
					var temp = r1;
					r1 = r2;
					r2 = temp;
					temp = r1Abs;
					r1Abs = r2Abs;
					r2Abs = temp;
				}
				if (c1 > c2) {
					var temp = c1;
					c1 = c2;
					c2 = temp;
					temp = c1Abs;
					c1Abs = c2Abs;
					c2Abs = temp;
				}

				if (1 == type) {
					if (null == oCacheVal.ascRange) {
						var oAscRange = new Range(c1, r1, c2, r2);
						oAscRange.setAbs(r1Abs, c1Abs, r2Abs, c2Abs);

						oCacheVal.ascRange = oAscRange;
					}
					oRes = oCacheVal.ascRange;
				} else if (2 == type) {
					if (null == oCacheVal.activeRange) {
						var oActiveRange = new ActiveRange(c1, r1, c2, r2);
						oActiveRange.setAbs(r1Abs, c1Abs, r2Abs, c2Abs);
						oActiveRange.startCol = oActiveRange.c1;
						oActiveRange.startRow = oActiveRange.r1;
						oCacheVal.activeRange = oActiveRange;
					}
					oRes = oCacheVal.activeRange;
				} else {
					if (null == oCacheVal.formulaRange) {
						var oFormulaRange = new FormulaRange(c1, r1, c2, r2);
						oFormulaRange.setAbs(r1Abs, c1Abs, r2Abs, c2Abs);

						oCacheVal.formulaRange = oFormulaRange;
					}
					oRes = oCacheVal.formulaRange;
				}
			}
			return oRes;
		};

		var g_oRangeCache = new RangeCache();
		/**
		 * @constructor
		 * @memberOf Asc
		 */
		function HandlersList(handlers) {
			if ( !(this instanceof HandlersList) ) {return new HandlersList(handlers);}
			this.handlers = handlers || {};
			return this;
		}

		HandlersList.prototype = {

			constructor: HandlersList,

			trigger: function (eventName) {
				var h = this.handlers[eventName], t = typeOf(h), a = Array.prototype.slice.call(arguments, 1), i;
				if (t === kFunctionL) {
					return h.apply(this, a);
				}
				if (t === kArrayL) {
					for (i = 0; i < h.length; i += 1) {
						if (typeOf(h[i]) === kFunctionL) {h[i].apply(this, a);}
					}
					return true;
				}
				return false;
			},

			add: function (eventName, eventHandler, replaceOldHandler) {
				var th = this.handlers, h, old, t;
				if (replaceOldHandler || !th.hasOwnProperty(eventName)) {
					th[eventName] = eventHandler;
				} else {
					old = h = th[eventName];
					t = typeOf(old);
					if (t !== kArrayL) {
						h = th[eventName] = [];
						if (t === kFunctionL) {h.push(old);}
					}
					h.push(eventHandler);
				}
			},

			remove: function (eventName, eventHandler) {
				var th = this.handlers, h = th[eventName], i;
				if (th.hasOwnProperty(eventName)) {
					if (typeOf(h) !== kArrayL || typeOf(eventHandler) !== kFunctionL) {
						delete th[eventName];
						return true;
					}
					for (i = h.length - 1; i >= 0; i -= 1) {
						if (h[i] === eventHandler) {
							delete h[i];
							return true;
						}
					}
				}
				return false;
			}

		};


		function outputDebugStr(channel) {
			var c = window.console;
			if (Asc.g_debug_mode && c && c[channel] && c[channel].apply) {
				c[channel].apply(this, Array.prototype.slice.call(arguments, 1));
			}
		}
		
		function trim(val)
		{
			if(!String.prototype.trim)
				return val.trim();
			else
				return val.replace(/^\s+|\s+$/g,'');  
		}

		function isNumberInfinity(val) {
		    var valTrim = trim(val);
		    var valInt = valTrim - 0;
		    return valInt == valTrim && valTrim.length > 0 && MIN_EXCEL_INT < valInt && valInt < MAX_EXCEL_INT;//
		}

		function arrayToLowerCase(array) {
			var result = [];
			for (var i = 0, length = array.length; i < length; ++i)
				result.push(array[i].toLowerCase());
			return result;
		}

		function isFixedWidthCell(frag) {
			for (var i = 0; i < frag.length; ++i) {
				var f = frag[i].format;
				if (f && f.getRepeat()) {return true;}
			}
			return false;
		}

		function dropDecimalAutofit(f) {
			var s = getFragmentsText(f);
			// Проверка scientific format
			if (s.search(/E/i) >= 0) {
				return f;
			}
			// Поиск десятичной точки
			var pos = s.indexOf(AscCommon.g_oDefaultCultureInfo.NumberDecimalSeparator);
			if (-1 !== pos) {
				f = [f[0].clone()];
				f[0].text = s.slice(0, pos);
			}
			return f;
		}

		function getFragmentsText(f) {
			return f.reduce(function (pv, cv) {
				return pv + cv.text;
			}, "");
		}

		function executeInR1C1Mode(mode, runFunction) {
			var oldMode = AscCommonExcel.g_R1C1Mode;
			AscCommonExcel.g_R1C1Mode = mode;
			runFunction();
			AscCommonExcel.g_R1C1Mode = oldMode;
		}

		function getEndValueRange (dx, start, v1, v2) {
			var x1, x2;
			if (0 !== dx) {
				if (start === v1) {
					x1 = v1;
					x2 = v2;
				} else if (start === v2) {
					x1 = v2;
					x2 = v1;
				} else {
					if (0 > dx) {
						x1 = v2;
						x2 = v1;
					} else {
						x1 = v1;
						x2 = v2;
					}
				}
			} else {
				x1 = v1;
				x2 = v2;
			}
			return {x1: x1, x2: x2};
		}

		//-----------------------------------------------------------------
		// События движения мыши
		//-----------------------------------------------------------------
		/** @constructor */
		function asc_CMouseMoveData (obj) {
			if ( !(this instanceof asc_CMouseMoveData) ) {
				return new asc_CMouseMoveData(obj);
			}
			
			if (obj) {
				this.type = obj.type;
				this.x = obj.x;
				this.reverseX = obj.reverseX;	// Отображать комментарий слева от ячейки
				this.y = obj.y;
				this.hyperlink = obj.hyperlink;
				this.aCommentIndexes = obj.aCommentIndexes;
				this.userId = obj.userId;
				this.lockedObjectType = obj.lockedObjectType;

				// Для resize
				this.sizeCCOrPt = obj.sizeCCOrPt;
				this.sizePx = obj.sizePx;

				//Filter
				this.filter = obj.filter;
			}

			return this;
		}
		asc_CMouseMoveData.prototype = {
			constructor: asc_CMouseMoveData,
			asc_getType: function () { return this.type; },
			asc_getX: function () { return this.x; },
			asc_getReverseX: function () { return this.reverseX; },
			asc_getY: function () { return this.y; },
			asc_getHyperlink: function () { return this.hyperlink; },
			asc_getCommentIndexes: function () { return this.aCommentIndexes; },
			asc_getUserId: function () { return this.userId; },
			asc_getLockedObjectType: function () { return this.lockedObjectType; },
			asc_getSizeCCOrPt: function () { return this.sizeCCOrPt; },
			asc_getSizePx: function () { return this.sizePx; },
			asc_getFilter: function () { return this.filter; }
		};

		// Гиперссылка
		/** @constructor */
		function asc_CHyperlink (obj) {
			if (!(this instanceof asc_CHyperlink)) {
				return new asc_CHyperlink(obj);
			}

			// Класс Hyperlink из модели
			this.hyperlinkModel = null != obj ? obj : new AscCommonExcel.Hyperlink();
			// Используется только для выдачи наружу и выставлении обратно
			this.text = null;

			return this;
		}
		asc_CHyperlink.prototype = {
			constructor: asc_CHyperlink,
			asc_getType: function () { return this.hyperlinkModel.getHyperlinkType(); },
			asc_getHyperlinkUrl: function () { return this.hyperlinkModel.Hyperlink; },
			asc_getTooltip: function () { return this.hyperlinkModel.Tooltip; },
			asc_getLocation: function () { return this.hyperlinkModel.getLocation(); },
			asc_getSheet: function () { return this.hyperlinkModel.LocationSheet; },
			asc_getRange: function () {return this.hyperlinkModel.getLocationRange();},
			asc_getText: function () { return this.text; },

			asc_setType: function (val) {
				// В принципе эта функция избыточна
				switch (val) {
					case Asc.c_oAscHyperlinkType.WebLink:
						this.hyperlinkModel.setLocation(null);
						break;
					case Asc.c_oAscHyperlinkType.RangeLink:
						this.hyperlinkModel.Hyperlink = null;
						break;
				}
			},
			asc_setHyperlinkUrl: function (val) { this.hyperlinkModel.Hyperlink = val; },
			asc_setTooltip: function (val) { this.hyperlinkModel.Tooltip = val ? val.slice(0, Asc.c_oAscMaxTooltipLength) : val; },
			asc_setLocation: function (val) { this.hyperlinkModel.setLocation(val); },
			asc_setSheet: function (val) { this.hyperlinkModel.setLocationSheet(val); },
			asc_setRange: function (val) { this.hyperlinkModel.setLocationRange(val); },
			asc_setText: function (val) { this.text = val; }
		};

		function CPagePrint() {
			this.pageWidth = 0;
			this.pageHeight = 0;

			this.pageClipRectLeft = 0;
			this.pageClipRectTop = 0;
			this.pageClipRectWidth = 0;
			this.pageClipRectHeight = 0;

			this.pageRange = null;

			this.leftFieldInPx = 0;
			this.topFieldInPx = 0;

			this.pageGridLines = false;
			this.pageHeadings = false;

			this.indexWorksheet = -1;

			this.startOffset = 0;
			this.startOffsetPx = 0;

			return this;
		}
		function CPrintPagesData () {
			this.arrPages = [];
			this.currentIndex = 0;

			return this;
		}
		/** @constructor */
		function asc_CAdjustPrint () {
			// Вид печати
			this.printType = Asc.c_oAscPrintType.ActiveSheets;
			this.pageOptionsMap = null;

			// ToDo сюда же start и end page index

			return this;
		}
		asc_CAdjustPrint.prototype.asc_getPrintType = function () { return this.printType; };
		asc_CAdjustPrint.prototype.asc_setPrintType = function (val) { this.printType = val; };
		asc_CAdjustPrint.prototype.asc_getPageOptionsMap = function () { return this.pageOptionsMap; };
		asc_CAdjustPrint.prototype.asc_setPageOptionsMap = function (val) { this.pageOptionsMap = val; };

		/** @constructor */
		function asc_CLockInfo () {
			this["sheetId"] = null;
			this["type"] = null;
			this["subType"] = null;
			this["guid"] = null;
			this["rangeOrObjectId"] = null;
		}

		/** @constructor */
		function asc_CCollaborativeRange (c1, r1, c2, r2) {
			this["c1"] = c1;
			this["r1"] = r1;
			this["c2"] = c2;
			this["r2"] = r2;
		}

		/** @constructor */
		function asc_CSheetViewSettings () {
			// Показывать ли сетку
			this.showGridLines = null;
			// Показывать обозначения строк и столбцов
			this.showRowColHeaders = null;

			// Закрепление области
			this.pane = null;

			//current view zoom
			this.zoomScale = 100;

			return this;
		}

		asc_CSheetViewSettings.prototype = {
			constructor: asc_CSheetViewSettings,
			clone: function () {
				var result = new asc_CSheetViewSettings();
				result.showGridLines = this.showGridLines;
				result.showRowColHeaders = this.showRowColHeaders;
				result.zoom = this.zoom;
				if (this.pane)
					result.pane = this.pane.clone();
				return result;
			},
			isEqual: function (settings) {
				return this.asc_getShowGridLines() === settings.asc_getShowGridLines() &&
					this.asc_getShowRowColHeaders() === settings.asc_getShowRowColHeaders();
			},
			asc_getShowGridLines: function () { return false !== this.showGridLines; },
			asc_getShowRowColHeaders: function () { return false !== this.showRowColHeaders; },
			asc_getZoomScale: function () { return this.zoomScale; },
			asc_getIsFreezePane: function () { return null !== this.pane && this.pane.isInit(); },
			asc_setShowGridLines: function (val) { this.showGridLines = val; },
			asc_setShowRowColHeaders: function (val) { this.showRowColHeaders = val; },
			asc_setZoomScale: function (val) { this.zoomScale = val; }
		};

		/** @constructor */
		function asc_CPane () {
			this.state = null;
			this.topLeftCell = null;
			this.xSplit = 0;
			this.ySplit = 0;
			// CellAddress для удобства
			this.topLeftFrozenCell = null;

			return this;
		}
		asc_CPane.prototype.isInit = function () {
			return null !== this.topLeftFrozenCell;
		};
		asc_CPane.prototype.clone = function() {
			var res = new asc_CPane();
			res.state = this.state;
			res.topLeftCell = this.topLeftCell;
			res.xSplit = this.xSplit;
			res.ySplit = this.ySplit;
			res.topLeftFrozenCell = this.topLeftFrozenCell ?
				new AscCommon.CellAddress(this.topLeftFrozenCell.row, this.topLeftFrozenCell.col) : null;
			return res;
		};
		asc_CPane.prototype.init = function() {
			// ToDo Обрабатываем пока только frozen и frozenSplit
			if ((AscCommonExcel.c_oAscPaneState.Frozen === this.state || AscCommonExcel.c_oAscPaneState.FrozenSplit === this.state) &&
				(0 < this.xSplit || 0 < this.ySplit)) {
				this.topLeftFrozenCell = new AscCommon.CellAddress(this.ySplit, this.xSplit, 0);
				if (!this.topLeftFrozenCell.isValid())
					this.topLeftFrozenCell = null;
			}
		};

		function RedoObjectParam () {
			this.bIsOn = false;
			this.bIsReInit = false;
			this.oChangeWorksheetUpdate = {};
			this.bUpdateWorksheetByModel = false;
			this.bOnSheetsChanged = false;
			this.oOnUpdateTabColor = {};
			this.oOnUpdateSheetViewSettings = {};
			this.bAddRemoveRowCol = false;
			this.bChangeActive = false;
			this.activeSheet = null;
		}


		/** @constructor */
		function asc_CStylesPainter(width, height) {
			this.defaultStyles = null;
			this.docStyles = null;

			this.styleThumbnailWidth = width;
			this.styleThumbnailHeight = height;
			this.styleThumbnailWidthPt = this.styleThumbnailWidth * 72 / 96;
			this.styleThumbnailHeightPt = this.styleThumbnailHeight * 72 / 96;

			this.styleThumbnailWidthWithRetina = this.styleThumbnailWidth;
			this.styleThumbnailHeightWithRetina = this.styleThumbnailHeight;
			if (AscCommon.AscBrowser.isRetina) {
				this.styleThumbnailWidthWithRetina =
					AscCommon.AscBrowser.convertToRetinaValue(this.styleThumbnailWidthWithRetina, true);
				this.styleThumbnailHeightWithRetina =
					AscCommon.AscBrowser.convertToRetinaValue(this.styleThumbnailHeightWithRetina, true);
			}
		}

		asc_CStylesPainter.prototype.asc_checkStylesNames = function(cellStylesAll) {
			var oStyle, i;
			for (i = 0; i < cellStylesAll.DefaultStyles.length; ++i) {
				oStyle = cellStylesAll.DefaultStyles[i];
				AscFonts.FontPickerByCharacter.getFontsByString(oStyle.Name);
				AscFonts.FontPickerByCharacter.getFontsByString(AscCommon.translateManager.getValue(oStyle.Name));
			}
			for (i = 0; i < cellStylesAll.CustomStyles.length; ++i) {
				oStyle = cellStylesAll.CustomStyles[i];
				AscFonts.FontPickerByCharacter.getFontsByString(oStyle.Name);
			}
		};
		asc_CStylesPainter.prototype.asc_getStyleThumbnailWidth = function () {
			return this.styleThumbnailWidthWithRetina;
		};
		asc_CStylesPainter.prototype.asc_getStyleThumbnailHeight = function () {
			return this.styleThumbnailHeightWithRetina;
		};
		asc_CStylesPainter.prototype.asc_getDefaultStyles = function () {
			return this.defaultStyles;
		};
		asc_CStylesPainter.prototype.asc_getDocStyles = function () {
			return this.docStyles;
		};
		asc_CStylesPainter.prototype.generateStylesAll = function (cellStylesAll, fmgrGraphics, oFont, sr) {
			this.generateDefaultStyles(cellStylesAll, fmgrGraphics, oFont, sr);
			this.generateDocumentStyles(cellStylesAll, fmgrGraphics, oFont, sr);
		};
		asc_CStylesPainter.prototype.generateDefaultStyles = function (cellStylesAll, fmgrGraphics, oFont, sr) {
			var cellStyles = cellStylesAll.DefaultStyles;

			var oCanvas = document.createElement('canvas');
			oCanvas.width = this.styleThumbnailWidthWithRetina;
			oCanvas.height = this.styleThumbnailHeightWithRetina;
			var oGraphics = new Asc.DrawingContext(
				{canvas: oCanvas, units: 1/*pt*/, fmgrGraphics: fmgrGraphics, font: oFont});

			var oStyle, oCustomStyle;
			this.defaultStyles = [];
			for (var i = 0; i < cellStyles.length; ++i) {
				oStyle = cellStyles[i];
				if (oStyle.Hidden) {
					continue;
				}
				// ToDo Возможно стоит переписать немного, чтобы не пробегать каждый раз по массиву custom-стилей (нужно генерировать AllStyles)
				oCustomStyle = cellStylesAll.getCustomStyleByBuiltinId(oStyle.BuiltinId);

				this.drawStyle(oGraphics, sr, oCustomStyle || oStyle, AscCommon.translateManager.getValue(oStyle.Name));
				this.defaultStyles.push(new AscCommon.CStyleImage(oStyle.Name, AscCommon.c_oAscStyleImage.Default,
					oCanvas.toDataURL("image/png")));
			}
		};
		asc_CStylesPainter.prototype.generateDocumentStyles = function (cellStylesAll, fmgrGraphics, oFont, sr) {
			var cellStyles = cellStylesAll.CustomStyles;

			var oCanvas = document.createElement('canvas');
			oCanvas.width = this.styleThumbnailWidthWithRetina;
			oCanvas.height = this.styleThumbnailHeightWithRetina;
			var oGraphics = new Asc.DrawingContext(
				{canvas: oCanvas, units: 1/*pt*/, fmgrGraphics: fmgrGraphics, font: oFont});

			var oStyle;
			this.docStyles = [];
			for (var i = 0; i < cellStyles.length && i < 1000; ++i) {
				oStyle = cellStyles[i];
				if (oStyle.Hidden || null != oStyle.BuiltinId) {
					continue;
				}

				this.drawStyle(oGraphics, sr, oStyle, oStyle.Name);
				this.docStyles.push(new AscCommon.CStyleImage(oStyle.Name, AscCommon.c_oAscStyleImage.Document,
					oCanvas.toDataURL("image/png")));
			}
		};
		asc_CStylesPainter.prototype.drawStyle = function (oGraphics, sr, oStyle, sStyleName) {
			oGraphics.clear();
			// Fill cell
			var oColor = oStyle.getFill();
			if (null !== oColor) {
				oGraphics.setFillStyle(oColor);
				oGraphics.fillRect(0, 0, this.styleThumbnailWidthPt, this.styleThumbnailHeightPt);
			}

			var drawBorder = function (b, x1, y1, x2, y2) {
				if (b && AscCommon.c_oAscBorderStyles.None !== b.s) {
					oGraphics.setStrokeStyle(b.c);

					// ToDo поправить
					oGraphics.setLineWidth(b.w).beginPath().moveTo(x1, y1).lineTo(x2, y2).stroke();
				}
			};

			// borders
			var oBorders = oStyle.getBorder();
			drawBorder(oBorders.l, 0, 0, 0, this.styleThumbnailHeightPt);
			drawBorder(oBorders.r, this.styleThumbnailWidthPt, 0, this.styleThumbnailWidthPt,
				this.styleThumbnailHeightPt);
			drawBorder(oBorders.t, 0, 0, this.styleThumbnailWidthPt, 0);
			drawBorder(oBorders.b, 0, this.styleThumbnailHeightPt, this.styleThumbnailWidthPt,
				this.styleThumbnailHeightPt);

			// Draw text
			var fc = oStyle.getFontColor();
			var oFontColor = fc !== null ? fc : new AscCommon.CColor(0, 0, 0);
			var format = oStyle.getFont();
			var fs = format.getSize();
			// Для размера шрифта делаем ограничение для превью в 16pt (у Excel 18pt, но и высота превью больше 22px)
			var oFont = new Asc.FontProperties(format.getName(), (16 < fs) ? 16 : fs, format.getBold(),
				format.getItalic(), format.getUnderline(), format.getStrikeout());

			var width_padding = 3; // 4 * 72 / 96

			var tm = sr.measureString(sStyleName);
			// Текст будем рисовать по центру (в Excel чуть по другому реализовано, у них постоянный отступ снизу)
			var textY = 0.5 * (this.styleThumbnailHeightPt - tm.height);
			oGraphics.setFont(oFont);
			oGraphics.setFillStyle(oFontColor);
			oGraphics.fillText(sStyleName, width_padding, textY + tm.baseline);
		};

		/** @constructor */
		function asc_CSheetPr() {
			if (!(this instanceof asc_CSheetPr)) {
				return new asc_CSheetPr();
			}

			this.CodeName = null;
			this.EnableFormatConditionsCalculation = null;
			this.FilterMode = null;
			this.Published = null;
			this.SyncHorizontal = null;
			this.SyncRef = null;
			this.SyncVertical = null;
			this.TransitionEntry = null;
			this.TransitionEvaluation = null;

			this.TabColor = null;

			return this;
		}
		asc_CSheetPr.prototype.clone = function()  {
			var res = new asc_CSheetPr();

			res.CodeName = this.CodeName;
			res.EnableFormatConditionsCalculation = this.EnableFormatConditionsCalculation;
			res.FilterMode = this.FilterMode;
			res.Published = this.Published;
			res.SyncHorizontal = this.SyncHorizontal;
			res.SyncRef = this.SyncRef;
			res.SyncVertical = this.SyncVertical;
			res.TransitionEntry = this.TransitionEntry;
			res.TransitionEvaluation = this.TransitionEvaluation;
			if (this.TabColor)
				res.TabColor = this.TabColor.clone();

			return res;
		};

		// Математическая информация о выделении
		/** @constructor */
		function asc_CSelectionMathInfo() {
			this.count = 0;
			this.countNumbers = 0;
			this.sum = null;
			this.average = null;
			this.min = null;
			this.max = null;
		}

		asc_CSelectionMathInfo.prototype = {
			constructor: asc_CSelectionMathInfo,
			asc_getCount: function () { return this.count; },
			asc_getCountNumbers: function () { return this.countNumbers; },
			asc_getSum: function () { return this.sum; },
			asc_getAverage: function () { return this.average; },
			asc_getMin: function () { return this.min; },
			asc_getMax: function () { return this.max; }
		};

		/** @constructor */
		function asc_CFindOptions() {
			this.findWhat = "";							// текст, который ищем
			this.scanByRows = true;						// просмотр по строкам/столбцам
			this.scanForward = true;					// поиск вперед/назад
			this.isMatchCase = false;					// учитывать регистр
			this.isWholeCell = false;					// ячейка целиком
			this.scanOnOnlySheet = true;				// искать только на листе/в книге
			this.lookIn = Asc.c_oAscFindLookIn.Formulas;	// искать в формулах/значениях/примечаниях

			this.replaceWith = "";						// текст, на который заменяем (если у нас замена)
			this.isReplaceAll = false;					// заменить все (если у нас замена)

			// внутренние переменные
			this.findInSelection = false;
			this.selectionRange = null;
			this.findRange = null;
			this.findResults = null;
			this.indexInArray = 0;
			this.countFind = 0;
			this.countReplace = 0;
			this.countFindAll = 0;
			this.countReplaceAll = 0;
			this.sheetIndex = -1;
			this.error = false;
		}
		asc_CFindOptions.prototype.clone = function () {
			var result = new asc_CFindOptions();
			result.findWhat = this.findWhat;
			result.scanByRows = this.scanByRows;
			result.scanForward = this.scanForward;
			result.isMatchCase = this.isMatchCase;
			result.isWholeCell = this.isWholeCell;
			result.scanOnOnlySheet = this.scanOnOnlySheet;
			result.lookIn = this.lookIn;

			result.replaceWith = this.replaceWith;
			result.isReplaceAll = this.isReplaceAll;

			result.findInSelection = this.findInSelection;
			result.selectionRange = this.selectionRange ? this.selectionRange.clone() : null;
			result.findRange = this.findRange ? this.findRange.clone() : null;
			result.indexInArray = this.indexInArray;
			result.countFind = this.countFind;
			result.countReplace = this.countReplace;
			result.countFindAll = this.countFindAll;
			result.countReplaceAll = this.countReplaceAll;
			result.sheetIndex = this.sheetIndex;
			result.error = this.error;
			return result;
		};
		asc_CFindOptions.prototype.isEqual = function (obj) {
			return obj && this.isEqual2(obj) && this.scanForward === obj.scanForward &&
				this.scanOnOnlySheet === obj.scanOnOnlySheet;
		};
		asc_CFindOptions.prototype.isEqual2 = function (obj) {
			return obj && this.findWhat === obj.findWhat && this.scanByRows === obj.scanByRows &&
				this.isMatchCase === obj.isMatchCase && this.isWholeCell === obj.isWholeCell &&
				this.lookIn === obj.lookIn;
		};
		asc_CFindOptions.prototype.clearFindAll = function () {
			this.countFindAll = 0;
			this.countReplaceAll = 0;
			this.error = false;
		};
		asc_CFindOptions.prototype.updateFindAll = function () {
			this.countFindAll += this.countFind;
			this.countReplaceAll += this.countReplace;
		};

		asc_CFindOptions.prototype.asc_setFindWhat = function (val) {this.findWhat = val;};
		asc_CFindOptions.prototype.asc_setScanByRows = function (val) {this.scanByRows = val;};
		asc_CFindOptions.prototype.asc_setScanForward = function (val) {this.scanForward = val;};
		asc_CFindOptions.prototype.asc_setIsMatchCase = function (val) {this.isMatchCase = val;};
		asc_CFindOptions.prototype.asc_setIsWholeCell = function (val) {this.isWholeCell = val;};
		asc_CFindOptions.prototype.asc_setScanOnOnlySheet = function (val) {this.scanOnOnlySheet = val;};
		asc_CFindOptions.prototype.asc_setLookIn = function (val) {this.lookIn = val;};
		asc_CFindOptions.prototype.asc_setReplaceWith = function (val) {this.replaceWith = val;};
		asc_CFindOptions.prototype.asc_setIsReplaceAll = function (val) {this.isReplaceAll = val;};

		/** @constructor */
		function findResults() {
			this.values = {};

			this.currentKey1 = -1;
			this.currentKey2 = -1;
			this.currentKeys1 = null;
			this.currentKeys2 = null;
		}

		findResults.prototype.isNotEmpty = function () {
			return 0 !== Object.keys(this.values).length;
		};
		findResults.prototype.contains = function (key1, key2) {
			return this.values[key1] && this.values[key1][key2];
		};
		findResults.prototype.add = function (key1, key2, cell) {
			if (!this.values[key1]) {
				this.values[key1] = {};
			}
			this.values[key1][key2] = cell;
		};
		findResults.prototype._init = function (key1, key2) {
			this.currentKey1 = key1;
			this.currentKey2 = key2;
			this.currentKeyIndex1 = -1;
			this.currentKeyIndex2 = -1;

			this.currentKeys2 = null;
			this.currentKeys1 = Object.keys(this.values).sort(AscCommon.fSortAscending);
			this.currentKeyIndex1 = this._findKey(this.currentKey1, this.currentKeys1);
			if (0 === this.currentKeys1[this.currentKeyIndex1] - this.currentKey1) {
				this.currentKeys2 = Object.keys(this.values[this.currentKey1]).sort(AscCommon.fSortAscending);
				this.currentKeyIndex2 = this._findKey(this.currentKey2, this.currentKeys2);
			}
		};
		findResults.prototype.find = function (key1, key2, forward) {
			this.forward = forward;

			if (this.currentKey1 !== key1 || this.currentKey2 !== key2) {
				this._init(key1, key2);
			}

			if (0 === this.currentKeys1.length) {
				return false;
			}

			var step = this.forward ? +1 : -1;
			this.currentKeyIndex2 += step;
			if (!this.currentKeys2 || !this.currentKeys2[this.currentKeyIndex2]) {
				this.currentKeyIndex1 += step;
				if (!this.currentKeys1[this.currentKeyIndex1]) {
					this.currentKeyIndex1 = this.forward ? 0 : this.currentKeys1.length - 1;
				}
				this.currentKey1 = this.currentKeys1[this.currentKeyIndex1] >> 0;
				this.currentKeys2 = Object.keys(this.values[this.currentKey1]).sort(AscCommon.fSortAscending);
				this.currentKeyIndex2 = this.forward ? 0 : this.currentKeys2.length - 1;
			}
			this.currentKey2 = this.currentKeys2[this.currentKeyIndex2] >> 0;
			return true;
		};
		findResults.prototype._findKey = function (key, arrayKeys) {
			var i = this.forward ? 0 : arrayKeys.length - 1;
			var step = this.forward ? +1 : -1;
			var _key;
			while (_key = arrayKeys[i]) {
				_key = step * ((_key >> 0) - key);
				if (_key >= 0) {
					return 0 === _key ? i : (i - step);
				}
				i += step;
			}
			return -2;
		};

		/** @constructor */
		function asc_CCompleteMenu(name, type) {
			this.name = name;
			this.type = type;
		}
		asc_CCompleteMenu.prototype.asc_getName = function () {return this.name;};
		asc_CCompleteMenu.prototype.asc_getType = function () {return this.type;};

		function CCacheMeasureEmpty() {
			this.cache = {};
		}
		CCacheMeasureEmpty.prototype.add = function (elem, val) {
			var fn = elem.getName();
			var font = (this.cache[fn] || (this.cache[fn] = {}));
			font[elem.getSize()] = val;
		};
		CCacheMeasureEmpty.prototype.get = function (elem) {
			var font = this.cache[elem.getName()];
			return font ? font[elem.getSize()] : null;
		};
		var g_oCacheMeasureEmpty = new CCacheMeasureEmpty();

		/** @constructor */
		function asc_CFormatCellsInfo() {
			this.type = Asc.c_oAscNumFormatType.General;
			this.decimalPlaces = 2;
			this.separator = false;
			this.symbol = null;
		}
		asc_CFormatCellsInfo.prototype.asc_setType = function (val) {this.type = val;};
		asc_CFormatCellsInfo.prototype.asc_setDecimalPlaces = function (val) {this.decimalPlaces = val;};
		asc_CFormatCellsInfo.prototype.asc_setSeparator = function (val) {this.separator = val;};
		asc_CFormatCellsInfo.prototype.asc_setSymbol = function (val) {this.symbol = val;};
		asc_CFormatCellsInfo.prototype.asc_getType = function () {return this.type;};
		asc_CFormatCellsInfo.prototype.asc_getDecimalPlaces = function () {return this.decimalPlaces;};
		asc_CFormatCellsInfo.prototype.asc_getSeparator = function () {return this.separator;};
		asc_CFormatCellsInfo.prototype.asc_getSymbol = function () {return this.symbol;};

		function asc_CSelectionRangeValue(){
			this.name =  null;
			this.type = null;
		}
		asc_CSelectionRangeValue.prototype.asc_setType = function (val) {this.type = val;};
		asc_CSelectionRangeValue.prototype.asc_setName = function (val) {this.name = val;};
		asc_CSelectionRangeValue.prototype.asc_getType = function () {return this.type;};
		asc_CSelectionRangeValue.prototype.asc_getName = function () {return this.name;};

		//передаём в меню для того, чтобы показать иконку опций авторавертывания таблиц
		function asc_CAutoCorrectOptions(){
			this.type = null;
			this.options = [];
			this.cellCoord = null;
		}
		asc_CAutoCorrectOptions.prototype.asc_setType = function (val) {this.type = val;};
		asc_CAutoCorrectOptions.prototype.asc_setOptions = function (val) {this.options = val;};
		asc_CAutoCorrectOptions.prototype.asc_setCellCoord = function(val) { this.cellCoord = val; };
		asc_CAutoCorrectOptions.prototype.asc_getType = function () {return this.type;};
		asc_CAutoCorrectOptions.prototype.asc_getOptions = function () {return this.options;};
		asc_CAutoCorrectOptions.prototype.asc_getCellCoord = function () {return this.cellCoord;};

		/*
		 * Export
		 * -----------------------------------------------------------------------------
		 */
		var prot;
		window['Asc'] = window['Asc'] || {};
		window['AscCommonExcel'] = window['AscCommonExcel'] || {};
		window['AscCommonExcel'].g_ActiveCell = null; // Active Cell for calculate (in R1C1 mode for relative cell)
		window['AscCommonExcel'].g_R1C1Mode = false; // No calculate in R1C1 mode
		window["AscCommonExcel"].c_oAscShiftType = c_oAscShiftType;
		window["AscCommonExcel"].recalcType = recalcType;
		window["AscCommonExcel"].sizePxinPt = sizePxinPt;
		window["AscCommonExcel"].applyFunction = applyFunction;
		window["Asc"].typeOf = typeOf;
		window["Asc"].lastIndexOf = lastIndexOf;
		window["Asc"].search = search;
		window["Asc"].getUniqueRangeColor = getUniqueRangeColor;
		window["Asc"].getMinValueOrNull = getMinValueOrNull;
		window["Asc"].round = round;
		window["Asc"].floor = floor;
		window["Asc"].ceil = ceil;
		window["Asc"].incDecFonSize = incDecFonSize;
		window["AscCommonExcel"].calcDecades = calcDecades;
		window["AscCommonExcel"].convertPtToPx = convertPtToPx;
		window["AscCommonExcel"].convertPxToPt = convertPxToPt;
		window["Asc"].outputDebugStr = outputDebugStr;
		window["Asc"].profileTime = profileTime;
		window["AscCommonExcel"].getMatchingBorder = getMatchingBorder;
		window["Asc"].isNumberInfinity = isNumberInfinity;
		window["Asc"].trim = trim;
		window["Asc"].arrayToLowerCase = arrayToLowerCase;
		window["Asc"].isFixedWidthCell = isFixedWidthCell;
		window["AscCommonExcel"].dropDecimalAutofit = dropDecimalAutofit;
		window["AscCommonExcel"].getFragmentsText = getFragmentsText;
		window['AscCommonExcel'].executeInR1C1Mode = executeInR1C1Mode;
		window["Asc"].getEndValueRange = getEndValueRange;

		window["AscCommonExcel"].referenceType = referenceType;
		window["Asc"].Range = Range;
		window["AscCommonExcel"].Range3D = Range3D;
		window["AscCommonExcel"].SelectionRange = SelectionRange;
		window["AscCommonExcel"].ActiveRange = ActiveRange;
		window["AscCommonExcel"].FormulaRange = FormulaRange;
		window["AscCommonExcel"].MultiplyRange = MultiplyRange;
		window["AscCommonExcel"].VisibleRange = VisibleRange;
		window["AscCommonExcel"].g_oRangeCache = g_oRangeCache;

		window["AscCommonExcel"].HandlersList = HandlersList;

		window["AscCommonExcel"].RedoObjectParam = RedoObjectParam;

		window["AscCommonExcel"].asc_CMouseMoveData = asc_CMouseMoveData;
		prot = asc_CMouseMoveData.prototype;
		prot["asc_getType"] = prot.asc_getType;
		prot["asc_getX"] = prot.asc_getX;
		prot["asc_getReverseX"] = prot.asc_getReverseX;
		prot["asc_getY"] = prot.asc_getY;
		prot["asc_getHyperlink"] = prot.asc_getHyperlink;		
		prot["asc_getCommentIndexes"] = prot.asc_getCommentIndexes;
		prot["asc_getUserId"] = prot.asc_getUserId;
		prot["asc_getLockedObjectType"] = prot.asc_getLockedObjectType;
		prot["asc_getSizeCCOrPt"] = prot.asc_getSizeCCOrPt;
		prot["asc_getSizePx"] = prot.asc_getSizePx;
		prot["asc_getFilter"] = prot.asc_getFilter;

		window["Asc"]["asc_CHyperlink"] = window["Asc"].asc_CHyperlink = asc_CHyperlink;
		prot = asc_CHyperlink.prototype;
		prot["asc_getType"] = prot.asc_getType;
		prot["asc_getHyperlinkUrl"] = prot.asc_getHyperlinkUrl;
		prot["asc_getTooltip"] = prot.asc_getTooltip;
		prot["asc_getLocation"] = prot.asc_getLocation;
		prot["asc_getSheet"] = prot.asc_getSheet;
		prot["asc_getRange"] = prot.asc_getRange;
		prot["asc_getText"] = prot.asc_getText;
		prot["asc_setType"] = prot.asc_setType;
		prot["asc_setHyperlinkUrl"] = prot.asc_setHyperlinkUrl;
		prot["asc_setTooltip"] = prot.asc_setTooltip;
		prot["asc_setLocation"] = prot.asc_setLocation;
		prot["asc_setSheet"] = prot.asc_setSheet;
		prot["asc_setRange"] = prot.asc_setRange;
		prot["asc_setText"] = prot.asc_setText;

		window["AscCommonExcel"].CPagePrint = CPagePrint;
		window["AscCommonExcel"].CPrintPagesData = CPrintPagesData;

		window["Asc"]["asc_CAdjustPrint"] = window["Asc"].asc_CAdjustPrint = asc_CAdjustPrint;
		prot = asc_CAdjustPrint.prototype;
		prot["asc_getPrintType"] = prot.asc_getPrintType;
		prot["asc_setPrintType"] = prot.asc_setPrintType;
		prot["asc_getPageOptionsMap"] = prot.asc_getPageOptionsMap;
		prot["asc_setPageOptionsMap"] = prot.asc_setPageOptionsMap;

		window["AscCommonExcel"].asc_CLockInfo = asc_CLockInfo;

		window["AscCommonExcel"].asc_CCollaborativeRange = asc_CCollaborativeRange;

		window["AscCommonExcel"].asc_CSheetViewSettings = asc_CSheetViewSettings;
		prot = asc_CSheetViewSettings.prototype;
		prot["asc_getShowGridLines"] = prot.asc_getShowGridLines;
		prot["asc_getShowRowColHeaders"] = prot.asc_getShowRowColHeaders;
		prot["asc_getIsFreezePane"] = prot.asc_getIsFreezePane;
		prot["asc_setShowGridLines"] = prot.asc_setShowGridLines;
		prot["asc_setShowRowColHeaders"] = prot.asc_setShowRowColHeaders;

		window["AscCommonExcel"].asc_CPane = asc_CPane;

		window["AscCommonExcel"].asc_CStylesPainter = asc_CStylesPainter;
		prot = asc_CStylesPainter.prototype;
		prot["asc_getStyleThumbnailWidth"] = prot.asc_getStyleThumbnailWidth;
		prot["asc_getStyleThumbnailHeight"] = prot.asc_getStyleThumbnailHeight;
		prot["asc_getDefaultStyles"] = prot.asc_getDefaultStyles;
		prot["asc_getDocStyles"] = prot.asc_getDocStyles;

		window["AscCommonExcel"].asc_CSheetPr = asc_CSheetPr;

		window["AscCommonExcel"].asc_CSelectionMathInfo = asc_CSelectionMathInfo;
		prot = asc_CSelectionMathInfo.prototype;
		prot["asc_getCount"] = prot.asc_getCount;
		prot["asc_getCountNumbers"] = prot.asc_getCountNumbers;
		prot["asc_getSum"] = prot.asc_getSum;
		prot["asc_getAverage"] = prot.asc_getAverage;
		prot["asc_getMin"] = prot.asc_getMin;
		prot["asc_getMax"] = prot.asc_getMax;

		window["Asc"]["asc_CFindOptions"] = window["Asc"].asc_CFindOptions = asc_CFindOptions;
		prot = asc_CFindOptions.prototype;
		prot["asc_setFindWhat"] = prot.asc_setFindWhat;
		prot["asc_setScanByRows"] = prot.asc_setScanByRows;
		prot["asc_setScanForward"] = prot.asc_setScanForward;
		prot["asc_setIsMatchCase"] = prot.asc_setIsMatchCase;
		prot["asc_setIsWholeCell"] = prot.asc_setIsWholeCell;
		prot["asc_setScanOnOnlySheet"] = prot.asc_setScanOnOnlySheet;
		prot["asc_setLookIn"] = prot.asc_setLookIn;
		prot["asc_setReplaceWith"] = prot.asc_setReplaceWith;
		prot["asc_setIsReplaceAll"] = prot.asc_setIsReplaceAll;

		window["AscCommonExcel"].findResults = findResults;

		window["AscCommonExcel"].asc_CCompleteMenu = asc_CCompleteMenu;
		prot = asc_CCompleteMenu.prototype;
		prot["asc_getName"] = prot.asc_getName;
		prot["asc_getType"] = prot.asc_getType;

		window["AscCommonExcel"].g_oCacheMeasureEmpty = g_oCacheMeasureEmpty;

		window["Asc"]["asc_CFormatCellsInfo"] = window["Asc"].asc_CFormatCellsInfo = asc_CFormatCellsInfo;
		prot = asc_CFormatCellsInfo.prototype;
		prot["asc_setType"] = prot.asc_setType;
		prot["asc_setDecimalPlaces"] = prot.asc_setDecimalPlaces;
		prot["asc_setSeparator"] = prot.asc_setSeparator;
		prot["asc_setSymbol"] = prot.asc_setSymbol;
		prot["asc_getType"] = prot.asc_getType;
		prot["asc_getDecimalPlaces"] = prot.asc_getDecimalPlaces;
		prot["asc_getSeparator"] = prot.asc_getSeparator;
		prot["asc_getSymbol"] = prot.asc_getSymbol;

		window["AscCommonExcel"]["asc_CSelectionRangeValue"] = window["AscCommonExcel"].asc_CSelectionRangeValue = asc_CSelectionRangeValue;
		prot = asc_CSelectionRangeValue.prototype;
		prot["asc_getType"] = prot.asc_getType;
		prot["asc_getName"] = prot.asc_getName;

		window["Asc"]["asc_CAutoCorrectOptions"] = window["Asc"].asc_CAutoCorrectOptions = asc_CAutoCorrectOptions;
		prot = asc_CAutoCorrectOptions.prototype;
		prot["asc_getType"] = prot.asc_getType;
		prot["asc_getOptions"] = prot.asc_getOptions;
		prot["asc_getCellCoord"] = prot.asc_getCellCoord;

})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

// Import
var CellValueType = AscCommon.CellValueType;
var c_oAscBorderWidth = AscCommon.c_oAscBorderWidth;
var c_oAscBorderStyles = AscCommon.c_oAscBorderStyles;
var FormulaTablePartInfo = AscCommon.FormulaTablePartInfo;
var parserHelp = AscCommon.parserHelp;
var gc_nMaxRow0 = AscCommon.gc_nMaxRow0;
var gc_nMaxCol0 = AscCommon.gc_nMaxCol0;
	var History = AscCommon.History;
	var c_oAscPrintDefaultSettings = AscCommon.c_oAscPrintDefaultSettings;

var UndoRedoDataTypes = AscCommonExcel.UndoRedoDataTypes;
var UndoRedoData_IndexSimpleProp = AscCommonExcel.UndoRedoData_IndexSimpleProp;

var UndoRedoData_Layout = AscCommonExcel.UndoRedoData_Layout;


var c_oAscCustomAutoFilter = Asc.c_oAscCustomAutoFilter;
var c_oAscAutoFilterTypes = Asc.c_oAscAutoFilterTypes;

var g_oColorManager = null;
	
var g_nHSLMaxValue = 255;
var g_nColorTextDefault = 1;
var g_nColorHyperlink = 10;
var g_nColorHyperlinkVisited = 11;

var g_oThemeColorsDefaultModsSpreadsheet = [
    [0, -4.9989318521683403E-2, -0.14999847407452621, -0.249977111117893, -0.34998626667073579, -0.499984740745262],
    [0, -9.9978637043366805E-2, -0.249977111117893, -0.499984740745262, -0.749992370372631, -0.89999084444715716],
    [0, 0.79998168889431442, 0.59999389629810485, 0.39997558519241921, -0.249977111117893, -0.499984740745262],
    [0, 0.89999084444715716, 0.749992370372631, 0.499984740745262, 0.249977111117893, 9.9978637043366805E-2],
    [0, 0.499984740745262, 0.34998626667073579, 0.249977111117893, 0.14999847407452621, 4.9989318521683403E-2]];

var map_themeExcel_to_themePresentation = {
	0: 12,
	1: 8,
	2: 13,
	3: 9,
	4: 0,
	5: 1,
	6: 2,
	7: 3,
	8: 4,
	9: 5,
	10: 11,
	11: 10
};
function shiftGetBBox(bbox, bHor)
{
	var bboxGet = null;
	if(bHor)
		bboxGet = Asc.Range(bbox.c1, bbox.r1, gc_nMaxCol0, bbox.r2);
	else
		bboxGet = Asc.Range(bbox.c1, bbox.r1, bbox.c2, gc_nMaxRow0);
	return bboxGet;
}
function shiftSort(a, b, offset)
{
	var nRes = 0;
	if(null == a.to || null == b.to)
	{
		if(null == a.to && null == b.to)
			nRes = 0;
		else if(null == a.to)
			nRes = -1;
		else if(null == b.to)
			nRes = 1;
	}
	else
	{
	    if (0 != offset.row) {
	        if (offset.row > 0)
	            nRes = b.to.r1 - a.to.r1;
	        else
	            nRes = a.to.r1 - b.to.r1;
	    }
	    if (0 == nRes && 0 != offset.col) {
	        if (offset.col > 0)
	            nRes = b.to.c1 - a.to.c1;
	        else
	            nRes = a.to.c1 - b.to.c1;
	    }
	}
	return nRes;
}
function createRgbColor(r, g, b) {
	return new RgbColor((r << 16) + (g << 8) + b);
}
var g_oRgbColorProperties = {
		rgb : 0
	};
function RgbColor(rgb)
{
	this.rgb = rgb;

	this._hash;
}
RgbColor.prototype =
{
	Properties: g_oRgbColorProperties,
	getHash: function() {
		if (!this._hash) {
			this._hash = this.rgb;
		}
		return this._hash;
	},
	clone : function()
	{
		return new RgbColor(this.rgb);
	},
	getType : function()
	{
		return UndoRedoDataTypes.RgbColor;
	},
	getProperties : function()
	{
		return this.Properties;
	},

    isEqual: function(oColor)
    {
        if(!oColor || !(oColor instanceof RgbColor)){
            return false;
        }
        if(this.rgb !== oColor.rgb){
            return false;
        }
        return true;
    },

	getProperty : function(nType)
	{
		switch(nType)
		{
		case this.Properties.rgb:return this.rgb;break;
		}
	},
	setProperty : function(nType, value)
	{
		switch(nType)
		{
		case this.Properties.rgb: this.rgb = value;break;
		}
	},
	Write_ToBinary2 : function(oBinaryWriter)
	{
		oBinaryWriter.WriteLong(this.rgb);
	},
	Read_FromBinary2 : function(oBinaryReader)
	{
		this.rgb = oBinaryReader.GetULongLE();
	},
	getRgb : function()
	{
		return this.rgb;
	},
	getR : function()
	{
		return (this.rgb >> 16) & 0xff;
	},
	getG : function()
	{
		return (this.rgb >> 8) & 0xff;
	},
	getB : function()
	{
		return this.rgb & 0xff;
	},
	getA : function () {
		return 1;
	}
};
var g_oThemeColorProperties = {
		rgb: 0,
		theme: 1,
		tint: 2
	};
function ThemeColor()
{
	this.rgb = null;
	this.theme = null;
	this.tint = null;

	this._hash;
}
ThemeColor.prototype =
{
	Properties: g_oThemeColorProperties,
	getHash: function() {
		if (!this._hash) {
			this._hash = this.theme + ';' + this.tint;
		}
		return this._hash;
	},
	clone : function()
	{
		//ThemeColor must be created by g_oColorManager for correct rebuild
		//no need getThemeColor because it return same object
		return this;
	},
	getType : function()
	{
		return UndoRedoDataTypes.ThemeColor;
	},
	getProperties : function()
	{
		return this.Properties;
	},
	getProperty : function(nType)
	{
		switch(nType)
		{
		case this.Properties.rgb:return this.rgb;break;
		case this.Properties.theme:return this.theme;break;
		case this.Properties.tint:return this.tint;break;
		}
	},
	setProperty : function(nType, value)
	{
		switch(nType)
		{
		case this.Properties.rgb: this.rgb = value;break;
		case this.Properties.theme: this.theme= value;break;
		case this.Properties.tint: this.tint = value;break;
		}
	},
    isEqual: function(oColor)
    {
        if(!oColor){
            return false;
        }
        if(this.theme !== oColor.theme){
            return false;
        }
        if(!AscFormat.fApproxEqual(this.tint, oColor.tint)){
            return false;
        }
        return true;
    },
	Write_ToBinary2 : function(oBinaryWriter)
	{
		oBinaryWriter.WriteByte(this.theme);
		if(null != this.tint)
		{
			oBinaryWriter.WriteByte(true);
			oBinaryWriter.WriteDouble2(this.tint);
		}
		else
		{
			oBinaryWriter.WriteBool(false);
		}
	},
	Read_FromBinary2AndReplace : function(oBinaryReader)
	{
		this.theme = oBinaryReader.GetUChar();
		var bTint = oBinaryReader.GetBool();
		if(bTint)
			this.tint = oBinaryReader.GetDoubleLE();
		return g_oColorManager.getThemeColor(this.theme, this.tint);
	},
	getRgb : function()
	{
		return this.rgb;
	},
	getR : function()
	{
		return (this.rgb >> 16) & 0xff;
	},
	getG : function()
	{
		return (this.rgb >> 8) & 0xff;

	},
	getB : function()
	{
		return this.rgb & 0xff;
	},
	getA : function () {
		return 1;
	},
	rebuild : function(theme)
	{
		var nRes = 0;
		var r = 0;
		var g = 0;
		var b = 0;
		if(null != this.theme && null != theme)
		{
			var oUniColor = theme.themeElements.clrScheme.colors[map_themeExcel_to_themePresentation[this.theme]];
			if(null != oUniColor)
			{
				var rgba = oUniColor.color.RGBA;
				if(null != rgba)
				{
					r = rgba.R;
					g = rgba.G;
					b = rgba.B;
				}
			}
			if(null != this.tint && 0 != this.tint)
			{
				var oCColorModifiers = new AscFormat.CColorModifiers();
				var HSL = {H: 0, S: 0, L: 0};
				oCColorModifiers.RGB2HSL(r, g, b, HSL);
				if (this.tint < 0)
					HSL.L = HSL.L * (1 + this.tint);
				else
					HSL.L = HSL.L * (1 - this.tint) + (g_nHSLMaxValue - g_nHSLMaxValue * (1 - this.tint));
				HSL.L >>= 0;
				var RGB = {R: 0, G: 0, B: 0};
				oCColorModifiers.HSL2RGB(HSL, RGB);
				r = RGB.R;
				g = RGB.G;
				b = RGB.B;
			}
			nRes |= b;
			nRes |= g << 8;
			nRes |= r << 16;
		}
		this.rgb = nRes;
	}
};
function CorrectAscColor(asc_color)
{
	if (null == asc_color)
		return null;

	var ret = null;

	var _type = asc_color.asc_getType();
	switch (_type)
	{
		case Asc.c_oAscColor.COLOR_TYPE_SCHEME:
		{
			// тут выставляется ТОЛЬКО из меню. поэтому:
			var _index = asc_color.asc_getValue() >> 0;
			var _id = (_index / 6) >> 0;
			var _pos = _index - _id * 6;
			var basecolor = g_oColorManager.getThemeColor(_id);
			var aTints = g_oThemeColorsDefaultModsSpreadsheet[AscCommon.GetDefaultColorModsIndex(basecolor.getR(), basecolor.getG(), basecolor.getB())];
			var tint = aTints[_pos];
			ret = g_oColorManager.getThemeColor(_id, tint);
			break;
		}
		default:
		{
			ret = createRgbColor(asc_color.asc_getR(), asc_color.asc_getG(), asc_color.asc_getB());
		}
	}
	return ret;
}
function ColorManager()
{
	this.theme = null;
	this.aColors = new Array(12);
}
ColorManager.prototype =
{
	isEqual : function(color1, color2, byRgb)
	{
		var bRes = false;
		if(null == color1 && null == color2)
			bRes = true;
		else if(null != color1 && null != color2)
		{
			if((color1 instanceof ThemeColor && color2 instanceof ThemeColor) || (color1 instanceof RgbColor && color2 instanceof RgbColor) || byRgb)
				bRes =  color1.getRgb() == color2.getRgb();
		}
		return bRes;
	},
	setTheme : function(theme)
	{
		this.theme = theme;
		this.rebuildColors();
	},
	getThemeColor : function(theme, tint)
	{
		if(null == tint)
			tint = null;
		var oColorObj = this.aColors[theme];
		if(null == oColorObj)
		{
			oColorObj = {};
			this.aColors[theme] = oColorObj;
		}
		var oThemeColor = oColorObj[tint];
		if(null == oThemeColor)
		{
			oThemeColor = new ThemeColor();
			oThemeColor.theme = theme;
			oThemeColor.tint = tint;
			if(null != this.theme)
				oThemeColor.rebuild(this.theme);
			oColorObj[tint] = oThemeColor;
		}
		return oThemeColor;
	},
	rebuildColors : function()
	{
		if(null != this.theme)
		{
			for(var i = 0, length = this.aColors.length; i < length; ++i)
			{
				var oColorObj = this.aColors[i];
				for(var j in oColorObj)
				{
					var oThemeColor = oColorObj[j];
					oThemeColor.rebuild(this.theme);
				}
			}
		}
	}
};
g_oColorManager = new ColorManager();

	var g_oDefaultFormat = {
		XfId: null,
		Font: null,
		Fill: null,
		Num: null,
		Border: null,
		Align: null,
		FillAbs: null,
		NumAbs: null,
		BorderAbs: null,
		AlignAbs: null,
		ColorAuto: new RgbColor(0)
	};

	/** @constructor */
	function Fragment(val) {
		this.text = null;
		this.format = null;
		if (null != val) {
			this.set(val);
		}
	}

	Fragment.prototype.clone = function () {
		return new Fragment(this);
	};
	Fragment.prototype.set = function (oVal) {
		if (null != oVal.text) {
			this.text = oVal.text;
		}
		if (null != oVal.format) {
			this.format = oVal.format;
		}
	};
	Fragment.prototype.checkVisitedHyperlink = function (row, col, hyperlinkManager) {
		var color = this.format.getColor();
		if (color instanceof AscCommonExcel.ThemeColor && g_nColorHyperlink === color.theme && null === color.tint) {
			//для посещенных гиперссылок
			var hyperlink = hyperlinkManager.getByCell(row, col);
			if (hyperlink && hyperlink.data.getVisited()) {
				this.format.setColor(g_oColorManager.getThemeColor(g_nColorHyperlinkVisited, null));
			}
		}
	};

	function readValAttr(attr){
		if(attr()){
			var val = attr()["val"];
			return val ? val : null;
		}
		return null;
	}
	function getNumFromXml(val) {
		return val ? val - 0 : null;
	}
	function getColorFromXml(attr) {
		if(attr()){
			var vals = attr();
			if(null != vals["theme"]) {
				return AscCommonExcel.g_oColorManager.getThemeColor(getNumFromXml(vals["theme"]), getNumFromXml(vals["tint"]));
			} else if(null != vals["rgb"]){
				return new AscCommonExcel.RgbColor(0x00ffffff & getNumFromXml(vals["rgb"]));
			}
		}
		return null;
	}

var g_oFontProperties = {
		fn: 0,
		scheme: 1,
		fs: 2,
		b: 3,
		i: 4,
		u: 5,
		s: 6,
		c: 7,
		va: 8
	};

	/** @constructor */
	function Font() {
		this.fn = null;
		this.scheme = null;
		this.fs = null;
		this.b = null;
		this.i = null;
		this.u = null;
		this.s = null;
		this.c = null;
		this.va = null;
		this.skip = null;
		this.repeat = null;

		this._hash;
		this._index;
	}
	Font.prototype.Properties = g_oFontProperties;
	Font.prototype.getHash = function() {
		if(!this._hash){
			var color = this.c ? this.c.getHash() : '';
			this._hash = this.fn + '|' +this.scheme + '|' +this.fs + '|' +this.b + '|' +this.i + '|' +this.u + '|' +
				this.s + '|' + color + '|' +this.va + '|' + this.skip + '|' +this.repeat;
		}
		return this._hash;
	};
	Font.prototype.getIndexNumber = function() {
		return this._index;
	};
	Font.prototype.setIndexNumber = function(val) {
		return this._index = val;
	};
	Font.prototype.assign = function(font) {
		this.fn = font.fn;
		this.scheme = font.scheme;
		this.fs = font.fs;
		this.b = font.b;
		this.i = font.i;
		this.u = font.u;
		this.s = font.s;
		this.c = font.c;
		this.va = font.va;
		this.skip = font.skip;
		this.repeat = font.repeat;
	};
	Font.prototype.assignFromObject = function(font) {
		if (null != font.fn) {
			this.setName(font.fn);
		}
		if (null != font.scheme) {
			this.setScheme(font.scheme);
		}
		if (null != font.fs) {
			this.setSize(font.fs);
		}
		if (null != font.b) {
			this.setBold(font.b);
		}
		if (null != font.i) {
			this.setItalic(font.i);
		}
		if (null != font.u) {
			this.setUnderline(font.u);
		}
		if (null != font.s) {
			this.setStrikeout(font.s);
		}
		if (null != font.c) {
			this.setColor(font.c);
		}
		if (null != font.va) {
			this.setVerticalAlign(font.va);
		}
		if (null != font.skip) {
			this.setSkip(font.skip);
		}
		if (null != font.repeat) {
			this.setRepeat(font.repeat);
		}
	};
	Font.prototype.merge = function (font, isTable) {
		var oRes = new Font();
		oRes.fn = this.fn || font.fn;
		oRes.scheme = this.scheme || font.scheme;
		oRes.fs = this.fs || font.fs;
		oRes.b = this.b || font.b;
		oRes.i = this.i || font.i;
		oRes.s = this.s || font.s;
		oRes.u = this.u || font.u;
		//заглушка excel при merge стилей игнорирует default цвет
		if (isTable && this.c && this.c.isEqual(g_oDefaultFormat.Font.c)) {
			oRes.c = font.c || this.c;
		} else {
			oRes.c = this.c || font.c;
		}
		oRes.va = this.va || font.va;
		oRes.skip = this.skip || font.skip;
		oRes.repeat = this.repeat || font.repeat;
		return oRes;
	};
	Font.prototype.getRgbOrNull = function () {
		var nRes = null;
		if (null != this.c) {
			nRes = this.c.getRgb();
		}
		return nRes;
	};
	Font.prototype.isEqual = function (font) {
		var bRes = this.fs == font.fs && this.b == font.b && this.i == font.i && this.u == font.u && this.s == font.s &&
			g_oColorManager.isEqual(this.c, font.c) && this.va == font.va && this.skip == font.skip &&
			this.repeat == font.repeat;
		if (bRes) {
			var schemeThis = this.getScheme();
			var schemeOther = font.getScheme();
			if (Asc.EFontScheme.fontschemeNone == schemeThis && Asc.EFontScheme.fontschemeNone == schemeOther) {
				bRes = this.fn == font.fn;
			} else if (Asc.EFontScheme.fontschemeNone != schemeThis &&
				Asc.EFontScheme.fontschemeNone != schemeOther) {
				bRes = schemeThis == schemeOther;
			} else {
				bRes = false;
			}
		}
		return bRes;
	};
	Font.prototype.clone = function () {
		var font = new Font();
		font.assign(this);
		return font;
	};
	Font.prototype.intersect = function (oFont, oDefVal) {
		if (this.fn != oFont.fn) {
			this.fn = oDefVal.fn;
		}
		if (this.scheme != oFont.scheme) {
			this.scheme = oDefVal.scheme;
		}
		if (this.fs != oFont.fs) {
			this.fs = oDefVal.fs;
		}
		if (this.b != oFont.b) {
			this.b = oDefVal.b;
		}
		if (this.i != oFont.i) {
			this.i = oDefVal.i;
		}
		if (this.u != oFont.u) {
			this.u = oDefVal.u;
		}
		if (this.s != oFont.s) {
			this.s = oDefVal.s;
		}
		if (false == g_oColorManager.isEqual(this.c, oFont.c)) {
			this.c = oDefVal.c;
		}
		if (this.va != oFont.va) {
			this.va = oDefVal.va;
		}
		if (this.skip != oFont.skip) {
			this.skip = oDefVal.skip;
		}
		if (this.repeat != oFont.repeat) {
			this.repeat = oDefVal.repeat;
		}
	};
	Font.prototype.getName = function () {
		return this.fn || g_oDefaultFormat.Font.fn;
	};
	Font.prototype.setName = function (val) {
		return this.fn = val;
	};
	Font.prototype.getScheme = function () {
		return this.scheme || Asc.EFontScheme.fontschemeNone;
	};
	Font.prototype.setScheme = function(val) {
		return (null != val && Asc.EFontScheme.fontschemeNone != val) ? this.scheme = val : this.scheme = null;
	};
	Font.prototype.getSize = function () {
		return this.fs || g_oDefaultFormat.Font.fs;
	};
	Font.prototype.setSize = function(val) {
		return this.fs = val;
	};
	Font.prototype.getBold = function () {
		return !!this.b;
	};
	Font.prototype.setBold = function(val) {
		return val ? this.b = true : this.b = null;
	};
	Font.prototype.getItalic = function () {
		return !!this.i;
	};
	Font.prototype.setItalic = function(val) {
		return val ? this.i = true : this.i = null;
	};
	Font.prototype.getUnderline = function () {
		return null != this.u ? this.u : Asc.EUnderline.underlineNone;
	};
	Font.prototype.setUnderline = function(val) {
		return (null != val && Asc.EUnderline.underlineNone != val) ? this.u = val : this.u = null;
	};
	Font.prototype.getStrikeout = function () {
		return !!this.s;
	};
	Font.prototype.setStrikeout = function(val) {
		return val ? this.s = true : this.s = null;
	};
	Font.prototype.getColor = function () {
		return this.c || g_oDefaultFormat.ColorAuto;
	};
	Font.prototype.setColor = function(val) {
		return this.c = val;
	};
	Font.prototype.getVerticalAlign = function () {
		return null != this.va ? this.va : AscCommon.vertalign_Baseline;
	};
	Font.prototype.setVerticalAlign = function(val) {
		return (null != val && AscCommon.vertalign_Baseline != val) ? this.va = val : this.va = null;
	};
	Font.prototype.getSkip = function () {
		return !!this.skip;
	};
	Font.prototype.setSkip = function(val) {
		return val ? this.skip = true : this.skip = null;
	};
	Font.prototype.getRepeat = function () {
		return !!this.repeat;
	};
	Font.prototype.setRepeat = function (val) {
		return val ? this.repeat = true : this.repeat = null;
	};
	Font.prototype.getType = function () {
		return UndoRedoDataTypes.StyleFont;
	};
	Font.prototype.getProperties = function () {
		return this.Properties;
	};
	Font.prototype.getProperty = function (nType) {
		switch (nType) {
			case this.Properties.fn:
				return this.fn;
				break;
			case this.Properties.scheme:
				return this.scheme;
				break;
			case this.Properties.fs:
				return this.fs;
				break;
			case this.Properties.b:
				return this.b;
				break;
			case this.Properties.i:
				return this.i;
				break;
			case this.Properties.u:
				return this.u;
				break;
			case this.Properties.s:
				return this.s;
				break;
			case this.Properties.c:
				return this.c;
				break;
			case this.Properties.va:
				return this.va;
				break;
		}
	};
	Font.prototype.setProperty = function (nType, value) {
		switch (nType) {
			case this.Properties.fn:
				this.fn = value;
				break;
			case this.Properties.scheme:
				this.scheme = value;
				break;
			case this.Properties.fs:
				this.fs = value;
				break;
			case this.Properties.b:
				this.b = value;
				break;
			case this.Properties.i:
				this.i = value;
				break;
			case this.Properties.u:
				this.u = value;
				break;
			case this.Properties.s:
				this.s = value;
				break;
			case this.Properties.c:
				this.c = value;
				break;
			case this.Properties.va:
				this.va = value;
				break;
		}
	};
	Font.prototype.onStartNode = function(elem, attr, uq) {
		var newContext = this;
		if("b" === elem){
			this.b = getBoolFromXml(readValAttr(attr));
		} else if("color" === elem){
			this.c = getColorFromXml(attr);
		} else if("i" === elem){
			this.i = getBoolFromXml(readValAttr(attr));
		} else if("name" === elem){
			this.fn = readValAttr(attr);
		} else if("scheme" === elem){
			this.scheme = readValAttr(attr);
		} else if("strike" === elem){
			this.s = getBoolFromXml(readValAttr(attr));
		} else if("sz" === elem){
			this.fs = getNumFromXml(readValAttr(attr));
		} else if("u" === elem){
			switch (readValAttr(attr)) {
				case "single":
					this.u = Asc.EUnderline.underlineSingle;
					break;
				case "double":
					this.u = Asc.EUnderline.underlineDouble;
					break;
				case "singleAccounting":
					this.u = Asc.EUnderline.underlineSingleAccounting;
					break;
				case "doubleAccounting":
					this.u = Asc.EUnderline.underlineDoubleAccounting;
					break;
				case "none":
					this.u = Asc.EUnderline.underlineNone;
					break;
			}
		} else if("vertAlign" === elem){
			switch (readValAttr(attr)) {
				case "baseline":
					this.va = AscCommon.vertalign_Baseline;
					break;
				case "superscript":
					this.va = AscCommon.vertalign_SuperScript;
					break;
				case "subscript":
					this.va = AscCommon.vertalign_SubScript;
					break;
			}
		} else {
			newContext = null;
		}
		return newContext;
	};

	var st_gradienttypeLINEAR = 0;
	var st_gradienttypePATH = 1;

	var st_patterntypeNONE = 0;
	var st_patterntypeSOLID = 1;
	var st_patterntypeMEDIUMGRAY = 2;
	var st_patterntypeDARKGRAY = 3;
	var st_patterntypeLIGHTGRAY = 4;
	var st_patterntypeDARKHORIZONTAL = 5;
	var st_patterntypeDARKVERTICAL = 6;
	var st_patterntypeDARKDOWN = 7;
	var st_patterntypeDARKUP = 8;
	var st_patterntypeDARKGRID = 9;
	var st_patterntypeDARKTRELLIS = 10;
	var st_patterntypeLIGHTHORIZONTAL = 11;
	var st_patterntypeLIGHTVERTICAL = 12;
	var st_patterntypeLIGHTDOWN = 13;
	var st_patterntypeLIGHTUP = 14;
	var st_patterntypeLIGHTGRID = 15;
	var st_patterntypeLIGHTTRELLIS = 16;
	var st_patterntypeGRAY125 = 17;
	var st_patterntypeGRAY0625 = 18;

	function FromXml_ST_GradientType(val) {
		var res = -1;
		if ("linear" === val) {
			res = st_gradienttypeLINEAR;
		} else if ("path" === val) {
			res = st_gradienttypePATH;
		}
		return res;
	}

	function FromXml_ST_PatternType(val) {
		var res = -1;
		if ("none" === val) {
			res = st_patterntypeNONE;
		} else if ("solid" === val) {
			res = st_patterntypeSOLID;
		} else if ("mediumGray" === val) {
			res = st_patterntypeMEDIUMGRAY;
		} else if ("darkGray" === val) {
			res = st_patterntypeDARKGRAY;
		} else if ("lightGray" === val) {
			res = st_patterntypeLIGHTGRAY;
		} else if ("darkHorizontal" === val) {
			res = st_patterntypeDARKHORIZONTAL;
		} else if ("darkVertical" === val) {
			res = st_patterntypeDARKVERTICAL;
		} else if ("darkDown" === val) {
			res = st_patterntypeDARKDOWN;
		} else if ("darkUp" === val) {
			res = st_patterntypeDARKUP;
		} else if ("darkGrid" === val) {
			res = st_patterntypeDARKGRID;
		} else if ("darkTrellis" === val) {
			res = st_patterntypeDARKTRELLIS;
		} else if ("lightHorizontal" === val) {
			res = st_patterntypeLIGHTHORIZONTAL;
		} else if ("lightVertical" === val) {
			res = st_patterntypeLIGHTVERTICAL;
		} else if ("lightDown" === val) {
			res = st_patterntypeLIGHTDOWN;
		} else if ("lightUp" === val) {
			res = st_patterntypeLIGHTUP;
		} else if ("lightGrid" === val) {
			res = st_patterntypeLIGHTGRID;
		} else if ("lightTrellis" === val) {
			res = st_patterntypeLIGHTTRELLIS;
		} else if ("gray125" === val) {
			res = st_patterntypeGRAY125;
		} else if ("gray0625" === val) {
			res = st_patterntypeGRAY0625;
		}
		return res;
	}

	function CT_GradientFill() {
		//Attributes
		this.type = null;//linear
		this.degree = null;//0
		this.left = null;//0
		this.right = null;//0
		this.top = null;//0
		this.bottom = null;//0
		//Members
		this.stop = [];
	}

	CT_GradientFill.prototype.readAttributes = function(attr, uq) {
		if (attr()) {
			var vals = attr();
			var val;
			val = vals["type"];
			if (undefined !== val) {
				val = FromXml_ST_GradientType(val);
				if (-1 !== val) {
					this.type = val;
				}
			}
			val = vals["degree"];
			if (undefined !== val) {
				this.degree = val - 0;
			}
			val = vals["left"];
			if (undefined !== val) {
				this.left = val - 0;
			}
			val = vals["right"];
			if (undefined !== val) {
				this.right = val - 0;
			}
			val = vals["top"];
			if (undefined !== val) {
				this.top = val - 0;
			}
			val = vals["bottom"];
			if (undefined !== val) {
				this.bottom = val - 0;
			}
		}
	};
	CT_GradientFill.prototype.onStartNode = function(elem, attr, uq) {
		var newContext = this;
		if ("stop" === elem) {
			newContext = new CT_GradientStop();
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
			this.stop.push(newContext);
		}
		else {
			newContext = null;
		}
		return newContext;
	};
	function CT_GradientStop() {
		//Attributes
		this.position = null;
		//Members
		this.color = null;
	}

	CT_GradientStop.prototype.readAttributes = function(attr, uq) {
		if (attr()) {
			var vals = attr();
			var val;
			val = vals["position"];
			if (undefined !== val) {
				this.position = val - 0;
			}
		}
	};
	CT_GradientStop.prototype.onStartNode = function(elem, attr, uq) {
		var newContext = this;
		if ("color" === elem) {
			this.color = getColorFromXml(attr);
		}
		else {
			newContext = null;
		}
		return newContext;
	};
	function CT_PatternFill() {
		//Attributes
		this.patternType = null;
		//Members
		this.fgColor = null;
		this.bgColor = null;
	}

	CT_PatternFill.prototype.readAttributes = function(attr, uq) {
		if (attr()) {
			var vals = attr();
			var val;
			val = vals["patternType"];
			if (undefined !== val) {
				val = FromXml_ST_PatternType(val);
				if (-1 !== val) {
					this.patternType = val;
				}
			}
		}
	};
	CT_PatternFill.prototype.onStartNode = function(elem, attr, uq) {
		var newContext = this;
		if ("fgColor" === elem) {
			this.fgColor = getColorFromXml(attr);
		}
		else if ("bgColor" === elem) {
			this.bgColor = getColorFromXml(attr);
		}
		else {
			newContext = null;
		}
		return newContext;
	};

	var g_oFillProperties = {
		bg: 0
	};

	/** @constructor */
	function Fill(val) {
		if (null == val) {
			val = g_oDefaultFormat.FillAbs;
		}
		this.bg = val.bg;

		this._hash;
		this._index;
	}

	Fill.prototype.Properties = g_oFillProperties;
	Fill.prototype.getHash = function () {
		if (!this._hash) {
			this._hash = this.bg ? this.bg.getHash() : '';
		}
		return this._hash;
	};
	Fill.prototype.getIndexNumber = function () {
		return this._index;
	};
	Fill.prototype.setIndexNumber = function (val) {
		return this._index = val;
	};
	Fill.prototype._mergeProperty = function (first, second, def) {
		if (def != first) {
			return first;
		} else {
			return second;
		}
	};
	Fill.prototype.merge = function (fill) {
		var oRes = new Fill();
		oRes.bg = this._mergeProperty(this.bg, fill.bg, g_oDefaultFormat.Fill.bg);
		return oRes;
	};
	Fill.prototype.getRgbOrNull = function () {
		var nRes = null;
		if (null != this.bg) {
			nRes = this.bg.getRgb();
		}
		return nRes;
	};
	Fill.prototype.getDif = function (val) {
		var oRes = new Fill(this);
		var bEmpty = true;
		if (g_oColorManager.isEqual(this.bg, val.bg)) {
			oRes.bg = null;
		} else {
			bEmpty = false;
		}
		if (bEmpty) {
			oRes = null;
		}
		return oRes;
	};
	Fill.prototype.isEqual = function (fill) {
		return g_oColorManager.isEqual(this.bg, fill.bg);
	};
	Fill.prototype.clone = function () {
		return new Fill(this);
	};
	Fill.prototype.getType = function () {
		return UndoRedoDataTypes.StyleFill;
	};
	Fill.prototype.getProperties = function () {
		return this.Properties;
	};
	Fill.prototype.getProperty = function (nType) {
		switch (nType) {
			case this.Properties.bg:
				return this.bg;
				break;
		}
	};
	Fill.prototype.setProperty = function (nType, value) {
		switch (nType) {
			case this.Properties.bg:
				this.bg = value;
				break;
		}
	};
	Fill.prototype.notEmpty = function () {
		return null !== this.bg;
	};
	Fill.prototype.onStartNode = function (elem, attr, uq) {
		var newContext = this;
		if ("gradientFill" === elem) {
			newContext = new CT_GradientFill();
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
		} else if ("patternFill" === elem) {
			newContext = new CT_PatternFill();
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
		} else {
			newContext = null;
		}
		return newContext;
	};
	Fill.prototype.onEndNode = function (prevContext, elem) {
		if ("gradientFill" === elem) {
			if (prevContext.stop.length > 0) {
				var stop = prevContext.stop[0];
				if (stop.color) {
					this.bg = stop.color;
				}
			}
		} else if ("patternFill" === elem) {
			if (st_patterntypeNONE !== prevContext.patternType) {
				if (AscCommon.openXml.SaxParserDataTransfer.priorityBg) {
					if (prevContext.bgColor) {
						this.bg = prevContext.bgColor;
					} else if (prevContext.fgColor) {
						this.bg = prevContext.fgColor;
					}
				} else {
					if (prevContext.fgColor) {
						this.bg = prevContext.fgColor;
					} else if (prevContext.bgColor) {
						this.bg = prevContext.bgColor;
					}
				}
			}
		}
	};

	function FromXml_ST_BorderStyle(val) {
		var res = -1;
		if ("none" === val) {
			res = c_oAscBorderStyles.None;
		} else if ("thin" === val) {
			res = c_oAscBorderStyles.Thin;
		} else if ("medium" === val) {
			res = c_oAscBorderStyles.Medium;
		} else if ("dashed" === val) {
			res = c_oAscBorderStyles.Dashed;
		} else if ("dotted" === val) {
			res = c_oAscBorderStyles.Dotted;
		} else if ("thick" === val) {
			res = c_oAscBorderStyles.Thick;
		} else if ("double" === val) {
			res = c_oAscBorderStyles.Double;
		} else if ("hair" === val) {
			res = c_oAscBorderStyles.Hair;
		} else if ("mediumDashed" === val) {
			res = c_oAscBorderStyles.MediumDashed;
		} else if ("dashDot" === val) {
			res = c_oAscBorderStyles.DashDot;
		} else if ("mediumDashDot" === val) {
			res = c_oAscBorderStyles.MediumDashDot;
		} else if ("dashDotDot" === val) {
			res = c_oAscBorderStyles.DashDotDot;
		} else if ("mediumDashDotDot" === val) {
			res = c_oAscBorderStyles.MediumDashDotDot;
		} else if ("slantDashDot" === val) {
			res = c_oAscBorderStyles.SlantDashDot;
		}
		return res;
	}

	var g_oBorderPropProperties = {
		s: 0, c: 1
	};

	function BorderProp() {
		this.s = c_oAscBorderStyles.None;
		this.w = c_oAscBorderWidth.None;
		this.c = g_oColorManager.getThemeColor(1);
	}
	BorderProp.prototype.Properties = g_oBorderPropProperties;
	BorderProp.prototype.getHash = function() {
		if (!this._hash) {
			var color = this.c ? this.c.getHash() : '';
			this._hash = this.s + ';' + this.w + ';' + color;
		}
		return this._hash;
	};
	BorderProp.prototype.setStyle = function (style) {
		this.s = style;
		switch (this.s) {
			case c_oAscBorderStyles.Thin:
			case c_oAscBorderStyles.DashDot:
			case c_oAscBorderStyles.DashDotDot:
			case c_oAscBorderStyles.Dashed:
			case c_oAscBorderStyles.Dotted:
			case c_oAscBorderStyles.Hair:
				this.w = c_oAscBorderWidth.Thin;
				break;
			case c_oAscBorderStyles.Medium:
			case c_oAscBorderStyles.MediumDashDot:
			case c_oAscBorderStyles.MediumDashDotDot:
			case c_oAscBorderStyles.MediumDashed:
			case c_oAscBorderStyles.SlantDashDot:
				this.w = c_oAscBorderWidth.Medium;
				break;
			case c_oAscBorderStyles.Thick:
			case c_oAscBorderStyles.Double:
				this.w = c_oAscBorderWidth.Thick;
				break;
			default:
				this.w = c_oAscBorderWidth.None;
				break;
		}
	};
	BorderProp.prototype.getDashSegments = function () {
		var res;
		switch (this.s) {
			case c_oAscBorderStyles.Hair:
				res = [1, 1];
				break;
			case c_oAscBorderStyles.Dotted:
				res = [2, 2];
				break;
			case c_oAscBorderStyles.DashDotDot:
			case c_oAscBorderStyles.MediumDashDotDot:
				res = [3, 3, 3, 3, 9, 3];
				break;
			case c_oAscBorderStyles.DashDot:
			case c_oAscBorderStyles.MediumDashDot:
			case c_oAscBorderStyles.SlantDashDot:
				res = [3, 3, 9, 3];
				break;
			case c_oAscBorderStyles.Dashed:
				res = [3, 1];
				break;
			case c_oAscBorderStyles.MediumDashed:
				res = [9, 3];
				break;
			case c_oAscBorderStyles.Thin:
			case c_oAscBorderStyles.Medium:
			case c_oAscBorderStyles.Thick:
			case c_oAscBorderStyles.Double:
			default:
				res = [];
				break;
		}
		return res;
	};
	BorderProp.prototype.getRgbOrNull = function () {
		var nRes = null;
		if (null != this.c) {
			nRes = this.c.getRgb();
		}
		return nRes;
	};
	BorderProp.prototype.isEmpty = function () {
		return c_oAscBorderStyles.None === this.s;
	};
	BorderProp.prototype.isEqual = function (val, byRgb) {
		return this.s === val.s && g_oColorManager.isEqual(this.c, val.c, byRgb);
	};
	BorderProp.prototype.clone = function () {
		var res = new BorderProp();
		res.merge(this);
		return res;
	};
	BorderProp.prototype.merge = function (oBorderProp) {
		if (null != oBorderProp.s && c_oAscBorderStyles.None !== oBorderProp.s) {
			this.s = oBorderProp.s;
			this.w = oBorderProp.w;
			if (null != oBorderProp.c) {
				this.c = oBorderProp.c;
			}
		}
	};
	BorderProp.prototype.getType = function () {
		return UndoRedoDataTypes.StyleBorderProp;
	};
	BorderProp.prototype.getProperties = function () {
		return this.Properties;
	};
	BorderProp.prototype.getProperty = function (nType) {
		switch (nType) {
			case this.Properties.s:
				return this.s;
				break;
			case this.Properties.c:
				return this.c;
				break;
		}
	};
	BorderProp.prototype.setProperty = function (nType, value) {
		switch (nType) {
			case this.Properties.s:
				this.setStyle(value);
				break;
			case this.Properties.c:
				this.c = value;
				break;
		}
	};
	BorderProp.prototype.readAttributes = function(attr, uq) {
		if(attr()){
			var vals = attr();
			var val;
			val = vals["style"];
			if(undefined !== val){
				val = FromXml_ST_BorderStyle(val);
				if(-1 !== val){
					this.setStyle(val);
				}
			}
		}
	};
	BorderProp.prototype.onStartNode = function(elem, attr, uq) {
		var newContext = this;
		if("color" === elem){
			this.c = getColorFromXml(attr);
		}
		else {
			newContext = null;
		}
		return newContext;
	};
var g_oBorderProperties = {
		l: 0,
		t: 1,
		r: 2,
		b: 3,
		d: 4,
		ih: 5,
		iv: 6,
		dd: 7,
		du: 8
	};

	/** @constructor */
	function Border(val) {
		if (null == val) {
			val = g_oDefaultFormat.BorderAbs;
		}
		this.l = val.l.clone();
		this.t = val.t.clone();
		this.r = val.r.clone();
		this.b = val.b.clone();
		this.d = val.d.clone();
		this.ih = val.ih.clone();
		this.iv = val.iv.clone();
		this.dd = val.dd;
		this.du = val.du;

		this._hash;
		this._index;
	}

	Border.prototype.Properties = g_oBorderProperties;
	Border.prototype.getHash = function() {
		if (!this._hash) {
			this._hash = (this.l ? this.l.getHash() : '') + '|';
			this._hash += (this.t ? this.t.getHash() : '') + '|';
			this._hash += (this.r ? this.r.getHash() : '') + '|';
			this._hash += (this.b ? this.b.getHash() : '') + '|';
			this._hash += (this.d ? this.d.getHash() : '') + '|';
			this._hash += (this.ih ? this.ih.getHash() : '') + '|';
			this._hash += (this.iv ? this.iv.getHash() : '') + '|';
			this._hash += this.dd + '|';
			this._hash += this.du;
		}
		return this._hash;
	};
	Border.prototype.getIndexNumber = function() {
		return this._index;
	};
	Border.prototype.setIndexNumber = function(val) {
		return this._index = val;
	};
	Border.prototype._mergeProperty = function (first, second, def) {
		if ((null != def.isEqual && false == def.isEqual(first)) || (null == def.isEqual && def != first)) {
			return first;
		} else {
			return second;
		}
	};
	Border.prototype.merge = function (border) {
		var defaultBorder = g_oDefaultFormat.Border;
		var oRes = new Border();
		oRes.l = this._mergeProperty(this.l, border.l, defaultBorder.l).clone();
		oRes.t = this._mergeProperty(this.t, border.t, defaultBorder.t).clone();
		oRes.r = this._mergeProperty(this.r, border.r, defaultBorder.r).clone();
		oRes.b = this._mergeProperty(this.b, border.b, defaultBorder.b).clone();
		oRes.d = this._mergeProperty(this.d, border.d, defaultBorder.d).clone();
		oRes.ih = this._mergeProperty(this.ih, border.ih, defaultBorder.ih).clone();
		oRes.iv = this._mergeProperty(this.iv, border.iv, defaultBorder.iv).clone();
		oRes.dd = this._mergeProperty(this.dd, border.dd, defaultBorder.dd);
		oRes.du = this._mergeProperty(this.du, border.du, defaultBorder.du);
		return oRes;
	};
	Border.prototype.getDif = function (val) {
		var oRes = new Border(this);
		var bEmpty = true;
		if (true == this.l.isEqual(val.l)) {
			oRes.l = null;
		} else {
			bEmpty = false;
		}
		if (true == this.t.isEqual(val.t)) {
			oRes.t = null;
		} else {
			bEmpty = false;
		}
		if (true == this.r.isEqual(val.r)) {
			oRes.r = null;
		} else {
			bEmpty = false;
		}
		if (true == this.b.isEqual(val.b)) {
			oRes.b = null;
		} else {
			bEmpty = false;
		}
		if (true == this.d.isEqual(val.d)) {
			oRes.d = null;
		}
		if (true == this.ih.isEqual(val.ih)) {
			oRes.ih = null;
		} else {
			bEmpty = false;
		}
		if (true == this.iv.isEqual(val.iv)) {
			oRes.iv = null;
		} else {
			bEmpty = false;
		}
		if (this.dd == val.dd) {
			oRes.dd = null;
		} else {
			bEmpty = false;
		}
		if (this.du == val.du) {
			oRes.du = null;
		} else {
			bEmpty = false;
		}
		if (bEmpty) {
			oRes = null;
		}
		return oRes;
	};
	Border.prototype.intersect = function (border, def, byRgb) {
		if (!this.l.isEqual(border.l, byRgb)) {
			this.l = def.l;
		}
		if (!this.t.isEqual(border.t, byRgb)) {
			this.t = def.t;
		}
		if (!this.r.isEqual(border.r, byRgb)) {
			this.r = def.r;
		}
		if (!this.b.isEqual(border.b, byRgb)) {
			this.b = def.b;
		}
		if (!this.d.isEqual(border.d, byRgb)) {
			this.d = def.d;
			this.dd = false;
			this.du = false;
		}
		if (!this.ih.isEqual(border.ih, byRgb)) {
			this.ih = def.ih;
		}
		if (!this.iv.isEqual(border.iv, byRgb)) {
			this.iv = def.iv;
		}
		if (this.dd !== border.dd) {
			this.dd = def.dd;
		}
	};
	Border.prototype.isEqual = function (val) {
		return this.l.isEqual(val.l) && this.t.isEqual(val.t) && this.r.isEqual(val.r) && this.b.isEqual(val.b) &&
			this.d.isEqual(val.d) && this.ih.isEqual(val.ih) && this.iv.isEqual(val.iv) && this.dd == val.dd &&
			this.du == val.du;
	};
	Border.prototype.clone = function () {
		return new Border(this);
	};
	Border.prototype.clean = function () {
		var defaultBorder = g_oDefaultFormat.Border;
		this.l = defaultBorder.l.clone();
		this.t = defaultBorder.t.clone();
		this.r = defaultBorder.r.clone();
		this.b = defaultBorder.b.clone();
		this.d = defaultBorder.d.clone();
		this.ih = defaultBorder.ih.clone();
		this.iv = defaultBorder.iv.clone();
		this.dd = defaultBorder.dd;
		this.du = defaultBorder.du;
	};
	Border.prototype.mergeInner = function (border) {
		if (border) {
			if (border.l) {
				this.l.merge(border.l);
			}
			if (border.t) {
				this.t.merge(border.t);
			}
			if (border.r) {
				this.r.merge(border.r);
			}
			if (border.b) {
				this.b.merge(border.b);
			}
			if (border.d) {
				this.d.merge(border.d);
			}
			if (border.ih) {
				this.ih.merge(border.ih);
			}
			if (border.iv) {
				this.iv.merge(border.iv);
			}
			if (null != border.dd) {
				this.dd = this.dd || border.dd;
			}
			if (null != border.du) {
				this.du = this.du || border.du;
			}
		}
	};
	Border.prototype.getType = function () {
		return UndoRedoDataTypes.StyleBorder;
	};
	Border.prototype.getProperties = function () {
		return this.Properties;
	};
	Border.prototype.getProperty = function (nType) {
		switch (nType) {
			case this.Properties.l:
				return this.l;
				break;
			case this.Properties.t:
				return this.t;
				break;
			case this.Properties.r:
				return this.r;
				break;
			case this.Properties.b:
				return this.b;
				break;
			case this.Properties.d:
				return this.d;
				break;
			case this.Properties.ih:
				return this.ih;
				break;
			case this.Properties.iv:
				return this.iv;
				break;
			case this.Properties.dd:
				return this.dd;
				break;
			case this.Properties.du:
				return this.du;
				break;
		}
	};
	Border.prototype.setProperty = function (nType, value) {
		switch (nType) {
			case this.Properties.l:
				this.l = value;
				break;
			case this.Properties.t:
				this.t = value;
				break;
			case this.Properties.r:
				this.r = value;
				break;
			case this.Properties.b:
				this.b = value;
				break;
			case this.Properties.d:
				this.d = value;
				break;
			case this.Properties.ih:
				this.ih = value;
				break;
			case this.Properties.iv:
				this.iv = value;
				break;
			case this.Properties.dd:
				this.dd = value;
				break;
			case this.Properties.du:
				this.du = value;
				break;
		}
	};
	Border.prototype.notEmpty = function () {
		return (this.l && c_oAscBorderStyles.None !== this.l.s) || (this.r && c_oAscBorderStyles.None !== this.r.s) ||
			(this.t && c_oAscBorderStyles.None !== this.t.s) || (this.b && c_oAscBorderStyles.None !== this.b.s) ||
			(this.dd && c_oAscBorderStyles.None !== this.dd.s) || (this.du && c_oAscBorderStyles.None !== this.du.s);
	};
	Border.prototype.readAttributes = function(attr, uq) {
		if(attr()){
			var vals = attr();
			var val;
			val = vals["diagonalUp"];
			if(undefined !== val){
				this.du = getBoolFromXml(val);
			}
			val = vals["diagonalDown"];
			if(undefined !== val){
				this.dd = getBoolFromXml(val);
			}
		}
	};
	Border.prototype.onStartNode = function(elem, attr, uq) {
		var newContext = this;
		if("start" === elem || "left" === elem){
			newContext = new BorderProp();
			if(newContext.readAttributes){
				newContext.readAttributes(attr, uq);
			}
			this.l = newContext;
		}
		else if("end" === elem || "right" === elem){
			newContext = new BorderProp();
			if(newContext.readAttributes){
				newContext.readAttributes(attr, uq);
			}
			this.r = newContext;
		}
		else if("top" === elem){
			newContext = new BorderProp();
			if(newContext.readAttributes){
				newContext.readAttributes(attr, uq);
			}
			this.t = newContext;
		}
		else if("bottom" === elem){
			newContext = new BorderProp();
			if(newContext.readAttributes){
				newContext.readAttributes(attr, uq);
			}
			this.b = newContext;
		}
		else if("diagonal" === elem){
			newContext = new BorderProp();
			if(newContext.readAttributes){
				newContext.readAttributes(attr, uq);
			}
			this.d = newContext;
		}
		else if("vertical" === elem){
			newContext = new BorderProp();
			if(newContext.readAttributes){
				newContext.readAttributes(attr, uq);
			}
			this.iv = newContext;
		}
		else if("horizontal" === elem){
			newContext = new BorderProp();
			if(newContext.readAttributes){
				newContext.readAttributes(attr, uq);
			}
			this.ih = newContext;
		}
		else {
			newContext = null;
		}
		return newContext;
	};
var g_oNumProperties = {
		f: 0,
		id: 1
	};
/** @constructor */
function Num(val)
{
	if(null == val)
		val = g_oDefaultFormat.NumAbs;
	this.f = val.f;
  this.id = val.id;

	this._hash;
	this._index;
}
Num.prototype =
{
	Properties: g_oNumProperties,
	getHash: function() {
		if (!this._hash) {
			this._hash = this.f + '|' + this.id;
		}
		return this._hash;
	},
	getIndexNumber: function() {
		return this._index;
	},
	setIndexNumber: function(val) {
		this._index = val;
	},
  setFormat: function(f, opt_id) {
    this.f = f;
    this.id = opt_id;
  },
  getFormat: function() {
    return (null != this.id) ? (AscCommon.getFormatByStandardId(this.id) || this.f) : this.f;
  },
  _mergeProperty : function(first, second, def)
  {
    if(def != first)
      return first;
    else
      return second;
  },
	merge : function(num)
	{
		var oRes = new Num();
    oRes.f = this._mergeProperty(this.f, num.f, g_oDefaultFormat.Num.f);
    oRes.id = this._mergeProperty(this.id, num.id, g_oDefaultFormat.Num.id);
		return oRes;
	},
  getDif: function(val) {
    var oRes = new Num(this);
    var bEmpty = true;
    if (this.f == val.f) {
      oRes.f = null;
    } else {
      bEmpty = false;
    }
    if (this.id == val.id) {
      oRes.id = null;
    } else {
      bEmpty = false;
    }
    if (bEmpty) {
      oRes = null;
    }
    return oRes;
  },
  isEqual: function(val) {
    if (null != this.id && null != val.id) {
      return this.id == val.id;
    } else if (null != this.id || null != val.id) {
      return false;
    } else {
      return this.f == val.f;
    }
  },
    clone : function()
    {
        return new Num(this);
    },
	getType : function()
	{
		return UndoRedoDataTypes.StyleNum;
	},
	getProperties : function()
	{
		return this.Properties;
	},
	getProperty : function(nType)
	{
		switch(nType)
		{
			case this.Properties.f: return this.f;break;
			case this.Properties.id: return this.id;break;
		}
	},
	setProperty : function(nType, value)
	{
		switch(nType)
		{
			case this.Properties.f: this.f = value;break;
			case this.Properties.id: this.id = value;break;
		}
	},
	readAttributes : function(attr, uq) {
		if (attr()) {
			var vals = attr();
			var val;
			val = vals["numFmtId"];
			var sFormat = null;
			var id;
			if (undefined !== val) {
				id = val - 0;
			}
			val = vals["formatCode"];
			if (undefined !== val) {
				sFormat = AscCommon.unleakString(uq(val));
			}
			this.f = null != sFormat ? sFormat : (AscCommonExcel.aStandartNumFormats[id] || "General");
			if ((5 <= id && id <= 8) || (14 <= id && id <= 17) || 22 == id || (27 <= id && id <= 31) ||
				(36 <= id && id <= 44)) {
				this.id = id;
			}
		}
	}
};
var g_oCellXfsProperties = {
		border: 0,
		fill: 1,
		font: 2,
		num: 3,
		align: 4,
		QuotePrefix: 5,
		XfId: 6,
		PivotButton: 7
	};
/** @constructor */
function CellXfs() {
    this.border = null;
    this.fill = null;
    this.font = null;
    this.num = null;
    this.align = null;
	this.QuotePrefix = null;
	this.PivotButton = null;
	this.XfId = null;

	//inner
	this._hash;
	this._index;
	this.operationCache = {};
}
CellXfs.prototype =
{
	Properties: g_oCellXfsProperties,
	getHash: function() {
		if (!this._hash) {
			this._hash = (this.border ? this.border.getIndexNumber() : '') + '|';
			this._hash += (this.fill ? this.fill.getIndexNumber() : '') + '|';
			this._hash += (this.font ? this.font.getIndexNumber() : '') + '|';
			this._hash += (this.num ? this.num.getIndexNumber() : '') + '|';
			this._hash += (this.align ? this.align.getIndexNumber() : '') + '|';
			this._hash += this.QuotePrefix + '|';
			this._hash += this.PivotButton + '|';
			this._hash += this.XfId + '|';
		}
		return this._hash;
	},
	getIndexNumber: function() {
		return this._index;
	},
	setIndexNumber: function(val) {
		this._index = val;
	},
	_mergeProperty : function(addFunc, first, second, isTable)
	{
		var res = null;
		if(null != first || null != second)
		{
			if(null == first)
				res = second;
			else if(null == second)
				res = first;
			else
			{
				if (null != first.merge) {
					res = addFunc.call(g_StyleCache, first.merge(second, isTable));
				} else {
					res = first;
				}
			}
		}
		return res;
	},
	merge : function(xfs, isTable)
	{
		var xfIndexNumber = xfs.getIndexNumber();
		if (undefined === xfIndexNumber) {
			xfs = g_StyleCache.addXf(xfs, true);
			xfIndexNumber = xfs.getIndexNumber();
		}
		var cache = this.getOperationCache("merge", xfIndexNumber);
		if (!cache) {
			cache = new CellXfs();
			cache.border = this._mergeProperty(g_StyleCache.addBorder, xfs.border, this.border);
			cache.fill = this._mergeProperty(g_StyleCache.addFill, xfs.fill, this.fill);
			cache.font = this._mergeProperty(g_StyleCache.addFont, xfs.font, this.font, isTable);
			cache.num = this._mergeProperty(g_StyleCache.addNum, xfs.num, this.num);
			cache.align = this._mergeProperty(g_StyleCache.addAlign, xfs.align, this.align);
			cache.QuotePrefix = this._mergeProperty(null, xfs.QuotePrefix, this.QuotePrefix);
			cache.PivotButton = this._mergeProperty(null, xfs.PivotButton, this.PivotButton);
			cache.XfId = this._mergeProperty(null, xfs.XfId, this.XfId);
			cache = g_StyleCache.addXf(cache);
			this.setOperationCache("merge", xfIndexNumber, cache);
		}
		return cache;
	},
    clone : function()
    {
        var res = new CellXfs();
		res.border = this.border;
		res.fill = this.fill;
		res.font = this.font;
		res.num = this.num;
		res.align = this.align;
		res.QuotePrefix = this.QuotePrefix;
		res.PivotButton = this.PivotButton;
		res.XfId = this.XfId;
        return res;
    },
	isEqual : function(xfs)
	{
		return this.font === xfs.font && this.fill === xfs.fill && this.border === xfs.border && this.num === xfs.num &&
			this.align === xfs.align && this.QuotePrefix === xfs.QuotePrefix && this.PivotButton === xfs.PivotButton &&
			this.XfId === xfs.XfId;
	},
	getType : function()
	{
		return UndoRedoDataTypes.StyleXfs;
	},
	getProperties : function()
	{
		return this.Properties;
	},
	getProperty : function(nType)
	{
		switch(nType)
		{
			case this.Properties.border: return this.border;break;
			case this.Properties.fill: return this.fill;break;
			case this.Properties.font: return this.font;break;
			case this.Properties.num: return this.num;break;
			case this.Properties.align: return this.align;break;
			case this.Properties.QuotePrefix: return this.QuotePrefix;break;
			case this.Properties.PivotButton: return this.PivotButton;break;
			case this.Properties.XfId: return this.XfId; break;
		}
	},
	setProperty : function(nType, value)
	{
		switch(nType)
		{
			case this.Properties.border: this.border = value;break;
			case this.Properties.fill: this.fill = value;break;
			case this.Properties.font: this.font = value;break;
			case this.Properties.num: this.num = value;break;
			case this.Properties.align: this.align = value;break;
			case this.Properties.QuotePrefix: this.QuotePrefix = value;break;
			case this.Properties.PivotButton: this.PivotButton = value;break;
			case this.Properties.XfId: this.XfId = value; break;
		}
	},
	getBorder: function() {
		return this.border;
	},
	setBorder: function(val) {
		this.border = val;
	},
	getFill: function() {
		return this.fill;
	},
	setFill: function(val) {
		this.fill = val;
	},
	getFont: function() {
		return this.font;
	},
	setFont: function(val) {
		this.font = val;
	},
	getNum: function() {
		return this.num;
	},
	setNum: function(val) {
		this.num = val;
	},
	getAlign: function() {
		return this.align;
	},
	setAlign: function(val) {
		this.align = val;
	},
	getQuotePrefix: function() {
		return this.QuotePrefix;
	},
	setQuotePrefix: function(val) {
		this.QuotePrefix = val;
	},
	getPivotButton: function() {
		return this.PivotButton;
	},
	setPivotButton: function(val) {
		this.PivotButton = val;
	},
	getXfId: function() {
		return this.XfId;
	},
	setXfId: function(val) {
		this.XfId = val;
	},
	getOperationCache: function(operation, val) {
		var res = undefined;
		var operation = this.operationCache[operation];
		if (operation) {
			res = operation[val];
		}
		return res;
	},
	setOperationCache: function(operation, val, xfs) {
		var valCache = this.operationCache[operation];
		if (!valCache) {
			valCache = {};
			this.operationCache[operation] = valCache;
		}
		valCache[val] = xfs;
	}
};

	function FromXml_ST_HorizontalAlignment(val) {
		var res = -1;
		if ("general" === val) {
			res = -1;
		} else if ("left" === val) {
			res = AscCommon.align_Left;
		} else if ("center" === val) {
			res = AscCommon.align_Center;
		} else if ("right" === val) {
			res = AscCommon.align_Right;
		} else if ("fill" === val) {
			res = AscCommon.align_Justify;
		} else if ("justify" === val) {
			res = AscCommon.align_Justify;
		} else if ("centerContinuous" === val) {
			res = AscCommon.align_Center;
		} else if ("distributed" === val) {
			res = AscCommon.align_Justify;
		}
		return res;
	}

	function FromXml_ST_VerticalAlignment(val) {
		var res = -1;
		if ("top" === val) {
			res = Asc.c_oAscVAlign.Top;
		} else if ("center" === val) {
			res = Asc.c_oAscVAlign.Center;
		} else if ("bottom" === val) {
			res = Asc.c_oAscVAlign.Bottom;
		} else if ("justify" === val) {
			res = Asc.c_oAscVAlign.Center;
		} else if ("distributed" === val) {
			res = Asc.c_oAscVAlign.Center;
		}
		return res;
	}

var g_oAlignProperties = {
		hor: 0,
		indent: 1,
		RelativeIndent: 2,
		shrink: 3,
		angle: 4,
		ver: 5,
		wrap: 6
	};
/** @constructor */
function Align(val)
{
	if(null == val)
		val = g_oDefaultFormat.AlignAbs;
	this.hor = val.hor;
	this.indent = val.indent;
	this.RelativeIndent = val.RelativeIndent;
	this.shrink = val.shrink;
	this.angle = val.angle;
	this.ver = val.ver;
	this.wrap = val.wrap;

	this._hash;
	this._index;
}
Align.prototype =
{
	Properties: g_oAlignProperties,
	getHash: function() {
		if (!this._hash) {
			this._hash = this.hor + '|' + this.indent + '|' + this.RelativeIndent + '|' + this.shrink + '|' +
				this.angle + '|' + this.ver + '|' + this.wrap;
		}
		return this._hash;
	},
	getIndexNumber: function() {
		return this._index;
	},
	setIndexNumber: function(val) {
		this._index = val;
	},
	_mergeProperty : function(first, second, def)
	{
		if (def != first)
			return first;
		else
			return second;
	},
	merge : function(border)
	{
		var defaultAlign = g_oDefaultFormat.Align;
		var oRes = new Align();
		oRes.hor = this._mergeProperty(this.hor, border.hor, defaultAlign.hor);
		oRes.indent = this._mergeProperty(this.indent, border.indent, defaultAlign.indent);
		oRes.RelativeIndent = this._mergeProperty(this.RelativeIndent, border.RelativeIndent, defaultAlign.RelativeIndent);
		oRes.shrink = this._mergeProperty(this.shrink, border.shrink, defaultAlign.shrink);
		oRes.angle = this._mergeProperty(this.angle, border.angle, defaultAlign.angle);
		oRes.ver = this._mergeProperty(this.ver, border.ver, defaultAlign.ver);
		oRes.wrap = this._mergeProperty(this.wrap, border.wrap, defaultAlign.wrap);
		return oRes;
	},
	getDif : function(val)
	{
		var oRes = new Align(this);
		var bEmpty = true;
		if(this.hor == val.hor)
			oRes.hor =  null;
		else
			bEmpty = false;
		if(this.indent == val.indent)
			oRes.indent =  null;
		else
			bEmpty = false;
		if(this.RelativeIndent == val.RelativeIndent)
			oRes.RelativeIndent =  null;
		else
			bEmpty = false;
		if(this.shrink == val.shrink)
			oRes.shrink =  null;
		else
			bEmpty = false;
		if(this.angle == val.angle)
			oRes.angle =  null;
		else
			bEmpty = false;
		if(this.ver == val.ver)
			oRes.ver =  null;
		else
			bEmpty = false;
		if(this.wrap == val.wrap)
			oRes.wrap =  null;
		else
			bEmpty = false;
		if(bEmpty)
			oRes = null;
		return oRes;
	},
	isEqual : function(val)
	{
		return this.hor == val.hor && this.indent == val.indent && this.RelativeIndent == val.RelativeIndent && this.shrink == val.shrink &&
				this.angle == val.angle && this.ver == val.ver && this.wrap == val.wrap;
	},
    clone : function()
    {
        return new Align(this);
    },
	getType : function()
	{
		return UndoRedoDataTypes.StyleAlign;
	},
	getProperties : function()
	{
		return this.Properties;
	},
	getProperty : function(nType)
	{
		switch(nType)
		{
			case this.Properties.hor: return this.hor;break;
			case this.Properties.indent: return this.indent;break;
			case this.Properties.RelativeIndent: return this.RelativeIndent;break;
			case this.Properties.shrink: return this.shrink;break;
			case this.Properties.angle: return this.angle;break;
			case this.Properties.ver: return this.ver;break;
			case this.Properties.wrap: return this.wrap;break;
		}
	},
	setProperty : function(nType, value)
	{
		switch(nType)
		{
			case this.Properties.hor: this.hor = value;break;
			case this.Properties.indent: this.indent = value;break;
			case this.Properties.RelativeIndent: this.RelativeIndent = value;break;
			case this.Properties.shrink: this.shrink = value;break;
			case this.Properties.angle: this.angle = value;break;
			case this.Properties.ver: this.ver = value;break;
			case this.Properties.wrap: this.wrap = value;break;
		}
	},
	getAngle: function() {
		var nRes = 0;
		if (0 <= this.angle && this.angle <= 180) {
			nRes = this.angle <= 90 ? this.angle : 90 - this.angle;
		}
		return nRes;
	},
	setAngle: function(val) {
		this.angle = AscCommonExcel.angleInterfaceToFormat(val);;
	},
	getWrap: function() {
		// Для justify wrap всегда true
		return AscCommon.align_Justify === this.hor ? true : this.wrap;
	},
	setWrap: function(val) {
		this.wrap = val;
	},
	getShrinkToFit: function() {
		return this.shrink;
	},
	setShrinkToFit: function(val) {
		this.shrink = val;
	},
	getAlignHorizontal: function() {
		return this.hor;
	},
	setAlignHorizontal: function(val) {
		this.hor = val;
	},
	getAlignVertical: function() {
		return this.ver;
	},
	setAlignVertical: function(val) {
		this.ver = val;
	},
	readAttributes : function(attr, uq) {
	if(attr()){
		var vals = attr();
		var val;
		val = vals["horizontal"];
		if(undefined !== val){
			val = FromXml_ST_HorizontalAlignment(val);
			if(-1 !== val){
				this.hor = val;
			}
		}
		val = vals["vertical"];
		if(undefined !== val){
			val = FromXml_ST_VerticalAlignment(val);
			if(-1 !== val){
				this.ver = val;
			}
		}
		val = vals["textRotation"];
		if(undefined !== val){
			this.angle = val - 0;
		}
		val = vals["wrapText"];
		if(undefined !== val){
			this.wrap = getBoolFromXml(val);
		}
		val = vals["indent"];
		if(undefined !== val){
			this.indent = val - 0;
		}
		val = vals["relativeIndent"];
		if(undefined !== val){
			this.RelativeIndent = val - 0;
		}
		val = vals["shrinkToFit"];
		if(undefined !== val){
			this.shrink = getBoolFromXml(val);
		}
	}
}
};
/** @constructor */
function CCellStyles() {
	this.CustomStyles = [];
	this.DefaultStyles = [];
	// ToDo нужно все компоновать в общий список стилей (для того, чтобы не было проблем с добавлением стилей и отсутствия имени стиля)
	this.AllStyles = {};
}
CCellStyles.prototype.generateFontMap = function (oFontMap) {
	this._generateFontMap(oFontMap, this.DefaultStyles);
	this._generateFontMap(oFontMap, this.CustomStyles);
};
CCellStyles.prototype._generateFontMap = function (oFontMap, aStyles) {
	var i, length, oStyle;
	for (i = 0, length = aStyles.length; i < length; ++i) {
		oStyle = aStyles[i];
		if (null != oStyle.xfs && null != oStyle.xfs.font)
			oFontMap[oStyle.xfs.font.getName()] = 1;
	}
};
/**
 * Возвращает колличество стилей без учета скрытых
 */
CCellStyles.prototype.getDefaultStylesCount = function () {
	var nCount = this.DefaultStyles.length;
	for (var i = 0, length = nCount; i < length; ++i) {
		if (this.DefaultStyles[i].Hidden)
			--nCount;
	}
	return nCount;
};
/**
 * Возвращает колличество стилей без учета скрытых и стандартных
 */
CCellStyles.prototype.getCustomStylesCount = function () {
	var nCount = this.CustomStyles.length;
	for (var i = 0, length = nCount; i < length; ++i) {
		if (this.CustomStyles[i].Hidden || null != this.CustomStyles[i].BuiltinId)
			--nCount;
	}
	return nCount;
};
CCellStyles.prototype.getStyleByXfId = function (oXfId) {
	for (var i = 0, length = this.CustomStyles.length; i < length; ++i) {
		if (oXfId === this.CustomStyles[i].XfId) {
			return this.CustomStyles[i];
		}
	}

	return null;
};
CCellStyles.prototype.getStyleNameByXfId = function (oXfId) {
	var styleName = null;
	if (null === oXfId)
		return styleName;

	var style = null;
	for (var i = 0, length = this.CustomStyles.length; i < length; ++i) {
		style = this.CustomStyles[i];
		if (oXfId === style.XfId) {
			if (null !== style.BuiltinId) {
				styleName = this.getDefaultStyleNameByBuiltinId(style.BuiltinId);
				if (null === styleName)
					styleName = style.Name;
				break;
			} else {
				styleName = style.Name;
				break;
			}
		}
	}

	return styleName;
};
CCellStyles.prototype.getDefaultStyleNameByBuiltinId = function (oBuiltinId) {
	var style = null;
	for (var i = 0, length = this.DefaultStyles.length; i < length; ++i) {
		style = this.DefaultStyles[i];
		if (style.BuiltinId === oBuiltinId)
			return style.Name;
	}
	return null;
};
CCellStyles.prototype.getCustomStyleByBuiltinId = function (oBuiltinId) {
	var style = null;
	for (var i = 0, length = this.CustomStyles.length; i < length; ++i) {
		style = this.CustomStyles[i];
		if (style.BuiltinId === oBuiltinId)
			return style;
	}
	return null;
};
CCellStyles.prototype._prepareCellStyle = function (name) {
	var defaultStyle = null;
	var style = null;
	var i, length;
	var maxXfId = -1;
	// Проверим, есть ли в default
	for (i = 0, length = this.DefaultStyles.length; i < length; ++i) {
		if (name === this.DefaultStyles[i].Name) {
			defaultStyle = this.DefaultStyles[i];
			break;
		}
	}
	// Если есть в default, ищем в custom по builtinId. Если нет, то по имени
	if (defaultStyle) {
		for (i = 0, length = this.CustomStyles.length; i < length; ++i) {
			if (defaultStyle.BuiltinId === this.CustomStyles[i].BuiltinId) {
				style = this.CustomStyles[i];
				break;
			}
			maxXfId = Math.max(maxXfId, this.CustomStyles[i].XfId);
		}
	} else {
		for (i = 0, length = this.CustomStyles.length; i < length; ++i) {
			if (name === this.CustomStyles[i].Name) {
				style = this.CustomStyles[i];
				break;
			}
			maxXfId = Math.max(maxXfId, this.CustomStyles[i].XfId);
		}
	}

	// Если нашли, то возвращаем XfId
	if (style)
		return style.XfId;

	if (defaultStyle) {
		this.CustomStyles[i] = defaultStyle.clone();
		this.CustomStyles[i].XfId = ++maxXfId;
		return this.CustomStyles[i].XfId;
	}
	return g_oDefaultFormat.XfId;
};
/** @constructor */
function CCellStyle() {
	this.BuiltinId = null;
	this.CustomBuiltin = null;
	this.Hidden = null;
	this.ILevel = null;
	this.Name = null;
	this.XfId = null;

	this.xfs = null;

	this.ApplyBorder = true;
	this.ApplyFill = true;
	this.ApplyFont = true;
	this.ApplyNumberFormat = true;
}
CCellStyle.prototype.clone = function () {
	var oNewStyle = new CCellStyle();
	oNewStyle.BuiltinId = this.BuiltinId;
	oNewStyle.CustomBuiltin = this.CustomBuiltin;
	oNewStyle.Hidden = this.Hidden;
	oNewStyle.ILevel = this.ILevel;
	oNewStyle.Name = this.Name;

	oNewStyle.ApplyBorder = this.ApplyBorder;
	oNewStyle.ApplyFill = this.ApplyFill;
	oNewStyle.ApplyFont = this.ApplyFont;
	oNewStyle.ApplyNumberFormat = this.ApplyNumberFormat;

	oNewStyle.xfs = this.xfs.clone();
	return oNewStyle;
};
CCellStyle.prototype.getFill = function () {
	if (null != this.xfs && null != this.xfs.fill)
		return this.xfs.fill.bg;

	return g_oDefaultFormat.Fill.bg;
};
CCellStyle.prototype.getFontColor = function () {
	if (null != this.xfs && null != this.xfs.font)
		return this.xfs.font.getColor();

	return g_oDefaultFormat.Font.c;
};
CCellStyle.prototype.getFont = function () {
	if (null != this.xfs && null != this.xfs.font)
		return this.xfs.font;
	return g_oDefaultFormat.Font;
};
CCellStyle.prototype.getBorder = function () {
	if (null != this.xfs && null != this.xfs.border)
		return this.xfs.border;
	return g_oDefaultFormat.Border;
};
CCellStyle.prototype.getNumFormatStr = function () {
	if(null != this.xfs && null != this.xfs.num)
		return this.xfs.num.getFormat();
	return g_oDefaultFormat.Num.getFormat();
};
/** @constructor */
function StyleManager(){
	//стиль ячейки по умолчанию, может содержать не все свойства
	this.oDefaultXfs = new CellXfs();
}
StyleManager.prototype =
{
	init: function(oDefaultXfs, wb) {
		//font
		if (!oDefaultXfs.font) {
			oDefaultXfs.font = new AscCommonExcel.Font();
		}
		if (!oDefaultXfs.font.scheme) {
			oDefaultXfs.font.scheme = Asc.EFontScheme.fontschemeMinor;
		}
		if (!oDefaultXfs.font.fn) {
			var sThemeFont = null;
			if (null != wb.theme.themeElements && null != wb.theme.themeElements.fontScheme) {
				if (Asc.EFontScheme.fontschemeMinor == oDefaultXfs.font.scheme && wb.theme.themeElements.fontScheme.minorFont) {
					sThemeFont = wb.theme.themeElements.fontScheme.minorFont.latin;
				} else if (Asc.EFontScheme.fontschemeMajor == oDefaultXfs.font.scheme && wb.theme.themeElements.fontScheme.majorFont) {
					sThemeFont = wb.theme.themeElements.fontScheme.majorFont.latin;
				}
			}
			oDefaultXfs.font.fn = sThemeFont ? sThemeFont : "Calibri";
		}
		if (!oDefaultXfs.font.fs) {
			oDefaultXfs.font.fs = 11;
		}
		if (!oDefaultXfs.font.c) {
			oDefaultXfs.font.c = AscCommonExcel.g_oColorManager.getThemeColor(AscCommonExcel.g_nColorTextDefault);
		}
		g_oDefaultFormat.Font = oDefaultXfs.font;
		if(null != oDefaultXfs.fill)
			g_oDefaultFormat.Fill = oDefaultXfs.fill.clone();
		if(null != oDefaultXfs.border)
			g_oDefaultFormat.Border = oDefaultXfs.border.clone();
		if(null != oDefaultXfs.num)
			g_oDefaultFormat.Num = oDefaultXfs.num.clone();
		if(null != oDefaultXfs.align)
			g_oDefaultFormat.Align = oDefaultXfs.align.clone();
		if (null !== oDefaultXfs.XfId) {
			this.oDefaultXfs.XfId = oDefaultXfs.XfId;
			g_oDefaultFormat.XfId = oDefaultXfs.XfId;
		}
		this.oDefaultXfs = oDefaultXfs;
	},
	setCellStyle : function(oItemWithXfs, val)
	{
		return this._setProperty(oItemWithXfs, val, "XfId", CellXfs.prototype.getXfId, CellXfs.prototype.setXfId);
	},
	setNum : function(oItemWithXfs, val)
	{
		return this._setProperty(oItemWithXfs, val, "num", CellXfs.prototype.getNum, CellXfs.prototype.setNum, g_StyleCache.addNum);
	},
	setFont : function(oItemWithXfs, val)
	{
		return this._setProperty(oItemWithXfs, val, "font", CellXfs.prototype.getFont, CellXfs.prototype.setFont, g_StyleCache.addFont);
	},
	setFill : function(oItemWithXfs, val)
	{
		if(val){
			var fill = new Fill();
			fill.bg = val;
			val = fill;
		}
		var oRes = this._setProperty(oItemWithXfs, val, "fill", CellXfs.prototype.getFill, CellXfs.prototype.setFill, g_StyleCache.addFill);
		if (oRes.oldVal) {
			oRes.oldVal = oRes.oldVal.bg;
		}
		if (oRes.newVal) {
			oRes.newVal = oRes.newVal.bg;
		}
		return oRes;
	},
	setBorder : function(oItemWithXfs, val)
	{
		return this._setProperty(oItemWithXfs, val, "border", CellXfs.prototype.getBorder, CellXfs.prototype.setBorder, g_StyleCache.addBorder);
	},
	setQuotePrefix : function(oItemWithXfs, val)
	{
		return this._setProperty(oItemWithXfs, val, "quotePrefix", CellXfs.prototype.getQuotePrefix, CellXfs.prototype.setQuotePrefix);
	},
	setPivotButton : function(oItemWithXfs, val)
	{
		return this._setProperty(oItemWithXfs, val, "pivotButton", CellXfs.prototype.getPivotButton, CellXfs.prototype.setPivotButton);
	},
	setFontname : function(oItemWithXfs, val)
	{
		return this._setFontProperty(oItemWithXfs, val, "name", Font.prototype.getName, function(val){
			this.setName(val);
			this.setScheme(null);
		}, "name");
	},
	setFontsize : function(oItemWithXfs, val)
	{
		return this._setFontProperty(oItemWithXfs, val, "size", Font.prototype.getSize, Font.prototype.setSize);
	},
	setFontcolor : function(oItemWithXfs, val)
	{
		return this._setFontProperty(oItemWithXfs, val, "color", Font.prototype.getColor, Font.prototype.setColor);
	},
	setBold : function(oItemWithXfs, val)
	{
		return this._setFontProperty(oItemWithXfs, val, "bold", Font.prototype.getBold, Font.prototype.setBold);
	},
	setItalic : function(oItemWithXfs, val)
	{
		return this._setFontProperty(oItemWithXfs, val, "italic", Font.prototype.getItalic, Font.prototype.setItalic);
	},
	setUnderline : function(oItemWithXfs, val)
	{
		return this._setFontProperty(oItemWithXfs, val, "underline", Font.prototype.getUnderline, Font.prototype.setUnderline);
	},
	setStrikeout : function(oItemWithXfs, val)
	{
		return this._setFontProperty(oItemWithXfs, val, "strikeout", Font.prototype.getStrikeout, Font.prototype.setStrikeout);
	},
	setFontAlign : function(oItemWithXfs, val)
	{
		return this._setFontProperty(oItemWithXfs, val, "fontAlign", Font.prototype.getVerticalAlign, Font.prototype.setVerticalAlign);
	},
	setAlignVertical : function(oItemWithXfs, val)
	{
		return this._setAlignProperty(oItemWithXfs, val, "alignVertical", Align.prototype.getAlignVertical, Align.prototype.setAlignVertical);
	},
	setAlignHorizontal : function(oItemWithXfs, val)
	{
		return this._setAlignProperty(oItemWithXfs, val, "alignHorizontal", Align.prototype.getAlignHorizontal, Align.prototype.setAlignHorizontal);
	},
	setShrinkToFit : function(oItemWithXfs, val)
	{
		return this._setAlignProperty(oItemWithXfs, val, "shrinkToFit", Align.prototype.getShrinkToFit, Align.prototype.setShrinkToFit);
	},
	setWrap : function(oItemWithXfs, val)
	{
		return this._setAlignProperty(oItemWithXfs, val, "wrap", Align.prototype.getWrap, Align.prototype.setWrap);
	},
    setAngle : function(oItemWithXfs, val)
    {
		return this._setAlignProperty(oItemWithXfs, val, "angle", function(){
			return AscCommonExcel.angleFormatToInterface2(this.angle);
		}, Align.prototype.setAngle);
    },
	setVerticalText : function(oItemWithXfs, val)
    {
		if(true == val)
			return this.setAngle(oItemWithXfs, AscCommonExcel.g_nVerticalTextAngle);
		else
			return this.setAngle(oItemWithXfs, 0);
    },
	_initXf: function(oItemWithXfs){
		var xfs = oItemWithXfs.xfs;
		if (!xfs) {
			if (oItemWithXfs.getDefaultXfs) {
				xfs = oItemWithXfs.getDefaultXfs();
			}
			if (!xfs) {
				xfs = this.oDefaultXfs;
			}
		}
		return xfs;
	},
	_initXfFont: function(xfs){
		xfs = xfs.clone();
		if(null == xfs.font){
			xfs.font = g_oDefaultFormat.Font;
		}
		xfs.font = xfs.font.clone();
		return xfs;
	},
	_initXfAlign: function(xfs){
		xfs = xfs.clone();
		if(null == xfs.align){
			xfs.align = g_oDefaultFormat.Align;
		}
		xfs.align = xfs.align.clone();
		return xfs;
	},
	_setProperty: function(oItemWithXfs, val, prop, getFunc, setFunc, addFunc) {
		var xfs = oItemWithXfs.xfs;
		var oRes = {newVal: null, oldVal: xfs ? getFunc.call(xfs) : null};
		xfs = this._initXf(oItemWithXfs);
		var hash = val && val.getHash ? val.getHash() : val;
		var xfsOperationCache = xfs;
		var newXf = xfs.getOperationCache(prop, hash);
		if (newXf) {
			oItemWithXfs.setStyleInternal(newXf);
			xfs = newXf;
		} else {
			xfs = xfs.clone();
			if (null != val) {
				if (addFunc) {
					setFunc.call(xfs, addFunc.call(g_StyleCache, val));
				} else {
					setFunc.call(xfs, val);
				}
			}
			else if (null != xfs) {
				setFunc.call(xfs, null);
			}

			xfs = g_StyleCache.addXf(xfs);
			xfsOperationCache.setOperationCache(prop, hash, xfs);
			oItemWithXfs.setStyleInternal(xfs);
		}
		oRes.newVal = xfs ? getFunc.call(xfs) : null;
		return oRes;
	},
	_setFontProperty : function(oItemWithXfs, val, prop, getFunc, setFunc)
	{
		var xfs = oItemWithXfs.xfs;
		var oRes = {newVal: val, oldVal: xfs && xfs.font ? getFunc.call(xfs.font): null};
		xfs = this._initXf(oItemWithXfs);
		var hash = val && val.getHash ? val.getHash() : val;
		var xfsOperationCache = xfs;
		var newXf = xfs.getOperationCache(prop, hash);
		if (newXf) {
			oItemWithXfs.setStyleInternal(newXf);
		} else {
			xfs = this._initXfFont(xfs);

			setFunc.call(xfs.font, val);
			xfs.font = g_StyleCache.addFont(xfs.font);

			xfs = g_StyleCache.addXf(xfs);
			xfsOperationCache.setOperationCache(prop, val, xfs);
			oItemWithXfs.setStyleInternal(xfs);
		}
		return oRes;
	},
	_setAlignProperty : function(oItemWithXfs, val, prop, getFunc, setFunc)
	{
		var xfs = oItemWithXfs.xfs;
		var oRes = {newVal: val, oldVal: xfs && xfs.align ? getFunc.call(xfs.align): getFunc.call(g_oDefaultFormat.Align)};
		xfs = this._initXf(oItemWithXfs);
		var xfsOperationCache = xfs;
		var newXf = xfs.getOperationCache(prop, val);
		if (newXf) {
			oItemWithXfs.setStyleInternal(newXf);
		} else {
			xfs = this._initXfAlign(xfs);

			setFunc.call(xfs.align, val);
			xfs.align = g_StyleCache.addAlign(xfs.align);

			xfs = g_StyleCache.addXf(xfs);
			xfsOperationCache.setOperationCache(prop, val, xfs);
			oItemWithXfs.setStyleInternal(xfs);
		}
		return oRes;
	}
};

	function StyleCache() {
		this.fonts = {count: 0, vals: {}};
		this.fills = {count: 0, vals: {}};
		this.borders = {count: 0, vals: {}};
		this.nums = {count: 0, vals: {}};
		this.aligns = {count: 0, vals: {}};
		this.xfs = {list: [], vals: {}};
	}

	StyleCache.prototype.addFont = function(newFont) {
		return this._add(this.fonts, newFont);
	};
	StyleCache.prototype.addFill = function(newFill) {
		return this._add(this.fills, newFill);
	};
	StyleCache.prototype.addBorder = function(newBorder) {
		return this._add(this.borders, newBorder);
	};
	StyleCache.prototype.addNum = function(newNum) {
		return this._add(this.nums, newNum);
	};
	StyleCache.prototype.addAlign = function(newAlign) {
		return this._add(this.aligns, newAlign);
	};
	StyleCache.prototype.addXf = function(newXf, recursively) {
		if (newXf) {
			if(newXf.font){
				newXf.font = this.addFont(newXf.font);
			}
			if(newXf.fill){
				newXf.fill = this.addFill(newXf.fill);
			}
			if(newXf.border){
				newXf.border = this.addBorder(newXf.border);
			}
			if(newXf.num){
				newXf.num = this.addNum(newXf.num);
			}
			if(newXf.align){
				newXf.align = this.addAlign(newXf.align);
			}
		}
		return this._add(this.xfs, newXf);
	};
	StyleCache.prototype.getXf = function(index) {
		return 1 <= index && index <= this.xfs.list.length ? this.xfs.list[index - 1] : null;
	};
	StyleCache.prototype.getXfCount = function() {
		return this.xfs.list.length;
	};
	StyleCache.prototype._add = function(container, newVal) {
		if (newVal && undefined === newVal.getIndexNumber()) {
			var hash = newVal.getHash();
			var res = container.vals[hash];
			if (!res) {
				if (container.list) {
					//index starts with 1
					newVal.setIndexNumber(container.list.push(newVal));
				} else {
					newVal.setIndexNumber(container.count++);
				}
				container.vals[hash] = newVal;
				res = newVal;
			}
			return res;
		} else {
			return newVal;
		}
	};
	var g_StyleCache = new StyleCache();

	/** @constructor */
	function SheetMergedStyles() {
		this.stylesTablePivot = [];
		this.stylesConditional = [];
	}

	SheetMergedStyles.prototype.setTablePivotStyle = function(range, xf, stripe) {
		this.stylesTablePivot.push({xf: xf, range: range, stripe: stripe, borders: undefined});
	};
	SheetMergedStyles.prototype.clearTablePivotStyle = function(range) {
		for (var i = this.stylesTablePivot.length - 1; i >= 0; --i) {
			var style = this.stylesTablePivot[i];
			if (style.range.isIntersect(range)) {
				this.stylesTablePivot.splice(i, 1);
			}
		}
	};
	SheetMergedStyles.prototype.setConditionalStyle = function(multiplyRange, formula) {
		this.stylesConditional.push({multiplyRange: multiplyRange, formula: formula});
	};
	SheetMergedStyles.prototype.clearConditionalStyle = function(multiplyRange) {
		for (var i = this.stylesConditional.length - 1; i >= 0; --i) {
			var style = this.stylesConditional[i];
			if (style.multiplyRange.isIntersect(multiplyRange)) {
				this.stylesConditional.splice(i, 1);
			}
		}
	};
	SheetMergedStyles.prototype.getStyle = function(hiddenManager, row, col, opt_ws) {
		var res = {table: [], conditional: []};
		if (opt_ws) {
			opt_ws._updateConditionalFormatting();
		}
		for (var i = 0; i < this.stylesConditional.length; ++i) {
			var style = this.stylesConditional[i];
			if (style.multiplyRange.contains(col, row)) {
				var xf = style.formula(row, col);
				if (xf) {
					res.conditional.push(xf);
				}
			}
		}
		for (var i = 0; i < this.stylesTablePivot.length; ++i) {
			var style = this.stylesTablePivot[i];
			var borderIndex;
			var xf = style.xf;
			if (style.range.contains(col, row) && (borderIndex = this._getBorderIndex(hiddenManager, style.range, style.stripe, row, col, xf)) >= 0) {
				if (borderIndex > 0) {
					if (!style.borders) {
						style.borders = {};
					}
					var xfModified = style.borders[borderIndex];
					if (!xfModified) {
						xfModified = xf.clone();
						var borderModified = xfModified.border.clone();
						if (0 !== (1 & borderIndex)) {
							borderModified.l = borderModified.iv;
						}
						if (0 !== (2 & borderIndex)) {
							borderModified.t = borderModified.ih;
						}
						if (0 !== (4 & borderIndex)) {
							borderModified.r = borderModified.iv;
						}
						if (0 !== (8 & borderIndex)) {
							borderModified.b = borderModified.ih;
						}
						if (0 !== (16 & borderIndex)) {
							borderModified.du = false;
							borderModified.dd = false;
						}
						xfModified.border = g_StyleCache.addBorder(borderModified);
						xfModified = g_StyleCache.addXf(xfModified);
						style.borders[borderIndex] = xfModified;
					}
					xf = xfModified;
				}
				res.table.push(xf);
			}
		}
		return res;
	};
	SheetMergedStyles.prototype._getBorderIndex = function(hiddenManager, bbox, stripe, row, col, xf) {
		var borderIndex = 0;
		var hidden;
		if (stripe) {
			if (stripe.row) {
				hidden = hiddenManager.getHiddenRowsCount(bbox.r1, row);
				var rowIndex = (row - bbox.r1 - hidden) % (stripe.size + stripe.offset);
				if (rowIndex < stripe.size) {
					if (xf.border) {
						if (bbox.c1 !== col && xf.border.l) {
							borderIndex += 1;
						}
						if (0 != rowIndex && xf.border.t) {
							borderIndex += 2;
						}
						if (bbox.c2 !== col && xf.border.r) {
							borderIndex += 4;
						}
						if (stripe.size - 1 != rowIndex && xf.border.b) {
							borderIndex += 8;
						}
					}
				} else {
					borderIndex = -1;
				}
			} else {
				hidden = hiddenManager.getHiddenColsCount(bbox.c1, col);
				var colIndex = (col - bbox.c1 - hidden) % (stripe.size + stripe.offset);
				if (colIndex < stripe.size) {
					if (xf.border) {
						if (0 != colIndex && xf.border.l) {
							borderIndex += 1;
						}
						if (bbox.r1 !== row && xf.border.t) {
							borderIndex += 2;
						}
						if (stripe.size - 1 != colIndex && xf.border.r) {
							borderIndex += 4;
						}
						if (bbox.r2 !== row && xf.border.b) {
							borderIndex += 8;
						}
					}
				} else {
					borderIndex = -1;
				}
			}
		} else if (xf.border) {
			if (bbox.c1 !== col && xf.border.l) {
				borderIndex += 1;
			}
			if (bbox.r1 !== row && xf.border.t) {
				borderIndex += 2;
			}
			if (bbox.c2 !== col && xf.border.r) {
				borderIndex += 4;
			}
			if (bbox.r2 !== row && xf.border.b) {
				borderIndex += 8;
			}
		}
		if (xf.border && (xf.border.du || xf.border.dd)) {
			borderIndex += 16;
		}
		return borderIndex;
	};
var g_oHyperlinkProperties = {
		Ref: 0,
		Location: 1,
		Hyperlink: 2,
		Tooltip: 3
	};
/** @constructor */
function Hyperlink () {
	this.Properties = g_oHyperlinkProperties;
    this.Ref = null;
    this.Hyperlink = null;
    this.Tooltip = null;
	// Составные части Location
	this.Location = null;
	this.LocationSheet = null;
	this.LocationRange = null;
	this.LocationRangeBbox = null;
	this.bUpdateLocation = false;
	
	this.bVisited = false;
}
Hyperlink.prototype = {
	clone : function (oNewWs) {
		var oNewHyp = new Hyperlink();
		if (null !== this.Ref)
			oNewHyp.Ref = this.Ref.clone(oNewWs);
		if (null !== this.getLocation())
			oNewHyp.setLocation(this.getLocation());
		if (null !== this.LocationSheet)
			oNewHyp.LocationSheet = this.LocationSheet;
		if (null !== this.LocationRange)
			oNewHyp.LocationRange = this.LocationRange;
		if (null !== this.LocationRangeBbox)
			oNewHyp.LocationRangeBbox = this.LocationRangeBbox.clone();
		if (null !== this.Hyperlink)
			oNewHyp.Hyperlink = this.Hyperlink;
		if (null !== this.Tooltip)
			oNewHyp.Tooltip = this.Tooltip;
		if (null !== this.bVisited)
			oNewHyp.bVisited = this.bVisited;
		return oNewHyp;
	},
	isEqual : function (obj) {
		var bRes = (this.getLocation() == obj.getLocation() && this.Hyperlink == obj.Hyperlink && this.Tooltip == obj.Tooltip);
		if (bRes) {
			var oBBoxRef = this.Ref.getBBox0();
			var oBBoxObj = obj.Ref.getBBox0();
			bRes = (oBBoxRef.r1 == oBBoxObj.r1 && oBBoxRef.c1 == oBBoxObj.c1 && oBBoxRef.r2 == oBBoxObj.r2 && oBBoxRef.c2 == oBBoxObj.c2);
		}
		return bRes;
	},
	isValid : function () {
		return null != this.Ref && (null != this.getLocation() || null != this.Hyperlink);
	},
	setLocationSheet : function (LocationSheet) {
		this.LocationSheet = LocationSheet;
		this.bUpdateLocation = true;
	},
	setLocationRange : function (LocationRange) {
		this.LocationRange = LocationRange;
		this.LocationRangeBbox = null;
		this.bUpdateLocation = true;
	},
	setLocation : function (Location) {
		this.bUpdateLocation = true;
		this.LocationSheet = this.LocationRange = this.LocationRangeBbox = null;

		if (null !== Location) {
			var result = parserHelp.parse3DRef(Location);
			if (!result) {
				// Can be in all mods. Excel bug...
				AscCommonExcel.executeInR1C1Mode(!AscCommonExcel.g_R1C1Mode, function () {
					result = parserHelp.parse3DRef(Location);
				});
			}
			if (null !== result) {
				this.LocationSheet = result.sheet;
				this.LocationRange = result.range;
			}
		}
		this._updateLocation();
	},
	getLocation : function () {
		if (this.bUpdateLocation)
			this._updateLocation();
		return this.Location;
	},
	getLocationRange : function () {
		return this.LocationRangeBbox && this.LocationRangeBbox.getName(AscCommonExcel.g_R1C1Mode ?
			AscCommonExcel.referenceType.A : AscCommonExcel.referenceType.R);
	},
	_updateLocation : function () {
		var t = this;
		this.Location = null;
		this.bUpdateLocation = false;
		if (null !== this.LocationSheet && null !== this.LocationRange) {
			this.LocationRangeBbox = AscCommonExcel.g_oRangeCache.getAscRange(this.LocationRange);
			if (!this.LocationRangeBbox) {
				// Can be in all mods. Excel bug...
				AscCommonExcel.executeInR1C1Mode(!AscCommonExcel.g_R1C1Mode, function () {
					t.LocationRangeBbox = AscCommonExcel.g_oRangeCache.getAscRange(t.LocationRange);
				});
			}
			if (this.LocationRangeBbox) {
				AscCommonExcel.executeInR1C1Mode(false, function () {
					t.LocationRange = t.LocationRangeBbox.getName(AscCommonExcel.referenceType.R);
				});
				this.Location = parserHelp.get3DRef(this.LocationSheet, this.LocationRange);
			}
		}
	},
	setVisited : function (bVisited) {
		this.bVisited = bVisited;
	},
	getVisited : function () {
		return this.bVisited;
	},
	getHyperlinkType : function () {
		return null !== this.Hyperlink ? Asc.c_oAscHyperlinkType.WebLink : Asc.c_oAscHyperlinkType.RangeLink;
	},
	getType : function () {
		return UndoRedoDataTypes.Hyperlink;
	},
	getProperties : function () {
		return this.Properties;
	},
	getProperty : function (nType) {
		switch (nType) {
			case this.Properties.Ref: return parserHelp.get3DRef(this.Ref.worksheet.getName(), this.Ref.getName()); break;
			case this.Properties.Location: return this.getLocation();break;
			case this.Properties.Hyperlink: return this.Hyperlink;break;
			case this.Properties.Tooltip: return this.Tooltip;break;
		}
	},
	setProperty : function (nType, value) {
		switch (nType) {
			case this.Properties.Ref:
				//todo обработать нули
				var oRefParsed = parserHelp.parse3DRef(value);
				if (null !== oRefParsed) {
					// Получаем sheet по имени
					var ws = window["Asc"]["editor"].wbModel.getWorksheetByName (oRefParsed.sheet);
					if (ws)
						this.Ref = ws.getRange2(oRefParsed.range);
				}
			break;
			case this.Properties.Location: this.setLocation(value);break;
			case this.Properties.Hyperlink: this.Hyperlink = value;break;
			case this.Properties.Tooltip: this.Tooltip = value;break;
		}
	},
	applyCollaborative : function (nSheetId, collaborativeEditing) {
		var bbox = this.Ref.getBBox0();
		var OffsetFirst = new AscCommon.CellBase(0, 0);
		var OffsetLast = new AscCommon.CellBase(0, 0);
		OffsetFirst.row = collaborativeEditing.getLockMeRow2(nSheetId, bbox.r1) - bbox.r1;
		OffsetFirst.col = collaborativeEditing.getLockMeColumn2(nSheetId, bbox.c1) - bbox.c1;
		OffsetLast.row = collaborativeEditing.getLockMeRow2(nSheetId, bbox.r2) - bbox.r2;
		OffsetLast.col = collaborativeEditing.getLockMeColumn2(nSheetId, bbox.c2) - bbox.c2;
		this.Ref.setOffsetFirst(OffsetFirst);
		this.Ref.setOffsetLast(OffsetLast);
	}
};
	/** @constructor */
	function SheetFormatPr() {
		this.nBaseColWidth = null;
		this.dDefaultColWidth = null;
		this.oAllRow = null;
	}
	SheetFormatPr.prototype.clone = function () {
		var oRes = new SheetFormatPr();
		oRes.nBaseColWidth = this.nBaseColWidth;
		oRes.dDefaultColWidth = this.dDefaultColWidth;
		if (null != this.oAllRow) {
			oRes.oAllRow = this.oAllRow.clone();
		}
		return oRes;
	};
	SheetFormatPr.prototype.correction = function () {
		if (null !== this.dDefaultColWidth && 0 > this.dDefaultColWidth) {
			this.dDefaultColWidth = null;
		}
	};
	/** @constructor */
	function Col(worksheet, index) {
		this.ws = worksheet;
		this.index = index;
		this.BestFit = null;
		this.hd = null;
		this.CustomWidth = null;
		this.width = null;
		this.xfs = null;

		this.widthPx = null;
		this.charCount = null;
	}

	Col.prototype.moveHor = function (nDif) {
		this.index += nDif;
	};
	Col.prototype.isEqual = function (obj) {
		var bRes = this.BestFit == obj.BestFit && this.hd == obj.hd && this.width == obj.width &&
			this.CustomWidth == obj.CustomWidth;
		if (bRes) {
			if (null != this.xfs && null != obj.xfs) {
				bRes = this.xfs.isEqual(obj.xfs);
			} else if (null != this.xfs ||
				null != obj.xfs) {
				bRes = false;
			}
		}
		return bRes;
	};
	Col.prototype.isEmpty = function () {
		return null == this.BestFit && null == this.hd && null == this.width && null == this.xfs &&
			null == this.CustomWidth;
	};
	Col.prototype.clone = function (oNewWs) {
		if (!oNewWs) {
			oNewWs = this.ws;
		}
		var oNewCol = new Col(oNewWs, this.index);
		if (null != this.BestFit) {
			oNewCol.BestFit = this.BestFit;
		}
		if (null != this.hd) {
			oNewCol.hd = this.hd;
		}
		if (null != this.width) {
			oNewCol.width = this.width;
		}
		if (null != this.CustomWidth) {
			oNewCol.CustomWidth = this.CustomWidth;
		}
		if (null != this.xfs) {
			oNewCol.xfs = this.xfs;
		}

		if (null != this.widthPx) {
			oNewCol.widthPx = this.widthPx;
		}
		if (null != this.charCount) {
			oNewCol.charCount = this.charCount;
		}
		return oNewCol;
	};
	Col.prototype.getWidthProp = function () {
		return new AscCommonExcel.UndoRedoData_ColProp(this);
	};
	Col.prototype.setWidthProp = function (prop) {
		if (null != prop) {
			if (null != prop.width) {
				this.width = prop.width;
			} else {
				this.width = null;
			}
			this.setHidden(prop.hd);
			if (null != prop.CustomWidth) {
				this.CustomWidth = prop.CustomWidth;
			} else {
				this.CustomWidth = null;
			}
			if (null != prop.BestFit) {
				this.BestFit = prop.BestFit;
			} else {
				this.BestFit = null;
			}
		}
	};
	Col.prototype.getStyle = function () {
		return this.xfs;
	};
	Col.prototype._getUpdateRange = function () {
		if (AscCommonExcel.g_nAllColIndex == this.index) {
			return new Asc.Range(0, 0, gc_nMaxCol0, gc_nMaxRow0);
		} else {
			return new Asc.Range(this.index, 0, this.index, gc_nMaxRow0);
		}
	};
	Col.prototype.setStyle = function (xfs) {
		var oldVal = this.xfs;
		this.setStyleInternal(xfs);
		if (History.Is_On() && oldVal !== this.xfs) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_SetStyle, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oldVal, this.xfs));
		}
	};
	Col.prototype.setStyleInternal = function (xfs) {
		this.xfs = g_StyleCache.addXf(xfs);
	};
	Col.prototype.setCellStyle = function (val) {
		var newVal = this.ws.workbook.CellStyles._prepareCellStyle(val);
		var oRes = this.ws.workbook.oStyleManager.setCellStyle(this, newVal);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			var oldStyleName = this.ws.workbook.CellStyles.getStyleNameByXfId(oRes.oldVal);
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_SetCellStyle, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oldStyleName, val));

			// Выставляем стиль
			var oStyle = this.ws.workbook.CellStyles.getStyleByXfId(oRes.newVal);
			if (oStyle.ApplyFont) {
				this.setFont(oStyle.getFont());
			}
			if (oStyle.ApplyFill) {
				this.setFill(oStyle.getFill());
			}
			if (oStyle.ApplyBorder) {
				this.setBorder(oStyle.getBorder());
			}
			if (oStyle.ApplyNumberFormat) {
				this.setNumFormat(oStyle.getNumFormatStr());
			}
		}
	};
	Col.prototype.setNumFormat = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setNum(this, new Num({f: val}));
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_Num, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setNum = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setNum(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_Num, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setFont = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setFont(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			var oldVal = null;
			if (null != oRes.oldVal) {
				oldVal = oRes.oldVal.clone();
			}
			var newVal = null;
			if (null != oRes.newVal) {
				newVal = oRes.newVal.clone();
			}
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_SetFont, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oldVal, newVal));
		}
	};
	Col.prototype.setFontname = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setFontname(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_Fontname, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setFontsize = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setFontsize(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_Fontsize, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setFontcolor = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setFontcolor(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_Fontcolor, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setBold = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setBold(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_Bold, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setItalic = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setItalic(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_Italic, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setUnderline = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setUnderline(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_Underline, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setStrikeout = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setStrikeout(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_Strikeout, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setFontAlign = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setFontAlign(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_FontAlign, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setAlignVertical = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setAlignVertical(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_AlignVertical, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setAlignHorizontal = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setAlignHorizontal(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_AlignHorizontal, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setFill = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setFill(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_Fill, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setBorder = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setBorder(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			var oldVal = null;
			if (null != oRes.oldVal) {
				oldVal = oRes.oldVal.clone();
			}
			var newVal = null;
			if (null != oRes.newVal) {
				newVal = oRes.newVal.clone();
			}
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_Border, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oldVal, newVal));
		}
	};
	Col.prototype.setShrinkToFit = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setShrinkToFit(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_ShrinkToFit, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setWrap = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setWrap(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_Wrap, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setAngle = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setAngle(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_Angle, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setVerticalText = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setVerticalText(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoCol, AscCH.historyitem_RowCol_Angle, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, false, oRes.oldVal, oRes.newVal));
		}
	};
	Col.prototype.setHidden = function (val) {
		if (this.index >= 0 && (!this.hd !== !val)) {
			this.ws.hiddenManager.addHidden(false, this.index);
		}
		this.hd = val;
	};
	Col.prototype.getHidden = function () {
		return true === this.hd;
	};
	Col.prototype.setIndex = function (val) {
		this.index = val;
	};
	Col.prototype.getIndex = function () {
		return this.index;
	};

	var g_nRowOffsetFlag = 0;
	var g_nRowOffsetXf = g_nRowOffsetFlag + 1;
	var g_nRowOffsetHeight = g_nRowOffsetXf + 4;
	var g_nRowStructSize = g_nRowOffsetHeight + 8;

	var g_nRowFlag_empty = 0;
	var g_nRowFlag_init = 1;
	var g_nRowFlag_hd = 2;
	var g_nRowFlag_CustomHeight = 4;
	var g_nRowFlag_CalcHeight = 8;
	var g_nRowFlag_NullHeight = 16;

	/**
	 * @constructor
	 */
	function Row(worksheet) {
		this.ws = worksheet;
		this.index = null;
		this.xfs = null;
		this.h = null;
		this.flags = g_nRowFlag_init;
		this._hasChanged = false;
	}
	Row.prototype.clear = function () {
		this.index = null;
		this.xfs = null;
		this.h = null;
		this.flags = g_nRowFlag_init;
		this._hasChanged = false;
	};
	Row.prototype.saveContent = function (opt_inCaseOfChange) {
		if (this.index >= 0 && (!opt_inCaseOfChange || this._hasChanged)) {
			this._hasChanged = false;
			var sheetMemory = this.ws.rowsData;
			sheetMemory.checkSize(this.index);
			var xfSave = this.xfs ? this.xfs.getIndexNumber() : 0;
			var flagToSave = this.flags;
			var heightToSave = this.h;
			if (null === heightToSave) {
				flagToSave |= g_nRowFlag_NullHeight;
				heightToSave = 0;
			}
			sheetMemory.setUint8(this.index, g_nRowOffsetFlag, flagToSave);
			sheetMemory.setUint32(this.index, g_nRowOffsetXf, xfSave);
			sheetMemory.setFloat64(this.index, g_nRowOffsetHeight, heightToSave);
		}
	};
	Row.prototype.loadContent = function (index) {
		var res = false;
		this.clear();
		this.index = index;
		var sheetMemory = this.ws.rowsData;
		if (sheetMemory.hasSize(this.index)) {
			this.flags = sheetMemory.getUint8(this.index, g_nRowOffsetFlag);
			if (0 != (g_nRowFlag_init & this.flags)) {
				this.xfs = g_StyleCache.getXf(sheetMemory.getUint32(this.index, g_nRowOffsetXf));
				if (0 !== (g_nRowFlag_NullHeight & this.flags)) {
					this.flags &= ~g_nRowFlag_NullHeight;
					this.h = null;
				} else {
					this.h = sheetMemory.getFloat64(this.index, g_nRowOffsetHeight);
				}
				res = true;
			}
		}
		return res;
	};
	Row.prototype.setChanged = function (val) {
		this._hasChanged = val;
	};
	Row.prototype.isEmpty = function () {
		return this.isEmptyProp();
	};
	Row.prototype.isEmptyProp = function () {
		//todo
		return null == this.xfs && null == this.h && g_nRowFlag_init == this.flags;
	};
	Row.prototype.clone = function (oNewWs, renameParams) {
		if (!oNewWs) {
			oNewWs = this.ws;
		}
		var oNewRow = new Row(oNewWs);
		oNewRow.index = this.index;
		oNewRow.flags = this.flags;
		if (null != this.xfs) {
			oNewRow.xfs = this.xfs;
		}
		if (null != this.h) {
			oNewRow.h = this.h;
		}
		return oNewRow;
	};
	Row.prototype.copyFrom = function (row) {
		this.flags = row.flags;
		if (null != row.xfs) {
			this.xfs = row.xfs;
		}
		if (null != row.h) {
			this.h = row.h;
		}
		this._hasChanged = true;
	};
	Row.prototype.getDefaultXfs = function () {
		var oRes = null;
		if (null != this.ws.oAllCol && null != this.ws.oAllCol.xfs) {
			oRes = this.ws.oAllCol.xfs.clone();
		}
		return oRes;
	};
	Row.prototype.getHeightProp = function () {
		return new AscCommonExcel.UndoRedoData_RowProp(this);
	};
	Row.prototype.setHeightProp = function (prop) {
		if (null != prop) {
			if (null != prop.h) {
				this.h = prop.h;
			} else {
				this.h = null;
			}
			this.setHidden(prop.hd);
			this.setCustomHeight(prop.CustomHeight);
		}
	};
	Row.prototype.getStyle = function () {
		return this.xfs;
	};
	Row.prototype._getUpdateRange = function () {
		if (AscCommonExcel.g_nAllRowIndex == this.index) {
			return new Asc.Range(0, 0, gc_nMaxCol0, gc_nMaxRow0);
		} else {
			return new Asc.Range(0, this.index, gc_nMaxCol0, this.index);
		}
	};
	Row.prototype.setStyle = function (xfs) {
		var oldVal = this.xfs;
		this.setStyleInternal(xfs);
		if (History.Is_On() && oldVal !== this.xfs) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_SetStyle, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oldVal, this.xfs));
		}
	};
	Row.prototype.setStyleInternal = function (xfs) {
		this.xfs = g_StyleCache.addXf(xfs);
		this._hasChanged = true;
	};
	Row.prototype.setCellStyle = function (val) {
		var newVal = this.ws.workbook.CellStyles._prepareCellStyle(val);
		var oRes = this.ws.workbook.oStyleManager.setCellStyle(this, newVal);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			var oldStyleName = this.ws.workbook.CellStyles.getStyleNameByXfId(oRes.oldVal);
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_SetCellStyle, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oldStyleName, val));

			// Выставляем стиль
			var oStyle = this.ws.workbook.CellStyles.getStyleByXfId(oRes.newVal);
			if (oStyle.ApplyFont) {
				this.setFont(oStyle.getFont());
			}
			if (oStyle.ApplyFill) {
				this.setFill(oStyle.getFill());
			}
			if (oStyle.ApplyBorder) {
				this.setBorder(oStyle.getBorder());
			}
			if (oStyle.ApplyNumberFormat) {
				this.setNumFormat(oStyle.getNumFormatStr());
			}
		}
	};
	Row.prototype.setNumFormat = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setNum(this, new Num({f: val}));
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_Num, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setNum = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setNum(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_Num, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setFont = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setFont(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			var oldVal = null;
			if (null != oRes.oldVal) {
				oldVal = oRes.oldVal.clone();
			}
			var newVal = null;
			if (null != oRes.newVal) {
				newVal = oRes.newVal.clone();
			}
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_SetFont, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oldVal, newVal));
		}
	};
	Row.prototype.setFontname = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setFontname(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_Fontname, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setFontsize = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setFontsize(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_Fontsize, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setFontcolor = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setFontcolor(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_Fontcolor, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setBold = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setBold(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_Bold, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setItalic = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setItalic(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_Italic, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setUnderline = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setUnderline(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_Underline, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setStrikeout = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setStrikeout(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_Strikeout, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setFontAlign = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setFontAlign(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_FontAlign, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setAlignVertical = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setAlignVertical(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_AlignVertical, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setAlignHorizontal = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setAlignHorizontal(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_AlignHorizontal, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setFill = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setFill(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_Fill, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setBorder = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setBorder(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			var oldVal = null;
			if (null != oRes.oldVal) {
				oldVal = oRes.oldVal.clone();
			}
			var newVal = null;
			if (null != oRes.newVal) {
				newVal = oRes.newVal.clone();
			}
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_Border, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oldVal, newVal));
		}
	};
	Row.prototype.setShrinkToFit = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setShrinkToFit(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_ShrinkToFit, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setWrap = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setWrap(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_Wrap, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setAngle = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setAngle(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_Angle, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setVerticalText = function (val) {
		var oRes = this.ws.workbook.oStyleManager.setVerticalText(this, val);
		if (History.Is_On() && oRes.oldVal != oRes.newVal) {
			History.Add(AscCommonExcel.g_oUndoRedoRow, AscCH.historyitem_RowCol_Angle, this.ws.getId(),
				this._getUpdateRange(), new UndoRedoData_IndexSimpleProp(this.index, true, oRes.oldVal, oRes.newVal));
		}
	};
	Row.prototype.setHidden = function (val) {
		if (this.index >= 0 && (!this.getHidden() !== !val)) {
			this.ws.hiddenManager.addHidden(true, this.index);
		}
		if (true === val) {
			this.flags |= g_nRowFlag_hd;
		} else {
			this.flags &= ~g_nRowFlag_hd;
		}
		this._hasChanged = true;
	};
	Row.prototype.getHidden = function () {
		return 0 !== (g_nRowFlag_hd & this.flags);
	};
	Row.prototype.setCustomHeight = function (val) {
		if (true === val) {
			this.flags |= g_nRowFlag_CustomHeight;
		} else {
			this.flags &= ~g_nRowFlag_CustomHeight;
		}
		this._hasChanged = true;
	};
	Row.prototype.getCustomHeight = function () {
		return 0 != (g_nRowFlag_CustomHeight & this.flags);
	};
	Row.prototype.setCalcHeight = function (val) {
		if (true === val) {
			this.flags |= g_nRowFlag_CalcHeight;
		} else {
			this.flags &= ~g_nRowFlag_CalcHeight;
		}
		this._hasChanged = true;
	};
	Row.prototype.getCalcHeight = function () {
		return 0 != (g_nRowFlag_CalcHeight & this.flags);
	};
	Row.prototype.setIndex = function (val) {
		this.index = val;
	};
	Row.prototype.getIndex = function () {
		return this.index;
	};
	Row.prototype.setHeight = function (val) {
		if (val < 0) {
			val = 0;
		} else if (val > Asc.c_oAscMaxRowHeight) {
			val = Asc.c_oAscMaxRowHeight;
		}
		this.h = val;
		this._hasChanged = true;
	};
	Row.prototype.getHeight = function () {
		return this.h;
	};

	function getStringFromMultiText(multiText) {
		var sRes = "";
		if (multiText) {
			for (var i = 0, length = multiText.length; i < length; ++i) {
				var elem = multiText[i];
				if (null != elem.text && !(elem.format && elem.format.getSkip())) {
					sRes += elem.text;
				}
			}
		}
		return sRes;
	}
	function isEqualMultiText(multiText1, multiText2) {
		var sRes = "";
		if (multiText1 && multiText2) {
			if (multiText1.length === multiText2.length) {
				for (var i = 0, length = multiText1.length; i < length; ++i) {
					var elem1 = multiText1[i];
					var elem2 = multiText2[i];
					if (!elem1.isEqual(elem2)) {
						return false;
					}
				}
				return true;
			} else {
				return false;
			}
		} else {
			return multiText1 === multiText2;
		}
	}
var g_oCMultiTextElemProperties = {
		text: 0,
		format: 1
	};
function CMultiTextElem() {
	this.text = null;
	this.format = null;
}
CMultiTextElem.prototype =
{
	Properties : g_oCMultiTextElemProperties,
	isEqual : function(val)
	{
		if(null == val)
			return false;
		return this.text == val.text && ((null == this.format && null == val.format) || (null != this.format && null != val.format && this.format.isEqual(val.format)));
	},
	clone : function()
	{
		var oRes = new CMultiTextElem();
		if(null != this.text)
			oRes.text = this.text;
		if(null != this.format)
			oRes.format = this.format.clone();
		return oRes;
	},
	getType : function()
	{
		return UndoRedoDataTypes.ValueMultiTextElem;
	},
	getProperties : function()
	{
		return this.Properties;
	},
	getProperty : function(nType)
	{
		switch(nType)
		{
			case this.Properties.text: return this.text;break;
			case this.Properties.format: return this.format;break;
		}
	},
	setProperty : function(nType, value)
	{
		switch(nType)
		{
			case this.Properties.text: this.text = value;break;
			case this.Properties.format: this.format = value;break;
		}
	}
};

var g_oCCellValueProperties = {
		text: 0,
		multiText: 1,
		number: 2,
		type: 3
	};

function CCellValue(opt_cell)
{
	if (opt_cell) {
		this.text = opt_cell.text;
		this.multiText = opt_cell.multiText;
		this.number = opt_cell.number;
		this.type = opt_cell.type;
	} else {
		this.text = null;
		this.multiText = null;
		this.number = null;
		this.type = CellValueType.Number;
	}
}
CCellValue.prototype = 
{
	Properties: g_oCCellValueProperties,
	isEqual : function(val)
	{
		if(null == val)
			return false;
		if(this.text != val.text)
			return false;
		if(this.number != val.number)
			return false;
		if(this.type != val.type)
			return false;
		if(null != this.multiText && null != val.multiText)
		{
			if(this.multiText.length == val.multiText.length)
			{
				for(var i = 0, length = this.multiText.length; i < length; ++i)
				{
					if(false == this.multiText[i].isEqual(val.multiText[i]))
						return false;
				}
				return true;
			}
			return false;
		}
		else if(null == this.multiText && null == val.multiText)
			return true;

		return false;
	},
	getType : function()
	{
		return UndoRedoDataTypes.CellValue;
	},
	getProperties : function()
	{
		return this.Properties;
	},
	getProperty : function(nType)
	{
		switch(nType)
		{
			case this.Properties.text: return this.text;break;
			case this.Properties.multiText: return this.multiText;break;
			case this.Properties.number: return this.number;break;
			case this.Properties.type: return this.type;break;
		}
	},
	setProperty : function(nType, value)
	{
		switch(nType)
		{
			case this.Properties.text: this.text = value;break;
			case this.Properties.multiText: this.multiText = value;break;
			case this.Properties.number: this.number = value;break;
			case this.Properties.type: this.type = value;break;
		}
	}
};

function TreeRBNode(key, storedValue){
	this.storedValue = storedValue;
	this.key = key;
	this.red = null;
	
	this.left = null;
	this.right = null;
	this.parent = null;
}
TreeRBNode.prototype = {
	constructor: TreeRBNode,
	isEqual : function(x){
		return this.key == x.key;
	}
};
/**
 *
 * @param low
 * @param high
 * @param storedValue
 * @constructor
 * @extends {TreeRBNode}
 */
function IntervalTreeRBNode(low, high, storedValue){
	TreeRBNode.call(this, low, storedValue);
	this.high = high;
	this.maxHigh = this.high;
	this.minLow = this.key;
}
IntervalTreeRBNode.prototype = Object.create(TreeRBNode.prototype);
IntervalTreeRBNode.prototype.constructor = IntervalTreeRBNode;
IntervalTreeRBNode.prototype.isEqual = function (x) {
	return this.key == x.key && this.high == x.high;
};
		
function TreeRB(){
	this.nil = null;
	this.root = null;
	this._init();
}
TreeRB.prototype = {
	constructor: TreeRB,
	_init : function(){
		this.nil = new TreeRBNode();
		this.nil.left = this.nil.right = this.nil.parent = this.nil;
		this.nil.key = -Number.MAX_VALUE;
		this.nil.red = 0;
		this.nil.storedValue = null;
		
		this.root = new TreeRBNode();
		this.root.left = this.nil.right = this.nil.parent = this.nil;
		this.root.key = Number.MAX_VALUE;
		this.root.red = 0;
		this.root.storedValue = null;
	},
	_treeInsertHelp : function(z){
		var oRes = z;
		z.left = z.right = this.nil;
		var y = this.root;
		var x = this.root.left;
		while(x != this.nil && !x.isEqual(z)){
			y = x;
			if(x.key > z.key)
				x = x.left;
			else
				x = x.right;
		}
		if(x == this.nil)
		{
			z.parent = y;
			if(y == this.root || y.key > z.key)
				y.left = z;
			else
				y.right = z;
		}
		else
			oRes = x;
		return oRes;
	},
	_fixUpMaxHigh : function(x){
	},
	_cleanMaxHigh : function(x){
	},
	_leftRotate : function(x){
		var y = x.right;
		x.right = y.left;
		if (y.left != this.nil)
			y.left.parent = x;
		y.parent = x.parent;
		if(x == x.parent.left){
			x.parent.left = y;
		}
		else{
			x.parent.right = y;
		}
		y.left = x;
		x.parent = y;
	},
	_rightRotate : function(y){
		var x = y.left;
		y.left = x.right;
		if(this.nil !=  x.right)
			x.right.parent = y;
		x.parent = y.parent;
		if(y == y.parent.left){
			y.parent.left = x;
		}
		else{
			y.parent.right = x;
		}
		x.right = y;
		y.parent = x;
	},
	insertOrGet : function(x){
		var y = null;
		var oRes = x;
		oRes = this._treeInsertHelp(x);
		if(x == oRes)
		{
			this._fixUpMaxHigh(x.parent);
			x.red = 1;
			while(x.parent.red)
			{
				if(x.parent == x.parent.parent.left){
					y = x.parent.parent.right;
					if(y.red){
						x.parent.red = 0;
						y.red = 0;
						x.parent.parent.red = 1;
						x = x.parent.parent;
					}
					else{
						if (x == x.parent.right) {
						  x = x.parent;
						  this._leftRotate(x);
						}
						x.parent.red=0;
						x.parent.parent.red=1;
						this._rightRotate(x.parent.parent);
					}
				}
				else{
					y = x.parent.parent.left;
					if (y.red){
						x.parent.red = 0;
						y.red = 0;
						x.parent.parent.red = 1;
						x = x.parent.parent;
					}
					else{
						if (x == x.parent.left) {
							x = x.parent;
							this._rightRotate(x);
						}
						x.parent.red = 0;
						x.parent.parent.red = 1;
						this._leftRotate(x.parent.parent);
					} 
				}
			}
			this.root.left.red = 0;
		}
		return oRes;
	},
	_getSuccessorOf : function(x){
		var y;
		if(this.nil != (y = x.right)){
			while(y.left != this.nil){
				y = y.left;
			}
			return(y);
		}
		else{
			y = x.parent;
			while(x == y.right) {
			  x = y;
			  y = y.parent;
			}
			if (y == this.root) return(this.nil);
			return(y);
		}
	},
	_deleteFixUp : function(x){
		var w;
		var rootLeft = this.root.left;
		
		while((!x.red) && (rootLeft != x)){
			if(x == x.parent.left){
				w = x.parent.right;
				if (w.red){
					w.red = 0;
					x.parent.red = 1;
					this._leftRotate(x.parent);
					w = x.parent.right;
				}
				if((!w.right.red) && (!w.left.red)){
					w.red = 1;
					x = x.parent;
				}
				else{
					if(!w.right.red){
						w.left.red = 0;
						w.red = 1;
						this._rightRotate(w);
						w = x.parent.right;
					}
					w.red = x.parent.red;
					x.parent.red = 0;
					w.right.red = 0;
					this._leftRotate(x.parent);
					x = rootLeft; /* this is to exit while loop */
				}
			}
			else{
				w = x.parent.left;
				if (w.red){
					w.red = 0;
					x.parent.red = 1;
					this._rightRotate(x.parent);
					w = x.parent.left;
				}
				if ( (!w.right.red) && (!w.left.red)){
					w.red = 1;
					x = x.parent;
				}
				else{
					if (!w.left.red) {
						w.right.red = 0;
						w.red = 1;
						this._leftRotate(w);
						w = x.parent.left;
					}
					w.red = x.parent.red;
					x.parent.red = 0;
					w.left.red = 0;
					this._rightRotate(x.parent);
					x = rootLeft; /* this is to exit while loop */
				}
			}
		}
		x.red=0;
	},
	deleteNode : function(z){
		var oRes = z.storedValue;
		var y = ((z.left == this.nil) || (z.right == this.nil)) ? z : this._getSuccessorOf(z);
		var x = (y.left == this.nil) ? y.right : y.left;
		if (this.root == (x.parent = y.parent)){
			this.root.left = x;
		}
		else{
			if (y == y.parent.left){
				y.parent.left = x;
			}
			else{
				y.parent.right = x;
			}
		}
		if (y != z){
			this._cleanMaxHigh(y);
			y.left = z.left;
			y.right = z.right;
			y.parent = z.parent;
			z.left.parent = z.right.parent = y;
			if (z == z.parent.left){
				z.parent.left = y; 
			}
			else{
				z.parent.right = y;
			}
			this._fixUpMaxHigh(x.parent); 
			if(!(y.red)){
				y.red = z.red;
				this._deleteFixUp(x);
			}
			else
				y.red = z.red; 
		}
		else{
			this._fixUpMaxHigh(x.parent);
			if (!(y.red))
				this._deleteFixUp(x);
		}
		return oRes;
	},
	_enumerateRecursion : function(low, high, x, enumResultStack){
		if(x != this.nil){
			if(low > x.key)
				this._enumerateRecursion(low, high, x.right, enumResultStack);
			else if(high < x.key)
				this._enumerateRecursion(low, high, x.left, enumResultStack);
			else
			{
				this._enumerateRecursion(low, high, x.left, enumResultStack);
				enumResultStack.push(x);
				this._enumerateRecursion(low, high, x.right, enumResultStack);
			}
		}
	},
	enumerate : function(low, high){
		var enumResultStack = [];
		if(low <= high)
			this._enumerateRecursion(low, high, this.root.left, enumResultStack);
		return enumResultStack;
	},
	getElem : function(val){
		var oRes = null;
		//todo переделать
		var aElems = this.enumerate(val, val);
		if(aElems.length > 0)
			oRes = aElems[0];
		return oRes;
	},
	getNodeAll : function(){
		return this.enumerate(-Number.MAX_VALUE, Number.MAX_VALUE);
	},
	isEmpty : function(){
		return this.nil == this.root.left;
	}
};

/**
 *
 * @constructor
 * @extends {TreeRB}
 */
function IntervalTreeRB(){
	TreeRB.call(this);
}
IntervalTreeRB.prototype = Object.create(TreeRB.prototype);
IntervalTreeRB.prototype.constructor = IntervalTreeRB;
IntervalTreeRB.prototype._init = function (x) {
	this.nil = new IntervalTreeRBNode();
	this.nil.left = this.nil.right = this.nil.parent = this.nil;
	this.nil.key = this.nil.high = this.nil.maxHigh = -Number.MAX_VALUE;
	this.nil.minLow = Number.MAX_VALUE;
	this.nil.red = 0;
	this.nil.storedValue = null;
	
	this.root = new IntervalTreeRBNode();
	this.root.left = this.nil.right = this.nil.parent = this.nil;
	this.root.key = this.root.high = this.root.maxHigh = Number.MAX_VALUE;
	this.root.minLow = -Number.MAX_VALUE;
	this.root.red = 0;
	this.root.storedValue = null;
};
IntervalTreeRB.prototype._fixUpMaxHigh = function (x) {
	while(x != this.root){
		x.maxHigh = Math.max(x.high, Math.max(x.left.maxHigh, x.right.maxHigh));
		x.minLow = Math.min(x.key, Math.min(x.left.minLow, x.right.minLow));
		x = x.parent;
	}
};
IntervalTreeRB.prototype._cleanMaxHigh = function (x) {
	x.maxHigh = -Number.MAX_VALUE;
	x.minLow = Number.MAX_VALUE;
};
IntervalTreeRB.prototype._overlap = function (a1, a2, b1, b2) {
	if (a1 <= b1){
		return ((b1 <= a2));
	}
	else{
		return ((a1 <= b2));
	}
};
IntervalTreeRB.prototype._enumerateRecursion = function (low, high, x, enumResultStack) {
	if(x != this.nil){
		if(this._overlap(low, high, x.minLow, x.maxHigh))
		{
			this._enumerateRecursion(low, high, x.left, enumResultStack);
			if (this._overlap(low, high, x.key, x.high))
				enumResultStack.push(x);
			this._enumerateRecursion(low, high, x.right, enumResultStack);
		}
	}
};
IntervalTreeRB.prototype._leftRotate = function (x) {
	var y = x.right;
	TreeRB.prototype._leftRotate.call(this, x);

	x.maxHigh = Math.max(x.left.maxHigh,Math.max(x.right.maxHigh,x.high));
	x.minLow = Math.min(x.left.minLow,Math.min(x.right.minLow,x.key));
	y.maxHigh = Math.max(x.maxHigh,Math.max(y.right.maxHigh,y.high));
	y.minLow = Math.min(x.minLow,Math.min(y.right.minLow,y.key));
};
IntervalTreeRB.prototype._rightRotate = function (y) {
	var x = y.left;
	TreeRB.prototype._rightRotate.call(this, y);
	
	y.maxHigh = Math.max(y.left.maxHigh,Math.max(y.right.maxHigh,y.high));
	y.minLow = Math.min(y.left.minLow,Math.min(y.right.minLow,y.key));
	x.maxHigh = Math.max(x.left.maxHigh,Math.max(y.maxHigh,x.high));
	x.minLow = Math.min(x.left.minLow,Math.min(y.minLow,y.key));
};
function RangeDataManagerElem(bbox, data)
{
	this.bbox = bbox;
	this.data = data;
}
function RangeDataManager(fChange)
{
	this.oIntervalTreeRB = new IntervalTreeRB();
	this.oDependenceManager = null;
	this.fChange = fChange;
}
RangeDataManager.prototype = {
    add: function (bbox, data, oChangeParam)
	{
		var oNewNode = new IntervalTreeRBNode(bbox.r1, bbox.r2, null);
		var oStoredNode = this.oIntervalTreeRB.insertOrGet(oNewNode);
		if(oStoredNode == oNewNode)
			oStoredNode.storedValue = [];
		var oNewElem = new RangeDataManagerElem(new Asc.Range(bbox.c1, bbox.r1, bbox.c2, bbox.r2), data);
		oStoredNode.storedValue.push(oNewElem);
		if(null != this.fChange)
		    this.fChange.call(this, oNewElem.data, null, oNewElem.bbox, oChangeParam);
	},
	get : function(bbox)
	{
		var oRes = {all: [], inner: [], outer: []};
		var oNodes = this.oIntervalTreeRB.enumerate(bbox.r1, bbox.r2);
		for(var i = 0, length = oNodes.length; i < length; i++)
		{
			var oNode = oNodes[i];
			if(oNode.storedValue)
			{
				for(var j = 0, length2 = oNode.storedValue.length; j < length2; j++)
				{
					var elem = oNode.storedValue[j];
					if(elem.bbox.isIntersect(bbox))
					{
						oRes.all.push(elem);
						if(bbox.containsRange(elem.bbox))
							oRes.inner.push(elem);
						else
							oRes.outer.push(elem);
					}
				}
			}
		}
		return oRes;
	},
	getExact : function(bbox)
	{
		var oRes = null;
		var oGet = this.get(bbox);
		for(var i = 0, length = oGet.inner.length; i < length; i++)
		{
			var elem = oGet.inner[i];
			if(elem.bbox.isEqual(bbox))
			{
				oRes = elem;
				break;
			}
		}
		return oRes;
	},
	_getByCell : function(nRow, nCol)
	{
		var oRes = null;
		var aAll = this.get(new Asc.Range(nCol, nRow, nCol, nRow));
		if(aAll.all.length > 0)
			oRes = aAll.all[0];
		return oRes;
	},
	getByCell : function(nRow, nCol)
	{
		var oRes = this._getByCell(nRow, nCol);
		if(null == oRes && null != this.oDependenceManager)
		{
			var oDependence = this.oDependenceManager._getByCell(nRow, nCol);
			if(null != oDependence)
			{
				var oTempRes = this.get(oDependence.bbox);
				if(oTempRes.all.length > 0)
					oRes = oTempRes.all[0];
			}
		}
		return oRes;
	},
	remove: function (bbox, bInnerOnly, oChangeParam)
	{
	    var aElems = this.get(bbox);
	    var aTargetArray;
	    if (bInnerOnly)
	        aTargetArray = aElems.inner;
	    else
	        aTargetArray = aElems.all;
	    for (var i = 0, length = aTargetArray.length; i < length; ++i)
		{
	        var elem = aTargetArray[i];
	        this.removeElement(elem, oChangeParam);
		}
	},
	removeElement: function (elemToDelete, oChangeParam)
	{
		if(null != elemToDelete)
		{
			var bbox = elemToDelete.bbox;
			var oNodes = this.oIntervalTreeRB.enumerate(bbox.r1, bbox.r2);
			for(var i = 0, length = oNodes.length; i < length; i++)
			{
				var oNode = oNodes[i];
				if(oNode.storedValue)
				{
					for(var j = 0, length2 = oNode.storedValue.length; j < length2; j++)
					{
						var elem = oNode.storedValue[j];
						if(elem.bbox.isEqual(bbox))
						{
							oNode.storedValue.splice(j, 1);
							break;
						}
					}
					if(0 == oNode.storedValue.length)
						this.oIntervalTreeRB.deleteNode(oNode);
				}
			}
			if(null != this.fChange)
			    this.fChange.call(this, elemToDelete.data, elemToDelete.bbox, null, oChangeParam);
		}
	},
	removeAll : function(oChangeParam)
	{
	    this.remove(new Asc.Range(0, 0, gc_nMaxCol0, gc_nMaxRow0), null, oChangeParam);
		//todo
		this.oIntervalTreeRB = new IntervalTreeRB();
	},
	shiftGet : function(bbox, bHor)
	{
		var bboxGet = shiftGetBBox(bbox, bHor);
		return {bbox: bboxGet, elems: this.get(bboxGet)};
	},
	shift: function (bbox, bAdd, bHor, oGetRes, oChangeParam)
	{
	    var _this = this;
	    if (null == oGetRes)
	        oGetRes = this.shiftGet(bbox, bHor);
	    var offset;
	    if (bHor)
	        offset = new AscCommon.CellBase(0, bbox.c2 - bbox.c1 + 1);
	    else
	        offset = new AscCommon.CellBase(bbox.r2 - bbox.r1 + 1, 0);
	    if (!bAdd) {
	        offset.row *= -1;
	        offset.col *= -1;
	    }
	    this._shiftmove(true, bbox, offset, oGetRes.elems, oChangeParam);
	},
	move: function (from, to, oChangeParam)
	{
	    var offset = new AscCommon.CellBase(to.r1 - from.r1, to.c1 - from.c1);
	    var oGetRes = this.get(from);
	    this._shiftmove(false, from, offset, oGetRes, oChangeParam);
	},
	_shiftmove: function (bShift, bbox, offset, elems, oChangeParam) {
	    var aToChange = [];
	    var bAdd = offset.row > 0 || offset.col > 0;
	    var bHor = 0 != offset.col ? true : false;
	    //сдвигаем inner
	    if (elems.inner.length > 0) {
	        var bboxAsc = Asc.Range(bbox.c1, bbox.r1, bbox.c2, bbox.r2);
	        for (var i = 0, length = elems.inner.length; i < length; i++) {
	            var elem = elems.inner[i];
	            var from = elem.bbox;
	            var to = null;
	            if (bShift) {
	                if (bAdd) {
	                    to = from.clone();
	                    to.setOffset(offset);
	                }
	                else if (!bboxAsc.containsRange(from)) {
	                    to = from.clone();
	                    if (bHor) {
	                        if (to.c1 <= bbox.c2)
	                            to.setOffsetFirst(new AscCommon.CellBase(0,  bbox.c2 - to.c1 + 1));
	                    }
	                    else {
	                        if (to.r1 <= bbox.r2)
	                            to.setOffsetFirst(new AscCommon.CellBase(bbox.r2 - to.r1 + 1, 0));
	                    }
	                    to.setOffset(offset);
	                }
	            }
	            else {
	                to = from.clone();
	                to.setOffset(offset);
	            }
	            aToChange.push({ elem: elem, to: to });
	        }
	    }
	    //меняем outer
	    if (bShift) {
	        if (elems.outer.length > 0) {
	            for (var i = 0, length = elems.outer.length; i < length; i++) {
	                var elem = elems.outer[i];
	                var from = elem.bbox;
	                var to = null;
	                if (bHor) {
	                    if (from.c1 < bbox.c1 && bbox.r1 <= from.r1 && from.r2 <= bbox.r2) {
	                        if (bAdd) {
	                            to = from.clone();
	                            to.setOffsetLast(new AscCommon.CellBase(0, bbox.c2 - bbox.c1 + 1));
	                        }
	                        else {
	                            to = from.clone();
	                            var nTemp1 = from.c2 - bbox.c1 + 1;
	                            var nTemp2 = bbox.c2 - bbox.c1 + 1;
	                            to.setOffsetLast(new AscCommon.CellBase(0, -Math.min(nTemp1, nTemp2)));
	                        }
	                    }
	                }
	                else {
	                    if (from.r1 < bbox.r1 && bbox.c1 <= from.c1 && from.c2 <= bbox.c2) {
	                        if (bAdd) {
	                            to = from.clone();
	                            to.setOffsetLast(new AscCommon.CellBase(bbox.r2 - bbox.r1 + 1, 0));
	                        }
	                        else {
	                            to = from.clone();
	                            var nTemp1 = from.r2 - bbox.r1 + 1;
	                            var nTemp2 = bbox.r2 - bbox.r1 + 1;
	                            to.setOffsetLast(new AscCommon.CellBase(-Math.min(nTemp1, nTemp2), 0));
	                        }
	                    }
	                }
	                if (null != to)
	                    aToChange.push({ elem: elem, to: to });
	            }
	        }
	    }
	    //сначала сортируем чтобы не было конфликтов при сдвиге
	    aToChange.sort(function (a, b) { return shiftSort(a, b, offset); });

	    if (null != this.fChange) {
	        for (var i = 0, length = aToChange.length; i < length; ++i) {
	            var item = aToChange[i];
	            this.fChange.call(this, item.elem.data, item.elem.bbox, item.to, oChangeParam);
	        }
	    }
	    //убираем fChange, чтобы потом послать его только на одну операцию, а не 2
	    var fOldChange = this.fChange;
	    this.fChange = null;
	    //сначала удаляем все чтобы не было конфликтов
	    for (var i = 0, length = aToChange.length; i < length; ++i) {
	        var item = aToChange[i];
	        var elem = item.elem;
	        this.removeElement(elem, oChangeParam);
	    }
	    //добавляем измененные ячейки
	    for (var i = 0, length = aToChange.length; i < length; ++i) {
	        var item = aToChange[i];
	        if (null != item.to)
	            this.add(item.to, item.elem.data, oChangeParam);
	    }
	    this.fChange = fOldChange;
	},
	getAll : function()
	{
		var aRes = [];
		var oNodes = this.oIntervalTreeRB.getNodeAll();
		for(var i = 0, length = oNodes.length; i < length; i++)
		{
			var oNode = oNodes[i];
			if(oNode.storedValue)
			{
				for(var j = 0, length2 = oNode.storedValue.length; j < length2; j++)
				{
					var elem = oNode.storedValue[j];
					aRes.push(elem);
				}
			}
		}
		return aRes;
	},
	setDependenceManager : function(oDependenceManager)
	{
		this.oDependenceManager = oDependenceManager;
	}
};

	/** @constructor */
	function sparklineGroup(addId) {
		// attributes
		this.type = null;
		this.lineWeight = null;
		this.displayEmptyCellsAs = null;
		this.markers = null;
		this.high = null;
		this.low = null;
		this.first = null;
		this.last = null;
		this.negative = null;
		this.displayXAxis = null;
		this.displayHidden = null;
		this.minAxisType = null;
		this.maxAxisType = null;
		this.rightToLeft = null;
		this.manualMax = null;
		this.manualMin = null;

		this.dateAxis = null;

		// elements
		this.colorSeries = null;
		this.colorNegative = null;
		this.colorAxis = null;
		this.colorMarkers = null;
		this.colorFirst = null;
		this.colorLast = null;
		this.colorHigh = null;
		this.colorLow = null;

		this.f = null;
		this.arrSparklines = [];

		//for drawing preview
		this.canvas = null;

		this.worksheet = null;
		this.Id = null;
		if (addId) {
			this.Id = AscCommon.g_oIdCounter.Get_NewId();
			AscCommon.g_oTableId.Add(this, this.Id);
		}
	}
	sparklineGroup.prototype.getObjectType = function () {
		return AscDFH.historyitem_type_Sparkline;
	};
	sparklineGroup.prototype.Get_Id = function () {
		return this.Id;
	};
	sparklineGroup.prototype.Write_ToBinary2 = function (w) {
		w.WriteLong(this.getObjectType());
		w.WriteString2(this.Id);
		w.WriteString2(this.worksheet ? this.worksheet.getId() : '-1');
	};
	sparklineGroup.prototype.Read_FromBinary2 = function (r) {
		this.Id = r.GetString2();

		// ToDDo не самая лучшая схема добавления на лист...
		var api_sheet = Asc['editor'];
		this.worksheet = api_sheet.wbModel.getWorksheetById(r.GetString2());
		if (this.worksheet) {
			this.worksheet.insertSparklineGroup(this);
		}
	};
	sparklineGroup.prototype.default = function () {
		this.type = Asc.c_oAscSparklineType.Line;
		this.lineWeight = 0.75;
		this.displayEmptyCellsAs = Asc.c_oAscEDispBlanksAs.Zero;
		this.markers = false;
		this.high = false;
		this.low = false;
		this.first = false;
		this.last = false;
		this.negative = false;
		this.displayXAxis = false;
		this.displayHidden = false;
		this.minAxisType = Asc.c_oAscSparklineAxisMinMax.Individual;
		this.maxAxisType = Asc.c_oAscSparklineAxisMinMax.Individual;
		this.rightToLeft = false;
		this.manualMax = null;
		this.manualMin = null;
		this.dateAxis = false;

		// elements
		var defaultSeriesColor = 3629202;
		var defaultOtherColor = 13631488;

		this.colorSeries = new RgbColor(defaultSeriesColor);
		this.colorNegative = new RgbColor(defaultOtherColor);
		this.colorAxis = new RgbColor(defaultOtherColor);
		this.colorMarkers = new RgbColor(defaultOtherColor);
		this.colorFirst = new RgbColor(defaultOtherColor);
		this.colorLast = new RgbColor(defaultOtherColor);
		this.colorHigh = new RgbColor(defaultOtherColor);
		this.colorLow = new RgbColor(defaultOtherColor);
	};
	sparklineGroup.prototype.setWorksheet = function (worksheet, oldWorksheet) {
		this.worksheet = worksheet;
		if (oldWorksheet) {
			var oldSparklines = [];
			var newSparklines = [];
			for (var i = 0; i < this.arrSparklines.length; ++i) {
				oldSparklines.push(this.arrSparklines[i].clone());
				this.arrSparklines[i].updateWorksheet(worksheet.sName, oldWorksheet.sName);
				newSparklines.push(this.arrSparklines[i].clone());
			}
			History.Add(new AscDFH.CChangesSparklinesChangeData(this, oldSparklines, newSparklines));
		}
	};

    sparklineGroup.prototype.checkProperty = function (propOld, propNew, type, fChangeConstructor) {
        if (null !== propNew && propOld !== propNew) {
            History.Add(new fChangeConstructor(this, type, propOld, propNew));
            return propNew;
        }
        return propOld;
    };

	sparklineGroup.prototype.set = function (val) {
		var getColor = function (color) {
			return color instanceof Asc.asc_CColor ? CorrectAscColor(color) : color ? color.clone(): color;
		};

		this.type = this.checkProperty(this.type, val.type, AscDFH.historyitem_Sparkline_Type, AscDFH.CChangesDrawingsLong);
		this.lineWeight = this.checkProperty(this.lineWeight, val.lineWeight, AscDFH.historyitem_Sparkline_LineWeight, AscDFH.CChangesDrawingsDouble);
		this.displayEmptyCellsAs = this.checkProperty(this.displayEmptyCellsAs, val.displayEmptyCellsAs, AscDFH.historyitem_Sparkline_DisplayEmptyCellsAs, AscDFH.CChangesDrawingsLong);
		this.markers = this.checkProperty(this.markers, val.markers, AscDFH.historyitem_Sparkline_Markers, AscDFH.CChangesDrawingsBool);
		this.high = this.checkProperty(this.high, val.high, AscDFH.historyitem_Sparkline_High, AscDFH.CChangesDrawingsBool);
		this.low = this.checkProperty(this.low, val.low, AscDFH.historyitem_Sparkline_Low, AscDFH.CChangesDrawingsBool);
		this.first = this.checkProperty(this.first, val.first, AscDFH.historyitem_Sparkline_First, AscDFH.CChangesDrawingsBool);
		this.last = this.checkProperty(this.last, val.last, AscDFH.historyitem_Sparkline_Last, AscDFH.CChangesDrawingsBool);
		this.negative = this.checkProperty(this.negative, val.negative, AscDFH.historyitem_Sparkline_Negative, AscDFH.CChangesDrawingsBool);
		this.displayXAxis = this.checkProperty(this.displayXAxis, val.displayXAxis, AscDFH.historyitem_Sparkline_DisplayXAxis, AscDFH.CChangesDrawingsBool);
		this.displayHidden = this.checkProperty(this.displayHidden, val.displayHidden, AscDFH.historyitem_Sparkline_DisplayHidden, AscDFH.CChangesDrawingsBool);
		this.minAxisType = this.checkProperty(this.minAxisType, val.minAxisType, AscDFH.historyitem_Sparkline_MinAxisType, AscDFH.CChangesDrawingsLong);
		this.maxAxisType = this.checkProperty(this.maxAxisType, val.maxAxisType, AscDFH.historyitem_Sparkline_MaxAxisType, AscDFH.CChangesDrawingsLong);
		this.rightToLeft = this.checkProperty(this.rightToLeft, val.rightToLeft, AscDFH.historyitem_Sparkline_RightToLeft, AscDFH.CChangesDrawingsBool);
		this.manualMax = this.checkProperty(this.manualMax, val.manualMax, AscDFH.historyitem_Sparkline_ManualMax, AscDFH.CChangesDrawingsDouble);
		this.manualMin = this.checkProperty(this.manualMin, val.manualMin, AscDFH.historyitem_Sparkline_ManualMin, AscDFH.CChangesDrawingsDouble);
		this.dateAxis = this.checkProperty(this.dateAxis, val.dateAxis, AscDFH.historyitem_Sparkline_DateAxis, AscDFH.CChangesDrawingsBool);

		this.colorSeries = this.checkProperty(this.colorSeries, getColor(val.colorSeries), AscDFH.historyitem_Sparkline_ColorSeries, AscDFH.CChangesDrawingsExcelColor);
		this.colorNegative = this.checkProperty(this.colorNegative, getColor(val.colorNegative), AscDFH.historyitem_Sparkline_ColorNegative, AscDFH.CChangesDrawingsExcelColor);
		this.colorAxis = this.checkProperty(this.colorAxis, getColor(val.colorAxis), AscDFH.historyitem_Sparkline_ColorAxis, AscDFH.CChangesDrawingsExcelColor);
		this.colorMarkers = this.checkProperty(this.colorMarkers, getColor(val.colorMarkers), AscDFH.historyitem_Sparkline_ColorMarkers, AscDFH.CChangesDrawingsExcelColor);
		this.colorFirst = this.checkProperty(this.colorFirst, getColor(val.colorFirst), AscDFH.historyitem_Sparkline_ColorFirst, AscDFH.CChangesDrawingsExcelColor);
		this.colorLast = this.checkProperty(this.colorLast, getColor(val.colorLast), AscDFH.historyitem_Sparkline_colorLast, AscDFH.CChangesDrawingsExcelColor);
		this.colorHigh = this.checkProperty(this.colorHigh, getColor(val.colorHigh), AscDFH.historyitem_Sparkline_ColorHigh, AscDFH.CChangesDrawingsExcelColor);
		this.colorLow = this.checkProperty(this.colorLow, getColor(val.colorLow), AscDFH.historyitem_Sparkline_ColorLow, AscDFH.CChangesDrawingsExcelColor);

		this.f = this.checkProperty(this.f, val.f, AscDFH.historyitem_Sparkline_F, AscDFH.CChangesDrawingsString);

		this.cleanCache();
	};
	sparklineGroup.prototype.clone = function (onlyProps) {
		var res = new sparklineGroup(!onlyProps);
		res.set(this);
		res.f = this.f;

		if (!onlyProps) {
			var newSparklines = [];
			for (var i = 0; i < this.arrSparklines.length; ++i) {
				res.arrSparklines.push(this.arrSparklines[i].clone());
				newSparklines.push(this.arrSparklines[i].clone());
			}
			History.Add(new AscDFH.CChangesSparklinesChangeData(res, null, newSparklines));
		}

		return res;
	};
	sparklineGroup.prototype.draw = function (oDrawingContext) {
		var oCacheView;
		var graphics = new AscCommon.CGraphics();
		graphics.init(oDrawingContext.ctx, oDrawingContext.getWidth(0), oDrawingContext.getHeight(0),
			oDrawingContext.getWidth(3), oDrawingContext.getHeight(3));
		graphics.m_oFontManager = AscCommon.g_fontManager;
		for (var i = 0; i < this.arrSparklines.length; ++i) {
			if (oCacheView = this.arrSparklines[i].oCacheView) {
				oCacheView.draw(graphics);
			}
		}
	};
	sparklineGroup.prototype.cleanCache = function () {
		// ToDo clean only colors (for color scheme)
		for (var i = 0; i < this.arrSparklines.length; ++i) {
			this.arrSparklines[i].oCacheView = null;
		}
	};
	sparklineGroup.prototype.updateCache = function (sheet, ranges) {
		var sparklineRange;
		for (var i = 0; i < this.arrSparklines.length; ++i) {
			sparklineRange = this.arrSparklines[i]._f;
			if (sparklineRange) {
				for (var j = 0; j < ranges.length; ++j) {
					if (sparklineRange.isIntersect(ranges[j], sheet)) {
						this.arrSparklines[i].oCacheView = null;
						break;
					}
				}
			}
		}
	};
	sparklineGroup.prototype.contains = function (c, r) {
		for (var j = 0; j < this.arrSparklines.length; ++j) {
			if (this.arrSparklines[j].contains(c, r)) {
				return j;
			}
		}
		return -1;
	};
	sparklineGroup.prototype.intersectionSimple = function (range) {
		for (var j = 0; j < this.arrSparklines.length; ++j) {
			if (this.arrSparklines[j].intersectionSimple(range)) {
				return j;
			}
		}
		return -1;
	};
	sparklineGroup.prototype.remove = function (range) {
		for (var i = 0; i < this.arrSparklines.length; ++i) {
			if (this.arrSparklines[i].checkInRange(range)) {
				History.Add(new AscDFH.CChangesSparklinesRemoveData(this, this.arrSparklines[i]));
				this.arrSparklines.splice(i, 1);
				--i;
			}
		}
		var bRemove = (0 === this.arrSparklines.length);
		return bRemove;
	};
	sparklineGroup.prototype.getLocationRanges = function (onlySingle) {
		var result = new AscCommonExcel.SelectionRange();
		this.arrSparklines.forEach(function (item, i) {
			if (0 === i) {
				result.assign2(item.sqref);
			} else {
				result.addRange();
				result.getLast().assign2(item.sqref);
			}
		});
		var unionRange = result.getUnion();
		return (!onlySingle || unionRange.isSingleRange()) ? unionRange : result;
	};
	sparklineGroup.prototype.getDataRanges = function () {
		var isUnion = true;
		var sheet = this.worksheet.getName();
		var result = new AscCommonExcel.SelectionRange();
		this.arrSparklines.forEach(function (item, i) {
			if (item._f) {
				isUnion = isUnion && sheet === item._f.sheet;
				if (0 === i) {
					result.assign2(item._f);
				} else {
					result.addRange();
					result.getLast().assign2(item._f);
				}
			} else {
				isUnion = false;
			}
		});
		var unionRange = isUnion ? result.getUnion() : result;
		return unionRange.isSingleRange() ? unionRange : result;
	};
	sparklineGroup.prototype.asc_getId = function () {
		return this.Id;
	};
	sparklineGroup.prototype.asc_getType = function () {
		return null !== this.type ? this.type : Asc.c_oAscSparklineType.Line;
	};
	sparklineGroup.prototype.asc_getLineWeight = function () {
		return null !== this.lineWeight ? this.lineWeight : 0.75;
	};
	sparklineGroup.prototype.asc_getDisplayEmpty = function () {
		return null !== this.displayEmptyCellsAs ? this.displayEmptyCellsAs : Asc.c_oAscEDispBlanksAs.Zero;
	};
	sparklineGroup.prototype.asc_getMarkersPoint = function () {
		return !!this.markers;
	};
	sparklineGroup.prototype.asc_getHighPoint = function () {
		return !!this.high;
	};
	sparklineGroup.prototype.asc_getLowPoint = function () {
		return !!this.low;
	};
	sparklineGroup.prototype.asc_getFirstPoint = function () {
		return !!this.first;
	};
	sparklineGroup.prototype.asc_getLastPoint = function () {
		return !!this.last;
	};
	sparklineGroup.prototype.asc_getNegativePoint = function () {
		return !!this.negative;
	};
	sparklineGroup.prototype.asc_getDisplayXAxis = function () {
		return this.displayXAxis;
	};
	sparklineGroup.prototype.asc_getDisplayHidden = function () {
		return this.displayHidden;
	};
	sparklineGroup.prototype.asc_getMinAxisType = function () {
		return null !== this.minAxisType ? this.minAxisType : Asc.c_oAscSparklineAxisMinMax.Individual;
	};
	sparklineGroup.prototype.asc_getMaxAxisType = function () {
		return null !== this.maxAxisType ? this.maxAxisType : Asc.c_oAscSparklineAxisMinMax.Individual;
	};
	sparklineGroup.prototype.asc_getRightToLeft = function () {
		return this.rightToLeft;
	};
	sparklineGroup.prototype.asc_getManualMax = function () {
		return this.manualMax;
	};
	sparklineGroup.prototype.asc_getManualMin = function () {
		return this.manualMin;
	};
	sparklineGroup.prototype.asc_getColorSeries = function () {
		return this.colorSeries ? Asc.colorObjToAscColor(this.colorSeries) : this.colorSeries;
	};
	sparklineGroup.prototype.asc_getColorNegative = function () {
		return this.colorNegative ? Asc.colorObjToAscColor(this.colorNegative) : this.colorNegative;
	};
	sparklineGroup.prototype.asc_getColorAxis = function () {
		return this.colorAxis ? Asc.colorObjToAscColor(this.colorAxis) : this.colorAxis;
	};
	sparklineGroup.prototype.asc_getColorMarkers = function () {
		return this.colorMarkers ? Asc.colorObjToAscColor(this.colorMarkers) : this.colorMarkers;
	};
	sparklineGroup.prototype.asc_getColorFirst = function () {
		return this.colorFirst ? Asc.colorObjToAscColor(this.colorFirst) : this.colorFirst;
	};
	sparklineGroup.prototype.asc_getColorLast = function () {
		return this.colorLast ? Asc.colorObjToAscColor(this.colorLast) : this.colorLast;
	};
	sparklineGroup.prototype.asc_getColorHigh = function () {
		return this.colorHigh ? Asc.colorObjToAscColor(this.colorHigh) : this.colorHigh;
	};
	sparklineGroup.prototype.asc_getColorLow = function () {
		return this.colorLow ? Asc.colorObjToAscColor(this.colorLow) : this.colorLow;
	};
	sparklineGroup.prototype.asc_getDataRanges = function () {
		var arrResultData = [];
		var arrResultLocation = [];
		var oLocationRanges = this.getLocationRanges(true);
		var oDataRanges = oLocationRanges.isSingleRange() && this.getDataRanges();
		if (oLocationRanges.isSingleRange() && oDataRanges.isSingleRange()) {
			for (var i = 0; i < oLocationRanges.ranges.length; ++i) {
				arrResultData.push(oDataRanges.ranges[i].getName());
				arrResultLocation.push(oLocationRanges.ranges[i].getAbsName());
			}
		} else {
			this.arrSparklines.forEach(function (item) {
				arrResultData.push(item.f || cErrorOrigin['ref']);
				arrResultLocation.push(item.sqref.getAbsName());
			});
		}
		return [arrResultData.join(AscCommon.FormulaSeparators.functionArgumentSeparator),
			arrResultLocation.join(AscCommon.FormulaSeparators.functionArgumentSeparator)];
	};
	sparklineGroup.prototype.asc_setType = function (val) {
		this.type = val;
	};
	sparklineGroup.prototype.asc_setLineWeight = function (val) {
		this.lineWeight = val;
	};
	sparklineGroup.prototype.asc_setDisplayEmpty = function (val) {
		this.displayEmptyCellsAs = val;
	};
	sparklineGroup.prototype.asc_setMarkersPoint = function (val) {
		this.markers = val;
	};
	sparklineGroup.prototype.asc_setHighPoint = function (val) {
		this.high = val;
	};
	sparklineGroup.prototype.asc_setLowPoint = function (val) {
		this.low = val;
	};
	sparklineGroup.prototype.asc_setFirstPoint = function (val) {
		this.first = val;
	};
	sparklineGroup.prototype.asc_setLastPoint = function (val) {
		this.last = val;
	};
	sparklineGroup.prototype.asc_setNegativePoint = function (val) {
		this.negative = val;
	};
	sparklineGroup.prototype.asc_setDisplayXAxis = function (val) {
		this.displayXAxis = val;
	};
	sparklineGroup.prototype.asc_setDisplayHidden = function (val) {
		this.displayHidden = val;
	};
	sparklineGroup.prototype.asc_setMinAxisType = function (val) {
		this.minAxisType = val;
	};
	sparklineGroup.prototype.asc_setMaxAxisType = function (val) {
		this.maxAxisType = val;
	};
	sparklineGroup.prototype.asc_setRightToLeft = function (val) {
		this.rightToLeft = val;
	};
	sparklineGroup.prototype.asc_setManualMax = function (val) {
		this.manualMax = val;
	};
	sparklineGroup.prototype.asc_setManualMin = function (val) {
		this.manualMin = val;
	};
	sparklineGroup.prototype.asc_setColorSeries = function (val) {
		this.colorSeries = val;
	};
	sparklineGroup.prototype.asc_setColorNegative = function (val) {
		this.colorNegative = val;
	};
	sparklineGroup.prototype.asc_setColorAxis = function (val) {
		this.colorAxis = val;
	};
	sparklineGroup.prototype.asc_setColorMarkers = function (val) {
		this.colorMarkers = val;
	};
	sparklineGroup.prototype.asc_setColorFirst = function (val) {
		this.colorFirst = val;
	};
	sparklineGroup.prototype.asc_setColorLast = function (val) {
		this.colorLast = val;
	};
	sparklineGroup.prototype.asc_setColorHigh = function (val) {
		this.colorHigh = val;
	};
	sparklineGroup.prototype.asc_setColorLow = function (val) {
		this.colorLow = val;
	};

	sparklineGroup.prototype.createExcellColor = function(aColor) {
		var oExcellColor = null;
		if(Array.isArray(aColor)) {
			if(2 === aColor.length){
				oExcellColor = AscCommonExcel.g_oColorManager.getThemeColor(aColor[0], aColor[1]);
			}
			else if(1 === aColor.length){
				oExcellColor = new AscCommonExcel.RgbColor(0x00ffffff & aColor[0]);
			}
		}
		return oExcellColor;
	};

	sparklineGroup.prototype._generateThumbCache = function () {
		function createItem(value) {
			return {numFormatStr: "General", isDateTimeFormat: false, val: value, isHidden: false};
		}

		switch (this.asc_getType()) {
			case Asc.c_oAscSparklineType.Line: {
				return [createItem(4), createItem(-58), createItem(51), createItem(-124), createItem(124), createItem(60)];
			}
			case Asc.c_oAscSparklineType.Column: {
				return [createItem(88), createItem(56), createItem(144), createItem(64), createItem(-56), createItem(-104),
					createItem(-40), createItem(-24), createItem(-56), createItem(104), createItem(56), createItem(80),
					createItem(-56), createItem(88)];
			}
			case Asc.c_oAscSparklineType.Stacked: {
				return [createItem(1), createItem(-1), createItem(-1), createItem(-2), createItem(1), createItem(1),
					createItem(-1), createItem(1), createItem(1), createItem(1), createItem(1), createItem(2), createItem(-1),
					createItem(1)];
			}
		}
		return [];
	};

	sparklineGroup.prototype._drawThumbBySparklineGroup = function (oSparkline, oSparklineGroup, oSparklineView, oGraphics) {
		oSparklineView.initFromSparkline(oSparkline, oSparklineGroup, null, true);
		var t = this;
		AscFormat.ExecuteNoHistory(function () {
			oSparklineView.chartSpace.setWorksheet(t.worksheet);
		}, this, []);

		oSparklineView.chartSpace.extX = 100;
		oSparklineView.chartSpace.extY = 100;
		oSparklineView.chartSpace.x = 0;
		oSparklineView.chartSpace.y = 0;
		var type = oSparklineGroup.asc_getType();
		if (type === Asc.c_oAscSparklineType.Stacked) {
			AscFormat.ExecuteNoHistory(function () {
				var oPlotArea = oSparklineView.chartSpace.chart.plotArea;
				if (!oPlotArea.layout) {
					oPlotArea.setLayout(new AscFormat.CLayout());
				}
				var fPos = 0.32;
				oPlotArea.layout.setWMode(AscFormat.LAYOUT_MODE_FACTOR);
				oPlotArea.layout.setW(1.0);
				oPlotArea.layout.setHMode(AscFormat.LAYOUT_MODE_FACTOR);
				oPlotArea.layout.setH(1 - 2 * fPos);
				oPlotArea.layout.setYMode(AscFormat.LAYOUT_MODE_EDGE);
				oPlotArea.layout.setY(fPos);
			}, this, []);
		}
		if (type === Asc.c_oAscSparklineType.Line) {
			AscFormat.ExecuteNoHistory(function () {
				var oPlotArea = oSparklineView.chartSpace.chart.plotArea;
				if (!oPlotArea.layout) {
					oPlotArea.setLayout(new AscFormat.CLayout());
				}
				var fPos = 0.16;
				oPlotArea.layout.setWMode(AscFormat.LAYOUT_MODE_FACTOR);
				oPlotArea.layout.setW(1 - fPos);
				oPlotArea.layout.setHMode(AscFormat.LAYOUT_MODE_FACTOR);
				oPlotArea.layout.setH(1 - fPos);
			}, this, []);
		}
		AscFormat.ExecuteNoHistory(function () {
			AscFormat.CheckSpPrXfrm(oSparklineView.chartSpace);
		}, this, []);
		oSparklineView.chartSpace.recalculate();
		oSparklineView.chartSpace.brush = AscFormat.CreateSolidFillRGBA(0xFF, 0xFF, 0xFF, 0xFF);

		oSparklineView.chartSpace.draw(oGraphics);
	};

	sparklineGroup.prototype._isEqualStyle = function (oSparklineGroup) {
		var equalColors = function (color1, color2) {
			return color1 ? color1.isEqual(color2) : color1 === color2;
		};
		return equalColors(this.colorSeries, oSparklineGroup.colorSeries) &&
			equalColors(this.colorNegative, oSparklineGroup.colorNegative) &&
			equalColors(this.colorMarkers, oSparklineGroup.colorMarkers) &&
			equalColors(this.colorFirst, oSparklineGroup.colorFirst) &&
			equalColors(this.colorLast, oSparklineGroup.colorLast) &&
			equalColors(this.colorHigh, oSparklineGroup.colorHigh) && equalColors(this.colorLow, oSparklineGroup.colorLow);
	};

	sparklineGroup.prototype.asc_getStyles = function (type) {
		History.TurnOff();
		var aRet = [];
		var nStyleIndex = -1;
		var oSparklineGroup = this.clone(true);
		if ('undefined' !== typeof type) {
			oSparklineGroup.asc_setType(type);
		}

		var canvas = document.createElement('canvas');
		canvas.width = 50;
		canvas.height = 50;
		if (AscCommon.AscBrowser.isRetina) {
			canvas.width = AscCommon.AscBrowser.convertToRetinaValue(canvas.width, true);
			canvas.height = AscCommon.AscBrowser.convertToRetinaValue(canvas.height, true);
		}
		var oSparklineView = new AscFormat.CSparklineView();
		var oSparkline = new sparkline();
		oSparkline.oCache = this._generateThumbCache();
		var oGraphics = new AscCommon.CGraphics();
		oGraphics.init(canvas.getContext('2d'), canvas.width, canvas.height, 100, 100);
		oGraphics.m_oFontManager = AscCommon.g_fontManager;
		oGraphics.transform(1, 0, 0, 1, 0, 0);

		for (var i = 0; i < 36; ++i) {
			oSparklineGroup.asc_setStyle(i);
			if (nStyleIndex === -1 && this._isEqualStyle(oSparklineGroup)) {
				nStyleIndex = i;
			}

			this._drawThumbBySparklineGroup(oSparkline, oSparklineGroup, oSparklineView, oGraphics);
			aRet.push(canvas.toDataURL("image/png"));
		}
		aRet.push(nStyleIndex);
		History.TurnOn();
		return aRet;
	};

	sparklineGroup.prototype.asc_setStyle = function (nStyleIndex) {
		var oStyle = AscFormat.aSparklinesStyles[nStyleIndex];
		if (oStyle) {
			this.colorSeries = this.createExcellColor(oStyle[0]);
			this.colorNegative = this.createExcellColor(oStyle[1]);
			this.colorAxis = this.createExcellColor(0xff000000);
			this.colorMarkers = this.createExcellColor(oStyle[2]);
			this.colorFirst = this.createExcellColor(oStyle[3]);
			this.colorLast = this.createExcellColor(oStyle[4]);
			this.colorHigh = this.createExcellColor(oStyle[5]);
			this.colorLow = this.createExcellColor(oStyle[6]);
		}
	};
	/** @constructor */
	function sparkline() {
		this.sqref = null;
		this.f = null;
		this._f = null;

		//for preview
		this.oCache = null;
		this.oCacheView = null;
	}

	sparkline.prototype.clone = function () {
		var res = new sparkline();

		res.sqref = this.sqref ? this.sqref.clone() : null;
		res.f = this.f;
		res._f = this._f ? this._f.clone() : null;

		return res;
	};
	sparkline.prototype.setSqref = function (sqref) {
		this.sqref = AscCommonExcel.g_oRangeCache.getAscRange(sqref).clone();
		this.sqref.setAbs(true, true, true, true);
	};
	sparkline.prototype.setF = function (f) {
		this.f = f;
		this._f = AscCommonExcel.g_oRangeCache.getRange3D(this.f);
	};
	sparkline.prototype.updateWorksheet = function (sheet, oldSheet) {
		var t = this;
		if (this._f && oldSheet === this._f.sheet && (null === this._f.sheet2 || oldSheet === this._f.sheet2)) {
			this._f.setSheet(sheet);
			AscCommonExcel.executeInR1C1Mode(false,function (){
				t.f = t._f.getName();
			});
		}
	};
	sparkline.prototype.checkInRange = function (range) {
		return this.sqref ? range.isIntersect(this.sqref) : false;
	};
	sparkline.prototype.contains = function (c, r) {
		return this.sqref ? this.sqref.contains(c, r) : false;
	};
	sparkline.prototype.intersectionSimple = function (range) {
		return this.sqref ? this.sqref.intersectionSimple(range) : false;
	};

	// For Auto Filters
	/** @constructor */
	function TablePart(handlers) {
		this.Ref = null;
		this.HeaderRowCount = null;
		this.TotalsRowCount = null;
		this.DisplayName = null;
		this.AutoFilter = null;
		this.SortState = null;
		this.TableColumns = null;
		this.TableStyleInfo = null;

		this.altText = null;
		this.altTextSummary = null;

		this.result = null;
		this.handlers = handlers;
	}

	TablePart.prototype.clone = function () {
		var i, res = new TablePart(this.handlers);
		res.Ref = this.Ref ? this.Ref.clone() : null;
		res.HeaderRowCount = this.HeaderRowCount;
		res.TotalsRowCount = this.TotalsRowCount;
		if (this.AutoFilter) {
			res.AutoFilter = this.AutoFilter.clone();
		}
		if (this.SortState) {
			res.SortState = this.SortState.clone();
		}
		if (this.TableColumns) {
			res.TableColumns = [];
			for (i = 0; i < this.TableColumns.length; ++i) {
				res.TableColumns.push(this.TableColumns[i].clone());
			}
		}
		if (this.TableStyleInfo) {
			res.TableStyleInfo = this.TableStyleInfo.clone();
		}

		if (this.result) {
			res.result = [];
			for (i = 0; i < this.result.length; ++i) {
				res.result.push(this.result[i].clone());
			}
		}
		res.DisplayName = this.DisplayName;

		res.altText = this.altText;
		res.altTextSummary = this.altTextSummary;

		return res;
	};
	TablePart.prototype.renameSheetCopy = function (ws, renameParams) {
		for (var i = 0; i < this.TableColumns.length; ++i) {
			this.TableColumns[i].renameSheetCopy(ws, renameParams);
		}
	};
	TablePart.prototype.removeDependencies = function (opt_cols) {
		if (!opt_cols) {
			opt_cols = this.TableColumns;
		}
		for (var i = 0; i < opt_cols.length; ++i) {
			opt_cols[i].removeDependencies();
		}
	};
	TablePart.prototype.buildDependencies = function () {
		for (var i = 0; i < this.TableColumns.length; ++i) {
			this.TableColumns[i].buildDependencies();
		}
	};
	TablePart.prototype.getAllFormulas = function (formulas) {
		for (var i = 0; i < this.TableColumns.length; ++i) {
			this.TableColumns[i].getAllFormulas(formulas);
		}
	};
	TablePart.prototype.moveRef = function (col, row) {
		var ref = this.Ref.clone();
		ref.setOffset(new AscCommon.CellBase(row || 0, col || 0));

		this.Ref = ref;
		//event
		this.handlers.trigger("changeRefTablePart", this);

		if (this.AutoFilter) {
			this.AutoFilter.moveRef(col, row);
		}
		if (this.SortState) {
			this.SortState.moveRef(col, row);
		}
	};
	TablePart.prototype.changeRef = function (col, row, bIsFirst, bIsNotChangeAutoFilter) {
		var ref = this.Ref.clone();
		var offset = new AscCommon.CellBase(row || 0, col || 0);
		if (bIsFirst) {
			ref.setOffsetFirst(offset);
		} else {
			ref.setOffsetLast(offset);
		}

		this.Ref = ref;

		//event
		this.handlers.trigger("changeRefTablePart", this);

		if (this.AutoFilter && !bIsNotChangeAutoFilter) {
			this.AutoFilter.changeRef(col, row, bIsFirst);
		}
		if (this.SortState) {
			this.SortState.changeRef(col, row, bIsFirst);
		}
	};
	TablePart.prototype.changeRefOnRange = function (range, autoFilters, generateNewTableColumns) {
		if (!range) {
			return;
		}

		//add table columns
		if (generateNewTableColumns) {
			var newTableColumns = [];
			var intersectionRanges = this.Ref.intersection(range);

			if (null !== intersectionRanges) {
				this.removeDependencies();
				var tableColumn;
				var headerRow = this.isHeaderRow() ? this.Ref.r1 : this.Ref.r1 - 1;
				for (var i = range.c1; i <= range.c2; i++) {
					if (i >= intersectionRanges.c1 && i <= intersectionRanges.c2) {
						var tableIndex = i - this.Ref.c1;
						tableColumn = this.TableColumns[tableIndex];
					} else {
						tableColumn = new TableColumn();
						var cell = autoFilters.worksheet.getCell3(headerRow, i);
						if (!cell.isNullText()) {
							tableColumn.Name =
								autoFilters.checkTableColumnName(newTableColumns.concat(this.TableColumns),
									cell.getValueWithoutFormat());
						}
					}

					newTableColumns.push(tableColumn);
				}

				for (var j = 0; j < newTableColumns.length; j++) {
					tableColumn = newTableColumns[j];
					if (tableColumn.Name === null) {
						tableColumn.Name = autoFilters._generateColumnName2(newTableColumns);
					}
				}

				this.TableColumns = newTableColumns;
				this.buildDependencies();
			}
		}
		this.Ref = Asc.Range(range.c1, range.r1, range.c2, range.r2);
		//event
		this.handlers.trigger("changeRefTablePart", this);

		if (this.AutoFilter) {
			this.AutoFilter.changeRefOnRange(range);
		}
	};
	TablePart.prototype.isApplyAutoFilter = function () {
		var res = false;

		if (this.AutoFilter) {
			res = this.AutoFilter.isApplyAutoFilter();
		}

		return res;
	};
	TablePart.prototype.isApplySortConditions = function () {
		var res = false;

		if (this.SortState && this.SortState.SortConditions && this.SortState.SortConditions[0]) {
			res = true;
		}

		return res;
	};

	TablePart.prototype.setHandlers = function (handlers) {
		if (this.handlers === null) {
			this.handlers = handlers;
		}
	};

	TablePart.prototype.deleteTableColumns = function (activeRange) {
		if (!activeRange) {
			return;
		}

		var diff = null, startCol;
		if (activeRange.c1 < this.Ref.c1 && activeRange.c2 >= this.Ref.c1 && activeRange.c2 < this.Ref.c2)//until
		{
			diff = activeRange.c2 - this.Ref.c1 + 1;
			startCol = 0;
		} else if (activeRange.c1 <= this.Ref.c2 && activeRange.c2 > this.Ref.c2 && activeRange.c1 > this.Ref.c1)//after
		{
			diff = this.Ref.c2 - activeRange.c1 + 1;
			startCol = activeRange.c1 - this.Ref.c1;
		} else if (activeRange.c1 >= this.Ref.c1 && activeRange.c2 <= this.Ref.c2)//inside
		{
			diff = activeRange.c2 - activeRange.c1 + 1;
			startCol = activeRange.c1 - this.Ref.c1;
		}

		if (diff !== null) {
			var deleted = this.TableColumns.splice(startCol, diff);
			this.removeDependencies(deleted);

			//todo undo
			var deletedMap = {};
			for (var i = 0; i < deleted.length; ++i) {
				deletedMap[deleted[i].Name] = 1;
			}
			this.handlers.trigger("deleteColumnTablePart", this.DisplayName, deletedMap);

			if (this.SortState) {
				var bIsDeleteSortState = this.SortState.changeColumns(activeRange, true);
				if (bIsDeleteSortState) {
					this.SortState = null;
				}
			}
		}

	};

	TablePart.prototype.addTableColumns = function (activeRange, autoFilters) {
		var newTableColumns = [], num = 0;
		this.removeDependencies();
		for (var j = 0; j < this.TableColumns.length;) {
			var curCol = num + this.Ref.c1;
			if (activeRange.c1 <= curCol && activeRange.c2 >= curCol) {
				newTableColumns[newTableColumns.length] = new TableColumn();
			} else {
				newTableColumns[newTableColumns.length] = this.TableColumns[j];
				j++
			}

			num++;
		}

		for (var j = 0; j < newTableColumns.length; j++) {
			var tableColumn = newTableColumns[j];
			if (tableColumn.Name === null) {
				tableColumn.Name = autoFilters._generateColumnName2(newTableColumns);
			}
		}

		this.TableColumns = newTableColumns;

		/*if(this.SortState && this.SortState.SortConditions && this.SortState.SortConditions[0])
		 {
		 var SortConditions = this.SortState.SortConditions[0];
		 if(activeRange.c1 <= SortConditions.Ref.c1)
		 {
		 var offset = activeRange.c2 - activeRange.c1 + 1;
		 SortConditions.Ref.c1 += offset;
		 SortConditions.Ref.c2 += offset;
		 }
		 }*/

		if (this.SortState) {
			this.SortState.changeColumns(activeRange);
		}

		this.buildDependencies();
	};

	TablePart.prototype.addTableLastColumn = function (activeRange, autoFilters, isAddLastColumn) {
		this.removeDependencies();
		var newTableColumns = this.TableColumns;
		newTableColumns.push(new TableColumn());
		newTableColumns[newTableColumns.length - 1].Name = autoFilters._generateColumnName2(newTableColumns);

		this.TableColumns = newTableColumns;
		this.buildDependencies();
	};

	TablePart.prototype.isAutoFilter = function () {
		return false;
	};

	TablePart.prototype.getAutoFilter = function () {
		return this.AutoFilter;
	};

	TablePart.prototype.getTableRangeForFormula = function (objectParam) {
		var res = null;
		var startRow = this.HeaderRowCount === null ? this.Ref.r1 + 1 : this.Ref.r1;
		var endRow = this.TotalsRowCount ? this.Ref.r2 - 1 : this.Ref.r2;
		switch (objectParam.param) {
			case FormulaTablePartInfo.all: {
				res = new Asc.Range(this.Ref.c1, this.Ref.r1, this.Ref.c2, this.Ref.r2);
				break;
			}
			case FormulaTablePartInfo.data: {
				res = new Asc.Range(this.Ref.c1, startRow, this.Ref.c2, endRow);
				break;
			}
			case FormulaTablePartInfo.headers: {
				if (this.HeaderRowCount === null) {
					res = new Asc.Range(this.Ref.c1, this.Ref.r1, this.Ref.c2, this.Ref.r1);
				} else if (!objectParam.toRef || objectParam.bConvertTableFormulaToRef) {
					res = new Asc.Range(this.Ref.c1, startRow, this.Ref.c2, endRow);
				}
				break;
			}
			case FormulaTablePartInfo.totals: {
				if (this.TotalsRowCount) {
					res = new Asc.Range(this.Ref.c1, this.Ref.r2, this.Ref.c2, this.Ref.r2);
				} else if (!objectParam.toRef || objectParam.bConvertTableFormulaToRef) {
					res = new Asc.Range(this.Ref.c1, startRow, this.Ref.c2, endRow);
				}
				break;
			}
			case FormulaTablePartInfo.thisRow: {
				if (objectParam.cell) {
					if (startRow <= objectParam.cell.r1 && objectParam.cell.r1 <= endRow) {
						res = new Asc.Range(this.Ref.c1, objectParam.cell.r1, this.Ref.c2, objectParam.cell.r1);
					} else if (objectParam.bConvertTableFormulaToRef) {
						res = new Asc.Range(this.Ref.c1, startRow, this.Ref.c2, endRow);
					}
				} else {
					if (objectParam.bConvertTableFormulaToRef) {
						res = new Asc.Range(this.Ref.c1, 0, this.Ref.c2, 0);
					} else {
						res = new Asc.Range(this.Ref.c1, startRow, this.Ref.c2, endRow);
					}
				}
				break;
			}
			case FormulaTablePartInfo.columns: {
				var startCol = this.getTableIndexColumnByName(objectParam.startCol);
				var endCol = this.getTableIndexColumnByName(objectParam.endCol);

				if (startCol === null) {
					break;
				}
				if (endCol === null) {
					endCol = startCol;
				}

				res = new Asc.Range(this.Ref.c1 + startCol, startRow, this.Ref.c1 + endCol, endRow);
				break;
			}
		}
		if (res) {
			if (objectParam.param === FormulaTablePartInfo.thisRow) {
				res.setAbs(false, true, false, true);
			} else {
				res.setAbs(true, true, true, true);
			}
		}
		return res;
	};

	TablePart.prototype.getTableIndexColumnByName = function (name) {
		var res = null;
		if (name === null || name === undefined || !this.TableColumns) {
			return res;
		}

		for (var i = 0; i < this.TableColumns.length; i++) {
			if (name.toLowerCase() === this.TableColumns[i].Name.toLowerCase()) {
				res = i;
				break;
			}
		}

		return res;
	};

	TablePart.prototype.getTableNameColumnByIndex = function (index) {
		var res = null;
		if (index === null || index === undefined || !this.TableColumns) {
			return res;
		}

		for (var i = 0; i < this.TableColumns.length; i++) {
			if (index === i) {
				res = this.TableColumns[i].Name;
				break;
			}
		}

		return res;
	};

	TablePart.prototype.showButton = function (val) {
		if (val === false) {
			if (!this.AutoFilter) {
				this.AutoFilter = new AutoFilter();
				this.AutoFilter.Ref = this.Ref;
			}

			this.AutoFilter.showButton(val);
		} else {
			if (this.AutoFilter && this.AutoFilter.FilterColumns && this.AutoFilter.FilterColumns.length) {
				this.AutoFilter.showButton(val);
			}
		}
	};

	TablePart.prototype.isShowButton = function () {
		var res = false;

		if (this.AutoFilter) {
			res = this.AutoFilter.isShowButton();
		} else {
			res = null;
		}

		return res;
	};

	TablePart.prototype.generateTotalsRowLabel = function (ws) {
		if (!this.TableColumns) {
			return;
		}

		//в случае одной колонки выставляем только формулу
		if (this.TableColumns.length > 1) {
			this.TableColumns[0].generateTotalsRowLabel();
		}
		this.TableColumns[this.TableColumns.length - 1].generateTotalsRowFunction(ws, this);
	};

	TablePart.prototype.changeDisplayName = function (newName) {
		this.DisplayName = newName;
	};

	TablePart.prototype.getRangeWithoutHeaderFooter = function () {
		var startRow = this.HeaderRowCount === null ? this.Ref.r1 + 1 : this.Ref.r1;
		var endRow = this.TotalsRowCount ? this.Ref.r2 - 1 : this.Ref.r2;

		return Asc.Range(this.Ref.c1, startRow, this.Ref.c2, endRow);
	};

	TablePart.prototype.checkTotalRowFormula = function (ws) {
		for (var i = 0; i < this.TableColumns.length; i++) {
			this.TableColumns[i].checkTotalRowFormula(ws, this);
		}
	};

	TablePart.prototype.changeAltText = function (val) {
		this.altText = val;
	};

	TablePart.prototype.changeAltTextSummary = function (val) {
		this.altTextSummary = val;
	};

	TablePart.prototype.addAutoFilter = function () {
		var autoFilter = new AscCommonExcel.AutoFilter();
		var cloneRef = this.Ref.clone();
		if (this.TotalsRowCount) {
			cloneRef.r2--
		}
		autoFilter.Ref = cloneRef;

		this.AutoFilter = autoFilter;
		return autoFilter;
	};

	TablePart.prototype.isHeaderRow = function () {
		return null === this.HeaderRowCount || this.HeaderRowCount > 0;
	};

	TablePart.prototype.isTotalsRow = function () {
		return this.TotalsRowCount > 0;
	};

	TablePart.prototype.generateSortState = function () {
		this.SortState = new AscCommonExcel.SortState();
		this.SortState.SortConditions = [];
		this.SortState.SortConditions[0] = new AscCommonExcel.SortCondition();
	};

	/** @constructor */
	function AutoFilter() {
		this.Ref = null;
		this.FilterColumns = null;
		this.SortState = null;

		this.result = null;
	}

	AutoFilter.prototype.clone = function () {
		var i, res = new AutoFilter();
		res.Ref = this.Ref ? this.Ref.clone() : null;
		res.refTable = this.refTable ? this.refTable.clone() : null;
		if (this.FilterColumns) {
			res.FilterColumns = [];
			for (i = 0; i < this.FilterColumns.length; ++i) {
				res.FilterColumns.push(this.FilterColumns[i].clone());
			}
		}

		if (this.SortState) {
			res.SortState = this.SortState.clone();
		}

		if (this.result) {
			res.result = [];
			for (i = 0; i < this.result.length; ++i) {
				res.result.push(this.result[i].clone());
			}
		}

		return res;
	};

	AutoFilter.prototype.addFilterColumn = function () {
		if (this.FilterColumns === null) {
			this.FilterColumns = [];
		}

		var oNewElem = new FilterColumn();
		this.FilterColumns.push(oNewElem);

		return oNewElem;
	};
	AutoFilter.prototype.moveRef = function (col, row) {
		var ref = this.Ref.clone();
		ref.setOffset(new AscCommon.CellBase(row || 0, col || 0));

		if (this.SortState) {
			this.SortState.moveRef(col, row);
		}

		this.Ref = ref;
	};
	AutoFilter.prototype.changeRef = function (col, row, bIsFirst) {
		var ref = this.Ref.clone();
		var offset = new AscCommon.CellBase(row || 0, col || 0);
		if (bIsFirst) {
			ref.setOffsetFirst(offset);
		} else {
			ref.setOffsetLast(offset);
		}

		this.Ref = ref;
	};
	AutoFilter.prototype.changeRefOnRange = function (range) {
		if (!range) {
			return;
		}

		this.Ref = Asc.Range(range.c1, range.r1, range.c2, range.r2);

		if (this.AutoFilter) {
			this.AutoFilter.changeRefOnRange(range);
		}
	};
	AutoFilter.prototype.isApplyAutoFilter = function () {
		var res = false;

		if (this.FilterColumns && this.FilterColumns.length) {
			for (var i = 0; i < this.FilterColumns.length; i++) {
				if (this.FilterColumns[i].isApplyAutoFilter()) {
					res = true;
					break;
				}
			}
		}

		return res;
	};

	AutoFilter.prototype.isApplySortConditions = function () {
		var res = false;

		if (this.SortState && this.SortState.SortConditions && this.SortState.SortConditions[0]) {
			res = true;
		}

		return res;
	};

	AutoFilter.prototype.isAutoFilter = function () {
		return true;
	};

	AutoFilter.prototype.cleanFilters = function () {
		if (!this.FilterColumns) {
			return;
		}

		for (var i = 0; i < this.FilterColumns.length; i++) {
			if (this.FilterColumns[i].ShowButton === false) {
				this.FilterColumns[i].clean();
			} else {
				this.FilterColumns.splice(i, 1);
				i--;
			}
		}
	};

	AutoFilter.prototype.showButton = function (val) {

		if (val === false) {
			if (this.FilterColumns === null) {
				this.FilterColumns = [];
			}

			var columnsLength = this.Ref.c2 - this.Ref.c1 + 1;
			for (var i = 0; i < columnsLength; i++) {
				var filterColumn = this._getFilterColumnByColId(i);
				if (filterColumn) {
					filterColumn.ShowButton = false;
				} else {
					filterColumn = new FilterColumn();
					filterColumn.ColId = i;
					filterColumn.ShowButton = false;
					this.FilterColumns.push(filterColumn);
				}
			}
		} else {
			if (this.FilterColumns && this.FilterColumns.length) {
				for (var i = 0; i < this.FilterColumns.length; i++) {
					this.FilterColumns[i].ShowButton = true;
				}
			}
		}
	};

	AutoFilter.prototype.isShowButton = function () {
		var res = true;

		if (this.FilterColumns && this.FilterColumns.length) {
			for (var i = 0; i < this.FilterColumns.length; i++) {
				if (this.FilterColumns[i].ShowButton === false) {
					res = false;
					break;
				}
			}
		}

		return res;
	};

	AutoFilter.prototype.getRangeWithoutHeaderFooter = function () {
		return Asc.Range(this.Ref.c1, this.Ref.r1 + 1, this.Ref.c2, this.Ref.r2);
	};

	AutoFilter.prototype._getFilterColumnByColId = function (colId) {
		var res = false;

		if (this.FilterColumns && this.FilterColumns.length) {
			for (var i = 0; i < this.FilterColumns.length; i++) {
				if (this.FilterColumns[i].ColId === colId) {
					res = this.FilterColumns[i];
					break;
				}
			}
		}

		return res;
	};

	//функция используется только для изменения данных сортировки, называется так как и в классе TablePart. возможно стоит переименовать.
	AutoFilter.prototype.deleteTableColumns = function (activeRange) {
		if (this.SortState) {
			var bIsDeleteSortState = this.SortState.changeColumns(activeRange, true);
			if (bIsDeleteSortState) {
				this.SortState = null;
			}
		}
	};

	//функция используется только для изменения данных сортировки, называется так как и в классе TablePart. возможно стоит переименовать.
	AutoFilter.prototype.addTableColumns = function (activeRange) {
		if (this.SortState) {
			this.SortState.changeColumns(activeRange);
		}
	};

	AutoFilter.prototype.getIndexByColId = function (colId) {
		var res = null;

		if (!this.FilterColumns) {
			return res;
		}

		for (var i = 0; i < this.FilterColumns.length; i++) {
			if (this.FilterColumns[i].ColId === colId) {
				res = i;
				break;
			}
		}

		return res;
	};

	AutoFilter.prototype.getFilterColumn = function (colId) {
		var res = null;

		if (!this.FilterColumns) {
			return res;
		}

		for (var i = 0; i < this.FilterColumns.length; i++) {
			if (this.FilterColumns[i].ColId === colId) {
				res = this.FilterColumns[i];
				break;
			}
		}

		return res;
	};

	AutoFilter.prototype.getAutoFilter = function () {
		return this;
	};

	AutoFilter.prototype.hiddenByAnotherFilter = function (worksheet, cellId, row, col) {
		var result = false;

		var filterColumns = this.FilterColumns;
		if (filterColumns) {
			for (var j = 0; j < filterColumns.length; j++) {
				var colId = filterColumns[j].ColId;
				if (colId !== cellId) {
					var cell = worksheet.getCell3(row, colId + col);
					var isDateTimeFormat = cell.getNumFormat().isDateTimeFormat() && cell.getType() === window["AscCommon"].CellValueType.Number;

					var isNumberFilter = filterColumns[j].isApplyCustomFilter();
					var val = (isDateTimeFormat || isNumberFilter) ? cell.getValueWithoutFormat() : cell.getValueWithFormat();
					if (filterColumns[j].isHideValue(val, isDateTimeFormat, null, cell)) {
						result = true;
						break;
					}
				}
			}
		}

		return result;
	};

	AutoFilter.prototype.setRowHidden = function(worksheet, newFilterColumn) {
		var startRow = this.Ref.r1 + 1;
		var endRow = this.Ref.r2;

		var colId = newFilterColumn ? newFilterColumn.ColId : null;
		var minChangeRow = null;
		var hiddenObj = {start: this.Ref.r1 + 1, h: null};
		var nHiddenRowCount = 0;
		var nRowsCount = 0;
		for (var i = startRow; i <= endRow; i++) {

			var isHidden = this.hiddenByAnotherFilter(worksheet, colId, i, this.Ref.c1);
			if(!newFilterColumn) {
				if (isHidden !== worksheet.getRowHidden(i)) {
					if (minChangeRow === null) {
						minChangeRow = i;
					}
				}

				if (true === isHidden) {
					worksheet.setRowHidden(isHidden, i, i);
				}
			} else {
				if (!isHidden) {
					var cell = worksheet.getCell3(i, colId + this.Ref.c1);
					var isDateTimeFormat = cell.getNumFormat().isDateTimeFormat() && cell.getType() === window["AscCommon"].CellValueType.Number;
					var isNumberFilter = false;
					if (newFilterColumn.CustomFiltersObj || newFilterColumn.Top10 || newFilterColumn.DynamicFilter) {
						isNumberFilter = true;
					}

					var currentValue = (isDateTimeFormat || isNumberFilter) ? cell.getValueWithoutFormat() : cell.getValueWithFormat();
					currentValue = window["Asc"].trim(currentValue);
					var isSetHidden = newFilterColumn.isHideValue(currentValue, isDateTimeFormat, null, cell);

					if (isSetHidden !== worksheet.getRowHidden(i) && minChangeRow === null) {
						minChangeRow = i;
					}

					//скрываем строки
					if (hiddenObj.h === null) {
						hiddenObj.h = isSetHidden;
						hiddenObj.start = i;
					} else if (hiddenObj.h !== isSetHidden) {
						worksheet.setRowHidden(hiddenObj.h, hiddenObj.start, i - 1);
						if (true === hiddenObj.h) {
							nHiddenRowCount += i - hiddenObj.start;
						}

						hiddenObj.h = isSetHidden;
						hiddenObj.start = i;
					}

					if (i === endRow) {
						worksheet.setRowHidden(hiddenObj.h, hiddenObj.start, i);
						if (true === hiddenObj.h) {
							nHiddenRowCount += i + 1 - hiddenObj.start;
						}
					}
					nRowsCount++;
				} else if (hiddenObj.h !== null) {
					worksheet.setRowHidden(hiddenObj.h, hiddenObj.start, i - 1);
					if (true === hiddenObj.h) {
						nHiddenRowCount += i - hiddenObj.start;
					}
					hiddenObj.h = null
				}
			}
		}

		return {nOpenRowsCount: nRowsCount - nHiddenRowCount, nAllRowsCount: endRow - startRow + 1, minChangeRow: minChangeRow};
	};

	AutoFilter.prototype.generateSortState = function () {
		this.SortState = new AscCommonExcel.SortState();
		this.SortState.SortConditions = [];
		this.SortState.SortConditions[0] = new AscCommonExcel.SortCondition();
	};

	function FilterColumns() {
		this.ColId = null;
		this.CustomFiltersObj = null;
	}

	FilterColumns.prototype.clone = function () {
		var res = new FilterColumns();
		res.ColId = this.ColId;
		if (this.CustomFiltersObj) {
			res.CustomFiltersObj = this.CustomFiltersObj.clone();
		}

		return res;
	};

	/** @constructor */
	function SortState() {
		this.Ref = null;
		this.CaseSensitive = null;
		this.SortConditions = null;
	}

	SortState.prototype.clone = function () {
		var i, res = new SortState();
		res.Ref = this.Ref ? this.Ref.clone() : null;
		res.CaseSensitive = this.CaseSensitive;
		if (this.SortConditions) {
			res.SortConditions = [];
			for (i = 0; i < this.SortConditions.length; ++i) {
				res.SortConditions.push(this.SortConditions[i].clone());
			}
		}
		return res;
	};

	SortState.prototype.moveRef = function (col, row) {
		var ref = this.Ref.clone();
		ref.setOffset(new AscCommon.CellBase(row || 0, col || 0));

		this.Ref = ref;

		if (this.SortConditions) {
			for (var i = 0; i < this.SortConditions.length; ++i) {
				this.SortConditions[i].moveRef(col, row);
			}
		}
	};

	SortState.prototype.changeRef = function (col, row, bIsFirst) {
		var ref = this.Ref.clone();
		var offset = new AscCommon.CellBase(row || 0, col || 0);
		if (bIsFirst) {
			ref.setOffsetFirst(offset);
		} else {
			ref.setOffsetLast(offset);
		}

		this.Ref = ref;
	};

	SortState.prototype.changeColumns = function (activeRange, isDelete) {
		var bIsSortStateDelete = true;
		//если изменяем диапазон так, что удаляется колонка с сортировкой, удаляем ее
		if (this.SortConditions) {
			for (var i = 0; i < this.SortConditions.length; ++i) {
				var bIsSortConditionsDelete = this.SortConditions[i].changeColumns(activeRange, isDelete);
				if (bIsSortConditionsDelete) {
					this.SortConditions[i] = null;
				} else {
					bIsSortStateDelete = false;
				}
			}
		}
		return bIsSortStateDelete;
	};


	/** @constructor */
	function TableColumn() {
		this.Name = null;
		this.TotalsRowLabel = null;
		this.TotalsRowFunction = null;
		this.TotalsRowFormula = null;
		this.dxf = null;
		this.CalculatedColumnFormula = null;
	}

	TableColumn.prototype.onFormulaEvent = function (type, eventData) {
	};
	TableColumn.prototype.renameSheetCopy = function (ws, renameParams) {
		if (this.TotalsRowFormula) {
			this.buildDependencies();
			this.TotalsRowFormula.renameSheetCopy(renameParams);
			this.applyTotalRowFormula(this.TotalsRowFormula.assemble(true), ws, true);
		}
	};
	TableColumn.prototype.buildDependencies = function () {
		if (this.TotalsRowFormula) {
			this.TotalsRowFormula.parse();
			this.TotalsRowFormula.buildDependencies();
		}
	};
	TableColumn.prototype.removeDependencies = function () {
		if (this.TotalsRowFormula) {
			this.TotalsRowFormula.removeDependencies();
		}
	};
	TableColumn.prototype.getAllFormulas = function (formulas) {
		if (this.TotalsRowFormula) {
			formulas.push(this.TotalsRowFormula);
		}
	};
	TableColumn.prototype.clone = function () {
		var res = new TableColumn();
		res.Name = this.Name;
		res.TotalsRowLabel = this.TotalsRowLabel;
		res.TotalsRowFunction = this.TotalsRowFunction;

		if (this.TotalsRowFormula) {
		res.applyTotalRowFormula(this.TotalsRowFormula.getFormula(), this.TotalsRowFormula.ws, false);
		}
		if (this.dxf) {
			res.dxf = this.dxf.clone;
		}
		res.CalculatedColumnFormula = this.CalculatedColumnFormula;
		return res;
	};
	TableColumn.prototype.generateTotalsRowLabel = function () {
		//TODO добавить в перевод
		if (this.TotalsRowLabel === null) {
			this.TotalsRowLabel = "Summary";
		}
	};
	TableColumn.prototype.generateTotalsRowFunction = function (ws, tablePart) {
		//TODO добавить в перевод
		if (null === this.TotalsRowFunction && null === this.TotalsRowLabel) {
			var columnRange = this.getRange(tablePart);

			var totalFunction = Asc.ETotalsRowFunction.totalrowfunctionSum;
			if (null !== columnRange) {
				for (var i = columnRange.r1; i <= columnRange.r2; i++) {
					var type = ws.getCell3(i, columnRange.c1).getType();
					if (null !== type && CellValueType.Number !== type) {
						totalFunction = Asc.ETotalsRowFunction.totalrowfunctionCount;
						break;
					}
				}
			}

			this.TotalsRowFunction = totalFunction;
		}
	};

	TableColumn.prototype.getTotalRowFormula = function (tablePart) {
		var res = null;

		if (null !== this.TotalsRowFunction) {
			switch (this.TotalsRowFunction) {
				case Asc.ETotalsRowFunction.totalrowfunctionAverage: {
					res = "SUBTOTAL(101," + tablePart.DisplayName + "[" + this.Name + "])";
					break;
				}
				case Asc.ETotalsRowFunction.totalrowfunctionCount: {
					res = "SUBTOTAL(103," + tablePart.DisplayName + "[" + this.Name + "])";
					break;
				}
				case Asc.ETotalsRowFunction.totalrowfunctionCountNums: {
					break;
				}
				case Asc.ETotalsRowFunction.totalrowfunctionCustom: {
					res = this.getTotalsRowFormula();
					break;
				}
				case Asc.ETotalsRowFunction.totalrowfunctionMax: {
					res = "SUBTOTAL(104," + tablePart.DisplayName + "[" + this.Name + "])";
					break;
				}
				case Asc.ETotalsRowFunction.totalrowfunctionMin: {
					res = "SUBTOTAL(105," + tablePart.DisplayName + "[" + this.Name + "])";
					break;
				}
				case Asc.ETotalsRowFunction.totalrowfunctionNone: {
					break;
				}
				case Asc.ETotalsRowFunction.totalrowfunctionStdDev: {
					res = "SUBTOTAL(107," + tablePart.DisplayName + "[" + this.Name + "])";
					break;
				}
				case Asc.ETotalsRowFunction.totalrowfunctionSum: {
					res = "SUBTOTAL(109," + tablePart.DisplayName + "[" + this.Name + "])";
					break;
				}
				case Asc.ETotalsRowFunction.totalrowfunctionVar: {
					res = "SUBTOTAL(110," + tablePart.DisplayName + "[" + this.Name + "])";
					break;
				}
			}
		}

		return res;
	};

	TableColumn.prototype.cleanTotalsData = function () {
		this.CalculatedColumnFormula = null;
		this.applyTotalRowFormula(null, null, false);
		this.TotalsRowFunction = null;
		this.TotalsRowLabel = null;
	};
	TableColumn.prototype.getTotalsRowFormula = function () {
		return this.TotalsRowFormula ? this.TotalsRowFormula.getFormula() : null;
	};
	TableColumn.prototype.getTotalsRowFunction = function () {
		return this.TotalsRowFunction;
	};
	TableColumn.prototype.getTotalsRowLabel = function () {
		return this.TotalsRowLabel ? this.TotalsRowFormula.TotalsRowLabel : null;
	};
	TableColumn.prototype.setTotalsRowFormula = function (val, ws) {
		this.cleanTotalsData();
		if ("=" === val[0]) {
			val = val.substring(1);
		}
		this.applyTotalRowFormula(val, ws, true);
		this.TotalsRowFunction = Asc.ETotalsRowFunction.totalrowfunctionCustom;
	};
	TableColumn.prototype.setTotalsRowFunction = function (val) {
		//функция работает только на undo/redo
		//для того, чтобы работала из меню, необходимо генерировать и добавлять формулу в ячейку
		this.cleanTotalsData();
		this.TotalsRowFunction = val;
	};

	TableColumn.prototype.setTotalsRowLabel = function (val) {
		this.cleanTotalsData();
		this.TotalsRowLabel = val;
	};

	TableColumn.prototype.checkTotalRowFormula = function (ws, tablePart) {
		if (null !== this.TotalsRowFunction &&
			Asc.ETotalsRowFunction.totalrowfunctionCustom !== this.TotalsRowFunction) {
			var totalRowFormula = this.getTotalRowFormula(tablePart);

			if (null !== totalRowFormula) {
				this.applyTotalRowFormula(totalRowFormula, ws, true);
				this.TotalsRowFunction = Asc.ETotalsRowFunction.totalrowfunctionCustom;
			}
		}
	};
	TableColumn.prototype.applyTotalRowFormula = function (val, opt_ws, opt_buildDep) {
		this.removeDependencies();
		if (val) {
			this.TotalsRowFormula = new AscCommonExcel.parserFormula(val, this, opt_ws);
			if (opt_buildDep) {
				this.buildDependencies();
			}
		} else {
			this.TotalsRowFormula = null;
		}
	};

	TableColumn.prototype.getRange = function (tablePart, includeHeader, includeTotal) {
		var res = null;

		var ref = tablePart.Ref;
		var startRow = (includeHeader && tablePart.isHeaderRow()) || (!tablePart.isHeaderRow()) ? ref.r1 : ref.r1 + 1;
		var endRow = (includeTotal && tablePart.isTotalsRow()) || (!tablePart.isTotalsRow()) ? ref.r2 : ref.r2 - 1;
		var col = null;
		for (var i = 0; i < tablePart.TableColumns.length; i++) {
			if (this.Name === tablePart.TableColumns[i].Name) {
				col = ref.c1 + i;
				break;
			}
		}

		if (null !== col) {
			res = Asc.Range(col, startRow, col, endRow);
		}

		return res;
	};

	/** @constructor */
	function TableStyleInfo() {
		this.Name = null;
		this.ShowColumnStripes = null;
		this.ShowRowStripes = null;
		this.ShowFirstColumn = null;
		this.ShowLastColumn = null;
	}

	TableStyleInfo.prototype.clone = function () {
		var res = new TableStyleInfo();
		res.Name = this.Name;
		res.ShowColumnStripes = this.ShowColumnStripes;
		res.ShowRowStripes = this.ShowRowStripes;
		res.ShowFirstColumn = this.ShowFirstColumn;
		res.ShowLastColumn = this.ShowLastColumn;
		return res;
	};
	TableStyleInfo.prototype.setName = function (val) {
		this.Name = val;
	};

	/** @constructor */
	function FilterColumn() {
		this.ColId = null;
		this.Filters = null;
		this.CustomFiltersObj = null;
		this.DynamicFilter = null;
		this.ColorFilter = null;
		this.Top10 = null;
		this.ShowButton = true;
	}

	FilterColumn.prototype.clone = function () {
		var res = new FilterColumn();
		res.ColId = this.ColId;
		if (this.Filters) {
			res.Filters = this.Filters.clone();
		}
		if (this.CustomFiltersObj) {
			res.CustomFiltersObj = this.CustomFiltersObj.clone();
		}
		if (this.DynamicFilter) {
			res.DynamicFilter = this.DynamicFilter.clone();
		}
		if (this.ColorFilter) {
			res.ColorFilter = this.ColorFilter.clone();
		}
		if (this.Top10) {
			res.Top10 = this.Top10.clone();
		}
		res.ShowButton = this.ShowButton;
		return res;
	};
	FilterColumn.prototype.isHideValue = function (val, isDateTimeFormat, top10Length, cell) {
		var res = false;
		if (this.Filters) {
			this.Filters._initLowerCaseValues();
			res = this.Filters.isHideValue(val.toLowerCase(), isDateTimeFormat);
		} else if (this.CustomFiltersObj) {
			res = this.CustomFiltersObj.isHideValue(val);
		} else if (this.Top10) {
			res = this.Top10.isHideValue(val, top10Length);
		} else if (this.ColorFilter) {
			res = this.ColorFilter.isHideValue(cell);
		} else if (this.DynamicFilter) {
			res = this.DynamicFilter.isHideValue(val);
		}

		return res;
	};
	FilterColumn.prototype.clean = function () {
		this.Filters = null;
		this.CustomFiltersObj = null;
		this.DynamicFilter = null;
		this.ColorFilter = null;
		this.Top10 = null;
	};
	FilterColumn.prototype.createFilter = function (obj) {

		var allFilterOpenElements = false;
		var newFilter;

		switch (obj.filter.type) {
			case c_oAscAutoFilterTypes.ColorFilter: {
				this.ColorFilter = obj.filter.filter.clone();
				break;
			}
			case c_oAscAutoFilterTypes.CustomFilters: {
				obj.filter.filter.check();
				this.CustomFiltersObj = obj.filter.filter.clone();
				break;
			}
			case c_oAscAutoFilterTypes.DynamicFilter: {
				this.DynamicFilter = obj.filter.filter.clone();
				break;
			}
			case c_oAscAutoFilterTypes.Top10: {
				this.Top10 = obj.filter.filter.clone();
				break;
			}
			case c_oAscAutoFilterTypes.Filters: {
				//если приходит только скрытое Blank, тогда добавляем CustomFilter, так же делает MS
				var addCustomFilter = false;
				for (var i = 0; i < obj.values.length; i++) {
					if ("" === obj.values[i].text && false === obj.values[i].visible) {
						addCustomFilter = true;
					} else if ("" !== obj.values[i].text && false === obj.values[i].visible) {
						addCustomFilter = false;
						break;
					}
				}

				if (addCustomFilter) {
					this.CustomFiltersObj = new CustomFilters();
					this.CustomFiltersObj._generateEmptyValueFilter();
				} else {
					newFilter = new Filters();
					allFilterOpenElements = newFilter.init(obj);

					if (!allFilterOpenElements) {
						this.Filters = newFilter;
					}
				}

				break;
			}
		}

		return allFilterOpenElements;
	};

	FilterColumn.prototype.isApplyAutoFilter = function () {
		var res = false;

		if (this.Filters !== null || this.CustomFiltersObj !== null || this.DynamicFilter !== null ||
			this.ColorFilter !== null || this.Top10 !== null) {
			res = true;
		}

		return res;
	};

	FilterColumn.prototype.init = function (range) {

		//добавляем данные, которые не передаются из меню при примененни а/ф(в данном случае только DynamicFilter)
		if (null !== this.DynamicFilter) {
			this.DynamicFilter.init(range);
		} else if (null !== this.Top10) {
			this.Top10.init(range);
		}

	};

	FilterColumn.prototype.isApplyCustomFilter = function () {
		var res = false;

		if (this.Top10 || this.CustomFiltersObj || this.ColorFilter || this.DynamicFilter) {
			res = true;
		}

		return res;
	};

	FilterColumn.prototype.isOnlyNotEqualEmpty = function () {
		var res = false;

		if (this.CustomFiltersObj) {
			var customFilters = this.CustomFiltersObj.CustomFilters;
			var customFilter = customFilters && 1 === customFilters.length ? customFilters[0] : null;
			if (customFilter && c_oAscCustomAutoFilter.doesNotEqual === customFilter.Operator && " " === customFilter.Val) {
				res = true;
			}
		}

		return res;
	};


	/** @constructor */
	function Filters() {
		this.Values = {};
		this.Dates = [];
		this.Blank = null;

		this.lowerCaseValues = null;
	}

	Filters.prototype.clone = function () {
		var i, res = new Filters();
		for (var i in this.Values) {
			res.Values[i] = this.Values[i];
		}
		if (this.Dates) {
			for (i = 0; i < this.Dates.length; ++i) {
				res.Dates.push(this.Dates[i].clone());
			}
		}
		res.Blank = this.Blank;
		return res;
	};
	Filters.prototype.init = function (obj) {
		var allFilterOpenElements = true;
		for (var i = 0; i < obj.values.length; i++) {
			if (obj.values[i].visible) {
				if (obj.values[i].isDateFormat) {
					if (obj.values[i].text === "") {
						this.Blank = true;
					} else {
						var dateGroupItem = new DateGroupItem();
						var autoFilterDateElem = new AutoFilterDateElem(obj.values[i].val, obj.values[i].val, 1);
						dateGroupItem.convertRangeToDateGroupItem(autoFilterDateElem);
						autoFilterDateElem.convertDateGroupItemToRange(dateGroupItem);

						this.Dates.push(autoFilterDateElem);
					}
				} else {
					if (obj.values[i].text === "") {
						this.Blank = true;
					} else {
						this.Values[obj.values[i].text] = true;
					}
				}
			} else {
				allFilterOpenElements = false;
			}
		}
		this._sortDate();
		this._initLowerCaseValues();

		return allFilterOpenElements;
	};
	Filters.prototype.isHideValue = function (val, isDateTimeFormat) {
		var res = false;

		if (isDateTimeFormat && this.Dates) {
			if (val === "") {
				res = !this.Blank ? true : false;
			} else {
				res = this.binarySearch(val, this.Dates) !== -1 ? false : true;
			}
		} else if (this.Values) {
			if (val === "") {
				res = !this.Blank ? true : false;
			} else {
				res = !this.lowerCaseValues[val] ? true : false;
			}
		}

		return res;
	};

	Filters.prototype.binarySearch = function (val, array) {
		var i = 0, j = array.length - 1, k;
		val = parseFloat(val);

		while (i <= j) {
			k = Math.floor((i + j) / 2);

			if (val >= array[k].start && val < array[k].end) {
				return k;
			} else if (val < array[k].start) {
				j = k - 1;
			} else {
				i = k + 1;
			}
		}

		return -1;
	};

	Filters.prototype.linearSearch = function (val, array) {
		var n = array.length, i = 0;
		val = parseFloat(val);

		while (i <= n && !(array[i] && val >= array[i].start && val < array[i].end))
			i++;

		if (i < n) {
			return i;
		} else {
			return -1;
		}
	};
	Filters.prototype._initLowerCaseValues = function () {
		if (this.lowerCaseValues === null) {
			this.lowerCaseValues = {};
			for (var i in this.Values) {
				this.lowerCaseValues[i.toLowerCase()] = true;
			}
		}
	};
	Filters.prototype._sortDate = function () {
		if (this.Dates && this.Dates.length) {
			this.Dates.sort(function sortArr(a, b) {
				return a.start - b.start;
			})
		}
	};

	Filters.prototype.clean = function () {
		this.Values = {};
		this.Dates = [];
		this.Blank = null;
	};
	
/** @constructor */
function Filter() {
	this.Val = null;
}
/** @constructor */
function DateGroupItem() {
	this.DateTimeGrouping = null;
	this.Day = null;
	this.Hour = null;
	this.Minute = null;
	this.Month = null;
	this.Second = null;
	this.Year = null;
}
DateGroupItem.prototype.clone = function() {
	var res = new DateGroupItem();
	res.DateTimeGrouping = this.DateTimeGrouping;
	res.Day = this.Day;
	res.Hour = this.Hour;
	res.Minute = this.Minute;
	res.Month = this.Month;
	res.Second = this.Second;
	res.Year = this.Year;
	return res;
};
DateGroupItem.prototype.convertRangeToDateGroupItem = function(range) {
	var startUtcDate = AscCommon.NumFormat.prototype.parseDate(range.start);
	var year = startUtcDate.year;
	var month = startUtcDate.month + 1;
	var day = startUtcDate.d;
	var hour = startUtcDate.hour;
	var minute = startUtcDate.minute;
	var second = startUtcDate.second;
	
	this.DateTimeGrouping = range.dateTimeGrouping;
	
	switch(this.DateTimeGrouping)
	{
		case 1://day
		{
			this.Year = year;
			this.Month = month;
			this.Day = day;
			break;
		}
		case 2://hour
		{
			this.Year = year;
			this.Month = month;
			this.Day = day;
			this.Hour = hour;
			break;
		}
		case 3://minute
		{
			this.Year = year;
			this.Month = month;
			this.Day = day;
			this.Hour = hour;
			this.Minute = minute;
			break;
		}
		case 4://month
		{
			this.Year = year;
			this.Month = month;
			break;
		}
		case 5://second
		{
			this.Year = year;
			this.Month = month;
			this.Day = day;
			this.Hour = hour;
			this.Minute = minute;
			this.Second = second;
			break;
		}
		case 6://year
		{
			this.Year = year;
			break;
		}
	}
};


var g_oCustomFilters = {
	And	 : 0,
	CustomFilters	: 1
};
/** @constructor */
function CustomFilters() {
	this.Properties = g_oCustomFilters;
	
	this.And = null;
	this.CustomFilters = null;
}
CustomFilters.prototype.getType = function() {
	return UndoRedoDataTypes.CustomFilters;
};
CustomFilters.prototype.getProperties = function() {
	return this.Properties;
};
CustomFilters.prototype.getProperty = function(nType) {
	switch (nType) {
		case this.Properties.And: return this.And; break;
		case this.Properties.CustomFilters: return this.CustomFilters; break;
	}
	return null;
};
CustomFilters.prototype.setProperty = function(nType, value) {
	switch (nType) {
		case this.Properties.And: this.And = value;break;
		case this.Properties.CustomFilters: this.CustomFilters = value;break;
	}
};
	
CustomFilters.prototype.clone = function() {
	var i, res = new CustomFilters();
	res.And = this.And;
	if (this.CustomFilters) {
		res.CustomFilters = [];
		for (i = 0; i < this.CustomFilters.length; ++i)
			res.CustomFilters.push(this.CustomFilters[i].clone());
	}
	return res;
};
CustomFilters.prototype.init = function(obj) {
	this.And = !obj.isChecked;
	this.CustomFilters = [];
	
	if(obj.filter1 != undefined)
		this.CustomFilters[0] = new CustomFilter(obj.filter1, obj.valFilter1);
	if(obj.filter2 != undefined)
		this.CustomFilters[1] = new CustomFilter(obj.filter2, obj.valFilter2);
};
CustomFilters.prototype.isHideValue = function(val){
	
	var res = false;
	var filterRes1 = this.CustomFilters[0] ? this.CustomFilters[0].isHideValue(val) : null;
	var filterRes2 = this.CustomFilters[1] ? this.CustomFilters[1].isHideValue(val) : null;
	
	if(!this.And && ((filterRes1 === null && filterRes2 === true || filterRes1 === true && filterRes2 === null || filterRes1 === true && filterRes2 === true)))
		res = true;
	if(this.And && ((filterRes1 === true || filterRes2 === true)))
		res = true;
	
	return res;
};
CustomFilters.prototype.asc_getAnd = function () { return this.And; };
CustomFilters.prototype.asc_getCustomFilters = function () { return this.CustomFilters; };

CustomFilters.prototype.asc_setAnd = function (val) { this.And = val; };
CustomFilters.prototype.asc_setCustomFilters = function (val) { this.CustomFilters = val; };

CustomFilters.prototype.check = function () {
	if(this.CustomFilters) {
		for(var i = 0; i < this.CustomFilters.length; i++) {
			this.CustomFilters[i].check();
		}
	}
};

CustomFilters.prototype._generateEmptyValueFilter = function() {
	this.And = true;
	this.CustomFilters = [];
	var customFilter = new CustomFilter();
	customFilter._generateEmptyValueFilter();
	this.CustomFilters.push(customFilter);
};

var g_oCustomFilter = {
	Operator	 : 0,
	Val	: 1
};

/** @constructor */
function CustomFilter(operator, val) {
	this.Properties = g_oCustomFilter;
	
	this.Operator = operator != undefined ? operator : null;
	this.Val = val != undefined ? val : null;
}
CustomFilter.prototype.getType = function() {
	return UndoRedoDataTypes.CustomFilter;
};
CustomFilter.prototype.getProperties = function() {
	return this.Properties;
};
CustomFilter.prototype.getProperty = function(nType) {
	switch (nType) {
		case this.Properties.Operator: return this.Operator; break;
		case this.Properties.Val: return this.Val; break;
	}
	return null;
};
CustomFilter.prototype.setProperty = function(nType, value) {
	switch (nType) {
		case this.Properties.Operator: this.Operator = value;break;
		case this.Properties.Val: this.Val = value;break;
	}
};

CustomFilter.prototype.clone = function() {
	var res = new CustomFilter();
	res.Operator = this.Operator;
	res.Val = this.Val;
	return res;
};
CustomFilter.prototype.init = function(operator, val) {
	this.Operator = operator;
	this.Val = val;
};
CustomFilter.prototype.isHideValue = function(val) {

	var result = false;
	var isDigitValue = !isNaN(val);
	if(!isDigitValue)
	{
		val = val.toLowerCase();
	}

	var checkComplexSymbols = null, filterVal;
	if(checkComplexSymbols != null)
	{
		result = checkComplexSymbols;
	}
	else
	{
		var isNumberFilter = this.Operator == c_oAscCustomAutoFilter.isGreaterThan || this.Operator == c_oAscCustomAutoFilter.isGreaterThanOrEqualTo || this.Operator == c_oAscCustomAutoFilter.isLessThan || this.Operator == c_oAscCustomAutoFilter.isLessThanOrEqualTo;
		
		if(c_oAscCustomAutoFilter.equals === this.Operator || c_oAscCustomAutoFilter.doesNotEqual === this.Operator)
		{
			filterVal = isNaN(this.Val) ? this.Val.toLowerCase() : this.Val;
		}
		else if(isNumberFilter)
		{
			if(isNaN(this.Val) && isNaN(val))
			{
				filterVal =  this.Val;
			}
			else
			{
				filterVal =  parseFloat(this.Val);
				val = parseFloat(val);
			}
		}
		else
		{
			filterVal = isNaN(this.Val) ? this.Val.toLowerCase() : this.Val;
		}

		var trimVal = "string" === typeof(val) ? window["Asc"].trim(val) : val;
		var trimFilterVal = "string" === typeof(filterVal) ? window["Asc"].trim(filterVal) : filterVal;


		var matchingValues = function(val1, val2, op) {
			var matchingInfo = AscCommonExcel.matchingValue(new AscCommonExcel.cString(val1));
			if(op) {
				matchingInfo.op = op;
			}
			return AscCommonExcel.matching(new AscCommonExcel.cString(val2), matchingInfo);
		};

		switch (this.Operator)
		{
			case c_oAscCustomAutoFilter.equals://equals
			{
				if(!isDigitValue) {
					result = matchingValues(trimFilterVal, trimVal);
				} else if(trimVal === trimFilterVal) {
					result = true;
				}
				
				break;
			}
			case c_oAscCustomAutoFilter.doesNotEqual://doesNotEqual
			{
				if(!isDigitValue) {
					result = matchingValues(trimFilterVal, trimVal, "<>");
				} else if(trimVal !== trimFilterVal) {
					result = true;
				}
					
				break;
			}
			
			case c_oAscCustomAutoFilter.isGreaterThan://isGreaterThan
			{
				if(val > filterVal)
				{
					result = true;
				}	
				
				break;
			}
			case c_oAscCustomAutoFilter.isGreaterThanOrEqualTo://isGreaterThanOrEqualTo
			{
				if(val >= filterVal)
				{
					result = true;
				}	
				
				break;
			}
			case c_oAscCustomAutoFilter.isLessThan://isLessThan
			{
				if(val < filterVal)
				{
					result = true;
				}
				
				break;
			}
			case c_oAscCustomAutoFilter.isLessThanOrEqualTo://isLessThanOrEqualTo
			{
				if(val <= filterVal)
				{
					result = true;
				}
				
				break;
			}
			case c_oAscCustomAutoFilter.beginsWith://beginsWith
			{
				if(!isDigitValue)
				{
					if(val.startsWith(filterVal))
						result = true;
				}
				
				break;
			}
			case c_oAscCustomAutoFilter.doesNotBeginWith://doesNotBeginWith
			{
				if(!isDigitValue)
				{
					if(!val.startsWith(filterVal))
						result = true;
				}
				else
					result = true;
				
				break;
			}
			case c_oAscCustomAutoFilter.endsWith://endsWith
			{
				if(!isDigitValue)
				{
					if(val.endsWith(filterVal))
						result = true;
				}
				
				break;
			}
			case c_oAscCustomAutoFilter.doesNotEndWith://doesNotEndWith
			{
				if(!isDigitValue)
				{
					if(!val.endsWith(filterVal))
						result = true;
				}
				else
					result = true;
				
				break;
			}
			case c_oAscCustomAutoFilter.contains://contains
			{
				if(!isDigitValue)
				{
					if(val.indexOf(filterVal) !== -1)
						result = true;
				}
				
				break;
			}
			case c_oAscCustomAutoFilter.doesNotContain://doesNotContain
			{
				if(!isDigitValue)
				{
					if(val.indexOf(filterVal) === -1)
						result = true;
				}
				else
					result = true;
				
				break;
			}
		}
	}	
	
	return !result;
};

CustomFilter.prototype.asc_getOperator = function () { return this.Operator; };
CustomFilter.prototype.asc_getVal = function () { return this.Val; };

CustomFilter.prototype.asc_setOperator = function (val) { this.Operator = val; };
CustomFilter.prototype.asc_setVal = function (val) { this.Val = val; };

CustomFilter.prototype.check = function () {
	if(c_oAscCustomAutoFilter.doesNotEqual === this.Operator) {
		if("" === this.Val.replace(/ /g, "")){
			this.Val = " ";
		}
	}
};

CustomFilter.prototype._generateEmptyValueFilter = function () {
	this.Operator = c_oAscCustomAutoFilter.doesNotEqual;
	this.Val = " ";
};

var g_oDynamicFilter = {
	Type : 0,
	Val	: 1,
	MaxVal: 2
};

/** @constructor */
function DynamicFilter() {
	this.Properties = g_oDynamicFilter;
	
	this.Type = null;
	this.Val = null;
	this.MaxVal = null;
}
DynamicFilter.prototype.getType = function() {
	return UndoRedoDataTypes.DynamicFilter;
};
DynamicFilter.prototype.getProperties = function() {
	return this.Properties;
};
DynamicFilter.prototype.getProperty = function(nType) {
	switch (nType) {
		case this.Properties.Type: return this.Type; break;
		case this.Properties.Val: return this.Val; break;
		case this.Properties.MaxVal: return this.MaxVal; break;
	}
	return null;
};
DynamicFilter.prototype.setProperty = function(nType, value) {
	switch (nType) {
		case this.Properties.Type: this.Type = value;break;
		case this.Properties.Val: this.Val = value;break;
		case this.Properties.MaxVal: this.MaxVal = value;break;
	}
};
DynamicFilter.prototype.clone = function() {
	var res = new DynamicFilter();
	res.Type = this.Type;
	res.Val = this.Val;
	res.MaxVal = this.MaxVal;
	return res;
};

DynamicFilter.prototype.init = function(range) {
	var res = null;
	
	switch(this.Type)
	{
		case Asc.c_oAscDynamicAutoFilter.aboveAverage:
		case Asc.c_oAscDynamicAutoFilter.belowAverage:
		{
			var summ = 0;
			var counter = 0;
			
			range._foreachNoEmpty(function(cell){
				var val = parseFloat(cell.getValueWithoutFormat());
				
				if(!isNaN(val))
				{
					summ += parseFloat(val);
					counter++;
				}
				
			});
			res = summ / counter;
			
			break;
		}
	}
	
	this.Val = res;
};

DynamicFilter.prototype.isHideValue = function(val) {
	var res = false;
	
	switch(this.Type)
	{
		case Asc.c_oAscDynamicAutoFilter.aboveAverage:
		{
			res = val > this.Val ? false : true;
			break;
		}
		case Asc.c_oAscDynamicAutoFilter.belowAverage:
		{
			res = val < this.Val ? false : true;
			break;
		}
	}
	
	return res;
};

DynamicFilter.prototype.asc_getType = function () { return this.Type; };
DynamicFilter.prototype.asc_getVal = function () { return this.Val; };
DynamicFilter.prototype.asc_getMaxVal = function () { return this.MaxVal; };

DynamicFilter.prototype.asc_setType = function (val) { this.Type = val; };
DynamicFilter.prototype.asc_setVal = function (val) { this.Val = val; };
DynamicFilter.prototype.asc_setMaxVal = function (val) { this.MaxVal = val; };

var g_oColorFilter = {
	CellColor : 0,
	dxf	: 1
};

/** @constructor */
function ColorFilter() {
	this.Properties = g_oColorFilter;
	
	this.CellColor = null;
	this.dxf = null;
}
ColorFilter.prototype.getType = function() {
	return UndoRedoDataTypes.ColorFilter;
};
ColorFilter.prototype.getProperties = function() {
	return this.Properties;
};
ColorFilter.prototype.getProperty = function(nType) {
	switch (nType) {
		case this.Properties.CellColor: return this.CellColor; break;
		case this.Properties.dxf: return this.dxf; break;
	}
	return null;
};
ColorFilter.prototype.setProperty = function(nType, value) {
	switch (nType) {
		case this.Properties.CellColor: this.CellColor = value;break;
		case this.Properties.dxf: this.dxf = value;break;
	}
};
ColorFilter.prototype.clone = function() {
	var res = new ColorFilter();
	res.CellColor = this.CellColor;
	if (this.dxf) {
		res.dxf = this.dxf.clone();
	}
	return res;
};
ColorFilter.prototype.isHideValue = function(cell) {
	
	var res = true;
	var t = this;
	
	var isEqualColors = function(filterColor, cellColor)
	{
		var res = false;
		if(filterColor === cellColor)
		{
			res = true;
		}
		else if(!filterColor && (!cellColor || null === cellColor.rgb || 0 === cellColor.rgb))
		{
			res = true;
		}
		else if(!cellColor && (!filterColor || null === filterColor.rgb || 0 === filterColor.rgb))
		{
			res = true;
		}
		else if(cellColor && filterColor && cellColor.rgb === filterColor.rgb)
		{
			res = true;
		}
		
		return res;
	};
	
	if(this.dxf && this.dxf.fill && cell)
	{
		var filterColor = this.dxf.fill.bg;
		cell.getLeftTopCellNoEmpty(function(cell) {
			if(false === t.CellColor)//font color
			{
				var multiText;
				if(cell && (multiText = cell.getValueMultiText()) !== null)
				{
					for(var j = 0; j < multiText.length; j++)
					{
						var fontColor = multiText[j].format ? multiText[j].format.getColor() : null;
						if(isEqualColors(filterColor,fontColor ))
						{
							res = false;
							break;
						}
					}
				}
				else
				{
					var fontColor = cell && cell.xfs && cell.xfs.font ? cell.xfs.font.getColor() : null;
					if(isEqualColors(filterColor,fontColor))
					{
						res = false;
					}
				}
			}
			else
			{
				var color = cell ? cell.getStyle() : null;
				var cellColor =  color !== null && color.fill && color.fill.bg ? color.fill.bg : null;

				if(isEqualColors(filterColor, cellColor))
				{
					res = false;
				}
			}
		});
	}
	
	return res;
};

ColorFilter.prototype.asc_getCellColor = function () { return this.CellColor; };
ColorFilter.prototype.asc_getDxf = function () { return this.dxf; };

ColorFilter.prototype.asc_setCellColor = function (val) { this.CellColor = val; };
ColorFilter.prototype.asc_setDxf = function (val) { this.dxf = val; };
ColorFilter.prototype.asc_getCColor = function ()
{ 
	var res = null;
	
	if(this.dxf && this.dxf.fill && null !== this.dxf.fill.bg && null !== this.dxf.fill.bg.rgb)
	{
		var color = this.dxf.fill.bg;
		
		var res = new Asc.asc_CColor();
		res.asc_putR(color.getR());
		res.asc_putG(color.getG());
		res.asc_putB(color.getB());
		res.asc_putA(color.getA());
	}
	
	return res;
};
ColorFilter.prototype.asc_setCColor = function (asc_CColor) 
{
	if(!this.dxf)
	{
		this.dxf = new CellXfs();
	}
	
	if(!this.dxf.bg)
	{
		this.dxf.fill = new Fill();
	}
	
	if(null === asc_CColor)
	{
		this.dxf.fill.bg = new RgbColor();
		this.dxf.fill.bg.rgb = null;
	}
	else
	{
		this.dxf.fill.bg = new RgbColor((asc_CColor.asc_getR() << 16) + (asc_CColor.asc_getG() << 8) + asc_CColor.asc_getB());
	}
};

var g_oTop10 = {
	FilterVal : 0,
	Percent	: 1,
	Top: 2,
	Val: 3
};

/** @constructor */
function Top10() {
	this.Properties = g_oTop10;
	
	this.FilterVal = null;
	this.Percent = null;
	this.Top = null;
	this.Val = null;
}
Top10.prototype.getType = function() {
	return UndoRedoDataTypes.Top10;
};
Top10.prototype.getProperties = function() {
	return this.Properties;
};
Top10.prototype.getProperty = function(nType) {
	switch (nType) {
		case this.Properties.FilterVal: return this.FilterVal; break;
		case this.Properties.Percent: return this.Percent; break;
		case this.Properties.Top: return this.Top; break;
		case this.Properties.Val: return this.Val; break;
	}
	return null;
};
Top10.prototype.setProperty = function(nType, value) {
	switch (nType) {
		case this.Properties.FilterVal: this.FilterVal = value;break;
		case this.Properties.Percent: this.Percent = value;break;
		case this.Properties.Top: this.Top = value;break;
		case this.Properties.Val: this.Val = value;break;
	}
};
Top10.prototype.clone = function() {
	var res = new Top10();
	res.FilterVal = this.FilterVal;
	res.Percent = this.Percent;
	res.Top = this.Top;
	res.Val = this.Val;
	return res;
};
Top10.prototype.isHideValue = function(val) {
	// ToDo работает не совсем правильно.
	var res = false;
	
	if(null !== this.FilterVal)
	{
		if(this.Top)
		{
			if(val < this.FilterVal)
			{
				res = true;
			}
		}
		else
		{
			if(val > this.FilterVal)
			{
				res = true;
			}
		}
	}
	
	return res;
};

Top10.prototype.init = function(range, reWrite){
	var res = null;
	var t = this;
	
	if(null === this.FilterVal || true === reWrite)
	{	
		if(range)
		{
			var arr = [];
			var alreadyAddValues = {};
			var count = 0;
			range._setPropertyNoEmpty(null, null, function(cell){
				var val = parseFloat(cell.getValueWithoutFormat());
				
				if(!isNaN(val) && !alreadyAddValues[val])
				{
					arr.push(val);
					alreadyAddValues[val] = 1;
					count++;
				}
			});
			
			if(arr.length)
			{
				arr.sort(function(a, b){
					var res;
					if(t.Top)
					{
						res = b - a;
					}
					else
					{
						res = a - b;
					}
					
					return res; 
				});
				
				if(this.Percent)
				{
					var num = parseInt(count * (this.Val / 100));
					if(0 === num)
					{
						num = 1;
					}
					
					res = arr[num - 1];
				}
				else
				{
					res = arr[this.Val - 1];
				}
				
			}
		}
	}
	
	if(null !== res)
	{
		this.FilterVal = res;
	}
}; 

Top10.prototype.asc_getFilterVal = function () { return this.FilterVal; };
Top10.prototype.asc_getPercent = function () { return this.Percent; };
Top10.prototype.asc_getTop = function () { return this.Top; };
Top10.prototype.asc_getVal = function () { return this.Val; };

Top10.prototype.asc_setFilterVal = function (val) { this.FilterVal = val; };
Top10.prototype.asc_setPercent = function (val) { this.Percent = val; };
Top10.prototype.asc_setTop = function (val) { this.Top = val; };
Top10.prototype.asc_setVal = function (val) { this.Val = val; };

/** @constructor */
function SortCondition() {
	this.Ref = null;
	this.ConditionSortBy = null;
	this.ConditionDescending = null;
	this.dxf = null;
}
SortCondition.prototype.clone = function() {
	var res = new SortCondition();
	res.Ref = this.Ref ? this.Ref.clone() : null;
	res.ConditionSortBy = this.ConditionSortBy;
	res.ConditionDescending = this.ConditionDescending;
	if (this.dxf)
		res.dxf = this.dxf.clone();
	return res;
};
SortCondition.prototype.moveRef = function(col, row) {
	var ref = this.Ref.clone();
	ref.setOffset(new AscCommon.CellBase(row || 0, col || 0));
	
	this.Ref = ref;
};
SortCondition.prototype.changeColumns = function(activeRange, isDelete) {
	var bIsDeleteCurSortCondition = false;
	var ref = this.Ref.clone();
	var offsetCol = null;
	
	if(isDelete)
	{
		if(activeRange.c1 <= ref.c1 && activeRange.c2 >= ref.c1)
		{
			bIsDeleteCurSortCondition = true;
		}
		else if(activeRange.c1 < ref.c1)
		{
			offsetCol = -(activeRange.c2 - activeRange.c1 + 1);
		}
	}
	else
	{
		if(activeRange.c1 <= ref.c1)
		{
			offsetCol = activeRange.c2 - activeRange.c1 + 1;
		}
	}
	
	if(null !== offsetCol)
	{
		ref.setOffset(new AscCommon.CellBase(0, offsetCol));
		this.Ref = ref;
	}
	
	return bIsDeleteCurSortCondition;
};

SortCondition.prototype.getSortType = function() {
	var res = null;

	if(true === this.ConditionDescending) {
		res = Asc.c_oAscSortOptions.Ascending;
	} else if(false === this.ConditionDescending) {
		res = Asc.c_oAscSortOptions.Descending;
	} else if(Asc.ESortBy.sortbyCellColor === this.ConditionSortBy) {
		res = Asc.c_oAscSortOptions.ByColorFill;
	} else if(Asc.ESortBy.sortbyCellColor === this.sortbyFontColor) {
		res = Asc.c_oAscSortOptions.ByColorFont;
	}

	return res;
};

SortCondition.prototype.getSortColor = function() {
	var res = null;

	if(this.dxf) {
		if(this.dxf.fill && this.dxf.fill.bg) {
			res = this.dxf.fill.bg;
		} else if(this.dxf.font && this.dxf.font.c) {
			res = this.dxf.font.c;
		}
	}

	return res;
};

SortCondition.prototype.applySort = function(type, ref, color) {
	this.Ref = ref;

	if(type === Asc.c_oAscSortOptions.ByColorFill || type === Asc.c_oAscSortOptions.ByColorFont) {
		var newDxf;
		if (type === Asc.c_oAscSortOptions.ByColorFill) {
			newDxf = new AscCommonExcel.CellXfs();
			newDxf.fill = new AscCommonExcel.Fill();
			newDxf.fill.bg = color;
			this.ConditionSortBy = Asc.ESortBy.sortbyCellColor;
		} else {
			newDxf.font = new AscCommonExcel.Font();
			newDxf.font.setColor(color);
			this.ConditionSortBy = Asc.ESortBy.sortbyFontColor;
		}

		this.dxf = AscCommonExcel.g_StyleCache.addXf(newDxf, true);
	} else if(type === Asc.c_oAscSortOptions.Ascending || type === Asc.c_oAscSortOptions.Descending) {
		this.ConditionDescending = type !== Asc.c_oAscSortOptions.Ascending;
	}

};

function AutoFilterDateElem(start, end, dateTimeGrouping) {
	this.start = start;
	this.end = end;
	this.dateTimeGrouping = dateTimeGrouping;
} 
AutoFilterDateElem.prototype.clone = function() {
	var res = new AutoFilterDateElem();
	res.start = this.start;
	this.end = this.end;
	this.dateTimeGrouping = this.dateTimeGrouping;
	
	return res;
};
AutoFilterDateElem.prototype.convertDateGroupItemToRange = function(oDateGroupItem) {
	var startDate, endDate, date;
	switch(oDateGroupItem.DateTimeGrouping)
	{
		case 1://day
		{
			date = new cDate(Date.UTC( oDateGroupItem.Year, oDateGroupItem.Month - 1, oDateGroupItem.Day));
			startDate = date.getExcelDateWithTime();
			date.addDays(1)
			endDate = date.getExcelDateWithTime();
			break;
		}
		case 2://hour
		{
			startDate = new cDate(Date.UTC( oDateGroupItem.Year, oDateGroupItem.Month - 1, oDateGroupItem.Day, oDateGroupItem.Hour, 1)).getExcelDateWithTime();
			endDate = new cDate(Date.UTC( oDateGroupItem.Year, oDateGroupItem.Month - 1, oDateGroupItem.Day, oDateGroupItem.Hour, 59)).getExcelDateWithTime();
			break;
		}
		case 3://minute
		{
			startDate = new cDate(Date.UTC( oDateGroupItem.Year, oDateGroupItem.Month - 1, oDateGroupItem.Day, oDateGroupItem.Hour, oDateGroupItem.Minute, 1)).getExcelDateWithTime();
			endDate = new cDate(Date.UTC( oDateGroupItem.Year, oDateGroupItem.Month - 1, oDateGroupItem.Day, oDateGroupItem.Hour, oDateGroupItem.Minute, 59)).getExcelDateWithTime();
			break;
		}
		case 4://month
		{
			date = new cDate(Date.UTC( oDateGroupItem.Year, oDateGroupItem.Month - 1, 1));
			startDate = date.getExcelDateWithTime();
			date.addMonths(1)
			endDate = date.getExcelDateWithTime();
			break;
		}
		case 5://second
		{
			startDate = new cDate(Date.UTC( oDateGroupItem.Year, oDateGroupItem.Month - 1, oDateGroupItem.Day, oDateGroupItem.Hour, oDateGroupItem.Second)).getExcelDateWithTime();
			endDate = new cDate(Date.UTC( oDateGroupItem.Year, oDateGroupItem.Month - 1, oDateGroupItem.Day, oDateGroupItem.Hour, oDateGroupItem.Second )).getExcelDateWithTime();
			break;
		}
		case 6://year
		{
			date = new cDate(Date.UTC( oDateGroupItem.Year, 0));
			startDate = date.getExcelDateWithTime();
			date.addYears(1)
			endDate = date.getExcelDateWithTime();
			break;
		}
	}
	
	this.start = startDate;
	this.end = endDate;
	this.dateTimeGrouping = oDateGroupItem.DateTimeGrouping;
};

	if (typeof Map === 'undefined') {
		(function() {
			var Map = function() {
				this.storage = {};
			};
			Map.prototype = {
				set: function(key, value) {
					this.storage[key] = value;
				},
				get: function(key) {
					return this.storage[key];
				},
				delete: function(key) {
					delete this.storage[key];
				},
				has: function(key) {
					return !!this.storage[key];
				}
			};

			window.Map = Map;
		})();
	}
	/**
	 * @constructor
	 * @memberOf AscCommonExcel
	 */
	function CSharedStrings () {
		this.all = [];
		this.text = new Map();
		//
		this.multiText = [];
		this.multiTextIndex = [];
	}

	CSharedStrings.prototype.addText = function(text) {
		var index = this.text.get(text);
		if (undefined === index) {
			this.all.push(text);
			index = this.all.length;
			this.text.set(text, index);
			if (AscFonts.IsCheckSymbols) {
				AscFonts.FontPickerByCharacter.getFontsByString(text);
			}
		}
		return index;
	};
	CSharedStrings.prototype.addMultiText = function(multiText) {
		var index, i;
		for (i = 0; i < this.multiText.length; ++i) {
			if (AscCommonExcel.isEqualMultiText(multiText, this.multiText[i])) {
				index = this.multiTextIndex[i];
				break;
			}
		}
		if (undefined === index) {
			this.all.push(multiText);
			index = this.all.length;
			this.multiText.push(multiText);
			this.multiTextIndex.push(index);
			if (AscFonts.IsCheckSymbols) {
				for (i = 0; i < multiText.length; ++i) {
					AscFonts.FontPickerByCharacter.getFontsByString(multiText[i].text);
				}
			}
		}
		return index;
	};
	CSharedStrings.prototype.get = function(index) {
		return 1 <= index && index <= this.all.length ? this.all[index - 1] : null;
	};
	CSharedStrings.prototype.getCount = function() {
		return this.all.length;
	};
	CSharedStrings.prototype.generateFontMap = function(oFontMap) {
		for (var i = 0; i < this.multiText.length; ++i) {
			var multiText = this.multiText[i];
			for (var j = 0; j < multiText.length; ++j) {
				var part = multiText[j];
				if (null != part.format) {
					oFontMap[part.format.getName()] = 1;
				}
			}
		}
	};

	/**
	 * @constructor
	 * @memberOf AscCommonExcel
	 */
	function CWorkbookFormulas () {
		this.all = [];
	}

	CWorkbookFormulas.prototype.add = function(formula) {
		var index = formula.getIndexNumber();
		if (undefined === index) {
			this.all.push(formula);
			index = this.all.length;
			formula.setIndexNumber(index);
		}
		return formula;
	};
	CWorkbookFormulas.prototype.get = function(index) {
		return 1 <= index && index <= this.all.length ? this.all[index - 1] : null;
	};
	CWorkbookFormulas.prototype.getCount = function() {
		return this.all.length;
	};


	/** @constructor */
	function asc_CPageMargins (ws) {
		this.left = null;
		this.right = null;
		this.top = null;
		this.bottom = null;

		this.ws = ws;

		return this;
	}
	asc_CPageMargins.prototype.init = function () {
		if (null == this.left)
			this.left = c_oAscPrintDefaultSettings.PageLeftField;
		if (null == this.top)
			this.top = c_oAscPrintDefaultSettings.PageTopField;
		if (null == this.right)
			this.right = c_oAscPrintDefaultSettings.PageRightField;
		if (null == this.bottom)
			this.bottom = c_oAscPrintDefaultSettings.PageBottomField;
	};
	asc_CPageMargins.prototype.asc_getLeft = function () { return this.left; };
	asc_CPageMargins.prototype.asc_getRight = function () { return this.right; };
	asc_CPageMargins.prototype.asc_getTop = function () { return this.top; };
	asc_CPageMargins.prototype.asc_getBottom = function () { return this.bottom; };

	asc_CPageMargins.prototype.asc_setLeft = function (newVal) {
		var oldVal = this.left;
		this.left = newVal;
		if (this.ws && History.Is_On() && oldVal !== this.left) {
			History.Add(AscCommonExcel.g_oUndoRedoLayout, AscCH.historyitem_Layout_Left, this.ws.getId(),
				null, new UndoRedoData_Layout(oldVal, newVal));
		}
	};
	asc_CPageMargins.prototype.asc_setRight = function (newVal) {
		var oldVal = this.right;
		this.right = newVal;
		if (this.ws && History.Is_On() && oldVal !== this.right) {
			History.Add(AscCommonExcel.g_oUndoRedoLayout, AscCH.historyitem_Layout_Right, this.ws.getId(),
				null, new UndoRedoData_Layout(oldVal, newVal));
		}
	};
	asc_CPageMargins.prototype.asc_setTop = function (newVal) {
		var oldVal = this.top;
		this.top = newVal;
		if (this.ws && History.Is_On() && oldVal !== this.top) {
			History.Add(AscCommonExcel.g_oUndoRedoLayout, AscCH.historyitem_Layout_Top, this.ws.getId(),
				null, new UndoRedoData_Layout(oldVal, newVal));
		}
	};
	asc_CPageMargins.prototype.asc_setBottom = function (newVal) {
		var oldVal = this.bottom;
		this.bottom = newVal;
		if (this.ws && History.Is_On() && oldVal !== this.bottom) {
			History.Add(AscCommonExcel.g_oUndoRedoLayout, AscCH.historyitem_Layout_Bottom, this.ws.getId(),
				null, new UndoRedoData_Layout(oldVal, newVal));
		}
	};
	asc_CPageMargins.prototype.asc_setOptions = function (obj) {
		var prop;
		prop = obj.asc_getLeft();
		if(prop !== this.asc_getLeft()) {
			this.asc_setLeft(prop);
		}
		prop = obj.asc_getRight();
		if(prop !== this.asc_getRight()) {
			this.asc_setRight(prop);
		}
		prop = obj.asc_getBottom();
		if(prop !== this.asc_getBottom()) {
			this.asc_setBottom(prop);
		}
		prop = obj.asc_getTop();
		if(prop !== this.asc_getTop()) {
			this.asc_setTop(prop);
		}
	};

	/** @constructor */
	function asc_CPageSetup(ws) {
		this.orientation = c_oAscPrintDefaultSettings.PageOrientation;
		this.width = c_oAscPrintDefaultSettings.PageWidth;
		this.height = c_oAscPrintDefaultSettings.PageHeight;

		this.fitToWidth = false; //ToDo can be a number
		this.fitToHeight = false; //ToDo can be a number

		// ToDo
		this.blackAndWhite = false;
		this.cellComments = 0; // none ST_CellComments
		this.copies = 1;
		this.draft = false;
		this.errors = 0; // displayed ST_PrintError
		this.firstPageNumber = -1;
		this.pageOrder = 0; // downThenOver ST_PageOrder
		this.scale = 100;
		this.useFirstPageNumber = false;
		this.usePrinterDefaults = true;

		this.ws = ws;

		return this;
	}
	asc_CPageSetup.prototype.asc_getOrientation = function () { return this.orientation; };
	asc_CPageSetup.prototype.asc_getWidth = function () { return this.width; };
	asc_CPageSetup.prototype.asc_getHeight = function () { return this.height; };

	asc_CPageSetup.prototype.asc_setOrientation = function (newVal) {
		var oldVal = this.orientation;
		this.orientation = newVal;
		if (this.ws && History.Is_On() && oldVal !== this.orientation) {
			History.Add(AscCommonExcel.g_oUndoRedoLayout, AscCH.historyitem_Layout_Orientation, this.ws.getId(),
				null, new UndoRedoData_Layout(oldVal, newVal));
		}
	};
	asc_CPageSetup.prototype.asc_setWidth = function (newVal) {
		var oldVal = this.width;
		this.width = newVal;
		if (this.ws && History.Is_On() && oldVal !== this.width) {
			History.Add(AscCommonExcel.g_oUndoRedoLayout, AscCH.historyitem_Layout_Width, this.ws.getId(),
				null, new UndoRedoData_Layout(oldVal, newVal));
		}
	};
	asc_CPageSetup.prototype.asc_setHeight = function (newVal) {
		var oldVal = this.height;
		this.height = newVal;
		if (this.ws && History.Is_On() && oldVal !== this.height) {
			History.Add(AscCommonExcel.g_oUndoRedoLayout, AscCH.historyitem_Layout_Height, this.ws.getId(),
				null, new UndoRedoData_Layout(oldVal, newVal));
		}
	};

	asc_CPageSetup.prototype.asc_getFitToWidth = function () { return this.fitToWidth; };
	asc_CPageSetup.prototype.asc_getFitToHeight = function () { return this.fitToHeight; };

	asc_CPageSetup.prototype.asc_setFitToWidth = function (newVal) {
		var oldVal = this.fitToWidth;
		this.fitToWidth = newVal;
		if (this.ws && History.Is_On() && oldVal !== this.fitToWidth) {
			History.Add(AscCommonExcel.g_oUndoRedoLayout, AscCH.historyitem_Layout_FitToWidth, this.ws.getId(),
				null, new UndoRedoData_Layout(oldVal, newVal));
		}
	};
	asc_CPageSetup.prototype.asc_setFitToHeight = function (newVal) {
		var oldVal = this.fitToHeight;
		this.fitToHeight = newVal;
		if (this.ws && History.Is_On() && oldVal !== this.fitToHeight) {
			History.Add(AscCommonExcel.g_oUndoRedoLayout, AscCH.historyitem_Layout_FitToHeight, this.ws.getId(),
				null, new UndoRedoData_Layout(oldVal, newVal));
		}
	};
	asc_CPageSetup.prototype.asc_setOptions = function (obj) {

		var prop;
		prop = obj.asc_getOrientation();
		if(prop !== this.asc_getOrientation()) {
			this.asc_setOrientation(prop);
		}
		prop = obj.asc_getWidth();
		if(prop !== this.asc_getWidth()) {
			this.asc_setWidth(prop);
		}
		prop = obj.asc_getHeight();
		if(prop !== this.asc_getHeight()) {
			this.asc_setHeight(prop);
		}
		prop = obj.asc_getHeight();
		if(prop !== this.asc_getHeight()) {
			this.asc_setHeight(prop);
		}
		prop = obj.asc_getFitToWidth();
		if(prop !== this.asc_getFitToWidth()) {
			this.asc_setFitToWidth(prop);
		}
		prop = obj.asc_getFitToHeight();
		if(prop !== this.asc_getFitToHeight()) {
			this.asc_setFitToHeight(prop);
		}
	};

	/** @constructor */
	//этот объект используется как в модели, так и в меню для передачи измененных опций page layout
	//если определена ws - это означает, что этот объект лежит в модели и при изменении его свойств идёт запись в историю
	//в противном случае запись в историю не происходит
	function asc_CPageOptions(ws) {
		this.pageMargins = new asc_CPageMargins(ws);
		this.pageSetup = new asc_CPageSetup(ws);
		this.gridLines = null;
		this.headings = null;
		this.ws = ws;

		return this;
	}
	asc_CPageOptions.prototype.init = function () {
		this.pageMargins.init();

		if (null == this.gridLines)
			this.gridLines = c_oAscPrintDefaultSettings.PageGridLines;
		if (null == this.headings)
			this.headings = c_oAscPrintDefaultSettings.PageHeadings;
	};
	asc_CPageOptions.prototype.asc_getPageMargins = function () { return this.pageMargins; };
	asc_CPageOptions.prototype.asc_getPageSetup = function () { return this.pageSetup; };
	asc_CPageOptions.prototype.asc_getGridLines = function () { return this.gridLines; };
	asc_CPageOptions.prototype.asc_getHeadings = function () { return this.headings; };
	//методы только для меню, без добавляем в историю
	asc_CPageOptions.prototype.asc_setPageMargins = function (val) { this.pageMargins = val; };
	asc_CPageOptions.prototype.asc_setPageSetup = function (val) { this.pageSetup = val; };

	asc_CPageOptions.prototype.asc_setGridLines = function (newVal) {
		var oldVal = this.gridLines;
		this.gridLines = newVal;
		if (this.ws && History.Is_On() && oldVal !== this.gridLines) {
			History.Add(AscCommonExcel.g_oUndoRedoLayout, AscCH.historyitem_Layout_GridLines, this.ws.getId(),
				null, new UndoRedoData_Layout(oldVal, newVal));
		}
	};
	asc_CPageOptions.prototype.asc_setHeadings = function (newVal) {
		var oldVal = this.headings;
		this.headings = newVal;
		if (this.ws && History.Is_On() && oldVal !== this.headings) {
			History.Add(AscCommonExcel.g_oUndoRedoLayout, AscCH.historyitem_Layout_Headings, this.ws.getId(),
				null, new UndoRedoData_Layout(oldVal, newVal));
		}
	};
	asc_CPageOptions.prototype.asc_setOptions = function (obj) {
		var gridLines = obj.asc_getGridLines();
		if(gridLines !== this.asc_getGridLines()) {
			this.asc_setGridLines(gridLines);
		}
		var heading = obj.asc_getHeadings();
		if(gridLines !== this.asc_getHeadings()) {
			this.asc_setHeadings(heading);
		}

		this.asc_getPageMargins().asc_setOptions(obj.asc_getPageMargins());
		this.asc_getPageSetup().asc_setOptions(obj.asc_getPageSetup());
	};

	//----------------------------------------------------------export----------------------------------------------------
	var prot;
	window['Asc'] = window['Asc'] || {};
	window['AscCommonExcel'] = window['AscCommonExcel'] || {};
	window['AscCommonExcel'].g_oColorManager = g_oColorManager;
	window['AscCommonExcel'].g_oDefaultFormat = g_oDefaultFormat;
	window['AscCommonExcel'].g_nColorTextDefault = g_nColorTextDefault;
	window['AscCommonExcel'].g_nColorHyperlink = g_nColorHyperlink;
	window['AscCommonExcel'].g_oThemeColorsDefaultModsSpreadsheet = g_oThemeColorsDefaultModsSpreadsheet;
	window['AscCommonExcel'].g_StyleCache = g_StyleCache;
	window['AscCommonExcel'].map_themeExcel_to_themePresentation = map_themeExcel_to_themePresentation;
	window['AscCommonExcel'].g_nRowStructSize = g_nRowStructSize;
	window['AscCommonExcel'].shiftGetBBox = shiftGetBBox;
	window['AscCommonExcel'].getStringFromMultiText = getStringFromMultiText;
	window['AscCommonExcel'].isEqualMultiText = isEqualMultiText;
	window['AscCommonExcel'].RgbColor = RgbColor;
	window['AscCommonExcel'].createRgbColor = createRgbColor;
	window['AscCommonExcel'].ThemeColor = ThemeColor;
	window['AscCommonExcel'].CorrectAscColor = CorrectAscColor;
	window['AscCommonExcel'].Fragment = Fragment;
	window['AscCommonExcel'].Font = Font;
	window['AscCommonExcel'].Fill = Fill;
	window['AscCommonExcel'].BorderProp = BorderProp;
	window['AscCommonExcel'].Border = Border;
	window['AscCommonExcel'].Num = Num;
	window['AscCommonExcel'].CellXfs = CellXfs;
	window['AscCommonExcel'].Align = Align;
	window['AscCommonExcel'].CCellStyles = CCellStyles;
	window['AscCommonExcel'].CCellStyle = CCellStyle;
	window['AscCommonExcel'].StyleManager = StyleManager;
	window['AscCommonExcel'].SheetMergedStyles = SheetMergedStyles;
	window['AscCommonExcel'].Hyperlink = Hyperlink;
	window['AscCommonExcel'].SheetFormatPr = SheetFormatPr;
	window['AscCommonExcel'].Col = Col;
	window['AscCommonExcel'].Row = Row;
	window['AscCommonExcel'].CMultiTextElem = CMultiTextElem;
	window['AscCommonExcel'].CCellValue = CCellValue;
	window['AscCommonExcel'].RangeDataManagerElem = RangeDataManagerElem;
	window['AscCommonExcel'].RangeDataManager = RangeDataManager;
	window['AscCommonExcel'].CSharedStrings = CSharedStrings;
	window['AscCommonExcel'].CWorkbookFormulas = CWorkbookFormulas;
	window["Asc"]["sparklineGroup"] = window['AscCommonExcel'].sparklineGroup = sparklineGroup;
	prot = sparklineGroup.prototype;
	prot["asc_getId"] = prot.asc_getId;
	prot["asc_getType"] = prot.asc_getType;
	prot["asc_getLineWeight"] = prot.asc_getLineWeight;
	prot["asc_getDisplayEmpty"] = prot.asc_getDisplayEmpty;
	prot["asc_getMarkersPoint"] = prot.asc_getMarkersPoint;
	prot["asc_getHighPoint"] = prot.asc_getHighPoint;
	prot["asc_getLowPoint"] = prot.asc_getLowPoint;
	prot["asc_getFirstPoint"] = prot.asc_getFirstPoint;
	prot["asc_getLastPoint"] = prot.asc_getLastPoint;
	prot["asc_getNegativePoint"] = prot.asc_getNegativePoint;
	prot["asc_getDisplayXAxis"] = prot.asc_getDisplayXAxis;
	prot["asc_getDisplayHidden"] = prot.asc_getDisplayHidden;
	prot["asc_getMinAxisType"] = prot.asc_getMinAxisType;
	prot["asc_getMaxAxisType"] = prot.asc_getMaxAxisType;
	prot["asc_getRightToLeft"] = prot.asc_getRightToLeft;
	prot["asc_getManualMax"] = prot.asc_getManualMax;
	prot["asc_getManualMin"] = prot.asc_getManualMin;
	prot["asc_getColorSeries"] = prot.asc_getColorSeries;
	prot["asc_getColorNegative"] = prot.asc_getColorNegative;
	prot["asc_getColorAxis"] = prot.asc_getColorAxis;
	prot["asc_getColorMarkers"] = prot.asc_getColorMarkers;
	prot["asc_getColorFirst"] = prot.asc_getColorFirst;
	prot["asc_getColorLast"] = prot.asc_getColorLast;
	prot["asc_getColorHigh"] = prot.asc_getColorHigh;
	prot["asc_getColorLow"] = prot.asc_getColorLow;
	prot["asc_getDataRanges"] = prot.asc_getDataRanges;
	prot["asc_setType"] = prot.asc_setType;
	prot["asc_setLineWeight"] = prot.asc_setLineWeight;
	prot["asc_setDisplayEmpty"] = prot.asc_setDisplayEmpty;
	prot["asc_setMarkersPoint"] = prot.asc_setMarkersPoint;
	prot["asc_setHighPoint"] = prot.asc_setHighPoint;
	prot["asc_setLowPoint"] = prot.asc_setLowPoint;
	prot["asc_setFirstPoint"] = prot.asc_setFirstPoint;
	prot["asc_setLastPoint"] = prot.asc_setLastPoint;
	prot["asc_setNegativePoint"] = prot.asc_setNegativePoint;
	prot["asc_setDisplayXAxis"] = prot.asc_setDisplayXAxis;
	prot["asc_setDisplayHidden"] = prot.asc_setDisplayHidden;
	prot["asc_setMinAxisType"] = prot.asc_setMinAxisType;
	prot["asc_setMaxAxisType"] = prot.asc_setMaxAxisType;
	prot["asc_setRightToLeft"] = prot.asc_setRightToLeft;
	prot["asc_setManualMax"] = prot.asc_setManualMax;
	prot["asc_setManualMin"] = prot.asc_setManualMin;
	prot["asc_setColorSeries"] = prot.asc_setColorSeries;
	prot["asc_setColorNegative"] = prot.asc_setColorNegative;
	prot["asc_setColorAxis"] = prot.asc_setColorAxis;
	prot["asc_setColorMarkers"] = prot.asc_setColorMarkers;
	prot["asc_setColorFirst"] = prot.asc_setColorFirst;
	prot["asc_setColorLast"] = prot.asc_setColorLast;
	prot["asc_setColorHigh"] = prot.asc_setColorHigh;
	prot["asc_setColorLow"] = prot.asc_setColorLow;
	prot["asc_getStyles"] = prot.asc_getStyles;
	prot["asc_setStyle"] = prot.asc_setStyle;
	window['AscCommonExcel'].sparkline = sparkline;
	window['AscCommonExcel'].TablePart = TablePart;
	window['AscCommonExcel'].AutoFilter = AutoFilter;
	window['AscCommonExcel'].SortState = SortState;
	window['AscCommonExcel'].TableColumn = TableColumn;
	window['AscCommonExcel'].TableStyleInfo = TableStyleInfo;
	window['AscCommonExcel'].FilterColumn = FilterColumn;
	window['AscCommonExcel'].Filters = Filters;
	window['AscCommonExcel'].Filter = Filter;
	window['AscCommonExcel'].DateGroupItem = DateGroupItem;
	window['AscCommonExcel'].SortCondition = SortCondition;
	window['AscCommonExcel'].AutoFilterDateElem = AutoFilterDateElem;

	window["Asc"]["CustomFilters"]			= window["Asc"].CustomFilters = CustomFilters;
	prot									= CustomFilters.prototype;
	prot["asc_getAnd"]						= prot.asc_getAnd;
	prot["asc_getCustomFilters"]			= prot.asc_getCustomFilters;
	prot["asc_setAnd"]						= prot.asc_setAnd;
	prot["asc_setCustomFilters"]			= prot.asc_setCustomFilters;

	window["Asc"]["CustomFilter"]			= window["Asc"].CustomFilter = CustomFilter;
	prot									= CustomFilter.prototype;
	prot["asc_getOperator"]					= prot.asc_getOperator;
	prot["asc_getVal"]						= prot.asc_getVal;
	prot["asc_setOperator"]					= prot.asc_setOperator;
	prot["asc_setVal"]						= prot.asc_setVal;

	window["Asc"]["DynamicFilter"]			= window["Asc"].DynamicFilter = DynamicFilter;
	prot									= DynamicFilter.prototype;
	prot["asc_getType"]						= prot.asc_getType;
	prot["asc_getVal"]						= prot.asc_getVal;
	prot["asc_getMaxVal"]					= prot.asc_getMaxVal;
	prot["asc_setType"]						= prot.asc_setType;
	prot["asc_setVal"]						= prot.asc_setVal;
	prot["asc_setMaxVal"]					= prot.asc_setMaxVal;

	window["Asc"]["ColorFilter"]			= window["Asc"].ColorFilter = ColorFilter;
	prot									= ColorFilter.prototype;
	prot["asc_getCellColor"]				= prot.asc_getCellColor;
	prot["asc_getCColor"]					= prot.asc_getCColor;
	prot["asc_getDxf"]						= prot.asc_getDxf;
	prot["asc_setCellColor"]				= prot.asc_setCellColor;
	prot["asc_setDxf"]						= prot.asc_setDxf;
	prot["asc_setCColor"]					= prot.asc_setCColor;

	window["Asc"]["Top10"]					= window["Asc"].Top10 = Top10;
	prot									= Top10.prototype;
	prot["asc_getFilterVal"]				= prot.asc_getFilterVal;
	prot["asc_getPercent"]					= prot.asc_getPercent;
	prot["asc_getTop"]						= prot.asc_getTop;
	prot["asc_getVal"]						= prot.asc_getVal;
	prot["asc_setFilterVal"]				= prot.asc_setFilterVal;
	prot["asc_setPercent"]					= prot.asc_setPercent;
	prot["asc_setTop"]						= prot.asc_setTop;
	prot["asc_setVal"]						= prot.asc_setVal;

	window["Asc"]["TreeRBNode"]			= window["Asc"].TreeRBNode = TreeRBNode;
	window["Asc"]["TreeRB"]			= window["Asc"].TreeRB = TreeRB;
	prot									= TreeRB.prototype;
	prot["insertOrGet"]						= prot.insertOrGet;
	prot["deleteNode"]			= prot.deleteNode;
	prot["enumerate"]						= prot.enumerate;
	prot["getElem"]			= prot.getElem;
	prot["getNodeAll"]			= prot.getNodeAll;
	prot["isEmpty"]			= prot.getNodeAll;


	window["Asc"]["asc_CPageMargins"] = window["Asc"].asc_CPageMargins = asc_CPageMargins;
	prot = asc_CPageMargins.prototype;
	prot["asc_getLeft"] = prot.asc_getLeft;
	prot["asc_getRight"] = prot.asc_getRight;
	prot["asc_getTop"] = prot.asc_getTop;
	prot["asc_getBottom"] = prot.asc_getBottom;
	prot["asc_setLeft"] = prot.asc_setLeft;
	prot["asc_setRight"] = prot.asc_setRight;
	prot["asc_setTop"] = prot.asc_setTop;
	prot["asc_setBottom"] = prot.asc_setBottom;

	window["Asc"]["asc_CPageSetup"] = window["Asc"].asc_CPageSetup = asc_CPageSetup;
	prot = asc_CPageSetup.prototype;
	prot["asc_getOrientation"] = prot.asc_getOrientation;
	prot["asc_getWidth"] = prot.asc_getWidth;
	prot["asc_getHeight"] = prot.asc_getHeight;
	prot["asc_setOrientation"] = prot.asc_setOrientation;
	prot["asc_setWidth"] = prot.asc_setWidth;
	prot["asc_setHeight"] = prot.asc_setHeight;
	prot["asc_getFitToWidth"] = prot.asc_getFitToWidth;
	prot["asc_getFitToHeight"] = prot.asc_getFitToHeight;
	prot["asc_setFitToWidth"] = prot.asc_setFitToWidth;
	prot["asc_setFitToHeight"] = prot.asc_setFitToHeight;

	window["Asc"]["asc_CPageOptions"] = window["Asc"].asc_CPageOptions = asc_CPageOptions;
	prot = asc_CPageOptions.prototype;
	prot["asc_getPageMargins"] = prot.asc_getPageMargins;
	prot["asc_getPageSetup"] = prot.asc_getPageSetup;
	prot["asc_getGridLines"] = prot.asc_getGridLines;
	prot["asc_getHeadings"] = prot.asc_getHeadings;
	prot["asc_setPageMargins"] = prot.asc_setPageMargins;
	prot["asc_setPageSetup"] = prot.asc_setPageSetup;
	prot["asc_setGridLines"] = prot.asc_setGridLines;
	prot["asc_setHeadings"] = prot.asc_setHeadings;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

// Import
	var g_memory = AscFonts.g_memory;

	var CellValueType = AscCommon.CellValueType;
	var c_oAscBorderStyles = AscCommon.c_oAscBorderStyles;
	var fSortAscending = AscCommon.fSortAscending;
	var parserHelp = AscCommon.parserHelp;
	var oNumFormatCache = AscCommon.oNumFormatCache;
	var gc_nMaxRow0 = AscCommon.gc_nMaxRow0;
	var gc_nMaxCol0 = AscCommon.gc_nMaxCol0;
	var g_oCellAddressUtils = AscCommon.g_oCellAddressUtils;
	var AscBrowser = AscCommon.AscBrowser;
	var CellAddress = AscCommon.CellAddress;
	var isRealObject = AscCommon.isRealObject;
	var History = AscCommon.History;
	var cBoolLocal = AscCommon.cBoolLocal;
	var cErrorLocal = AscCommon.cErrorLocal;
	var cErrorOrigin = AscCommon.cErrorOrigin;
	var c_oAscNumFormatType = Asc.c_oAscNumFormatType;

	var UndoRedoItemSerializable = AscCommonExcel.UndoRedoItemSerializable;
	var UndoRedoData_CellSimpleData = AscCommonExcel.UndoRedoData_CellSimpleData;
	var UndoRedoData_CellValueData = AscCommonExcel.UndoRedoData_CellValueData;
	var UndoRedoData_FromToRowCol = AscCommonExcel.UndoRedoData_FromToRowCol;
	var UndoRedoData_FromTo = AscCommonExcel.UndoRedoData_FromTo;
	var UndoRedoData_IndexSimpleProp = AscCommonExcel.UndoRedoData_IndexSimpleProp;
	var UndoRedoData_BBox = AscCommonExcel.UndoRedoData_BBox;
	var UndoRedoData_SheetAdd = AscCommonExcel.UndoRedoData_SheetAdd;
	var UndoRedoData_DefinedNames = AscCommonExcel.UndoRedoData_DefinedNames;
	var g_oDefaultFormat = AscCommonExcel.g_oDefaultFormat;
	var g_StyleCache = AscCommonExcel.g_StyleCache;
	var Border = AscCommonExcel.Border;
	var RangeDataManagerElem = AscCommonExcel.RangeDataManagerElem;
	var RangeDataManager = AscCommonExcel.RangeDataManager;

	var cElementType = AscCommonExcel.cElementType;

	var parserFormula = AscCommonExcel.parserFormula;

	var c_oAscError = Asc.c_oAscError;
	var c_oAscInsertOptions = Asc.c_oAscInsertOptions;
	var c_oAscDeleteOptions = Asc.c_oAscDeleteOptions;
	var c_oAscGetDefinedNamesList = Asc.c_oAscGetDefinedNamesList;
	var c_oAscDefinedNameReason = Asc.c_oAscDefinedNameReason;
	var c_oNotifyType = AscCommon.c_oNotifyType;
	var g_cCalcRecursion = AscCommonExcel.g_cCalcRecursion;

	var g_nVerticalTextAngle = 255;
	//определяется в WorksheetView.js
	var oDefaultMetrics = {
		ColWidthChars: 0,
		RowHeight: 0
	};
	var g_sNewSheetNamePattern = "Sheet";
	var g_nSheetNameMaxLength = 31;
	var g_nAllColIndex = -1;
	var g_nAllRowIndex = -1;
	var aStandartNumFormats = [];
	var aStandartNumFormatsId = {};
	var oFormulaLocaleInfo = {
		Parse: true,
		DigitSep: true
	};

	(function(){
		aStandartNumFormats[0] = "General";
		aStandartNumFormats[1] = "0";
		aStandartNumFormats[2] = "0.00";
		aStandartNumFormats[3] = "#,##0";
		aStandartNumFormats[4] = "#,##0.00";
		aStandartNumFormats[9] = "0%";
		aStandartNumFormats[10] = "0.00%";
		aStandartNumFormats[11] = "0.00E+00";
		aStandartNumFormats[12] = "# ?/?";
		aStandartNumFormats[13] = "# ??/??";
		aStandartNumFormats[14] = "m/d/yyyy";
		aStandartNumFormats[15] = "d-mmm-yy";
		aStandartNumFormats[16] = "d-mmm";
		aStandartNumFormats[17] = "mmm-yy";
		aStandartNumFormats[18] = "h:mm AM/PM";
		aStandartNumFormats[19] = "h:mm:ss AM/PM";
		aStandartNumFormats[20] = "h:mm";
		aStandartNumFormats[21] = "h:mm:ss";
		aStandartNumFormats[22] = "m/d/yyyy h:mm";
		aStandartNumFormats[37] = "#,##0_);(#,##0)";
		aStandartNumFormats[38] = "#,##0_);[Red](#,##0)";
		aStandartNumFormats[39] = "#,##0.00_);(#,##0.00)";
		aStandartNumFormats[40] = "#,##0.00_);[Red](#,##0.00)";
		aStandartNumFormats[45] = "mm:ss";
		aStandartNumFormats[46] = "[h]:mm:ss";
		aStandartNumFormats[47] = "mm:ss.0";
		aStandartNumFormats[48] = "##0.0E+0";
		aStandartNumFormats[49] = "@";
		for(var i in aStandartNumFormats)
		{
			aStandartNumFormatsId[aStandartNumFormats[i]] = i - 0;
		}
	})();

	var c_oRangeType =
		{
			Range:0,
			Col:1,
			Row:2,
			All:3
		};
	var c_oSharedShiftType = {
		Processed: 1,
		NeedTransform: 2,
		PreProcessed: 3
	};
	var emptyStyleComponents = {table: [], conditional: []};
	function getRangeType(oBBox){
		if(null == oBBox)
			oBBox = this.bbox;
		if(oBBox.c1 == 0 && gc_nMaxCol0 == oBBox.c2 && oBBox.r1 == 0 && gc_nMaxRow0 == oBBox.r2)
			return c_oRangeType.All;
		if(oBBox.c1 == 0 && gc_nMaxCol0 == oBBox.c2)
			return c_oRangeType.Row;
		else if(oBBox.r1 == 0 && gc_nMaxRow0 == oBBox.r2)
			return c_oRangeType.Col;
		else
			return c_oRangeType.Range;
	}

	function getCompiledStyleFromArray(xf, xfs) {
		for (var i = 0; i < xfs.length; ++i) {
			if (null == xf) {
				xf = xfs[i];
			} else {
				xf = xf.merge(xfs[i]);
			}
		}
		return xf;
	}
	function getCompiledStyle(sheetMergedStyles, hiddenManager, nRow, nCol, opt_cell, opt_ws, opt_styleComponents) {
		var styleComponents = opt_styleComponents ? opt_styleComponents : sheetMergedStyles.getStyle(hiddenManager, nRow, nCol, opt_ws);
		var xf = getCompiledStyleFromArray(null, styleComponents.table);
		if (opt_cell) {
			if (null === xf) {
				xf = opt_cell.xfs;
			} else if (opt_cell.xfs) {
				xf = xf.merge(opt_cell.xfs, true);
			}
		} else if (opt_ws) {
			opt_ws._getRowNoEmpty(nRow, function(row){
				if(row && null != row.xfs){
					xf = null === xf ? row.xfs : xf.merge(row.xfs, true);
				} else {
					var col = opt_ws._getColNoEmptyWithAll(nCol);
					if(null != col && null != col.xfs){
						xf = null === xf ? col.xfs : xf.merge(col.xfs, true);
					}
				}
			});

		}
		xf = getCompiledStyleFromArray(xf, styleComponents.conditional);
		return xf;
	}

	function getDefNameIndex(name) {
		//uniqueness is checked without capitalization
		return name ? name.toLowerCase() : name;
	}

	function getDefNameId(sheetId, name) {
		if (sheetId) {
			return sheetId + AscCommon.g_cCharDelimiter + getDefNameIndex(name);
		} else {
			return getDefNameIndex(name);
		}
	}

	var g_FDNI = {sheetId: null, name: null};

	function getFromDefNameId(nodeId) {
		var index = nodeId ? nodeId.indexOf(AscCommon.g_cCharDelimiter) : -1;
		if (-1 != index) {
			g_FDNI.sheetId = nodeId.substring(0, index);
			g_FDNI.name = nodeId.substring(index + 1);
		} else {
			g_FDNI.sheetId = null;
			g_FDNI.name = nodeId;
		}
	}

	function DefName(wb, name, ref, sheetId, hidden, isTable) {
		this.wb = wb;
		this.name = name;
		this.ref = ref;
		this.sheetId = sheetId;
		this.hidden = hidden;
		this.isTable = isTable;

		this.isLock = null;
		this.parsedRef = null;
	}

	DefName.prototype = {
		clone: function(wb){
			return new DefName(wb, this.name, this.ref, this.sheetId, this.hidden, this.isTable);
		},
		removeDependencies: function() {
			if (this.parsedRef) {
				this.parsedRef.removeDependencies();
				this.parsedRef = null;
			}
		},
		setRef: function(ref, opt_noRemoveDependencies, opt_forceBuild, opt_open) {
			if(!opt_noRemoveDependencies){
				this.removeDependencies();
			}
			//для R1C1: ref - всегда строка в виде A1B1
			//флаг opt_open - на открытие, undo/redo, принятие изменений - строка приходит в виде A1B1 - преобразовывать не нужно
			//во всех остальных случаях парсим ref и заменяем на формат A1B1
			opt_open = opt_open || this.wb.bRedoChanges || this.wb.bUndoChanges;

			this.ref = ref;
			//all ref should be 3d, so worksheet can be anyone
			this.parsedRef = new parserFormula(ref, this, AscCommonExcel.g_DefNameWorksheet);
			this.parsedRef.setIsTable(this.isTable);
			if (opt_forceBuild) {
				var oldR1C1mode = AscCommonExcel.g_R1C1Mode;
				if(opt_open) {
					AscCommonExcel.g_R1C1Mode = false;
				}
				this.parsedRef.parse();
				if(opt_open) {
					AscCommonExcel.g_R1C1Mode = oldR1C1mode;
				}
				this.parsedRef.buildDependencies();
			} else {
				if(!opt_open) {
					this.parsedRef.parse();
					this.ref = this.parsedRef.assemble();
				}
				this.wb.dependencyFormulas.addToBuildDependencyDefName(this);
			}
		},
		getRef: function(bLocale) {
			//R1C1 - отдаём в зависимости от флага bLocale(для меню в виде R1C1)
			var res;
			if(!this.parsedRef.isParsed) {
				var oldR1C1mode = AscCommonExcel.g_R1C1Mode;
				AscCommonExcel.g_R1C1Mode = false;
				this.parsedRef.parse();
				AscCommonExcel.g_R1C1Mode = oldR1C1mode;
			}
			if(bLocale) {
				res = this.parsedRef.assembleLocale(AscCommonExcel.cFormulaFunctionToLocale, true);
			} else {
				res = this.parsedRef.assemble();
			}
			return res;
		},
		getNodeId: function() {
			return getDefNameId(this.sheetId, this.name);
		},
		getAscCDefName: function(bLocale) {
			var index = null;
			if (this.sheetId) {
				var sheet = this.wb.getWorksheetById(this.sheetId);
				index = sheet.getIndex();
			}
			return new Asc.asc_CDefName(this.name, this.getRef(bLocale), index, this.isTable, this.hidden, this.isLock);
		},
		getUndoDefName: function() {
			return new UndoRedoData_DefinedNames(this.name, this.ref, this.sheetId, this.isTable);
		},
		setUndoDefName: function(newUndoName) {
			this.name = newUndoName.name;
			this.sheetId = newUndoName.sheetId;
			this.hidden = false;
			this.isTable = newUndoName.isTable;
			if (this.ref != newUndoName.ref) {
				this.setRef(newUndoName.ref);
			}
		},
		onFormulaEvent: function(type, eventData) {
			if (AscCommon.c_oNotifyParentType.IsDefName === type) {
				return null;
			} else if (AscCommon.c_oNotifyParentType.Change === type) {
				this.wb.dependencyFormulas.addToChangedDefName(this);
			} else if (AscCommon.c_oNotifyParentType.ChangeFormula === type) {
				var notifyType = eventData.notifyData.type;
				if (!(this.isTable &&
					(c_oNotifyType.Shift === notifyType || c_oNotifyType.Move === notifyType ||
					c_oNotifyType.Delete === notifyType))) {
				var oldUndoName = this.getUndoDefName();
					this.parsedRef.setFormulaString(this.ref = eventData.assemble);
				this.wb.dependencyFormulas.addToChangedDefName(this);
				var newUndoName = this.getUndoDefName();
					History.Add(AscCommonExcel.g_oUndoRedoWorkbook, AscCH.historyitem_Workbook_DefinedNamesChangeUndo,
						null, null, new UndoRedoData_FromTo(oldUndoName, newUndoName), true);
			}
		}
		}
	};

	function getCellIndex(row, col) {
		return row * AscCommon.gc_nMaxCol + col;
	}

	var g_FCI = {row: null, col: null};

	function getFromCellIndex(cellIndex) {
		g_FCI.row = Math.floor(cellIndex / AscCommon.gc_nMaxCol);
		g_FCI.col = cellIndex % AscCommon.gc_nMaxCol;
	}

	function getVertexIndex(bbox) {
		//without $
		//значения в areaMap хранятся в виде A1B1
		//данная функция используется только для получения данных из areaMap
		var res;
		AscCommonExcel.executeInR1C1Mode(false, function () {
			res = bbox.getName(AscCommonExcel.referenceType.R);
		});
		return res;
	}

	function DependencyGraph(wb) {
		this.wb = wb;
		//listening
		this.sheetListeners = {};
		this.volatileListeners = {};
		this.defNameListeners = {};
		this.tempGetByCells = [];
		//set dirty
		this.isInCalc = false;
		this.changedCell = null;
		this.changedCellRepeated = null;
		this.changedRange = null;
		this.changedRangeRepeated = null;
		this.changedDefName = null;
		this.changedDefNameRepeated = null;
		this.changedShared = {};
		this.buildCell = {};
		this.buildDefName = {};
		this.buildShared = {};
		this.cleanCellCache = {};
		//lock
		this.lockCounter = 0;
		//defined name
		this.defNames = {wb: {}, sheet: {}};
		this.tableNamePattern = "Table";
		this.tableNameIndex = 0;
	}

	DependencyGraph.prototype = {
		//listening
		startListeningRange: function(sheetId, bbox, listener) {
			//todo bbox clone or bbox immutable
			var listenerId = listener.getListenerId();
			var sheetContainer = this.sheetListeners[sheetId];
			if (!sheetContainer) {
				sheetContainer = {cellMap: {}, areaMap: {}, areaTree: new RangeTree(), defName3d: {}};
				this.sheetListeners[sheetId] = sheetContainer;
			}
			if (bbox.isOneCell()) {
				var cellIndex = getCellIndex(bbox.r1, bbox.c1);
				var cellMapElem = sheetContainer.cellMap[cellIndex];
				if (!cellMapElem) {
					cellMapElem = {count: 0, listeners: {}};
					sheetContainer.cellMap[cellIndex] = cellMapElem;
				}
				if (!cellMapElem.listeners[listenerId]) {
					cellMapElem.listeners[listenerId] = listener;
					cellMapElem.count++;
				}
			} else {
				var vertexIndex = getVertexIndex(bbox);
				var areaSheetElem = sheetContainer.areaMap[vertexIndex];
				if (!areaSheetElem) {
					//todo clone inside or outside startListeningRange?
					bbox = bbox.clone();
					areaSheetElem = {id: null, bbox: bbox, count: 0, listeners: {}};
					sheetContainer.areaMap[vertexIndex] = areaSheetElem;
					sheetContainer.areaTree.add(bbox, areaSheetElem);
				}
				if (!areaSheetElem.listeners[listenerId]) {
					areaSheetElem.listeners[listenerId] = listener;
					areaSheetElem.count++;
				}
			}
		},
		endListeningRange: function(sheetId, bbox, listener) {
			var listenerId = listener.getListenerId();
			if (null != listenerId) {
				var sheetContainer = this.sheetListeners[sheetId];
				if (sheetContainer) {
					if (bbox.isOneCell()) {
						var cellIndex = getCellIndex(bbox.r1, bbox.c1);
						var cellMapElem = sheetContainer.cellMap[cellIndex];
						if (cellMapElem && cellMapElem.listeners[listenerId]) {
							delete cellMapElem.listeners[listenerId];
							cellMapElem.count--;
							if (cellMapElem.count <= 0) {
								delete sheetContainer.cellMap[cellIndex];
							}
						}
					} else {
						var vertexIndex = getVertexIndex(bbox);
						var areaSheetElem = sheetContainer.areaMap[vertexIndex];
						if (areaSheetElem && areaSheetElem.listeners[listenerId]) {
							delete areaSheetElem.listeners[listenerId];
							areaSheetElem.count--;
							if (areaSheetElem.count <= 0) {
								delete sheetContainer.areaMap[vertexIndex];
								sheetContainer.areaTree.remove(bbox, areaSheetElem);
							}
						}
					}
				}
			}
		},
		startListeningVolatile: function(listener) {
			var listenerId = listener.getListenerId();
			this.volatileListeners[listenerId] = listener;
		},
		endListeningVolatile: function(listener) {
			var listenerId = listener.getListenerId();
			if (null != listenerId) {
				delete this.volatileListeners[listenerId];
			}
		},
		startListeningDefName: function(name, listener, opt_sheetId) {
			var listenerId = listener.getListenerId();
			var nameIndex = getDefNameIndex(name);
			var container = this.defNameListeners[nameIndex];
			if (!container) {
				container = {count: 0, listeners: {}};
				this.defNameListeners[nameIndex] = container;
			}
			if (!container.listeners[listenerId]) {
				container.listeners[listenerId] = listener;
				container.count++;
			}
			if(opt_sheetId){
				var sheetContainer = this.sheetListeners[opt_sheetId];
				if (!sheetContainer) {
					sheetContainer = {cellMap: {}, areaMap: {}, areaTree: new RangeTree(), defName3d: {}};
					this.sheetListeners[opt_sheetId] = sheetContainer;
				}
				sheetContainer.defName3d[listenerId] = listener;
			}
		},
		isListeningDefName: function(name) {
			return null != this.defNameListeners[getDefNameIndex(name)];
		},
		endListeningDefName: function(name, listener, opt_sheetId) {
			var listenerId = listener.getListenerId();
			if (null != listenerId) {
				var nameIndex = getDefNameIndex(name);
				var container = this.defNameListeners[nameIndex];
				if (container && container.listeners[listenerId]) {
					delete container.listeners[listenerId];
					container.count--;
					if (container.count <= 0) {
						delete this.defNameListeners[nameIndex];
					}
				}
				if(opt_sheetId){
					var sheetContainer = this.sheetListeners[opt_sheetId];
					if (sheetContainer) {
						delete sheetContainer.defName3d[listenerId];
					}
				}
			}
		},
		//shift, move
		deleteNodes: function(sheetId, bbox) {
			this.buildDependency();
			this._shiftMoveDelete(c_oNotifyType.Delete, sheetId, bbox, null);
			this.addToChangedRange(sheetId, bbox);
		},
		shift: function(sheetId, bbox, offset) {
			this.buildDependency();
			return this._shiftMoveDelete(c_oNotifyType.Shift, sheetId, bbox, offset);
		},
		move: function(sheetId, bboxFrom, offset) {
			this.buildDependency();
			this._shiftMoveDelete(c_oNotifyType.Move, sheetId, bboxFrom, offset);
			this.addToChangedRange(sheetId, bboxFrom);
		},
		prepareChangeSheet: function(sheetId, data, tableNamesMap) {
			this.buildDependency();
			var listeners = {};
			var sheetContainer = this.sheetListeners[sheetId];
			if (sheetContainer) {
				for (var cellIndex in sheetContainer.cellMap) {
					var cellMapElem = sheetContainer.cellMap[cellIndex];
					for (var listenerId in cellMapElem.listeners) {
						listeners[listenerId] = cellMapElem.listeners[listenerId];
					}
				}
				for (var vertexIndex in sheetContainer.areaMap) {
					var areaSheetElem = sheetContainer.areaMap[vertexIndex];
					for (var listenerId in areaSheetElem.listeners) {
						listeners[listenerId] = areaSheetElem.listeners[listenerId];
					}
				}
				for (var listenerId in sheetContainer.defName3d) {
					listeners[listenerId] = sheetContainer.defName3d[listenerId];
				}
			}
			if(tableNamesMap){
				for (var tableName in tableNamesMap) {
					var nameIndex = getDefNameIndex(tableName);
					var container = this.defNameListeners[nameIndex];
					if (container) {
						for (var listenerId in container.listeners) {
							listeners[listenerId] = container.listeners[listenerId];
						}
					}
				}
			}
			var notifyData = {
				type: c_oNotifyType.Prepare, actionType: c_oNotifyType.ChangeSheet, data: data, transformed: {},
				preparedData: {}
			};
			for (var listenerId in listeners) {
				listeners[listenerId].notify(notifyData);
			}
			for (var listenerId in notifyData.transformed) {
				if (notifyData.transformed.hasOwnProperty(listenerId)) {
					delete listeners[listenerId];
					var elems = notifyData.transformed[listenerId];
					for (var i = 0; i < elems.length; ++i) {
						var elem = elems[i];
						listeners[elem.getListenerId()] = elem;
						elem.notify(notifyData);
					}
				}
			}
			return {listeners: listeners, data: data, preparedData: notifyData.preparedData};
		},
		changeSheet: function(prepared) {
			var notifyData = {type: c_oNotifyType.ChangeSheet, data: prepared.data, preparedData: prepared.preparedData};
			for (var listenerId in prepared.listeners) {
				prepared.listeners[listenerId].notify(notifyData);
			}
		},
		prepareRemoveSheet: function(sheetId, tableNames) {
			var t = this;
			//cells
			var formulas = [];
			this.wb.getWorksheetById(sheetId).getAllFormulas(formulas);
			for (var i = 0; i < formulas.length; ++i) {
				formulas[i].removeDependencies();
			}
			//defnames
			this._foreachDefNameSheet(sheetId, function(defName){
				if (!defName.isTable) {
					t._removeDefName(sheetId, defName.name, AscCH.historyitem_Workbook_DefinedNamesChangeUndo);
					}
			});
			//tables
			var tableNamesMap = {};
			for (var i = 0; i < tableNames.length; ++i) {
				var tableName = tableNames[i];
				this._removeDefName(null, tableName, null);
				tableNamesMap[tableName] = 1;
			}
			//dependence
			return this.prepareChangeSheet(sheetId, {remove: sheetId, tableNamesMap: tableNamesMap}, tableNamesMap);
		},
		removeSheet: function(prepared) {
			this.changeSheet(prepared);
		},
		//lock
		lockRecal: function() {
			++this.lockCounter;
		},
		isLockRecal: function() {
			return this.lockCounter > 0;
		},
		unlockRecal: function() {
			if (0 < this.lockCounter) {
				--this.lockCounter;
			}
			if (0 >= this.lockCounter) {
				this.calcTree();
			}
		},
		lockRecalExecute: function(callback) {
			this.lockRecal();
			callback();
			this.unlockRecal();
		},
		//defined name
		getDefNameByName: function(name, sheetId, opt_exact) {
			var res = null;
			var nameIndex = getDefNameIndex(name);
			if (sheetId) {
				var sheetContainer = this.defNames.sheet[sheetId];
				if (sheetContainer) {
					res = sheetContainer[nameIndex];
				}
			}
			if (!res && !(opt_exact && sheetId)) {
				res = this.defNames.wb[nameIndex];
			}
			return res;
		},
		getDefNameByNodeId: function(nodeId) {
			getFromDefNameId(nodeId);
			return this.getDefNameByName(g_FDNI.name, g_FDNI.sheetId, true);
		},
		getDefNameByRef: function(ref, sheetId) {
			var getByRef = function(defName) {
				if (!defName.hidden && defName.ref == ref) {
					return defName.name;
				}
			};
			var res = this._foreachDefNameSheet(sheetId, getByRef);
			if (!res) {
				res = this._foreachDefNameBook(getByRef);
			}
			return res;
		},
		getDefinedNamesWB: function(type, bLocale) {
			var names = [], activeWS;

			function getNames(defName) {
				if (defName.ref && !defName.hidden && defName.name.indexOf("_xlnm") < 0) {
					names.push(defName.getAscCDefName(bLocale));
				}
			}

			function sort(a, b) {
				if (a.name > b.name) {
					return 1;
				} else if (a.name < b.name) {
					return -1;
				} else {
					return 0;
				}
			}

			switch (type) {
				case c_oAscGetDefinedNamesList.Worksheet:
				case c_oAscGetDefinedNamesList.WorksheetWorkbook:
					activeWS = this.wb.getActiveWs();
					this._foreachDefNameSheet(activeWS.getId(), getNames);
					if (c_oAscGetDefinedNamesList.WorksheetWorkbook) {
						this._foreachDefNameBook(getNames);
					}
					break;
				case c_oAscGetDefinedNamesList.All:
				default:
					this._foreachDefName(getNames);
					break;
			}
			return names.sort(sort);
		},
		addDefNameOpen: function(name, ref, sheetIndex, hidden, isTable) {
			var sheetId = this.wb.getSheetIdByIndex(sheetIndex);
			var defName = new DefName(this.wb, name, ref, sheetId, hidden, isTable);
			this._addDefName(defName);
			return defName;
		},
		addDefName: function(name, ref, sheetId, hidden, isTable) {
			var defName = new DefName(this.wb, name, ref, sheetId, hidden, isTable);
			defName.setRef(defName.ref, true);
			this._addDefName(defName);
			return defName;
		},
		removeDefName: function(sheetId, name) {
			this._removeDefName(sheetId, name, AscCH.historyitem_Workbook_DefinedNamesChange);
		},
		editDefinesNames: function(oldUndoName, newUndoName) {
			var res = null;
			if (!AscCommon.rx_defName.test(getDefNameIndex(newUndoName.name)) || !newUndoName.ref ||
				newUndoName.ref.length == 0) {
				return res;
			}
			if (oldUndoName) {
				res = this.getDefNameByName(oldUndoName.name, oldUndoName.sheetId);
			} else {
				res = this.addDefName(newUndoName.name, newUndoName.ref, newUndoName.sheetId, false, false);
			}
			History.Create_NewPoint();
			if (res && oldUndoName) {
				if (oldUndoName.name != newUndoName.name) {
					this.buildDependency();

					res = this._delDefName(res.name, res.sheetId);
					res.setUndoDefName(newUndoName);
					this._addDefName(res);

					var notifyData = {type: c_oNotifyType.ChangeDefName, from: oldUndoName, to: newUndoName};
					this._broadcastDefName(oldUndoName.name, notifyData);

					this.addToChangedDefName(res);
				} else {
					res.setUndoDefName(newUndoName);
				}
			}
			History.Add(AscCommonExcel.g_oUndoRedoWorkbook, AscCH.historyitem_Workbook_DefinedNamesChange, null, null,
						new UndoRedoData_FromTo(oldUndoName, newUndoName));
			return res;
		},
		checkDefName: function (name, sheetIndex) {
			var res = new Asc.asc_CCheckDefName();
			var range = AscCommonExcel.g_oRangeCache.getRange3D(name) ||
				AscCommonExcel.g_oRangeCache.getAscRange(name);
			if (range || !AscCommon.rx_defName.test(name.toLowerCase())) {
				res.status = false;
				res.reason = c_oAscDefinedNameReason.WrongName;
				return res;
			}

			var sheetId = this.wb.getSheetIdByIndex(sheetIndex);
			var defName = this.getDefNameByName(name, sheetId, true);
			if (defName) {
				res.status = false;
				if (defName.isLock) {
					res.reason = c_oAscDefinedNameReason.IsLocked;
				} else {
					res.reason = c_oAscDefinedNameReason.Existed;
				}
			} else {
				if (this.isListeningDefName(name)) {
					res.status = false;
					res.reason = c_oAscDefinedNameReason.NameReserved;
				} else {
					res.status = true;
					res.reason = c_oAscDefinedNameReason.OK;
				}
			}

			return res;
		},
		copyDefNameByWorksheet: function(wsFrom, wsTo, renameParams) {
			var sheetContainerFrom = this.defNames.sheet[wsFrom.getId()];
			if (sheetContainerFrom) {
				for (var name in sheetContainerFrom) {
					var defNameOld = sheetContainerFrom[name];
					if (!defNameOld.isTable && defNameOld.parsedRef) {
						var parsedRefNew = defNameOld.parsedRef.clone();
						parsedRefNew.renameSheetCopy(renameParams);
						var refNew = parsedRefNew.assemble(true);
						this.addDefName(defNameOld.name, refNew, wsTo.getId(), defNameOld.hidden, defNameOld.isTable);
					}
				}
			}
		},
		saveDefName: function() {
			var list = [];
			this._foreachDefName(function(defName) {
				if (!defName.isTable && defName.ref) {
					list.push(defName.getAscCDefName());
				}
			});
			return list;
		},
		unlockDefName: function() {
			this._foreachDefName(function(defName) {
				defName.isLock = null;
			});
		},
		checkDefNameLock: function() {
			return this._foreachDefName(function(defName) {
				return defName.isLock;
			});
		},
		//defined name table
		getNextTableName: function() {
			var sNewName;
			var collaborativeIndexUser = "";
			if (this.wb.oApi.collaborativeEditing.getCollaborativeEditing()) {
				collaborativeIndexUser = "_" + this.wb.oApi.CoAuthoringApi.get_indexUser();
			}
			do {
				this.tableNameIndex++;
				sNewName = this.tableNamePattern + this.tableNameIndex + collaborativeIndexUser;
			} while (this.getDefNameByName(sNewName, null) || this.isListeningDefName(sNewName));
			return sNewName;
		},
		addTableName: function(ws, table, opt_isOpen) {
			var ref = table.getRangeWithoutHeaderFooter();

			var defNameRef = parserHelp.get3DRef(ws.getName(), ref.getAbsName());
			var defName = this.getDefNameByName(table.DisplayName, null);
			if (!defName) {
				if(opt_isOpen){
					this.addDefNameOpen(table.DisplayName, defNameRef, null, null, true);
				} else {
					this.addDefName(table.DisplayName, defNameRef, null, null, true);
				}
			} else {
				defName.setRef(defNameRef);
			}
		},
		changeTableRef: function(table) {
			var defName = this.getDefNameByName(table.DisplayName, null);
			if (defName) {
				this.buildDependency();
				var oldUndoName = defName.getUndoDefName();
				var newUndoName = defName.getUndoDefName();
				var ref = table.getRangeWithoutHeaderFooter();
				newUndoName.ref = defName.ref.split('!')[0] + '!' + ref.getAbsName();
				History.TurnOff();
				this.editDefinesNames(oldUndoName, newUndoName);
				var notifyData = {type: c_oNotifyType.ChangeDefName, from: oldUndoName, to: newUndoName};
				this._broadcastDefName(defName.name, notifyData);
				History.TurnOn();
				this.addToChangedDefName(defName);
				this.calcTree();
			}
		},
		changeTableName: function(tableName, newName) {
			var defName = this.getDefNameByName(tableName, null);
			if (defName) {
				var oldUndoName = defName.getUndoDefName();
				var newUndoName = defName.getUndoDefName();
				newUndoName.name = newName;
				History.TurnOff();
				this.editDefinesNames(oldUndoName, newUndoName);
				History.TurnOn();
			}
		},
		delTableName: function(tableName, bConvertTableFormulaToRef) {
			this.buildDependency();
			var defName = this.getDefNameByName(tableName);
			
			this.addToChangedDefName(defName);
			var notifyData = {type: c_oNotifyType.ChangeDefName, from: defName.getUndoDefName(), to: null, bConvertTableFormulaToRef: bConvertTableFormulaToRef};
			this._broadcastDefName(tableName, notifyData);
			
			this._delDefName(tableName, null);
			if (defName) {
				defName.removeDependencies();
			}
		},
		delColumnTable: function(tableName, deleted) {
			this.buildDependency();
			var notifyData = {type: c_oNotifyType.DelColumnTable, tableName: tableName, deleted: deleted};
			this._broadcastDefName(tableName, notifyData);
		},
		renameTableColumn: function(tableName) {
			var defName = this.getDefNameByName(tableName, null);
			if (defName) {
				this.buildDependency();
				var notifyData = {type: c_oNotifyType.RenameTableColumn, tableName: tableName};
				this._broadcastDefName(defName.name, notifyData);
			}
			this.calcTree();
		},
		//set dirty
		addToChangedRange2: function(sheetId, bbox) {
			if (!this.changedRange) {
				this.changedRange = {};
			}
			var changedSheet = this.changedRange[sheetId];
			if (!changedSheet) {
				//{}, а не [], потому что при сборке может придти сразу много одинаковых ячеек
				changedSheet = {};
				this.changedRange[sheetId] = changedSheet;
			}
			var name = bbox.getName();
			if (this.isInCalc && !changedSheet[name]) {
				if (!this.changedRangeRepeated) {
					this.changedRangeRepeated = {};
				}
				var changedSheetRepeated = this.changedRangeRepeated[sheetId];
				if (!changedSheetRepeated) {
					changedSheetRepeated = {};
					this.changedRangeRepeated[sheetId] = changedSheetRepeated;
				}
				changedSheetRepeated[name] = bbox;
			}
			changedSheet[name] = bbox;
		},
		addToChangedCell: function(cell) {
			var sheetId = cell.ws.getId();
			if (!this.changedCell) {
				this.changedCell = {};
			}
			var changedSheet = this.changedCell[sheetId];
			if (!changedSheet) {
				//{}, а не [], потому что при сборке может придти сразу много одинаковых ячеек
				changedSheet = {};
				this.changedCell[sheetId] = changedSheet;
			}
			var cellIndex = getCellIndex(cell.nRow, cell.nCol);
			if (this.isInCalc && !changedSheet[cellIndex]) {
				if (!this.changedCellRepeated) {
					this.changedCellRepeated = {};
				}
				var changedSheetRepeated = this.changedCellRepeated[sheetId];
				if (!changedSheetRepeated) {
					changedSheetRepeated = {};
					this.changedCellRepeated[sheetId] = changedSheetRepeated;
				}
				changedSheetRepeated[cellIndex] = 1;
			}
			changedSheet[cellIndex] = 1;
		},
		addToChangedDefName: function(defName) {
			if (!this.changedDefName) {
				this.changedDefName = {};
			}
			var nodeId = defName.getNodeId();
			if (this.isInCalc && !this.changedDefName[nodeId]) {
				if (!this.changedDefNameRepeated) {
					this.changedDefNameRepeated = {};
				}
				this.changedDefNameRepeated[nodeId] = 1;
			}
			this.changedDefName[nodeId] = 1;
		},
		addToChangedRange: function(sheetId, bbox) {
			var notifyData = {type: c_oNotifyType.Dirty};
			var sheetContainer = this.sheetListeners[sheetId];
			if (sheetContainer) {
				for (var cellIndex in sheetContainer.cellMap) {
					getFromCellIndex(cellIndex);
					if (bbox.contains(g_FCI.col, g_FCI.row)) {
						var cellMapElem = sheetContainer.cellMap[cellIndex];
						for (var listenerId in cellMapElem.listeners) {
							cellMapElem.listeners[listenerId].notify(notifyData);
						}
					}
				}
				for (var areaIndex in sheetContainer.areaMap) {
					var areaMapElem = sheetContainer.areaMap[areaIndex];
					var isIntersect = bbox.isIntersect(areaMapElem.bbox);
					if (isIntersect) {
						for (var listenerId in areaMapElem.listeners) {
							areaMapElem.listeners[listenerId].notify(notifyData);
						}
					}
				}
			}
		},
		addToChangedHiddenRows: function() {
			//notify hidden rows
			var tmpRange = new Asc.Range(0, 0, gc_nMaxCol0, 0);
			for (var i = 0; i < this.wb.aWorksheets.length; ++i) {
				var ws = this.wb.aWorksheets[i];
				var hiddenRange = ws.hiddenManager.getHiddenRowsRange();
				if (hiddenRange) {
					tmpRange.r1 = hiddenRange.r1;
					tmpRange.r2 = hiddenRange.r2;
					this.addToChangedRange(ws.getId(), tmpRange);
				}
			}
		},
		addToBuildDependencyCell: function(cell) {
			var sheetId = cell.ws.getId();
			var unparsedSheet = this.buildCell[sheetId];
			if (!unparsedSheet) {
				//{}, а не [], потому что при сборке может придти сразу много одинаковых ячеек
				unparsedSheet = {};
				this.buildCell[sheetId] = unparsedSheet;
			}
			unparsedSheet[getCellIndex(cell.nRow, cell.nCol)] = 1;
		},
		addToBuildDependencyDefName: function(defName) {
			this.buildDefName[defName.getNodeId()] = 1;
		},
		addToBuildDependencyShared: function(shared) {
			this.buildShared[shared.getIndexNumber()] = shared;
		},
		addToCleanCellCache: function(sheetId, row, col) {
			var sheetArea = this.cleanCellCache[sheetId];
			if (sheetArea) {
				sheetArea.union3(col, row);
			} else {
				this.cleanCellCache[sheetId] = new Asc.Range(col, row, col, row);
			}
		},
		addToChangedShared: function(parsed) {
			this.changedShared[parsed.getIndexNumber()] = parsed;
		},
		notifyChanged: function(changedFormulas) {
			var notifyData = {type: c_oNotifyType.Dirty};
			for (var listenerId in changedFormulas) {
				changedFormulas[listenerId].notify(notifyData);
			}
		},
		//build, calc
		buildDependency: function() {
			for (var sheetId in this.buildCell) {
				var ws = this.wb.getWorksheetById(sheetId);
				if (ws) {
					var unparsedSheet = this.buildCell[sheetId];
					for (var cellIndex in unparsedSheet) {
						getFromCellIndex(cellIndex);
						ws._getCellNoEmpty(g_FCI.row, g_FCI.col, function(cell) {
							if (cell) {
								cell._BuildDependencies(true, true);
							}
						});
					}
				}
			}
			for (var defNameId in this.buildDefName) {
				var defName = this.getDefNameByNodeId(defNameId);
				if (defName && defName.parsedRef) {
					defName.parsedRef.parse();
					defName.parsedRef.buildDependencies();
					this.addToChangedDefName(defName);
				}
			}
			for (var index in this.buildShared) {
				if (this.buildShared.hasOwnProperty(index)) {
					var parsed = this.wb.workbookFormulas.get(index - 0);
					if (parsed) {
						parsed.parse();
						parsed.buildDependencies();
						var shared = parsed.getShared();
						this.wb.dependencyFormulas.addToChangedRange2(parsed.getWs().getId(), shared.ref);
					}
				}
			}
			this.buildCell = {};
			this.buildDefName = {};
			this.buildShared = {};
		},
		calcTree: function() {
			if (this.lockCounter > 0) {
				return;
			}
			var notifyData = {type: c_oNotifyType.Dirty, areaData: undefined};
			this.buildDependency();
			this.addToChangedHiddenRows();
			//broadscast Volatile only if something changed
			if (this.changedCell || this.changedRange || this.changedDefName) {
				this._broadscastVolatile(notifyData);
			}
			this._broadcastCellsStart();
			while (this.changedCellRepeated || this.changedRangeRepeated || this.changedDefNameRepeated) {
				this._broadcastDefNames(notifyData);
				this._broadcastCells(notifyData);
				this._broadcastRanges(notifyData);
			}
			this._broadcastCellsEnd();
			this._calculateDirty();
			this.updateSharedFormulas();
			//copy cleanCellCache to prevent recursion in trigger("cleanCellCache")
			var tmpCellCache = this.cleanCellCache;
			this.cleanCellCache = {};
			for (var i in tmpCellCache) {
				this.wb.handlers.trigger("cleanCellCache", i, [tmpCellCache[i]], true);
			}
			AscCommonExcel.g_oVLOOKUPCache.clean();
			AscCommonExcel.g_oHLOOKUPCache.clean();
		},
		initOpen: function() {
			this._foreachDefName(function(defName) {
				defName.setRef(defName.ref, true, true, true);
			});
		},
		getSnapshot: function(wb) {
			var res = new DependencyGraph(wb);
			this._foreachDefName(function(defName){
				//_addDefName because we don't need dependency
				//include table defNames too.
				res._addDefName(defName.clone(wb));
			});
			res.tableNameIndex = this.tableNameIndex;
			return res;
		},
		getAllFormulas: function(formulas) {
			this._foreachDefName(function(defName) {
				if (defName.parsedRef) {
					formulas.push(defName.parsedRef);
				}
			});
		},
		updateSharedFormulas: function() {
			var newRef;
			for (var indexNumber in this.changedShared) {
				var parsed = this.changedShared[indexNumber];
				var shared = parsed.getShared();
				if (shared) {
					var ws = parsed.getWs();
					var ref = shared.ref;
					var r1 = gc_nMaxRow0;
					var c1 = gc_nMaxCol0;
					var r2 = 0;
					var c2 = 0;
					ws.getRange3(ref.r1, ref.c1, ref.r2, ref.c2)._foreachNoEmpty(function(cell) {
						if (parsed === cell.getFormulaParsed()) {
							r1 = Math.min(r1, cell.nRow);
							c1 = Math.min(c1, cell.nCol);
							r2 = Math.max(r2, cell.nRow);
							c2 = Math.max(c2, cell.nCol);
						}
					});
					newRef = undefined;
					if (r1 <= r2 && c1 <= c2) {
						newRef = new Asc.Range(c1, r1, c2, r2);
					}
					parsed.setSharedRef(newRef);
				}
			}
			this.changedShared = {};
		},
		//internal
		_addDefName: function(defName) {
			var nameIndex = getDefNameIndex(defName.name);
			var container;
			var sheetId = defName.sheetId;
			if (sheetId) {
				container = this.defNames.sheet[sheetId];
				if (!container) {
					container = {};
					this.defNames.sheet[sheetId] = container;
				}
			} else {
				container = this.defNames.wb;
			}
			var cur = container[nameIndex];
			if (cur) {
				cur.removeDependencies();
			}
			container[nameIndex] = defName;
		},
		_removeDefName: function(sheetId, name, historyType) {
			var defName = this._delDefName(name, sheetId);
			if (defName) {
				if (null != historyType) {
					History.Create_NewPoint();
					History.Add(AscCommonExcel.g_oUndoRedoWorkbook, historyType, null, null,
								new UndoRedoData_FromTo(defName.getUndoDefName(), null));
				}

				defName.removeDependencies();
				this.addToChangedDefName(defName);
			}
		},
		_delDefName: function(name, sheetId) {
			var res = null;
			var nameIndex = getDefNameIndex(name);
			var sheetContainer;
			if (sheetId) {
				sheetContainer = this.defNames.sheet[sheetId];
			}
			else {
				sheetContainer = this.defNames.wb;
			}
			if (sheetContainer) {
				res = sheetContainer[nameIndex];
				delete sheetContainer[nameIndex];
			}
			return res;
		},
		_foreachDefName: function(action) {
			var containerSheet;
			var sheetId;
			var name;
			var res;
			for (sheetId in this.defNames.sheet) {
				containerSheet = this.defNames.sheet[sheetId];
				for (name in containerSheet) {
					res = action(containerSheet[name], containerSheet);
					if (res) {
						break;
					}
				}
			}
			if (!res) {
				res = this._foreachDefNameBook(action);
			}
			return res;
		},
		_foreachDefNameSheet: function(sheetId, action) {
			var name;
			var res;
			var containerSheet = this.defNames.sheet[sheetId];
			if (containerSheet) {
				for (name in containerSheet) {
					res = action(containerSheet[name], containerSheet);
					if (res) {
						break;
					}
				}
			}
			return res;
		},
		_foreachDefNameBook: function(action) {
			var containerSheet;
			var name;
			var res;
			for (name in this.defNames.wb) {
				res = action(this.defNames.wb[name], this.defNames.wb);
				if (res) {
					break;
				}
			}
			return res;
		},
		_broadscastVolatile: function(notifyData) {
			for (var i in this.volatileListeners) {
				this.volatileListeners[i].notify(notifyData);
			}
		},
		_broadcastDefName: function(name, notifyData) {
			var nameIndex = getDefNameIndex(name);
			var container = this.defNameListeners[nameIndex];
			if (container) {
				for (var listenerId in container.listeners) {
					container.listeners[listenerId].notify(notifyData);
				}
			}
		},
		_broadcastDefNames: function(notifyData) {
			if (this.changedDefNameRepeated) {
				var changedDefName = this.changedDefNameRepeated;
				this.changedDefNameRepeated = null;
				for (var nodeId in changedDefName) {
					getFromDefNameId(nodeId);
					this._broadcastDefName(g_FDNI.name, notifyData);
				}
			}
		},
		_broadcastCells: function(notifyData) {
			if (this.changedCellRepeated) {
				var changedCell = this.changedCellRepeated;
				this.changedCellRepeated = null;
				for (var sheetId in changedCell) {
					var changedSheet = changedCell[sheetId];
					var sheetContainer = this.sheetListeners[sheetId];
					if (sheetContainer) {
						for (var cellIndex in changedSheet) {
							if (sheetContainer) {
								var cellMapElem = sheetContainer.cellMap[cellIndex];
								if (cellMapElem) {
									for (var listenerId in cellMapElem.listeners) {
										cellMapElem.listeners[listenerId].notify(notifyData);
									}
								}
							}
						}
						if (sheetContainer) {
							var areas = sheetContainer.areaTree.getByCells(changedSheet);
							this.tempGetByCells.push({areaTree: sheetContainer.areaTree, areas: areas});
							for (var i = 0; i < areas.length; ++i) {
								var area = areas[i];
								notifyData.areaData = area;
								for (var listenerId in area.data.listeners) {
									area.data.listeners[listenerId].notify(notifyData);
								}
							}
							notifyData.areaData = undefined;
						}
					}
				}
			}
		},
		_broadcastRanges: function(notifyData) {
			if (this.changedRangeRepeated) {
				var changedRange = this.changedRangeRepeated;
				this.changedRangeRepeated = null;
				for (var sheetId in changedRange) {
					var changedSheet = changedRange[sheetId];
					var sheetContainer = this.sheetListeners[sheetId];
					if (sheetContainer) {
						if (sheetContainer) {
							for (var rangeRef in changedSheet) {
								var range = changedSheet[rangeRef];
								for (var cellIndex in sheetContainer.cellMap) {
								getFromCellIndex(cellIndex);
									if (range.contains(g_FCI.col, g_FCI.row)) {
										var cellMapElem = sheetContainer.cellMap[cellIndex];
										if (cellMapElem) {
											for (var listenerId in cellMapElem.listeners) {
												cellMapElem.listeners[listenerId].notify(notifyData);
									}
							}
						}
								}
							}
							var areas = sheetContainer.areaTree.getByRanges(changedSheet);
							this.tempGetByCells.push({areaTree: sheetContainer.areaTree, areas: areas});
							for (var i = 0; i < areas.length; ++i) {
								var area = areas[i];
								notifyData.areaData = area;
								for (var listenerId in area.data.listeners) {
									area.data.listeners[listenerId].notify(notifyData);
								}
							}
							notifyData.areaData = undefined;
						}
					}
				}
			}
		},
		_broadcastCellsStart: function() {
			this.isInCalc = true;
			this.changedCellRepeated = this.changedCell;
			this.changedRangeRepeated = this.changedRange;
			this.changedDefNameRepeated = this.changedDefName;
		},
		_broadcastCellsEnd: function() {
			this.isInCalc = false;
			this.changedDefName = null;
			for (var i = 0; i < this.tempGetByCells.length; ++i) {
				var temp = this.tempGetByCells[i];
				temp.areaTree.getByCellsRangesEnd(temp.areas);
			}
			this.tempGetByCells = [];
		},
		_calculateDirty: function() {
			var t = this;
			this._foreachChanged(function(cell){
				if (cell && cell.isFormula()) {
					cell.setIsDirty(true);
				}
			});
			this._foreachChanged(function(cell){
				cell && cell._checkDirty();
			});
			this.changedCell = null;
			this.changedRange = null;
		},
		_foreachChanged: function(callback) {
			var sheetId, changedSheet, ws, bbox;
			for (sheetId in this.changedCell) {
				if (this.changedCell.hasOwnProperty(sheetId)) {
					changedSheet = this.changedCell[sheetId];
					ws = this.wb.getWorksheetById(sheetId);
					if (changedSheet && ws) {
						for (var cellIndex in changedSheet) {
							if (changedSheet.hasOwnProperty(cellIndex)) {
								getFromCellIndex(cellIndex);
								ws._getCell(g_FCI.row, g_FCI.col, callback);
							}
						}
					}
				}
			}
			for (sheetId in this.changedRange) {
				if (this.changedRange.hasOwnProperty(sheetId)) {
					changedSheet = this.changedRange[sheetId];
					ws = this.wb.getWorksheetById(sheetId);
					if (changedSheet && ws) {
						for (var name in changedSheet) {
							if (changedSheet.hasOwnProperty(name)) {
								bbox = changedSheet[name];
								ws.getRange3(bbox.r1, bbox.c1, bbox.r2, bbox.c2)._foreachNoEmpty(callback);
							}
						}
					}
				}
			}
		},
		_shiftMoveDelete: function(notifyType, sheetId, bbox, offset) {
			var listeners = {};
			var res = {changed: listeners, shiftedShared: {}};
			var sheetContainer = this.sheetListeners[sheetId];
			if (sheetContainer) {
				var bboxShift;
				if (c_oNotifyType.Shift === notifyType) {
					var bHor = 0 !== offset.col;
					bboxShift = AscCommonExcel.shiftGetBBox(bbox, bHor);
				}
				var isIntersect;
				for (var cellIndex in sheetContainer.cellMap) {
					getFromCellIndex(cellIndex);
					if (c_oNotifyType.Shift === notifyType) {
						isIntersect = bboxShift.contains(g_FCI.col, g_FCI.row);
					} else {
						isIntersect = bbox.contains(g_FCI.col, g_FCI.row);
					}
					if (isIntersect) {
						var cellMapElem = sheetContainer.cellMap[cellIndex];
						for (var listenerId in cellMapElem.listeners) {
							listeners[listenerId] = cellMapElem.listeners[listenerId];
						}
					}
				}
				for (var areaIndex in sheetContainer.areaMap) {
					var areaMapElem = sheetContainer.areaMap[areaIndex];
					if (c_oNotifyType.Shift === notifyType) {
						isIntersect = bboxShift.isIntersect(areaMapElem.bbox)
					} else if (c_oNotifyType.Move === notifyType || c_oNotifyType.Delete === notifyType) {
						isIntersect = bbox.isIntersect(areaMapElem.bbox);
					}
					if (isIntersect) {
						for (var listenerId in areaMapElem.listeners) {
							listeners[listenerId] = areaMapElem.listeners[listenerId];
						}
					}
				}
				var notifyData = {
					type: notifyType, sheetId: sheetId, bbox: bbox, offset: offset, shiftedShared: res.shiftedShared
				};
				for (var listenerId in listeners) {
					listeners[listenerId].notify(notifyData);
				}
				}
			return res;
			}
	};

	function RangeTree() {
		this.yTree = new Asc.TreeRB();
		this.id = 0;
	}

	RangeTree.prototype = {
		maxSharedRecursion: 100,
		add: function(bbox, data) {
			data.id = this.id++;
			var startFlag = bbox.r1 !== bbox.r2 ? 1 : 3;
			//cellsInAreaCount - heuristic for recursion shared(for example A2 shared to AN with '=A1+1')
			var dataWrap = {bbox: bbox, data: data, cellsInArea: null, cellsInAreaCount: 0};
			var top = this.yTree.insertOrGet(new Asc.TreeRBNode(bbox.r1, {count: 0, vals: {}}));
			top.storedValue.vals[data.id] = {startFlag: startFlag, dataWrap: dataWrap};
			top.storedValue.count++;
			if (bbox.r1 != bbox.r2) {
				startFlag = 2;
				var bottom = this.yTree.insertOrGet(new Asc.TreeRBNode(bbox.r2, {count: 0, vals: {}}));
				bottom.storedValue.vals[data.id] = {startFlag: startFlag, dataWrap: dataWrap};
				bottom.storedValue.count++;
			}
		},
		remove: function(bbox, data) {
			var top = this.yTree.getElem(bbox.r1);
			if (top) {
				if (top.storedValue.vals[data.id]) {
					delete top.storedValue.vals[data.id];
					top.storedValue.count--;
					if (top.storedValue.count <= 0) {
						this.yTree.deleteNode(top);
					}
				}
				var bottom = this.yTree.getElem(bbox.r2);
				if (bottom && bottom.storedValue.vals[data.id]) {
					delete bottom.storedValue.vals[data.id];
					bottom.storedValue.count--;
					if (bottom.storedValue.count <= 0) {
						this.yTree.deleteNode(bottom);
					}
				}
			}
		},
		getByCells: function(cells) {
			var res = [];
			var nodes = this.yTree.getNodeAll();
			var cellArr = [];
			for (var cellIndex in cells) {
				cellArr.push(cellIndex - 0);
			}
			//sort завязана на реализацию getCellIndex
			cellArr.sort(function(a, b) {
				return a - b;
			});
			if (cellArr.length > 0 && nodes.length > 0) {
				var curNodes = {};
				var curY = null;
				var curNodeY = null;
				var curNodeYIndex = 0;
				var curCellIndex = 0;
				var curCellX = null;
				var curCellY = null;
				while (curNodeYIndex < nodes.length && curCellIndex < cellArr.length) {
					if (!curNodeY) {
						curNodeY = nodes[curNodeYIndex];
						curY = curNodeY.key;
						for (var id in curNodeY.storedValue.vals) {
							var elem = curNodeY.storedValue.vals[id];
							if (0 !== (1 & elem.startFlag) &&
								!(elem.dataWrap.cellsInArea && elem.dataWrap.cellsInArea.isEqual(elem.dataWrap.bbox))) {
								for (var i = elem.dataWrap.bbox.c1; i <= elem.dataWrap.bbox.c2; ++i) {
									var curNodesElem = curNodes[i];
									if (!curNodesElem) {
										curNodesElem = {};
										curNodes[i] = curNodesElem;
									}
									curNodesElem[id] = elem;
								}
							}
						}
					}
					if (!curCellX) {
						var cellIndex = cellArr[curCellIndex];
						getFromCellIndex(cellIndex);
						curCellX = g_FCI.col;
						curCellY = g_FCI.row;
					}
					if (curCellY <= curY) {
						var curNodesElemX = curNodes[curCellX];
						for (var id in curNodesElemX) {
							var elem = curNodesElemX[id];
							if (elem.dataWrap.bbox.r1 <= curCellY && !(elem.dataWrap.cellsInArea &&
								elem.dataWrap.cellsInArea.contains(curCellX, curCellY))) {
								if (elem.dataWrap.cellsInArea) {
									elem.dataWrap.cellsInArea.union3(curCellX, curCellY);
								} else {
									elem.dataWrap.cellsInArea = new Asc.Range(curCellX, curCellY, curCellX, curCellY);
								}
								res.push(elem.dataWrap);
								if (elem.dataWrap.cellsInArea.isEqual(elem.dataWrap.bbox)) {
								for (var i = elem.dataWrap.bbox.c1; i <= elem.dataWrap.bbox.c2; ++i) {
									var curNodesElem = curNodes[i];
									if (curNodesElem) {
										delete curNodesElem[id];
									}
								}
							}
						}
						}
						curCellIndex++;
						curCellX = null;
						curCellY = null;
					} else {
						for (var id in curNodeY.storedValue.vals) {
							var elem = curNodeY.storedValue.vals[id];
							if (0 !== (2 & elem.startFlag) &&
								!(elem.dataWrap.cellsInArea && elem.dataWrap.cellsInArea.isEqual(elem.dataWrap.bbox))) {
								for (var i = elem.dataWrap.bbox.c1; i <= elem.dataWrap.bbox.c2; ++i) {
									var curNodesElem = curNodes[i];
									if (curNodesElem) {
										delete curNodesElem[id];
									}
								}
							}
						}
						curNodeYIndex++;
						curNodeY = null;
					}
				}
			}
			return res;
		},
		getByRanges: function(changedSheet) {
			var res = [];
			var node, id, bbox, intersect;
			var nodes = this.yTree.getNodeAll();
			if (nodes.length > 0) {
				var starts = [];
				var ends = [];
				for (var rangeRef in changedSheet) {
					if (changedSheet.hasOwnProperty(rangeRef)) {
						bbox = changedSheet[rangeRef];
						starts.push(bbox);
						ends.push(bbox);
					}
				}
				if (starts.length > 0 && ends.length > 0) {
					starts.sort(function(a, b) {
						return a.r1 - b.r1;
					});
					ends.sort(function(a, b) {
						return a.r2 - b.r2;
					});
					var curNodes = {};
					var curBBoxes = {};
					var startIndex = 0;
					var endIndex = 0;
					var nodeIndex = 0;
					var startVal = starts[startIndex++];
					var endVal = ends[endIndex++];
					var nodeVal = nodes[nodeIndex++];
					while (true) {
						var type = 2;
						if (startVal.r1 <= nodeVal.key) {
							if (startVal.r1 <= endVal.r2) {
								type = 1;
							}
						} else if (nodeVal.key <= endVal.r2) {
							type = 0;
						}
						if (1 === type) {
							for (id in curNodes) {
								if (curNodes.hasOwnProperty(id)) {
									node = curNodes[id];
									intersect = node.dataWrap.bbox.intersectionSimple(startVal);
									if (intersect &&
										!(node.dataWrap.cellsInArea && node.dataWrap.cellsInArea.isEqual(intersect))) {
										if (node.dataWrap.cellsInArea) {
											if (node.dataWrap.cellsInAreaCount < this.maxSharedRecursion) {
												node.dataWrap.cellsInArea.union2(intersect);
												node.dataWrap.cellsInAreaCount++;
											} else {
												node.dataWrap.cellsInArea = node.dataWrap.bbox;
											}
										} else {
											node.dataWrap.cellsInArea = intersect;
										}
										res.push(node.dataWrap);
									}
								}
							}
							curBBoxes[startVal.getName()] = startVal;
							if (startIndex < starts.length) {
								startVal = starts[startIndex++];
							} else {
								startVal = {r1: Number.MAX_VALUE};
							}
						} else if (2 === type) {
							delete curBBoxes[endVal.getName()];
							if (endIndex < ends.length) {
								endVal = ends[endIndex++];
							} else {
								break;
							}
						} else {
							for (id in nodeVal.storedValue.vals) {
								if (nodeVal.storedValue.vals.hasOwnProperty(id)) {
									node = nodeVal.storedValue.vals[id];
									if (0 !== (1 & node.startFlag)) {
										for (var name in curBBoxes) {
											if (curBBoxes.hasOwnProperty(name)) {
												bbox = curBBoxes[name];
												intersect = node.dataWrap.bbox.intersectionSimple(bbox);
												if (intersect && !(node.dataWrap.cellsInArea &&
													node.dataWrap.cellsInArea.isEqual(intersect))) {
													if (node.dataWrap.cellsInArea) {
														if (node.dataWrap.cellsInAreaCount < this.maxSharedRecursion) {
															node.dataWrap.cellsInArea.union2(intersect);
															node.dataWrap.cellsInAreaCount++;
														} else {
															node.dataWrap.cellsInArea = node.dataWrap.bbox;
														}
													} else {
														node.dataWrap.cellsInArea = intersect;
													}
													res.push(node.dataWrap);
												}
											}
										}
										curNodes[node.dataWrap.data.id] = node;
									} else if (0 !== (2 & node.startFlag)) {
										delete curNodes[node.dataWrap.data.id];
									}
								}
							}
							if (nodeIndex < nodes.length) {
								nodeVal = nodes[nodeIndex++];
							} else {
								break;
							}
						}
					}
				}
			}
			return res;
		},
		getByCellsRangesEnd: function(areas) {
			for (var i = 0; i < areas.length; ++i) {
				var area = areas[i];
				area.cellsInArea = null;
				area.cellsInAreaCount = 0;
			}
		}
	};

	function ForwardTransformationFormula(elem, formula, parsed) {
		this.elem = elem;
		this.formula = formula;
		this.parsed = parsed;
	}
	ForwardTransformationFormula.prototype = {
		onFormulaEvent: function(type, eventData) {
			if (AscCommon.c_oNotifyParentType.ChangeFormula === type) {
				this.formula = eventData.assemble;
			}
		}
	};
	function angleFormatToInterface(val)
	{
		var nRes = 0;
		if(0 <= val && val <= 180)
			nRes = val <= 90 ? val : 90 - val;
		return nRes;
	}
	function angleFormatToInterface2(val)
	{
		if(g_nVerticalTextAngle == val)
			return val;
		else
			return angleFormatToInterface(val);
	}
	function angleInterfaceToFormat(val)
	{
		var nRes = val;
		if(-90 <= val && val <= 90)
		{
			if(val < 0)
				nRes = 90 - val;
		}
		else if(g_nVerticalTextAngle != val)
			nRes = 0;
		return nRes;
	}
	function getUniqueKeys(array) {
		var i, o = {};
		for (i = 0; i < array.length; ++i) {
			o[array[i].v] = o.hasOwnProperty(array[i].v);
		}
		return o;
	}
//-------------------------------------------------------------------------------------------------
	function CT_Workbook() {
		//Members
		this.sheets = null;
		this.pivotCaches = null;
	}
	CT_Workbook.prototype.onStartNode = function(elem, attr, uq) {
		var newContext = this;
		if ("workbook" === elem) {
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
		} else if ("sheets" === elem) {
			//todo check name duplication
			this.sheets = [];
		} else if ("sheet" === elem) {
			newContext = new CT_Sheet();
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
			this.sheets.push(newContext);
		} else if ("pivotCaches" === elem) {
			//todo check name duplication
			this.pivotCaches = [];
		} else if ("pivotCache" === elem) {
			newContext = new CT_PivotCache();
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
			this.pivotCaches.push(newContext);
		} else {
			newContext = null;
		}
		return newContext;
	};
	function CT_Sheet() {
		//Attributes
		this.id = null;
	}
	CT_Sheet.prototype.readAttributes = function(attr, uq) {
		if (attr()) {
			var vals = attr();
			var val;
			val = vals["r:id"];
			if (undefined !== val) {
				this.id = AscCommon.unleakString(uq(val));
			}
		}
	};
	function CT_PivotCache() {
		//Attributes
		this.cacheId = null;
		this.id = null;
	}
	CT_PivotCache.prototype.readAttributes = function(attr, uq) {
		if (attr()) {
			var vals = attr();
			var val;
			val = vals["cacheId"];
			if (undefined !== val) {
				this.cacheId = val - 0;
			}
			val = vals["r:id"];
			if (undefined !== val) {
				this.id = AscCommon.unleakString(uq(val));
			}
		}
	};
	/**
	 * @constructor
	 */
	function Workbook(eventsHandlers, oApi){
		this.oApi = oApi;
		this.handlers = eventsHandlers;
		this.dependencyFormulas = new DependencyGraph(this);
		this.nActive = 0;

		this.theme = null;
		this.clrSchemeMap = null;

		this.CellStyles = new AscCommonExcel.CCellStyles();
		this.TableStyles = new Asc.CTableStyles();
		this.oStyleManager = new AscCommonExcel.StyleManager();
		this.sharedStrings = new AscCommonExcel.CSharedStrings();
		this.workbookFormulas = new AscCommonExcel.CWorkbookFormulas();
		this.loadCells = [];//to return one object when nested _getCell calls

		this.aComments = [];	// Комментарии к документу
		this.aWorksheets = [];
		this.aWorksheetsById = {};
		this.aCollaborativeActions = [];
		this.bCollaborativeChanges = false;
		this.bUndoChanges = false;
		this.bRedoChanges = false;
		this.aCollaborativeChangeElements = [];
		this.externalReferences = [];
		this.calcPr = {
			calcId: null, calcMode: null, fullCalcOnLoad: null, refMode: null, iterate: null, iterateCount: null,
			iterateDelta: null, fullPrecision: null, calcCompleted: null, calcOnSave: null, concurrentCalc: null,
			concurrentManualCount: null, forceFullCalc: null
		};

		this.wsHandlers = null;

		this.openErrors = [];

		this.maxDigitWidth = 0;
		this.paddingPlusBorder = 0;

		this.lastFindOptions = null;
		this.lastFindCells = {};
	}
	Workbook.prototype.init=function(tableCustomFunc, bNoBuildDep, bSnapshot){
		if(this.nActive < 0)
			this.nActive = 0;
		if(this.nActive >= this.aWorksheets.length)
			this.nActive = this.aWorksheets.length - 1;

		var self = this;

		this.wsHandlers = new AscCommonExcel.asc_CHandlersList( /*handlers*/{
			"changeRefTablePart"   : function (table) {
				self.dependencyFormulas.changeTableRef(table);
			},
			"changeColumnTablePart": function ( tableName ) {
				self.dependencyFormulas.renameTableColumn( tableName );
			},
			"deleteColumnTablePart": function(tableName, deleted) {
				self.dependencyFormulas.delColumnTable(tableName, deleted);
			}, 'onFilterInfo' : function () {
				self.handlers.trigger("asc_onFilterInfo");
			}
		} );
		for(var i = 0, length = tableCustomFunc.length; i < length; ++i) {
			var elem = tableCustomFunc[i];
			elem.column.applyTotalRowFormula(elem.formula, elem.ws, !bNoBuildDep);
		}
		//ws
		this.forEach(function (ws) {
			ws.initPostOpen(self.wsHandlers);
		});
		//show active if it hidden
		var wsActive = this.getActiveWs();
		if (wsActive && wsActive.getHidden()) {
			wsActive.setHidden(false);
		}

		if(!bNoBuildDep){
			this.dependencyFormulas.initOpen();
			this.dependencyFormulas.calcTree();
		}
		if (bSnapshot) {
			this.snapshot = this._getSnapshot();
		}
	};
	Workbook.prototype.forEach = function (callback, isCopyPaste) {
		//if copy/paste - use only actve ws
		if (isCopyPaste) {
			callback(this.getActiveWs(), this.getActive());
		} else {
			for (var i = 0, l = this.aWorksheets.length; i < l; ++i) {
				callback(this.aWorksheets[i], i);
			}
		}
	};
	Workbook.prototype.rebuildColors=function(){
		AscCommonExcel.g_oColorManager.rebuildColors();
		this.forEach(function (ws) {
			ws.rebuildColors();
		});
	};
	Workbook.prototype.getDefaultFont=function(){
		return g_oDefaultFormat.Font.getName();
	};
	Workbook.prototype.getDefaultSize=function(){
		return g_oDefaultFormat.Font.getSize();
	};
	Workbook.prototype.getActive=function(){
		return this.nActive;
	};
	Workbook.prototype.getActiveWs = function () {
		return this.getWorksheet(this.nActive);
	};
	Workbook.prototype.setActive=function(index){
		if(index >= 0 && index < this.aWorksheets.length){
			this.nActive = index;
			// Must clean find
			this.cleanFindResults();
			return true;
		}
		return false;
	};
	Workbook.prototype.setActiveById=function(sheetId){
		var ws = this.getWorksheetById(sheetId);
		return this.setActive(ws.getIndex());
	};
	Workbook.prototype.getSheetIdByIndex = function(index) {
		var ws = this.getWorksheet(index);
		return ws ? ws.getId() : null;
	};
	Workbook.prototype.getWorksheet=function(index){
		//index 0-based
		if(index >= 0 && index < this.aWorksheets.length){
			return this.aWorksheets[index];
		}
		return null;
	};
	Workbook.prototype.getWorksheetById=function(id){
		return this.aWorksheetsById[id];
	};
	Workbook.prototype.getWorksheetByName=function(name){
		for(var i = 0; i < this.aWorksheets.length; i++)
			if(this.aWorksheets[i].getName() == name){
				return this.aWorksheets[i];
			}
		return null;
	};
	Workbook.prototype.getWorksheetIndexByName=function(name){
		for(var i = 0; i < this.aWorksheets.length; i++)
			if(this.aWorksheets[i].getName() == name){
				return i;
			}
		return null;
	};
	Workbook.prototype.getWorksheetCount=function(){
		return this.aWorksheets.length;
	};
	Workbook.prototype.createWorksheet=function(indexBefore, sName, sId){
		this.dependencyFormulas.lockRecal();
		History.Create_NewPoint();
		History.TurnOff();
		var wsActive = this.getActiveWs();
		var oNewWorksheet = new Worksheet(this, this.aWorksheets.length, sId);
		if (this.checkValidSheetName(sName))
			oNewWorksheet.sName = sName;
		oNewWorksheet.initPostOpen(this.wsHandlers);
		if(null != indexBefore && indexBefore >= 0 && indexBefore < this.aWorksheets.length)
			this.aWorksheets.splice(indexBefore, 0, oNewWorksheet);
		else
		{
			indexBefore = this.aWorksheets.length;
			this.aWorksheets.push(oNewWorksheet);
		}
		this.aWorksheetsById[oNewWorksheet.getId()] = oNewWorksheet;
		this._updateWorksheetIndexes(wsActive);
		History.TurnOn();
		this._insertWorksheetFormula(oNewWorksheet.index);
		History.Add(AscCommonExcel.g_oUndoRedoWorkbook, AscCH.historyitem_Workbook_SheetAdd, null, null, new UndoRedoData_SheetAdd(indexBefore, oNewWorksheet.getName(), null, oNewWorksheet.getId()));
		History.SetSheetUndo(wsActive.getId());
		History.SetSheetRedo(oNewWorksheet.getId());
		this.dependencyFormulas.unlockRecal();
		return oNewWorksheet.index;
	};
	Workbook.prototype.copyWorksheet=function(index, insertBefore, sName, sId, bFromRedo, tableNames){
		//insertBefore - optional
		if(index >= 0 && index < this.aWorksheets.length){
			//buildRecalc вызываем чтобы пересчиталося cwf(может быть пустым если сделать сдвиг формул и скопировать лист)
			this.dependencyFormulas.buildDependency();
			History.TurnOff();
			var wsActive = this.getActiveWs();
			var wsFrom = this.aWorksheets[index];
			var newSheet = new Worksheet(this, -1, sId);
			if(null != insertBefore && insertBefore >= 0 && insertBefore < this.aWorksheets.length){
				//помещаем новый sheet перед insertBefore
				this.aWorksheets.splice(insertBefore, 0, newSheet);
			}
			else{
				//помещаем новый sheet в конец
				this.aWorksheets.push(newSheet);
			}
			this.aWorksheetsById[newSheet.getId()] = newSheet;
			this._updateWorksheetIndexes(wsActive);
			//copyFrom after sheet add because formula assemble dependce on sheet structure
			var renameParams = newSheet.copyFrom(wsFrom, sName, tableNames);
			newSheet.initPostOpen(this.wsHandlers);
			History.TurnOn();

			this.dependencyFormulas.copyDefNameByWorksheet(wsFrom, newSheet, renameParams);
			//для формул. создаем копию this.cwf[this.Id] для нового листа.
			//newSheet._BuildDependencies(wsFrom.getCwf());

			//now insertBefore is index of inserted sheet
			this._insertWorksheetFormula(insertBefore);

			if (!tableNames) {
				tableNames = newSheet.getTableNames();
			}

			History.Add(AscCommonExcel.g_oUndoRedoWorkbook, AscCH.historyitem_Workbook_SheetAdd, null, null, new UndoRedoData_SheetAdd(insertBefore, newSheet.getName(), wsFrom.getId(), newSheet.getId(), tableNames));
			History.SetSheetUndo(wsActive.getId());
			History.SetSheetRedo(newSheet.getId());
			if(!(bFromRedo === true))
			{
				wsFrom.copyObjects(newSheet, wsFrom);
			}
			this.sortDependency();
		}
	};
	Workbook.prototype.insertWorksheet = function (index, sheet) {
		var wsActive = this.getActiveWs();
		if(null != index && index >= 0 && index < this.aWorksheets.length){
			//помещаем новый sheet перед insertBefore
			this.aWorksheets.splice(index, 0, sheet);
		}
		else{
			//помещаем новый sheet в конец
			this.aWorksheets.push(sheet);
		}
		this.aWorksheetsById[sheet.getId()] = sheet;
		this._updateWorksheetIndexes(wsActive);
		this._insertWorksheetFormula(index);
		this._insertTablePartsName(sheet);
		//восстанавливаем список ячеек с формулами для sheet
		sheet._BuildDependencies(sheet.getCwf());
		this.sortDependency();
	};
	Workbook.prototype._insertTablePartsName = function (sheet) {
		if(sheet && sheet.TableParts && sheet.TableParts.length)
		{
			for(var i = 0; i < sheet.TableParts.length; i++)
			{
				var tablePart = sheet.TableParts[i];
				this.dependencyFormulas.addTableName(sheet, tablePart);
				tablePart.buildDependencies();
			}
		}
	};
	Workbook.prototype._insertWorksheetFormula=function(index){
		if( index > 0 && index < this.aWorksheets.length ) {
			var oWsBefore = this.aWorksheets[index - 1];
			this.dependencyFormulas.changeSheet(this.dependencyFormulas.prepareChangeSheet(oWsBefore.getId(), {insert: index}));
		}
	};
	Workbook.prototype.replaceWorksheet=function(indexFrom, indexTo){
		if(indexFrom >= 0 && indexFrom < this.aWorksheets.length &&
			indexTo >= 0 && indexTo < this.aWorksheets.length){
			var wsActive = this.getActiveWs();
			var oWsFrom = this.aWorksheets[indexFrom];
			var tempW = {
				wF: oWsFrom,
				wFI: indexFrom,
				wTI: indexTo
			};
			//wTI index insert before
			if(tempW.wFI < tempW.wTI)
				tempW.wTI++;
			this.dependencyFormulas.lockRecal();
			var prepared = this.dependencyFormulas.prepareChangeSheet(oWsFrom.getId(), {replace: tempW}, null);
			//move sheets
			var movedSheet = this.aWorksheets.splice(indexFrom, 1);
			this.aWorksheets.splice(indexTo, 0, movedSheet[0]);
			this._updateWorksheetIndexes(wsActive);
			this.dependencyFormulas.changeSheet(prepared);

			this._insertWorksheetFormula(indexTo);

			History.Add(AscCommonExcel.g_oUndoRedoWorkbook, AscCH.historyitem_Workbook_SheetMove, null, null, new UndoRedoData_FromTo(indexFrom, indexTo));
			this.dependencyFormulas.unlockRecal();
		}
	};
	Workbook.prototype.findSheetNoHidden = function (nIndex) {
		var i, ws, oRes = null, bFound = false, countWorksheets = this.getWorksheetCount();
		for (i = nIndex; i < countWorksheets; ++i) {
			ws = this.getWorksheet(i);
			if (false === ws.getHidden()) {
				oRes = ws;
				bFound = true;
				break;
			}
		}
		// Не нашли справа, ищем слева от текущего
		if (!bFound) {
			for (i = nIndex - 1; i >= 0; --i) {
				ws = this.getWorksheet(i);
				if (false === ws.getHidden()) {
					oRes = ws;
					break;
				}
			}
		}
		return oRes;
	};
	Workbook.prototype.removeWorksheet=function(nIndex, outputParams){
		//проверяем останется ли хоть один нескрытый sheet
		var bEmpty = true;
		for(var i = 0, length = this.aWorksheets.length; i < length; ++i)
		{
			var worksheet = this.aWorksheets[i];
			if(false == worksheet.getHidden() && i != nIndex)
			{
				bEmpty = false;
				break;
			}
		}
		if(bEmpty)
			return -1;

		var removedSheet = this.getWorksheet(nIndex);
		if(removedSheet)
		{
			var removedSheetId = removedSheet.getId();
			this.dependencyFormulas.lockRecal();
			var prepared = this.dependencyFormulas.prepareRemoveSheet(removedSheetId, removedSheet.getTableNames());
			//delete sheet
			var wsActive = this.getActiveWs();
			var oVisibleWs = null;
			this.aWorksheets.splice(nIndex, 1);
			delete this.aWorksheetsById[removedSheetId];

			if (nIndex == this.getActive()) {
				oVisibleWs = this.findSheetNoHidden(nIndex);
				if (null != oVisibleWs)
					wsActive = oVisibleWs;
			}
			History.Add(AscCommonExcel.g_oUndoRedoWorkbook, AscCH.historyitem_Workbook_SheetRemove, null, null, new AscCommonExcel.UndoRedoData_SheetRemove(nIndex, removedSheetId, removedSheet));
			if (null != oVisibleWs) {
				History.SetSheetUndo(removedSheetId);
				History.SetSheetRedo(wsActive.getId());
			}
			if(null != outputParams)
			{
				outputParams.sheet = removedSheet;
			}
			this._updateWorksheetIndexes(wsActive);
			this.dependencyFormulas.removeSheet(prepared);
			this.dependencyFormulas.unlockRecal();
			return wsActive.getIndex();
		}
		return -1;
	};
	Workbook.prototype._updateWorksheetIndexes = function (wsActive) {
		this.forEach(function (ws, index) {
			ws._setIndex(index);
		});
		if (null != wsActive) {
			this.setActive(wsActive.getIndex());
		}
	};
	Workbook.prototype.checkUniqueSheetName=function(name){
		var workbookSheetCount = this.getWorksheetCount();
		for (var i = 0; i < workbookSheetCount; i++){
			if (this.getWorksheet(i).getName() == name)
				return i;
		}
		return -1;
	};
	Workbook.prototype.checkValidSheetName=function(name){
		return (name && name.length < g_nSheetNameMaxLength);
	};
	Workbook.prototype.getUniqueSheetNameFrom=function(name, bCopy){
		var nIndex = 1;
		var sNewName = "";
		var fGetPostfix = null;
		if(bCopy)
		{

			var result = /^(.*)\((\d)\)$/.exec(name);
			if(result)
			{
				fGetPostfix = function(nIndex){return "(" + nIndex +")";};
				name = result[1];
			}
			else
			{
				fGetPostfix = function(nIndex){return " (" + nIndex +")";};
				name = name;
			}
		}
		else
		{
			fGetPostfix = function(nIndex){return nIndex.toString();};
		}
		var workbookSheetCount = this.getWorksheetCount();
		while(nIndex < 10000)
		{
			var sPosfix = fGetPostfix(nIndex);
			sNewName = name + sPosfix;
			if(sNewName.length > g_nSheetNameMaxLength)
			{
				name = name.substring(0, g_nSheetNameMaxLength - sPosfix.length);
				sNewName = name + sPosfix;
			}
			var bUniqueName = true;
			for (var i = 0; i < workbookSheetCount; i++){
				if (this.getWorksheet(i).getName() == sNewName)
				{
					bUniqueName = false;
					break;
				}
			}
			if(bUniqueName)
				break;
			nIndex++;
		}
		return sNewName;
	};
	Workbook.prototype._generateFontMap=function(){
		var oFontMap = {
			"Arial"		: 1
		};
		var i;

		oFontMap[g_oDefaultFormat.Font.getName()] = 1;

		//theme
		if(null != this.theme)
			AscFormat.checkThemeFonts(oFontMap, this.theme.themeElements.fontScheme);
		//xfs
		for (i = 1; i <= g_StyleCache.getXfCount(); ++i) {
			var xf = g_StyleCache.getXf(i);
			if (xf.font) {
				oFontMap[xf.font.getName()] = 1;
			}
		}
		//sharedStrings
		this.sharedStrings.generateFontMap(oFontMap);

		this.forEach(function (ws) {
			ws.generateFontMap(oFontMap);
		});
		this.CellStyles.generateFontMap(oFontMap);

		return oFontMap;
	};
	Workbook.prototype.generateFontMap=function(){
		var oFontMap = this._generateFontMap();

		var aRes = [];
		for(var i in oFontMap)
			aRes.push(i);
		return aRes;
	};
	Workbook.prototype.generateFontMap2=function(){
		var oFontMap = this._generateFontMap();

		var aRes = [];
		for(var i in oFontMap)
			aRes.push(new AscFonts.CFont(i, 0, "", 0));
		AscFonts.FontPickerByCharacter.extendFonts(aRes);
		return aRes;
	};
	Workbook.prototype.getAllImageUrls = function(){
		var aImageUrls = [];
		this.forEach(function (ws) {
			ws.getAllImageUrls(aImageUrls);
		});
		return aImageUrls;
	};
	Workbook.prototype.reassignImageUrls = function(oImages){
		this.forEach(function (ws) {
			ws.reassignImageUrls(oImages);
		});
	};
	Workbook.prototype.recalcWB = function(rebuild, opt_sheetId) {
		var formulas;
		if (rebuild) {
			formulas = this.getAllFormulas();
			for (var i = 0; i < formulas.length; ++i) {
				var formula = formulas[i];
				formula.removeDependencies();
				formula.setFormula(formula.getFormula());
				formula.parse();
				formula.buildDependencies();
			}
		} else if (opt_sheetId) {
			formulas = [];
			var ws = this.getWorksheetById(opt_sheetId);
			ws.getAllFormulas(formulas);
		} else {
			formulas = this.getAllFormulas();
		}
		this.dependencyFormulas.notifyChanged(formulas);
		this.dependencyFormulas.calcTree();
	};
	Workbook.prototype.checkDefName = function (checkName, scope) {
		return this.dependencyFormulas.checkDefName(checkName, scope);
	};
	Workbook.prototype.getDefinedNamesWB = function (defNameListId, bLocale) {
		return this.dependencyFormulas.getDefinedNamesWB(defNameListId, bLocale);
	};
	Workbook.prototype.getDefinesNames = function ( name, sheetId ) {
		return this.dependencyFormulas.getDefNameByName( name, sheetId );
	};
	Workbook.prototype.getDefinedName = function(name) {
		var sheetId = this.getSheetIdByIndex(name.LocalSheetId);
		return this.dependencyFormulas.getDefNameByName(name.Name, sheetId);
	};
	Workbook.prototype.delDefinesNames = function ( defName ) {
		this.delDefinesNamesUndoRedo(this.getUndoDefName(defName));
	};
	Workbook.prototype.delDefinesNamesUndoRedo = function ( defName ) {
		this.dependencyFormulas.removeDefName( defName.sheetId, defName.name );
		this.dependencyFormulas.calcTree();
	};
	Workbook.prototype.editDefinesNames = function ( oldName, newName ) {
		return this.editDefinesNamesUndoRedo(this.getUndoDefName(oldName), this.getUndoDefName(newName));
	};
	Workbook.prototype.editDefinesNamesUndoRedo = function ( oldName, newName ) {
		var res = this.dependencyFormulas.editDefinesNames( oldName, newName );
		this.dependencyFormulas.calcTree();
		return res;
	};
	Workbook.prototype.findDefinesNames = function ( ref, sheetId ) {
		return this.dependencyFormulas.getDefNameByRef( ref, sheetId );
	};
	Workbook.prototype.unlockDefName = function(){
		this.dependencyFormulas.unlockDefName();
	};
	Workbook.prototype.checkDefNameLock = function(){
		return this.dependencyFormulas.checkDefNameLock();
	};
	Workbook.prototype._SerializeHistoryBase64 = function (oMemory, item, aPointChangesBase64) {
		if (!item.LocalChange) {
			var nPosStart = oMemory.GetCurPosition();
			item.Serialize(oMemory, this.oApi.collaborativeEditing);
			var nPosEnd = oMemory.GetCurPosition();
			var nLen = nPosEnd - nPosStart;
			if (nLen > 0)
				aPointChangesBase64.push(nLen + ";" + oMemory.GetBase64Memory2(nPosStart, nLen));
		}
	};
	Workbook.prototype.SerializeHistory = function(){
		var aRes = [];
		//соединяем изменения, которые были до приема данных с теми, что получились после.

		var t, j, length2;

		// Пересчитываем позиции
		AscCommon.CollaborativeEditing.Refresh_DCChanges();

		var aActions = this.aCollaborativeActions.concat(History.GetSerializeArray());
		if(aActions.length > 0)
		{
			var oMemory = new AscCommon.CMemory();
			for(var i = 0, length = aActions.length; i < length; ++i)
			{
				var aPointChanges = aActions[i];
				for (j = 0, length2 = aPointChanges.length; j < length2; ++j) {
					var item = aPointChanges[j];
					this._SerializeHistoryBase64(oMemory, item, aRes);
				}
			}
			this.aCollaborativeActions = [];
			this.snapshot = this._getSnapshot();
		}
		return aRes;
	};
	Workbook.prototype._getSnapshot = function() {
		var wb = new Workbook(new AscCommonExcel.asc_CHandlersList(), this.oApi);
		wb.dependencyFormulas = this.dependencyFormulas.getSnapshot(wb);
		this.forEach(function (ws) {
			ws = ws.getSnapshot(wb);
			wb.aWorksheets.push(ws);
			wb.aWorksheetsById[ws.getId()] = ws;
		});
		//init trigger
		wb.init({}, true, false);
		return wb;
	};
	Workbook.prototype.getAllFormulas = function() {
		var res = [];
		this.dependencyFormulas.getAllFormulas(res);
		this.forEach(function (ws) {
			ws.getAllFormulas(res);
		});
		return res;
	};
	Workbook.prototype._forwardTransformation = function(wbSnapshot, changesMine, changesTheir) {
		History.TurnOff();
		//first mine changes to resolve conflict sheet names
		var res1 = this._forwardTransformationGetTransform(wbSnapshot, changesTheir, changesMine);
		var res2 = this._forwardTransformationGetTransform(wbSnapshot, changesMine, changesTheir);
		//modify formulas at the end - to prevent negative effect during tranformation
		var i, elem, elemWrap;
		for (i = 0; i < res1.modify.length; ++i) {
			elemWrap = res1.modify[i];
			elem = elemWrap.elem;
			elem.oClass.forwardTransformationSet(elem.nActionType, elem.oData, elem.nSheetId, elemWrap);
		}
		for (i = 0; i < res2.modify.length; ++i) {
			elemWrap = res2.modify[i];
			elem = elemWrap.elem;
			elem.oClass.forwardTransformationSet(elem.nActionType, elem.oData, elem.nSheetId, elemWrap);
		}
		//rename current wb
		for (var oldName in res1.renameSheet) {
			var ws = this.getWorksheetByName(oldName);
			if (ws) {
				ws.setName(res1.renameSheet[oldName]);
			}
		}
		History.TurnOn();
	};
	Workbook.prototype._forwardTransformationGetTransform = function(wbSnapshot, changesMaster, changesModify) {
		var res = {modify: [], renameSheet: {}};
		var changesMasterSelected = [];
		var i, elem;
		if (changesModify.length > 0) {
			//select useful master changes
			for ( i = 0; i < changesMaster.length; ++i) {
				elem = changesMaster[i];
				if (elem.oClass && elem.oClass.forwardTransformationIsAffect &&
					elem.oClass.forwardTransformationIsAffect(elem.nActionType)) {
					changesMasterSelected.push(elem);
				}
			}
		}
		if (changesMasterSelected.length > 0 && changesModify.length > 0) {
			var wbSnapshotCur = wbSnapshot._getSnapshot();
			var formulas = [];
			for (i = 0; i < changesModify.length; ++i) {
				elem = changesModify[i];
				var renameRes = null;
				if (elem.oClass && elem.oClass.forwardTransformationGet) {
					var getRes = elem.oClass.forwardTransformationGet(elem.nActionType, elem.oData, elem.nSheetId);
					if (getRes && getRes.formula) {
						//inserted formulas
						formulas.push(new ForwardTransformationFormula(elem, getRes.formula, null));
					}
					if (getRes && getRes.name) {
						//add/rename sheet
						//get getUniqueSheetNameFrom if need
						renameRes = this._forwardTransformationRenameStart(wbSnapshotCur._getSnapshot(),
																		   changesMasterSelected, getRes);
					}
				}
				if (elem.oClass && elem.oClass.forwardTransformationIsAffect &&
					elem.oClass.forwardTransformationIsAffect(elem.nActionType)) {
					if (formulas.length > 0) {
						//modify all formulas before apply next change
						this._forwardTransformationFormula(wbSnapshotCur._getSnapshot(), formulas,
														   changesMasterSelected, res);
						formulas = [];
					}
					//apply useful mine change
					elem.oClass.Redo(elem.nActionType, elem.oData, elem.nSheetId, wbSnapshotCur);
				}
				if (renameRes) {
					this._forwardTransformationRenameEnd(renameRes, res.renameSheet, getRes, elem);
				}
			}
			this._forwardTransformationFormula(wbSnapshotCur, formulas, changesMasterSelected, res);
		}
		return res;
	};
	Workbook.prototype._forwardTransformationRenameStart = function(wbSnapshot, changes, getRes) {
		var res = {newName: null};
		for (var i = 0; i < changes.length; ++i) {
			var elem = changes[i];
			elem.oClass.Redo(elem.nActionType, elem.oData, elem.nSheetId, wbSnapshot);
		}
		if (-1 != wbSnapshot.checkUniqueSheetName(getRes.name)) {
			res.newName = wbSnapshot.getUniqueSheetNameFrom(getRes.name, true);
		}
		return res;
	};
	Workbook.prototype._forwardTransformationRenameEnd = function(renameRes, renameSheet, getRes, elemCur) {
		var isChange = false;
		if (getRes.from) {
			var renameCur = renameSheet[getRes.from];
			if (renameCur) {
				//no need rename next formulas
				delete renameSheet[getRes.from];
				getRes.from = renameCur;
				isChange = true;
			}
		}
		if (renameRes && renameRes.newName) {
			renameSheet[getRes.name] = renameRes.newName;
			getRes.name = renameRes.newName;
			isChange = true;
		}
		//apply immediately cause it is conflict
		if (isChange && elemCur.oClass.forwardTransformationSet) {
			elemCur.oClass.forwardTransformationSet(elemCur.nActionType, elemCur.oData, elemCur.nSheetId, getRes);
		}
	};
	Workbook.prototype._forwardTransformationFormula = function(wbSnapshot, formulas, changes, res) {
		if (formulas.length > 0) {
			var i, elem, ftFormula, ws;
			//parse formulas
			for (i = 0; i < formulas.length; ++i) {
				ftFormula = formulas[i];
				ws = wbSnapshot.getWorksheetById(ftFormula.elem.nSheetId);
				if (ws) {
					ftFormula.parsed = new parserFormula(ftFormula.formula, ftFormula, ws);
					ftFormula.parsed.parse();
					ftFormula.parsed.buildDependencies();
				}
			}
			//rename sheet first to prevent name conflict
			for (var oldName in res.renameSheet) {
				ws = wbSnapshot.getWorksheetByName(oldName);
				if (ws) {
					ws.setName(res.renameSheet[oldName]);
				}
			}
			//apply useful theirs changes
			for (i = 0; i < changes.length; ++i) {
				elem = changes[i];
				elem.oClass.Redo(elem.nActionType, elem.oData, elem.nSheetId, wbSnapshot);
			}
			//assemble
			for (i = 0; i < formulas.length; ++i) {
				ftFormula = formulas[i];
				if (ftFormula.parsed) {
					ftFormula.parsed.removeDependencies();
					res.modify.push(ftFormula);
				}
			}
		}
	};
	Workbook.prototype.DeserializeHistory = function(aChanges, fCallback){
		var oThis = this;
		//сохраняем те изменения, которые были до приема данных, потому что дальше undo/redo будет очищено
		this.aCollaborativeActions = this.aCollaborativeActions.concat(History.GetSerializeArray());
		if(aChanges.length > 0)
		{
			this.bCollaborativeChanges = true;
			//собираем общую длину
			var dstLen = 0;
			var aIndexes = [], i, length = aChanges.length, sChange;
			for(i = 0; i < length; ++i)
			{
				sChange = aChanges[i];
				var nIndex = sChange.indexOf(";");
				if (-1 != nIndex) {
					dstLen += parseInt(sChange.substring(0, nIndex));
					nIndex++;
				}
				aIndexes.push(nIndex);
			}
			var pointer = g_memory.Alloc(dstLen);
			var stream = new AscCommon.FT_Stream2(pointer.data, dstLen);
			stream.obj = pointer.obj;
			var nCurOffset = 0;
			var aUndoRedoElems = [];
			for (i = 0; i < length; ++i) {
				sChange = aChanges[i];
				var oBinaryFileReader = new AscCommonExcel.BinaryFileReader();
				nCurOffset = oBinaryFileReader.getbase64DecodedData2(sChange, aIndexes[i], stream, nCurOffset);
				var item = new UndoRedoItemSerializable();
				item.Deserialize(stream);
				aUndoRedoElems.push(item);
			}
			var wsViews = window["Asc"]["editor"].wb.wsViews;
			if(oThis.oApi.collaborativeEditing.getFast()){
				AscCommon.CollaborativeEditing.Clear_DocumentPositions();
			}
			for (var i in wsViews) {
				if (isRealObject(wsViews[i]) && isRealObject(wsViews[i].objectRender) &&
					isRealObject(wsViews[i].objectRender.controller)) {
					wsViews[i].endEditChart();
					if (oThis.oApi.collaborativeEditing.getFast()) {
						var oState = wsViews[i].objectRender.saveStateBeforeLoadChanges();
						if (oState) {
							if (oState.Pos) {
								AscCommon.CollaborativeEditing.Add_DocumentPosition(oState.Pos);
							}
							if (oState.StartPos) {
								AscCommon.CollaborativeEditing.Add_DocumentPosition(oState.StartPos);
							}
							if (oState.EndPos) {
								AscCommon.CollaborativeEditing.Add_DocumentPosition(oState.EndPos);
							}
						}
					}
					wsViews[i].objectRender.controller.resetSelection();
				}
			}
			oFormulaLocaleInfo.Parse = false;
			oFormulaLocaleInfo.DigitSep = false;
			AscFonts.IsCheckSymbols = true;
			History.Clear();
			History.TurnOff();
			var history = new AscCommon.CHistory();
			history.init(this);
			history.Create_NewPoint();

			history.SetSelection(null);
			history.SetSelectionRedo(null);
			var oRedoObjectParam = new AscCommonExcel.RedoObjectParam();
			history.UndoRedoPrepare(oRedoObjectParam, false);
			var changesMine = [].concat.apply([], oThis.aCollaborativeActions);
			oThis._forwardTransformation(oThis.snapshot, changesMine, aUndoRedoElems);
			for (var i = 0, length = aUndoRedoElems.length; i < length; ++i)
			{
				var item = aUndoRedoElems[i];
				if ((null != item.oClass || (item.oData && typeof item.oData.sChangedObjectId === "string")) && null != item.nActionType) {
					if (window["NATIVE_EDITOR_ENJINE"] === true && window["native"]["CheckNextChange"]) {
						if (!window["native"]["CheckNextChange"]())
							break;
					}
					// TODO if(g_oUndoRedoGraphicObjects == item.oClass && item.oData.drawingData)
					//     item.oData.drawingData.bCollaborativeChanges = true;
					history.RedoAdd(oRedoObjectParam, item.oClass, item.nActionType, item.nSheetId, item.oRange, item.oData);
				}
			}
			AscFonts.IsCheckSymbols = false;

			var oFontMap = this._generateFontMap();
			window["Asc"]["editor"]._loadFonts(oFontMap, function(){
				if(oThis.oApi.collaborativeEditing.getFast()){


					for(var i in wsViews){
						if(isRealObject(wsViews[i]) && isRealObject(wsViews[i].objectRender) && isRealObject(wsViews[i].objectRender.controller)){
							var oState = wsViews[i].objectRender.getStateBeforeLoadChanges();
							if(oState){
								if (oState.Pos)
									AscCommon.CollaborativeEditing.Update_DocumentPosition(oState.Pos);
								if (oState.StartPos)
									AscCommon.CollaborativeEditing.Update_DocumentPosition(oState.StartPos);
								if (oState.EndPos)
									AscCommon.CollaborativeEditing.Update_DocumentPosition(oState.EndPos);
							}
							wsViews[i].objectRender.loadStateAfterLoadChanges();
						}
					}
				}
				oFormulaLocaleInfo.Parse = true;
				oFormulaLocaleInfo.DigitSep = true;
				history.UndoRedoEnd(null, oRedoObjectParam, false);
				History.TurnOn();
				oThis.bCollaborativeChanges = false;
				//make snapshot for faormulas
				oThis.snapshot = oThis._getSnapshot();
				if(null != fCallback)
					fCallback();
			});
		} else if(null != fCallback) {
			fCallback();
		}
	};
	Workbook.prototype.DeserializeHistoryNative = function(oRedoObjectParam, data, isFull){
		if(null != data)
		{
			this.bCollaborativeChanges = true;

			if(null == oRedoObjectParam)
			{
				var wsViews = window["Asc"]["editor"].wb.wsViews;
				for (var i in wsViews) {
					if (isRealObject(wsViews[i]) && isRealObject(wsViews[i].objectRender) &&
						isRealObject(wsViews[i].objectRender.controller)) {
						wsViews[i].endEditChart();
						wsViews[i].objectRender.controller.resetSelection();
					}
				}

				History.Clear();
				History.Create_NewPoint();
				History.SetSelection(null);
				History.SetSelectionRedo(null);
				oRedoObjectParam = new AscCommonExcel.RedoObjectParam();
				History.UndoRedoPrepare(oRedoObjectParam, false);
			}

			var stream = new AscCommon.FT_Stream2(data, data.length);
			stream.obj = null;
			// Применяем изменения, пока они есть
			var _count = stream.GetLong();
			var _pos = 4;
			for (var i = 0; i < _count; i++)
			{
				if (window["NATIVE_EDITOR_ENJINE"] === true && window["native"]["CheckNextChange"])
				{
					if (!window["native"]["CheckNextChange"]())
						break;
				}

				var _len = stream.GetLong();

				_pos += 4;
				stream.size = _pos + _len;
				stream.Seek(_pos);
				stream.Seek2(_pos);

				var item = new UndoRedoItemSerializable();
				item.Deserialize(stream);
				if ((null != item.oClass || (item.oData && typeof item.oData.sChangedObjectId === "string")) && null != item.nActionType)
					History.RedoAdd(oRedoObjectParam, item.oClass, item.nActionType, item.nSheetId, item.oRange, item.oData);

				_pos += _len;
				stream.Seek2(_pos);
				stream.size = data.length;
			}

			if(isFull){
				History.UndoRedoEnd(null, oRedoObjectParam, false);
				History.Clear();
				oRedoObjectParam = null;
			}
			this.bCollaborativeChanges = false;
		}
		return oRedoObjectParam;
	};
	Workbook.prototype.getTableRangeForFormula = function(name, objectParam){
		var res = null;
		for(var i = 0, length = this.aWorksheets.length; i < length; ++i)
		{
			var ws = this.aWorksheets[i];
			res = ws.getTableRangeForFormula(name, objectParam);
			if(res !== null){
				res = {wsID:ws.getId(),range:res};
				break;
			}
		}
		return res;
	};
	Workbook.prototype.getTableIndexColumnByName = function(tableName, columnName){
		var res = null;
		for(var i = 0, length = this.aWorksheets.length; i < length; ++i)
		{
			var ws = this.aWorksheets[i];
			res = ws.getTableIndexColumnByName(tableName, columnName);
			if(res !== null){
				res = {wsID:ws.getId(), index: res, name: columnName};
				break;
			}
		}
		return res;
	};
	Workbook.prototype.getTableNameColumnByIndex = function(tableName, columnIndex){
		var res = null;
		for(var i = 0, length = this.aWorksheets.length; i < length; ++i)
		{
			var ws = this.aWorksheets[i];
			res = ws.getTableNameColumnByIndex(tableName, columnIndex);
			if(res !== null){
				res = {wsID:ws.getId(), columnName: res};
				break;
			}
		}
		return res;
	};
	Workbook.prototype.updateSparklineCache = function (sheet, ranges) {
		this.forEach(function (ws) {
			ws.updateSparklineCache(sheet, ranges);
		});
	};
	Workbook.prototype.sortDependency = function () {
		this.dependencyFormulas.calcTree();
	};
	/**
	 * Вычисляет ширину столбца для заданного количества символов
	 * @param {Number} count  Количество символов
	 * @returns {Number}      Ширина столбца в символах
	 */
	Workbook.prototype.charCountToModelColWidth = function (count) {
		if (count <= 0) {
			return 0;
		}
		return Asc.floor((count * this.maxDigitWidth + this.paddingPlusBorder) / this.maxDigitWidth * 256) / 256;
	};
	/**
	 * Вычисляет ширину столбца в px
	 * @param {Number} mcw  Количество символов
	 * @returns {Number}    Ширина столбца в px
	 */
	Workbook.prototype.modelColWidthToColWidth = function (mcw) {
		return Asc.floor(((256 * mcw + Asc.floor(128 / this.maxDigitWidth)) / 256) * this.maxDigitWidth);
	};
	/**
	 * Вычисляет количество символов по ширине столбца
	 * @param {Number} w  Ширина столбца в px
	 * @returns {Number}  Количество символов
	 */
	Workbook.prototype.colWidthToCharCount = function (w) {
		var pxInOneCharacter = this.maxDigitWidth + this.paddingPlusBorder;
		// Когда меньше 1 символа, то просто считаем по пропорции относительно размера 1-го символа
		return w < pxInOneCharacter ?
			(1 - Asc.floor(100 * (pxInOneCharacter - w) / pxInOneCharacter + 0.49999) / 100) :
			Asc.floor((w - this.paddingPlusBorder) / this.maxDigitWidth * 100 + 0.5) / 100;
	};
	Workbook.prototype.getUndoDefName = function(ascName) {
		if (!ascName) {
			return ascName;
		}
		var sheetId = this.getSheetIdByIndex(ascName.LocalSheetId);
		return new UndoRedoData_DefinedNames(ascName.Name, ascName.Ref, sheetId, ascName.isTable);
	};
	Workbook.prototype.changeColorScheme = function (index) {
		var scheme = AscCommon.getColorThemeByIndex(index);
		if (!scheme) {
			index -= AscCommon.g_oUserColorScheme.length;
			if (index < 0 || index >= this.theme.extraClrSchemeLst.length) {
				return false;
			}

			scheme = this.theme.extraClrSchemeLst[index].clrScheme.createDuplicate();
		}
		History.Create_NewPoint();
		//не делаем Duplicate потому что предполагаем что схема не будет менять частями, а только обьектом целиком.
		History.Add(AscCommonExcel.g_oUndoRedoWorkbook, AscCH.historyitem_Workbook_ChangeColorScheme, null,
			null, new AscCommonExcel.UndoRedoData_ClrScheme(this.theme.themeElements.clrScheme, scheme));
		this.theme.themeElements.clrScheme = scheme;
		this.rebuildColors();
		return true;
	};
	// ----- Search -----
	Workbook.prototype.cleanFindResults = function () {
		this.lastFindOptions = null;
		this.lastFindCells = {};
	};
	Workbook.prototype.findCellText = function (options) {
		var ws = this.getActiveWs();
		var result = ws.findCellText(options), result2 = null;
		if (!options.scanOnOnlySheet) {
			// Search on workbook
			var key = result && (result.col + "-" + result.row);
			if (!key || (options.isEqual(this.lastFindOptions) && this.lastFindCells[key])) {
				// Мы уже находили данную ячейку, попробуем на другом листе
				var i, active = this.getActive(), start = 0, end = this.getWorksheetCount();
				var inc = options.scanForward ? +1 : -1;
				for (i = active + inc; i < end && i >= start; i += inc) {
					ws = this.getWorksheet(i);
					if (ws.getHidden()) {
						continue;
					}
					result2 = ws.findCellText(options);
					if (result2) {
						break;
					}
				}
				if (!result2) {
					// Мы дошли до конца или начала (в зависимости от направления, теперь пойдем до активного)
					if (options.scanForward) {
						i = 0;
						end = active;
					} else {
						i = end - 1;
						start = active + 1;
					}
					inc *= -1;
					for (; i < end && i >= start; i += inc) {
						ws = this.getWorksheet(i);
						if (ws.getHidden()) {
							continue;
						}
						result2 = ws.findCellText(options);
						if (result2) {
							break;
						}
					}
				}

				if (result2) {
					this.handlers.trigger('undoRedoHideSheet', i);
					key = result2.col + "-" + result2.row;
				}
			}

			if (key) {
				this.lastFindOptions = options.clone();
				this.lastFindCells[key] = true;
			}
		}
		if (!result2 && !result) {
			this.cleanFindResults();
		}
		return result2 || result;
	};
//-------------------------------------------------------------------------------------------------
	var tempHelp = new ArrayBuffer(8);
	var tempHelpUnit = new Uint8Array(tempHelp);
	var tempHelpFloat = new Float64Array(tempHelp);
	function SheetMemory(structSize, maxIndex) {
		this.data = null;
		this.count = 0;
		this.structSize = structSize;
		this.maxIndex = maxIndex;
	}
	SheetMemory.prototype.checkSize = function(index) {
		var allocatedCount = this.data ? this.data.length / this.structSize : 0;
		if (allocatedCount < index + 1) {
			var newAllocatedCount = Math.min(Math.max((1.5 * this.count) >> 0, index + 1), (this.maxIndex + 1));
			if (newAllocatedCount > allocatedCount) {
				var oldData = this.data;
				this.data = new Uint8Array(newAllocatedCount * this.structSize);
				if (oldData) {
					this.data.set(oldData);
				}
			}
		}
		this.count = Math.min(Math.max(this.count, index + 1), this.maxIndex + 1);
	};
	SheetMemory.prototype.hasSize = function(index) {
		return index + 1 <= this.count;
	};
	SheetMemory.prototype.getSize = function() {
		return this.count;
	};
	SheetMemory.prototype.clone = function() {
		var sheetMemory = new SheetMemory(this.structSize, this.maxIndex);
		sheetMemory.data = this.data ? new Uint8Array(this.data) : null;
		sheetMemory.count = this.count;
		return sheetMemory;
	};
	SheetMemory.prototype.deleteRange = function(start, deleteCount) {
		if (start < this.count) {
			var startOffset = start * this.structSize;
			if (start + deleteCount < this.count) {
				var endOffset = (start + deleteCount) * this.structSize;
				this.data.set(this.data.subarray(endOffset), startOffset);
				this.data.fill(0, (this.count - deleteCount) * this.structSize);
				this.count -= deleteCount;
			} else {
				this.data.fill(0, startOffset);
				this.count = start;
			}
		}
	};
	SheetMemory.prototype.insertRange = function(start, insertCount) {
		if (start < this.count) {
			this.checkSize(this.count - 1 + insertCount);
			var startOffset = start * this.structSize;
			if (start + insertCount < this.count) {
				var endOffset = (start + insertCount) * this.structSize;
				var endData = (this.count - insertCount) * this.structSize;
				this.data.set(this.data.subarray(startOffset, endData), endOffset);
				this.data.fill(0, startOffset, endOffset);
			} else {
				this.data.fill(0, startOffset);
			}
		}
	};
	SheetMemory.prototype.copyRange = function(sheetMemory, startFrom, startTo, count) {
		var countCopied = 0;
		if (startFrom < sheetMemory.count) {
			countCopied = Math.min(count, sheetMemory.count - startFrom);
			this.checkSize(startTo + countCopied);
			countCopied = Math.min(countCopied, this.count - startTo);
			if (countCopied > 0) {
				var startOffsetFrom = startFrom * this.structSize;
				var endOffsetFrom = (startFrom + countCopied) * this.structSize;
				var startOffsetTo = startTo * this.structSize;

				this.data.set(sheetMemory.data.subarray(startOffsetFrom, endOffsetFrom), startOffsetTo);
			}
		}
		var countErase = Math.min(count - countCopied, this.count - (startTo + countCopied));
		if (countErase > 0) {
			var startOffsetErase = (startTo + countCopied) * this.structSize;
			var endOffsetErase = (startTo + countCopied + countErase) * this.structSize;
			this.data.fill(0, startOffsetErase, endOffsetErase);
		}
	};
	SheetMemory.prototype.copyRangeByChunk = function(from, fromCount, to, toCount) {
		if (from < this.count) {
			this.checkSize(to + toCount);
			var fromStartOffset = from * this.structSize;
			var fromEndOffset = Math.min((from + fromCount), this.count) * this.structSize;
			var fromSubArray = this.data.subarray(fromStartOffset, fromEndOffset);
			for (var i = to; i < to + toCount && i < this.count; i += fromCount) {
				this.data.set(fromSubArray, i * this.structSize);
			}
		}
	};
	SheetMemory.prototype.clear = function(start, end) {
		end = Math.min(end, this.count);
		if (start < end) {
			this.data.fill(0, start * this.structSize, end * this.structSize);
		}
	};
	SheetMemory.prototype.getUint8 = function(index, offset) {
		offset += index * this.structSize;
		return this.data[offset];
	};
	SheetMemory.prototype.setUint8 = function(index, offset, val) {
		offset += index * this.structSize;
		this.data[offset] = val;
	};
	SheetMemory.prototype.getUint16 = function(index, offset) {
		offset += index * this.structSize;
		return AscFonts.FT_Common.IntToUInt(this.data[offset] | this.data[offset + 1] << 8);
	};
	SheetMemory.prototype.setUint16 = function(index, offset, val) {
		offset += index * this.structSize;
		this.data[offset] = (val) & 0xFF;
		this.data[offset + 1] = (val >>> 8) & 0xFF;
	};
	SheetMemory.prototype.getUint32 = function(index, offset) {
		offset += index * this.structSize;
		return AscFonts.FT_Common.IntToUInt(this.data[offset] | this.data[offset + 1] << 8 | this.data[offset + 2] << 16 | this.data[offset + 3] << 24);
	};
	SheetMemory.prototype.setUint32 = function(index, offset, val) {
		offset += index * this.structSize;
		this.data[offset] = (val) & 0xFF;
		this.data[offset + 1] = (val >>> 8) & 0xFF;
		this.data[offset + 2] = (val >>> 16) & 0xFF;
		this.data[offset + 3] = (val >>> 24) & 0xFF;
	};
	SheetMemory.prototype.getFloat64 = function(index, offset) {
		offset += index * this.structSize;
		tempHelpUnit[0] = this.data[offset];
		tempHelpUnit[1] = this.data[offset + 1];
		tempHelpUnit[2] = this.data[offset + 2];
		tempHelpUnit[3] = this.data[offset + 3];
		tempHelpUnit[4] = this.data[offset + 4];
		tempHelpUnit[5] = this.data[offset + 5];
		tempHelpUnit[6] = this.data[offset + 6];
		tempHelpUnit[7] = this.data[offset + 7];
		return tempHelpFloat[0];
	};
	SheetMemory.prototype.setFloat64 = function(index, offset, val) {
		offset += index * this.structSize;
		tempHelpFloat[0] = val;
		this.data[offset] = tempHelpUnit[0];
		this.data[offset + 1] = tempHelpUnit[1];
		this.data[offset + 2] = tempHelpUnit[2];
		this.data[offset + 3] = tempHelpUnit[3];
		this.data[offset + 4] = tempHelpUnit[4];
		this.data[offset + 5] = tempHelpUnit[5];
		this.data[offset + 6] = tempHelpUnit[6];
		this.data[offset + 7] = tempHelpUnit[7];
	};
	/**
	 * @constructor
	 */
	function Worksheet(wb, _index, sId){
		this.workbook = wb;
		this.sName = this.workbook.getUniqueSheetNameFrom(g_sNewSheetNamePattern, false);
		this.bHidden = false;
		this.oSheetFormatPr = new AscCommonExcel.SheetFormatPr();
		this.index = _index;
		this.Id = null != sId ? sId : AscCommon.g_oIdCounter.Get_NewId();
		this.nRowsCount = 0;
		this.nColsCount = 0;
		this.rowsData = new SheetMemory(AscCommonExcel.g_nRowStructSize, gc_nMaxRow0);
		this.cellsByCol = [];
		this.aCols = [];// 0 based
		this.hiddenManager = new HiddenManager(this);
		this.Drawings = [];
		this.TableParts = [];
		this.AutoFilter = null;
		this.oAllCol = null;
		this.aComments = [];
		var oThis = this;
		this.bExcludeHiddenRows = false;
		this.mergeManager = new RangeDataManager(function(data, from, to){
			if(History.Is_On() && (null != from || null != to))
			{
				if(null != from)
					from = from.clone();
				if(null != to)
					to = to.clone();
				var oHistoryRange = from;
				if(null == oHistoryRange)
					oHistoryRange = to;
				History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_ChangeMerge, oThis.getId(), oHistoryRange, new UndoRedoData_FromTo(new UndoRedoData_BBox(from), new UndoRedoData_BBox(to)));
			}
			//расширяем границы
			if(null != to){
				var maxRow = gc_nMaxRow0 !== to.r2 ? to.r2 : to.r1;
				var maxCol = gc_nMaxCol0 !== to.c2 ? to.c2 : to.c1;
				if(maxRow >= oThis.nRowsCount)
					oThis.nRowsCount = maxRow + 1;
				if(maxCol >= oThis.nColsCount)
					oThis.nColsCount = maxCol + 1;
			}
		});
		this.hyperlinkManager = new RangeDataManager(function(data, from, to, oChangeParam){
			if(History.Is_On() && (null != from || null != to))
			{
				if(null != from)
					from = from.clone();
				if(null != to)
					to = to.clone();
				var oHistoryRange = from;
				if(null == oHistoryRange)
					oHistoryRange = to;
				var oHistoryData = null;
				if(null == from || null == to)
					oHistoryData = data.clone();
				History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_ChangeHyperlink, oThis.getId(), oHistoryRange, new AscCommonExcel.UndoRedoData_FromToHyperlink(from, to, oHistoryData));
			}
			if (null != to)
				data.Ref = oThis.getRange3(to.r1, to.c1, to.r2, to.c2);
			else if (oChangeParam && oChangeParam.removeStyle && null != data.Ref)
				data.Ref.cleanFormat();
			//расширяем границы
			if(null != to){
				var maxRow = gc_nMaxRow0 !== to.r2 ? to.r2 : to.r1;
				var maxCol = gc_nMaxCol0 !== to.c2 ? to.c2 : to.c1;
				if(maxRow >= oThis.nRowsCount)
					oThis.nRowsCount = maxRow + 1;
				if(maxCol >= oThis.nColsCount)
					oThis.nColsCount = maxCol + 1;
			}
		});
		this.hyperlinkManager.setDependenceManager(this.mergeManager);
		this.DrawingDocument = new AscCommon.CDrawingDocument();
		this.sheetViews = [];
		this.aConditionalFormattingRules = [];
		this.updateConditionalFormattingRange = null;
		this.sheetPr = null;
		this.aFormulaExt = null;

		this.autoFilters = AscCommonExcel.AutoFilters !== undefined ? new AscCommonExcel.AutoFilters(this) : null;

		this.oDrawingOjectsManager = new DrawingObjectsManager(this);
		this.contentChanges = new AscCommon.CContentChanges();

		this.aSparklineGroups = [];

		this.selectionRange = new AscCommonExcel.SelectionRange(this);
		this.sheetMergedStyles = new AscCommonExcel.SheetMergedStyles();
		this.pivotTables = [];
		this.headerFooter = null;
		this.rowBreaks = null;
		this.colBreaks = null;
		this.legacyDrawingHF = null;
		this.picture = null;

		this.PagePrintOptions = new Asc.asc_CPageOptions(this);

		this.lastFindOptions = null;

		/*handlers*/
		this.handlers = null;
	}

	Worksheet.prototype.getCompiledStyle = function (row, col, opt_cell, opt_styleComponents) {
		return getCompiledStyle(this.sheetMergedStyles, this.hiddenManager, row, col, opt_cell, this, opt_styleComponents);
	};
	Worksheet.prototype.getColData = function(index) {
		var sheetMemory = this.cellsByCol[index];
		if(!sheetMemory){
			sheetMemory = new SheetMemory(g_nCellStructSize, gc_nMaxRow0);
			this.cellsByCol[index] = sheetMemory;
		}
		return sheetMemory;
	};
	Worksheet.prototype.getColDataNoEmpty = function(index) {
		return this.cellsByCol[index];
	};
	Worksheet.prototype.getColDataLength = function() {
		return this.cellsByCol.length;
	};
	Worksheet.prototype.getSnapshot = function(wb) {
		var ws = new Worksheet(wb, this.index, this.Id);
		ws.sName = this.sName;
		for (var i = 0; i < this.TableParts.length; ++i) {
			var table = this.TableParts[i];
			ws.addTablePart(table.clone(null), false);
		}
		for (i = 0; i < this.sheetViews.length; ++i) {
			ws.sheetViews.push(this.sheetViews[i].clone());
		}
		return ws;
	};
	Worksheet.prototype.addContentChanges = function (changes) {
		this.contentChanges.Add(changes);
	};
	Worksheet.prototype.refreshContentChanges = function () {
		this.contentChanges.Refresh();
		this.contentChanges.Clear();
	};
	Worksheet.prototype.rebuildColors=function(){
		this.rebuildTabColor();

		for (var i = 0; i < this.aSparklineGroups.length; ++i) {
			this.aSparklineGroups[i].cleanCache();
		}
	};
	Worksheet.prototype.generateFontMap=function(oFontMap){
		//пробегаемся по Drawing
		for(var i = 0, length = this.Drawings.length; i < length; ++i)
		{
			var drawing = this.Drawings[i];
			if(drawing)
				drawing.getAllFonts(oFontMap);
		}
	};
	Worksheet.prototype.getAllImageUrls = function(aImages){
		for(var i = 0; i < this.Drawings.length; ++i){
			this.Drawings[i].graphicObject.getAllRasterImages(aImages);
		}
	};
	Worksheet.prototype.reassignImageUrls = function(oImages){
		for(var i = 0; i < this.Drawings.length; ++i){
			this.Drawings[i].graphicObject.Reassign_ImageUrls(oImages);
		}
	};
	Worksheet.prototype.copyFrom=function(wsFrom, sName, tableNames){	var i, elem, range;
		var t = this;
		this.sName = this.workbook.checkValidSheetName(sName) ? sName : this.workbook.getUniqueSheetNameFrom(wsFrom.sName, true);
		this.bHidden = wsFrom.bHidden;
		this.oSheetFormatPr = wsFrom.oSheetFormatPr.clone();
		//this.index = wsFrom.index;
		this.nRowsCount = wsFrom.nRowsCount;
		this.nColsCount = wsFrom.nColsCount;
		var renameParams = {lastName: wsFrom.getName(), newName: this.getName(), tableNameMap: {}};
		for (i = 0; i < wsFrom.TableParts.length; ++i)
		{
			var tableFrom = wsFrom.TableParts[i];
			var tableTo = tableFrom.clone(null);
			if(tableNames && tableNames.length) {
				tableTo.changeDisplayName(tableNames[i]);
			} else {
				tableTo.changeDisplayName(this.workbook.dependencyFormulas.getNextTableName());
			}
			this.addTablePart(tableTo, true);
			renameParams.tableNameMap[tableFrom.DisplayName] = tableTo.DisplayName;
		}
		for (i = 0; i < this.TableParts.length; ++i) {
			this.TableParts[i].renameSheetCopy(this, renameParams);
		}
		if(wsFrom.AutoFilter)
			this.AutoFilter = wsFrom.AutoFilter.clone();
		for (i in wsFrom.aCols) {
			var col = wsFrom.aCols[i];
			if(null != col)
				this.aCols[i] = col.clone(this);
		}
		if(null != wsFrom.oAllCol)
			this.oAllCol = wsFrom.oAllCol.clone(this);

		//copy row/cell data
		this.rowsData = wsFrom.rowsData.clone();
		wsFrom._forEachColData(function(sheetMemory, index){
			t.cellsByCol[index] = sheetMemory.clone();
		});

		var aMerged = wsFrom.mergeManager.getAll();
		for(i in aMerged)
		{
			elem = aMerged[i];
			range = this.getRange3(elem.bbox.r1, elem.bbox.c1, elem.bbox.r2, elem.bbox.c2);
			range.mergeOpen();
		}
		var aHyperlinks = wsFrom.hyperlinkManager.getAll();
		for(i in aHyperlinks)
		{
			elem = aHyperlinks[i];
			range = this.getRange3(elem.bbox.r1, elem.bbox.c1, elem.bbox.r2, elem.bbox.c2);
			range.setHyperlinkOpen(elem.data);
		}
		if(null != wsFrom.aComments) {
			for (i = 0; i < wsFrom.aComments.length; i++) {
				var comment = wsFrom.aComments[i].clone()
				comment.wsId = this.getId();
				comment.nId = "sheet" + comment.wsId + "_" + (i + 1);
				this.aComments.push(comment);
			}
		}
		for (i = 0; i < wsFrom.sheetViews.length; ++i) {
			this.sheetViews.push(wsFrom.sheetViews[i].clone());
		}
		for (i = 0; i < wsFrom.aConditionalFormattingRules.length; ++i) {
			this.aConditionalFormattingRules.push(wsFrom.aConditionalFormattingRules[i].clone());
		}
		if (wsFrom.sheetPr)
			this.sheetPr = wsFrom.sheetPr.clone();

		this.selectionRange = wsFrom.selectionRange.clone(this);

		//change cell formulas
		this._forEachCell(function(cell) {
			if (cell.isFormula()) {
				var parsed;
				if (cell.transformSharedFormula()) {
					parsed = cell.getFormulaParsed();
				} else {
					parsed = cell.getFormulaParsed();
					parsed = parsed.clone(null, new CCellWithFormula(t, cell.nRow, cell.nCol), t);
				}
				parsed.renameSheetCopy(renameParams);
				parsed.setFormulaString(parsed.assemble(true));
				cell.setFormulaInternal(parsed, true);
				t.workbook.dependencyFormulas.addToBuildDependencyCell(cell);
			}
		});

		return renameParams;
	};
	Worksheet.prototype.copyObjects = function (oNewWs, wsFrom) {
		var i;
		if (null != this.Drawings && this.Drawings.length > 0) {
			var drawingObjects = new AscFormat.DrawingObjects();
			oNewWs.Drawings = [];
			AscFormat.NEW_WORKSHEET_DRAWING_DOCUMENT = oNewWs.DrawingDocument;
			for (i = 0; i < this.Drawings.length; ++i) {
				var drawingObject = drawingObjects.cloneDrawingObject(this.Drawings[i]);
				drawingObject.graphicObject = this.Drawings[i].graphicObject.copy();
				drawingObject.graphicObject.setWorksheet(oNewWs);
				drawingObject.graphicObject.addToDrawingObjects();
				var drawingBase = this.Drawings[i];
				drawingObject.graphicObject.setDrawingBaseCoords(drawingBase.from.col, drawingBase.from.colOff,
																 drawingBase.from.row, drawingBase.from.rowOff, drawingBase.to.col, drawingBase.to.colOff,
																 drawingBase.to.row, drawingBase.to.rowOff, drawingBase.Pos.X, drawingBase.Pos.Y, drawingBase.ext.cx,
																 drawingBase.ext.cy);
				if(drawingObject.graphicObject.setDrawingBaseType){
					drawingObject.graphicObject.setDrawingBaseType(drawingBase.Type);
				}
				oNewWs.Drawings[oNewWs.Drawings.length - 1] = drawingObject;
			}
			AscFormat.NEW_WORKSHEET_DRAWING_DOCUMENT = null;
			drawingObjects.pushToAObjects(oNewWs.Drawings);
			drawingObjects.updateChartReferences2(parserHelp.getEscapeSheetName(wsFrom.sName),
												  parserHelp.getEscapeSheetName(oNewWs.sName));
		}

		var newSparkline;
		for (i = 0; i < this.aSparklineGroups.length; ++i) {
			newSparkline = this.aSparklineGroups[i].clone();
			newSparkline.setWorksheet(oNewWs, wsFrom);
			oNewWs.aSparklineGroups.push(newSparkline);
		}
	};
	Worksheet.prototype.initColumn = function (column) {
		if (column) {
			if (null !== column.width) {
				column.widthPx = this.modelColWidthToColWidth(column.width);
				column.charCount = this.colWidthToCharCount(column.widthPx);
			} else {
				column.widthPx = column.charCount = null;
			}
		}
	};
	Worksheet.prototype.initColumns = function () {
		this.initColumn(this.oAllCol);
		this.aCols.forEach(this.initColumn, this);
	};
	Worksheet.prototype.initPostOpen = function (handlers) {
		this.PagePrintOptions.init();

		// Sheet Views
		if (0 === this.sheetViews.length) {
			// Даже если не было, создадим
			this.sheetViews.push(new AscCommonExcel.asc_CSheetViewSettings());
		}
		//this.setTableFormulaAfterOpen();
		this.hiddenManager.initPostOpen();
		this.oSheetFormatPr.correction();

		this.handlers = handlers;
		this._setHandlersTablePart();
	};
	Worksheet.prototype._getValuesForConditionalFormatting = function(ranges, numbers) {
		var res = [];
		for (var i = 0; i < ranges.length; ++i) {
			var elem = ranges[i];
			var range = this.getRange3(elem.r1, elem.c1, elem.r2, elem.c2);
			res = res.concat(range._getValues(numbers));
		}
		return res;
	};
	Worksheet.prototype._isConditionalFormattingIntersect = function(range, ranges) {
		for (var i = 0; i < ranges.length; ++i) {
			if (range.isIntersect(ranges[i])) {
				return true;
			}
		}
		return false;
	};
	Worksheet.prototype.setDirtyConditionalFormatting = function(range) {
		if (!range) {
			range = new AscCommonExcel.MultiplyRange([new Asc.Range(0, 0, gc_nMaxCol0, gc_nMaxRow0)]);
		}
		if (this.updateConditionalFormattingRange) {
			this.updateConditionalFormattingRange.union2(range);
		} else {
			this.updateConditionalFormattingRange = range.clone();
		}
	};
	Worksheet.prototype._updateConditionalFormatting = function() {
		if (!this.updateConditionalFormattingRange) {
			return;
		}
		var range = this.updateConditionalFormattingRange;
		this.updateConditionalFormattingRange = null;
		var t = this;
		var aRules = this.aConditionalFormattingRules.sort(function(v1, v2) {
			return v2.priority - v1.priority;
		});
		var oGradient1, oGradient2, oRule, multiplyRange, oRuleElement = null;
		var o, l, cell, ranges, values, value, tmp, min, mid, max, dxf, compareFunction, nc, sum;
		this.sheetMergedStyles.clearConditionalStyle(range);
		var getCacheFunction = function(rule, setFunc) {
			var cache = {
				cache: {},
				get: function(row, col) {
					var cacheVal;
					var cacheRow = this.cache[row];
					if (!cacheRow) {
						cacheRow = {};
						this.cache[row] = cacheRow;
					} else {
						cacheVal = cacheRow[col];
					}
					if(undefined ===cacheVal){
						cacheVal = this.set(row, col);
						cacheRow[col] = cacheVal;
					}
					return cacheVal;
				},
				set: function(row, col) {
					if(rule){
						return setFunc(row, col) ? rule.dxf : null;
					} else {
						return setFunc(row, col);
					}
				}
			};
			return function(row, col) {
				return cache.get(row, col);
			};
		};
		for (var i = 0; i < aRules.length; ++i) {
			oRule = aRules[i];
			ranges = oRule.ranges;
			if (this._isConditionalFormattingIntersect(range, ranges)) {
				multiplyRange = new AscCommonExcel.MultiplyRange(ranges);
					// ToDo dataBar, expression, iconSet (page 2679)
					if (AscCommonExcel.ECfType.colorScale === oRule.type) {
						if (1 !== oRule.aRuleElements.length) {
							break;
						}
						oRuleElement = oRule.aRuleElements[0];
						if (!(oRuleElement instanceof AscCommonExcel.CColorScale)) {
							break;
						}
						values = this._getValuesForConditionalFormatting(ranges, true);
						// ToDo CFVO Type formula (page 2681)
						l = oRuleElement.aColors.length;
						if (0 < values.length && 2 <= l) {
							oGradient1 = new AscCommonExcel.CGradient(oRuleElement.aColors[0], oRuleElement.aColors[1]);
							min = oRuleElement.getMin(values);
							max = oRuleElement.getMax(values);
							oGradient2 = null;
							if (2 < l) {
								oGradient2 = new AscCommonExcel.CGradient(oRuleElement.aColors[1], oRuleElement.aColors[2]);
								mid = oRuleElement.getMid(values);

								oGradient1.init(min, mid);
								oGradient2.init(mid, max);
							} else {
								oGradient1.init(min, max);
							}

							compareFunction = (function(oGradient1, oGradient2) {
								return function(row, col) {
									var val;
									t._getCellNoEmpty(row, col, function(cell) {
										val = cell && cell.getNumberValue();
									});
									dxf = null;
									if (null !== val) {
										dxf = new AscCommonExcel.CellXfs();
										tmp = (oGradient2 && val > oGradient1.max) ? oGradient2 : oGradient1;
										dxf.fill = new AscCommonExcel.Fill({bg: tmp.calculateColor(val)});
										dxf = g_StyleCache.addXf(dxf, true);
									}
									return dxf;
								};
							})(oGradient1, oGradient2);
						}
					} else if (AscCommonExcel.ECfType.top10 === oRule.type) {
						if (oRule.rank > 0 && oRule.dxf) {
							nc = 0;
							values = this._getValuesForConditionalFormatting(ranges, false);
							o = oRule.bottom ? Number.MAX_VALUE : -Number.MAX_VALUE;
							for (cell = 0; cell < values.length; ++cell) {
								value = values[cell];
								if (CellValueType.Number === value.type && !isNaN(tmp = parseFloat(value.v))) {
									++nc;
									value.v = tmp;
								} else {
									value.v = o;
								}
							}
							values.sort((function(condition) {
								return function(v1, v2) {
									return condition * (v2.v - v1.v);
								}
							})(oRule.bottom ? -1 : 1));

							nc = Math.max(1, oRule.percent ? Math.floor(nc * oRule.rank / 100) : oRule.rank);
							var threshold = values.length >= nc ? values[nc - 1].v : o;
							compareFunction = (function(rule, threshold) {
								return function(row, col) {
									var val;
									t._getCellNoEmpty(row, col, function(cell) {
										val = cell ? cell.getNumberValue() : null;
									});
									return (null !== val && (rule.bottom ? val <= threshold : val >= threshold)) ? rule.dxf : null;
								};
							})(oRule, threshold);
						}
					} else if (AscCommonExcel.ECfType.aboveAverage === oRule.type) {
						if (!oRule.dxf) {
							continue;
						}
						values = this._getValuesForConditionalFormatting(ranges, false);
						sum = 0;
						nc = 0;
						for (cell = 0; cell < values.length; ++cell) {
							value = values[cell];
							if (CellValueType.Number === value.type && !isNaN(tmp = parseFloat(value.v))) {
								++nc;
								value.v = tmp;
								sum += tmp;
							} else {
								value.v = null;
							}
						}

						tmp = sum / nc;
						/*if (oRule.hasStdDev()) {
						 sum = 0;
						 for (cell = 0; cell < values.length; ++cell) {
						 value = values[cell];
						 if (null !== value.v) {
						 sum += (value.v - tmp) * (value.v - tmp);
						 }
						 }
						 sum = Math.sqrt(sum / (nc - 1));
						 }*/
						compareFunction = (function(rule, average, stdDev) {
							return function(row, col) {
								var val;
								t._getCellNoEmpty(row, col, function(cell) {
									val = cell ? cell.getNumberValue() : null;
								});
								return (null !== val && rule.getAverage(val, average, stdDev)) ? rule.dxf : null;
							};
						})(oRule, tmp, sum);
					} else {
						if (!oRule.dxf) {
							continue;
						}
						switch (oRule.type) {
							case AscCommonExcel.ECfType.duplicateValues:
							case AscCommonExcel.ECfType.uniqueValues:
								o = getUniqueKeys(this._getValuesForConditionalFormatting(ranges, false));
								compareFunction = (function(rule, obj, condition) {
									return function(row, col) {
										var val;
										t._getCellNoEmpty(row, col, function(cell) {
											val = cell ? cell.getValueWithoutFormat() : "";
										});
										return (val.length > 0 ? condition === obj[val] : false) ? rule.dxf : null;
									};
								})(oRule, o, oRule.type === AscCommonExcel.ECfType.duplicateValues);
								break;
							case AscCommonExcel.ECfType.containsText:
								compareFunction = (function(rule, text) {
									return function(row, col) {
										var val;
										t._getCellNoEmpty(row, col, function(cell) {
											val = cell ? cell.getValueWithoutFormat().toLowerCase() : "";
										});
										return (-1 !== val.indexOf(text)) ? rule.dxf : null;
									};
							})(oRule, oRule.text && oRule.text.toLowerCase());
								break;
							case AscCommonExcel.ECfType.notContainsText:
								compareFunction = (function(rule, text) {
									return function(row, col) {
										var val;
										t._getCellNoEmpty(row, col, function(cell) {
											val = cell ? cell.getValueWithoutFormat().toLowerCase() : "";
										});
										return (-1 === val.indexOf(text)) ? rule.dxf : null;
									};
							})(oRule, oRule.text && oRule.text.toLowerCase());
								break;
							case AscCommonExcel.ECfType.beginsWith:
								compareFunction = (function(rule, text) {
									return function(row, col) {
										var val;
										t._getCellNoEmpty(row, col, function(cell) {
											val = cell ? cell.getValueWithoutFormat().toLowerCase() : "";
										});
										return val.startsWith(text) ? rule.dxf : null;
									};
								})(oRule, oRule.text && oRule.text.toLowerCase());
								break;
							case AscCommonExcel.ECfType.endsWith:
								compareFunction = (function(rule, text) {
									return function(row, col) {
										var val;
										t._getCellNoEmpty(row, col, function(cell) {
											val = cell ? cell.getValueWithoutFormat().toLowerCase() : "";
										});
										return val.endsWith(text) ? rule.dxf : null;
									};
								})(oRule, oRule.text && oRule.text.toLowerCase());
								break;
							case AscCommonExcel.ECfType.containsErrors:
								compareFunction = (function(rule) {
									return function(row, col) {
										var val;
										t._getCellNoEmpty(row, col, function(cell) {
											val = (cell ? CellValueType.Error === cell.getType() : false);
										});
										return val ? rule.dxf : null;
									};
								})(oRule);
								break;
							case AscCommonExcel.ECfType.notContainsErrors:
								compareFunction = (function(rule) {
									return function(row, col) {
										var val;
										t._getCellNoEmpty(row, col, function(cell) {
											val = (cell ? CellValueType.Error !== cell.getType() : true);
										});
										return val ? rule.dxf : null;
									};
								})(oRule);
								break;
							case AscCommonExcel.ECfType.containsBlanks:
								compareFunction = (function(rule) {
									return function(row, col) {
										var val;
										t._getCellNoEmpty(row, col, function(cell) {
											if (cell) {
												//todo LEN(TRIM(A1))=0
												val = "" === cell.getValueWithoutFormat().replace(/^ +| +$/g, '');
											} else {
												val = true;
											}
										});
										return val ? rule.dxf : null;
									};
								})(oRule);
								break;
							case AscCommonExcel.ECfType.notContainsBlanks:
								compareFunction = (function(rule) {
									return function(row, col) {
										var val;
										t._getCellNoEmpty(row, col, function(cell) {
											if (cell) {
												//todo LEN(TRIM(A1))=0
												val = "" !== cell.getValueWithoutFormat().replace(/^ +| +$/g, '');
											} else {
												val = false;
											}
										});
										return val ? rule.dxf : null;
									};
								})(oRule);
								break;
							case AscCommonExcel.ECfType.timePeriod:
								if (oRule.timePeriod) {
									compareFunction = (function(rule, period) {
										return function(row, col) {
											var val;
											t._getCellNoEmpty(row, col, function(cell) {
												val = cell ? cell.getValueWithoutFormat() : "";
											});
											var n = parseFloat(val);
											return (period.start <= n && n < period.end) ? rule.dxf : null;
										};
									})(oRule, oRule.getTimePeriod());
								} else {
									continue;
								}
								break;
							case AscCommonExcel.ECfType.cellIs:
								var val1 = oRule.aRuleElements[0] && oRule.aRuleElements[0].getValue(this);
								var val2 = oRule.aRuleElements[1] && oRule.aRuleElements[1].getValue(this);
								if (val1 && val1.toLowerCase) {
									val1 = val1.toLowerCase();
								}
								if (val2 && val2.toLowerCase) {
									val2 = val2.toLowerCase();
								}
								compareFunction = (function(rule, v1, v2) {
									return function(row, col) {
										var val;
										t._getCellNoEmpty(row, col, function(cell) {
											val = cell ? cell.getValueWithoutFormat().toLowerCase() : "";
										});
										return rule.cellIs(val, v1, v2) ? rule.dxf : null;
									};
								})(oRule, val1, val2);
								break;
							case AscCommonExcel.ECfType.expression:
								var offset = new AscCommon.CellBase(0, 0);
							var bboxCf = oRule.getBBox();
								var rowLT = bboxCf ? bboxCf.r1 : 0;
								var colLT = bboxCf ? bboxCf.c1 : 0;
							var formulaParent =  new AscCommonExcel.CConditionalFormattingFormulaWrapper(this, oRule);
								compareFunction = getCacheFunction(oRule, (function(rule, formulaCF, rowLT, colLT) {
									return function(row, col) {
										offset.row = row - rowLT;
										offset.col = col - colLT;
										var bboxCell = new Asc.Range(col, row, col, row);
										var res = formulaCF && formulaCF.getValueRaw(t, formulaParent, bboxCell, offset);
										if (res && res.tocBool) {
											res = res.tocBool();
											if (res && res.toBool) {
												return res.toBool();
											}
										}
										return false;
									};
								})(oRule, oRule.aRuleElements[0], rowLT, colLT));
								break;
							default:
								continue;
								break;
						}
					}
					if (compareFunction) {
						this.sheetMergedStyles.setConditionalStyle(multiplyRange, compareFunction);
					}
				}
			}
	};
	Worksheet.prototype._forEachRow = function(fAction) {
		this.getRange3(0, 0, gc_nMaxRow0, 0)._foreachRowNoEmpty(fAction);
	};
	Worksheet.prototype._forEachCol = function(fAction) {
		this.getRange3(0, 0, 0, gc_nMaxCol0)._foreachColNoEmpty(fAction);
	};
	Worksheet.prototype._forEachColData = function(fAction) {
		for (var i = 0; i < this.cellsByCol.length; ++i) {
			var sheetMemory = this.cellsByCol[i];
			if (sheetMemory) {
				fAction(sheetMemory, i);
			}
		}
	};
	Worksheet.prototype._forEachCell = function(fAction) {
		this.getRange3(0, 0, gc_nMaxRow0, gc_nMaxCol0)._foreachNoEmpty(fAction);
	};
	Worksheet.prototype.getId=function(){
		return this.Id;
	};
	Worksheet.prototype.getIndex=function(){
		return this.index;
	};
	Worksheet.prototype.getName=function(){
		return this.sName !== undefined && this.sName.length > 0 ? this.sName : "";
	};
	Worksheet.prototype.setName=function(name, bFromUndoRedo){
		if(name.length <= g_nSheetNameMaxLength)
		{
			var lastName = this.sName;
			History.Create_NewPoint();
			var prepared = this.workbook.dependencyFormulas.prepareChangeSheet(this.getId(), {rename: {from: lastName, to: name}});
			this.sName = name;
			this.workbook.dependencyFormulas.changeSheet(prepared);

			History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_Rename, this.getId(), null, new UndoRedoData_FromTo(lastName, name));
			if(!bFromUndoRedo)
			{
				var _lastName = parserHelp.getEscapeSheetName(lastName);
				var _newName = parserHelp.getEscapeSheetName(this.sName);

				for (var key in this.workbook.aWorksheets)
				{
					var wsModel = this.workbook.aWorksheets[key];
					if ( wsModel )
						wsModel.oDrawingOjectsManager.updateChartReferencesWidthHistory(_lastName, _newName, true);
				}
			}
			this.workbook.dependencyFormulas.calcTree();
		} else {
			console.log(new Error('The sheet name must be less than 31 characters.'));
		}
	};
	Worksheet.prototype.getTabColor=function(){
		return this.sheetPr && this.sheetPr.TabColor ? Asc.colorObjToAscColor(this.sheetPr.TabColor) : null;
	};
	Worksheet.prototype.setTabColor=function(color){
		if (!this.sheetPr)
			this.sheetPr = new AscCommonExcel.asc_CSheetPr();

		History.Create_NewPoint();
		History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_SetTabColor, this.getId(), null,
					new UndoRedoData_FromTo(this.sheetPr.TabColor ? this.sheetPr.TabColor.clone() : null, color ? color.clone() : null));

		this.sheetPr.TabColor = color;
		if (!this.workbook.bUndoChanges && !this.workbook.bRedoChanges)
			this.workbook.handlers.trigger("asc_onUpdateTabColor", this.getIndex());
	};
	Worksheet.prototype.rebuildTabColor = function() {
		if (this.sheetPr && this.sheetPr.TabColor) {
			this.workbook.handlers.trigger("asc_onUpdateTabColor", this.getIndex());
		}
	};
	Worksheet.prototype.getHidden=function(){
		return true === this.bHidden;
	};
	Worksheet.prototype.setHidden = function (hidden) {
		var bOldHidden = this.bHidden, wb = this.workbook, wsActive = wb.getActiveWs(), oVisibleWs = null;
		this.bHidden = hidden;
		if (true == this.bHidden && this.getIndex() == wsActive.getIndex())
		{
			oVisibleWs = wb.findSheetNoHidden(this.getIndex());
			if (null != oVisibleWs) {
				var nNewIndex = oVisibleWs.getIndex();
				wb.setActive(nNewIndex);
				if (!wb.bUndoChanges && !wb.bRedoChanges)
					wb.handlers.trigger("undoRedoHideSheet", nNewIndex);
			}
		}
		if (bOldHidden != hidden) {
			History.Create_NewPoint();
			History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_Hide, this.getId(), null, new UndoRedoData_FromTo(bOldHidden, hidden));
			if (null != oVisibleWs) {
				History.SetSheetUndo(wsActive.getId());
				History.SetSheetRedo(oVisibleWs.getId());
			}
		}
	};
	Worksheet.prototype.getSheetView = function () {
		return this.sheetViews[0];
	};
	Worksheet.prototype.getSheetViewSettings = function () {
		return this.sheetViews[0].clone();
	};
	Worksheet.prototype.setDisplayGridlines = function (value) {
		var view = this.sheetViews[0];
		if (value !== view.showGridLines) {
			History.Create_NewPoint();
			History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_SetDisplayGridlines,
				this.getId(), null, new UndoRedoData_FromTo(view.showGridLines, value));
			view.showGridLines = value;

			if (!this.workbook.bUndoChanges && !this.workbook.bRedoChanges) {
				this.workbook.handlers.trigger("asc_onUpdateSheetViewSettings");
			}
		}
	};
	Worksheet.prototype.setDisplayHeadings = function (value) {
		var view = this.sheetViews[0];
		if (value !== view.showRowColHeaders) {
			History.Create_NewPoint();
			History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_SetDisplayHeadings,
				this.getId(), null, new UndoRedoData_FromTo(view.showRowColHeaders, value));
			view.showRowColHeaders = value;

			if (!this.workbook.bUndoChanges && !this.workbook.bRedoChanges) {
				this.workbook.handlers.trigger("asc_onUpdateSheetViewSettings");
			}
		}
	};
	Worksheet.prototype.getRowsCount=function(){
		var result = this.nRowsCount;
		var pane = this.sheetViews.length && this.sheetViews[0].pane;
		if (pane && pane.topLeftFrozenCell)
			result = Math.max(result, pane.topLeftFrozenCell.getRow0());
		return result;
	};
	Worksheet.prototype.removeRows=function(start, stop, bExcludeHiddenRows){
		var removeRowsArr = bExcludeHiddenRows ? this._getNoHiddenRowsArr(start, stop) : [{start: start, stop: stop}];
		for(var i = removeRowsArr.length - 1; i >= 0; i--) {
			var oRange = this.getRange(new CellAddress(removeRowsArr[i].start, 0, 0), new CellAddress(removeRowsArr[i].stop, gc_nMaxCol0, 0));
			oRange.deleteCellsShiftUp();
		}
	};
	Worksheet.prototype._getNoHiddenRowsArr=function(start, stop){
		var res = [];
		var elem = null;
		for (var i = start; i <= stop; i++) {
			if (this.getRowHidden(i)) {
				if (elem) {
					res.push(elem);
					elem = null;
				}
			} else {
				if (!elem) {
					elem = {};
					elem.start = i;
					elem.stop = i;
				} else {
					elem.stop++;
				}
				if (i === stop) {
					res.push(elem);
				}
			}
		}
		return res;
	};
	Worksheet.prototype._updateFormulasParents = function(r1, c1, r2, c2, bbox, offset, shiftedShared) {
		var t = this;
		var cellWithFormula;
		this.getRange3(r1, c1, r2, c2)._foreachNoEmpty(function(cell){
			var newNRow = cell.nRow + offset.row;
			var newNCol = cell.nCol + offset.col;
			var bHor = 0 !== offset.col;
			var toDelete = offset.col < 0 || offset.row < 0;

			if (cell.isFormula()) {
				var processed = c_oSharedShiftType.NeedTransform;
				var parsed = cell.getFormulaParsed();
				var shared = parsed.getShared();
				if (shared) {
					processed = shiftedShared[parsed.getListenerId()];
					var isPreProcessed = c_oSharedShiftType.PreProcessed === processed;
					if (!processed || isPreProcessed) {
						if (!processed) {
							var bboxShift = AscCommonExcel.shiftGetBBox(bbox, bHor);
							//if shared not completly in shift range - transform
							//if shared intersect delete range - transform
							if (bboxShift.containsRange(shared.ref) && (!toDelete || !bbox.isIntersect(shared.ref))) {
								processed = c_oSharedShiftType.Processed;
							} else {
								processed = c_oSharedShiftType.NeedTransform;
							}
						} else if(isPreProcessed) {
							//At PreProcessed stage all required formula was transformed. here we need to shift shared
							processed = c_oSharedShiftType.Processed;
						}
						if (c_oSharedShiftType.Processed === processed) {
							var newRef = shared.ref.clone();
							newRef.forShift(bbox, offset, t.workbook.bUndoChanges);
							parsed.setSharedRef(newRef, !isPreProcessed);
							t.workbook.dependencyFormulas.addToChangedRange2(t.getId(), newRef);
						}
						shiftedShared[parsed.getListenerId()] = processed;
					}
				}
				if (c_oSharedShiftType.NeedTransform === processed) {
					var isTransform = cell.transformSharedFormula();
					parsed = cell.getFormulaParsed();
					if (isTransform) {
						parsed.buildDependencies();
					}

					cellWithFormula = parsed.getParent();
				cellWithFormula.nRow = newNRow;
				cellWithFormula.nCol = newNCol;
				t.workbook.dependencyFormulas.addToChangedCell(cellWithFormula);
			}
			}
			if (newNRow >= t.nRowsCount) {
				t.nRowsCount = newNRow + 1;
			}
			if (newNCol >= t.nColsCount) {
				t.nColsCount = newNCol + 1;
			}
		});
	};
	Worksheet.prototype._removeRows=function(start, stop){
		var t = this;
		this.workbook.dependencyFormulas.lockRecal();
		History.Create_NewPoint();
		//start, stop 0 based
		var nDif = -(stop - start + 1);
		var oActualRange = new Asc.Range(0, start, gc_nMaxCol0, stop);
		var offset = new AscCommon.CellBase(nDif, 0);
		//renameDependencyNodes before move cells to store current location in history
		var renameRes = this.renameDependencyNodes(offset, oActualRange);
		var redrawTablesArr = this.autoFilters.insertRows("delCell", oActualRange, c_oAscDeleteOptions.DeleteRows);
		this.updatePivotOffset(oActualRange, offset);

		var oDefRowPr = new AscCommonExcel.UndoRedoData_RowProp();
		this.getRange3(start,0,stop,gc_nMaxCol0)._foreachRowNoEmpty(function(row){
			var oOldProps = row.getHeightProp();
			if (false === oOldProps.isEqual(oDefRowPr))
				History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_RowProp, t.getId(), row._getUpdateRange(), new UndoRedoData_IndexSimpleProp(row.getIndex(), true, oOldProps, oDefRowPr));
			row.setStyle(null);

		}, function(cell){
			t._removeCell(null, null, cell);
		});

		this._updateFormulasParents(start, 0, gc_nMaxRow0, gc_nMaxCol0, oActualRange, offset, renameRes.shiftedShared);
		this.rowsData.deleteRange(start, (-nDif));
		this._forEachColData(function(sheetMemory) {
			sheetMemory.deleteRange(start, (-nDif));
		});
		//notifyChanged after move cells to get new locations(for intersect ranges)
		this.workbook.dependencyFormulas.notifyChanged(renameRes.changed);
		History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_RemoveRows, this.getId(), new Asc.Range(0, start, gc_nMaxCol0, gc_nMaxRow0), new UndoRedoData_FromToRowCol(true, start, stop));

		this.autoFilters.redrawStylesTables(redrawTablesArr);

		this.workbook.dependencyFormulas.unlockRecal();

		return true;
	};
	Worksheet.prototype.insertRowsBefore=function(index, count){
		var oRange = this.getRange(new CellAddress(index, 0, 0), new CellAddress(index + count - 1, gc_nMaxCol0, 0));
		oRange.addCellsShiftBottom();
	};
	Worksheet.prototype._getBordersForInsert = function(r1, c1, r2, c2, bRow) {
		var t = this;
		var borders = {};
		var offsetRow = (bRow && r1 > 0) ? -1 : 0;
		var offsetCol = (!bRow && c1 > 0) ? -1 : 0;
		if(0 !== offsetRow || 0 !== offsetCol){
			this.getRange3(r1, c1, r2, c2)._foreachNoEmpty(function(cell) {
				if (cell.xfs && cell.xfs.border) {
					t._getCellNoEmpty(cell.nRow + offsetRow, cell.nCol + offsetCol, function(neighbor) {
						if (neighbor && neighbor.xfs && neighbor.xfs.border) {
							var newBorder = neighbor.xfs.border.clone();
							newBorder.intersect(cell.xfs.border, g_oDefaultFormat.BorderAbs, true);
							borders[bRow ? cell.nCol : cell.nRow] = newBorder;
						}
					});
				}
			});
		}
		return borders;
	};
	Worksheet.prototype._insertRowsBefore=function(index, count){
		this.workbook.dependencyFormulas.lockRecal();
		var oActualRange = new Asc.Range(0, index, gc_nMaxCol0, index + count - 1);
		History.Create_NewPoint();
		var offset = new AscCommon.CellBase(count, 0);
		//renameDependencyNodes before move cells to store current location in history
		var renameRes = this.renameDependencyNodes(offset, oActualRange);
		var redrawTablesArr = this.autoFilters.insertRows("insCell", oActualRange, c_oAscInsertOptions.InsertColumns);
		this.updatePivotOffset(oActualRange, offset);

		this._updateFormulasParents(index, 0, gc_nMaxRow0, gc_nMaxCol0, oActualRange, offset, renameRes.shiftedShared);
		var borders = this._getBordersForInsert(index, 0, index, gc_nMaxCol0, true);
		//insert new row/cell
		this.rowsData.insertRange(index, count);
		this._forEachColData(function(sheetMemory) {
			sheetMemory.insertRange(index, count);
		});
		if (index > 0 && false == this.workbook.bUndoChanges && (false == this.workbook.bRedoChanges || this.workbook.bCollaborativeChanges))
		{
			//copy property from row/cell above
			this.rowsData.copyRangeByChunk((index - 1), 1, index, count);
			this._forEachColData(function(sheetMemory) {
				sheetMemory.copyRangeByChunk((index - 1), 1, index, count);
			});
			//show rows and remain only cell xf property
			this.getRange3(index, 0, index + count - 1, gc_nMaxCol0)._foreachRowNoEmpty(function(row) {
				row.setHidden(false);
			},function(cell) {
				cell.clearDataKeepXf(borders[cell.nCol]);
			});
		}
		//notifyChanged after move cells to get new locations(for intersect ranges)
		this.workbook.dependencyFormulas.notifyChanged(renameRes.changed);
		History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_AddRows, this.getId(), new Asc.Range(0, index, gc_nMaxCol0, gc_nMaxRow0), new UndoRedoData_FromToRowCol(true, index, index + count - 1));

		this.autoFilters.redrawStylesTables(redrawTablesArr);

		this.workbook.dependencyFormulas.unlockRecal();

		this.nRowsCount += count;

		return true;
	};
	Worksheet.prototype.insertRowsAfter=function(index, count){
		//index 0 based
		return this.insertRowsBefore(index + 1, count);
	};
	Worksheet.prototype.getColsCount=function(){
		var result = this.nColsCount;
		var pane = this.sheetViews.length && this.sheetViews[0].pane;
		if (pane && pane.topLeftFrozenCell)
			result = Math.max(result, pane.topLeftFrozenCell.getCol0());
		return result;
	};
	Worksheet.prototype.removeCols=function(start, stop){
		var oRange = this.getRange(new CellAddress(0, start, 0), new CellAddress(gc_nMaxRow0, stop, 0));
		oRange.deleteCellsShiftLeft();
	};
	Worksheet.prototype._removeCols=function(start, stop){
		var t = this;
		this.workbook.dependencyFormulas.lockRecal();
		History.Create_NewPoint();
		//start, stop 0 based
		var nDif = -(stop - start + 1), i, j, length;
		var oActualRange = new Asc.Range(start, 0, stop, gc_nMaxRow0);
		var offset = new AscCommon.CellBase(0, nDif);
		//renameDependencyNodes before move cells to store current location in history
		var renameRes = this.renameDependencyNodes(offset, oActualRange);
		var redrawTablesArr = this.autoFilters.insertColumn(oActualRange, nDif);
		this.updatePivotOffset(oActualRange, offset);

		var oDefColPr = new AscCommonExcel.UndoRedoData_ColProp();
		this.getRange3(0, start, gc_nMaxRow0,stop)._foreachColNoEmpty(function(col){
			var nIndex = col.getIndex();
			var oOldProps = col.getWidthProp();
			if(false === oOldProps.isEqual(oDefColPr))
				History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_ColProp, t.getId(), new Asc.Range(nIndex, 0, nIndex, gc_nMaxRow0), new UndoRedoData_IndexSimpleProp(nIndex, false, oOldProps, oDefColPr));
			col.setStyle(null);
		}, function(cell){
			t._removeCell(null, null, cell);
		});
		this._updateFormulasParents(0, start, gc_nMaxRow0, gc_nMaxCol0, oActualRange, offset, renameRes.shiftedShared);
		this.cellsByCol.splice(start, stop - start + 1);
		this.aCols.splice(start, stop - start + 1);
		for(i = start, length = this.aCols.length; i < length; ++i)
		{
			var elem = this.aCols[i];
			if(null != elem)
				elem.moveHor(nDif);
		}
		//notifyChanged after move cells to get new locations(for intersect ranges)
		this.workbook.dependencyFormulas.notifyChanged(renameRes.changed);
		History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_RemoveCols, this.getId(), new Asc.Range(start, 0, gc_nMaxCol0, gc_nMaxRow0), new UndoRedoData_FromToRowCol(false, start, stop));

		this.autoFilters.redrawStylesTables(redrawTablesArr);

		this.workbook.dependencyFormulas.unlockRecal();

		return true;
	};
	Worksheet.prototype.insertColsBefore=function(index, count){
		var oRange = this.getRange3(0, index, gc_nMaxRow0, index + count - 1);
		oRange.addCellsShiftRight();
	};
	Worksheet.prototype._insertColsBefore=function(index, count){
		this.workbook.dependencyFormulas.lockRecal();
		var oActualRange = new Asc.Range(index, 0, index + count - 1, gc_nMaxRow0);
		History.Create_NewPoint();
		var offset = new AscCommon.CellBase(0, count);
		//renameDependencyNodes before move cells to store current location in history
		var renameRes = this.renameDependencyNodes(offset, oActualRange);
		var redrawTablesArr = this.autoFilters.insertColumn(oActualRange, count);
		this.updatePivotOffset(oActualRange, offset);

		this._updateFormulasParents(0, index, gc_nMaxRow0, gc_nMaxCol0, oActualRange, offset, renameRes.shiftedShared);
		var borders = this._getBordersForInsert(0, index, gc_nMaxRow0, index, false);
		//remove tail
		this.cellsByCol.splice(gc_nMaxCol0 - count + 1, count);
		var prevCellsByCol = index > 0 ? this.cellsByCol[index - 1] : null;
		for(var i = 0; i < count; ++i) {
			var sheetMemory = prevCellsByCol ? prevCellsByCol.clone() : undefined;
			this.cellsByCol.splice(index + i, 0, sheetMemory);
		}
		//show rows and remain only cell xf property
		this.getRange3(0, index, gc_nMaxRow0, index + count - 1)._foreachNoEmpty(function(cell) {
			cell.clearDataKeepXf(borders[cell.nRow]);
		});
		//notifyChanged after move cells to get new locations(for intersect ranges)
		this.workbook.dependencyFormulas.notifyChanged(renameRes.changed);
		History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_AddCols, this.getId(), new Asc.Range(index, 0, gc_nMaxCol0, gc_nMaxRow0), new UndoRedoData_FromToRowCol(false, index, index + count - 1));

		this.autoFilters.redrawStylesTables(redrawTablesArr);

		this.workbook.dependencyFormulas.unlockRecal();

		var oPrevCol = null;
		if(index > 0)
			oPrevCol = this.aCols[index - 1];
		if(null == oPrevCol && null != this.oAllCol)
			oPrevCol = this.oAllCol;
		for(var i = 0; i < count; ++i)
		{
			var oNewCol = null;
			if (null != oPrevCol && false == this.workbook.bUndoChanges && (false == this.workbook.bRedoChanges || this.workbook.bCollaborativeChanges))
			{
				History.LocalChange = true;
				oNewCol = oPrevCol.clone();
				oNewCol.setHidden(null);
				oNewCol.BestFit = null;
				oNewCol.index = index + i;
				History.LocalChange = false;
			}
			this.aCols.splice(index, 0, oNewCol);
		}
		for(var i = index + count, length = this.aCols.length; i < length; ++i)
		{
			var elem = this.aCols[i];
			if(null != elem)
				elem.moveHor(count);
		}
		this.nColsCount += count;

		return true;
	};
	Worksheet.prototype.insertColsAfter=function(index, count){
		//index 0 based
		return this.insertColsBefore(index + 1, count);
	};
	Worksheet.prototype.getDefaultWidth=function(){
		return this.oSheetFormatPr.dDefaultColWidth;
	};
	Worksheet.prototype.getDefaultFontName=function(){
		return this.workbook.getDefaultFont();
	};
	Worksheet.prototype.getDefaultFontSize=function(){
		return this.workbook.getDefaultSize();
	};
	Worksheet.prototype.getBaseColWidth = function () {
		return this.oSheetFormatPr.nBaseColWidth || 8; // Число символов для дефалтовой ширины (по умолчинию 8)
	};
	Worksheet.prototype.charCountToModelColWidth = function (count) {
		return this.workbook.charCountToModelColWidth(count);
	};
	Worksheet.prototype.modelColWidthToColWidth = function (mcw) {
		return this.workbook.modelColWidthToColWidth(mcw);
	};
	Worksheet.prototype.colWidthToCharCount = function (w) {
		return this.workbook.colWidthToCharCount(w);
	};
	Worksheet.prototype.getColWidth=function(index){
		//index 0 based
		//Результат в пунктах
		var col = this._getColNoEmptyWithAll(index);
		if(null != col && null != col.width)
			return col.width;
		var dResult = this.oSheetFormatPr.dDefaultColWidth;
		if(dResult === undefined || dResult === null || dResult == 0)
		//dResult = (8) + 5;//(EMCA-376.page 1857.)defaultColWidth = baseColumnWidth + {margin padding (2 pixels on each side, totalling 4 pixels)} + {gridline (1pixel)}
			dResult = -1; // calc default width at presentation level
		return dResult;
	};
	Worksheet.prototype.setColWidth=function(width, start, stop){
		width = this.charCountToModelColWidth(width);
		if(0 == width)
			return this.setColHidden(true, start, stop);

		//start, stop 0 based
		if(null == start)
			return;
		if(null == stop)
			stop = start;
		History.Create_NewPoint();
		var oSelection = History.GetSelection();
		if(null != oSelection)
		{
			oSelection = oSelection.clone();
			oSelection.assign(start, 0, stop, gc_nMaxRow0);
			History.SetSelection(oSelection);
			History.SetSelectionRedo(oSelection);
		}
		var oThis = this;
		var fProcessCol = function(col){
			if(col.width != width)
			{
				var oOldProps = col.getWidthProp();
				col.width = width;
				col.CustomWidth = true;
				col.BestFit = null;
				col.setHidden(null);
				oThis.initColumn(col);
				var oNewProps = col.getWidthProp();
				if(false == oOldProps.isEqual(oNewProps))
					History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_ColProp, oThis.getId(),
								col._getUpdateRange(),
								new UndoRedoData_IndexSimpleProp(col.index, false, oOldProps, oNewProps));
			}
		};
		if(0 == start && gc_nMaxCol0 == stop)
		{
			var col = this.getAllCol();
			fProcessCol(col);
			for(var i in this.aCols){
				var col = this.aCols[i];
				if (null != col)
					fProcessCol(col);
			}
		}
		else
		{
			for(var i = start; i <= stop; i++){
				var col = this._getCol(i);
				fProcessCol(col);
			}
		}
	};
	Worksheet.prototype.getColHidden=function(index){
		var col = this._getColNoEmptyWithAll(index);
		return col ? col.getHidden() : false;
	};
	Worksheet.prototype.setColHidden=function(bHidden, start, stop){
		//start, stop 0 based
		if(null == start)
			return;
		if(null == stop)
			stop = start;
		History.Create_NewPoint();
		var oThis = this;
		var fProcessCol = function(col){
			if(col.getHidden() != bHidden)
			{
				var oOldProps = col.getWidthProp();
				if(bHidden)
				{
					col.setHidden(bHidden);
					if(null == col.width || true != col.CustomWidth)
						col.width = 0;
					col.CustomWidth = true;
					col.BestFit = null;
				}
				else
				{
					col.setHidden(null);
					if(0 >= col.width)
						col.width = null;
				}
				var oNewProps = col.getWidthProp();
				if(false == oOldProps.isEqual(oNewProps))
					History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_ColProp, oThis.getId(),
								col._getUpdateRange(),
								new UndoRedoData_IndexSimpleProp(col.index, false, oOldProps, oNewProps));
			}
		};
		if(0 != start && gc_nMaxCol0 == stop)
		{
			var col = null;
			if(false == bHidden)
				col = this.oAllCol;
			else
				col = this.getAllCol();
			if(null != col)
				fProcessCol(col);
			for(var i in this.aCols){
				var col = this.aCols[i];
				if (null != col)
					fProcessCol(col);
			}
		}
		else
		{
			for(var i = start; i <= stop; i++){
				var col = null;
				if(false == bHidden)
					col = this._getColNoEmpty(i);
				else
					col = this._getCol(i);
				if(null != col)
					fProcessCol(col);
			}
		}
	};
	Worksheet.prototype.getColCustomWidth = function (index) {
		var isBestFit;
		var column = this._getColNoEmptyWithAll(index);
		if (!column) {
			isBestFit = true;
		} else if (column.getHidden()) {
			isBestFit = false;
		} else {
			isBestFit = !!(column.BestFit || (null === column.BestFit && null === column.CustomWidth));
		}
		return !isBestFit;
	};
	Worksheet.prototype.setColBestFit=function(bBestFit, width, start, stop){
		//start, stop 0 based
		if(null == start)
			return;
		if(null == stop)
			stop = start;
		History.Create_NewPoint();
		var oThis = this;
		var fProcessCol = function(col){
			var oOldProps = col.getWidthProp();
			if(bBestFit)
			{
				col.BestFit = bBestFit;
				col.setHidden(null);
			}
			else
				col.BestFit = null;
			col.width = width;
			oThis.initColumn(col);
			var oNewProps = col.getWidthProp();
			if(false == oOldProps.isEqual(oNewProps))
				History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_ColProp, oThis.getId(),
							col._getUpdateRange(),
							new UndoRedoData_IndexSimpleProp(col.index, false, oOldProps, oNewProps));
		};
		if(0 != start && gc_nMaxCol0 == stop)
		{
			var col = null;
			if(bBestFit && oDefaultMetrics.ColWidthChars == width)
				col = this.oAllCol;
			else
				col = this.getAllCol();
			if(null != col)
				fProcessCol(col);
			for(var i in this.aCols){
				var col = this.aCols[i];
				if (null != col)
					fProcessCol(col);
			}
		}
		else
		{
			for(var i = start; i <= stop; i++){
				var col = null;
				if(bBestFit && oDefaultMetrics.ColWidthChars == width)
					col = this._getColNoEmpty(i);
				else
					col = this._getCol(i);
				if(null != col)
					fProcessCol(col);
			}
		}
	};
	Worksheet.prototype.isDefaultHeightHidden=function(){
		return null != this.oSheetFormatPr.oAllRow && this.oSheetFormatPr.oAllRow.getHidden();
	};
	Worksheet.prototype.isDefaultWidthHidden=function(){
		return null != this.oAllCol && this.oAllCol.getHidden();
	};
	Worksheet.prototype.setDefaultHeight = function (h){
		// ToDo refactoring this
		if (this.oSheetFormatPr.oAllRow && !this.oSheetFormatPr.oAllRow.getCustomHeight()) {
			this.oSheetFormatPr.oAllRow.h = h;
		}
	};
	Worksheet.prototype.getDefaultHeight=function(){
		// ToDo http://bugzilla.onlyoffice.com/show_bug.cgi?id=19666 (флага CustomHeight нет)
		var dRes = null;
		// Нужно возвращать выставленную, только если флаг CustomHeight = true
		if(null != this.oSheetFormatPr.oAllRow && this.oSheetFormatPr.oAllRow.getCustomHeight())
			dRes = this.oSheetFormatPr.oAllRow.h;
		return dRes;
	};
	Worksheet.prototype.getRowHeight = function(index) {
		var res;
		this._getRowNoEmptyWithAll(index, function(row){
			res = row ? row.getHeight() : -1;
		});
		return res;
	};
	Worksheet.prototype.setRowHeight=function(height, start, stop, isCustom){
		if(0 == height)
			return this.setRowHidden(true, start, stop);
		//start, stop 0 based
		if(null == start)
			return;
		if(null == stop)
			stop = start;
		History.Create_NewPoint();
		var oThis = this, i;
		var oSelection = History.GetSelection();
		if(null != oSelection)
		{
			oSelection = oSelection.clone();
			oSelection.assign(0, start, gc_nMaxCol0, stop);
			History.SetSelection(oSelection);
			History.SetSelectionRedo(oSelection);
		}
		var fProcessRow = function(row){
			if(row)
			{
				var oOldProps = row.getHeightProp();
				row.setHeight(height);
				if (isCustom) {
					row.setCustomHeight(true);
				}
				row.setCalcHeight(true);
				row.setHidden(false);
				var oNewProps = row.getHeightProp();
				if(false === oOldProps.isEqual(oNewProps))
					History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_RowProp, oThis.getId(), row._getUpdateRange(), new UndoRedoData_IndexSimpleProp(row.index, true, oOldProps, oNewProps));
			}
		};
		if(0 == start && gc_nMaxRow0 == stop)
		{
			fProcessRow(this.getAllRow());
			this._forEachRow(fProcessRow);
		}
		else
		{
			this.getRange3(start,0,stop, 0)._foreachRow(fProcessRow);
		}
		this.workbook.dependencyFormulas.calcTree();
	};
	Worksheet.prototype.getRowHidden=function(index){
		var res;
		this._getRowNoEmptyWithAll(index, function(row){
			res = row ? row.getHidden() : false;
		});
		return res;
	};
	Worksheet.prototype.setRowHidden=function(bHidden, start, stop){
		//start, stop 0 based
		if(null == start)
			return;
		if(null == stop)
			stop = start;
		History.Create_NewPoint();
		var oThis = this, i;
		var startIndex = null, endIndex = null, updateRange;

		var fProcessRow = function(row){
			if(row && bHidden != row.getHidden())
			{
				row.setHidden(bHidden);

				if(row.index === endIndex + 1 && startIndex !== null)
					endIndex++;
				else
				{
					if(startIndex !== null)
					{
						updateRange = new Asc.Range(0, startIndex, gc_nMaxCol0, endIndex);
						History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_RowHide, oThis.getId(), updateRange, new UndoRedoData_FromToRowCol(bHidden, startIndex, endIndex));
					}

					startIndex = row.index;
					endIndex = row.index;
				}
			}
		};
		if(0 == start && gc_nMaxRow0 == stop)
		{
			// ToDo реализовать скрытие всех строк!
		}
		else
		{
			for (i = start; i <= stop; ++i) {
				false == bHidden ? this._getRowNoEmpty(i, fProcessRow) : this._getRow(i, fProcessRow);
			}

			if(startIndex !== null)//заносим последние строки
			{
				updateRange = new Asc.Range(0, startIndex, gc_nMaxCol0, endIndex);
				History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_RowHide, oThis.getId(),updateRange, new UndoRedoData_FromToRowCol(bHidden, startIndex, endIndex));
			}
		}
		this.workbook.dependencyFormulas.calcTree();
	};
	Worksheet.prototype.getRowCustomHeight = function (index) {
		var isCustomHeight = false;
		this._getRowNoEmptyWithAll(index, function (row) {
			if (!row) {
				isCustomHeight = false;
			} else if (row.getHidden()) {
				isCustomHeight = true;
			} else {
				isCustomHeight = row.getCustomHeight();
			}
		});
		return isCustomHeight;
	};
	Worksheet.prototype.setRowBestFit=function(bBestFit, height, start, stop){
		//start, stop 0 based
		if(null == start)
			return;
		if(null == stop)
			stop = start;
		History.Create_NewPoint();
		var oThis = this, i;
		var isDefaultProp = (true == bBestFit && oDefaultMetrics.RowHeight == height);
		var fProcessRow = function(row){
			if(row)
			{
				var oOldProps = row.getHeightProp();
				row.setCustomHeight(!bBestFit);
				row.setCalcHeight(true);
				row.setHeight(height);
				var oNewProps = row.getHeightProp();
				if(false == oOldProps.isEqual(oNewProps))
					History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_RowProp, oThis.getId(), row._getUpdateRange(), new UndoRedoData_IndexSimpleProp(row.index, true, oOldProps, oNewProps));
			}
		};
		if(0 == start && gc_nMaxRow0 == stop) {
			fProcessRow(isDefaultProp ? this.oSheetFormatPr.oAllRow : this.getAllRow());
			this._forEachRow(fProcessRow);
		} else {
			var range = this.getRange3(start,0,stop, 0);
			if (isDefaultProp) {
				range._foreachRowNoEmpty(fProcessRow);
			} else {
				range._foreachRow(fProcessRow);
			}
		}
		this.workbook.dependencyFormulas.calcTree();
	};
	Worksheet.prototype.getCell=function(oCellAdd){
		return this.getRange(oCellAdd, oCellAdd);
	};
	Worksheet.prototype.getCell2=function(sCellAdd){
		if( sCellAdd.indexOf("$") > -1)
			sCellAdd = sCellAdd.replace(/\$/g,"");
		return this.getRange2(sCellAdd);
	};
	Worksheet.prototype.getCell3=function(r1, c1){
		return this.getRange3(r1, c1, r1, c1);
	};
	Worksheet.prototype.getRange=function(cellAdd1, cellAdd2){
		//Если range находится за границами ячеек расширяем их
		var nRow1 = cellAdd1.getRow0();
		var nCol1 = cellAdd1.getCol0();
		var nRow2 = cellAdd2.getRow0();
		var nCol2 = cellAdd2.getCol0();
		return this.getRange3(nRow1, nCol1, nRow2, nCol2);
	};
	Worksheet.prototype.getRange2=function(sRange){
		var bbox = AscCommonExcel.g_oRangeCache.getAscRange(sRange);
		if(null != bbox)
			return Range.prototype.createFromBBox(this, bbox);
		return null;
	};
	Worksheet.prototype.getRange3=function(r1, c1, r2, c2){
		var nRowMin = r1;
		var nRowMax = r2;
		var nColMin = c1;
		var nColMax = c2;
		if(r1 > r2){
			nRowMax = r1;
			nRowMin = r2;
		}
		if(c1 > c2){
			nColMax = c1;
			nColMin = c2;
		}
		return new Range(this, nRowMin, nColMin, nRowMax, nColMax);
	};
	Worksheet.prototype.getRange4=function(r, c){
		return new Range(this, r, c, r, c);
	};
	Worksheet.prototype._removeCell=function(nRow, nCol, cell){
		var t = this;
		var processCell = function(cell) {
			if(null != cell)
			{
				var sheetId = t.getId();
				if (false == cell.isEmpty()) {
					var oUndoRedoData_CellData = new AscCommonExcel.UndoRedoData_CellData(cell.getValueData(), null);
					if (null != cell.xfs)
						oUndoRedoData_CellData.style = cell.xfs.clone();
					cell.setFormulaInternal(null);
					History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_RemoveCell, sheetId, new Asc.Range(nCol, nRow, nCol, nRow), new UndoRedoData_CellSimpleData(nRow, nCol, oUndoRedoData_CellData, null));
				}
				t.workbook.dependencyFormulas.addToChangedCell(cell);

				cell.clearData();
				cell.saveContent(true);
			}
		};
		if(null != cell)
		{
			nRow = cell.nRow;
			nCol = cell.nCol;
			processCell(cell);
		} else {
			this._getCellNoEmpty(nRow, nCol, processCell);
		}
	};
	Worksheet.prototype._getCell=function(row, col, fAction){
		var wb = this.workbook;
		var targetCell = null;
		for (var k = 0; k < wb.loadCells.length; ++k) {
			var elem = wb.loadCells[k];
			if (elem.nRow == row && elem.nCol == col && this === elem.ws) {
				targetCell = elem;
				break;
			}
		}
		if(null === targetCell){
			var cell = new Cell(this);
			wb.loadCells.push(cell);
			if (!cell.loadContent(row, col)) {
				this._initCell(cell, row, col);
			}
			fAction(cell);
			cell.saveContent(true);
			wb.loadCells.pop();
		} else {
			fAction(targetCell);
		}
	};
	Worksheet.prototype._initRow=function(row, index){
		var t = this;
		row.setChanged(true);
		if (null != this.oSheetFormatPr.oAllRow) {
			row.copyFrom(this.oSheetFormatPr.oAllRow);
			row.setIndex(index);
		}
		this.nRowsCount = index >= this.nRowsCount ? index + 1 : this.nRowsCount;
	};
	Worksheet.prototype._initCell=function(cell, nRow, nCol){
		var t = this;
		cell.setChanged(true);
		this._getRowNoEmpty(nRow, function(row) {
			var oCol = t._getColNoEmptyWithAll(nCol);
			var xfs = null;
			if (row && null != row.xfs)
				xfs = row.xfs.clone();
			else if (null != oCol && null != oCol.xfs)
				xfs = oCol.xfs.clone();
			cell.setStyleInternal(xfs);
			if (nRow >= t.nRowsCount)
				t.nRowsCount = nRow + 1;
			if (nCol >= t.nColsCount)
				t.nColsCount = nCol + 1;
		});
		//init ColData otherwise all 'foreach' will not return this cell until saveContent(loadCells)
		var sheetMemory = this.getColData(nCol);
		sheetMemory.checkSize(nRow);
	};
	Worksheet.prototype._getCellNoEmpty=function(row, col, fAction){
		var wb = this.workbook;
		var targetCell = null;
		for (var k = 0; k < wb.loadCells.length; ++k) {
			var elem = wb.loadCells[k];
			if (elem.nRow == row && elem.nCol == col && this === elem.ws) {
				targetCell = elem;
				break;
			}
		}
		if (null === targetCell) {
			var cell = new Cell(this);
			var res = cell.loadContent(row, col) ? cell : null;
			if (res && fAction) {
				wb.loadCells.push(cell);
			}
			fAction(res);
			cell.saveContent(true);
			if (res) {
				wb.loadCells.pop();
			}
		} else {
			fAction(targetCell);
		}
	};
	Worksheet.prototype._getRowNoEmpty=function(nRow, fAction){
		//0-based
		var row = new AscCommonExcel.Row(this);
		if(row.loadContent(nRow)){
			fAction(row);
			row.saveContent(true);
		} else {
			fAction(null);
		}
	};
	Worksheet.prototype._getRowNoEmptyWithAll=function(nRow, fAction){
		var t = this;
		this._getRowNoEmpty(nRow, function(row){
			if(!row)
				row = t.oSheetFormatPr.oAllRow;
			fAction(row);
		});

	};
	Worksheet.prototype._getColNoEmpty = function (col) {
		//0-based
		return this.aCols[col] || null;
	};
	Worksheet.prototype._getColNoEmptyWithAll = function (col) {
		return this._getColNoEmpty(col) || this.oAllCol;
	};
	Worksheet.prototype._getRow = function(index, fAction) {
		//0-based
		var row = null;
		if (g_nAllRowIndex == index)
			row = this.getAllRow();
		else {
			row = new AscCommonExcel.Row(this);
			if (!row.loadContent(index)) {
				this._initRow(row, index);
			}
		}
		fAction(row);
		row.saveContent(true);
	};
	Worksheet.prototype._getCol=function(index){
		//0-based
		var oCurCol;
		if (g_nAllColIndex == index)
			oCurCol = this.getAllCol();
		else
		{
			oCurCol = this.aCols[index];
			if(null == oCurCol)
			{
				if(null != this.oAllCol)
				{
					oCurCol = this.oAllCol.clone();
					oCurCol.index = index;
				}
				else
					oCurCol = new AscCommonExcel.Col(this, index);
				this.aCols[index] = oCurCol;
				this.nColsCount = index >= this.nColsCount ? index + 1 : this.nColsCount;
			}
		}
		return oCurCol;
	};
	Worksheet.prototype._prepareMoveRangeGetCleanRanges=function(oBBoxFrom, oBBoxTo){
		var intersection = oBBoxFrom.intersectionSimple(oBBoxTo);
		var aRangesToCheck = [];
		if(null != intersection)
		{
			var oThis = this;
			var fAddToRangesToCheck = function(aRangesToCheck, r1, c1, r2, c2)
			{
				if(r1 <= r2 && c1 <= c2)
					aRangesToCheck.push(oThis.getRange3(r1, c1, r2, c2));
			};
			if(intersection.r1 == oBBoxTo.r1 && intersection.c1 == oBBoxTo.c1)
			{
				fAddToRangesToCheck(aRangesToCheck, oBBoxTo.r1, intersection.c2 + 1, intersection.r2, oBBoxTo.c2);
				fAddToRangesToCheck(aRangesToCheck, intersection.r2 + 1, oBBoxTo.c1, oBBoxTo.r2, oBBoxTo.c2);
			}
			else if(intersection.r2 == oBBoxTo.r2 && intersection.c1 == oBBoxTo.c1)
			{
				fAddToRangesToCheck(aRangesToCheck, oBBoxTo.r1, oBBoxTo.c1, intersection.r1 - 1, oBBoxTo.c2);
				fAddToRangesToCheck(aRangesToCheck, intersection.r1, intersection.c2 + 1, oBBoxTo.r2, oBBoxTo.c2);
			}
			else if(intersection.r1 == oBBoxTo.r1 && intersection.c2 == oBBoxTo.c2)
			{
				fAddToRangesToCheck(aRangesToCheck, oBBoxTo.r1, oBBoxTo.c1, intersection.r2, intersection.c1 - 1);
				fAddToRangesToCheck(aRangesToCheck, intersection.r2 + 1, oBBoxTo.c1, oBBoxTo.r2, oBBoxTo.c2);
			}
			else if(intersection.r2 == oBBoxTo.r2 && intersection.c2 == oBBoxTo.c2)
			{
				fAddToRangesToCheck(aRangesToCheck, oBBoxTo.r1, oBBoxTo.c1, intersection.r1 - 1, oBBoxTo.c2);
				fAddToRangesToCheck(aRangesToCheck, intersection.r1, oBBoxTo.c1, oBBoxTo.r2, intersection.c1 - 1);
			}
		}
		else
			aRangesToCheck.push(this.getRange3(oBBoxTo.r1, oBBoxTo.c1, oBBoxTo.r2, oBBoxTo.c2));
		return aRangesToCheck;
	};
	Worksheet.prototype._prepareMoveRange=function(oBBoxFrom, oBBoxTo){
		var res = 0;
		if(oBBoxFrom.isEqual(oBBoxTo))
			return res;
		var range = this.getRange3(oBBoxTo.r1, oBBoxTo.c1, oBBoxTo.r2, oBBoxTo.c2);
		var aMerged = this.mergeManager.get(range.getBBox0());
		if(aMerged.outer.length > 0)
			return -2;
		var aRangesToCheck = this._prepareMoveRangeGetCleanRanges(oBBoxFrom, oBBoxTo);
		for(var i = 0, length = aRangesToCheck.length; i < length; i++)
		{
			range = aRangesToCheck[i];
			range._foreachNoEmpty(
				function(cell){
					if(!cell.isNullTextString())
					{
						res = -1;
						return res;
					}
				});
			if(0 != res)
				return res;
		}
		return res;
	};
	Worksheet.prototype._moveRange=function(oBBoxFrom, oBBoxTo, copyRange){
		if(oBBoxFrom.isEqual(oBBoxTo))
			return;
		var oThis = this;
		History.Create_NewPoint();
		History.StartTransaction();

		this.workbook.dependencyFormulas.lockRecal();
		var offset = new AscCommon.CellBase(oBBoxTo.r1 - oBBoxFrom.r1, oBBoxTo.c1 - oBBoxFrom.c1);
		var intersection = oBBoxFrom.intersectionSimple(oBBoxTo);
		var oRangeIntersection = null;
		if(null != intersection)
			oRangeIntersection = this.getRange3(intersection.r1, intersection.c1, intersection.r2, intersection.c2 );
		//запоминаем то что нужно переместить
		var aTempObj = {cells: {}, merged: null, hyperlinks: null};
		if(false == this.workbook.bUndoChanges && (false == this.workbook.bRedoChanges || this.workbook.bCollaborativeChanges))
		{
			History.LocalChange = true;
			var aMerged = this.mergeManager.get(oBBoxFrom);
			if(aMerged.inner.length > 0)
				aTempObj.merged = aMerged.inner;
			var aHyperlinks = this.hyperlinkManager.get(oBBoxFrom);
			if(aHyperlinks.inner.length > 0)
				aTempObj.hyperlinks = aHyperlinks.inner;
			var aMergedToRemove = null;
			if(!copyRange){
				aMergedToRemove = aTempObj.merged;
			}
			else if(null != intersection){
				var aMergedIntersection = this.mergeManager.get(intersection);
				if(aMergedIntersection.all.length > 0)
					aMergedToRemove = aMergedIntersection.all;
			}
			if(null != aMergedToRemove){
				for(var i = 0, length = aMergedToRemove.length; i < length; i++)
				{
					var elem = aMergedToRemove[i];
					this.mergeManager.removeElement(elem);
				}
			}
			if(!copyRange){
				if(null != aTempObj.hyperlinks)
				{
					for(var i = 0, length = aTempObj.hyperlinks.length; i < length; i++)
					{
						var elem = aTempObj.hyperlinks[i];
						this.hyperlinkManager.removeElement(elem);
					}
				}
			}
			History.LocalChange = false;
		}
		//удаляем to через историю, для undo
		var aRangesToCheck = this._prepareMoveRangeGetCleanRanges(oBBoxFrom, oBBoxTo);
		for (var i = 0, length = aRangesToCheck.length; i < length; i++) {
			var range = aRangesToCheck[i];
			range.cleanAll();
			//выставляем для slave refError
			if (!copyRange)
				this.workbook.dependencyFormulas.deleteNodes(this.getId(), range.getBBox0());
		}

		if(!copyRange){
			this.workbook.dependencyFormulas.move(this.Id, oBBoxFrom, offset);
		}
		var nRowsCountNew = 0;
		var nColsCountNew = 0;
		//todo avoid double getRange3
		this.getRange3(oBBoxFrom.r1, oBBoxFrom.c1, oBBoxFrom.r2, oBBoxFrom.c2)._foreachNoEmpty(function(cell) {
			if (cell.transformSharedFormula()) {
				var parsed = cell.getFormulaParsed();
				parsed.buildDependencies();
			}
		});
		var isClearFromArea = !copyRange || (copyRange && oThis.workbook.bUndoChanges);
		var moveCells = function(copyRange, from, to, r1From, r1To, count){
			var fromData = oThis.getColDataNoEmpty(from);
			var toData;
			if(fromData){
				toData = oThis.getColData(to);
				toData.copyRange(fromData, r1From, r1To, count);
				if (isClearFromArea) {
					if(from !== to) {
						fromData.clear(r1From, r1From + count);
					} else {
						if (r1From < r1To) {
							fromData.clear(r1From, Math.min(r1From + count, r1To));
						} else {
							fromData.clear(Math.max(r1From, r1To + count), r1From + count);
						}
					}
				}
			} else {
				toData = oThis.getColDataNoEmpty(to);
				if(toData) {
					toData.clear(r1To, r1To + count);
				}
			}
			if (toData) {
				nRowsCountNew = Math.max(nRowsCountNew, toData.getSize());
				nColsCountNew = Math.max(nColsCountNew, to + 1);
			}
		};
		if(oBBoxFrom.c1 < oBBoxTo.c1){
			for(var i = 0 ; i < oBBoxFrom.c2 - oBBoxFrom.c1 + 1; ++i){
				moveCells(copyRange, oBBoxFrom. c2 - i, oBBoxTo.c2 - i, oBBoxFrom.r1, oBBoxTo.r1, oBBoxFrom.r2 - oBBoxFrom.r1 + 1);
			}
		} else {
			for(var i = 0 ; i < oBBoxFrom.c2 - oBBoxFrom.c1 + 1; ++i){
				moveCells(copyRange, oBBoxFrom.c1 + i, oBBoxTo.c1 + i, oBBoxFrom.r1, oBBoxTo.r1, oBBoxFrom.r2 - oBBoxFrom.r1 + 1);
			}
		}
		//modify nRowsCount/nColsCount for correct foreach functions
		this.nRowsCount = Math.max(this.nRowsCount, nRowsCountNew);
		this.nColsCount = Math.max(this.nColsCount, nColsCountNew);
		this.getRange3(oBBoxTo.r1, oBBoxTo.c1, oBBoxTo.r2, oBBoxTo.c2)._foreachNoEmpty(function(cell){
			var formula = cell.getFormulaParsed();
			if (formula) {
				var cellWithFormula = formula.getParent();
				if (copyRange) {
					History.TurnOff();
					cellWithFormula = new CCellWithFormula(cellWithFormula.ws, cell.nRow, cell.nCol);
					var newFormula = formula.clone(null, cellWithFormula, oThis);
					newFormula.changeOffset(offset, false, true);
					newFormula.setFormulaString(newFormula.assemble(true));
					cell.setFormulaInternal(newFormula, !isClearFromArea);
					History.TurnOn();
				} else {
					cellWithFormula.nRow = cell.nRow;
					cellWithFormula.nCol = cell.nCol;
				}
				oThis.workbook.dependencyFormulas.addToBuildDependencyCell(cell);
			}
		});


		if(false == this.workbook.bUndoChanges && (false == this.workbook.bRedoChanges || this.workbook.bCollaborativeChanges))
		{
			History.LocalChange = true;
			if(null != aTempObj.merged)
			{
				for(var i = 0, length = aTempObj.merged.length; i < length; i++)
				{
					var elem = aTempObj.merged[i];
					var oNewBBox;
					var oNewData = elem.data;
					if(copyRange)
						oNewBBox = elem.bbox.clone();
					else
						oNewBBox = elem.bbox;
					oNewBBox.setOffset(offset);
					this.mergeManager.add(oNewBBox, oNewData);
				}
			}
			//todo сделать для пересечения
			if(null != aTempObj.hyperlinks && (!copyRange || null == intersection))
			{
				for(var i = 0, length = aTempObj.hyperlinks.length; i < length; i++)
				{
					var elem = aTempObj.hyperlinks[i];
					var oNewBBox;
					var oNewData;
					if(copyRange){
						oNewBBox = elem.bbox.clone();
						oNewData = elem.data.clone();
					}
					else{
						oNewBBox = elem.bbox;
						oNewData = elem.data;
					}
					oNewBBox.setOffset(offset);
					this.hyperlinkManager.add(oNewBBox, oNewData);
				}
			}
			History.LocalChange = false;
		}

		this.workbook.dependencyFormulas.unlockRecal();

		if(true == this.workbook.bUndoChanges || true == this.workbook.bRedoChanges)
		{
			this.autoFilters.unmergeTablesAfterMove( oBBoxTo );
		}

		// ToDo возможно нужно уменьшить диапазон обновления
		History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_MoveRange,
					this.getId(), new Asc.Range(0, 0, gc_nMaxCol0, gc_nMaxRow0),
					new UndoRedoData_FromTo(new UndoRedoData_BBox(oBBoxFrom), new UndoRedoData_BBox(oBBoxTo), copyRange));

		if(false == this.workbook.bUndoChanges && false == this.workbook.bRedoChanges)
			this.autoFilters._moveAutoFilters( oBBoxTo, oBBoxFrom, null, copyRange, true, oBBoxFrom );
		History.EndTransaction();
		return true;
	};
	Worksheet.prototype._shiftCellsLeft=function(oBBox){
		//todo удаление когда есть замерженые ячейки
		var t = this;
		var nLeft = oBBox.c1;
		var nRight = oBBox.c2;
		var dif = nLeft - nRight - 1;
		var oActualRange = new Asc.Range(nLeft, oBBox.r1, gc_nMaxCol0, oBBox.r2);
		var offset = new AscCommon.CellBase(0, dif);
		//renameDependencyNodes before move cells to store current location in history
		var renameRes = this.renameDependencyNodes(offset, oBBox);
		var redrawTablesArr = this.autoFilters.insertColumn( oBBox, dif );

		this.getRange3(oBBox.r1, oBBox.c1, oBBox.r2, oBBox.c2)._foreachNoEmpty(function(cell){
			t._removeCell(null, null, cell);
		});

		this._updateFormulasParents(oActualRange.r1, oActualRange.c1, oActualRange.r2, oActualRange.c2, oBBox, offset, renameRes.shiftedShared);
		var cellsByColLength = this.getColDataLength();
		for (var i = nRight + 1; i < cellsByColLength; ++i) {
			var sheetMemoryFrom = this.getColDataNoEmpty(i);
			if (sheetMemoryFrom) {
				this.getColData(i + dif).copyRange(sheetMemoryFrom, oBBox.r1, oBBox.r1, oBBox.r2 - oBBox.r1 + 1);
				sheetMemoryFrom.clear(oBBox.r1, oBBox.r2 + 1);
			}
		}
		//notifyChanged after move cells to get new locations(for intersect ranges)
		this.workbook.dependencyFormulas.notifyChanged(renameRes.changed);
		History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_ShiftCellsLeft, this.getId(), oActualRange, new UndoRedoData_BBox(oBBox));

		this.autoFilters.redrawStylesTables(redrawTablesArr);
		//todo проверить не уменьшились ли границы таблицы
	};
	Worksheet.prototype._shiftCellsUp=function(oBBox){
		var t = this;
		var nTop = oBBox.r1;
		var nBottom = oBBox.r2;
		var dif = nTop - nBottom - 1;
		var oActualRange = new Asc.Range(oBBox.c1, oBBox.r1, oBBox.c2, gc_nMaxRow0);
		var offset = new AscCommon.CellBase(dif, 0);
		//renameDependencyNodes before move cells to store current location in history
		var renameRes = this.renameDependencyNodes(offset, oBBox);
		var redrawTablesArr = this.autoFilters.insertRows("delCell", oBBox, c_oAscDeleteOptions.DeleteCellsAndShiftTop);

		this.getRange3(oBBox.r1, oBBox.c1, oBBox.r2, oBBox.c2)._foreachNoEmpty(function(cell){
			t._removeCell(null, null, cell);
		});
		this._updateFormulasParents(oActualRange.r1, oActualRange.c1, oActualRange.r2, oActualRange.c2, oBBox, offset, renameRes.shiftedShared);
		for (var i = oBBox.c1; i <= oBBox.c2; ++i) {
			var sheetMemory = this.getColDataNoEmpty(i);
			if (sheetMemory) {
				sheetMemory.deleteRange(nTop, -dif);
			}
		}
		//notifyChanged after move cells to get new locations(for intersect ranges)
		this.workbook.dependencyFormulas.notifyChanged(renameRes.changed);
		History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_ShiftCellsTop, this.getId(), oActualRange, new UndoRedoData_BBox(oBBox));

		this.autoFilters.redrawStylesTables(redrawTablesArr);
		//todo проверить не уменьшились ли границы таблицы
	};
	Worksheet.prototype._shiftCellsRight=function(oBBox, displayNameFormatTable){
		var nLeft = oBBox.c1;
		var nRight = oBBox.c2;
		var dif = nRight - nLeft + 1;
		var oActualRange = new Asc.Range(oBBox.c1, oBBox.r1, gc_nMaxCol0, oBBox.r2);
		var offset = new AscCommon.CellBase(0, dif);
		//renameDependencyNodes before move cells to store current location in history
		var renameRes = this.renameDependencyNodes(offset, oBBox);
		var redrawTablesArr = this.autoFilters.insertColumn( oBBox, dif, displayNameFormatTable );

		this._updateFormulasParents(oActualRange.r1, oActualRange.c1, oActualRange.r2, oActualRange.c2, oBBox, offset, renameRes.shiftedShared);
		var borders = this._getBordersForInsert(oBBox.r1, oBBox.c1, oBBox.r2, oBBox.c2, false);
		var cellsByColLength = this.getColDataLength();
		for (var i = cellsByColLength - 1; i >= nLeft; --i) {
			var sheetMemoryFrom = this.getColDataNoEmpty(i);
			if (sheetMemoryFrom) {
				if (i + dif <= gc_nMaxCol0) {
					this.getColData(i + dif).copyRange(sheetMemoryFrom, oBBox.r1, oBBox.r1, oBBox.r2 - oBBox.r1 + 1);
				}
				sheetMemoryFrom.clear(oBBox.r1, oBBox.r2 + 1);
			}
		}
		if (nLeft > 0 && false == this.workbook.bUndoChanges && (false == this.workbook.bRedoChanges || this.workbook.bCollaborativeChanges))
		{
			var prevSheetMemory = this.getColDataNoEmpty(nLeft - 1);
			if (prevSheetMemory) {
				//todo hidden, keep only style
				for (var i = nLeft; i <= nRight; ++i) {
					this.getColData(i).copyRange(prevSheetMemory, oBBox.r1, oBBox.r1, oBBox.r2 - oBBox.r1 + 1);
				}
				//show rows and remain only cell xf property
				this.getRange3(oBBox.r1, oBBox.c1, oBBox.r2, oBBox.c2)._foreachNoEmpty(function(cell) {
					cell.clearDataKeepXf(borders[cell.nRow]);
				});
			}
		}
		//notifyChanged after move cells to get new locations(for intersect ranges)
		this.workbook.dependencyFormulas.notifyChanged(renameRes.changed);
		History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_ShiftCellsRight, this.getId(), oActualRange, new UndoRedoData_BBox(oBBox));


		this.autoFilters.redrawStylesTables(redrawTablesArr);
	};
	Worksheet.prototype._shiftCellsBottom=function(oBBox, displayNameFormatTable){
		var nTop = oBBox.r1;
		var nBottom = oBBox.r2;
		var dif = nBottom - nTop + 1;
		var oActualRange = new Asc.Range(oBBox.c1, oBBox.r1, oBBox.c2, gc_nMaxRow0);
		var offset = new AscCommon.CellBase(dif, 0);
		//renameDependencyNodes before move cells to store current location in history
		var renameRes = this.renameDependencyNodes(offset, oBBox);
		var redrawTablesArr;
		if (!this.workbook.bUndoChanges && undefined === displayNameFormatTable) {
			redrawTablesArr = this.autoFilters.insertRows("insCell", oBBox, c_oAscInsertOptions.InsertCellsAndShiftDown,
				displayNameFormatTable);
		}
		this._updateFormulasParents(oActualRange.r1, oActualRange.c1, oActualRange.r2, oActualRange.c2, oBBox, offset, renameRes.shiftedShared);
		var borders = this._getBordersForInsert(oBBox.r1, oBBox.c1, oBBox.r2, oBBox.c2, true);
		//rowcount
		for (var i = oBBox.c1; i <= oBBox.c2; ++i) {
			var sheetMemory = this.getColDataNoEmpty(i);
			if (sheetMemory) {
				sheetMemory.insertRange(nTop, dif);
				if (nTop > 0 && false == this.workbook.bUndoChanges && (false == this.workbook.bRedoChanges || this.workbook.bCollaborativeChanges))
				{
					sheetMemory.copyRangeByChunk((nTop - 1), 1, nTop, dif);
				}
			}
		}
		if (nTop > 0 && false == this.workbook.bUndoChanges && (false == this.workbook.bRedoChanges || this.workbook.bCollaborativeChanges))
		{
			//show rows and remain only cell xf property
			this.getRange3(oBBox.r1, oBBox.c1, oBBox.r2, oBBox.c2)._foreachNoEmpty(function(cell) {
				cell.clearDataKeepXf(borders[cell.nCol]);
			});
		}
		//notifyChanged after move cells to get new locations(for intersect ranges)
		this.workbook.dependencyFormulas.notifyChanged(renameRes.changed);
		History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_ShiftCellsBottom, this.getId(), oActualRange, new UndoRedoData_BBox(oBBox));

		//пока перенес добавление только последней строки(в данном случае порядок занесения в истрию должен быть именно в таком порядке)
		//TODO возможно стоит полностью перенести сюда обработку для ф/т и а/ф
		if (!this.workbook.bUndoChanges && undefined !== displayNameFormatTable) {
			redrawTablesArr = this.autoFilters.insertRows("insCell", oBBox, c_oAscInsertOptions.InsertCellsAndShiftDown,
				displayNameFormatTable);
		}

		if(!this.workbook.bUndoChanges)
		{
			this.autoFilters.redrawStylesTables(redrawTablesArr);
		}
	};
	Worksheet.prototype._setIndex=function(ind){
		this.index = ind;
	};
	Worksheet.prototype._BuildDependencies=function(cellRange){
		/*
		 Построение графа зависимостей.
		 */
		var ca;
		for (var i in cellRange) {
			if (null === cellRange[i]) {
				cellRange[i] = i;
				continue;
			}

			ca = g_oCellAddressUtils.getCellAddress(i);
			this._getCellNoEmpty(ca.getRow0(), ca.getCol0(), function(c) {
				if (c) {
					c._BuildDependencies(true);
				}
			});
		}
	};
	Worksheet.prototype._setHandlersTablePart = function(){
		if(!this.TableParts)
			return;

		for(var i = 0; i < this.TableParts.length; i++)
		{
			this.TableParts[i].setHandlers(this.handlers);
		}
	};
	Worksheet.prototype.getTableRangeForFormula = function(name, objectParam){
		var res = null;
		if(!this.TableParts)
			return res;

		for(var i = 0; i < this.TableParts.length; i++)
		{
			if(this.TableParts[i].DisplayName === name)
			{
				res = this.TableParts[i].getTableRangeForFormula(objectParam);
				break;
			}
		}
		return res;
	};
	Worksheet.prototype.getTableIndexColumnByName = function(tableName, columnName){
		var res = null;
		if(!this.TableParts)
			return res;

		for(var i = 0; i < this.TableParts.length; i++)
		{
			if(this.TableParts[i].DisplayName === tableName)
			{
				res = this.TableParts[i].getTableIndexColumnByName(columnName);
				break;
			}
		}
		return res;
	};
	Worksheet.prototype.getTableNameColumnByIndex = function(tableName, columnIndex){
		var res = null;
		if(!this.TableParts)
			return res;

		for(var i = 0; i < this.TableParts.length; i++)
		{
			if(this.TableParts[i].DisplayName === tableName)
			{
				res = this.TableParts[i].getTableNameColumnByIndex(columnIndex);
				break;
			}
		}
		return res;
	};
	Worksheet.prototype.isApplyFilterBySheet = function () {
		var res = false;

		if (this.AutoFilter && this.AutoFilter.isApplyAutoFilter()) {
			res = true;
		}

		if (false === res && this.TableParts) {
			for (var i = 0; i < this.TableParts.length; i++) {
				if (true === this.TableParts[i].isApplyAutoFilter()) {
					res = true;
					break;
				}
			}
		}

		return res;
	};
	Worksheet.prototype.getTableNames = function() {
		var res = [];
		if (this.TableParts) {
			for (var i = 0; i < this.TableParts.length; i++) {
				res.push(this.TableParts[i].DisplayName);
			}
		}
		return res;
	};
	Worksheet.prototype.renameDependencyNodes = function(offset, oBBox){
		return this.workbook.dependencyFormulas.shift(this.Id, oBBox, offset);
	};
	Worksheet.prototype.getAllCol = function(){
		if(null == this.oAllCol)
			this.oAllCol = new AscCommonExcel.Col(this, g_nAllColIndex);
		return this.oAllCol;
	};
	Worksheet.prototype.getAllRow = function(){
		if (null == this.oSheetFormatPr.oAllRow) {
			this.oSheetFormatPr.oAllRow = new AscCommonExcel.Row(this);
			this.oSheetFormatPr.oAllRow.setIndex(g_nAllRowIndex);
		}
		return this.oSheetFormatPr.oAllRow;
	};
	Worksheet.prototype.getAllRowNoEmpty = function(){
		return this.oSheetFormatPr.oAllRow;
	};
	Worksheet.prototype.getHyperlinkByCell = function(row, col){
		var oHyperlink = this.hyperlinkManager.getByCell(row, col);
		return oHyperlink ? oHyperlink.data : null;
	};
	Worksheet.prototype.getMergedByCell = function(row, col){
		var oMergeInfo = this.mergeManager.getByCell(row, col);
		return oMergeInfo ? oMergeInfo.bbox : null;
	};
	Worksheet.prototype.getMergedByRange = function(bbox){
		return this.mergeManager.get(bbox);
	};
	Worksheet.prototype._expandRangeByMergedAddToOuter = function(aOuter, range, aMerged){
		for(var i = 0, length = aMerged.all.length; i < length; i++)
		{
			var elem = aMerged.all[i];
			if(!range.containsRange(elem.bbox))
				aOuter.push(elem);
		}
	};
	Worksheet.prototype._expandRangeByMergedGetOuter = function(range){
		var aOuter = [];
		//смотрим только границы
		this._expandRangeByMergedAddToOuter(aOuter, range, this.mergeManager.get(new Asc.Range(range.c1, range.r1, range.c1, range.r2)));
		if(range.c1 != range.c2)
		{
			this._expandRangeByMergedAddToOuter(aOuter, range, this.mergeManager.get(new Asc.Range(range.c2, range.r1, range.c2, range.r2)));
			if(range.c2 - range.c1 > 1)
			{
				this._expandRangeByMergedAddToOuter(aOuter, range, this.mergeManager.get(new Asc.Range(range.c1 + 1, range.r1, range.c2 - 1, range.r1)));
				if(range.r1 != range.r2)
					this._expandRangeByMergedAddToOuter(aOuter, range, this.mergeManager.get(new Asc.Range(range.c1 + 1, range.r2, range.c2 - 1, range.r2)));
			}
		}
		return aOuter;
	};
	Worksheet.prototype.expandRangeByMerged = function(range){
		if(null != range)
		{
			var aOuter = this._expandRangeByMergedGetOuter(range);
			if(aOuter.length > 0)
			{
				range = range.clone();
				while(aOuter.length > 0)
				{
					for(var i = 0, length = aOuter.length; i < length; i++)
						range.union2(aOuter[i].bbox);
					aOuter = this._expandRangeByMergedGetOuter(range);
				}
			}
		}
		return range;
	};
	Worksheet.prototype.createTablePart = function(){

		return new AscCommonExcel.TablePart(this.handlers);
	};
	Worksheet.prototype.onUpdateRanges = function(ranges) {
		this.workbook.updateSparklineCache(this.sName, ranges);
		// ToDo do not update conditional formatting on hidden sheet
		this.setDirtyConditionalFormatting(new AscCommonExcel.MultiplyRange(ranges));
		this.workbook.handlers.trigger("toggleAutoCorrectOptions", null,true);
		this.clearFindResults();
	};
	Worksheet.prototype.updateSparklineCache = function(sheet, ranges) {
		for (var i = 0; i < this.aSparklineGroups.length; ++i) {
			this.aSparklineGroups[i].updateCache(sheet, ranges);
		}
	};
	Worksheet.prototype.getSparklineGroup = function(c, r) {
		for (var i = 0; i < this.aSparklineGroups.length; ++i) {
			if (-1 !== this.aSparklineGroups[i].contains(c, r)) {
				return this.aSparklineGroups[i];
			}
		}
		return null;
	};
	Worksheet.prototype.removeSparklines = function (range) {
		for (var i = this.aSparklineGroups.length - 1; i > -1 ; --i) {
			if (this.aSparklineGroups[i].remove(range)) {
				History.Add(new AscDFH.CChangesDrawingsSparklinesRemove(this.aSparklineGroups[i]));
                this.aSparklineGroups.splice(i, 1);
			}
		}
	};
	Worksheet.prototype.removeSparklineGroups = function (range) {
		for (var i = this.aSparklineGroups.length - 1; i > -1 ; --i) {
			if (-1 !== this.aSparklineGroups[i].intersectionSimple(range)) {
                History.Add(new AscDFH.CChangesDrawingsSparklinesRemove(this.aSparklineGroups[i]));
                this.aSparklineGroups.splice(i, 1);
            }
		}
	};
	Worksheet.prototype.insertSparklineGroup = function (sparklineGroup) {
		this.aSparklineGroups.push(sparklineGroup);
	};
	Worksheet.prototype.removeSparklineGroup = function (id) {
		for (var i = 0; i < this.aSparklineGroups.length; ++i) {
			if (id === this.aSparklineGroups[i].Get_Id()) {
				this.aSparklineGroups.splice(i, 1);
				break;
			}
		}
	};
	Worksheet.prototype.getCwf = function() {
		var cwf = {};
		var range = this.getRange3(0,0, gc_nMaxRow0, gc_nMaxCol0);
		range._setPropertyNoEmpty(null, null, function(cell){
			if(cell.isFormula()){
				var name = cell.getName();
				cwf[name] = name;
			}
		});
		return cwf;
	};
	Worksheet.prototype.getAllFormulas = function(formulas) {
		var range = this.getRange3(0, 0, gc_nMaxRow0, gc_nMaxCol0);
		range._setPropertyNoEmpty(null, null, function(cell) {
			if (cell.isFormula()) {
				formulas.push(cell.getFormulaParsed());
			}
		});
		for (var i = 0; i < this.TableParts.length; ++i) {
			var table = this.TableParts[i];
			table.getAllFormulas(formulas);
		}
	};
	Worksheet.prototype.setTableStyleAfterOpen = function () {
		if (this.TableParts && this.TableParts.length) {
			for (var i = 0; i < this.TableParts.length; i++) {
				var table = this.TableParts[i];
				this.autoFilters._setColorStyleTable(table.Ref, table);
			}
		}
	};
	Worksheet.prototype.setTableFormulaAfterOpen = function () {
		if (this.TableParts && this.TableParts.length) {
			for (var i = 0; i < this.TableParts.length; i++) {
				var table = this.TableParts[i];
				//TODO пока заменяем при открытии на TotalsRowFormula
				table.checkTotalRowFormula(this);
			}
		}
	};
	Worksheet.prototype.addTablePart = function (tablePart, bAddToDependencies) {
		this.TableParts.push(tablePart);
		if (bAddToDependencies) {
			this.workbook.dependencyFormulas.addTableName(this, tablePart);
			tablePart.buildDependencies();
		}
	};
	Worksheet.prototype.changeTablePart = function (index, tablePart, bChangeName) {
		var oldTablePart = this.TableParts[index];
		if (oldTablePart) {
			oldTablePart.removeDependencies();
		}
		this.TableParts[index] = tablePart;
		tablePart.buildDependencies();
		if (bChangeName && oldTablePart) {
			this.workbook.dependencyFormulas.changeTableName(oldTablePart.DisplayName, tablePart.DisplayName);
		}
	};
	Worksheet.prototype.deleteTablePart = function (index, bConvertTableFormulaToRef) {
		if(bConvertTableFormulaToRef)
		{
			//TODO скорее всего стоит убрать else
			var tablePart = this.TableParts[index];
			this.workbook.dependencyFormulas.delTableName(tablePart.DisplayName, bConvertTableFormulaToRef);
			tablePart.removeDependencies();
			
			//delete table
			this.TableParts.splice(index, 1);
		}
		else
		{
			var deleted = this.TableParts.splice(index, 1);
			for (var delIndex = 0; delIndex < deleted.length; ++delIndex) {
				var tablePart = deleted[delIndex];
				this.workbook.dependencyFormulas.delTableName(tablePart.DisplayName);
				tablePart.removeDependencies();
			}
		}
		
	};
	Worksheet.prototype.initPivotTables = function () {
		for (var i = 0; i < this.pivotTables.length; ++i) {
			this.pivotTables[i].init();
		}
	};
	Worksheet.prototype.clearPivotTable = function (pivotTable) {
		var pos, cells;
		if (this.pageFieldsPositions) {
			for (var i = 0; i < pivotTable.pageFieldsPositions.length; ++i) {
				pos = pivotTable.pageFieldsPositions[i];
				cells = this.getRange3(pos.row, pos.col, pos.row, pos.col + 1);
				cells.clearTableStyle();
				cells.cleanAll();
			}
		}

		var pivotRange = pivotTable.getRange();
		cells = this.getRange3(pivotRange.r1, pivotRange.c1, pivotRange.r2, pivotRange.c2);
		cells.clearTableStyle();
		cells.cleanAll();
	};
	Worksheet.prototype.updatePivotTable = function (pivotTable) {
		pivotTable.init();
		var cleanRanges = [];
		var pos, cells, bWarning, pivotRange;
		var i, l = pivotTable.pageFieldsPositions.length;
		pos = 0 < l && pivotTable.pageFieldsPositions[0];
		if (pos && 0 > pos.row) {
			// ToDo add check exist data in cells
			pivotRange = pivotTable.getRange();
			pivotRange.setOffset(new AscCommon.CellBase(-1 * pos.row, 0));
			pivotTable.init();
			cells = this.getRange3(pivotRange.r1, pivotRange.c1, pivotRange.r2, pivotRange.c2);
			cells._foreachNoEmpty(function (cell) {
				return (bWarning = !cell.isNullText()) ? null : cell;
			});
			cleanRanges.push(cells);
		}
		for (i = 0; i < pivotTable.pageFieldsPositions.length; ++i) {
			pos = pivotTable.pageFieldsPositions[i];
			cells = this.getRange3(pos.row, pos.col, pos.row, pos.col + 1);
			if (!bWarning) {
				cells._foreachNoEmpty(function (cell) {
					return (bWarning = !cell.isNullText()) ? null : cell;
				});
			}
			cleanRanges.push(cells);
		}
		var t = this;
		function callback(res) {
			if (res) {
				t._updatePivotTable(pivotTable, cleanRanges);
			}
		}
		if (bWarning) {
			// ToDo add confirm event
			callback(true);
		} else {
			callback(true);
		}
	};
	Worksheet.prototype._updatePivotTable = function (pivotTable, cleanRanges) {
		var pos, cells, index, i, j, k, r, c1, r1, field, indexField, cacheIndex, sharedItem, item, items, setName,
			oCellValue, rowIndexes, last;
		for (i = 0; i < cleanRanges.length; ++i) {
			cleanRanges[i].cleanAll();
		}
		var pivotRange = pivotTable.getRange();
		var cacheRecords = pivotTable.getRecords();
		var cacheFields = pivotTable.asc_getCacheFields();
		var pivotFields = pivotTable.asc_getPivotFields();
		var pageFields = pivotTable.asc_getPageFields();
		var colFields = pivotTable.asc_getColumnFields();
		var rowFields = pivotTable.asc_getRowFields();
		var dataFields = pivotTable.asc_getDataFields();
		var rowFieldsPos = [];
		for (i = 0; i < pivotTable.pageFieldsPositions.length; ++i) {
			pos = pivotTable.pageFieldsPositions[i];
			cells = this.getRange4(pos.row, pos.col);
			index = pageFields[i].asc_getIndex();
			cells.setValue(pageFields[i].asc_getName() || pivotFields[index].asc_getName() ||
				cacheFields[index].asc_getName());

			cells = this.getRange4(pos.row, pos.col + 1);
			cells.setValue('(All)');
		}
		var countC = pivotTable.getColumnFieldsCount();
		var countR = pivotTable.getRowFieldsCount(true);
		var countD = pivotTable.getDataFieldsCount();
		var valuesWithFormat = [];
		var cacheValuesCol = [];
		var cacheValuesRow = [];

		// column
		c1 = pivotRange.c1 + countR;
		r1 = pivotRange.r1;
		if (countC) {
			cells = this.getRange4(r1, c1);
			cells.setValue('Column Labels');
			++r1;
		}

		items = pivotTable.getColItems();
		if (items) {
			for (i = 0; i < items.length; ++i) {
				item = items[i];
				r = item.getR();
				rowIndexes = undefined;
				if (countC) {
					for (j = 0; j < item.x.length; ++j) {
						if (AscCommonExcel.c_oAscItemType.Grand === item.t) {
							field = null;
							oCellValue = new AscCommonExcel.CCellValue();
							oCellValue.text = 'Grand Total';
							oCellValue.type = AscCommon.CellValueType.String;
						} else {
							indexField = colFields[r + j].asc_getIndex();
							field = pivotFields[indexField];
							cacheIndex = field.getItem(item.x[j].getV());
							if (null !== item.t) {
								oCellValue = new AscCommonExcel.CCellValue();
								oCellValue.text =
									valuesWithFormat[r1 + r + j] + AscCommonExcel.ToName_ST_ItemType(item.t);
								oCellValue.type = AscCommon.CellValueType.String;
							} else {
								sharedItem = cacheFields[indexField].getSharedItem(cacheIndex.x);
								oCellValue = sharedItem.getCellValue();
							}

							if (countD) {
								rowIndexes = pivotTable.getValues(cacheRecords, rowIndexes, indexField, cacheIndex.x);
							}
						}

						cells = this.getRange4(r1 + r + j, c1 + i);
						if (field && null !== field.numFmtId) {
							cells.setNum(new AscCommonExcel.Num({id: field.numFmtId}));
						}
						cells.setValueData(new AscCommonExcel.UndoRedoData_CellValueData(null, oCellValue));
						if (null === item.t) {
							valuesWithFormat[r1 + r + j] = cells.getValueWithFormat();
						}
					}
				} else if (countR && countD) {
					// add header for data
					cells = this.getRange4(r1, c1 + i);
					index = dataFields[i].asc_getIndex();
					cells.setValue(dataFields[i].asc_getName() || pivotFields[index].asc_getName() ||
						cacheFields[index].asc_getName());
				}
				if (countD) {
					cacheValuesCol.push(rowIndexes);
				}
			}
		}

		// rows
		countR = pivotTable.getRowFieldsCount();
		if (countR) {
			c1 = pivotRange.c1;
			r1 = pivotRange.r1 + countC;
			setName = false;
			for (i = 0; i < rowFields.length; ++i) {
				if (0 === i) {
					cells = this.getRange4(r1, c1);
					cells.setValue('Row Labels');
				}
				index = rowFields[i].asc_getIndex();
				field = pivotFields[index];
				if (setName) {
					cells = this.getRange4(r1, c1);
					cells.setValue(pivotFields[index].asc_getName() || cacheFields[index].asc_getName());
					setName = false;
				}
				rowFieldsPos[i] = c1;
				if (field && false === field.compact) {
					++c1;
					setName = true;
				}
			}

			++r1;

			items = pivotTable.getRowItems();
			if (items) {
				for (i = 0; i < items.length; ++i) {
					item = items[i];
					r = item.getR();
					for (j = 0; j < item.x.length; ++j) {
						if (AscCommonExcel.c_oAscItemType.Grand === item.t) {
							field = null;
							oCellValue = new AscCommonExcel.CCellValue();
							oCellValue.text = 'Grand Total';
							oCellValue.type = AscCommon.CellValueType.String;
						} else {
							indexField = rowFields[r].asc_getIndex();
							field = pivotFields[indexField];
							cacheIndex = field.getItem(item.x[j].getV());
							if (null !== item.t) {
								oCellValue = new AscCommonExcel.CCellValue();
								oCellValue.text =
									valuesWithFormat[r1 + r + j] + AscCommonExcel.ToName_ST_ItemType(item.t);
								oCellValue.type = AscCommon.CellValueType.String;
							} else {
								sharedItem = cacheFields[indexField].getSharedItem(cacheIndex.x);
								oCellValue = sharedItem.getCellValue();
							}

							if (countD) {
								cacheValuesRow.push(indexField, cacheIndex.x);
							}
						}

						cells = this.getRange4(r1 + i, rowFieldsPos[r]);
						if (field && null !== field.numFmtId) {
							cells.setNum(new AscCommonExcel.Num({id: field.numFmtId}));
						}
						cells.setValueData(new AscCommonExcel.UndoRedoData_CellValueData(null, oCellValue));

						if (null === item.t) {
							valuesWithFormat[r1 + r + j] = cells.getValueWithFormat();
						}
					}
					last = r === countR - 1 || null !== item.t;
					if (countD && (last || (field && field.asc_getSubtotalTop()))) {
						for (j = 0; j < cacheValuesCol.length; ++j) {
							rowIndexes = cacheValuesCol[j];
							for (k = 0; k < cacheValuesRow.length && (!rowIndexes || 0 !== rowIndexes.length); k += 2) {
								rowIndexes =
									pivotTable.getValues(cacheRecords, rowIndexes, cacheValuesRow[k], cacheValuesRow[k + 1]);
							}
							if (0 !== rowIndexes.length) {
								cells = this.getRange4(r1 + i, rowFieldsPos[r] + 1 + j);
								oCellValue = new AscCommonExcel.CCellValue();
								oCellValue.number = pivotTable.getValue(cacheRecords, rowIndexes, dataFields[0].asc_getIndex(),
																		(null !== item.t && c_oAscItemType.Grand !== item.t) ? item.t :
																			dataFields[0].asc_getSubtotal());
								oCellValue.type = AscCommon.CellValueType.Number;
								cells.setValueData(new AscCommonExcel.UndoRedoData_CellValueData(null, oCellValue));
							}
						}
						if (last) {
							cacheValuesRow = [];
						}
					}
				}
			}
		}
	};
	Worksheet.prototype.updatePivotTablesStyle = function (range) {
		var t = this;
		var pivotTable, pivotRange, pivotFields, rowFields, styleInfo, style, wholeStyle, cells, j, r, x, pos,
			firstHeaderRow0, firstDataCol0, countC, countCWValues, countR, countD, stripe1, stripe2, items, l, item,
			start, end, isOutline, arrSubheading, emptyStripe = new Asc.CTableStyleElement();
		var dxf, dxfLabels, dxfValues, grandColumn, index;
		var checkRowSubheading = function (_i, _r, _v, _dxf) {
			var sub, bSet = true;
			if ((sub = arrSubheading[_i])) {
				if (sub.v === _v) {
					bSet = false;
				} else {
					cells = t.getRange3(sub.r, pivotRange.c1 + _i, _r - 1, pivotRange.c1 + _i);
					cells.setTableStyle(sub.dxf);
				}
			}
			if (bSet) {
				arrSubheading[_i] = (null === _v) ? null : {r: _r, dxf: _dxf, v: _v};
			}
		};
		var endRowSubheadings = function (_i, _r) {
			for (;_i < arrSubheading.length; ++_i) {
				checkRowSubheading(_i, _r, null, null);
			}
		};

		for (var i = 0; i < this.pivotTables.length; ++i) {
			grandColumn = 0;
			pivotTable = this.pivotTables[i];
			pivotRange = pivotTable.getRange();
			pivotFields = pivotTable.asc_getPivotFields();
			rowFields = pivotTable.asc_getRowFields();
			styleInfo = pivotTable.asc_getStyleInfo();
			if (!pivotTable.isInit || !styleInfo || (range && !pivotTable.intersection(range))) {
				continue;
			}
			style = this.workbook.TableStyles.AllStyles[styleInfo.asc_getName()];
			if (!style) {
				continue;
			}

			wholeStyle = style.wholeTable && style.wholeTable.dxf;

			// Page Field Labels, Page Field Values
			dxfLabels = style.pageFieldLabels && style.pageFieldLabels.dxf;
			dxfValues = style.pageFieldValues && style.pageFieldValues.dxf;
			for (j = 0; j < pivotTable.pageFieldsPositions.length; ++j) {
				pos = pivotTable.pageFieldsPositions[j];
				cells = this.getRange4(pos.row, pos.col);
				cells.clearTableStyle();
				cells.setTableStyle(wholeStyle);
				cells.setTableStyle(dxfLabels);
				cells = this.getRange4(pos.row, pos.col + 1);
				cells.clearTableStyle();
				cells.setTableStyle(wholeStyle);
				cells.setTableStyle(dxfValues);
			}

			cells = this.getRange3(pivotRange.r1, pivotRange.c1, pivotRange.r2, pivotRange.c2);
			cells.clearTableStyle();

			countC = pivotTable.getColumnFieldsCount();
			countR = pivotTable.getRowFieldsCount(true);

			if (0 === countC + countR) {
				continue;
			}

			firstHeaderRow0 = pivotTable.getFirstHeaderRow0();
			firstDataCol0 = pivotTable.getFirstDataCol();
			countD = pivotTable.getDataFieldsCount();
			countCWValues = pivotTable.getColumnFieldsCount(true);

			// Whole Table
			cells.setTableStyle(wholeStyle);

			// First Column Stripe, Second Column Stripe
			if (styleInfo.showColStripes) {
				stripe1 = style.firstColumnStripe || emptyStripe;
				stripe2 = style.secondColumnStripe || emptyStripe;
				start = pivotRange.c1 + firstDataCol0;
				if (stripe1.dxf) {
					cells = this.getRange3(pivotRange.r1 + firstHeaderRow0 + 1, start, pivotRange.r2, pivotRange.c2);
					cells.setTableStyle(stripe1.dxf, new Asc.CTableStyleStripe(stripe1.size, stripe2.size));
				}
				if (stripe2.dxf && start + stripe1.size <= pivotRange.c2) {
					cells = this.getRange3(pivotRange.r1 + firstHeaderRow0 + 1, start + stripe1.size, pivotRange.r2,
						pivotRange.c2);
					cells.setTableStyle(stripe2.dxf, new Asc.CTableStyleStripe(stripe2.size, stripe1.size));
				}
			}
			// First Row Stripe, Second Row Stripe
			if (styleInfo.showRowStripes && countR && (pivotRange.c1 + countR - 1 !== pivotRange.c2)) {
				stripe1 = style.firstRowStripe || emptyStripe;
				stripe2 = style.secondRowStripe || emptyStripe;
				start = pivotRange.r1 + firstHeaderRow0 + 1;
				if (stripe1.dxf) {
					cells = this.getRange3(start, pivotRange.c1, pivotRange.r2, pivotRange.c2);
					cells.setTableStyle(stripe1.dxf, new Asc.CTableStyleStripe(stripe1.size, stripe2.size, true));
				}
				if (stripe2.dxf && start + stripe1.size <= pivotRange.r2) {
					cells = this.getRange3(start + stripe1.size, pivotRange.c1, pivotRange.r2, pivotRange.c2);
					cells.setTableStyle(stripe1.dxf, new Asc.CTableStyleStripe(stripe2.size, stripe1.size, true));
				}
			}

			// First Column
			dxf = style.firstColumn && style.firstColumn.dxf;
			if (styleInfo.showRowHeaders && countR && dxf) {
				cells = this.getRange3(pivotRange.r1, pivotRange.c1, pivotRange.r2, pivotRange.c1 +
					Math.max(0, firstDataCol0 - 1));
				cells.setTableStyle(dxf);
			}

			// Header Row
			dxf = style.headerRow && style.headerRow.dxf;
			if (styleInfo.showColHeaders && dxf) {
				cells = this.getRange3(pivotRange.r1, pivotRange.c1, pivotRange.r1 + firstHeaderRow0, pivotRange.c2);
				cells.setTableStyle(dxf);
			}

			// First Header Cell
			dxf = style.firstHeaderCell && style.firstHeaderCell.dxf;
			if (styleInfo.showColHeaders && styleInfo.showRowHeaders && countCWValues && (countR + countD) && dxf) {
				cells = this.getRange3(pivotRange.r1, pivotRange.c1, pivotRange.r1 + firstHeaderRow0 - (countR ? 1 : 0),
					pivotRange.c1 + Math.max(0, firstDataCol0 - 1));
				cells.setTableStyle(dxf);
			}

			// Subtotal Column + Grand Total Column
			items = pivotTable.getColItems();
			if (items) {
				start = pivotRange.c1 + firstDataCol0;
				for (j = 0; j < items.length; ++j) {
					dxf = null;
					item = items[j];
					r = item.getR();
					if (AscCommonExcel.c_oAscItemType.Grand === item.t || 0 === countCWValues) {
						// Grand Total Column
						dxf = style.lastColumn;
						grandColumn = 1;
					} else {
						// Subtotal Column
						if (r + 1 !== countC) {
							if (countD && null !== item.t) {
								if (0 === r) {
									dxf = style.firstSubtotalColumn;
								} else if (1 === r % 2) {
									dxf = style.secondSubtotalColumn;
								} else {
									dxf = style.thirdSubtotalColumn;
								}
							}
						}
					}
					dxf = dxf && dxf.dxf;
					if (dxf) {
						cells = this.getRange3(pivotRange.r1 + 1, start + j, pivotRange.r2, start + j);
						cells.setTableStyle(dxf);
					}
				}
			}

			// Subtotal Row + Row Subheading + Grand Total Row
			items = pivotTable.getRowItems();
			if (items && countR) {
				arrSubheading = [];
				countR = pivotTable.getRowFieldsCount();
				start = pivotRange.r1 + firstHeaderRow0 + 1;
				for (j = 0; j < items.length; ++j) {
					dxf = null;
					item = items[j];
					if (null !== item.t) {
						if (AscCommonExcel.c_oAscItemType.Grand === item.t) {
							// Grand Total Row
							dxf = style.totalRow;
							pos = 0;
						} else if (AscCommonExcel.c_oAscItemType.Blank === item.t) {
							// Blank Row
							dxf = style.blankRow;
							pos = 0;
						} else if (styleInfo.showRowHeaders) {
							// Subtotal Row
							r = item.getR();
							if (r + 1 !== countR) {
								if (0 === r) {
									dxf = style.firstSubtotalRow;
								} else if (1 === r % 2) {
									dxf = style.secondSubtotalRow;
								} else {
									dxf = style.thirdSubtotalRow;
								}
								pos = pivotTable.getRowFieldPos(r);
							}
						}
						dxf = dxf && dxf.dxf;
						if (dxf) {
							cells = this.getRange3(start + j, pivotRange.c1 + pos, start + j, pivotRange.c2);
							cells.setTableStyle(dxf);
						}
						endRowSubheadings(pos, start + j);
					} else if (styleInfo.showRowHeaders) {
						// Row Subheading
						r = item.getR();
						index = rowFields[r].asc_getIndex();
						isOutline = (AscCommonExcel.st_VALUES !== index && false !== pivotFields[index].outline);
						for (x = 0, l = item.x.length; x < l; ++x, ++r) {
							dxf = null;
							if (r + 1 !== countR) {
								if (0 === r) {
									dxf = style.firstRowSubheading;
								} else if (1 === r % 2) {
									dxf = style.secondRowSubheading;
								} else {
									dxf = style.thirdRowSubheading;
								}
								dxf = dxf && dxf.dxf;
								if (dxf) {
									pos = pivotTable.getRowFieldPos(r);
									if (1 === l && isOutline) {
										endRowSubheadings(pos, start + j);
										cells = this.getRange3(start + j, pivotRange.c1 + pos, start + j, pivotRange.c2);
										cells.setTableStyle(dxf);
									} else {
										checkRowSubheading(pos, start + j, item.x[x].getV(), dxf);
									}
								}
							}
						}
					}
				}
				endRowSubheadings(0, pivotRange.r2 + 1);
			}

			// Column Subheading
			items = pivotTable.getColItems();
			if (items && styleInfo.showColHeaders) {
				start = pivotRange.c1 + firstDataCol0;
				end = pivotRange.c2 - grandColumn;
				for (j = 0; j < countCWValues; ++j) {
					if (0 === j) {
						dxf = style.firstColumnSubheading;
					} else if (1 === j % 2) {
						dxf = style.secondColumnSubheading;
					} else {
						dxf = style.thirdColumnSubheading;
					}
					dxf = dxf && dxf.dxf;
					if (dxf) {
						cells = this.getRange3(pivotRange.r1 + 1 + j, start, pivotRange.r1 + 1 + j, end);
						cells.setTableStyle(dxf);
					}
				}
				pos = pivotRange.r1 + 1 + firstHeaderRow0 - (countR ? 1 : 0);
				for (j = 0; j < items.length; ++j) {
					item = items[j];
					if (null !== item.t && AscCommonExcel.c_oAscItemType.Grand !== item.t) {
						r = item.getR();
						if (0 === r) {
							dxf = style.firstColumnSubheading;
						} else if (1 === r % 2) {
							dxf = style.secondColumnSubheading;
						} else {
							dxf = style.thirdColumnSubheading;
						}
						dxf = dxf && dxf.dxf;
						if (dxf) {
							cells =
								this.getRange3(pivotRange.r1 + 1 + r, start + j, pos, start + j);
							cells.setTableStyle(dxf);
						}
					}
				}
			}
		}
	};
	Worksheet.prototype.updatePivotOffset = function (range, offset) {
		var pivotTable, pivotRange, cells;
		for (var i = 0; i < this.pivotTables.length; ++i) {
			pivotTable = this.pivotTables[i];
			pivotRange = pivotTable.getRange();

			if ((offset.col && range.c1 <= pivotRange.c2) || (offset.row && range.r1 <= pivotRange.r2)) {
				cells = this.getRange3(pivotRange.r1, pivotRange.c1, pivotRange.r2, pivotRange.c2);
				cells.clearTableStyle();
				pivotRange.setOffset(offset);
				pivotTable.init();
				this.updatePivotTablesStyle(pivotRange);
			}
		}
	};
	Worksheet.prototype.inPivotTable = function (range) {
		return this.pivotTables.some(function (element) {
			return element.intersection(range);
		});
	};
	Worksheet.prototype.checkShiftPivotTable = function (range, offset) {
		return this.pivotTables.some(function (element) {
			return AscCommonExcel.c_oAscShiftType.Change === element.isIntersectForShift(range, offset);
		});
	};
	Worksheet.prototype.checkDeletePivotTables = function (range) {
		for (var i = 0; i < this.pivotTables.length; ++i) {
			if (this.pivotTables[i].intersection(range) && !this.pivotTables[i].getAllRange(this).inContains(range)) {
				return false;
			}
		}
		return true;
	};
	Worksheet.prototype.deletePivotTable = function (id) {
		for (var i = 0; i < this.pivotTables.length; ++i) {
			if (id === this.pivotTables[i].Get_Id()) {
				this.clearPivotTable(this.pivotTables[i]);
				this.pivotTables.splice(i, 1);
				break;
			}
		}
	};
	Worksheet.prototype.deletePivotTables = function (range) {
		for (var i = 0; i < this.pivotTables.length; ++i) {
			if (this.pivotTables[i].intersection(range)) {
				this.clearPivotTable(this.pivotTables[i]);
				History.Add(new AscDFH.CChangesPivotTableDefinitionDelete(this.pivotTables[i]));
				this.pivotTables.splice(i--, 1);
			}
		}
		return true;
	};
	Worksheet.prototype.getPivotTable = function (col, row) {
		var res = null;
		for (var i = 0; i < this.pivotTables.length; ++i) {
			if (this.pivotTables[i].contains(col, row)) {
				res = this.pivotTables[i];
				break;
			}
		}
		return res;
	};
	Worksheet.prototype.getPivotTableByName = function (name) {
		var res = null;
		for (var i = 0; i < this.pivotTables.length; ++i) {
			if (this.pivotTables[i].asc_getName() === name) {
				res = this.pivotTables[i];
				break;
			}
		}
		return res;
	};
	Worksheet.prototype.insertPivotTable = function (pivotTable) {
		pivotTable.worksheet = this;
		this.pivotTables.push(pivotTable);
	};
	Worksheet.prototype.getPivotTableButtons = function (range) {
		var res = [];
		var pivotTable, pivotRange, j, pos, countC, countCWValues, countR, cell;
		for (var i = 0; i < this.pivotTables.length; ++i) {
			pivotTable = this.pivotTables[i];
			if (!pivotTable.intersection(range)) {
				continue;
			}

			for (j = 0; j < pivotTable.pageFieldsPositions.length; ++j) {
				pos = pivotTable.pageFieldsPositions[j];
				cell = new AscCommon.CellBase(pos.row, pos.col + 1);
				if (range.contains2(cell)) {
					res.push(cell);
				}
			}

			if (false !== pivotTable.showHeaders) {
				countC = pivotTable.getColumnFieldsCount();
				countCWValues = pivotTable.getColumnFieldsCount(true);
				countR = pivotTable.getRowFieldsCount(true);
				pivotRange = pivotTable.getRange();

				if (countR) {
					countR = pivotTable.hasCompact() ? 1 : countR;
					pos = pivotRange.r1 + pivotTable.getFirstHeaderRow0();
					for (j = 0; j < countR; ++j) {
						cell = new AscCommon.CellBase(pos, pivotRange.c1 + j);
						if (range.contains2(cell)) {
							res.push(cell);
						}
					}
				}
				if (countCWValues) {
					countC = pivotTable.hasCompact() ? 1 : countC;
					pos = pivotRange.c1 + pivotTable.getFirstDataCol();
					for (j = 0; j < countC; ++j) {
						cell = new AscCommon.CellBase(pivotRange.r1, pos + j);
						if (range.contains2(cell)) {
							res.push(cell);
						}
					}
				}
			}
		}
		return res;
	};
	Worksheet.prototype.getPivotTablesClearRanges = function (range) {
		// For outline and compact pivot tables layout we need clear the grid
		var pivotTable, pivotRange, intersection, res = [];
		for (var i = 0; i < this.pivotTables.length; ++i) {
			pivotTable = this.pivotTables[i];
			if (pivotTable.clearGrid) {
				pivotRange = pivotTable.getRange();
				if (intersection = pivotRange.intersectionSimple(range)) {
					res.push(intersection);
					res.push(pivotRange);
				}
			}
		}
		return res;
	};
	// ----- Search -----
	Worksheet.prototype.clearFindResults = function () {
		this.lastFindOptions = null;
	};
	Worksheet.prototype._findAllCells = function (options) {
		if (true !== options.isMatchCase) {
			options.findWhat = options.findWhat.toLowerCase();
		}
		var selectionRange = options.selectionRange || this.selectionRange;
		var lastRange = selectionRange.getLast();
		var activeCell = selectionRange.activeCell;
		var merge = this.getMergedByCell(activeCell.row, activeCell.col);
		options.findInSelection = options.scanOnOnlySheet &&
			!(selectionRange.isSingleRange() && (lastRange.isOneCell() || lastRange.isEqual(merge)));
		var findRange = options.findInSelection ? this.getRange3(lastRange.r1, lastRange.c1, lastRange.r2, lastRange.c2) :
			this.getRange3(0, 0, this.getRowsCount(), this.getColsCount());

		if (this.lastFindOptions && this.lastFindOptions.findResults && options.isEqual2(this.lastFindOptions) &&
			findRange.getBBox0().isEqual(this.lastFindOptions.findRange)) {
			return;
		}

		var oldResults = this.lastFindOptions && this.lastFindOptions.findResults.isNotEmpty();
		var result = new AscCommonExcel.findResults(), tmp;
		findRange._foreachNoEmpty(function (cell, r, c) {
			if (!cell.isNullText() && cell.isEqual(options)) {
				if (!options.scanByRows) {
					tmp = r;
					r = c;
					c = tmp;
				}
				result.add(r, c, cell);
			}
		});
		this.lastFindOptions = options.clone();
		// ToDo support multiselect
		this.lastFindOptions.findRange = findRange.getBBox0().clone();
		this.lastFindOptions.findResults = result;

		if (this.workbook.oApi.selectSearchingResults && (oldResults || result.isNotEmpty()) &&
			this === this.workbook.getActiveWs()) {
			this.workbook.handlers.trigger("drawWS");
		}
	};
	Worksheet.prototype.findCellText = function (options) {
		this._findAllCells(options);

		var selectionRange = options.selectionRange || this.selectionRange;
		var activeCell = selectionRange.activeCell;

		var tmp, key1 = activeCell.row, key2 = activeCell.col;
		if (!options.scanByRows) {
			tmp = key1;
			key1 = key2;
			key2 = tmp;
		}

		var result = null;
		var findResults = this.lastFindOptions.findResults;
		if (findResults.find(key1, key2, options.scanForward)) {
			key1 = findResults.currentKey1;
			key2 = findResults.currentKey2;
			if (!options.scanByRows) {
				tmp = key1;
				key1 = key2;
				key2 = tmp;
			}
			result = new AscCommon.CellBase(key1, key2);
		}
		return result;
	};
	Worksheet.prototype.inFindResults = function (row, col) {
		var tmp, res = false;
		var findResults = this.lastFindOptions && this.lastFindOptions.findResults;
		if (findResults) {
			if (!this.lastFindOptions.scanByRows) {
				tmp = col;
				col = row;
				row = tmp;
			}
			res = findResults.contains(row, col);
		}
		return res;
	};
	Worksheet.prototype.excludeHiddenRows = function (bExclude) {
		this.bExcludeHiddenRows = bExclude;
	};
//-------------------------------------------------------------------------------------------------
	var g_nCellOffsetFlag = 0;
	var g_nCellOffsetXf = g_nCellOffsetFlag + 1;
	var g_nCellOffsetFormula = g_nCellOffsetXf + 4;
	var g_nCellOffsetValue = g_nCellOffsetFormula + 4;
	var g_nCellStructSize = g_nCellOffsetValue + 8;

	var g_nCellFlag_empty = 0;
	var g_nCellFlag_init = 1;
	var g_nCellFlag_typeMask = 6;
	var g_nCellFlag_valueMask = 24;
	var g_nCellFlag_isDirtyMask = 32;
	var g_nCellFlag_isCalcMask = 64;
	/**
	 * @constructor
	 */
	function Cell(worksheet){
		this.ws = worksheet;
		this.nRow = -1;
		this.nCol = -1;
		this.xfs = null;
		this.formulaParsed = null;

		this.type = CellValueType.Number;
		this.number = null;
		this.text = null;
		this.multiText = null;
		this.textIndex = null;

		this.isDirty = false;
		this.isCalc = false;

		this._hasChanged = false;
	}
	Cell.prototype.clear = function(keepIndex) {
			this.nRow = -1;
			this.nCol = -1;
		this.clearData();

		this._hasChanged = false;
	};
	Cell.prototype.clearData = function() {
		this.xfs = null;
		this.formulaParsed = null;

		this.type = CellValueType.Number;
		this.number = null;
		this.text = null;
		this.multiText = null;
		this.textIndex = null;

		this.isDirty = false;
		this.isCalc = false;

		this._hasChanged = true;
	};
	Cell.prototype.clearDataKeepXf = function(border) {
		var xfs = this.xfs;
		this.clearData();
		this.xfs = xfs;
		History.TurnOff();
		this.setBorder(border);
		History.TurnOn();
	};
	Cell.prototype.saveContent = function(opt_inCaseOfChange) {
		if (this.hasRowCol() && (!opt_inCaseOfChange || this._hasChanged)) {
			this._hasChanged = false;
			var wb = this.ws.workbook;
			var sheetMemory = this.ws.getColData(this.nCol);
			sheetMemory.checkSize(this.nRow);
			var xfSave = this.xfs ? this.xfs.getIndexNumber() : 0;
			var numberSave = 0;
			var formulaSave = this.formulaParsed ? wb.workbookFormulas.add(this.formulaParsed).getIndexNumber() :  0;
			var flagValue = 0;
			if (null != this.number) {
				flagValue = 1;
				sheetMemory.setFloat64(this.nRow, g_nCellOffsetValue, this.number);
			} else if (null != this.text) {
				flagValue = 2;
				numberSave = this.getTextIndex();
				sheetMemory.setUint32(this.nRow, g_nCellOffsetValue, numberSave);
			} else if (null != this.multiText) {
				flagValue = 3;
				numberSave = this.getTextIndex();
				sheetMemory.setUint32(this.nRow, g_nCellOffsetValue, numberSave);
			}
			sheetMemory.setUint8(this.nRow, g_nCellOffsetFlag, this._toFlags(flagValue));
			sheetMemory.setUint32(this.nRow, g_nCellOffsetXf, xfSave);
			sheetMemory.setUint32(this.nRow, g_nCellOffsetFormula, formulaSave);
		}
	};
	Cell.prototype.loadContent = function(row, col, opt_sheetMemory) {
		var res = false;
		this.clear();
		this.nRow = row;
		this.nCol = col;
		var sheetMemory = opt_sheetMemory ? opt_sheetMemory : this.ws.getColDataNoEmpty(this.nCol);
		if (sheetMemory) {
			if (sheetMemory.hasSize(this.nRow)) {
				var flags = sheetMemory.getUint8(this.nRow, g_nCellOffsetFlag);
				if (0 != (g_nCellFlag_init & flags)) {
					var wb = this.ws.workbook;
					var flagValue = this._fromFlags(flags);
					this.xfs = g_StyleCache.getXf(sheetMemory.getUint32(this.nRow, g_nCellOffsetXf));
					this.formulaParsed = wb.workbookFormulas.get(sheetMemory.getUint32(this.nRow, g_nCellOffsetFormula));
					if (1 === flagValue) {
						this.number = sheetMemory.getFloat64(this.nRow, g_nCellOffsetValue);
					} else if (2 === flagValue) {
						this.textIndex = sheetMemory.getUint32(this.nRow, g_nCellOffsetValue);
						this.text = wb.sharedStrings.get(this.textIndex);
					} else if (3 === flagValue) {
						this.textIndex = sheetMemory.getUint32(this.nRow, g_nCellOffsetValue);
						this.multiText = wb.sharedStrings.get(this.textIndex);
					}
					res = true;
				}
			}
		}
		return res;
	};
	Cell.prototype._toFlags = function(flagValue) {
		var flags = g_nCellFlag_init | (this.type << 1) | (flagValue << 3);
		if(this.isDirty){
			flags |= g_nCellFlag_isDirtyMask;
		}
		if(this.isCalc){
			flags |= g_nCellFlag_isCalcMask;
		}
		return flags;
	};
	Cell.prototype._fromFlags = function(flags) {
		this.type = (flags & g_nCellFlag_typeMask) >>> 1;
		this.isDirty = 0 != (flags & g_nCellFlag_isDirtyMask);
		this.isCalc = 0 != (flags & g_nCellFlag_isCalcMask);
		return (flags & g_nCellFlag_valueMask) >>> 3;
	};
	Cell.prototype.processFormula = function(callback) {
		if (this.formulaParsed) {
			var shared = this.formulaParsed.getShared();
			var offsetRow, offsetCol;
			if (shared) {
				offsetRow = this.nRow - shared.base.nRow;
				offsetCol = this.nCol - shared.base.nCol;
				if (0 !== offsetRow || 0 !== offsetCol) {
					var oldRow = this.formulaParsed.parent.nRow;
					var oldCol = this.formulaParsed.parent.nCol;

					//todo assemble by param
					var old = AscCommonExcel.g_ProcessShared;
					AscCommonExcel.g_ProcessShared = true;
					var offsetShared = new AscCommon.CellBase(offsetRow, offsetCol);
					this.formulaParsed.changeOffset(offsetShared, false);
					this.formulaParsed.parent.nRow = this.nRow;
					this.formulaParsed.parent.nCol = this.nCol;
					callback(this.formulaParsed);
					offsetShared.row = -offsetRow;
					offsetShared.col = -offsetCol;
					this.formulaParsed.changeOffset(offsetShared, false);
					this.formulaParsed.parent.nRow = oldRow;
					this.formulaParsed.parent.nCol = oldCol;
					AscCommonExcel.g_ProcessShared = old;
				} else {
					callback(this.formulaParsed);
				}
			} else {
				callback(this.formulaParsed);
			}
		}
	};
	Cell.prototype.setChanged = function(val) {
		this._hasChanged = val;
	};
	Cell.prototype.getStyle=function(){
		return this.xfs;
	};
	Cell.prototype.getCompiledStyle = function (opt_styleComponents) {
		return this.ws.getCompiledStyle(this.nRow, this.nCol, this, opt_styleComponents);
	};
	Cell.prototype.getTableStyle = function () {
		var hiddenManager = this.ws.hiddenManager;
		var sheetMergedStyles = this.ws.sheetMergedStyles;
		var styleComponents = sheetMergedStyles.getStyle(hiddenManager, this.nRow, this.nCol, this.ws);
		return getCompiledStyleFromArray(null, styleComponents.table);
	};
	Cell.prototype.duplicate=function(){
		var t = this;
		var oNewCell = new Cell(this.ws);
		oNewCell.nRow = this.nRow;
		oNewCell.nCol = this.nCol;
		oNewCell.xfs = this.xfs;
		oNewCell.type = this.type;
		oNewCell.number = this.number;
		oNewCell.text = this.text;
		oNewCell.multiText = this.multiText;
		this.processFormula(function(parsed) {
			//todo without parse
			var newFormula = new parserFormula(parsed.getFormula(), oNewCell, t.ws);
			AscCommonExcel.executeInR1C1Mode(false, function () {
				newFormula.parse();
			});
			oNewCell.setFormulaInternal(newFormula);
		});
		return oNewCell;
	};
	Cell.prototype.clone=function(oNewWs, renameParams){
		if(!oNewWs)
			oNewWs = this.ws;
		var oNewCell = new Cell(oNewWs);
		oNewCell.nRow = this.nRow;
		oNewCell.nCol = this.nCol;
		if(null != this.xfs)
			oNewCell.xfs = this.xfs;
		oNewCell.type = this.type;
		oNewCell.number = this.number;
		oNewCell.text = this.text;
		oNewCell.multiText = this.multiText;
		this.processFormula(function(parsed) {
			var newFormula;
			if (oNewWs != this.ws && renameParams) {
				var formula = parsed.clone(null, null, this.ws);
				formula.renameSheetCopy(renameParams);
				newFormula = formula.assemble(true);
			} else {
				newFormula = parsed.getFormula();
			}
			oNewCell.setFormulaInternal(new parserFormula(newFormula, oNewCell, oNewWs));
			oNewWs.workbook.dependencyFormulas.addToBuildDependencyCell(oNewCell);
		});
		return oNewCell;
	};
	Cell.prototype.setRowCol=function(nRow, nCol){
		this.nRow = nRow;
		this.nCol = nCol;
	};
	Cell.prototype.hasRowCol = function() {
		return this.nRow >= 0 && this.nCol >= 0;
	};
	Cell.prototype.isEqual = function (options) {
		var cellText;
		cellText = (options.lookIn === Asc.c_oAscFindLookIn.Formulas) ? this.getValueForEdit() : this.getValue();
		if (true !== options.isMatchCase) {
			cellText = cellText.toLowerCase();
		}
		return (0 <= cellText.indexOf(options.findWhat)) &&
			(true !== options.isWholeCell || options.findWhat.length === cellText.length);
	};
	Cell.prototype.isNullText=function(){
		return this.isNullTextString() && !this.formulaParsed;
	};
	Cell.prototype.isEmptyTextString = function() {
		this._checkDirty();
		if(null != this.number || (null != this.text && "" != this.text))
			return false;
		if(null != this.multiText && "" != AscCommonExcel.getStringFromMultiText(this.multiText))
			return false;
		return true;
	};
	Cell.prototype.isNullTextString = function() {
		this._checkDirty();
		return null === this.number && null === this.text && null === this.multiText;
	};
	Cell.prototype.isEmpty=function(){
		if(false == this.isNullText())
			return false;
		if(null != this.xfs)
			return false;
		return true;
	};
	Cell.prototype.isFormula=function(){
		return this.formulaParsed ? true : false;
	};
	Cell.prototype.getName=function(){
		return g_oCellAddressUtils.getCellId(this.nRow, this.nCol);
	};
	Cell.prototype.setTypeInternal=function(val) {
		this.type = val;
		this._hasChanged = true;
	};
	Cell.prototype.correctValueByType = function() {
		//todo implemented only Number->String. other is stub
		switch (this.type) {
			case CellValueType.Number:
				if (null !== this.text) {
					this.setValueNumberInternal(parseInt(this.text) || 0);
				} else if (null !== this.multiText) {
					this.setValueNumberInternal(0);
				}
				break;
			case CellValueType.Bool:
				if (null !== this.text || null !== this.multiText) {
					this.setValueNumberInternal(0);
				}
				break;
			case CellValueType.String:
				if (null !== this.number) {
					this.setValueTextInternal(this.number.toString());
				}
				break;
			case CellValueType.Error:
				if (null !== this.number) {
					this.setValueTextInternal(cErrorOrigin["nil"]);
				}
				break;
		}
	};
	Cell.prototype.setValueNumberInternal=function(val) {
		this.number = val;
		this.text = null;
		this.multiText = null;
		this.textIndex = null;
		this._hasChanged = true;
	};
	Cell.prototype.setValueTextInternal=function(val) {
		this.number = null;
		this.text = val;
		this.multiText = null;
		this.textIndex = null;
		this._hasChanged = true;
	};
	Cell.prototype.setValueMultiTextInternal=function(val) {
		this.number = null;
		this.text = null;
		this.multiText = val;
		this.textIndex = null;
		this._hasChanged = true;
	};
	Cell.prototype.setValue=function(val,callback, isCopyPaste) {
		var ws = this.ws;
		var wb = ws.workbook;
		var DataOld = null;
		if (History.Is_On()) {
			DataOld = this.getValueData();
		}
		var bIsTextFormat = false;
		if (!isCopyPaste) {
			var sNumFormat;
			if (null != this.xfs && null != this.xfs.num) {
				sNumFormat = this.xfs.num.getFormat();
			} else {
				sNumFormat = g_oDefaultFormat.Num.getFormat();
			}
			var numFormat = oNumFormatCache.get(sNumFormat);
			bIsTextFormat = numFormat.isTextFormat();
		}

		var newFP = null;
		if (false == bIsTextFormat) {
			/*
			 Устанавливаем значение в Range ячеек. При этом происходит проверка значения на формулу.
			 Если значение является формулой, то проверяем содержиться ли в ячейке формула или нет, если "да" - то очищаем в графе зависимостей список, от которых зависит формула(masterNodes), позже будет построен новый. Затем выставляем флаг о необходимости дальнейшего пересчета, и заносим ячейку в список пересчитываемых ячеек.
			 */
			if (null != val && val[0] == "=" && val.length > 1) {
				var cellWithFormula = new CCellWithFormula(this.ws, this.nRow, this.nCol);
				newFP = new parserFormula(val.substring(1), cellWithFormula, this.ws);

				var formulaLocaleParse = isCopyPaste === true ? false : oFormulaLocaleInfo.Parse;
				var formulaLocaleDigetSep = isCopyPaste === true ? false : oFormulaLocaleInfo.DigitSep;
				var parseResult = new AscCommonExcel.ParseResult();
				if (!newFP.parse(formulaLocaleParse, formulaLocaleDigetSep, parseResult)) {
					switch (parseResult.error) {
						case c_oAscError.ID.FrmlWrongFunctionName:
							break;
						case c_oAscError.ID.FrmlParenthesesCorrectCount:
							this.setValue("=" + newFP.getFormula(), callback, isCopyPaste);
							return;
						default :
						{
							wb.handlers.trigger("asc_onError", parseResult.error, c_oAscError.Level.NoCritical);
							if (callback) {
								callback(false);
							}
							return;
						}
					}
				} else {
					newFP.setFormulaString(newFP.assemble());
				}
			}
		}
		//удаляем старые значения
		this.cleanText();
		this.setFormulaInternal(null);

		if (newFP) {
			this.setFormulaInternal(newFP);
			wb.dependencyFormulas.addToBuildDependencyCell(this);
		} else if (val) {
			this._setValue(val);
			wb.dependencyFormulas.addToChangedCell(this);
		} else {
			wb.dependencyFormulas.addToChangedCell(this);
		}

		var DataNew = null;
		if (History.Is_On()) {
			DataNew = this.getValueData();
		}
		if (History.Is_On() && false == DataOld.isEqual(DataNew)) {
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_ChangeValue, this.ws.getId(),
						new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow),
						new UndoRedoData_CellSimpleData(this.nRow, this.nCol, DataOld, DataNew));
		}
		//sortDependency вызывается ниже History.Add(AscCH.historyitem_Cell_ChangeValue, потому что в ней может быть выставлен формат ячейки(если это текстовый, то принимая изменения формула станет текстом)
		this.ws.workbook.sortDependency();
		if (!this.ws.workbook.dependencyFormulas.isLockRecal()) {
			this._adjustCellFormat();
		}

		//todo не должны удаляться ссылки, если сделать merge ее части.
		if (this.isNullTextString()) {
			var cell = this.ws.getCell3(this.nRow, this.nCol);
			cell.removeHyperlink();
		}
	};
	Cell.prototype.setValue2=function(array){
		var DataOld = null;
		if(History.Is_On())
			DataOld = this.getValueData();
		//[{text:"",format:TextFormat},{}...]
		this.setFormulaInternal(null);
		this.cleanText();
		this._setValue2(array);
		this.ws.workbook.dependencyFormulas.addToChangedCell(this);
		this.ws.workbook.sortDependency();
		var DataNew = null;
		if(History.Is_On())
			DataNew = this.getValueData();
		if(History.Is_On() && false == DataOld.isEqual(DataNew))
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_ChangeValue, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, DataOld, DataNew));
		//todo не должны удаляться ссылки, если сделать merge ее части.
		if(this.isNullTextString())
		{
			var cell = this.ws.getCell3(this.nRow, this.nCol);
			cell.removeHyperlink();
		}
	};
	Cell.prototype.setFormulaTemplate = function(bHistoryUndo, action) {
		var DataOld = null;
		var DataNew = null;
		if (History.Is_On())
			DataOld = this.getValueData();

		this.cleanText();
		action(this);

		if (History.Is_On()) {
			DataNew = this.getValueData();
			if (false == DataOld.isEqual(DataNew)){
				var typeHistory = bHistoryUndo ? AscCH.historyitem_Cell_ChangeValueUndo : AscCH.historyitem_Cell_ChangeValue;
				History.Add(AscCommonExcel.g_oUndoRedoCell, typeHistory, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, DataOld, DataNew), bHistoryUndo);}
		}
	};
	Cell.prototype.setFormula = function(formula, bHistoryUndo) {
		var cellWithFormula = new CCellWithFormula(this.ws, this.nRow, this.nCol);
		this.setFormulaParsed(new parserFormula(formula, cellWithFormula, this.ws), bHistoryUndo);
	};
	Cell.prototype.setFormulaParsed = function(parsed, bHistoryUndo) {
		this.setFormulaTemplate(bHistoryUndo, function(cell){
			cell.setFormulaInternal(parsed);
			cell.ws.workbook.dependencyFormulas.addToBuildDependencyCell(cell);
		});
	};
	Cell.prototype.setFormulaInternal = function(formula, dontTouchPrev) {
		if (!dontTouchPrev && this.formulaParsed) {
			var shared = this.formulaParsed.getShared();
			if (shared) {
				if (shared.ref.isOnTheEdge(this.nCol, this.nRow)) {
					this.ws.workbook.dependencyFormulas.addToChangedShared(this.formulaParsed);
				}
				var index = this.ws.workbook.workbookFormulas.add(this.formulaParsed).getIndexNumber();
				History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_RemoveSharedFormula, this.ws.getId(),
					new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, index, null), true);
			} else {
				this.formulaParsed.removeDependencies();
			}
		}
		this.formulaParsed = formula;
		this._hasChanged = true;
	};
	Cell.prototype.transformSharedFormula = function() {
		var res = false;
		var parsed = this.formulaParsed;
		if (parsed) {
			var shared = parsed.getShared();
			if (shared) {
				var offsetShared = new AscCommon.CellBase(this.nRow - shared.base.nRow, this.nCol - shared.base.nCol);
				var cellWithFormula = new AscCommonExcel.CCellWithFormula(this.ws, this.nRow, this.nCol);
				var newFormula = parsed.clone(undefined, cellWithFormula);
				newFormula.removeShared();
				newFormula.changeOffset(offsetShared, false);
				newFormula.setFormulaString(newFormula.assemble(true));
				this.setFormulaInternal(newFormula);
				res = true;
			}
		}
		return res;
	};
	Cell.prototype.changeOffset = function(offset, canResize, bHistoryUndo) {
		this.setFormulaTemplate(bHistoryUndo, function(cell){
			cell.transformSharedFormula();
			var parsed = cell.getFormulaParsed();
			parsed.removeDependencies();
			parsed.changeOffset(offset, canResize);
			parsed.setFormulaString(parsed.assemble(true));
			parsed.buildDependencies();
		});
	};
	Cell.prototype.setType=function(type){
		if(type != this.type){
			var DataOld = this.getValueData();
			this.setTypeInternal(type);
			this.correctValueByType();
			this._hasChanged = true;
			var DataNew = this.getValueData();
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_ChangeValue, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, DataOld, DataNew));
		}
		return type;
	};
	Cell.prototype.getType=function(){
		this._checkDirty();
		return this.type;
	};
	Cell.prototype.setCellStyle=function(val){
		var newVal = this.ws.workbook.CellStyles._prepareCellStyle(val);
		var oRes = this.ws.workbook.oStyleManager.setCellStyle(this, newVal);
		if(History.Is_On()) {
			var oldStyleName = this.ws.workbook.CellStyles.getStyleNameByXfId(oRes.oldVal);
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_Style, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oldStyleName, val));

			// Выставляем стиль
			var oStyle = this.ws.workbook.CellStyles.getStyleByXfId(oRes.newVal);
			if (oStyle.ApplyFont)
				this.setFont(oStyle.getFont());
			if (oStyle.ApplyFill)
				this.setFill(oStyle.getFill());
			if (oStyle.ApplyBorder)
				this.setBorder(oStyle.getBorder());
			if (oStyle.ApplyNumberFormat)
				this.setNumFormat(oStyle.getNumFormatStr());
		}
	};
	Cell.prototype.setNumFormat=function(val){
		this.setNum(new AscCommonExcel.Num({f:val}));
	};
	Cell.prototype.setNum=function(val){
		var oRes = this.ws.workbook.oStyleManager.setNum(this, val);
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_Num, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.shiftNumFormat=function(nShift, dDigitsCount){
		var bRes = false;
		var sNumFormat;
		if(null != this.xfs && null != this.xfs.num)
			sNumFormat = this.xfs.num.getFormat();
		else
			sNumFormat = g_oDefaultFormat.Num.getFormat();
		var type = this.getType();
		var oCurNumFormat = oNumFormatCache.get(sNumFormat);
		if (null != oCurNumFormat && false == oCurNumFormat.isGeneralFormat()) {
			var output = {};
			bRes = oCurNumFormat.shiftFormat(output, nShift);
			if (true == bRes) {
				this.setNumFormat(output.format);
			}
		} else if (CellValueType.Number == type) {
			var sGeneral = AscCommon.DecodeGeneralFormat(this.number, type, dDigitsCount);
			var oGeneral = oNumFormatCache.get(sGeneral);
			if (null != oGeneral && false == oGeneral.isGeneralFormat()) {
				var output = {};
				bRes = oGeneral.shiftFormat(output, nShift);
				if (true == bRes) {
					this.setNumFormat(output.format);
				}
			}
		}
		return bRes;
	};
	Cell.prototype.setFont=function(val, bModifyValue){
		if(false != bModifyValue)
		{
			//убираем комплексные строки
			if(null != this.multiText && false == this.ws.workbook.bUndoChanges && false == this.ws.workbook.bRedoChanges)
			{
				var oldVal = null;
				if(History.Is_On())
					oldVal = this.getValueData();
				this.setValueTextInternal(AscCommonExcel.getStringFromMultiText(this.multiText));
				if(History.Is_On())
				{
					var newVal = this.getValueData();
					History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_ChangeValue, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oldVal, newVal));
				}
			}
		}
		var oRes = this.ws.workbook.oStyleManager.setFont(this, val);
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
		{
			var oldVal = null;
			if(null != oRes.oldVal)
				oldVal = oRes.oldVal.clone();
			var newVal = null;
			if(null != oRes.newVal)
				newVal = oRes.newVal.clone();
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_SetFont, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oldVal, newVal));
		}
	};
	Cell.prototype.setFontname=function(val){
		var oRes = this.ws.workbook.oStyleManager.setFontname(this, val);
		this._setFontProp(function(format){return val != format.getName();}, function(format){format.setName(val);});
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_Fontname, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setFontsize=function(val){
		var oRes = this.ws.workbook.oStyleManager.setFontsize(this, val);
		this._setFontProp(function(format){return val != format.getSize();}, function(format){format.setSize(val);});
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_Fontsize, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setFontcolor=function(val){
		var oRes = this.ws.workbook.oStyleManager.setFontcolor(this, val);
		this._setFontProp(function(format){return val != format.getColor();}, function(format){format.setColor(val);});
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_Fontcolor, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setBold=function(val){
		var oRes = this.ws.workbook.oStyleManager.setBold(this, val);
		this._setFontProp(function(format){return val != format.getBold();}, function(format){format.setBold(val);});
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_Bold, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setItalic=function(val){
		var oRes = this.ws.workbook.oStyleManager.setItalic(this, val);
		this._setFontProp(function(format){return val != format.getItalic();}, function(format){format.setItalic(val);});
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_Italic, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setUnderline=function(val){
		var oRes = this.ws.workbook.oStyleManager.setUnderline(this, val);
		this._setFontProp(function(format){return val != format.getUnderline();}, function(format){format.setUnderline(val);});
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_Underline, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setStrikeout=function(val){
		var oRes = this.ws.workbook.oStyleManager.setStrikeout(this, val);
		this._setFontProp(function(format){return val != format.getStrikeout();}, function(format){format.setStrikeout(val);});
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_Strikeout, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setFontAlign=function(val){
		var oRes = this.ws.workbook.oStyleManager.setFontAlign(this, val);
		this._setFontProp(function(format){return val != format.getVerticalAlign();}, function(format){format.setVerticalAlign(val);});
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_FontAlign, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setAlignVertical=function(val){
		var oRes = this.ws.workbook.oStyleManager.setAlignVertical(this, val);
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_AlignVertical, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setAlignHorizontal=function(val){
		var oRes = this.ws.workbook.oStyleManager.setAlignHorizontal(this, val);
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_AlignHorizontal, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setFill=function(val){
		var oRes = this.ws.workbook.oStyleManager.setFill(this, val);
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_Fill, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setBorder=function(val){
		var oRes = this.ws.workbook.oStyleManager.setBorder(this, val);
		if(History.Is_On() && oRes.oldVal != oRes.newVal){
			var oldVal = null;
			if(null != oRes.oldVal)
				oldVal = oRes.oldVal.clone();
			var newVal = null;
			if(null != oRes.newVal)
				newVal = oRes.newVal.clone();
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_Border, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oldVal, newVal));
		}
	};
	Cell.prototype.setShrinkToFit=function(val){
		var oRes = this.ws.workbook.oStyleManager.setShrinkToFit(this, val);
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_ShrinkToFit, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setWrap=function(val){
		var oRes = this.ws.workbook.oStyleManager.setWrap(this, val);
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_Wrap, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setAngle=function(val){
		var oRes = this.ws.workbook.oStyleManager.setAngle(this, val);
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_Angle, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setVerticalText=function(val){
		var oRes = this.ws.workbook.oStyleManager.setVerticalText(this, val);
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_Angle, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setQuotePrefix=function(val){
		var oRes = this.ws.workbook.oStyleManager.setQuotePrefix(this, val);
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_SetQuotePrefix, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setPivotButton=function(val){
		var oRes = this.ws.workbook.oStyleManager.setPivotButton(this, val);
		if(History.Is_On() && oRes.oldVal != oRes.newVal)
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_SetPivotButton, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oRes.oldVal, oRes.newVal));
	};
	Cell.prototype.setStyle=function(xfs){
		var oldVal = this.xfs;
		this.setStyleInternal(xfs);
		if(History.Is_On() && oldVal != this.xfs)
		{
			History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_SetStyle, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, oldVal, this.xfs));
		}
	};
	Cell.prototype.setStyleInternal = function(xfs) {
		this.xfs = g_StyleCache.addXf(xfs);
		this._hasChanged = true;
	};
	Cell.prototype.getFormula=function(){
		var res = "";
		this.processFormula(function(parsed) {
			res = parsed.getFormula();
		});
		return res;
	};
	Cell.prototype.getFormulaParsed=function(){
		return this.formulaParsed;
	};
	Cell.prototype.getValueForEdit = function() {
		this._checkDirty();
		//todo
		// if (CellValueType.Error == this.getType()) {
		// 	return this._getValueTypeError(textValueForEdit);
		// }
		return AscCommonExcel.getStringFromMultiText(this.getValueForEdit2());
	};
	Cell.prototype.getValueForEdit2 = function() {
		this._checkDirty();
		var cultureInfo = AscCommon.g_oDefaultCultureInfo;
		//todo проблема точности. в excel у чисел только 15 значащих цифр у нас больше.
		//применяем форматирование
		var oValueText = null;
		var oValueArray = null;
		var xfs = this.getCompiledStyle();
		if (this.isFormula()) {
			this.processFormula(function(parsed) {
				// ToDo если будет притормаживать, то завести переменную и не рассчитывать каждый раз!
				oValueText = "=" + parsed.assembleLocale(AscCommonExcel.cFormulaFunctionToLocale, true);
			});
		} else {
			if(null != this.text || null != this.number)
			{
				if (CellValueType.Bool === this.type && null != this.number)
					oValueText = (this.number == 1) ? cBoolLocal.t : cBoolLocal.f;
				else
				{
					if(null != this.text)
						oValueText = this.text;
					if(CellValueType.Number === this.type || CellValueType.String === this.type)
					{
						var oNumFormat;
						if(null != xfs && null != xfs.num)
							oNumFormat = oNumFormatCache.get(xfs.num.getFormat());
						else
							oNumFormat = oNumFormatCache.get(g_oDefaultFormat.Num.getFormat());
						if(CellValueType.String != this.type && null != oNumFormat && null != this.number)
						{
							var nValue = this.number;
							var oTargetFormat = oNumFormat.getFormatByValue(nValue);
							if(oTargetFormat)
							{
								if(1 == oTargetFormat.nPercent)
								{
									//prercent
									oValueText = AscCommon.oGeneralEditFormatCache.format(nValue * 100) + "%";
								}
								else if(oTargetFormat.bDateTime)
								{
									//Если число не подходит под формат даты возвращаем само число
									if(false == oTargetFormat.isInvalidDateValue(nValue))
									{
										var bDate = oTargetFormat.bDate;
										var bTime = oTargetFormat.bTime;
										if(false == bDate && nValue >= 1)
											bDate = true;
										if(false == bTime && Math.floor(nValue) != nValue)
											bTime = true;
										var sDateFormat = "";
										if (bDate) {
											sDateFormat = AscCommon.getShortDateFormat(cultureInfo);
										}
										var sTimeFormat = 'h:mm:ss';
										if (cultureInfo.AMDesignator.length > 0 && cultureInfo.PMDesignator.length > 0){
											sTimeFormat += ' AM/PM';
										}
										if(bDate && bTime)
											oNumFormat = oNumFormatCache.get(sDateFormat + ' ' + sTimeFormat);
										else if(bTime)
											oNumFormat = oNumFormatCache.get(sTimeFormat);
										else
											oNumFormat = oNumFormatCache.get(sDateFormat);

										var aFormatedValue = oNumFormat.format(nValue, CellValueType.Number, AscCommon.gc_nMaxDigCount);
										oValueText = "";
										for(var i = 0, length = aFormatedValue.length; i < length; ++i)
											oValueText += aFormatedValue[i].text;
									}
									else
										oValueText = AscCommon.oGeneralEditFormatCache.format(nValue);
								}
								else
									oValueText = AscCommon.oGeneralEditFormatCache.format(nValue);
							}
						}
					}
				}
			}
			else if(this.multiText)
				oValueArray = this.multiText;
		}
		if(null != xfs && true == xfs.QuotePrefix && CellValueType.String == this.type && false == this.isFormula())
		{
			if(null != oValueText)
				oValueText = "'" + oValueText;
			else if(null != oValueArray)
				oValueArray = [{text:"'"}].concat(oValueArray);
		}
		return this._getValue2Result(oValueText, oValueArray, true);
	};
	Cell.prototype.getValueForExample = function(numFormat, cultureInfo) {
		var aText = this._getValue2(AscCommon.gc_nMaxDigCountView, function(){return true;}, numFormat, cultureInfo);
		return AscCommonExcel.getStringFromMultiText(aText);
	};
	Cell.prototype.getValueWithoutFormat = function() {
		this._checkDirty();
		var sResult = "";
		if(null != this.number)
		{
			if(CellValueType.Bool === this.type)
				sResult = this.number == 1 ? cBoolLocal.t : cBoolLocal.f;
			else
				sResult = this.number.toString();
		}
		else if(null != this.text)
			sResult = this.text;
		else if(null != this.multiText)
			sResult = AscCommonExcel.getStringFromMultiText(this.multiText);
		return sResult;
	};
	Cell.prototype.getValue = function() {
		this._checkDirty();
		var aTextValue2 = this.getValue2(AscCommon.gc_nMaxDigCountView, function() {return true;});
		return AscCommonExcel.getStringFromMultiText(aTextValue2);
	};
	Cell.prototype.getValue2 = function(dDigitsCount, fIsFitMeasurer) {
		this._checkDirty();
		if(null == fIsFitMeasurer)
			fIsFitMeasurer = function(aText){return true;};
		if(null == dDigitsCount)
			dDigitsCount = AscCommon.gc_nMaxDigCountView;
		return this._getValue2(dDigitsCount, fIsFitMeasurer);
	};
	Cell.prototype.getNumberValue = function() {
		this._checkDirty();
		return this.number;
	};
	Cell.prototype.getValueText = function() {
		this._checkDirty();
		return this.text;
	};
	Cell.prototype.getTextIndex = function() {
		if (null === this.textIndex) {
			var wb = this.ws.workbook;
			if (null != this.text) {
				this.textIndex = wb.sharedStrings.addText(this.text);
			} else if (null != this.multiText) {
				this.textIndex = wb.sharedStrings.addMultiText(this.multiText);
			}
		}
		return this.textIndex;
	};
	Cell.prototype.getValueMultiText = function() {
		this._checkDirty();
		return this.multiText;
	};
	Cell.prototype.getNumFormatStr=function(){
		if(null != this.xfs && null != this.xfs.num)
			return this.xfs.num.getFormat();
		return g_oDefaultFormat.Num.getFormat();
	};
	Cell.prototype.getNumFormat=function(){
		return oNumFormatCache.get(this.getNumFormatStr());
	};
	Cell.prototype.getNumFormatType=function(){
		return this.getNumFormat().getType();
	};
	Cell.prototype.getNumFormatTypeInfo=function(){
		return this.getNumFormat().getTypeInfo();
	};
	Cell.prototype.getOffset=function(cell){
		return this.getOffset3(cell.nCol + 1, cell.nRow + 1);
	};
	Cell.prototype.getOffset2=function(cellId){
		var cAddr2 = new CellAddress(cellId);
		return this.getOffset3(cAddr2.col, cAddr2.row);
	};
	Cell.prototype.getOffset3=function(col, row){
		return new AscCommon.CellBase(this.nRow - row + 1, this.nCol - col + 1);
	};
	Cell.prototype.getValueData = function(){
		this._checkDirty();
		var formula = this.isFormula() ? this.getFormula() : null;
		return new UndoRedoData_CellValueData(formula, new AscCommonExcel.CCellValue(this));
	};
	Cell.prototype.setValueData = function(Val){
		//значения устанавляваются через setValue, чтобы пересчитались формулы
		if(null != Val.formula)
			this.setFormula(Val.formula);
		else if(null != Val.value)
		{
			var DataOld = null;
			var DataNew = null;
			if (History.Is_On())
				DataOld = this.getValueData();
			this.setFormulaInternal(null);
			this._setValueData(Val.value);
			this.ws.workbook.dependencyFormulas.addToChangedCell(this);
			this.ws.workbook.sortDependency();
			if (History.Is_On()) {
				DataNew = this.getValueData();
				if (false == DataOld.isEqual(DataNew))
					History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_ChangeValue, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, DataOld, DataNew));
			}
		}
		else
			this.setValue("");
	};
	Cell.prototype._checkDirty = function(){
		var t = this;
		if (this.getIsDirty()) {
			if (g_cCalcRecursion.incLevel()) {
				var isCalc = this.getIsCalc();
				this.setIsCalc(true);
				this.processFormula(function(parsed) {
					if (!isCalc) {
						parsed.calculate();
					} else {
						parsed.calculateCycleError();
		}
				});

				g_cCalcRecursion.decLevel();
				if (g_cCalcRecursion.getIsForceBacktracking()) {
					g_cCalcRecursion.insert({ws: this.ws, nRow: this.nRow, nCol: this.nCol});
					if (0 === g_cCalcRecursion.getLevel() && !g_cCalcRecursion.getIsProcessRecursion()) {
						g_cCalcRecursion.setIsProcessRecursion(true);
						do {
							g_cCalcRecursion.setIsForceBacktracking(false);
							g_cCalcRecursion.foreachInReverse(function(elem) {
								elem.ws._getCellNoEmpty(elem.nRow, elem.nCol, function(cell) {
									if(cell && cell.getIsDirty()){
										cell.setIsCalc(false);
										cell._checkDirty();
									}
								});
							});
						} while (g_cCalcRecursion.getIsForceBacktracking());
						g_cCalcRecursion.setIsProcessRecursion(false);
					}
				} else {
					this.setIsCalc(false);
					this.setIsDirty(false);
				}
			}
		}
	};
	Cell.prototype.getFont=function(){
		var xfs = this.getCompiledStyle();
		if(null != xfs && null != xfs.font)
			return xfs.font;
		return g_oDefaultFormat.Font;
	};
	Cell.prototype._adjustCellFormat = function() {
		var t = this;
		this.processFormula(function(parsed) {
			var valueCalc = parsed.value;
			if (valueCalc) {
			if (0 <= valueCalc.numFormat) {
					if (aStandartNumFormatsId[t.getNumFormatStr()] == 0) {
						t.setNum(new AscCommonExcel.Num({id: valueCalc.numFormat}));
				}
			} else if (AscCommonExcel.cNumFormatFirstCell === valueCalc.numFormat) {
				// ищет в формуле первый рэндж и устанавливает формат ячейки как формат первой ячейки в рэндже
					var r = parsed.getFirstRange();
						if (r && r.getNumFormatStr) {
						var sCurFormat = t.getNumFormatStr();
							if (g_oDefaultFormat.Num.getFormat() == sCurFormat) {
								var sNewFormat = r.getNumFormatStr();
								if (sCurFormat != sNewFormat) {
								t.setNumFormat(sNewFormat);
								}
							}
						}
					}
				}
		});
	};
	Cell.prototype._calculateRefType = function () {
		var parsed = this.getFormulaParsed();
		var val = parsed.value;
		if (cElementType.cell === val.type || cElementType.cell3D === val.type) {
			val = val.getValue();
			if (cElementType.empty === val.type) {
				// Bug http://bugzilla.onlyoffice.com/show_bug.cgi?id=33941
				val.value = 0;
				val.type = cElementType.number;
			}
		} else if (cElementType.array === val.type) {
			val = val.getElement(0);
		} else if (cElementType.cellsRange === val.type || cElementType.cellsRange3D === val.type) {
			val = val.cross(new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), this.ws.getId());
		}
		parsed.value = val;
	};
	Cell.prototype._updateCellValue = function() {
		if (!this.isFormula()) {
			return;
		}
		this._calculateRefType();
		var res = this.getFormulaParsed().value;
		if (res) {
			this.cleanText();
			switch (res.type) {
				case cElementType.number:
					this.setTypeInternal(CellValueType.Number);
					this.setValueNumberInternal(res.getValue());
					break;
				case cElementType.bool:
					this.setTypeInternal(CellValueType.Bool);
					this.setValueNumberInternal(res.value ? 1 : 0);
					break;
				case cElementType.error:
					this.setTypeInternal(CellValueType.Error);
					this.setValueTextInternal(res.getValue().toString());
					break;
				case cElementType.name:
					this.setTypeInternal(CellValueType.Error);
					this.setValueTextInternal(res.getValue().toString());
					break;
				default:
					this.setTypeInternal(CellValueType.String);
					this.setValueTextInternal(res.getValue().toString());
			}
			this.ws.workbook.dependencyFormulas.addToCleanCellCache(this.ws.getId(), this.nRow, this.nCol);
			AscCommonExcel.g_oVLOOKUPCache.remove(this);
			AscCommonExcel.g_oHLOOKUPCache.remove(this);
		}
	};
	Cell.prototype.cleanText = function() {
		this.number = null;
		this.text = null;
		this.multiText = null;
		this.textIndex = null;
		this.type = CellValueType.Number;
		this._hasChanged = true;
	};
	Cell.prototype._BuildDependencies = function(parse, opt_dirty) {
		var parsed = this.getFormulaParsed();
		if (parsed) {
			if (parse) {
				parsed.parse();
			}
			parsed.buildDependencies();
			if (opt_dirty || parsed.ca || this.isNullTextString()) {
				this.ws.workbook.dependencyFormulas.addToChangedCell(this);
			}
		}
	};
	Cell.prototype._setValueData = function(val){
		this.number = val.number;
		this.text = val.text;
		this.multiText = val.multiText;
		this.textIndex = null;
		this.type = val.type;
		this._hasChanged = true;
	};
	Cell.prototype._getValue2 = function(dDigitsCount, fIsFitMeasurer, opt_numFormat, opt_cultureInfo) {
		var aRes = null;
		var bNeedMeasure = true;
		var sText = null;
		var aText = null;
		var isMultyText = false;
		if (CellValueType.Number == this.type || CellValueType.String == this.type) {
			if (null != this.text) {
				sText = this.text;
			} else if (null != this.multiText) {
				aText = this.multiText;
				isMultyText = true;
			}

			if (CellValueType.String == this.type) {
				bNeedMeasure = false;
			}
			var oNumFormat;
			if (opt_numFormat) {
				oNumFormat = opt_numFormat;
			} else {
				var xfs = this.getCompiledStyle();
				if (null != xfs && null != xfs.num) {
					oNumFormat = oNumFormatCache.get(xfs.num.getFormat());
				} else {
					oNumFormat = oNumFormatCache.get(g_oDefaultFormat.Num.getFormat());
				}
			}

			if (false == oNumFormat.isGeneralFormat()) {
				if (null != this.number) {
					aText = oNumFormat.format(this.number, this.type, dDigitsCount, false, opt_cultureInfo);
					isMultyText = false;
					sText = null;
				} else if (CellValueType.String == this.type) {
					var oTextFormat = oNumFormat.getTextFormat();
					if (null != oTextFormat && "@" != oTextFormat.formatString) {
						if (null != this.text) {
							aText = oNumFormat.format(this.text, this.type, dDigitsCount, false, opt_cultureInfo);
							isMultyText = false;
							sText = null;
						} else if (null != this.multiText) {
							var sSimpleString = AscCommonExcel.getStringFromMultiText(this.multiText);
							aText = oNumFormat.format(sSimpleString, this.type, dDigitsCount, false, opt_cultureInfo);
							isMultyText = false;
							sText = null;
						}
					}
				}
			} else if (CellValueType.Number == this.type && null != this.number) {
				bNeedMeasure = false;
				var bFindResult = false;
				//варируем dDigitsCount чтобы результат влез в ячейку
				var nTempDigCount = Math.ceil(dDigitsCount);
				var sOriginText = this.number;
				while (nTempDigCount >= 1) {
					//Строим подходящий general format
					var sGeneral = AscCommon.DecodeGeneralFormat(sOriginText, this.type, nTempDigCount);
					if (null != sGeneral) {
						oNumFormat = oNumFormatCache.get(sGeneral);
					}

					if (null != oNumFormat) {
						sText = null;
						isMultyText = false;
						aText = oNumFormat.format(sOriginText, this.type, dDigitsCount, false, opt_cultureInfo);
						if (true == oNumFormat.isTextFormat()) {
							break;
						} else {
							aRes = this._getValue2Result(sText, aText, isMultyText);
							//Проверяем влезает ли текст
							if (true == fIsFitMeasurer(aRes)) {
								bFindResult = true;
								break;
							}
							aRes = null;
						}
					}
					nTempDigCount--;
				}
				if (false == bFindResult) {
					aRes = null;
					sText = null;
					isMultyText = false;
					var font = new AscCommonExcel.Font();
					if (dDigitsCount > 1) {
						font.setRepeat(true);
						aText = [{text: "#", format: font}];
					} else {
						aText = [{text: "", format: font}];
					}
				}
			}
		} else if (CellValueType.Bool === this.type) {
			if (null != this.number) {
				sText = (0 != this.number) ? cBoolLocal.t : cBoolLocal.f;
			}
		} else if (CellValueType.Error === this.type) {
			if (null != this.text) {
				sText = this._getValueTypeError(this.text);
			}
		}
		if (bNeedMeasure) {
			aRes = this._getValue2Result(sText, aText, isMultyText);
			//Проверяем влезает ли текст
			if (false == fIsFitMeasurer(aRes)) {
				aRes = null;
				sText = null;
				isMultyText = false;
				var font = new AscCommonExcel.Font();
				font.setRepeat(true);
				aText = [{text: "#", format: font}];
			}
		}
		if (null == aRes) {
			aRes = this._getValue2Result(sText, aText, isMultyText);
		}
		return aRes;
	};
	Cell.prototype._setValue = function(val)
	{
		this.cleanText();

		function checkCellValueTypeError(sUpText){
			switch (sUpText){
				case cErrorLocal["nil"]:
					return cErrorOrigin["nil"];
					break;
				case cErrorLocal["div"]:
					return cErrorOrigin["div"];
					break;
				case cErrorLocal["value"]:
					return cErrorOrigin["value"];
					break;
				case cErrorLocal["ref"]:
					return cErrorOrigin["ref"];
					break;
				case cErrorLocal["name"]:
				case cErrorLocal["name"].replace('\\', ''): // ToDo это неправильная правка для бага 32463 (нужно переделать parse формул)
					return cErrorOrigin["name"];
					break;
				case cErrorLocal["num"]:
					return cErrorOrigin["num"];
					break;
				case cErrorLocal["na"]:
					return cErrorOrigin["na"];
					break;
				case cErrorLocal["getdata"]:
					return cErrorOrigin["getdata"];
					break;
				case cErrorLocal["uf"]:
					return cErrorOrigin["uf"];
					break;
			}
			return false;
		}

		if("" == val)
			return;
		var oNumFormat;
		var xfs = this.getCompiledStyle();
		if(null != xfs && null != xfs.num)
			oNumFormat = oNumFormatCache.get(xfs.num.getFormat());
		else
			oNumFormat = oNumFormatCache.get(g_oDefaultFormat.Num.getFormat());
		if(oNumFormat.isTextFormat())
		{
			this.setTypeInternal(CellValueType.String);
			this.setValueTextInternal(val);
		}
		else
		{
			if (AscCommon.g_oFormatParser.isLocaleNumber(val))
			{
				this.setTypeInternal(CellValueType.Number);
				this.setValueNumberInternal(AscCommon.g_oFormatParser.parseLocaleNumber(val));
			}
			else
			{
				var sUpText = val.toUpperCase();
				if(cBoolLocal.t === sUpText || cBoolLocal.f === sUpText)
				{
					this.setTypeInternal(CellValueType.Bool);
					this.setValueNumberInternal((cBoolLocal.t === sUpText) ? 1 : 0);
				}
				else if(checkCellValueTypeError(sUpText))
				{
					this.setTypeInternal(CellValueType.Error);
					this.setValueTextInternal(checkCellValueTypeError(sUpText));
				}
				else
				{
					//распознаем формат
					var res = AscCommon.g_oFormatParser.parse(val);
					if(null != res)
					{
						//Сравниваем с текущим форматом, если типы совпадают - меняем только значение ячейки
						var nFormatType = oNumFormat.getType();
						if(!((c_oAscNumFormatType.Percent == nFormatType && res.bPercent) ||
							(c_oAscNumFormatType.Currency == nFormatType && res.bCurrency) ||
							(c_oAscNumFormatType.Date == nFormatType && res.bDate) ||
							(c_oAscNumFormatType.Time == nFormatType && res.bTime)) && res.format != oNumFormat.sFormat) {
							this.setNumFormat(res.format);
						}
						this.setTypeInternal(CellValueType.Number);
						this.setValueNumberInternal(res.value);
					}
					else
					{
						this.setTypeInternal(CellValueType.String);
						//проверяем QuotePrefix
						if(val.length > 0 && "'" == val[0])
						{
							this.setQuotePrefix(true);
							val = val.substring(1);
						}
						this.setValueTextInternal(val);
					}
				}
			}
		}
		if (/(^(((http|https|ftp):\/\/)|(mailto:)|(www.)))|@/i.test(val)) {
			// Удаляем концевые пробелы и переводы строки перед проверкой гиперссылок
			val = val.replace(/\s+$/, '');
			var typeHyp = AscCommon.getUrlType(val);
			if (AscCommon.c_oAscUrlType.Invalid != typeHyp) {
				val = AscCommon.prepareUrl(val, typeHyp);

				var oNewHyperlink = new AscCommonExcel.Hyperlink();
				oNewHyperlink.Ref = this.ws.getCell3(this.nRow, this.nCol);
				oNewHyperlink.Hyperlink = val;
				oNewHyperlink.Ref.setHyperlink(oNewHyperlink);
			}
		}
	};
	Cell.prototype._setValue2 = function(aVal)
	{
		var sSimpleText = "";
		for(var i = 0, length = aVal.length; i < length; ++i)
			sSimpleText += aVal[i].text;
		this._setValue(sSimpleText);
		var nRow = this.nRow;
		var nCol = this.nCol;
		if(CellValueType.String == this.type && null == this.ws.hyperlinkManager.getByCell(nRow, nCol))
		{
			this.cleanText();
			this.setTypeInternal(CellValueType.String);
			//проверяем можно ли перевести массив в простую строку.
			if(aVal.length > 0)
			{
				this.multiText = [];
				for(var i = 0, length = aVal.length; i < length; i++){
					var item = aVal[i];
					var oNewElem = new AscCommonExcel.CMultiTextElem();
					oNewElem.text = item.text;
					if (null != item.format) {
						oNewElem.format = new AscCommonExcel.Font();
						oNewElem.format.assign(item.format);
					}
					this.multiText.push(oNewElem);
				}
				this._minimizeMultiText(true);
			}
			//обрабатываем QuotePrefix
			if(null != this.text)
			{
				if(this.text.length > 0 && "'" == this.text[0])
				{
					this.setQuotePrefix(true);
					this.setValueTextInternal(this.text.substring(1));
				}
			}
			else if(null != this.multiText)
			{
				if(this.multiText.length > 0)
				{
					var oFirstItem = this.multiText[0];
					if(null != oFirstItem.text && oFirstItem.text.length > 0 && "'" == oFirstItem.text[0])
					{
						this.setQuotePrefix(true);
						if(1 != oFirstItem.text.length)
							oFirstItem.text = oFirstItem.text.substring(1);
						else
						{
							this.multiText.shift();
							if(0 == this.multiText.length)
							{
								this.setValueTextInternal("");
							}
						}
					}
				}
			}
		}
	};
	Cell.prototype._setFontProp = function(fCheck, fAction)
	{
		var bRes = false;
		if(null != this.multiText)
		{
			//проверяем поменяются ли свойства
			var bChange = false;
			for(var i = 0, length = this.multiText.length; i < length; ++i)
			{
				var elem = this.multiText[i];
				if (null != elem.format && true == fCheck(elem.format))
				{
					bChange = true;
					break;
				}
			}
			if(bChange)
			{
				var backupObj = this.getValueData();
				for (var i = 0, length = this.multiText.length; i < length; ++i) {
					var elem = this.multiText[i];
					if (null != elem.format)
						fAction(elem.format)
				}
				//пробуем преобразовать в простую строку
				if(this._minimizeMultiText(false))
				{
					var DataNew = this.getValueData();
					History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_ChangeValue, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow,this.nCol, backupObj, DataNew));
				}
				else
				{
					var DataNew = this._cloneMultiText();
					History.Add(AscCommonExcel.g_oUndoRedoCell, AscCH.historyitem_Cell_ChangeArrayValueFormat, this.ws.getId(), new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow), new UndoRedoData_CellSimpleData(this.nRow, this.nCol, backupObj.value.multiText, DataNew));
				}
			}
			bRes = true;
		}
		return bRes;
	};
	Cell.prototype._getValue2Result = function(sText, aText, isMultyText)
	{
		var aResult = [];
		if(null == sText && null == aText)
			sText = "";
		var oNewItem, cellfont;
		var xfs = this.getCompiledStyle();
		if(null != xfs && null != xfs.font)
			cellfont = xfs.font;
		else
			cellfont = g_oDefaultFormat.Font;
		if(null != sText){
			oNewItem = new AscCommonExcel.Fragment();
			oNewItem.text = sText;
			oNewItem.format = cellfont.clone();
			oNewItem.checkVisitedHyperlink(this.nRow, this.nCol, this.ws.hyperlinkManager);
			oNewItem.format.setSkip(false);
			oNewItem.format.setRepeat(false);
			aResult.push(oNewItem);
		} else if(null != aText){
			for(var i = 0; i < aText.length; i++){
				oNewItem = new AscCommonExcel.Fragment();
				var oCurtext = aText[i];
				if(null != oCurtext.text)
				{
					oNewItem.text = oCurtext.text;
					var oCurFormat = new AscCommonExcel.Font();
					if (isMultyText) {
						if (null != oCurtext.format) {
							oCurFormat.assign(oCurtext.format);
						} else {
							oCurFormat.assign(cellfont);
						}
					} else {
						oCurFormat.assign(cellfont);
						if (null != oCurtext.format) {
							oCurFormat.assignFromObject(oCurtext.format);
						}
					}
					oNewItem.format = oCurFormat;
					oNewItem.checkVisitedHyperlink(this.nRow, this.nCol, this.ws.hyperlinkManager);
					aResult.push(oNewItem);
				}
			}
		}
		return aResult;
	};
	Cell.prototype._getValueTypeError = function(text) {
		switch (text){
			case cErrorOrigin["nil"]:
				return cErrorLocal["nil"];
				break;
			case cErrorOrigin["div"]:
				return cErrorLocal["div"];
				break;
			case cErrorOrigin["value"]:
				return cErrorLocal["value"];
				break;
			case cErrorOrigin["ref"]:
				return cErrorLocal["ref"];
				break;
			case cErrorOrigin["name"]:
				return cErrorLocal["name"].replace('\\', ''); // ToDo это неправильная правка для бага 32463 (нужно переделать parse формул)
				break;
			case cErrorOrigin["num"]:
				return cErrorLocal["num"];
				break;
			case cErrorOrigin["na"]:
				return cErrorLocal["na"];
				break;
			case cErrorOrigin["getdata"]:
				return cErrorLocal["getdata"];
				break;
			case cErrorOrigin["uf"]:
				return cErrorLocal["uf"];
				break;
		}
		return cErrorLocal["nil"];
	};
	Cell.prototype._minimizeMultiText = function(bSetCellFont) {
		var bRes = false;
		if(null != this.multiText && this.multiText.length > 0)
		{
			var cellFont = this.getFont();
			var oIntersectFont = null;
			for (var i = 0, length = this.multiText.length; i < length; i++) {
				var elem = this.multiText[i];
				if (null != elem.format) {
					if (null == oIntersectFont)
						oIntersectFont = elem.format.clone();
					oIntersectFont.intersect(elem.format, cellFont);
				}
				else {
					oIntersectFont = cellFont;
					break;
				}
			}

			if(bSetCellFont)
			{
				if (oIntersectFont.isEqual(g_oDefaultFormat.Font))
					this.setFont(null, false);
				else
					this.setFont(oIntersectFont, false);
			}
			//если у всех элементов один формат, то сохраняем только текст
			var bIsEqual = true;
			for (var i = 0, length = this.multiText.length; i < length; i++)
			{
				var elem = this.multiText[i];
				if (null != elem.format && false == oIntersectFont.isEqual(elem.format))
				{
					bIsEqual = false;
					break;
				}
			}
			if(bIsEqual)
			{
				this.setValueTextInternal(AscCommonExcel.getStringFromMultiText(this.multiText));
				bRes = true;
			}
		}
		return bRes;
	};
	Cell.prototype._cloneMultiText = function() {
		var oRes = [];
		for(var i = 0, length = this.multiText.length; i < length; ++i)
			oRes.push(this.multiText[i].clone());
		return oRes;
	};
	Cell.prototype.getIsDirty = function() {
		return this.isDirty;
	};
	Cell.prototype.setIsDirty = function(val) {
		this.isDirty = val;
		this._hasChanged = true;
	};
	Cell.prototype.getIsCalc = function() {
		return this.isCalc;
	};
	Cell.prototype.setIsCalc = function(val) {
		this.isCalc = val;
		this._hasChanged = true;
	};
//-------------------------------------------------------------------------------------------------

	function CCellWithFormula(ws, row, col) {
		this.ws = ws;
		this.nRow = row;
		this.nCol = col;
	}
	CCellWithFormula.prototype.onFormulaEvent = function(type, eventData) {
		if (AscCommon.c_oNotifyParentType.GetRangeCell === type) {
			return new Asc.Range(this.nCol, this.nRow, this.nCol, this.nRow);
		} else if (AscCommon.c_oNotifyParentType.Change === type) {
			this._onChange(eventData);
		} else if (AscCommon.c_oNotifyParentType.ChangeFormula === type) {
			this._onChangeFormula(eventData);
		} else if (AscCommon.c_oNotifyParentType.EndCalculate === type) {
			this.ws._getCell(this.nRow, this.nCol, function(cell) {
				cell._updateCellValue();
			});
		} else if (AscCommon.c_oNotifyParentType.Shared === type) {
			return this._onShared(eventData);
					}
	};
	CCellWithFormula.prototype._onChange = function(eventData) {
		var areaData = eventData.notifyData.areaData;
		var shared = eventData.formula.getShared();
		if (shared) {
			var dependencyFormulas = this.ws.workbook.dependencyFormulas;
			if (areaData) {
				var bbox = areaData.bbox;
				var changedRange = bbox.getSharedIntersect(shared.ref, areaData.cellsInArea);
				dependencyFormulas.addToChangedRange2(this.ws.getId(), changedRange);
			} else {
				dependencyFormulas.addToChangedRange2(this.ws.getId(), shared.ref);
				}
		} else {
			this.ws.workbook.dependencyFormulas.addToChangedCell(this);
		}
	};
	CCellWithFormula.prototype._onChangeFormula = function(eventData) {
		var t = this;
		var wb = this.ws.workbook;
		var parsed = eventData.formula;
		var shared = parsed.getShared();
		if (shared) {
			var index = wb.workbookFormulas.add(parsed).getIndexNumber();
			History.Add(AscCommonExcel.g_oUndoRedoSharedFormula, AscCH.historyitem_SharedFormula_ChangeFormula, null, null, new UndoRedoData_IndexSimpleProp(index, false, parsed.getFormulaRaw(), eventData.assemble), true);
			wb.dependencyFormulas.addToChangedRange2(this.ws.getId(), shared.ref);
		} else {
			this.ws._getCell(this.nRow, this.nCol, function(cell) {
				if (parsed === cell.formulaParsed) {
					cell.setFormulaTemplate(true, function(cell) {
						cell.formulaParsed.setFormulaString(eventData.assemble);
						wb.dependencyFormulas.addToChangedCell(cell);
			});
		}
			});
		}
	};
	CCellWithFormula.prototype._onShared = function(eventData) {
		var res = false;
		var data = eventData.notifyData;
		var parsed = eventData.formula;
		var forceTransform = false;
		var sharedShift;//affected shared
		var ranges;//ranges than needed to be transform
		var i;
		var shared = parsed.getShared();
		if (shared) {
			if (c_oNotifyType.Shift === data.type) {
				var bHor = 0 !== data.offset.col;
				var toDelete = data.offset.col < 0 || data.offset.row < 0;
				var bboxShift = AscCommonExcel.shiftGetBBox(data.bbox, bHor);
				sharedShift = parsed.getSharedIntersect(data.sheetId, bboxShift);
				if (sharedShift) {
					//try to remain as many shared formulas as possible
					//that shared can only be at intersection with bboxShift
					var sharedIntersect;
					if (parsed.canShiftShared(bHor) && (sharedIntersect = bboxShift.intersectionSimple(shared.ref))) {
						//collect relative complement of sharedShift and sharedIntersect
						ranges = sharedIntersect.difference(sharedShift);
						ranges = ranges.concat(sharedShift.difference(sharedIntersect));
						//cut off shared than affected relative complement of bboxShift
						var cantBeShared;
						var diff = bboxShift.difference(new Asc.Range(0, 0, gc_nMaxCol0, gc_nMaxRow0));
						if (toDelete) {
							//cut off shared than affected delete range
							diff.push(data.bbox);
						}
						for (i = 0; i < diff.length; ++i) {
							var elem = parsed.getSharedIntersect(data.sheetId, diff[i]);
							if (elem) {
								if (cantBeShared) {
									cantBeShared.union2(elem)
								} else {
									cantBeShared = elem;
								}
							}
						}
						if (cantBeShared) {
							var intersection = sharedIntersect.intersectionSimple(cantBeShared);
							if (intersection) {
								ranges.push(intersection);
							}
						}
						forceTransform = true;
						data.shiftedShared[parsed.getListenerId()] = c_oSharedShiftType.PreProcessed;
					} else {
						ranges = [sharedShift];
					}
				}
				res = true;
			} else if (c_oNotifyType.Move === data.type || c_oNotifyType.Delete === data.type) {
				sharedShift = parsed.getSharedIntersect(data.sheetId, data.bbox);
				if (sharedShift) {
					ranges = [sharedShift];
				}
				res = true;
			} else if (AscCommon.c_oNotifyType.ChangeDefName === data.type && data.bConvertTableFormulaToRef) {
				this._processShared(shared, shared.ref, data, parsed, true, function(newFormula) {
					return newFormula.processNotify(data);
				});
				res = true;
			}
			if (ranges) {
				for (i = 0; i < ranges.length; ++i) {
					this._processShared(shared, ranges[i], data, parsed, forceTransform, function(newFormula) {
						return newFormula.shiftCells(data.type, data.sheetId, data.bbox, data.offset);
					});
				}
			}
		}
		return res;
	};
	CCellWithFormula.prototype._processShared = function(shared, ref, data, parsed, forceTransform, action) {
		var t = this;
		var cellWithFormula;
		var cellOffset = new AscCommon.CellBase();
		var newFormula;
		this.ws.getRange3(ref.r1, ref.c1, ref.r2, ref.c2)._foreachNoEmpty(function(cell) {
			if (parsed === cell.getFormulaParsed()) {
				if (!cellWithFormula) {
					cellWithFormula = new AscCommonExcel.CCellWithFormula(cell.ws, cell.nRow, cell.nCol);
					newFormula = parsed.clone(undefined, cellWithFormula);
					newFormula.removeShared();
					cellOffset.row = cell.nRow - shared.base.nRow;
					cellOffset.col = cell.nCol - shared.base.nCol;
				} else {
					cellOffset.row = cell.nRow - cellWithFormula.nRow;
					cellOffset.col = cell.nCol - cellWithFormula.nCol;
					cellWithFormula.nRow = cell.nRow;
					cellWithFormula.nCol = cell.nCol;
				}
				newFormula.changeOffset(cellOffset, false);
				if (action(newFormula) || forceTransform) {
					cellWithFormula = undefined;
					newFormula.setFormulaString(newFormula.assemble(true));
					cell.setFormulaTemplate(true, function(cell) {
						cell.setFormulaInternal(newFormula);
						newFormula.buildDependencies();
					});
				}
				t.ws.workbook.dependencyFormulas.addToChangedCell(cell);
			}
		});
	};

	function CellTypeAndValue(type, v) {
		this.type = type;
		this.v = v;
	}
	CellTypeAndValue.prototype.valueOf = function() {
		return this.v;
	};

	function ignoreFirstRowSort(worksheet, bbox) {
		var res = false;

		var oldExcludeVal = worksheet.bExcludeHiddenRows;
		worksheet.bExcludeHiddenRows = false;
		if(bbox.r1 < bbox.r2) {
			var rowFirst = worksheet.getRange3(bbox.r1, bbox.c1, bbox.r1, bbox.c2);
			var rowSecond = worksheet.getRange3(bbox.r1 + 1, bbox.c1, bbox.r1 + 1, bbox.c2);
			var typesFirst = [];
			var typesSecond = [];
			rowFirst._setPropertyNoEmpty(null, null, function(cell, row, col) {
				if (cell && !cell.isNullTextString()) {
					typesFirst.push({col: col, type: cell.getType()});
				}
			});
			rowSecond._setPropertyNoEmpty(null, null, function(cell, row, col) {
				if (cell && !cell.isNullTextString()) {
					typesSecond.push({col: col, type: cell.getType()});
				}
			});
			var indexFirst = 0;
			var indexSecond = 0;
			while (indexFirst < typesFirst.length && indexSecond < typesSecond.length) {
				var curFirst = typesFirst[indexFirst];
				var curSecond = typesSecond[indexSecond];
				if (curFirst.col < curSecond.col) {
					indexFirst++;
				} else if (curFirst.col > curSecond.col) {
					indexSecond++;
				} else {
					if (curFirst.type != curSecond.type) {
						//has head
						res = true;
						break;
					}
					indexFirst++;
					indexSecond++;
				}
			}
		}
		worksheet.bExcludeHiddenRows = oldExcludeVal;

		return res;
	}

	/**
	 * @constructor
	 */
	function Range(worksheet, r1, c1, r2, c2){
		this.worksheet = worksheet;
		this.bbox = new Asc.Range(c1, r1, c2, r2);
	}
	Range.prototype.createFromBBox=function(worksheet, bbox){
		var oRes = new Range(worksheet, bbox.r1, bbox.c1, bbox.r2, bbox.c2);
		oRes.bbox = bbox.clone();
		return oRes;
	};
	Range.prototype.clone=function(oNewWs){
		if(!oNewWs)
			oNewWs = this.worksheet;
		return this.createFromBBox(oNewWs, this.bbox);
	};
	Range.prototype._foreach = function(action) {
		if (null != action) {
			var wb = this.worksheet.workbook;
			var tempCell = new Cell(this.worksheet);
			wb.loadCells.push(tempCell);
			var oBBox = this.bbox;
			for (var i = oBBox.r1; i <= oBBox.r2; i++) {
				if (this.worksheet.bExcludeHiddenRows && this.worksheet.getRowHidden(i)) {
					continue;
				}
				for (var j = oBBox.c1; j <= oBBox.c2; j++) {
					var targetCell = null;
					for (var k = 0; k < wb.loadCells.length - 1; ++k) {
						var elem = wb.loadCells[k];
						if (elem.nRow == i && elem.nCol == j && this.worksheet === elem.ws) {
							targetCell = elem;
							break;
						}
					}
					if (null === targetCell) {
						if (!tempCell.loadContent(i, j)) {
							this.worksheet._initCell(tempCell, i, j);
						}
						action(tempCell, i, j, oBBox.r1, oBBox.c1);
						tempCell.saveContent(true);
					} else {
						action(targetCell, i, j, oBBox.r1, oBBox.c1);
					}
				}
			}
			wb.loadCells.pop();
		}
	};
	Range.prototype._foreach2=function(action){
		if(null != action)
		{
			var wb = this.worksheet.workbook;
			var oRes;
			var tempCell = new Cell(this.worksheet);
			wb.loadCells.push(tempCell);
			var oBBox = this.bbox, minC = Math.min( this.worksheet.getColsCount(), oBBox.c2 ), minR = Math.min( this.worksheet.getRowsCount(), oBBox.r2 );
			for(var i = oBBox.r1; i <= minR; i++){
				if (this.worksheet.bExcludeHiddenRows && this.worksheet.getRowHidden(i)) {
					continue;
				}
				for(var j = oBBox.c1; j <= minC; j++){
					var targetCell = null;
					for (var k = 0; k < wb.loadCells.length - 1; ++k) {
						var elem = wb.loadCells[k];
						if (elem.nRow == i && elem.nCol == j && this.worksheet === elem.ws) {
							targetCell = elem;
							break;
						}
					}
					if (null === targetCell) {
						if (tempCell.loadContent(i, j)) {
							oRes = action(tempCell, i, j, oBBox.r1, oBBox.c1);
							tempCell.saveContent(true);
						} else {
							oRes = action(null, i, j, oBBox.r1, oBBox.c1);
						}
					} else {
						oRes = action(targetCell, i, j, oBBox.r1, oBBox.c1);
					}

					if(null != oRes){
						wb.loadCells.pop();
						return oRes;
					}
				}
			}
			wb.loadCells.pop();
		}
	};
	Range.prototype._foreachNoEmpty = function(actionCell, actionRow, excludeHiddenRows) {
		var oRes, i;
		var wb = this.worksheet.workbook;
		var oBBox = this.bbox, minR = Math.min(this.worksheet.getRowsCount(), oBBox.r2);
		if (actionCell || actionRow) {
			var colData;
			var bExcludeHiddenRows = (this.worksheet.bExcludeHiddenRows || excludeHiddenRows);
			var excludedCount = 0;
			var tempCell = new Cell(this.worksheet);
			var tempRow = new AscCommonExcel.Row(this.worksheet);
			var allRow = this.worksheet.getAllRow();
			var allRowHidden = allRow && allRow.getHidden();
			var colDatasIndex = [];
			var colDatas = [];
			if (actionCell) {
				var minColData = Math.min(this.worksheet.getColDataLength() - 1, oBBox.c2);
				for (i = oBBox.c1; i <= minColData; i++) {
					colData = this.worksheet.getColDataNoEmpty(i);
					if (colData) {
						colDatas.push(colData);
						colDatasIndex.push(i);
					}
				}
				wb.loadCells.push(tempCell);
			}
			for (i = oBBox.r1; i <= minR; i++) {
				if (actionRow) {
					if (tempRow.loadContent(i)) {
						if (bExcludeHiddenRows && tempRow.getHidden()) {
							excludedCount++;
							continue;
						}
						oRes = actionRow(tempRow, excludedCount);
						tempRow.saveContent(true);
						if (null != oRes) {
							if (actionCell) {
								wb.loadCells.pop();
							}
							return oRes;
						}
					} else if (bExcludeHiddenRows && allRowHidden) {
						excludedCount++;
						continue;
					}
				} else if (bExcludeHiddenRows && this.worksheet.getRowHidden(i)) {
					excludedCount++;
					continue;
				}
				for (var j = 0; j < colDatasIndex.length; j++) {
					colData = colDatas[j];
					var nCol = colDatasIndex[j];
					if (colData.hasSize(i)) {
						var targetCell = null;
						for (var k = 0; k < wb.loadCells.length - 1; ++k) {
							var elem = wb.loadCells[k];
							if (elem.nRow == i && elem.nCol == nCol && this.worksheet === elem.ws) {
								targetCell = elem;
								break;
							}
						}
						if (null === targetCell) {
							if (tempCell.loadContent(i, nCol, colData)) {
								oRes = actionCell(tempCell, i, nCol, oBBox.r1, oBBox.c1, excludedCount);
								tempCell.saveContent(true);
							}
						} else {
							oRes = actionCell(targetCell, i, nCol, oBBox.r1, oBBox.c1, excludedCount);
						}
						if (null != oRes) {
							if (actionCell) {
								wb.loadCells.pop();
							}
							return oRes;
						}
					} else {
						//splice by one element is too slow
						var endIndex = j + 1;
						while (endIndex < colDatasIndex.length && !colDatas[endIndex].hasSize(i)) {
							endIndex++;
						}
						colDatas.splice(j, endIndex - j);
						colDatasIndex.splice(j, endIndex - j);
						j--;
					}
				}
			}
			if (actionCell) {
				wb.loadCells.pop();
			}
		}
	};
	Range.prototype._foreachRow = function(actionRow, actionCell){
		var oBBox = this.bbox;
		if (null != actionRow) {
			var tempRow = new AscCommonExcel.Row(this.worksheet);
			for (var i = oBBox.r1; i <= oBBox.r2; i++) {
				if (!tempRow.loadContent(i)) {
					this.worksheet._initRow(tempRow, i);
				}
				if (this.worksheet.bExcludeHiddenRows && tempRow.getHidden()) {
					continue;
				}
				actionRow(tempRow);
				tempRow.saveContent(true);
			}
		}
		if (null != actionCell) {
			return this._foreachNoEmpty(actionCell);
		}
	};
	Range.prototype._foreachRowNoEmpty = function(actionRow, actionCell, excludeHiddenRows) {
		return this._foreachNoEmpty(actionCell, actionRow, excludeHiddenRows);
	};
	Range.prototype._foreachCol = function(actionCol, actionCell){
		var oBBox = this.bbox;
		if(null != actionCol)
		{
			for(var i = oBBox.c1; i <= oBBox.c2; ++i)
			{
				var col = this.worksheet._getCol(i);
				if(null != col)
					actionCol(col);
			}
		}
		if(null != actionCell) {
			this._foreachNoEmpty(actionCell);
						}
	};
	Range.prototype._foreachColNoEmpty=function(actionCol, actionCell){
		var oBBox = this.bbox;
		var minC = Math.min( oBBox.c2,this.worksheet.getColsCount() );
			if(null != actionCol)
			{
				for(var i = oBBox.c1; i <= minC; ++i)
				{
					var col = this.worksheet._getColNoEmpty(i);
					if(null != col)
					{
						var oRes = actionCol(col);
						if(null != oRes)
							return oRes;
					}
				}
			}
		if(null != actionCell) {
			return this._foreachNoEmpty(actionCell);
							}
	};
	Range.prototype._getRangeType=function(oBBox){
		if(null == oBBox)
			oBBox = this.bbox;
		return getRangeType(oBBox);
	};
	Range.prototype._getValues = function (numbers) {
		var res = [];
		var fAction = numbers ? function (c) {
			var v = c.getNumberValue();
			if (null !== v) {
				res.push(v);
			}
		} : function (c) {
			res.push(new CellTypeAndValue(c.getType(), c.getValueWithoutFormat()));
		};
		this._setPropertyNoEmpty(null, null, fAction);
		return res;
	};
	Range.prototype._getValuesAndMap = function (withEmpty) {
		var v, arrRes = [], mapRes = {};
		var fAction = function(c) {
			v = c.getValueWithoutFormat();
			arrRes.push(new CellTypeAndValue(c.getType(), v));
			mapRes[v.toLowerCase()] = true;
		};
		if (withEmpty) {
			this._setProperty(null, null, fAction);
		} else {
			this._setPropertyNoEmpty(null, null, fAction);
		}
		return {values: arrRes, map: mapRes};
	};
	Range.prototype._setProperty=function(actionRow, actionCol, actionCell){
		var nRangeType = this._getRangeType();
		if(c_oRangeType.Range == nRangeType)
			this._foreach(actionCell);
		else if(c_oRangeType.Row == nRangeType)
			this._foreachRow(actionRow, actionCell);
		else if(c_oRangeType.Col == nRangeType)
			this._foreachCol(actionCol, actionCell);
		else
		{
			//сюда не должны заходить вообще
			// this._foreachRow(actionRow, actionCell);
			// if(null != actionCol)
			// this._foreachCol(actionCol, null);
		}
	};
	Range.prototype._setPropertyNoEmpty=function(actionRow, actionCol, actionCell){
		var nRangeType = this._getRangeType();
		if(c_oRangeType.Range == nRangeType)
			return this._foreachNoEmpty(actionCell);
		else if(c_oRangeType.Row == nRangeType)
			return this._foreachRowNoEmpty(actionRow, actionCell);
		else if(c_oRangeType.Col == nRangeType)
			return this._foreachColNoEmpty(actionCol, actionCell);
		else
		{
			var oRes = this._foreachRowNoEmpty(actionRow, actionCell);
			if(null != oRes)
				return oRes;
			if(null != actionCol)
				oRes = this._foreachColNoEmpty(actionCol, null);
			return oRes;
		}
	};
	Range.prototype.containCell=function(cellId){
		var cellAddress = cellId;
		return 	cellAddress.getRow0() >= this.bbox.r1 && cellAddress.getCol0() >= this.bbox.c1 &&
			cellAddress.getRow0() <= this.bbox.r2 && cellAddress.getCol0() <= this.bbox.c2;
	};
	Range.prototype.containCell2=function(cell){
		return 	cell.nRow >= this.bbox.r1 && cell.nCol >= this.bbox.c1 &&
			cell.nRow <= this.bbox.r2 && cell.nCol <= this.bbox.c2;
	};
	Range.prototype.cross = function(bbox){
		if( bbox.r1 >= this.bbox.r1 && bbox.r1 <= this.bbox.r2 && this.bbox.c1 == this.bbox.c2)
			return {r:bbox.r1};
		if( bbox.c1 >= this.bbox.c1 && bbox.c1 <= this.bbox.c2 && this.bbox.r1 == this.bbox.r2)
			return {c:bbox.c1};

		return undefined;
	};
	Range.prototype.getWorksheet=function(){
		return this.worksheet;
	};
	Range.prototype.isFormula = function(){
		var nRow = this.bbox.r1;
		var nCol = this.bbox.c1;
		var isFormula;
		this.worksheet._getCellNoEmpty(nRow, nCol, function(cell) {
			isFormula = cell.isFormula();
		});
		return isFormula;
	};
	Range.prototype.isOneCell=function(){
		var oBBox = this.bbox;
		return oBBox.r1 == oBBox.r2 && oBBox.c1 == oBBox.c2;
	};
	Range.prototype.getBBox0=function(){
		//0 - based
		return this.bbox;
	};
	Range.prototype.getName=function(){
		return this.bbox.getName();
	};
	Range.prototype.setValue=function(val,callback, isCopyPaste){
		History.Create_NewPoint();
		History.StartTransaction();
		this._foreach(function(cell){
			cell.setValue(val,callback, isCopyPaste);
			// if(cell.isEmpty())
			// cell.Remove();
		});
		History.EndTransaction();
	};
	Range.prototype.setValue2=function(array){
		History.Create_NewPoint();
		History.StartTransaction();
		//[{"text":"qwe","format":{"b":true, "i":false, "u":Asc.EUnderline.underlineNone, "s":false, "fn":"Arial", "fs": 12, "c": 0xff00ff, "va": "subscript"  }},{}...]
		/*
		 Устанавливаем значение в Range ячеек. В отличае от setValue, сюда мы попадаем только в случае ввода значения отличного от формулы. Таким образом, если в ячейке была формула, то для нее в графе очищается список ячеек от которых зависела. После чего выставляем флаг о необходимости пересчета.
		 */
		this._foreach(function(cell){
			cell.setValue2(array);
			// if(cell.isEmpty())
			// cell.Remove();
		});
		History.EndTransaction();
	};
	Range.prototype.setValueData = function(val){
		History.Create_NewPoint();
		History.StartTransaction();
		
		this._foreach(function(cell){
			cell.setValueData(val);
		});
		History.EndTransaction();
	};
	Range.prototype.setCellStyle=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setCellStyle(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setCellStyle(val);
						  },
						  function(col){
							  col.setCellStyle(val);
						  },
						  function(cell){
							  cell.setCellStyle(val);
						  });
	};
	Range.prototype.clearTableStyle = function() {
		this.worksheet.sheetMergedStyles.clearTablePivotStyle(this.bbox);
	};
	Range.prototype.setTableStyle = function(xf, stripe) {
		if (xf) {
			this.worksheet.sheetMergedStyles.setTablePivotStyle(this.bbox, xf, stripe);
		}
	};
	Range.prototype.setNumFormat=function(val){
		this.setNum(new AscCommonExcel.Num({f:val}));
	};
	Range.prototype.setNum = function(val) {
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if (c_oRangeType.All == nRangeType) {
			this.worksheet.getAllCol().setNum(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row) {
							  if (c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setNum(val);
						  },
						  function(col) {
							  col.setNum(val);
						  },
						  function(cell) {
							  cell.setNum(val);
						  });
	};
	Range.prototype.shiftNumFormat=function(nShift, aDigitsCount){
		History.Create_NewPoint();
		var bRes = false;
		this._setPropertyNoEmpty(null, null, function(cell, nRow0, nCol0, nRowStart, nColStart){
			bRes |= cell.shiftNumFormat(nShift, aDigitsCount[nCol0 - nColStart]);
		});
		return bRes;
	};
	Range.prototype.setFont=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setFont(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setFont(val);
						  },
						  function(col){
							  col.setFont(val);
						  },
						  function(cell){
							  cell.setFont(val);
						  });
	};
	Range.prototype.setFontname=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setFontname(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setFontname(val);
						  },
						  function(col){
							  col.setFontname(val);
						  },
						  function(cell){
							  cell.setFontname(val);
						  });
	};
	Range.prototype.setFontsize=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setFontsize(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setFontsize(val);
						  },
						  function(col){
							  col.setFontsize(val);
						  },
						  function(cell){
							  cell.setFontsize(val);
						  });
	};
	Range.prototype.setFontcolor=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setFontcolor(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setFontcolor(val);
						  },
						  function(col){
							  col.setFontcolor(val);
						  },
						  function(cell){
							  cell.setFontcolor(val);
						  });
	};
	Range.prototype.setBold=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setBold(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setBold(val);
						  },
						  function(col){
							  col.setBold(val);
						  },
						  function(cell){
							  cell.setBold(val);
						  });
	};
	Range.prototype.setItalic=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setItalic(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setItalic(val);
						  },
						  function(col){
							  col.setItalic(val);
						  },
						  function(cell){
							  cell.setItalic(val);
						  });
	};
	Range.prototype.setUnderline=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setUnderline(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setUnderline(val);
						  },
						  function(col){
							  col.setUnderline(val);
						  },
						  function(cell){
							  cell.setUnderline(val);
						  });
	};
	Range.prototype.setStrikeout=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setStrikeout(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setStrikeout(val);
						  },
						  function(col){
							  col.setStrikeout(val);
						  },
						  function(cell){
							  cell.setStrikeout(val);
						  });
	};
	Range.prototype.setFontAlign=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setFontAlign(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setFontAlign(val);
						  },
						  function(col){
							  col.setFontAlign(val);
						  },
						  function(cell){
							  cell.setFontAlign(val);
						  });
	};
	Range.prototype.setAlignVertical=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setAlignVertical(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setAlignVertical(val);
						  },
						  function(col){
							  col.setAlignVertical(val);
						  },
						  function(cell){
							  cell.setAlignVertical(val);
						  });
	};
	Range.prototype.setAlignHorizontal=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setAlignHorizontal(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setAlignHorizontal(val);
						  },
						  function(col){
							  col.setAlignHorizontal(val);
						  },
						  function(cell){
							  cell.setAlignHorizontal(val);
						  });
	};
	Range.prototype.setFill=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setFill(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setFill(val);
						  },
						  function(col){
							  col.setFill(val);
						  },
						  function(cell){
							  cell.setFill(val);
						  });
	};
	Range.prototype.setBorderSrc=function(border){
		History.Create_NewPoint();
		History.StartTransaction();
		if (null == border)
			border = new Border();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setBorder(border.clone());
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setBorder(border.clone());
						  },
						  function(col){
							  col.setBorder(border.clone());
						  },
						  function(cell){
							  cell.setBorder(border.clone());
						  });
		History.EndTransaction();
	};
	Range.prototype._setBorderMerge=function(bLeft, bTop, bRight, bBottom, oNewBorder, oCurBorder){
		var oTargetBorder = new Border();
		//не делаем clone для свойств потому у нас нельзя поменять свойство отдельное свойство border можно только применить border целиком
		if(bLeft)
			oTargetBorder.l = oNewBorder.l;
		else
			oTargetBorder.l = oNewBorder.iv;
		if(bTop)
			oTargetBorder.t = oNewBorder.t;
		else
			oTargetBorder.t = oNewBorder.ih;
		if(bRight)
			oTargetBorder.r = oNewBorder.r;
		else
			oTargetBorder.r = oNewBorder.iv;
		if(bBottom)
			oTargetBorder.b = oNewBorder.b;
		else
			oTargetBorder.b = oNewBorder.ih;
		oTargetBorder.d = oNewBorder.d;
		oTargetBorder.dd = oNewBorder.dd;
		oTargetBorder.du = oNewBorder.du;
		var oRes = null;
		if(null != oCurBorder)
		{
			oCurBorder.mergeInner(oTargetBorder);
			oRes = oCurBorder;
		}
		else
			oRes = oTargetBorder;
		return oRes;
	};
	Range.prototype._setCellBorder=function(bbox, cell, oNewBorder){
		if(null == oNewBorder)
			cell.setBorder(oNewBorder);
		else
		{
			var oCurBorder = null;
			if(null != cell.xfs && null != cell.xfs.border)
				oCurBorder = cell.xfs.border.clone();
			else
				oCurBorder = g_oDefaultFormat.Border.clone();
			var nRow = cell.nRow;
			var nCol = cell.nCol;
			cell.setBorder(this._setBorderMerge(nCol == bbox.c1, nRow == bbox.r1, nCol == bbox.c2, nRow == bbox.r2, oNewBorder, oCurBorder));
		}
	};
	Range.prototype._setRowColBorder=function(bbox, rowcol, bRow, oNewBorder){
		if(null == oNewBorder)
			rowcol.setBorder(oNewBorder);
		else
		{
			var oCurBorder = null;
			if(null != rowcol.xfs && null != rowcol.xfs.border)
				oCurBorder = rowcol.xfs.border.clone();
			var bLeft, bTop, bRight, bBottom = false;
			if(bRow)
			{
				bTop = rowcol.index == bbox.r1;
				bBottom = rowcol.index == bbox.r2;
			}
			else
			{
				bLeft = rowcol.index == bbox.c1;
				bRight = rowcol.index == bbox.c2;
			}
			rowcol.setBorder(this._setBorderMerge(bLeft, bTop, bRight, bBottom, oNewBorder, oCurBorder));
		}
	};
	Range.prototype._setBorderEdge=function(bbox, oItemWithXfs, nRow, nCol, oNewBorder){
		var oCurBorder = null;
		if(null != oItemWithXfs.xfs && null != oItemWithXfs.xfs.border)
			oCurBorder = oItemWithXfs.xfs.border;
		if(null != oCurBorder)
		{
			var oCurBorderProp = null;
			if(nCol == bbox.c1 - 1)
				oCurBorderProp = oCurBorder.r;
			else if(nRow == bbox.r1 - 1)
				oCurBorderProp = oCurBorder.b;
			else if(nCol == bbox.c2 + 1)
				oCurBorderProp = oCurBorder.l;
			else if(nRow == bbox.r2 + 1)
				oCurBorderProp = oCurBorder.t;
			var oNewBorderProp = null;
			if(null == oNewBorder)
				oNewBorderProp = new AscCommonExcel.BorderProp();
			else
			{
				if(nCol == bbox.c1 - 1)
					oNewBorderProp = oNewBorder.l;
				else if(nRow == bbox.r1 - 1)
					oNewBorderProp = oNewBorder.t;
				else if(nCol == bbox.c2 + 1)
					oNewBorderProp = oNewBorder.r;
				else if(nRow == bbox.r2 + 1)
					oNewBorderProp = oNewBorder.b;
			}

			if(null != oNewBorderProp && null != oCurBorderProp && c_oAscBorderStyles.None != oCurBorderProp.s && (null == oNewBorder || c_oAscBorderStyles.None != oNewBorderProp.s) &&
				(oNewBorderProp.s != oCurBorderProp.s || oNewBorderProp.getRgbOrNull() != oCurBorderProp.getRgbOrNull())){
				var oTargetBorder = oCurBorder.clone();
				if(nCol == bbox.c1 - 1)
					oTargetBorder.r = new AscCommonExcel.BorderProp();
				else if(nRow == bbox.r1 - 1)
					oTargetBorder.b = new AscCommonExcel.BorderProp();
				else if(nCol == bbox.c2 + 1)
					oTargetBorder.l = new AscCommonExcel.BorderProp();
				else if(nRow == bbox.r2 + 1)
					oTargetBorder.t = new AscCommonExcel.BorderProp();
				oItemWithXfs.setBorder(oTargetBorder);
			}
		}
	};
	Range.prototype.setBorder=function(border){
		//border = null очисть border
		//"ih" - внутренние горизонтальные, "iv" - внутренние вертикальные
		History.Create_NewPoint();
		var _this = this;
		var oBBox = this.bbox;
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			var oAllCol = this.worksheet.getAllCol();
			_this._setRowColBorder(oBBox, oAllCol, false, border);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  _this._setRowColBorder(oBBox, row, true, border);
						  },
						  function(col){
							  _this._setRowColBorder(oBBox, col, false, border);
						  },
						  function(cell){
							  _this._setCellBorder(oBBox, cell, border);
						  });
		//убираем граничные border
		var aEdgeBorders = [];
		if(oBBox.c1 > 0 && (null == border || !border.l.isEmpty()))
			aEdgeBorders.push(this.worksheet.getRange3(oBBox.r1, oBBox.c1 - 1, oBBox.r2, oBBox.c1 - 1));
		if(oBBox.r1 > 0 && (null == border || !border.t.isEmpty()))
			aEdgeBorders.push(this.worksheet.getRange3(oBBox.r1 - 1, oBBox.c1, oBBox.r1 - 1, oBBox.c2));
		if(oBBox.c2 < gc_nMaxCol0 && (null == border || !border.r.isEmpty()))
			aEdgeBorders.push(this.worksheet.getRange3(oBBox.r1, oBBox.c2 + 1, oBBox.r2, oBBox.c2 + 1));
		if(oBBox.r2 < gc_nMaxRow0 && (null == border || !border.b.isEmpty()))
			aEdgeBorders.push(this.worksheet.getRange3(oBBox.r2 + 1, oBBox.c1, oBBox.r2 + 1, oBBox.c2));
		for(var i = 0, length = aEdgeBorders.length; i < length; i++)
		{
			var range = aEdgeBorders[i];
			range._setPropertyNoEmpty(function(row){
										  if(c_oRangeType.All == nRangeType && null == row.xfs)
											  return;
										  _this._setBorderEdge(oBBox, row, row.index, 0, border);
									  },
									  function(col){
										  _this._setBorderEdge(oBBox, col, 0, col.index, border);
									  },
									  function(cell){
										  _this._setBorderEdge(oBBox, cell, cell.nRow, cell.nCol, border);
									  });
		}
	};
	Range.prototype.setShrinkToFit=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setShrinkToFit(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setShrinkToFit(val);
						  },
						  function(col){
							  col.setShrinkToFit(val);
						  },
						  function(cell){
							  cell.setShrinkToFit(val);
						  });
	};
	Range.prototype.setWrap=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setWrap(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setWrap(val);
						  },
						  function(col){
							  col.setWrap(val);
						  },
						  function(cell){
							  cell.setWrap(val);
						  });
	};
	Range.prototype.setAngle=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setAngle(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setAngle(val);
						  },
						  function(col){
							  col.setAngle(val);
						  },
						  function(cell){
							  cell.setAngle(val);
						  });
	};
	Range.prototype.setVerticalText=function(val){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			this.worksheet.getAllCol().setVerticalText(val);
			fSetProperty = this._setPropertyNoEmpty;
		}
		fSetProperty.call(this, function(row){
							  if(c_oRangeType.All == nRangeType && null == row.xfs)
								  return;
							  row.setVerticalText(val);
						  },
						  function(col){
							  col.setVerticalText(val);
						  },
						  function(cell){
							  cell.setVerticalText(val);
						  });
	};
	Range.prototype.setType=function(type){
		History.Create_NewPoint();
		this.createCellOnRowColCross();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
			fSetProperty = this._setPropertyNoEmpty;
		fSetProperty.call(this, null, null,
						  function(cell){
							  cell.setType(type);
						  });
	};
	Range.prototype.getType=function(){
		var type;
		this.worksheet._getCellNoEmpty(this.bbox.r1,this.bbox.c1, function(cell) {
			if(null != cell)
				type = cell.getType();
			else
				type = null;
		});
		return type;
	};
	Range.prototype.isNullText=function(){
		var isNullText;
		this.worksheet._getCellNoEmpty(this.bbox.r1,this.bbox.c1, function(cell) {
			isNullText = (null != cell) ? cell.isNullText() : true;
		});
		return isNullText;
	};
	Range.prototype.isEmptyTextString=function(){
		var isEmptyTextString;
		this.worksheet._getCellNoEmpty(this.bbox.r1,this.bbox.c1, function(cell) {
			isEmptyTextString = (null != cell) ? cell.isEmptyTextString() : true;
		});
		return isEmptyTextString;
	};
	Range.prototype.isNullTextString=function(){
		var isNullTextString;
		this.worksheet._getCellNoEmpty(this.bbox.r1,this.bbox.c1, function(cell) {
			isNullTextString = (null != cell) ? cell.isNullTextString() : true;
		});
		return isNullTextString;
	};
	Range.prototype.isFormula=function(){
		var isFormula;
		this.worksheet._getCellNoEmpty(this.bbox.r1,this.bbox.c1, function(cell) {
			isFormula = (null != cell) ? cell.isFormula() : false;
		});
		return isFormula;
	};
	Range.prototype.getFormula=function(){
		var formula;
		this.worksheet._getCellNoEmpty(this.bbox.r1,this.bbox.c1, function(cell) {
			if(null != cell)
				formula = cell.getFormula();
			else
				formula = "";
		});
		return formula;
	};
	Range.prototype.getValueForEdit=function(){
		var t = this;
		var valueForEdit;
		this.worksheet._getCellNoEmpty(this.bbox.r1,this.bbox.c1, function(cell) {
			if(null != cell)
			{
				var numFormat = t.getNumFormat();
				valueForEdit = cell.getValueForEdit(numFormat);
			}
			else
				valueForEdit = "";
		});
		return valueForEdit;
	};
	Range.prototype.getValueForEdit2=function(){
		var t = this;
		var valueForEdit2;
		this.worksheet._getCellNoEmpty(this.bbox.r1,this.bbox.c1, function(cell) {
			if(null != cell)
			{
				valueForEdit2 = cell.getValueForEdit2();
			}
			else
			{
				var xfs = null;
				t.worksheet._getRowNoEmpty(t.bbox.r1, function(row){
					var oCol = t.worksheet._getColNoEmptyWithAll(t.bbox.c1);
					if(row && null != row.xfs)
						xfs = row.xfs.clone();
					else if(null != oCol && null != oCol.xfs)
						xfs = oCol.xfs.clone();
				});
				var oTempCell = new Cell(t.worksheet);
				oTempCell.setRowCol(t.bbox.r1, t.bbox.c1);
				oTempCell.setStyleInternal(xfs);
				valueForEdit2 = oTempCell.getValueForEdit2();
			}
		});
		return valueForEdit2;
	};
	Range.prototype.getValueWithoutFormat=function(){
		var valueWithoutFormat;
		this.worksheet._getCellNoEmpty(this.bbox.r1, this.bbox.c1, function(cell) {
			if(null != cell)
				valueWithoutFormat = cell.getValueWithoutFormat();
			else
				valueWithoutFormat = "";
		});
		return valueWithoutFormat;
	};
	Range.prototype.getValue=function(){
		return this.getValueWithoutFormat();
	};
	Range.prototype.getValueWithFormat=function(){
		var value;
		this.worksheet._getCellNoEmpty(this.bbox.r1, this.bbox.c1, function(cell) {
			if(null != cell)
				value = cell.getValue();
			else
				value = "";
		});
		return value;
	};
	Range.prototype.getValue2=function(dDigitsCount, fIsFitMeasurer){
		//[{"text":"qwe","format":{"b":true, "i":false, "u":Asc.EUnderline.underlineNone, "s":false, "fn":"Arial", "fs": 12, "c": 0xff00ff, "va": "subscript"  }},{}...]
		var t = this;
		var value2;
		this.worksheet._getCellNoEmpty(this.bbox.r1, this.bbox.c1, function(cell){
			if(null != cell)
				value2 = cell.getValue2(dDigitsCount, fIsFitMeasurer);
			else
			{
				var xfs = null;
				t.worksheet._getRowNoEmpty(t.bbox.r1, function(row){
					var oCol = t.worksheet._getColNoEmptyWithAll(t.bbox.c1);

					if(row && null != row.xfs)
						xfs = row.xfs.clone();
					else if(null != oCol && null != oCol.xfs)
						xfs = oCol.xfs.clone();
				});
				var oTempCell = new Cell(t.worksheet);
				oTempCell.setRowCol(t.bbox.r1, t.bbox.c1);
				oTempCell.setStyleInternal(xfs);
				value2 = oTempCell.getValue2(dDigitsCount, fIsFitMeasurer);
			}
		});
		return value2;
	};
	Range.prototype.getNumberValue = function() {
		var numberValue;
		this.worksheet._getCellNoEmpty(this.bbox.r1, this.bbox.c1, function(cell) {
			numberValue = null != cell ? cell.getNumberValue() : null;
		});
		return numberValue;
	};
	Range.prototype.getValueData=function(){
		var res = null;
		this.worksheet._getCellNoEmpty(this.bbox.r1, this.bbox.c1, function(cell) {
			if(null != cell)
				res = cell.getValueData();
		});
		return res;
	};
	Range.prototype.getXfId = function () {
		var t = this;
		var nRow = this.bbox.r1;
		var nCol = this.bbox.c1;
		var XfId = g_oDefaultFormat.XfId;
		this.worksheet._getCellNoEmpty(nRow, nCol, function (cell) {
			var xfs = cell ? cell.getCompiledStyle() : t.worksheet.getCompiledStyle(nRow, nCol);
			if (xfs && null !== xfs.XfId) {
				XfId = xfs.XfId;
			}
		});
		return XfId;
	};
	Range.prototype.getStyleName=function(){
		var res = this.worksheet.workbook.CellStyles.getStyleNameByXfId(this.getXfId());

		// ToDo убрать эту заглушку (нужно делать на открытии) в InitStyleManager
		return res || this.worksheet.workbook.CellStyles.getStyleNameByXfId(g_oDefaultFormat.XfId);
	};
	Range.prototype.getTableStyle=function(){
		var tableStyle;
		this.worksheet._getCellNoEmpty(this.bbox.r1,this.bbox.c1, function(cell) {
			tableStyle = cell ? cell.getTableStyle() : null;
		});
		return tableStyle;
	};
	Range.prototype.getNumFormat=function(){
		return oNumFormatCache.get(this.getNumFormatStr());
	};
	Range.prototype.getNumFormatStr = function () {
		var t = this;
		var nRow = this.bbox.r1;
		var nCol = this.bbox.c1;
		var numFormatStr = g_oDefaultFormat.Num.getFormat();
		;this.worksheet._getCellNoEmpty(nRow, nCol, function (cell) {
			var xfs = cell ? cell.getCompiledStyle() : t.worksheet.getCompiledStyle(nRow, nCol);
			if (xfs && xfs.num) {
				numFormatStr = xfs.num.getFormat();
			}
		});
		return numFormatStr;
	};
	Range.prototype.getNumFormatType=function(){
		return this.getNumFormat().getType();
	};
	Range.prototype.getNumFormatTypeInfo=function(){
		return this.getNumFormat().getTypeInfo();
	};
// Узнаем отличается ли шрифт (размер и гарнитура) в ячейке от шрифта в строке
	Range.prototype.isNotDefaultFont = function () {
		// Получаем фонт ячейки
		var t = this;
		var cellFont = this.getFont();
		var rowFont = g_oDefaultFormat.Font;
		this.worksheet._getRowNoEmpty(this.bbox.r1, function(row) {
			if (row && null != row.xfs && null != row.xfs.font)
				rowFont = row.xfs.font;
			else if (null != t.worksheet.oAllCol && t.worksheet.oAllCol.xfs && t.worksheet.oAllCol.xfs.font)
				rowFont = t.worksheet.oAllCol.xfs.font;
		});

		return (cellFont.getName() !== rowFont.getName() || cellFont.getSize() !== rowFont.getSize());
	};
	Range.prototype.getFont = function (original) {
		var t = this;
		var nRow = this.bbox.r1;
		var nCol = this.bbox.c1;
		var font = g_oDefaultFormat.Font;
		this.worksheet._getCellNoEmpty(nRow, nCol, function (cell) {
			var xfs;
			if (cell) {
				xfs = original ? cell.getStyle() : cell.getCompiledStyle();
			} else {
				xfs = t.worksheet.getCompiledStyle(nRow, nCol, null, original ? emptyStyleComponents : null);
			}
			if (xfs && xfs.font) {
				font = xfs.font;
			}
		});
		return font
	};
	Range.prototype.getAlignHorizontalByValue=function(align){
		//возвращает Align в зависимости от значния в ячейке
		//values:  none, center, justify, left , right, null
		var t = this;
		if(null == align){
			//пытаемся определить по значению
			var nRow = this.bbox.r1;
			var nCol = this.bbox.c1;
			this.worksheet._getCellNoEmpty(nRow, nCol, function(cell) {
				if(cell){
					switch(cell.getType()){
						case CellValueType.String:align = AscCommon.align_Left;break;
						case CellValueType.Bool:
						case CellValueType.Error:align = AscCommon.align_Center;break;
						default:
							//Если есть value и не проставлен тип значит это число, у всех остальных типов значение не null
							if(t.getValueWithoutFormat())
							{
								//смотрим
								var oNumFmt = t.getNumFormat();
								if(true == oNumFmt.isTextFormat())
									align = AscCommon.align_Left;
								else
									align = AscCommon.align_Right;
							}
							else
								align = AscCommon.align_Left;
							break;
					}
				}
			});
			if(null == align)
				align = AscCommon.align_Left;
		}
		return align;
	};
	Range.prototype.getFill = function () {
		var t = this;
		var nRow = this.bbox.r1;
		var nCol = this.bbox.c1;
		var fill = g_oDefaultFormat.Fill.bg;
		this.worksheet._getCellNoEmpty(nRow, nCol, function (cell) {
			var xfs = cell ? cell.getCompiledStyle() : t.worksheet.getCompiledStyle(nRow, nCol);
			if (xfs && xfs.fill) {
				fill = xfs.fill.bg;
			}
		});
		return fill;
	};
	Range.prototype.getBorderSrc = function (opt_row, opt_col) {
		//Возвращает как записано в файле, не проверяя бордеры соседних ячеек
		//формат
		//\{"l": {"s": "solid", "c": 0xff0000}, "t": {} ,"r": {} ,"b": {} ,"d": {},"dd": false ,"du": false }
		//"s" values: none, thick, thin, medium, dashDot, dashDotDot, dashed, dotted, double, hair, mediumDashDot, mediumDashDotDot, mediumDashed, slantDashDot
		//"dd" diagonal line, starting at the top left corner of the cell and moving down to the bottom right corner of the cell
		//"du" diagonal line, starting at the bottom left corner of the cell and moving up to the top right corner of the cell
		var t = this;
		var nRow = null != opt_row ? opt_row : this.bbox.r1;
		var nCol = null != opt_col ? opt_col : this.bbox.c1;
		var border = g_oDefaultFormat.Border;
		this.worksheet._getCellNoEmpty(nRow, nCol, function (cell) {
			var xfs = cell ? cell.getCompiledStyle() : t.worksheet.getCompiledStyle(nRow, nCol);
			if (xfs && xfs.border) {
				border = xfs.border;
			}
		});
		return border;
	};
	Range.prototype.getBorder = function (opt_row, opt_col) {
		//Возвращает как записано в файле, не проверяя бордеры соседних ячеек
		//формат
		//\{"l": {"s": "solid", "c": 0xff0000}, "t": {} ,"r": {} ,"b": {} ,"d": {},"dd": false ,"du": false }
		//"s" values: none, thick, thin, medium, dashDot, dashDotDot, dashed, dotted, double, hair, mediumDashDot, mediumDashDotDot, mediumDashed, slantDashDot
		//"dd" diagonal line, starting at the top left corner of the cell and moving down to the bottom right corner of the cell
		//"du" diagonal line, starting at the bottom left corner of the cell and moving up to the top right corner of the cell
		return this.getBorderSrc(opt_row, opt_col) || g_oDefaultFormat.Border;
	};
	Range.prototype.getBorderFull=function(){
		//Возвращает как excel, т.е. проверяет бордеры соседних ячеек
		//
		//\{"l": {"s": "solid", "c": 0xff0000}, "t": {} ,"r": {} ,"b": {} ,"d": {},"dd": false ,"du": false }
		//"s" values: none, thick, thin, medium, dashDot, dashDotDot, dashed, dotted, double, hair, mediumDashDot, mediumDashDotDot, mediumDashed, slantDashDot
		//
		//"dd" diagonal line, starting at the top left corner of the cell and moving down to the bottom right corner of the cell
		//"du" diagonal line, starting at the bottom left corner of the cell and moving up to the top right corner of the cell
		var borders = this.getBorder(this.bbox.r1, this.bbox.c1).clone();
		var nRow = this.bbox.r1;
		var nCol = this.bbox.c1;
		if(c_oAscBorderStyles.None === borders.l.s){
			if(nCol > 1){
				var left = this.getBorder(nRow, nCol - 1);
				if(c_oAscBorderStyles.None !== left.r.s)
					borders.l = left.r;
			}
		}
		if(c_oAscBorderStyles.None === borders.t.s){
			if(nRow > 1){
				var top = this.getBorder(nRow - 1, nCol);
				if(c_oAscBorderStyles.None !== top.b.s)
					borders.t = top.b;
			}
		}
		if(c_oAscBorderStyles.None === borders.r.s){
			var right = this.getBorder(nRow, nCol + 1);
			if(c_oAscBorderStyles.None !== right.l.s)
				borders.r = right.l;
		}
		if(c_oAscBorderStyles.None === borders.b.s){
			var bottom = this.getBorder(nRow + 1, nCol);
			if(c_oAscBorderStyles.None !== bottom.t.s)
				borders.b = bottom.t;
		}
		return borders;
	};
	Range.prototype.getAlign=function(){
		//угол от -90 до 90 против часовой стрелки от оси OX
		var t = this;
		var nRow = this.bbox.r1;
		var nCol = this.bbox.c1;
		var align = g_oDefaultFormat.Align;
		this.worksheet._getCellNoEmpty(nRow, nCol, function(cell) {
			if(null != cell)
			{
				var xfs = cell.getCompiledStyle();
				if(null != xfs)
				{
					if(null != xfs.align)
						align = xfs.align;
					else
						align = g_oDefaultFormat.AlignAbs;
				}
			}
			else
			{
				var xfs = t.worksheet.getCompiledStyle(nRow, nCol);
				if (null != xfs && null != xfs.align) {
					align = xfs.align;
				}
			}
		});
		return align;
	};
	Range.prototype.hasMerged=function(){
		var aMerged = this.worksheet.mergeManager.get(this.bbox);
		if(aMerged.all.length > 0)
			return aMerged.all[0].bbox;
		return null;
	};
	Range.prototype.mergeOpen=function(){
		this.worksheet.mergeManager.add(this.bbox, 1);
	};
	Range.prototype.merge=function(type){
		if(null == type)
			type = Asc.c_oAscMergeOptions.Merge;
		var oBBox = this.bbox;
		History.Create_NewPoint();
		History.StartTransaction();
		if(oBBox.r1 == oBBox.r2 && oBBox.c1 == oBBox.c2){
			if(type == Asc.c_oAscMergeOptions.MergeCenter)
				this.setAlignHorizontal(AscCommon.align_Center);
			History.EndTransaction();
			return;
		}
		if(this.hasMerged())
		{
			this.unmerge();
			if(type == Asc.c_oAscMergeOptions.MergeCenter)
			{
				//сбрасываем AlignHorizontal
				this.setAlignHorizontal(null);
				History.EndTransaction();
				return;
			}
		}
		//пробегаемся по границе диапазона, чтобы посмотреть какие границы нужно оставлять
		var oLeftBorder = null;
		var oTopBorder = null;
		var oRightBorder = null;
		var oBottomBorder = null;
		var nRangeType = this._getRangeType(oBBox);
		if(c_oRangeType.Range == nRangeType)
		{
			var oThis = this;
			var fGetBorder = function(bRow, v1, v2, v3, type)
			{
				var oRes = null;
				for(var i = v1; i <= v2; ++i)
				{
					var bNeedDelete = true;
					oThis.worksheet._getCellNoEmpty(bRow ? v3 : i, bRow ? i : v3, function(cell) {
						if(null != cell && null != cell.xfs && null != cell.xfs.border)
						{
							var border = cell.xfs.border;
							var oBorderProp;
							switch(type)
							{
								case 1: oBorderProp = border.l;break;
								case 2: oBorderProp = border.t;break;
								case 3: oBorderProp = border.r;break;
								case 4: oBorderProp = border.b;break;
							}
							if(false == oBorderProp.isEmpty())
							{
								if(null == oRes)
								{
									oRes = oBorderProp;
									bNeedDelete = false;
								}
								else if(true == oRes.isEqual(oBorderProp))
									bNeedDelete = false;
							}
						}
					});
					if(bNeedDelete)
					{
						oRes = null;
						break;
					}
				}
				return oRes;
			};
			oLeftBorder = fGetBorder(false, oBBox.r1, oBBox.r2, oBBox.c1, 1);
			oTopBorder = fGetBorder(true, oBBox.c1, oBBox.c2, oBBox.r1, 2);
			oRightBorder = fGetBorder(false, oBBox.r1, oBBox.r2, oBBox.c2, 3);
			oBottomBorder = fGetBorder(true, oBBox.c1, oBBox.c2, oBBox.r2, 4);
		}
		else if(c_oRangeType.Row == nRangeType)
		{
			this.worksheet._getRowNoEmpty(oBBox.r1, function(row){
				if(row && null != row.xfs && null != row.xfs.border && false == row.xfs.border.t.isEmpty())
					oTopBorder = row.xfs.border.t;
			});
			if(oBBox.r1 != oBBox.r2)
			{
				this.worksheet._getRowNoEmpty(oBBox.r2, function(row){
					if(row && null != row.xfs && null != row.xfs.border && false == row.xfs.border.b.isEmpty())
						oBottomBorder = row.xfs.border.b;
				});
			}
		}
		else
		{
			var oLeftCol = this.worksheet._getColNoEmptyWithAll(oBBox.c1);
			if(null != oLeftCol && null != oLeftCol.xfs && null != oLeftCol.xfs.border && false == oLeftCol.xfs.border.l.isEmpty())
				oLeftBorder = oLeftCol.xfs.border.l;
			if(oBBox.c1 != oBBox.c2)
			{
				var oRightCol = this.worksheet._getColNoEmptyWithAll(oBBox.c2);
				if(null != oRightCol && null != oRightCol.xfs && null != oRightCol.xfs.border && false == oRightCol.xfs.border.r.isEmpty())
					oRightBorder = oRightCol.xfs.border.r;
			}
		}

		var bFirst = true;
		var oLeftTopCellStyle = null;
		var oFirstCellStyle = null;
		var oFirstCellValue = null;
		var oFirstCellRow = null;
		var oFirstCellCol = null;
		var oFirstCellHyperlink = null;
		this._setPropertyNoEmpty(null,null,
								 function(cell, nRow0, nCol0, nRowStart, nColStart){
									 if(bFirst && false == cell.isNullText())
									 {
										 bFirst = false;
										 oFirstCellStyle = cell.getStyle();
										 oFirstCellValue = cell.getValueData();
										 oFirstCellRow = cell.nRow;
										 oFirstCellCol = cell.nCol;

									 }
									 if(nRow0 == nRowStart && nCol0 == nColStart)
										 oLeftTopCellStyle = cell.getStyle();
								 });
		//правила работы с гиперссылками во время merge(отличются от Excel в случаем областей, например hyperlink: C3:D3 мержим C2:C3)
		// 1)оставляем все ссылки, которые не полностью лежат в merge области
		// 2)оставляем многоклеточные ссылки, top граница которых совпадает с top границей merge области, а высота merge > 1 или совпадает с высотой области merge
		// 3)оставляем и переносим в первую ячейку одну одноклеточную ссылку, если она находится в первой ячейке с данными
		var aHyperlinks = this.worksheet.hyperlinkManager.get(oBBox);
		var aHyperlinksToRestore = [];
		for(var i = 0, length = aHyperlinks.inner.length; i < length; i++)
		{
			var elem = aHyperlinks.inner[i];
			if(oFirstCellRow == elem.bbox.r1 && oFirstCellCol == elem.bbox.c1 && elem.bbox.r1 == elem.bbox.r2 && elem.bbox.c1 == elem.bbox.c2)
			{
				var oNewHyperlink = elem.data.clone();
				oNewHyperlink.Ref.setOffset(new AscCommon.CellBase(oBBox.r1 - oFirstCellRow, oBBox.c1 - oFirstCellCol));
				aHyperlinksToRestore.push(oNewHyperlink);
			}
			else if( oBBox.r1 == elem.bbox.r1 && (elem.bbox.r1 != elem.bbox.r2 || (elem.bbox.c1 != elem.bbox.c2 && oBBox.r1 == oBBox.r2)))
				aHyperlinksToRestore.push(elem.data);
		}
		this.cleanAll();
		//восстанавливаем hyperlink
		for(var i = 0, length = aHyperlinksToRestore.length; i < length; i++)
		{
			var elem = aHyperlinksToRestore[i];
			this.worksheet.hyperlinkManager.add(elem.Ref.getBBox0(), elem);
		}
		var oTargetStyle = null;
		if(null != oFirstCellValue && null != oFirstCellRow && null != oFirstCellCol)
		{
			if(null != oFirstCellStyle)
				oTargetStyle = oFirstCellStyle.clone();
			this.worksheet._getCell(oBBox.r1, oBBox.c1, function(cell){
				cell.setValueData(oFirstCellValue);
			});
			if(null != oFirstCellHyperlink)
			{
				var oLeftTopRange = this.worksheet.getCell3(oBBox.r1, oBBox.c1);
				oLeftTopRange.setHyperlink(oFirstCellHyperlink, true);
			}
		}
		else if(null != oLeftTopCellStyle)
			oTargetStyle = oLeftTopCellStyle.clone();

		//убираем бордеры
		if(null != oTargetStyle)
		{
			if(null != oTargetStyle.border)
				oTargetStyle.border = null;
		}
		else if(null != oLeftBorder || null != oTopBorder || null != oRightBorder || null != oBottomBorder)
			oTargetStyle = new AscCommonExcel.CellXfs();
		var fSetProperty = this._setProperty;
		var nRangeType = this._getRangeType();
		if(c_oRangeType.All == nRangeType)
		{
			fSetProperty = this._setPropertyNoEmpty;
			oTargetStyle = null
		}
		fSetProperty.call(this, function(row){
							  if(null == oTargetStyle)
								  row.setStyle(null);
							  else
							  {
								  var oNewStyle = oTargetStyle.clone();
								  if(row.index == oBBox.r1 && null != oTopBorder)
								  {
									  oNewStyle.border = new Border();
									  oNewStyle.border.t = oTopBorder.clone();
								  }
								  else if(row.index == oBBox.r2 && null != oBottomBorder)
								  {
									  oNewStyle.border = new Border();
									  oNewStyle.border.b = oBottomBorder.clone();
								  }
								  row.setStyle(oNewStyle);
							  }
						  },function(col){
							  if(null == oTargetStyle)
								  col.setStyle(null);
							  else
							  {
								  var oNewStyle = oTargetStyle.clone();
								  if(col.index == oBBox.c1 && null != oLeftBorder)
								  {
									  oNewStyle.border = new Border();
									  oNewStyle.border.l = oLeftBorder.clone();
								  }
								  else if(col.index == oBBox.c2 && null != oRightBorder)
								  {
									  oNewStyle.border = new Border();
									  oNewStyle.border.r = oRightBorder.clone();
								  }
								  col.setStyle(oNewStyle);
							  }
						  },
						  function(cell, nRow, nCol, nRowStart, nColStart){
							  //важно установить именно здесь, чтобы ячейка не удалилась после применения стилей.
							  if(null == oTargetStyle)
								  cell.setStyle(null);
							  else
							  {
								  var oNewStyle = oTargetStyle.clone();
								  if(oBBox.r1 == nRow && oBBox.c1 == nCol)
								  {
									  if(null != oLeftBorder || null != oTopBorder || (oBBox.r1 == oBBox.r2 && null != oBottomBorder) || (oBBox.c1 == oBBox.c2 && null != oRightBorder))
									  {
										  oNewStyle.border = new Border();
										  if(null != oLeftBorder)
											  oNewStyle.border.l = oLeftBorder.clone();
										  if(null != oTopBorder)
											  oNewStyle.border.t = oTopBorder.clone();
										  if(oBBox.r1 == oBBox.r2 && null != oBottomBorder)
											  oNewStyle.border.b = oBottomBorder.clone();
										  if(oBBox.c1 == oBBox.c2 && null != oRightBorder)
											  oNewStyle.border.r = oRightBorder.clone();
									  }
								  }
								  else if(oBBox.r1 == nRow && oBBox.c2 == nCol)
								  {
									  if(null != oRightBorder || null != oTopBorder || (oBBox.r1 == oBBox.r2 && null != oBottomBorder))
									  {
										  oNewStyle.border = new Border();
										  if(null != oRightBorder)
											  oNewStyle.border.r = oRightBorder.clone();
										  if(null != oTopBorder)
											  oNewStyle.border.t = oTopBorder.clone();
										  if(oBBox.r1 == oBBox.r2 && null != oBottomBorder)
											  oNewStyle.border.b = oBottomBorder.clone();
									  }
								  }
								  else if(oBBox.r2 == nRow && oBBox.c1 == nCol)
								  {
									  if(null != oLeftBorder || null != oBottomBorder || (oBBox.c1 == oBBox.c2 && null != oRightBorder))
									  {
										  oNewStyle.border = new Border();
										  if(null != oLeftBorder)
											  oNewStyle.border.l = oLeftBorder.clone();
										  if(null != oBottomBorder)
											  oNewStyle.border.b = oBottomBorder.clone();
										  if(oBBox.c1 == oBBox.c2 && null != oRightBorder)
											  oNewStyle.border.r = oRightBorder.clone();
									  }
								  }
								  else if(oBBox.r2 == nRow && oBBox.c2 == nCol)
								  {
									  if(null != oRightBorder || null != oBottomBorder)
									  {
										  oNewStyle.border = new Border();
										  if(null != oRightBorder)
											  oNewStyle.border.r = oRightBorder.clone();
										  if(null != oBottomBorder)
											  oNewStyle.border.b = oBottomBorder.clone();
									  }
								  }
								  else if(oBBox.r1 == nRow)
								  {
									  if(null != oTopBorder || (oBBox.r1 == oBBox.r2 && null != oBottomBorder))
									  {
										  oNewStyle.border = new Border();
										  if(null != oTopBorder)
											  oNewStyle.border.t = oTopBorder.clone();
										  if(oBBox.r1 == oBBox.r2 && null != oBottomBorder)
											  oNewStyle.border.b = oBottomBorder.clone();
									  }
								  }
								  else if(oBBox.r2 == nRow)
								  {
									  if(null != oBottomBorder)
									  {
										  oNewStyle.border = new Border();
										  oNewStyle.border.b = oBottomBorder.clone();
									  }
								  }
								  else if(oBBox.c1 == nCol)
								  {
									  if(null != oLeftBorder || (oBBox.c1 == oBBox.c2 && null != oRightBorder))
									  {
										  oNewStyle.border = new Border();
										  if(null != oLeftBorder)
											  oNewStyle.border.l = oLeftBorder.clone();
										  if(oBBox.c1 == oBBox.c2 && null != oRightBorder)
											  oNewStyle.border.r = oRightBorder.clone();
									  }
								  }
								  else if(oBBox.c2 == nCol)
								  {
									  if(null != oRightBorder)
									  {
										  oNewStyle.border = new Border();
										  oNewStyle.border.r = oRightBorder.clone();
									  }
								  }
								  cell.setStyle(oNewStyle);
							  }
						  });
		if(type == Asc.c_oAscMergeOptions.MergeCenter)
			this.setAlignHorizontal(AscCommon.align_Center);
		if(false == this.worksheet.workbook.bUndoChanges && false == this.worksheet.workbook.bRedoChanges)
			this.worksheet.mergeManager.add(this.bbox, 1);
		History.EndTransaction();
	};
	Range.prototype.unmerge=function(bOnlyInRange){
		History.Create_NewPoint();
		History.StartTransaction();
		if(false == this.worksheet.workbook.bUndoChanges && false == this.worksheet.workbook.bRedoChanges)
			this.worksheet.mergeManager.remove(this.bbox);
		History.EndTransaction();
	};
	Range.prototype._getHyperlinks=function(){
		var nRangeType = this._getRangeType();
		var result = [];
		var oThis = this;
		if(c_oRangeType.Range == nRangeType)
		{
			var oTempRows = {};
			var fAddToTempRows = function(oTempRows, bbox, data){
				if(null != bbox)
				{
					for(var i = bbox.r1; i <= bbox.r2; i++)
					{
						var row = oTempRows[i];
						if(null == row)
						{
							row = {};
							oTempRows[i] = row;
						}
						for(var j = bbox.c1; j <= bbox.c2; j++)
						{
							var cell = row[j];
							if(null == cell)
								row[j] = data;
						}
					}
				}
			};
			//todo возможно надо сделать оптимизацию для скрытых строк
			var aHyperlinks = this.worksheet.hyperlinkManager.get(this.bbox);
			for(var i = 0, length = aHyperlinks.all.length; i < length; i++)
			{
				var hyp = aHyperlinks.all[i];
				var hypBBox = hyp.bbox.intersectionSimple(this.bbox);
				fAddToTempRows(oTempRows, hypBBox, hyp.data);
				//расширяем гиперссылки на merge ячейках
				var aMerged = this.worksheet.mergeManager.get(hyp.bbox);
				for(var j = 0, length2 = aMerged.all.length; j < length2; j++)
				{
					var merge = aMerged.all[j];
					var mergeBBox = merge.bbox.intersectionSimple(this.bbox);
					fAddToTempRows(oTempRows, mergeBBox, hyp.data);
				}
			}
			//формируем результат
			for(var i in oTempRows)
			{
				var nRowIndex = i - 0;
				var row = oTempRows[i];
				for(var j in row)
				{
					var nColIndex = j - 0;
					var oCurHyp = row[j];
					result.push({hyperlink: oCurHyp, col: nColIndex, row: nRowIndex});
				}
			}
		}
		return result;
	};
	Range.prototype.getHyperlink=function(){
		var aHyperlinks = this._getHyperlinks();
		if(null != aHyperlinks && aHyperlinks.length > 0)
			return aHyperlinks[0].hyperlink;
		return null;
	};
	Range.prototype.getHyperlinks=function(){
		return this._getHyperlinks();
	};
	Range.prototype.setHyperlinkOpen=function(val){
		if(null != val && false == val.isValid())
			return;
		this.worksheet.hyperlinkManager.add(val.Ref.getBBox0(), val);
	};
	Range.prototype.setHyperlink=function(val, bWithoutStyle){
		if(null != val && false == val.isValid())
			return;
		//проверяем, может эта ссылка уже существует
		var i, length, hyp;
		var bExist = false;
		var aHyperlinks = this.worksheet.hyperlinkManager.get(this.bbox);
		for(i = 0, length = aHyperlinks.all.length; i < length; i++)
		{
			hyp = aHyperlinks.all[i];
			if(hyp.data.isEqual(val))
			{
				bExist = true;
				break;
			}
		}
		if(false == bExist)
		{
			History.Create_NewPoint();
			History.StartTransaction();
			if(false == this.worksheet.workbook.bUndoChanges && false == this.worksheet.workbook.bRedoChanges)
			{
				//удаляем ссылки с тем же адресом
				for(i = 0, length = aHyperlinks.all.length; i < length; i++)
				{
					hyp = aHyperlinks.all[i];
					if(hyp.bbox.isEqual(this.bbox))
						this.worksheet.hyperlinkManager.removeElement(hyp);
				}
			}
			//todo перейти на CellStyle
			if(true != bWithoutStyle)
			{
				var oHyperlinkFont = new AscCommonExcel.Font();
				oHyperlinkFont.setName(this.worksheet.workbook.getDefaultFont());
				oHyperlinkFont.setSize(this.worksheet.workbook.getDefaultSize());
				oHyperlinkFont.setUnderline(Asc.EUnderline.underlineSingle);
				oHyperlinkFont.setColor(AscCommonExcel.g_oColorManager.getThemeColor(AscCommonExcel.g_nColorHyperlink));
				this.setFont(oHyperlinkFont);
			}
			if(false == this.worksheet.workbook.bUndoChanges && false == this.worksheet.workbook.bRedoChanges)
				this.worksheet.hyperlinkManager.add(val.Ref.getBBox0(), val);
			History.EndTransaction();
		}
	};
	Range.prototype.removeHyperlink = function (val, removeStyle) {
		var bbox = this.bbox;
		var elem = null;
		if(null != val)
		{
			bbox = val.Ref.getBBox0();
			elem = new RangeDataManagerElem(bbox, val);
		}
		if(false == this.worksheet.workbook.bUndoChanges && false == this.worksheet.workbook.bRedoChanges)
		{
			History.Create_NewPoint();
			History.StartTransaction();
			var oChangeParam = { removeStyle: removeStyle };
			if(null != elem)
				this.worksheet.hyperlinkManager.removeElement(elem, oChangeParam);
			else
				this.worksheet.hyperlinkManager.remove(bbox, !bbox.isOneCell(), oChangeParam);
			History.EndTransaction();
		}
	};
	Range.prototype.deleteCellsShiftUp=function(preDeleteAction){
		return this._shiftUpDown(true, preDeleteAction);
	};
	Range.prototype.addCellsShiftBottom=function(displayNameFormatTable){
		return this._shiftUpDown(false, null, displayNameFormatTable);
	};
	Range.prototype.addCellsShiftRight=function(displayNameFormatTable){
		return this._shiftLeftRight(false, null,displayNameFormatTable);
	};
	Range.prototype.deleteCellsShiftLeft=function(preDeleteAction){
		return this._shiftLeftRight(true, preDeleteAction);
	};
	Range.prototype._canShiftLeftRight=function(bLeft){
		var aColsToDelete = [], aCellsToDelete = [];
		var oBBox = this.bbox;
		var nRangeType = this._getRangeType(oBBox);
		if(c_oRangeType.Range != nRangeType && c_oRangeType.Col != nRangeType)
			return null;

		var nWidth = oBBox.c2 - oBBox.c1 + 1;
		if(!bLeft && !this.worksheet.workbook.bUndoChanges && !this.worksheet.workbook.bRedoChanges){
			var rangeEdge = this.worksheet.getRange3(oBBox.r1, gc_nMaxCol0 - nWidth + 1, oBBox.r2, gc_nMaxCol0);
			var aMerged = this.worksheet.mergeManager.get(rangeEdge.bbox);
			if(aMerged.all.length > 0)
				return null;
			var aHyperlink = this.worksheet.hyperlinkManager.get(rangeEdge.bbox);
			if(aHyperlink.all.length > 0)
				return null;

			var bError = rangeEdge._setPropertyNoEmpty(null, function(col){
				if(null != col){
					if(null != col && null != col.xfs && null != col.xfs.fill && null != col.xfs.fill.getRgbOrNull())
						return true;
					aColsToDelete.push(col);
				}
			}, function(cell){
				if(null != cell){
					if(null != cell.xfs && null != cell.xfs.fill && null != cell.xfs.fill.getRgbOrNull())
						return true;
					if(!cell.isNullText())
						return true;
					aCellsToDelete.push(cell.nRow, cell.nCol);
				}
			});
			if(bError)
				return null;
		}
		return {aColsToDelete: aColsToDelete, aCellsToDelete: aCellsToDelete};
	};
	Range.prototype._shiftLeftRight=function(bLeft, preDeleteAction, displayNameFormatTable){
		var canShiftRes = this._canShiftLeftRight(bLeft);
		if(null === canShiftRes)
			return false;

		if (preDeleteAction)
			preDeleteAction();

		//удаляем крайние колонки и ячейки
		var i, length, colIndex;
		for(i = 0, length = canShiftRes.aColsToDelete.length; i < length; ++i){
			colIndex = canShiftRes.aColsToDelete[i].index;
			this.worksheet._removeCols(colIndex, colIndex);
		}
		for(i = 0; i < canShiftRes.aCellsToDelete.length; i+=2)
			this.worksheet._removeCell(canShiftRes.aCellsToDelete[i], canShiftRes.aCellsToDelete[i + 1]);

		var oBBox = this.bbox;
		var nWidth = oBBox.c2 - oBBox.c1 + 1;
		var nRangeType = this._getRangeType(oBBox);
		var mergeManager = this.worksheet.mergeManager;
		this.worksheet.workbook.dependencyFormulas.lockRecal();
		//todo вставить предупреждение, что будет unmerge
		History.Create_NewPoint();
		History.StartTransaction();
		var oShiftGet = null;
		if (false == this.worksheet.workbook.bUndoChanges && (false == this.worksheet.workbook.bRedoChanges || this.worksheet.workbook.bCollaborativeChanges))
		{
			History.LocalChange = true;
			oShiftGet = mergeManager.shiftGet(this.bbox, true);
			var aMerged = oShiftGet.elems;
			if(null != aMerged.outer && aMerged.outer.length > 0)
			{
				var bChanged = false;
				for(i = 0, length = aMerged.outer.length; i < length; i++)
				{
					var elem = aMerged.outer[i];
					if(!(elem.bbox.c1 < oShiftGet.bbox.c1 && oShiftGet.bbox.r1 <= elem.bbox.r1 && elem.bbox.r2 <= oShiftGet.bbox.r2))
					{
						mergeManager.removeElement(elem);
						bChanged = true;
					}
				}
				if(bChanged)
					oShiftGet = null;
			}
			History.LocalChange = false;
		}
		//сдвигаем ячейки
		if(bLeft)
		{
			if(c_oRangeType.Range == nRangeType)
				this.worksheet._shiftCellsLeft(oBBox);
			else
				this.worksheet._removeCols(oBBox.c1, oBBox.c2);
		}
		else
		{
			if(c_oRangeType.Range == nRangeType)
				this.worksheet._shiftCellsRight(oBBox, displayNameFormatTable);
			else
				this.worksheet._insertColsBefore(oBBox.c1, nWidth);
		}
		if (false == this.worksheet.workbook.bUndoChanges && (false == this.worksheet.workbook.bRedoChanges || this.worksheet.workbook.bCollaborativeChanges))
		{
			History.LocalChange = true;
			mergeManager.shift(this.bbox, !bLeft, true, oShiftGet);
			this.worksheet.hyperlinkManager.shift(this.bbox, !bLeft, true);
			History.LocalChange = false;
		}
		History.EndTransaction();
		this.worksheet.workbook.dependencyFormulas.unlockRecal();
		return true;
	};
	Range.prototype._canShiftUpDown=function(bUp){
		var aRowsToDelete = [], aCellsToDelete = [];
		var oBBox = this.bbox;
		var nRangeType = this._getRangeType(oBBox);
		if(c_oRangeType.Range != nRangeType && c_oRangeType.Row != nRangeType)
			return null;

		var nHeight = oBBox.r2 - oBBox.r1 + 1;
		if(!bUp && !this.worksheet.workbook.bUndoChanges && !this.worksheet.workbook.bRedoChanges){
			var rangeEdge = this.worksheet.getRange3(gc_nMaxRow0 - nHeight + 1, oBBox.c1, gc_nMaxRow0, oBBox.c2);
			var aMerged = this.worksheet.mergeManager.get(rangeEdge.bbox);
			if(aMerged.all.length > 0)
				return null;
			var aHyperlink = this.worksheet.hyperlinkManager.get(rangeEdge.bbox);
			if(aHyperlink.all.length > 0)
				return null;

			var bError = rangeEdge._setPropertyNoEmpty(function(row){
				if(null != row){
					if(null != row.xfs && null != row.xfs.fill && null != row.xfs.fill.getRgbOrNull())
						return true;
					aRowsToDelete.push(row.index);
				}
			}, null,  function(cell){
				if(null != cell){
					if(null != cell.xfs && null != cell.xfs.fill && null != cell.xfs.fill.getRgbOrNull())
						return true;
					if(!cell.isNullText())
						return true;
					aCellsToDelete.push(cell.nRow, cell.nCol);
				}
			});
			if(bError)
				return null;
		}
		return {aRowsToDelete: aRowsToDelete, aCellsToDelete: aCellsToDelete};
	};
	Range.prototype._shiftUpDown = function (bUp, preDeleteAction, displayNameFormatTable) {
		var canShiftRes = this._canShiftUpDown(bUp);
		if(null === canShiftRes)
			return false;

		if (preDeleteAction)
			preDeleteAction();

		//удаляем крайние колонки и ячейки
		var i, length, rowIndex;
		for(i = 0, length = canShiftRes.aRowsToDelete.length; i < length; ++i){
			rowIndex = canShiftRes.aRowsToDelete[i];
			this.worksheet._removeRows(rowIndex, rowIndex);
		}
		for(i = 0; i < canShiftRes.aCellsToDelete.length; i+=2)
			this.worksheet._removeCell(canShiftRes.aCellsToDelete[i], canShiftRes.aCellsToDelete[i + 1]);

		var oBBox = this.bbox;
		var nHeight = oBBox.r2 - oBBox.r1 + 1;
		var nRangeType = this._getRangeType(oBBox);
		var mergeManager = this.worksheet.mergeManager;
		this.worksheet.workbook.dependencyFormulas.lockRecal();
		//todo вставить предупреждение, что будет unmerge
		History.Create_NewPoint();
		History.StartTransaction();
		var oShiftGet = null;
		if (false == this.worksheet.workbook.bUndoChanges && (false == this.worksheet.workbook.bRedoChanges || this.worksheet.workbook.bCollaborativeChanges))
		{
			History.LocalChange = true;
			oShiftGet = mergeManager.shiftGet(this.bbox, false);
			var aMerged = oShiftGet.elems;
			if(null != aMerged.outer && aMerged.outer.length > 0)
			{
				var bChanged = false;
				for(i = 0, length = aMerged.outer.length; i < length; i++)
				{
					var elem = aMerged.outer[i];
					if(!(elem.bbox.r1 < oShiftGet.bbox.r1 && oShiftGet.bbox.c1 <= elem.bbox.c1 && elem.bbox.c2 <= oShiftGet.bbox.c2))
					{
						mergeManager.removeElement(elem);
						bChanged = true;
					}
				}
				if(bChanged)
					oShiftGet = null;
			}
			History.LocalChange = false;
		}
		//сдвигаем ячейки
		if(bUp)
		{
			if(c_oRangeType.Range == nRangeType)
				this.worksheet._shiftCellsUp(oBBox);
			else
				this.worksheet._removeRows(oBBox.r1, oBBox.r2);
		}
		else
		{
			if(c_oRangeType.Range == nRangeType)
				this.worksheet._shiftCellsBottom(oBBox, displayNameFormatTable);
			else
				this.worksheet._insertRowsBefore(oBBox.r1, nHeight);
		}
		if (false == this.worksheet.workbook.bUndoChanges && (false == this.worksheet.workbook.bRedoChanges || this.worksheet.workbook.bCollaborativeChanges))
		{
			History.LocalChange = true;
			mergeManager.shift(this.bbox, !bUp, false, oShiftGet);
			this.worksheet.hyperlinkManager.shift(this.bbox, !bUp, false);
			History.LocalChange = false;
		}
		History.EndTransaction();
		this.worksheet.workbook.dependencyFormulas.unlockRecal();
		return true;
	};
	Range.prototype.setOffset=function(offset){
		this.bbox.setOffset(offset);
	};
	Range.prototype.setOffsetFirst=function(offset){
		this.bbox.setOffsetFirst(offset);
	};
	Range.prototype.setOffsetLast=function(offset){
		this.bbox.setOffsetLast(offset);
	};
	Range.prototype.setOffsetWithAbs = function() {
		this.bbox.setOffsetWithAbs.apply(this.bbox, arguments);
	};
	Range.prototype.intersect=function(range){
		var oBBox1 = this.bbox;
		var oBBox2 = range.bbox;
		var r1 = Math.max(oBBox1.r1, oBBox2.r1);
		var c1 = Math.max(oBBox1.c1, oBBox2.c1);
		var r2 = Math.min(oBBox1.r2, oBBox2.r2);
		var c2 = Math.min(oBBox1.c2, oBBox2.c2);
		if(r1 <= r2 && c1 <= c2)
			return this.worksheet.getRange3(r1, c1, r2, c2);
		return null;
	};
	Range.prototype.cleanFormat=function(){
		History.Create_NewPoint();
		History.StartTransaction();
		this.unmerge();
		this._setPropertyNoEmpty(function(row){
			row.setStyle(null);
			// if(row.isEmpty())
			// row.Remove();
		},function(col){
			col.setStyle(null);
			// if(col.isEmpty())
			// col.Remove();
		},function(cell, nRow0, nCol0, nRowStart, nColStart){
			cell.setStyle(null);
			// if(cell.isEmpty())
			// cell.Remove();
		});
		History.EndTransaction();
	};
	Range.prototype.cleanText=function(){
		History.Create_NewPoint();
		History.StartTransaction();
		this._setPropertyNoEmpty(null, null,
								 function(cell, nRow0, nCol0, nRowStart, nColStart){
									 cell.setValue("");
									 // if(cell.isEmpty())
									 // cell.Remove();
								 });
		History.EndTransaction();
	};
	Range.prototype.cleanAll=function(){
		History.Create_NewPoint();
		History.StartTransaction();
		this.unmerge();
		//удаляем только гиперссылки, которые полностью лежат в области
		var aHyperlinks = this.worksheet.hyperlinkManager.get(this.bbox);
		for(var i = 0, length = aHyperlinks.inner.length; i < length; ++i)
			this.removeHyperlink(aHyperlinks.inner[i].data);
		var oThis = this;
		this._setPropertyNoEmpty(function(row){
			row.setStyle(null);
			// if(row.isEmpty())
			// row.Remove();
		},function(col){
			col.setStyle(null);
			// if(col.isEmpty())
			// col.Remove();
		},function(cell, nRow0, nCol0, nRowStart, nColStart){
			oThis.worksheet._removeCell(nRow0, nCol0, cell);
		});

		this.worksheet.workbook.dependencyFormulas.calcTree();
		History.EndTransaction();
	};
	Range.prototype.cleanHyperlinks=function(){
		History.Create_NewPoint();
		History.StartTransaction();
		//удаляем только гиперссылки, которые полностью лежат в области
		var aHyperlinks = this.worksheet.hyperlinkManager.get(this.bbox);
		for(var i = 0, length = aHyperlinks.inner.length; i < length; ++i)
			this.removeHyperlink(aHyperlinks.inner[i].data);
		History.EndTransaction();
	};
	Range.prototype.sort=function(nOption, nStartCol, sortColor, opt_guessHeader){
		var bbox = this.bbox;
		if (opt_guessHeader) {
			//если тип ячеек первого и второго row попарно совпадает, то считаем первую строку заголовком
			//todo рассмотреть замерженые ячейки. стили тоже влияют, но непонятно как сравнивать border


			var bIgnoreFirstRow = ignoreFirstRowSort(this.worksheet, bbox);

			if(bIgnoreFirstRow) {
				bbox = bbox.clone();
				bbox.r1++;
			}
		}
		//todo горизонтальная сортировка
		var aMerged = this.worksheet.mergeManager.get(bbox);
		if(aMerged.outer.length > 0 || (aMerged.inner.length > 0 && null == _isSameSizeMerged(bbox, aMerged.inner)))
			return null;
		var nMergedHeight = 1;
		if(aMerged.inner.length > 0)
		{
			var merged = aMerged.inner[0];
			nMergedHeight = merged.bbox.r2 - merged.bbox.r1 + 1;
			//меняем nStartCol, потому что приходит колонка той ячейки, на которой начали выделение
			nStartCol = merged.bbox.c1;
		}
		this.worksheet.workbook.dependencyFormulas.lockRecal();
		var colorFill = nOption === Asc.c_oAscSortOptions.ByColorFill;
		var colorText = nOption === Asc.c_oAscSortOptions.ByColorFont;
		var isSortColor = !!(colorFill || colorText);

		var oRes = null;
		var oThis = this;
		var bAscent = false;
		if(nOption == Asc.c_oAscSortOptions.Ascending)
			bAscent = true;
		var nRowFirst0 = bbox.r1;
		var nRowLast0 = bbox.r2;
		var nColFirst0 = bbox.c1;
		var nColLast0 = bbox.c2;
		var bWholeCol = false;
		var bWholeRow = false;
		if(0 == nRowFirst0 && gc_nMaxRow0 == nRowLast0)
			bWholeCol = true;
		if(0 == nColFirst0 && gc_nMaxCol0 == nColLast0)
			bWholeRow = true;
		var oRangeCol = this.worksheet.getRange(new CellAddress(nRowFirst0, nStartCol, 0), new CellAddress(nRowLast0, nStartCol, 0));
		var nLastRow0 = 0;
		var nLastCol0 = nColLast0;
		if(true == bWholeRow)
		{
			nLastCol0 = 0;
			this._foreachRowNoEmpty(null, function(cell){
				var nCurCol0 = cell.nCol;
				if(nCurCol0 > nLastCol0)
					nLastCol0 = nCurCol0;
			});
		}
		//собираем массив обьектов для сортировки
		var aSortElems = [];
		var fAddSortElems = function(oCell, nRow0, nCol0,nRowStart0, nColStart0){
			//не сортируем сткрытие строки
			if (!oThis.worksheet.getRowHidden(nRow0)) {
				if(nLastRow0 < nRow0)
					nLastRow0 = nRow0;
				var val = oCell.getValueWithoutFormat();

				//for sort color
				var colorFillCell, colorsTextCell = null;
				if(colorFill)
				{
					var styleCell = oCell.getStyle();
					colorFillCell = styleCell !== null && styleCell.fill ? styleCell.fill.bg : null;
				}
				else if(colorText)
				{
					var value2 = oCell.getValue2();
					for(var n = 0; n < value2.length; n++)
					{
						if(null === colorsTextCell)
						{
							colorsTextCell = [];
						}

						colorsTextCell.push(value2[n].format.getColor());
					}
				}

				var nNumber = null;
				var sText = null;
				if("" != val)
				{
					var nVal = val - 0;
					if(nVal == val)
						nNumber = nVal;
					else
						sText = val;
					aSortElems.push({row: nRow0, num: nNumber, text: sText, colorFill: colorFillCell, colorsText: colorsTextCell});
				}
				else if(isSortColor)
				{
					aSortElems.push({row: nRow0, num: nNumber, text: sText, colorFill: colorFillCell, colorsText: colorsTextCell});
				}
			}
		};
		if(nColFirst0 == nStartCol)
		{
			while(0 == aSortElems.length && nStartCol <= nLastCol0)
			{
				if(false == bWholeCol)
					oRangeCol._foreachNoEmpty(fAddSortElems);
				else
					oRangeCol._foreachColNoEmpty(null, fAddSortElems);
				if(0 == aSortElems.length)
				{
					nStartCol++;
					oRangeCol = this.worksheet.getRange(new CellAddress(nRowFirst0, nStartCol, 0), new CellAddress(nRowLast0, nStartCol, 0));
				}
			}
		}
		else
		{
			if(false == bWholeCol)
				oRangeCol._foreachNoEmpty(fAddSortElems);
			else
				oRangeCol._foreachColNoEmpty(null, fAddSortElems);
		}
		function strcmp ( str1, str2 ) {
			return ( ( str1 == str2 ) ? 0 : ( ( str1 > str2 ) ? 1 : -1 ) );
		}


		//color sort
		var colorFillCmp = function(color1, color2)
		{
			var res = false;
			//TODO возможно так сравнивать не правильно, позже пересмотреть
			if(colorFill)
			{
				res = (color1 !== null && color2 !== null && color1.rgb === color2.rgb) || (color1 === color2) ? true : false;
			}
			else if(colorText && color1 && color1.length)
			{
				for(var n = 0; n < color1.length; n++)
				{
					if(color1[n] && color2 !== null && color1[n].rgb === color2.rgb)
					{
						res = true;
						break;
					}
				}
			}

			return res;
		};

		if(isSortColor)
		{
			var newArrayNeedColor = [];
			var newArrayAnotherColor = [];

			for(var i = 0; i < aSortElems.length; i++)
			{
				var color = colorFill ? aSortElems[i].colorFill : aSortElems[i].colorsText;
				if(colorFillCmp(color, sortColor))
				{
					newArrayNeedColor.push(aSortElems[i]);
				}
				else
				{
					newArrayAnotherColor.push(aSortElems[i]);
				}
			}

			aSortElems = newArrayNeedColor.concat(newArrayAnotherColor);
		}
		else
		{
			aSortElems.sort(function(a, b){
				var res = 0;
				if(null != a.text)
				{
					if(null != b.text)
						res = strcmp(a.text.toUpperCase(), b.text.toUpperCase());
					else
						res = 1;
				}
				else if(null != a.num)
				{
					if(null != b.num)
						res = a.num - b.num;
					else
						res = -1;
				}
				if(0 == res)
					res = a.row - b.row;
				else if(!bAscent)
					res = -res;
				return res;
			});
		}

		//проверяем что это не пустая операция
		var aSortData = [];
		var nHiddenCount = 0;
		var oFromArray = {};
		var nRowMax = 0;
		var nRowMin = gc_nMaxRow0;
		var nToMax = 0;
		for(var i = 0, length = aSortElems.length; i < length; ++i)
		{
			var item = aSortElems[i];
			var nNewIndex = i * nMergedHeight + nRowFirst0 + nHiddenCount;
			while(false != oThis.worksheet.getRowHidden(nNewIndex))
			{
				nHiddenCount++;
				nNewIndex = i * nMergedHeight + nRowFirst0 + nHiddenCount;
			}
			var oNewElem = new UndoRedoData_FromToRowCol(true, item.row, nNewIndex);
			oFromArray[item.row] = 1;
			if(nRowMax < item.row)
				nRowMax = item.row;
			if(nRowMax < nNewIndex)
				nRowMax = nNewIndex;
			if(nRowMin > item.row)
				nRowMin = item.row;
			if(nRowMin > nNewIndex)
				nRowMin = nNewIndex;
			if(nToMax < nNewIndex)
				nToMax = nNewIndex;
			if(oNewElem.from != oNewElem.to)
				aSortData.push(oNewElem);
		}
		if(aSortData.length > 0)
		{
			//добавляем индексы перехода пустых ячеек(нужно для сортировки комментариев)
			for(var i = nRowMin; i <= nRowMax; ++i)
			{
				if(null == oFromArray[i] && false == oThis.worksheet.getRowHidden(i))
				{
					var nFrom = i;
					var nTo = ++nToMax;
					while(false != oThis.worksheet.getRowHidden(nTo))
						nTo = ++nToMax;
					if(nFrom != nTo)
					{
						var oNewElem = new UndoRedoData_FromToRowCol(true, nFrom, nTo);
						aSortData.push(oNewElem);
					}
				}
			}
			History.Create_NewPoint();
			var oSelection = History.GetSelection();
			if(null != oSelection)
			{
				oSelection = oSelection.clone();
				oSelection.assign(nColFirst0, nRowFirst0, nLastCol0, nLastRow0);
				History.SetSelection(oSelection);
				History.SetSelectionRedo(oSelection);
			}
			var oUndoRedoBBox = new UndoRedoData_BBox({r1:nRowFirst0, c1:nColFirst0, r2:nLastRow0, c2:nLastCol0});
			oRes = new AscCommonExcel.UndoRedoData_SortData(oUndoRedoBBox, aSortData);
			this._sortByArray(oUndoRedoBBox, aSortData);
			History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_Sort, this.worksheet.getId(), new Asc.Range(0, nRowFirst0, gc_nMaxCol0, nLastRow0), oRes);
		}
		this.worksheet.workbook.dependencyFormulas.unlockRecal();
		return oRes;
	};
	Range.prototype._sortByArray=function(oBBox, aSortData, bUndo){
		var t = this;
		var height = oBBox.r2 - oBBox.r1 + 1;
		var oSortedIndexes = {};
		for(var i = 0, length = aSortData.length; i < length; ++i)
		{
			var item = aSortData[i];
			var nFrom = item.from;
			var nTo = item.to;
			if(true == this.worksheet.workbook.bUndoChanges)
			{
				nFrom = item.to;
				nTo = item.from;
			}
			oSortedIndexes[nFrom] = nTo;
		}
		//сортируются только одинарные гиперссылки, все неодинарные оставляем
		var aSortedHyperlinks = [];
		if(false == this.worksheet.workbook.bUndoChanges && (false == this.worksheet.workbook.bRedoChanges || this.worksheet.workbook.bCollaborativeChanges))
		{
			History.LocalChange = true;
			var aHyperlinks = this.worksheet.hyperlinkManager.get(this.bbox);
			for(var i = 0, length = aHyperlinks.inner.length; i < length; i++)
			{
				var elem = aHyperlinks.inner[i];
				var hyp = elem.data;
				if(hyp.Ref.isOneCell())
				{
					var nFrom = elem.bbox.r1;
					var nTo = oSortedIndexes[nFrom];
					if(null != nTo)
					{
						//удаляем ссылки, а не перемещаем, чтобы не было конфликтов(например в случае если все ячейки имеют ссылки
						// и их надо передвинуть)
						var oTempBBox = hyp.Ref.getBBox0();
						this.worksheet.hyperlinkManager.removeElement(new RangeDataManagerElem(oTempBBox, hyp));
						var oNewHyp = hyp.clone();
						oNewHyp.Ref.setOffset(new AscCommon.CellBase(nTo - nFrom, 0));
						aSortedHyperlinks.push(oNewHyp);
					}
				}
			}
			History.LocalChange = false;
		}
		var t = this;
		var tempRange = this.worksheet.getRange3(oBBox.r1, oBBox.c1, oBBox.r2, oBBox.c2);
		tempRange._foreachNoEmpty(function(cell){
			var ws = t.worksheet;
			var formula = cell.getFormulaParsed();
			if (formula) {
				var cellWithFormula = formula.getParent();
				var nFrom = cell.nRow;
				var nTo = oSortedIndexes[nFrom];
				if(null != nTo) {
					cell.changeOffset(new AscCommon.CellBase(nTo - nFrom, 0), true, true);
					formula = cell.getFormulaParsed();
					cellWithFormula = formula.getParent();
					cellWithFormula.nRow = nTo;
				}
				ws.workbook.dependencyFormulas.addToChangedCell(cellWithFormula);
			}
		});
		var tempSheetMemory = new SheetMemory(g_nCellStructSize, height);
		for (var i = oBBox.c1; i <= oBBox.c2; ++i) {
			var sheetMemory = this.worksheet.getColDataNoEmpty(i);
			if (sheetMemory) {
				tempSheetMemory.copyRange(sheetMemory, oBBox.r1, 0, height);
				for (var j in oSortedIndexes) {
					var nIndexFrom = j - 0;
					var nIndexTo = oSortedIndexes[j];
					tempSheetMemory.copyRange(sheetMemory, nIndexFrom, nIndexTo - oBBox.r1, 1);
				}
				sheetMemory.copyRange(tempSheetMemory, 0, oBBox.r1, height);
			}
		}
		this.worksheet.workbook.dependencyFormulas.addToChangedRange(this.worksheet.getId(), new Asc.Range(oBBox.c1, oBBox.r1, oBBox.c2, oBBox.r2));

		this.worksheet.workbook.dependencyFormulas.calcTree();
		if(false == this.worksheet.workbook.bUndoChanges && (false == this.worksheet.workbook.bRedoChanges || this.worksheet.workbook.bCollaborativeChanges))
		{
			History.LocalChange = true;
			//восстанавливаем удаленые гиперссылки
			if(aSortedHyperlinks.length > 0)
			{
				for(var i = 0, length = aSortedHyperlinks.length; i < length; i++)
				{
					var hyp = aSortedHyperlinks[i];
					this.worksheet.hyperlinkManager.add(hyp.Ref.getBBox0(), hyp);
				}
			}
			History.LocalChange = false;
		}
	};
	function _isSameSizeMerged(bbox, aMerged) {
		var oRes = null;
		var nWidth = null;
		var nHeight = null;
		for(var i = 0, length = aMerged.length; i < length; i++)
		{
			var mergedBBox = aMerged[i].bbox;
			var nCurWidth = mergedBBox.c2 - mergedBBox.c1 + 1;
			var nCurHeight = mergedBBox.r2 - mergedBBox.r1 + 1;
			if(null == nWidth || null == nHeight)
			{
				nWidth = nCurWidth;
				nHeight = nCurHeight;
			}
			else if(nCurWidth != nWidth || nCurHeight != nHeight)
			{
				nWidth = null;
				nHeight = null;
				break;
			}
		}
		if(null != nWidth && null != nHeight)
		{
			//проверяем что merge ячеки полностью заполняют область
			var nBBoxWidth = bbox.c2 - bbox.c1 + 1;
			var nBBoxHeight = bbox.r2 - bbox.r1 + 1;
			if(nBBoxWidth == nWidth || nBBoxHeight == nHeight)
			{
				var bRes = false;
				var aRowColTest = null;
				if(nBBoxWidth == nWidth && nBBoxHeight == nHeight)
					bRes = true;
				else if(nBBoxWidth == nWidth)
				{
					aRowColTest = new Array(nBBoxHeight);
					for(var i = 0, length = aMerged.length; i < length; i++)
					{
						var merged = aMerged[i];
						for(var j = merged.bbox.r1; j <= merged.bbox.r2; j++)
							aRowColTest[j - bbox.r1] = 1;
					}
				}
				else if(nBBoxHeight == nHeight)
				{
					aRowColTest = new Array(nBBoxWidth);
					for(var i = 0, length = aMerged.length; i < length; i++)
					{
						var merged = aMerged[i];
						for(var j = merged.bbox.c1; j <= merged.bbox.c2; j++)
							aRowColTest[j - bbox.c1] = 1;
					}
				}
				if(null != aRowColTest)
				{
					var bExistNull = false;
					for(var i = 0, length = aRowColTest.length; i < length; i++)
					{
						if(null == aRowColTest[i])
						{
							bExistNull = true;
							break;
						}
					}
					if(!bExistNull)
						bRes = true;
				}
				if(bRes)
					oRes = {width: nWidth, height: nHeight};
			}
		}
		return oRes;
	}
	function _canPromote(from, wsFrom, to, wsTo, bIsPromote, nWidth, nHeight, bVertical, nIndex) {
		var oRes = {oMergedFrom: null, oMergedTo: null, to: to};
		//если надо только удалить внутреннее содержимое не смотрим на замерженость
		if(!bIsPromote || !((true == bVertical && nIndex >= 0 && nIndex < nHeight) || (false == bVertical && nIndex >= 0 && nIndex < nWidth)))
		{
			if(null != to){
				var oMergedTo = wsTo.mergeManager.get(to);
				if(oMergedTo.outer.length > 0)
					oRes = null;
				else
				{
					var oMergedFrom = wsFrom.mergeManager.get(from);
					oRes.oMergedFrom = oMergedFrom;
					if(oMergedTo.inner.length > 0)
					{
						oRes.oMergedTo = oMergedTo;
						if (bIsPromote) {
							if (oMergedFrom.inner.length > 0) {
								//merge области должны иметь одинаковый размер
								var oSizeFrom = _isSameSizeMerged(from, oMergedFrom.inner);
								var oSizeTo = _isSameSizeMerged(to, oMergedTo.inner);
								if (!(null != oSizeFrom && null != oSizeTo && oSizeTo.width == oSizeFrom.width && oSizeTo.height == oSizeFrom.height))
									oRes = null;
							}
							else
								oRes = null;
						}
					}
				}
			}
		}
		return oRes;
	}
// Подготовка Copy Style
	function preparePromoteFromTo(from, to) {
		var bSuccess = true;
		if (to.isOneCell())
			to.setOffsetLast(new AscCommon.CellBase((from.r2 - from.r1) - (to.r2 - to.r1), (from.c2 - from.c1) - (to.c2 - to.c1)));

		if(!from.isIntersect(to)) {
			var bFromWholeCol = (0 == from.c1 && gc_nMaxCol0 == from.c2);
			var bFromWholeRow = (0 == from.r1 && gc_nMaxRow0 == from.r2);
			var bToWholeCol = (0 == to.c1 && gc_nMaxCol0 == to.c2);
			var bToWholeRow = (0 == to.r1 && gc_nMaxRow0 == to.r2);
			bSuccess = (bFromWholeCol === bToWholeCol && bFromWholeRow === bToWholeRow);
		} else
			bSuccess = false;
		return bSuccess;
	}
// Перед promoteFromTo обязательно должна быть вызывана функция preparePromoteFromTo
	function promoteFromTo(from, wsFrom, to, wsTo) {
		var bVertical = true;
		var nIndex = 1;
		//проверяем можно ли осуществить promote
		var oCanPromote = _canPromote(from, wsFrom, to, wsTo, false, 1, 1, bVertical, nIndex);
		if(null != oCanPromote)
		{
			History.Create_NewPoint();
			var oSelection = History.GetSelection();
			if(null != oSelection)
			{
				oSelection = oSelection.clone();
				oSelection.assign(from.c1, from.r1, from.c2, from.r2);
				History.SetSelection(oSelection);
			}
			var oSelectionRedo = History.GetSelectionRedo();
			if(null != oSelectionRedo)
			{
				oSelectionRedo = oSelectionRedo.clone();
				oSelectionRedo.assign(to.c1, to.r1, to.c2, to.r2);
				History.SetSelectionRedo(oSelectionRedo);
			}
			//удаляем merge ячейки в to(после _canPromote должны остаться только inner)
			wsTo.mergeManager.remove(to, true);
			_promoteFromTo(from, wsFrom, to, wsTo, false, oCanPromote, false, bVertical, nIndex);
		}
	}
	Range.prototype.canPromote=function(bCtrl, bVertical, nIndex){
		var oBBox = this.bbox;
		var nWidth = oBBox.c2 - oBBox.c1 + 1;
		var nHeight = oBBox.r2 - oBBox.r1 + 1;
		var bWholeCol = false;	var bWholeRow = false;
		if(0 == oBBox.r1 && gc_nMaxRow0 == oBBox.r2)
			bWholeCol = true;
		if(0 == oBBox.c1 && gc_nMaxCol0 == oBBox.c2)
			bWholeRow = true;
		if((bWholeCol && bWholeRow) || (true == bVertical && bWholeCol) || (false == bVertical && bWholeRow))
			return null;
		var oPromoteAscRange = null;
		if(0 == nIndex)
			oPromoteAscRange = Asc.Range(oBBox.c1, oBBox.r1, oBBox.c2, oBBox.r2);
		else
		{
			if(bVertical)
			{
				if(nIndex > 0)
				{
					if(nIndex >= nHeight)
						oPromoteAscRange = Asc.Range(oBBox.c1, oBBox.r2 + 1, oBBox.c2, oBBox.r1 + nIndex);
					else
						oPromoteAscRange = Asc.Range(oBBox.c1, oBBox.r1 + nIndex, oBBox.c2, oBBox.r2);
				}
				else
					oPromoteAscRange = Asc.Range(oBBox.c1, oBBox.r1 + nIndex, oBBox.c2, oBBox.r1 - 1);
			}
			else
			{
				if(nIndex > 0)
				{
					if(nIndex >= nWidth)
						oPromoteAscRange = Asc.Range(oBBox.c2 + 1, oBBox.r1, oBBox.c1 + nIndex, oBBox.r2);
					else
						oPromoteAscRange = Asc.Range(oBBox.c1 + nIndex, oBBox.r1, oBBox.c2, oBBox.r2);
				}
				else
					oPromoteAscRange = Asc.Range(oBBox.c1 + nIndex, oBBox.r1, oBBox.c1 - 1, oBBox.r2);
			}
		}
		//проверяем можно ли осуществить promote
		return _canPromote(oBBox, this.worksheet, oPromoteAscRange, this.worksheet, true, nWidth, nHeight, bVertical, nIndex);
	};
	Range.prototype.promote=function(bCtrl, bVertical, nIndex, oCanPromote){
		//todo отдельный метод для promote в таблицах и merge в таблицах
		if (!oCanPromote) {
			oCanPromote = this.canPromote(bCtrl, bVertical, nIndex);
		}
		var oBBox = this.bbox;
		var nWidth = oBBox.c2 - oBBox.c1 + 1;
		var nHeight = oBBox.r2 - oBBox.r1 + 1;

		History.Create_NewPoint();
		var oSelection = History.GetSelection();
		if(null != oSelection)
		{
			oSelection = oSelection.clone();
			oSelection.assign(oBBox.c1, oBBox.r1, oBBox.c2, oBBox.r2);
			History.SetSelection(oSelection);
		}
		var oSelectionRedo = History.GetSelectionRedo();
		if(null != oSelectionRedo)
		{
			oSelectionRedo = oSelectionRedo.clone();
			if(0 == nIndex)
				oSelectionRedo.assign(oBBox.c1, oBBox.r1, oBBox.c2, oBBox.r2);
			else
			{
				if(bVertical)
				{
					if(nIndex > 0)
					{
						if(nIndex >= nHeight)
							oSelectionRedo.assign(oBBox.c1, oBBox.r1, oBBox.c2, oBBox.r1 + nIndex);
						else
							oSelectionRedo.assign(oBBox.c1, oBBox.r1, oBBox.c2, oBBox.r1 + nIndex - 1);
					}
					else
						oSelectionRedo.assign(oBBox.c1, oBBox.r1 + nIndex, oBBox.c2, oBBox.r2);
				}
				else
				{
					if(nIndex > 0)
					{
						if(nIndex >= nWidth)
							oSelectionRedo.assign(oBBox.c1, oBBox.r1, oBBox.c1 + nIndex, oBBox.r2);
						else
							oSelectionRedo.assign(oBBox.c1, oBBox.r1, oBBox.c1 + nIndex - 1, oBBox.r2);
					}
					else
						oSelectionRedo.assign(oBBox.c1 + nIndex, oBBox.r1, oBBox.c2, oBBox.r2);
				}
			}
			History.SetSelectionRedo(oSelectionRedo);
		}
		_promoteFromTo(oBBox, this.worksheet, oCanPromote.to, this.worksheet, true, oCanPromote, bCtrl, bVertical, nIndex);
	};
	function _promoteFromTo(from, wsFrom, to, wsTo, bIsPromote, oCanPromote, bCtrl, bVertical, nIndex) {
		var wb = wsFrom.workbook;

		wb.dependencyFormulas.lockRecal();
		History.StartTransaction();

		var oldExcludeHiddenRows = wsFrom.bExcludeHiddenRows;
		if(wsFrom.autoFilters.bIsExcludeHiddenRows(from, wsFrom.selectionRange.activeCell)){
			wsFrom.excludeHiddenRows(true);
		}

		var toRange = wsTo.getRange3(to.r1, to.c1, to.r2, to.c2);
		var fromRange = wsFrom.getRange3(from.r1, from.c1, from.r2, from.c2);
		var bChangeRowColProp = false;
		var nLastCol = from.c2;
		if (0 == from.c1 && gc_nMaxCol0 == from.c2)
		{
			var aRowProperties = [];
			nLastCol = 0;
			fromRange._foreachRowNoEmpty(function(row){
				if(!row.isEmptyProp())
					aRowProperties.push({index: row.index - from.r1, prop: row.getHeightProp(), style: row.getStyle()});
			}, function(cell){
				var nCurCol0 = cell.nCol;
				if(nCurCol0 > nLastCol)
					nLastCol = nCurCol0;
			});
			if(aRowProperties.length > 0)
			{
				bChangeRowColProp = true;
				var nCurCount = 0;
				var nCurIndex = 0;
				while (true) {
					for (var i = 0, length = aRowProperties.length; i < length; ++i) {
						var propElem = aRowProperties[i];
						nCurIndex = to.r1 + nCurCount * (from.r2 - from.r1 + 1) + propElem.index;
						if (nCurIndex > to.r2)
							break;
						else{
							wsTo._getRow(nCurIndex, function(row) {
								if (null != propElem.style)
									row.setStyle(propElem.style);
								if (null != propElem.prop) {
									var oNewProps = propElem.prop;
									var oOldProps = row.getHeightProp();
									if (false === oOldProps.isEqual(oNewProps)) {
										row.setHeightProp(oNewProps);
										History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_RowProp, wsTo.getId(), row._getUpdateRange(), new UndoRedoData_IndexSimpleProp(nCurIndex, true, oOldProps, oNewProps));
									}
								}
							});
						}
					}
					nCurCount++;
					if (nCurIndex > to.r2)
						break;
				}
			}
		}
		var nLastRow = from.r2;
		if (0 == from.r1 && gc_nMaxRow0 == from.r2)
		{
			var aColProperties = [];
			nLastRow = 0;
			fromRange._foreachColNoEmpty(function(col){
				if(!col.isEmpty())
					aColProperties.push({ index: col.index - from.c1, prop: col.getWidthProp(), style: col.getStyle() });
			}, function(cell){
				var nCurRow0 = cell.nRow;
				if(nCurRow0 > nLastRow)
					nLastRow = nCurRow0;
			});
			if (aColProperties.length > 0)
			{
				bChangeRowColProp = true;
				var nCurCount = 0;
				var nCurIndex = 0;
				while (true) {
					for (var i = 0, length = aColProperties.length; i < length; ++i) {
						var propElem = aColProperties[i];
						nCurIndex = to.c1 + nCurCount * (from.c2 - from.c1 + 1) + propElem.index;
						if (nCurIndex > to.c2)
							break;
						else{
							var col = wsTo._getCol(nCurIndex);
							if (null != propElem.style)
								col.setStyle(propElem.style);
							if (null != propElem.prop) {
								var oNewProps = propElem.prop;
								var oOldProps = col.getWidthProp();
								if (false == oOldProps.isEqual(oNewProps)) {
									col.setWidthProp(oNewProps);
									wsTo.initColumn(col);
									History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_ColProp, wsTo.getId(), new Asc.Range(nCurIndex, 0, nCurIndex, gc_nMaxRow0), new UndoRedoData_IndexSimpleProp(nCurIndex, false, oOldProps, oNewProps));
								}
							}
						}
					}
					nCurCount++;
					if (nCurIndex > to.c2)
						break;
				}
			}
		}
		if (bChangeRowColProp)
			wb.handlers.trigger("changeWorksheetUpdate", wsTo.getId());
		if(nLastCol != from.c2 || nLastRow != from.r2)
		{
			var offset = new AscCommon.CellBase(nLastRow - from.r2, nLastCol - from.c2);
			toRange.setOffsetLast(offset);
			to = toRange.getBBox0();
			fromRange.setOffsetLast(offset);
			from = fromRange.getBBox0();
		}
		var nWidth = from.c2 - from.c1 + 1;
		var nHeight = from.r2 - from.r1 + 1;
		//удаляем текст или все в области для заполнения
		if(bIsPromote && nIndex >= 0 && ((true == bVertical && nHeight > nIndex) || (false == bVertical && nWidth > nIndex)))
		{
			//удаляем только текст в области для заполнения
			toRange.cleanText();
		}
		else
		{
			//удаляем все в области для заполнения
			if(bIsPromote)
				toRange.cleanAll();
			else
				toRange.cleanFormat();
			//собираем все данные
			var bReverse = false;
			if(nIndex < 0)
				bReverse = true;
			var oPromoteHelper = new PromoteHelper(bVertical, bReverse, from);
			fromRange._foreachNoEmpty(function(oCell, nRow0, nCol0, nRowStart0, nColStart0){
				if(null != oCell)
				{
					var nVal = null;
					var bDelimiter = false;
					var sPrefix = null;
					var padding = 0;
					var bDate = false;
					if(bIsPromote)
					{
						if (!oCell.isFormula())
						{
							var sValue = oCell.getValueWithoutFormat();
							if("" != sValue)
							{
								bDelimiter = true;
								var nType = oCell.getType();
								if(CellValueType.Number == nType || CellValueType.String == nType)
								{
									if(CellValueType.Number == nType)
										nVal = sValue - 0;
									else
									{
										//если текст заканчивается на цифру тоже используем ее
										var nEndIndex = sValue.length;
										for(var k = sValue.length - 1; k >= 0; --k)
										{
											var sCurChart = sValue[k];
											if('0' <= sCurChart && sCurChart <= '9')
												nEndIndex--;
											else
												break;
										}
										if(sValue.length != nEndIndex)
										{
											sPrefix = sValue.substring(0, nEndIndex);
											var sNumber = sValue.substring(nEndIndex);
											//sNumber have no decimal point, so can use simple parseInt
											nVal = sNumber - 0;
											padding = sNumber[0] === '0' ? sNumber.length : 0;
										}
									}
								}
								if(null != oCell.xfs && null != oCell.xfs.num && null != oCell.xfs.num.getFormat()){
									var numFormat = oNumFormatCache.get(oCell.xfs.num.getFormat());
									if(numFormat.isDateTimeFormat())
										bDate = true;
								}
								if(null != nVal)
									bDelimiter = false;
							}
						}
						else
							bDelimiter = true;
					}
					oPromoteHelper.add(nRow0 - nRowStart0, nCol0 - nColStart0, nVal, bDelimiter, sPrefix, padding, bDate, oCell.duplicate());
				}
			});
			var bCopy = false;
			if(bCtrl)
				bCopy = true;
			//в случае одной ячейки с числом меняется смысл bCtrl
			if(1 == nWidth && 1 == nHeight && oPromoteHelper.isOnlyIntegerSequence())
				bCopy = !bCopy;
			oPromoteHelper.finishAdd(bCopy);
			//заполняем ячейки данными
			var nStartRow, nEndRow, nStartCol, nEndCol, nColDx, bRowFirst;
			if(bVertical)
			{
				nStartRow = to.c1;
				nEndRow = to.c2;
				bRowFirst = false;
				if(bReverse)
				{
					nStartCol = to.r2;
					nEndCol = to.r1;
					nColDx = -1;
				}
				else
				{
					nStartCol = to.r1;
					nEndCol = to.r2;
					nColDx = 1;
				}
			}
			else
			{
				nStartRow = to.r1;
				nEndRow = to.r2;
				bRowFirst = true;
				if(bReverse)
				{
					nStartCol = to.c2;
					nEndCol = to.c1;
					nColDx = -1;
				}
				else
				{
					nStartCol = to.c1;
					nEndCol = to.c2;
					nColDx = 1;
				}
			}
			for(var i = nStartRow; i <= nEndRow; i ++)
			{
				oPromoteHelper.setIndex(i - nStartRow);
				for(var j = nStartCol; (nStartCol - j) * (nEndCol - j) <= 0; j += nColDx)
				{
					if (bVertical && wsTo.bExcludeHiddenRows && wsTo.getRowHidden(j))
					{
						continue;
					}

					var data = oPromoteHelper.getNext();
					if(null != data && (data.oAdditional || (false == bCopy && null != data.nCurValue)))
					{
						var oFromCell = data.oAdditional;
						var nRow = bRowFirst ? i : j;
						var nCol = bRowFirst ? j : i;
						wsTo._getCell(nRow, nCol, function(oCopyCell){
							if(bIsPromote)
							{
								if(false == bCopy && null != data.nCurValue)
								{
									var oCellValue = new AscCommonExcel.CCellValue();
									if (null != data.sPrefix) {
										var sVal = data.sPrefix;
										//toString enough, becouse nCurValue nave not decimal part
										var sNumber = data.nCurValue.toString();
										if (sNumber.length < data.padding) {
											sNumber = '0'.repeat(data.padding - sNumber.length) + sNumber;
										}
										sVal += sNumber;
										oCellValue.text = sVal;
										oCellValue.type = CellValueType.String;
									} else {
										oCellValue.number = data.nCurValue;
										oCellValue.type = CellValueType.Number;
									}
									oCopyCell.setValueData(new UndoRedoData_CellValueData(null, oCellValue));
								}
								else if(null != oFromCell)
								{
									//копируем полностью
									if(!oFromCell.isFormula()){
										oCopyCell.setValueData(oFromCell.getValueData());
										//todo
										// if(oCopyCell.isEmptyTextString())
										// wsTo._getHyperlink().remove({r1: oCopyCell.nRow, c1: oCopyCell.nCol, r2: oCopyCell.nRow, c2: oCopyCell.nCol});
									} else {
										var _p_ = oFromCell.getFormulaParsed().clone(null, oFromCell, this);
										var assemb = _p_.changeOffset(oCopyCell.getOffset2(oFromCell.getName())).assemble(true);
										oCopyCell.setFormula(assemb);
									}
								}
							}
							//выставляем стиль после текста, потому что если выставить числовой стиль ячейки 'text', то после этого не применится формула
							if (null != oFromCell) {
								oCopyCell.setStyle(oFromCell.getStyle());
								if (bIsPromote)
									oCopyCell.setType(oFromCell.getType());
							}
						});
					}
				}
			}
			if(bIsPromote) {
				wb.dependencyFormulas.addToChangedRange( wsTo.Id, to );
			}
			//добавляем замерженые области
			var nDx = from.c2 - from.c1 + 1;
			var nDy = from.r2 - from.r1 + 1;
			var oMergedFrom = oCanPromote.oMergedFrom;
			if(null != oMergedFrom && oMergedFrom.all.length > 0)
			{
				for (var i = to.c1; i <= to.c2; i += nDx) {
					for (var j = to.r1; j <= to.r2; j += nDy) {
						for (var k = 0, length3 = oMergedFrom.all.length; k < length3; k++) {
							var oMergedBBox = oMergedFrom.all[k].bbox;
							var oNewMerged = Asc.Range(i + oMergedBBox.c1 - from.c1, j + oMergedBBox.r1 - from.r1, i + oMergedBBox.c2 - from.c1, j + oMergedBBox.r2 - from.r1);
							if(to.contains(oNewMerged.c1, oNewMerged.r1)) {
								if(to.c2 < oNewMerged.c2)
									oNewMerged.c2 = to.c2;
								if(to.r2 < oNewMerged.r2)
									oNewMerged.r2 = to.r2;
								if(!oNewMerged.isOneCell())
									wsTo.mergeManager.add(oNewMerged, 1);
							}
						}
					}
				}
			}
			if(bIsPromote)
			{
				//добавляем ссылки
				//не как в Excel поддерживаются ссылки на диапазоны
				var oHyperlinks = wsFrom.hyperlinkManager.get(from);
				if(oHyperlinks.inner.length > 0)
				{
					for (var i = to.c1; i <= to.c2; i += nDx) {
						for (var j = to.r1; j <= to.r2; j += nDy) {
							for(var k = 0, length3 = oHyperlinks.inner.length; k < length3; k++){
								var oHyperlink = oHyperlinks.inner[k];
								var oHyperlinkBBox = oHyperlink.bbox;
								var oNewHyperlink = Asc.Range(i + oHyperlinkBBox.c1 - from.c1, j + oHyperlinkBBox.r1 - from.r1, i + oHyperlinkBBox.c2 - from.c1, j + oHyperlinkBBox.r2 - from.r1);
								if (to.containsRange(oNewHyperlink))
									wsTo.hyperlinkManager.add(oNewHyperlink, oHyperlink.data.clone());
							}
						}
					}
				}
			}
		}

		wsFrom.excludeHiddenRows(oldExcludeHiddenRows);
		History.EndTransaction();
		wb.dependencyFormulas.unlockRecal();
	}
	Range.prototype.createCellOnRowColCross=function(){
		var oThis = this;
		var bbox = this.bbox;
		var nRangeType = this._getRangeType(bbox);
		if(c_oRangeType.Row == nRangeType)
		{
			this._foreachColNoEmpty(function(col){
				if(null != col.xfs)
				{
					for(var i = bbox.r1; i <= bbox.r2; ++i)
						oThis.worksheet._getCell(i, col.index, function(){});
				}
			}, null);
		}
		else if(c_oRangeType.Col == nRangeType)
		{
			this._foreachRowNoEmpty(function(row){
				if(null != row.xfs)
				{
					for(var i = bbox.c1; i <= bbox.c2; ++i)
						oThis.worksheet._getCell(row.index, i, function(){});
				}
			}, null);
		}
	};

	Range.prototype.getLeftTopCell = function(fAction) {
		return this.worksheet._getCell(this.bbox.r1, this.bbox.c1, fAction);
	};

	Range.prototype.getLeftTopCellNoEmpty = function(fAction) {
		return this.worksheet._getCellNoEmpty(this.bbox.r1, this.bbox.c1, fAction);
	};
//-------------------------------------------------------------------------------------------------
	/**
	 * @constructor
	 */
	function PromoteHelper(bVerical, bReverse, bbox){
		//автозаполнение происходит всегда в правую сторону, поэтому менются индексы в методе add, и это надо учитывать при вызове getNext
		this.bVerical = bVerical;
		this.bReverse = bReverse;
		this.bbox = bbox;
		this.oDataRow = {};
		//для get
		this.oCurRow = null;
		this.nCurColIndex = null;
		this.nRowLength = 0;
		this.nColLength = 0;
		if(this.bVerical)
		{
			this.nRowLength = this.bbox.c2 - this.bbox.c1 + 1;
			this.nColLength = this.bbox.r2 - this.bbox.r1 + 1;
		}
		else
		{
			this.nRowLength = this.bbox.r2 - this.bbox.r1 + 1;
			this.nColLength = this.bbox.c2 - this.bbox.c1 + 1;
		}
	}
	PromoteHelper.prototype = {
		add: function(nRow, nCol, nVal, bDelimiter, sPrefix, padding, bDate, oAdditional){
			if(this.bVerical)
			{
				//транспонируем для удобства
				var temp = nRow;
				nRow = nCol;
				nCol = temp;
			}
			if(this.bReverse)
				nCol = this.nColLength - nCol - 1;
			var row = this.oDataRow[nRow];
			if(null == row)
			{
				row = {};
				this.oDataRow[nRow] = row;
			}
			row[nCol] = {nCol: nCol, nVal: nVal, bDelimiter: bDelimiter, sPrefix: sPrefix, padding: padding, bDate: bDate, oAdditional: oAdditional, oSequence: null, nCurValue: null};
		},
		isOnlyIntegerSequence: function(){
			var bRes = true;
			var bEmpty = true;
			for(var i in this.oDataRow)
			{
				var row = this.oDataRow[i];
				for(var j in row)
				{
					var data = row[j];
					bEmpty = false;
					if(!(null != data.nVal && true != data.bDate && null == data.sPrefix))
					{
						bRes = false;
						break;
					}
				}
				if(!bRes)
					break;
			}
			if(bEmpty)
				bRes = false;
			return bRes;
		},
		_promoteSequence: function(aDigits){
			// Это коэффициенты линейного приближения (http://office.microsoft.com/ru-ru/excel-help/HP010072685.aspx)
			// y=a1*x+a0 (где: x=0,1....; y=значения в ячейках; a0 и a1 - это решения приближения функции методом наименьших квадратов
			// (n+1)*a0        + (x0+x1+....)      *a1=(y0+y1+...)
			// (x0+x1+....)*a0 + (x0*x0+x1*x1+....)*a1=(y0*x0+y1*x1+...)
			// http://www.exponenta.ru/educat/class/courses/vvm/theme_7/theory.asp
			var a0 = 0.0;
			var a1 = 0.0;
			// Индекс X
			var nX = 0;
			if(1 == aDigits.length)
			{
				nX = 1;
				a1 = 1;
				a0 = aDigits[0].y;
			}
			else
			{
				// (n+1)
				var nN = aDigits.length;
				// (x0+x1+....)
				var nXi = 0;
				// (x0*x0+x1*x1+....)
				var nXiXi = 0;
				// (y0+y1+...)
				var dYi = 0.0;
				// (y0*x0+y1*x1+...)
				var dYiXi = 0.0;

				// Цикл по всем строкам
				for (var i = 0, length = aDigits.length; i < length; ++i)
				{
					var data = aDigits[i];
					nX = data.x;
					var dValue = data.y;

					// Вычисляем значения
					nXi += nX;
					nXiXi += nX * nX;
					dYi += dValue;
					dYiXi += dValue * nX;
				}
				nX++;

				// Теперь решаем систему уравнений
				// Общий детерминант
				var dD = nN * nXiXi - nXi * nXi;
				// Детерминант первого корня
				var dD1 = dYi * nXiXi - nXi * dYiXi;
				// Детерминант второго корня
				var dD2 = nN * dYiXi - dYi * nXi;

				a0 = dD1 / dD;
				a1 = dD2 / dD;
			}
			return {a0: a0, a1: a1, nX: nX};
		},
		_addSequenceToRow : function(nRowIndex, aSortRowIndex, row, aCurSequence){
			if(aCurSequence.length > 0)
			{
				var oFirstData = aCurSequence[0];
				var bCanPromote = true;
				//если последовательность состоит из одного числа и той же колонке есть еще последовательности, то надо копировать, а не автозаполнять
				if(1 == aCurSequence.length)
				{
					var bVisitRowIndex = false;
					var oVisitData = null;
					for(var i = 0, length = aSortRowIndex.length; i < length; i++)
					{
						var nCurRowIndex = aSortRowIndex[i];
						if(nRowIndex == nCurRowIndex)
						{
							bVisitRowIndex = true;
							if(oVisitData && oFirstData.sPrefix == oVisitData.sPrefix && oFirstData.bDate == oVisitData.bDate)
							{
								bCanPromote = false;
								break;
							}
						}
						else
						{
							var oCurRow = this.oDataRow[nCurRowIndex];
							if(oCurRow)
							{
								var data = oCurRow[oFirstData.nCol];
								if(null != data)
								{
									if(null != data.nVal)
									{
										oVisitData = data;
										if(bVisitRowIndex)
										{
											if(oFirstData.sPrefix == oVisitData.sPrefix && oFirstData.bDate == oVisitData.bDate)
												bCanPromote = false;
											break;
										}
									}
									else if(data.bDelimiter)
									{
										oVisitData = null;
										if(bVisitRowIndex)
											break;
									}
								}
							}
						}
					}
				}
				if(bCanPromote)
				{
					var nMinIndex = null;
					var nMaxIndex = null;
					var bValidIndexDif = true;
					var nPrevX = null;
					var nPrevVal = null;
					var nIndexDif = null;
					var nValueDif = null;
					var nMaxPadding = 0;
					//анализируем последовательность, если числа расположены не на одинаковом расстоянии, то считаем их сплошной последовательностью
					//последовательность с промежутками может быть только целочисленной
					for(var i = 0, length = aCurSequence.length; i < length; i++)
					{
						var data = aCurSequence[i];
						var nCurX = data.nCol;
						if(null == nMinIndex || null == nMaxIndex)
							nMinIndex = nMaxIndex = nCurX;
						else
						{
							if(nCurX < nMinIndex)
								nMinIndex = nCurX;
							if(nCurX > nMaxIndex)
								nMaxIndex = nCurX;
						}
						if(bValidIndexDif)
						{
							if(null != nPrevX && null != nPrevVal)
							{
								var nCurDif = nCurX - nPrevX;
								var nCurValDif = data.nVal - nPrevVal;
								if(null == nIndexDif || null == nCurValDif)
								{
									nIndexDif = nCurDif;
									nValueDif = nCurValDif;
								}
								else if(nIndexDif != nCurDif || nValueDif != nCurValDif)
								{
									nIndexDif = null;
									bValidIndexDif = false;
								}
							}
						}
						nMaxPadding = Math.max(nMaxPadding, data.padding);
						nPrevX = nCurX;
						nPrevVal = data.nVal;
					}
					var bWithSpace = false;
					if(null != nIndexDif)
					{
						nIndexDif = Math.abs(nIndexDif);
						if(nIndexDif > 1)
							bWithSpace = true;
					}
					//заполняем массив с координатами
					var bExistSpace = false;
					nPrevX = null;
					var aDigits = [];
					for(var i = 0, length = aCurSequence.length; i < length; i++)
					{
						var data = aCurSequence[i];
						data.padding = nMaxPadding;
						var nCurX = data.nCol;
						var x = nCurX - nMinIndex;
						if(null != nIndexDif && nIndexDif > 0)
							x /= nIndexDif;
						if(null != nPrevX && nCurX - nPrevX > 1)
							bExistSpace = true;
						var y = data.nVal;
						//даты автозаполняем только по целой части
						if(data.bDate)
							y = parseInt(y);
						aDigits.push({x: x, y: y});
						nPrevX = nCurX;
					}
					if(aDigits.length > 0)
					{
						var oSequence = this._promoteSequence(aDigits);
						if(1 == aDigits.length && this.bReverse)
						{
							//меняем коэффициенты для случая одного числа в последовательности, иначе она в любую сторону будет возрастающей
							oSequence.a1 *= -1;
						}
						var bIsIntegerSequence = oSequence.a1 != parseInt(oSequence.a1);
						//для дат и чисел с префиксом автозаполняются только целочисленные последовательности
						if(!((null != oFirstData.sPrefix || true == oFirstData.bDate) && bIsIntegerSequence))
						{
							if(false == bWithSpace && bExistSpace)
							{
								for(var i = nMinIndex; i <= nMaxIndex; i++)
								{
									var data = row[i];
									if(null == data)
									{
										data = {nCol: i, nVal: null, bDelimiter: oFirstData.bDelimiter, sPrefix: oFirstData.sPrefix, bDate: oFirstData.bDate, oAdditional: null, oSequence: null, nCurValue: null};
										row[i] = data;
									}
									data.oSequence = oSequence;
								}
							}
							else
							{
								for(var i = 0, length = aCurSequence.length; i < length; i++)
								{
									var nCurX = aCurSequence[i].nCol;
									if(null != nCurX)
										row[nCurX].oSequence = oSequence;
								}
							}
						}
					}
				}
			}
		},
		finishAdd : function(bCopy){
			if(true != bCopy)
			{
				var aSortRowIndex = [];
				for(var i in this.oDataRow)
					aSortRowIndex.push(i - 0);
				aSortRowIndex.sort(fSortAscending);
				for(var i = 0, length = aSortRowIndex.length; i < length; i++)
				{
					var nRowIndex = aSortRowIndex[i];
					var row = this.oDataRow[nRowIndex];
					//собираем информация о последовательностях в row
					var aSortIndex = [];
					for(var j in row)
						aSortIndex.push(j - 0);
					aSortIndex.sort(fSortAscending);
					var aCurSequence = [];
					var oPrevData = null;
					for(var j = 0, length2 = aSortIndex.length; j < length2; j++)
					{
						var nColIndex = aSortIndex[j];
						var data = row[nColIndex];
						var bAddToSequence = false;
						if(null != data.nVal)
						{
							bAddToSequence = true;
							if(null != oPrevData && (oPrevData.bDelimiter != data.bDelimiter || oPrevData.sPrefix != data.sPrefix || oPrevData.bDate != data.bDate))
							{
								this._addSequenceToRow(nRowIndex, aSortRowIndex, row, aCurSequence);
								aCurSequence = [];
								oPrevData = null;
							}
							oPrevData = data;
						}
						else if(data.bDelimiter)
						{
							this._addSequenceToRow(nRowIndex, aSortRowIndex, row, aCurSequence);
							aCurSequence = [];
							oPrevData = null;
						}
						if(bAddToSequence)
							aCurSequence.push(data);
					}
					this._addSequenceToRow(nRowIndex, aSortRowIndex, row, aCurSequence);
				}
			}
		},
		setIndex: function(index){
			if(0 != this.nRowLength && index >= this.nRowLength)
				index = index % (this.nRowLength);
			this.oCurRow = this.oDataRow[index];
			this.nCurColIndex = 0;
		},
		getNext: function(){
			var oRes = null;
			if(this.oCurRow)
			{
				var oRes = this.oCurRow[this.nCurColIndex];
				if(null != oRes)
				{
					oRes.nCurValue = null;
					if(null != oRes.oSequence)
					{
						var sequence = oRes.oSequence;
						if(oRes.bDate || null != oRes.sPrefix)
							oRes.nCurValue = Math.abs(sequence.a1 * sequence.nX + sequence.a0);
						else
							oRes.nCurValue = sequence.a1 * sequence.nX + sequence.a0;
						sequence.nX ++;
					}
				}
				this.nCurColIndex++;
				if(this.nCurColIndex >= this.nColLength)
					this.nCurColIndex = 0;
			}
			return oRes;
		}
	};

//-------------------------------------------------------------------------------------------------

	/**
	 * @constructor
	 */
	function HiddenManager(ws) {
		this.ws = ws;
		this.hiddenRowsSum = [];
		this.hiddenColsSum = [];
		this.dirty = true;
		this.recalcHiddenRows = {};
		this.recalcHiddenCols = {};
		this.hiddenRowMin = gc_nMaxRow0;
		this.hiddenRowMax = 0;
	}
	HiddenManager.prototype.initPostOpen = function () {
		this.hiddenRowMin = gc_nMaxRow0;
		this.hiddenRowMax = 0;
	};
	HiddenManager.prototype.addHidden = function (isRow, index) {
		(isRow ? this.recalcHiddenRows : this.recalcHiddenCols)[index] = true;
		if (isRow) {
			this.hiddenRowMin = Math.min(this.hiddenRowMin, index);
			this.hiddenRowMax = Math.max(this.hiddenRowMax, index);
		}
		this.setDirty(true);
	};
	HiddenManager.prototype.getRecalcHidden = function () {
		var res = [];
		var i;
		for (i in this.recalcHiddenRows) {
			i = +i;
			res.push(new Asc.Range(0, i, gc_nMaxCol0, i));
		}
		for (i in this.recalcHiddenCols) {
			i = +i;
			res.push(new Asc.Range(i, 0, i, gc_nMaxRow0));
		}
		this.recalcHiddenRows = {};
		this.recalcHiddenCols = {};
		return res;
	};
	HiddenManager.prototype.getHiddenRowsRange = function() {
		var res;
		if (this.hiddenRowMin <= this.hiddenRowMax) {
			res = {r1: this.hiddenRowMin, r2: this.hiddenRowMax};
			this.hiddenRowMin = gc_nMaxRow0;
			this.hiddenRowMax = 0;
		}
		return res;
	};
	HiddenManager.prototype.setDirty = function(val) {
		this.dirty = val;
	};
	HiddenManager.prototype.getHiddenRowsCount = function(from, to) {
		return this._getHiddenCount(true, from, to);
	};
	HiddenManager.prototype.getHiddenColsCount = function(from, to) {
		return this._getHiddenCount(false, from, to);
	};
	HiddenManager.prototype._getHiddenCount = function(isRow, from, to) {
		//todo wrong result if 'to' is hidden
		if (this.dirty) {
			this.dirty = false;
			this._init();
		}
		var hiddenSum = isRow ? this.hiddenRowsSum : this.hiddenColsSum;
		var toCount = to < hiddenSum.length ? hiddenSum[to] : 0;
		var fromCount = from < hiddenSum.length ? hiddenSum[from] : 0;
		return fromCount - toCount;
	};
	HiddenManager.prototype._init = function() {
		if (this.ws) {
			this.hiddenColsSum = this._initHiddenSumCol(this.ws.aCols);
			this.hiddenRowsSum = this._initHiddenSumRow();
		}
	};
	HiddenManager.prototype._initHiddenSumCol = function(elems) {
		var hiddenSum = [];
		if (this.ws) {
			var i;
			var hiddenFlags = [];
			for (i in elems) {
				if (elems.hasOwnProperty(i)) {
					var elem = elems[i];
					if (null != elem && elem.getHidden()) {
						hiddenFlags[i] = 1;
					}
				}
			}
			var sum = 0;
			for (i = hiddenFlags.length - 1; i >= 0; --i) {
				if (hiddenFlags[i] > 0) {
					sum++;
				}
				hiddenSum[i] = sum;
			}
		}
		return hiddenSum;
	};
	HiddenManager.prototype._initHiddenSumRow = function() {
		var hiddenSum = [];
		if (this.ws) {
			var i;
			var hiddenFlags = [];
			this.ws._forEachRow(function(row) {
				if (row.getHidden()) {
					hiddenFlags[row.getIndex()] = 1;
				}
			});
			var sum = 0;
			for (i = hiddenFlags.length - 1; i >= 0; --i) {
				if (hiddenFlags[i] > 0) {
					sum++;
				}
				hiddenSum[i] = sum;
			}
		}
		return hiddenSum;
	};

	/**
	 * @constructor
	 */
	function DrawingObjectsManager(worksheet)
	{
		this.worksheet = worksheet;
	}

	DrawingObjectsManager.prototype.updateChartReferences = function(oldWorksheet, newWorksheet)
	{
		AscFormat.ExecuteNoHistory(function(){
			this.updateChartReferencesWidthHistory(oldWorksheet, newWorksheet);
		}, this, []);
	};

	DrawingObjectsManager.prototype.updateChartReferencesWidthHistory = function(oldWorksheet, newWorksheet, bNoRebuildCache)
	{
		var aObjects = this.worksheet.Drawings;
		for (var i = 0; i < aObjects.length; i++) {
			var graphicObject = aObjects[i].graphicObject;
			if ( graphicObject.updateChartReferences )
			{
				graphicObject.updateChartReferences(oldWorksheet, newWorksheet, bNoRebuildCache);
			}
		}
	};


	DrawingObjectsManager.prototype.rebuildCharts = function(data)
	{
		var aObjects = this.worksheet.Drawings;
		for(var i = 0; i < aObjects.length; ++i)
		{
			if(aObjects[i].graphicObject.rebuildSeries)
			{
				aObjects[i].graphicObject.rebuildSeries(data);
			}
		}
	};

	window['AscCommonExcel'] = window['AscCommonExcel'] || {};
	window['AscCommonExcel'].g_nVerticalTextAngle = g_nVerticalTextAngle;
	window['AscCommonExcel'].oDefaultMetrics = oDefaultMetrics;
	window['AscCommonExcel'].g_nAllColIndex = g_nAllColIndex;
	window['AscCommonExcel'].g_nAllRowIndex = g_nAllRowIndex;
	window['AscCommonExcel'].g_DefNameWorksheet = null;
	window['AscCommonExcel'].aStandartNumFormats = aStandartNumFormats;
	window['AscCommonExcel'].aStandartNumFormatsId = aStandartNumFormatsId;
	window['AscCommonExcel'].oFormulaLocaleInfo = oFormulaLocaleInfo;
	window['AscCommonExcel'].getDefNameIndex = getDefNameIndex;
	window['AscCommonExcel'].angleFormatToInterface2 = angleFormatToInterface2;
	window['AscCommonExcel'].angleInterfaceToFormat = angleInterfaceToFormat;
	window['AscCommonExcel'].Workbook = Workbook;
	window['AscCommonExcel'].CT_Workbook = CT_Workbook;
	window['AscCommonExcel'].Worksheet = Worksheet;
	window['AscCommonExcel'].Cell = Cell;
	window['AscCommonExcel'].Range = Range;
	window['AscCommonExcel'].DefName = DefName;
	window['AscCommonExcel'].RangeTree = RangeTree;
	window['AscCommonExcel'].DependencyGraph = DependencyGraph;
	window['AscCommonExcel'].HiddenManager = HiddenManager;
	window['AscCommonExcel'].CCellWithFormula = CCellWithFormula;
	window['AscCommonExcel'].preparePromoteFromTo = preparePromoteFromTo;
	window['AscCommonExcel'].promoteFromTo = promoteFromTo;
	window['AscCommonExcel'].getCompiledStyle = getCompiledStyle;
	window['AscCommonExcel'].getCompiledStyleFromArray = getCompiledStyleFromArray;
	window['AscCommonExcel'].ignoreFirstRowSort = ignoreFirstRowSort;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
(function(window, undefined) {

      // Import
	var openXml = AscCommon.openXml;

      var g_memory = AscFonts.g_memory;
      var DecodeBase64Char = AscFonts.DecodeBase64Char;
      var b64_decode = AscFonts.b64_decode;
      
      var CellValueType = AscCommon.CellValueType;
      var c_oAscCellAnchorType = AscCommon.c_oAscCellAnchorType;
      var c_oAscBorderStyles = AscCommon.c_oAscBorderStyles;
      var gc_nMaxRow0 = AscCommon.gc_nMaxRow0;
      var gc_nMaxCol0 = AscCommon.gc_nMaxCol0;
      var Binary_CommonReader = AscCommon.Binary_CommonReader;
      var BinaryCommonWriter = AscCommon.BinaryCommonWriter;
      var c_oSerPropLenType = AscCommon.c_oSerPropLenType;
      var c_oSerConstants = AscCommon.c_oSerConstants;
    var History = AscCommon.History;
    var pptx_content_loader = AscCommon.pptx_content_loader;
    var pptx_content_writer = AscCommon.pptx_content_writer;

      var c_oAscPageOrientation = Asc.c_oAscPageOrientation;
    
    var g_oDefaultFormat = AscCommonExcel.g_oDefaultFormat;
	var g_StyleCache = AscCommonExcel.g_StyleCache;
    var g_cSharedWriteStreak = 64;//like Excel

//dif:
//Version:2 добавлены свойства колонок и строк CustomWidth, CustomHeight(раньше считались true)
    /** @enum */
    var c_oSerTableTypes =
    {
        Other: 0,
        SharedStrings: 1,
        Styles: 2,
        Workbook: 3,
        Worksheets: 4,
        CalcChain: 5
    };
    /** @enum */
    var c_oSerStylesTypes =
    {
        Borders: 0,
        Border: 1,
        CellXfs: 2,
        Xfs: 3,
        Fills: 4,
        Fill: 5,
        Fonts: 6,
        Font: 7,
        NumFmts: 8,
        NumFmt: 9,
        Dxfs: 10,
        Dxf: 11,
        TableStyles: 12,
        CellStyleXfs: 14,
        CellStyles: 15,
        CellStyle: 16
    };
    /** @enum */
    var c_oSerBorderTypes =
    {
        Bottom: 0,
        Diagonal: 1,
        End: 2,
        Horizontal: 3,
        Start: 4,
        Top: 5,
        Vertical: 6,
        DiagonalDown: 7,
        DiagonalUp: 8,
        Outline: 9
    };
    /** @enum */
    var c_oSerBorderPropTypes =
    {
        Color: 0,
        Style: 1
    };
    /** @enum */
    var c_oSerXfsTypes =
    {
        ApplyAlignment: 0,
        ApplyBorder: 1,
        ApplyFill: 2,
        ApplyFont: 3,
        ApplyNumberFormat: 4,
        ApplyProtection: 5,
        BorderId: 6,
        FillId: 7,
        FontId: 8,
        NumFmtId: 9,
        PivotButton: 10,
        QuotePrefix: 11,
        XfId: 12,
        Aligment: 13,
        Protection: 14
    };
    /** @enum */
    var c_oSerAligmentTypes =
    {
        Horizontal: 0,
        Indent: 1,
        JustifyLastLine: 2,
        ReadingOrder: 3,
        RelativeIndent: 4,
        ShrinkToFit: 5,
        TextRotation: 6,
        Vertical: 7,
        WrapText: 8
    };
    /** @enum */
    var c_oSerFillTypes =
    {
        PatternFill: 0,
        PatternFillBgColor: 1
    };
    /** @enum */
    var c_oSerFontTypes =
    {
        Bold: 0,
        Color: 1,
        Italic: 3,
        RFont: 4,
        Strike: 5,
        Sz: 6,
        Underline: 7,
        VertAlign: 8,
        Scheme: 9
    };
    /** @enum */
    var c_oSerNumFmtTypes =
    {
        FormatCode: 0,
        NumFmtId: 1
    };
    /** @enum */
    var c_oSerSharedStringTypes =
    {
        Si: 0,
        Run: 1,
        RPr: 2,
        Text: 3
    };
    /** @enum */
    var c_oSerWorkbookTypes =
    {
        WorkbookPr: 0,
        BookViews: 1,
        WorkbookView: 2,
        DefinedNames: 3,
        DefinedName: 4,
        ExternalReferences: 5,
        ExternalReference: 6,
        PivotCaches: 7,
        PivotCache: 8,
        ExternalBook: 9,
        OleLink:10,
		DdeLink: 11,
		VbaProject: 12,
		JsaProject: 13,
		Comments: 14,
		CalcPr: 15
    };
    /** @enum */
    var c_oSerWorkbookPrTypes =
    {
        Date1904: 0,
        DateCompatibility: 1,
		HidePivotFieldList: 2,
		ShowPivotChartFilter: 3
    };
    /** @enum */
    var c_oSerWorkbookViewTypes =
    {
        ActiveTab: 0
    };
    /** @enum */
    var c_oSerDefinedNameTypes =
    {
        Name: 0,
        Ref: 1,
        LocalSheetId: 2,
        Hidden: 3
    };
	/** @enum */
	var c_oSerCalcPrTypes = {
		CalcId: 0,
		CalcMode: 1,
		FullCalcOnLoad: 2,
		RefMode: 3,
		Iterate: 4,
		IterateCount: 5,
		IterateDelta: 6,
		FullPrecision: 7,
		CalcCompleted: 8,
		CalcOnSave: 9,
		ConcurrentCalc: 10,
		ConcurrentManualCount: 11,
		ForceFullCalc: 12
	};
	/** @enum */
    var c_oSerWorksheetsTypes =
    {
        Worksheet: 0,
        WorksheetProp: 1,
        Cols: 2,
        Col: 3,
        Dimension: 4,
        Hyperlinks: 5,
        Hyperlink: 6,
        MergeCells: 7,
        MergeCell: 8,
        SheetData: 9,
        Row: 10,
        SheetFormatPr: 11,
        Drawings: 12,
        Drawing: 13,
        PageMargins: 14,
        PageSetup: 15,
        PrintOptions: 16,
        Autofilter: 17,
        TableParts: 18,
        Comments: 19,
        Comment: 20,
        ConditionalFormatting: 21,
        SheetViews: 22,
        SheetView: 23,
        SheetPr: 24,
        SparklineGroups: 25,
		PivotTable: 26,
        HeaderFooter: 27,
        LegacyDrawingHF: 28,
        Picture: 29,
        RowBreaks: 30,
        ColBreaks: 31
    };
    /** @enum */
    var c_oSerWorksheetPropTypes =
    {
        Name: 0,
        SheetId: 1,
        State: 2,
        Ref: 3
    };
    /** @enum */
    var c_oSerWorksheetColTypes =
    {
        BestFit: 0,
        Hidden: 1,
        Max: 2,
        Min: 3,
        Style: 4,
        Width: 5,
        CustomWidth: 6
    };
    /** @enum */
    var c_oSerHyperlinkTypes =
    {
        Ref: 0,
        Hyperlink: 1,
        Location: 2,
        Tooltip: 3
    };
    /** @enum */
    var c_oSerSheetFormatPrTypes =
    {
        DefaultColWidth		: 0,
        DefaultRowHeight	: 1,
        BaseColWidth		: 2,
        CustomHeight		: 3,
        ZeroHeight			: 4
    };
    /** @enum */
    var c_oSerRowTypes =
    {
        Row: 0,
        Style: 1,
        Height: 2,
        Hidden: 3,
        Cells: 4,
        Cell: 5,
        CustomHeight: 6
    };
    /** @enum */
    var c_oSerCellTypes =
    {
        Ref: 0,
        Style: 1,
        Type: 2,
        Value: 3,
        Formula: 4,
        RefRowCol: 5,
        ValueText: 6
    };
    /** @enum */
    var c_oSerFormulaTypes =
    {
        Aca: 0,
        Bx: 1,
        Ca: 2,
        Del1: 3,
        Del2: 4,
        Dt2D: 5,
        Dtr: 6,
        R1: 7,
        R2: 8,
        Ref: 9,
        Si: 10,
        T: 11,
        Text: 12
    };
    /** @enum */
    var c_oSer_DrawingFromToType =
    {
        Col: 0,
        ColOff: 1,
        Row: 2,
        RowOff: 3
    };
    /** @enum */
    var c_oSer_DrawingPosType =
    {
        X: 0,
        Y: 1
    };
    /** @enum */
    var c_oSer_DrawingExtType =
    {
        Cx: 0,
        Cy: 1
    };
    /** @enum */
    var c_oSer_OtherType =
    {
        Media: 0,
        MediaItem: 1,
        MediaId: 2,
        MediaSrc: 3,
        Theme: 5
    };
    /** @enum */
    var c_oSer_CalcChainType =
    {
        CalcChainItem: 0,
        Array: 1,
        SheetId: 2,
        DependencyLevel: 3,
        Ref: 4,
        ChildChain: 5,
        NewThread: 6
    };
    /** @enum */
    var  c_oSer_PageMargins =
    {
        Left: 0,
        Top: 1,
        Right: 2,
        Bottom: 3,
        Header: 4,
        Footer: 5
    };
    /** @enum */
    var  c_oSer_PageSetup =
    {
        Orientation: 0,
        PaperSize: 1
    };
    /** @enum */
    var  c_oSer_PrintOptions =
    {
        GridLines: 0,
        Headings: 1
    };
    /** @enum */
    var c_oSer_TablePart =
    {
        Table:0,
        Ref:1,
        TotalsRowCount:2,
        DisplayName:3,
        AutoFilter:4,
        SortState:5,
        TableColumns:6,
        TableStyleInfo:7,
		HeaderRowCount:8,
		AltTextTable: 9
    };
    /** @enum */
    var c_oSer_TableStyleInfo =
    {
        Name:0,
        ShowColumnStripes:1,
        ShowRowStripes:2,
        ShowFirstColumn:3,
        ShowLastColumn:4
    };
    /** @enum */
    var c_oSer_TableColumns =
    {
        TableColumn:0,
        Name:1,
        DataDxfId:2,
        TotalsRowLabel:3,
        TotalsRowFunction:4,
        TotalsRowFormula:5,
        CalculatedColumnFormula:6
    };
    /** @enum */
    var c_oSer_SortState =
    {
        Ref:0,
        CaseSensitive:1,
        SortConditions:2,
        SortCondition:3,
        ConditionRef:4,
        ConditionSortBy:5,
        ConditionDescending:6,
        ConditionDxfId:7
    };
    /** @enum */
    var c_oSer_AutoFilter =
    {
        Ref:0,
        FilterColumns:1,
        FilterColumn:2,
        SortState:3
    };
    /** @enum */
    var c_oSer_FilterColumn =
    {
        ColId:0,
        Filters:1,
        Filter:2,
        DateGroupItem:3,
        CustomFilters:4,
        ColorFilter:5,
        Top10:6,
        DynamicFilter: 7,
        HiddenButton: 8,
        ShowButton: 9,
        FiltersBlank: 10
    };
    /** @enum */
    var c_oSer_Filter =
    {
        Val:0
    };
    /** @enum */
    var c_oSer_DateGroupItem =
    {
        DateTimeGrouping:0,
        Day:1,
        Hour:2,
        Minute:3,
        Month:4,
        Second:5,
        Year:6
    };
    /** @enum */
    var c_oSer_CustomFilters =
    {
        And:0,
        CustomFilters:1,
        CustomFilter:2,
        Operator:3,
        Val:4
    };
    /** @enum */
    var c_oSer_DynamicFilter =
    {
        Type: 0,
        Val: 1,
        MaxVal: 2
    };
    /** @enum */
    var c_oSer_ColorFilter =
    {
        CellColor:0,
        DxfId:1
    };
    /** @enum */
    var c_oSer_Top10 =
    {
        FilterVal:0,
        Percent:1,
        Top:2,
        Val:3
    };
    /** @enum */
    var c_oSer_Dxf =
    {
        Alignment:0,
        Border:1,
        Fill:2,
        Font:3,
        NumFmt:4
    };
    /** @enum */
    var c_oSer_TableStyles = {
        DefaultTableStyle:0,
        DefaultPivotStyle:1,
        TableStyles: 2,
        TableStyle: 3
    };
    var c_oSer_TableStyle = {
        Name: 0,
        Pivot: 1,
        Table: 2,
        Elements: 3,
        Element: 4,
        DisplayName: 5
    };
    var c_oSer_TableStyleElement = {
        DxfId: 0,
        Size: 1,
        Type: 2
    };
    var c_oSer_Comments =
    {
        Row: 0,
        Col: 1,
        CommentDatas : 2,
        CommentData : 3,
        Left: 4,
        LeftOffset: 5,
        Top: 6,
        TopOffset: 7,
        Right: 8,
        RightOffset: 9,
        Bottom: 10,
        BottomOffset: 11,
        LeftMM: 12,
        TopMM: 13,
        WidthMM: 14,
        HeightMM: 15,
        MoveWithCells: 16,
        SizeWithCells: 17
    };
    var c_oSer_CommentData =
    {
        Text : 0,
        Time : 1,
        UserId : 2,
        UserName : 3,
        QuoteText : 4,
        Solved : 5,
        Document : 6,
        Replies : 7,
        Reply : 8,
        OOTime : 9
    };
    var c_oSer_ConditionalFormatting = {
        Pivot						: 0,
        SqRef						: 1,
        ConditionalFormattingRule	: 2
    };
    var c_oSer_ConditionalFormattingRule = {
        AboveAverage	: 0,
        Bottom			: 1,
        DxfId			: 2,
        EqualAverage	: 3,
        Operator		: 4,
        Percent			: 5,
        Priority		: 6,
        Rank			: 7,
        StdDev			: 8,
        StopIfTrue		: 9,
        Text			: 10,
        TimePeriod		: 11,
        Type			: 12,
        ColorScale		: 14,
        DataBar			: 15,
        FormulaCF		: 16,
        IconSet			: 17
    };
    var c_oSer_ConditionalFormattingRuleColorScale = {
        CFVO			: 0,
        Color			: 1
    };
    var c_oSer_ConditionalFormattingDataBar = {
        CFVO			: 0,
        Color			: 1,
        MaxLength		: 2,
        MinLength		: 3,
        ShowValue		: 4
    };
    var c_oSer_ConditionalFormattingIconSet = {
        CFVO			: 0,
        IconSet			: 1,
        Percent			: 2,
        Reverse			: 3,
        ShowValue		: 4
    };
    var c_oSer_ConditionalFormattingValueObject = {
        Gte				: 0,
        Type			: 1,
        Val				: 2
    };
    var c_oSer_SheetView = {
        ColorId						: 0,
        DefaultGridColor			: 1,
        RightToLeft					: 2,
        ShowFormulas				: 3,
        ShowGridLines				: 4,
        ShowOutlineSymbols			: 5,
        ShowRowColHeaders			: 6,
        ShowRuler					: 7,
        ShowWhiteSpace				: 8,
        ShowZeros					: 9,
        TabSelected					: 10,
        TopLeftCell					: 11,
        View						: 12,
        WindowProtection			: 13,
        WorkbookViewId				: 14,
        ZoomScale					: 15,
        ZoomScaleNormal				: 16,
        ZoomScalePageLayoutView		: 17,
        ZoomScaleSheetLayoutView	: 18,

		Pane						: 19,
		Selection					: 20
    };
    var c_oSer_DrawingType =
    {
        Type: 0,
        From: 1,
        To: 2,
        Pos: 3,
        Pic: 4,
        PicSrc: 5,
        GraphicFrame: 6,
        Chart: 7,
        Ext: 8,
        pptxDrawing: 9,
        Chart2: 10
    };
    /** @enum */
    var c_oSer_Pane = {
        ActivePane	: 0,
		State		: 1,
        TopLeftCell	: 2,
        XSplit		: 3,
		YSplit		: 4
    };
	/** @enum */
	 var c_oSer_Selection = {
		ActiveCell: 0,
		ActiveCellId: 1,
		Sqref: 2,
		Pane: 3
	};
    /** @enum */
    var c_oSer_CellStyle = {
        BuiltinId		: 0,
        CustomBuiltin	: 1,
        Hidden			: 2,
        ILevel			: 3,
        Name			: 4,
        XfId			: 5
    };
    /** @enum */
    var c_oSer_SheetPr = {
        CodeName							: 0,
        EnableFormatConditionsCalculation	: 1,
        FilterMode							: 2,
        Published							: 3,
        SyncHorizontal						: 4,
        SyncRef								: 5,
        SyncVertical						: 6,
        TransitionEntry						: 7,
        TransitionEvaluation				: 8,

        TabColor							: 9
    };
    /** @enum */
    var c_oSer_Sparkline = {
        SparklineGroup: 0,
        ManualMax: 1,
        ManualMin: 2,
        LineWeight: 3,
        Type: 4,
        DateAxis: 5,
        DisplayEmptyCellsAs: 6,
        Markers: 7,
        High: 8,
        Low: 9,
        First: 10,
        Last: 11,
        Negative: 12,
        DisplayXAxis: 13,
        DisplayHidden: 14,
        MinAxisType: 15,
        MaxAxisType: 16,
        RightToLeft: 17,
        ColorSeries: 18,
        ColorNegative: 19,
        ColorAxis: 20,
        ColorMarkers: 21,
        ColorFirst: 22,
        ColorLast: 23,
        ColorHigh: 24,
        ColorLow: 25,
        Ref: 26,
        Sparklines: 27,
        Sparkline: 28,
        SparklineRef: 29,
        SparklineSqRef: 30
    };
	/** @enum */
	var c_oSer_AltTextTable = {
		AltText: 0,
		AltTextSummary: 1
	};
	/** @enum */
	var c_oSer_PivotTypes = {
		id: 0,
		cache: 1,
		record: 2,
		cacheId: 3,
		table: 4
	};
	/** @enum */
	var c_oSer_ExternalLinkTypes = {
		Id: 0,
		SheetNames: 1,
		SheetName: 2,
		DefinedNames: 3,
		DefinedName: 4,
		DefinedNameName: 5,
		DefinedNameRefersTo: 6,
		DefinedNameSheetId: 7,
		SheetDataSet: 8,
		SheetData: 9,
		SheetDataSheetId: 10,
		SheetDataRefreshError: 11,
		SheetDataRow: 12,
		SheetDataRowR: 13,
		SheetDataRowCell: 14,
		SheetDataRowCellRef: 15,
		SheetDataRowCellType: 16,
		SheetDataRowCellValue: 17
	};
    var c_oSer_HeaderFooter = {
        AlignWithMargins: 0,
        DifferentFirst: 1,
        DifferentOddEven: 2,
        ScaleWithDoc: 3,
        EvenFooter: 4,
        EvenHeader: 5,
        FirstFooter: 6,
        FirstHeader: 7,
        OddFooter: 8,
        OddHeader: 9
    };
    var c_oSer_RowColBreaks = {
        Count: 0,
        ManualBreakCount: 1,
        Break: 2,
        Id: 3,
        Man: 4,
        Max: 5,
        Min: 6,
        Pt: 7
    };
    var c_oSer_LegacyDrawingHF = {
        Drawings: 0,
        Drawing: 1,
        DrawingId: 2,
        DrawingShape: 3,
        Cfe: 4,
        Cff: 5,
        Cfo: 6,
        Che: 7,
        Chf: 8,
        Cho: 9,
        Lfe: 10,
        Lff: 11,
        Lfo: 12,
        Lhe: 13,
        Lhf: 14,
        Lho: 15,
        Rfe: 16,
        Rff: 17,
        Rfo: 18,
        Rhe: 19,
        Rhf: 20,
        Rho: 21
    };
	/** @enum */
    var EBorderStyle =
    {
        borderstyleDashDot:  0,
        borderstyleDashDotDot:  1,
        borderstyleDashed:  2,
        borderstyleDotted:  3,
        borderstyleDouble:  4,
        borderstyleHair:  5,
        borderstyleMedium:  6,
        borderstyleMediumDashDot:  7,
        borderstyleMediumDashDotDot:  8,
        borderstyleMediumDashed:  9,
        borderstyleNone: 10,
        borderstyleSlantDashDot: 11,
        borderstyleThick: 12,
        borderstyleThin: 13
    };
    /** @enum */
    var EUnderline =
    {
        underlineDouble:  0,
        underlineDoubleAccounting:  1,
        underlineNone:  2,
        underlineSingle:  3,
        underlineSingleAccounting:  4
    };
    /** @enum */
    var ECellAnchorType =
    {
        cellanchorAbsolute:  0,
        cellanchorOneCell:  1,
        cellanchorTwoCell:  2
    };
    /** @enum */
    var EVisibleType =
    {
        visibleHidden:  0,
        visibleVeryHidden:  1,
        visibleVisible:  2
    };
    /** @enum */
    var ECellTypeType =
    {
        celltypeBool:  0,
        celltypeDate:  1,
        celltypeError:  2,
        celltypeInlineStr:  3,
        celltypeNumber:  4,
        celltypeSharedString:  5,
        celltypeStr:  6
    };
    /** @enum */
    var ECellFormulaType =
    {
        cellformulatypeArray:  0,
        cellformulatypeDataTable:  1,
        cellformulatypeNormal:  2,
        cellformulatypeShared:  3
    };
    /** @enum */
    var EPageOrientation =
    {
        pageorientLandscape: 0,
        pageorientPortrait: 1
    };
    /** @enum */
    var EPageSize =
    {
        pagesizeLetterPaper:  1,
        pagesizeLetterSmall:  2,
        pagesizeTabloidPaper:  3,
        pagesizeLedgerPaper:  4,
        pagesizeLegalPaper:  5,
        pagesizeStatementPaper:  6,
        pagesizeExecutivePaper:  7,
        pagesizeA3Paper:  8,
        pagesizeA4Paper:  9,
        pagesizeA4SmallPaper:  10,
        pagesizeA5Paper:  11,
        pagesizeB4Paper:  12,
        pagesizeB5Paper:  13,
        pagesizeFolioPaper:  14,
        pagesizeQuartoPaper:  15,
        pagesizeStandardPaper1:  16,
        pagesizeStandardPaper2:  17,
        pagesizeNotePaper:  18,
        pagesize9Envelope:  19,
        pagesize10Envelope:  20,
        pagesize11Envelope:  21,
        pagesize12Envelope:  22,
        pagesize14Envelope:  23,
        pagesizeCPaper:  24,
        pagesizeDPaper:  25,
        pagesizeEPaper:  26,
        pagesizeDLEnvelope:  27,
        pagesizeC5Envelope:  28,
        pagesizeC3Envelope:  29,
        pagesizeC4Envelope:  30,
        pagesizeC6Envelope:  31,
        pagesizeC65Envelope:  32,
        pagesizeB4Envelope:  33,
        pagesizeB5Envelope:  34,
        pagesizeB6Envelope:  35,
        pagesizeItalyEnvelope:  36,
        pagesizeMonarchEnvelope:  37,
        pagesize6_3_4Envelope:  38,
        pagesizeUSStandardFanfold:  39,
        pagesizeGermanStandardFanfold:  40,
        pagesizeGermanLegalFanfold:  41,
        pagesizeISOB4:  42,
        pagesizeJapaneseDoublePostcard:  43,
        pagesizeStandardPaper3:  44,
        pagesizeStandardPaper4:  45,
        pagesizeStandardPaper5:  46,
        pagesizeInviteEnvelope:  47,
        pagesizeLetterExtraPaper:  50,
        pagesizeLegalExtraPaper:  51,
        pagesizeTabloidExtraPaper:  52,
        pagesizeA4ExtraPaper:  53,
        pagesizeLetterTransversePaper:  54,
        pagesizeA4TransversePaper:  55,
        pagesizeLetterExtraTransversePaper:  56,
        pagesizeSuperA_SuperA_A4Paper:  57,
        pagesizeSuperB_SuperB_A3Paper:  58,
        pagesizeLetterPlusPaper:  59,
        pagesizeA4PlusPaper:  60,
        pagesizeA5TransversePaper:  61,
        pagesizeJISB5TransversePaper:  62,
        pagesizeA3ExtraPaper:  63,
        pagesizeA5ExtraPaper:  64,
        pagesizeISOB5ExtraPaper:  65,
        pagesizeA2Paper:  66,
        pagesizeA3TransversePaper:  67,
        pagesizeA3ExtraTransversePaper:  68
    };
    /** @enum */
    var ETotalsRowFunction =
    {
        totalrowfunctionAverage: 1,
        totalrowfunctionCount: 2,
        totalrowfunctionCountNums: 3,
        totalrowfunctionCustom: 4,
        totalrowfunctionMax: 5,
        totalrowfunctionMin: 6,
        totalrowfunctionNone: 7,
        totalrowfunctionStdDev: 8,
        totalrowfunctionSum: 9,
        totalrowfunctionVar: 10
    };
    /** @enum */
    var ESortBy =
    {
        sortbyCellColor: 1,
        sortbyFontColor: 2,
        sortbyIcon: 3,
        sortbyValue: 4
    };
    /** @enum */
    var ECustomFilter =
    {
        customfilterEqual: 1,
        customfilterGreaterThan: 2,
        customfilterGreaterThanOrEqual: 3,
        customfilterLessThan: 4,
        customfilterLessThanOrEqual: 5,
        customfilterNotEqual: 6
    };
    /** @enum */
    var EDateTimeGroup =
    {
        datetimegroupDay: 1,
        datetimegroupHour: 2,
        datetimegroupMinute: 3,
        datetimegroupMonth: 4,
        datetimegroupSecond: 5,
        datetimegroupYear: 6
    };
    /** @enum */
    var ETableStyleType =
    {
        tablestyletypeBlankRow: 0,
        tablestyletypeFirstColumn: 1,
        tablestyletypeFirstColumnStripe: 2,
        tablestyletypeFirstColumnSubheading: 3,
        tablestyletypeFirstHeaderCell: 4,
        tablestyletypeFirstRowStripe: 5,
        tablestyletypeFirstRowSubheading: 6,
        tablestyletypeFirstSubtotalColumn: 7,
        tablestyletypeFirstSubtotalRow: 8,
        tablestyletypeFirstTotalCell: 9,
        tablestyletypeHeaderRow: 10,
        tablestyletypeLastColumn: 11,
        tablestyletypeLastHeaderCell: 12,
        tablestyletypeLastTotalCell: 13,
        tablestyletypePageFieldLabels: 14,
        tablestyletypePageFieldValues: 15,
        tablestyletypeSecondColumnStripe: 16,
        tablestyletypeSecondColumnSubheading: 17,
        tablestyletypeSecondRowStripe: 18,
        tablestyletypeSecondRowSubheading: 19,
        tablestyletypeSecondSubtotalColumn: 20,
        tablestyletypeSecondSubtotalRow: 21,
        tablestyletypeThirdColumnSubheading: 22,
        tablestyletypeThirdRowSubheading: 23,
        tablestyletypeThirdSubtotalColumn: 24,
        tablestyletypeThirdSubtotalRow: 25,
        tablestyletypeTotalRow: 26,
        tablestyletypeWholeTable: 27
    };
    /** @enum */
    var EFontScheme =
    {
        fontschemeMajor: 0,
        fontschemeMinor: 1,
        fontschemeNone: 2
    };
    /** @enum */
    var ECfOperator =
    {
        Operator_beginsWith: 0,
        Operator_between: 1,
        Operator_containsText: 2,
        Operator_endsWith: 3,
        Operator_equal: 4,
        Operator_greaterThan: 5,
        Operator_greaterThanOrEqual: 6,
        Operator_lessThan: 7,
        Operator_lessThanOrEqual: 8,
        Operator_notBetween: 9,
        Operator_notContains: 10,
        Operator_notEqual: 11
    };
    /** @enum */
    var ECfType =
    {
        aboveAverage: 0,
        beginsWith: 1,
        cellIs: 2,
        colorScale: 3,
        containsBlanks: 4,
        containsErrors: 5,
        containsText: 6,
        dataBar: 7,
        duplicateValues: 8,
        expression: 9,
        iconSet: 10,
        notContainsBlanks: 11,
        notContainsErrors: 12,
        notContainsText: 13,
        timePeriod: 14,
        top10: 15,
        uniqueValues: 16,
        endsWith: 17
    };
    /** @enum */
    var EIconSetType =
    {
        Arrows3: 0,
        Arrows3Gray: 1,
        Flags3: 2,
        Signs3: 3,
        Symbols3: 4,
        Symbols3_2: 5,
        Traffic3Lights1: 6,
        Traffic3Lights2: 7,
        Arrows4: 8,
        Arrows4Gray: 9,
        Rating4: 10,
        RedToBlack4: 11,
        Traffic4Lights: 12,
        Arrows5: 13,
        Arrows5Gray: 14,
        Quarters5: 15,
        Rating5: 16
    };
    var ECfvoType =
    {
        Formula: 0,
        Maximum: 1,
        Minimum: 2,
        Number: 3,
        Percent: 4,
        Percentile: 5
    };
    var ST_TimePeriod = {
        last7Days : 'last7Days',
        lastMonth : 'lastMonth',
        lastWeek  : 'lastWeek',
        nextMonth : 'nextMonth',
        nextWeek  : 'nextWeek',
        thisMonth : 'thisMonth',
        thisWeek  : 'thisWeek',
        today     : 'today',
        tomorrow  : 'tomorrow',
        yesterday : 'yesterday'
    };
    
    var g_nNumsMaxId = 160;

    var DocumentPageSize = new function() {
        this.oSizes = [
            {id:EPageSize.pagesizeLetterPaper, w_mm: 215.9, h_mm: 279.4},
            {id:EPageSize.pagesizeLetterSmall, w_mm: 215.9, h_mm: 279.4},
            {id:EPageSize.pagesizeTabloidPaper, w_mm: 279.4, h_mm: 431.8},
            {id:EPageSize.pagesizeLedgerPaper, w_mm: 431.8, h_mm: 279.4},
            {id:EPageSize.pagesizeLegalPaper, w_mm: 215.9, h_mm: 355.6},
            {id:EPageSize.pagesizeStatementPaper, w_mm: 495.3, h_mm: 215.9},
            {id:EPageSize.pagesizeExecutivePaper, w_mm: 184.2, h_mm: 266.7},
            {id:EPageSize.pagesizeA3Paper, w_mm: 297, h_mm: 420},
            {id:EPageSize.pagesizeA4Paper, w_mm: 210, h_mm: 297},
            {id:EPageSize.pagesizeA4SmallPaper, w_mm: 210, h_mm: 297},
            {id:EPageSize.pagesizeA5Paper, w_mm: 148, h_mm: 210},
            {id:EPageSize.pagesizeB4Paper, w_mm: 250, h_mm: 353},
            {id:EPageSize.pagesizeB5Paper, w_mm: 176, h_mm: 250},
            {id:EPageSize.pagesizeFolioPaper, w_mm: 215.9, h_mm: 330.2},
            {id:EPageSize.pagesizeQuartoPaper, w_mm: 215, h_mm: 275},
            {id:EPageSize.pagesizeStandardPaper1, w_mm: 254, h_mm: 355.6},
            {id:EPageSize.pagesizeStandardPaper2, w_mm: 279.4, h_mm: 431.8},
            {id:EPageSize.pagesizeNotePaper, w_mm: 215.9, h_mm: 279.4},
            {id:EPageSize.pagesize9Envelope, w_mm: 98.4, h_mm: 225.4},
            {id:EPageSize.pagesize10Envelope, w_mm: 104.8, h_mm: 241.3},
            {id:EPageSize.pagesize11Envelope, w_mm: 114.3, h_mm: 263.5},
            {id:EPageSize.pagesize12Envelope, w_mm: 120.7, h_mm: 279.4},
            {id:EPageSize.pagesize14Envelope, w_mm: 127, h_mm: 292.1},
            {id:EPageSize.pagesizeCPaper, w_mm: 431.8, h_mm: 558.8},
            {id:EPageSize.pagesizeDPaper, w_mm: 558.8, h_mm: 863.6},
            {id:EPageSize.pagesizeEPaper, w_mm: 863.6, h_mm: 1117.6},
            {id:EPageSize.pagesizeDLEnvelope, w_mm: 110, h_mm: 220},
            {id:EPageSize.pagesizeC5Envelope, w_mm: 162, h_mm: 229},
            {id:EPageSize.pagesizeC3Envelope, w_mm: 324, h_mm: 458},
            {id:EPageSize.pagesizeC4Envelope, w_mm: 229, h_mm: 324},
            {id:EPageSize.pagesizeC6Envelope, w_mm: 114, h_mm: 162},
            {id:EPageSize.pagesizeC65Envelope, w_mm: 114, h_mm: 229},
            {id:EPageSize.pagesizeB4Envelope, w_mm: 250, h_mm: 353},
            {id:EPageSize.pagesizeB5Envelope, w_mm: 176, h_mm: 250},
            {id:EPageSize.pagesizeB6Envelope, w_mm: 176, h_mm: 125},
            {id:EPageSize.pagesizeItalyEnvelope, w_mm: 110, h_mm: 230},
            {id:EPageSize.pagesizeMonarchEnvelope, w_mm: 98.4, h_mm: 190.5},
            {id:EPageSize.pagesize6_3_4Envelope, w_mm: 92.1, h_mm: 165.1},
            {id:EPageSize.pagesizeUSStandardFanfold, w_mm: 377.8, h_mm: 279.4},
            {id:EPageSize.pagesizeGermanStandardFanfold, w_mm: 215.9, h_mm: 304.8},
            {id:EPageSize.pagesizeGermanLegalFanfold, w_mm: 215.9, h_mm: 330.2},
            {id:EPageSize.pagesizeISOB4, w_mm: 250, h_mm: 353},
            {id:EPageSize.pagesizeJapaneseDoublePostcard, w_mm: 200, h_mm: 148},
            {id:EPageSize.pagesizeStandardPaper3, w_mm: 228.6, h_mm: 279.4},
            {id:EPageSize.pagesizeStandardPaper4, w_mm: 254, h_mm: 279.4},
            {id:EPageSize.pagesizeStandardPaper5, w_mm: 381, h_mm: 279.4},
            {id:EPageSize.pagesizeInviteEnvelope, w_mm: 220, h_mm: 220},
            {id:EPageSize.pagesizeLetterExtraPaper, w_mm: 235.6, h_mm: 304.8},
            {id:EPageSize.pagesizeLegalExtraPaper, w_mm: 235.6, h_mm: 381},
            {id:EPageSize.pagesizeTabloidExtraPaper, w_mm: 296.9, h_mm: 457.2},
            {id:EPageSize.pagesizeA4ExtraPaper, w_mm: 236, h_mm: 322},
            {id:EPageSize.pagesizeLetterTransversePaper, w_mm: 210.2, h_mm: 279.4},
            {id:EPageSize.pagesizeA4TransversePaper, w_mm: 210, h_mm: 297},
            {id:EPageSize.pagesizeLetterExtraTransversePaper, w_mm: 235.6, h_mm: 304.8},
            {id:EPageSize.pagesizeSuperA_SuperA_A4Paper, w_mm: 227, h_mm: 356},
            {id:EPageSize.pagesizeSuperB_SuperB_A3Paper, w_mm: 305, h_mm: 487},
            {id:EPageSize.pagesizeLetterPlusPaper, w_mm: 215.9, h_mm: 12.69},
            {id:EPageSize.pagesizeA4PlusPaper, w_mm: 210, h_mm: 330},
            {id:EPageSize.pagesizeA5TransversePaper, w_mm: 148, h_mm: 210},
            {id:EPageSize.pagesizeJISB5TransversePaper, w_mm: 182, h_mm: 257},
            {id:EPageSize.pagesizeA3ExtraPaper, w_mm: 322, h_mm: 445},
            {id:EPageSize.pagesizeA5ExtraPaper, w_mm: 174, h_mm: 235},
            {id:EPageSize.pagesizeISOB5ExtraPaper, w_mm: 201, h_mm: 276},
            {id:EPageSize.pagesizeA2Paper, w_mm: 420, h_mm: 594},
            {id:EPageSize.pagesizeA3TransversePaper, w_mm: 297, h_mm: 420},
            {id:EPageSize.pagesizeA3ExtraTransversePaper, w_mm: 322, h_mm: 445}
        ];
        this.getSizeByWH = function(widthMm, heightMm)
        {
            for( var index in this.oSizes)
            {
                var item = this.oSizes[index];
                if(widthMm == item.w_mm && heightMm == item.h_mm)
                    return item;
            }
            return this.oSizes[8];//A4
        };
        this.getSizeById = function(id)
        {
            for( var index in this.oSizes)
            {
                var item = this.oSizes[index];
                if(id == item.id)
                    return item;
            }
            return this.oSizes[8];//A4
        };
    };

      function OpenColor() {
          this.rgb = null;
          this.auto = null;
          this.theme = null;
          this.tint = null;
      }

	function OpenFormula() {
		this.aca = null;
		this.bx = null;
		this.ca = null;
		this.del1 = null;
		this.del2 = null;
		this.dt2d = null;
		this.dtr = null;
		this.r1 = null;
		this.r2 = null;
		this.ref = null;
		this.si = null;
		this.t = null;
		this.v = null;
	}
	OpenFormula.prototype.clean = function(){
		this.aca = null;
		this.bx = null;
		this.ca = null;
		this.del1 = null;
		this.del2 = null;
		this.dt2d = null;
		this.dtr = null;
		this.r1 = null;
		this.r2 = null;
		this.ref = null;
		this.si = null;
		this.t = null;
		this.v = null;
	};
	function OpenColumnFormula(nRow, formula, parsed, refPos, base) {
		this.nRow = nRow;
		this.formula = formula;
		this.parsed = parsed;
		this.refPos = refPos;
		this.base = base;
	}

	function ReadColorSpreadsheet2(bcr, length) {
		var output = null;
		var color = new OpenColor();
		var res = bcr.Read2Spreadsheet(length, function(t,l){
			return bcr.ReadColorSpreadsheet(t,l, color);
		});
		if(null != color.theme)
			output = AscCommonExcel.g_oColorManager.getThemeColor(color.theme, color.tint);
		else if(null != color.rgb)
			output = new AscCommonExcel.RgbColor(0x00ffffff & color.rgb);
		return output;
	}

	function getSqRefString(ranges) {
		var refs = [];
		for (var i = 0; i < ranges.length; ++i) {
			refs.push(ranges[i].getName());
		}
		return refs.join(' ');
	}

    /** @constructor */
    function BinaryTableWriter(memory, aDxfs, isCopyPaste)
    {
        this.memory = memory;
        this.aDxfs = aDxfs;
        this.bs = new BinaryCommonWriter(this.memory);
        this.isCopyPaste = isCopyPaste;
        this.Write = function(aTables, ws)
        {
            var oThis = this;
            for(var i = 0, length = aTables.length; i < length; ++i)
            {
                var rangeTable = null;
                //get range for copy/paste
                if (this.isCopyPaste)
                    rangeTable = aTables[i].Ref;

                if(!this.isCopyPaste || (this.isCopyPaste && rangeTable && this.isCopyPaste.isIntersect(rangeTable) && !ws.bExcludeHiddenRows))
                    this.bs.WriteItem(c_oSer_TablePart.Table, function(){oThis.WriteTable(aTables[i]);});
            }
        };
        this.WriteTable = function(table)
        {
            var oThis = this;
            //Ref
            if(null != table.Ref)
            {
                this.memory.WriteByte(c_oSer_TablePart.Ref);
                this.memory.WriteString2(table.Ref.getName());
            }
            //HeaderRowCount
            if(null != table.HeaderRowCount)
                this.bs.WriteItem(c_oSer_TablePart.HeaderRowCount, function(){oThis.memory.WriteLong(table.HeaderRowCount);});
            //TotalsRowCount
            if(null != table.TotalsRowCount)
                this.bs.WriteItem(c_oSer_TablePart.TotalsRowCount, function(){oThis.memory.WriteLong(table.TotalsRowCount);});
            //Display Name
            if(null != table.DisplayName)
            {
                this.memory.WriteByte(c_oSer_TablePart.DisplayName);
                this.memory.WriteString2(table.DisplayName);
            }
            //AutoFilter
            if(null != table.AutoFilter)
                this.bs.WriteItem(c_oSer_TablePart.AutoFilter, function(){oThis.WriteAutoFilter(table.AutoFilter);});
            //SortState
            if(null != table.SortState)
                this.bs.WriteItem(c_oSer_TablePart.SortState, function(){oThis.WriteSortState(table.SortState);});
            //TableColumns
            if(null != table.TableColumns)
                this.bs.WriteItem(c_oSer_TablePart.TableColumns, function(){oThis.WriteTableColumns(table.TableColumns);});
            //TableStyleInfo
            if(null != table.TableStyleInfo)
                this.bs.WriteItem(c_oSer_TablePart.TableStyleInfo, function(){oThis.WriteTableStyleInfo(table.TableStyleInfo);});
			if(null != table.altText || null != table.altTextSummary)
				this.bs.WriteItem(c_oSer_TablePart.AltTextTable, function(){oThis.WriteAltTextTable(table);});
        };
		this.WriteAltTextTable = function(table)
		{
			var oThis = this;
			if (null != table.altText) {
				this.memory.WriteByte(c_oSer_AltTextTable.AltText);
				this.memory.WriteString2(table.altText);
			}
			if (null != table.altTextSummary) {
				this.memory.WriteByte(c_oSer_AltTextTable.AltTextSummary);
				this.memory.WriteString2(table.altTextSummary);
			}
 		};
        this.WriteAutoFilter = function(autofilter)
        {
            var oThis = this;
            //Ref
            if(null != autofilter.Ref)
            {
				this.memory.WriteByte(c_oSer_AutoFilter.Ref);
                this.memory.WriteString2(autofilter.Ref.getName());
            }
            //FilterColumns
            if(null != autofilter.FilterColumns)
                this.bs.WriteItem(c_oSer_AutoFilter.FilterColumns, function(){oThis.WriteFilterColumns(autofilter.FilterColumns);});
            //SortState
            if(null != autofilter.SortState)
                this.bs.WriteItem(c_oSer_AutoFilter.SortState, function(){oThis.WriteSortState(autofilter.SortState);});
        };
        this.WriteFilterColumns = function(filterColumns)
        {
            var oThis = this;
            for(var i = 0, length = filterColumns.length; i < length; ++i)
                this.bs.WriteItem(c_oSer_AutoFilter.FilterColumn, function(){oThis.WriteFilterColumn(filterColumns[i]);});
        };
        this.WriteFilterColumn = function(filterColumn)
        {
            var oThis = this;
            //ColId
            if(null != filterColumn.ColId)
                this.bs.WriteItem(c_oSer_FilterColumn.ColId, function(){oThis.memory.WriteLong(filterColumn.ColId);});
            //Filters
            if(null != filterColumn.Filters)
                this.bs.WriteItem(c_oSer_FilterColumn.Filters, function(){oThis.WriteFilters(filterColumn.Filters);});
            //CustomFilters
            if(null != filterColumn.CustomFiltersObj)
                this.bs.WriteItem(c_oSer_FilterColumn.CustomFilters, function(){oThis.WriteCustomFilters(filterColumn.CustomFiltersObj);});
            //DynamicFilter
            if(null != filterColumn.DynamicFilter)
                this.bs.WriteItem(c_oSer_FilterColumn.DynamicFilter, function(){oThis.WriteDynamicFilter(filterColumn.DynamicFilter);});
            //ColorFilter
            if(null != filterColumn.ColorFilter)
                this.bs.WriteItem(c_oSer_FilterColumn.ColorFilter, function(){oThis.WriteColorFilter(filterColumn.ColorFilter);});
            //Top10
            if(null != filterColumn.Top10)
                this.bs.WriteItem(c_oSer_FilterColumn.Top10, function(){oThis.WriteTop10(filterColumn.Top10);});
            //ShowButton
            if(null != filterColumn.ShowButton)
                this.bs.WriteItem(c_oSer_FilterColumn.ShowButton, function(){oThis.memory.WriteBool(filterColumn.ShowButton);});
        };
        this.WriteFilters = function(filters)
        {
            var oThis = this;
            if(null != filters.Values)
            {
				for(var i in filters.Values)
					this.bs.WriteItem(c_oSer_FilterColumn.Filter, function(){oThis.WriteFilter(i);});
            }
            if(null != filters.Dates)
            {
                for(var i = 0, length = filters.Dates.length; i < length; ++i)
                    this.bs.WriteItem(c_oSer_FilterColumn.DateGroupItem, function(){oThis.WriteDateGroupItem(filters.Dates[i]);});
            }
            if(null != filters.Blank)
                this.bs.WriteItem(c_oSer_FilterColumn.FiltersBlank, function(){oThis.memory.WriteBool(filters.Blank);});
        };
        this.WriteFilter = function(val)
        {
            if(null != val)
            {
                this.memory.WriteByte(c_oSer_Filter.Val);
                this.memory.WriteString2(val);
            }
        };
        this.WriteDateGroupItem = function(dateGroupItem)
        {
			var oDateGroupItem = new AscCommonExcel.DateGroupItem();
			oDateGroupItem.convertRangeToDateGroupItem(dateGroupItem);
			dateGroupItem = oDateGroupItem;
			
			if(null != dateGroupItem.DateTimeGrouping)
            {
                this.memory.WriteByte(c_oSer_DateGroupItem.DateTimeGrouping);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteByte(dateGroupItem.DateTimeGrouping);
            }
            if(null != dateGroupItem.Day)
            {
                this.memory.WriteByte(c_oSer_DateGroupItem.Day);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(dateGroupItem.Day);
            }
            if(null != dateGroupItem.Hour)
            {
                this.memory.WriteByte(c_oSer_DateGroupItem.Hour);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(dateGroupItem.Hour);
            }
            if(null != dateGroupItem.Minute)
            {
                this.memory.WriteByte(c_oSer_DateGroupItem.Minute);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(dateGroupItem.Minute);
            }
            if(null != dateGroupItem.Month)
            {
                this.memory.WriteByte(c_oSer_DateGroupItem.Month);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(dateGroupItem.Month);
            }
            if(null != dateGroupItem.Second)
            {
                this.memory.WriteByte(c_oSer_DateGroupItem.Second);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(dateGroupItem.Second);
            }
            if(null != dateGroupItem.Year)
            {
                this.memory.WriteByte(c_oSer_DateGroupItem.Year);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(dateGroupItem.Year);
            }
        };
        this.WriteCustomFilters = function(customFilters)
        {
            var oThis = this;
            if(null != customFilters.And)
                this.bs.WriteItem(c_oSer_CustomFilters.And, function(){oThis.memory.WriteBool(customFilters.And);});
            if(null != customFilters.CustomFilters && customFilters.CustomFilters.length > 0)
                this.bs.WriteItem(c_oSer_CustomFilters.CustomFilters, function(){oThis.WriteCustomFiltersItems(customFilters.CustomFilters);});
        };
        this.WriteCustomFiltersItems = function(aCustomFilters)
        {
            var oThis = this;
            for(var i = 0, length = aCustomFilters.length; i < length; ++i)
                this.bs.WriteItem(c_oSer_CustomFilters.CustomFilter, function(){oThis.WriteCustomFiltersItem(aCustomFilters[i]);});
        };
        this.WriteCustomFiltersItem = function(customFilter)
        {
            if(null != customFilter.Operator)
            {
                this.memory.WriteByte(c_oSer_CustomFilters.Operator);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteByte(customFilter.Operator);
            }
            if(null != customFilter.Val)
            {
                this.memory.WriteByte(c_oSer_CustomFilters.Val);
                this.memory.WriteByte(c_oSerPropLenType.Variable);
                this.memory.WriteString2(customFilter.Val);
            }
        };
        this.WriteDynamicFilter = function(dynamicFilter)
        {
            if(null != dynamicFilter.Type)
            {
                this.memory.WriteByte(c_oSer_DynamicFilter.Type);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteByte(dynamicFilter.Type);
            }
            if(null != dynamicFilter.Val)
            {
                this.memory.WriteByte(c_oSer_DynamicFilter.Val);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(dynamicFilter.Val);
            }
            if(null != dynamicFilter.MaxVal)
            {
                this.memory.WriteByte(c_oSer_DynamicFilter.MaxVal);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(dynamicFilter.MaxVal);
            }
        };
        this.WriteColorFilter = function(colorFilter)
        {
            if(null != colorFilter.CellColor)
            {
                this.memory.WriteByte(c_oSer_ColorFilter.CellColor);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(colorFilter.CellColor);
            }
            if(null != colorFilter.dxf)
            {
                this.memory.WriteByte(c_oSer_ColorFilter.DxfId);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(this.aDxfs.length);
                this.aDxfs.push(colorFilter.dxf);
            }
        };
        this.WriteTop10 = function(top10)
        {
            if(null != top10.FilterVal)
            {
                this.memory.WriteByte(c_oSer_Top10.FilterVal);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(top10.FilterVal);
            }
            if(null != top10.Percent)
            {
                this.memory.WriteByte(c_oSer_Top10.Percent);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(top10.Percent);
            }
            if(null != top10.Top)
            {
                this.memory.WriteByte(c_oSer_Top10.Top);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(top10.Top);
            }
            if(null != top10.Val)
            {
                this.memory.WriteByte(c_oSer_Top10.Val);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(top10.Val);
            }
        };
        this.WriteSortState = function(sortState)
        {
            var oThis = this;
            if(null != sortState.Ref)
            {
                this.memory.WriteByte(c_oSer_SortState.Ref);
                this.memory.WriteString2(sortState.Ref.getName());
            }
            if(null != sortState.CaseSensitive)
                this.bs.WriteItem(c_oSer_SortState.CaseSensitive, function(){oThis.memory.WriteBool(sortState.CaseSensitive);});
            if(null != sortState.SortConditions)
                this.bs.WriteItem(c_oSer_SortState.SortConditions, function(){oThis.WriteSortConditions(sortState.SortConditions);});
        };
        this.WriteSortConditions = function(sortConditions)
        {
            var oThis = this;
            for(var i = 0, length = sortConditions.length; i < length; ++i)
                this.bs.WriteItem(c_oSer_SortState.SortCondition, function(){oThis.WriteSortCondition(sortConditions[i]);});
        };
        this.WriteSortCondition = function(sortCondition)
        {
            if(null != sortCondition.Ref)
            {
                this.memory.WriteByte(c_oSer_SortState.ConditionRef);
                this.memory.WriteByte(c_oSerPropLenType.Variable);
                this.memory.WriteString2(sortCondition.Ref.getName());
            }
            if(null != sortCondition.ConditionSortBy)
            {
                this.memory.WriteByte(c_oSer_SortState.ConditionSortBy);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteByte(sortCondition.ConditionSortBy);
            }
            if(null != sortCondition.ConditionDescending)
            {
                this.memory.WriteByte(c_oSer_SortState.ConditionDescending);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(sortCondition.ConditionDescending);
            }
            if(null != sortCondition.dxf)
            {
                this.memory.WriteByte(c_oSer_SortState.ConditionDxfId);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(this.aDxfs.length);
                this.aDxfs.push(sortCondition.dxf);
            }
        };
        this.WriteTableColumns = function(tableColumns)
        {
            var oThis = this;
            for(var i = 0, length = tableColumns.length; i < length; ++i)
                this.bs.WriteItem(c_oSer_TableColumns.TableColumn, function(){oThis.WriteTableColumn(tableColumns[i]);});
        };
        this.WriteTableColumn = function(tableColumn)
        {
            var oThis = this;
            if(null != tableColumn.Name)
            {
                this.memory.WriteByte(c_oSer_TableColumns.Name);
                this.memory.WriteString2(tableColumn.Name);
            }
            if(null != tableColumn.TotalsRowLabel)
            {
                this.memory.WriteByte(c_oSer_TableColumns.TotalsRowLabel);
                this.memory.WriteString2(tableColumn.TotalsRowLabel);
            }
            if(null != tableColumn.TotalsRowFunction)
                this.bs.WriteItem(c_oSer_TableColumns.TotalsRowFunction, function(){oThis.memory.WriteByte(tableColumn.TotalsRowFunction);});

            if(null != tableColumn.TotalsRowFormula)
            {
                this.memory.WriteByte(c_oSer_TableColumns.TotalsRowFormula);
                this.memory.WriteString2(tableColumn.TotalsRowFormula.getFormula());
            }
            if(null != tableColumn.dxf)
            {
                this.bs.WriteItem(c_oSer_TableColumns.DataDxfId, function(){oThis.memory.WriteLong(oThis.aDxfs.length);});
                this.aDxfs.push(tableColumn.dxf);
            }
            if(null != tableColumn.CalculatedColumnFormula)
            {
                this.memory.WriteByte(c_oSer_TableColumns.CalculatedColumnFormula);
                this.memory.WriteString2(tableColumn.CalculatedColumnFormula);
            }
        };
        this.WriteTableStyleInfo = function(tableStyleInfo)
        {
            if(null != tableStyleInfo.Name)
            {
                this.memory.WriteByte(c_oSer_TableStyleInfo.Name);
                this.memory.WriteByte(c_oSerPropLenType.Variable);
                this.memory.WriteString2(tableStyleInfo.Name);
            }
            if(null != tableStyleInfo.ShowColumnStripes)
            {
                this.memory.WriteByte(c_oSer_TableStyleInfo.ShowColumnStripes);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(tableStyleInfo.ShowColumnStripes);
            }
            if(null != tableStyleInfo.ShowRowStripes)
            {
                this.memory.WriteByte(c_oSer_TableStyleInfo.ShowRowStripes);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(tableStyleInfo.ShowRowStripes);
            }
            if(null != tableStyleInfo.ShowFirstColumn)
            {
                this.memory.WriteByte(c_oSer_TableStyleInfo.ShowFirstColumn);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(tableStyleInfo.ShowFirstColumn);
            }
            if(null != tableStyleInfo.ShowLastColumn)
            {
                this.memory.WriteByte(c_oSer_TableStyleInfo.ShowLastColumn);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(tableStyleInfo.ShowLastColumn);
            }
        }
    }
    /** @constructor */
    function BinarySharedStringsTableWriter(memory, wb, oSharedStrings)
    {
        this.memory = memory;
		this.wb = wb;
        this.bs = new BinaryCommonWriter(this.memory);
        this.bsw = new BinaryStylesTableWriter(this.memory);
        this.oSharedStrings = oSharedStrings;
        this.Write = function()
        {
            var oThis = this;
            this.bs.WriteItemWithLength(function(){oThis.WriteSharedStringsContent();});
        };
        this.WriteSharedStringsContent = function()
        {
            var oThis = this;
            var aSharedStrings = [];
			for (var i in this.oSharedStrings.strings) {
				if (this.oSharedStrings.strings.hasOwnProperty(i)){
					var from = i - 0;
					var to = oSharedStrings.strings[i];
					aSharedStrings[to] = this.wb.sharedStrings.get(from);
                }
			}
			for (var i = 0; i < aSharedStrings.length; ++i) {
				this.bs.WriteItem(c_oSerSharedStringTypes.Si, function(){oThis.WriteSi(aSharedStrings[i]);});
			}
        };
        this.WriteSi = function(si)
        {
			var oThis = this;
			if (typeof si === 'string') {
				this.memory.WriteByte(c_oSerSharedStringTypes.Text);
				this.memory.WriteString2(si);
			} else {
				for (var i = 0, length = si.length; i < length; ++i) {
					this.bs.WriteItem(c_oSerSharedStringTypes.Run, function() {oThis.WriteRun(si[i]);});
				}
			}
        };
        this.WriteRun = function(run)
        {
            var oThis = this;
            if(null != run.format)
                this.bs.WriteItem(c_oSerSharedStringTypes.RPr, function(){oThis.bsw.WriteFont(run.format);});
            if(null != run.text)
            {
                this.memory.WriteByte(c_oSerSharedStringTypes.Text);
                this.memory.WriteString2(run.text);
            }
        };
    }

	function StyleWriteMap(action, prepare) {
		this.action = action;
		this.prepare = prepare;
		this.ids = {};
		this.elems = [];
	}

	StyleWriteMap.prototype.add = function(elem) {
		var index = 0;
		if (elem) {
			elem = this.action.call(g_StyleCache, elem);
			index = this.ids[elem.getIndexNumber()];
			if (undefined === index) {
				index = this.elems.length;
				this.ids[elem.getIndexNumber()] = index;
				this.elems.push(this.prepare ? this.prepare(elem) : elem);
			}
		}
		return index;
	};
	StyleWriteMap.prototype.addNoCheck = function(elem) {
		this.elems.push(elem);
	};
	function XfForWrite(xf) {
		this.xf = xf;
		this.fontid = 0;
		this.fillid = 0;
		this.borderid = 0;
		this.numid = 0;
		this.XfId = null;
	}

	function StylesForWrite() {
		var t = this;
		this.oXfsMap = new StyleWriteMap(g_StyleCache.addXf, function(xf) {
			return t._getElem(xf, null);
		});
		this.oFontMap = new StyleWriteMap(g_StyleCache.addFont);
		this.oFillMap = new StyleWriteMap(g_StyleCache.addFill);
		this.nDefaultFillIndex = 0;
		this.oBorderMap = new StyleWriteMap(g_StyleCache.addBorder);
		this.oNumMap = new StyleWriteMap(g_StyleCache.addNum);
		this.oXfsStylesMap = [];
	}

	StylesForWrite.prototype.init = function(defaultXfs) {
		var fill = new AscCommonExcel.Fill();
		this.oFillMap.add(fill);
		//second fill is equal to first (in Excel it is different, but it does not matter - they are ignored)
		this.oFillMap.addNoCheck(fill);
		this.oXfsMap.add(defaultXfs);
		//first 2 fills are predefined, so default fill can be not 0
		this.nDefaultFillIndex = this.oXfsMap.elems[this.oXfsMap.elems.length - 1].fillid;
	};
	StylesForWrite.prototype.add = function(xf) {
		return this.oXfsMap.add(xf);
	};
	StylesForWrite.prototype.addCellStyle = function(style) {
		this.oXfsStylesMap.push(this._getElem(style.xfs, style.XfId));
	};
	StylesForWrite.prototype.finalizeCellStyles = function() {
		//XfId это порядковый номер, поэтому сортируем
		this.oXfsStylesMap.sort(function(a, b) {
			return a.XfId - b.XfId;
		});
	};
	StylesForWrite.prototype.getNumIdByFormat = function(num) {
		var numid = null;
		if (null != num.id) {
			numid = num.id;
		} else {
			numid = AscCommonExcel.aStandartNumFormatsId[num.getFormat()];
		}

		if (null == numid) {
			numid = g_nNumsMaxId + this.oNumMap.add(num);
		}
		return numid;
	};
	StylesForWrite.prototype._getElem = function(xf, XfId) {
		var elem = new XfForWrite(xf);
		elem.fontid = this.oFontMap.add(xf.font);
		elem.fillid = xf.fill ? this.oFillMap.add(xf.fill) : this.nDefaultFillIndex;
		elem.borderid = this.oBorderMap.add(xf.border);
		elem.numid = xf.num ? this.getNumIdByFormat(xf.num) : 0;
		elem.XfId = XfId;
		return elem;
	};
    /** @constructor */
    function BinaryStylesTableWriter(memory, wb, oBinaryWorksheetsTableWriter)
    {
        this.memory = memory;
        this.bs = new BinaryCommonWriter(this.memory);
        this.wb = wb;
        this.aDxfs = null;
		this.stylesForWrite = null;
        if(null != oBinaryWorksheetsTableWriter)
        {
            this.aDxfs = oBinaryWorksheetsTableWriter.aDxfs;
			this.stylesForWrite = oBinaryWorksheetsTableWriter.stylesForWrite;
        }
        this.Write = function()
        {
            var oThis = this;
            this.bs.WriteItemWithLength(function(){oThis.WriteStylesContent();});
        };
        this.WriteStylesContent = function()
        {
            var oThis = this;
            var wb = this.wb;
            //borders
            this.bs.WriteItem(c_oSerStylesTypes.Borders, function(){oThis.WriteBorders();});
            //fills
            this.bs.WriteItem(c_oSerStylesTypes.Fills, function(){oThis.WriteFills();});
            //fonts
            this.bs.WriteItem(c_oSerStylesTypes.Fonts, function(){oThis.WriteFonts();});
            //CellStyleXfs
            this.bs.WriteItem(c_oSerStylesTypes.CellStyleXfs, function(){oThis.WriteCellStyleXfs();});
            //cellxfs
            this.bs.WriteItem(c_oSerStylesTypes.CellXfs, function(){oThis.WriteCellXfs();});

            //CellStyles
            this.bs.WriteItem(c_oSerStylesTypes.CellStyles, function(){oThis.WriteCellStyles(wb.CellStyles.CustomStyles);});

            if(null != wb.TableStyles)
                this.bs.WriteItem(c_oSerStylesTypes.TableStyles, function(){oThis.WriteTableStyles(wb.TableStyles);});
            //Dxfs пишется после TableStyles, потому что Dxfs может пополниться при записи TableStyles
            if(null != this.aDxfs && this.aDxfs.length > 0)
            {
                var oDxfsNumFormatToId = {};
                for(var i = 0, length = this.aDxfs.length; i < length; i++)
                {
                    var dxf = this.aDxfs[i];
                    if(dxf && dxf.num)
                        oDxfsNumFormatToId[dxf.num.getFormat()] = this.stylesForWrite.getNumIdByFormat(dxf.num);
                }
                this.bs.WriteItem(c_oSerStylesTypes.Dxfs, function(){oThis.WriteDxfs(oThis.aDxfs, oDxfsNumFormatToId);});
            }
            //numfmts пишется в конце потому что они могут пополниться при записи Dxfs
            this.bs.WriteItem(c_oSerStylesTypes.NumFmts, function(){oThis.WriteNumFmts();});
        };
        this.WriteBorders = function()
        {
            var oThis = this;
			var elems = this.stylesForWrite.oBorderMap.elems;
			for (var i = 0; i < elems.length; ++i) {
				//todo avoid diff
				var border = elems[i].getDif(g_oDefaultFormat.BorderAbs);
				this.bs.WriteItem(c_oSerStylesTypes.Border, function() {oThis.WriteBorder(border)});
            }
        };
        this.WriteBorder = function(border)
        {
            if(null == border)
                return;
            var oThis = this;
            //Bottom
            if(null != border.b)
                this.bs.WriteItem(c_oSerBorderTypes.Bottom, function(){oThis.WriteBorderProp(border.b);});
            //Diagonal
            if(null != border.d)
                this.bs.WriteItem(c_oSerBorderTypes.Diagonal, function(){oThis.WriteBorderProp(border.d);});
            //End
            if(null != border.r)
                this.bs.WriteItem(c_oSerBorderTypes.End, function(){oThis.WriteBorderProp(border.r);});
            //Horizontal
            if(null != border.ih)
                this.bs.WriteItem(c_oSerBorderTypes.Horizontal, function(){oThis.WriteBorderProp(border.ih);});
            //Start
            if(null != border.l)
                this.bs.WriteItem(c_oSerBorderTypes.Start, function(){oThis.WriteBorderProp(border.l);});
            //Top
            if(null != border.t)
                this.bs.WriteItem(c_oSerBorderTypes.Top, function(){oThis.WriteBorderProp(border.t);});
            //Vertical
            if(null != border.iv)
                this.bs.WriteItem(c_oSerBorderTypes.Vertical, function(){oThis.WriteBorderProp(border.iv);});
            //DiagonalDown
            if(null != border.dd)
                this.bs.WriteItem(c_oSerBorderTypes.DiagonalDown, function(){oThis.memory.WriteBool(border.dd);});
            //DiagonalUp
            if(null != border.du)
                this.bs.WriteItem(c_oSerBorderTypes.DiagonalUp, function(){oThis.memory.WriteBool(border.du);});
        };
        this.WriteBorderProp = function(borderProp)
        {
            var oThis = this;
            if(null != borderProp.c)
            {
                this.memory.WriteByte(c_oSerBorderPropTypes.Color);
                this.memory.WriteByte(c_oSerPropLenType.Variable);
                this.bs.WriteItemWithLength(function(){oThis.bs.WriteColorSpreadsheet(borderProp.c);});
            }
            if(null != borderProp.s)
            {
                var nStyle = EBorderStyle.borderstyleNone;
                switch(borderProp.s)
                {
                    case c_oAscBorderStyles.DashDot:			nStyle = EBorderStyle.borderstyleDashDot;break;
                    case c_oAscBorderStyles.DashDotDot:			nStyle = EBorderStyle.borderstyleDashDotDot;break;
                    case c_oAscBorderStyles.Dashed:				nStyle = EBorderStyle.borderstyleDashed;break;
                    case c_oAscBorderStyles.Dotted:				nStyle = EBorderStyle.borderstyleDotted;break;
                    case c_oAscBorderStyles.Double:				nStyle = EBorderStyle.borderstyleDouble;break;
                    case c_oAscBorderStyles.Hair:				nStyle = EBorderStyle.borderstyleHair;break;
                    case c_oAscBorderStyles.Medium:				nStyle = EBorderStyle.borderstyleMedium;break;
                    case c_oAscBorderStyles.MediumDashDot:		nStyle = EBorderStyle.borderstyleMediumDashDot;break;
                    case c_oAscBorderStyles.MediumDashDotDot:	nStyle = EBorderStyle.borderstyleMediumDashDotDot;break;
                    case c_oAscBorderStyles.MediumDashed:		nStyle = EBorderStyle.borderstyleMediumDashed;break;
                    case c_oAscBorderStyles.None:				nStyle = EBorderStyle.borderstyleNone;break;
                    case c_oAscBorderStyles.SlantDashDot:		nStyle = EBorderStyle.borderstyleSlantDashDot;break;
                    case c_oAscBorderStyles.Thick:				nStyle = EBorderStyle.borderstyleThick;break;
                    case c_oAscBorderStyles.Thin:				nStyle = EBorderStyle.borderstyleThin;break;
                }
                this.memory.WriteByte(c_oSerBorderPropTypes.Style);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteByte(nStyle);
            }
        };
        this.WriteFills = function()
        {
            var oThis = this;
			var elems = this.stylesForWrite.oFillMap.elems;
			for (var i = 0; i < elems.length; ++i) {
				this.bs.WriteItem(c_oSerStylesTypes.Fill, function() {oThis.WriteFill(elems[i]);});
            }
        };
        this.WriteFill = function(fill)
        {
            var oThis = this;
            this.bs.WriteItem(c_oSerFillTypes.PatternFill, function(){oThis.WritePatternFill(fill);});
        };
        this.WritePatternFill = function(fill)
        {
            var oThis = this;
            if(null != fill.bg)
                this.bs.WriteItem(c_oSerFillTypes.PatternFillBgColor, function(){oThis.bs.WriteColorSpreadsheet(fill.bg);});
        };
        this.WriteFonts = function()
        {
            var oThis = this;
			var elems = this.stylesForWrite.oFontMap.elems;
			for (var i = 0; i < elems.length; ++i) {
				this.bs.WriteItem(c_oSerStylesTypes.Font, function() {oThis.WriteFont(elems[i]);});
            }
        };
        this.WriteFont = function(font)
        {
            var oThis = this;
            if(null != font.b)
            {
                this.memory.WriteByte(c_oSerFontTypes.Bold);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(font.b);
            }
            if(null != font.c)
            {
                this.memory.WriteByte(c_oSerFontTypes.Color);
                this.memory.WriteByte(c_oSerPropLenType.Variable);
                this.bs.WriteItemWithLength(function(){oThis.bs.WriteColorSpreadsheet(font.c);});
            }
            if(null != font.i)
            {
                this.memory.WriteByte(c_oSerFontTypes.Italic);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(font.i);
            }
            if(null != font.fn)
            {
                this.memory.WriteByte(c_oSerFontTypes.RFont);
                this.memory.WriteByte(c_oSerPropLenType.Variable);
                this.memory.WriteString2(font.fn);
            }
            if(null != font.scheme)
            {
                this.memory.WriteByte(c_oSerFontTypes.Scheme);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteByte(font.scheme);
            }
            if(null != font.s)
            {
                this.memory.WriteByte(c_oSerFontTypes.Strike);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(font.s);
            }
            if(null != font.fs)
            {
                this.memory.WriteByte(c_oSerFontTypes.Sz);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                //tood write double
                this.memory.WriteDouble2(font.fs);
            }
            if(null != font.u)
            {
                this.memory.WriteByte(c_oSerFontTypes.Underline);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteByte(font.u);
            }
            if(null != font.va)
            {
                var va = font.va;
                //server constants SubScript:1, SuperScript: 2
                if (va === AscCommon.vertalign_SubScript) {
                    va = AscCommon.vertalign_SuperScript;
                } else if (va === AscCommon.vertalign_SuperScript) {
                    va = AscCommon.vertalign_SubScript;
                }
                this.memory.WriteByte(c_oSerFontTypes.VertAlign);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteByte(va);
            }
        };
        this.WriteNumFmts = function()
        {
            var oThis = this;
			var elems = this.stylesForWrite.oNumMap.elems;
			for (var i = 0; i < elems.length; ++i) {
				this.bs.WriteItem(c_oSerStylesTypes.NumFmt, function() {oThis.WriteNum(g_nNumsMaxId + i, elems[i].getFormat());});
            }
        };
        this.WriteNum = function(id, format)
        {
            if(null != format)
            {
                this.memory.WriteByte(c_oSerNumFmtTypes.FormatCode);
                this.memory.WriteByte(c_oSerPropLenType.Variable);
                this.memory.WriteString2(format);
            }
            if(null != id)
            {
                this.memory.WriteByte(c_oSerNumFmtTypes.NumFmtId);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(id);
            }
        };
        this.WriteCellStyleXfs = function()
        {
            var oThis = this;
			var elems = this.stylesForWrite.oXfsStylesMap;
			for (var i = 0; i < elems.length; ++i) {
				this.bs.WriteItem(c_oSerStylesTypes.Xfs, function() {oThis.WriteXfs(elems[i], true);});
            }
        };
        this.WriteCellXfs = function()
        {
            var oThis = this;
			var elems = this.stylesForWrite.oXfsMap.elems;
			for (var i = 0; i < elems.length; ++i) {
				this.bs.WriteItem(c_oSerStylesTypes.Xfs, function() {oThis.WriteXfs(elems[i]);});
            }
        };
        this.WriteXfs = function(xfForWrite, isCellStyle)
        {
            var oThis = this;
            var xf = xfForWrite.xf;
            if(null != xfForWrite.borderid)
            {
                if(0 != xfForWrite.borderid)
                {
                    this.memory.WriteByte(c_oSerXfsTypes.ApplyBorder);
                    this.memory.WriteByte(c_oSerPropLenType.Byte);
                    this.memory.WriteBool(true);
                }
                this.memory.WriteByte(c_oSerXfsTypes.BorderId);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(xfForWrite.borderid);
            }
            if(null != xfForWrite.fillid)
            {
                if(0 != xfForWrite.fillid)
                {
                    this.memory.WriteByte(c_oSerXfsTypes.ApplyFill);
                    this.memory.WriteByte(c_oSerPropLenType.Byte);
                    this.memory.WriteBool(true);
                }
                this.memory.WriteByte(c_oSerXfsTypes.FillId);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(xfForWrite.fillid);
            }
            if(null != xfForWrite.fontid)
            {
                if(0 != xfForWrite.fontid)
                {
                    this.memory.WriteByte(c_oSerXfsTypes.ApplyFont);
                    this.memory.WriteByte(c_oSerPropLenType.Byte);
                    this.memory.WriteBool(true);
                }
                this.memory.WriteByte(c_oSerXfsTypes.FontId);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(xfForWrite.fontid);
            }
            if(null != xfForWrite.numid)
            {
                if(0 != xfForWrite.numid)
                {
                    this.memory.WriteByte(c_oSerXfsTypes.ApplyNumberFormat);
                    this.memory.WriteByte(c_oSerPropLenType.Byte);
                    this.memory.WriteBool(true);
                }
                this.memory.WriteByte(c_oSerXfsTypes.NumFmtId);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(xfForWrite.numid);
            }
			if (xf) {
				if(null != xf.align)
				{
					var alignMinimized = xf.align.getDif(g_oDefaultFormat.AlignAbs);
					if(null != alignMinimized)
					{
						this.memory.WriteByte(c_oSerXfsTypes.ApplyAlignment);
						this.memory.WriteByte(c_oSerPropLenType.Byte);
						this.memory.WriteBool(true);

						this.memory.WriteByte(c_oSerXfsTypes.Aligment);
						this.memory.WriteByte(c_oSerPropLenType.Variable);
						this.bs.WriteItemWithLength(function(){oThis.WriteAlign(alignMinimized);});
					}
				}
				if(null != xf.QuotePrefix)
				{
					this.memory.WriteByte(c_oSerXfsTypes.QuotePrefix);
					this.memory.WriteByte(c_oSerPropLenType.Byte);
					this.memory.WriteBool(xf.QuotePrefix);
				}
				if(null != xf.PivotButton)
				{
					this.memory.WriteByte(c_oSerXfsTypes.PivotButton);
					this.memory.WriteByte(c_oSerPropLenType.Byte);
					this.memory.WriteBool(xf.PivotButton);
				}
				if(!isCellStyle && null != xf.XfId)
				{
					this.memory.WriteByte(c_oSerXfsTypes.XfId);
					this.memory.WriteByte(c_oSerPropLenType.Long);
					this.memory.WriteLong(xf.XfId);
				}
            }
        };
        this.WriteAlign = function(align)
        {
            if(null != align.hor)
            {
                var ha = 4;
                switch (align.hor) {
                    case AscCommon.align_Center :ha = 0;break;
                    case AscCommon.align_Justify :ha = 5;break;
                    case AscCommon.align_Left :ha = 6;break;
                    case AscCommon.align_Right :ha = 7;break;
                }
                this.memory.WriteByte(c_oSerAligmentTypes.Horizontal);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteByte(ha);
            }
            if(null != align.indent)
            {
                this.memory.WriteByte(c_oSerAligmentTypes.Indent);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(align.indent);
            }
            if(null != align.RelativeIndent)
            {
                this.memory.WriteByte(c_oSerAligmentTypes.RelativeIndent);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(align.RelativeIndent);
            }
            if(null != align.shrink)
            {
                this.memory.WriteByte(c_oSerAligmentTypes.ShrinkToFit);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(align.shrink);
            }
            if(null != align.angle)
            {
                this.memory.WriteByte(c_oSerAligmentTypes.TextRotation);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(align.angle);
            }
            if(null != align.ver)
            {
                this.memory.WriteByte(c_oSerAligmentTypes.Vertical);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteByte(align.ver);
            }
            if(null != align.wrap)
            {
                this.memory.WriteByte(c_oSerAligmentTypes.WrapText);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(align.wrap);
            }
        };
        this.WriteDxfs = function(Dxfs, oDxfsNumFormatToId)
        {
            var oThis = this;
            for(var i = 0, length = Dxfs.length; i < length; ++i)
                this.bs.WriteItem(c_oSerStylesTypes.Dxf, function(){oThis.WriteDxf(Dxfs[i], oDxfsNumFormatToId);});
        };
        this.WriteDxf = function(Dxf, oDxfsNumFormatToId)
        {
            var oThis = this;
            if(null != Dxf.align)
                this.bs.WriteItem(c_oSer_Dxf.Alignment, function(){oThis.WriteAlign(Dxf.align);});
            if(null != Dxf.border)
                this.bs.WriteItem(c_oSer_Dxf.Border, function(){oThis.WriteBorder(Dxf.border);});
            if(null != Dxf.fill)
                this.bs.WriteItem(c_oSer_Dxf.Fill, function(){oThis.WriteFill(Dxf.fill);});
            if(null != Dxf.font)
                this.bs.WriteItem(c_oSer_Dxf.Font, function(){oThis.WriteFont(Dxf.font);});
            if(null != Dxf.num && null != oDxfsNumFormatToId)
            {
                var numId = oDxfsNumFormatToId[Dxf.num.getFormat()];
                if(null != numId)
                    this.bs.WriteItem(c_oSer_Dxf.NumFmt, function(){oThis.WriteNum(numId, Dxf.num.getFormat());});
            }
        };
        this.WriteCellStyles = function (cellStyles) {
            var oThis = this;
            for(var i = 0, length = cellStyles.length; i < length; ++i)
            {
                var style = cellStyles[i];
                this.bs.WriteItem(c_oSerStylesTypes.CellStyle, function(){oThis.WriteCellStyle(style);});
            }
        };
        this.WriteCellStyle = function (oCellStyle) {
            var oThis = this;
            if (null != oCellStyle.BuiltinId)
                this.bs.WriteItem(c_oSer_CellStyle.BuiltinId, function(){oThis.memory.WriteLong(oCellStyle.BuiltinId);});
            if (null != oCellStyle.CustomBuiltin)
                this.bs.WriteItem(c_oSer_CellStyle.CustomBuiltin, function(){oThis.memory.WriteBool(oCellStyle.CustomBuiltin);});
            if (null != oCellStyle.Hidden)
                this.bs.WriteItem(c_oSer_CellStyle.Hidden, function(){oThis.memory.WriteBool(oCellStyle.Hidden);});
            if (null != oCellStyle.ILevel)
                this.bs.WriteItem(c_oSer_CellStyle.ILevel, function(){oThis.memory.WriteLong(oCellStyle.ILevel);});
            if (null != oCellStyle.Name) {
                this.memory.WriteByte(c_oSer_CellStyle.Name);
                this.memory.WriteString2(oCellStyle.Name);
            }
            if (null != oCellStyle.XfId)
                this.bs.WriteItem(c_oSer_CellStyle.XfId, function(){oThis.memory.WriteLong(oCellStyle.XfId);});
        };
        this.WriteTableStyles = function(tableStyles)
        {
            var oThis = this;
            if(null != tableStyles.DefaultTableStyle)
            {
                this.memory.WriteByte(c_oSer_TableStyles.DefaultTableStyle);
                this.memory.WriteString2(tableStyles.DefaultTableStyle);
            }
            if(null != tableStyles.DefaultPivotStyle)
            {
                this.memory.WriteByte(c_oSer_TableStyles.DefaultPivotStyle);
                this.memory.WriteString2(tableStyles.DefaultPivotStyle);
            }
            var bEmptyCustom = true;
            for(var i in tableStyles.CustomStyles)
            {
                bEmptyCustom = false;
                break;
            }
            if(false == bEmptyCustom)
            {
                this.bs.WriteItem(c_oSer_TableStyles.TableStyles, function(){oThis.WriteTableCustomStyles(tableStyles.CustomStyles);});
            }
        };
        this.WriteTableCustomStyles = function(customStyles)
        {
            var oThis = this;
            for(var i in customStyles)
            {
                var style = customStyles[i];
                this.bs.WriteItem(c_oSer_TableStyles.TableStyle, function(){oThis.WriteTableCustomStyle(style);});
            }
        };
        this.WriteTableCustomStyle = function(customStyle)
        {
            var oThis = this;
            if(null != customStyle.name)
            {
                this.memory.WriteByte(c_oSer_TableStyle.Name);
                this.memory.WriteString2(customStyle.name);
            }
            if(null != customStyle.pivot)
                this.bs.WriteItem(c_oSer_TableStyle.Pivot, function(){oThis.memory.WriteBool(customStyle.pivot);});
            if(null != customStyle.table)
                this.bs.WriteItem(c_oSer_TableStyle.Table, function(){oThis.memory.WriteBool(customStyle.table);});

            this.bs.WriteItem(c_oSer_TableStyle.Elements, function(){oThis.WriteTableCustomStyleElements(customStyle);});
        };
        this.WriteTableCustomStyleElements = function(customStyle)
        {
            var oThis = this;
            if(null != customStyle.blankRow)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeBlankRow, customStyle.blankRow);});
            if(null != customStyle.firstColumn)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeFirstColumn, customStyle.firstColumn);});
            if(null != customStyle.firstColumnStripe)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeFirstColumnStripe, customStyle.firstColumnStripe);});
            if(null != customStyle.firstColumnSubheading)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeFirstColumnSubheading, customStyle.firstColumnSubheading);});
            if(null != customStyle.firstHeaderCell)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeFirstHeaderCell, customStyle.firstHeaderCell);});
            if(null != customStyle.firstRowStripe)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeFirstRowStripe, customStyle.firstRowStripe);});
            if(null != customStyle.firstRowSubheading)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeFirstRowSubheading, customStyle.firstRowSubheading);});
            if(null != customStyle.firstSubtotalColumn)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeFirstSubtotalColumn, customStyle.firstSubtotalColumn);});
            if(null != customStyle.firstSubtotalRow)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeFirstSubtotalRow, customStyle.firstSubtotalRow);});
            if(null != customStyle.firstTotalCell)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeFirstTotalCell, customStyle.firstTotalCell);});
            if(null != customStyle.headerRow)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeHeaderRow, customStyle.headerRow);});
            if(null != customStyle.lastColumn)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeLastColumn, customStyle.lastColumn);});
            if(null != customStyle.lastHeaderCell)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeLastHeaderCell, customStyle.lastHeaderCell);});
            if(null != customStyle.lastTotalCell)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeLastTotalCell, customStyle.lastTotalCell);});
            if(null != customStyle.pageFieldLabels)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypePageFieldLabels, customStyle.pageFieldLabels);});
            if(null != customStyle.pageFieldValues)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypePageFieldValues, customStyle.pageFieldValues);});
            if(null != customStyle.secondColumnStripe)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeSecondColumnStripe, customStyle.secondColumnStripe);});
            if(null != customStyle.secondColumnSubheading)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeSecondColumnSubheading, customStyle.secondColumnSubheading);});
            if(null != customStyle.secondRowStripe)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeSecondRowStripe, customStyle.secondRowStripe);});
            if(null != customStyle.secondRowSubheading)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeSecondRowSubheading, customStyle.secondRowSubheading);});
            if(null != customStyle.secondSubtotalColumn)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeSecondSubtotalColumn, customStyle.secondSubtotalColumn);});
            if(null != customStyle.secondSubtotalRow)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeSecondSubtotalRow, customStyle.secondSubtotalRow);});
            if(null != customStyle.thirdColumnSubheading)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeThirdColumnSubheading, customStyle.thirdColumnSubheading);});
            if(null != customStyle.thirdRowSubheading)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeThirdRowSubheading, customStyle.thirdRowSubheading);});
            if(null != customStyle.thirdSubtotalColumn)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeThirdSubtotalColumn, customStyle.thirdSubtotalColumn);});
            if(null != customStyle.thirdSubtotalRow)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeThirdSubtotalRow, customStyle.thirdSubtotalRow);});
            if(null != customStyle.totalRow)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeTotalRow, customStyle.totalRow);});
            if(null != customStyle.wholeTable)
                this.bs.WriteItem(c_oSer_TableStyle.Element, function(){oThis.WriteTableCustomStyleElement(ETableStyleType.tablestyletypeWholeTable, customStyle.wholeTable);});
        };
        this.WriteTableCustomStyleElement = function(type, customElement)
        {
            if(null != type)
            {
                this.memory.WriteByte(c_oSer_TableStyleElement.Type);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteByte(type);
            }
            if(null != customElement.size)
            {
                this.memory.WriteByte(c_oSer_TableStyleElement.Size);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(customElement.size);
            }
            if(null != customElement.dxf && null != this.aDxfs)
            {
                this.memory.WriteByte(c_oSer_TableStyleElement.DxfId);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(this.aDxfs.length);
                this.aDxfs.push(customElement.dxf);
            }
        };
    }
    function BinaryWorkbookTableWriter(memory, wb, oBinaryWorksheetsTableWriter, isCopyPaste)
    {
        this.memory = memory;
        this.bs = new BinaryCommonWriter(this.memory);
        this.wb = wb;
        this.oBinaryWorksheetsTableWriter = oBinaryWorksheetsTableWriter;
        this.isCopyPaste = isCopyPaste;
        this.Write = function()
        {
            var oThis = this;
            this.bs.WriteItemWithLength(function(){oThis.WriteWorkbookContent();});
        };
        this.WriteWorkbookContent = function()
        {
            var oThis = this;
            //WorkbookPr
            this.bs.WriteItem(c_oSerWorkbookTypes.WorkbookPr, function(){oThis.WriteWorkbookPr();});

            //BookViews
            this.bs.WriteItem(c_oSerWorkbookTypes.BookViews, function(){oThis.WriteBookViews();});

            //DefinedNames
            this.bs.WriteItem(c_oSerWorkbookTypes.DefinedNames, function(){oThis.WriteDefinedNames();});

			this.bs.WriteItem(c_oSerWorkbookTypes.CalcPr, function(){oThis.WriteCalcPr(oThis.wb.calcPr);});

			//PivotCaches
			var isEmptyCaches = true;
			var pivotCaches = {};
			this.oBinaryWorksheetsTableWriter.wb.forEach(function(ws) {
				for (var i = 0; i < ws.pivotTables.length; ++i) {
					var pivotTable = ws.pivotTables[i];
					if (null !== pivotTable.cacheId && pivotTable.cacheDefinition) {
						isEmptyCaches = false;
						pivotCaches[pivotTable.cacheId] = pivotTable.cacheDefinition;
					}
				}
			}, this.oBinaryWorksheetsTableWriter.isCopyPaste);
			if (!isEmptyCaches) {
				this.bs.WriteItem(c_oSerWorkbookTypes.PivotCaches, function () {oThis.WritePivotCaches(pivotCaches);});
			}
			if (this.wb.externalReferences.length > 0) {
				this.bs.WriteItem(c_oSerWorkbookTypes.ExternalReferences, function() {oThis.WriteExternalReferences();});
			}
			if (!this.isCopyPaste) {
				var macros = this.wb.oApi.macros.GetData();
				if (macros) {
					this.bs.WriteItem(c_oSerWorkbookTypes.JsaProject, function() {oThis.memory.WriteXmlString(macros);});
				}
                if (this.wb.aComments.length > 0) {
                    this.bs.WriteItem(c_oSerWorkbookTypes.Comments, function() {oThis.WriteComments(oThis.wb.aComments);});
                }
			}
        };
        this.WriteWorkbookPr = function()
        {
            var oWorkbookPr = this.wb.WorkbookPr;
            if(null != oWorkbookPr)
            {
                if(null != oWorkbookPr.Date1904)
                {
                    this.memory.WriteByte(c_oSerWorkbookPrTypes.Date1904);
                    this.memory.WriteByte(c_oSerPropLenType.Byte);
                    this.memory.WriteBool(oWorkbookPr.Date1904);
                }
                else if (null != oWorkbookPr.DateCompatibility)
                {
                    this.memory.WriteByte(c_oSerWorkbookPrTypes.DateCompatibility);
                    this.memory.WriteByte(c_oSerPropLenType.Byte);
                    this.memory.WriteBool(oWorkbookPr.DateCompatibility);
                }
				else if (null != oWorkbookPr.HidePivotFieldList)
				{
					this.memory.WriteByte(c_oSerWorkbookPrTypes.HidePivotFieldList);
					this.memory.WriteByte(c_oSerPropLenType.Byte);
					this.memory.WriteBool(oWorkbookPr.HidePivotFieldList);
				}
				else if (null != oWorkbookPr.ShowPivotChartFilter)
				{
					this.memory.WriteByte(c_oSerWorkbookPrTypes.ShowPivotChartFilter);
					this.memory.WriteByte(c_oSerPropLenType.Byte);
					this.memory.WriteBool(oWorkbookPr.ShowPivotChartFilter);
				}
			}
        };
        this.WriteBookViews = function()
        {
            var oThis = this;
            this.bs.WriteItem(c_oSerWorkbookTypes.WorkbookView, function(){oThis.WriteWorkbookView();});
        };
        this.WriteWorkbookView = function()
        {
            if (null != this.wb.nActive)
            {
                this.memory.WriteByte( c_oSerWorkbookViewTypes.ActiveTab);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(this.wb.nActive);
            }
        };
        this.WriteDefinedNames = function()
        {
            var oThis = this;
            var defNameList = this.wb.dependencyFormulas.saveDefName();

            var filterDefName = "_xlnm._FilterDatabase";
			var tempMap = {};

            if(null != defNameList ){
                for(var i = 0; i < defNameList.length; i++){
                    if(defNameList[i].Name !== filterDefName) {
						//TODO временная правка. на открытие может приходить _FilterDatabase. защищаемся от записи двух одинаковых именванных диапазона
						if(defNameList[i].Name === "_FilterDatabase") {
							tempMap[defNameList[i].LocalSheetId] = 1;
						}
						this.bs.WriteItem(c_oSerWorkbookTypes.DefinedName, function(){oThis.WriteDefinedName(defNameList[i]);});
                    }
                }
            }

            //write filters defines name
            //TODO сделать добавление данных именованных диапазонов при добавлении а/ф
            var ws, ref, defNameRef, defName;
            for(var i = 0; i < wb.aWorksheets.length; i++) {
				ws = wb.aWorksheets[i];
                if(ws && ws.AutoFilter && ws.AutoFilter.Ref && !tempMap[ws.index]) {
                    ref = ws.AutoFilter.Ref;
					defNameRef = AscCommon.parserHelp.get3DRef(ws.getName(), ref.getAbsName());
					defName = new Asc.asc_CDefName(filterDefName, defNameRef, ws.index, false, true);
                    this.bs.WriteItem(c_oSerWorkbookTypes.DefinedName, function(){oThis.WriteDefinedName(defName);});
                }
            }
        };
        this.WriteDefinedName = function(oDefinedName, LocalSheetId)
        {
            var oThis = this;
            if (null != oDefinedName.Name)
            {
                this.memory.WriteByte(c_oSerDefinedNameTypes.Name);
                this.memory.WriteString2(oDefinedName.Name);
            }
            if (null != oDefinedName.Ref)
            {
                this.memory.WriteByte(c_oSerDefinedNameTypes.Ref);
                this.memory.WriteString2(oDefinedName.Ref);
            }
            if (null !== oDefinedName.LocalSheetId){
                this.bs.WriteItem(c_oSerDefinedNameTypes.LocalSheetId, function(){oThis.memory.WriteLong(oDefinedName.LocalSheetId);});
            }
            if (null != oDefinedName.Hidden) {
                this.bs.WriteItem(c_oSerDefinedNameTypes.Hidden, function(){oThis.memory.WriteBool(oDefinedName.Hidden);});
            }
        };
		this.WriteCalcPr = function(calcPr)
		{
			var t = this;
			//calcId Specifies the version of the calculation engine used to calculate values in the workbook
			//do not pretend to be other editors
			// if (null != calcPr.calcId) {
				// this.bs.WriteItem(c_oSerCalcPrTypes.CalcId, function() {t.memory.WriteLong(calcPr.calcId)});
			// }
			if (null != calcPr.calcMode) {
				this.bs.WriteItem(c_oSerCalcPrTypes.CalcMode, function() {t.memory.WriteByte(calcPr.calcMode)});
			}
			if (null != calcPr.fullCalcOnLoad) {
				this.bs.WriteItem(c_oSerCalcPrTypes.FullCalcOnLoad, function() {t.memory.WriteBool(calcPr.fullCalcOnLoad)});
			}
			if (null != calcPr.refMode) {
				this.bs.WriteItem(c_oSerCalcPrTypes.RefMode, function() {t.memory.WriteByte(calcPr.refMode)});
			}
			if (null != calcPr.iterate) {
				this.bs.WriteItem(c_oSerCalcPrTypes.Iterate, function() {t.memory.WriteBool(calcPr.iterate)});
			}
			if (null != calcPr.iterateCount) {
				this.bs.WriteItem(c_oSerCalcPrTypes.IterateCount, function() {t.memory.WriteLong(calcPr.iterateCount)});
			}
			if (null != calcPr.iterateDelta) {
				this.bs.WriteItem(c_oSerCalcPrTypes.IterateDelta, function() {t.memory.WriteDouble2(calcPr.iterateDelta)});
			}
			if (null != calcPr.fullPrecision) {
				this.bs.WriteItem(c_oSerCalcPrTypes.FullPrecision, function() {t.memory.WriteBool(calcPr.fullPrecision)});
			}
			if (null != calcPr.calcCompleted) {
				this.bs.WriteItem(c_oSerCalcPrTypes.CalcCompleted, function() {t.memory.WriteBool(calcPr.calcCompleted)});
			}
			if (null != calcPr.calcOnSave) {
				this.bs.WriteItem(c_oSerCalcPrTypes.CalcOnSave, function() {t.memory.WriteBool(calcPr.calcOnSave)});
			}
			if (null != calcPr.concurrentCalc) {
				this.bs.WriteItem(c_oSerCalcPrTypes.ConcurrentCalc, function() {t.memory.WriteBool(calcPr.concurrentCalc)});
			}
			if (null != calcPr.concurrentManualCount) {
				this.bs.WriteItem(c_oSerCalcPrTypes.ConcurrentManualCount, function() {t.memory.WriteLong(calcPr.concurrentManualCount)});
			}
			if (null != calcPr.forceFullCalc) {
				this.bs.WriteItem(c_oSerCalcPrTypes.ForceFullCalc, function() {t.memory.WriteBool(calcPr.forceFullCalc)});
			}
		};
		this.WritePivotCaches = function(pivotCaches) {
			var oThis = this;
			for (var id in pivotCaches) {
				this.bs.WriteItem(c_oSerWorkbookTypes.PivotCache, function(){oThis.WritePivotCache(id, pivotCaches[id]);});
			}
		};
		this.WritePivotCache = function(id, pivotCache) {
			var oThis = this;
			var oldId = pivotCache.id;
			pivotCache.id = null;
			this.bs.WriteItem(c_oSer_PivotTypes.id, function() {
				oThis.memory.WriteLong(id - 0);
			});
			this.bs.WriteItem(c_oSer_PivotTypes.cache, function() {
				pivotCache.toXml(oThis.memory);
			});
			if (pivotCache.cacheRecords) {
				this.bs.WriteItem(c_oSer_PivotTypes.record, function() {
					pivotCache.cacheRecords.toXml(oThis.memory);
				});
			}
			pivotCache.id = oldId;
		};
		this.WriteExternalReferences = function() {
			var oThis = this;
			for (var i = 0; i < this.wb.externalReferences.length; i++) {
				var externalReference = this.wb.externalReferences[i];
				switch (externalReference.Type) {
					case 0:
						this.bs.WriteItem(c_oSerWorkbookTypes.ExternalBook, function() {
							oThis.WriteExternalReference(externalReference);
						});
						break;
					case 1:
						this.bs.WriteItem(c_oSerWorkbookTypes.OleLink, function() {
							oThis.memory.WriteBuffer(externalReference.Buffer, 0, externalReference.Buffer.length);
						});
						break;
					case 2:
						this.bs.WriteItem(c_oSerWorkbookTypes.DdeLink, function() {
							oThis.memory.WriteBuffer(externalReference.Buffer, 0, externalReference.Buffer.length);
						});
						break;
				}
			}
		};
		this.WriteExternalReference = function(externalReference) {
			var oThis = this;
			if (null != externalReference.Id) {
				oThis.memory.WriteByte(c_oSer_ExternalLinkTypes.Id);
				oThis.memory.WriteString2(externalReference.Id);
			}
			if (externalReference.SheetNames.length > 0) {
				this.bs.WriteItem(c_oSer_ExternalLinkTypes.SheetNames, function() {
					oThis.WriteExternalSheetNames(externalReference.SheetNames);
				});
			}
			if (externalReference.DefinedNames.length > 0) {
				this.bs.WriteItem(c_oSer_ExternalLinkTypes.DefinedNames, function() {
					oThis.WriteExternalDefinedNames(externalReference.DefinedNames);
				});
			}
			if (externalReference.SheetDataSet.length > 0) {
				this.bs.WriteItem(c_oSer_ExternalLinkTypes.SheetDataSet, function() {
					oThis.WriteExternalSheetDataSet(externalReference.SheetDataSet);
				});
			}
		};
		this.WriteExternalSheetNames = function(sheetNames) {
			for (var i = 0; i < sheetNames.length; i++) {
				this.memory.WriteByte(c_oSer_ExternalLinkTypes.SheetName);
				this.memory.WriteString2(sheetNames[i]);
			}
		};
		this.WriteExternalDefinedNames = function(definedNames) {
			var oThis = this;
			for (var i = 0; i < definedNames.length; i++) {
				this.bs.WriteItem(c_oSer_ExternalLinkTypes.DefinedName, function() {
					oThis.WriteExternalDefinedName(definedNames[i]);
				});
			}
		};
		this.WriteExternalDefinedName = function(definedName) {
			var oThis = this;
			if (null != definedName.Name) {
				oThis.memory.WriteByte(c_oSer_ExternalLinkTypes.DefinedNameName);
				oThis.memory.WriteString2(definedName.Name);
			}
			if (null != definedName.RefersTo) {
				oThis.memory.WriteByte(c_oSer_ExternalLinkTypes.DefinedNameRefersTo);
				oThis.memory.WriteString2(definedName.RefersTo);
			}
			if (null != definedName.SheetId) {
				this.bs.WriteItem(c_oSer_ExternalLinkTypes.DefinedNameSheetId, function() {
					oThis.memory.WriteLong(definedName.SheetId);
				});
			}
		};
		this.WriteExternalSheetDataSet = function(sheetDataSet) {
			var oThis = this;
			for (var i = 0; i < sheetDataSet.length; i++) {
				this.bs.WriteItem(c_oSer_ExternalLinkTypes.SheetData, function() {
					oThis.WriteExternalSheetData(sheetDataSet[i]);
				});
			}
		};
		this.WriteExternalSheetData = function(sheetData) {
			var oThis = this;
			if (null != sheetData.SheetId) {
				this.bs.WriteItem(c_oSer_ExternalLinkTypes.SheetDataSheetId, function() {
					oThis.memory.WriteLong(sheetData.SheetId);
				});
			}
			if (null != sheetData.RefreshError) {
				this.bs.WriteItem(c_oSer_ExternalLinkTypes.SheetDataRefreshError, function() {
					oThis.memory.WriteBool(sheetData.RefreshError);
				});
			}
			if (sheetData.Row.length > 0) {
				for (var i = 0; i < sheetData.Row.length; i++) {
					this.bs.WriteItem(c_oSer_ExternalLinkTypes.SheetDataRow, function() {
						oThis.WriteExternalRow(sheetData.Row[i]);
					});
				}
			}
		};
		this.WriteExternalRow = function(row) {
			var oThis = this;
			if (null != row.R) {
				this.bs.WriteItem(c_oSer_ExternalLinkTypes.SheetDataRowR, function() {
					oThis.memory.WriteLong(row.R);
				});
			}
			if (row.Cell.length > 0) {
				for (var i = 0; i < row.Cell.length; i++) {
					this.bs.WriteItem(c_oSer_ExternalLinkTypes.SheetDataRowCell, function() {
						oThis.WriteExternalCell(row.Cell[i]);
					});
				}
			}
		};
		this.WriteExternalCell = function(cell) {
			var oThis = this;
			if (null != cell.Ref) {
				oThis.memory.WriteByte(c_oSer_ExternalLinkTypes.SheetDataRowCellRef);
				oThis.memory.WriteString2(cell.Ref);
			}
			if (null != cell.CellType) {
				this.bs.WriteItem(c_oSer_ExternalLinkTypes.SheetDataRowCellType, function() {
					oThis.memory.WriteByte(cell.CellType);
				});
			}
			if (null != cell.CellValue) {
				oThis.memory.WriteByte(c_oSer_ExternalLinkTypes.SheetDataRowCellValue);
				oThis.memory.WriteString2(cell.CellValue);
			}
		};
        this.WriteComments = function(aComments) {
            var t = this;
            for (var i = 0; i < aComments.length; ++i) {
                this.bs.WriteItem( c_oSer_Comments.CommentData, function(){t.oBinaryWorksheetsTableWriter.WriteCommentData(aComments[i]);});
            }
        };
    }
	function BinaryWorksheetsTableWriter(memory, wb, oSharedStrings, aDxfs, isCopyPaste)
    {
        this.memory = memory;
        this.bs = new BinaryCommonWriter(this.memory);
        this.wb = wb;
        this.oSharedStrings = oSharedStrings;
        this.aDxfs = aDxfs;
		this.stylesForWrite = new StylesForWrite();
        this.isCopyPaste = isCopyPaste;
        this.sharedFormulas = {};
		this.sharedFormulasIndex = 0;
        this._getCrc32FromObjWithProperty = function(val)
        {
            return Asc.crc32(this._getStringFromObjWithProperty(val));
        };
        this._getStringFromObjWithProperty = function(val)
        {
            var sRes = "";
            if(val.getProperties)
            {
                var properties = val.getProperties();
                for(var i in properties)
                {
                    var oCurProp = val.getProperty(properties[i]);
                    if(null != oCurProp && oCurProp.getProperties)
                        sRes += this._getStringFromObjWithProperty(oCurProp);
                    else
                        sRes += oCurProp;
                }
            }
            return sRes;
        };
        this._prepeareStyles = function()
        {
			this.stylesForWrite.init(this.wb.oStyleManager.oDefaultXfs);
			var styles = this.wb.CellStyles.CustomStyles;
			var style = null;
			for(var i = 0; i < styles.length; ++i) {
				style = styles[i];
				if (style.xfs) {
					this.stylesForWrite.addCellStyle(style);
				}
			}
			this.stylesForWrite.finalizeCellStyles();
        };
        this.Write = function()
        {
            var oThis = this;
            this._prepeareStyles();
            this.bs.WriteItemWithLength(function(){oThis.WriteWorksheetsContent();});
        };
        this.WriteWorksheetsContent = function()
        {
			var oThis = this;
			this.wb.forEach(function (ws, index) {
				oThis.bs.WriteItem(c_oSerWorksheetsTypes.Worksheet, function () {
					oThis.WriteWorksheet(ws, index);
				});
			}, this.isCopyPaste);
        };
        this.WriteWorksheet = function(ws, index)
        {
            var i;
            var oThis = this;
            this.bs.WriteItem(c_oSerWorksheetsTypes.WorksheetProp, function(){oThis.WriteWorksheetProp(ws, index);});

            if(ws.aCols.length > 0 || null != ws.oAllCol)
                this.bs.WriteItem(c_oSerWorksheetsTypes.Cols, function(){oThis.WriteWorksheetCols(ws);});
            
            if(!oThis.isCopyPaste)
               this.bs.WriteItem(c_oSerWorksheetsTypes.SheetViews, function(){oThis.WriteSheetViews(ws);});

            if (null !== ws.sheetPr)
                this.bs.WriteItem(c_oSerWorksheetsTypes.SheetPr, function () {oThis.WriteSheetPr(ws.sheetPr);});

            this.bs.WriteItem(c_oSerWorksheetsTypes.SheetFormatPr, function(){oThis.WriteSheetFormatPr(ws);});

            if(null != ws.PagePrintOptions)
            {
                this.bs.WriteItem(c_oSerWorksheetsTypes.PageMargins, function(){oThis.WritePageMargins(ws.PagePrintOptions.asc_getPageMargins());});

                this.bs.WriteItem(c_oSerWorksheetsTypes.PageSetup, function(){oThis.WritePageSetup(ws.PagePrintOptions.asc_getPageSetup());});

                this.bs.WriteItem(c_oSerWorksheetsTypes.PrintOptions, function(){oThis.WritePrintOptions(ws.PagePrintOptions);});
            }

            this.bs.WriteItem(c_oSerWorksheetsTypes.SheetData, function(){oThis.WriteSheetData(ws);});

            this.bs.WriteItem(c_oSerWorksheetsTypes.Hyperlinks, function(){oThis.WriteHyperlinks(ws);});

            this.bs.WriteItem(c_oSerWorksheetsTypes.MergeCells, function(){oThis.WriteMergeCells(ws);});

            if (ws.Drawings && (ws.Drawings.length))
                this.bs.WriteItem(c_oSerWorksheetsTypes.Drawings, function(){oThis.WriteDrawings(ws.Drawings);});

            if (ws.aComments.length > 0) {
                this.bs.WriteItem(c_oSerWorksheetsTypes.Comments, function () {
                    oThis.WriteComments(ws.aComments, ws);
                });
            }

            var oBinaryTableWriter;
            if(null != ws.AutoFilter && !this.isCopyPaste)
            {
                oBinaryTableWriter = new BinaryTableWriter(this.memory, this.aDxfs);
                this.bs.WriteItem(c_oSerWorksheetsTypes.Autofilter, function(){oBinaryTableWriter.WriteAutoFilter(ws.AutoFilter);});
            }
            if(null != ws.TableParts && ws.TableParts.length > 0)
            {
                oBinaryTableWriter = new BinaryTableWriter(this.memory, this.aDxfs, this.isCopyPaste);
                this.bs.WriteItem(c_oSerWorksheetsTypes.TableParts, function(){oBinaryTableWriter.Write(ws.TableParts, ws);});
            }
			if (ws.aSparklineGroups.length > 0) {
                this.bs.WriteItem(c_oSerWorksheetsTypes.SparklineGroups, function(){oThis.WriteSparklineGroups(ws.aSparklineGroups);});
            }
            // ToDo combine rules for matching ranges
			for (i = 0; i < ws.aConditionalFormattingRules.length; ++i) {
				this.bs.WriteItem(c_oSerWorksheetsTypes.ConditionalFormatting, function(){oThis.WriteConditionalFormatting(ws.aConditionalFormattingRules[i]);});
			}
			for (i = 0; i < ws.pivotTables.length; ++i) {
				this.bs.WriteItem(c_oSerWorksheetsTypes.PivotTable, function(){oThis.WritePivotTable(ws.pivotTables[i])});
			}
            if (null !== ws.headerFooter) {
                this.bs.WriteItem(c_oSerWorksheetsTypes.HeaderFooter, function () {oThis.WriteHeaderFooter(ws.headerFooter);});
            }
            if (null !== ws.rowBreaks) {
                this.bs.WriteItem(c_oSerWorksheetsTypes.RowBreaks, function () {oThis.WriteRowColBreaks(ws.rowBreaks);});
            }
            if (null !== ws.colBreaks) {
                this.bs.WriteItem(c_oSerWorksheetsTypes.ColBreaks, function () {oThis.WriteRowColBreaks(ws.colBreaks);});
            }
            if (null !== ws.legacyDrawingHF) {
                this.bs.WriteItem(c_oSerWorksheetsTypes.LegacyDrawingHF, function () {oThis.WriteLegacyDrawingHF(ws.legacyDrawingHF);});
            }
            if (null !== ws.picture) {
                this.memory.WriteByte(c_oSerWorksheetsTypes.Picture);
                this.memory.WriteString2(ws.picture);
            }
        };
        this.WriteWorksheetProp = function(ws, index)
        {
            var oThis = this;
            //Name
            this.memory.WriteByte(c_oSerWorksheetPropTypes.Name);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.memory.WriteString2(ws.sName);
            //SheetId
            this.memory.WriteByte(c_oSerWorksheetPropTypes.SheetId);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(index + 1);
            //Hidden
            if(null != ws.bHidden)
            {
                this.memory.WriteByte(c_oSerWorksheetPropTypes.State);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                if(true == ws.bHidden)
                    this.memory.WriteByte(EVisibleType.visibleHidden);
                else
                    this.memory.WriteByte(EVisibleType.visibleVisible);
            }
            //activeRange(serialize activeRange)
            if(oThis.isCopyPaste)
            {
                var activeRange = oThis.isCopyPaste;

                var newRange = null;
                if(ws.bExcludeHiddenRows)
                {
                    for(var i = activeRange.r1; i < activeRange.r2; i++)
                    {
                        if(ws.getRowHidden(i))
                        {
                            if(!newRange)
                            {
								newRange = activeRange.clone();
                            }
							newRange.r2--;
                        }
                    }

                    if(newRange)
                    {
						activeRange = newRange;
                    }
                }

                this.memory.WriteByte(c_oSerWorksheetPropTypes.Ref);
                this.memory.WriteByte(c_oSerPropLenType.Variable);
                this.memory.WriteString2(activeRange.getName());
            }
        };
        this.WriteWorksheetCols = function(ws)
        {
            var oThis = this;
            var aCols = ws.aCols;
            var oPrevCol = null;
            var nPrevIndexStart = null;
            var nPrevIndex = null;
            var aIndexes = [];
            for(var i in aCols)
                aIndexes.push(i - 0);
            aIndexes.sort(AscCommon.fSortAscending);
            var fInitCol = function(col, nMin, nMax){
                var oRes = {BestFit: col.BestFit, hd: col.getHidden(), Max: nMax, Min: nMin, xfsid: null, width: col.width, CustomWidth: col.CustomWidth};
                if(null == oRes.width)
                {
                    if(null != ws.oSheetFormatPr.dDefaultColWidth)
                        oRes.width = ws.oSheetFormatPr.dDefaultColWidth;
                    else
                        oRes.width = AscCommonExcel.oDefaultMetrics.ColWidthChars;
                }
                if(null != col.xfs)
					oRes.xfsid = oThis.stylesForWrite.add(col.xfs);
                return oRes;
            };
            var oAllCol = null;
            if(null != ws.oAllCol)
            {
                oAllCol = fInitCol(ws.oAllCol, 0, gc_nMaxCol0);
            }
            for(var i = 0 , length = aIndexes.length; i < length; ++i)
            {
                var nIndex = aIndexes[i];
                var col = aCols[nIndex];
                if(null != col)
                {
                    if(false == col.isEmpty())
                    {
                        if(null != oAllCol && null == nPrevIndex && nIndex > 0)
                        {
                            oAllCol.Min = 1;
                            oAllCol.Max = nIndex;
                            this.bs.WriteItem(c_oSerWorksheetsTypes.Col, function(){oThis.WriteWorksheetCol(oAllCol);});
                        }
                        if(null != nPrevIndex && (nPrevIndex + 1 != nIndex || false == oPrevCol.isEqual(col)))
                        {
                            var oColToWrite = fInitCol(oPrevCol, nPrevIndexStart + 1, nPrevIndex + 1);
                            this.bs.WriteItem(c_oSerWorksheetsTypes.Col, function(){oThis.WriteWorksheetCol(oColToWrite);});
                            nPrevIndexStart = null;
                            if(null != oAllCol && nPrevIndex + 1 != nIndex)
                            {
                                oAllCol.Min = nPrevIndex + 2;
                                oAllCol.Max = nIndex;
                                this.bs.WriteItem(c_oSerWorksheetsTypes.Col, function(){oThis.WriteWorksheetCol(oAllCol);});
                            }
                        }
                        oPrevCol = col;
                        nPrevIndex = nIndex;
                        if(null == nPrevIndexStart)
                            nPrevIndexStart = nPrevIndex;
                    }
                }
            }
            if(null != nPrevIndexStart && null != nPrevIndex && null != oPrevCol)
            {
                var oColToWrite = fInitCol(oPrevCol, nPrevIndexStart + 1, nPrevIndex + 1);
                this.bs.WriteItem(c_oSerWorksheetsTypes.Col, function(){oThis.WriteWorksheetCol(oColToWrite);});
            }
            if(null != oAllCol)
            {
                if(null == nPrevIndex)
                {
                    oAllCol.Min = 1;
                    oAllCol.Max = gc_nMaxCol0 + 1;
                    this.bs.WriteItem(c_oSerWorksheetsTypes.Col, function(){oThis.WriteWorksheetCol(oAllCol);});
                }
                else if(gc_nMaxCol0 != nPrevIndex)
                {
                    oAllCol.Min = nPrevIndex + 2;
                    oAllCol.Max = gc_nMaxCol0 + 1;
                    this.bs.WriteItem(c_oSerWorksheetsTypes.Col, function(){oThis.WriteWorksheetCol(oAllCol);});
                }
            }
        };
        this.WriteWorksheetCol = function(oCol)
        {
            if(null != oCol.BestFit)
            {
                this.memory.WriteByte(c_oSerWorksheetColTypes.BestFit);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(oCol.BestFit);
            }
            if(oCol.hd)
            {
                this.memory.WriteByte(c_oSerWorksheetColTypes.Hidden);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(oCol.hd);
            }
            if(null != oCol.Max)
            {
                this.memory.WriteByte(c_oSerWorksheetColTypes.Max);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(oCol.Max);
            }
            if(null != oCol.Min)
            {
                this.memory.WriteByte(c_oSerWorksheetColTypes.Min);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(oCol.Min);
            }
            if(null != oCol.xfsid)
            {
                this.memory.WriteByte(c_oSerWorksheetColTypes.Style);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(oCol.xfsid);
            }
            if(null != oCol.width)
            {
                this.memory.WriteByte(c_oSerWorksheetColTypes.Width);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(oCol.width);
            }
            if(null != oCol.CustomWidth)
            {
                this.memory.WriteByte(c_oSerWorksheetColTypes.CustomWidth);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(oCol.CustomWidth);
            }
        };
        this.WriteSheetViews = function (ws) {
            var oThis = this;
            for (var i = 0, length = ws.sheetViews.length; i < length; ++i) {
				this.bs.WriteItem(c_oSerWorksheetsTypes.SheetView, function(){oThis.WriteSheetView(ws, ws.sheetViews[i]);});
            }
        };
		this.WriteSheetView = function (ws, oSheetView) {
            var oThis = this;
            if (null !== oSheetView.showGridLines)
                this.bs.WriteItem(c_oSer_SheetView.ShowGridLines, function(){oThis.memory.WriteBool(oSheetView.showGridLines);});
            if (null !== oSheetView.showRowColHeaders)
                this.bs.WriteItem(c_oSer_SheetView.ShowRowColHeaders, function(){oThis.memory.WriteBool(oSheetView.showRowColHeaders);});
			if (null !== oSheetView.zoomScale)
				this.bs.WriteItem(c_oSer_SheetView.ZoomScale, function(){oThis.memory.WriteLong(oSheetView.zoomScale);});
            if (null !== oSheetView.pane && oSheetView.pane.isInit())
                this.bs.WriteItem(c_oSer_SheetView.Pane, function(){oThis.WriteSheetViewPane(oSheetView.pane);});
			if (null !== ws.selectionRange)
				this.bs.WriteItem(c_oSer_SheetView.Selection, function(){oThis.WriteSheetViewSelection(ws.selectionRange);});
        };
        this.WriteSheetViewPane = function (oPane) {
            var oThis = this;
			//this.bs.WriteItem(c_oSer_Pane.ActivePane, function(){oThis.memory.WriteByte();});
            // Всегда пишем Frozen
            this.bs.WriteItem(c_oSer_Pane.State, function(){oThis.memory.WriteString3(AscCommonExcel.c_oAscPaneState.Frozen);});
            this.bs.WriteItem(c_oSer_Pane.TopLeftCell, function(){oThis.memory.WriteString3(oPane.topLeftFrozenCell.getID());});

            var col = oPane.topLeftFrozenCell.getCol0();
            var row = oPane.topLeftFrozenCell.getRow0();
            if (0 < col)
                this.bs.WriteItem(c_oSer_Pane.XSplit, function(){oThis.memory.WriteDouble2(col);});
            if (0 < row)
                this.bs.WriteItem(c_oSer_Pane.YSplit, function(){oThis.memory.WriteDouble2(row);});
        };
		this.WriteSheetViewSelection = function (selectionRange) {
			var oThis = this;
			if (null != selectionRange.activeCell) {
				this.bs.WriteItem(c_oSer_Selection.ActiveCell, function(){oThis.memory.WriteString3(selectionRange.activeCell.getName());});
			}
			if (null != selectionRange.activeCellId) {
				this.bs.WriteItem(c_oSer_Selection.ActiveCellId, function(){oThis.memory.WriteLong(selectionRange.activeCellId);});
			}
			//this.bs.WriteItem(c_oSer_Selection.Pane, function(){oThis.memory.WriteByte();});
			if (null != selectionRange.ranges) {
				var sqref = getSqRefString(selectionRange.ranges);
				this.bs.WriteItem(c_oSer_Selection.Sqref, function(){oThis.memory.WriteString3(sqref);});
			}
		};
        this.WriteSheetPr = function (sheetPr) {
            var oThis = this;
            if (null !== sheetPr.CodeName)
                this.bs.WriteItem(c_oSer_SheetPr.CodeName, function(){oThis.memory.WriteString3(sheetPr.CodeName);});
            if (null !== sheetPr.EnableFormatConditionsCalculation)
                this.bs.WriteItem(c_oSer_SheetPr.EnableFormatConditionsCalculation, function(){oThis.memory.WriteBool(sheetPr.EnableFormatConditionsCalculation);});
            if (null !== sheetPr.FilterMode)
                this.bs.WriteItem(c_oSer_SheetPr.FilterMode, function(){oThis.memory.WriteBool(sheetPr.FilterMode);});
            if (null !== sheetPr.Published)
                this.bs.WriteItem(c_oSer_SheetPr.Published, function(){oThis.memory.WriteBool(sheetPr.Published);});
            if (null !== sheetPr.SyncHorizontal)
                this.bs.WriteItem(c_oSer_SheetPr.SyncHorizontal, function(){oThis.memory.WriteBool(sheetPr.SyncHorizontal);});
            if (null !== sheetPr.SyncRef)
                this.bs.WriteItem(c_oSer_SheetPr.SyncRef, function(){oThis.memory.WriteString3(sheetPr.SyncRef);});
            if (null !== sheetPr.SyncVertical)
                this.bs.WriteItem(c_oSer_SheetPr.SyncVertical, function(){oThis.memory.WriteBool(sheetPr.SyncVertical);});
            if (null !== sheetPr.TransitionEntry)
                this.bs.WriteItem(c_oSer_SheetPr.TransitionEntry, function(){oThis.memory.WriteBool(sheetPr.TransitionEntry);});
            if (null !== sheetPr.TransitionEvaluation)
                this.bs.WriteItem(c_oSer_SheetPr.TransitionEvaluation, function(){oThis.memory.WriteBool(sheetPr.TransitionEvaluation);});
            if (null !== sheetPr.TabColor)
                this.bs.WriteItem(c_oSer_SheetPr.TabColor, function(){oThis.bs.WriteColorSpreadsheet(sheetPr.TabColor);});
        };
        this.WriteSheetFormatPr = function(ws)
        {
            if (null !== ws.oSheetFormatPr.nBaseColWidth) {
                this.memory.WriteByte(c_oSerSheetFormatPrTypes.BaseColWidth);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(ws.oSheetFormatPr.nBaseColWidth);
            }
            if(null !== ws.oSheetFormatPr.dDefaultColWidth) {
                this.memory.WriteByte(c_oSerSheetFormatPrTypes.DefaultColWidth);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(ws.oSheetFormatPr.dDefaultColWidth);
            }
            if(null !== ws.oSheetFormatPr.oAllRow) {
                var oAllRow = ws.oSheetFormatPr.oAllRow;
                if(oAllRow.h)
                {
                    this.memory.WriteByte(c_oSerSheetFormatPrTypes.DefaultRowHeight);
                    this.memory.WriteByte(c_oSerPropLenType.Double);
                    this.memory.WriteDouble2(oAllRow.h);
                }
                if(oAllRow.getCustomHeight())
                {
                    this.memory.WriteByte(c_oSerSheetFormatPrTypes.CustomHeight);
                    this.memory.WriteByte(c_oSerPropLenType.Byte);
                    this.memory.WriteBool(true);
                }
                if(oAllRow.getHidden())
                {
                    this.memory.WriteByte(c_oSerSheetFormatPrTypes.ZeroHeight);
                    this.memory.WriteByte(c_oSerPropLenType.Byte);
                    this.memory.WriteBool(true);
                }
            }
        };
        this.WritePageMargins = function(oMargins)
        {
            //Left
            var dLeft = oMargins.asc_getLeft();
            if(null != dLeft)
            {
                this.memory.WriteByte(c_oSer_PageMargins.Left);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(dLeft);
            }
            //Top
            var dTop = oMargins.asc_getTop();
            if(null != dTop)
            {
                this.memory.WriteByte(c_oSer_PageMargins.Top);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(dTop);
            }
            //Right
            var dRight = oMargins.asc_getRight();
            if(null != dRight)
            {
                this.memory.WriteByte(c_oSer_PageMargins.Right);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(dRight);
            }
            //Bottom
            var dBottom = oMargins.asc_getBottom();
            if(null != dBottom)
            {
                this.memory.WriteByte(c_oSer_PageMargins.Bottom);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(dBottom);
            }

            this.memory.WriteByte(c_oSer_PageMargins.Header);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble2(12.7);//0.5inch

            this.memory.WriteByte(c_oSer_PageMargins.Footer);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble2(12.7);//0.5inch
        };
        this.WritePageSetup = function(oPageSetup)
        {
            //Orientation
            var byteOrientation = oPageSetup.asc_getOrientation();
            if(null != byteOrientation)
            {
                var byteFormatOrientation = null;
                switch(byteOrientation)
                {
                    case c_oAscPageOrientation.PagePortrait: byteFormatOrientation = EPageOrientation.pageorientPortrait;break;
                    case c_oAscPageOrientation.PageLandscape: byteFormatOrientation = EPageOrientation.pageorientLandscape;break;
                }
                if(null != byteFormatOrientation)
                {
                    this.memory.WriteByte(c_oSer_PageSetup.Orientation);
                    this.memory.WriteByte(c_oSerPropLenType.Byte);
                    this.memory.WriteByte(byteFormatOrientation);
                }
            }
            //PageSize
            var dWidth = oPageSetup.asc_getWidth();
            var dHeight = oPageSetup.asc_getHeight();
            if(null != dWidth && null != dHeight)
            {
                var item = DocumentPageSize.getSizeByWH(dWidth, dHeight);
                this.memory.WriteByte(c_oSer_PageSetup.PaperSize);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteByte(item.id);
            }
        };
        this.WritePrintOptions = function(oPrintOptions)
        {
            //GridLines
            var bGridLines = oPrintOptions.asc_getGridLines();
            if(null != bGridLines)
            {
                this.memory.WriteByte(c_oSer_PrintOptions.GridLines);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(bGridLines);
            }
            //Headings
            var bHeadings = oPrintOptions.asc_getHeadings();
            if(null != bHeadings)
            {
                this.memory.WriteByte(c_oSer_PrintOptions.Headings);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(bHeadings);
            }
        };
        this.WriteHyperlinks = function(ws)
        {
            var oThis = this;
            var oHyperlinks = ws.hyperlinkManager.getAll();
            //todo sort
            for(var i in oHyperlinks)
            {
                var elem = oHyperlinks[i];
                //write only active hyperlink, if copy/paste
                if(!this.isCopyPaste || (this.isCopyPaste && elem && elem.bbox && this.isCopyPaste.containsRange(elem.bbox)))
                    this.bs.WriteItem(c_oSerWorksheetsTypes.Hyperlink, function(){oThis.WriteHyperlink(elem.data);});
            }
        };
        this.WriteHyperlink = function (oHyperlink) {
            if (null != oHyperlink.Ref) {
                this.memory.WriteByte(c_oSerHyperlinkTypes.Ref);
                this.memory.WriteString2(oHyperlink.Ref.getName());
            }
            if (null != oHyperlink.Hyperlink) {
                this.memory.WriteByte(c_oSerHyperlinkTypes.Hyperlink);
                this.memory.WriteString2(oHyperlink.Hyperlink);
            }
            if (null !== oHyperlink.getLocation()) {
                this.memory.WriteByte(c_oSerHyperlinkTypes.Location);
                this.memory.WriteString2(oHyperlink.getLocation());
            }
            if (null != oHyperlink.Tooltip) {
                this.memory.WriteByte(c_oSerHyperlinkTypes.Tooltip);
                this.memory.WriteString2(oHyperlink.Tooltip);
            }
        };
        this.WriteMergeCells = function(ws)
        {
            var oMerged = ws.mergeManager.getAll();
			var aMergedUsed = {};//защита чтобы не писать один и тотже диапазон несколько раз
            for(var i in oMerged)
            {
                var elem = oMerged[i];
                var bbox = elem.bbox;
                if(bbox.r1 != bbox.r2 || bbox.c1 != bbox.c2)
                {
                    //write only active merge, if copy/paste
                    if(!this.isCopyPaste || (this.isCopyPaste && this.isCopyPaste.containsRange(bbox)))
                    {
						var sCurMerged = bbox.getName();
						if(null == aMergedUsed[sCurMerged]){
							aMergedUsed[sCurMerged] = 1;
							this.memory.WriteByte(c_oSerWorksheetsTypes.MergeCell);
							this.memory.WriteString2(sCurMerged);
						}
                    }
                }
            }
        };
        this.WriteDrawings = function(aDrawings)
        {
            var oThis = this;
            var oPPTXWriter = pptx_content_writer.BinaryFileWriter;
            oPPTXWriter.ClearIdMap();
            for(var i = 0, length = aDrawings.length; i < length; ++i)
            {
                //write only active drawing, if copy/paste
                var oDrawing = aDrawings[i];
                if(!this.isCopyPaste)
                    this.bs.WriteItem(c_oSerWorksheetsTypes.Drawing, function(){oThis.WriteDrawing(oDrawing);});
                else if(this.isCopyPaste && oDrawing.graphicObject.selected)//for copy/paste
                {
                    if(oDrawing.isGroup() && oDrawing.graphicObject.selectedObjects && oDrawing.graphicObject.selectedObjects.length)
                    {
                        var oDrawingSelected = oDrawing.graphicObject.selectedObjects;
                        var curDrawing, graphicObject;
                        for(var selDr = 0; selDr < oDrawingSelected.length; selDr++)
                        {
                            curDrawing = oDrawingSelected[selDr];

							//меняем graphicObject на время записи
							graphicObject = oDrawing.graphicObject;
							oDrawing.graphicObject = curDrawing;

                            this.bs.WriteItem(c_oSerWorksheetsTypes.Drawing, function(){oThis.WriteDrawing(oDrawing, curDrawing);});
							
							//возвращаем graphicObject обратно
							oDrawing.graphicObject = graphicObject;
                        }
                    }
                    else
                    {
                        var oCurDrawingToWrite;
                        if(!oDrawing.graphicObject.fromSerialize)
                        {
                            this.bs.WriteItem(c_oSerWorksheetsTypes.Drawing, function(){oThis.WriteDrawing(oDrawing);});
                        }
                        else
                        {
                            var oCurDrawingToWrite = AscFormat.ExecuteNoHistory(function()
                            {
                                var oRet = oDrawing.graphicObject.copy();
                                var oMetrics = oDrawing.getGraphicObjectMetrics();
                                AscFormat.SetXfrmFromMetrics(oRet, oMetrics);
                                return oRet;
                            }, this, []);
                            var oOldGrObject = oDrawing.graphicObject;
                            oDrawing.graphicObject = oCurDrawingToWrite;
                            this.bs.WriteItem(c_oSerWorksheetsTypes.Drawing, function(){oThis.WriteDrawing(oDrawing);});
                            oDrawing.graphicObject = oOldGrObject;
                        }
                    }
                }
            }
            oPPTXWriter.ClearIdMap();
        };
        this.WriteDrawing = function(oDrawing, curDrawing)
        {
            var oThis = this;
            if(null != oDrawing.Type)
                this.bs.WriteItem(c_oSer_DrawingType.Type, function(){oThis.memory.WriteByte(ECellAnchorType.cellanchorOneCell);});

            switch(oDrawing.Type)
            {
                case c_oAscCellAnchorType.cellanchorTwoCell:
                {
                    this.bs.WriteItem(c_oSer_DrawingType.From, function(){oThis.WriteFromTo(oDrawing.from);});
                    this.bs.WriteItem(c_oSer_DrawingType.To, function(){oThis.WriteFromTo(oDrawing.to);});
                    break;
                }
                case c_oAscCellAnchorType.cellanchorOneCell:
                {
                    this.bs.WriteItem(c_oSer_DrawingType.From, function(){oThis.WriteFromTo(oDrawing.from);});
                    this.bs.WriteItem(c_oSer_DrawingType.Ext, function(){oThis.WriteExt(oDrawing.ext);});
                    break;
                }
                case c_oAscCellAnchorType.cellanchorAbsolute:
                {
                    this.bs.WriteItem(c_oSer_DrawingType.Pos, function(){oThis.WritePos(oDrawing.Pos);});
                    this.bs.WriteItem(c_oSer_DrawingType.Ext, function(){oThis.WriteExt(oDrawing.ext);});
                    break;
                }
            }
            if(curDrawing)
                this.bs.WriteItem(c_oSer_DrawingType.pptxDrawing, function(){pptx_content_writer.WriteDrawing(oThis.memory, curDrawing, null, null, null);});
            else
                this.bs.WriteItem(c_oSer_DrawingType.pptxDrawing, function(){pptx_content_writer.WriteDrawing(oThis.memory, oDrawing.graphicObject, null, null, null);});
        };
        this.WriteFromTo = function(oFromTo)
        {
            if(null != oFromTo.col)
            {
                this.memory.WriteByte(c_oSer_DrawingFromToType.Col);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(oFromTo.col);
            }
            if(null != oFromTo.colOff)
            {
                this.memory.WriteByte(c_oSer_DrawingFromToType.ColOff);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(oFromTo.colOff);
            }
            if(null != oFromTo.row)
            {
                this.memory.WriteByte(c_oSer_DrawingFromToType.Row);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(oFromTo.row);
            }
            if(null != oFromTo.rowOff)
            {
                this.memory.WriteByte(c_oSer_DrawingFromToType.RowOff);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(oFromTo.rowOff);
            }
        };
        this.WritePos = function(oPos)
        {
            if(null != oPos.X)
            {
                this.memory.WriteByte(c_oSer_DrawingPosType.X);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(oPos.X);
            }
            if(null != oPos.Y)
            {
                this.memory.WriteByte(c_oSer_DrawingPosType.Y);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(oPos.Y);
            }
        };
        this.WriteExt = function(oExt)
        {
            if(null != oExt.cx)
            {
                this.memory.WriteByte(c_oSer_DrawingExtType.Cx);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(oExt.cx);
            }
            if(null != oExt.cy)
            {
                this.memory.WriteByte(c_oSer_DrawingExtType.Cy);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(oExt.cy);
            }
        };
        this.WriteSheetData = function(ws)
        {
            var oThis = this;
            var range;
            if(oThis.isCopyPaste ){
				range = ws.getRange3(oThis.isCopyPaste.r1, oThis.isCopyPaste.c1, oThis.isCopyPaste.r2, oThis.isCopyPaste.c2);
			} else {
				range = ws.getRange3(0, 0, gc_nMaxRow0, gc_nMaxCol0);
			}
			var bIsTablePartContainActiveRange;
			if (oThis.isCopyPaste) {
				bIsTablePartContainActiveRange = ws.autoFilters.isTablePartContainActiveRange(ws.selectionRange.getLast());
			}

			var nStartRow = -1;
			var nStartCells = -1;
            var curRow = -1;
            var allRow = ws.getAllRowNoEmpty();
			var tempRow = new AscCommonExcel.Row(ws);
			if (allRow) {
				tempRow.copyFrom(allRow);
			}
			range._foreachRowNoEmpty(function(row, excludedCount) {
				if (-1 != nStartRow) {
					oThis.bs.WriteItemWithLengthEnd(nStartCells);
					oThis.bs.WriteItemEnd(nStartRow);
				}
				nStartRow = oThis.bs.WriteItemStart(c_oSerWorksheetsTypes.Row);
				nStartCells = oThis.WriteRow(row, -excludedCount);
				curRow = row.getIndex();
			}, function(cell, nRow0, nCol0, nRowStart0, nColStart0, excludedCount) {
				if (curRow != nRow0) {
					if (-1 != nStartRow) {
						oThis.bs.WriteItemWithLengthEnd(nStartCells);
						oThis.bs.WriteItemEnd(nStartRow);
					}
					tempRow.setIndex(nRow0);
					nStartRow = oThis.bs.WriteItemStart(c_oSerWorksheetsTypes.Row);
					nStartCells = oThis.WriteRow(tempRow, -excludedCount);
					curRow = nRow0;
				}
				//готовим ячейку к записи
				var nXfsId;
				var cellXfs = cell.xfs;
				/*if (oThis.isCopyPaste && bIsTablePartContainActiveRange) {
					var compiledXfs = cell.getCompiledStyle();
					nXfsId = oThis.stylesForWrite.add(compiledXfs);
					cellXfs = compiledXfs;
				} else {*/
					nXfsId = oThis.stylesForWrite.add(cell.xfs);
				//}

				//сохраняем как и Excel даже пустой стиль(нужно чтобы убрать стиль строки/колонки)
				if (null != cellXfs || false == cell.isNullText()) {
					oThis.bs.WriteItem(c_oSerRowTypes.Cell, function () {
						oThis.WriteCell(cell, nXfsId, nRow0 - excludedCount);
					});
				}
			}, (ws.bExcludeHiddenRows && oThis.isCopyPaste));

			if (-1 != nStartRow) {
				this.bs.WriteItemWithLengthEnd(nStartCells);
				this.bs.WriteItemEnd(nStartRow);
			}
		};
      
        this.WriteRow = function(oRow, changeIndex)
        {
            var oThis = this;
            if(null != oRow.index)
            {
                this.memory.WriteByte(c_oSerRowTypes.Row);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(oRow.index + 1 + changeIndex);
            }
            if(null != oRow.xfs)
            {
                var nXfsId = this.stylesForWrite.add(oRow.xfs);
                this.memory.WriteByte(c_oSerRowTypes.Style);
                this.memory.WriteByte(c_oSerPropLenType.Long);
                this.memory.WriteLong(nXfsId);
            }
            if(null != oRow.h)
            {
                this.memory.WriteByte(c_oSerRowTypes.Height);
                this.memory.WriteByte(c_oSerPropLenType.Double);
                this.memory.WriteDouble2(oRow.h);
            }
            if(oRow.getCustomHeight())
            {
                this.memory.WriteByte(c_oSerRowTypes.CustomHeight);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(true);
            }
            if(oRow.getHidden())
            {
                this.memory.WriteByte(c_oSerRowTypes.Hidden);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(true);
            }

            this.memory.WriteByte(c_oSerRowTypes.Cells);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            return this.bs.WriteItemWithLengthStart();
        };
        this.WriteCell = function(cell, nXfsId, nRowIndex)
        {
            var oThis = this;
            if(cell.nCol >= 0)
            {
				this.bs.WriteItem(c_oSerCellTypes.RefRowCol, function(){oThis.memory.WriteLong(nRowIndex);oThis.memory.WriteLong(cell.nCol);});
				
				if(null != nXfsId)
				{
					this.bs.WriteItem(c_oSerCellTypes.Style, function(){oThis.memory.WriteLong(nXfsId);});
				}
				if (cell.isFormula()) {
					this.bs.WriteItem(c_oSerCellTypes.Formula, function() {oThis.WriteFormula(cell);});
				}
				if(!cell.isNullTextString())
				{
                    if (null != cell.formulaParsed && cell.isEmptyTextString()) {
                        this.bs.WriteItem(c_oSerCellTypes.Type, function(){oThis.memory.WriteByte(ECellTypeType.celltypeStr);});
                        this.bs.WriteItem(c_oSerCellTypes.ValueText, function(){oThis.memory.WriteString3("");});
                    } else {
                        var nCellType = cell.getType();
                        if(null != nCellType)
                        {
                            var nType = ECellTypeType.celltypeNumber;
                            switch(nCellType)
                            {
                                case CellValueType.Bool: nType = ECellTypeType.celltypeBool; break;
                                case CellValueType.Error: nType = ECellTypeType.celltypeError; break;
                                case CellValueType.Number: nType = ECellTypeType.celltypeNumber; break;
                                case CellValueType.String: nType = ECellTypeType.celltypeSharedString; break;
                            }
                            if(ECellTypeType.celltypeNumber != nType)
                                this.bs.WriteItem(c_oSerCellTypes.Type, function(){oThis.memory.WriteByte(nType);});
                        }
                        var dValue = 0;
                        if(CellValueType.Error == nCellType || CellValueType.String == nCellType)
                        {
                            var textIndex = cell.getTextIndex();
                            if (null !== textIndex) {
                                dValue = this.oSharedStrings.strings[textIndex];
                                if (undefined === dValue) {
                                    dValue = this.oSharedStrings.index++;
                                    this.oSharedStrings.strings[textIndex] = dValue;
                                }
                            }
                        }
                        else
                        {
                            if(null != cell.number)
                                dValue = cell.number;
                        }
                        this.bs.WriteItem(c_oSerCellTypes.Value, function(){oThis.memory.WriteDouble2(dValue);});
                    }
				}
			}
        };
        this.WriteFormula = function(cell)
        {
			var parsed = cell.getFormulaParsed();
			var formula;
			var si;
			var ref;
			var type;
			var shared = parsed.getShared();
            if (shared) {
                var sharedToWrite = this.sharedFormulas[parsed.getIndexNumber()];
                if (!sharedToWrite) {
                    sharedToWrite = {saveShared: !shared.ref.isOneCell() && parsed.canSaveShared(), si: {}};
                    this.sharedFormulas[parsed.getIndexNumber()] = sharedToWrite;
                }
                if (sharedToWrite.saveShared && shared.ref.contains(cell.nCol, cell.nRow)) {
                    type = ECellFormulaType.cellformulatypeShared;
                    var rowIndex = Math.floor((cell.nRow - shared.ref.r1) / g_cSharedWriteStreak);
                    var row = sharedToWrite.si[rowIndex];
                    if (!row) {
                        row = {};
                        sharedToWrite.si[rowIndex] = row;
                    }
                    var colIndex = Math.floor((cell.nCol - shared.ref.c1) / g_cSharedWriteStreak);
                    si = row[colIndex];
                    if (undefined === si) {
                        row[colIndex] = si = this.sharedFormulasIndex++;
                        if (!(cell.nRow === shared.base.nRow && cell.nCol === shared.base.nCol)) {
                            cell.processFormula(function(parsed) {
                                formula = parsed.getFormula();
                            });
                        } else {
                            formula = parsed.getFormula();
                        }
                        var r1 = shared.ref.r1 + rowIndex * g_cSharedWriteStreak;
                        var c1 = shared.ref.c1 + colIndex * g_cSharedWriteStreak;
                        ref = new Asc.Range(c1, r1,
                            Math.min(c1 + g_cSharedWriteStreak - 1, shared.ref.c2),
                            Math.min(r1 + g_cSharedWriteStreak - 1, shared.ref.r2));
                    }
                } else {
                    cell.processFormula(function(parsed) {
                        formula = parsed.getFormula();
                    });
                }
            } else {
                formula = parsed.getFormula();
            }

            // if(null != oFormula.aca)
            // {
            // this.memory.WriteByte(c_oSerFormulaTypes.Aca);
            // this.memory.WriteByte(c_oSerPropLenType.Byte);
            // this.memory.WriteBool(oFormula.aca);
            // }
            // if(null != oFormula.bx)
            // {
            // this.memory.WriteByte(c_oSerFormulaTypes.Bx);
            // this.memory.WriteByte(c_oSerPropLenType.Byte);
            // this.memory.WriteBool(oFormula.bx);
            // }
            if(true === parsed.ca)
            {
                this.memory.WriteByte(c_oSerFormulaTypes.Ca);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(parsed.ca);
            }
            // if(null != oFormula.del1)
            // {
            // this.memory.WriteByte(c_oSerFormulaTypes.Del1);
            // this.memory.WriteByte(c_oSerPropLenType.Byte);
            // this.memory.WriteBool(oFormula.del1);
            // }
            // if(null != oFormula.del2)
            // {
            // this.memory.WriteByte(c_oSerFormulaTypes.Del2);
            // this.memory.WriteByte(c_oSerPropLenType.Byte);
            // this.memory.WriteBool(oFormula.del2);
            // }
            // if(null != oFormula.dt2d)
            // {
            // this.memory.WriteByte(c_oSerFormulaTypes.Dt2D);
            // this.memory.WriteByte(c_oSerPropLenType.Byte);
            // this.memory.WriteBool(oFormula.dt2d);
            // }
            // if(null != oFormula.dtr)
            // {
            // this.memory.WriteByte(c_oSerFormulaTypes.Dtr);
            // this.memory.WriteByte(c_oSerPropLenType.Byte);
            // this.memory.WriteBool(oFormula.dtr);
            // }
            // if(null != oFormula.r1)
            // {
            // this.memory.WriteByte(c_oSerFormulaTypes.R1);
            // this.memory.WriteByte(c_oSerPropLenType.Variable);
            // this.memory.WriteString2(oFormula.r1);
            // }
            // if(null != oFormula.r2)
            // {
            // this.memory.WriteByte(c_oSerFormulaTypes.R2);
            // this.memory.WriteByte(c_oSerPropLenType.Variable);
            // this.memory.WriteString2(oFormula.r2);
            // }
			if (undefined !== ref) {
				this.memory.WriteByte(c_oSerFormulaTypes.Ref);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.memory.WriteString2(ref.getName());
			}
			if (undefined !== si) {
				this.memory.WriteByte(c_oSerFormulaTypes.Si);
				this.memory.WriteByte(c_oSerPropLenType.Long);
				this.memory.WriteLong(si);
			}
			if (undefined !== type) {
				this.memory.WriteByte(c_oSerFormulaTypes.T);
				this.memory.WriteByte(c_oSerPropLenType.Byte);
				this.memory.WriteByte(type);
			}
			if (undefined !== formula) {
				this.memory.WriteByte(c_oSerFormulaTypes.Text);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.memory.WriteString2(formula);
			}
        };
        this.WriteComments = function(aComments, ws)
        {
            var oThis = this;
            var i, elem;
            for(i = 0; i < aComments.length; ++i)
            {
                elem = aComments[i];
                //write only active comments, if copy/paste
                if(this.isCopyPaste)
				{
					//ignore hidden rows if ws.bExcludeHiddenRows === true
					if(!this.isCopyPaste.contains(elem.nCol, elem.nRow) || (ws.bExcludeHiddenRows && ws.getRowHidden(elem.nRow)))
					{
						continue;
					}
				}
				if (elem.coords && elem.coords.isValid()) {
					this.bs.WriteItem(c_oSerWorksheetsTypes.Comment, function(){oThis.WriteComment(elem);});
				}
            }
        };
        this.WriteComment = function(comment)
        {
            var oThis = this;
            this.memory.WriteByte(c_oSer_Comments.Row);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(comment.coords.nRow);

            this.memory.WriteByte(c_oSer_Comments.Col);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(comment.coords.nCol);

            this.memory.WriteByte(c_oSer_Comments.CommentDatas);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.WriteCommentDatas(comment);});

            this.memory.WriteByte(c_oSer_Comments.Left);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(comment.coords.nLeft);

            this.memory.WriteByte(c_oSer_Comments.Top);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(comment.coords.nTop);

            this.memory.WriteByte(c_oSer_Comments.Right);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(comment.coords.nRight);

            this.memory.WriteByte(c_oSer_Comments.Bottom);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(comment.coords.nBottom);

            this.memory.WriteByte(c_oSer_Comments.LeftOffset);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(comment.coords.nLeftOffset);

            this.memory.WriteByte(c_oSer_Comments.TopOffset);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(comment.coords.nTopOffset);

            this.memory.WriteByte(c_oSer_Comments.RightOffset);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(comment.coords.nRightOffset);

            this.memory.WriteByte(c_oSer_Comments.BottomOffset);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(comment.coords.nBottomOffset);

            this.memory.WriteByte(c_oSer_Comments.LeftMM);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble2(comment.coords.dLeftMM);

            this.memory.WriteByte(c_oSer_Comments.TopMM);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble2(comment.coords.dTopMM);

            this.memory.WriteByte(c_oSer_Comments.WidthMM);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble2(comment.coords.dWidthMM);

            this.memory.WriteByte(c_oSer_Comments.HeightMM);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble2(comment.coords.dHeightMM);

            this.memory.WriteByte(c_oSer_Comments.MoveWithCells);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(comment.coords.bMoveWithCells);

            this.memory.WriteByte(c_oSer_Comments.SizeWithCells);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(comment.coords.bSizeWithCells);
        };
        this.WriteCommentDatas = function(data)
        {
            var oThis = this;
            this.bs.WriteItem( c_oSer_Comments.CommentData, function(){oThis.WriteCommentData(data);});
        };
        this.WriteCommentData = function(oCommentData)
        {
            var oThis = this;
            var sText = oCommentData.asc_getText();
            if(null != sText)
            {
                this.memory.WriteByte(c_oSer_CommentData.Text);
                this.memory.WriteString2(sText);
            }
            var sTime = oCommentData.asc_getTime();
            if(null != sTime && "" !== sTime)
            {
                var oDate = new Date(sTime - 0);

                this.memory.WriteByte(c_oSer_CommentData.Time);
                this.memory.WriteString2(this.DateToISO8601(oDate));
            }
            var sOOTime = oCommentData.asc_getOnlyOfficeTime();
            if(null != sOOTime && "" !== sOOTime)
            {
                var oDate = new Date(sOOTime - 0);

                this.memory.WriteByte(c_oSer_CommentData.OOTime);
                this.memory.WriteString2(this.DateToISO8601(oDate));
            }
            var sUserId = oCommentData.asc_getUserId();
            if(null != sUserId)
            {
                this.memory.WriteByte(c_oSer_CommentData.UserId);
                this.memory.WriteString2(sUserId);
            }
            var sUserName = oCommentData.asc_getUserName();
            if(null != sUserName)
            {
                this.memory.WriteByte(c_oSer_CommentData.UserName);
                this.memory.WriteString2(sUserName);
            }
            var sQuoteText = oCommentData.asc_getQuoteText();
            if(null != sQuoteText)
            {
                this.memory.WriteByte(c_oSer_CommentData.QuoteText);
                this.memory.WriteString2(sQuoteText);
            }
            var bSolved = oCommentData.asc_getSolved();
            if(null != bSolved)
                this.bs.WriteItem( c_oSer_CommentData.Solved, function(){oThis.memory.WriteBool(bSolved);});
            var bDocumentFlag = oCommentData.asc_getDocumentFlag();
            if(null != bDocumentFlag)
                this.bs.WriteItem( c_oSer_CommentData.Document, function(){oThis.memory.WriteBool(bDocumentFlag);});
            var aReplies = oCommentData.aReplies;
            if(null != aReplies && aReplies.length > 0)
                this.bs.WriteItem( c_oSer_CommentData.Replies, function(){oThis.WriteReplies(aReplies);});
        };
        this.DateToISO8601 = function(d)
        {
            function pad(n){return n < 10 ? '0' + n : n;}
            return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' +
                pad(d.getUTCDate()) + 'T' + pad(d.getUTCHours()) + ':' +
                pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds())+'Z';
        };
        this.WriteReplies = function(aReplies)
        {
            var oThis = this;
            for(var i = 0, length = aReplies.length; i < length; ++i)
                this.bs.WriteItem( c_oSer_CommentData.Reply, function(){oThis.WriteCommentData(aReplies[i]);});
        };
		this.WriteConditionalFormatting = function(oRule)
		{
			var oThis = this;
			if (null != oRule.pivot) {
				this.bs.WriteItem(c_oSer_ConditionalFormatting.Pivot, function() {oThis.memory.WriteBool(oRule.pivot);});
			}
			if (null != oRule.ranges) {
				var sqref = getSqRefString(oRule.ranges);
				this.bs.WriteItem(c_oSer_ConditionalFormatting.SqRef, function() {oThis.memory.WriteString3(sqref);});
			}
			this.bs.WriteItem(c_oSer_ConditionalFormatting.ConditionalFormattingRule, function() {oThis.WriteConditionalFormattingRule(oRule);});
		};
		this.WriteConditionalFormattingRule = function(rule) {
			var oThis = this;
			if (null != rule.aboveAverage) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingRule.AboveAverage, function() {oThis.memory.WriteBool(rule.aboveAverage);});
			}
			if (null != rule.bottom) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingRule.Bottom, function() {oThis.memory.WriteBool(rule.bottom);});
			}
			if (null != rule.dxf) {
				var DxfId = this.aDxfs.length;
				this.aDxfs.push(rule.dxf);
				this.bs.WriteItem(c_oSer_ConditionalFormattingRule.DxfId, function() {oThis.memory.WriteLong(DxfId);});
			}
			if (null != rule.equalAverage) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingRule.EqualAverage, function() {oThis.memory.WriteBool(rule.equalAverage);});
			}
			if (null != rule.operator) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingRule.Operator, function() {oThis.memory.WriteByte(rule.operator);});
			}
			if (null != rule.percent) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingRule.Percent, function() {oThis.memory.WriteBool(rule.percent);});
			}
			if (null != rule.priority) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingRule.Priority, function() {oThis.memory.WriteLong(rule.priority);});
			}
			if (null != rule.rank) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingRule.Rank, function() {oThis.memory.WriteLong(rule.rank);});
			}
			if (null != rule.stdDev) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingRule.StdDev, function() {oThis.memory.WriteLong(rule.stdDev);});
			}
			if (null != rule.stopIfTrue) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingRule.StopIfTrue, function() {oThis.memory.WriteBool(rule.stopIfTrue);});
			}
			if (null != rule.text) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingRule.Text, function() {oThis.memory.WriteString3(rule.text);});
			}
			if (null != rule.timePeriod) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingRule.TimePeriod, function() {oThis.memory.WriteString3(rule.timePeriod);});
			}
			if (null != rule.type) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingRule.Type, function() {oThis.memory.WriteByte(rule.type);});
			}
			for (var i = 0; i < rule.aRuleElements.length; ++i) {
				var elem = rule.aRuleElements[i];
				if (elem instanceof AscCommonExcel.CColorScale) {
					this.bs.WriteItem(c_oSer_ConditionalFormattingRule.ColorScale, function() {oThis.WriteColorScale(elem);});
				} else if (elem instanceof AscCommonExcel.CDataBar) {
					this.bs.WriteItem(c_oSer_ConditionalFormattingRule.DataBar, function() {oThis.WriteDataBar(elem);});
				} else if (elem instanceof AscCommonExcel.CFormulaCF) {
					this.bs.WriteItem(c_oSer_ConditionalFormattingRule.FormulaCF, function() {oThis.memory.WriteString3(elem.Text);});
				} else if (elem instanceof AscCommonExcel.CIconSet) {
					this.bs.WriteItem(c_oSer_ConditionalFormattingRule.IconSet, function() {oThis.WriteIconSet(elem);});
				}
			}
		};
		this.WriteColorScale = function(colorScale) {
			var oThis = this;
			var i, elem;
			for (i = 0; i < colorScale.aCFVOs.length; ++i) {
				elem = colorScale.aCFVOs[i];
				this.bs.WriteItem(c_oSer_ConditionalFormattingRuleColorScale.CFVO, function() {oThis.WriteCFVO(elem);});
			}
			for (i = 0; i < colorScale.aColors.length; ++i) {
				elem = colorScale.aColors[i];
				this.bs.WriteItem(c_oSer_ConditionalFormattingRuleColorScale.Color, function() {oThis.bs.WriteColorSpreadsheet(elem);});
			}
		};
		this.WriteDataBar = function(dataBar) {
			var oThis = this;
			var i, elem;
			if (null != dataBar.MaxLength) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingDataBar.MaxLength, function() {oThis.memory.WriteLong(dataBar.MaxLength);});
			}
			if (null != dataBar.MinLength) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingDataBar.MinLength, function() {oThis.memory.WriteLong(dataBar.MinLength);});
			}
			if (null != dataBar.ShowValue) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingDataBar.ShowValue, function() {oThis.memory.WriteBool(dataBar.ShowValue);});
			}
			if (null != dataBar.Color) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingDataBar.Color, function() {oThis.bs.WriteColorSpreadsheet(dataBar.Color);});
			}
			for (i = 0; i < dataBar.aCFVOs.length; ++i) {
				elem = dataBar.aCFVOs[i];
				this.bs.WriteItem(c_oSer_ConditionalFormattingRuleColorScale.CFVO, function() {oThis.WriteCFVO(elem);});
			}
		};
		this.WriteIconSet = function(iconSet) {
			var oThis = this;
			var i, elem;
			if (null != iconSet.IconSet) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingIconSet.IconSet, function() {oThis.memory.WriteByte(iconSet.IconSet);});
			}
			if (null != iconSet.Percent) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingIconSet.Percent, function() {oThis.memory.WriteBool(iconSet.Percent);});
			}
			if (null != iconSet.Reverse) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingIconSet.Reverse, function() {oThis.memory.WriteBool(iconSet.Reverse);});
			}
			if (null != iconSet.ShowValue) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingIconSet.ShowValue, function() {oThis.memory.WriteBool(iconSet.ShowValue);});
			}
			for (i = 0; i < iconSet.aCFVOs.length; ++i) {
				elem = iconSet.aCFVOs[i];
				this.bs.WriteItem(c_oSer_ConditionalFormattingRuleColorScale.CFVO, function() {oThis.WriteCFVO(elem);});
			}
		};
		this.WriteCFVO = function(cfvo) {
			var oThis = this;
			if (null != cfvo.Gte) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingValueObject.Gte, function() {oThis.memory.WriteBool(cfvo.Gte);});
			}
			if (null != cfvo.Type) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingValueObject.Type, function() {oThis.memory.WriteByte(cfvo.Type);});
			}
			if (null != cfvo.Val) {
				this.bs.WriteItem(c_oSer_ConditionalFormattingValueObject.Val, function() {oThis.memory.WriteString3(cfvo.Val);});
			}
		};
		this.WriteSparklineGroups = function(aSparklineGroups)
        {
            var oThis = this;
            for(var i = 0, length = aSparklineGroups.length; i < length; ++i)
                this.bs.WriteItem( c_oSer_Sparkline.SparklineGroup, function(){oThis.WriteSparklineGroup(aSparklineGroups[i]);});
        };
		this.WriteSparklineGroup = function(oSparklineGroup)
        {
			var oThis = this;
			if (null != oSparklineGroup.manualMax) {
                this.bs.WriteItem( c_oSer_Sparkline.ManualMax, function(){oThis.memory.WriteDouble2(oSparklineGroup.manualMax);});
			}
			if (null != oSparklineGroup.manualMin) {
                this.bs.WriteItem( c_oSer_Sparkline.ManualMin, function(){oThis.memory.WriteDouble2(oSparklineGroup.manualMin);});
			}
			if (null != oSparklineGroup.lineWeight) {
                this.bs.WriteItem( c_oSer_Sparkline.LineWeight, function(){oThis.memory.WriteDouble2(oSparklineGroup.lineWeight);});
			}
			if (null != oSparklineGroup.type) {
                this.bs.WriteItem( c_oSer_Sparkline.Type, function(){oThis.memory.WriteByte(oSparklineGroup.type);});
			}
			if (null != oSparklineGroup.dateAxis) {
                this.bs.WriteItem( c_oSer_Sparkline.DateAxis, function(){oThis.memory.WriteBool(oSparklineGroup.dateAxis);});
			}
			if (null != oSparklineGroup.displayEmptyCellsAs) {
                this.bs.WriteItem( c_oSer_Sparkline.DisplayEmptyCellsAs, function(){oThis.memory.WriteByte(oSparklineGroup.displayEmptyCellsAs);});
			}
			if (null != oSparklineGroup.markers) {
                this.bs.WriteItem( c_oSer_Sparkline.Markers, function(){oThis.memory.WriteBool(oSparklineGroup.markers);});
			}
			if (null != oSparklineGroup.high) {
                this.bs.WriteItem( c_oSer_Sparkline.High, function(){oThis.memory.WriteBool(oSparklineGroup.high);});
			}
			if (null != oSparklineGroup.low) {
                this.bs.WriteItem( c_oSer_Sparkline.Low, function(){oThis.memory.WriteBool(oSparklineGroup.low);});
			}
			if (null != oSparklineGroup.first) {
                this.bs.WriteItem( c_oSer_Sparkline.First, function(){oThis.memory.WriteBool(oSparklineGroup.first);});
			}
			if (null != oSparklineGroup.last) {
                this.bs.WriteItem( c_oSer_Sparkline.Last, function(){oThis.memory.WriteBool(oSparklineGroup.last);});
			}
			if (null != oSparklineGroup.negative) {
                this.bs.WriteItem( c_oSer_Sparkline.Negative, function(){oThis.memory.WriteBool(oSparklineGroup.negative);});
			}
			if (null != oSparklineGroup.displayXAxis) {
                this.bs.WriteItem( c_oSer_Sparkline.DisplayXAxis, function(){oThis.memory.WriteBool(oSparklineGroup.displayXAxis);});
			}
			if (null != oSparklineGroup.displayHidden) {
                this.bs.WriteItem( c_oSer_Sparkline.DisplayHidden, function(){oThis.memory.WriteBool(oSparklineGroup.displayHidden);});
			}
			if (null != oSparklineGroup.minAxisType) {
                this.bs.WriteItem( c_oSer_Sparkline.MinAxisType, function(){oThis.memory.WriteByte(oSparklineGroup.minAxisType);});
			}
			if (null != oSparklineGroup.maxAxisType) {
                this.bs.WriteItem( c_oSer_Sparkline.MaxAxisType, function(){oThis.memory.WriteByte(oSparklineGroup.maxAxisType);});
			}
			if (null != oSparklineGroup.rightToLeft) {
                this.bs.WriteItem( c_oSer_Sparkline.RightToLeft, function(){oThis.memory.WriteBool(oSparklineGroup.rightToLeft);});
			}
			if (null != oSparklineGroup.colorSeries) {
                this.bs.WriteItem(c_oSer_Sparkline.ColorSeries, function(){oThis.bs.WriteColorSpreadsheet(oSparklineGroup.colorSeries);});
			}
			if (null != oSparklineGroup.colorNegative) {
                this.bs.WriteItem(c_oSer_Sparkline.ColorNegative, function(){oThis.bs.WriteColorSpreadsheet(oSparklineGroup.colorNegative);});
			}
			if (null != oSparklineGroup.colorAxis) {
                this.bs.WriteItem(c_oSer_Sparkline.ColorAxis, function(){oThis.bs.WriteColorSpreadsheet(oSparklineGroup.colorAxis);});
			}
			if (null != oSparklineGroup.colorMarkers) {
                this.bs.WriteItem(c_oSer_Sparkline.ColorMarkers, function(){oThis.bs.WriteColorSpreadsheet(oSparklineGroup.colorMarkers);});
			}
			if (null != oSparklineGroup.colorFirst) {
                this.bs.WriteItem(c_oSer_Sparkline.ColorFirst, function(){oThis.bs.WriteColorSpreadsheet(oSparklineGroup.colorFirst);});
			}
			if (null != oSparklineGroup.colorLast) {
                this.bs.WriteItem(c_oSer_Sparkline.ColorLast, function(){oThis.bs.WriteColorSpreadsheet(oSparklineGroup.colorLast);});
			}
			if (null != oSparklineGroup.colorHigh) {
                this.bs.WriteItem(c_oSer_Sparkline.ColorHigh, function(){oThis.bs.WriteColorSpreadsheet(oSparklineGroup.colorHigh);});
			}
			if (null != oSparklineGroup.colorLow) {
                this.bs.WriteItem(c_oSer_Sparkline.ColorLow, function(){oThis.bs.WriteColorSpreadsheet(oSparklineGroup.colorLow);});
			}
			if (null != oSparklineGroup.f) {
                this.memory.WriteByte(c_oSer_Sparkline.Ref);
                this.memory.WriteString2(oSparklineGroup.f);
			}
			if (null != oSparklineGroup.arrSparklines) {
				this.bs.WriteItem(c_oSer_Sparkline.Sparklines, function(){oThis.WriteSparklines(oSparklineGroup);});
			}
		};
		this.WriteSparklines = function(oSparklineGroup)
        {
            var oThis = this;
            for(var i = 0, length = oSparklineGroup.arrSparklines.length; i < length; ++i)
                this.bs.WriteItem( c_oSer_Sparkline.Sparkline, function(){oThis.WriteSparkline(oSparklineGroup.arrSparklines[i]);});
        };
		this.WriteSparkline = function(oSparkline)
        {
			if (null != oSparkline.f) {
                this.memory.WriteByte(c_oSer_Sparkline.SparklineRef);
                this.memory.WriteString2(oSparkline.f);
			}
			if (null != oSparkline.sqref) {
				this.memory.WriteByte(c_oSer_Sparkline.SparklineSqRef);
                this.memory.WriteString2(oSparkline.sqref.getName());
			}
		}
		this.WritePivotTable = function(pivotTable)
		{
			var oThis = this;
			if (null != pivotTable.cacheId) {
				this.bs.WriteItem(c_oSer_PivotTypes.cacheId, function() {oThis.memory.WriteLong(pivotTable.cacheId);});
			}
			this.bs.WriteItem(c_oSer_PivotTypes.table, function() {pivotTable.toXml(oThis.memory);});
		}
        this.WriteHeaderFooter = function(headerFooter)
        {
            var oThis = this;
            if (null !== headerFooter.alignWithMargins) {
                this.bs.WriteItem(c_oSer_HeaderFooter.AlignWithMargins, function() {oThis.memory.WriteBool(headerFooter.alignWithMargins);});
            }
            if (null !== headerFooter.differentFirst) {
                this.bs.WriteItem(c_oSer_HeaderFooter.DifferentFirst, function() {oThis.memory.WriteBool(headerFooter.differentFirst);});
            }
            if (null !== headerFooter.differentOddEven) {
                this.bs.WriteItem(c_oSer_HeaderFooter.DifferentOddEven, function() {oThis.memory.WriteBool(headerFooter.differentOddEven);});
            }
            if (null !== headerFooter.scaleWithDoc) {
                this.bs.WriteItem(c_oSer_HeaderFooter.ScaleWithDoc, function() {oThis.memory.WriteBool(headerFooter.scaleWithDoc);});
            }
            if (null !== headerFooter.evenFooter) {
                this.memory.WriteByte(c_oSer_HeaderFooter.EvenFooter);
                this.memory.WriteString2(headerFooter.evenFooter);
            }
            if (null !== headerFooter.evenHeader) {
                this.memory.WriteByte(c_oSer_HeaderFooter.EvenHeader);
                this.memory.WriteString2(headerFooter.evenHeader);
            }
            if (null !== headerFooter.firstFooter) {
                this.memory.WriteByte(c_oSer_HeaderFooter.FirstFooter);
                this.memory.WriteString2(headerFooter.firstFooter);
            }
            if (null !== headerFooter.firstHeader) {
                this.memory.WriteByte(c_oSer_HeaderFooter.FirstHeader);
                this.memory.WriteString2(headerFooter.firstHeader);
            }
            if (null !== headerFooter.oddFooter) {
                this.memory.WriteByte(c_oSer_HeaderFooter.OddFooter);
                this.memory.WriteString2(headerFooter.oddFooter);
            }
            if (null !== headerFooter.oddHeader) {
                this.memory.WriteByte(c_oSer_HeaderFooter.OddHeader);
                this.memory.WriteString2(headerFooter.oddHeader);
            }
        }
        this.WriteRowColBreaks = function(breaks)
        {
            var oThis = this;
            if (null !== breaks.count) {
                this.bs.WriteItem(c_oSer_RowColBreaks.Count, function() {oThis.memory.WriteLong(breaks.count);});
            }
            if (null !== breaks.manualBreakCount) {
                this.bs.WriteItem(c_oSer_RowColBreaks.ManualBreakCount, function() {oThis.memory.WriteLong(breaks.manualBreakCount);});
            }
            for(var i = 0; i < breaks.breaks.length; ++i){
                this.bs.WriteItem(c_oSer_RowColBreaks.Break, function() {oThis.WriteRowColBreak(breaks.breaks[i]);});
            }
        };
        this.WriteRowColBreak = function(brk)
        {
            var oThis = this;
            if (null !== brk.id) {
                this.bs.WriteItem(c_oSer_RowColBreaks.Id, function() {oThis.memory.WriteLong(brk.id);});
            }
            if (null !== brk.man) {
                this.bs.WriteItem(c_oSer_RowColBreaks.Man, function() {oThis.memory.WriteBool(brk.man);});
            }
            if (null !== brk.max) {
                this.bs.WriteItem(c_oSer_RowColBreaks.Max, function() {oThis.memory.WriteLong(brk.max);});
            }
            if (null !== brk.min) {
                this.bs.WriteItem(c_oSer_RowColBreaks.Min, function() {oThis.memory.WriteLong(brk.min);});
            }
            if (null !== brk.pt) {
                this.bs.WriteItem(c_oSer_RowColBreaks.Pt, function() {oThis.memory.WriteBool(brk.pt);});
            }
        };
        this.WriteLegacyDrawingHF = function(legacyDrawingHF)
        {
            var oThis = this;
            if (null !== legacyDrawingHF.cfe) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Cfe, function() {oThis.memory.WriteLong(legacyDrawingHF.cfe);});
            }
            if (null !== legacyDrawingHF.cff) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Cff, function() {oThis.memory.WriteLong(legacyDrawingHF.cff);});
            }
            if (null !== legacyDrawingHF.cfo) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Cfo, function() {oThis.memory.WriteLong(legacyDrawingHF.cfo);});
            }
            if (null !== legacyDrawingHF.che) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Che, function() {oThis.memory.WriteLong(legacyDrawingHF.che);});
            }
            if (null !== legacyDrawingHF.chf) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Chf, function() {oThis.memory.WriteLong(legacyDrawingHF.chf);});
            }
            if (null !== legacyDrawingHF.cho) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Cho, function() {oThis.memory.WriteLong(legacyDrawingHF.cho);});
            }
            if (null !== legacyDrawingHF.lfe) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Lfe, function() {oThis.memory.WriteLong(legacyDrawingHF.lfe);});
            }
            if (null !== legacyDrawingHF.lff) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Lff, function() {oThis.memory.WriteLong(legacyDrawingHF.lff);});
            }
            if (null !== legacyDrawingHF.lfo) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Lfo, function() {oThis.memory.WriteLong(legacyDrawingHF.lfo);});
            }
            if (null !== legacyDrawingHF.lhe) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Lhe, function() {oThis.memory.WriteLong(legacyDrawingHF.lhe);});
            }
            if (null !== legacyDrawingHF.lhf) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Lhf, function() {oThis.memory.WriteLong(legacyDrawingHF.lhf);});
            }
            if (null !== legacyDrawingHF.lho) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Lho, function() {oThis.memory.WriteLong(legacyDrawingHF.lho);});
            }
            if (null !== legacyDrawingHF.rfe) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Rfe, function() {oThis.memory.WriteLong(legacyDrawingHF.rfe);});
            }
            if (null !== legacyDrawingHF.rff) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Rff, function() {oThis.memory.WriteLong(legacyDrawingHF.rff);});
            }
            if (null !== legacyDrawingHF.rfo) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Rfo, function() {oThis.memory.WriteLong(legacyDrawingHF.rfo);});
            }
            if (null !== legacyDrawingHF.rhe) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Rhe, function() {oThis.memory.WriteLong(legacyDrawingHF.rhe);});
            }
            if (null !== legacyDrawingHF.rhf) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Rhf, function() {oThis.memory.WriteLong(legacyDrawingHF.rhf);});
            }
            if (null !== legacyDrawingHF.rho) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Rho, function() {oThis.memory.WriteLong(legacyDrawingHF.rho);});
            }
            this.bs.WriteItem(c_oSer_LegacyDrawingHF.Drawings, function() {oThis.WriteLegacyDrawingHFDrawings(legacyDrawingHF.drawings);});

        };
        this.WriteLegacyDrawingHFDrawings = function(drawings) {
            var oThis = this;
            for (var i = 0; i < drawings.length; ++i) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.Drawing, function() {oThis.WriteLegacyDrawingHFDrawing(drawings[i]);});
            }
        };
        this.WriteLegacyDrawingHFDrawing = function(drawing) {
            var oThis = this;
            if (null !== drawing.id) {
                this.memory.WriteByte(c_oSer_LegacyDrawingHF.DrawingId);
                this.memory.WriteString2(drawing.id);
            }
            if (null !== drawing.graphicObject) {
                this.bs.WriteItem(c_oSer_LegacyDrawingHF.DrawingShape, function(){pptx_content_writer.WriteDrawing(oThis.memory, drawing.graphicObject, null, null, null);});
            }
        }
    }
    /** @constructor */
    function BinaryOtherTableWriter(memory, wb)
    {
        this.memory = memory;
        this.wb = wb;
        this.bs = new BinaryCommonWriter(this.memory);
        this.Write = function()
        {
            var oThis = this;
            this.bs.WriteItemWithLength(function(){oThis.WriteOtherContent();});
        };
        this.WriteOtherContent = function()
        {
            var oThis = this;
            this.bs.WriteItem(c_oSer_OtherType.Theme, function(){pptx_content_writer.WriteTheme(oThis.memory, oThis.wb.theme);});
        };
    }
    /** @constructor */
    function BinaryFileWriter(wb, isCopyPaste)
    {
        this.Memory = new AscCommon.CMemory();
        this.wb = wb;
        this.isCopyPaste = isCopyPaste;
        this.nLastFilePos = 0;
        this.nRealTableCount = 0;
        this.bs = new BinaryCommonWriter(this.Memory);
        this.Write = function(noBase64, onlySaveBase64)
        {
            var t = this;
            pptx_content_writer._Start();
			if (noBase64) {
				this.Memory.WriteXmlString(this.WriteFileHeader(0, Asc.c_nVersionNoBase64));
			}
			AscCommonExcel.executeInR1C1Mode(false, function () {
				t.WriteMainTable();
			});
            pptx_content_writer._End();
			if (noBase64) {
			    if (onlySaveBase64)
                    return this.Memory.GetBase64Memory();
			    else
			        return this.Memory.GetData();
			} else {
				return this.WriteFileHeader(this.Memory.GetCurPosition(), AscCommon.c_oSerFormat.Version) + this.Memory.GetBase64Memory();
			}
        };
        this.WriteFileHeader = function(nDataSize, version)
        {
            return AscCommon.c_oSerFormat.Signature + ";v" + version + ";" + nDataSize  + ";";
        };
        this.WriteMainTable = function()
        {
            var nTableCount = 128;//Специально ставим большое число, чтобы не увеличивать его при добавлении очередной таблицы.
            this.nRealTableCount = 0;//Специально ставим большое число, чтобы не увеличивать его при добавлении очередной таблицы.
            var nStart = this.Memory.GetCurPosition();
            //вычисляем с какой позиции можно писать таблицы
            var nmtItemSize = 5;//5 byte
            this.nLastFilePos = nStart + nTableCount * nmtItemSize;
            //Write mtLen 
            this.Memory.WriteByte(0);
            var oSharedStrings = {index: 0, strings: {}};
            //Write SharedStrings
            var nSharedStringsPos = this.ReserveTable(c_oSerTableTypes.SharedStrings);
            //Write Styles
            var nStylesTablePos = this.ReserveTable(c_oSerTableTypes.Styles);
            //Workbook
            var aDxfs = [];
            var oBinaryWorksheetsTableWriter = new BinaryWorksheetsTableWriter(this.Memory, this.wb, oSharedStrings, aDxfs, this.isCopyPaste);
            this.WriteTable(c_oSerTableTypes.Workbook, new BinaryWorkbookTableWriter(this.Memory, this.wb, oBinaryWorksheetsTableWriter, this.isCopyPaste));
            //Worksheets
            this.WriteTable(c_oSerTableTypes.Worksheets, oBinaryWorksheetsTableWriter);
            //OtherTable
            if(!this.isCopyPaste)
                this.WriteTable(c_oSerTableTypes.Other, new BinaryOtherTableWriter(this.Memory, this.wb));
            //Write SharedStrings
            this.WriteReserved(new BinarySharedStringsTableWriter(this.Memory, this.wb, oSharedStrings), nSharedStringsPos);
            //Write Styles
            this.WriteReserved(new BinaryStylesTableWriter(this.Memory, this.wb, oBinaryWorksheetsTableWriter), nStylesTablePos);
            //Пишем количество таблиц
            this.Memory.Seek(nStart);
            this.Memory.WriteByte(this.nRealTableCount);

            //seek в конец, потому что GetBase64Memory заканчивает запись на текущей позиции.
            this.Memory.Seek(this.nLastFilePos);
        };
        this.WriteTable = function(type, oTableSer)
        {
            //Write mtItem
            //Write mtiType
            this.Memory.WriteByte(type);
            //Write mtiOffBits
            this.Memory.WriteLong(this.nLastFilePos);

            //Write table
            //Запоминаем позицию в MainTable
            var nCurPos = this.Memory.GetCurPosition();
            //Seek в свободную область
            this.Memory.Seek(this.nLastFilePos);
            oTableSer.Write();
            //сдвигаем позицию куда можно следующую таблицу
            this.nLastFilePos = this.Memory.GetCurPosition();
            //Seek вобратно в MainTable
            this.Memory.Seek(nCurPos);

            this.nRealTableCount++;
        };
        this.ReserveTable = function(type)
        {
            var res = 0;
            //Write mtItem
            //Write mtiType
            this.Memory.WriteByte(type);
            res = this.Memory.GetCurPosition();
            //Write mtiOffBits
            this.Memory.WriteLong(this.nLastFilePos);
            return res;
        };
        this.WriteReserved = function(oTableSer, nPos)
        {
            this.Memory.Seek(nPos);
            this.Memory.WriteLong(this.nLastFilePos);

            //Write table
            //Запоминаем позицию в MainTable
            var nCurPos = this.Memory.GetCurPosition();
            //Seek в свободную область
            this.Memory.Seek(this.nLastFilePos);
            oTableSer.Write();
            //сдвигаем позицию куда можно следующую таблицу
            this.nLastFilePos = this.Memory.GetCurPosition();
            //Seek вобратно в MainTable
            this.Memory.Seek(nCurPos);

            this.nRealTableCount++;
        };
    }
    /** @constructor */
    function Binary_TableReader(stream, oReadResult, ws, Dxfs)
    {
        this.stream = stream;
        this.ws = ws;
        this.Dxfs = Dxfs;
        this.bcr = new Binary_CommonReader(this.stream);
        this.oReadResult = oReadResult;
        this.Read = function(length, aTables)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            res = this.bcr.Read1(length, function(t,l){
                return oThis.ReadTables(t,l, aTables);
            });
            return res;
        };
        this.ReadTables = function(type, length, aTables)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_TablePart.Table == type )
            {
                var oNewTable = this.ws.createTablePart();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadTable(t,l, oNewTable);
                });
                if(null != oNewTable.Ref && null != oNewTable.DisplayName)
                    this.ws.workbook.dependencyFormulas.addTableName(this.ws, oNewTable, true);
                aTables.push(oNewTable);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadTable = function(type, length, oTable)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_TablePart.Ref == type )
                oTable.Ref = AscCommonExcel.g_oRangeCache.getAscRange(this.stream.GetString2LE(length));
            else if ( c_oSer_TablePart.HeaderRowCount == type )
                oTable.HeaderRowCount = this.stream.GetULongLE();
            else if ( c_oSer_TablePart.TotalsRowCount == type )
                oTable.TotalsRowCount = this.stream.GetULongLE();
            else if ( c_oSer_TablePart.DisplayName == type )
                oTable.DisplayName = this.stream.GetString2LE(length);
            else if ( c_oSer_TablePart.AutoFilter == type )
            {
                oTable.AutoFilter = new AscCommonExcel.AutoFilter();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadAutoFilter(t,l, oTable.AutoFilter);
                });
            }
            else if ( c_oSer_TablePart.SortState == type )
            {
                oTable.SortState = new AscCommonExcel.SortState();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadSortState(t,l, oTable.SortState);
                });
            }
            else if ( c_oSer_TablePart.TableColumns == type )
            {
                oTable.TableColumns = [];
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadTableColumns(t,l, oTable.TableColumns);
                });
            }
            else if ( c_oSer_TablePart.TableStyleInfo == type )
            {
                oTable.TableStyleInfo = new AscCommonExcel.TableStyleInfo();
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadTableStyleInfo(t,l, oTable.TableStyleInfo);
                });
            }
			else if ( c_oSer_TablePart.AltTextTable == type )
			{
				res = this.bcr.Read1(length, function(t,l){
					return oThis.ReadAltTextTable(t,l, oTable);
				});
			}
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
		this.ReadAltTextTable = function(type, length, oTable)
		{
			var res = c_oSerConstants.ReadOk;
			var oThis = this;
			if (c_oSer_AltTextTable.AltText == type) {
				oTable.altText = this.stream.GetString2LE(length);
			} else if ( c_oSer_AltTextTable.AltTextSummary == type ) {
				oTable.altTextSummary  = this.stream.GetString2LE(length);
			} else
				res = c_oSerConstants.ReadUnknown;
			return res;
		};
        this.ReadAutoFilter = function(type, length, oAutoFilter)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_AutoFilter.Ref == type )
			{
				var sRef = this.stream.GetString2LE(length);

				//TODO пересмотреть проверку
				//возможно здесь 3d ref - проверяем
				if(-1 !== sRef.indexOf("!"))
				{
					var is3DRef = AscCommon.parserHelp.parse3DRef(sRef);
					if(is3DRef){
						sRef = is3DRef.range;
					}
				}

				oAutoFilter.Ref = AscCommonExcel.g_oRangeCache.getAscRange(sRef);
			}
            else if ( c_oSer_AutoFilter.FilterColumns == type )
            {
                oAutoFilter.FilterColumns = [];
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadFilterColumns(t,l, oAutoFilter.FilterColumns);
                });
            }
            else if ( c_oSer_AutoFilter.SortState == type )
            {
                oAutoFilter.SortState = new AscCommonExcel.SortState();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadSortState(t,l, oAutoFilter.SortState);
                });
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadFilterColumns = function(type, length, aFilterColumns)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_AutoFilter.FilterColumn == type )
            {
                var oFilterColumn = new AscCommonExcel.FilterColumn();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadFilterColumn(t,l, oFilterColumn);
                });
                aFilterColumns.push(oFilterColumn);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadFilterColumn = function(type, length, oFilterColumn)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_FilterColumn.ColId == type )
                oFilterColumn.ColId = this.stream.GetULongLE();
            else if ( c_oSer_FilterColumn.Filters == type )
            {
                oFilterColumn.Filters = new AscCommonExcel.Filters();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadFilters(t,l, oFilterColumn.Filters);
                });
				
				//sort dates
				if(oFilterColumn.Filters && oFilterColumn.Filters.Dates && oFilterColumn.Filters.Dates.length)
				{
					oFilterColumn.Filters.Dates.sort (function sortArr(a, b)
					{
						return a.start - b.start;
					})
				}
            }
            else if ( c_oSer_FilterColumn.CustomFilters == type )
            {
                oFilterColumn.CustomFiltersObj = new Asc.CustomFilters();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadCustomFilters(t,l, oFilterColumn.CustomFiltersObj);
                });
            }
            else if ( c_oSer_FilterColumn.DynamicFilter == type )
            {
                oFilterColumn.DynamicFilter = new Asc.DynamicFilter();
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadDynamicFilter(t,l, oFilterColumn.DynamicFilter);
                });
            }else if ( c_oSer_FilterColumn.ColorFilter == type )
            {
                oFilterColumn.ColorFilter = new Asc.ColorFilter();
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadColorFilter(t,l, oFilterColumn.ColorFilter);
                });
            }
            else if ( c_oSer_FilterColumn.Top10 == type )
            {
                oFilterColumn.Top10 = new Asc.Top10();
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadTop10(t,l, oFilterColumn.Top10);
                });
            }
            else if ( c_oSer_FilterColumn.HiddenButton == type )
                oFilterColumn.ShowButton = !this.stream.GetBool();
            else if ( c_oSer_FilterColumn.ShowButton == type )
                oFilterColumn.ShowButton = this.stream.GetBool();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadFilters = function(type, length, oFilters)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_FilterColumn.Filter == type )
            {
                var oFilterVal = new AscCommonExcel.Filter();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadFilter(t,l, oFilterVal);
                });
                if(null != oFilterVal.Val)
					oFilters.Values[oFilterVal.Val] = 1;
            }
            else if ( c_oSer_FilterColumn.DateGroupItem == type )
            {
                var oDateGroupItem = new AscCommonExcel.DateGroupItem();
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadDateGroupItem(t,l, oDateGroupItem);
                });

				var autoFilterDateElem = new AscCommonExcel.AutoFilterDateElem();
				autoFilterDateElem.convertDateGroupItemToRange(oDateGroupItem);
				oFilters.Dates.push(autoFilterDateElem);
            }
            else if ( c_oSer_FilterColumn.FiltersBlank == type )
                oFilters.Blank = this.stream.GetBool();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadFilter = function(type, length, oFilter)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_Filter.Val == type )
                oFilter.Val = this.stream.GetString2LE(length);
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadDateGroupItem = function(type, length, oDateGroupItem)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_DateGroupItem.DateTimeGrouping == type )
                oDateGroupItem.DateTimeGrouping = this.stream.GetUChar();
            else if ( c_oSer_DateGroupItem.Day == type )
                oDateGroupItem.Day = this.stream.GetULongLE();
            else if ( c_oSer_DateGroupItem.Hour == type )
                oDateGroupItem.Hour = this.stream.GetULongLE();
            else if ( c_oSer_DateGroupItem.Minute == type )
                oDateGroupItem.Minute = this.stream.GetULongLE();
            else if ( c_oSer_DateGroupItem.Month == type )
                oDateGroupItem.Month = this.stream.GetULongLE();
            else if ( c_oSer_DateGroupItem.Second == type )
                oDateGroupItem.Second = this.stream.GetULongLE();
            else if ( c_oSer_DateGroupItem.Year == type )
                oDateGroupItem.Year = this.stream.GetULongLE();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadCustomFilters = function(type, length, oCustomFilters)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_CustomFilters.And == type )
                oCustomFilters.And = this.stream.GetBool();
            else if ( c_oSer_CustomFilters.CustomFilters == type )
            {
                oCustomFilters.CustomFilters = [];
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadCustomFiltersItems(t,l, oCustomFilters.CustomFilters);
                });
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadCustomFiltersItems = function(type, length, aCustomFilters)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_CustomFilters.CustomFilter == type )
            {
                var oCustomFiltersItem = new Asc.CustomFilter();
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadCustomFiltersItem(t,l, oCustomFiltersItem);
                });
                aCustomFilters.push(oCustomFiltersItem);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadCustomFiltersItem = function(type, length, oCustomFiltersItem)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_CustomFilters.Operator == type )
                oCustomFiltersItem.Operator = this.stream.GetUChar();
            else if ( c_oSer_CustomFilters.Val == type )
                oCustomFiltersItem.Val = this.stream.GetString2LE(length);
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadDynamicFilter = function(type, length, oDynamicFilter)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_DynamicFilter.Type == type )
                oDynamicFilter.Type = this.stream.GetUChar();
            else if ( c_oSer_DynamicFilter.Val == type )
                oDynamicFilter.Val = this.stream.GetDoubleLE();
            else if ( c_oSer_DynamicFilter.MaxVal == type )
                oDynamicFilter.MaxVal = this.stream.GetDoubleLE();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadColorFilter = function(type, length, oColorFilter)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_ColorFilter.CellColor == type )
                oColorFilter.CellColor = this.stream.GetBool();
            else if ( c_oSer_ColorFilter.DxfId == type )
            {
                var DxfId = this.stream.GetULongLE();
                oColorFilter.dxf = this.Dxfs[DxfId];
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadTop10 = function(type, length, oTop10)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_Top10.FilterVal == type )
                oTop10.FilterVal = this.stream.GetDoubleLE();
            else if ( c_oSer_Top10.Percent == type )
                oTop10.Percent = this.stream.GetBool();
            else if ( c_oSer_Top10.Top == type )
                oTop10.Top = this.stream.GetBool();
            else if ( c_oSer_Top10.Val == type )
                oTop10.Val = this.stream.GetDoubleLE();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadSortConditionContent = function(type, length, oSortCondition)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_SortState.ConditionRef == type )
                oSortCondition.Ref = AscCommonExcel.g_oRangeCache.getAscRange(this.stream.GetString2LE(length));
            else if ( c_oSer_SortState.ConditionSortBy == type )
                oSortCondition.ConditionSortBy = this.stream.GetUChar();
            else if ( c_oSer_SortState.ConditionDescending == type )
                oSortCondition.ConditionDescending = this.stream.GetBool();
            else if ( c_oSer_SortState.ConditionDxfId == type )
            {
                var DxfId = this.stream.GetULongLE();
                oSortCondition.dxf = this.Dxfs[DxfId];
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadSortCondition = function(type, length, aSortConditions)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_SortState.SortCondition == type )
            {
                var oSortCondition = new AscCommonExcel.SortCondition();
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadSortConditionContent(t,l, oSortCondition);
                });
                aSortConditions.push(oSortCondition);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadSortState = function(type, length, oSortState)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_SortState.Ref == type )
                oSortState.Ref = AscCommonExcel.g_oRangeCache.getAscRange(this.stream.GetString2LE(length));
            else if ( c_oSer_SortState.CaseSensitive == type )
                oSortState.CaseSensitive = this.stream.GetBool();
            else if ( c_oSer_SortState.SortConditions == type )
            {
                oSortState.SortConditions = [];
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadSortCondition(t,l, oSortState.SortConditions);
                });
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadTableColumn = function(type, length, oTableColumn)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_TableColumns.Name == type )
                oTableColumn.Name = this.stream.GetString2LE(length);
            else if ( c_oSer_TableColumns.TotalsRowLabel == type )
                oTableColumn.TotalsRowLabel = this.stream.GetString2LE(length);
            else if ( c_oSer_TableColumns.TotalsRowFunction == type )
                oTableColumn.TotalsRowFunction = this.stream.GetUChar();
            else if ( c_oSer_TableColumns.TotalsRowFormula == type ) {
                var formula = this.stream.GetString2LE(length);
                this.oReadResult.tableCustomFunc.push({formula: formula, column: oTableColumn, ws: this.ws});
            }  else if ( c_oSer_TableColumns.DataDxfId == type ) {
                var DxfId = this.stream.GetULongLE();
                oTableColumn.dxf = this.Dxfs[DxfId];
            }
            /*else if ( c_oSer_TableColumns.CalculatedColumnFormula == type )
			{
				oTableColumn.CalculatedColumnFormula = this.stream.GetString2LE(length);
			}*/
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadTableColumns = function(type, length, aTableColumns)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_TableColumns.TableColumn == type )
            {
                var oTableColumn = new AscCommonExcel.TableColumn();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadTableColumn(t,l, oTableColumn);
                });
                aTableColumns.push(oTableColumn);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadTableStyleInfo = function(type, length, oTableStyleInfo)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_TableStyleInfo.Name == type )
                oTableStyleInfo.Name = this.stream.GetString2LE(length);
            else if ( c_oSer_TableStyleInfo.ShowColumnStripes == type )
                oTableStyleInfo.ShowColumnStripes = this.stream.GetBool();
            else if ( c_oSer_TableStyleInfo.ShowRowStripes == type )
                oTableStyleInfo.ShowRowStripes = this.stream.GetBool();
            else if ( c_oSer_TableStyleInfo.ShowFirstColumn == type )
                oTableStyleInfo.ShowFirstColumn = this.stream.GetBool();
            else if ( c_oSer_TableStyleInfo.ShowLastColumn == type )
                oTableStyleInfo.ShowLastColumn = this.stream.GetBool();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
    }
    /** @constructor */
    function Binary_SharedStringTableReader(stream, wb, aSharedStrings)
    {
        this.stream = stream;
        this.wb = wb;
        this.aSharedStrings = aSharedStrings;
        this.bcr = new Binary_CommonReader(this.stream);
        this.Read = function()
        {
            var oThis = this;
			var tempValue = {text: null, multiText: null};
            return this.bcr.ReadTable(function(t, l){
                return oThis.ReadSharedStringContent(t,l, tempValue);
            });
        };
        this.ReadSharedStringContent = function(type, length, tempValue)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSerSharedStringTypes.Si === type )
            {
                var oThis = this;
				tempValue.text = null;
				tempValue.multiText = null;
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadSharedString(t,l, tempValue);
                });
                if(null != this.aSharedStrings) {
					if (null != tempValue.text) {
						this.aSharedStrings.push(tempValue.text);
					} else if (null != tempValue.multiText) {
						this.aSharedStrings.push(tempValue.multiText);
					}
				}
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadSharedString = function(type, length, tempValue)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSerSharedStringTypes.Run == type )
            {
                var oThis = this;
                var oRun = new AscCommonExcel.CMultiTextElem();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadRun(t,l,oRun);
                });
                if(null == tempValue.multiText)
                    tempValue.multiText = [];
                tempValue.multiText.push(oRun);
            }
            else if ( c_oSerSharedStringTypes.Text == type )
            {
                if(null == tempValue.text)
                    tempValue.text = "";
                tempValue.text += this.stream.GetString2LE(length);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadRun = function(type, length, oRun)
        {
            var oThis = this;
            var res = c_oSerConstants.ReadOk;
            if ( c_oSerSharedStringTypes.RPr == type )
            {
                if(null == oRun.format)
                    oRun.format = new AscCommonExcel.Font();
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadRPr(t,l, oRun.format);
                });
                this.CheckSchemeFont(oRun.format);
            }
            else if ( c_oSerSharedStringTypes.Text == type )
            {
                if(null == oRun.text)
                    oRun.text = "";
                oRun.text += this.stream.GetString2LE(length);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.CheckSchemeFont = function(font)
        {
            if(null != font.scheme)
            {
                var theme = this.wb.theme;
                if(null != theme)
                {
                    var fontScheme = theme.themeElements.fontScheme;
                    var sFontName = null;
                    switch(font.scheme)
                    {
                        case EFontScheme.fontschemeMinor: sFontName = fontScheme.minorFont.latin;break;
                        case EFontScheme.fontschemeMajor: sFontName = fontScheme.majorFont.latin;break;
                    }
                    if(null != sFontName && "" != sFontName)
                        font.fn = sFontName;
                }
            }
        };
        this.ReadRPr = function(type, length, rPr)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerFontTypes.Bold == type )
                rPr.b = this.stream.GetBool();
            else if ( c_oSerFontTypes.Color == type ){
				var color = ReadColorSpreadsheet2(this.bcr, length);
				if (color) {
					rPr.c = color;
				}
			} else if ( c_oSerFontTypes.Italic == type )
                rPr.i = this.stream.GetBool();
            else if ( c_oSerFontTypes.RFont == type )
                rPr.fn = this.stream.GetString2LE(length);
            else if ( c_oSerFontTypes.Strike == type )
                rPr.s = this.stream.GetBool();
            else if ( c_oSerFontTypes.Sz == type )
                rPr.fs = this.stream.GetDoubleLE();
            else if ( c_oSerFontTypes.Underline == type )
                rPr.u = this.stream.GetUChar();
            else if ( c_oSerFontTypes.VertAlign == type )
            {
                rPr.va = this.stream.GetUChar();
                //server constants SubScript:1, SuperScript: 2
                if (rPr.va === AscCommon.vertalign_SubScript) {
                    rPr.va = AscCommon.vertalign_SuperScript;
                } else if (rPr.va === AscCommon.vertalign_SuperScript) {
                    rPr.va = AscCommon.vertalign_SubScript;
                }
            }
            else if ( c_oSerFontTypes.Scheme == type )
                rPr.scheme = this.stream.GetUChar();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
    }
    /** @constructor */
    function Binary_StylesTableReader(stream, wb, aCellXfs, Dxfs, isCopyPaste, useNumId)
    {
        this.stream = stream;
        this.wb = wb;
        this.oStyleManager = wb.oStyleManager;
        this.aCellXfs = aCellXfs;
        this.Dxfs = Dxfs;
        this.bcr = new Binary_CommonReader(this.stream);
        this.bssr = new Binary_SharedStringTableReader(this.stream, wb);
		this.isCopyPaste = isCopyPaste;
		this.useNumId = useNumId;
        this.Read = function()
        {
            var oThis = this;
            var oStyleObject = {aBorders: [], aFills: [], aFonts: [], oNumFmts: {}, aCellStyleXfs: [],
                aCellXfs: [], aCellStyles: [], oCustomTableStyles: {}};
            var res = this.bcr.ReadTable(function (t, l) {
                return oThis.ReadStylesContent(t, l, oStyleObject);
            });
            this.InitStyleManager(oStyleObject);
            return res;
        };
        this.InitStyleManager = function (oStyleObject)
        {
			for (var i = 0; i < oStyleObject.aFonts.length; ++i) {
				oStyleObject.aFonts[i] = g_StyleCache.addFont(oStyleObject.aFonts[i]);
			}
			for (var i = 0; i < oStyleObject.aFills.length; ++i) {
				oStyleObject.aFills[i] = g_StyleCache.addFill(oStyleObject.aFills[i]);
			}
			for (var i = 0; i < oStyleObject.aBorders.length; ++i) {
				oStyleObject.aBorders[i] = g_StyleCache.addBorder(oStyleObject.aBorders[i]);
			}
			for (var XfIdTmp in oStyleObject.aCellStyleXfs) {
				var xf = oStyleObject.aCellStyleXfs[XfIdTmp];
				if (xf.align) {
					xf.align = g_StyleCache.addAlign(xf.align);
				}
			}
			for (var i = 0; i < oStyleObject.aCellXfs.length; ++i) {
				var xf = oStyleObject.aCellXfs[i];
				if (xf.align) {
					xf.align = g_StyleCache.addAlign(xf.align);
				}
			}
			for (var i = 0; i < this.Dxfs.length; ++i) {
				this.Dxfs[i] = g_StyleCache.addXf(this.Dxfs[i], true);
			}

            // ToDo убрать - это заглушка
            var arrStyleMap = {};
            // Начнем с 1, т.к. 2 зарегистрировано для normal
            var nIndexStyleMap = 1;
            var XfIdTmp;
            // Список имен для стилей
            var oCellStyleNames = {};

            for (var nIndex in oStyleObject.aCellStyles) {
                if (!oStyleObject.aCellStyles.hasOwnProperty(nIndex))
                    continue;

                var oCellStyle = oStyleObject.aCellStyles[nIndex];
                var oCellStyleXfs = oStyleObject.aCellStyleXfs[oCellStyle.XfId];
                // Если есть стиль, но нет описания, то уберем этот стиль (Excel делает также)
                if (null == oCellStyleXfs)
                    continue;

                var newXf = new AscCommonExcel.CellXfs();
                // XfId
                XfIdTmp = oCellStyle.XfId;
                if (null !== XfIdTmp) {
                    if (0 !== XfIdTmp) {
                        arrStyleMap[XfIdTmp] = nIndexStyleMap;
                        oCellStyle.XfId = nIndexStyleMap++;
                    }
                } else
                    continue;	// Если его нет, то это ошибка по спецификации

                // Border
                if (null != oCellStyleXfs.borderid) {
                    var borderCellStyle = oStyleObject.aBorders[oCellStyleXfs.borderid];
                    if(null != borderCellStyle)
						newXf.border = borderCellStyle;
                }
                // Fill
                if (null != oCellStyleXfs.fillid) {
                    var fillCellStyle = oStyleObject.aFills[oCellStyleXfs.fillid];
                    if(null != fillCellStyle)
						newXf.fill = fillCellStyle;
                }
                // Font
                if(null != oCellStyleXfs.fontid) {
                    var fontCellStyle = oStyleObject.aFonts[oCellStyleXfs.fontid];
                    if(null != fontCellStyle)
						newXf.font = fontCellStyle;
                }
                // NumFmt
                if(null != oCellStyleXfs.numid) {
                    var oCurNumCellStyle = oStyleObject.oNumFmts[oCellStyleXfs.numid];
                    if(null != oCurNumCellStyle)
						newXf.num = g_StyleCache.addNum(oCurNumCellStyle);
                    else
						newXf.num = g_StyleCache.addNum(this.ParseNum({id: oCellStyleXfs.numid, f: null}, oStyleObject.oNumFmts));
                }
                // QuotePrefix
                if(null != oCellStyleXfs.QuotePrefix)
					newXf.QuotePrefix = oCellStyleXfs.QuotePrefix;
				//PivotButton
				if(null != oCellStyleXfs.PivotButton)
					newXf.PivotButton = oCellStyleXfs.PivotButton;
                // align
                if(null != oCellStyleXfs.align)
					newXf.align = oCellStyleXfs.align;
                // ApplyBorder (ToDo возможно это свойство должно быть в xfs)
                if (null !== oCellStyleXfs.ApplyBorder)
                    oCellStyle.ApplyBorder = oCellStyleXfs.ApplyBorder;
                // ApplyFill (ToDo возможно это свойство должно быть в xfs)
                if (null !== oCellStyleXfs.ApplyFill)
                    oCellStyle.ApplyFill = oCellStyleXfs.ApplyFill;
                // ApplyFont (ToDo возможно это свойство должно быть в xfs)
                if (null !== oCellStyleXfs.ApplyFont)
                    oCellStyle.ApplyFont = oCellStyleXfs.ApplyFont;
                // ApplyNumberFormat (ToDo возможно это свойство должно быть в xfs)
                if (null !== oCellStyleXfs.ApplyNumberFormat)
                    oCellStyle.ApplyNumberFormat = oCellStyleXfs.ApplyNumberFormat;

				oCellStyle.xfs = g_StyleCache.addXf(newXf);
                // ToDo при отсутствии имени все не очень хорошо будет!
                this.wb.CellStyles.CustomStyles.push(oCellStyle);
                if (null !== oCellStyle.Name)
                    oCellStyleNames[oCellStyle.Name] = true;
            }

            // ToDo стоит это переделать в дальнейшем (пробежимся по именам, и у отсутствующих создадим имя)
            var nNewStyleIndex = 1, newStyleName;
            for (var i = 0, length = this.wb.CellStyles.CustomStyles.length; i < length; ++i) {
                if (null === this.wb.CellStyles.CustomStyles[i].Name) {
                    do {
                        newStyleName = "Style" + nNewStyleIndex++;
                    } while (oCellStyleNames[newStyleName])
                        ;
                    this.wb.CellStyles.CustomStyles[i].Name = newStyleName;
                }
            }

            // ToDo это нужно будет переделать (проходимся по всем стилям и меняем у них XfId по порядку)

            for(var i = 0, length = oStyleObject.aCellXfs.length; i < length; ++i) {
                var xfs = oStyleObject.aCellXfs[i];
                var newXf = new AscCommonExcel.CellXfs();

                if(null != xfs.borderid)
                {
                    var border = oStyleObject.aBorders[xfs.borderid];
                    if(null != border)
						newXf.border = border;
                }
                if(null != xfs.fillid)
                {
                    var fill = oStyleObject.aFills[xfs.fillid];
                    if(null != fill)
						newXf.fill = fill;
                }
                if(null != xfs.fontid)
                {
                    var font = oStyleObject.aFonts[xfs.fontid];
                    if(null != font)
						newXf.font = font;
                }
                if(null != xfs.numid)
                {
                    var oCurNum = oStyleObject.oNumFmts[xfs.numid];
                    //todo
                    if(null != oCurNum)
						newXf.num = g_StyleCache.addNum(oCurNum);
                    else
						newXf.num = g_StyleCache.addNum(this.ParseNum({id: xfs.numid, f: null}, oStyleObject.oNumFmts));
                }
                if(null != xfs.QuotePrefix)
					newXf.QuotePrefix = xfs.QuotePrefix;
				if(null != xfs.PivotButton)
					newXf.PivotButton = xfs.PivotButton;
                if(null != xfs.align)
					newXf.align = xfs.align;
                if (null !== xfs.XfId) {
                    XfIdTmp = arrStyleMap[xfs.XfId];
                    if (null == XfIdTmp)
                        XfIdTmp = 0;
					newXf.XfId = XfIdTmp;
                }

                if(0 == this.aCellXfs.length && !this.isCopyPaste)
                    this.oStyleManager.init(newXf, this.wb);
                this.aCellXfs.push(g_StyleCache.addXf(newXf));
            }
            for(var i in oStyleObject.oCustomTableStyles)
            {
                var item = oStyleObject.oCustomTableStyles[i];
                if(null != item)
                {
                    var style = item.style;
                    var elems = item.elements;
                    this.initTableStyle(style, elems, this.Dxfs);
                    this.wb.TableStyles.CustomStyles[i] = style;
                }
            }
        };
        this.initTableStyle = function(style, elems, Dxfs)
        {
            for(var j = 0, length2 = elems.length; j < length2; ++j)
            {
                var elem = elems[j];
                if(null != elem.DxfId)
                {
                    var Dxf = Dxfs[elem.DxfId];
                    if(null != Dxf)
                    {
                        var oTableStyleElement = new CTableStyleElement();
                        oTableStyleElement.dxf = Dxf;
                        if(null != elem.Size)
                            oTableStyleElement.size = elem.Size;
                        switch(elem.Type)
                        {
                            case ETableStyleType.tablestyletypeBlankRow: style.blankRow = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeFirstColumn: style.firstColumn = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeFirstColumnStripe: style.firstColumnStripe = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeFirstColumnSubheading: style.firstColumnSubheading = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeFirstHeaderCell: style.firstHeaderCell = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeFirstRowStripe: style.firstRowStripe = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeFirstRowSubheading: style.firstRowSubheading = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeFirstSubtotalColumn: style.firstSubtotalColumn = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeFirstSubtotalRow: style.firstSubtotalRow = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeFirstTotalCell: style.firstTotalCell = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeHeaderRow: style.headerRow = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeLastColumn: style.lastColumn = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeLastHeaderCell: style.lastHeaderCell = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeLastTotalCell: style.lastTotalCell = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypePageFieldLabels: style.pageFieldLabels = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypePageFieldValues: style.pageFieldValues = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeSecondColumnStripe: style.secondColumnStripe = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeSecondColumnSubheading: style.secondColumnSubheading = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeSecondRowStripe: style.secondRowStripe = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeSecondRowSubheading: style.secondRowSubheading = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeSecondSubtotalColumn: style.secondSubtotalColumn = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeSecondSubtotalRow: style.secondSubtotalRow = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeThirdColumnSubheading: style.thirdColumnSubheading = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeThirdRowSubheading: style.thirdRowSubheading = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeThirdSubtotalColumn: style.thirdSubtotalColumn = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeThirdSubtotalRow: style.thirdSubtotalRow = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeTotalRow: style.totalRow = oTableStyleElement;break;
                            case ETableStyleType.tablestyletypeWholeTable: style.wholeTable = oTableStyleElement;break;
                        }
                    }
                }
            }
        };
		this.ParseNum = function(oNum, oNumFmts) {
			var oRes = new AscCommonExcel.Num();
			var useNumId = false;
			if (null != oNum && null != oNum.f) {
				oRes.f = oNum.f;
			} else {
				var sStandartNumFormat = AscCommonExcel.aStandartNumFormats[oNum.id];
				if (null != sStandartNumFormat) {
					oRes.f = sStandartNumFormat;
				}
				if (null == oRes.f) {
					oRes.f = "General";
				}
				//format string is more priority then id. so, fill oRes.id only if format is empty
				useNumId = true;
			}
			if ((useNumId || this.useNumId) &&
				((5 <= oNum.id && oNum.id <= 8) || (14 <= oNum.id && oNum.id <= 17) || 22 == oNum.id ||
				(27 <= oNum.id && oNum.id <= 31) || (36 <= oNum.id && oNum.id <= 44))) {
					oRes.id = oNum.id;
				}
			if (null != oNumFmts) {
				oNumFmts[oNum.id] = oRes;
			}
			return oRes;
		};
        this.ReadStylesContent = function (type, length, oStyleObject) {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if (c_oSerStylesTypes.Borders === type) {
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadBorders(t, l, oStyleObject.aBorders);
                });
                oStyleObject.aBorders[0] = new AscCommonExcel.Border();
            } else if (c_oSerStylesTypes.Fills === type) {
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadFills(t, l, oStyleObject.aFills);
                });
                oStyleObject.aFills[0] = new AscCommonExcel.Fill();
                oStyleObject.aFills[1] = new AscCommonExcel.Fill();
            } else if (c_oSerStylesTypes.Fonts === type) {
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadFonts(t, l, oStyleObject.aFonts);
                });
            } else if (c_oSerStylesTypes.NumFmts === type) {
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadNumFmts(t, l, oStyleObject.oNumFmts);
                });
            } else if (c_oSerStylesTypes.CellStyleXfs === type) {
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadCellStyleXfs(t, l, oStyleObject.aCellStyleXfs);
                });
            } else if (c_oSerStylesTypes.CellXfs === type) {
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadCellXfs(t,l, oStyleObject.aCellXfs);
                });
            } else if (c_oSerStylesTypes.CellStyles === type) {
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadCellStyles(t, l, oStyleObject.aCellStyles);
                });
            } else if (c_oSerStylesTypes.Dxfs === type) {
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadDxfs(t, l, oThis.Dxfs);
                });
            } else if (c_oSerStylesTypes.TableStyles === type) {
                res = this.bcr.Read1(length, function (t, l){
                    return oThis.ReadTableStyles(t, l, oThis.wb.TableStyles, oStyleObject.oCustomTableStyles);
                });
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadBorders = function(type, length, aBorders)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerStylesTypes.Border == type )
            {
                var oNewBorder = new AscCommonExcel.Border();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadBorder(t,l,oNewBorder);
                });
                aBorders.push(oNewBorder);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadBorder = function(type, length, oNewBorder)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerBorderTypes.Bottom == type )
            {
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadBorderProp(t,l,oNewBorder.b);
                });
            }
            else if ( c_oSerBorderTypes.Diagonal == type )
            {
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadBorderProp(t,l,oNewBorder.d);
                });
            }
            else if ( c_oSerBorderTypes.End == type )
            {
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadBorderProp(t,l,oNewBorder.r);
                });
            }
            else if ( c_oSerBorderTypes.Horizontal == type )
            {
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadBorderProp(t,l,oNewBorder.ih);
                });
            }
            else if ( c_oSerBorderTypes.Start == type )
            {
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadBorderProp(t,l,oNewBorder.l);
                });
            }
            else if ( c_oSerBorderTypes.Top == type )
            {
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadBorderProp(t,l,oNewBorder.t);
                });
            }
            else if ( c_oSerBorderTypes.Vertical == type )
            {
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadBorderProp(t,l,oNewBorder.iv);
                });
            }
            else if ( c_oSerBorderTypes.DiagonalDown == type )
            {
                oNewBorder.dd = this.stream.GetBool();
            }
            else if ( c_oSerBorderTypes.DiagonalUp == type )
            {
                oNewBorder.du = this.stream.GetBool();
            }
            // else if ( c_oSerBorderTypes.Outline == type )
            // {
            // oNewBorder.outline = this.stream.GetBool();
            // }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadBorderProp = function(type, length, oBorderProp)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerBorderPropTypes.Style == type )
            {
                switch(this.stream.GetUChar())
                {
                    case EBorderStyle.borderstyleDashDot:			oBorderProp.setStyle(c_oAscBorderStyles.DashDot);break;
                    case EBorderStyle.borderstyleDashDotDot:		oBorderProp.setStyle(c_oAscBorderStyles.DashDotDot);break;
                    case EBorderStyle.borderstyleDashed:			oBorderProp.setStyle(c_oAscBorderStyles.Dashed);break;
                    case EBorderStyle.borderstyleDotted:			oBorderProp.setStyle(c_oAscBorderStyles.Dotted);break;
                    case EBorderStyle.borderstyleDouble:			oBorderProp.setStyle(c_oAscBorderStyles.Double);break;
                    case EBorderStyle.borderstyleHair:				oBorderProp.setStyle(c_oAscBorderStyles.Hair);break;
                    case EBorderStyle.borderstyleMedium:			oBorderProp.setStyle(c_oAscBorderStyles.Medium);break;
                    case EBorderStyle.borderstyleMediumDashDot:		oBorderProp.setStyle(c_oAscBorderStyles.MediumDashDot);break;
                    case EBorderStyle.borderstyleMediumDashDotDot:	oBorderProp.setStyle(c_oAscBorderStyles.MediumDashDotDot);break;
                    case EBorderStyle.borderstyleMediumDashed:		oBorderProp.setStyle(c_oAscBorderStyles.MediumDashed);break;
                    case EBorderStyle.borderstyleNone:				oBorderProp.setStyle(c_oAscBorderStyles.None);break;
                    case EBorderStyle.borderstyleSlantDashDot:		oBorderProp.setStyle(c_oAscBorderStyles.SlantDashDot);break;
                    case EBorderStyle.borderstyleThick:				oBorderProp.setStyle(c_oAscBorderStyles.Thick);break;
                    case EBorderStyle.borderstyleThin:				oBorderProp.setStyle(c_oAscBorderStyles.Thin);break;
                    default :										oBorderProp.setStyle(c_oAscBorderStyles.None);break;
                }
            }
            else if ( c_oSerBorderPropTypes.Color == type ) {
				var color = ReadColorSpreadsheet2(this.bcr, length);
				if (null != color) {
					oBorderProp.c = color;
				}
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadCellStyleXfs = function (type, length, aCellStyleXfs) {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if (c_oSerStylesTypes.Xfs === type) {
                var oNewXfs = {ApplyAlignment: null, ApplyBorder: null, ApplyFill: null, ApplyFont: null, ApplyNumberFormat: null,
                    BorderId: null, FillId: null, FontId: null, NumFmtId: null, QuotePrefix: null, Aligment: null, PivotButton: null};
                res = this.bcr.Read2Spreadsheet(length, function (t, l) {
                    return oThis.ReadXfs(t, l, oNewXfs);
                });
                aCellStyleXfs.push(oNewXfs);
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadCellXfs = function(type, length, aCellXfs)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerStylesTypes.Xfs == type )
            {
                var oNewXfs = {ApplyAlignment: null, ApplyBorder: null, ApplyFill: null, ApplyFont: null, ApplyNumberFormat: null,
                    BorderId: null, FillId: null, FontId: null, NumFmtId: null, QuotePrefix: null, Aligment: null, XfId: null, PivotButton: null};
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadXfs(t,l,oNewXfs);
                });
                aCellXfs.push(oNewXfs);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadXfs = function(type, length, oXfs)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerXfsTypes.ApplyAlignment == type )
                oXfs.ApplyAlignment = this.stream.GetBool();
            else if ( c_oSerXfsTypes.ApplyBorder == type )
                oXfs.ApplyBorder = this.stream.GetBool();
            else if ( c_oSerXfsTypes.ApplyFill == type )
                oXfs.ApplyFill = this.stream.GetBool();
            else if ( c_oSerXfsTypes.ApplyFont == type )
                oXfs.ApplyFont = this.stream.GetBool();
            else if ( c_oSerXfsTypes.ApplyNumberFormat == type )
                oXfs.ApplyNumberFormat = this.stream.GetBool();
            else if ( c_oSerXfsTypes.BorderId == type )
                oXfs.borderid = this.stream.GetULongLE();
            else if ( c_oSerXfsTypes.FillId == type )
                oXfs.fillid = this.stream.GetULongLE();
            else if ( c_oSerXfsTypes.FontId == type )
                oXfs.fontid = this.stream.GetULongLE();
            else if ( c_oSerXfsTypes.NumFmtId == type )
                oXfs.numid = this.stream.GetULongLE();
            else if ( c_oSerXfsTypes.QuotePrefix == type )
                oXfs.QuotePrefix = this.stream.GetBool();
			else if ( c_oSerXfsTypes.PivotButton == type )
				oXfs.PivotButton = this.stream.GetBool();
            else if (c_oSerXfsTypes.XfId === type)
                oXfs.XfId = this.stream.GetULongLE();
            else if ( c_oSerXfsTypes.Aligment == type )
            {
                if(null == oXfs.Aligment)
                    oXfs.align = new AscCommonExcel.Align();
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadAligment(t,l,oXfs.align);
                });
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadAligment = function(type, length, oAligment)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSerAligmentTypes.Horizontal == type )
            {
                switch(this.stream.GetUChar())
                {
                    case 0 :
                    case 1 : oAligment.hor = AscCommon.align_Center;break;
                    case 2 :
                    case 3 :
                    case 5 : oAligment.hor = AscCommon.align_Justify;break;
                    case 4 : oAligment.hor = null;break;
                    case 6 : oAligment.hor = AscCommon.align_Left;break;
                    case 7 : oAligment.hor = AscCommon.align_Right;break;
                }
            }
            else if ( c_oSerAligmentTypes.Indent == type )
                oAligment.indent = this.stream.GetULongLE();
            else if ( c_oSerAligmentTypes.RelativeIndent == type )
                oAligment.RelativeIndent = this.stream.GetULongLE();
            else if ( c_oSerAligmentTypes.ShrinkToFit == type )
                oAligment.shrink = this.stream.GetBool();
            else if ( c_oSerAligmentTypes.TextRotation == type )
                oAligment.angle = this.stream.GetULongLE();
            else if ( c_oSerAligmentTypes.Vertical == type )
            {
                oAligment.ver = this.stream.GetUChar();
                if (Asc.c_oAscVAlign.Dist == oAligment.ver ||
                    Asc.c_oAscVAlign.Just == oAligment.ver) {
                    oAligment.ver = Asc.c_oAscVAlign.Center;
                }
            }
            else if ( c_oSerAligmentTypes.WrapText == type )
                oAligment.wrap= this.stream.GetBool();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadFills = function(type, length, aFills)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerStylesTypes.Fill == type )
            {
                var oNewFill = new AscCommonExcel.Fill();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadFill(t,l,oNewFill);
                });
                aFills.push(oNewFill);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadFill = function(type, length, oFill)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerFillTypes.PatternFill == type )
            {
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadPatternFill(t,l,oFill);
                });
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadPatternFill = function(type, length, oFill)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerFillTypes.PatternFillBgColor == type ) {
				var color = ReadColorSpreadsheet2(this.bcr, length);
				if (null != color) {
					oFill.bg = color;
				}
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadFonts = function(type, length, aFonts)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerStylesTypes.Font == type )
            {
                var oNewFont = new AscCommonExcel.Font();
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.bssr.ReadRPr(t,l,oNewFont);
                });
                this.bssr.CheckSchemeFont(oNewFont);
                aFonts.push(oNewFont);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadNumFmts = function(type, length, oNumFmts)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerStylesTypes.NumFmt == type )
            {
                var oNewNumFmt = {f: null, id: null};
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadNumFmt(t,l,oNewNumFmt);
                });
				if (null != oNewNumFmt.id) {
					this.ParseNum(oNewNumFmt, oNumFmts);
				}
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadNumFmt = function(type, length, oNumFmt)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSerNumFmtTypes.FormatCode == type )
            {
                oNumFmt.f = this.stream.GetString2LE(length);
            }
            else if ( c_oSerNumFmtTypes.NumFmtId == type )
            {
                oNumFmt.id = this.stream.GetULongLE();
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadCellStyles = function (type, length, aCellStyles) {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            var oCellStyle = null;
            if (c_oSerStylesTypes.CellStyle === type) {
                oCellStyle = new AscCommonExcel.CCellStyle();
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadCellStyle(t, l, oCellStyle);
                });
                aCellStyles.push(oCellStyle);
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadCellStyle = function (type, length, oCellStyle) {
            var res = c_oSerConstants.ReadOk;
            if (c_oSer_CellStyle.BuiltinId === type)
                oCellStyle.BuiltinId = this.stream.GetULongLE();
            else if (c_oSer_CellStyle.CustomBuiltin === type)
                oCellStyle.CustomBuiltin = this.stream.GetBool();
            else if (c_oSer_CellStyle.Hidden === type)
                oCellStyle.Hidden = this.stream.GetBool();
            else if (c_oSer_CellStyle.ILevel === type)
                oCellStyle.ILevel = this.stream.GetULongLE();
            else if (c_oSer_CellStyle.Name === type)
                oCellStyle.Name = this.stream.GetString2LE(length);
            else if (c_oSer_CellStyle.XfId === type)
                oCellStyle.XfId = this.stream.GetULongLE();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadDxfs = function(type, length, aDxfs)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerStylesTypes.Dxf == type )
            {
                var oDxf = new AscCommonExcel.CellXfs();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadDxf(t,l,oDxf);
                });
                aDxfs.push(oDxf);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadDxf = function(type, length, oDxf)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_Dxf.Alignment == type )
            {
                oDxf.align = new AscCommonExcel.Align();
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadAligment(t,l,oDxf.align);
                });
            }
            else if ( c_oSer_Dxf.Border == type )
            {
                var oNewBorder = new AscCommonExcel.Border();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadBorder(t,l,oNewBorder);
                });
                oDxf.border = oNewBorder;
            }
            else if ( c_oSer_Dxf.Fill == type )
            {
                var oNewFill = new AscCommonExcel.Fill();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadFill(t,l,oNewFill);
                });
                oDxf.fill = oNewFill;
            }
            else if ( c_oSer_Dxf.Font == type )
            {
                var oNewFont = new AscCommonExcel.Font();
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.bssr.ReadRPr(t,l,oNewFont);
                });
                this.bssr.CheckSchemeFont(oNewFont);
                oDxf.font = oNewFont;
            }
            else if ( c_oSer_Dxf.NumFmt == type )
            {
                var oNewNumFmt = {f: null, id: null};
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadNumFmt(t,l,oNewNumFmt);
                });
                if(null != oNewNumFmt.id)
                    oDxf.num = this.ParseNum(oNewNumFmt, null);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadTableStyles = function(type, length, oTableStyles, oCustomStyles)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_TableStyles.DefaultTableStyle == type )
                oTableStyles.DefaultTableStyle = this.stream.GetString2LE(length);
            else if ( c_oSer_TableStyles.DefaultPivotStyle == type )
                oTableStyles.DefaultPivotStyle = this.stream.GetString2LE(length);
            else if ( c_oSer_TableStyles.TableStyles == type )
            {
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadTableCustomStyles(t,l, oCustomStyles);
                });
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadTableCustomStyles = function(type, length, oCustomStyles)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if (c_oSer_TableStyles.TableStyle === type)
            {
                var oNewStyle = new CTableStyle();
                var aElements = [];
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadTableCustomStyle(t,l, oNewStyle, aElements);
                });
                if(null != oNewStyle.name) {
                    if (null === oNewStyle.displayName)
                        oNewStyle.displayName = oNewStyle.name;
                    oCustomStyles[oNewStyle.name] = {style : oNewStyle, elements: aElements};
                }
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadTableCustomStyle = function(type, length, oNewStyle, aElements)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if (c_oSer_TableStyle.Name === type)
                oNewStyle.name = this.stream.GetString2LE(length);
            else if (c_oSer_TableStyle.Pivot === type)
                oNewStyle.pivot = this.stream.GetBool();
            else if (c_oSer_TableStyle.Table === type)
                oNewStyle.table = this.stream.GetBool();
            else if (c_oSer_TableStyle.Elements === type) {
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadTableCustomStyleElements(t,l, aElements);
                });
            } else if (c_oSer_TableStyle.DisplayName === type)
                oNewStyle.displayName = this.stream.GetString2LE(length);
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadTableCustomStyleElements = function(type, length, aElements)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if (c_oSer_TableStyle.Element === type)
            {
                var oNewStyleElement = {Type: null, Size: null, DxfId: null};
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadTableCustomStyleElement(t,l, oNewStyleElement);
                });
                if(null != oNewStyleElement.Type && null != oNewStyleElement.DxfId)
                    aElements.push(oNewStyleElement);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadTableCustomStyleElement = function(type, length, oNewStyleElement)
        {
            var res = c_oSerConstants.ReadOk;
            if (c_oSer_TableStyleElement.Type === type)
                oNewStyleElement.Type = this.stream.GetUChar();
            else if (c_oSer_TableStyleElement.Size === type)
                oNewStyleElement.Size = this.stream.GetULongLE();
            else if (c_oSer_TableStyleElement.DxfId === type)
                oNewStyleElement.DxfId = this.stream.GetULongLE();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
    }
    /** @constructor */
    function Binary_WorkbookTableReader(stream, oWorkbook, bwtr)
    {
        this.stream = stream;
        this.oWorkbook = oWorkbook;
        this.bcr = new Binary_CommonReader(this.stream);
        this.bwtr = bwtr;
        this.Read = function()
        {
            var oThis = this;
            return this.bcr.ReadTable(function(t, l){
                return oThis.ReadWorkbookContent(t,l);
            });
        };
        this.ReadWorkbookContent = function(type, length)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerWorkbookTypes.WorkbookPr === type )
            {
                if(null == this.oWorkbook.WorkbookPr)
                    this.oWorkbook.WorkbookPr = {};
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadWorkbookPr(t,l,oThis.oWorkbook.WorkbookPr);
                });
            }
            else if ( c_oSerWorkbookTypes.BookViews === type )
            {
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadBookViews(t,l);
                });
            }
            else if ( c_oSerWorkbookTypes.DefinedNames === type )
            {
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadDefinedNames(t,l);
                });
            }
			else if (c_oSerWorkbookTypes.CalcPr === type)
			{
				res = this.bcr.Read1(length, function(t, l) {
					return oThis.ReadCalcPr(t, l, oThis.oWorkbook.calcPr);
				});
			}
			else if ( c_oSerWorkbookTypes.ExternalReferences === type )
			{
				res = this.bcr.Read1(length, function(t,l){
					return oThis.ReadExternalReferences(t,l);
				});
			}
			else if (c_oSerWorkbookTypes.JsaProject == type)
			{
				this.oWorkbook.oApi.macros.SetData(AscCommon.GetStringUtf8(this.stream, length));
			}
            else if (c_oSerWorkbookTypes.Comments == type)
            {
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.bwtr.ReadCommentDatas(t,l, oThis.oWorkbook.aComments);
                });
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadWorkbookPr = function(type, length, WorkbookPr)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSerWorkbookPrTypes.Date1904 == type )
            {
                WorkbookPr.Date1904 = this.stream.GetBool();
                AscCommon.bDate1904 = WorkbookPr.Date1904;
                AscCommonExcel.c_DateCorrectConst = AscCommon.bDate1904?AscCommonExcel.c_Date1904Const:AscCommonExcel.c_Date1900Const;
            }
            else if ( c_oSerWorkbookPrTypes.DateCompatibility == type )
                WorkbookPr.DateCompatibility = this.stream.GetBool();
			else if ( c_oSerWorkbookPrTypes.HidePivotFieldList == type ) {
				WorkbookPr.HidePivotFieldList = this.stream.GetBool();
			} else if ( c_oSerWorkbookPrTypes.ShowPivotChartFilter == type ) {
				WorkbookPr.ShowPivotChartFilter = this.stream.GetBool();
			} else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadBookViews = function(type, length)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerWorkbookTypes.WorkbookView == type )
            {
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadWorkbookView(t,l);
                });
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadWorkbookView = function(type, length)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSerWorkbookViewTypes.ActiveTab == type )
                this.oWorkbook.nActive = this.stream.GetULongLE();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadDefinedNames = function(type, length)
        {
            var res = c_oSerConstants.ReadOk, LocalSheetId;
            var oThis = this;
            if ( c_oSerWorkbookTypes.DefinedName == type )
            {
                var oNewDefinedName = new Asc.asc_CDefName();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadDefinedName(t,l,oNewDefinedName);
                });
                if (null != oNewDefinedName.Name && null != oNewDefinedName.Ref) {
                    this.oWorkbook.dependencyFormulas.addDefNameOpen(oNewDefinedName.Name, oNewDefinedName.Ref, oNewDefinedName.LocalSheetId, oNewDefinedName.Hidden, false);
                }
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadDefinedName = function(type, length, oDefinedName)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSerDefinedNameTypes.Name == type )
                oDefinedName.Name = this.stream.GetString2LE(length);
            else if ( c_oSerDefinedNameTypes.Ref == type )
                oDefinedName.Ref = this.stream.GetString2LE(length);
            else if ( c_oSerDefinedNameTypes.LocalSheetId == type )
                oDefinedName.LocalSheetId = this.stream.GetULongLE();
            else if ( c_oSerDefinedNameTypes.Hidden == type )
                oDefinedName.Hidden = this.stream.GetBool();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
		this.ReadCalcPr = function(type, length, oCalcPr) {
			var res = c_oSerConstants.ReadOk;
			if (c_oSerCalcPrTypes.CalcId == type) {
				oCalcPr.calcId = this.stream.GetULongLE();
			} else if (c_oSerCalcPrTypes.CalcMode == type) {
				oCalcPr.calcMode = this.stream.GetUChar();
			} else if (c_oSerCalcPrTypes.FullCalcOnLoad == type) {
				oCalcPr.fullCalcOnLoad = this.stream.GetBool();
			} else if (c_oSerCalcPrTypes.RefMode == type) {
				oCalcPr.refMode = this.stream.GetUChar();
			} else if (c_oSerCalcPrTypes.Iterate == type) {
				oCalcPr.iterate = this.stream.GetBool();
			} else if (c_oSerCalcPrTypes.IterateCount == type) {
				oCalcPr.iterateCount = this.stream.GetULongLE();
			} else if (c_oSerCalcPrTypes.IterateDelta == type) {
				oCalcPr.iterateDelta = this.stream.GetDoubleLE();
			} else if (c_oSerCalcPrTypes.FullPrecision == type) {
				oCalcPr.fullPrecision = this.stream.GetBool();
			} else if (c_oSerCalcPrTypes.CalcCompleted == type) {
				oCalcPr.calcCompleted = this.stream.GetBool();
			} else if (c_oSerCalcPrTypes.CalcOnSave == type) {
				oCalcPr.calcOnSave = this.stream.GetBool();
			} else if (c_oSerCalcPrTypes.ConcurrentCalc == type) {
				oCalcPr.concurrentCalc = this.stream.GetBool();
			} else if (c_oSerCalcPrTypes.ConcurrentManualCount == type) {
				oCalcPr.concurrentManualCount = this.stream.GetULongLE();
			} else if (c_oSerCalcPrTypes.ForceFullCalc == type) {
				oCalcPr.forceFullCalc = this.stream.GetBool();
			} else {
				res = c_oSerConstants.ReadUnknown;
			}
			return res;
		};
		this.ReadExternalReferences = function(type, length) {
			var res = c_oSerConstants.ReadOk;
			var oThis = this;
			if (c_oSerWorkbookTypes.ExternalBook == type) {
				var externalBook = {Type: 0, Id: null, SheetNames: [], DefinedNames: [], SheetDataSet: []};
				res = this.bcr.Read1(length, function(t, l) {
					return oThis.ReadExternalBook(t, l, externalBook);
				});
				this.oWorkbook.externalReferences.push(externalBook);
			} else if (c_oSerWorkbookTypes.OleLink == type) {
				this.oWorkbook.externalReferences.push({Type: 1, Buffer: this.stream.GetBuffer(length)});
			} else if (c_oSerWorkbookTypes.DdeLink == type) {
				this.oWorkbook.externalReferences.push({Type: 2, Buffer: this.stream.GetBuffer(length)});
			} else {
				res = c_oSerConstants.ReadUnknown;
			}
			return res;
		};
		this.ReadExternalBook = function(type, length, externalBook) {
			var res = c_oSerConstants.ReadOk;
			var oThis = this;
			if (c_oSer_ExternalLinkTypes.Id == type) {
				externalBook.Id = this.stream.GetString2LE(length);
			} else if (c_oSer_ExternalLinkTypes.SheetNames == type) {
				res = this.bcr.Read1(length, function(t, l) {
					return oThis.ReadExternalSheetNames(t, l, externalBook.SheetNames);
				});
			} else if (c_oSer_ExternalLinkTypes.DefinedNames == type) {
				res = this.bcr.Read1(length, function(t, l) {
					return oThis.ReadExternalDefinedNames(t, l, externalBook.DefinedNames);
				});
			} else if (c_oSer_ExternalLinkTypes.SheetDataSet == type) {
				res = this.bcr.Read1(length, function(t, l) {
					return oThis.ReadExternalSheetDataSet(t, l, externalBook.SheetDataSet);
				});
			} else {
				res = c_oSerConstants.ReadUnknown;
			}
			return res;
		};
		this.ReadExternalSheetNames = function(type, length, sheetNames) {
			var res = c_oSerConstants.ReadOk;
			var oThis = this;
			if (c_oSer_ExternalLinkTypes.SheetName == type) {
				sheetNames.push(this.stream.GetString2LE(length));
			} else {
				res = c_oSerConstants.ReadUnknown;
			}
			return res;
		};
		this.ReadExternalDefinedNames = function(type, length, definedNames) {
			var res = c_oSerConstants.ReadOk;
			var oThis = this;
			if (c_oSer_ExternalLinkTypes.DefinedName == type) {
				var definedName = {Name: null, RefersTo: null, SheetId: null};
				res = this.bcr.Read1(length, function(t, l) {
					return oThis.ReadExternalDefinedName(t, l, definedName);
				});
				definedNames.push(definedName);
			} else {
				res = c_oSerConstants.ReadUnknown;
			}
			return res;
		};
		this.ReadExternalDefinedName = function(type, length, definedName) {
			var res = c_oSerConstants.ReadOk;
			var oThis = this;
			if (c_oSer_ExternalLinkTypes.DefinedNameName == type) {
				definedName.Name = this.stream.GetString2LE(length);
			} else if (c_oSer_ExternalLinkTypes.DefinedNameRefersTo == type) {
				definedName.RefersTo = this.stream.GetString2LE(length);
			} else if (c_oSer_ExternalLinkTypes.DefinedNameSheetId == type) {
				definedName.SheetId = this.stream.GetULongLE();
			} else {
				res = c_oSerConstants.ReadUnknown;
			}
			return res;
		};
		this.ReadExternalSheetDataSet = function(type, length, sheetDataSet) {
			var res = c_oSerConstants.ReadOk;
			var oThis = this;
			if (c_oSer_ExternalLinkTypes.SheetData == type) {
				var sheetData = {SheetId: null, RefreshError: null, Row: []};
				res = this.bcr.Read1(length, function(t, l) {
					return oThis.ReadExternalSheetData(t, l, sheetData);
				});
				sheetDataSet.push(sheetData);
			} else {
				res = c_oSerConstants.ReadUnknown;
			}
			return res;
		};
		this.ReadExternalSheetData = function(type, length, sheetData) {
			var res = c_oSerConstants.ReadOk;
			var oThis = this;
			if (c_oSer_ExternalLinkTypes.SheetDataSheetId == type) {
				sheetData.SheetId = this.stream.GetULongLE();
			} else if (c_oSer_ExternalLinkTypes.SheetDataRefreshError == type) {
				sheetData.RefreshError = this.stream.GetBool();
			} else if (c_oSer_ExternalLinkTypes.SheetDataRow == type) {
				var row = {R: null, Cell: []};
				res = this.bcr.Read1(length, function(t, l) {
					return oThis.ReadExternalRow(t, l, row);
				});
				sheetData.Row.push(row);
			} else {
				res = c_oSerConstants.ReadUnknown;
			}
			return res;
		};
		this.ReadExternalRow = function(type, length, row) {
			var res = c_oSerConstants.ReadOk;
			var oThis = this;
			if (c_oSer_ExternalLinkTypes.SheetDataRowR == type) {
				row.R = this.stream.GetULongLE();
			} else if (c_oSer_ExternalLinkTypes.SheetDataRowCell == type) {
				var cell = {Ref: null, CellType: null, CellValue: null};
				res = this.bcr.Read1(length, function(t, l) {
					return oThis.ReadExternalCell(t, l, cell);
				});
				row.Cell.push(cell);
			} else {
				res = c_oSerConstants.ReadUnknown;
			}
			return res;
		};
		this.ReadExternalCell = function(type, length, cell) {
			var res = c_oSerConstants.ReadOk;
			var oThis = this;
			if (c_oSer_ExternalLinkTypes.SheetDataRowCellRef == type) {
				cell.Ref = this.stream.GetString2LE(length);
			} else if (c_oSer_ExternalLinkTypes.SheetDataRowCellType == type) {
				cell.CellType = this.stream.GetUChar();
			} else if (c_oSer_ExternalLinkTypes.SheetDataRowCellValue == type) {
				cell.CellValue = this.stream.GetString2LE(length);
			} else {
				res = c_oSerConstants.ReadUnknown;
			}
			return res;
		};
    }
    /** @constructor */
    function Binary_WorksheetTableReader(stream, oReadResult, wb, aSharedStrings, aCellXfs, Dxfs, oMediaArray, copyPasteObj)
    {
        this.stream = stream;
        this.wb = wb;
        this.aSharedStrings = aSharedStrings;
        this.oMediaArray = oMediaArray;
        this.aCellXfs = aCellXfs;
        this.Dxfs = Dxfs;
        this.bcr = new Binary_CommonReader(this.stream);
        this.aMerged = [];
        this.aHyperlinks = [];
        this.copyPasteObj = copyPasteObj;
        this.curWorksheet = null;
        this.oReadResult = oReadResult;
        this.Read = function()
        {
            var oThis = this;
            return this.bcr.ReadTable(function(t, l){
                return oThis.ReadWorksheetsContent(t,l);
            });
        };
		this.ReadSheetDataExternal = function(bNoBuildDep)
		{
			//console.profile('ReadSheetDataExternal');
			var oThis = this;
			var res = c_oSerConstants.ReadOk;
			var oldPos = this.stream.GetCurPos();
			for (var i = 0; i < this.oReadResult.sheetData.length; ++i) {
				var sheetDataElem = this.oReadResult.sheetData[i];
				var ws = sheetDataElem.ws;
				this.stream.Seek2(sheetDataElem.pos);
				var tmp = {
					pos: null, len: null, bNoBuildDep: bNoBuildDep, ws: ws, row: new AscCommonExcel.Row(ws),
					cell: new AscCommonExcel.Cell(ws), formula: new OpenFormula(), sharedFormulas: {},
					prevFormulas: {}, siFormulas: {}, prevRow: -1, prevCol: -1
				};
				res = this.bcr.Read1(sheetDataElem.len, function(t, l) {
					return oThis.ReadSheetData(t, l, tmp);
				});
				if (!bNoBuildDep) {
					for (var nCol in tmp.prevFormulas) {
						if (tmp.prevFormulas.hasOwnProperty(nCol)) {
							var prevFormula = tmp.prevFormulas[nCol];
							if (!tmp.siFormulas[prevFormula.parsed.getListenerId()]) {
								prevFormula.parsed.buildDependencies();
							}
						}
					}
					for (var listenerId in tmp.siFormulas) {
						if (tmp.siFormulas.hasOwnProperty(listenerId)) {
							tmp.siFormulas[listenerId].buildDependencies();
						}
					}
				}
				if(c_oSerConstants.ReadOk !== res)
					break;
			}
			this.stream.Seek2(oldPos);
			//console.profileEnd();
			return res;
		};
        this.ReadWorksheetsContent = function(type, length)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerWorksheetsTypes.Worksheet === type )
            {
                this.aMerged = [];
                this.aHyperlinks = [];
                var oNewWorksheet = new AscCommonExcel.Worksheet(this.wb, wb.aWorksheets.length);
                oNewWorksheet.aFormulaExt = [];
				
				//TODO при copy/paste в word из excel необходимо подменить DrawingDocument из word - пересмотреть правку!
				if(typeof editor != "undefined" && editor && editor.WordControl && editor.WordControl.m_oLogicDocument && editor.WordControl.m_oLogicDocument.DrawingDocument)
					oNewWorksheet.DrawingDocument = editor.WordControl.m_oLogicDocument.DrawingDocument;
				else if(this.copyPasteObj && this.copyPasteObj.isCopyPaste)
				{
					oNewWorksheet.DrawingDocument = window["Asc"]["editor"].wbModel.getActiveWs().DrawingDocument;
				}
				
                this.curWorksheet = oNewWorksheet;
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadWorksheet(t,l, oNewWorksheet);
                });
                this.curWorksheet = null;
                //merged
                var i;
                for(i = 0, length = this.aMerged.length; i < length; ++i)
                {
                    var range = oNewWorksheet.getRange2(this.aMerged[i]);
                    if(null != range)
                        range.mergeOpen();
                }
                //hyperlinks
                for(i = 0, length = this.aHyperlinks.length; i < length; ++i)
                {
                    var hyperlink = this.aHyperlinks[i];
                    if (null !== hyperlink.Ref)
                        hyperlink.Ref.setHyperlinkOpen(hyperlink);
                }
                this.wb.aWorksheets.push(oNewWorksheet);
                this.wb.aWorksheetsById[oNewWorksheet.getId()] = oNewWorksheet;
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadWorksheet = function(type, length, oWorksheet)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            var oBinary_TableReader, oConditionalFormatting;
            if ( c_oSerWorksheetsTypes.WorksheetProp == type )
            {
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadWorksheetProp(t,l, oWorksheet);
                });
            }
            else if ( c_oSerWorksheetsTypes.Cols == type )
            {
                var aTempCols = [];
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadWorksheetCols(t,l, aTempCols, oWorksheet);
                });

                var fInitCol = function(oFrom, oTo)
                {
                    if(null != oFrom.BestFit)
                        oTo.BestFit = oFrom.BestFit;
                    oTo.setHidden(oFrom.hd);
                    if(null != oFrom.xfs)
                        oTo.setStyle(oFrom.xfs);
                    else if(null != oFrom.xfsid)
                    {
                        var xfs = oThis.aCellXfs[oFrom.xfsid];
                        if(null != xfs)
                        {
                            oFrom.xfs = xfs;
                            oTo.setStyle(xfs);
                        }
                    }
                    if(null != oFrom.width)
                        oTo.width = oFrom.width;
                    if(null != oFrom.CustomWidth)
                        oTo.CustomWidth = oFrom.CustomWidth;
                    if(oTo.index >= oWorksheet.nColsCount)
                        oWorksheet.nColsCount = oTo.index + 1;
                };
                //если есть стиль последней колонки, назначаем его стилем всей таблицы и убираем из колонок
                var oAllCol = null;
                if(aTempCols.length > 0)
                {
                    var oLast = aTempCols[aTempCols.length - 1];
                    if(AscCommon.gc_nMaxCol == oLast.Max)
                    {
                        oAllCol = oLast;
                        fInitCol(oAllCol, oWorksheet.getAllCol());
                    }
                }
                for(var i = 0, length = aTempCols.length; i < length; ++i)
                {
                    var elem = aTempCols[i];
                    if(null != oAllCol && elem.BestFit == oAllCol.BestFit && elem.hd == oAllCol.hd && elem.xfs == oAllCol.xfs && elem.width == oAllCol.width && elem.CustomWidth == oAllCol.CustomWidth)
                        continue;
                    if(null == elem.width)
                    {
                        elem.width = 0;
                        elem.hd = true;
                    }
                    for(var j = elem.Min; j <= elem.Max; j++){
                        var oNewCol = new AscCommonExcel.Col(oWorksheet, j - 1);
                        fInitCol(elem, oNewCol);
                        oWorksheet.aCols[oNewCol.index] = oNewCol;
                    }
                }
            }
            else if ( c_oSerWorksheetsTypes.SheetFormatPr == type )
            {
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadSheetFormatPr(t,l, oWorksheet);
                });
            }
            else if ( c_oSerWorksheetsTypes.PageMargins == type )
            {
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadPageMargins(t,l, oWorksheet.PagePrintOptions.pageMargins);
                });
            }
            else if ( c_oSerWorksheetsTypes.PageSetup == type )
            {
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadPageSetup(t,l, oWorksheet.PagePrintOptions.pageSetup);
                });
            }
            else if ( c_oSerWorksheetsTypes.PrintOptions == type )
            {
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadPrintOptions(t,l, oWorksheet.PagePrintOptions);
                });
            }
            else if ( c_oSerWorksheetsTypes.Hyperlinks == type )
            {
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadHyperlinks(t,l, oWorksheet);
                });
            }
            else if ( c_oSerWorksheetsTypes.MergeCells == type )
            {
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadMergeCells(t,l, oWorksheet);
                });
            }
            else if ( c_oSerWorksheetsTypes.SheetData == type )
            {
				this.oReadResult.sheetData.push({ws: oWorksheet, pos: this.stream.GetCurPos(), len: length});
				res = c_oSerConstants.ReadUnknown;
            }
            else if ( c_oSerWorksheetsTypes.Drawings == type )
            {
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadDrawings(t,l, oWorksheet.Drawings, oWorksheet);
                });
            }
            else if ( c_oSerWorksheetsTypes.Autofilter == type )
            {
                oBinary_TableReader = new Binary_TableReader(this.stream, this.oReadResult, oWorksheet, this.Dxfs);
                oWorksheet.AutoFilter = new AscCommonExcel.AutoFilter();
                res = this.bcr.Read1(length, function(t,l){
                    return oBinary_TableReader.ReadAutoFilter(t,l, oWorksheet.AutoFilter);
                });
            }
            else if ( c_oSerWorksheetsTypes.TableParts == type )
            {
                oBinary_TableReader = new Binary_TableReader(this.stream, this.oReadResult, oWorksheet, this.Dxfs);
                oBinary_TableReader.Read(length, oWorksheet.TableParts);
            } else if ( c_oSerWorksheetsTypes.Comments == type
                && !(typeof editor !== "undefined" && editor.WordControl && editor.WordControl.m_oLogicDocument && Array.isArray(editor.WordControl.m_oLogicDocument.Slides))) {
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadComments(t,l, oWorksheet);
                });
            } else if (c_oSerWorksheetsTypes.ConditionalFormatting === type && typeof AscCommonExcel.CConditionalFormatting != "undefined") {
                oConditionalFormatting = new AscCommonExcel.CConditionalFormatting();
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadConditionalFormatting(t, l, oConditionalFormatting);
                });
				if (oConditionalFormatting.isValid()) {
					oConditionalFormatting.initRules();
					oWorksheet.aConditionalFormattingRules =
						oWorksheet.aConditionalFormattingRules.concat(oConditionalFormatting.aRules);
				}
            } else if (c_oSerWorksheetsTypes.SheetViews === type) {
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadSheetViews(t, l, oWorksheet.sheetViews);
                });
            } else if (c_oSerWorksheetsTypes.SheetPr === type) {
                oWorksheet.sheetPr = new AscCommonExcel.asc_CSheetPr();
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadSheetPr(t, l, oWorksheet.sheetPr);
                });
			} else if (c_oSerWorksheetsTypes.SparklineGroups === type) {
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadSparklineGroups(t, l, oWorksheet);
                });
            } else if (c_oSerWorksheetsTypes.HeaderFooter === type) {
                oWorksheet.headerFooter = {
                    alignWithMargins: null, differentFirst: null, differentOddEven: null, scaleWithDoc: null,
                    evenFooter: null, evenHeader: null, firstFooter: null, firstHeader: null, oddFooter: null,
                    oddHeader: null
                };
                res = this.bcr.Read1(length, function(t, l) {
                    return oThis.ReadHeaderFooter(t, l, oWorksheet.headerFooter);
                });
            } else if (c_oSerWorksheetsTypes.RowBreaks === type) {
                oWorksheet.rowBreaks = {count: null, manualBreakCount: null, breaks: []};
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadRowColBreaks(t, l, oWorksheet.rowBreaks);
                });
            } else if (c_oSerWorksheetsTypes.ColBreaks === type) {
                oWorksheet.colBreaks = {count: null, manualBreakCount: null, breaks: []};
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadRowColBreaks(t, l, oWorksheet.colBreaks);
                });
            } else if (c_oSerWorksheetsTypes.LegacyDrawingHF === type) {
                oWorksheet.legacyDrawingHF = {
                    drawings: [], cfe: null, cff: null, cfo: null, che: null, chf: null, cho: null, lfe: null,
                    lff: null, lfo: null, lhe: null, lhf: null, lho: null, rfe: null, rff: null, rfo: null, rhe: null,
                    rhf: null, rho: null
                };
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadLegacyDrawingHF(t, l, oWorksheet.legacyDrawingHF);
                });
            } else if (c_oSerWorksheetsTypes.Picture === type) {
                oWorksheet.picture = this.stream.GetString2LE(length);
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadWorksheetProp = function(type, length, oWorksheet)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSerWorksheetPropTypes.Name == type )
                oWorksheet.sName = this.stream.GetString2LE(length);
            else if ( c_oSerWorksheetPropTypes.SheetId == type )
                oWorksheet.nSheetId = this.stream.GetULongLE();
            else if ( c_oSerWorksheetPropTypes.State == type )
            {
                switch(this.stream.GetUChar())
                {
                    case EVisibleType.visibleHidden: oWorksheet.bHidden = true;break;
                    case EVisibleType.visibleVeryHidden: oWorksheet.bHidden = true;break;
                    case EVisibleType.visibleVisible: oWorksheet.bHidden = false;break;
                }
            }
            else if(this.copyPasteObj.isCopyPaste && c_oSerWorksheetPropTypes.Ref == type)
                this.copyPasteObj.activeRange = this.stream.GetString2LE(length);
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadWorksheetCols = function(type, length, aTempCols, oWorksheet)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerWorksheetsTypes.Col == type )
            {
                var oTempCol = {BestFit: null, hd: null, Max: null, Min: null, xfs: null, xfsid: null, width: null, CustomWidth: null};
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadWorksheetCol(t,l, oTempCol);
                });
                aTempCols.push(oTempCol);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadWorksheetCol = function(type, length, oCol)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSerWorksheetColTypes.BestFit == type )
                oCol.BestFit = this.stream.GetBool();
            else if ( c_oSerWorksheetColTypes.Hidden == type )
                oCol.hd = this.stream.GetBool();
            else if ( c_oSerWorksheetColTypes.Max == type )
                oCol.Max = this.stream.GetULongLE();
            else if ( c_oSerWorksheetColTypes.Min == type )
                oCol.Min = this.stream.GetULongLE();
            else if ( c_oSerWorksheetColTypes.Style == type )
                oCol.xfsid = this.stream.GetULongLE();
            else if ( c_oSerWorksheetColTypes.Width == type )
            {
                oCol.width = this.stream.GetDoubleLE();
				if (oCol.width < 0) {
					oCol.width = 0;
				} else if (oCol.width > Asc.c_oAscMaxColumnWidth) {
					oCol.width = Asc.c_oAscMaxColumnWidth;
				}
                if(AscCommon.CurFileVersion < 2)
                    oCol.CustomWidth = 1;
            }
            else if ( c_oSerWorksheetColTypes.CustomWidth == type )
                oCol.CustomWidth = this.stream.GetBool();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadSheetFormatPr = function(type, length, oWorksheet)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSerSheetFormatPrTypes.DefaultColWidth == type )
                oWorksheet.oSheetFormatPr.dDefaultColWidth = this.stream.GetDoubleLE();
            else if (c_oSerSheetFormatPrTypes.BaseColWidth === type)
                oWorksheet.oSheetFormatPr.nBaseColWidth = this.stream.GetULongLE();
            else if ( c_oSerSheetFormatPrTypes.DefaultRowHeight == type )
            {
                var oAllRow = oWorksheet.getAllRow();
                oAllRow.setHeight(this.stream.GetDoubleLE());
            }
            else if ( c_oSerSheetFormatPrTypes.CustomHeight == type )
            {
                var oAllRow = oWorksheet.getAllRow();
				var CustomHeight = this.stream.GetBool();
				if(CustomHeight)
					oAllRow.setCustomHeight(true);
            }
            else if ( c_oSerSheetFormatPrTypes.ZeroHeight == type )
            {
                var oAllRow = oWorksheet.getAllRow();
				var hd = this.stream.GetBool();
				if(hd)
					oAllRow.setHidden(true);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadPageMargins = function(type, length, oPageMargins)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_PageMargins.Left == type )
                oPageMargins.asc_setLeft(this.stream.GetDoubleLE());
            else if ( c_oSer_PageMargins.Top == type )
                oPageMargins.asc_setTop(this.stream.GetDoubleLE());
            else if ( c_oSer_PageMargins.Right == type )
                oPageMargins.asc_setRight(this.stream.GetDoubleLE());
            else if ( c_oSer_PageMargins.Bottom == type )
                oPageMargins.asc_setBottom(this.stream.GetDoubleLE());
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadPageSetup = function(type, length, oPageSetup)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_PageSetup.Orientation == type )
            {
                var byteFormatOrientation = this.stream.GetUChar();
                var byteOrientation = null;
                switch(byteFormatOrientation)
                {
                    case EPageOrientation.pageorientPortrait: byteOrientation = c_oAscPageOrientation.PagePortrait;break;
                    case EPageOrientation.pageorientLandscape: byteOrientation = c_oAscPageOrientation.PageLandscape;break;
                }
                if(null != byteOrientation)
                    oPageSetup.asc_setOrientation(byteOrientation);
            }
            else if ( c_oSer_PageSetup.PaperSize == type )
            {
                var bytePaperSize = this.stream.GetUChar();
                var item = DocumentPageSize.getSizeById(bytePaperSize);
                oPageSetup.asc_setWidth(item.w_mm);
                oPageSetup.asc_setHeight(item.h_mm);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadPrintOptions = function(type, length, oPrintOptions)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_PrintOptions.GridLines == type )
                oPrintOptions.asc_setGridLines(this.stream.GetBool());
            else if ( c_oSer_PrintOptions.Headings == type )
                oPrintOptions.asc_setHeadings(this.stream.GetBool());
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadHyperlinks = function(type, length, ws)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerWorksheetsTypes.Hyperlink == type )
            {
                var oNewHyperlink = new AscCommonExcel.Hyperlink();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadHyperlink(t,l, ws, oNewHyperlink);
                });
                this.aHyperlinks.push(oNewHyperlink);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadHyperlink = function(type, length, ws, oHyperlink)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSerHyperlinkTypes.Ref == type )
                oHyperlink.Ref = ws.getRange2(this.stream.GetString2LE(length));
            else if ( c_oSerHyperlinkTypes.Hyperlink == type )
                oHyperlink.Hyperlink = this.stream.GetString2LE(length);
            else if ( c_oSerHyperlinkTypes.Location == type )
                oHyperlink.setLocation(this.stream.GetString2LE(length));
            else if ( c_oSerHyperlinkTypes.Tooltip == type )
                oHyperlink.Tooltip = this.stream.GetString2LE(length);
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadMergeCells = function(type, length)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSerWorksheetsTypes.MergeCell == type )
            {
                this.aMerged.push(this.stream.GetString2LE(length));
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadSheetData = function(type, length, tmp)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerWorksheetsTypes.Row === type )
            {
				tmp.pos =  null;
				tmp.len = null;
				tmp.row.clear();
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadRow(t,l, tmp);
                });
				if(null === tmp.row.index) {
					tmp.row.index = tmp.prevRow + 1;
				}
				tmp.row.saveContent();
				if(tmp.row.index >= tmp.ws.nRowsCount)
                    tmp.ws.nRowsCount = tmp.row.index + 1;
				tmp.prevRow = tmp.row.index;
				tmp.prevCol = -1;
				//читаем ячейки
				if (null !== tmp.pos && null !== tmp.len) {
					var nOldPos = this.stream.GetCurPos();
					this.stream.Seek2(tmp.pos);
					res = this.bcr.Read1(tmp.len, function(t,l){
						return oThis.ReadCells(t,l, tmp, tmp.row.index);
					});
					this.stream.Seek2(nOldPos);
				}
			}
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadRow = function(type, length, tmp)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerRowTypes.Row == type )
            {
            	var index = this.stream.GetULongLE() - 1;
				tmp.row.setIndex(index);
            }
            else if ( c_oSerRowTypes.Style == type )
            {
                var xfs = this.aCellXfs[this.stream.GetULongLE()];
                if(xfs)
					tmp.row.setStyle(xfs);
            }
            else if ( c_oSerRowTypes.Height == type )
            {
            	var h = this.stream.GetDoubleLE();
				tmp.row.setHeight(h);
                if(AscCommon.CurFileVersion < 2)
					tmp.row.setCustomHeight(true);
            }
            else if ( c_oSerRowTypes.CustomHeight == type )
			{
				var CustomHeight = this.stream.GetBool();
				if(CustomHeight)
					tmp.row.setCustomHeight(true);
			}
            else if ( c_oSerRowTypes.Hidden == type )
			{
				var hd = this.stream.GetBool();
				if(hd)
					tmp.row.setHidden(true);
			}
            else if ( c_oSerRowTypes.Cells == type )
            {
				//запоминам место чтобы читать Cells в конце, когда уже зачитан oRow.index
				tmp.pos = this.stream.GetCurPos();
				tmp.len = length;
				res = c_oSerConstants.ReadUnknown;
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadCells = function(type, length, tmp, index)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerRowTypes.Cell === type )
            {
				tmp.cell.clear();
                tmp.formula.clean();
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadCell(t,l, tmp, tmp.cell, tmp.prevRow);
                });
                if (tmp.cell.hasRowCol()) {
                    tmp.prevCol = tmp.cell.nCol;
                } else {
                    tmp.prevCol++;
                    tmp.cell.setRowCol(tmp.prevRow, tmp.prevCol);
                }
				//use only excel
				if(!(this.copyPasteObj && this.copyPasteObj.isCopyPaste && typeof editor != "undefined" && editor)) {
					this.setFormulaOpen(tmp);
				}
				tmp.cell.saveContent();
                if (tmp.cell.nCol >= tmp.ws.nColsCount) {
                    tmp.ws.nColsCount = tmp.cell.nCol + 1;
                }
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
		this.setFormulaOpen = function(tmp) {
			var cell = tmp.cell;
			var formula = tmp.formula;
			var curFormula;
			var prevFormula = tmp.prevFormulas[cell.nCol];
			if (null !== formula.si && (curFormula = tmp.sharedFormulas[formula.si])) {
				curFormula.parsed.getShared().ref.union3(cell.nCol, cell.nRow);
				if (prevFormula !== curFormula) {
					if (prevFormula && !tmp.bNoBuildDep && !tmp.siFormulas[prevFormula.parsed.getListenerId()]) {
						prevFormula.parsed.buildDependencies();
					}
					tmp.prevFormulas[cell.nCol] = curFormula;
				}
			} else if (formula.v && formula.v.length <= AscCommon.c_oAscMaxFormulaLength) {
				var offsetRow;
				var shared;
				var sharedRef;
				if (prevFormula && (shared = prevFormula.parsed.getShared())) {
					offsetRow = cell.nRow - shared.ref.r1;
				} else {
					offsetRow = 1;
				}
				if (prevFormula && prevFormula.nRow + offsetRow === cell.nRow &&
					AscCommonExcel.compareFormula(prevFormula.formula, prevFormula.refPos, formula.v, offsetRow)) {
					if (!(shared && shared.ref)) {
					    sharedRef = new Asc.Range(cell.nCol, prevFormula.nRow, cell.nCol, cell.nRow);
						prevFormula.parsed.setShared(sharedRef, prevFormula.base);
					} else {
						shared.ref.union3(cell.nCol, cell.nRow);
					}
					curFormula = prevFormula;
				} else {
					if (prevFormula && !tmp.bNoBuildDep && !tmp.siFormulas[prevFormula.parsed.getListenerId()]) {
						prevFormula.parsed.buildDependencies();
					}
					var parseResult = new AscCommonExcel.ParseResult([]);
					var newFormulaParent = new AscCommonExcel.CCellWithFormula(cell.ws, cell.nRow, cell.nCol);
					var parsed = new AscCommonExcel.parserFormula(formula.v, newFormulaParent, cell.ws);
					parsed.ca = formula.ca;
					parsed.parse(undefined, undefined, parseResult);
					if (null !== formula.ref) {
						if(formula.t === ECellFormulaType.cellformulatypeShared) {
							sharedRef = AscCommonExcel.g_oRangeCache.getAscRange(formula.ref).clone();
							parsed.setShared(sharedRef, newFormulaParent);
						}
					}
					curFormula = new OpenColumnFormula(cell.nRow, formula.v, parsed, parseResult.refPos, newFormulaParent);
					tmp.prevFormulas[cell.nCol] = curFormula;
				}
				if (null !== formula.si && curFormula.parsed.getShared()) {
					tmp.sharedFormulas[formula.si] = curFormula;
					tmp.siFormulas[curFormula.parsed.getListenerId()] = curFormula.parsed;
				}
			}
			if (curFormula) {
				cell.setFormulaInternal(curFormula.parsed);
				//TODO в версии 5.1.5 при открытии ячейки с формулой и пустым текстом попадали в changedCell по условию !cell.getValueWithoutFormat()
				//TODO добавляю данное условие для правки бага. до выпуска обязательно пересмотреть!!!
				if (curFormula.parsed.ca || cell.isNullTextString() || !cell.getValueWithoutFormat()) {
					tmp.ws.workbook.dependencyFormulas.addToChangedCell(cell);
				}
			}
		};
        this.ReadCell = function(type, length, tmp, oCell, nRowIndex)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerCellTypes.Ref === type ){
				var oCellAddress = AscCommon.g_oCellAddressUtils.getCellAddress(this.stream.GetString2LE(length));
				oCell.setRowCol(nRowIndex, oCellAddress.getCol0());
			}
            else if ( c_oSerCellTypes.RefRowCol === type ){
				var nRow = this.stream.GetULongLE();//todo не используем можно убрать
				oCell.setRowCol(nRowIndex, this.stream.GetULongLE());
			}
            else if( c_oSerCellTypes.Style === type )
            {
                var nStyleIndex = this.stream.GetULongLE();
                if(0 != nStyleIndex)
                {
                    var xfs = this.aCellXfs[nStyleIndex];
                    if(null != xfs)
                        oCell.setStyle(xfs);
                }
            }
            else if( c_oSerCellTypes.Type === type )
            {
                switch(this.stream.GetUChar())
                {
                    case ECellTypeType.celltypeBool: oCell.setTypeInternal(CellValueType.Bool);break;
                    case ECellTypeType.celltypeError: oCell.setTypeInternal(CellValueType.Error);break;
                    case ECellTypeType.celltypeNumber: oCell.setTypeInternal(CellValueType.Number);break;
                    case ECellTypeType.celltypeSharedString: oCell.setTypeInternal(CellValueType.String);break;
                }
            }
            else if( c_oSerCellTypes.Formula === type )
            {
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadFormula(t,l, tmp.formula);
                });
            }
			else if (c_oSerCellTypes.Value === type) {
				var val = this.stream.GetDoubleLE();
				if (CellValueType.String === oCell.getType() || CellValueType.Error === oCell.getType()) {
					var ss = this.aSharedStrings[val];
                    if (typeof ss === 'string') {
                        oCell.setValueTextInternal(ss);
                    } else {
                        oCell.setValueMultiTextInternal(ss);
                    }
				} else {
                    oCell.setValueNumberInternal(val);
				}
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadFormula = function(type, length, oFormula)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSerFormulaTypes.Aca === type )
                oFormula.aca = this.stream.GetBool();
            else if ( c_oSerFormulaTypes.Bx === type )
                oFormula.bx = this.stream.GetBool();
            else if ( c_oSerFormulaTypes.Ca === type )
                oFormula.ca = this.stream.GetBool();
            else if ( c_oSerFormulaTypes.Del1 === type )
                oFormula.del1 = this.stream.GetBool();
            else if ( c_oSerFormulaTypes.Del2 === type )
                oFormula.del2 = this.stream.GetBool();
            else if ( c_oSerFormulaTypes.Dt2D === type )
                oFormula.dt2d = this.stream.GetBool();
            else if ( c_oSerFormulaTypes.Dtr === type )
                oFormula.dtr = this.stream.GetBool();
            else if ( c_oSerFormulaTypes.R1 === type )
                oFormula.r1 = this.stream.GetString2LE(length);
            else if ( c_oSerFormulaTypes.R2 === type )
                oFormula.r2 = this.stream.GetString2LE(length);
            else if ( c_oSerFormulaTypes.Ref === type )
                oFormula.ref = this.stream.GetString2LE(length);
            else if ( c_oSerFormulaTypes.Si === type )
                oFormula.si = this.stream.GetULongLE();
            else if ( c_oSerFormulaTypes.T === type )
                oFormula.t = this.stream.GetUChar();
            else if ( c_oSerFormulaTypes.Text === type )
                oFormula.v = this.stream.GetString2LE(length);
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadDrawings = function(type, length, aDrawings, ws)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerWorksheetsTypes.Drawing == type )
            {
                var objectRender = new AscFormat.DrawingObjects();
                var oFlags = {from: false, to: false, pos: false, ext: false};
                var oNewDrawing = objectRender.createDrawingObject();
                res = this.bcr.Read1(length, function(t, l) {
                    return oThis.ReadDrawing(t, l, oNewDrawing, oFlags);
                });
                if(null != oNewDrawing.graphicObject)
                {
                    if(false != oFlags.from && false != oFlags.to)
                        oNewDrawing.Type = c_oAscCellAnchorType.cellanchorTwoCell;
                    else if(false != oFlags.from && false != oFlags.ext)
                        oNewDrawing.Type = c_oAscCellAnchorType.cellanchorOneCell;
                    else if(false != oFlags.pos && false != oFlags.ext)
                        oNewDrawing.Type = c_oAscCellAnchorType.cellanchorAbsolute;
                    if(oNewDrawing.graphicObject)
                    {
						//TODO при copy/paste в word из excel пропадает метод setWorksheet
						if(typeof oNewDrawing.graphicObject.setWorksheet != "undefined")
							oNewDrawing.graphicObject.setWorksheet(ws);
                    }
                    if(!oNewDrawing.graphicObject.spPr)
                    {
                        oNewDrawing.graphicObject.setSpPr(new AscFormat.CSpPr());
                        oNewDrawing.graphicObject.spPr.setParent(oNewDrawing.graphicObject);
                    }
                    if(!oNewDrawing.graphicObject.spPr.xfrm)
                    {
                        oNewDrawing.graphicObject.spPr.setXfrm(new AscFormat.CXfrm());
                        oNewDrawing.graphicObject.spPr.xfrm.setParent(oNewDrawing.graphicObject.spPr);
                        oNewDrawing.graphicObject.spPr.xfrm.setOffX(0);
                        oNewDrawing.graphicObject.spPr.xfrm.setOffY(0);
                        oNewDrawing.graphicObject.spPr.xfrm.setExtX(0);
                        oNewDrawing.graphicObject.spPr.xfrm.setExtY(0);
                    }
                    if(oNewDrawing.graphicObject.setBFromSerialize)
                    {
                        oNewDrawing.graphicObject.setBFromSerialize(true);
                    }
                    oNewDrawing.graphicObject.fromSerialize = true;
                    aDrawings.push(oNewDrawing);
                }
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadDrawing = function(type, length, oDrawing, oFlags)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_DrawingType.Type == type )
                oDrawing.Type = this.stream.GetUChar();
            else if ( c_oSer_DrawingType.From == type )
            {
                oFlags.from = true;
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadFromTo(t,l, oDrawing.from);
                });
            }
            else if ( c_oSer_DrawingType.To == type )
            {
                oFlags.to = true;
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadFromTo(t,l, oDrawing.to);
                });
            }
            else if ( c_oSer_DrawingType.Pos == type )
            {
                oFlags.pos = true;
                if(null == oDrawing.Pos)
                    oDrawing.Pos = {};
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadPos(t,l, oDrawing.Pos);
                });
            }
            else if ( c_oSer_DrawingType.Ext == type )
            {
                oFlags.ext = true;
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadExt(t,l, oDrawing.ext);
                });
            }
            else if ( c_oSer_DrawingType.Pic == type )
            {
                oDrawing.image = new Image();
                res = this.bcr.Read1(length, function(t,l){
                    //return oThis.ReadPic(t,l, oDrawing.Pic);
                    return oThis.ReadPic(t,l, oDrawing);
                });
            }
            /** proprietary begin **/
            else if ( c_oSer_DrawingType.GraphicFrame == type )
            {
                //todo удалить
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadGraphicFrame(t, l, oDrawing);
                });
            }
            /** proprietary end **/
            else if ( c_oSer_DrawingType.pptxDrawing == type )
            {
               // res = c_oSerConstants.ReadUnknown;
                var graphicObject = this.ReadPptxDrawing();
                if (graphicObject) {
                    oDrawing.graphicObject = graphicObject;
                    //TODO при copy/paste в word из excel пропадает метод setDrawingBase
                    if(typeof graphicObject.setDrawingBase != "undefined")
                        graphicObject.setDrawingBase(oDrawing);
                }
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadPptxDrawing = function () {
            var graphicObject;
            var oGraphicObject = pptx_content_loader.ReadGraphicObject(this.stream, this.curWorksheet);
            if(null != oGraphicObject
                && !((oGraphicObject.getObjectType() === AscDFH.historyitem_type_Shape || oGraphicObject.getObjectType() === AscDFH.historyitem_type_ImageShape) && !oGraphicObject.spPr)
                && !AscCommon.IsHiddenObj(oGraphicObject))
            {
                graphicObject = oGraphicObject;
            }
            return graphicObject;
        };
        this.ReadGraphicFrame = function (type, length, oDrawing) {
            var res = c_oSerConstants.ReadOk;
            if (c_oSer_DrawingType.Chart2 == type) {
                var oNewChartSpace = new AscFormat.CChartSpace();
                var oBinaryChartReader = new AscCommon.BinaryChartReader(this.stream);
                res = oBinaryChartReader.ExternalReadCT_ChartSpace(length, oNewChartSpace, this.curWorksheet);
                oDrawing.graphicObject = oNewChartSpace;
                oNewChartSpace.setBDeleted(false);
                if(oNewChartSpace.setDrawingBase)
                {
                    oNewChartSpace.setDrawingBase(oDrawing);
                }
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadFromTo = function(type, length, oFromTo)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_DrawingFromToType.Col == type )
            //oFromTo.Col = this.stream.GetULongLE();
                oFromTo.col = this.stream.GetULongLE();
            else if ( c_oSer_DrawingFromToType.ColOff == type )
            //oFromTo.ColOff = this.stream.GetDoubleLE();
                oFromTo.colOff = this.stream.GetDoubleLE();
            else if ( c_oSer_DrawingFromToType.Row == type )
            //oFromTo.Row = this.stream.GetULongLE();
                oFromTo.row = this.stream.GetULongLE();
            else if ( c_oSer_DrawingFromToType.RowOff == type )
            //oFromTo.RowOff = this.stream.GetDoubleLE();
                oFromTo.rowOff = this.stream.GetDoubleLE();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadPos = function(type, length, oPos)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_DrawingPosType.X == type )
                oPos.X = this.stream.GetDoubleLE();
            else if ( c_oSer_DrawingPosType.Y == type )
                oPos.Y = this.stream.GetDoubleLE();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadExt = function(type, length, oExt)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_DrawingExtType.Cx == type )
                oExt.cx = this.stream.GetDoubleLE();
            else if ( c_oSer_DrawingExtType.Cy == type )
                oExt.cy = this.stream.GetDoubleLE();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadPic = function(type, length, oDrawing)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_DrawingType.PicSrc == type )
            {
                var nIndex = this.stream.GetULongLE();
                var src = this.oMediaArray[nIndex];
                if(null != src)
                {
                  oDrawing.image.src = src;
                  oDrawing.imageUrl = src;
                }
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadComments = function(type, length, oWorksheet)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSerWorksheetsTypes.Comment == type && AscCommonExcel.asc_CCommentCoords)
            {
                var oCommentCoords = new AscCommonExcel.asc_CCommentCoords();
                var aCommentData = [];
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadComment(t,l, oCommentCoords, aCommentData);
                });
                if (oCommentCoords.isValid()) {
                    var i;
                    for(i = 0, length = aCommentData.length; i < length; ++i)
                    {
                        aCommentData[i].coords = oCommentCoords;

                        var elem = aCommentData[i];
                        elem.asc_putRow(oCommentCoords.nRow);
                        elem.asc_putCol(oCommentCoords.nCol);

                        if (elem.asc_getDocumentFlag()) {
                            this.wb.aComments.push(elem);
                        } else {
                            oWorksheet.aComments.push(elem);
                        }
                    }
                }
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadComment = function(type, length, oCommentCoords, aCommentData)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_Comments.Row == type )
                oCommentCoords.nRow = this.stream.GetULongLE();
            else if ( c_oSer_Comments.Col == type )
                oCommentCoords.nCol = this.stream.GetULongLE();
            else if ( c_oSer_Comments.CommentDatas == type )
            {
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadCommentDatas(t,l, aCommentData);
                });
            }
            else if ( c_oSer_Comments.Left == type )
                oCommentCoords.nLeft = this.stream.GetULongLE();
            else if ( c_oSer_Comments.LeftOffset == type )
                oCommentCoords.nLeftOffset = this.stream.GetULongLE();
            else if ( c_oSer_Comments.Top == type )
                oCommentCoords.nTop = this.stream.GetULongLE();
            else if ( c_oSer_Comments.TopOffset == type )
                oCommentCoords.nTopOffset = this.stream.GetULongLE();
            else if ( c_oSer_Comments.Right == type )
                oCommentCoords.nRight = this.stream.GetULongLE();
            else if ( c_oSer_Comments.RightOffset == type )
                oCommentCoords.nRightOffset = this.stream.GetULongLE();
            else if ( c_oSer_Comments.Bottom == type )
                oCommentCoords.nBottom = this.stream.GetULongLE();
            else if ( c_oSer_Comments.BottomOffset == type )
                oCommentCoords.nBottomOffset = this.stream.GetULongLE();
            else if ( c_oSer_Comments.LeftMM == type )
                oCommentCoords.dLeftMM = this.stream.GetDoubleLE();
            else if ( c_oSer_Comments.TopMM == type )
                oCommentCoords.dTopMM = this.stream.GetDoubleLE();
            else if ( c_oSer_Comments.WidthMM == type )
                oCommentCoords.dWidthMM = this.stream.GetDoubleLE();
            else if ( c_oSer_Comments.HeightMM == type )
                oCommentCoords.dHeightMM = this.stream.GetDoubleLE();
            else if ( c_oSer_Comments.MoveWithCells == type )
                oCommentCoords.bMoveWithCells = this.stream.GetBool();
            else if ( c_oSer_Comments.SizeWithCells == type )
                oCommentCoords.bSizeWithCells = this.stream.GetBool();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadCommentDatas = function(type, length, aCommentData)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_Comments.CommentData === type )
            {
                var oCommentData = new Asc.asc_CCommentData();
                oCommentData.asc_putDocumentFlag(false);
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadCommentData(t,l,oCommentData);
                });

				if (oCommentData.asc_getDocumentFlag()) {
					oCommentData.nId = "doc_" + (this.wb.aComments.length + 1);
				} else {
					oCommentData.wsId = this.curWorksheet.Id;
					oCommentData.nId = "sheet" + oCommentData.wsId + "_" + (this.curWorksheet.aComments.length + 1);
				}
                aCommentData.push(oCommentData);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadCommentData = function(type, length, oCommentData)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_CommentData.Text == type )
                oCommentData.asc_putText(this.stream.GetString2LE(length));
            else if ( c_oSer_CommentData.Time == type )
            {
                var oDate = this.Iso8601ToDate(this.stream.GetString2LE(length));
                if(null != oDate)
                    oCommentData.asc_putTime(oDate.getTime() + "");
            }
            else if ( c_oSer_CommentData.OOTime == type )
            {
                var oDate = this.Iso8601ToDate(this.stream.GetString2LE(length));
                if(null != oDate)
                    oCommentData.asc_putOnlyOfficeTime(oDate.getTime() + "");
            }
            else if ( c_oSer_CommentData.UserId == type )
                oCommentData.asc_putUserId(this.stream.GetString2LE(length));
            else if ( c_oSer_CommentData.UserName == type )
                oCommentData.asc_putUserName(this.stream.GetString2LE(length));
            else if ( c_oSer_CommentData.QuoteText == type )
                oCommentData.asc_putQuoteText(this.stream.GetString2LE(length));
            else if ( c_oSer_CommentData.Replies == type )
            {
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadReplies(t,l, oCommentData);
                });
            }
            else if ( c_oSer_CommentData.Solved == type )
                oCommentData.asc_putSolved(this.stream.GetBool());
            else if ( c_oSer_CommentData.Document == type )
                oCommentData.asc_putDocumentFlag(this.stream.GetBool());
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadConditionalFormatting = function (type, length, oConditionalFormatting) {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            var oConditionalFormattingRule = null;
            if (c_oSer_ConditionalFormatting.Pivot === type)
                oConditionalFormatting.pivot = this.stream.GetBool();
            else if (c_oSer_ConditionalFormatting.SqRef === type) {
                oConditionalFormatting.setSqref(this.stream.GetString2LE(length));
            }
            else if (c_oSer_ConditionalFormatting.ConditionalFormattingRule === type) {
                oConditionalFormattingRule = new AscCommonExcel.CConditionalFormattingRule();
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadConditionalFormattingRule(t, l, oConditionalFormattingRule);
                });
                oConditionalFormatting.aRules.push(oConditionalFormattingRule);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadConditionalFormattingRule = function (type, length, oConditionalFormattingRule) {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            var oConditionalFormattingRuleElement = null;

            if (c_oSer_ConditionalFormattingRule.AboveAverage === type)
                oConditionalFormattingRule.aboveAverage = this.stream.GetBool();
            else if (c_oSer_ConditionalFormattingRule.Bottom === type)
                oConditionalFormattingRule.bottom = this.stream.GetBool();
            else if (c_oSer_ConditionalFormattingRule.DxfId === type)
            {
                var DxfId = this.stream.GetULongLE();
                oConditionalFormattingRule.dxf = this.Dxfs[DxfId];
            }
            else if (c_oSer_ConditionalFormattingRule.EqualAverage === type)
                oConditionalFormattingRule.equalAverage = this.stream.GetBool();
            else if (c_oSer_ConditionalFormattingRule.Operator === type)
                oConditionalFormattingRule.operator = this.stream.GetUChar();
            else if (c_oSer_ConditionalFormattingRule.Percent === type)
                oConditionalFormattingRule.percent = this.stream.GetBool();
            else if (c_oSer_ConditionalFormattingRule.Priority === type)
                oConditionalFormattingRule.priority = this.stream.GetULongLE();
            else if (c_oSer_ConditionalFormattingRule.Rank === type)
                oConditionalFormattingRule.rank = this.stream.GetULongLE();
            else if (c_oSer_ConditionalFormattingRule.StdDev === type)
                oConditionalFormattingRule.stdDev = this.stream.GetULongLE();
            else if (c_oSer_ConditionalFormattingRule.StopIfTrue === type)
                oConditionalFormattingRule.stopIfTrue = this.stream.GetBool();
            else if (c_oSer_ConditionalFormattingRule.Text === type)
                oConditionalFormattingRule.text = this.stream.GetString2LE(length);
            else if (c_oSer_ConditionalFormattingRule.TimePeriod === type)
                oConditionalFormattingRule.timePeriod = this.stream.GetString2LE(length);
            else if (c_oSer_ConditionalFormattingRule.Type === type)
                oConditionalFormattingRule.type = this.stream.GetUChar();
            else if (c_oSer_ConditionalFormattingRule.ColorScale === type) {
                oConditionalFormattingRuleElement = new AscCommonExcel.CColorScale();
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadColorScale(t, l, oConditionalFormattingRuleElement);
                });
                oConditionalFormattingRule.aRuleElements.push(oConditionalFormattingRuleElement);
            } else if (c_oSer_ConditionalFormattingRule.DataBar === type) {
                oConditionalFormattingRuleElement = new AscCommonExcel.CDataBar();
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadDataBar(t, l, oConditionalFormattingRuleElement);
                });
                oConditionalFormattingRule.aRuleElements.push(oConditionalFormattingRuleElement);
            } else if (c_oSer_ConditionalFormattingRule.FormulaCF === type) {
                oConditionalFormattingRuleElement = new AscCommonExcel.CFormulaCF();
                oConditionalFormattingRuleElement.Text = this.stream.GetString2LE(length);
                oConditionalFormattingRule.aRuleElements.push(oConditionalFormattingRuleElement);
            } else if (c_oSer_ConditionalFormattingRule.IconSet === type) {
                oConditionalFormattingRuleElement = new AscCommonExcel.CIconSet();
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadIconSet(t, l, oConditionalFormattingRuleElement);
                });
                oConditionalFormattingRule.aRuleElements.push(oConditionalFormattingRuleElement);
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadColorScale = function (type, length, oColorScale) {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            var oObject = null;
            if (c_oSer_ConditionalFormattingRuleColorScale.CFVO === type) {
                oObject = new AscCommonExcel.CConditionalFormatValueObject();
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadCFVO(t, l, oObject);
                });
                oColorScale.aCFVOs.push(oObject);
            } else if (c_oSer_ConditionalFormattingRuleColorScale.Color === type) {
				var color = ReadColorSpreadsheet2(this.bcr, length);
				if (null != color) {
					oColorScale.aColors.push(color);
				}
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadDataBar = function (type, length, oDataBar) {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            var oObject = null;
            if (c_oSer_ConditionalFormattingDataBar.MaxLength === type)
                oDataBar.MaxLength = this.stream.GetULongLE();
            else if (c_oSer_ConditionalFormattingDataBar.MinLength === type)
                oDataBar.MinLength = this.stream.GetULongLE();
            else if (c_oSer_ConditionalFormattingDataBar.ShowValue === type)
                oDataBar.ShowValue = this.stream.GetBool();
            else if (c_oSer_ConditionalFormattingDataBar.Color === type) {
				var color = ReadColorSpreadsheet2(this.bcr, length);
				if (color) {
					oDataBar.Color = color;
				}
            } else if (c_oSer_ConditionalFormattingDataBar.CFVO === type) {
                oObject = new AscCommonExcel.CConditionalFormatValueObject();
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadCFVO(t, l, oObject);
                });
                oDataBar.aCFVOs.push(oObject);
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadIconSet = function (type, length, oIconSet) {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            var oObject = null;
            if (c_oSer_ConditionalFormattingIconSet.IconSet === type)
                oIconSet.IconSet = this.stream.GetUChar();
            else if (c_oSer_ConditionalFormattingIconSet.Percent === type)
                oIconSet.Percent = this.stream.GetBool();
            else if (c_oSer_ConditionalFormattingIconSet.Reverse === type)
                oIconSet.Reverse = this.stream.GetBool();
            else if (c_oSer_ConditionalFormattingIconSet.ShowValue === type)
                oIconSet.ShowValue = this.stream.GetBool();
            else if (c_oSer_ConditionalFormattingIconSet.CFVO === type) {
                oObject = new AscCommonExcel.CConditionalFormatValueObject();
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadCFVO(t, l, oObject);
                });
                oIconSet.aCFVOs.push(oObject);
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadCFVO = function (type, length, oCFVO) {
            var res = c_oSerConstants.ReadOk;
            if (c_oSer_ConditionalFormattingValueObject.Gte === type)
                oCFVO.Gte = this.stream.GetBool();
            else if (c_oSer_ConditionalFormattingValueObject.Type === type)
                oCFVO.Type = this.stream.GetUChar();
            else if (c_oSer_ConditionalFormattingValueObject.Val === type)
                oCFVO.Val = this.stream.GetString2LE(length);
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadSheetViews = function (type, length, aSheetViews) {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            var oSheetView = null;

            if (c_oSerWorksheetsTypes.SheetView === type && 0 == aSheetViews.length) {
                oSheetView = new AscCommonExcel.asc_CSheetViewSettings();
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadSheetView(t, l, oSheetView);
                });
                aSheetViews.push(oSheetView);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadSheetView = function (type, length, oSheetView) {
            var oThis = this;
            var res = c_oSerConstants.ReadOk;
			if (c_oSer_SheetView.ColorId === type) {
				this.stream.GetLong();
			} else if (c_oSer_SheetView.DefaultGridColor === type) {
				this.stream.GetBool();
			} else if (c_oSer_SheetView.RightToLeft === type) {
				this.stream.GetBool();
			} else if (c_oSer_SheetView.ShowFormulas === type) {
				this.stream.GetBool();
			} else if (c_oSer_SheetView.ShowGridLines === type) {
				oSheetView.showGridLines = this.stream.GetBool();
			} else if (c_oSer_SheetView.ShowOutlineSymbols === type) {
				this.stream.GetBool();
			} else if (c_oSer_SheetView.ShowRowColHeaders === type) {
				oSheetView.showRowColHeaders = this.stream.GetBool();
			} else if (c_oSer_SheetView.ShowRuler === type) {
				this.stream.GetBool();
			} else if (c_oSer_SheetView.ShowWhiteSpace === type) {
				this.stream.GetBool();
			} else if (c_oSer_SheetView.ShowZeros === type) {
				this.stream.GetBool();
			} else if (c_oSer_SheetView.TabSelected === type) {
				this.stream.GetBool();
			} else if (c_oSer_SheetView.TopLeftCell === type) {
				this.stream.GetString2LE(length);
			} else if (c_oSer_SheetView.View === type) {
				this.stream.GetUChar();
			} else if (c_oSer_SheetView.WindowProtection === type) {
				this.stream.GetBool();
			} else if (c_oSer_SheetView.WorkbookViewId === type) {
				this.stream.GetLong();
			} else if (c_oSer_SheetView.ZoomScale === type) {
				oSheetView.asc_setZoomScale(this.stream.GetLong());
			} else if (c_oSer_SheetView.ZoomScaleNormal === type) {
				this.stream.GetLong();
			} else if (c_oSer_SheetView.ZoomScalePageLayoutView === type) {
				this.stream.GetLong();
			} else if (c_oSer_SheetView.ZoomScaleSheetLayoutView === type) {
				this.stream.GetLong();
            } else if (c_oSer_SheetView.Pane === type) {
                oSheetView.pane = new AscCommonExcel.asc_CPane();
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadPane(t, l, oSheetView.pane);
                });
                oSheetView.pane.init();
			} else if (c_oSer_SheetView.Selection === type) {
				this.curWorksheet.selectionRange.clean();
				res = this.bcr.Read1(length, function (t, l) {
					return oThis.ReadSelection(t, l, oThis.curWorksheet.selectionRange);
				});
				this.curWorksheet.selectionRange.update();
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadPane = function (type, length, oPane) {
            var res = c_oSerConstants.ReadOk;
			if (c_oSer_Pane.ActivePane === type)
				this.stream.GetUChar();
			else if (c_oSer_Pane.State === type)
				oPane.state = this.stream.GetString2LE(length);
            else if (c_oSer_Pane.TopLeftCell === type)
				oPane.topLeftCell = this.stream.GetString2LE(length);
			else if (c_oSer_Pane.XSplit === type)
				oPane.xSplit = this.stream.GetDoubleLE();
			else if (c_oSer_Pane.YSplit === type)
				oPane.ySplit = this.stream.GetDoubleLE();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
		this.ReadSelection = function (type, length, selectionRange) {
			var res = c_oSerConstants.ReadOk;
			if (c_oSer_Selection.ActiveCell === type) {
				var activeCell = AscCommonExcel.g_oRangeCache.getAscRange(this.stream.GetString2LE(length));
				if (activeCell) {
					selectionRange.activeCell = new AscCommon.CellBase(activeCell.r1, activeCell.c1);
				}
			} else if (c_oSer_Selection.ActiveCellId === type) {
				selectionRange.activeCellId = this.stream.GetLong();
			} else if (c_oSer_Selection.Sqref === type) {
				var sqref = this.stream.GetString2LE(length);
				var selectionNew = AscCommonExcel.g_oRangeCache.getActiveRangesFromSqRef(sqref);
				if (selectionNew.length > 0) {
					selectionRange.ranges = selectionNew;
				}
			} else if (c_oSer_Selection.Pane === type) {
				this.stream.GetUChar();
			} else
				res = c_oSerConstants.ReadUnknown;
			return res;
		};
        this.ReadSheetPr = function (type, length, oSheetPr) {
            var oThis = this;
            var res = c_oSerConstants.ReadOk;
            if (c_oSer_SheetPr.CodeName === type)
                oSheetPr.CodeName = this.stream.GetString2LE(length);
            else if (c_oSer_SheetPr.EnableFormatConditionsCalculation === type)
                oSheetPr.EnableFormatConditionsCalculation = this.stream.GetBool();
            else if (c_oSer_SheetPr.FilterMode === type)
                oSheetPr.FilterMode = this.stream.GetBool();
            else if (c_oSer_SheetPr.Published === type)
                oSheetPr.Published = this.stream.GetBool();
            else if (c_oSer_SheetPr.SyncHorizontal === type)
                oSheetPr.SyncHorizontal = this.stream.GetBool();
            else if (c_oSer_SheetPr.SyncRef === type)
                oSheetPr.SyncRef = this.stream.GetString2LE(length);
            else if (c_oSer_SheetPr.SyncVertical === type)
                oSheetPr.SyncVertical = this.stream.GetBool();
            else if (c_oSer_SheetPr.TransitionEntry === type)
                oSheetPr.TransitionEntry = this.stream.GetBool();
            else if (c_oSer_SheetPr.TransitionEvaluation === type)
                oSheetPr.TransitionEvaluation = this.stream.GetBool();
            else if (c_oSer_SheetPr.TabColor === type) {
				var color = ReadColorSpreadsheet2(this.bcr, length);
				if (color) {
					oSheetPr.TabColor = color;
				}
            } else
                res = c_oSerConstants.ReadUnknown;

            return res;
        };
		this.ReadSparklineGroups = function (type, length, oWorksheet) {
            var oThis = this;
            var res = c_oSerConstants.ReadOk;
            if (c_oSer_Sparkline.SparklineGroup === type) {
				var newSparklineGroup = new AscCommonExcel.sparklineGroup(true);
                newSparklineGroup.setWorksheet(oWorksheet);
				res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadSparklineGroup(t, l, newSparklineGroup);
                });
                oWorksheet.aSparklineGroups.push(newSparklineGroup);
			} else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadHeaderFooter = function (type, length, headerFooter) {
            var res = c_oSerConstants.ReadOk;
            if (c_oSer_HeaderFooter.AlignWithMargins === type) {
                headerFooter.alignWithMargins = this.stream.GetBool();
            } else if (c_oSer_HeaderFooter.DifferentFirst === type) {
                headerFooter.differentFirst = this.stream.GetBool();
            } else if (c_oSer_HeaderFooter.DifferentOddEven === type) {
                headerFooter.differentOddEven = this.stream.GetBool();
            } else if (c_oSer_HeaderFooter.ScaleWithDoc === type) {
                headerFooter.scaleWithDoc = this.stream.GetBool();
            } else if (c_oSer_HeaderFooter.EvenFooter === type) {
                headerFooter.evenFooter = this.stream.GetString2LE(length);
            } else if (c_oSer_HeaderFooter.EvenHeader === type) {
                headerFooter.evenHeader = this.stream.GetString2LE(length);
            } else if (c_oSer_HeaderFooter.FirstFooter === type) {
                headerFooter.firstFooter = this.stream.GetString2LE(length);
            } else if (c_oSer_HeaderFooter.FirstHeader === type) {
                headerFooter.firstHeader = this.stream.GetString2LE(length);
            } else if (c_oSer_HeaderFooter.OddFooter === type) {
                headerFooter.oddFooter = this.stream.GetString2LE(length);
            } else if (c_oSer_HeaderFooter.OddHeader === type) {
                headerFooter.oddHeader = this.stream.GetString2LE(length);
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadRowColBreaks = function (type, length, breaks) {
            var oThis = this;
            var res = c_oSerConstants.ReadOk;
            if (c_oSer_RowColBreaks.Count === type) {
                breaks.count = this.stream.GetLong();
            } else if (c_oSer_RowColBreaks.ManualBreakCount === type) {
                breaks.manualBreakCount = this.stream.GetLong();
            } else if (c_oSer_RowColBreaks.Break === type) {
                var brk = {id: null, man: null, max: null, min: null, pt: null};
                res = this.bcr.Read1(length, function(t, l) {
                    return oThis.ReadRowColBreak(t, l, brk);
                });
                breaks.breaks.push(brk);
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadRowColBreak = function (type, length, brk) {
            var res = c_oSerConstants.ReadOk;
            if (c_oSer_RowColBreaks.Id === type) {
                brk.id = this.stream.GetLong();
            } else if (c_oSer_RowColBreaks.Man === type) {
                brk.man = this.stream.GetBool();
            } else if (c_oSer_RowColBreaks.Max === type) {
                brk.max = this.stream.GetLong();
            } else if (c_oSer_RowColBreaks.Min === type) {
                brk.min = this.stream.GetLong();
            } else if (c_oSer_RowColBreaks.Pt === type) {
                brk.pt = this.stream.GetBool();
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadLegacyDrawingHF = function (type, length, legacyDrawingHF) {
            var oThis = this;
            var res = c_oSerConstants.ReadOk;
            if (c_oSer_LegacyDrawingHF.Drawings === type) {
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadLegacyDrawingHFDrawings(t, l, legacyDrawingHF.drawings);
                });
            } else if (c_oSer_LegacyDrawingHF.Cfe === type) {
                legacyDrawingHF.cfe = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Cff === type) {
                legacyDrawingHF.cff = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Cfo === type) {
                legacyDrawingHF.cfo = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Che === type) {
                legacyDrawingHF.che = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Chf === type) {
                legacyDrawingHF.chf = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Cho === type) {
                legacyDrawingHF.cho = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Lfe === type) {
                legacyDrawingHF.lfe = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Lff === type) {
                legacyDrawingHF.lff = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Lfo === type) {
                legacyDrawingHF.lfo = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Lhe === type) {
                legacyDrawingHF.lhe = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Lhf === type) {
                legacyDrawingHF.lhf = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Lho === type) {
                legacyDrawingHF.lho = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Rfe === type) {
                legacyDrawingHF.rfe = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Rff === type) {
                legacyDrawingHF.rff = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Rfo === type) {
                legacyDrawingHF.rfo = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Rhe === type) {
                legacyDrawingHF.rhe = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Rhf === type) {
                legacyDrawingHF.rhf = this.stream.GetBool();
            } else if (c_oSer_LegacyDrawingHF.Rho === type) {
                legacyDrawingHF.rho = this.stream.GetBool();
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadLegacyDrawingHFDrawings = function (type, length, drawings) {
            var oThis = this;
            var res = c_oSerConstants.ReadOk;
            if (c_oSer_LegacyDrawingHF.Drawing === type) {
                var drawing = {id: null, graphicObject: null};
                res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadLegacyDrawingHFDrawing(t, l, drawing);
                });
                if (null !== drawing.id && null !== drawing.graphicObject) {
                    drawings.push(drawing);
                }
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadLegacyDrawingHFDrawing = function (type, length, drawing) {
            var oThis = this;
            var res = c_oSerConstants.ReadOk;
            if (c_oSer_LegacyDrawingHF.DrawingId === type) {
                drawing.id = this.stream.GetString2LE(length);
            } else if (c_oSer_LegacyDrawingHF.DrawingShape === type) {
                var graphicObject = this.ReadPptxDrawing();
                if (graphicObject) {
                    drawing.graphicObject = graphicObject;
                }
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
		this.ReadSparklineGroup = function (type, length, oSparklineGroup) {
            var oThis = this;
            var res = c_oSerConstants.ReadOk;
            if (c_oSer_Sparkline.ManualMax === type) {
				oSparklineGroup.manualMax = this.stream.GetDoubleLE();
			} else if (c_oSer_Sparkline.ManualMin === type) {
				oSparklineGroup.manualMin = this.stream.GetDoubleLE();
			} else if (c_oSer_Sparkline.LineWeight === type) {
				oSparklineGroup.lineWeight = this.stream.GetDoubleLE();
			} else if (c_oSer_Sparkline.Type === type) {
				oSparklineGroup.type = this.stream.GetUChar();
			} else if (c_oSer_Sparkline.DateAxis === type) {
				oSparklineGroup.dateAxis = this.stream.GetBool();
			} else if (c_oSer_Sparkline.DisplayEmptyCellsAs === type) {
				oSparklineGroup.displayEmptyCellsAs = this.stream.GetUChar();
			} else if (c_oSer_Sparkline.Markers === type) {
				oSparklineGroup.markers = this.stream.GetBool();
			} else if (c_oSer_Sparkline.High === type) {
				oSparklineGroup.high = this.stream.GetBool();
			} else if (c_oSer_Sparkline.Low === type) {
				oSparklineGroup.low = this.stream.GetBool();
			} else if (c_oSer_Sparkline.First === type) {
				oSparklineGroup.first = this.stream.GetBool();
			} else if (c_oSer_Sparkline.Last === type) {
				oSparklineGroup.last = this.stream.GetBool();
			} else if (c_oSer_Sparkline.Negative === type) {
				oSparklineGroup.negative = this.stream.GetBool();
			} else if (c_oSer_Sparkline.DisplayXAxis === type) {
				oSparklineGroup.displayXAxis = this.stream.GetBool();
			} else if (c_oSer_Sparkline.DisplayHidden === type) {
				oSparklineGroup.displayHidden = this.stream.GetBool();
			} else if (c_oSer_Sparkline.MinAxisType === type) {
				oSparklineGroup.minAxisType = this.stream.GetUChar();
			} else if (c_oSer_Sparkline.MaxAxisType === type) {
				oSparklineGroup.maxAxisType = this.stream.GetUChar();
			} else if (c_oSer_Sparkline.RightToLeft === type) {
				oSparklineGroup.rightToLeft = this.stream.GetBool();
			} else if (c_oSer_Sparkline.ColorSeries === type) {
				oSparklineGroup.colorSeries = ReadColorSpreadsheet2(this.bcr, length);
			} else if (c_oSer_Sparkline.ColorNegative === type) {
				oSparklineGroup.colorNegative = ReadColorSpreadsheet2(this.bcr, length);
			} else if (c_oSer_Sparkline.ColorAxis === type) {
				oSparklineGroup.colorAxis = ReadColorSpreadsheet2(this.bcr, length);
			} else if (c_oSer_Sparkline.ColorMarkers === type) {
				oSparklineGroup.colorMarkers = ReadColorSpreadsheet2(this.bcr, length);
			} else if (c_oSer_Sparkline.ColorFirst === type) {
				oSparklineGroup.colorFirst = ReadColorSpreadsheet2(this.bcr, length);
			} else if (c_oSer_Sparkline.ColorLast === type) {
				oSparklineGroup.colorLast = ReadColorSpreadsheet2(this.bcr, length);
			} else if (c_oSer_Sparkline.ColorHigh === type) {
				oSparklineGroup.colorHigh = ReadColorSpreadsheet2(this.bcr, length);
			} else if (c_oSer_Sparkline.ColorLow === type) {
				oSparklineGroup.colorLow = ReadColorSpreadsheet2(this.bcr, length);
			} else if (c_oSer_Sparkline.Ref === type) {
				oSparklineGroup.f = this.stream.GetString2LE(length);
			} else if (c_oSer_Sparkline.Sparklines === type) {
				res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadSparklines(t, l, oSparklineGroup);
                });
			} else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
		this.ReadSparklines = function (type, length, oSparklineGroup) {
            var oThis = this;
            var res = c_oSerConstants.ReadOk;
            if (c_oSer_Sparkline.Sparkline === type) {
				var newSparkline = new AscCommonExcel.sparkline();
				res = this.bcr.Read1(length, function (t, l) {
                    return oThis.ReadSparkline(t, l, newSparkline);
                });
				oSparklineGroup.arrSparklines.push(newSparkline);
			} else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
		this.ReadSparkline = function (type, length, oSparkline) {
            var res = c_oSerConstants.ReadOk;
            if (c_oSer_Sparkline.SparklineRef === type) {
				oSparkline.setF(this.stream.GetString2LE(length));
			} else if (c_oSer_Sparkline.SparklineSqRef === type) {
				oSparkline.setSqref(this.stream.GetString2LE(length));
			} else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.Iso8601ToDate = function(sDate)
        {
            var numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ];
            var minutesOffset = 0;
            var struct;
            if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(sDate))) {
                // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC
                for (var i = 0, k; (k = numericKeys[i]); ++i) {
                    struct[k] = +struct[k] || 0;
                }

                // allow undefined days and months
                struct[2] = (+struct[2] || 1) - 1;
                struct[3] = +struct[3] || 1;

                if (struct[8] !== 'Z' && struct[9] !== undefined) {
                    minutesOffset = struct[10] * 60 + struct[11];

                    if (struct[9] === '+') {
                        minutesOffset = 0 - minutesOffset;
                    }
                }

                return new Date(Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]));
            }
            return null;
        };
        this.ReadReplies = function(type, length, oCommentData)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_CommentData.Reply === type )
            {
                var oReplyData = new Asc.asc_CCommentData();
                oReplyData.asc_putDocumentFlag(false);
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadCommentData(t,l,oReplyData);
                });
                oCommentData.aReplies.push(oReplyData);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
    }
    /** @constructor */
    function Binary_CalcChainTableReader(stream, aCalcChain)
    {
        this.stream = stream;
        this.aCalcChain = aCalcChain;
        this.bcr = new Binary_CommonReader(this.stream);
        this.Read = function()
        {
            var oThis = this;
            return this.bcr.ReadTable(function(t, l){
                return oThis.ReadCalcChainContent(t,l);
            });
        };
        this.ReadCalcChainContent = function(type, length)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_CalcChainType.CalcChainItem === type )
            {
                var oNewCalcChain = {};
                res = this.bcr.Read2Spreadsheet(length, function(t,l){
                    return oThis.ReadCalcChain(t,l, oNewCalcChain);
                });
                this.aCalcChain.push(oNewCalcChain);
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadCalcChain = function(type, length, oCalcChain)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_CalcChainType.Array == type )
                oCalcChain.Array = this.stream.GetBool();
            else if ( c_oSer_CalcChainType.SheetId == type )
                oCalcChain.SheetId = this.stream.GetULongLE();
            else if ( c_oSer_CalcChainType.DependencyLevel == type )
                oCalcChain.DependencyLevel = this.stream.GetBool();
            else if ( c_oSer_CalcChainType.Ref == type )
                oCalcChain.Ref = this.stream.GetString2LE(length);
            else if ( c_oSer_CalcChainType.ChildChain == type )
                oCalcChain.ChildChain = this.stream.GetBool();
            else if ( c_oSer_CalcChainType.NewThread == type )
                oCalcChain.NewThread = this.stream.GetBool();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
    }
    /** @constructor */
    function Binary_OtherTableReader(stream, oMedia, wb)
    {
        this.stream = stream;
        this.oMedia = oMedia;
        this.wb = wb;
        this.bcr = new Binary_CommonReader(this.stream);
        this.Read = function()
        {
            var oThis = this;
            var oRes = this.bcr.ReadTable(function(t, l){
                return oThis.ReadOtherContent(t,l);
            });
            this.wb.clrSchemeMap = AscFormat.GenerateDefaultColorMap();
            if(null == this.wb.theme)
                this.wb.theme = AscFormat.GenerateDefaultTheme(this.wb, 'Calibri');

            Asc.getBinaryOtherTableGVar(this.wb);

            return oRes;
        };
        this.ReadOtherContent = function(type, length)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_OtherType.Media === type )
            {
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadMediaContent(t,l);
                });
            }
            else if ( c_oSer_OtherType.Theme === type )
            {
                this.wb.theme = pptx_content_loader.ReadTheme(this, this.stream);
                res = c_oSerConstants.ReadUnknown;
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadMediaContent = function(type, length)
        {
            var res = c_oSerConstants.ReadOk;
            var oThis = this;
            if ( c_oSer_OtherType.MediaItem === type )
            {
                var oNewMedia = {};
                res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadMediaItem(t,l, oNewMedia);
                });
                if(null != oNewMedia.id && null != oNewMedia.src)
                    this.oMedia[oNewMedia.id] = oNewMedia.src;
            }
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        this.ReadMediaItem = function(type, length, oNewMedia)
        {
            var res = c_oSerConstants.ReadOk;
            if ( c_oSer_OtherType.MediaSrc === type )
            {
                var src = this.stream.GetString2LE(length);
                if(0 != src.indexOf("http:") && 0 != src.indexOf("data:") && 0 != src.indexOf("https:") && 0 != src.indexOf("ftp:") && 0 != src.indexOf("file:"))
                    oNewMedia.src = AscCommon.g_oDocumentUrls.getImageUrl(src);
                else
                    oNewMedia.src = src;
            }
            else if ( c_oSer_OtherType.MediaId === type )
                oNewMedia.id = this.stream.GetULongLE();
            else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
    }

    function getBinaryOtherTableGVar(wb)
    {
        AscCommonExcel.g_oColorManager.setTheme(wb.theme);

        var sMinorFont = null;
        if(null != wb.theme.themeElements && null != wb.theme.themeElements.fontScheme && null != wb.theme.themeElements.fontScheme.minorFont)
            sMinorFont = wb.theme.themeElements.fontScheme.minorFont.latin;
        var sDefFont = "Calibri";
        if(null != sMinorFont && "" != sMinorFont)
            sDefFont = sMinorFont;
        g_oDefaultFormat.Font = new AscCommonExcel.Font();
		g_oDefaultFormat.Font.assignFromObject({
		    fn: sDefFont,
            scheme: EFontScheme.fontschemeMinor,
			fs: 11,
			c: AscCommonExcel.g_oColorManager.getThemeColor(AscCommonExcel.g_nColorTextDefault)
		});
        g_oDefaultFormat.Fill = g_oDefaultFormat.FillAbs = new AscCommonExcel.Fill({bg : null});
        g_oDefaultFormat.Border = g_oDefaultFormat.BorderAbs = new AscCommonExcel.Border({
            l : new AscCommonExcel.BorderProp(),
            t : new AscCommonExcel.BorderProp(),
            r : new AscCommonExcel.BorderProp(),
            b : new AscCommonExcel.BorderProp(),
            d : new AscCommonExcel.BorderProp(),
            ih : new AscCommonExcel.BorderProp(),
            iv : new AscCommonExcel.BorderProp(),
            dd : false,
            du : false
        });
        g_oDefaultFormat.Num = g_oDefaultFormat.NumAbs = new AscCommonExcel.Num({f : "General"});
        g_oDefaultFormat.Align = g_oDefaultFormat.AlignAbs = new AscCommonExcel.Align({
            hor : null,
            indent : 0,
            RelativeIndent : 0,
            shrink : false,
            angle : 0,
            ver : Asc.c_oAscVAlign.Bottom,
            wrap : false
        });
    }


    /** @constructor */
    function BinaryFileReader(isCopyPaste)
    {
        this.stream = null;
        this.copyPasteObj =
        {
            isCopyPaste: isCopyPaste,
            activeRange: null
        };
        this.oReadResult = {
            tableCustomFunc: [],
            sheetData: []
        };
        this.getbase64DecodedData = function(szSrc)
        {
			var isBase64 = typeof szSrc === 'string';
			var srcLen = szSrc.length;
			var nWritten = 0;
			
            var nType = 0;
            var index = AscCommon.c_oSerFormat.Signature.length;
            var version = "";
            var dst_len = "";
            while (true)
            {
                index++;
                var _c = isBase64 ? szSrc.charCodeAt(index) : szSrc[index];
                if (_c == ";".charCodeAt(0))
                {

                    if(0 == nType)
                    {
                        nType = 1;
                        continue;
                    }
                    else
                    {
                        index++;
                        break;
                    }
                }
                if(0 == nType)
                    version += String.fromCharCode(_c);
                else
                    dst_len += String.fromCharCode(_c);
            }
			var nVersion = 0;
			if(version.length > 1)
			{
				var nTempVersion = version.substring(1) - 0;
				if(nTempVersion)
					AscCommon.CurFileVersion = nVersion = nTempVersion;
			}
			var stream;
			if (Asc.c_nVersionNoBase64 !== nVersion) {
				var dstLen = parseInt(dst_len);

				var pointer = g_memory.Alloc(dstLen);
				stream = new AscCommon.FT_Stream2(pointer.data, dstLen);
				stream.obj = pointer.obj;

				var dstPx = stream.data;

				if (window.chrome)
				{
					while (index < srcLen)
					{
						var dwCurr = 0;
						var i;
						var nBits = 0;
						for (i=0; i<4; i++)
						{
							if (index >= srcLen)
								break;
							var nCh = DecodeBase64Char(isBase64 ? szSrc.charCodeAt(index++) : szSrc[index++]);
							if (nCh == -1)
							{
								i--;
								continue;
							}
							dwCurr <<= 6;
							dwCurr |= nCh;
							nBits += 6;
						}

						dwCurr <<= 24-nBits;
						for (i=0; i<nBits/8; i++)
						{
							dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
							dwCurr <<= 8;
						}
					}
				}
				else
				{
					var p = b64_decode;
					while (index < srcLen)
					{
						var dwCurr = 0;
						var i;
						var nBits = 0;
						for (i=0; i<4; i++)
						{
							if (index >= srcLen)
								break;
							var nCh = p[isBase64 ? szSrc.charCodeAt(index++) : szSrc[index++]];
							if (nCh == undefined)
							{
								i--;
								continue;
							}
							dwCurr <<= 6;
							dwCurr |= nCh;
							nBits += 6;
						}

						dwCurr <<= 24-nBits;
						for (i=0; i<nBits/8; i++)
						{
							dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
							dwCurr <<= 8;
						}
					}
				}
			} else {
				stream = new AscCommon.FT_Stream2(szSrc, szSrc.length);
				//skip header
				stream.EnterFrame(index);
				stream.Seek(index);
			}

            return stream;
        };
        this.getbase64DecodedData2 = function(szSrc, szSrcOffset, stream, streamOffset)
        {
            var srcLen = szSrc.length;
            var nWritten = streamOffset;
            var dstPx = stream.data;
            var index = szSrcOffset;

            if (window.chrome)
            {
                while (index < srcLen)
                {
                    var dwCurr = 0;
                    var i;
                    var nBits = 0;
                    for (i=0; i<4; i++)
                    {
                        if (index >= srcLen)
                            break;
                        var nCh = DecodeBase64Char(szSrc.charCodeAt(index++));
                        if (nCh == -1)
                        {
                            i--;
                            continue;
                        }
                        dwCurr <<= 6;
                        dwCurr |= nCh;
                        nBits += 6;
                    }

                    dwCurr <<= 24-nBits;
                    var nLen = (nBits/8) | 0;
                    for (i=0; i<nLen; i++)
                    {
                        dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
                        dwCurr <<= 8;
                    }
                }
            }
            else
            {
                var p = b64_decode;
                while (index < srcLen)
                {
                    var dwCurr = 0;
                    var i;
                    var nBits = 0;
                    for (i=0; i<4; i++)
                    {
                        if (index >= srcLen)
                            break;
                        var nCh = p[szSrc.charCodeAt(index++)];
                        if (nCh == undefined)
                        {
                            i--;
                            continue;
                        }
                        dwCurr <<= 6;
                        dwCurr |= nCh;
                        nBits += 6;
                    }

                    dwCurr <<= 24-nBits;
                    var nLen = (nBits/8) | 0;
                    for (i=0; i<nLen; i++)
                    {
                        dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
                        dwCurr <<= 8;
                    }
                }
            }
            return nWritten;
        };
        this.Read = function(data, wb)
        {
            var t = this;
            pptx_content_loader.Clear();
			var pasteBinaryFromExcel = false;
			if(this.copyPasteObj && this.copyPasteObj.isCopyPaste && typeof editor != "undefined" && editor)
				pasteBinaryFromExcel = true;
			
			this.stream = this.getbase64DecodedData(data);
			if(!pasteBinaryFromExcel)
				History.TurnOff();

			AscCommonExcel.executeInR1C1Mode(false, function () {
				t.ReadMainTable(wb);
			});

            if(!this.copyPasteObj.isCopyPaste)
            {
                ReadDefCellStyles(wb, wb.CellStyles.DefaultStyles);
                // ReadDefTableStyles(wb, wb.TableStyles.DefaultStyles);
                // wb.TableStyles.concatStyles();
            }
			if(!pasteBinaryFromExcel)
				History.TurnOn();
			//чтобы удалялся stream с бинарником
			pptx_content_loader.Clear(true);
        };
        this.ReadMainTable = function(wb)
        {
            var res = c_oSerConstants.ReadOk;
            //mtLen
            res = this.stream.EnterFrame(1);
            if(c_oSerConstants.ReadOk != res)
                return res;
            var mtLen = this.stream.GetUChar();
            var aSeekTable = [];
            var nOtherTableOffset = null;
            var nSharedStringTableOffset = null;
            var nStyleTableOffset = null;
            var nWorkbookTableOffset = null;
            for(var i = 0; i < mtLen; ++i)
            {
                //mtItem
                res = this.stream.EnterFrame(5);
                if(c_oSerConstants.ReadOk != res)
                    return res;
                var mtiType = this.stream.GetUChar();
                var mtiOffBits = this.stream.GetULongLE();
                if(c_oSerTableTypes.Other == mtiType)
                    nOtherTableOffset = mtiOffBits;
                else if(c_oSerTableTypes.SharedStrings == mtiType)
                    nSharedStringTableOffset = mtiOffBits;
                else if(c_oSerTableTypes.Styles == mtiType)
                    nStyleTableOffset = mtiOffBits;
                else if(c_oSerTableTypes.Workbook == mtiType)
                    nWorkbookTableOffset = mtiOffBits;
                else
                    aSeekTable.push( {type: mtiType, offset: mtiOffBits} );
            }
            var aSharedStrings = [];
            var aCellXfs = [];
            var aDxfs = [];
            var oMediaArray = {};
            wb.aWorksheets = [];
            if(null != nOtherTableOffset)
            {
                res = this.stream.Seek(nOtherTableOffset);
                if(c_oSerConstants.ReadOk == res)
                    res = (new Binary_OtherTableReader(this.stream, oMediaArray, wb)).Read();
            }
            if(null != nSharedStringTableOffset)
            {
                res = this.stream.Seek(nSharedStringTableOffset);
                if(c_oSerConstants.ReadOk == res)
                    res = (new Binary_SharedStringTableReader(this.stream, wb, aSharedStrings)).Read();
            }
            if(null != nStyleTableOffset)
            {
                res = this.stream.Seek(nStyleTableOffset);
                if(c_oSerConstants.ReadOk == res)
                    res = (new Binary_StylesTableReader(this.stream, wb, aCellXfs, aDxfs, this.copyPasteObj.isCopyPaste)).Read();
            }
			var bwtr = new Binary_WorksheetTableReader(this.stream, this.oReadResult, wb, aSharedStrings, aCellXfs, aDxfs, oMediaArray, this.copyPasteObj);
            if(c_oSerConstants.ReadOk == res)
            {
                for(var i = 0; i < aSeekTable.length; ++i)
                {
                    var seek = aSeekTable[i];
                    var mtiType = seek.type;
                    var mtiOffBits = seek.offset;
                    res = this.stream.Seek(mtiOffBits);
                    if(c_oSerConstants.ReadOk != res)
                        break;
                    var bwtr = new Binary_WorksheetTableReader(this.stream, this.oReadResult, wb, aSharedStrings, aCellXfs, aDxfs, oMediaArray, this.copyPasteObj);
                    switch(mtiType)
                    {
                        // case c_oSerTableTypes.SharedStrings:
                        // res = (new Binary_SharedStringTableReader(this.stream, aSharedStrings)).Read();
                        // break;
                        // case c_oSerTableTypes.Styles:
                        // res = (new Binary_StylesTableReader(this.stream, wb.oStyleManager, aCellXfs)).Read();
                        // break;
                        // case c_oSerTableTypes.Workbook:
                        // res = (new Binary_WorkbookTableReader(this.stream, wb)).Read();
                        // break;
                        case c_oSerTableTypes.Worksheets:
                            res = bwtr.Read();
                            break;
                        // case c_oSerTableTypes.CalcChain:
                        //     res = (new Binary_CalcChainTableReader(this.stream, wb.calcChain)).Read();
                        //     break;
                        // case c_oSerTableTypes.Other:
                        // res = (new Binary_OtherTableReader(this.stream, oMediaArray)).Read();
                        // break;
                    }
                    if(c_oSerConstants.ReadOk != res)
                        break;
                }
            }
            //todo инициализация формул из-за именованных диапазонов перенесена в wb.init ее надо вызывать в любом случае(Rev: 61959)
            //надо вернуть чтение Binary_WorkbookTableReader, когда будем реализовывать копирования именованных диапазонов
            if(!this.copyPasteObj.isCopyPaste)
            {
                if(null != nWorkbookTableOffset)
                {
                    res = this.stream.Seek(nWorkbookTableOffset);
                    if(c_oSerConstants.ReadOk == res)
                        res = (new Binary_WorkbookTableReader(this.stream, wb, bwtr)).Read();
                }
				bwtr.ReadSheetDataExternal(false);
                wb.init(this.oReadResult.tableCustomFunc, false, true);
            } else {
				bwtr.ReadSheetDataExternal(true);
				if(window["Asc"] && window["Asc"]["editor"] !== undefined) {
					wb.init(this.oReadResult.tableCustomFunc, true);
				}
            }
            return res;
        };
    }
    function CTableStyles()
    {
        this.DefaultTableStyle = "TableStyleMedium2";
        this.DefaultPivotStyle = "PivotStyleLight16";
        this.CustomStyles = {};
        this.DefaultStyles = {};
		this.DefaultStylesPivot = {};
        this.AllStyles = {};
    }
    CTableStyles.prototype =
    {
        concatStyles : function()
        {
            for(var i in this.DefaultStyles)
                this.AllStyles[i] = this.DefaultStyles[i];
			for(var i in this.DefaultStylesPivot)
				this.AllStyles[i] = this.DefaultStylesPivot[i];
            for(var i in this.CustomStyles)
                this.AllStyles[i] = this.CustomStyles[i];
        },
		readAttributes: function(attr, uq) {
			if (attr()) {
				var vals = attr();
				var val;
				val = vals["defaultTableStyle"];
				if (undefined !== val) {
					this.DefaultTableStyle = AscCommon.unleakString(uq(val));
				}
				val = vals["defaultPivotStyle"];
				if (undefined !== val) {
					this.DefaultPivotStyle = AscCommon.unleakString(uq(val));
				}
			}
		},
		onStartNode: function(elem, attr, uq) {
			var newContext = this;
			if ("tableStyle" === elem) {
				newContext = new CTableStyle();
				if (newContext.readAttributes) {
					newContext.readAttributes(attr, uq);
				}
				this.CustomStyles[newContext.name] = newContext;
				openXml.SaxParserDataTransfer.curTableStyle = newContext;
			} else {
				newContext = null;
			}
			return newContext;
		}
    };
	function CTableStyleStripe(size, offset, opt_row){
		this.size = size;
		this.offset = offset;
		this.row = opt_row;
	}
    function CTableStyle()
    {
        this.name = null;
        this.pivot = true;
        this.table = true;
        this.displayName = null; // Показываемое имя (для дефалтовых оно будет с пробелами, а для пользовательских совпадает с name)

        this.blankRow = null;
        this.firstColumn = null;
        this.firstColumnStripe = null;
        this.firstColumnSubheading = null;
        this.firstHeaderCell = null;
        this.firstRowStripe = null;
        this.firstRowSubheading = null;
        this.firstSubtotalColumn = null;
        this.firstSubtotalRow = null;
        this.firstTotalCell = null;
        this.headerRow = null;
        this.lastColumn = null;
        this.lastHeaderCell = null;
        this.lastTotalCell = null;
        this.pageFieldLabels = null;
        this.pageFieldValues = null;
        this.secondColumnStripe = null;
        this.secondColumnSubheading = null;
        this.secondRowStripe = null;
        this.secondRowSubheading = null;
        this.secondSubtotalColumn = null;
        this.secondSubtotalRow = null;
        this.thirdColumnSubheading = null;
        this.thirdRowSubheading = null;
        this.thirdSubtotalColumn = null;
        this.thirdSubtotalRow = null;
        this.totalRow = null;
        this.wholeTable = null;
    }
	CTableStyle.prototype.initStyle = function (sheetMergedStyles, bbox, options, headerRowCount, totalsRowCount) {
		var r1Data = bbox.r1 + headerRowCount;
		var r2Data = bbox.r2 - totalsRowCount;
		var bboxTmp;
		var offsetStripe;
		var stripe;
		if (this.wholeTable) {
			sheetMergedStyles.setTablePivotStyle(bbox, this.wholeTable.dxf);
		}
		if (r1Data <= r2Data) {
			if (options.ShowColumnStripes) {
				if (this.firstColumnStripe) {
					offsetStripe = this.secondColumnStripe ? this.secondColumnStripe.size : 1;
					stripe = new CTableStyleStripe(this.firstColumnStripe.size, offsetStripe);
					bboxTmp = new Asc.Range(bbox.c1, r1Data, bbox.c2, r2Data);
					sheetMergedStyles.setTablePivotStyle(bboxTmp, this.firstColumnStripe.dxf, stripe);
				}
				if (this.secondColumnStripe) {
					offsetStripe = this.firstColumnStripe ? this.firstColumnStripe.size : 1;
					stripe = new CTableStyleStripe(this.secondColumnStripe.size, offsetStripe);
					if (bbox.c1 + offsetStripe <= bbox.c2) {
						bboxTmp = new Asc.Range(bbox.c1 + offsetStripe, r1Data, bbox.c2, r2Data);
						sheetMergedStyles.setTablePivotStyle(bboxTmp, this.secondColumnStripe.dxf, stripe);
					}
				}
			}
			if (options.ShowRowStripes) {
				if (this.firstRowStripe) {
					offsetStripe = this.secondRowStripe ? this.secondRowStripe.size : 1;
					stripe = new CTableStyleStripe(this.firstRowStripe.size, offsetStripe, true);
					bboxTmp = new Asc.Range(bbox.c1, r1Data, bbox.c2, r2Data);
					sheetMergedStyles.setTablePivotStyle(bboxTmp, this.firstRowStripe.dxf, stripe);
				}
				if (this.secondRowStripe) {
					offsetStripe = this.firstRowStripe ? this.firstRowStripe.size : 1;
					stripe = new CTableStyleStripe(this.secondRowStripe.size, offsetStripe, true);
					if (r1Data + offsetStripe <= r2Data) {
						bboxTmp = new Asc.Range(bbox.c1, r1Data + offsetStripe, bbox.c2, r2Data);
						sheetMergedStyles.setTablePivotStyle(bboxTmp, this.secondRowStripe.dxf, stripe);
					}
				}
			}
		}
		if (options.ShowLastColumn && this.lastColumn) {
			bboxTmp = new Asc.Range(bbox.c2, bbox.r1, bbox.c2, bbox.r2);
			sheetMergedStyles.setTablePivotStyle(bboxTmp, this.lastColumn.dxf);
		}
		if (options.ShowFirstColumn && this.firstColumn) {
			bboxTmp = new Asc.Range(bbox.c1, bbox.r1, bbox.c1, bbox.r2);
			sheetMergedStyles.setTablePivotStyle(bboxTmp, this.firstColumn.dxf);
		}
		if (this.headerRow && headerRowCount > 0) {
			bboxTmp = new Asc.Range(bbox.c1, bbox.r1, bbox.c2, bbox.r1);
			sheetMergedStyles.setTablePivotStyle(bboxTmp, this.headerRow.dxf);
		}
		if (this.totalRow && totalsRowCount > 0) {
			bboxTmp = new Asc.Range(bbox.c1, bbox.r2, bbox.c2, bbox.r2);
			sheetMergedStyles.setTablePivotStyle(bboxTmp, this.totalRow.dxf);
		}
		if (this.firstHeaderCell && headerRowCount > 0) {
			bboxTmp = new Asc.Range(bbox.c1, bbox.r1, bbox.c1, bbox.r1);
			sheetMergedStyles.setTablePivotStyle(bboxTmp, this.firstHeaderCell.dxf);
		}
		if (this.lastHeaderCell && headerRowCount > 0) {
			bboxTmp = new Asc.Range(bbox.c2, bbox.r1, bbox.c2, bbox.r1);
			sheetMergedStyles.setTablePivotStyle(bboxTmp, this.lastHeaderCell.dxf);
		}
		if (this.firstTotalCell && totalsRowCount > 0) {
			bboxTmp = new Asc.Range(bbox.c1, bbox.r2, bbox.c1, bbox.r2);
			sheetMergedStyles.setTablePivotStyle(bboxTmp, this.firstTotalCell.dxf);
		}
		if (this.lastTotalCell && totalsRowCount > 0) {
			bboxTmp = new Asc.Range(bbox.c2, bbox.r2, bbox.c2, bbox.r2);
			sheetMergedStyles.setTablePivotStyle(bboxTmp, this.lastTotalCell.dxf);
		}
	};
	CTableStyle.prototype.readAttributes = function (attr, uq) {
		if (attr()) {
			var vals = attr();
			var val;
			val = vals["name"];
			if (undefined !== val) {
				this.name = AscCommon.unleakString(uq(val));
				this.displayName = this.name;
			}
			val = vals["displayName"];
			if (undefined !== val) {
				this.displayName = AscCommon.unleakString(uq(val));
			}
			val = vals["pivot"];
			if (undefined !== val) {
				this.pivot = getBoolFromXml(val);
			}
			val = vals["table"];
			if (undefined !== val) {
				this.table = getBoolFromXml(val);
			}
		}
	};
	CTableStyle.prototype.onStartNode = function (elem, attr, uq) {
		var newContext = this;
		if ("tableStyleElement" === elem) {
			newContext = new CTableStyleElement();
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
		} else {
			newContext = null;
		}
		return newContext;
	};

    function CTableStyleElement()
    {
        this.size = 1;
        this.dxf = null;
    }
	CTableStyleElement.prototype.readAttributes = function(attr, uq) {
		if(attr()){
			var vals = attr();
			var val;
			val = vals["type"];
			if(undefined !== val){
				var tableStyle = openXml.SaxParserDataTransfer.curTableStyle;
				if("wholeTable"===val)
					tableStyle.wholeTable = this;
				else if("headerRow"===val)
					tableStyle.headerRow = this;
				else if("totalRow"===val)
					tableStyle.totalRow = this;
				else if("firstColumn"===val)
					tableStyle.firstColumn = this;
				else if("lastColumn"===val)
					tableStyle.lastColumn = this;
				else if("firstRowStripe"===val)
					tableStyle.firstRowStripe = this;
				else if("secondRowStripe"===val)
					tableStyle.secondRowStripe = this;
				else if("firstColumnStripe"===val)
					tableStyle.firstColumnStripe = this;
				else if("secondColumnStripe"===val)
					tableStyle.secondColumnStripe = this;
				else if("firstHeaderCell"===val)
					tableStyle.firstHeaderCell = this;
				else if("lastHeaderCell"===val)
					tableStyle.lastHeaderCell = this;
				else if("firstTotalCell"===val)
					tableStyle.firstTotalCell = this;
				else if("lastTotalCell"===val)
					tableStyle.lastTotalCell = this;
				else if("firstSubtotalColumn"===val)
					tableStyle.firstSubtotalColumn = this;
				else if("secondSubtotalColumn"===val)
					tableStyle.secondSubtotalColumn = this;
				else if("thirdSubtotalColumn"===val)
					tableStyle.thirdSubtotalColumn = this;
				else if("firstSubtotalRow"===val)
					tableStyle.firstSubtotalRow = this;
				else if("secondSubtotalRow"===val)
					tableStyle.secondSubtotalRow = this;
				else if("thirdSubtotalRow"===val)
					tableStyle.thirdSubtotalRow = this;
				else if("blankRow"===val)
					tableStyle.blankRow = this;
				else if("firstColumnSubheading"===val)
					tableStyle.firstColumnSubheading = this;
				else if("secondColumnSubheading"===val)
					tableStyle.secondColumnSubheading = this;
				else if("thirdColumnSubheading"===val)
					tableStyle.thirdColumnSubheading = this;
				else if("firstRowSubheading"===val)
					tableStyle.firstRowSubheading = this;
				else if("secondRowSubheading"===val)
					tableStyle.secondRowSubheading = this;
				else if("thirdRowSubheading"===val)
					tableStyle.thirdRowSubheading = this;
				else if("pageFieldLabels"===val)
					tableStyle.pageFieldLabels = this;
				else if("pageFieldValues"===val)
					tableStyle.pageFieldValues = this;
			}
			val = vals["size"];
			if(undefined !== val){
				this.size = val - 0;
			}
			val = vals["dxfId"];
			if (undefined !== val) {
				this.dxf = openXml.SaxParserDataTransfer.dxfs[tableStyle.pivot ? val - 0 : val - 1] || null;
			}
		}
	};
    function ReadDefTableStyles(wb)
    {
    	var stylesZip = " ";
		var jsZipWrapper = new AscCommon.JSZipWrapper();
		return jsZipWrapper.loadAsync(stylesZip, {"base64": true}).then(function(zip) {
			return zip.files["presetTableStyles.xml"].async("string");
		}).then(function(content) {
			jsZipWrapper.close();
			var stylesXml = new CT_PresetTableStyles(wb.TableStyles.DefaultStyles, wb.TableStyles.DefaultStylesPivot);
			new openXml.SaxParserBase().parse(content, stylesXml);
			wb.TableStyles.concatStyles();
		});
    }
    function ReadDefCellStyles(wb, oOutput)
    {
        var Types = {
            Style		: 0,
            BuiltinId	: 1,
            Hidden		: 2,
            CellStyle	: 3,
            Xfs			: 4,
            Font		: 5,
            Fill		: 6,
            Border		: 7,
            NumFmts		: 8
        };
        // Пишем тип и размер (версию не пишем)
        var sStyles = "XLSY;;11499; ";

        var oBinaryFileReader = new BinaryFileReader();
        var stream = oBinaryFileReader.getbase64DecodedData(sStyles);
        var bcr = new Binary_CommonReader(stream);
        var oBinary_StylesTableReader = new Binary_StylesTableReader(stream, wb, [], [], undefined, true);

        var length = stream.GetULongLE();

        var fReadStyle = function(type, length, oCellStyle, oStyleObject) {
            var res = c_oSerConstants.ReadOk;
            if (Types.BuiltinId === type) {
                oCellStyle.BuiltinId = stream.GetULongLE();
            } else if (Types.Hidden === type) {
                oCellStyle.Hidden = stream.GetBool();
            } else if (Types.CellStyle === type) {
                res = bcr.Read1(length, function(t, l) {
                    return oBinary_StylesTableReader.ReadCellStyle(t, l, oCellStyle);
                });
            } else if (Types.Xfs === type) {
                oStyleObject.xfs = {ApplyAlignment: null, ApplyBorder: null, ApplyFill: null, ApplyFont: null, ApplyNumberFormat: null,
                    BorderId: null, FillId: null, FontId: null, NumFmtId: null, QuotePrefix: null, Aligment: null, XfId: null, PivotButton: null};
                res = bcr.Read2Spreadsheet(length, function (t, l) {
                    return oBinary_StylesTableReader.ReadXfs(t, l, oStyleObject.xfs);
                });
            } else if (Types.Font === type) {
                oStyleObject.font = new AscCommonExcel.Font();
                res = bcr.Read2Spreadsheet(length, function (t, l) {
                    return oBinary_StylesTableReader.bssr.ReadRPr(t, l, oStyleObject.font);
                });
                oBinary_StylesTableReader.bssr.CheckSchemeFont(oStyleObject.font);
            } else if (Types.Fill === type) {
                oStyleObject.fill = new AscCommonExcel.Fill();
                res = bcr.Read1(length, function (t, l) {
                    return oBinary_StylesTableReader.ReadFill(t, l, oStyleObject.fill);
                });
            } else if (Types.Border === type) {
                oStyleObject.border = new AscCommonExcel.Border();
                res = bcr.Read1(length, function (t, l) {
                    return oBinary_StylesTableReader.ReadBorder(t, l, oStyleObject.border);
                });
            } else if (Types.NumFmts === type) {
                res = bcr.Read1(length, function (t, l) {
                    return oBinary_StylesTableReader.ReadNumFmts(t, l, oStyleObject.oNumFmts);
                });
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };
        var fReadStyles = function (type, length, oOutput) {
            var res = c_oSerConstants.ReadOk;
            var oStyleObject = {font: null, fill: null, border: null, oNumFmts: {}, xfs: null};
            if (Types.Style === type) {
                var oCellStyle = new AscCommonExcel.CCellStyle();
                res = bcr.Read1(length, function (t, l) {
                    return fReadStyle(t,l, oCellStyle, oStyleObject);
                });

                var newXf = new AscCommonExcel.CellXfs();
                // Border
                if (null !== oStyleObject.border)
					newXf.border = g_StyleCache.addBorder(oStyleObject.border);
                // Fill
                if (null !== oStyleObject.fill)
					newXf.fill = g_StyleCache.addFill(oStyleObject.fill);
                // Font
                if (null !== oStyleObject.font)
					newXf.font = g_StyleCache.addFont(oStyleObject.font);
                // NumFmt
                if (null !== oStyleObject.xfs.numid) {
                    var oCurNum = oStyleObject.oNumFmts[oStyleObject.xfs.numid];
                    if(null != oCurNum)
						newXf.num = g_StyleCache.addNum(oCurNum);
                    else
						newXf.num = g_StyleCache.addNum(oBinary_StylesTableReader.ParseNum({id: oStyleObject.xfs.numid, f: null}, oStyleObject.oNumFmts));
                }
                // QuotePrefix
                if(null != oStyleObject.xfs.QuotePrefix)
					newXf.QuotePrefix = oStyleObject.xfs.QuotePrefix;
				// PivotButton
				if(null != oStyleObject.xfs.PivotButton)
					newXf.PivotButton = oStyleObject.xfs.PivotButton;
                // align
                if(null != oStyleObject.xfs.align)
					newXf.align = g_StyleCache.addAlign(oStyleObject.xfs.align);
                // XfId
                if (null !== oStyleObject.xfs.XfId)
					newXf.XfId = oStyleObject.xfs.XfId;
                // ApplyBorder (ToDo возможно это свойство должно быть в xfs)
                if (null !== oStyleObject.xfs.ApplyBorder)
                    oCellStyle.ApplyBorder = oStyleObject.xfs.ApplyBorder;
                // ApplyFill (ToDo возможно это свойство должно быть в xfs)
                if (null !== oStyleObject.xfs.ApplyFill)
                    oCellStyle.ApplyFill = oStyleObject.xfs.ApplyFill;
                // ApplyFont (ToDo возможно это свойство должно быть в xfs)
                if (null !== oStyleObject.xfs.ApplyFont)
                    oCellStyle.ApplyFont = oStyleObject.xfs.ApplyFont;
                // ApplyNumberFormat (ToDo возможно это свойство должно быть в xfs)
                if (null !== oStyleObject.xfs.ApplyNumberFormat)
                    oCellStyle.ApplyNumberFormat = oStyleObject.xfs.ApplyNumberFormat;
                oCellStyle.xfs = g_StyleCache.addXf(newXf);

                oOutput.push(oCellStyle);
            } else
                res = c_oSerConstants.ReadUnknown;
            return res;
        };

        var res = bcr.Read1(length, function (t, l) {
            return fReadStyles(t, l, oOutput);
        });

        // Если нет стилей в документе, то добавим
        if (0 === wb.CellStyles.CustomStyles.length && 0 < oOutput.length) {
            wb.CellStyles.CustomStyles.push(oOutput[0].clone());
            wb.CellStyles.CustomStyles[0].XfId = 0;
        }
        // Если XfId не задан, то определим его
        if (null == g_oDefaultFormat.XfId) {
            g_oDefaultFormat.XfId = 0;
        }
    }

	function CT_PresetTableStyles(tableStyles, pivotStyles) {
		this.tableStyles = tableStyles;
		this.pivotStyles = pivotStyles;
	}

	CT_PresetTableStyles.prototype.onStartNode = function(elem, attr, uq) {
		var newContext = this;
		if ("presetTableStyles" === elem) {
		} else if (0 === elem.indexOf("TableStyle") || 0 === elem.indexOf("PivotStyle")) {
			newContext = new CT_Stylesheet(new Asc.CTableStyles());
		} else {
			newContext = null;
		}
		return newContext;
	};
	CT_PresetTableStyles.prototype.onEndNode = function(prevContext, elem) {
		if (0 === elem.indexOf("TableStyle")) {
			for (var i in prevContext.tableStyles.CustomStyles) {
				this.tableStyles[i] = prevContext.tableStyles.CustomStyles[i];
			}
		} else if (0 === elem.indexOf("PivotStyle")) {
			for (var i in prevContext.tableStyles.CustomStyles) {
				this.pivotStyles[i] = prevContext.tableStyles.CustomStyles[i];
			}
		}
	};

	function CT_Stylesheet(tableStyles) {
		//Members
		this.numFmts = [];
		this.fonts = [];
		this.fills = [];
		this.borders = [];
		this.cellStyleXfs = [];
		this.cellXfs = [];
		this.cellStyles = [];
		this.dxfs = [];
		this.tableStyles = tableStyles;
	}

	CT_Stylesheet.prototype.onStartNode = function(elem, attr, uq) {
		var newContext = this;
		if ("styleSheet" === elem) {
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
		} else if ("numFmts" === elem) {
			openXml.SaxParserDataTransfer.numFmts = this.numFmts;
		} else if ("numFmt" === elem) {
			newContext = new AscCommonExcel.Num();
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
			this.numFmts.push(newContext);
		} else if ("fonts" === elem) {
			openXml.SaxParserDataTransfer.fonts = this.fonts;
		} else if ("font" === elem) {
			newContext = new AscCommonExcel.Font();
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
			this.fonts.push(newContext);
		} else if ("fills" === elem) {
			openXml.SaxParserDataTransfer.fills = this.fills;
			openXml.SaxParserDataTransfer.priorityBg = false;
		} else if ("fill" === elem) {
			newContext = new AscCommonExcel.Fill();
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
			this.fills.push(newContext);
		} else if ("borders" === elem) {
			openXml.SaxParserDataTransfer.borders = this.borders;
		} else if ("border" === elem) {
			newContext = new AscCommonExcel.Border();
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
			this.borders.push(newContext);
			// } else if("cellStyleXfs" === elem){
			// 	newContext = new CT_CellStyleXfs();
			// 	if(newContext.readAttributes){
			// 		newContext.readAttributes(attr, uq);
			// 	}
			// 	this.cellStyleXfs = newContext;
			// } else if("cellXfs" === elem){
			// 	newContext = new CT_CellXfs();
			// 	if(newContext.readAttributes){
			// 		newContext.readAttributes(attr, uq);
			// 	}
			// 	this.cellXfs = newContext;
			// } else if("cellStyles" === elem){
			// 	newContext = new CT_CellStyles();
			// 	if(newContext.readAttributes){
			// 		newContext.readAttributes(attr, uq);
			// 	}
			// 	this.cellStyles = newContext;
		} else if ("dxfs" === elem) {
			openXml.SaxParserDataTransfer.dxfs = this.dxfs;
			openXml.SaxParserDataTransfer.priorityBg = true;
		} else if ("dxf" === elem) {
			newContext = new CT_Dxf();
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
		} else if ("tableStyles" === elem) {
			newContext = this.tableStyles;
		} else {
			newContext = null;
		}
		return newContext;
	};
	CT_Stylesheet.prototype.onEndNode = function(prevContext, elem) {
		if ("dxf" === elem) {
			this.dxfs.push(g_StyleCache.addXf(prevContext.xf, true));
		}
	};

	function CT_Dxf() {
		//Members
		this.xf = new AscCommonExcel.CellXfs();
	}

	CT_Dxf.prototype.onStartNode = function(elem, attr, uq) {
		var newContext = this;
		if ("font" === elem) {
			newContext = new AscCommonExcel.Font();
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
			this.xf.font = newContext;
		} else if ("numFmt" === elem) {
			newContext = new AscCommonExcel.Num();
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
			this.xf.num = newContext;
		} else if ("fill" === elem) {
			newContext = new AscCommonExcel.Fill();
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
			this.xf.fill = newContext;
		} else if ("alignment" === elem) {
			newContext = new AscCommonExcel.Align();
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
			this.xf.align = newContext;
		} else if ("border" === elem) {
			newContext = new AscCommonExcel.Border();
			if (newContext.readAttributes) {
				newContext.readAttributes(attr, uq);
			}
			this.xf.border = newContext;
		} else {
			newContext = null;
		}
		return newContext;
	};

    window['Asc'] = window['Asc'] || {};
    window['AscCommonExcel'] = window['AscCommonExcel'] || {};
    window["Asc"].EBorderStyle = EBorderStyle;
    window["Asc"].EUnderline = EUnderline;
    window["Asc"].ECellAnchorType = ECellAnchorType;
    window["Asc"].EVisibleType = EVisibleType;
    window["Asc"].ECellTypeType = ECellTypeType;
    window["Asc"].ECellFormulaType = ECellFormulaType;
    window["Asc"].EPageOrientation = EPageOrientation;
    window["Asc"].EPageSize = EPageSize;
    window["Asc"].ETotalsRowFunction = ETotalsRowFunction;
    window["Asc"].ESortBy = ESortBy;
    window["Asc"].ECustomFilter = ECustomFilter;
    window["Asc"].EDateTimeGroup = EDateTimeGroup;
    window["Asc"].ETableStyleType = ETableStyleType;
    window["Asc"].EFontScheme = EFontScheme;
    window["Asc"].EIconSetType = EIconSetType;
    window["AscCommonExcel"].ECfOperator = ECfOperator;
	window["AscCommonExcel"].ECfType = ECfType;
    window["AscCommonExcel"].ECfvoType = ECfvoType;
    window["AscCommonExcel"].ST_TimePeriod = ST_TimePeriod;

    window["Asc"].CTableStyles = CTableStyles;
    window["Asc"].CTableStyle = CTableStyle;
    window["Asc"].CTableStyleElement = CTableStyleElement;
    window["Asc"].CTableStyleStripe = CTableStyleStripe;
    window["AscCommonExcel"].BinaryFileReader = BinaryFileReader;
    window["AscCommonExcel"].BinaryFileWriter = BinaryFileWriter;

    window["AscCommonExcel"].BinaryTableWriter = BinaryTableWriter;
    window["AscCommonExcel"].Binary_TableReader = Binary_TableReader;

    window["Asc"].getBinaryOtherTableGVar = getBinaryOtherTableGVar;
    window["Asc"].ReadDefTableStyles = ReadDefTableStyles;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(/**
 * @param {Window} window
 * @param {undefined} undefined
 */
	function (window, undefined) {
	// Import
	var c_oAscBorderStyles = AscCommon.c_oAscBorderStyles;

	/** @constructor */
	function asc_CCellFlag() {
		this.merge = Asc.c_oAscMergeOptions.None;
		this.shrinkToFit = false;
		this.wrapText = false;
		this.selectionType = null;
		this.lockText = false;
		this.multiselect = false;
	}

	asc_CCellFlag.prototype.asc_getMerge = function () {
		return this.merge;
	};
	asc_CCellFlag.prototype.asc_getShrinkToFit = function () {
		return this.shrinkToFit;
	};
	asc_CCellFlag.prototype.asc_getWrapText = function () {
		return this.wrapText;
	};
	asc_CCellFlag.prototype.asc_getSelectionType = function () {
		return this.selectionType;
	};
	asc_CCellFlag.prototype.asc_getMultiselect = function () {
		return this.multiselect;
	};
	asc_CCellFlag.prototype.asc_getLockText = function () {
		return this.lockText;
	};

	/** @constructor */
	function asc_CFont(name, size, color, b, i, u, s, sub, sup) {
		this.name = name !== undefined ? name : "Arial";
		this.size = size !== undefined ? size : 10;
		this.color = color !== undefined ? color : null;
		this.bold = !!b;
		this.italic = !!i;
		this.underline = !!u;
		this.strikeout = !!s;
		this.subscript = !!sub;
		this.superscript = !!sup;
	}

	asc_CFont.prototype = {
		asc_getName: function () {
			return this.name;
		}, asc_getSize: function () {
			return this.size;
		}, asc_getBold: function () {
			return this.bold;
		}, asc_getItalic: function () {
			return this.italic;
		}, asc_getUnderline: function () {
			return this.underline;
		}, asc_getStrikeout: function () {
			return this.strikeout;
		}, asc_getSubscript: function () {
			return this.subscript;
		}, asc_getSuperscript: function () {
			return this.superscript;
		}, asc_getColor: function () {
			return this.color;
		}
	};

	/** @constructor */
	function asc_CFill(color) {
		this.color = color !== undefined ? color : null;
	}

	asc_CFill.prototype = {
		asc_getColor: function () {
			return this.color;
		}
	};

	/** @constructor */
	function asc_CBorder(style, color) {
		// ToDo заглушка для создания border-а
		if (typeof style === "string") {
			switch (style) {
				case "thin"    :
					this.style = c_oAscBorderStyles.Thin;
					break;
				case "medium"  :
					this.style = c_oAscBorderStyles.Medium;
					break;
				case "thick"  :
					this.style = c_oAscBorderStyles.Thick;
					break;
				default      :
					this.style = c_oAscBorderStyles.None;
					break;
			}
		} else {
			this.style = style !== undefined ? style : c_oAscBorderStyles.None;
		}
		this.color = color !== undefined ? color : null;
	}

	asc_CBorder.prototype = {
		asc_getStyle: function () {
			return this.style;
		}, asc_getColor: function () {
			return this.color;
		}
	};

	/** @constructor */
	function asc_CBorders() {
		this.left = null;
		this.top = null;
		this.right = null;
		this.bottom = null;
		this.diagDown = null;
		this.diagUp = null;
	}

	asc_CBorders.prototype = {
		asc_getLeft: function () {
			return this.left;
		}, asc_getTop: function () {
			return this.top;
		}, asc_getRight: function () {
			return this.right;
		}, asc_getBottom: function () {
			return this.bottom;
		}, asc_getDiagDown: function () {
			return this.diagDown;
		}, asc_getDiagUp: function () {
			return this.diagUp;
		}
	};

	/** @constructor */
	function asc_CAutoFilterInfo() {
		this.tableStyleName = null;
		this.tableName = null;
		this.isApplyAutoFilter = false;   // Кнопка очистить фильтр: false - disable, true - pressed button
		this.isAutoFilter = false;  // Кнопка автофильтр (также влияет на formatTable и Sort). Возможные состояния:
		// - null - мы в пересечении с таблицой (но не полностью в ней)
		// - true/false - когда мы полностью в таблице или вне ее (true/false в зависимости от того применен фильтр или нет)
	}

	asc_CAutoFilterInfo.prototype = {
		asc_getTableStyleName: function () {
			return this.tableStyleName;
		}, asc_getTableName: function () {
			return this.tableName;
		}, asc_getIsAutoFilter: function () {
			return this.isAutoFilter;
		}, asc_getIsApplyAutoFilter: function () {
			return this.isApplyAutoFilter;
		}
	};

	/** @constructor */
	function asc_CFormatTableInfo() {
		this.tableStyleName = null;
		this.tableName = null;

		this.tableRange = null;

		this.firstRow = null;
		this.lastRow = null;
		this.bandHor = null;
		this.firstCol = null;
		this.lastCol = null;
		this.bandVer = null;
		this.filterButton = null;

		//info send in menu - what you can do with row/col into table
		this.isInsertRowAbove = null;
		this.isInsertRowBelow = null;
		this.isInsertColumnLeft = null;
		this.isInsertColumnRight = null;
		this.isDeleteRow = null;
		this.isDeleteColumn = null;
		this.isDeleteTable = null;

		this.altText = null;
		this.altTextSummary = null;
	}

	asc_CFormatTableInfo.prototype = {
		asc_getTableStyleName: function () {
			return this.tableStyleName;
		}, asc_getTableName: function () {
			return this.tableName;
		},

		asc_getFirstRow: function () {
			return this.firstRow;
		}, asc_getLastRow: function () {
			return this.lastRow;
		}, asc_getBandHor: function () {
			return this.bandHor;
		}, asc_getFirstCol: function () {
			return this.firstCol;
		}, asc_getLastCol: function () {
			return this.lastCol;
		}, asc_getBandVer: function () {
			return this.bandVer;
		}, asc_getFilterButton: function () {
			return this.filterButton;
		}, asc_getTableRange: function () {
			return this.tableRange;
		},

		asc_getIsInsertRowAbove: function () {
			return this.isInsertRowAbove;
		}, asc_getIsInsertRowBelow: function () {
			return this.isInsertRowBelow;
		}, asc_getIsInsertColumnLeft: function () {
			return this.isInsertColumnLeft;
		}, asc_getIsInsertColumnRight: function () {
			return this.isInsertColumnRight;
		}, asc_getIsDeleteRow: function () {
			return this.isDeleteRow;
		}, asc_getIsDeleteColumn: function () {
			return this.isDeleteColumn;
		}, asc_getIsDeleteTable: function () {
			return this.isDeleteTable;
		},

		asc_getTitle: function () {
			return this.altText;
		}, asc_getDescription: function () {
			return this.altTextSummary;
		}
	};

	/** @constructor */
	function asc_CCellInfo() {
		this.formula = "";
		this.text = "";
		this.halign = "left";
		this.valign = "top";
		this.flags = null;
		this.font = null;
		this.fill = null;
		this.border = null;
		this.innertext = null;
		this.numFormat = null;
		this.hyperlink = null;
		this.comment = null;
		this.isLocked = false;
		this.isLockedTable = false;
		this.isLockedSparkline = false;
		this.isLockedPivotTable = false;
		this.styleName = null;
		this.numFormatInfo = null;
		this.angle = null;
		this.autoFilterInfo = null;
		this.formatTableInfo = null;
		this.sparklineInfo = null;
		this.pivotTableInfo = null;
	}

	asc_CCellInfo.prototype.asc_getFormula = function () {
		return this.formula;
	};
	asc_CCellInfo.prototype.asc_getText = function () {
		return this.text;
	};
	asc_CCellInfo.prototype.asc_getHorAlign = function () {
		return this.halign;
	};
	asc_CCellInfo.prototype.asc_getVertAlign = function () {
		return this.valign;
	};
	asc_CCellInfo.prototype.asc_getFlags = function () {
		return this.flags;
	};
	asc_CCellInfo.prototype.asc_getFont = function () {
		return this.font;
	};
	asc_CCellInfo.prototype.asc_getFill = function () {
		return this.fill;
	};
	asc_CCellInfo.prototype.asc_getBorders = function () {
		return this.border;
	};
	asc_CCellInfo.prototype.asc_getInnerText = function () {
		return this.innertext;
	};
	asc_CCellInfo.prototype.asc_getNumFormat = function () {
		return this.numFormat;
	};
	asc_CCellInfo.prototype.asc_getHyperlink = function () {
		return this.hyperlink;
	};
	asc_CCellInfo.prototype.asc_getComments = function () {
		return this.comment ? [this.comment] : [];
	};
	asc_CCellInfo.prototype.asc_getLocked = function () {
		return this.isLocked;
	};
	asc_CCellInfo.prototype.asc_getLockedTable = function () {
		return this.isLockedTable;
	};
	asc_CCellInfo.prototype.asc_getLockedSparkline = function () {
		return this.isLockedSparkline;
	};
	asc_CCellInfo.prototype.asc_getLockedPivotTable = function () {
		return this.isLockedPivotTable;
	};
	asc_CCellInfo.prototype.asc_getStyleName = function () {
		return this.styleName;
	};
	asc_CCellInfo.prototype.asc_getNumFormatInfo = function () {
		return this.numFormatInfo;
	};
	asc_CCellInfo.prototype.asc_getAngle = function () {
		return this.angle;
	};
	asc_CCellInfo.prototype.asc_getAutoFilterInfo = function () {
		return this.autoFilterInfo;
	};
	asc_CCellInfo.prototype.asc_getFormatTableInfo = function () {
		return this.formatTableInfo;
	};
	asc_CCellInfo.prototype.asc_getSparklineInfo = function () {
		return this.sparklineInfo;
	};
	asc_CCellInfo.prototype.asc_getPivotTableInfo = function () {
		return this.pivotTableInfo;
	};

	/** @constructor */
	function asc_CDefName(n, r, s, t, h, l) {
		this.Name = n;
		this.LocalSheetId = s;
		this.Ref = r;
		this.isTable = t;
		this.Hidden = h;
		this.isLock = l;
	}

	asc_CDefName.prototype = {
		asc_getName: function () {
			return this.Name;
		}, asc_getScope: function () {
			return this.LocalSheetId;
		}, asc_getRef: function () {
			return this.Ref;
		}, asc_getIsTable: function () {
			return this.isTable;
		}, asc_getIsHidden: function () {
			return this.Hidden;
		}, asc_getIsLock: function () {
			return this.isLock;
		}
	};

	/** @constructor */
	function asc_CCheckDefName(s, r) {
		this.status = s;
		this.reason = r;
	}

	asc_CCheckDefName.prototype.asc_getStatus = function () {
		return this.status;
	};
	asc_CCheckDefName.prototype.asc_getReason = function () {
		return this.reason;
	};

	//----------------------------------------------------------export----------------------------------------------------
	var prot;
	window['Asc'] = window['Asc'] || {};
	window['AscCommonExcel'] = window['AscCommonExcel'] || {};

	window["AscCommonExcel"].asc_CCellFlag = asc_CCellFlag;
	prot = asc_CCellFlag.prototype;
	prot["asc_getMerge"] = prot.asc_getMerge;
	prot["asc_getShrinkToFit"] = prot.asc_getShrinkToFit;
	prot["asc_getWrapText"] = prot.asc_getWrapText;
	prot["asc_getSelectionType"] = prot.asc_getSelectionType;
	prot["asc_getMultiselect"] = prot.asc_getMultiselect;
	prot["asc_getLockText"] = prot.asc_getLockText;

	window["AscCommonExcel"].asc_CFont = asc_CFont;
	prot = asc_CFont.prototype;
	prot["asc_getName"] = prot.asc_getName;
	prot["asc_getSize"] = prot.asc_getSize;
	prot["asc_getBold"] = prot.asc_getBold;
	prot["asc_getItalic"] = prot.asc_getItalic;
	prot["asc_getUnderline"] = prot.asc_getUnderline;
	prot["asc_getStrikeout"] = prot.asc_getStrikeout;
	prot["asc_getSubscript"] = prot.asc_getSubscript;
	prot["asc_getSuperscript"] = prot.asc_getSuperscript;
	prot["asc_getColor"] = prot.asc_getColor;

	window["AscCommonExcel"].asc_CFill = asc_CFill;
	prot = asc_CFill.prototype;
	prot["asc_getColor"] = prot.asc_getColor;

	window["Asc"].asc_CBorder = window["Asc"]["asc_CBorder"] = asc_CBorder;
	prot = asc_CBorder.prototype;
	prot["asc_getStyle"] = prot.asc_getStyle;
	prot["asc_getColor"] = prot.asc_getColor;

	window["AscCommonExcel"].asc_CBorders = asc_CBorders;
	prot = asc_CBorders.prototype;
	prot["asc_getLeft"] = prot.asc_getLeft;
	prot["asc_getTop"] = prot.asc_getTop;
	prot["asc_getRight"] = prot.asc_getRight;
	prot["asc_getBottom"] = prot.asc_getBottom;
	prot["asc_getDiagDown"] = prot.asc_getDiagDown;
	prot["asc_getDiagUp"] = prot.asc_getDiagUp;

	window["AscCommonExcel"].asc_CAutoFilterInfo = asc_CAutoFilterInfo;
	prot = asc_CAutoFilterInfo.prototype;
	prot["asc_getTableStyleName"] = prot.asc_getTableStyleName;
	prot["asc_getTableName"] = prot.asc_getTableName;
	prot["asc_getIsAutoFilter"] = prot.asc_getIsAutoFilter;
	prot["asc_getIsApplyAutoFilter"] = prot.asc_getIsApplyAutoFilter;

	window["AscCommonExcel"].asc_CFormatTableInfo = asc_CFormatTableInfo;
	prot = asc_CFormatTableInfo.prototype;
	prot["asc_getTableStyleName"] = prot.asc_getTableStyleName;
	prot["asc_getTableName"] = prot.asc_getTableName;
	prot["asc_getFirstRow"] = prot.asc_getFirstRow;
	prot["asc_getLastRow"] = prot.asc_getLastRow;
	prot["asc_getBandHor"] = prot.asc_getBandHor;
	prot["asc_getFirstCol"] = prot.asc_getFirstCol;
	prot["asc_getLastCol"] = prot.asc_getLastCol;
	prot["asc_getBandVer"] = prot.asc_getBandVer;
	prot["asc_getFilterButton"] = prot.asc_getFilterButton;
	prot["asc_getTableRange"] = prot.asc_getTableRange;
	prot["asc_getIsInsertRowAbove"] = prot.asc_getIsInsertRowAbove;
	prot["asc_getIsInsertRowBelow"] = prot.asc_getIsInsertRowBelow;
	prot["asc_getIsInsertColumnLeft"] = prot.asc_getIsInsertColumnLeft;
	prot["asc_getIsInsertColumnRight"] = prot.asc_getIsInsertColumnRight;
	prot["asc_getIsDeleteRow"] = prot.asc_getIsDeleteRow;
	prot["asc_getIsDeleteColumn"] = prot.asc_getIsDeleteColumn;
	prot["asc_getIsDeleteTable"] = prot.asc_getIsDeleteTable;
	prot["asc_getTitle"] = prot.asc_getTitle;
	prot["asc_getDescription"] = prot.asc_getDescription;

	window["AscCommonExcel"].asc_CCellInfo = asc_CCellInfo;
	prot = asc_CCellInfo.prototype;
	prot["asc_getName"] = prot.asc_getName;
	prot["asc_getFormula"] = prot.asc_getFormula;
	prot["asc_getText"] = prot.asc_getText;
	prot["asc_getHorAlign"] = prot.asc_getHorAlign;
	prot["asc_getVertAlign"] = prot.asc_getVertAlign;
	prot["asc_getFlags"] = prot.asc_getFlags;
	prot["asc_getFont"] = prot.asc_getFont;
	prot["asc_getFill"] = prot.asc_getFill;
	prot["asc_getBorders"] = prot.asc_getBorders;
	prot["asc_getInnerText"] = prot.asc_getInnerText;
	prot["asc_getNumFormat"] = prot.asc_getNumFormat;
	prot["asc_getHyperlink"] = prot.asc_getHyperlink;
	prot["asc_getComments"] = prot.asc_getComments;
	prot["asc_getLocked"] = prot.asc_getLocked;
	prot["asc_getLockedTable"] = prot.asc_getLockedTable;
	prot["asc_getLockedSparkline"] = prot.asc_getLockedSparkline;
	prot["asc_getLockedPivotTable"] = prot.asc_getLockedPivotTable;
	prot["asc_getStyleName"] = prot.asc_getStyleName;
	prot["asc_getNumFormatInfo"] = prot.asc_getNumFormatInfo;
	prot["asc_getAngle"] = prot.asc_getAngle;
	prot["asc_getAutoFilterInfo"] = prot.asc_getAutoFilterInfo;
	prot["asc_getFormatTableInfo"] = prot.asc_getFormatTableInfo;
	prot["asc_getSparklineInfo"] = prot.asc_getSparklineInfo;
	prot["asc_getPivotTableInfo"] = prot.asc_getPivotTableInfo;

	window["Asc"].asc_CDefName = window["Asc"]["asc_CDefName"] = asc_CDefName;
	prot = asc_CDefName.prototype;
	prot["asc_getName"] = prot.asc_getName;
	prot["asc_getScope"] = prot.asc_getScope;
	prot["asc_getRef"] = prot.asc_getRef;
	prot["asc_getIsTable"] = prot.asc_getIsTable;
	prot["asc_getIsHidden"] = prot.asc_getIsHidden;
	prot["asc_getIsLock"] = prot.asc_getIsLock;

	window["Asc"].asc_CCheckDefName = window["Asc"]["asc_CCheckDefName"] = asc_CCheckDefName;
	prot = asc_CCheckDefName.prototype;
	prot["asc_getStatus"] = prot.asc_getStatus;
	prot["asc_getReason"] = prot.asc_getReason;

})(window);
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

var translations_map = {};
var styles_index_map = {};
styles_index_map["Normal"]          = 0;
styles_index_map["No list"]         = 1;
styles_index_map["Heading 1"]       = 2;
styles_index_map["Heading 2"]       = 3;
styles_index_map["Heading 3"]       = 4;
styles_index_map["Heading 4"]       = 5;
styles_index_map["Heading 5"]       = 6;
styles_index_map["Heading 6"]       = 7;
styles_index_map["Heading 7"]       = 8;
styles_index_map["Heading 8"]       = 9;
styles_index_map["Heading 9"]       = 10;
styles_index_map["Paragraph List"]  = 11;
styles_index_map["Normal Table"]    = 12;
styles_index_map["No Spacing"]      = 13;


// en
translations_map["en"] = {};
translations_map["en"].DefaultStyles =
[
    "Normal",
    "No List",
    "Heading 1",
    "Heading 2",
    "Heading 3",
    "Heading 4",
    "Heading 5",
    "Heading 6",
    "Heading 7",
    "Heading 8",
    "Heading 9",
    "Paragraph List",
    "Normal Table",
    "No Spacing"
];
translations_map["en"].StylesText = "AaBbCcDdEeFf";

// ru
translations_map["ru"] = {};
translations_map["ru"].DefaultStyles =
[
    "Обычный",
    "Нет списка",
    "Заголовок 1",
    "Заголовок 2",
    "Заголовок 3",
    "Заголовок 4",
    "Заголовок 5",
    "Заголовок 6",
    "Заголовок 7",
    "Заголовок 8",
    "Заголовок 9",
    "Абзац списка",
    "Обычная таблица",
    "Без интервала"
];
translations_map["ru"].StylesText = "АаБбВвГгДдЕе";

// de
translations_map["de"] = {};
translations_map["de"].DefaultStyles =
[
    "Standard",
    "Keine Liste",
    "Überschrift 1",
    "Überschrift 2",
    "Überschrift 3",
    "Überschrift 4",
    "Überschrift 5",
    "Überschrift 6",
    "Überschrift 7",
    "Überschrift 8",
    "Überschrift 9",
    "Listenabsatz",
    "Normale Tabelle",
    "Kein Leerraum"
];
translations_map["de"].StylesText = "AaBbCcDdEeFf";

// fr
translations_map["fr"] = {};
translations_map["fr"].DefaultStyles =
[
    "Normal",
    "Sans liste",
    "Titre 1",
    "Titre 2",
    "Titre 3",
    "Titre 4",
    "Titre 5",
    "Titre 6",
    "Titre 7",
    "Titre 8",
    "Titre 9",
    "Paragraphe de liste",
    "Tableau normal",
    "Sans interligne"
];
translations_map["fr"].StylesText = "AaBbCcDdEeFf";

// it
translations_map["it"] = {};
translations_map["it"].DefaultStyles =
[
    "Normale",
    "Nessun elenco",
    "Titolo 1",
    "Titolo 2",
    "Titolo 3",
    "Titolo 4",
    "Titolo 5",
    "Titolo 6",
    "Titolo 7",
    "Titolo 8",
    "Titolo 9",
    "Paragrafo elenco",
    "Tabella normale",
    "Nessuna spaziatura"
];
translations_map["it"].StylesText = "AaBbCcDdEeFf";

// es
translations_map["es"] = {};
translations_map["es"].DefaultStyles =
[
    "Normal",
    "No lista",
    "Título 1",
    "Título 2",
    "Título 3",
    "Título 4",
    "Título 5",
    "Título 6",
    "Título 7",
    "Título 8",
    "Título 9",
    "Lista de párrafos",
    "Tabla",
    "Sin espaciado"
];
translations_map["es"].StylesText = "AaBbCcDdEeFf";

// lv
translations_map["lv"] = {};
translations_map["lv"].DefaultStyles =
[
    "Normāls",
    "Nav saraksts",
    "Virsraksts 1",
    "Virsraksts 2",
    "Virsraksts 3",
    "Virsraksts 4",
    "Virsraksts 5",
    "Virsraksts 6",
    "Virsraksts 7",
    "Virsraksts 8",
    "Virsraksts 9",
    "Panta saraksts",
    "Normāla tabula",
    "Bez atstarpes"
];
translations_map["lv"].StylesText = "AaBbCcDdEeFf";

    //--------------------------------------------------------export----------------------------------------------------
    window['AscCommonWord'] = window['AscCommonWord'] || {};
    window['AscCommonWord'].translations_map = translations_map;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var CShape = AscFormat.CShape;

var isRealObject = AscCommon.isRealObject;
var global_MatrixTransformer = AscCommon.global_MatrixTransformer;

CShape.prototype.setRecalculateInfo = function()
{
    this.recalcInfo =
    {
        recalculateContent:        true,
        recalculateTxBoxContent:   true,
        recalculateBrush:          true,
        recalculatePen:            true,
        recalculateTransform:      true,
        recalculateTransformText:  true,
        recalculateBounds:         true,
        recalculateGeometry:       true,
        recalculateStyle:          true,
        recalculateFill:           true,
        recalculateLine:           true,
        recalculateTransparent:    true,
        recalculateTextStyles:     [true, true, true, true, true, true, true, true, true],
        recalculateShapeStyleForParagraph: true,
        recalculateWrapPolygon: true,
        oContentMetrics: null,
        AllDrawings: []
    };

    this.bNeedUpdatePosition = true;
    this.textStyleForParagraph = null;
    this.contentWidth = null;
    this.contentHeight = null;
    this.compiledStyles = [];
    this.posX = null;
    this.posY = null;

    this.localTransform = new AscCommon.CMatrix();
    this.localTransformText = new AscCommon.CMatrix();
};

CShape.prototype.recalcContent = function()
{
    if(this.bWordShape)
    {
        this.recalcInfo.recalculateTxBoxContent = true;
        this.recalcInfo.AllDrawings = [];
        if(this.checkAutofit && this.checkAutofit())
        {
            this.recalcGeometry();
            this.recalcWrapPolygon();
            this.recalcBounds();
            this.recalcTransform();
        }
    }
    else
    {
        this.recalcInfo.recalculateContent = true;
    }
};

CShape.prototype.getDrawingDocument = function()
{
    return editor.WordControl.m_oLogicDocument.DrawingDocument;
};

CShape.prototype.getTextArtPreviewManager = function()
{
    return editor.textArtPreviewManager;
};

CShape.prototype.recalcBrush = function()
{
    this.recalcInfo.recalculateBrush = true;
};


CShape.prototype.recalcPen = function()
{
    this.recalcInfo.recalculatePen = true;
};

CShape.prototype.recalcTransform = function()
{
    this.recalcInfo.recalculateTransform = true;
    this.snapArrayX.length = 0;
    this.snapArrayY.length = 0;
};
CShape.prototype.recalcTransformText = function()
{
    this.recalcInfo.recalculateTransformText = true;
};
CShape.prototype.recalcBounds = function()
{
    this.recalcInfo.recalculateBounds = true;
};
CShape.prototype.recalcGeometry = function()
{
    this.recalcInfo.recalculateGeometry = true;
};
CShape.prototype.recalcStyle = function()
{
    this.recalcInfo.recalculateStyle = true;
};
CShape.prototype.recalcFill = function()
{
    this.recalcInfo.recalculateFill = true;
};
CShape.prototype.recalcLine = function()
{
    this.recalcInfo.recalculateLine = true;
};
CShape.prototype.recalcTransparent = function()
{
    this.recalcInfo.recalculateTransparent = true;
};
CShape.prototype.recalcTextStyles = function()
{
    this.recalcInfo.recalculateTextStyles = true;
};
CShape.prototype.recalcTxBoxContent = function()
{
    this.recalcInfo.recalculateTxBoxContent = true;
    this.recalcInfo.AllDrawings = [];
    if(this.checkAutofit && this.checkAutofit() && (!editor || !editor.noCreatePoint || editor.exucuteHistory))
    {
        this.recalcGeometry();
        this.recalcWrapPolygon();
        this.recalcBounds();
        this.recalcTransform();
    }
};

CShape.prototype.recalcWrapPolygon = function()
{
    this.recalcInfo.recalculateWrapPolygon = true;
};

CShape.prototype.addToRecalculate = function()
{
    editor.WordControl.m_oLogicDocument.DrawingObjects.addToRecalculate(this);//TODO: надо уходить от editor'а;
};
CShape.prototype.handleUpdatePosition = function()
{
    this.recalcTransform();
    this.recalcBounds();
    this.recalcTransformText();
    this.addToRecalculate();
};
CShape.prototype.handleUpdateExtents = function()
{
    this.recalcContent();
    this.recalcGeometry();
    this.recalcBounds();
    this.recalcWrapPolygon();
    this.recalcContent();
    this.recalcTxBoxContent();
    this.recalcTransform();
    this.recalcTransformText();
    this.addToRecalculate();
};
CShape.prototype.handleUpdateRot = function()
{
    this.recalcTransform();
    if(this.bodyPr && this.bodyPr.upright)
    {
        this.recalcContent();
    }
    this.recalcTransformText();
    this.recalcBounds();
    this.recalcWrapPolygon();
    this.addToRecalculate();
};
CShape.prototype.handleUpdateFlip = function()
{
    this.recalcTransform();
    this.recalcTransformText();
    this.recalcContent();
    this.recalcWrapPolygon();
    this.addToRecalculate();
};
CShape.prototype.handleUpdateFill = function()
{
    this.recalcBrush();
    this.recalcFill();
    this.recalcTransparent();
    this.addToRecalculate();
};
CShape.prototype.handleUpdateLn = function()
{
    this.recalcLine();
    this.recalcPen();
    this.recalcBounds();
    this.recalcWrapPolygon();
    this.recalcContent();
    this.recalcTransformText();
    this.addToRecalculate();
    if(this.recalcInfo && this.recalcInfo.recalculateTransform){
        if(this.group)
        {
            var oMainGroup = this.getMainGroup && this.getMainGroup();
            if(oMainGroup.parent && oMainGroup.parent.Refresh_RecalcData)
            {
                oMainGroup.parent.Refresh_RecalcData({Type: AscDFH.historyitem_Drawing_SetExtent});
            }
        }
        else
        {
            if(this.parent && this.parent.Refresh_RecalcData)
            {
                this.parent.Refresh_RecalcData({Type: AscDFH.historyitem_Drawing_SetExtent});
            }
        }
    }
};
CShape.prototype.handleUpdateGeometry = function()
{
    this.recalcGeometry();
    this.recalcBounds();
    this.recalcWrapPolygon();
    this.recalcContent();
    this.recalcTransformText();
    this.addToRecalculate();
};
CShape.prototype.convertPixToMM = function(pix)
{
    return this.getDrawingDocument().GetMMPerDot(pix);
};
CShape.prototype.getCanvasContext = function()
{
    return this.getDrawingDocument().CanvasHitContext;
};
CShape.prototype.getCompiledStyle = function()
{
    return this.style;
};
CShape.prototype.getHierarchy = function()
{
    return [];
};
CShape.prototype.getParentObjects = function ()
{
    return { slide: null, layout: null, master: null, theme: editor.WordControl.m_oLogicDocument.theme};
};


CShape.prototype.recalculateTxBoxContent = function()
{
    if(this.textBoxContent === null || this.textBoxContent.Parent !== this)
    {
        this.txWarpStructParamarks = null;
        this.txWarpStruct = null;
        this.txWarpStructParamarksNoTransform = null;
        this.txWarpStructNoTransform = null;
        this.recalcInfo.warpGeometry = null;
        return;
    }
    this.txWarpStruct = null;
    var oBodyPr = this.getBodyPr();
    var oRecalcObj = this.recalculateDocContent(this.textBoxContent, oBodyPr);
    this.contentHeight = oRecalcObj.contentH;
    this.contentWidth = oRecalcObj.w;
    if(this.recalcInfo.recalcTitle)
    {
        this.recalcInfo.bRecalculatedTitle = true;
        this.recalcInfo.recalcTitle = null;

        var oTextWarpContent = this.checkTextWarp(this.textBoxContent, oBodyPr, oRecalcObj.w, oRecalcObj.h, true, false);
        this.txWarpStructParamarks = oTextWarpContent.oTxWarpStructParamarksNoTransform;
        this.txWarpStruct = oTextWarpContent.oTxWarpStructNoTransform;

        this.txWarpStructParamarksNoTransform = oTextWarpContent.oTxWarpStructParamarksNoTransform;
        this.txWarpStructNoTransform = oTextWarpContent.oTxWarpStructNoTransform;
    }
    else
    {
        var oTextWarpContent = this.checkTextWarp(this.textBoxContent, oBodyPr, oRecalcObj.w, oRecalcObj.h, true, true);
        this.txWarpStructParamarks = oTextWarpContent.oTxWarpStructParamarks;
        this.txWarpStruct = oTextWarpContent.oTxWarpStruct;

        this.txWarpStructParamarksNoTransform = oTextWarpContent.oTxWarpStructParamarksNoTransform;
        this.txWarpStructNoTransform = oTextWarpContent.oTxWarpStructNoTransform;
    }
    return oRecalcObj;
};

CShape.prototype.recalculate = function ()
{
    if(this.bDeleted || !this.bWordShape)
        return;
    AscFormat.ExecuteNoHistory(function()
    {
        if (this.recalcInfo.recalculateBrush) {
            this.recalculateBrush();
            this.recalcInfo.recalculateBrush = false;
        }

        if (this.recalcInfo.recalculatePen) {
            this.recalculatePen();
            this.recalcInfo.recalculatePen = false;
        }
        if (this.recalcInfo.recalculateTransform) {
            this.recalculateTransform();
            this.recalcInfo.recalculateTransform = false;
        }

        if (this.recalcInfo.recalculateGeometry) {
            this.recalculateGeometry();
            this.recalcInfo.recalculateGeometry = false;
        }

        if(this.recalcInfo.recalculateBounds)
        {
            this.recalculateBounds();
            this.recalcInfo.recalculateBounds = false;
        }
        if(this.recalcInfo.recalculateWrapPolygon)
        {
            this.recalculateWrapPolygon();
            this.recalcInfo.recalculateWrapPolygon = false;
        }
        this.bNeedUpdatePosition = true;
    }, this, []);
};

CShape.prototype.recalculateText = function()
{
    if(!this.bWordShape)
        return;
    AscFormat.ExecuteNoHistory(function()
    {
        if(this.bWordShape)
        {
            if (this.recalcInfo.recalculateTxBoxContent)
            {
                this.recalcInfo.oContentMetrics = this.recalculateTxBoxContent();
                this.recalcInfo.recalculateTxBoxContent = false;
                this.recalcInfo.AllDrawings = [];
                var oContent = this.getDocContent();
                if(oContent)
                {
                    oContent.GetAllDrawingObjects(this.recalcInfo.AllDrawings);
                }
            }
        }
        else
        {
            if (this.recalcInfo.recalculateContent)
            {
                this.recalcInfo.oContentMetrics = this.recalculateContent();
                this.recalcInfo.recalculateContent = false;
            }
        }

        if (this.recalcInfo.recalculateTransformText) {
            this.recalculateTransformText();
        }
    }, this, []);
};

CShape.prototype.recalculateWrapPolygon = function()
{
    if(this.parent && this.parent.wrappingPolygon)
    {
        this.parent.wrappingPolygon.calculateRelToAbs(this.localTransform, this);
    }
};

CShape.prototype.getArrayWrapPolygons = function()
{
    var ret;
    if(this.spPr && this.spPr.geometry)
        ret =  this.spPr.geometry.getArrayPolygons();
    else
        ret = [];
    var t = this.localTransform;
    for(var i = 0; i < ret.length; ++i)
    {
        var polygon = ret[i];
        for(var j = 0; j < polygon.length; ++j)
        {
            var p = polygon[j];
            var x = t.TransformPointX(p.x, p.y);
            var y = t.TransformPointY(p.x, p.y);
            p.x = x;
            p.y = y;
        }
    }
    return ret;
};

CShape.prototype.recalculateContent = function()
{
    var content = this.getDocContent();
    if(content)
    {
        var body_pr = this.getBodyPr();
        var oRecalcObj = this.recalculateDocContent(content, body_pr);
        this.contentHeight = oRecalcObj.contentH;
        this.contentWidth = oRecalcObj.w;
        return oRecalcObj;
    }
    return null;
};

CShape.prototype.recalculateTransform =  function()
{
    this.recalculateLocalTransform(this.localTransform);
};



CShape.prototype.updatePosition = function(x, y)
{
    this.posX = x;
    this.posY = y;
    if(!this.group)
    {
        this.x = this.localX + x;
        this.y = this.localY + y;
    }
    else
    {
        this.x = this.localX;
        this.y = this.localY;
    }
    this.updateTransformMatrix();
};

CShape.prototype.checkShapeChild = function()
{
    return false;
};

CShape.prototype.checkShapeChildTransform = function()
{
};
CShape.prototype.GetAllParagraphs = function(Props, ParaArray)
{
    var oContent = this.getDocContent();
    oContent && oContent.GetAllParagraphs(Props, ParaArray);
};



CShape.prototype.getArrayWrapIntervals = function(x0,y0, x1, y1, Y0Sp, Y1Sp, LeftField, RightField, arr_intervals, bMathWrap)
{
    return this.parent.getArrayWrapIntervals(x0,y0, x1, y1, Y0Sp, Y1Sp, LeftField, RightField, arr_intervals, bMathWrap);
};
CShape.prototype.updateTransformMatrix = function()
{
    var oParentTransform = null;
    if(this.parent && this.parent.Get_ParentParagraph)
    {
        var oParagraph = this.parent.Get_ParentParagraph();
        if(oParagraph)
        {
            oParentTransform = oParagraph.Get_ParentTextTransform();
        }
    }
    this.transform = this.localTransform.CreateDublicate();
    global_MatrixTransformer.TranslateAppend(this.transform, this.posX, this.posY);
    if(oParentTransform)
    {
        global_MatrixTransformer.MultiplyAppend(this.transform, oParentTransform);
    }
    this.invertTransform = global_MatrixTransformer.Invert(this.transform);

    if(this.localTransformText)
    {
        this.transformText = this.localTransformText.CreateDublicate();
        global_MatrixTransformer.TranslateAppend(this.transformText, this.posX, this.posY);
        if(oParentTransform)
        {
            global_MatrixTransformer.MultiplyAppend(this.transformText, oParentTransform);
        }
        this.invertTransformText = global_MatrixTransformer.Invert(this.transformText);
    }
    if(this.localTransformTextWordArt)
    {
        this.transformTextWordArt = this.localTransformTextWordArt.CreateDublicate();
        global_MatrixTransformer.TranslateAppend(this.transformTextWordArt, this.posX, this.posY);
        if(oParentTransform)
        {
            global_MatrixTransformer.MultiplyAppend(this.transformTextWordArt, oParentTransform);
        }
        this.invertTransformTextWordArt = global_MatrixTransformer.Invert(this.transformTextWordArt);
    }

    this.checkShapeChildTransform();
    this.checkContentDrawings();
};

CShape.prototype.checkContentDrawings = function()
{
    if(this.textBoxContent)
    {
        var all_drawings = this.textBoxContent.GetAllDrawingObjects([]);
        for(var i = 0; i < all_drawings.length; ++i)
        {
            all_drawings[i].GraphicObj.updateTransformMatrix();
        }
    }
};

CShape.prototype.applyParentTransform = function(transform)
{
    global_MatrixTransformer.MultiplyAppend(this.transform, transform);
    global_MatrixTransformer.MultiplyAppend(this.transformText, transform);
    this.invertTransform = global_MatrixTransformer.Invert(this.transform);
    this.invertTransformText = global_MatrixTransformer.Invert(this.transformText);
};

CShape.prototype.recalculateShapeStyleForParagraph = function()
{
    var styles = editor.WordControl.m_oLogicDocument.Styles;

    this.textStyleForParagraph = {TextPr: g_oDocumentDefaultTextPr.Copy(), ParaPr: g_oDocumentDefaultParaPr.Copy()};
    this.textStyleForParagraph.ParaPr.Merge( styles.Default.ParaPr.Copy() );
    this.textStyleForParagraph.TextPr.Merge( styles.Default.TextPr.Copy() );

    if(this.style && this.style.fontRef)
    {
        //this.textStyleForParagraph.ParaPr.Spacing.Line = 1;
        this.textStyleForParagraph.TextPr.Color.Auto = false;
        var shape_text_pr = new CTextPr();
        if(this.style.fontRef.Color)
        {
            shape_text_pr.Unifill = AscFormat.CreateUniFillByUniColorCopy(this.style.fontRef.Color);
        }
        if(this.style.fontRef.idx === AscFormat.fntStyleInd_major)
        {
            shape_text_pr.RFonts.Ascii = { Name: "+mj-lt", Index : -1 };
            shape_text_pr.RFonts.EastAsia = { Name: "+mj-ea", Index : -1 };
            shape_text_pr.RFonts.CS = { Name: "+mj-cs", Index : -1 };
        }
        else if( this.style.fontRef.idx === AscFormat.fntStyleInd_minor)
        {
            shape_text_pr.RFonts.Ascii = { Name: "+mn-lt", Index : -1 };
            shape_text_pr.RFonts.EastAsia = { Name: "+mn-ea", Index : -1 };
            shape_text_pr.RFonts.CS = { Name: "+mn-cs", Index : -1 };
        }
        shape_text_pr.FontRef = this.style.fontRef.createDuplicate();
        this.textStyleForParagraph.TextPr.Merge(shape_text_pr);
    }
};
CShape.prototype.Get_ShapeStyleForPara = function()
{
    if(this.recalcInfo.recalculateShapeStyleForParagraph)
    {
        this.recalculateShapeStyleForParagraph();
        this.recalcInfo.recalculateShapeStyleForParagraph = false;
    }
    return this.textStyleForParagraph;
};

CShape.prototype.Refresh_RecalcData = function(data)
{
    this.recalcTxBoxContent();
    this.recalcTransformText();
    this.Refresh_RecalcData2();
};

CShape.prototype.Refresh_RecalcData2 = function()
{

    var oController = this.getDrawingObjectsController();
    if(oController && AscFormat.getTargetTextObject(oController) === this)
    {
        this.recalcInfo.recalcTitle = this.getDocContent();
        this.recalcInfo.bRecalculatedTitle = true;
    }
    if(this.checkAutofit && this.checkAutofit())
    {
        this.handleUpdateExtents();
        if(this.group)
        {
            var oMainGroup = this.getMainGroup();
            if(oMainGroup.parent)
            {
                oMainGroup.parent.Refresh_RecalcData({Type: AscDFH.historyitem_Drawing_SetExtent});
            }
        }
        else
        {
            if(this.parent)
            {
                this.parent.Refresh_RecalcData({Type: AscDFH.historyitem_Drawing_SetExtent});
            }
        }
        return;
    }
    this.recalcTxBoxContent();
    this.recalcTransformText();
    this.addToRecalculate();

    var HdrFtr = this.IsHdrFtr(true);
    if (HdrFtr)
        HdrFtr.Refresh_RecalcData2();
};

CShape.prototype.Get_StartPage_Absolute = function()
{
    return 0;
};
CShape.prototype.Get_AbsolutePage = function(CurPage)
{
    var oDrawing = this.GetParaDrawing();
    if(oDrawing)
    {
        return oDrawing.PageNum;
    }
    return 0;
};
CShape.prototype.Get_AbsoluteColumn = function(CurPage)
{
    return 0;
};
CShape.prototype.Get_Numbering = function()
{
    return editor.WordControl.m_oLogicDocument.Numbering;
};
CShape.prototype.Get_TableStyleForPara = function()
{
    return null;
};
CShape.prototype.IsCell = function(isReturnCell)
{
	if (true === isReturnCell)
		return null;

    return false;
};

CShape.prototype.hitInTextRect = function(x, y)
{
    return this.hitInTextRectWord(x, y);
};

CShape.prototype.Set_CurrentElement = function(bUpdate, pageIndex)
{

    if(this.group)
    {
        var main_group = this.group.getMainGroup();
        para_drawing = main_group.parent;
    }
    else
    {
        para_drawing = this.parent;
    }
    if(para_drawing && para_drawing.DocumentContent)
    {
        var drawing_objects = editor.WordControl.m_oLogicDocument.DrawingObjects;
        drawing_objects.resetSelection(true);
        var para_drawing;
        if(this.group)
        {
            var main_group = this.group.getMainGroup();
            drawing_objects.selectObject(main_group, pageIndex);
            main_group.selectObject(this, pageIndex);
            main_group.selection.textSelection = this;
            drawing_objects.selection.groupSelection = main_group;
            para_drawing = main_group.parent;
        }
        else
        {
            drawing_objects.selectObject(this, pageIndex);
            drawing_objects.selection.textSelection = this;
            para_drawing = this.parent;
        }

        if (para_drawing && para_drawing.Parent instanceof Paragraph)
            para_drawing.Parent.Document_SetThisElementCurrent(false);

        var hdr_ftr = para_drawing.DocumentContent.IsHdrFtr(true);
        if(hdr_ftr)
        {
            hdr_ftr.Content.Set_DocPosType(docpostype_DrawingObjects);
            hdr_ftr.Set_CurrentElement(bUpdate);
        }
        else
        {
            drawing_objects.document.Set_DocPosType(docpostype_DrawingObjects);
            drawing_objects.document.Selection.Use = true;

            if ( true === bUpdate )
            {
                drawing_objects.document.Document_UpdateInterfaceState();
                drawing_objects.document.Document_UpdateRulersState();
                drawing_objects.document.Document_UpdateSelectionState();
            }
        }
    }
};

CShape.prototype.GetParaDrawing = function()
{
    if(this.group)
    {
        var cur_group = this.group;
        while(cur_group.group)
        {
            cur_group = cur_group.group;
        }
        if(cur_group.parent)
        {
            return cur_group.parent;
        }
    }
    else
    {
        if(this.parent)
        {
            return this.parent;
        }
    }
    return null;
};


CShape.prototype.Get_StartPage_Relative = function()
{
    return 0;
};
CShape.prototype.CheckTableCoincidence = function(table)
{
    var para_drawing = this.GetParaDrawing();
    if(para_drawing && para_drawing.DocumentContent)
    {
        return para_drawing.DocumentContent.CheckTableCoincidence(table);
    }
    return false;
};

CShape.prototype.GetPrevElementEndInfo = function(CurElement)
{
    var para_drawing = this.GetParaDrawing();
    if(isRealObject(para_drawing) && isRealObject(para_drawing.DocumentContent) && (para_drawing.DocumentContent.GetPrevElementEndInfo) )
    {
        var parent_paragraph = para_drawing.Get_ParentParagraph();
        if(parent_paragraph)
            return para_drawing.DocumentContent.GetPrevElementEndInfo(parent_paragraph);
    }
    return null;
};
CShape.prototype.Is_ThisElementCurrent = function(CurElement)
{
    return editor.WordControl.m_oLogicDocument.DrawingObjects.getTargetDocContent() === this.getDocContent();
};
CShape.prototype.Is_UseInDocument = function()
{
    if(this.group)
    {
        var aSpTree = this.group.spTree;
        for(var i = 0; i < aSpTree.length; ++i)
        {
            if(aSpTree[i] === this)
            {
                return this.group.Is_UseInDocument();
            }
        }
        return false;
    }
    if(this.parent && this.parent.Is_UseInDocument && this.parent.GraphicObj === this)
    {
        return this.parent.Is_UseInDocument();
    }
    return false;
};
CShape.prototype.IsHdrFtr = function(bool)
{
    if(!this.group)
    {
        if(isRealObject(this.parent) && isRealObject(this.parent.DocumentContent))
            return this.parent.DocumentContent.IsHdrFtr(bool);
    }
    else
    {
        var cur_group = this.group;
        while(cur_group.group)
            cur_group = cur_group.group;
        if(isRealObject(cur_group.parent) && isRealObject(cur_group.parent.DocumentContent))
            return cur_group.parent.DocumentContent.IsHdrFtr(bool);
    }
    return bool ? null : false;
};
CShape.prototype.IsFootnote = function(bReturnFootnote)
{
	if(!this.group)
	{
		if(isRealObject(this.parent) && isRealObject(this.parent.DocumentContent))
			return this.parent.DocumentContent.IsFootnote(bReturnFootnote);
	}
	else
	{
		var cur_group = this.group;
		while(cur_group.group)
			cur_group = cur_group.group;
		if(isRealObject(cur_group.parent) && isRealObject(cur_group.parent.DocumentContent))
			return cur_group.parent.DocumentContent.IsFootnote(bReturnFootnote);
	}
	return bReturnFootnote ? null : false;
};
CShape.prototype.OnContentReDraw = function()
{
    if(!isRealObject(this.group))
    {
        if(isRealObject(this.parent))
        {
            this.parent.OnContentReDraw();
        }
    }
    else
    {
        var cur_group = this.group;
        while(isRealObject(cur_group.group))
            cur_group = cur_group.group;

        if(isRealObject(cur_group) && isRealObject(cur_group.parent))
            cur_group.parent.OnContentReDraw();
    }

};


CShape.prototype.Get_TextBackGroundColor = function()
{
    return undefined;
};
CShape.prototype.documentStatistics = function(stats)
{
    var content = this.getDocContent();
    return content && content.CollectDocumentStatistics(stats);
};

CShape.prototype.checkPosTransformText = function()
{
    if(AscFormat.isRealNumber(this.posX) && AscFormat.isRealNumber(this.posY))
    {
        this.transformText = this.localTransformText.CreateDublicate();
        global_MatrixTransformer.TranslateAppend(this.transformText, this.posX, this.posY);
        this.invertTransformText = global_MatrixTransformer.Invert(this.transformText);

        if(this.localTransformTextWordArt)
        {
            this.transformTextWordArt = this.localTransformTextWordArt.CreateDublicate();
            global_MatrixTransformer.TranslateAppend(this.transformTextWordArt, this.posX, this.posY);
            this.invertTransformTextWordArt = global_MatrixTransformer.Invert(this.transformTextWordArt);
        }
    }
};
CShape.prototype.getNearestPos = function(x, y, pageIndex)
{
    if(isRealObject(this.textBoxContent) && this.invertTransformText)
    {
        var t_x = this.invertTransformText.TransformPointX(x, y);
        var t_y = this.invertTransformText.TransformPointY(x, y);
        var nearest_pos = this.textBoxContent.Get_NearestPos(0, t_x, t_y, false);
        return nearest_pos;
    }
    return null;
};


CShape.prototype.cursorGetPos = function()
{
    var content = this.getDocContent();
    if(isRealObject(content))
    {
        var pos = content.GetCursorPosXY();
        var transform = this.transformText;
        var x = transform.TransformPointX(pos.X, pos.Y);
        var y = transform.TransformPointY(pos.X, pos.Y);
        return {X: x, Y: y};
    }
    return {X: 0, Y: 0};
};


CShape.prototype.cursorMoveAt = function( X, Y, AddToSelect )
{
    var content = this.getDocContent();
    if(isRealObject(content) && this.invertTransformText)
    {
        var t_x = this.invertTransformText.TransformPointX(X, Y);
        var t_y = this.invertTransformText.TransformPointY(X, Y);
        content.MoveCursorToXY(t_x, t_y, AddToSelect, undefined, AscFormat.isRealNumber(this.selectStartPage) ? this.selectStartPage : 0);
    }
};


CShape.prototype.Get_Styles = function()
{
    return editor.WordControl.m_oLogicDocument.Styles;
};
CShape.prototype.Is_InTable = function(bReturnTopTable)
{
    if ( true === bReturnTopTable )
        return null;

    return false;
};

CShape.prototype.Get_Numbering = function()
{
    return editor.WordControl.m_oLogicDocument.Get_Numbering();
};

CShape.prototype.Get_TableStyleForPara = function()
{
    return editor.WordControl.m_oLogicDocument.Get_TableStyleForPara();
};

CShape.prototype.Is_DrawingShape = function(bRetShape)
{
    if(bRetShape === true)
    {
        return this;
    }
    return true;
};

CShape.prototype.Is_InTable = function(bReturnTopTable)
{
    if ( true === bReturnTopTable )
        return null;

    return false;
};

CShape.prototype.canChangeWrapPolygon = function(bReturnTopTable)
{
    return true;
};

CShape.prototype.Get_ColorMap = function()
{
    return editor.WordControl.m_oLogicDocument.Get_ColorMap();
};

CShape.prototype.Is_TopDocument = function()
{
    return false;
};

CShape.prototype.recalcText = function(bResetRecalcCache)
{
    if(this.recalculateText && this.recalcTxBoxContent && this.recalculateText)
    {
        this.recalcTxBoxContent();
        this.recalcTransformText();
        if(bResetRecalcCache){
            var oContent = this.getDocContent();
            if(oContent){
                oContent.Reset_RecalculateCache();
            }
        }
        if(this.checkAutofit && this.checkAutofit())
        {
            this.recalcGeometry();
            this.recalcWrapPolygon();
            this.recalcBounds();

            this.recalcTransform();

            if(!this.group){
                if(this.parent && this.parent.Parent){
                    var Run = this.parent.Parent.Get_DrawingObjectRun( this.parent.Id );
                    if(Run){
                        Run.RecalcInfo.Measure = true;
                    }
                }
            }
        }
    }
};

CShape.prototype.getRecalcObject = function()
{
    var content = this.getDocContent && this.getDocContent();
    if(content)
    {
        return content.SaveRecalculateObject();
    }
    if(this.spTree)
    {
        var ret = [];
        for(var i = 0; i < this.spTree.length; ++i)
        {
            ret.push(this.spTree[i].getRecalcObject())
        }
        return ret;
    }
    return null;
};

CShape.prototype.setRecalcObject =  function(object)
{
    if(!object)
        return;
    var content = this.getDocContent && this.getDocContent();
    if(content)
    {
        content.LoadRecalculateObject(object);
    }
    if(Array.isArray(object) && this.spTree && this.spTree.length === object.length)
    {
        for(var i = 0;  i < this.spTree.length; ++i)
        {
            this.spTree[i].setRecalcObject(object[i]);
        }
    }
};


CShape.prototype.setStartPage = function(pageIndex, bNoResetSelectPage, bCheckContent)
{
    if(!(bNoResetSelectPage === true))
        this.selectStartPage = pageIndex;
    var content = this.getDocContent && this.getDocContent();
    if(content)
    {
        content.Set_StartPage(pageIndex);
        if(true === bCheckContent)
        {
            if(this.bWordShape && this.checkContentByCallback && this.checkContentByCallback(content,
                function(oRun){
                    for(var i = 0; i < oRun.Content.length; ++i){
                        if(oRun.Content[i].Type === para_PageNum){
                            return true;
                        }
                    }
                    return false;
                }
            ))
            {
                this.recalcInfo.recalculateTxBoxContent = true;
                this.recalcInfo.recalculateTransformText = true;
                this.recalculateText();
            }
        }
    }
    if(Array.isArray(this.spTree))
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            this.spTree[i].setStartPage && this.spTree[i].setStartPage(pageIndex, undefined, bCheckContent);
        }
    }
};
CShape.prototype.getStyles = function()
{
    return {styles: editor.WordControl.m_oLogicDocument.Styles, styleId: null};
};


CShape.prototype.getDrawingObjectsController = function()
{
    return editor.WordControl.m_oLogicDocument.DrawingObjects;
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var CShape = AscFormat.CShape;
var CImageShape = AscFormat.CImageShape;

CImageShape.prototype.Get_Theme = CShape.prototype.Get_Theme;
CImageShape.prototype.Get_ColorMap = CShape.prototype.Get_ColorMap;
CImageShape.prototype.addToRecalculate = CShape.prototype.addToRecalculate;
CImageShape.prototype.convertPixToMM = CShape.prototype.convertPixToMM;
CImageShape.prototype.getCanvasContext = CShape.prototype.getCanvasContext;
CImageShape.prototype.getHierarchy = CShape.prototype.getHierarchy;
CImageShape.prototype.getParentObjects = CShape.prototype.getParentObjects;
CImageShape.prototype.recalculateTransform = CShape.prototype.recalculateTransform;
CImageShape.prototype.recalculateBounds = CShape.prototype.recalculateBounds;
CImageShape.prototype.deselect = CShape.prototype.deselect;
CImageShape.prototype.getArrayWrapPolygons = CShape.prototype.getArrayWrapPolygons;
CImageShape.prototype.hitToHandles = CShape.prototype.hitToHandles;
CImageShape.prototype.hitInBoundingRect = CShape.prototype.hitInBoundingRect;
CImageShape.prototype.getRotateAngle = CShape.prototype.getRotateAngle;
CImageShape.prototype.recalculateWrapPolygon = CShape.prototype.recalculateWrapPolygon;
CImageShape.prototype.Is_UseInDocument = CShape.prototype.Is_UseInDocument;

CImageShape.prototype.setRecalculateInfo = function()
{
    this.recalcInfo =
    {
        recalculateBrush:          true,
        recalculatePen:            true,
        recalculateTransform:      true,
        recalculateBounds:         true,
        recalculateGeometry:       true,
        recalculateFill:           true,
        recalculateLine:           true,
        recalculateTransparent:    true,
        recalculateWrapPolygon: true
    };


    this.bNeedUpdatePosition = true;

    this.posX = null;
    this.posY = null;

    this.localTransform = new AscCommon.CMatrix();
    this.localTransformText = new AscCommon.CMatrix();
};

CImageShape.prototype.recalcBrush = function()
{
    this.recalcInfo.recalculateBrush = true;
};

CImageShape.prototype.recalcPen = function()
{
    this.recalcInfo.recalculatePen = true;
};
CImageShape.prototype.recalcTransform = function()
{
    this.recalcInfo.recalculateTransform = true;
};
CImageShape.prototype.recalcBounds = function()
{
    this.recalcInfo.recalculateBounds = true;
};
CImageShape.prototype.recalcGeometry = function()
{
    this.recalcInfo.recalculateGeometry = true;
};
CImageShape.prototype.recalcStyle = function()
{
    this.recalcInfo.recalculateStyle = true;
};
CImageShape.prototype.recalcFill = function()
{
    this.recalcInfo.recalculateFill = true;
};
CImageShape.prototype.recalcLine = function()
{
    this.recalcInfo.recalculateLine = true;
};
CImageShape.prototype.recalcTransparent = function()
{
    this.recalcInfo.recalculateTransparent = true;
};
CImageShape.prototype.recalcWrapPolygon = function()
{
    this.recalcInfo.recalculateWrapPolygon = true;
};

CImageShape.prototype.handleUpdatePosition = function()
{
    this.recalcTransform();
    this.recalcBounds();
    this.addToRecalculate();
};
CImageShape.prototype.handleUpdateExtents = function()
{
    this.recalcGeometry();
    this.recalcBounds();
    this.recalcTransform();
    this.recalcWrapPolygon();
    this.addToRecalculate();
};
CImageShape.prototype.handleUpdateRot = function()
{
    this.recalcTransform();
    this.recalcBounds();
    this.recalcWrapPolygon();
    this.addToRecalculate();
};
CImageShape.prototype.handleUpdateFlip = function()
{
    this.recalcTransform();
    this.recalcWrapPolygon();
    this.addToRecalculate();
};
CImageShape.prototype.handleUpdateFill = function()
{
    this.recalcBrush();
    this.addToRecalculate();
};
CImageShape.prototype.handleUpdateGeometry = function()
{
    this.recalcBounds();
    this.recalcGeometry();
    this.addToRecalculate();
};

CImageShape.prototype.recalculateLocalTransform = CShape.prototype.recalculateLocalTransform;
CImageShape.prototype.convertPixToMM = CShape.prototype.convertPixToMM;
CImageShape.prototype.getCanvasContext = CShape.prototype.getCanvasContext;
CImageShape.prototype.getCompiledStyle = CShape.prototype.getCompiledStyle;
CImageShape.prototype.getHierarchy = CShape.prototype.getHierarchy;
CImageShape.prototype.getParentObjects = CShape.prototype.getParentObjects;
CImageShape.prototype.recalculate = function ()
{
    if(this.bDeleted)
        return;
    AscFormat.ExecuteNoHistory(function() {
        if (this.recalcInfo.recalculateBrush) {
            this.recalculateBrush();
            this.recalcInfo.recalculateBrush = false;
        }

        if (this.recalcInfo.recalculatePen) {
            this.recalculatePen();
            this.recalcInfo.recalculatePen = false;
        }
        if (this.recalcInfo.recalculateTransform) {
            this.recalculateTransform();
            this.recalcInfo.recalculateTransform = false;
        }

        if (this.recalcInfo.recalculateGeometry) {
            this.recalculateGeometry();
            this.recalcInfo.recalculateGeometry = false;
        }
        if (this.recalcInfo.recalculateBounds) {
            this.recalculateBounds();
            this.recalcInfo.recalculateBounds = false;
        }
        if(this.recalcInfo.recalculateWrapPolygon)
        {
            this.recalculateWrapPolygon();
            this.recalcInfo.recalculateWrapPolygon = false;
        }
        this.bNeedUpdatePosition = true;
    }, this, []);
};
CImageShape.prototype.canChangeWrapPolygon = CShape.prototype.canChangeWrapPolygon;
CImageShape.prototype.hitInInnerArea = CShape.prototype.hitInInnerArea;
CImageShape.prototype.hitInPath = CShape.prototype.hitInPath;
CImageShape.prototype.hitToHandles = CShape.prototype.hitToHandles;
CImageShape.prototype.hitInBoundingRect = CShape.prototype.hitInBoundingRect;
CImageShape.prototype.check_bounds = CShape.prototype.check_bounds;
CImageShape.prototype.updatePosition = CShape.prototype.updatePosition;
CImageShape.prototype.updateTransformMatrix = CShape.prototype.updateTransformMatrix;
CImageShape.prototype.getDrawingDocument = CShape.prototype.getDrawingDocument;
CImageShape.prototype.getArrayWrapIntervals = CShape.prototype.getArrayWrapIntervals;
CImageShape.prototype.getBounds = CShape.prototype.getBounds;
CImageShape.prototype.setStartPage = CShape.prototype.setStartPage;
CImageShape.prototype.getRecalcObject = CShape.prototype.getRecalcObject;
CImageShape.prototype.setRecalcObject = CShape.prototype.setRecalcObject;
CImageShape.prototype.checkContentDrawings = function()
{};
CImageShape.prototype.checkShapeChildTransform = function()
{
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var CShape = AscFormat.CShape;
var CGroupShape = AscFormat.CGroupShape;

CGroupShape.prototype.addToRecalculate = CShape.prototype.addToRecalculate;


CGroupShape.prototype.Get_Theme = CShape.prototype.Get_Theme;
CGroupShape.prototype.setStartPage = CShape.prototype.setStartPage;

CGroupShape.prototype.handleUpdateFill = function()
{
    for(var i = 0; i < this.spTree.length; ++i)
    {
        this.spTree[i].handleUpdateFill();
    }
};
CGroupShape.prototype.recalcText = function(bResetCache)
{
    if(this.spTree)
    {
        for(var i = 0; i < this.spTree.length; ++i)
        {
            if(this.spTree[i].recalcText)
            {
                this.spTree[i].recalcText(bResetCache);
            }
        }
    }
};
CGroupShape.prototype.handleUpdateLn = function()
{
    for(var i = 0; i < this.spTree.length; ++i)
    {
        this.spTree[i].handleUpdateLn();
    }
};

CGroupShape.prototype.getRecalcObject = CShape.prototype.getRecalcObject;
CGroupShape.prototype.setRecalcObject = CShape.prototype.setRecalcObject;
CGroupShape.prototype.Get_ColorMap = CShape.prototype.Get_ColorMap;
CGroupShape.prototype.Is_UseInDocument = CShape.prototype.Is_UseInDocument;


CGroupShape.prototype.getTargetDocContent = AscFormat.DrawingObjectsController.prototype.getTargetDocContent;
CGroupShape.prototype.documentUpdateInterfaceState = function()
{
    if(this.selection.textSelection)
    {
        this.selection.textSelection.getDocContent().Document_UpdateInterfaceState();
    }
    else if(this.selection.chartSelection && this.selection.chartSelection.selection.textSelection)
    {
        this.selection.chartSelection.selection.textSelection.getDocContent().Document_UpdateInterfaceState();
    }
    else
    {
        var para_pr = AscFormat.DrawingObjectsController.prototype.getParagraphParaPr.call(this);
        var text_pr = AscFormat.DrawingObjectsController.prototype.getParagraphTextPr.call(this);
        if(!para_pr)
        {
            para_pr = new CParaPr();
        }
        if(!text_pr)
        {
            text_pr = new CTextPr();
        }

        var theme = this.Get_Theme();
        if(theme && theme.themeElements && theme.themeElements.fontScheme)
        {
            if(text_pr.FontFamily)
            {
                text_pr.FontFamily.Name =  theme.themeElements.fontScheme.checkFont(text_pr.FontFamily.Name);
            }
            if(text_pr.RFonts)
            {
                if(text_pr.RFonts.Ascii)
                    text_pr.RFonts.Ascii.Name     = theme.themeElements.fontScheme.checkFont(text_pr.RFonts.Ascii.Name);
                if(text_pr.RFonts.EastAsia)
                    text_pr.RFonts.EastAsia.Name  = theme.themeElements.fontScheme.checkFont(text_pr.RFonts.EastAsia.Name);
                if(text_pr.RFonts.HAnsi)
                    text_pr.RFonts.HAnsi.Name     = theme.themeElements.fontScheme.checkFont(text_pr.RFonts.HAnsi.Name);
                if(text_pr.RFonts.CS)
                    text_pr.RFonts.CS.Name        = theme.themeElements.fontScheme.checkFont(text_pr.RFonts.CS.Name);
            }
        }
        if(text_pr.Unifill)
        {
            var RGBAColor = text_pr.Unifill.getRGBAColor();
            text_pr.Color = new CDocumentColor(RGBAColor.R, RGBAColor.G, RGBAColor.B, false);
        }
        if(text_pr.Shd && text_pr.Shd.Unifill && theme)
        {
            text_pr.Shd.Unifill.check(theme, this.Get_ColorMap());
        }

        editor.UpdateParagraphProp(para_pr);
        editor.UpdateTextPr(text_pr);
    }
};
CGroupShape.prototype.setRecalculateInfo = function()
{
    this.recalcInfo =
    {
        recalculateBrush: true,
        recalculatePen: true,
        recalculateTransform: true,
        recalculateArrGraphicObjects: true,
        recalculateBounds: true,
        recalculateScaleCoefficients: true,
        recalculateWrapPolygon: true
    };
    this.localTransform = new AscCommon.CMatrix();
    this.posX = null;
    this.posY = null;
    this.bNeedUpdatePosition = true;
};

CGroupShape.prototype.recalcTransform = function()
{
    if(!editor || !editor.noCreatePoint || editor.exucuteHistory)
    {
        this.recalcInfo.recalculateScaleCoefficients = true;
        this.recalcInfo.recalculateTransform = true;
        for(var i = 0; i < this.spTree.length; ++i)
        {
            this.spTree[i].recalcTransform();
        }
    }
};

CGroupShape.prototype.recalculate = function()
{

    if(this.bDeleted)
        return;
    AscFormat.ExecuteNoHistory(function()
    {
        if(this.recalcInfo.recalculateBrush)
        {
            this.recalculateBrush();
            this.recalcInfo.recalculateBrush = false;
        }
        if(this.recalcInfo.recalculatePen)
        {
            this.recalculatePen();
            this.recalcInfo.recalculatePen = false;
        }
        if(this.recalcInfo.recalculateTransform)
        {
            this.recalculateTransform();
            this.recalcInfo.recalculateTransform = false;
        }
        if(this.recalcInfo.recalculateArrGraphicObjects)
        {
            this.recalculateArrGraphicObjects();
            this.recalcInfo.recalculateArrGraphicObjects = false;
        }
        for(var i = 0; i < this.spTree.length; ++i)
        {
            this.spTree[i].recalculate();
        }
        if(this.recalcInfo.recalculateBounds)
        {
            this.recalculateBounds();
            this.recalcInfo.recalculateBounds = false;
        }
        if(this.recalcInfo.recalculateWrapPolygon)
        {
            this.recalculateWrapPolygon();
            this.recalcInfo.recalculateWrapPolygon = false;
        }
    }, this, []);
};

CGroupShape.prototype.recalcBounds = function()
{
    this.recalcInfo.recalculateBounds = true;
    for(var i = 0; i < this.spTree.length; ++i)
    {
        this.spTree[i].recalcBounds();
    }
};

CGroupShape.prototype.addToDrawingObjects =  CShape.prototype.addToDrawingObjects;
CGroupShape.prototype.setDrawingObjects = CShape.prototype.setDrawingObjects;
CGroupShape.prototype.setDrawingBase = CShape.prototype.setDrawingBase;
CGroupShape.prototype.deleteDrawingBase = CShape.prototype.deleteDrawingBase;
CGroupShape.prototype.addToRecalculate = CShape.prototype.addToRecalculate;
CGroupShape.prototype.convertPixToMM = CShape.prototype.convertPixToMM;
CGroupShape.prototype.getCanvasContext = CShape.prototype.getCanvasContext;
CGroupShape.prototype.getHierarchy = CShape.prototype.getHierarchy;
CGroupShape.prototype.getParentObjects = CShape.prototype.getParentObjects;
CGroupShape.prototype.recalculateTransform = CShape.prototype.recalculateTransform;
CGroupShape.prototype.deselect = CShape.prototype.deselect;
CGroupShape.prototype.hitToHandles = CShape.prototype.hitToHandles;
CGroupShape.prototype.hitInBoundingRect = CShape.prototype.hitInBoundingRect;
CGroupShape.prototype.getRotateAngle = CShape.prototype.getRotateAngle;
CGroupShape.prototype.getDrawingDocument = CShape.prototype.getDrawingDocument;
CGroupShape.prototype.handleUpdatePosition = function()
{
    this.recalcBounds();
    this.recalcTransform();
    this.addToRecalculate();
    for(var i = 0; i < this.spTree.length; ++i)
    {
        if(this.spTree[i].recalcTransform)
        {
            this.spTree[i].recalcTransform();
        }
    }
};
CGroupShape.prototype.handleUpdateRot = function()
{
    this.recalcTransform();
    this.recalcBounds();
    this.recalcWrapPolygon();
    this.addToRecalculate();
};
CGroupShape.prototype.recalcWrapPolygon = function()
{
    this.recalcInfo.recalculateWrapPolygon = true;
};
CGroupShape.prototype.handleUpdateFlip = function()
{
    this.recalcTransform();
    this.recalcBounds();
    this.recalcWrapPolygon();
    this.addToRecalculate();
};
CGroupShape.prototype.handleUpdateChildOffset = function()
{
    this.recalcTransform();
    this.recalcBounds();
    this.recalcWrapPolygon();
    this.addToRecalculate()
};
CGroupShape.prototype.handleUpdateChildExtents = function()
{
    this.recalcTransform();
    this.recalcBounds();
    this.recalcWrapPolygon();
    this.addToRecalculate()
};

CGroupShape.prototype.recalculateWrapPolygon = CShape.prototype.recalculateWrapPolygon;

CGroupShape.prototype.getArrayWrapPolygons = function()
{
    var arr_wrap_polygons = [];
    for(var i = 0; i < this.spTree.length; ++i)
    {
        arr_wrap_polygons = arr_wrap_polygons.concat(this.spTree[i].getArrayWrapPolygons());
    }
    return arr_wrap_polygons;
};


CGroupShape.prototype.recalculateTransform = CShape.prototype.recalculateTransform;
CGroupShape.prototype.updatePosition = CShape.prototype.updatePosition;


CGroupShape.prototype.checkShapeChild = function()
{
    return false;
};

CGroupShape.prototype.checkShapeChildTransform = function()
{
    for(var i = 0;i < this.spTree.length; ++i)
    {
        this.spTree[i].updatePosition(this.posX, this.posY);
    }
};


CGroupShape.prototype.getArrayWrapIntervals = CShape.prototype.getArrayWrapIntervals;

CGroupShape.prototype.updateTransformMatrix = CShape.prototype.updateTransformMatrix;
CGroupShape.prototype.recalculateLocalTransform = CShape.prototype.recalculateLocalTransform;
CGroupShape.prototype.checkContentDrawings = function()
{
};

CGroupShape.prototype.applyParentTransform = function(transform)
{
};

CGroupShape.prototype.Refresh_RecalcData = function(data)
{
    switch (data.Type)
    {
        case AscDFH.historyitem_GroupShapeAddToSpTree:
        case AscDFH.historyitem_GroupShapeRemoveFromSpTree:
        {
            if(!this.group)
            {
                this.recalcInfo.recalculateArrGraphicObjects = true;
                this.addToRecalculate();
            }
            else
            {
                this.group.handleUpdateSpTree();
            }
        }
    }
    this.Refresh_RecalcData2();
};

CGroupShape.prototype.Refresh_RecalcData2 = function()
{
    this.addToRecalculate();
};

CGroupShape.prototype.documentStatistics = function(stat)
{
    for(var i = 0; i < this.spTree.length; ++i)
    {
        if(this.spTree[i].documentStatistics)
            this.spTree[i].documentStatistics(stat);
    }
};

CGroupShape.prototype.recalculateText = function()
{
    for(var i = 0; i < this.spTree.length; ++i)
    {
        if(this.spTree[i].recalculateText)
            this.spTree[i].recalculateText();
    }
};

CGroupShape.prototype.recalculateBounds = function()
{
    var sp_tree = this.spTree;
    var x_arr_max = [], y_arr_max = [], x_arr_min = [], y_arr_min = [];
    for(var i = 0; i < sp_tree.length; ++i)
    {
        sp_tree[i].recalculate();
        var bounds = sp_tree[i].bounds;
        var l = bounds.l;
        var r = bounds.r;
        var t = bounds.t;
        var b = bounds.b;
        x_arr_max.push(r);
        x_arr_min.push(l);
        y_arr_max.push(b);
        y_arr_min.push(t);
    }


    //if(!this.group)
    {
        var tr = this.localTransform;
        var arr_p_x = [];
        var arr_p_y = [];
        arr_p_x.push(tr.TransformPointX(0,0));
        arr_p_y.push(tr.TransformPointY(0,0));
        arr_p_x.push(tr.TransformPointX(this.extX,0));
        arr_p_y.push(tr.TransformPointY(this.extX,0));
        arr_p_x.push(tr.TransformPointX(this.extX,this.extY));
        arr_p_y.push(tr.TransformPointY(this.extX,this.extY));
        arr_p_x.push(tr.TransformPointX(0,this.extY));
        arr_p_y.push(tr.TransformPointY(0,this.extY));

        x_arr_max = x_arr_max.concat(arr_p_x);
        x_arr_min = x_arr_min.concat(arr_p_x);
        y_arr_max = y_arr_max.concat(arr_p_y);
        y_arr_min = y_arr_min.concat(arr_p_y);
    }

    this.bounds.x = Math.min.apply(Math, x_arr_min);
    this.bounds.y = Math.min.apply(Math, y_arr_min);
    this.bounds.l = this.bounds.x;
    this.bounds.t = this.bounds.y;
    this.bounds.r = Math.max.apply(Math, x_arr_max);
    this.bounds.b = Math.max.apply(Math, y_arr_max);
    this.bounds.w = this.bounds.r - this.bounds.l;
    this.bounds.h = this.bounds.b - this.bounds.t;
};


CGroupShape.prototype.getBoundsPos = function()
{
    var sp_tree = this.spTree;
    var x_arr_max = [], y_arr_max = [], x_arr_min = [], y_arr_min = [];
    for(var i = 0; i < sp_tree.length; ++i)
    {
        var bounds = sp_tree[i].bounds;
        var l = sp_tree[i].x;
        var r = sp_tree[i].x + sp_tree[i].extX;
        var t = sp_tree[i].y;
        var b = sp_tree[i].y + sp_tree[i].extY;
        x_arr_max.push(r);
        x_arr_min.push(l);
        y_arr_max.push(b);
        y_arr_min.push(t);
    }
    return {x: Math.min.apply(Math, x_arr_min), y: Math.min.apply(Math, y_arr_min)};
};


CGroupShape.prototype.getAbsolutePos = function()
{
    var sp_tree = this.spTree;
    var x_arr_max = [], y_arr_max = [], x_arr_min = [], y_arr_min = [];
    for(var i = 0; i < sp_tree.length; ++i)
    {
        var bounds = sp_tree[i].bounds;
        var l = sp_tree[i].x;
        var r = sp_tree[i].x + sp_tree[i].extX;
        var t = sp_tree[i].y;
        var b = sp_tree[i].y + sp_tree[i].extY;
        x_arr_max.push(r);
        x_arr_min.push(l);
        y_arr_max.push(b);
        y_arr_min.push(t);
    }
    return {x: Math.min.apply(Math, x_arr_min), y: Math.min.apply(Math, y_arr_min)};
};

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var CShape = AscFormat.CShape;
var CChartSpace = AscFormat.CChartSpace;

CChartSpace.prototype.recalculateTransform = CShape.prototype.recalculateTransform;
CChartSpace.prototype.recalculateBounds =  function()
{
    var t = this.localTransform;
    var arr_p_x = [];
    var arr_p_y = [];
    arr_p_x.push(t.TransformPointX(0,0));
    arr_p_y.push(t.TransformPointY(0,0));
    arr_p_x.push(t.TransformPointX(this.extX,0));
    arr_p_y.push(t.TransformPointY(this.extX,0));
    arr_p_x.push(t.TransformPointX(this.extX,this.extY));
    arr_p_y.push(t.TransformPointY(this.extX,this.extY));
    arr_p_x.push(t.TransformPointX(0,this.extY));
    arr_p_y.push(t.TransformPointY(0,this.extY));

    this.bounds.x = Math.min.apply(Math, arr_p_x);
    this.bounds.y = Math.min.apply(Math, arr_p_y);
    this.bounds.l = this.bounds.x;
    this.bounds.t = this.bounds.y;
    this.bounds.r = Math.max.apply(Math, arr_p_x);
    this.bounds.b = Math.max.apply(Math, arr_p_y);
    this.bounds.w = this.bounds.r - this.bounds.l;
    this.bounds.h = this.bounds.b - this.bounds.t;
};
CChartSpace.prototype.deselect = CShape.prototype.deselect;
CChartSpace.prototype.hitToHandles = CShape.prototype.hitToHandles;
CChartSpace.prototype.hitInBoundingRect = CShape.prototype.hitInBoundingRect;
CChartSpace.prototype.getRotateAngle = CShape.prototype.getRotateAngle;
CChartSpace.prototype.getInvertTransform = CShape.prototype.getInvertTransform;
CChartSpace.prototype.hit = CShape.prototype.hit;
CChartSpace.prototype.hitInInnerArea = CShape.prototype.hitInInnerArea;
CChartSpace.prototype.hitInPath = CShape.prototype.hitInPath;
CChartSpace.prototype.check_bounds = CShape.prototype.check_bounds;
CChartSpace.prototype.Get_Theme = CShape.prototype.Get_Theme;
CChartSpace.prototype.Get_ColorMap = CShape.prototype.Get_ColorMap;
CChartSpace.prototype.Get_AbsolutePage = CShape.prototype.Get_AbsolutePage;
CChartSpace.prototype.GetParaDrawing = CShape.prototype.GetParaDrawing;

CChartSpace.prototype.handleUpdateFill = function()
{
    this.recalcInfo.recalculatePenBrush = true;
    this.recalcInfo.recalculateBrush = true;
    this.recalcInfo.recalculateChart = true;
    this.addToRecalculate();
};
CChartSpace.prototype.handleUpdateLn = function()
{
    this.recalcInfo.recalculatePenBrush = true;
    this.recalcInfo.recalculatePen = true;
    this.recalcInfo.recalculateChart = true;
    this.addToRecalculate();
};

CChartSpace.prototype.setRecalculateInfo = function()
{
    this.recalcInfo =
    {
        recalcTitle: null,
        recalculateTransform: true,
        recalculateBounds:    true,
        recalculateChart:     true,
        recalculateSeriesColors: true,
        recalculateMarkers: true,
        recalculateGridLines: true,
        recalculateDLbls: true,
        recalculateAxisLabels: true,
        dataLbls:[],
        axisLabels: [],
        recalculateAxisVal: true,
        recalculateAxisCat: true ,
        recalculateAxisTickMark: true,
        recalculateBrush: true,
        recalculatePen: true,
        recalculatePlotAreaBrush: true,
        recalculatePlotAreaPen: true,
        recalculateHiLowLines: true,
        recalculateUpDownBars: true,
        recalculateLegend: true,
        recalculateWrapPolygon: true,
        recalculatePenBrush: true,
        recalculateTextPr: true
    };

    this.chartObj = null;
    this.rectGeometry = AscFormat.ExecuteNoHistory(function(){return  AscFormat.CreateGeometry("rect");},  this, []);
    this.bNeedUpdatePosition = true;
};
CChartSpace.prototype.recalcTransform = function()
{
    this.recalcInfo.recalculateTransform = true;
};
CChartSpace.prototype.recalcBounds = function()
{
    this.recalcInfo.recalculateBounds = true;
};
CChartSpace.prototype.recalcWrapPolygon = function()
{
    this.recalcInfo.recalculateWrapPolygon = true;
};
CChartSpace.prototype.recalcChart = function()
{
    this.recalcInfo.recalculateChart = true;
};
CChartSpace.prototype.recalcSeriesColors = function()
{
    this.recalcInfo.recalculateSeriesColors = true;
};

CChartSpace.prototype.recalcDLbls = function()
{
    this.recalcInfo.recalculateDLbls = true;
};

CChartSpace.prototype.addToSetPosition = function(dLbl)
{
    if(dLbl instanceof AscFormat.CDLbl)
        this.recalcInfo.dataLbls.push(dLbl);
    else if(dLbl instanceof AscFormat.CTitle)
        this.recalcInfo.axisLabels.push(dLbl);
};

CChartSpace.prototype.addToRecalculate = CShape.prototype.addToRecalculate;

CChartSpace.prototype.handleUpdatePosition = function()
{
    this.recalcTransform();
    this.recalcBounds();
    this.addToRecalculate();
};
CChartSpace.prototype.handleUpdateExtents = function()
{
    this.recalcChart();
    this.recalcBounds();
    this.recalcTransform();
    this.recalcWrapPolygon();
    this.recalcTitles();
    this.handleUpdateInternalChart();
};
CChartSpace.prototype.handleUpdateFlip = function()
{
    this.handleUpdateExtents();
};
CChartSpace.prototype.handleUpdateChart = function()
{
    this.recalcChart();
    this.setRecalculateInfo();
    this.addToRecalculate();
};
CChartSpace.prototype.handleUpdateStyle = function()
{
    this.recalcInfo.recalculateSeriesColors = true;
    this.recalcInfo.recalculateLegend = true;
    this.recalcInfo.recalculatePlotAreaBrush = true;
    this.recalcInfo.recalculatePlotAreaPen = true;
    this.recalcInfo.recalculateBrush = true;
    this.recalcInfo.recalculatePen = true;
    this.recalcInfo.recalculateHiLowLines = true;
    this.recalcInfo.recalculateUpDownBars = true;
    this.handleTitlesAfterChangeTheme();
    this.recalcInfo.recalculateAxisLabels = true;
    this.recalcInfo.recalculateAxisVal = true;
    this.addToRecalculate();
};
CChartSpace.prototype.canGroup = CShape.prototype.canGroup;
CChartSpace.prototype.convertPixToMM = CShape.prototype.convertPixToMM;
CChartSpace.prototype.getCanvasContext = CShape.prototype.getCanvasContext;
CChartSpace.prototype.getHierarchy = CShape.prototype.getHierarchy;
CChartSpace.prototype.getParentObjects = CShape.prototype.getParentObjects;
CChartSpace.prototype.recalculateTransform = CShape.prototype.recalculateTransform;
CChartSpace.prototype.recalculateChart = function()
{
    if(this.chartObj == null)
        this.chartObj =  new AscFormat.CChartsDrawer();
    this.chartObj.recalculate(this);
};
CChartSpace.prototype.canResize = CShape.prototype.canResize;
CChartSpace.prototype.canMove = CShape.prototype.canMove;


CChartSpace.prototype.recalcText = function()
{
    this.recalcInfo.recalculateAxisLabels = true;
    this.recalcTitles2();
    this.handleUpdateInternalChart();
};

CChartSpace.prototype.setStartPage = function(pageIndex)
{
    this.selectStartPage = pageIndex;
    var title, content;
    if(this.chart && this.chart.title)
    {
        title = this.chart.title;
        content = title.getDocContent();
        content && content.Set_StartPage(pageIndex);
    }
    if(this.chart && this.chart.plotArea)
    {
        var aAxes = this.chart.plotArea.axId;
        if(aAxes)
        {
            for(var i = 0; i < aAxes.length; ++i)
            {
                var axis = aAxes[i];
                if(axis && axis.title)
                {
                    title = axis.title;
                    content = title.getDocContent();
                    content && content.Set_StartPage(pageIndex);
                }
            }
        }
    }
};
CChartSpace.prototype.getRecalcObject = CShape.prototype.getRecalcObject;
CChartSpace.prototype.setRecalcObject = CShape.prototype.setRecalcObject;
CChartSpace.prototype.canRotate = function()
{
    return false;
};


CChartSpace.prototype.createResizeTrack = CShape.prototype.createResizeTrack;
CChartSpace.prototype.createMoveTrack = CShape.prototype.createMoveTrack;
CChartSpace.prototype.getRectBounds = CShape.prototype.getRectBounds;

CChartSpace.prototype.recalculate = function()
{
    if(this.bDeleted)
        return;
    AscFormat.ExecuteNoHistory(function()
    {
        var bOldTrackRevision =  editor.WordControl.m_oLogicDocument.TrackRevisions;
        if(bOldTrackRevision){
            editor.WordControl.m_oLogicDocument.TrackRevisions = false;
        }
        this.updateLinks();


        var bCheckLabels = false;
        if(this.recalcInfo.recalcTitle)
        {
            this.recalculateChartTitleEditMode(true);
            this.recalcInfo.recalcTitle = null;
            this.recalcInfo.bRecalculatedTitle = true;
        }
        if(this.recalcInfo.recalculateTransform)
        {
            this.recalculateTransform();
            this.rectGeometry.Recalculate(this.extX, this.extY);
            this.recalcInfo.recalculateTransform = false;
        }
        if(this.recalcInfo.recalculateMarkers)
        {
            this.recalculateMarkers();
            this.recalcInfo.recalculateMarkers = false;
        }
        if(this.recalcInfo.recalculateSeriesColors)
        {
            this.recalculateSeriesColors();
            this.recalcInfo.recalculateSeriesColors = false;
        }
        if(this.recalcInfo.recalculateGridLines)
        {
            this.recalculateGridLines();
            this.recalcInfo.recalculateGridLines = false;
        }
        if(this.recalcInfo.recalculateAxisTickMark)
        {
            this.recalculateAxisTickMark();
            this.recalcInfo.recalculateAxisTickMark = false;
        }
        if(this.recalcInfo.recalculateDLbls)
        {
            this.recalculateDLbls();
            this.recalcInfo.recalculateDLbls = false;
        }

        if(this.recalcInfo.recalculateBrush)
        {
            this.recalculateChartBrush();
            this.recalcInfo.recalculateBrush = false;
        }

        if(this.recalcInfo.recalculatePen)
        {
            this.recalculateChartPen();
            this.recalcInfo.recalculatePen = false;
        }

        if(this.recalcInfo.recalculateHiLowLines)
        {
            this.recalculateHiLowLines();
            this.recalcInfo.recalculateHiLowLines = false;
        }
        if(this.recalcInfo.recalculatePlotAreaBrush)
        {
            this.recalculatePlotAreaChartBrush();
            this.recalculateWalls();
            this.recalcInfo.recalculatePlotAreaBrush = false;
        }
        if(this.recalcInfo.recalculatePlotAreaPen)
        {
            this.recalculatePlotAreaChartPen();
            this.recalcInfo.recalculatePlotAreaPen = false;
        }
        if(this.recalcInfo.recalculateUpDownBars)
        {
            this.recalculateUpDownBars();
            this.recalcInfo.recalculateUpDownBars = false;
        }

        var b_recalc_labels = false;
        if(this.recalcInfo.recalculateAxisLabels)
        {
            this.recalculateAxisLabels();
            this.recalcInfo.recalculateAxisLabels = false;
            b_recalc_labels = true;
        }
        
        var b_recalc_legend = false;
        if(this.recalcInfo.recalculateLegend)
        {
            this.recalculateLegend();
            this.recalcInfo.recalculateLegend = false;
            b_recalc_legend = true;
        }



        if(this.recalcInfo.recalculateAxisVal)
        {
            if(AscFormat.CChartsDrawer.prototype._isSwitchCurrent3DChart(this)){
                //old variant
                this.recalculateAxis();
            }
            else{
                this.recalculateAxes();
            }
            this.recalcInfo.recalculateAxisVal = false;
            bCheckLabels = true;
        }
        if(this.recalcInfo.recalculatePenBrush)
        {
            this.recalculatePenBrush();
            this.recalcInfo.recalculatePenBrush = false;
        }

        if(this.recalcInfo.recalculateChart)
        {
            this.recalculateChart();
            this.recalcInfo.recalculateChart = false;
            if(bCheckLabels && this.chartObj.nDimensionCount === 3)
            {
                this.checkAxisLabelsTransform();
            }
        }


        this.calculateLabelsPositions(b_recalc_labels, b_recalc_legend);
        
        if(this.recalcInfo.recalculateTextPr)
        {
            this.recalculateTextPr();
            this.recalcInfo.recalculateTextPr = false;
        }

        if(this.recalcInfo.recalculateBounds)
        {
            this.recalculateBounds();
            this.recalcInfo.recalculateBounds = false;
        }
        if(this.recalcInfo.recalculateWrapPolygon)
        {
            this.recalculateWrapPolygon();
            this.recalcInfo.recalculateWrapPolygon = false;
        }
        this.recalcInfo.axisLabels.length = 0;
        this.bNeedUpdatePosition = true;
        if(AscFormat.isRealNumber(this.posX) && AscFormat.isRealNumber(this.posY))
        {
            this.updatePosition(this.posX, this.posY);
        }
        if(bOldTrackRevision){
            editor.WordControl.m_oLogicDocument.TrackRevisions = true;
        }
    }, this, []);
};



CChartSpace.prototype.deselect = CShape.prototype.deselect;

CChartSpace.prototype.getDrawingDocument = CShape.prototype.getDrawingDocument;

CChartSpace.prototype.updatePosition = CShape.prototype.updatePosition;
CChartSpace.prototype.recalculateWrapPolygon = CShape.prototype.recalculateWrapPolygon;
CChartSpace.prototype.getArrayWrapPolygons = function()
{
    return this.rectGeometry.getArrayPolygons();
};



CChartSpace.prototype.checkContentDrawings = function()
{};

CChartSpace.prototype.checkShapeChildTransform = function(transform_text)
{
    if(this.parent)
    {
        if(transform_text)
        {
            if(this.chart)
            {
                if(this.chart.plotArea)
                {
                    if(this.chart.plotArea.charts[0] && this.chart.plotArea.charts[0].series)
                    {
                        var series = this.chart.plotArea.charts[0].series;
                        for(var i = 0; i < series.length; ++i)
                        {
                            var ser = series[i];
                            var pts = AscFormat.getPtsFromSeries(ser);
                            for(var j = 0; j < pts.length; ++j)
                            {
                                if(pts[j].compiledDlb)
                                {
                                    pts[j].compiledDlb.checkShapeChildTransform(transform_text);
                                }
                            }
                        }
                    }
                    if(this.chart.plotArea.catAx)
                    {
                        if(this.chart.plotArea.catAx.title)
                            this.chart.plotArea.catAx.title.checkShapeChildTransform(transform_text);
                        if(this.chart.plotArea.catAx.labels)
                            this.chart.plotArea.catAx.labels.checkShapeChildTransform(transform_text);
                    }
                    if(this.chart.plotArea.valAx)
                    {
                        if(this.chart.plotArea.valAx.title)
                            this.chart.plotArea.valAx.title.checkShapeChildTransform(transform_text);
                        if(this.chart.plotArea.valAx.labels)
                            this.chart.plotArea.valAx.labels.checkShapeChildTransform(transform_text);
                    }

                }
                if(this.chart.title)
                {
                    this.chart.title.checkShapeChildTransform(transform_text);
                }
                if(this.chart.legend)
                {
                    this.chart.legend.checkShapeChildTransform(transform_text);
                }
            }
        }

    }
};


CChartSpace.prototype.recalculateLocalTransform = CShape.prototype.recalculateLocalTransform;
CChartSpace.prototype.updateTransformMatrix  = function()
{

    var posX = this.localTransform.tx + this.posX;
    var posY = this.localTransform.ty + this.posY;

    this.transform = this.localTransform.CreateDublicate();
    AscCommon.global_MatrixTransformer.TranslateAppend(this.transform, this.posX, this.posY);

    var oParentTransform = null;
    if(this.parent && this.parent.Get_ParentParagraph)
    {
        var oParagraph = this.parent.Get_ParentParagraph();
        if(oParagraph)
        {
            oParentTransform = oParagraph.Get_ParentTextTransform();

            if(oParentTransform)
            {
                AscCommon.global_MatrixTransformer.MultiplyAppend(this.transform, oParentTransform);
            }
        }
    }

    this.invertTransform = AscCommon.global_MatrixTransformer.Invert(this.transform);
    this.updateChildLabelsTransform(posX,posY);
    this.checkShapeChildTransform(oParentTransform);
};
CChartSpace.prototype.getArrayWrapIntervals = CShape.prototype.getArrayWrapIntervals;
CChartSpace.prototype.select = CShape.prototype.select;
CChartSpace.prototype.Is_UseInDocument = CShape.prototype.Is_UseInDocument;
//CChartSpace.prototype.Refresh_RecalcData = function(data)
//{
//    this.addToRecalculate();
//};

function CreateUnifillSolidFillSchemeColor(colorId, tintOrShade)
{
    var unifill = new AscFormat.CUniFill();
    unifill.setFill(new AscFormat.CSolidFill());
    unifill.fill.setColor(new AscFormat.CUniColor());
    unifill.fill.color.setColor(new AscFormat.CSchemeColor());
    unifill.fill.color.color.setId(colorId);
    return AscFormat.CreateUniFillSolidFillWidthTintOrShade(unifill, tintOrShade);
}

function CreateNoFillLine()
{
    var ret = new AscFormat.CLn();
    ret.setFill(AscFormat.CreateNoFillUniFill());
    return ret;
}

function CreateNoFillUniFill()
{
    var ret = new AscFormat.CUniFill();
    ret.setFill(new AscFormat.CNoFill());
    return ret;
}

window['AscFormat'].CreateUnifillSolidFillSchemeColor = CreateUnifillSolidFillSchemeColor;
window['AscFormat'].CreateNoFillLine = CreateNoFillLine;
window['AscFormat'].CreateNoFillUniFill = CreateNoFillUniFill;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var changestype_Drawing_Props = AscCommon.changestype_Drawing_Props;
var changestype_2_ElementsArray_and_Type = AscCommon.changestype_2_ElementsArray_and_Type;
var g_oTableId = AscCommon.g_oTableId;
var isRealObject = AscCommon.isRealObject;
var global_mouseEvent = AscCommon.global_mouseEvent;
var History = AscCommon.History;

var DrawingObjectsController = AscFormat.DrawingObjectsController;
var HANDLE_EVENT_MODE_HANDLE = AscFormat.HANDLE_EVENT_MODE_HANDLE;
var HANDLE_EVENT_MODE_CURSOR = AscFormat.HANDLE_EVENT_MODE_CURSOR;

var asc_CImgProperty = Asc.asc_CImgProperty;

function CBoundsRectForMath(oDrawing)
{
    this.L = 0;
    this.T = 0;
    this.R = 0;
    this.B = 0;

    if(oDrawing)
    {
        this.Distance = oDrawing.Get_Distance();
        switch (oDrawing.Get_Type())
        {
            case para_Drawing:
            {
                this.WrapType = oDrawing.wrappingType;
                switch(oDrawing.wrappingType)
                {
                    case WRAPPING_TYPE_NONE:
                    {
                        break;
                    }
                    case WRAPPING_TYPE_SQUARE :
                    case WRAPPING_TYPE_THROUGH:
                    case WRAPPING_TYPE_TIGHT:
                    {
                        this.L = oDrawing.wrappingPolygon.left + this.Distance.L;
                        this.R = oDrawing.wrappingPolygon.right - this.Distance.R;
                        this.T = oDrawing.wrappingPolygon.top + this.Distance.T;
                        this.B = oDrawing.wrappingPolygon.bottom - this.Distance.B;
                        break;
                    }
                    case WRAPPING_TYPE_TOP_AND_BOTTOM:
                    {
                        var oLimits = editor.WordControl.m_oLogicDocument.Get_PageLimits(oDrawing.PageNum);
                        this.L = oLimits.X;
                        this.R = oLimits.XLimit;
                        this.T = oDrawing.wrappingPolygon.top + this.Distance.T;
                        this.B = oDrawing.wrappingPolygon.bottom - this.Distance.B;
                        break;
                    }
                }
                break;
            }
            case flowobject_Paragraph:
            case flowobject_Table:
            {
                this.WrapType = oDrawing.WrappingType;
                switch(oDrawing.WrappingType)
                {
                    case WRAPPING_TYPE_NONE:
                    {
                        break;
                    }
                    case WRAPPING_TYPE_SQUARE :
                    case WRAPPING_TYPE_THROUGH:
                    case WRAPPING_TYPE_TIGHT:
                    {
                        this.L = oDrawing.X;
                        this.R = oDrawing.X + oDrawing.W;
                        this.T = oDrawing.Y;
                        this.B = oDrawing.Y + oDrawing.H;
                        break;
                    }
                    case WRAPPING_TYPE_TOP_AND_BOTTOM:
                    {
                        var oLimits = editor.WordControl.m_oLogicDocument.Get_PageLimits(oDrawing.PageNum);
                        this.L = oLimits.X;
                        this.R = oLimits.XLimit;
                        this.T = oDrawing.Y;
                        this.B = oDrawing.Y + oDrawing.H;
                        break;
                    }
                }
            }
        }

    }
    else
    {
        this.WrapType = WRAPPING_TYPE_NONE;
        this.Distance = new AscFormat.CDistance(0, 0, 0, 0);
    }
}

function CGraphicObjects(document, drawingDocument, api)
{
    this.api = api;
    this.document = document;
    this.drawingDocument = drawingDocument;

    this.graphicPages = [];

    this.startTrackPos =
    {
        x: null,
        y: null,
        pageIndex: null
    };

    this.arrPreTrackObjects = [];
    this.arrTrackObjects = [];


    this.curState = new AscFormat.NullState(this);

    this.selectionInfo =
    {
        selectionArray: []
    };

    this.maximalGraphicObjectZIndex = 1024;

    this.spline = null;
    this.polyline = null;

    this.drawingObjects = [];


    this.urlMap = [];
    this.recalcMap = {};

    this.recalculateMap = {};

    this.selectedObjects = [];
    this.selection =
    {
        groupSelection:       null,
        chartSelection:       null,
        textSelection:        null,
        wrapPolygonSelection: null
    };

    this.selectedObjects = [];

    this.handleEventMode = HANDLE_EVENT_MODE_HANDLE;

    this.nullState = new AscFormat.NullState(this);
    this.bNoCheckChartTextSelection = false;

    this.Id = AscCommon.g_oIdCounter.Get_NewId();
    this.Lock = new AscCommon.CLock();
    g_oTableId.Add( this, this.Id );
}

CGraphicObjects.prototype =
{
    handleAdjustmentHit: DrawingObjectsController.prototype.handleAdjustmentHit,
    handleHandleHit: DrawingObjectsController.prototype.handleHandleHit,
    handleMoveHit: DrawingObjectsController.prototype.handleMoveHit,
    handleEnter: DrawingObjectsController.prototype.handleEnter,

    rotateTrackObjects: DrawingObjectsController.prototype.rotateTrackObjects,
    handleRotateTrack: DrawingObjectsController.prototype.handleRotateTrack,
    trackResizeObjects: DrawingObjectsController.prototype.trackResizeObjects,
    resetInternalSelection: DrawingObjectsController.prototype.resetInternalSelection,
    handleTextHit: DrawingObjectsController.prototype.handleTextHit,
    getConnectorsForCheck: DrawingObjectsController.prototype.getConnectorsForCheck,
    getConnectorsForCheck2: DrawingObjectsController.prototype.getConnectorsForCheck2,
    checkDrawingHyperlink: DrawingObjectsController.prototype.checkDrawingHyperlink,

    checkSelectedObjectsAndCallback: function(callback, args, bNoSendProps, nHistoryPointType, aAdditionaObjects)
    {
        var check_type = AscCommon.changestype_Drawing_Props;
        if(editor.WordControl.m_oLogicDocument.Document_Is_SelectionLocked(check_type, null, false, false) === false)
        {
            var nPointType = AscFormat.isRealNumber(nHistoryPointType) ? nHistoryPointType : AscDFH.historydescription_CommonControllerCheckSelected;
            History.Create_NewPoint(nPointType);
            callback.apply(this, args);
            this.document.Recalculate();
        }
    },

    AddContentControl: function(nContentControlType)
    {
        var oTargetDocContent = this.getTargetDocContent();
        if(oTargetDocContent && !oTargetDocContent.bPresentation){
            return oTargetDocContent.AddContentControl(nContentControlType);
        }

        return null;
    },

    Get_Id: function()
    {
        return this.Id;
    },

    TurnOffCheckChartSelection: function()
    {
        this.bNoCheckChartTextSelection = true;
    },

    TurnOnCheckChartSelection: function()
    {
        this.bNoCheckChartTextSelection = false;
    },


    getDrawingDocument: function()
    {
        return editor.WordControl.m_oDrawingDocument;
    },
    sortDrawingArrays: function()
    {
        for(var i = 0; i < this.graphicPages.length; ++i)
        {
            if(this.graphicPages[i])
                this.graphicPages[i].sortDrawingArrays();
        }
    },

    getSelectedObjects: function()
    {
        return this.selectedObjects;
    },

    getTheme: function()
    {
        return this.document.theme;
    },

    getColorMapOverride: function()
    {
        return null;
    },

    isViewMode: function()
    {
        return this.document.IsViewMode();
    },

    convertPixToMM: function(v)
    {
        return this.document.DrawingDocument.GetMMPerDot(v);
    },

    getGraphicInfoUnderCursor: function(pageIndex, x, y)
    {
        this.handleEventMode = HANDLE_EVENT_MODE_CURSOR;
        var ret = this.curState.onMouseDown(global_mouseEvent, x, y, pageIndex, false);
        this.handleEventMode = HANDLE_EVENT_MODE_HANDLE;
        if(ret && ret.cursorType === "text")
        {
            if((this.selection.chartSelection && this.selection.chartSelection.selection.textSelection) ||
                (this.selection.groupSelection && this.selection.groupSelection.selection.chartSelection && this.selection.groupSelection.selection.chartSelection.selection.textSelection))
            {
                ret = {};
            }
        }
        return ret || {};
    },

    updateCursorType: function(pageIndex, x, y, e, bTextFlag)
    {
        var ret;
        this.handleEventMode = HANDLE_EVENT_MODE_CURSOR;
        ret = this.curState.onMouseDown(global_mouseEvent, x, y, pageIndex, bTextFlag);
        this.handleEventMode = HANDLE_EVENT_MODE_HANDLE;
        if(ret)
        {
            if(ret.cursorType !== "text")
                this.drawingDocument.SetCursorType(ret.cursorType);
            return true;
        }
        return false;
    },

    removeTextSelection: function(){
        var oTargetDocContent = this.getTargetDocContent();
        if(oTargetDocContent && oTargetDocContent.IsSelectionUse()){
            oTargetDocContent.RemoveSelection();
        }
    },

	getDefaultText: DrawingObjectsController.prototype.getDefaultText,
    canEdit: DrawingObjectsController.prototype.canEdit,
    createImage: DrawingObjectsController.prototype.createImage,
    createOleObject: DrawingObjectsController.prototype.createOleObject,
    createTextArt: DrawingObjectsController.prototype.createTextArt,
    getChartObject: DrawingObjectsController.prototype.getChartObject,
    getChartSpace2: DrawingObjectsController.prototype.getChartSpace2,
    CreateDocContent: DrawingObjectsController.prototype.CreateDocContent,



    clearPreTrackObjects: function()
    {
        this.arrPreTrackObjects.length = 0;
    },

    addPreTrackObject: function(preTrackObject)
    {
        this.arrPreTrackObjects.push(preTrackObject);
    },

    clearTrackObjects: function()
    {
        this.arrTrackObjects.length = 0;
    },

    addTrackObject: function(trackObject)
    {
        this.arrTrackObjects.push(trackObject);
    },

    swapTrackObjects: function()
    {
        this.clearTrackObjects();
        for(var i = 0; i < this.arrPreTrackObjects.length; ++i)
            this.addTrackObject(this.arrPreTrackObjects[i]);
        this.clearPreTrackObjects();
    },


    addToRecalculate: function(object)
    {
        if(typeof object.Get_Id === "function" && typeof object.recalculate === "function")
            History.RecalcData_Add({Type: AscDFH.historyitem_recalctype_Drawing, Object: object});
        return;
    },

    createWatermarkImage: DrawingObjectsController.prototype.createWatermarkImage,



    getTrialImage: function(sImageUrl)
    {
        return AscFormat.ExecuteNoHistory(function(){
            var oParaDrawing = new ParaDrawing();
            oParaDrawing.Set_PositionH(Asc.c_oAscRelativeFromH.Page, true, c_oAscAlignH.Center, undefined);
            oParaDrawing.Set_PositionV(Asc.c_oAscRelativeFromV.Page, true, c_oAscAlignV.Center, undefined);
            oParaDrawing.Set_WrappingType(WRAPPING_TYPE_NONE);
            oParaDrawing.Set_BehindDoc( false );
            oParaDrawing.Set_Distance( 3.2, 0, 3.2, 0 );
            oParaDrawing.Set_DrawingType(drawing_Anchor);
            var oShape = this.createWatermarkImage(sImageUrl);
            oParaDrawing.Extent.W = oShape.spPr.xfrm.extX;
            oParaDrawing.Extent.H = oShape.spPr.xfrm.extY;
            oShape.setParent(oParaDrawing);
            oParaDrawing.Set_GraphicObject(oShape);
            return oParaDrawing;
        }, this, []);

    },
	
    recalculate_: function(data)
    {
        if(data.All)
        {
            for(var i = 0; i < this.drawingObjects.length; ++i)
            {
                if(this.drawingObjects[i].GraphicObj)
                {
                    if(this.drawingObjects[i].GraphicObj.recalcText)
                    {
                        this.drawingObjects[i].GraphicObj.recalcText(true);
                    }
                    this.drawingObjects[i].GraphicObj.recalculate();
                }
            }
            for(var i = 0; i < this.drawingObjects.length; ++i)
            {
                if(this.drawingObjects[i].GraphicObj && this.drawingObjects[i].GraphicObj.recalculateText)
                {
                    this.drawingObjects[i].GraphicObj.recalculateText();
                }
            }
        }
        else
        {
            var map = data.Map;
            for(var key in map)
            {
                if(map.hasOwnProperty(key))
                    map[key].recalculate();
            }
        }
    },

    recalculateText_: function(data)
    {
        if(data.All)
        {
            //TODO
        }
        else
        {
            var map = data.Map;
            for(var key in map)
            {
                if(map.hasOwnProperty(key) && map[key].recalculateText)
                    map[key].recalculateText();
            }
        }
    },

    recalculate: function()
    {
        var b_update = false;
        for(var key in this.recalculateMap)
        {
            if(this.recalculateMap.hasOwnProperty(key))
                this.recalculateMap[key].recalculate();
        }
        this.recalculateMap = {};
    },


    selectObject: DrawingObjectsController.prototype.selectObject,

    checkSelectedObjectsForMove: DrawingObjectsController.prototype.checkSelectedObjectsForMove,

    getDrawingPropsFromArray: DrawingObjectsController.prototype.getDrawingPropsFromArray,
    getPropsFromChart: DrawingObjectsController.prototype.getPropsFromChart,
    getSelectedObjectsByTypes: DrawingObjectsController.prototype.getSelectedObjectsByTypes,


    getPageSizesByDrawingObjects: function()
    {
        var aW = [], aH = [];
        var aBPages = [];
        var page_limits;
        if(this.selectedObjects.length > 0)
        {
            for(var i = 0; i < this.selectedObjects.length; ++i)
            {
                if(!aBPages[this.selectedObjects[i].selectStartPage])
                {
                    page_limits = this.document.Get_PageLimits(this.selectedObjects[i].selectStartPage);
                    aW.push(page_limits.XLimit);
                    aH.push(page_limits.YLimit);
                    aBPages[this.selectedObjects[i].selectStartPage] = true;
                }
            }
            return {W: Math.min.apply(Math, aW), H: Math.min.apply(Math, aH)};
        }
        page_limits = this.document.Get_PageLimits(0);
        return {W: page_limits.XLimit, H: page_limits.YLimit};
    },

	AcceptRevisionChanges: function(Type, bAll)
    {
        var oDocContent = this.getTargetDocContent();
        if(oDocContent)
        {
            oDocContent.AcceptRevisionChanges(Type, bAll);
        }
    },


	RejectRevisionChanges: function(Type, bAll)
    {
        var oDocContent = this.getTargetDocContent();
        if(oDocContent)
        {
            oDocContent.RejectRevisionChanges(Type, bAll);
        }
    },

    Get_Props: function()
    {
        var props_by_types = DrawingObjectsController.prototype.getDrawingProps.call(this);
        var para_drawing_props = null;
        for(var i = 0; i < this.selectedObjects.length; ++i)
        {
            para_drawing_props = this.selectedObjects[i].parent.Get_Props(para_drawing_props);
        }
        var chart_props, shape_props, image_props;
        if(para_drawing_props)
        {
            if(props_by_types.shapeProps)
            {
                shape_props = new asc_CImgProperty(para_drawing_props);
                shape_props.ShapeProperties = AscFormat.CreateAscShapePropFromProp(props_by_types.shapeProps);
                shape_props.verticalTextAlign = props_by_types.shapeProps.verticalTextAlign;
                shape_props.vert = props_by_types.shapeProps.vert;
                shape_props.Width = props_by_types.shapeProps.w;
                shape_props.Height = props_by_types.shapeProps.h;
                shape_props.lockAspect = props_by_types.shapeProps.lockAspect;
                if(this.selection.group){
                    shape_props.description = props_by_types.shapeProps.description;
                    shape_props.title = props_by_types.shapeProps.title;
                }
            }
            if(props_by_types.imageProps)
            {
                image_props = new asc_CImgProperty(para_drawing_props);
                image_props.ImageUrl = props_by_types.imageProps.ImageUrl;
                image_props.Width = props_by_types.imageProps.w;
                image_props.Height = props_by_types.imageProps.h;
                image_props.lockAspect = props_by_types.imageProps.lockAspect;

                image_props.pluginGuid = props_by_types.imageProps.pluginGuid;
                image_props.pluginData = props_by_types.imageProps.pluginData;

                image_props.oleWidth = props_by_types.imageProps.oleWidth;
                image_props.oleHeight = props_by_types.imageProps.oleHeight;
                if(this.selection.group){
                    image_props.description = props_by_types.imageProps.description;
                    image_props.title = props_by_types.imageProps.title;
                }
            }
            if(props_by_types.chartProps && !(props_by_types.chartProps.severalCharts === true))
            {
                chart_props = new asc_CImgProperty(para_drawing_props);
                chart_props.ChartProperties = props_by_types.chartProps.chartProps;
                chart_props.severalCharts = props_by_types.chartProps.severalCharts;
                chart_props.severalChartStyles = props_by_types.chartProps.severalChartStyles;
                chart_props.severalChartTypes = props_by_types.chartProps.severalChartTypes;
                chart_props.lockAspect = props_by_types.chartProps.lockAspect;
                if(this.selection.group){
                    chart_props.description = props_by_types.chartProps.description;
                    chart_props.title = props_by_types.chartProps.title;
                }
            }
        }

        if(props_by_types.shapeProps)
        {
            var pr = props_by_types.shapeProps;
            if (pr.fill != null && pr.fill.fill != null && pr.fill.fill.type == Asc.c_oAscFill.FILL_TYPE_BLIP)
            {
                this.drawingDocument.DrawImageTextureFillShape(pr.fill.fill.RasterImageId);
            }
            else
            {
                this.drawingDocument.DrawImageTextureFillShape(null);
            }
        }
        else
        {
            this.drawingDocument.DrawImageTextureFillShape(null);
        }
        var ret = [];
        if(isRealObject(shape_props))
        {
            ret.push(shape_props);
        }
        if(isRealObject(image_props))
        {
            ret.push(image_props);
        }

        if(isRealObject(chart_props))
        {
            ret.push(chart_props);
        }
        return ret;
    },

    resetTextSelection: DrawingObjectsController.prototype.resetTextSelection,
    collectPropsFromDLbls: DrawingObjectsController.prototype.collectPropsFromDLbls,

    setProps: function(oProps)
    {
        var oApplyProps, i;

        for(i = 0; i < this.selectedObjects.length; ++i)
        {
            this.selectedObjects[i].parent.Set_Props(oProps);
        }
        if(AscFormat.isRealNumber(oProps.Width) || AscFormat.isRealNumber(oProps.Height))
        {
            oApplyProps = oProps;
        }
        else
        {
            oApplyProps = oProps.ShapeProperties ? oProps.ShapeProperties : oProps;
            if(AscFormat.isRealBool(oProps.lockAspect))
            {
                oApplyProps.lockAspect = oProps.lockAspect;
            }
        }
        this.applyDrawingProps(oApplyProps);
        if(AscFormat.isRealNumber(oApplyProps.Width) || AscFormat.isRealNumber(oApplyProps.Height))
        {
            /*в случае если в насторойках ParaDrawing стоит UseAlign - пересчитываем drawing, т. к. ширина и высото ParaDrawing рассчитывается по bounds*/
            var aSelectedObjects = this.selectedObjects;
            for(i = 0; i < aSelectedObjects.length; ++i)
            {
                aSelectedObjects[i].parent.CheckWH();
            }
        }
        this.document.Recalculate();
        if(oApplyProps.textArtProperties && typeof oApplyProps.textArtProperties.asc_getForm() === "string")
        {
            this.document.Document_UpdateSelectionState();
        }
        oApplyProps && (AscFormat.isRealNumber(oApplyProps.verticalTextAlign) || AscFormat.isRealNumber(oApplyProps.vert)) && this.document.Document_UpdateSelectionState();
    },

    applyDrawingProps: DrawingObjectsController.prototype.applyDrawingProps,

    CheckAutoFit : function()
    {
        for(var i = this.drawingObjects.length - 1; i > -1; --i)
        {
                this.drawingObjects[i].CheckGroupSizes();
        }
    },

    checkUseDrawings: function(aDrawings)
    {
        for(var i = aDrawings.length - 1; i > -1; --i)
        {
            if(!aDrawings[i].Is_UseInDocument())
            {
                aDrawings.splice(i, 1);
            }
        }
    },

    bringToFront : function()//перемещаем заселекченые объекты наверх
    {
        if(false === this.document.Document_Is_SelectionLocked(changestype_Drawing_Props))
        {
            History.Create_NewPoint(AscDFH.historydescription_Document_GrObjectsBringToFront);
            if(this.selection.groupSelection)
            {
                this.selection.groupSelection.bringToFront();
            }
            else
            {
                var aSelectedObjectsCopy = [], i;
                for(i = 0; i < this.selectedObjects.length; ++i)
                {
                    aSelectedObjectsCopy.push(this.selectedObjects[i].parent);
                }
                aSelectedObjectsCopy.sort(ComparisonByZIndexSimple);
                for(i = 0; i < aSelectedObjectsCopy.length; ++i)
                {
                    aSelectedObjectsCopy[i].Set_RelativeHeight(this.getZIndex());
                }
            }
            this.document.Recalculate();
            this.document.Document_UpdateUndoRedoState();
        }
    },

    checkZIndexMap: function(oDrawing, oDrawingMap, nNewZIndex)
    {
        if(!isRealObject(oDrawingMap[oDrawing.Get_Id()]))
        {
            oDrawingMap[oDrawing.Get_Id()] = oDrawing.RelativeHeight;
        }
        oDrawing.Set_RelativeHeight2(nNewZIndex);
    },

    insertBetween: function(aToInsert/*массив в котрый вставляем*/, aDrawings/*массив куда вставляем*/, nPos, oDrawingMap)
    {
        if(nPos > aDrawings.length || nPos < 0)
            return;
        var i, j, nBetweenMin, nBetweenMax, nTempInterval, aTempDrawingsArray, nDelta;
        if(nPos === aDrawings.length)
        {
            for(i = 0; i < aToInsert.length; ++i)
            {
                this.checkZIndexMap(aToInsert[i], oDrawingMap, this.getZIndex());
                aDrawings.push(aToInsert[i]);
            }
        }
        else
        {
            if(nPos > 0)
            {
                nBetweenMin = aDrawings[nPos-1].RelativeHeight;
            }
            else
            {
                nBetweenMin = -1;
            }
            nBetweenMax = aDrawings[nPos].RelativeHeight;
            if(aToInsert.length < nBetweenMax - nBetweenMin)//интервала хватает для вставки
            {
                for(i = 0; i < aToInsert.length; ++i)
                {
                    nBetweenMin += ((nBetweenMax - nBetweenMin)/(aToInsert.length + 1 - i)) >> 0;
                    this.checkZIndexMap(aToInsert[i], oDrawingMap, nBetweenMin);
                    aDrawings.splice(nPos + i, aToInsert[i]);
                }
            }
            else
            {
                nDelta =  nBetweenMax - nBetweenMin - aToInsert.length + 1; //сколько нам не хватает для вставки
                for(i = nPos; i < aDrawings.length; ++i)
                {
                    this.checkZIndexMap(aDrawings[i], oDrawingMap, aDrawings[i].RelativeHeight + nDelta);
                    if(i < aDrawings.length - 1)
                    {
                        if(aDrawings[i].RelativeHeight <= aDrawings[i+1].RelativeHeight)
                        {
                            break;
                        }
                    }
                }
                for(i = 0; i < aToInsert.length; ++i)
                {
                    this.checkZIndexMap(aToInsert[i], oDrawingMap, nBetweenMin+i);
                    aDrawings.splice(nPos + i, aToInsert[i]);
                }
            }
        }
    },

    checkDrawingsMap: function(oDrawingMap)
    {
        var aDrawings = [], oDrawing, aZIndex = [];
        for(var key in oDrawingMap)
        {
            if(oDrawingMap.hasOwnProperty(key))
            {
                oDrawing = g_oTableId.Get_ById(key);
                aDrawings.push(oDrawing);
                aZIndex.push(oDrawing.RelativeHeight);
                oDrawing.Set_RelativeHeight2(oDrawingMap[key]);
            }
        }
        return {aDrawings: aDrawings, aZIndex: aZIndex};
    },

    applyZIndex: function(oDrawingObject)
    {
        var aDrawings = oDrawingObject.aDrawings, aZIndex = oDrawingObject.aZIndex;
        for(var i = 0; i < aDrawings.length; ++i)
        {
            aDrawings[i].Set_RelativeHeight(aZIndex[i]);
        }
    },

    bringForward : function()//перемещаем заселекченные объекты на один уровень выше
    {
        if(this.selection.groupSelection)
        {
            if(false === this.document.Document_Is_SelectionLocked(changestype_Drawing_Props))
            {
                History.Create_NewPoint(AscDFH.historydescription_Document_GrObjectsBringForwardGroup);
                this.selection.groupSelection.bringForward();
                this.document.Recalculate();
                this.document.Document_UpdateUndoRedoState();
            }
        }
        else
        {
            var aDrawings = [].concat(this.drawingObjects), i, j, aSelect = [], nIndexLastNoSelect = -1, oDrawingsMap = {};
            this.checkUseDrawings(aDrawings);
            aDrawings.sort(ComparisonByZIndexSimple);
            for(i = aDrawings.length - 1; i > -1; --i)
            {
                if(aDrawings[i].GraphicObj.selected)
                {
                    if(nIndexLastNoSelect !== -1)
                    {
                        for(j = i; j > -1; --j)
                        {
                            if(aDrawings[j].GraphicObj.selected)
                            {
                                aSelect.splice(0, 0, aDrawings.splice(j, 1)[0]);
                                --nIndexLastNoSelect;
                            }
                            else
                            {
                                break;
                            }
                        }
                        this.insertBetween(aSelect, aDrawings, nIndexLastNoSelect + 1, oDrawingsMap);
                        aSelect.length = 0;
                        nIndexLastNoSelect = -1;
                        i = j+1;
                    }
                }
                else
                {
                    nIndexLastNoSelect = i;
                }
            }
            var oCheckObject = this.checkDrawingsMap(oDrawingsMap);
            if(false === this.document.Document_Is_SelectionLocked(AscCommon.changestype_None, {Type: changestype_2_ElementsArray_and_Type, CheckType: changestype_Drawing_Props, Elements:oCheckObject.aDrawings}))
            {
                History.Create_NewPoint(AscDFH.historydescription_Document_GrObjectsBringForward);
                this.applyZIndex(oCheckObject);
                this.document.Recalculate();
                this.document.Document_UpdateUndoRedoState();
            }
        }
    },

    sendToBack : function()
    {
        if(this.selection.groupSelection)
        {
            if(false === this.document.Document_Is_SelectionLocked(changestype_Drawing_Props))
            {
                History.Create_NewPoint(AscDFH.historydescription_Document_GrObjectsSendToBackGroup);
                this.selection.groupSelection.sendToBack();
                this.document.Recalculate();
                this.document.Document_UpdateUndoRedoState();
            }
        }
        else
        {
            var aDrawings = [].concat(this.drawingObjects), i, aSelect = [], oDrawingsMap = {};
            this.checkUseDrawings(aDrawings);
            aDrawings.sort(ComparisonByZIndexSimple);
            for(i = 0; i < aDrawings.length; ++i)
            {
                if(aDrawings[i].GraphicObj.selected)
                {
                    aSelect.push(aDrawings.splice(i, 1)[0]);
                }
            }
            this.insertBetween(aSelect, aDrawings, 0, oDrawingsMap);
            var oCheckObject = this.checkDrawingsMap(oDrawingsMap);
            if(false === this.document.Document_Is_SelectionLocked(AscCommon.changestype_None, {Type: changestype_2_ElementsArray_and_Type, CheckType: changestype_Drawing_Props, Elements:oCheckObject.aDrawings}))
            {
                History.Create_NewPoint(AscDFH.historydescription_Document_GrObjectsSendToBack);
                this.applyZIndex(oCheckObject);
                this.document.Recalculate();
                this.document.Document_UpdateUndoRedoState();
            }
        }
    },

    bringBackward : function()
    {
        if(this.selection.groupSelection)
        {
            if(false === this.document.Document_Is_SelectionLocked(changestype_Drawing_Props, {Type : changestype_2_ElementsArray_and_Type , Elements : [this.selection.groupSelection.parent.Get_ParentParagraph()], CheckType : AscCommon.changestype_Paragraph_Content}))
            {
                History.Create_NewPoint(AscDFH.historydescription_Document_GrObjectsBringBackwardGroup);
                this.selection.groupSelection.bringBackward();
                this.document.Recalculate();
                this.document.Document_UpdateUndoRedoState();
            }
        }
        else
        {
            var aDrawings = [].concat(this.drawingObjects), i, j, aSelect = [], nIndexLastNoSelect = -1, oDrawingsMap = {};
            this.checkUseDrawings(aDrawings);
            aDrawings.sort(ComparisonByZIndexSimple);
            for(i = 0; i < aDrawings.length; ++i)
            {
                if(aDrawings[i].GraphicObj.selected)
                {
                    if(nIndexLastNoSelect !== -1)
                    {
                        for(j = i; j < aDrawings.length; ++j)
                        {
                            if(aDrawings[j].GraphicObj.selected)
                            {
                                aSelect.push(aDrawings.splice(j, 1)[0]);
                            }
                            else
                            {
                                break;
                            }
                        }

                        this.insertBetween(aSelect, aDrawings, nIndexLastNoSelect, oDrawingsMap);
                        aSelect.length = 0;
                        nIndexLastNoSelect = -1;
                        i = j-1;
                    }
                }
                else
                {
                    nIndexLastNoSelect = i;
                }
            }
            var oCheckObject = this.checkDrawingsMap(oDrawingsMap);
            if(false === this.document.Document_Is_SelectionLocked(AscCommon.changestype_None, {Type: changestype_2_ElementsArray_and_Type, CheckType: changestype_Drawing_Props, Elements:oCheckObject.aDrawings}))
            {
                History.Create_NewPoint(AscDFH.historydescription_Document_GrObjectsBringBackward);
                this.applyZIndex(oCheckObject);
                this.document.Recalculate();
                this.document.Document_UpdateUndoRedoState();
            }
        }
    },

    editChart: function(chart)
    {
        var chart_space = this.getChartSpace2(chart, null), select_start_page, parent_paragraph, nearest_pos;


        var by_types;
        by_types = AscFormat.getObjectsByTypesFromArr(this.selectedObjects, true);

        var aSelectedCharts = [];
        for(i = 0; i < by_types.charts.length; ++i)
        {
            if(by_types.charts[i].selected)
            {
                aSelectedCharts.push(by_types.charts[i]);
            }
        }

        if(aSelectedCharts.length === 1)
        {
            if(aSelectedCharts[0].group)
            {
                var parent_group = aSelectedCharts[0].group;
                var major_group = aSelectedCharts[0].getMainGroup();
                for(var i = parent_group.spTree.length -1; i > -1; --i)
                {
                    if(parent_group.spTree[i] === aSelectedCharts[0])
                    {
                        parent_group.removeFromSpTreeByPos(i);
                        chart_space.setGroup(parent_group);
                        chart_space.spPr.xfrm.setOffX(aSelectedCharts[0].spPr.xfrm.offX);
                        chart_space.spPr.xfrm.setOffY(aSelectedCharts[0].spPr.xfrm.offY);
                        parent_group.addToSpTree(i, chart_space);
                        major_group.updateCoordinatesAfterInternalResize();
                        major_group.parent.CheckWH();
                        if(this.selection.groupSelection)
                        {
                            select_start_page = this.selection.groupSelection.selectedObjects[0].selectStartPage;
                            this.selection.groupSelection.resetSelection();
                            this.selection.groupSelection.selectObject(chart_space, select_start_page);
                        }
                        this.document.Recalculate();
                        this.document.Document_UpdateInterfaceState();
                        return;
                    }
                }
            }
            else
            {
                chart_space.spPr.xfrm.setOffX(0);
                chart_space.spPr.xfrm.setOffY(0);
                select_start_page = aSelectedCharts[0].selectStartPage;
                chart_space.setParent(aSelectedCharts[0].parent);
                aSelectedCharts[0].parent.Set_GraphicObject(chart_space);
                aSelectedCharts[0].parent.docPr.setTitle(chart["cTitle"]);
                aSelectedCharts[0].parent.docPr.setDescr(chart["cDescription"]);
                this.resetSelection();
                this.selectObject(chart_space, select_start_page);
                aSelectedCharts[0].parent.CheckWH();
                this.document.Recalculate();
                this.document.Document_UpdateInterfaceState();
            }
        }
    },

    getCompatibilityMode: function(){
        var ret = 0xFF;
        if(this.document && this.document.GetCompatibilityMode){
            ret = this.document.GetCompatibilityMode();
        }
        return ret;
    },


    mergeDrawings: function(pageIndex, HeaderDrawings, HeaderTables, FooterDrawings, FooterTables)
    {
        var nCompatibilityMode = this.getCompatibilityMode();
        if(!this.graphicPages[pageIndex])
        {
            this.graphicPages[pageIndex] = new CGraphicPage(pageIndex, this);
        }
        var drawings = [], tables = [], i, hdr_ftr_page = this.graphicPages[pageIndex].hdrFtrPage;
        if(HeaderDrawings)
        {
            drawings = drawings.concat(HeaderDrawings);
        }
        if(FooterDrawings)
        {
            drawings = drawings.concat(FooterDrawings);
        }

        var getFloatObjects = function(arrObjects)
        {
            var  ret = [];
            for(var i = 0; i < arrObjects.length; ++i)
            {
                if(arrObjects[i].GetType() === type_Paragraph)
                {
                    var calc_frame = arrObjects[i].CalculatedFrame;
                    var FramePr = arrObjects[i].Get_FramePr();
                    var FrameDx = ( undefined === FramePr.HSpace ? 0 : FramePr.HSpace );
                    var FrameDy = ( undefined === FramePr.VSpace ? 0 : FramePr.VSpace );
                    ret.push(new CFlowParagraph(arrObjects[i], calc_frame.L2, calc_frame.T2, calc_frame.W2, calc_frame.H2, FrameDx, FrameDy, 0, 0, FramePr.Wrap));
                }
                else if(arrObjects[i].GetType() === type_Table)
                {
                    ret.push(new CFlowTable(arrObjects[i], 0));
                }
            }
            return ret;
        };
        if(HeaderTables)
        {
            tables = tables.concat(getFloatObjects(HeaderTables));
        }
        if(FooterTables)
        {
            tables = tables.concat(getFloatObjects(FooterTables));
        }

        hdr_ftr_page.clear();
        for(i = 0; i < drawings.length; ++i)
        {

            var cur_drawing = drawings[i];
            if(!cur_drawing.bNoNeedToAdd && cur_drawing.PageNum === pageIndex)
            {
                var drawing_array = null;

                if(cur_drawing.Is_Inline()){
                    drawing_array = hdr_ftr_page.inlineObjects;
                }
                else if(cur_drawing.behindDoc === true && (cur_drawing.wrappingType === WRAPPING_TYPE_NONE ||  nCompatibilityMode < document_compatibility_mode_Word15)){
                    drawing_array = hdr_ftr_page.behindDocObjects;
                }
                else{
                    drawing_array = hdr_ftr_page.beforeTextObjects;
                }
                if(Array.isArray(drawing_array))
                {
                    drawing_array.push(drawings[i].GraphicObj);
                }
            }
        }
        for(i = 0; i < tables.length; ++i)
        {
            hdr_ftr_page.flowTables.push(tables[i]);
        }
        hdr_ftr_page.behindDocObjects.sort(ComparisonByZIndexSimpleParent);
        hdr_ftr_page.beforeTextObjects.sort(ComparisonByZIndexSimpleParent);
    },

    addFloatTable: function(table)
    {
        var hdr_ftr = table.Table.Parent.IsHdrFtr(true);
        if(!this.graphicPages[table.PageNum + table.PageController])
        {
            this.graphicPages[table.PageNum + table.PageController] = new CGraphicPage(table.PageNum + table.PageController, this);
        }
        if(!hdr_ftr)
        {

            this.graphicPages[table.PageNum + table.PageController].addFloatTable(table);
        }
        else
        {
           // this.graphicPages[table.PageNum + table.PageController].hdrFtrPage.addFloatTable(table);
        }
    },

    removeFloatTableById: function(pageIndex, id)
    {
        if(!this.graphicPages[pageIndex])
        {
            this.graphicPages[pageIndex] = new CGraphicPage(pageIndex, this);
        }
        var table = g_oTableId.Get_ById(id);
        if(table)
        {
            var hdr_ftr = table.Parent.IsHdrFtr(true);
            if(!hdr_ftr)
            {
                this.graphicPages[pageIndex].removeFloatTableById(id);
            }
        }
    },

    selectionIsTableBorder: function()
    {
        var content = this.getTargetDocContent();
        if(content)
            return content.IsMovingTableBorder();
        return false;
    },


    getTableByXY: function(x, y, pageIndex, documentContent)
    {
        if(!this.graphicPages[pageIndex])
        {
            this.graphicPages[pageIndex] = new CGraphicPage(pageIndex, this);
        }
        if(!documentContent.IsHdrFtr())
            return this.graphicPages[pageIndex].getTableByXY(x, y, documentContent);
        else
            return this.graphicPages[pageIndex].hdrFtrPage.getTableByXY(x, y, documentContent);
        return null;
    },

    OnMouseDown: function(e, x, y, pageIndex)
    {
        //console.log("down " + this.curState.id);
        this.curState.onMouseDown(e, x, y, pageIndex);
    },

    OnMouseMove: function(e, x, y, pageIndex)
    {

        //console.log("move " + this.curState.id);
        this.curState.onMouseMove(e, x, y, pageIndex);
    },

    OnMouseUp: function(e, x, y, pageIndex)
    {

        //console.log("up " + this.curState.id);
        this.curState.onMouseUp(e, x, y, pageIndex);
    },

    draw: function(pageIndex, graphics)
    {
        this.graphicPages[pageIndex] && this.graphicPages[pageIndex].draw(graphics);
    },

    selectionDraw: function()
    {
        this.drawingDocument.m_oWordControl.OnUpdateOverlay();
    },

    updateOverlay: function()
    {
        this.drawingDocument.m_oWordControl.OnUpdateOverlay();
    },

    isPolylineAddition: function()
    {
        return this.curState.polylineFlag === true;
    },

    shapeApply: function(props)
    {
        this.applyDrawingProps(props);
    },


    addShapeOnPage: function(sPreset, nPageIndex, dX, dY, dExtX, dExtY)
    {
        if ( docpostype_HdrFtr !== this.document.Get_DocPosType() || null !== this.document.HdrFtr.CurHdrFtr )
        {
            if (docpostype_HdrFtr !== this.document.Get_DocPosType())
            {
                this.document.Set_DocPosType(docpostype_DrawingObjects);
                this.document.Selection.Use   = true;
                this.document.Selection.Start = true;
            }
            else
            {
                this.document.Selection.Use   = true;
                this.document.Selection.Start = true;

                var CurHdrFtr = this.document.HdrFtr.CurHdrFtr;
                var DocContent = CurHdrFtr.Content;

                DocContent.Set_DocPosType(docpostype_DrawingObjects);
                DocContent.Selection.Use   = true;
                DocContent.Selection.Start = true;
            }

            this.changeCurrentState(new AscFormat.StartAddNewShape(this, sPreset));
            this.OnMouseDown({}, dX, dY, nPageIndex);
            if(AscFormat.isRealNumber(dExtX) && AscFormat.isRealNumber(dExtY))
            {
                this.OnMouseMove({IsLocked: true}, dX + dExtX, dY + dExtY, nPageIndex)
            }
            this.OnMouseUp({}, dX, dY, nPageIndex);
            this.document.Document_UpdateInterfaceState();
            this.document.Document_UpdateRulersState();
            this.document.Document_UpdateSelectionState();
        }
    },


    drawOnOverlay: function(overlay)
    {
        var _track_objects = this.arrTrackObjects;
        var _object_index;
        var _object_count = _track_objects.length;
        for(_object_index = 0; _object_index < _object_count; ++_object_index)
        {
            _track_objects[_object_index].draw(overlay);
        }
        if(this.curState.InlinePos)
        {
            this.drawingDocument.AutoShapesTrack.SetCurrentPage(this.curState.InlinePos.Page);
            this.drawingDocument.AutoShapesTrack.DrawInlineMoveCursor(this.curState.InlinePos.X, this.curState.InlinePos.Y, this.curState.InlinePos.Height, this.curState.InlinePos.transform);
        }
        //TODO Anchor Position
        return;
    },


    getAllFloatObjectsOnPage: function(pageIndex, docContent)
    {
        if(!this.graphicPages[pageIndex])
            this.graphicPages[pageIndex] = new CGraphicPage(pageIndex, this);
        var arr, page, i, ret = [];
        if(!docContent.IsHdrFtr())
        {

            page = this.graphicPages[pageIndex];
        }
        else
        {
            page = this.graphicPages[pageIndex].hdrFtrPage;
        }
        arr = page.behindDocObjects.concat(page.beforeTextObjects);
        for(i = 0; i < arr.length; ++i)
        {
            if(arr[i].parent && arr[i].parent.DocumentContent === docContent)
            {
                ret.push(arr[i].parent);
            }
        }
        return ret;
    },

    getAllFloatTablesOnPage: function(pageIndex, docContent)
    {
        if(!this.graphicPages[pageIndex])
            this.graphicPages[pageIndex] = new CGraphicPage(pageIndex, this);
        if(!docContent)
        {
            docContent = this.document;
        }

        var tables, page;
        if(!docContent.IsHdrFtr())
        {

            page = this.graphicPages[pageIndex];
        }
        else
        {
            page = this.graphicPages[pageIndex].hdrFtrPage;
        }
        tables = page.flowTables;
        var ret = [];
        for(var i = 0; i < tables.length; ++i)
        {
            if(flowobject_Table === tables[i].Type && tables[i].Table.Parent === docContent)
                ret.push(tables[i]);
        }
        return ret;
    },

    getTargetDocContent: DrawingObjectsController.prototype.getTargetDocContent,
    getTextArtPreviewManager: DrawingObjectsController.prototype.getTextArtPreviewManager,
    getEditorApi: DrawingObjectsController.prototype.getEditorApi,
    resetConnectors: DrawingObjectsController.prototype.resetConnectors,
    checkDlblsPosition: DrawingObjectsController.prototype.checkDlblsPosition,

    handleChartDoubleClick: function(drawing, chart, e, x, y, pageIndex)
    {
        if(false === this.document.Document_Is_SelectionLocked(changestype_Drawing_Props))
        {
            editor.asc_doubleClickOnChart(this.getChartObject());
        }
        this.clearTrackObjects();
        this.clearPreTrackObjects();
        this.changeCurrentState(new AscFormat.NullState(this));
        this.document.OnMouseUp(e, x, y, pageIndex);
    },

    handleSignatureDblClick: function(sGuid, width, height){
        editor.sendEvent("asc_onSignatureDblClick", sGuid, width, height);
    },


    handleOleObjectDoubleClick: function(drawing, oleObject, e, x, y, pageIndex)
    {
		if(drawing && drawing.ParaMath){
			drawing.Convert_ToMathObject();
		}
        else if(false === this.document.Document_Is_SelectionLocked(changestype_Drawing_Props) || !this.document.CanEdit())
        {
            var pluginData = new Asc.CPluginData();
            pluginData.setAttribute("data", oleObject.m_sData);
            pluginData.setAttribute("guid", oleObject.m_sApplicationId);
            pluginData.setAttribute("width", oleObject.extX);
            pluginData.setAttribute("height", oleObject.extY);
            pluginData.setAttribute("widthPix", oleObject.m_nPixWidth);
            pluginData.setAttribute("heightPix", oleObject.m_nPixHeight);
            pluginData.setAttribute("objectId", oleObject.Id);
            editor.asc_pluginRun(oleObject.m_sApplicationId, 0, pluginData);
        }
        this.clearTrackObjects();
        this.clearPreTrackObjects();
        this.changeCurrentState(new AscFormat.NullState(this));
        this.document.OnMouseUp(e, x, y, pageIndex);
    },

    startEditCurrentOleObject: function(){
        var oSelector = this.selection.groupSelection ? this.selection.groupSelection : this;
        var oThis = this;
        if(oSelector.selectedObjects.length === 1 && oSelector.selectedObjects[0].getObjectType() === AscDFH.historyitem_type_OleObject){
            var oleObject = oSelector.selectedObjects[0];
            if(false === this.document.Document_Is_SelectionLocked(changestype_Drawing_Props)){
                var pluginData = new Asc.CPluginData();
                pluginData.setAttribute("data", oleObject.m_sData);
                pluginData.setAttribute("guid", oleObject.m_sApplicationId);
                pluginData.setAttribute("width", oleObject.extX);
                pluginData.setAttribute("height", oleObject.extY);
                pluginData.setAttribute("widthPix", oleObject.m_nPixWidth);
                pluginData.setAttribute("heightPix", oleObject.m_nPixHeight);
                pluginData.setAttribute("objectId", oleObject.Id);
                editor.asc_pluginRun(oleObject.m_sApplicationId, 0, pluginData);
            }
        }
    },

    handleMathDrawingDoubleClick : function(drawing, e, x, y, pageIndex)
    {
        drawing.Convert_ToMathObject();
        this.changeCurrentState(new AscFormat.NullState(this));
        this.document.OnMouseUp(e, x, y, pageIndex);
    },

    addInlineImage: function( W, H, Img, Chart, bFlow )
    {
        var content = this.getTargetDocContent();
        if(content)
        {
            if(!content.bPresentation){
                content.AddInlineImage(W, H, Img, Chart, bFlow );
            }
            else{
                if(this.selectedObjects.length > 0)
                {
                    this.resetSelection2();
                    this.document.AddInlineImage(W, H, Img, Chart, bFlow );
                }
            }
        }
        else
        {
            if(this.selectedObjects[0] && this.selectedObjects[0].parent && this.selectedObjects[0].parent.Is_Inline())
            {
                this.resetInternalSelection();
                this.document.Remove(1, true);
                this.document.AddInlineImage(W, H, Img, Chart, bFlow );
            }
            else
            {
                if(this.selectedObjects.length > 0)
                {
                    this.resetSelection2();
                    this.document.AddInlineImage(W, H, Img, Chart, bFlow );
                }
            }
        }
    },

    addSignatureLine: function(oSignatureDrawing)
    {
        var content = this.getTargetDocContent();
        if(content)
        {
            if(!content.bPresentation){
                content.AddSignatureLine(oSignatureDrawing);
            }
            else{
                if(this.selectedObjects.length > 0)
                {
                    this.resetSelection2();
                    this.document.AddSignatureLine(oSignatureDrawing);
                }
            }
        }
        else
        {
            if(this.selectedObjects[0] && this.selectedObjects[0].parent && this.selectedObjects[0].parent.Is_Inline())
            {
                this.resetInternalSelection();
                this.document.Remove(1, true);
                this.document.AddSignatureLine(oSignatureDrawing);
            }
            else
            {
                if(this.selectedObjects.length > 0)
                {
                    this.resetSelection2();
                    this.document.AddSignatureLine(oSignatureDrawing);
                }
            }
        }
    },

    getDrawingArray: function()
    {
        var ret = [];
        var arrDrawings = [].concat(this.drawingObjects);
        this.checkUseDrawings(arrDrawings);
        for(var i = 0; i < arrDrawings.length; ++i) {
            if(arrDrawings[i] && arrDrawings[i].GraphicObj && !arrDrawings[i].GraphicObj.bDeleted){
                ret.push(arrDrawings[i].GraphicObj);
            }
        }
        return ret;
    },

    getAllSignatures: AscFormat.DrawingObjectsController.prototype.getAllSignatures,

    getAllSignatures2: AscFormat.DrawingObjectsController.prototype.getAllSignatures2,

    addOleObject: function(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId)
    {
        var content = this.getTargetDocContent();
        if(content)
        {
            if(!content.bPresentation){
                content.AddOleObject(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId);
            }
            else{
                if(this.selectedObjects.length > 0)
                {
                    this.resetSelection2();
                    this.document.AddOleObject(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId);
                }
            }
        }
        else
        {
            if(this.selectedObjects[0] && this.selectedObjects[0].parent && this.selectedObjects[0].parent.Is_Inline())
            {
                this.resetInternalSelection();
                this.document.Remove(1, true);
                this.document.AddOleObject(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId);
            }
            else
            {
                if(this.selectedObjects.length > 0)
                {
                    this.resetSelection2();
                    this.document.AddOleObject(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId);
                }
            }
        }
    },

    addInlineTable: function( Cols, Rows )
    {
        var content = this.getTargetDocContent();
        if(content)
        {
            content.AddInlineTable(Cols, Rows);
        }
    },

    addImages: function( aImages )
    {
        var content = this.getTargetDocContent();
        if(content && !content.bPresentation)
        {
            content.AddImages(aImages);
        }
        else{
            this.resetSelection2();
            this.document.AddImages(aImages);
        }
    },


    canAddComment: function()
    {
        var content = this.getTargetDocContent();
        return content && content.CanAddComment();
    },

    addComment: function(commentData)
    {
        var content = this.getTargetDocContent();
        return content && content.AddComment(commentData, true, true);
    },

    hyperlinkCheck: DrawingObjectsController.prototype.hyperlinkCheck,

    hyperlinkCanAdd: DrawingObjectsController.prototype.hyperlinkCanAdd,

    hyperlinkRemove: DrawingObjectsController.prototype.hyperlinkRemove,

    hyperlinkModify: DrawingObjectsController.prototype.hyperlinkModify,

    hyperlinkAdd: DrawingObjectsController.prototype.hyperlinkAdd,

    isCurrentElementParagraph: function()
    {
        var content = this.getTargetDocContent();
        return content && content.Is_CurrentElementParagraph();
    },
    isCurrentElementTable: function()
    {
        var content = this.getTargetDocContent();
        return content && content.Is_CurrentElementTable();
    },


	GetSelectedContent : function(SelectedContent)
    {
        var content = this.getTargetDocContent();
        if(content)
        {
            content.GetSelectedContent(SelectedContent);
        }
        else
        {
            var para = new Paragraph(this.document.DrawingDocument, this.document);
            var selectedObjects, run, drawing, i;
            if(this.selection.groupSelection)
            {
                selectedObjects = this.selection.groupSelection.selectedObjects;
                var groupParaDrawing = this.selection.groupSelection.parent;
                //TODO: в случае инлановой группы для определения позиции нужно чтобы докуметн был рассчитан. Не понятно можно ли использовать рассчитаные позиции. Пока создаем инлайновые ParaDrawing.
                for(i = 0; i < selectedObjects.length; ++i)
                {
                    run =  new ParaRun(para, false);
                    selectedObjects[i].recalculate();
                    drawing = new ParaDrawing(0, 0, selectedObjects[i].copy(), this.document.DrawingDocument, this.document, null);
                    drawing.Set_DrawingType(groupParaDrawing.DrawingType);
                    drawing.GraphicObj.setParent(drawing);
                    if(drawing.GraphicObj.spPr && drawing.GraphicObj.spPr.xfrm && AscFormat.isRealNumber(drawing.GraphicObj.spPr.xfrm.offX) && AscFormat.isRealNumber(drawing.GraphicObj.spPr.xfrm.offY))
                    {
                        drawing.GraphicObj.spPr.xfrm.setOffX(0);
                        drawing.GraphicObj.spPr.xfrm.setOffY(0);
                    }
                    drawing.CheckWH();
                    if(groupParaDrawing.DrawingType === drawing_Anchor)
                    {
                        drawing.Set_Distance(groupParaDrawing.Distance.L, groupParaDrawing.Distance.T, groupParaDrawing.Distance.R, groupParaDrawing.Distance.B);
                        drawing.Set_WrappingType(groupParaDrawing.wrappingType);
                        drawing.Set_BehindDoc(groupParaDrawing.behindDoc);
                        drawing.Set_PositionH(groupParaDrawing.PositionH.RelativeFrom, groupParaDrawing.PositionH.Align, groupParaDrawing.PositionH.Value + selectedObjects[i].bounds.x, groupParaDrawing.PositionH.Percent);
                        drawing.Set_PositionV(groupParaDrawing.PositionV.RelativeFrom, groupParaDrawing.PositionV.Align, groupParaDrawing.PositionV.Value + selectedObjects[i].bounds.y, groupParaDrawing.PositionV.Percent);
                    }
                    run.Add_ToContent(run.State.ContentPos, drawing, true, false);
                    para.Internal_Content_Add(para.CurPos.ContentPos, run, true);
                }
            }
            else
            {
                selectedObjects = this.selectedObjects;
                for(i = 0; i < selectedObjects.length; ++i)
                {
                    run =  new ParaRun(para, false);
                    selectedObjects[i].recalculate();
                    drawing = new ParaDrawing(0, 0, selectedObjects[i].copy(), this.document.DrawingDocument, this.document, null);

                    drawing.Set_DrawingType(selectedObjects[i].parent.DrawingType);
                    if(selectedObjects[i].parent.Extent)
                    {
                        drawing.setExtent(selectedObjects[i].parent.Extent.W, selectedObjects[i].parent.Extent.H)
                    }
                    drawing.GraphicObj.setParent(drawing);
                    drawing.CheckWH();
					drawing.Set_ParaMath(selectedObjects[i].parent.ParaMath);
                    drawing.docPr.setFromOther(selectedObjects[i].parent.docPr);
                    if(selectedObjects[i].parent.DrawingType === drawing_Anchor)
                    {
                        drawing.Set_Distance(selectedObjects[i].parent.Distance.L, selectedObjects[i].parent.Distance.T, selectedObjects[i].parent.Distance.R, selectedObjects[i].parent.Distance.B);
                        drawing.Set_WrappingType(selectedObjects[i].parent.wrappingType);
                        drawing.Set_BehindDoc(selectedObjects[i].parent.behindDoc);
                        if(selectedObjects[i].parent.wrappingPolygon && drawing.wrappingPolygon)
                        {
                            drawing.wrappingPolygon.fromOther(selectedObjects[i].parent.wrappingPolygon);
                        }
                        drawing.Set_BehindDoc(selectedObjects[i].parent.behindDoc);
                        drawing.Set_RelativeHeight(selectedObjects[i].parent.RelativeHeight);
                        if(selectedObjects[i].parent.PositionH.Align){
                            drawing.Set_PositionH(selectedObjects[i].parent.PositionH.RelativeFrom, selectedObjects[i].parent.PositionH.Align, selectedObjects[i].parent.PositionH.Value, selectedObjects[i].parent.PositionH.Percent);
                        }
                        else{
                            drawing.Set_PositionH(selectedObjects[i].parent.PositionH.RelativeFrom, selectedObjects[i].parent.PositionH.Align, selectedObjects[i].parent.PositionH.Value + selectedObjects[i].bounds.x, selectedObjects[i].parent.PositionH.Percent);
                        }

                        if(selectedObjects[i].parent.PositionV.Align){
                            drawing.Set_PositionV(selectedObjects[i].parent.PositionV.RelativeFrom, selectedObjects[i].parent.PositionV.Align, selectedObjects[i].parent.PositionV.Value, selectedObjects[i].parent.PositionV.Percent);
                        }
                        else{
                            drawing.Set_PositionV(selectedObjects[i].parent.PositionV.RelativeFrom, selectedObjects[i].parent.PositionV.Align, selectedObjects[i].parent.PositionV.Value + selectedObjects[i].bounds.y, selectedObjects[i].parent.PositionV.Percent);
                        }
                    }
                    run.Add_ToContent(run.State.ContentPos, drawing, true, false);
                    para.Internal_Content_Add(para.CurPos.ContentPos, run, true);
                }
            }
            SelectedContent.Add( new CSelectedElement( para, true ) );
        }
    },

    getCurrentPageAbsolute: function()
    {
        if(this.curState.majorObject)
        {
            return this.curState.majorObject.selectStartPage;
        }
        var selection_arr = this.selectedObjects;
        if(selection_arr[0].length > 0)
        {
            return selection_arr[0].selectStartPage;
        }
        return 0;
    },

    createGraphicPage: function(pageIndex)
    {
        if(!isRealObject(this.graphicPages[pageIndex]))
            this.graphicPages[pageIndex] = new CGraphicPage(pageIndex, this);
    },

    resetDrawingArrays : function(pageIndex, docContent)
    {
        var hdr_ftr = docContent.IsHdrFtr(true);
        if(!hdr_ftr)
        {
            if(isRealObject(this.graphicPages[pageIndex]))
            {
                this.graphicPages[pageIndex].resetDrawingArrays(docContent);
            }
        }
    },

    mergeHdrFtrPages: function(page1, page2, pageIndex)
    {
        if(!isRealObject(this.graphicPages[pageIndex]))
            this.graphicPages[pageIndex] = new CGraphicPage(pageIndex, this);
        this.graphicPages[pageIndex].hdrFtrPage.clear();
        this.graphicPages[pageIndex].hdrFtrPage.mergePages(page1, page2);
    },



    onEndRecalculateDocument: function(pagesCount)
    {
        for(var i = 0; i < pagesCount; ++i)
        {
            if(!isRealObject(this.graphicPages[i]))
                this.graphicPages[i] = new CGraphicPage(i, this);
        }
        if(this.graphicPages.length > pagesCount)
        {
            for(i = pagesCount; i < this.graphicPages.length; ++i)
                delete  this.graphicPages[i];
        }
    },


    documentStatistics: function( CurPage, Statistics )
    {
        if(this.graphicPages[CurPage])
        {
            this.graphicPages[CurPage].documentStatistics(Statistics);
        }
    },

    setSelectionState: DrawingObjectsController.prototype.setSelectionState,

    getSelectionState: DrawingObjectsController.prototype.getSelectionState,
    applyPropsToChartSpace: DrawingObjectsController.prototype.applyPropsToChartSpace,

    documentUpdateSelectionState: function()
    {
        if(this.selection.textSelection)
        {
            this.selection.textSelection.updateSelectionState();
        }
        else if(this.selection.groupSelection)
        {
            this.selection.groupSelection.documentUpdateSelectionState();
        }
        else if(this.selection.chartSelection)
        {
            this.selection.chartSelection.documentUpdateSelectionState();
        }
        else
        {
            this.drawingDocument.SelectClear();
            this.drawingDocument.TargetEnd();
        }
    },


    getMajorParaDrawing: function()
    {
        return this.selectedObjects.length >  0  ? this.selectedObjects[0].parent : null;
    },

    documentUpdateRulersState: function()
    {
        var content = this.getTargetDocContent();
        if(content && content.Parent && content.Parent.getObjectType && content.Parent.getObjectType() === AscDFH.historyitem_type_Shape)
        {
            content.Parent.documentUpdateRulersState();
        }
       //else if(this.selectedObjects.length > 0)
       //{
       //    var parent_paragraph = this.selectedObjects[0].parent.Get_ParentParagraph();
       //    if(parent_paragraph)
       //    {
       //        parent_paragraph.Document_UpdateRulersState();
       //    }
       //}
    },


    updateTextPr: function()
    {
        var TextPr = this.getParagraphTextPr();
        if(TextPr)
        {
            var theme = this.document.Get_Theme();
            if(theme && theme.themeElements && theme.themeElements.fontScheme)
            {
                if(TextPr.FontFamily)
                {
                    TextPr.FontFamily.Name =  theme.themeElements.fontScheme.checkFont(TextPr.FontFamily.Name);
                }
                if(TextPr.RFonts)
                {
                    if(TextPr.RFonts.Ascii)
                        TextPr.RFonts.Ascii.Name     = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.Ascii.Name);
                    if(TextPr.RFonts.EastAsia)
                        TextPr.RFonts.EastAsia.Name  = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.EastAsia.Name);
                    if(TextPr.RFonts.HAnsi)
                        TextPr.RFonts.HAnsi.Name     = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.HAnsi.Name);
                    if(TextPr.RFonts.CS)
                        TextPr.RFonts.CS.Name        = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.CS.Name);
                }
            }
            editor.UpdateTextPr(TextPr);
        }
    },

    updateParentParagraphParaPr : function()
    {
        var majorParaDrawing = this.getMajorParaDrawing();
        if(majorParaDrawing)
        {
            var parent_para = this.selectedObjects[0].parent.Get_ParentParagraph(), ParaPr;
            if(parent_para)
            {
                ParaPr = parent_para.Get_CompiledPr2(true).ParaPr;
                if (ParaPr)
                {
                    var NumType    = -1;
                    var NumSubType = -1;

                    var oNumPr = parent_para.GetNumPr();
                    if (oNumPr && oNumPr.IsValid())
                    {
                    	var oNum = this.document.GetNumbering().GetNum(oNumPr.NumId);
                        if (oNum && oNum.GetLvl(oNumPr.Lvl))
                        {
                            var oInfo = oNum.GetLvl(oNumPr.Lvl).GetPresetType();

                            NumType    = oInfo.Type;
                            NumSubType = oInfo.SubType;
                        }
                    }

                    ParaPr.ListType = { Type : NumType, SubType : NumSubType };

                    editor.sync_ParaSpacingLine( ParaPr.Spacing );
                    editor.Update_ParaInd(ParaPr.Ind);
                    editor.sync_PrAlignCallBack(ParaPr.Jc);
                    editor.sync_ParaStyleName(ParaPr.StyleName);
                    editor.sync_ListType(ParaPr.ListType);
                }
            }
        }
    },

    documentUpdateInterfaceState: function()
    {
        if(this.selection.textSelection)
        {
            this.selection.textSelection.getDocContent().Document_UpdateInterfaceState();
        }
        else if(this.selection.groupSelection)
        {
            this.selection.groupSelection.documentUpdateInterfaceState();
        }
        else
        {
            var para_pr = DrawingObjectsController.prototype.getParagraphParaPr.call(this);
            if(!para_pr)
            {
                //if(this.selectedObjects[0] && this.selectedObjects[0].parent && this.selectedObjects[0].parent.Is_Inline())
                //{
                //    var parent_para = this.selectedObjects[0].parent.Get_ParentParagraph();
                //    if(parent_para)
                //        para_pr = parent_para.Get_CompiledPr2(true).ParaPr;
                //}
            }
            if(para_pr)
            {
                var TextPr = this.getParagraphTextPr();
                var theme = this.document.Get_Theme();
                if(theme && theme.themeElements && theme.themeElements.fontScheme)
                {
                    if(TextPr.FontFamily)
                    {
                        TextPr.FontFamily.Name =  theme.themeElements.fontScheme.checkFont(TextPr.FontFamily.Name);
                    }
                    if(TextPr.RFonts)
                    {
                        if(TextPr.RFonts.Ascii)
                            TextPr.RFonts.Ascii.Name     = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.Ascii.Name);
                        if(TextPr.RFonts.EastAsia)
                            TextPr.RFonts.EastAsia.Name  = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.EastAsia.Name);
                        if(TextPr.RFonts.HAnsi)
                            TextPr.RFonts.HAnsi.Name     = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.HAnsi.Name);
                        if(TextPr.RFonts.CS)
                            TextPr.RFonts.CS.Name        = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.CS.Name);
                    }
                }
                editor.UpdateParagraphProp(para_pr);
                editor.UpdateTextPr(TextPr);
            }
        }
    },

    resetInterfaceTextPr: function()
    {
       // var oTextPr =  new CTextPr();
       // oTextPr.Set_FromObject(
       //     {
       //         Bold: false,
       //         Italic: false,
       //         Underline: false,
       //         Strikeout: false,
       //         FontFamily:{
       //             Name : "", Index : -1
       //         },
       //         FontSize: null,
       //         VertAlign: null,
       //         HighLight: highlight_None,
       //         Spacing: null,
       //         DStrikeout: false,
       //         Caps: null,
       //         SmallCaps: null,
       //         Position: null,
       //         Lang: null
       //     }
       // );
       // editor.UpdateTextPr(oTextPr);
		editor.Update_ParaTab(AscCommonWord.Default_Tab_Stop, new CParaTabs());
        editor.sync_ParaSpacingLine( new CParaSpacing() );
        editor.Update_ParaInd(new CParaInd());
        editor.sync_PrAlignCallBack(null);
        editor.sync_ParaStyleName(null);
        editor.sync_ListType({ Type : -1, SubType : -1 });
    },

    isNeedUpdateRulers: function()
    {
        if(this.selectedObjects.length === 1 && this.selectedObjects[0].getDocContent && this.selectedObjects[0].getDocContent())
        {
            return true;
        }
        return false;
    },

    documentCreateFontCharMap: function( FontCharMap )
    {
        //ToDo
        return;
    },

    documentCreateFontMap: function( FontCharMap )
    {
        //TODO
        return;
    },

    tableCheckSplit: function()
    {
        var content = this.getTargetDocContent();
        return content && content.CanSplitTableCells();
    },

    tableCheckMerge: function()
    {
        var content = this.getTargetDocContent();
        return content && content.CanMergeTableCells();
    },

    tableSelect: function( Type )
    {
        var content = this.getTargetDocContent();
        return content && content.SelectTable(Type);
    },

    tableRemoveTable: function()
    {
        var content = this.getTargetDocContent();
        return content && content.RemoveTable();
    },

    tableSplitCell: function(Cols, Rows)
    {
        var content = this.getTargetDocContent();
        return content && content.SplitTableCells(Cols, Rows);
    },

    tableMergeCells: function()
    {
        var content = this.getTargetDocContent();
        return content && content.MergeTableCells();
    },

    tableRemoveCol: function()
    {
        var content = this.getTargetDocContent();
        return content && content.RemoveTableColumn();
    },


    tableAddCol: function(bBefore)
    {
        var content = this.getTargetDocContent();
        return content && content.AddTableColumn(bBefore);
    },

    tableRemoveRow: function()
    {

        var content = this.getTargetDocContent();
        return content && content.RemoveTableRow();
    },

    tableAddRow: function(bBefore)
    {

        var content = this.getTargetDocContent();
        return content && content.AddTableRow(bBefore);
    },

	distributeTableCells : function(isHorizontally)
	{
		var content = this.getTargetDocContent();
		return content && content.DistributeTableCells(isHorizontally);
	},


    documentSearch: function( CurPage, String, search_Common )
    {
        if(this.graphicPages[CurPage])
        {
            this.graphicPages[CurPage].documentSearch(String, search_Common);
            CGraphicPage.prototype.documentSearch.call(this.getHdrFtrObjectsByPageIndex(CurPage), String, search_Common);
        }
    },

    getSelectedElementsInfo: function( Info )
    {

        if(this.selectedObjects.length === 0)
            Info.Set_Drawing(-1);

        var content = this.getTargetDocContent();
        if(content)
        {
            Info.Set_Drawing(selected_DrawingObjectText);
            content.GetSelectedElementsInfo(Info);
        }
        else
        {
            Info.Set_Drawing(selected_DrawingObject);
        }
        return Info;
    },

    getAllObjectsOnPage: function(pageIndex, bHdrFtr)
    {
        var graphic_page;
        if(bHdrFtr)
        {
            graphic_page = this.getHdrFtrObjectsByPageIndex(pageIndex);
        }
        else
        {
            graphic_page = this.graphicPages[pageIndex];
        }
        return graphic_page? graphic_page.behindDocObjects.concat(graphic_page.inlineObjects.concat(graphic_page.beforeTextObjects)) : [];
    },

    selectNextObject: DrawingObjectsController.prototype.selectNextObject,


    getCurrentParagraph: function(bIgnoreSelection, arrSelectedParagraphs)
    {
        var content = this.getTargetDocContent();
        if(content)
        {
            return content.GetCurrentParagraph(bIgnoreSelection, arrSelectedParagraphs);
        }
        else
        {
            var ParaDrawing = this.getMajorParaDrawing();
            if (ParaDrawing && ParaDrawing.Parent instanceof Paragraph)
                return ParaDrawing.Parent;

            return null;
        }
    },

    getSelectedText: function(bClearText, oPr)
    {
        var content = this.getTargetDocContent();
        if(content)
        {
            return content.GetSelectedText(bClearText, oPr);
        }
        else
        {
            return "";
        }
    },

    getCurPosXY: function()
    {
        var content = this.getTargetDocContent();
        if(content)
        {
            return content.GetCurPosXY();
        }
        else
        {
            if(this.selectedObjects.length === 1)
            {
                return {X:this.selectedObjects[0].parent.X, Y: this.selectedObjects[0].parent.Y};
            }
            return {X: 0, Y: 0};
        }
    },

    isTextSelectionUse: function()
    {

        var content = this.getTargetDocContent();
        if(content)
        {
            return content.IsTextSelectionUse();
        }
        else
        {
            return false;
        }
    },


    isSelectionUse: function()
    {
        var content = this.getTargetDocContent();
        if(content)
        {
            return content.IsTextSelectionUse();
        }
        else
        {
            return this.selectedObjects.length > 0;
        }
    },

    paragraphFormatPaste: function( CopyTextPr, CopyParaPr, Bool )
    {
        var content = this.getTargetDocContent();
        content && content.PasteFormatting(CopyTextPr, CopyParaPr, Bool );
    },

    getHdrFtrObjectsByPageIndex: function(pageIndex)
    {
        if(this.graphicPages[pageIndex])
        {
            return this.graphicPages[pageIndex].hdrFtrPage;
        }
        return null;
    },

    getNearestPos: function(x, y, pageIndex, drawing)
    {
        if(drawing && drawing.GraphicObj)
        {
            if(drawing.GraphicObj.getObjectType() !== AscDFH.historyitem_type_ImageShape && drawing.GraphicObj.getObjectType() !== AscDFH.historyitem_type_OleObject && drawing.GraphicObj.getObjectType() !== AscDFH.historyitem_type_ChartSpace)
                return null;
        }
        this.handleEventMode = HANDLE_EVENT_MODE_CURSOR;
        var cursor_type = this.nullState.onMouseDown(global_mouseEvent, x, y, pageIndex);
        this.handleEventMode = HANDLE_EVENT_MODE_HANDLE;
        var object;
        if(cursor_type )
        {
            object = g_oTableId.Get_ById(cursor_type.objectId);
            if(object)
            {
                if(cursor_type.cursorType === "text")
                {
                    if(object.getNearestPos)
                    {
                        return object.getNearestPos(x, y, pageIndex);
                    }
                }
                else
                {
                    if((object.getObjectType() === AscDFH.historyitem_type_ImageShape || object.getObjectType() === AscDFH.historyitem_type_OleObject) && object.parent)
                    {
                        var oShape = object.parent.isShapeChild(true);
                        if(oShape)
                        {
                            return oShape.getNearestPos(x, y, pageIndex);
                        }
                    }
                }
            }
        }
        return null;
    },

    selectionCheck: function( X, Y, Page_Abs, NearPos )
    {
        var text_object = AscFormat.getTargetTextObject(this);
        if(text_object)
            return text_object.selectionCheck( X, Y, Page_Abs, NearPos );
        return false;
    },

    checkTextObject: function(x, y, pageIndex)
    {
        var text_object = AscFormat.getTargetTextObject(this);
        if(text_object && text_object.hitInTextRect)
        {
            if(text_object.selectStartPage === pageIndex)
            {
                if(text_object.hitInTextRect(x, y))
                {
                    return true;
                }
            }
        }
        return false;
    },

    getParagraphParaPrCopy: function()
    {
        return this.getParagraphParaPr();
    },

    getParagraphTextPrCopy: function()
    {
        return this.getParagraphTextPr();
    },

    getParagraphParaPr: function()
    {
        var ret =  DrawingObjectsController.prototype.getParagraphParaPr.call(this);

        if(ret && ret.Shd && ret.Shd.Unifill)
        {
            ret.Shd.Unifill.check(this.document.theme, this.document.Get_ColorMap());
        }
        return ret ? ret : new CParaPr();
    },

    getColorMap: function()
    {
        return this.document.Get_ColorMap();
    },


	GetStyleFromFormatting: function()
    {
        var oContent = this.getTargetDocContent();
        if(oContent)
        {
            var oStyleFormatting = oContent.GetStyleFromFormatting();
            var oTextPr = oStyleFormatting.TextPr;
            if(oTextPr.TextFill)
            {
                oTextPr.TextFill = undefined;
            }
            if(oTextPr.TextOutline)
            {
                oTextPr.TextOutline = undefined;
            }
            return oStyleFormatting;
        }
        return null;
    },

    getParagraphTextPr: function()
    {
        var ret =  DrawingObjectsController.prototype.getParagraphTextPr.call(this);
        if(ret)
        {
            var ret_;
            if(ret.Unifill && ret.Unifill.canConvertPPTXModsToWord())
            {
                ret_ = ret.Copy();
                ret_.Unifill.convertToWordMods();
            }
            else
            {
                ret_ = ret;
            }
            if(ret_.Unifill)
            {
                ret_.Unifill.check(this.document.theme, this.document.Get_ColorMap());
            }
            return ret_;
        }
        else
        {
            return new CTextPr();
        }
    },

    isSelectedText: function()
    {
        return isRealObject(/*this.selection.textSelection || this.selection.groupSelection && this.selection.groupSelection.selection.textSelection*/this.getTargetDocContent());
    },

    selectAll: DrawingObjectsController.prototype.selectAll,

    drawSelect: function(pageIndex)
    {
        DrawingObjectsController.prototype.drawSelect.call(this, pageIndex, this.drawingDocument);
    },

    drawBehindDoc: function(pageIndex, graphics)
    {
        if(this.graphicPages[pageIndex])
        {
            graphics.shapePageIndex = pageIndex;
            this.graphicPages[pageIndex].drawBehindDoc(graphics);
            graphics.shapePageIndex = null;
        }
    },

    drawBehindObjectsByContent: function(pageIndex, graphics, content)
    {
        var page;
        if(content.IsHdrFtr())
        {
            page = this.getHdrFtrObjectsByPageIndex(pageIndex);
        }
        else
        {
            page = this.graphicPages[pageIndex];
        }
        page && page.drawBehindObjectsByContent(graphics, content)
    },

    drawBeforeObjectsByContent: function(pageIndex, graphics, content)
    {
        var page;
        if(content.IsHdrFtr())
        {
            page = this.getHdrFtrObjectsByPageIndex(pageIndex);
        }
        else
        {
            page = this.graphicPages[pageIndex];
        }
        page && page.drawBeforeObjectsByContent(graphics, content)
    },


    endTrackShape: function()
    {

    },

    drawBeforeObjects: function(pageIndex, graphics)
    {
        if(this.graphicPages[pageIndex])
        {
            graphics.shapePageIndex = pageIndex;
            this.graphicPages[pageIndex].drawBeforeObjects(graphics);
            graphics.shapePageIndex = null;
        }
    },

    drawBehindDocHdrFtr: function(pageIndex, graphics)
    {

        graphics.shapePageIndex = pageIndex;
        var hdr_footer_objects = this.getHdrFtrObjectsByPageIndex(pageIndex);

        if(hdr_footer_objects != null)
        {
            var behind_doc = hdr_footer_objects.behindDocObjects;
            for(var i = 0; i < behind_doc.length; ++i)
            {
                behind_doc[i].draw(graphics);
            }
        }
        graphics.shapePageIndex = null;
    },


    drawBeforeObjectsHdrFtr: function(pageIndex, graphics)
    {
        graphics.shapePageIndex = pageIndex;
        var hdr_footer_objects = this.getHdrFtrObjectsByPageIndex(pageIndex);
        if(hdr_footer_objects != null)
        {
            var bef_arr = hdr_footer_objects.beforeTextObjects;
            for(var i = 0; i < bef_arr.length; ++i)
            {
                bef_arr[i].draw(graphics);
            }
        }
        graphics.shapePageIndex = null;
    },

    setStartTrackPos: function(x, y, pageIndex)
    {
        this.startTrackPos.x = x;
        this.startTrackPos.y = y;
        this.startTrackPos.pageIndex = pageIndex;
    },

    needUpdateOverlay: function()
    {
        return this.arrTrackObjects.length > 0 || this.curState.InlinePos;
    },

    changeCurrentState: function(state)
    {
        this.curState = state;
    },

    handleDblClickEmptyShape: function(oShape){
        if(!oShape.getDocContent() && !AscFormat.CheckLinePresetForParagraphAdd(oShape.getPresetGeom())){

            if(false === this.document.Document_Is_SelectionLocked(changestype_Drawing_Props))
            {
                History.Create_NewPoint(AscDFH.historydescription_Document_GrObjectsBringBackward);
                if(!oShape.bWordShape){
                    oShape.createTextBody();
                }
                else{
                    oShape.createTextBoxContent();
                }
                this.document.Recalculate();
                var oContent = oShape.getDocContent();
                oContent.Set_CurrentElement(0, true);
                this.updateSelectionState();
            }
            this.clearTrackObjects();
            this.clearPreTrackObjects();
            this.changeCurrentState(new AscFormat.NullState(this));
        }
    },

    canGroup: function(bGetArray)
    {
        var selection_array = this.selectedObjects;
        if(selection_array.length < 2)
            return bGetArray ? [] :false;
        if(!selection_array[0].canGroup())
            return bGetArray ? [] : false;
        var first_page_index = selection_array[0].parent.pageIndex;
        for(var index = 1; index < selection_array.length; ++index)
        {
            if(!selection_array[index].canGroup())
                return  bGetArray ? [] : false;
            if(first_page_index !== selection_array[index].parent.pageIndex)
                return bGetArray ? [] : false;
        }
        if(bGetArray)
        {
            var ret = selection_array.concat([]);
            ret.sort(ComparisonByZIndexSimpleParent);
            return ret;
        }
        return true;
    },

    canUnGroup: DrawingObjectsController.prototype.canUnGroup,
    getBoundsForGroup: DrawingObjectsController.prototype.getBoundsForGroup,


    getArrayForGrouping: function()
    {
        return this.canGroup(true);
    },


    startSelectionFromCurPos: function()
    {
        var content = this.getTargetDocContent();
        if(content)
        {
            content.StartSelectionFromCurPos();
        }
    },


    Check_TrackObjects: function()
    {
        return this.arrTrackObjects.length > 0;
    },

    getGroup: DrawingObjectsController.prototype.getGroup,

    addObjectOnPage: function(pageIndex, object)
    {
        var hdr_ftr = object.parent.DocumentContent.IsHdrFtr(true);
        if(!hdr_ftr)
        {
            if(!this.graphicPages[pageIndex])
            {
                this.graphicPages[pageIndex] = new CGraphicPage(pageIndex, this);
                for(var z = 0; z < pageIndex; ++z)
                {
                    if(!this.graphicPages[z])
                        this.graphicPages[z] = new CGraphicPage(z, this);
                }
            }
            this.graphicPages[pageIndex].addObject(object);
        }
        else
        {
            //hdr_ftr.DrawingPage.addObject(object);
        }
    },

    cursorGetPos: function()
    {
        var oTargetDocContent = this.getTargetDocContent();
        if(oTargetDocContent){
            var oPos = oTargetDocContent.GetCursorPosXY();
            var oTransform = oTargetDocContent.Get_ParentTextTransform();
            if(oTransform){
                var _x = oTransform.TransformPointX(oPos.X, oPos.Y);
                var _y = oTransform.TransformPointY(oPos.X, oPos.Y);
                return {X: _x, Y: _y};
            }
            return oPos;
        }
        return {X: 0, Y: 0};
    },

	GetSelectionBounds: DrawingObjectsController.prototype.GetSelectionBounds,

    checkCommonBounds: function(arrDrawings)
    {
        var l, t, r,b;
        var x_arr_min = [], y_arr_min = [];
        var x_arr_max = [], y_arr_max = [];
        for(var i = 0; i < arrDrawings.length; ++i)
        {
            var rot = AscFormat.normalizeRotate(AscFormat.isRealNumber(arrDrawings[i].rot) ? arrDrawings[i].rot : 0);
            if (AscFormat.checkNormalRotate(rot))
            {
                l = arrDrawings[i].posX;
                r = arrDrawings[i].extX + arrDrawings[i].posX;
                t = arrDrawings[i].posY;
                b = arrDrawings[i].extY + arrDrawings[i].posY;
            }
            else
            {
                l = arrDrawings[i].posX + arrDrawings[i].extX/2 - arrDrawings[i].extY/2;
                r = arrDrawings[i].posX + arrDrawings[i].extX/2 + arrDrawings[i].extY/2;
                t = arrDrawings[i].posY + arrDrawings[i].extY/2 - arrDrawings[i].extX/2;
                b = arrDrawings[i].extY + arrDrawings[i].extY/2 + arrDrawings[i].extX/2;
            }

            x_arr_max.push(r);
            x_arr_min.push(l);
            y_arr_max.push(b);
            y_arr_min.push(t);
        }
        return {minX: Math.min.apply(Math, x_arr_min), maxX: Math.max.apply(Math, x_arr_max), minY: Math.min.apply(Math, y_arr_min), maxY: Math.max.apply(Math, y_arr_max)};
    },

    groupSelectedObjects: function()
    {
        var objects_for_grouping = this.canGroup(true);
        if(objects_for_grouping.length < 2)
            return;
        var bTrackRevisions = false;
        if(this.document.TrackRevisions){
            bTrackRevisions = true;
            this.document.TrackRevisions = false;
        }
        var i;
        var common_bounds = this.checkCommonBounds(objects_for_grouping);
        var para_drawing = new ParaDrawing(common_bounds.maxX - common_bounds.minX, common_bounds.maxY - common_bounds.minY, null, this.drawingDocument, null, null);
        para_drawing.Set_WrappingType(WRAPPING_TYPE_NONE);
        para_drawing.Set_DrawingType(drawing_Anchor);
        for(i = 0; i < objects_for_grouping.length; ++i)
        {
            if(objects_for_grouping[i].checkExtentsByDocContent && objects_for_grouping[i].checkExtentsByDocContent(true))
            {
                objects_for_grouping[i].updatePosition(objects_for_grouping[i].posX, objects_for_grouping[i].posY)
            }
        }
        var group = this.getGroup(objects_for_grouping);
        group.spPr.xfrm.setOffX(0);
        group.spPr.xfrm.setOffY(0);
        group.setParent(para_drawing);
        para_drawing.Set_GraphicObject(group);

        var page_index = objects_for_grouping[0].parent.pageIndex;
        var first_paragraph = objects_for_grouping[0].parent.Get_ParentParagraph();
        var nearest_pos = this.document.Get_NearestPos(objects_for_grouping[0].parent.pageIndex, common_bounds.minX, common_bounds.minY, true, para_drawing);

        nearest_pos.Paragraph.Check_NearestPos(nearest_pos);

        var nPageIndex = objects_for_grouping[0].parent.pageIndex;
        for(i = 0; i < objects_for_grouping.length; ++i)
        {
            objects_for_grouping[i].parent.Remove_FromDocument(false);
            if(objects_for_grouping[i].setParent){
                objects_for_grouping[i].setParent(null);
            }
        }
        para_drawing.Set_XYForAdd( common_bounds.minX,  common_bounds.minY, nearest_pos, nPageIndex);
        para_drawing.Set_Props(new asc_CImgProperty(
            {
                PositionH:
                {
                    RelativeFrom: Asc.c_oAscRelativeFromH.Page,
                    UseAlign : false,
                    Align    : undefined,
                    Value    : common_bounds.minX
                },

                PositionV:
                {
                    RelativeFrom: Asc.c_oAscRelativeFromV.Page,
                    UseAlign    : false,
                    Align       : undefined,
                    Value       : common_bounds.minY
                }
            }));
        para_drawing.Add_ToDocument2(first_paragraph);
        para_drawing.Parent = first_paragraph;
        this.addGraphicObject(para_drawing);
        this.resetSelection();
        this.selectObject(group, page_index);
        this.document.Recalculate();
        if(bTrackRevisions){
            this.document.TrackRevisions = true;
        }
    },

    unGroupSelectedObjects: function()
    {
        if(!(this.isViewMode() === false))
            return;
        var bTrackRevisions = false;
        if(this.document.TrackRevisions){
            bTrackRevisions = true;
            this.document.TrackRevisions = false;
        }
        var ungroup_arr = this.canUnGroup(true);
        if(ungroup_arr.length > 0)
        {
            this.resetSelection();
            var i, j, nearest_pos, cur_group, sp_tree, sp, parent_paragraph, page_num;
            var a_objects = [];
            var arrCenterPos = [], aPos;
            for(i = 0; i < ungroup_arr.length; ++i)
            {
                cur_group = ungroup_arr[i];
                sp_tree = cur_group.spTree;
                aPos = [];
                for(j = 0; j < sp_tree.length; ++j)
                {
                    sp = sp_tree[j];
                    xc = sp.transform.TransformPointX(sp.extX/2, sp.extY/2);
                    yc = sp.transform.TransformPointY(sp.extX/2, sp.extY/2);
                    aPos.push({xc: xc, yc: yc});
                }
                arrCenterPos.push(aPos);
            }

            for(i = 0; i < ungroup_arr.length; ++i)
            {
                cur_group = ungroup_arr[i];
                parent_paragraph = cur_group.parent.Get_ParentParagraph();
                page_num = cur_group.selectStartPage;
                cur_group.normalize();
                cur_group.parent.Remove_FromDocument(false);
                cur_group.setBDeleted(true);
                sp_tree = cur_group.spTree;
                aPos = arrCenterPos[i];
                for(j = 0; j < sp_tree.length; ++j)
                {
                    sp = sp_tree[j];
                    var drawing = new ParaDrawing(0, 0, sp_tree[j], this.drawingDocument, null, null);

                    var xc, yc, hc = sp.extX/2, vc = sp.extY/2;
                    if(aPos && aPos[j]){
                        xc = aPos[j].xc;
                        yc = aPos[j].yc;
                    }
                    else {
                        xc = sp.transform.TransformPointX(hc, vc);
                        yc = sp.transform.TransformPointY(hc, vc);
                    }

                    drawing.Set_GraphicObject(sp);
                    sp.setParent(drawing);
                    drawing.Set_DrawingType(drawing_Anchor);
                    drawing.Set_WrappingType(cur_group.parent.wrappingType);
                    drawing.Set_BehindDoc(cur_group.parent.behindDoc);
                    drawing.CheckWH();
                    sp.spPr.xfrm.setRot(AscFormat.normalizeRotate(sp.rot + cur_group.rot));
                    sp.spPr.xfrm.setOffX(0);
                    sp.spPr.xfrm.setOffY(0);
                    sp.spPr.xfrm.setFlipH(cur_group.spPr.xfrm.flipH === true ? !(sp.spPr.xfrm.flipH === true) : sp.spPr.xfrm.flipH === true);
                    sp.spPr.xfrm.setFlipV(cur_group.spPr.xfrm.flipV === true ? !(sp.spPr.xfrm.flipV === true) : sp.spPr.xfrm.flipV === true);
                    sp.setGroup(null);
                    if(sp.spPr.Fill && sp.spPr.Fill.fill && sp.spPr.Fill.fill.type === Asc.c_oAscFill.FILL_TYPE_GRP && cur_group.spPr && cur_group.spPr.Fill)
                    {
                        sp.spPr.setFill(cur_group.spPr.Fill.createDuplicate());
                    }

                    nearest_pos = this.document.Get_NearestPos(page_num, sp.bounds.x + sp.posX, sp.bounds.y + sp.posY, true, drawing);
                    nearest_pos.Paragraph.Check_NearestPos(nearest_pos);

                    drawing.Set_XYForAdd(xc - hc, yc - vc, nearest_pos, page_num);
                    a_objects.push({drawing: drawing, par: parent_paragraph, posX: xc - hc, posY: yc - vc});
                    this.selectObject(sp, page_num);
                }
            }
            for(i = 0; i < a_objects.length; ++i)
            {
                a_objects[i].drawing.Set_Props(new asc_CImgProperty(
                    {
                        PositionH:
                        {
                            RelativeFrom: Asc.c_oAscRelativeFromH.Page,
                            UseAlign : false,
                            Align    : undefined,
                            Value    : a_objects[i].posX
                        },

                        PositionV:
                        {
                            RelativeFrom: Asc.c_oAscRelativeFromV.Page,
                            UseAlign    : false,
                            Align       : undefined,
                            Value       : a_objects[i].posY
                        }
                    }));
                a_objects[i].drawing.Add_ToDocument2(a_objects[i].par);
            }
            this.document.Recalculate();
        }
        if(bTrackRevisions){
            this.document.TrackRevisions = true;
        }
    },

    setTableProps: function(Props)
    {
        var content = this.getTargetDocContent();
        if(content)
        {
            content.SetTableProps(Props);
        }
    },


    selectionIsEmpty: function(bCheckHidden)
    {
        var content = this.getTargetDocContent();
        if(content)
        {
            content.IsSelectionEmpty(bCheckHidden);
        }
        return false;
    },

    moveSelectedObjects: DrawingObjectsController.prototype.moveSelectedObjects,

    cursorMoveLeft: DrawingObjectsController.prototype.cursorMoveLeft,

    cursorMoveRight: DrawingObjectsController.prototype.cursorMoveRight,


    cursorMoveUp: DrawingObjectsController.prototype.cursorMoveUp,

    cursorMoveDown: DrawingObjectsController.prototype.cursorMoveDown,

    cursorMoveEndOfLine: DrawingObjectsController.prototype.cursorMoveEndOfLine,
    getMoveDist: DrawingObjectsController.prototype.getMoveDist,


    cursorMoveStartOfLine: DrawingObjectsController.prototype.cursorMoveStartOfLine,

    cursorMoveAt: DrawingObjectsController.prototype.cursorMoveAt,
    getAllConnectors: DrawingObjectsController.prototype.getAllConnectors,
    getAllConnectorsByDrawings: DrawingObjectsController.prototype.getAllConnectorsByDrawings,

    cursorMoveToCell: function(bNext )
    {
        var content = this.getTargetDocContent();
        if(content)
        {
            content.MoveCursorToCell(bNext);
        }
    },

    updateAnchorPos: function()
    {
        //TODO
    },

    resetSelection: DrawingObjectsController.prototype.resetSelection,
    deselectObject: DrawingObjectsController.prototype.deselectObject,

    resetSelection2: function()
    {
        var sel_arr = this.selectedObjects;
        if(sel_arr.length > 0)
        {
            var top_obj = sel_arr[0];
            for(var i = 1; i < sel_arr.length; ++i)
            {
                var cur_obj = sel_arr[i];
                if(cur_obj.selectStartPage < top_obj.selectStartPage)
                {
                    top_obj = cur_obj;
                }
                else if(cur_obj.selectStartPage === top_obj.selectStartPage)
                {
                    if(cur_obj.parent.Get_ParentParagraph().Y < top_obj.parent.Get_ParentParagraph().Y)
                        top_obj = cur_obj;
                }
            }
            this.resetSelection();
            top_obj.parent.GoTo_Text();
        }
    },

    moveCursorToSignature: function(sGuid)
    {
        var aSignatureShapes = this.getAllSignatures2([], this.getDrawingArray());
        var oShape, oMainGroup;
        for(var i = 0; i < aSignatureShapes.length; ++i)
        {
            oShape = aSignatureShapes[i];
            if(oShape && oShape.signatureLine && oShape.signatureLine.id === sGuid)
            {
                oMainGroup = oShape.getMainGroup();
                if(oMainGroup)
                {
                    if(oMainGroup.parent)
                    {
                        this.resetSelection();
                        oMainGroup.parent.GoTo_Text(true, true);
                    }
                }
                else
                {
                    if(oShape.parent)
                    {
                        this.resetSelection();
                        oShape.parent.GoTo_Text(true, true);
                    }
                }
                return;
            }
        }
    },

    recalculateCurPos: DrawingObjectsController.prototype.recalculateCurPos,

    remove: function(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd)
    {
        var content = this.getTargetDocContent(true);
        if(content)
        {
            content.Remove(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd);
            var oTargetTextObject = AscFormat.getTargetTextObject(this);
            oTargetTextObject && oTargetTextObject.checkExtentsByDocContent && oTargetTextObject.checkExtentsByDocContent();
            this.document.Recalculate();
        }
        else if(this.selectedObjects.length > 0)
        {
            if(this.selection.groupSelection)
            {
                if(this.selection.groupSelection.selection.chartSelection)
                {
                    this.selection.groupSelection.selection.chartSelection.remove();
                    this.document.Recalculate();
                }
                else
                {
                    var group_map = {}, group_arr = [], i, cur_group, sp, xc, yc, hc, vc, rel_xc, rel_yc, j;
                    for(i = 0; i < this.selection.groupSelection.selectedObjects.length; ++i)
                    {
                        this.selection.groupSelection.selectedObjects[i].group.removeFromSpTree(this.selection.groupSelection.selectedObjects[i].Get_Id());
                        group_map[this.selection.groupSelection.selectedObjects[i].group.Get_Id()+""] = this.selection.groupSelection.selectedObjects[i].group;
                    }
                    group_map[this.selection.groupSelection.Get_Id()] = this.selection.groupSelection;
                    for(var key in group_map)
                    {
                        if(group_map.hasOwnProperty(key))
                            group_arr.push(group_map[key]);
                    }
                    group_arr.sort(AscFormat.CompareGroups);
                    for(i = 0; i < group_arr.length; ++i)
                    {
                        cur_group = group_arr[i];
                        if(isRealObject(cur_group.group))
                        {
                            if(cur_group.spTree.length === 0)
                            {
                                cur_group.group.removeFromSpTree(cur_group.Get_Id());
                            }
                            else if(cur_group.spTree.length == 1)
                            {
                                sp = cur_group.spTree[0];
                                hc = sp.spPr.xfrm.extX/2;
                                vc = sp.spPr.xfrm.extY/2;
                                xc = sp.transform.TransformPointX(hc, vc);
                                yc = sp.transform.TransformPointY(hc, vc);
                                rel_xc = cur_group.group.invertTransform.TransformPointX(xc, yc);
                                rel_yc = cur_group.group.invertTransform.TransformPointY(xc, yc);
                                sp.spPr.xfrm.setOffX(rel_xc - hc);
                                sp.spPr.xfrm.setOffY(rel_yc - vc);
                                sp.spPr.xfrm.setRot(AscFormat.normalizeRotate(cur_group.rot + sp.rot));
                                sp.spPr.xfrm.setFlipH(cur_group.spPr.xfrm.flipH === true ? !(sp.spPr.xfrm.flipH === true) : sp.spPr.xfrm.flipH === true);
                                sp.spPr.xfrm.setFlipV(cur_group.spPr.xfrm.flipV === true ? !(sp.spPr.xfrm.flipV === true) : sp.spPr.xfrm.flipV === true);
                                sp.setGroup(cur_group.group);
                                for(j = 0; j < cur_group.group.spTree.length; ++j)
                                {
                                    if(cur_group.group.spTree[j] === cur_group)
                                    {
                                        cur_group.group.addToSpTree(j, sp);
                                        cur_group.group.removeFromSpTree(cur_group.Get_Id());
                                    }
                                }
                            }
                        }
                        else
                        {
                            var para_drawing = cur_group.parent;
                            if(cur_group.spTree.length === 0)
                            {
                                this.resetInternalSelection();
                                this.remove();
                                return;
                            }
                            else if(cur_group.spTree.length === 1)
                            {
                                sp = cur_group.spTree[0];
                                sp.spPr.xfrm.setOffX(0);
                                sp.spPr.xfrm.setOffY(0);
                                sp.spPr.xfrm.setRot(AscFormat.normalizeRotate(cur_group.rot + sp.rot));
                                sp.spPr.xfrm.setFlipH(cur_group.spPr.xfrm.flipH === true ? !(sp.spPr.xfrm.flipH === true) : sp.spPr.xfrm.flipH === true);
                                sp.spPr.xfrm.setFlipV(cur_group.spPr.xfrm.flipV === true ? !(sp.spPr.xfrm.flipV === true) : sp.spPr.xfrm.flipV === true);
                                sp.setGroup(null);
                                para_drawing.Set_GraphicObject(sp);
                                sp.setParent(para_drawing);
                                this.resetSelection();
                                this.selectObject(sp, cur_group.selectStartPage);
                                new_x = sp.transform.tx;
                                new_y = sp.transform.ty;
                                para_drawing.CheckWH();
                                if(!para_drawing.Is_Inline())
                                {
                                    para_drawing.Set_XY(new_x, new_y, para_drawing.Get_ParentParagraph(), para_drawing.GraphicObj.selectStartPage, true);
                                }
                                this.document.Recalculate();
                                return;
                            }
                            else
                            {
                                this.resetInternalSelection();
                                var new_x, new_y;
                               // var pos = cur_group.getBoundsPos();
                                cur_group.updateCoordinatesAfterInternalResize();

                                new_x = cur_group.x + cur_group.spPr.xfrm.offX;
                                new_y = cur_group.y + cur_group.spPr.xfrm.offY;

                                cur_group.spPr.xfrm.setOffX(0);
                                cur_group.spPr.xfrm.setOffY(0);

                                para_drawing.Set_XY(new_x, new_y, cur_group.parent.Get_ParentParagraph(), cur_group.selectStartPage, false);//X, Y, Paragraph, PageNum, bResetAlign
                                this.document.Recalculate();
                                break;
                            }

                        }
                    }
                }
            }
            else if(this.selection.chartSelection)
            {
                this.selection.chartSelection.remove();
                this.document.Recalculate();

            }
            else
            {
                var first_selected = this.selectedObjects[0];
                var arr_drawings_ = [];
                for(var i = 0; i < this.selectedObjects.length; ++i)
                {
                    this.selectedObjects[i].parent.Remove_FromDocument(false);
                    if(this.selectedObjects[i].signatureLine){
                        this.document.Api.sendEvent("asc_onRemoveSignature", this.selectedObjects[i].signatureLine.id);
                    }
                    arr_drawings_.push(this.selectedObjects[i].parent);
                }
                this.resetSelection();
                first_selected.parent.GoTo_Text();
                this.document.Recalculate();
            }
        }
    },

    addGraphicObject: function(paraDrawing)
    {
        this.drawingObjects.push(paraDrawing);
    },

    getZIndex: function()
    {
        this.maximalGraphicObjectZIndex+=1024;
        return this.maximalGraphicObjectZIndex;
    },

    IsInDrawingObject: function(X, Y, nPageIndex, oContent){
        var _X, _Y, oTransform, oInvertTransform;
        if(oContent){
            oTransform = oContent.Get_ParentTextTransform();
            if(oTransform){
                oInvertTransform = AscCommon.global_MatrixTransformer.Invert(oTransform);
                _X = oInvertTransform.TransformPointX(X, Y);
                _Y = oInvertTransform.TransformPointY(X, Y);
            }
            else{
                _X = X;
                _Y = Y;
            }
        }
        else{
            _X = X;
            _Y = Y;
        }
        return this.isPointInDrawingObjects(_X, _Y, nPageIndex);
    },

    isPointInDrawingObjects: function(x, y, pageIndex, bSelected, bNoText)
    {
        var ret;
        this.handleEventMode = HANDLE_EVENT_MODE_CURSOR;
        ret = this.curState.onMouseDown(global_mouseEvent, x, y, pageIndex);
        this.handleEventMode = HANDLE_EVENT_MODE_HANDLE;
        if(isRealObject(ret))
        {
            if(bNoText === true)
            {
                if(ret.cursorType === "text")
                {
                    return -1;
                }
            }
            var object = g_oTableId.Get_ById(ret.objectId);
            if(isRealObject(object) && (!(bSelected === true) ||  bSelected && object.selected) )
            {
                if(object.group)
                    object = object.getMainGroup();

                if(isRealObject(object) && isRealObject(object.parent))
                {
                    return ret.bMarker ?  DRAWING_ARRAY_TYPE_BEFORE : object.parent.getDrawingArrayType();
                }
            }
            else
            {
                if(!(bSelected === true))
                {
                    return DRAWING_ARRAY_TYPE_BEFORE;
                }
                return -1;
            }
        }
        return -1;
    },

    isPointInDrawingObjects2: function(x, y, pageIndex, bSelected)
    {
        return this.isPointInDrawingObjects(x, y, pageIndex, bSelected, true) > -1;
    },

    isPointInDrawingObjects3: function(x, y, pageIndex, bSelected, bText)
    {
        if(bText){
            var ret;
            this.handleEventMode = HANDLE_EVENT_MODE_CURSOR;
            ret = this.curState.onMouseDown(global_mouseEvent, x, y, pageIndex);
            this.handleEventMode = HANDLE_EVENT_MODE_HANDLE;
            if(isRealObject(ret)){
                if(ret.cursorType === "text")
                {
                    return true;
                }
            }
            return false;
        }
        var oOldState = this.curState;
        this.changeCurrentState(new AscFormat.NullState(this));
        var bRet = this.isPointInDrawingObjects(x, y, pageIndex, bSelected, true) > -1;
        this.changeCurrentState(oOldState);
        return bRet;
    },


    pointInObjInDocContent: function( docContent, X, Y, pageIndex )
    {
        var ret;
        this.handleEventMode = HANDLE_EVENT_MODE_CURSOR;
        ret = this.curState.onMouseDown(global_mouseEvent, X, Y, pageIndex);
        this.handleEventMode = HANDLE_EVENT_MODE_HANDLE;
        if(ret)
        {
            var object = g_oTableId.Get_ById(ret.objectId);
            if(object)
            {
                var parent_drawing;
                if(!object.group && object.parent)
                {
                    parent_drawing = object;
                }
                else if(object.group)
                {
                    parent_drawing = object.group;
                    while(parent_drawing.group)
                        parent_drawing = parent_drawing.group;
                }
                if(parent_drawing &&  parent_drawing.parent)
                    return docContent === parent_drawing.parent.DocumentContent.Is_TopDocument(true);
            }
        }
        return false;
    },

    pointInSelectedObject: function(x, y, pageIndex)
    {
        var ret;
        this.handleEventMode = HANDLE_EVENT_MODE_CURSOR;
        ret = this.curState.onMouseDown(global_mouseEvent, x, y, pageIndex);
        this.handleEventMode = HANDLE_EVENT_MODE_HANDLE;
        if(ret)
        {
            var object = g_oTableId.Get_ById(ret.objectId);
            if(object && object.selected /*&& object.selectStartPage === pageIndex*/)
                return true;
        }
        return false;
    },


    Save_DocumentStateBeforeLoadChanges: function(oState)
    {
        var oTargetDocContent = this.getTargetDocContent(undefined, true);
        if(oTargetDocContent)
        {
            oState.Pos      = oTargetDocContent.GetContentPosition(false, false, undefined);
            oState.StartPos = oTargetDocContent.GetContentPosition(true, true, undefined);
            oState.EndPos   = oTargetDocContent.GetContentPosition(true, false, undefined);
            oState.DrawingSelection = oTargetDocContent.Selection.Use;
        }
        oState.DrawingsSelectionState = this.getSelectionState()[0];
        var oPos = this.getLeftTopSelectedObject2();
        oState.X = oPos.X;
        oState.Y = oPos.Y;
    },

    Load_DocumentStateAfterLoadChanges: function(oState)
    {
        this.clearPreTrackObjects();
        this.clearTrackObjects();
        this.resetSelection();
        this.changeCurrentState(new AscFormat.NullState(this));
        return this.loadDocumentStateAfterLoadChanges(oState);
    },

    loadDocumentStateAfterLoadChanges:  DrawingObjectsController.prototype.loadDocumentStateAfterLoadChanges,
    checkTrackDrawings:  DrawingObjectsController.prototype.checkTrackDrawings,

    canChangeWrapPolygon: function()
    {
        return !this.selection.groupSelection && !this.selection.textSelection && !this.selection.chartSelection
            && this.selectedObjects.length === 1 && this.selectedObjects[0].canChangeWrapPolygon && this.selectedObjects[0].canChangeWrapPolygon() && !this.selectedObjects[0].parent.Is_Inline();
    },

    startChangeWrapPolygon: function()
    {
        if(this.canChangeWrapPolygon())
        {
            var bNeedBehindDoc = this.getCompatibilityMode() < document_compatibility_mode_Word15;
            if(this.selectedObjects[0].parent.wrappingType !== WRAPPING_TYPE_THROUGH
                || this.selectedObjects[0].parent.wrappingType !== WRAPPING_TYPE_TIGHT
            || this.selectedObjects[0].parent.behindDoc !== bNeedBehindDoc)
            {
                if(false === this.document.Document_Is_SelectionLocked(changestype_Drawing_Props, {Type : AscCommon.changestype_2_Element_and_Type , Element : this.selectedObjects[0].parent.Get_ParentParagraph(), CheckType : AscCommon.changestype_Paragraph_Content} ))
                {
                    History.Create_NewPoint(AscDFH.historydescription_Document_GrObjectsChangeWrapPolygon);
                    this.selectedObjects[0].parent.Set_WrappingType(WRAPPING_TYPE_TIGHT);
                    this.selectedObjects[0].parent.Set_BehindDoc(bNeedBehindDoc);
                    this.selectedObjects[0].parent.Check_WrapPolygon();
                    this.document.Recalculate();
                    this.document.Document_UpdateInterfaceState();
                }
            }
            this.resetInternalSelection();
            this.selection.wrapPolygonSelection = this.selectedObjects[0];
            this.updateOverlay();
        }
    },


    removeById: function(pageIndex, id)
    {
        var object = g_oTableId.Get_ById(id);
        if(isRealObject(object))
        {
            var hdr_ftr = object.DocumentContent.IsHdrFtr(true);
            var page = !hdr_ftr ? this.graphicPages[pageIndex] : null;
            if(isRealObject(page))
            {
                page.delObjectById(id);
            }
        }
    },


    Remove_ById: function(id)
    {
        for(var i = 0; i < this.graphicPages.length; ++i)
        {
            this.removeById(i, id)
        }
    },


    selectById: function(id, pageIndex)
    {
        this.resetSelection();
        var obj = g_oTableId.Get_ById(id), nPageIndex = pageIndex;
        if(obj && obj.GraphicObj)
        {
            if(obj.DocumentContent && obj.DocumentContent.IsHdrFtr())
            {
                if(obj.DocumentContent.Get_StartPage_Absolute() !== obj.PageNum)
                {
                    nPageIndex = obj.PageNum;
                }
            }
            else
            {
                if(AscFormat.isRealNumber(obj.PageNum))
                {
                    nPageIndex = obj.PageNum;
                }
            }
            obj.GraphicObj.select(this, nPageIndex);
        }

    },

    calculateAfterChangeTheme: function()
    {
        /*todo*/
        for(var i = 0; i < this.drawingObjects.length; ++i)
        {
            this.drawingObjects[i].calculateAfterChangeTheme();
        }
        editor.SyncLoadImages(this.urlMap);
        this.urlMap = [];
    },

    updateSelectionState: function()
    {
        return;
    },


    drawSelectionPage: function(pageIndex)
    {
        var oMatrix = null;
        if(this.selection.textSelection)
        {

            if(this.selection.textSelection.selectStartPage === pageIndex)
            {
                if(this.selection.textSelection.transformText)
                {
                    oMatrix = this.selection.textSelection.transformText.CreateDublicate();
                }
                this.drawingDocument.UpdateTargetTransform(oMatrix);
                this.selection.textSelection.getDocContent().DrawSelectionOnPage(0);
            }
        }
        else if(this.selection.groupSelection)
        {
            if(this.selection.groupSelection.selectStartPage === pageIndex)
            {
                this.selection.groupSelection.drawSelectionPage(0);
            }
        }
        else if(this.selection.chartSelection && this.selection.chartSelection.selectStartPage === pageIndex && this.selection.chartSelection.selection.textSelection)
        {
            if(this.selection.chartSelection.selection.textSelection.transformText)
            {
                oMatrix = this.selection.chartSelection.selection.textSelection.transformText.CreateDublicate();
            }
            this.drawingDocument.UpdateTargetTransform(oMatrix);
            this.selection.chartSelection.selection.textSelection.getDocContent().DrawSelectionOnPage(0);
        }
    },
    getAllRasterImagesOnPage: function(pageIndex)
    {
        var ret = [];
        if(this.graphicPages[pageIndex])
        {
            var graphic_page = this.graphicPages[pageIndex];
            var hdr_ftr_page = this.getHdrFtrObjectsByPageIndex(pageIndex);

            var graphic_array = graphic_page.beforeTextObjects.concat(graphic_page.inlineObjects).concat(graphic_page.behindDocObjects);
            graphic_array = graphic_array.concat(hdr_ftr_page.beforeTextObjects).concat(hdr_ftr_page.inlineObjects).concat(hdr_ftr_page.behindDocObjects);
            for(var i = 0; i < graphic_array.length; ++i)
            {
                if(graphic_array[i].getAllRasterImages)
                    graphic_array[i].getAllRasterImages(ret);
            }
        }
        return ret;
    },

    checkChartTextSelection: DrawingObjectsController.prototype.checkChartTextSelection,
    checkNeedResetChartSelection: DrawingObjectsController.prototype.checkNeedResetChartSelection,


    addNewParagraph: DrawingObjectsController.prototype.addNewParagraph,


    paragraphClearFormatting: function(isClearParaPr, isClearTextPr)
    {
        this.applyDocContentFunction(CDocumentContent.prototype.ClearParagraphFormatting, [isClearParaPr, isClearTextPr], CTable.prototype.ClearParagraphFormatting);
    },

    applyDocContentFunction: DrawingObjectsController.prototype.applyDocContentFunction,
    applyTextFunction: DrawingObjectsController.prototype.applyTextFunction,

    setParagraphSpacing: DrawingObjectsController.prototype.setParagraphSpacing,

    setParagraphTabs: DrawingObjectsController.prototype.setParagraphTabs,

    setParagraphNumbering: DrawingObjectsController.prototype.setParagraphNumbering,

    setParagraphShd: DrawingObjectsController.prototype.setParagraphShd,


    setParagraphStyle:  DrawingObjectsController.prototype.setParagraphStyle,


    setParagraphContextualSpacing: DrawingObjectsController.prototype.setParagraphContextualSpacing,

    setParagraphPageBreakBefore: DrawingObjectsController.prototype.setParagraphPageBreakBefore,
    setParagraphKeepLines: DrawingObjectsController.prototype.setParagraphKeepLines,

    setParagraphKeepNext: DrawingObjectsController.prototype.setParagraphKeepNext,


    setParagraphWidowControl: DrawingObjectsController.prototype.setParagraphWidowControl,

    setParagraphBorders: DrawingObjectsController.prototype.setParagraphBorders,

    paragraphAdd: DrawingObjectsController.prototype.paragraphAdd,

    paragraphIncDecFontSize: DrawingObjectsController.prototype.paragraphIncDecFontSize,

    paragraphIncDecIndent: DrawingObjectsController.prototype.paragraphIncDecIndent,

    setParagraphAlign: DrawingObjectsController.prototype.setParagraphAlign,

    setParagraphIndent: DrawingObjectsController.prototype.setParagraphIndent,
    getSelectedObjectsBounds: DrawingObjectsController.prototype.getSelectedObjectsBounds,
    getContextMenuPosition: DrawingObjectsController.prototype.getContextMenuPosition,
    getLeftTopSelectedFromArray: DrawingObjectsController.prototype.getLeftTopSelectedFromArray,

    getFromTargetTextObjectContextMenuPosition: function(oTargetTextObject, pageIndex)
    {
        var dPosX = this.document.TargetPos.X, dPosY = this.document.TargetPos.Y, oTransform = oTargetTextObject.transformText;
        return {X: oTransform.TransformPointX(dPosX, dPosY), Y: oTransform.TransformPointY(dPosX, dPosY), PageIndex: this.document.TargetPos.PageNum};
    },

    getLeftTopSelectedObject: function(pageIndex)
    {
        if(this.selectedObjects.length > 0)
        {
            var oRes = this.getLeftTopSelectedObjectByPage(pageIndex);
            if(oRes.bSelected === true)
            {
                return oRes;
            }
            var aSelectedObjectsCopy = [].concat(this.selectedObjects);
            aSelectedObjectsCopy.sort(function(a, b){return a.selectStartPage - b.selectStartPage});
            return this.getLeftTopSelectedObjectByPage(aSelectedObjectsCopy[0].selectStartPage);
        }
        return {X: 0, Y: 0, PageIndex: pageIndex};
    },

    getLeftTopSelectedObject2: function()
    {
        if(this.selectedObjects.length > 0)
        {
            var aSelectedObjectsCopy = [].concat(this.selectedObjects);
            aSelectedObjectsCopy.sort(function(a, b){return a.selectStartPage - b.selectStartPage});
            return this.getLeftTopSelectedObjectByPage(aSelectedObjectsCopy[0].selectStartPage);
        }
        return {X: 0, Y: 0, PageIndex: 0};
    },

    getLeftTopSelectedObjectByPage: function(pageIndex)
    {
        var oDrawingPage, oRes;
        if(this.document.Get_DocPosType() === docpostype_HdrFtr)
        {
            if(this.graphicPages[pageIndex])
            {
                oDrawingPage = this.graphicPages[pageIndex].hdrFtrPage;
            }
        }
        else
        {
            if(this.graphicPages[pageIndex])
            {
                oDrawingPage = this.graphicPages[pageIndex];
            }
        }
        if(oDrawingPage)
        {
            oRes = this.getLeftTopSelectedFromArray(oDrawingPage.beforeTextObjects, pageIndex);
            if(oRes.bSelected)
            {
                return oRes;
            }
            oRes = this.getLeftTopSelectedFromArray(oDrawingPage.inlineObjects, pageIndex);
            if(oRes.bSelected)
            {
                return oRes;
            }
            oRes = this.getLeftTopSelectedFromArray(oDrawingPage.behindDocObjects, pageIndex);
            if(oRes.bSelected)
            {
                return oRes;
            }
        }
        return {X: 0, Y: 0, PageIndex: pageIndex};
    },



    CheckRange: function(X0, Y0, X1, Y1, Y0Sp, Y1Sp, LeftField, RightField, PageNum, HdrFtrRanges, docContent, bMathWrap)
    {
        if(isRealObject(this.graphicPages[PageNum]))
        {
            var Ranges = this.graphicPages[PageNum].CheckRange(X0, Y0, X1, Y1, Y0Sp, Y1Sp, LeftField, RightField, HdrFtrRanges, docContent, bMathWrap);

            var ResultRanges = [];

            // Уберем лишние отрезки
            var Count = Ranges.length;
            for ( var Index = 0; Index < Count; Index++ )
            {
                var Range = Ranges[Index];

                if ( Range.X1 > X0 && Range.X0 < X1 )
                {
                    Range.X0 = Math.max( X0, Range.X0 );
                    Range.X1 = Math.min( X1, Range.X1 );

                    ResultRanges.push( Range );
                }
            }

            return ResultRanges;
        }
        return HdrFtrRanges;
    },

    getTableProps: function()
    {
        var content = this.getTargetDocContent();
        if(content)
            return content.Interface_Update_TablePr( true );

        return null;
    },

    startAddShape: function(preset)
    {
        /*todo*/
        switch(preset)
        {
            case "spline":
            {
                this.changeCurrentState(new AscFormat.SplineBezierState(this));
                break;
            }
            case "polyline1":
            {
                this.changeCurrentState(new AscFormat.PolyLineAddState(this));
                break;
            }
            case "polyline2":
            {
                this.changeCurrentState(new AscFormat.AddPolyLine2State(this));
                break;
            }
            default :
            {
                this.changeCurrentState(new AscFormat.StartAddNewShape(this, preset));
                break;
            }
        }
    }
};

function ComparisonByZIndexSimpleParent(obj1, obj2)
{
    if(obj1.parent && obj2.parent)
        return ComparisonByZIndexSimple(obj1.parent, obj2.parent);
    return 0;
}

function ComparisonByZIndexSimple(obj1, obj2)
{
    if(AscFormat.isRealNumber(obj1.RelativeHeight) && AscFormat.isRealNumber(obj2.RelativeHeight))
    {
        if(obj1.RelativeHeight === obj2.RelativeHeight)
        {
            if(editor && editor.WordControl && editor.WordControl.m_oLogicDocument)
            {
                return editor.WordControl.m_oLogicDocument.CompareDrawingsLogicPositions(obj2, obj1);
            }
        }
        return obj1.RelativeHeight - obj2.RelativeHeight;
    }
    if(!AscFormat.isRealNumber(obj1.RelativeHeight) && AscFormat.isRealNumber(obj2.RelativeHeight))
        return -1;
    if(AscFormat.isRealNumber(obj1.RelativeHeight) && !AscFormat.isRealNumber(obj2.RelativeHeight))
        return 1;
    return 0;
}

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CGraphicObjects = CGraphicObjects;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

var DRAWING_ARRAY_TYPE_INLINE = 0x00;
var DRAWING_ARRAY_TYPE_BEHIND = 0x01;
var DRAWING_ARRAY_TYPE_WRAPPING = 0x02;
var DRAWING_ARRAY_TYPE_BEFORE = 0x03;

function CGraphicPage(pageIndex, graphicObjects)
{
    this.pageIndex = pageIndex;
    this.graphicObjects = graphicObjects;
    this.drawingDocument = editor.WordControl.m_oDrawingDocument;

    this.arrGraphicObjects = [];

    this.selectionInfo =
    {
        selectionArray: []
    };

    //массивы для отрисовки
    this.inlineObjects = [];
    this.behindDocObjects = [];
    this.beforeTextObjects = [];
    this.flowTables = [];


    this.hdrFtrPage = null;
    this.wrapManager = null;
    if(graphicObjects)
    {
        this.hdrFtrPage =  new CGraphicPage(pageIndex, null);
        this.wrapManager = new CWrapManager(this);
    }
}

CGraphicPage.prototype =
{
    getCompatibilityMode: function () {
        return editor.WordControl.m_oLogicDocument.GetCompatibilityMode();
    },
    addFloatTable: function(table)
    {
        for(var i = 0; i < this.flowTables.length; ++i)
        {
            if(this.flowTables[i] === table)
                return;
        }
        this.flowTables.push(table);
    },

    addObject: function(object)
    {

        var drawing_array, need_sort = true;
        if(object.parent.Is_Inline()){
            drawing_array = this.inlineObjects;
            need_sort = false;
        }
        else if(object.parent.behindDoc == true && (this.getCompatibilityMode() < document_compatibility_mode_Word15 || object.parent.wrappingType === WRAPPING_TYPE_NONE)){
            drawing_array  = this.behindDocObjects;
        }
        else{
            drawing_array = this.beforeTextObjects;
        }
        if(Array.isArray(drawing_array))
        {
            for(var i = 0; i < drawing_array.length; ++i)
            {
                if(drawing_array[i] === object)
                {
                    break;
                }
            }
            if(i === drawing_array.length)
            {
                drawing_array.push(object);
                if(need_sort)
                {
                    drawing_array.sort(ComparisonByZIndexSimpleParent);
                }
            }
        }
    },


    concatPage: function(page)
    {
        this.inlineObjects = this.inlineObjects.concat(page.inlineObjects);
        this.behindDocObjects = this.behindDocObjects.concat(page.behindDocObjects);
        this.beforeTextObjects = this.beforeTextObjects.concat(page.beforeTextObjects);
        this.flowTables = this.flowTables.concat(page.flowTables);
    },

    mergePages: function(page1, page2)
    {
        if(page1)
        {
            this.concatPage(page1);
        }
        if(page2)
        {
            this.concatPage(page2);
        }
        this.behindDocObjects.sort(ComparisonByZIndexSimpleParent);
        this.beforeTextObjects.sort(ComparisonByZIndexSimpleParent);
    },

    clear: function()
    {
        this.inlineObjects = [];
        this.behindDocObjects = [];
        this.beforeTextObjects = [];
        this.flowTables = [];
    },



    CheckRange: function(X0, Y0, X1, Y1, Y0sp, Y1Ssp, LeftField, RightField, HdrFtrRanges, docContent, bMathWrap)
    {
        return this.wrapManager.checkRanges(X0, Y0, X1, Y1, Y0sp, Y1Ssp, LeftField, RightField, HdrFtrRanges, docContent, bMathWrap);
    },

    removeFloatTableById: function(id)
    {
        for(var index = 0; index < this.flowTables.length; ++index)
        {
            if(this.flowTables[index].Id === id)
            {
                this.flowTables.splice(index, 1);
                return;
            }
        }
    },

    documentStatistics: function(Statistics)
    {
        var cur_array = this.inlineObjects.concat(this.behindDocObjects).concat(this.beforeTextObjects);
        for(var i = 0; i < cur_array.length; ++i)
        {
            if(cur_array[i].documentStatistics)
                cur_array[i].documentStatistics(Statistics);
        }

    },

    getTableByXY: function(x, y, documentContent)
    {
        for(var index = this.flowTables.length -1; index > -1; --index)
        {
            if(this.flowTables[index].IsPointIn(x, y) && this.flowTables[index].Table.Parent === documentContent)
                return this.flowTables[index];
        }
        return null;
    },

    delObjectById: function(id)
    {
        var oDrawing = AscCommon.g_oTableId.Get_ById(id);
        if(oDrawing){
            var drawing_array;
            if(oDrawing.Is_Inline()){
                drawing_array = this.inlineObjects;
            }
            else if(oDrawing.behindDoc === true  && (this.getCompatibilityMode() < document_compatibility_mode_Word15 || oDrawing.wrappingType === WRAPPING_TYPE_NONE)){
                drawing_array = this.behindDocObjects;
            }
            else{
                drawing_array = this.beforeTextObjects;
            }
            for(var index = 0; index < drawing_array.length; ++index){
                if(drawing_array[index].parent === oDrawing){
                    return drawing_array.splice(index, 1);
                }
            }
        }
        return null;
    },

    resetDrawingArrays: function(docContent)
    {
        function findInArrayAndRemove(drawingArray, docContent, document)
        {
            if(docContent === document)
            {
                drawingArray.length = 0;
                return;
            }
            var b_is_top_doc = docContent.Is_TopDocument();
            for(var i = drawingArray.length-1; i > -1; --i)
            {
                if(!drawingArray[i].parent || drawingArray[i].parent.DocumentContent === docContent
                    || (b_is_top_doc && drawingArray[i].parent.DocumentContent.Is_TopDocument(true) === docContent))
                    drawingArray.splice(i, 1);
            }
        }
        function findTableInArrayAndRemove(drawingArray, docContent, document)
        {
            if(!docContent === document)
            {
                drawingArray.length = 0;
                return;
            }
            for(var i = drawingArray.length-1; i >-1; --i)
            {
                if(drawingArray[i].Table.Parent === docContent)
                    drawingArray.splice(i, 1);
            }
        }

        function findInArrayAndRemoveFromDrawingPage(drawingPage, docContent, document)
        {
            if(!drawingPage)
                return;
            if(Array.isArray(drawingPage.inlineObjects))
            {
                findInArrayAndRemove(drawingPage.inlineObjects, docContent, document);
                findInArrayAndRemove(drawingPage.behindDocObjects, docContent, document);
                findInArrayAndRemove(drawingPage.beforeTextObjects, docContent, document);
                findTableInArrayAndRemove(drawingPage.flowTables, docContent, document);
            }
        }

        if(!AscCommon.isRealObject(docContent))
            docContent = this.graphicObjects.document;

        findInArrayAndRemoveFromDrawingPage(this, docContent, editor.WordControl.m_oLogicDocument);
    },


    draw: function(graphics)
    {
        for(var _object_index = 0; _object_index < this.inlineObjects.length; ++_object_index)
            this.inlineObjects[_object_index].draw(graphics);

        for(_object_index = 0; _object_index < this.beforeTextObjects.length; ++_object_index)
            this.beforeTextObjects[_object_index].draw(graphics);
        for(_object_index = 0; _object_index < this.behindDocObjects.length; ++_object_index)
            this.behindDocObjects[_object_index].draw(graphics);
    },

    drawSelect: function()
    {
        var _graphic_objects = this.selectionInfo.selectionArray;
        var _object_index;
        var _objects_count = _graphic_objects.length;
        var _graphic_object;
        for(_object_index = 0; _object_index < _objects_count; ++_object_index)
        {
            _graphic_object = _graphic_objects[_object_index].graphicObject;
            var _transform = _graphic_object.getTransformMatrix();
            if(_transform === null)
                _transform = new AscCommon.CMatrix();

            var _extensions = _graphic_object.getExtensions();
            if(_extensions === null)
                _extensions = {extX: 0, extY: 0};


            this.drawingDocument.DrawTrack(AscFormat.TYPE_TRACK.SHAPE , _transform, 0, 0, _extensions.extX, _extensions.extY, /*shape.geometry ? shape.geometry.preset == "line"  : false*/false);
        }
    },

    selectionCheck: function(x, y)
    {

    },

    documentSearch: function(String, search_Common)
    {
        var search_array = [];
        search_array= search_array.concat(this.behindDocObjects);
        search_array= search_array.concat(this.inlineObjects);
        search_array= search_array.concat(this.beforeTextObjects);

        for(var i = 0; i < search_array.length; ++i)
        {
            if(search_array[i].documentSearch)
                search_array[i].documentSearch(String, search_Common);
        }

    },

    addGraphicObject: function(graphicObject){
        if(graphicObject.Is_Inline()){
            this.inlineObjects.push(graphicObject);
        }
        else if(graphicObject.behindDoc === true && (this.getCompatibilityMode() < document_compatibility_mode_Word15 || graphicObject.wrappingType === WRAPPING_TYPE_NONE)){
            this.behindDocObjects.push(graphicObject);
            this.behindDocObjects.sort(ComparisonByZIndexSimpleParent);
        }
        else{
            this.beforeTextObjects.push(graphicObject);
            this.beforeTextObjects.sort(ComparisonByZIndexSimpleParent);
        }
    },

    sortDrawingArrays: function()
    {
        this.behindDocObjects.sort(ComparisonByZIndexSimpleParent);
        this.beforeTextObjects.sort(ComparisonByZIndexSimpleParent);
        if(this.hdrFtrPage)
        {
            this.hdrFtrPage.sortDrawingArrays();
        }
    },

    drawBehindDoc: function(graphics)
    {
        for(var _object_index = 0; _object_index < this.behindDocObjects.length; ++_object_index)
            this.behindDocObjects[_object_index].draw(graphics);

        graphics.SetIntegerGrid(true);
    },


    drawBehindObjectsByContent: function(graphics, content)
    {
        var bIntegerGrid = graphics.m_bIntegerGrid;
        var drawing;
        for(var _object_index = 0; _object_index < this.behindDocObjects.length; ++_object_index)
        {
            drawing = this.behindDocObjects[_object_index];
            if(drawing.parent && drawing.parent.DocumentContent && drawing.parent.DocumentContent === content)
            {
                drawing.draw(graphics);
            }
        }
        graphics.SetIntegerGrid(bIntegerGrid);
    },
    drawBeforeObjectsByContent: function(graphics, content)
    {
        var bIntegerGrid = graphics.m_bIntegerGrid;
        var drawing;
        for(var _object_index = 0; _object_index < this.beforeTextObjects.length; ++_object_index)
        {
            drawing = this.beforeTextObjects[_object_index];
            if(drawing.parent && drawing.parent.DocumentContent && drawing.parent.DocumentContent === content)
            {
                drawing.draw(graphics);
            }
        }
        graphics.SetIntegerGrid(bIntegerGrid);
    },


    drawBeforeObjects: function(graphics)
    {
        for(var _object_index = 0; _object_index < this.beforeTextObjects.length; ++_object_index)
            this.beforeTextObjects[_object_index].draw(graphics);

        graphics.SetIntegerGrid(true);
    }
};

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */


// Import
var History = AscCommon.History;

var WRAP_TEXT_SIDE_BOTH_SIDES = 0x00;
var WRAP_TEXT_SIDE_LARGEST = 0x01;
var WRAP_TEXT_SIDE_LEFT = 0x02;
var WRAP_TEXT_SIDE_RIGHT = 0x03;

var APPROXIMATE_ANGLE = 0.3;
function CWrapPolygon(wordGraphicObject)
{
    this.calculatedPoints = [];
    this.arrPoints = [];
    this.relativeArrPoints = new ArrayWrapPoint([]);

    this.edited = false;

    this.wrapSide = WRAP_TEXT_SIDE_BOTH_SIDES;


    this.posX = null;
    this.posY = null;

    this.left = null;
    this.top = null;
    this.right = null;
    this.bottom = null;

    this.localLeft = null;
    this.localTop = null;
    this.localRight = null;
    this.localBottom = null;

    this.wordGraphicObject = wordGraphicObject;

    AscCommon.g_oTableId.Add( this, AscCommon.g_oIdCounter.Get_NewId());
}

CWrapPolygon.prototype =
{
    Get_Id: function()
    {
        return this.Id;
    },

    getObjectType: function()
    {
        return AscDFH.historyitem_type_WrapPolygon;
    },

    setEdited: function(pr)
    {
        History.Add(new CChangesWrapPolygonEdited(this, this.edited, pr));
        this.edited = pr;
    },

    setArrRelPoints: function(pr)
    {
        var NewRelPoint = new ArrayWrapPoint(pr);
        History.Add(new CChangesWrapPolygonRelPoints(this, this.relativeArrPoints, NewRelPoint));
        this.relativeArrPoints = pr;
    },

    setWrapSide: function(pr)
    {
        History.Add(new CChangesWrapPolygonWrapSide(this, this.wrapSide, pr));
        this.wrapSide = pr;
    },

    fromOther: function(wrapPolygon)
    {
        if(!wrapPolygon)
            return;
        if(this.edited !== wrapPolygon.edited)
        {
            this.setEdited(wrapPolygon.edited);
        }
        var rel = [];
        for(var i = 0; i < wrapPolygon.relativeArrPoints.length; ++i)
        {
            rel.push({x: wrapPolygon.relativeArrPoints[i].x, y: wrapPolygon.relativeArrPoints[i].y});
        }
        this.setArrRelPoints(rel);

        if(this.wrapSide !== wrapPolygon.wrapSide)
        {
            this.setWrapSide(wrapPolygon.wrapSide);
        }
    },

    Write_ToBinary2: function(writer)
    {
        writer.WriteLong(AscDFH.historyitem_type_WrapPolygon);
        writer.WriteString2(this.Get_Id());
        AscFormat.writeObject(writer, this.wordGraphicObject);
    },

    Read_FromBinary2: function(reader)
    {
        this.Id = reader.GetString2();
        this.wordGraphicObject = AscFormat.readObject(reader);
    },

    Load_LinkData: function(data)
    {
    },

    getIntersection: function(y)
    {
        var min_x = null;
        var max_x = null;

        var cur_max_x;
        var cur_min_x;
        var point_count = this.calculatedPoints.length;
        if(point_count === 0)
        {
            return {max: null, min: null};
        }
        for(var point_index = 1; point_index < point_count; ++point_index)
        {
            var point0 = this.calculatedPoints[point_index-1];
            var point1 = this.calculatedPoints[point_index];
            if(!(point0.y > y && point1.y > y || point0.y < y && point1.y < y ))
            {
                if(point0.y === point1.y)
                {
                    cur_max_x = Math.max(point0.x, point1.x);
                    cur_min_x = Math.min(point0.x, point1.x);
                }
                else
                {
                    if(point0.x === point1.x)
                    {
                        cur_max_x = point0.x;
                        cur_min_x = point0.x;
                    }
                    else
                    {
                        cur_max_x = ((y - point0.y)/(point1.y - point0.y))*(point1.x - point0.x) + point0.x;
                        cur_min_x = cur_max_x;
                    }
                }
                if(max_x === null)
                {
                    max_x = cur_max_x;
                    min_x = cur_min_x;
                }
                else
                {
                    if(cur_max_x > max_x)
                        max_x = cur_max_x;
                    if(cur_min_x < min_x)
                        min_x = cur_min_x;
                }
            }
        }
        point0 = this.calculatedPoints[point_count-1];
        point1 = this.calculatedPoints[0];
        if(!(point0.y > y && point1.y > y || point0.y < y && point1.y < y ))
        {
            if(point0.y === point1.y)
            {
                cur_max_x = Math.max(point0.x, point1.x);
                cur_min_x = Math.min(point0.x, point1.x);
            }
            else
            {
                if(point0.x === point1.x)
                {
                    cur_max_x = point0.x;
                    cur_min_x = point0.x;
                }
                else
                {
                    cur_max_x = ((y - point0.y)/(point1.y - point0.y))*(point1.x - point0.x) + point0.x;
                    cur_min_x = cur_max_x;
                }
            }
            if(max_x === null)
            {
                max_x = cur_max_x;
                min_x = cur_min_x;
            }
            else
            {
                if(cur_max_x > max_x)
                    max_x = cur_max_x;
                if(cur_min_x < min_x)
                    min_x = cur_min_x;
            }
        }
        return {max: max_x, min: min_x};
    },

    getArrayWrapIntervals: function(x0, y0, x1, y1, LeftField, RightField, ret, bMathWrap)
    {
        if(y1 - this.top < 0.0001 || this.bottom - y0 < 0.0001 || true !== this.wordGraphicObject.useWrap)
            return ret;

        var ret2 = [];
        var nWrapType, nWrapSide;
        if(bMathWrap === true)
        {
            nWrapType = WRAPPING_TYPE_SQUARE;
			nWrapSide = WRAP_TEXT_SIDE_BOTH_SIDES;
        }
        else
        {
            nWrapType = this.wordGraphicObject.wrappingType;
            nWrapSide = this.wrapSide;
        }
        switch(nWrapType)
        {
            case WRAPPING_TYPE_NONE:
            {
                return ret;
            }
            case WRAPPING_TYPE_SQUARE:
            {
                switch(nWrapSide)
                {
                    case WRAP_TEXT_SIDE_BOTH_SIDES:
                    {
                        if(this.wordGraphicObject.wrappingType === WRAPPING_TYPE_THROUGH || this.wordGraphicObject.wrappingType === WRAPPING_TYPE_TIGHT)
                        {
                            var oDistanse = this.wordGraphicObject.Get_Distance();
                            ret2.push({X0: this.left + oDistanse.L, X1: this.right - oDistanse.R, Y1: this.bottom});
                        }
                        else
                        {
                            ret2.push({X0: this.left, X1: this.right, Y1: this.bottom});

                        }
                        break;
                    }
                    case WRAP_TEXT_SIDE_LARGEST:
                    {
                        if(RightField - this.right > 0 && RightField - this.right >  this.left -LeftField)
                            ret2.push({X0: LeftField, X1: this.right, Y1: this.bottom});
                        else if(this.left - LeftField > 0 && this.left - LeftField > RightField - this.right)
                        {
                            ret2.push({X0: this.left, X1: RightField, Y1: this.bottom});
                        }
                        break;
                    }
                    case WRAP_TEXT_SIDE_LEFT:
                    {
                        if(this.left > LeftField)
                        {
                            ret2.push({X0: this.left, X1: RightField, Y1: this.bottom});
                        }
                        break;
                    }
                    case WRAP_TEXT_SIDE_RIGHT:
                    {
                        if(this.right < RightField)
                        {
                            ret2.push({X0: LeftField, X1: this.right, Y1: this.bottom});
                        }
                        break;
                    }
                }
                break;
            }
            case WRAPPING_TYPE_TOP_AND_BOTTOM:
            {
                if (this.right < LeftField || this.left > RightField)
                    return ret;

                ret2.push({X0: x0, X1: x1, Y1: this.bottom});
                break;
            }
            case WRAPPING_TYPE_THROUGH:
            case WRAPPING_TYPE_TIGHT:
            {

                var intersection_top = this.getIntersection(y0);
                var intersection_bottom = this.getIntersection(y1);

                var max_x = null;
                var min_x = null;
                if(intersection_top.max !== null)
                    max_x = intersection_top.max;
                if(intersection_top.min !== null)
                    min_x = intersection_top.min;

                if(intersection_bottom.max !== null)
                {
                    if(max_x === null)
                        max_x = intersection_bottom.max;
                    else
                    {
                        if(intersection_bottom.max > max_x)
                            max_x = intersection_bottom.max;
                    }
                }

                if(intersection_bottom.min !== null)
                {
                    if(min_x === null)
                        min_x = intersection_bottom.min;
                    else
                    {
                        if(intersection_bottom.min < min_x)
                            min_x = intersection_bottom.min;
                    }
                }


                var arr_points = this.calculatedPoints;
                var point_count = arr_points.length;
                var between_flag = false;
                for(var point_index = 0; point_index < point_count; ++point_index)
                {
                    var cur_point = arr_points[point_index];
                    if(cur_point.y > y0 && cur_point.y < y1)
                    {
                        between_flag = true;
                        if(max_x === null)
                            max_x = cur_point.x;
                        else
                        {
                            if(max_x < cur_point.x)
                                max_x = cur_point.x;
                        }
                        if(min_x === null)
                            min_x = cur_point.x;
                        else
                        {
                            if(min_x > cur_point.x)
                                min_x = cur_point.x;
                        }
                    }
                }

                if(max_x !== null && min_x !== null)
                {
                    var oDistance = this.wordGraphicObject.Get_Distance();
                    max_x+= oDistance.R;
                    min_x-= oDistance.L;
                    switch(nWrapSide)
                    {
                        case WRAP_TEXT_SIDE_BOTH_SIDES:
                        {
                            ret2.push({X0: min_x, X1: max_x, Y1: y1});
                            break;
                        }
                        case WRAP_TEXT_SIDE_LARGEST:
                        {
                            if(RightField - max_x > 0 && RightField - max_x >  min_x -LeftField)
                                ret2.push({X0: LeftField, X1: max_x, Y1: y1});
                            else if(min_x - LeftField > 0 && min_x - LeftField > RightField - max_x)
                            {
                                ret2.push({X0: min_x, X1: RightField, Y1: y1});
                            }
                            break;
                        }
                        case WRAP_TEXT_SIDE_LEFT:
                        {
                            ret2.push({X0: Math.max(min_x, LeftField), X1: RightField, Y1: y1});
                            break;
                        }
                        case WRAP_TEXT_SIDE_RIGHT:
                        {
                            ret2.push({X0: LeftField, X1: Math.min(max_x, RightField), Y1: y1});
                            break;
                        }
                    }
                }

                break;
            }
        }
        ret2.sort(function(a, b){return a.X0 - b.X0});
        if(ret2.length > 0 &&  (nWrapType === WRAPPING_TYPE_SQUARE || nWrapType === WRAPPING_TYPE_TIGHT || nWrapType === WRAPPING_TYPE_THROUGH))
        {
            var dx = nWrapType === WRAPPING_TYPE_SQUARE ? 6.35 : 3.175 ;
            if(ret2[0].X0  < LeftField + dx)
            {
                ret2[0].X0 = x0 ;
            }
            ret2.sort(function(a, b){ return a.X1 - b.X1});
            if(ret2[ret2.length - 1].X1 > RightField - dx)
            {
                ret2[ret2.length - 1].X1 = x1;
            }
        }
        for(var s = 0; s < ret2.length; ++s)
        {
            ret2[s].typeLeft = this.wordGraphicObject.wrappingType;
            ret2[s].typeRight = this.wordGraphicObject.wrappingType;
        }
        for(s = 0; s < ret2.length; ++s)
        {
            ret.push(ret2[s]);
        }

        return ret;

    },

    calculate: function(drawing)
    {
        var arrPolygons = drawing.getArrayWrapPolygons();
        var transform = new AscCommon.CMatrix();
        var arrEdges = [];
        var arrPoints = [];
        var polygonsCount = arrPolygons.length;
        for(var polygon_index=0; polygon_index < polygonsCount; ++polygon_index)
        {
            var cur_polygon = arrPolygons[polygon_index];
            var curLen = cur_polygon.length;

            if (curLen < 2)
                continue;

            var polygon_point0 = new CPolygonPoint();
            polygon_point0.x = transform.TransformPointX(cur_polygon[0].x, cur_polygon[0].y);
            polygon_point0.y = transform.TransformPointY(cur_polygon[0].x, cur_polygon[0].y);
            arrPoints.push(polygon_point0);

            for(var point_index = 1; point_index < curLen; ++point_index)
            {
                var transformed_x1 = transform.TransformPointX(cur_polygon[point_index].x, cur_polygon[point_index].y);
                var transformed_y1 = transform.TransformPointY(cur_polygon[point_index].x, cur_polygon[point_index].y);

                if (Math.abs(transformed_x1 - polygon_point0.x) < AscFormat.APPROXIMATE_EPSILON && Math.abs(transformed_y1 - polygon_point0.y) < AscFormat.APPROXIMATE_EPSILON)
                    continue;

                var _prev = polygon_point0;

                polygon_point0 = new CPolygonPoint();
                polygon_point0.x = transformed_x1;
                polygon_point0.y = transformed_y1;

                arrPoints.push(polygon_point0);
                arrEdges.push(new AscFormat.GraphEdge(_prev, polygon_point0));
            }
        }
        if(arrPoints.length < 2)
        {
            return [];
        }
        arrEdges.sort(function(a, b){return Math.min(a.point1.y, a.point2.y) - Math.min(b.point1.y, b.point2.y)});
        arrPoints.sort(function(a, b){return a.y - b.y});

        for(point_index = 0; point_index < arrPoints.length; ++point_index)
        {
            var cur_point = arrPoints[point_index];
            for(var point_index2 = point_index + 1; point_index2 < arrPoints.length-1; ++point_index2)
            {
                if(Math.abs(arrPoints[point_index2].y - cur_point.y) < AscFormat.APPROXIMATE_EPSILON2 && Math.abs(arrPoints[point_index2].x - cur_point.x) < AscFormat.APPROXIMATE_EPSILON2)
                {
                    arrPoints.splice(point_index2, 1);
                    --point_index2;
                }
                else
                {
                    if(Math.abs(arrPoints[point_index2].y - cur_point.y) >= AscFormat.APPROXIMATE_EPSILON2)
                        break;
                }
            }
        }
        var left_path_arr = [];
        var right_path_arr = [];
        var cur_start_index = 0;
        var cur_x_min, cur_x_max;
        var cur_y;
        var x_min = null, x_max = null;

        var edgesCount = arrEdges.length;
        for(point_index = 0;  point_index < arrPoints.length; ++point_index)
        {
            cur_point = arrPoints[point_index];
            cur_x_min = cur_point.x;
            cur_x_max = cur_point.x;
            cur_y = cur_point.y;
            for(var edge_index = cur_start_index; edge_index < edgesCount; ++edge_index)
            {
                if(arrEdges[edge_index].point2.y >= cur_y)
                {
                    cur_start_index = edge_index;
                    break;
                }
            }

            for(edge_index = cur_start_index; edge_index < edgesCount; ++edge_index)
            {
                var cur_edge = arrEdges[edge_index];

                var inter = cur_edge.getIntersectionPointX(cur_y);
                if (inter != null)
                {
                    if (inter.length == 1)
                    {
                        if(inter[0] < cur_x_min)
                            cur_x_min = inter[0];
                        if(inter[0] > cur_x_max)
                            cur_x_max = inter[0];
                    }
                    else
                    {
                        if(inter[0] < cur_x_min)
                            cur_x_min = inter[0];
                        if(inter[1] > cur_x_max)
                            cur_x_max = inter[1];
                    }
                }
            }
            if(cur_x_max <= cur_x_min)
            {
                var t_min, t_max;
                t_min = Math.min(cur_x_min, cur_x_max) - 2;
                t_max = Math.max(cur_x_min, cur_x_max) + 2;
                cur_x_max = t_max;
                cur_x_min = t_min;
            }

            left_path_arr.push({x: cur_x_min, y: cur_y});
            right_path_arr.push({x: cur_x_max, y: cur_y});

            if(x_max === null)
                x_max = cur_x_max;
            else
            {
                if(cur_x_max > x_max)
                    x_max = cur_x_max;
            }
            if(x_min === null)
                x_min = cur_x_min;
            else
            {
                if(cur_x_min < x_min)
                    x_min = cur_x_min;
            }
        }

        for(point_index = 1; point_index < left_path_arr.length - 1; ++point_index)
        {
            var point_prev = left_path_arr[point_index - 1];
            var point_last = left_path_arr[point_index + 1];
            var dx_prev = point_prev.x - left_path_arr[point_index].x;
            var dy_prev = point_prev.y - left_path_arr[point_index].y;
            var dx_last = point_last.x - left_path_arr[point_index].x;
            var dy_last = point_last.y - left_path_arr[point_index].y;

            var l_prev = Math.sqrt(dx_prev*dx_prev + dy_prev*dy_prev);
            var l_last = Math.sqrt(dx_last*dx_last + dy_last*dy_last);
            if(l_prev === 0 || l_last === 0)
            {
                left_path_arr.splice(point_index, 1);
                --point_index;
            }
            if(l_prev < AscFormat.APPROXIMATE_EPSILON3 && l_last < AscFormat.APPROXIMATE_EPSILON3 && Math.abs(Math.acos((dx_last*dx_prev + dy_last*dy_prev)/(l_last*l_prev)) - Math.PI) < APPROXIMATE_ANGLE)
            {
                left_path_arr.splice(point_index, 1);
                --point_index;
            }
        }

        for(point_index = 1; point_index < right_path_arr.length - 1; ++point_index)
        {
            point_prev = right_path_arr[point_index - 1];
            point_last = right_path_arr[point_index + 1];
            dx_prev = point_prev.x - right_path_arr[point_index].x;
            dy_prev = point_prev.y - right_path_arr[point_index].y;
            dx_last = point_last.x - right_path_arr[point_index].x;
            dy_last = point_last.y - right_path_arr[point_index].y;

            l_prev = Math.sqrt(dx_prev*dx_prev + dy_prev*dy_prev);
            l_last = Math.sqrt(dx_last*dx_last + dy_last*dy_last);
            if(l_prev === 0 || l_last === 0)
            {
                right_path_arr.splice(point_index, 1);
                --point_index;
            }
            if(l_prev < AscFormat.APPROXIMATE_EPSILON3 && l_last < AscFormat.APPROXIMATE_EPSILON3 && Math.abs(Math.acos((dx_last*dx_prev + dy_last*dy_prev)/(l_last*l_prev)) - Math.PI) < APPROXIMATE_ANGLE)
            {
                right_path_arr.splice(point_index, 1);
                --point_index;
            }
        }

        var aPoints = [];
        aPoints.push(left_path_arr[0]);
        for(point_index = 0; point_index < right_path_arr.length; ++point_index)
        {
            aPoints.push(right_path_arr[point_index]);
        }
        for(point_index =  left_path_arr.length - 1; point_index > 0; --point_index)
        {
            aPoints.push(left_path_arr[point_index]);
        }
        return this.calculateAbsToRel(drawing, aPoints);
    },

    calculateRelToAbs: function(transform, drawing)
    {

        var bounds = drawing.bounds, oDistance = drawing.parent.Get_Distance(), oEffectExtent = drawing.parent.EffectExtent;
        if(this.relativeArrPoints.length === 0)
        {

            var oEffectExtent = drawing.parent.EffectExtent;
            var W, H;
            if(AscFormat.isRealNumber(drawing.rot)){
                if(AscFormat.checkNormalRotate(drawing.rot))
                {
                    W = drawing.extX;
                    H = drawing.extY;
                }
                else
                {
                    W = drawing.extY;
                    H = drawing.extX;
                }
            }
            else{
                W = drawing.parent.extX;
                H = drawing.parent.extY;
            }
            var xc = drawing.localTransform.TransformPointX(drawing.extX / 2, drawing.extY / 2);
            var yc = drawing.localTransform.TransformPointY(drawing.extX / 2, drawing.extY / 2);
            this.arrPoints.length = 0;
            this.localLeft = - AscFormat.getValOrDefault(oEffectExtent.L, 0) + (xc - W / 2) - oDistance.L ;
            this.localRight =  AscFormat.getValOrDefault(oEffectExtent.R, 0) + (xc + W / 2) + oDistance.R;
            this.localTop = - AscFormat.getValOrDefault(oEffectExtent.T, 0) + (yc - H / 2) - oDistance.T;
            this.localBottom = AscFormat.getValOrDefault(oEffectExtent.B, 0) + (yc + H / 2) + oDistance.B;
            return;
        }
        var relArr = this.relativeArrPoints;
        var absArr = this.arrPoints;
        absArr.length = 0;
        for(var point_index = 0; point_index < relArr.length; ++point_index)
        {
            var rel_point = relArr[point_index];
            var tr_x = (transform.TransformPointX(rel_point.x*drawing.extX/21600, rel_point.y*drawing.extY/21600));
            var tr_y = (transform.TransformPointY(rel_point.x*drawing.extX/21600, rel_point.y*drawing.extY/21600));
            absArr[point_index] = {x: tr_x, y:tr_y};
        }

        var min_x, max_x, min_y, max_y;
        min_x = absArr[0].x;
        max_x = min_x;
        min_y = absArr[0].y;
        max_y = min_y;

        for(point_index = 0; point_index < absArr.length; ++point_index)
        {
            var absPoint = absArr[point_index];
            if(min_x > absPoint.x)
                min_x = absPoint.x;
            if(max_x < absPoint.x)
                max_x = absPoint.x;

            if(min_y > absPoint.y)
                min_y = absPoint.y;
            if(max_y < absPoint.y)
                max_y = absPoint.y;
        }

        if(bounds.l < min_x)
            this.localLeft = bounds.l - oDistance.L  - AscFormat.getValOrDefault(oEffectExtent.L, 0);
        else
            this.localLeft  = min_x - oDistance.L  - AscFormat.getValOrDefault(oEffectExtent.L, 0);

        if(bounds.r > max_x)
            this.localRight = bounds.r + oDistance.R + AscFormat.getValOrDefault(oEffectExtent.R, 0);
        else
            this.localRight = max_x + oDistance.R + AscFormat.getValOrDefault(oEffectExtent.R, 0);

        if(bounds.t < min_y)
            this.localTop = bounds.t - oDistance.T - AscFormat.getValOrDefault(oEffectExtent.T, 0);
        else
            this.localTop = min_y - oDistance.T - AscFormat.getValOrDefault(oEffectExtent.T, 0);

        if(bounds.b > max_y)
            this.localBottom = bounds.b + oDistance.B + AscFormat.getValOrDefault(oEffectExtent.B, 0);
        else
            this.localBottom = max_y + oDistance.B + AscFormat.getValOrDefault(oEffectExtent.B, 0);
    },

    calculateAbsToRel: function(drawing, aPoints)
    {
        var relArr = [];
        if(aPoints.length === 0)
        {
            return relArr;
        }
        var transform = drawing.localTransform;
        var invert_transform = AscCommon.global_MatrixTransformer.Invert(transform);
        for(var point_index = 0; point_index < aPoints.length; ++point_index)
        {
            var abs_point = aPoints[point_index];
            var tr_x = invert_transform.TransformPointX(abs_point.x, abs_point.y)*(21600/drawing.extX)>>0;
            var tr_y = invert_transform.TransformPointY(abs_point.x, abs_point.y)*(21600/drawing.extY)>>0;
            relArr[point_index] = {x: tr_x, y:tr_y};
        }

        var min_x, max_x, min_y, max_y;
        min_x = aPoints[0].x;
        max_x = min_x;
        min_y = aPoints[0].y;
        max_y = min_y;

        for(point_index = 0; point_index < aPoints.length; ++point_index)
        {
            var absPoint = aPoints[point_index];
            if(min_x > absPoint.x)
                min_x = absPoint.x;
            if(max_x < absPoint.x)
                max_x = absPoint.x;

            if(min_y > absPoint.y)
                min_y = absPoint.y;
            if(max_y < absPoint.y)
                max_y = absPoint.y;
        }
        return relArr;
    },

    updatePosition: function(x, y)
    {
        this.posX = x;
        this.posY = y;
        this.calculatedPoints.length = 0;
        var p, local_point;
        for(var i = 0;  i < this.arrPoints.length; ++i)
        {
            local_point = this.arrPoints[i];
            p = new CPolygonPoint();
            p.x = (local_point.x + x);
            p.y = (local_point.y + y);
            this.calculatedPoints.push(p);
        }
        this.left   = this.localLeft + x;
        this.top    = this.localTop + y;
        this.right  = this.localRight + x;
        this.bottom = this.localBottom + y;
    },

    Refresh_RecalcData : function(Data)
    {
        if(this.wordGraphicObject && this.wordGraphicObject.GraphicObj && this.wordGraphicObject.GraphicObj.recalcWrapPolygon)
        {
            this.wordGraphicObject.GraphicObj.recalcWrapPolygon();
            this.wordGraphicObject.GraphicObj.addToRecalculate();
            this.wordGraphicObject.Refresh_RecalcData();
        }
    },

    Refresh_RecalcData2 : function()
    {
    }
};


function CPolygonPoint()
{
    this.x = +0;
    this.y = +0;
}


function CWrapManager(graphicPage)
{
    this.graphicPage = graphicPage;

}

CWrapManager.prototype =
{
    checkRanges: function(x0, y0, x1, y1, Y0sp, Y1Ssp, LeftField, RightField, hdrFtrRa, docContent, bMathWrap)
    {
        var arr_intervals = [];

        var index;
        if(docContent == null)
        {

            var aDrawings = this.graphicPage.behindDocObjects;
            for(var index = 0; index < aDrawings.length; ++index)
            {
                var oParaDrawing = aDrawings[index].parent;
                if(oParaDrawing.IsLayoutInCell())
                {
                    var oTableCell = oParaDrawing.DocumentContent.IsTableCellContent(true);
                    if(oTableCell !== docContent)
                    {
                        continue;
                    }
                }
                aDrawings[index].getArrayWrapIntervals(x0,y0, x1, y1, Y0sp, Y1Ssp, LeftField, RightField,  arr_intervals, bMathWrap);
            }

            aDrawings = this.graphicPage.beforeTextObjects;
            for(var index = 0; index < aDrawings.length; ++index)
            {
                var oParaDrawing = aDrawings[index].parent;
                if(oParaDrawing.IsLayoutInCell())
                {
                    var oTableCell = oParaDrawing.DocumentContent.IsTableCellContent(true);
                    if(oTableCell !== docContent)
                    {
                        continue;
                    }
                }
                aDrawings[index].getArrayWrapIntervals(x0,y0, x1, y1, Y0sp, Y1Ssp, LeftField, RightField,  arr_intervals, bMathWrap);
            }
            var arrFlowTables = this.graphicPage.flowTables;
            for(index = 0; index < arrFlowTables.length; ++index)
            {
                arrFlowTables[index].getArrayWrapIntervals(x0,y0, x1, y1, Y0sp, Y1Ssp, LeftField, RightField,  arr_intervals, bMathWrap);
            }
        }
        else
        {
            if(!docContent.IsHdrFtr())
            {

                var aDrawings = this.graphicPage.behindDocObjects;
                for(index = 0; index < aDrawings.length; ++index)
                {
                    var oParaDrawing = aDrawings[index].parent;
                    if(oParaDrawing)
                    {

                        if(oParaDrawing && oParaDrawing.DocumentContent)
                        {
                            if(oParaDrawing.IsLayoutInCell())
                            {
                                var oTableCell1 = docContent.IsTableCellContent(true);
                                var oTableCell2 = oParaDrawing.DocumentContent.IsTableCellContent(true);
                                if(oTableCell1 !== oTableCell2)
                                {
                                    continue;
                                }
                            }
                            if(oParaDrawing.DocumentContent === docContent)
                            {
                                aDrawings[index].getArrayWrapIntervals(x0,y0, x1, y1, Y0sp, Y1Ssp, LeftField, RightField, arr_intervals, bMathWrap);
                            }
                        }
                    }
                }
                aDrawings = this.graphicPage.beforeTextObjects;
                for(index = 0; index < aDrawings.length; ++index)
                {
                    var oParaDrawing = aDrawings[index].parent;
                    if(oParaDrawing)
                    {

                        if(oParaDrawing && oParaDrawing.DocumentContent)
                        {
                            if(oParaDrawing.IsLayoutInCell())
                            {
                                var oTableCell1 = docContent.IsTableCellContent(true);
                                var oTableCell2 = oParaDrawing.DocumentContent.IsTableCellContent(true);
                                if(oTableCell1 !== oTableCell2)
                                {
                                    continue;
                                }
                            }
                            if(oParaDrawing.DocumentContent === docContent)
                            {
                                aDrawings[index].getArrayWrapIntervals(x0,y0, x1, y1, Y0sp, Y1Ssp, LeftField, RightField, arr_intervals, bMathWrap);
                            }
                        }
                    }
                }
                arrFlowTables = this.graphicPage.flowTables;
                for(index = 0; index < arrFlowTables.length; ++index)
                {
                    var cur_float_table = arrFlowTables[index];
                    if(cur_float_table.Table.Parent === docContent)
                    {
                        cur_float_table.getArrayWrapIntervals(x0,y0, x1, y1, Y0sp, Y1Ssp, LeftField, RightField, arr_intervals, bMathWrap);
                    }
                }
            }
            else
            {
                var pageIndex = this.graphicPage.pageIndex;
                var graphic_objects = this.graphicPage.graphicObjects;
                var hdr_footer_objects = this.graphicPage.graphicObjects.getHdrFtrObjectsByPageIndex(pageIndex);
                if(hdr_footer_objects != null)
                {
                    var aDrawings = hdr_footer_objects.behindDocObjects;
                    for(index = 0; index < aDrawings.length; ++index)
                    {
                        if(aDrawings[index].parent && aDrawings[index].parent.DocumentContent === docContent)
                        {
                            aDrawings[index].getArrayWrapIntervals(x0,y0, x1, y1, Y0sp, Y1Ssp, LeftField, RightField, arr_intervals, bMathWrap);
                        }
                    }
                    aDrawings = hdr_footer_objects.beforeTextObjects;
                    for(index = 0; index < aDrawings.length; ++index)
                    {
                        if(aDrawings[index].parent && aDrawings[index].parent.DocumentContent === docContent)
                        {
                            aDrawings[index].getArrayWrapIntervals(x0,y0, x1, y1, Y0sp, Y1Ssp, LeftField, RightField, arr_intervals, bMathWrap);
                        }
                    }
                    arrFlowTables = hdr_footer_objects.flowTables;
                    for(index = 0; index < arrFlowTables.length; ++index)
                    {
                        var cur_float_table = arrFlowTables[index];
                        if(cur_float_table.Table.Parent === docContent)
                        {
                            cur_float_table.getArrayWrapIntervals(x0,y0, x1, y1, Y0sp, Y1Ssp, LeftField, RightField, arr_intervals, bMathWrap);
                        }
                    }
                }
            }
        }


        for(index = 0; index < hdrFtrRa.length; ++index)
        {
            arr_intervals.push(hdrFtrRa[index]);
        }
        arr_intervals.sort(function(a, b){return a.X0 - b.X0});
        for(var s  = 0; s < arr_intervals.length - 1; ++s)
        {
            var int0 = arr_intervals[s];
            var int1 = arr_intervals[s+1];
            var dist;
            if(int0.typeRight === WRAPPING_TYPE_SQUARE || int0.typeRight === WRAPPING_TYPE_TIGHT || int0.typeRight === WRAPPING_TYPE_THROUGH
                || int1.typeLeft === WRAPPING_TYPE_SQUARE || int1.typeLeft === WRAPPING_TYPE_TIGHT || int1.typeLeft === WRAPPING_TYPE_THROUGH || bMathWrap === true)
            {
                dist = (int0.typeRight === WRAPPING_TYPE_TIGHT || int0.typeRight === WRAPPING_TYPE_THROUGH) || (int1.typeLeft === WRAPPING_TYPE_TIGHT || int1.typeLeft === WRAPPING_TYPE_THROUGH) ? 3.175 : 6.35;
                var d = arr_intervals[s+1].X0 - arr_intervals[s].X1;
                if(d > 0 && d < dist)
                {
                    int0.X1 = int1.X1;
                    int0.Y1 = Math.min(int0.Y1, int1.Y1);
                    int0.typeRight = int1.typeRight;
                    arr_intervals.splice(s+1, 1);
                    --s;
                }
            }

        }
        for(var interval_index = 0; interval_index < arr_intervals.length; ++interval_index)
        {
            var cur_interval = arr_intervals[interval_index];
            for(var interval_index2 =  interval_index+1; interval_index2 < arr_intervals.length; ++interval_index2)
            {
                var cur_interval2 = arr_intervals[interval_index2];
                if(cur_interval2.X0 <= cur_interval.X1)
                {
                    if(cur_interval2.X1 > cur_interval.X1)
                    {
                        cur_interval.X1 = cur_interval2.X1;
                        cur_interval.Y1 = Math.min(cur_interval.Y1, cur_interval2.Y1);
                    }
                    arr_intervals.splice(interval_index2, 1);
                    --interval_index2;
                }
                else
                    break;
            }
        }
        return arr_intervals;
    }
};

function TrackNewPointWrapPolygon(originalObject, point1)
{
    this.originalObject = originalObject;
    this.point1 = point1;
    this.pageIndex = originalObject.selectStartPage;
    this.arrPoints = [];
    for(var  i = 0; i < originalObject.parent.wrappingPolygon.calculatedPoints.length; ++i)
    {
        this.arrPoints[i] = {};
        this.arrPoints[i].x = originalObject.parent.wrappingPolygon.calculatedPoints[i].x;
        this.arrPoints[i].y = originalObject.parent.wrappingPolygon.calculatedPoints[i].y;
    }
    this.arrPoints.splice(point1+1, 0, {x: null, y: null});
    this.matrix = new AscCommon.CMatrix();
    this.point2 = originalObject.parent.wrappingPolygon.calculatedPoints[point1 + 1] ? originalObject.parent.wrappingPolygon.calculatedPoints[point1 + 1] : originalObject.parent.wrappingPolygon.calculatedPoints[0];
}


TrackNewPointWrapPolygon.prototype =
{
    track: function(x, y)
    {
        this.arrPoints[this.point1+1].x = x;
        this.arrPoints[this.point1+1].y = y;
    },

    draw: function(overlay)
    {
        overlay.SetCurrentPage(this.pageIndex);
        overlay.DrawEditWrapPointsTrackLines([this.arrPoints[this.point1], this.arrPoints[this.point1+1], this.point2], this.matrix);
        overlay.ds();
    }
};

function TrackPointWrapPointWrapPolygon(originalObject, point)
{
    this.originalObject = originalObject;
    this.point = point;
    this.pointCoord = {};
    this.pointCoord.x = originalObject.parent.wrappingPolygon.calculatedPoints[point].x;
    this.pointCoord.y = originalObject.parent.wrappingPolygon.calculatedPoints[point].y;
    this.point1 = originalObject.parent.wrappingPolygon.calculatedPoints[point - 1] ? originalObject.parent.wrappingPolygon.calculatedPoints[point - 1] : originalObject.parent.wrappingPolygon.calculatedPoints[originalObject.parent.wrappingPolygon.calculatedPoints.length-1];
    this.point2 = originalObject.parent.wrappingPolygon.calculatedPoints[point + 1] ? originalObject.parent.wrappingPolygon.calculatedPoints[point + 1] : originalObject.parent.wrappingPolygon.calculatedPoints[0];
    this.matrix = new AscCommon.CMatrix();
    this.pageIndex = originalObject.selectStartPage;
}

TrackPointWrapPointWrapPolygon.prototype =
{
    track: function(x, y)
    {
        this.pointCoord.x = x;
        this.pointCoord.y = y;
    },

    draw: function(overlay)
    {
        overlay.SetCurrentPage(this.pageIndex);
        overlay.DrawEditWrapPointsTrackLines([this.point1, this.pointCoord, this.point2], this.matrix);
        overlay.ds();
    }
};


function CChangesWrapPolygonEdited(Class, OldPr, NewPr){
	AscDFH.CChangesBaseBoolProperty.call(this, Class, OldPr, NewPr);
}
CChangesWrapPolygonEdited.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesWrapPolygonEdited.prototype.constructor = CChangesWrapPolygonEdited;
CChangesWrapPolygonEdited.prototype.Type = AscDFH.historyitem_WrapPolygonSetEdited;
CChangesWrapPolygonEdited.prototype.private_SetValue = function(value){
    if(this.Class){
        this.Class.edited = value;
        if(this.Class.wordGraphicObject && this.Class.wordGraphicObject.GraphicObj && this.Class.wordGraphicObject.GraphicObj.recalcWrapPolygon)
        {
            this.Class.wordGraphicObject.GraphicObj.recalcWrapPolygon();
            this.Class.wordGraphicObject.GraphicObj.addToRecalculate()
        }
    }
};

function CChangesWrapPolygonWrapSide(Class, OldPr, NewPr){
	AscDFH.CChangesBaseLongProperty.call(this, Class, OldPr, NewPr);
}
CChangesWrapPolygonWrapSide.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesWrapPolygonWrapSide.prototype.constructor = CChangesWrapPolygonWrapSide;
CChangesWrapPolygonWrapSide.prototype.Type = AscDFH.historyitem_WrapPolygonSetWrapSide;
CChangesWrapPolygonWrapSide.prototype.private_SetValue = function(value){
    if(this.Class){
        this.Class.wrapSide = value;
        if(this.Class.wordGraphicObject && this.Class.wordGraphicObject.GraphicObj && this.Class.wordGraphicObject.GraphicObj.recalcWrapPolygon)
        {
            this.Class.wordGraphicObject.GraphicObj.recalcWrapPolygon();
            this.Class.wordGraphicObject.GraphicObj.addToRecalculate()
        }
    }

};

function CChangesWrapPolygonRelPoints(Class, OldPr, NewPr){
	AscDFH.CChangesBaseObjectProperty.call(this, Class, OldPr, NewPr);
}
CChangesWrapPolygonRelPoints.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesWrapPolygonRelPoints.prototype.constructor = CChangesWrapPolygonRelPoints;
CChangesWrapPolygonRelPoints.prototype.Type = AscDFH.historyitem_WrapPolygonSetRelPoints;
CChangesWrapPolygonRelPoints.prototype.private_IsCreateEmptyObject = function(){
    return true;
};
CChangesWrapPolygonRelPoints.prototype.private_CreateObject = function(){
    return new ArrayWrapPoint();
};

CChangesWrapPolygonRelPoints.prototype.private_SetValue = function(value){
    if(this.Class){
        var aRelPoints = [];
        for(var i = 0;  i < value.length; ++i){
            aRelPoints.push(value[i]);
        }
        this.Class.relativeArrPoints = aRelPoints;
        if(this.Class.wordGraphicObject && this.Class.wordGraphicObject.GraphicObj && this.Class.wordGraphicObject.GraphicObj.recalcWrapPolygon)
        {
            this.Class.wordGraphicObject.GraphicObj.recalcWrapPolygon();
            this.Class.wordGraphicObject.GraphicObj.addToRecalculate()
        }
    }
};

function ArrayWrapPoint(oArray){
	Array.call(this);
    if(oArray){
        this.length = oArray.length;
        for(var i = 0;  i < oArray.length; ++i){
            this[i] = {};
            this[i].x = oArray[i].x;
            this[i].y = oArray[i].y;
        }
    }
}
ArrayWrapPoint.prototype = Object.create(Array.prototype);
ArrayWrapPoint.prototype.constructor = ArrayWrapPoint;
ArrayWrapPoint.prototype.Write_ToBinary = function(Writer){
    Writer.WriteLong(this.length);
    for(var i = 0; i < this.length; ++i){
        Writer.WriteLong(this[i].x >> 0);
        Writer.WriteLong(this[i].y >> 0);
    }
};
ArrayWrapPoint.prototype.Read_FromBinary = function(Reader){
    var nLength = Reader.GetLong();
    var x, y;
    for(var i = 0; i < nLength; ++i){
        x = Reader.GetLong();
        y = Reader.GetLong();
        this.push({x: x, y: y});
    }
    this.length = nLength;
};


AscDFH.changesFactory = AscDFH.changesFactory || {};
AscDFH.changesFactory[AscDFH.historyitem_WrapPolygonSetEdited] = CChangesWrapPolygonEdited;
AscDFH.changesFactory[AscDFH.historyitem_WrapPolygonSetWrapSide] = CChangesWrapPolygonWrapSide;
AscDFH.changesFactory[AscDFH.historyitem_WrapPolygonSetRelPoints] = CChangesWrapPolygonRelPoints;


//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CWrapPolygon = CWrapPolygon;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 05.04.2017
 * Time: 11:42
 */

var type_Unknown = 0x00;

/**
 * Базовый класс для элементов содержимого документа (Paragraph, CTable, CBlockLevelSdt)
 * @param oParent - ссылка на базовый класс
 * @constructor
 */
function CDocumentContentElementBase(oParent)
{
	this.Id = AscCommon.g_oIdCounter.Get_NewId();

	this.Parent = oParent;
	this.Prev   = null;
	this.Next   = null;
	this.Index  = -1; // перед тем как пользоваться этим параметром нужно у родительского класса вызывать this.Parent.Update_ContentIndexing();

	this.Recalculated = false; // Данный параметр управляет тем, были ли у нас произведены изменения с элементом с момента последнего пересчета

	this.X            = 0;
	this.Y            = 0;
	this.XLimit       = 0;
	this.YLimit       = 0;
	this.PageNum      = 0;
	this.ColumnNum    = 0;
	this.ColumnsCount = 0;
}

CDocumentContentElementBase.prototype.Get_Type = function()
{
	return this.GetType();
};
CDocumentContentElementBase.prototype.GetType = function()
{
	return type_Unknown;
};
CDocumentContentElementBase.prototype.Is_Inline = function()
{
	return true;
};
CDocumentContentElementBase.prototype.Set_DocumentIndex = function(nIndex)
{
	this.Index = nIndex;
};
CDocumentContentElementBase.prototype.Set_DocumentNext = function(oElement)
{
	this.Next = oElement;
};
CDocumentContentElementBase.prototype.Set_DocumentPrev = function(oElement)
{
	this.Prev = oElement;
};
CDocumentContentElementBase.prototype.Get_DocumentNext = function()
{
	return this.Next;
};
CDocumentContentElementBase.prototype.Get_DocumentPrev = function()
{
	return this.Prev;
};
CDocumentContentElementBase.prototype.GetParent = function()
{
	return this.Parent;
};
CDocumentContentElementBase.prototype.SetParent = function(oParent)
{
	this.Parent = oParent;
};
CDocumentContentElementBase.prototype.Set_Parent = function(oParent)
{
	this.Parent = oParent;
};
CDocumentContentElementBase.prototype.Get_Parent = function()
{
	return this.Parent;
};
CDocumentContentElementBase.prototype.GetId = function()
{
	return this.Id;
};
CDocumentContentElementBase.prototype.Get_Id = function()
{
	return this.GetId();
};
CDocumentContentElementBase.prototype.Reset = function(X, Y, XLimit, YLimit, PageAbs, ColumnAbs, ColumnsCount)
{
	this.X            = X;
	this.Y            = Y;
	this.XLimit       = XLimit;
	this.YLimit       = YLimit;
	this.PageNum      = PageAbs;
	this.ColumnNum    = ColumnAbs ? ColumnAbs : 0;
	this.ColumnsCount = ColumnsCount ? ColumnsCount : 1;
};
CDocumentContentElementBase.prototype.Recalculate_Page = function(CurPage)
{
	return recalcresult_NextElement;
};
CDocumentContentElementBase.prototype.Get_PageBounds = function(CurPage)
{
	return new CDocumentBounds(this.X, this.Y, this.XLimit, this.YLimit);
};
CDocumentContentElementBase.prototype.GetContentBounds = function(CurPage)
{
	return new CDocumentBounds(this.X, this.Y, this.XLimit, this.YLimit);
};
CDocumentContentElementBase.prototype.IsEmptyPage = function(nCurPage)
{
	return false;
};
CDocumentContentElementBase.prototype.Reset_RecalculateCache = function()
{
};
CDocumentContentElementBase.prototype.Write_ToBinary2 = function(Writer)
{
	Writer.WriteLong(AscDFH.historyitem_type_Unknown);
};
CDocumentContentElementBase.prototype.Read_FromBinary2 = function(Reader)
{
};
CDocumentContentElementBase.prototype.Get_PagesCount = function()
{
	return 0;
};
CDocumentContentElementBase.prototype.Document_CreateFontMap = function(FontMap)
{
};
CDocumentContentElementBase.prototype.Document_CreateFontCharMap = function(FontCharMap)
{
};
CDocumentContentElementBase.prototype.Document_Get_AllFontNames = function(AllFonts)
{
};
CDocumentContentElementBase.prototype.IsInText = function(X, Y, CurPage)
{
	return null;
};
CDocumentContentElementBase.prototype.IsInDrawing = function(X, Y, CurPage)
{
	return false;
};
CDocumentContentElementBase.prototype.IsTableBorder = function(X, Y, CurPage)
{
	return null;
};
CDocumentContentElementBase.prototype.UpdateCursorType = function(X, Y, CurPage)
{
};
CDocumentContentElementBase.prototype.Selection_SetStart = function(X, Y, CurPage, MouseEvent, isTableBorder)
{
};
CDocumentContentElementBase.prototype.Selection_SetEnd = function(X, Y, CurPage, MouseEvent, isTableBorder)
{
};
CDocumentContentElementBase.prototype.IsSelectionEmpty = function(isCheckHidden)
{
	return true;
};
CDocumentContentElementBase.prototype.GetSelectedElementsInfo = function(oInfo)
{
};
CDocumentContentElementBase.prototype.Document_UpdateRulersState = function(CurPage)
{
	this.Content.Document_UpdateRulersState(CurPage);
};
CDocumentContentElementBase.prototype.IsSelectionUse = function()
{
	return false;
};
CDocumentContentElementBase.prototype.IsSelectionToEnd = function()
{
	return false;
};
CDocumentContentElementBase.prototype.RemoveSelection = function()
{
};
CDocumentContentElementBase.prototype.SetSelectionUse = function(isUse)
{
};
CDocumentContentElementBase.prototype.SetSelectionToBeginEnd = function(isSelectionStart, isElementStart)
{
};
CDocumentContentElementBase.prototype.SelectAll = function(nDirection)
{
};
CDocumentContentElementBase.prototype.GetCalculatedTextPr = function()
{
	var oTextPr = new CTextPr();
	oTextPr.Init_Default();
	return oTextPr;
};
CDocumentContentElementBase.prototype.GetCalculatedParaPr = function()
{
	var oParaPr = new CParaPr();
	oParaPr.Init_Default();
	return oParaPr;
};
CDocumentContentElementBase.prototype.GetDirectParaPr = function()
{
	return new CParaPr();
};
CDocumentContentElementBase.prototype.GetDirectTextPr = function()
{
	return new CTextPr();
};
CDocumentContentElementBase.prototype.DrawSelectionOnPage = function(CurPage)
{
};
CDocumentContentElementBase.prototype.StopSelection = function()
{
};
CDocumentContentElementBase.prototype.GetSelectionBounds = function()
{
	return {
		Start     : null,
		End       : null,
		Direction : 0
	};
};
CDocumentContentElementBase.prototype.RecalculateCurPos = function(bUpdateX, bUpdateY)
{
	return null;
};
CDocumentContentElementBase.prototype.Can_CopyCut = function()
{
	return false;
};
CDocumentContentElementBase.prototype.CanCopyCut = function()
{
	return this.Can_CopyCut();
};
CDocumentContentElementBase.prototype.CheckPosInSelection = function(X, Y, CurPage, NearPos)
{
	return false;
};
CDocumentContentElementBase.prototype.Get_NearestPos = function(CurPage, X, Y, bAnchor, Drawing)
{
	return {
		X          : 0,
		Y          : 0,
		Height     : 0,
		PageNum    : 0,
		Internal   : {Line : 0, Page : 0, Range : 0},
		Transform  : null,
		Paragraph  : null,
		ContentPos : null,
		SearchPos  : null
	};
};
CDocumentContentElementBase.prototype.GetNearestPos = function(CurPage, X, Y, bAnchor, Drawing)
{
	return this.Get_NearestPos(CurPage, X, Y, bAnchor, Drawing);
};
CDocumentContentElementBase.prototype.CanUpdateTarget = function(CurPage)
{
	return false;
};
CDocumentContentElementBase.prototype.MoveCursorLeftWithSelectionFromEnd = function(Word)
{
};
CDocumentContentElementBase.prototype.MoveCursorLeft = function(AddToSelect, Word)
{
	return false;
};
CDocumentContentElementBase.prototype.MoveCursorRight = function(AddToSelect, Word)
{
	return false;
};
CDocumentContentElementBase.prototype.MoveCursorRightWithSelectionFromStart = function(Word)
{

};
CDocumentContentElementBase.prototype.MoveCursorToStartPos = function(AddToSelect)
{
};
CDocumentContentElementBase.prototype.MoveCursorToEndPos = function(AddToSelect, StartSelectFromEnd)
{
};
CDocumentContentElementBase.prototype.MoveCursorUp = function(AddToSelect)
{
	return false;
};
CDocumentContentElementBase.prototype.MoveCursorUpToLastRow = function(X, Y, AddToSelect)
{
	return false;
};
CDocumentContentElementBase.prototype.MoveCursorDown = function(AddToSelect)
{
	return false;
};
CDocumentContentElementBase.prototype.MoveCursorDownToFirstRow = function(X, Y, AddToSelect)
{
	return false;
};
CDocumentContentElementBase.prototype.MoveCursorToEndOfLine = function(AddToSelect)
{
	return false;
};
CDocumentContentElementBase.prototype.MoveCursorToStartOfLine = function(AddToSelect)
{
	return false;
};
CDocumentContentElementBase.prototype.MoveCursorToXY = function(X, Y, bLine, bDontChangeRealPos, CurPage)
{
	return false;
};
CDocumentContentElementBase.prototype.MoveCursorToCell = function(bNext)
{
	return false;
};
CDocumentContentElementBase.prototype.IsCursorAtBegin = function()
{
	return true;
};
CDocumentContentElementBase.prototype.IsCursorAtEnd = function()
{
	return true;
};
CDocumentContentElementBase.prototype.GetSelectionState = function()
{
	return [];
};
CDocumentContentElementBase.prototype.SetSelectionState = function(State, StateIndex)
{

};
CDocumentContentElementBase.prototype.AddNewParagraph = function()
{

};
CDocumentContentElementBase.prototype.Get_SelectionState2 = function()
{
	return null;
};
CDocumentContentElementBase.prototype.Set_SelectionState2 = function(State)
{
};
CDocumentContentElementBase.prototype.IsStartFromNewPage = function()
{
	return false;
};
CDocumentContentElementBase.prototype.GetAllParagraphs = function(Props, ParaArray)
{
};
CDocumentContentElementBase.prototype.SetContentSelection = function(StartDocPos, EndDocPos, Depth, StartFlag, EndFlag)
{
};
CDocumentContentElementBase.prototype.GetContentPosition = function(bSelection, bStart, PosArray)
{
};
CDocumentContentElementBase.prototype.SetContentPosition = function(DocPos, Depth, Flag)
{
};
CDocumentContentElementBase.prototype.GetNumberingInfo = function(oNumberingEngine)
{
};
CDocumentContentElementBase.prototype.AddInlineImage = function(W, H, Img, Chart, bFlow)
{
};
CDocumentContentElementBase.prototype.AddImages = function(aImages)
{
};
CDocumentContentElementBase.prototype.AddOleObject = function(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId)
{
};
CDocumentContentElementBase.prototype.AddSignatureLine = function(oSignatureDrawing)
{
};
CDocumentContentElementBase.prototype.AddTextArt = function(nStyle)
{
};
CDocumentContentElementBase.prototype.AddInlineTable = function(nCols, nRows)
{
};
CDocumentContentElementBase.prototype.Remove = function(nCount, bOnlyText, bRemoveOnlySelection, bOnAddText)
{
};
CDocumentContentElementBase.prototype.Set_ReviewType = function(ReviewType)
{

};
CDocumentContentElementBase.prototype.Get_ReviewType = function()
{
	return reviewtype_Common;
};
CDocumentContentElementBase.prototype.Is_Empty = function()
{
	return true;
};
CDocumentContentElementBase.prototype.Add = function(oParaItem)
{
	// TODO: Данную функцию нужно заменить на AddToParagraph
};
CDocumentContentElementBase.prototype.PreDelete = function()
{
};
CDocumentContentElementBase.prototype.ClearParagraphFormatting = function(isClearParaPr, isClearTextPr)
{
};
CDocumentContentElementBase.prototype.GetCursorPosXY = function()
{
	return {X : 0, Y : 0};
};
CDocumentContentElementBase.prototype.StartSelectionFromCurPos = function()
{
};
CDocumentContentElementBase.prototype.SetParagraphAlign = function(Align)
{
};
CDocumentContentElementBase.prototype.SetParagraphDefaultTabSize = function(TabSize)
{
};
CDocumentContentElementBase.prototype.SetParagraphSpacing = function(Spacing)
{
};
CDocumentContentElementBase.prototype.SetParagraphTabs = function(Tabs)
{
};
CDocumentContentElementBase.prototype.SetParagraphIndent = function(Ind)
{
};
CDocumentContentElementBase.prototype.SetParagraphShd = function(Shd)
{
};
CDocumentContentElementBase.prototype.SetParagraphStyle = function(Name)
{
};
CDocumentContentElementBase.prototype.SetParagraphContextualSpacing = function(Value)
{
};
CDocumentContentElementBase.prototype.SetParagraphPageBreakBefore = function(Value)
{
};
CDocumentContentElementBase.prototype.SetParagraphKeepLines = function(Value)
{
};
CDocumentContentElementBase.prototype.SetParagraphKeepNext = function(Value)
{
};
CDocumentContentElementBase.prototype.SetParagraphWidowControl = function(Value)
{
};
CDocumentContentElementBase.prototype.SetParagraphBorders = function(Borders)
{
};
CDocumentContentElementBase.prototype.SetParagraphFramePr = function(FramePr, bDelete)
{
};
CDocumentContentElementBase.prototype.IncreaseDecreaseFontSize = function(bIncrease)
{
};
CDocumentContentElementBase.prototype.IncreaseDecreaseIndent = function(bIncrease)
{
};
CDocumentContentElementBase.prototype.SetImageProps = function(oProps)
{
};
CDocumentContentElementBase.prototype.SetTableProps = function(oProps)
{
};
CDocumentContentElementBase.prototype.GetSelectedContent = function(oSelectedContent)
{
};
CDocumentContentElementBase.prototype.PasteFormatting = function(TextPr, ParaPr, ApplyPara)
{
};
CDocumentContentElementBase.prototype.GetCurPosXY = function()
{
	return {X : 0, Y : 0};
};
CDocumentContentElementBase.prototype.GetSelectedText = function(bClearText, oPr)
{
	return null;
};
CDocumentContentElementBase.prototype.GetCurrentParagraph = function(bIgnoreSelection, arrSelectedParagraphs)
{
	return null;
};
CDocumentContentElementBase.prototype.AddTableRow = function(bBefore)
{
	return false;
};
CDocumentContentElementBase.prototype.AddTableColumn = function(bBefore)
{
	return false;
};
CDocumentContentElementBase.prototype.RemoveTableRow = function(nRowIndex)
{
	return false;
};
CDocumentContentElementBase.prototype.RemoveTableColumn = function()
{
	return false;
};
CDocumentContentElementBase.prototype.MergeTableCells = function()
{
	return false;
};
CDocumentContentElementBase.prototype.SplitTableCells = function(nColsCount, nRowsCount)
{
	return false;
};
CDocumentContentElementBase.prototype.RemoveTable = function()
{
	return false;
};
CDocumentContentElementBase.prototype.SelectTable = function(Type)
{
};
CDocumentContentElementBase.prototype.DistributeTableCells = function(isHorizontally)
{
	return false;
};
CDocumentContentElementBase.prototype.CanMergeTableCells = function()
{
	return false;
};
CDocumentContentElementBase.prototype.CanSplitTableCells = function()
{
	return false;
};
CDocumentContentElementBase.prototype.Document_UpdateInterfaceState = function()
{
};
CDocumentContentElementBase.prototype.Document_UpdateRulersState = function()
{
};
CDocumentContentElementBase.prototype.GetTableProps = function()
{
	return null;
};
CDocumentContentElementBase.prototype.AddHyperlink = function(Props)
{
};
CDocumentContentElementBase.prototype.ModifyHyperlink = function(Props)
{
};
CDocumentContentElementBase.prototype.RemoveHyperlink = function()
{
};
CDocumentContentElementBase.prototype.CanAddHyperlink = function(bCheckInHyperlink)
{
	return false;
};
CDocumentContentElementBase.prototype.IsCursorInHyperlink = function(bCheckEnd)
{
	return null;
};
CDocumentContentElementBase.prototype.AddComment = function(Comment, bStart, bEnd)
{
};
CDocumentContentElementBase.prototype.CanAddComment = function()
{
	return false;
};
CDocumentContentElementBase.prototype.GetSelectionAnchorPos = function()
{
	return null;
};
CDocumentContentElementBase.prototype.AddContentControl = function(nContentControlType)
{
	return null;
};
CDocumentContentElementBase.prototype.RecalculateMinMaxContentWidth = function(isRotated)
{
	return {Min : 0, Max : 0};
};
CDocumentContentElementBase.prototype.Shift = function(CurPage, dX, dY)
{
};
CDocumentContentElementBase.prototype.UpdateEndInfo = function()
{
};
CDocumentContentElementBase.prototype.PrepareRecalculateObject = function()
{
};
CDocumentContentElementBase.prototype.SaveRecalculateObject = function()
{
	return null;
};
CDocumentContentElementBase.prototype.LoadRecalculateObject = function(RecalcObj)
{
};
CDocumentContentElementBase.prototype.Set_ApplyToAll = function(bValue)
{
};
CDocumentContentElementBase.prototype.RecalculateAllTables = function()
{
};
CDocumentContentElementBase.prototype.GetAllFloatElements = function(FloatObjects)
{
	if (!FloatObjects)
		return [];

	return FloatObjects;
};
CDocumentContentElementBase.prototype.Get_FirstParagraph = function()
{
	return null;
};
CDocumentContentElementBase.prototype.StartFromNewPage = function()
{
};
CDocumentContentElementBase.prototype.CollectDocumentStatistics = function(Stats)
{
};
CDocumentContentElementBase.prototype.CompareDrawingsLogicPositions = function(CompareObject)
{
	return 0;
};
CDocumentContentElementBase.prototype.GetStyleFromFormatting = function()
{
	return null;
};
CDocumentContentElementBase.prototype.GetAllContentControls = function(arrContentControls)
{
};
CDocumentContentElementBase.prototype.IsSelectedAll = function()
{
	return false;
};
CDocumentContentElementBase.prototype.CheckContentControlDeletingLock = function()
{
};
CDocumentContentElementBase.prototype.GetLastRangeVisibleBounds = function()
{
	return {
		X        : 0,
		Y        : 0,
		W        : 0,
		H        : 0,
		BaseLine : 0,
		XLimit   : 0
	};
};
CDocumentContentElementBase.prototype.FindNextFillingForm = function(isNext, isCurrent, isStart)
{
	return null;
};
CDocumentContentElementBase.prototype.GetRevisionsChangeParagraph = function(SearchEngine)
{
	return null;
};
CDocumentContentElementBase.prototype.AcceptRevisionChanges = function(Type, bAll)
{
};
CDocumentContentElementBase.prototype.RejectRevisionChanges = function(Type, bAll)
{
};
CDocumentContentElementBase.prototype.GetDocumentPositionFromObject = function(PosArray)
{
	if (!PosArray)
		PosArray = [];

	if (this.Parent)
	{
		PosArray.splice(0, 0, {Class : this.Parent, Position : this.Get_Index()});
		this.Parent.GetDocumentPositionFromObject(PosArray);
	}

	return PosArray;
};
CDocumentContentElementBase.prototype.Get_Index = function()
{
	if (!this.Parent)
		return -1;

	this.Parent.Update_ContentIndexing();

	return this.Index;
};
CDocumentContentElementBase.prototype.GetOutlineParagraphs = function(arrOutline, oPr)
{
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с номерами страниц
//----------------------------------------------------------------------------------------------------------------------
CDocumentContentElementBase.prototype.Get_StartPage_Absolute = function()
{
	return this.Get_AbsolutePage(0);
};
CDocumentContentElementBase.prototype.Get_StartPage_Relative = function()
{
	return this.PageNum;
};
CDocumentContentElementBase.prototype.Get_StartColumn = function()
{
	return this.ColumnNum;
};
CDocumentContentElementBase.prototype.Get_ColumnsCount = function()
{
	return this.ColumnsCount;
};
CDocumentContentElementBase.prototype.private_GetRelativePageIndex = function(CurPage)
{
	if (!this.ColumnsCount || 0 === this.ColumnsCount)
		return this.PageNum + CurPage;

	return this.PageNum + ((this.ColumnNum + CurPage) / this.ColumnsCount | 0);
};
CDocumentContentElementBase.prototype.private_GetAbsolutePageIndex = function(CurPage)
{
	return this.Parent.Get_AbsolutePage(this.private_GetRelativePageIndex(CurPage));
};
CDocumentContentElementBase.prototype.Get_AbsolutePage = function(CurPage)
{
	return this.private_GetAbsolutePageIndex(CurPage);
};
CDocumentContentElementBase.prototype.Get_AbsoluteColumn = function(CurPage)
{
	if (this.Parent instanceof CDocument)
		return this.private_GetColumnIndex(CurPage);

	return this.Parent.Get_AbsoluteColumn(this.private_GetRelativePageIndex(CurPage));
};
CDocumentContentElementBase.prototype.private_GetColumnIndex = function(CurPage)
{
	return (this.ColumnNum + CurPage) - (((this.ColumnNum + CurPage) / this.ColumnsCount | 0) * this.ColumnsCount);
};
CDocumentContentElementBase.prototype.Get_CurrentPage_Absolute = function()
{
	return this.private_GetAbsolutePageIndex(0);
};
CDocumentContentElementBase.prototype.Get_CurrentPage_Relative = function()
{
	return this.private_GetRelativePageIndex(0);
};
CDocumentContentElementBase.prototype.GetAbsolutePage = function(CurPage)
{
	return this.private_GetAbsolutePageIndex(CurPage);
};
CDocumentContentElementBase.prototype.GetAbsoluteColumn = function(CurPage)
{
	return this.Get_AbsoluteColumn(CurPage);
};
//----------------------------------------------------------------------------------------------------------------------
CDocumentContentElementBase.prototype.GetPagesCount = function()
{
	return this.Get_PagesCount();
};
CDocumentContentElementBase.prototype.GetIndex = function()
{
	return this.Index;
};
CDocumentContentElementBase.prototype.GetPageBounds = function(CurPage)
{
	return this.Get_PageBounds(CurPage);
};
CDocumentContentElementBase.prototype.GetNearestPos = function(CurPage, X, Y, bAnchor, Drawing)
{
	return this.Get_NearestPos(CurPage, X, Y, bAnchor, Drawing);
};
CDocumentContentElementBase.prototype.CreateFontMap = function(oFontMap)
{
	return this.Document_CreateFontMap(oFontMap);
};
CDocumentContentElementBase.prototype.CreateFontCharMap = function(oFontCharMap)
{
	return this.Document_CreateFontCharMap(oFontCharMap);
};
CDocumentContentElementBase.prototype.GetAllFontNames = function(FontNames)
{
	return this.Document_Get_AllFontNames(FontNames);
};
CDocumentContentElementBase.prototype.GetSelectionState2 = function()
{
	return this.Get_SelectionState2();
};
CDocumentContentElementBase.prototype.SetSelectionState2 = function(State)
{
	return this.Set_SelectionState2(State);
};
CDocumentContentElementBase.prototype.SetReviewType = function(ReviewType)
{
	this.Set_ReviewType(ReviewType);
};
CDocumentContentElementBase.prototype.GetReviewType = function()
{
	return this.Get_ReviewType();
};
CDocumentContentElementBase.prototype.IsEmpty = function(oProps)
{
	return this.Is_Empty(oProps);
};
CDocumentContentElementBase.prototype.AddToParagraph = function(oItem)
{
	return this.Add(oItem);
};
CDocumentContentElementBase.prototype.GetAllDrawingObjects = function(AllDrawingObjects)
{
};
CDocumentContentElementBase.prototype.GetAllComments = function(AllComments)
{
};
CDocumentContentElementBase.prototype.GetAllMaths = function(AllMaths)
{
};
CDocumentContentElementBase.prototype.UpdateBookmarks = function(oManager)
{
};
/**
 * Получаем текущий TableOfContents, это может быть просто поле или поле вместе с оберткой Sdt
 * @param isUnique ищем с параметром Unique = true
 * @param isCheckFields Проверять ли TableOfContents, заданные через сложные поля
 * @returns {CComplexField | CBlockLevelSdt | null}
 */
CDocumentContentElementBase.prototype.GetTableOfContents = function(isUnique, isCheckFields)
{
	return null;
};
/**
 * Проверяем у родительского класса выделен ли только один элемент
 * @returns {boolean}
 */
CDocumentContentElementBase.prototype.IsSelectedSingleElement = function()
{
	if (this.Parent)
		return this.Parent.IsSelectedSingleElement();

	return false;
};
/**
 * Получаем последний параграф в данном контенте, если последний элемент не параграф, то запрашиваем у него
 * @returns {?Paragraph}
 */
CDocumentContentElementBase.prototype.GetLastParagraph = function()
{
	return null;
};
/**
 * Получаем первый параграф в данном контенте
 * @returns {?Paragraph}
 */
CDocumentContentElementBase.prototype.GetFirstParagraph = function()
{
	return this.Get_FirstParagraph();
};
/**
 * Получаем параграф, следующий за данным элементом
 * @returns {?Paragraph}
 */
CDocumentContentElementBase.prototype.GetNextParagraph = function()
{
	var oNextElement = this.Get_DocumentNext();

	if (oNextElement)
	{
		if (type_Paragraph === oNextElement.GetType())
			return oNextElement;
		else
			return oNextElement.GetFirstParagraph();
	}

	if (this.Parent && this.Parent.GetNextParagraph)
		return this.Parent.GetNextParagraph();

	return null;
};
/**
 * Получаем параграф, идущий перед данным элементом
 * @returns {?Paragraph}
 */
CDocumentContentElementBase.prototype.GetPrevParagraph = function()
{
	var oPrevElement = this.Get_DocumentPrev();

	if (oPrevElement)
	{
		if (type_Paragraph === oPrevElement.GetType())
			return oPrevElement;
		else
			return oPrevElement.GetLastParagraph();
	}

	if (this.Parent && this.Parent.GetPrevParagraph)
		return this.Parent.GetPrevParagraph();

	return null;
};
/**
 * Собираем список заголовков
 * @param {Paragraph[]} arrOutline
 * @param {object} oPr
 */
CDocumentContentElementBase.prototype.GetOutlineParagraphs = function(arrOutline, oPr)
{
};
/**
 * Вплоть до заданного параграфа ищем последнюю похожую нумерацию
 * @param oContinueEngine {CDocumentNumberingContinueEngine}
 * @returns {CNumPr | null}
 */
CDocumentContentElementBase.prototype.GetSimilarNumbering = function(oContinueEngine)
{
	return null;
};
/**
 * Переходим к следующей ссылке на сноску
 * @param isNext {boolean} - направление поиска
 * @param isCurrent {boolean} - ищем начиная с текущей позиции или с края элемента
 * @returns {boolean}
 */
CDocumentContentElementBase.prototype.GotoFootnoteRef = function(isNext, isCurrent)
{
	return false;
};
/**
 * Сообщаем, пересчитан ли данный элемент с момента внесения в него изменений
 * @param {boolean} isRecalculated
 */
CDocumentContentElementBase.prototype.SetIsRecalculated = function(isRecalculated)
{
	this.Recalculated = isRecalculated;
};
/**
 * Узнаем рассчитан ли данный параграф
 * @returns {boolean}
 */
CDocumentContentElementBase.prototype.IsRecalculated = function()
{
	return this.Recalculated;
};

//--------------------------------------------------------export--------------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CDocumentContentElementBase = CDocumentContentElementBase;
window['AscCommonWord'].type_Unknown = type_Unknown;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
function CParagraphContentBase()
{
	this.Type      = para_Unknown;
	this.Paragraph = null;

	this.StartLine  = -1;
	this.StartRange = -1;

	this.Lines       = [];
	this.LinesLength = 0;
}
CParagraphContentBase.prototype.GetType = function()
{
	return this.Type;
};
CParagraphContentBase.prototype.Get_Type = function()
{
	return this.Type;
};
CParagraphContentBase.prototype.CanSplit = function()
{
	return false;
};
CParagraphContentBase.prototype.IsParagraphContentElement = function()
{
	return true;
};
CParagraphContentBase.prototype.IsStopCursorOnEntryExit = function()
{
	return false;
};
CParagraphContentBase.prototype.PreDelete = function()
{
};
/**
 * Выствялем параграф, в котром лежит данный элемент
 * @param {Paragraph} oParagraph
 */
CParagraphContentBase.prototype.SetParagraph = function(oParagraph)
{
	this.Paragraph = oParagraph;
};
/**
 * Получаем параграф, в котором лежит данный элемент
 * @returns {null|Paragraph}
 */
CParagraphContentBase.prototype.GetParagraph = function()
{
	return this.Paragraph;
};
CParagraphContentBase.prototype.Is_Empty = function()
{
	return true;
};
CParagraphContentBase.prototype.IsEmpty = function()
{
	return this.Is_Empty();
};
CParagraphContentBase.prototype.Is_CheckingNearestPos = function()
{
	return false;
};
CParagraphContentBase.prototype.Get_CompiledTextPr = function()
{
	return null;
};
CParagraphContentBase.prototype.Clear_TextPr = function()
{

};
CParagraphContentBase.prototype.Remove = function()
{
	return false;
};
CParagraphContentBase.prototype.Get_DrawingObjectRun = function(Id)
{
	return null;
};
CParagraphContentBase.prototype.Get_DrawingObjectContentPos = function(Id, ContentPos, Depth)
{
	return false;
};
CParagraphContentBase.prototype.Get_Layout = function(DrawingLayout, UseContentPos, ContentPos, Depth)
{
};
/**
 * Ищем список элементов, идущих после заданной позициц
 * @param oRunElements {CParagraphRunElements}
 * @param isUseContentPos {boolean}
 * @param nDepth {number}
 */
CParagraphContentBase.prototype.GetNextRunElements = function(oRunElements, isUseContentPos, nDepth)
{
};
/**
 * Ищем список элементов рана, предществующих заданной позиции
 * @param oRunElements {CParagraphRunElements}
 * @param isUseContentPos {boolean}
 * @param nDepth {number}
 */
CParagraphContentBase.prototype.GetPrevRunElements = function(oRunElements, isUseContentPos, nDepth)
{
};
CParagraphContentBase.prototype.CollectDocumentStatistics = function(ParaStats)
{
};
CParagraphContentBase.prototype.Create_FontMap = function(Map)
{
};
CParagraphContentBase.prototype.Get_AllFontNames = function(AllFonts)
{
};
CParagraphContentBase.prototype.GetSelectedText = function(bAll, bClearText, oPr)
{
	return "";
};
CParagraphContentBase.prototype.Get_SelectionDirection = function()
{
	return 1;
};
CParagraphContentBase.prototype.Clear_TextFormatting = function( DefHyper )
{
};
CParagraphContentBase.prototype.Can_AddDropCap = function()
{
	return null;
};
CParagraphContentBase.prototype.Get_TextForDropCap = function(DropCapText, UseContentPos, ContentPos, Depth)
{
};
CParagraphContentBase.prototype.Get_StartTabsCount = function(TabsCounter)
{
	return true;
};
CParagraphContentBase.prototype.Remove_StartTabs = function(TabsCounter)
{
	return true;
};
CParagraphContentBase.prototype.Copy = function(Selected)
{
	return new this.constructor();
};
CParagraphContentBase.prototype.CopyContent = function(Selected)
{
	return [];
};
CParagraphContentBase.prototype.Split = function()
{
	return new ParaRun();
};
CParagraphContentBase.prototype.Get_Text = function(Text)
{
};
CParagraphContentBase.prototype.Apply_TextPr = function(oTextPr, isIncFontSize, isApplyToAll)
{
};
CParagraphContentBase.prototype.Get_ParaPosByContentPos = function(ContentPos, Depth)
{
	return new CParaPos(this.StartRange, this.StartLine, 0, 0);
};
CParagraphContentBase.prototype.UpdateBookmarks = function(oManager)
{
};
/**
 * @param oSpellCheckerEngine {CParagraphSpellCheckerEngine}
 * @param nDepth {number}
 */
CParagraphContentBase.prototype.CheckSpelling = function(oSpellCheckerEngine, nDepth)
{
};
CParagraphContentBase.prototype.GetParent = function()
{
	if (!this.Paragraph)
		return null;

	var oContentPos = this.Paragraph.Get_PosByElement(this);
	if (!oContentPos || oContentPos.Get_Depth() < 0)
		return null;

	oContentPos.Decrease_Depth(1);
	return this.Paragraph.Get_ElementByPos(oContentPos);
};
CParagraphContentBase.prototype.GetPosInParent = function(_oParent)
{
	var oParent = (_oParent? _oParent : this.GetParent());
	if (!oParent || !oParent.Content)
		return -1;

	for (var nPos = 0, nCount = oParent.Content.length; nPos < nCount; ++nPos)
	{
		if (this === oParent.Content[nPos])
			return nPos;
	}

	return -1;
};
CParagraphContentBase.prototype.RemoveTabsForTOC = function(isTab)
{
	return isTab;
};
/**
 * Ищем сложное поле заданного типа
 * @param nType
 * @returns {?CComplexField}
 */
CParagraphContentBase.prototype.GetComplexField = function(nType)
{
	return null;
};
/**
 * Ищем все сложные поля заданного типа
 * @param nType
 * @param arrComplexFields
 */
CParagraphContentBase.prototype.GetComplexFieldsArray = function(nType, arrComplexFields)
{
};
//----------------------------------------------------------------------------------------------------------------------
// Функции пересчета
//----------------------------------------------------------------------------------------------------------------------
CParagraphContentBase.prototype.Recalculate_Reset = function(StartRange, StartLine)
{
	this.StartLine   = StartLine;
	this.StartRange  = StartRange;
};
CParagraphContentBase.prototype.Recalculate_Range = function(PRS, ParaPr)
{
};
CParagraphContentBase.prototype.Recalculate_Set_RangeEndPos = function(PRS, PRP, Depth)
{
};
CParagraphContentBase.prototype.Recalculate_LineMetrics = function(PRS, ParaPr, _CurLine, _CurRange)
{
};
CParagraphContentBase.prototype.Recalculate_Range_Width = function(PRSC, _CurLine, _CurRange)
{
};
CParagraphContentBase.prototype.Recalculate_Range_Spaces = function(PRSA, CurLine, CurRange, CurPage)
{
};
CParagraphContentBase.prototype.Recalculate_PageEndInfo = function(PRSI, _CurLine, _CurRange)
{
};
CParagraphContentBase.prototype.SaveRecalculateObject = function(Copy)
{
	var RecalcObj = new CRunRecalculateObject(this.StartLine, this.StartRange);
	return RecalcObj;
};
CParagraphContentBase.prototype.LoadRecalculateObject = function(RecalcObj, Parent)
{
	this.StartLine  = RecalcObj.StartLine;
	this.StartRange = RecalcObj.StartRange;
};
CParagraphContentBase.prototype.PrepareRecalculateObject = function()
{
};
CParagraphContentBase.prototype.Is_EmptyRange = function(_CurLine, _CurRange)
{
	return true;
};
CParagraphContentBase.prototype.Check_Range_OnlyMath = function(Checker, CurRange, CurLine)
{
};
CParagraphContentBase.prototype.Check_MathPara = function(Checker)
{
};
CParagraphContentBase.prototype.Check_PageBreak = function()
{
	return false;
};
CParagraphContentBase.prototype.Check_BreakPageEnd = function(PBChecker)
{
	return true;
};
CParagraphContentBase.prototype.Recalculate_CurPos = function(X, Y, CurrentRun, _CurRange, _CurLine, CurPage, UpdateCurPos, UpdateTarget, ReturnTarget)
{
	return { X : X };
};
CParagraphContentBase.prototype.RecalculateMinMaxContentWidth = function(MinMax)
{
};
CParagraphContentBase.prototype.Get_Range_VisibleWidth = function(RangeW, _CurLine, _CurRange)
{
};
CParagraphContentBase.prototype.Shift_Range = function(Dx, Dy, _CurLine, _CurRange)
{
};
//----------------------------------------------------------------------------------------------------------------------
// Функции отрисовки
//----------------------------------------------------------------------------------------------------------------------
CParagraphContentBase.prototype.Draw_HighLights = function(PDSH)
{
};
CParagraphContentBase.prototype.Draw_Elements = function(PDSE)
{
};
CParagraphContentBase.prototype.Draw_Lines = function(PDSL)
{
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с курсором
//----------------------------------------------------------------------------------------------------------------------
CParagraphContentBase.prototype.Is_CursorPlaceable = function()
{
	return false;
};
CParagraphContentBase.prototype.IsCursorPlaceable = function()
{
	return this.Is_CursorPlaceable();
};
CParagraphContentBase.prototype.Cursor_Is_Start = function()
{
	return true;
};
CParagraphContentBase.prototype.Cursor_Is_NeededCorrectPos = function()
{
	return true;
};
CParagraphContentBase.prototype.Cursor_Is_End = function()
{
	return true;
};
CParagraphContentBase.prototype.MoveCursorToStartPos = function()
{
};
CParagraphContentBase.prototype.MoveCursorToEndPos = function(SelectFromEnd)
{
};
CParagraphContentBase.prototype.Get_ParaContentPosByXY = function(SearchPos, Depth, _CurLine, _CurRange, StepEnd)
{
	return false;
};
CParagraphContentBase.prototype.Get_ParaContentPos = function(bSelection, bStart, ContentPos, bUseCorrection)
{
};
CParagraphContentBase.prototype.Set_ParaContentPos = function(ContentPos, Depth)
{
};
CParagraphContentBase.prototype.Get_PosByElement = function(Class, ContentPos, Depth, UseRange, Range, Line)
{
	if (this === Class)
		return true;

	return false;
};
CParagraphContentBase.prototype.Get_ElementByPos = function(ContentPos, Depth)
{
	return this;
};
CParagraphContentBase.prototype.Get_ClassesByPos = function(Classes, ContentPos, Depth)
{
	Classes.push(this);
};
CParagraphContentBase.prototype.Get_PosByDrawing = function(Id, ContentPos, Depth)
{
	return false;
};
CParagraphContentBase.prototype.Get_RunElementByPos = function(ContentPos, Depth)
{
	return null;
};
CParagraphContentBase.prototype.Get_LastRunInRange = function(_CurLine, _CurRange)
{
	return null;
};
CParagraphContentBase.prototype.Get_LeftPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
};
CParagraphContentBase.prototype.Get_RightPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
};
CParagraphContentBase.prototype.Get_WordStartPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
};
CParagraphContentBase.prototype.Get_WordEndPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
};
CParagraphContentBase.prototype.Get_EndRangePos = function(_CurLine, _CurRange, SearchPos, Depth)
{
	return false;
};
CParagraphContentBase.prototype.Get_StartRangePos = function(_CurLine, _CurRange, SearchPos, Depth)
{
	return false;
};
CParagraphContentBase.prototype.Get_StartRangePos2 = function(_CurLine, _CurRange, ContentPos, Depth)
{
};
CParagraphContentBase.prototype.Get_EndRangePos2 = function(_CurLine, _CurRange, ContentPos, Depth)
{
};
CParagraphContentBase.prototype.Get_StartPos = function(ContentPos, Depth)
{
};
CParagraphContentBase.prototype.Get_EndPos = function(BehindEnd, ContentPos, Depth)
{
};
CParagraphContentBase.prototype.MoveCursorOutsideElement = function(isBefore)
{
	var oParent = this.GetParent();
	if (!oParent)
		return;

	var nPosInParent = this.GetPosInParent(oParent);

	if (isBefore)
	{
		if (nPosInParent <= 0)
		{
			if (this.SetThisElementCurrent)
				this.SetThisElementCurrent();

			this.MoveCursorToStartPos();
		}
		else
		{
			var oElement = oParent.GetElement(nPosInParent - 1);
			if (oElement.IsCursorPlaceable())
			{
				if (oElement.SetThisElementCurrent)
					oElement.SetThisElementCurrent();

				oElement.MoveCursorToEndPos();
			}
			else
			{
				if (this.SetThisElementCurrent)
					this.SetThisElementCurrent();

				this.MoveCursorToStartPos();
			}
		}
	}
	else
	{
		if (nPosInParent >= oParent.GetElementsCount() - 1)
		{
			if (this.SetThisElementCurrent)
				this.SetThisElementCurrent();

			this.MoveCursorToEndPos();
		}
		else
		{
			var oElement = oParent.GetElement(nPosInParent + 1);
			if (oElement.IsCursorPlaceable())
			{
				if (oElement.SetThisElementCurrent)
					oElement.SetThisElementCurrent();

				oElement.MoveCursorToStartPos();
			}
			else
			{
				if (this.SetThisElementCurrent)
					this.SetThisElementCurrent();

				this.MoveCursorToEndPos();
			}
		}
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с селектом
//----------------------------------------------------------------------------------------------------------------------
CParagraphContentBase.prototype.Set_SelectionContentPos = function(StartContentPos, EndContentPos, Depth, StartFlag, EndFlag)
{
};
CParagraphContentBase.prototype.RemoveSelection = function()
{
};
CParagraphContentBase.prototype.SelectAll = function(Direction)
{
};
CParagraphContentBase.prototype.Selection_DrawRange = function(_CurLine, _CurRange, SelectionDraw)
{
};
CParagraphContentBase.prototype.IsSelectionEmpty = function(CheckEnd)
{
	return true;
};
CParagraphContentBase.prototype.Selection_CheckParaEnd = function()
{
	return false;
};
CParagraphContentBase.prototype.IsSelectedAll = function(Props)
{
	return true;
};
CParagraphContentBase.prototype.Selection_CorrectLeftPos = function(Direction)
{
	return true;
};
CParagraphContentBase.prototype.Selection_CheckParaContentPos = function(ContentPos)
{
	return true;
};
//----------------------------------------------------------------------------------------------------------------------
CParagraphContentBase.prototype.Get_CurrentParaPos = function()
{
	return new CParaPos(this.StartRange, this.StartLine, 0, 0);
};
CParagraphContentBase.prototype.Get_TextPr = function(ContentPos, Depth)
{
	return new CTextPr();
};
CParagraphContentBase.prototype.Set_ReviewType = function(ReviewType, RemovePrChange)
{
};
CParagraphContentBase.prototype.Set_ReviewTypeWithInfo = function(ReviewType, ReviewInfo)
{
};
CParagraphContentBase.prototype.Check_RevisionsChanges = function(Checker, ContentPos, Depth)
{
};
CParagraphContentBase.prototype.AcceptRevisionChanges = function(Type, bAll)
{
};
CParagraphContentBase.prototype.RejectRevisionChanges = function(Type, bAll)
{
};
CParagraphContentBase.prototype.GetTextPr = function(ContentPos, Depth)
{
	return this.Get_TextPr(ContentPos, Depth);
};
CParagraphContentBase.prototype.ApplyTextPr = function(oTextPr, isIncFontSize, isApplyToAll)
{
	return this.Apply_TextPr(oTextPr, isIncFontSize, isApplyToAll);
};
/**
 * Функция для поиска внутри элементов параграфа
 * @param {CParagraphSearch} oParaSearch
 * @param {number} nDepth
 */
CParagraphContentBase.prototype.Search = function(oParaSearch, nDepth)
{
};
CParagraphContentBase.prototype.Add_SearchResult = function(SearchResult, Start, ContentPos, Depth)
{
};
CParagraphContentBase.prototype.Clear_SearchResults = function()
{
};
CParagraphContentBase.prototype.Remove_SearchResult = function(SearchResult)
{
};
CParagraphContentBase.prototype.Search_GetId = function(bNext, bUseContentPos, ContentPos, Depth)
{
	return null;
};
CParagraphContentBase.prototype.Check_NearestPos = function(ParaNearPos, Depth)
{
};
CParagraphContentBase.prototype.Restart_CheckSpelling = function()
{
};
CParagraphContentBase.prototype.GetDirectTextPr = function()
{
	return null;
};

/**
 * Это базовый класс для элементов содержимого(контент) параграфа, у которых есть свое содержимое.
 * @constructor
 * @extends {CParagraphContentBase}
 */
function CParagraphContentWithContentBase()
{
	CParagraphContentBase.call(this);
    
    // Массив Lines разделен на три части
    // 1. Состоит из одного элемента, означающего количество строк
    // 2. Количество элементов указывается в первой части, каждый элемент означает относительный сдвиг начала информации 
    //    о строке в 3 части (поэтому первый элемент всегда равен 0).    
    // 3. Сама информация о начале и конце отрезка в строке. Каждый отрезок представлен парой StartPos, EndPos.
    //
    // Пример. 2 строки, в первой строке 3 отрезка, во второй строке 1 отрезок
    // this.Lines = [2, 0, 6, 0, 15, 15, 17, 17, 20, 20, 25];

	this.Lines = [0];

    this.StartLine   = -1;
    this.StartRange  = -1;
}

CParagraphContentWithContentBase.prototype = Object.create(CParagraphContentBase.prototype);
CParagraphContentWithContentBase.prototype.constructor = CParagraphContentWithContentBase;

CParagraphContentWithContentBase.prototype.Recalculate_Reset = function(StartRange, StartLine)
{
    this.StartLine   = StartLine;
    this.StartRange  = StartRange;

    this.protected_ClearLines();
};

CParagraphContentWithContentBase.prototype.protected_ClearLines = function()
{
	this.Lines = [0];
};

CParagraphContentWithContentBase.prototype.protected_GetRangeOffset = function(LineIndex, RangeIndex)
{
    return (1 + this.Lines[0] + this.Lines[1 + LineIndex] + RangeIndex * 2);
};

CParagraphContentWithContentBase.prototype.protected_GetRangeStartPos = function(LineIndex, RangeIndex)
{
    return this.Lines[this.protected_GetRangeOffset(LineIndex, RangeIndex)];
};

CParagraphContentWithContentBase.prototype.protected_GetRangeEndPos = function(LineIndex, RangeIndex)
{
    return this.Lines[this.protected_GetRangeOffset(LineIndex, RangeIndex) + 1];
};

CParagraphContentWithContentBase.prototype.protected_GetLinesCount = function()
{
    return this.Lines[0];
};

CParagraphContentWithContentBase.prototype.protected_GetRangesCount = function(LineIndex)
{
    if (LineIndex === this.Lines[0] - 1)
        return (this.Lines.length - this.Lines[1 + LineIndex] - (this.Lines[0] + 1)) / 2;
    else
        return (this.Lines[1 + LineIndex + 1] - this.Lines[1 + LineIndex]) / 2;
};

// Здесь предполагается, что строки с номерами меньше, чем LineIndex заданы, а также заданы и отрезки в строке 
// LineIndex, с номерами меньшими, чем RangeIndex. В данной функции удаляются все записи, которые идут после LineIndex,
// RangeIndex. Т.е. удаляются все строки, с номерами больше, чем LineIndex, и в строке LineIndex удаляются все отрезки 
// с номерами больше, чем RangeIndex. Возвращается позиция предпоследнего отрезка, либо 0.
CParagraphContentWithContentBase.prototype.protected_AddRange = function(LineIndex, RangeIndex)
{
    // Удаляем лишние записи о строках и отрезках
    if (this.Lines[0] >= LineIndex + 1)
    {
        var RangeOffset = this.protected_GetRangeOffset(LineIndex, 0) + RangeIndex * 2;
        this.Lines.splice(RangeOffset, this.Lines.length - RangeOffset);

        if (this.Lines[0] !== LineIndex + 1 && 0 === RangeIndex)
            this.Lines.splice(LineIndex + 1, this.Lines[0] - LineIndex);
        else if (this.Lines[0] !== LineIndex + 1 && 0 !== RangeIndex)
        {
            this.Lines.splice(LineIndex + 2, this.Lines[0] - LineIndex - 1);
            this.Lines[0] = LineIndex + 1;
        }
    }

    if (0 === RangeIndex)
    {
        if (this.Lines[0] !== LineIndex + 1)
        {
            // Добавляем информацию о новой строке, сначала ее относительный сдвиг, потом меняем само количество строк
            var OffsetValue = this.Lines.length - LineIndex - 1;
            this.Lines.splice(LineIndex + 1, 0, OffsetValue);
            this.Lines[0] = LineIndex + 1;
        }
    }
    
    var RangeOffset = 1 + this.Lines[0] + this.Lines[LineIndex + 1] + RangeIndex * 2; // this.protected_GetRangeOffset(LineIndex, RangeIndex);
    
    // Резервируем место для StartPos и EndPos заданного отрезка
    this.Lines[RangeOffset + 0] = 0;
    this.Lines[RangeOffset + 1] = 0;    
    
    if (0 !== LineIndex || 0 !== RangeIndex)
        return this.Lines[RangeOffset - 1];
    else
        return 0;
};

// Заполняем добавленный отрезок значениями
CParagraphContentWithContentBase.prototype.protected_FillRange = function(LineIndex, RangeIndex, StartPos, EndPos)
{
    var RangeOffset = this.protected_GetRangeOffset(LineIndex, RangeIndex);
    this.Lines[RangeOffset + 0] = StartPos;
    this.Lines[RangeOffset + 1] = EndPos;
};
CParagraphContentWithContentBase.prototype.protected_FillRangeEndPos = function(LineIndex, RangeIndex, EndPos)
{
    var RangeOffset = this.protected_GetRangeOffset(LineIndex, RangeIndex);
    this.Lines[RangeOffset + 1] = EndPos;
};
CParagraphContentWithContentBase.prototype.private_UpdateSpellChecking = function()
{
	if (this.Paragraph)
	{
		this.Paragraph.SpellChecker.ClearPausedEngine();
		this.Paragraph.RecalcInfo.Set_Type_0_Spell(pararecalc_0_Spell_All);
	}
};
CParagraphContentWithContentBase.prototype.Is_UseInDocument = function(Id)
{
    if(this.Paragraph)
    {
        for(var i = 0; i < this.Content.length; ++i)
        {
            if(this.Content[i].Get_Id && this.Content[i].Get_Id() === Id)
            {
                break;
            }
        }
        if(i < this.Content.length)
        {
            return this.Paragraph.Is_UseInDocument(this.Get_Id());
        }
    }
    return false;
};
CParagraphContentWithContentBase.prototype.protected_GetPrevRangeEndPos = function(LineIndex, RangeIndex)
{
    var RangeCount  = this.protected_GetRangesCount(LineIndex - 1);
    var RangeOffset = this.protected_GetRangeOffset(LineIndex - 1, RangeCount - 1);

    return LineIndex == 0 && RangeIndex == 0 ? 0 : this.Lines[RangeOffset + 1];
};
CParagraphContentWithContentBase.prototype.private_UpdateTrackRevisions = function()
{
    if (this.Paragraph && this.Paragraph.LogicDocument && this.Paragraph.LogicDocument.Get_TrackRevisionsManager)
    {
        var RevisionsManager = this.Paragraph.LogicDocument.Get_TrackRevisionsManager();
        RevisionsManager.Check_Paragraph(this.Paragraph);
    }
};
CParagraphContentWithContentBase.prototype.CanSplit = function()
{
	return true;
};
CParagraphContentWithContentBase.prototype.PreDelete = function()
{
};
CParagraphContentWithContentBase.prototype.private_UpdateDocumentOutline = function()
{
	if (this.Paragraph)
		this.Paragraph.UpdateDocumentOutline();
};
/**
 * Это базовый класс для элементов параграфа, которые сами по себе могут содержать элементы параграфа.
 * @constructor
 * @extends {CParagraphContentWithContentBase}
 */
function CParagraphContentWithParagraphLikeContent()
{
	CParagraphContentWithContentBase.call(this);

    this.Type              = undefined;
    this.Paragraph         = null;                  // Ссылка на родительский класс параграф.
    this.m_oContentChanges = new AscCommon.CContentChanges(); // Список изменений(добавление/удаление элементов)
    this.Content           = [];                    // Содержимое данного элемента.

    this.State             = new CParaRunState();   // Состояние курсора/селекта.
    this.Selection         = this.State.Selection;  // Для более быстрого и более простого обращения к селекту.

    this.NearPosArray      = [];
    this.SearchMarks       = [];
}

CParagraphContentWithParagraphLikeContent.prototype = Object.create(CParagraphContentWithContentBase.prototype);
CParagraphContentWithParagraphLikeContent.prototype.constructor = CParagraphContentWithParagraphLikeContent;

CParagraphContentWithParagraphLikeContent.prototype.Get_Type = function()
{
    return this.Type;
};
CParagraphContentWithParagraphLikeContent.prototype.Copy = function(Selected, oPr)
{
    var NewElement = new this.constructor();

    var StartPos = 0;
    var EndPos   = this.Content.length - 1;

    if ( true === Selected && true === this.State.Selection.Use )
    {
        StartPos = this.State.Selection.StartPos;
        EndPos   = this.State.Selection.EndPos;

        if ( StartPos > EndPos )
        {
            StartPos = this.State.Selection.EndPos;
            EndPos   = this.State.Selection.StartPos;
        }
    }

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        var Item = this.Content[CurPos];

        if ( StartPos === CurPos || EndPos === CurPos )
            NewElement.Add_ToContent( CurPos - StartPos, Item.Copy(Selected, oPr) );
        else
            NewElement.Add_ToContent( CurPos - StartPos, Item.Copy(false, oPr) );
    }

    return NewElement;
};
CParagraphContentWithParagraphLikeContent.prototype.CopyContent = function(Selected)
{
    var CopyContent = [];

    var StartPos = 0;
    var EndPos = this.Content.length - 1;

    if (true === Selected && true === this.State.Selection.Use)
    {
        StartPos = this.State.Selection.StartPos;
        EndPos   = this.State.Selection.EndPos;
        if (StartPos > EndPos)
        {
            StartPos = this.State.Selection.EndPos;
            EndPos   = this.State.Selection.StartPos;
        }
    }

    for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
    {
        var Item = this.Content[CurPos];

        if ((StartPos === CurPos || EndPos === CurPos) && true !== Item.IsSelectedAll())
        {
            var Content = Item.CopyContent(Selected);
            for (var ContentPos = 0, ContentLen = Content.length; ContentPos < ContentLen; ContentPos++)
            {
                CopyContent.push(Content[ContentPos]);
            }
        }
        else
        {
            CopyContent.push(Item.Copy(false));
        }
    }

    return CopyContent;
};
CParagraphContentWithParagraphLikeContent.prototype.Clear_ContentChanges = function()
{
    this.m_oContentChanges.Clear();
};
CParagraphContentWithParagraphLikeContent.prototype.Add_ContentChanges = function(Changes)
{
    this.m_oContentChanges.Add( Changes );
};
CParagraphContentWithParagraphLikeContent.prototype.Refresh_ContentChanges = function()
{
    this.m_oContentChanges.Refresh();
};
CParagraphContentWithParagraphLikeContent.prototype.Recalc_RunsCompiledPr = function()
{
    var Count = this.Content.length;
    for (var Pos = 0; Pos < Count; Pos++)
    {
        var Item = this.Content[Pos];

        if (Item.Recalc_RunsCompiledPr)
            Item.Recalc_RunsCompiledPr();
    }
};
CParagraphContentWithParagraphLikeContent.prototype.GetAllDrawingObjects = function(DrawingObjs)
{
    var Count = this.Content.length;
    for (var Index = 0; Index < Count; Index++)
    {
        var Item = this.Content[Index];

        if (Item.GetAllDrawingObjects)
            Item.GetAllDrawingObjects(DrawingObjs);
    }
};
CParagraphContentWithParagraphLikeContent.prototype.SetParagraph = function(Paragraph)
{
	this.Paragraph = Paragraph;

	var ContentLen = this.Content.length;
	for (var CurPos = 0; CurPos < ContentLen; CurPos++)
	{
		this.Content[CurPos].SetParagraph(Paragraph);
	}
};
CParagraphContentWithParagraphLikeContent.prototype.Is_Empty = function()
{
    for (var Index = 0, ContentLen = this.Content.length; Index < ContentLen; Index++)
    {
        if (false === this.Content[Index].Is_Empty())
            return false;
    }

    return true;
};
CParagraphContentWithParagraphLikeContent.prototype.Is_CheckingNearestPos = function()
{
    if (this.NearPosArray.length > 0)
        return true;

    return false;
};
CParagraphContentWithParagraphLikeContent.prototype.Is_StartFromNewLine = function()
{
    if (this.Content.length < 0)
        return false;

    return this.Content[0].Is_StartFromNewLine();
};
CParagraphContentWithParagraphLikeContent.prototype.GetSelectedElementsInfo = function(Info, ContentPos, Depth)
{
	var Selection = this.Selection;

	if (ContentPos)
	{
		var Pos = ContentPos.Get(Depth);
		if (this.Content[Pos].GetSelectedElementsInfo)
			this.Content[Pos].GetSelectedElementsInfo(Info, ContentPos, Depth + 1);
	}
	else
	{
		if (true === Selection.Use && Selection.StartPos === Selection.EndPos && this.Content[Selection.EndPos].GetSelectedElementsInfo)
			this.Content[Selection.EndPos].GetSelectedElementsInfo(Info);
		else if (false === Selection.Use && this.Content[this.State.ContentPos].GetSelectedElementsInfo)
			this.Content[this.State.ContentPos].GetSelectedElementsInfo(Info);
	}
};
CParagraphContentWithParagraphLikeContent.prototype.GetSelectedText = function(bAll, bClearText, oPr)
{
    var Str = "";
    for (var Pos = 0, Count = this.Content.length; Pos < Count; Pos++)
    {
        var _Str = this.Content[Pos].GetSelectedText(bAll, bClearText, oPr);

        if (null === _Str)
            return null;

        Str += _Str;
    }

    return Str;
};
CParagraphContentWithParagraphLikeContent.prototype.Get_SelectionDirection = function()
{
    if (true !== this.Selection.Use)
        return 0;

    if (this.Selection.StartPos < this.Selection.EndPos)
        return 1;
    else if (this.Selection.StartPos > this.Selection.EndPos)
        return -1;

    return this.Content[this.Selection.StartPos].Get_SelectionDirection();
};
CParagraphContentWithParagraphLikeContent.prototype.Get_TextPr = function(_ContentPos, Depth)
{
    if ( undefined === _ContentPos )
        return this.Content[0].Get_TextPr();
    else
        return this.Content[_ContentPos.Get(Depth)].Get_TextPr(_ContentPos, Depth + 1);
};
CParagraphContentWithParagraphLikeContent.prototype.Get_FirstTextPr = function(bByPos)
{
    var oElement = null;
    if (this.Content.length > 0)
    {
        if (true === bByPos)
        {
            if (true === this.Selection.Use)
            {
                if (this.Selection.StartPos > this.Selection.EndPos)
                    oElement = this.Content[this.Selection.EndPos];
                else
                    oElement = this.Content[this.Selection.StartPos];
            }
            else
                oElement = this.Content[this.State.ContentPos];
        }
        else
        {
            oElement = this.Content[0];
        }
    }

    if (null !== oElement && undefined !== oElement)
    {
        if (para_Run === this.Content[0].Type)
            return this.Content[0].Get_TextPr();
        else
            return this.Content[0].Get_FirstTextPr();
    }
    else
        return new CTextPr();
};
CParagraphContentWithParagraphLikeContent.prototype.Get_CompiledTextPr = function(Copy)
{
    var TextPr = null;

    if (true === this.State.Selection)
    {
        var StartPos = this.State.Selection.StartPos;
        var EndPos   = this.State.Selection.EndPos;

        if (StartPos > EndPos)
        {
            StartPos = this.State.Selection.EndPos;
            EndPos   = this.State.Selection.StartPos;
        }

        TextPr = this.Content[StartPos].Get_CompiledTextPr(Copy);

        while (null === TextPr && StartPos < EndPos)
        {
            StartPos++;
            TextPr = this.Content[StartPos].Get_CompiledTextPr(Copy);
        }

        for (var CurPos = StartPos + 1; CurPos <= EndPos; CurPos++)
        {
            var CurTextPr = this.Content[CurPos].Get_CompiledPr(false);

            if (null !== CurTextPr)
                TextPr = TextPr.Compare(CurTextPr);
        }
    }
    else
    {
        var CurPos = this.State.ContentPos;

        if (CurPos >= 0 && CurPos < this.Content.length)
            TextPr = this.Content[CurPos].Get_CompiledTextPr(Copy);
    }

    return TextPr;
};
CParagraphContentWithParagraphLikeContent.prototype.Check_Content = function()
{
    // Данная функция запускается при чтении файла. Заглушка, на случай, когда в данном классе ничего не будет
    if (this.Content.length <= 0)
        this.Add_ToContent(0, new ParaRun(), false);
};
CParagraphContentWithParagraphLikeContent.prototype.Add_ToContent = function(Pos, Item, UpdatePosition)
{
    this.Content.splice(Pos, 0, Item);
    this.private_UpdateTrackRevisions();
	this.private_UpdateDocumentOutline();
    this.private_CheckUpdateBookmarks([Item]);

    if (false !== UpdatePosition)
    {
        // Обновляем текущую позицию
        if (this.State.ContentPos >= Pos)
            this.State.ContentPos++;

        // Обновляем начало и конец селекта
        if (true === this.State.Selection.Use)
        {
            if (this.State.Selection.StartPos >= Pos)
                this.State.Selection.StartPos++;

            if (this.State.Selection.EndPos >= Pos)
                this.State.Selection.EndPos++;
        }

        // Также передвинем всем метки переносов страниц и строк
        var LinesCount = this.protected_GetLinesCount();
        for (var CurLine = 0; CurLine < LinesCount; CurLine++)
        {
            var RangesCount = this.protected_GetRangesCount(CurLine);
            for (var CurRange = 0; CurRange < RangesCount; CurRange++)
            {
                var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
                var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

                if (StartPos > Pos)
                    StartPos++;

                if (EndPos > Pos)
                    EndPos++;

                this.protected_FillRange(CurLine, CurRange, StartPos, EndPos);
            }

            // Особый случай, когда мы добавляем элемент в самый последний ран
            if (Pos === this.Content.length - 1 && LinesCount - 1 === CurLine)
            {
                this.protected_FillRangeEndPos(CurLine, RangesCount - 1, this.protected_GetRangeEndPos(CurLine, RangesCount - 1) + 1);
            }
        }
    }

    // Обновляем позиции в NearestPos
    var NearPosLen = this.NearPosArray.length;
    for (var Index = 0; Index < NearPosLen; Index++)
    {
        var HyperNearPos = this.NearPosArray[Index];
        var ContentPos = HyperNearPos.NearPos.ContentPos;
        var Depth      = HyperNearPos.Depth;

        if (ContentPos.Data[Depth] >= Pos)
            ContentPos.Data[Depth]++;
    }

    // Обновляем позиции в поиске
    var SearchMarksCount = this.SearchMarks.length;
    for (var Index = 0; Index < SearchMarksCount; Index++)
    {
        var Mark       = this.SearchMarks[Index];
        var ContentPos = (true === Mark.Start ? Mark.SearchResult.StartPos : Mark.SearchResult.EndPos);
        var Depth      = Mark.Depth;

        if (ContentPos.Data[Depth] >= Pos)
            ContentPos.Data[Depth]++;
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Remove_FromContent = function(Pos, Count, UpdatePosition)
{
	for (var nIndex = Pos; nIndex < Pos + Count; ++nIndex)
	{
		this.Content[nIndex].PreDelete();
	}

	var DeletedItems = this.Content.slice(Pos, Pos + Count);
	this.Content.splice(Pos, Count);
    this.private_UpdateTrackRevisions();
	this.private_UpdateDocumentOutline();
	this.private_CheckUpdateBookmarks(DeletedItems);

    if (false !== UpdatePosition)
    {
        // Обновим текущую позицию
        if (this.State.ContentPos > Pos + Count)
            this.State.ContentPos -= Count;
        else if (this.State.ContentPos > Pos)
            this.State.ContentPos = Pos;

        // Обновим начало и конец селекта
        if (true === this.State.Selection.Use)
        {
            if (this.State.Selection.StartPos <= this.State.Selection.EndPos)
            {
                if (this.State.Selection.StartPos > Pos + Count)
                    this.State.Selection.StartPos -= Count;
                else if (this.State.Selection.StartPos > Pos)
                    this.State.Selection.StartPos = Pos;

                if (this.State.Selection.EndPos >= Pos + Count)
                    this.State.Selection.EndPos -= Count;
                else if (this.State.Selection.EndPos >= Pos)
                    this.State.Selection.EndPos = Math.max(0, Pos - 1);
            }
            else
            {
                if (this.State.Selection.StartPos >= Pos + Count)
                    this.State.Selection.StartPos -= Count;
                else if (this.State.Selection.StartPos >= Pos)
                    this.State.Selection.StartPos = Math.max(0, Pos - 1);

                if (this.State.Selection.EndPos > Pos + Count)
                    this.State.Selection.EndPos -= Count;
                else if (this.State.Selection.EndPos > Pos)
                    this.State.Selection.EndPos = Pos;
            }

            this.Selection.StartPos = Math.max(0, Math.min(this.Content.length - 1, this.Selection.StartPos));
            this.Selection.EndPos   = Math.max(0, Math.min(this.Content.length - 1, this.Selection.EndPos));
        }

        // Также передвинем всем метки переносов страниц и строк
        var LinesCount = this.protected_GetLinesCount();
        for (var CurLine = 0; CurLine < LinesCount; CurLine++)
        {
            var RangesCount = this.protected_GetRangesCount(CurLine);
            for (var CurRange = 0; CurRange < RangesCount; CurRange++)
            {
                var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
                var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

                if (StartPos > Pos + Count)
                    StartPos -= Count;
                else if (StartPos > Pos)
                    StartPos = Math.max(0, Pos);

                if (EndPos >= Pos + Count)
                    EndPos -= Count;
                else if (EndPos >= Pos)
                    EndPos = Math.max(0, Pos);

                this.protected_FillRange(CurLine, CurRange, StartPos, EndPos);
            }
        }
    }

    // Обновляем позиции в NearestPos
    var NearPosLen = this.NearPosArray.length;
    for (var Index = 0; Index < NearPosLen; Index++)
    {
        var HyperNearPos = this.NearPosArray[Index];
        var ContentPos = HyperNearPos.NearPos.ContentPos;
        var Depth      = HyperNearPos.Depth;

        if (ContentPos.Data[Depth] > Pos + Count)
            ContentPos.Data[Depth] -= Count;
        else if (ContentPos.Data[Depth] > Pos)
            ContentPos.Data[Depth] = Math.max(0, Pos);
    }

    // Обновляем позиции в поиске
    var SearchMarksCount = this.SearchMarks.length;
    for (var Index = 0; Index < SearchMarksCount; Index++)
    {
        var Mark       = this.SearchMarks[Index];
        var ContentPos = (true === Mark.Start ? Mark.SearchResult.StartPos : Mark.SearchResult.EndPos);
        var Depth      = Mark.Depth;

        if (ContentPos.Data[Depth] > Pos + Count)
            ContentPos.Data[Depth] -= Count;
        else if (ContentPos.Data[Depth] > Pos)
            ContentPos.Data[Depth] = Math.max(0, Pos);
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Remove = function(Direction, bOnAddText)
{
    var Selection = this.State.Selection;

    if (true === Selection.Use)
    {
        var StartPos = Selection.StartPos;
        var EndPos   = Selection.EndPos;

        if (StartPos > EndPos)
        {
            StartPos = Selection.EndPos;
            EndPos   = Selection.StartPos;
        }

        if (StartPos === EndPos)
        {
            this.Content[StartPos].Remove(Direction, bOnAddText);

            if (StartPos !== this.Content.length - 1 && true === this.Content[StartPos].Is_Empty() && true !== bOnAddText)
            {
                this.Remove_FromContent( StartPos, 1, true );
            }
        }
        else
        {
            this.Content[EndPos].Remove(Direction, bOnAddText);

            if (EndPos !== this.Content.length - 1 && true === this.Content[EndPos].Is_Empty() && true !== bOnAddText)
            {
                this.Remove_FromContent(EndPos, 1, true);
            }

            if (this.Paragraph && this.Paragraph.LogicDocument && true === this.Paragraph.LogicDocument.Is_TrackRevisions())
            {
                for (var CurPos = EndPos - 1; CurPos > StartPos; CurPos--)
                {
                    this.Content[CurPos].Set_ReviewType(reviewtype_Remove, false);
                }
            }
            else
            {
                for (var CurPos = EndPos - 1; CurPos > StartPos; CurPos--)
                {
                    this.Remove_FromContent(CurPos, 1, true);
                }
            }

            this.Content[StartPos].Remove(Direction, bOnAddText);

            if (true === this.Content[StartPos].Is_Empty())
                this.Remove_FromContent(StartPos, 1, true);
        }

        this.RemoveSelection();
        this.State.ContentPos = StartPos;
    }
    else
    {
        var ContentPos = this.State.ContentPos;

        if (true === this.Cursor_Is_Start() || true === this.Cursor_Is_End())
        {
            this.SelectAll();
            this.SelectThisElement(1);
        }
        else
        {
            while (false === this.Content[ContentPos].Remove(Direction, bOnAddText))
            {
                if (Direction < 0)
                    ContentPos--;
                else
                    ContentPos++;

                if (ContentPos < 0 || ContentPos >= this.Content.length)
                    break;

                if (Direction < 0)
                    this.Content[ContentPos].MoveCursorToEndPos(false);
                else
                    this.Content[ContentPos].MoveCursorToStartPos();

            }

            if (ContentPos < 0 || ContentPos >= this.Content.length)
                return false;
            else
            {
                if (ContentPos !== this.Content.length - 1 && true === this.Content[ContentPos].Is_Empty() && true !== bOnAddText)
                    this.Remove_FromContent(ContentPos, 1, true);

                this.State.ContentPos = ContentPos;
            }
        }
    }

    return true;
};
CParagraphContentWithParagraphLikeContent.prototype.Get_CurrentParaPos = function()
{
    var CurPos = this.State.ContentPos;

    if (CurPos >= 0 && CurPos < this.Content.length)
        return this.Content[CurPos].Get_CurrentParaPos();

    return new CParaPos(this.StartRange, this.StartLine, 0, 0);
};
CParagraphContentWithParagraphLikeContent.prototype.Apply_TextPr = function(TextPr, IncFontSize, ApplyToAll)
{
    if ( true === ApplyToAll )
    {
        var ContentLen = this.Content.length;
        for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
        {
            this.Content[CurPos].Apply_TextPr( TextPr, IncFontSize, true );
        }
    }
    else
    {
        var Selection = this.State.Selection;

        if ( true === Selection.Use )
        {
            var StartPos = Selection.StartPos;
            var EndPos   = Selection.EndPos;

            if ( StartPos === EndPos )
            {
                var NewElements = this.Content[EndPos].Apply_TextPr( TextPr, IncFontSize, false );

                if ( para_Run === this.Content[EndPos].Type )
                {
                    var CenterRunPos = this.private_ReplaceRun( EndPos, NewElements );

                    if ( StartPos === this.State.ContentPos )
                        this.State.ContentPos = CenterRunPos;

                    // Подправим метки селекта
                    Selection.StartPos = CenterRunPos;
                    Selection.EndPos   = CenterRunPos;
                }
            }
            else
            {
                var Direction = 1;
                if ( StartPos > EndPos )
                {
                    var Temp = StartPos;
                    StartPos = EndPos;
                    EndPos = Temp;

                    Direction = -1;
                }

                for ( var CurPos = StartPos + 1; CurPos < EndPos; CurPos++ )
                {
                    this.Content[CurPos].Apply_TextPr( TextPr, IncFontSize, false );
                }


                var NewElements = this.Content[EndPos].Apply_TextPr( TextPr, IncFontSize, false );
                if ( para_Run === this.Content[EndPos].Type )
                    this.private_ReplaceRun( EndPos, NewElements );

                var NewElements = this.Content[StartPos].Apply_TextPr( TextPr, IncFontSize, false );
                if ( para_Run === this.Content[StartPos].Type )
                    this.private_ReplaceRun( StartPos, NewElements );

                // Подправим селект. Заметим, что метки выделения изменяются внутри функции Add_ToContent
                // за счет того, что EndPos - StartPos > 1.
                if ( Selection.StartPos < Selection.EndPos && true === this.Content[Selection.StartPos].IsSelectionEmpty() )
                    Selection.StartPos++;
                else if ( Selection.EndPos < Selection.StartPos && true === this.Content[Selection.EndPos].IsSelectionEmpty() )
                    Selection.EndPos++;

                if ( Selection.StartPos < Selection.EndPos && true === this.Content[Selection.EndPos].IsSelectionEmpty() )
                    Selection.EndPos--;
                else if ( Selection.EndPos < Selection.StartPos && true === this.Content[Selection.StartPos].IsSelectionEmpty() )
                    Selection.StartPos--;
            }
        }
        else
        {
            var Pos = this.State.ContentPos;
            var Element = this.Content[Pos];
            var NewElements = Element.Apply_TextPr( TextPr, IncFontSize, false );

            if ( para_Run === Element.Type )
            {
                var CenterRunPos = this.private_ReplaceRun( Pos, NewElements );
                this.State.ContentPos = CenterRunPos;
            }
        }
    }
};
CParagraphContentWithParagraphLikeContent.prototype.private_ReplaceRun = function(Pos, NewRuns)
{
    // По логике, можно удалить Run, стоящий в позиции Pos и добавить все раны, которые не null в массиве NewRuns.
    // Но, согласно работе ParaRun.Apply_TextPr, в массиве всегда идет ровно 3 рана (возможно null). Второй ран
    // всегда не null. Первый не null ран и есть ран, идущий в позиции Pos.

    var LRun = NewRuns[0];
    var CRun = NewRuns[1];
    var RRun = NewRuns[2];

    // CRun - всегда не null
    var CenterRunPos = Pos;

    if (null !== LRun)
    {
        this.Add_ToContent(Pos + 1, CRun, true);
        CenterRunPos = Pos + 1;
    }
    else
    {
        // Если LRun - null, значит CRun - это и есть тот ран который стоит уже в позиции Pos
    }

    if (null !== RRun)
        this.Add_ToContent(CenterRunPos + 1, RRun, true);

    return CenterRunPos;
};
CParagraphContentWithParagraphLikeContent.prototype.Clear_TextPr = function()
{
    var Count = this.Content.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        var Item = this.Content[Index];
        Item.Clear_TextPr();
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Check_NearestPos = function(ParaNearPos, Depth)
{
    var HyperNearPos = new CParagraphElementNearPos();
    HyperNearPos.NearPos = ParaNearPos.NearPos;
    HyperNearPos.Depth   = Depth;

    this.NearPosArray.push(HyperNearPos);
    ParaNearPos.Classes.push(this);

    var CurPos = ParaNearPos.NearPos.ContentPos.Get(Depth);
    this.Content[CurPos].Check_NearestPos(ParaNearPos, Depth + 1);
};
CParagraphContentWithParagraphLikeContent.prototype.Get_DrawingObjectRun = function(Id)
{
    var Run = null;

    var ContentLen = this.Content.length;
    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        var Element = this.Content[CurPos];
        Run = Element.Get_DrawingObjectRun( Id );
        if (null !== Run)
            return Run;
    }

    return Run;
};
CParagraphContentWithParagraphLikeContent.prototype.Get_DrawingObjectContentPos = function(Id, ContentPos, Depth)
{
    for (var Index = 0, ContentLen = this.Content.length; Index < ContentLen; Index++)
    {
        var Element = this.Content[Index];

        if (true === Element.Get_DrawingObjectContentPos(Id, ContentPos, Depth + 1))
        {
            ContentPos.Update2(Index, Depth);
            return true;
        }
    }

    return false;
};
CParagraphContentWithParagraphLikeContent.prototype.Get_Layout = function(DrawingLayout, UseContentPos, ContentPos, Depth)
{
    var CurLine  = DrawingLayout.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? DrawingLayout.Range - this.StartRange : DrawingLayout.Range );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var CurContentPos = ( true === UseContentPos ? ContentPos.Get(Depth) : -1 );

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        this.Content[CurPos].Get_Layout(DrawingLayout, ( CurPos === CurContentPos ? true : false ), ContentPos, Depth + 1 );

        if (true === DrawingLayout.Layout)
            return;
    }
};
CParagraphContentWithParagraphLikeContent.prototype.GetNextRunElements = function(oRunElements, isUseContentPos, nDepth)
{
	if (oRunElements.IsEnoughElements())
		return;

	var nCurPos     = true === isUseContentPos ? oRunElements.ContentPos.Get(nDepth) : 0;
	var nContentLen = this.Content.length;

	oRunElements.UpdatePos(nCurPos, nDepth);
	this.Content[nCurPos].GetNextRunElements(oRunElements, isUseContentPos, nDepth + 1);

	nCurPos++;

	while (nCurPos < nContentLen)
	{
		if (oRunElements.IsEnoughElements())
			return;

		oRunElements.UpdatePos(nCurPos, nDepth);
		this.Content[nCurPos].GetNextRunElements(oRunElements, false, nDepth + 1);

		nCurPos++;
	}
};
CParagraphContentWithParagraphLikeContent.prototype.GetPrevRunElements = function(oRunElements, isUseContentPos, nDepth)
{
	if (oRunElements.IsEnoughElements())
		return;

	var nCurPos = true === isUseContentPos ? oRunElements.ContentPos.Get(nDepth) : this.Content.length - 1;

	oRunElements.UpdatePos(nCurPos, nDepth);
	this.Content[nCurPos].GetPrevRunElements(oRunElements, isUseContentPos, nDepth + 1);

	nCurPos--;

	while (nCurPos >= 0)
	{
		if (oRunElements.IsEnoughElements())
			return;

		oRunElements.UpdatePos(nCurPos, nDepth);
		this.Content[nCurPos].GetPrevRunElements(oRunElements, false, nDepth + 1);

		nCurPos--;
	}
};
CParagraphContentWithParagraphLikeContent.prototype.CollectDocumentStatistics = function(ParaStats)
{
	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
		this.Content[Index].CollectDocumentStatistics(ParaStats);
};
CParagraphContentWithParagraphLikeContent.prototype.Create_FontMap = function(Map)
{
    var Count = this.Content.length;
    for (var Index = 0; Index < Count; Index++)
        this.Content[Index].Create_FontMap( Map );
};
CParagraphContentWithParagraphLikeContent.prototype.Get_AllFontNames = function(AllFonts)
{
    var Count = this.Content.length;
    for (var Index = 0; Index < Count; Index++)
        this.Content[Index].Get_AllFontNames( AllFonts );
};
CParagraphContentWithParagraphLikeContent.prototype.Clear_TextFormatting = function()
{
    for (var Pos = 0, Count = this.Content.length; Pos < Count; Pos++)
    {
        var Item = this.Content[Pos];
        Item.Clear_TextFormatting();
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Can_AddDropCap = function()
{
    for (var Pos = 0, Count = this.Content.length; Pos < Count; Pos++)
    {
        var ItemResult = this.Content[Pos].Can_AddDropCap();

        if (null !== ItemResult)
            return ItemResult;
    }

    return null;
};
CParagraphContentWithParagraphLikeContent.prototype.Get_TextForDropCap = function(DropCapText, UseContentPos, ContentPos, Depth)
{
    var EndPos = ( true === UseContentPos ? ContentPos.Get(Depth) : this.Content.length - 1 );

    for ( var Pos = 0; Pos <= EndPos; Pos++ )
    {
        this.Content[Pos].Get_TextForDropCap( DropCapText, (true === UseContentPos && Pos === EndPos ? true : false), ContentPos, Depth + 1 );

        if ( true === DropCapText.Mixed && ( true === DropCapText.Check || DropCapText.Runs.length > 0 ) )
            return;
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Get_StartTabsCount = function(TabsCounter)
{
    var ContentLen = this.Content.length;
    for ( var Pos = 0; Pos < ContentLen; Pos++ )
    {
        var Element = this.Content[Pos];
        if ( false === Element.Get_StartTabsCount( TabsCounter ) )
            return false;
    }

    return true;
};
CParagraphContentWithParagraphLikeContent.prototype.Remove_StartTabs = function(TabsCounter)
{
    var ContentLen = this.Content.length;
    for ( var Pos = 0; Pos < ContentLen; Pos++ )
    {
        var Element = this.Content[Pos];
        if ( false === Element.Remove_StartTabs( TabsCounter ) )
            return false;
    }

    return true;
};
CParagraphContentWithParagraphLikeContent.prototype.Document_UpdateInterfaceState = function()
{
    if ( true === this.Selection.Use )
    {
        var StartPos = this.Selection.StartPos;
        var EndPos   = this.Selection.EndPos;
        if (StartPos > EndPos)
        {
            StartPos = this.Selection.EndPos;
            EndPos   = this.Selection.StartPos;
        }

        for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
        {
            var Element = this.Content[CurPos];

            if (true !== Element.IsSelectionEmpty() && Element.Document_UpdateInterfaceState)
                Element.Document_UpdateInterfaceState();
        }
    }
    else
    {
        var Element = this.Content[this.State.ContentPos];
        if (Element.Document_UpdateInterfaceState)
            Element.Document_UpdateInterfaceState();
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Split = function(ContentPos, Depth)
{
    var Element = new this.constructor();

    var CurPos = ContentPos.Get(Depth);

    var TextPr = this.Get_TextPr(ContentPos, Depth);

    // Разделяем текущий элемент (возвращается правая, отделившаяся часть, если она null, тогда заменяем
    // ее на пустой ран с заданными настройками).
    var NewElement = this.Content[CurPos].Split( ContentPos, Depth + 1 );

    if ( null === NewElement )
    {
        NewElement = new ParaRun();
        NewElement.Set_Pr( TextPr.Copy() );
    }

    // Теперь делим на три части:
    // 1. До элемента с номером CurPos включительно (оставляем эту часть в исходном параграфе)
    // 2. После элемента с номером CurPos (добавляем эту часть в новый параграф)
    // 3. Новый элемент, полученный после разделения элемента с номером CurPos, который мы
    //    добавляем в начало нового параграфа.

    var NewContent = this.Content.slice( CurPos + 1 );
    this.Remove_FromContent( CurPos + 1, this.Content.length - CurPos - 1, false );

    // Добавляем в новую гиперссылку Right элемент и NewContent
    var Count = NewContent.length;
    for ( var Pos = 0; Pos < Count; Pos++ )
        Element.Add_ToContent( Pos, NewContent[Pos], false );

    Element.Add_ToContent( 0, NewElement, false );

    return Element;
};
CParagraphContentWithParagraphLikeContent.prototype.Get_Text = function(Text)
{
    var ContentLen = this.Content.length;
    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        this.Content[CurPos].Get_Text( Text );
    }
};
CParagraphContentWithParagraphLikeContent.prototype.GetAllParagraphs = function(Props, ParaArray)
{
    var ContentLen = this.Content.length;
    for (var CurPos = 0; CurPos < ContentLen; CurPos++)
    {
        if (this.Content[CurPos].GetAllParagraphs)
            this.Content[CurPos].GetAllParagraphs(Props, ParaArray);
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Get_ClassesByPos = function(Classes, ContentPos, Depth)
{
    Classes.push(this);
    var CurPos = ContentPos.Get(Depth);
    if (0 <= CurPos && CurPos <= this.Content.length - 1)
        this.Content[CurPos].Get_ClassesByPos(Classes, ContentPos, Depth + 1);
};
CParagraphContentWithParagraphLikeContent.prototype.Get_ContentLength = function()
{
    return this.Content.length;
};
CParagraphContentWithParagraphLikeContent.prototype.Get_Parent = function()
{
    if (!this.Paragraph)
        return null;

    var ContentPos = this.Paragraph.Get_PosByElement(this);
    if (null == ContentPos || undefined == ContentPos || ContentPos.Get_Depth() < 0)
        return null;

    ContentPos.Decrease_Depth(1);
    return this.Paragraph.Get_ElementByPos(ContentPos);
};
CParagraphContentWithParagraphLikeContent.prototype.Get_PosInParent = function(Parent)
{
    var _Parent = (_Parent? Parent : this.Get_Parent());
    if (!_Parent)
        return -1;

    for (var Pos = 0, Count = _Parent.Content.length; Pos < Count; ++Pos)
    {
        if (this === _Parent.Content[Pos])
            return Pos;
    }

    return -1;
};
CParagraphContentWithParagraphLikeContent.prototype.Correct_Content = function()
{
    if (this.Content.length < 0)
        this.Add_ToContent(0, new ParaRun(this.Paragraph, false));
};
CParagraphContentWithParagraphLikeContent.prototype.UpdateBookmarks = function(oManager)
{
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		this.Content[nIndex].UpdateBookmarks(oManager);
	}
};
CParagraphContentWithParagraphLikeContent.prototype.RemoveTabsForTOC = function(_isTab)
{
	var isTab = _isTab;
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		if (this.Content[nIndex].RemoveTabsForTOC(isTab))
			isTab = true;
	}

	return isTab;
};
CParagraphContentWithParagraphLikeContent.prototype.RemoveAll = function()
{
	this.Remove_FromContent(0, this.Content.length);
};
CParagraphContentWithParagraphLikeContent.prototype.AddToContent = function(nPos, oItem, isUpdatePositions)
{
	return this.Add_ToContent(nPos, oItem, isUpdatePositions);
};
CParagraphContentWithParagraphLikeContent.prototype.RemoveFromContent = function(nPos, nCount, isUpdatePositions)
{
	return this.Remove_FromContent(nPos, nCount, isUpdatePositions);
};
CParagraphContentWithParagraphLikeContent.prototype.GetComplexField = function(nType)
{
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		var oResult = this.Content[nIndex].GetComplexField(nType);
		if (oResult)
			return oResult;
	}
	return null;
};
CParagraphContentWithParagraphLikeContent.prototype.GetComplexFieldsArray = function(nType, arrComplexFields)
{
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		this.Content[nIndex].GetComplexFieldsArray(nType, arrComplexFields);
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Функции пересчета
//----------------------------------------------------------------------------------------------------------------------
CParagraphContentWithParagraphLikeContent.prototype.Recalculate_Range = function(PRS, ParaPr, Depth)
{
    if ( this.Paragraph !== PRS.Paragraph )
    {
        this.Paragraph = PRS.Paragraph;
        this.private_UpdateSpellChecking();
    }

    var CurLine  = PRS.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range );

    // Добавляем информацию о новом отрезке
    var RangeStartPos = this.protected_AddRange(CurLine, CurRange);
    var RangeEndPos   = 0;

    var ContentLen = this.Content.length;
    var Pos = RangeStartPos;
    for ( ; Pos < ContentLen; Pos++ )
    {
        var Item = this.Content[Pos];

        if (para_Math === Item.Type)
            Item.Set_Inline(true);

        if ( ( 0 === Pos && 0 === CurLine && 0 === CurRange ) || Pos !== RangeStartPos )
        {
            Item.Recalculate_Reset( PRS.Range, PRS.Line );
        }

        PRS.Update_CurPos( Pos, Depth );
        Item.Recalculate_Range( PRS, ParaPr, Depth + 1 );

        if ( true === PRS.NewRange )
        {
            RangeEndPos = Pos;
            break;
        }
    }

    if ( Pos >= ContentLen )
    {
        RangeEndPos = Pos - 1;
    }

    this.protected_FillRange(CurLine, CurRange, RangeStartPos, RangeEndPos);
};
CParagraphContentWithParagraphLikeContent.prototype.Recalculate_Set_RangeEndPos = function(PRS, PRP, Depth)
{
    var CurLine  = PRS.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range );
    var CurPos   = PRP.Get(Depth);

    this.protected_FillRangeEndPos(CurLine, CurRange, CurPos);

    this.Content[CurPos].Recalculate_Set_RangeEndPos( PRS, PRP, Depth + 1 );
};
CParagraphContentWithParagraphLikeContent.prototype.Recalculate_LineMetrics = function(PRS, ParaPr, _CurLine, _CurRange)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = (0 === CurLine ? _CurRange - this.StartRange : _CurRange);

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
    {
        this.Content[CurPos].Recalculate_LineMetrics(PRS, ParaPr, _CurLine, _CurRange);
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Recalculate_Range_Width = function(PRSC, _CurLine, _CurRange)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        this.Content[CurPos].Recalculate_Range_Width( PRSC, _CurLine, _CurRange );
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Recalculate_Range_Spaces = function(PRSA, _CurLine, _CurRange, _CurPage)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        this.Content[CurPos].Recalculate_Range_Spaces( PRSA, _CurLine, _CurRange, _CurPage );
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Recalculate_PageEndInfo = function(PRSI, _CurLine, _CurRange)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        this.Content[CurPos].Recalculate_PageEndInfo( PRSI, _CurLine, _CurRange );
    }
};
CParagraphContentWithParagraphLikeContent.prototype.SaveRecalculateObject = function(Copy)
{
	var RecalcObj = new CRunRecalculateObject(this.StartLine, this.StartRange);
	RecalcObj.Save_Lines(this, Copy);
	RecalcObj.Save_Content(this, Copy);
	return RecalcObj;
};
CParagraphContentWithParagraphLikeContent.prototype.LoadRecalculateObject = function(RecalcObj)
{
    RecalcObj.Load_Lines( this );
    RecalcObj.Load_Content( this );
};
CParagraphContentWithParagraphLikeContent.prototype.PrepareRecalculateObject = function()
{
	this.protected_ClearLines();

	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		this.Content[Index].PrepareRecalculateObject();
	}
};
CParagraphContentWithParagraphLikeContent.prototype.Is_EmptyRange = function(_CurLine, _CurRange)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        if ( false === this.Content[CurPos].Is_EmptyRange(_CurLine, _CurRange) )
            return false;
    }

    return true;
};
CParagraphContentWithParagraphLikeContent.prototype.Check_Range_OnlyMath = function(Checker, _CurRange, _CurLine)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        this.Content[CurPos].Check_Range_OnlyMath(Checker, _CurRange, _CurLine);

        if (false === Checker.Result)
            break;
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Check_MathPara = function(Checker)
{
    Checker.Result = false;
    Checker.Found  = true;
};
CParagraphContentWithParagraphLikeContent.prototype.Check_PageBreak = function()
{
    var Count = this.Content.length;
    for (var Pos = 0; Pos < Count; Pos++)
    {
        if (true === this.Content[Pos].Check_PageBreak())
            return true;
    }

    return false;
};
CParagraphContentWithParagraphLikeContent.prototype.Check_BreakPageEnd = function(PBChecker)
{
    var ContentLen = this.Content.length;
    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        var Element = this.Content[CurPos];

        if ( true !== Element.Check_BreakPageEnd(PBChecker) )
            return false;
    }

    return true;
};
CParagraphContentWithParagraphLikeContent.prototype.Get_ParaPosByContentPos = function(ContentPos, Depth)
{
    var Pos = ContentPos.Get(Depth);

    return this.Content[Pos].Get_ParaPosByContentPos( ContentPos, Depth + 1 );
};
CParagraphContentWithParagraphLikeContent.prototype.Recalculate_CurPos = function(_X, Y, CurrentRun, _CurRange, _CurLine, _CurPage, UpdateCurPos, UpdateTarget, ReturnTarget)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );
    var X = _X;

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        var Item = this.Content[CurPos];
        var Res = Item.Recalculate_CurPos( X, Y, (true === CurrentRun && CurPos === this.State.ContentPos ? true : false), _CurRange, _CurLine, _CurPage, UpdateCurPos, UpdateTarget, ReturnTarget );

        if ( true === CurrentRun && CurPos === this.State.ContentPos )
            return Res;
        else
            X = Res.X;
    }

    return { X : X };
};
CParagraphContentWithParagraphLikeContent.prototype.Refresh_RecalcData = function(Data)
{
    if (undefined !== this.Paragraph && null !== this.Paragraph)
        this.Paragraph.Refresh_RecalcData2(0);
};
CParagraphContentWithParagraphLikeContent.prototype.RecalculateMinMaxContentWidth = function(MinMax)
{
	var Count = this.Content.length;
	for (var Pos = 0; Pos < Count; Pos++)
	{
		this.Content[Pos].RecalculateMinMaxContentWidth(MinMax);
	}
};
CParagraphContentWithParagraphLikeContent.prototype.Get_Range_VisibleWidth = function(RangeW, _CurLine, _CurRange)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        this.Content[CurPos].Get_Range_VisibleWidth(RangeW, _CurLine, _CurRange);
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Shift_Range = function(Dx, Dy, _CurLine, _CurRange)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        this.Content[CurPos].Shift_Range(Dx, Dy, _CurLine, _CurRange);
    }
};
//----------------------------------------------------------------------------------------------------------------------
// Функции отрисовки
//----------------------------------------------------------------------------------------------------------------------
CParagraphContentWithParagraphLikeContent.prototype.Draw_HighLights = function(PDSH)
{
    var CurLine  = PDSH.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PDSH.Range - this.StartRange : PDSH.Range );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        this.Content[CurPos].Draw_HighLights( PDSH );
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Draw_Elements = function(PDSE)
{
    var CurLine  = PDSE.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PDSE.Range - this.StartRange : PDSE.Range );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        this.Content[CurPos].Draw_Elements( PDSE );
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Draw_Lines = function(PDSL)
{
	var CurLine  = PDSL.Line - this.StartLine;
	var CurRange = ( 0 === CurLine ? PDSL.Range - this.StartRange : PDSL.Range );

	var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
	var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

	var nCurDepth = PDSL.CurDepth;
	for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
	{
		PDSL.CurPos.Update(CurPos, nCurDepth);
		PDSL.CurDepth = nCurDepth + 1;

		this.Content[CurPos].Draw_Lines(PDSL);
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с курсором
//----------------------------------------------------------------------------------------------------------------------
CParagraphContentWithParagraphLikeContent.prototype.Is_CursorPlaceable = function()
{
    return true;
};
CParagraphContentWithParagraphLikeContent.prototype.Cursor_Is_Start = function()
{
    var CurPos = 0;
    while ( CurPos < this.State.ContentPos && CurPos < this.Content.length - 1 )
    {
        if ( true === this.Content[CurPos].Is_Empty() )
            CurPos++;
        else
            return false;
    }

    return this.Content[CurPos].Cursor_Is_Start();
};
CParagraphContentWithParagraphLikeContent.prototype.Cursor_Is_NeededCorrectPos = function()
{
    return false;
};
CParagraphContentWithParagraphLikeContent.prototype.Cursor_Is_End = function()
{
    var CurPos = this.Content.length - 1;
    while ( CurPos > this.State.ContentPos && CurPos > 0 )
    {
        if ( true === this.Content[CurPos].Is_Empty() )
            CurPos--;
        else
            return false;
    }

    return this.Content[CurPos].Cursor_Is_End();
};
CParagraphContentWithParagraphLikeContent.prototype.MoveCursorToStartPos = function()
{
    this.State.ContentPos = 0;

    if ( this.Content.length > 0 )
    {
        this.Content[0].MoveCursorToStartPos();
    }
};
CParagraphContentWithParagraphLikeContent.prototype.MoveCursorToEndPos = function(SelectFromEnd)
{
    var ContentLen = this.Content.length;

    if ( ContentLen > 0 )
    {
        this.State.ContentPos = ContentLen - 1;
        this.Content[ContentLen - 1].MoveCursorToEndPos( SelectFromEnd );
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Get_ParaContentPosByXY = function(SearchPos, Depth, _CurLine, _CurRange, StepEnd)
{
    var Result = false;

    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        var Item = this.Content[CurPos];

        if ( false === SearchPos.InText )
            SearchPos.InTextPos.Update2( CurPos, Depth );

        if ( true === Item.Get_ParaContentPosByXY( SearchPos, Depth + 1, _CurLine, _CurRange, StepEnd ) )
        {
            SearchPos.Pos.Update2( CurPos, Depth );
            Result = true;
        }
    }

    return Result;
};
CParagraphContentWithParagraphLikeContent.prototype.Get_ParaContentPos = function(bSelection, bStart, ContentPos, bUseCorrection)
{
	var Pos = ( true === bSelection ? ( true === bStart ? this.State.Selection.StartPos : this.State.Selection.EndPos ) : this.State.ContentPos );
	ContentPos.Add(Pos);

	if (Pos < 0 || Pos >= this.Content.length)
		return;

	this.Content[Pos].Get_ParaContentPos(bSelection, bStart, ContentPos, bUseCorrection);
};
CParagraphContentWithParagraphLikeContent.prototype.Set_ParaContentPos = function(ContentPos, Depth)
{
    var Pos = ContentPos.Get(Depth);

    if ( Pos >= this.Content.length )
        Pos = this.Content.length - 1;

    if ( Pos < 0 )
        Pos = 0;

    this.State.ContentPos = Pos;

    this.Content[Pos].Set_ParaContentPos( ContentPos, Depth + 1 );
};
CParagraphContentWithParagraphLikeContent.prototype.Get_PosByElement = function(Class, ContentPos, Depth, UseRange, Range, Line)
{
    if ( this === Class )
        return true;

    if (this.Content.length <= 0)
    	return false;

    var StartPos = 0;
    var EndPos   = this.Content.length - 1;

    if ( true === UseRange )
    {
        var CurLine  = Line - this.StartLine;
        var CurRange = ( 0 === CurLine ? Range - this.StartRange : Range );

        if (CurLine >= 0 && CurLine < this.protected_GetLinesCount() && CurRange >= 0 && CurRange < this.protected_GetRangesCount(CurLine))
        {
            StartPos = Math.min(this.Content.length - 1, Math.max(0, this.protected_GetRangeStartPos(CurLine, CurRange)));
            EndPos   = Math.min(this.Content.length - 1, Math.max(0, this.protected_GetRangeEndPos(CurLine, CurRange)));
        }
    }

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        var Element = this.Content[CurPos];

        ContentPos.Update( CurPos, Depth );

        if ( true === Element.Get_PosByElement(Class, ContentPos, Depth + 1, true, CurRange, CurLine) )
            return true;
    }

    return false;
};
CParagraphContentWithParagraphLikeContent.prototype.Get_ElementByPos = function(ContentPos, Depth)
{
    if (Depth >= ContentPos.Depth)
        return this;

    var CurPos = ContentPos.Get(Depth);
    if (!this.Content[CurPos])
    	return null;

    return this.Content[CurPos].Get_ElementByPos(ContentPos, Depth + 1);
};
CParagraphContentWithParagraphLikeContent.prototype.Get_PosByDrawing = function(Id, ContentPos, Depth)
{
    var Count = this.Content.length;
    for ( var CurPos = 0; CurPos < Count; CurPos++ )
    {
        var Element = this.Content[CurPos];

        ContentPos.Update( CurPos, Depth );

        if ( true === Element.Get_PosByDrawing(Id, ContentPos, Depth + 1) )
            return true;
    }

    return false;
};
CParagraphContentWithParagraphLikeContent.prototype.Get_RunElementByPos = function(ContentPos, Depth)
{
    if ( undefined !== ContentPos )
    {
        var Pos = ContentPos.Get(Depth);

        return this.Content[Pos].Get_RunElementByPos( ContentPos, Depth + 1 );
    }
    else
    {
        var Count = this.Content.length;
        if ( Count <= 0 )
            return null;

        var Pos = 0;
        var Element = this.Content[Pos];

        while ( null === Element && Pos < Count - 1 )
            Element = this.Content[++Pos];

        return Element;
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Get_LastRunInRange = function(_CurLine, _CurRange)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    if (CurLine < this.protected_GetLinesCount() && CurRange < this.protected_GetRangesCount(CurLine))
    {
        var LastItem = this.Content[this.protected_GetRangeEndPos(CurLine, CurRange)];
        if ( undefined !== LastItem )
            return LastItem.Get_LastRunInRange(_CurLine, _CurRange);
    }

    return null;
};
CParagraphContentWithParagraphLikeContent.prototype.Get_LeftPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
	if (this.Content.length <= 0)
		return false;

	var CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) : this.Content.length - 1 );

	this.Content[CurPos].Get_LeftPos(SearchPos, ContentPos, Depth + 1, UseContentPos);
	SearchPos.Pos.Update(CurPos, Depth);

	if (true === SearchPos.Found)
		return true;

	CurPos--;

	if (CurPos >= 0 && this.Content[CurPos + 1].IsStopCursorOnEntryExit())
	{
		this.Content[CurPos].Get_EndPos(false, SearchPos.Pos, Depth + 1);
		SearchPos.Pos.Update(CurPos, Depth);
		SearchPos.Found = true;
		return true;
	}

	while (CurPos >= 0)
	{
		this.Content[CurPos].Get_LeftPos(SearchPos, ContentPos, Depth + 1, false);
		SearchPos.Pos.Update(CurPos, Depth);

		if (true === SearchPos.Found)
			return true;

		CurPos--;
	}

	return false;
};
CParagraphContentWithParagraphLikeContent.prototype.Get_RightPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
	if (this.Content.length <= 0)
		return false;

	var CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) : 0 );

	this.Content[CurPos].Get_RightPos(SearchPos, ContentPos, Depth + 1, UseContentPos, StepEnd);
	SearchPos.Pos.Update(CurPos, Depth);

	if (true === SearchPos.Found)
		return true;

	CurPos++;

	var Count = this.Content.length;
	if (CurPos < Count && this.Content[CurPos - 1].IsStopCursorOnEntryExit())
	{
		this.Content[CurPos].Get_StartPos(SearchPos.Pos, Depth + 1);
		SearchPos.Pos.Update(CurPos, Depth);
		SearchPos.Found = true;
		return true;
	}

	while (CurPos < this.Content.length)
	{
		this.Content[CurPos].Get_RightPos(SearchPos, ContentPos, Depth + 1, false, StepEnd);
		SearchPos.Pos.Update(CurPos, Depth);

		if (true === SearchPos.Found)
			return true;

		CurPos++;
	}

	return false;
};
CParagraphContentWithParagraphLikeContent.prototype.Get_WordStartPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
    var CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) : this.Content.length - 1 );

    this.Content[CurPos].Get_WordStartPos(SearchPos, ContentPos, Depth + 1, UseContentPos);

    if ( true === SearchPos.UpdatePos )
        SearchPos.Pos.Update( CurPos, Depth );

    if ( true === SearchPos.Found )
        return;

    CurPos--;

    var Count = this.Content.length;
    while ( CurPos >= 0 )
    {
        var OldUpdatePos = SearchPos.UpdatePos;

        this.Content[CurPos].Get_WordStartPos(SearchPos, ContentPos, Depth + 1, false);

        if (true === SearchPos.UpdatePos)
            SearchPos.Pos.Update( CurPos, Depth );
        else
            SearchPos.UpdatePos = OldUpdatePos;

        if ( true === SearchPos.Found )
            return;

        CurPos--;
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Get_WordEndPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
    var CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) : 0 );

    this.Content[CurPos].Get_WordEndPos(SearchPos, ContentPos, Depth + 1, UseContentPos, StepEnd);

    if ( true === SearchPos.UpdatePos )
        SearchPos.Pos.Update( CurPos, Depth );

    if ( true === SearchPos.Found )
        return;

    CurPos++;

    var Count = this.Content.length;
    while ( CurPos < Count )
    {
        var OldUpdatePos = SearchPos.UpdatePos;

        this.Content[CurPos].Get_WordEndPos(SearchPos, ContentPos, Depth + 1, false, StepEnd);

        if (true === SearchPos.UpdatePos)
            SearchPos.Pos.Update( CurPos, Depth );
        else
            SearchPos.UpdatePos = OldUpdatePos;

        if ( true === SearchPos.Found )
            return;

        CurPos++;
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Get_EndRangePos = function(_CurLine, _CurRange, SearchPos, Depth)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange);

    if ( EndPos >= this.Content.length || EndPos < 0 )
        return false;

    var Result = this.Content[EndPos].Get_EndRangePos( _CurLine, _CurRange, SearchPos, Depth + 1 );

    if ( true === Result )
        SearchPos.Pos.Update( EndPos, Depth );

    return Result;
};
CParagraphContentWithParagraphLikeContent.prototype.Get_StartRangePos = function(_CurLine, _CurRange, SearchPos, Depth)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);

    if ( StartPos >= this.Content.length || StartPos < 0 )
        return false;

    var Result = this.Content[StartPos].Get_StartRangePos( _CurLine, _CurRange, SearchPos, Depth + 1 );

    if ( true === Result )
        SearchPos.Pos.Update( StartPos, Depth );

    return Result;
};
CParagraphContentWithParagraphLikeContent.prototype.Get_StartRangePos2 = function(_CurLine, _CurRange, ContentPos, Depth)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var Pos = this.protected_GetRangeStartPos(CurLine, CurRange);

    ContentPos.Update( Pos, Depth );

    this.Content[Pos].Get_StartRangePos2( _CurLine, _CurRange, ContentPos, Depth + 1 );
};
CParagraphContentWithParagraphLikeContent.prototype.Get_EndRangePos2 = function(_CurLine, _CurRange, ContentPos, Depth)
{
	var CurLine  = _CurLine - this.StartLine;
	var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

	var Pos = this.protected_GetRangeEndPos(CurLine, CurRange);
	ContentPos.Update(Pos, Depth);
	this.Content[Pos].Get_EndRangePos2(_CurLine, _CurRange, ContentPos, Depth + 1);
};
CParagraphContentWithParagraphLikeContent.prototype.Get_StartPos = function(ContentPos, Depth)
{
    if ( this.Content.length > 0 )
    {
        ContentPos.Update( 0, Depth );

        this.Content[0].Get_StartPos( ContentPos, Depth + 1 );
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Get_EndPos = function(BehindEnd, ContentPos, Depth)
{
    var ContentLen = this.Content.length;
    if ( ContentLen > 0 )
    {
        ContentPos.Update( ContentLen - 1, Depth );

        this.Content[ContentLen - 1].Get_EndPos( BehindEnd, ContentPos, Depth + 1 );
    }
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с селектом
//----------------------------------------------------------------------------------------------------------------------
CParagraphContentWithParagraphLikeContent.prototype.Set_SelectionContentPos = function(StartContentPos, EndContentPos, Depth, StartFlag, EndFlag)
{
	if (this.Content.length <= 0)
		return;

    var Selection = this.Selection;

    var OldStartPos = Selection.StartPos;
    var OldEndPos   = Selection.EndPos;

    if ( OldStartPos > OldEndPos )
    {
        OldStartPos = Selection.EndPos;
        OldEndPos   = Selection.StartPos;
    }

    var StartPos = 0;
    switch (StartFlag)
    {
        case  1: StartPos = 0; break;
        case -1: StartPos = this.Content.length - 1; break;
        case  0: StartPos = StartContentPos.Get(Depth); break;
    }

    var EndPos = 0;
    switch (EndFlag)
    {
        case  1: EndPos = 0; break;
        case -1: EndPos = this.Content.length - 1; break;
        case  0: EndPos = EndContentPos.Get(Depth); break;
    }

    // Удалим отметки о старом селекте
    if ( OldStartPos < StartPos && OldStartPos < EndPos )
    {
        var TempBegin = Math.max(0, OldStartPos);
        var TempEnd   = Math.min(this.Content.length - 1, Math.min(StartPos, EndPos) - 1);
        for (var CurPos = TempBegin; CurPos <= TempEnd; ++CurPos)
        {
            this.Content[CurPos].RemoveSelection();
        }
    }

    if ( OldEndPos > StartPos && OldEndPos > EndPos )
    {
        var TempBegin = Math.max(0, Math.max(StartPos, EndPos) + 1);
        var TempEnd   = Math.min(OldEndPos, this.Content.length - 1);
        for (var CurPos = TempBegin; CurPos <= TempEnd; ++CurPos)
        {
            this.Content[CurPos].RemoveSelection();
        }
    }

    // Выставим метки нового селекта

    Selection.Use      = true;
    Selection.StartPos = StartPos;
    Selection.EndPos   = EndPos;

    if ( StartPos != EndPos )
    {
        this.Content[StartPos].Set_SelectionContentPos( StartContentPos, null, Depth + 1, StartFlag, StartPos > EndPos ? 1 : -1 );
        this.Content[EndPos].Set_SelectionContentPos( null, EndContentPos, Depth + 1, StartPos > EndPos ? -1 : 1, EndFlag );

        var _StartPos = StartPos;
        var _EndPos   = EndPos;
        var Direction = 1;

        if ( _StartPos > _EndPos )
        {
            _StartPos = EndPos;
            _EndPos   = StartPos;
            Direction = -1;
        }

        for ( var CurPos = _StartPos + 1; CurPos < _EndPos; CurPos++ )
        {
            this.Content[CurPos].SelectAll( Direction );
        }
    }
    else
    {
        this.Content[StartPos].Set_SelectionContentPos( StartContentPos, EndContentPos, Depth + 1, StartFlag, EndFlag );
    }
};
CParagraphContentWithParagraphLikeContent.prototype.SetContentSelection = function(StartDocPos, EndDocPos, Depth, StartFlag, EndFlag)
{
	if (this.Content.length <= 0)
		return;

    if ((0 === StartFlag && (!StartDocPos[Depth] || this !== StartDocPos[Depth].Class)) || (0 === EndFlag && (!EndDocPos[Depth] || this !== EndDocPos[Depth].Class)))
        return;

    var StartPos = 0, EndPos = 0;
    switch (StartFlag)
    {
        case 0 : StartPos = StartDocPos[Depth].Position; break;
        case 1 : StartPos = 0; break;
        case -1: StartPos = this.Content.length - 1; break;
    }

    switch (EndFlag)
    {
        case 0 : EndPos = EndDocPos[Depth].Position; break;
        case 1 : EndPos = 0; break;
        case -1: EndPos = this.Content.length - 1; break;
    }

    var _StartDocPos = StartDocPos, _StartFlag = StartFlag;
    if (null !== StartDocPos && true === StartDocPos[Depth].Deleted)
    {
        if (StartPos < this.Content.length)
        {
            _StartDocPos = null;
            _StartFlag = 1;
        }
        else if (StartPos > 0)
        {
            StartPos--;
            _StartDocPos = null;
            _StartFlag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    var _EndDocPos = EndDocPos, _EndFlag = EndFlag;
    if (null !== EndDocPos && true === EndDocPos[Depth].Deleted)
    {
        if (EndPos < this.Content.length)
        {
            _EndDocPos = null;
            _EndFlag = 1;
        }
        else if (EndPos > 0)
        {
            EndPos--;
            _EndDocPos = null;
            _EndFlag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    this.Selection.Use      = true;
    this.Selection.StartPos = Math.max(0, Math.min(this.Content.length - 1, StartPos));
    this.Selection.EndPos   = Math.max(0, Math.min(this.Content.length - 1, EndPos));

    if (StartPos !== EndPos)
    {
        if (this.Content[StartPos] && this.Content[StartPos].SetContentSelection)
            this.Content[StartPos].SetContentSelection(_StartDocPos, null, Depth + 1, _StartFlag, StartPos > EndPos ? 1 : -1);

        if (this.Content[EndPos] && this.Content[EndPos].SetContentSelection)
            this.Content[EndPos].SetContentSelection(null, _EndDocPos, Depth + 1, StartPos > EndPos ? -1 : 1, _EndFlag);

        var _StartPos = StartPos;
        var _EndPos = EndPos;
        var Direction = 1;

        if (_StartPos > _EndPos)
        {
            _StartPos = EndPos;
            _EndPos = StartPos;
            Direction = -1;
        }

        for (var CurPos = _StartPos + 1; CurPos < _EndPos; CurPos++)
        {
            this.Content[CurPos].SelectAll(Direction);
        }
    }
    else
    {
        if (this.Content[StartPos] && this.Content[StartPos].SetContentSelection)
            this.Content[StartPos].SetContentSelection(_StartDocPos, _EndDocPos, Depth + 1, _StartFlag, _EndFlag);
    }
};
CParagraphContentWithParagraphLikeContent.prototype.SetContentPosition = function(DocPos, Depth, Flag)
{
	if (this.Content.length <= 0)
		return;

    if (0 === Flag && (!DocPos[Depth] || this !== DocPos[Depth].Class))
        return;

    var Pos = 0;
    switch (Flag)
    {
        case 0 : Pos = DocPos[Depth].Position; break;
        case 1 : Pos = 0; break;
        case -1: Pos = this.Content.length - 1; break;
    }

    var _DocPos = DocPos, _Flag = Flag;
    if (null !== DocPos && true === DocPos[Depth].Deleted)
    {
        if (Pos < this.Content.length)
        {
            _DocPos = null;
            _Flag = 1;
        }
        else if (Pos > 0)
        {
            Pos--;
            _DocPos = null;
            _Flag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    this.State.ContentPos = Math.max(0, Math.min(this.Content.length - 1, Pos));

    // TODO: Как только в CMathContent CurPos перейдет на стандартное this.State.ContentPos убрать эту проверку
    if (this.CurPos)
        this.CurPos = this.State.ContentPos;

    if (this.Content[Pos] && this.Content[Pos].SetContentPosition)
        this.Content[Pos].SetContentPosition(_DocPos, Depth + 1, _Flag);
    else
        this.Content[Pos].MoveCursorToStartPos();
};
CParagraphContentWithParagraphLikeContent.prototype.RemoveSelection = function()
{
    var Selection = this.Selection;

    if ( true === Selection.Use )
    {
        var StartPos = Selection.StartPos;
        var EndPos   = Selection.EndPos;

        if ( StartPos > EndPos )
        {
            StartPos = Selection.EndPos;
            EndPos   = Selection.StartPos;
        }

        StartPos = Math.max( 0, StartPos );
        EndPos   = Math.min( this.Content.length - 1, EndPos );

        for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
        {
            this.Content[CurPos].RemoveSelection();
        }
    }

    Selection.Use      = false;
    Selection.StartPos = 0;
    Selection.EndPos   = 0;
};
CParagraphContentWithParagraphLikeContent.prototype.SelectAll = function(Direction)
{
    var ContentLen = this.Content.length;

    var Selection = this.Selection;

    Selection.Use = true;

    if ( -1 === Direction )
    {
        Selection.StartPos = ContentLen - 1;
        Selection.EndPos   = 0;
    }
    else
    {
        Selection.StartPos = 0;
        Selection.EndPos   = ContentLen - 1;
    }

    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        this.Content[CurPos].SelectAll( Direction );
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Selection_DrawRange = function(_CurLine, _CurRange, SelectionDraw)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        this.Content[CurPos].Selection_DrawRange( _CurLine, _CurRange, SelectionDraw );
    }
};
CParagraphContentWithParagraphLikeContent.prototype.IsSelectionEmpty = function(CheckEnd)
{
	if (this.Content.length <= 0)
		return true;

    var StartPos = this.State.Selection.StartPos;
    var EndPos   = this.State.Selection.EndPos;

    if ( StartPos > EndPos )
    {
        StartPos = this.State.Selection.EndPos;
        EndPos   = this.State.Selection.StartPos;
    }

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        if ( false === this.Content[CurPos].IsSelectionEmpty(CheckEnd) )
            return false;
    }

    return true;
};
CParagraphContentWithParagraphLikeContent.prototype.Selection_CheckParaEnd = function()
{
    // Сюда не должен попадать ParaEnd
    return false;
};
CParagraphContentWithParagraphLikeContent.prototype.Selection_CheckParaContentPos = function(ContentPos, Depth, bStart, bEnd)
{
    var CurPos = ContentPos.Get(Depth);

    if (this.Selection.StartPos <= CurPos && CurPos <= this.Selection.EndPos)
        return this.Content[CurPos].Selection_CheckParaContentPos(ContentPos, Depth + 1, bStart && this.Selection.StartPos === CurPos, bEnd && CurPos === this.Selection.EndPos);
    else if (this.Selection.EndPos <= CurPos && CurPos <= this.Selection.StartPos)
        return this.Content[CurPos].Selection_CheckParaContentPos(ContentPos, Depth + 1, bStart && this.Selection.EndPos === CurPos, bEnd && CurPos === this.Selection.StartPos);

    return false;
};
CParagraphContentWithParagraphLikeContent.prototype.IsSelectedAll = function(Props)
{
    var Selection = this.State.Selection;

    if ( false === Selection.Use && true !== this.Is_Empty( Props ) )
        return false;

    var StartPos = Selection.StartPos;
    var EndPos   = Selection.EndPos;

    if ( EndPos < StartPos )
    {
        StartPos = Selection.EndPos;
        EndPos   = Selection.StartPos;
    }

    for ( var Pos = 0; Pos <= StartPos; Pos++ )
    {
        if ( false === this.Content[Pos].IsSelectedAll( Props ) )
            return false;
    }

    var Count = this.Content.length;
    for ( var Pos = EndPos; Pos < Count; Pos++ )
    {
        if ( false === this.Content[Pos].IsSelectedAll( Props ) )
            return false;
    }

    return true;
};
CParagraphContentWithParagraphLikeContent.prototype.Selection_CorrectLeftPos = function(Direction)
{
    if ( false === this.Selection.Use || true === this.Is_Empty( { SkipAnchor : true } ) )
        return true;

    var Selection = this.State.Selection;
    var StartPos = Math.min( Selection.StartPos, Selection.EndPos );
    var EndPos   = Math.max( Selection.StartPos, Selection.EndPos );

    for ( var Pos = 0; Pos < StartPos; Pos++ )
    {
        if ( true !== this.Content[Pos].Is_Empty( { SkipAnchor : true } ) )
            return false;
    }

    for ( var Pos = StartPos; Pos <= EndPos; Pos++ )
    {
        if ( true === this.Content[Pos].Selection_CorrectLeftPos(Direction) )
        {
            if ( 1 === Direction )
                this.Selection.StartPos = Pos + 1;
            else
                this.Selection.EndPos   = Pos + 1;

            this.Content[Pos].RemoveSelection();
        }
        else
            return false;
    }

    return true;
};
CParagraphContentWithParagraphLikeContent.prototype.IsSelectionUse = function()
{
    return this.State.Selection.Use;
};
//----------------------------------------------------------------------------------------------------------------------
// Spelling
//----------------------------------------------------------------------------------------------------------------------
CParagraphContentWithParagraphLikeContent.prototype.Restart_CheckSpelling = function()
{
    for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; nIndex++)
    {
        this.Content[nIndex].Restart_CheckSpelling();
    }
};
/**
 * @param oSpellCheckerEngine {CParagraphSpellCheckerEngine}
 * @param nDepth {number}
 */
CParagraphContentWithParagraphLikeContent.prototype.CheckSpelling = function(oSpellCheckerEngine, nDepth)
{
	if (oSpellCheckerEngine.IsExceedLimit())
		return;

	var nStartPos = 0;
	if (oSpellCheckerEngine.IsFindStart())
		nStartPos = oSpellCheckerEngine.GetPos(nDepth);
	else
		this.SpellingMarks = [];

    for (var nPos = nStartPos, nCount = this.Content.length; nPos < nCount; ++nPos)
    {
    	var oItem = this.Content[nPos];

    	oSpellCheckerEngine.UpdatePos(nPos, nDepth);
        oItem.CheckSpelling(oSpellCheckerEngine, nDepth + 1);

        if (oSpellCheckerEngine.IsExceedLimit())
        	return;
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Add_SpellCheckerElement = function(Element, Start, Depth)
{
    if (true === Start)
        this.Content[Element.StartPos.Get(Depth)].Add_SpellCheckerElement(Element, Start, Depth + 1);
    else
        this.Content[Element.EndPos.Get(Depth)].Add_SpellCheckerElement(Element, Start, Depth + 1);

    this.SpellingMarks.push( new CParagraphSpellingMark( Element, Start, Depth ) );
};
CParagraphContentWithParagraphLikeContent.prototype.Remove_SpellCheckerElement = function(Element)
{
    var Count = this.SpellingMarks.length;
    for (var Pos = 0; Pos < Count; Pos++)
    {
        var SpellingMark = this.SpellingMarks[Pos];
        if (Element === SpellingMark.Element)
        {
            this.SpellingMarks.splice(Pos, 1);
            break;
        }
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Clear_SpellingMarks = function()
{
    this.SpellingMarks = [];
};
//----------------------------------------------------------------------------------------------------------------------
// Search and Replace
//----------------------------------------------------------------------------------------------------------------------
CParagraphContentWithParagraphLikeContent.prototype.Search = function(ParaSearch, Depth)
{
    this.SearchMarks = [];

    var ContentLen = this.Content.length;
    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        var Element = this.Content[CurPos];

        ParaSearch.ContentPos.Update( CurPos, Depth );

        Element.Search( ParaSearch, Depth + 1 );
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Add_SearchResult = function(SearchResult, Start, ContentPos, Depth)
{
    if ( true === Start )
        SearchResult.ClassesS.push( this );
    else
        SearchResult.ClassesE.push( this );

    this.SearchMarks.push( new CParagraphSearchMark( SearchResult, Start, Depth ) );

    this.Content[ContentPos.Get(Depth)].Add_SearchResult( SearchResult, Start, ContentPos, Depth + 1 );
};
CParagraphContentWithParagraphLikeContent.prototype.Clear_SearchResults = function()
{
    this.SearchMarks = [];
};
CParagraphContentWithParagraphLikeContent.prototype.Remove_SearchResult = function(SearchResult)
{
    var MarksCount = this.SearchMarks.length;
    for ( var Index = 0; Index < MarksCount; Index++ )
    {
        var Mark = this.SearchMarks[Index];
        if ( SearchResult === Mark.SearchResult )
        {
            this.SearchMarks.splice( Index, 1 );
            Index--;
            MarksCount--;
        }
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Search_GetId = function(bNext, bUseContentPos, ContentPos, Depth)
{
    // Определим позицию, начиная с которой мы будем искать ближайший найденный элемент
    var StartPos = 0;

    if ( true === bUseContentPos )
    {
        StartPos = ContentPos.Get( Depth );
    }
    else
    {
        if ( true === bNext )
        {
            StartPos = 0;
        }
        else
        {
            StartPos = this.Content.length - 1;
        }
    }

    // Производим поиск ближайшего элемента
    if ( true === bNext )
    {
        var ContentLen = this.Content.length;

        for ( var CurPos = StartPos; CurPos < ContentLen; CurPos++ )
        {
            var ElementId = this.Content[CurPos].Search_GetId( true, bUseContentPos && CurPos === StartPos ? true : false, ContentPos, Depth + 1 );
            if ( null !== ElementId )
                return ElementId;
        }
    }
    else
    {
        var ContentLen = this.Content.length;

        for ( var CurPos = StartPos; CurPos >= 0; CurPos-- )
        {
            var ElementId = this.Content[CurPos].Search_GetId( false, bUseContentPos && CurPos === StartPos ? true : false, ContentPos, Depth + 1 );
            if ( null !== ElementId )
                return ElementId;
        }
    }

    return null;
};
//----------------------------------------------------------------------------------------------------------------------
// Разное
//----------------------------------------------------------------------------------------------------------------------
CParagraphContentWithParagraphLikeContent.prototype.Set_ReviewType = function(ReviewType, RemovePrChange)
{
    for (var Index = 0, Count = this.Content.length; Index < Count; Index++)
    {
        var Element = this.Content[Index];
        if (para_Run === Element.Type)
        {
            Element.Set_ReviewType(ReviewType);

            if (true === RemovePrChange)
                Element.Remove_PrChange();
        }
        else if (Element.Set_ReviewType)
            Element.Set_ReviewType(ReviewType);
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Set_ReviewTypeWithInfo = function(ReviewType, ReviewInfo)
{
    for (var Index = 0, Count = this.Content.length; Index < Count; Index++)
    {
        var Element = this.Content[Index];
        if (Element && Element.Set_ReviewTypeWithInfo)
            Element.Set_ReviewTypeWithInfo(ReviewType, ReviewInfo);
    }
};
CParagraphContentWithParagraphLikeContent.prototype.Check_RevisionsChanges = function(Checker, ContentPos, Depth)
{
    for (var CurPos = 0, Count = this.Content.length; CurPos < Count; CurPos++)
    {
        ContentPos.Update(CurPos, Depth);
        this.Content[CurPos].Check_RevisionsChanges(Checker, ContentPos, Depth + 1);
    }
};
CParagraphContentWithParagraphLikeContent.prototype.AcceptRevisionChanges = function(Type, bAll)
{
    if (true === this.Selection.Use || true === bAll)
    {
        var StartPos = this.Selection.StartPos;
        var EndPos   = this.Selection.EndPos;
        if (StartPos > EndPos)
        {
            StartPos = this.Selection.EndPos;
            EndPos   = this.Selection.StartPos;
        }

        if (true === bAll)
        {
            StartPos = 0;
            EndPos   = this.Content.length - 1;
        }

        // Начинаем с конца, потому что при выполнении данной функции, количество элементов может изменяться
        if (this.Content[EndPos].AcceptRevisionChanges)
            this.Content[EndPos].AcceptRevisionChanges(Type, bAll);

        if (StartPos < EndPos)
        {
            for (var CurPos = EndPos - 1; CurPos > StartPos; CurPos--)
            {
                var Element = this.Content[CurPos];
                var ReviewType = Element.Get_ReviewType ? Element.Get_ReviewType() : reviewtype_Common;

                var isGoInside = false;
                if (reviewtype_Add === ReviewType)
                {
                    if (undefined === Type || c_oAscRevisionsChangeType.TextAdd === Type)
                        Element.Set_ReviewType(reviewtype_Common);

                    isGoInside = true;
                }
                else if (reviewtype_Remove === ReviewType)
                {
                    if (undefined === Type || c_oAscRevisionsChangeType.TextRem === Type)
                        this.Remove_FromContent(CurPos, 1, true);
                }
                else if (reviewtype_Common === ReviewType)
                {
                    isGoInside = true;
                }

                if (true === isGoInside && Element.AcceptRevisionChanges)
                    Element.AcceptRevisionChanges(Type, true);
            }

            if (this.Content[StartPos].AcceptRevisionChanges)
                this.Content[StartPos].AcceptRevisionChanges(Type, bAll);
        }

        this.Correct_Content();
    }
};
CParagraphContentWithParagraphLikeContent.prototype.RejectRevisionChanges = function(Type, bAll)
{
    if (true === this.Selection.Use || true === bAll)
    {
        var StartPos = this.Selection.StartPos;
        var EndPos   = this.Selection.EndPos;
        if (StartPos > EndPos)
        {
            StartPos = this.Selection.EndPos;
            EndPos   = this.Selection.StartPos;
        }

        if (true === bAll)
        {
            StartPos = 0;
            EndPos   = this.Content.length - 1;
        }

        // Начинаем с конца, потому что при выполнении данной функции, количество элементов может изменяться
        if (this.Content[EndPos].RejectRevisionChanges)
            this.Content[EndPos].RejectRevisionChanges(Type, bAll);

        if (StartPos < EndPos)
        {
            for (var CurPos = EndPos - 1; CurPos > StartPos; CurPos--)
            {
                var Element = this.Content[CurPos];
                var ReviewType = Element.Get_ReviewType ? Element.Get_ReviewType() : reviewtype_Common;

                var isGoInside = false;
                if (reviewtype_Remove === ReviewType)
                {
                    if (undefined === Type || c_oAscRevisionsChangeType.TextRem === Type)
                        Element.Set_ReviewType(reviewtype_Common);

                    isGoInside = true;
                }
                else if (reviewtype_Add === ReviewType)
                {
                    if (undefined === Type || c_oAscRevisionsChangeType.TextAdd === Type)
                        this.Remove_FromContent(CurPos, 1, true);
                }
                else if (reviewtype_Common === ReviewType)
                {
                    isGoInside = true;
                }

                if (true === isGoInside && Element.RejectRevisionChanges)
                    Element.RejectRevisionChanges(Type, true);
            }

            if (this.Content[StartPos].RejectRevisionChanges)
                this.Content[StartPos].RejectRevisionChanges(Type, bAll);
        }

        this.Correct_Content();
    }
};
CParagraphContentWithParagraphLikeContent.prototype.private_UpdateTrackRevisions = function()
{
    if (this.Paragraph && this.Paragraph.LogicDocument && this.Paragraph.LogicDocument.Get_TrackRevisionsManager)
    {
        var RevisionsManager = this.Paragraph.LogicDocument.Get_TrackRevisionsManager();
        RevisionsManager.Check_Paragraph(this.Paragraph);
    }
};
CParagraphContentWithParagraphLikeContent.prototype.private_CheckUpdateBookmarks = function(Items)
{
	if (!Items)
		return;

	for (var nIndex = 0, nCount = Items.length; nIndex < nCount; ++nIndex)
	{
		if (para_Bookmark === Items[nIndex].Type)
		{
			var oLogicDocument = this.Paragraph && this.Paragraph.LogicDocument ? this.Paragraph.LogicDocument : editor.WordControl.m_oLogicDocument;
			oLogicDocument.GetBookmarksManager().SetNeedUpdate(true);
			return;
		}
	}
};
CParagraphContentWithParagraphLikeContent.prototype.Get_FootnotesList = function(oEngine)
{
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		if (this.Content[nIndex].Get_FootnotesList)
			this.Content[nIndex].Get_FootnotesList(oEngine);

		if (oEngine.IsRangeFull())
			return;
	}
};
CParagraphContentWithParagraphLikeContent.prototype.GotoFootnoteRef = function(isNext, isCurrent, isStepOver)
{
	var nPos = 0;

	if (true === isCurrent)
	{
		if (true === this.Selection.Use)
			nPos = Math.min(this.Selection.StartPos, this.Selection.EndPos);
		else
			nPos = this.State.ContentPos;
	}
	else
	{
		if (true === isNext)
			nPos = 0;
		else
			nPos = this.Content.length - 1;
	}

	if (true === isNext)
	{
		for (var nIndex = nPos, nCount = this.Content.length - 1; nIndex < nCount; ++nIndex)
		{
			var nRes = this.Content[nIndex].GotoFootnoteRef ? this.Content[nIndex].GotoFootnoteRef(true, true === isCurrent && nPos === nIndex, isStepOver) : 0;

			if (nRes > 0)
				isStepOver = true;
			else  if (-1 === nRes)
				return true;
		}
	}
	else
	{
		for (var nIndex = nPos; nIndex >= 0; --nIndex)
		{
			var nRes = this.Content[nIndex].GotoFootnoteRef ? this.Content[nIndex].GotoFootnoteRef(true, true === isCurrent && nPos === nIndex, isStepOver) : 0;

			if (nRes > 0)
				isStepOver = true;
			else  if (-1 === nRes)
				return true;
		}
	}

	return false;
};
CParagraphContentWithParagraphLikeContent.prototype.GetFootnoteRefsInRange = function(arrFootnotes, _CurLine, _CurRange)
{
	var CurLine = _CurLine - this.StartLine;
	var CurRange = (0 === CurLine ? _CurRange - this.StartRange : _CurRange);

	var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
	var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

	for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
	{
		if (this.Content[CurPos].GetFootnoteRefsInRange)
			this.Content[CurPos].GetFootnoteRefsInRange(arrFootnotes, _CurLine, _CurRange);
	}
};
CParagraphContentWithParagraphLikeContent.prototype.GetAllContentControls = function(arrContentControls)
{
	if (!arrContentControls)
		arrContentControls = [];

	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		if (this.Content[nIndex].GetAllContentControls)
			this.Content[nIndex].GetAllContentControls(arrContentControls);
	}

	return arrContentControls;
};
CParagraphContentWithParagraphLikeContent.prototype.Is_UseInDocument = function()
{
	return (this.Paragraph && true === this.Paragraph.Is_UseInDocument() && true === this.Is_UseInParagraph() ? true : false);
};
CParagraphContentWithParagraphLikeContent.prototype.Is_UseInParagraph = function()
{
	if (!this.Paragraph)
		return false;

	var ContentPos = this.Paragraph.Get_PosByElement(this);
	if (!ContentPos)
		return false;

	return true;
};
CParagraphContentWithParagraphLikeContent.prototype.SelectThisElement = function(nDirection)
{
	var ContentPos = this.Paragraph.Get_PosByElement(this);
	if (!ContentPos)
		return false;

	var StartPos = ContentPos.Copy();
	var EndPos   = ContentPos.Copy();

	if (nDirection > 0)
	{
		this.Get_StartPos(StartPos, StartPos.Get_Depth() + 1);
		this.Get_EndPos(true, EndPos, EndPos.Get_Depth() + 1);
	}
	else
	{
		this.Get_StartPos(EndPos, EndPos.Get_Depth() + 1);
		this.Get_EndPos(true, StartPos, StartPos.Get_Depth() + 1);
	}

	this.Paragraph.Selection.Use   = true;
	this.Paragraph.Selection.Start = false;
	this.Paragraph.Set_ParaContentPos(StartPos, true, -1, -1);
	this.Paragraph.Set_SelectionContentPos(StartPos, EndPos, false);
	this.Paragraph.Document_SetThisElementCurrent(false);

	return true;
};
CParagraphContentWithParagraphLikeContent.prototype.SetThisElementCurrent = function()
{
	var ContentPos = this.Paragraph.Get_PosByElement(this);
	if (!ContentPos)
		return;

	var StartPos = ContentPos.Copy();
	this.Get_StartPos(StartPos, StartPos.Get_Depth() + 1);

	this.Paragraph.Set_ParaContentPos(StartPos, true, -1, -1, false);
	this.Paragraph.Document_SetThisElementCurrent(false);
};
CParagraphContentWithParagraphLikeContent.prototype.GetSelectedContentControls = function(arrContentControls)
{
	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (StartPos > EndPos)
		{
			StartPos = this.Selection.EndPos;
			EndPos   = this.Selection.StartPos;
		}

		for (var Index = StartPos; Index <= EndPos; ++Index)
		{
			if (this.Content[Index].GetSelectedContentControls)
				this.Content[Index].GetSelectedContentControls(arrContentControls);
		}
	}
	else
	{
		if (this.Content[this.State.ContentPos].GetSelectedContentControls)
			this.Content[this.State.ContentPos].GetSelectedContentControls(arrContentControls);
	}
};
CParagraphContentWithParagraphLikeContent.prototype.CreateRunWithText = function(sValue)
{
	var oRun = new ParaRun();
	oRun.AddText(sValue);
	oRun.Set_Pr(this.Get_FirstTextPr());
	return oRun;
};
CParagraphContentWithParagraphLikeContent.prototype.ReplaceAllWithText = function(sValue)
{
	var oRun = this.CreateRunWithText(sValue);
	oRun.Apply_TextPr(this.Get_TextPr(), undefined, true);
	this.Remove_FromContent(0, this.Content.length);
	this.Add_ToContent(0, oRun);
	this.MoveCursorToStartPos();
};
CParagraphContentWithParagraphLikeContent.prototype.FindNextFillingForm = function(isNext, isCurrent, isStart)
{
	var nCurPos = this.Selection.Use === true ? this.Selection.EndPos : this.State.ContentPos;

	var nStartPos = 0, nEndPos = 0;
	if (isCurrent)
	{
		if (isStart)
		{
			nStartPos = nCurPos;
			nEndPos   = isNext ? this.Content.length - 1 : 0;
		}
		else
		{
			nStartPos = isNext ? 0 : this.Content.length - 1;
			nEndPos   = nCurPos;
		}
	}
	else
	{
		if (isNext)
		{
			nStartPos = 0;
			nEndPos   = this.Content.length - 1;
		}
		else
		{
			nStartPos = this.Content.length - 1;
			nEndPos   = 0;
		}
	}

	if (isNext)
	{
		for (var nIndex = nStartPos; nIndex <= nEndPos; ++nIndex)
		{
			if (this.Content[nIndex].FindNextFillingForm)
			{
				var oRes = this.Content[nIndex].FindNextFillingForm(true, isCurrent && nIndex === nCurPos ? true : false, isStart);
				if (oRes)
					return oRes;
			}
		}
	}
	else
	{
		for (var nIndex = nStartPos; nIndex >= nEndPos; --nIndex)
		{
			if (this.Content[nIndex].FindNextFillingForm)
			{
				var oRes = this.Content[nIndex].FindNextFillingForm(false, isCurrent && nIndex === nCurPos ? true : false, isStart);
				if (oRes)
					return oRes;
			}
		}
	}

	return null;
};
CParagraphContentWithParagraphLikeContent.prototype.IsEmpty = function()
{
	return this.Is_Empty();
};
CParagraphContentWithParagraphLikeContent.prototype.AddContentControl = function()
{
	if (true === this.IsSelectionUse())
	{
		if (this.Selection.StartPos === this.Selection.EndPos && para_Run !== this.Content[this.Selection.StartPos].Type)
		{
			if (this.Content[this.Selection.StartPos].AddContentControl)
				return this.Content[this.Selection.StartPos].AddContentControl();

			return null;
		}
		else
		{
			var nStartPos = this.Selection.StartPos;
			var nEndPos   = this.Selection.EndPos;
			if (nEndPos < nStartPos)
			{
				nStartPos = this.Selection.EndPos;
				nEndPos   = this.Selection.StartPos;
			}

			for (var nIndex = nStartPos; nIndex <= nEndPos; ++nIndex)
			{
				if (para_Run !== this.Content[nIndex].Type)
				{
					// TODO: Вывести сообщение, что в данном месте нельзя добавить Plain text content control
					return null;
				}
			}

			var oContentControl = new CInlineLevelSdt();

			var oNewRun = this.Content[nEndPos].Split_Run(Math.max(this.Content[nEndPos].Selection.StartPos, this.Content[nEndPos].Selection.EndPos));
			this.Add_ToContent(nEndPos + 1, oNewRun);

			oNewRun = this.Content[nStartPos].Split_Run(Math.min(this.Content[nStartPos].Selection.StartPos, this.Content[nStartPos].Selection.EndPos));
			this.Add_ToContent(nStartPos + 1, oNewRun);

			for (var nIndex = nEndPos + 1; nIndex >= nStartPos + 1; --nIndex)
			{
				oContentControl.Add_ToContent(0, this.Content[nIndex]);
				this.Remove_FromContent(nIndex, 1);
			}

			this.Add_ToContent(nStartPos + 1, oContentControl);
			this.Selection.StartPos = nStartPos + 1;
			this.Selection.EndPos   = nStartPos + 1;
			oContentControl.SelectAll(1);

			return oContentControl;
		}
	}
	else
	{
		var oContentControl = new CInlineLevelSdt();
		oContentControl.Add_ToContent(0, new ParaRun());
		this.Add(oContentControl);
		return oContentControl;
	}
};
CParagraphContentWithParagraphLikeContent.prototype.GetElement = function(nPos)
{
	if (nPos < 0 || nPos >= this.Content.length)
		return null;

	return this.Content[nPos];
};
CParagraphContentWithParagraphLikeContent.prototype.GetElementsCount = function()
{
	return this.Content.length;
};
CParagraphContentWithParagraphLikeContent.prototype.PreDelete = function()
{
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		if (this.Content[nIndex] && this.Content[nIndex].PreDelete)
			this.Content[nIndex].PreDelete();
	}
};
CParagraphContentWithParagraphLikeContent.prototype.GetCurrentComplexFields = function(arrComplexFields, isCurrent, isFieldPos)
{
	var nEndPos = isCurrent ? this.State.ContentPos : this.Content.length - 1;
	for (var nIndex = 0; nIndex <= nEndPos; ++nIndex)
	{
		if (this.Content[nIndex] && this.Content[nIndex].GetCurrentComplexFields)
			this.Content[nIndex].GetCurrentComplexFields(arrComplexFields, isCurrent && nIndex === nEndPos, isFieldPos);
	}
};
CParagraphContentWithParagraphLikeContent.prototype.GetDirectTextPr = function()
{
	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;

		if (StartPos > EndPos)
		{
			StartPos = this.Selection.EndPos;
			EndPos   = this.Selection.StartPos;
		}

		while (true === this.Content[StartPos].IsSelectionEmpty() && StartPos < EndPos)
			StartPos++;

		return this.Content[StartPos].GetDirectTextPr();
	}
	else
	{
		return this.Content[this.State.ContentPos].GetDirectTextPr();
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Функции, которые должны быть реализованы в классах наследниках
//----------------------------------------------------------------------------------------------------------------------
CParagraphContentWithParagraphLikeContent.prototype.Add = function(Item)
{
	if (undefined !== Item.Parent)
		Item.Parent = this;

	switch (Item.Type)
	{
		case para_Run:
		case para_Hyperlink:
		case para_InlineLevelSdt:
		case para_Field:
		{
			var TextPr = this.Get_FirstTextPr();
			Item.SelectAll();
			Item.Apply_TextPr(TextPr);
			Item.RemoveSelection();

			var CurPos = this.State.ContentPos;
			var CurItem = this.Content[CurPos];
			if (para_Run === CurItem.Type)
			{
				var NewRun = CurItem.Split2(CurItem.State.ContentPos);
				this.Add_ToContent(CurPos + 1, Item);
				this.Add_ToContent(CurPos + 2, NewRun);

				this.State.ContentPos = CurPos + 2;
				this.Content[this.State.ContentPos].MoveCursorToStartPos();
			}
			else
			{
				CurItem.Add(Item);
			}

			break;
		}
		case para_Math :
		{
			var ContentPos = new CParagraphContentPos();
			this.Get_ParaContentPos(false, false, ContentPos);
			var CurPos = ContentPos.Get(0);

			// Ран формула делит на части, а в остальные элементы добавляется целиком
			if (para_Run === this.Content[CurPos].Type)
			{
				// Разделяем текущий элемент (возвращается правая часть)
				var NewElement = this.Content[CurPos].Split(ContentPos, 1);

				if (null !== NewElement)
					this.Add_ToContent(CurPos + 1, NewElement, true);

				var Elem = new ParaMath();
				Elem.Root.Load_FromMenu(Item.Menu, this.GetParagraph());
				Elem.Root.Correct_Content(true);
				this.Add_ToContent(CurPos + 1, Elem, true);

				// Перемещаем кусор в конец формулы
				this.State.ContentPos = CurPos + 1;
				this.Content[this.State.ContentPos].MoveCursorToEndPos(false);
			}
			else
			{
				this.Content[CurPos].Add(Item);
			}

			break;
		}
		default:
		{
			this.Content[this.State.ContentPos].Add(Item);
			break;
		}
	}
};
CParagraphContentWithParagraphLikeContent.prototype.Undo = function(Data){};
CParagraphContentWithParagraphLikeContent.prototype.Redo = function(Data){};
CParagraphContentWithParagraphLikeContent.prototype.Save_Changes = function(Data, Writer){};
CParagraphContentWithParagraphLikeContent.prototype.Load_Changes = function(Reader){};
CParagraphContentWithParagraphLikeContent.prototype.Write_ToBinary2 = function(Writer){};
CParagraphContentWithParagraphLikeContent.prototype.Read_FromBinary2 = function(Reader){};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var g_oTableId = AscCommon.g_oTableId;
var History = AscCommon.History;

function CCommentData()
{
    this.m_sText      = "";
    this.m_sTime      = "";
	this.m_sOOTime      = "";
    this.m_sUserId    = "";
    this.m_sUserName  = "";
    this.m_sQuoteText = null;
    this.m_bSolved    = false;
    this.m_aReplies   = [];
    
    this.Copy = function()
    {
        var NewData = new CCommentData();
        
        NewData.m_sText      = this.m_sText;
        NewData.m_sTime      = this.m_sTime;
		NewData.m_sOOTime    = this.m_sOOTime;
        NewData.m_sUserId    = this.m_sUserId;
        NewData.m_sUserName  = this.m_sUserName;
        NewData.m_sQuoteText = this.m_sQuoteText;
        NewData.m_bSolved    = this.m_bSolved;
        
        var Count = this.m_aReplies.length;
        for (var Pos = 0; Pos < Count; Pos++)
        {
            NewData.m_aReplies.push(this.m_aReplies[Pos].Copy());
        }

        return NewData;
    };

    this.Add_Reply = function(CommentData)
    {
        this.m_aReplies.push( CommentData );
    };

    this.Set_Text = function(Text)
    {
        this.m_sText = Text;
    };

    this.Get_Text = function()
    {
        return this.m_sText;
    };

    this.Get_QuoteText = function()
    {
        return this.m_sQuoteText;
    };

    this.Set_QuoteText = function(Quote)
    {
        this.m_sQuoteText = Quote;
    };

    this.Get_Solved = function()
    {
        return this.m_bSolved;
    };

    this.Set_Solved = function(Solved)
    {
        this.m_bSolved = Solved;
    };

    this.Set_Name = function(Name)
    {
        this.m_sUserName = Name;
    };

    this.Get_Name = function()
    {
        return this.m_sUserName;
    };

    this.Get_RepliesCount = function()
    {
        return this.m_aReplies.length;
    };

    this.Get_Reply = function(Index)
    {
        if ( Index < 0 || Index >= this.m_aReplies.length )
            return null;

        return this.m_aReplies[Index];
    };

    this.Read_FromAscCommentData = function(AscCommentData)
    {
        this.m_sText      = AscCommentData.asc_getText();
        this.m_sTime      = AscCommentData.asc_getTime();
		this.m_sOOTime    = AscCommentData.asc_getOnlyOfficeTime();
        this.m_sUserId    = AscCommentData.asc_getUserId();
        this.m_sQuoteText = AscCommentData.asc_getQuoteText();
        this.m_bSolved    = AscCommentData.asc_getSolved();
        this.m_sUserName  = AscCommentData.asc_getUserName();

        var RepliesCount  = AscCommentData.asc_getRepliesCount();
        for ( var Index = 0; Index < RepliesCount; Index++ )
        {
            var Reply = new CCommentData();
            Reply.Read_FromAscCommentData( AscCommentData.asc_getReply(Index) );
            this.m_aReplies.push( Reply );
        }
    };

    this.Write_ToBinary2 = function(Writer)
    {
        // String            : m_sText
        // String            : m_sTime
		// String            : m_sOOTime
        // String            : m_sUserId
        // String            : m_sUserName
        // Bool              : Null ли QuoteText
        // String            : (Если предыдущий параметр false) QuoteText
        // Bool              : Solved
        // Long              : Количество отетов
        // Array of Variable : Ответы

        var Count = this.m_aReplies.length;
        Writer.WriteString2( this.m_sText );
        Writer.WriteString2( this.m_sTime );
		Writer.WriteString2( this.m_sOOTime );
        Writer.WriteString2( this.m_sUserId );
        Writer.WriteString2( this.m_sUserName );

        if ( null === this.m_sQuoteText )
            Writer.WriteBool( true );
        else
        {
            Writer.WriteBool( false );
            Writer.WriteString2( this.m_sQuoteText );
        }
        Writer.WriteBool( this.m_bSolved );
        Writer.WriteLong( Count );

        for ( var Index = 0; Index < Count; Index++ )
        {
            this.m_aReplies[Index].Write_ToBinary2(Writer);
        }
    };

    this.Read_FromBinary2 = function(Reader)
    {
        // String            : m_sText
        // String            : m_sTime
		// String            : m_sOOTime
        // String            : m_sUserId
        // Bool              : Null ли QuoteText
        // String            : (Если предыдущий параметр false) QuoteText
        // Bool              : Solved
        // Long              : Количество отетов
        // Array of Variable : Ответы

        this.m_sText     = Reader.GetString2();
        this.m_sTime     = Reader.GetString2();
		this.m_sOOTime   = Reader.GetString2();
        this.m_sUserId   = Reader.GetString2();
        this.m_sUserName = Reader.GetString2();

        var bNullQuote = Reader.GetBool();
        if ( true != bNullQuote  )
            this.m_sQuoteText = Reader.GetString2();
        else
            this.m_sQuoteText = null;

        this.m_bSolved = Reader.GetBool();

        var Count = Reader.GetLong();
        this.m_aReplies.length = 0;
        for ( var Index = 0; Index < Count; Index++ )
        {
            var oReply = new CCommentData();
            oReply.Read_FromBinary2( Reader );
            this.m_aReplies.push( oReply );
        }
    };
}
CCommentData.prototype.GetUserName = function()
{
	return this.m_sUserName;
};
CCommentData.prototype.SetUserName = function(sUserName)
{
	this.m_sUserName = sUserName;
};
CCommentData.prototype.GetDateTime = function()
{
	var nTime = parseInt(this.m_sTime);
	if (isNaN(nTime))
		nTime = 0;

	return nTime;
};
CCommentData.prototype.GetRepliesCount = function()
{
	return this.Get_RepliesCount();
};
CCommentData.prototype.GetReply = function(nIndex)
{
	return this.Get_Reply(nIndex);
};
CCommentData.prototype.GetText = function()
{
	return this.Get_Text();
};
CCommentData.prototype.SetText = function(sText)
{
	this.m_sText = sText;
};
CCommentData.prototype.GetQuoteText = function()
{
	return this.Get_QuoteText();
};
CCommentData.prototype.IsSolved = function()
{
	return this.m_bSolved;
};

function CCommentDrawingRect(X, Y, W, H, CommentId, InvertTransform)
{
    this.X = X;
    this.Y = Y;
    this.H = H;
    this.W = W;
    this.CommentId = CommentId;
    this.InvertTransform = InvertTransform;
}

var comment_type_Common = 1; // Комментарий к обычному тексу
var comment_type_HdrFtr = 2; // Комментарий к колонтитулу

function CComment(Parent, Data)
{
    this.Id     = AscCommon.g_oIdCounter.Get_NewId();

    this.Parent = Parent;
    this.Data   = Data;

    this.m_oTypeInfo =
    {
        Type : comment_type_Common,
        Data : null
    };
    
    this.StartId = null; // Id объекта, в содержимом которого идет начало комментария
    this.EndId   = null; // Id объекта, в содержимом которого идет конец комментария

    this.m_oStartInfo =
    {
        X       : 0,
        Y       : 0,
        H       : 0,
        PageNum : 0
    };

    this.Lock = new AscCommon.CLock(); // Зажат ли комментарий другим пользователем
    if ( false === AscCommon.g_oIdCounter.m_bLoad )
    {
        this.Lock.Set_Type( AscCommon.locktype_Mine, false );
        AscCommon.CollaborativeEditing.Add_Unlock2( this );
    }
    
    this.Copy = function()
    {
        return new CComment(this.Parent, this.Data.Copy());
    };
    
    this.Set_StartId = function(ObjId)
    {
        this.StartId = ObjId;        
    };
    
    this.Set_EndId = function(ObjId)
    {
        this.EndId = ObjId;
    };
    
    this.Set_StartInfo = function(PageNum, X, Y, H)
    {
        this.m_oStartInfo.X       = X;
        this.m_oStartInfo.Y       = Y;
        this.m_oStartInfo.H       = H;
        this.m_oStartInfo.PageNum = PageNum;        
    };

	this.Set_Data = function(Data)
	{
		History.Add(new CChangesCommentChange(this, this.Data, Data));
		this.Data = Data;
	};

    this.Remove_Marks = function()
    {
        var ObjStart = g_oTableId.Get_ById(this.StartId);
        var ObjEnd   = g_oTableId.Get_ById(this.EndId);

        if ( ObjStart === ObjEnd )
        {
            if ( null != ObjStart )
                ObjStart.RemoveCommentMarks( this.Id );
        }
        else
        {
            if ( null != ObjStart )
                ObjStart.RemoveCommentMarks( this.Id );

            if ( null != ObjEnd )
                ObjEnd.RemoveCommentMarks( this.Id );
        }
    };

    this.Set_TypeInfo = function(Type, Data)
    {
        var New =
        {
            Type : Type,
            Data : Data
        };

        History.Add(new CChangesCommentTypeInfo(this, this.m_oTypeInfo, New));

        this.m_oTypeInfo = New;

        if ( comment_type_HdrFtr === Type )
        {
            // Проставим начальные значения страниц (это текущий номер страницы, на котором произошло добавление комментария)
            var PageNum = Data.Content.Get_StartPage_Absolute();
            this.m_oStartInfo.PageNum = PageNum;
        }
    };

    this.Get_TypeInfo = function()
    {
        return this.m_oTypeInfo;
    };
//-----------------------------------------------------------------------------------
// Undo/Redo функции
//-----------------------------------------------------------------------------------
    this.Refresh_RecalcData = function(Data)
    {
        // Ничего не делаем (если что просто будет перерисовка)
    };
//-----------------------------------------------------------------------------------
// Функции для работы с совместным редактированием
//-----------------------------------------------------------------------------------
    this.Get_Id = function()
    {
        return this.Id;
    };

    this.Write_ToBinary2 = function(Writer)
    {
        Writer.WriteLong( AscDFH.historyitem_type_Comment );

        // String   : Id
        // Variable : Data
        // Long     : m_oTypeInfo.Type
        //          : m_oTypeInfo.Data
        //    Если comment_type_HdrFtr
        //    String : Id колонтитула

        Writer.WriteString2( this.Id );
        this.Data.Write_ToBinary2(Writer);
        Writer.WriteLong( this.m_oTypeInfo.Type );

        if ( comment_type_HdrFtr === this.m_oTypeInfo.Type )
            Writer.WriteString2( this.m_oTypeInfo.Data.Get_Id() );
    };

    this.Read_FromBinary2 = function(Reader)
    {
        // String   : Id
        // Variable : Data
        // Long     : m_oTypeInfo.Type
        //          : m_oTypeInfo.Data
        //    Если comment_type_HdrFtr
        //    String : Id колонтитула

        this.Id = Reader.GetString2();
        this.Data = new CCommentData();
        this.Data.Read_FromBinary2(Reader);
        this.m_oTypeInfo.Type = Reader.GetLong();
        if ( comment_type_HdrFtr === this.m_oTypeInfo.Type )
            this.m_oTypeInfo.Data = g_oTableId.Get_ById( Reader.GetString2() );
    };

    this.Check_MergeData = function(arrAllParagraphs)
    {
        // Проверяем, не удалили ли мы параграф, к которому был сделан данный комментарий
        // Делаем это в самом конце, а не сразу, чтобы заполнились данные о начальном и
        // конечном параграфах.

		this.Set_StartId(null);
		this.Set_EndId(null);

		var bStartSet = false, bEndSet = false;
        for (var nIndex = 0, nCount = arrAllParagraphs.length; nIndex < nCount; ++nIndex)
		{
			var oPara   = arrAllParagraphs[nIndex];
			var oResult = oPara.CheckCommentStartEnd(this.Id);
			if (true === oResult.Start)
			{
				this.Set_StartId(oPara.Get_Id());
				bStartSet = true;
			}

			if (true === oResult.End)
			{
				this.Set_EndId(oPara.Get_Id());
				bEndSet = true;
			}

			if (bStartSet && bEndSet)
				break;
		}

		var bUse = true;
		if (null != this.StartId)
		{
			var ObjStart = g_oTableId.Get_ById(this.StartId);

			if (true != ObjStart.Is_UseInDocument())
				bUse = false;
		}

		if (true === bUse && null != this.EndId)
		{
			var ObjEnd = g_oTableId.Get_ById(this.EndId);

			if (true != ObjEnd.Is_UseInDocument())
				bUse = false;
		}

        if ( false === bUse )
            editor.WordControl.m_oLogicDocument.RemoveComment( this.Id, true, false );
    };

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    g_oTableId.Add( this, this.Id );
}
CComment.prototype.GetData = function()
{
	return this.Data;
};
CComment.prototype.IsSolved = function()
{
	if (this.Data)
		return this.Data.IsSolved();

	return false;
};

var comments_NoComment        = 0;
var comments_NonActiveComment = 1;
var comments_ActiveComment    = 2;

function CComments()
{
    this.Id     = AscCommon.g_oIdCounter.Get_NewId();

    this.m_bUse       = false; // Используются ли комментарии
	this.m_bUseSolved = false; // Использовать ли разрешенные комментарии

    this.m_aComments    = {};    // ассоциативный  массив
    this.m_sCurrent     = null;  // текущий комментарий
    
    this.Pages = [];

    this.Get_Id = function()
    {
        return this.Id;
    };

    this.Set_Use = function(Use)
    {
        this.m_bUse = Use;
    };

    this.Is_Use = function()
    {
        return this.m_bUse;
    };

	this.Add = function(Comment)
	{
		var Id = Comment.Get_Id();

		History.Add(new CChangesCommentsAdd(this, Id, Comment));
		this.m_aComments[Id] = Comment;
	};

    this.Get_ById = function(Id)
    {
        if ( "undefined" != typeof(this.m_aComments[Id]) )
            return this.m_aComments[Id];

        return null;
    };

    this.Remove_ById = function(Id)
    {
        if ( "undefined" != typeof(this.m_aComments[Id]) )
        {
            History.Add(new CChangesCommentsRemove(this, Id, this.m_aComments[Id]));

            // Сначала удаляем комментарий из списка комментариев, чтобы данная функция не зацикливалась на вызове Remove_Marks
            var Comment = this.m_aComments[Id];
            delete this.m_aComments[Id];
            Comment.Remove_Marks();
            return true;
        }

        return false;
    };

    this.Reset_Drawing = function(PageNum)
    {
        this.Pages[PageNum] = [];
    };

    this.Add_DrawingRect = function(X, Y, W, H, PageNum, arrCommentId, InvertTransform)
    {
        this.Pages[PageNum].push( new CCommentDrawingRect(X, Y, W, H, arrCommentId, InvertTransform) );
    };

    this.Set_Current = function(Id)
    {
        this.m_sCurrent = Id;
    };

    this.Get_ByXY = function(PageNum, X, Y)
	{
		var Page = this.Pages[PageNum], _X, _Y;
		if (undefined !== Page)
		{
			var Count = Page.length;
			for (var Pos = 0; Pos < Count; Pos++)
			{
				var DrawingRect = Page[Pos];
				if (!DrawingRect.InvertTransform)
				{
					_X = X;
					_Y = Y;
				}
				else
				{
					_X = DrawingRect.InvertTransform.TransformPointX(X, Y);
					_Y = DrawingRect.InvertTransform.TransformPointY(X, Y);
				}
				if (_X >= DrawingRect.X && _X <= DrawingRect.X + DrawingRect.W && _Y >= DrawingRect.Y && _Y <= DrawingRect.Y + DrawingRect.H)
				{
					var arrComments = [];
					for (var nCommentIndex = 0, nCommentsCount = DrawingRect.CommentId.length; nCommentIndex < nCommentsCount; ++nCommentIndex)
					{
						var oComment = this.Get_ById(DrawingRect.CommentId[nCommentIndex]);
						if (oComment)
							arrComments.push(oComment);
					}

					return arrComments;
				}
			}
		}

		return [];
	};

    this.Get_Current = function()
    {
        if ( null != this.m_sCurrent )
        {
            var Comment = this.Get_ById( this.m_sCurrent );
            if ( null != Comment )
                return Comment;
        }

        return null;
    };

    this.Get_CurrentId = function()
    {
        return this.m_sCurrent;
    };

    this.Set_CommentData = function(Id, CommentData)
    {
        var Comment = this.Get_ById( Id );
        if ( null != Comment )
            Comment.Set_Data( CommentData );
    };

    this.Check_MergeData = function()
    {
    	var arrAllParagraphs = null;

        for (var Id in this.m_aComments)
        {
        	if (!arrAllParagraphs && editor && editor.WordControl.m_oLogicDocument)
        		arrAllParagraphs = editor.WordControl.m_oLogicDocument.GetAllParagraphs({All : true});

            this.m_aComments[Id].Check_MergeData(arrAllParagraphs);
        }
    };

//-----------------------------------------------------------------------------------
// Undo/Redo функции
//-----------------------------------------------------------------------------------
    this.Refresh_RecalcData = function(Data)
    {
        // Ничего не делаем, т.к. изменение комментариев не влияет на пересчет
    };

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    g_oTableId.Add( this, this.Id );
}
CComments.prototype.GetAllComments = function()
{
	return this.m_aComments;
};
CComments.prototype.SetUseSolved = function(isUse)
{
	this.m_bUseSolved = isUse;
};
CComments.prototype.IsUseSolved = function()
{
	return this.m_bUseSolved;
};

/**
 * Класс для элемента начала/конца комментария в параграфе
 * @constructor
 * @extends {CParagraphContentBase}
 */
function ParaComment(Start, Id)
{
	CParagraphContentBase.call(this);
    this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.Paragraph = null;

    this.Start     = Start;
    this.CommentId = Id;

    this.Type  = para_Comment;

    this.StartLine  = 0;
    this.StartRange = 0;

    this.Lines = [];
    this.LinesLength = 0;

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    g_oTableId.Add( this, this.Id );
}

ParaComment.prototype = Object.create(CParagraphContentBase.prototype);
ParaComment.prototype.constructor = ParaComment;

ParaComment.prototype.Get_Id = function()
{
	return this.Id;
};
ParaComment.prototype.GetId = function()
{
	return this.Get_Id();
};
ParaComment.prototype.Set_CommentId = function(NewCommentId)
{
	if (this.CommentId !== NewCommentId)
	{
		History.Add(new CChangesParaCommentCommentId(this, this.CommentId, NewCommentId));
		this.CommentId = NewCommentId;
	}
};
ParaComment.prototype.Copy = function(Selected)
{
	return new ParaComment(this.Start, this.CommentId);
};
ParaComment.prototype.Recalculate_Range_Spaces = function(PRSA, CurLine, CurRange, CurPage)
{
	var Para             = PRSA.Paragraph;
	var DocumentComments = Para.LogicDocument.Comments;
	var Comment          = DocumentComments.Get_ById(this.CommentId);
	if (null === Comment)
		return;

	var X    = PRSA.X;
	var Y    = Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent;
	var H    = Para.Lines[CurLine].Metrics.Ascent + Para.Lines[CurLine].Metrics.Descent;
	var Page = Para.Get_StartPage_Absolute() + CurPage;

	if (comment_type_HdrFtr === Comment.m_oTypeInfo.Type)
	{
		var HdrFtr = Comment.m_oTypeInfo.Data;

		if (-1 !== HdrFtr.RecalcInfo.CurPage)
			Page = HdrFtr.RecalcInfo.CurPage;
	}

	if (Para && Para === AscCommon.g_oTableId.Get_ById(Para.Get_Id()))
	{
		// Заглушка для повторяющегося заголовка в таблицах
		if (true === this.Start)
		{
			Comment.Set_StartId(Para.Get_Id());
			Comment.Set_StartInfo(Page, X, Y, H);
		}
		else
		{
			Comment.Set_EndId(Para.Get_Id());
		}
	}
};
ParaComment.prototype.Recalculate_PageEndInfo = function(PRSI, _CurLine, _CurRange)
{
	if (true === this.Start)
		PRSI.AddComment(this.CommentId);
	else
		PRSI.RemoveComment(this.CommentId);
};
ParaComment.prototype.SaveRecalculateObject = function(Copy)
{
	var RecalcObj = new CRunRecalculateObject(this.StartLine, this.StartRange);
	return RecalcObj;
};
ParaComment.prototype.LoadRecalculateObject = function(RecalcObj, Parent)
{
	this.StartLine  = RecalcObj.StartLine;
	this.StartRange = RecalcObj.StartRange;

	var PageNum = Parent.Get_StartPage_Absolute();

	var DocumentComments = editor.WordControl.m_oLogicDocument.Comments;
	var Comment          = DocumentComments.Get_ById(this.CommentId);

	Comment.m_oStartInfo.PageNum = PageNum;
};
ParaComment.prototype.PrepareRecalculateObject = function()
{
};
ParaComment.prototype.Shift_Range = function(Dx, Dy, _CurLine, _CurRange)
{
	var DocumentComments = editor.WordControl.m_oLogicDocument.Comments;
	var Comment          = DocumentComments.Get_ById(this.CommentId);
	if (null === Comment)
		return;

	if (true === this.Start)
	{
		Comment.m_oStartInfo.X += Dx;
		Comment.m_oStartInfo.Y += Dy;
	}
};
ParaComment.prototype.Draw_HighLights = function(PDSH)
{
	if (true === this.Start)
		PDSH.AddComment(this.CommentId);
	else
		PDSH.RemoveComment(this.CommentId);
};
ParaComment.prototype.Refresh_RecalcData = function()
{
};
ParaComment.prototype.Write_ToBinary2 = function(Writer)
{
	Writer.WriteLong(AscDFH.historyitem_type_CommentMark);

	// String   : Id
	// String   : Id комментария
	// Bool     : Start

	Writer.WriteString2("" + this.Id);
	Writer.WriteString2("" + this.CommentId);
	Writer.WriteBool(this.Start);
};
ParaComment.prototype.Read_FromBinary2 = function(Reader)
{
	this.Id        = Reader.GetString2();
	this.CommentId = Reader.GetString2();
	this.Start     = Reader.GetBool();
};
ParaComment.prototype.SetCommentId = function(sCommentId)
{
	this.Set_CommentId(sCommentId);
};
ParaComment.prototype.GetCommentId = function()
{
	return this.CommentId;
};
ParaComment.prototype.IsCommentStart = function()
{
	return this.Start;
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommon'] = window['AscCommon'] || {};

window['AscCommon'].CCommentData = CCommentData;
window['AscCommon'].CComments    = CComments;
window['AscCommon'].CComment     = CComment;
window['AscCommon'].ParaComment  = ParaComment;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 08.11.2016
 * Time: 15:59
 */

AscDFH.changesFactory[AscDFH.historyitem_Comment_Change]   = CChangesCommentChange;
AscDFH.changesFactory[AscDFH.historyitem_Comment_TypeInfo] = CChangesCommentTypeInfo;

AscDFH.changesFactory[AscDFH.historyitem_Comments_Add]    = CChangesCommentsAdd;
AscDFH.changesFactory[AscDFH.historyitem_Comments_Remove] = CChangesCommentsRemove;

AscDFH.changesFactory[AscDFH.historyitem_ParaComment_CommentId] = CChangesParaCommentCommentId;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_Comment_Change]        = [AscDFH.historyitem_Comment_Change];
AscDFH.changesRelationMap[AscDFH.historyitem_Comment_TypeInfo]      = [AscDFH.historyitem_Comment_TypeInfo];
AscDFH.changesRelationMap[AscDFH.historyitem_Comments_Add]          = [
	AscDFH.historyitem_Comments_Add,
	AscDFH.historyitem_Comments_Remove
];
AscDFH.changesRelationMap[AscDFH.historyitem_Comments_Remove]       = [
	AscDFH.historyitem_Comments_Add,
	AscDFH.historyitem_Comments_Remove
];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaComment_CommentId] = [AscDFH.historyitem_ParaComment_CommentId];
//----------------------------------------------------------------------------------------------------------------------

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesCommentChange(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesCommentChange.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesCommentChange.prototype.constructor = CChangesCommentChange;
CChangesCommentChange.prototype.Type = AscDFH.historyitem_Comment_Change;
CChangesCommentChange.prototype.WriteToBinary = function(Writer)
{
	// Variable : New data
	// Variable : Old data

	this.New.Write_ToBinary2(Writer);
	this.Old.Write_ToBinary2(Writer);
};
CChangesCommentChange.prototype.ReadFromBinary = function(Reader)
{
	// Variable : New data
	// Variable : Old data

	this.New = new AscCommon.CCommentData();
	this.Old = new AscCommon.CCommentData();
	this.New.Read_FromBinary2(Reader);
	this.Old.Read_FromBinary2(Reader);
};
CChangesCommentChange.prototype.private_SetValue = function(Value)
{
	this.Class.Data = Value;
	editor.sync_ChangeCommentData(this.Class.Id, Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesCommentTypeInfo(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesCommentTypeInfo.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesCommentTypeInfo.prototype.constructor = CChangesCommentTypeInfo;
CChangesCommentTypeInfo.prototype.Type = AscDFH.historyitem_Comment_TypeInfo;
CChangesCommentTypeInfo.prototype.WriteToBinary = function(Writer)
{
	// Variable : New data
	// Variable : Old data

	Writer.WriteLong(this.New.Type);
	if (comment_type_HdrFtr === this.New.Type)
		Writer.WriteString2(this.New.Data.Get_Id());

	Writer.WriteLong(this.Old.Type);
	if (comment_type_HdrFtr === this.Old.Type)
		Writer.WriteString2(this.Old.Data.Get_Id());
};
CChangesCommentTypeInfo.prototype.ReadFromBinary = function(Reader)
{
	// Variable : New data
	// Variable : Old data

	this.New = {
		Type : 0,
		Data : null
	};

	this.Old = {
		Type : 0,
		Data : null
	};

	this.New.Type = Reader.GetLong();
	if (comment_type_HdrFtr === this.New.Type)
		this.New.Data = AscCommon.g_oTableId.Get_ById(Reader.GetString2());

	this.Old.Type = Reader.GetLong();
	if (comment_type_HdrFtr === this.Old.Type)
		this.Old.Data = AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesCommentTypeInfo.prototype.private_SetValue = function(Value)
{
	this.Class.m_oTypeInfo = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesCommentsAdd(Class, Id, Comment)
{
	AscDFH.CChangesBase.call(this, Class);

	this.Id      = Id;
	this.Comment = Comment;
}
CChangesCommentsAdd.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesCommentsAdd.prototype.constructor = CChangesCommentsAdd;
CChangesCommentsAdd.prototype.Type = AscDFH.historyitem_Comments_Add;
CChangesCommentsAdd.prototype.Undo = function()
{
	var oComments = this.Class;
	delete oComments.m_aComments[this.Id];
	editor.sync_RemoveComment(this.Id);
};
CChangesCommentsAdd.prototype.Redo = function()
{
	this.Class.m_aComments[this.Id] = this.Comment;
	editor.sync_AddComment(this.Id, this.Comment.Data);
};
CChangesCommentsAdd.prototype.WriteToBinary = function(Writer)
{
	// String : Id комментария
	Writer.WriteString2(this.Id);
};
CChangesCommentsAdd.prototype.ReadFromBinary = function(Reader)
{
	// String : Id комментария
	this.Id      = Reader.GetString2();
	this.Comment = AscCommon.g_oTableId.Get_ById(this.Id);
};
CChangesCommentsAdd.prototype.CreateReverseChange = function()
{
	return new CChangesCommentsRemove(this.Class, this.Id, this.Comment);
};
CChangesCommentsAdd.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if ((AscDFH.historyitem_Comments_Add === oChange.Type || AscDFH.historyitem_Comments_Remove === oChange.Type) && this.Id === oChange.Id)
		return false;

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesCommentsRemove(Class, Id, Comment)
{
	AscDFH.CChangesBase.call(this, Class);

	this.Id      = Id;
	this.Comment = Comment;
}
CChangesCommentsRemove.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesCommentsRemove.prototype.constructor = CChangesCommentsRemove;
CChangesCommentsRemove.prototype.Type = AscDFH.historyitem_Comments_Remove;
CChangesCommentsRemove.prototype.Undo = function()
{
	this.Class.m_aComments[this.Id] = this.Comment;
	editor.sync_AddComment(this.Id, this.Comment.Data);
};
CChangesCommentsRemove.prototype.Redo = function()
{
	delete this.Class.m_aComments[this.Id];
	editor.sync_RemoveComment(this.Id);
};
CChangesCommentsRemove.prototype.WriteToBinary = function(Writer)
{
	// String : Id комментария
	Writer.WriteString2(this.Id);
};
CChangesCommentsRemove.prototype.ReadFromBinary = function(Reader)
{
	// String : Id комментария
	this.Id      = Reader.GetString2();
	this.Comment = AscCommon.g_oTableId.Get_ById(this.Id);
};
CChangesCommentsRemove.prototype.CreateReverseChange = function()
{
	return new CChangesCommentsAdd(this.Class, this.Id, this.Comment);
};
CChangesCommentsRemove.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if ((AscDFH.historyitem_Comments_Add === oChange.Type || AscDFH.historyitem_Comments_Remove === oChange.Type) && this.Id === oChange.Id)
		return false;

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaCommentCommentId(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesParaCommentCommentId.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaCommentCommentId.prototype.constructor = CChangesParaCommentCommentId;
CChangesParaCommentCommentId.prototype.Type = AscDFH.historyitem_ParaComment_CommentId;
CChangesParaCommentCommentId.prototype.WriteToBinary = function(Writer)
{
	// String : New Id
	// String : Old Id
	Writer.WriteString2(this.New);
	Writer.WriteString2(this.Old);
};
CChangesParaCommentCommentId.prototype.ReadFromBinary = function(Reader)
{
	// String : New Id
	// String : Old Id

	this.New = Reader.GetString2();
	this.Old = Reader.GetString2();
};
CChangesParaCommentCommentId.prototype.private_SetValue = function(Value)
{
	this.Class.CommentId = Value;
};
CChangesParaCommentCommentId.prototype.Load = function()
{
	this.Redo();

	var Comment = AscCommon.g_oTableId.Get_ById(this.New);
	if (null !== this.Class.Paragraph && null !== Comment && Comment instanceof CComment)
	{
		if (true === this.Class.Start)
			Comment.Set_StartId(this.Class.Paragraph.Get_Id());
		else
			Comment.Set_EndId(this.Class.Paragraph.Get_Id());
	}
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 11.10.2017
 * Time: 13:47
 */

/**
 *
 * @constructor
 * @extends {CParagraphContentBase}
 */
function CParagraphBookmark(isStart, sBookmarkId, sBookmarkName)
{
	CParagraphContentBase.call(this);
	this.Id = AscCommon.g_oIdCounter.Get_NewId();

	this.Type         = para_Bookmark;
	this.Start        = isStart ? true : false;
	this.BookmarkId   = sBookmarkId;
	this.BookmarkName = sBookmarkName;
	this.Use          = true;
	this.PageAbs      = 1;
	this.X            = 0;
	this.Y            = 0;

	AscCommon.g_oTableId.Add(this, this.Id);
}

CParagraphBookmark.prototype = Object.create(CParagraphContentBase.prototype);
CParagraphBookmark.prototype.constructor = CParagraphBookmark;

CParagraphBookmark.prototype.Get_Id = function()
{
	return this.Id;
};
CParagraphBookmark.prototype.GetId = function()
{
	return this.Id;
};
CParagraphBookmark.prototype.Copy = function()
{
	return new CParagraphBookmark(this.Start, this.BookmarkId, this.BookmarkName);
};
CParagraphBookmark.prototype.GetBookmarkId = function()
{
	return this.BookmarkId;
};
CParagraphBookmark.prototype.GetBookmarkName = function()
{
	return this.BookmarkName;
};
CParagraphBookmark.prototype.IsUse = function()
{
	return this.Use;
};
CParagraphBookmark.prototype.SetUse = function(isUse)
{
	this.Use = isUse;
};
CParagraphBookmark.prototype.UpdateBookmarks = function(oManager)
{
	oManager.ProcessBookmarkChar(this);
};
CParagraphBookmark.prototype.IsStart = function()
{
	return this.Start;
};
CParagraphBookmark.prototype.Recalculate_Range = function(PRS, ParaPr)
{
	this.PageAbs = PRS.Paragraph.Get_AbsolutePage(PRS.Page);

	this.X = PRS.X;
	this.Y = PRS.Y;
};
CParagraphBookmark.prototype.GetPage = function()
{
	return this.PageAbs;
};
CParagraphBookmark.prototype.GetXY = function()
{
	return {X : this.X, Y : this.Y};
};
CParagraphBookmark.prototype.GoToBookmark = function()
{
	var oParagraph = this.Paragraph;
	if (!oParagraph)
		return;

	var oLogicDocument = oParagraph.LogicDocument;
	if (!oLogicDocument)
		return;

	var oCurPos = oParagraph.Get_PosByElement(this);
	if (!oCurPos)
		return;

	oLogicDocument.RemoveSelection();
	oParagraph.Set_ParaContentPos(oCurPos, false, -1, -1, true); // Корректировать позицию нужно обязательно
	oParagraph.Document_SetThisElementCurrent(true);
};
CParagraphBookmark.prototype.RemoveBookmark = function()
{
	var oParagraph = this.Paragraph;
	if (!oParagraph)
		return;

	var oCurPos = oParagraph.Get_PosByElement(this);
	if (!oCurPos)
		return;

	var oParent      = this.GetParent();
	var nPosInParent = this.GetPosInParent(oParent);

	if (!oParent || -1 === nPosInParent)
		return;

	oParent.Remove_FromContent(nPosInParent, 1);
};
//----------------------------------------------------------------------------------------------------------------------
// Функции совместного редактирования
//----------------------------------------------------------------------------------------------------------------------
CParagraphBookmark.prototype.Refresh_RecalcData = function()
{
};
CParagraphBookmark.prototype.Write_ToBinary2 = function(Writer)
{
	Writer.WriteLong(AscDFH.historyitem_type_ParaBookmark);

	// String   : Id
	// String   : Id закладки
	// String   : Имя закладки
	// Bool     : Start

	Writer.WriteString2("" + this.Id);
	Writer.WriteString2("" + this.BookmarkId);
	Writer.WriteString2(this.BookmarkName);
	Writer.WriteBool(this.Start);
};
CParagraphBookmark.prototype.Read_FromBinary2 = function(Reader)
{
	this.Id           = Reader.GetString2();
	this.BookmarkId   = Reader.GetString2();
	this.BookmarkName = Reader.GetString2();
	this.Start        = Reader.GetBool();
};


function CBookmarksManager(oLogicDocument)
{
	this.LogicDocument = oLogicDocument;

	// Список всех закладок
	this.Bookmarks = [];

	// Массив с временными элементами
	this.BookmarksChars = {};

	// Нужно ли обновлять список закладок
	this.NeedUpdate = true;

	this.IdCounter    = 0;
	this.IdCounterTOC = 0;
}
CBookmarksManager.prototype.SetNeedUpdate = function(isNeed)
{
	this.NeedUpdate = isNeed;
};
CBookmarksManager.prototype.IsNeedUpdate = function()
{
	return this.NeedUpdate;
};
CBookmarksManager.prototype.BeginCollectingProcess = function()
{
	this.Bookmarks      = [];
	this.BookmarksChars = {};

	this.IdCounter    = 0;
	this.IdCounterTOC = 0;
};
CBookmarksManager.prototype.ProcessBookmarkChar = function(oParaBookmark)
{
	if (!(oParaBookmark instanceof CParagraphBookmark))
		return;

	var sBookmarkId = oParaBookmark.GetBookmarkId();
	if (undefined !== this.BookmarksChars[sBookmarkId])
	{
		if (oParaBookmark.IsStart())
		{
			oParaBookmark.SetUse(false);
		}
		else
		{
			this.BookmarksChars[sBookmarkId].SetUse(true);
			oParaBookmark.SetUse(true);
			this.Bookmarks.push([this.BookmarksChars[sBookmarkId], oParaBookmark]);
			delete this.BookmarksChars[sBookmarkId];
		}
	}
	else
	{
		if (!oParaBookmark.IsStart())
			oParaBookmark.SetUse(false);
		else
			this.BookmarksChars[sBookmarkId] = oParaBookmark;
	}

	if (oParaBookmark.IsStart())
	{
		var sBookmarkName = oParaBookmark.GetBookmarkName();
		if (sBookmarkName && 0 === sBookmarkName.indexOf("_Toc"))
		{
			var nId = parseInt(sBookmarkName.substring(4));
			if (!isNaN(nId))
				this.IdCounterTOC = Math.max(this.IdCounterTOC, nId);
		}

		var nId = parseInt(sBookmarkId);
		if (!isNaN(nId))
			this.IdCounter = Math.max(this.IdCounter, nId);
	}
};
CBookmarksManager.prototype.EndCollectingProcess = function()
{
	for (var sId in this.BookmarksChars)
	{
		this.BookmarksChars[sId].SetUse(false);
	}

	this.BookmarksChars = {};

	this.NeedUpdate = false;
};
CBookmarksManager.prototype.GetBookmarkById = function(Id)
{
	this.Update();

	for (var nIndex = 0, nCount = this.Bookmarks.length; nIndex < nCount; ++nIndex)
	{
		if (this.Bookmarks[nIndex].GetBookmarkId() === Id)
			return this.Bookmarks[nIndex];
	}

	return null;
};
CBookmarksManager.prototype.GetBookmarkByName = function(sName)
{
	this.Update();

	for (var nIndex = 0, nCount = this.Bookmarks.length; nIndex < nCount; ++nIndex)
	{
		var oStart = this.Bookmarks[nIndex][0];
		if (oStart.GetBookmarkName() === sName)
			return this.Bookmarks[nIndex];
	}

	return null;
};
CBookmarksManager.prototype.HaveBookmark = function(sName)
{
	this.Update();

	for (var nIndex = 0, nCount = this.Bookmarks.length; nIndex < nCount; ++nIndex)
	{
		var oStart = this.Bookmarks[nIndex][0];
		if (oStart.GetBookmarkName() === sName)
			return true;
	}

	return false;
};
CBookmarksManager.prototype.Update = function()
{
	if (this.NeedUpdate)
		this.LogicDocument.UpdateBookmarks();
};
CBookmarksManager.prototype.GetNewBookmarkId = function()
{
	this.Update();

	return ("" + ++this.IdCounter);
};
CBookmarksManager.prototype.GetNewBookmarkNameTOC = function()
{
	this.Update();

	return ("_Toc" + ++this.IdCounterTOC);
};
CBookmarksManager.prototype.RemoveTOCBookmarks = function()
{
	this.Update();

	for (var nIndex = 0, nCount = this.Bookmarks.length; nIndex < nCount; ++nIndex)
	{
		var oStart = this.Bookmarks[nIndex][0];
		var oEnd   = this.Bookmarks[nIndex][1];

		if (0 === oStart.GetBookmarkName().toLowerCase().indexOf("_toc"))
		{
			oStart.RemoveBookmark();
			oEnd.RemoveBookmark();
		}
	}
};
CBookmarksManager.prototype.GetCount = function()
{
	this.Update();

	return this.Bookmarks.length;
};
CBookmarksManager.prototype.GetName = function(nIndex)
{
	this.Update();

	if (nIndex < 0 || this.Index >= this.Bookmarks.length)
		return "";

	return this.Bookmarks[nIndex][0].GetBookmarkName();
};
CBookmarksManager.prototype.GetId = function(nIndex)
{
	this.Update();

	if (nIndex < 0 || this.Index >= this.Bookmarks.length)
		return "";

	return this.Bookmarks[nIndex][0].GetBookmarkId();
};
CBookmarksManager.prototype.RemoveBookmark = function(sName)
{
	this.Update();

	if (!this.GetBookmarkByName(sName))
		return;

	this.LogicDocument.RemoveBookmark(sName);
};
CBookmarksManager.prototype.AddBookmark = function(sName)
{
	this.Update();

	if (this.GetBookmarkByName(sName))
		return;

	this.LogicDocument.AddBookmark(sName);
};
CBookmarksManager.prototype.GoToBookmark = function(sName)
{
	this.Update();

	var oBookmark = this.GetBookmarkByName(sName);
	if (oBookmark)
		oBookmark[0].GoToBookmark();
};
CBookmarksManager.prototype.IsHiddenBookmark = function(sName)
{
	return (sName && '_' === sName.charAt(0));
};
CBookmarksManager.prototype.IsInternalUseBookmark = function(sName)
{
	return (sName === "_GoBack");
};
CBookmarksManager.prototype.CheckNewBookmarkName = function(sName)
{
	if (!sName)
		return false;

	return (sName === XRegExp.match(sName, new XRegExp('(\\pL)(\\pL|\_|\\pN){0,39}')));
};
CBookmarksManager.prototype.GetNameForHeadingBookmark = function(oParagraph)
{
	if (!oParagraph)
		return "";

	var sText = oParagraph.GetText();

	var nStartPos = 0;
	while (nStartPos < sText.length)
	{
		var nChar = sText.charCodeAt(nStartPos);
		if (0x0020 !== nChar && 0x0009 !== nChar)
			break;

		nStartPos++;
	}

	var sName = "";
	for (var nIndex = nStartPos, nLen = Math.min(sText.length, nStartPos + 10); nIndex < nLen; ++nIndex)
	{
		var nChar = sText.charCodeAt(nIndex);
		if (0x0020 === nChar || 0x0009 === nChar)
			sName += "_";
		else
			sName += sText.charAt(nIndex);
	}

	if (!sName)
		return "";

	return "_" + sName;
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CParagraphBookmark = CParagraphBookmark;
CBookmarksManager.prototype['asc_GetCount']              = CBookmarksManager.prototype.GetCount;
CBookmarksManager.prototype['asc_GetName']               = CBookmarksManager.prototype.GetName;
CBookmarksManager.prototype['asc_GetId']                 = CBookmarksManager.prototype.GetId;
CBookmarksManager.prototype['asc_AddBookmark']           = CBookmarksManager.prototype.AddBookmark;
CBookmarksManager.prototype['asc_RemoveBookmark']        = CBookmarksManager.prototype.RemoveBookmark;
CBookmarksManager.prototype['asc_GoToBookmark']          = CBookmarksManager.prototype.GoToBookmark;
CBookmarksManager.prototype['asc_HaveBookmark']          = CBookmarksManager.prototype.HaveBookmark;
CBookmarksManager.prototype['asc_IsHiddenBookmark']      = CBookmarksManager.prototype.IsHiddenBookmark;
CBookmarksManager.prototype['asc_IsInternalUseBookmark'] = CBookmarksManager.prototype.IsInternalUseBookmark;
CBookmarksManager.prototype['asc_CheckNewBookmarkName']  = CBookmarksManager.prototype.CheckNewBookmarkName;




/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var align_Left = AscCommon.align_Left;
var g_oTableId = AscCommon.g_oTableId;
var History = AscCommon.History;

var linerule_Auto = Asc.linerule_Auto;
var c_oAscShdClear = Asc.c_oAscShdClear;
var c_oAscShdNil = Asc.c_oAscShdNil;
var c_oAscDropCap = Asc.c_oAscDropCap;

var EvenAndOddHeaders = false;

var Default_Tab_Stop = 12.5;

var Default_Heading_Font = "Arial";
var Default_Font         = "Arial";

var highlight_None = -1;

var vertalign_Koef_Size  =  0.65;  // Коэффициент изменения размера текста для верхнего и нижнего индексов
var vertalign_Koef_Super =  0.35;  // Позиция верхнего индекса (относительно размера текста)
var vertalign_Koef_Sub   = -0.141; // Позиция нижнего индекса (относительно размера текста)

var smallcaps_Koef = 0.8; // Коэффициент изменения размера шрифта для малых прописных букв

var smallcaps_and_script_koef = vertalign_Koef_Size * smallcaps_Koef; // суммарный коэффициент, когда текст одновременно и в индексе, и написан малыми прописными

var g_dKoef_pt_to_mm = 25.4 / 72;
var g_dKoef_pc_to_mm = g_dKoef_pt_to_mm / 12;
var g_dKoef_in_to_mm = 25.4;
var g_dKoef_twips_to_mm = g_dKoef_pt_to_mm / 20;
var g_dKoef_mm_to_pt = 1 / g_dKoef_pt_to_mm;
var g_dKoef_mm_to_twips = 1 / g_dKoef_twips_to_mm;

var tblwidth_Auto = 0x00;
var tblwidth_Mm   = 0x01;
var tblwidth_Nil  = 0x02;
var tblwidth_Pct  = 0x03;

var tbllayout_Fixed   = 0x00;
var tbllayout_AutoFit = 0x01;

var border_None   = 0x0000;
var border_Single = 0x0001;

var vertalignjc_Top    = 0x00;
var vertalignjc_Center = 0x01;
var vertalignjc_Bottom = 0x02;

var vmerge_Restart  = 0x01;
var vmerge_Continue = 0x02;

var spacing_Auto = -1;

var styletype_Paragraph = 0x01;
var styletype_Numbering = 0x02;
var styletype_Table     = 0x03;
var styletype_Character = 0x04;

var textdirection_LRTB  = 0x00;
var textdirection_TBRL  = 0x01;
var textdirection_BTLR  = 0x02;
var textdirection_LRTBV = 0x03;
var textdirection_TBRLV = 0x04;
var textdirection_TBLRV = 0x05;

function IsEqualStyleObjects(Object1, Object2)
{
    if (undefined === Object1 && undefined === Object2)
        return true;

    if (undefined === Object1 || undefined === Object2)
        return false;

    return Object1.Is_Equal(Object2);
}

function IsEqualNullableFloatNumbers(nNum1, nNum2)
{
	if (undefined === nNum1 && undefined === nNum2)
		return true;

	if (undefined === nNum1 || undefined === nNum2)
		return false;

	return Math.abs(nNum1 - nNum2) < 0.001;
}

function CheckUndefinedToNull(isConvert, Value)
{
	return (true === isConvert && undefined === Value ? null : Value);
}

function CTableStylePr()
{
    this.TextPr      = new CTextPr();
    this.ParaPr      = new CParaPr();
    this.TablePr     = new CTablePr();
    this.TableRowPr  = new CTableRowPr();
    this.TableCellPr = new CTableCellPr();
}

CTableStylePr.prototype =
{
    Merge : function(TableStylePr)
    {
        this.TextPr.Merge( TableStylePr.TextPr );
        this.ParaPr.Merge( TableStylePr.ParaPr );
        this.TablePr.Merge( TableStylePr.TablePr );
        this.TableRowPr.Merge( TableStylePr.TableRowPr );
        this.TableCellPr.Merge( TableStylePr.TableCellPr );
    },

    Copy : function()
    {
        var TableStylePr = new CTableStylePr();
        TableStylePr.TextPr      = this.TextPr.Copy();
        TableStylePr.ParaPr      = this.ParaPr.Copy();
        TableStylePr.TablePr     = this.TablePr.Copy();
        TableStylePr.TableRowPr  = this.TableRowPr.Copy();
        TableStylePr.TableCellPr = this.TableCellPr.Copy();
        return TableStylePr;
    },

    Is_Equal : function(TableStylePr)
    {
        if (true !== this.TextPr.Is_Equal(TableStylePr.TextPr)
            || true !== this.ParaPr.Is_Equal(TableStylePr.ParaPr)
            || true !== this.TablePr.Is_Equal(TableStylePr.TablePr)
            || true !== this.TableRowPr.Is_Equal(TableStylePr.TableRowPr)
            || true !== this.TableCellPr.Is_Equal(TableStylePr.TableCellPr))
            return false;

        return false;
    },

    Check_PresentationPr : function(Theme)
    {
        this.TextPr.Check_PresentationPr();
        this.TableCellPr.Check_PresentationPr(Theme);
    },

    Set_FromObject : function(Obj)
    {
        if ( undefined != Obj.TextPr )
            this.TextPr.Set_FromObject( Obj.TextPr );

        if ( undefined != Obj.ParaPr )
            this.ParaPr.Set_FromObject( Obj.ParaPr );

        if ( undefined != Obj.TablePr )
            this.TablePr.Set_FromObject( Obj.TablePr );

        if ( undefined != Obj.TableRowPr )
            this.TableRowPr.Set_FromObject( Obj.TableRowPr );

        if ( undefined != Obj.TableCellPr )
            this.TableCellPr.Set_FromObject( Obj.TableCellPr );
    },

    Write_ToBinary : function(Writer)
    {
        this.TextPr.Write_ToBinary( Writer );
        this.ParaPr.Write_ToBinary( Writer );
        this.TablePr.Write_ToBinary( Writer );
        this.TableRowPr.Write_ToBinary( Writer );
        this.TableCellPr.Write_ToBinary( Writer );
    },

    Read_FromBinary : function(Reader)
    {
        this.TextPr.Read_FromBinary( Reader );
        this.ParaPr.Read_FromBinary( Reader );
        this.TablePr.Read_FromBinary( Reader );
        this.TableRowPr.Read_FromBinary( Reader );
        this.TableCellPr.Read_FromBinary( Reader );
    },

    Init_Default : function()
    {
        this.TextPr.Init_Default();
        this.ParaPr.Init_Default();
        this.TablePr.Init_Default();
        this.TableRowPr.Init_Default();
        this.TableCellPr.Init_Default();
    }
};

function CStyle(Name, BasedOnId, NextId, type, bNoCreateTablePr)
{
    this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.Name    = Name;
    this.BasedOn = BasedOnId;
    this.Next    = NextId;
    this.Type    = (null != type ? type : styletype_Paragraph);
    this.Link    = null;
    this.Custom  = false;

    this.qFormat        = null;// false
    this.uiPriority     = null;// -1
    this.hidden         = null;// false
    this.semiHidden     = null;// false
    this.unhideWhenUsed = null;// false

    this.TextPr = new CTextPr();
    this.ParaPr = new CParaPr();

    this.TablePr     = new CTablePr();
    this.TableRowPr  = new CTableRowPr();
    this.TableCellPr = new CTableCellPr();

    if(bNoCreateTablePr !== true)
    {
        // Условные типы форматирования стилей таблицы
        this.TableBand1Horz  = new CTableStylePr();
        this.TableBand1Vert  = new CTableStylePr();
        this.TableBand2Horz  = new CTableStylePr();
        this.TableBand2Vert  = new CTableStylePr();
        this.TableFirstCol   = new CTableStylePr();
        this.TableFirstRow   = new CTableStylePr();
        this.TableLastCol    = new CTableStylePr();
        this.TableLastRow    = new CTableStylePr();
        this.TableTLCell     = new CTableStylePr();
        this.TableTRCell     = new CTableStylePr();
        this.TableBLCell     = new CTableStylePr();
        this.TableBRCell     = new CTableStylePr();
        this.TableWholeTable = new CTableStylePr();
    }

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    g_oTableId.Add( this, this.Id );
}

CStyle.prototype =
{
//-----------------------------------------------------------------------------------
// Работаем с Id данного объекта
//-----------------------------------------------------------------------------------
    GetId : function()
    {
        return this.Id;
    },

    Get_Id : function()
    {
        return this.GetId();
    },
//-----------------------------------------------------------------------------------
// Базовые функции для работы со стилем
//-----------------------------------------------------------------------------------
    Copy : function()
    {
        var Style = new CStyle();

        Style.Name           = this.Name;
        Style.BasedOn        = this.BasedOn;
        Style.Next           = this.Next;
        Style.Type           = this.Type;
        Style.qFormat        = this.qFormat       ;
        Style.uiPriority     = this.uiPriority    ;
        Style.hidden         = this.hidden        ;
        Style.semiHidden     = this.semiHidden    ;
        Style.unhideWhenUsed = this.unhideWhenUsed;

        Style.TextPr      = this.TextPr.Copy();
        Style.ParaPr      = this.ParaPr.Copy();
        Style.TablePr     = this.TablePr.Copy();
        Style.TablePr     = this.TablePr.Copy();
        Style.TableRowPr  = this.TableRowPr.Copy();
        Style.TableCellPr = this.TableCellPr.Copy();

        if (undefined !== this.TableBand1Horz)
        {
            Style.TableBand1Horz = this.TableBand1Horz.Copy();
            Style.TableBand1Vert = this.TableBand1Vert.Copy();
            Style.TableBand2Horz = this.TableBand2Horz.Copy();
            Style.TableBand2Vert = this.TableBand2Vert.Copy();
            Style.TableFirstCol  = this.TableFirstCol.Copy();
            Style.TableFirstRow  = this.TableFirstRow.Copy();
            Style.TableLastCol   = this.TableLastCol.Copy();
            Style.TableLastRow   = this.TableLastRow.Copy();
            Style.TableTLCell    = this.TableTLCell.Copy();
            Style.TableTRCell    = this.TableTRCell.Copy();
            Style.TableBLCell    = this.TableBLCell.Copy();
            Style.TableBRCell    = this.TableBRCell.Copy();
            Style.TableWholeTable= this.TableWholeTable.Copy();
        }

        return Style;
    },

	RemapIdReferences : function(OldId, NewId)
	{
		if (OldId === this.BasedOn)
			this.Set_BasedOn(NewId);

		if (OldId === this.Link)
			this.Set_Link(NewId);

		if (OldId === this.Next)
			this.Set_Next(NewId);
	},

	Set_TextPr : function(Value)
	{
		var Old = this.TextPr;
		var New = new CTextPr();
		New.Set_FromObject(Value);

		this.TextPr = New;

		History.Add(new CChangesStyleTextPr(this, Old, New));
	},

	Set_ParaPr : function(Value)
	{
		var Old = this.ParaPr;
		var New = new CParaPr();
		New.Set_FromObject(Value);

		this.ParaPr = New;

		History.Add(new CChangesStyleParaPr(this, Old, New));
	},

	Set_TablePr : function(Value)
	{
		var Old = this.TablePr;
		var New = new CTablePr();
		New.Set_FromObject(Value);

		this.TablePr = New;

		History.Add(new CChangesStyleTablePr(this, Old, New));
	},

	Set_TableRowPr : function(Value)
	{
		var Old = this.TableRowPr;
		var New = new CTableRowPr();
		New.Set_FromObject(Value);

		this.TableRowPr = New;

		History.Add(new CChangesStyleTableRowPr(this, Old, New));
	},

	Set_TableCellPr : function(Value)
	{
		var Old = this.TableCellPr;
		var New = new CTableCellPr();
		New.Set_FromObject(Value);

		this.TableCellPr = New;

		History.Add(new CChangesStyleTableCellPr(this, Old, New));
	},

	Set_TableBand1Horz : function(Value)
	{
		var Old = this.TableBand1Horz;
		var New = new CTableStylePr();
		New.Set_FromObject(Value);

		this.TableBand1Horz = New;

		History.Add(new CChangesStyleTableBand1Horz(this, Old, New));
	},

	Set_TableBand1Vert : function(Value)
	{
		var Old = this.TableBand1Vert;
		var New = new CTableStylePr();
		New.Set_FromObject(Value);

		this.TableBand1Vert = New;

		History.Add(new CChangesStyleTableBand1Vert(this, Old, New));
	},

    Set_TableBand2Horz : function(Value)
    {
        var Old = this.TableBand2Horz;
        var New = new CTableStylePr();
        New.Set_FromObject(Value);

        this.TableBand2Horz = New;

        History.Add(new CChangesStyleTableBand2Horz(this, Old, New));
    },

	Set_TableBand2Vert : function(Value)
	{
		var Old = this.TableBand2Vert;
		var New = new CTableStylePr();
		New.Set_FromObject(Value);

		this.TableBand2Vert = New;

		History.Add(new CChangesStyleTableBand2Vert(this, Old, New));
	},

	Set_TableFirstCol : function(Value)
	{
		var Old = this.TableFirstCol;
		var New = new CTableStylePr();
		New.Set_FromObject(Value);

		this.TableFirstCol = New;

		History.Add(new CChangesStyleTableFirstCol(this, Old, New));
	},

	Set_TableFirstRow : function(Value)
	{
		var Old = this.TableFirstRow;
		var New = new CTableStylePr();
		New.Set_FromObject(Value);

		this.TableFirstRow = New;

		History.Add(new CChangesStyleTableFirstRow(this, Old, New));
	},

	Set_TableLastCol : function(Value)
	{
		var Old = this.TableLastCol;
		var New = new CTableStylePr();
		New.Set_FromObject(Value);

		this.TableLastCol = New;

		History.Add(new CChangesStyleTableLastCol(this, Old, New));
	},

	Set_TableLastRow : function(Value)
	{
		var Old = this.TableLastRow;
		var New = new CTableStylePr();
		New.Set_FromObject(Value);

		this.TableLastRow = New;

		History.Add(new CChangesStyleTableLastRow(this, Old, New));
	},

	Set_TableTLCell : function(Value)
	{
		var Old = this.TableTLCell;
		var New = new CTableStylePr();
		New.Set_FromObject(Value);

		this.TableTLCell = New;

		History.Add(new CChangesStyleTableTLCell(this, Old, New));
	},

	Set_TableTRCell : function(Value)
	{
		var Old = this.TableTRCell;
		var New = new CTableStylePr();
		New.Set_FromObject(Value);

		this.TableTRCell = New;

		History.Add(new CChangesStyleTableTRCell(this, Old, New));
	},

	Set_TableBLCell : function(Value)
	{
		var Old = this.TableBLCell;
		var New = new CTableStylePr();
		New.Set_FromObject(Value);

		this.TableBLCell = New;

		History.Add(new CChangesStyleTableBLCell(this, Old, New));
	},

	Set_TableBRCell : function(Value)
	{
		var Old = this.TableBRCell;
		var New = new CTableStylePr();
		New.Set_FromObject(Value);

		this.TableBRCell = New;

		History.Add(new CChangesStyleTableBRCell(this, Old, New));
	},

	Set_TableWholeTable : function(Value)
	{
		var Old = this.TableWholeTable;
		var New = new CTableStylePr();
		New.Set_FromObject(Value);

		this.TableWholeTable = New;

		History.Add(new CChangesStyleTableWholeTable(this, Old, New));
	},

	Set_Name : function(Value)
	{
		History.Add(new CChangesStyleName(this, this.Name, Value));
		this.Name = Value;
	},

    Get_Name : function()
    {
        return this.Name;
    },

	Set_BasedOn : function(Value)
	{
		History.Add(new CChangesStyleBasedOn(this, this.BasedOn, Value));
		this.BasedOn = Value;
	},

    Get_BasedOn : function()
    {
        return this.BasedOn;
    },

	Set_Next : function(Value)
	{
		History.Add(new CChangesStyleNext(this, this.Next, Value));
		this.Next = Value;
	},

    Get_Next : function()
    {
        return this.Next;
    },

	Set_Link : function(Value)
	{
		History.Add(new CChangesStyleLink(this, this.Link, Value));
		this.Link = Value;
	},

	Get_Link : function()
	{
		return this.Link;
	},

	Set_Type : function(Value)
	{
		History.Add(new CChangesStyleType(this, this.Type, Value));
		this.Type = Value;
	},

    Get_Type : function()
    {
        return this.Type;
    },

	Set_QFormat : function(Value)
	{
		History.Add(new CChangesStyleQFormat(this, this.qFormat, Value));
		this.qFormat = Value;
	},

	Set_UiPriority : function(Value)
	{
		History.Add(new CChangesStyleUiPriority(this, this.uiPriority, Value));
		this.uiPriority = Value;
	},

	Set_Hidden : function(Value)
	{
		History.Add(new CChangesStyleHidden(this, this.hidden, Value));
		this.hidden = Value;
	},

	Set_SemiHidden : function(Value)
	{
		History.Add(new CChangesStyleSemiHidden(this, this.semiHidden, Value));
		this.semiHidden = Value;
	},

	Set_UnhideWhenUsed : function(Value)
	{
		History.Add(new CChangesStyleUnhideWhenUsed(this, this.unhideWhenUsed, Value));
		this.unhideWhenUsed = Value;
	},

    Clear : function(Name, BasedOnId, NextId, Type)
    {
        this.Set_Name(Name);
        this.Set_BasedOn(BasedOnId);
        this.Set_Next(NextId);
        this.Set_Type(Type);

        if (undefined != this.Link && null != this.Link)
            this.Set_Link(null);

        if (undefined != this.qFormat && null != this.qFormat)
            this.Set_QFormat(null);

        if (undefined != this.uiPriority && null != this.uiPriority)
            this.Set_UiPriority(null);

        if (undefined != this.hidden && null != this.hidden)
            this.Set_Hidden(null);

        if (undefined != this.semiHidden && null != this.semiHidden)
            this.Set_SemiHidden(null);

        if (undefined != this.unhideWhenUsed && null != this.unhideWhenUsed)
            this.Set_UnhideWhenUsed(null);

        this.Set_TextPr(new CTextPr());
        this.Set_ParaPr(new CParaPr());
        this.Set_TablePr(new CTablePr());
        this.Set_TableRowPr(new CTableRowPr());
        this.Set_TableCellPr(new CTableCellPr());

        if (undefined != this.TableBand1Horz ) this.Set_TableBand1Horz (new CTableStylePr());
        if (undefined != this.TableBand1Vert ) this.Set_TableBand1Vert (new CTableStylePr());
        if (undefined != this.TableBand2Horz ) this.Set_TableBand2Horz (new CTableStylePr());
        if (undefined != this.TableBand2Vert ) this.Set_TableBand2Vert (new CTableStylePr());
        if (undefined != this.TableFirstCol  ) this.Set_TableFirstCol  (new CTableStylePr());
        if (undefined != this.TableFirstRow  ) this.Set_TableFirstRow  (new CTableStylePr());
        if (undefined != this.TableLastCol   ) this.Set_TableLastCol   (new CTableStylePr());
        if (undefined != this.TableLastRow   ) this.Set_TableLastRow   (new CTableStylePr());
        if (undefined != this.TableTLCell    ) this.Set_TableTLCell    (new CTableStylePr());
        if (undefined != this.TableTRCell    ) this.Set_TableTRCell    (new CTableStylePr());
        if (undefined != this.TableBLCell    ) this.Set_TableBLCell    (new CTableStylePr());
        if (undefined != this.TableBRCell    ) this.Set_TableBRCell    (new CTableStylePr());
        if (undefined != this.TableWholeTable) this.Set_TableWholeTable(new CTableStylePr());
    },
//-----------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------
    Document_Get_AllFontNames : function(AllFonts)
    {
        if ( undefined != this.TextPr )
            this.TextPr.Document_Get_AllFontNames(AllFonts);
    },

	private_CreateDefaultUnifillColor : function()
	{
		var Unifill        = new AscFormat.CUniFill();
		Unifill.fill       = new AscFormat.CSolidFill();
		Unifill.fill.color = AscFormat.builder_CreateSchemeColor('tx1');
		return Unifill;
	},

    Create_NormalTable : function()
    {
        var TablePr =
        {
            TableInd : 0 ,
            TableCellMar :
            {
                Top :
                {
                    W    : 0,
                    Type : tblwidth_Mm
                },

                Left :
                {
                    W    : 1.9, // 5.4pt
                    Type : tblwidth_Mm
                },

                Bottom :
                {
                    W    : 0,
                    Type : tblwidth_Mm
                },

                Right :
                {
                    W    : 1.9, // 5.4pt
                    Type : tblwidth_Mm
                }
            }
        };

        this.Set_UiPriority( 99 );
        this.Set_SemiHidden( true );
        this.Set_UnhideWhenUsed( true );
        this.Set_TablePr( TablePr );
    },

    Create_TableGrid : function()
    {
        var ParaPr =
        {
            Spacing :
            {
                After    : 0,
                Line     : 1,
                LineRule : linerule_Auto
            }
        };

        var TablePr =
        {
            TableInd : 0,

            TableBorders :
            {
                Top :
                {
                    Color : { r : 0, g : 0, b : 0 },
                    Space : 0,
                    Size  : 0.5 * g_dKoef_pt_to_mm,
                    Value : border_Single
                },

                Left :
                {
                    Color : { r : 0, g : 0, b : 0 },
                    Space : 0,
                    Size  : 0.5 * g_dKoef_pt_to_mm,
                    Value : border_Single
                },

                Bottom :
                {
                    Color : { r : 0, g : 0, b : 0 },
                    Space : 0,
                    Size  : 0.5 * g_dKoef_pt_to_mm,
                    Value : border_Single
                },

                Right :
                {
                    Color : { r : 0, g : 0, b : 0 },
                    Space : 0,
                    Size  : 0.5 * g_dKoef_pt_to_mm,
                    Value : border_Single
                },

                InsideH :
                {
                    Color : { r : 0, g : 0, b : 0 },
                    Space : 0,
                    Size  : 0.5 * g_dKoef_pt_to_mm,
                    Value : border_Single
                },

                InsideV :
                {
                    Color : { r : 0, g : 0, b : 0 },
                    Space : 0,
                    Size  : 0.5 * g_dKoef_pt_to_mm,
                    Value : border_Single
                }
            },

            TableCellMar :
            {
                Top :
                {
                    W    : 0,
                    Type : tblwidth_Mm
                },

                Left :
                {
                    W    : 1.9,
                    Type : tblwidth_Mm
                },

                Bottom :
                {
                    W    : 0,
                    Type : tblwidth_Mm
                },

                Right :
                {
                    W    : 1.9,
                    Type : tblwidth_Mm
                }
            }
        };

        this.Set_UiPriority(59);
        this.Set_TablePr(TablePr);
        this.Set_ParaPr(ParaPr);
    },

    Create_Table_LightShading : function()
    {
        this.uiPriority = 60;

        var ParaPr =
        {
            Spacing :
            {
                After    : 0,
                Line     : 1,
                LineRule : linerule_Auto
            }
        };

        var TablePr =
        {
            TableStyleColBandSize : 1,
            TableStyleRowBandSize : 1,
            TableInd : 0,

            TableBorders :
            {
                Top :
                {
                    Color : { r : 0, g : 0, b : 0 },
                    Space : 0,
                    Size  : 18 / 8 * g_dKoef_pt_to_mm,
                    Value : border_Single
                },

                Bottom :
                {
                    Color : { r : 0, g : 0, b : 0 },
                    Space : 0,
                    Size  : 18 / 8 * g_dKoef_pt_to_mm,
                    Value : border_Single
                }
            },

            TableCellMar :
            {
                Top :
                {
                    W    : 0,
                    Type : tblwidth_Mm
                },
                Left :
                {
                    W    : 5.75 * g_dKoef_pt_to_mm, // 0.08 inch
                    Type : tblwidth_Mm
                },

                Bottom :
                {
                    W    : 0,
                    Type : tblwidth_Mm
                },

                Right :
                {
                    W    : 5.75 * g_dKoef_pt_to_mm, // 0.08 inch
                    Type : tblwidth_Mm
                }
            }
        };

        var TableFirstRow =
        {
            TextPr :
            {
                Bold : true,
                Color :
                {
                    r : 255,
                    g : 255,
                    b : 255
                }
            },

            ParaPr :
            {
                Spacing :
                {
                    After    : 0,
                    Before   : 0,
                    Line     : 1,
                    LineRule : linerule_Auto
                }
            },

            TableCellPr :
            {
                TableCellBorders :
                {
                    Bottom :
                    {
                        Color : { r : 0, g : 0, b : 0 },
                        Space : 0,
                        Size  : 18 / 8 * g_dKoef_pt_to_mm,
                        Value : border_Single
                    },

                    Left :
                    {
                        Value : border_None
                    },

                    Right :
                    {
                        Value : border_None
                    },

                    Top :
                    {
                        Color : { r : 0, g : 0, b : 0 },
                        Space : 0,
                        Size  : 18 / 8 * g_dKoef_pt_to_mm,
                        Value : border_Single
                    }
                },

                Shd :
                {
                    Value : c_oAscShdClear,
                    Color :
                    {
                        r : 0x4F,
                        g : 0x81,
                        b : 0xBD
                    }
                }
            }
        };

        var TableLastRow =
        {
            TextPr :
            {
                Color :
                {
                    r : 0,
                    g : 0,
                    b : 0
                }
            },

            TableCellPr :
            {
                TableCellBorders :
                {
                    Bottom :
                    {
                        Color : { r : 0, g : 0, b : 0 },
                        Space : 0,
                        Size  : 18 / 8 * g_dKoef_pt_to_mm,
                        Value : border_Single
                    },

                    Left :
                    {
                        Value : border_None
                    },

                    Right :
                    {
                        Value : border_None
                    },

                    Top :
                    {
                        Color : { r : 0, g : 0, b : 0 },
                        Space : 0,
                        Size  : 12 / 8 * g_dKoef_pt_to_mm,
                        Value : border_Single
                    }
                },

                Shd :
                {
                    Value : c_oAscShdClear,
                    Color :
                    {
                        r : 0xFF,
                        g : 0xFF,
                        b : 0xFF
                    }
                }
            }
        };

        var TableFirstCol =
        {
            TextPr :
            {
                Bold  : true,
                Color :
                {
                    r : 255,
                    g : 255,
                    b : 255
                }
            },

            ParaPr :
            {
                Spacing :
                {
                    After    : 0,
                    Before   : 0,
                    Line     : 1,
                    LineRule : linerule_Auto
                }
            },

            TableCellPr :
            {
                TableCellBorder :
                {
                    Bottom :
                    {
                        Color : { r : 0, g : 0, b : 0 },
                        Space : 0,
                        Size  : 18 / 8 * g_dKoef_pt_to_mm,
                        Value : border_Single
                    },

                    Left :
                    {
                        Value : border_None
                    },

                    Right :
                    {
                        Value : border_None
                    },

                    Top :
                    {
                        Value : border_None
                    }
                },

                Shd :
                {
                    Value : c_oAscShdClear,
                    Color :
                    {
                        r : 0x4F,
                        g : 0x81,
                        b : 0xBD
                    }
                }
            }

        };

        var TableLastCol =
        {
            TextPr :
            {
                Bold  : true,
                Color :
                {
                    r : 255,
                    g : 255,
                    b : 255
                }
            },

            TableCellPr :
            {
                TableCellBorders :
                {
                    Left :
                    {
                        Value : border_None
                    },

                    Right :
                    {
                        Value : border_None
                    }
                },

                Shd :
                {
                    Value : c_oAscShdClear,
                    Color :
                    {
                        r : 0x4F,
                        g : 0x81,
                        b : 0xBD
                    }
                }
            }
        };

        var TableBand1Vert =
        {
            TableCellPr :
            {
                TableCellBorders :
                {
                    Left :
                    {
                        Value : border_None
                    },

                    Right :
                    {
                        Value : border_None
                    }
                },

                Shd :
                {
                    Value : c_oAscShdClear,
                    Color :
                    {
                        r : 0xD8,
                        g : 0xD8,
                        b : 0xD8
                    }
                }
            }
        };

        var TableBand1Horz =
        {
            TableCellPr :
            {
                Shd :
                {
                    Value : c_oAscShdClear,
                    Color :
                    {
                        r : 0xD8,
                        g : 0xD8,
                        b : 0xD8
                    }
                }
            }
        };

        var TableTRCell =
        {
            TableCellPr :
            {
                TableCellBorders:
                {
                    Bottom :
                    {
                        Color : { r : 0, g : 0, b : 0 },
                        Space : 0,
                        Size  : 18 / 8 * g_dKoef_pt_to_mm,
                        Value : border_Single
                    },

                    Left :
                    {
                        Value : border_None
                    },

                    Right :
                    {
                        Value : border_None
                    },

                    Top :
                    {
                        Color : { r : 0, g : 0, b : 0 },
                        Space : 0,
                        Size  : 18 / 8 * g_dKoef_pt_to_mm,
                        Value : border_Single
                    }
                },

                Shd :
                {
                    Value : c_oAscShdClear,
                    Color :
                    {
                        r : 0,
                        g : 255,
                        b : 0
                    }
                }
            }
        };

        var TableTLCell =
        {
            TextPr :
            {
                Color :
                {
                    r : 255,
                    g : 255,
                    b : 255
                }
            },

            TableCellPr :
            {
                TableCellBorders:
                {
                    Bottom :
                    {
                        Color : { r : 0, g : 0, b : 0 },
                        Space : 0,
                        Size  : 18 / 8 * g_dKoef_pt_to_mm,
                        Value : border_Single
                    },

                    Left :
                    {
                        Value : border_None
                    },

                    Right :
                    {
                        Value : border_None
                    },

                    Top :
                    {
                        Color : { r : 0, g : 0, b : 0 },
                        Space : 0,
                        Size  : 18 / 8 * g_dKoef_pt_to_mm,
                        Value : border_Single
                    }
                }          ,

                Shd :
                {
                    Value : c_oAscShdClear,
                    Color :
                    {
                        r : 255,
                        g : 0,
                        b : 0
                    }
                }
            }
        };

        this.Set_UiPriority( 60 );
        this.Set_ParaPr( ParaPr );
        this.Set_TablePr( TablePr );
        this.Set_TableFirstRow( TableFirstRow );
        this.Set_TableLastRow( TableLastRow );
        this.Set_TableFirstCol( TableFirstCol );
        this.Set_TableLastCol( TableLastCol );
        this.Set_TableBand1Horz( TableBand1Horz );
        this.Set_TableBand1Vert( TableBand1Vert );
        this.Set_TableTRCell( TableTRCell );
        this.Set_TableTLCell( TableTLCell );
    },

    Create_Table_ColorfulListAccent6 : function()
    {
        this.uiPriority = 72;

        var ParaPr =
        {
            Spacing :
            {
                After    : 0,
                Line     : 1,
                LineRule : linerule_Auto
            }
        };

        var TextPr =
        {
            Color : { r : 0, g : 0, b : 0 }
        };

        var TablePr =
        {
            TableStyleColBandSize : 1,
            TableStyleRowBandSize : 1,
            TableInd              : 0,

            TableCellMar :
            {
                TableCellMar :
                {
                    Top :
                    {
                        W    : 0,
                        Type : tblwidth_Mm
                    },
                    Left :
                    {
                        W    : 5.75 * g_dKoef_pt_to_mm, // 0.08 inch
                        Type : tblwidth_Mm
                    },

                    Bottom :
                    {
                        W    : 0,
                        Type : tblwidth_Mm
                    },

                    Right :
                    {
                        W    : 5.75 * g_dKoef_pt_to_mm, // 0.08 inch
                        Type : tblwidth_Mm
                    }
                }
            }
        };

        var TableCellPr =
        {
            Shd :
            {
                Value : c_oAscShdClear,
                Color : { r : 0xFE, g : 0xF4, b : 0xEC }
            }
        };

        var TableFirstRow =
        {
            TextPr :
            {
                Bold  : true,
                Color : { r : 0xFF, g : 0xFF, b : 0xFF }
            },

            TableCellPr :
            {
                TableCellBorders :
                {
                    Bottom :
                    {
                        Color : { r : 0xFF, g : 0xFF, b : 0xFF },
                        Space : 0,
                        Size  : 12 / 8 * g_dKoef_pt_to_mm,
                        Value : border_Single
                    }
                },

                Shd :
                {
                    Value : c_oAscShdClear,
                    Color : { r : 0x34, g : 0x8D, b : 0xA5 }
                }
            }
        };

        var TableLastRow =
        {
            TextPr :
            {
                Bold  : true,
                Color : { r : 0x34, g : 0x8D, b : 0xA5 }
            },

            TableCellPr :
            {
                TableCellBorders :
                {
                    Top :
                    {
                        Color : { r : 0, g : 0, b : 0 },
                        Space : 0,
                        Size  : 12 / 8 * g_dKoef_pt_to_mm,
                        Value : border_Single
                    }
                },

                Shd :
                {
                    Value : c_oAscShdClear,
                    Color : { r : 0xFF, g : 0xFF, b : 0xFF }
                }
            }
        };

        var TableFirstCol =
        {
            TextPr :
            {
                Bold : true
            }
        };

        var TableLastCol =
        {
            TextPr :
            {
                Bold : true
            }
        };

        var TableBand1Vert =
        {
            TableCellPr :
            {
                TableCellBorders :
                {
                    Top     : { Value : border_None },
                    Left    : { Value : border_None },
                    Bottom  : { Value : border_None },
                    Right   : { Value : border_None },
                    InsideH : { Value : border_None },
                    InsideV : { Value : border_None }
                },

                Shd :
                {
                    Value : c_oAscShdClear,
                    Color : { r : 0xFD, g : 0xE4, b : 0xD0 }
                }
            }
        };

        var TableBand1Horz =
        {
            TableCellPr :
            {
                Shd :
                {
                    Value : c_oAscShdClear,
                    Color : { r : 0xFD, g : 0xE9, b : 0xD9 }
                }
            }
        };

        this.Set_UiPriority( 72 );
        this.Set_ParaPr( ParaPr );
        this.Set_TextPr( TextPr );
        this.Set_TablePr( TablePr );
        this.Set_TableCellPr( TableCellPr );
        this.Set_TableFirstRow( TableFirstRow );
        this.Set_TableLastRow( TableLastRow );
        this.Set_TableFirstCol( TableFirstCol );
        this.Set_TableLastCol( TableLastCol );
        this.Set_TableBand1Horz( TableBand1Horz );
        this.Set_TableBand1Vert( TableBand1Vert );
    },

    Create_Table_Lined : function(Color1, Color2)
    {
        var TextColor1 = new CDocumentColor(0xF2, 0xF2, 0xF2, false);
        var TextFont1  = { Name : "Arial", Index : -1 };
        var TextSize1  = 11;

        var CellShd1   = new CDocumentShd();
        CellShd1.Value = c_oAscShdClear;
        CellShd1.Color = new CDocumentColor(Color1.r, Color1.g, Color1.b);

        var TableStylePrBoundary =
        {
            TextPr :
            {
                RFonts   : { Ascii : TextFont1, HAnsi : TextFont1 },
                Color    : TextColor1,
                FontSize : TextSize1
            },

            TableCellPr :
            {
                Shd : CellShd1
            }
        };

        var ParaPr =
        {
            Spacing :
            {
                After    : 0,
                Line     : 1,
                LineRule : linerule_Auto
            },

            Borders :
            {
                Top :
                {
                    Color : { r : 0, g : 0, b : 0, Auto : true },
                    Space : 0,
                    Size  : 0,
                    Value : border_None
                },

                Left :
                {
                    Color : { r : 0, g : 0, b : 0, Auto : true },
                    Space : 0,
                    Size  : 0,
                    Value : border_None
                },

                Bottom :
                {
                    Color : { r : 0, g : 0, b : 0, Auto : true },
                    Space : 0,
                    Size  : 0,
                    Value : border_None
                },

                Right :
                {
                    Color : { r : 0, g : 0, b : 0, Auto : true },
                    Space : 0,
                    Size  : 0,
                    Value : border_None
                },

                Between :
                {
                    Color : { r : 0, g : 0, b : 0, Auto : true },
                    Space : 0,
                    Size  : 0,
                    Value : border_None
                }
            }
        };

        var TextPr =
        {
            Color : { r : 0x40, g : 0x40, b : 0x40 }
        };

        var TablePr =
        {
            TableStyleColBandSize : 1,
            TableStyleRowBandSize : 1,
            TableInd : 0,

            TableCellMar :
            {
                Top    : new CTableMeasurement(tblwidth_Mm, 4.8 * g_dKoef_pt_to_mm),
                Left   : new CTableMeasurement(tblwidth_Mm, 8.5 * g_dKoef_pt_to_mm),
                Bottom : new CTableMeasurement(tblwidth_Mm, 4.8 * g_dKoef_pt_to_mm),
                Right  : new CTableMeasurement(tblwidth_Mm, 8.5 * g_dKoef_pt_to_mm)
            }
        };

        var TableStylePrBand1 =
        {
            TextPr :
            {
                RFonts   : { Ascii : TextFont1, HAnsi : TextFont1 },
                Color    : { r : 0x40, g : 0x40, b : 0x40 },
                FontSize : TextSize1
            }
        };

        var TableStylePrBand2 =
        {
            TextPr :
            {
                RFonts   : { Ascii : TextFont1, HAnsi : TextFont1 },
                Color    : { r : 0x40, g : 0x40, b : 0x40 },
                FontSize : TextSize1
            },

            TableCellPr :
            {
                Shd :
                {
                    Value : c_oAscShdClear,
                    Color : { r : Color2.r, g : Color2.g, b : Color2.b}
                }
            }
        };

        this.Set_UiPriority(99);
        this.Set_ParaPr(ParaPr);
        this.Set_TextPr(TextPr);
        this.Set_TablePr(TablePr);

        this.Set_TableFirstRow(TableStylePrBoundary);
        this.Set_TableLastRow(TableStylePrBoundary);
        this.Set_TableFirstCol(TableStylePrBoundary);
        this.Set_TableLastCol(TableStylePrBoundary);

        this.Set_TableBand1Horz(TableStylePrBand1);
        this.Set_TableBand1Vert(TableStylePrBand1);

        this.Set_TableBand2Horz(TableStylePrBand2);
        this.Set_TableBand2Vert(TableStylePrBand2);
    },

    Create_Table_Bordered : function(Color1, Color2)
    {
        var TableTextPr =
        {
            RFonts   : {Ascii : {Name : "Arial", Index : -1}, HAnsi : {Name : "Arial", Index : -1}},
            Color    : { r : 0x40, g : 0x40, b : 0x40 },
            FontSize : 11
        };

        var ParaPr =
        {
            Spacing :
            {
                After    : 0,
                Line     : 1,
                LineRule : linerule_Auto
            },

            Borders :
            {
                Top :
                {
                    Color : { r : 0, g : 0, b : 0, Auto : true },
                    Space : 0,
                    Size  : 0,
                    Value : border_None
                },

                Left :
                {
                    Color : { r : 0, g : 0, b : 0, Auto : true },
                    Space : 0,
                    Size  : 0,
                    Value : border_None
                },

                Bottom :
                {
                    Color : { r : 0, g : 0, b : 0, Auto : true },
                    Space : 0,
                    Size  : 0,
                    Value : border_None
                },

                Right :
                {
                    Color : { r : 0, g : 0, b : 0, Auto : true },
                    Space : 0,
                    Size  : 0,
                    Value : border_None
                },

                Between :
                {
                    Color : { r : 0, g : 0, b : 0, Auto : true },
                    Space : 0,
                    Size  : 0,
                    Value : border_None
                }
            }
        };

        var TextPr =
        {
            Color : { r : 0x40, g : 0x40, b : 0x40 }
        };

        var TableBorder1 =
        {
            Color : { r : Color1.r, g : Color1.g, b : Color1.b },
            Value : border_Single,
            Size  : 0.5 * g_dKoef_pt_to_mm,
            Space : 0
        };

        var TableBorder2 =
        {
            Color : { r : Color2.r, g : Color2.g, b : Color2.b },
            Value : border_Single,
            Size  : 1.5 * g_dKoef_pt_to_mm,
            Space : 0
        };

        var TablePr =
        {
            TableStyleColBandSize : 1,
            TableStyleRowBandSize : 1,
            TableInd : 0,

            TableBorders :
            {
                Top     : TableBorder1,
                Left    : TableBorder1,
                Bottom  : TableBorder1,
                Right   : TableBorder1,
                InsideH : TableBorder1,
                InsideV : TableBorder1
            },

            TableCellMar :
            {
                Top    : new CTableMeasurement(tblwidth_Mm, 4.8 * g_dKoef_pt_to_mm),
                Left   : new CTableMeasurement(tblwidth_Mm, 8.5 * g_dKoef_pt_to_mm),
                Bottom : new CTableMeasurement(tblwidth_Mm, 4.8 * g_dKoef_pt_to_mm),
                Right  : new CTableMeasurement(tblwidth_Mm, 8.5 * g_dKoef_pt_to_mm)
            }
        };

        var TableFirstRow =
        {
            TextPr : TableTextPr,

            TableCellPr :
            {
                TableCellBorders :
                {
                    Bottom : TableBorder2
                }
            }
        };

        var TableLastRow =
        {
            TextPr      : TableTextPr,
            TableCellPr :
            {
                TableCellBorders :
                {
                    Top : TableBorder2
                }
            }
        };

        var TableFirstCol =
        {
            TextPr      : TableTextPr,
            TableCellPr :
            {
                TableCellBorders :
                {
                    Right : TableBorder2
                }
            }
        };

        var TableLastCol =
        {
            TextPr      : TableTextPr,
            TableCellPr :
            {
                TableCellBorders :
                {
                    Left : TableBorder2
                }
            }
        };

        var TableBand1Horz =
        {
            TextPr : TableTextPr,
            TableCellPr :
            {
                TableCellBorders :
                {
                    Top     : TableBorder1,
                    Left    : TableBorder1,
                    Bottom  : TableBorder1,
                    Right   : TableBorder1,
                    InsideH : TableBorder1,
                    InsideV : TableBorder1
                }
            }
        };

        this.Set_UiPriority(99);
        this.Set_ParaPr(ParaPr);
        this.Set_TablePr(TablePr);
        this.Set_TableFirstRow(TableFirstRow);
        this.Set_TableLastRow(TableLastRow);
        this.Set_TableFirstCol(TableFirstCol);
        this.Set_TableLastCol(TableLastCol);
        this.Set_TableBand1Horz(TableBand1Horz);
    },

    Create_Table_BorderedAndLined : function(TableBorder, TableShdColorBoundary, TableShdColorVertBand, TableShdColorHorzBand)
    {
        var TextPr1 =
        {
            RFonts   : { Ascii : { Name : "Arial", Index : -1 }, HAnsi : { Name : "Arial", Index : -1 } },
            Color    : { r : 0xF2, g : 0xF2, b : 0xF2 },
            FontSize : 11
        };

        var TextPr2 =
        {
            RFonts   : { Ascii : { Name : "Arial", Index : -1 }, HAnsi : { Name : "Arial", Index : -1 } },
            Color    : { r : 0x40, g : 0x40, b : 0x40 },
            FontSize : 11
        };

        var TableCellPr1 =
        {
            Shd :
            {
                Value : c_oAscShdClear,
                Color : { r : TableShdColorBoundary.r, g : TableShdColorBoundary.g, b : TableShdColorBoundary.b}
            }
        };

        var TableCellPrVert =
        {
            Shd :
            {
                Value : c_oAscShdClear,
                Color : { r : TableShdColorVertBand.r, g : TableShdColorVertBand.g, b : TableShdColorVertBand.b}
            }
        };

        var TableCellPrHorz =
        {
            Shd :
            {
                Value : c_oAscShdClear,
                Color : { r : TableShdColorHorzBand.r, g : TableShdColorHorzBand.g, b : TableShdColorHorzBand.b}
            }
        };

        var ParaPr =
        {
            Spacing :
            {
                After    : 0,
                Line     : 1,
                LineRule : linerule_Auto
            },

            Borders :
            {
                Top :
                {
                    Color : { r : 0, g : 0, b : 0, Auto : true },
                    Space : 0,
                    Size  : 0,
                    Value : border_None
                },

                Left :
                {
                    Color : { r : 0, g : 0, b : 0, Auto : true },
                    Space : 0,
                    Size  : 0,
                    Value : border_None
                },

                Bottom :
                {
                    Color : { r : 0, g : 0, b : 0, Auto : true },
                    Space : 0,
                    Size  : 0,
                    Value : border_None
                },

                Right :
                {
                    Color : { r : 0, g : 0, b : 0, Auto : true },
                    Space : 0,
                    Size  : 0,
                    Value : border_None
                },

                Between :
                {
                    Color : { r : 0, g : 0, b : 0, Auto : true },
                    Space : 0,
                    Size  : 0,
                    Value : border_None
                }
            }
        };

        var TextPr =
        {
            Color : { r : 0x40, g : 0x40, b : 0x40 }
        };

        var TableBorder1 =
        {
            Color : { r : TableBorder.r, g : TableBorder.g, b : TableBorder.b },
            Value : border_Single,
            Size  : 0.5 * g_dKoef_pt_to_mm,
            Space : 0
        };

        var TablePr =
        {
            TableStyleColBandSize : 1,
            TableStyleRowBandSize : 1,
            TableInd : 0,

            TableCellMar :
            {
                Top    : new CTableMeasurement(tblwidth_Mm, 4.8 * g_dKoef_pt_to_mm),
                Left   : new CTableMeasurement(tblwidth_Mm, 8.5 * g_dKoef_pt_to_mm),
                Bottom : new CTableMeasurement(tblwidth_Mm, 4.8 * g_dKoef_pt_to_mm),
                Right  : new CTableMeasurement(tblwidth_Mm, 8.5 * g_dKoef_pt_to_mm)
            },

            TableBorders :
            {
                Top     : TableBorder1,
                Left    : TableBorder1,
                Bottom  : TableBorder1,
                Right   : TableBorder1,
                InsideH : TableBorder1,
                InsideV : TableBorder1
            }
        };

        var TableFirstRow =
        {
            TextPr      : TextPr1,
            TableCellPr : TableCellPr1
        };

        var TableLastRow =
        {
            TextPr      : TextPr1,
            TableCellPr : TableCellPr1
        };

        var TableFirstCol =
        {
            TextPr      : TextPr1,
            TableCellPr : TableCellPr1
        };

        var TableLastCol =
        {
            TextPr      : TextPr1,
            TableCellPr : TableCellPr1
        };

        var TableBand1Vert =
        {
            TextPr : TextPr2
        };

        var TableBand2Vert =
        {
            TextPr      : TextPr2,
            TableCellPr : TableCellPrVert
        };

        var TableBand1Horz =
        {
            TextPr : TextPr2
        };

        var TableBand2Horz =
        {
            TextPr      : TextPr2,
            TableCellPr : TableCellPrHorz
        };

        this.Set_UiPriority(99);
        this.Set_ParaPr(ParaPr);
        this.Set_TextPr(TextPr);
        this.Set_TablePr(TablePr);
        this.Set_TableFirstRow(TableFirstRow);
        this.Set_TableLastRow(TableLastRow);
        this.Set_TableFirstCol(TableFirstCol);
        this.Set_TableLastCol(TableLastCol);
        this.Set_TableBand1Horz(TableBand1Horz);
        this.Set_TableBand1Vert(TableBand1Vert);
        this.Set_TableBand2Horz(TableBand2Horz);
        this.Set_TableBand2Vert(TableBand2Vert);
    },

    isEqual: function(cStyles)
    {
        var result = false;
        if(this.BasedOn == cStyles.BasedOn && this.Name == cStyles.Name && this.Next == cStyles.Next && this.Type == cStyles.Type && this.hidden == cStyles.hidden)
        {
            if(this.qFormat == cStyles.qFormat && this.semiHidden == cStyles.semiHidden && this.uiPriority == cStyles.uiPriority && this.unhideWhenUsed == cStyles.unhideWhenUsed)
            {
                var isEqualParaPr = this.ParaPr.isEqual(this.ParaPr, cStyles.ParaPr);
                var isEqualTextPr = this.TextPr.isEqual(this.TextPr, cStyles.TextPr);
                if(isEqualParaPr && isEqualTextPr)
                    result = true;
            }
        }
        return result;
    },

    Is_Equal : function(oStyle)
    {
        if (oStyle.Name != this.Name
            || this.BasedOn !== oStyle.BasedOn
            || this.Next !== oStyle.Next
            || this.Type !== oStyle.Type
            || this.Link !== oStyle.Link
            || this.qFormat !== oStyle.qFormat
            || this.uiPriority !== oStyle.uiPriority
            || this.hidden !== oStyle.hidden
            || this.semiHidden !== oStyle.semiHidden
            || this.unhideWhenUsed !== oStyle.unhideWhenUsed
            || true !== this.TextPr.Is_Equal(oStyle.TextPr)
            || true !== this.ParaPr.Is_Equal(oStyle.ParaPr)
            || (styletype_Table === this.Type
                && (true !== this.TablePr.Is_Equal(oStyle.TablePr)
                    || true !== this.TableRowPr.Is_Equal(oStyle.TableRowPr)
                    || true !== this.TableCellPr.Is_Equal(oStyle.TableCellPr)
                    || true !== IsEqualStyleObjects(this.TableBand1Horz , oStyle.TableBand1Horz )
                    || true !== IsEqualStyleObjects(this.TableBand1Vert , oStyle.TableBand1Vert )
                    || true !== IsEqualStyleObjects(this.TableBand2Horz , oStyle.TableBand2Horz )
                    || true !== IsEqualStyleObjects(this.TableBand2Vert , oStyle.TableBand2Vert )
                    || true !== IsEqualStyleObjects(this.TableFirstCol  , oStyle.TableFirstCol  )
                    || true !== IsEqualStyleObjects(this.TableFirstRow  , oStyle.TableFirstRow  )
                    || true !== IsEqualStyleObjects(this.TableLastCol   , oStyle.TableLastCol   )
                    || true !== IsEqualStyleObjects(this.TableLastRow   , oStyle.TableLastRow   )
                    || true !== IsEqualStyleObjects(this.TableTLCell    , oStyle.TableTLCell    )
                    || true !== IsEqualStyleObjects(this.TableTRCell    , oStyle.TableTRCell    )
                    || true !== IsEqualStyleObjects(this.TableBLCell    , oStyle.TableBLCell    )
                    || true !== IsEqualStyleObjects(this.TableBRCell    , oStyle.TableBRCell    )
                    || true !== IsEqualStyleObjects(this.TableWholeTable, oStyle.TableWholeTable)
                    )
                )
            )
            return false;

        return true;
    },
//-----------------------------------------------------------------------------------
// Undo/Redo функции
//-----------------------------------------------------------------------------------
	GetSelectionState : function()
    {
    },

	SetSelectionState : function(State, StateIndex)
    {
    },

    Get_ParentObject_or_DocumentPos : function()
    {
        return { Type : AscDFH.historyitem_recalctype_Inline, Data : 0 };
    },

    Refresh_RecalcData : function(Data)
    {
        var Type = Data.Type;

        var bNeedRecalc = false;

        switch ( Type )
        {
            case AscDFH.historyitem_Style_TextPr          :
            case AscDFH.historyitem_Style_ParaPr          :
            case AscDFH.historyitem_Style_TablePr         :
            case AscDFH.historyitem_Style_TableRowPr      :
            case AscDFH.historyitem_Style_TableCellPr     :
            case AscDFH.historyitem_Style_TableBand1Horz  :
            case AscDFH.historyitem_Style_TableBand1Vert  :
            case AscDFH.historyitem_Style_TableBand2Horz  :
            case AscDFH.historyitem_Style_TableBand2Vert  :
            case AscDFH.historyitem_Style_TableFirstCol   :
            case AscDFH.historyitem_Style_TableFirstRow   :
            case AscDFH.historyitem_Style_TableLastCol    :
            case AscDFH.historyitem_Style_TableLastRow    :
            case AscDFH.historyitem_Style_TableTLCell     :
            case AscDFH.historyitem_Style_TableTRCell     :
            case AscDFH.historyitem_Style_TableBLCell     :
            case AscDFH.historyitem_Style_TableBRCell     :
            case AscDFH.historyitem_Style_TableWholeTable :
            case AscDFH.historyitem_Style_Name            :
            case AscDFH.historyitem_Style_BasedOn         :
            case AscDFH.historyitem_Style_Next            :
            case AscDFH.historyitem_Style_Type            :
            case AscDFH.historyitem_Style_QFormat         :
            case AscDFH.historyitem_Style_UiPriority      :
            case AscDFH.historyitem_Style_Hidden          :
            case AscDFH.historyitem_Style_SemiHidden      :
            case AscDFH.historyitem_Style_UnhideWhenUsed  :
            case AscDFH.historyitem_Style_Link            :
            {
                bNeedRecalc = true;
                break;
            }
        }

        if ( true === bNeedRecalc )
        {
            // Сообщаем родительскому классу, что изменения произошли в элементе с номером this.Index и на странице this.PageNum
            return this.Refresh_RecalcData2();
        }
    },

	Refresh_RecalcData2 : function()
	{
		var oHistory = History;
		if (!oHistory)
			return;

		if (!oHistory.AddChangedStyleToRecalculateData(this.Get_Id(), this))
			return;
	},

	RecalculateRelatedParagraphs : function()
	{
		var oHistory = History;
		if (!oHistory)
			return;

		var LogicDocument = editor.WordControl.m_oLogicDocument;
		var Styles        = LogicDocument.Get_Styles();

		var AllParagraphs = [];

		if (this.Id != Styles.Default.Paragraph)
		{
			var AllStylesId = Styles.private_GetAllBasedStylesId(this.Id);
			AllParagraphs   = oHistory.GetAllParagraphsForRecalcData({Style : true, StylesId : AllStylesId});
			LogicDocument.Add_ChangedStyle(AllStylesId);
		}
		else
		{
			AllParagraphs = oHistory.GetAllParagraphsForRecalcData({All : true});
			LogicDocument.Add_ChangedStyle([this.Id]);
		}

		var Count = AllParagraphs.length;
		for (var Index = 0; Index < Count; Index++)
		{
			var Para = AllParagraphs[Index];
			Para.Refresh_RecalcData({Type : AscDFH.historyitem_Paragraph_PStyle});
		}
	},
//-----------------------------------------------------------------------------------
// Функции для совместного редактирования
//-----------------------------------------------------------------------------------
    Write_ToBinary2 : function(Writer)
    {
        Writer.WriteLong(AscDFH.historyitem_type_Style);

        // String   : Id
        // Bool(und) -> Bool(null) -> String : Name
        // Bool(und) -> Bool(null) -> String : BasedOn
        // Bool(und) -> Bool(null) -> String : Next
        // Long : Type
        // Bool(und) -> Bool(null) -> Long : uiPriority
        // Bool(und) -> Bool(null) -> Bool : qFormat
        // Bool(und) -> Bool(null) -> Bool : hidden
        // Bool(und) -> Bool(null) -> Bool : semiHidden
        // Bool(und) -> Bool(null) -> Bool : unhideWhenUsed
        // Variable(CTextPr)      : TextPr
        // Variable(CParaPr)      : ParaPr
        // Variable(CTablePr)     : TablePr
        // Variable(CTableRowPr)  : TableRowPr
        // Variable(CTableCellPr) : TableCellPr
        // Variable(CTableStylePr) : TableBand1Horz
        // Variable(CTableStylePr) : TableBand1Vert
        // Variable(CTableStylePr) : TableBand2Horz
        // Variable(CTableStylePr) : TableBand2Vert
        // Variable(CTableStylePr) : TableFirstCol
        // Variable(CTableStylePr) : TableFirstRow
        // Variable(CTableStylePr) : TableLastCol
        // Variable(CTableStylePr) : TableLastRow
        // Variable(CTableStylePr) : TableTLCell
        // Variable(CTableStylePr) : TableTRCell
        // Variable(CTableStylePr) : TableBLCell
        // Variable(CTableStylePr) : TableBRCell
        // Variable(CTableStylePr) : TableWholeTable

        Writer.WriteString2(this.Id);

        this.private_WriteUndefinedNullString(Writer, this.Name);
        this.private_WriteUndefinedNullString(Writer, this.BasedOn);
        this.private_WriteUndefinedNullString(Writer, this.Next);

        Writer.WriteLong(this.Type);

        this.private_WriterUndefinedNullLong(Writer, this.uiPriority);
        this.private_WriterUndefinedNullBool(Writer, this.qFormat);
        this.private_WriterUndefinedNullBool(Writer, this.hidden);
        this.private_WriterUndefinedNullBool(Writer, this.semiHidden);
        this.private_WriterUndefinedNullBool(Writer, this.unhideWhenUsed);

        this.TextPr.Write_ToBinary(Writer);
        this.ParaPr.Write_ToBinary(Writer);

        this.TablePr.Write_ToBinary(Writer);
        this.TableRowPr.Write_ToBinary(Writer);
        this.TableCellPr.Write_ToBinary(Writer);

        this.TableBand1Horz.Write_ToBinary(Writer);
        this.TableBand1Vert.Write_ToBinary(Writer);
        this.TableBand2Horz.Write_ToBinary(Writer);
        this.TableBand2Vert.Write_ToBinary(Writer);
        this.TableFirstCol.Write_ToBinary(Writer);
        this.TableFirstRow.Write_ToBinary(Writer);
        this.TableLastCol.Write_ToBinary(Writer);
        this.TableLastRow.Write_ToBinary(Writer);
        this.TableTLCell.Write_ToBinary(Writer);
        this.TableTRCell.Write_ToBinary(Writer);
        this.TableBLCell.Write_ToBinary(Writer);
        this.TableBRCell.Write_ToBinary(Writer);
        this.TableWholeTable.Write_ToBinary(Writer);
    },

    private_WriteUndefinedNullString : function(Writer, Value)
    {
        if (undefined === Value)
        {
            Writer.WriteBool(true);
        }
        else
        {
            Writer.WriteBool(false);
            if (null === Value)
            {
                Writer.WriteBool(true);
            }
            else
            {
                Writer.WriteBool(false);
                Writer.WriteString2(Value);
            }
        }
    },

    private_WriterUndefinedNullLong : function(Writer, Value)
    {
        if (undefined === Value)
        {
            Writer.WriteBool(true);
        }
        else
        {
            Writer.WriteBool(false);
            if (null === Value)
            {
                Writer.WriteBool(true);
            }
            else
            {
                Writer.WriteBool(false);
                Writer.WriteLong(Value);
            }
        }
    },

    private_WriterUndefinedNullBool : function(Writer, Value)
    {
        if (undefined === Value)
        {
            Writer.WriteBool(true);
        }
        else
        {
            Writer.WriteBool(false);
            if (null === Value)
            {
                Writer.WriteBool(true);
            }
            else
            {
                Writer.WriteBool(false);
                Writer.WriteBool(Value);
            }
        }
    },

    private_ReadUndefinedNullString : function(Reader)
    {
        if (true === Reader.GetBool())
            return undefined;
        else if (true === Reader.GetBool())
            return null;
        else
            return Reader.GetString2();
    },

    private_ReadUndefinedNullLong : function(Reader)
    {
        if (true === Reader.GetBool())
            return undefined;
        else if (true === Reader.GetBool())
            return null;
        else
            return Reader.GetLong();
    },

    private_ReadUndefinedNullBool : function(Reader)
    {
        if (true === Reader.GetBool())
            return undefined;
        else if (true === Reader.GetBool())
            return null;
        else
            return Reader.GetBool();
    },

    Read_FromBinary2 : function(Reader)
    {
        // String   : Id
        // Bool(und) -> Bool(null) -> String : Name
        // Bool(und) -> Bool(null) -> String : BasedOn
        // Bool(und) -> Bool(null) -> String : Next
        // Long : Type
        // Bool(und) -> Bool(null) -> Long : uiPriority
        // Bool(und) -> Bool(null) -> Bool : qFormat
        // Bool(und) -> Bool(null) -> Bool : hidden
        // Bool(und) -> Bool(null) -> Bool : semiHidden
        // Bool(und) -> Bool(null) -> Bool : unhideWhenUsed
        // Variable(CTextPr)      : TextPr
        // Variable(CParaPr)      : ParaPr
        // Variable(CTablePr)     : TablePr
        // Variable(CTableRowPr)  : TableRowPr
        // Variable(CTableCellPr) : TableCellPr
        // Variable(CTableStylePr) : TableBand1Horz
        // Variable(CTableStylePr) : TableBand1Vert
        // Variable(CTableStylePr) : TableBand2Horz
        // Variable(CTableStylePr) : TableBand2Vert
        // Variable(CTableStylePr) : TableFirstCol
        // Variable(CTableStylePr) : TableFirstRow
        // Variable(CTableStylePr) : TableLastCol
        // Variable(CTableStylePr) : TableLastRow
        // Variable(CTableStylePr) : TableTLCell
        // Variable(CTableStylePr) : TableTRCell
        // Variable(CTableStylePr) : TableBLCell
        // Variable(CTableStylePr) : TableBRCell
        // Variable(CTableStylePr) : TableWholeTable

        this.Id = Reader.GetString2();

        this.Name    = this.private_ReadUndefinedNullString(Reader);
        this.BasedOn = this.private_ReadUndefinedNullString(Reader);
        this.Next    = this.private_ReadUndefinedNullString(Reader);

        this.Type = Reader.GetLong();

        this.uiPriority     = this.private_ReadUndefinedNullLong(Reader);
        this.qFormat        = this.private_ReadUndefinedNullBool(Reader);
        this.hidden         = this.private_ReadUndefinedNullBool(Reader);
        this.semiHidden     = this.private_ReadUndefinedNullBool(Reader);
        this.unhideWhenUsed = this.private_ReadUndefinedNullBool(Reader);

        this.TextPr.Read_FromBinary(Reader);
        this.ParaPr.Read_FromBinary(Reader);

        this.TablePr.Read_FromBinary(Reader);
        this.TableRowPr.Read_FromBinary(Reader);
        this.TableCellPr.Read_FromBinary(Reader);

        this.TableBand1Horz.Read_FromBinary(Reader);
        this.TableBand1Vert.Read_FromBinary(Reader);
        this.TableBand2Horz.Read_FromBinary(Reader);
        this.TableBand2Vert.Read_FromBinary(Reader);
        this.TableFirstCol.Read_FromBinary(Reader);
        this.TableFirstRow.Read_FromBinary(Reader);
        this.TableLastCol.Read_FromBinary(Reader);
        this.TableLastRow.Read_FromBinary(Reader);
        this.TableTLCell.Read_FromBinary(Reader);
        this.TableTRCell.Read_FromBinary(Reader);
        this.TableBLCell.Read_FromBinary(Reader);
        this.TableBRCell.Read_FromBinary(Reader);
        this.TableWholeTable.Read_FromBinary(Reader);
    },

    Load_LinkData : function(LinkData)
    {
        if (true === LinkData.StyleUpdate)
        {
            var LogicDocument = editor.WordControl.m_oLogicDocument;
            if (!LogicDocument)
                return;

            var Styles = LogicDocument.Get_Styles();
            if (!Styles)
                return;

            var AllParagraphs = [];
            if (this.Id != Styles.Default.Paragraph)
            {
                var AllStylesId = Styles.private_GetAllBasedStylesId(this.Id);
                AllParagraphs = LogicDocument.GetAllParagraphsByStyle(AllStylesId);
                LogicDocument.Add_ChangedStyle(AllStylesId);
            }
            else
            {
                AllParagraphs = LogicDocument.GetAllParagraphs({All : true});
                LogicDocument.Add_ChangedStyle([this.Id]);
            }

            var Count = AllParagraphs.length;
            for ( var Index = 0; Index < Count; Index++ )
            {
                var Para = AllParagraphs[Index];
                Para.Recalc_CompiledPr();
                Para.Recalc_RunsCompiledPr();
            }
        }
    }
};
/**
 * Выставляем текстовые настройки
 * @param {CTextPr | Object} oTextPr
 */
CStyle.prototype.SetTextPr = function(oTextPr)
{
	this.Set_TextPr(oTextPr);
};
/**
 * Получаем текстовые настройки
 * @returns {CTextPr}
 */
CStyle.prototype.GetTextPr = function()
{
	return this.TextPr;
};
/**
 * Выставляем настройки параграфа
 * @param {CParaPr | Object} oParaPr
 */
CStyle.prototype.SetParaPr = function(oParaPr)
{
	this.Set_ParaPr(oParaPr);
};
/**
 * Получаем настройки параграфа
 * @returns {CParaPr}
 */
CStyle.prototype.GetParaPr = function()
{
	return this.ParaPr;
};
/**
 * Выставляем значение приоритета данного стиля
 * @param {number} nUiPriority
 */
CStyle.prototype.SetUiPriority = function(nUiPriority)
{
	this.Set_UiPriority(nUiPriority);
};
/**
 * Получаем значение приоритета данного стиля
 * @returns {number}
 */
CStyle.prototype.GetUiPriority = function()
{
	return this.uiPriority;
};
/**
 * Выставляем параметр примарность данного стиля
 * @param {boolean} isQFormat
 */
CStyle.prototype.SetQFormat = function(isQFormat)
{
	this.Set_QFormat(isQFormat);
};
/**
 * Получаем параметр примарности стиля
 * @returns {boolean}
 */
CStyle.prototype.GetQFormat = function()
{
	return this.qFormat;
};
/**
 * @param {boolean} isHidden
 */
CStyle.prototype.SetHidden = function(isHidden)
{
	this.Set_Hidden(isHidden);
};
/**
 * @returns {boolean}
 */
CStyle.prototype.GetHidden = function()
{
	return this.hidden;
};
/**
 * @param {boolean} isSemiHidden
 */
CStyle.prototype.SetSemiHidden = function(isSemiHidden)
{
	this.Set_SemiHidden(isSemiHidden);
};
/**
 * @returns {boolean}
 */
CStyle.prototype.GetSemiHidden = function()
{
	return this.semiHidden;
};
/**
 * Нужно ли показывать стиль в панели при его использовании
 * @param {boolean} isUnhide
 */
CStyle.prototype.SetUnhideWhenUsed = function(isUnhide)
{
	this.Set_UnhideWhenUsed(isUnhide);
};
/**
 * Нужно ли показывать стиль в панели при его использовании
 * @returns {boolean}
 */
CStyle.prototype.GetUnhideWhenUsed = function()
{
	return this.unhideWhenUsed;
};
CStyle.prototype.GetName = function()
{
	return this.Get_Name();
};
CStyle.prototype.GetBasedOn = function()
{
	return this.Get_BasedOn();
};
CStyle.prototype.GetNext = function()
{
	return this.Get_Next()
};
CStyle.prototype.GetType = function()
{
	return this.Get_Type();
};
/**
 * Выставляем линкованный стиль
 * @param {string} sLink
 */
CStyle.prototype.SetLink = function(sLink)
{
	this.Set_Link(sLink);
};
/**
 * Возвращаем идентефикатор линкованного стиля
 * @returns {null|string}
 */
CStyle.prototype.GetLink = function()
{
	return this.Link;
};
CStyle.prototype.IsEqual = function(oOtherStyle)
{
	return this.Is_Equal(oOtherStyle);
};
/**
 * Создаем слинкованный символьный шрифт
 * @param {string} sStyleName
 * @param {string} sBasedOn
 * @returns {CStyle}
 */
CStyle.prototype.CreateLinkedCharacterStyle = function(sStyleName, sBasedOn)
{
	var oStyle = new CStyle(sStyleName, sBasedOn, null, styletype_Character, true);

	oStyle.SetTextPr(this.GetTextPr());
	oStyle.SetUiPriority(this.GetUiPriority());
	oStyle.SetLink(this.GetId());

	this.SetLink(oStyle.GetId());

	return oStyle;
};
/**
 * Дефолтовые настройки для стиля Normal
 */
CStyle.prototype.CreateNormal = function()
{
	this.SetQFormat(true);
};
/**
 * Дефолтовые настройки для стиля Default Paragraph Font
 */
CStyle.prototype.CreateDefaultParagraphFont = function()
{
	this.SetUiPriority(1);
	this.SetSemiHidden(true);
	this.SetUnhideWhenUsed(true);
};
/**
 * Дефолтовые настройки для стиля No List
 */
CStyle.prototype.CreateNoList = function()
{
	this.SetUiPriority(99);
	this.SetSemiHidden(true);
	this.SetUnhideWhenUsed(true);
};
/**
 * Дефолтовые настройки для стиля Hyperlink
 */
CStyle.prototype.CreateHyperlink = function()
{
	this.SetUiPriority(99);
	this.SetUnhideWhenUsed(true);

	this.SetTextPr({
		Color     : {r : 0x00, g : 0x00, b : 0xFF},
		Underline : true,
		Unifill   : AscFormat.CreateUniFillSchemeColorWidthTint(11, 0)
	});
};
/**
 * Дефолтовые настройки для стиля No Spacing
 */
CStyle.prototype.CreateNoSpacing = function()
{
	this.SetUiPriority(1);
	this.SetQFormat(true);

	this.SetParaPr({
		Spacing : {
			Line     : 1,
			LineRule : linerule_Auto,
			After    : 0,
			Before   : 0
		}
	});
};
/**
 * Дефолтовые настройки для стиля Header
 */
CStyle.prototype.CreateHeader = function()
{
	this.SetUiPriority(99);
	this.SetUnhideWhenUsed(true);

	var RPos = 297 - 30 - 15; // Ширина страницы - левое поле - правое поле
	var CPos = RPos / 2;

	this.SetParaPr({
		Spacing : {
			After    : 0,
			Line     : 1,
			LineRule : linerule_Auto
		},

		Tabs : {
			Tabs : [
				{
					Value : tab_Center,
					Pos   : CPos
				},
				{
					Value : tab_Right,
					Pos   : RPos
				}
			]
		}
	});
};
/**
 * Дефолтовые настройки для стиля Footer
 */
CStyle.prototype.CreateFooter = function()
{
	this.SetUiPriority(99);
	this.SetUnhideWhenUsed(true);

	var RPos = 297 - 30 - 15; // Ширина страницы - левое поле - правое поле
	var CPos = RPos / 2;

	this.SetParaPr({
		Spacing : {
			After    : 0,
			Line     : 1,
			LineRule : linerule_Auto
		},

		Tabs : {
			Tabs : [
				{
					Value : tab_Center,
					Pos   : CPos
				},
				{
					Value : tab_Right,
					Pos   : RPos
				}
			]
		}
	});
};
/**
 * Дефолтовый стиль для footnote text
 */
CStyle.prototype.CreateFootnoteText = function()
{
	this.SetUiPriority(99);
	this.SetSemiHidden(true);
	this.SetUnhideWhenUsed(true);

	this.SetParaPr({
		Spacing : {
			After    : 40 * g_dKoef_twips_to_mm,
			Line     : 1,
			LineRule : linerule_Auto
		}
	});

	this.SetTextPr({
		FontSize : 9
	});
};
/**
 * Дефолтовые настройки для стиля footnote reference
 */
CStyle.prototype.CreateFootnoteReference = function()
{
	this.SetUiPriority(99);
	this.SetUnhideWhenUsed(true);
	this.SetTextPr({
		VertAlign : AscCommon.vertalign_SuperScript
	});
};
CStyle.prototype.CreateTOC = function(nLvl, nType)
{
	var ParaPr = {},
		TextPr = {};

	if (undefined === nType || null === nType || Asc.c_oAscTOCStylesType.Simple === nType)
	{
		ParaPr = {
			Spacing : {
				After : 57 / 20 * g_dKoef_pt_to_mm
			},

			Ind : {
				Left      : 0,
				Right     : 0,
				FirstLine : 0
			}
		};

		if (1 === nLvl)
			ParaPr.Ind.Left = 283 / 20 * g_dKoef_pt_to_mm;
		else if (2 === nLvl)
			ParaPr.Ind.Left = 567 / 20 * g_dKoef_pt_to_mm;
		else if (3 === nLvl)
			ParaPr.Ind.Left = 850 / 20 * g_dKoef_pt_to_mm;
		else if (4 === nLvl)
			ParaPr.Ind.Left = 1134 / 20 * g_dKoef_pt_to_mm;
		else if (5 === nLvl)
			ParaPr.Ind.Left = 1417 / 20 * g_dKoef_pt_to_mm;
		else if (6 === nLvl)
			ParaPr.Ind.Left = 1701 / 20 * g_dKoef_pt_to_mm;
		else if (7 === nLvl)
			ParaPr.Ind.Left = 1984 / 20 * g_dKoef_pt_to_mm;
		else if (8 === nLvl)
			ParaPr.Ind.Left = 2268 / 20 * g_dKoef_pt_to_mm;
	}
	else if (Asc.c_oAscTOCStylesType.Standard === nType)
	{
		ParaPr = {
			Spacing : {
				After : 57 / 20 * g_dKoef_pt_to_mm
			},

			Ind : {
				Left      : 0,
				Right     : 0,
				FirstLine : 0
			}
		};

		if (0 === nLvl)
		{
			TextPr.Bold     = true;
			TextPr.FontSize = 14;
		}
		else if (1 === nLvl)
		{
			ParaPr.Ind.Left = 283 / 20 * g_dKoef_pt_to_mm;
			TextPr.Bold     = true;
			TextPr.FontSize = 13;
		}
		else if (2 === nLvl)
		{
			ParaPr.Ind.Left = 567 / 20 * g_dKoef_pt_to_mm;
			TextPr.FontSize = 13;
		}
		else if (3 === nLvl)
		{
			ParaPr.Ind.Left = 850 / 20 * g_dKoef_pt_to_mm;
			TextPr.FontSize = 11;
		}
		else if (4 === nLvl)
		{
			ParaPr.Ind.Left = 1134 / 20 * g_dKoef_pt_to_mm;
			TextPr.FontSize = 11;
		}
		else if (5 === nLvl)
		{
			ParaPr.Ind.Left = 1417 / 20 * g_dKoef_pt_to_mm;
			TextPr.FontSize = 11;
		}
		else if (6 === nLvl)
		{
			ParaPr.Ind.Left = 1701 / 20 * g_dKoef_pt_to_mm;
			TextPr.FontSize = 11;
		}
		else if (7 === nLvl)
		{
			ParaPr.Ind.Left = 1984 / 20 * g_dKoef_pt_to_mm;
			TextPr.FontSize = 11;
		}
		else if (8 === nLvl)
		{
			ParaPr.Ind.Left = 2268 / 20 * g_dKoef_pt_to_mm;
			TextPr.FontSize = 11;
		}
	}
	else if (Asc.c_oAscTOCStylesType.Modern === nType)
	{
		ParaPr = {
			Ind : {
				Left      : 0,
				Right     : 0,
				FirstLine : 0
			}
		};

		if (0 === nLvl)
		{
			ParaPr.Spacing = {
				After : 170 / 20 * g_dKoef_pt_to_mm
			};

			ParaPr.Brd = {
				Bottom : {
					Color : {r : 0x00, g : 0x00, b : 0x00},
					Space : 0,
					Size  : 1 * g_dKoef_pt_to_mm,
					Value : border_Single
				}
			};


			TextPr.Bold     = true;
			TextPr.FontSize = 14;
		}
		else if (1 === nLvl)
		{
			ParaPr.Spacing = {
				After : 57 / 20 * g_dKoef_pt_to_mm
			};

			TextPr.Bold     = true;
			TextPr.FontSize = 13;
		}
		else if (2 === nLvl)
		{
			ParaPr.Spacing = {
				After : 57 / 20 * g_dKoef_pt_to_mm
			};

			TextPr.FontSize = 13;
		}
		else
		{
			ParaPr.Spacing = {
				After : 57 / 20 * g_dKoef_pt_to_mm
			};

			TextPr.FontSize = 11;
		}
	}
	else if (Asc.c_oAscTOCStylesType.Classic === nType)
	{
		ParaPr.Spacing = {
			After : 57 / 20 * g_dKoef_pt_to_mm
		};

		ParaPr.Ind = {
			Left      : 0,
			Right     : 0,
			FirstLine : 0
		};

		TextPr.FontSize = 11;

		if (0 === nLvl)
		{
			ParaPr.Spacing.After = 170 / 20 * g_dKoef_pt_to_mm;

			TextPr.Bold     = true;
			TextPr.FontSize = 14;
		}
		else if (1 === nLvl)
		{
			TextPr.Bold     = true;
			TextPr.FontSize = 13;
		}
		else if (2 === nLvl)
		{
			ParaPr.Ind.FirstLine = 283 / 20 * g_dKoef_pt_to_mm;

			TextPr.FontSize = 13;
		}
		else if (3 === nLvl)
		{
			ParaPr.Ind.FirstLine = 567 / 20 * g_dKoef_pt_to_mm;
		}
		else if (4 === nLvl)
		{
			ParaPr.Ind.FirstLine = 850 / 20 * g_dKoef_pt_to_mm;
		}
		else if (5 === nLvl)
		{
			ParaPr.Ind.FirstLine = 1134 / 20 * g_dKoef_pt_to_mm;
		}
		else if (6 === nLvl)
		{
			ParaPr.Ind.FirstLine = 1417 / 20 * g_dKoef_pt_to_mm;
		}
		else if (7 === nLvl)
		{
			ParaPr.Ind.FirstLine = 1701 / 20 * g_dKoef_pt_to_mm;
		}
		else if (8 === nLvl)
		{
			ParaPr.Ind.FirstLine = 1984 / 20 * g_dKoef_pt_to_mm;
		}
	}

	this.Set_UiPriority(39);
	this.Set_UnhideWhenUsed(true);
	this.Set_ParaPr(ParaPr);
	this.Set_TextPr(TextPr);
};
CStyle.prototype.CreateTOCHeading = function()
{
	var ParaPr = {};

	this.Set_UiPriority(39);
	this.Set_UnhideWhenUsed(true);
	this.Set_ParaPr(ParaPr);
};
/**
 * Дефолтовые настройки для стиля ListParagraph
 */
CStyle.prototype.CreateListParagraph = function()
{
	this.SetQFormat(true);
	this.SetUiPriority(34);

	this.SetParaPr({

		Ind : {
			Left : 720 * g_dKoef_twips_to_mm
		},

		ContextualSpacing : true
	});
};
/**
 * Дефолтовые настройки для стиля Heading (1..9)
 * @param nLvl {number} 0..8
 */
CStyle.prototype.CreateHeading = function(nLvl)
{
	if (0 === nLvl)
	{
		this.SetParaPr({

			KeepNext  : true,
			KeepLines : true,

			Spacing : {
				Before   : 480 * g_dKoef_twips_to_mm,
				After    : 200 * g_dKoef_twips_to_mm
			},

			OutlineLvl : 0
		});

		this.SetTextPr({

			FontSize   : 20,
			FontSizeCS : 20,
			RFonts     : {
				Ascii    : {Name : Default_Heading_Font, Index : -1},
				EastAsia : {Name : Default_Heading_Font, Index : -1},
				HAnsi    : {Name : Default_Heading_Font, Index : -1},
				CS       : {Name : Default_Heading_Font, Index : -1}
			}
		});
	}
	else if (1 === nLvl)
	{
		this.SetParaPr({

			KeepNext  : true,
			KeepLines : true,

			Spacing : {
				Before   : 360 * g_dKoef_twips_to_mm,
				After    : 200 * g_dKoef_twips_to_mm
			},

			OutlineLvl : 1
		});

		this.SetTextPr({
			FontSize : 17,
			RFonts   : {
				Ascii    : {Name : Default_Heading_Font, Index : -1},
				EastAsia : {Name : Default_Heading_Font, Index : -1},
				HAnsi    : {Name : Default_Heading_Font, Index : -1},
				CS       : {Name : Default_Heading_Font, Index : -1}
			}
		});
	}
	else if (2 === nLvl)
	{
		this.SetParaPr({

			KeepNext  : true,
			KeepLines : true,

			Spacing : {
				Before : 320 * g_dKoef_twips_to_mm,
				After  : 200 * g_dKoef_twips_to_mm
			},

			OutlineLvl : 2
		});

		this.SetTextPr({
			FontSize   : 15,
			FontSizeCS : 15,
			RFonts     : {
				Ascii    : {Name : Default_Heading_Font, Index : -1},
				EastAsia : {Name : Default_Heading_Font, Index : -1},
				HAnsi    : {Name : Default_Heading_Font, Index : -1},
				CS       : {Name : Default_Heading_Font, Index : -1}
			}
		});
	}
	else if (3 === nLvl)
	{
		this.SetParaPr({

			KeepNext  : true,
			KeepLines : true,

			Spacing : {
				Before : 320 * g_dKoef_twips_to_mm,
				After  : 200 * g_dKoef_twips_to_mm
			},

			OutlineLvl : 3
		});

		this.SetTextPr({

			FontSize   : 13,
			FontSizeCS : 13,

			RFonts : {
				Ascii    : {Name : Default_Heading_Font, Index : -1},
				EastAsia : {Name : Default_Heading_Font, Index : -1},
				HAnsi    : {Name : Default_Heading_Font, Index : -1},
				CS       : {Name : Default_Heading_Font, Index : -1}
			},

			Bold   : true,
			BoldCS : true
		});
	}
	else if (4 === nLvl)
	{
		this.SetParaPr({

			KeepNext  : true,
			KeepLines : true,

			Spacing : {
				Before : 320 * g_dKoef_twips_to_mm,
				After  : 200 * g_dKoef_twips_to_mm
			},

			OutlineLvl : 4
		});

		this.SetTextPr({

			FontSize   : 12,
			FontSizeCS : 12,

			RFonts : {
				Ascii    : {Name : Default_Heading_Font, Index : -1},
				EastAsia : {Name : Default_Heading_Font, Index : -1},
				HAnsi    : {Name : Default_Heading_Font, Index : -1},
				CS       : {Name : Default_Heading_Font, Index : -1}
			},

			Bold   : true,
			BoldCS : true
		});
	}
	else if (5 === nLvl)
	{
		this.SetParaPr({

			KeepNext  : true,
			KeepLines : true,

			Spacing : {
				Before : 320 * g_dKoef_twips_to_mm,
				After  : 200 * g_dKoef_twips_to_mm
			},

			OutlineLvl : 5
		});

		this.SetTextPr({

			FontSize   : 11,
			FontSizeCS : 11,

			Bold   : true,
			BoldCS : true,

			RFonts : {
				Ascii    : {Name : Default_Heading_Font, Index : -1},
				EastAsia : {Name : Default_Heading_Font, Index : -1},
				HAnsi    : {Name : Default_Heading_Font, Index : -1},
				CS       : {Name : Default_Heading_Font, Index : -1}
			}
		});
	}
	else if (6 === nLvl)
	{
		this.SetParaPr({

			KeepNext   : true,
			KeepLines  : true,

			Spacing    : {
				Before : 320 * g_dKoef_twips_to_mm,
				After  : 200 * g_dKoef_twips_to_mm
			},

			OutlineLvl : 6
		});

		this.SetTextPr({

			FontSize   : 11,
			FontSizeCS : 11,

			RFonts : {
				Ascii    : {Name : Default_Heading_Font, Index : -1},
				EastAsia : {Name : Default_Heading_Font, Index : -1},
				HAnsi    : {Name : Default_Heading_Font, Index : -1},
				CS       : {Name : Default_Heading_Font, Index : -1}
			},

			Bold     : true,
			BoldCS   : true,
			Italic   : true,
			ItalicCS : true
		});
	}
	else if (7 === nLvl)
	{
		this.SetParaPr({

			KeepNext  : true,
			KeepLines : true,

			Spacing : {
				Before : 320 * g_dKoef_twips_to_mm,
				After  : 200 * g_dKoef_twips_to_mm
			},

			OutlineLvl : 7
		});

		this.SetTextPr({

			FontSize   : 11,
			FontSizeCS : 11,

			RFonts : {
				Ascii    : {Name : Default_Heading_Font, Index : -1},
				EastAsia : {Name : Default_Heading_Font, Index : -1},
				HAnsi    : {Name : Default_Heading_Font, Index : -1},
				CS       : {Name : Default_Heading_Font, Index : -1}
			},

			Italic   : true,
			ItalicCS : true
		});
	}
	else if (8 === nLvl)
	{
		this.SetParaPr({

			KeepNext  : true,
			KeepLines : true,

			Spacing : {
				Before : 320 * g_dKoef_twips_to_mm,
				After  : 200 * g_dKoef_twips_to_mm
			},

			OutlineLvl : 8
		});

		this.SetTextPr({

			FontSize   : 10.5,
			FontSizeCS : 10.5,

			RFonts : {
				Ascii    : {Name : Default_Heading_Font, Index : -1},
				EastAsia : {Name : Default_Heading_Font, Index : -1},
				HAnsi    : {Name : Default_Heading_Font, Index : -1},
				CS       : {Name : Default_Heading_Font, Index : -1}
			},

			Italic   : true,
			ItalicCS : true
		});
	}

	this.SetQFormat(true);
	this.SetUiPriority(9);

	if (0 !== nLvl)
		this.SetUnhideWhenUsed(true);
};
/**
 * Дефолтовые настройки для линкованного стиля текста для Heading (1..9)
 * @param nLvl {number} 0..8
 */
CStyle.prototype.CreateHeadingLinkStyle = function(nLvl)
{
	var TextPr = {
		RFonts     : {
			Ascii    : {Name : Default_Heading_Font, Index : -1},
			EastAsia : {Name : Default_Heading_Font, Index : -1},
			HAnsi    : {Name : Default_Heading_Font, Index : -1},
			CS       : {Name : Default_Heading_Font, Index : -1}
		}
	};

	if (0 === nLvl)
	{
		TextPr.FontSize   = 20;
		TextPr.FontSizeCS = 20;
	}
	else if (1 === nLvl)
	{
		TextPr.FontSize   = 17;
		TextPr.FontSizeCS = 17;
	}
	else if (2 === nLvl)
	{
		TextPr.FontSize   = 15;
		TextPr.FontSizeCS = 15;
	}
	else if (3 === nLvl)
	{
		TextPr.FontSize   = 13;
		TextPr.FontSizeCS = 13;
		TextPr.Bold       = true;
		TextPr.BoldCd     = true;
	}
	else if (4 === nLvl)
	{
		TextPr.FontSize   = 12;
		TextPr.FontSizeCS = 12;
		TextPr.Bold       = true;
		TextPr.BoldCS     = true;
	}
	else if (5 === nLvl)
	{
		TextPr.FontSize   = 11;
		TextPr.FontSizeCS = 11;
		TextPr.Bold       = true;
		TextPr.BoldCS     = true;
	}
	else if (6 === nLvl)
	{
		TextPr.FontSize   = 11;
		TextPr.FontSizeCS = 11;
		TextPr.Bold       = true;
		TextPr.BoldCS     = true;
	}
	else if (7 === nLvl)
	{
		TextPr.FontSize   = 11;
		TextPr.FontSizeCS = 11;
	}
	else if (8 === nLvl)
	{
		TextPr.FontSize   = 10.5;
		TextPr.FontSizeCS = 10.5;
	}

	this.Set_UiPriority(9);
	this.Set_TextPr(TextPr);
};
/**
 * Дефолтовые настройки для стиля Title
 */
CStyle.prototype.CreateTitle = function()
{
	this.SetQFormat(true);
	this.SetUiPriority(10);

	this.SetTextPr({
		FontSize   : 24,
		FontSizeCS : 24
	});

	this.SetParaPr({
		Spacing           : {
			Before : 300 * g_dKoef_twips_to_mm,
			After  : 200 * g_dKoef_twips_to_mm
		},
		ContextualSpacing : true
	});
};
/**
 * Дефолтовые настройки для стиля Subtitle
 */
CStyle.prototype.CreateSubtitle = function()
{
	this.SetQFormat(true);
	this.SetUiPriority(11);

	this.SetTextPr({
		FontSize   : 12,
		FontSizeCS : 12
	});

	this.SetParaPr({
		Spacing : {
			After  : 200 * g_dKoef_twips_to_mm,
			Before : 200 * g_dKoef_twips_to_mm
		}
	});
};
/**
 * Дефолтовые настройки для стиля Quote
 */
CStyle.prototype.CreateQuote = function()
{
	this.SetQFormat(true);
	this.SetUiPriority(29);

	this.SetTextPr({
		Italic : true
	});

	this.SetParaPr({
		Ind : {
			Left  : 720 * g_dKoef_twips_to_mm,
			Right : 720 * g_dKoef_twips_to_mm
		}
	});
};
/**
 * Дефолтовые настройки для стиля IntenseQuote
 */
CStyle.prototype.CreateIntenseQuote = function()
{
	this.SetQFormat(true);
	this.SetUiPriority(30);

	this.SetTextPr({
		Italic : true
	});

	this.SetParaPr({

		ContextualSpacing : false,

		Ind : {
			Left  : 720 * g_dKoef_twips_to_mm,
			Right : 720 * g_dKoef_twips_to_mm
		},

		Shd : {
			Value : c_oAscShdClear,
			Color : {r : 0xF2, g : 0xF2, b : 0xF2}
		},

		Brd : {

			Left : {
				Color   : {r : 0xFF, g : 0xFF, b : 0xFF},
				Space   : 10 * g_dKoef_pt_to_mm,
				Size    : 0.5 * g_dKoef_pt_to_mm,
				Value   : border_Single
			},

			Top : {
				Color   : {r : 0xFF, g : 0xFF, b : 0xFF},
				Space   : 5 * g_dKoef_pt_to_mm,
				Size    : 0.5 * g_dKoef_pt_to_mm,
				Value   : border_Single
			},

			Right : {
				Color   : {r : 0xFF, g : 0xFF, b : 0xFF},
				Space   : 10 * g_dKoef_pt_to_mm,
				Size    : 0.5 * g_dKoef_pt_to_mm,
				Value   : border_Single
			},

			Bottom : {
				Color   : {r : 0xFF, g : 0xFF, b : 0xFF},
				Space   : 5 * g_dKoef_pt_to_mm,
				Size    : 0.5 * g_dKoef_pt_to_mm,
				Value   : border_Single
			}
		}
	});
};
/**
 * Конвертируем стиль в Asc.CAscStyle
 * @returns {Asc.CAscStyle}
 */
CStyle.prototype.ToAscStyle = function()
{
	var oAscStyle = new Asc.CAscStyle();

	oAscStyle.StyleId    = this.Id;

	oAscStyle.Name       = this.Name;
	oAscStyle.Type       = this.Type;
	oAscStyle.qFormat    = null === this.qFormat || undefined === this.qFormat ? false : this.qFormat;
	oAscStyle.uiPriority = null === this.qFormat || undefined === this.qFormat ? -1 : this.uiPriority;

	return oAscStyle;
};
/**
 * Получаем текстовые настройки
 * @returns {CTextPr}
 */
CStyle.prototype.GetTextPr = function()
{
	return this.TextPr;
};
/**
 * Получаем настройки для параграфа
 * @returns {CParaPr}
 */
CStyle.prototype.GetParaPr = function()
{
	return this.ParaPr;
};
/**
 * Показывать ли данный стиль в верхней панели
 * @param {CStyles} oStyles
 * @returns {boolean}
 */
CStyle.prototype.IsExpressStyle = function(oStyles)
{
	if (true === this.qFormat)
		return true;

	if (oStyles
		&& oStyles.Default
		&& (oStyles.Default.Header === this.Id
		|| oStyles.Default.Footer === this.Id
		|| oStyles.Default.FootnoteText === this.Id))
		return true;

	return false;
};
/**
 * Выставляем является ли данный стиль кастомным
 * @param {boolean} isCustom
 */
CStyle.prototype.SetCustom = function(isCustom)
{
	History.Add(new CChangesStyleCustom(this, this.Name, isCustom));
	this.Custom = isCustom;
};
/**
 * Проверяем является ли данный стиль кастомным
 * @returns {boolean}
 */
CStyle.prototype.IsCustom = function()
{
	return this.Custom;
};
/**
 * Проверяем является ли данный стиль, стилем для параграфа
 * @returns {boolean}
 */
CStyle.prototype.IsParagraphStyle = function()
{
	return (this.Type === styletype_Paragraph);
};

function CStyles(bCreateDefault)
{
    if (bCreateDefault !== false)
    {
        this.Id = AscCommon.g_oIdCounter.Get_NewId();
        this.Lock = new AscCommon.CLock();

		this.Default = {
			ParaPr      : new CParaPr(),
			TextPr      : new CTextPr(),
			TablePr     : new CTablePr(),
			TableRowPr  : new CTableRowPr(),
			TableCellPr : new CTableCellPr(),

			Paragraph         : null,
			Character         : null,
			Numbering         : null,
			Table             : null,
			TableGrid         : null,
			Headings          : [],
			ParaList          : null,
			Header            : null,
			Footer            : null,
			Hyperlink         : null,
			FootnoteText      : null,
			FootnoteTextChar  : null,
			FootnoteReference : null,
			NoSpacing         : null,
			Title             : null,
			Subtitle          : null,
			Quote             : null,
			IntenseQuote      : null,
			TOC               : [],
			TOCHeading        : null
		};

        // Заполняем значения по умолчанию
        this.Default.ParaPr.Init_Default();
        this.Default.TextPr.Init_Default();
        this.Default.TablePr.Init_Default();
        this.Default.TableRowPr.Init_Default();
        this.Default.TableCellPr.Init_Default();

        this.Style = [];

        // Создадим стандартные стили

		// Дефолтовый стиль для параграфа
		var oNormal = new CStyle("Normal", null, null, styletype_Paragraph);
		oNormal.CreateNormal();
		this.Default.Paragraph = this.Add(oNormal);

		// Дефолтовый стиль для текста
		var oDefaultParagraphFont = new CStyle("Default Paragraph Font", null, null, styletype_Character);
		oDefaultParagraphFont.CreateDefaultParagraphFont();
		this.Default.Character = this.Add(oDefaultParagraphFont);

		// Дефолтовый стиль для нумерации в списках
		var oNoList = new CStyle("No List", null, null, styletype_Numbering);
		oNoList.CreateNoList();
		this.Default.Numbering = this.Add(oNoList);

		// Создаем стандартные стили для заголовков
		for (var nLvl = 0; nLvl <= 8; ++nLvl)
		{
			var oHeadingStyle = new CStyle("Heading " + (nLvl + 1), this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
			oHeadingStyle.CreateHeading(nLvl);
			this.Default.Headings[nLvl] = this.Add(oHeadingStyle);
			this.Add(oHeadingStyle.CreateLinkedCharacterStyle("Heading " + (nLvl + 1) + " Char", this.Default.Character));
		}

		// Создаем стандартный стиль для нумерованных параграфов
		var oListParagraph = new CStyle("List Paragraph", this.Default.Paragraph, null, styletype_Paragraph);
		oListParagraph.CreateListParagraph();
		this.Default.ParaList = this.Add(oListParagraph);

		// Создаем стандартный стиль для таблиц
		var Style_Table = new CStyle("Normal Table", null, null, styletype_Table);
		Style_Table.Create_NormalTable();
		this.Default.Table = this.Add(Style_Table);

		// Создаем стиль "Без интервала"
		var oNoSpacing = new CStyle("No Spacing", null, null, styletype_Paragraph);
		oNoSpacing.CreateNoSpacing();
		this.Default.NoSpacing = this.Add(oNoSpacing);

		// Создаем стиль "Заголовок"
		var oTitle = new CStyle("Title", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
		oTitle.CreateTitle();
		this.Default.Title = this.Add(oTitle);
		this.Add(oTitle.CreateLinkedCharacterStyle("Title Char", this.Default.Character));

		// Создаем стиль "Подзаголовок"
		var oSubtitle = new CStyle("Subtitle", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
		oSubtitle.CreateSubtitle();
		this.Default.Subtitle = this.Add(oSubtitle);
		this.Add(oSubtitle.CreateLinkedCharacterStyle("Subtitle Char", this.Default.Character));

		// Создаем стиль "Цитата"
		var oQuote = new CStyle("Quote", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
		oQuote.CreateQuote();
		this.Default.Quote = this.Add(oQuote);
		this.Add(oQuote.CreateLinkedCharacterStyle("Quote Char"), this.Default.Character);

		// Создаем стиль "Выделенная цитата"
		var oIntenseQuote = new CStyle("Intense Quote", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
		oIntenseQuote.CreateIntenseQuote();
		this.Default.IntenseQuote = this.Add(oIntenseQuote);
		this.Add(oIntenseQuote.CreateLinkedCharacterStyle("Intense Quote Char"), this.Default.Character);

		// Создаем стандартный стиль верхнего колонтитула
		var oHeader = new CStyle("Header", this.Default.Paragraph, null, styletype_Paragraph);
		oHeader.CreateHeader();
		this.Default.Header = this.Add(oHeader);
		this.Add(oHeader.CreateLinkedCharacterStyle("Header Char", this.Default.Character));

		// Создаем стандартный стиль нижнего колонтитула
		var oFooter = new CStyle("Footer", this.Default.Paragraph, null, styletype_Paragraph);
		oFooter.CreateFooter();
		this.Default.Footer = this.Add(oFooter);
		this.Add(oFooter.CreateLinkedCharacterStyle("Footer Char", this.Default.Character));

		// Создаем стиль для таблиц, который будет применяться к новым таблицам
		var Style_TableGrid = new CStyle("Table Grid", this.Default.Table, null, styletype_Table);
		Style_TableGrid.Create_TableGrid();
		this.Default.TableGrid = this.Add(Style_TableGrid);

        /*
         // Создаем стандартный стиль для таблиц
         var Style_Table = new CStyle("LightShading", this.Default.Table, null, styletype_Table );
         Style_Table.Create_Table_LightShading();
         this.Add( Style_Table );

         // Создаем стандартный стиль для таблиц
         var Style_Table = new CStyle("ColorfulListAccent6", this.Default.Table, null, styletype_Table );
         Style_Table.Create_Table_ColorfulListAccent6();
         this.Add( Style_Table );
         */

        // Стандартные стили таблиц
        var Style_Table_Lined = new CStyle("Lined", this.Default.Table, null, styletype_Table );
        Style_Table_Lined.Create_Table_Lined(new CDocumentColor(0x7F, 0x7F, 0x7F), new CDocumentColor(0xF2, 0xF2, 0xF2));
        this.Add( Style_Table_Lined );

        var Style_Table_Lined_Accent1 = new CStyle("Lined - Accent 1", this.Default.Table, null, styletype_Table );
        Style_Table_Lined_Accent1.Create_Table_Lined( new CDocumentColor(0x54, 0x8D, 0xD4), new CDocumentColor(0xC6, 0xD9, 0xF1));
        this.Add( Style_Table_Lined_Accent1 );

        var Style_Table_Lined_Accent2 = new CStyle("Lined - Accent 2", this.Default.Table, null, styletype_Table );
        Style_Table_Lined_Accent2.Create_Table_Lined( new CDocumentColor(0xD9, 0x95, 0x94), new CDocumentColor(0xF2, 0xDB, 0xDB));
        this.Add( Style_Table_Lined_Accent2 );

        var Style_Table_Lined_Accent3 = new CStyle("Lined - Accent 3", this.Default.Table, null, styletype_Table );
        Style_Table_Lined_Accent3.Create_Table_Lined( new CDocumentColor(0x9B, 0xB5, 0x59), new CDocumentColor(0xEA, 0xF1, 0xDD));
        this.Add( Style_Table_Lined_Accent3 );

        var Style_Table_Lined_Accent4 = new CStyle("Lined - Accent 4", this.Default.Table, null, styletype_Table );
        Style_Table_Lined_Accent4.Create_Table_Lined( new CDocumentColor(0xB2, 0xA1, 0xC7), new CDocumentColor(0xE5, 0xDF, 0xEC));
        this.Add( Style_Table_Lined_Accent4 );

        var Style_Table_Lined_Accent5 = new CStyle("Lined - Accent 5", this.Default.Table, null, styletype_Table );
        Style_Table_Lined_Accent5.Create_Table_Lined( new CDocumentColor(0x4B, 0xAC, 0xC6), new CDocumentColor(0xDA, 0xEE, 0xF3));
        this.Add( Style_Table_Lined_Accent5 );

        var Style_Table_Lined_Accent6 = new CStyle("Lined - Accent 6", this.Default.Table, null, styletype_Table );
        Style_Table_Lined_Accent6.Create_Table_Lined( new CDocumentColor(0xF7, 0x96, 0x46), new CDocumentColor(0xFD, 0xE9, 0xD9));
        this.Add( Style_Table_Lined_Accent6 );

        var Style_Table_Bordered = new CStyle("Bordered", this.Default.Table, null, styletype_Table );
        Style_Table_Bordered.Create_Table_Bordered( new CDocumentColor(0xD9, 0xD9, 0xD9), new CDocumentColor(0x7F, 0x7F, 0x7F));
        this.Add( Style_Table_Bordered );

        var Style_Table_Bordered_Accent_1 = new CStyle("Bordered - Accent 1", this.Default.Table, null, styletype_Table );
        Style_Table_Bordered_Accent_1.Create_Table_Bordered( new CDocumentColor(0xB8, 0xCC, 0xE4), new CDocumentColor(0x4F, 0x81, 0xBD));
        this.Add( Style_Table_Bordered_Accent_1 );

        var Style_Table_Bordered_Accent_2 = new CStyle("Bordered - Accent 2", this.Default.Table, null, styletype_Table );
        Style_Table_Bordered_Accent_2.Create_Table_Bordered( new CDocumentColor(0xE5, 0xB8, 0xB7), new CDocumentColor(0xD9, 0x95, 0x94));
        this.Add( Style_Table_Bordered_Accent_2 );

        var Style_Table_Bordered_Accent_3 = new CStyle("Bordered - Accent 3", this.Default.Table, null, styletype_Table );
        Style_Table_Bordered_Accent_3.Create_Table_Bordered( new CDocumentColor(0xD6, 0xE3, 0xBC), new CDocumentColor(0xC2, 0xD6, 0x9B));
        this.Add( Style_Table_Bordered_Accent_3 );

        var Style_Table_Bordered_Accent_4 = new CStyle("Bordered - Accent 4", this.Default.Table, null, styletype_Table );
        Style_Table_Bordered_Accent_4.Create_Table_Bordered( new CDocumentColor(0xCC, 0xC0, 0xD9), new CDocumentColor(0xB2, 0xA1, 0xC7));
        this.Add( Style_Table_Bordered_Accent_4 );

        var Style_Table_Bordered_Accent_5 = new CStyle("Bordered - Accent 5", this.Default.Table, null, styletype_Table );
        Style_Table_Bordered_Accent_5.Create_Table_Bordered( new CDocumentColor(0xB6, 0xDD, 0xE8), new CDocumentColor(0x92, 0xCD, 0xDC));
        this.Add( Style_Table_Bordered_Accent_5 );

        var Style_Table_Bordered_Accent_6 = new CStyle("Bordered - Accent 6", this.Default.Table, null, styletype_Table );
        Style_Table_Bordered_Accent_6.Create_Table_Bordered( new CDocumentColor(0xFB, 0xD4, 0xB4), new CDocumentColor(0xFA, 0xBF, 0x8F));
        this.Add( Style_Table_Bordered_Accent_6 );

        var Style_Table_BorderedLined = new CStyle("Bordered & Lined", this.Default.Table, null, styletype_Table );
        Style_Table_BorderedLined.Create_Table_BorderedAndLined(new CDocumentColor(0x59, 0x59, 0x59), new CDocumentColor(0x7F, 0x7F, 0x7F), new CDocumentColor(0xD9, 0xD9, 0xD9), new CDocumentColor(0xF2, 0xF2, 0xF2));
        this.Add( Style_Table_BorderedLined );

        var Style_Table_BorderedLined_Accent1 = new CStyle("Bordered & Lined - Accent 1", this.Default.Table, null, styletype_Table );
        Style_Table_BorderedLined_Accent1.Create_Table_BorderedAndLined(new CDocumentColor(0x1F, 0x49, 0x7D), new CDocumentColor(0x54, 0x8D, 0xD4), new CDocumentColor(0xC6, 0xD9, 0xF1), new CDocumentColor(0xC6, 0xD9, 0xF1));
        this.Add( Style_Table_BorderedLined_Accent1 );

        var Style_Table_BorderedLined_Accent2 = new CStyle("Bordered & Lined - Accent 2", this.Default.Table, null, styletype_Table );
        Style_Table_BorderedLined_Accent2.Create_Table_BorderedAndLined( new CDocumentColor(0xC0, 0x50, 0x4D), new CDocumentColor(0xD9, 0x95, 0x94), new CDocumentColor(0xF2, 0xDB, 0xDB), new CDocumentColor(0xF2, 0xDB, 0xDB));
        this.Add( Style_Table_BorderedLined_Accent2 );

        var Style_Table_BorderedLined_Accent3 = new CStyle("Bordered & Lined - Accent 3", this.Default.Table, null, styletype_Table );
        Style_Table_BorderedLined_Accent3.Create_Table_BorderedAndLined( new CDocumentColor(0x76, 0x92, 0x3C), new CDocumentColor(0x9B, 0xBB, 0x59), new CDocumentColor(0xEA, 0xF1, 0xDD), new CDocumentColor(0xEA, 0xF1, 0xDD));
        this.Add( Style_Table_BorderedLined_Accent3 );

        var Style_Table_BorderedLined_Accent4 = new CStyle("Bordered & Lined - Accent 4", this.Default.Table, null, styletype_Table );
        Style_Table_BorderedLined_Accent4.Create_Table_BorderedAndLined( new CDocumentColor(0x80, 0x64, 0xA2), new CDocumentColor(0xB2, 0xA1, 0xC7), new CDocumentColor(0xE5, 0xDF, 0xEC), new CDocumentColor(0xE5, 0xDF, 0xEC));
        this.Add( Style_Table_BorderedLined_Accent4 );

        var Style_Table_BorderedLined_Accent5 = new CStyle("Bordered & Lined - Accent 5", this.Default.Table, null, styletype_Table );
        Style_Table_BorderedLined_Accent5.Create_Table_BorderedAndLined( new CDocumentColor(0x31, 0x84, 0x9B), new CDocumentColor(0x4B, 0xAC, 0xC6), new CDocumentColor(0xDA, 0xEE, 0xF3), new CDocumentColor(0xDA, 0xEE, 0xF3));
        this.Add( Style_Table_BorderedLined_Accent5 );

        var Style_Table_BorderedLined_Accent6 = new CStyle("Bordered & Lined - Accent 6", this.Default.Table, null, styletype_Table );
        Style_Table_BorderedLined_Accent6.Create_Table_BorderedAndLined( new CDocumentColor(0xE3, 0x6C, 0x0A), new CDocumentColor(0xF7, 0x96, 0x46), new CDocumentColor(0xFD, 0xE9, 0xD9), new CDocumentColor(0xFD, 0xE9, 0xD9));
        this.Add( Style_Table_BorderedLined_Accent6 );

        // Создаем стиль гиперссылки
        var oHyperlink = new CStyle("Hyperlink", null, null, styletype_Character );
		oHyperlink.CreateHyperlink();
        this.Default.Hyperlink = this.Add(oHyperlink);

		// Создаем стили для сносок
		var oFootnoteText = new CStyle("footnote text", this.Default.Paragraph, null, styletype_Paragraph);
		oFootnoteText.CreateFootnoteText();
		this.Default.FootnoteText = this.Add(oFootnoteText);
		this.Default.FootnoteTextChar = this.Add(oFootnoteText.CreateLinkedCharacterStyle("Footnote Text Char"), this.Default.Character);

		var oFootnoteReference = new CStyle("footnote reference", this.Default.Character, null, styletype_Character);
		oFootnoteReference.CreateFootnoteReference();
		this.Default.FootnoteReference = this.Add(oFootnoteReference);

		for (var nLvl = 0; nLvl <= 8; ++nLvl)
		{
			var oStyleTOC = new CStyle("toc " + (nLvl + 1), this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
			oStyleTOC.CreateTOC(nLvl);
			this.Default.TOC[nLvl] = this.Add(oStyleTOC);
		}

		var oStyleTOCHeading = new CStyle("TOC Heading", this.Default.TOCHeading);
		oStyleTOCHeading.CreateTOCHeading();
		this.Default.TOCHeading = this.Add(oStyleTOCHeading);

        // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
        g_oTableId.Add( this, this.Id );
    }
	else
	{
		this.Default = {
			ParaPr      : new CParaPr(),
			TextPr      : new CTextPr(),
			TablePr     : new CTablePr(),
			TableRowPr  : new CTableRowPr(),
			TableCellPr : new CTableCellPr(),

			Paragraph         : null,
			Character         : null,
			Numbering         : null,
			Table             : null,
			TableGrid         : null,
			Headings          : [],
			ParaList          : null,
			Header            : null,
			Footer            : null,
			Hyperlink         : null,
			FootnoteText      : null,
			FootnoteTextChar  : null,
			FootnoteReference : null,

			TOC               : [],
			TOCHeading        : null
		};

		// Заполняем значения по умолчанию
		this.Default.ParaPr.Init_Default();
		this.Default.TextPr.Init_Default();
		this.Default.TablePr.Init_Default();
		this.Default.TableRowPr.Init_Default();
		this.Default.TableCellPr.Init_Default();

		this.Style = [];
	}

    this.LogicDocument = null;
}

CStyles.prototype =
{
//-----------------------------------------------------------------------------------
// Работаем с Id данного объекта
//-----------------------------------------------------------------------------------
    GetId : function()
    {
        return this.Id;
    },

    Get_Id : function()
    {
        return this.GetId();
    },
//-----------------------------------------------------------------------------------
// Базовые функции для работы со стилем
//-----------------------------------------------------------------------------------
	Add : function(Style)
	{
		var Id = Style.Get_Id();
		History.Add(new CChangesStylesAdd(this, Id, Style));
		this.Style[Id] = Style;
		this.Update_Interface(Id);
		return Id;
	},

	Remove : function(Id)
	{
		History.Add(new CChangesStylesRemove(this, Id, this.Style[Id]));
		delete this.Style[Id];
		this.Update_Interface(Id);
	},

	SetDefaultParagraph : function(Id)
	{
		if (Id !== this.Default.Paragraph)
		{
			History.Add(new CChangesStylesChangeDefaultParagraphId(this, this.Default.Paragraph, Id));
			this.Default.Paragraph = Id;
		}
	},

	SetDefaultCharacter : function(Id)
	{
		if (Id !== this.Default.Character)
		{
			History.Add(new CChangesStylesChangeDefaultCharacterId(this, this.Default.Character, Id));
			this.Default.Character = Id;
		}
	},

	SetDefaultNumbering : function(Id)
	{
		if (Id !== this.Default.Numbering)
		{
			History.Add(new CChangesStylesChangeDefaultNumberingId(this, this.Default.Numbering, Id));
			this.Default.Numbering = Id;
		}
	},

	SetDefaultTable : function(Id)
	{
		if (Id !== this.Default.Table)
		{
			History.Add(new CChangesStylesChangeDefaultTableId(this, this.Default.Table, Id));
			this.Default.Table = Id;
		}
	},

	SetDefaultTableGrid : function(Id)
	{
		if (Id !== this.Default.TableGrid)
		{
			History.Add(new CChangesStylesChangeDefaultTableGridId(this, this.Default.TableGrid, Id));
			this.Default.TableGrid = Id;
		}
	},

	SetDefaultParaList : function(Id)
	{
		if (Id !== this.Default.ParaList)
		{
			History.Add(new CChangesStylesChangeDefaultParaListId(this, this.Default.ParaList, Id));
			this.Default.ParaList = Id;
		}
	},

	SetDefaultHeader : function(Id)
	{
		if (Id !== this.Default.Header)
		{
			History.Add(new CChangesStylesChangeDefaultHeaderId(this, this.Default.Header, Id));
			this.Default.Header = Id;
		}
	},

	SetDefaultFooter : function(Id)
	{
		if (Id !== this.Default.Footer)
		{
			History.Add(new CChangesStylesChangeDefaultFooterId(this, this.Default.Footer, Id));
			this.Default.Footer = Id;
		}
	},
	
	SetDefaultHyperlink : function(Id)
	{
		if (Id !== this.Default.Hyperlink)
		{
			History.Add(new CChangesStylesChangeDefaultHyperlinkId(this, this.Default.Hyperlink, Id));
			this.Default.Hyperlink = Id;
		}
	},

	SetDefaultFootnoteText : function(Id)
	{
		if (Id !== this.Default.FootnoteText)
		{
			History.Add(new CChangesStylesChangeDefaultFootnoteTextId(this, this.Default.FootnoteText, Id));
			this.Default.FootnoteText = Id;
		}
	},

	SetDefaultFootnoteTextChar : function(Id)
	{
		if (Id !== this.Default.FootnoteTextChar)
		{
			History.Add(new CChangesStylesChangeDefaultFootnoteTextCharId(this, this.Default.FootnoteTextChar, Id));
			this.Default.FootnoteTextChar = Id;
		}
	},

	SetDefaultFootnoteReference : function(Id)
	{
		if (Id !== this.Default.FootnoteReference)
		{
			History.Add(new CChangesStylesChangeDefaultFootnoteReferenceId(this, this.Default.FootnoteReference, Id));
			this.Default.FootnoteReference = Id;
		}
	},

	SetDefaultHeading : function(Id, Lvl)
	{
		if (Id !== this.Default.Headings[Lvl])
		{
			History.Add(new CChangesStylesChangeDefaultHeadingsId(this, this.Default.Headings[Lvl], Id, Lvl));
			this.Default.Headings[Lvl] = Id;
		}
	},

	SetDefaultNoSpacing : function(Id)
	{
		if (Id !== this.Default.NoSpacing)
		{
			History.Add(new CChangesStylesChangeDefaultNoSpacingId(this, this.Default.NoSpacing, Id));
			this.Default.NoSpacing = Id;
		}
	},

	SetDefaultTitle : function(Id)
	{
		if (Id !== this.Default.Title)
		{
			History.Add(new CChangesStylesChangeDefaultTitleId(this, this.Default.Title, Id));
			this.Default.Title = Id;
		}
	},

	SetDefaultSubtitle : function(Id)
	{
		if (Id !== this.Default.Subtitle)
		{
			History.Add(new CChangesStylesChangeDefaultSubtitleId(this, this.Default.Subtitle, Id));
			this.Default.Subtitle = Id;
		}
	},

	SetDefaultQuote : function(Id)
	{
		if (Id !== this.Default.Quote)
		{
			History.Add(new CChangesStylesChangeDefaultQuoteId(this, this.Default.Quote, Id));
			this.Default.Quote = Id;
		}
	},

	SetDefaultIntenseQuote : function(Id)
	{
		if (Id !== this.Default.IntenseQuote)
		{
			History.Add(new CChangesStylesChangeDefaultIntenseQuoteId(this, this.Default.IntenseQuote, Id));
			this.Default.IntenseQuote = Id;
		}
	},

	RemapIdReferences : function(OldId, NewId)
	{
		if (OldId === this.Default.Paragraph)
			this.SetDefaultParagraph(NewId);

		if (OldId === this.Default.Character)
			this.SetDefaultCharacter(NewId);

		if (OldId === this.Default.Numbering)
			this.SetDefaultNumbering(NewId);

		if (OldId === this.Default.Table)
			this.SetDefaultTable(NewId);

		if (OldId === this.Default.TableGrid)
			this.SetDefaultTableGrid(NewId);

		if (OldId === this.Default.ParaList)
			this.SetDefaultParaList(NewId);

		if (OldId === this.Default.Header)
			this.SetDefaultHeader(NewId);

		if (OldId === this.Default.Footer)
			this.SetDefaultFooter(NewId);

		if (OldId === this.Default.Hyperlink)
			this.SetDefaultHyperlink(NewId);

		if (OldId === this.Default.FootnoteText)
			this.SetDefaultFootnoteText(NewId);

		if (OldId === this.Default.FootnoteTextChar)
			this.SetDefaultFootnoteTextChar(NewId);

		if (OldId === this.Default.FootnoteReference)
			this.SetDefaultFootnoteReference(NewId);

		for (var nIndex = 0, nCount = this.Default.Headings.length; nIndex < nCount; ++nIndex)
		{
			if (OldId === this.Default.Headings[nIndex])
				this.SetDefaultHeading(NewId, nIndex);
		}

		if (OldId === this.Default.NoSpacing)
			this.SetDefaultNoSpacing(NewId);

		if (OldId === this.Default.Title)
			this.SetDefaultTitle(NewId);

		if (OldId === this.Default.Subtitle)
			this.SetDefaultSubtitle(NewId);

		if (OldId === this.Default.Quote)
			this.SetDefaultQuote(NewId);

		if (OldId === this.Default.IntenseQuote)
			this.SetDefaultIntenseQuote(NewId);

		for (var Id in this.Style)
		{
			this.Style[Id].RemapIdReferences(OldId, NewId);
		}
	},

    Copy : function()
    {
        var Styles = new CStyles();

        Styles.Default.ParaPr      = this.Default.ParaPr.Copy();
        Styles.Default.TextPr      = this.Default.TextPr.Copy();
        Styles.Default.TablePr     = this.Default.TablePr.Copy();
        Styles.Default.TableRowPr  = this.Default.TableRowPr.Copy();
        Styles.Default.TableCellPr = this.Default.TableCellPr.Copy();

        // Тут можно копировать напрямую, т.к. это либо null, либо StyleId, который мы повторяем
		Styles.Default.Paragraph    = this.Default.Paragraph;
		Styles.Default.Character    = this.Default.Character;
		Styles.Default.Numbering    = this.Default.Numbering;
		Styles.Default.Table        = this.Default.Table;
		Styles.Default.TableGrid    = this.Default.TableGrid;
		Styles.Default.ParaList     = this.Default.ParaList;
		Styles.Default.Header       = this.Default.Header;
		Styles.Default.Footer       = this.Default.Footer;
		Styles.Default.Hyperlink    = this.Default.Hyperlink;
		Styles.Default.NoSpacing    = this.Default.NoSpacing;
		Styles.Default.Title        = this.Default.Title;
		Styles.Default.Subtitle     = this.Default.Subtitle;
		Styles.Default.Quote        = this.Default.Quote;
		Styles.Default.IntenseQuote = this.Default.IntenseQuote;

        for (var Index = 0, Count = this.Default.Headings.length; Index < Count; Index++)
        {
            Styles.Default.Headings[Index] = this.Default.Headings[Index];
        }

        for (var StyleId in this.Style)
        {
            Styles.Style[StyleId] = this.Style[StyleId].Copy();
        }

        return Styles;
    },
    
    CopyStyle : function()
    {
        var res = [];
        for (var StyleId in this.Style)
        {
            res[StyleId] = this.Style[StyleId].Copy();
        }
        return res;
    },

    Get_DefaultParaPr : function()
    {
        return this.Default.ParaPr;
    },

	Set_DefaultParaPr : function(ParaPr)
	{
		History.Add(new CChangesStylesChangeDefaultParaPr(this, this.Default.ParaPr, ParaPr));
		this.Default.ParaPr.Init_Default();
		this.Default.ParaPr.Merge(ParaPr);

		// TODO: Пока данная функция используется только в билдере, как только будет использоваться в самом редакторе,
		//       надо будет сделать, чтобы происходил пересчет всех стилей.
	},

    Get_DefaultTextPr : function()
    {
        return this.Default.TextPr;
    },

	Set_DefaultTextPr : function(TextPr)
	{
		History.Add(new CChangesStylesChangeDefaultTextPr(this, this.Default.TextPr, TextPr));
        this.Default.TextPr.Init_Default();
		this.Default.TextPr.Merge(TextPr);

		// TODO: Пока данная функция используется только в билдере, как только будет использоваться в самом редакторе,
		//       надо будет сделать, чтобы происходил пересчет всех стилей.
	},
//-----------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------
    Set_LogicDocument : function(LogicDocument)
    {
        this.LogicDocument = LogicDocument;
    },

    Get_Pr : function(StyleId, Type, TableStyle, ShapeStyle)
    {
        var Pr = {TextPr : new CTextPr(), ParaPr : new CParaPr()};
        // Сначала копируем параметры заданные в табличном стиле
        switch (Type)
        {
            case styletype_Paragraph:
            {
                if (undefined === StyleId)
                    StyleId = this.Default.Paragraph;

                if (TableStyle != null || ShapeStyle != null)
                {
                    if (ShapeStyle != null)
                    {
                        Pr.TextPr.Merge(ShapeStyle.TextPr);
                        if(!TableStyle)
                        {
                            Pr.ParaPr.Merge(ShapeStyle.ParaPr);
                        }
                    }
                    if (TableStyle != null)
                    {
                        Pr.TextPr.Merge(TableStyle.TextPr);
                        Pr.ParaPr.Merge(TableStyle.ParaPr);
                    }
                }
                else
                {
                    Pr.TextPr.Merge(this.Default.TextPr);
                    Pr.ParaPr.Merge(this.Default.ParaPr);
                }
                break;
            }
            case styletype_Table:
            {
                if (undefined === StyleId)
                    StyleId = this.Default.Table;

                // Сначала копируем параметры по умолчанию
                Pr.TextPr = this.Default.TextPr.Copy();
                Pr.ParaPr = this.Default.ParaPr.Copy();

                // В таблицах мы не учитываем настройки дефолтового параграфа, т.е. стиля Normal (баг 31469)

                Pr.TablePr     = this.Default.TablePr.Copy();
                Pr.TableRowPr  = this.Default.TableRowPr.Copy();
                Pr.TableCellPr = this.Default.TableCellPr.Copy();

                Pr.TableFirstCol   = new CTableStylePr();
                Pr.TableFirstRow   = new CTableStylePr();
                Pr.TableLastCol    = new CTableStylePr();
                Pr.TableLastRow    = new CTableStylePr();
                Pr.TableBand1Horz  = new CTableStylePr();
                Pr.TableBand1Vert  = new CTableStylePr();
                Pr.TableBand2Horz  = new CTableStylePr();
                Pr.TableBand2Vert  = new CTableStylePr();
                Pr.TableTLCell     = new CTableStylePr();
                Pr.TableTRCell     = new CTableStylePr();
                Pr.TableBLCell     = new CTableStylePr();
                Pr.TableBRCell     = new CTableStylePr();
                Pr.TableWholeTable = new CTableStylePr();

                break;
            }
            case styletype_Character:
            {
                if (undefined === StyleId)
                    StyleId = this.Default.Character;

                Pr.TextPr = new CTextPr();
                break;
            }
        }

        // Рассчитываем стиль
        this.Internal_Get_Pr(Pr, StyleId, Type, ( null === TableStyle && null == ShapeStyle ? true : false ), [], StyleId);

        if (styletype_Table === Type)
        {
            // В таблицах мы не учитываем настройки дефолтового параграфа, т.е. стиля Normal (баг 31469)

            // Соединим настройки для всей таблицы в одну общую настройку и удалим одну из них за ненадобностью
            Pr.ParaPr.Merge(Pr.TableWholeTable.ParaPr);
            Pr.TextPr.Merge(Pr.TableWholeTable.TextPr);
            Pr.TablePr.Merge(Pr.TableWholeTable.TablePr);
            Pr.TableRowPr.Merge(Pr.TableWholeTable.TableRowPr);
            Pr.TableCellPr.Merge(Pr.TableWholeTable.TableCellPr);
        }

        return Pr;
    },

    Get_Next : function(StyleId)
    {
        var NextId = this.Style[StyleId].Next;

        if (null !== NextId && undefined !== this.Style[NextId])
            return NextId;

        return null;
    },

    Get_Name : function(StyleId)
    {
        if ( undefined != this.Style[StyleId] )
            return this.Style[StyleId].Name;

        return "";
    },

    Get_Default_Paragraph : function()
    {
        return this.Default.Paragraph;
    },

    Get_Default_Character : function()
    {
        return this.Default.Character;
    },

    Get_Default_Numbering : function()
    {
        return this.Default.Numbering;
    },

    Get_Default_Table : function()
    {
        return this.Default.Table;
    },

    Get_Default_TableGrid : function()
    {
        return this.Default.TableGrid;
    },

    Get_Default_Heading : function(Lvl)
    {
        Lvl = Math.max( Math.min( Lvl, 8 ), 0 );
        return this.Default.Headings[Lvl];
    },

    Get_Default_ParaList : function()
    {
        return this.Default.ParaList;
    },

    Get_Default_Header : function()
    {
        return this.Default.Header;
    },

    Get_Default_Footer : function()
    {
        return this.Default.Footer;
    },

    Internal_Get_Pr : function(Pr, StyleId, Type, bUseDefault, PassedStyles, StartStyleId)
	{
		// Делаем проверку от зацикливания, среди уже пройденных стилей ищем текущий стриль.
		for (var nIndex = 0, nCount = PassedStyles.length; nIndex < nCount; nIndex++)
		{
			if (PassedStyles[nIndex] == StyleId)
				return;
		}
		PassedStyles.push(StyleId);

		var Style = this.Style[StyleId];
		if (undefined == StyleId || undefined === Style)
		{
			if (true === bUseDefault)
			{
				// Копируем свойства по умолчанию для данного типа
				switch (Type)
				{
					case styletype_Paragraph:
					{
						var DefId = this.Default.Paragraph;

						if (undefined != this.Style[DefId])
						{
							Pr.ParaPr.Merge(this.Style[DefId].ParaPr);
							Pr.TextPr.Merge(this.Style[DefId].TextPr);
						}

						break;
					}
					case styletype_Numbering:
					{
						var DefId = this.Default.Numbering;
						break;
					}
					case styletype_Table:
					{
						var DefId = this.Default.Table;

						if (undefined != this.Style[DefId])
						{
							Pr.ParaPr.Merge(this.Style[DefId].ParaPr);
							Pr.TextPr.Merge(this.Style[DefId].TextPr);
							Pr.TablePr.Merge(this.Styles[DefId].TablePr);
							Pr.TableRowPr.Merge(this.Styles[DefId].TableRowPr);
							Pr.TableCellPr.Merge(this.Styles[DefId].TableCellPr);
						}

						break;
					}
					case styletype_Character:
					{
						var DefId = this.Default.Character;

						if (undefined != this.Style[DefId])
						{
							Pr.TextPr.Merge(this.Style[DefId].TextPr);
						}

						break;
					}
				}
			}

			return;
		}

		if (null === Style.BasedOn)
		{
			// TODO: Проверить нужно ли копировать стили по умолчанию для данного типа стиля, когда сам стиль задан
			//       Для параграфа, вроде как не нужно (см. ivanova_veronica.docx стиль "Colon")

			// Копируем свойства по умолчанию для данного типа
			if (true === bUseDefault)
			{
				// Копируем свойства по умолчанию для данного типа
				switch (Type)
				{
					case styletype_Paragraph:
					{
						//                        var DefId = this.Default.Paragraph;
						//
						//                        Pr.ParaPr.Merge( this.Style[DefId].ParaPr );
						//                        Pr.TextPr.Merge( this.Style[DefId].TextPr );

						break;
					}
					case styletype_Numbering:
					{
						var DefId = this.Default.Numbering;
						break;
					}
					case styletype_Table:
					{
						var DefId = this.Default.Table;

						/*
						 Pr.ParaPr.Merge( this.Style[DefId].ParaPr );
						 Pr.TextPr.Merge( this.Style[DefId].TextPr );
						 Pr.TablePr.Merge( this.Styles[DefId].TablePr );
						 Pr.TableRowPr.Merge( this.Styles[DefId].TableRowPr );
						 Pr.TableCellPr.Merge( this.Styles[DefId].TableCellPr );
						 */

						break;
					}
					case styletype_Character:
					{
						var DefId = this.Default.Character;

						if (undefined != this.Style[DefId])
						{
							Pr.TextPr.Merge(this.Style[DefId].TextPr);
						}

						break;
					}
				}
			}
		}
		else
		{
			// Копируем свойства родительского стиля
			this.Internal_Get_Pr(Pr, Style.BasedOn, Type, false, PassedStyles, StartStyleId);
		}

		// Копируем свойства из стиля нумерации
		var oLogicDocument = this.private_GetLogicDocument();
		if ((styletype_Paragraph === Type || styletype_Table === Type) && undefined != Style.ParaPr.NumPr && oLogicDocument)
		{
			var oNumbering = oLogicDocument.GetNumbering();
			if (0 != Style.ParaPr.NumPr.NumId)
			{
				var oNum = oNumbering.GetNum(Style.ParaPr.NumPr.NumId);
				if (oNum)
				{
					var nLvl = oNum.GetLvlByStyle(StyleId);
					if (-1 != nLvl)
						Pr.ParaPr.Merge(oNumbering.GetParaPr(Style.ParaPr.NumPr.NumId, nLvl));
					else if (undefined !== Style.ParaPr.NumPr.Lvl)
						Pr.ParaPr.Merge(oNumbering.GetParaPr(Style.ParaPr.NumPr.NumId, Style.ParaPr.NumPr.Lvl));
					else
						Pr.ParaPr.NumPr = undefined;
				}
			}
			else
			{
				// Word значение 0 для NumId воспринимает как отсутствие нумерации и обнуляет левый отступ и
				// отступ первой строки
				Pr.ParaPr.NumPr         = undefined;
				Pr.ParaPr.Ind.Left      = 0;
				Pr.ParaPr.Ind.FirstLine = 0;
			}
		}

		// Копируем свойства текущего стиля
		switch (Type)
		{
			case styletype_Paragraph:
			{
				Pr.ParaPr.Merge(Style.ParaPr);
				Pr.TextPr.Merge(Style.TextPr);

				break;
			}
			case styletype_Numbering:
			{
				break;
			}
			case styletype_Table:
			{
				// Делаем как в Word: стиль с именем "Normal Table" используется всегда встроенный (баг 37902)
				if ("Normal Table" !== Style.GetName())
				{
					Pr.ParaPr.Merge(Style.ParaPr);
					Pr.TextPr.Merge(Style.TextPr);

					if (undefined != Style.TablePr)
					{
						Pr.TablePr.Merge(Style.TablePr);
						Pr.TableRowPr.Merge(Style.TableRowPr);
						Pr.TableCellPr.Merge(Style.TableCellPr);

						Pr.TableBand1Horz.Merge(Style.TableBand1Horz);
						Pr.TableBand1Vert.Merge(Style.TableBand1Vert);
						Pr.TableBand2Horz.Merge(Style.TableBand2Horz);
						Pr.TableBand2Vert.Merge(Style.TableBand2Vert);
						Pr.TableFirstCol.Merge(Style.TableFirstCol);
						Pr.TableFirstRow.Merge(Style.TableFirstRow);
						Pr.TableLastCol.Merge(Style.TableLastCol);
						Pr.TableLastRow.Merge(Style.TableLastRow);
						Pr.TableTLCell.Merge(Style.TableTLCell);
						Pr.TableTRCell.Merge(Style.TableTRCell);
						Pr.TableBLCell.Merge(Style.TableBLCell);
						Pr.TableBRCell.Merge(Style.TableBRCell);
						Pr.TableWholeTable.Merge(Style.TableWholeTable);
					}
				}

				break;
			}
			case styletype_Character:
			{
				Pr.TextPr.Merge(Style.TextPr);

				break;
			}
		}
	},

    Document_Get_AllFontNames : function(AllFonts)
    {
        for ( var Id in this.Style )
        {
            var Style = this.Style[Id];
            Style.Document_Get_AllFontNames(AllFonts);
        }

        this.Default.TextPr.Document_Get_AllFontNames(AllFonts);
    },

    Get_AllTableStyles : function()
    {
        var TableStyles = [];
        for ( var Id in this.Style )
        {
            var Style = this.Style[Id];
            if ( styletype_Table === Style.Type )
                TableStyles.push( Id );
        }

        return TableStyles;
    },

    Update_Interface : function(StyleId)
    {
        if (null != this.LogicDocument && undefined !== this.LogicDocument)
        {
            // Данный стиль может быть базовым для других стилей, поэтому нам нужно пересчитать все параграфы, не только у
            // которых выставлен данный стиль, но и у которых выставлен стиль, для которого данный будет базовым (в любом поколении).

            this.LogicDocument.Add_ChangedStyle(this.private_GetAllBasedStylesId(StyleId));
        }
    },

    private_GetAllBasedStylesId : function(StyleId)
    {
        var arrStyles = [];

        // Отдельно добавляем StyleId, т.к. данная функция вызывается и после удаления стиля из списка,
        // но при этом в данный массив стиль должен попасть.
        arrStyles.push(StyleId);

        for (var CurStyleId in this.Style)
        {
            if (CurStyleId == StyleId)
            {
                arrStyles.push(StyleId);
            }

            var oStyle = this.Style[CurStyleId];
            var BaseId = oStyle.Get_BasedOn();
            var PassedStyles = [];
            while (null != BaseId && undefined != BaseId)
            {
                var bBreak = false;
                // Делаем проверку от зацикливания, среди уже пройденных стилей ищем текущий стриль.
                for (var nIndex = 0, nCount = PassedStyles.length; nIndex < nCount; nIndex++)
                {
                    if (PassedStyles[nIndex] == BaseId)
                    {
                        bBreak = true;
                        break;
                    }
                }

                if (true === bBreak)
                    break;

                PassedStyles.push(BaseId);

                if (BaseId == StyleId)
                {
                    arrStyles.push(CurStyleId);
                    break;
                }

                var BaseStyle = this.Style[BaseId];
                if (!BaseStyle)
                    break;

                BaseId = BaseStyle.Get_BasedOn();
            }
        }

        return arrStyles;
    },

    Check_StyleNumberingOnLoad : function(Numbering)
    {
        // TODO: Похоже Word сначала пробегается по дефолтовым стилям, типа Heading, потом по остальным.
        for (var StyleId in this.Style)
        {
            var Style = this.Style[StyleId];

            var oNumPr = Style.ParaPr.NumPr;
            if (!oNumPr || !oNumPr.NumId)
                continue;

            var oNum = Numbering.GetNum(oNumPr.NumId);
            if (!oNum)
                continue;

            var nLvl = (oNumPr.Lvl ? oNumPr.Lvl : 0);
            var oLvl = oNum.GetLvl(nLvl);

            if (!oLvl || oLvl.GetPStyle())
                continue;

            var oNewLvl = oLvl.Copy();
            oNewLvl.PStyle = StyleId;
            oNum.SetLvl(oNewLvl, nLvl);
        }
    },
//-----------------------------------------------------------------------------------
// Undo/Redo функции
//-----------------------------------------------------------------------------------
	GetSelectionState : function()
    {
    },

	SetSelectionState : function(State, StateIndex)
    {
    },

    Get_ParentObject_or_DocumentPos : function()
    {
        return { Type : AscDFH.historyitem_recalctype_Inline, Data : 0 };
    },

    Refresh_RecalcData : function(Data)
    {
        var Type = Data.Type;

        var bNeedRecalc = false;

        switch ( Type )
        {
            case AscDFH.historyitem_Styles_Add   :
            case AscDFH.historyitem_Styles_Remove:
            {
                bNeedRecalc = true;
                break;
            }
        }

        if ( true === bNeedRecalc )
        {
            // Сообщаем родительскому классу, что изменения произошли в элементе с номером this.Index и на странице this.PageNum
            return this.Refresh_RecalcData2(Data.Id);
        }
    },

    Refresh_RecalcData2 : function(StyleId)
    {
        if (undefined != StyleId)
        {
            // TODO: Надо сделать механизм, чтобы данное действие не вызывалось много раз подряд, а только 1.
            var LogicDocument = editor.WordControl.m_oLogicDocument;

            var AllParagraphs = [];

            if (StyleId != this.Default.Paragraph)
            {
                var AllStylesId = this.private_GetAllBasedStylesId(StyleId);
                AllParagraphs = LogicDocument.GetAllParagraphsByStyle(AllStylesId);
            }
            else
            {
                AllParagraphs = LogicDocument.GetAllParagraphs({All : true});
            }

            var Count = AllParagraphs.length;
            for (var Index = 0; Index < Count; Index++)
            {
                var Para = AllParagraphs[Index];
                Para.Refresh_RecalcData({ Type : AscDFH.historyitem_Paragraph_PStyle });
            }
        }
    },
//-----------------------------------------------------------------------------------
// Функции для совместного редактирования
//-----------------------------------------------------------------------------------
    Load_LinkData : function(LinkData)
    {
        if (undefined !== LinkData.UpdateStyleId)
        {
            var StyleId = LinkData.UpdateStyleId;

            var LogicDocument = editor.WordControl.m_oLogicDocument;
            if (!LogicDocument)
                return;

            var AllParagraphs = [];

            if (StyleId != this.Default.Paragraph)
            {
                var AllStylesId = this.private_GetAllBasedStylesId(StyleId);
                AllParagraphs = LogicDocument.GetAllParagraphsByStyle(AllStylesId);
            }
            else
            {
                AllParagraphs = LogicDocument.GetAllParagraphs({All : true});
            }

            var Count = AllParagraphs.length;
            for (var Index = 0; Index < Count; Index++)
            {
                var Para = AllParagraphs[Index];
                Para.Recalc_CompiledPr();
                Para.Recalc_RunsCompiledPr();
            }
        }
    }
};
/**
 * Получаем стиль по идентификатору
 * @param sStyleId {string}
 * @returns {?CStyle}
 */
CStyles.prototype.Get = function(sStyleId)
{
	return (this.Style[sStyleId] ? this.Style[sStyleId] : null);
};
/**
 * Получаем идентификатор стиля по его имени
 * @param {string} sName
 * @param {boolean} [isReturnParaDefault=false] Возвращать ли дефолтовый стиль для параграфа, если стиль не найден
 * @returns {?string}
 */
CStyles.prototype.GetStyleIdByName = function(sName, isReturnParaDefault)
{
	for (var sId in this.Style)
	{
		var oStyle = this.Style[sId];
		if (sName === oStyle.GetName())
			return sId;
	}

	if (isReturnParaDefault)
		return this.Default.Paragraph;

	return null;
};
/**
 * Получаем идентификатор стиля по умолчанию для параграфов
 * @returns {string}
 */
CStyles.prototype.GetDefaultParagraph = function()
{
	return this.Default.Paragraph;
};
CStyles.prototype.GetDefaultFootnoteText = function()
{
	return this.Default.FootnoteText;
};
CStyles.prototype.GetDefaultFootnoteTextChar = function()
{
	return this.Default.FootnoteTextChar;
};
CStyles.prototype.GetDefaultFootnoteReference = function()
{
	return this.Default.FootnoteReference;
};
CStyles.prototype.GetDefaultTOC = function(nLvl)
{
	nLvl = Math.max(Math.min(nLvl, 8), 0);
	return this.Default.TOC[nLvl];
};
CStyles.prototype.GetDefaultTOCHeading = function()
{
	return this.Default.TOCHeading;
};
CStyles.prototype.GetDefaultHyperlink = function()
{
	return this.Default.Hyperlink;
};
CStyles.prototype.GetDefaultHeading = function(nLvl)
{
	return this.Default.Headings[Math.max(Math.min(nLvl, 8), 0)];
};
CStyles.prototype.GetHeadingLevelByName = function(sStyleName)
{
	var sId = this.GetStyleIdByName(sStyleName);
	if (!sId)
		return -1;

	for (var nIndex = 0; nIndex <= 8; ++nIndex)
	{
		if (sId === this.Default.Headings[nIndex])
			return nIndex;
	}

	return -1;
};
/**
 * Получаем тип набора стилей для Table of Contents
 * @returns {Asc.c_oAscTOCStylesType}
 */
CStyles.prototype.GetTOCStylesType = function()
{
	if (this.private_CheckTOCStyles(Asc.c_oAscTOCStylesType.Simple))
		return Asc.c_oAscTOCStylesType.Simple;
	else if (this.private_CheckTOCStyles(Asc.c_oAscTOCStylesType.Standard))
		return Asc.c_oAscTOCStylesType.Standard;
	else if (this.private_CheckTOCStyles(Asc.c_oAscTOCStylesType.Modern))
		return Asc.c_oAscTOCStylesType.Modern;
	else if (this.private_CheckTOCStyles(Asc.c_oAscTOCStylesType.Classic))
		return Asc.c_oAscTOCStylesType.Classic;

	return Asc.c_oAscTOCStylesType.Current;
};
CStyles.prototype.private_CheckTOCStyles = function(nType)
{
	for (var nLvl = 0; nLvl <= 8; ++nLvl)
	{
		if (!this.private_CheckTOCStyle(nLvl, nType))
			return false;
	}

	return true;
};
CStyles.prototype.private_CheckTOCStyle = function(nLvl, nType)
{
	var oTOCStyle = this.Get(this.GetDefaultTOC(nLvl));

	if (!this.LogicDocument || !oTOCStyle)
		return false;

	this.LogicDocument.TurnOffHistory();
	var oCheckStyle = new CStyle();
	oCheckStyle.Clear(oTOCStyle.GetName(), oTOCStyle.GetBasedOn(), oTOCStyle.GetNext(), oTOCStyle.GetType());
	oCheckStyle.CreateTOC(nLvl, nType);
	this.LogicDocument.TurnOnHistory();

	return (!!oCheckStyle.IsEqual(oTOCStyle));
};
/**
 * Переделываем стили для Table of Contents на заданную коллекцию стилей
 * @param nType {Asc.c_oAscTOCStylesType}
 */
CStyles.prototype.SetTOCStylesType = function(nType)
{
	if (Asc.c_oAscTOCStylesType.Current === nType)
		return;

	for (var nLvl = 0; nLvl <= 8; ++nLvl)
	{
		var oStyle = this.Get(this.GetDefaultTOC(nLvl));
		if (!oStyle)
			continue;

		oStyle.Clear(oStyle.GetName(), oStyle.GetBasedOn(), oStyle.GetNext(), oStyle.GetType());
		oStyle.CreateTOC(nLvl, nType);
	}
};
/**
 * Получаем массив стилей в виде классов Asc.CAscStyle
 * @returns {Asc.CAscStyle[]}
 */
CStyles.prototype.GetAscStylesArray = function()
{
	var arrStyles = [];
	for (var sId in this.Style)
	{
		arrStyles.push(this.Style[sId].ToAscStyle());
	}

	return arrStyles;
};
/**
 * Получаем ссылку на класс документа
 * @returns {?CDocument}
 */
CStyles.prototype.private_GetLogicDocument = function()
{
	return (editor && editor.WordControl && editor.WordControl.m_oLogicDocument ? editor.WordControl.m_oLogicDocument : null);
};

function CDocumentColor(r,g,b, Auto)
{
    this.r = r;
    this.g = g;
    this.b = b;

    this.Auto = ( Auto === undefined ? false : Auto );
}

CDocumentColor.prototype =
{
    Copy : function()
    {
        return new CDocumentColor(this.r, this.g, this.b, this.Auto);
    },

    Write_ToBinary : function(Writer)
    {
        // Byte : r
        // Byte : g
        // Byte : b
        // Bool : Auto

        Writer.WriteByte( this.r );
        Writer.WriteByte( this.g );
        Writer.WriteByte( this.b );
        Writer.WriteBool( this.Auto );
    },

    Read_FromBinary : function(Reader)
    {
        // Byte : r
        // Byte : g
        // Byte : b
        // Bool : Auto

        this.r = Reader.GetByte();
        this.g = Reader.GetByte();
        this.b = Reader.GetByte();
        this.Auto = Reader.GetBool();
    },

    Set : function(r, g, b, Auto)
    {
        this.r = r;
        this.g = g;
        this.b = b;
        this.Auto = ( Auto === undefined ? false : Auto );
    },

    Compare : function(Color)
    {
        if (this.r === Color.r
            && this.g === Color.g
            && this.b === Color.b
            && (this.Auto === Color.Auto
                || (false === this.Auto
                    && Color.Auto === undefined)))
            return true;

        return false;
    },

    Is_Equal : function(Color)
    {
        if (this.r !== Color.r
            || this.g !== Color.g
            || this.b !== Color.b
            || this.Auto !== Color.Auto)
            return false;

        return true;
    },

    Check_BlackAutoColor : function()
    {
        // TODO: Коэффициенты подобраны опытным путем. В некоторых "пограничных" случаях
        //       может быть несовпадение с Word (когда изменение на 1 одного из каналов
        //       меняет цвет), чтобы такого не было надо более точно подобрать коэффициенты.
        if ( 0.5 * this.r + this.g + 0.195 * this.b < 103 )
            return false;

        return true;
    }
};
CDocumentColor.prototype.WriteToBinary = function(oWriter)
{
	this.Write_ToBinary(oWriter);
};
CDocumentColor.prototype.ReadFromBinary = function(oReader)
{
	this.Read_FromBinary(oReader);
};

function CDocumentShd()
{
    this.Value = c_oAscShdNil;
    this.Color = new CDocumentColor(255, 255, 255);
    this.Unifill = undefined;
    this.FillRef = undefined;
}

CDocumentShd.prototype =
{
    Copy : function()
    {
        var Shd = new CDocumentShd();
        Shd.Value = this.Value;

        if ( undefined !== this.Color )
            Shd.Color.Set( this.Color.r, this.Color.g, this.Color.b, this.Color.Auto );
        
        if( undefined !== this.Unifill )
            Shd.Unifill = this.Unifill.createDuplicate();

        if( undefined !== this.FillRef )
            Shd.FillRef = this.FillRef.createDuplicate();

        return Shd;
    },

    Compare : function(Shd)
    {
        if ( undefined === Shd )
            return false;
        
        if ( this.Value === Shd.Value )
        {
            switch ( this.Value )
            {
                case c_oAscShdNil:
                    return true;

                case c_oAscShdClear:
                {
                    return this.Color.Compare( Shd.Color ) && AscFormat.CompareUnifillBool(this.Unifill, Shd.Unifill);
                }
            }
        }

        return false;
    },

    Is_Equal : function(Shd)
    {
        if (this.Value !== Shd.Value
            || true !== IsEqualStyleObjects(this.Color, Shd.Color)
            || true !== IsEqualStyleObjects(this.Unifill, Shd.Unifill))
            return false;

        return true;
    },
    
    Get_Color : function(Paragraph)
    {
        if ( undefined !== this.Unifill )
        {
            this.Unifill.check(Paragraph.Get_Theme(), Paragraph.Get_ColorMap());
            var RGBA = this.Unifill.getRGBAColor();
            return new CDocumentColor( RGBA.R, RGBA.G, RGBA.B, false );
        }
        else
            return this.Color;
    },

    Get_Color2 : function(Theme, ColorMap)
    {
        if ( undefined !== this.Unifill )
        {
            this.Unifill.check(Theme, ColorMap);
            var RGBA = this.Unifill.getRGBAColor();
            return new CDocumentColor( RGBA.R, RGBA.G, RGBA.B, false );
        }
        else
            return this.Color;
    },

    Get_Color3 : function(Theme, ColorMap)
    {
        if ( undefined !== this.Unifill )
        {
            this.Unifill.check(Theme, ColorMap);
            return this.Unifill.getRGBAColor();
        }
        else
        {
            return {R: 255, G: 255, B: 255, A: 255};
        }
    },
    
    Init_Default : function()
    {
        this.Value = c_oAscShdNil;
        this.Color.Set( 0, 0, 0, false );
        this.Unifill = undefined;
        this.FillRef = undefined;
    },

    Set_FromObject : function(Shd)
    {
        if ( undefined === Shd )
        {
            this.Value = c_oAscShdNil;
            return;
        }
        
        this.Value = Shd.Value;
        if ( c_oAscShdNil != Shd.Value )
        {
            if( undefined != Shd.Color )
                this.Color.Set( Shd.Color.r, Shd.Color.g, Shd.Color.b, Shd.Color.Auto );
            if(undefined != Shd.Unifill)
            {
                this.Unifill = Shd.Unifill.createDuplicate();
            }
            if(undefined != Shd.FillRef)
            {
                this.FillRef = Shd.FillRef.createDuplicate();
            }
        }
        else if ( undefined === Shd.Color )
            this.Color = undefined;
    },

    Check_PresentationPr : function(Theme)
    {
        if(this.FillRef && Theme)
        {
            this.Unifill = Theme.getFillStyle(this.FillRef.idx, this.FillRef.Color);
            this.FillRef = undefined;
        }
    },

    Write_ToBinary : function(Writer)
    {
        // Byte : Value
        //
        // Если c_oAscShdClear
        // Variable : Color

        Writer.WriteByte( this.Value );
        if ( c_oAscShdClear === this.Value )
        {
            this.Color.Write_ToBinary(Writer);
            if(this.Unifill)
            {
                Writer.WriteBool(true);
                this.Unifill.Write_ToBinary(Writer);
            }
            else
            {
                Writer.WriteBool(false);
            }
            if(this.FillRef)
            {
                Writer.WriteBool(true);
                this.FillRef.Write_ToBinary(Writer);
            }
            else
            {
                Writer.WriteBool(false);
            }
        }
    },

    Read_FromBinary : function(Reader)
    {
        // Byte : Value
        //
        // Если c_oAscShdClear
        // Variable : Color

        this.Value = Reader.GetByte();

        if ( c_oAscShdClear === this.Value )
        {
            this.Color.Read_FromBinary(Reader);
            if(Reader.GetBool())
            {
                this.Unifill = new AscFormat.CUniFill();
                this.Unifill.Read_FromBinary(Reader);
            }
            if(Reader.GetBool())
            {
                this.FillRef = new AscFormat.StyleRef();
                this.FillRef.Read_FromBinary(Reader);
            }
        }
        else
            this.Color.Set(0, 0, 0);
    }
};

function CDocumentBorder()
{
    this.Color = new CDocumentColor( 0, 0, 0 );
    this.Unifill = undefined;
    this.LineRef = undefined;
    this.Space = 0;
    this.Size  = 0.5 * g_dKoef_pt_to_mm;
    this.Value = border_None;
}

CDocumentBorder.prototype =
{
    Copy : function()
    {
        var Border = new CDocumentBorder();

        if ( undefined === this.Color )
            Border.Color = undefined;
        else
            Border.Color.Set(this.Color.r, this.Color.g, this.Color.b);

        if(undefined === this.Unifill)
            Border.Unifill = undefined;
        else
            Border.Unifill = this.Unifill.createDuplicate();

        if(undefined === this.LineRef)
        {
            Border.LineRef = undefined;
        }
        else
        {
            Border.LineRef = this.LineRef.createDuplicate();
        }

        if ( undefined === this.Space )
            Border.Space = undefined;
        else
            Border.Space = this.Space;

        if ( undefined === this.Size )
            Border.Size = undefined;
        else
            Border.Size  = this.Size;

        if ( undefined === this.Value )
            Border.Value = undefined;
        else
            Border.Value = this.Value;

        return Border;
    },

    Compare : function(Border)
    {
        if ( false === this.Color.Compare(Border.Color) )
            return false;

        if(AscFormat.CompareUnifillBool(this.Unifill, Border.Unifill) === false)
            return false;

        if(this.LineRef !== undefined && Border.LineRef === undefined || Border.LineRef !== undefined && this.LineRef === undefined)
            return false;

        if(this.LineRef !== undefined && !this.LineRef.compare(Border.LineRef))
        {
            return false;
        }

        if ( Math.abs( this.Size - Border.Size ) > 0.001 )
            return false;

        if ( Math.abs( this.Space - Border.Space ) > 0.001 )
            return false;

        if ( this.Value != Border.Value )
            return false;

        return true;
    },

    Is_Equal : function(Border)
    {
        if (true !== IsEqualStyleObjects(this.Color, Border.Color)
            || true !== IsEqualStyleObjects(this.Unifill, Border.Unifill)
            || this.Space !== Border.Space
            || this.Size !== Border.Size
            || this.Value !== Border.Value)
            return false;

        return true;
    },

    Get_Color : function(Paragraph)
    {
        if ( undefined !== this.Unifill )
        {
            this.Unifill.check(Paragraph.Get_Theme(), Paragraph.Get_ColorMap());
            var RGBA = this.Unifill.getRGBAColor();
            return new CDocumentColor( RGBA.R, RGBA.G, RGBA.B, false );
        }
        else
            return this.Color;
    },

    Get_Color2 : function(Theme, ColorMap)
    {
        if ( undefined !== this.Unifill )
        {
            this.Unifill.check(Theme, ColorMap);
            var RGBA = this.Unifill.getRGBAColor();
            return new CDocumentColor( RGBA.R, RGBA.G, RGBA.B, false );
        }
        else
            return this.Color;
    },

    Check_PresentationPr : function(Theme)
    {
        if(this.LineRef && Theme)
        {
            var pen = Theme.getLnStyle(this.LineRef.idx, this.LineRef.Color);

            this.Unifill = pen.Fill;
            this.LineRef = undefined;
            this.Size = AscFormat.isRealNumber(pen.w) ? pen.w / 36000 : 12700 /36000;
        }
        if(!this.Unifill || !this.Unifill.fill || this.Unifill.fill.type === Asc.c_oAscFill.FILL_TYPE_NOFILL)
        {
            this.Value = border_None;
        }
    },

    Set_FromObject : function(Border)
    {
        this.Space = Border.Space;
        this.Size  = Border.Size;
        this.Value = Border.Value;

        if ( undefined != Border.Color )
            this.Color = new CDocumentColor( Border.Color.r, Border.Color.g, Border.Color.b );
        else
            this.Color = undefined;

        if(undefined != Border.Unifill)
        {
            this.Unifill = Border.Unifill.createDuplicate();
        }
        if(undefined != Border.LineRef)
        {
            this.LineRef = Border.LineRef.createDuplicate();
        }
    },

    Check_Null : function()
    {
        if ( undefined === this.Space || undefined === this.Size || undefined === this.Value || undefined === this.Color || undefined === this.Unifill || undefined === this.LineRef)
            return false;

        return true;
    },

    Write_ToBinary : function(Writer)
    {
        // Double   : Size
        // Long     : Space
        // Byte     : Value
        // Variable : Color

        Writer.WriteDouble( this.Size );
        Writer.WriteLong( this.Space );
        Writer.WriteByte( this.Value );
        this.Color.Write_ToBinary( Writer );
        if(this.Unifill)
        {
            Writer.WriteBool(true);
            this.Unifill.Write_ToBinary(Writer);
        }
        else
        {
            Writer.WriteBool(false);
        }
        if(this.LineRef)
        {
            Writer.WriteBool(true);
            this.LineRef.Write_ToBinary(Writer);
        }
        else
        {
            Writer.WriteBool(false);
        }

    },

    Read_FromBinary : function(Reader)
    {
        // Double   : Size
        // Long     : Space
        // Byte     : Value
        // Variable : Color

        this.Size  = Reader.GetDouble();
        this.Space = Reader.GetLong();
        this.Value = Reader.GetByte();
        this.Color.Read_FromBinary( Reader );
        if(Reader.GetBool())
        {
            this.Unifill = new AscFormat.CUniFill();
            this.Unifill.Read_FromBinary(Reader);
        }
        if(Reader.GetBool())
        {
            this.LineRef = new AscFormat.StyleRef();
            this.LineRef.Read_FromBinary(Reader);
        }
    }
};
CDocumentBorder.prototype.IsNone = function()
{
	return this.Value === border_None ? true : false;
};
/**
 * Получаем рассчитанную толщину линии в зависимости от типа.
 * @returns {number}
 */
CDocumentBorder.prototype.GetWidth = function()
{
	if (border_None === this.Value)
		return 0;

	return this.Size;
};

function CTableMeasurement(Type, W)
{
    this.Type = Type;
    this.W    = W;
}

CTableMeasurement.prototype =
{
    Copy : function()
    {
        return new CTableMeasurement(this.Type, this.W);
    },

    Is_Equal : function(Other)
    {
        if (this.Type !== Other.Type
            || this.W !== Other.W)
            return false;

        return true;
    },

    Write_ToBinary : function(Writer)
    {
        // Double : W
        // Long   : Type
        Writer.WriteDouble( this.W );
        Writer.WriteLong( this.Type );
    },

    Read_FromBinary : function(Reader)
    {
        // Double : W
        // Long   : Type

        this.W    = Reader.GetDouble();
        this.Type = Reader.GetLong();
    },

    Set_FromObject : function(Obj)
    {
        this.W    = Obj.W;
        this.Type = Obj.Type;
    }
};
/**
 * Измерение в миллиметрах?
 * @returns {boolean}
 */
CTableMeasurement.prototype.IsMM = function()
{
	return !!(tblwidth_Mm === this.Type);
};
/**
 * Измерение в процентах?
 * @returns {boolean}
 */
CTableMeasurement.prototype.IsPercent = function()
{
	return !!(tblwidth_Pct === this.Type);
};
/**
 * Получаем значение ширины в процентах или в миллиметрах
 * @returns {number}
 */
CTableMeasurement.prototype.GetValue = function()
{
	return this.W;
};

function CTablePr()
{
    this.TableStyleColBandSize = undefined;
    this.TableStyleRowBandSize = undefined;
    this.Jc                    = undefined;
    this.Shd                   = undefined;
    this.TableBorders          =
    {
        Bottom  : undefined,
        Left    : undefined,
        Right   : undefined,
        Top     : undefined,
        InsideH : undefined,
        InsideV : undefined
    };
    this.TableCellMar          =
    {
        Bottom : undefined,
        Left   : undefined,
        Right  : undefined,
        Top    : undefined
    };
    this.TableCellSpacing      = undefined;
    this.TableInd              = undefined;
    this.TableW                = undefined;
    this.TableLayout           = undefined;
    this.TableDescription      = undefined;
    this.TableCaption          = undefined;
}

CTablePr.prototype =
{
    Copy : function()
    {
        var TablePr = new CTablePr();

        TablePr.TableStyleColBandSize = this.TableStyleColBandSize;
        TablePr.TableStyleRowBandSize = this.TableStyleRowBandSize;
        TablePr.Jc                    = this.Jc;

        if ( undefined != this.Shd )
            TablePr.Shd = this.Shd.Copy();

        // TableBorders
        if ( undefined != this.TableBorders.Bottom )
            TablePr.TableBorders.Bottom = this.TableBorders.Bottom.Copy();

        if ( undefined != this.TableBorders.Left )
            TablePr.TableBorders.Left = this.TableBorders.Left.Copy();

        if ( undefined != this.TableBorders.Right )
            TablePr.TableBorders.Right = this.TableBorders.Right.Copy();

        if ( undefined != this.TableBorders.Top )
            TablePr.TableBorders.Top = this.TableBorders.Top.Copy();

        if ( undefined != this.TableBorders.InsideH )
            TablePr.TableBorders.InsideH = this.TableBorders.InsideH.Copy();

        if ( undefined != this.TableBorders.InsideV )
            TablePr.TableBorders.InsideV = this.TableBorders.InsideV.Copy();

        // TableCellMar
        if ( undefined != this.TableCellMar.Bottom )
            TablePr.TableCellMar.Bottom = this.TableCellMar.Bottom.Copy();

        if ( undefined != this.TableCellMar.Left )
            TablePr.TableCellMar.Left = this.TableCellMar.Left.Copy();

        if ( undefined != this.TableCellMar.Right )
            TablePr.TableCellMar.Right = this.TableCellMar.Right.Copy();

        if ( undefined != this.TableCellMar.Top )
            TablePr.TableCellMar.Top = this.TableCellMar.Top.Copy();

        TablePr.TableCellSpacing = this.TableCellSpacing;
        TablePr.TableInd         = this.TableInd;

        if ( undefined != this.TableW )
            TablePr.TableW = this.TableW.Copy();

        TablePr.TableLayout = this.TableLayout;

        TablePr.TableDescription = this.TableDescription;
        TablePr.TableCaption     = this.TableCaption;

        return TablePr;
    },

    Merge : function(TablePr)
    {
        if ( undefined != TablePr.TableStyleColBandSize )
            this.TableStyleColBandSize = TablePr.TableStyleColBandSize;

        if ( undefined != TablePr.TableStyleRowBandSize )
            this.TableStyleRowBandSize = TablePr.TableStyleRowBandSize;

        if ( undefined != TablePr.Jc )
            this.Jc = TablePr.Jc;

        if ( undefined != TablePr.Shd )
            this.Shd = TablePr.Shd.Copy();

        // TableBorders
        if ( undefined != TablePr.TableBorders.Bottom )
            this.TableBorders.Bottom = TablePr.TableBorders.Bottom.Copy();

        if ( undefined != TablePr.TableBorders.Left )
            this.TableBorders.Left = TablePr.TableBorders.Left.Copy();

        if ( undefined != TablePr.TableBorders.Right )
            this.TableBorders.Right = TablePr.TableBorders.Right.Copy();

        if ( undefined != TablePr.TableBorders.Top )
            this.TableBorders.Top = TablePr.TableBorders.Top.Copy();

        if ( undefined != TablePr.TableBorders.InsideH )
            this.TableBorders.InsideH = TablePr.TableBorders.InsideH.Copy();

        if ( undefined != TablePr.TableBorders.InsideV )
            this.TableBorders.InsideV = TablePr.TableBorders.InsideV.Copy();

        // TableCellMar
        if ( undefined != TablePr.TableCellMar.Bottom )
            this.TableCellMar.Bottom = TablePr.TableCellMar.Bottom.Copy();

        if ( undefined != TablePr.TableCellMar.Left )
            this.TableCellMar.Left = TablePr.TableCellMar.Left.Copy();

        if ( undefined != TablePr.TableCellMar.Right )
            this.TableCellMar.Right = TablePr.TableCellMar.Right.Copy();

        if ( undefined != TablePr.TableCellMar.Top )
            this.TableCellMar.Top = TablePr.TableCellMar.Top.Copy();

        if ( undefined != TablePr.TableCellSpacing )
            this.TableCellSpacing = TablePr.TableCellSpacing;

        if ( undefined != TablePr.TableInd )
            this.TableInd         = TablePr.TableInd;

        if ( undefined != TablePr.TableW )
            this.TableW = TablePr.TableW.Copy();

        if ( undefined != TablePr.TableLayout )
            this.TableLayout = TablePr.TableLayout;

        if (undefined !== TablePr.TableDescription)
        	this.TableDescription = TablePr.TableDescription;

        if (undefined !== TablePr.TableCaption)
        	this.TableCaption = TablePr.TableCaption;
    },

    Is_Equal : function(TablePr)
    {
        if (this.TableStyleColBandSize !== TablePr.TableStyleColBandSize
            || this.TableStyleRowBandSize !== TablePr.TableStyleRowBandSize
            || this.Jc !== TablePr.Jc
            || true !== IsEqualStyleObjects(this.TableBorders.Bottom, TablePr.TableBorders.Bottom)
            || true !== IsEqualStyleObjects(this.TableBorders.Left   , TablePr.TableBorders.Left   )
            || true !== IsEqualStyleObjects(this.TableBorders.Right  , TablePr.TableBorders.Right  )
            || true !== IsEqualStyleObjects(this.TableBorders.Top    , TablePr.TableBorders.Top    )
            || true !== IsEqualStyleObjects(this.TableBorders.InsideH, TablePr.TableBorders.InsideH)
            || true !== IsEqualStyleObjects(this.TableBorders.InsideV, TablePr.TableBorders.InsideV)
            || true !== IsEqualStyleObjects(this.TableCellMar.Bottom, TablePr.TableCellMar.Bottom)
            || true !== IsEqualStyleObjects(this.TableCellMar.Left  , TablePr.TableCellMar.Left  )
            || true !== IsEqualStyleObjects(this.TableCellMar.Right , TablePr.TableCellMar.Right )
            || true !== IsEqualStyleObjects(this.TableCellMar.Top   , TablePr.TableCellMar.Top   )
            || this.TableCellSpacing !== TablePr.TableCellSpacing
            || this.TableInd !== TablePr.TableInd
            || true !== IsEqualStyleObjects(this.TableW, TablePr.TableW)
            || this.TableLayout !== TablePr.TableLayout)
            return false;

        return true;
    },

    Init_Default : function()
    {
        this.TableStyleColBandSize = 1;
        this.TableStyleRowBandSize = 1;
        this.Jc                    = align_Left;
        this.Shd                   = new CDocumentShd();
        this.TableBorders.Bottom   = new CDocumentBorder();
        this.TableBorders.Left     = new CDocumentBorder();
        this.TableBorders.Right    = new CDocumentBorder();
        this.TableBorders.Top      = new CDocumentBorder();
        this.TableBorders.InsideH  = new CDocumentBorder();
        this.TableBorders.InsideV  = new CDocumentBorder();
        this.TableCellMar.Bottom   = new CTableMeasurement(tblwidth_Mm, 0);
        this.TableCellMar.Left     = new CTableMeasurement(tblwidth_Mm, 1.9/*5.4 * g_dKoef_pt_to_mm*/); // 5.4pt
        this.TableCellMar.Right    = new CTableMeasurement(tblwidth_Mm, 1.9/*5.4 * g_dKoef_pt_to_mm*/); // 5.4pt
        this.TableCellMar.Top      = new CTableMeasurement(tblwidth_Mm, 0);
        this.TableCellSpacing      = null;
        this.TableInd              = 0;
        this.TableW                = new CTableMeasurement(tblwidth_Auto, 0);
        this.TableLayout           = tbllayout_AutoFit;
        this.TableDescription      = "";
        this.TableCaption          = "";
    },

    Set_FromObject : function(TablePr)
    {
        this.TableStyleColBandSize = TablePr.TableStyleColBandSize;
        this.TableStyleRowBandSize = TablePr.TableStyleRowBandSize;
        this.Jc = TablePr.Jc;

        if ( undefined != TablePr.Shd )
        {
            this.Shd = new CDocumentShd();
            this.Shd.Set_FromObject(TablePr.Shd);
        }
        else
            this.Shd = undefined;

        if ( undefined != TablePr.TableBorders )
        {
            if ( undefined != TablePr.TableBorders.Bottom )
            {
                this.TableBorders.Bottom = new CDocumentBorder();
                this.TableBorders.Bottom.Set_FromObject( TablePr.TableBorders.Bottom );
            }
            else
                this.TableBorders.Bottom = undefined;

            if ( undefined != TablePr.TableBorders.Left )
            {
                this.TableBorders.Left = new CDocumentBorder();
                this.TableBorders.Left.Set_FromObject( TablePr.TableBorders.Left );
            }
            else
                this.TableBorders.Left = undefined;

            if ( undefined != TablePr.TableBorders.Right )
            {
                this.TableBorders.Right = new CDocumentBorder();
                this.TableBorders.Right.Set_FromObject( TablePr.TableBorders.Right );
            }
            else
                this.TableBorders.Right = undefined;

            if ( undefined != TablePr.TableBorders.Top )
            {
                this.TableBorders.Top = new CDocumentBorder();
                this.TableBorders.Top.Set_FromObject( TablePr.TableBorders.Top );
            }
            else
                this.TableBorders.Top = undefined;

            if ( undefined != TablePr.TableBorders.InsideH )
            {
                this.TableBorders.InsideH = new CDocumentBorder();
                this.TableBorders.InsideH.Set_FromObject( TablePr.TableBorders.InsideH );
            }
            else
                this.TableBorders.InsideH = undefined;

            if ( undefined != TablePr.TableBorders.InsideV )
            {
                this.TableBorders.InsideV = new CDocumentBorder();
                this.TableBorders.InsideV.Set_FromObject( TablePr.TableBorders.InsideV );
            }
            else
                this.TableBorders.InsideV = undefined;
        }
        else
        {
            this.TableBorders.Bottom  = undefined;
            this.TableBorders.Left    = undefined;
            this.TableBorders.Right   = undefined;
            this.TableBorders.Top     = undefined;
            this.TableBorders.InsideH = undefined;
            this.TableBorders.InsideV = undefined;
        }

        if ( undefined != TablePr.TableCellMar )
        {
            if ( undefined != TablePr.TableCellMar.Bottom )
                this.TableCellMar.Bottom = new CTableMeasurement( TablePr.TableCellMar.Bottom.Type, TablePr.TableCellMar.Bottom.W );
            else
                this.TableCellMar.Bottom = undefined;

            if ( undefined != TablePr.TableCellMar.Left )
                this.TableCellMar.Left = new CTableMeasurement( TablePr.TableCellMar.Left.Type, TablePr.TableCellMar.Left.W );
            else
                this.TableCellMar.Left = undefined;

            if ( undefined != TablePr.TableCellMar.Right )
                this.TableCellMar.Right = new CTableMeasurement( TablePr.TableCellMar.Right.Type, TablePr.TableCellMar.Right.W );
            else
                this.TableCellMar.Right = undefined;

            if ( undefined != TablePr.TableCellMar.Top )
                this.TableCellMar.Top = new CTableMeasurement( TablePr.TableCellMar.Top.Type, TablePr.TableCellMar.Top.W );
            else
                this.TableCellMar.Top = undefined;
        }
        else
        {
            this.TableCellMar.Bottom = undefined;
            this.TableCellMar.Left   = undefined;
            this.TableCellMar.Right  = undefined;
            this.TableCellMar.Top    = undefined;
        }

        this.TableCellSpacing = TablePr.TableCellSpacing;
        this.TableInd         = TablePr.TableInd;

        if ( undefined != TablePr.TableW )
            this.TableW = new CTableMeasurement( TablePr.TableW.Type, TablePr.TableW.W );
        else
            this.TableW = undefined;

        this.TableLayout = TablePr.TableLayout;

        this.TableDescription = TablePr.TableDescription;
        this.TableCaption     = TablePr.TableCaption;
    },

    Check_PresentationPr : function(Theme)
    {
        if(this.Shd)
        {
            this.Shd.Check_PresentationPr(Theme);
        }
        if(this.TableBorders.Bottom)
        {
            this.TableBorders.Bottom.Check_PresentationPr(Theme);
        }
        if(this.TableBorders.Left)
        {
            this.TableBorders.Left.Check_PresentationPr(Theme);
        }
        if(this.TableBorders.Right)
        {
            this.TableBorders.Right.Check_PresentationPr(Theme);
        }
        if(this.TableBorders.Top)
        {
            this.TableBorders.Top.Check_PresentationPr(Theme);
        }
        if(this.TableBorders.InsideH)
        {
            this.TableBorders.InsideH.Check_PresentationPr(Theme);
        }
        if(this.TableBorders.InsideV)
        {
            this.TableBorders.InsideV.Check_PresentationPr(Theme);
        }
    },

    Write_ToBinary : function(Writer)
    {
        var StartPos = Writer.GetCurPosition();
        Writer.Skip(4);
        var Flags = 0;

        if ( undefined != this.TableStyleColBandSize )
        {
            Writer.WriteLong( this.TableStyleColBandSize );
            Flags |= 1;
        }

        if ( undefined != this.TableStyleRowBandSize )
        {
            Writer.WriteLong( this.TableStyleRowBandSize );
            Flags |= 2;
        }

        if ( undefined != this.Jc )
        {
            Writer.WriteLong( this.Jc );
            Flags |= 4;
        }

        if ( undefined != this.Shd )
        {
            this.Shd.Write_ToBinary( Writer );
            Flags |= 8;
        }

        if ( undefined != this.TableBorders.Bottom )
        {
            this.TableBorders.Bottom.Write_ToBinary( Writer );
            Flags |= 16;
        }

        if ( undefined != this.TableBorders.Left )
        {
            this.TableBorders.Left.Write_ToBinary( Writer );
            Flags |= 32;
        }

        if ( undefined != this.TableBorders.Right )
        {
            this.TableBorders.Right.Write_ToBinary( Writer );
            Flags |= 64;
        }

        if ( undefined != this.TableBorders.Top )
        {
            this.TableBorders.Top.Write_ToBinary( Writer );
            Flags |= 128;
        }

        if ( undefined != this.TableBorders.InsideH )
        {
            this.TableBorders.InsideH.Write_ToBinary( Writer );
            Flags |= 256;
        }

        if ( undefined != this.TableBorders.InsideV )
        {
            this.TableBorders.InsideV.Write_ToBinary( Writer );
            Flags |= 512;
        }

        if ( undefined != this.TableCellMar.Bottom )
        {
            this.TableCellMar.Bottom.Write_ToBinary( Writer );
            Flags |= 1024;
        }

        if ( undefined != this.TableCellMar.Left )
        {
            this.TableCellMar.Left.Write_ToBinary( Writer );
            Flags |= 2048;
        }

        if ( undefined != this.TableCellMar.Right )
        {
            this.TableCellMar.Right.Write_ToBinary( Writer );
            Flags |= 4096;
        }

        if ( undefined != this.TableCellMar.Top )
        {
            this.TableCellMar.Top.Write_ToBinary( Writer );
            Flags |= 8192;
        }

        if ( undefined != this.TableCellSpacing )
        {
            if ( null === this.TableCellSpacing )
                Writer.WriteBool(true);
            else
            {
                Writer.WriteBool(false);
                Writer.WriteDouble(this.TableCellSpacing);
            }

            Flags |= 16384;
        }

        if ( undefined != this.TableInd )
        {
            Writer.WriteDouble(this.TableInd);

            Flags |= 32768;
        }

        if ( undefined != this.TableW )
        {
            this.TableW.Write_ToBinary( Writer );
            Flags |= 65536;
        }

        if ( undefined != this.TableLayout )
        {
            Writer.WriteLong( this.TableLayout );
            Flags |= 131072;
        }

        if (undefined !== this.TableDescription)
		{
			Writer.WriteString2(this.TableDescription);
			Flags |= 262144;
		}

		if (undefined !== this.TableCaption)
		{
			Writer.WriteString2(this.TableCaption);
			Flags |= 524288;
		}

        var EndPos = Writer.GetCurPosition();
        Writer.Seek( StartPos );
        Writer.WriteLong( Flags );
        Writer.Seek( EndPos );
    },

    Read_FromBinary : function(Reader)
    {
        var Flags = Reader.GetLong();

        if ( 1 & Flags )
            this.TableStyleColBandSize = Reader.GetLong();

        if ( 2 & Flags )
            this.TableStyleRowBandSize = Reader.GetLong();

        if ( 4 & Flags )
            this.Jc = Reader.GetLong();

        if ( 8 & Flags )
        {
            this.Shd = new CDocumentShd();
            this.Shd.Read_FromBinary(Reader);
        }

        if ( 16 & Flags )
        {
            this.TableBorders.Bottom = new CDocumentBorder();
            this.TableBorders.Bottom.Read_FromBinary( Reader );
        }

        if ( 32 & Flags )
        {
            this.TableBorders.Left = new CDocumentBorder();
            this.TableBorders.Left.Read_FromBinary( Reader );
        }

        if ( 64 & Flags )
        {
            this.TableBorders.Right = new CDocumentBorder();
            this.TableBorders.Right.Read_FromBinary( Reader );
        }

        if ( 128 & Flags )
        {
            this.TableBorders.Top = new CDocumentBorder();
            this.TableBorders.Top.Read_FromBinary( Reader );
        }

        if ( 256 & Flags )
        {
            this.TableBorders.InsideH = new CDocumentBorder();
            this.TableBorders.InsideH.Read_FromBinary( Reader );
        }

        if ( 512 & Flags )
        {
            this.TableBorders.InsideV = new CDocumentBorder();
            this.TableBorders.InsideV.Read_FromBinary( Reader );
        }

        if ( 1024 & Flags )
        {
            this.TableCellMar.Bottom = new CTableMeasurement(tblwidth_Auto, 0);
            this.TableCellMar.Bottom.Read_FromBinary(Reader);
        }

        if ( 2048 & Flags )
        {
            this.TableCellMar.Left = new CTableMeasurement(tblwidth_Auto, 0);
            this.TableCellMar.Left.Read_FromBinary(Reader);
        }

        if ( 4096 & Flags )
        {
            this.TableCellMar.Right = new CTableMeasurement(tblwidth_Auto, 0);
            this.TableCellMar.Right.Read_FromBinary(Reader);
        }

        if ( 8192 & Flags )
        {
            this.TableCellMar.Top = new CTableMeasurement(tblwidth_Auto, 0);
            this.TableCellMar.Top.Read_FromBinary(Reader);
        }

        if ( 16384 & Flags )
        {
            if ( true === Reader.GetBool() )
                this.TableCellSpacing = null;
            else
                this.TableCellSpacing = Reader.GetDouble()
        }

        if ( 32768 & Flags )
            this.TableInd = Reader.GetDouble();

        if ( 65536 & Flags )
        {
            this.TableW = new CTableMeasurement(tblwidth_Auto, 0);
            this.TableW.Read_FromBinary(Reader);
        }

        if ( 131072 & Flags )
            this.TableLayout = Reader.GetLong();

		if (262144 & Flags)
			this.TableDescription = Reader.GetString2();

		if (524288 & Flags)
			this.TableCaption = Reader.GetString2();
    }
};

function CTableRowHeight(Value, HRule)
{
    this.Value = Value;
    this.HRule = HRule;
}

CTableRowHeight.prototype =
{
    Copy : function()
    {
        return new CTableRowHeight(this.Value, this.HRule);
    },

    Is_Equal : function(Other)
    {
        if (this.Value !== Other.Value
            || this.HRule !== Other.HRule)
            return false;

        return true;
    },

    Write_ToBinary : function(Writer)
    {
        // Double : Value
        // Long   : HRule
        Writer.WriteDouble( this.Value );
        Writer.WriteLong( this.HRule );
    },

    Read_FromBinary : function(Reader)
    {
        // Double : Value
        // Long   : HRule

        this.Value = Reader.GetDouble();
        this.HRule = Reader.GetLong();
    }
};
CTableRowHeight.prototype.IsAuto = function()
{
	return (this.HRule === Asc.linerule_Auto ? true : false);
};
CTableRowHeight.prototype.GetValue = function()
{
	return this.Value;
};
CTableRowHeight.prototype.GetRule = function()
{
	return this.HRule;
};

function CTableRowPr()
{
    this.CantSplit        = undefined;
    this.GridAfter        = undefined;
    this.GridBefore       = undefined;
    this.Jc               = undefined;
    this.TableCellSpacing = undefined;
    this.Height           = undefined;
    this.WAfter           = undefined;
    this.WBefore          = undefined;
    this.TableHeader      = undefined;
}

CTableRowPr.prototype =
{
    Copy : function()
    {
        var RowPr = new CTableRowPr();

        RowPr.CantSplit        = this.CantSplit;
        RowPr.GridAfter        = this.GridAfter;
        RowPr.GridBefore       = this.GridBefore;
        RowPr.Jc               = this.Jc;
        RowPr.TableCellSpacing = this.TableCellSpacing;

        if ( undefined != this.Height )
            RowPr.Height = this.Height.Copy();

        if ( undefined != this.WAfter )
            RowPr.WAfter = this.WAfter.Copy();

        if ( undefined != this.WBefore )
            RowPr.WBefore = this.WBefore.Copy();

        RowPr.TableHeader = this.TableHeader;

        return RowPr;
    },

    Merge : function(RowPr)
	{
		if (undefined !== RowPr.CantSplit)
			this.CantSplit = RowPr.CantSplit;

		if (undefined !== RowPr.GridAfter)
			this.GridAfter = RowPr.GridAfter;

		if (undefined !== RowPr.GridBefore)
			this.GridBefore = RowPr.GridBefore;

		if (undefined !== RowPr.Jc)
			this.Jc = RowPr.Jc;

		if (undefined !== RowPr.TableCellSpacing)
			this.TableCellSpacing = RowPr.TableCellSpacing;

		if (undefined !== RowPr.Height)
			this.Height = RowPr.Height.Copy();

		if (undefined !== RowPr.WAfter)
			this.WAfter = RowPr.WAfter.Copy();

		if (undefined !== RowPr.WBefore)
			this.WBefore = RowPr.WBefore.Copy();

		if (undefined !== RowPr.TableHeader)
			this.TableHeader = RowPr.TableHeader;
	},

    Is_Equal : function(RowPr)
    {
        if (this.CantSplit !== RowPr.CantSplit
            || this.GridAfter !== RowPr.GridAfter
            || this.GridBefore !== RowPr.GridBefore
            || this.Jc !== RowPr.Jc
            || this.TableCellSpacing !== RowPr.TableCellSpacing
            || true !== IsEqualStyleObjects(this.Height, RowPr.Height)
            || true !== IsEqualStyleObjects(this.WAfter, RowPr.WAfter)
            || true !== IsEqualStyleObjects(this.WBefore, RowPr.WBefore)
            || this.TableHeader !== RowPr.TableHeader)
            return false;

        return true;
    },

    Init_Default : function()
    {
        this.CantSplit        = false;
        this.GridAfter        = 0;
        this.GridBefore       = 0;
        this.Jc               = align_Left;
        this.TableCellSpacing = null;
        this.Height           = new CTableRowHeight(0, Asc.linerule_Auto);
        this.WAfter           = new CTableMeasurement(tblwidth_Auto, 0);
        this.WBefore          = new CTableMeasurement(tblwidth_Auto, 0);
        this.TableHeader      = false;
    },

    Set_FromObject : function(RowPr)
    {
        this.CantSplit        = RowPr.CantSplit;
        this.GridAfter        = RowPr.GridAfter;
        this.GridBefore       = RowPr.GridBefore;
        this.Jc               = RowPr.Jc;
        this.TableCellSpacing = RowPr.TableCellSpacing;

        if ( undefined != RowPr.Height )
            this.Height = new CTableRowHeight( RowPr.Height.Value, RowPr.Height.HRule );
        else
            this.Height = undefined;

        if ( undefined != RowPr.WAfter )
            this.WAfter = new CTableMeasurement( RowPr.WAfter.Type, RowPr.WAfter.W );
        else
            this.WAfter = undefined;

        if ( undefined != RowPr.WBefore )
            this.WBefore = new CTableMeasurement( RowPr.WBefore.Type, RowPr.WBefore.W );
        else
            this.WBefore = undefined;

        this.TableHeader = RowPr.TableHeader;
    },

    Write_ToBinary : function(Writer)
    {
        var StartPos = Writer.GetCurPosition();
        Writer.Skip(4);
        var Flags = 0;

        if ( undefined != this.CantSplit )
        {
            Writer.WriteBool( this.CantSplit );
            Flags |= 1;
        }

        if ( undefined != this.GridAfter )
        {
            Writer.WriteLong( this.GridAfter );
            Flags |= 2;
        }

        if ( undefined != this.GridBefore )
        {
            Writer.WriteLong( this.GridBefore );
            Flags |= 4;
        }

        if ( undefined != this.Jc )
        {
            Writer.WriteLong( this.Jc );
            Flags |= 8;
        }

        if ( undefined != this.TableCellSpacing )
        {
            if ( null === this.TableCellSpacing )
                Writer.WriteBool( true );
            else
            {
                Writer.WriteBool( false );
                Writer.WriteDouble( this.TableCellSpacing );
            }

            Flags |= 16;
        }

        if ( undefined != this.Height )
        {
            this.Height.Write_ToBinary( Writer );
            Flags |= 32;
        }

        if ( undefined != this.WAfter )
        {
            this.WAfter.Write_ToBinary(Writer);
            Flags |= 64;
        }

        if ( undefined != this.WBefore )
        {
            this.WBefore.Write_ToBinary(Writer);
            Flags |= 128;
        }

        if ( undefined != this.TableHeader )
        {
            Writer.WriteBool( this.TableHeader );
            Flags |= 256;
        }

        var EndPos = Writer.GetCurPosition();
        Writer.Seek( StartPos );
        Writer.WriteLong( Flags );
        Writer.Seek( EndPos );
    },

    Read_FromBinary : function(Reader)
    {
        var Flags = Reader.GetLong();

        if ( 1 & Flags )
            this.CantSplit = Reader.GetBool();

        if ( 2 & Flags )
            this.GridAfter = Reader.GetLong();

        if ( 4 & Flags )
            this.GridBefore = Reader.GetLong();

        if ( 8 & Flags )
            this.Jc = Reader.GetLong();

        if ( 16 & Flags )
        {
            if ( true === Reader.GetBool() )
                this.TableCellSpacing = Reader.GetLong();
            else
                this.TableCellSpacing = Reader.GetDouble();
        }

        if ( 32 & Flags )
        {
            this.Height = new CTableRowHeight(0, Asc.linerule_Auto);
            this.Height.Read_FromBinary(Reader);
        }

        if ( 64 & Flags )
        {
            this.WAfter = new CTableMeasurement(tblwidth_Auto, 0);
            this.WAfter.Read_FromBinary(Reader);
        }

        if ( 128 & Flags )
        {
            this.WBefore = new CTableMeasurement(tblwidth_Auto, 0);
            this.WBefore.Read_FromBinary(Reader);
        }

        if ( 256 & Flags )
            this.TableHeader = Reader.GetBool();
    }
};

function CTableCellPr()
{
    this.GridSpan         = undefined;
    this.Shd              = undefined;
    this.TableCellMar     = undefined; // undefined/null/{Top, Left, Right, Bottom}
    this.TableCellBorders =
    {
        Bottom : undefined,
        Left   : undefined,
        Right  : undefined,
        Top    : undefined
    };
    this.TableCellW       = undefined;
    this.VAlign           = undefined;
    this.VMerge           = undefined;
    this.TextDirection    = undefined;
    this.NoWrap           = undefined;
    this.HMerge           = undefined;
}

CTableCellPr.prototype =
{
    Copy : function()
    {
        var CellPr = new CTableCellPr();

        CellPr.GridSpan = this.GridSpan;

        if (undefined != this.Shd)
            CellPr.Shd = this.Shd.Copy();

        if (undefined === this.TableCellMar)
            CellPr.TableCellMar = undefined;
        else if (null === this.TableCellMar)
            CellPr.TableCellMar = null;
        else
        {
            CellPr.TableCellMar        = {};
            CellPr.TableCellMar.Bottom = undefined != this.TableCellMar.Bottom ? this.TableCellMar.Bottom.Copy() : undefined;
            CellPr.TableCellMar.Left   = undefined != this.TableCellMar.Left ? this.TableCellMar.Left.Copy() : undefined;
            CellPr.TableCellMar.Right  = undefined != this.TableCellMar.Right ? this.TableCellMar.Right.Copy() : undefined;
            CellPr.TableCellMar.Top    = undefined != this.TableCellMar.Top ? this.TableCellMar.Top.Copy() : undefined;
        }

        if (undefined != this.TableCellBorders.Bottom)
            CellPr.TableCellBorders.Bottom = this.TableCellBorders.Bottom.Copy();

        if (undefined != this.TableCellBorders.Left)
            CellPr.TableCellBorders.Left = this.TableCellBorders.Left.Copy();

        if (undefined != this.TableCellBorders.Right)
            CellPr.TableCellBorders.Right = this.TableCellBorders.Right.Copy();

        if (undefined != this.TableCellBorders.Top)
            CellPr.TableCellBorders.Top = this.TableCellBorders.Top.Copy();

        if (undefined != this.TableCellW)
            CellPr.TableCellW = this.TableCellW.Copy();

        CellPr.VAlign        = this.VAlign;
        CellPr.VMerge        = this.VMerge;
        CellPr.TextDirection = this.TextDirection;
        CellPr.NoWrap        = this.NoWrap;
        CellPr.HMerge        = this.HMerge;

        return CellPr;
    },

    Merge : function(CellPr)
    {
        if (undefined != CellPr.GridSpan)
            this.GridSpan = CellPr.GridSpan;

        if (undefined != CellPr.Shd)
            this.Shd = CellPr.Shd.Copy();

        if (undefined === CellPr.TableCellMar)
        {
        }
        else if (null === CellPr.TableCellMar)
            this.TableCellMar = null;
        else
        {
            this.TableCellMar        = {};
            this.TableCellMar.Bottom = undefined != CellPr.TableCellMar.Bottom ? CellPr.TableCellMar.Bottom.Copy() : undefined;
            this.TableCellMar.Left   = undefined != CellPr.TableCellMar.Left ? CellPr.TableCellMar.Left.Copy() : undefined;
            this.TableCellMar.Right  = undefined != CellPr.TableCellMar.Right ? CellPr.TableCellMar.Right.Copy() : undefined;
            this.TableCellMar.Top    = undefined != CellPr.TableCellMar.Top ? CellPr.TableCellMar.Top.Copy() : undefined;
        }

        if (undefined != CellPr.TableCellBorders.Bottom)
            this.TableCellBorders.Bottom = CellPr.TableCellBorders.Bottom.Copy();

        if (undefined != CellPr.TableCellBorders.Left)
            this.TableCellBorders.Left = CellPr.TableCellBorders.Left.Copy();

        if (undefined != CellPr.TableCellBorders.Right)
            this.TableCellBorders.Right = CellPr.TableCellBorders.Right.Copy();

        if (undefined != CellPr.TableCellBorders.Top)
            this.TableCellBorders.Top = CellPr.TableCellBorders.Top.Copy();

        if (undefined != CellPr.TableCellW)
            this.TableCellW = CellPr.TableCellW.Copy();

        if (undefined != CellPr.VAlign)
            this.VAlign = CellPr.VAlign;

        if (undefined != CellPr.VMerge)
            this.VMerge = CellPr.VMerge;

        if (undefined != CellPr.TextDirection)
            this.TextDirection = CellPr.TextDirection;

        if (undefined !== CellPr.NoWrap)
            this.NoWrap = CellPr.NoWrap;

        if (undefined != CellPr.HMerge)
        	this.HMerge = CellPr.HMerge;
    },

    Is_Equal : function(CellPr)
    {
        if (this.GridSpan !== CellPr.GridSpan
            || true !== IsEqualStyleObjects(this.Shd, CellPr.Shd)
            || (this.TableCellMar !== undefined
                && CellPr.TableCellMar === undefined)
            || (CellPr.TableCellMar !== undefined
                && this.TableCellMar === undefined)
            || (this.TableCellMar !== null
                && CellPr.TableCellMar === null)
            || (CellPr.TableCellMar !== null
                && this.TableCellMar === null)
            || (this.TableCellMar !== undefined
                && this.TableCellMar !== null
                && (true !== IsEqualStyleObjects(this.TableCellMar.Top, CellPr.TableCellMar.Top)
                    || true !== IsEqualStyleObjects(this.TableCellMar.Left, CellPr.TableCellMar.Left)
                    || true !== IsEqualStyleObjects(this.TableCellMar.Right, CellPr.TableCellMar.Right)
                    || true !== IsEqualStyleObjects(this.TableCellMar.Bottom, CellPr.TableCellMar.Bottom)))
            || true !== IsEqualStyleObjects(this.TableCellBorders.Bottom, CellPr.TableCellBorders.Bottom)
            || true !== IsEqualStyleObjects(this.TableCellBorders.Left, CellPr.TableCellBorders.Left)
            || true !== IsEqualStyleObjects(this.TableCellBorders.Right, CellPr.TableCellBorders.Right)
            || true !== IsEqualStyleObjects(this.TableCellBorders.Top, CellPr.TableCellBorders.Top)
            || true !== IsEqualStyleObjects(this.TableCellW, CellPr.TableCellW)
            || this.VAlign !== CellPr.VAlign
            || this.VMerge !== CellPr.VMerge
            || this.TextDirection !== CellPr.TextDirection
            || this.NoWrap !== CellPr.NoWrap
			|| this.HMerge !== CellPr.HMerge)
            return false;

        return true;
    },

    Init_Default : function()
    {
        this.GridSpan                = 1;
        this.Shd                     = new CDocumentShd();
        this.TableCellMar            = null;
        this.TableCellBorders.Bottom = undefined;
        this.TableCellBorders.Left   = undefined;
        this.TableCellBorders.Right  = undefined;
        this.TableCellBorders.Top    = undefined;
        this.TableCellW              = new CTableMeasurement(tblwidth_Auto, 0);
        this.VAlign                  = vertalignjc_Top;
        this.VMerge                  = vmerge_Restart;
        this.TextDirection           = textdirection_LRTB;
        this.NoWrap                  = false;
        this.HMerge                  = vmerge_Restart;
    },

    Set_FromObject : function(CellPr)
    {
        this.GridSpan = CellPr.GridSpan;

        if ( undefined != CellPr.Shd )
        {
            this.Shd = new CDocumentShd();
            this.Shd.Set_FromObject( CellPr.Shd );
        }
        else
            this.Shd = undefined;

        if ( undefined === CellPr.TableCellMar )
            this.TableCellMar = undefined;
        else if ( null === CellPr.TableCellMar )
            this.TableCellMar = null;
        else
        {
            this.TableCellMar = {};

            if ( undefined != CellPr.TableCellMar.Bottom )
                this.TableCellMar.Bottom = new CTableMeasurement( CellPr.TableCellMar.Bottom.Type, CellPr.TableCellMar.Bottom.W );
            else
                this.TableCellMar.Bottom = undefined;

            if ( undefined != CellPr.TableCellMar.Left )
                this.TableCellMar.Left = new CTableMeasurement( CellPr.TableCellMar.Left.Type, CellPr.TableCellMar.Left.W );
            else
                this.TableCellMar.Left = undefined;

            if ( undefined != CellPr.TableCellMar.Right )
                this.TableCellMar.Right = new CTableMeasurement( CellPr.TableCellMar.Right.Type, CellPr.TableCellMar.Right.W );
            else
                this.TableCellMar.Right = undefined;

            if ( undefined != CellPr.TableCellMar.Top )
                this.TableCellMar.Top = new CTableMeasurement( CellPr.TableCellMar.Top.Type, CellPr.TableCellMar.Top.W );
            else
                this.TableCellMar.Top = undefined;
        }

        if ( undefined != CellPr.TableCellBorders )
        {
            if ( undefined != CellPr.TableCellBorders.Bottom )
            {
                this.TableCellBorders.Bottom = new CDocumentBorder();
                this.TableCellBorders.Bottom.Set_FromObject( CellPr.TableCellBorders.Bottom );
            }
            else
                this.TableCellBorders.Bottom = undefined;

            if ( undefined != CellPr.TableCellBorders.Left )
            {
                this.TableCellBorders.Left = new CDocumentBorder();
                this.TableCellBorders.Left.Set_FromObject( CellPr.TableCellBorders.Left );
            }
            else
                this.TableCellBorders.Left = undefined;

            if ( undefined != CellPr.TableCellBorders.Right )
            {
                this.TableCellBorders.Right = new CDocumentBorder();
                this.TableCellBorders.Right.Set_FromObject( CellPr.TableCellBorders.Right );
            }
            else
                this.TableCellBorders.Right = undefined;

            if ( undefined != CellPr.TableCellBorders.Top )
            {
                this.TableCellBorders.Top = new CDocumentBorder();
                this.TableCellBorders.Top.Set_FromObject( CellPr.TableCellBorders.Top );
            }
            else
                this.TableCellBorders.Top = undefined;
        }
        else
        {
            this.TableCellBorders.Bottom = undefined;
            this.TableCellBorders.Left   = undefined;
            this.TableCellBorders.Right  = undefined;
            this.TableCellBorders.Top    = undefined;
        }

        if ( undefined != CellPr.TableCellW )
            this.TableCellW = new CTableMeasurement( CellPr.TableCellW.Type, CellPr.TableCellW.W );
        else
            this.TableCellW = undefined;


        this.VAlign = CellPr.VAlign;
        this.VMerge = CellPr.VMerge;
        this.TextDirection = CellPr.TextDirection;
        this.NoWrap = CellPr.NoWrap;
        this.HMerge = CellPr.HMerge;

    },

    Check_PresentationPr : function(Theme)
    {
        if(this.Shd)
        {
            this.Shd.Check_PresentationPr(Theme);
        }
        if(this.TableCellBorders.Bottom)
        {
            this.TableCellBorders.Bottom.Check_PresentationPr(Theme);
        }
        if(this.TableCellBorders.Left)
        {
            this.TableCellBorders.Left.Check_PresentationPr(Theme);
        }
        if(this.TableCellBorders.Right)
        {
            this.TableCellBorders.Right.Check_PresentationPr(Theme);
        }
        if(this.TableCellBorders.Top)
        {
            this.TableCellBorders.Top.Check_PresentationPr(Theme);
        }
    },

    Write_ToBinary : function(Writer)
    {
        var StartPos = Writer.GetCurPosition();
        Writer.Skip(4);
        var Flags = 0;

        if ( undefined != this.GridSpan )
        {
            Writer.WriteLong( this.GridSpan );
            Flags |= 1;
        }

        if ( undefined != this.Shd )
        {
            this.Shd.Write_ToBinary( Writer );
            Flags |= 2;
        }

        if ( undefined != this.TableCellMar )
        {
            if ( null === this.TableCellMar )
            {
                Flags |= 4;
            }
            else
            {
                if ( undefined != this.TableCellMar.Bottom )
                {
                    this.TableCellMar.Bottom.Write_ToBinary(Writer);
                    Flags |= 8;
                }

                if ( undefined != this.TableCellMar.Left )
                {
                    this.TableCellMar.Left.Write_ToBinary(Writer);
                    Flags |= 16;
                }

                if ( undefined != this.TableCellMar.Right )
                {
                    this.TableCellMar.Right.Write_ToBinary(Writer);
                    Flags |= 32;
                }

                if ( undefined != this.TableCellMar.Top )
                {
                    this.TableCellMar.Top.Write_ToBinary(Writer);
                    Flags |= 64;
                }

                Flags |= 128;
            }
        }

        if ( undefined != this.TableCellBorders.Bottom )
        {
            this.TableCellBorders.Bottom.Write_ToBinary( Writer );
            Flags |= 256;
        }

        if ( undefined != this.TableCellBorders.Left )
        {
            this.TableCellBorders.Left.Write_ToBinary( Writer );
            Flags |= 512;
        }

        if ( undefined != this.TableCellBorders.Right )
        {
            this.TableCellBorders.Right.Write_ToBinary( Writer );
            Flags |= 1024;
        }

        if ( undefined != this.TableCellBorders.Top )
        {
            this.TableCellBorders.Top.Write_ToBinary( Writer );
            Flags |= 2048;
        }

        if ( undefined != this.TableCellW )
        {
            this.TableCellW.Write_ToBinary(Writer);
            Flags |= 4096;
        }

        if ( undefined != this.VAlign )
        {
            Writer.WriteLong( this.VAlign );
            Flags |= 8192;
        }

        if ( undefined != this.VMerge )
        {
            Writer.WriteLong( this.VMerge );
            Flags |= 16384;
        }

        if (undefined !== this.TextDirection)
        {
            Writer.WriteLong( this.TextDirection );
            Flags |= 32768;
        }

        if (undefined !== this.NoWrap)
        {
            Writer.WriteBool(this.NoWrap);
            Flags |= 65536;
        }

        if (undefined !== this.HMerge)
		{
			Writer.WriteLong(this.HMerge);
			Flags |= 131072;
		}

        var EndPos = Writer.GetCurPosition();
        Writer.Seek( StartPos );
        Writer.WriteLong( Flags );
        Writer.Seek( EndPos );
    },

    Read_FromBinary : function(Reader)
    {
        var Flags = Reader.GetLong();

        if ( 1 & Flags )
            this.GridSpan = Reader.GetLong();

        if ( 2 & Flags )
        {
            this.Shd = new CDocumentShd();
            this.Shd.Read_FromBinary( Reader );
        }

        if ( 4 & Flags )
            this.TableCellMar = null;
        else if ( 128 & Flags )
        {
            this.TableCellMar = {};
            if ( 8 & Flags )
            {
                this.TableCellMar.Bottom = new CTableMeasurement(tblwidth_Auto, 0);
                this.TableCellMar.Bottom.Read_FromBinary( Reader );
            }

            if ( 16 & Flags )
            {
                this.TableCellMar.Left = new CTableMeasurement(tblwidth_Auto, 0);
                this.TableCellMar.Left.Read_FromBinary( Reader );
            }

            if ( 32 & Flags )
            {
                this.TableCellMar.Right = new CTableMeasurement(tblwidth_Auto, 0);
                this.TableCellMar.Right.Read_FromBinary( Reader );
            }

            if ( 64 & Flags )
            {
                this.TableCellMar.Top = new CTableMeasurement(tblwidth_Auto, 0);
                this.TableCellMar.Top.Read_FromBinary( Reader );
            }
        }

        if ( 256 & Flags )
        {
            this.TableCellBorders.Bottom = new CDocumentBorder();
            this.TableCellBorders.Bottom.Read_FromBinary( Reader );
        }

        if ( 512 & Flags )
        {
            this.TableCellBorders.Left = new CDocumentBorder();
            this.TableCellBorders.Left.Read_FromBinary( Reader );
        }

        if ( 1024 & Flags )
        {
            this.TableCellBorders.Right = new CDocumentBorder();
            this.TableCellBorders.Right.Read_FromBinary( Reader );
        }

        if ( 2048 & Flags )
        {
            this.TableCellBorders.Top = new CDocumentBorder();
            this.TableCellBorders.Top.Read_FromBinary( Reader );
        }

        if ( 4096 & Flags )
        {
            this.TableCellW = new CTableMeasurement(tblwidth_Auto, 0);
            this.TableCellW.Read_FromBinary( Reader );
        }

        if ( 8192 & Flags )
            this.VAlign = Reader.GetLong();

        if ( 16384 & Flags )
            this.VMerge = Reader.GetLong();

        if (32768 & Flags)
            this.TextDirection = Reader.GetLong();

        if (65536 & Flags)
            this.NoWrap = Reader.GetBool();

		if (131072 & Flags)
			this.HMerge = Reader.GetLong();
    }
};
CTableCellPr.prototype.Is_Empty = function()
{
	if (undefined !== this.GridSpan
		|| undefined !== this.Shd
		|| undefined !== this.TableCellMar
		|| undefined !== this.TableCellBorders.Bottom
		|| undefined !== this.TableCellBorders.Left
		|| undefined !== this.TableCellBorders.Right
		|| undefined !== this.TableCellBorders.Top
		|| undefined !== this.TableCellW
		|| undefined !== this.VAlign
		|| undefined !== this.VMerge
		|| undefined !== this.TextDirection
		|| undefined !== this.NoWrap
		|| undefined !== this.HMerge)
		return false;

	return true;
};

function CRFonts()
{
    this.Ascii    = undefined;
    this.EastAsia = undefined;
    this.HAnsi    = undefined;
    this.CS       = undefined;
    this.Hint     = undefined;
}

CRFonts.prototype =
{
    Set_All : function(FontName, FontIndex)
    {
        this.Ascii =
        {
            Name  : FontName,
            Index : FontIndex
        };

        this.EastAsia =
        {
            Name  : FontName,
            Index : FontIndex
        };

        this.HAnsi =
        {
            Name  : FontName,
            Index : FontIndex
        };

        this.CS =
        {
            Name  : FontName,
            Index : FontIndex
        };

        this.Hint = fonthint_Default;
    },

    Copy : function()
    {
        var RFonts = new CRFonts();
        if ( undefined !== this.Ascii )
        {
            RFonts.Ascii = {Name: this.Ascii.Name, Index: this.Ascii.Index};
        }
        if ( undefined !== this.EastAsia )
        {
            RFonts.EastAsia = {Name: this.EastAsia.Name, Index: this.EastAsia.Index};
        }
        if ( undefined !== this.HAnsi )
        {
            RFonts.HAnsi = {Name: this.HAnsi.Name, Index: this.HAnsi.Index};
        }
        if ( undefined !== this.CS )
        {
            RFonts.CS = {Name: this.CS.Name, Index: this.CS.Index};
        }
        if ( undefined != this.Hint )
            this.Hint = RFonts.Hint;
        return RFonts;
    },

    Merge : function(RFonts)
    {
        if ( undefined !== RFonts.Ascii )
            this.Ascii = RFonts.Ascii;

        if ( undefined != RFonts.EastAsia )
            this.EastAsia = RFonts.EastAsia;

        if ( undefined != RFonts.HAnsi )
            this.HAnsi = RFonts.HAnsi;

        if ( undefined != RFonts.CS )
            this.CS = RFonts.CS;

        if ( undefined != RFonts.Hint )
            this.Hint = RFonts.Hint;
    },

    Init_Default : function()
    {
        this.Ascii =
        {
            Name  : "Arial",
            Index : -1
        };

        this.EastAsia =
        {
            Name  : "Arial",
            Index : -1
        };

        this.HAnsi =
        {
            Name  : "Arial",
            Index : -1
        };

        this.CS =
        {
            Name  : "Arial",
            Index : -1
        };

        this.Hint = fonthint_Default;
    },

    Set_FromObject : function(RFonts, isUndefinedToNull)
	{
		if (undefined != RFonts.Ascii)
		{
			this.Ascii = {
				Name  : RFonts.Ascii.Name,
				Index : RFonts.Ascii.Index
			};
		}
		else
		{
			this.Ascii = isUndefinedToNull ? null : undefined;
		}

		if (undefined != RFonts.EastAsia)
		{
			this.EastAsia = {
				Name  : RFonts.EastAsia.Name,
				Index : RFonts.EastAsia.Index
			};
		}
		else
		{
			this.EastAsia = isUndefinedToNull ? null : undefined;
		}

		if (undefined != RFonts.HAnsi)
		{
			this.HAnsi = {
				Name  : RFonts.HAnsi.Name,
				Index : RFonts.HAnsi.Index
			};
		}
		else
		{
			this.HAnsi = isUndefinedToNull ? null : undefined;
		}

		if (undefined != RFonts.CS)
		{
			this.CS = {
				Name  : RFonts.CS.Name,
				Index : RFonts.CS.Index
			};
		}
		else
		{
			this.CS = isUndefinedToNull ? null : undefined;
		}

		this.Hint = CheckUndefinedToNull(isUndefinedToNull, RFonts.Hint);
	},

    Compare : function(RFonts)
    {
        // Ascii
        if ( undefined !== this.Ascii && ( undefined === RFonts.Ascii || this.Ascii.Name !== RFonts.Ascii.Name ) )
            this.Ascii = undefined;

        // EastAsia
        if ( undefined !== this.EastAsia && ( undefined === RFonts.EastAsia || this.EastAsia.Name !== RFonts.EastAsia.Name ) )
            this.EastAsia = undefined;

        // HAnsi
        if ( undefined !== this.HAnsi && ( undefined === RFonts.HAnsi || this.HAnsi.Name !== RFonts.HAnsi.Name ) )
            this.HAnsi = undefined;

        // CS
        if ( undefined !== this.CS && ( undefined === RFonts.CS || this.CS.Name !== RFonts.CS.Name ) )
            this.CS = undefined;

        // Hint
        if ( undefined !== this.Hint && ( undefined === RFonts.Hint || this.Hint !== RFonts.Hint ) )
            this.Hint = undefined;
    },

    Write_ToBinary : function(Writer)
    {
        var StartPos = Writer.GetCurPosition();
        Writer.Skip(4);
        var Flags = 0;

        if ( undefined != this.Ascii )
        {
            Writer.WriteString2( this.Ascii.Name );
            Flags |= 1;
        }

        if ( undefined != this.EastAsia )
        {
            Writer.WriteString2( this.EastAsia.Name );
            Flags |= 2;
        }

        if ( undefined != this.HAnsi )
        {
            Writer.WriteString2( this.HAnsi.Name );
            Flags |= 4;
        }

        if ( undefined != this.CS )
        {
            Writer.WriteString2( this.CS.Name );
            Flags |= 8;
        }

        if ( undefined != this.Hint )
        {
            Writer.WriteLong( this.Hint );
            Flags |= 16;
        }

        var EndPos = Writer.GetCurPosition();
        Writer.Seek( StartPos );
        Writer.WriteLong( Flags );
        Writer.Seek( EndPos );
    },

    Read_FromBinary : function(Reader)
    {
        var Flags = Reader.GetLong();

        // Ascii
        if ( Flags & 1 )
            this.Ascii = { Name : Reader.GetString2(), Index : -1 };

        // EastAsia
        if ( Flags & 2 )
            this.EastAsia = { Name : Reader.GetString2(), Index : -1 };

        // HAnsi
        if ( Flags & 4 )
            this.HAnsi = { Name : Reader.GetString2(), Index : -1 };

        // CS
        if ( Flags & 8 )
            this.CS = { Name : Reader.GetString2(), Index : -1 };

        // Hint
        if ( Flags & 16 )
            this.Hint = Reader.GetLong();
    },

    Is_Equal : function(RFonts)
    {
        if ((undefined === this.Ascii && undefined !== RFonts.Ascii) || (undefined !== this.Ascii && (undefined === RFonts.Ascii || this.Ascii.Name !== RFonts.Ascii.Name)))
            return false;

        if ((undefined === this.EastAsia && undefined !== RFonts.EastAsia) || (undefined !== this.EastAsia && (undefined === RFonts.EastAsia || this.EastAsia.Name !== RFonts.EastAsia.Name)))
            return false;

        if ((undefined === this.HAnsi && undefined !== RFonts.HAnsi) || (undefined !== this.HAnsi && (undefined === RFonts.HAnsi || this.HAnsi.Name !== RFonts.HAnsi.Name)))
            return false;

        if ((undefined == this.CS && undefined !== RFonts.CS) || (undefined !== this.CS && (undefined === RFonts.CS || this.CS.Name !== RFonts.CS.Name)))
            return false;

        if ((undefined === this.Hint && undefined !== RFonts.Hint) || (undefined !== this.Hint && (undefined === RFonts.Hint || this.Hint !== RFonts.Hint)))
            return false;

        return true;
    }
};
CRFonts.prototype.Is_Empty = function()
{
	if (undefined !== this.Ascii
		|| undefined !== this.EastAsia
		|| undefined !== this.HAnsi
		|| undefined !== this.CS
		|| undefined !== this.Hint)
		return false;

	return true;
};
CRFonts.prototype.SetAll = function(sFontName, nFontIndex)
{
	if (undefined === nFontIndex)
		nFontIndex = -1;

	this.Set_All(sFontName, nFontIndex);
};

function CLang()
{
    this.Bidi     = undefined;
    this.EastAsia = undefined;
    this.Val      = undefined;
}

CLang.prototype =
{
    Copy : function()
    {
        var Lang = new CLang();
        Lang.Bidi     = this.Bidi;
        Lang.EastAsia = this.EastAsia;
        Lang.Val      = this.Val;
        return Lang;
    },

    Merge : function(Lang)
    {
        if ( undefined !== Lang.Bidi )
            this.Bidi = Lang.Bidi;

        if ( undefined !== Lang.EastAsia )
            this.EastAsia = Lang.EastAsia;

        if ( undefined !== Lang.Val )
            this.Val = Lang.Val;
    },

    Init_Default : function()
    {
        this.Bidi     = lcid_enUS;
        this.EastAsia = lcid_enUS;
        this.Val      = lcid_enUS;
    },

    Set_FromObject : function(Lang, isUndefinedToNull)
	{
		this.Bidi     = CheckUndefinedToNull(isUndefinedToNull, Lang.Bidi);
		this.EastAsia = CheckUndefinedToNull(isUndefinedToNull, Lang.EastAsia);
		this.Val      = CheckUndefinedToNull(isUndefinedToNull, Lang.Val);
	},

    Compare : function(Lang)
    {
        // Bidi
        if ( undefined !== this.Bidi && this.Bidi !== Lang.Bidi )
            this.Bidi = undefined;

        // EastAsia
        if ( undefined !== this.EastAsia && this.EastAsia !== Lang.EastAsia )
            this.EastAsia = undefined;

        // Val
        if ( undefined !== this.Val && this.Val !== Lang.Val )
            this.Val = undefined;
    },

    Write_ToBinary : function(Writer)
    {
        var StartPos = Writer.GetCurPosition();
        Writer.Skip(4);
        var Flags = 0;

        if ( undefined != this.Bidi )
        {
            Writer.WriteLong( this.Bidi );
            Flags |= 1;
        }

        if ( undefined != this.EastAsia )
        {
            Writer.WriteLong( this.EastAsia );
            Flags |= 2;
        }

        if ( undefined != this.Val )
        {
            Writer.WriteLong( this.Val );
            Flags |= 4;
        }

        var EndPos = Writer.GetCurPosition();
        Writer.Seek( StartPos );
        Writer.WriteLong( Flags );
        Writer.Seek( EndPos );
    },

    Read_FromBinary : function(Reader)
    {
        var Flags = Reader.GetLong();

        // Bidi
        if ( Flags & 1 )
            this.Bidi = Reader.GetLong();

        // EastAsia
        if ( Flags & 2 )
            this.EastAsia = Reader.GetLong();

        // Val
        if ( Flags & 4 )
            this.Val = Reader.GetLong();
    },

    Is_Equal : function(Lang)
    {
        if (this.Bidi !== Lang.Bidi
            || this.EastAsia !== Lang.EastAsia
            || this.Val !== Lang.Val)
            return false;

        return true;
    }
};
CLang.prototype.Is_Empty = function()
{
	if (undefined !== this.Bidi
		|| undefined !== this.EastAsia
		|| undefined !== this.Val)
		return false;

	return true;
};

function CTextPr()
{
    this.Bold       = undefined; // Жирный текст
    this.Italic     = undefined; // Наклонный текст
    this.Strikeout  = undefined; // Зачеркивание
    this.Underline  = undefined;
    this.FontFamily = undefined;
    this.FontSize   = undefined;
    this.Color      = undefined;
    this.VertAlign  = undefined;
    this.HighLight  = undefined; // highlight_None/Color
    this.RStyle     = undefined;
    this.Spacing    = undefined; // Дополнительное расстояние между символвами
    this.DStrikeout = undefined; // Двойное зачеркивание
    this.Caps       = undefined;
    this.SmallCaps  = undefined;
    this.Position   = undefined; // Смещение по Y

    this.RFonts     = new CRFonts();
    this.BoldCS     = undefined;
    this.ItalicCS   = undefined;
    this.FontSizeCS = undefined;
    this.CS         = undefined;
    this.RTL        = undefined;
    this.Lang       = new CLang();
    this.Unifill    = undefined;
    this.FontRef    = undefined;

    this.Shd        = undefined;
    this.Vanish     = undefined;

    this.TextOutline = undefined;
    this.TextFill    = undefined;
}

CTextPr.prototype =
{
    Clear : function()
    {
        this.Bold       = undefined;
        this.Italic     = undefined;
        this.Strikeout  = undefined;
        this.Underline  = undefined;
        this.FontFamily = undefined;
        this.FontSize   = undefined;
        this.Color      = undefined;
        this.VertAlign  = undefined;
        this.HighLight  = undefined;
        this.RStyle     = undefined;
        this.Spacing    = undefined;
        this.DStrikeout = undefined;
        this.Caps       = undefined;
        this.SmallCaps  = undefined;
        this.Position   = undefined;

        this.RFonts     = new CRFonts();
        this.BoldCS     = undefined;
        this.ItalicCS   = undefined;
        this.FontSizeCS = undefined;
        this.CS         = undefined;
        this.RTL        = undefined;
        this.Lang       = new CLang();
        this.Unifill    = undefined;
        this.FontRef    = undefined;
        this.Shd        = undefined;
        this.Vanish     = undefined;
        this.TextOutline = undefined;
        this.TextFill    = undefined;
        this.AscFill    = undefined;
        this.AscUnifill = undefined;
        this.AscLine    = undefined;
    },

    Copy : function(bCopyPrChange)
    {
        var TextPr = new CTextPr();
        TextPr.Bold      = this.Bold;
        TextPr.Italic    = this.Italic;
        TextPr.Strikeout = this.Strikeout;
        TextPr.Underline = this.Underline;

        if ( undefined != this.FontFamily )
        {
            TextPr.FontFamily = {};
            TextPr.FontFamily.Name  = this.FontFamily.Name;
            TextPr.FontFamily.Index = this.FontFamily.Index;
        }

        TextPr.FontSize   = this.FontSize;

        if ( undefined != this.Color )
            TextPr.Color = new CDocumentColor(this.Color.r, this.Color.g, this.Color.b, this.Color.Auto);

        TextPr.VertAlign = this.VertAlign;
        TextPr.HighLight = this.Copy_HighLight();

        TextPr.RStyle     = this.RStyle;
        TextPr.Spacing    = this.Spacing;
        TextPr.DStrikeout = this.DStrikeout;
        TextPr.Caps       = this.Caps;
        TextPr.SmallCaps  = this.SmallCaps;
        TextPr.Position   = this.Position;
        TextPr.RFonts     = this.RFonts.Copy();
        TextPr.BoldCS     = this.BoldCS;
        TextPr.ItalicCS   = this.ItalicCS;
        TextPr.FontSizeCS = this.FontSizeCS;
        TextPr.CS         = this.CS;
        TextPr.RTL        = this.RTL;
        TextPr.Lang       = this.Lang.Copy();
        if(undefined != this.Unifill)
            TextPr.Unifill = this.Unifill.createDuplicate();
        if(undefined != this.FontRef)
            TextPr.FontRef = this.FontRef.createDuplicate();
        
        if (undefined !== this.Shd )
            TextPr.Shd = this.Shd.Copy();
        
        TextPr.Vanish     = this.Vanish;

        if (true === bCopyPrChange && undefined !== this.PrChange)
        {
            TextPr.PrChange   = this.PrChange.Copy();
            TextPr.ReviewInfo = this.ReviewInfo.Copy();
        }
        if(undefined != this.TextOutline)
        {
            TextPr.TextOutline = this.TextOutline.createDuplicate();
        }
        if(undefined != this.TextFill)
        {
            TextPr.TextFill = this.TextFill.createDuplicate();
        }

        return TextPr;
    },

    Copy_HighLight : function()
    {
        if ( undefined === this.HighLight )
            return undefined;
        else if ( highlight_None === this.HighLight )
            return highlight_None;
        else
            return this.HighLight.Copy();

        return undefined;
    },

    Merge : function(TextPr)
    {
        if ( undefined != TextPr.Bold )
            this.Bold = TextPr.Bold;

        if ( undefined != TextPr.Italic )
            this.Italic = TextPr.Italic;

        if ( undefined != TextPr.Strikeout )
            this.Strikeout = TextPr.Strikeout;

        if ( undefined != TextPr.Underline )
            this.Underline = TextPr.Underline;

        if ( undefined != TextPr.FontFamily )
        {
            this.FontFamily = {};
            this.FontFamily.Name  = TextPr.FontFamily.Name;
            this.FontFamily.Index = TextPr.FontFamily.Index;
        }

        if ( undefined != TextPr.FontSize )
            this.FontSize = TextPr.FontSize;

        if ( undefined != TextPr.Color )
            this.Color = TextPr.Color.Copy();

        if ( undefined != TextPr.VertAlign )
            this.VertAlign = TextPr.VertAlign;

        if ( undefined === TextPr.HighLight )
        {}
        else if ( highlight_None === TextPr.HighLight )
            this.HighLight = highlight_None;
        else
            this.HighLight = TextPr.HighLight.Copy();

        if ( undefined != TextPr.RStyle )
            this.RStyle = TextPr.RStyle;

        if ( undefined != TextPr.Spacing )
            this.Spacing = TextPr.Spacing;

        if ( undefined != TextPr.DStrikeout )
            this.DStrikeout = TextPr.DStrikeout;

        if ( undefined != TextPr.SmallCaps )
            this.SmallCaps = TextPr.SmallCaps;

        if ( undefined != TextPr.Caps )
            this.Caps = TextPr.Caps;

        if ( undefined != TextPr.Position )
            this.Position = TextPr.Position;

        this.RFonts.Merge( TextPr.RFonts );

        if ( undefined != TextPr.BoldCS )
            this.BoldCS = TextPr.BoldCS;

        if ( undefined != TextPr.ItalicCS )
            this.ItalicCS = TextPr.ItalicCS;

        if ( undefined != TextPr.FontSizeCS )
            this.FontSizeCS = TextPr.FontSizeCS;

        if ( undefined != TextPr.CS )
            this.CS = TextPr.CS;

        if ( undefined != TextPr.RTL )
            this.RTL = TextPr.RTL;

        this.Lang.Merge( TextPr.Lang );

        if(undefined != TextPr.Unifill)
            this.Unifill = TextPr.Unifill.createDuplicate();
        else
        {
            if(undefined != TextPr.Color)
            {
                this.Unifill = undefined;
            }
        }
        if(undefined != TextPr.FontRef)
        {
            this.FontRef = TextPr.FontRef.createDuplicate();
        }
        
        if ( undefined !== TextPr.Shd )
            this.Shd = TextPr.Shd.Copy();
        
        if ( undefined !== TextPr.Vanish )
            this.Vanish = TextPr.Vanish;

        if(undefined != TextPr.TextOutline)
        {
            this.TextOutline = TextPr.TextOutline.createDuplicate();
        }
        if(undefined != TextPr.TextFill)
        {
            this.TextFill = TextPr.TextFill.createDuplicate();
        }
    },

    Init_Default : function()
    {
        this.Bold       = false;
        this.Italic     = false;
        this.Underline  = false;
        this.Strikeout  = false;
        this.FontFamily =
        {
            Name  : "Arial",
            Index : -1
        };
        this.FontSize   = 11;
        this.Color      = new CDocumentColor(0, 0, 0, true);
        this.VertAlign  = AscCommon.vertalign_Baseline;
        this.HighLight  = highlight_None;
        this.RStyle     = undefined;
        this.Spacing    = 0;
        this.DStrikeout = false;
        this.SmallCaps  = false;
        this.Caps       = false;
        this.Position   = 0;
        this.RFonts.Init_Default();
        this.BoldCS     = false;
        this.ItalicCS   = false;
        this.FontSizeCS = 11;
        this.CS         = false;
        this.RTL        = false;
        this.Lang.Init_Default();
        this.Unifill    = undefined;
        this.FontRef    = undefined;
        this.Shd        = undefined;     
        this.Vanish     = false;

        this.TextOutline = undefined;
        this.TextFill    = undefined;
    },

    Set_FromObject : function(TextPr, isUndefinedToNull)
	{
		this.Bold      = CheckUndefinedToNull(isUndefinedToNull, TextPr.Bold);
		this.Italic    = CheckUndefinedToNull(isUndefinedToNull, TextPr.Italic);
		this.Strikeout = CheckUndefinedToNull(isUndefinedToNull, TextPr.Strikeout);
		this.Underline = CheckUndefinedToNull(isUndefinedToNull, TextPr.Underline);

		if (undefined !== TextPr.FontFamily)
		{
			this.FontFamily       = {};
			this.FontFamily.Name  = TextPr.FontFamily.Name;
			this.FontFamily.Index = TextPr.FontFamily.Index;
		}
		else
		{
			if (isUndefinedToNull)
				this.FontFamily = null;
			else
				this.FontFamily = undefined;
		}

		this.FontSize = CheckUndefinedToNull(isUndefinedToNull, TextPr.FontSize);

		if (null === TextPr.Color || undefined === TextPr.Color)
			this.Color = CheckUndefinedToNull(isUndefinedToNull, TextPr.Color);
		else
			this.Color = new CDocumentColor(TextPr.Color.r, TextPr.Color.g, TextPr.Color.b, TextPr.Color.Auto);

		this.VertAlign = CheckUndefinedToNull(isUndefinedToNull, TextPr.VertAlign);

		if (undefined === TextPr.HighLight || null === TextPr.HighLight)
			this.HighLight = CheckUndefinedToNull(isUndefinedToNull, undefined);
		else if (highlight_None === TextPr.HighLight)
			this.HighLight = highlight_None;
		else
			this.HighLight = new CDocumentColor(TextPr.HighLight.r, TextPr.HighLight.g, TextPr.HighLight.b);

		this.RStyle     = CheckUndefinedToNull(isUndefinedToNull, TextPr.RStyle);
		this.Spacing    = CheckUndefinedToNull(isUndefinedToNull, TextPr.Spacing);
		this.DStrikeout = CheckUndefinedToNull(isUndefinedToNull, TextPr.DStrikeout);
		this.Caps       = CheckUndefinedToNull(isUndefinedToNull, TextPr.Caps);
		this.SmallCaps  = CheckUndefinedToNull(isUndefinedToNull, TextPr.SmallCaps);
		this.Position   = CheckUndefinedToNull(isUndefinedToNull, TextPr.Position);

		if (undefined !== TextPr.RFonts)
			this.RFonts.Set_FromObject(TextPr.RFonts, isUndefinedToNull);

		this.BoldCS     = CheckUndefinedToNull(isUndefinedToNull, TextPr.BoldCS);
		this.ItalicCS   = CheckUndefinedToNull(isUndefinedToNull, TextPr.ItalicCS);
		this.FontSizeCS = CheckUndefinedToNull(isUndefinedToNull, TextPr.FontSizeCS);
		this.CS         = CheckUndefinedToNull(isUndefinedToNull, TextPr.CS);
		this.RTL        = CheckUndefinedToNull(isUndefinedToNull, TextPr.RTL);

		if (undefined !== TextPr.Lang)
			this.Lang.Set_FromObject(TextPr.Lang, isUndefinedToNull);

		if (undefined !== TextPr.Shd)
		{
			this.Shd = new CDocumentShd();
			this.Shd.Set_FromObject(TextPr.Shd);
		}
		else
		{
			this.Shd = undefined;
		}

		this.Vanish      = CheckUndefinedToNull(isUndefinedToNull, TextPr.Vanish);
		this.Unifill     = CheckUndefinedToNull(isUndefinedToNull, TextPr.Unifill);
		this.FontRef     = CheckUndefinedToNull(isUndefinedToNull, TextPr.FontRef);
		this.TextFill    = CheckUndefinedToNull(isUndefinedToNull, TextPr.TextFill);
		this.TextOutline = CheckUndefinedToNull(isUndefinedToNull, TextPr.TextOutline);
		this.AscFill     = CheckUndefinedToNull(isUndefinedToNull, TextPr.AscFill);
		this.AscUnifill  = CheckUndefinedToNull(isUndefinedToNull, TextPr.AscUnifill);
		this.AscLine     = CheckUndefinedToNull(isUndefinedToNull, TextPr.AscLine);
	},

    Check_PresentationPr: function()
    {
        if(this.FontRef && !this.Unifill)
        {
            var prefix;
            if(this.FontRef.idx === AscFormat.fntStyleInd_minor)
            {
                prefix = "+mn-";
            }
            else
            {
                prefix = "+mj-";
            }
            this.RFonts.Set_FromObject(
                {
                    Ascii: {
                        Name: prefix+"lt",
                        Index: -1
                    },
                    EastAsia: {
                        Name: prefix+"ea",
                        Index: -1
                    },
                    HAnsi: {
                        Name: prefix+"lt",
                        Index: -1
                    },
                    CS: {
                        Name: prefix+"lt",
                        Index: -1
                    }
                }
            );
            if(this.FontRef.Color && !this.Unifill)
            {
                this.Unifill = AscFormat.CreateUniFillByUniColorCopy(this.FontRef.Color);
            }
        }
    },

    Compare : function(TextPr)
    {
        // Bold
        if ( undefined !== this.Bold && this.Bold !== TextPr.Bold )
            this.Bold = undefined;

        // Italic
        if ( undefined !== this.Italic && this.Italic !== TextPr.Italic )
            this.Italic = undefined;

        // Strikeout
        if ( undefined !== this.Strikeout && this.Strikeout !== TextPr.Strikeout )
            this.Strikeout = undefined;

        // Underline
        if ( undefined !== this.Underline && this.Underline !== TextPr.Underline )
            this.Underline = undefined;

        // FontFamily
        if ( undefined !== this.FontFamily && ( undefined === TextPr.FontFamily || this.FontFamily.Name !== TextPr.FontFamily.Name ) )
            this.FontFamily = undefined;

        // FontSize
        if ( undefined !== this.FontSize && ( undefined === TextPr.FontSize || Math.abs( this.FontSize - TextPr.FontSize ) >= 0.001 ) )
            this.FontSize = undefined;

        // Color
        if ( undefined !== this.Color && ( undefined === TextPr.Color || true !== this.Color.Compare(TextPr.Color) ) )
            this.Color = undefined;

        // VertAlign
        if ( undefined !== this.VertAlign && this.VertAlign !== TextPr.VertAlign )
            this.VertAlign = undefined;

        // HighLight
        if ( undefined !== this.HighLight && ( undefined === TextPr.HighLight || ( highlight_None === this.HighLight && highlight_None !== TextPr.HighLight )  || ( highlight_None !== this.HighLight && highlight_None === TextPr.HighLight ) || ( highlight_None !== this.HighLight && highlight_None !== TextPr.HighLight && true !== this.HighLight.Compare( TextPr.HighLight ) ) ) )
            this.HighLight = undefined;

        // RStyle
        if ( undefined !== this.RStyle && ( undefined === TextPr.RStyle || this.RStyle !== TextPr.RStyle ) )
            this.RStyle = undefined;

        // Spacing
        if ( undefined !== this.Spacing && ( undefined === TextPr.Spacing || Math.abs(this.Spacing - TextPr.Spacing) >= 0.001 ) )
            this.Spacing = undefined;

        // DStrikeout
        if ( undefined !== this.DStrikeout && ( undefined === TextPr.DStrikeout || this.DStrikeout !== TextPr.DStrikeout ) )
            this.DStrikeout = undefined;

        // Caps
        if ( undefined !== this.Caps && ( undefined === TextPr.Caps || this.Caps !== TextPr.Caps ) )
            this.Caps = undefined;

        // SmallCaps
        if ( undefined !== this.SmallCaps && ( undefined === TextPr.SmallCaps || this.SmallCaps !== TextPr.SmallCaps ) )
            this.SmallCaps = undefined;

        // Position
        if ( undefined !== this.Position && ( undefined === TextPr.Position || Math.abs(this.Position - TextPr.Position) >= 0.001 ) )
            this.Position = undefined;

        // RFonts
        this.RFonts.Compare( TextPr.RFonts );

        // BoldCS
        if ( undefined !== this.BoldCS && this.BoldCS !== TextPr.BoldCS )
            this.BoldCS = undefined;

        // ItalicCS
        if ( undefined !== this.ItalicCS && this.ItalicCS !== TextPr.ItalicCS )
            this.ItalicCS = undefined;

        // FontSizeCS
        if ( undefined !== this.FontSizeCS && ( undefined === TextPr.FontSizeCS || Math.abs( this.FontSizeCS - TextPr.FontSizeCS ) >= 0.001 ) )
            this.FontSizeCS = undefined;

        // CS
        if ( undefined !== this.CS && this.CS !== TextPr.CS )
            this.CS = undefined;

        // RTL
        if ( undefined !== this.RTL && this.RTL !== TextPr.RTL )
            this.RTL = undefined;

        // Lang
        this.Lang.Compare( TextPr.Lang );
        //Result_TextPr.Unifill = CompareUniFill(this.Unifill, TextPr.Unifill);       
        
        // Vanish
        if ( undefined !== this.Vanish && this.Vanish !== TextPr.Vanish )
            this.Vanish = undefined;

        if(undefined !== this.Unifill && !this.Unifill.IsIdentical(TextPr.Unifill))
        {
            this.Unifill = AscFormat.CompareUniFill(this.Unifill, TextPr.Unifill);
            if(null === this.Unifill){
                this.Unifill = undefined;
            }
            this.Color = undefined;
            this.TextFill = undefined;
        }


        if(undefined !== this.TextFill &&  !this.TextFill.IsIdentical(TextPr.TextFill))
        {
            this.Unifill = undefined;
            this.Color = undefined;
            this.TextFill = AscFormat.CompareUniFill(this.TextFill, TextPr.TextFill);
            if(null === this.TextFill){
                this.TextFill = undefined;
            }
        }


        if(undefined !== this.TextOutline &&  !this.TextOutline.IsIdentical(TextPr.TextOutline)){
            if(TextPr.TextOutline !== undefined){
                this.TextOutline = this.TextOutline.compare(TextPr.TextOutline);
            }
            else{
                this.TextOutline = undefined;
            }

        }




        return this;
    },

    Write_ToBinary : function(Writer)
    {
        var StartPos = Writer.GetCurPosition();
        Writer.Skip(4);
        var Flags = 0;

        if ( undefined != this.Bold )
        {
            Writer.WriteBool( this.Bold );
            Flags |= 1;
        }

        if ( undefined != this.Italic )
        {
            Writer.WriteBool( this.Italic );
            Flags |= 2;
        }

        if ( undefined != this.Underline )
        {
            Writer.WriteBool( this.Underline );
            Flags |= 4;
        }

        if ( undefined != this.Strikeout )
        {
            Writer.WriteBool( this.Strikeout );
            Flags |= 8;
        }

        if ( undefined != this.FontFamily )
        {
            Writer.WriteString2( this.FontFamily.Name );
            Flags |= 16;
        }

        if ( undefined != this.FontSize )
        {
            Writer.WriteDouble( this.FontSize );
            Flags |= 32;
        }

        if ( undefined != this.Color )
        {
            this.Color.Write_ToBinary(Writer);
            Flags |= 64;
        }

        if ( undefined != this.VertAlign )
        {
            Writer.WriteLong( this.VertAlign );
            Flags |= 128;
        }

        if ( undefined != this.HighLight )
        {
            if ( highlight_None === this.HighLight )
            {
                Writer.WriteLong( highlight_None );
            }
            else
            {
                Writer.WriteLong( 0 );
                this.HighLight.Write_ToBinary( Writer );
            }

            Flags |= 256;
        }

        if ( undefined != this.RStyle )
        {
            Writer.WriteString2( this.RStyle );
            Flags |= 512;
        }

        if ( undefined != this.Spacing )
        {
            Writer.WriteDouble( this.Spacing );
            Flags |= 1024;
        }

        if ( undefined != this.DStrikeout )
        {
            Writer.WriteBool( this.DStrikeout );
            Flags |= 2048;
        }

        if ( undefined != this.Caps )
        {
            Writer.WriteBool( this.Caps );
            Flags |= 4096;
        }

        if ( undefined != this.SmallCaps )
        {
            Writer.WriteBool( this.SmallCaps );
            Flags |= 8192;
        }

        if ( undefined != this.Position )
        {
            Writer.WriteDouble( this.Position );
            Flags |= 16384;
        }

        if ( undefined != this.RFonts )
        {
            this.RFonts.Write_ToBinary( Writer );
            Flags |= 32768;
        }

        if ( undefined != this.BoldCS )
        {
            Writer.WriteBool( this.BoldCS );
            Flags |= 65536;
        }

        if ( undefined != this.ItalicCS )
        {
            Writer.WriteBool( this.ItalicCS );
            Flags |= 131072;
        }

        if ( undefined != this.FontSizeCS )
        {
            Writer.WriteDouble( this.FontSizeCS );
            Flags |= 262144;
        }

        if ( undefined != this.CS )
        {
            Writer.WriteBool( this.CS );
            Flags |= 524288;
        }

        if ( undefined != this.RTL )
        {
            Writer.WriteBool( this.RTL );
            Flags |= 1048576;
        }

        if ( undefined != this.Lang )
        {
            this.Lang.Write_ToBinary( Writer );
            Flags |= 2097152;
        }

        if(undefined != this.Unifill)
        {
            this.Unifill.Write_ToBinary(Writer);
            Flags |= 4194304;
        }
        
        if ( undefined !== this.Shd )
        {
            this.Shd.Write_ToBinary(Writer);
            Flags |= 8388608;
        }
        
        if ( undefined !== this.Vanish )
        {
            Writer.WriteBool( this.Vanish );    
            Flags |= 16777216;
        }

        if( undefined !== this.FontRef )
        {
            this.FontRef.Write_ToBinary(Writer);
            Flags |= 33554432;
        }

        if (undefined !== this.PrChange)
        {
            this.PrChange.Write_ToBinary(Writer);
            Flags |= 67108864;
        }
        if(undefined !== this.TextOutline)
        {
            this.TextOutline.Write_ToBinary(Writer);
            Flags |= 134217728;
        }
        if(undefined !== this.TextFill)
        {
            this.TextFill.Write_ToBinary(Writer);
            Flags |= 268435456;
        }

        if (undefined !== this.PrChange)
        {
            this.PrChange.Write_ToBinary(Writer);
            this.ReviewInfo.Write_ToBinary(Writer);
            Flags |= 536870912;
        }

        var EndPos = Writer.GetCurPosition();
        Writer.Seek( StartPos );
        Writer.WriteLong( Flags );
        Writer.Seek( EndPos );
    },

    Read_FromBinary : function(Reader)
    {
        var Flags = Reader.GetLong();

        // Bold
        if ( Flags & 1 )
            this.Bold = Reader.GetBool();

        // Italic
        if ( Flags & 2 )
            this.Italic = Reader.GetBool();

        // Underline
        if ( Flags & 4 )
            this.Underline = Reader.GetBool();

        // Strikeout
        if ( Flags & 8 )
            this.Strikeout = Reader.GetBool();

        // FontFamily
        if ( Flags & 16 )
            this.FontFamily = { Name : Reader.GetString2(), Index : -1 };

        // FontSize
        if ( Flags & 32 )
            this.FontSize = Reader.GetDouble();

        // Color
        if ( Flags & 64 )
        {
            this.Color = new CDocumentColor(0, 0, 0);
            this.Color.Read_FromBinary(Reader);
        }

        // VertAlign
        if ( Flags & 128 )
            this.VertAlign = Reader.GetLong();

        // HighLight
        if ( Flags & 256 )
        {
            var HL_type = Reader.GetLong();
            if ( highlight_None == HL_type )
                this.HighLight = highlight_None;
            else
            {
                this.HighLight = new CDocumentColor(0, 0, 0);
                this.HighLight.Read_FromBinary(Reader);
            }
        }

        // RStyle
        if ( Flags & 512 )
            this.RStyle = Reader.GetString2();

        // Spacing
        if ( Flags & 1024 )
            this.Spacing = Reader.GetDouble();

        // DStrikeout
        if ( Flags & 2048 )
            this.DStrikeout = Reader.GetBool();

        // Caps
        if ( Flags & 4096 )
            this.Caps = Reader.GetBool();

        // SmallCaps
        if ( Flags & 8192 )
            this.SmallCaps = Reader.GetBool();

        // Position
        if ( Flags & 16384 )
            this.Position = Reader.GetDouble();

        // RFonts
        if ( Flags & 32768 )
            this.RFonts.Read_FromBinary( Reader );

        // BoldCS
        if ( Flags & 65536 )
            this.BoldCS = Reader.GetBool();

        // ItalicCS
        if ( Flags & 131072 )
            this.ItalicCS = Reader.GetBool();

        // FontSizeCS
        if ( Flags & 262144 )
            this.FontSizeCS = Reader.GetDouble();

        // CS
        if ( Flags & 524288 )
            this.CS = Reader.GetBool();

        // RTL
        if ( Flags & 1048576 )
            this.RTL = Reader.GetBool();

        // Lang
        if ( Flags & 2097152 )
            this.Lang.Read_FromBinary( Reader );

        // Unifill
        if ( Flags & 4194304 )
        {
            this.Unifill = new AscFormat.CUniFill()
            this.Unifill.Read_FromBinary( Reader );
        }
        
        // Shd
        if ( Flags & 8388608 )
        {
            this.Shd = new CDocumentShd();
            this.Shd.Read_FromBinary( Reader );
        }
        
        // Vanish
        if ( Flags & 16777216 )
            this.Vanish = Reader.GetBool();

        if ( Flags & 33554432 )
        {
            this.FontRef = new AscFormat.FontRef();
            this.FontRef.Read_FromBinary(Reader);
        }

        if (Flags & 67108864)
        {
            this.PrChange = new CTextPr();
            this.PrChange.Read_FromBinary(Reader);
        }

        if(Flags & 134217728)
        {
            this.TextOutline = new AscFormat.CLn();
            this.TextOutline.Read_FromBinary(Reader);
        }

        if(Flags & 268435456)
        {
            this.TextFill = new AscFormat.CUniFill();
            this.TextFill.Read_FromBinary(Reader);
        }

        if (Flags & 536870912)
        {
            this.PrChange   = new CTextPr();
            this.ReviewInfo = new CReviewInfo();
            this.PrChange.Read_FromBinary(Reader);
            this.ReviewInfo.Read_FromBinary(Reader);
        }
    },

    Check_NeedRecalc : function()
    {
        // Потому что в параграфе внутри Internal_recalculate_0 кэшируются ParaTextPr
        return true;

        if ( undefined != this.Bold )
            return true;

        if ( undefined != this.Italic )
            return true;

        if ( undefined != this.FontFamily )
            return true;

        if ( undefined != this.FontSize )
            return true;

        if ( undefined != this.VertAlign )
            return true;

        if ( undefined != this.Spacing )
            return true;

        if ( undefined != this.Caps )
            return true;

        if ( undefined != this.SmallCaps )
            return true;

        if ( undefined != this.Position )
            return true;

        if ( undefined != this.RFonts.Ascii )
            return true;

        if ( undefined != this.RFonts.EastAsia )
            return true;

        if ( undefined != this.RFonts.HAnsi )
            return true;

        if ( undefined != this.RFonts.CS )
            return true;

        if ( undefined != this.RTL || undefined != this.CS || undefined != this.BoldCS || undefined != this.ItalicCS || undefined != this.FontSizeCS )
            return true;

        if ( undefined != this.Lang.Val )
            return true;

        // Потому что в параграфе внутри Internal_recalculate_0 кэшируются ParaTextPr
        if ( undefined != this.Color )
            return true;

        if ( undefined != this.HighLight )
            return true;
        
        if ( undefined != this.Shd )
            return true;

        return false;
    },

    Get_FontKoef : function()
    {
        var dFontKoef  = 1;

        switch ( this.VertAlign )
        {
            case AscCommon.vertalign_Baseline:
            {
                dFontKoef = 1;
                break;
            }
            case AscCommon.vertalign_SubScript:
            case AscCommon.vertalign_SuperScript:
            {
                dFontKoef = vertalign_Koef_Size;
                break;
            }
        }

        return dFontKoef;
    },

    Document_Get_AllFontNames : function(AllFonts)
    {
        if ( undefined != this.RFonts.Ascii )
            AllFonts[this.RFonts.Ascii.Name] = true;

        if ( undefined != this.RFonts.HAnsi )
            AllFonts[this.RFonts.HAnsi.Name] = true;

        if ( undefined != this.RFonts.EastAsia )
            AllFonts[this.RFonts.EastAsia.Name] = true;

        if ( undefined != this.RFonts.CS )
            AllFonts[this.RFonts.CS.Name] = true;
    },

    Document_CreateFontMap : function(FontMap, FontScheme)
    {
        var Style   = ( true === this.Bold   ? 1 : 0 ) + ( true === this.Italic   ? 2 : 0 );
        var StyleCS = ( true === this.BoldCS ? 1 : 0 ) + ( true === this.ItalicCS ? 2 : 0 );
        var Size    = this.FontSize;
        var SizeCS  = this.FontSizeCS;

        var RFonts = this.RFonts;
        var CheckedName;
        if ( undefined != RFonts.Ascii )
        {
            CheckedName = FontScheme.checkFont(RFonts.Ascii.Name);
            var Key = "" + CheckedName + "_" + Style + "_" + Size;
            FontMap[Key] =
            {
                Name  : CheckedName,
                Style : Style,
                Size  : Size
            };
        }

        if ( undefined != RFonts.EastAsia )
        {
            CheckedName = FontScheme.checkFont(RFonts.EastAsia.Name);
            var Key = "" + CheckedName + "_" + Style + "_" + Size;
            FontMap[Key] =
            {
                Name  : CheckedName,
                Style : Style,
                Size  : Size
            };
        }

        if ( undefined != RFonts.HAnsi )
        {
            CheckedName = FontScheme.checkFont(RFonts.HAnsi.Name);
            var Key = "" + CheckedName + "_" + Style + "_" + Size;
            FontMap[Key] =
            {
                Name  : CheckedName,
                Style : Style,
                Size  : Size
            };
        }

        if ( undefined != RFonts.CS )
        {

            CheckedName = FontScheme.checkFont(RFonts.CS.Name);
            var Key = "" + CheckedName + "_" + StyleCS + "_" + SizeCS;
            FontMap[Key] =
            {
                Name  : CheckedName,
                Style : StyleCS,
                Size  : SizeCS
            };
        }
    },

    isEqual: function(TextPrOld, TextPrNew)
    {
        if(TextPrOld == undefined || TextPrNew == undefined)
            return false;
        for(var TextPr in TextPrOld)
        {
            if(typeof TextPrOld[TextPr] == 'object')
            {
                /*for(var cpPr in TextPrOld[TextPr])
                 {
                 if(TextPrOld[TextPr][cpPr] != TextPrNew[TextPr][cpPr])
                 return false;
                 }*/
                this.isEqual(TextPrOld[TextPr],TextPrNew[TextPr]);
            }
            else
            {
                if(typeof TextPrOld[TextPr] == "number" && typeof TextPrNew[TextPr] == "number")
                {
                    if(Math.abs(TextPrOld[TextPr] - TextPrNew[TextPr]) > 0.001)
                        return false;
                }
                else if(TextPrOld[TextPr] != TextPrNew[TextPr])
                    return false;
            }
        }
        return true;
    },

    Is_Equal : function(TextPr)
    {
        if (this.Bold !== TextPr.Bold)
            return false;

        if (this.Italic !== TextPr.Italic)
            return false;

        if (this.Strikeout !== TextPr.Strikeout)
            return false;

        if (this.Underline !== TextPr.Underline)
            return false;

		if ((undefined === this.FontFamily && undefined !== TextPr.FontFamily) || (undefined !== this.FontFamily && (undefined === TextPr.FontFamily || this.FontFamily.Name !== TextPr.FontFamily.Name)))
			return false;

        if (false
            || (undefined === this.FontSize
                && undefined !== TextPr.FontSize)
            || (undefined !== this.FontSize
                && (undefined === TextPr.FontSize
                    || Math.abs(this.FontSize - TextPr.FontSize) >= 0.001)))
            return false;

        if ((undefined === this.Color && undefined !== TextPr.Color) || (undefined !== this.Color && (undefined === TextPr.Color || true !== this.Color.Compare(TextPr.Color))))
            return false;

        if (this.VertAlign !== TextPr.VertAlign)
            return false;

        if ((undefined === this.HighLight && undefined !== TextPr.HighLight) || (undefined !== this.HighLight && (undefined === TextPr.HighLight || (highlight_None === this.HighLight && highlight_None !== TextPr.HighLight) || (highlight_None !== this.HighLight && highlight_None === TextPr.HighLight) || (highlight_None !== this.HighLight && highlight_None !== TextPr.HighLight && true !== this.HighLight.Compare(TextPr.HighLight)))))
            return false;

        if (this.RStyle !== TextPr.RStyle)
            return false;

        if ((undefined === this.Spacing && undefined !== TextPr.Spacing) || (undefined !== this.Spacing && (undefined === TextPr.Spacing || Math.abs(this.Spacing - TextPr.Spacing) >= 0.001)))
            return false;

        if (this.DStrikeout !== TextPr.DStrikeout)
            return false;

        if (this.Caps !== TextPr.Caps)
            return false;

        if (this.SmallCaps !== TextPr.SmallCaps)
            return false;

        if ((undefined === this.Position && undefined !== TextPr.Position) || (undefined !== this.Position && (undefined === TextPr.Position || Math.abs(this.Position - TextPr.Position) >= 0.001)))
            return false;

        if (true !== this.RFonts.Is_Equal(TextPr.RFonts))
            return false;

        if (this.BoldCS !== TextPr.BoldCS)
            return false;

        if (this.ItalicCS !== TextPr.ItalicCS)
            return false;

        if (false
            || (undefined === this.FontSizeCS
                && undefined !== TextPr.FontSizeCS)
            || (undefined !== this.FontSizeCS
                && (undefined === TextPr.FontSizeCS
                    || Math.abs(this.FontSizeCS - TextPr.FontSizeCS) >= 0.001)))
            return false;

        if (this.CS !== TextPr.CS)
            return false;

        if (this.RTL !== TextPr.RTL)
            return false;

        if (true !== this.Lang.Is_Equal(TextPr.Lang))
            return false;

        if ((undefined === this.Unifill && undefined !== TextPr.Unifill) || (undefined !== this.Unifill && (undefined === TextPr.Unifill || true !== this.Unifill.IsIdentical(TextPr.Unifill))))
            return false;

        if ((undefined === this.TextOutline && undefined !== TextPr.TextOutline) || (undefined !== this.TextOutline && (undefined === TextPr.TextOutline || true !== this.TextOutline.IsIdentical(TextPr.TextOutline))))
            return false;

        if ((undefined === this.TextFill && undefined !== TextPr.TextFill) || (undefined !== this.TextFill && (undefined === TextPr.TextFill || true !== this.TextFill.IsIdentical(TextPr.TextFill))))
            return false;

        if (this.Vanish !== TextPr.Vanish)
            return false;

		if (!IsEqualStyleObjects(this.Shd, TextPr.Shd))
			return false;
		if(undefined != TextPr.AscLine){
		    return false;
        }
        if(undefined != TextPr.AscUnifill){
            return false;
        }
        if(undefined != TextPr.AscFill){
            return false;
        }

        return true;
    },

    Have_PrChange : function()
    {
        if (undefined === this.PrChange || null === this.PrChange)
            return false;

        return true;
    },

    Add_PrChange : function()
    {
        this.PrChange   = this.Copy();
        this.ReviewInfo = new CReviewInfo();
        this.ReviewInfo.Update();
    },

    Set_PrChange : function(PrChange, ReviewInfo)
    {
        this.PrChange   = PrChange;
        this.ReviewInfo = ReviewInfo;
    },

    Remove_PrChange : function()
    {
        delete this.PrChange;
        delete this.ReviewInfo;
    },

    Get_DiffPrChange : function()
    {
        var TextPr = new CTextPr();

        if (false === this.Have_PrChange())
            return TextPr;

        var PrChange = this.PrChange;
        if (this.Bold !== PrChange.Bold)
            TextPr.Bold = this.Bold;

        if (this.Italic !== PrChange.Italic)
            TextPr.Italic = this.Italic;

        if (this.Strikeout !== PrChange.Strikeout)
            TextPr.Strikeout = this.Strikeout;

        if (this.Underline !== PrChange.Underline)
            TextPr.Underline = this.Underline;

        if (undefined !== this.FontFamily && (undefined === PrChange.FontFamily || this.FontFamily.Name !== PrChange.FontFamily.Name))
            TextPr.FontFamily = {Name : this.FontFamily.Name, Index : -1};

        if (undefined !== this.FontSize && (undefined === PrChange.FontSize || Math.abs(this.FontSize - PrChange.FontSize) >= 0.001))
            TextPr.FontSize = this.FontSize;

        if (undefined !== this.Color && (undefined === PrChange.Color || true !== this.Color.Compare(PrChange.Color)))
            TextPr.Color = this.Color.Copy();

        if (this.VertAlign !== PrChange.VertAlign)
            TextPr.VertAlign = this.VertAlign;

        if (highlight_None === this.HighLight)
        {
            if (highlight_None !== PrChange.HighLight)
                TextPr.HighLight = highlight_None;
        }
        else if (undefined !== this.HighLight)
        {
            if (undefined === PrChange.HighLight || highlight_None === PrChange.HighLight || true !== this.HighLight.Compare(PrChange.HighLight))
                TextPr.HighLight = this.HighLight.Copy();
        }

        if (this.RStyle !== PrChange.RStyle)
            TextPr.RStyle = this.RStyle;

        if (undefined !== this.Spacing && (undefined === PrChange.Spacing || Math.abs(this.Spacing - PrChange.Spacing) >= 0.001))
            TextPr.Spacing = this.Spacing;

        if (this.DStrikeout !== PrChange.DStrikeout)
            TextPr.DStrikeout = this.DStrikeout;

        if (this.Caps !== PrChange.Caps)
            TextPr.Caps = this.Caps;

        if (this.SmallCaps !== PrChange.SmallCaps)
            TextPr.SmallCaps = this.SmallCaps;

        if (undefined !== this.Position && (undefined === PrChange.Position || Math.abs(this.Position - PrChange.Position) >= 0.001))
            TextPr.Position = this.Position;

        if (undefined !== this.RFonts && (undefined === PrChange.RFonts || true !== this.RFonts.Is_Equal(TextPr.RFonts)))
            TextPr.RFonts = this.RFonts.Copy();

        if (this.BoldCS !== PrChange.BoldCS)
            TextPr.BoldCS = this.BoldCS;

        if (this.ItalicCS !== PrChange.ItalicCS)
            TextPr.ItalicCS = this.ItalicCS;

        if (undefined !== this.FontSizeCS && (undefined === PrChange.FontSizeCS || Math.abs(this.FontSizeCS - PrChange.FontSizeCS) >= 0.001))
            TextPr.FontSizeCS = this.FontSizeCS;

        if (this.CS !== PrChange.CS)
            TextPr.CS = this.CS;

        if (this.RTL !== PrChange.RTL)
            TextPr.RTL = this.RTL;

        if (undefined !== this.Lang && (undefined === PrChange.Lang || true !== this.Lang.Is_Equal(PrChange.Lang)))
            TextPr.Lang = this.Lang.Copy();

        if (undefined !== this.Unifill && (undefined === PrChange.Unifill || true !== this.Unifill.IsIdentical(PrChange.Unifill)))
            TextPr.Unifill = this.Unifill.createDuplicate();

        if (undefined !== this.TextOutline && (undefined === PrChange.TextOutline || true !== this.TextOutline.IsIdentical(PrChange.TextOutline)))
            TextPr.TextOutline = this.TextOutline.createDuplicate();

        if (undefined !== this.TextFill && (undefined === PrChange.TextFill || true !== this.TextFill.IsIdentical(PrChange.TextFill)))
            TextPr.TextFill = this.TextFill.createDuplicate();

        if (this.Vanish !== PrChange.Vanish)
            TextPr.Vanish = this.Vanish;

        // TODO: Shd

        return TextPr;
    },

    Get_Description : function()
    {
        var Description = "Text formatting: ";

        if (undefined !== this.Bold)
            Description += this.Bold ? "Bold; " : "No Bold; ";

        if (undefined !== this.Italic)
            Description += this.Italic ? "Italic; " : "No Italic; ";

        if (undefined !== this.Strikeout)
            Description += this.Strikeout ? "Strikeout; " : "No Strikeout; ";

        if (undefined !== this.DStrikeout)
            Description += this.DStrikeout ? "Double Strikeout; " : "No Double Strikeout; ";

        if (undefined !== this.FontSize)
            Description += this.FontSize + "FontSize; ";

//        if (undefined !== this.Color && (undefined === PrChange.Color || true !== this.Color.Compare(PrChange.Color)))
//            TextPr.Color = this.Color.Copy();
//
//        if (this.VertAlign !== PrChange.VertAlign)
//            TextPr.VertAlign = this.VertAlign;
//
//        if (highlight_None === this.HighLight)
//        {
//            if (highlight_None !== PrChange.HighLight)
//                TextPr.HighLight = highlight_None;
//        }
//        else if (undefined !== this.HighLight)
//        {
//            if (undefined === PrChange.HighLight || highlight_None === PrChange.HighLight || true !== this.HighLight.Compare(PrChange.HighLight))
//                TextPr.HighLight = this.HighLight.Copy();
//        }
//
//        if (this.RStyle !== PrChange.RStyle)
//            TextPr.RStyle = this.RStyle;
//
//        if (undefined !== this.Spacing && (undefined === PrChange.Spacing || Math.abs(this.Spacing - PrChange.Spacing) >= 0.001))
//            TextPr.Spacing = this.Spacing;
//
//        if (this.Caps !== PrChange.Caps)
//            TextPr.Caps = this.Caps;
//
//        if (this.SmallCaps !== PrChange.SmallCaps)
//            TextPr.SmallCaps = this.SmallCaps;
//
//        if (undefined !== this.Position && (undefined === PrChange.Position || Math.abs(this.Position - PrChange.Position) >= 0.001))
//            TextPr.Position = this.Position;
//
//        if (undefined !== this.RFonts && (undefined === PrChange.RFonts || true !== this.RFonts.Is_Equal(TextPr.RFonts)))
//            TextPr.RFonts = this.RFonts.Copy();
//
//        if (this.BoldCS !== PrChange.BoldCS)
//            TextPr.BoldCS = this.BoldCS;
//
//        if (this.ItalicCS !== PrChange.ItalicCS)
//            TextPr.ItalicCS = this.ItalicCS;
//
//        if (undefined !== this.FontSizeCS && (undefined === PrChange.FontSizeCS || Math.abs(this.FontSizeCS - PrChange.FontSizeCS) >= 0.001))
//            TextPr.FontSizeCS = this.FontSizeCS;
//
//        if (this.CS !== PrChange.CS)
//            TextPr.CS = this.CS;
//
//        if (this.RTL !== PrChange.RTL)
//            TextPr.RTL = this.RTL;
//
//        if (undefined !== this.Lang && (undefined === PrChange.Lang || true !== this.Lang.Is_Equal(PrChange.Lang)))
//            TextPr.Lang = this.Lang.Copy();
//
//        if (undefined !== this.Unifill && (undefined === PrChange.Unifill || true !== this.Unifill.IsIdentical(PrChange.Unifill)))
//            TextPr.Unifill = this.Unifill.createDuplicate();
//
//        if (undefined !== this.TextOutline && (undefined === PrChange.TextOutline || true !== this.TextOutline.IsIdentical(PrChange.TextOutline)))
//            TextPr.TextOutline = this.TextOutline.createDublicate();
//
//        if (undefined !== this.TextFill && (undefined === PrChange.TextFill || true !== this.TextFill.IsIdentical(PrChange.TextFill)))
//            TextPr.TextFill = this.TextFill.createDublicate();
//
//        if (this.Vanish !== PrChange.Vanish)
//            TextPr.Vanish = this.Vanish;

        return Description;
    }
};
CTextPr.prototype.Is_Empty = function()
{
	if (undefined !== this.Bold
		|| undefined !== this.Italic
		|| undefined !== this.Strikeout
		|| undefined !== this.Underline
		|| undefined !== this.FontFamily
		|| undefined !== this.FontSize
		|| undefined !== this.Color
		|| undefined !== this.VertAlign
		|| undefined !== this.HighLight
		|| undefined !== this.RStyle
		|| undefined !== this.Spacing
		|| undefined !== this.DStrikeout
		|| undefined !== this.Caps
		|| undefined !== this.SmallCaps
		|| undefined !== this.Position
		|| true !== this.RFonts.Is_Empty()
		|| undefined !== this.BoldCS
		|| undefined !== this.ItalicCS
		|| undefined !== this.FontSizeCS
		|| undefined !== this.CS
		|| undefined !== this.RTL
		|| true !== this.Lang.Is_Empty()
		|| undefined !== this.Unifill
		|| undefined !== this.FontRef
		|| undefined !== this.Shd
		|| undefined !== this.Vanish
		|| undefined !== this.TextOutline
		|| undefined !== this.TextFill)
		return false;

	return true;
};
CTextPr.prototype.GetBold = function()
{
    return this.Bold;
};
CTextPr.prototype.SetBold = function(isBold)
{
	this.Bold = isBold;
};
CTextPr.prototype.GetItalic = function()
{
    return this.Italic;
};
CTextPr.prototype.SetItalic = function(isItalic)
{
	this.Italic = isItalic;
};
CTextPr.prototype.GetStrikeout = function()
{
    return this.Strikeout;
};
CTextPr.prototype.SetStrikeout = function(isStrikeout)
{
	this.Strikeout = isStrikeout;
};
CTextPr.prototype.GetUnderline = function()
{
    return this.Underline;
};
CTextPr.prototype.SetUnderline = function(isUnderling)
{
	this.Underline = isUnderline;
};
CTextPr.prototype.GetColor = function()
{
    return this.Color;
};
CTextPr.prototype.SetColor = function(nR, nG, nB, isAuto)
{
	if (undefined === nR)
		this.Color = undefined;
	else
		this.Color = new CDocumentColor(nR, nG, nB, isAuto);
};
CTextPr.prototype.GetVertAlign = function()
{
    return this.VertAlign;
};
CTextPr.prototype.SetVertAlign = function(nVertAlign)
{
	this.VertAlign = nVertAlign;
};
CTextPr.prototype.GetHighlight = function()
{
    return this.HighLight;
};
CTextPr.prototype.SetHighlight = function(nHighlight)
{
	this.HighLight = nHighlight;
};
CTextPr.prototype.GetSpacing = function()
{
    return this.Spacing;
};
CTextPr.prototype.SetSpacing = function(nSpacing)
{
	this.Spacing = nSpacing;
};
CTextPr.prototype.GetDStrikeout = function()
{
    return this.DStrikeout;
};
CTextPr.prototype.SetDStrikeout = function(isDStrikeout)
{
	this.DStrikeout = isDStrikeout;
};
CTextPr.prototype.GetCaps = function()
{
    return this.Caps;
};
CTextPr.prototype.SetCaps = function(isCaps)
{
	this.Caps = isCaps;
};
CTextPr.prototype.GetSmallCaps = function()
{
    return this.SmallCaps;
};
CTextPr.prototype.SetSmallCaps = function(isSmallCaps)
{
	this.SmallCaps = isSmallCaps;
};
CTextPr.prototype.GetPosition = function()
{
    return this.Position;
};
CTextPr.prototype.SetPosition = function(nPosition)
{
	this.Position = nPosition;
};
CTextPr.prototype.GetFontFamily = function()
{
    if (this.RFonts && this.RFonts.Ascii && this.RFonts.Ascii.Name)
        return this.RFonts.Ascii.Name;

    return undefined;
};
CTextPr.prototype.SetFontFamily = function(sFontName)
{
	if (!this.RFonts)
		this.RFonts = new CRFonts();

	this.RFonts.SetAll(sFontName);
};
CTextPr.prototype.GetFontSize = function()
{
    return this.FontSize;
};
CTextPr.prototype.SetFontSize = function(nFontSize)
{
	this.FontSize = nFontSize;
};
CTextPr.prototype.GetLang = function()
{
    if (this.Lang)
        return this.Lang.Val;

    return undefined;
};
CTextPr.prototype.SetLang = function(nLang)
{
	if (!this.Lang)
		this.Lang = new CLang();

	this.Lang.Val = nLang;
};
CTextPr.prototype.GetShd = function()
{
    return this.Shd;
};
CTextPr.prototype.SetShd = function(nType, nR, nG, nB)
{
	if (!this.Shd)
		this.Shd = new CDocumentShd();

	this.Shd.Value = nType;

	if (Asc.c_oAscShdNil === nType)
		return;

	this.Shd.Color.Set(nR, nG, nB);
};
CTextPr.prototype.WriteToBinary = function(oWriter)
{
	return this.Write_ToBinary(oWriter);
};
CTextPr.prototype.ReadFromBinary = function(oReader)
{
	return this.Read_FromBinary(oReader);
};
CTextPr.prototype.GetAllFontNames = function(arrAllFonts)
{
	return this.Document_Get_AllFontNames(arrAllFonts);
};
//----------------------------------------------------------------------------------------------------------------------
// CTextPr Export
//----------------------------------------------------------------------------------------------------------------------
CTextPr.prototype['get_Bold']       = CTextPr.prototype.get_Bold       = CTextPr.prototype['Get_Bold']       = CTextPr.prototype.GetBold;
CTextPr.prototype['put_Bold']       = CTextPr.prototype.put_Bold       = CTextPr.prototype.SetBold;
CTextPr.prototype['get_Italic']     = CTextPr.prototype.get_Italic     = CTextPr.prototype['Get_Italic']     = CTextPr.prototype.GetItalic;
CTextPr.prototype['put_Italic']     = CTextPr.prototype.put_Italic     = CTextPr.prototype.SetItalic;
CTextPr.prototype['get_Strikeout']  = CTextPr.prototype.get_Strikeout  = CTextPr.prototype['Get_Strikeout']  = CTextPr.prototype.GetStrikeout;
CTextPr.prototype['put_Strikeout']  = CTextPr.prototype.put_Strikeout  = CTextPr.prototype.SetStrikeout;
CTextPr.prototype['get_Underline']  = CTextPr.prototype.get_Underline  = CTextPr.prototype['Get_Underline']  = CTextPr.prototype.GetUnderline;
CTextPr.prototype['put_Underline']  = CTextPr.prototype.put_Underline  = CTextPr.prototype.SetUnderline;
CTextPr.prototype['get_Color']      = CTextPr.prototype.get_Color      = CTextPr.prototype['Get_Color']      = CTextPr.prototype.GetColor;
CTextPr.prototype['put_Color']      = CTextPr.prototype.put_Color      = CTextPr.prototype.SetColor;
CTextPr.prototype['get_VertAlign']  = CTextPr.prototype.get_VertAlign  = CTextPr.prototype['Get_VertAlign']  = CTextPr.prototype.GetVertAlign;
CTextPr.prototype['put_VertAlign']  = CTextPr.prototype.put_VertAlign  = CTextPr.prototype.SetVertAlign;
CTextPr.prototype['get_Highlight']  = CTextPr.prototype.get_Highlight  = CTextPr.prototype['Get_Highlight']  = CTextPr.prototype.GetHighlight;
CTextPr.prototype['put_Highlight']  = CTextPr.prototype.put_Highlight  = CTextPr.prototype.SetHighlight;
CTextPr.prototype['get_Spacing']    = CTextPr.prototype.get_Spacing    = CTextPr.prototype['Get_Spacing']    = CTextPr.prototype.GetSpacing;
CTextPr.prototype['put_Spacing']    = CTextPr.prototype.put_Spacing    = CTextPr.prototype.SetSpacing;
CTextPr.prototype['get_DStrikeout'] = CTextPr.prototype.get_DStrikeout = CTextPr.prototype['Get_DStrikeout'] = CTextPr.prototype.GetDStrikeout;
CTextPr.prototype['put_DStrikeout'] = CTextPr.prototype.put_DStrikeout = CTextPr.prototype.SetDStrikeout;
CTextPr.prototype['get_Caps']       = CTextPr.prototype.get_Caps       = CTextPr.prototype['Get_Caps']       = CTextPr.prototype.GetCaps;
CTextPr.prototype['put_Caps']       = CTextPr.prototype.put_Caps       = CTextPr.prototype.SetCaps;
CTextPr.prototype['get_SmallCaps']  = CTextPr.prototype.get_SmallCaps  = CTextPr.prototype['Get_SmallCaps']  = CTextPr.prototype.GetSmallCaps;
CTextPr.prototype['put_SmallCaps']  = CTextPr.prototype.put_SmallCaps  = CTextPr.prototype.SetSmallCaps;
CTextPr.prototype['get_Position']   = CTextPr.prototype.get_Position   = CTextPr.prototype['Get_Position']   = CTextPr.prototype.GetPosition;
CTextPr.prototype['put_Position']   = CTextPr.prototype.put_Position   = CTextPr.prototype.SetPosition;
CTextPr.prototype['get_FontFamily'] = CTextPr.prototype.get_FontFamily = CTextPr.prototype['Get_FontFamily'] = CTextPr.prototype.GetFontFamily;
CTextPr.prototype['put_FontFamily'] = CTextPr.prototype.put_FontFamily = CTextPr.prototype.SetFontFamily;
CTextPr.prototype['get_FontSize']   = CTextPr.prototype.get_FontSize   = CTextPr.prototype['Get_FontSize']   = CTextPr.prototype.GetFontSize;
CTextPr.prototype['put_FontSize']   = CTextPr.prototype.put_FontSize   = CTextPr.prototype.SetFontSize;
CTextPr.prototype['get_Lang']       = CTextPr.prototype.get_Lang       = CTextPr.prototype['Get_Lang']       = CTextPr.prototype.GetLang;
CTextPr.prototype['put_Lang']       = CTextPr.prototype.put_Lang       = CTextPr.prototype.SetLang;
CTextPr.prototype['get_Shd']        = CTextPr.prototype.get_Shd        = CTextPr.prototype['Get_Shd']        = CTextPr.prototype.GetShd;
CTextPr.prototype['put_Shd']        = CTextPr.prototype.put_Shd        = CTextPr.prototype.SetShd;
//----------------------------------------------------------------------------------------------------------------------

function CParaTab(Value, Pos, Leader)
{
	this.Value  = Value;
	this.Pos    = Pos;
	this.Leader = undefined !== Leader ? Leader : Asc.c_oAscTabLeader.None;
}
CParaTab.prototype.Copy = function()
{
	return new CParaTab(this.Value, this.Pos, this.Leader);
};
CParaTab.prototype.Is_Equal = function(Tab)
{
	return this.IsEqual(Tab);
};
CParaTab.prototype.IsEqual = function(Tab)
{
	// TODO: Если таб точно такого же типа и в той же позиции, то неясно нужно ли проверять совпадение Tab.Leader
	if (this.Value !== Tab.Value
		|| this.Pos !== Tab.Pos)
		return false;

	return true;
};
CParaTab.prototype.IsRightTab = function()
{
	return this.Value === tab_Right;
};
CParaTab.prototype.IsLeftTab = function()
{
	return this.Value === tab_Left;
};
CParaTab.prototype.IsCenterTab = function()
{
	return this.Value === tab_Center;
};
CParaTab.prototype.GetLeader = function()
{
	return this.Leader;
};

function CParaTabs()
{
	this.Tabs = [];
}
CParaTabs.prototype.Add = function(_Tab)
{
	var Index = 0;
	for (Index = 0; Index < this.Tabs.length; Index++)
	{
		var Tab = this.Tabs[Index];

		if (Math.abs(Tab.Pos - _Tab.Pos) < 0.001)
		{
			this.Tabs.splice(Index, 1, _Tab);
			break;
		}

		if (Tab.Pos > _Tab.Pos)
			break;
	}

	if (-1 != Index)
		this.Tabs.splice(Index, 0, _Tab);
};
CParaTabs.prototype.Merge = function(Tabs)
{
	var _Tabs = Tabs.Tabs;

	for (var Index = 0; Index < _Tabs.length; Index++)
	{
		var _Tab = _Tabs[Index];

		var Index2 = 0;
		var Flag   = 0;
		for (Index2 = 0; Index2 < this.Tabs.length; Index2++)
		{
			var Tab = this.Tabs[Index2];

			if (Math.abs(Tab.Pos - _Tab.Pos) < 0.001)
			{
				if (tab_Clear === _Tab.Value)
					Flag = -2; // таб нужно удалить
				else
					Flag = -1; // табы совпали, не надо новый добавлять

				break;
			}

			if (Tab.Pos > _Tab.Pos)
				break;
		}

		if (-2 === Flag)
			this.Tabs.splice(Index2, 1);
		else if (-1 != Flag)
			this.Tabs.splice(Index2, 0, _Tab);
	}
};
CParaTabs.prototype.IsEqual = function(Tabs)
{
	if (this.Tabs.length !== Tabs.Tabs.length)
		return false;

	for (var CurTab = 0, TabsCount = this.Tabs.length; CurTab < TabsCount; CurTab++)
	{
		if (true !== this.Tabs[CurTab].IsEqual(Tabs.Tabs[CurTab]))
			return false;
	}

	return true;
};
CParaTabs.prototype.Is_Equal = function(Tabs)
{
	return this.IsEqual(Tabs);
};
CParaTabs.prototype.Copy = function()
{
	var Tabs  = new CParaTabs();
	var Count = this.Tabs.length;

	for (var Index = 0; Index < Count; Index++)
		Tabs.Add(this.Tabs[Index].Copy());

	return Tabs;
};
CParaTabs.prototype.Set_FromObject = function(Tabs)
{
	if (Tabs instanceof Array)
	{
		for (var nIndex = 0, nCount = Tabs.length; nIndex < nCount; ++nIndex)
			this.Add(new CParaTab(Tabs[nIndex].Value, Tabs[nIndex].Pos, Tabs[nIndex].Leader));
	}
};
CParaTabs.prototype.GetCount = function()
{
	return this.Tabs.length;
};
CParaTabs.prototype.Get_Count = function()
{
	return this.GetCount();
};
CParaTabs.prototype.Get = function(Index)
{
	return this.Tabs[Index];
};
CParaTabs.prototype.Get_Value = function(Pos)
{
	var Count = this.Tabs.length;
	for (var Index = 0; Index < Count; Index++)
	{
		var Tab = this.Tabs[Index];
		if (Math.abs(Tab.Pos - Pos) < 0.001)
			return Tab.Value;
	}

	return -1;
};
CParaTabs.prototype.Write_ToBinary = function(Writer)
{
	// Long : количество (если 0, удаляем элемент)
	// Массив
	// Byte   : Value
	// Double : Pos
	// Long   : Leader

	var Count = this.Tabs.length;
	Writer.WriteLong(Count);

	for (var Index = 0; Index < Count; Index++)
	{
		Writer.WriteByte(this.Tabs[Index].Value);
		Writer.WriteDouble(this.Tabs[Index].Pos);
		Writer.WriteLong(this.Tabs[Index].Leader);
	}
};
CParaTabs.prototype.Read_FromBinary = function(Reader)
{
	// Long : количество (если 0, удаляем элемент)
	// Массив
	// Byte   : Value
	// Double : Pos
	// Long   : Leader

	var Count = Reader.GetLong();
	this.Tabs = [];

	for (var Index = 0; Index < Count; Index++)
	{
		var Value  = Reader.GetByte();
		var Pos    = Reader.GetDouble();
		var Leader = Reader.GetLong();
		this.Add(new CParaTab(Value, Pos, Leader));
	}
};

function CParaInd()
{
    this.Left      = undefined; // Левый отступ
    this.Right     = undefined; // Правый отступ
    this.FirstLine = undefined; // Первая строка
}

CParaInd.prototype =
{
    Copy : function()
    {
        var Ind = new CParaInd();
        Ind.Left      = this.Left;
        Ind.Right     = this.Right;
        Ind.FirstLine = this.FirstLine;
        return Ind;
    },

    Merge : function(Ind)
    {
        if ( undefined != Ind.Left )
            this.Left = Ind.Left;

        if ( undefined != Ind.Right )
            this.Right = Ind.Right;

        if ( undefined != Ind.FirstLine )
            this.FirstLine = Ind.FirstLine;
    },

    Is_Equal  : function(Ind)
    {
        if (IsEqualNullableFloatNumbers(this.Left, Ind.Left)
			&& IsEqualNullableFloatNumbers(this.Right, Ind.Right)
			&& IsEqualNullableFloatNumbers(this.FirstLine, Ind.FirstLine))
            return true;

        return false;
    },

    Set_FromObject : function(Ind)
    {
        if ( undefined != Ind.Left )
            this.Left = Ind.Left;
        else
            this.Left = undefined;

        if ( undefined != Ind.Right )
            this.Right = Ind.Right;
        else
            this.Right = undefined;

        if ( undefined != Ind.FirstLine )
            this.FirstLine = Ind.FirstLine;
        else
            this.FirstLine = undefined;
    },

    Write_ToBinary : function(Writer)
    {
        var StartPos = Writer.GetCurPosition();
        Writer.Skip(4);
        var Flags = 0;

        if ( undefined != this.Left )
        {
            Writer.WriteDouble( this.Left );
            Flags |= 1;
        }

        if ( undefined != this.Right )
        {
            Writer.WriteDouble( this.Right );
            Flags |= 2;
        }

        if ( undefined != this.FirstLine )
        {
            Writer.WriteDouble( this.FirstLine );
            Flags |= 4;
        }

        var EndPos = Writer.GetCurPosition();
        Writer.Seek( StartPos );
        Writer.WriteLong( Flags );
        Writer.Seek( EndPos );
    },

    Read_FromBinary : function(Reader)
    {
        var Flags = Reader.GetLong();

        if ( Flags & 1 )
            this.Left = Reader.GetDouble();

        if ( Flags & 2 )
            this.Right = Reader.GetDouble();

        if ( Flags & 4 )
            this.FirstLine = Reader.GetDouble();
    }
};
CParaInd.prototype.Is_Empty = function()
{
	if (undefined !== this.Left
		|| undefined !== this.Right
		|| undefined !== this.FirstLine)
		return false;

	return true;
};
CParaInd.prototype.Get_Diff = function(Ind)
{
    var DiffInd = new CParaInd();

    if (this.Left !== Ind.Left)
        DiffInd.Left = this.Left;

    if (this.Left !== Ind.Right)
        DiffInd.Right = this.Right;

    if (this.FirstLine !== Ind.FirstLine)
        DiffInd.FirstLine = this.FirstLine;

    return DiffInd;
};

function CParaSpacing()
{
    this.Line              = undefined; // Расстояние между строками внутри абзаца
    this.LineRule          = undefined; // Тип расстрояния между строками
    this.Before            = undefined; // Дополнительное расстояние до абзаца
    this.BeforePct         = undefined; // Расстояние до абзаца в процентах от высоты строки
    this.BeforeAutoSpacing = undefined; // Использовать ли автоматический расчет расстояния до параграфа
    this.After             = undefined; // Дополнительное расстояние после абзаца
    this.AfterPct          = undefined; // Расстояние после абзаца в процентах от высоты строки
    this.AfterAutoSpacing  = undefined; // Использовать ли автоматический расчет расстояния после параграфа
}

CParaSpacing.prototype =
{
    Copy : function()
    {
        var Spacing = new CParaSpacing();
        Spacing.Line              = this.Line;
        Spacing.LineRule          = this.LineRule;
        Spacing.Before            = this.Before;
        Spacing.BeforeAutoSpacing = this.BeforeAutoSpacing;
        Spacing.After             = this.After;
        Spacing.AfterAutoSpacing  = this.AfterAutoSpacing;
        Spacing.BeforePct         = this.BeforePct;
        Spacing.AfterPct          = this.AfterPct;
        return Spacing;
    },

    Merge : function(Spacing)
    {
        if ( undefined != Spacing.Line )
            this.Line = Spacing.Line;

        if ( undefined != Spacing.LineRule )
            this.LineRule = Spacing.LineRule;

        if ( undefined != Spacing.Before )
            this.Before = Spacing.Before;

        if ( undefined != Spacing.BeforeAutoSpacing )
            this.BeforeAutoSpacing = Spacing.BeforeAutoSpacing;

        if ( undefined != Spacing.After )
            this.After = Spacing.After;

        if ( undefined != Spacing.AfterAutoSpacing )
            this.AfterAutoSpacing = Spacing.AfterAutoSpacing;

        if ( undefined != Spacing.BeforePct )
            this.BeforePct = Spacing.BeforePct;

        if ( undefined != Spacing.AfterPct )
            this.AfterPct = Spacing.AfterPct;
    },

	Is_Equal : function(Spacing)
	{
		if (this.Line !== Spacing.Line
			|| this.LineRule !== Spacing.LineRule
			|| (this.Before === undefined && Spacing.Before !== undefined)
			|| (this.Before !== undefined && Spacing.Before === undefined)
			|| ((this.Before !== undefined && Spacing.Before !== undefined) && (this.Before - Spacing.Before) > 0.001)
			|| this.BeforeAutoSpacing !== Spacing.BeforeAutoSpacing
			|| (this.After === undefined && Spacing.After !== undefined)
			|| (this.After !== undefined && Spacing.After === undefined)
			|| ((this.After !== undefined && Spacing.After !== undefined) && (this.After - Spacing.After) > 0.001)
			|| (this.AfterPct === undefined && Spacing.AfterPct !== undefined)
			|| (this.AfterPct !== undefined && Spacing.AfterPct === undefined)
			|| ((this.AfterPct !== undefined && Spacing.AfterPct !== undefined) && (this.AfterPct - Spacing.AfterPct) > 0.001)
			|| (this.BeforePct === undefined && Spacing.BeforePct !== undefined)
			|| (this.BeforePct !== undefined && Spacing.BeforePct === undefined)
			|| ((this.BeforePct !== undefined && Spacing.BeforePct !== undefined) && (this.BeforePct - Spacing.BeforePct) > 0.001)
			|| this.AfterAutoSpacing !== Spacing.AfterAutoSpacing)
			return false;

		return true;
	},

    Set_FromObject : function(Spacing)
    {
        this.Line              = Spacing.Line;
        this.LineRule          = Spacing.LineRule;
        this.Before            = Spacing.Before;
        this.BeforeAutoSpacing = Spacing.BeforeAutoSpacing;
        this.After             = Spacing.After;
        this.AfterAutoSpacing  = Spacing.AfterAutoSpacing;
        this.BeforePct         = Spacing.BeforePct;
        this.AfterPct          = Spacing.AfterPct;
    },

    Write_ToBinary : function(Writer)
    {
        var StartPos = Writer.GetCurPosition();
        Writer.Skip(4);
        var Flags = 0;

        if ( undefined != this.Line )
        {
            Writer.WriteDouble( this.Line );
            Flags |= 1;
        }

        if ( undefined != this.LineRule )
        {
            Writer.WriteByte( this.LineRule );
            Flags |= 2;
        }

        if ( undefined != this.Before )
        {
            Writer.WriteDouble( this.Before );
            Flags |= 4;
        }

        if ( undefined != this.After )
        {
            Writer.WriteDouble( this.After );
            Flags |= 8;
        }

        if ( undefined != this.AfterAutoSpacing )
        {
            Writer.WriteBool( this.AfterAutoSpacing );
            Flags |= 16;
        }

        if ( undefined != this.BeforeAutoSpacing )
        {
            Writer.WriteBool( this.BeforeAutoSpacing );
            Flags |= 32;
        }

        if ( undefined != this.BeforePct )
        {
            Writer.WriteLong( this.BeforePct );
            Flags |= 64;
        }

        if ( undefined != this.AfterPct )
        {
            Writer.WriteLong( this.AfterPct );
            Flags |= 128;
        }

        var EndPos = Writer.GetCurPosition();
        Writer.Seek( StartPos );
        Writer.WriteLong( Flags );
        Writer.Seek( EndPos );
    },

    Read_FromBinary : function(Reader)
    {
        var Flags = Reader.GetLong();

        if ( Flags & 1 )
            this.Line = Reader.GetDouble();

        if ( Flags & 2 )
            this.LineRule = Reader.GetByte();

        if ( Flags & 4 )
            this.Before = Reader.GetDouble();

        if ( Flags & 8 )
            this.After = Reader.GetDouble();

        if ( Flags & 16 )
            this.AfterAutoSpacing = Reader.GetBool();

        if ( Flags & 32 )
            this.BeforeAutoSpacing = Reader.GetBool();

        if ( Flags & 64 )
            this.BeforePct = Reader.GetLong();

        if ( Flags & 128 )
            this.AfterPct = Reader.GetLong();
    }
};
CParaSpacing.prototype.Get_Diff = function(Spacing)
{
    var DiffSpacing = new CParaSpacing();

    if (this.Line !== Spacing.Line)
        DiffSpacing.Line = this.Line;

    if (this.LineRule !== Spacing.LineRule)
        DiffSpacing.LineRule = this.LineRule;

    if (this.Before !== Spacing.Before)
        DiffSpacing.Before = this.Before;

    if (this.BeforeAutoSpacing !== Spacing.BeforeAutoSpacing)
        DiffSpacing.BeforeAutoSpacing = this.BeforeAutoSpacing;

    if (this.After !== Spacing.After)
        DiffSpacing.After = this.After;

    if (this.AfterAutoSpacing !== Spacing.AfterAutoSpacing)
        DiffSpacing.AfterAutoSpacing = this.AfterAutoSpacing;

    if (this.BeforePct !== Spacing.BeforePct)
        DiffSpacing.BeforePct = this.BeforePct;

    if (this.AfterPct !== Spacing.AfterPct)
        DiffSpacing.AfterPct = this.AfterPct;


    return DiffSpacing;
};
CParaSpacing.prototype.Is_Empty = function()
{
	if (undefined !== this.Line
		|| undefined !== this.LineRule
		|| undefined !== this.Before
		|| undefined !== this.BeforeAutoSpacing
		|| undefined !== this.After
		|| undefined !== this.AfterAutoSpacing
		|| undefined !== this.BeforePct
		|| undefined !== this.AfterPct)
		return false;

	return true;
};

function CNumPr(sNumId, nLvl)
{
    this.NumId = undefined !== sNumId ? sNumId : "-1";
    this.Lvl   = undefined !== nLvl ? nLvl : 0;
}

CNumPr.prototype =
{
    Copy : function()
    {
        var NumPr = new CNumPr();
        NumPr.NumId = this.NumId;
        NumPr.Lvl   = this.Lvl;
        return NumPr;
    },

    Merge : function(NumPr)
    {
        if ( undefined != NumPr.NumId )
            this.NumId = NumPr.NumId;

        if ( undefined != NumPr.Lvl )
            this.Lvl = NumPr.Lvl;
    },

    Is_Equal : function(NumPr)
    {
        if (this.NumId != NumPr.NumId
            || this.Lvl !== NumPr.Lvl)
            return false;

        return true;
    },

    Set : function(NumId, Lvl)
    {
        this.NumId = NumId;
        this.Lvl   = Lvl;
    },

    Set_FromObject : function(NumPr)
    {
        this.NumId = NumPr.NumId;
        this.Lvl   = NumPr.Lvl;
    },

    Write_ToBinary : function(Writer)
    {
        // Bool   : Is NumId undefined
        // String : NumId
        // Bool   : IsLvl undefined
        // Byte   : Lvl

        if ( undefined === this.NumId )
            Writer.WriteBool( true );
        else
        {
            Writer.WriteBool( false );
            Writer.WriteString2( this.NumId );
        }

        if ( undefined === this.Lvl )
            Writer.WriteBool( true );
        else
        {
            Writer.WriteBool( false );
            Writer.WriteByte( this.Lvl );
        }
    },

    Read_FromBinary : function(Reader)
    {
        // Bool   : Is NumId undefined
        // String : NumId
        // Byte   : Lvl

        if ( true === Reader.GetBool() )
            this.NumId = undefined;
        else
            this.NumId = Reader.GetString2();

        if ( true === Reader.GetBool() )
            this.Lvl = undefined;
        else
            this.Lvl = Reader.GetByte();
    }
};
CNumPr.prototype.IsValid = function()
{
	if (undefined === this.NumId
		|| null === this.NumId
		|| 0 === this.NumId
		|| "0" === this.NumId)
		return false;

	return true;
};

var wrap_Around    = 0x01;
var wrap_Auto      = 0x02;
var wrap_None      = 0x03;
var wrap_NotBeside = 0x04;
var wrap_Through   = 0x05;
var wrap_Tight     = 0x06;

function CFramePr()
{
    this.DropCap = undefined; // Является ли данный элемент буквицей
    this.H       = undefined;
    this.HAnchor = undefined;
    this.HRule   = undefined;
    this.HSpace  = undefined;
    this.Lines   = undefined;
    this.VAnchor = undefined;
    this.VSpace  = undefined;
    this.W       = undefined;
    this.Wrap    = undefined;
    this.X       = undefined;
    this.XAlign  = undefined;
    this.Y       = undefined;
    this.YAlign  = undefined;
}

CFramePr.prototype =
{
    Copy : function()
    {
        var FramePr = new CFramePr();

        FramePr.DropCap = this.DropCap;
        FramePr.H       = this.H;
        FramePr.HAnchor = this.HAnchor;
        FramePr.HRule   = this.HRule;
        FramePr.HSpace  = this.HSpace;
        FramePr.Lines   = this.Lines;
        FramePr.VAnchor = this.VAnchor;
        FramePr.VSpace  = this.VSpace;
        FramePr.W       = this.W;
        FramePr.Wrap    = this.Wrap;
        FramePr.X       = this.X;
        FramePr.XAlign  = this.XAlign;
        FramePr.Y       = this.Y;
        FramePr.YAlign  = this.YAlign;

        return FramePr;
    },

    Compare : function(FramePr)
    {
        if (this.DropCap != FramePr.DropCap
            || Math.abs(this.H - FramePr.H) > 0.001
            || this.HAnchor != FramePr.HAnchor
            || this.HRule != FramePr.HRule
            || this.HSpace != FramePr.HSpace
            || this.Lines != FramePr.Lines
            || this.VAnchor != FramePr.VAnchor
            || this.VSpace != FramePr.VSpace
            || Math.abs(this.W - FramePr.W) > 0.001
            || this.Wrap != FramePr.Wrap
            || Math.abs(this.X - FramePr.X) > 0.001
            || this.XAlign != FramePr.XAlign
            || Math.abs(this.Y - FramePr.Y) > 0.001
            || this.YAlign != FramePr.YAlign)
            return false;

        return true;
    },

    Is_Equal : function(FramePr)
    {
        return this.Compare(FramePr);
    },

    Set_FromObject : function(FramePr)
    {
        this.DropCap = FramePr.DropCap;
        this.H       = FramePr.H;
        this.HAnchor = FramePr.HAnchor;
        this.HRule   = FramePr.HRule;
        this.HSpace  = FramePr.HSpace;
        this.Lines   = FramePr.Lines;
        this.VAnchor = FramePr.VAnchor;
        this.VSpace  = FramePr.VSpace;
        this.W       = FramePr.W;
        this.Wrap    = FramePr.Wrap;
        this.X       = FramePr.X;
        this.XAlign  = FramePr.XAlign;
        this.Y       = FramePr.Y;
        this.YAlign  = FramePr.YAlign;
    },

	Write_ToBinary : function(Writer)
	{
		var StartPos = Writer.GetCurPosition();
		Writer.Skip(4);
		var Flags = 0;

		if (undefined != this.DropCap)
		{
			Writer.WriteLong(this.DropCap);
			Flags |= 1;
		}

		if (undefined != this.H)
		{
			Writer.WriteDouble(this.H);
			Flags |= 2;
		}

		if (undefined != this.HAnchor)
		{
			Writer.WriteLong(this.HAnchor);
			Flags |= 4;
		}

		if (undefined != this.HRule)
		{
			Writer.WriteLong(this.HRule);
			Flags |= 8;
		}

		if (undefined != this.HSpace)
		{
			Writer.WriteDouble(this.HSpace);
			Flags |= 16;
		}

		if (undefined != this.Lines)
		{
			Writer.WriteLong(this.Lines);
			Flags |= 32;
		}

		if (undefined != this.VAnchor)
		{
			Writer.WriteLong(this.VAnchor);
			Flags |= 64;
		}

		if (undefined != this.VSpace)
		{
			Writer.WriteDouble(this.VSpace);
			Flags |= 128;
		}

		if (undefined != this.W)
		{
			Writer.WriteDouble(this.W);
			Flags |= 256;
		}

		if (undefined != this.X)
		{
			Writer.WriteDouble(this.X);
			Flags |= 512;
		}

		if (undefined != this.XAlign)
		{
			Writer.WriteLong(this.XAlign);
			Flags |= 1024;
		}

		if (undefined != this.Y)
		{
			Writer.WriteDouble(this.Y);
			Flags |= 2048;
		}

		if (undefined != this.YAlign)
		{
			Writer.WriteLong(this.YAlign);
			Flags |= 4096;
		}

		if (undefined !== this.Wrap)
		{
			Writer.WriteLong(this.Wrap);
			Flags |= 8192;
		}

		var EndPos = Writer.GetCurPosition();
		Writer.Seek(StartPos);
		Writer.WriteLong(Flags);
		Writer.Seek(EndPos);
	},

	Read_FromBinary : function(Reader)
	{
		var Flags = Reader.GetLong();

		if (Flags & 1)
			this.DropCap = Reader.GetLong();

		if (Flags & 2)
			this.H = Reader.GetDouble();

		if (Flags & 4)
			this.HAnchor = Reader.GetLong();

		if (Flags & 8)
			this.HRule = Reader.GetLong();

		if (Flags & 16)
			this.HSpace = Reader.GetDouble();

		if (Flags & 32)
			this.Lines = Reader.GetLong();

		if (Flags & 64)
			this.VAnchor = Reader.GetLong();

		if (Flags & 128)
			this.VSpace = Reader.GetDouble();

		if (Flags & 256)
			this.W = Reader.GetDouble();

		if (Flags & 512)
			this.X = Reader.GetDouble();

		if (Flags & 1024)
			this.XAlign = Reader.GetLong();

		if (Flags & 2048)
			this.Y = Reader.GetDouble();

		if (Flags & 4096)
			this.YAlign = Reader.GetLong();

		if (Flags & 8192)
			this.Wrap = Reader.GetLong();
	},

    Init_Default_DropCap : function(bInside)
    {
        this.DropCap = ( true === bInside ? c_oAscDropCap.Drop : c_oAscDropCap.Margin );
        this.Lines   = 3;
        this.Wrap    = wrap_Around;
        this.VAnchor = Asc.c_oAscVAnchor.Text;
        this.HAnchor = ( true === bInside ? Asc.c_oAscHAnchor.Text : Asc.c_oAscHAnchor.Page );

        this.X       = undefined;
        this.XAlign  = undefined;
        this.Y       = undefined;
        this.YAlign  = undefined;

        this.H       = undefined;
        this.W       = undefined;
        this.HRule   = undefined;
    },

    Get_W : function()
    {
        return this.W;
    },

    Get_H : function()
    {
        return this.H;
    },

    Is_DropCap : function()
    {
        if ( c_oAscDropCap.Margin === this.DropCap || c_oAscDropCap.Drop === this.DropCap )
            return true;

        return false;
    }
};

function CParaPr()
{
    this.ContextualSpacing = undefined;          // Удалять ли интервал между параграфами одинакового стиля
    this.Ind               = new CParaInd();     // Отступы
    this.Jc                = undefined;          // Прилегание параграфа
    this.KeepLines         = undefined;          // Неразрывный параграф
    this.KeepNext          = undefined;          // Не разъединять со следующим параграфом
    this.PageBreakBefore   = undefined;          // Разрыв страницы перед параграфом
    this.Spacing           = new CParaSpacing(); // Расстояния между строками внутри параграфа и между параграфами
    this.Shd               = undefined;          // Заливка параграфа
    this.Brd =
    {
        First   : undefined,            // Является ли данный параграф первым в группе параграфов с одинаковыми краями и настройками границ
        Last    : undefined,            // Является ли данный параграф последним в группе параграфов с одинаковыми краями и настройками границ
        Between : undefined,
        Bottom  : undefined,
        Left    : undefined,
        Right   : undefined,
        Top     : undefined
    };
    this.WidowControl      = undefined; // Запрет висячих строк
    this.Tabs              = undefined; // Заданные табы
    this.NumPr             = undefined; // Нумерация
    this.PStyle            = undefined; // Стиль параграфа
    this.FramePr           = undefined;
    this.OutlineLvl        = undefined; // Для TableOfContents

    this.DefaultRunPr      = undefined;
    this.Bullet            = undefined;
    this.Lvl               = undefined;
    this.DefaultTab    = undefined;

    this.PrChange          = undefined;
}

CParaPr.prototype =
{
    Copy : function(bCopyPrChange)
    {
        var ParaPr = new CParaPr();

        ParaPr.ContextualSpacing = this.ContextualSpacing;

        if ( undefined != this.Ind )
            ParaPr.Ind = this.Ind.Copy();

        ParaPr.Jc              = this.Jc;
        ParaPr.KeepLines       = this.KeepLines;
        ParaPr.KeepNext        = this.KeepNext;
        ParaPr.PageBreakBefore = this.PageBreakBefore;

        if ( undefined != this.Spacing )
            ParaPr.Spacing = this.Spacing.Copy();

        if ( undefined != this.Shd )
            ParaPr.Shd = this.Shd.Copy();

        ParaPr.Brd.First = this.Brd.First;
        ParaPr.Brd.Last  = this.Brd.Last;

        if ( undefined != this.Brd.Between )
            ParaPr.Brd.Between = this.Brd.Between.Copy();

        if ( undefined != this.Brd.Bottom )
            ParaPr.Brd.Bottom = this.Brd.Bottom.Copy();

        if ( undefined != this.Brd.Left )
            ParaPr.Brd.Left = this.Brd.Left.Copy();

        if ( undefined != this.Brd.Right )
            ParaPr.Brd.Right = this.Brd.Right.Copy();

        if ( undefined != this.Brd.Top )
            ParaPr.Brd.Top = this.Brd.Top.Copy();

        ParaPr.WidowControl = this.WidowControl;

        if ( undefined != this.Tabs )
            ParaPr.Tabs = this.Tabs.Copy();

        if ( undefined != this.NumPr )
            ParaPr.NumPr = this.NumPr.Copy();

        if ( undefined != this.PStyle )
            ParaPr.PStyle = this.PStyle;

        if ( undefined != this.FramePr )
            ParaPr.FramePr = this.FramePr.Copy();
        else
            ParaPr.FramePr = undefined;

        if( undefined != this.DefaultRunPr)
            ParaPr.DefaultRunPr = this.DefaultRunPr.Copy();

        if( undefined != this.Bullet)
            ParaPr.Bullet = this.Bullet.createDuplicate();

        if(undefined != this.Lvl)
            ParaPr.Lvl = this.Lvl;

        if(undefined != this.DefaultTab)
            ParaPr.DefaultTab = this.DefaultTab;

        if (true === bCopyPrChange && undefined !== this.PrChange)
        {
            ParaPr.PrChange   = this.PrChange.Copy();
            ParaPr.ReviewInfo = this.ReviewInfo.Copy();
        }

        if (undefined !== this.OutlineLvl)
        	ParaPr.OutlineLvl = this.OutlineLvl;

        return ParaPr;
    },

    Merge : function(ParaPr)
    {
        if ( undefined != ParaPr.ContextualSpacing )
            this.ContextualSpacing = ParaPr.ContextualSpacing;

        if ( undefined != ParaPr.Ind )
            this.Ind.Merge( ParaPr.Ind );

        if ( undefined != ParaPr.Jc )
            this.Jc = ParaPr.Jc;

        if ( undefined != ParaPr.KeepLines )
            this.KeepLines = ParaPr.KeepLines;

        if ( undefined != ParaPr.KeepNext )
            this.KeepNext = ParaPr.KeepNext;

        if ( undefined != ParaPr.PageBreakBefore )
            this.PageBreakBefore = ParaPr.PageBreakBefore;

        if ( undefined != ParaPr.Spacing )
            this.Spacing.Merge( ParaPr.Spacing );

        if ( undefined != ParaPr.Shd )
            this.Shd = ParaPr.Shd.Copy();

        if ( undefined != ParaPr.Brd.First )
            this.Brd.First = ParaPr.Brd.First;

        if ( undefined != ParaPr.Brd.Last )
            this.Brd.Last  = ParaPr.Brd.Last;

        if ( undefined != ParaPr.Brd.Between )
            this.Brd.Between = ParaPr.Brd.Between.Copy();

        if ( undefined != ParaPr.Brd.Bottom )
            this.Brd.Bottom = ParaPr.Brd.Bottom.Copy();

        if ( undefined != ParaPr.Brd.Left )
            this.Brd.Left = ParaPr.Brd.Left.Copy();

        if ( undefined != ParaPr.Brd.Right )
            this.Brd.Right = ParaPr.Brd.Right.Copy();

        if ( undefined != ParaPr.Brd.Top )
            this.Brd.Top = ParaPr.Brd.Top.Copy();

        if ( undefined != ParaPr.WidowControl )
            this.WidowControl = ParaPr.WidowControl;

        if ( undefined != ParaPr.Tabs )
        {
            if ( undefined === this.Tabs )
                this.Tabs = ParaPr.Tabs.Copy();
            else
                this.Tabs.Merge( ParaPr.Tabs );
        }

        if ( undefined != ParaPr.NumPr )
        {
            if ( undefined === this.NumPr )
                this.NumPr = ParaPr.NumPr.Copy();
            else
                this.NumPr.Merge( ParaPr.NumPr );

            if ( undefined != this.NumPr && this.NumPr.Lvl > 8 )
                this.NumPr = undefined;
        }

        if ( undefined != ParaPr.PStyle )
            this.PStyle = ParaPr.PStyle;

        this.FramePr = undefined;

        if( undefined != ParaPr.DefaultRunPr )
        {
            if( undefined == this.DefaultRunPr )
                this.DefaultRunPr = new CTextPr();
            this.DefaultRunPr.Merge(ParaPr.DefaultRunPr);
        }

        if(undefined != ParaPr.Bullet)
        {
            if(ParaPr.Bullet.isBullet())
            {
                if(!this.Bullet)
                {
                    this.Bullet = new AscFormat.CBullet();
                }
                var PrBullet = ParaPr.Bullet;
                if(PrBullet.bulletColor)
                {
                    this.Bullet.bulletColor = PrBullet.bulletColor.createDuplicate();
                }
                if(PrBullet.bulletSize)
                {
                    this.Bullet.bulletSize = PrBullet.bulletSize.createDuplicate();
                }
                if(PrBullet.bulletTypeface)
                {
                    this.Bullet.bulletTypeface = PrBullet.bulletTypeface.createDuplicate();
                }
                if(PrBullet.bulletType)
                {
                    this.Bullet.bulletType = PrBullet.bulletType.createDuplicate();
                }
                this.Bullet.Bullet = PrBullet.Bullet;

            }
            else
            {
                if(this.Bullet && this.Bullet.isBullet()){
                    if(ParaPr.Bullet.bulletColor){
                        this.Bullet.bulletColor = ParaPr.Bullet.bulletColor.createDuplicate();
                    }
                    if(ParaPr.Bullet.bulletSize){
                        this.Bullet.bulletSize = ParaPr.Bullet.bulletSize.createDuplicate();
                    }
                    if(ParaPr.Bullet.bulletTypeface){
                        this.Bullet.bulletTypeface = ParaPr.Bullet.bulletTypeface.createDuplicate();
                    }
                }
            }
        }

        if(undefined != ParaPr.Lvl)
            this.Lvl = ParaPr.Lvl;

        if(undefined != ParaPr.DefaultTab)
            this.DefaultTab = ParaPr.DefaultTab;

        if (undefined !== ParaPr.OutlineLvl)
        	this.OutlineLvl = ParaPr.OutlineLvl;
    },

    Init_Default : function()
    {
        this.ContextualSpacing         = false;
        this.Ind                       = new CParaInd();
        this.Ind.Left                  = 0;
        this.Ind.Right                 = 0;
        this.Ind.FirstLine             = 0;
        this.Jc                        = align_Left;
        this.KeepLines                 = false;
        this.KeepNext                  = false;
        this.PageBreakBefore           = false;
        this.Spacing                   = new CParaSpacing();
        this.Spacing.Line              = 1.15;
        this.Spacing.LineRule          = linerule_Auto;
        this.Spacing.Before            = 0;
        this.Spacing.BeforeAutoSpacing = false;
        this.Spacing.After             = 10 * g_dKoef_pt_to_mm;
        this.Spacing.AfterAutoSpacing  = false;
        this.Shd                       = new CDocumentShd();
        this.Brd.First                 = true;
        this.Brd.Last                  = true;
        this.Brd.Between               = new CDocumentBorder();
        this.Brd.Bottom                = new CDocumentBorder();
        this.Brd.Left                  = new CDocumentBorder();
        this.Brd.Right                 = new CDocumentBorder();
        this.Brd.Top                   = new CDocumentBorder();
        this.WidowControl              = true;
        this.Tabs                      = new CParaTabs();
        this.NumPr                     = undefined;
        this.PStyle                    = undefined;
        this.FramePr                   = undefined;
        this.OutlineLvl                = undefined;

        this.DefaultRunPr              = undefined;
        this.Bullet                    = undefined;
        this.DefaultTab            = undefined;
    },

    Set_FromObject : function(ParaPr)
    {
        this.ContextualSpacing = ParaPr.ContextualSpacing;

		this.Ind = new CParaInd();
		if (undefined != ParaPr.Ind)
			this.Ind.Set_FromObject(ParaPr.Ind);

        this.Jc              = ParaPr.Jc;
        this.KeepLines       = ParaPr.KeepLines;
        this.KeepNext        = ParaPr.KeepNext;
        this.PageBreakBefore = ParaPr.PageBreakBefore;

		this.Spacing = new CParaSpacing();
		if (undefined != ParaPr.Spacing)
			this.Spacing.Set_FromObject(ParaPr.Spacing);

        if ( undefined != ParaPr.Shd )
        {
            this.Shd = new CDocumentShd();
            this.Shd.Set_FromObject( ParaPr.Shd );
        }
        else
            this.Shd = undefined;

        if ( undefined != ParaPr.Brd )
        {
            if ( undefined != ParaPr.Brd.Between )
            {
                this.Brd.Between = new CDocumentBorder();
                this.Brd.Between.Set_FromObject( ParaPr.Brd.Between );
            }
            else
                this.Brd.Between = undefined;

            if ( undefined != ParaPr.Brd.Bottom )
            {
                this.Brd.Bottom = new CDocumentBorder();
                this.Brd.Bottom.Set_FromObject( ParaPr.Brd.Bottom );
            }
            else
                this.Brd.Bottom = undefined;

            if ( undefined != ParaPr.Brd.Left )
            {
                this.Brd.Left = new CDocumentBorder();
                this.Brd.Left.Set_FromObject( ParaPr.Brd.Left );
            }
            else
                this.Brd.Left = undefined;

            if ( undefined != ParaPr.Brd.Right )
            {
                this.Brd.Right = new CDocumentBorder();
                this.Brd.Right.Set_FromObject( ParaPr.Brd.Right );
            }
            else
                this.Brd.Right = undefined;

            if ( undefined != ParaPr.Brd.Top )
            {
                this.Brd.Top = new CDocumentBorder();
                this.Brd.Top.Set_FromObject( ParaPr.Brd.Top );
            }
            else
                this.Brd.Top = undefined;
        }
        else
        {
            this.Brd.Between = undefined;
            this.Brd.Bottom  = undefined;
            this.Brd.Left    = undefined;
            this.Brd.Right   = undefined;
            this.Brd.Top     = undefined;
        }

        this.WidowControl = ParaPr.WidowControl;

        if ( undefined != ParaPr.Tabs )
        {
            this.Tabs = new CParaTabs();
            this.Tabs.Set_FromObject( ParaPr.Tabs.Tabs );
        }
        else
            this.Tabs = undefined;

        if ( undefined != ParaPr.NumPr )
        {
            this.NumPr = new CNumPr();
            this.NumPr.Set_FromObject( ParaPr.NumPr );
        }
        else
            this.NumPr = undefined;

        if ( undefined != ParaPr.FramePr )
        {
            this.FramePr = new CFramePr();
            this.FramePr.Set_FromObject( ParaPr.FramePr );
        }
        else
            this.FramePr = undefined;

        if( undefined != ParaPr.DefaultRunPr )
        {
            this.DefaultRunPr = new CTextPr();
            this.DefaultRunPr.Set_FromObject(ParaPr.DefaultRunPr);
        }

        if( undefined != ParaPr.Bullet )
        {
            this.Bullet = new AscFormat.CBullet();
            this.Bullet.Set_FromObject(ParaPr.Bullet);
        }

        if(undefined != ParaPr.DefaultTab)
        {
            this.DefaultTab = ParaPr.DefaultTab;
        }

        if (undefined !== ParaPr.OutlineLvl)
        	this.OutlineLvl = ParaPr.OutlineLvl;
    },

    Compare : function(ParaPr)
    {
        // При сравнении добавляем 1 элемент Locked
        var Result_ParaPr = new CParaPr();
        Result_ParaPr.Locked  = false;

        if ( ParaPr.ContextualSpacing === this.ContextualSpacing )
            Result_ParaPr.ContextualSpacing = ParaPr.ContextualSpacing;

        Result_ParaPr.Ind = new CParaInd();
        if ( undefined != ParaPr.Ind && undefined != this.Ind )
        {
            if ( undefined != ParaPr.Ind.Left && undefined != this.Ind.Left && Math.abs( ParaPr.Ind.Left - this.Ind.Left ) < 0.001 )
                Result_ParaPr.Ind.Left = ParaPr.Ind.Left;

            if ( undefined != ParaPr.Ind.Right && undefined != this.Ind.Right && Math.abs( ParaPr.Ind.Right - this.Ind.Right ) < 0.001 )
                Result_ParaPr.Ind.Right = ParaPr.Ind.Right;

            if ( undefined != ParaPr.Ind.FirstLine && undefined != this.Ind.FirstLine && Math.abs( ParaPr.Ind.FirstLine - this.Ind.FirstLine ) < 0.001 )
                Result_ParaPr.Ind.FirstLine = ParaPr.Ind.FirstLine;
        }

        if ( ParaPr.Jc === this.Jc )
            Result_ParaPr.Jc = ParaPr.Jc;

        if ( ParaPr.KeepLines === this.KeepLines )
            Result_ParaPr.KeepLines = ParaPr.KeepLines;

        if ( ParaPr.KeepNext === this.KeepNext )
            Result_ParaPr.KeepNext = ParaPr.KeepNext;

        if ( ParaPr.PageBreakBefore === this.PageBreakBefore )
            Result_ParaPr.PageBreakBefore = ParaPr.PageBreakBefore;

        Result_ParaPr.Spacing = new CParaSpacing();
        if ( undefined != this.Spacing && undefined != ParaPr.Spacing )
        {
            if ( undefined != this.Spacing.After && undefined != ParaPr.Spacing.After && Math.abs( this.Spacing.After - ParaPr.Spacing.After ) < 0.001 )
                Result_ParaPr.Spacing.After = ParaPr.Spacing.After;

            if ( this.Spacing.AfterAutoSpacing === ParaPr.Spacing.AfterAutoSpacing )
                Result_ParaPr.Spacing.AfterAutoSpacing = ParaPr.Spacing.AfterAutoSpacing;

            if ( undefined != this.Spacing.Before && undefined != ParaPr.Spacing.Before && Math.abs( this.Spacing.Before - ParaPr.Spacing.Before ) < 0.001 )
                Result_ParaPr.Spacing.Before = ParaPr.Spacing.Before;

            if ( this.Spacing.BeforeAutoSpacing === ParaPr.Spacing.BeforeAutoSpacing )
                Result_ParaPr.Spacing.BeforeAutoSpacing = ParaPr.Spacing.BeforeAutoSpacing;

            if ( undefined != this.Spacing.Line && undefined != ParaPr.Spacing.Line && Math.abs( this.Spacing.Line - ParaPr.Spacing.Line ) < 0.001 )
                Result_ParaPr.Spacing.Line = ParaPr.Spacing.Line;

            if ( this.Spacing.LineRule === ParaPr.Spacing.LineRule )
                Result_ParaPr.Spacing.LineRule = ParaPr.Spacing.LineRule;
        }

        if ( undefined != this.Shd && undefined != ParaPr.Shd && true === this.Shd.Compare(ParaPr.Shd) )
            Result_ParaPr.Shd = ParaPr.Shd.Copy();

        if ( undefined != this.Brd.Between && undefined != ParaPr.Brd.Between && true === this.Brd.Between.Compare( ParaPr.Brd.Between ) )
            Result_ParaPr.Brd.Between = ParaPr.Brd.Between.Copy();

        if ( undefined != this.Brd.Bottom && undefined != ParaPr.Brd.Bottom && true === this.Brd.Bottom.Compare( ParaPr.Brd.Bottom ) )
            Result_ParaPr.Brd.Bottom = ParaPr.Brd.Bottom.Copy();

        if ( undefined != this.Brd.Left && undefined != ParaPr.Brd.Left && true === this.Brd.Left.Compare( ParaPr.Brd.Left ) )
            Result_ParaPr.Brd.Left = ParaPr.Brd.Left.Copy();

        if ( undefined != this.Brd.Right && undefined != ParaPr.Brd.Right && true === this.Brd.Right.Compare( ParaPr.Brd.Right ) )
            Result_ParaPr.Brd.Right = ParaPr.Brd.Right.Copy();

        if ( undefined != this.Brd.Top && undefined != ParaPr.Brd.Top && true === this.Brd.Top.Compare( ParaPr.Brd.Top ) )
            Result_ParaPr.Brd.Top = ParaPr.Brd.Top.Copy();

        if ( ParaPr.WidowControl === this.WidowControl )
            Result_ParaPr.WidowControl = ParaPr.WidowControl;

        // PStyle
        if ( undefined != this.PStyle && undefined != ParaPr.PStyle && this.PStyle === ParaPr.PStyle )
            Result_ParaPr.PStyle = ParaPr.PStyle;

        // NumPr
        if ( undefined != this.NumPr && undefined != ParaPr.NumPr && this.NumPr.NumId === ParaPr.NumPr.NumId )
        {
            Result_ParaPr.NumPr = new CParaPr();
            Result_ParaPr.NumPr.NumId = ParaPr.NumPr.NumId;
            Result_ParaPr.NumPr.Lvl   = Math.max( this.NumPr.Lvl, ParaPr.NumPr.Lvl );
        }

        // Locked
        if ( undefined != this.Locked && undefined != ParaPr.Locked )
        {
            if ( this.Locked != ParaPr.Locked )
                Result_ParaPr.Locked = true;
            else
                Result_ParaPr.Locked = ParaPr.Locked;
        }

        // FramePr
        if ( undefined != this.FramePr && undefined != ParaPr.FramePr && true === this.FramePr.Compare(ParaPr.FramePr) )
            Result_ParaPr.FramePr = this.FramePr;

        if(undefined != this.Bullet && undefined != ParaPr.Bullet )
            Result_ParaPr.Bullet = AscFormat.CompareBullets(ParaPr.Bullet, this.Bullet);

        if(undefined != this.DefaultRunPr && undefined != ParaPr.DefaultRunPr)
            Result_ParaPr.DefaultRunPr = this.DefaultRunPr.Compare(ParaPr.DefaultRunPr);

        if(undefined != this.Lvl && undefined != ParaPr.Lvl && ParaPr.Lvl === this.Lvl)
            Result_ParaPr.Lvl = this.Lvl;


        if(undefined != this.DefaultTab && undefined != ParaPr.DefaultTab && ParaPr.DefaultTab === this.DefaultTab)
            Result_ParaPr.DefaultTab = this.DefaultTab;

        if (undefined !== this.Tabs && undefined !== ParaPr.Tabs && this.Tabs.Is_Equal(ParaPr.Tabs))
        	Result_ParaPr.Tabs = this.Tabs.Copy();

        if (this.OutlineLvl === ParaPr.OutlineLvl)
        	Result_ParaPr.OutlineLvl = this.OutlineLvl;

        return Result_ParaPr;
    },

    Write_ToBinary : function(Writer)
    {
        var StartPos = Writer.GetCurPosition();
        Writer.Skip(4);
        var Flags = 0;

        if ( undefined != this.ContextualSpacing )
        {
            Writer.WriteBool( this.ContextualSpacing );
            Flags |= 1;
        }

        if ( undefined != this.Ind )
        {
            this.Ind.Write_ToBinary(Writer);
            Flags |= 2;
        }

        if ( undefined != this.Jc )
        {
            Writer.WriteByte( this.Jc );
            Flags |= 4;
        }

        if ( undefined != this.KeepLines )
        {
            Writer.WriteBool( this.KeepLines );
            Flags |= 8;
        }

        if ( undefined != this.KeepNext )
        {
            Writer.WriteBool( this.KeepNext );
            Flags |= 16;
        }

        if ( undefined != this.PageBreakBefore )
        {
            Writer.WriteBool( this.PageBreakBefore );
            Flags |= 32;
        }

        if ( undefined != this.Spacing )
        {
            this.Spacing.Write_ToBinary(Writer);
            Flags |= 64;
        }

        if ( undefined != this.Shd )
        {
            this.Shd.Write_ToBinary(Writer);
            Flags |= 128;
        }

        if ( undefined != this.Brd.Between )
        {
            this.Brd.Between.Write_ToBinary( Writer );
            Flags |= 256;
        }

        if ( undefined != this.Brd.Bottom )
        {
            this.Brd.Bottom.Write_ToBinary( Writer );
            Flags |= 512;
        }

        if ( undefined != this.Brd.Left )
        {
            this.Brd.Left.Write_ToBinary( Writer );
            Flags |= 1024;
        }

        if ( undefined != this.Brd.Right )
        {
            this.Brd.Right.Write_ToBinary( Writer );
            Flags |= 2048;
        }

        if ( undefined != this.Brd.Top )
        {
            this.Brd.Top.Write_ToBinary( Writer );
            Flags |= 4096;
        }

        if ( undefined != this.WidowControl )
        {
            Writer.WriteBool( this.WidowControl );
            Flags |= 8192;
        }

        if ( undefined != this.Tabs )
        {
            this.Tabs.Write_ToBinary( Writer );
            Flags |= 16384;
        }

        if ( undefined != this.NumPr )
        {
            this.NumPr.Write_ToBinary( Writer );
            Flags |= 32768;
        }

        if ( undefined != this.PStyle )
        {
            Writer.WriteString2( this.PStyle );
            Flags |= 65536;
        }

        if ( undefined != this.FramePr )
        {
            this.FramePr.Write_ToBinary( Writer );
            Flags |= 131072;
        }

        if(undefined != this.DefaultRunPr)
        {
            this.DefaultRunPr.Write_ToBinary( Writer );
            Flags |= 262144;
        }

        if(undefined != this.Bullet)
        {
            this.Bullet.Write_ToBinary( Writer );
            Flags |= 524288;
        }

        if(undefined != this.Lvl)
        {
            Writer.WriteByte(this.Lvl);
            Flags |= 1048576;
        }

        if(undefined != this.DefaultTab)
        {
            Writer.WriteDouble(this.DefaultTab);
            Flags |= 2097152;
        }

        if (undefined !== this.OutlineLvl)
		{
			Writer.WriteByte(this.OutlineLvl);
			Flags |= 4194304;
		}

        var EndPos = Writer.GetCurPosition();
        Writer.Seek( StartPos );
        Writer.WriteLong( Flags );
        Writer.Seek( EndPos );
    },

    Read_FromBinary : function(Reader)
    {
        var Flags = Reader.GetLong();

        if ( Flags & 1 )
            this.ContextualSpacing = Reader.GetBool();

        if ( Flags & 2 )
        {
            this.Ind = new CParaInd();
            this.Ind.Read_FromBinary( Reader );
        }

        if ( Flags & 4 )
            this.Jc = Reader.GetByte();

        if ( Flags & 8 )
            this.KeepLines = Reader.GetBool();

        if ( Flags & 16 )
            this.KeepNext = Reader.GetBool();

        if ( Flags & 32 )
            this.PageBreakBefore = Reader.GetBool();

        if ( Flags & 64 )
        {
            this.Spacing = new CParaSpacing();
            this.Spacing.Read_FromBinary( Reader );
        }

        if ( Flags & 128 )
        {
            this.Shd = new CDocumentShd();
            this.Shd.Read_FromBinary( Reader );
        }

        if ( Flags & 256 )
        {
            this.Brd.Between = new CDocumentBorder();
            this.Brd.Between.Read_FromBinary( Reader );
        }

        if ( Flags & 512 )
        {
            this.Brd.Bottom = new CDocumentBorder();
            this.Brd.Bottom.Read_FromBinary( Reader );
        }

        if ( Flags & 1024 )
        {
            this.Brd.Left = new CDocumentBorder();
            this.Brd.Left.Read_FromBinary( Reader );
        }

        if ( Flags & 2048 )
        {
            this.Brd.Right = new CDocumentBorder();
            this.Brd.Right.Read_FromBinary( Reader );
        }

        if ( Flags & 4096 )
        {
            this.Brd.Top = new CDocumentBorder();
            this.Brd.Top.Read_FromBinary( Reader );
        }

        if ( Flags & 8192 )
            this.WidowControl = Reader.GetBool();

        if ( Flags & 16384 )
        {
            this.Tabs = new CParaTabs();
            this.Tabs.Read_FromBinary( Reader );
        }

        if ( Flags & 32768 )
        {
            this.NumPr = new CNumPr();
            this.NumPr.Read_FromBinary( Reader );
        }

        if ( Flags & 65536 )
            this.PStyle = Reader.GetString2();

        if ( Flags & 131072 )
        {
            this.FramePr = new CFramePr();
            this.FramePr.Read_FromBinary( Reader );
        }

        if(Flags & 262144)
        {
            this.DefaultRunPr = new CTextPr();
            this.DefaultRunPr.Read_FromBinary(Reader);
        }

        if(Flags & 524288)
        {
            this.Bullet = new AscFormat.CBullet();
            this.Bullet.Read_FromBinary(Reader);
        }

        if(Flags & 1048576)
        {
            this.Lvl = Reader.GetByte();
        }

        if(Flags & 2097152)
        {
            this.DefaultTab = Reader.GetDouble();
        }

        if (Flags & 4194304)
			this.OutlineLvl = Reader.GetByte();
    },

    isEqual: function(ParaPrUOld,ParaPrNew)
    {
        if(ParaPrUOld == undefined || ParaPrNew == undefined)
            return false;
        for(var pPr in ParaPrUOld)
        {
            if(typeof ParaPrUOld[pPr] == 'object')
            {
                if(!this.isEqual(ParaPrUOld[pPr],ParaPrNew[pPr]))
                    return false
            }
            else
            {
                if(typeof ParaPrUOld[pPr] == "number" && typeof ParaPrNew[pPr] == "number")
                {
                    if(Math.abs(ParaPrUOld[pPr] - ParaPrNew[pPr]) > 0.001)
                        return false;
                }
                else if(ParaPrUOld[pPr] != ParaPrNew[pPr])
                    return false;
            }
        }
        return true;
    },

    Is_Equal : function(ParaPr)
    {
        if (this.ContextualSpacing !== ParaPr.ContextualSpacing
            || true !== IsEqualStyleObjects(this.Ind, ParaPr.Ind)
            || this.Jc !== ParaPr.Jc
            || this.KeepLines !== ParaPr.KeepLines
            || this.KeepNext !== ParaPr.KeepNext
            || this.PageBreakBefore !== ParaPr.PageBreakBefore
            || true !== IsEqualStyleObjects(this.Spacing, ParaPr.Spacing)
            || true !== IsEqualStyleObjects(this.Shd, ParaPr.Shd)
            || true !== IsEqualStyleObjects(this.Brd.Between, ParaPr.Brd.Between)
            || true !== IsEqualStyleObjects(this.Brd.Bottom , ParaPr.Brd.Bottom )
            || true !== IsEqualStyleObjects(this.Brd.Left   , ParaPr.Brd.Left   )
            || true !== IsEqualStyleObjects(this.Brd.Right  , ParaPr.Brd.Right  )
            || true !== IsEqualStyleObjects(this.Brd.Top    , ParaPr.Brd.Top    )
            || this.WidowControl !== ParaPr.WidowControl
            || true !== IsEqualStyleObjects(this.Tabs, ParaPr.Tabs)
            || true !== IsEqualStyleObjects(this.NumPr, ParaPr.NumPr)
            || this.PStyle !== ParaPr.PStyle
            || true !== IsEqualStyleObjects(this.FramePr, ParaPr.FramePr)
			|| this.OutlineLvl !== ParaPr.OutlineLvl)
            return false;

        return true;
    },

    Get_PresentationBullet: function(theme, colorMap)
    {
        var Bullet = new CPresentationBullet();
        if(this.Bullet && this.Bullet.isBullet())
        {
            switch(this.Bullet.bulletType.type)
            {
                case AscFormat.BULLET_TYPE_BULLET_CHAR:
                {
                    Bullet.m_nType = numbering_presentationnumfrmt_Char;
                    if(typeof this.Bullet.bulletType.Char === "string" && this.Bullet.bulletType.Char.length > 0)
                    {
                        Bullet.m_sChar = this.Bullet.bulletType.Char.substring(0, 1);
                    }
                    else
                    {
                        Bullet.m_sChar = "•";
                    }
                    break;
                }

                case AscFormat.BULLET_TYPE_BULLET_AUTONUM :
                {
                    Bullet.m_nType = g_NumberingArr[this.Bullet.bulletType.AutoNumType];
                    Bullet.m_nStartAt = this.Bullet.bulletType.startAt;
                    break;
                }
                case AscFormat.BULLET_TYPE_BULLET_NONE :
                {
                    break;
                }
                case AscFormat.BULLET_TYPE_BULLET_BLIP :
                {
                    Bullet.m_nType = numbering_presentationnumfrmt_Char;
                    Bullet.m_sChar = "•";
                    break;
                }
            }

            if(this.Bullet.bulletColor){
                if(this.Bullet.bulletColor.type === AscFormat.BULLET_TYPE_COLOR_NONE){
                    Bullet.m_bColorTx = false;
                    Bullet.m_oColor.a = 0;
                }
                if(this.Bullet.bulletColor.type === AscFormat.BULLET_TYPE_COLOR_CLR){
                    if(this.Bullet.bulletColor.UniColor && this.Bullet.bulletColor.UniColor.color && theme && colorMap){
                        Bullet.m_bColorTx = false;
                        Bullet.Unifill = AscFormat.CreateUniFillByUniColor(this.Bullet.bulletColor.UniColor);
                    }
                }
            }
            if(this.Bullet.bulletTypeface)
            {
                if(this.Bullet.bulletTypeface.type == AscFormat.BULLET_TYPE_TYPEFACE_BUFONT){
                    Bullet.m_bFontTx = false;
                    Bullet.m_sFont = this.Bullet.bulletTypeface.typeface;
                }

            }
            if(this.Bullet.bulletSize)
            {
                switch (this.Bullet.bulletSize.type){
                    case AscFormat.BULLET_TYPE_SIZE_TX:{
                        Bullet.m_bSizeTx = true;
                        break;
                    }
                    case AscFormat.BULLET_TYPE_SIZE_PCT:{
                        Bullet.m_bSizeTx = false;
                        Bullet.m_bSizePct = true;
                        Bullet.m_dSize = this.Bullet.bulletSize.val/100000.0;
                        break;
                    }
                    case AscFormat.BULLET_TYPE_SIZE_PTS:{
                        Bullet.m_bSizeTx = false;
                        Bullet.m_bSizePct = false;
                        Bullet.m_dSize = this.Bullet.bulletSize.val/100.0;
                        break;
                    }
                }
            }
        }
        return Bullet;
    },

    Have_PrChange : function()
    {
        if (undefined === this.PrChange || null === this.PrChange)
            return false;

        return true;
    },

    Add_PrChange : function()
    {
        this.PrChange = this.Copy();
        this.ReviewInfo = new CReviewInfo();
        this.ReviewInfo.Update();
    },

    Set_PrChange : function(PrChange, ReviewInfo)
    {
        this.PrChange   = PrChange;
        this.ReviewInfo = ReviewInfo;
    },

    Remove_PrChange : function()
    {
        delete this.PrChange;
        delete this.ReviewInfo;
    }
};
CParaPr.prototype.Is_Empty         = function()
{
	if (undefined !== this.ContextualSpacing
		|| true !== this.Ind.Is_Empty()
		|| undefined !== this.Jc
		|| undefined !== this.KeepLines
		|| undefined !== this.KeepNext
		|| undefined !== this.PageBreakBefore
		|| true !== this.Spacing.Is_Empty()
		|| undefined !== this.Shd
		|| undefined !== this.Brd.First
		|| undefined !== this.Brd.Last
		|| undefined !== this.Brd.Between
		|| undefined !== this.Brd.Bottom
		|| undefined !== this.Brd.Left
		|| undefined !== this.Brd.Right
		|| undefined !== this.Brd.Top
		|| undefined !== this.WidowControl
		|| undefined !== this.Tabs
		|| undefined !== this.NumPr
		|| undefined !== this.PStyle)
		return false;

	return true;
};
CParaPr.prototype.Get_DiffPrChange = function()
{
    var ParaPr = new CParaPr();

    if (false === this.Have_PrChange())
        return ParaPr;

    var PrChange = this.PrChange;

    if (this.ContextualSpacing !== PrChange.ContextualSpacing)
        ParaPr.ContextualSpacing = this.ContextualSpacing;

    ParaPr.Ind = this.Ind.Get_Diff(PrChange.Ind);

    if (this.Jc !== PrChange.Jc)
        ParaPr.Jc = this.Jc;

    if (this.KeepLines !== PrChange.KeepLines)
        ParaPr.KeepLines = this.KeepLines;

    if (this.KeepNext !== PrChange.KeepNext)
        ParaPr.KeepNext = this.KeepNext;

    if (this.PageBreakBefore !== PrChange.PageBreakBefore)
        ParaPr.PageBreakBefore = this.PageBreakBefore;

    ParaPr.Spacing = this.Spacing.Get_Diff(PrChange.Spacing);

    // TODO: Shd
    // TODO: Brd

    if (this.WidowControl !== PrChange.WidowControl)
        ParaPr.WidowControl = this.WidowControl;

    if (this.Tabs !== PrChange.Tabs)
        ParaPr.Tabs = this.Tabs;

    if (this.NumPr !== PrChange.NumPr)
        ParaPr.NumPr = this.NumPr;

    if (this.PStyle !== PrChange.PStyle)
        ParaPr.PStyle = this.PStyle;

    return ParaPr;
};
CParaPr.prototype.GetContextualSpacing = function()
{
    return this.ContextualSpacing;
};
CParaPr.prototype.SetContextualSpacing = function(isContextualSpacing)
{
	this.ContextualSpacing = isContextualSpacing;
};
CParaPr.prototype.GetIndLeft = function()
{
    return this.Ind.Left;
};
CParaPr.prototype.GetIndRight = function()
{
    return this.Ind.Right;
};
CParaPr.prototype.GetIndFirstLine = function()
{
    return this.Ind.FirstLine;
};
CParaPr.prototype.SetInd = function(nFirst, nLeft, nRight)
{
	if (undefined !== nFirst)
		this.Ind.FirstLine = nFirst;

	if (undefined !== nLeft)
		this.Ind.Left = nLeft;

	if (undefined !== nRight)
		this.Ind.Right = nRight;
};
CParaPr.prototype.GetJc = function()
{
    return this.Jc;
};
CParaPr.prototype.SetJc = function(nAlign)
{
	this.Jc = nAlign;
};
CParaPr.prototype.GetKeepLines = function()
{
    return this.KeepLines;
};
CParaPr.prototype.SetKeepLines = function(isKeepLines)
{
	this.KeepLines = isKeepLines;
};
CParaPr.prototype.GetKeepNext = function()
{
    return this.KeepNext;
};
CParaPr.prototype.SetKeepNext = function(isKeepNext)
{
	this.KeepNext = isKeepNext;
};
CParaPr.prototype.GetPageBreakBefore = function()
{
    return this.PageBreakBefore;
};
CParaPr.prototype.SetPageBreakBefore = function(isPageBreakBefore)
{
	this.PageBreakBefore = isPageBreakBefore;
};
CParaPr.prototype.GetSpacingLine = function()
{
    return this.Spacing.Line;
};
CParaPr.prototype.GetSpacingLineRule = function()
{
    return this.Spacing.LineRule;
};
CParaPr.prototype.GetSpacingBefore = function()
{
    return this.Spacing.Before;
};
CParaPr.prototype.GetSpacingBeforeAutoSpacing = function()
{
    return this.Spacing.BeforeAutoSpacing;
};
CParaPr.prototype.GetSpacingAfter = function()
{
    return this.Spacing.After;
};
CParaPr.prototype.GetSpacingAfterAutoSpacing = function()
{
    return this.Spacing.AfterAutoSpacing;
};
CParaPr.prototype.SetSpacing = function(nLine, nLineRule, nBefore, nAfter, isBeforeAuto, isAfterAuto)
{
	if (undefined !== nLine)
		this.Spacing.Line = nLine;

	if (undefined !== nLineRule)
		this.Spacing.LineRule = nLineRule;

	if (undefined !== nBefore)
		this.Spacing.Before = nBefore;

	if (undefined !== nAfter)
		this.Spacing.After = nAfter;

	if (undefined !== isBeforeAuto)
		this.Spacing.BeforeAutoSpacing = isBeforeAuto;

	if (undefined !== isAfterAuto)
		this.Spacing.AfterAutoSpacing = isAfterAuto;
};
CParaPr.prototype.GetWidowControl = function()
{
    return this.WidowControl;
};
CParaPr.prototype.SetWidowControl = function(isWidowControl)
{
	this.WidowControl = isWidowControl;
};
CParaPr.prototype.GetTabs = function()
{
    return this.Tabs;
};
CParaPr.prototype.GetNumPr = function()
{
    return this.NumPr;
};
CParaPr.prototype.SetNumPr = function(sNumId, nLvl)
{
	if (undefined === sNumId)
		this.NumPr = undefined;
	else
		this.NumPr = new CNumPr(sNumId, nLvl);
};
CParaPr.prototype.GetPStyle = function()
{
    return this.PStyle;
};
CParaPr.prototype.SetPStyle = function(sPStyle)
{
	this.PStyle = sPStyle;
};
CParaPr.prototype.GetOutlineLvl = function()
{
	return this.OutlineLvl;
};
CParaPr.prototype.SetOutlineLvl = function(nOutlineLvl)
{
	this.OutlineLvl = nOutlineLvl;
};
CParaPr.prototype.WriteToBinary = function(oWriter)
{
	return this.Write_ToBinary(oWriter);
};
CParaPr.prototype.ReadFromBinary = function(oReader)
{
	return this.Read_FromBinary(oReader);
};
//----------------------------------------------------------------------------------------------------------------------
// CParaPr Export
//----------------------------------------------------------------------------------------------------------------------
CParaPr.prototype['get_ContextualSpacing']        = CParaPr.prototype.get_ContextualSpacing        = CParaPr.prototype['Get_ContextualSpacing']        = CParaPr.prototype.GetContextualSpacing;
CParaPr.prototype['put_ContextualSpacing']        = CParaPr.prototype.put_ContextualSpacing        = CParaPr.prototype.SetContextualSpacing;
CParaPr.prototype['get_IndLeft']                  = CParaPr.prototype.get_IndLeft                  = CParaPr.prototype['Get_IndLeft']                  = CParaPr.prototype.GetIndLeft;
CParaPr.prototype['get_IndRight']                 = CParaPr.prototype.get_IndRight                 = CParaPr.prototype['Get_IndRight']                 = CParaPr.prototype.GetIndRight;
CParaPr.prototype['get_IndFirstLine']             = CParaPr.prototype.get_IndFirstLine             = CParaPr.prototype['Get_IndFirstLine']             = CParaPr.prototype.GetIndFirstLine;
CParaPr.prototype['put_Ind']                      = CParaPr.prototype.put_Ind                      = CParaPr.prototype.SetInd;
CParaPr.prototype['get_Jc']                       = CParaPr.prototype.get_Jc                       = CParaPr.prototype['Get_Jc']                       = CParaPr.prototype.GetJc;
CParaPr.prototype['put_Jc']                       = CParaPr.prototype.put_Jc                       = CParaPr.prototype.SetJc;
CParaPr.prototype['get_KeepLines']                = CParaPr.prototype.get_KeepLines                = CParaPr.prototype['Get_KeepLines']                = CParaPr.prototype.GetKeepLines;
CParaPr.prototype['put_KeepLines']                = CParaPr.prototype.put_KeepLines                = CParaPr.prototype.SetKeepLines;
CParaPr.prototype['get_KeepNext']                 = CParaPr.prototype.get_KeepNext                 = CParaPr.prototype['Get_KeepNext']                 = CParaPr.prototype.GetKeepNext;
CParaPr.prototype['put_KeepNext']                 = CParaPr.prototype.put_KeepNext                 = CParaPr.prototype.SetKeepNext;
CParaPr.prototype['get_PageBreakBefore']          = CParaPr.prototype.get_PageBreakBefore          = CParaPr.prototype['Get_PageBreakBefore']          = CParaPr.prototype.GetPageBreakBefore;
CParaPr.prototype['put_PageBreakBefore']          = CParaPr.prototype.put_PageBreakBefore          = CParaPr.prototype.SetPageBreakBefore;
CParaPr.prototype['get_SpacingLine']              = CParaPr.prototype.get_SpacingLine              = CParaPr.prototype['Get_SpacingLine']              = CParaPr.prototype.GetSpacingLine;
CParaPr.prototype['get_SpacingLineRule']          = CParaPr.prototype.get_SpacingLineRule          = CParaPr.prototype['Get_SpacingLineRule']          = CParaPr.prototype.GetSpacingLineRule;
CParaPr.prototype['get_SpacingBefore']            = CParaPr.prototype.get_SpacingBefore            = CParaPr.prototype['Get_SpacingBefore']            = CParaPr.prototype.GetSpacingBefore;
CParaPr.prototype['get_SpacingBeforeAutoSpacing'] = CParaPr.prototype.get_SpacingBeforeAutoSpacing = CParaPr.prototype['Get_SpacingBeforeAutoSpacing'] = CParaPr.prototype.GetSpacingBeforeAutoSpacing;
CParaPr.prototype['get_SpacingAfter']             = CParaPr.prototype.get_SpacingAfter             = CParaPr.prototype['Get_SpacingAfter']             = CParaPr.prototype.GetSpacingAfter;
CParaPr.prototype['get_SpacingAfterAutoSpacing']  = CParaPr.prototype.get_SpacingAfterAutoSpacing  = CParaPr.prototype['Get_SpacingAfterAutoSpacing']  = CParaPr.prototype.GetSpacingAfterAutoSpacing;
CParaPr.prototype['put_Spacing']                  = CParaPr.prototype.put_Spacing                  = CParaPr.prototype.SetSpacing;
CParaPr.prototype['get_WidowControl']             = CParaPr.prototype.get_WidowControl             = CParaPr.prototype['Get_WidowControl']             = CParaPr.prototype.GetWidowControl;
CParaPr.prototype['put_WidowControl']             = CParaPr.prototype.put_WidowControl             = CParaPr.prototype.SetWidowControl;
CParaPr.prototype['get_Tabs']                     = CParaPr.prototype.get_Tabs                     = CParaPr.prototype['Get_Tabs']                     = CParaPr.prototype.GetTabs;
CParaPr.prototype['get_NumPr']                    = CParaPr.prototype.get_NumPr                    = CParaPr.prototype['Get_NumPr']                    = CParaPr.prototype.GetNumPr;
CParaPr.prototype['put_NumPr']                    = CParaPr.prototype.put_NumPr                    = CParaPr.prototype.SetNumPr;
CParaPr.prototype['get_PStyle']                   = CParaPr.prototype.get_PStyle                   = CParaPr.prototype['Get_PStyle']                   = CParaPr.prototype.GetPStyle;
CParaPr.prototype['put_PStyle']                   = CParaPr.prototype.put_PStyle                   = CParaPr.prototype.SetPStyle;
CParaPr.prototype['get_OutlineLvl']               = CParaPr.prototype.get_OutlineLvl               = CParaPr.prototype['Get_OutlineLvl']               = CParaPr.prototype.GetOutlineLvl;
CParaPr.prototype['put_OutlineLvl']               = CParaPr.prototype.put_OutlineLvl               = CParaPr.prototype.SetOutlineLvl;
//----------------------------------------------------------------------------------------------------------------------

function Copy_Bounds(Bounds)
{
    if ( undefined === Bounds )
        return {};
    var Bounds_new = {};
    Bounds_new.Bottom = Bounds.Bottom;
    Bounds_new.Left   = Bounds.Left;
    Bounds_new.Right  = Bounds.Right;
    Bounds_new.Top    = Bounds.Top;
    return Bounds_new;
}

function asc_CStyle()
{
    this.Name    = "";

    this.BasedOn = "";
    this.Next    = "";
    this.Link    = "";
    this.Type    = styletype_Paragraph;

    this.TextPr = new CTextPr();
    this.ParaPr = new CParaPr();
}
asc_CStyle.prototype.get_Name = function()
{
    return this.Name;
};
asc_CStyle.prototype.put_Name = function(sName)
{
    this.Name = sName;
};
asc_CStyle.prototype.put_BasedOn = function(Name)
{
    this.BasedOn = Name;
};
asc_CStyle.prototype.get_BasedOn = function()
{
    return this.BasedOn;
};
asc_CStyle.prototype.put_Next = function(Name)
{
    this.Next = Name;
};
asc_CStyle.prototype.get_Next = function()
{
    return this.Next;
};
asc_CStyle.prototype.put_Type = function(Type)
{
    this.Type = Type;
};
asc_CStyle.prototype.get_Type = function()
{
    return this.Type;
};
asc_CStyle.prototype.put_Link = function(LinkStyle)
{
    this.Link = LinkStyle;
};
asc_CStyle.prototype.get_Link = function()
{
    return this.Link;
};
asc_CStyle.prototype.fill_ParaPr = function(oPr)
{
    this.ParaPr = oPr.Copy();
};
asc_CStyle.prototype.get_ParaPr = function()
{
    return this.ParaPr;
};
asc_CStyle.prototype.fill_TextPr = function(oPr)
{
    this.TextPr = oPr.Copy();
};
asc_CStyle.prototype.get_TextPr = function()
{
    return this.TextPr;
};

//---------------------------------------------------------export---------------------------------------------------
window['Asc'] = window['Asc'] || {};
window['AscCommonWord'] = window['AscCommonWord'] || {};
window["Asc"]["asc_CStyle"] = window["Asc"].asc_CStyle = asc_CStyle;
asc_CStyle.prototype["get_Name"]    = asc_CStyle.prototype.get_Name;
asc_CStyle.prototype["put_Name"]    = asc_CStyle.prototype.put_Name;
asc_CStyle.prototype["get_BasedOn"] = asc_CStyle.prototype.get_BasedOn;
asc_CStyle.prototype["put_BasedOn"] = asc_CStyle.prototype.put_BasedOn;
asc_CStyle.prototype["get_Next"]    = asc_CStyle.prototype.get_Next;
asc_CStyle.prototype["put_Next"]    = asc_CStyle.prototype.put_Next;
asc_CStyle.prototype["get_Type"]    = asc_CStyle.prototype.get_Type;
asc_CStyle.prototype["put_Type"]    = asc_CStyle.prototype.put_Type;
asc_CStyle.prototype["get_Link"]    = asc_CStyle.prototype.get_Link;
asc_CStyle.prototype["put_Link"]    = asc_CStyle.prototype.put_Link;

window["AscCommonWord"].CDocumentColor = CDocumentColor;
window["AscCommonWord"].CStyle = CStyle;
window["AscCommonWord"].CTextPr = CTextPr;
window["AscCommonWord"].CParaPr = CParaPr;
window["AscCommonWord"].CParaTabs = CParaTabs;
window["AscCommonWord"].g_dKoef_pt_to_mm = g_dKoef_pt_to_mm;
window["AscCommonWord"].border_Single = border_Single;
window["AscCommonWord"].Default_Tab_Stop = Default_Tab_Stop;
window["AscCommonWord"].highlight_None = highlight_None;
window["AscCommonWord"].spacing_Auto = spacing_Auto;
window["AscCommonWord"].wrap_NotBeside = wrap_NotBeside;
window["AscCommonWord"].wrap_Around = wrap_Around;

// Создаем глобальные дефолтовые стили, чтобы быстро можно было отдать дефолтовые настройки
var g_oDocumentDefaultTextPr = new CTextPr();
var g_oDocumentDefaultParaPr = new CParaPr();
var g_oDocumentDefaultTablePr = new CTablePr();
var g_oDocumentDefaultTableCellPr = new CTableCellPr();
var g_oDocumentDefaultTableRowPr = new CTableRowPr();
var g_oDocumentDefaultTableStylePr = new CTableStylePr();
g_oDocumentDefaultTextPr.Init_Default();
g_oDocumentDefaultParaPr.Init_Default();
g_oDocumentDefaultTablePr.Init_Default();
g_oDocumentDefaultTableCellPr.Init_Default();
g_oDocumentDefaultTableRowPr.Init_Default();
g_oDocumentDefaultTableStylePr.Init_Default();

// ----------------------------------------------------------------

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 08.11.2016
 * Time: 19:48
 */

AscDFH.changesFactory[AscDFH.historyitem_Style_TextPr]          = CChangesStyleTextPr;
AscDFH.changesFactory[AscDFH.historyitem_Style_ParaPr]          = CChangesStyleParaPr;
AscDFH.changesFactory[AscDFH.historyitem_Style_TablePr]         = CChangesStyleTablePr;
AscDFH.changesFactory[AscDFH.historyitem_Style_TableRowPr]      = CChangesStyleTableRowPr;
AscDFH.changesFactory[AscDFH.historyitem_Style_TableCellPr]     = CChangesStyleTableCellPr;
AscDFH.changesFactory[AscDFH.historyitem_Style_TableBand1Horz]  = CChangesStyleTableBand1Horz;
AscDFH.changesFactory[AscDFH.historyitem_Style_TableBand1Vert]  = CChangesStyleTableBand1Vert;
AscDFH.changesFactory[AscDFH.historyitem_Style_TableBand2Horz]  = CChangesStyleTableBand2Horz;
AscDFH.changesFactory[AscDFH.historyitem_Style_TableBand2Vert]  = CChangesStyleTableBand2Vert;
AscDFH.changesFactory[AscDFH.historyitem_Style_TableFirstCol]   = CChangesStyleTableFirstCol;
AscDFH.changesFactory[AscDFH.historyitem_Style_TableFirstRow]   = CChangesStyleTableFirstRow;
AscDFH.changesFactory[AscDFH.historyitem_Style_TableLastCol]    = CChangesStyleTableLastCol;
AscDFH.changesFactory[AscDFH.historyitem_Style_TableLastRow]    = CChangesStyleTableLastRow;
AscDFH.changesFactory[AscDFH.historyitem_Style_TableTLCell]     = CChangesStyleTableTLCell;
AscDFH.changesFactory[AscDFH.historyitem_Style_TableTRCell]     = CChangesStyleTableTRCell;
AscDFH.changesFactory[AscDFH.historyitem_Style_TableBLCell]     = CChangesStyleTableBLCell;
AscDFH.changesFactory[AscDFH.historyitem_Style_TableBRCell]     = CChangesStyleTableBRCell;
AscDFH.changesFactory[AscDFH.historyitem_Style_TableWholeTable] = CChangesStyleTableWholeTable;
AscDFH.changesFactory[AscDFH.historyitem_Style_Name]            = CChangesStyleName;
AscDFH.changesFactory[AscDFH.historyitem_Style_BasedOn]         = CChangesStyleBasedOn;
AscDFH.changesFactory[AscDFH.historyitem_Style_Next]            = CChangesStyleNext;
AscDFH.changesFactory[AscDFH.historyitem_Style_Type]            = CChangesStyleType;
AscDFH.changesFactory[AscDFH.historyitem_Style_QFormat]         = CChangesStyleQFormat;
AscDFH.changesFactory[AscDFH.historyitem_Style_UiPriority]      = CChangesStyleUiPriority;
AscDFH.changesFactory[AscDFH.historyitem_Style_Hidden]          = CChangesStyleHidden;
AscDFH.changesFactory[AscDFH.historyitem_Style_SemiHidden]      = CChangesStyleSemiHidden;
AscDFH.changesFactory[AscDFH.historyitem_Style_UnhideWhenUsed]  = CChangesStyleUnhideWhenUsed;
AscDFH.changesFactory[AscDFH.historyitem_Style_Link]            = CChangesStyleLink;
AscDFH.changesFactory[AscDFH.historyitem_Style_Custom]          = CChangesStyleCustom;

AscDFH.changesFactory[AscDFH.historyitem_Styles_Add]                              = CChangesStylesAdd;
AscDFH.changesFactory[AscDFH.historyitem_Styles_Remove]                           = CChangesStylesRemove;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultTextPr]              = CChangesStylesChangeDefaultTextPr;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultParaPr]              = CChangesStylesChangeDefaultParaPr;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultParagraphId]         = CChangesStylesChangeDefaultParagraphId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultCharacterId]         = CChangesStylesChangeDefaultCharacterId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultNumberingId]         = CChangesStylesChangeDefaultNumberingId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultTableId]             = CChangesStylesChangeDefaultTableId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultTableGridId]         = CChangesStylesChangeDefaultTableGridId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultHeadingsId]          = CChangesStylesChangeDefaultHeadingsId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultParaListId]          = CChangesStylesChangeDefaultParaListId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultHeaderId]            = CChangesStylesChangeDefaultHeaderId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultFooterId]            = CChangesStylesChangeDefaultFooterId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultHyperlinkId]         = CChangesStylesChangeDefaultHyperlinkId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultFootnoteTextId]      = CChangesStylesChangeDefaultFootnoteTextId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultFootnoteTextCharId]  = CChangesStylesChangeDefaultFootnoteTextCharId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultFootnoteReferenceId] = CChangesStylesChangeDefaultFootnoteReferenceId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultNoSpacingId]         = CChangesStylesChangeDefaultNoSpacingId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultTitleId]             = CChangesStylesChangeDefaultTitleId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultSubtitleId]          = CChangesStylesChangeDefaultSubtitleId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultQuoteId]             = CChangesStylesChangeDefaultQuoteId;
AscDFH.changesFactory[AscDFH.historyitem_Styles_ChangeDefaultIntenseQuoteId]      = CChangesStylesChangeDefaultIntenseQuoteId;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TextPr]          = [AscDFH.historyitem_Style_TextPr];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_ParaPr]          = [AscDFH.historyitem_Style_ParaPr];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TablePr]         = [AscDFH.historyitem_Style_TablePr];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TableRowPr]      = [AscDFH.historyitem_Style_TableRowPr];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TableCellPr]     = [AscDFH.historyitem_Style_TableCellPr];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TableBand1Horz]  = [AscDFH.historyitem_Style_TableBand1Horz];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TableBand1Vert]  = [AscDFH.historyitem_Style_TableBand1Vert];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TableBand2Horz]  = [AscDFH.historyitem_Style_TableBand2Horz];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TableBand2Vert]  = [AscDFH.historyitem_Style_TableBand2Vert];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TableFirstCol]   = [AscDFH.historyitem_Style_TableFirstCol];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TableFirstRow]   = [AscDFH.historyitem_Style_TableFirstRow];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TableLastCol]    = [AscDFH.historyitem_Style_TableLastCol];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TableLastRow]    = [AscDFH.historyitem_Style_TableLastRow];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TableTLCell]     = [AscDFH.historyitem_Style_TableTLCell];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TableTRCell]     = [AscDFH.historyitem_Style_TableTRCell];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TableBLCell]     = [AscDFH.historyitem_Style_TableBLCell];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TableBRCell]     = [AscDFH.historyitem_Style_TableBRCell];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_TableWholeTable] = [AscDFH.historyitem_Style_TableWholeTable];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_Name]            = [AscDFH.historyitem_Style_Name];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_BasedOn]         = [AscDFH.historyitem_Style_BasedOn];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_Next]            = [AscDFH.historyitem_Style_Next];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_Type]            = [AscDFH.historyitem_Style_Type];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_QFormat]         = [AscDFH.historyitem_Style_QFormat];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_UiPriority]      = [AscDFH.historyitem_Style_UiPriority];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_Hidden]          = [AscDFH.historyitem_Style_Hidden];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_SemiHidden]      = [AscDFH.historyitem_Style_SemiHidden];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_UnhideWhenUsed]  = [AscDFH.historyitem_Style_UnhideWhenUsed];
AscDFH.changesRelationMap[AscDFH.historyitem_Style_Link]            = [AscDFH.historyitem_Style_Link];

AscDFH.changesRelationMap[AscDFH.historyitem_Styles_Add]                 = [
	AscDFH.historyitem_Styles_Add,
	AscDFH.historyitem_Styles_Remove
];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_Remove]              = [
	AscDFH.historyitem_Styles_Add,
	AscDFH.historyitem_Styles_Remove
];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultTextPr]              = [AscDFH.historyitem_Styles_ChangeDefaultTextPr];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultParaPr]              = [AscDFH.historyitem_Styles_ChangeDefaultParaPr];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultParagraphId]         = [AscDFH.historyitem_Styles_ChangeDefaultParagraphId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultCharacterId]         = [AscDFH.historyitem_Styles_ChangeDefaultCharacterId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultNumberingId]         = [AscDFH.historyitem_Styles_ChangeDefaultNumberingId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultTableId]             = [AscDFH.historyitem_Styles_ChangeDefaultTableId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultTableGridId]         = [AscDFH.historyitem_Styles_ChangeDefaultTableGridId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultHeadingsId]          = [AscDFH.historyitem_Styles_ChangeDefaultHeadingsId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultParaListId]          = [AscDFH.historyitem_Styles_ChangeDefaultParaListId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultHeaderId]            = [AscDFH.historyitem_Styles_ChangeDefaultHeaderId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultFooterId]            = [AscDFH.historyitem_Styles_ChangeDefaultFooterId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultHyperlinkId]         = [AscDFH.historyitem_Styles_ChangeDefaultHyperlinkId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultFootnoteTextId]      = [AscDFH.historyitem_Styles_ChangeDefaultFootnoteTextId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultFootnoteTextCharId]  = [AscDFH.historyitem_Styles_ChangeDefaultFootnoteTextCharId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultFootnoteReferenceId] = [AscDFH.historyitem_Styles_ChangeDefaultFootnoteReferenceId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultNoSpacingId]         = [AscDFH.historyitem_Styles_ChangeDefaultNoSpacingId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultTitleId]             = [AscDFH.historyitem_Styles_ChangeDefaultTitleId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultSubtitleId]          = [AscDFH.historyitem_Styles_ChangeDefaultSubtitleId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultQuoteId]             = [AscDFH.historyitem_Styles_ChangeDefaultQuoteId];
AscDFH.changesRelationMap[AscDFH.historyitem_Styles_ChangeDefaultIntenseQuoteId]      = [AscDFH.historyitem_Styles_ChangeDefaultIntenseQuoteId];
//----------------------------------------------------------------------------------------------------------------------


/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectValue}
 */
function CChangesStyleBaseObjectProperty(Class, Old, New)
{
	AscDFH.CChangesBaseObjectValue.call(this, Class, Old, New);
}
CChangesStyleBaseObjectProperty.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleBaseObjectProperty.prototype.constructor = CChangesStyleBaseObjectProperty;
CChangesStyleBaseObjectProperty.prototype.Load = function()
{
	this.Redo();
	AscCommon.CollaborativeEditing.Add_LinkData(this.Class, {StyleUpdate : true});
};
/**
 * Базовый класс для строковых параметров у стиля.
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesStyleBaseStringProperty(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesStyleBaseStringProperty.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesStyleBaseStringProperty.prototype.constructor = CChangesStyleBaseStringProperty;
CChangesStyleBaseStringProperty.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Is undefined new
	// 2-bit : Is null new
	// 3-bit : Is undefined old
	// 4-bit : Is null old
	// String : New (1,2 - bits are zero)
	// String : Old (3,4 - bits are zero)

	var nFlags = 0;

	if (undefined === this.New)
		nFlags |= 1;
	else if (null === this.New)
		nFlags |= 2;

	if (undefined === this.Old)
		nFlags |= 4;
	else if (null === this.Old)
		nFlags |= 8;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New && null !== this.New)
		Writer.WriteString2(this.New);

	if (undefined !== this.Old && null !== this.Old)
		Writer.WriteString2(this.Old);
};
CChangesStyleBaseStringProperty.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Is undefined new
	// 2-bit : Is null new
	// 3-bit : Is undefined old
	// 4-bit : Is null old
	// String : New (1,2 - bits are zero)
	// String : Old (3,4 - bits are zero)

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.New = undefined;
	else if (nFlags & 2)
		this.New = null;
	else
		this.New = Reader.GetString2();

	if (nFlags & 4)
		this.Old = undefined;
	else if (nFlags & 8)
		this.Old = null;
	else
		this.Old = Reader.GetString2();
};
CChangesStyleBaseStringProperty.prototype.Load = function()
{
	this.Redo();
	AscCommon.CollaborativeEditing.Add_LinkData(this.Class, {StyleUpdate : true});
};
/**
 * Базовый класс для строковых параметров у стиля.
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesStyleBaseBoolProperty(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesStyleBaseBoolProperty.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesStyleBaseBoolProperty.prototype.constructor = CChangesStyleBaseBoolProperty;
CChangesStyleBaseBoolProperty.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Is undefined new
	// 2-bit : Is null new
	// 3-bit : Is undefined old
	// 4-bit : Is null old
	// Bool : New (1,2 - bits are zero)
	// Bool : Old (3,4 - bits are zero)

	var nFlags = 0;

	if (undefined === this.New)
		nFlags |= 1;
	else if (null === this.New)
		nFlags |= 2;

	if (undefined === this.Old)
		nFlags |= 4;
	else if (null === this.Old)
		nFlags |= 8;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New && null !== this.New)
		Writer.WriteBool(this.New);

	if (undefined !== this.Old && null !== this.Old)
		Writer.WriteBool(this.Old);
};
CChangesStyleBaseBoolProperty.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Is undefined new
	// 2-bit : Is null new
	// 3-bit : Is undefined old
	// 4-bit : Is null old
	// Bool : New (1,2 - bits are zero)
	// Bool : Old (3,4 - bits are zero)

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.New = undefined;
	else if (nFlags & 2)
		this.New = null;
	else
		this.New = Reader.GetBool();

	if (nFlags & 4)
		this.Old = undefined;
	else if (nFlags & 8)
		this.Old = null;
	else
		this.Old = Reader.GetBool();
};
CChangesStyleBaseBoolProperty.prototype.Load = function()
{
	this.Redo();
	AscCommon.CollaborativeEditing.Add_LinkData(this.Class, {StyleUpdate : true});
};
/**
 * Базовый класс для строковых параметров у стиля.
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesStyleBaseLongProperty(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesStyleBaseLongProperty.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesStyleBaseLongProperty.prototype.constructor = CChangesStyleBaseLongProperty;
CChangesStyleBaseLongProperty.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Is undefined new
	// 2-bit : Is null new
	// 3-bit : Is undefined old
	// 4-bit : Is null old
	// Long : New (1,2 - bits are zero)
	// Long : Old (3,4 - bits are zero)

	var nFlags = 0;

	if (undefined === this.New)
		nFlags |= 1;
	else if (null === this.New)
		nFlags |= 2;

	if (undefined === this.Old)
		nFlags |= 4;
	else if (null === this.Old)
		nFlags |= 8;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New && null !== this.New)
		Writer.WriteLong(this.New);

	if (undefined !== this.Old && null !== this.Old)
		Writer.WriteLong(this.Old);
};
CChangesStyleBaseLongProperty.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Is undefined new
	// 2-bit : Is null new
	// 3-bit : Is undefined old
	// 4-bit : Is null old
	// Long : New (1,2 - bits are zero)
	// Long : Old (3,4 - bits are zero)

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.New = undefined;
	else if (nFlags & 2)
		this.New = null;
	else
		this.New = Reader.GetLong();

	if (nFlags & 4)
		this.Old = undefined;
	else if (nFlags & 8)
		this.Old = null;
	else
		this.Old = Reader.GetLong();
};
CChangesStyleBaseLongProperty.prototype.Load = function()
{
	this.Redo();
	AscCommon.CollaborativeEditing.Add_LinkData(this.Class, {StyleUpdate : true});
};


/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTextPr(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTextPr.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTextPr.prototype.constructor = CChangesStyleTextPr;
CChangesStyleTextPr.prototype.Type = AscDFH.historyitem_Style_TextPr;
CChangesStyleTextPr.prototype.private_CreateObject = function()
{
	return new CTextPr();
};
CChangesStyleTextPr.prototype.private_SetValue = function(Value)
{
	this.Class.TextPr = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleParaPr(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleParaPr.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleParaPr.prototype.constructor = CChangesStyleParaPr;
CChangesStyleParaPr.prototype.Type = AscDFH.historyitem_Style_ParaPr;
CChangesStyleParaPr.prototype.private_CreateObject = function()
{
	return new CParaPr();
};
CChangesStyleParaPr.prototype.private_SetValue = function(Value)
{
	this.Class.ParaPr = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTablePr(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTablePr.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTablePr.prototype.constructor = CChangesStyleTablePr;
CChangesStyleTablePr.prototype.Type = AscDFH.historyitem_Style_TablePr;
CChangesStyleTablePr.prototype.private_CreateObject = function()
{
	return new CTablePr();
};
CChangesStyleTablePr.prototype.private_SetValue = function(Value)
{
	this.Class.TablePr = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTableRowPr(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTableRowPr.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTableRowPr.prototype.constructor = CChangesStyleTableRowPr;
CChangesStyleTableRowPr.prototype.Type = AscDFH.historyitem_Style_TableRowPr;
CChangesStyleTableRowPr.prototype.private_CreateObject = function()
{
	return new CTableRowPr();
};
CChangesStyleTableRowPr.prototype.private_SetValue = function(Value)
{
	this.Class.TableRowPr = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTableCellPr(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTableCellPr.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTableCellPr.prototype.constructor = CChangesStyleTableCellPr;
CChangesStyleTableCellPr.prototype.Type = AscDFH.historyitem_Style_TableCellPr;
CChangesStyleTableCellPr.prototype.private_CreateObject = function()
{
	return new CTableCellPr();
};
CChangesStyleTableCellPr.prototype.private_SetValue = function(Value)
{
	this.Class.TableCellPr = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTableBand1Horz(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTableBand1Horz.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTableBand1Horz.prototype.constructor = CChangesStyleTableBand1Horz;
CChangesStyleTableBand1Horz.prototype.Type = AscDFH.historyitem_Style_TableBand1Horz;
CChangesStyleTableBand1Horz.prototype.private_CreateObject = function()
{
	return new CTableStylePr();
};
CChangesStyleTableBand1Horz.prototype.private_SetValue = function(Value)
{
	this.Class.TableBand1Horz = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTableBand1Vert(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTableBand1Vert.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTableBand1Vert.prototype.constructor = CChangesStyleTableBand1Vert;
CChangesStyleTableBand1Vert.prototype.Type = AscDFH.historyitem_Style_TableBand1Vert;
CChangesStyleTableBand1Vert.prototype.private_CreateObject = function()
{
	return new CTableStylePr();
};
CChangesStyleTableBand1Vert.prototype.private_SetValue = function(Value)
{
	this.Class.TableBand1Vert = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTableBand2Horz(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTableBand2Horz.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTableBand2Horz.prototype.constructor = CChangesStyleTableBand2Horz;
CChangesStyleTableBand2Horz.prototype.Type = AscDFH.historyitem_Style_TableBand2Horz;
CChangesStyleTableBand2Horz.prototype.private_CreateObject = function()
{
	return new CTableStylePr();
};
CChangesStyleTableBand2Horz.prototype.private_SetValue = function(Value)
{
	this.Class.TableBand2Horz = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTableBand2Vert(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTableBand2Vert.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTableBand2Vert.prototype.constructor = CChangesStyleTableBand2Vert;
CChangesStyleTableBand2Vert.prototype.Type = AscDFH.historyitem_Style_TableBand2Vert;
CChangesStyleTableBand2Vert.prototype.private_CreateObject = function()
{
	return new CTableStylePr();
};
CChangesStyleTableBand2Vert.prototype.private_SetValue = function(Value)
{
	this.Class.TableBand2Vert = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTableFirstCol(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTableFirstCol.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTableFirstCol.prototype.constructor = CChangesStyleTableFirstCol;
CChangesStyleTableFirstCol.prototype.Type = AscDFH.historyitem_Style_TableFirstCol;
CChangesStyleTableFirstCol.prototype.private_CreateObject = function()
{
	return new CTableStylePr();
};
CChangesStyleTableFirstCol.prototype.private_SetValue = function(Value)
{
	this.Class.TableFirstCol = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTableFirstRow(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTableFirstRow.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTableFirstRow.prototype.constructor = CChangesStyleTableFirstRow;
CChangesStyleTableFirstRow.prototype.Type = AscDFH.historyitem_Style_TableFirstRow;
CChangesStyleTableFirstRow.prototype.private_CreateObject = function()
{
	return new CTableStylePr();
};
CChangesStyleTableFirstRow.prototype.private_SetValue = function(Value)
{
	this.Class.TableFirstRow = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTableLastCol(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTableLastCol.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTableLastCol.prototype.constructor = CChangesStyleTableLastCol;
CChangesStyleTableLastCol.prototype.Type = AscDFH.historyitem_Style_TableLastCol;
CChangesStyleTableLastCol.prototype.private_CreateObject = function()
{
	return new CTableStylePr();
};
CChangesStyleTableLastCol.prototype.private_SetValue = function(Value)
{
	this.Class.TableLastCol = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTableLastRow(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTableLastRow.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTableLastRow.prototype.constructor = CChangesStyleTableLastRow;
CChangesStyleTableLastRow.prototype.Type = AscDFH.historyitem_Style_TableLastRow;
CChangesStyleTableLastRow.prototype.private_CreateObject = function()
{
	return new CTableStylePr();
};
CChangesStyleTableLastRow.prototype.private_SetValue = function(Value)
{
	this.Class.TableLastRow = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTableTLCell(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTableTLCell.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTableTLCell.prototype.constructor = CChangesStyleTableTLCell;
CChangesStyleTableTLCell.prototype.Type = AscDFH.historyitem_Style_TableTLCell;
CChangesStyleTableTLCell.prototype.private_CreateObject = function()
{
	return new CTableStylePr();
};
CChangesStyleTableTLCell.prototype.private_SetValue = function(Value)
{
	this.Class.TableTLCell = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTableTRCell(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTableTRCell.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTableTRCell.prototype.constructor = CChangesStyleTableTRCell;
CChangesStyleTableTRCell.prototype.Type = AscDFH.historyitem_Style_TableTRCell;
CChangesStyleTableTRCell.prototype.private_CreateObject = function()
{
	return new CTableStylePr();
};
CChangesStyleTableTRCell.prototype.private_SetValue = function(Value)
{
	this.Class.TableTRCell = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTableBLCell(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTableBLCell.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTableBLCell.prototype.constructor = CChangesStyleTableBLCell;
CChangesStyleTableBLCell.prototype.Type = AscDFH.historyitem_Style_TableBLCell;
CChangesStyleTableBLCell.prototype.private_CreateObject = function()
{
	return new CTableStylePr();
};
CChangesStyleTableBLCell.prototype.private_SetValue = function(Value)
{
	this.Class.TableBLCell = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTableBRCell(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTableBRCell.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTableBRCell.prototype.constructor = CChangesStyleTableBRCell;
CChangesStyleTableBRCell.prototype.Type = AscDFH.historyitem_Style_TableBRCell;
CChangesStyleTableBRCell.prototype.private_CreateObject = function()
{
	return new CTableStylePr();
};
CChangesStyleTableBRCell.prototype.private_SetValue = function(Value)
{
	this.Class.TableBRCell = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseObjectProperty}
 */
function CChangesStyleTableWholeTable(Class, Old, New, Color)
{
	CChangesStyleBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesStyleTableWholeTable.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStyleTableWholeTable.prototype.constructor = CChangesStyleTableWholeTable;
CChangesStyleTableWholeTable.prototype.Type = AscDFH.historyitem_Style_TableWholeTable;
CChangesStyleTableWholeTable.prototype.private_CreateObject = function()
{
	return new CTableStylePr();
};
CChangesStyleTableWholeTable.prototype.private_SetValue = function(Value)
{
	this.Class.TableWholeTable = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStyleName(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStyleName.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStyleName.prototype.constructor = CChangesStyleName;
CChangesStyleName.prototype.Type = AscDFH.historyitem_Style_Name;
CChangesStyleName.prototype.private_SetValue = function(Value)
{
	this.Class.Name = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStyleBasedOn(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStyleBasedOn.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStyleBasedOn.prototype.constructor = CChangesStyleBasedOn;
CChangesStyleBasedOn.prototype.Type = AscDFH.historyitem_Style_BasedOn;
CChangesStyleBasedOn.prototype.private_SetValue = function(Value)
{
	this.Class.BasedOn = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStyleNext(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStyleNext.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStyleNext.prototype.constructor = CChangesStyleNext;
CChangesStyleNext.prototype.Type = AscDFH.historyitem_Style_Next;
CChangesStyleNext.prototype.private_SetValue = function(Value)
{
	this.Class.Next = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongValue}
 */
function CChangesStyleType(Class, Old, New)
{
	AscDFH.CChangesBaseLongValue.call(this, Class, Old, New);
}
CChangesStyleType.prototype = Object.create(AscDFH.CChangesBaseLongValue.prototype);
CChangesStyleType.prototype.constructor = CChangesStyleType;
CChangesStyleType.prototype.Type = AscDFH.historyitem_Style_Type;
CChangesStyleType.prototype.private_SetValue = function(Value)
{
	this.Class.Type = Value;
};
CChangesStyleType.prototype.Load = function()
{
	this.Redo();
	AscCommon.CollaborativeEditing.Add_LinkData(this.Class, {StyleUpdate : true});
};
/**
 * @constructor
 * @extends {CChangesStyleBaseBoolProperty}
 */
function CChangesStyleQFormat(Class, Old, New)
{
	CChangesStyleBaseBoolProperty.call(this, Class, Old, New);
}
CChangesStyleQFormat.prototype = Object.create(CChangesStyleBaseBoolProperty.prototype);
CChangesStyleQFormat.prototype.constructor = CChangesStyleQFormat;
CChangesStyleQFormat.prototype.Type = AscDFH.historyitem_Style_QFormat;
CChangesStyleQFormat.prototype.private_SetValue = function(Value)
{
	this.Class.qFormat = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseLongProperty}
 */
function CChangesStyleUiPriority(Class, Old, New)
{
	CChangesStyleBaseLongProperty.call(this, Class, Old, New);
}
CChangesStyleUiPriority.prototype = Object.create(CChangesStyleBaseLongProperty.prototype);
CChangesStyleUiPriority.prototype.constructor = CChangesStyleUiPriority;
CChangesStyleUiPriority.prototype.Type = AscDFH.historyitem_Style_UiPriority;
CChangesStyleUiPriority.prototype.private_SetValue = function(Value)
{
	this.Class.uiPriority = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseBoolProperty}
 */
function CChangesStyleHidden(Class, Old, New)
{
	CChangesStyleBaseBoolProperty.call(this, Class, Old, New);
}
CChangesStyleHidden.prototype = Object.create(CChangesStyleBaseBoolProperty.prototype);
CChangesStyleHidden.prototype.constructor = CChangesStyleHidden;
CChangesStyleHidden.prototype.Type = AscDFH.historyitem_Style_Hidden;
CChangesStyleHidden.prototype.private_SetValue = function(Value)
{
	this.Class.hidden = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseBoolProperty}
 */
function CChangesStyleSemiHidden(Class, Old, New)
{
	CChangesStyleBaseBoolProperty.call(this, Class, Old, New);
}
CChangesStyleSemiHidden.prototype = Object.create(CChangesStyleBaseBoolProperty.prototype);
CChangesStyleSemiHidden.prototype.constructor = CChangesStyleSemiHidden;
CChangesStyleSemiHidden.prototype.Type = AscDFH.historyitem_Style_SemiHidden;
CChangesStyleSemiHidden.prototype.private_SetValue = function(Value)
{
	this.Class.semiHidden = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseBoolProperty}
 */
function CChangesStyleUnhideWhenUsed(Class, Old, New)
{
	CChangesStyleBaseBoolProperty.call(this, Class, Old, New);
}
CChangesStyleUnhideWhenUsed.prototype = Object.create(CChangesStyleBaseBoolProperty.prototype);
CChangesStyleUnhideWhenUsed.prototype.constructor = CChangesStyleUnhideWhenUsed;
CChangesStyleUnhideWhenUsed.prototype.Type = AscDFH.historyitem_Style_UnhideWhenUsed;
CChangesStyleUnhideWhenUsed.prototype.private_SetValue = function(Value)
{
	this.Class.unhideWhenUsed = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStyleLink(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStyleLink.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStyleLink.prototype.constructor = CChangesStyleLink;
CChangesStyleLink.prototype.Type = AscDFH.historyitem_Style_Link;
CChangesStyleLink.prototype.private_SetValue = function(Value)
{
	this.Class.Link = Value;
};

/**
 * @constructor
 * @extends {CChangesStyleBaseBoolProperty}
 */
function CChangesStyleCustom(Class, Old, New)
{
	CChangesStyleBaseBoolProperty.call(this, Class, Old, New);
}
CChangesStyleCustom.prototype = Object.create(CChangesStyleBaseBoolProperty.prototype);
CChangesStyleCustom.prototype.constructor = CChangesStyleCustom;
CChangesStyleCustom.prototype.Type = AscDFH.historyitem_Style_Custom;
CChangesStyleCustom.prototype.private_SetValue = function(Value)
{
	this.Class.Custom = Value;
};

/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesStylesAdd(Class, Id, Style)
{
	AscDFH.CChangesBase.call(this, Class);

	this.Id    = Id;
	this.Style = Style;
}
CChangesStylesAdd.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesStylesAdd.prototype.constructor = CChangesStylesAdd;
CChangesStylesAdd.prototype.Type = AscDFH.historyitem_Styles_Add;
CChangesStylesAdd.prototype.Undo = function()
{
	delete this.Class.Style[this.Id];
	this.Class.Update_Interface(this.Id);
};
CChangesStylesAdd.prototype.Redo = function()
{
	this.Class.Style[this.Id] = this.Style;
	this.Class.Update_Interface(this.Id);
};
CChangesStylesAdd.prototype.WriteToBinary = function(Writer)
{
	// String : Id
	Writer.WriteString2(this.Id);
};
CChangesStylesAdd.prototype.ReadFromBinary = function(Reader)
{
	// String : Id
	this.Id    = Reader.GetString2();
	this.Style = AscCommon.g_oTableId.Get_ById(this.Id);
};
CChangesStylesAdd.prototype.Load = function()
{
	this.Redo();
	AscCommon.CollaborativeEditing.Add_LinkData(this.Class, {UpdateStyleId : this.Id});
};
CChangesStylesAdd.prototype.CreateReverseChange = function()
{
	return new CChangesStylesRemove(this.Class, this.Id, this.Style);
};
CChangesStylesAdd.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if ((AscDFH.historyitem_Styles_Add === oChange.Type || AscDFH.historyitem_Styles_Remove === oChange.Type) && this.Id === oChange.Id)
		return false;

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesStylesRemove(Class, Id, Style)
{
	AscDFH.CChangesBase.call(this, Class);

	this.Id    = Id;
	this.Style = Style;
}
CChangesStylesRemove.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesStylesRemove.prototype.constructor = CChangesStylesRemove;
CChangesStylesRemove.prototype.Type = AscDFH.historyitem_Styles_Remove;
CChangesStylesRemove.prototype.Undo = function()
{
	this.Class.Style[this.Id] = this.Style;
	this.Class.Update_Interface(this.Id);
};
CChangesStylesRemove.prototype.Redo = function()
{
	delete this.Class.Style[this.Id];
	this.Class.Update_Interface(this.Id);
};
CChangesStylesRemove.prototype.WriteToBinary = function(Writer)
{
	// String : Id
	Writer.WriteString2(this.Id);
};
CChangesStylesRemove.prototype.ReadFromBinary = function(Reader)
{
	// String : Id
	this.Id    = Reader.GetString2();
	this.Style = AscCommon.g_oTableId.Get_ById(this.Id);
};
CChangesStylesRemove.prototype.Load = function()
{
	this.Redo();
	AscCommon.CollaborativeEditing.Add_LinkData(this.Class, {UpdateStyleId : this.Id});
};
CChangesStylesRemove.prototype.CreateReverseChange = function()
{
	return new CChangesStylesAdd(this.Class, this.Id, this.Style);
};
CChangesStylesRemove.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if ((AscDFH.historyitem_Styles_Add === oChange.Type || AscDFH.historyitem_Styles_Remove === oChange.Type) && this.Id === oChange.Id)
		return false;

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectValue}
 */
function CChangesStylesChangeDefaultTextPr(Class, Old, New)
{
	AscDFH.CChangesBaseObjectValue.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultTextPr.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStylesChangeDefaultTextPr.prototype.constructor = CChangesStylesChangeDefaultTextPr;
CChangesStylesChangeDefaultTextPr.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultTextPr;
CChangesStylesChangeDefaultTextPr.prototype.private_CreateObject = function()
{
	return new CTextPr();
};
CChangesStylesChangeDefaultTextPr.prototype.private_SetValue = function(Value)
{
	this.Class.Default.TextPr = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectValue}
 */
function CChangesStylesChangeDefaultParaPr(Class, Old, New)
{
	AscDFH.CChangesBaseObjectValue.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultParaPr.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesStylesChangeDefaultParaPr.prototype.constructor = CChangesStylesChangeDefaultParaPr;
CChangesStylesChangeDefaultParaPr.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultParaPr;
CChangesStylesChangeDefaultParaPr.prototype.private_CreateObject = function()
{
	return new CParaPr();
};
CChangesStylesChangeDefaultParaPr.prototype.private_SetValue = function(Value)
{
	this.Class.Default.ParaPr = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultParagraphId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultParagraphId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultParagraphId.prototype.constructor = CChangesStylesChangeDefaultParagraphId;
CChangesStylesChangeDefaultParagraphId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultParagraphId;
CChangesStylesChangeDefaultParagraphId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.Paragraph = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultCharacterId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultCharacterId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultCharacterId.prototype.constructor = CChangesStylesChangeDefaultCharacterId;
CChangesStylesChangeDefaultCharacterId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultCharacterId;
CChangesStylesChangeDefaultCharacterId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.Character = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultNumberingId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultNumberingId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultNumberingId.prototype.constructor = CChangesStylesChangeDefaultNumberingId;
CChangesStylesChangeDefaultNumberingId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultNumberingId;
CChangesStylesChangeDefaultNumberingId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.Numbering = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultTableId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultTableId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultTableId.prototype.constructor = CChangesStylesChangeDefaultTableId;
CChangesStylesChangeDefaultTableId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultTableId;
CChangesStylesChangeDefaultTableId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.Table = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultTableGridId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultTableGridId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultTableGridId.prototype.constructor = CChangesStylesChangeDefaultTableGridId;
CChangesStylesChangeDefaultTableGridId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultTableGridId;
CChangesStylesChangeDefaultTableGridId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.TableGrid = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesStylesChangeDefaultHeadingsId(Class, Old, New, Lvl)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
	this.Lvl = Lvl;
}
CChangesStylesChangeDefaultHeadingsId.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesStylesChangeDefaultHeadingsId.prototype.constructor = CChangesStylesChangeDefaultHeadingsId;
CChangesStylesChangeDefaultHeadingsId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultHeadingsId;
CChangesStylesChangeDefaultHeadingsId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.Headings[this.Lvl] = Value;
};
CChangesStylesChangeDefaultHeadingsId.prototype.WriteToBinary = function(Writer)
{
	// Long  : Lvl
	// Long  : Flag
	// 1-bit : Is undefined new
	// 2-bit : Is null new
	// 3-bit : Is undefined old
	// 4-bit : Is null old
	// String : New (1,2 - bits are zero)
	// String : Old (3,4 - bits are zero)


	Writer.WriteLong(this.Lvl);

	var nFlags = 0;
	if (undefined === this.New)
		nFlags |= 1;
	else if (null === this.New)
		nFlags |= 2;

	if (undefined === this.Old)
		nFlags |= 4;
	else if (null === this.Old)
		nFlags |= 8;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New && null !== this.New)
		Writer.WriteString2(this.New);

	if (undefined !== this.Old && null !== this.Old)
		Writer.WriteString2(this.Old);
};
CChangesStylesChangeDefaultHeadingsId.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Lvl
	// Long  : Flag
	// 1-bit : Is undefined new
	// 2-bit : Is null new
	// 3-bit : Is undefined old
	// 4-bit : Is null old
	// String : New (1,2 - bits are zero)
	// String : Old (3,4 - bits are zero)

	this.Lvl = Reader.GetLong();

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.New = undefined;
	else if (nFlags & 2)
		this.New = null;
	else
		this.New = Reader.GetString2();

	if (nFlags & 4)
		this.Old = undefined;
	else if (nFlags & 8)
		this.Old = null;
	else
		this.Old = Reader.GetString2();
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultParaListId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultParaListId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultParaListId.prototype.constructor = CChangesStylesChangeDefaultParaListId;
CChangesStylesChangeDefaultParaListId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultParaListId;
CChangesStylesChangeDefaultParaListId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.ParaList = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultHeaderId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultHeaderId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultHeaderId.prototype.constructor = CChangesStylesChangeDefaultHeaderId;
CChangesStylesChangeDefaultHeaderId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultHeaderId;
CChangesStylesChangeDefaultHeaderId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.Header = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultFooterId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultFooterId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultFooterId.prototype.constructor = CChangesStylesChangeDefaultFooterId;
CChangesStylesChangeDefaultFooterId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultFooterId;
CChangesStylesChangeDefaultFooterId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.Footer = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultHyperlinkId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultHyperlinkId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultHyperlinkId.prototype.constructor = CChangesStylesChangeDefaultHyperlinkId;
CChangesStylesChangeDefaultHyperlinkId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultHyperlinkId;
CChangesStylesChangeDefaultHyperlinkId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.Header = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultFootnoteTextId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultFootnoteTextId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultFootnoteTextId.prototype.constructor = CChangesStylesChangeDefaultFootnoteTextId;
CChangesStylesChangeDefaultFootnoteTextId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultFootnoteTextId;
CChangesStylesChangeDefaultFootnoteTextId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.FootnoteText = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultFootnoteTextCharId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultFootnoteTextCharId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultFootnoteTextCharId.prototype.constructor = CChangesStylesChangeDefaultFootnoteTextCharId;
CChangesStylesChangeDefaultFootnoteTextCharId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultFootnoteTextCharId;
CChangesStylesChangeDefaultFootnoteTextCharId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.FootnoteTextChar = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultFootnoteReferenceId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultFootnoteReferenceId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultFootnoteReferenceId.prototype.constructor = CChangesStylesChangeDefaultFootnoteReferenceId;
CChangesStylesChangeDefaultFootnoteReferenceId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultFootnoteReferenceId;
CChangesStylesChangeDefaultFootnoteReferenceId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.FootnoteReference = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultNoSpacingId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultNoSpacingId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultNoSpacingId.prototype.constructor = CChangesStylesChangeDefaultNoSpacingId;
CChangesStylesChangeDefaultNoSpacingId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultNoSpacingId;
CChangesStylesChangeDefaultNoSpacingId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.NoSpacing = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultTitleId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultTitleId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultTitleId.prototype.constructor = CChangesStylesChangeDefaultTitleId;
CChangesStylesChangeDefaultTitleId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultTitleId;
CChangesStylesChangeDefaultTitleId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.Title = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultSubtitleId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultSubtitleId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultSubtitleId.prototype.constructor = CChangesStylesChangeDefaultSubtitleId;
CChangesStylesChangeDefaultSubtitleId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultSubtitleId;
CChangesStylesChangeDefaultSubtitleId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.Subtitle = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultQuoteId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultQuoteId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultQuoteId.prototype.constructor = CChangesStylesChangeDefaultQuoteId;
CChangesStylesChangeDefaultQuoteId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultQuoteId;
CChangesStylesChangeDefaultQuoteId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.Quote = Value;
};
/**
 * @constructor
 * @extends {CChangesStyleBaseStringProperty}
 */
function CChangesStylesChangeDefaultIntenseQuoteId(Class, Old, New)
{
	CChangesStyleBaseStringProperty.call(this, Class, Old, New);
}
CChangesStylesChangeDefaultIntenseQuoteId.prototype = Object.create(CChangesStyleBaseStringProperty.prototype);
CChangesStylesChangeDefaultIntenseQuoteId.prototype.constructor = CChangesStylesChangeDefaultIntenseQuoteId;
CChangesStylesChangeDefaultIntenseQuoteId.prototype.Type = AscDFH.historyitem_Styles_ChangeDefaultIntenseQuoteId;
CChangesStylesChangeDefaultIntenseQuoteId.prototype.private_SetValue = function(Value)
{
	this.Class.Default.IntenseQuote = Value;
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 05.04.2017
 * Time: 14:41
 */

/**
 * Класс для отображения изменения сделанного в режиме рецензирования
 * @constructor
 */
function CRevisionsChange()
{
	this.Type      = c_oAscRevisionsChangeType.Unknown;
	this.X         = 0;
	this.Y         = 0;
	this.Value     = "";

	this.UserName  = "";
	this.UserId    = "";
	this.DateTime  = "";
	this.UserColor = new AscCommon.CColor(0, 0, 0, 255);

	this.Paragraph = null;
	this.StartPos  = null;
	this.EndPos    = null;

	this._X       = 0;
	this._Y       = 0;
	this._PageNum = 0;
	this._PosChanged = false;
}
CRevisionsChange.prototype.get_UserId = function(){return this.UserId;};
CRevisionsChange.prototype.put_UserId = function(UserId)
{
	this.UserId = UserId;
	this.private_UpdateUserColor();
};
CRevisionsChange.prototype.get_UserName = function(){return this.UserName;};
CRevisionsChange.prototype.put_UserName = function(UserName)
{
	this.UserName = UserName;
	this.private_UpdateUserColor();
};
CRevisionsChange.prototype.get_DateTime = function(){return this.DateTime};
CRevisionsChange.prototype.put_DateTime = function(DateTime){this.DateTime = DateTime};
CRevisionsChange.prototype.get_UserColor = function(){return this.UserColor;};
CRevisionsChange.prototype.get_StartPos = function(){return this.StartPos};
CRevisionsChange.prototype.put_StartPos = function(StartPos){this.StartPos = StartPos;};
CRevisionsChange.prototype.get_EndPos = function(){return this.EndPos};
CRevisionsChange.prototype.put_EndPos = function(EndPos){this.EndPos = EndPos;};
CRevisionsChange.prototype.get_Type  = function(){return this.Type;};
CRevisionsChange.prototype.get_X     = function(){return this.X;};
CRevisionsChange.prototype.get_Y     = function(){return this.Y;};
CRevisionsChange.prototype.get_Value = function(){return this.Value;};
CRevisionsChange.prototype.put_Type  = function(Type){this.Type = Type;};
CRevisionsChange.prototype.put_XY    = function(X, Y){this.X = X; this.Y = Y;};
CRevisionsChange.prototype.put_Value = function(Value){this.Value = Value;};
CRevisionsChange.prototype.put_Paragraph = function(Para){this.Paragraph = Para;};
CRevisionsChange.prototype.get_Paragraph = function(){return this.Paragraph;};
CRevisionsChange.prototype.get_LockUserId = function()
{
	if (this.Paragraph)
	{
		var Lock = this.Paragraph.Get_Lock();
		var LockType = Lock.Get_Type();

		if (locktype_Mine !== LockType && locktype_None !== LockType)
			return Lock.Get_UserId();
	}

	return null;
};
CRevisionsChange.prototype.put_InternalPos = function(x, y, pageNum)
{
	if (this._PageNum !== pageNum
		|| Math.abs(this._X - x) > 0.001
		|| Math.abs(this._Y - y) > 0.001)
	{
		this._X = x;
		this._Y = y;
		this._PageNum = pageNum;
		this._PosChanged = true;
	}
	else
	{
		this._PosChanged = false;
	}
};
CRevisionsChange.prototype.get_InternalPosX = function()
{
	return this._X;
};
CRevisionsChange.prototype.get_InternalPosY = function()
{
	return this._Y;
};
CRevisionsChange.prototype.get_InternalPosPageNum = function()
{
	return this._PageNum;
};
CRevisionsChange.prototype.ComparePrevPosition = function()
{
	if (true === this._PosChanged)
		return false;

	return true;
};
CRevisionsChange.prototype.private_UpdateUserColor = function()
{
	this.UserColor = AscCommon.getUserColorById(this.UserId, this.UserName, true, false);
};

//--------------------------------------------------------export--------------------------------------------------------
CRevisionsChange.prototype['get_UserId'] = CRevisionsChange.prototype.get_UserId;
CRevisionsChange.prototype['put_UserId'] = CRevisionsChange.prototype.put_UserId;
CRevisionsChange.prototype['get_UserName'] = CRevisionsChange.prototype.get_UserName;
CRevisionsChange.prototype['put_UserName'] = CRevisionsChange.prototype.put_UserName;
CRevisionsChange.prototype['get_DateTime'] = CRevisionsChange.prototype.get_DateTime;
CRevisionsChange.prototype['put_DateTime'] = CRevisionsChange.prototype.put_DateTime;
CRevisionsChange.prototype['get_UserColor'] = CRevisionsChange.prototype.get_UserColor;
CRevisionsChange.prototype['get_StartPos'] = CRevisionsChange.prototype.get_StartPos;
CRevisionsChange.prototype['put_StartPos'] = CRevisionsChange.prototype.put_StartPos;
CRevisionsChange.prototype['get_EndPos'] = CRevisionsChange.prototype.get_EndPos;
CRevisionsChange.prototype['put_EndPos'] = CRevisionsChange.prototype.put_EndPos;
CRevisionsChange.prototype['get_Type'] = CRevisionsChange.prototype.get_Type;
CRevisionsChange.prototype['get_X'] = CRevisionsChange.prototype.get_X;
CRevisionsChange.prototype['get_Y'] = CRevisionsChange.prototype.get_Y;
CRevisionsChange.prototype['get_Value'] = CRevisionsChange.prototype.get_Value;
CRevisionsChange.prototype['put_Type'] = CRevisionsChange.prototype.put_Type;
CRevisionsChange.prototype['put_XY'] = CRevisionsChange.prototype.put_XY;
CRevisionsChange.prototype['put_Value'] = CRevisionsChange.prototype.put_Value;
CRevisionsChange.prototype['get_LockUserId'] = CRevisionsChange.prototype.get_LockUserId;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

var flowobject_Image     = 0x01;
var flowobject_Table     = 0x02;
var flowobject_Paragraph = 0x03;

// Сортируем объекты {X0, X1} по X0
function Sort_Ranges_X0(A,B)
{
    if ( !A.X0 || !B.X0  )
        return 0;

    if( A.X0 < B.X0 )
        return -1;
    else if( A.X0 > B.X0 )
        return 1;

    return 0;
}

// Сравниваем, вложено ли множество первых отрезков во второе
// (множество отрезков здесь - это дизъюнктное объединение отрезков)
function FlowObjects_CheckInjection(Range1, Range2)
{
    for ( var Index = 0; Index < Range1.length; Index++ )
    {
        var R1 = Range1[Index];
        var bInject = false;
        for ( var Index2 = 0; Index2 < Range2.length; Index2++ )
        {
            var R2 = Range2[Index2];

            if ( R1.X0 >= R2.X0 && R1.X0 <= R2.X1 && R1.X1 >= R2.X0 && R1.X1 <= R2.X1 )
                bInject = true;
        }

        if ( !bInject )
            return false;
    }

    return true;
}

// Сравниваем, совпали ли множества отрезков
function FlowObjects_CompareRanges(Range1, Range2)
{
    if ( Range1.length < Range2.length )
        return -1;
    else if ( Range1.length > Range2.length )
        return -1;

    for ( var Index = 0; Index < Range1.length; Index++ )
    {
        if ( Math.abs( Range1[Index].X0 - Range2[Index].X0 ) > 0.001 || Math.abs( Range1[Index].X1 - Range2[Index].X1 ) )
            return -1;
    }

    return 0;
}

function CFlowTable(Table, PageIndex)
{
    this.Type           = flowobject_Table;
    
    this.Table          = Table;
    this.Id             = Table.Get_Id();
    this.PageNum        = Table.Get_StartPage_Absolute();
    this.PageController = PageIndex - Table.PageNum;
    this.Distance       = Table.Distance;

    var Bounds = Table.Get_PageBounds(this.PageController);
    this.X = Bounds.Left;
    this.Y = AscCommon.CorrectMMToTwips(Bounds.Top) + AscCommon.TwipsToMM(1); // Сдвигаемся на 1 twips вниз, чтобы не было пересечения с предыдущей строкой
    this.W = Bounds.Right  - Bounds.Left;
    this.H =  AscCommon.CorrectMMToTwips(Bounds.Bottom - Bounds.Top);

    this.WrappingType = WRAPPING_TYPE_SQUARE;
}

CFlowTable.prototype =
{

    Get_Type : function()
    {
        return flowobject_Table;
    },

    IsPointIn : function(X,Y)
    {
        if ( X <= this.X + this.W && X >= this.X && Y >= this.Y && Y <= this.Y + this.H )
            return true;

        return false;
    },

	UpdateCursorType : function(X, Y, PageIndex)
    {

    },

    Get_Distance : function()
    {
        var oDist = this.Distance;
        return new AscFormat.CDistance(AscFormat.getValOrDefault(oDist.L, AscFormat.DISTANCE_TO_TEXT_LEFTRIGHT), AscFormat.getValOrDefault(oDist.T, 0), AscFormat.getValOrDefault(oDist.R, AscFormat.DISTANCE_TO_TEXT_LEFTRIGHT), AscFormat.getValOrDefault(oDist.B, 0));

    },

    getArrayWrapIntervals: function(x0,y0, x1, y1, Y0Sp, Y1Sp, LeftField, RightField, ret, bMathWrap)
    {
        if(this.WrappingType === WRAPPING_TYPE_THROUGH || this.WrappingType === WRAPPING_TYPE_TIGHT)
        {
            y0 = Y0Sp;
            y1 = Y1Sp;
        }
        var top = this.Y - AscFormat.getValOrDefault(this.Distance.T, 0);
        var bottom = this.Y + this.H + AscFormat.getValOrDefault(this.Distance.B, 0);
        if(y1 < top || y0 > bottom)
            return ret;

        var b_check = false, X0, X1, Y1, WrapType = (bMathWrap === true) ? WRAPPING_TYPE_SQUARE : this.WrappingType;
        switch(WrapType)
        {
            case WRAPPING_TYPE_NONE:
            {
                return ret;
            }
            case WRAPPING_TYPE_SQUARE:
            case WRAPPING_TYPE_THROUGH:
            case WRAPPING_TYPE_TIGHT:
            {
                X0 = this.X - AscFormat.getValOrDefault(this.Distance.L, AscFormat.DISTANCE_TO_TEXT_LEFTRIGHT);
                X1 = this.X + this.W + AscFormat.getValOrDefault(this.Distance.R, AscFormat.DISTANCE_TO_TEXT_LEFTRIGHT);
                Y1 = bottom;
                b_check = true;
                break;
            }
            case WRAPPING_TYPE_TOP_AND_BOTTOM:
            {
                var L = this.X - AscFormat.getValOrDefault(this.Distance.L, AscFormat.DISTANCE_TO_TEXT_LEFTRIGHT);
                var R = this.X + this.W + AscFormat.getValOrDefault(this.Distance.R, AscFormat.DISTANCE_TO_TEXT_LEFTRIGHT);

                if (R < LeftField || L > RightField)
                    return ret;

                X0 = x0;
                X1 = x1;
                Y1 = bottom;
                break;
            }
        }
        if(b_check)
        {
            var dx = this.WrappingType === WRAPPING_TYPE_SQUARE ? 6.35 : 3.175 ;
            if(X0  < LeftField + dx)
            {
                X0 = x0 ;
            }
            if(X1 > RightField - dx)
            {
                X1 = x1;
            }
        }
        ret.push({X0: X0, X1: X1, Y1: Y1, typeLeft: this.WrappingType, typeRight: this.WrappingType});
        return ret;
    }

};

function CFlowParagraph(Paragraph, X, Y, W, H, Dx, Dy, StartIndex, FlowCount, Wrap)
{
    this.Type      = flowobject_Paragraph;
    
    this.Table     = Paragraph;
    this.Paragraph = Paragraph;
    this.Id        = Paragraph.Get_Id();

    this.PageNum   = Paragraph.PageNum + Paragraph.Pages.length - 1;
    this.PageController = 0;

    this.StartIndex = StartIndex;
    this.FlowCount  = FlowCount;

    this.Distance =
    {
        T : Dy,
        B : Dy,
        L : Dx,
        R : Dx
    };

    this.X = X;
    this.Y = Y;
    this.W = W;
    this.H = H;
    
    this.WrappingType = WRAPPING_TYPE_SQUARE;
    
    switch (Wrap)
    {
        case undefined:
        case wrap_Around:
        case wrap_Auto:      this.WrappingType = WRAPPING_TYPE_SQUARE;         break;        
        case wrap_None:      this.WrappingType = WRAPPING_TYPE_NONE;           break;
        case wrap_NotBeside: this.WrappingType = WRAPPING_TYPE_TOP_AND_BOTTOM; break;
        case wrap_Through:   this.WrappingType = WRAPPING_TYPE_THROUGH;        break;
        case wrap_Tight:     this.WrappingType = WRAPPING_TYPE_TIGHT;          break;
    }
}

CFlowParagraph.prototype =
{
    Get_Type : function()
    {
        return flowobject_Paragraph;
    },

    IsPointIn : function(X,Y)
    {
        if ( X <= this.X + this.W && X >= this.X && Y >= this.Y && Y <= this.Y + this.H )
            return true;

        return false;
    },

	UpdateCursorType : function(X, Y, PageIndex)
    {

    },

    Get_Distance : function()
    {
        var oDist = this.Distance;
        return new AscFormat.CDistance(AscFormat.getValOrDefault(oDist.L, AscFormat.DISTANCE_TO_TEXT_LEFTRIGHT), AscFormat.getValOrDefault(oDist.T, 0), AscFormat.getValOrDefault(oDist.R, AscFormat.DISTANCE_TO_TEXT_LEFTRIGHT), AscFormat.getValOrDefault(oDist.B, 0));

    },

    getArrayWrapIntervals: function(x0,y0, x1, y1, Y0Sp, Y1Sp, LeftField, RightField, ret, bMathWrap)
    {
        return CFlowTable.prototype.getArrayWrapIntervals.call(this, x0,y0, x1, y1, Y0Sp, Y1Sp, LeftField, RightField, ret, bMathWrap);
    }
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Содержимое параграфа должно иметь:
//
// 1. Type    - тип
// 2. Draw    - рисуем на контексте
// 3. Measure  - измеряем
// 4. Is_RealContent - является ли данный элемент реальным элементом параграфа
//---- после использования Measure -----
// 1. Width        - ширина (для рассчетов)
// 2. Height       - высота
// 3. WidthVisible - видимая ширина
// ------- после пересчета -------------
// 1. CurPage
// 2. CurLine
// 3. CurRange

// TODO: Добавить во все элементы функции типа Is_RealContent, чтобы при добавлении
//       нового элемента не надо было бы просматривать каждый раз все функции класса
//       CParagraph.

// Import
var g_fontApplication = AscFonts.g_fontApplication;

var g_oTableId      = AscCommon.g_oTableId;
var g_oTextMeasurer = AscCommon.g_oTextMeasurer;
var isRealObject    = AscCommon.isRealObject;
var History         = AscCommon.History;

var HitInLine  = AscFormat.HitInLine;
var MOVE_DELTA = AscFormat.MOVE_DELTA;

var c_oAscRelativeFromH = Asc.c_oAscRelativeFromH;
var c_oAscRelativeFromV = Asc.c_oAscRelativeFromV;

var para_Unknown                   = -1; //
var para_RunBase                   = 0x0000; // Базовый элемент, он не должен использоваться как самостоятельный объект
var para_Text                      = 0x0001; // Текст
var para_Space                     = 0x0002; // Пробелы
var para_TextPr                    = 0x0003; // Свойства текста
var para_End                       = 0x0004; // Конец параграфа
var para_NewLine                   = 0x0010; // Новая строка
var para_NewLineRendered           = 0x0011; // Рассчитанный перенос строки
var para_InlineBreak               = 0x0012; // Перенос внутри строки (для обтекания)
var para_PageBreakRendered         = 0x0013; // Рассчитанный перенос страницы
var para_Numbering                 = 0x0014; // Элемент, обозначающий нумерацию для списков
var para_Tab                       = 0x0015; // Табуляция
var para_Drawing                   = 0x0016; // Графика (картинки, автофигуры, диаграммы, графики)
var para_PageNum                   = 0x0017; // Нумерация страницы
var para_FlowObjectAnchor          = 0x0018; // Привязка для "плавающих" объектов
var para_HyperlinkStart            = 0x0019; // Начало гиперссылки
var para_HyperlinkEnd              = 0x0020; // Конец гиперссылки
var para_CollaborativeChangesStart = 0x0021; // Начало изменений другого редактора
var para_CollaborativeChangesEnd   = 0x0022; // Конец изменений другого редактора
var para_CommentStart              = 0x0023; // Начало комментария
var para_CommentEnd                = 0x0024; // Начало комментария
var para_PresentationNumbering     = 0x0025; // Элемент, обозначающий нумерацию для списков в презентациях
var para_Math                      = 0x0026; // Формула
var para_Run                       = 0x0027; // Текстовый элемент
var para_Sym                       = 0x0028; // Символ
var para_Comment                   = 0x0029; // Метка начала или конца комментария
var para_Hyperlink                 = 0x0030; // Гиперссылка
var para_Math_Run                  = 0x0031; // Run в формуле
var para_Math_Placeholder          = 0x0032; // Плейсхолдер
var para_Math_Composition          = 0x0033; // Математический объект (дробь, степень и т.п.)
var para_Math_Text                 = 0x0034; // Текст в формуле
var para_Math_Ampersand            = 0x0035; // &
var para_Field                     = 0x0036; // Поле
var para_Math_BreakOperator        = 0x0037; // break operator в формуле
var para_Math_Content              = 0x0038; // math content
var para_FootnoteReference         = 0x0039; // Ссылка на сноску
var para_FootnoteRef               = 0x0040; // Номер сноски (должен быть только внутри сноски)
var para_Separator                 = 0x0041; // Разделить, который используется для сносок
var para_ContinuationSeparator     = 0x0042; // Большой разделитель, который используется для сносок
var para_PageCount                 = 0x0043; // Количество страниц
var para_InlineLevelSdt            = 0x0044; // Внутристроковый контейнер
var para_FieldChar                 = 0x0045;
var para_InstrText                 = 0x0046;
var para_Bookmark                  = 0x0047;

var break_Line   = 0x01;
var break_Page   = 0x02;
var break_Column = 0x03;

var nbsp_charcode = 0x00A0;

var nbsp_string = String.fromCharCode(0x00A0);
var sp_string   = String.fromCharCode(0x0032);

var g_aNumber     = [];
g_aNumber[0x0030] = 1;
g_aNumber[0x0031] = 1;
g_aNumber[0x0032] = 1;
g_aNumber[0x0033] = 1;
g_aNumber[0x0034] = 1;
g_aNumber[0x0035] = 1;
g_aNumber[0x0036] = 1;
g_aNumber[0x0037] = 1;
g_aNumber[0x0038] = 1;
g_aNumber[0x0039] = 1;

// Suitable Run content for the paragraph simple changes
var g_oSRCFPSC             = [];
g_oSRCFPSC[para_Text]      = 1;
g_oSRCFPSC[para_Space]     = 1;
g_oSRCFPSC[para_End]       = 1;
g_oSRCFPSC[para_Tab]       = 1;
g_oSRCFPSC[para_Sym]       = 1;
g_oSRCFPSC[para_PageCount] = 1;
g_oSRCFPSC[para_FieldChar] = 1;
g_oSRCFPSC[para_InstrText] = 1;
g_oSRCFPSC[para_Bookmark]  = 1;


var g_aSpecialSymbols     = [];
g_aSpecialSymbols[0x00AE] = 1;


// Список символов, которые не могут находиться в конце строки
// A characters that can not be at the end of a line
var g_aCCNBAEL = [];


var PARATEXT_FLAGS_MASK               = 0xFFFFFFFF; // 4 байта
var PARATEXT_FLAGS_FONTKOEF_SCRIPT    = 0x00000001; // 0 бит
var PARATEXT_FLAGS_FONTKOEF_SMALLCAPS = 0x00000002; // 1 бит
var PARATEXT_FLAGS_SPACEAFTER         = 0x00010000; // 16 бит
var PARATEXT_FLAGS_CAPITALS           = 0x00020000; // 17 бит

var PARATEXT_FLAGS_NON_FONTKOEF_SCRIPT    = PARATEXT_FLAGS_MASK ^ PARATEXT_FLAGS_FONTKOEF_SCRIPT;
var PARATEXT_FLAGS_NON_FONTKOEF_SMALLCAPS = PARATEXT_FLAGS_MASK ^ PARATEXT_FLAGS_FONTKOEF_SMALLCAPS;
var PARATEXT_FLAGS_NON_SPACEAFTER         = PARATEXT_FLAGS_MASK ^ PARATEXT_FLAGS_SPACEAFTER;
var PARATEXT_FLAGS_NON_CAPITALS           = PARATEXT_FLAGS_MASK ^ PARATEXT_FLAGS_CAPITALS;

var TEXTWIDTH_DIVIDER = 16384;

/**
 * Базовый класс для элементов, лежащих внутри рана.
 * @constructor
 */
function CRunElementBase()
{
	this.Width        = 0x00000000 | 0;
	this.WidthVisible = 0x00000000 | 0;
}
CRunElementBase.prototype.Type             = para_RunBase;
CRunElementBase.prototype.Get_Type         = function()
{
	return this.Type;
};
CRunElementBase.prototype.Draw             = function(X, Y, Context, PDSE)
{
};
CRunElementBase.prototype.Measure          = function(Context, TextPr)
{
	this.Width        = 0x00000000 | 0;
	this.WidthVisible = 0x00000000 | 0;
};
CRunElementBase.prototype.Get_Width        = function()
{
	return (this.Width / TEXTWIDTH_DIVIDER);
};
CRunElementBase.prototype.Get_WidthVisible = function()
{
	return (this.WidthVisible / TEXTWIDTH_DIVIDER);
};
CRunElementBase.prototype.Set_WidthVisible = function(WidthVisible)
{
	this.WidthVisible = (WidthVisible * TEXTWIDTH_DIVIDER) | 0;
};
CRunElementBase.prototype.Is_RealContent   = function()
{
	return true;
};
CRunElementBase.prototype.Can_AddNumbering = function()
{
	return true;
};
CRunElementBase.prototype.Copy             = function()
{
	return new CRunElementBase();
};
CRunElementBase.prototype.Write_ToBinary   = function(Writer)
{
	// Long : Type
	Writer.WriteLong(this.Type);
};
CRunElementBase.prototype.Read_FromBinary  = function(Reader)
{
};
CRunElementBase.prototype.GetType = function()
{
	return this.Type;
};
/**
 * Проверять ли автозамену на вводе данного элемента
 * @returns {boolean}
 */
CRunElementBase.prototype.CanStartAutoCorrect = function()
{
	return false;
};

/**
 * Класс представляющий текстовый символ
 * @param {Number} nCharCode - Юникодное значение символа
 * @constructor
 * @extends {CRunElementBase}
 */
function ParaText(nCharCode)
{
	CRunElementBase.call(this);

	this.Value        = undefined !== nCharCode ? nCharCode : 0x00;
	this.Width        = 0x00000000 | 0;
	this.WidthVisible = 0x00000000 | 0;
	this.Flags        = 0x00000000 | 0;

	this.Set_SpaceAfter(this.private_IsSpaceAfter());

	if (AscFonts.IsCheckSymbols)
		AscFonts.FontPickerByCharacter.getFontBySymbol(this.Value);
}
ParaText.prototype = Object.create(CRunElementBase.prototype);
ParaText.prototype.constructor = ParaText;

ParaText.prototype.Type = para_Text;
ParaText.prototype.Set_CharCode = function(CharCode)
{
	this.Value = CharCode;
	this.Set_SpaceAfter(this.private_IsSpaceAfter());

	if (AscFonts.IsCheckSymbols)
		AscFonts.FontPickerByCharacter.getFontBySymbol(this.Value);
};
ParaText.prototype.Draw = function(X, Y, Context)
{
	var CharCode = this.Value;

	var FontKoef = 1;
	if (this.Flags & PARATEXT_FLAGS_FONTKOEF_SCRIPT && this.Flags & PARATEXT_FLAGS_FONTKOEF_SMALLCAPS)
		FontKoef = smallcaps_and_script_koef;
	else if (this.Flags & PARATEXT_FLAGS_FONTKOEF_SCRIPT)
		FontKoef = vertalign_Koef_Size;
	else if (this.Flags & PARATEXT_FLAGS_FONTKOEF_SMALLCAPS)
		FontKoef = smallcaps_Koef;

	Context.SetFontSlot(((this.Flags >> 8) & 0xFF), FontKoef);

	var ResultCharCode = (this.Flags & PARATEXT_FLAGS_CAPITALS ? (String.fromCharCode(CharCode).toUpperCase()).charCodeAt(0) : CharCode);

	if (true !== this.Is_NBSP())
		Context.FillTextCode(X, Y, ResultCharCode);
	else if (editor && editor.ShowParaMarks)
		Context.FillText(X, Y, String.fromCharCode(0x00B0));
};
ParaText.prototype.Measure = function(Context, TextPr)
{
	var bCapitals      = false;
	var CharCode       = this.Value;
	var ResultCharCode = CharCode;

	if (true === TextPr.Caps || true === TextPr.SmallCaps)
	{
		this.Flags |= PARATEXT_FLAGS_CAPITALS;
		ResultCharCode = (String.fromCharCode(CharCode).toUpperCase()).charCodeAt(0);
		bCapitals      = (ResultCharCode === CharCode ? true : false);
	}
	else
	{
		this.Flags &= PARATEXT_FLAGS_NON_CAPITALS;
		bCapitals = false;
	}

	if (TextPr.VertAlign !== AscCommon.vertalign_Baseline)
		this.Flags |= PARATEXT_FLAGS_FONTKOEF_SCRIPT;
	else
		this.Flags &= PARATEXT_FLAGS_NON_FONTKOEF_SCRIPT;

	if (true != TextPr.Caps && true === TextPr.SmallCaps && false === bCapitals)
		this.Flags |= PARATEXT_FLAGS_FONTKOEF_SMALLCAPS;
	else
		this.Flags &= PARATEXT_FLAGS_NON_FONTKOEF_SMALLCAPS;

	var Hint = TextPr.RFonts.Hint;
	var bCS  = TextPr.CS;
	var bRTL = TextPr.RTL;
	var lcid = TextPr.Lang.EastAsia;

	var FontSlot = g_font_detector.Get_FontClass(ResultCharCode, Hint, lcid, bCS, bRTL);

	var Flags_0Byte = (this.Flags >> 0) & 0xFF;
	var Flags_2Byte = (this.Flags >> 16) & 0xFF;

	this.Flags = Flags_0Byte | ((FontSlot & 0xFF) << 8) | (Flags_2Byte << 16);

	var FontKoef = 1;
	if (this.Flags & PARATEXT_FLAGS_FONTKOEF_SCRIPT && this.Flags & PARATEXT_FLAGS_FONTKOEF_SMALLCAPS)
		FontKoef = smallcaps_and_script_koef;
	else if (this.Flags & PARATEXT_FLAGS_FONTKOEF_SCRIPT)
		FontKoef = vertalign_Koef_Size;
	else if (this.Flags & PARATEXT_FLAGS_FONTKOEF_SMALLCAPS)
		FontKoef = smallcaps_Koef;

	// Разрешенные размеры шрифта только либо целое, либо целое/2. Даже после применения FontKoef, поэтому
	// мы должны подкрутить коэффициент так, чтобы после домножения на него, у на получался разрешенный размер.
	var FontSize = TextPr.FontSize;
	if (1 !== FontKoef)
		FontKoef = (((FontSize * FontKoef * 2 + 0.5) | 0) / 2) / FontSize;

	Context.SetFontSlot(FontSlot, FontKoef);
	var Temp = Context.MeasureCode(ResultCharCode);

	var ResultWidth = (Math.max((Temp.Width + TextPr.Spacing), 0) * TEXTWIDTH_DIVIDER) | 0;

	this.Width        = ResultWidth;
	this.WidthVisible = ResultWidth;
};
ParaText.prototype.Is_RealContent = function()
{
	return true;
};
ParaText.prototype.Can_AddNumbering = function()
{
	return true;
};
ParaText.prototype.Copy = function()
{
	return new ParaText(this.Value);
};
ParaText.prototype.Is_NBSP = function()
{
	return ( this.Value === nbsp_charcode ? true : false);
};
ParaText.prototype.Is_Punctuation = function()
{
	if (undefined !== AscCommon.g_aPunctuation[this.Value])
		return true;

	return false;
};
ParaText.prototype.Is_Number = function()
{
	if (1 === g_aNumber[this.Value])
		return true;

	return false;
};
ParaText.prototype.Is_SpecialSymbol = function()
{
	if (1 === g_aSpecialSymbols[this.Value])
		return true;

	return false;
};
ParaText.prototype.IsSpaceAfter = function()
{
	return (this.Flags & PARATEXT_FLAGS_SPACEAFTER ? true : false);
};
/**
 * Получаем символ для проверки орфографии
 * @param bCaps {boolean}
 * @return {string}
 */
ParaText.prototype.GetCharForSpellCheck = function(bCaps)
{
	// Закрывающуюся кавычку (0x2019), посылаем как апостроф

	if (0x2019 === this.Value)
		return String.fromCharCode(0x0027);
	else
	{
		if (true === bCaps)
			return (String.fromCharCode(this.Value)).toUpperCase();
		else
			return String.fromCharCode(this.Value);
	}
};
ParaText.prototype.Set_SpaceAfter = function(bSpaceAfter)
{
	if (bSpaceAfter)
		this.Flags |= PARATEXT_FLAGS_SPACEAFTER;
	else
		this.Flags &= PARATEXT_FLAGS_NON_SPACEAFTER;
};
ParaText.prototype.IsNoBreakHyphen = function()
{
	if (false === this.IsSpaceAfter() && this.Value === 0x002D)
		return true;

	return false;
};
ParaText.prototype.Write_ToBinary = function(Writer)
{
	// Long : Type
	// Long : Value

	Writer.WriteLong(para_Text);
	Writer.WriteLong(this.Value);
};
ParaText.prototype.Read_FromBinary = function(Reader)
{
	this.Set_CharCode(Reader.GetLong());
};
ParaText.prototype.private_IsSpaceAfter = function()
{
	// Дефисы
	if (0x002D === this.Value || 0x2014 === this.Value)
		return true;

	if (AscCommon.isEastAsianScript(this.Value) && this.CanBeAtEndOfLine())
		return true;

	return false;
};
ParaText.prototype.CanBeAtBeginOfLine = function()
{
	if (this.Is_NBSP())
		return false;

	return (!(AscCommon.g_aPunctuation[this.Value] & AscCommon.PUNCTUATION_FLAG_CANT_BE_AT_BEGIN));
};
ParaText.prototype.CanBeAtEndOfLine = function()
{
	if (this.Is_NBSP())
		return false;

	return (!(AscCommon.g_aPunctuation[this.Value] & AscCommon.PUNCTUATION_FLAG_CANT_BE_AT_END));
};
ParaText.prototype.CanStartAutoCorrect = function()
{
	// 34 "
	// 39 '
	// 45 -

	return (34 === this.Value
	|| 39 === this.Value
	|| 45 === this.Value);
};

/**
 * Класс представляющий пробелбный символ
 * @constructor
 * @extends {CRunElementBase}
 */
function ParaSpace()
{
	CRunElementBase.call(this);

    this.Flags        = 0x00000000 | 0;
    this.Width        = 0x00000000 | 0;
    this.WidthVisible = 0x00000000 | 0;
}
ParaSpace.prototype = Object.create(CRunElementBase.prototype);
ParaSpace.prototype.constructor = ParaSpace;

ParaSpace.prototype.Type = para_Space;
ParaSpace.prototype.Draw = function(X, Y, Context)
{
	if (undefined !== editor && editor.ShowParaMarks)
	{
		Context.SetFontSlot(fontslot_ASCII, this.Get_FontKoef());
		Context.FillText(X, Y, String.fromCharCode(0x00B7));
	}
};
ParaSpace.prototype.Measure = function(Context, TextPr)
{
	this.Set_FontKoef_Script(TextPr.VertAlign !== AscCommon.vertalign_Baseline ? true : false);
	this.Set_FontKoef_SmallCaps(true != TextPr.Caps && true === TextPr.SmallCaps ? true : false);

	// Разрешенные размеры шрифта только либо целое, либо целое/2. Даже после применения FontKoef, поэтому
	// мы должны подкрутить коэффициент так, чтобы после домножения на него, у на получался разрешенный размер.
	var FontKoef = this.Get_FontKoef();
	var FontSize = TextPr.FontSize;
	if (1 !== FontKoef)
		FontKoef = (((FontSize * FontKoef * 2 + 0.5) | 0) / 2) / FontSize;

	Context.SetFontSlot(fontslot_ASCII, FontKoef);

	var Temp = Context.MeasureCode(0x20);

	var ResultWidth = (Math.max((Temp.Width + TextPr.Spacing), 0) * 16384) | 0;
	this.Width      = ResultWidth;
	// Не меняем здесь WidthVisible, это значение для пробела высчитывается отдельно, и не должно меняться при пересчете
};
ParaSpace.prototype.Get_FontKoef = function()
{
	if (this.Flags & PARATEXT_FLAGS_FONTKOEF_SCRIPT && this.Flags & PARATEXT_FLAGS_FONTKOEF_SMALLCAPS)
		return smallcaps_and_script_koef;
	else if (this.Flags & PARATEXT_FLAGS_FONTKOEF_SCRIPT)
		return vertalign_Koef_Size;
	else if (this.Flags & PARATEXT_FLAGS_FONTKOEF_SMALLCAPS)
		return smallcaps_Koef;
	else
		return 1;
};
ParaSpace.prototype.Set_FontKoef_Script = function(bScript)
{
	if (bScript)
		this.Flags |= PARATEXT_FLAGS_FONTKOEF_SCRIPT;
	else
		this.Flags &= PARATEXT_FLAGS_NON_FONTKOEF_SCRIPT;
};
ParaSpace.prototype.Set_FontKoef_SmallCaps = function(bSmallCaps)
{
	if (bSmallCaps)
		this.Flags |= PARATEXT_FLAGS_FONTKOEF_SMALLCAPS;
	else
		this.Flags &= PARATEXT_FLAGS_NON_FONTKOEF_SMALLCAPS;
};
ParaSpace.prototype.Is_RealContent = function()
{
	return true;
};
ParaSpace.prototype.Can_AddNumbering = function()
{
	return true;
};
ParaSpace.prototype.Copy = function()
{
	return new ParaSpace();
};
ParaSpace.prototype.Write_ToBinary = function(Writer)
{
	// Long : Type
	// Long : Value

	Writer.WriteLong(para_Space);
	Writer.WriteLong(this.Value);
};
ParaSpace.prototype.Read_FromBinary = function(Reader)
{
	this.Value = Reader.GetLong();
};
ParaSpace.prototype.CanStartAutoCorrect = function()
{
	return true;
};


/**
 * Класс представляющий символ
 * @param Char
 * @param FontFamily
 * @constructor
 * @extends {CRunElementBase}
 */
function ParaSym(Char, FontFamily)
{
	CRunElementBase.call(this);

    this.FontFamily = FontFamily;
    this.Char       = Char;

    this.FontSlot   = fontslot_ASCII;
    this.FontKoef   = 1;

    this.Width        = 0;
    this.Height       = 0;
    this.WidthVisible = 0;
}
ParaSym.prototype = Object.create(CRunElementBase.prototype);
ParaSym.prototype.constructor = ParaSym;

ParaSym.prototype.Type = para_Sym;
ParaSym.prototype.Draw = function(X,Y,Context, TextPr)
{
	var CurTextPr = TextPr.Copy();

	switch (this.FontSlot)
	{
		case fontslot_ASCII:
			CurTextPr.RFonts.Ascii = {Name : this.FontFamily, Index : -1};
			break;
		case fontslot_CS:
			CurTextPr.RFonts.CS = {Name : this.FontFamily, Index : -1};
			break;
		case fontslot_EastAsia:
			CurTextPr.RFonts.EastAsia = {Name : this.FontFamily, Index : -1};
			break;
		case fontslot_HAnsi:
			CurTextPr.RFonts.HAnsi = {Name : this.FontFamily, Index : -1};
			break;
	}

	Context.SetTextPr(CurTextPr);
	Context.SetFontSlot(this.FontSlot, this.FontKoef);

	Context.FillText(X, Y, String.fromCharCode(this.Char));
	Context.SetTextPr(TextPr);
};
ParaSym.prototype.Measure = function(Context, TextPr)
{
	this.FontKoef = TextPr.Get_FontKoef();

	var Hint = TextPr.RFonts.Hint;
	var bCS  = TextPr.CS;
	var bRTL = TextPr.RTL;
	var lcid = TextPr.Lang.EastAsia;

	this.FontSlot = g_font_detector.Get_FontClass(this.CalcValue.charCodeAt(0), Hint, lcid, bCS, bRTL);

	var CurTextPr = TextPr.Copy();

	switch (this.FontSlot)
	{
		case fontslot_ASCII:
			CurTextPr.RFonts.Ascii = {Name : this.FontFamily, Index : -1};
			break;
		case fontslot_CS:
			CurTextPr.RFonts.CS = {Name : this.FontFamily, Index : -1};
			break;
		case fontslot_EastAsia:
			CurTextPr.RFonts.EastAsia = {Name : this.FontFamily, Index : -1};
			break;
		case fontslot_HAnsi:
			CurTextPr.RFonts.HAnsi = {Name : this.FontFamily, Index : -1};
			break;
	}

	Context.SetTextPr(CurTextPr);
	Context.SetFontSlot(this.FontSlot, this.FontKoef);

	var Temp = Context.Measure(this.CalcValue);
	Context.SetTextPr(TextPr);

	Temp.Width = Math.max(Temp.Width + TextPr.Spacing, 0);

	this.Width        = Temp.Width;
	this.Height       = Temp.Height;
	this.WidthVisible = Temp.Width;
};
ParaSym.prototype.Is_RealContent = function()
{
	return true;
};
ParaSym.prototype.Can_AddNumbering = function()
{
	return true;
};
ParaSym.prototype.Copy = function()
{
	return new ParaSym(this.Char, this.FontFamily);
};
ParaSym.prototype.Write_ToBinary = function(Writer)
{
	// Long   : Type
	// String : FontFamily
	// Long   : Char

	Writer.WriteLong(this.Type);
	Writer.WriteString2(this.FontFamily);
	Writer.WriteLong(this.Char);
};
ParaSym.prototype.Read_FromBinary = function(Reader)
{
	// String : FontFamily
	// Long   : Char

	this.FontFamily = Reader.GetString2();
	this.Char       = Reader.GetLong();
};


/**
 * Класс представляющий символ конца параграфа
 * @constructor
 * @extends {CRunElementBase}
 */
function ParaEnd()
{
	CRunElementBase.call(this);

    this.SectionPr    = null;
    this.WidthVisible = 0x00000000 | 0; 
}
ParaEnd.prototype = Object.create(CRunElementBase.prototype);
ParaEnd.prototype.constructor = ParaEnd;

ParaEnd.prototype.Type = para_End;
ParaEnd.prototype.Draw = function(X, Y, Context, bEndCell, bForceDraw)
{
	if ((undefined !== editor && editor.ShowParaMarks) || true === bForceDraw)
	{
		Context.SetFontSlot(fontslot_ASCII);

		if (null !== this.SectionPr)
		{
			Context.b_color1(0, 0, 0, 255);
			Context.p_color(0, 0, 0, 255);

			Context.SetFont({
				FontFamily : {Name : "Courier New", Index : -1},
				FontSize   : 8,
				Italic     : false,
				Bold       : false
			});
			var Widths = this.SectionPr.Widths;
			var strSectionBreak = this.SectionPr.Str;

			var Len = strSectionBreak.length;

			for (var Index = 0; Index < Len; Index++)
			{
				Context.FillText(X, Y, strSectionBreak[Index]);
				X += Widths[Index];
			}
		}
		else if (true === bEndCell)
			Context.FillText(X, Y, String.fromCharCode(0x00A4));
		else
			Context.FillText(X, Y, String.fromCharCode(0x00B6));
	}
};
ParaEnd.prototype.Measure = function(Context, bEndCell)
{
	Context.SetFontSlot(fontslot_ASCII);

	if (true === bEndCell)
		this.WidthVisible = (Context.Measure(String.fromCharCode(0x00A4)).Width * TEXTWIDTH_DIVIDER) | 0;
	else
		this.WidthVisible = (Context.Measure(String.fromCharCode(0x00B6)).Width * TEXTWIDTH_DIVIDER) | 0;
};
ParaEnd.prototype.Get_Width = function()
{
	return 0;
};
ParaEnd.prototype.Update_SectionPr = function(SectionPr, W)
{
	var Type = SectionPr.Type;

	var strSectionBreak = "";
	switch (Type)
	{
		case c_oAscSectionBreakType.Column     :
			strSectionBreak = " End of Section ";
			break;
		case c_oAscSectionBreakType.Continuous :
			strSectionBreak = " Section Break (Continuous) ";
			break;
		case c_oAscSectionBreakType.EvenPage   :
			strSectionBreak = " Section Break (Even Page) ";
			break;
		case c_oAscSectionBreakType.NextPage   :
			strSectionBreak = " Section Break (Next Page) ";
			break;
		case c_oAscSectionBreakType.OddPage    :
			strSectionBreak = " Section Break (Odd Page) ";
			break;
	}

	g_oTextMeasurer.SetFont({
		FontFamily : {Name : "Courier New", Index : -1},
		FontSize   : 8,
		Italic     : false,
		Bold       : false
	});

	var Widths = [];

	var nStrWidth = 0;
	var Len       = strSectionBreak.length;
	for (var Index = 0; Index < Len; Index++)
	{
		var Val       = g_oTextMeasurer.Measure(strSectionBreak[Index]).Width;
		nStrWidth += Val;
		Widths[Index] = Val;
	}

	var strSymbol = ":";
	var nSymWidth = g_oTextMeasurer.Measure(strSymbol).Width * 2 / 3;

	var strResult = "";
	if (W - 6 * nSymWidth >= nStrWidth)
	{
		var Count     = parseInt((W - nStrWidth) / ( 2 * nSymWidth ));
		var strResult = strSectionBreak;
		for (var Index = 0; Index < Count; Index++)
		{
			strResult = strSymbol + strResult + strSymbol;
			Widths.splice(0, 0, nSymWidth);
			Widths.splice(Widths.length, 0, nSymWidth);
		}
	}
	else
	{
		var Count = parseInt(W / nSymWidth);
		for (var Index = 0; Index < Count; Index++)
		{
			strResult += strSymbol;
			Widths[Index] = nSymWidth;
		}
	}

	var ResultW = 0;
	var Count   = Widths.length;
	for (var Index = 0; Index < Count; Index++)
	{
		ResultW += Widths[Index];
	}

	var AddW = 0;
	if (ResultW < W && Count > 1)
	{
		AddW = (W - ResultW) / (Count - 1);
	}

	for (var Index = 0; Index < Count - 1; Index++)
	{
		Widths[Index] += AddW;
	}

	this.SectionPr          = {};
	this.SectionPr.OldWidth = this.Width;
	this.SectionPr.Str      = strResult;
	this.SectionPr.Widths   = Widths;

	var _W            = (W * TEXTWIDTH_DIVIDER) | 0;
	this.WidthVisible = _W;
};
ParaEnd.prototype.Clear_SectionPr = function()
{
	this.SectionPr = null;
};
ParaEnd.prototype.Is_RealContent = function()
{
	return true;
};
ParaEnd.prototype.Can_AddNumbering = function()
{
	return true;
};
ParaEnd.prototype.Copy = function()
{
	return new ParaEnd();
};
ParaEnd.prototype.Write_ToBinary = function(Writer)
{
	// Long   : Type
	Writer.WriteLong(para_End);
};
ParaEnd.prototype.Read_FromBinary = function(Reader)
{
};

/**
 * Класс представляющий разрыв строки/колонки/страницы
 * @param BreakType
 * @constructor
 * @extends {CRunElementBase}
 */
function ParaNewLine(BreakType)
{
	CRunElementBase.call(this);

    this.BreakType = BreakType;

    this.Flags = {}; // специальные флаги для разных break
    this.Flags.Use = true;

    if (break_Page === this.BreakType || break_Column === this.BreakType)
        this.Flags.NewLine = true;

    this.Height       = 0;
    this.Width        = 0;
    this.WidthVisible = 0;
}
ParaNewLine.prototype = Object.create(CRunElementBase.prototype);
ParaNewLine.prototype.constructor = ParaNewLine;

ParaNewLine.prototype.Type = para_NewLine;
ParaNewLine.prototype.Draw = function(X, Y, Context)
{
	if (false === this.Flags.Use)
		return;

	if (undefined !== editor && editor.ShowParaMarks)
	{
		// Цвет и шрифт можно не запоминать и не выставлять старый, т.к. на данном элемента всегда заканчивается
		// отрезок обтекания или целая строка.

		switch (this.BreakType)
		{
			case break_Line:
			{
				Context.b_color1(0, 0, 0, 255);
				Context.SetFont({
					FontFamily : {Name : "ASCW3", Index : -1},
					FontSize   : 10,
					Italic     : false,
					Bold       : false
				});
				Context.FillText(X, Y, String.fromCharCode(0x0038/*0x21B5*/));
				break;
			}
			case break_Page:
			case break_Column:
			{
				var strPageBreak = this.Flags.BreakPageInfo.Str;
				var Widths       = this.Flags.BreakPageInfo.Widths;

				Context.b_color1(0, 0, 0, 255);
				Context.SetFont({
					FontFamily : {Name : "Courier New", Index : -1},
					FontSize   : 8,
					Italic     : false,
					Bold       : false
				});

				var Len = strPageBreak.length;
				for (var Index = 0; Index < Len; Index++)
				{
					Context.FillText(X, Y, strPageBreak[Index]);
					X += Widths[Index];
				}

				break;
			}
		}

	}
};
ParaNewLine.prototype.Measure = function(Context)
{
	if (false === this.Flags.Use)
	{
		this.Width        = 0;
		this.WidthVisible = 0;
		this.Height       = 0;
		return;
	}

	switch (this.BreakType)
	{
		case break_Line:
		{
			this.Width  = 0;
			this.Height = 0;

			Context.SetFont({FontFamily : {Name : "ASCW3", Index : -1}, FontSize : 10, Italic : false, Bold : false});
			var Temp = Context.Measure(String.fromCharCode(0x0038));

			// Почему-то в шрифте Wingding 3 символ 0x0038 имеет неправильную ширину
			this.WidthVisible = Temp.Width * 1.7;

			break;
		}
		case break_Page:
		case break_Column:
		{
			this.Width  = 0;
			this.Height = 0;

			break;
		}
	}
};
ParaNewLine.prototype.Get_Width = function()
{
	return this.Width;
};
ParaNewLine.prototype.Get_WidthVisible = function()
{
	return this.WidthVisible;
};
ParaNewLine.prototype.Set_WidthVisible = function(WidthVisible)
{
	this.WidthVisible = WidthVisible;
};
ParaNewLine.prototype.Update_String = function(_W)
{
	if (false === this.Flags.Use)
	{
		this.Width        = 0;
		this.WidthVisible = 0;
		this.Height       = 0;
		return;
	}

	if (break_Page === this.BreakType || break_Column === this.BreakType)
	{
		var W = ( false === this.Flags.NewLine ? 50 : _W );

		g_oTextMeasurer.SetFont({
			FontFamily : {Name : "Courier New", Index : -1},
			FontSize   : 8,
			Italic     : false,
			Bold       : false
		});

		var Widths = [];

		var nStrWidth    = 0;
		var strBreakPage = break_Page === this.BreakType ? " Page Break " : " Column Break ";
		var Len          = strBreakPage.length;
		for (var Index = 0; Index < Len; Index++)
		{
			var Val       = g_oTextMeasurer.Measure(strBreakPage[Index]).Width;
			nStrWidth += Val;
			Widths[Index] = Val;
		}

		var strSymbol = String.fromCharCode("0x00B7");
		var nSymWidth = g_oTextMeasurer.Measure(strSymbol).Width * 2 / 3;

		var strResult = "";
		if (W - 6 * nSymWidth >= nStrWidth)
		{
			var Count     = parseInt((W - nStrWidth) / ( 2 * nSymWidth ));
			var strResult = strBreakPage;
			for (var Index = 0; Index < Count; Index++)
			{
				strResult = strSymbol + strResult + strSymbol;
				Widths.splice(0, 0, nSymWidth);
				Widths.splice(Widths.length, 0, nSymWidth);
			}
		}
		else
		{
			var Count = parseInt(W / nSymWidth);
			for (var Index = 0; Index < Count; Index++)
			{
				strResult += strSymbol;
				Widths[Index] = nSymWidth;
			}
		}

		var ResultW = 0;
		var Count   = Widths.length;
		for (var Index = 0; Index < Count; Index++)
		{
			ResultW += Widths[Index];
		}

		var AddW = 0;
		if (ResultW < W && Count > 1)
		{
			AddW = (W - ResultW) / (Count - 1);
		}

		for (var Index = 0; Index < Count - 1; Index++)
		{
			Widths[Index] += AddW;
		}

		this.Flags.BreakPageInfo        = {};
		this.Flags.BreakPageInfo.Str    = strResult;
		this.Flags.BreakPageInfo.Widths = Widths;

		this.Width        = W;
		this.WidthVisible = W;
	}
};
ParaNewLine.prototype.Is_RealContent = function()
{
	return true;
};
ParaNewLine.prototype.Can_AddNumbering = function()
{
	if (break_Line === this.BreakType)
		return true;

	return false;
};
ParaNewLine.prototype.Copy = function()
{
	return new ParaNewLine(this.BreakType);
};
/**
 * Функция проверяет особый случай, когда у нас PageBreak, после которого в параграфе ничего не идет
 * @returns {boolean}
 */
ParaNewLine.prototype.Is_NewLine = function()
{
	if (break_Line === this.BreakType || ((break_Page === this.BreakType || break_Column === this.BreakType) && true === this.Flags.NewLine))
		return true;

	return false;
};
ParaNewLine.prototype.Write_ToBinary = function(Writer)
{
	// Long   : Type
	// Long   : BreakType
	// Optional :
	// Long   : Flags (breakPage)
	Writer.WriteLong(para_NewLine);
	Writer.WriteLong(this.BreakType);

	if (break_Page === this.BreakType || break_Column === this.BreakType)
	{
		Writer.WriteBool(this.Flags.NewLine);
	}
};
ParaNewLine.prototype.Read_FromBinary = function(Reader)
{
	this.BreakType = Reader.GetLong();

	if (break_Page === this.BreakType || break_Column === this.BreakType)
		this.Flags = {NewLine : Reader.GetBool()};
};
/**
 * Разрыв страницы или колонки?
 * @returns {boolean}
 */
ParaNewLine.prototype.IsPageOrColumnBreak = function()
{
	return (break_Page === this.BreakType || break_Column === this.BreakType);
};
/**
 * Разрыв страницы?
 * @returns {boolean}
 */
ParaNewLine.prototype.IsPageBreak = function()
{
	return (break_Page === this.BreakType);
};
/**
 * Разрыв колонки?
 * @returns {boolean}
 */
ParaNewLine.prototype.IsColumnBreak = function()
{
	return (break_Column === this.BreakType);
};
/**
 * Перенос строки?
 * @returns {boolean}
 */
ParaNewLine.prototype.IsLineBreak = function()
{
	return (break_Line === this.BreakType);
};


/**
 * Класс представляющий символ(текст) нумерации параграфа
 * @constructor
 * @extends {CRunElementBase}
 */
function ParaNumbering()
{
	CRunElementBase.call(this);

	this.Item = null; // Элемент в ране, к которому привязана нумерация
	this.Run  = null; // Ран, к которому привязана нумерация

	this.Line  = 0;
	this.Range = 0;
	this.Page  = 0;

	this.Internal = {
		NumInfo   : undefined,
		CalcValue : -1
	};
}
ParaNumbering.prototype = Object.create(CRunElementBase.prototype);
ParaNumbering.prototype.constructor = ParaNumbering;

ParaNumbering.prototype.Type = para_Numbering;
ParaNumbering.prototype.Draw = function(X,Y,Context, Numbering, TextPr, NumPr, Theme)
{
	Numbering.Draw(NumPr.NumId, NumPr.Lvl, X, Y, Context, this.Internal.NumInfo, TextPr, Theme);
};
ParaNumbering.prototype.Measure = function (Context, Numbering, NumInfo, TextPr, NumPr, Theme)
{
	this.Internal.NumInfo   = NumInfo;
	this.Internal.CalcValue = NumInfo && NumPr ? NumInfo[NumPr.Lvl] : -1;

	this.Width        = 0;
	this.Height       = 0;
	this.WidthVisible = 0;
	this.WidthNum     = 0;
	this.WidthSuff    = 0;

	if (undefined === Numbering)
		return {Width : this.Width, Height : this.Height, WidthVisible : this.WidthVisible};

	var Temp          = Numbering.Measure(NumPr.NumId, NumPr.Lvl, Context, NumInfo, TextPr, Theme);
	this.Width        = Temp.Width;
	this.WidthVisible = Temp.Width;
	this.WidthNum     = Temp.Width;
	this.WidthSuff    = 0;
	this.Height       = Temp.Ascent; // Это не вся высота, а только высота над BaseLine
};
ParaNumbering.prototype.Check_Range = function(Range, Line)
{
	if (null !== this.Item && null !== this.Run && Range === this.Range && Line === this.Line)
		return true;

	return false;
};
ParaNumbering.prototype.Is_RealContent = function()
{
	return true;
};
ParaNumbering.prototype.Can_AddNumbering = function()
{
	return false;
};
ParaNumbering.prototype.Copy = function()
{
	return new ParaNumbering();
};
ParaNumbering.prototype.Write_ToBinary = function(Writer)
{
	// Long   : Type
	Writer.WriteLong(this.Type);
};
ParaNumbering.prototype.Read_FromBinary = function(Reader)
{
};
ParaNumbering.prototype.GetCalculatedValue = function()
{
	return this.Internal.CalcValue;
};

// TODO: Реализовать табы по точке и с чертой.
var tab_Clear  = 0x00;
var tab_Left   = 0x01;
var tab_Right  = 0x02;
var tab_Center = 0x03;

var tab_Symbol = 0x0022;//0x2192;

/**
 * Класс представляющий элемент табуляции.
 * @constructor
 * @extends {CRunElementBase}
 */
function ParaTab()
{
	CRunElementBase.call(this);

	this.Width        = 0;
	this.WidthVisible = 0;
	this.RealWidth    = 0;

	this.DotWidth        = 0;
	this.UnderscoreWidth = 0;
	this.HyphenWidth     = 0;
	this.Leader          = Asc.c_oAscTabLeader.None;
}
ParaTab.prototype = Object.create(CRunElementBase.prototype);
ParaTab.prototype.constructor = ParaTab;

ParaTab.prototype.Type = para_Tab;
ParaTab.prototype.Draw = function(X, Y, Context)
{
	if (this.WidthVisible > 0.01)
	{
		var sChar = null, nCharWidth = 0;
		switch (this.Leader)
		{
			case Asc.c_oAscTabLeader.Dot:
				sChar      = '.';
				nCharWidth = this.DotWidth;
				break;
			case Asc.c_oAscTabLeader.Heavy:
			case Asc.c_oAscTabLeader.Underscore:
				sChar      = '_';
				nCharWidth = this.UnderscoreWidth;
				break;
			case Asc.c_oAscTabLeader.Hyphen:
				sChar      = '-';
				nCharWidth = this.HyphenWidth;
				break;
			case Asc.c_oAscTabLeader.MiddleDot:
				sChar      = '·';
				nCharWidth = this.MiddleDotWidth;
				break;
		}

		if (null !== sChar && nCharWidth > 0.001)
		{
			Context.SetFontSlot(fontslot_ASCII, 1);
			var nCharsCount = Math.floor(this.WidthVisible / nCharWidth);

			var _X = X + (this.WidthVisible - nCharsCount * nCharWidth) / 2;
			for (var nIndex = 0; nIndex < nCharsCount; ++nIndex, _X += nCharWidth)
				Context.FillText(_X, Y, sChar);
		}
	}

	if (editor && editor.ShowParaMarks)
	{
		Context.p_color(0, 0, 0, 255);
		Context.b_color1(0, 0, 0, 255);

		var X0 = this.Width / 2 - this.RealWidth / 2;

		Context.SetFont({FontFamily : {Name : "ASCW3", Index : -1}, FontSize : 10, Italic : false, Bold : false});

		if (X0 > 0)
			Context.FillText2(X + X0, Y, String.fromCharCode(tab_Symbol), 0, this.Width);
		else
			Context.FillText2(X, Y, String.fromCharCode(tab_Symbol), this.RealWidth - this.Width, this.Width);
	}
};
ParaTab.prototype.Measure = function(Context)
{
	this.DotWidth        = Context.Measure(".").Width;
	this.UnderscoreWidth = Context.Measure("_").Width;
	this.HyphenWidth     = Context.Measure("-").Width * 1.5;
	this.MiddleDotWidth  = Context.Measure("·").Width;

	Context.SetFont({FontFamily : {Name : "ASCW3", Index : -1}, FontSize : 10, Italic : false, Bold : false});
	this.RealWidth = Context.Measure(String.fromCharCode(tab_Symbol)).Width;
};
ParaTab.prototype.SetLeader = function(nLeaderType)
{
	this.Leader = nLeaderType;
};
ParaTab.prototype.Get_Width = function()
{
	return this.Width;
};
ParaTab.prototype.Get_WidthVisible = function()
{
	return this.WidthVisible;
};
ParaTab.prototype.Set_WidthVisible = function(WidthVisible)
{
	this.WidthVisible = WidthVisible;
};
ParaTab.prototype.Copy = function()
{
	return new ParaTab();
};


/**
 * Класс представляющий элемент номер страницы
 * @constructor
 * @extends {CRunElementBase}
 */
function ParaPageNum()
{
	CRunElementBase.call(this);

    this.FontKoef = 1;

    this.NumWidths = [];

    this.Widths = [];
    this.String = [];

    this.Width        = 0;
    this.WidthVisible = 0;

    this.Parent = null;
}
ParaPageNum.prototype = Object.create(CRunElementBase.prototype);
ParaPageNum.prototype.constructor = ParaPageNum;

ParaPageNum.prototype.Type = para_PageNum;
ParaPageNum.prototype.Draw = function(X, Y, Context)
{
	// Value - реальное значение, которое должно быть отрисовано.
	// Align - прилегание параграфа, в котором лежит данный номер страницы.

	var Len = this.String.length;

	var _X = X;
	var _Y = Y;

	Context.SetFontSlot(fontslot_ASCII, this.FontKoef);
	for (var Index = 0; Index < Len; Index++)
	{
		var Char = this.String.charAt(Index);
		Context.FillText(_X, _Y, Char);
		_X += this.Widths[Index];
	}
};
ParaPageNum.prototype.Measure = function (Context, TextPr)
{
	this.FontKoef = TextPr.Get_FontKoef();
	Context.SetFontSlot(fontslot_ASCII, this.FontKoef);

	for (var Index = 0; Index < 10; Index++)
	{
		this.NumWidths[Index] = Context.Measure("" + Index).Width;
	}

	this.Width        = 0;
	this.Height       = 0;
	this.WidthVisible = 0;
};
ParaPageNum.prototype.Get_Width = function()
{
	return this.Width;
};
ParaPageNum.prototype.Get_WidthVisible = function()
{
	return this.WidthVisible;
};
ParaPageNum.prototype.Set_WidthVisible = function(WidthVisible)
{
	this.WidthVisible = WidthVisible;
};
ParaPageNum.prototype.Set_Page = function(PageNum)
{
	this.String = "" + PageNum;
	var Len     = this.String.length;

	var RealWidth = 0;
	for (var Index = 0; Index < Len; Index++)
	{
		var Char = parseInt(this.String.charAt(Index));

		this.Widths[Index] = this.NumWidths[Char];
		RealWidth += this.NumWidths[Char];
	}

	this.Width        = RealWidth;
	this.WidthVisible = RealWidth;
};
ParaPageNum.prototype.SaveRecalculateObject = function(Copy)
{
	return new CPageNumRecalculateObject(this.Type, this.Widths, this.String, this.Width, Copy);
};
ParaPageNum.prototype.LoadRecalculateObject = function(RecalcObj)
{
	this.Widths = RecalcObj.Widths;
	this.String = RecalcObj.String;

	this.Width        = RecalcObj.Width;
	this.WidthVisible = this.Width;
};
ParaPageNum.prototype.PrepareRecalculateObject = function()
{
	this.Widths = [];
	this.String = "";
};
ParaPageNum.prototype.Document_CreateFontCharMap = function(FontCharMap)
{
	var sValue = "1234567890";
	for (var Index = 0; Index < sValue.length; Index++)
	{
		var Char = sValue.charAt(Index);
		FontCharMap.AddChar(Char);
	}
};
ParaPageNum.prototype.Is_RealContent = function()
{
	return true;
};
ParaPageNum.prototype.Can_AddNumbering = function()
{
	return true;
};
ParaPageNum.prototype.Copy = function()
{
	return new ParaPageNum();
};
ParaPageNum.prototype.Write_ToBinary = function(Writer)
{
	// Long   : Type
	Writer.WriteLong(para_PageNum);
}
ParaPageNum.prototype.Read_FromBinary = function(Reader)
{
};
ParaPageNum.prototype.GetPageNumValue = function()
{
	var nPageNum = parseInt(this.String);
	if (isNaN(nPageNum))
		return 1;

	return nPageNum;
};
ParaPageNum.prototype.GetType = function()
{
	return this.Type;
};
/**
 * Выставляем родительский класс
 * @param {ParaRun} oParent
 */
ParaPageNum.prototype.SetParent = function(oParent)
{
	this.Parent = oParent;
};
/**
 * Получаем родительский класс
 * @returns {?ParaRun}
 */
ParaPageNum.prototype.GetParent = function()
{
	return this.Parent;
};

function CPageNumRecalculateObject(Type, Widths, String, Width, Copy)
{
    this.Type   = Type;
    this.Widths = Widths;
    this.String = String;
    this.Width  = Width;

    if ( true === Copy )
    {
        this.Widths = [];
        var Len = Widths.length;
        for ( var Index = 0; Index < Len; Index++ )
            this.Widths[Index] = Widths[Index];
    }
}


/**
 * Класс представляющий символ нумерации у параграфа в презентациях
 * @constructor
 * @extends {CRunElementBase}
 */
function ParaPresentationNumbering()
{
	CRunElementBase.call(this);

    // Эти данные заполняются во время пересчета, перед вызовом Measure
    this.Bullet    = null;
    this.BulletNum = null;
}
ParaPresentationNumbering.prototype = Object.create(CRunElementBase.prototype);
ParaPresentationNumbering.prototype.constructor = ParaPresentationNumbering;

ParaPresentationNumbering.prototype.Type = para_PresentationNumbering;
ParaPresentationNumbering.prototype.Draw = function(X, Y, Context, FirstTextPr, PDSE)
{
	this.Bullet.Draw(X, Y, Context, FirstTextPr, PDSE);
};
ParaPresentationNumbering.prototype.Measure = function (Context, FirstTextPr, Theme)
{
	this.Width        = 0;
	this.Height       = 0;
	this.WidthVisible = 0;

	var Temp = this.Bullet.Measure(Context, FirstTextPr, this.BulletNum, Theme);

	this.Width        = Temp.Width;
	this.WidthVisible = Temp.Width;
};
ParaPresentationNumbering.prototype.Is_RealContent = function()
{
	return true;
};
ParaPresentationNumbering.prototype.Can_AddNumbering = function()
{
	return false;
};
ParaPresentationNumbering.prototype.Copy = function()
{
	return new ParaPresentationNumbering();
};
ParaPresentationNumbering.prototype.Write_ToBinary = function(Writer)
{
	// Long   : Type
	Writer.WriteLong(this.Type);
};
ParaPresentationNumbering.prototype.Read_FromBinary = function(Reader)
{
};
ParaPresentationNumbering.prototype.Check_Range = function(Range, Line)
{
	if (null !== this.Item && null !== this.Run && Range === this.Range && Line === this.Line)
		return true;

	return false;
};


/**
 * Класс представляющий ссылку на сноску.
 * @param {CFootEndnote} Footnote - Ссылка на сноску.
 * @param {string} CustomMark
 * @constructor
 * @extends {CRunElementBase}
 */
function ParaFootnoteReference(Footnote, CustomMark)
{
	this.Footnote   = Footnote;
	this.CustomMark = CustomMark ? CustomMark : undefined;

	this.Width        = 0;
	this.WidthVisible = 0;
	this.Number       = 1;
	this.NumFormat    = Asc.c_oAscNumberingFormat.Decimal;

	this.Run          = null;
	this.Widths       = [];
}
ParaFootnoteReference.prototype = Object.create(CRunElementBase.prototype);
ParaFootnoteReference.prototype.constructor = ParaFootnoteReference;

ParaFootnoteReference.prototype.Type = para_FootnoteReference;
ParaFootnoteReference.prototype.Get_Type = function()
{
	return para_FootnoteReference;
};
ParaFootnoteReference.prototype.Draw = function(X, Y, Context, PDSE)
{
	if (true === this.IsCustomMarkFollows())
		return;

	var TextPr = this.Run.Get_CompiledPr(false);

	var FontKoef = 1;
	if (TextPr.VertAlign !== AscCommon.vertalign_Baseline)
		FontKoef = vertalign_Koef_Size;

	Context.SetFontSlot(fontslot_ASCII, FontKoef);

	var _X = X;
	var T  = this.private_GetString();
	if (this.Widths.length !== T.length)
		return;

	for (var nPos = 0; nPos < T.length; ++nPos)
	{
		var Char = T.charAt(nPos);
		Context.FillText(_X, Y, Char);
		_X += this.Widths[nPos];
	}

	if (editor && editor.ShowParaMarks && Context.DrawFootnoteRect && this.Run)
	{
		var TextAscent = this.Run.TextAscent;
		Context.p_color(0, 0, 0, 255);
		Context.DrawFootnoteRect(X, PDSE.BaseLine - TextAscent, this.Get_Width(), TextAscent);
	}
};
ParaFootnoteReference.prototype.Measure = function(Context, TextPr, MathInfo, Run)
{
	this.Run = Run;
	this.private_Measure();
};
ParaFootnoteReference.prototype.Copy = function()
{
	var oFootnote = this.Footnote.Parent.CreateFootnote();
	oFootnote.Copy2(this.Footnote);
	return new ParaFootnoteReference(oFootnote);
};
ParaFootnoteReference.prototype.Write_ToBinary = function(Writer)
{
	// Long   : Type
	// String : FootnoteId
	// Bool : is undefined mark ?
	// false -> String2 : CustomMark
	Writer.WriteLong(this.Type);
	Writer.WriteString2(this.Footnote.Get_Id());

	if (undefined === this.CustomMark)
	{
		Writer.WriteBool(true);
	}
	else
	{
		Writer.WriteBool(false);
		Writer.WriteString2(this.CustomMark);
	}
};
ParaFootnoteReference.prototype.Read_FromBinary = function(Reader)
{
	// String : FootnoteId
	// Bool : is undefined mark ?
	// false -> String2 : CustomMark
	this.Footnote = g_oTableId.Get_ById(Reader.GetString2());

	if (false === Reader.GetBool())
		this.CustomMark = Reader.GetString2();
};
ParaFootnoteReference.prototype.Get_Footnote = function()
{
	return this.Footnote;
};
ParaFootnoteReference.prototype.UpdateNumber = function(PRS)
{
	if (this.Footnote && true !== PRS.IsFastRecalculate() && PRS.TopDocument instanceof CDocument)
	{
		var nPageAbs    = PRS.GetPageAbs();
		var nColumnAbs  = PRS.GetColumnAbs();
		var nAdditional = PRS.GetFootnoteReferencesCount(this);
		var oSectPr     = PRS.GetSectPr();
		var nNumFormat  = oSectPr.GetFootnoteNumFormat();

		var oLogicDocument       = this.Footnote.Get_LogicDocument();
		var oFootnotesController = oLogicDocument.GetFootnotesController();

		this.NumFormat = nNumFormat;
		this.Number    = oFootnotesController.GetFootnoteNumberOnPage(nPageAbs, nColumnAbs, oSectPr) + nAdditional;

		// Если данная сноска не участвует в нумерации, просто уменьшаем ей номер на 1, для упрощения работы
		if (this.IsCustomMarkFollows())
			this.Number--;

		this.private_Measure();
		this.Footnote.SetNumber(this.Number, oSectPr, this.IsCustomMarkFollows());
	}
	else
	{
		this.Number    = 1;
		this.NumFormat = Asc.c_oAscNumberingFormat.Decimal;
		this.private_Measure();
	}
};
ParaFootnoteReference.prototype.private_Measure = function()
{
	if (!this.Run)
		return;

	if (this.IsCustomMarkFollows())
	{
		this.Width        = 0;
		this.WidthVisible = 0;
		return;
	}

	var oMeasurer = g_oTextMeasurer;

	var TextPr = this.Run.Get_CompiledPr(false);
	var Theme  = this.Run.GetParagraph().Get_Theme();

    var FontKoef = 1;
    if (TextPr.VertAlign !== AscCommon.vertalign_Baseline)
        FontKoef = vertalign_Koef_Size;

	oMeasurer.SetTextPr(TextPr, Theme);
	oMeasurer.SetFontSlot(fontslot_ASCII, FontKoef);

	var X = 0;
	var T = this.private_GetString();
	this.Widths = [];
	for (var nPos = 0; nPos < T.length; ++nPos)
	{
		var Char  = T.charAt(nPos);
		var CharW = oMeasurer.Measure(Char).Width
		this.Widths.push(CharW);
		X += CharW;
	}


	var ResultWidth   = (Math.max((X + TextPr.Spacing), 0) * TEXTWIDTH_DIVIDER) | 0;
	this.Width        = ResultWidth;
	this.WidthVisible = ResultWidth;
};
ParaFootnoteReference.prototype.private_GetString = function()
{
	if (Asc.c_oAscNumberingFormat.Decimal === this.NumFormat)
		return Numbering_Number_To_String(this.Number);
	if (Asc.c_oAscNumberingFormat.LowerRoman === this.NumFormat)
		return Numbering_Number_To_Roman(this.Number, true);
	else if (Asc.c_oAscNumberingFormat.UpperRoman === this.NumFormat)
		return Numbering_Number_To_Roman(this.Number, false);
	else if (Asc.c_oAscNumberingFormat.LowerLetter === this.NumFormat)
		return Numbering_Number_To_Alpha(this.Number, true);
	else if (Asc.c_oAscNumberingFormat.UpperLetter === this.NumFormat)
		return Numbering_Number_To_Alpha(this.Number, false);
	else// if (Asc.c_oAscNumberingFormat.Decimal === this.NumFormat)
		return Numbering_Number_To_String(this.Number);
};
ParaFootnoteReference.prototype.IsCustomMarkFollows = function()
{
	return (undefined !== this.CustomMark ? true : false);
};
ParaFootnoteReference.prototype.GetCustomText = function()
{
	return this.CustomMark;
};
ParaFootnoteReference.prototype.CreateDocumentFontMap = function(FontMap)
{
	if (this.Footnote)
		this.Footnote.Document_CreateFontMap(FontMap);
};
ParaFootnoteReference.prototype.GetAllContentControls = function(arrContentControls)
{
	if (this.Footnote)
		this.Footnote.GetAllContentControls(arrContentControls);
};
ParaFootnoteReference.prototype.GetAllFontNames = function(arrAllFonts)
{
	if (this.Footnote)
		this.Footnote.Document_Get_AllFontNames(arrAllFonts);
};

/**
 * Класс представляющий номер сноски внутри сноски.
 * @param {CFootEndnote} Footnote - Ссылка на сноску.
 * @constructor
 * @extends {ParaFootnoteReference}
 */
function ParaFootnoteRef(Footnote)
{
	ParaFootnoteReference.call(this, Footnote);
}
ParaFootnoteRef.prototype = Object.create(ParaFootnoteReference.prototype);
ParaFootnoteRef.prototype.constructor = ParaFootnoteRef;

ParaFootnoteRef.prototype.Type = para_FootnoteRef;
ParaFootnoteRef.prototype.Get_Type = function()
{
	return para_FootnoteRef;
};
ParaFootnoteRef.prototype.Copy = function()
{
	return new ParaFootnoteRef(this.Get_Footnote());
};
ParaFootnoteRef.prototype.UpdateNumber = function(oFootnote)
{
	this.Footnote = oFootnote;
	if (this.Footnote && this.Footnote instanceof CFootEndnote)
	{
		this.Number    = this.Footnote.GetNumber();
		this.NumFormat = this.Footnote.GetReferenceSectPr().GetFootnoteNumFormat();
		this.private_Measure();
	}
	else
	{
		this.Number    = 1;
		this.NumFormat = Asc.c_oAscNumberingFormat.Decimal;
		this.private_Measure();
	}
};

/**
 * Класс представляющий собой разделитель (который в основном используется для сносок).
 * @constructor
 * @extends {CRunElementBase}
 */
function ParaSeparator()
{
	CRunElementBase.call(this);
	this.LineW = 0;
}
ParaSeparator.prototype = Object.create(CRunElementBase.prototype);
ParaSeparator.prototype.constructor = ParaSeparator;

ParaSeparator.prototype.Type     = para_Separator;
ParaSeparator.prototype.Get_Type = function()
{
	return para_Separator;
};
ParaSeparator.prototype.Draw     = function(X, Y, Context, PDSE)
{
	var l = X, t = PDSE.LineTop, r = X + this.Get_Width(), b = PDSE.BaseLine;

    Context.p_color(0, 0, 0, 255);
	Context.drawHorLineExt(c_oAscLineDrawingRule.Center, (t + b) / 2, l, r, this.LineW, 0, 0);

	if (editor && editor.ShowParaMarks && Context.DrawFootnoteRect)
    {
        Context.DrawFootnoteRect(X, PDSE.LineTop, this.Get_Width(), PDSE.BaseLine - PDSE.LineTop);
    }
};
ParaSeparator.prototype.Measure  = function(Context, TextPr)
{
	this.Width        = (50 * TEXTWIDTH_DIVIDER) | 0;
	this.WidthVisible = (50 * TEXTWIDTH_DIVIDER) | 0;

	this.LineW = (TextPr.FontSize / 18) * g_dKoef_pt_to_mm;
};
ParaSeparator.prototype.Copy     = function()
{
	return new ParaSeparator();
};
ParaSeparator.prototype.UpdateWidth = function(PRS)
{
	var oPara    = PRS.Paragraph;
	var nCurPage = PRS.Page;

	oPara.Parent.Update_ContentIndexing();
	var oLimits = oPara.Parent.Get_PageContentStartPos2(oPara.PageNum, oPara.ColumnNum, nCurPage, oPara.Index);

	var nWidth = (Math.min(50, (oLimits.XLimit - oLimits.X)) * TEXTWIDTH_DIVIDER) | 0;

	this.Width        = nWidth;
	this.WidthVisible = nWidth;
};

/**
 * Класс представляющий собой длинный разделитель (который в основном используется для сносок).
 * @constructor
 * @extends {CRunElementBase}
 */
function ParaContinuationSeparator()
{
	CRunElementBase.call(this);
	this.LineW = 0;
}
ParaContinuationSeparator.prototype = Object.create(CRunElementBase.prototype);
ParaContinuationSeparator.prototype.constructor = ParaContinuationSeparator;

ParaContinuationSeparator.prototype.Type         = para_ContinuationSeparator;
ParaContinuationSeparator.prototype.Get_Type     = function()
{
	return para_ContinuationSeparator;
};
ParaContinuationSeparator.prototype.Draw         = function(X, Y, Context, PDSE)
{
	var l = X, t = PDSE.LineTop, r = X + this.Get_Width(), b = PDSE.BaseLine;

    Context.p_color(0, 0, 0, 255);
	Context.drawHorLineExt(c_oAscLineDrawingRule.Center, (t + b) / 2, l, r, this.LineW, 0, 0);

	if (editor && editor.ShowParaMarks && Context.DrawFootnoteRect)
    {
        Context.DrawFootnoteRect(X, PDSE.LineTop, this.Get_Width(), PDSE.BaseLine - PDSE.LineTop);
    }
};
ParaContinuationSeparator.prototype.Measure      = function(Context, TextPr)
{
	this.Width        = (50 * TEXTWIDTH_DIVIDER) | 0;
	this.WidthVisible = (50 * TEXTWIDTH_DIVIDER) | 0;

	this.LineW = (TextPr.FontSize / 18) * g_dKoef_pt_to_mm;
};
ParaContinuationSeparator.prototype.Copy         = function()
{
	return new ParaContinuationSeparator();
};
ParaContinuationSeparator.prototype.UpdateWidth = function(PRS)
{
	var oPara    = PRS.Paragraph;
	var nCurPage = PRS.Page;

	oPara.Parent.Update_ContentIndexing();
	var oLimits = oPara.Parent.Get_PageContentStartPos2(oPara.PageNum, oPara.ColumnNum, nCurPage, oPara.Index);

	var nWidth = (Math.max(oLimits.XLimit - PRS.X, 50) * TEXTWIDTH_DIVIDER) | 0;

	this.Width        = nWidth;
	this.WidthVisible = nWidth;
};


/**
 * Класс представляющий элемент "количество страниц"
 * @param PageCount
 * @constructor
 * @extends {CRunElementBase}
 */
function ParaPageCount(PageCount)
{
	CRunElementBase.call(this);

	this.FontKoef  = 1;
	this.NumWidths = [];
	this.Widths    = [];
	this.String    = "";
	this.PageCount = undefined !== PageCount ? PageCount : 1;
	this.Parent    = null;
}
ParaPageCount.prototype = Object.create(CRunElementBase.prototype);
ParaPageCount.prototype.constructor = ParaPageCount;

ParaPageCount.prototype.Type = para_PageCount;
ParaPageCount.prototype.Copy = function()
{
	return new ParaPageCount();
};
ParaPageCount.prototype.Is_RealContent = function()
{
	return true;
};
ParaPageCount.prototype.Can_AddNumbering = function()
{
	return true;
};
ParaPageCount.prototype.Measure = function(Context, TextPr)
{
	this.FontKoef = TextPr.Get_FontKoef();
	Context.SetFontSlot(fontslot_ASCII, this.FontKoef);

	for (var Index = 0; Index < 10; Index++)
	{
		this.NumWidths[Index] = Context.Measure("" + Index).Width;
	}

	this.private_UpdateWidth();
};
ParaPageCount.prototype.Draw = function(X, Y, Context)
{
	var Len = this.String.length;

	var _X = X;
	var _Y = Y;

	Context.SetFontSlot(fontslot_ASCII, this.FontKoef);
	for (var Index = 0; Index < Len; Index++)
	{
		var Char = this.String.charAt(Index);
		Context.FillText(_X, _Y, Char);
		_X += this.Widths[Index];
	}
};
ParaPageCount.prototype.Document_CreateFontCharMap = function(FontCharMap)
{
	var sValue = "1234567890";
	for (var Index = 0; Index < sValue.length; Index++)
	{
		var Char = sValue.charAt(Index);
		FontCharMap.AddChar(Char);
	}
};
ParaPageCount.prototype.Update_PageCount = function(nPageCount)
{
	this.PageCount = nPageCount;
	this.private_UpdateWidth();
};
ParaPageCount.prototype.SetNumValue = function(nValue)
{
	this.Update_PageCount(nValue);
};
ParaPageCount.prototype.private_UpdateWidth = function()
{
	this.String = "" + this.PageCount;

	var RealWidth = 0;
	for (var Index = 0, Len = this.String.length; Index < Len; Index++)
	{
		var Char = parseInt(this.String.charAt(Index));

		this.Widths[Index] = this.NumWidths[Char];
		RealWidth += this.NumWidths[Char];
	}

	RealWidth = (RealWidth * TEXTWIDTH_DIVIDER) | 0;

	this.Width        = RealWidth;
	this.WidthVisible = RealWidth;
};
ParaPageCount.prototype.Write_ToBinary = function(Writer)
{
	// Long : Type
	// Long : PageCount
	Writer.WriteLong(this.Type);
	Writer.WriteLong(this.PageCount);
};
ParaPageCount.prototype.Read_FromBinary = function(Reader)
{
	this.PageCount = Reader.GetLong();
};
ParaPageCount.prototype.GetPageCountValue = function()
{
	return this.PageCount;
};
/**
 * Выставляем родительский класс
 * @param {ParaRun} oParent
 */
ParaPageCount.prototype.SetParent = function(oParent)
{
	this.Parent = oParent;
};
/**
 * Получаем родительский класс
 * @returns {?ParaRun}
 */
ParaPageCount.prototype.GetParent = function()
{
	return this.Parent;
};

function ParagraphContent_Read_FromBinary(Reader)
{
	var ElementType = Reader.GetLong();

	var Element = null;
	switch (ElementType)
	{
		case para_TextPr:
		case para_Drawing:
		case para_HyperlinkStart:
		case para_InlineLevelSdt:
		case para_Bookmark:
		{
			var ElementId = Reader.GetString2();
			Element       = g_oTableId.Get_ById(ElementId);
			return Element;
		}
		case para_RunBase               : Element = new CRunElementBase(); break;
		case para_Text                  : Element = new ParaText(); break;
		case para_Space                 : Element = new ParaSpace(); break;
		case para_End                   : Element = new ParaEnd(); break;
		case para_NewLine               : Element = new ParaNewLine(); break;
		case para_Numbering             : Element = new ParaNumbering(); break;
		case para_Tab                   : Element = new ParaTab(); break;
		case para_PageNum               : Element = new ParaPageNum(); break;
		case para_Math_Placeholder      : Element = new CMathText(); break;
		case para_Math_Text             : Element = new CMathText(); break;
		case para_Math_BreakOperator    : Element = new CMathText(); break;
		case para_Math_Ampersand        : Element = new CMathAmp(); break;
		case para_PresentationNumbering : Element = new ParaPresentationNumbering(); break;
		case para_FootnoteReference     : Element = new ParaFootnoteReference(); break;
		case para_FootnoteRef           : Element = new ParaFootnoteRef(); break;
		case para_Separator             : Element = new ParaSeparator(); break;
		case para_ContinuationSeparator : Element = new ParaContinuationSeparator(); break;
		case para_PageCount             : Element = new ParaPageCount(); break;
		case para_FieldChar             : Element = new ParaFieldChar(); break;
		case para_InstrText             : Element = new ParaInstrText(); break;
	}

	if (null != Element)
		Element.Read_FromBinary(Reader);

	return Element;
}

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].ParaNewLine   = ParaNewLine;
window['AscCommonWord'].ParaText      = ParaText;
window['AscCommonWord'].ParaSpace     = ParaSpace;
window['AscCommonWord'].ParaPageNum   = ParaPageNum;
window['AscCommonWord'].ParaPageCount = ParaPageCount;

window['AscCommonWord'].break_Page = break_Page;
window['AscCommonWord'].break_Column = break_Column;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 02.11.2016
 * Time: 16:36
 */

/**
 * Класс представляющий собой настройки текста (сейчас используется как настройка текста для конца параграфа)
 * @param oProps
 * @constructor
 * @extends {CRunElementBase}
 */
function ParaTextPr(oProps)
{
	CRunElementBase.call(this);

	this.Id = AscCommon.g_oIdCounter.Get_NewId();

	this.Type      = para_TextPr;
	this.Value     = new CTextPr();
	this.Parent    = null;
	this.CalcValue = this.Value;

	this.Width        = 0;
	this.Height       = 0;
	this.WidthVisible = 0;

	if (oProps)
		this.Value.Set_FromObject(oProps);

	// Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
	g_oTableId.Add(this, this.Id);
}
ParaTextPr.prototype = Object.create(CRunElementBase.prototype);
ParaTextPr.prototype.constructor = ParaTextPr;

ParaTextPr.prototype.Type = para_TextPr;
ParaTextPr.prototype.Get_Type = function()
{
	return this.Type;
};
ParaTextPr.prototype.Copy = function()
{
	var ParaTextPr_new = new ParaTextPr();
	ParaTextPr_new.Set_Value(this.Value);
	return ParaTextPr_new;
};
ParaTextPr.prototype.Is_RealContent = function()
{
	return true;
};
ParaTextPr.prototype.Can_AddNumbering = function()
{
	return false;
};
ParaTextPr.prototype.Get_Id = function()
{
	return this.Id;
};
ParaTextPr.prototype.GetParagraph = function()
{
	if (this.Parent instanceof Paragraph)
		return this.Parent;

	return null;
};
ParaTextPr.prototype.IsParagraphSimpleChanges = function()
{
	return true;
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для изменения свойств
//----------------------------------------------------------------------------------------------------------------------
ParaTextPr.prototype.Apply_TextPr = function(TextPr)
{
	if (undefined !== TextPr.Bold)
		this.Set_Bold(TextPr.Bold);

	if (undefined !== TextPr.Italic)
		this.Set_Italic(TextPr.Italic);

	if (undefined !== TextPr.Strikeout)
		this.Set_Strikeout(TextPr.Strikeout);

	if (undefined !== TextPr.Underline)
		this.Set_Underline(TextPr.Underline);

	if (undefined !== TextPr.FontSize)
		this.Set_FontSize(TextPr.FontSize);

	if (undefined !== TextPr.FontSizeCS)
		this.Set_FontSizeCS(TextPr.FontSizeCS);

	if (undefined !== TextPr.Color)
	{
		this.Set_Color(TextPr.Color);

		if (undefined !== this.Value.Unifill)
		{
			this.Set_Unifill(undefined);
		}

		if (undefined !== this.Value.TextFill)
		{
			this.Set_TextFill(undefined);
		}
	}

	if (undefined !== TextPr.VertAlign)
		this.Set_VertAlign(TextPr.VertAlign);

	if (undefined !== TextPr.HighLight)
		this.Set_HighLight(TextPr.HighLight);

	if (undefined !== TextPr.RStyle)
		this.Set_RStyle(TextPr.RStyle);

	if (undefined !== TextPr.Spacing)
		this.Set_Spacing(TextPr.Spacing);

	if (undefined !== TextPr.DStrikeout)
		this.Set_DStrikeout(TextPr.DStrikeout);

	if (undefined !== TextPr.Caps)
		this.Set_Caps(TextPr.Caps);

	if (undefined !== TextPr.SmallCaps)
		this.Set_SmallCaps(TextPr.SmallCaps);

	if (undefined !== TextPr.Position)
		this.Set_Position(TextPr.Position);

	if (undefined != TextPr.RFonts)
		this.Set_RFonts2(TextPr.RFonts);

	if (undefined != TextPr.Lang)
		this.Set_Lang(TextPr.Lang);

	if (undefined != TextPr.Unifill)
	{
		this.Set_Unifill(TextPr.Unifill.createDuplicate());
		if (undefined != this.Value.Color)
		{
			this.Set_Color(undefined);
		}
		if (undefined != this.Value.TextFill)
		{
			this.Set_TextFill(undefined);
		}
	}
	if (undefined != TextPr.TextOutline)
	{
		this.Set_TextOutline(TextPr.TextOutline);
	}
	if (undefined != TextPr.TextFill)
	{
		this.Set_TextFill(TextPr.TextFill);
		if (undefined != this.Value.Color)
		{
			this.Set_Color(undefined);
		}
		if (undefined != this.Value.Unifill)
		{
			this.Set_Unifill(undefined);
		}
	}
};
ParaTextPr.prototype.Clear_Style = function()
{
	// Пока удаляем все кроме настроек языка
	if (undefined != this.Value.Bold)
		this.Set_Bold(undefined);

	if (undefined != this.Value.Italic)
		this.Set_Italic(undefined);

	if (undefined != this.Value.Strikeout)
		this.Set_Strikeout(undefined);

	if (undefined != this.Value.Underline)
		this.Set_Underline(undefined);

	if (undefined != this.Value.FontSize)
		this.Set_FontSize(undefined);

	if (undefined != this.Value.Color)
		this.Set_Color(undefined);

	if (undefined != this.Value.Unifill)
		this.Set_Unifill(undefined);

	if (undefined != this.Value.VertAlign)
		this.Set_VertAlign(undefined);

	if (undefined != this.Value.HighLight)
		this.Set_HighLight(undefined);

	if (undefined != this.Value.RStyle)
		this.Set_RStyle(undefined);

	if (undefined != this.Value.Spacing)
		this.Set_Spacing(undefined);

	if (undefined != this.Value.DStrikeout)
		this.Set_DStrikeout(undefined);

	if (undefined != this.Value.Caps)
		this.Set_Caps(undefined);

	if (undefined != this.Value.SmallCaps)
		this.Set_SmallCaps(undefined);

	if (undefined != this.Value.Position)
		this.Set_Position(undefined);

	if (undefined != this.Value.RFonts.Ascii)
		this.Set_RFonts_Ascii(undefined);

	if (undefined != this.Value.RFonts.HAnsi)
		this.Set_RFonts_HAnsi(undefined);

	if (undefined != this.Value.RFonts.CS)
		this.Set_RFonts_CS(undefined);

	if (undefined != this.Value.RFonts.EastAsia)
		this.Set_RFonts_EastAsia(undefined);

	if (undefined != this.Value.RFonts.Hint)
		this.Set_RFonts_Hint(undefined);

	if (undefined != this.Value.TextFill)
		this.Set_TextFill(undefined);

	if (undefined != this.Value.TextOutline)
		this.Set_TextOutline(undefined);
};
ParaTextPr.prototype.Set_Bold = function(Value)
{
	if (null === Value)
		Value = undefined;

	if (this.Value.Bold === Value)
		return;

	History.Add(new CChangesParaTextPrBold(this, this.Value.Bold, Value));
	this.Value.Bold = Value;
};
ParaTextPr.prototype.Set_Italic = function(Value)
{
	if (null === Value)
		Value = undefined;

	if (this.Value.Italic === Value)
		return;

	History.Add(new CChangesParaTextPrItalic(this, this.Value.Italic, Value));
	this.Value.Italic = Value;
};
ParaTextPr.prototype.Set_Strikeout = function(Value)
{
	if (null === Value)
		Value = undefined;

	if (this.Value.Strikeout === Value)
		return;

	History.Add(new CChangesParaTextPrStrikeout(this, this.Value.Strikeout, Value));
	this.Value.Strikeout = Value;
};
ParaTextPr.prototype.Set_Underline = function(Value)
{
	if (null === Value)
		Value = undefined;

	if (this.Value.Underline === Value)
		return;

	History.Add(new CChangesParaTextPrUnderline(this, this.Value.Underline, Value));
	this.Value.Underline = Value;
};
ParaTextPr.prototype.Set_FontSize = function(Value)
{
	if (null === Value)
		Value = undefined;

	if (this.Value.FontSize === Value)
		return;

	History.Add(new CChangesParaTextPrFontSize(this, this.Value.FontSize, Value));
	this.Value.FontSize = Value;
};
ParaTextPr.prototype.Set_Color = function(Value)
{
	if (null === Value)
		Value = undefined;

	History.Add(new CChangesParaTextPrColor(this, this.Value.Color, Value));
	this.Value.Color = Value;
};
ParaTextPr.prototype.Set_VertAlign = function(Value)
{
	if (null === Value)
		Value = undefined;

	if (this.Value.VertAlign === Value)
		return;

	History.Add(new CChangesParaTextPrVertAlign(this, this.Value.VertAlign, Value));
	this.Value.VertAlign = Value;
};
ParaTextPr.prototype.Set_HighLight = function(Value)
{
	if (null === Value)
		Value = undefined;

	History.Add(new CChangesParaTextPrHighLight(this, this.Value.HighLight, Value));
	this.Value.HighLight = Value;
};
ParaTextPr.prototype.Set_RStyle = function(Value)
{
	if (null === Value)
		Value = undefined;

	if (this.Value.RStyle === Value)
		return;

	History.Add(new CChangesParaTextPrRStyle(this, this.Value.RStyle, Value));
	this.Value.RStyle = Value;
};
ParaTextPr.prototype.Set_Spacing = function(Value)
{
	if (null === Value)
		Value = undefined;

	if (this.Value.Spacing === Value)
		return;

	History.Add(new CChangesParaTextPrSpacing(this, this.Value.Spacing, Value));
	this.Value.Spacing = Value;
};
ParaTextPr.prototype.Set_DStrikeout = function(Value)
{
	if (null === Value)
		Value = undefined;

	if (this.Value.DStrikeout === Value)
		return;

	History.Add(new CChangesParaTextPrDStrikeout(this, this.Value.DStrikeout, Value));
	this.Value.DStrikeout = Value;
};
ParaTextPr.prototype.Set_Caps = function(Value)
{
	if (null === Value)
		Value = undefined;

	if (this.Value.Caps === Value)
		return;

	History.Add(new CChangesParaTextPrCaps(this, this.Value.Caps, Value));
	this.Value.Caps = Value;
};
ParaTextPr.prototype.Set_SmallCaps = function(Value)
{
	if (null === Value)
		Value = undefined;

	if (this.Value.SmallCaps === Value)
		return;

	History.Add(new CChangesParaTextPrSmallCaps(this, this.Value.SmallCaps, Value));
	this.Value.SmallCaps = Value;
};
ParaTextPr.prototype.Set_Position = function(Value)
{
	if (null === Value)
		Value = undefined;

	if (this.Value.Position === Value)
		return;

	History.Add(new CChangesParaTextPrPosition(this, this.Value.Position, Value));
	this.Value.Position = Value;
};
ParaTextPr.prototype.Set_Value = function(Value)
{
	if (!Value || !(Value instanceof CTextPr) || true === this.Value.Is_Equal(Value))
		return;

	History.Add(new CChangesParaTextPrValue(this, this.Value, Value));
	this.Value = Value;
};
ParaTextPr.prototype.Set_RFonts = function(Value)
{
	var _Value = Value ? Value : new CRFonts();
	History.Add(new CChangesParaTextPrRFonts(this, this.Value.RFonts, _Value));
	this.Value.RFonts = _Value;
};
ParaTextPr.prototype.Set_RFonts2 = function(RFonts)
{
	if (undefined != RFonts)
	{
		if (undefined !== RFonts.Ascii)
			this.Set_RFonts_Ascii(RFonts.Ascii);

		if (undefined !== RFonts.HAnsi)
			this.Set_RFonts_HAnsi(RFonts.HAnsi);

		if (undefined !== RFonts.CS)
			this.Set_RFonts_CS(RFonts.CS);

		if (undefined !== RFonts.EastAsia)
			this.Set_RFonts_EastAsia(RFonts.EastAsia);

		if (undefined !== RFonts.Hint)
			this.Set_RFonts_Hint(RFonts.Hint);
	}
};
ParaTextPr.prototype.Set_RFonts_Ascii = function(Value)
{
	if (null === Value)
		Value = undefined;

	History.Add(new CChangesParaTextPrRFontsAscii(this, this.Value.RFonts.Ascii, Value));
	this.Value.RFonts.Ascii = Value;
};
ParaTextPr.prototype.Set_RFonts_HAnsi = function(Value)
{
	if (null === Value)
		Value = undefined;

	History.Add(new CChangesParaTextPrRFontsHAnsi(this, this.Value.RFonts.HAnsi, Value));
	this.Value.RFonts.HAnsi = Value;
};
ParaTextPr.prototype.Set_RFonts_CS = function(Value)
{
	if (null === Value)
		Value = undefined;

	History.Add(new CChangesParaTextPrRFontsCS(this, this.Value.RFonts.CS, Value));
	this.Value.RFonts.CS = Value;
};
ParaTextPr.prototype.Set_RFonts_EastAsia = function(Value)
{
	if (null === Value)
		Value = undefined;

	History.Add(new CChangesParaTextPrRFontsEastAsia(this, this.Value.RFonts.EastAsia, Value));
	this.Value.RFonts.EastAsia = Value;
};
ParaTextPr.prototype.Set_RFonts_Hint = function(Value)
{
	if (null === Value)
		Value = undefined;

	History.Add(new CChangesParaTextPrRFontsHint(this, this.Value.RFonts.Hint, Value));
	this.Value.RFonts.Hint = Value;
};
ParaTextPr.prototype.Set_Lang = function(Value)
{
	var _Value = new CLang();
	if (Value)
		_Value.Set_FromObject(Value);

	History.Add(new CChangesParaTextPrLang(this, this.Value.Lang, Value));
	this.Value.Lang = _Value;
};
ParaTextPr.prototype.Set_Lang_Bidi = function(Value)
{
	History.Add(new CChangesParaTextPrLangBidi(this, this.Value.Lang.Bidi, Value));
	this.Value.Lang.Bidi = Value;
};
ParaTextPr.prototype.Set_Lang_EastAsia = function(Value)
{
	History.Add(new CChangesParaTextPrLangEastAsia(this, this.Value.Lang.EastAsia, Value));
	this.Value.Lang.EastAsia = Value;
};
ParaTextPr.prototype.Set_Lang_Val = function(Value)
{
	History.Add(new CChangesParaTextPrLangVal(this, this.Value.Lang.Val, Value));
	this.Value.Lang.Val = Value;
};
ParaTextPr.prototype.Set_Unifill = function(Value)
{
	History.Add(new CChangesParaTextPrUnifill(this, this.Value.Unifill, Value));
	this.Value.Unifill = Value;
};
ParaTextPr.prototype.Set_FontSizeCS = function(Value)
{
	if (null === Value)
		Value = undefined;

	if (this.Value.FontSizeCS === Value)
		return;

	History.Add(new CChangesParaTextPrFontSizeCS(this, this.Value.FontSizeCS, Value));
	this.Value.FontSizeCS = Value;
};
ParaTextPr.prototype.Set_TextOutline = function(Value)
{
	History.Add(new CChangesParaTextPrTextOutline(this, this.Value.TextOutline, Value));
	this.Value.TextOutline = Value;
};
ParaTextPr.prototype.Set_TextFill = function(Value)
{
	History.Add(new CChangesParaTextPrTextFill(this, this.Value.TextFill, Value));
	this.Value.TextFill = Value;
};
/**
 * Выставляем настройки (если какая-либо undefined, то такая настройка удаляется)
 * @param {CTextPr} oTextPr
 */
ParaTextPr.prototype.SetPr = function(oTextPr)
{
	if (!oTextPr)
		oTextPr = new CTextPr();

	this.Set_Value(oTextPr);
};
//----------------------------------------------------------------------------------------------------------------------
// Undo/Redo функции
//----------------------------------------------------------------------------------------------------------------------
ParaTextPr.prototype.Get_ParentObject_or_DocumentPos = function()
{
	if (null != this.Parent)
		return this.Parent.Get_ParentObject_or_DocumentPos();
};
ParaTextPr.prototype.Refresh_RecalcData = function(Data)
{
	if (undefined !== this.Parent && null !== this.Parent)
		this.Parent.Refresh_RecalcData2();
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с совместным редактирования
//----------------------------------------------------------------------------------------------------------------------
ParaTextPr.prototype.Write_ToBinary = function(Writer)
{
	// Long   : Type
	// String : Id

	Writer.WriteLong(this.Type);
	Writer.WriteString2(this.Id);
};
ParaTextPr.prototype.Write_ToBinary2 = function(Writer)
{
	Writer.WriteLong(AscDFH.historyitem_type_TextPr);

	// Long   : Type
	// String : Id
	// Long   : Value

	Writer.WriteLong(this.Type);
	Writer.WriteString2(this.Id);
	this.Value.Write_ToBinary(Writer);
};
ParaTextPr.prototype.Read_FromBinary2 = function(Reader)
{
	this.Type = Reader.GetLong();
	this.Id   = Reader.GetString2();

	this.Value.Clear();
	this.Value.Read_FromBinary(Reader);
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].ParaTextPr = ParaTextPr;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 02.11.2016
 * Time: 16:42
 */

AscDFH.changesFactory[AscDFH.historyitem_TextPr_Bold]            = CChangesParaTextPrBold;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_Italic]          = CChangesParaTextPrItalic;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_Strikeout]       = CChangesParaTextPrStrikeout;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_Underline]       = CChangesParaTextPrUnderline;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_FontSize]        = CChangesParaTextPrFontSize;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_Color]           = CChangesParaTextPrColor;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_VertAlign]       = CChangesParaTextPrVertAlign;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_HighLight]       = CChangesParaTextPrHighLight;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_RStyle]          = CChangesParaTextPrRStyle;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_Spacing]         = CChangesParaTextPrSpacing;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_DStrikeout]      = CChangesParaTextPrDStrikeout;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_Caps]            = CChangesParaTextPrCaps;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_SmallCaps]       = CChangesParaTextPrSmallCaps;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_Position]        = CChangesParaTextPrPosition;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_Value]           = CChangesParaTextPrValue;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_RFonts]          = CChangesParaTextPrRFonts;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_RFonts_Ascii]    = CChangesParaTextPrRFontsAscii;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_RFonts_HAnsi]    = CChangesParaTextPrRFontsHAnsi;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_RFonts_CS]       = CChangesParaTextPrRFontsCS;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_RFonts_EastAsia] = CChangesParaTextPrRFontsEastAsia;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_RFonts_Hint]     = CChangesParaTextPrRFontsHint;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_Lang]            = CChangesParaTextPrLang;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_Lang_Bidi]       = CChangesParaTextPrLangBidi;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_Lang_EastAsia]   = CChangesParaTextPrLangEastAsia;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_Lang_Val]        = CChangesParaTextPrLangVal;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_Unifill]         = CChangesParaTextPrUnifill;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_FontSizeCS]      = CChangesParaTextPrFontSizeCS;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_Outline]         = CChangesParaTextPrTextOutline;
AscDFH.changesFactory[AscDFH.historyitem_TextPr_Fill]            = CChangesParaTextPrTextFill;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_Bold]            = [
	AscDFH.historyitem_TextPr_Bold,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_Italic]          = [
	AscDFH.historyitem_TextPr_Italic,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_Strikeout]       = [
	AscDFH.historyitem_TextPr_Strikeout,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_Underline]       = [
	AscDFH.historyitem_TextPr_Underline,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_FontSize]        = [
	AscDFH.historyitem_TextPr_FontSize,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_Color]           = [
	AscDFH.historyitem_TextPr_Color,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_VertAlign]       = [
	AscDFH.historyitem_TextPr_VertAlign,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_HighLight]       = [
	AscDFH.historyitem_TextPr_HighLight,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_RStyle]          = [
	AscDFH.historyitem_TextPr_RStyle,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_Spacing]         = [
	AscDFH.historyitem_TextPr_Spacing,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_DStrikeout]      = [
	AscDFH.historyitem_TextPr_DStrikeout,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_Caps]            = [
	AscDFH.historyitem_TextPr_Caps,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_SmallCaps]       = [
	AscDFH.historyitem_TextPr_SmallCaps,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_Position]        = [
	AscDFH.historyitem_TextPr_Position,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_Value]           = [
	AscDFH.historyitem_TextPr_Bold,
	AscDFH.historyitem_TextPr_Italic,
	AscDFH.historyitem_TextPr_Strikeout,
	AscDFH.historyitem_TextPr_Underline,
	AscDFH.historyitem_TextPr_FontSize,
	AscDFH.historyitem_TextPr_Color,
	AscDFH.historyitem_TextPr_VertAlign,
	AscDFH.historyitem_TextPr_HighLight,
	AscDFH.historyitem_TextPr_RStyle,
	AscDFH.historyitem_TextPr_Spacing,
	AscDFH.historyitem_TextPr_DStrikeout,
	AscDFH.historyitem_TextPr_Caps,
	AscDFH.historyitem_TextPr_SmallCaps,
	AscDFH.historyitem_TextPr_Position,
	AscDFH.historyitem_TextPr_Value,
	AscDFH.historyitem_TextPr_RFonts,
	AscDFH.historyitem_TextPr_RFonts_Ascii,
	AscDFH.historyitem_TextPr_RFonts_HAnsi,
	AscDFH.historyitem_TextPr_RFonts_CS,
	AscDFH.historyitem_TextPr_RFonts_EastAsia,
	AscDFH.historyitem_TextPr_RFonts_Hint,
	AscDFH.historyitem_TextPr_Lang,
	AscDFH.historyitem_TextPr_Lang_Bidi,
	AscDFH.historyitem_TextPr_Lang_EastAsia,
	AscDFH.historyitem_TextPr_Lang_Val,
	AscDFH.historyitem_TextPr_Unifill,
	AscDFH.historyitem_TextPr_FontSizeCS,
	AscDFH.historyitem_TextPr_Outline,
	AscDFH.historyitem_TextPr_Fill
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_RFonts]          = [
	AscDFH.historyitem_TextPr_RFonts,
	AscDFH.historyitem_TextPr_RFonts_Ascii,
	AscDFH.historyitem_TextPr_RFonts_HAnsi,
	AscDFH.historyitem_TextPr_RFonts_CS,
	AscDFH.historyitem_TextPr_RFonts_EastAsia,
	AscDFH.historyitem_TextPr_RFonts_Hint,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_RFonts_Ascii]    = [
	AscDFH.historyitem_TextPr_RFonts_Ascii,
	AscDFH.historyitem_TextPr_RFonts,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_RFonts_HAnsi]    = [
	AscDFH.historyitem_TextPr_RFonts_HAnsi,
	AscDFH.historyitem_TextPr_RFonts,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_RFonts_CS]       = [
	AscDFH.historyitem_TextPr_RFonts_CS,
	AscDFH.historyitem_TextPr_RFonts,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_RFonts_EastAsia] = [
	AscDFH.historyitem_TextPr_RFonts_EastAsia,
	AscDFH.historyitem_TextPr_RFonts,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_RFonts_Hint]     = [
	AscDFH.historyitem_TextPr_RFonts_Hint,
	AscDFH.historyitem_TextPr_RFonts,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_Lang]            = [
	AscDFH.historyitem_TextPr_Lang,
	AscDFH.historyitem_TextPr_Lang_Bidi,
	AscDFH.historyitem_TextPr_Lang_EastAsia,
	AscDFH.historyitem_TextPr_Lang_Val,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_Lang_Bidi]       = [
	AscDFH.historyitem_TextPr_Lang_Bidi,
	AscDFH.historyitem_TextPr_Lang,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_Lang_EastAsia]   = [
	AscDFH.historyitem_TextPr_Lang_EastAsia,
	AscDFH.historyitem_TextPr_Lang,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_Lang_Val]        = [
	AscDFH.historyitem_TextPr_Lang_Val,
	AscDFH.historyitem_TextPr_Lang,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_Unifill]         = [
	AscDFH.historyitem_TextPr_Unifill,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_FontSizeCS]      = [
	AscDFH.historyitem_TextPr_FontSizeCS,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_Outline]         = [
	AscDFH.historyitem_TextPr_Outline,
	AscDFH.historyitem_TextPr_Value
];
AscDFH.changesRelationMap[AscDFH.historyitem_TextPr_Fill]            = [
	AscDFH.historyitem_TextPr_Fill,
	AscDFH.historyitem_TextPr_Value
];

/**
 * Общая функция объединения изменений, которые зависят только от себя и AscDFH.historyitem_TextPr_Value
 * @param oChange
 * @returns {boolean}
 */
function private_ParaTextPrChangesOnMergeValue(oChange)
{
	if (oChange.Class !== this.Class)
		return true;

	if (oChange.Type === this.Type || oChange.Type === AscDFH.historyitem_TextPr_Value)
		return false;

	return true;
}
/**
 * Общая функция объединения изменений, которые зависят от себя, AscDFH.historyitem_TextPr_Value,
 * AscDFH.historyitem_TextPr_Lang
 * @param oChange
 * @returns {boolean}
 */
function private_ParaTextPrChangesOnMergeLangValue(oChange)
{
	if (oChange.Class !== this.Class)
		return true;

	if (oChange.Type === this.Type || oChange.Type === AscDFH.historyitem_TextPr_Value || oChange.Type === AscDFH.historyitem_TextPr_Lang)
		return false;

	return true;
}
/**
 * Общая функция объединения изменений, которые зависят от себя, AscDFH.historyitem_TextPr_Value,
 * AscDFH.historyitem_TextPr_RFonts
 * @param oChange
 * @returns {boolean}
 */
function private_ParaTextPrChangesOnMergeRFontsValue(oChange)
{
	if (oChange.Class !== this.Class)
		return true;

	if (oChange.Type === this.Type || oChange.Type === AscDFH.historyitem_TextPr_Value || oChange.Type === AscDFH.historyitem_TextPr_RFonts)
		return false;

	return true;
}
//----------------------------------------------------------------------------------------------------------------------

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesParaTextPrBold(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrBold.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesParaTextPrBold.prototype.constructor = CChangesParaTextPrBold;
CChangesParaTextPrBold.prototype.Type = AscDFH.historyitem_TextPr_Bold;
CChangesParaTextPrBold.prototype.private_SetValue = function(Value)
{
	this.Class.Value.Bold = Value;
};
CChangesParaTextPrBold.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesParaTextPrItalic(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrItalic.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesParaTextPrItalic.prototype.constructor = CChangesParaTextPrItalic;
CChangesParaTextPrItalic.prototype.Type = AscDFH.historyitem_TextPr_Italic;
CChangesParaTextPrItalic.prototype.private_SetValue = function(Value)
{
	this.Class.Value.Italic = Value;
};
CChangesParaTextPrItalic.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesParaTextPrStrikeout(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrStrikeout.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesParaTextPrStrikeout.prototype.constructor = CChangesParaTextPrStrikeout;
CChangesParaTextPrStrikeout.prototype.Type = AscDFH.historyitem_TextPr_Strikeout;
CChangesParaTextPrStrikeout.prototype.private_SetValue = function(Value)
{
	this.Class.Value.Strikeout = Value;
};
CChangesParaTextPrStrikeout.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesParaTextPrUnderline(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrUnderline.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesParaTextPrUnderline.prototype.constructor = CChangesParaTextPrUnderline;
CChangesParaTextPrUnderline.prototype.Type = AscDFH.historyitem_TextPr_Underline;
CChangesParaTextPrUnderline.prototype.private_SetValue = function(Value)
{
	this.Class.Value.Underline = Value;
};
CChangesParaTextPrUnderline.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleProperty}
 */
function CChangesParaTextPrFontSize(Class, Old, New, Color)
{
	AscDFH.CChangesBaseDoubleProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrFontSize.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
CChangesParaTextPrFontSize.prototype.constructor = CChangesParaTextPrFontSize;
CChangesParaTextPrFontSize.prototype.Type = AscDFH.historyitem_TextPr_FontSize;
CChangesParaTextPrFontSize.prototype.private_SetValue = function(Value)
{
	this.Class.Value.FontSize = Value;
};
CChangesParaTextPrFontSize.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParaTextPrColor(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrColor.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParaTextPrColor.prototype.constructor = CChangesParaTextPrColor;
CChangesParaTextPrColor.prototype.Type = AscDFH.historyitem_TextPr_Color;
CChangesParaTextPrColor.prototype.private_SetValue = function(Value)
{
	this.Class.Value.Color = Value;
};
CChangesParaTextPrColor.prototype.private_CreateObject = function()
{
	return new CDocumentColor(0, 0, 0, false);
};
CChangesParaTextPrColor.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesParaTextPrVertAlign(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrVertAlign.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesParaTextPrVertAlign.prototype.constructor = CChangesParaTextPrVertAlign;
CChangesParaTextPrVertAlign.prototype.Type = AscDFH.historyitem_TextPr_VertAlign;
CChangesParaTextPrVertAlign.prototype.private_SetValue = function(Value)
{
	this.Class.Value.VertAlign = Value;
};
CChangesParaTextPrVertAlign.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaTextPrHighLight(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrHighLight.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaTextPrHighLight.prototype.constructor = CChangesParaTextPrHighLight;
CChangesParaTextPrHighLight.prototype.Type = AscDFH.historyitem_TextPr_HighLight;
CChangesParaTextPrHighLight.prototype.private_SetValue = function(Value)
{
	this.Class.Value.HighLight = Value;
};
CChangesParaTextPrHighLight.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is "none" New ?
	// 4-bit : Is undefined New ?
	// 5-bit : Is "none" New ?
	// Variable(?CDocumentColor) : New (если 2 и 3 биты нулевые)
	// Variable(?CDocumentColor) : Old (если 4 и 5 биты нулевые)

	var nFlags = 0;

	if (false !== this.Color)
		nFlags |= 1;

	if (undefined === this.New)
		nFlags |= 2;
	else if (highlight_None === this.New)
		nFlags |= 4;

	if (undefined === this.Old)
		nFlags |= 8;
	else if (highlight_None === this.Old)
		nFlags |= 16;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New && highlight_None !== this.New)
		this.New.Write_ToBinary(Writer);

	if (undefined !== this.Old && highlight_None !== this.Old)
		this.Old.Write_ToBinary(Writer);
};
CChangesParaTextPrHighLight.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is "none" New ?
	// 4-bit : Is undefined New ?
	// 5-bit : Is "none" New ?
	// Variable(?CDocumentColor) : New (если 2 и 3 биты нулевые)
	// Variable(?CDocumentColor) : Old (если 4 и 5 биты нулевые)

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.Color = true;
	else
		this.Color = false;

	if (nFlags & 2)
	{
		this.New = undefined;
	}
	else if (nFlags & 4)
	{
		this.New = highlight_None;
	}
	else
	{
		this.New = new CDocumentColor(0, 0, 0);
		this.New.Read_FromBinary(Reader);
	}

	if (nFlags & 8)
	{
		this.Old = undefined;
	}
	else if (nFlags & 16)
	{
		this.Old = highlight_None;
	}
	else
	{
		this.Old = new CDocumentColor(0, 0, 0);
		this.Old.Read_FromBinary(Reader);
	}
};
CChangesParaTextPrHighLight.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseStringProperty}
 */
function CChangesParaTextPrRStyle(Class, Old, New, Color)
{
	AscDFH.CChangesBaseStringProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrRStyle.prototype = Object.create(AscDFH.CChangesBaseStringProperty.prototype);
CChangesParaTextPrRStyle.prototype.constructor = CChangesParaTextPrRStyle;
CChangesParaTextPrRStyle.prototype.Type = AscDFH.historyitem_TextPr_RStyle;
CChangesParaTextPrRStyle.prototype.private_SetValue = function(Value)
{
	this.Class.Value.RStyle = Value;
};
CChangesParaTextPrRStyle.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleProperty}
 */
function CChangesParaTextPrSpacing(Class, Old, New, Color)
{
	AscDFH.CChangesBaseDoubleProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrSpacing.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
CChangesParaTextPrSpacing.prototype.constructor = CChangesParaTextPrSpacing;
CChangesParaTextPrSpacing.prototype.Type = AscDFH.historyitem_TextPr_Spacing;
CChangesParaTextPrSpacing.prototype.private_SetValue = function(Value)
{
	this.Class.Value.Spacing = Value;
};
CChangesParaTextPrSpacing.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesParaTextPrDStrikeout(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrDStrikeout.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesParaTextPrDStrikeout.prototype.constructor = CChangesParaTextPrDStrikeout;
CChangesParaTextPrDStrikeout.prototype.Type = AscDFH.historyitem_TextPr_DStrikeout;
CChangesParaTextPrDStrikeout.prototype.private_SetValue = function(Value)
{
	this.Class.Value.DStrikeout = Value;
};
CChangesParaTextPrDStrikeout.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesParaTextPrCaps(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrCaps.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesParaTextPrCaps.prototype.constructor = CChangesParaTextPrCaps;
CChangesParaTextPrCaps.prototype.Type = AscDFH.historyitem_TextPr_Caps;
CChangesParaTextPrCaps.prototype.private_SetValue = function(Value)
{
	this.Class.Value.Caps = Value;
};
CChangesParaTextPrCaps.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesParaTextPrSmallCaps(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrSmallCaps.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesParaTextPrSmallCaps.prototype.constructor = CChangesParaTextPrSmallCaps;
CChangesParaTextPrSmallCaps.prototype.Type = AscDFH.historyitem_TextPr_SmallCaps;
CChangesParaTextPrSmallCaps.prototype.private_SetValue = function(Value)
{
	this.Class.Value.SmallCaps = Value;
};
CChangesParaTextPrSmallCaps.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleProperty}
 */
function CChangesParaTextPrPosition(Class, Old, New, Color)
{
	AscDFH.CChangesBaseDoubleProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrPosition.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
CChangesParaTextPrPosition.prototype.constructor = CChangesParaTextPrPosition;
CChangesParaTextPrPosition.prototype.Type = AscDFH.historyitem_TextPr_Position;
CChangesParaTextPrPosition.prototype.private_SetValue = function(Value)
{
	this.Class.Value.Position = Value;
};
CChangesParaTextPrPosition.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParaTextPrValue(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrValue.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParaTextPrValue.prototype.constructor = CChangesParaTextPrValue;
CChangesParaTextPrValue.prototype.Type = AscDFH.historyitem_TextPr_Value;
CChangesParaTextPrValue.prototype.private_SetValue = function(Value)
{
	this.Class.Value = Value;
};
CChangesParaTextPrValue.prototype.private_CreateObject = function()
{
	return new CTextPr();
};
CChangesParaTextPrValue.prototype.private_IsCreateEmptyObject = function()
{
	return true;
};
CChangesParaTextPrValue.prototype.Merge = function(oChange)
{
	if (oChange.Class !== this.Class)
		return true;

	if (oChange.Type === this.Type)
		return false;

	if (!this.New)
		this.New = new CTextPr();

	switch (oChange.Type)
	{
		case AscDFH.historyitem_TextPr_Bold:
		{
			this.New.Bold = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_Italic:
		{
			this.New.Italic = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_Strikeout:
		{
			this.New.Strikeout = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_Underline:
		{
			this.New.Underline = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_FontSize:
		{
			this.New.FontSize = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_Color:
		{
			this.New.Color = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_VertAlign:
		{
			this.New.VertAlign = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_HighLight:
		{
			this.New.HighLight = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_RStyle:
		{
			this.New.RStyle = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_Spacing:
		{
			this.New.Spacing = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_DStrikeout:
		{
			this.New.DStrikeout = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_Caps:
		{
			this.New.Caps = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_SmallCaps:
		{
			this.New.SmallCaps = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_Position:
		{
			this.New.Position = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_RFonts:
		{
			this.New.RFonts = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_RFonts_Ascii:
		{
			if (!this.New.RFonts)
				this.New.RFonts = new CRFonts();

			this.New.RFonts.Ascii = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_RFonts_HAnsi:
		{
			if (!this.New.RFonts)
				this.New.RFonts = new CRFonts();

			this.New.RFonts.HAnsi = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_RFonts_CS:
		{
			if (!this.New.RFonts)
				this.New.RFonts = new CRFonts();

			this.New.RFonts.CS = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_RFonts_EastAsia:
		{
			if (!this.New.RFonts)
				this.New.RFonts = new CRFonts();

			this.New.RFonts.EastAsia = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_RFonts_Hint:
		{
			if (!this.New.RFonts)
				this.New.RFonts = new CRFonts();

			this.New.RFonts.Hint = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_Lang:
		{
			this.New.Lang = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_Lang_Bidi:
		{
			if (!this.New.Lang)
				this.New.Lang = new CLang();

			this.New.Lang.Bidi = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_Lang_EastAsia:
		{
			if (!this.New.Lang)
				this.New.Lang = new CLang();

			this.New.Lang.EastAsia = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_Lang_Val:
		{
			if (!this.New.Lang)
				this.New.Lang = new CLang();

			this.New.Lang.Val = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_Unifill:
		{
			this.New.Unifill = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_FontSizeCS:
		{
			this.New.FontSizeCS = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_Outline:
		{
			this.New.TextOutline = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_Fill:
		{
			this.New.TextFill = oChange.New;
			break;
		}
	}

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParaTextPrRFonts(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrRFonts.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParaTextPrRFonts.prototype.constructor = CChangesParaTextPrRFonts;
CChangesParaTextPrRFonts.prototype.Type = AscDFH.historyitem_TextPr_RFonts;
CChangesParaTextPrRFonts.prototype.private_SetValue = function(Value)
{
	this.Class.Value.RFonts = Value;
};
CChangesParaTextPrRFonts.prototype.private_CreateObject = function()
{
	return new CRFonts();
};
CChangesParaTextPrRFonts.prototype.private_IsCreateEmptyObject = function()
{
	return true;
};
CChangesParaTextPrRFonts.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type || oChange.Type === AscDFH.historyitem_TextPr_Value)
		return false;

	if (!this.New)
		this.New = new CRFonts();

	switch (oChange.Type)
	{
		case AscDFH.historyitem_TextPr_RFonts_Ascii:
		{
			this.New.Ascii = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_RFonts_HAnsi:
		{
			this.New.HAnsi = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_RFonts_CS:
		{
			this.New.CS = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_RFonts_EastAsia:
		{
			this.New.EastAsia = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_RFonts_Hint:
		{
			this.New.Hint = oChange.New;
			break;
		}
	}

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaTextPrRFontsAscii(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrRFontsAscii.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaTextPrRFontsAscii.prototype.constructor = CChangesParaTextPrRFontsAscii;
CChangesParaTextPrRFontsAscii.prototype.Type = AscDFH.historyitem_TextPr_RFonts_Ascii;
CChangesParaTextPrRFontsAscii.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = 0;

	if (false !== this.Color)
		nFlags |= 1;

	if (undefined === this.New)
		nFlags |= 2;

	if (undefined === this.Old)
		nFlags |= 4;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New)
		Writer.WriteString2(this.New.Name);

	if (undefined !== this.Old)
		Writer.WriteString2(this.Old.Name);
};
CChangesParaTextPrRFontsAscii.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.Color = true;
	else
		this.Color = false;

	if (nFlags & 2)
	{
		this.New = undefined;
	}
	else
	{
		this.New = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}

	if (nFlags & 4)
	{
		this.Old = undefined;
	}
	else
	{
		this.Old = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}
};
CChangesParaTextPrRFontsAscii.prototype.private_SetValue = function(Value)
{
	this.Class.Value.RFonts.Ascii = Value;
};
CChangesParaTextPrRFontsAscii.prototype.Merge = private_ParaTextPrChangesOnMergeRFontsValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaTextPrRFontsHAnsi(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrRFontsHAnsi.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaTextPrRFontsHAnsi.prototype.constructor = CChangesParaTextPrRFontsHAnsi;
CChangesParaTextPrRFontsHAnsi.prototype.Type = AscDFH.historyitem_TextPr_RFonts_HAnsi;
CChangesParaTextPrRFontsHAnsi.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = 0;

	if (false !== this.Color)
		nFlags |= 1;

	if (undefined === this.New)
		nFlags |= 2;

	if (undefined === this.Old)
		nFlags |= 4;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New)
		Writer.WriteString2(this.New.Name);

	if (undefined !== this.Old)
		Writer.WriteString2(this.Old.Name);
};
CChangesParaTextPrRFontsHAnsi.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.Color = true;
	else
		this.Color = false;

	if (nFlags & 2)
	{
		this.New = undefined;
	}
	else
	{
		this.New = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}

	if (nFlags & 4)
	{
		this.Old = undefined;
	}
	else
	{
		this.Old = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}
};
CChangesParaTextPrRFontsHAnsi.prototype.private_SetValue = function(Value)
{
	this.Class.Value.RFonts.HAnsi = Value;
};
CChangesParaTextPrRFontsHAnsi.prototype.Merge = private_ParaTextPrChangesOnMergeRFontsValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaTextPrRFontsCS(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrRFontsCS.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaTextPrRFontsCS.prototype.constructor = CChangesParaTextPrRFontsCS;
CChangesParaTextPrRFontsCS.prototype.Type = AscDFH.historyitem_TextPr_RFonts_CS;
CChangesParaTextPrRFontsCS.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = 0;

	if (false !== this.Color)
		nFlags |= 1;

	if (undefined === this.New)
		nFlags |= 2;

	if (undefined === this.Old)
		nFlags |= 4;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New)
		Writer.WriteString2(this.New.Name);

	if (undefined !== this.Old)
		Writer.WriteString2(this.Old.Name);
};
CChangesParaTextPrRFontsCS.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.Color = true;
	else
		this.Color = false;

	if (nFlags & 2)
	{
		this.New = undefined;
	}
	else
	{
		this.New = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}

	if (nFlags & 4)
	{
		this.Old = undefined;
	}
	else
	{
		this.Old = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}
};
CChangesParaTextPrRFontsCS.prototype.private_SetValue = function(Value)
{
	this.Class.Value.RFonts.CS = Value;
};
CChangesParaTextPrRFontsCS.prototype.Merge = private_ParaTextPrChangesOnMergeRFontsValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaTextPrRFontsEastAsia(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrRFontsEastAsia.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaTextPrRFontsEastAsia.prototype.constructor = CChangesParaTextPrRFontsEastAsia;
CChangesParaTextPrRFontsEastAsia.prototype.Type = AscDFH.historyitem_TextPr_RFonts_EastAsia;
CChangesParaTextPrRFontsEastAsia.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = 0;

	if (false !== this.Color)
		nFlags |= 1;

	if (undefined === this.New)
		nFlags |= 2;

	if (undefined === this.Old)
		nFlags |= 4;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New)
		Writer.WriteString2(this.New.Name);

	if (undefined !== this.Old)
		Writer.WriteString2(this.Old.Name);
};
CChangesParaTextPrRFontsEastAsia.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.Color = true;
	else
		this.Color = false;

	if (nFlags & 2)
	{
		this.New = undefined;
	}
	else
	{
		this.New = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}

	if (nFlags & 4)
	{
		this.Old = undefined;
	}
	else
	{
		this.Old = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}
};
CChangesParaTextPrRFontsEastAsia.prototype.private_SetValue = function(Value)
{
	this.Class.Value.RFonts.EastAsia = Value;
};
CChangesParaTextPrRFontsEastAsia.prototype.Merge = private_ParaTextPrChangesOnMergeRFontsValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesParaTextPrRFontsHint(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrRFontsHint.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesParaTextPrRFontsHint.prototype.constructor = CChangesParaTextPrRFontsHint;
CChangesParaTextPrRFontsHint.prototype.Type = AscDFH.historyitem_TextPr_RFonts_Hint;
CChangesParaTextPrRFontsHint.prototype.private_SetValue = function(Value)
{
	this.Class.Value.RFonts.Hint = Value;
};
CChangesParaTextPrRFontsHint.prototype.Merge = private_ParaTextPrChangesOnMergeRFontsValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParaTextPrLang(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrLang.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParaTextPrLang.prototype.constructor = CChangesParaTextPrLang;
CChangesParaTextPrLang.prototype.Type = AscDFH.historyitem_TextPr_Lang;
CChangesParaTextPrLang.prototype.private_SetValue = function(Value)
{
	this.Class.Value.Lang = Value;
};
CChangesParaTextPrLang.prototype.private_CreateObject = function()
{
	return new CLang();
};
CChangesParaTextPrLang.prototype.private_IsCreateEmptyObject = function()
{
	return true;
};
CChangesParaTextPrLang.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (AscDFH.historyitem_TextPr_Lang === oChange.Type || AscDFH.historyitem_TextPr_Value === oChange.Type)
		return false;

	if (!this.New)
		this.New = new CLang();

	switch (oChange.Type)
	{
		case AscDFH.historyitem_TextPr_Lang_Bidi:
		{
			this.New.Bidi = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_Lang_EastAsia:
		{
			this.New.EastAsia = oChange.New;
			break;
		}
		case AscDFH.historyitem_TextPr_Lang_Val:
		{
			this.New.Val = oChange.New;
			break;
		}
	}

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesParaTextPrLangBidi(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrLangBidi.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesParaTextPrLangBidi.prototype.constructor = CChangesParaTextPrLangBidi;
CChangesParaTextPrLangBidi.prototype.Type = AscDFH.historyitem_TextPr_Lang_Bidi;
CChangesParaTextPrLangBidi.prototype.private_SetValue = function(Value)
{
	this.Class.Value.Lang.Bidi = Value;
};
CChangesParaTextPrLangBidi.prototype.Merge = private_ParaTextPrChangesOnMergeLangValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesParaTextPrLangEastAsia(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrLangEastAsia.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesParaTextPrLangEastAsia.prototype.constructor = CChangesParaTextPrLangEastAsia;
CChangesParaTextPrLangEastAsia.prototype.Type = AscDFH.historyitem_TextPr_Lang_EastAsia;
CChangesParaTextPrLangEastAsia.prototype.private_SetValue = function(Value)
{
	this.Class.Value.Lang.EastAsia = Value;
};
CChangesParaTextPrLangEastAsia.prototype.Merge = private_ParaTextPrChangesOnMergeLangValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesParaTextPrLangVal(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrLangVal.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesParaTextPrLangVal.prototype.constructor = CChangesParaTextPrLangVal;
CChangesParaTextPrLangVal.prototype.Type = AscDFH.historyitem_TextPr_Lang_Val;
CChangesParaTextPrLangVal.prototype.private_SetValue = function(Value)
{
	this.Class.Value.Lang.Val = Value;
};
CChangesParaTextPrLangVal.prototype.Merge = private_ParaTextPrChangesOnMergeLangValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParaTextPrUnifill(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrUnifill.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParaTextPrUnifill.prototype.constructor = CChangesParaTextPrUnifill;
CChangesParaTextPrUnifill.prototype.Type = AscDFH.historyitem_TextPr_Unifill;
CChangesParaTextPrUnifill.prototype.private_SetValue = function(Value)
{
	this.Class.Value.Unifill = Value;
};
CChangesParaTextPrUnifill.prototype.private_CreateObject = function()
{
	return new AscFormat.CUniFill();
};
CChangesParaTextPrUnifill.prototype.Load = function(Color)
{
	this.Redo();

	var Unifill = this.Class.Value.Unifill;
	if (AscCommon.CollaborativeEditing
		&& Unifill
		&& Unifill.fill
		&& Unifill.fill.type === Asc.c_oAscFill.FILL_TYPE_BLIP
		&& typeof Unifill.fill.RasterImageId === "string"
		&& Unifill.fill.RasterImageId.length > 0)
	{
		AscCommon.CollaborativeEditing.Add_NewImage(Unifill.fill.RasterImageId);
	}
};
CChangesParaTextPrUnifill.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleProperty}
 */
function CChangesParaTextPrFontSizeCS(Class, Old, New, Color)
{
	AscDFH.CChangesBaseDoubleProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrFontSizeCS.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
CChangesParaTextPrFontSizeCS.prototype.constructor = CChangesParaTextPrFontSizeCS;
CChangesParaTextPrFontSizeCS.prototype.Type = AscDFH.historyitem_TextPr_FontSizeCS;
CChangesParaTextPrFontSizeCS.prototype.private_SetValue = function(Value)
{
	this.Class.Value.FontSizeCS = Value;
};
CChangesParaTextPrFontSizeCS.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParaTextPrTextOutline(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrTextOutline.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParaTextPrTextOutline.prototype.constructor = CChangesParaTextPrTextOutline;
CChangesParaTextPrTextOutline.prototype.Type = AscDFH.historyitem_TextPr_Outline;
CChangesParaTextPrTextOutline.prototype.private_SetValue = function(Value)
{
	this.Class.Value.TextOutline = Value;
};
CChangesParaTextPrTextOutline.prototype.private_CreateObject = function()
{
	return new AscFormat.CLn();
};
CChangesParaTextPrTextOutline.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParaTextPrTextFill(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParaTextPrTextFill.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParaTextPrTextFill.prototype.constructor = CChangesParaTextPrTextFill;
CChangesParaTextPrTextFill.prototype.Type = AscDFH.historyitem_TextPr_Fill;
CChangesParaTextPrTextFill.prototype.private_SetValue = function(Value)
{
	this.Class.Value.TextFill = Value;
};
CChangesParaTextPrTextFill.prototype.private_CreateObject = function()
{
	return new AscFormat.CUniFill();
};
CChangesParaTextPrTextFill.prototype.Merge = private_ParaTextPrChangesOnMergeValue;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 03.11.2016
 * Time: 11:37
 */

var drawing_Inline = 0x01;
var drawing_Anchor = 0x02;

var WRAPPING_TYPE_NONE           = 0x00;
var WRAPPING_TYPE_SQUARE         = 0x01;
var WRAPPING_TYPE_THROUGH        = 0x02;
var WRAPPING_TYPE_TIGHT          = 0x03;
var WRAPPING_TYPE_TOP_AND_BOTTOM = 0x04;

var WRAP_HIT_TYPE_POINT   = 0x00;
var WRAP_HIT_TYPE_SECTION = 0x01;

/**
 * Оберточный класс для автофигур и картинок. Именно он непосредственно лежит в ране.
 * @constructor
 * @extends {CRunElementBase}
 */
function ParaDrawing(W, H, GraphicObj, DrawingDocument, DocumentContent, Parent)
{
	CRunElementBase.call(this);

	this.Id          = AscCommon.g_oIdCounter.Get_NewId();
	this.DrawingType = drawing_Inline;
	this.GraphicObj  = GraphicObj;

	this.X      = 0;
	this.Y      = 0;
	this.Width  = 0;
	this.Height = 0;

	this.PageNum = 0;
	this.LineNum = 0;
	this.YOffset = 0;

	this.DocumentContent = DocumentContent;
	this.DrawingDocument = DrawingDocument;
	this.Parent          = Parent;

	this.LogicDocument = DrawingDocument ? DrawingDocument.m_oLogicDocument : null;

	// Расстояние до окружающего текста
	this.Distance = {
		T : 0,
		B : 0,
		L : 0,
		R : 0
	};

	// Расположение в таблице
	this.LayoutInCell = true;

	// Z-order
	this.RelativeHeight = undefined;

	//
	this.SimplePos = {
		Use : false,
		X   : 0,
		Y   : 0
	};

	// Ширина и высота
	this.Extent = {
		W : W,
		H : H
	};

	this.EffectExtent = {
		L : 0,
		T : 0,
		R : 0,
		B : 0
	};

	this.docPr = new AscFormat.CNvPr();

	this.SizeRelH = undefined;
	this.SizeRelV = undefined;
	//{RelativeFrom      : c_oAscRelativeFromH.Column, Percent: ST_PositivePercentage}

	this.AllowOverlap = true;

	//привязка к параграфу
	this.Locked = null;

	//скрытые drawing'и
	this.Hidden = null;

	// Позиция по горизонтали
	this.PositionH = {
		RelativeFrom : c_oAscRelativeFromH.Column, // Относительно чего вычисляем координаты
		Align        : false,                      // true : В поле Value лежит тип прилегания, false - в поле Value
												   // лежит точное значени
		Value        : 0,                          //
		Percent      : false                       // Значение Valuе задано в процентах
	};

	// Позиция по горизонтали
	this.PositionV = {
		RelativeFrom : c_oAscRelativeFromV.Paragraph, // Относительно чего вычисляем координаты
		Align        : false,                         // true : В поле Value лежит тип прилегания, false - в поле Value
													  // лежит точное значени
		Value        : 0,                             //
		Percent      : false                          // Значение Valuе задано в процентах
	};

	// Данный поля используются для перемещения Flow-объекта
	this.PositionH_Old = undefined;
	this.PositionV_Old = undefined;

	this.Internal_Position = new CAnchorPosition();

	// Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
	//--------------------------------------------------------
	this.selectX      = 0;
	this.selectY      = 0;
	this.wrappingType = WRAPPING_TYPE_THROUGH;
	this.useWrap      = true;

	if (typeof CWrapPolygon !== "undefined")
		this.wrappingPolygon = new CWrapPolygon(this);

	this.document        = editor.WordControl.m_oLogicDocument;
	this.drawingDocument = DrawingDocument;
	this.graphicObjects  = editor.WordControl.m_oLogicDocument.DrawingObjects;
	this.selected        = false;

	this.behindDoc    = false;
	this.bNoNeedToAdd = false;

	this.pageIndex = -1;
	this.Lock      = new AscCommon.CLock();

	this.ParaMath = null;

	this.SkipOnRecalculate = false;
	//for clip
	this.LineTop = null;
	this.LineBottom = null;
	//------------------------------------------------------------
	g_oTableId.Add(this, this.Id);

	if (this.graphicObjects)
	{
		this.Set_RelativeHeight(this.graphicObjects.getZIndex());
		if (History.Is_On() && !g_oTableId.m_bTurnOff)
		{
			this.graphicObjects.addGraphicObject(this);
		}
	}
}
ParaDrawing.prototype = Object.create(CRunElementBase.prototype);
ParaDrawing.prototype.constructor = ParaDrawing;

ParaDrawing.prototype.Type = para_Drawing;
ParaDrawing.prototype.Get_Type = function()
{
	return this.Type;
};
ParaDrawing.prototype.Get_Width = function()
{
	return this.Width;
};
ParaDrawing.prototype.Get_WidthVisible = function()
{
	return this.WidthVisible;
};
ParaDrawing.prototype.Set_WidthVisible = function(WidthVisible)
{
	this.WidthVisible = WidthVisible;
};
ParaDrawing.prototype.GetSelectedContent = function(SelectedContent)
{
	if (this.GraphicObj && this.GraphicObj.GetSelectedContent)
	{
		this.GraphicObj.GetSelectedContent(SelectedContent);
	}
};
ParaDrawing.prototype.Search_GetId = function(bNext, bCurrent)
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.Search_GetId === "function")
		return this.GraphicObj.Search_GetId(bNext, bCurrent);
	return null;
};

ParaDrawing.prototype.CheckCorrect = function(){
	if(!this.GraphicObj){
		return false;
	}
	if(this.GraphicObj && this.GraphicObj.checkCorrect){
		return this.GraphicObj.checkCorrect();
	}
	return true;
};

ParaDrawing.prototype.GetAllDrawingObjects = function(DrawingObjects)
{
	if (null == DrawingObjects)
	{
		DrawingObjects = [];
	}
	if (this.GraphicObj.GetAllDrawingObjects)
	{
		this.GraphicObj.GetAllDrawingObjects(DrawingObjects);
	}
};
ParaDrawing.prototype.canRotate = function()
{
	return isRealObject(this.GraphicObj) && typeof this.GraphicObj.canRotate == "function" && this.GraphicObj.canRotate();
};
ParaDrawing.prototype.GetParagraph = function()
{
	return this.Parent;
};
ParaDrawing.prototype.Get_Run = function()
{
	if (this.Parent)
		return this.Parent.Get_DrawingObjectRun(this.Id);

	return null;
};
ParaDrawing.prototype.Get_Props = function(OtherProps)
{
	var Props    = {};
	Props.Width  = this.GraphicObj.extX;
	Props.Height = this.GraphicObj.extY;
	if (drawing_Inline === this.DrawingType)
		Props.WrappingStyle = c_oAscWrapStyle2.Inline;
	else if (WRAPPING_TYPE_NONE === this.wrappingType)
		Props.WrappingStyle = ( this.behindDoc === true ? c_oAscWrapStyle2.Behind : c_oAscWrapStyle2.InFront );
	else
	{
		switch (this.wrappingType)
		{
			case WRAPPING_TYPE_SQUARE         :
				Props.WrappingStyle = c_oAscWrapStyle2.Square;
				break;
			case WRAPPING_TYPE_TIGHT          :
				Props.WrappingStyle = c_oAscWrapStyle2.Tight;
				break;
			case WRAPPING_TYPE_THROUGH        :
				Props.WrappingStyle = c_oAscWrapStyle2.Through;
				break;
			case WRAPPING_TYPE_TOP_AND_BOTTOM :
				Props.WrappingStyle = c_oAscWrapStyle2.TopAndBottom;
				break;
			default                           :
				Props.WrappingStyle = c_oAscWrapStyle2.Inline;
				break;
		}
	}

	if (drawing_Inline === this.DrawingType)
	{
		Props.Paddings =
		{
			Left   : AscFormat.DISTANCE_TO_TEXT_LEFTRIGHT,
			Right  : AscFormat.DISTANCE_TO_TEXT_LEFTRIGHT,
			Top    : 0,
			Bottom : 0
		};
	}
	else
	{
		var oDistance  = this.Get_Distance();
		Props.Paddings =
		{
			Left   : oDistance.L,
			Right  : oDistance.R,
			Top    : oDistance.T,
			Bottom : oDistance.B
		};
	}

	Props.AllowOverlap = this.AllowOverlap;

	Props.Position =
	{
		X : this.X,
		Y : this.Y
	};

	Props.PositionH =
	{
		RelativeFrom : this.PositionH.RelativeFrom,
		UseAlign     : this.PositionH.Align,
		Align        : ( true === this.PositionH.Align ? this.PositionH.Value : undefined ),
		Value        : ( true === this.PositionH.Align ? 0 : this.PositionH.Value ),
		Percent      : this.PositionH.Percent
	};

	Props.PositionV =
	{
		RelativeFrom : this.PositionV.RelativeFrom,
		UseAlign     : this.PositionV.Align,
		Align        : ( true === this.PositionV.Align ? this.PositionV.Value : undefined ),
		Value        : ( true === this.PositionV.Align ? 0 : this.PositionV.Value ),
		Percent      : this.PositionV.Percent
	};


	if (this.SizeRelH && this.SizeRelH.Percent > 0)
	{
		Props.SizeRelH =
		{
			RelativeFrom : AscFormat.ConvertRelSizeHToRelPosition(this.SizeRelH.RelativeFrom),
			Value        : (this.SizeRelH.Percent * 100) >> 0
		};
	}

	if (this.SizeRelV && this.SizeRelV.Percent > 0)
	{
		Props.SizeRelV =
		{
			RelativeFrom : AscFormat.ConvertRelSizeVToRelPosition(this.SizeRelV.RelativeFrom),
			Value        : (this.SizeRelV.Percent * 100) >> 0
		};
	}

	Props.Internal_Position = this.Internal_Position;

	Props.Locked        = this.Lock.Is_Locked();
	var ParentParagraph = this.Get_ParentParagraph();
	if (ParentParagraph && undefined !== ParentParagraph.Parent)
	{
		var DocContent = ParentParagraph.Parent;
		if (true === DocContent.Is_DrawingShape() || (DocContent.GetTopDocumentContent() instanceof CFootEndnote))
			Props.CanBeFlow = false;
	}

    Props.title = this.docPr.title !== null ? this.docPr.title : undefined;
    Props.description = this.docPr.descr !== null ? this.docPr.descr : undefined;

	if (null != OtherProps && undefined != OtherProps)
	{
		// Соединяем
		if (undefined === OtherProps.Width || 0.001 > Math.abs(Props.Width - OtherProps.Width))
			Props.Width = undefined;

		if (undefined === OtherProps.Height || 0.001 > Math.abs(Props.Height - OtherProps.Height))
			Props.Height = undefined;

		if (undefined === OtherProps.WrappingStyle || Props.WrappingStyle != OtherProps.WrappingStyle)
			Props.WrappingStyle = undefined;

		if (undefined === OtherProps.ImageUrl || Props.ImageUrl != OtherProps.ImageUrl)
			Props.ImageUrl = undefined;

		if (undefined === OtherProps.Paddings.Left || 0.001 > Math.abs(Props.Paddings.Left - OtherProps.Paddings.Left))
			Props.Paddings.Left = undefined;

		if (undefined === OtherProps.Paddings.Right || 0.001 > Math.abs(Props.Paddings.Right - OtherProps.Paddings.Right))
			Props.Paddings.Right = undefined;

		if (undefined === OtherProps.Paddings.Top || 0.001 > Math.abs(Props.Paddings.Top - OtherProps.Paddings.Top))
			Props.Paddings.Top = undefined;

		if (undefined === OtherProps.Paddings.Bottom || 0.001 > Math.abs(Props.Paddings.Bottom - OtherProps.Paddings.Bottom))
			Props.Paddings.Bottom = undefined;

		if (undefined === OtherProps.AllowOverlap || Props.AllowOverlap != OtherProps.AllowOverlap)
			Props.AllowOverlap = undefined;

		if (undefined === OtherProps.Position.X || 0.001 > Math.abs(Props.Position.X - OtherProps.Position.X))
			Props.Position.X = undefined;

		if (undefined === OtherProps.Position.Y || 0.001 > Math.abs(Props.Position.Y - OtherProps.Position.Y))
			Props.Position.Y = undefined;

		if (undefined === OtherProps.PositionH.RelativeFrom || Props.PositionH.RelativeFrom != OtherProps.PositionH.RelativeFrom)
			Props.PositionH.RelativeFrom = undefined;

		if (undefined === OtherProps.PositionH.UseAlign || Props.PositionH.UseAlign != OtherProps.PositionH.UseAlign)
			Props.PositionH.UseAlign = undefined;

		if (Props.PositionH.RelativeFrom === OtherProps.PositionH.RelativeFrom && Props.PositionH.UseAlign === OtherProps.PositionH.UseAlign)
		{
			if (true != Props.PositionH.UseAlign && 0.001 > Math.abs(Props.PositionH.Value - OtherProps.PositionH.Value))
				Props.PositionH.Value = undefined;

			if (true === Props.PositionH.UseAlign && Props.PositionH.Align != OtherProps.PositionH.Align)
				Props.PositionH.Align = undefined;
		}

		if (undefined === OtherProps.PositionV.RelativeFrom || Props.PositionV.RelativeFrom != OtherProps.PositionV.RelativeFrom)
			Props.PositionV.RelativeFrom = undefined;

		if (undefined === OtherProps.PositionV.UseAlign || Props.PositionV.UseAlign != OtherProps.PositionV.UseAlign)
			Props.PositionV.UseAlign = undefined;

		if (Props.PositionV.RelativeFrom === OtherProps.PositionV.RelativeFrom && Props.PositionV.UseAlign === OtherProps.PositionV.UseAlign)
		{
			if (true != Props.PositionV.UseAlign && 0.001 > Math.abs(Props.PositionV.Value - OtherProps.PositionV.Value))
				Props.PositionV.Value = undefined;

			if (true === Props.PositionV.UseAlign && Props.PositionV.Align != OtherProps.PositionV.Align)
				Props.PositionV.Align = undefined;
		}


		if (false === OtherProps.Locked)
			Props.Locked = false;

		if (false === OtherProps.CanBeFlow || false === Props.CanBeFlow)
			Props.CanBeFlow = false;
		else
			Props.CanBeFlow = true;

		if(undefined === OtherProps.title || Props.title !== OtherProps.title){
			Props.title = undefined;
		}

		if(undefined === OtherProps.description || Props.description !== OtherProps.description){
			Props.description = undefined;
		}
	}

	return Props;
};
ParaDrawing.prototype.Is_UseInDocument = function()
{
	if (this.Parent)
	{
		var Run = this.Parent.Get_DrawingObjectRun(this.Id);
		if (Run)
		{
			return Run.Is_UseInDocument(this.Get_Id());
		}
	}
	return false;
};
ParaDrawing.prototype.CheckGroupSizes = function()
{
	if (this.GraphicObj && this.GraphicObj.CheckGroupSizes)
	{
		this.GraphicObj.CheckGroupSizes();
	}
};
ParaDrawing.prototype.Set_DrawingType = function(DrawingType)
{
	History.Add(new CChangesParaDrawingDrawingType(this, this.DrawingType, DrawingType));
	this.DrawingType = DrawingType;
};
ParaDrawing.prototype.Set_WrappingType = function(WrapType)
{
	History.Add(new CChangesParaDrawingWrappingType(this, this.wrappingType, WrapType));
	this.wrappingType = WrapType;
};
ParaDrawing.prototype.Set_Distance = function(L, T, R, B)
{
	var oDistance = this.Get_Distance();
	if (!AscFormat.isRealNumber(L))
	{
		L = oDistance.L;
	}
	if (!AscFormat.isRealNumber(T))
	{
		T = oDistance.T;
	}
	if (!AscFormat.isRealNumber(R))
	{
		R = oDistance.R;
	}
	if (!AscFormat.isRealNumber(B))
	{
		B = oDistance.B;
	}

	History.Add(new CChangesParaDrawingDistance(this,
		{
			Left   : this.Distance.L,
			Top    : this.Distance.T,
			Right  : this.Distance.R,
			Bottom : this.Distance.B
		},
		{
			Left   : L,
			Top    : T,
			Right  : R,
			Bottom : B
		}));

	this.Distance.L = L;
	this.Distance.R = R;
	this.Distance.T = T;
	this.Distance.B = B;
};
ParaDrawing.prototype.Set_AllowOverlap = function(AllowOverlap)
{
	History.Add(new CChangesParaDrawingAllowOverlap(this, this.AllowOverlap, AllowOverlap));
	this.AllowOverlap = AllowOverlap;
};
ParaDrawing.prototype.Set_PositionH = function(RelativeFrom, Align, Value, Percent)
{
	History.Add(new CChangesParaDrawingPositionH(this,
		{
			RelativeFrom : this.PositionH.RelativeFrom,
			Align        : this.PositionH.Align,
			Value        : this.PositionH.Value,
			Percent      : this.PositionH.Percent
		},
		{
			RelativeFrom : RelativeFrom,
			Align        : Align,
			Value        : Value,
			Percent      : Percent
		}));
	this.PositionH.RelativeFrom = RelativeFrom;
	this.PositionH.Align        = Align;
	this.PositionH.Value        = Value;
	this.PositionH.Percent      = Percent;
};
ParaDrawing.prototype.Set_PositionV = function(RelativeFrom, Align, Value, Percent)
{
	History.Add(new CChangesParaDrawingPositionV(this,
		{
			RelativeFrom : this.PositionV.RelativeFrom,
			Align        : this.PositionV.Align,
			Value        : this.PositionV.Value,
			Percent      : this.PositionV.Percent
		},
		{
			RelativeFrom : RelativeFrom,
			Align        : Align,
			Value        : Value,
			Percent      : Percent
		}));

	this.PositionV.RelativeFrom = RelativeFrom;
	this.PositionV.Align        = Align;
	this.PositionV.Value        = Value;
	this.PositionV.Percent      = Percent;
};
ParaDrawing.prototype.Set_BehindDoc = function(BehindDoc)
{
	History.Add(new CChangesParaDrawingBehindDoc(this, this.behindDoc, BehindDoc));
	this.behindDoc = BehindDoc;
};
ParaDrawing.prototype.Set_GraphicObject = function(graphicObject)
{
	var oldId = isRealObject(this.GraphicObj) ? this.GraphicObj.Get_Id() : null;
	var newId = isRealObject(graphicObject) ? graphicObject.Get_Id() : null;

	History.Add(new CChangesParaDrawingGraphicObject(this, oldId, newId));

	if (graphicObject && graphicObject.handleUpdateExtents)
		graphicObject.handleUpdateExtents();

	this.GraphicObj = graphicObject;
};
ParaDrawing.prototype.setSimplePos = function(use, x, y)
{
	History.Add(new CChangesParaDrawingSimplePos(this,
		{
			Use : this.SimplePos.Use,
			X   : this.SimplePos.X,
			Y   : this.SimplePos.Y
		},
		{
			Use : use,
			X   : x,
			Y   : y
		}));

	this.SimplePos.Use = use;
	this.SimplePos.X   = x;
	this.SimplePos.Y   = y;
};
ParaDrawing.prototype.setExtent = function(extX, extY)
{
	History.Add(new CChangesParaDrawingExtent(this,
		{
			W : this.Extent.W,
			H : this.Extent.H
		},
		{
			W : extX,
			H : extY
		}));

	this.Extent.W = extX;
	this.Extent.H = extY;
};
ParaDrawing.prototype.addWrapPolygon = function(wrapPolygon)
{
	History.Add(new CChangesParaDrawingWrapPolygon(this, this.wrappingPolygon, wrapPolygon));
	this.wrappingPolygon = wrapPolygon;
};
ParaDrawing.prototype.Set_Locked = function(bLocked)
{
	History.Add(new CChangesParaDrawingLocked(this, this.Locked, bLocked));
	this.Locked = bLocked;
};
ParaDrawing.prototype.Set_RelativeHeight = function(nRelativeHeight)
{
	History.Add(new CChangesParaDrawingRelativeHeight(this, this.RelativeHeight, nRelativeHeight));
	this.Set_RelativeHeight2(nRelativeHeight);
};
ParaDrawing.prototype.Set_RelativeHeight2 = function(nRelativeHeight)
{
	this.RelativeHeight = nRelativeHeight;
	if (this.graphicObjects && AscFormat.isRealNumber(nRelativeHeight) && nRelativeHeight > this.graphicObjects.maximalGraphicObjectZIndex)
	{
		this.graphicObjects.maximalGraphicObjectZIndex = nRelativeHeight;
	}
};
ParaDrawing.prototype.setEffectExtent = function(L, T, R, B)
{
	var oEE = this.EffectExtent;
	History.Add(new CChangesParaDrawingEffectExtent(this,
		{
			L : oEE.L,
			T : oEE.T,
			R : oEE.R,
			B : oEE.B
		},
		{
			L : L,
			T : T,
			R : R,
			B : B
		}));

	this.EffectExtent.L = L;
	this.EffectExtent.T = T;
	this.EffectExtent.R = R;
	this.EffectExtent.B = B;
};
ParaDrawing.prototype.Set_Parent = function(oParent)
{
	History.Add(new CChangesParaDrawingParent(this, this.Parent, oParent));
	this.Parent = oParent;
};
ParaDrawing.prototype.Set_ParaMath = function(ParaMath)
{
	History.Add(new CChangesParaDrawingParaMath(this, this.ParaMath, ParaMath));
	this.ParaMath = ParaMath;
};
ParaDrawing.prototype.Set_LayoutInCell = function(LayoutInCell)
{
	if (this.LayoutInCell === LayoutInCell)
		return;

	History.Add(new CChangesParaDrawingLayoutInCell(this, this.LayoutInCell, LayoutInCell));
	this.LayoutInCell = LayoutInCell;
};
ParaDrawing.prototype.SetSizeRelH = function(oSize)
{
	History.Add(new CChangesParaDrawingSizeRelH(this, this.SizeRelH, oSize));
	this.SizeRelH = oSize;
};
ParaDrawing.prototype.SetSizeRelV  = function(oSize)
{
	History.Add(new CChangesParaDrawingSizeRelV(this, this.SizeRelV, oSize));
	this.SizeRelV = oSize;
};
ParaDrawing.prototype.getXfrmExtX = function()
{
	if (isRealObject(this.GraphicObj) && isRealObject(this.GraphicObj.spPr) && isRealObject(this.GraphicObj.spPr.xfrm))
		return this.GraphicObj.spPr.xfrm.extX;
	if (AscFormat.isRealNumber(this.Extent.W))
		return this.Extent.W;
	return 0;
};
ParaDrawing.prototype.getXfrmExtY = function()
{
	if (isRealObject(this.GraphicObj) && isRealObject(this.GraphicObj.spPr) && isRealObject(this.GraphicObj.spPr.xfrm))
		return this.GraphicObj.spPr.xfrm.extY;
	if (AscFormat.isRealNumber(this.Extent.H))
		return this.Extent.H;
	return 0;
};
ParaDrawing.prototype.Get_Bounds = function()
{
    var W, H;
    W = this.GraphicObj.bounds.w;
    H = this.GraphicObj.bounds.h;
    return {Left : this.X, Top : this.Y, Bottom : this.Y + H, Right : this.X + W};
};
ParaDrawing.prototype.Search = function(Str, Props, SearchEngine, Type)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.Search === "function")
	{
		this.GraphicObj.Search(Str, Props, SearchEngine, Type)
	}
};
ParaDrawing.prototype.Set_Props = function(Props)
{
	var bCheckWrapPolygon = false;
	if (undefined != Props.WrappingStyle)
	{
		if (drawing_Inline === this.DrawingType && c_oAscWrapStyle2.Inline != Props.WrappingStyle && undefined === Props.Paddings)
		{
			this.Set_Distance(3.2, 0, 3.2, 0);
		}

		this.Set_DrawingType(c_oAscWrapStyle2.Inline === Props.WrappingStyle ? drawing_Inline : drawing_Anchor);
		if (c_oAscWrapStyle2.Inline === Props.WrappingStyle)
		{
			if (isRealObject(this.GraphicObj.bounds) && AscFormat.isRealNumber(this.GraphicObj.bounds.w) && AscFormat.isRealNumber(this.GraphicObj.bounds.h))
			{
				this.CheckWH();
			}
		}
		if (c_oAscWrapStyle2.Behind === Props.WrappingStyle || c_oAscWrapStyle2.InFront === Props.WrappingStyle)
		{
			this.Set_WrappingType(WRAPPING_TYPE_NONE);
			this.Set_BehindDoc(c_oAscWrapStyle2.Behind === Props.WrappingStyle ? true : false);
		}
		else
		{
			switch (Props.WrappingStyle)
			{
				case c_oAscWrapStyle2.Square      :
					this.Set_WrappingType(WRAPPING_TYPE_SQUARE);
					break;
				case c_oAscWrapStyle2.Tight       :
				{
					bCheckWrapPolygon = true;
					this.Set_WrappingType(WRAPPING_TYPE_TIGHT);
					break;
				}
				case c_oAscWrapStyle2.Through     :
				{
					this.Set_WrappingType(WRAPPING_TYPE_THROUGH);
					bCheckWrapPolygon = true;
					break;
				}
				case c_oAscWrapStyle2.TopAndBottom:
					this.Set_WrappingType(WRAPPING_TYPE_TOP_AND_BOTTOM);
					break;
				default                           :
					this.Set_WrappingType(WRAPPING_TYPE_SQUARE);
					break;
			}

			this.Set_BehindDoc(false);
		}
	}

	if (undefined != Props.Paddings)
		this.Set_Distance(Props.Paddings.Left, Props.Paddings.Top, Props.Paddings.Right, Props.Paddings.Bottom);

	if (undefined != Props.AllowOverlap)
		this.Set_AllowOverlap(Props.AllowOverlap);

	if (undefined != Props.PositionH)
	{
		this.Set_PositionH(Props.PositionH.RelativeFrom, Props.PositionH.UseAlign, ( true === Props.PositionH.UseAlign ? Props.PositionH.Align : Props.PositionH.Value ), Props.PositionH.Percent);
	}
	if (undefined != Props.PositionV)
	{
		this.Set_PositionV(Props.PositionV.RelativeFrom, Props.PositionV.UseAlign, ( true === Props.PositionV.UseAlign ? Props.PositionV.Align : Props.PositionV.Value ), Props.PositionV.Percent);
	}
	if (undefined != Props.SizeRelH)
	{
		this.SetSizeRelH({
			RelativeFrom : AscFormat.ConvertRelPositionHToRelSize(Props.SizeRelH.RelativeFrom),
			Percent      : Props.SizeRelH.Value / 100.0
		});
	}

	if (undefined != Props.SizeRelV)
	{
		this.SetSizeRelV({
			RelativeFrom : AscFormat.ConvertRelPositionVToRelSize(Props.SizeRelV.RelativeFrom),
			Percent      : Props.SizeRelV.Value / 100.0
		});
	}

	if (this.SizeRelH && !this.SizeRelV)
	{
		this.SetSizeRelV({RelativeFrom : AscCommon.c_oAscSizeRelFromV.sizerelfromvPage, Percent : 0});
	}

	if (this.SizeRelV && !this.SizeRelH)
	{
		this.SetSizeRelH({RelativeFrom : AscCommon.c_oAscSizeRelFromH.sizerelfromhPage, Percent : 0})
	}

	if (bCheckWrapPolygon)
	{
		this.Check_WrapPolygon();
	}

	if(undefined != Props.description){
		this.docPr.setDescr(Props.description);
	}
	if(undefined != Props.title){
		this.docPr.setTitle(Props.title);
	}
};
ParaDrawing.prototype.CheckWH = function()
{
	if (!this.GraphicObj)
		return;
	var oldExtW = this.Extent.W;
	var oldExtH = this.Extent.H;
	if (this.GraphicObj.spPr && this.GraphicObj.spPr.xfrm
		&& AscFormat.isRealNumber(this.GraphicObj.spPr.xfrm.extX)
		&& AscFormat.isRealNumber(this.GraphicObj.spPr.xfrm.extY)){
		this.Extent.W = this.GraphicObj.spPr.xfrm.extX;
		this.Extent.H = this.GraphicObj.spPr.xfrm.extY;
	}
	this.GraphicObj.recalculate();
	this.Extent.W = oldExtW;
	this.Extent.H = oldExtH;
	var extX, extY, rot;
	if (this.GraphicObj.spPr && this.GraphicObj.spPr.xfrm )
	{
		if(AscFormat.isRealNumber(this.GraphicObj.spPr.xfrm.extX) && AscFormat.isRealNumber(this.GraphicObj.spPr.xfrm.extY))
		{
            extX = this.GraphicObj.spPr.xfrm.extX;
            extY = this.GraphicObj.spPr.xfrm.extY;
		}
		else
		{
			extX = 5;
			extY = 5;
		}
		if(AscFormat.isRealNumber(this.GraphicObj.spPr.xfrm.rot))
		{
			rot = this.GraphicObj.spPr.xfrm.rot;
		}
		else
		{
			rot = 0;
		}
	}
	else
	{
		extX = 5;
		extY = 5;
		rot = 0;
	}
	this.setExtent(extX, extY);


	var EEL = 0.0, EET = 0.0, EER = 0.0, EEB = 0.0;
	//if(this.Is_Inline())
	{
		var xc          = this.GraphicObj.localTransform.TransformPointX(this.GraphicObj.extX / 2, this.GraphicObj.extY / 2);
		var yc          = this.GraphicObj.localTransform.TransformPointY(this.GraphicObj.extX / 2, this.GraphicObj.extY / 2);
		var oBounds     = this.GraphicObj.bounds;
		var LineCorrect = 0;
		if (this.GraphicObj.pen && this.GraphicObj.pen.Fill && this.GraphicObj.pen.Fill.fill)
		{
			LineCorrect = (this.GraphicObj.pen.w == null) ? 12700 : parseInt(this.GraphicObj.pen.w);
			LineCorrect /= 72000.0;
		}


		var l = oBounds.l;
		var r = oBounds.r;
		var t = oBounds.t;
		var b = oBounds.b;

		var startX, startY;
		if(!AscFormat.checkNormalRotate(rot)){
			var t = extX;
			extX = extY;
			extY = t;
		}


		startX = xc - extX/2.0;
		startY = yc - extY/2.0;

		if(l > startX){
			l = startX;
		}
		if(r < startX + extX){
			r = startX + extX;
		}
		if(t > startY){
			t = startY;
		}
		if(b < startY + extY){
			b = startY + extY;
		}

		EEL = (xc - extX / 2) - l + LineCorrect;
		EET = (yc - extY / 2) - t + LineCorrect;
		EER = r + LineCorrect - (xc + extX / 2);
		EEB = b + LineCorrect - (yc + extY / 2);
	}
	this.setEffectExtent(EEL, EET, EER, EEB);
	this.Check_WrapPolygon();
};
ParaDrawing.prototype.Check_WrapPolygon = function()
{
	if ((this.wrappingType === WRAPPING_TYPE_TIGHT || this.wrappingType === WRAPPING_TYPE_THROUGH) && this.wrappingPolygon && !this.wrappingPolygon.edited)
	{
		this.GraphicObj.recalculate();
		this.wrappingPolygon.setArrRelPoints(this.wrappingPolygon.calculate(this.GraphicObj));
	}
};
ParaDrawing.prototype.Draw = function( X, Y, pGraphics, PDSE)
{
	var nPageIndex = null;
	if(AscCommon.isRealObject(PDSE))
	{
		nPageIndex = PDSE.Page;
	}
	if (pGraphics.Start_Command)
	{
		pGraphics.m_aDrawings.push(new AscFormat.ParaDrawingStruct(undefined, this));
		return;
	}
	if (this.Is_Inline())
	{
		pGraphics.shapePageIndex = nPageIndex;
		this.draw(pGraphics, PDSE);
		pGraphics.shapePageIndex = null;
	}
	if (pGraphics.End_Command)
	{
		pGraphics.End_Command();
	}
};

ParaDrawing.prototype.Measure = function()
{
	if (!this.GraphicObj)
	{
		this.Width  = 0;
		this.Height = 0;
		return;
	}
	if (AscFormat.isRealNumber(this.Extent.W) && AscFormat.isRealNumber(this.Extent.H) && (!this.GraphicObj.checkAutofit || !this.GraphicObj.checkAutofit()) && !this.SizeRelH && !this.SizeRelV)
	{
		var oEffectExtent = this.EffectExtent;

		var W, H;
		if(AscFormat.isRealNumber(this.GraphicObj.rot)){
            if(AscFormat.checkNormalRotate(this.GraphicObj.rot))
            {
                W = this.Extent.W;
                H = this.Extent.H;
            }
            else
			{
                W = this.Extent.H;
                H = this.Extent.W;
			}
		}
		else{
			W = this.Extent.W;
			H = this.Extent.H;
		}
		this.Width        = W + AscFormat.getValOrDefault(oEffectExtent.L, 0) + AscFormat.getValOrDefault(oEffectExtent.R, 0);
		this.Height       = H + AscFormat.getValOrDefault(oEffectExtent.T, 0) + AscFormat.getValOrDefault(oEffectExtent.B, 0);
		this.WidthVisible = this.Width;
	}
	else
	{
		this.GraphicObj.recalculate();
		if (this.GraphicObj.recalculateText)
		{
			this.GraphicObj.recalculateText();
		}
		if (this.PositionH.UseAlign || this.Is_Inline())
		{
			this.Width = this.GraphicObj.bounds.w;
		}
		else
		{
			this.Width = this.GraphicObj.extX;
		}
		this.WidthVisible = this.Width;
		if (this.PositionV.UseAlign || this.Is_Inline())
		{
			this.Height = this.GraphicObj.bounds.h;
		}
		else
		{
			this.Height = this.GraphicObj.extY;
		}
	}
};
ParaDrawing.prototype.SaveRecalculateObject = function(Copy)
{
	var DrawingObj = {};

	DrawingObj.Type         = this.Type;
	DrawingObj.DrawingType  = this.DrawingType;
	DrawingObj.WrappingType = this.wrappingType;

	if (drawing_Anchor === this.Get_DrawingType() && true === this.Use_TextWrap())
	{
		var oDistance      = this.Get_Distance();
		DrawingObj.FlowPos =
		{
			X : this.X - oDistance.L,
			Y : this.Y - oDistance.T,
			W : this.Width + oDistance.R,
			H : this.Height + oDistance.B
		}
	}
	DrawingObj.PageNum         = this.PageNum;
	DrawingObj.X               = this.X;
	DrawingObj.Y               = this.Y;
	DrawingObj.spRecaclcObject = this.GraphicObj.getRecalcObject();

	return DrawingObj;
};
ParaDrawing.prototype.LoadRecalculateObject = function(RecalcObj)
{
	this.updatePosition3(RecalcObj.PageNum, RecalcObj.X, RecalcObj.Y);
	this.GraphicObj.setRecalcObject(RecalcObj.spRecaclcObject);
};
ParaDrawing.prototype.Reassign_ImageUrls = function(mapUrls)
{
	if (this.GraphicObj)
	{
		this.GraphicObj.Reassign_ImageUrls(mapUrls);
	}
};
ParaDrawing.prototype.PrepareRecalculateObject = function()
{
};
ParaDrawing.prototype.Is_RealContent = function()
{
	return true;
};
ParaDrawing.prototype.Can_AddNumbering = function()
{
	if (drawing_Inline === this.DrawingType)
		return true;

	return false;
};
ParaDrawing.prototype.Copy = function()
{
	var c = new ParaDrawing(this.Extent.W, this.Extent.H, null, editor.WordControl.m_oLogicDocument.DrawingDocument, null, null);
	c.Set_DrawingType(this.DrawingType);
	if (isRealObject(this.GraphicObj))
	{
		c.Set_GraphicObject(this.GraphicObj.copy());
		c.GraphicObj.setParent(c);
	}

	var d = this.Distance;
	c.Set_PositionH(this.PositionH.RelativeFrom, this.PositionH.Align, this.PositionH.Value, this.PositionH.Percent);
	c.Set_PositionV(this.PositionV.RelativeFrom, this.PositionV.Align, this.PositionV.Value, this.PositionV.Percent);
	c.Set_Distance(d.L, d.T, d.R, d.B);
	c.Set_AllowOverlap(this.AllowOverlap);
	c.Set_WrappingType(this.wrappingType);
	if (this.wrappingPolygon)
	{
		c.wrappingPolygon.fromOther(this.wrappingPolygon);
	}
	c.Set_BehindDoc(this.behindDoc);
	c.Set_RelativeHeight(this.RelativeHeight);
	if (this.SizeRelH)
	{
		c.SetSizeRelH({RelativeFrom : this.SizeRelH.RelativeFrom, Percent : this.SizeRelH.Percent});
	}
	if (this.SizeRelV)
	{
		c.SetSizeRelV({RelativeFrom : this.SizeRelV.RelativeFrom, Percent : this.SizeRelV.Percent});
	}
	if (AscFormat.isRealNumber(this.Extent.W) && AscFormat.isRealNumber(this.Extent.H))
	{
		c.setExtent(this.Extent.W, this.Extent.H);
	}
	var EE = this.EffectExtent;
	if (EE.L > 0 || EE.T > 0 || EE.R > 0 || EE.B > 0)
	{
		c.setEffectExtent(EE.L, EE.T, EE.R, EE.B);
	}
	c.docPr.setFromOther(this.docPr);
	if (this.ParaMath)
		c.Set_ParaMath(this.ParaMath.Copy());
	return c;
};
ParaDrawing.prototype.Get_Id = function()
{
	return this.Id;
};
ParaDrawing.prototype.setParagraphTabs = function(tabs)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.setParagraphTabs === "function")
		this.GraphicObj.setParagraphTabs(tabs);
};
ParaDrawing.prototype.IsMovingTableBorder = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.IsMovingTableBorder === "function")
		return this.GraphicObj.IsMovingTableBorder();
	return false;
};
ParaDrawing.prototype.SetVerticalClip = function(Top, Bottom)
{
	this.LineTop = Top;
	this.LineBottom = Bottom;
};
ParaDrawing.prototype.Update_Position = function(Paragraph, ParaLayout, PageLimits, PageLimitsOrigin, LineNum)
{
	if (undefined != this.PositionH_Old)
	{
		this.PositionH.RelativeFrom = this.PositionH_Old.RelativeFrom2;
		this.PositionH.Align        = this.PositionH_Old.Align2;
		this.PositionH.Value        = this.PositionH_Old.Value2;
		this.PositionH.Percent      = this.PositionH_Old.Percent2;
	}

	if (undefined != this.PositionV_Old)
	{
		this.PositionV.RelativeFrom = this.PositionV_Old.RelativeFrom2;
		this.PositionV.Align        = this.PositionV_Old.Align2;
		this.PositionV.Value        = this.PositionV_Old.Value2;
		this.PositionV.Percent      = this.PositionV_Old.Percent2;
	}

	var oDocumentContent = this.Parent.Parent;
	if (oDocumentContent && oDocumentContent.IsBlockLevelSdtContent())
		oDocumentContent = oDocumentContent.Parent.Parent;

	this.Parent          = Paragraph;
	this.DocumentContent = oDocumentContent;
	var PageNum          = ParaLayout.PageNum;

	var OtherFlowObjects = editor.WordControl.m_oLogicDocument.DrawingObjects.getAllFloatObjectsOnPage(PageNum, this.Parent.Parent);
	var bInline          = this.Is_Inline();
	var W, H;
	if (this.Is_Inline())
	{
		W = this.GraphicObj.bounds.w;
		H = this.GraphicObj.bounds.h;
	}
	else
	{
		if (this.PositionH.Align)
			W = this.GraphicObj.bounds.w;
		else
			W = this.getXfrmExtX();

		if (this.PositionV.Align)
			H = this.GraphicObj.bounds.h;
		else
			H = this.getXfrmExtY();
	}
	this.Internal_Position.Set(W, H, this.YOffset, ParaLayout, PageLimitsOrigin, this.GraphicObj.bounds.l, this.GraphicObj.bounds.t, this.GraphicObj.bounds.w, this.GraphicObj.bounds.h);
	this.Internal_Position.Calculate_X(bInline, this.PositionH.RelativeFrom, this.PositionH.Align, this.PositionH.Value, this.PositionH.Percent);
	this.Internal_Position.Calculate_Y(bInline, this.PositionV.RelativeFrom, this.PositionV.Align, this.PositionV.Value, this.PositionV.Percent);
	this.Internal_Position.Correct_Values(bInline, PageLimits, this.AllowOverlap, this.Use_TextWrap(), OtherFlowObjects);

	var OldPageNum = this.PageNum;
	this.PageNum   = PageNum;
	this.LineNum   = LineNum;
	this.X         = this.Internal_Position.CalcX;
	this.Y         = this.Internal_Position.CalcY;

	if (undefined != this.PositionH_Old)
	{
		// Восстанови старые значения, чтобы в историю изменений все нормально записалось
		this.PositionH.RelativeFrom = this.PositionH_Old.RelativeFrom;
		this.PositionH.Align        = this.PositionH_Old.Align;
		this.PositionH.Value        = this.PositionH_Old.Value;
		this.PositionH.Percent      = this.PositionH_Old.Percent;

		// Рассчитаем сдвиг с учетом старой привязки
		var Value = this.Internal_Position.Calculate_X_Value(this.PositionH_Old.RelativeFrom);
		this.Set_PositionH(this.PositionH_Old.RelativeFrom, false, Value, false);
		// На всякий случай пересчитаем заново координату
		this.X = this.Internal_Position.Calculate_X(bInline, this.PositionH.RelativeFrom, this.PositionH.Align, this.PositionH.Value, this.PositionH.Percent);
	}

	if (undefined != this.PositionV_Old)
	{
		// Восстанови старые значения, чтобы в историю изменений все нормально записалось
		this.PositionV.RelativeFrom = this.PositionV_Old.RelativeFrom;
		this.PositionV.Align        = this.PositionV_Old.Align;
		this.PositionV.Value        = this.PositionV_Old.Value;
		this.PositionV.Percent      = this.PositionV_Old.Percent;

		// Рассчитаем сдвиг с учетом старой привязки
		var Value = this.Internal_Position.Calculate_Y_Value(this.PositionV_Old.RelativeFrom);
		this.Set_PositionV(this.PositionV_Old.RelativeFrom, false, Value, false);
		// На всякий случай пересчитаем заново координату
		this.Y = this.Internal_Position.Calculate_Y(bInline, this.PositionV.RelativeFrom, this.PositionV.Align, this.PositionV.Value, this.PositionV.Percent);
	}

	var DiffX = 0.0, DiffY = 0.0;
	if(this.Is_Inline() || this.PositionH.Align || this.PositionV.Align)
	{
		var extX, extY, rot;
		if (this.GraphicObj.spPr && this.GraphicObj.spPr.xfrm )
		{
			if(AscFormat.isRealNumber(this.GraphicObj.spPr.xfrm.extX) && AscFormat.isRealNumber(this.GraphicObj.spPr.xfrm.extY))
			{
				extX = this.GraphicObj.spPr.xfrm.extX;
				extY = this.GraphicObj.spPr.xfrm.extY;
			}
			else
			{
				extX = 5;
				extY = 5;
			}
			if(AscFormat.isRealNumber(this.GraphicObj.spPr.xfrm.rot))
			{
				rot = this.GraphicObj.spPr.xfrm.rot;
			}
			else
			{
				rot = 0;
			}
		}
		else
		{
			extX = 5;
			extY = 5;
			rot = 0;
		}
		var xc          = this.GraphicObj.localTransform.TransformPointX(extX / 2, extY / 2);
		var yc          = this.GraphicObj.localTransform.TransformPointY(extX / 2, extY / 2);
		var oBounds     = this.GraphicObj.bounds;
		if(!AscFormat.checkNormalRotate(rot)){
			var t = extX;
			extX = extY;
			extY = t;
		}
		var oEffectExtent = this.EffectExtent;
		if(this.Is_Inline() || this.PositionH.Align)
		{
			DiffX = AscFormat.getValOrDefault(oEffectExtent.L, 0.0) - (xc - extX / 2) + oBounds.l;
		}
		if(this.Is_Inline() || this.PositionV.Align)
		{
			DiffY = AscFormat.getValOrDefault(oEffectExtent.T, 0.0) - (yc - extY / 2) + oBounds.t;
		}
	}
	this.updatePosition3(this.PageNum, this.X + DiffX, this.Y - DiffY, OldPageNum);
	this.useWrap = this.Use_TextWrap();
};
ParaDrawing.prototype.Update_PositionYHeaderFooter = function(TopMarginY, BottomMarginY)
{
	this.Internal_Position.Update_PositionYHeaderFooter(TopMarginY, BottomMarginY);
	this.Internal_Position.Calculate_Y(this.Is_Inline(), this.PositionV.RelativeFrom, this.PositionV.Align, this.PositionV.Value, this.PositionV.Percent);
	this.Y = this.Internal_Position.CalcY;
	this.updatePosition3(this.PageNum, this.X, this.Y, this.PageNum);
};
ParaDrawing.prototype.Reset_SavedPosition = function()
{
	this.PositionV_Old = undefined;
	this.PositionH_Old = undefined;
};
ParaDrawing.prototype.setParagraphBorders = function(val)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.setParagraphBorders === "function")
		this.GraphicObj.setParagraphBorders(val);
};
ParaDrawing.prototype.deselect = function()
{
	this.selected = false;
	if (this.GraphicObj && this.GraphicObj.deselect)
		this.GraphicObj.deselect();
};
ParaDrawing.prototype.updatePosition3 = function(pageIndex, x, y, oldPageNum)
{
	this.graphicObjects.removeById(pageIndex, this.Get_Id());
	if (AscFormat.isRealNumber(oldPageNum))
	{
		this.graphicObjects.removeById(oldPageNum, this.Get_Id());
	}
	this.setPageIndex(pageIndex);
	if (typeof this.GraphicObj.setStartPage === "function")
	{
		var bIsHfdFtr = this.DocumentContent && this.DocumentContent.IsHdrFtr();
		this.GraphicObj.setStartPage(pageIndex, bIsHfdFtr, bIsHfdFtr);
	}
	var bInline = this.Is_Inline();
	var _x      = (this.PositionH.Align || bInline) ? x - this.GraphicObj.bounds.x : x;
	var _y      = (this.PositionV.Align || bInline) ? y - this.GraphicObj.bounds.y : y;

	if (!(this.DocumentContent && this.DocumentContent.IsHdrFtr() && this.DocumentContent.Get_StartPage_Absolute() !== pageIndex))
	{
		this.graphicObjects.addObjectOnPage(pageIndex, this.GraphicObj);
		this.bNoNeedToAdd = false;
	}
	else
	{
		this.bNoNeedToAdd = true;
	}



	if (this.GraphicObj.bNeedUpdatePosition || !(AscFormat.isRealNumber(this.GraphicObj.posX) && AscFormat.isRealNumber(this.GraphicObj.posY)) || !(Math.abs(this.GraphicObj.posX - _x) < MOVE_DELTA && Math.abs(this.GraphicObj.posY - _y) < MOVE_DELTA))
		this.GraphicObj.updatePosition(_x, _y);
	if (this.GraphicObj.bNeedUpdatePosition || !(AscFormat.isRealNumber(this.wrappingPolygon.posX) && AscFormat.isRealNumber(this.wrappingPolygon.posY)) || !(Math.abs(this.wrappingPolygon.posX - _x) < MOVE_DELTA && Math.abs(this.wrappingPolygon.posY - _y) < MOVE_DELTA))
		this.wrappingPolygon.updatePosition(_x, _y);

    this.selectX = this.GraphicObj.bounds.l + _x;
    this.selectY = this.GraphicObj.bounds.t + _y;
	this.calculateSnapArrays();
};
ParaDrawing.prototype.calculateAfterChangeTheme = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.calculateAfterChangeTheme === "function")
	{
		this.GraphicObj.calculateAfterChangeTheme();
	}
};
ParaDrawing.prototype.selectionIsEmpty = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.selectionIsEmpty === "function")
		return this.GraphicObj.selectionIsEmpty();
	return false;
};
ParaDrawing.prototype.recalculateDocContent = function()
{
};
ParaDrawing.prototype.Shift = function(Dx, Dy)
{
	this.X += Dx;
	this.Y += Dy;

	this.updatePosition3(this.PageNum, this.X, this.Y);
};
ParaDrawing.prototype.IsLayoutInCell = function()
{
	// Начиная с 15-ой версии Word не дает менять этот параметр и всегда считает его true
	if (this.LogicDocument && this.LogicDocument.GetCompatibilityMode() >= document_compatibility_mode_Word15)
		return true;

	return this.LayoutInCell;
};
ParaDrawing.prototype.Get_Distance = function()
{
	var oDist = this.Distance;
	return new AscFormat.CDistance(AscFormat.getValOrDefault(oDist.L, AscFormat.DISTANCE_TO_TEXT_LEFTRIGHT), AscFormat.getValOrDefault(oDist.T, 0), AscFormat.getValOrDefault(oDist.R, AscFormat.DISTANCE_TO_TEXT_LEFTRIGHT), AscFormat.getValOrDefault(oDist.B, 0));
};
ParaDrawing.prototype.Set_XYForAdd = function(X, Y, NearPos, PageNum)
{
	if (null !== NearPos)
	{
		var Layout = NearPos.Paragraph.Get_Layout(NearPos.ContentPos, this);
		this.private_SetXYByLayout(X, Y, PageNum, Layout, true, true);

		var nRecalcIndex   = null;
		var oLogicDocument = this.document;
		if (oLogicDocument)
		{
			nRecalcIndex = oLogicDocument.Get_History().GetRecalculateIndex();
			this.SetSkipOnRecalculate(true);
            oLogicDocument.TurnOff_InterfaceEvents();
            oLogicDocument.Recalculate();
            oLogicDocument.TurnOn_InterfaceEvents(false)
			this.SetSkipOnRecalculate(false);
		}

		if (null !== nRecalcIndex)
			oLogicDocument.Get_History().SetRecalculateIndex(nRecalcIndex);

		Layout = NearPos.Paragraph.Get_Layout(NearPos.ContentPos, this);
		this.private_SetXYByLayout(X, Y, PageNum, Layout, true, true);
	}
};
ParaDrawing.prototype.SetSkipOnRecalculate = function(isSkip)
{
	this.SkipOnRecalculate = isSkip;
};
ParaDrawing.prototype.IsSkipOnRecalculate = function()
{
	return this.SkipOnRecalculate;
};
ParaDrawing.prototype.Set_XY = function(X, Y, Paragraph, PageNum, bResetAlign)
{
	if (Paragraph)
	{
		var PageNumOld = this.PageNum;
		var ContentPos = Paragraph.Get_DrawingObjectContentPos(this.Get_Id());
		if (null === ContentPos)
			return;

		var Layout = Paragraph.Get_Layout(ContentPos, this);
		this.private_SetXYByLayout(X, Y, PageNum, Layout, (bResetAlign || true !== this.PositionH.Align ? true : false), (bResetAlign || true !== this.PositionV.Align ? true : false));

		var nRecalcIndex   = null;
		var oLogicDocument = this.document;
		if (oLogicDocument)
		{
			nRecalcIndex = oLogicDocument.Get_History().GetRecalculateIndex();
			this.SetSkipOnRecalculate(true);
			oLogicDocument.Recalculate();
			this.SetSkipOnRecalculate(false);
		}

		if (null !== nRecalcIndex)
			oLogicDocument.Get_History().SetRecalculateIndex(nRecalcIndex);

		if (!this.LogicDocument
			|| null === this.LogicDocument.FullRecalc.Id
			|| (PageNum < this.LogicDocument.FullRecalc.PageIndex
			&& PageNumOld < this.LogicDocument.FullRecalc.PageIndex))
			Layout = Paragraph.Get_Layout(ContentPos, this);

		this.private_SetXYByLayout(X, Y, PageNum, Layout, (bResetAlign || true !== this.PositionH.Align ? true : false), (bResetAlign || true !== this.PositionV.Align ? true : false));
	}
};
ParaDrawing.prototype.private_SetXYByLayout = function(X, Y, PageNum, Layout, bChangeX, bChangeY)
{
	this.PageNum = PageNum;

	var _W = (this.PositionH.Align ? this.Extent.W : this.getXfrmExtX() );
	var _H = (this.PositionV.Align ? this.Extent.H : this.getXfrmExtY() );

	this.Internal_Position.Set(_W, _H, this.YOffset, Layout.ParagraphLayout, Layout.PageLimitsOrigin, this.GraphicObj.bounds.l, this.GraphicObj.bounds.t, this.GraphicObj.bounds.w, this.GraphicObj.bounds.h);
	this.Internal_Position.Calculate_X(false, c_oAscRelativeFromH.Page, false, X - Layout.PageLimitsOrigin.X, false);
	this.Internal_Position.Calculate_Y(false, c_oAscRelativeFromV.Page, false, Y - Layout.PageLimitsOrigin.Y, false);
	this.Internal_Position.Correct_Values(false, Layout.PageLimits, this.AllowOverlap, this.Use_TextWrap(), []);

	if (true === bChangeX)
	{
		this.X = this.Internal_Position.CalcX;

		// Рассчитаем сдвиг с учетом старой привязки
		var ValueX = this.Internal_Position.Calculate_X_Value(this.PositionH.RelativeFrom);
		this.Set_PositionH(this.PositionH.RelativeFrom, false, ValueX, false);

		// На всякий случай пересчитаем заново координату
		this.X = this.Internal_Position.Calculate_X(false, this.PositionH.RelativeFrom, this.PositionH.Align, this.PositionH.Value, this.PositionH.Percent);
	}

	if (true === bChangeY)
	{
		this.Y = this.Internal_Position.CalcY;

		// Рассчитаем сдвиг с учетом старой привязки
		var ValueY = this.Internal_Position.Calculate_Y_Value(this.PositionV.RelativeFrom);
		this.Set_PositionV(this.PositionV.RelativeFrom, false, ValueY, false);

		// На всякий случай пересчитаем заново координату
		this.Y = this.Internal_Position.Calculate_Y(false, this.PositionV.RelativeFrom, this.PositionV.Align, this.PositionV.Value, this.PositionV.Percent);
	}
};
ParaDrawing.prototype.Get_DrawingType = function()
{
	return this.DrawingType;
};
ParaDrawing.prototype.Is_Inline = function()
{
	if (!this.Parent || !this.Parent.Get_ParentTextTransform || null !== this.Parent.Get_ParentTextTransform())
		return true;

	return ( drawing_Inline === this.DrawingType ? true : false );
};
ParaDrawing.prototype.Use_TextWrap = function()
{
	// Если автофигура привязана к параграфу с рамкой, обтекание не делается
	if (!this.Parent || !this.Parent.Get_FramePr || (null !== this.Parent.Get_FramePr() && undefined !== this.Parent.Get_FramePr()))
		return false;

	// здесь должна быть проверка, нужно ли использовать обтекание относительно данного объекта,
	// или он просто лежит над или под текстом.
	return ( drawing_Anchor === this.DrawingType && !(this.wrappingType === WRAPPING_TYPE_NONE) );
};
ParaDrawing.prototype.Draw_Selection = function()
{
	var Padding = this.DrawingDocument.GetMMPerDot(6);
	this.DrawingDocument.AddPageSelection(this.PageNum, this.selectX - Padding, this.selectY - Padding, this.Width + 2 * Padding, this.Height + 2 * Padding);
};
ParaDrawing.prototype.OnEnd_MoveInline = function(NearPos)
{
	NearPos.Paragraph.Check_NearestPos(NearPos);

	var RunPr = this.Remove_FromDocument(false);

	// При переносе всегда создаем копию, чтобы в совместном редактировании не было проблем
	var NewParaDrawing = this.Copy();
    this.DocumentContent.Select_DrawingObject(NewParaDrawing.Get_Id());
	NewParaDrawing.Add_ToDocument(NearPos, true, RunPr);

};
ParaDrawing.prototype.Get_ParentTextTransform = function()
{
	if (this.Parent)
	{
		return this.Parent.Get_ParentTextTransform();
	}
	return null;
};
ParaDrawing.prototype.GoTo_Text = function(bBefore, bUpdateStates)
{
	if (undefined != this.Parent && null != this.Parent)
	{
		this.Parent.Cursor_MoveTo_Drawing(this.Id, bBefore);
		this.Parent.Document_SetThisElementCurrent(undefined === bUpdateStates ? true : bUpdateStates);
	}
};
ParaDrawing.prototype.Remove_FromDocument = function(bRecalculate)
{
	var Result = null;
	var Run    = this.Parent.Get_DrawingObjectRun(this.Id);

	if (null !== Run)
	{
		Run.Remove_DrawingObject(this.Id);

		if (true === Run.Is_InHyperlink())
			Result = new CTextPr();
		else
			Result = Run.Get_TextPr();
	}

	if (false != bRecalculate)
		editor.WordControl.m_oLogicDocument.Recalculate();

	return Result;
};
ParaDrawing.prototype.Get_ParentParagraph = function()
{
	if (this.Parent instanceof Paragraph)
		return this.Parent;
	if (this.Parent instanceof ParaRun)
		return this.Parent.Paragraph;
	return null;
};
ParaDrawing.prototype.Add_ToDocument = function(NearPos, bRecalculate, RunPr, Run)
{
	NearPos.Paragraph.Check_NearestPos(NearPos);

	var LogicDocument = this.DrawingDocument.m_oLogicDocument;

	var Para       = new Paragraph(this.DrawingDocument, LogicDocument);
	var DrawingRun = new ParaRun(Para);
	DrawingRun.Add_ToContent(0, this);

	if (RunPr)
		DrawingRun.Set_Pr(RunPr.Copy());

	if (Run)
		DrawingRun.Set_ReviewTypeWithInfo(Run.Get_ReviewType(), Run.Get_ReviewInfo());

	Para.Add_ToContent(0, DrawingRun);

	var SelectedElement = new CSelectedElement(Para, false);
	var SelectedContent = new CSelectedContent();
	SelectedContent.Add(SelectedElement);
	SelectedContent.Set_MoveDrawing(true);

	NearPos.Paragraph.Parent.Insert_Content(SelectedContent, NearPos);
	NearPos.Paragraph.Clear_NearestPosArray();
	NearPos.Paragraph.Correct_Content();

	if (false != bRecalculate)
		LogicDocument.Recalculate();
};
ParaDrawing.prototype.Add_ToDocument2 = function(Paragraph)
{
	var DrawingRun = new ParaRun(Paragraph);
	DrawingRun.Add_ToContent(0, this);

	Paragraph.Add_ToContent(0, DrawingRun);
};
ParaDrawing.prototype.UpdateCursorType = function(X, Y, PageIndex)
{
	this.DrawingDocument.SetCursorType("move", new AscCommon.CMouseMoveData());

	if (null != this.Parent)
	{
		var Lock = this.Parent.Lock;
		if (true === Lock.Is_Locked())
		{
			var PNum = Math.max(0, Math.min(PageIndex - this.Parent.PageNum, this.Parent.Pages.length - 1));
			var _X   = this.Parent.Pages[PNum].X;
			var _Y   = this.Parent.Pages[PNum].Y;

			var MMData              = new AscCommon.CMouseMoveData();
			var Coords              = this.DrawingDocument.ConvertCoordsToCursorWR(_X, _Y, this.Parent.Get_StartPage_Absolute() + ( PageIndex - this.Parent.PageNum ));
			MMData.X_abs            = Coords.X - 5;
			MMData.Y_abs            = Coords.Y;
			MMData.Type             = AscCommon.c_oAscMouseMoveDataTypes.LockedObject;
			MMData.UserId           = Lock.Get_UserId();
			MMData.HaveChanges      = Lock.Have_Changes();
			MMData.LockedObjectType = c_oAscMouseMoveLockedObjectType.Common;

			editor.sync_MouseMoveCallback(MMData);
		}
	}
};
ParaDrawing.prototype.Get_AnchorPos = function()
{
	return this.Parent.Get_AnchorPos(this);
};
ParaDrawing.prototype.CheckRecalcAutoFit = function(oSectPr)
{
	if (this.GraphicObj && this.GraphicObj.CheckNeedRecalcAutoFit)
	{
		if (this.GraphicObj.CheckNeedRecalcAutoFit(oSectPr))
		{
			if (this.GraphicObj)
			{
				this.GraphicObj.recalcWrapPolygon && this.GraphicObj.recalcWrapPolygon();
			}
			this.Measure();
		}
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Undo/Redo функции
//----------------------------------------------------------------------------------------------------------------------
ParaDrawing.prototype.Get_ParentObject_or_DocumentPos = function()
{
	if (this.Parent != null)
		return this.Parent.Get_ParentObject_or_DocumentPos();
};
ParaDrawing.prototype.Refresh_RecalcData = function(Data)
{
	if (undefined != this.Parent && null != this.Parent)
	{
		if (isRealObject(Data))
		{
			switch (Data.Type)
			{
				case AscDFH.historyitem_Drawing_Distance:
				{
					if (this.GraphicObj)
					{
						this.GraphicObj.recalcWrapPolygon && this.GraphicObj.recalcWrapPolygon();
						this.GraphicObj.addToRecalculate();
					}
					break;
				}

				case AscDFH.historyitem_Drawing_SetExtent:
				{
					var Run = this.Parent.Get_DrawingObjectRun(this.Id);
					if (Run)
					{
						Run.RecalcInfo.Measure = true;
					}
					break;
				}

				case AscDFH.historyitem_Drawing_SetSizeRelH:
				case AscDFH.historyitem_Drawing_SetSizeRelV:
				case AscDFH.historyitem_Drawing_SetGraphicObject:
				{
					if (this.GraphicObj)
					{
						this.GraphicObj.handleUpdateExtents && this.GraphicObj.handleUpdateExtents();
						this.GraphicObj.addToRecalculate();
					}
					var Run = this.Parent.Get_DrawingObjectRun(this.Id);
					if (Run)
					{
						Run.RecalcInfo.Measure = true;
					}
					break;
				}
				case AscDFH.historyitem_Drawing_WrappingType:
				{
					if (this.GraphicObj)
					{
						this.GraphicObj.recalcWrapPolygon && this.GraphicObj.recalcWrapPolygon();
						this.GraphicObj.addToRecalculate()
					}
					break;
				}
			}
		}
		return this.Parent.Refresh_RecalcData2();
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для совместного редактирования
//----------------------------------------------------------------------------------------------------------------------
ParaDrawing.prototype.hyperlinkCheck = function(bCheck)
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.hyperlinkCheck === "function")
		return this.GraphicObj.hyperlinkCheck(bCheck);
	return null;
};
ParaDrawing.prototype.hyperlinkCanAdd = function(bCheckInHyperlink)
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.hyperlinkCanAdd === "function")
		return this.GraphicObj.hyperlinkCanAdd(bCheckInHyperlink);
	return false;
};
ParaDrawing.prototype.hyperlinkRemove = function()
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.hyperlinkCanAdd === "function")
		return this.GraphicObj.hyperlinkRemove();
	return false;
};
ParaDrawing.prototype.hyperlinkModify = function( HyperProps )
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.hyperlinkModify === "function")
		return this.GraphicObj.hyperlinkModify(HyperProps);
};
ParaDrawing.prototype.hyperlinkAdd = function( HyperProps )
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.hyperlinkAdd === "function")
		return this.GraphicObj.hyperlinkAdd(HyperProps);
};
ParaDrawing.prototype.documentStatistics = function(stat)
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.documentStatistics === "function")
		this.GraphicObj.documentStatistics(stat);
};
ParaDrawing.prototype.documentCreateFontCharMap = function(fontMap)
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.documentCreateFontCharMap === "function")
		this.GraphicObj.documentCreateFontCharMap(fontMap);
};
ParaDrawing.prototype.documentCreateFontMap = function(fontMap)
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.documentCreateFontMap === "function")
		this.GraphicObj.documentCreateFontMap(fontMap);
};
ParaDrawing.prototype.tableCheckSplit = function()
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.tableCheckSplit === "function")
		return this.GraphicObj.tableCheckSplit();
	return false;
};
ParaDrawing.prototype.tableCheckMerge = function()
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.tableCheckMerge === "function")
		return this.GraphicObj.tableCheckMerge();
	return false;
};
ParaDrawing.prototype.tableSelect = function( Type )
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.tableSelect === "function")
		return this.GraphicObj.tableSelect(Type);
};
ParaDrawing.prototype.tableRemoveTable = function()
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.tableRemoveTable === "function")
		return this.GraphicObj.tableRemoveTable();
};
ParaDrawing.prototype.tableSplitCell = function(Cols, Rows)
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.tableSplitCell === "function")
		return this.GraphicObj.tableSplitCell(Cols, Rows);
};
ParaDrawing.prototype.tableMergeCells = function(Cols, Rows)
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.tableMergeCells === "function")
		return this.GraphicObj.tableMergeCells(Cols, Rows);
};
ParaDrawing.prototype.tableRemoveCol = function()
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.tableRemoveCol === "function")
		return this.GraphicObj.tableRemoveCol();
};
ParaDrawing.prototype.tableAddCol = function(bBefore)
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.tableAddCol === "function")
		return this.GraphicObj.tableAddCol(bBefore);
};
ParaDrawing.prototype.tableRemoveRow = function()
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.tableRemoveRow === "function")
		return this.GraphicObj.tableRemoveRow();
};
ParaDrawing.prototype.tableAddRow = function(bBefore)
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.tableAddRow === "function")
		return this.GraphicObj.tableAddRow(bBefore);
};
ParaDrawing.prototype.getCurrentParagraph = function(bIgnoreSelection, arrSelectedParagraphs)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.getCurrentParagraph === "function")
		return this.GraphicObj.getCurrentParagraph(bIgnoreSelection, arrSelectedParagraphs);

	if (this.Parent instanceof Paragraph)
		return this.Parent;
};
ParaDrawing.prototype.getSelectedText = function(bClearText, oPr)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.getSelectedText === "function")
		return this.GraphicObj.getSelectedText(bClearText, oPr);
	return "";
};
ParaDrawing.prototype.getCurPosXY = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.getCurPosXY === "function")
		return this.GraphicObj.getCurPosXY();
	return {X : 0, Y : 0};
};
ParaDrawing.prototype.setParagraphKeepLines = function(Value)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.setParagraphKeepLines === "function")
		return this.GraphicObj.setParagraphKeepLines(Value);
};
ParaDrawing.prototype.setParagraphKeepNext = function(Value)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.setParagraphKeepNext === "function")
		return this.GraphicObj.setParagraphKeepNext(Value);
};
ParaDrawing.prototype.setParagraphWidowControl = function(Value)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.setParagraphWidowControl === "function")
		return this.GraphicObj.setParagraphWidowControl(Value);
};
ParaDrawing.prototype.setParagraphPageBreakBefore = function(Value)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.setParagraphPageBreakBefore === "function")
		return this.GraphicObj.setParagraphPageBreakBefore(Value);
};
ParaDrawing.prototype.isTextSelectionUse = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.isTextSelectionUse === "function")
		return this.GraphicObj.isTextSelectionUse();
	return false;
};
ParaDrawing.prototype.paragraphFormatPaste = function( CopyTextPr, CopyParaPr, Bool )
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.isTextSelectionUse === "function")
		return this.GraphicObj.paragraphFormatPaste(CopyTextPr, CopyParaPr, Bool);
};
ParaDrawing.prototype.getNearestPos = function(x, y, pageIndex)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.getNearestPos === "function")
		return this.GraphicObj.getNearestPos(x, y, pageIndex);
	return null;
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для записи/чтения в поток
//----------------------------------------------------------------------------------------------------------------------
ParaDrawing.prototype.Write_ToBinary = function(Writer)
{
	// Long   : Type
	// String : Id

	Writer.WriteLong(this.Type);
	Writer.WriteString2(this.Id);
};
ParaDrawing.prototype.Write_ToBinary2 = function(Writer)
{
	Writer.WriteLong(AscDFH.historyitem_type_Drawing);
	Writer.WriteString2(this.Id);
	AscFormat.writeDouble(Writer, this.Extent.W);
	AscFormat.writeDouble(Writer, this.Extent.H);
	AscFormat.writeObject(Writer, this.GraphicObj);
	AscFormat.writeObject(Writer, this.DocumentContent);
	AscFormat.writeObject(Writer, this.Parent);
	AscFormat.writeObject(Writer, this.wrappingPolygon);
	AscFormat.writeLong(Writer, this.RelativeHeight);
	AscFormat.writeObject(Writer, this.docPr);
};
ParaDrawing.prototype.Read_FromBinary2 = function(Reader)
{
	this.Id              = Reader.GetString2();
	this.DrawingDocument = editor.WordControl.m_oLogicDocument.DrawingDocument;
	this.LogicDocument   = this.DrawingDocument ? this.DrawingDocument.m_oLogicDocument : null;

	this.Extent.W        = AscFormat.readDouble(Reader);
	this.Extent.H        = AscFormat.readDouble(Reader);
	this.GraphicObj      = AscFormat.readObject(Reader);
	this.DocumentContent = AscFormat.readObject(Reader);
	this.Parent          = AscFormat.readObject(Reader);
	this.wrappingPolygon = AscFormat.readObject(Reader);
	this.RelativeHeight  = AscFormat.readLong(Reader);
	this.docPr = AscFormat.readObject(Reader);
	if (this.wrappingPolygon)
	{
		this.wrappingPolygon.wordGraphicObject = this;
	}

	this.drawingDocument = editor.WordControl.m_oLogicDocument.DrawingDocument;
	this.document        = editor.WordControl.m_oLogicDocument;
	this.graphicObjects  = editor.WordControl.m_oLogicDocument.DrawingObjects;
	this.graphicObjects.addGraphicObject(this);
	g_oTableId.Add(this, this.Id);
};
ParaDrawing.prototype.Load_LinkData = function()
{
};
ParaDrawing.prototype.draw = function(graphics, PDSE)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.draw === "function")
	{
		graphics.SaveGrState();
		var bInline = this.Is_Inline();
		if(bInline && AscCommon.isRealObject(PDSE) && AscFormat.isRealNumber(this.LineTop) && AscFormat.isRealNumber(this.LineBottom) && AscCommon.isRealObject(this.GraphicObj.bounds))
		{
			var x, y, w, h;
			var oEffectExtent = this.EffectExtent;
			x = PDSE.X;
			y = this.LineTop;
			w = this.GraphicObj.bounds.r - this.GraphicObj.bounds.l + AscFormat.getValOrDefault(oEffectExtent.R, 0) + AscFormat.getValOrDefault(oEffectExtent.L, 0);
			h = this.LineBottom - this.LineTop;
			graphics.AddClipRect(x, y, w, h);
		}
		this.GraphicObj.draw(graphics);
		graphics.RestoreGrState();
	}
};
ParaDrawing.prototype.drawAdjustments = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.drawAdjustments === "function")
	{
		this.GraphicObj.drawAdjustments();
	}
};
ParaDrawing.prototype.getTransformMatrix = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.getTransformMatrix === "function")
	{
		return this.GraphicObj.getTransformMatrix();
	}
	return null;
};
ParaDrawing.prototype.getExtensions = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.getExtensions === "function")
	{
		return this.GraphicObj.getExtensions();
	}
	return null;
};
ParaDrawing.prototype.isGroup = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.isGroup === "function")
		return this.GraphicObj.isGroup();
	return false;
};
ParaDrawing.prototype.isShapeChild = function(bRetShape)
{
	if (!this.Is_Inline() || !this.DocumentContent)
		return bRetShape ? null : false;

	var cur_doc_content = this.DocumentContent;
	var oCell;
	while (oCell = cur_doc_content.IsTableCellContent(true))
	{
		cur_doc_content = oCell.Row.Table.Parent;
	}

	if (isRealObject(cur_doc_content.Parent) && typeof cur_doc_content.Parent.getObjectType === "function" && cur_doc_content.Parent.getObjectType() === AscDFH.historyitem_type_Shape)
		return bRetShape ? cur_doc_content.Parent : true;

	return bRetShape ? null : false;
};
ParaDrawing.prototype.checkShapeChildAndGetTopParagraph = function(paragraph)
{
	var parent_paragraph   = !paragraph ? this.Get_ParentParagraph() : paragraph;
	var parent_doc_content = parent_paragraph.Parent;
	if (parent_doc_content.Parent instanceof AscFormat.CShape)
	{
		if (!parent_doc_content.Parent.group)
		{
			return parent_doc_content.Parent.parent.Get_ParentParagraph();
		}
		else
		{
			var top_group = parent_doc_content.Parent.group;
			while (top_group.group)
				top_group = top_group.group;
			return top_group.parent.Get_ParentParagraph();
		}
	}
	else if (parent_doc_content.IsTableCellContent())
	{
		var top_doc_content = parent_doc_content;
		var oCell;
		while (oCell = top_doc_content.IsTableCellContent(true))
		{
			top_doc_content = oCell.Row.Table.Parent;
		}
		if (top_doc_content.Parent instanceof AscFormat.CShape)
		{
			if (!top_doc_content.Parent.group)
			{
				return top_doc_content.Parent.parent.Get_ParentParagraph();
			}
			else
			{
				var top_group = top_doc_content.Parent.group;
				while (top_group.group)
					top_group = top_group.group;
				return top_group.parent.Get_ParentParagraph();
			}
		}
		else
		{
			return parent_paragraph;
		}

	}
	return parent_paragraph;
};
ParaDrawing.prototype.hit = function(x, y)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.hit === "function")
	{
		return this.GraphicObj.hit(x, y);
	}
	return false;
};
ParaDrawing.prototype.hitToTextRect = function(x, y)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.hitToTextRect === "function")
	{
		return this.GraphicObj.hitToTextRect(x, y);
	}
	return false;
};
ParaDrawing.prototype.cursorGetPos = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.cursorGetPos === "function")
	{
		return this.GraphicObj.cursorGetPos();
	}
	return {X : 0, Y : 0};
};
ParaDrawing.prototype.getResizeCoefficients = function(handleNum, x, y)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.getResizeCoefficients === "function")
	{
		return this.GraphicObj.getResizeCoefficients(handleNum, x, y);
	}
	return {kd1 : 1, kd2 : 1};
};
ParaDrawing.prototype.getParagraphParaPr = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.getParagraphParaPr === "function")
	{
		return this.GraphicObj.getParagraphParaPr();
	}
	return null;
};
ParaDrawing.prototype.getParagraphTextPr = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.getParagraphTextPr === "function")
	{
		return this.GraphicObj.getParagraphTextPr();
	}
	return null;
};
ParaDrawing.prototype.getAngle = function(x, y)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.getAngle === "function")
		return this.GraphicObj.getAngle(x, y);
	return 0;
};
ParaDrawing.prototype.calculateSnapArrays = function()
{
	this.GraphicObj.snapArrayX.length = 0;
	this.GraphicObj.snapArrayY.length = 0;
	if (this.GraphicObj)
		this.GraphicObj.recalculateSnapArrays();

};
ParaDrawing.prototype.recalculateCurPos = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.recalculateCurPos === "function")
	{
		this.GraphicObj.recalculateCurPos();
	}
};
ParaDrawing.prototype.setPageIndex = function(newPageIndex)
{
	this.pageIndex = newPageIndex;
	this.PageNum   = newPageIndex;
};
ParaDrawing.prototype.Get_PageNum = function()
{
	return this.PageNum;
};
ParaDrawing.prototype.GetAllParagraphs = function(Props, ParaArray)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.GetAllParagraphs === "function")
		this.GraphicObj.GetAllParagraphs(Props, ParaArray);
};
ParaDrawing.prototype.GetAllDocContents = function(aDocContents)
{
	var _ret = Array.isArray(aDocContents) ? aDocContents : [];
	this.GraphicObj.getAllDocContents(_ret);
	return _ret;
};
ParaDrawing.prototype.getTableProps = function()
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.getTableProps === "function")
		return this.GraphicObj.getTableProps();
	return null;
};
ParaDrawing.prototype.canGroup = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.canGroup === "function")
		return this.GraphicObj.canGroup();
	return false;
};
ParaDrawing.prototype.canUnGroup = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.canGroup === "function")
		return this.GraphicObj.canUnGroup();
	return false;
};
ParaDrawing.prototype.select = function(pageIndex)
{
	this.selected = true;
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.select === "function")
		this.GraphicObj.select(pageIndex);

};
ParaDrawing.prototype.paragraphClearFormatting = function(isClearParaPr, isClearTextPr)
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.paragraphAdd === "function")
		this.GraphicObj.paragraphClearFormatting(isClearParaPr, isClearTextPr);
};
ParaDrawing.prototype.paragraphAdd = function(paraItem, bRecalculate)
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.paragraphAdd === "function")
		this.GraphicObj.paragraphAdd(paraItem, bRecalculate);
};
ParaDrawing.prototype.setParagraphShd = function(Shd)
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.setParagraphShd === "function")
		this.GraphicObj.setParagraphShd(Shd);
};
ParaDrawing.prototype.getArrayWrapPolygons = function()
{
	if ((isRealObject(this.GraphicObj) && typeof this.GraphicObj.getArrayWrapPolygons === "function"))
		return this.GraphicObj.getArrayWrapPolygons();

	return [];
};
ParaDrawing.prototype.getArrayWrapIntervals = function(x0, y0, x1, y1, Y0Sp, Y1Sp, LeftField, RightField, arr_intervals, bMathWrap)
{
	if (this.wrappingType === WRAPPING_TYPE_THROUGH || this.wrappingType === WRAPPING_TYPE_TIGHT)
	{
		y0 = Y0Sp;
		y1 = Y1Sp;
	}

	this.wrappingPolygon.wordGraphicObject = this;
	return this.wrappingPolygon.getArrayWrapIntervals(x0, y0, x1, y1, LeftField, RightField, arr_intervals, bMathWrap);
};
ParaDrawing.prototype.setAllParagraphNumbering = function(numInfo)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.addInlineTable === "function")
		this.GraphicObj.setAllParagraphNumbering(numInfo);
};
ParaDrawing.prototype.addNewParagraph = function(bRecalculate)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.addNewParagraph === "function")
		this.GraphicObj.addNewParagraph(bRecalculate);
};
ParaDrawing.prototype.addInlineTable = function(cols, rows)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.addInlineTable === "function")
		this.GraphicObj.addInlineTable(cols, rows);
};
ParaDrawing.prototype.applyTextPr = function(paraItem, bRecalculate)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.applyTextPr === "function")
		this.GraphicObj.applyTextPr(paraItem, bRecalculate);
};
ParaDrawing.prototype.allIncreaseDecFontSize = function(bIncrease)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.allIncreaseDecFontSize === "function")
		this.GraphicObj.allIncreaseDecFontSize(bIncrease);
};
ParaDrawing.prototype.setParagraphNumbering = function(NumInfo)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.allIncreaseDecFontSize === "function")
		this.GraphicObj.setParagraphNumbering(NumInfo);
};
ParaDrawing.prototype.allIncreaseDecIndent = function(bIncrease)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.allIncreaseDecIndent === "function")
		this.GraphicObj.allIncreaseDecIndent(bIncrease);
};
ParaDrawing.prototype.allSetParagraphAlign = function(align)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.allSetParagraphAlign === "function")
		this.GraphicObj.allSetParagraphAlign(align);
};
ParaDrawing.prototype.paragraphIncreaseDecFontSize = function(bIncrease)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.paragraphIncreaseDecFontSize === "function")
		this.GraphicObj.paragraphIncreaseDecFontSize(bIncrease);
};
ParaDrawing.prototype.paragraphIncreaseDecIndent = function(bIncrease)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.paragraphIncreaseDecIndent === "function")
		this.GraphicObj.paragraphIncreaseDecIndent(bIncrease);
};
ParaDrawing.prototype.setParagraphAlign = function(align)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.setParagraphAlign === "function")
		this.GraphicObj.setParagraphAlign(align);
};
ParaDrawing.prototype.setParagraphSpacing = function(Spacing)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.setParagraphSpacing === "function")
		this.GraphicObj.setParagraphSpacing(Spacing);
};
ParaDrawing.prototype.updatePosition = function(x, y)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.updatePosition === "function")
	{
		this.GraphicObj.updatePosition(x, y);
	}
};
ParaDrawing.prototype.updatePosition2 = function(x, y)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.updatePosition === "function")
	{
		this.GraphicObj.updatePosition2(x, y);
	}
};
ParaDrawing.prototype.addInlineImage = function(W, H, Img, chart, bFlow)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.addInlineImage === "function")
		this.GraphicObj.addInlineImage(W, H, Img, chart, bFlow);
};
ParaDrawing.prototype.addSignatureLine = function(oSignatureDrawing)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.addSignatureLine === "function")
		this.GraphicObj.addSignatureLine(oSignatureDrawing);
};
ParaDrawing.prototype.canAddComment = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.canAddComment === "function")
		return this.GraphicObj.canAddComment();
	return false;
};
ParaDrawing.prototype.addComment = function(commentData)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.addComment === "function")
		return this.GraphicObj.addComment(commentData);
};
ParaDrawing.prototype.selectionSetStart = function(x, y, event, pageIndex)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.selectionSetStart === "function")
		this.GraphicObj.selectionSetStart(x, y, event, pageIndex);
};
ParaDrawing.prototype.selectionSetEnd = function(x, y, event, pageIndex)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.selectionSetEnd === "function")
		this.GraphicObj.selectionSetEnd(x, y, event, pageIndex);
};
ParaDrawing.prototype.selectionRemove = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.selectionRemove === "function")
		this.GraphicObj.selectionRemove();
};
ParaDrawing.prototype.updateSelectionState = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.updateSelectionState === "function")
		this.GraphicObj.updateSelectionState();
};
ParaDrawing.prototype.cursorMoveLeft = function(AddToSelect, Word)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.cursorMoveLeft === "function")
		this.GraphicObj.cursorMoveLeft(AddToSelect, Word);
};
ParaDrawing.prototype.cursorMoveRight = function(AddToSelect, Word)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.cursorMoveRight === "function")
		this.GraphicObj.cursorMoveRight(AddToSelect, Word);
};
ParaDrawing.prototype.cursorMoveUp = function(AddToSelect)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.cursorMoveUp === "function")
		this.GraphicObj.cursorMoveUp(AddToSelect);
};
ParaDrawing.prototype.cursorMoveDown = function(AddToSelect)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.cursorMoveDown === "function")
		this.GraphicObj.cursorMoveDown(AddToSelect);
};
ParaDrawing.prototype.cursorMoveEndOfLine = function(AddToSelect)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.cursorMoveEndOfLine === "function")
		this.GraphicObj.cursorMoveEndOfLine(AddToSelect);
};
ParaDrawing.prototype.cursorMoveStartOfLine = function(AddToSelect)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.cursorMoveStartOfLine === "function")
		this.GraphicObj.cursorMoveStartOfLine(AddToSelect);
};
ParaDrawing.prototype.remove = function(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.remove === "function")
		this.GraphicObj.remove(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd);
};
ParaDrawing.prototype.hitToWrapPolygonPoint = function(x, y)
{
	if (this.wrappingPolygon && this.wrappingPolygon.arrPoints.length > 0)
	{
		var radius      = this.drawingDocument.GetMMPerDot(AscCommon.TRACK_CIRCLE_RADIUS);
		var arr_point   = this.wrappingPolygon.calculatedPoints;
		var point_count = arr_point.length;
		var dx, dy;

		var previous_point;
		for (var i = 0; i < arr_point.length; ++i)
		{
			var cur_point = arr_point[i];
			dx            = x - cur_point.x;
			dy            = y - cur_point.y;
			if (Math.sqrt(dx * dx + dy * dy) < radius)
				return {hit : true, hitType : WRAP_HIT_TYPE_POINT, pointNum : i};
		}

		cur_point      = arr_point[0];
		previous_point = arr_point[arr_point.length - 1];
		var vx, vy;
		vx             = cur_point.x - previous_point.x;
		vy             = cur_point.y - previous_point.y;
		if (Math.abs(vx) > 0 || Math.abs(vy) > 0)
		{
			if (HitInLine(this.drawingDocument.CanvasHitContext, x, y, previous_point.x, previous_point.y, cur_point.x, cur_point.y))
				return {hit : true, hitType : WRAP_HIT_TYPE_SECTION, pointNum1 : arr_point.length - 1, pointNum2 : 0};
		}

		for (var point_index = 1; point_index < point_count; ++point_index)
		{
			cur_point      = arr_point[point_index];
			previous_point = arr_point[point_index - 1];

			vx = cur_point.x - previous_point.x;
			vy = cur_point.y - previous_point.y;

			if (Math.abs(vx) > 0 || Math.abs(vy) > 0)
			{
				if (HitInLine(this.drawingDocument.CanvasHitContext, x, y, previous_point.x, previous_point.y, cur_point.x, cur_point.y))
					return {hit   : true,
						hitType   : WRAP_HIT_TYPE_SECTION,
						pointNum1 : point_index - 1,
						pointNum2 : point_index
					};
			}
		}
	}
	return {hit : false};
};
ParaDrawing.prototype.documentGetAllFontNames = function(AllFonts)
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.documentGetAllFontNames === "function")
		this.GraphicObj.documentGetAllFontNames(AllFonts);
};
ParaDrawing.prototype.isCurrentElementParagraph = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.isCurrentElementParagraph === "function")
		return this.GraphicObj.isCurrentElementParagraph();
	return false;
};
ParaDrawing.prototype.isCurrentElementTable = function()
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.isCurrentElementTable === "function")
		return this.GraphicObj.isCurrentElementTable();
	return false;
};
ParaDrawing.prototype.canChangeWrapPolygon = function()
{
	if (this.Is_Inline())
		return false;
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.canChangeWrapPolygon === "function")
		return this.GraphicObj.canChangeWrapPolygon();
	return false;
};
ParaDrawing.prototype.init = function()
{
};
ParaDrawing.prototype.calculateAfterOpen = function()
{
};
ParaDrawing.prototype.getBounds = function()
{

	return this.GraphicObj.bounds;
};
ParaDrawing.prototype.getWrapContour = function()
{
	if (isRealObject(this.wrappingPolygon))
	{
		var kw         = 1 / 36000;
		var kh         = 1 / 36000;
		var rel_points = this.wrappingPolygon.relativeArrPoints;
		var ret        = [];
		for (var i = 0; i < rel_points.length; ++i)
		{
			ret[i] = {x : rel_points[i].x * kw, y : rel_points[i].y * kh};
		}
		return ret;
	}
	return [];
};
ParaDrawing.prototype.getDrawingArrayType = function()
{
	if (this.Is_Inline())
		return DRAWING_ARRAY_TYPE_INLINE;
	if (this.behindDoc === true){
		if(this.wrappingType === WRAPPING_TYPE_NONE || (this.document && this.document.GetCompatibilityMode && this.document.GetCompatibilityMode() < document_compatibility_mode_Word15)){
			return DRAWING_ARRAY_TYPE_BEHIND;
		}
	}
	return DRAWING_ARRAY_TYPE_BEFORE;
};
ParaDrawing.prototype.documentSearch = function(String, search_Common)
{
	if (isRealObject(this.GraphicObj) && typeof this.GraphicObj.documentSearch === "function")
		this.GraphicObj.documentSearch(String, search_Common)
};
ParaDrawing.prototype.setParagraphContextualSpacing = function(Value)
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.setParagraphContextualSpacing === "function")
		this.GraphicObj.setParagraphContextualSpacing(Value);
};
ParaDrawing.prototype.setParagraphStyle = function(style)
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.setParagraphStyle === "function")
		this.GraphicObj.setParagraphStyle(style);
};
ParaDrawing.prototype.copy = function()
{
	var c = new ParaDrawing(this.Extent.W, this.Extent.H, null, editor.WordControl.m_oLogicDocument.DrawingDocument, null, null);
	c.Set_DrawingType(this.DrawingType);
	if (isRealObject(this.GraphicObj))
	{
		var g = this.GraphicObj.copy(c);
		c.Set_GraphicObject(g);
		g.setParent(c);
	}
	var d = this.Distance;
	c.Set_PositionH(this.PositionH.RelativeFrom, this.PositionH.Align, this.PositionH.Value, this.PositionH.Percent);
	c.Set_PositionV(this.PositionV.RelativeFrom, this.PositionV.Align, this.PositionV.Value, this.PositionV.Percent);
	c.Set_Distance(d.L, d.T, d.R, d.B);
	c.Set_AllowOverlap(this.AllowOverlap);
	c.Set_WrappingType(this.wrappingType);
	c.Set_BehindDoc(this.behindDoc);
	var EE = this.EffectExtent;
	c.setEffectExtent(EE.L, EE.T, EE.R, EE.B);
	return c;
};
ParaDrawing.prototype.OnContentReDraw = function()
{
	if (this.Parent && this.Parent.Parent)
		this.Parent.Parent.OnContentReDraw(this.PageNum, this.PageNum);
};
ParaDrawing.prototype.getBase64Img = function()
{
	if (isRealObject(this.GraphicObj) && typeof  this.GraphicObj.getBase64Img === "function")
		return this.GraphicObj.getBase64Img();
	return null;
};
ParaDrawing.prototype.isPointInObject = function(x, y, pageIndex)
{
	if (this.pageIndex === pageIndex)
	{
		if (isRealObject(this.GraphicObj))
		{
			var hit         = (typeof  this.GraphicObj.hit === "function") ? this.GraphicObj.hit(x, y) : false;
			var hit_to_text = (typeof  this.GraphicObj.hitToTextRect === "function") ? this.GraphicObj.hitToTextRect(x, y) : false;
			return hit || hit_to_text;
		}
	}
	return false;
};
ParaDrawing.prototype.Restart_CheckSpelling = function()
{
	this.GraphicObj && this.GraphicObj.Restart_CheckSpelling && this.GraphicObj.Restart_CheckSpelling();
};
ParaDrawing.prototype.Is_MathEquation = function()
{
	if (undefined !== this.ParaMath && null !== this.ParaMath)
		return true;

	return false;
};
ParaDrawing.prototype.Get_ParaMath = function()
{
	return this.ParaMath;
};
ParaDrawing.prototype.Convert_ToMathObject = function(isOpen)
{
	if (isOpen)
	{
		this.private_ConvertToMathObject(isOpen);
	}
	else
	{
		// TODO: Вообще здесь нужно запрашивать шрифты, которые использовались в старой формуле,
		//      но пока это только 1 шрифт "Cambria Math".
		var loader   = AscCommon.g_font_loader;
		var fontinfo = g_fontApplication.GetFontInfo("Cambria Math");
		var isasync  = loader.LoadFont(fontinfo, ConvertEquationToMathCallback, this);
		if (false === isasync)
		{
			this.private_ConvertToMathObject();
		}
	}
};
ParaDrawing.prototype.private_ConvertToMathObject = function(isOpen)
{
	var Para = this.GetParagraph();
	if (undefined === Para || null === Para || !(Para instanceof Paragraph))
		return;

	var ParaContentPos = Para.Get_PosByDrawing(this.Get_Id());
	if (null === ParaContentPos)
		return;

	var Depth = ParaContentPos.Get_Depth();
	var TopElementPos = ParaContentPos.Get(0);
	var BotElementPos = ParaContentPos.Get(Depth);

	var TopElement = Para.Content[TopElementPos];

	// Уменьшаем глубину на 1, чтобы получить позицию родительского класса
	var RunPos = ParaContentPos.Copy();
	RunPos.Decrease_Depth(1);
	var Run = Para.Get_ElementByPos(RunPos);

	if (undefined === TopElement || undefined === TopElement.Content || !(Run instanceof ParaRun))
		return;

	var LogicDocument = editor.WordControl.m_oLogicDocument;
	if (isOpen || false === LogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_None, {
			Type      : AscCommon.changestype_2_Element_and_Type,
			Element   : Para,
			CheckType : AscCommon.changestype_Paragraph_Content
		}))
	{
		if (!isOpen)
		{
			LogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_ConvertOldEquation);
		}

		// Коректируем формулу после конвертации
		this.ParaMath.Correct_AfterConvertFromEquation();

		// Сначала удаляем Drawing из рана
		Run.Remove_FromContent(BotElementPos, 1);

		// TODO: Тут возможно лучше взять настройки предыдущего элемента, но пока просто удалим самое неприятное
		// свойство.
		if (true === Run.Is_Empty())
			Run.Set_Position(undefined);

		// Теперь разделяем параграф по заданной позиции и добавляем туда новую формулу.
		var RightElement = TopElement.Split(ParaContentPos, 1);
		Para.Add_ToContent(TopElementPos + 1, RightElement);
		Para.Add_ToContent(TopElementPos + 1, this.ParaMath);
		Para.Correct_Content(TopElementPos, TopElementPos + 2);

		if (!isOpen)
		{
			// Устанавливаем курсор в начало правого элемента, полученного после Split
			LogicDocument.RemoveSelection();
			RightElement.MoveCursorToStartPos();
			Para.CurPos.ContentPos = TopElementPos + 2;
			Para.Document_SetThisElementCurrent(false);

			LogicDocument.Recalculate();
			LogicDocument.Document_UpdateSelectionState();
			LogicDocument.Document_UpdateInterfaceState();
		}
	}
};
ParaDrawing.prototype.GetRevisionsChangeParagraph = function(SearchEngine)
{
	if (this.GraphicObj && this.GraphicObj.GetRevisionsChangeParagraph)
		this.GraphicObj.GetRevisionsChangeParagraph(SearchEngine);
};
ParaDrawing.prototype.Get_ObjectType = function()
{
	if (this.GraphicObj)
		return this.GraphicObj.getObjectType();

	return AscDFH.historyitem_type_Drawing;
};
ParaDrawing.prototype.GetAllContentControls = function(arrContentControls)
{
	if(this.GraphicObj)
	{
		this.GraphicObj.GetAllContentControls(arrContentControls);
	}
};


ParaDrawing.prototype.CheckContentControlEditingLock = function(){
	if(this.DocumentContent && this.DocumentContent.CheckContentControlEditingLock){
        this.DocumentContent.CheckContentControlEditingLock();
	}
};


ParaDrawing.prototype.CheckContentControlDeletingLock = function(){
	if(this.DocumentContent && this.DocumentContent.CheckContentControlDeletingLock){
        this.DocumentContent.CheckContentControlDeletingLock();
	}
};

/**
 * Класс, описывающий текущее положение параграфа при рассчете позиции автофигуры.
 * @constructor
 */
function CParagraphLayout(X, Y, PageNum, LastItemW, ColumnStartX, ColumnEndX, Left_Margin, Right_Margin, Page_W, Top_Margin, Bottom_Margin, Page_H, MarginH, MarginV, LineTop, ParagraphTop)
{
	this.X             = X;
	this.Y             = Y;
	this.PageNum       = PageNum;
	this.LastItemW     = LastItemW;
	this.ColumnStartX  = ColumnStartX;
	this.ColumnEndX    = ColumnEndX;
	this.Left_Margin   = Left_Margin;
	this.Right_Margin  = Right_Margin;
	this.Page_W        = Page_W;
	this.Top_Margin    = Top_Margin;
	this.Bottom_Margin = Bottom_Margin;
	this.Page_H        = Page_H;
	this.Margin_H      = MarginH;
	this.Margin_V      = MarginV;
	this.LineTop       = LineTop;
	this.ParagraphTop  = ParagraphTop;
}
/**
 * Класс, описывающий позицию автофигуры на странице.
 * @constructor
 */
function CAnchorPosition()
{
	// Рассчитанные координаты
	this.CalcX         = 0;
	this.CalcY         = 0;

	// Данные для Inline-объектов
	this.YOffset       = 0;

	// Данные для Flow-объектов
	this.W             = 0;
	this.H             = 0;
	this.BoundsL       = 0;
	this.BoundsT       = 0;
	this.BoundsW       = 0;
	this.BoundsH       = 0;
	this.X             = 0;
	this.Y             = 0;
	this.PageNum       = 0;
	this.LastItemW     = 0;
	this.ColumnStartX  = 0;
	this.ColumnEndX    = 0;
	this.Left_Margin   = 0;
	this.Right_Margin  = 0;
	this.Page_W        = 0;
	this.Top_Margin    = 0;
	this.Bottom_Margin = 0;
	this.Page_H        = 0;
	this.Margin_H      = 0;
	this.Margin_V      = 0;
	this.LineTop       = 0;
	this.ParagraphTop  = 0;
	this.Page_X        = 0;
	this.Page_Y        = 0;
}
CAnchorPosition.prototype.Set = function(W, H, YOffset, ParaLayout, PageLimits, BoundsL, BoundsT, BoundsW, BoundsH)
{
	this.W = W;
	this.H = H;
	this.BoundsL = BoundsL;
	this.BoundsT = BoundsT;
	this.BoundsW = BoundsW;
	this.BoundsH = BoundsH;

	this.YOffset = YOffset;

	this.X             = ParaLayout.X;
	this.Y             = ParaLayout.Y;
	this.PageNum       = ParaLayout.PageNum;
	this.LastItemW     = ParaLayout.LastItemW;
	this.ColumnStartX  = ParaLayout.ColumnStartX;
	this.ColumnEndX    = ParaLayout.ColumnEndX;
	this.Left_Margin   = ParaLayout.Left_Margin;
	this.Right_Margin  = ParaLayout.Right_Margin;
	this.Page_W        = PageLimits.XLimit - PageLimits.X;// ParaLayout.Page_W;
	this.Top_Margin    = ParaLayout.Top_Margin;
	this.Bottom_Margin = ParaLayout.Bottom_Margin;
	this.Page_H        = PageLimits.YLimit - PageLimits.Y;// ParaLayout.Page_H;
	this.Margin_H      = ParaLayout.Margin_H;
	this.Margin_V      = ParaLayout.Margin_V;
	this.LineTop       = ParaLayout.LineTop;
	this.ParagraphTop  = ParaLayout.ParagraphTop;
	this.Page_X        = PageLimits.X;
	this.Page_Y        = PageLimits.Y;
};
CAnchorPosition.prototype.Calculate_X = function(bInline, RelativeFrom, bAlign, Value, bPercent)
{
	if (true === bInline)
	{
		this.CalcX = this.X;
	}
	else
	{
		// Вычисляем координату по X
		switch (RelativeFrom)
		{
			case c_oAscRelativeFromH.Character:
			{
				// Почему то Word при позиционировании относительно символа использует не
				// текущуюю позицию, а позицию предыдущего элемента (именно для этого мы
				// храним параметр LastItemW).

				var _X = this.X - this.LastItemW;

				if (true === bAlign)
				{
					switch (Value)
					{
						case c_oAscAlignH.Center:
						{
							this.CalcX = _X - this.W / 2;
							break;
						}

						case c_oAscAlignH.Inside:
						case c_oAscAlignH.Outside:
						case c_oAscAlignH.Left:
						{
							this.CalcX = _X;
							break;
						}

						case c_oAscAlignH.Right:
						{
							this.CalcX = _X - this.W;
							break;
						}
					}
				}
				else
					this.CalcX = _X + Value;

				break;
			}

			case c_oAscRelativeFromH.Column:
			{
				if (true === bAlign)
				{
					switch (Value)
					{
						case c_oAscAlignH.Center:
						{
							this.CalcX = (this.ColumnEndX + this.ColumnStartX - this.W) / 2;
							break;
						}

						case c_oAscAlignH.Inside:
						case c_oAscAlignH.Outside:
						case c_oAscAlignH.Left:
						{
							this.CalcX = this.ColumnStartX;
							break;
						}

						case c_oAscAlignH.Right:
						{
							this.CalcX = this.ColumnEndX - this.W;
							break;
						}
					}
				}
				else
					this.CalcX = this.ColumnStartX + Value;

				break;
			}

			case c_oAscRelativeFromH.InsideMargin:
			case c_oAscRelativeFromH.LeftMargin:
			case c_oAscRelativeFromH.OutsideMargin:
			{
				if (true === bAlign)
				{
					switch (Value)
					{
						case c_oAscAlignH.Center:
						{
							this.CalcX = (this.Left_Margin - this.W) / 2;
							break;
						}

						case c_oAscAlignH.Inside:
						case c_oAscAlignH.Outside:
						case c_oAscAlignH.Left:
						{
							this.CalcX = 0;
							break;
						}

						case c_oAscAlignH.Right:
						{
							this.CalcX = this.Left_Margin - this.W;
							break;
						}
					}
				}
				else if (true === bPercent)
				{
					this.CalcX = this.Page_X + this.Left_Margin * Value / 100;
				}
				else
				{
					this.CalcX = Value;
				}

				break;
			}

			case c_oAscRelativeFromH.Margin:
			{
				var X_s = this.Page_X + this.Left_Margin;
				var X_e = this.Page_X + this.Page_W - this.Right_Margin;

				if (true === bAlign)
				{
					switch (Value)
					{
						case c_oAscAlignH.Center:
						{
							this.CalcX = (X_e + X_s - this.W) / 2;
							break;
						}

						case c_oAscAlignH.Inside:
						case c_oAscAlignH.Outside:
						case c_oAscAlignH.Left:
						{
							this.CalcX = X_s;
							break;
						}

						case c_oAscAlignH.Right:
						{
							this.CalcX = X_e - this.W;
							break;
						}
					}
				}
				else if (true === bPercent)
				{
					this.CalcX = X_s + (X_e - X_s) * Value / 100;
				}
				else
				{
					this.CalcX = this.Margin_H + Value;
				}

				break;
			}

			case c_oAscRelativeFromH.Page:
			{
				if (true === bAlign)
				{
					switch (Value)
					{
						case c_oAscAlignH.Center:
						{
							this.CalcX = (this.Page_W - this.W) / 2;
							break;
						}

						case c_oAscAlignH.Inside:
						case c_oAscAlignH.Outside:
						case c_oAscAlignH.Left:
						{
							this.CalcX = 0;
							break;
						}

						case c_oAscAlignH.Right:
						{
							this.CalcX = this.Page_W - this.W;
							break;
						}
					}
				}
				else if (true === bPercent)
				{
					this.CalcX = this.Page_X + this.Page_W * Value / 100;
				}
				else
				{
					this.CalcX = Value + this.Page_X;
				}

				break;
			}

			case c_oAscRelativeFromH.RightMargin:
			{
				var X_s = this.Page_X + this.Page_W - this.Right_Margin;
				var X_e = this.Page_X + this.Page_W;

				if (true === bAlign)
				{
					switch (Value)
					{
						case c_oAscAlignH.Center:
						{
							this.CalcX = (X_e + X_s - this.W) / 2;
							break;
						}

						case c_oAscAlignH.Inside:
						case c_oAscAlignH.Outside:
						case c_oAscAlignH.Left:
						{
							this.CalcX = X_s;
							break;
						}

						case c_oAscAlignH.Right:
						{
							this.CalcX = X_e - this.W;
							break;
						}
					}
				}
				else if (true === bPercent)
				{
					this.CalcX = X_s + (X_e - X_s) * Value / 100;
				}
				else
				{
					this.CalcX = X_s + Value;
				}

				break;
			}
		}
	}

	return this.CalcX;
};
CAnchorPosition.prototype.Calculate_Y = function(bInline, RelativeFrom, bAlign, Value, bPercent)
{
	if (true === bInline)
	{
		this.CalcY = this.Y - this.H - this.YOffset;
	}
	else
	{
		// Вычисляем координату по Y
		switch (RelativeFrom)
		{
			case c_oAscRelativeFromV.BottomMargin:
			case c_oAscRelativeFromV.InsideMargin:
			case c_oAscRelativeFromV.OutsideMargin:
			{
				var _Y = this.Page_H - this.Bottom_Margin;

				if (true === bAlign)
				{
					switch (Value)
					{
						case c_oAscAlignV.Bottom:
						case c_oAscAlignV.Outside:
						{
							this.CalcY = this.Page_H - this.H;
							break;
						}
						case c_oAscAlignV.Center:
						{
							this.CalcY = (_Y + this.Page_H - this.H) / 2;
							break;
						}

						case c_oAscAlignV.Inside:
						case c_oAscAlignV.Top:
						{
							this.CalcY = _Y;
							break;
						}
					}
				}
				else if (true === bPercent)
				{
					if (Math.abs(this.Page_Y) > 0.001)
						this.CalcY = this.Margin_V;
					else
						this.CalcY = _Y + this.Bottom_Margin * Value / 100;
				}
				else
				{
					this.CalcY = _Y + Value;
				}

				break;
			}

			case c_oAscRelativeFromV.Line:
			{
				var _Y = this.LineTop;

				if (true === bAlign)
				{
					switch (Value)
					{
						case c_oAscAlignV.Bottom:
						case c_oAscAlignV.Outside:
						{
							this.CalcY = _Y - this.H;
							break;
						}
						case c_oAscAlignV.Center:
						{
							this.CalcY = _Y - this.H / 2;
							break;
						}

						case c_oAscAlignV.Inside:
						case c_oAscAlignV.Top:
						{
							this.CalcY = _Y;
							break;
						}
					}
				}
				else
					this.CalcY = _Y + Value;

				break;
			}

			case c_oAscRelativeFromV.Margin:
			{
				var Y_s = this.Top_Margin;
				var Y_e = this.Page_H - this.Bottom_Margin;

				if (true === bAlign)
				{
					switch (Value)
					{
						case c_oAscAlignV.Bottom:
						case c_oAscAlignV.Outside:
						{
							this.CalcY = Y_e - this.H;
							break;
						}
						case c_oAscAlignV.Center:
						{
							this.CalcY = (Y_s + Y_e - this.H) / 2;
							break;
						}

						case c_oAscAlignV.Inside:
						case c_oAscAlignV.Top:
						{
							this.CalcY = Y_s;
							break;
						}
					}
				}
				else if (true === bPercent)
				{
					if (Math.abs(this.Page_Y) > 0.001)
						this.CalcY = this.Margin_V;
					else
						this.CalcY = Y_s + (Y_e - Y_s) * Value / 100;
				}
				else
				{
					this.CalcY = this.Margin_V + Value;
				}

				break;
			}

			case c_oAscRelativeFromV.Page:
			{
				if (true === bAlign)
				{
					switch (Value)
					{
						case c_oAscAlignV.Bottom:
						case c_oAscAlignV.Outside:
						{
							this.CalcY = this.Page_H - this.H;
							break;
						}
						case c_oAscAlignV.Center:
						{
							this.CalcY = (this.Page_H - this.H) / 2;
							break;
						}

						case c_oAscAlignV.Inside:
						case c_oAscAlignV.Top:
						{
							this.CalcY = 0;
							break;
						}
					}
				}
				else if (true === bPercent)
				{
					if (Math.abs(this.Page_Y) > 0.001)
						this.CalcY = this.Margin_V;
					else
						this.CalcY = this.Page_H * Value / 100;
				}
				else
				{
					this.CalcY = Value + this.Page_Y;
				}

				break;
			}

			case c_oAscRelativeFromV.Paragraph:
			{
				// Почему то Word не дает возможности использовать прилегание
				// относительно абзаца, только абсолютные позиции
				var _Y = this.ParagraphTop;

				if (true === bAlign)
					this.CalcY = _Y;
				else
					this.CalcY = _Y + Value;

				break;
			}

			case c_oAscRelativeFromV.TopMargin:
			{
				var Y_s = 0;
				var Y_e = this.Top_Margin;

				if (true === bAlign)
				{
					switch (Value)
					{
						case c_oAscAlignV.Bottom:
						case c_oAscAlignV.Outside:
						{
							this.CalcY = Y_e - this.H;
							break;
						}
						case c_oAscAlignV.Center:
						{
							this.CalcY = (Y_s + Y_e - this.H) / 2;
							break;
						}

						case c_oAscAlignV.Inside:
						case c_oAscAlignV.Top:
						{
							this.CalcY = Y_s;
							break;
						}
					}
				}
				else if (true === bPercent)
				{
					if (Math.abs(this.Page_Y) > 0.001)
						this.CalcY = this.Margin_V;
					else
						this.CalcY = this.Top_Margin * Value / 100;
				}
				else
					this.CalcY = Y_s + Value;

				break;
			}
		}
	}

	return this.CalcY;
};
CAnchorPosition.prototype.Update_PositionYHeaderFooter = function(TopMarginY, BottomMarginY)
{
	var TopY    = Math.max(this.Page_Y, Math.min(TopMarginY, this.Page_H));
	var BottomY = Math.max(this.Page_Y, Math.min(BottomMarginY, this.Page_H));

	this.Margin_V      = TopY;
	this.Top_Margin    = TopY;
	this.Bottom_Margin = this.Page_H - BottomY;
};
CAnchorPosition.prototype.Correct_Values = function(bInline, PageLimits, AllowOverlap, UseTextWrap, OtherFlowObjects)
{
	if (true != bInline)
	{
		var X_min = PageLimits.X;
		var Y_min = PageLimits.Y;
		var X_max = PageLimits.XLimit;
		var Y_max = PageLimits.YLimit;

		var W = this.W;
		var H = this.H;

		var CurX = this.CalcX;
		var CurY = this.CalcY;

		var bBreak = false;
		while (true != bBreak)
		{
			bBreak = true;
			for (var Index = 0; Index < OtherFlowObjects.length; Index++)
			{
				var Drawing = OtherFlowObjects[Index];
				if (( false === AllowOverlap || false === Drawing.AllowOverlap ) && true === Drawing.Use_TextWrap() && true === UseTextWrap && ( CurX <= Drawing.X + Drawing.W && CurX + W >= Drawing.X && CurY <= Drawing.Y + Drawing.H && CurY + H >= Drawing.Y ))
				{
					// Если убирается справа, размещаем справа от картинки
					if (Drawing.X + Drawing.W < X_max - W - 0.001)
						CurX = Drawing.X + Drawing.W + 0.001;
					else
					{
						CurX = this.CalcX;
						CurY = Drawing.Y + Drawing.H + 0.001;
					}

					bBreak = false;
				}
			}
		}

		// Автофигуры с обтеканием за/перед текстом могут лежать где угодно
		if (true === UseTextWrap)
		{
			// Скорректируем рассчитанную позицию, так чтобы объект не выходил за заданные пределы
			if (CurX + this.BoundsL + this.BoundsW > X_max)
				CurX = X_max - this.BoundsL - this.BoundsW;

			if (CurX + this.BoundsL < X_min)
				CurX = X_min - this.BoundsL;

			// Скорректируем рассчитанную позицию, так чтобы объект не выходил за заданные пределы
			if (CurY + this.BoundsT + this.BoundsH > Y_max)
				CurY = Y_max - this.BoundsT - this.BoundsH;

			if (CurY + this.BoundsT < Y_min)
				CurY = Y_min - this.BoundsT;
		}

		this.CalcX = CurX;
		this.CalcY = CurY;
	}
};
CAnchorPosition.prototype.Calculate_X_Value = function(RelativeFrom)
{
	var Value = 0;
	switch (RelativeFrom)
	{
		case c_oAscRelativeFromH.Character:
		{
			// Почему то Word при позиционировании относительно символа использует не
			// текущуюю позицию, а позицию предыдущего элемента (именно для этого мы
			// храним параметр LastItemW).

			Value = this.CalcX - this.X + this.LastItemW;

			break;
		}

		case c_oAscRelativeFromH.Column:
		{
			Value = this.CalcX - this.ColumnStartX;

			break;
		}

		case c_oAscRelativeFromH.InsideMargin:
		case c_oAscRelativeFromH.LeftMargin:
		case c_oAscRelativeFromH.OutsideMargin:
		{
			Value = this.CalcX;

			break;
		}

		case c_oAscRelativeFromH.Margin:
		{
			Value = this.CalcX - this.Margin_H;

			break;
		}

		case c_oAscRelativeFromH.Page:
		{
			Value = this.CalcX - this.Page_X;

			break;
		}

		case c_oAscRelativeFromH.RightMargin:
		{
			Value = this.CalcX - this.Page_W + this.Right_Margin;

			break;
		}
	}

	return Value;
};
CAnchorPosition.prototype.Calculate_Y_Value = function(RelativeFrom)
{
	var Value = 0;

	switch (RelativeFrom)
	{
		case c_oAscRelativeFromV.BottomMargin:
		case c_oAscRelativeFromV.InsideMargin:
		case c_oAscRelativeFromV.OutsideMargin:
		{
			Value = this.CalcY - this.Page_H + this.Bottom_Margin;

			break;
		}

		case c_oAscRelativeFromV.Line:
		{
			Value = this.CalcY - this.LineTop;

			break;
		}

		case c_oAscRelativeFromV.Margin:
		{
			Value = this.CalcY - this.Margin_V;

			break;
		}

		case c_oAscRelativeFromV.Page:
		{
			Value = this.CalcY - this.Page_Y;

			break;
		}

		case c_oAscRelativeFromV.Paragraph:
		{
			Value = this.CalcY - this.ParagraphTop;

			break;
		}

		case c_oAscRelativeFromV.TopMargin:
		{
			Value = this.CalcY;

			break;
		}
	}

	return Value;
};

function ConvertEquationToMathCallback(ParaDrawing)
{
	ParaDrawing.private_ConvertToMathObject();
}

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].ParaDrawing = ParaDrawing;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 03.11.2016
 * Time: 11:56
 */

AscDFH.changesFactory[AscDFH.historyitem_Drawing_DrawingType]       = CChangesParaDrawingDrawingType;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_WrappingType]      = CChangesParaDrawingWrappingType;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_Distance]          = CChangesParaDrawingDistance;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_AllowOverlap]      = CChangesParaDrawingAllowOverlap;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_PositionH]         = CChangesParaDrawingPositionH;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_PositionV]         = CChangesParaDrawingPositionV;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_BehindDoc]         = CChangesParaDrawingBehindDoc;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_SetGraphicObject]  = CChangesParaDrawingGraphicObject;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_SetSimplePos]      = CChangesParaDrawingSimplePos;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_SetExtent]         = CChangesParaDrawingExtent;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_SetWrapPolygon]    = CChangesParaDrawingWrapPolygon;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_SetLocked]         = CChangesParaDrawingLocked;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_SetRelativeHeight] = CChangesParaDrawingRelativeHeight;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_SetEffectExtent]   = CChangesParaDrawingEffectExtent;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_SetParent]         = CChangesParaDrawingParent;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_SetParaMath]       = CChangesParaDrawingParaMath;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_LayoutInCell]      = CChangesParaDrawingLayoutInCell;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_SetSizeRelH]       = CChangesParaDrawingSizeRelH;
AscDFH.changesFactory[AscDFH.historyitem_Drawing_SetSizeRelV]       = CChangesParaDrawingSizeRelV;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_DrawingType]       = [AscDFH.historyitem_Drawing_DrawingType];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_WrappingType]      = [AscDFH.historyitem_Drawing_WrappingType];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_Distance]          = [AscDFH.historyitem_Drawing_Distance];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_AllowOverlap]      = [AscDFH.historyitem_Drawing_AllowOverlap];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_PositionH]         = [AscDFH.historyitem_Drawing_PositionH];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_PositionV]         = [AscDFH.historyitem_Drawing_PositionV];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_BehindDoc]         = [AscDFH.historyitem_Drawing_BehindDoc];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_SetGraphicObject]  = [AscDFH.historyitem_Drawing_SetGraphicObject];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_SetSimplePos]      = [AscDFH.historyitem_Drawing_SetSimplePos];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_SetExtent]         = [AscDFH.historyitem_Drawing_SetExtent];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_SetWrapPolygon]    = [AscDFH.historyitem_Drawing_SetWrapPolygon];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_SetLocked]         = [AscDFH.historyitem_Drawing_SetLocked];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_SetRelativeHeight] = [AscDFH.historyitem_Drawing_SetRelativeHeight];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_SetEffectExtent]   = [AscDFH.historyitem_Drawing_SetEffectExtent];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_SetParent]         = [AscDFH.historyitem_Drawing_SetParent];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_SetParaMath]       = [AscDFH.historyitem_Drawing_SetParaMath];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_LayoutInCell]      = [AscDFH.historyitem_Drawing_LayoutInCell];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_SetSizeRelH]       = [AscDFH.historyitem_Drawing_SetSizeRelH];
AscDFH.changesRelationMap[AscDFH.historyitem_Drawing_SetSizeRelV]       = [AscDFH.historyitem_Drawing_SetSizeRelV];
//----------------------------------------------------------------------------------------------------------------------

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongValue}
 */
function CChangesParaDrawingDrawingType(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongValue.call(this, Class, Old, New, Color);
}
CChangesParaDrawingDrawingType.prototype = Object.create(AscDFH.CChangesBaseLongValue.prototype);
CChangesParaDrawingDrawingType.prototype.constructor = CChangesParaDrawingDrawingType;
CChangesParaDrawingDrawingType.prototype.Type = AscDFH.historyitem_Drawing_DrawingType;
CChangesParaDrawingDrawingType.prototype.private_SetValue = function(Value)
{
	this.Class.DrawingType = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongValue}
 */
function CChangesParaDrawingWrappingType(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongValue.call(this, Class, Old, New, Color);
}
CChangesParaDrawingWrappingType.prototype = Object.create(AscDFH.CChangesBaseLongValue.prototype);
CChangesParaDrawingWrappingType.prototype.constructor = CChangesParaDrawingWrappingType;
CChangesParaDrawingWrappingType.prototype.Type = AscDFH.historyitem_Drawing_WrappingType;
CChangesParaDrawingWrappingType.prototype.private_SetValue = function(Value)
{
	this.Class.wrappingType = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaDrawingDistance(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaDrawingDistance.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaDrawingDistance.prototype.constructor = CChangesParaDrawingDistance;
CChangesParaDrawingDistance.prototype.Type = AscDFH.historyitem_Drawing_Distance;
CChangesParaDrawingDistance.prototype.private_SetValue = function(Value)
{
	var oDrawing = this.Class;

	oDrawing.Distance.L = Value.Left;
	oDrawing.Distance.T = Value.Top;
	oDrawing.Distance.R = Value.Right;
	oDrawing.Distance.B = Value.Bottom;

	if (oDrawing.GraphicObj && oDrawing.GraphicObj.recalcWrapPolygon)
		oDrawing.GraphicObj.recalcWrapPolygon();
};
CChangesParaDrawingDistance.prototype.WriteToBinary = function(Writer)
{
	// Double : New.Left
	// Double : New.Top
	// Double : New.Right
	// Double : New.Bottom
	// Double : Old.Left
	// Double : Old.Top
	// Double : Old.Right
	// Double : Old.Bottom

	Writer.WriteDouble(this.New.Left);
	Writer.WriteDouble(this.New.Top);
	Writer.WriteDouble(this.New.Right);
	Writer.WriteDouble(this.New.Bottom);
	Writer.WriteDouble(this.Old.Left);
	Writer.WriteDouble(this.Old.Top);
	Writer.WriteDouble(this.Old.Right);
	Writer.WriteDouble(this.Old.Bottom);
};
CChangesParaDrawingDistance.prototype.ReadFromBinary = function(Reader)
{
	// Double : New.Left
	// Double : New.Top
	// Double : New.Right
	// Double : New.Bottom
	// Double : Old.Left
	// Double : Old.Top
	// Double : Old.Right
	// Double : Old.Bottom

	this.New = {
		Left   : 0,
		Top    : 0,
		Right  : 0,
		Bottom : 0
	};

	this.Old = {
		Left   : 0,
		Top    : 0,
		Right  : 0,
		Bottom : 0
	};

	this.New.Left   = Reader.GetDouble();
	this.New.Top    = Reader.GetDouble();
	this.New.Right  = Reader.GetDouble();
	this.New.Bottom = Reader.GetDouble();
	this.Old.Left   = Reader.GetDouble();
	this.Old.Top    = Reader.GetDouble();
	this.Old.Right  = Reader.GetDouble();
	this.Old.Bottom = Reader.GetDouble();
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolValue}
 */
function CChangesParaDrawingAllowOverlap(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolValue.call(this, Class, Old, New, Color);
}
CChangesParaDrawingAllowOverlap.prototype = Object.create(AscDFH.CChangesBaseBoolValue.prototype);
CChangesParaDrawingAllowOverlap.prototype.constructor = CChangesParaDrawingAllowOverlap;
CChangesParaDrawingAllowOverlap.prototype.Type = AscDFH.historyitem_Drawing_AllowOverlap;
CChangesParaDrawingAllowOverlap.prototype.private_SetValue = function(Value)
{
	this.Class.AllowOverlap = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaDrawingPositionH(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaDrawingPositionH.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaDrawingPositionH.prototype.constructor = CChangesParaDrawingPositionH;
CChangesParaDrawingPositionH.prototype.Type = AscDFH.historyitem_Drawing_PositionH;
CChangesParaDrawingPositionH.prototype.private_SetValue = function(Value)
{
	var oDrawing = this.Class;
	oDrawing.PositionH.RelativeFrom = Value.RelativeFrom;
	oDrawing.PositionH.Align        = Value.Align;
	oDrawing.PositionH.Value        = Value.Value;
	oDrawing.PositionH.Percent      = Value.Percent;
};
CChangesParaDrawingPositionH.prototype.WriteToBinary = function(Writer)
{
	// Long : New.RelativeFrom
	// Bool : New.Align
	//   true  -> Long   : New.Value
	//   false -> Double : New.Value
	// Bool : New.Percent
	// Long : Old.RelativeFrom
	// Bool : Old.Align
	//   true  -> Long   : Old.Value
	//   false -> Double : Old.Value
	// Bool : Old.Percent

	Writer.WriteLong(this.New.RelativeFrom);
	Writer.WriteBool(this.New.Align);
	if (true === this.New.Align)
		Writer.WriteLong(this.New.Value);
	else
		Writer.WriteDouble(this.New.Value);
	Writer.WriteBool(this.New.Percent === true);

	Writer.WriteLong(this.Old.RelativeFrom);
	Writer.WriteBool(this.Old.Align);
	if (true === this.Old.Align)
		Writer.WriteLong(this.Old.Value);
	else
		Writer.WriteDouble(this.Old.Value);
	Writer.WriteBool(this.Old.Percent === true);
};
CChangesParaDrawingPositionH.prototype.ReadFromBinary = function(Reader)
{
	// Long : New.RelativeFrom
	// Bool : New.Align
	//   true  -> Long   : New.Value
	//   false -> Double : New.Value
	// Bool : New.Percent
	// Long : Old.RelativeFrom
	// Bool : Old.Align
	//   true  -> Long   : Old.Value
	//   false -> Double : Old.Value
	// Bool : Old.Percent

	// Long : RelativeFrom
	// Bool : Align
	//   true  -> Long   : Value
	//   false -> Double : Value

	this.New = {};
	this.Old = {};

	this.New.RelativeFrom = Reader.GetLong();
	this.New.Align        = Reader.GetBool();

	if (true === this.New.Align)
		this.New.Value = Reader.GetLong();
	else
		this.New.Value = Reader.GetDouble();

	this.New.Percent = Reader.GetBool();

	this.Old.RelativeFrom = Reader.GetLong();
	this.Old.Align        = Reader.GetBool();

	if (true === this.Old.Align)
		this.Old.Value = Reader.GetLong();
	else
		this.Old.Value = Reader.GetDouble();

	this.Old.Percent = Reader.GetBool();
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaDrawingPositionV(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaDrawingPositionV.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaDrawingPositionV.prototype.constructor = CChangesParaDrawingPositionV;
CChangesParaDrawingPositionV.prototype.Type = AscDFH.historyitem_Drawing_PositionV;
CChangesParaDrawingPositionV.prototype.private_SetValue = function(Value)
{
	var oDrawing = this.Class;
	oDrawing.PositionV.RelativeFrom = Value.RelativeFrom;
	oDrawing.PositionV.Align        = Value.Align;
	oDrawing.PositionV.Value        = Value.Value;
	oDrawing.PositionV.Percent      = Value.Percent;
};
CChangesParaDrawingPositionV.prototype.WriteToBinary = function(Writer)
{
	// Long : New.RelativeFrom
	// Bool : New.Align
	//   true  -> Long   : New.Value
	//   false -> Double : New.Value
	// Bool : New.Percent
	// Long : Old.RelativeFrom
	// Bool : Old.Align
	//   true  -> Long   : Old.Value
	//   false -> Double : Old.Value
	// Bool : Old.Percent

	Writer.WriteLong(this.New.RelativeFrom);
	Writer.WriteBool(this.New.Align);
	if (true === this.New.Align)
		Writer.WriteLong(this.New.Value);
	else
		Writer.WriteDouble(this.New.Value);
	Writer.WriteBool(this.New.Percent === true);

	Writer.WriteLong(this.Old.RelativeFrom);
	Writer.WriteBool(this.Old.Align);
	if (true === this.Old.Align)
		Writer.WriteLong(this.Old.Value);
	else
		Writer.WriteDouble(this.Old.Value);
	Writer.WriteBool(this.Old.Percent === true);
};
CChangesParaDrawingPositionV.prototype.ReadFromBinary = function(Reader)
{
	// Long : New.RelativeFrom
	// Bool : New.Align
	//   true  -> Long   : New.Value
	//   false -> Double : New.Value
	// Bool : New.Percent
	// Long : Old.RelativeFrom
	// Bool : Old.Align
	//   true  -> Long   : Old.Value
	//   false -> Double : Old.Value
	// Bool : Old.Percent

	// Long : RelativeFrom
	// Bool : Align
	//   true  -> Long   : Value
	//   false -> Double : Value

	this.New = {};
	this.Old = {};

	this.New.RelativeFrom = Reader.GetLong();
	this.New.Align        = Reader.GetBool();

	if (true === this.New.Align)
		this.New.Value = Reader.GetLong();
	else
		this.New.Value = Reader.GetDouble();

	this.New.Percent = Reader.GetBool();

	this.Old.RelativeFrom = Reader.GetLong();
	this.Old.Align        = Reader.GetBool();

	if (true === this.Old.Align)
		this.Old.Value = Reader.GetLong();
	else
		this.Old.Value = Reader.GetDouble();

	this.Old.Percent = Reader.GetBool();
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolValue}
 */
function CChangesParaDrawingBehindDoc(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolValue.call(this, Class, Old, New, Color);
}
CChangesParaDrawingBehindDoc.prototype = Object.create(AscDFH.CChangesBaseBoolValue.prototype);
CChangesParaDrawingBehindDoc.prototype.constructor = CChangesParaDrawingBehindDoc;
CChangesParaDrawingBehindDoc.prototype.Type = AscDFH.historyitem_Drawing_BehindDoc;
CChangesParaDrawingBehindDoc.prototype.private_SetValue = function(Value)
{
	this.Class.behindDoc = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaDrawingGraphicObject(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaDrawingGraphicObject.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaDrawingGraphicObject.prototype.constructor = CChangesParaDrawingGraphicObject;
CChangesParaDrawingGraphicObject.prototype.Type = AscDFH.historyitem_Drawing_SetGraphicObject;
CChangesParaDrawingGraphicObject.prototype.private_SetValue = function(Value)
{
	var oDrawing = this.Class;
	if(Value)
		oDrawing.GraphicObj = g_oTableId.Get_ById(Value);
	else
		oDrawing.GraphicObj = null;

	if(isRealObject(oDrawing.GraphicObj) && oDrawing.GraphicObj.handleUpdateExtents)
		oDrawing.GraphicObj.handleUpdateExtents();
};
CChangesParaDrawingGraphicObject.prototype.WriteToBinary = function(Writer)
{
	// Long : Flags
	// 1bit : is null New
	// 2bit : is null Old

	var nFlags = 0;

	if (!this.New)
		nFlags |= 1;

	if (!this.Old)
		nFlags |= 2;

	Writer.WriteLong(nFlags);

	if (this.New)
		Writer.WriteString2(this.New);

	if (this.Old)
		Writer.WriteString2(this.Old);
};
CChangesParaDrawingGraphicObject.prototype.ReadFromBinary = function(Reader)
{
	// Long : Flags
	// 1bit : is null New
	// 2bit : is null Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.New = null;
	else
		this.New = Reader.GetString2();

	if (nFlags & 2)
		this.Old = null;
	else
		this.Old = Reader.GetString2();
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaDrawingSimplePos(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaDrawingSimplePos.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaDrawingSimplePos.prototype.constructor = CChangesParaDrawingSimplePos;
CChangesParaDrawingSimplePos.prototype.Type = AscDFH.historyitem_Drawing_SetSimplePos;
CChangesParaDrawingSimplePos.prototype.private_SetValue = function(Value)
{
	var oDrawing = this.Class;
	oDrawing.SimplePos.Use = Value.Use;
	oDrawing.SimplePos.X   = Value.X;
	oDrawing.SimplePos.Y   = Value.Y;
};
CChangesParaDrawingSimplePos.prototype.WriteToBinary = function(Writer)
{
	// Bool   : New.Use
	// Double : New.X
	// Double : New.Y
	// Bool   : Old.Use
	// Double : Old.X
	// Double : Old.Y

	Writer.WriteBool(this.New.Use);
	Writer.WriteDouble(this.New.X);
	Writer.WriteDouble(this.New.Y);
	Writer.WriteBool(this.Old.Use);
	Writer.WriteDouble(this.Old.X);
	Writer.WriteDouble(this.Old.Y);
};
CChangesParaDrawingSimplePos.prototype.ReadFromBinary = function(Reader)
{
	// Bool   : New.Use
	// Double : New.X
	// Double : New.Y
	// Bool   : Old.Use
	// Double : Old.X
	// Double : Old.Y

	this.New = {};
	this.Old = {};

	this.New.Use = Reader.GetBool();
	this.New.X   = Reader.GetDouble();
	this.New.Y   = Reader.GetDouble();
	this.Old.Use = Reader.GetBool();
	this.Old.X   = Reader.GetDouble();
	this.Old.Y   = Reader.GetDouble();
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaDrawingExtent(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaDrawingExtent.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaDrawingExtent.prototype.constructor = CChangesParaDrawingExtent;
CChangesParaDrawingExtent.prototype.Type = AscDFH.historyitem_Drawing_SetExtent;
CChangesParaDrawingExtent.prototype.private_SetValue = function(Value)
{
	var oDrawing = this.Class;
	oDrawing.Extent.W = Value.W;
	oDrawing.Extent.H = Value.H;
};
CChangesParaDrawingExtent.prototype.WriteToBinary = function(Writer)
{
	// Double : New.W
	// Double : New.H
	// Double : Old.W
	// Double : Old.H
	Writer.WriteDouble(this.New.W);
	Writer.WriteDouble(this.New.H);
	Writer.WriteDouble(this.Old.W);
	Writer.WriteDouble(this.Old.H);
};
CChangesParaDrawingExtent.prototype.ReadFromBinary = function(Reader)
{
	// Double : New.W
	// Double : New.H
	// Double : Old.W
	// Double : Old.H

	this.New = {};
	this.Old = {};

	this.New.W = Reader.GetDouble();
	this.New.H = Reader.GetDouble();
	this.Old.W = Reader.GetDouble();
	this.Old.H = Reader.GetDouble();
};
CChangesParaDrawingExtent.prototype.Load = function()
{
	this.Redo();

	var oDrawing = this.Class;
	if(oDrawing.Parent)
	{
		var oRun = oDrawing.Parent.Get_DrawingObjectRun(oDrawing.Get_Id());
		if (oRun)
			oRun.RecalcInfo.Measure = true;
	}
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaDrawingWrapPolygon(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaDrawingWrapPolygon.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaDrawingWrapPolygon.prototype.constructor = CChangesParaDrawingWrapPolygon;
CChangesParaDrawingWrapPolygon.prototype.Type = AscDFH.historyitem_Drawing_SetWrapPolygon;
CChangesParaDrawingWrapPolygon.prototype.private_SetValue = function(Value)
{
	var oDrawing = this.Class;
	oDrawing.wrappingPolygon = Value;
};
CChangesParaDrawingWrapPolygon.prototype.WriteToBinary = function(Writer)
{
	AscFormat.writeObject(Writer, this.New);
	AscFormat.writeObject(Writer, this.Old);
};
CChangesParaDrawingWrapPolygon.prototype.ReadFromBinary = function(Reader)
{
	this.New = AscFormat.readObject(Reader);
	this.Old = AscFormat.readObject(Reader);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolValue}
 */
function CChangesParaDrawingLocked(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolValue.call(this, Class, Old, New, Color);
}
CChangesParaDrawingLocked.prototype = Object.create(AscDFH.CChangesBaseBoolValue.prototype);
CChangesParaDrawingLocked.prototype.constructor = CChangesParaDrawingLocked;
CChangesParaDrawingLocked.prototype.Type = AscDFH.historyitem_Drawing_SetLocked;
CChangesParaDrawingLocked.prototype.private_SetValue = function(Value)
{
	this.Class.Locked = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongValue}
 */
function CChangesParaDrawingRelativeHeight(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongValue.call(this, Class, Old, New, Color);
}
CChangesParaDrawingRelativeHeight.prototype = Object.create(AscDFH.CChangesBaseLongValue.prototype);
CChangesParaDrawingRelativeHeight.prototype.constructor = CChangesParaDrawingRelativeHeight;
CChangesParaDrawingRelativeHeight.prototype.Type = AscDFH.historyitem_Drawing_SetRelativeHeight;
CChangesParaDrawingRelativeHeight.prototype.private_SetValue = function(Value)
{
	this.Class.Set_RelativeHeight2(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaDrawingEffectExtent(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaDrawingEffectExtent.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaDrawingEffectExtent.prototype.constructor = CChangesParaDrawingEffectExtent;
CChangesParaDrawingEffectExtent.prototype.Type = AscDFH.historyitem_Drawing_SetEffectExtent;
CChangesParaDrawingEffectExtent.prototype.private_SetValue = function(Value)
{
	var oDrawing = this.Class;
	oDrawing.EffectExtent.L = Value.L;
	oDrawing.EffectExtent.T = Value.T;
	oDrawing.EffectExtent.R = Value.R;
	oDrawing.EffectExtent.B = Value.B;
};
CChangesParaDrawingEffectExtent.prototype.WriteToBinary = function(Writer)
{
	// Double : New.L
	// Double : New.T
	// Double : New.R
	// Double : New.B
	// Double : Old.L
	// Double : Old.T
	// Double : Old.R
	// Double : Old.B
	Writer.WriteDouble(this.New.L);
	Writer.WriteDouble(this.New.T);
	Writer.WriteDouble(this.New.R);
	Writer.WriteDouble(this.New.B);
	Writer.WriteDouble(this.Old.L);
	Writer.WriteDouble(this.Old.T);
	Writer.WriteDouble(this.Old.R);
	Writer.WriteDouble(this.Old.B);
};
CChangesParaDrawingEffectExtent.prototype.ReadFromBinary = function(Reader)
{
	// Double : New.L
	// Double : New.T
	// Double : New.R
	// Double : New.B
	// Double : Old.L
	// Double : Old.T
	// Double : Old.R
	// Double : Old.B

	this.New = {};
	this.Old = {};

	this.New.L = Reader.GetDouble();
	this.New.T = Reader.GetDouble();
	this.New.R = Reader.GetDouble();
	this.New.B = Reader.GetDouble();
	this.Old.L = Reader.GetDouble();
	this.Old.T = Reader.GetDouble();
	this.Old.R = Reader.GetDouble();
	this.Old.B = Reader.GetDouble();
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaDrawingParent(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaDrawingParent.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaDrawingParent.prototype.constructor = CChangesParaDrawingParent;
CChangesParaDrawingParent.prototype.Type = AscDFH.historyitem_Drawing_SetParent;
CChangesParaDrawingParent.prototype.private_SetValue = function(Value)
{
	var oDrawing = this.Class;
	oDrawing.Parent = Value;
};
CChangesParaDrawingParent.prototype.WriteToBinary = function(Writer)
{
	AscFormat.writeObject(Writer, this.New);
	AscFormat.writeObject(Writer, this.Old);
};
CChangesParaDrawingParent.prototype.ReadFromBinary = function(Reader)
{
	this.New = AscFormat.readObject(Reader);
	this.Old = AscFormat.readObject(Reader);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaDrawingParaMath(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaDrawingParaMath.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaDrawingParaMath.prototype.constructor = CChangesParaDrawingParaMath;
CChangesParaDrawingParaMath.prototype.Type = AscDFH.historyitem_Drawing_SetParaMath;
CChangesParaDrawingParaMath.prototype.private_SetValue = function(Value)
{
	this.Class.ParaMath = Value;
};
CChangesParaDrawingParaMath.prototype.WriteToBinary = function(Writer)
{
	// Long   : Flags
	// 1-bit  : is undefined New
	// 2-bit  : is undefined Old
	// String : New
	// String : Old

	var nFlags = 0;
	if (!(this.New instanceof ParaMath))
		nFlags |= 1;

	if (!(this.Old instanceof ParaMath))
		nFlags |= 2;

	Writer.WriteLong(nFlags);

	if (this.New instanceof ParaMath)
		Writer.WriteString2(this.New.Get_Id());

	if (this.Old instanceof ParaMath)
		Writer.WriteString2(this.Old.Get_Id());
};
CChangesParaDrawingParaMath.prototype.ReadFromBinary = function(Reader)
{
	// Long   : Flags
	// 1-bit  : is undefined New
	// 2-bit  : is undefined Old
	// String : New
	// String : Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.New = null;
	else
		this.New = g_oTableId.Get_ById(Reader.GetString2());

	if (nFlags & 2)
		this.Old = null;
	else
		this.Old = g_oTableId.Get_ById(Reader.GetString2());
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolValue}
 */
function CChangesParaDrawingLayoutInCell(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolValue.call(this, Class, Old, New, Color);
}
CChangesParaDrawingLayoutInCell.prototype = Object.create(AscDFH.CChangesBaseBoolValue.prototype);
CChangesParaDrawingLayoutInCell.prototype.constructor = CChangesParaDrawingLayoutInCell;
CChangesParaDrawingLayoutInCell.prototype.Type = AscDFH.historyitem_Drawing_LayoutInCell;
CChangesParaDrawingLayoutInCell.prototype.private_SetValue = function(Value)
{
	this.Class.LayoutInCell = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaDrawingSizeRelH(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaDrawingSizeRelH.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaDrawingSizeRelH.prototype.constructor = CChangesParaDrawingSizeRelH;
CChangesParaDrawingSizeRelH.prototype.Type = AscDFH.historyitem_Drawing_SetSizeRelH;
CChangesParaDrawingSizeRelH.prototype.private_SetValue = function(Value)
{
	this.Class.SizeRelH = Value;
};
CChangesParaDrawingSizeRelH.prototype.WriteToBinary = function(Writer)
{
	// Bool  : New is undefined
	// false->
	//       Long   : New.RelativeFrom
	//       Double : New.Percent
	// Bool  : Old is undefined
	// false->
	//       Long   : Old.RelativeFrom
	//       Double : Old.Percent

	if (this.New)
	{
		Writer.WriteBool(false);
		Writer.WriteLong(this.New.RelativeFrom);
		Writer.WriteDouble(this.New.Percent);
	}
	else
	{
		Writer.WriteBool(true);
	}

	if (this.Old)
	{
		Writer.WriteBool(false);
		Writer.WriteLong(this.Old.RelativeFrom);
		Writer.WriteDouble(this.Old.Percent);
	}
	else
	{
		Writer.WriteBool(true);
	}
};
CChangesParaDrawingSizeRelH.prototype.ReadFromBinary = function(Reader)
{
	// Bool  : New is undefined
	// false->
	//       Long   : New.RelativeFrom
	//       Double : New.Percent
	// Bool  : Old is undefined
	// false->
	//       Long   : Old.RelativeFrom
	//       Double : Old.Percent

	if (true === Reader.GetBool())
	{
		this.New = undefined;
	}
	else
	{
		this.New = {};
		this.New.RelativeFrom = Reader.GetLong();
		this.New.Percent      = Reader.GetDouble();
	}

	if (true === Reader.GetBool())
	{
		this.Old = undefined;
	}
	else
	{
		this.Old = {};
		this.Old.RelativeFrom = Reader.GetLong();
		this.Old.Percent      = Reader.GetDouble();
	}
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesParaDrawingSizeRelV(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesParaDrawingSizeRelV.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesParaDrawingSizeRelV.prototype.constructor = CChangesParaDrawingSizeRelV;
CChangesParaDrawingSizeRelV.prototype.Type = AscDFH.historyitem_Drawing_SetSizeRelV;
CChangesParaDrawingSizeRelV.prototype.private_SetValue = function(Value)
{
	this.Class.SizeRelV = Value;
};
CChangesParaDrawingSizeRelV.prototype.WriteToBinary = function(Writer)
{
	// Bool  : New is undefined
	// false->
	//       Long   : New.RelativeFrom
	//       Double : New.Percent
	// Bool  : Old is undefined
	// false->
	//       Long   : Old.RelativeFrom
	//       Double : Old.Percent

	if (this.New)
	{
		Writer.WriteBool(false);
		Writer.WriteLong(this.New.RelativeFrom);
		Writer.WriteDouble(this.New.Percent);
	}
	else
	{
		Writer.WriteBool(true);
	}

	if (this.Old)
	{
		Writer.WriteBool(false);
		Writer.WriteLong(this.Old.RelativeFrom);
		Writer.WriteDouble(this.Old.Percent);
	}
	else
	{
		Writer.WriteBool(true);
	}
};
CChangesParaDrawingSizeRelV.prototype.ReadFromBinary = function(Reader)
{
	// Bool  : New is undefined
	// false->
	//       Long   : New.RelativeFrom
	//       Double : New.Percent
	// Bool  : Old is undefined
	// false->
	//       Long   : Old.RelativeFrom
	//       Double : Old.Percent

	if (true === Reader.GetBool())
	{
		this.New = undefined;
	}
	else
	{
		this.New = {};
		this.New.RelativeFrom = Reader.GetLong();
		this.New.Percent      = Reader.GetDouble();
	}

	if (true === Reader.GetBool())
	{
		this.Old = undefined;
	}
	else
	{
		this.Old = {};
		this.Old.RelativeFrom = Reader.GetLong();
		this.Old.Percent      = Reader.GetDouble();
	}
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 20.10.2017
 * Time: 15:46
 */

var fieldtype_UNKNOWN    = 0x0000;
var fieldtype_MERGEFIELD = 0x0001;
var fieldtype_PAGENUM    = 0x0002;
var fieldtype_PAGECOUNT  = 0x0003;
var fieldtype_FORMTEXT   = 0x0004;
var fieldtype_TOC        = 0x0005;
var fieldtype_PAGEREF    = 0x0006;
var fieldtype_PAGE       = fieldtype_PAGENUM;
var fieldtype_NUMPAGES   = fieldtype_PAGECOUNT;

var fieldtype_ASK        = 0x0007;
var fieldtype_REF        = 0x0008;
var fieldtype_HYPERLINK  = 0x0009;

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};

window['AscCommonWord'].fieldtype_UNKNOWN    = fieldtype_UNKNOWN;
window['AscCommonWord'].fieldtype_MERGEFIELD = fieldtype_MERGEFIELD;
window['AscCommonWord'].fieldtype_PAGENUM    = fieldtype_PAGENUM;
window['AscCommonWord'].fieldtype_PAGECOUNT  = fieldtype_PAGECOUNT;
window['AscCommonWord'].fieldtype_FORMTEXT   = fieldtype_FORMTEXT;
window['AscCommonWord'].fieldtype_TOC        = fieldtype_TOC;
window['AscCommonWord'].fieldtype_PAGEREF    = fieldtype_PAGEREF;
window['AscCommonWord'].fieldtype_PAGE       = fieldtype_PAGE;
window['AscCommonWord'].fieldtype_NUMPAGES   = fieldtype_NUMPAGES;
window['AscCommonWord'].fieldtype_ASK        = fieldtype_ASK;
window['AscCommonWord'].fieldtype_REF        = fieldtype_REF;
window['AscCommonWord'].fieldtype_HYPERLINK  = fieldtype_HYPERLINK;

/**
 * Базовый класс для инструкции сложного поля.
 * @constructor
 */
function CFieldInstructionBase()
{
	this.ComplexField = null;
}
CFieldInstructionBase.prototype.Type = fieldtype_UNKNOWN;
CFieldInstructionBase.prototype.GetType = function()
{
	return this.Type;
};
CFieldInstructionBase.prototype.SetComplexField = function(oComplexField)
{
	this.ComplexField = oComplexField;
};
CFieldInstructionBase.prototype.GetComplexField = function()
{
	return this.ComplexField;
};
CFieldInstructionBase.prototype.ToString = function()
{
	return "";
};
CFieldInstructionBase.prototype.SetPr = function()
{
};

/**
 * PAGE field
 * @constructor
 */
function CFieldInstructionPAGE()
{
	CFieldInstructionBase.call(this);
}

CFieldInstructionPAGE.prototype = Object.create(CFieldInstructionBase.prototype);
CFieldInstructionPAGE.prototype.constructor = CFieldInstructionPAGE;
CFieldInstructionPAGE.prototype.Type = fieldtype_PAGE;

/**
 * PAGEREF field
 * @constructor
 */
function CFieldInstructionPAGEREF(sBookmarkName, isHyperlink, isPositionRelative)
{
	CFieldInstructionBase.call(this);

	this.BookmarkName = sBookmarkName ? sBookmarkName : "";
	this.Hyperlink    = isHyperlink ? true : false;
	this.PosRelative  = isPositionRelative ? true : false;
}

CFieldInstructionPAGEREF.prototype = Object.create(CFieldInstructionBase.prototype);
CFieldInstructionPAGEREF.prototype.constructor = CFieldInstructionPAGEREF;
CFieldInstructionPAGEREF.prototype.Type = fieldtype_PAGEREF;
CFieldInstructionPAGEREF.prototype.SetHyperlink = function(isHyperlink)
{
	this.Hyperlink   = isHyperlink ? true : false;
};
CFieldInstructionPAGEREF.prototype.SetPositionRelative = function(isPosRel)
{
	this.PosRelative = isPosRel ? true : false;
};
CFieldInstructionPAGEREF.prototype.IsHyperlink = function()
{
	return this.Hyperlink;
};
CFieldInstructionPAGEREF.prototype.IsPositionRelative = function()
{
	return this.PosRelative;
};
CFieldInstructionPAGEREF.prototype.GetBookmarkName = function()
{
	return this.BookmarkName;
};

/**
 * TOC field
 * @constructor
 */
function CFieldInstructionTOC()
{
	CFieldInstructionBase.call(this);

	this.PreserveTabs     = false;
	this.RemoveBreaks     = true;
	this.Hyperlinks       = false;
	this.Separator        = "";
	this.HeadingS         = -1;
	this.HeadingE         = -1;
	this.Styles           = [];
	this.SkipPageRef      = false;
	this.SkipPageRefStart = -1;
	this.SkipPageRefEnd   = -1;
	this.ForceTabLeader   = undefined;
}

CFieldInstructionTOC.prototype = Object.create(CFieldInstructionBase.prototype);
CFieldInstructionTOC.prototype.constructor = CFieldInstructionTOC;
CFieldInstructionTOC.prototype.Type = fieldtype_TOC;
CFieldInstructionTOC.prototype.IsPreserveTabs = function()
{
	return this.PreserveTabs;
};
CFieldInstructionTOC.prototype.SetPreserveTabs = function(isPreserve)
{
	this.PreserveTabs = isPreserve;
};
CFieldInstructionTOC.prototype.IsRemoveBreaks = function()
{
	return this.RemoveBreaks;
};
CFieldInstructionTOC.prototype.SetRemoveBreaks = function(isRemove)
{
	this.RemoveBreaks = isRemove;
};
CFieldInstructionTOC.prototype.IsHyperlinks = function()
{
	return this.Hyperlinks;
};
CFieldInstructionTOC.prototype.SetHyperlinks = function(isHyperlinks)
{
	this.Hyperlinks = isHyperlinks;
};
CFieldInstructionTOC.prototype.SetSeparator = function(sSeparator)
{
	this.Separator = sSeparator;
};
CFieldInstructionTOC.prototype.GetSeparator = function()
{
	return this.Separator;
};
CFieldInstructionTOC.prototype.SetHeadingRange = function(nStart, nEnd)
{
	this.HeadingS = nStart;
	this.HeadingE = nEnd;
};
CFieldInstructionTOC.prototype.GetHeadingRangeStart = function()
{
	return this.HeadingS;
};
CFieldInstructionTOC.prototype.GetHeadingRangeEnd = function()
{
	return this.HeadingE;
};
CFieldInstructionTOC.prototype.SetStylesArrayRaw = function(sString)
{
	// В спецификации написано, то разделено запятыми, но на деле Word реагирует на точку с запятой
	var arrValues = sString.split(";");
	var arrStyles = [];

	for (var nIndex = 0, nCount = arrValues.length; nIndex < nCount - 1; nIndex += 2)
	{
		var sName = arrValues[nIndex];
		var nLvl  = parseInt(arrValues[nIndex + 1]);
		if (isNaN(nLvl))
			break;

		arrStyles.push({
			Name : sName,
			Lvl  : nLvl
		});
	}

	this.SetStylesArray(arrStyles);
};
CFieldInstructionTOC.prototype.SetStylesArray = function(arrStyles)
{
	this.Styles = arrStyles;
};
CFieldInstructionTOC.prototype.GetStylesArray = function()
{
	return this.Styles;
};
CFieldInstructionTOC.prototype.SetPageRefSkippedLvls = function(isSkip, nSkipStart, nSkipEnd)
{
	this.SkipPageRef = isSkip;

	if (true === isSkip
		&& null !== nSkipStart
		&& undefined !== nSkipStart
		&& null !== nSkipEnd
		&& undefined !== nSkipEnd)
	{
		this.SkipPageRefStart = nSkipStart;
		this.SkipPageRefEnd   = nSkipEnd;
	}
	else
	{
		this.SkipPageRefStart = -1;
		this.SkipPageRefEnd   = -1;
	}
};
CFieldInstructionTOC.prototype.IsSkipPageRefLvl = function(nLvl)
{
	if (undefined === nLvl)
		return this.SkipPageRef;

	if (false === this.SkipPageRef)
		return false;

	if (-1 === this.SkipPageRefStart || -1 === this.SkipPageRefEnd)
		return true;

	return  (nLvl >= this.SkipPageRefStart - 1 && nLvl <= this.SkipPageRefEnd - 1);
};
CFieldInstructionTOC.prototype.SetPr = function(oPr)
{
	if (!(oPr instanceof Asc.CTableOfContentsPr))
		return;

	this.SetStylesArray(oPr.get_Styles());
	this.SetHeadingRange(oPr.get_OutlineStart(), oPr.get_OutlineEnd());
	this.SetHyperlinks(oPr.get_Hyperlink());

	if (oPr.PageNumbers)
		this.SetPageRefSkippedLvls(false);
	else
		this.SetPageRefSkippedLvls(true);

	if (oPr.RightTab)
		this.SetSeparator("");
	else
		this.SetSeparator(" ");

	this.ForceTabLeader = oPr.TabLeader;
};
CFieldInstructionTOC.prototype.GetForceTabLeader = function()
{
	var nTabLeader = this.ForceTabLeader;
	this.ForceTabLeader = undefined;
	return nTabLeader;
};
CFieldInstructionTOC.prototype.ToString = function()
{
	var sInstr = "TOC ";

	if (this.HeadingS >= 1
		&& this.HeadingS <= 9
		&& this.HeadingE >= this.HeadingS
		&& this.HeadingE <= 9)
		sInstr +=  "\\o " + "\"" + this.HeadingS + "-" + this.HeadingE + "\" ";

	if (this.SkipPageRef)
	{
		sInstr += "\\n ";

		if (this.SkipPageRefStart >= 1
			&& this.SkipPageRefStart <= 9
			&& this.SkipPageRefEnd >= this.SkipPageRefStart
			&& this.SkipPageRefEnd <= 9)
			sInstr +=  "\"" + this.SkipPageRefStart + "-" + this.SkipPageRefEnd + "\" ";
	}

	if (this.Hyperlinks)
		sInstr += "\\h ";

	if (!this.RemoveBreaks)
		sInstr += "\\x ";

	if (this.PreserveTabs)
		sInstr += "\\w ";

	if (this.Separator)
		sInstr += "\\p \"" + this.Separator + "\"";

	if (this.Styles.length > 0)
	{
		sInstr += "\\t \"";

		for (var nIndex = 0, nCount = this.Styles.length; nIndex < nCount; ++nIndex)
		{
			sInstr += this.Styles[nIndex].Name + ";" + this.Styles[nIndex].Lvl + ";";
		}

		sInstr += "\" ";
	}

	return sInstr;
};

/**
 * ASK field
 * @constructor
 */
function CFieldInstructionASK()
{
	CFieldInstructionBase.call(this);

	this.BookmarkName = "";
	this.PromptText   = "";
}
CFieldInstructionASK.prototype = Object.create(CFieldInstructionBase.prototype);
CFieldInstructionASK.prototype.constructor = CFieldInstructionASK;
CFieldInstructionASK.prototype.Type = fieldtype_ASK;
CFieldInstructionASK.prototype.SetBookmarkName = function(sBookmarkName)
{
	this.BookmarkName = sBookmarkName;
};
CFieldInstructionASK.prototype.GetBookmarkName = function()
{
	return this.BookmarkName;
};
CFieldInstructionASK.prototype.SetPromptText = function(sText)
{
	this.PromptText = sText;
};
CFieldInstructionASK.prototype.GetPromptText = function()
{
	if (!this.PromptText)
		return this.BookmarkName;

	return this.PromptText;
};

/**
 * REF field
 * @constructor
 */
function CFieldInstructionREF()
{
	CFieldInstructionBase.call(this);

	this.BookmarkName = "";
}
CFieldInstructionREF.prototype = Object.create(CFieldInstructionBase.prototype);
CFieldInstructionREF.prototype.constructor = CFieldInstructionREF;
CFieldInstructionREF.prototype.Type = fieldtype_REF;
CFieldInstructionREF.prototype.SetBookmarkName = function(sBookmarkName)
{
	this.BookmarkName = sBookmarkName;
};
CFieldInstructionREF.prototype.GetBookmarkName = function()
{
	return this.BookmarkName;
};

/**
 * NUMPAGES field
 * @constructor
 */
function CFieldInstructionNUMPAGES()
{
	CFieldInstructionBase.call(this);
}
CFieldInstructionNUMPAGES.prototype = Object.create(CFieldInstructionBase.prototype);
CFieldInstructionNUMPAGES.prototype.constructor = CFieldInstructionNUMPAGES;
CFieldInstructionNUMPAGES.prototype.Type = fieldtype_NUMPAGES;

/**
 * HYPERLINK field
 * @constructor
 */
function CFieldInstructionHYPERLINK()
{
	CFieldInstructionBase.call(this);

	this.ToolTip      = "";
	this.Link         = "";
	this.BookmarkName = "";
}
CFieldInstructionHYPERLINK.prototype = Object.create(CFieldInstructionBase.prototype);
CFieldInstructionHYPERLINK.prototype.constructor = CFieldInstructionHYPERLINK;
CFieldInstructionHYPERLINK.prototype.Type = fieldtype_HYPERLINK;
CFieldInstructionHYPERLINK.prototype.SetToolTip = function(sToolTip)
{
	this.ToolTip = sToolTip;
};
CFieldInstructionHYPERLINK.prototype.GetToolTip = function()
{
	if ("" === this.ToolTip)
		return this.Link;

	return this.ToolTip;
};
CFieldInstructionHYPERLINK.prototype.SetLink = function(sLink)
{
	this.Link = sLink;
};
CFieldInstructionHYPERLINK.prototype.GetLink = function()
{
	return this.Link;
};
CFieldInstructionHYPERLINK.prototype.SetBookmarkName = function(sBookmarkName)
{
	this.BookmarkName = sBookmarkName;
};
CFieldInstructionHYPERLINK.prototype.GetBookmarkName = function()
{
	return this.BookmarkName;
};
CFieldInstructionHYPERLINK.prototype.ToString = function()
{
	var sInstr = "HYPERLINK ";
	if (this.Link)
		sInstr +=  "\"" + this.Link + "\"";

	if (this.ToolTip)
		sInstr += "\\o \"" + this.ToolTip + "\"";

	if (this.BookmarkName)
		sInstr += "\\l " + this.BookmarkName;

	return sInstr;
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для совместимости с обычным ParaHyperlink
//----------------------------------------------------------------------------------------------------------------------
CFieldInstructionHYPERLINK.prototype.GetAnchor = function()
{
	return this.GetBookmarkName();
};
CFieldInstructionHYPERLINK.prototype.GetValue = function()
{
	return this.GetLink();
};
CFieldInstructionHYPERLINK.prototype.SetVisited = function(isVisited)
{
};
/**
 * Проверяем является ли данная ссылка ссылкой в начало документа
 * @returns {boolean}
 */
CFieldInstructionHYPERLINK.prototype.IsTopOfDocument = function()
{
	return (this.GetBookmarkName() === "_top");
};


/**
 * Класс для разбора строки с инструкцией
 * @constructor
 */
function CFieldInstructionParser()
{
	this.Line   = "";
	this.Pos    = 0;
	this.Buffer = "";
	this.Result = null;

	this.SavedStates = [];
}
CFieldInstructionParser.prototype.GetInstructionClass = function(sLine)
{
	this.Line   = sLine;
	this.Pos    = 0;
	this.Buffer = "";
	this.Result = null;

	this.private_Parse();

	return this.Result;
};
CFieldInstructionParser.prototype.private_Parse = function()
{
	if (!this.private_ReadNext())
		return this.private_ReadREF("");

	switch (this.Buffer.toUpperCase())
	{
		case "PAGE": this.private_ReadPAGE(); break;
		case "PAGEREF": this.private_ReadPAGEREF(); break;
		case "TOC": this.private_ReadTOC(); break;
		case "ASK": this.private_ReadASK(); break;
		case "REF": this.private_ReadREF(); break;
		case "NUMPAGES": this.private_ReadNUMPAGES(); break;
		case "HYPERLINK": this.private_ReadHYPERLINK(); break;

		default: this.private_ReadREF(this.Buffer); break;
	}
};
CFieldInstructionParser.prototype.private_ReadNext = function()
{
	var nLen  = this.Line.length,
		bWord = false;

	this.Buffer = "";

	while (this.Pos < nLen)
	{
		var nCharCode = this.Line.charCodeAt(this.Pos);
		if (32 === nCharCode || 9 === nCharCode)
		{
			if (bWord)
				return true;
		}
		else if (34 === nCharCode && (0 === this.Pos || 92 !== this.Line.charCodeAt(this.Pos - 1)))
		{
			// Кавычки
			this.Pos++;
			while (this.Pos < nLen)
			{
				nCharCode = this.Line.charCodeAt(this.Pos);
				if (34 === nCharCode && 92 !== this.Line.charCodeAt(this.Pos - 1))
				{
					this.Pos++;
					break;
				}

				bWord = true;

				if (34 === nCharCode && 92 === this.Line.charCodeAt(this.Pos - 1) && this.Buffer.length > 0)
					this.Buffer = this.Buffer.substring(0, this.Buffer.length - 1);

				this.Buffer += this.Line.charAt(this.Pos);

				this.Pos++;
			}

			return bWord;
		}
		else
		{
			this.Buffer += this.Line.charAt(this.Pos);
			bWord = true;
		}

		this.Pos++;
	}

	if (bWord)
		return true;

	return false;
};
CFieldInstructionParser.prototype.private_ReadArguments = function()
{
	var arrArguments = [];

	var sArgument = this.private_ReadArgument();
	while (null !== sArgument)
	{
		arrArguments.push(sArgument);
		sArgument = this.private_ReadArgument();
	}

	return arrArguments;
};
CFieldInstructionParser.prototype.private_ReadArgument = function()
{
	this.private_SaveState();

	if (!this.private_ReadNext())
		return null;

	if (this.private_IsSwitch())
	{
		this.private_RestoreState();
		return null;
	}

	this.private_RemoveLastState();
	return this.Buffer;
};
CFieldInstructionParser.prototype.private_IsSwitch = function()
{
	return this.Buffer.charAt(0) === '\\';
};
CFieldInstructionParser.prototype.private_GetSwitchLetter = function()
{
	return this.Buffer.charAt(1);
};
CFieldInstructionParser.prototype.private_SaveState = function()
{
	this.SavedStates.push(this.Pos);
};
CFieldInstructionParser.prototype.private_RestoreState = function()
{
	if (this.SavedStates.length > 0)
		this.Pos = this.SavedStates[this.SavedStates.length - 1];

	this.private_RemoveLastState();
};
CFieldInstructionParser.prototype.private_RemoveLastState = function()
{
	if (this.SavedStates.length > 0)
		this.SavedStates.splice(this.SavedStates.length - 1, 1);
};
CFieldInstructionParser.prototype.private_ReadGeneralFormatSwitch = function()
{
	if (!this.private_IsSwitch() || this.Buffer.charAt(1) !== '*')
		return;

	if (!this.private_ReadNext() || this.private_IsSwitch())
		return;

	// TODO: Тут надо прочитать поле

	//console.log("General switch: " + this.Buffer);
};
CFieldInstructionParser.prototype.private_ReadPAGE = function()
{
	this.Result = new CFieldInstructionPAGE();

	// Zero or more general-formatting-switches

	while (this.private_ReadNext())
	{
		if (this.private_IsSwitch())
			this.private_ReadGeneralFormatSwitch();
	}
};
CFieldInstructionParser.prototype.private_ReadPAGEREF = function()
{
	var sBookmarkName = null;
	var isHyperlink = false, isPageRel = false;

	var isSwitch = false, isBookmark = false;

	while (this.private_ReadNext())
	{
		if (this.private_IsSwitch())
		{
			isSwitch = true;

			if ('p' === this.Buffer.charAt(1))
				isPageRel = true;
			else if ('h' === this.Buffer.charAt(1))
				isHyperlink = true;
		}
		else if (!isSwitch && !isBookmark)
		{
			sBookmarkName = this.Buffer;
			isBookmark    = true;
		}
	}

	this.Result = new CFieldInstructionPAGEREF(sBookmarkName, isHyperlink, isPageRel);
};
CFieldInstructionParser.prototype.private_ReadTOC = function()
{
	// TODO: \a, \b, \c, \d, \f, \l, \s, \z, \u

	this.Result = new CFieldInstructionTOC();

	while (this.private_ReadNext())
	{
		if (this.private_IsSwitch())
		{
			var sType = this.private_GetSwitchLetter();
			if ('w' === sType)
			{
				this.Result.SetPreserveTabs(true);
			}
			else if ('x' === sType)
			{
				this.Result.SetRemoveBreaks(false);
			}
			else if ('h' === sType)
			{
				this.Result.SetHyperlinks(true);
			}
			else if ('p' === sType)
			{
				var arrArguments = this.private_ReadArguments();
				if (arrArguments.length > 0)
					this.Result.SetSeparator(arrArguments[0]);
			}
			else if ('o' === sType)
			{
				var arrArguments = this.private_ReadArguments();
				if (arrArguments.length > 0)
				{
					var arrRange = this.private_ParseIntegerRange(arrArguments[0]);
					if (null !== arrRange)
						this.Result.SetHeadingRange(arrRange[0], arrRange[1]);
				}
			}
			else if ('t' === sType)
			{
				var arrArguments = this.private_ReadArguments();
				if (arrArguments.length > 0)
					this.Result.SetStylesArrayRaw(arrArguments[0]);
			}
			else if ('n' === sType)
			{
				var arrArguments = this.private_ReadArguments();
				if (arrArguments.length > 0)
				{
					var arrRange = this.private_ParseIntegerRange(arrArguments[0]);
					if (null !== arrRange)
						this.Result.SetPageRefSkippedLvls(true, arrRange[0], arrRange[1]);
					else
						this.Result.SetPageRefSkippedLvls(true, -1, -1);
				}
				else
				{
					this.Result.SetPageRefSkippedLvls(true, -1, -1);
				}
			}
		}


	}

};
CFieldInstructionParser.prototype.private_ReadASK = function()
{
	this.Result = new CFieldInstructionASK();

	var arrArguments = this.private_ReadArguments();

	if (arrArguments.length >= 2)
		this.Result.SetPromptText(arrArguments[1]);

	if (arrArguments.length >= 1)
		this.Result.SetBookmarkName(arrArguments[0]);

	// TODO: Switches
};
CFieldInstructionParser.prototype.private_ReadREF = function(sBookmarkName)
{
	this.Result = new CFieldInstructionREF();

	if (undefined !== sBookmarkName)
	{
		this.Result.SetBookmarkName(sBookmarkName);
	}
	else
	{
		var arrArguments = this.private_ReadArguments();
		if (arrArguments.length > 0)
		{
			this.Result.SetBookmarkName(arrArguments[0]);
		}
	}

	// TODO: Switches
};
CFieldInstructionParser.prototype.private_ReadNUMPAGES = function()
{
	this.Result = new CFieldInstructionNUMPAGES();

	// TODO: Switches
};
CFieldInstructionParser.prototype.private_ReadHYPERLINK = function()
{
	this.Result = new CFieldInstructionHYPERLINK();
	var arrArguments = this.private_ReadArguments();
	if (arrArguments.length > 0)
		this.Result.SetLink(arrArguments[0]);

	while (this.private_ReadNext())
	{
		if (this.private_IsSwitch())
		{
			var sType = this.private_GetSwitchLetter();
			if ('o' === sType)
			{
				arrArguments = this.private_ReadArguments();
				if (arrArguments.length > 0)
					this.Result.SetToolTip(arrArguments[0]);
			}
			else if ('l' === sType)
			{
				arrArguments = this.private_ReadArguments();
				if (arrArguments.length > 0)
					this.Result.SetBookmarkName(arrArguments[0]);
			}

			// TODO: Остальные флаги \m \n \t для нас бесполезны
		}
	}
};
CFieldInstructionParser.prototype.private_ParseIntegerRange = function(sValue)
{
	// value1-value2

	var nSepPos = sValue.indexOf("-");
	if (-1 === nSepPos)
		return null;

	var nValue1 = parseInt(sValue.substr(0, nSepPos));
	var nValue2 = parseInt(sValue.substr(nSepPos + 1));

	if (isNaN(nValue1) || isNaN(nValue2))
		return null;

	return [nValue1, nValue2];
};




/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 15.08.2017
 * Time: 12:52
 */

var fldchartype_Begin    = 0;
var fldchartype_Separate = 1;
var fldchartype_End      = 2;

function ParaFieldChar(Type, LogicDocument)
{
	CRunElementBase.call(this);

	this.LogicDocument = LogicDocument;
	this.Use           = true;
	this.CharType      = undefined === Type ? fldchartype_Begin : Type;
	this.ComplexField  = (this.CharType === fldchartype_Begin) ? new CComplexField(LogicDocument) : null;
	this.Run           = null;
	this.X             = 0;
	this.Y             = 0;
	this.PageAbs       = 0;

	this.FontKoef      = 1;
	this.NumWidths     = [];
	this.Widths        = [];
	this.String        = "";
	this.NumValue      = null;
}
ParaFieldChar.prototype = Object.create(CRunElementBase.prototype);
ParaFieldChar.prototype.constructor = ParaFieldChar;
ParaFieldChar.prototype.Type = para_FieldChar;
ParaFieldChar.prototype.Copy = function()
{
	return new ParaFieldChar(this.CharType, this.LogicDocument);
};
ParaFieldChar.prototype.Measure = function(Context, TextPr)
{
	if (this.IsSeparate())
	{
		this.FontKoef = TextPr.Get_FontKoef();
		Context.SetFontSlot(fontslot_ASCII, this.FontKoef);

		for (var Index = 0; Index < 10; Index++)
		{
			this.NumWidths[Index] = Context.Measure("" + Index).Width;
		}

		this.private_UpdateWidth();
	}
};
ParaFieldChar.prototype.Draw = function(X, Y, Context)
{
	if (this.IsSeparate() && null !== this.NumValue)
	{
		var Len = this.String.length;

		var _X = X;
		var _Y = Y;

		Context.SetFontSlot(fontslot_ASCII, this.FontKoef);
		for (var Index = 0; Index < Len; Index++)
		{
			var Char = this.String.charAt(Index);
			Context.FillText(_X, _Y, Char);
			_X += this.Widths[Index];
		}
	}
};
ParaFieldChar.prototype.IsBegin = function()
{
	return (this.CharType === fldchartype_Begin ? true : false);
};
ParaFieldChar.prototype.IsEnd = function()
{
	return (this.CharType === fldchartype_End ? true : false);
};
ParaFieldChar.prototype.IsSeparate = function()
{
	return (this.CharType === fldchartype_Separate ? true : false);
};
ParaFieldChar.prototype.IsUse = function()
{
	return this.Use;
};
ParaFieldChar.prototype.SetUse = function(isUse)
{
	this.Use = isUse;
};
ParaFieldChar.prototype.GetComplexField = function()
{
	return this.ComplexField;
};
ParaFieldChar.prototype.SetComplexField = function(oComplexField)
{
	this.ComplexField = oComplexField;
};
ParaFieldChar.prototype.Write_ToBinary = function(Writer)
{
	// Long : Type
	// Long : CharType
	Writer.WriteLong(this.Type);
	Writer.WriteLong(this.CharType);
};
ParaFieldChar.prototype.Read_FromBinary = function(Reader)
{
	// Long : CharType
	this.CharType = Reader.GetLong();

	this.LogicDocument = editor.WordControl.m_oLogicDocument;
	this.ComplexField  = (this.CharType === fldchartype_Begin) ? new CComplexField(this.LogicDocument) : null;
};
ParaFieldChar.prototype.SetParent = function(oParent)
{
	this.Run = oParent;
};
ParaFieldChar.prototype.SetRun = function(oRun)
{
	this.Run = oRun;
};
ParaFieldChar.prototype.GetRun = function()
{
	return this.Run;
};
ParaFieldChar.prototype.SetXY = function(X, Y)
{
	this.X = X;
	this.Y = Y;
};
ParaFieldChar.prototype.GetXY = function()
{
	return {X : this.X, Y : this.Y};
};
ParaFieldChar.prototype.SetPage = function(nPage)
{
	this.PageAbs = nPage;
};
ParaFieldChar.prototype.GetPage = function()
{
	return this.PageAbs;
};
ParaFieldChar.prototype.GetTopDocumentContent = function()
{
	if (!this.Run)
		return null;

	var oParagraph = this.Run.GetParagraph();
	if (!oParagraph)
		return null;

	return oParagraph.Parent.GetTopDocumentContent();
};
/**
 * Специальная функция для работы с полями PAGE NUMPAGES в колонтитулах
 * @param nValue
 */
ParaFieldChar.prototype.SetNumValue = function(nValue)
{
	this.NumValue = nValue;
	this.private_UpdateWidth();
};
ParaFieldChar.prototype.private_UpdateWidth = function()
{
	if (null === this.NumValue)
		return;

	this.String = "" + this.NumValue;

	var RealWidth = 0;
	for (var Index = 0, Len = this.String.length; Index < Len; Index++)
	{
		var Char = parseInt(this.String.charAt(Index));

		this.Widths[Index] = this.NumWidths[Char];
		RealWidth += this.NumWidths[Char];
	}

	RealWidth = (RealWidth * TEXTWIDTH_DIVIDER) | 0;

	this.Width        = RealWidth;
	this.WidthVisible = RealWidth;
};
ParaFieldChar.prototype.IsNumValue = function()
{
	return (this.IsSeparate() && null !== this.NumValue ? true : false);
};
ParaFieldChar.prototype.SaveRecalculateObject = function(Copy)
{
	return new CPageNumRecalculateObject(this.Type, this.Widths, this.String, this.Width, Copy);
};
ParaFieldChar.prototype.LoadRecalculateObject = function(RecalcObj)
{
	this.Widths = RecalcObj.Widths;
	this.String = RecalcObj.String;

	this.Width        = RecalcObj.Width;
	this.WidthVisible = this.Width;
};
ParaFieldChar.prototype.PrepareRecalculateObject = function()
{
	this.Widths = [];
	this.String = "";
};

/**
 * Класс представляющий символ инструкции сложного поля
 * @param {Number} nCharCode
 * @constructor
 */
function ParaInstrText(nCharCode)
{
	CRunElementBase.call(this);

	this.Value        = (undefined !== nCharCode ? nCharCode : 0x00);
	this.Width        = 0x00000000 | 0;
	this.WidthVisible = 0x00000000 | 0;
	this.Run          = null;
	this.Replacement  = null; // Используется, когда InstrText идет в неположенном месте и должно восприниматься как обычный текст
}
ParaInstrText.prototype = Object.create(CRunElementBase.prototype);
ParaInstrText.prototype.constructor = ParaInstrText;
ParaInstrText.prototype.Type = para_InstrText;
ParaInstrText.prototype.Copy = function()
{
	return new ParaInstrText(this.Value);
};
ParaInstrText.prototype.Measure = function(Context, TextPr)
{
};
ParaInstrText.prototype.Draw = function(X, Y, Context)
{
};
ParaInstrText.prototype.Write_ToBinary = function(Writer)
{
	// Long : Type
	// Long : Value
	Writer.WriteLong(this.Type);
	Writer.WriteLong(this.Value);
};
ParaInstrText.prototype.Read_FromBinary = function(Reader)
{
	// Long : Value
	this.Value = Reader.GetLong();
};
ParaInstrText.prototype.SetParent = function(oParent)
{
	this.Run = oParent;
};
ParaInstrText.prototype.SetRun = function(oRun)
{
	this.Run = oRun;
};
ParaInstrText.prototype.GetRun = function()
{
	return this.Run;
};
ParaInstrText.prototype.GetValue = function()
{
	return String.fromCharCode(this.Value);
};
ParaInstrText.prototype.Set_CharCode = function(CharCode)
{
	this.Value = CharCode;
};
ParaInstrText.prototype.SetReplacementItem = function(oItem)
{
	this.Replacement = oItem;
};
ParaInstrText.prototype.GetReplacementItem = function()
{
	return this.Replacement;
};

function CComplexField(oLogicDocument)
{
	this.LogicDocument   = oLogicDocument;
	this.Current         = false;
	this.BeginChar       = null;
	this.EndChar         = null;
	this.SeparateChar    = null;
	this.InstructionLine = "";
	this.Instruction     = null;
	this.Id              = null;
}
CComplexField.prototype.SetCurrent = function(isCurrent)
{
	this.Current = isCurrent;
};
CComplexField.prototype.IsCurrent = function()
{
	return this.Current;
};
CComplexField.prototype.SetInstruction = function(oParaInstr)
{
	this.InstructionLine += oParaInstr.GetValue();
};
CComplexField.prototype.SetInstructionLine = function(sLine)
{
	this.InstructionLine = sLine;
};
CComplexField.prototype.GetBeginChar = function()
{
	return this.BeginChar;
};
CComplexField.prototype.GetEndChar = function()
{
	return this.EndChar;
};
CComplexField.prototype.GetSeparateChar = function()
{
	return this.SeparateChar;
};
CComplexField.prototype.SetBeginChar = function(oChar)
{
	oChar.SetComplexField(this);

	this.BeginChar       = oChar;
	this.SeparateChar    = null;
	this.EndChar         = null;
	this.InstructionLine = "";
};
CComplexField.prototype.SetEndChar = function(oChar)
{
	oChar.SetComplexField(this);

	this.EndChar = oChar;
};
CComplexField.prototype.SetSeparateChar = function(oChar)
{
	oChar.SetComplexField(this);

	this.SeparateChar = oChar;
	this.EndChar      = null;
};
CComplexField.prototype.Update = function(isCreateHistoryPoint)
{
	this.private_UpdateInstruction();

	if (!this.Instruction || !this.BeginChar || !this.EndChar || !this.SeparateChar)
		return;

	this.SelectFieldValue();

	if (true === isCreateHistoryPoint)
	{
		if (true === this.LogicDocument.Document_Is_SelectionLocked(changestype_Paragraph_Content))
			return;

		this.LogicDocument.Create_NewHistoryPoint();
	}

	switch (this.Instruction.GetType())
	{
		case fieldtype_PAGE:
		case fieldtype_PAGENUM:
			this.private_UpdatePAGE();
			break;
		case fieldtype_TOC:
			this.private_UpdateTOC();
			break;
		case fieldtype_PAGEREF:
			this.private_UpdatePAGEREF();
			break;
		case fieldtype_NUMPAGES:
		case fieldtype_PAGECOUNT:
			this.private_UpdateNUMPAGES();
			break;

	}

	this.LogicDocument.Recalculate();
};
CComplexField.prototype.private_UpdatePAGE = function()
{
	var oRun       = this.BeginChar.GetRun();
	var oParagraph = oRun.GetParagraph();
	var nInRunPos = oRun.GetElementPosition(this.BeginChar);
	var nLine     = oRun.GetLineByPosition(nInRunPos);
	var nPage     = oParagraph.GetPageByLine(nLine);
	var nPageAbs  = oParagraph.Get_AbsolutePage(nPage) + 1;
	// TODO: Тут надо рассчитывать значение исходя из настроек секции

	this.LogicDocument.AddText("" + nPageAbs);
};
CComplexField.prototype.private_UpdateTOC = function()
{
	this.LogicDocument.GetBookmarksManager().RemoveTOCBookmarks();

	var nTabPos = 9345 / 20 / 72 * 25.4; // Стандартное значение для A4 и обычных полей 3см и 2см
	var oSectPr = this.LogicDocument.GetCurrentSectionPr();
	if (oSectPr)
	{
		if (oSectPr.Get_ColumnsCount() > 1)
		{
			// TODO: Сейчас забирается ширина текущей колонки. По правильному надо читать поля от текущего места
			nTabPos = Math.max(0, Math.min(oSectPr.Get_ColumnWidth(0), oSectPr.Get_PageWidth(), oSectPr.Get_PageWidth() - oSectPr.Get_PageMargin_Left() - oSectPr.Get_PageMargin_Right()));
		}
		else
		{
			nTabPos = Math.max(0, Math.min(oSectPr.Get_PageWidth(), oSectPr.Get_PageWidth() - oSectPr.Get_PageMargin_Left() - oSectPr.Get_PageMargin_Right()));
		}
	}

	var oStyles          = this.LogicDocument.Get_Styles();
	var arrOutline       = this.LogicDocument.GetOutlineParagraphs(null, {
		OutlineStart : this.Instruction.GetHeadingRangeStart(),
		OutlineEnd   : this.Instruction.GetHeadingRangeEnd(),
		Styles       : this.Instruction.GetStylesArray()
	});
	var oSelectedContent = new CSelectedContent();

	var isPreserveTabs   = this.Instruction.IsPreserveTabs();
	var sSeparator       = this.Instruction.GetSeparator();

	var nForceTabLeader = this.Instruction.GetForceTabLeader();

	var oTab = new CParaTab(tab_Right, nTabPos, Asc.c_oAscTabLeader.Dot);
	if (undefined !== nForceTabLeader)
	{
		oTab = new CParaTab(tab_Right, nTabPos, nForceTabLeader);
	}
	else if ((!sSeparator || "" === sSeparator) && arrOutline.length > 0)
	{
		var arrSelectedParagraphs = this.LogicDocument.GetCurrentParagraph(false, true);
		if (arrSelectedParagraphs.length > 0)
		{
			var oPara = arrSelectedParagraphs[0];
			var oTabs = oPara.GetParagraphTabs();

			if (oTabs.Tabs.length > 0)
				oTab = oTabs.Tabs[oTabs.Tabs.length - 1];
		}
	}

	if (arrOutline.length > 0)
	{
		for (var nIndex = 0, nCount = arrOutline.length; nIndex < nCount; ++nIndex)
		{
			var oSrcParagraph = arrOutline[nIndex].Paragraph;

			var oPara = oSrcParagraph.Copy(null, null, {
				SkipPageBreak         : true,
				SkipLineBreak         : this.Instruction.IsRemoveBreaks(),
				SkipColumnBreak       : true,
				SkipAnchors           : true,
				SkipFootnoteReference : true,
				SkipComplexFields     : true,
				SkipComments          : true
			});
			oPara.Style_Add(oStyles.GetDefaultTOC(arrOutline[nIndex].Lvl), false);


			var oClearTextPr = new CTextPr();
			oClearTextPr.Set_FromObject({
				FontSize  : null,
				Unifill   : null,
				Underline : null,
				Color     : null
			});

			oPara.SelectAll();
			oPara.ApplyTextPr(oClearTextPr);
			oPara.RemoveSelection();

			var sBookmarkName = oSrcParagraph.AddBookmarkForTOC();

			var oContainer    = oPara,
				nContainerPos = 0;

			if (this.Instruction.IsHyperlinks())
			{
				var sHyperlinkStyleId = oStyles.GetDefaultHyperlink();

				var oHyperlink = new ParaHyperlink();
				for (var nParaPos = 0, nParaCount = oPara.Content.length - 1; nParaPos < nParaCount; ++nParaPos)
				{
					// TODO: Проверить, нужно ли проставлять этот стиль во внутренние раны
					if (oPara.Content[0] instanceof ParaRun)
						oPara.Content[0].Set_RStyle(sHyperlinkStyleId);

					oHyperlink.Add_ToContent(nParaPos, oPara.Content[0]);
					oPara.Remove_FromContent(0, 1);
				}
				oHyperlink.SetAnchor(sBookmarkName);
				oPara.Add_ToContent(0, oHyperlink);

				oContainer    = oHyperlink;
				nContainerPos = oHyperlink.Content.length;
			}
			else
			{
				// TODO: ParaEnd
				oContainer    = oPara;
				nContainerPos = oPara.Content.length - 1;
			}

			var isAddTabForNumbering = false;
			if (oSrcParagraph.HaveNumbering() && oSrcParagraph.GetParent())
			{
				var oNumPr     = oSrcParagraph.GetNumPr();
				var oNumbering = this.LogicDocument.GetNumbering();
				var oNumInfo   = oSrcParagraph.GetParent().CalculateNumberingValues(oSrcParagraph, oNumPr);
				var sText      = oNumbering.GetText(oNumPr.NumId, oNumPr.Lvl, oNumInfo);
				var oNumTextPr = oSrcParagraph.GetNumberingCompiledPr();

				var oNumberingRun = new ParaRun(oPara, false);
				oNumberingRun.AddText(sText);

				if (oNumTextPr)
					oNumberingRun.Set_RFonts(oNumTextPr.RFonts);

				oContainer.Add_ToContent(0, oNumberingRun);
				nContainerPos++;

				var oNumTabRun = new ParaRun(oPara, false);

				var oNumLvl  = oNumbering.GetNum(oNumPr.NumId).GetLvl(oNumPr.Lvl);
				var nNumSuff = oNumLvl.GetSuff();

				if (Asc.c_oAscNumberingSuff.Space === nNumSuff)
				{
					oNumTabRun.Add_ToContent(0, new ParaSpace());
					oContainer.Add_ToContent(1, oNumTabRun);
					nContainerPos++;
				}
				else if (Asc.c_oAscNumberingSuff.Tab === nNumSuff)
				{
					oNumTabRun.Add_ToContent(0, new ParaTab());
					isAddTabForNumbering = true;
					oContainer.Add_ToContent(1, oNumTabRun);
					nContainerPos++;
				}
			}

			// Word добавляет табы независимо о наличия Separator и PAGEREF
			var oTabs = new CParaTabs();
			oTabs.Add(oTab);

			if ((!isPreserveTabs && oPara.RemoveTabsForTOC()) || isAddTabForNumbering)
			{
				// TODO: Табы для нумерации как-то зависят от самой нумерации и не совсем такие, как без нумерации


				// В данной ситуации ворд делает следующим образом: он пробегает по параграфу и смотрит, если там есть
				// табы (в контенте, а не в свойствах), тогда он первый таб оставляет, а остальные заменяет на пробелы,
				// при этом в список табов добавляется новый левый таб без заполнителя, отступающий на 1,16 см от левого
				// поля параграфа, т.е. позиция таба зависит от стиля.

				var nFirstTabPos = 11.6;
				var sTOCStyleId  = this.LogicDocument.GetStyles().GetDefaultTOC(arrOutline[nIndex].Lvl);
				if (sTOCStyleId)
				{
					var oParaPr  = this.LogicDocument.GetStyles().Get_Pr(sTOCStyleId, styletype_Paragraph, null, null).ParaPr;
					nFirstTabPos = 11.6 + (oParaPr.Ind.Left + oParaPr.Ind.FirstLine);
				}

				oTabs.Add(new CParaTab(tab_Left, nFirstTabPos, Asc.c_oAscTabLeader.None));
			}

			oPara.Set_Tabs(oTabs);

			if (!(this.Instruction.IsSkipPageRefLvl(arrOutline[nIndex].Lvl)))
			{
				var oSeparatorRun = new ParaRun(oPara, false);
				if (!sSeparator || "" === sSeparator)
					oSeparatorRun.AddToContent(0, new ParaTab());
				else
					oSeparatorRun.AddText(sSeparator.charAt(0));

				oContainer.Add_ToContent(nContainerPos, oSeparatorRun);

				var oPageRefRun = new ParaRun(oPara, false);

				oPageRefRun.AddToContent(-1, new ParaFieldChar(fldchartype_Begin, this.LogicDocument));
				oPageRefRun.AddInstrText("PAGEREF " + sBookmarkName + " \\h");
				oPageRefRun.AddToContent(-1, new ParaFieldChar(fldchartype_Separate, this.LogicDocument));
				oPageRefRun.AddText("" + (oSrcParagraph.GetFirstNonEmptyPageAbsolute() + 1));
				oPageRefRun.AddToContent(-1, new ParaFieldChar(fldchartype_End, this.LogicDocument));
				oContainer.Add_ToContent(nContainerPos + 1, oPageRefRun);
			}

			oSelectedContent.Add(new CSelectedElement(oPara, true));
		}
	}
	else
	{
		var sReplacementText = AscCommon.translateManager.getValue("No table of contents entries found.");

		var oPara = new Paragraph(this.LogicDocument.GetDrawingDocument(), this.LogicDocument, false);
		var oRun  = new ParaRun(oPara, false);
		oRun.Set_Bold(true);
		oRun.AddText(sReplacementText);
		oPara.AddToContent(0, oRun);
		oSelectedContent.Add(new CSelectedElement(oPara, true));
	}

	this.LogicDocument.TurnOff_Recalculate();
	this.LogicDocument.TurnOff_InterfaceEvents();
	this.LogicDocument.Remove(1, false, false, false);
	this.LogicDocument.TurnOn_Recalculate(false);
	this.LogicDocument.TurnOn_InterfaceEvents(false);

	var oRun       = this.BeginChar.GetRun();
	var oParagraph = oRun.GetParagraph();
	var oNearPos   = {
		Paragraph  : oParagraph,
		ContentPos : oParagraph.Get_ParaContentPos(false, false)
	};
	oParagraph.Check_NearestPos(oNearPos);

	oSelectedContent.DoNotAddEmptyPara = true;

	oParagraph.Parent.Insert_Content(oSelectedContent, oNearPos);
};
CComplexField.prototype.private_UpdatePAGEREF = function()
{
	var oBookmarksManager = this.LogicDocument.GetBookmarksManager();
	var oBookmark = oBookmarksManager.GetBookmarkByName(this.Instruction.GetBookmarkName());

	var sValue = AscCommon.translateManager.getValue("Error! Bookmark not defined.");
	if (oBookmark)
	{
		var oStartBookmark = oBookmark[0];
		var nBookmarkPage  = oStartBookmark.GetPage() + 1;
		if (this.Instruction.IsPositionRelative())
		{
			if (oStartBookmark.GetPage() === this.SeparateChar.GetPage())
			{
				var oBookmarkXY = oStartBookmark.GetXY();
				var oFieldXY    = this.SeparateChar.GetXY();

				if (Math.abs(oBookmarkXY.Y - oFieldXY.Y) < 0.001)
					sValue = oBookmarkXY.X < oFieldXY.X ? AscCommon.translateManager.getValue("above") : AscCommon.translateManager.getValue("below");
				else if (oBookmarkXY.Y < oFieldXY.Y)
					sValue = AscCommon.translateManager.getValue("above");
				else
					sValue = AscCommon.translateManager.getValue("below");
			}
			else
			{
				sValue = AscCommon.translateManager.getValue("on page ") + nBookmarkPage;
			}
		}
		else
		{
			sValue = (oStartBookmark.GetPage() + 1) + "";
		}
	}

	this.LogicDocument.AddText(sValue);
};
CComplexField.prototype.private_UpdateNUMPAGES = function()
{
	this.LogicDocument.AddText("" + this.LogicDocument.GetPagesCount());
};
CComplexField.prototype.SelectFieldValue = function()
{
	var oDocument = this.GetTopDocumentContent();
	if (!oDocument)
		return;

	oDocument.RemoveSelection();

	var oRun = this.SeparateChar.GetRun();
	oRun.Make_ThisElementCurrent(false);
	oRun.SetCursorPosition(oRun.GetElementPosition(this.SeparateChar) + 1);
	var oStartPos = oDocument.GetContentPosition(false);

	oRun = this.EndChar.GetRun();
	oRun.Make_ThisElementCurrent(false);
	oRun.SetCursorPosition(oRun.GetElementPosition(this.EndChar));
	var oEndPos = oDocument.GetContentPosition(false);

	oDocument.SetSelectionByContentPositions(oStartPos, oEndPos);
};
CComplexField.prototype.SelectFieldCode = function()
{
	var oDocument = this.GetTopDocumentContent();
	if (!oDocument)
		return;

	oDocument.RemoveSelection();

	var oRun = this.BeginChar.GetRun();
	oRun.Make_ThisElementCurrent(false);
	oRun.SetCursorPosition(oRun.GetElementPosition(this.BeginChar) + 1);
	var oStartPos = oDocument.GetContentPosition(false);

	oRun = this.SeparateChar.GetRun();
	oRun.Make_ThisElementCurrent(false);
	oRun.SetCursorPosition(oRun.GetElementPosition(this.SeparateChar));
	var oEndPos = oDocument.GetContentPosition(false);

	oDocument.SetSelectionByContentPositions(oStartPos, oEndPos);
};
CComplexField.prototype.SelectField = function()
{
	var oDocument = this.GetTopDocumentContent();
	if (!oDocument)
		return;

	oDocument.RemoveSelection();

	var oRun = this.BeginChar.GetRun();
	oRun.Make_ThisElementCurrent(false);
	oRun.SetCursorPosition(oRun.GetElementPosition(this.BeginChar));
	var oStartPos = oDocument.GetContentPosition(false);

	oRun = this.EndChar.GetRun();
	oRun.Make_ThisElementCurrent(false);
	oRun.SetCursorPosition(oRun.GetElementPosition(this.EndChar) + 1);
	var oEndPos = oDocument.GetContentPosition(false);

	oDocument.RemoveSelection();
	oDocument.SetSelectionByContentPositions(oStartPos, oEndPos);
};
CComplexField.prototype.GetTopDocumentContent = function()
{
	if (!this.BeginChar || !this.SeparateChar || !this.EndChar)
		return;

	var oTopDocument = this.BeginChar.GetTopDocumentContent();

	if (oTopDocument !== this.EndChar.GetTopDocumentContent() || oTopDocument !== this.SeparateChar.GetTopDocumentContent())
		return null;

	return oTopDocument;
};
CComplexField.prototype.IsUse = function()
{
	if (!this.BeginChar)
		return false;

	return this.BeginChar.IsUse();
};
CComplexField.prototype.GetStartDocumentPosition = function()
{
	if (!this.BeginChar)
		return null;

	var oDocument = this.LogicDocument;
	var oState    = oDocument.SaveDocumentState();

	var oRun = this.BeginChar.GetRun();
	oRun.Make_ThisElementCurrent(false);
	oRun.SetCursorPosition(oRun.GetElementPosition(this.BeginChar));
	var oDocPos = oDocument.GetContentPosition(false);

	oDocument.LoadDocumentState(oState);

	return oDocPos;
};
CComplexField.prototype.GetEndDocumentPosition = function()
{
	if (!this.EndChar)
		return null;

	var oDocument = this.LogicDocument;
	var oState    = oDocument.SaveDocumentState();

	var oRun = this.EndChar.GetRun();
	oRun.Make_ThisElementCurrent(false);
	oRun.SetCursorPosition(oRun.GetElementPosition(this.EndChar) + 1);
	var oDocPos = oDocument.GetContentPosition(false);

	oDocument.LoadDocumentState(oState);

	return oDocPos;
};
CComplexField.prototype.IsValid = function()
{
	return this.IsUse() && this.BeginChar && this.SeparateChar && this.EndChar;
};
CComplexField.prototype.GetInstruction = function()
{
	this.private_UpdateInstruction();
	return this.Instruction;
};
CComplexField.prototype.private_UpdateInstruction = function()
{
	if (!this.Instruction && this.InstructionLine)
	{
		var oParser = new CFieldInstructionParser();
		this.Instruction = oParser.GetInstructionClass(this.InstructionLine);
		this.Instruction.SetComplexField(this);
	}
};
CComplexField.prototype.IsHidden = function()
{
	if (!this.BeginChar || !this.SeparateChar)
		return false;

	var oInstruction = this.GetInstruction();

	return (oInstruction && (fieldtype_ASK === oInstruction.GetType() || (this.SeparateChar.IsNumValue() && (fieldtype_NUMPAGES === oInstruction.GetType() || fieldtype_PAGE === oInstruction.GetType())))) ? true : false;
};
CComplexField.prototype.RemoveFieldWrap = function()
{
	if (!this.IsValid())
		return;

	var oRun = this.EndChar.GetRun();
	var nInRunPos = oRun.GetElementPosition(this.EndChar);
	if (-1 !== nInRunPos)
		oRun.RemoveFromContent(nInRunPos, 1);

	var oDocument = this.GetTopDocumentContent();
	if (!oDocument)
		return;

	var oRun = this.BeginChar.GetRun();
	oRun.Make_ThisElementCurrent(false);
	oRun.SetCursorPosition(oRun.GetElementPosition(this.BeginChar));
	var oStartPos = oDocument.GetContentPosition(false);

	oRun = this.SeparateChar.GetRun();
	oRun.Make_ThisElementCurrent(false);
	oRun.SetCursorPosition(oRun.GetElementPosition(this.SeparateChar) + 1);
	var oEndPos = oDocument.GetContentPosition(false);

	oDocument.SetSelectionByContentPositions(oStartPos, oEndPos);
	oDocument.Remove();
};
CComplexField.prototype.MoveCursorOutsideElement = function(isBefore)
{
	var oDocument = this.GetTopDocumentContent();
	if (!oDocument)
		return;

	oDocument.RemoveSelection();

	if (isBefore)
	{
		var oRun = this.BeginChar.GetRun();
		oRun.Make_ThisElementCurrent(false);
		oRun.SetCursorPosition(oRun.GetElementPosition(this.BeginChar));

		if (oRun.IsCursorAtBegin())
			oRun.MoveCursorOutsideElement(true);
	}
	else
	{
		var oRun = this.EndChar.GetRun();
		oRun.Make_ThisElementCurrent(false);
		oRun.SetCursorPosition(oRun.GetElementPosition(this.EndChar) + 1);

		if (oRun.IsCursorAtEnd())
			oRun.MoveCursorOutsideElement(false);
	}
};
CComplexField.prototype.RemoveField = function()
{
	if (!this.IsValid())
		return;

	var oDocument = this.GetTopDocumentContent();
	if (!oDocument)
		return;

	this.SelectField();
	oDocument.Remove();
};
/**
 * Выставляем свойства для данного поля
 * @param oPr (зависит от типа данного поля)
 */
CComplexField.prototype.SetPr = function(oPr)
{
	if (!this.IsValid())
		return;

	var oInstruction = this.GetInstruction();
	if (!oInstruction)
		return;

	var oDocument = this.GetTopDocumentContent();
	if (!oDocument)
		return;

	oInstruction.SetPr(oPr);
	var sNewInstruction = oInstruction.ToString();

	this.SelectFieldCode();
	oDocument.Remove();

	var oRun      = this.BeginChar.GetRun();
	var nInRunPos = oRun.GetElementPosition(this.BeginChar) + 1;
	oRun.AddInstrText(sNewInstruction, nInRunPos);
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CComplexField = CComplexField;



function TEST_ADDFIELD(sInstruction)
{
	var oLogicDocument = editor.WordControl.m_oLogicDocument;
	oLogicDocument.Create_NewHistoryPoint();
	oLogicDocument.AddFieldWithInstruction(sInstruction);
	oLogicDocument.Recalculate();
}
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var History = AscCommon.History;

/**
 *
 * @constructor
 * @extends {CParagraphContentWithParagraphLikeContent}
 */
function ParaHyperlink()
{
	CParagraphContentWithParagraphLikeContent.call(this);

    this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.Type    = para_Hyperlink;
    this.Value   = "";
    this.Visited = false;
    this.ToolTip = "";
    this.Anchor  = "";

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    AscCommon.g_oTableId.Add( this, this.Id );
}

ParaHyperlink.prototype = Object.create(CParagraphContentWithParagraphLikeContent.prototype);
ParaHyperlink.prototype.constructor = ParaHyperlink;

ParaHyperlink.prototype.Get_Id = function()
{
    return this.Id;
};


ParaHyperlink.prototype.Get_FirstTextPr2 = function()
{
    for(var i = 0; i < this.Content.length; ++i)
    {
        if(this.Content[i].Type === para_Run && !this.Content[i].Is_Empty())
        {
            return this.Content[i].Get_CompiledPr();
        }
    }
    return null;
};

ParaHyperlink.prototype.Copy = function(Selected, oPr)
{
    var NewHyperlink = CParagraphContentWithParagraphLikeContent.prototype.Copy.apply(this, arguments);
    NewHyperlink.SetValue(this.Value);
    NewHyperlink.SetToolTip(this.ToolTip);
    NewHyperlink.SetAnchor(this.Anchor);
    NewHyperlink.Visited = this.Visited;
    return NewHyperlink;
};

ParaHyperlink.prototype.GetSelectedElementsInfo = function(Info, ContentPos, Depth)
{
    Info.SetHyperlink(this);
    CParagraphContentWithParagraphLikeContent.prototype.GetSelectedElementsInfo.apply(this, arguments);
};

ParaHyperlink.prototype.Add_ToContent = function(Pos, Item, UpdatePosition)
{
    if (para_Hyperlink === Item.Type)
    {
        // При добавлении гиперссылки в гиперссылку мы добавляем контент гиперссылки, а не ее целиком
        for (var ItemPos = 0, Count = Item.Content.length; ItemPos < Count; ItemPos++)
        {
            this.Add_ToContent(Pos + ItemPos, Item.Content[ItemPos], UpdatePosition);
        }

        return;
    }

	History.Add(new CChangesHyperlinkAddItem(this, Pos, [Item]));

    CParagraphContentWithParagraphLikeContent.prototype.Add_ToContent.apply(this, arguments);
};

ParaHyperlink.prototype.Remove_FromContent = function(Pos, Count, UpdatePosition)
{
    // Получим массив удаляемых элементов
    var DeletedItems = this.Content.slice( Pos, Pos + Count );
    History.Add(new CChangesHyperlinkRemoveItem(this, Pos, DeletedItems));

    CParagraphContentWithParagraphLikeContent.prototype.Remove_FromContent.apply(this, arguments);
};

ParaHyperlink.prototype.Add = function(Item)
{
	if (para_Hyperlink === Item.Type)
	{
		// Вместо добавления самого элемента добавляем его содержимое
		var Count = Item.Content.length;

		if (Count > 0)
		{
			var CurPos  = this.State.ContentPos;
			var CurItem = this.Content[CurPos];

			var CurContentPos = new CParagraphContentPos();
			CurItem.Get_ParaContentPos(false, false, CurContentPos);

			var NewItem = CurItem.Split(CurContentPos, 0);
			for (var Index = 0; Index < Count; Index++)
			{
				this.Add_ToContent(CurPos + Index + 1, Item.Content[Index], false);
			}
			this.Add_ToContent(CurPos + Count + 1, NewItem, false);
			this.State.ContentPos = CurPos + Count;
			this.Content[this.State.ContentPos].MoveCursorToEndPos();
		}
	}
	else
	{
		CParagraphContentWithParagraphLikeContent.prototype.Add.apply(this, arguments);
	}
};

ParaHyperlink.prototype.Clear_TextPr = function()
{
    var HyperlinkStyle = null;
    if ( undefined !== this.Paragraph && null !== this.Paragraph )
    {
        var Styles = this.Paragraph.Parent.Get_Styles();
        HyperlinkStyle = Styles.GetDefaultHyperlink();
    }

    var Count = this.Content.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        var Item = this.Content[Index];
        Item.Clear_TextPr();

        if ( para_Run === Item.Type && null !== HyperlinkStyle )
            Item.Set_RStyle( HyperlinkStyle );
    }
};

ParaHyperlink.prototype.Clear_TextFormatting = function( DefHyper )
{
    var Count = this.Content.length;

    for (var Pos = 0; Pos < Count; Pos++)
    {
        var Item = this.Content[Pos];
        Item.Clear_TextFormatting(DefHyper);

        if (para_Run === Item.Type && null !== DefHyper && undefined !== DefHyper)
            Item.Set_RStyle(DefHyper);
    }
};

ParaHyperlink.prototype.Split = function (ContentPos, Depth)
{
    var NewHyperlink = CParagraphContentWithParagraphLikeContent.prototype.Split.apply(this, arguments);
    NewHyperlink.SetValue(this.Value);
    NewHyperlink.SetToolTip(this.ToolTip);
    return NewHyperlink;
};

ParaHyperlink.prototype.CopyContent = function(Selected)
{
    var Content = CParagraphContentWithParagraphLikeContent.prototype.CopyContent.apply(this, arguments);

    for (var CurPos = 0, Count = Content.length; CurPos < Count; CurPos++)
    {
        var Item = Content[CurPos];
        Item.Clear_TextFormatting();
    }

    return Content;
};

//-----------------------------------------------------------------------------------
// Функции отрисовки
//-----------------------------------------------------------------------------------
ParaHyperlink.prototype.Draw_Elements = function(PDSE)
{
    PDSE.VisitedHyperlink = this.Visited;
    PDSE.Hyperlink = true;
    CParagraphContentWithParagraphLikeContent.prototype.Draw_Elements.apply(this, arguments);
    PDSE.VisitedHyperlink = false;
    PDSE.Hyperlink = false;
};

ParaHyperlink.prototype.Draw_Lines = function(PDSL)
{
    PDSL.VisitedHyperlink = this.Visited;
    PDSL.Hyperlink = true;
    CParagraphContentWithParagraphLikeContent.prototype.Draw_Lines.apply(this, arguments);
    PDSL.VisitedHyperlink = false;
    PDSL.Hyperlink = false;
};
//-----------------------------------------------------------------------------------
// Работаем со значениями
//-----------------------------------------------------------------------------------
ParaHyperlink.prototype.GetVisited = function()
{
    return this.Visited;
};
ParaHyperlink.prototype.SetVisited = function(isVisited)
{
	this.Visited = isVisited;
};
ParaHyperlink.prototype.SetToolTip = function(ToolTip)
{
    History.Add(new CChangesHyperlinkToolTip(this, this.ToolTip, ToolTip));
    this.ToolTip = ToolTip;
};
ParaHyperlink.prototype.GetToolTip = function()
{
	if (this.Anchor)
		return AscCommon.translateManager.getValue("Current Document");

	if ( null === this.ToolTip )
	{
		if ( "string" === typeof(this.Value) )
			return this.Value;
		else
			return "";
	}
	else
		return this.ToolTip;
};
ParaHyperlink.prototype.Set_Value = function(Value)
{
    History.Add(new CChangesHyperlinkValue(this, this.Value, Value));
    this.Value = Value;
};
ParaHyperlink.prototype.GetAnchor = function()
{
	return this.Anchor;
};
ParaHyperlink.prototype.SetAnchor = function(sBookmarkName)
{
	History.Add(new CChangesHyperlinkAnchor(this, this.Anchor, sBookmarkName));
	this.Anchor = sBookmarkName;
};
ParaHyperlink.prototype.GetValue = function()
{
	return this.Value;
};
ParaHyperlink.prototype.SetValue = function(sValue)
{
	this.Set_Value(sValue);
};
/**
 * Проверяем является ли данная ссылка внутренней
 * @returns {boolean}
 */
ParaHyperlink.prototype.IsAnchor = function()
{
	return !!(this.Anchor);
};
/**
 * Проверяем является ли данная ссылка ссылкой в начало документа
 * @returns {boolean}
 */
ParaHyperlink.prototype.IsTopOfDocument = function()
{
	return (this.Anchor === "_top");
};
//----------------------------------------------------------------------------------------------------------------------
// Функции совместного редактирования
//----------------------------------------------------------------------------------------------------------------------
ParaHyperlink.prototype.Write_ToBinary2 = function(Writer)
{
    Writer.WriteLong( AscDFH.historyitem_type_Hyperlink );

    // String : Id
    // String : Value
    // String : ToolTip
    // Long   : Количество элементов
    // Array of Strings : массив с Id элементов
	// String : Anchor

    Writer.WriteString2( this.Id );
    if(!(editor && editor.isDocumentEditor))
    {
        this.Write_ToBinary2SpreadSheets(Writer);
        return;
    }

    Writer.WriteString2( this.Value );
    Writer.WriteString2( this.ToolTip );

    var Count = this.Content.length;
    Writer.WriteLong( Count );

    for ( var Index = 0; Index < Count; Index++ )
    {
        Writer.WriteString2( this.Content[Index].Get_Id() );
    }

	Writer.WriteString2(this.Anchor);
};

ParaHyperlink.prototype.Read_FromBinary2 = function(Reader)
{
    // String : Id
    // String : Value
    // String : ToolTip
    // Long   : Количество элементов
    // Array of Strings : массив с Id элементов
	// String : Anchor

    this.Id      = Reader.GetString2();
    this.Value   = Reader.GetString2();
    this.ToolTip = Reader.GetString2();

    var Count = Reader.GetLong();
    this.Content = [];

    for ( var Index = 0; Index < Count; Index++ )
    {
        var Element = AscCommon.g_oTableId.Get_ById( Reader.GetString2() );
        if ( null !== Element )
            this.Content.push( Element );
    }

    this.Anchor = Reader.GetString2();
};

ParaHyperlink.prototype.Write_ToBinary2SpreadSheets = function(Writer)
{
    Writer.WriteString2("");
    Writer.WriteString2("");
    Writer.WriteLong(0);
};

ParaHyperlink.prototype.Document_UpdateInterfaceState = function()
{
	var oHyperText = new CParagraphGetText();
	this.Get_Text(oHyperText);

	var oHyperProps = new Asc.CHyperlinkProperty(this);
	oHyperProps.put_Text(oHyperText.Text);
	oHyperProps.put_InternalHyperlink(this);

	var sAnchor = oHyperProps.get_Bookmark();

	var oLogicDocument = this.Paragraph ? this.Paragraph.LogicDocument : null;
	if (oLogicDocument && sAnchor)
	{
		var oBookmarksManager = oLogicDocument.GetBookmarksManager();
		var oBookmark         = oBookmarksManager.GetBookmarkByName(sAnchor);
		if (oBookmarksManager.IsHiddenBookmark(sAnchor) && oBookmark)
		{
			var oPara = oBookmark[0].GetParagraph();
			if (oBookmarksManager.GetNameForHeadingBookmark(oPara) === sAnchor)
			{
				oHyperProps.put_Heading(oPara);
			}
			else
			{
				oHyperProps.put_Bookmark(null);
			}
		}
	}

	editor.sync_HyperlinkPropCallback(oHyperProps);
	CParagraphContentWithParagraphLikeContent.prototype.Document_UpdateInterfaceState.apply(this, arguments);
};

function CParaHyperLinkStartState(HyperLink)
{
    this.Value = HyperLink.Value;
    this.ToolTip = HyperLink.ToolTip;
    this.Content = [];
    for(var i = 0; i < HyperLink.Content.length; ++i)
    {
        this.Content.push(HyperLink.Content);
    }
}

/**
 * Класс описывающий типы привязок для гиперссылки
 * @param {c_oAscHyperlinkAnchor} nType
 * @param vParam
 * @constructor
 */
function CHyperlinkAnchor(nType, vParam)
{
	this.Type = nType;

	this.Bookmark  = null;
	this.Paragraph = null;
	this.Lvl       = null;

	if (c_oAscHyperlinkAnchor.Bookmark === this.Type)
	{
		this.Bookmark = vParam;
	}
	else if (c_oAscHyperlinkAnchor.Heading === this.Type)
	{
		this.Paragraph = vParam.Paragraph;
		this.Lvl       = vParam.Lvl;
	}
}
CHyperlinkAnchor.prototype.GetType = function()
{
	return this.Type;
};
CHyperlinkAnchor.prototype.GetBookmarkName = function()
{
	if (c_oAscHyperlinkAnchor.Bookmark === this.Type)
		return this.Bookmark;

	return "";
};
CHyperlinkAnchor.prototype.GetHeadingText = function()
{
	if (c_oAscHyperlinkAnchor.Heading === this.Type && this.Paragraph instanceof Paragraph)
		return this.Paragraph.GetText();

	return "";
};
CHyperlinkAnchor.prototype.GetHeadingLevel = function()
{
	if (c_oAscHyperlinkAnchor.Heading === this.Type)
		return this.Lvl;

	return -1;
};
CHyperlinkAnchor.prototype.GetHeadingParagraph = function()
{
	if (c_oAscHyperlinkAnchor.Heading === this.Type && this.Paragraph instanceof Paragraph)
		return this.Paragraph;

	return "";
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].ParaHyperlink = ParaHyperlink;

CHyperlinkAnchor.prototype['asc_GetType']             = CHyperlinkAnchor.prototype.GetType;
CHyperlinkAnchor.prototype['asc_GetBookmarkName']     = CHyperlinkAnchor.prototype.GetBookmarkName;
CHyperlinkAnchor.prototype['asc_GetHeadingText']      = CHyperlinkAnchor.prototype.GetHeadingText;
CHyperlinkAnchor.prototype['asc_GetHeadingLevel']     = CHyperlinkAnchor.prototype.GetHeadingLevel;
CHyperlinkAnchor.prototype['asc_GetHeadingParagraph'] = CHyperlinkAnchor.prototype.GetHeadingParagraph;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 08.11.2016
 * Time: 18:59
 */

AscDFH.changesFactory[AscDFH.historyitem_Hyperlink_Value]      = CChangesHyperlinkValue;
AscDFH.changesFactory[AscDFH.historyitem_Hyperlink_ToolTip]    = CChangesHyperlinkToolTip;
AscDFH.changesFactory[AscDFH.historyitem_Hyperlink_AddItem]    = CChangesHyperlinkAddItem;
AscDFH.changesFactory[AscDFH.historyitem_Hyperlink_RemoveItem] = CChangesHyperlinkRemoveItem;
AscDFH.changesFactory[AscDFH.historyitem_Hyperlink_Anchor]     = CChangesHyperlinkAnchor;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_Hyperlink_Value]      = [AscDFH.historyitem_Hyperlink_Value];
AscDFH.changesRelationMap[AscDFH.historyitem_Hyperlink_ToolTip]    = [AscDFH.historyitem_Hyperlink_ToolTip];
AscDFH.changesRelationMap[AscDFH.historyitem_Hyperlink_AddItem]    = [
	AscDFH.historyitem_Hyperlink_AddItem,
	AscDFH.historyitem_Hyperlink_RemoveItem
];
AscDFH.changesRelationMap[AscDFH.historyitem_Hyperlink_RemoveItem] = [
	AscDFH.historyitem_Hyperlink_AddItem,
	AscDFH.historyitem_Hyperlink_RemoveItem
];
AscDFH.changesRelationMap[AscDFH.historyitem_Hyperlink_Anchor]     = [AscDFH.historyitem_Hyperlink_Anchor];
//----------------------------------------------------------------------------------------------------------------------

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseStringValue}
 */
function CChangesHyperlinkValue(Class, Old, New, Color)
{
	AscDFH.CChangesBaseStringValue.call(this, Class, Old, New, Color);
}
CChangesHyperlinkValue.prototype = Object.create(AscDFH.CChangesBaseStringValue.prototype);
CChangesHyperlinkValue.prototype.constructor = CChangesHyperlinkValue;
CChangesHyperlinkValue.prototype.Type = AscDFH.historyitem_Hyperlink_Value;
CChangesHyperlinkValue.prototype.private_SetValue = function(Value)
{
	this.Class.Value = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseStringValue}
 */
function CChangesHyperlinkToolTip(Class, Old, New, Color)
{
	AscDFH.CChangesBaseStringValue.call(this, Class, Old, New, Color);
}
CChangesHyperlinkToolTip.prototype = Object.create(AscDFH.CChangesBaseStringValue.prototype);
CChangesHyperlinkToolTip.prototype.constructor = CChangesHyperlinkToolTip;
CChangesHyperlinkToolTip.prototype.Type = AscDFH.historyitem_Hyperlink_ToolTip;
CChangesHyperlinkToolTip.prototype.private_SetValue = function(Value)
{
	this.Class.ToolTip = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesHyperlinkAddItem(Class, Pos, Items)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, true);
}
CChangesHyperlinkAddItem.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesHyperlinkAddItem.prototype.constructor = CChangesHyperlinkAddItem;
CChangesHyperlinkAddItem.prototype.Type = AscDFH.historyitem_Hyperlink_AddItem;
CChangesHyperlinkAddItem.prototype.Undo = function()
{
	var oHyperlink = this.Class;
	oHyperlink.Content.splice(this.Pos, this.Items.length);
	oHyperlink.private_UpdateTrackRevisions();
	oHyperlink.private_CheckUpdateBookmarks(this.Items);
	oHyperlink.private_UpdateSpellChecking();
};
CChangesHyperlinkAddItem.prototype.Redo = function()
{
	var oHyperlink = this.Class;
	var Array_start = oHyperlink.Content.slice(0, this.Pos);
	var Array_end   = oHyperlink.Content.slice(this.Pos);

	oHyperlink.Content = Array_start.concat(this.Items, Array_end);
	oHyperlink.private_UpdateTrackRevisions();
	oHyperlink.private_CheckUpdateBookmarks(this.Items);
	oHyperlink.private_UpdateSpellChecking();
};
CChangesHyperlinkAddItem.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesHyperlinkAddItem.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesHyperlinkAddItem.prototype.Load = function(Color)
{
	var oHyperlink = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var Pos     = oHyperlink.m_oContentChanges.Check(AscCommon.contentchanges_Add, this.PosArray[nIndex]);
		var Element = this.Items[nIndex];

		if (null != Element)
		{
			oHyperlink.Content.splice(Pos, 0, Element);
			AscCommon.CollaborativeEditing.Update_DocumentPositionsOnAdd(oHyperlink, Pos);
		}
	}

	oHyperlink.private_UpdateTrackRevisions();
	oHyperlink.private_UpdateSpellChecking();
};
CChangesHyperlinkAddItem.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_Hyperlink_AddItem === oChanges.Type || AscDFH.historyitem_Hyperlink_RemoveItem === oChanges.Type))
		return true;

	return false;
};
CChangesHyperlinkAddItem.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesHyperlinkRemoveItem);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesHyperlinkRemoveItem(Class, Pos, Items)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, false);
}
CChangesHyperlinkRemoveItem.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesHyperlinkRemoveItem.prototype.constructor = CChangesHyperlinkRemoveItem;
CChangesHyperlinkRemoveItem.prototype.Type = AscDFH.historyitem_Hyperlink_RemoveItem;
CChangesHyperlinkRemoveItem.prototype.Undo = function()
{
	var oHyperlink  = this.Class;
	var Array_start = oHyperlink.Content.slice(0, this.Pos);
	var Array_end   = oHyperlink.Content.slice(this.Pos);

	oHyperlink.Content = Array_start.concat(this.Items, Array_end);
	oHyperlink.private_UpdateTrackRevisions();
	oHyperlink.private_CheckUpdateBookmarks(this.Items);
	oHyperlink.private_UpdateSpellChecking();
};
CChangesHyperlinkRemoveItem.prototype.Redo = function()
{
	var oHyperlink  = this.Class;
	oHyperlink.Content.splice(this.Pos, this.Items.length);
	oHyperlink.private_UpdateTrackRevisions();
	oHyperlink.private_CheckUpdateBookmarks(this.Items);
	oHyperlink.private_UpdateSpellChecking();
};
CChangesHyperlinkRemoveItem.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesHyperlinkRemoveItem.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesHyperlinkRemoveItem.prototype.Load = function(Color)
{
	var oHyperlink = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var ChangesPos = oHyperlink.m_oContentChanges.Check(AscCommon.contentchanges_Remove, this.PosArray[nIndex]);

		if (false === ChangesPos)
			continue;

		oHyperlink.Content.splice(ChangesPos, 1);
		AscCommon.CollaborativeEditing.Update_DocumentPositionsOnRemove(oHyperlink, ChangesPos, 1);
	}
	oHyperlink.private_UpdateTrackRevisions();
	oHyperlink.private_UpdateSpellChecking();
};
CChangesHyperlinkRemoveItem.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_Hyperlink_AddItem === oChanges.Type || AscDFH.historyitem_Hyperlink_RemoveItem === oChanges.Type))
		return true;

	return false;
};
CChangesHyperlinkRemoveItem.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesHyperlinkAddItem);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseStringValue}
 */
function CChangesHyperlinkAnchor(Class, Old, New, Color)
{
	AscDFH.CChangesBaseStringValue.call(this, Class, Old, New, Color);
}
CChangesHyperlinkAnchor.prototype = Object.create(AscDFH.CChangesBaseStringValue.prototype);
CChangesHyperlinkAnchor.prototype.constructor = CChangesHyperlinkAnchor;
CChangesHyperlinkAnchor.prototype.Type = AscDFH.historyitem_Hyperlink_Anchor;
CChangesHyperlinkAnchor.prototype.private_SetValue = function(Value)
{
	this.Class.Anchor = Value;
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var History = AscCommon.History;

/**
 *
 * @param FieldType
 * @param Arguments
 * @param Switches
 * @constructor
 * @extends {CParagraphContentWithParagraphLikeContent}
 */
function ParaField(FieldType, Arguments, Switches)
{
	CParagraphContentWithParagraphLikeContent.call(this);

    this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.Type    = para_Field;

    this.FieldType = (undefined === FieldType ? fieldtype_UNKNOWN : FieldType);
    this.Arguments = (undefined === Arguments ? []                : Arguments);
    this.Switches  = (undefined === Switches  ? []                : Switches);

    this.TemplateContent = this.Content;

    this.Bounds = {};

	this.FormFieldName        = "";
	this.FormFieldDefaultText = "";

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    AscCommon.g_oTableId.Add( this, this.Id );
}

ParaField.prototype = Object.create(CParagraphContentWithParagraphLikeContent.prototype);
ParaField.prototype.constructor = ParaField;

ParaField.prototype.Get_Id = function()
{
    return this.Id;
};
ParaField.prototype.Copy = function(Selected, oPr)
{
    var NewField = CParagraphContentWithParagraphLikeContent.prototype.Copy.apply(this, arguments);

    // TODO: Сделать функциями с иторией
    NewField.FieldType = this.FieldType;
    NewField.Arguments = this.Arguments;
    NewField.Switches  = this.Switches;

    if (editor)
        editor.WordControl.m_oLogicDocument.Register_Field(NewField);

    return NewField;
};
ParaField.prototype.GetSelectedElementsInfo = function(Info, ContentPos, Depth)
{
	Info.Set_Field(this);
	CParagraphContentWithParagraphLikeContent.prototype.GetSelectedElementsInfo.apply(this, arguments);
};
ParaField.prototype.Get_Bounds = function()
{
    var aBounds = [];
    for (var Place in this.Bounds)
    {
        aBounds.push(this.Bounds[Place]);
    }

    return aBounds;
};
ParaField.prototype.Add_ToContent = function(Pos, Item, UpdatePosition)
{
	History.Add(new CChangesParaFieldAddItem(this, Pos, [Item]));
	CParagraphContentWithParagraphLikeContent.prototype.Add_ToContent.apply(this, arguments);
};
ParaField.prototype.Remove_FromContent = function(Pos, Count, UpdatePosition)
{
	// Получим массив удаляемых элементов
	var DeletedItems = this.Content.slice(Pos, Pos + Count);
	History.Add(new CChangesParaFieldRemoveItem(this, Pos, DeletedItems));

	CParagraphContentWithParagraphLikeContent.prototype.Remove_FromContent.apply(this, arguments);
};
ParaField.prototype.Add = function(Item)
{
	if (para_Field === Item.Type)
	{
		// Вместо добавления самого элемента добавляем его содержимое
		var Count = Item.Content.length;

		if (Count > 0)
		{
			var CurPos  = this.State.ContentPos;
			var CurItem = this.Content[CurPos];

			var CurContentPos = new CParagraphContentPos();
			CurItem.Get_ParaContentPos(false, false, CurContentPos);

			var NewItem = CurItem.Split(CurContentPos, 0);
			for (var Index = 0; Index < Count; Index++)
			{
				this.Add_ToContent(CurPos + Index + 1, Item.Content[Index], false);
			}
			this.Add_ToContent(CurPos + Count + 1, NewItem, false);
			this.State.ContentPos = CurPos + Count;
			this.Content[this.State.ContentPos].MoveCursorToEndPos();
		}
	}
	else
	{
		CParagraphContentWithParagraphLikeContent.prototype.Add.apply(this, arguments);
	}
};
ParaField.prototype.Split = function (ContentPos, Depth)
{
    // Не даем разделять поле
    return null;
};
ParaField.prototype.CanSplit = function()
{
	return false;
};
ParaField.prototype.Recalculate_Range_Spaces = function(PRSA, _CurLine, _CurRange, _CurPage)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = (0 === _CurLine ? _CurRange - this.StartRange : _CurRange);

    if (0 === CurLine && 0 === CurRange && true !== PRSA.RecalcFast)
        this.Bounds = {};

    var X0 = PRSA.X;
    var Y0 = PRSA.Y0;
    var Y1 = PRSA.Y1;

    CParagraphContentWithParagraphLikeContent.prototype.Recalculate_Range_Spaces.apply(this, arguments);

	var X1 = PRSA.X;

	this.Bounds[((CurLine << 16) & 0xFFFF0000) | (CurRange & 0x0000FFFF)] = {
		X0        : X0,
		X1        : X1,
		Y0        : Y0,
		Y1        : Y1,
		PageIndex : PRSA.Paragraph.Get_AbsolutePage(_CurPage)
	};
};
ParaField.prototype.Draw_HighLights = function(PDSH)
{
    var X0 = PDSH.X;
    var Y0 = PDSH.Y0;
    var Y1 = PDSH.Y1;

    CParagraphContentWithParagraphLikeContent.prototype.Draw_HighLights.apply(this, arguments);

    var X1 = PDSH.X;

    if (Math.abs(X0 - X1) > 0.001 && (true === PDSH.DrawMMFields || fieldtype_FORMTEXT === this.Get_FieldType()))
    {
        PDSH.MMFields.Add(Y0, Y1, X0, X1, 0, 0, 0, 0  );
    }
};
ParaField.prototype.Is_UseInDocument = function()
{
	return (this.Paragraph && true === this.Paragraph.Is_UseInDocument() && true === this.Is_UseInParagraph() ? true : false);
};
ParaField.prototype.Is_UseInParagraph = function()
{
	if (!this.Paragraph)
		return false;

	var ContentPos = this.Paragraph.Get_PosByElement(this);
	if (!ContentPos)
		return false;

	return true;
};
ParaField.prototype.Get_LeftPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
	if (false === UseContentPos && this.Content.length > 0)
	{
		// При переходе в новый контент встаем в его конец
		var CurPos = this.Content.length - 1;
		this.Content[CurPos].Get_EndPos(false, SearchPos.Pos, Depth + 1);
		SearchPos.Pos.Update(CurPos, Depth);
		SearchPos.Found = true;
		return true;
	}

	CParagraphContentWithParagraphLikeContent.prototype.Get_LeftPos.call(this, SearchPos, ContentPos, Depth, UseContentPos);
};
ParaField.prototype.Get_RightPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
	if (false === UseContentPos && this.Content.length > 0)
	{
		// При переходе в новый контент встаем в его начало
		this.Content[0].Get_StartPos(SearchPos.Pos, Depth + 1);
		SearchPos.Pos.Update(0, Depth);
		SearchPos.Found = true;
		return true;
	}

	CParagraphContentWithParagraphLikeContent.prototype.Get_RightPos.call(this, SearchPos, ContentPos, Depth, UseContentPos, StepEnd);
};
ParaField.prototype.Remove = function(nDirection, bOnAddText)
{
	CParagraphContentWithParagraphLikeContent.prototype.Remove.call(this, nDirection, bOnAddText);

	if (this.Is_Empty() && !bOnAddText && fieldtype_FORMTEXT === this.Get_FieldType() && this.Paragraph && this.Paragraph.LogicDocument && true === this.Paragraph.LogicDocument.IsFillingFormMode())
	{
		var sDefaultText = this.FormFieldDefaultText == "" ? "     " : this.FormFieldDefaultText;
		this.SetValue(sDefaultText);
	}
};
ParaField.prototype.Shift_Range = function(Dx, Dy, _CurLine, _CurRange)
{
	CParagraphContentWithParagraphLikeContent.prototype.Shift_Range.call(this, Dx, Dy, _CurLine, _CurRange);

	var CurLine = _CurLine - this.StartLine;
	var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

	var oRangeBounds = this.Bounds[((CurLine << 16) & 0xFFFF0000) | (CurRange & 0x0000FFFF)];
	if (oRangeBounds)
	{
		oRangeBounds.X0 += Dx;
		oRangeBounds.X1 += Dx;
		oRangeBounds.Y0 += Dy;
		oRangeBounds.Y1 += Dy;
	}
};
ParaField.prototype.Get_LeftPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
	var bResult = CParagraphContentWithParagraphLikeContent.prototype.Get_LeftPos.call(this, SearchPos, ContentPos, Depth, UseContentPos);

	if (true !== bResult && this.Paragraph && this.Paragraph.LogicDocument && true === this.Paragraph.LogicDocument.IsFillingFormMode())
	{
		this.Get_StartPos(SearchPos.Pos, Depth);
		SearchPos.Found = true;
		return true;
	}

	return bResult;
};
ParaField.prototype.Get_RightPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
	var bResult = CParagraphContentWithParagraphLikeContent.prototype.Get_RightPos.call(this, SearchPos, ContentPos, Depth, UseContentPos, StepEnd);

	if (true !== bResult && this.Paragraph && this.Paragraph.LogicDocument && true === this.Paragraph.LogicDocument.IsFillingFormMode())
	{
		this.Get_EndPos(false, SearchPos.Pos, Depth);
		SearchPos.Found = true;
		return true;
	}

	return bResult;
};
ParaField.prototype.Get_WordStartPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
	CParagraphContentWithParagraphLikeContent.prototype.Get_WordStartPos.call(this, SearchPos, ContentPos, Depth, UseContentPos);

	if (true !== SearchPos.Found && this.Paragraph && this.Paragraph.LogicDocument && true === this.Paragraph.LogicDocument.IsFillingFormMode())
	{
		this.Get_StartPos(SearchPos.Pos, Depth);
		SearchPos.UpdatePos = true;
		SearchPos.Found     = true;
	}
};
ParaField.prototype.Get_WordEndPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
	CParagraphContentWithParagraphLikeContent.prototype.Get_WordEndPos.call(this, SearchPos, ContentPos, Depth, UseContentPos, StepEnd);

	if (true !== SearchPos.Found && this.Paragraph && this.Paragraph.LogicDocument && true === this.Paragraph.LogicDocument.IsFillingFormMode())
	{
		this.Get_EndPos(false, SearchPos.Pos, Depth);
		SearchPos.UpdatePos = true;
		SearchPos.Found     = true;
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Работа с данными поля
//----------------------------------------------------------------------------------------------------------------------
ParaField.prototype.Get_Argument = function(Index)
{
    return this.Arguments[Index];
};
ParaField.prototype.Get_FieldType = function()
{
    return this.FieldType;
};
ParaField.prototype.Map_MailMerge = function(_Value)
{
    // Пока у нас в Value может быть только текст, в будущем планируется, чтобы могли быть картинки.
    var Value = _Value;
    if (undefined === Value || null === Value)
        Value = "";

    History.TurnOff();

    var oRun = this.private_GetMappedRun(Value);

    // Подменяем содержимое поля
    this.Content = [];
    this.Content[0] = oRun;

    this.MoveCursorToStartPos();

    History.TurnOn();
};
ParaField.prototype.Restore_StandardTemplate = function()
{
    // В любом случае сначала восстанавливаем исходное содержимое.
    this.Restore_Template();

    if (fieldtype_MERGEFIELD === this.FieldType && true === AscCommon.CollaborativeEditing.Is_SingleUser() && 1 === this.Arguments.length)
    {
        var oRun = this.private_GetMappedRun("«" + this.Arguments[0] + "»");
        this.Remove_FromContent(0, this.Content.length);
        this.Add_ToContent(0, oRun);
        this.MoveCursorToStartPos();

        this.TemplateContent = this.Content;
    }
};
ParaField.prototype.Restore_Template = function()
{
    // Восстанавливаем содержимое поля.
    this.Content = this.TemplateContent;
    this.MoveCursorToStartPos();
};
ParaField.prototype.Is_NeedRestoreTemplate = function()
{
    if (1 !== this.TemplateContent.length)
        return true;

    var oRun = this.TemplateContent[0];
    if (fieldtype_MERGEFIELD === this.FieldType)
    {
        var sStandardText = "«" + this.Arguments[0] + "»";

        var oRunText = new CParagraphGetText();
        oRun.Get_Text(oRunText);

        if (sStandardText === oRunText.Text)
            return false;

        return true;
    }

    return false;
};
ParaField.prototype.Replace_MailMerge = function(_Value)
{
    // Пока у нас в Value может быть только текст, в будущем планируется, чтобы могли быть картинки.
    var Value = _Value;
    if (undefined === Value || null === Value)
        Value = "";

    var Paragraph = this.Paragraph;

    if (!Paragraph)
        return false;

    // Получим ран, на который мы подменяем поле
    var oRun = this.private_GetMappedRun(Value);

    // Ищем расположение данного поля в параграфе
    var ParaContentPos = Paragraph.Get_PosByElement(this);

    if (null === ParaContentPos)
        return false;

    var Depth    = ParaContentPos.Get_Depth();
    var FieldPos = ParaContentPos.Get(Depth);

    if (Depth < 0)
        return false;

    ParaContentPos.Decrease_Depth(1);
    var FieldContainer = Paragraph.Get_ElementByPos(ParaContentPos);
    if (!FieldContainer || !FieldContainer.Content || FieldContainer.Content[FieldPos] !== this)
        return false;

    FieldContainer.Remove_FromContent(FieldPos, 1);
    FieldContainer.Add_ToContent(FieldPos, oRun);

    return true;
};
ParaField.prototype.private_GetMappedRun = function(sValue)
{
	return this.CreateRunWithText(sValue);
};
ParaField.prototype.SetFormFieldName = function(sName)
{
	History.Add(new CChangesParaFieldFormFieldName(this, this.FormFieldName, sName));
	this.FormFieldName = sName;
};
ParaField.prototype.GetFormFieldName = function()
{
	return this.FormFieldName;
};
ParaField.prototype.SetFormFieldDefaultText = function(sText)
{
	History.Add(new CChangesParaFieldFormFieldDefaultText(this, this.FormFieldDefaultText, sText));
	this.FormFieldDefaultText = sText;
};
ParaField.prototype.GetValue = function()
{
	var oText = new CParagraphGetText();
	oText.SetBreakOnNonText(false);
	oText.SetParaEndToSpace(true);

	this.Get_Text(oText);

	return oText.Text;
};
ParaField.prototype.SetValue = function(sValue)
{
	this.ReplaceAllWithText(sValue);
};
ParaField.prototype.IsFillingForm = function()
{
	if (fieldtype_FORMTEXT === this.Get_FieldType())
		return true;

	return false;
};
ParaField.prototype.FindNextFillingForm = function(isNext, isCurrent, isStart)
{
	if (!this.IsFillingForm())
		return CParagraphContentWithParagraphLikeContent.prototype.FindNextFillingForm.apply(this, arguments);

	if (isCurrent && true === this.IsSelectedAll())
	{
		if (isNext)
			return CParagraphContentWithParagraphLikeContent.prototype.FindNextFillingForm.apply(this, arguments);

		return null;
	}

	if (!isCurrent && isNext)
		return this;

	var oRes = CParagraphContentWithParagraphLikeContent.prototype.FindNextFillingForm.apply(this, arguments);
	if (!oRes && !isNext)
		return this;

	return null;
};
//----------------------------------------------------------------------------------------------------------------------
// Функции совместного редактирования
//----------------------------------------------------------------------------------------------------------------------
ParaField.prototype.Write_ToBinary2 = function(Writer)
{
    Writer.WriteLong(AscDFH.historyitem_type_Field);

    // String : Id
    // Long   : FieldType
    // Long   : Количество аргументов
    // Array of Strings : массив аргументов
    // Long   : Количество переключателей
    // Array of Strings : массив переключателей
    // Long   : Количество элементов
    // Array of Strings : массив с Id элементов

    Writer.WriteString2(this.Id);
    Writer.WriteLong(this.FieldType);

    var ArgsCount = this.Arguments.length;
    Writer.WriteLong(ArgsCount);
    for (var Index = 0; Index < ArgsCount; Index++)
        Writer.WriteString2(this.Arguments[Index]);

    var SwitchesCount = this.Switches.length;
    Writer.WriteLong(SwitchesCount);
    for (var Index = 0; Index < SwitchesCount; Index++)
        Writer.WriteString2(this.Switches[Index]);

    var Count = this.Content.length;
    Writer.WriteLong(Count);
    for (var Index = 0; Index < Count; Index++)
        Writer.WriteString2(this.Content[Index].Get_Id());
};
ParaField.prototype.Read_FromBinary2 = function(Reader)
{
    // String : Id
    // Long   : FieldType
    // Long   : Количество аргументов
    // Array of Strings : массив аргументов
    // Long   : Количество переключателей
    // Array of Strings : массив переключателей
    // Long   : Количество элементов
    // Array of Strings : массив с Id элементов

    this.Id = Reader.GetString2();
    this.FieldType = Reader.GetLong();

    var Count = Reader.GetLong();
    this.Arguments = [];
    for (var Index = 0; Index < Count; Index++)
        this.Arguments.push(Reader.GetString2());

    Count = Reader.GetLong();
    this.Switches = [];
    for (var Index = 0; Index < Count; Index++)
        this.Switches.push(Reader.GetString2());

    Count = Reader.GetLong();
    this.Content = [];
    for (var Index = 0; Index < Count; Index++)
    {
        var Element = AscCommon.g_oTableId.Get_ById(Reader.GetString2());
        if (null !== Element)
            this.Content.push(Element);
    }

    this.TemplateContent = this.Content;

    if (editor)
        editor.WordControl.m_oLogicDocument.Register_Field(this);
};
//----------------------------------------------------------------------------------------------------------------------
ParaField.prototype.IsStopCursorOnEntryExit = function()
{
	return true;
};
//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].ParaField = ParaField;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 10.11.2016
 * Time: 18:59
 */

AscDFH.changesFactory[AscDFH.historyitem_Field_AddItem]              = CChangesParaFieldAddItem;
AscDFH.changesFactory[AscDFH.historyitem_Field_RemoveItem]           = CChangesParaFieldRemoveItem;
AscDFH.changesFactory[AscDFH.historyitem_Field_FormFieldName]        = CChangesParaFieldFormFieldName;
AscDFH.changesFactory[AscDFH.historyitem_Field_FormFieldDefaultText] = CChangesParaFieldFormFieldDefaultText;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_Field_AddItem]              = [AscDFH.historyitem_Field_AddItem, AscDFH.historyitem_Field_RemoveItem];
AscDFH.changesRelationMap[AscDFH.historyitem_Field_RemoveItem]           = [AscDFH.historyitem_Field_AddItem, AscDFH.historyitem_Field_RemoveItem];
AscDFH.changesRelationMap[AscDFH.historyitem_Field_FormFieldName]        = [AscDFH.historyitem_Field_FormFieldName];
AscDFH.changesRelationMap[AscDFH.historyitem_Field_FormFieldDefaultText] = [AscDFH.historyitem_Field_FormFieldDefaultText];
//----------------------------------------------------------------------------------------------------------------------

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesParaFieldAddItem(Class, Pos, Items)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, true);
}
CChangesParaFieldAddItem.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesParaFieldAddItem.prototype.constructor = CChangesParaFieldAddItem;
CChangesParaFieldAddItem.prototype.Type = AscDFH.historyitem_Field_AddItem;
CChangesParaFieldAddItem.prototype.Undo = function()
{
	var oField = this.Class;
	oField.Content.splice(this.Pos, this.Items.length);
	oField.private_UpdateSpellChecking();
	oField.private_UpdateTrackRevisions();
	oField.private_CheckUpdateBookmarks(this.Items);
};
CChangesParaFieldAddItem.prototype.Redo = function()
{
	var oField = this.Class;

	var Array_start = oField.Content.slice(0, this.Pos);
	var Array_end   = oField.Content.slice(this.Pos);

	oField.Content = Array_start.concat(this.Items, Array_end);
	oField.private_UpdateTrackRevisions();
	oField.private_CheckUpdateBookmarks(this.Items);
	oField.private_UpdateSpellChecking();
};
CChangesParaFieldAddItem.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesParaFieldAddItem.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesParaFieldAddItem.prototype.Load = function(Color)
{
	var oField = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var Pos     = oField.m_oContentChanges.Check(AscCommon.contentchanges_Add, this.PosArray[nIndex]);
		var Element = this.Items[nIndex];

		if (null != Element)
		{
			oField.Content.splice(Pos, 0, Element);
			AscCommon.CollaborativeEditing.Update_DocumentPositionsOnAdd(oField, Pos);
		}
	}

	oField.private_UpdateTrackRevisions();
	oField.private_UpdateSpellChecking();
};
CChangesParaFieldAddItem.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_Field_AddItem === oChanges.Type || AscDFH.historyitem_Field_RemoveItem === oChanges.Type))
		return true;

	return false;
};
CChangesParaFieldAddItem.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesParaFieldRemoveItem);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesParaFieldRemoveItem(Class, Pos, Items)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, false);
}
CChangesParaFieldRemoveItem.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesParaFieldRemoveItem.prototype.constructor = CChangesParaFieldRemoveItem;
CChangesParaFieldRemoveItem.prototype.Type = AscDFH.historyitem_Field_RemoveItem;
CChangesParaFieldRemoveItem.prototype.Undo = function()
{
	var oField = this.Class;

	var Array_start = oField.Content.slice(0, this.Pos);
	var Array_end   = oField.Content.slice(this.Pos);

	oField.Content = Array_start.concat(this.Items, Array_end);
	oField.private_UpdateSpellChecking();
	oField.private_CheckUpdateBookmarks(this.Items);
	oField.private_UpdateTrackRevisions();
};
CChangesParaFieldRemoveItem.prototype.Redo = function()
{
	var oField = this.Class;
	oField.Content.splice(this.Pos, this.Items.length);
	oField.private_UpdateTrackRevisions();
	oField.private_CheckUpdateBookmarks(this.Items);
	oField.private_UpdateSpellChecking();
};
CChangesParaFieldRemoveItem.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesParaFieldRemoveItem.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesParaFieldRemoveItem.prototype.Load = function(Color)
{
	var oField = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var ChangesPos = oField.m_oContentChanges.Check(AscCommon.contentchanges_Remove, this.PosArray[nIndex]);

		if (false === ChangesPos)
			continue;

		oField.Content.splice(ChangesPos, 1);
		AscCommon.CollaborativeEditing.Update_DocumentPositionsOnRemove(oField, ChangesPos, 1);
	}
	oField.private_UpdateTrackRevisions();
	oField.private_UpdateSpellChecking();
};
CChangesParaFieldRemoveItem.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_Field_AddItem === oChanges.Type || AscDFH.historyitem_Field_RemoveItem === oChanges.Type))
		return true;

	return false;
};
CChangesParaFieldRemoveItem.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesParaFieldAddItem);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseStringProperty}
 */
function CChangesParaFieldFormFieldName(Class, Old, New)
{
	AscDFH.CChangesBaseStringProperty.call(this, Class, Old, New);
}
CChangesParaFieldFormFieldName.prototype = Object.create(AscDFH.CChangesBaseStringProperty.prototype);
CChangesParaFieldFormFieldName.prototype.constructor = CChangesParaFieldFormFieldName;
CChangesParaFieldFormFieldName.prototype.Type = AscDFH.historyitem_Field_FormFieldName;
CChangesParaFieldFormFieldName.prototype.private_SetValue = function(Value)
{
	this.Class.FormFieldName = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseStringProperty}
 */
function CChangesParaFieldFormFieldDefaultText(Class, Old, New)
{
	AscDFH.CChangesBaseStringProperty.call(this, Class, Old, New);
}
CChangesParaFieldFormFieldDefaultText.prototype = Object.create(AscDFH.CChangesBaseStringProperty.prototype);
CChangesParaFieldFormFieldDefaultText.prototype.constructor = CChangesParaFieldFormFieldDefaultText;
CChangesParaFieldFormFieldDefaultText.prototype.Type = AscDFH.historyitem_Field_FormFieldDefaultText;
CChangesParaFieldFormFieldDefaultText.prototype.private_SetValue = function(Value)
{
	this.Class.FormFieldDefaultText = Value;
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
  
// Import
var g_oTableId = AscCommon.g_oTableId;
var g_oTextMeasurer = AscCommon.g_oTextMeasurer;
var History = AscCommon.History;

var c_oAscShdNil = Asc.c_oAscShdNil;

var reviewtype_Common = 0x00;
var reviewtype_Remove = 0x01;
var reviewtype_Add    = 0x02;

function CSpellCheckerMarks()
{
	this.len = 0;
	this.data = null;

	this.Check = function(len)
	{
		if (len <= this.len)
		{
			for (var i = 0; i < len; i++)
				this.data[i] = 0;
			return this.data;
		}

		this.len = len;
		this.data = typeof(Int8Array) !== undefined ? new Int8Array(this.len) : new Array(this.len);
		return this.data;
	};
}
var g_oSpellCheckerMarks = new CSpellCheckerMarks();

/**
 *
 * @param Paragraph
 * @param bMathRun
 * @constructor
 * @extends {CParagraphContentWithContentBase}
 */
function ParaRun(Paragraph, bMathRun)
{
	CParagraphContentWithContentBase.call(this);
    
    this.Id         = AscCommon.g_oIdCounter.Get_NewId();  // Id данного элемента
    this.Type       = para_Run;                  // тип данного элемента
    this.Paragraph  = Paragraph;                 // Ссылка на параграф
    this.Pr         = new CTextPr();             // Текстовые настройки данного run
    this.Content    = [];                        // Содержимое данного run
        
    this.State      = new CParaRunState();       // Положение курсора и селекта в данного run
    this.Selection  = this.State.Selection;
    this.CompiledPr = new CTextPr();             // Скомпилированные настройки
    this.RecalcInfo = new CParaRunRecalcInfo();  // Флаги для пересчета (там же флаг пересчета стиля)

    this.TextAscent  = 0; // текстовый ascent + linegap
    this.TextAscent  = 0; // текстовый ascent + linegap
    this.TextDescent = 0; // текстовый descent
    this.TextHeight  = 0; // высота текста
    this.TextAscent2 = 0; // текстовый ascent
    this.Ascent      = 0; // общий ascent
    this.Descent     = 0; // общий descent
    this.YOffset     = 0; // смещение по Y

    this.CollPrChangeMine   = false;
    this.CollPrChangeOther  = false;
    this.CollaborativeMarks = new CRunCollaborativeMarks();
    this.m_oContentChanges  = new AscCommon.CContentChanges(); // список изменений(добавление/удаление элементов)

    this.NearPosArray  = [];
    this.SearchMarks   = [];
    this.SpellingMarks = [];

    this.ReviewType    = reviewtype_Common;
    this.ReviewInfo    = new CReviewInfo();
    if (editor && !editor.isPresentationEditor && editor.WordControl && editor.WordControl.m_oLogicDocument && true === editor.WordControl.m_oLogicDocument.Is_TrackRevisions())
    {
        this.ReviewType = reviewtype_Add;
        this.ReviewInfo.Update();
    }

    if(bMathRun)
    {
        this.Type = para_Math_Run;

        // запомним позицию для Recalculate_CurPos, когда  Run пустой
        this.pos          = new CMathPosition();
        this.ParaMath     = null;
        this.Parent       = null;
        this.ArgSize      = 0;
        this.size         = new CMathSize();
        this.MathPrp      = new CMPrp();
        this.bEqArray     = false;
    }
    this.StartState = null;

    this.CompositeInput = null;

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    g_oTableId.Add( this, this.Id );
    if(this.Paragraph && !this.Paragraph.bFromDocument)
    {
        this.Save_StartState();
    }
}

ParaRun.prototype = Object.create(CParagraphContentWithContentBase.prototype);
ParaRun.prototype.constructor = ParaRun;

ParaRun.prototype.Get_Type = function()
{
    return this.Type;
};
//-----------------------------------------------------------------------------------
// Функции для работы с Id
//-----------------------------------------------------------------------------------
ParaRun.prototype.Get_Id = function()
{
    return this.Id;
};
ParaRun.prototype.Set_ParaMath = function(ParaMath, Parent)
{
    this.ParaMath = ParaMath;
    this.Parent   = Parent;

    for(var i = 0; i < this.Content.length; i++)
    {
        this.Content[i].relate(this);
    }
};
ParaRun.prototype.Save_StartState = function()
{
    this.StartState = new CParaRunStartState(this);
};
//-----------------------------------------------------------------------------------
// Функции для работы с содержимым данного рана
//-----------------------------------------------------------------------------------
ParaRun.prototype.Copy = function(Selected, oPr)
{
	if (!oPr)
		oPr = {};

    var bMath = this.Type == para_Math_Run ? true : false;

    var NewRun = new ParaRun(this.Paragraph, bMath);

    NewRun.Set_Pr( this.Pr.Copy() );

    if (this.Paragraph && this.Paragraph.bFromDocument && this.Paragraph.LogicDocument && true === this.Paragraph.LogicDocument.Is_TrackRevisions())
        NewRun.Set_ReviewType(reviewtype_Add);

    if(true === bMath)
        NewRun.Set_MathPr(this.MathPrp.Copy());

    var StartPos = 0;
    var EndPos   = this.Content.length;

    if (true === Selected && true === this.State.Selection.Use)
    {
        StartPos = this.State.Selection.StartPos;
        EndPos   = this.State.Selection.EndPos;

        if (StartPos > EndPos)
        {
            StartPos = this.State.Selection.EndPos;
            EndPos   = this.State.Selection.StartPos;
        }
    }
    else if (true === Selected && true !== this.State.Selection.Use)
        EndPos = -1;

	for (var CurPos = StartPos, AddedPos = 0; CurPos < EndPos; CurPos++)
	{
		var Item = this.Content[CurPos];

		if (para_NewLine === Item.Type
			&& oPr
			&& ((oPr.SkipLineBreak && Item.IsLineBreak())
			|| (oPr.SkipPageBreak && Item.IsPageBreak())
			|| (oPr.SkipColumnBreak && Item.IsColumnBreak())))
		{
			if (oPr.Paragraph && true !== oPr.Paragraph.IsEmpty())
			{
				NewRun.Add_ToContent(AddedPos, new ParaSpace(), false);
				AddedPos++;
			}
		}
		else
		{
			// TODO: Как только перенесем para_End в сам параграф (как и нумерацию) убрать здесь
			if (para_End !== Item.Type
				&& (para_Drawing !== Item.Type || Item.Is_Inline() || true !== oPr.SkipAnchors)
				&& (para_FootnoteReference !== Item.Type || true !== oPr.SkipFootnoteReference)
				&& ((para_FieldChar !== Item.Type && para_InstrText !== Item.Type) || true !== oPr.SkipComplexFields))
			{
				NewRun.Add_ToContent(AddedPos, Item.Copy(), false);
				AddedPos++;
			}
		}
	}

    return NewRun;
};

ParaRun.prototype.Copy2 = function()
{
    var NewRun = new ParaRun(this.Paragraph);

    NewRun.Set_Pr( this.Pr.Copy() );

    var StartPos = 0;
    var EndPos   = this.Content.length;

    for ( var CurPos = StartPos; CurPos < EndPos; CurPos++ )
    {
        var Item = this.Content[CurPos];
        NewRun.Add_ToContent( CurPos - StartPos, Item.Copy(), false );
    }
    return NewRun;
};

ParaRun.prototype.CopyContent = function(Selected)
{
    return [this.Copy(Selected)];
};

ParaRun.prototype.GetAllDrawingObjects = function(DrawingObjs)
{
    var Count = this.Content.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        var Item = this.Content[Index];

        if ( para_Drawing === Item.Type )
        {
            DrawingObjs.push(Item);
            Item.GetAllDrawingObjects(DrawingObjs);
        }
    }
};

ParaRun.prototype.Clear_ContentChanges = function()
{
    this.m_oContentChanges.Clear();
};

ParaRun.prototype.Add_ContentChanges = function(Changes)
{
    this.m_oContentChanges.Add( Changes );
};

ParaRun.prototype.Refresh_ContentChanges = function()
{
    this.m_oContentChanges.Refresh();
};

ParaRun.prototype.Get_Text = function(Text)
{
    if ( null === Text.Text )
        return;

    var ContentLen = this.Content.length;

    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        var Item = this.Content[CurPos];
        var ItemType = Item.Type;

        var bBreak = false;

        switch ( ItemType )
        {
            case para_Drawing:
            case para_PageNum:
            case para_PageCount:
            {
				if (true === Text.BreakOnNonText)
				{
					Text.Text = null;
					bBreak = true;
				}

                break;
            }
			case para_End:
			{
				if (true === Text.BreakOnNonText)
				{
					Text.Text = null;
					bBreak = true;
				}

				if (true === Text.ParaEndToSpace)
					Text.Text += " ";

				break;
			}

            case para_Text : Text.Text += String.fromCharCode(Item.Value); break;
            case para_Space:
            case para_Tab  : Text.Text += " "; break;
        }

        if ( true === bBreak )
            break;
    }
};

// Проверяем пустой ли ран
ParaRun.prototype.Is_Empty = function(oProps)
{
	var SkipAnchor  = (undefined !== oProps ? oProps.SkipAnchor : false);
	var SkipEnd     = (undefined !== oProps ? oProps.SkipEnd : false);
	var SkipPlcHldr = (undefined !== oProps ? oProps.SkipPlcHldr : false);
	var SkipNewLine = (undefined !== oProps ? oProps.SkipNewLine : false);
	var SkipCF      = (undefined !== oProps ? oProps.SkipComplexFields : false);

	var nCount = this.Content.length;

	if (true !== SkipAnchor
		&& true !== SkipEnd
		&& true !== SkipPlcHldr
		&& true !== SkipNewLine
		&& true !== SkipCF)
	{
		if (nCount > 0)
			return false;
		else
			return true;
	}
	else
	{
		for (var nCurPos = 0; nCurPos < nCount; ++nCurPos)
		{
			var oItem = this.Content[nCurPos];
			var nType = oItem.Type;

			if ((true !== SkipAnchor || para_Drawing !== nType || false !== oItem.Is_Inline())
				&& (true !== SkipEnd || para_End !== nType)
				&& (true !== SkipPlcHldr || true !== oItem.IsPlaceholder())
				&& (true !== SkipNewLine || para_NewLine !== nType)
				&& (true !== SkipCF || (para_InstrText !== nType && para_FieldChar !== nType)))
				return false;
		}

		return true;
	}
};

ParaRun.prototype.Is_CheckingNearestPos = function()
{
    if (this.NearPosArray.length > 0)
        return true;

    return false;
};

// Начинается ли данный ран с новой строки
ParaRun.prototype.Is_StartFromNewLine = function()
{
    if (this.protected_GetLinesCount() < 2 || 0 !== this.protected_GetRangeStartPos(1, 0))
        return false;

    return true;
};

// Добавляем элемент в текущую позицию
ParaRun.prototype.Add = function(Item, bMath)
{
	if (undefined !== Item.Parent)
		Item.Parent = this;

	if (this.Paragraph && this.Paragraph.LogicDocument)
	{
		// Специальный код, связанный с обработкой изменения языка ввода при наборе.
		if (true === this.Paragraph.LogicDocument.CheckLanguageOnTextAdd && editor)
		{
			var nRequiredLanguage = editor.asc_getKeyboardLanguage();
			var nCurrentLanguage  = this.Get_CompiledPr(false).Lang.Val;
			if (-1 !== nRequiredLanguage && nRequiredLanguage !== nCurrentLanguage)
			{
				var NewLang = new CLang();
				NewLang.Val = nRequiredLanguage;

				if (this.Is_Empty())
				{
					this.Set_Lang(NewLang);
				}
				else
				{
					var NewRun = this.private_SplitRunInCurPos();
					if (NewRun)
					{
						NewRun.Set_Lang(NewLang);
						NewRun.MoveCursorToStartPos();
						NewRun.Add(Item, bMath);
						NewRun.Make_ThisElementCurrent();
						return;
					}
				}
			}
		}

		if(this.Paragraph.bFromDocument)
        {
            // Специальный код, связанный с работой сносок:
            // 1. При добавлении сноски мы ее оборачиваем в отдельный ран со специальным стилем.
            // 2. Если мы находимся в ране со специальным стилем сносок и следующий или предыдущий элемент и есть сноска, тогда
            //    мы добавляем элемент (если это не ссылка на сноску) в новый ран без стиля для сносок.
            var oStyles = this.Paragraph.LogicDocument.Get_Styles();
            if (para_FootnoteRef === Item.Type || para_FootnoteReference === Item.Type)
            {
                if (this.Is_Empty())
                {
                	this.Set_VertAlign(undefined);
                    this.Set_RStyle(oStyles.GetDefaultFootnoteReference());
                }
                else
                {
                    var NewRun = this.private_SplitRunInCurPos();
                    if (NewRun)
                    {
                        NewRun.Set_VertAlign(undefined);
                        NewRun.Set_RStyle(oStyles.GetDefaultFootnoteReference());
                        NewRun.MoveCursorToStartPos();
                        NewRun.Add(Item, bMath);
                        NewRun.Make_ThisElementCurrent();
                        return;
                    }
                }
            }
            else if (true === this.private_IsCurPosNearFootnoteReference())
            {
                var NewRun = this.private_SplitRunInCurPos();
                if (NewRun)
                {
                    NewRun.Set_VertAlign(AscCommon.vertalign_Baseline);
                    NewRun.MoveCursorToStartPos();
                    NewRun.Add(Item, bMath);
                    NewRun.Make_ThisElementCurrent();
                    return;
                }
            }
            // Специальный код с обработкой выделения (highlight)
            // Текст, который пишем до или после выделенного текста делаем без выделения.
            if ((0 === this.State.ContentPos || this.Content.length === this.State.ContentPos) && highlight_None !== this.Get_CompiledPr(false).HighLight)
            {
                var Parent = this.Get_Parent();
                var RunPos = this.private_GetPosInParent(Parent);
                if (null !== Parent && -1 !== RunPos)
                {
                    if ((0 === this.State.ContentPos
                        && (0 === RunPos
                        || Parent.Content[RunPos - 1].Type !== para_Run
                        || highlight_None === Parent.Content[RunPos - 1].Get_CompiledPr(false).HighLight))
                        || (this.Content.length === this.State.ContentPos
                        && (RunPos === Parent.Content.length - 1
                        || para_Run !== Parent.Content[RunPos + 1].Type
                        || highlight_None === Parent.Content[RunPos + 1].Get_CompiledPr(false).HighLight)
                        || (RunPos === Parent.Content.length - 2
                        && Parent instanceof Paragraph)))
                    {
                        var NewRun = this.private_SplitRunInCurPos();
                        if (NewRun)
                        {
                            NewRun.Set_HighLight(highlight_None);
                            NewRun.MoveCursorToStartPos();
                            NewRun.Add(Item, bMath);
                            NewRun.Make_ThisElementCurrent();
                            return;
                        }
                    }
                }
            }
        }
	}

	var oTrackRevisionsRun = this.CheckTrackRevisionsBeforeAdd();
    if (oTrackRevisionsRun)
    {
		oTrackRevisionsRun.private_AddItemToRun(oTrackRevisionsRun.State.ContentPos, Item);
		oTrackRevisionsRun.Make_ThisElementCurrent();
    }
    else if(this.Type == para_Math_Run && this.State.ContentPos == 0 && true === this.Is_StartForcedBreakOperator()) // если в начале текущего Run идет принудительный перенос => создаем новый Run
    {
        var NewRun = new ParaRun(this.Paragraph, bMath);
        NewRun.Set_Pr(this.Pr.Copy());
        NewRun.private_AddItemToRun(0, Item);

        // Ищем данный элемент в родительском классе
        var RunPos = this.private_GetPosInParent(this.Parent);

        this.Parent.Internal_Content_Add(RunPos, NewRun, true);
    }
    else
	{
		this.private_AddItemToRun(this.State.ContentPos, Item);

		if (this.Type === para_Run && Item.CanStartAutoCorrect())
			this.ProcessAutoCorrect(this.State.ContentPos - 1);
	}
};

/**
 * Ищем подходящий ран для добавления текста в режиме рецензирования (если нужно создаем новый), если возвращается
 * null, значит текущий ран подходит.
 * @returns {?ParaRun}
 */
ParaRun.prototype.CheckTrackRevisionsBeforeAdd = function()
{
	var TrackRevisions = false;
	if (this.Paragraph && this.Paragraph.LogicDocument)
		TrackRevisions = this.Paragraph.LogicDocument.Is_TrackRevisions();

	var ReviewType = this.Get_ReviewType();
	if ((true === TrackRevisions && (reviewtype_Add !== ReviewType || true !== this.ReviewInfo.Is_CurrentUser()))
		|| (false === TrackRevisions && reviewtype_Common !== ReviewType))
	{
		var DstReviewType = true === TrackRevisions ? reviewtype_Add : reviewtype_Common;

		// Если мы стоим в конце рана, тогда проверяем следующий элемент родительского класса, аналогично если мы стоим
		// в начале рана, проверяем предыдущий элемент родительского класса.

		var Parent = this.Get_Parent();
		if (null === Parent)
			return null;

		// Ищем данный элемент в родительском классе
		var RunPos = this.private_GetPosInParent(Parent);

		if (-1 === RunPos)
			return null;

		var CurPos = this.State.ContentPos;
		if (0 === CurPos && RunPos > 0)
		{
			var PrevElement = Parent.Content[RunPos - 1];
			if (para_Run === PrevElement.Type && DstReviewType === PrevElement.Get_ReviewType() && true === this.Pr.Is_Equal(PrevElement.Pr) && PrevElement.ReviewInfo && true === PrevElement.ReviewInfo.Is_CurrentUser())
			{
				PrevElement.State.ContentPos = PrevElement.Content.length;
				return PrevElement;
			}
		}

		if (this.Content.length === CurPos && (RunPos < Parent.Content.length - 2 || (RunPos < Parent.Content.length - 1 && !(Parent instanceof Paragraph))))
		{
			var NextElement = Parent.Content[RunPos + 1];
			if (para_Run === NextElement.Type && DstReviewType === NextElement.Get_ReviewType() && true === this.Pr.Is_Equal(NextElement.Pr) && NextElement.ReviewInfo && true === NextElement.ReviewInfo.Is_CurrentUser())
			{
				NextElement.State.ContentPos = 0;
				return NextElement;
			}
		}

		var NewRun = new ParaRun(this.Paragraph, this.IsMathRun());
		NewRun.Set_Pr(this.Pr.Copy());
		NewRun.Set_ReviewType(DstReviewType);
		NewRun.State.ContentPos = 0;

		if (0 === CurPos)
		{
			Parent.Add_ToContent(RunPos, NewRun);
		}
		else if (this.Content.length === CurPos)
		{
			Parent.Add_ToContent(RunPos + 1, NewRun);
		}
		else
		{
			var OldReviewInfo = (this.ReviewInfo ? this.ReviewInfo.Copy() : undefined);
			var OldReviewType = this.ReviewType;

			// Нужно разделить данный ран в текущей позиции
			var RightRun = this.Split2(CurPos);
			Parent.Add_ToContent(RunPos + 1, NewRun);
			Parent.Add_ToContent(RunPos + 2, RightRun);

			this.Set_ReviewTypeWithInfo(OldReviewType, OldReviewInfo);
			RightRun.Set_ReviewTypeWithInfo(OldReviewType, OldReviewInfo);
		}

		return NewRun;
	}

	return null;
};
/**
 * Проверяем, предзназначен ли данный ран чисто для математических формул.
 * @returns {boolean}
 */
ParaRun.prototype.IsMathRun = function()
{
	return this.Type === para_Math_Run ? true : false;
};

ParaRun.prototype.private_SplitRunInCurPos = function()
{
	var NewRun = null;
	var Parent = this.Get_Parent();
	var RunPos = this.private_GetPosInParent();
	if (null !== Parent && -1 !== RunPos)
	{
		// Если мы стоим в начале рана, тогда добавим новый ран в начало, если мы стоим в конце рана, тогда
		// добавим новый ран после текущего, а если мы в середине рана, тогда надо разбивать текущий ран.
		NewRun = new ParaRun(this.Paragraph, para_Math_Run === this.Type);
		NewRun.Set_Pr(this.Pr.Copy());

		var CurPos = this.State.ContentPos;
		if (0 === CurPos)
		{
			Parent.Add_ToContent(RunPos, NewRun);
		}
		else if (this.Content.length === CurPos)
		{
			Parent.Add_ToContent(RunPos + 1, NewRun);
		}
		else
		{
			// Нужно разделить данный ран в текущей позиции
			var RightRun = this.Split2(CurPos);
			Parent.Add_ToContent(RunPos + 1, NewRun);
			Parent.Add_ToContent(RunPos + 2, RightRun);
		}
	}

	return NewRun;
};
ParaRun.prototype.private_IsCurPosNearFootnoteReference = function()
{
	if (this.Paragraph && this.Paragraph.LogicDocument && this.Paragraph.bFromDocument)
	{
		var oStyles = this.Paragraph.LogicDocument.Get_Styles();
		var nCurPos = this.State.ContentPos;

		if (this.Get_RStyle() === oStyles.GetDefaultFootnoteReference()
			&& ((nCurPos > 0 && this.Content[nCurPos - 1] && (para_FootnoteRef === this.Content[nCurPos - 1].Type || para_FootnoteReference === this.Content[nCurPos - 1].Type))
			|| (nCurPos < this.Content.length && this.Content[nCurPos] && (para_FootnoteRef === this.Content[nCurPos].Type || para_FootnoteReference === this.Content[nCurPos].Type))))
			return true;
	}

	return false;
};
ParaRun.prototype.private_AddItemToRun = function(nPos, Item)
{
	if (para_FootnoteReference === Item.Type && true === Item.IsCustomMarkFollows() && undefined !== Item.GetCustomText())
	{
		this.AddToContent(nPos, Item, true);
		this.AddText(Item.GetCustomText(), nPos + 1);
	}
	else
	{
		this.Add_ToContent(nPos, Item, true);
	}
};


ParaRun.prototype.Remove = function(Direction, bOnAddText)
{
    var TrackRevisions = null;
    if (this.Paragraph && this.Paragraph.LogicDocument)
        TrackRevisions = this.Paragraph.LogicDocument.Is_TrackRevisions();

    var Selection = this.State.Selection;

    var ReviewType = this.Get_ReviewType();
    if (true === TrackRevisions && reviewtype_Add !== ReviewType)
    {
        if (reviewtype_Remove === ReviewType)
        {
            // Тут мы ничего не делаем, просто перешагиваем через удаленный текст
            if (true !== Selection.Use)
            {
                var CurPos = this.State.ContentPos;

                // Просто перешагиваем через элемент
                if (Direction < 0)
                {
                    // Пропускаем все Flow-объекты
                    while (CurPos > 0 && para_Drawing === this.Content[CurPos - 1].Type && false === this.Content[CurPos - 1].Is_Inline())
                        CurPos--;

                    if (CurPos <= 0)
                        return false;

                    this.State.ContentPos--;
                }
                else
                {
                    if (CurPos >= this.Content.length || para_End === this.Content[CurPos].Type)
                        return false;

                    this.State.ContentPos++;
                }

                this.Make_ThisElementCurrent();
            }
            else
            {
                // Ничего не делаем
            }
        }
        else
        {
            if (true === Selection.Use)
            {
                // Мы должны данный ран разбить в начальной и конечной точках выделения и центральный ран пометить как
                // удаленный.

                var StartPos = Selection.StartPos;
                var EndPos   = Selection.EndPos;

                if (StartPos > EndPos)
                {
                    StartPos = Selection.EndPos;
                    EndPos   = Selection.StartPos;
                }

                var Parent = this.Get_Parent();
                var RunPos = this.private_GetPosInParent(Parent);

                if (-1 !== RunPos)
                {
                    var DeletedRun = null;
                    if (StartPos <= 0 && EndPos >= this.Content.length)
                        DeletedRun = this;
                    else if (StartPos <= 0)
                    {
                        this.Split2(EndPos, Parent, RunPos);
                        DeletedRun = this;
                    }
                    else if (EndPos >= this.Content.length)
                    {
                        DeletedRun = this.Split2(StartPos, Parent, RunPos);
                    }
                    else
                    {
                        this.Split2(EndPos, Parent, RunPos);
                        DeletedRun = this.Split2(StartPos, Parent, RunPos);
                    }

                    DeletedRun.Set_ReviewType(reviewtype_Remove);
                }
            }
            else
            {
                var Parent = this.Get_Parent();
                var RunPos = this.private_GetPosInParent(Parent);

                var CurPos = this.State.ContentPos;
                if (Direction < 0)
                {
                    // Пропускаем все Flow-объекты
                    while (CurPos > 0 && para_Drawing === this.Content[CurPos - 1].Type && false === this.Content[CurPos - 1].Is_Inline())
                        CurPos--;

                    if (CurPos <= 0)
                        return false;

                    // Проверяем, возможно предыдущий элемент - инлайн картинка, тогда мы его не удаляем, а выделяем как картинку
                    if (para_Drawing == this.Content[CurPos - 1].Type && true === this.Content[CurPos - 1].Is_Inline())
                    {
                        return this.Paragraph.Parent.Select_DrawingObject(this.Content[CurPos - 1].Get_Id());
                    }

                    if (1 === CurPos && 1 === this.Content.length)
                    {
                        this.Set_ReviewType(reviewtype_Remove);
                        this.State.ContentPos = CurPos - 1;
                        this.Make_ThisElementCurrent();
                        return true;
                    }
                    else if (1 === CurPos && Parent && RunPos > 0)
                    {
                        var PrevElement = Parent.Content[RunPos - 1];
                        if (para_Run === PrevElement.Type && reviewtype_Remove === PrevElement.Get_ReviewType() && true === this.Pr.Is_Equal(PrevElement.Pr))
                        {
                            var Item = this.Content[CurPos - 1];
                            this.Remove_FromContent(CurPos - 1, 1, true);
                            PrevElement.Add_ToContent(PrevElement.Content.length, Item);
                            PrevElement.State.ContentPos = PrevElement.Content.length - 1;
                            PrevElement.Make_ThisElementCurrent();
                            return true;
                        }
                    }
                    else if (CurPos === this.Content.length && Parent && RunPos < Parent.Content.length - 1)
                    {
                        var NextElement = Parent.Content[RunPos + 1];
                        if (para_Run === NextElement.Type && reviewtype_Remove === NextElement.Get_ReviewType() && true === this.Pr.Is_Equal(NextElement.Pr))
                        {
                            var Item = this.Content[CurPos - 1];
                            this.Remove_FromContent(CurPos - 1, 1, true);
                            NextElement.Add_ToContent(0, Item);
                            this.State.ContentPos = CurPos - 1;
                            this.Make_ThisElementCurrent();
                            return true;
                        }
                    }

                    // Если мы дошли до сюда, значит данный элемент нужно выделять в отдельный ран
                    var RRun = this.Split2(CurPos, Parent, RunPos);
                    var CRun = this.Split2(CurPos - 1, Parent, RunPos);

                    CRun.Set_ReviewType(reviewtype_Remove);
                    this.State.ContentPos = CurPos - 1;
                    this.Make_ThisElementCurrent();
                }
                else
                {
                    if (CurPos >= this.Content.length || para_End === this.Content[CurPos].Type)
                        return false;

                    // Проверяем, возможно следующий элемент - инлайн картинка, тогда мы его не удаляем, а выделяем как картинку
                    if (para_Drawing == this.Content[CurPos].Type && true === this.Content[CurPos].Is_Inline())
                    {
                        return this.Paragraph.Parent.Select_DrawingObject(this.Content[CurPos].Get_Id());
                    }

                    if (CurPos === this.Content.length - 1 && 0 === CurPos)
                    {
                        this.Set_ReviewType(reviewtype_Remove);
                        this.State.ContentPos = 1;
                        this.Make_ThisElementCurrent();
                        return true;
                    }
                    else if (0 === CurPos && Parent && RunPos > 0)
                    {
                        var PrevElement = Parent.Content[RunPos - 1];
                        if (para_Run === PrevElement.Type && reviewtype_Remove === PrevElement.Get_ReviewType() && true === this.Pr.Is_Equal(PrevElement.Pr))
                        {
                            var Item = this.Content[CurPos];
                            this.Remove_FromContent(CurPos, 1, true);
                            PrevElement.Add_ToContent(PrevElement.Content.length, Item);
                            this.State.ContentPos = CurPos;
                            this.Make_ThisElementCurrent();
                            return true;
                        }
                    }
                    else if (CurPos === this.Content.length - 1 && Parent && RunPos < Parent.Content.length - 1)
                    {
                        var NextElement = Parent.Content[RunPos + 1];
                        if (para_Run === NextElement.Type && reviewtype_Remove === NextElement.Get_ReviewType() && true === this.Pr.Is_Equal(NextElement.Pr))
                        {
                            var Item = this.Content[CurPos];
                            this.Remove_FromContent(CurPos, 1, true);
                            NextElement.Add_ToContent(0, Item);
                            NextElement.State.ContentPos = 1;
                            NextElement.Make_ThisElementCurrent();
                            return true;
                        }
                    }

                    // Если мы дошли до сюда, значит данный элемент нужно выделять в отдельный ран
                    var RRun = this.Split2(CurPos + 1, Parent, RunPos);
                    var CRun = this.Split2(CurPos, Parent, RunPos);

                    CRun.Set_ReviewType(reviewtype_Remove);

                    RRun.State.ContentPos = 0;
                    RRun.Make_ThisElementCurrent();
                }
            }
        }
    }
    else
    {
        if (true === Selection.Use)
        {
            var StartPos = Selection.StartPos;
            var EndPos = Selection.EndPos;

            if (StartPos > EndPos)
            {
                var Temp = StartPos;
                StartPos = EndPos;
                EndPos = Temp;
            }

            // Если в выделение попадает ParaEnd, тогда удаляем все кроме этого элемента
            if (true === this.Selection_CheckParaEnd())
            {
                for (var CurPos = EndPos - 1; CurPos >= StartPos; CurPos--)
                {
                    if (para_End !== this.Content[CurPos].Type)
                        this.Remove_FromContent(CurPos, 1, true);
                }
            }
            else
            {
                this.Remove_FromContent(StartPos, EndPos - StartPos, true);
            }

            this.RemoveSelection();
            this.State.ContentPos = StartPos;
        }
        else
        {
            var CurPos = this.State.ContentPos;

            if (Direction < 0)
            {
                // Пропускаем все Flow-объекты
                while (CurPos > 0 && para_Drawing === this.Content[CurPos - 1].Type && false === this.Content[CurPos - 1].Is_Inline())
                    CurPos--;

                if (CurPos <= 0)
                    return false;

                // Проверяем, возможно предыдущий элемент - инлайн картинка, тогда мы его не удаляем, а выделяем как картинку
                if (para_Drawing == this.Content[CurPos - 1].Type && true === this.Content[CurPos - 1].Is_Inline())
                {
                    return this.Paragraph.Parent.Select_DrawingObject(this.Content[CurPos - 1].Get_Id());
                }
                else if (para_FieldChar === this.Content[CurPos - 1].Type)
				{
					var oComplexField = this.Content[CurPos - 1].GetComplexField();
					if (oComplexField)
					{
						oComplexField.SelectField();
						var oLogicDocument = this.Paragraph ? this.Paragraph.LogicDocument : null;
						if (oLogicDocument)
						{
							oLogicDocument.Document_UpdateInterfaceState();
							oLogicDocument.Document_UpdateSelectionState();
						}
					}
					return true;
				}

                this.Remove_FromContent(CurPos - 1, 1, true);

                this.State.ContentPos = CurPos - 1;
            }
            else
            {
            	while (CurPos < this.Content.length && para_Drawing === this.Content[CurPos].Type && false === this.Content[CurPos].Is_Inline())
					CurPos++;

                if (CurPos >= this.Content.length || para_End === this.Content[CurPos].Type)
                    return false;

                // Проверяем, возможно следующий элемент - инлайн картинка, тогда мы его не удаляем, а выделяем как картинку
                if (para_Drawing == this.Content[CurPos].Type && true === this.Content[CurPos].Is_Inline())
                {
                    return this.Paragraph.Parent.Select_DrawingObject(this.Content[CurPos].Get_Id());
                }
				else if (para_FieldChar === this.Content[CurPos].Type)
				{
					var oComplexField = this.Content[CurPos].GetComplexField();
					if (oComplexField)
					{
						oComplexField.SelectField();
						var oLogicDocument = this.Paragraph ? this.Paragraph.LogicDocument : null;
						if (oLogicDocument)
						{
							oLogicDocument.Document_UpdateInterfaceState();
							oLogicDocument.Document_UpdateSelectionState();
						}
					}
					return true;
				}

                this.Remove_FromContent(CurPos, 1, true);

                this.State.ContentPos = CurPos;
            }
        }
    }

    return true;
};

ParaRun.prototype.Remove_ParaEnd = function()
{
    var Pos = -1;

    var ContentLen = this.Content.length;
    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        if ( para_End === this.Content[CurPos].Type )
        {
            Pos = CurPos;
            break;
        }
    }

    if ( -1 === Pos )
        return false;

    this.Remove_FromContent( Pos, ContentLen - Pos, true );

    return true;
};

/**
 * Обновляем позиции селекта, курсора и переносов строк при добавлении элемента в контент данного рана.
 * @param Pos
 */
ParaRun.prototype.private_UpdatePositionsOnAdd = function(Pos)
{
    // Обновляем текущую позицию
    if (this.State.ContentPos >= Pos)
        this.State.ContentPos++;

    // Обновляем начало и конец селекта
    if (true === this.State.Selection.Use)
    {
        if (this.State.Selection.StartPos >= Pos)
            this.State.Selection.StartPos++;

        if (this.State.Selection.EndPos >= Pos)
            this.State.Selection.EndPos++;
    }

    // Также передвинем всем метки переносов страниц и строк
    var LinesCount = this.protected_GetLinesCount();
    for (var CurLine = 0; CurLine < LinesCount; CurLine++)
    {
        var RangesCount = this.protected_GetRangesCount(CurLine);

        for (var CurRange = 0; CurRange < RangesCount; CurRange++)
        {
            var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
            var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange);

            if (StartPos > Pos)
                StartPos++;

            if (EndPos > Pos)
                EndPos++;

            this.protected_FillRange(CurLine, CurRange, StartPos, EndPos);
        }

        // Особый случай, когда мы добавляем элемент в самый последний ран
        if (Pos === this.Content.length - 1 && LinesCount - 1 === CurLine)
        {
            this.protected_FillRangeEndPos(CurLine, RangesCount - 1, this.protected_GetRangeEndPos(CurLine, RangesCount - 1) + 1);
        }
    }
};

/**
 * Обновляем позиции селекта, курсора и переносов строк при удалении элементов из контента данного рана.
 * @param Pos
 * @param Count
 */
ParaRun.prototype.private_UpdatePositionsOnRemove = function(Pos, Count)
{
    // Обновим текущую позицию
    if (this.State.ContentPos > Pos + Count)
        this.State.ContentPos -= Count;
    else if (this.State.ContentPos > Pos)
        this.State.ContentPos = Pos;

    // Обновим начало и конец селекта
    if (true === this.State.Selection.Use)
    {
        if (this.State.Selection.StartPos <= this.State.Selection.EndPos)
        {
            if (this.State.Selection.StartPos > Pos + Count)
                this.State.Selection.StartPos -= Count;
            else if (this.State.Selection.StartPos > Pos)
                this.State.Selection.StartPos = Pos;

            if (this.State.Selection.EndPos >= Pos + Count)
                this.State.Selection.EndPos -= Count;
            else if (this.State.Selection.EndPos > Pos)
                this.State.Selection.EndPos = Math.max(0, Pos - 1);
        }
        else
        {
            if (this.State.Selection.StartPos >= Pos + Count)
                this.State.Selection.StartPos -= Count;
            else if (this.State.Selection.StartPos > Pos)
                this.State.Selection.StartPos = Math.max(0, Pos - 1);

            if (this.State.Selection.EndPos > Pos + Count)
                this.State.Selection.EndPos -= Count;
            else if (this.State.Selection.EndPos > Pos)
                this.State.Selection.EndPos = Pos;
        }
    }

    // Также передвинем всем метки переносов страниц и строк
    var LinesCount = this.protected_GetLinesCount();
    for (var CurLine = 0; CurLine < LinesCount; CurLine++)
    {
        var RangesCount = this.protected_GetRangesCount(CurLine);
        for (var CurRange = 0; CurRange < RangesCount; CurRange++)
        {
            var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
            var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange);

            if (StartPos > Pos + Count)
                StartPos -= Count;
            else if (StartPos > Pos)
                StartPos = Math.max(0, Pos);

            if (EndPos >= Pos + Count)
                EndPos -= Count;
            else if (EndPos >= Pos)
                EndPos = Math.max(0, Pos);

            this.protected_FillRange(CurLine, CurRange, StartPos, EndPos);
        }
    }
};

ParaRun.prototype.private_UpdateCompositeInputPositionsOnAdd = function(Pos)
{
	if (null !== this.CompositeInput)
	{
		if (Pos <= this.CompositeInput.Pos)
			this.CompositeInput.Pos++;
		else if (Pos < this.CompositeInput.Pos + this.CompositeInput.Length)
			this.CompositeInput.Length++;
	}
};

ParaRun.prototype.private_UpdateCompositeInputPositionsOnRemove = function(Pos, Count)
{
	if (null !== this.CompositeInput)
	{
		if (Pos + Count <= this.CompositeInput.Pos)
		{
			this.CompositeInput.Pos -= Count;
		}
		else if (Pos < this.CompositeInput.Pos)
		{
			this.CompositeInput.Pos    = Pos;
			this.CompositeInput.Length = Math.max(0, this.CompositeInput.Length - (Count - (this.CompositeInput.Pos - Pos)));
		}
		else if (Pos + Count < this.CompositeInput.Pos + this.CompositeInput.Length)
		{
			this.CompositeInput.Length = Math.max(0, this.CompositeInput.Length - Count);
		}
		else if (Pos < this.CompositeInput.Pos + this.CompositeInput.Length)
		{
			this.CompositeInput.Length = Math.max(0, Pos - this.CompositeInput.Pos);
		}
	}
};

ParaRun.prototype.GetLogicDocument = function()
{
	if (this.Paragraph && this.Paragraph.LogicDocument)
		return this.Paragraph.LogicDocument;

	return editor.WordControl.m_oLogicDocument;
};

// Добавляем элемент в позицию с сохранием в историю
ParaRun.prototype.Add_ToContent = function(Pos, Item, UpdatePosition)
{
	if (-1 === Pos)
		Pos = this.Content.length;

	if (Item.SetParent)
		Item.SetParent(this);

	History.Add(new CChangesRunAddItem(this, Pos, [Item], true));
    this.Content.splice( Pos, 0, Item );

    if (true === UpdatePosition)
        this.private_UpdatePositionsOnAdd(Pos);

    // Обновляем позиции в NearestPos
    var NearPosLen = this.NearPosArray.length;
    for ( var Index = 0; Index < NearPosLen; Index++ )
    {
        var RunNearPos = this.NearPosArray[Index];
        var ContentPos = RunNearPos.NearPos.ContentPos;
        var Depth      = RunNearPos.Depth;

        if ( ContentPos.Data[Depth] >= Pos )
            ContentPos.Data[Depth]++;
    }

	// Обновляем позиции в поиске
	var SearchMarksCount = this.SearchMarks.length;
	for (var Index = 0; Index < SearchMarksCount; Index++)
	{
		var Mark       = this.SearchMarks[Index];
		var ContentPos = ( true === Mark.Start ? Mark.SearchResult.StartPos : Mark.SearchResult.EndPos );
		var Depth      = Mark.Depth;

		if (ContentPos.Data[Depth] > Pos || (ContentPos.Data[Depth] === Pos && true === Mark.Start))
			ContentPos.Data[Depth]++;
	}

    // Обновляем позиции для орфографии
    var SpellingMarksCount = this.SpellingMarks.length;
    for ( var Index = 0; Index < SpellingMarksCount; Index++ )
    {
        var Mark       = this.SpellingMarks[Index];
        var ContentPos = ( true === Mark.Start ? Mark.Element.StartPos : Mark.Element.EndPos );
        var Depth      = Mark.Depth;

        if ( ContentPos.Data[Depth] >= Pos )
            ContentPos.Data[Depth]++;
    }

    this.private_UpdateSpellChecking();
	this.private_UpdateDocumentOutline();
    this.private_UpdateTrackRevisionOnChangeContent(true);

    // Обновляем позиции меток совместного редактирования
    this.CollaborativeMarks.Update_OnAdd( Pos );

    this.RecalcInfo.OnAdd(Pos);
};

ParaRun.prototype.Remove_FromContent = function(Pos, Count, UpdatePosition)
{
    // Получим массив удаляемых элементов
    var DeletedItems = this.Content.slice( Pos, Pos + Count );
	History.Add(new CChangesRunRemoveItem(this, Pos, DeletedItems));

    this.Content.splice( Pos, Count );

    if (true === UpdatePosition)
        this.private_UpdatePositionsOnRemove(Pos, Count);

	// Обновляем позиции в NearestPos
    var NearPosLen = this.NearPosArray.length;
    for ( var Index = 0; Index < NearPosLen; Index++ )
    {
        var RunNearPos = this.NearPosArray[Index];
        var ContentPos = RunNearPos.NearPos.ContentPos;
        var Depth      = RunNearPos.Depth;

        if ( ContentPos.Data[Depth] > Pos + Count )
            ContentPos.Data[Depth] -= Count;
        else if ( ContentPos.Data[Depth] > Pos )
            ContentPos.Data[Depth] = Math.max( 0 , Pos );
    }

    // Обновляем позиции в поиске
    var SearchMarksCount = this.SearchMarks.length;
    for ( var Index = 0; Index < SearchMarksCount; Index++ )
    {
        var Mark       = this.SearchMarks[Index];
        var ContentPos = ( true === Mark.Start ? Mark.SearchResult.StartPos : Mark.SearchResult.EndPos );
        var Depth      = Mark.Depth;

        if ( ContentPos.Data[Depth] > Pos + Count )
            ContentPos.Data[Depth] -= Count;
        else if ( ContentPos.Data[Depth] > Pos )
            ContentPos.Data[Depth] = Math.max( 0 , Pos );
    }

    // Обновляем позиции для орфографии
    var SpellingMarksCount = this.SpellingMarks.length;
    for ( var Index = 0; Index < SpellingMarksCount; Index++ )
    {
        var Mark       = this.SpellingMarks[Index];
        var ContentPos = ( true === Mark.Start ? Mark.Element.StartPos : Mark.Element.EndPos );
        var Depth      = Mark.Depth;

        if ( ContentPos.Data[Depth] > Pos + Count )
            ContentPos.Data[Depth] -= Count;
        else if ( ContentPos.Data[Depth] > Pos )
            ContentPos.Data[Depth] = Math.max( 0 , Pos );
    }

    this.private_UpdateSpellChecking();
	this.private_UpdateDocumentOutline();
	this.private_UpdateTrackRevisionOnChangeContent(true);

    // Обновляем позиции меток совместного редактирования
    this.CollaborativeMarks.Update_OnRemove( Pos, Count );

    this.RecalcInfo.OnRemove(Pos, Count);
};

/**
 * Добавляем к массиву содержимого массив новых элементов
 * @param arrNewItems
 */
ParaRun.prototype.ConcatToContent = function(arrNewItems)
{
	for (var nIndex = 0, nCount = arrNewItems.length; nIndex < nCount; ++nIndex)
	{
		if (arrNewItems[nIndex].SetParent)
			arrNewItems[nIndex].SetParent(this);
	}

	var StartPos = this.Content.length;
	this.Content = this.Content.concat(arrNewItems);

	History.Add(new CChangesRunAddItem(this, StartPos, arrNewItems, false));

	this.private_UpdateTrackRevisionOnChangeContent(true);

	// Отмечаем, что надо перемерить элементы в данном ране
	this.RecalcInfo.Measure = true;
};
/**
 * Добавляем в конец рана заданную строку
 * @param {string} sString
 * @param {number} [nPos=-1] если позиция не задана (или значение -1), то добавляем в конец
 */
ParaRun.prototype.AddText = function(sString, nPos)
{
	var nCharPos = undefined !== nPos && null !== nPos && -1 !== nPos ? nPos : this.Content.length;

	if (this.IsMathRun())
	{
		for (var oIterator = sString.getUnicodeIterator(); oIterator.check(); oIterator.next())
		{
			var nCharCode = oIterator.value();

			var oMathText = new CMathText();
			oMathText.add(nCharCode);
			this.AddToContent(nCharPos++, oMathText);
		}
	}
	else
	{
		for (var oIterator = sString.getUnicodeIterator(); oIterator.check(); oIterator.next())
		{
			var nCharCode = oIterator.value();

			if (9 === nCharCode) // \t
				this.AddToContent(nCharPos++, new ParaTab());
			else if (10 === nCharCode) // \n
				this.AddToContent(nCharPos++, new ParaNewLine(break_Line));
			else if (13 === nCharCode) // \r
				continue;
			else if (32 === nCharCode) // space
				this.AddToContent(nCharPos++, new ParaSpace());
			else
				this.AddToContent(nCharPos++, new ParaText(nCharCode));
		}
	}
};
/**
 * Добавляем в конец рана заданную инструкцию для сложного поля
 * @param {string} sString
 * @param {number} [nPos=-1] если позиция не задана (или значение -1), то добавляем в конец
 */
ParaRun.prototype.AddInstrText = function(sString, nPos)
{
	var nCharPos = undefined !== nPos && null !== nPos && -1 !== nPos ? nPos : this.Content.length;
	for (var oIterator = sString.getUnicodeIterator(); oIterator.check(); oIterator.next())
	{
		this.AddToContent(nCharPos++, new ParaInstrText(oIterator.value()));
	}
};

// Определим строку и отрезок текущей позиции
ParaRun.prototype.Get_CurrentParaPos = function()
{
    var Pos = this.State.ContentPos;

    if (-1 === this.StartLine)
        return new CParaPos(-1, -1, -1, -1);

    var CurLine  = 0;
    var CurRange = 0;

    var LinesCount = this.protected_GetLinesCount();
    for (; CurLine < LinesCount; CurLine++)
    {
        var RangesCount = this.protected_GetRangesCount(CurLine);
        for (CurRange = 0; CurRange < RangesCount; CurRange++)
        {
            var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
            var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);
            if ( Pos < EndPos && Pos >= StartPos )
                return new CParaPos((CurLine === 0 ? CurRange + this.StartRange : CurRange), CurLine + this.StartLine, 0, 0);
        }
    }

    // Значит курсор стоит в самом конце, поэтому посылаем последний отрезок
    if(this.Type == para_Math_Run && LinesCount > 1)
    {
        var Line  = LinesCount - 1,
            Range = this.protected_GetRangesCount(LinesCount - 1) - 1;

        StartPos = this.protected_GetRangeStartPos(Line, Range);
        EndPos   = this.protected_GetRangeEndPos(Line, Range);

        // учтем, что в одной строке в формуле может быть только один Range
        while(StartPos == EndPos && Line > 0 && this.Content.length !== 0) // == this.Content.length, т.к. последний Range
        {
            Line--;
            StartPos = this.protected_GetRangeStartPos(Line, Range);
            EndPos   = this.protected_GetRangeEndPos(Line, Range);
        }

        return new CParaPos((this.protected_GetRangesCount(Line) - 1), Line + this.StartLine, 0, 0 );
    }

    return new CParaPos((LinesCount <= 1 ? this.protected_GetRangesCount(0) - 1 + this.StartRange : this.protected_GetRangesCount(LinesCount - 1) - 1), LinesCount - 1 + this.StartLine, 0, 0 );
};

ParaRun.prototype.Get_ParaPosByContentPos = function(ContentPos, Depth)
{
    if (this.StartRange < 0 || this.StartLine < 0)
        return new CParaPos(0, 0, 0, 0);

    var Pos = ContentPos.Get(Depth);

    var CurLine  = 0;
    var CurRange = 0;

    var LinesCount = this.protected_GetLinesCount();
    if (LinesCount <= 0)
        return new CParaPos(0, 0, 0, 0);

    for (; CurLine < LinesCount; CurLine++)
    {
        var RangesCount = this.protected_GetRangesCount(CurLine);
        for (CurRange = 0; CurRange < RangesCount; CurRange++)
        {
            var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
            var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

            var bUpdateMathRun = Pos == EndPos && StartPos == EndPos && EndPos == this.Content.length && this.Type == para_Math_Run; // для para_Run позиция может быть после последнего элемента (пример: Run, за ним идет мат объект)
            if (Pos < EndPos && Pos >= StartPos || bUpdateMathRun)
                return new CParaPos((CurLine === 0 ? CurRange + this.StartRange : CurRange), CurLine + this.StartLine, 0, 0);
        }
    }

    return new CParaPos((LinesCount === 1 ? this.protected_GetRangesCount(0) - 1 + this.StartRange : this.protected_GetRangesCount(0) - 1), LinesCount - 1 + this.StartLine, 0, 0);
};

ParaRun.prototype.Recalculate_CurPos = function(X, Y, CurrentRun, _CurRange, _CurLine, CurPage, UpdateCurPos, UpdateTarget, ReturnTarget)
{
    var Para = this.Paragraph;

    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var Pos = StartPos;
    var _EndPos = ( true === CurrentRun ? Math.min( EndPos, this.State.ContentPos ) : EndPos );

    if(this.Type == para_Math_Run)
    {
        var Lng = this.Content.length;

        Pos = _EndPos;

        var LocParaMath = this.ParaMath.GetLinePosition(_CurLine, _CurRange);
        X = LocParaMath.x;
        Y = LocParaMath.y;

        var MATH_Y = Y;
        var loc;

        if(Lng == 0)
        {
            X += this.pos.x;
            Y += this.pos.y;
        }
        else if(Pos < EndPos)
        {
            loc = this.Content[Pos].GetLocationOfLetter();

            X += loc.x;
            Y += loc.y;
        }
        else if(!(StartPos == EndPos)) // исключаем этот случай StartPos == EndPos && EndPos == Pos, это возможно когда конец Run находится в начале строки, при этом ни одна из букв этого Run не входит в эту строку
        {
            var Letter = this.Content[Pos - 1];
            loc = Letter.GetLocationOfLetter();

            X += loc.x + Letter.Get_WidthVisible();
            Y += loc.y;
        }

    }
    else
    {
        for ( ; Pos < _EndPos; Pos++ )
        {
            var Item = this.private_CheckInstrText(this.Content[Pos]);
            var ItemType = Item.Type;

            if (para_Drawing === ItemType && drawing_Inline !== Item.DrawingType)
                continue;

            X += Item.Get_WidthVisible();
        }
    }

	var bNearFootnoteReference = this.private_IsCurPosNearFootnoteReference();
    if ( true === CurrentRun && Pos === this.State.ContentPos )
    {
        if ( true === UpdateCurPos )
        {
            // Обновляем позицию курсора в параграфе

            Para.CurPos.X        = X;
            Para.CurPos.Y        = Y;
            Para.CurPos.PagesPos = CurPage;

            if ( true === UpdateTarget )
            {
                var CurTextPr = this.Get_CompiledPr(false);
				var dFontKoef = bNearFootnoteReference ? 1 : CurTextPr.Get_FontKoef();

				g_oTextMeasurer.SetTextPr(CurTextPr, this.Paragraph.Get_Theme());
				g_oTextMeasurer.SetFontSlot(fontslot_ASCII, dFontKoef);
				var Height    = g_oTextMeasurer.GetHeight();
				var Descender = Math.abs(g_oTextMeasurer.GetDescender());
				var Ascender  = Height - Descender;

				Para.DrawingDocument.SetTargetSize(Height, Ascender);

                var RGBA;
                Para.DrawingDocument.UpdateTargetTransform(Para.Get_ParentTextTransform());
                if(CurTextPr.TextFill)
                {
                    CurTextPr.TextFill.check(Para.Get_Theme(), Para.Get_ColorMap());
                    var oColor = CurTextPr.TextFill.getRGBAColor();
                    Para.DrawingDocument.SetTargetColor( oColor.R, oColor.G, oColor.B );
                }
                else if(CurTextPr.Unifill)
                {
                    CurTextPr.Unifill.check(Para.Get_Theme(), Para.Get_ColorMap());
                    RGBA = CurTextPr.Unifill.getRGBAColor();
                    Para.DrawingDocument.SetTargetColor( RGBA.R, RGBA.G, RGBA.B );
                }
                else
                {
                    if ( true === CurTextPr.Color.Auto )
                    {
                        // Выясним какая заливка у нашего текста
                        var Pr = Para.Get_CompiledPr();
                        var BgColor = undefined;
                        if ( undefined !== Pr.ParaPr.Shd && c_oAscShdNil !== Pr.ParaPr.Shd.Value )
                        {
                            if(Pr.ParaPr.Shd.Unifill)
                            {
                                Pr.ParaPr.Shd.Unifill.check(this.Paragraph.Get_Theme(), this.Paragraph.Get_ColorMap());
                                var RGBA =  Pr.ParaPr.Shd.Unifill.getRGBAColor();
                                BgColor = new CDocumentColor(RGBA.R, RGBA.G, RGBA.B, false);
                            }
                            else
                            {
                                BgColor = Pr.ParaPr.Shd.Color;
                            }
                        }
                        else
                        {
                            // Нам надо выяснить заливку у родительского класса (возможно мы находимся в ячейке таблицы с забивкой)
                            BgColor = Para.Parent.Get_TextBackGroundColor();

                            if ( undefined !== CurTextPr.Shd && c_oAscShdNil !== CurTextPr.Shd.Value && !(CurTextPr.FontRef && CurTextPr.FontRef.Color) )
                                BgColor = CurTextPr.Shd.Get_Color( this.Paragraph );
                        }

                        // Определим автоцвет относительно заливки
                        var AutoColor = ( undefined != BgColor && false === BgColor.Check_BlackAutoColor() ? new CDocumentColor( 255, 255, 255, false ) : new CDocumentColor( 0, 0, 0, false ) );
                        var  RGBA, Theme = Para.Get_Theme(), ColorMap = Para.Get_ColorMap();
                        if((BgColor == undefined || BgColor.Auto) && CurTextPr.FontRef && CurTextPr.FontRef.Color)
                        {
                            CurTextPr.FontRef.Color.check(Theme, ColorMap);
                            RGBA = CurTextPr.FontRef.Color.RGBA;
                            AutoColor = new CDocumentColor( RGBA.R, RGBA.G, RGBA.B, RGBA.A );
                        }

                        Para.DrawingDocument.SetTargetColor( AutoColor.r, AutoColor.g, AutoColor.b );
                    }
                    else
                        Para.DrawingDocument.SetTargetColor( CurTextPr.Color.r, CurTextPr.Color.g, CurTextPr.Color.b );
                }

                var TargetY = Y - Ascender - CurTextPr.Position;
				if (!bNearFootnoteReference)
				{
					switch (CurTextPr.VertAlign)
					{
						case AscCommon.vertalign_SubScript:
						{
							TargetY -= CurTextPr.FontSize * g_dKoef_pt_to_mm * vertalign_Koef_Sub;
							break;
						}
						case AscCommon.vertalign_SuperScript:
						{
							TargetY -= CurTextPr.FontSize * g_dKoef_pt_to_mm * vertalign_Koef_Super;
							break;
						}
					}
				}

                var PageAbs = Para.Get_AbsolutePage(CurPage);
                // TODO: Тут делаем, чтобы курсор не выходил за границы буквицы. На самом деле, надо делать, чтобы
                //       курсор не выходил за границы строки, но для этого надо делать обрезку по строкам, а без нее
                //       такой вариант будет смотреться плохо.
                if (para_Math_Run === this.Type && null !== this.Parent && true !== this.Parent.bRoot && this.Parent.bMath_OneLine)
                {
                    var oBounds = this.Parent.Get_Bounds();
                    var __Y0 = TargetY, __Y1 = TargetY + Height;

                    // пока так
                    // TO DO : переделать

                    var YY = this.Parent.pos.y - this.Parent.size.ascent,
                        XX = this.Parent.pos.x;

                    var ___Y0 = MATH_Y + YY - 0.2 * oBounds.H;
                    var ___Y1 = MATH_Y + YY + 1.4 * oBounds.H;

                    __Y0 = Math.max( __Y0, ___Y0 );
                    __Y1 = Math.min( __Y1, ___Y1 );

					Para.DrawingDocument.SetTargetSize(__Y1 - __Y0, Ascender);
                    Para.DrawingDocument.UpdateTarget( X, __Y0, PageAbs );
                }
                else if ( undefined != Para.Get_FramePr() )
                {
                    var __Y0 = TargetY, __Y1 = TargetY + Height;
                    var ___Y0 = Para.Pages[CurPage].Y + Para.Lines[CurLine].Top;
                    var ___Y1 = Para.Pages[CurPage].Y + Para.Lines[CurLine].Bottom;

                    __Y0 = Math.max( __Y0, ___Y0 );
                    __Y1 = Math.min( __Y1, ___Y1 );

					Para.DrawingDocument.SetTargetSize(__Y1 - __Y0, Ascender);
                    Para.DrawingDocument.UpdateTarget( X, __Y0, PageAbs );
                }
                else
                {
                    Para.DrawingDocument.UpdateTarget(X, TargetY, PageAbs);
                }
            }
        }

        if ( true === ReturnTarget )
        {
			var CurTextPr = this.Get_CompiledPr(false);
			var dFontKoef = bNearFootnoteReference ? 1 : CurTextPr.Get_FontKoef();

			g_oTextMeasurer.SetTextPr(CurTextPr, this.Paragraph.Get_Theme());
			g_oTextMeasurer.SetFontSlot(fontslot_ASCII, dFontKoef);

			var Height    = g_oTextMeasurer.GetHeight();
			var Descender = Math.abs(g_oTextMeasurer.GetDescender());
			var Ascender  = Height - Descender;

			var TargetY = Y - Ascender - CurTextPr.Position;
			if (!bNearFootnoteReference)
			{
				switch (CurTextPr.VertAlign)
				{
					case AscCommon.vertalign_SubScript:
					{
						TargetY -= CurTextPr.FontSize * g_dKoef_pt_to_mm * vertalign_Koef_Sub;
						break;
					}
					case AscCommon.vertalign_SuperScript:
					{
						TargetY -= CurTextPr.FontSize * g_dKoef_pt_to_mm * vertalign_Koef_Super;
						break;
					}
				}
			}


            return { X : X, Y : TargetY, Height : Height, PageNum : Para.Get_AbsolutePage(CurPage), Internal : { Line : CurLine, Page : CurPage, Range : CurRange } };
        }
        else
            return { X : X, Y : Y, PageNum : Para.Get_AbsolutePage(CurPage), Internal : { Line : CurLine, Page : CurPage, Range : CurRange } };

    }

    return { X : X, Y: Y,  PageNum : Para.Get_AbsolutePage(CurPage), Internal : { Line : CurLine, Page : CurPage, Range : CurRange } };
};

// Проверяем, произошло ли простейшее изменение (набор или удаление текста)
ParaRun.prototype.Is_SimpleChanges = function(Changes)
{
    var ParaPos = null;

    var Count = Changes.length;
    for (var Index = 0; Index < Count; Index++)
    {
        var Data = Changes[Index].Data;

        if (undefined === Data.Items || 1 !== Data.Items.length)
            return false;

        var Type = Data.Type;
        var Item = Data.Items[0];

        if (undefined === Item)
            return false;

        if (AscDFH.historyitem_ParaRun_AddItem !== Type && AscDFH.historyitem_ParaRun_RemoveItem !== Type)
            return false;

        // Добавление/удаление картинок может изменить размер строки. Добавление/удаление переноса строки/страницы/колонки
        // нельзя обсчитывать функцией Recalculate_Fast. Добавление и удаление разметок сложных полей тоже нельзя
		// обсчитывать в быстром пересчете.
        // TODO: Но на самом деле стоило бы сделать нормальную проверку на высоту строки в функции Recalculate_Fast
        var ItemType = Item.Type;
        if (para_Drawing === ItemType || para_NewLine === ItemType || para_FootnoteRef === ItemType || para_FootnoteReference === ItemType || para_FieldChar === ItemType || para_InstrText === ItemType)
            return false;

        // Проверяем, что все изменения произошли в одном и том же отрезке
        var CurParaPos = this.Get_SimpleChanges_ParaPos([Changes[Index]]);
        if (null === CurParaPos)
            return false;

        if (null === ParaPos)
            ParaPos = CurParaPos;
        else if (ParaPos.Line !== CurParaPos.Line || ParaPos.Range !== CurParaPos.Range)
            return false;
    }

    return true;
};

/**
 * Проверяем произошло ли простое изменение параграфа, сейчас главное, чтобы это было не добавлениe/удаление картинки
 * или ссылки на сноску или разметки сложного поля. На вход приходит либо массив изменений, либо одно изменение
 * (можно не в массиве).
 */
ParaRun.prototype.IsParagraphSimpleChanges = function(_Changes)
{
    var Changes = _Changes;
    if (!_Changes.length)
        Changes = [_Changes];

    var ChangesCount = Changes.length;
    for (var ChangesIndex = 0; ChangesIndex < ChangesCount; ChangesIndex++)
    {
        var Data = Changes[ChangesIndex].Data;
        var ChangeType = Data.Type;

        if (AscDFH.historyitem_ParaRun_AddItem === ChangeType || AscDFH.historyitem_ParaRun_RemoveItem === ChangeType)
        {
            for (var ItemIndex = 0, ItemsCount = Data.Items.length; ItemIndex < ItemsCount; ItemIndex++)
            {
                var Item = Data.Items[ItemIndex];
                if (para_Drawing === Item.Type || para_FootnoteReference === Item.Type || para_FieldChar === Item.Type || para_InstrText === Item.Type)
                    return false;
            }
        }
    }

    return true;
};
/**
 * Проверяем, подходит ли содержимое данного рана быстрого пересчета
 * @returns {boolean}
 */
ParaRun.prototype.IsContentSuitableForParagraphSimpleChanges = function()
{
	for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos)
	{
		var nItemType = this.Content[nPos].Type;
		if (1 !== g_oSRCFPSC[nItemType])
			return false;
	}
	return true;
};

// Возвращаем строку и отрезок, в котором произошли простейшие изменения
ParaRun.prototype.Get_SimpleChanges_ParaPos = function(Changes)
{
    var Change = Changes[0].Data;
    var Type   = Changes[0].Data.Type;
    var Pos    = Change.Pos;

    var CurLine  = 0;
    var CurRange = 0;

    var LinesCount = this.protected_GetLinesCount();
    for (; CurLine < LinesCount; CurLine++)
    {
        var RangesCount = this.protected_GetRangesCount(CurLine);
        for (CurRange = 0; CurRange < RangesCount; CurRange++)
        {
            var RangeStartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
            var RangeEndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

            if  ( ( AscDFH.historyitem_ParaRun_AddItem === Type && Pos < RangeEndPos && Pos >= RangeStartPos ) || ( AscDFH.historyitem_ParaRun_RemoveItem === Type && Pos < RangeEndPos && Pos >= RangeStartPos ) || ( AscDFH.historyitem_ParaRun_RemoveItem === Type && Pos >= RangeEndPos && CurLine === LinesCount - 1 && CurRange === RangesCount - 1 ) )
            {
                // Если отрезок остается пустым, тогда надо все заново пересчитывать
                if ( RangeStartPos === RangeEndPos )
                    return null;

                return new CParaPos( ( CurLine === 0 ? CurRange + this.StartRange : CurRange ), CurLine + this.StartLine, 0, 0 );
            }
        }
    }

    // Если отрезок остается пустым, тогда надо все заново пересчитывать
    if (this.protected_GetRangeStartPos(0, 0) === this.protected_GetRangeEndPos(0, 0))
        return null;

    return new CParaPos( this.StartRange, this.StartLine, 0, 0 );
};

ParaRun.prototype.Split = function (ContentPos, Depth)
{
    var CurPos = ContentPos.Get(Depth);
    return this.Split2( CurPos );
};

ParaRun.prototype.Split2 = function(CurPos, Parent, ParentPos)
{
    History.Add(new CChangesRunOnStartSplit(this, CurPos));
    AscCommon.CollaborativeEditing.OnStart_SplitRun(this, CurPos);

    // Если задается Parent и ParentPos, тогда ран автоматически добавляется в родительский класс
    var UpdateParent    = (undefined !== Parent && undefined !== ParentPos && this === Parent.Content[ParentPos] ? true : false);
    var UpdateSelection = (true === UpdateParent && true === Parent.IsSelectionUse() && true === this.IsSelectionUse() ? true : false);

    // Создаем новый ран
    var bMathRun = this.Type == para_Math_Run;
    var NewRun = new ParaRun(this.Paragraph, bMathRun);

    // Копируем настройки
    NewRun.Set_Pr(this.Pr.Copy(true));
    NewRun.Set_ReviewTypeWithInfo(this.ReviewType, this.ReviewInfo ? this.ReviewInfo.Copy() : undefined);

    NewRun.CollPrChangeMine  = this.CollPrChangeMine;
    NewRun.CollPrChangeOther = this.CollPrChangeOther;

    if(bMathRun)
        NewRun.Set_MathPr(this.MathPrp.Copy());

    // TODO: Как только избавимся от para_End переделать тут
    // Проверим, если наш ран содержит para_End, тогда мы должны para_End переметить в правый ран

    var CheckEndPos = -1;
    var CheckEndPos2 = Math.min( CurPos, this.Content.length );
    for ( var Pos = 0; Pos < CheckEndPos2; Pos++ )
    {
        if ( para_End === this.Content[Pos].Type )
        {
            CheckEndPos = Pos;
            break;
        }
    }

    if ( -1 !== CheckEndPos )
        CurPos = CheckEndPos;

    var ParentOldSelectionStartPos, ParentOldSelectionEndPos, OldSelectionStartPos, OldSelectionEndPos;
    if (true === UpdateSelection)
    {
        ParentOldSelectionStartPos = Parent.Selection.StartPos;
        ParentOldSelectionEndPos   = Parent.Selection.EndPos;
        OldSelectionStartPos = this.Selection.StartPos;
        OldSelectionEndPos   = this.Selection.EndPos;
    }

    if (true === UpdateParent)
    {
        Parent.Add_ToContent(ParentPos + 1, NewRun);

        // Обновим массив NearPosArray
        for (var Index = 0, Count = this.NearPosArray.length; Index < Count; Index++)
        {
            var RunNearPos = this.NearPosArray[Index];
            var ContentPos = RunNearPos.NearPos.ContentPos;
            var Depth      = RunNearPos.Depth;

            var Pos = ContentPos.Get(Depth);

            if (Pos >= CurPos)
            {
                ContentPos.Update2(Pos - CurPos, Depth);
                ContentPos.Update2(ParentPos + 1, Depth - 1);

                this.NearPosArray.splice(Index, 1);
                Count--;
                Index--;

                NewRun.NearPosArray.push(RunNearPos);

                if (this.Paragraph)
                {
                    for (var ParaIndex = 0, ParaCount = this.Paragraph.NearPosArray.length; ParaIndex < ParaCount; ParaIndex++)
                    {
                        var ParaNearPos = this.Paragraph.NearPosArray[ParaIndex];
                        if (ParaNearPos.Classes[ParaNearPos.Classes.length - 1] === this)
                            ParaNearPos.Classes[ParaNearPos.Classes.length - 1] = NewRun;
                    }
                }
            }
        }
    }

    // Разделяем содержимое по ранам
    NewRun.ConcatToContent( this.Content.slice(CurPos) );
    this.Remove_FromContent( CurPos, this.Content.length - CurPos, true );

    // Если были точки орфографии, тогда переместим их в новый ран
    var SpellingMarksCount = this.SpellingMarks.length;
    for ( var Index = 0; Index < SpellingMarksCount; Index++ )
    {
        var Mark    = this.SpellingMarks[Index];
        var MarkPos = ( true === Mark.Start ? Mark.Element.StartPos.Get(Mark.Depth) : Mark.Element.EndPos.Get(Mark.Depth) );

        if ( MarkPos >= CurPos )
        {
            var MarkElement = Mark.Element;
            if ( true === Mark.Start )
            {
                MarkElement.StartPos.Data[Mark.Depth] -= CurPos;
            }
            else
            {
                MarkElement.EndPos.Data[Mark.Depth] -= CurPos;
            }

            NewRun.SpellingMarks.push( Mark );

            this.SpellingMarks.splice( Index, 1 );
            SpellingMarksCount--;
            Index--;
        }
    }

    if (true === UpdateSelection)
    {
        if (ParentOldSelectionStartPos <= ParentPos && ParentPos <= ParentOldSelectionEndPos)
            Parent.Selection.EndPos = ParentOldSelectionEndPos + 1;
        else if (ParentOldSelectionEndPos <= ParentPos && ParentPos <= ParentOldSelectionStartPos)
            Parent.Selection.StartPos = ParentOldSelectionStartPos + 1;

        if (OldSelectionStartPos <= CurPos && CurPos <= OldSelectionEndPos)
        {
            this.Selection.EndPos = this.Content.length;
            NewRun.Selection.Use      = true;
            NewRun.Selection.StartPos = 0;
            NewRun.Selection.EndPos   = OldSelectionEndPos - CurPos;
        }
        else if (OldSelectionEndPos <= CurPos && CurPos <= OldSelectionStartPos)
        {
            this.Selection.StartPos = this.Content.length;
            NewRun.Selection.Use      = true;
            NewRun.Selection.EndPos   = 0;
            NewRun.Selection.StartPos = OldSelectionStartPos - CurPos;
        }
    }

    History.Add(new CChangesRunOnEndSplit(this, NewRun));
    AscCommon.CollaborativeEditing.OnEnd_SplitRun(NewRun);
    return NewRun;
};


ParaRun.prototype.Check_NearestPos = function(ParaNearPos, Depth)
{
    var RunNearPos = new CParagraphElementNearPos();
    RunNearPos.NearPos = ParaNearPos.NearPos;
    RunNearPos.Depth   = Depth;

    this.NearPosArray.push( RunNearPos );
    ParaNearPos.Classes.push( this );
};

ParaRun.prototype.Get_DrawingObjectRun = function(Id)
{
    var ContentLen = this.Content.length;
    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        var Element = this.Content[CurPos];

        if ( para_Drawing === Element.Type && Id === Element.Get_Id() )
            return this;
    }

    return null;
};

ParaRun.prototype.Get_DrawingObjectContentPos = function(Id, ContentPos, Depth)
{
    var ContentLen = this.Content.length;
    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        var Element = this.Content[CurPos];

        if ( para_Drawing === Element.Type && Id === Element.Get_Id() )
        {
            ContentPos.Update( CurPos, Depth );
            return true;
        }
    }

    return false;
};

ParaRun.prototype.Get_DrawingObjectSimplePos = function(Id)
{
    var ContentLen = this.Content.length;
    for (var CurPos = 0; CurPos < ContentLen; CurPos++)
    {
        var Element = this.Content[CurPos];
        if (para_Drawing === Element.Type && Id === Element.Get_Id())
            return CurPos;
    }

    return -1;
};

ParaRun.prototype.Remove_DrawingObject = function(Id)
{
    var ContentLen = this.Content.length;
    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        var Element = this.Content[CurPos];

        if ( para_Drawing === Element.Type && Id === Element.Get_Id() )
        {
            var TrackRevisions = null;
            if (this.Paragraph && this.Paragraph.LogicDocument && this.Paragraph.bFromDocument)
                TrackRevisions = this.Paragraph.LogicDocument.Is_TrackRevisions();

            if (true === TrackRevisions)
            {
                var ReviewType = this.Get_ReviewType();
                if (reviewtype_Common === ReviewType)
                {
                    // Разбиваем ран на две части
                    var StartPos = CurPos;
                    var EndPos = CurPos + 1;

                    var Parent = this.Get_Parent();
                    var RunPos = this.private_GetPosInParent(Parent);

                    if (-1 !== RunPos && Parent)
                    {
                        var DeletedRun = null;
                        if (StartPos <= 0 && EndPos >= this.Content.length)
                            DeletedRun = this;
                        else if (StartPos <= 0)
                        {
                            this.Split2(EndPos, Parent, RunPos);
                            DeletedRun = this;
                        }
                        else if (EndPos >= this.Content.length)
                        {
                            DeletedRun = this.Split2(StartPos, Parent, RunPos);
                        }
                        else
                        {
                            this.Split2(EndPos, Parent, RunPos);
                            DeletedRun = this.Split2(StartPos, Parent, RunPos);
                        }

                        DeletedRun.Set_ReviewType(reviewtype_Remove);
                    }
                }
                else if (reviewtype_Add === ReviewType)
                {
                    this.Remove_FromContent(CurPos, 1, true);
                }
                else if (reviewtype_Remove === ReviewType)
                {
                    // Ничего не делаем
                }
            }
            else
            {
                this.Remove_FromContent(CurPos, 1, true);
            }

            return;
        }
    }
};

ParaRun.prototype.Get_Layout = function(DrawingLayout, UseContentPos, ContentPos, Depth)
{
    var CurLine  = DrawingLayout.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? DrawingLayout.Range - this.StartRange : DrawingLayout.Range );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var CurContentPos = ( true === UseContentPos ? ContentPos.Get(Depth) : -1 );

    var CurPos = StartPos;
    for ( ; CurPos < EndPos; CurPos++ )
    {
        if ( CurContentPos === CurPos )
            break;

        var Item         = this.Content[CurPos];
        var ItemType     = Item.Type;
        var WidthVisible = Item.Get_WidthVisible();

        switch ( ItemType )
        {
            case para_Text:
            case para_Space:
            case para_PageNum:
            case para_PageCount:
            {
                DrawingLayout.LastW = WidthVisible;

                break;
            }
            case para_Drawing:
            {
                if ( true === Item.Is_Inline() || true === DrawingLayout.Paragraph.Parent.Is_DrawingShape() )
                {
                    DrawingLayout.LastW = WidthVisible;
                }

                break;
            }
        }

        DrawingLayout.X += WidthVisible;
    }

    if (CurContentPos === CurPos)
        DrawingLayout.Layout = true;
};

ParaRun.prototype.GetNextRunElements = function(oRunElements, isUseContentPos, nDepth)
{
    var nStartPos  = true === isUseContentPos ? oRunElements.ContentPos.Get(nDepth) : 0;

    for (var nCurPos = nStartPos, nCount = this.Content.length; nCurPos < nCount; ++nCurPos)
    {
    	if (oRunElements.IsEnoughElements())
    		return;

		oRunElements.UpdatePos(nCurPos, nDepth);
		oRunElements.Add(this.Content[nCurPos]);
    }
};
ParaRun.prototype.GetPrevRunElements = function(oRunElements, isUseContentPos, nDepth)
{
    var nStartPos = true === isUseContentPos ? oRunElements.ContentPos.Get(nDepth) - 1 : this.Content.length - 1;

    for (var nCurPos = nStartPos; nCurPos >= 0; --nCurPos)
    {
    	if (oRunElements.IsEnoughElements())
    		return;

		oRunElements.UpdatePos(nCurPos, nDepth);
		oRunElements.Add(this.Content[nCurPos]);
    }
};

ParaRun.prototype.CollectDocumentStatistics = function(ParaStats)
{
	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		var Item     = this.Content[Index];
		var ItemType = Item.Type;

		var bSymbol  = false;
		var bSpace   = false;
		var bNewWord = false;

		if ((para_Text === ItemType && false === Item.Is_NBSP()) || (para_PageNum === ItemType || para_PageCount === ItemType))
		{
			if (false === ParaStats.Word)
				bNewWord = true;

			bSymbol = true;
			bSpace  = false;

			ParaStats.Word           = true;
			ParaStats.EmptyParagraph = false;
		}
		else if ((para_Text === ItemType && true === Item.Is_NBSP()) || para_Space === ItemType || para_Tab === ItemType)
		{
			bSymbol = true;
			bSpace  = true;

			ParaStats.Word = false;
		}

		if (true === bSymbol)
			ParaStats.Stats.Add_Symbol(bSpace);

		if (true === bNewWord)
			ParaStats.Stats.Add_Word();
	}
};

ParaRun.prototype.Create_FontMap = function(Map)
{
    // для Math_Para_Pun argSize учитывается, когда мержатся текстовые настройки в Internal_Compile_Pr()
    if ( undefined !== this.Paragraph && null !== this.Paragraph )
    {
        var TextPr;
        var FontSize, FontSizeCS;
        if(this.Type === para_Math_Run)
        {
            TextPr = this.Get_CompiledPr(false);

            FontSize   = TextPr.FontSize;
            FontSizeCS = TextPr.FontSizeCS;

            if(null !== this.Parent && undefined !== this.Parent && null !== this.Parent.ParaMath && undefined !== this.Parent.ParaMath)
            {
                TextPr.FontSize   = this.Math_GetRealFontSize(TextPr.FontSize);
                TextPr.FontSizeCS = this.Math_GetRealFontSize(TextPr.FontSizeCS);
            }
        }
        else
            TextPr = this.Get_CompiledPr(false);

        TextPr.Document_CreateFontMap(Map, this.Paragraph.Get_Theme().themeElements.fontScheme);
        var Count = this.Content.length;
        for (var Index = 0; Index < Count; Index++)
        {
            var Item = this.Content[Index];

			if (para_Drawing === Item.Type)
				Item.documentCreateFontMap(Map);
			else if (para_FootnoteReference === Item.Type)
				Item.CreateDocumentFontMap(Map);
        }

        if(this.Type === para_Math_Run)
        {
            TextPr.FontSize   = FontSize;
            TextPr.FontSizeCS = FontSizeCS;
        }
    }
};

ParaRun.prototype.Get_AllFontNames = function(AllFonts)
{
	this.Pr.Document_Get_AllFontNames(AllFonts);

	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		var Item = this.Content[Index];

		if (para_Drawing === Item.Type)
			Item.documentGetAllFontNames(AllFonts);
		else if (para_FootnoteReference === Item.Type)
			Item.GetAllFontNames(AllFonts);
	}
};

ParaRun.prototype.GetSelectedText = function(bAll, bClearText, oPr)
{
    var StartPos = 0;
    var EndPos   = 0;

    if ( true === bAll )
    {
        StartPos = 0;
        EndPos   = this.Content.length;
    }
    else if ( true === this.Selection.Use )
    {
        StartPos = this.State.Selection.StartPos;
        EndPos   = this.State.Selection.EndPos;

        if ( StartPos > EndPos )
        {
            var Temp = EndPos;
            EndPos   = StartPos;
            StartPos = Temp;
        }
    }

    var Str = "";

    for ( var Pos = StartPos; Pos < EndPos; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        switch ( ItemType )
        {
            case para_Drawing:
            case para_Numbering:
            case para_PresentationNumbering:
            case para_PageNum:
            case para_PageCount:
            {
                if ( true === bClearText )
                    return null;

                break;
            }

            case para_Text :
            {
                Str += AscCommon.encodeSurrogateChar(Item.Value);
                break;
            }
            case para_Space:
            case para_Tab  : Str += " "; break;
			case para_NewLine:
			{
				if (oPr && true === oPr.NewLine)
				{
					Str += '\r';
				}
				break;
			}
			case para_End:
			{
				if (oPr && true === oPr.NewLineParagraph)
				{
					if (this.Paragraph && null === this.Paragraph.Get_DocumentNext() && true === this.Paragraph.Parent.IsTableCellContent() && true !== this.Paragraph.Parent.IsLastTableCellInRow(true))
						Str += '\t';
					else
						Str += '\r\n';
				}

				break;
			}
        }
    }

    return Str;
};

ParaRun.prototype.Get_SelectionDirection = function()
{
    if (true !== this.Selection.Use)
        return 0;

    if (this.Selection.StartPos <= this.Selection.EndPos)
        return 1;

    return -1;
};

ParaRun.prototype.Can_AddDropCap = function()
{
    var Count = this.Content.length;

    for ( var Pos = 0; Pos < Count; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        switch ( ItemType )
        {
            case para_Text:
                return true;

            case para_Space:
            case para_Tab:
            case para_PageNum:
            case para_PageCount:
                return false;

        }
    }

    return null;
};

ParaRun.prototype.Get_TextForDropCap = function(DropCapText, UseContentPos, ContentPos, Depth)
{
    var EndPos = ( true === UseContentPos ? ContentPos.Get(Depth) : this.Content.length );

    for ( var Pos = 0; Pos < EndPos; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        if ( true === DropCapText.Check )
        {
			if (para_Space === ItemType || para_Tab === ItemType || para_PageNum === ItemType || para_PageCount === ItemType || para_Drawing === ItemType || para_End === ItemType)
            {
                DropCapText.Mixed = true;
                return;
            }
        }
        else
        {
            if ( para_Text === ItemType )
            {
                DropCapText.Runs.push(this);
                DropCapText.Text.push(Item);

                this.Remove_FromContent( Pos, 1, true );
                Pos--;
                EndPos--;

                if ( true === DropCapText.Mixed )
                    return;
            }
        }
    }
};

ParaRun.prototype.Get_StartTabsCount = function(TabsCounter)
{
    var ContentLen = this.Content.length;

    for ( var Pos = 0; Pos < ContentLen; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        if ( para_Tab === ItemType )
        {
            TabsCounter.Count++;
            TabsCounter.Pos.push( Pos );
        }
        else if ( para_Text === ItemType || para_Space === ItemType || (para_Drawing === ItemType && true === Item.Is_Inline() ) || para_PageNum === ItemType || para_PageCount === ItemType || para_Math === ItemType )
            return false;
    }

    return true;
};

ParaRun.prototype.Remove_StartTabs = function(TabsCounter)
{
    var ContentLen = this.Content.length;
    for ( var Pos = 0; Pos < ContentLen; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        if ( para_Tab === ItemType )
        {
            this.Remove_FromContent( Pos, 1, true );

            TabsCounter.Count--;
            Pos--;
            ContentLen--;
        }
        else if ( para_Text === ItemType || para_Space === ItemType || (para_Drawing === ItemType && true === Item.Is_Inline() ) || para_PageNum === ItemType || para_PageCount === ItemType || para_Math === ItemType )
            return false;
    }

    return true;
};
//-----------------------------------------------------------------------------------
// Функции пересчета
//-----------------------------------------------------------------------------------   
// Пересчитываем размеры всех элементов
ParaRun.prototype.Recalculate_MeasureContent = function()
{
	if (!this.RecalcInfo.IsMeasureNeed())
		return;

	var oTextPr = this.Get_CompiledPr(false);
	var oTheme  = this.Paragraph.Get_Theme();

	g_oTextMeasurer.SetTextPr(oTextPr, oTheme);
	g_oTextMeasurer.SetFontSlot(fontslot_ASCII);

	// Запрашиваем текущие метрики шрифта, под TextAscent мы будем понимать ascent + linegap(которые записаны в шрифте)
	this.TextHeight  = g_oTextMeasurer.GetHeight();
	this.TextDescent = Math.abs(g_oTextMeasurer.GetDescender());
	this.TextAscent  = this.TextHeight - this.TextDescent;
	this.TextAscent2 = g_oTextMeasurer.GetAscender();
	this.YOffset     = oTextPr.Position;

	var oInfoMathText;
	if (para_Math_Run == this.Type)
	{
		oInfoMathText = new CMathInfoTextPr({
			TextPr      : oTextPr,
			ArgSize     : this.Parent.Compiled_ArgSz.value,
			bNormalText : this.IsNormalText(),
			bEqArray    : this.Parent.IsEqArray()
		});
	}

	if (this.RecalcInfo.Measure)
	{
		for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos)
		{
			this.private_MeasureElement(nPos, oTextPr, oTheme, oInfoMathText);
		}
	}
	else
	{
		for (var nIndex = 0, nCount = this.RecalcInfo.MeasurePositions.length; nIndex < nCount; ++nIndex)
		{
			var nPos = this.RecalcInfo.MeasurePositions[nIndex];
			if (!this.Content[nPos])
				continue;

			this.private_MeasureElement(nPos, oTextPr, oTheme, oInfoMathText);
		}
	}

	this.RecalcInfo.Recalc = true;
	this.RecalcInfo.ResetMeasure();
};
ParaRun.prototype.private_MeasureElement = function(nPos, oTextPr, oTheme, oInfoMathText)
{
	var oParagraph = this.GetParagraph();

	var oItem     = this.Content[nPos];
	var nItemType = oItem.Type;

	if (para_Drawing === nItemType && oParagraph)
	{
		oItem.Parent          = oParagraph;
		oItem.DocumentContent = oParagraph.Parent;
		oItem.DrawingDocument = oParagraph.Parent.DrawingDocument;
	}

	// TODO: Как только избавимся от para_End переделать здесь
	if (para_End === nItemType && oParagraph)
	{
		var oEndTextPr = oParagraph.GetParaEndCompiledPr();
		g_oTextMeasurer.SetTextPr(oEndTextPr, oTheme);
		oItem.Measure(g_oTextMeasurer, oEndTextPr);
		return;
	}

	oItem.Measure(g_oTextMeasurer, oTextPr, oInfoMathText, this);

	if (para_Drawing === nItemType)
	{
		// После автофигур надо заново выставлять настройки
		g_oTextMeasurer.SetTextPr(oTextPr, oTheme);
		g_oTextMeasurer.SetFontSlot(fontslot_ASCII);
	}
};
ParaRun.prototype.Recalculate_Measure2 = function(Metrics)
{
    var TAscent  = Metrics.Ascent;
    var TDescent = Metrics.Descent;

    var Count = this.Content.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        var Item = this.Content[Index];
        var ItemType = Item.Type;

        if ( para_Text === ItemType )
        {
            var Temp = g_oTextMeasurer.Measure2(String.fromCharCode(Item.Value));

            if ( null === TAscent || TAscent < Temp.Ascent )
                TAscent = Temp.Ascent;

            if ( null === TDescent || TDescent > Temp.Ascent - Temp.Height )
                TDescent = Temp.Ascent - Temp.Height;
        }
    }

    Metrics.Ascent  = TAscent;
    Metrics.Descent = TDescent;
};

ParaRun.prototype.Recalculate_Range = function(PRS, ParaPr, Depth)
{
    if ( this.Paragraph !== PRS.Paragraph )
    {
        this.Paragraph = PRS.Paragraph;
        this.RecalcInfo.TextPr  = true;
        this.RecalcInfo.Measure = true;

        this.private_UpdateSpellChecking();
    }

    // Сначала измеряем элементы (можно вызывать каждый раз, внутри разруливается, чтобы измерялось 1 раз)
    this.Recalculate_MeasureContent();

    var CurLine  = PRS.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range );

    // Если мы рассчитываем первый отрезок в первой строке, тогда нам нужно обновить информацию о нумерации
    if ( 0 === CurRange && 0 === CurLine )
    {
        var PrevRecalcInfo = PRS.RunRecalcInfoLast;

        // Либо до этого ничего не было (изначально первая строка и первый отрезок), либо мы заново пересчитываем
        // первую строку и первый отрезок (из-за обтекания, например).
        if ( null === PrevRecalcInfo )
            this.RecalcInfo.NumberingAdd = true;
        else
            this.RecalcInfo.NumberingAdd = PrevRecalcInfo.NumberingAdd;

        this.RecalcInfo.NumberingUse  = false;
        this.RecalcInfo.NumberingItem = null;
    }

    // Сохраняем ссылку на информацию пересчета данного рана
    PRS.RunRecalcInfoLast = this.RecalcInfo;

    // Добавляем информацию о новом отрезке
    var RangeStartPos = this.protected_AddRange(CurLine, CurRange);
    var RangeEndPos   = 0;

    var Para                = PRS.Paragraph;

    var MoveToLBP           = PRS.MoveToLBP;
    var NewRange            = PRS.NewRange;
    var ForceNewPage        = PRS.ForceNewPage;
    var NewPage             = PRS.NewPage;
    var End                 = PRS.End;

    var Word                = PRS.Word;
    var StartWord           = PRS.StartWord;
    var FirstItemOnLine     = PRS.FirstItemOnLine;
	var EmptyLine           = PRS.EmptyLine;
    var TextOnLine          = PRS.TextOnLine;

    var RangesCount         = PRS.RangesCount;

    var SpaceLen            = PRS.SpaceLen;
    var WordLen             = PRS.WordLen;

    var X                   = PRS.X;
    var XEnd                = PRS.XEnd;

    var ParaLine            = PRS.Line;
    var ParaRange           = PRS.Range;
    var bMathWordLarge      = PRS.bMathWordLarge;
    var OperGapRight        = PRS.OperGapRight;
    var OperGapLeft         = PRS.OperGapLeft;

    var bInsideOper         = PRS.bInsideOper;
    var bContainCompareOper = PRS.bContainCompareOper;
    var bEndRunToContent    = PRS.bEndRunToContent;
    var bNoOneBreakOperator = PRS.bNoOneBreakOperator;
    var bForcedBreak        = PRS.bForcedBreak;

    var Pos = RangeStartPos;

    var ContentLen = this.Content.length;
    var XRange    = PRS.XRange;
    var oSectionPr = undefined;

    if (false === StartWord && true === FirstItemOnLine && XEnd - X < 0.001 && RangesCount > 0)
    {
        NewRange = true;
        RangeEndPos = Pos;
    }
    else
    {
        for (; Pos < ContentLen; Pos++)
        {
            var Item = this.Content[Pos];
            var ItemType = Item.Type;

            if (PRS.ComplexFields.IsHiddenFieldContent() && para_End !== ItemType && para_FieldChar !== ItemType)
            	continue;

			if (para_InstrText === ItemType && !PRS.IsFastRecalculate())
			{
				var oInstrText = Item;
				if (!PRS.ComplexFields.IsComplexFieldCode())
				{
					if (32 === Item.Value)
					{
						Item     = new ParaSpace();
						ItemType = para_Space;
					}
					else
					{
						Item     = new ParaText(Item.Value);
						ItemType = para_Text;
					}
					Item.Measure(g_oTextMeasurer, this.Get_CompiledPr(false));
					oInstrText.SetReplacementItem(Item);
				}
				else
				{
					oInstrText.SetReplacementItem(null);
				}
			}

            // Проверяем, не нужно ли добавить нумерацию к данному элементу
            if (true === this.RecalcInfo.NumberingAdd && true === Item.Can_AddNumbering())
                X = this.private_RecalculateNumbering(PRS, Item, ParaPr, X);

            switch (ItemType)
            {
                case para_Sym:
                case para_Text:
                case para_FootnoteReference:
                case para_FootnoteRef:
                case para_Separator:
                case para_ContinuationSeparator:
                {
                    // Отмечаем, что началось слово
                    StartWord = true;

					if (para_ContinuationSeparator === ItemType || para_Separator === ItemType)
						Item.UpdateWidth(PRS);

					if (true !== PRS.IsFastRecalculate())
					{
						if (para_FootnoteReference === ItemType)
						{
							Item.UpdateNumber(PRS);
							PRS.AddFootnoteReference(Item, PRS.GetCurrentContentPos(Pos));
						}
						else if (para_FootnoteRef === ItemType)
						{
							Item.UpdateNumber(PRS.TopDocument);
						}
					}

                    // При проверке, убирается ли слово, мы должны учитывать ширину предшествующих пробелов.
                    var LetterLen = Item.Width / TEXTWIDTH_DIVIDER;//var LetterLen = Item.Get_Width();

                    if (true !== Word)
                    {
                        // Слово только началось. Делаем следующее:
                        // 1) Если до него на строке ничего не было и данная строка не
                        //    имеет разрывов, тогда не надо проверять убирается ли слово в строке.
                        // 2) В противном случае, проверяем убирается ли слово в промежутке.

                        // Если слово только началось, и до него на строке ничего не было, и в строке нет разрывов, тогда не надо проверять убирается ли оно на строке.
                        if (true !== FirstItemOnLine || false === Para.Internal_Check_Ranges(ParaLine, ParaRange))
						{
							if (X + SpaceLen + LetterLen > XEnd)
							{
								if (para_Text === ItemType && !Item.CanBeAtBeginOfLine() && !PRS.LineBreakFirst)
								{
									MoveToLBP = true;
									NewRange  = true;
								}
								else
								{
									NewRange    = true;
									RangeEndPos = Pos;
								}
							}
						}

                        if (true !== NewRange)
                        {
                        	// Если с данного элемента не может начинаться строка, тогда считает все пробелы идущие
							// до него частью этого слова.
							// Если места для разрыва строки еще не было, значит это все еще первый элемент идет, и
							// тогда общую ширину пробелов прибавляем к ширине символа.
							// Если разрыв были и с данного символа не может начинаться строка, тогда испоьльзуем
							// предыдущий разрыв.
							if (para_Text === ItemType)
							{
								if (PRS.LineBreakFirst && !Item.CanBeAtBeginOfLine())
								{
									FirstItemOnLine = true;
									LetterLen       = LetterLen + SpaceLen;
									SpaceLen        = 0;
								}
								else if (Item.CanBeAtBeginOfLine())
								{
									PRS.Set_LineBreakPos(Pos, FirstItemOnLine);
								}
							}

                            // Если текущий символ с переносом, например, дефис, тогда на нем заканчивается слово
                            if (Item.Flags & PARATEXT_FLAGS_SPACEAFTER)//if ( true === Item.IsSpaceAfter() )
							{
								// Добавляем длину пробелов до слова и ширину самого слова.
								X += SpaceLen + LetterLen;

								Word            = false;
								FirstItemOnLine = false;
								EmptyLine       = false;
								TextOnLine      = true;
								SpaceLen        = 0;
								WordLen         = 0;
							}
                            else
							{
								Word    = true;
								WordLen = LetterLen;
							}
						}
                    }
                    else
                    {
                        if(X + SpaceLen + WordLen + LetterLen > XEnd)
                        {
                            if(true === FirstItemOnLine)
                            {
                                // Слово оказалось единственным элементом в промежутке, и, все равно,
                                // не умещается целиком. Делаем следующее:
                                //
                                //
                                // 1) Если у нас строка без вырезов, тогда ставим перенос строки на
                                //    текущей позиции.
                                // 2) Если у нас строка с вырезом, и данный вырез не последний, тогда
                                //    ставим перенос внутри строки в начале слова.
                                // 3) Если у нас строка с вырезом и вырез последний, тогда ставим перенос
                                //    строки в начале слова.

                                if (false === Para.Internal_Check_Ranges(ParaLine, ParaRange))
                                {
                                    // Слово не убирается в отрезке. Переносим слово в следующий отрезок
                                    MoveToLBP = true;
                                    NewRange = true;
                                }
                                else
                                {
                                    EmptyLine = false;
									TextOnLine = true;
                                    X += WordLen;

                                    // Слово не убирается в отрезке, но, поскольку, слово 1 на строке и отрезок тоже 1,
                                    // делим слово в данном месте
                                    NewRange = true;
                                    RangeEndPos = Pos;
                                }
                            }
                            else
                            {
                                // Слово не убирается в отрезке. Переносим слово в следующий отрезок
                                MoveToLBP = true;
                                NewRange = true;
                            }
                        }

                        if (true !== NewRange)
                        {
                            // Мы убираемся в пределах данной строки. Прибавляем ширину буквы к ширине слова
                            WordLen += LetterLen;

                            // Если текущий символ с переносом, например, дефис, тогда на нем заканчивается слово
                            if (Item.Flags & PARATEXT_FLAGS_SPACEAFTER)//if ( true === Item.IsSpaceAfter() )
                            {
                                // Добавляем длину пробелов до слова и ширину самого слова.
                                X += SpaceLen + WordLen;

                                Word = false;
                                FirstItemOnLine = false;
                                EmptyLine = false;
								TextOnLine = true;
                                SpaceLen = 0;
                                WordLen = 0;
                            }
                        }
                    }

                    break;
                }
                case para_Math_Text:
                case para_Math_Ampersand:
                case para_Math_Placeholder:
                {
                    // Отмечаем, что началось слово
                    StartWord = true;

                    // При проверке, убирается ли слово, мы должны учитывать ширину предшествующих пробелов.
                    var LetterLen = Item.Get_Width2() / TEXTWIDTH_DIVIDER;//var LetterLen = Item.Get_Width();

                    if (true !== Word)
                    {
                        // Если слово только началось, и до него на строке ничего не было, и в строке нет разрывов, тогда не надо проверять убирается ли оно на строке.
                        if (true !== FirstItemOnLine /*|| false === Para.Internal_Check_Ranges(ParaLine, ParaRange)*/)
                        {
                            if (X + SpaceLen + LetterLen > XEnd)
                            {
                                NewRange = true;
                                RangeEndPos = Pos;
                            }
                            else if(bForcedBreak == true)
                            {
                                MoveToLBP = true;
                                NewRange = true;
                                PRS.Set_LineBreakPos(Pos, FirstItemOnLine);
                            }
                        }

                        if(true !== NewRange)
                        {
                            if(this.Parent.bRoot == true)
                                PRS.Set_LineBreakPos(Pos, FirstItemOnLine);

                            WordLen += LetterLen;
                            Word = true;
                        }

                    }
                    else
                    {
                        if(X + SpaceLen + WordLen + LetterLen > XEnd)
                        {
                            if(true === FirstItemOnLine /*&& true === Para.Internal_Check_Ranges(ParaLine, ParaRange)*/)
                            {
                                // Слово оказалось единственным элементом в промежутке, и, все равно, не умещается целиком.
                                // для Формулы слово не разбиваем, перенос не делаем, пишем в одну строку (слово выйдет за границу как в Ворде)

                                bMathWordLarge = true;

                            }
                            else
                            {
                                // Слово не убирается в отрезке. Переносим слово в следующий отрезок
                                MoveToLBP = true;
                                NewRange = true;
                            }
                        }

                        if (true !== NewRange)
                        {
                            // Мы убираемся в пределах данной строки. Прибавляем ширину буквы к ширине слова
                            WordLen += LetterLen;
                        }
                    }

                    break;
                }
                case para_Space:
                {
                	if (Word && PRS.LastItem && para_Text === PRS.LastItem.Type && !PRS.LastItem.CanBeAtEndOfLine())
					{
						WordLen += Item.Width / TEXTWIDTH_DIVIDER;//SpaceLen += Item.Get_Width();
						break;
					}

                    FirstItemOnLine = false;

                    if (true === Word)
                    {
                        // Добавляем длину пробелов до слова + длина самого слова. Не надо проверять
                        // убирается ли слово, мы это проверяем при добавленнии букв.
                        X += SpaceLen + WordLen;

                        Word = false;
                        EmptyLine = false;
						TextOnLine = true;
                        SpaceLen = 0;
                        WordLen = 0;
                    }

                    // На пробеле не делаем перенос. Перенос строки или внутристрочный
                    // перенос делаем при добавлении любого непробельного символа
                    SpaceLen += Item.Width / TEXTWIDTH_DIVIDER;//SpaceLen += Item.Get_Width();

                    break;
                }
                case para_Math_BreakOperator:
                {
                    var BrkLen = Item.Get_Width2()/TEXTWIDTH_DIVIDER;

                    var bCompareOper = Item.Is_CompareOperator();
                    var bOperBefore = this.ParaMath.Is_BrkBinBefore() == true;

                    var bOperInEndContent = bOperBefore === false && bEndRunToContent === true && Pos == ContentLen - 1 && Word == true, // необходимо для того, чтобы у контентов мат объектов (к-ые могут разбиваться на строки) не было отметки Set_LineBreakPos, иначе скобка (или GapLeft), перед которой стоит break_Operator, перенесется на следующую строку (без текста !)
                        bLowPriority      = bCompareOper == false && bContainCompareOper == false;

                    if(Pos == 0 && true === this.IsForcedBreak()) // принудительный перенос срабатывает всегда
                    {
                        if(FirstItemOnLine === true && Word == false && bNoOneBreakOperator == true) // первый оператор в строке
                        {
                            WordLen += BrkLen;
                        }
                        else if(bOperBefore)
                        {
                            X += SpaceLen + WordLen;
                            WordLen = 0;
                            SpaceLen = 0;
                            NewRange = true;
                            RangeEndPos = Pos;

                        }
                        else
                        {
                            if(FirstItemOnLine == false && X + SpaceLen + WordLen + BrkLen > XEnd)
                            {
                                MoveToLBP = true;
                                NewRange = true;
                            }
                            else
                            {
                                X += SpaceLen + WordLen;
                                Word = false;
                                MoveToLBP = true;
                                NewRange = true;
                                PRS.Set_LineBreakPos(1, FirstItemOnLine);
                            }
                        }
                    }
                    else if(bOperInEndContent || bLowPriority) // у этого break Operator приоритет низкий(в контенте на данном уровне есть другие операторы с более высоким приоритетом) => по нему не разбиваем, обрабатываем как обычную букву
                    {
                        if(X + SpaceLen + WordLen + BrkLen > XEnd)
                        {
                            if(FirstItemOnLine == true)
                            {
                                bMathWordLarge = true;
                            }
                            else
                            {
                                // Слово не убирается в отрезке. Переносим слово в следующий отрезок
                                MoveToLBP = true;
                                NewRange = true;
                            }
                        }
                        else
                        {
                            WordLen += BrkLen;
                        }
                    }
                    else
                    {
                        var WorLenCompareOper = WordLen + X - XRange + (bOperBefore  ? SpaceLen : BrkLen);

                        var bOverXEnd, bOverXEndMWordLarge;
                        var bNotUpdBreakOper = false;

                        var bCompareWrapIndent = PRS.bFirstLine == true ? WorLenCompareOper > PRS.WrapIndent : true;

                        if(PRS.bPriorityOper == true && bCompareOper == true && bContainCompareOper == true && bCompareWrapIndent == true && !(Word == false && FirstItemOnLine === true)) // (Word == true && FirstItemOnLine == true) - не первый элемент в строке
                            bContainCompareOper = false;

                        if(bOperBefore)  // оператор "до" => оператор находится в начале строки
                        {
                            bOverXEnd = X + WordLen + SpaceLen + BrkLen > XEnd; // BrkLen прибавляем дла случая, если идут подряд Brk Operators в конце
                            bOverXEndMWordLarge = X + WordLen + SpaceLen > XEnd; // ширину самого оператора не учитываем при расчете bMathWordLarge, т.к. он будет находится на следующей строке

                            if(bOverXEnd && (true !== FirstItemOnLine || true === Word))
                            {
                                // если вышли за границы не обновляем параметр bInsideOper, т.к. если уже были breakOperator, то, соответственно, он уже выставлен в true
                                // а если на этом уровне не было breakOperator, то и обновлять его нне нужо

                                if(FirstItemOnLine === false)
                                {
                                    MoveToLBP = true;
                                    NewRange = true;
                                }
                                else
                                {
                                    if(Word == true && bOverXEndMWordLarge == true)
                                    {
                                        bMathWordLarge = true;
                                    }

                                    X += SpaceLen + WordLen;

                                    if(PRS.bBreakPosInLWord == true)
                                    {
                                        PRS.Set_LineBreakPos(Pos, FirstItemOnLine);

                                    }
                                    else
                                    {
                                        bNotUpdBreakOper = true;
                                    }

                                    RangeEndPos = Pos;

                                    SpaceLen = 0;
                                    WordLen = 0;

                                    NewRange = true;
                                    EmptyLine = false;
									TextOnLine = true;
                                }
                            }
                            else
                            {
                                if(FirstItemOnLine === false)
                                    bInsideOper = true;


                                if(Word == false && FirstItemOnLine == true )
                                {
                                    SpaceLen += BrkLen;
                                }
                                else
                                {
                                    // проверка на FirstItemOnLine == false нужна для случая, если иду подряд несколько breakOperator
                                    // в этом случае Word == false && FirstItemOnLine == false, нужно также поставить отметку для потенциального переноса

                                    X += SpaceLen + WordLen;
                                    PRS.Set_LineBreakPos(Pos, FirstItemOnLine);
                                    EmptyLine = false;
									TextOnLine = true;
                                    WordLen = BrkLen;
                                    SpaceLen = 0;

                                }

                                // в первой строке может не быть ни одного break Operator, при этом слово не выходит за границы, т.о. обновляем FirstItemOnLine также и на Word = true
                                // т.к. оператор идет в начале строки, то соответственно слово в стоке не будет первым, если в строке больше одного оператора
                                if(bNoOneBreakOperator == false || Word == true)
                                    FirstItemOnLine = false;

                            }
                        }
                        else   // оператор "после" => оператор находится в конце строки
                        {
                            bOverXEnd = X + WordLen + BrkLen - Item.GapRight > XEnd;
                            bOverXEndMWordLarge = bOverXEnd;

                            if(bOverXEnd && FirstItemOnLine === false) // Слово не убирается в отрезке. Переносим слово в следующий отрезок
                            {
                                MoveToLBP = true;
                                NewRange = true;

                                if(Word == false)
                                    PRS.Set_LineBreakPos(Pos, FirstItemOnLine);
                            }
                            else
                            {
                                bInsideOper = true;

                                // осуществляем здесь, чтобы не изменить GapRight в случае, когда новое слово не убирается на break_Operator
                                OperGapRight = Item.GapRight;

                                if(bOverXEndMWordLarge == true) // FirstItemOnLine == true
                                {
                                    bMathWordLarge = true;

                                }

                                X += BrkLen + WordLen;

                                EmptyLine = false;
								TextOnLine = true;
                                SpaceLen = 0;
                                WordLen = 0;

                                var bNotUpdate = bOverXEnd == true && PRS.bBreakPosInLWord == false;

                                // FirstItemOnLine == true
                                if(bNotUpdate == false) // LineBreakPos обновляем здесь, т.к. слово может начаться с мат объекта, а не с Run, в мат объекте нет соответствующей проверки
								{
									PRS.Set_LineBreakPos(Pos + 1, FirstItemOnLine);
								}
                                else
                                {
                                    bNotUpdBreakOper = true;
                                }

                                FirstItemOnLine = false;

                                Word = false;
                            }
                        }
                    }

                    if(bNotUpdBreakOper == false)
                        bNoOneBreakOperator = false;

                    break;
                }
                case para_Drawing:
                {
                    if(oSectionPr === undefined)
                    {
                        oSectionPr = Para.Get_SectPr();
                    }
                    Item.CheckRecalcAutoFit(oSectionPr);
                    if (true === Item.Is_Inline() || true === Para.Parent.Is_DrawingShape())
                    {
                    	// TODO: Нельзя что-то писать в историю во время пересчета, это действие надо делать при открытии
                        // if (true !== Item.Is_Inline())
                        //     Item.Set_DrawingType(drawing_Inline);

                        if (true === StartWord)
                            FirstItemOnLine = false;

                        Item.YOffset = this.YOffset;

                        // Если до этого было слово, тогда не надо проверять убирается ли оно, но если стояли пробелы,
                        // тогда мы их учитываем при проверке убирается ли данный элемент, и добавляем только если
                        // данный элемент убирается
                        if (true === Word || WordLen > 0)
                        {
                            // Добавляем длину пробелов до слова + длина самого слова. Не надо проверять
                            // убирается ли слово, мы это проверяем при добавленнии букв.
                            X += SpaceLen + WordLen;

                            Word = false;
                            EmptyLine = false;
							TextOnLine = true;
                            SpaceLen = 0;
                            WordLen = 0;
                        }

                        var DrawingWidth = Item.Get_Width();
                        if (X + SpaceLen + DrawingWidth > XEnd && ( false === FirstItemOnLine || false === Para.Internal_Check_Ranges(ParaLine, ParaRange) ))
                        {
                            // Автофигура не убирается, ставим перенос перед ней
                            NewRange = true;
                            RangeEndPos = Pos;
                        }
                        else
                        {
                            // Добавляем длину пробелов до автофигуры
                            X += SpaceLen + DrawingWidth;

                            FirstItemOnLine = false;
                            EmptyLine = false;
                        }

                        SpaceLen = 0;
                    }
                    else if (!Item.IsSkipOnRecalculate())
                    {
                        // Основная обработка происходит в Recalculate_Range_Spaces. Здесь обрабатывается единственный случай,
                        // когда после второго пересчета с уже добавленной картинкой оказывается, что место в параграфе, где
                        // идет картинка ушло на следующую страницу. В этом случае мы ставим перенос страницы перед картинкой.

                        var LogicDocument = Para.Parent;
                        var LDRecalcInfo = LogicDocument.RecalcInfo;
                        var DrawingObjects = LogicDocument.DrawingObjects;
                        var CurPage = PRS.Page;

                        if (true === LDRecalcInfo.Check_FlowObject(Item) && true === LDRecalcInfo.Is_PageBreakBefore())
                        {
                            LDRecalcInfo.Reset();

                            // Добавляем разрыв страницы. Если это первая страница, тогда ставим разрыв страницы в начале параграфа,
                            // если нет, тогда в начале текущей строки.

                            if (null != Para.Get_DocumentPrev() && true != Para.Parent.IsTableCellContent() && 0 === CurPage)
                            {
                                Para.Recalculate_Drawing_AddPageBreak(0, 0, true);
                                PRS.RecalcResult = recalcresult_NextPage | recalcresultflags_Page;
                                PRS.NewRange = true;
                                return;
                            }
                            else
                            {
                                if (ParaLine != Para.Pages[CurPage].FirstLine)
                                {
                                    Para.Recalculate_Drawing_AddPageBreak(ParaLine, CurPage, false);
                                    PRS.RecalcResult = recalcresult_NextPage | recalcresultflags_Page;
                                    PRS.NewRange = true;
                                    return;
                                }
                                else
                                {
                                    RangeEndPos = Pos;
                                    NewRange = true;
                                    ForceNewPage = true;
                                }
                            }


                            // Если до этого было слово, тогда не надо проверять убирается ли оно
                            if (true === Word || WordLen > 0)
                            {
                                // Добавляем длину пробелов до слова + длина самого слова. Не надо проверять
                                // убирается ли слово, мы это проверяем при добавленнии букв.
                                X += SpaceLen + WordLen;

                                Word = false;
                                SpaceLen = 0;

                                WordLen = 0;
                            }
                        }
                    }

                    break;
                }
                case para_PageCount:
                case para_PageNum:
                {
                    if (para_PageCount === ItemType)
                    {
                        var oHdrFtr = Para.Parent.IsHdrFtr(true);
                        if (oHdrFtr)
                            oHdrFtr.Add_PageCountElement(Item);
                    }
                    else if (para_PageNum === ItemType)
                    {
                        var LogicDocument = Para.LogicDocument;
                        var SectionPage   = LogicDocument.Get_SectionPageNumInfo2(Para.Get_AbsolutePage(PRS.Page)).CurPage;

                        Item.Set_Page(SectionPage);
                    }

                    // Если до этого было слово, тогда не надо проверять убирается ли оно, но если стояли пробелы,
                    // тогда мы их учитываем при проверке убирается ли данный элемент, и добавляем только если
                    // данный элемент убирается
                    if (true === Word || WordLen > 0)
                    {
                        // Добавляем длину пробелов до слова + длина самого слова. Не надо проверять
                        // убирается ли слово, мы это проверяем при добавленнии букв.
                        X += SpaceLen + WordLen;

                        Word = false;
                        EmptyLine = false;
						TextOnLine = true;
                        SpaceLen = 0;
                        WordLen = 0;
                    }

                    // Если на строке начиналось какое-то слово, тогда данная строка уже не пустая
                    if (true === StartWord)
                        FirstItemOnLine = false;

                    var PageNumWidth = Item.Get_Width();
                    if (X + SpaceLen + PageNumWidth > XEnd && ( false === FirstItemOnLine || false === Para.Internal_Check_Ranges(ParaLine, ParaRange) ))
                    {
                        // Данный элемент не убирается, ставим перенос перед ним
                        NewRange = true;
                        RangeEndPos = Pos;
                    }
                    else
                    {
                        // Добавляем длину пробелов до слова и ширину данного элемента
                        X += SpaceLen + PageNumWidth;

                        FirstItemOnLine = false;
                        EmptyLine = false;
						TextOnLine = true;
                    }

                    SpaceLen = 0;

                    break;
                }
                case para_Tab:
                {
                    // Сначала проверяем, если у нас уже есть таб, которым мы должны рассчитать, тогда высчитываем
                    // его ширину.

					var isLastTabToRightEdge = PRS.LastTab && -1 !== PRS.LastTab.Value ? PRS.LastTab.TabRightEdge : false;

                    X = this.private_RecalculateLastTab(PRS.LastTab, X, XEnd, Word, WordLen, SpaceLen);

                    // Добавляем длину пробелов до слова + длина самого слова. Не надо проверять
                    // убирается ли слово, мы это проверяем при добавленнии букв.
                    X += SpaceLen + WordLen;
                    Word = false;
                    SpaceLen = 0;
                    WordLen = 0;

                    var TabPos   = Para.private_RecalculateGetTabPos(X, ParaPr, PRS.Page, false);
                    var NewX     = TabPos.NewX;
                    var TabValue = TabPos.TabValue;

                    Item.SetLeader(TabPos.TabLeader);

					PRS.LastTab.TabPos       = NewX;
					PRS.LastTab.Value        = TabValue;
					PRS.LastTab.X            = X;
					PRS.LastTab.Item         = Item;
					PRS.LastTab.TabRightEdge = TabPos.TabRightEdge;

                    // Если таб не левый, значит он не может быть сразу рассчитан, а если левый, тогда
                    // рассчитываем его сразу здесь
                    if (tab_Left !== TabValue)
                    {
						Item.Width        = 0;
						Item.WidthVisible = 0;
                    }
                    else
					{
						// TODO: Если таб расположен между правым полем страницы и правым отступом параграфа (отступ
						// должен быть положительным), то начиная с версии document_compatibility_mode_Word15
						// табы немного неправильно рассчитываются. Смотри файл "Табы. Рассчет табов рядом с правым краем(2016).docx"

						var twX    = AscCommon.MMToTwips(X);
						var twXEnd = AscCommon.MMToTwips(XEnd);
						var twNewX = AscCommon.MMToTwips(NewX);

						var oLogicDocument     = PRS.Paragraph.LogicDocument;
						var nCompatibilityMode = oLogicDocument && oLogicDocument.GetCompatibilityMode ? oLogicDocument.GetCompatibilityMode() : document_compatibility_mode_Current;
						if (nCompatibilityMode <= document_compatibility_mode_Word14
							&& !isLastTabToRightEdge
							&& true !== TabPos.DefaultTab
							&& (twX >= twXEnd && XEnd < 558.7 && PRS.Range >= PRS.RangesCount - 1))
						{
							Para.Lines[PRS.Line].Ranges[PRS.Range].XEnd = 558.7;
							XEnd                                        = 558.7;
							PRS.BadLeftTab                              = true;

							twXEnd = AscCommon.MMToTwips(XEnd);
						}

						if (!PRS.BadLeftTab
							&& (false === FirstItemOnLine || false === Para.Internal_Check_Ranges(ParaLine, ParaRange))
							&& (((TabPos.DefaultTab || PRS.Range < PRS.RangesCount - 1) && twNewX > twXEnd)
							|| (!TabPos.DefaultTab && twNewX > AscCommon.MMToTwips(TabPos.PageXLimit))))
						{
							WordLen     = NewX - X;
							RangeEndPos = Pos;
							NewRange    = true;
						}
						else
						{
							Item.Width        = NewX - X;
							Item.WidthVisible = NewX - X;

							X = NewX;
						}
                    }

					// Считаем, что с таба начинается слово
					PRS.Set_LineBreakPos(Pos, FirstItemOnLine);

                    // Если перенос идет по строке, а не из-за обтекания, тогда разрываем перед табом, а если
                    // из-за обтекания, тогда разрываем перед последним словом, идущим перед табом
                    if (RangesCount === CurRange)
                    {
                        if (true === StartWord)
                        {
                            FirstItemOnLine = false;
                            EmptyLine = false;
							TextOnLine = true;
                        }
                    }


                    StartWord = true;
                    Word = true;

                    break;
                }
                case para_NewLine:
                {
                    // Сначала проверяем, если у нас уже есть таб, которым мы должны рассчитать, тогда высчитываем
                    // его ширину.
                    X = this.private_RecalculateLastTab(PRS.LastTab, X, XEnd, Word, WordLen, SpaceLen);

                    X += WordLen;

                    if (true === Word)
                    {
                        EmptyLine = false;
						TextOnLine = true;
                        Word = false;
                        X += SpaceLen;
                        SpaceLen = 0;
                    }

                    if (break_Page === Item.BreakType || break_Column === Item.BreakType)
                    {
                        PRS.BreakPageLine = true;
                        if (break_Page === Item.BreakType)
                            PRS.BreakRealPageLine = true;

						// Учитываем разрыв страницы/колонки, только если мы находимся в главной части документа, либо
						// во вложенной в нее SdtContent (вложение может быть многоуровневым)
                        var oParent = Para.Parent;
                        while (oParent instanceof CDocumentContent && oParent.IsBlockLevelSdtContent())
							oParent = oParent.GetParent().GetParent();

						if (!(oParent instanceof CDocument) || true !== Para.Is_Inline())
						{
							// TODO: Продумать, как избавиться от данного элемента, т.к. удалять его при пересчете нельзя,
							//       иначе будут проблемы с совместным редактированием.

							Item.Flags.Use = false;
							continue;
						}

						if (break_Page === Item.BreakType && true === Para.Check_BreakPageEnd(Item))
                            continue;

                        Item.Flags.NewLine = true;

                        NewPage       = true;
                        NewRange      = true;
                    }
                    else
                    {
                        NewRange = true;
                        EmptyLine = false;
						TextOnLine = true;

                        // здесь оставляем проверку, т.к. в случае, если после неинлайновой формулы нах-ся инлайновая необходимо в любом случае сделать перенос (проверка в private_RecalculateRange(), где выставляется PRS.ForceNewLine = true не пройдет)
                        if (true === PRS.MathNotInline)
                            PRS.ForceNewLine = true;
                    }

                    RangeEndPos = Pos + 1;

                    break;
                }
                case para_End:
                {
                    if (true === Word)
                    {
                        FirstItemOnLine = false;
                        EmptyLine       = false;
						TextOnLine      = true;
                    }

                    X += WordLen;

                    if (true === Word)
                    {
                        X += SpaceLen;
                        SpaceLen = 0;
                        WordLen  = 0;
                    }

                    X = this.private_RecalculateLastTab(PRS.LastTab, X, XEnd, Word, WordLen, SpaceLen);

                    NewRange = true;
                    End      = true;

                    RangeEndPos = Pos + 1;

                    break;
                }
				case para_FieldChar:
				{
					if (PRS.IsFastRecalculate())
						break;

					Item.SetXY(X + SpaceLen + WordLen, PRS.Y);
					Item.SetPage(Para.Get_AbsolutePage(CurPage));

					Item.SetRun(this);
					PRS.ComplexFields.ProcessFieldCharAndCollectComplexField(Item);

					if (Item.IsSeparate())
					{
						// Специальная ветка, для полей PAGE и NUMPAGES, находящихся в колонтитуле
						var oComplexField = Item.GetComplexField();
						var oHdrFtr       = Para.Parent.IsHdrFtr(true);
						if (oHdrFtr && oComplexField)
						{
							var oInstruction = oComplexField.GetInstruction();
							if (oInstruction && (fieldtype_NUMPAGES === oInstruction.GetType() || fieldtype_PAGE === oInstruction.GetType()))
							{
								if (fieldtype_NUMPAGES === oInstruction.GetType())
								{
									oHdrFtr.Add_PageCountElement(Item);
								}
								else
								{
									var LogicDocument = Para.LogicDocument;
									var SectionPage   = LogicDocument.Get_SectionPageNumInfo2(Para.Get_AbsolutePage(PRS.Page)).CurPage;
									Item.SetNumValue(SectionPage);
								}
							}

							// Если до этого было слово, тогда не надо проверять убирается ли оно, но если стояли пробелы,
							// тогда мы их учитываем при проверке убирается ли данный элемент, и добавляем только если
							// данный элемент убирается
							if (true === Word || WordLen > 0)
							{
								// Добавляем длину пробелов до слова + длина самого слова. Не надо проверять
								// убирается ли слово, мы это проверяем при добавленнии букв.
								X += SpaceLen + WordLen;

								Word = false;
								EmptyLine = false;
								TextOnLine = true;
								SpaceLen = 0;
								WordLen = 0;
							}

							// Если на строке начиналось какое-то слово, тогда данная строка уже не пустая
							if (true === StartWord)
								FirstItemOnLine = false;

							var PageNumWidth = Item.Get_Width();
							if (X + SpaceLen + PageNumWidth > XEnd && ( false === FirstItemOnLine || false === Para.Internal_Check_Ranges(ParaLine, ParaRange) ))
							{
								// Данный элемент не убирается, ставим перенос перед ним
								NewRange = true;
								RangeEndPos = Pos;
							}
							else
							{
								// Добавляем длину пробелов до слова и ширину данного элемента
								X += SpaceLen + PageNumWidth;

								FirstItemOnLine = false;
								EmptyLine = false;
								TextOnLine = true;
							}

							SpaceLen = 0;
						}
						else
						{
							Item.SetNumValue(null);
						}
					}

					break;
				}
				case para_InstrText:
				{
					if (PRS.IsFastRecalculate())
						break;

					PRS.ComplexFields.ProcessInstruction(Item);

					break;
				}
            }

            if (para_Space !== ItemType)
            	PRS.LastItem = Item;

            if (true === NewRange)
                break;
        }
    }


    PRS.MoveToLBP       = MoveToLBP;
    PRS.NewRange        = NewRange;
    PRS.ForceNewPage    = ForceNewPage;
    PRS.NewPage         = NewPage;
    PRS.End             = End;

    PRS.Word            = Word;
    PRS.StartWord       = StartWord;
    PRS.FirstItemOnLine = FirstItemOnLine;
    PRS.EmptyLine       = EmptyLine;
    PRS.TextOnLine      = TextOnLine;

    PRS.SpaceLen        = SpaceLen;
    PRS.WordLen         = WordLen;
    PRS.bMathWordLarge  = bMathWordLarge;
    PRS.OperGapRight    = OperGapRight;
    PRS.OperGapLeft     = OperGapLeft;

    PRS.X               = X;
    PRS.XEnd            = XEnd;

    PRS.bInsideOper         = bInsideOper;
    PRS.bContainCompareOper = bContainCompareOper;
    PRS.bEndRunToContent    = bEndRunToContent;
    PRS.bNoOneBreakOperator = bNoOneBreakOperator;
    PRS.bForcedBreak        = bForcedBreak;


    if(this.Type == para_Math_Run)
    {
        if(true === NewRange)
        {
            var WidthLine = X - XRange;

            if(this.ParaMath.Is_BrkBinBefore() == false)
                WidthLine += SpaceLen;

            this.ParaMath.UpdateWidthLine(PRS, WidthLine);
        }
        else
        {
            // для пустого Run, обновляем LineBreakPos на случай, если пустой Run находится между break_operator (мат. объект) и мат объектом
            if(this.Content.length == 0)
            {
                if(PRS.bForcedBreak == true)
                {
                    PRS.MoveToLBP = true;
                    PRS.NewRange = true;
                    PRS.Set_LineBreakPos(0, PRS.FirstItemOnLine);
                }
                else if(this.ParaMath.Is_BrkBinBefore() == false && Word == false && PRS.bBreakBox == true)
                {
                    PRS.Set_LineBreakPos(Pos, PRS.FirstItemOnLine);
                    PRS.X += SpaceLen;
                    PRS.SpaceLen = 0;
                }
            }

            // запоминаем конец Run
            PRS.PosEndRun.Set(PRS.CurPos);
            PRS.PosEndRun.Update2(this.Content.length, Depth);

        }
    }

    if ( Pos >= ContentLen )
    {
        RangeEndPos = Pos;
    }

    this.protected_FillRange(CurLine, CurRange, RangeStartPos, RangeEndPos);

    this.RecalcInfo.Recalc = false;
};

ParaRun.prototype.Recalculate_Set_RangeEndPos = function(PRS, PRP, Depth)
{
    var CurLine  = PRS.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range );
    var CurPos   = PRP.Get(Depth);

    this.protected_FillRangeEndPos(CurLine, CurRange, CurPos);
};

ParaRun.prototype.Recalculate_LineMetrics = function(PRS, ParaPr, _CurLine, _CurRange, ContentMetrics)
{
	var Para = PRS.Paragraph;

	// Если заданный отрезок пустой, тогда мы не должны учитывать метрики данного рана.

	var CurLine  = _CurLine - this.StartLine;
	var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

	var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
	var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

	var UpdateLineMetricsText = false;
	var LineRule              = ParaPr.Spacing.LineRule;

	for (var CurPos = StartPos; CurPos < EndPos; CurPos++)
	{
		var Item = this.private_CheckInstrText(this.Content[CurPos]);

		if (Item === Para.Numbering.Item)
		{
			PRS.LineAscent = Para.Numbering.LineAscent;
		}

		switch (Item.Type)
		{
			case para_Sym:
			case para_Text:
			case para_PageNum:
			case para_PageCount:
			case para_FootnoteReference:
			case para_FootnoteRef:
			case para_Separator:
			case para_ContinuationSeparator:
			{
				UpdateLineMetricsText = true;
				break;
			}
			case para_Math_Text:
			case para_Math_Ampersand:
			case para_Math_Placeholder:
			case para_Math_BreakOperator:
			{
				ContentMetrics.UpdateMetrics(Item.size);

				break;
			}
			case para_Space:
			{
				break;
			}
			case para_Drawing:
			{
				if (true === Item.Is_Inline() || true === Para.Parent.Is_DrawingShape())
				{
					// Обновим метрики строки
					if (Asc.linerule_Exact === LineRule)
					{
						if (PRS.LineAscent < Item.Height)
							PRS.LineAscent = Item.Height;
					}
					else
					{
						if (PRS.LineAscent < Item.Height + this.YOffset)
							PRS.LineAscent = Item.Height + this.YOffset;

						if (PRS.LineDescent < -this.YOffset)
							PRS.LineDescent = -this.YOffset;
					}
				}

				break;
			}

			case para_End:
			{
				break;
			}
			case para_FieldChar:
			{
				if (Item.IsNumValue())
					UpdateLineMetricsText = true;

				break;
			}
		}
	}

	if (true === UpdateLineMetricsText)
	{
		// Пересчитаем метрику строки относительно размера данного текста
		if (PRS.LineTextAscent < this.TextAscent)
			PRS.LineTextAscent = this.TextAscent;

		if (PRS.LineTextAscent2 < this.TextAscent2)
			PRS.LineTextAscent2 = this.TextAscent2;

		if (PRS.LineTextDescent < this.TextDescent)
			PRS.LineTextDescent = this.TextDescent;

		if (Asc.linerule_Exact === LineRule)
		{
			// Смещение не учитывается в метриках строки, когда расстояние между строк точное
			if (PRS.LineAscent < this.TextAscent)
				PRS.LineAscent = this.TextAscent;

			if (PRS.LineDescent < this.TextDescent)
				PRS.LineDescent = this.TextDescent;
		}
		else
		{
			if (PRS.LineAscent < this.TextAscent + this.YOffset)
				PRS.LineAscent = this.TextAscent + this.YOffset;

			if (PRS.LineDescent < this.TextDescent - this.YOffset)
				PRS.LineDescent = this.TextDescent - this.YOffset;
		}
	}
};

ParaRun.prototype.Recalculate_Range_Width = function(PRSC, _CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var Pos = StartPos; Pos < EndPos; Pos++ )
    {
		var Item = this.private_CheckInstrText(this.Content[Pos]);
        var ItemType = Item.Type;

		if (PRSC.ComplexFields.IsHiddenFieldContent() && para_End !== ItemType && para_FieldChar !== ItemType)
			continue;

		switch( ItemType )
        {
            case para_Sym:
            case para_Text:
            case para_FootnoteReference:
            case para_FootnoteRef:
            case para_Separator:
            case para_ContinuationSeparator:
            {
                PRSC.Letters++;

                if ( true !== PRSC.Word )
                {
                    PRSC.Word = true;
                    PRSC.Words++;
                }

                PRSC.Range.W += Item.Width / TEXTWIDTH_DIVIDER;//Item.Get_Width();
                PRSC.Range.W += PRSC.SpaceLen;

                PRSC.SpaceLen = 0;

                // Пробелы перед первым словом в строке не считаем
                if (PRSC.Words > 1)
                    PRSC.Spaces += PRSC.SpacesCount;
                else
                    PRSC.SpacesSkip += PRSC.SpacesCount;

                PRSC.SpacesCount = 0;

                // Если текущий символ, например, дефис, тогда на нем заканчивается слово
                if (Item.Flags & PARATEXT_FLAGS_SPACEAFTER)//if ( true === Item.IsSpaceAfter() )
                    PRSC.Word = false;

                break;
            }
            case para_Math_Text:
            case para_Math_Placeholder:
            case para_Math_Ampersand:
            case para_Math_BreakOperator:
            {
                PRSC.Letters++;

                PRSC.Range.W += Item.Get_Width() / TEXTWIDTH_DIVIDER; // Get_Width рассчитываем ширину с учетом состояний Gaps
                break;
            }
            case para_Space:
            {
                if ( true === PRSC.Word )
                {
                    PRSC.Word        = false;
                    PRSC.SpacesCount = 1;
                    PRSC.SpaceLen    = Item.Width / TEXTWIDTH_DIVIDER;//Item.Get_Width();
                }
                else
                {
                    PRSC.SpacesCount++;
                    PRSC.SpaceLen += Item.Width / TEXTWIDTH_DIVIDER;//Item.Get_Width();
                }

                break;
            }
            case para_Drawing:
            {
                PRSC.Words++;
                PRSC.Range.W += PRSC.SpaceLen;

                if (PRSC.Words > 1)
                    PRSC.Spaces += PRSC.SpacesCount;
                else
                    PRSC.SpacesSkip += PRSC.SpacesCount;

                PRSC.Word        = false;
                PRSC.SpacesCount = 0;
                PRSC.SpaceLen    = 0;

                if ( true === Item.Is_Inline() || true === PRSC.Paragraph.Parent.Is_DrawingShape() )
                    PRSC.Range.W += Item.Get_Width();

                break;
            }
            case para_PageNum:
            case para_PageCount:
            {
                PRSC.Words++;
                PRSC.Range.W += PRSC.SpaceLen;

                if (PRSC.Words > 1)
                    PRSC.Spaces += PRSC.SpacesCount;
                else
                    PRSC.SpacesSkip += PRSC.SpacesCount;

                PRSC.Word        = false;
                PRSC.SpacesCount = 0;
                PRSC.SpaceLen    = 0;

                PRSC.Range.W += Item.Get_Width();

                break;
            }
            case para_Tab:
            {
                PRSC.Range.W += Item.Get_Width();
                PRSC.Range.W += PRSC.SpaceLen;

				// Учитываем только слова и пробелы, идущие после последнего таба

				PRSC.LettersSkip += PRSC.Letters;
                PRSC.SpacesSkip  += PRSC.Spaces;

                PRSC.Words   = 0;
                PRSC.Spaces  = 0;
                PRSC.Letters = 0;

                PRSC.SpaceLen    = 0;
                PRSC.SpacesCount = 0;
                PRSC.Word        = false;

                break;
            }

            case para_NewLine:
            {
                if (true === PRSC.Word && PRSC.Words > 1)
                    PRSC.Spaces += PRSC.SpacesCount;

                PRSC.SpacesCount = 0;
                PRSC.Word        = false;

                PRSC.Range.WBreak = Item.Get_WidthVisible();

                break;
            }
            case para_End:
            {
                if ( true === PRSC.Word )
                    PRSC.Spaces += PRSC.SpacesCount;

				PRSC.Range.WEnd = Item.Get_WidthVisible();

                break;
            }
			case para_FieldChar:
			{
				PRSC.ComplexFields.ProcessFieldChar(Item);

				if (Item.IsNumValue())
				{
					PRSC.Words++;
					PRSC.Range.W += PRSC.SpaceLen;

					if (PRSC.Words > 1)
						PRSC.Spaces += PRSC.SpacesCount;
					else
						PRSC.SpacesSkip += PRSC.SpacesCount;

					PRSC.Word        = false;
					PRSC.SpacesCount = 0;
					PRSC.SpaceLen    = 0;

					PRSC.Range.W += Item.Get_Width();
				}

				break;
			}
        }
    }
};

ParaRun.prototype.Recalculate_Range_Spaces = function(PRSA, _CurLine, _CurRange, CurPage)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var Pos = StartPos; Pos < EndPos; Pos++ )
    {
		var Item = this.private_CheckInstrText(this.Content[Pos]);
        var ItemType = Item.Type;

		if (PRSA.ComplexFields.IsHiddenFieldContent() && para_End !== ItemType && para_FieldChar !== ItemType)
		{
			// Чтобы правильно позиционировался курсор и селект
			Item.WidthVisible = 0;
			continue;
		}

		switch( ItemType )
        {
            case para_Sym:
            case para_Text:
            case para_FootnoteReference:
            case para_FootnoteRef:
            case para_Separator:
            case para_ContinuationSeparator:
            {
                var WidthVisible = 0;

                if ( 0 !== PRSA.LettersSkip )
                {
                    WidthVisible = Item.Width / TEXTWIDTH_DIVIDER;//WidthVisible = Item.Get_Width();
                    PRSA.LettersSkip--;
                }
                else
                    WidthVisible = Item.Width / TEXTWIDTH_DIVIDER + PRSA.JustifyWord;//WidthVisible = Item.Get_Width() + PRSA.JustifyWord;

                Item.WidthVisible = (WidthVisible * TEXTWIDTH_DIVIDER) | 0;//Item.Set_WidthVisible(WidthVisible);

				if (para_FootnoteReference === ItemType)
				{
					var oFootnote = Item.Get_Footnote();
					oFootnote.UpdatePositionInfo(this.Paragraph, this, _CurLine, _CurRange, PRSA.X, WidthVisible);
				}

                PRSA.X    += WidthVisible;
                PRSA.LastW = WidthVisible;

                break;
            }
            case para_Math_Text:
            case para_Math_Placeholder:
            case para_Math_BreakOperator:
            case para_Math_Ampersand:
            {
                var WidthVisible = Item.Get_Width() / TEXTWIDTH_DIVIDER; // Get_Width рассчитываем ширину с учетом состояний Gaps
                Item.WidthVisible = (WidthVisible * TEXTWIDTH_DIVIDER)| 0;//Item.Set_WidthVisible(WidthVisible);

                PRSA.X    += WidthVisible;
                PRSA.LastW = WidthVisible;

                break;
            }
            case para_Space:
            {
                var WidthVisible = Item.Width / TEXTWIDTH_DIVIDER;//WidthVisible = Item.Get_Width();

                if ( 0 !== PRSA.SpacesSkip )
                {
                    PRSA.SpacesSkip--;
                }
                else if ( 0 !== PRSA.SpacesCounter )
                {
                    WidthVisible += PRSA.JustifySpace;
                    PRSA.SpacesCounter--;
                }

                Item.WidthVisible = (WidthVisible * TEXTWIDTH_DIVIDER) | 0;//Item.Set_WidthVisible(WidthVisible);

                PRSA.X    += WidthVisible;
                PRSA.LastW = WidthVisible;

                break;
            }
            case para_Drawing:
            {
                var Para = PRSA.Paragraph;
                var PageAbs = Para.private_GetAbsolutePageIndex(CurPage);
                var PageRel = Para.private_GetRelativePageIndex(CurPage);
                var ColumnAbs = Para.Get_AbsoluteColumn(CurPage);

                var LogicDocument = this.Paragraph.LogicDocument;
                var LD_PageLimits = LogicDocument.Get_PageLimits(PageAbs);
                var LD_PageFields = LogicDocument.Get_PageFields(PageAbs);

                var Page_Width  = LD_PageLimits.XLimit;
                var Page_Height = LD_PageLimits.YLimit;

                var DrawingObjects = Para.Parent.DrawingObjects;
                var PageLimits     = Para.Parent.Get_PageLimits(PageRel);
                var PageFields     = Para.Parent.Get_PageFields(PageRel);

                var X_Left_Field   = PageFields.X;
                var Y_Top_Field    = PageFields.Y;
                var X_Right_Field  = PageFields.XLimit;
                var Y_Bottom_Field = PageFields.YLimit;

                var X_Left_Margin   = PageFields.X - PageLimits.X;
                var Y_Top_Margin    = PageFields.Y - PageLimits.Y;
                var X_Right_Margin  = PageLimits.XLimit - PageFields.XLimit;
                var Y_Bottom_Margin = PageLimits.YLimit - PageFields.YLimit;

                if (true === Para.Parent.IsTableCellContent() && (true !== Item.Use_TextWrap() || false === Item.IsLayoutInCell()))
                {
                    X_Left_Field   = LD_PageFields.X;
                    Y_Top_Field    = LD_PageFields.Y;
                    X_Right_Field  = LD_PageFields.XLimit;
                    Y_Bottom_Field = LD_PageFields.YLimit;

                    X_Left_Margin   = X_Left_Field;
                    X_Right_Margin  = Page_Width  - X_Right_Field;
                    Y_Bottom_Margin = Page_Height - Y_Bottom_Field;
                    Y_Top_Margin    = Y_Top_Field;
                }

               	var _CurPage = 0;
				if (0 !== PageAbs && CurPage > ColumnAbs)
					_CurPage = CurPage - ColumnAbs;

				var ColumnStartX = (0 === CurPage ? Para.X_ColumnStart : Para.Pages[_CurPage].X     );
				var ColumnEndX   = (0 === CurPage ? Para.X_ColumnEnd   : Para.Pages[_CurPage].XLimit);

                var Top_Margin    = Y_Top_Margin;
                var Bottom_Margin = Y_Bottom_Margin;
                var Page_H        = Page_Height;

                if ( true === Para.Parent.IsTableCellContent() && true == Item.Use_TextWrap() )
                {
                    Top_Margin    = 0;
                    Bottom_Margin = 0;
                    Page_H        = 0;
                }

                var PageLimitsOrigin = Para.Parent.Get_PageLimits(PageRel);
                if (true === Para.Parent.IsTableCellContent() && false === Item.IsLayoutInCell())
                {
                    PageLimitsOrigin = LogicDocument.Get_PageLimits(PageAbs);
                    var PageFieldsOrigin = LogicDocument.Get_PageFields(PageAbs);
                    ColumnStartX = PageFieldsOrigin.X;
                    ColumnEndX   = PageFieldsOrigin.XLimit;
                }

                if ( true != Item.Use_TextWrap() )
                {
                    PageFields.X      = X_Left_Field;
                    PageFields.Y      = Y_Top_Field;
                    PageFields.XLimit = X_Right_Field;
                    PageFields.YLimit = Y_Bottom_Field;

                    PageLimits.X = 0;
                    PageLimits.Y = 0;
                    PageLimits.XLimit = Page_Width;
                    PageLimits.YLimit = Page_Height;
                }

                if ( true === Item.Is_Inline() || true === Para.Parent.Is_DrawingShape() )
                {
                	if (linerule_Exact === Para.Get_CompiledPr2(false).ParaPr.Spacing.LineRule)
					{
						var LineTop    = Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent;
						var LineBottom = Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Descent;
						Item.SetVerticalClip(LineTop, LineBottom);
					}
					else
					{
						Item.SetVerticalClip(null, null);
					}

                    Item.Update_Position(PRSA.Paragraph, new CParagraphLayout( PRSA.X, PRSA.Y , PageAbs, PRSA.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent, Para.Pages[CurPage].Y), PageLimits, PageLimitsOrigin, _CurLine);
                    Item.Reset_SavedPosition();

                    PRSA.X    += Item.WidthVisible;
                    PRSA.LastW = Item.WidthVisible;
                }
                else if (!Item.IsSkipOnRecalculate())
                {
                    Para.Pages[CurPage].Add_Drawing(Item);

                    if ( true === PRSA.RecalcFast )
                    {
                        // Если у нас быстрый пересчет, тогда мы не трогаем плавающие картинки
                        // TODO: Если здесь привязка к символу, тогда быстрый пересчет надо отменить
                        break;
                    }

                    if (true === PRSA.RecalcFast2)
                    {
                        // Тут мы должны сравнить положение картинок
                        var oRecalcObj = Item.SaveRecalculateObject();
                        Item.Update_Position(PRSA.Paragraph, new CParagraphLayout( PRSA.X, PRSA.Y , PageAbs, PRSA.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent, Para.Pages[_CurPage].Y), PageLimits, PageLimitsOrigin, _CurLine);

                        if (Math.abs(Item.X - oRecalcObj.X) > 0.001 || Math.abs(Item.Y - oRecalcObj.Y) > 0.001 || Item.PageNum !== oRecalcObj.PageNum)
                        {
                            // Положение картинок не совпало, отправляем пересчет текущей страницы.
                            PRSA.RecalcResult = recalcresult_CurPage | recalcresultflags_Page;
                            return;
                        }

                        break;
                    }

                    // У нас Flow-объект. Если он с обтеканием, тогда мы останавливаем пересчет и
                    // запоминаем текущий объект. В функции Internal_Recalculate_2 пересчитываем
                    // его позицию и сообщаем ее внешнему классу.

                    if ( true === Item.Use_TextWrap() )
                    {
                        var LogicDocument = Para.Parent;
                        var LDRecalcInfo  = Para.Parent.RecalcInfo;
                        if ( true === LDRecalcInfo.Can_RecalcObject() )
                        {
                            // Обновляем позицию объекта
                            Item.Update_Position(PRSA.Paragraph, new CParagraphLayout( PRSA.X, PRSA.Y , PageAbs, PRSA.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent, Para.Pages[_CurPage].Y), PageLimits, PageLimitsOrigin, _CurLine);
                            LDRecalcInfo.Set_FlowObject( Item, 0, recalcresult_NextElement, -1 );

                            // TODO: Добавить проверку на не попадание в предыдущие колонки
                            if (0 === PRSA.CurPage && Item.wrappingPolygon.top > PRSA.PageY + 0.001 && Item.wrappingPolygon.left > PRSA.PageX + 0.001)
                                PRSA.RecalcResult = recalcresult_CurPagePara;
                            else
                                PRSA.RecalcResult = recalcresult_CurPage | recalcresultflags_Page;

                            return;
                        }
                        else if ( true === LDRecalcInfo.Check_FlowObject(Item) )
                        {
                            // Если мы находимся с таблице, тогда делаем как Word, не пересчитываем предыдущую страницу,
                            // даже если это необходимо. Такое поведение нужно для точного определения рассчиталась ли
                            // данная страница окончательно или нет. Если у нас будет ветка с переходом на предыдущую страницу,
                            // тогда не рассчитав следующую страницу мы о конечном рассчете текущей страницы не узнаем.

                            // Если данный объект нашли, значит он уже был рассчитан и нам надо проверить номер страницы.
                            // Заметим, что даже если картинка привязана к колонке, и после пересчета место привязки картинки
                            // сдвигается в следующую колонку, мы проверяем все равно только реальную страницу (без
                            // учета колонок, так делает и Word).
                            if ( Item.PageNum === PageAbs )
                            {
                                // Все нормально, можно продолжить пересчет
                                LDRecalcInfo.Reset();
                                Item.Reset_SavedPosition();
                            }
                            else if ( true === Para.Parent.IsTableCellContent() )
                            {
                                // Картинка не на нужной странице, но так как это таблица
                                // мы пересчитываем заново текущую страницу, а не предыдущую

                                // Обновляем позицию объекта
                                Item.Update_Position(PRSA.Paragraph, new CParagraphLayout( PRSA.X, PRSA.Y, PageAbs, PRSA.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent, Para.Pages[_CurPage].Y), PageLimits, PageLimitsOrigin, _CurLine);

                                LDRecalcInfo.Set_FlowObject( Item, 0, recalcresult_NextElement, -1 );
                                LDRecalcInfo.Set_PageBreakBefore( false );
                                PRSA.RecalcResult = recalcresult_CurPage | recalcresultflags_Page;
                                return;
                            }
                            else
                            {
                                LDRecalcInfo.Set_PageBreakBefore( true );
                                DrawingObjects.removeById( Item.PageNum, Item.Get_Id() );
                                PRSA.RecalcResult = recalcresult_PrevPage | recalcresultflags_Page;
                                return;
                            }
                        }
                        else
                        {
                            // Либо данный элемент уже обработан, либо будет обработан в будущем
                        }

                        continue;
                    }
                    else
					{
						// Картинка ложится на или под текст, в данном случае пересчет можно спокойно продолжать
						Item.Update_Position(PRSA.Paragraph, new CParagraphLayout(PRSA.X, PRSA.Y, PageAbs, PRSA.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent, Para.Pages[_CurPage].Y), PageLimits, PageLimitsOrigin, _CurLine);
						Item.Reset_SavedPosition();
					}
                }


                break;
            }
            case para_PageNum:
            case para_PageCount:
            {
                PRSA.X    += Item.WidthVisible;
                PRSA.LastW = Item.WidthVisible;

                break;
            }
            case para_Tab:
            {
                PRSA.X += Item.WidthVisible;

                break;
            }
            case para_End:
            {
                var SectPr = PRSA.Paragraph.Get_SectionPr();
                if (!PRSA.Paragraph.LogicDocument || PRSA.Paragraph.LogicDocument !== PRSA.Paragraph.Parent || !PRSA.Paragraph.bFromDocument)
                    SectPr = undefined;

                if ( undefined !== SectPr )
                {
                    // Нас интересует следующая секция
                    var LogicDocument = PRSA.Paragraph.LogicDocument;
                    var NextSectPr = LogicDocument.SectionsInfo.Get_SectPr(PRSA.Paragraph.Index + 1).SectPr;

                    Item.Update_SectionPr(NextSectPr, PRSA.XEnd - PRSA.X);
                }
                else
                    Item.Clear_SectionPr();

                PRSA.X += Item.Get_Width();

                break;
            }
            case para_NewLine:
            {
				if (break_Page === Item.BreakType || break_Column === Item.BreakType)
					Item.Update_String(PRSA.XEnd - PRSA.X);

                PRSA.X += Item.WidthVisible;

                break;
            }
			case para_FieldChar:
			{
				PRSA.ComplexFields.ProcessFieldChar(Item);

				if (Item.IsNumValue())
				{
					PRSA.X    += Item.WidthVisible;
					PRSA.LastW = Item.WidthVisible;
				}

				break;
			}

        }
    }
};

ParaRun.prototype.Recalculate_PageEndInfo = function(PRSI, _CurLine, _CurRange)
{
	var CurLine  = _CurLine - this.StartLine;
	var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

	var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
	var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

	for (var Pos = StartPos; Pos < EndPos; ++Pos)
	{
		var Item = this.Content[Pos];
		if (para_FieldChar === Item.Type)
		{
			PRSI.ProcessFieldChar(Item);
		}
	}
};

ParaRun.prototype.private_RecalculateNumbering = function(PRS, Item, ParaPr, _X)
{
    var X = PRS.Recalculate_Numbering(Item, this, ParaPr, _X);

    // Запоминаем, что на данном элементе была добавлена нумерация
    this.RecalcInfo.NumberingAdd  = false;
    this.RecalcInfo.NumberingUse  = true;
    this.RecalcInfo.NumberingItem = PRS.Paragraph.Numbering;

    return X;
};

ParaRun.prototype.private_RecalculateLastTab = function(LastTab, X, XEnd, Word, WordLen, SpaceLen)
{
	if (tab_Left === LastTab.Value)
	{
		LastTab.Reset();
	}
    else if ( -1 !== LastTab.Value )
    {
        var TempXPos = X;

        if ( true === Word || WordLen > 0 )
            TempXPos += SpaceLen + WordLen;

        var TabItem   = LastTab.Item;
        var TabStartX = LastTab.X;
        var TabRangeW = TempXPos - TabStartX;
        var TabValue  = LastTab.Value;
        var TabPos    = LastTab.TabPos;

		var oLogicDocument     = this.Paragraph ? this.Paragraph.LogicDocument : null;
		var nCompatibilityMode = oLogicDocument && oLogicDocument.GetCompatibilityMode ? oLogicDocument.GetCompatibilityMode() : document_compatibility_mode_Current;

		if (AscCommon.MMToTwips(TabPos) > AscCommon.MMToTwips(XEnd) && nCompatibilityMode >= document_compatibility_mode_Word15)
		{
			TabValue = tab_Right;
			TabPos   = XEnd;
		}

        var TabCalcW = 0;
        if ( tab_Right === TabValue )
            TabCalcW = Math.max( TabPos - (TabStartX + TabRangeW), 0 );
        else if ( tab_Center === TabValue )
            TabCalcW = Math.max( TabPos - (TabStartX + TabRangeW / 2), 0 );

        if ( X + TabCalcW > LastTab.PageXLimit )
            TabCalcW = LastTab.PageXLimit - X;

        TabItem.Width        = TabCalcW;
        TabItem.WidthVisible = TabCalcW;

        LastTab.Reset();

        return X + TabCalcW;
    }

    return X;
};
/**
 * Специальная функия для проверки InstrText. Если InstrText идет не между Begin и Separate сложного поля, тогда
 * мы заменяем его обычным текстовым элементом.
 * @param oItem
 */
ParaRun.prototype.private_CheckInstrText = function(oItem)
{
	if (!oItem)
		return oItem;

	if (para_InstrText !== oItem.Type)
		return oItem;

	var oReplacement = oItem.GetReplacementItem();
	return (oReplacement ? oReplacement : oItem);
};

ParaRun.prototype.Refresh_RecalcData = function(oData)
{
	var oPara = this.Paragraph;

	if (this.Type == para_Math_Run)
	{
		if (this.Parent !== null && this.Parent !== undefined)
		{
			this.Parent.Refresh_RecalcData();
		}
	}
	else if (-1 !== this.StartLine && oPara)
	{
		var nCurLine = this.StartLine;

		if (oData instanceof CChangesRunAddItem || oData instanceof CChangesRunRemoveItem)
		{
			nCurLine = -1;
			var nChangePos = oData.GetMinPos();
			for (var nLine = 0, nLinesCount = this.protected_GetLinesCount(); nLine < nLinesCount; ++nLine)
			{
				for (var nRange = 0, nRangesCount = this.protected_GetRangesCount(nLine); nRange < nRangesCount; ++nRange)
				{
					var nStartPos = this.protected_GetRangeStartPos(nLine, nRange);
					var nEndPos   = this.protected_GetRangeEndPos(nLine, nRange);

					if (nStartPos <= nChangePos && nChangePos < nEndPos)
					{
						nCurLine = nLine + this.StartLine;
						break;
					}
				}

				if (-1 !== nCurLine)
					break;
			}

			if (-1 === nCurLine)
				nCurLine = this.StartLine + this.protected_GetLinesCount() - 1;
		}

		for (var nCurPage = 0, nPagesCount = oPara.GetPagesCount(); nCurPage < nPagesCount; ++nCurPage)
		{
			var oPage = oPara.Pages[nCurPage];
			if (oPage.StartLine <= nCurLine && nCurLine <= oPage.EndLine)
			{
				oPara.Refresh_RecalcData2(nCurPage);
				return;
			}

		}

		oPara.Refresh_RecalcData2(0);
	}
};
ParaRun.prototype.Refresh_RecalcData2 = function()
{
	this.Refresh_RecalcData();
};
ParaRun.prototype.SaveRecalculateObject = function(Copy)
{
    var RecalcObj = new CRunRecalculateObject(this.StartLine, this.StartRange);
    RecalcObj.Save_Lines( this, Copy );
    RecalcObj.Save_RunContent( this, Copy );
    return RecalcObj;
};
ParaRun.prototype.LoadRecalculateObject = function(RecalcObj)
{
    RecalcObj.Load_Lines(this);
    RecalcObj.Load_RunContent(this);
};
ParaRun.prototype.PrepareRecalculateObject = function()
{
	this.protected_ClearLines();

	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		var Item     = this.Content[Index];
		var ItemType = Item.Type;

		if (para_PageNum === ItemType || para_Drawing === ItemType)
			Item.PrepareRecalculateObject();
	}
};
ParaRun.prototype.Is_EmptyRange = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    if ( EndPos <= StartPos )
        return true;

    return false;
};

ParaRun.prototype.Check_Range_OnlyMath = function(Checker, _CurRange, _CurLine)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for (var Pos = StartPos; Pos < EndPos; Pos++)
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        if (para_End === ItemType || para_NewLine === ItemType || (para_Drawing === ItemType && true !== Item.Is_Inline()))
            continue;
        else
        {
            Checker.Result = false;
            Checker.Math   = null;
            break;
        }
    }
};

ParaRun.prototype.Check_MathPara = function(Checker)
{
    var Count = this.Content.length;
    if ( Count <= 0 )
        return;

    var Item = ( Checker.Direction > 0 ? this.Content[0] : this.Content[Count - 1] );
    var ItemType = Item.Type;

    if ( para_End === ItemType || para_NewLine === ItemType )
    {
        Checker.Result = true;
        Checker.Found  = true;
    }
    else
    {
        Checker.Result = false;
        Checker.Found  = true;
    }
};

ParaRun.prototype.Check_PageBreak = function()
{
    var Count = this.Content.length;
    for (var Pos = 0; Pos < Count; Pos++)
    {
        var Item = this.Content[Pos];
        if (para_NewLine === Item.Type && (break_Page === Item.BreakType || break_Column === Item.BreakType))
            return true;
    }

    return false;
};

ParaRun.prototype.Check_BreakPageEnd = function(PBChecker)
{
    var ContentLen = this.Content.length;
    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        var Item = this.Content[CurPos];

        if ( true === PBChecker.FindPB )
        {
            if ( Item === PBChecker.PageBreak )
            {
                PBChecker.FindPB = false;
                PBChecker.PageBreak.Flags.NewLine = true;
            }
        }
        else
        {
            var ItemType = Item.Type;

            if ( para_End === ItemType )
                return true;
            else if ( para_Drawing !== ItemType || drawing_Anchor !== Item.Get_DrawingType() )
                return false;
        }
    }

    return true;
};

ParaRun.prototype.RecalculateMinMaxContentWidth = function(MinMax)
{
    this.Recalculate_MeasureContent();

    var bWord        = MinMax.bWord;
    var nWordLen     = MinMax.nWordLen;
    var nSpaceLen    = MinMax.nSpaceLen;
    var nMinWidth    = MinMax.nMinWidth;
    var nMaxWidth    = MinMax.nMaxWidth;
    var nCurMaxWidth = MinMax.nCurMaxWidth;
    var nMaxHeight   = MinMax.nMaxHeight;

    var bCheckTextHeight = false;
    var Count = this.Content.length;
    for ( var Pos = 0; Pos < Count; Pos++ )
    {
		var Item     = this.private_CheckInstrText(this.Content[Pos]);
        var ItemType = Item.Type;

        switch( ItemType )
        {
            case para_Text:
            {
                var ItemWidth = Item.Width / TEXTWIDTH_DIVIDER;//var ItemWidth = Item.Get_Width();
                if ( false === bWord )
                {
                    bWord    = true;
                    nWordLen = ItemWidth;
                }
                else
                {
                    nWordLen += ItemWidth;

                    if (Item.Flags & PARATEXT_FLAGS_SPACEAFTER)
                    {
                        if ( nMinWidth < nWordLen )
                            nMinWidth = nWordLen;

                        bWord    = false;
                        nWordLen = 0;
                    }
                }

                if ( nSpaceLen > 0 )
                {
                    nCurMaxWidth += nSpaceLen;
                    nSpaceLen     = 0;
                }

                nCurMaxWidth += ItemWidth;
                bCheckTextHeight = true;
                break;
            }
            case para_Math_Text:
            case para_Math_Ampersand:
            case para_Math_Placeholder:
            {
                var ItemWidth = Item.Get_Width() / TEXTWIDTH_DIVIDER;
                if ( false === bWord )
                {
                    bWord    = true;
                    nWordLen = ItemWidth;
                }
                else
                {
                    nWordLen += ItemWidth;
                }

                nCurMaxWidth += ItemWidth;
                bCheckTextHeight = true;
                break;
            }
            case para_Space:
            {
                if ( true === bWord )
                {
                    if ( nMinWidth < nWordLen )
                        nMinWidth = nWordLen;

                    bWord    = false;
                    nWordLen = 0;
                }

                // Мы сразу не добавляем ширину пробелов к максимальной ширине, потому что
                // пробелы, идущие в конце параграфа или перед переносом строки(явным), не
                // должны учитываться.
                nSpaceLen += Item.Width / TEXTWIDTH_DIVIDER;//nSpaceLen += Item.Get_Width();
                bCheckTextHeight = true;
                break;
            }
            case para_Math_BreakOperator:
            {
                if ( true === bWord )
                {
                    if ( nMinWidth < nWordLen )
                        nMinWidth = nWordLen;

                    bWord    = false;
                    nWordLen = 0;
                }

                nCurMaxWidth += Item.Get_Width() / TEXTWIDTH_DIVIDER;
                bCheckTextHeight = true;
                break;
            }

            case para_Drawing:
            {
                if ( true === bWord )
                {
                    if ( nMinWidth < nWordLen )
                        nMinWidth = nWordLen;

                    bWord    = false;
                    nWordLen = 0;
                }

                if ((true === Item.Is_Inline() || true === this.Paragraph.Parent.Is_DrawingShape()) && Item.Width > nMinWidth)
                {
                    nMinWidth = Item.Width;
                }
                else if (true === Item.Use_TextWrap())
                {
                    var DrawingW = Item.getXfrmExtX();
                    if (DrawingW > nMinWidth)
                        nMinWidth = DrawingW;
                }

                if ((true === Item.Is_Inline() || true === this.Paragraph.Parent.Is_DrawingShape()) && Item.Height > nMaxHeight)
                {
                    nMaxHeight = Item.Height;
                }
                else if (true === Item.Use_TextWrap())
                {
                    var DrawingH = Item.getXfrmExtY();
                    if (DrawingH > nMaxHeight)
                        nMaxHeight = DrawingH;
                }

                if ( nSpaceLen > 0 )
                {
                    nCurMaxWidth += nSpaceLen;
                    nSpaceLen     = 0;
                }

                if ( true === Item.Is_Inline() || true === this.Paragraph.Parent.Is_DrawingShape() )
                    nCurMaxWidth += Item.Width;

                break;
            }

            case para_PageNum:
            case para_PageCount:
            {
                if ( true === bWord )
                {
                    if ( nMinWidth < nWordLen )
                        nMinWidth = nWordLen;

                    bWord    = false;
                    nWordLen = 0;
                }

                if ( Item.Width > nMinWidth )
                    nMinWidth = Item.Get_Width();

                if ( nSpaceLen > 0 )
                {
                    nCurMaxWidth += nSpaceLen;
                    nSpaceLen     = 0;
                }

                nCurMaxWidth += Item.Get_Width();
                bCheckTextHeight = true;
                break;
            }

            case para_Tab:
            {
                nWordLen += Item.Width;

                if ( nMinWidth < nWordLen )
                    nMinWidth = nWordLen;

                bWord    = false;
                nWordLen = 0;

                if ( nSpaceLen > 0 )
                {
                    nCurMaxWidth += nSpaceLen;
                    nSpaceLen     = 0;
                }

                nCurMaxWidth += Item.Width;
                bCheckTextHeight = true;
                break;
            }

            case para_NewLine:
            {
                if ( nMinWidth < nWordLen )
                    nMinWidth = nWordLen;

                bWord    = false;
                nWordLen = 0;

                nSpaceLen = 0;

                if ( nCurMaxWidth > nMaxWidth )
                    nMaxWidth = nCurMaxWidth;

                nCurMaxWidth = 0;
                bCheckTextHeight = true;
                break;
            }

            case para_End:
            {
                if ( nMinWidth < nWordLen )
                    nMinWidth = nWordLen;

                if ( nCurMaxWidth > nMaxWidth )
                    nMaxWidth = nCurMaxWidth;

                if (nMaxHeight < 0.001)
                    bCheckTextHeight = true;

                break;
            }
        }
    }

    if (true === bCheckTextHeight && nMaxHeight < this.TextAscent + this.TextDescent)
        nMaxHeight = this.TextAscent + this.TextDescent;

    MinMax.bWord        = bWord;
    MinMax.nWordLen     = nWordLen;
    MinMax.nSpaceLen    = nSpaceLen;
    MinMax.nMinWidth    = nMinWidth;
    MinMax.nMaxWidth    = nMaxWidth;
    MinMax.nCurMaxWidth = nCurMaxWidth;
    MinMax.nMaxHeight   = nMaxHeight;
};

ParaRun.prototype.Get_Range_VisibleWidth = function(RangeW, _CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var Pos = StartPos; Pos < EndPos; Pos++ )
    {
        var Item = this.private_CheckInstrText(this.Content[Pos]);
        var ItemType = Item.Type;

        switch( ItemType )
        {
            case para_Sym:
            case para_Text:
            case para_Space:
            case para_Math_Text:
            case para_Math_Ampersand:
            case para_Math_Placeholder:
            case para_Math_BreakOperator:
            {
                RangeW.W += Item.Get_WidthVisible();
                break;
            }
            case para_Drawing:
            {
                if ( true === Item.Is_Inline() )
                    RangeW.W += Item.Width;

                break;
            }
            case para_PageNum:
            case para_PageCount:
            case para_Tab:
            {
                RangeW.W += Item.Width;
                break;
            }
            case para_NewLine:
            {
                RangeW.W += Item.WidthVisible;

                break;
            }
            case para_End:
            {
                RangeW.W += Item.Get_WidthVisible();
                RangeW.End = true;

                break;
            }
			default:
			{
				if (Item.Get_WidthVisible())
					RangeW.W += Item.Get_WidthVisible();

				break;
			}
        }
    }
};

ParaRun.prototype.Shift_Range = function(Dx, Dy, _CurLine, _CurRange)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var CurPos = StartPos; CurPos < EndPos; CurPos++ )
    {
        var Item = this.Content[CurPos];

        if ( para_Drawing === Item.Type )
            Item.Shift( Dx, Dy );
    }
};
//-----------------------------------------------------------------------------------
// Функции отрисовки
//-----------------------------------------------------------------------------------
ParaRun.prototype.Draw_HighLights = function(PDSH)
{
    var pGraphics = PDSH.Graphics;

    var CurLine   = PDSH.Line - this.StartLine;
    var CurRange  = ( 0 === CurLine ? PDSH.Range - this.StartRange : PDSH.Range );

    var aHigh     = PDSH.High;
    var aColl     = PDSH.Coll;
    var aFind     = PDSH.Find;
    var aComm     = PDSH.Comm;
    var aShd      = PDSH.Shd;
    var aFields   = PDSH.MMFields;

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var Para     = PDSH.Paragraph;
    var SearchResults = Para.SearchResults;

    var bDrawFind = PDSH.DrawFind;
    var bDrawColl = PDSH.DrawColl;

    var oCompiledPr = this.Get_CompiledPr(false);
    var oShd = oCompiledPr.Shd;
    var bDrawShd  = ( oShd === undefined || c_oAscShdNil === oShd.Value || (oShd.Color && true === oShd.Color.Auto) ? false : true );
    var ShdColor  = ( true === bDrawShd ? oShd.Get_Color( PDSH.Paragraph ) : null );

    if(this.Type == para_Math_Run && this.IsPlaceholder())
        bDrawShd = false;

    var X  = PDSH.X;
    var Y0 = PDSH.Y0;
    var Y1 = PDSH.Y1;

    var CommentsFlag  = PDSH.CommentsFlag;
    var arrComments   = [];
    for (var nIndex = 0, nCount = PDSH.Comments.length; nIndex < nCount; ++nIndex)
	{
		arrComments.push(PDSH.Comments[nIndex]);
	}

    var HighLight = oCompiledPr.HighLight;

    var SearchMarksCount = this.SearchMarks.length;

    this.CollaborativeMarks.Init_Drawing();

    for ( var Pos = StartPos; Pos < EndPos; Pos++ )
    {
		var Item = this.private_CheckInstrText(this.Content[Pos]);
        var ItemType         = Item.Type;
        var ItemWidthVisible = Item.Get_WidthVisible();

        if (PDSH.ComplexFields.IsHiddenFieldContent() && para_End !== ItemType && para_FieldChar !== ItemType)
        	continue;

        // Определим попадание в поиск и совместное редактирование. Попадание в комментарий определять не надо,
        // т.к. класс CParaRun попадает или не попадает в комментарий целиком.

        for ( var SPos = 0; SPos < SearchMarksCount; SPos++)
        {
            var Mark = this.SearchMarks[SPos];
            var MarkPos = Mark.SearchResult.StartPos.Get(Mark.Depth);

            if ( Pos === MarkPos && true === Mark.Start )
                PDSH.SearchCounter++;
        }

        var DrawSearch = ( PDSH.SearchCounter > 0 && true === bDrawFind ? true : false );

        var DrawColl = this.CollaborativeMarks.Check( Pos );

        if ( true === bDrawShd )
            aShd.Add( Y0, Y1, X, X + ItemWidthVisible, 0, ShdColor.r, ShdColor.g, ShdColor.b, undefined, oShd );

		if (PDSH.ComplexFields.IsComplexField()
			&& !PDSH.ComplexFields.IsComplexFieldCode()
			&& PDSH.ComplexFields.IsCurrentComplexField()
			&& !PDSH.ComplexFields.IsHyperlinkField())
			PDSH.CFields.Add(Y0, Y1, X, X + ItemWidthVisible, 0, 0, 0, 0);

        switch( ItemType )
        {
            case para_PageNum:
            case para_PageCount:
            case para_Drawing:
            case para_Tab:
            case para_Text:
            case para_Math_Text:
            case para_Math_Placeholder:
            case para_Math_BreakOperator:
            case para_Math_Ampersand:
            case para_Sym:
            case para_FootnoteReference:
            case para_FootnoteRef:
            case para_Separator:
            case para_ContinuationSeparator:
            {
                if ( para_Drawing === ItemType && !Item.Is_Inline() )
                    break;

                if ( CommentsFlag != comments_NoComment )
                    aComm.Add( Y0, Y1, X, X + ItemWidthVisible, 0, 0, 0, 0, { Active : CommentsFlag === comments_ActiveComment ? true : false, CommentId : arrComments } );
                else if ( highlight_None != HighLight )
                    aHigh.Add( Y0, Y1, X, X + ItemWidthVisible, 0, HighLight.r, HighLight.g, HighLight.b, undefined, HighLight );

                if ( true === DrawSearch )
                    aFind.Add( Y0, Y1, X, X + ItemWidthVisible, 0, 0, 0, 0  );
                else if ( null !== DrawColl )
                    aColl.Add( Y0, Y1, X, X + ItemWidthVisible, 0, DrawColl.r, DrawColl.g, DrawColl.b );

                if ( para_Drawing != ItemType || Item.Is_Inline() )
                    X += ItemWidthVisible;

                break;
            }
            case para_Space:
            {
                // Пробелы в конце строки (и строку состоящую из пробелов) не подчеркиваем, не зачеркиваем и не выделяем
                if ( PDSH.Spaces > 0 )
                {
                    if ( CommentsFlag != comments_NoComment )
                        aComm.Add( Y0, Y1, X, X + ItemWidthVisible, 0, 0, 0, 0, { Active : CommentsFlag === comments_ActiveComment ? true : false, CommentId : arrComments } );
                    else if ( highlight_None != HighLight )
                        aHigh.Add( Y0, Y1, X, X + ItemWidthVisible, 0, HighLight.r, HighLight.g, HighLight.b, undefined, HighLight );

                    PDSH.Spaces--;
                }

                if ( true === DrawSearch )
                    aFind.Add( Y0, Y1, X, X + ItemWidthVisible, 0, 0, 0, 0  );
                else if ( null !== DrawColl )
                    aColl.Add( Y0, Y1, X, X + ItemWidthVisible, 0, DrawColl.r, DrawColl.g, DrawColl.b  );

                X += ItemWidthVisible;

                break;
            }
            case para_End:
            {
                if ( null !== DrawColl )
                    aColl.Add( Y0, Y1, X, X + ItemWidthVisible, 0, DrawColl.r, DrawColl.g, DrawColl.b  );

                X += Item.Get_Width();
                break;
            }
            case para_NewLine:
            {
                X += ItemWidthVisible;
                break;
            }
			case para_FieldChar:
			{
				PDSH.ComplexFields.ProcessFieldChar(Item);

				if (Item.IsNumValue())
				{
					if ( CommentsFlag != comments_NoComment )
						aComm.Add( Y0, Y1, X, X + ItemWidthVisible, 0, 0, 0, 0, { Active : CommentsFlag === comments_ActiveComment ? true : false, CommentId : arrComments } );
					else if ( highlight_None != HighLight )
						aHigh.Add( Y0, Y1, X, X + ItemWidthVisible, 0, HighLight.r, HighLight.g, HighLight.b, undefined, HighLight );

					if ( true === DrawSearch )
						aFind.Add( Y0, Y1, X, X + ItemWidthVisible, 0, 0, 0, 0  );
					else if ( null !== DrawColl )
						aColl.Add( Y0, Y1, X, X + ItemWidthVisible, 0, DrawColl.r, DrawColl.g, DrawColl.b );

						X += ItemWidthVisible;
				}

				break;
			}
        }

        for ( var SPos = 0; SPos < SearchMarksCount; SPos++)
        {
            var Mark = this.SearchMarks[SPos];
            var MarkPos = Mark.SearchResult.EndPos.Get(Mark.Depth);

            if ( Pos + 1 === MarkPos && true !== Mark.Start )
                PDSH.SearchCounter--;
        }
    }

    // Обновим позицию X
    PDSH.X = X;
};

ParaRun.prototype.Draw_Elements = function(PDSE)
{
    var CurLine  = PDSE.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PDSE.Range - this.StartRange : PDSE.Range );
    var CurPage  = PDSE.Page;

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var Para      = PDSE.Paragraph;
    var pGraphics = PDSE.Graphics;
    var BgColor   = PDSE.BgColor;
    var Theme     = PDSE.Theme;

    var X = PDSE.X;
    var Y = PDSE.Y;

    var CurTextPr = this.Get_CompiledPr( false );
    pGraphics.SetTextPr( CurTextPr, Theme );

    var InfoMathText ;
    if(this.Type == para_Math_Run)
    {
        var ArgSize = this.Parent.Compiled_ArgSz.value,
            bNormalText = this.IsNormalText();

        var InfoTextPr =
        {
            TextPr:         CurTextPr,
            ArgSize:        ArgSize,
            bNormalText:    bNormalText,
            bEqArray:       this.bEqArray
        };

        InfoMathText = new CMathInfoTextPr(InfoTextPr);
    }

    if ( undefined !== CurTextPr.Shd && c_oAscShdNil !== CurTextPr.Shd.Value && !(CurTextPr.FontRef && CurTextPr.FontRef.Color) )
        BgColor = CurTextPr.Shd.Get_Color( Para );

    var AutoColor = ( undefined != BgColor && false === BgColor.Check_BlackAutoColor() ? new CDocumentColor( 255, 255, 255, false ) : new CDocumentColor( 0, 0, 0, false ) );
    var  RGBA, Theme = PDSE.Theme, ColorMap = PDSE.ColorMap;
    if((BgColor == undefined || BgColor.Auto) && CurTextPr.FontRef && CurTextPr.FontRef.Color)
    {
        CurTextPr.FontRef.Color.check(Theme, ColorMap);
        RGBA = CurTextPr.FontRef.Color.RGBA;
        AutoColor = new CDocumentColor( RGBA.R, RGBA.G, RGBA.B, RGBA.A );
    }


    var RGBA;
    var ReviewType  = this.Get_ReviewType();
    var ReviewColor = null;
    var bPresentation = this.Paragraph && !this.Paragraph.bFromDocument;
    if (reviewtype_Add === ReviewType || reviewtype_Remove === ReviewType)
    {
        ReviewColor = this.Get_ReviewColor();
        pGraphics.b_color1(ReviewColor.r, ReviewColor.g, ReviewColor.b, 255);
    }
    else if (CurTextPr.Unifill)
    {
        CurTextPr.Unifill.check(PDSE.Theme, PDSE.ColorMap);
        RGBA = CurTextPr.Unifill.getRGBAColor();

        if ( true === PDSE.VisitedHyperlink && ( undefined === this.Pr.Color && undefined === this.Pr.Unifill || bPresentation) )
        {
            AscFormat.G_O_VISITED_HLINK_COLOR.check(PDSE.Theme, PDSE.ColorMap);
            RGBA = AscFormat.G_O_VISITED_HLINK_COLOR.getRGBAColor();
            pGraphics.b_color1( RGBA.R, RGBA.G, RGBA.B, RGBA.A );
        }
        else
        {
            if(bPresentation && PDSE.Hyperlink)
            {
                AscFormat.G_O_HLINK_COLOR.check(PDSE.Theme, PDSE.ColorMap);
                RGBA = AscFormat.G_O_HLINK_COLOR.getRGBAColor();
                pGraphics.b_color1( RGBA.R, RGBA.G, RGBA.B, RGBA.A );
            }
            else
            {
                pGraphics.b_color1( RGBA.R, RGBA.G, RGBA.B, RGBA.A);
            }
        }
    }
    else
    {
        if ( true === PDSE.VisitedHyperlink && ( undefined === this.Pr.Color && undefined === this.Pr.Unifill ) )
        {
            AscFormat.G_O_VISITED_HLINK_COLOR.check(PDSE.Theme, PDSE.ColorMap);
            RGBA = AscFormat.G_O_VISITED_HLINK_COLOR.getRGBAColor();
            pGraphics.b_color1( RGBA.R, RGBA.G, RGBA.B, RGBA.A );
        }
        else if ( true === CurTextPr.Color.Auto )
        {
            pGraphics.b_color1( AutoColor.r, AutoColor.g, AutoColor.b, 255);
        }
        else
        {
            pGraphics.b_color1( CurTextPr.Color.r, CurTextPr.Color.g, CurTextPr.Color.b, 255);
        }
    }

    for ( var Pos = StartPos; Pos < EndPos; Pos++ )
    {
		var Item = this.private_CheckInstrText(this.Content[Pos]);
        var ItemType = Item.Type;

		if (PDSE.ComplexFields.IsHiddenFieldContent() && para_End !== ItemType && para_FieldChar !== ItemType)
			continue;

        var TempY = Y;

        switch (CurTextPr.VertAlign)
        {
            case AscCommon.vertalign_SubScript:
            {
                Y -= vertalign_Koef_Sub * CurTextPr.FontSize * g_dKoef_pt_to_mm;
                break;
            }
            case AscCommon.vertalign_SuperScript:
            {
                Y -= vertalign_Koef_Super * CurTextPr.FontSize * g_dKoef_pt_to_mm;
                break;
            }
        }

        switch( ItemType )
        {
            case para_PageNum:
            case para_PageCount:
            case para_Drawing:
            case para_Tab:
            case para_Text:
            case para_Sym:
            case para_FootnoteReference:
            case para_FootnoteRef:
            case para_Separator:
            case para_ContinuationSeparator:
            {
                if (para_Drawing != ItemType || Item.Is_Inline())
                {
                    Item.Draw(X, Y - this.YOffset, pGraphics, PDSE);
                    X += Item.Get_WidthVisible();
                }

                // Внутри отрисовки инлайн-автофигур могут изменится цвета и шрифт, поэтому восстанавливаем настройки
                if ((para_Drawing === ItemType && Item.Is_Inline()) || (para_Tab === ItemType))
                {
                    pGraphics.SetTextPr( CurTextPr, Theme );

                    if (reviewtype_Add === ReviewType || reviewtype_Remove === ReviewType)
                    {
                        pGraphics.b_color1(ReviewColor.r, ReviewColor.g, ReviewColor.b, 255);
                    }
                    else if (RGBA)
                    {
                        pGraphics.b_color1( RGBA.R, RGBA.G, RGBA.B, 255);
                        pGraphics.p_color( RGBA.R, RGBA.G, RGBA.B, 255);
                    }
                    else
                    {
                        if ( true === CurTextPr.Color.Auto )
                        {
                            pGraphics.b_color1( AutoColor.r, AutoColor.g, AutoColor.b, 255);
                            pGraphics.p_color( AutoColor.r, AutoColor.g, AutoColor.b, 255);
                        }
                        else
                        {
                            pGraphics.b_color1( CurTextPr.Color.r, CurTextPr.Color.g, CurTextPr.Color.b, 255);
                            pGraphics.p_color(  CurTextPr.Color.r, CurTextPr.Color.g, CurTextPr.Color.b, 255);
                        }
                    }
                }

                break;
            }
            case para_Space:
            {
                Item.Draw( X, Y - this.YOffset, pGraphics );

                X += Item.Get_WidthVisible();

                break;
            }
            case para_End:
            {
                var SectPr = Para.Get_SectionPr();
                if (!Para.LogicDocument || Para.LogicDocument !== Para.Parent)
                    SectPr = undefined;

                if ( undefined === SectPr )
                {
                	var oEndTextPr = Para.GetParaEndCompiledPr();

                    if (reviewtype_Common !== ReviewType)
                    {
                        pGraphics.SetTextPr(oEndTextPr, PDSE.Theme);
                        pGraphics.b_color1(ReviewColor.r, ReviewColor.g, ReviewColor.b, 255);
                    }
                    else if (oEndTextPr.Unifill)
                    {
						oEndTextPr.Unifill.check(PDSE.Theme, PDSE.ColorMap);
                        var RGBAEnd = oEndTextPr.Unifill.getRGBAColor();
                        pGraphics.SetTextPr(oEndTextPr, PDSE.Theme);
                        pGraphics.b_color1(RGBAEnd.R, RGBAEnd.G, RGBAEnd.B, 255);
                    }
                    else
                    {
                        pGraphics.SetTextPr(oEndTextPr, PDSE.Theme);
                        if (true === oEndTextPr.Color.Auto)
                            pGraphics.b_color1(AutoColor.r, AutoColor.g, AutoColor.b, 255);
                        else
                            pGraphics.b_color1(oEndTextPr.Color.r, oEndTextPr.Color.g, oEndTextPr.Color.b, 255);
                    }

                    var bEndCell = false;

                    var oDocContent = Para.GetParent();
                    var oCell       = oDocContent.IsTableCellContent(true);
                    if (oCell)
					{
						var oCellContent = oCell.GetContent();
						bEndCell = Para === oCellContent.GetLastParagraph();
					}

                    Item.Draw(X, Y - this.YOffset, pGraphics, bEndCell, reviewtype_Common !== ReviewType ?  true : false);
                }
                else
                {
                    Item.Draw(X, Y - this.YOffset, pGraphics, false, false);
                }

                X += Item.Get_Width();

                break;
            }
            case para_NewLine:
            {
                Item.Draw( X, Y - this.YOffset, pGraphics );
                X += Item.WidthVisible;
                break;
            }
            case para_Math_Ampersand:
            case para_Math_Text:
            case para_Math_BreakOperator:
            {
                var PosLine = this.ParaMath.GetLinePosition(PDSE.Line, PDSE.Range);
                Item.Draw(PosLine.x, PosLine.y, pGraphics, InfoMathText);
                X += Item.Get_WidthVisible();
                break;
            }
            case para_Math_Placeholder:
            {
                if(pGraphics.RENDERER_PDF_FLAG !== true) // если идет печать/ конвертация в PDF плейсхолдер не отрисовываем
                {
                    var PosLine = this.ParaMath.GetLinePosition(PDSE.Line, PDSE.Range);
                    Item.Draw(PosLine.x, PosLine.y, pGraphics, InfoMathText);
                    X += Item.Get_WidthVisible();
                }
                break;
            }
			case para_FieldChar:
			{
				PDSE.ComplexFields.ProcessFieldChar(Item);

				if (Item.IsNumValue())
				{
					Item.Draw(X, Y - this.YOffset, pGraphics, PDSE);
					X += Item.Get_WidthVisible();
				}

				break;
			}
        }

        Y = TempY;
    }
    // Обновляем позицию
    PDSE.X = X;
};

ParaRun.prototype.Draw_Lines = function(PDSL)
{
    var CurLine  = PDSL.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PDSL.Range - this.StartRange : PDSL.Range );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var X        = PDSL.X;
    var Y        = PDSL.Baseline;
    var UndOff   = PDSL.UnderlineOffset;

    var Para       = PDSL.Paragraph;

    var aStrikeout  = PDSL.Strikeout;
    var aDStrikeout = PDSL.DStrikeout;
    var aUnderline  = PDSL.Underline;
    var aSpelling   = PDSL.Spelling;

    var CurTextPr = this.Get_CompiledPr( false );
    var StrikeoutY = Y - this.YOffset;

    var fontCoeff = 1; // учтем ArgSize
    if(this.Type == para_Math_Run)
    {
        var ArgSize = this.Parent.Compiled_ArgSz;
        fontCoeff   = MatGetKoeffArgSize(CurTextPr.FontSize, ArgSize.value);
    }

	var UnderlineY = Y + UndOff - this.YOffset;
	var LineW      = (CurTextPr.FontSize / 18) * g_dKoef_pt_to_mm;

    switch(CurTextPr.VertAlign)
    {
        case AscCommon.vertalign_Baseline   :
		{
			StrikeoutY += -CurTextPr.FontSize * fontCoeff * g_dKoef_pt_to_mm * 0.27;
			break;
		}
        case AscCommon.vertalign_SubScript  :
		{
			StrikeoutY += -CurTextPr.FontSize * fontCoeff * vertalign_Koef_Size * g_dKoef_pt_to_mm * 0.27 - vertalign_Koef_Sub * CurTextPr.FontSize  * fontCoeff * g_dKoef_pt_to_mm;
			UnderlineY -= vertalign_Koef_Sub * CurTextPr.FontSize  * fontCoeff * g_dKoef_pt_to_mm;
			break;
		}
        case AscCommon.vertalign_SuperScript:
		{
			StrikeoutY += -CurTextPr.FontSize * fontCoeff * vertalign_Koef_Size * g_dKoef_pt_to_mm * 0.27 - vertalign_Koef_Super * CurTextPr.FontSize * fontCoeff * g_dKoef_pt_to_mm;
			break;
		}
    }


    var BgColor = PDSL.BgColor;
    if ( undefined !== CurTextPr.Shd && c_oAscShdNil !== CurTextPr.Shd.Value  && !(CurTextPr.FontRef && CurTextPr.FontRef.Color) )
        BgColor = CurTextPr.Shd.Get_Color( Para );

    var CurColor, RGBA, Theme = this.Paragraph.Get_Theme(), ColorMap = this.Paragraph.Get_ColorMap();
    var AutoColor = ( undefined != BgColor && false === BgColor.Check_BlackAutoColor() ? new CDocumentColor( 255, 255, 255, false ) : new CDocumentColor( 0, 0, 0, false ) );
    if((BgColor == undefined || BgColor.Auto) && CurTextPr.FontRef && CurTextPr.FontRef.Color)
    {
        CurTextPr.FontRef.Color.check(Theme, ColorMap);
        RGBA = CurTextPr.FontRef.Color.RGBA;
        AutoColor = new CDocumentColor( RGBA.R, RGBA.G, RGBA.B, RGBA.A );
    }

    var ReviewType  = this.Get_ReviewType();
    var bAddReview  = reviewtype_Add === ReviewType ? true : false;
    var bRemReview  = reviewtype_Remove === ReviewType ? true : false;
    var ReviewColor = this.Get_ReviewColor();

    // Выставляем цвет обводки

    var bPresentation = this.Paragraph && !this.Paragraph.bFromDocument;
    if ( true === PDSL.VisitedHyperlink && ( undefined === this.Pr.Color && undefined === this.Pr.Unifill || bPresentation) )
    {
        AscFormat.G_O_VISITED_HLINK_COLOR.check(Theme, ColorMap);
        RGBA = AscFormat.G_O_VISITED_HLINK_COLOR.getRGBAColor();
        CurColor = new CDocumentColor( RGBA.R, RGBA.G, RGBA.B, RGBA.A );
    }
    else if ( true === CurTextPr.Color.Auto && !CurTextPr.Unifill)
        CurColor = new CDocumentColor( AutoColor.r, AutoColor.g, AutoColor.b );
    else
    {
        if(bPresentation && PDSL.Hyperlink)
        {
            AscFormat.G_O_HLINK_COLOR.check(Theme, ColorMap);
            RGBA = AscFormat.G_O_HLINK_COLOR.getRGBAColor();
            CurColor = new CDocumentColor( RGBA.R, RGBA.G, RGBA.B, RGBA.A );
        }
        else if(CurTextPr.Unifill)
        {
            CurTextPr.Unifill.check(Theme, ColorMap);
            RGBA = CurTextPr.Unifill.getRGBAColor();
            CurColor = new CDocumentColor( RGBA.R, RGBA.G, RGBA.B );
        }
        else
        {
            CurColor = new CDocumentColor( CurTextPr.Color.r, CurTextPr.Color.g, CurTextPr.Color.b );
        }
    }

    PDSL.CurPos.Update(StartPos, PDSL.CurDepth);
    var nSpellingErrorsCounter = PDSL.GetSpellingErrorsCounter();

    var SpellingMarksCount = this.SpellingMarks.length;
    var SpellDataLen = EndPos + 1;
    var SpellData = g_oSpellCheckerMarks.Check(SpellDataLen);
    var Mark = null, MarkIndex = 0;
    for ( var SPos = 0; SPos < SpellingMarksCount; SPos++)
    {
        Mark = this.SpellingMarks[SPos];

        if ( false === Mark.Element.Checked )
        {
            if ( true === Mark.Start )
            {
            	MarkIndex = Mark.Element.StartPos.Get(Mark.Depth);
            	if (MarkIndex < SpellDataLen)
            		SpellData[MarkIndex] += 1;
            }
            else
            {
				MarkIndex = Mark.Element.EndPos.Get(Mark.Depth);
				if (MarkIndex < SpellDataLen)
					SpellData[MarkIndex] -= 1;
            }
        }
    }

    for ( var Pos = StartPos; Pos < EndPos; Pos++ )
    {
		var Item             = this.private_CheckInstrText(this.Content[Pos]);
		var ItemType         = Item.Type;
		var ItemWidthVisible = Item.Get_WidthVisible();

		if (PDSL.ComplexFields.IsHiddenFieldContent() && para_End !== ItemType && para_FieldChar !== ItemType)
			continue;

		if (SpellData[Pos])
			nSpellingErrorsCounter += SpellData[Pos];

        switch( ItemType )
        {
            case para_End:
            {
                if (this.Paragraph)
                {
                    if (bAddReview)
                        aUnderline.Add(UnderlineY, UnderlineY, X, X + ItemWidthVisible, LineW, ReviewColor.r, ReviewColor.g, ReviewColor.b);
                    else if (bRemReview)
                        aStrikeout.Add(StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, ReviewColor.r, ReviewColor.g, ReviewColor.b);
                }

                X += ItemWidthVisible;

                break;
            }
            case para_NewLine:
            {
                X += ItemWidthVisible;
                break;
            }

            case para_PageNum:
            case para_PageCount:
            case para_Drawing:
            case para_Tab:
            case para_Text:
            case para_Sym:
            case para_FootnoteReference:
            case para_FootnoteRef:
            case para_Separator:
            case para_ContinuationSeparator:
            {
                if (para_Text === ItemType && null !== this.CompositeInput && Pos >= this.CompositeInput.Pos && Pos < this.CompositeInput.Pos + this.CompositeInput.Length)
                {
                    aUnderline.Add(UnderlineY, UnderlineY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b, undefined, CurTextPr);
                }

                if ( para_Drawing != ItemType || Item.Is_Inline() )
                {
                    if (true === bRemReview)
                        aStrikeout.Add(StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, ReviewColor.r, ReviewColor.g, ReviewColor.b);
                    else if (true === CurTextPr.DStrikeout)
                        aDStrikeout.Add( StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b, undefined, CurTextPr );
                    else if ( true === CurTextPr.Strikeout )
                        aStrikeout.Add( StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b, undefined, CurTextPr );

                    if (true === bAddReview)
                        aUnderline.Add(UnderlineY, UnderlineY, X, X + ItemWidthVisible, LineW, ReviewColor.r, ReviewColor.g, ReviewColor.b);
                    else if (true === CurTextPr.Underline)
                        aUnderline.Add(UnderlineY, UnderlineY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b, undefined, CurTextPr );

					if (nSpellingErrorsCounter > 0)
                        aSpelling.Add( UnderlineY, UnderlineY, X, X + ItemWidthVisible, LineW, 0, 0, 0 );

                    X += ItemWidthVisible;
                }

                break;
            }
            case para_Space:
            {
                // Пробелы, идущие в конце строки, не подчеркиваем и не зачеркиваем
                if ( PDSL.Spaces > 0 )
                {
                    if (true === bRemReview)
                        aStrikeout.Add(StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, ReviewColor.r, ReviewColor.g, ReviewColor.b);
                    else if (true === CurTextPr.DStrikeout)
                        aDStrikeout.Add( StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b, undefined, CurTextPr  );
                    else if ( true === CurTextPr.Strikeout )
                        aStrikeout.Add( StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b, undefined, CurTextPr  );

                    if (true === bAddReview)
                        aUnderline.Add(UnderlineY, UnderlineY, X, X + ItemWidthVisible, LineW, ReviewColor.r, ReviewColor.g, ReviewColor.b);
                    else if (true === CurTextPr.Underline)
                        aUnderline.Add( UnderlineY, UnderlineY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b, undefined, CurTextPr );

                    PDSL.Spaces--;
                }

                X += ItemWidthVisible;

                break;
            }
            case para_Math_Text:
            case para_Math_BreakOperator:
            case para_Math_Ampersand:
            {
                if (true === bRemReview)
                    aStrikeout.Add( StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, ReviewColor.r, ReviewColor.g, ReviewColor.b, undefined, CurTextPr );
                else if (true === CurTextPr.DStrikeout)
                    aDStrikeout.Add( StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b, undefined, CurTextPr );
                else if ( true === CurTextPr.Strikeout )
                    aStrikeout.Add( StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b, undefined, CurTextPr );


                X += ItemWidthVisible;
                break;
            }
            case para_Math_Placeholder:
            {
                var ctrPrp = this.Parent.GetCtrPrp();
                if (true === bRemReview)
                    aStrikeout.Add( StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, ReviewColor.r, ReviewColor.g, ReviewColor.b, undefined, CurTextPr );
                if(true === ctrPrp.DStrikeout)
                    aDStrikeout.Add( StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b, undefined, CurTextPr );
                else if(true === ctrPrp.Strikeout)
                    aStrikeout.Add( StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b, undefined, CurTextPr );

                X += ItemWidthVisible;
                break;
            }
			case para_FieldChar:
			{
				PDSL.ComplexFields.ProcessFieldChar(Item);

				if (Item.IsNumValue())
				{
					if (true === bRemReview)
						aStrikeout.Add(StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, ReviewColor.r, ReviewColor.g, ReviewColor.b);
					else if (true === CurTextPr.DStrikeout)
						aDStrikeout.Add(StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b, undefined, CurTextPr);
					else if (true === CurTextPr.Strikeout)
						aStrikeout.Add(StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b, undefined, CurTextPr);

					if (true === bAddReview)
						aUnderline.Add(UnderlineY, UnderlineY, X, X + ItemWidthVisible, LineW, ReviewColor.r, ReviewColor.g, ReviewColor.b);
					else if (true === CurTextPr.Underline)
						aUnderline.Add(UnderlineY, UnderlineY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b, undefined, CurTextPr);

					if (nSpellingErrorsCounter > 0)
						aSpelling.Add(UnderlineY, UnderlineY, X, X + ItemWidthVisible, LineW, 0, 0, 0);

					X += ItemWidthVisible;
				}

				break;
			}
        }
	}

	if (true === this.Pr.Have_PrChange() && para_Math_Run !== this.Type)
    {
        var ReviewColor = this.Get_PrReviewColor();
        PDSL.RunReview.Add(0, 0, PDSL.X, X, 0, ReviewColor.r, ReviewColor.g, ReviewColor.b, {RunPr: this.Pr});
    }

    var CollPrChangeColor = this.private_GetCollPrChangeOther();
    if (false !== CollPrChangeColor)
        PDSL.CollChange.Add(0, 0, PDSL.X, X, 0, CollPrChangeColor.r, CollPrChangeColor.g, CollPrChangeColor.b, {RunPr : this.Pr});

    // Обновляем позицию
    PDSL.X = X;
};
//-----------------------------------------------------------------------------------
// Функции для работы с курсором
//-----------------------------------------------------------------------------------
// Находится ли курсор в начале рана
ParaRun.prototype.Is_CursorPlaceable = function()
{
    return true;
};

ParaRun.prototype.Cursor_Is_Start = function()
{
    if ( this.State.ContentPos <= 0 )
        return true;

    return false;
};

// Проверяем нужно ли поправить позицию курсора
ParaRun.prototype.Cursor_Is_NeededCorrectPos = function()
{
    if ( true === this.Is_Empty(false) )
        return true;

    var NewRangeStart = false;
    var RangeEnd      = false;

    var Pos = this.State.ContentPos;

    var LinesLen = this.protected_GetLinesCount();
    for ( var CurLine = 0; CurLine < LinesLen; CurLine++ )
    {
        var RangesLen = this.protected_GetRangesCount(CurLine);
        for ( var CurRange = 0; CurRange < RangesLen; CurRange++ )
        {
            var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
            var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

            if (0 !== CurLine || 0 !== CurRange)
            {
                if (Pos === StartPos)
                {
                    NewRangeStart = true;
                }
            }

            if (Pos === EndPos)
            {
                RangeEnd = true;
            }
        }

        if ( true === NewRangeStart )
            break;
    }

    if ( true !== NewRangeStart && true !== RangeEnd && true === this.Cursor_Is_Start() )
        return true;

    return false;
};

ParaRun.prototype.Cursor_Is_End = function()
{
    if ( this.State.ContentPos >= this.Content.length )
        return true;

    return false;
};
/**
 * Проверяем находится ли курсор в начале рана
 * @returns {boolean}
 */
ParaRun.prototype.IsCursorAtBegin = function()
{
	return this.Cursor_Is_Start();
};
/**
 * Проверяем находится ли курсор в конце рана
 * @returns {boolean}
 */
ParaRun.prototype.IsCursorAtEnd = function()
{
	return this.Cursor_Is_End();
};

ParaRun.prototype.MoveCursorToStartPos = function()
{
    this.State.ContentPos = 0;
};

ParaRun.prototype.MoveCursorToEndPos = function(SelectFromEnd)
{
    if ( true === SelectFromEnd )
    {
        var Selection = this.State.Selection;
        Selection.Use      = true;
        Selection.StartPos = this.Content.length;
        Selection.EndPos   = this.Content.length;
    }
    else
    {
        var CurPos = this.Content.length;

        while ( CurPos > 0 )
        {
            if ( para_End === this.Content[CurPos - 1].Type )
                CurPos--;
            else
                break;
        }

        this.State.ContentPos = CurPos;
    }
};

ParaRun.prototype.Get_ParaContentPosByXY = function(SearchPos, Depth, _CurLine, _CurRange, StepEnd)
{
    var Result = false;

    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var CurPos = StartPos;
    var InMathText = this.Type == para_Math_Run ? SearchPos.InText == true : false;


    for (; CurPos < EndPos; CurPos++ )
    {
        var Item = this.private_CheckInstrText(this.Content[CurPos]);
        var ItemType = Item.Type;

        var TempDx = 0;

        if (para_Drawing != ItemType || true === Item.Is_Inline())
        {
            TempDx = Item.Get_WidthVisible();
        }

        if(this.Type == para_Math_Run)
        {
            var PosLine = this.ParaMath.GetLinePosition(_CurLine, _CurRange);
            var loc = this.Content[CurPos].GetLocationOfLetter();
            SearchPos.CurX = PosLine.x + loc.x; // позиция формулы в строке + смещение буквы в контенте
        }

        // Проверяем, попали ли мы в данный элемент
        var Diff = SearchPos.X - SearchPos.CurX;


        if ((Math.abs( Diff ) < SearchPos.DiffX + 0.001 && (SearchPos.CenterMode || SearchPos.X > SearchPos.CurX)) && InMathText == false)
        {
			SearchPos.DiffX = Math.abs(Diff);
			SearchPos.Pos.Update(CurPos, Depth);
			Result = true;

            if ( Diff >= - 0.001 && Diff <= TempDx + 0.001 )
            {
                SearchPos.InTextPos.Update( CurPos, Depth );
                SearchPos.InText = true;
            }
        }

        SearchPos.CurX += TempDx;

        // Заглушка для знака параграфа и конца строки
        Diff = SearchPos.X - SearchPos.CurX;
        if ((Math.abs( Diff ) < SearchPos.DiffX + 0.001 && (SearchPos.CenterMode || SearchPos.X > SearchPos.CurX)) && InMathText == false)
        {
            if ( para_End === ItemType )
            {
                SearchPos.End = true;

                // Если мы ищем позицию для селекта, тогда нужно искать и за знаком параграфа
                if ( true === StepEnd )
                {
					SearchPos.DiffX = Math.abs(Diff);
                    SearchPos.Pos.Update( this.Content.length, Depth );
                    Result = true;
                }
            }
            else if ( CurPos === EndPos - 1 && para_NewLine != ItemType )
            {
				SearchPos.DiffX = Math.abs(Diff);
                SearchPos.Pos.Update( EndPos, Depth );
                Result = true;
            }
        }
    }

    // Такое возможно, если все раны до этого (в том числе и этот) были пустыми, тогда, чтобы не возвращать
    // неправильную позицию вернем позицию начала данного путого рана.
    if ( SearchPos.DiffX > 1000000 - 1 )
    {
    	SearchPos.DiffX = SearchPos.X - SearchPos.CurX;
        SearchPos.Pos.Update( StartPos, Depth );
        Result = true;
    }

    if (this.Type == para_Math_Run) // не только для пустых Run, но и для проверки на конец Run (т.к. Diff не обновляется)
    {
        //для пустых Run искомая позиция - позиция самого Run
        var bEmpty = this.Is_Empty();

        var PosLine = this.ParaMath.GetLinePosition(_CurLine, _CurRange);

        if(bEmpty)
            SearchPos.CurX = PosLine.x + this.pos.x;

        Diff = SearchPos.X - SearchPos.CurX;
        if(SearchPos.InText == false && (bEmpty || StartPos !== EndPos) && (Math.abs( Diff ) < SearchPos.DiffX + 0.001 && (SearchPos.CenterMode || SearchPos.X > SearchPos.CurX)))
        {
			SearchPos.DiffX = Math.abs(Diff);
			SearchPos.Pos.Update(CurPos, Depth);
			Result = true;
        }
    }

    return Result;
};

ParaRun.prototype.Get_ParaContentPos = function(bSelection, bStart, ContentPos, bUseCorrection)
{
    var Pos = ( true !== bSelection ? this.State.ContentPos : ( false !== bStart ? this.State.Selection.StartPos : this.State.Selection.EndPos ) );

    if (Pos < 0)
    	Pos = 0;

    if (Pos > this.Content.length)
    	Pos = this.Content.length;

    ContentPos.Add(Pos);
};

ParaRun.prototype.Set_ParaContentPos = function(ContentPos, Depth)
{
    var Pos = ContentPos.Get(Depth);

    var Count = this.Content.length;
    if ( Pos > Count )
        Pos = Count;

    // TODO: Как только переделаем работу c Para_End переделать здесь
    for ( var TempPos = 0; TempPos < Pos; TempPos++ )
    {
        if ( para_End === this.Content[TempPos].Type )
        {
            Pos = TempPos;
            break;
        }
    }

    if ( Pos < 0 )
        Pos = 0;

    this.State.ContentPos = Pos;
};

ParaRun.prototype.Get_PosByElement = function(Class, ContentPos, Depth, UseRange, Range, Line)
{
    if ( this === Class )
        return true;

    return false;
};

ParaRun.prototype.Get_ElementByPos = function(ContentPos, Depth)
{
    return this;
};

ParaRun.prototype.Get_PosByDrawing = function(Id, ContentPos, Depth)
{
    var Count = this.Content.length;
    for ( var CurPos = 0; CurPos < Count; CurPos++ )
    {
        var Item = this.Content[CurPos];
        if ( para_Drawing === Item.Type && Id === Item.Get_Id() )
        {
            ContentPos.Update( CurPos, Depth );
            return true;
        }
    }

    return false;
};

ParaRun.prototype.Get_RunElementByPos = function(ContentPos, Depth)
{
    if ( undefined !== ContentPos )
    {
        var CurPos = ContentPos.Get(Depth);
        var ContentLen = this.Content.length;

        if ( CurPos >= this.Content.length || CurPos < 0 )
            return null;

        return this.Content[CurPos];
    }
    else
    {
        if ( this.Content.length > 0 )
            return this.Content[0];
        else
            return null;
    }
};

ParaRun.prototype.Get_LastRunInRange = function(_CurLine, _CurRange)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    return this;
};

ParaRun.prototype.Get_LeftPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
	var CurPos = true === UseContentPos ? ContentPos.Get(Depth) : this.Content.length;

	var isFieldCode  = SearchPos.IsComplexFieldCode();
	var isFieldValue = SearchPos.IsComplexFieldValue();
	var isHiddenCF   = SearchPos.IsHiddenComplexField();

	while (true)
	{
		CurPos--;

		var Item = this.private_CheckInstrText(this.Content[CurPos]);

		if (CurPos >= 0 && para_FieldChar === Item.Type)
		{
			SearchPos.ProcessComplexFieldChar(-1, Item);
			isFieldCode  = SearchPos.IsComplexFieldCode();
			isFieldValue = SearchPos.IsComplexFieldValue();
			isHiddenCF   = SearchPos.IsHiddenComplexField();
		}

		if (CurPos >= 0 && (isFieldCode || isHiddenCF))
			continue;

		if (CurPos < 0 || (!(para_Drawing === Item.Type && false === Item.Is_Inline() && false === SearchPos.IsCheckAnchors()) && !(para_FootnoteReference === Item.Type && true === Item.IsCustomMarkFollows())))
			break;
	}

	if (CurPos >= 0)
	{
		SearchPos.Found = true;
		SearchPos.Pos.Update(CurPos, Depth);
	}
};

ParaRun.prototype.Get_RightPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
	var CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) : 0 );

	var isFieldCode  = SearchPos.IsComplexFieldCode();
	var isFieldValue = SearchPos.IsComplexFieldValue();
	var isHiddenCF   = SearchPos.IsHiddenComplexField();

	var Count = this.Content.length;
	while (true)
	{
		CurPos++;

		// Мы встали в конец рана:
		//   Если мы перешагнули para_End или para_Drawing Anchor, тогда возвращаем false
		//   В противном случае true
		if (Count === CurPos)
		{
			if (CurPos === 0)
				return;

			var PrevItem     = this.private_CheckInstrText(this.Content[CurPos - 1]);
			var PrevItemType = PrevItem.Type;

			if (para_FieldChar === PrevItem.Type)
			{
				SearchPos.ProcessComplexFieldChar(1, PrevItem);
				isFieldCode  = SearchPos.IsComplexFieldCode();
				isFieldValue = SearchPos.IsComplexFieldValue();
				isHiddenCF   = SearchPos.IsHiddenComplexField();
			}

			if (isFieldCode || isHiddenCF)
				return;

			if ((true !== StepEnd && para_End === PrevItemType) || (para_Drawing === PrevItemType && false === PrevItem.Is_Inline() && false === SearchPos.IsCheckAnchors()) || (para_FootnoteReference === PrevItemType && true === PrevItem.IsCustomMarkFollows()))
				return;

			break;
		}

		if (CurPos > Count)
			break;

		// Минимальное значение CurPos = 1, т.к. мы начинаем со значния >= 0 и добавляем 1
		var Item     = this.private_CheckInstrText(this.Content[CurPos - 1]);
		var ItemType = Item.Type;

		if (para_FieldChar === Item.Type)
		{
			SearchPos.ProcessComplexFieldChar(1, Item);
			isFieldCode  = SearchPos.IsComplexFieldCode();
			isFieldValue = SearchPos.IsComplexFieldValue();
			isHiddenCF   = SearchPos.IsHiddenComplexField();
		}

		if (isFieldCode || isHiddenCF)
			continue;

		if (!(true !== StepEnd && para_End === ItemType)
			&& !(para_Drawing === Item.Type && false === Item.Is_Inline())
			&& !(para_FootnoteReference === Item.Type && true === Item.IsCustomMarkFollows()))
			break;
	}

	if (CurPos <= Count)
	{
		SearchPos.Found = true;
		SearchPos.Pos.Update(CurPos, Depth);
	}
};

ParaRun.prototype.Get_WordStartPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
    var CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) - 1 : this.Content.length - 1 );

    if ( CurPos < 0 )
        return;

    SearchPos.Shift = true;

    var NeedUpdate = false;

	var isFieldCode  = SearchPos.IsComplexFieldCode();
	var isFieldValue = SearchPos.IsComplexFieldValue();
	var isHiddenCF   = SearchPos.IsHiddenComplexField();

    // На первом этапе ищем позицию первого непробельного элемента
    if ( 0 === SearchPos.Stage )
    {
        while ( true )
        {
            var Item = this.private_CheckInstrText(this.Content[CurPos]);
            var Type = Item.Type;

            var bSpace = false;

			if (para_FieldChar === Type)
			{
				SearchPos.ProcessComplexFieldChar(-1, Item);
				isFieldCode  = SearchPos.IsComplexFieldCode();
				isFieldValue = SearchPos.IsComplexFieldValue();
				isHiddenCF   = SearchPos.IsHiddenComplexField();
			}

            if ( para_Space === Type || para_Tab === Type || ( para_Text === Type && true === Item.Is_NBSP() ) || ( para_Drawing === Type && true !== Item.Is_Inline() ) )
                bSpace = true;

            if (true === bSpace || isFieldCode || isHiddenCF)
            {
                CurPos--;

                // Выходим из данного рана
                if ( CurPos < 0 )
                    return;
            }
            else
            {
                // Если мы остановились на нетекстовом элементе, тогда его и возвращаем
                if ( para_Text !== this.Content[CurPos].Type && para_Math_Text !== this.Content[CurPos].Type)
                {
                    SearchPos.Pos.Update( CurPos, Depth );
                    SearchPos.Found     = true;
                    SearchPos.UpdatePos = true;
                    return;
                }

                SearchPos.Pos.Update( CurPos, Depth );
                SearchPos.Stage       = 1;
                SearchPos.Punctuation = this.Content[CurPos].Is_Punctuation();
                NeedUpdate            = true;

                break;
            }
        }
    }
    else
    {
        CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) : this.Content.length );
    }

    // На втором этапе мы смотрим на каком элементе мы встали: если текст - пунктуация, тогда сдвигаемся
    // до конца всех знаков пунктуации

    while ( CurPos > 0 )
    {
        CurPos--;
        var Item = this.private_CheckInstrText(this.Content[CurPos]);
        var TempType = Item.Type;

		if (para_FieldChar === Item.Type)
		{
			SearchPos.ProcessComplexFieldChar(-1, Item);
			isFieldCode  = SearchPos.IsComplexFieldCode();
			isFieldValue = SearchPos.IsComplexFieldValue();
			isHiddenCF   = SearchPos.IsHiddenComplexField();
		}

		if (isFieldCode || isHiddenCF)
			continue;

        if ( (para_Text !== TempType && para_Math_Text !== TempType) || true === Item.Is_NBSP() || ( true === SearchPos.Punctuation && true !== Item.Is_Punctuation() ) || ( false === SearchPos.Punctuation && false !== Item.Is_Punctuation() ) )
        {
            SearchPos.Found = true;
            break;
        }
        else
        {
            SearchPos.Pos.Update( CurPos, Depth );
            NeedUpdate = true;
        }
    }

    SearchPos.UpdatePos = NeedUpdate;
};

ParaRun.prototype.Get_WordEndPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
    var CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) : 0 );

    var ContentLen = this.Content.length;
    if ( CurPos >= ContentLen )
        return;

    var NeedUpdate = false;

	var isFieldCode  = SearchPos.IsComplexFieldCode();
	var isFieldValue = SearchPos.IsComplexFieldValue();
	var isHiddenCF   = SearchPos.IsHiddenComplexField();

    if ( 0 === SearchPos.Stage )
    {
        // На первом этапе ищем первый нетекстовый ( и не таб ) элемент
        while ( true )
        {
            var Item = this.private_CheckInstrText(this.Content[CurPos]);
            var Type = Item.Type;
            var bText = false;

			if (para_FieldChar === Type)
			{
				SearchPos.ProcessComplexFieldChar(1, Item);
				isFieldCode  = SearchPos.IsComplexFieldCode();
				isFieldValue = SearchPos.IsComplexFieldValue();
				isHiddenCF   = SearchPos.IsHiddenComplexField();
			}

            if ( (para_Text === Type || para_Math_Text === Type) && true != Item.Is_NBSP() && ( true === SearchPos.First || ( SearchPos.Punctuation === Item.Is_Punctuation() ) ) )
                bText = true;

            if (true === bText || isFieldCode || isHiddenCF)
            {
            	if (!isFieldCode && !isHiddenCF)
				{
					if (true === SearchPos.First)
					{
						SearchPos.First       = false;
						SearchPos.Punctuation = Item.Is_Punctuation();
					}

					// Отмечаем, что сдвиг уже произошел
					SearchPos.Shift = true;
				}

                CurPos++;

                // Выходим из рана
                if ( CurPos >= ContentLen )
                    return;
            }
            else
            {
                SearchPos.Stage = 1;

                // Первый найденный элемент не текстовый, смещаемся вперед
                if ( true === SearchPos.First )
                {
                    // Если первый найденный элемент - конец параграфа, тогда выходим из поиска
                    if ( para_End === Type )
                    {
                        if ( true === StepEnd )
                        {
                            SearchPos.Pos.Update( CurPos + 1, Depth );
                            SearchPos.Found     = true;
                            SearchPos.UpdatePos = true;
                        }

                        return;
                    }

                    CurPos++;

                    // Отмечаем, что сдвиг уже произошел
                    SearchPos.Shift = true;
                }

                break;
            }
        }
    }

    if ( CurPos >= ContentLen )
        return;


    // На втором этапе мы смотрим на каком элементе мы встали: если это не пробел, тогда
    // останавливаемся здесь. В противном случае сдвигаемся вперед, пока не попали на первый
    // не пробельный элемент.
    if ( !(para_Space === this.Content[CurPos].Type || ( para_Text === this.Content[CurPos].Type && true === this.Content[CurPos].Is_NBSP() ) ) )
    {
        SearchPos.Pos.Update( CurPos, Depth );
        SearchPos.Found     = true;
        SearchPos.UpdatePos = true;
    }
    else
    {
        while ( CurPos < ContentLen - 1 )
        {
            CurPos++;
            var Item = this.private_CheckInstrText(this.Content[CurPos]);
            var TempType = Item.Type;

			if (para_FieldChar === Item.Type)
			{
				SearchPos.ProcessComplexFieldChar(1, Item);
				isFieldCode  = SearchPos.IsComplexFieldCode();
				isFieldValue = SearchPos.IsComplexFieldValue();
				isHiddenCF   = SearchPos.IsHiddenComplexField();
			}

			if (isFieldCode || isHiddenCF)
				continue;

            if ( (true !== StepEnd && para_End === TempType) || !( para_Space === TempType || ( para_Text === TempType && true === Item.Is_NBSP() ) ) )
            {
                SearchPos.Found = true;
                break;
            }
        }

        // Обновляем позицию в конце каждого рана (хуже от этого не будет)
        SearchPos.Pos.Update( CurPos, Depth );
        SearchPos.UpdatePos = true;
    }
};

ParaRun.prototype.Get_EndRangePos = function(_CurLine, _CurRange, SearchPos, Depth)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var LastPos = -1;
    for ( var CurPos = StartPos; CurPos < EndPos; CurPos++ )
    {
        var Item = this.Content[CurPos];
        var ItemType = Item.Type;
        if ( !((para_Drawing === ItemType && true !== Item.Is_Inline()) || para_End === ItemType || (para_NewLine === ItemType && break_Line === Item.BreakType)))
            LastPos = CurPos + 1;
    }

    // Проверяем, попал ли хоть один элемент в данный отрезок, если нет, тогда не регистрируем такой ран
    if ( -1 !== LastPos )
    {
        SearchPos.Pos.Update( LastPos, Depth );
        return true;
    }
    else
        return false;
};

ParaRun.prototype.Get_StartRangePos = function(_CurLine, _CurRange, SearchPos, Depth)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var FirstPos = -1;
    for ( var CurPos = EndPos - 1; CurPos >= StartPos; CurPos-- )
    {
        var Item = this.Content[CurPos];
        if ( !(para_Drawing === Item.Type && true !== Item.Is_Inline()) )
            FirstPos = CurPos;
    }

    // Проверяем, попал ли хоть один элемент в данный отрезок, если нет, тогда не регистрируем такой ран
    if ( -1 !== FirstPos )
    {
        SearchPos.Pos.Update( FirstPos, Depth );
        return true;
    }
    else
        return false;
};

ParaRun.prototype.Get_StartRangePos2 = function(_CurLine, _CurRange, ContentPos, Depth)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var Pos = this.protected_GetRangeStartPos(CurLine, CurRange);
    ContentPos.Update( Pos, Depth );
};

ParaRun.prototype.Get_EndRangePos2 = function(_CurLine, _CurRange, ContentPos, Depth)
{
	var CurLine  = _CurLine - this.StartLine;
	var CurRange = (0 === CurLine ? _CurRange - this.StartRange : _CurRange);
	var Pos      = this.protected_GetRangeEndPos(CurLine, CurRange);
	ContentPos.Update(Pos, Depth);
};

ParaRun.prototype.Get_StartPos = function(ContentPos, Depth)
{
    ContentPos.Update( 0, Depth );
};

ParaRun.prototype.Get_EndPos = function(BehindEnd, ContentPos, Depth)
{
    var ContentLen = this.Content.length;

    if ( true === BehindEnd )
        ContentPos.Update( ContentLen, Depth );
    else
    {
        for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
        {
            if ( para_End === this.Content[CurPos].Type )
            {
                ContentPos.Update( CurPos, Depth );
                return;
            }
        }

        // Не нашли para_End
        ContentPos.Update( ContentLen, Depth );
    }
};
//-----------------------------------------------------------------------------------
// Функции для работы с селектом
//-----------------------------------------------------------------------------------
ParaRun.prototype.Set_SelectionContentPos = function(StartContentPos, EndContentPos, Depth, StartFlag, EndFlag)
{
    var StartPos = 0;
    switch (StartFlag)
    {
        case  1: StartPos = 0; break;
        case -1: StartPos = this.Content.length; break;
        case  0: StartPos = StartContentPos.Get(Depth); break;
    }

    var EndPos = 0;
    switch (EndFlag)
    {
        case  1: EndPos = 0; break;
        case -1: EndPos = this.Content.length; break;
        case  0: EndPos = EndContentPos.Get(Depth); break;
    }

    var Selection = this.State.Selection;
    Selection.StartPos = StartPos;
    Selection.EndPos   = EndPos;
    Selection.Use      = true;
};
ParaRun.prototype.SetContentSelection = function(StartDocPos, EndDocPos, Depth, StartFlag, EndFlag)
{
    var StartPos = 0;
    switch (StartFlag)
    {
        case  1: StartPos = 0; break;
        case -1: StartPos = this.Content.length; break;
        case  0: StartPos = StartDocPos[Depth].Position; break;
    }

    var EndPos = 0;
    switch (EndFlag)
    {
        case  1: EndPos = 0; break;
        case -1: EndPos = this.Content.length; break;
        case  0: EndPos = EndDocPos[Depth].Position; break;
    }

    var Selection = this.State.Selection;
    Selection.StartPos = StartPos;
    Selection.EndPos   = EndPos;
    Selection.Use      = true;
};
ParaRun.prototype.SetContentPosition = function(DocPos, Depth, Flag)
{
    var Pos = 0;
    switch (Flag)
    {
        case  1: Pos = 0; break;
        case -1: Pos = this.Content.length; break;
        case  0: Pos = DocPos[Depth].Position; break;
    }

    var nLen = this.Content.length;
    if (nLen > 0 && Pos >= nLen && para_End === this.Content[nLen - 1].Type)
    	Pos = nLen - 1;

    this.State.ContentPos = Pos;
};
ParaRun.prototype.Set_SelectionAtEndPos = function()
{
    this.Set_SelectionContentPos(null, null, 0, -1, -1);
};

ParaRun.prototype.Set_SelectionAtStartPos = function()
{
    this.Set_SelectionContentPos(null, null, 0, 1, 1);
};

ParaRun.prototype.IsSelectionUse = function()
{
    return this.State.Selection.Use;
};

ParaRun.prototype.IsSelectedAll = function(Props)
{
    var Selection = this.State.Selection;
    if ( false === Selection.Use && true !== this.Is_Empty( Props ) )
        return false;

    var SkipAnchor = Props ? Props.SkipAnchor : false;
    var SkipEnd    = Props ? Props.SkipEnd    : false;

    var StartPos = Selection.StartPos;
    var EndPos   = Selection.EndPos;

    if ( EndPos < StartPos )
    {
        StartPos = Selection.EndPos;
        EndPos   = Selection.StartPos;
    }

    for ( var Pos = 0; Pos < StartPos; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        if ( !( ( true === SkipAnchor && ( para_Drawing === ItemType && true !== Item.Is_Inline() ) ) || ( true === SkipEnd && para_End === ItemType ) ) )
            return false;
    }

    var Count = this.Content.length;
    for ( var Pos = EndPos; Pos < Count; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        if ( !( ( true === SkipAnchor && ( para_Drawing === ItemType && true !== Item.Is_Inline() ) ) || ( true === SkipEnd && para_End === ItemType ) ) )
            return false;
    }

    return true;
};

ParaRun.prototype.Selection_CorrectLeftPos = function(Direction)
{
    if ( false === this.Selection.Use || true === this.Is_Empty( { SkipAnchor : true } ) )
        return true;

    var Selection = this.State.Selection;
    var StartPos = Math.min( Selection.StartPos, Selection.EndPos );
    var EndPos   = Math.max( Selection.StartPos, Selection.EndPos );

    for ( var Pos = 0; Pos < StartPos; Pos++ )
    {
        var Item = this.Content[Pos];
        if ( para_Drawing !== Item.Type || true === Item.Is_Inline() )
            return false;
    }

    for ( var Pos = StartPos; Pos < EndPos; Pos++ )
    {
        var Item = this.Content[Pos];
        if ( para_Drawing === Item.Type && true !== Item.Is_Inline() )
        {
            if ( 1 === Direction )
                Selection.StartPos = Pos + 1;
            else
                Selection.EndPos   = Pos + 1;
        }
        else
            return false;
    }

    return true;
};

ParaRun.prototype.RemoveSelection = function()
{
    var Selection = this.State.Selection;

    Selection.Use      = false;
    Selection.StartPos = 0;
    Selection.EndPos   = 0;
};

ParaRun.prototype.SelectAll = function(Direction)
{
    var Selection = this.State.Selection;

    Selection.Use      = true;

    if ( -1 === Direction )
    {
        Selection.StartPos = this.Content.length;
        Selection.EndPos   = 0;
    }
    else
    {
        Selection.StartPos = 0;
        Selection.EndPos   = this.Content.length;
    }
};

ParaRun.prototype.Selection_DrawRange = function(_CurLine, _CurRange, SelectionDraw)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var Selection = this.State.Selection;
    var SelectionUse      = Selection.Use;
    var SelectionStartPos = Selection.StartPos;
    var SelectionEndPos   = Selection.EndPos;

    if ( SelectionStartPos > SelectionEndPos )
    {
        SelectionStartPos = Selection.EndPos;
        SelectionEndPos   = Selection.StartPos;
    }

    var FindStart = SelectionDraw.FindStart;

    for(var CurPos = StartPos; CurPos < EndPos; CurPos++)
    {
        var Item = this.private_CheckInstrText(this.Content[CurPos]);
        var ItemType = Item.Type;
        var DrawSelection = false;

        if ( true === FindStart )
        {
            if ( true === Selection.Use && CurPos >= SelectionStartPos && CurPos < SelectionEndPos )
            {
                FindStart = false;

                DrawSelection = true;
            }
            else
            {
                if ( para_Drawing !== ItemType || true === Item.Is_Inline() )
                    SelectionDraw.StartX += Item.Get_WidthVisible();
            }
        }
        else
        {
            if ( true === Selection.Use && CurPos >= SelectionStartPos && CurPos < SelectionEndPos )
            {
                DrawSelection = true;
            }
        }

        if ( true === DrawSelection )
        {
            if (para_Drawing === ItemType && true !== Item.Is_Inline())
            {
                if (true === SelectionDraw.Draw)
                    Item.Draw_Selection();
            }
            else
                SelectionDraw.W += Item.Get_WidthVisible();
        }
    }

    SelectionDraw.FindStart = FindStart;
};

ParaRun.prototype.IsSelectionEmpty = function(CheckEnd)
{
    var Selection = this.State.Selection;
    if (true !== Selection.Use)
        return true;

    if(this.Type == para_Math_Run && this.IsPlaceholder())
        return true;

    var StartPos = Selection.StartPos;
    var EndPos   = Selection.EndPos;

    if ( StartPos > EndPos )
    {
        StartPos = Selection.EndPos;
        EndPos   = Selection.StartPos;
    }

    if ( true === CheckEnd )
        return ( EndPos > StartPos ? false : true );
    else if(this.Type == para_Math_Run && this.Is_Empty())
    {
        return false;
    }
    else
    {
        for ( var CurPos = StartPos; CurPos < EndPos; CurPos++ )
        {
            var ItemType = this.Content[CurPos].Type;
            if (para_End !== ItemType)
                return false;
        }
    }

    return true;
};

ParaRun.prototype.Selection_CheckParaEnd = function()
{
    var Selection = this.State.Selection;
    if ( true !== Selection.Use )
        return false;

    var StartPos = Selection.StartPos;
    var EndPos   = Selection.EndPos;

    if ( StartPos > EndPos )
    {
        StartPos = Selection.EndPos;
        EndPos   = Selection.StartPos;
    }

    for ( var CurPos = StartPos; CurPos < EndPos; CurPos++ )
    {
        var Item = this.Content[CurPos];

        if ( para_End === Item.Type )
            return true;
    }

    return false;
};

ParaRun.prototype.Selection_CheckParaContentPos = function(ContentPos, Depth, bStart, bEnd)
{
    var CurPos = ContentPos.Get(Depth);

    if (this.Selection.StartPos <= this.Selection.EndPos && this.Selection.StartPos <= CurPos && CurPos <= this.Selection.EndPos)
    {
        if ((true !== bEnd)   || (true === bEnd   && CurPos !== this.Selection.EndPos))
            return true;
    }
    else if (this.Selection.StartPos > this.Selection.EndPos && this.Selection.EndPos <= CurPos && CurPos <= this.Selection.StartPos)
    {
        if ((true !== bEnd)   || (true === bEnd   && CurPos !== this.Selection.StartPos))
            return true;
    }

    return false;
};
//-----------------------------------------------------------------------------------
// Функции для работы с настройками текста свойств
//-----------------------------------------------------------------------------------
ParaRun.prototype.Clear_TextFormatting = function( DefHyper )
{
    // Highlight и Lang не сбрасываются при очистке текстовых настроек

    this.Set_Bold( undefined );
    this.Set_Italic( undefined );
    this.Set_Strikeout( undefined );
    this.Set_Underline( undefined );
    this.Set_FontSize( undefined );
    this.Set_Color( undefined );
    this.Set_Unifill( undefined );
    this.Set_VertAlign( undefined );
    this.Set_Spacing( undefined );
    this.Set_DStrikeout( undefined );
    this.Set_Caps( undefined );
    this.Set_SmallCaps( undefined );
    this.Set_Position( undefined );
    this.Set_RFonts2( undefined );
    this.Set_RStyle( undefined );
    this.Set_Shd( undefined );
    this.Set_TextFill( undefined );
    this.Set_TextOutline( undefined );

    // Насильно заставим пересчитать стиль, т.к. как данная функция вызывается у параграфа, у которого мог смениться стиль
    this.Recalc_CompiledPr(true);
};

ParaRun.prototype.Get_TextPr = function()
{
    return this.Pr.Copy();
};

ParaRun.prototype.Get_FirstTextPr = function()
{
    return this.Pr;
};

ParaRun.prototype.Get_CompiledTextPr = function(Copy)
{
	if (true === this.State.Selection.Use && true === this.Selection_CheckParaEnd())
	{
		var oRunTextPr = this.Get_CompiledPr(true);
		var oEndTextPr = this.Paragraph.GetParaEndCompiledPr();

		oRunTextPr = oRunTextPr.Compare(oEndTextPr);

		return oRunTextPr;
	}
	else
	{
		return this.Get_CompiledPr(Copy);
	}
};

ParaRun.prototype.GetDirectTextPr = function()
{
	return this.Pr;
};

ParaRun.prototype.Recalc_CompiledPr = function(RecalcMeasure)
{
    this.RecalcInfo.TextPr  = true;

    // Если изменение какой-то текстовой настройки требует пересчета элементов
    if ( true === RecalcMeasure )
        this.RecalcInfo.Measure = true;

    // Если мы в формуле, тогда ее надо пересчитывать
    this.private_RecalcCtrPrp();
};

ParaRun.prototype.Recalc_RunsCompiledPr = function()
{
    this.Recalc_CompiledPr(true);
};

ParaRun.prototype.Get_CompiledPr = function(bCopy)
{
	if (this.IsStyleHyperlink() && this.IsInHyperlinkInTOC())
		this.RecalcInfo.TextPr = true;

    if ( true === this.RecalcInfo.TextPr )
    {
        this.RecalcInfo.TextPr = false;
        this.CompiledPr = this.Internal_Compile_Pr();
    }

    if ( false === bCopy )
        return this.CompiledPr;
    else
        return this.CompiledPr.Copy(); // Отдаем копию объекта, чтобы никто не поменял извне настройки стиля
};

ParaRun.prototype.Internal_Compile_Pr = function ()
{
	if (undefined === this.Paragraph || null === this.Paragraph)
	{
		// Сюда мы никогда не должны попадать, но на всякий случай,
		// чтобы не выпадало ошибок сгенерим дефолтовые настройки
		var TextPr = new CTextPr();
		TextPr.Init_Default();
		this.RecalcInfo.TextPr = true;
		return TextPr;
	}

	// Получим настройки текста, для данного параграфа
	var TextPr = this.Paragraph.Get_CompiledPr2(false).TextPr.Copy();

	// Мержим настройки стиля.
	// Одно исключение, когда задан стиль Hyperlink внутри класса Hyperlink внутри поля TOC, то стиль
	// мержить не надо и, более того, цвет и подчеркивание из прямых настроек тоже не используется.
	if (undefined !== this.Pr.RStyle)
	{
		if (!this.IsStyleHyperlink() || !this.IsInHyperlinkInTOC())
		{
			var Styles      = this.Paragraph.Parent.Get_Styles();
			var StyleTextPr = Styles.Get_Pr(this.Pr.RStyle, styletype_Character).TextPr;
			TextPr.Merge(StyleTextPr);
		}
	}

	if (this.Type == para_Math_Run)
	{
		if (undefined === this.Parent || null === this.Parent)
		{
			// Сюда мы никогда не должны попадать, но на всякий случай,
			// чтобы не выпадало ошибок сгенерим дефолтовые настройки
			var TextPr = new CTextPr();
			TextPr.Init_Default();
			this.RecalcInfo.TextPr = true;
			return TextPr;
		}

		if (!this.IsNormalText()) // math text
		{
			// выставим дефолтные текстовые настройки  для математических Run
			var Styles  = this.Paragraph.Parent.Get_Styles();
			var StyleId = this.Paragraph.Style_Get();
			// скопируем текстовые настройки прежде чем подменим на пустые

			var MathFont    = {Name : "Cambria Math", Index : -1};
			var oShapeStyle = null, oShapeTextPr = null;
			;
			if (Styles && typeof Styles.lastId === "string")
			{
				StyleId      = Styles.lastId;
				Styles       = Styles.styles;
				oShapeStyle  = Styles.Get(StyleId);
				oShapeTextPr = oShapeStyle.TextPr.Copy();
				oShapeStyle.TextPr.RFonts.Merge({Ascii : MathFont});
			}
			var StyleDefaultTextPr = Styles.Default.TextPr.Copy();


			// Ascii - по умолчанию шрифт Cambria Math
			// hAnsi, eastAsia, cs - по умолчанию шрифты не Cambria Math, а те, которые компилируются в документе
			Styles.Default.TextPr.RFonts.Merge({Ascii : MathFont});


			var Pr = Styles.Get_Pr(StyleId, styletype_Paragraph, null, null);

			TextPr.RFonts.Set_FromObject(Pr.TextPr.RFonts);

			// подменяем обратно
			Styles.Default.TextPr = StyleDefaultTextPr;
			if (oShapeStyle && oShapeTextPr)
			{
				oShapeStyle.TextPr = oShapeTextPr;
			}
		}


		if (this.IsPlaceholder())
		{

			TextPr.Merge(this.Parent.GetCtrPrp());
			TextPr.Merge(this.Pr);            // Мержим прямые настройки данного рана
		}
		else
		{
			TextPr.Merge(this.Pr);            // Мержим прямые настройки данного рана

			if (!this.IsNormalText()) // math text
			{
				var MPrp = this.MathPrp.GetTxtPrp();
				TextPr.Merge(MPrp); // bold, italic
			}
		}
	}
	else
	{
		TextPr.Merge(this.Pr); // Мержим прямые настройки данного рана

		if (this.Pr.Color && !this.Pr.Unifill)
		{
			TextPr.Unifill = undefined;
		}
	}

	// Для совместимости со старыми версиями запишем FontFamily
	TextPr.FontFamily.Name  = TextPr.RFonts.Ascii.Name;
	TextPr.FontFamily.Index = TextPr.RFonts.Ascii.Index;

	return TextPr;
};

ParaRun.prototype.IsStyleHyperlink = function()
{
	if (!this.Paragraph || !this.Paragraph.bFromDocument || !this.Paragraph.LogicDocument || !this.Paragraph.LogicDocument.Get_Styles() || !this.Paragraph.LogicDocument.Get_Styles().GetDefaultHyperlink)
		return false;

	return (this.Pr.RStyle === this.Paragraph.LogicDocument.Get_Styles().GetDefaultHyperlink() ? true : false);
};
ParaRun.prototype.IsInHyperlinkInTOC = function()
{
	var oParagraph = this.GetParagraph();
	if (!oParagraph || !oParagraph.bFromDocument)
		return false;

	var oPos = oParagraph.Get_PosByElement(this);
	if (!oPos)
		return false;

	var isHyperlink = false;
	var arrClasses = oParagraph.Get_ClassesByPos(oPos);
	for (var nIndex = 0, nCount = arrClasses.length; nIndex < nCount; ++nIndex)
	{
		if (arrClasses[nIndex] instanceof ParaHyperlink)
		{
			isHyperlink = true;
			break;
		}
	}

	if (!isHyperlink)
		return false;

	var arrComplexFields = oParagraph.GetComplexFieldsByPos(oPos);

	for (var nIndex = 0, nCount = arrComplexFields.length; nIndex < nCount; ++nIndex)
	{
		var oInstruction = arrComplexFields[nIndex].GetInstruction();
		if (oInstruction && fieldtype_TOC === oInstruction.GetType())
			return true;
	}

	return false;
};

ParaRun.prototype.Set_Pr = function(TextPr)
{
	return this.SetPr(TextPr);
};
/**
 * Жестко меняем настройки на заданные
 * @param {CTextPr} oTextPr
 */
ParaRun.prototype.SetPr = function(oTextPr)
{
	History.Add(new CChangesRunTextPr(this, this.Pr, oTextPr, this.private_IsCollPrChangeMine()));
	this.Pr = oTextPr;
	this.Recalc_CompiledPr(true);

	this.private_UpdateSpellChecking();
	this.private_UpdateTrackRevisionOnChangeTextPr(true);
};
ParaRun.prototype.Apply_TextPr = function(TextPr, IncFontSize, ApplyToAll)
{
    var bReview = false;
    if (this.Paragraph && this.Paragraph.LogicDocument && this.Paragraph.bFromDocument && true === this.Paragraph.LogicDocument.Is_TrackRevisions())
        bReview = true;

    var ReviewType = this.Get_ReviewType();
    var IsPrChange = this.Have_PrChange();
    if ( true === ApplyToAll )
    {
        if (true === bReview && true !== this.Have_PrChange())
            this.Add_PrChange();

        if ( undefined === IncFontSize )
        {
            this.Apply_Pr(TextPr);
        }
        else
        {
            var _TextPr = new CTextPr();
            var CurTextPr = this.Get_CompiledPr( false );

            this.private_AddCollPrChangeMine();
            this.Set_FontSize( FontSize_IncreaseDecreaseValue( IncFontSize, CurTextPr.FontSize ) );
        }

        // Дополнительно проверим, если у нас para_End лежит в данном ране и попадает в выделение, тогда
        // применим заданные настроки к символу конца параграфа

        // TODO: Возможно, стоит на этапе пересчета запонимать, лежит ли para_End в данном ране. Чтобы в каждом
        //       ране потом не бегать каждый раз по всему массиву в поисках para_End.

        var bEnd = false;
        var Count = this.Content.length;
        for ( var Pos = 0; Pos < Count; Pos++ )
        {
            if ( para_End === this.Content[Pos].Type )
            {
                bEnd = true;
                break;
            }
        }

        if ( true === bEnd )
		{
			if (undefined === IncFontSize)
			{
				if (!TextPr.AscFill && !TextPr.AscLine && !TextPr.AscUnifill)
				{
					this.Paragraph.TextPr.Apply_TextPr(TextPr);
				}
				else
				{
					var oEndTextPr = this.Paragraph.GetParaEndCompiledPr();
					if (TextPr.AscFill)
					{
						this.Paragraph.TextPr.Set_TextFill(AscFormat.CorrectUniFill(TextPr.AscFill, oEndTextPr.TextFill, 1));
					}
					if (TextPr.AscUnifill)
					{
						this.Paragraph.TextPr.Set_Unifill(AscFormat.CorrectUniFill(TextPr.AscUnifill, oEndTextPr.Unifill, 0));
					}
					if (TextPr.AscLine)
					{
						this.Paragraph.TextPr.Set_TextOutline(AscFormat.CorrectUniStroke(TextPr.AscLine, oEndTextPr.TextOutline, 0));
					}
				}
			}
			else
			{
				var oEndTextPr = this.Paragraph.GetParaEndCompiledPr();

				// TODO: Как только перенесем историю изменений TextPr в сам класс CTextPr, переделать тут
				this.Paragraph.TextPr.Set_FontSize(FontSize_IncreaseDecreaseValue(IncFontSize, oEndTextPr.FontSize));
			}
		}
    }
    else
    {
        var Result = [];
        var LRun = this, CRun = null, RRun = null;

        if ( true === this.State.Selection.Use )
        {
            var StartPos = this.State.Selection.StartPos;
            var EndPos   = this.State.Selection.EndPos;

            if (StartPos === EndPos && 0 !== this.Content.length)
			{
				CRun = this;
				LRun = null;
				RRun = null;
			}
			else
			{
				var Direction = 1;
				if (StartPos > EndPos)
				{
					var Temp  = StartPos;
					StartPos  = EndPos;
					EndPos    = Temp;
					Direction = -1;
				}

				// Если выделено не до конца, тогда разделяем по последней точке
				if (EndPos < this.Content.length)
				{
					RRun = LRun.Split_Run(EndPos);
					RRun.Set_ReviewType(ReviewType);
					if (IsPrChange)
						RRun.Add_PrChange();
				}

				// Если выделено не с начала, тогда делим по начальной точке
				if (StartPos > 0)
				{
					CRun = LRun.Split_Run(StartPos);
					CRun.Set_ReviewType(ReviewType);
					if (IsPrChange)
						CRun.Add_PrChange();
				}
				else
				{
					CRun = LRun;
					LRun = null;
				}

				if (null !== LRun)
				{
					LRun.Selection.Use      = true;
					LRun.Selection.StartPos = LRun.Content.length;
					LRun.Selection.EndPos   = LRun.Content.length;
				}

				CRun.SelectAll(Direction);

				if (true === bReview && true !== CRun.Have_PrChange())
					CRun.Add_PrChange();

				if (undefined === IncFontSize)
					CRun.Apply_Pr(TextPr);
				else
				{
					var _TextPr   = new CTextPr();
					var CurTextPr = this.Get_CompiledPr(false);

					CRun.private_AddCollPrChangeMine();
					CRun.Set_FontSize(FontSize_IncreaseDecreaseValue(IncFontSize, CurTextPr.FontSize));
				}

				if (null !== RRun)
				{
					RRun.Selection.Use      = true;
					RRun.Selection.StartPos = 0;
					RRun.Selection.EndPos   = 0;
				}

				// Дополнительно проверим, если у нас para_End лежит в данном ране и попадает в выделение, тогда
				// применим заданные настроки к символу конца параграфа

				// TODO: Возможно, стоит на этапе пересчета запонимать, лежит ли para_End в данном ране. Чтобы в каждом
				//       ране потом не бегать каждый раз по всему массиву в поисках para_End.

				if (true === this.Selection_CheckParaEnd())
				{
					if (undefined === IncFontSize)
					{
						if (!TextPr.AscFill && !TextPr.AscLine && !TextPr.AscUnifill)
						{
							this.Paragraph.TextPr.Apply_TextPr(TextPr);
						}
						else
						{
							var oEndTextPr = this.Paragraph.GetParaEndCompiledPr();
							if (TextPr.AscFill)
							{
								this.Paragraph.TextPr.Set_TextFill(AscFormat.CorrectUniFill(TextPr.AscFill, oEndTextPr.TextFill, 1));
							}
							if (TextPr.AscUnifill)
							{
								this.Paragraph.TextPr.Set_Unifill(AscFormat.CorrectUniFill(TextPr.AscUnifill, oEndTextPr.Unifill, 0));
							}
							if (TextPr.AscLine)
							{
								this.Paragraph.TextPr.Set_TextOutline(AscFormat.CorrectUniStroke(TextPr.AscLine, oEndTextPr.TextOutline, 0));
							}
						}
					}
					else
					{
						var oEndTextPr = this.Paragraph.GetParaEndCompiledPr();

						// TODO: Как только перенесем историю изменений TextPr в сам класс CTextPr, переделать тут
						this.Paragraph.TextPr.Set_FontSize(FontSize_IncreaseDecreaseValue(IncFontSize, oEndTextPr.FontSize));
					}
				}
			}
        }
        else
        {
            var CurPos = this.State.ContentPos;

            // Если выделено не до конца, тогда разделяем по последней точке
            if ( CurPos < this.Content.length )
            {
                RRun = LRun.Split_Run(CurPos);
                RRun.Set_ReviewType(ReviewType);
                if (IsPrChange)
                    RRun.Add_PrChange();
            }

            if ( CurPos > 0 )
            {
                CRun = LRun.Split_Run(CurPos);
                CRun.Set_ReviewType(ReviewType);
                if (IsPrChange)
                    CRun.Add_PrChange();
            }
            else
            {
                CRun = LRun;
                LRun = null;
            }

            if ( null !== LRun )
                LRun.RemoveSelection();

            CRun.RemoveSelection();
            CRun.MoveCursorToStartPos();

            if (true === bReview && true !== CRun.Have_PrChange())
                CRun.Add_PrChange();

            if ( undefined === IncFontSize )
            {
                CRun.Apply_Pr( TextPr );
            }
            else
            {
                var _TextPr = new CTextPr();
                var CurTextPr = this.Get_CompiledPr( false );
                CRun.private_AddCollPrChangeMine();
                CRun.Set_FontSize( FontSize_IncreaseDecreaseValue( IncFontSize, CurTextPr.FontSize ) );
            }


            if ( null !== RRun )
                RRun.RemoveSelection();
        }

        Result.push( LRun );
        Result.push( CRun );
        Result.push( RRun );

        return Result;
    }
};

ParaRun.prototype.Split_Run = function(Pos)
{
    History.Add(new CChangesRunOnStartSplit(this, Pos));
    AscCommon.CollaborativeEditing.OnStart_SplitRun(this, Pos);

    // Создаем новый ран
    var bMathRun = this.Type == para_Math_Run;
    var NewRun = new ParaRun(this.Paragraph, bMathRun);

    // Копируем настройки
    NewRun.Set_Pr(this.Pr.Copy(true));

    if(bMathRun)
        NewRun.Set_MathPr(this.MathPrp.Copy());


    var OldCrPos = this.State.ContentPos;
    var OldSSPos = this.State.Selection.StartPos;
    var OldSEPos = this.State.Selection.EndPos;

    // Разделяем содержимое по ранам
    NewRun.ConcatToContent( this.Content.slice(Pos) );
    this.Remove_FromContent( Pos, this.Content.length - Pos, true );

    // Подправим точки селекта и текущей позиции
    if ( OldCrPos >= Pos )
    {
        NewRun.State.ContentPos = OldCrPos - Pos;
        this.State.ContentPos   = this.Content.length;
    }
    else
    {
        NewRun.State.ContentPos = 0;
    }

    if ( OldSSPos >= Pos )
    {
        NewRun.State.Selection.StartPos = OldSSPos - Pos;
        this.State.Selection.StartPos   = this.Content.length;
    }
    else
    {
        NewRun.State.Selection.StartPos = 0;
    }

    if ( OldSEPos >= Pos )
    {
        NewRun.State.Selection.EndPos = OldSEPos - Pos;
        this.State.Selection.EndPos   = this.Content.length;
    }
    else
    {
        NewRun.State.Selection.EndPos = 0;
    }

    // Если были точки орфографии, тогда переместим их в новый ран
    var SpellingMarksCount = this.SpellingMarks.length;
    for ( var Index = 0; Index < SpellingMarksCount; Index++ )
    {
        var Mark    = this.SpellingMarks[Index];
        var MarkPos = ( true === Mark.Start ? Mark.Element.StartPos.Get(Mark.Depth) : Mark.Element.EndPos.Get(Mark.Depth) );

        if ( MarkPos >= Pos )
        {
            var MarkElement = Mark.Element;
            if ( true === Mark.Start )
            {
                //MarkElement.ClassesS[Mark.Depth]       = NewRun;
                MarkElement.StartPos.Data[Mark.Depth] -= Pos;
            }
            else
            {
                //MarkElement.ClassesE[Mark.Depth]     = NewRun;
                MarkElement.EndPos.Data[Mark.Depth] -= Pos;
            }

            NewRun.SpellingMarks.push( Mark );

            this.SpellingMarks.splice( Index, 1 );
            SpellingMarksCount--;
            Index--;
        }
    }

    History.Add(new CChangesRunOnEndSplit(this, NewRun));
    AscCommon.CollaborativeEditing.OnEnd_SplitRun(NewRun);
    return NewRun;
};

ParaRun.prototype.Clear_TextPr = function()
{
    // Данная функция вызывается пока только при изменении стиля параграфа. Оставляем в этой ситуации язык неизмененным,
    // а также не трогаем highlight.
    var NewTextPr = new CTextPr();
    NewTextPr.Lang      = this.Pr.Lang.Copy();
    NewTextPr.HighLight = this.Pr.Copy_HighLight();
    this.Set_Pr( NewTextPr );
};

/**
 * В данной функции мы применяем приходящие настройки поверх старых. Если значение undefined, то старое значение
 * не меняем, а если null, то удаляем его из прямых настроек.
 * @param {CTextPr} TextPr
 */
ParaRun.prototype.Apply_Pr = function(TextPr)
{
	this.private_AddCollPrChangeMine();

	if (this.Type == para_Math_Run && false === this.IsNormalText())
	{
		if (null === TextPr.Bold && null === TextPr.Italic)
			this.Math_Apply_Style(undefined);
		else
		{
			if (undefined != TextPr.Bold)
			{
				if (TextPr.Bold == true)
				{
					if (this.MathPrp.sty == STY_ITALIC || this.MathPrp.sty == undefined)
						this.Math_Apply_Style(STY_BI);
					else if (this.MathPrp.sty == STY_PLAIN)
						this.Math_Apply_Style(STY_BOLD);

				}
				else if (TextPr.Bold == false || TextPr.Bold == null)
				{
					if (this.MathPrp.sty == STY_BI || this.MathPrp.sty == undefined)
						this.Math_Apply_Style(STY_ITALIC);
					else if (this.MathPrp.sty == STY_BOLD)
						this.Math_Apply_Style(STY_PLAIN);
				}
			}

			if (undefined != TextPr.Italic)
			{
				if (TextPr.Italic == true)
				{
					if (this.MathPrp.sty == STY_BOLD)
						this.Math_Apply_Style(STY_BI);
					else if (this.MathPrp.sty == STY_PLAIN || this.MathPrp.sty == undefined)
						this.Math_Apply_Style(STY_ITALIC);
				}
				else if (TextPr.Italic == false || TextPr.Italic == null)
				{
					if (this.MathPrp.sty == STY_BI)
						this.Math_Apply_Style(STY_BOLD);
					else if (this.MathPrp.sty == STY_ITALIC || this.MathPrp.sty == undefined)
						this.Math_Apply_Style(STY_PLAIN);
				}
			}
		}
	}
	else
	{
		if (undefined !== TextPr.Bold)
			this.Set_Bold(null === TextPr.Bold ? undefined : TextPr.Bold);

		if (undefined !== TextPr.Italic)
			this.Set_Italic(null === TextPr.Italic ? undefined : TextPr.Italic);
	}

	if (undefined !== TextPr.Strikeout)
		this.Set_Strikeout(null === TextPr.Strikeout ? undefined : TextPr.Strikeout);

	if (undefined !== TextPr.Underline)
		this.Set_Underline(null === TextPr.Underline ? undefined : TextPr.Underline);

	if (undefined !== TextPr.FontSize)
		this.Set_FontSize(null === TextPr.FontSize ? undefined : TextPr.FontSize);

	if (undefined !== TextPr.Color && undefined === TextPr.Unifill)
	{
		this.Set_Color(null === TextPr.Color ? undefined : TextPr.Color);
		this.Set_Unifill(undefined);
		this.Set_TextFill(undefined);
	}
	else if (undefined !== TextPr.Unifill)
	{
		this.Set_Unifill(null === TextPr.Unifill ? undefined : TextPr.Unifill);
		this.Set_Color(undefined);
		this.Set_TextFill(undefined);
	}
	else if (undefined !== TextPr.AscUnifill && this.Paragraph)
	{
		if (!this.Paragraph.bFromDocument)
		{
			var oCompiledPr = this.Get_CompiledPr(true);
			this.Set_Unifill(AscFormat.CorrectUniFill(TextPr.AscUnifill, oCompiledPr.Unifill, 0), AscCommon.isRealObject(TextPr.AscUnifill) && TextPr.AscUnifill.asc_CheckForseSet());
			this.Set_Color(undefined);
			this.Set_TextFill(undefined);
		}
	}
	else if (undefined !== TextPr.TextFill)
	{
		this.Set_Unifill(undefined);
		this.Set_Color(undefined);
		this.Set_TextFill(null === TextPr.TextFill ? undefined : TextPr.TextFill);
	}
	else if (undefined !== TextPr.AscFill && this.Paragraph)
	{
		var oMergeUnifill, oColor;
		if (this.Paragraph.bFromDocument)
		{
			var oCompiledPr = this.Get_CompiledPr(true);
			if (oCompiledPr.TextFill)
			{
				oMergeUnifill = oCompiledPr.TextFill;
			}
			else if (oCompiledPr.Unifill)
			{
				oMergeUnifill = oCompiledPr.Unifill;
			}
			else if (oCompiledPr.Color)
			{
				oColor        = oCompiledPr.Color;
				oMergeUnifill = AscFormat.CreateUnfilFromRGB(oColor.r, oColor.g, oColor.b);
			}
			this.Set_Unifill(undefined);
			this.Set_Color(undefined);
			this.Set_TextFill(AscFormat.CorrectUniFill(TextPr.AscFill, oMergeUnifill, 1), AscCommon.isRealObject(TextPr.AscFill) && TextPr.AscFill.asc_CheckForseSet());
		}
	}

	if (undefined !== TextPr.TextOutline)
	{
		this.Set_TextOutline(null === TextPr.TextOutline ? undefined : TextPr.TextOutline);
	}
	else if (undefined !== TextPr.AscLine && this.Paragraph)
	{
		var oCompiledPr = this.Get_CompiledPr(true);
		this.Set_TextOutline(AscFormat.CorrectUniStroke(TextPr.AscLine, oCompiledPr.TextOutline, 0));
	}

	if (undefined !== TextPr.VertAlign)
		this.Set_VertAlign(null === TextPr.VertAlign ? undefined : TextPr.VertAlign);

	if (undefined !== TextPr.HighLight)
		this.Set_HighLight(null === TextPr.HighLight ? undefined : TextPr.HighLight);

	if (undefined !== TextPr.RStyle)
		this.Set_RStyle(null === TextPr.RStyle ? undefined : TextPr.RStyle);

	if (undefined !== TextPr.Spacing)
		this.Set_Spacing(null === TextPr.Spacing ? undefined : TextPr.Spacing);

	if (undefined !== TextPr.DStrikeout)
		this.Set_DStrikeout(null === TextPr.DStrikeout ? undefined : TextPr.DStrikeout);

	if (undefined !== TextPr.Caps)
		this.Set_Caps(null === TextPr.Caps ? undefined : TextPr.Caps);

	if (undefined !== TextPr.SmallCaps)
		this.Set_SmallCaps(null === TextPr.SmallCaps ? undefined : TextPr.SmallCaps);

	if (undefined !== TextPr.Position)
		this.Set_Position(null === TextPr.Position ? undefined : TextPr.Position);

	if (undefined !== TextPr.RFonts)
	{
		if (this.Type == para_Math_Run && !this.IsNormalText()) // при смене Font в этом случае (даже на Cambria Math) cs, eastAsia не меняются
		{
			// только для редактирования
			// делаем так для проверки действительно ли нужно сменить Font, чтобы при смене других текстовых настроек не выставился Cambria Math (TextPr.RFonts приходит всегда в виде объекта)
			if (TextPr.RFonts.Ascii !== undefined || TextPr.RFonts.HAnsi !== undefined)
			{
				var RFonts = new CRFonts();
				RFonts.Set_All("Cambria Math", -1);

				this.Set_RFonts2(RFonts);
			}
		}
		else
			this.Set_RFonts2(TextPr.RFonts);
	}


	if (undefined !== TextPr.Lang)
		this.Set_Lang2(TextPr.Lang);

	if (undefined !== TextPr.Shd)
		this.Set_Shd(TextPr.Shd);

	for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos)
	{
		if (para_End === this.Content[nPos].Type)
			return this.Paragraph.TextPr.Apply_TextPr(TextPr);
	}
};

ParaRun.prototype.Have_PrChange = function()
{
    return this.Pr.Have_PrChange();
};

ParaRun.prototype.Get_PrReviewColor = function()
{
    if (this.Pr.ReviewInfo)
        return this.Pr.ReviewInfo.Get_Color();

    return REVIEW_COLOR;
};

ParaRun.prototype.Add_PrChange = function()
{
    if (false === this.Have_PrChange())
    {
        this.Pr.Add_PrChange();
		History.Add(new CChangesRunPrChange(this,
			{
				PrChange   : undefined,
				ReviewInfo : undefined
			},
			{
				PrChange   : this.Pr.PrChange,
				ReviewInfo : this.Pr.ReviewInfo
			}));
		this.private_UpdateTrackRevisions();
    }
};

ParaRun.prototype.Set_PrChange = function(PrChange, ReviewInfo)
{
	History.Add(new CChangesRunPrChange(this,
		{
			PrChange   : this.Pr.PrChange,
			ReviewInfo : this.Pr.ReviewInfo ? this.Pr.ReviewInfo.Copy() : undefined
		},
		{
			PrChange   : PrChange,
			ReviewInfo : ReviewInfo ? ReviewInfo.Copy() : undefined
		}));
	this.Pr.Set_PrChange(PrChange, ReviewInfo);
    this.private_UpdateTrackRevisions();
};

ParaRun.prototype.Remove_PrChange = function()
{
	if (true === this.Have_PrChange())
	{
		History.Add(new CChangesRunPrChange(this,
			{
				PrChange   : this.Pr.PrChange,
				ReviewInfo : this.Pr.ReviewInfo
			},
			{
				PrChange   : undefined,
				ReviewInfo : undefined
			}));
		this.Pr.Remove_PrChange();
		this.private_UpdateTrackRevisions();
	}
};

ParaRun.prototype.Reject_PrChange = function()
{
    if (true === this.Have_PrChange())
    {
		if (this.GetParaEnd())
			this.Paragraph.TextPr.SetPr(this.Pr.PrChange);

        this.Set_Pr(this.Pr.PrChange);

        this.Remove_PrChange();
    }
};

ParaRun.prototype.Accept_PrChange = function()
{
    this.Remove_PrChange();
};

ParaRun.prototype.Get_DiffPrChange = function()
{
    return this.Pr.Get_DiffPrChange();
};

ParaRun.prototype.Set_Bold = function(Value)
{
    if ( Value !== this.Pr.Bold )
    {
        var OldValue = this.Pr.Bold;
        this.Pr.Bold = Value;

        History.Add(new CChangesRunBold(this, OldValue, Value, this.private_IsCollPrChangeMine()));

        this.Recalc_CompiledPr(true);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Get_Bold = function()
{
    return this.Get_CompiledPr(false).Bold;
};

ParaRun.prototype.Set_Italic = function(Value)
{
    if ( Value !== this.Pr.Italic )
    {
        var OldValue = this.Pr.Italic;
        this.Pr.Italic = Value;

        History.Add(new CChangesRunItalic(this, OldValue, Value, this.private_IsCollPrChangeMine()));

        this.Recalc_CompiledPr(true);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Get_Italic = function()
{
    return this.Get_CompiledPr(false).Italic;
};

ParaRun.prototype.Set_Strikeout = function(Value)
{
    if ( Value !== this.Pr.Strikeout )
    {
        var OldValue = this.Pr.Strikeout;
        this.Pr.Strikeout = Value;

        History.Add(new CChangesRunStrikeout(this, OldValue, Value, this.private_IsCollPrChangeMine()));

        this.Recalc_CompiledPr(false);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Get_Strikeout = function()
{
    return this.Get_CompiledPr(false).Strikeout;
};

ParaRun.prototype.Set_Underline = function(Value)
{
    if ( Value !== this.Pr.Underline )
    {
        var OldValue = this.Pr.Underline;
        this.Pr.Underline = Value;

        History.Add(new CChangesRunUnderline(this, OldValue, Value, this.private_IsCollPrChangeMine()));

        this.Recalc_CompiledPr(false);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Get_Underline = function()
{
    return this.Get_CompiledPr(false).Underline;
};

ParaRun.prototype.Set_FontSize = function(Value)
{
    if ( Value !== this.Pr.FontSize )
    {
        var OldValue = this.Pr.FontSize;
        this.Pr.FontSize = Value;

        History.Add(new CChangesRunFontSize(this, OldValue, Value, this.private_IsCollPrChangeMine()));

        this.Recalc_CompiledPr(true);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Get_FontSize = function()
{
    return this.Get_CompiledPr(false).FontSize;
};

ParaRun.prototype.Set_Color = function(Value)
{
    if ( ( undefined === Value && undefined !== this.Pr.Color ) || ( Value instanceof CDocumentColor && ( undefined === this.Pr.Color || false === Value.Compare(this.Pr.Color) ) ) )
    {
        var OldValue = this.Pr.Color;
        this.Pr.Color = Value;

        History.Add(new CChangesRunColor(this, OldValue, Value, this.private_IsCollPrChangeMine()));

        this.Recalc_CompiledPr(false);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Set_Unifill = function(Value, bForce)
{
    if ( ( undefined === Value && undefined !== this.Pr.Unifill ) || ( Value instanceof AscFormat.CUniFill && ( undefined === this.Pr.Unifill || false === AscFormat.CompareUnifillBool(this.Pr.Unifill, Value) ) ) || bForce )
    {
        var OldValue = this.Pr.Unifill;
        this.Pr.Unifill = Value;

        History.Add(new CChangesRunUnifill(this, OldValue, Value, this.private_IsCollPrChangeMine()));

        this.Recalc_CompiledPr(false);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};
ParaRun.prototype.Set_TextFill = function(Value, bForce)
{
    if ( ( undefined === Value && undefined !== this.Pr.TextFill ) || ( Value instanceof AscFormat.CUniFill && ( undefined === this.Pr.TextFill || false === AscFormat.CompareUnifillBool(this.Pr.TextFill.IsIdentical, Value) ) ) || bForce )
    {
        var OldValue = this.Pr.TextFill;
        this.Pr.TextFill = Value;

        History.Add(new CChangesRunTextFill(this, OldValue, Value, this.private_IsCollPrChangeMine()));

        this.Recalc_CompiledPr(false);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Set_TextOutline = function(Value)
{
    if ( ( undefined === Value && undefined !== this.Pr.TextOutline ) || ( Value instanceof AscFormat.CLn && ( undefined === this.Pr.TextOutline || false === this.Pr.TextOutline.IsIdentical(Value) ) ) )
    {
        var OldValue = this.Pr.TextOutline;
        this.Pr.TextOutline = Value;

        History.Add(new CChangesRunTextOutline(this, OldValue, Value, this.private_IsCollPrChangeMine()));

        this.Recalc_CompiledPr(false);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Get_Color = function()
{
    return this.Get_CompiledPr(false).Color;
};

ParaRun.prototype.Set_VertAlign = function(Value)
{
    if ( Value !== this.Pr.VertAlign )
    {
        var OldValue = this.Pr.VertAlign;
        this.Pr.VertAlign = Value;

        History.Add(new CChangesRunVertAlign(this, OldValue, Value, this.private_IsCollPrChangeMine()));

        this.Recalc_CompiledPr(true);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Get_VertAlign = function()
{
    return this.Get_CompiledPr(false).VertAlign;
};

ParaRun.prototype.Set_HighLight = function(Value)
{
    var OldValue = this.Pr.HighLight;
    if ( (undefined === Value && undefined !== OldValue) || ( highlight_None === Value && highlight_None !== OldValue ) || ( Value instanceof CDocumentColor && ( undefined === OldValue || highlight_None === OldValue || false === Value.Compare(OldValue) ) ) )
    {
        this.Pr.HighLight = Value;
        History.Add(new CChangesRunHighLight(this, OldValue, Value, this.private_IsCollPrChangeMine()));

        this.Recalc_CompiledPr(false);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Get_HighLight = function()
{
    return this.Get_CompiledPr(false).HighLight;
};

ParaRun.prototype.Set_RStyle = function(Value)
{
    if ( Value !== this.Pr.RStyle )
    {
        var OldValue = this.Pr.RStyle;
        this.Pr.RStyle = Value;

        History.Add(new CChangesRunRStyle(this, OldValue, Value, this.private_IsCollPrChangeMine()));

        this.Recalc_CompiledPr(true);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};
ParaRun.prototype.Get_RStyle = function()
{
	return this.Get_CompiledPr(false).RStyle;
};

ParaRun.prototype.Set_Spacing = function(Value)
{
    if (Value !== this.Pr.Spacing)
    {
        var OldValue = this.Pr.Spacing;
        this.Pr.Spacing = Value;

        History.Add(new CChangesRunSpacing(this, OldValue, Value, this.private_IsCollPrChangeMine()));

        this.Recalc_CompiledPr(true);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Get_Spacing = function()
{
    return this.Get_CompiledPr(false).Spacing;
};

ParaRun.prototype.Set_DStrikeout = function(Value)
{
    if ( Value !== this.Pr.DStrikeout )
    {
        var OldValue = this.Pr.DStrikeout;
        this.Pr.DStrikeout = Value;

        History.Add(new CChangesRunDStrikeout(this, OldValue, Value, this.private_IsCollPrChangeMine()));

        this.Recalc_CompiledPr(false);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Get_DStrikeout = function()
{
    return this.Get_CompiledPr(false).DStrikeout;
};

ParaRun.prototype.Set_Caps = function(Value)
{
    if ( Value !== this.Pr.Caps )
    {
        var OldValue = this.Pr.Caps;
        this.Pr.Caps = Value;

        History.Add(new CChangesRunCaps(this, OldValue, Value, this.private_IsCollPrChangeMine()));
        this.Recalc_CompiledPr(true);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Get_Caps = function()
{
    return this.Get_CompiledPr(false).Caps;
};

ParaRun.prototype.Set_SmallCaps = function(Value)
{
    if ( Value !== this.Pr.SmallCaps )
    {
        var OldValue = this.Pr.SmallCaps;
        this.Pr.SmallCaps = Value;

        History.Add(new CChangesRunSmallCaps(this, OldValue, Value, this.private_IsCollPrChangeMine()));
        this.Recalc_CompiledPr(true);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Get_SmallCaps = function()
{
    return this.Get_CompiledPr(false).SmallCaps;
};

ParaRun.prototype.Set_Position = function(Value)
{
    if ( Value !== this.Pr.Position )
    {
        var OldValue = this.Pr.Position;
        this.Pr.Position = Value;

        History.Add(new CChangesRunPosition(this, OldValue, Value, this.private_IsCollPrChangeMine()));
        this.Recalc_CompiledPr(false);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);

        this.YOffset = this.Get_Position();
    }
};

ParaRun.prototype.Get_Position = function()
{
    return this.Get_CompiledPr(false).Position;
};

ParaRun.prototype.Set_RFonts = function(Value)
{
    var OldValue = this.Pr.RFonts;
    this.Pr.RFonts = Value;

    History.Add(new CChangesRunRFonts(this, OldValue, Value, this.private_IsCollPrChangeMine()));

    this.Recalc_CompiledPr(true);
    this.private_UpdateTrackRevisionOnChangeTextPr(true);
};

ParaRun.prototype.Get_RFonts = function()
{
    return this.Get_CompiledPr(false).RFonts;
};

ParaRun.prototype.Set_RFonts2 = function(RFonts)
{
	if (undefined !== RFonts)
	{
		if (undefined !== RFonts.Ascii)
			this.Set_RFonts_Ascii(RFonts.Ascii);

		if (undefined !== RFonts.HAnsi)
			this.Set_RFonts_HAnsi(RFonts.HAnsi);

		if (undefined !== RFonts.CS)
			this.Set_RFonts_CS(RFonts.CS);

		if (undefined !== RFonts.EastAsia)
			this.Set_RFonts_EastAsia(RFonts.EastAsia);

		if (undefined !== RFonts.Hint)
			this.Set_RFonts_Hint(RFonts.Hint);
	}
	else
	{
		this.Set_RFonts_Ascii(undefined);
		this.Set_RFonts_HAnsi(undefined);
		this.Set_RFonts_CS(undefined);
		this.Set_RFonts_EastAsia(undefined);
		this.Set_RFonts_Hint(undefined);
	}
};
ParaRun.prototype.Set_RFont_ForMathRun = function()
{
    this.Set_RFonts_Ascii({Name : "Cambria Math", Index : -1});
    this.Set_RFonts_CS({Name : "Cambria Math", Index : -1});
    this.Set_RFonts_EastAsia({Name : "Cambria Math", Index : -1});
    this.Set_RFonts_HAnsi({Name : "Cambria Math", Index : -1});
};
ParaRun.prototype.Set_RFonts_Ascii = function(Value)
{
	var _Value = (null === Value ? undefined : Value);

	if (_Value !== this.Pr.RFonts.Ascii)
	{
		var OldValue         = this.Pr.RFonts.Ascii;
		this.Pr.RFonts.Ascii = _Value;

		History.Add(new CChangesRunRFontsAscii(this, OldValue, _Value, this.private_IsCollPrChangeMine()));
		this.Recalc_CompiledPr(true);
		this.private_UpdateTrackRevisionOnChangeTextPr(true);
	}
};
ParaRun.prototype.Set_RFonts_HAnsi = function(Value)
{
	var _Value = (null === Value ? undefined : Value);

	if (_Value !== this.Pr.RFonts.HAnsi)
	{
		var OldValue         = this.Pr.RFonts.HAnsi;
		this.Pr.RFonts.HAnsi = _Value;

		History.Add(new CChangesRunRFontsHAnsi(this, OldValue, _Value, this.private_IsCollPrChangeMine()));
		this.Recalc_CompiledPr(true);
		this.private_UpdateTrackRevisionOnChangeTextPr(true);
	}
};
ParaRun.prototype.Set_RFonts_CS = function(Value)
{
	var _Value = (null === Value ? undefined : Value);

	if (_Value !== this.Pr.RFonts.CS)
	{
		var OldValue      = this.Pr.RFonts.CS;
		this.Pr.RFonts.CS = _Value;

		History.Add(new CChangesRunRFontsCS(this, OldValue, _Value, this.private_IsCollPrChangeMine()));
		this.Recalc_CompiledPr(true);
		this.private_UpdateTrackRevisionOnChangeTextPr(true);
	}
};
ParaRun.prototype.Set_RFonts_EastAsia = function(Value)
{
	var _Value = (null === Value ? undefined : Value);

	if (_Value !== this.Pr.RFonts.EastAsia)
	{
		var OldValue            = this.Pr.RFonts.EastAsia;
		this.Pr.RFonts.EastAsia = _Value;

		History.Add(new CChangesRunRFontsEastAsia(this, OldValue, _Value, this.private_IsCollPrChangeMine()));
		this.Recalc_CompiledPr(true);
		this.private_UpdateTrackRevisionOnChangeTextPr(true);
	}
};
ParaRun.prototype.Set_RFonts_Hint = function(Value)
{
	var _Value = (null === Value ? undefined : Value);

	if (_Value !== this.Pr.RFonts.Hint)
	{
		var OldValue        = this.Pr.RFonts.Hint;
		this.Pr.RFonts.Hint = _Value;

		History.Add(new CChangesRunRFontsHint(this, OldValue, _Value, this.private_IsCollPrChangeMine()));
		this.Recalc_CompiledPr(true);
		this.private_UpdateTrackRevisionOnChangeTextPr(true);
	}
};

ParaRun.prototype.Set_Lang = function(Value)
{
    var OldValue = this.Pr.Lang;

    this.Pr.Lang = new CLang();
    if ( undefined != Value )
        this.Pr.Lang.Set_FromObject( Value );

    History.Add(new CChangesRunLang(this, OldValue, this.Pr.Lang, this.private_IsCollPrChangeMine()));
    this.Recalc_CompiledPr(false);
    this.private_UpdateTrackRevisionOnChangeTextPr(true);
};

ParaRun.prototype.Set_Lang2 = function(Lang)
{
    if ( undefined != Lang )
    {
        if ( undefined != Lang.Bidi )
            this.Set_Lang_Bidi( Lang.Bidi );

        if ( undefined != Lang.EastAsia )
            this.Set_Lang_EastAsia( Lang.EastAsia );

        if ( undefined != Lang.Val )
            this.Set_Lang_Val( Lang.Val );

        this.private_UpdateSpellChecking();
    }
};

ParaRun.prototype.Set_Lang_Bidi = function(Value)
{
    if ( Value !== this.Pr.Lang.Bidi )
    {
        var OldValue = this.Pr.Lang.Bidi;
        this.Pr.Lang.Bidi = Value;

		History.Add(new CChangesRunLangBidi(this, OldValue, Value, this.private_IsCollPrChangeMine()));
        this.Recalc_CompiledPr(false);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Set_Lang_EastAsia = function(Value)
{
    if ( Value !== this.Pr.Lang.EastAsia )
    {
        var OldValue = this.Pr.Lang.EastAsia;
        this.Pr.Lang.EastAsia = Value;

        History.Add(new CChangesRunLangEastAsia(this, OldValue, Value, this.private_IsCollPrChangeMine()));
        this.Recalc_CompiledPr(false);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Set_Lang_Val = function(Value)
{
    if ( Value !== this.Pr.Lang.Val )
    {
        var OldValue = this.Pr.Lang.Val;
        this.Pr.Lang.Val = Value;

        History.Add(new CChangesRunLangVal(this, OldValue, Value, this.private_IsCollPrChangeMine()));
        this.Recalc_CompiledPr(false);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};

ParaRun.prototype.Set_Shd = function(Shd)
{
    if ( (undefined === this.Pr.Shd && undefined === Shd) || (undefined !== this.Pr.Shd && undefined !== Shd && true === this.Pr.Shd.Compare( Shd ) ) )
        return;

    var OldShd = this.Pr.Shd;

    if ( undefined !== Shd )
    {
        this.Pr.Shd = new CDocumentShd();
        this.Pr.Shd.Set_FromObject( Shd );
    }
    else
        this.Pr.Shd = undefined;

    History.Add(new CChangesRunShd(this, OldShd, this.Pr.Shd, this.private_IsCollPrChangeMine()));
    this.Recalc_CompiledPr(false);
    this.private_UpdateTrackRevisionOnChangeTextPr(true);
};

//-----------------------------------------------------------------------------------
// Undo/Redo функции
//-----------------------------------------------------------------------------------
ParaRun.prototype.Check_HistoryUninon = function(Data1, Data2)
{
    var Type1 = Data1.Type;
    var Type2 = Data2.Type;

    if ( AscDFH.historyitem_ParaRun_AddItem === Type1 && AscDFH.historyitem_ParaRun_AddItem === Type2 )
    {
        if ( 1 === Data1.Items.length && 1 === Data2.Items.length && Data1.Pos === Data2.Pos - 1 && para_Text === Data1.Items[0].Type && para_Text === Data2.Items[0].Type )
            return true;
    }

    return false;
};
//-----------------------------------------------------------------------------------
// Функции для совместного редактирования
//-----------------------------------------------------------------------------------
ParaRun.prototype.Write_ToBinary2 = function(Writer)
{
    Writer.WriteLong( AscDFH.historyitem_type_ParaRun );

    // Long     : Type
    // String   : Id
    // String   : Paragraph Id
    // Variable : CTextPr
    // Long     : ReviewType
    // Bool     : isUndefined ReviewInfo
    // ->false  : ReviewInfo
    // Long     : Количество элементов
    // Array of variable : массив с элементами

    Writer.WriteLong(this.Type);
    var ParagraphToWrite, PrToWrite, ContentToWrite;
    if(this.StartState)
    {
        ParagraphToWrite = this.StartState.Paragraph;
        PrToWrite = this.StartState.Pr;
        ContentToWrite = this.StartState.Content;
    }
    else
    {
        ParagraphToWrite = this.Paragraph;
        PrToWrite = this.Pr;
        ContentToWrite = this.Content;
    }

    Writer.WriteString2( this.Id );
    Writer.WriteString2( null !== ParagraphToWrite && undefined !== ParagraphToWrite ? ParagraphToWrite.Get_Id() : "" );
    PrToWrite.Write_ToBinary( Writer );
    Writer.WriteLong(this.ReviewType);
    if (this.ReviewInfo)
    {
        Writer.WriteBool(false);
        this.ReviewInfo.Write_ToBinary(Writer);
    }
    else
    {
        Writer.WriteBool(true);
    }

    var Count = ContentToWrite.length;
    Writer.WriteLong( Count );
    for ( var Index = 0; Index < Count; Index++ )
    {
        var Item = ContentToWrite[Index];
        Item.Write_ToBinary( Writer );
    }
};

ParaRun.prototype.Read_FromBinary2 = function(Reader)
{
    // Long     : Type
    // String   : Id
    // String   : Paragraph Id
    // Variable : CTextPr
    // Long     : ReviewType
    // Bool     : isUndefined ReviewInfo
    // ->false  : ReviewInfo
    // Long     : Количество элементов
    // Array of variable : массив с элементами

    this.Type      = Reader.GetLong();
    this.Id        = Reader.GetString2();
    this.Paragraph = g_oTableId.Get_ById( Reader.GetString2() );
    this.Pr        = new CTextPr();
    this.Pr.Read_FromBinary( Reader );
    this.ReviewType = Reader.GetLong();
    this.ReviewInfo = new CReviewInfo();
    if (false === Reader.GetBool())
        this.ReviewInfo.Read_FromBinary(Reader);

    if (para_Math_Run == this.Type)
	{
        this.MathPrp = new CMPrp();
		this.size    = new CMathSize();
        this.pos     = new CMathPosition();
	}

    if(undefined !== editor && true === editor.isDocumentEditor)
    {
        var Count = Reader.GetLong();
        this.Content = [];
        for ( var Index = 0; Index < Count; Index++ )
        {
            var Element = ParagraphContent_Read_FromBinary( Reader );
            if ( null !== Element )
                this.Content.push( Element );
        }
    }
};

ParaRun.prototype.Clear_CollaborativeMarks = function()
{
    this.CollaborativeMarks.Clear();
    this.CollPrChangeOther = false;
};
ParaRun.prototype.private_AddCollPrChangeMine = function()
{
    this.CollPrChangeMine  = true;
    this.CollPrChangeOther = false;
};
ParaRun.prototype.private_IsCollPrChangeMine = function()
{
    if (true === this.CollPrChangeMine)
        return true;

    return false;
};
ParaRun.prototype.private_AddCollPrChangeOther = function(Color)
{
    this.CollPrChangeOther = Color;
    AscCommon.CollaborativeEditing.Add_ChangedClass(this);
};
ParaRun.prototype.private_GetCollPrChangeOther = function()
{
    return this.CollPrChangeOther;
};

ParaRun.prototype.private_RecalcCtrPrp = function()
{
    if (para_Math_Run === this.Type && undefined !== this.Parent && null !== this.Parent && null !== this.Parent.ParaMath)
        this.Parent.ParaMath.SetRecalcCtrPrp(this);
};
function CParaRunSelection()
{
    this.Use      = false;
    this.StartPos = 0;
    this.EndPos   = 0;
}

function CParaRunState()
{
    this.Selection  = new CParaRunSelection();
    this.ContentPos = 0;
}

function CParaRunRecalcInfo()
{
    this.TextPr  = true; // Нужно ли пересчитать скомпилированные настройки
    this.Measure = true; // Нужно ли перемерять элементы
    this.Recalc  = true; // Нужно ли пересчитывать (только если текстовый ран)
    this.RunLen  = 0;

    this.MeasurePositions = []; // Массив позиций элементов, которые нужно пересчитать

    // Далее идут параметры, которые выставляются после пересчета данного Range, такие как пересчитывать ли нумерацию
    this.NumberingItem = null;
    this.NumberingUse  = false; // Используется ли нумерация в данном ране
    this.NumberingAdd  = true;  // Нужно ли в следующем ране использовать нумерацию
}

CParaRunRecalcInfo.prototype.Reset = function()
{
	this.TextPr  = true;
	this.Measure = true;
	this.Recalc  = true;
	this.RunLen  = 0;

	this.MeasurePositions = [];
};
/**
 * Вызываем данную функцию после пересчета элементов рана
 */
CParaRunRecalcInfo.prototype.ResetMeasure = function()
{
	this.Measure          = false;
	this.MeasurePositions = [];
};
/**
 * Проверяем нужен ли пересчет элементов рана
 * @return {boolean}
 */
CParaRunRecalcInfo.prototype.IsMeasureNeed = function()
{
	return (this.Measure || this.MeasurePositions.length > 0);
};
/**
 * Регистрируем добавление элемента в ран
 * @param nPos {number}
 */
CParaRunRecalcInfo.prototype.OnAdd = function(nPos)
{
	for (var nIndex = 0, nCount = this.MeasurePositions.length; nIndex < nCount; ++nIndex)
	{
		if (this.MeasurePositions[nIndex] >= nPos)
			this.MeasurePositions[nIndex]++;
	}

	this.MeasurePositions.push(nPos);
};
/**
 * Регистрируем удаление элементов из рана
 * @param nPos {number}
 * @param nCount {number}
 */
CParaRunRecalcInfo.prototype.OnRemove = function(nPos, nCount)
{
	for (var nIndex = 0, nLen = this.MeasurePositions.length; nIndex < nLen; ++nIndex)
	{
		if (nPos <= this.MeasurePositions[nIndex] && this.MeasurePositions[nIndex] <= nPos + nCount - 1)
		{
			this.MeasurePositions.splice(nIndex, 1);
			nIndex--;
		}
		else if (this.MeasurePositions[nIndex] >= nPos + nCount)
		{
			this.MeasurePositions[nIndex] -= nCount;
		}
	}
};

function CParaRunRange(StartPos, EndPos)
{
    this.StartPos = StartPos; // Начальная позиция в контенте, с которой начинается данный отрезок
    this.EndPos   = EndPos;   // Конечная позиция в контенте, на которой заканчивается данный отрезок (перед которой)
}

function CParaRunLine()
{
    this.Ranges       = [];
    this.Ranges[0]    = new CParaRunRange( 0, 0 );
    this.RangesLength = 0;
}

CParaRunLine.prototype =
{
    Add_Range : function(RangeIndex, StartPos, EndPos)
    {
        if ( 0 !== RangeIndex )
        {
            this.Ranges[RangeIndex] = new CParaRunRange( StartPos, EndPos );
            this.RangesLength  = RangeIndex + 1;
        }
        else
        {
            this.Ranges[0].StartPos = StartPos;
            this.Ranges[0].EndPos   = EndPos;
            this.RangesLength = 1;
        }

        if ( this.Ranges.length > this.RangesLength )
            this.Ranges.legth = this.RangesLength;
    },

    Copy : function()
    {
        var NewLine = new CParaRunLine();

        NewLine.RangesLength = this.RangesLength;

        for ( var CurRange = 0; CurRange < this.RangesLength; CurRange++ )
        {
            var Range = this.Ranges[CurRange];
            NewLine.Ranges[CurRange] = new CParaRunRange( Range.StartPos, Range.EndPos );
        }

        return NewLine;
    },

    Compare : function(OtherLine, CurRange)
    {
        // Сначала проверим наличие данного отрезка в обеих строках
        if ( this.RangesLength <= CurRange || OtherLine.RangesLength <= CurRange )
            return false;

        var OtherRange = OtherLine.Ranges[CurRange];
        var ThisRange  = this.Ranges[CurRange];

        if ( OtherRange.StartPos !== ThisRange.StartPos || OtherRange.EndPos !== ThisRange.EndPos )
            return false;

        return true;
    }


};

// Метка о конце или начале изменений пришедших от других соавторов документа
var pararun_CollaborativeMark_Start = 0x00;
var pararun_CollaborativeMark_End   = 0x01;

function CParaRunCollaborativeMark(Pos, Type)
{
    this.Pos  = Pos;
    this.Type = Type;
}

function FontSize_IncreaseDecreaseValue(bIncrease, Value)
{
    // Закон изменения размеров :
    // 1. Если значение меньше 8, тогда мы увеличиваем/уменьшаем по 1 (от 1 до 8)
    // 2. Если значение больше 72, тогда мы увеличиваем/уменьшаем по 10 (от 80 до бесконечности
    // 3. Если значение в отрезке [8,72], тогда мы переходим по следующим числам 8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72

    var Sizes = [8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72];

    var NewValue = Value;
    if ( true === bIncrease )
    {
        if ( Value < Sizes[0] )
        {
            if ( Value >= Sizes[0] - 1 )
                NewValue = Sizes[0];
            else
                NewValue = Math.floor(Value + 1);
        }
        else if ( Value >= Sizes[Sizes.length - 1] )
        {
            NewValue = Math.min( 300, Math.floor( Value / 10 + 1 ) * 10 );
        }
        else
        {
            for ( var Index = 0; Index < Sizes.length; Index++ )
            {
                if ( Value < Sizes[Index] )
                {
                    NewValue = Sizes[Index];
                    break;
                }
            }
        }
    }
    else
    {
        if ( Value <= Sizes[0] )
        {
            NewValue = Math.max( Math.floor( Value - 1 ), 1 );
        }
        else if ( Value > Sizes[Sizes.length - 1] )
        {
            if ( Value <= Math.floor( Sizes[Sizes.length - 1] / 10 + 1 ) * 10 )
                NewValue = Sizes[Sizes.length - 1];
            else
                NewValue = Math.floor( Math.ceil(Value / 10) - 1 ) * 10;
        }
        else
        {
            for ( var Index = Sizes.length - 1; Index >= 0; Index-- )
            {
                if ( Value > Sizes[Index] )
                {
                    NewValue = Sizes[Index];
                    break;
                }
            }
        }
    }

    return NewValue;
}


function CRunCollaborativeMarks()
{
    this.Ranges = [];
    this.DrawingObj = {};
}

CRunCollaborativeMarks.prototype =
{
    Add : function(PosS, PosE, Color)
    {
        var Count = this.Ranges.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            var Range = this.Ranges[Index];

            if ( PosS > Range.PosE )
                continue;
            else if ( PosS >= Range.PosS && PosS <= Range.PosE && PosE >= Range.PosS && PosE <= Range.PosE )
            {
                if ( true !== Color.Compare(Range.Color) )
                {
                    var _PosE = Range.PosE;
                    Range.PosE = PosS;
                    this.Ranges.splice( Index + 1, 0, new CRunCollaborativeRange(PosS, PosE, Color) );
                    this.Ranges.splice( Index + 2, 0, new CRunCollaborativeRange(PosE, _PosE, Range.Color) );
                }

                return;
            }
            else if ( PosE < Range.PosS )
            {
                this.Ranges.splice( Index, 0, new CRunCollaborativeRange(PosS, PosE, Color) );
                return;
            }
            else if ( PosS < Range.PosS && PosE > Range.PosE )
            {
                Range.PosS = PosS;
                Range.PosE = PosE;
                Range.Color = Color;
                return;
            }
            else if ( PosS < Range.PosS ) // && PosE <= Range.PosE )
            {
                if ( true === Color.Compare(Range.Color) )
                    Range.PosS = PosS;
                else
                {
                    Range.PosS = PosE;
                    this.Ranges.splice( Index, 0, new CRunCollaborativeRange(PosS, PosE, Color) );
                }

                return;
            }
            else //if ( PosS >= Range.PosS && PosE > Range.Pos.E )
            {
                if ( true === Color.Compare(Range.Color) )
                    Range.PosE = PosE;
                else
                {
                    Range.PosE = PosS;
                    this.Ranges.splice( Index + 1, 0, new CRunCollaborativeRange(PosS, PosE, Color) );
                }

                return;
            }
        }

        this.Ranges.push( new CRunCollaborativeRange(PosS, PosE, Color) );
    },

    Update_OnAdd : function(Pos)
    {
        var Count = this.Ranges.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            var Range = this.Ranges[Index];

            if ( Pos <= Range.PosS )
            {
                Range.PosS++;
                Range.PosE++;
            }
            else if ( Pos > Range.PosS && Pos < Range.PosE )
            {
                var NewRange = new CRunCollaborativeRange( Pos + 1, Range.PosE + 1, Range.Color.Copy() );
                this.Ranges.splice( Index + 1, 0, NewRange );
                Range.PosE = Pos;
                Count++;
                Index++;
            }
            //else if ( Pos < Range.PosE )
            //    Range.PosE++;
        }
    },

    Update_OnRemove : function(Pos, Count)
    {
        var Len = this.Ranges.length;
        for ( var Index = 0; Index < Len; Index++ )
        {
            var Range = this.Ranges[Index];

            var PosE = Pos + Count;
            if ( Pos < Range.PosS )
            {
                if ( PosE <= Range.PosS )
                {
                    Range.PosS -= Count;
                    Range.PosE -= Count;
                }
                else if ( PosE >= Range.PosE )
                {
                    this.Ranges.splice( Index, 1 );
                    Len--;
                    Index--;continue;
                }
                else
                {
                    Range.PosS = Pos;
                    Range.PosE -= Count;
                }
            }
            else if ( Pos >= Range.PosS && Pos < Range.PosE )
            {
                if ( PosE >= Range.PosE )
                    Range.PosE = Pos;
                else
                    Range.PosE -= Count;
            }
            else
                continue;
        }
    },

    Clear : function()
    {
        this.Ranges = [];
    },

    Init_Drawing  : function()
    {
        this.DrawingObj = {};

        var Count = this.Ranges.length;
        for ( var CurPos = 0; CurPos < Count; CurPos++ )
        {
            var Range = this.Ranges[CurPos];

            for ( var Pos = Range.PosS; Pos < Range.PosE; Pos++ )
                this.DrawingObj[Pos] = Range.Color;
        }
    },

    Check : function(Pos)
    {
        if ( undefined !== this.DrawingObj[Pos] )
            return this.DrawingObj[Pos];

        return null;
    }
};

function CRunCollaborativeRange(PosS, PosE, Color)
{
    this.PosS  = PosS;
    this.PosE  = PosE;
    this.Color = Color;
}

ParaRun.prototype.Math_SetPosition = function(pos, PosInfo)
{
    var Line  = PosInfo.CurLine,
        Range = PosInfo.CurRange;

    var CurLine  = Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? Range - this.StartRange : Range );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    // запомним позицию для Recalculate_CurPos, когда  Run пустой
    this.pos.x = pos.x;
    this.pos.y = pos.y;

    for(var Pos = StartPos; Pos < EndPos; Pos++)
    {
        var Item = this.Content[Pos];
        if(PosInfo.DispositionOpers !== null && Item.Type == para_Math_BreakOperator)
        {
            PosInfo.DispositionOpers.push(pos.x + Item.GapLeft);
        }

        this.Content[Pos].setPosition(pos);
        pos.x += this.Content[Pos].Get_WidthVisible(); // Get_Width => Get_WidthVisible
                                                     // Get_WidthVisible - Width + Gaps с учетом настроек состояния
    }
};
ParaRun.prototype.Math_Get_StartRangePos = function(_CurLine, _CurRange, SearchPos, Depth, bStartLine)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);

    var Pos = this.State.ContentPos;
    var Result = true;

    if(bStartLine || StartPos < Pos)
    {
        SearchPos.Pos.Update(StartPos, Depth);
    }
    else
    {
        Result = false;
    }

    return Result;
};
ParaRun.prototype.Math_Get_EndRangePos = function(_CurLine, _CurRange, SearchPos, Depth, bEndLine)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange);

    var Pos = this.State.ContentPos;
    var Result = true;

    if(bEndLine  || Pos < EndPos)
    {
        SearchPos.Pos.Update(EndPos, Depth);
    }
    else
    {
        Result = false;
    }

    return Result;
};
ParaRun.prototype.Math_Is_End = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange);

    return EndPos == this.Content.length;
};
ParaRun.prototype.IsEmptyRange = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    return StartPos == EndPos;
};
ParaRun.prototype.Recalculate_Range_OneLine = function(PRS, ParaPr, Depth)
{
    // данная функция используется только для мат объектов, которые на строки не разбиваются

    // ParaText (ParagraphContent.js)
    // для настройки TextPr
    // Measure

    // FontClassification.js
    // Get_FontClass

    var Lng = this.Content.length;

    var CurLine  = PRS.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range );


    // обновляем позиции start и end для Range
    var RangeStartPos = this.protected_AddRange(CurLine, CurRange);
    var RangeEndPos = Lng;

    this.Math_RecalculateContent(PRS);

    this.protected_FillRange(CurLine, CurRange, RangeStartPos, RangeEndPos);
};
ParaRun.prototype.Math_RecalculateContent = function(PRS)
{
    var WidthPoints = this.Parent.Get_WidthPoints();
    this.bEqArray = this.Parent.IsEqArray();

    var ascent = 0, descent = 0, width = 0;

    this.Recalculate_MeasureContent();
    var Lng = this.Content.length;

    for(var i = 0 ; i < Lng; i++)
    {
        var Item = this.Content[i];
        var size = Item.size,
            Type = Item.Type;

        var WidthItem = Item.Get_WidthVisible(); // Get_Width => Get_WidthVisible
                                                 // Get_WidthVisible - Width + Gaps с учетом настроек состояния
        width += WidthItem;

        if(ascent < size.ascent)
            ascent = size.ascent;

        if (descent < size.height - size.ascent)
            descent = size.height - size.ascent;

        if(this.bEqArray)
        {
            if(Type === para_Math_Ampersand && true === Item.IsAlignPoint())
            {
                WidthPoints.AddNewAlignRange();
            }
            else
            {
                WidthPoints.UpdatePoint(WidthItem);
            }
        }
    }

    this.size.width  = width;
    this.size.ascent = ascent;
    this.size.height = ascent + descent;
};
ParaRun.prototype.Math_Set_EmptyRange = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = (0 === CurLine ? _CurRange - this.StartRange : _CurRange);

    var RangeStartPos = this.protected_AddRange(CurLine, CurRange);
    var RangeEndPos   = RangeStartPos;

    this.protected_FillRange(CurLine, CurRange, RangeStartPos, RangeEndPos);
};
// в этой функции проставляем состояние Gaps (крайние или нет) для всех операторов, к-ые участвуют в разбиении, чтобы не получилось случайно, что при изменении разбивки формулы на строки произошло, что у оператора не будет проставлен Gap
ParaRun.prototype.UpdateOperators = function(_CurLine, _CurRange, bEmptyGapLeft, bEmptyGapRight)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for(var Pos = StartPos; Pos < EndPos; Pos++)
    {
        var _bEmptyGapLeft  = bEmptyGapLeft && Pos == StartPos,
            _bEmptyGapRight = bEmptyGapRight && Pos == EndPos - 1;

        this.Content[Pos].Update_StateGapLeft(_bEmptyGapLeft);
        this.Content[Pos].Update_StateGapRight(_bEmptyGapRight);
    }
};
ParaRun.prototype.Math_Apply_Style = function(Value)
{
    if(Value !== this.MathPrp.sty)
    {
        var OldValue     = this.MathPrp.sty;
        this.MathPrp.sty = Value;

        History.Add(new CChangesRunMathStyle(this, OldValue, Value));

        this.Recalc_CompiledPr(true);
        this.private_UpdateTrackRevisionOnChangeTextPr(true);
    }
};
ParaRun.prototype.IsNormalText = function()
{
    var comp_MPrp = this.MathPrp.GetCompiled_ScrStyles();
    return comp_MPrp.nor === true;
};
ParaRun.prototype.getPropsForWrite = function()
{
    var prRPr = null, wRPrp = null;
    if(this.Paragraph && false === this.Paragraph.bFromDocument){
        prRPr = this.Pr.Copy();
    }
    else{
        wRPrp = this.Pr.Copy();
    }
    var mathRPrp = this.MathPrp.Copy();

    return {wRPrp: wRPrp, mathRPrp: mathRPrp, prRPrp: prRPr};
};
ParaRun.prototype.Get_MathPr = function(bCopy)
{
    if(this.Type = para_Math_Run)
    {
        if(bCopy)
            return this.MathPrp.Copy();
        else
            return this.MathPrp;
    }
};
ParaRun.prototype.Math_PreRecalc = function(Parent, ParaMath, ArgSize, RPI, GapsInfo)
{
    this.Parent    = Parent;
    this.Paragraph = ParaMath.Paragraph;

    var FontSize = this.Get_CompiledPr(false).FontSize;

    if(RPI.bChangeInline)
        this.RecalcInfo.Measure = true; // нужно сделать пересчет элементов, например для дроби, т.к. ArgSize у внутренних контентов будет другой => размер

    if(RPI.bCorrect_ConvertFontSize) // изменение FontSize после конвертации из старого формата в новый
    {
        var FontKoef;

        if(ArgSize == -1 || ArgSize == -2)
        {
            var Pr = new CTextPr();

            if(this.Pr.FontSize !== null && this.Pr.FontSize !== undefined)
            {
                FontKoef = MatGetKoeffArgSize(this.Pr.FontSize, ArgSize);
                Pr.FontSize = (((this.Pr.FontSize/FontKoef * 2 + 0.5) | 0) / 2);
                this.RecalcInfo.TextPr  = true;
                this.RecalcInfo.Measure = true;
            }

            if(this.Pr.FontSizeCS !== null && this.Pr.FontSizeCS !== undefined)
            {
                FontKoef = MatGetKoeffArgSize( this.Pr.FontSizeCS, ArgSize);
                Pr.FontSizeCS = (((this.Pr.FontSizeCS/FontKoef * 2 + 0.5) | 0) / 2);
                this.RecalcInfo.TextPr  = true;
                this.RecalcInfo.Measure = true;
            }

            this.Apply_Pr(Pr);
        }
    }

    for (var Pos = 0 ; Pos < this.Content.length; Pos++ )
    {
        if( !this.Content[Pos].IsAlignPoint() )
            GapsInfo.setGaps(this.Content[Pos], FontSize);

        this.Content[Pos].PreRecalc(this, ParaMath);
        this.Content[Pos].SetUpdateGaps(false);
    }

};
ParaRun.prototype.Math_GetRealFontSize = function(FontSize)
{
    var RealFontSize = FontSize ;

    if(FontSize !== null && FontSize !== undefined)
    {
        var ArgSize   = this.Parent.Compiled_ArgSz.value;
        RealFontSize  = FontSize*MatGetKoeffArgSize(FontSize, ArgSize);
    }

    return RealFontSize;
};
ParaRun.prototype.Math_CompareFontSize = function(ComparableFontSize, bStartLetter)
{
    var lng = this.Content.length;

    var Letter = this.Content[lng - 1];

    if(bStartLetter == true)
        Letter = this.Content[0];


    var CompiledPr = this.Get_CompiledPr(false);
    var LetterFontSize = Letter.Is_LetterCS() ? CompiledPr.FontSizeCS : CompiledPr.FontSize;

    return ComparableFontSize == this.Math_GetRealFontSize(LetterFontSize);
};
ParaRun.prototype.Math_EmptyRange = function(_CurLine, _CurRange) // до пересчета нужно узнать будет ли данный Run пустым или нет в данном Range, необходимо для того, чтобы выставить wrapIndent
{
    var bEmptyRange = true;
    var Lng = this.Content.length;

    if(Lng > 0)
    {
        var CurLine  = _CurLine - this.StartLine;
        var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

        bEmptyRange = this.protected_GetPrevRangeEndPos(CurLine, CurRange) >= Lng;
    }

    return bEmptyRange;
};
ParaRun.prototype.Math_UpdateGaps = function(_CurLine, _CurRange, GapsInfo)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var FontSize = this.Get_CompiledPr(false).FontSize;

    for(var Pos = StartPos; Pos < EndPos; Pos++)
    {
        GapsInfo.updateCurrentObject(this.Content[Pos], FontSize);

        var bUpdateCurrent = this.Content[Pos].IsNeedUpdateGaps();

        if(bUpdateCurrent || GapsInfo.bUpdate)
        {
            GapsInfo.updateGaps();
        }

        GapsInfo.bUpdate = bUpdateCurrent;

        this.Content[Pos].SetUpdateGaps(false);

    }
};
ParaRun.prototype.Math_Can_ModidyForcedBreak = function(Pr, bStart, bEnd)
{
    var Pos = this.Math_GetPosForcedBreak(bStart, bEnd);

    if(Pos !== null)
    {
        if(this.MathPrp.IsBreak())
        {
            Pr.Set_DeleteForcedBreak();
        }
        else
        {
            Pr.Set_InsertForcedBreak();
        }
    }

};
ParaRun.prototype.Math_GetPosForcedBreak = function(bStart, bEnd)
{
    var ResultPos = null;

    if(this.Content.length > 0)
    {
        var StartPos = this.Selection.StartPos,
            EndPos   = this.Selection.EndPos,
            bSelect  = this.Selection.Use;

        if(StartPos > EndPos)
        {
            StartPos = this.Selection.EndPos;
            EndPos   = this.Selection.StartPos;
        }

        var bCheckTwoItem = bSelect == false || (bSelect == true && EndPos == StartPos),
            bCheckOneItem = bSelect == true && EndPos - StartPos == 1;

        if(bStart)
        {
            ResultPos = this.Content[0].Type == para_Math_BreakOperator ? 0 : ResultPos;
        }
        else if(bEnd)
        {
            var lastPos = this.Content.length - 1;
            ResultPos = this.Content[lastPos].Type == para_Math_BreakOperator ? lastPos : ResultPos;
        }
        else if(bCheckTwoItem)
        {
            var Pos = bSelect == false ? this.State.ContentPos : StartPos;
            var bPrevBreakOperator  = Pos > 0 ? this.Content[Pos - 1].Type == para_Math_BreakOperator : false,
                bCurrBreakOperator  = Pos < this.Content.length ? this.Content[Pos].Type == para_Math_BreakOperator : false;

            if(bCurrBreakOperator)
            {
                ResultPos = Pos
            }
            else if(bPrevBreakOperator)
            {
                ResultPos = Pos - 1;
            }

        }
        else if(bCheckOneItem)
        {
            if(this.Content[StartPos].Type == para_Math_BreakOperator)
            {
                ResultPos = StartPos;
            }
        }
    }

    return ResultPos;
};
ParaRun.prototype.Check_ForcedBreak = function(bStart, bEnd)
{
    return this.Math_GetPosForcedBreak(bStart, bEnd) !== null;
};
ParaRun.prototype.Set_MathForcedBreak = function(bInsert)
{
	if (bInsert == true && false == this.MathPrp.IsBreak())
	{
		History.Add(new CChangesRunMathForcedBreak(this, true, undefined));
		this.MathPrp.Insert_ForcedBreak();
	}
	else if (bInsert == false && true == this.MathPrp.IsBreak())
	{
		History.Add(new CChangesRunMathForcedBreak(this, false, this.MathPrp.Get_AlnAt()));
		this.MathPrp.Delete_ForcedBreak();
	}
};
ParaRun.prototype.Math_SplitRunForcedBreak = function()
{
    var Pos =  this.Math_GetPosForcedBreak();
    var NewRun = null;

    if(Pos != null && Pos > 0) // разбиваем Run на два
    {
        NewRun = this.Split_Run(Pos);
    }

    return NewRun;
};
ParaRun.prototype.UpdLastElementForGaps = function(_CurLine, _CurRange, GapsInfo)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);
    var FontSize = this.Get_CompiledPr(false).FontSize;
    var Last     = this.Content[EndPos];

    GapsInfo.updateCurrentObject(Last, FontSize);

};
ParaRun.prototype.IsPlaceholder = function()
{
    return this.Content.length == 1 && this.Content[0].IsPlaceholder && this.Content[0].IsPlaceholder();
};
ParaRun.prototype.AddMathPlaceholder = function()
{
    var oPlaceholder = new CMathText(false);
	oPlaceholder.SetPlaceholder();
    this.Add_ToContent(0, oPlaceholder, false);
};
ParaRun.prototype.RemoveMathPlaceholder = function()
{
	for (var nPos = 0; nPos < this.Content.length; ++nPos)
	{
		if (para_Math_Placeholder === this.Content[nPos].Type)
		{
			this.Remove_FromContent(nPos, 1, true);
			nPos--;
		}
	}
};
ParaRun.prototype.Set_MathPr = function(MPrp)
{
    var OldValue = this.MathPrp;
    this.MathPrp.Set_Pr(MPrp);

    History.Add(new CChangesRunMathPrp(this, OldValue, this.MathPrp));
    this.Recalc_CompiledPr(true);
    this.private_UpdateTrackRevisionOnChangeTextPr(true);
};
ParaRun.prototype.Set_MathTextPr2 = function(TextPr, MathPr)
{
    this.Set_Pr(TextPr.Copy());
    this.Set_MathPr(MathPr.Copy());
};
ParaRun.prototype.IsAccent = function()
{
    return this.Parent.IsAccent();
};
ParaRun.prototype.GetCompiled_ScrStyles = function()
{
    return this.MathPrp.GetCompiled_ScrStyles();
};
ParaRun.prototype.IsEqArray = function()
{
    return this.Parent.IsEqArray();
};
ParaRun.prototype.IsForcedBreak = function()
{
    var bForcedBreak = false;

    if(this.ParaMath!== null)
        bForcedBreak = false == this.ParaMath.Is_Inline() && true == this.MathPrp.IsBreak();

    return bForcedBreak;
};
ParaRun.prototype.Is_StartForcedBreakOperator = function()
{
    var bStartOperator = this.Content.length > 0 && this.Content[0].Type == para_Math_BreakOperator;
    return true == this.IsForcedBreak() && true == bStartOperator;
};
ParaRun.prototype.Get_AlignBrk = function(_CurLine, bBrkBefore)
{
    // null      - break отсутствует
    // 0         - break присутствует, alnAt = undefined
    // Number    = break присутствует, alnAt = Number


    // если оператор находится в конце строки и по этому оператору осушествляется принудительный перенос (Forced)
    // тогда StartPos = 0, EndPos = 1 (для предыдущей строки), т.к. оператор с принудительным переносом всегда должен находится в начале Run

    var CurLine  = _CurLine - this.StartLine;
    var AlnAt = null;

    if(CurLine > 0)
    {
        var RangesCount = this.protected_GetRangesCount(CurLine - 1);
        var StartPos = this.protected_GetRangeStartPos(CurLine - 1, RangesCount - 1);
        var EndPos = this.protected_GetRangeEndPos(CurLine - 1, RangesCount - 1);

        var bStartBreakOperator = bBrkBefore == true && StartPos == 0 && EndPos == 0;
        var bEndBreakOperator   = bBrkBefore == false && StartPos == 0 && EndPos == 1;

        if(bStartBreakOperator || bEndBreakOperator)
        {
            AlnAt = false == this.Is_StartForcedBreakOperator() ? null : this.MathPrp.Get_AlignBrk();
        }
    }

    return AlnAt;
};
ParaRun.prototype.Math_Is_InclineLetter = function()
{
    var result = false;

    if(this.Content.length == 1)
        result = this.Content[0].Is_InclineLetter();

    return result;
};
ParaRun.prototype.GetMathTextPrForMenu = function()
{
    var TextPr = new CTextPr();

    if(this.IsPlaceholder())
        TextPr.Merge(this.Parent.GetCtrPrp());

    TextPr.Merge(this.Pr);

    var MathTextPr = this.MathPrp.Copy();
    var BI = MathTextPr.GetBoldItalic();

    TextPr.Italic = BI.Italic;
    TextPr.Bold   = BI.Bold;

    return TextPr;
};
ParaRun.prototype.ApplyPoints = function(PointsInfo)
{
    if(this.Parent.IsEqArray())
    {
        this.size.width = 0;

        for(var Pos = 0; Pos < this.Content.length; Pos++)
        {
            var Item = this.Content[Pos];
            if(Item.Type === para_Math_Ampersand && true === Item.IsAlignPoint())
            {
                PointsInfo.NextAlignRange();
                Item.size.width = PointsInfo.GetAlign();
            }

            this.size.width += this.Content[Pos].Get_WidthVisible(); // Get_Width => Get_WidthVisible
                                                                     // Get_WidthVisible - Width + Gaps с учетом настроек состояния
        }
    }
};
ParaRun.prototype.Get_TextForAutoCorrect = function(AutoCorrectEngine, RunPos)
{
    var ActionElement = AutoCorrectEngine.Get_ActionElement();
    var nCount = this.Content.length;
    for (var nPos = 0; nPos < nCount; nPos++)
    {
        var Item = this.Content[nPos];
        if (para_Math_Text === Item.Type || para_Math_BreakOperator === Item.Type)
        {
            AutoCorrectEngine.Add_Text(String.fromCharCode(Item.value), this, nPos, RunPos, Item.Pos);
        }
		else if (para_Math_Ampersand === Item.Type)
		{
			 AutoCorrectEngine.Add_Text('&', this, nPos, RunPos, Item.Pos);
		}

        if (Item === ActionElement)
        {
            AutoCorrectEngine.Stop_CollectText();
            break;
        }
    }

    if (null === AutoCorrectEngine.TextPr)
        AutoCorrectEngine.TextPr = this.Pr.Copy();

    if (null == AutoCorrectEngine.MathPr)
        AutoCorrectEngine.MathPr = this.MathPrp.Copy();
};
ParaRun.prototype.IsShade = function()
{
    var oShd = this.Get_CompiledPr(false).Shd;
    return !(oShd === undefined || c_oAscShdNil === oShd.Value);
};
ParaRun.prototype.Get_RangesByPos = function(Pos)
{
    var Ranges = [];
    var LinesCount = this.protected_GetLinesCount();
    for (var LineIndex = 0; LineIndex < LinesCount; LineIndex++)
    {
        var RangesCount = this.protected_GetRangesCount(LineIndex);
        for (var RangeIndex = 0; RangeIndex < RangesCount; RangeIndex++)
        {
            var StartPos = this.protected_GetRangeStartPos(LineIndex, RangeIndex);
            var EndPos   = this.protected_GetRangeEndPos(LineIndex, RangeIndex);

            if (StartPos <= Pos && Pos <= EndPos)
                Ranges.push({Range : (LineIndex === 0 ? RangeIndex + this.StartRange : RangeIndex), Line : LineIndex + this.StartLine});
        }
    }

    return Ranges;
};
ParaRun.prototype.CompareDrawingsLogicPositions = function(CompareObject)
{
    var Drawing1 = CompareObject.Drawing1;
    var Drawing2 = CompareObject.Drawing2;

    for (var Pos = 0, Count = this.Content.length; Pos < Count; Pos++)
    {
        var Item = this.Content[Pos];

        if (Item === Drawing1)
        {
            CompareObject.Result = 1;
            return;
        }
        else if (Item === Drawing2)
        {
            CompareObject.Result = -1;
            return;
        }
    }
};
ParaRun.prototype.Get_ReviewType = function()
{
    return this.ReviewType;
};
ParaRun.prototype.Get_ReviewInfo = function()
{
	return this.ReviewInfo;
};
ParaRun.prototype.Get_ReviewColor = function()
{
    if (this.ReviewInfo)
        return this.ReviewInfo.Get_Color();

    return REVIEW_COLOR;
};
ParaRun.prototype.Set_ReviewType = function(Value)
{
    if (Value !== this.ReviewType)
    {
        var OldReviewType = this.ReviewType;
        var OldReviewInfo = this.ReviewInfo.Copy();

        this.ReviewType = Value;
        this.ReviewInfo.Update();

		History.Add(new CChangesRunReviewType(this,
			{
				ReviewType : OldReviewType,
				ReviewInfo : OldReviewInfo
			},
			{
				ReviewType : this.ReviewType,
				ReviewInfo : this.ReviewInfo.Copy()
			}));
		this.private_UpdateTrackRevisions();
	}
};
ParaRun.prototype.Set_ReviewTypeWithInfo = function(ReviewType, ReviewInfo)
{
	History.Add(new CChangesRunReviewType(this,
		{
			ReviewType : this.ReviewType,
			ReviewInfo : this.ReviewInfo ? this.ReviewInfo.Copy() : undefined
		},
		{
			ReviewType : ReviewType,
			ReviewInfo : ReviewInfo ? ReviewInfo.Copy() : undefined
		}));

	this.ReviewType = ReviewType;
	this.ReviewInfo = ReviewInfo;

	this.private_UpdateTrackRevisions();
};
ParaRun.prototype.Get_Parent = function()
{
	return this.GetParent();
};
ParaRun.prototype.private_GetPosInParent = function(_Parent)
{
	return this.GetPosInParent(_Parent);
};
ParaRun.prototype.Make_ThisElementCurrent = function(bUpdateStates)
{
    if (this.Is_UseInDocument())
    {
        var ContentPos = this.Paragraph.Get_PosByElement(this);
        ContentPos.Add(this.State.ContentPos);
        this.Paragraph.Set_ParaContentPos(ContentPos, true, -1, -1, false);
        this.Paragraph.Document_SetThisElementCurrent(true === bUpdateStates ? true : false);
    }
};
ParaRun.prototype.SetThisElementCurrent = function()
{
	var ContentPos = this.Paragraph.Get_PosByElement(this);
	if (!ContentPos)
		return;

	var StartPos = ContentPos.Copy();
	this.Get_StartPos(StartPos, StartPos.Get_Depth() + 1);

	this.Paragraph.Set_ParaContentPos(StartPos, true, -1, -1, false);
	this.Paragraph.Document_SetThisElementCurrent(false);
};
ParaRun.prototype.GetAllParagraphs = function(Props, ParaArray)
{
    var ContentLen = this.Content.length;
    for (var CurPos = 0; CurPos < ContentLen; CurPos++)
    {
        if (para_Drawing == this.Content[CurPos].Type)
            this.Content[CurPos].GetAllParagraphs(Props, ParaArray);
    }
};
ParaRun.prototype.Check_RevisionsChanges = function(Checker, ContentPos, Depth)
{
    if (this.Is_Empty())
        return;

    if (true !== Checker.Is_ParaEndRun() && true !== Checker.Is_CheckOnlyTextPr())
    {
        var ReviewType = this.Get_ReviewType();
        if (ReviewType !== Checker.Get_AddRemoveType() || (reviewtype_Common !== ReviewType && this.ReviewInfo.Get_UserId() !== Checker.Get_AddRemoveUserId()))
        {
            Checker.Flush_AddRemoveChange();
            ContentPos.Update(0, Depth);

            if (reviewtype_Add === ReviewType || reviewtype_Remove === ReviewType)
                Checker.Start_AddRemove(ReviewType, ContentPos);
        }

        if (reviewtype_Add === ReviewType || reviewtype_Remove === ReviewType)
        {
            var Text = "";
            var ContentLen = this.Content.length;
            for (var CurPos = 0; CurPos < ContentLen; CurPos++)
            {
                var Item = this.Content[CurPos];
                var ItemType = Item.Type;
                switch (ItemType)
                {
                    case para_Drawing:
                    {
                        Checker.Add_Text(Text);
                        Text = "";
                        Checker.Add_Drawing(Item);
                        break;
                    }
                    case para_Text :
                    {
                        Text += String.fromCharCode(Item.Value);
                        break;
                    }
                    case para_Math_Text:
                    {
                        Text += String.fromCharCode(Item.getCodeChr());
                        break;
                    }
                    case para_Space:
                    case para_Tab  :
                    {
                        Text += " ";
                        break;
                    }
                }
            }
            Checker.Add_Text(Text);
            ContentPos.Update(this.Content.length, Depth);
            Checker.Set_AddRemoveEndPos(ContentPos);
            Checker.Update_AddRemoveReviewInfo(this.ReviewInfo);
        }
    }

    var HavePrChange = this.Have_PrChange();
    var DiffPr = this.Get_DiffPrChange();
    if (HavePrChange !== Checker.Have_PrChange() || true !== Checker.Compare_PrChange(DiffPr) || this.Pr.ReviewInfo.Get_UserId() !== Checker.Get_PrChangeUserId())
    {
        Checker.Flush_TextPrChange();
        ContentPos.Update(0, Depth);
        if (true === HavePrChange)
        {
            Checker.Start_PrChange(DiffPr, ContentPos);
        }
    }

    if (true === HavePrChange)
    {
        ContentPos.Update(this.Content.length, Depth);
        Checker.Set_PrChangeEndPos(ContentPos);
        Checker.Update_PrChangeReviewInfo(this.Pr.ReviewInfo);
    }
};
ParaRun.prototype.private_UpdateTrackRevisionOnChangeContent = function(bUpdateInfo)
{
    if (reviewtype_Common !== this.Get_ReviewType())
    {
        this.private_UpdateTrackRevisions();

        if (true === bUpdateInfo && this.Paragraph && this.Paragraph.LogicDocument && this.Paragraph.bFromDocument && true === this.Paragraph.LogicDocument.Is_TrackRevisions() && this.ReviewInfo && true === this.ReviewInfo.Is_CurrentUser())
        {
            var OldReviewInfo = this.ReviewInfo.Copy();
            this.ReviewInfo.Update();
            History.Add(new CChangesRunContentReviewInfo(this, OldReviewInfo, this.ReviewInfo.Copy()));
        }
    }
};
ParaRun.prototype.private_UpdateTrackRevisionOnChangeTextPr = function(bUpdateInfo)
{
    if (true === this.Have_PrChange())
    {
        this.private_UpdateTrackRevisions();

        if (true === bUpdateInfo && this.Paragraph && this.Paragraph.bFromDocument && this.Paragraph.LogicDocument && true === this.Paragraph.LogicDocument.Is_TrackRevisions())
        {
            var OldReviewInfo = this.Pr.ReviewInfo.Copy();
            this.Pr.ReviewInfo.Update();
            History.Add(new CChangesRunPrReviewInfo(this, OldReviewInfo, this.Pr.ReviewInfo.Copy()));
        }
    }
};
ParaRun.prototype.private_UpdateTrackRevisions = function()
{
    if (this.Paragraph && this.Paragraph.bFromDocument && this.Paragraph.LogicDocument && this.Paragraph.LogicDocument.Get_TrackRevisionsManager)
    {
        var RevisionsManager = this.Paragraph.LogicDocument.Get_TrackRevisionsManager();
        RevisionsManager.Check_Paragraph(this.Paragraph);
    }
};
ParaRun.prototype.AcceptRevisionChanges = function(Type, bAll)
{
    var Parent = this.Get_Parent();
    var RunPos = this.private_GetPosInParent();

    var ReviewType = this.Get_ReviewType();
    var HavePrChange = this.Have_PrChange();

    // Нет изменений в данном ране
    if (reviewtype_Common === ReviewType && true !== HavePrChange)
        return;

    if (true === this.Selection.Use || true === bAll)
    {
        var StartPos = this.Selection.StartPos;
        var EndPos = this.Selection.EndPos;
        if (StartPos > EndPos)
        {
            StartPos = this.Selection.EndPos;
            EndPos = this.Selection.StartPos;
        }

        if (true === bAll)
        {
            StartPos = 0;
            EndPos   = this.Content.length;
        }

        var CenterRun = null, CenterRunPos = RunPos;
        if (0 === StartPos && this.Content.length === EndPos)
        {
            CenterRun = this;
        }
        else if (StartPos > 0 && this.Content.length === EndPos)
        {
            CenterRun = this.Split2(StartPos, Parent, RunPos);
            CenterRunPos = RunPos + 1;
        }
        else if (0 === StartPos && this.Content.length > EndPos)
        {
            CenterRun = this;
            this.Split2(EndPos, Parent, RunPos);
        }
        else
        {
            this.Split2(EndPos, Parent, RunPos);
            CenterRun = this.Split2(StartPos, Parent, RunPos);
            CenterRunPos = RunPos + 1;
        }

        if (true === HavePrChange && (undefined === Type || c_oAscRevisionsChangeType.TextPr === Type))
        {
            CenterRun.Remove_PrChange();
        }

        if (reviewtype_Add === ReviewType && (undefined === Type || c_oAscRevisionsChangeType.TextAdd === Type))
        {
            CenterRun.Set_ReviewType(reviewtype_Common);
        }
        else if (reviewtype_Remove === ReviewType && (undefined === Type || c_oAscRevisionsChangeType.TextRem === Type))
        {
            Parent.Remove_FromContent(CenterRunPos, 1);

            if (Parent.Get_ContentLength() <= 0)
            {
                Parent.RemoveSelection();
                Parent.Add_ToContent(0, new ParaRun());
                Parent.MoveCursorToStartPos();
            }
        }
    }
};
ParaRun.prototype.RejectRevisionChanges = function(Type, bAll)
{
    var Parent = this.Get_Parent();
    var RunPos = this.private_GetPosInParent();

    var ReviewType = this.Get_ReviewType();
    var HavePrChange = this.Have_PrChange();

    // Нет изменений в данном ране
    if (reviewtype_Common === ReviewType && true !== HavePrChange)
        return;

    if (true === this.Selection.Use || true === bAll)
    {
        var StartPos = this.Selection.StartPos;
        var EndPos = this.Selection.EndPos;
        if (StartPos > EndPos)
        {
            StartPos = this.Selection.EndPos;
            EndPos = this.Selection.StartPos;
        }

        if (true === bAll)
        {
            StartPos = 0;
            EndPos   = this.Content.length;
        }

        var CenterRun = null, CenterRunPos = RunPos;
        if (0 === StartPos && this.Content.length === EndPos)
        {
            CenterRun = this;
        }
        else if (StartPos > 0 && this.Content.length === EndPos)
        {
            CenterRun = this.Split2(StartPos, Parent, RunPos);
            CenterRunPos = RunPos + 1;
        }
        else if (0 === StartPos && this.Content.length > EndPos)
        {
            CenterRun = this;
            this.Split2(EndPos, Parent, RunPos);
        }
        else
        {
            this.Split2(EndPos, Parent, RunPos);
            CenterRun = this.Split2(StartPos, Parent, RunPos);
            CenterRunPos = RunPos + 1;
        }

        if (true === HavePrChange && (undefined === Type || c_oAscRevisionsChangeType.TextPr === Type))
        {
            CenterRun.Set_Pr(CenterRun.Pr.PrChange);
        }

        if (reviewtype_Add === ReviewType && (undefined === Type || c_oAscRevisionsChangeType.TextAdd === Type))
        {
            Parent.Remove_FromContent(CenterRunPos, 1);

            if (Parent.Get_ContentLength() <= 0)
            {
                Parent.RemoveSelection();
                Parent.Add_ToContent(0, new ParaRun());
                Parent.MoveCursorToStartPos();
            }
        }
        else if (reviewtype_Remove === ReviewType && (undefined === Type || c_oAscRevisionsChangeType.TextRem === Type))
        {
            CenterRun.Set_ReviewType(reviewtype_Common);
        }
    }
};
ParaRun.prototype.Is_InHyperlink = function()
{
    if (!this.Paragraph)
        return false;

    var ContentPos = this.Paragraph.Get_PosByElement(this);
    var Classes    = this.Paragraph.Get_ClassesByPos(ContentPos);

    var bHyper = false;
    var bRun   = false;

    for (var Index = 0, Count = Classes.length; Index < Count; Index++)
    {
        var Item = Classes[Index];
        if (Item === this)
        {
            bRun = true;
            break;
        }
        else if (Item instanceof ParaHyperlink)
        {
            bHyper = true;
        }
    }

    return (bHyper && bRun);
};
ParaRun.prototype.Get_ClassesByPos = function(Classes, ContentPos, Depth)
{
    Classes.push(this);
};
ParaRun.prototype.GetDocumentPositionFromObject = function(PosArray)
{
    if (!PosArray)
        PosArray = [];

    if (this.Paragraph)
    {
        var ParaContentPos = this.Paragraph.Get_PosByElement(this);
        if (null !== ParaContentPos)
        {
            var Depth = ParaContentPos.Get_Depth();
            while (Depth > 0)
            {
                var Pos = ParaContentPos.Get(Depth);
                ParaContentPos.Decrease_Depth(1);
                var Class = this.Paragraph.Get_ElementByPos(ParaContentPos);
                Depth--;

                PosArray.splice(0, 0, {Class : Class, Position : Pos});
            }
            PosArray.splice(0, 0, {Class : this.Paragraph, Position : ParaContentPos.Get(0)});
        }

        this.Paragraph.GetDocumentPositionFromObject(PosArray);
    }

    return PosArray;
};
ParaRun.prototype.Is_UseInParagraph = function()
{
    if (!this.Paragraph)
        return false;

    var ContentPos = this.Paragraph.Get_PosByElement(this);
    if (!ContentPos)
        return false;

    return true;
};
ParaRun.prototype.Displace_BreakOperator = function(isForward, bBrkBefore, CountOperators)
{
    var bResult = true;
    var bFirstItem = this.State.ContentPos == 0 || this.State.ContentPos == 1,
        bLastItem  = this.State.ContentPos == this.Content.length - 1 || this.State.ContentPos == this.Content.length;

    if(true === this.Is_StartForcedBreakOperator() && bFirstItem == true)
    {
        var AlnAt = this.MathPrp.Get_AlnAt();

        var NotIncrease = AlnAt == CountOperators && isForward == true;

        if(NotIncrease == false)
        {
            this.MathPrp.Displace_Break(isForward);

            var NewAlnAt = this.MathPrp.Get_AlnAt();

            if(AlnAt !== NewAlnAt)
            {
                History.Add(new CChangesRunMathAlnAt(this, AlnAt, NewAlnAt));
            }
        }
    }
    else
    {
        bResult = (bLastItem && bBrkBefore) || (bFirstItem && !bBrkBefore) ? false : true;
    }

    return bResult; // применили смещение к данному Run
};
ParaRun.prototype.Math_UpdateLineMetrics = function(PRS, ParaPr)
{
    var LineRule = ParaPr.Spacing.LineRule;

    // Пересчитаем метрику строки относительно размера данного текста
    if ( PRS.LineTextAscent < this.TextAscent )
        PRS.LineTextAscent = this.TextAscent;

    if ( PRS.LineTextAscent2 < this.TextAscent2 )
        PRS.LineTextAscent2 = this.TextAscent2;

    if ( PRS.LineTextDescent < this.TextDescent )
        PRS.LineTextDescent = this.TextDescent;

    if ( Asc.linerule_Exact === LineRule )
    {
        // Смещение не учитывается в метриках строки, когда расстояние между строк точное
        if ( PRS.LineAscent < this.TextAscent )
            PRS.LineAscent = this.TextAscent;

        if ( PRS.LineDescent < this.TextDescent )
            PRS.LineDescent = this.TextDescent;
    }
    else
    {
        if ( PRS.LineAscent < this.TextAscent + this.YOffset  )
            PRS.LineAscent = this.TextAscent + this.YOffset;

        if ( PRS.LineDescent < this.TextDescent - this.YOffset )
            PRS.LineDescent = this.TextDescent - this.YOffset;
    }

};
ParaRun.prototype.Set_CompositeInput = function(oCompositeInput)
{
    this.CompositeInput = oCompositeInput;
};
ParaRun.prototype.Get_FootnotesList = function(oEngine)
{
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		var oItem = this.Content[nIndex];
		if (para_FootnoteReference === oItem.Type)
		{
			oEngine.Add(oItem.Get_Footnote(), oItem, this);
		}
	}
};
ParaRun.prototype.Is_UseInDocument = function()
{
	return (this.Paragraph && true === this.Paragraph.Is_UseInDocument() && true === this.Is_UseInParagraph() ? true : false);
};
ParaRun.prototype.GetParaEnd = function()
{
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		if (this.Content[nIndex].Type === para_End)
			return this.Content[nIndex];
	}

	return null;
};
ParaRun.prototype.RemoveElement = function(oElement)
{
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		if (oElement === this.Content[nIndex])
			return this.Remove_FromContent(nIndex, 1, true);
	}
};
ParaRun.prototype.GotoFootnoteRef = function(isNext, isCurrent, isStepOver)
{
	var nPos = 0;
	if (true === isCurrent)
	{
		if (true === this.Selection.Use)
			nPos = Math.min(this.Selection.StartPos, this.Selection.EndPos);
		else
			nPos = this.State.ContentPos;
	}
	else
	{
		if (true === isNext)
			nPos = 0;
		else
			nPos = this.Content.length - 1;
	}

	var nResult = 0;
	if (true === isNext)
	{
		for (var nIndex = nPos, nCount = this.Content.length; nIndex < nCount; ++nIndex)
		{
			if (para_FootnoteReference === this.Content[nIndex].Type && ((true !== isCurrent && true === isStepOver) || (true === isCurrent && (true === this.Selection.Use || nPos !== nIndex))))
			{
				if (this.Paragraph && this.Paragraph.bFromDocument && this.Paragraph.LogicDocument)
					this.Paragraph.LogicDocument.RemoveSelection();

				this.State.ContentPos = nIndex;
				this.Make_ThisElementCurrent(true);
				return -1;
			}
			nResult++;
		}
	}
	else
	{
		for (var nIndex = Math.min(nPos, this.Content.length - 1); nIndex >= 0; --nIndex)
		{
			if (para_FootnoteReference === this.Content[nIndex].Type && ((true !== isCurrent && true === isStepOver) || (true === isCurrent && (true === this.Selection.Use || nPos !== nIndex))))
			{
				if (this.Paragraph && this.Paragraph.bFromDocument && this.Paragraph.LogicDocument)
					this.Paragraph.LogicDocument.RemoveSelection();

				this.State.ContentPos = nIndex;
				this.Make_ThisElementCurrent(true);
				return -1;
			}
			nResult++;
		}
	}

	return nResult;
};
ParaRun.prototype.GetFootnoteRefsInRange = function(arrFootnotes, _CurLine, _CurRange)
{
	var CurLine = _CurLine - this.StartLine;
	var CurRange = (0 === CurLine ? _CurRange - this.StartRange : _CurRange);

	var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
	var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

	for (var CurPos = StartPos; CurPos < EndPos; CurPos++)
	{
		if (para_FootnoteReference === this.Content[CurPos].Type)
			arrFootnotes.push(this.Content[CurPos]);
	}
};
ParaRun.prototype.GetAllContentControls = function(arrContentControls)
{
	if (!arrContentControls)
		return;

	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		var oItem = this.Content[nIndex];
		if (para_Drawing === oItem.Type || para_FootnoteReference === oItem.Type)
		{
			oItem.GetAllContentControls(arrContentControls);
		}
	}
};
/**
 * Получаем позицию заданного элемента
 * @param oElement
 * @returns {number} позиция, либо -1, если заданного элемента нет
 */
ParaRun.prototype.GetElementPosition = function(oElement)
{
	for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos)
	{
		if (oElement === this.Content[nPos])
			return nPos;
	}

	return -1;
};
/**
 * Устанавливаем текущее положение позиции курсора в данном ране
 * @param nPos
 */
ParaRun.prototype.SetCursorPosition = function(nPos)
{
	this.State.ContentPos = Math.max(0, Math.min(nPos, this.Content.length));
};
/**
 * Получаем номер строки по заданной позиции.
 * @param nPos
 */
ParaRun.prototype.GetLineByPosition = function(nPos)
{
	for (var nLineIndex = 0, nLinesCount = this.protected_GetLinesCount(); nLineIndex < nLinesCount; ++nLineIndex)
	{
		for (var nRangeIndex = 0, nRangesCount = this.protected_GetRangesCount(nLineIndex); nRangeIndex < nRangesCount; ++nRangeIndex)
		{
			var nStartPos = this.protected_GetRangeStartPos(nLineIndex, nRangeIndex);
			var nEndPos   = this.protected_GetRangeEndPos(nLineIndex, nRangeIndex);

			if (nPos >= nStartPos && nPos < nEndPos)
				return nLineIndex + this.StartLine;
		}
	}

	return this.StartLine;
};
/**
 * Данная функция вызывается перед удалением данного рана из родительского класса.
 */
ParaRun.prototype.PreDelete = function()
{
};
ParaRun.prototype.GetCurrentComplexFields = function(arrComplexFields, isCurrent, isFieldPos)
{
	var nEndPos = isCurrent ? this.State.ContentPos : this.Content.length;
	for (var nPos = 0; nPos < nEndPos; ++nPos)
	{
		var oItem = this.Content[nPos];
		if (oItem.Type !== para_FieldChar)
			continue;

		if (isFieldPos)
		{
			var oComplexField = oItem.GetComplexField();
			if (oItem.IsBegin())
			{
				arrComplexFields.push(new CComplexFieldStatePos(oComplexField, true));
			}
			else if (oItem.IsSeparate())
			{
				if (arrComplexFields.length > 0)
				{
					arrComplexFields[arrComplexFields.length - 1].SetFieldCode(false)
				}
			}
			else if (oItem.IsEnd())
			{
				if (arrComplexFields.length > 0)
				{
					arrComplexFields.splice(arrComplexFields.length - 1, 1);
				}
			}
		}
		else
		{
			if (oItem.IsBegin())
			{
				arrComplexFields.push(oItem.GetComplexField());
			}
			else if (oItem.IsEnd())
			{
				if (arrComplexFields.length > 0)
				{
					arrComplexFields.splice(arrComplexFields.length - 1, 1);
				}
			}
		}
	}
};
ParaRun.prototype.RemoveTabsForTOC = function(_isTab)
{
	var isTab = _isTab;
	for (var nPos = 0; nPos < this.Content.length; ++nPos)
	{
		if (para_Tab === this.Content[nPos].Type)
		{
			if (!isTab)
			{
				// Первый таб в параграфе оставляем
				isTab = true;
			}
			else
			{
				this.Remove_FromContent(nPos, 1);
			}
		}
	}

	return isTab;
};
ParaRun.prototype.AddToContent = function(nPos, oItem, isUpdatePositions)
{
	return this.Add_ToContent(nPos, oItem, isUpdatePositions);
};
ParaRun.prototype.RemoveFromContent = function(nPos, nCount, isUpdatePositions)
{
	return this.Remove_FromContent(nPos, nCount, isUpdatePositions);
};
ParaRun.prototype.GetComplexField = function(nType)
{
	for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos)
	{
		var oItem = this.Content[nPos];

		if (para_FieldChar === oItem.Type && oItem.IsBegin())
		{
			var oComplexField = oItem.GetComplexField();
			if (!oComplexField)
				continue;

			var oInstruction = oComplexField.GetInstruction();
			if (!oInstruction)
				continue;

			if (nType === oInstruction.GetType())
				return oComplexField;
		}
	}
	return null;
};
ParaRun.prototype.GetComplexFieldsArray = function(nType, arrComplexFields)
{
	for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos)
	{
		var oItem = this.Content[nPos];

		if (para_FieldChar === oItem.Type && oItem.IsBegin())
		{
			var oComplexField = oItem.GetComplexField();
			if (!oComplexField)
				continue;

			var oInstruction = oComplexField.GetInstruction();
			if (!oInstruction)
				continue;

			if (nType === oInstruction.GetType())
				arrComplexFields.push(oComplexField);
		}
	}
};
/**
 * Получаем количетсво элементов в ране
 * @returns {Number}
 */
ParaRun.prototype.GetElementsCount = function()
{
	return this.Content.length;
};
/**
 * Проверяем является ли данный ран специальным, содержащим ссылку на сноску
 * @returns {boolean}
 */
ParaRun.prototype.IsFootnoteReferenceRun = function()
{
	return (1 === this.Content.length && para_FootnoteReference === this.Content[0].Type);
};
/**
 * Производим автозамену
 * @param nPos - позиция, на которой был добавлен последний элемент, с которого стартовала автозамена
 * @returns {boolean}
 */
ParaRun.prototype.ProcessAutoCorrect = function(nPos)
{
	// Сколько максимально просматриваем элементов влево
	var nMaxElements = 10;

	var oParagraph = this.GetParagraph();
	if (!oParagraph)
		return false;

	var oDocument = oParagraph.LogicDocument;
	if (!oDocument || !(oDocument instanceof CDocument))
		return false;

	var oContentPos = oParagraph.Get_PosByElement(this);
	if (!oContentPos)
		return false;

	oContentPos.Update(nPos, oContentPos.GetDepth() + 1);

	if (para_Text === this.Content[nPos].Type && (34 === this.Content[nPos].Value || 39 === this.Content[nPos].Value))
	{
		if (oDocument.IsAutoCorrectSmartQuotes())
		{
			var isOpenQuote = true;

			var oRunElementsBefore = new CParagraphRunElements(oContentPos, 1, null, false);
			oParagraph.GetPrevRunElements(oRunElementsBefore);
			var arrElements = oRunElementsBefore.GetElements();
			if (arrElements.length > 0)
			{
				var oPrevElement = arrElements[0];
				if (para_Text === oPrevElement.Type && 45 !== oPrevElement.Value)
					isOpenQuote = false;
			}

			var nCharCode = (34 === this.Content[nPos].Value ? (isOpenQuote ? 8220 : 8221) : (isOpenQuote ? 8216 : 8217));

			// Проверку на лок можно не делать, т.к. мы собираемся менять содержимое данного рана, а такую проверку мы уже делали

			oDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_AutoCorrectSmartQuotes);

			this.RemoveFromContent(nPos, 1);
			this.AddToContent(nPos, new ParaText(nCharCode));
			this.State.ContentPos = nPos + 1;
			return true;
		}
		return false;
	}
	else if (para_Text === this.Content[nPos].Type && 45 === this.Content[nPos].Value)
	{
		if (oDocument.IsAutoCorrectHyphensWithDash())
		{
			var oRunElementsBefore = new CParagraphRunElements(oContentPos, 1, null, false);
			oRunElementsBefore.SetSaveContentPositions(true);
			oParagraph.GetPrevRunElements(oRunElementsBefore);
			var arrElements = oRunElementsBefore.GetElements();
			if (arrElements.length > 0 && para_Text === arrElements[0].Type && 45 === arrElements[0].Value)
			{
				oDocument.Create_NewHistoryPoint(AscDFH.Document_AutoCorrectHyphensWithDash);

				var oDash = new ParaText(8212);
				this.AddToContent(nPos + 1, oDash);
				var oStartPos = oRunElementsBefore.GetContentPositions()[0];
				var oEndPos   = oContentPos;
				oContentPos.Update(nPos + 1, oContentPos.GetDepth());

				oParagraph.RemoveSelection();
				oParagraph.SetSelectionUse(true);
				oParagraph.SetSelectionContentPos(oStartPos, oEndPos, false);
				oParagraph.Remove(1);
				oParagraph.RemoveSelection();

				// TODO:
				for (var nTempPos = 0, nCount = this.Content.length; nTempPos < nCount; ++nTempPos)
				{
					if (this.Content[nTempPos] === oDash)
					{
						this.State.ContentPos = nTempPos + 1;
						break;
					}
				}

				return true;
			}
		}
		return false;
	}

	var oRunElementsBefore = new CParagraphRunElements(oContentPos, nMaxElements, null, true);
	oParagraph.GetPrevRunElements(oRunElementsBefore);
	var arrElements = oRunElementsBefore.GetElements();
	if (arrElements.length <= 0)
		return false;

	var sText = "";
	for (var nIndex = 0, nCount = arrElements.length; nIndex < nCount; ++nIndex)
	{
		if (para_Text !== arrElements[nIndex].Type)
			return false;

		sText += String.fromCharCode(arrElements[nIndex].Value);
	}

	// Автосоздание списка
	if (oParagraph.GetNumPr())
		return false;

	var oPrevNumPr = null;
	var oPrevParagraph = oParagraph.Get_DocumentPrev();
	if (oPrevParagraph && type_Paragraph === oPrevParagraph.GetType())
		oPrevNumPr = oPrevParagraph.GetNumPr();

	if (oRunElementsBefore.IsEnd())
	{
		var oNumPr = null;

		if (oDocument.IsAutomaticBulletedLists())
		{
			var oNumLvl = this.private_GetSuitableBulletedLvlForAutoCorrect(sText);
			if (oNumLvl)
			{
				if (oPrevNumPr)
				{
					var oPrevNumLvl = oDocument.GetNumbering().GetNum(oPrevNumPr.NumId).GetLvl(oPrevNumPr.Lvl);
					if (oPrevNumLvl.IsSimilar(oNumLvl))
					{
						oNumPr = new CNumPr(oPrevNumPr.NumId, oPrevNumPr.Lvl);
					}
				}

				if (!oNumPr)
				{
					var oNum = oDocument.GetNumbering().CreateNum();
					oNum.CreateDefault(c_oAscMultiLevelNumbering.Bullet);
					oNum.SetLvl(oNumLvl, 0);
					oNumPr = new CNumPr(oNum.GetId(), 0);
				}
			}
		}

		if (oDocument.IsAutomaticNumberedLists())
		{
			var arrResult = this.private_GetSuitableNumberedLvlForAutoCorrect(sText);

			if (arrResult)
			{
				for (var nIndex = 0, nCount = arrResult.length; nIndex < nCount; ++nIndex)
				{
					var oResult = arrResult[nIndex];
					if (oResult && -1 !== oResult.Value && oResult.Lvl)
					{
						if (1 === oResult.Value)
						{
							var oNum = oDocument.GetNumbering().CreateNum();
							oNum.CreateDefault(c_oAscMultiLevelNumbering.Numbered);
							oNum.SetLvl(oResult.Lvl, 0);
							oNumPr = new CNumPr(oNum.GetId(), 0);
							break;
						}
						else if (oPrevNumPr)
						{
							oResult.Lvl.ResetNumberedText(oPrevNumPr.Lvl);
							var oPrevNumLvl = oDocument.GetNumbering().GetNum(oPrevNumPr.NumId).GetLvl(oPrevNumPr.Lvl);
							if (oPrevNumLvl.IsSimilar(oResult.Lvl))
							{
								var oNumInfo = oPrevParagraph.Parent.CalculateNumberingValues(oPrevParagraph, oPrevNumPr);
								if (oResult.Value > oNumInfo[oPrevNumPr.Lvl] && oResult.Value <= oNumInfo[oPrevNumPr.Lvl] + 2)
								{
									oNumPr = new CNumPr(oPrevNumPr.NumId, oPrevNumPr.Lvl);
									break;
								}
							}
						}
					}
				}
			}
		}


		if (oNumPr)
		{
			if (false === oDocument.Document_Is_SelectionLocked({
					Type      : AscCommon.changestype_2_ElementsArray_and_Type,
					Elements  : [oParagraph],
					CheckType : AscCommon.changestype_Paragraph_Properties
				}))
			{
				oDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_AutomaticListAsType);

				var oStartPos = oParagraph.GetStartPos();
				var oEndPos   = oContentPos;
				oContentPos.Update(nPos + 1, oContentPos.GetDepth());

				oParagraph.RemoveSelection();
				oParagraph.SetSelectionUse(true);
				oParagraph.SetSelectionContentPos(oStartPos, oEndPos, false);
				oParagraph.Remove(1);
				oParagraph.RemoveSelection();
				oParagraph.MoveCursorToStartPos(false);

				oParagraph.ApplyNumPr(oNumPr.NumId, oNumPr.Lvl);

				oDocument.Recalculate();
			}
		}
	}

	return false;
};
/**
 * Подбираем подходящий маркированный список
 * @param sText {string}
 * @returns {?CNumberingLvl}
 */
ParaRun.prototype.private_GetSuitableBulletedLvlForAutoCorrect = function(sText)
{
	var oNumberingLvl = new CNumberingLvl();
	oNumberingLvl.InitDefault(0, c_oAscMultiLevelNumbering.Bullet);

	if ('*' === sText)
	{
		var oTextPr = new CTextPr();
		oTextPr.RFonts.SetAll("Symbol");
		oNumberingLvl.SetByType(c_oAscNumberingLevel.Bullet, 0, String.fromCharCode(0x00B7), oTextPr);
		return oNumberingLvl;
	}
	else if ('-' === sText)
	{
		var oTextPr = new CTextPr();
		oTextPr.RFonts.SetAll("Arial");
		oNumberingLvl.SetByType(c_oAscNumberingLevel.Bullet, 0, String.fromCharCode(0x2013), oTextPr);
		return oNumberingLvl;
	}

	return null;
};
/**
 * Подбираем подходящий нумерованный список
 * @param sText {string}
 * @returns {null | {Lvl : CNumberingLvl, Value : number}}
 */
ParaRun.prototype.private_GetSuitableNumberedLvlForAutoCorrect = function(sText)
{
	if (sText.length < 2)
		return null;

	var sLastChar = sText.charAt(sText.length - 1);
	if ('.' !== sLastChar && ')' !== sLastChar)
		return null;

	var nFirstCharCode = sText.charCodeAt(0);

	var nValue = -1;

	var sValue = sText.slice(0, sText.length - 1);

	// Проверяем, либо у нас все числовое, либо у нас все буквенное (все заглавные, либо все не заглавные)
	if (48 <= nFirstCharCode && nFirstCharCode <= 57)
	{
		var oNumberingLvl = new CNumberingLvl();
		oNumberingLvl.InitDefault(0, c_oAscMultiLevelNumbering.Numbered);

		for (var nIndex = 0, nCount = sValue.length; nIndex < nCount; ++nIndex)
		{
			var nCurCharCode = sValue.charCodeAt(nIndex);
			if (48 > nCurCharCode || nCurCharCode > 57)
				return null;
		}

		if ('.' === sLastChar)
			oNumberingLvl.SetByType(c_oAscNumberingLevel.DecimalDot_Left, 0);
		else if (')' === sLastChar)
			oNumberingLvl.SetByType(c_oAscNumberingLevel.DecimalBracket_Left, 0);

		nValue = parseInt(sValue);

		if (isNaN(nValue))
			nValue = -1;

		return [{Lvl : oNumberingLvl, Value : nValue}];
	}
	else if (65 <= nFirstCharCode && nFirstCharCode <= 90)
	{
		var nRoman  = AscCommon.RomanToInt(sValue);
		var nLetter = AscCommon.LatinNumberingToInt(sValue);

		var arrResult = [];
		if (!isNaN(nRoman))
		{
			var oNumberingLvl = new CNumberingLvl();
			oNumberingLvl.InitDefault(0, c_oAscMultiLevelNumbering.Numbered);

			if ('.' === sLastChar)
				oNumberingLvl.SetByType(c_oAscNumberingLevel.UpperRomanDot_Right, 0);
			else if (')' === sLastChar)
				oNumberingLvl.SetByType(c_oAscNumberingLevel.UpperRomanBracket_Left, 0);

			arrResult.push({Lvl : oNumberingLvl, Value : nRoman});
		}

		if (!isNaN(nLetter))
		{
			var oNumberingLvl = new CNumberingLvl();
			oNumberingLvl.InitDefault(0, c_oAscMultiLevelNumbering.Numbered);

			if ('.' === sLastChar)
				oNumberingLvl.SetByType(c_oAscNumberingLevel.UpperLetterDot_Left, 0);
			else if (')' === sLastChar)
				oNumberingLvl.SetByType(c_oAscNumberingLevel.UpperLetterBracket_Left, 0);

			arrResult.push({Lvl : oNumberingLvl, Value : nLetter});
		}

		if (arrResult.length > 0)
			return arrResult;

		return null;
	}
	else if (97 <= nFirstCharCode && nFirstCharCode <= 122)
	{
		var nRoman  = AscCommon.RomanToInt(sValue);
		var nLetter = AscCommon.LatinNumberingToInt(sValue);

		var arrResult = [];

		if (!isNaN(nRoman))
		{
			var oNumberingLvl = new CNumberingLvl();
			oNumberingLvl.InitDefault(0, c_oAscMultiLevelNumbering.Numbered);

			if ('.' === sLastChar)
				oNumberingLvl.SetByType(c_oAscNumberingLevel.LowerRomanDot_Right, 0);
			else if (')' === sLastChar)
				oNumberingLvl.SetByType(c_oAscNumberingLevel.LowerRomanBracket_Left, 0);

			arrResult.push({Lvl : oNumberingLvl, Value : nRoman});
		}
		if (!isNaN(nLetter))
		{
			var oNumberingLvl = new CNumberingLvl();
			oNumberingLvl.InitDefault(0, c_oAscMultiLevelNumbering.Numbered);

			if ('.' === sLastChar)
				oNumberingLvl.SetByType(c_oAscNumberingLevel.LowerLetterDot_Left, 0);
			else if (')' === sLastChar)
				oNumberingLvl.SetByType(c_oAscNumberingLevel.LowerLetterBracket_Left, 0);

			arrResult.push({Lvl : oNumberingLvl, Value : nLetter});
		}

		if (arrResult.length > 0)
			return arrResult;

		return null;
	}

	return null;
};

function CParaRunStartState(Run)
{
    this.Paragraph = Run.Paragraph;
    this.Pr = Run.Pr.Copy();
    this.Content = [];
    for(var i = 0; i < Run.Content.length; ++i)
    {
        this.Content.push(Run.Content[i]);
    }
}

function CReviewInfo()
{
    this.Editor   = editor;
    this.UserId   = "";
    this.UserName = "";
    this.DateTime = "";
}
CReviewInfo.prototype.Update = function()
{
    if (this.Editor && this.Editor.DocInfo)
    {
        this.UserId   = this.Editor.DocInfo.get_UserId();
        this.UserName = this.Editor.DocInfo.get_UserName();
        this.DateTime = (new Date()).getTime();
    }
};
CReviewInfo.prototype.Copy = function()
{
    var Info = new CReviewInfo();
    Info.UserId   = this.UserId;
    Info.UserName = this.UserName;
    Info.DateTime = this.DateTime;
    return Info;
};
CReviewInfo.prototype.Get_UserId = function()
{
    return this.UserId;
};
CReviewInfo.prototype.Get_UserName = function()
{
    return this.UserName;
};
CReviewInfo.prototype.Get_DateTime = function()
{
    return this.DateTime;
};
CReviewInfo.prototype.Write_ToBinary = function(Writer)
{
    Writer.WriteString2(this.UserId);
    Writer.WriteString2(this.UserName);
    Writer.WriteString2(this.DateTime);
};
CReviewInfo.prototype.Read_FromBinary = function(Reader)
{
    this.UserId   = Reader.GetString2();
    this.UserName = Reader.GetString2();
    this.DateTime = parseInt(Reader.GetString2());
};
CReviewInfo.prototype.Get_Color = function()
{
    if (!this.UserId && !this.UserName)
        return REVIEW_COLOR;

    return AscCommon.getUserColorById(this.UserId, this.UserName, true, false);
};
CReviewInfo.prototype.Is_CurrentUser = function()
{
    if (this.Editor && this.Editor.DocInfo)
    {
        var UserId = this.Editor.DocInfo.get_UserId();
        return (UserId === this.UserId);
    }

    return true;
};
CReviewInfo.prototype.Get_UserId = function()
{
    return this.UserId;
};

function CanUpdatePosition(Para, Run) {
    return (Para && true === Para.Is_UseInDocument() && true === Run.Is_UseInParagraph());
}

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].ParaRun = ParaRun;
window['AscCommonWord'].CanUpdatePosition = CanUpdatePosition;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

/**
 * User: Ilja.Kirillov
 * Date: 21.10.2016
 * Time: 12:56
 */

AscDFH.changesFactory[AscDFH.historyitem_ParaRun_AddItem]           = CChangesRunAddItem;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_RemoveItem]        = CChangesRunRemoveItem;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_Bold]              = CChangesRunBold;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_Italic]            = CChangesRunItalic;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_Strikeout]         = CChangesRunStrikeout;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_Underline]         = CChangesRunUnderline;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_FontFamily]        = undefined; // obsolete
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_FontSize]          = CChangesRunFontSize;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_Color]             = CChangesRunColor;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_VertAlign]         = CChangesRunVertAlign;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_HighLight]         = CChangesRunHighLight;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_RStyle]            = CChangesRunRStyle;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_Spacing]           = CChangesRunSpacing;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_DStrikeout]        = CChangesRunDStrikeout;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_Caps]              = CChangesRunCaps;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_SmallCaps]         = CChangesRunSmallCaps;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_Position]          = CChangesRunPosition;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_Value]             = undefined; // obsolete
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_RFonts]            = CChangesRunRFonts;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_Lang]              = CChangesRunLang;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_RFonts_Ascii]      = CChangesRunRFontsAscii;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_RFonts_HAnsi]      = CChangesRunRFontsHAnsi;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_RFonts_CS]         = CChangesRunRFontsCS;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_RFonts_EastAsia]   = CChangesRunRFontsEastAsia;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_RFonts_Hint]       = CChangesRunRFontsHint;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_Lang_Bidi]         = CChangesRunLangBidi;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_Lang_EastAsia]     = CChangesRunLangEastAsia;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_Lang_Val]          = CChangesRunLangVal;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_TextPr]            = CChangesRunTextPr;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_Unifill]           = CChangesRunUnifill;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_Shd]               = CChangesRunShd;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_MathStyle]         = CChangesRunMathStyle;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_MathPrp]           = CChangesRunMathPrp;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_ReviewType]        = CChangesRunReviewType;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_PrChange]          = CChangesRunPrChange;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_TextFill]          = CChangesRunTextFill;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_TextOutline]       = CChangesRunTextOutline;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_PrReviewInfo]      = CChangesRunPrReviewInfo;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_ContentReviewInfo] = CChangesRunContentReviewInfo;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_OnStartSplit]      = CChangesRunOnStartSplit;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_OnEndSplit]        = CChangesRunOnEndSplit;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_MathAlnAt]         = CChangesRunMathAlnAt;
AscDFH.changesFactory[AscDFH.historyitem_ParaRun_MathForcedBreak]   = CChangesRunMathForcedBreak;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_AddItem]           = [
	AscDFH.historyitem_ParaRun_AddItem,
	AscDFH.historyitem_ParaRun_RemoveItem
];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_RemoveItem]        = [
	AscDFH.historyitem_ParaRun_AddItem,
	AscDFH.historyitem_ParaRun_RemoveItem
];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_Bold]              = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_Bold];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_Italic]            = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_Italic];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_Strikeout]         = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_Strikeout];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_Underline]         = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_Underline];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_FontSize]          = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_FontSize];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_Color]             = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_Color];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_VertAlign]         = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_VertAlign];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_HighLight]         = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_HighLight];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_RStyle]            = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_RStyle];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_Spacing]           = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_Spacing];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_DStrikeout]        = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_DStrikeout];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_Caps]              = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_Caps];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_SmallCaps]         = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_SmallCaps];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_Position]          = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_Position];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_RFonts]            = [
	AscDFH.historyitem_ParaRun_TextPr,
	AscDFH.historyitem_ParaRun_RFonts,
	AscDFH.historyitem_ParaRun_RFonts_Ascii,
	AscDFH.historyitem_ParaRun_RFonts_HAnsi,
	AscDFH.historyitem_ParaRun_RFonts_CS,
	AscDFH.historyitem_ParaRun_RFonts_EastAsia,
	AscDFH.historyitem_ParaRun_RFonts_Hint
];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_Lang]              = [
	AscDFH.historyitem_ParaRun_TextPr,
	AscDFH.historyitem_ParaRun_Lang,
	AscDFH.historyitem_ParaRun_Lang_Bidi,
	AscDFH.historyitem_ParaRun_Lang_EastAsia,
	AscDFH.historyitem_ParaRun_Lang_Val
];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_RFonts_Ascii]      = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_RFonts, AscDFH.historyitem_ParaRun_RFonts_Ascii];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_RFonts_HAnsi]      = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_RFonts, AscDFH.historyitem_ParaRun_RFonts_HAnsi];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_RFonts_CS]         = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_RFonts, AscDFH.historyitem_ParaRun_RFonts_CS];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_RFonts_EastAsia]   = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_RFonts, AscDFH.historyitem_ParaRun_RFonts_EastAsia];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_RFonts_Hint]       = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_RFonts, AscDFH.historyitem_ParaRun_RFonts_Hint];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_Lang_Bidi]         = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_Lang, AscDFH.historyitem_ParaRun_Lang_Bidi];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_Lang_EastAsia]     = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_Lang, AscDFH.historyitem_ParaRun_Lang_EastAsia];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_Lang_Val]          = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_Lang, AscDFH.historyitem_ParaRun_Lang_Val];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_TextPr]            = [
	AscDFH.historyitem_ParaRun_Bold,
	AscDFH.historyitem_ParaRun_Italic,
	AscDFH.historyitem_ParaRun_Strikeout,
	AscDFH.historyitem_ParaRun_Underline,
	AscDFH.historyitem_ParaRun_FontSize,
	AscDFH.historyitem_ParaRun_Color,
	AscDFH.historyitem_ParaRun_VertAlign,
	AscDFH.historyitem_ParaRun_HighLight,
	AscDFH.historyitem_ParaRun_RStyle,
	AscDFH.historyitem_ParaRun_Spacing,
	AscDFH.historyitem_ParaRun_DStrikeout,
	AscDFH.historyitem_ParaRun_Caps,
	AscDFH.historyitem_ParaRun_SmallCaps,
	AscDFH.historyitem_ParaRun_Position,
	AscDFH.historyitem_ParaRun_RFonts,
	AscDFH.historyitem_ParaRun_Lang,
	AscDFH.historyitem_ParaRun_RFonts_Ascii,
	AscDFH.historyitem_ParaRun_RFonts_HAnsi,
	AscDFH.historyitem_ParaRun_RFonts_CS,
	AscDFH.historyitem_ParaRun_RFonts_EastAsia,
	AscDFH.historyitem_ParaRun_RFonts_Hint,
	AscDFH.historyitem_ParaRun_Lang_Bidi,
	AscDFH.historyitem_ParaRun_Lang_EastAsia,
	AscDFH.historyitem_ParaRun_Lang_Val,
	AscDFH.historyitem_ParaRun_TextPr,
	AscDFH.historyitem_ParaRun_Unifill,
	AscDFH.historyitem_ParaRun_Shd,
	AscDFH.historyitem_ParaRun_PrChange,
	AscDFH.historyitem_ParaRun_TextFill,
	AscDFH.historyitem_ParaRun_TextOutline,
	AscDFH.historyitem_ParaRun_PrReviewInfo
];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_Unifill]           = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_Unifill];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_Shd]               = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_Shd];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_MathStyle]         = [
	AscDFH.historyitem_ParaRun_MathStyle,
	AscDFH.historyitem_ParaRun_MathPrp
];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_MathPrp]           = [
	AscDFH.historyitem_ParaRun_MathStyle,
	AscDFH.historyitem_ParaRun_MathPrp,
	AscDFH.historyitem_ParaRun_MathAlnAt,
	AscDFH.historyitem_ParaRun_MathForcedBreak
];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_ReviewType]        = [
	AscDFH.historyitem_ParaRun_ReviewType,
	AscDFH.historyitem_ParaRun_ContentReviewInfo
];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_PrChange]          = [
	AscDFH.historyitem_ParaRun_TextPr,
	AscDFH.historyitem_ParaRun_PrChange,
	AscDFH.historyitem_ParaRun_PrReviewInfo
];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_TextFill]          = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_TextFill];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_TextOutline]       = [AscDFH.historyitem_ParaRun_TextPr, AscDFH.historyitem_ParaRun_TextOutline];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_PrReviewInfo]      = [
	AscDFH.historyitem_ParaRun_TextPr,
	AscDFH.historyitem_ParaRun_PrChange,
	AscDFH.historyitem_ParaRun_PrReviewInfo
];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_ContentReviewInfo] = [
	AscDFH.historyitem_ParaRun_ReviewType,
	AscDFH.historyitem_ParaRun_ContentReviewInfo
];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_OnStartSplit]      = [];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_OnEndSplit]        = [];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_MathAlnAt]         = [
	AscDFH.historyitem_ParaRun_MathPrp,
	AscDFH.historyitem_ParaRun_MathAlnAt,
	AscDFH.historyitem_ParaRun_MathForcedBreak
];
AscDFH.changesRelationMap[AscDFH.historyitem_ParaRun_MathForcedBreak]   = [
	AscDFH.historyitem_ParaRun_MathPrp,
	AscDFH.historyitem_ParaRun_MathAlnAt,
	AscDFH.historyitem_ParaRun_MathForcedBreak
];

/**
 * Общая функция объединения изменений, которые зависят только от себя и AscDFH.historyitem_ParaRun_TextPr
 * @param oChange
 * @returns {boolean}
 */
function private_ParaRunChangesOnMergeTextPr(oChange)
{
	if (oChange.Class !== this.Class)
		return true;

	if (oChange.Type === this.Type || oChange.Type === AscDFH.historyitem_ParaRun_TextPr)
		return false;

	return true;
}
/**
 * Общая функция объединения изменений, которые зависят от себя, AscDFH.historyitem_ParaRun_TextPr,
 * AscDFH.historyitem_ParaRun_RFonts
 * @param oChange
 * @returns {boolean}
 */
function private_ParaRunChangesOnMergeRFontsTextPr(oChange)
{
	if (oChange.Class !== this.Class)
		return true;

	if (oChange.Type === this.Type || oChange.Type === AscDFH.historyitem_ParaRun_TextPr || oChange.Type === AscDFH.historyitem_ParaRun_RFonts)
		return false;

	return true;
}
/**
 * Общая функция объединения изменений, которые зависят от себя, AscDFH.historyitem_ParaRun_TextPr,
 * AscDFH.historyitem_ParaRun_Lang
 * @param oChange
 * @returns {boolean}
 */
function private_ParaRunChangesOnMergeLangTextPr(oChange)
{
	if (oChange.Class !== this.Class)
		return true;

	if (oChange.Type === this.Type || oChange.Type === AscDFH.historyitem_ParaRun_TextPr || oChange.Type === AscDFH.historyitem_ParaRun_Lang)
		return false;

	return true;
}
//----------------------------------------------------------------------------------------------------------------------

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesRunAddItem(Class, Pos, Items, Color)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, true);

	this.Color = true === Color ? true : false;
}
CChangesRunAddItem.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesRunAddItem.prototype.constructor = CChangesRunAddItem;
CChangesRunAddItem.prototype.Type = AscDFH.historyitem_ParaRun_AddItem;
CChangesRunAddItem.prototype.Undo = function()
{
	var oRun = this.Class;

	oRun.Content.splice(this.Pos, this.Items.length);

	oRun.RecalcInfo.Measure = true;
	oRun.private_UpdateSpellChecking();
	oRun.private_UpdateTrackRevisionOnChangeContent(false);
};
CChangesRunAddItem.prototype.Redo = function()
{
	var oRun = this.Class;

	var Array_start = oRun.Content.slice(0, this.Pos);
	var Array_end   = oRun.Content.slice(this.Pos);

	oRun.Content = Array_start.concat(this.Items, Array_end);

	oRun.RecalcInfo.Measure = true;
	oRun.private_UpdateSpellChecking();
	oRun.private_UpdateTrackRevisionOnChangeContent(false);

	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		if (this.Items.SetParent)
			this.Items.SetParent(oRun);
	}
};
CChangesRunAddItem.prototype.private_WriteItem = function(Writer, Item)
{
	Item.Write_ToBinary(Writer);
};
CChangesRunAddItem.prototype.private_ReadItem = function(Reader)
{
	return ParagraphContent_Read_FromBinary(Reader);
};
CChangesRunAddItem.prototype.Load = function(Color)
{
	var oRun = this.Class;
	for (var Index = 0, Count = this.Items.length; Index < Count; Index++)
	{
		var Pos = oRun.m_oContentChanges.Check(AscCommon.contentchanges_Add, this.PosArray[Index]);
		var Element = this.Items[Index];
		if (null != Element)
		{
			if (true === this.Color && null !== Color)
			{
				oRun.CollaborativeMarks.Update_OnAdd(Pos);
				oRun.CollaborativeMarks.Add(Pos, Pos + 1, Color);
				AscCommon.CollaborativeEditing.Add_ChangedClass(oRun);
			}

			oRun.Content.splice(Pos, 0, Element);
			oRun.private_UpdatePositionsOnAdd(Pos);
			oRun.private_UpdateCompositeInputPositionsOnAdd(Pos);
			AscCommon.CollaborativeEditing.Update_DocumentPositionsOnAdd(oRun, Pos);

			if (Element.SetParent)
				Element.SetParent(oRun);
		}
	}

	oRun.RecalcInfo.Measure = true;
	oRun.private_UpdateSpellChecking();
	oRun.private_UpdateTrackRevisionOnChangeContent(false);
};
CChangesRunAddItem.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_ParaRun_AddItem === oChanges.Type || AscDFH.historyitem_ParaRun_RemoveItem === oChanges.Type))
		return true;

	return false;
};
CChangesRunAddItem.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesRunRemoveItem);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesRunRemoveItem(Class, Pos, Items)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, false);
}
CChangesRunRemoveItem.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesRunRemoveItem.prototype.constructor = CChangesRunRemoveItem;
CChangesRunRemoveItem.prototype.Type = AscDFH.historyitem_ParaRun_RemoveItem;
CChangesRunRemoveItem.prototype.Undo = function()
{
	var oRun = this.Class;

	var Array_start = oRun.Content.slice(0, this.Pos);
	var Array_end   = oRun.Content.slice(this.Pos);

	oRun.Content = Array_start.concat(this.Items, Array_end);

	oRun.RecalcInfo.Measure = true;
	oRun.private_UpdateSpellChecking();
	oRun.private_UpdateTrackRevisionOnChangeContent(false);

	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		if (this.Items.SetParent)
			this.Items.SetParent(oRun);
	}
};
CChangesRunRemoveItem.prototype.Redo = function()
{
	var oRun = this.Class;
	oRun.Content.splice(this.Pos, this.Items.length);

	oRun.RecalcInfo.Measure = true;
	oRun.private_UpdateSpellChecking();
	oRun.private_UpdateTrackRevisionOnChangeContent(false);
};
CChangesRunRemoveItem.prototype.private_WriteItem = function(Writer, Item)
{
	Item.Write_ToBinary(Writer);
};
CChangesRunRemoveItem.prototype.private_ReadItem = function(Reader)
{
	return ParagraphContent_Read_FromBinary(Reader);
};
CChangesRunRemoveItem.prototype.Load = function()
{
	var oRun = this.Class;

	var nLastChangesPos = null;
	var nChangesCount   = 0;
	for (var Index = 0, Count = this.PosArray.length; Index < Count; Index++)
	{
		var nChangesPos = oRun.m_oContentChanges.Check(AscCommon.contentchanges_Remove, this.PosArray[Index]);

		// действие совпало, не делаем его
		if (false === nChangesPos)
			continue;

		// В большинстве случаев удаления идут подряд и не меняются, т.е. их позиции у другого клиента тоже идут подряд
		// Для улучшения производительности мы объединяем подряд идущие удаления
		if (null === nLastChangesPos)
		{
			nLastChangesPos = nChangesPos;
			nChangesCount   = 1;
		}
		else if (nLastChangesPos === nChangesPos)
		{
			nChangesCount++;
		}
		else
		{
			oRun.CollaborativeMarks.Update_OnRemove(nLastChangesPos, nChangesCount);
			oRun.Content.splice(nLastChangesPos, nChangesCount);
			oRun.private_UpdatePositionsOnRemove(nLastChangesPos, nChangesCount);
			oRun.private_UpdateCompositeInputPositionsOnRemove(nLastChangesPos, nChangesCount);
			AscCommon.CollaborativeEditing.Update_DocumentPositionsOnRemove(oRun, nLastChangesPos, nChangesCount);

			nLastChangesPos = nChangesPos;
			nChangesCount   = 1;
		}
	}

	if (nChangesCount)
	{
		oRun.CollaborativeMarks.Update_OnRemove(nLastChangesPos, nChangesCount);
		oRun.Content.splice(nLastChangesPos, nChangesCount);
		oRun.private_UpdatePositionsOnRemove(nLastChangesPos, nChangesCount);
		oRun.private_UpdateCompositeInputPositionsOnRemove(nLastChangesPos, nChangesCount);
		AscCommon.CollaborativeEditing.Update_DocumentPositionsOnRemove(oRun, nLastChangesPos, nChangesCount);
	}

	oRun.RecalcInfo.Measure = true;
	oRun.private_UpdateSpellChecking();
	oRun.private_UpdateTrackRevisionOnChangeContent(false);
};
CChangesRunRemoveItem.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_ParaRun_AddItem === oChanges.Type || AscDFH.historyitem_ParaRun_RemoveItem === oChanges.Type))
		return true;

	return false;
};
CChangesRunRemoveItem.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesRunAddItem);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesRunBold(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesRunBold.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesRunBold.prototype.constructor = CChangesRunBold;
CChangesRunBold.prototype.Type = AscDFH.historyitem_ParaRun_Bold;
CChangesRunBold.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.Bold = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunBold.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunBold.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesRunItalic(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesRunItalic.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesRunItalic.prototype.constructor = CChangesRunItalic;
CChangesRunItalic.prototype.Type = AscDFH.historyitem_ParaRun_Italic;
CChangesRunItalic.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.Italic = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunItalic.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunItalic.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesRunStrikeout(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesRunStrikeout.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesRunStrikeout.prototype.constructor = CChangesRunStrikeout;
CChangesRunStrikeout.prototype.Type = AscDFH.historyitem_ParaRun_Strikeout;
CChangesRunStrikeout.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.Strikeout = Value;

	oRun.Recalc_CompiledPr(false);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunStrikeout.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunStrikeout.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesRunUnderline(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesRunUnderline.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesRunUnderline.prototype.constructor = CChangesRunUnderline;
CChangesRunUnderline.prototype.Type = AscDFH.historyitem_ParaRun_Underline;
CChangesRunUnderline.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.Underline = Value;

	oRun.Recalc_CompiledPr(false);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunUnderline.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunUnderline.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleProperty}
 */
function CChangesRunFontSize(Class, Old, New, Color)
{
	AscDFH.CChangesBaseDoubleProperty.call(this, Class, Old, New, Color);
}
CChangesRunFontSize.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
CChangesRunFontSize.prototype.constructor = CChangesRunFontSize;
CChangesRunFontSize.prototype.Type = AscDFH.historyitem_ParaRun_FontSize;
CChangesRunFontSize.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.FontSize = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunFontSize.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunFontSize.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesRunColor(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesRunColor.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesRunColor.prototype.constructor = CChangesRunColor;
CChangesRunColor.prototype.Type = AscDFH.historyitem_ParaRun_Color;
CChangesRunColor.prototype.private_CreateObject = function()
{
	return new CDocumentColor(0, 0, 0, false);
};
CChangesRunColor.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.Color = Value;

	oRun.Recalc_CompiledPr(false);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunColor.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunColor.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesRunVertAlign(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesRunVertAlign.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesRunVertAlign.prototype.constructor = CChangesRunVertAlign;
CChangesRunVertAlign.prototype.Type = AscDFH.historyitem_ParaRun_VertAlign;
CChangesRunVertAlign.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.VertAlign = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunVertAlign.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunVertAlign.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesRunHighLight(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesRunHighLight.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesRunHighLight.prototype.constructor = CChangesRunHighLight;
CChangesRunHighLight.prototype.Type = AscDFH.historyitem_ParaRun_HighLight;
CChangesRunHighLight.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is "none" New ?
	// 4-bit : Is undefined New ?
	// 5-bit : Is "none" New ?
	// Variable(?CDocumentColor) : New (если 2 и 3 биты нулевые)
	// Variable(?CDocumentColor) : Old (если 4 и 5 биты нулевые)

	var nFlags = 0;

	if (false !== this.Color)
		nFlags |= 1;

	if (undefined === this.New)
		nFlags |= 2;
	else if (highlight_None === this.New)
		nFlags |= 4;

	if (undefined === this.Old)
		nFlags |= 8;
	else if (highlight_None === this.Old)
		nFlags |= 16;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New && highlight_None !== this.New)
		this.New.Write_ToBinary(Writer);

	if (undefined !== this.Old && highlight_None !== this.Old)
		this.Old.Write_ToBinary(Writer);
};
CChangesRunHighLight.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is "none" New ?
	// 4-bit : Is undefined New ?
	// 5-bit : Is "none" New ?
	// Variable(?CDocumentColor) : New (если 2 и 3 биты нулевые)
	// Variable(?CDocumentColor) : Old (если 4 и 5 биты нулевые)

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.Color = true;
	else
		this.Color = false;

	if (nFlags & 2)
	{
		this.New = undefined;
	}
	else if (nFlags & 4)
	{
		this.New = highlight_None;
	}
	else
	{
		this.New = new CDocumentColor(0, 0, 0);
		this.New.Read_FromBinary(Reader);
	}

	if (nFlags & 8)
	{
		this.Old = undefined;
	}
	else if (nFlags & 16)
	{
		this.Old = highlight_None;
	}
	else
	{
		this.Old = new CDocumentColor(0, 0, 0);
		this.Old.Read_FromBinary(Reader);
	}
};
CChangesRunHighLight.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.HighLight = Value;

	oRun.Recalc_CompiledPr(false);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunHighLight.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunHighLight.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseStringProperty}
 */
function CChangesRunRStyle(Class, Old, New, Color)
{
	AscDFH.CChangesBaseStringProperty.call(this, Class, Old, New, Color);
}
CChangesRunRStyle.prototype = Object.create(AscDFH.CChangesBaseStringProperty.prototype);
CChangesRunRStyle.prototype.constructor = CChangesRunRStyle;
CChangesRunRStyle.prototype.Type = AscDFH.historyitem_ParaRun_RStyle;
CChangesRunRStyle.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.RStyle = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunRStyle.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunRStyle.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleProperty}
 */
function CChangesRunSpacing(Class, Old, New, Color)
{
	AscDFH.CChangesBaseDoubleProperty.call(this, Class, Old, New, Color);
}
CChangesRunSpacing.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
CChangesRunSpacing.prototype.constructor = CChangesRunSpacing;
CChangesRunSpacing.prototype.Type = AscDFH.historyitem_ParaRun_Spacing;
CChangesRunSpacing.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.Spacing = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunSpacing.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunSpacing.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesRunDStrikeout(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesRunDStrikeout.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesRunDStrikeout.prototype.constructor = CChangesRunDStrikeout;
CChangesRunDStrikeout.prototype.Type = AscDFH.historyitem_ParaRun_DStrikeout;
CChangesRunDStrikeout.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.DStrikeout = Value;

	oRun.Recalc_CompiledPr(false);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunDStrikeout.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunDStrikeout.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesRunCaps(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesRunCaps.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesRunCaps.prototype.constructor = CChangesRunCaps;
CChangesRunCaps.prototype.Type = AscDFH.historyitem_ParaRun_Caps;
CChangesRunCaps.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.Caps = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunCaps.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunCaps.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesRunSmallCaps(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesRunSmallCaps.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesRunSmallCaps.prototype.constructor = CChangesRunSmallCaps;
CChangesRunSmallCaps.prototype.Type = AscDFH.historyitem_ParaRun_SmallCaps;
CChangesRunSmallCaps.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.SmallCaps = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunSmallCaps.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunSmallCaps.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleProperty}
 */
function CChangesRunPosition(Class, Old, New, Color)
{
	AscDFH.CChangesBaseDoubleProperty.call(this, Class, Old, New, Color);
}
CChangesRunPosition.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
CChangesRunPosition.prototype.constructor = CChangesRunPosition;
CChangesRunPosition.prototype.Type = AscDFH.historyitem_ParaRun_Position;
CChangesRunPosition.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.Position = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunPosition.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunPosition.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesRunRFonts(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesRunRFonts.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesRunRFonts.prototype.constructor = CChangesRunRFonts;
CChangesRunRFonts.prototype.Type = AscDFH.historyitem_ParaRun_RFonts;
CChangesRunRFonts.prototype.private_CreateObject = function()
{
	return new CRFonts();
};
CChangesRunRFonts.prototype.private_IsCreateEmptyObject = function()
{
	return true;
};
CChangesRunRFonts.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.RFonts = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunRFonts.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunRFonts.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type || AscDFH.historyitem_ParaRun_TextPr === oChange.Type)
		return false;

	if (!this.New)
		this.New = new CRFonts();

	switch (oChange.Type)
	{
		case AscDFH.historyitem_ParaRun_RFonts_Ascii:
		{
			this.New.Ascii = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_RFonts_HAnsi:
		{
			this.New.HAnsi = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_RFonts_CS:
		{
			this.New.CS = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_RFonts_EastAsia:
		{
			this.New.EastAsia = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_RFonts_Hint:
		{
			this.New.Hint = oChange.New;
			break;
		}
	}

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesRunLang(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesRunLang.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesRunLang.prototype.constructor = CChangesRunLang;
CChangesRunLang.prototype.Type = AscDFH.historyitem_ParaRun_Lang;
CChangesRunLang.prototype.private_CreateObject = function()
{
	return new CLang();
};
CChangesRunLang.prototype.private_IsCreateEmptyObject = function()
{
	return true;
};
CChangesRunLang.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.Lang = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateSpellChecking();
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunLang.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunLang.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type || AscDFH.historyitem_ParaRun_TextPr === oChange.Type)
		return false;

	if (!this.New)
		this.New = new CLang();

	switch (oChange.Type)
	{
		case AscDFH.historyitem_ParaRun_Lang_Bidi:
		{
			this.New.Bidi = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_Lang_EastAsia:
		{
			this.New.EastAsia = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_Lang_Val:
		{
			this.New.Val = oChange.New;
			break;
		}
	}

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesRunRFontsAscii(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesRunRFontsAscii.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesRunRFontsAscii.prototype.constructor = CChangesRunRFontsAscii;
CChangesRunRFontsAscii.prototype.Type = AscDFH.historyitem_ParaRun_RFonts_Ascii;
CChangesRunRFontsAscii.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = 0;

	if (false !== this.Color)
		nFlags |= 1;

	if (undefined === this.New)
		nFlags |= 2;

	if (undefined === this.Old)
		nFlags |= 4;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New)
		Writer.WriteString2(this.New.Name);

	if (undefined !== this.Old)
		Writer.WriteString2(this.Old.Name);
};
CChangesRunRFontsAscii.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.Color = true;
	else
		this.Color = false;

	if (nFlags & 2)
	{
		this.New = undefined;
	}
	else
	{
		this.New = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}

	if (nFlags & 4)
	{
		this.Old = undefined;
	}
	else
	{
		this.Old = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}
};
CChangesRunRFontsAscii.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.RFonts.Ascii = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunRFontsAscii.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunRFontsAscii.prototype.Merge = private_ParaRunChangesOnMergeRFontsTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesRunRFontsHAnsi(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesRunRFontsHAnsi.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesRunRFontsHAnsi.prototype.constructor = CChangesRunRFontsHAnsi;
CChangesRunRFontsHAnsi.prototype.Type = AscDFH.historyitem_ParaRun_RFonts_HAnsi;
CChangesRunRFontsHAnsi.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = 0;

	if (false !== this.Color)
		nFlags |= 1;

	if (undefined === this.New)
		nFlags |= 2;

	if (undefined === this.Old)
		nFlags |= 4;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New)
		Writer.WriteString2(this.New.Name);

	if (undefined !== this.Old)
		Writer.WriteString2(this.Old.Name);
};
CChangesRunRFontsHAnsi.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.Color = true;
	else
		this.Color = false;

	if (nFlags & 2)
	{
		this.New = undefined;
	}
	else
	{
		this.New = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}

	if (nFlags & 4)
	{
		this.Old = undefined;
	}
	else
	{
		this.Old = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}
};
CChangesRunRFontsHAnsi.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.RFonts.HAnsi = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunRFontsHAnsi.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunRFontsHAnsi.prototype.Merge = private_ParaRunChangesOnMergeRFontsTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesRunRFontsCS(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesRunRFontsCS.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesRunRFontsCS.prototype.constructor = CChangesRunRFontsCS;
CChangesRunRFontsCS.prototype.Type = AscDFH.historyitem_ParaRun_RFonts_CS;
CChangesRunRFontsCS.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = 0;

	if (false !== this.Color)
		nFlags |= 1;

	if (undefined === this.New)
		nFlags |= 2;

	if (undefined === this.Old)
		nFlags |= 4;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New)
		Writer.WriteString2(this.New.Name);

	if (undefined !== this.Old)
		Writer.WriteString2(this.Old.Name);
};
CChangesRunRFontsCS.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.Color = true;
	else
		this.Color = false;

	if (nFlags & 2)
	{
		this.New = undefined;
	}
	else
	{
		this.New = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}

	if (nFlags & 4)
	{
		this.Old = undefined;
	}
	else
	{
		this.Old = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}
};
CChangesRunRFontsCS.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.RFonts.CS = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunRFontsCS.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunRFontsCS.prototype.Merge = private_ParaRunChangesOnMergeRFontsTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesRunRFontsEastAsia(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesRunRFontsEastAsia.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesRunRFontsEastAsia.prototype.constructor = CChangesRunRFontsEastAsia;
CChangesRunRFontsEastAsia.prototype.Type = AscDFH.historyitem_ParaRun_RFonts_EastAsia;
CChangesRunRFontsEastAsia.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = 0;

	if (false !== this.Color)
		nFlags |= 1;

	if (undefined === this.New)
		nFlags |= 2;

	if (undefined === this.Old)
		nFlags |= 4;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New)
		Writer.WriteString2(this.New.Name);

	if (undefined !== this.Old)
		Writer.WriteString2(this.Old.Name);
};
CChangesRunRFontsEastAsia.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.Color = true;
	else
		this.Color = false;

	if (nFlags & 2)
	{
		this.New = undefined;
	}
	else
	{
		this.New = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}

	if (nFlags & 4)
	{
		this.Old = undefined;
	}
	else
	{
		this.Old = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}
};
CChangesRunRFontsEastAsia.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.RFonts.EastAsia = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunRFontsEastAsia.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunRFontsEastAsia.prototype.Merge = private_ParaRunChangesOnMergeRFontsTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesRunRFontsHint(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesRunRFontsHint.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesRunRFontsHint.prototype.constructor = CChangesRunRFontsHint;
CChangesRunRFontsHint.prototype.Type = AscDFH.historyitem_ParaRun_RFonts_Hint;
CChangesRunRFontsHint.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.RFonts.Hint = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunRFontsHint.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunRFontsHint.prototype.Merge = private_ParaRunChangesOnMergeRFontsTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesRunLangBidi(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesRunLangBidi.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesRunLangBidi.prototype.constructor = CChangesRunLangBidi;
CChangesRunLangBidi.prototype.Type = AscDFH.historyitem_ParaRun_Lang_Bidi;
CChangesRunLangBidi.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.Lang.Bidi = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateSpellChecking();
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunLangBidi.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunLangBidi.prototype.Merge = private_ParaRunChangesOnMergeLangTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesRunLangEastAsia(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesRunLangEastAsia.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesRunLangEastAsia.prototype.constructor = CChangesRunLangEastAsia;
CChangesRunLangEastAsia.prototype.Type = AscDFH.historyitem_ParaRun_Lang_EastAsia;
CChangesRunLangEastAsia.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.Lang.EastAsia = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateSpellChecking();
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunLangEastAsia.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunLangEastAsia.prototype.Merge = private_ParaRunChangesOnMergeLangTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesRunLangVal(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesRunLangVal.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesRunLangVal.prototype.constructor = CChangesRunLangVal;
CChangesRunLangVal.prototype.Type = AscDFH.historyitem_ParaRun_Lang_Val;
CChangesRunLangVal.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.Lang.Val = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateSpellChecking();
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunLangVal.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunLangVal.prototype.Merge = private_ParaRunChangesOnMergeLangTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesRunTextPr(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesRunTextPr.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesRunTextPr.prototype.constructor = CChangesRunTextPr;
CChangesRunTextPr.prototype.Type = AscDFH.historyitem_ParaRun_TextPr;
CChangesRunTextPr.prototype.private_CreateObject = function()
{
	return new CTextPr();
};
CChangesRunTextPr.prototype.private_IsCreateEmptyObject = function()
{
	return true;
};
CChangesRunTextPr.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunTextPr.prototype.Load = function(Color)
{
	this.Redo();

	var Unifill = this.Class.Pr.Unifill;
	if (AscCommon.CollaborativeEditing
		&& Unifill
		&& Unifill.fill
		&& Unifill.fill.type === Asc.c_oAscFill.FILL_TYPE_BLIP
		&& typeof Unifill.fill.RasterImageId === "string"
		&& Unifill.fill.RasterImageId.length > 0)
	{
		AscCommon.CollaborativeEditing.Add_NewImage(Unifill.fill.RasterImageId);
	}

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunTextPr.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type)
		return false;

	if (!this.New)
		this.New = new CTextPr();

	switch (oChange.Type)
	{
		case AscDFH.historyitem_ParaRun_Bold:
		{
			this.New.Bold = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_Italic:
		{
			this.New.Italic = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_Strikeout:
		{
			this.New.Strikeout = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_Underline:
		{
			this.New.Underline = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_FontSize:
		{
			this.New.FontSize = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_Color:
		{
			this.New.Color = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_VertAlign:
		{
			this.New.VertAlign = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_HighLight:
		{
			this.New.HighLight = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_RStyle:
		{
			this.New.RStyle = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_Spacing:
		{
			this.New.Spacing = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_DStrikeout:
		{
			this.New.DStrikeout = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_Caps:
		{
			this.New.Caps = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_SmallCaps:
		{
			this.New.SmallCaps = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_Position:
		{
			this.New.Position = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_RFonts:
		{
			this.New.RFonts = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_Lang:
		{
			this.New.Lang = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_RFonts_Ascii:
		{
			if (!this.New.RFonts)
				this.New.RFonts = new CRFonts();

			this.New.RFonts.Ascii = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_RFonts_HAnsi:
		{
			if (!this.New.RFonts)
				this.New.RFonts = new CRFonts();

			this.New.RFonts.HAnsi = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_RFonts_CS:
		{
			if (!this.New.RFonts)
				this.New.RFonts = new CRFonts();

			this.New.RFonts.CS = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_RFonts_EastAsia:
		{
			if (!this.New.RFonts)
				this.New.RFonts = new CRFonts();

			this.New.RFonts.EastAsia = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_RFonts_Hint:
		{
			if (!this.New.RFonts)
				this.New.RFonts = new CRFonts();

			this.New.RFonts.Hint = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_Lang_Bidi:
		{
			if (!this.New.Lang)
				this.New.Lang = new CLang();

			this.New.Lang.Bidi = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_Lang_EastAsia:
		{
			if (!this.New.Lang)
				this.New.Lang = new CLang();

			this.New.Lang.EastAsia = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_Lang_Val:
		{
			if (!this.New.Lang)
				this.New.Lang = new CLang();

			this.New.Lang.Val = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_Unifill:
		{
			this.New.Unifill = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_Shd:
		{
			this.New.Shd = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_PrChange:
		{
			this.New.PrChange   = oChange.New.PrChange;
			this.New.ReviewInfo = oChange.New.ReviewInfo;
			break;
		}
		case AscDFH.historyitem_ParaRun_TextFill:
		{
			this.New.TextFil = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_TextOutline:
		{
			this.New.TextOutline = oChange.New;
			break;
		}
		case AscDFH.historyitem_ParaRun_PrReviewInfo:
		{
			this.New.ReviewInfo = oChange.New;
			break;
		}
	}

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesRunUnifill(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesRunUnifill.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesRunUnifill.prototype.constructor = CChangesRunUnifill;
CChangesRunUnifill.prototype.Type = AscDFH.historyitem_ParaRun_Unifill;
CChangesRunUnifill.prototype.private_CreateObject = function()
{
	return new AscFormat.CUniFill();
};
CChangesRunUnifill.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.Unifill = Value;

	oRun.Recalc_CompiledPr(false);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunUnifill.prototype.Load = function(Color)
{
	this.Redo();

	var Unifill = this.Class.Pr.Unifill;
	if (AscCommon.CollaborativeEditing
		&& Unifill
		&& Unifill.fill
		&& Unifill.fill.type === Asc.c_oAscFill.FILL_TYPE_BLIP
		&& typeof Unifill.fill.RasterImageId === "string"
		&& Unifill.fill.RasterImageId.length > 0)
	{
		AscCommon.CollaborativeEditing.Add_NewImage(Unifill.fill.RasterImageId);
	}

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunUnifill.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesRunShd(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesRunShd.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesRunShd.prototype.constructor = CChangesRunShd;
CChangesRunShd.prototype.Type = AscDFH.historyitem_ParaRun_Shd;
CChangesRunShd.prototype.private_CreateObject = function()
{
	return new CDocumentShd();
};
CChangesRunShd.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.Shd = Value;

	oRun.Recalc_CompiledPr(false);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunShd.prototype.Load = function(Color)
{
	this.Redo();

	var Unifill = this.Class.Pr.Unifill;
	if (AscCommon.CollaborativeEditing
		&& Unifill
		&& Unifill.fill
		&& Unifill.fill.type === Asc.c_oAscFill.FILL_TYPE_BLIP
		&& typeof Unifill.fill.RasterImageId === "string"
		&& Unifill.fill.RasterImageId.length > 0)
	{
		AscCommon.CollaborativeEditing.Add_NewImage(Unifill.fill.RasterImageId);
	}

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunShd.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesRunMathStyle(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesRunMathStyle.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesRunMathStyle.prototype.constructor = CChangesRunMathStyle;
CChangesRunMathStyle.prototype.Type = AscDFH.historyitem_ParaRun_MathStyle;
CChangesRunMathStyle.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.MathPrp.sty = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunMathStyle.prototype.Merge = function(oChange)
{
	if (oChange.Class !== this.Class)
		return true;

	if (this.Type === oChange.Type || AscDFH.historyitem_ParaRun_MathPrp === oChange.Type)
		return false;

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesRunMathPrp(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesRunMathPrp.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesRunMathPrp.prototype.constructor = CChangesRunMathPrp;
CChangesRunMathPrp.prototype.Type = AscDFH.historyitem_ParaRun_MathPrp;
CChangesRunMathPrp.prototype.private_CreateObject = function()
{
	return new CMPrp();
};
CChangesRunMathPrp.prototype.private_IsCreateEmptyObject = function()
{
	return true;
};
CChangesRunMathPrp.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.MathPrp = Value;

	oRun.Recalc_CompiledPr(true);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunMathPrp.prototype.Merge = function(oChange)
{
	if (oChange.Class !== this.Class)
		return true;

	if (this.Type === oChange.Type)
		return false;

	if (!this.New)
		this.New = new CMPrp();

	if (AscDFH.historyitem_ParaRun_MathStyle === oChange.Type)
	{
		this.New.sty = oChange.New;
	}
	else if (AscDFH.historyitem_ParaRun_MathAlnAt === oChange.Type)
	{
		if (undefined !== this.New.brk)
			this.New.brk.Apply_AlnAt(oChange.New);
	}
	else if (AscDFH.historyitem_ParaRun_MathForcedBreak === oChange.Type)
	{
		if(oChange.bInsert)
			this.New.Insert_ForcedBreak(oChange.alnAt);
		else
			this.New.Delete_ForcedBreak();
	}


	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesRunReviewType(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesRunReviewType.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesRunReviewType.prototype.constructor = CChangesRunReviewType;
CChangesRunReviewType.prototype.Type = AscDFH.historyitem_ParaRun_ReviewType;
CChangesRunReviewType.prototype.WriteToBinary = function(Writer)
{
	// Long        : New ReviewType
	// CReviewInfo : New ReviewInfo
	// Long        : Old ReviewType
	// CReviewInfo : Old ReviewInfo
	Writer.WriteLong(this.New.ReviewType);
	this.New.ReviewInfo.Write_ToBinary(Writer);
	Writer.WriteLong(this.Old.ReviewType);
	this.Old.ReviewInfo.Write_ToBinary(Writer);
};
CChangesRunReviewType.prototype.ReadFromBinary = function(Reader)
{
	// Long        : New ReviewType
	// CReviewInfo : New ReviewInfo
	// Long        : Old ReviewType
	// CReviewInfo : Old ReviewInfo

	this.New = {
		ReviewType : reviewtype_Common,
		ReviewInfo : new CReviewInfo()
	};

	this.Old = {
		ReviewType : reviewtype_Common,
		ReviewInfo : new CReviewInfo()
	};

	this.New.ReviewType = Reader.GetLong();
	this.New.ReviewInfo.Read_FromBinary(Reader);
	this.Old.ReviewType = Reader.GetLong();
	this.Old.ReviewInfo.Read_FromBinary(Reader);
};
CChangesRunReviewType.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;

	oRun.ReviewType = Value.ReviewType;
	oRun.ReviewInfo = Value.ReviewInfo;
	oRun.private_UpdateTrackRevisions();
};
CChangesRunReviewType.prototype.Merge = function(oChange)
{
	if (oChange.Class !== this.Class)
		return true;

	if (this.Type === oChange.Type)
		return false;

	if (AscDFH.historyitem_ParaRun_ContentReviewInfo === oChange.Type)
		this.New.ReviewInfo = oChange.New;

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesRunPrChange(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesRunPrChange.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesRunPrChange.prototype.constructor = CChangesRunPrChange;
CChangesRunPrChange.prototype.Type = AscDFH.historyitem_ParaRun_PrChange;
CChangesRunPrChange.prototype.WriteToBinary = function(Writer)
{
	// Long : Flags
	// 1-bit : is New.PrChange undefined ?
	// 2-bit : is New.ReviewInfo undefined ?
	// 3-bit : is Old.PrChange undefined ?
	// 4-bit : is Old.ReviewInfo undefined ?
	// Variable(CTextPr)     : New.PrChange   (1bit = 0)
	// Variable(CReviewInfo) : New.ReviewInfo (2bit = 0)
	// Variable(CTextPr)     : Old.PrChange   (3bit = 0)
	// Variable(CReviewInfo) : Old.ReviewInfo (4bit = 0)
	var nFlags = 0;
	if (undefined === this.New.PrChange)
		nFlags |= 1;

	if (undefined === this.New.ReviewInfo)
		nFlags |= 2;

	if (undefined === this.Old.PrChange)
		nFlags |= 4;

	if (undefined === this.Old.ReviewInfo)
		nFlags |= 8;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New.PrChange)
		this.New.PrChange.Write_ToBinary(Writer);

	if (undefined !== this.New.ReviewInfo)
		this.New.ReviewInfo.Write_ToBinary(Writer);

	if (undefined !== this.Old.PrChange)
		this.Old.PrChange.Write_ToBinary(Writer);

	if (undefined !== this.Old.ReviewInfo)
		this.Old.ReviewInfo.Write_ToBinary(Writer);
};
CChangesRunPrChange.prototype.ReadFromBinary = function(Reader)
{
	// Long : Flags
	// 1-bit : is New.PrChange undefined ?
	// 2-bit : is New.ReviewInfo undefined ?
	// 3-bit : is Old.PrChange undefined ?
	// 4-bit : is Old.ReviewInfo undefined ?
	// Variable(CTextPr)     : New.PrChange   (1bit = 0)
	// Variable(CReviewInfo) : New.ReviewInfo (2bit = 0)
	// Variable(CTextPr)     : Old.PrChange   (3bit = 0)
	// Variable(CReviewInfo) : Old.ReviewInfo (4bit = 0)
	var nFlags = Reader.GetLong();

	this.New = {
		PrChange   : undefined,
		ReviewInfo : undefined
	};

	this.Old = {
		PrChange   : undefined,
		ReviewInfo : undefined
	};

	if (nFlags & 1)
	{
		this.New.PrChange = undefined;
	}
	else
	{
		this.New.PrChange = new CTextPr();
		this.New.PrChange.Read_FromBinary(Reader);
	}

	if (nFlags & 2)
	{
		this.New.ReviewInfo = undefined;
	}
	else
	{
		this.New.ReviewInfo = new CReviewInfo();
		this.New.ReviewInfo.Read_FromBinary(Reader);
	}

	if (nFlags & 4)
	{
		this.Old.PrChange = undefined;
	}
	else
	{
		this.Old.PrChange = new CTextPr();
		this.Old.PrChange.Read_FromBinary(Reader);
	}

	if (nFlags & 8)
	{
		this.Old.ReviewInfo = undefined;
	}
	else
	{
		this.Old.ReviewInfo = new CReviewInfo();
		this.Old.ReviewInfo.Read_FromBinary(Reader);
	}
};
CChangesRunPrChange.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;

	oRun.Pr.PrChange   = Value.PrChange;
	oRun.Pr.ReviewInfo = Value.ReviewInfo;
	oRun.private_UpdateTrackRevisions();
};
CChangesRunPrChange.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type || AscDFH.historyitem_ParaRun_TextPr === oChange.Type)
		return false;

	if (AscDFH.historyitem_ParaRun_PrReviewInfo === oChange.Type)
		this.New.ReviewInfo = oChange.New;

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesRunTextFill(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesRunTextFill.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesRunTextFill.prototype.constructor = CChangesRunTextFill;
CChangesRunTextFill.prototype.Type = AscDFH.historyitem_ParaRun_TextFill;
CChangesRunTextFill.prototype.private_CreateObject = function()
{
	return new AscFormat.CUniFill();
};
CChangesRunTextFill.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.TextFill = Value;

	oRun.Recalc_CompiledPr(false);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunTextFill.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunTextFill.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesRunTextOutline(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesRunTextOutline.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesRunTextOutline.prototype.constructor = CChangesRunTextOutline;
CChangesRunTextOutline.prototype.Type = AscDFH.historyitem_ParaRun_TextOutline;
CChangesRunTextOutline.prototype.private_CreateObject = function()
{
	return new AscFormat.CLn();
};
CChangesRunTextOutline.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.TextOutline = Value;

	oRun.Recalc_CompiledPr(false);
	oRun.private_UpdateTrackRevisionOnChangeTextPr(false);
};
CChangesRunTextOutline.prototype.Load = function(Color)
{
	this.Redo();

	if (this.Color && Color)
		this.Class.private_AddCollPrChangeOther(Color);
};
CChangesRunTextOutline.prototype.Merge = private_ParaRunChangesOnMergeTextPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesRunPrReviewInfo(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesRunPrReviewInfo.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesRunPrReviewInfo.prototype.constructor = CChangesRunPrReviewInfo;
CChangesRunPrReviewInfo.prototype.Type = AscDFH.historyitem_ParaRun_PrReviewInfo;
CChangesRunPrReviewInfo.prototype.private_CreateObject = function()
{
	return new CReviewInfo();
};
CChangesRunPrReviewInfo.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.Pr.ReviewInfo = Value;
};
CChangesRunPrReviewInfo.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type || AscDFH.historyitem_ParaRun_TextPr === oChange.Type || AscDFH.historyitem_ParaRun_PrChange === oChange.Type)
		return false;

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesRunContentReviewInfo(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesRunContentReviewInfo.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesRunContentReviewInfo.prototype.constructor = CChangesRunContentReviewInfo;
CChangesRunContentReviewInfo.prototype.Type = AscDFH.historyitem_ParaRun_ContentReviewInfo;
CChangesRunContentReviewInfo.prototype.private_CreateObject = function()
{
	return new CReviewInfo();
};
CChangesRunContentReviewInfo.prototype.private_IsCreateEmptyObject = function()
{
	return true;
};
CChangesRunContentReviewInfo.prototype.private_SetValue = function(Value)
{
	var oRun = this.Class;
	oRun.ReviewInfo = Value;
};
CChangesRunContentReviewInfo.prototype.Merge = function(oChange)
{
	if (oChange.Class !== this.Class)
		return true;

	if (this.Type === oChange.Type || AscDFH.historyitem_ParaRun_ReviewType === oChange.Type)
		return false;

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesRunOnStartSplit(Class, Pos)
{
	AscDFH.CChangesBase.call(this, Class);
	this.Pos = Pos;
}
CChangesRunOnStartSplit.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesRunOnStartSplit.prototype.constructor = CChangesRunOnStartSplit;
CChangesRunOnStartSplit.prototype.Type = AscDFH.historyitem_ParaRun_OnStartSplit;
CChangesRunOnStartSplit.prototype.Undo = function()
{
};
CChangesRunOnStartSplit.prototype.Redo = function()
{
};
CChangesRunOnStartSplit.prototype.WriteToBinary = function(Writer)
{
	Writer.WriteLong(this.Pos);
};
CChangesRunOnStartSplit.prototype.ReadFromBinary = function(Reader)
{
	this.Pos = Reader.GetLong();
};
CChangesRunOnStartSplit.prototype.Load = function()
{
	if (AscCommon.CollaborativeEditing)
		AscCommon.CollaborativeEditing.OnStart_SplitRun(this.Class, this.Pos);
};
CChangesRunOnStartSplit.prototype.CreateReverseChange = function()
{
	return null;
};
CChangesRunOnStartSplit.prototype.Merge = function(oChange)
{
	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesRunOnEndSplit(Class, NewRun)
{
	AscDFH.CChangesBase.call(this, Class);
	this.NewRun = NewRun;
}
CChangesRunOnEndSplit.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesRunOnEndSplit.prototype.constructor = CChangesRunOnEndSplit;
CChangesRunOnEndSplit.prototype.Type = AscDFH.historyitem_ParaRun_OnEndSplit;
CChangesRunOnEndSplit.prototype.Undo = function()
{
};
CChangesRunOnEndSplit.prototype.Redo = function()
{
};
CChangesRunOnEndSplit.prototype.WriteToBinary = function(Writer)
{
	Writer.WriteString2(this.NewRun.Get_Id());
};
CChangesRunOnEndSplit.prototype.ReadFromBinary = function(Reader)
{
	var RunId = Reader.GetString2();
	this.NewRun = g_oTableId.Get_ById(RunId);
};
CChangesRunOnEndSplit.prototype.Load = function()
{
	if (AscCommon.CollaborativeEditing)
		AscCommon.CollaborativeEditing.OnEnd_SplitRun(this.NewRun);
};
CChangesRunOnEndSplit.prototype.CreateReverseChange = function()
{
	return null;
};
CChangesRunOnEndSplit.prototype.Merge = function(oChange)
{
	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesRunMathAlnAt(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesRunMathAlnAt.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesRunMathAlnAt.prototype.constructor = CChangesRunMathAlnAt;
CChangesRunMathAlnAt.prototype.Type = AscDFH.historyitem_ParaRun_MathAlnAt;
CChangesRunMathAlnAt.prototype.private_SetValue = function(Value)
{
	this.Class.MathPrp.Apply_AlnAt(Value);
};
CChangesRunMathAlnAt.prototype.WriteToBinary = function(Writer)
{
	// Long : Flags
	// 1-bit : New is undefined ?
	// 2-bit : Old is undefined ?
	// 1bit = 0 long : this.New
	// 2bit = 0 long : this.Old

	var nFlags = 0;
	if (undefined === this.New)
		nFlags |= 1;

	if (undefined === this.Old)
		nFlags |= 2;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New)
		Writer.WriteLong(this.New);

	if (undefined !== this.Old)
		Writer.WriteLong(this.Old);
};
CChangesRunMathAlnAt.prototype.ReadFromBinary = function(Reader)
{
	// Long : Flags
	// 1-bit : New is undefined ?
	// 2-bit : Old is undefined ?
	// 1bit = 0 long : this.New
	// 2bit = 0 long : this.Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.New = undefined;
	else
		this.New = Reader.GetLong();

	if (nFlags & 2)
		this.Old = undefined;
	else
		this.Old = Reader.GetLong();
};
CChangesRunMathAlnAt.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type || AscDFH.historyitem_ParaRun_MathPrp === oChange.Type || AscDFH.historyitem_ParaRun_MathForcedBreak === oChange.Type)
		return false;

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesRunMathForcedBreak(Class, bInsert, alnAt)
{
	AscDFH.CChangesBase.call(this, Class);

	this.bInsert = bInsert;
	this.alnAt   = alnAt;
}
CChangesRunMathForcedBreak.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesRunMathForcedBreak.prototype.constructor = CChangesRunMathForcedBreak;
CChangesRunMathForcedBreak.prototype.Type = AscDFH.historyitem_ParaRun_MathForcedBreak;
CChangesRunMathForcedBreak.prototype.Undo = function()
{
	var oRun = this.Class;

	if(this.bInsert)
		oRun.MathPrp.Delete_ForcedBreak();
	else
		oRun.MathPrp.Insert_ForcedBreak(this.alnAt);
};
CChangesRunMathForcedBreak.prototype.Redo = function()
{
	var oRun = this.Class;

	if(this.bInsert)
		oRun.MathPrp.Insert_ForcedBreak(this.alnAt);
	else
		oRun.MathPrp.Delete_ForcedBreak();
};
CChangesRunMathForcedBreak.prototype.WriteToBinary = function(Writer)
{
	// Long : Flags
	// 1-bit : bInsert ?
	// 2-bit : alnAt is undefined ?
	// 2bit = 0 long : this.alnAt

	var nFlags = 0;
	if (true === this.bInsert)
		nFlags |= 1;

	if (undefined === this.alnAt)
		nFlags |= 2;

	Writer.WriteLong(nFlags);

	if (undefined !== this.alnAt)
		Writer.WriteLong(this.alnAt);
};
CChangesRunMathForcedBreak.prototype.ReadFromBinary = function(Reader)
{
	// Long : Flags
	// 1-bit : bInsert ?
	// 2-bit : alnAt is undefined ?
	// 2bit = 0 long : this.alnAt

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.bInsert = true;
	else
		this.bInsert = false;

	if (nFlags & 2)
		this.alnAt = undefined;
	else
		this.alnAt = Reader.GetLong();
};
CChangesRunMathForcedBreak.prototype.CreateReverseChange = function()
{
	return new CChangesRunMathForcedBreak(this.Class, !this.bInsert, this.alnAt);
};
CChangesRunMathForcedBreak.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type || AscDFH.historyitem_ParaRun_MathPrp === oChange.Type)
		return false;

	if (AscDFH.historyitem_ParaRun_MathAlnAt === oChange.Type)
		this.alnAt = oChange.New;

	return true;
};



/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var align_Right = AscCommon.align_Right;
var align_Left = AscCommon.align_Left;
var align_Center = AscCommon.align_Center;
var align_Justify = AscCommon.align_Justify;
var g_oTableId = AscCommon.g_oTableId;
var History = AscCommon.History;

var g_dMathArgSizeKoeff_1 = 0.76;
var g_dMathArgSizeKoeff_2 = 0.6498; // 0.76 * 0.855

function CMathPropertiesSettings()
{
    this.brkBin     = null;

    this.defJc      = null;
    this.dispDef    = null;  // свойство: применять/ не применять paragraph settings (в тч defJc)

    this.intLim     = null;
    this.naryLim    = null;

    this.lMargin    = null;
    this.rMargin    = null;
    this.wrapIndent = null;
    this.wrapRight  = null;

    this.smallFrac  = null;

    //   не реализовано    //

    // for minus operator
    // when brkBin is set to repeat
    this.brkBinSub  = null;

    //***** WORD IGNORES followings parameters *****//

    // mathFont: в качестве font поддерживается только Cambria Math
    // остальные шрифты  возможно будут поддержаны MS Word в будущем

    this.mathFont   = null;

    // Default font for math zones
    // Gives a drop-down list of math fonts that can be used as the default math font to be used in the document.
    // Currently only Cambria Math has thorough math support, but others such as the STIX fonts are coming soon.

    // http://blogs.msdn.com/b/murrays/archive/2008/10/27/default-document-math-properties.aspx


    // http://msdn.microsoft.com/en-us/library/ff529906(v=office.12).aspx
    // Word ignores the interSp attribute and fails to write it back out.
    this.interSp    = null;
    // http://msdn.microsoft.com/en-us/library/ff529301(v=office.12).aspx
    // Word does not implement this feature and does not write the intraSp element.
    this.intraSp    = null;

    // http://msdn.microsoft.com/en-us/library/ff533406(v=office.12).aspx
    this.postSp     = null;
    this.preSp      = null;

    // RichEdit Hot Keys
    // http://blogs.msdn.com/b/murrays/archive/2013/10/30/richedit-hot-keys.aspx

    //*********************//
}
CMathPropertiesSettings.prototype.SetDefaultPr = function()
{
    this.brkBin     = BREAK_BEFORE;
    this.defJc      = align_Justify;
    this.dispDef    = true;
    this.intLim     = NARY_SubSup;
    this.mathFont   = {Name  : "Cambria Math", Index : -1 };
    this.lMargin    = 0;
    this.naryLim    = NARY_UndOvr;
    this.rMargin    = 0;
    this.smallFrac  = false;
    this.wrapIndent = 25; // mm
    this.wrapRight  = false;
};
CMathPropertiesSettings.prototype.Merge = function(Pr)
{
    if(Pr.wrapIndent !== null && Pr.wrapIndent !== undefined)
        this.wrapIndent = Pr.wrapIndent;

    if(Pr.lMargin !== null && Pr.lMargin !== undefined)
        this.lMargin = Pr.lMargin;

    if(Pr.rMargin !== null && Pr.rMargin !== undefined)
        this.rMargin = Pr.rMargin;

    if(Pr.intLim !== null && Pr.intLim !== undefined)
        this.intLim = Pr.intLim;

    if(Pr.naryLim !== null && Pr.naryLim !== undefined)
        this.naryLim = Pr.naryLim;

    if(Pr.defJc !== null && Pr.defJc !== undefined)
        this.defJc = Pr.defJc;

    if(Pr.brkBin !== null && Pr.brkBin !== undefined)
        this.brkBin = Pr.brkBin;

    if(Pr.dispDef !== null && Pr.dispDef !== undefined)
        this.dispDef = Pr.dispDef;
	
    if(Pr.mathFont !== null && Pr.mathFont !== undefined)
        this.mathFont = Pr.mathFont;

    if(Pr.wrapRight !== null && Pr.wrapRight !== undefined)
        this.wrapRight = Pr.wrapRight;

    if(Pr.smallFrac !== null && Pr.smallFrac !== undefined)
        this.smallFrac = Pr.smallFrac;
};
CMathPropertiesSettings.prototype.Copy = function()
{
    var NewPr = new CMathPropertiesSettings();

    NewPr.brkBin     = this.brkBin;
    NewPr.defJc      = this.defJc;
    NewPr.dispDef    = this.dispDef;
    NewPr.intLim     = this.intLim;
    NewPr.lMargin    = this.lMargin;
    NewPr.naryLim    = this.naryLim;
    NewPr.rMargin    = this.rMargin;
    NewPr.wrapIndent = this.wrapIndent;
    NewPr.brkBinSub  = this.brkBinSub;
    NewPr.interSp    = this.interSp;
    NewPr.intraSp    = this.intraSp;
    NewPr.mathFont   = this.mathFont;
    NewPr.postSp     = this.postSp;
    NewPr.preSp      = this.preSp;
    NewPr.smallFrac  = this.smallFrac;
    NewPr.wrapRight  = this.wrapRight;

    return NewPr;
};
CMathPropertiesSettings.prototype.Write_ToBinary = function(Writer)
{
    var StartPos = Writer.GetCurPosition();
    Writer.Skip(4);
    var Flags = 0;

    if(undefined !== this.brkBin)
    {
        Writer.WriteLong( this.brkBin );
        Flags |= 1;
    }

    if(undefined !== this.brkBinSub)
    {
        Writer.WriteLong( this.brkBinSub );
        Flags |= 2;
    }

    if(undefined !== this.defJc)
    {
        Writer.WriteLong( this.defJc );
        Flags |= 4;
    }

    if(undefined !== this.dispDef)
    {
        Writer.WriteBool( this.dispDef );
        Flags |= 8;
    }

    if(undefined !== this.interSp)
    {
        Writer.WriteLong( this.interSp );
        Flags |= 16;
    }

    if(undefined !== this.intLim)
    {
        Writer.WriteLong( this.intLim );
        Flags |= 32;
    }

    if(undefined !== this.intraSp)
    {
        Writer.WriteLong( this.intraSp );
        Flags |= 64;
    }

    if(undefined !== this.lMargin)
    {
        Writer.WriteLong( this.lMargin );
        Flags |= 128;
    }

    if(undefined !== this.mathFont)
    {
        Writer.WriteString2( this.mathFont.Name );
        Flags |= 256;
    }

    if(undefined !== this.naryLim)
    {
        Writer.WriteLong( this.naryLim );
        Flags |= 512;
    }

    if(undefined !== this.postSp)
    {
        Writer.WriteLong( this.postSp );
        Flags |= 1024;
    }

    if(undefined !== this.preSp)
    {
        Writer.WriteLong( this.preSp );
        Flags |= 2048;
    }

    if(undefined !== this.rMargin)
    {
        Writer.WriteLong( this.rMargin );
        Flags |= 4096;
    }

    if(undefined !== this.smallFrac)
    {
        Writer.WriteBool( this.smallFrac );
        Flags |= 8192;
    }

    if(undefined !== this.wrapIndent)
    {
        Writer.WriteLong( this.wrapIndent );
        Flags |= 16384;
    }

    if(undefined !== this.wrapRight)
    {
        Writer.WriteBool( this.wrapRight );
        Flags |= 32768;
    }

    var EndPos = Writer.GetCurPosition();
    Writer.Seek( StartPos );
    Writer.WriteLong( Flags );
    Writer.Seek( EndPos );
};
CMathPropertiesSettings.prototype.Read_FromBinary = function(Reader)
{
    var Flags = Reader.GetLong();

    if ( Flags & 1 )
        this.brkBin = Reader.GetLong();

    if( Flags & 2 )
        this.brkBinSub = Reader.GetLong();

    if( Flags & 4 )
        this.defJc = Reader.GetLong();

    if( Flags & 8 )
        this.dispDef = Reader.GetBool();

    if( Flags & 16 )
        this.interSp = Reader.GetLong();

    if( Flags & 32 )
        this.intLim = Reader.GetLong();

    if( Flags & 64 )
        this.intraSp = Reader.GetLong();

    if( Flags & 128 )
        this.lMargin = Reader.GetLong();

    if( Flags & 256 )
    {
        this.mathFont =
        {
            Name  : Reader.GetString2(),
            Index : -1
        };
    }

    if( Flags & 512 )
        this.naryLim = Reader.GetLong();

    if( Flags & 1024 )
        this.postSp = Reader.GetLong();

    if( Flags & 2048 )
        this.preSp = Reader.GetLong();

    if( Flags & 4096 )
        this.rMargin = Reader.GetLong();

    if( Flags & 8192 )
        this.smallFrac = Reader.GetBool();

    if( Flags & 16384 )
        this.wrapIndent = Reader.GetLong();

    if( Flags & 32768 )
        this.wrapRight = Reader.GetBool();


};

function CMathSettings()
{
    this.Pr         = new CMathPropertiesSettings();
    this.CompiledPr = new CMathPropertiesSettings();
    this.DefaultPr  = new CMathPropertiesSettings();

    this.DefaultPr.SetDefaultPr();

    this.bNeedCompile = true;
}
CMathSettings.prototype.SetPr = function(Pr)
{
    this.bNeedCompile = true;
    this.Pr.Merge(Pr);
    this.SetCompiledPr();
};
CMathSettings.prototype.GetPr = function()
{
    return this.Pr;
};
CMathSettings.prototype.SetCompiledPr = function()
{
    if(this.bNeedCompile)
    {
        this.CompiledPr.Merge(this.DefaultPr);
        this.CompiledPr.Merge(this.Pr);

        this.bNeedCompile = false;
    }
};
CMathSettings.prototype.GetPrDispDef = function()
{
    var Pr;
    if(this.CompiledPr.dispDef ==  false)
        Pr = this.DefaultPr;
    else
        Pr = this.CompiledPr;

    return Pr;
};
CMathSettings.prototype.Get_WrapIndent = function(WrapState)
{
    this.SetCompiledPr();

    var wrapIndent = 0;
    if(this.wrapRight == false && (WrapState == ALIGN_MARGIN_WRAP || WrapState == ALIGN_WRAP))
        wrapIndent = this.GetPrDispDef().wrapIndent;

    return wrapIndent;
};
CMathSettings.prototype.Get_LeftMargin = function(WrapState)
{
    this.SetCompiledPr();

    var lMargin = 0;
    if(WrapState == ALIGN_MARGIN_WRAP || WrapState == ALIGN_MARGIN)
        lMargin = this.GetPrDispDef().lMargin;

    return lMargin;
};
CMathSettings.prototype.Get_RightMargin = function(WrapState)
{
    this.SetCompiledPr();
    var rMargin    =  0;
    if(WrapState == ALIGN_MARGIN_WRAP || WrapState == ALIGN_MARGIN)
        rMargin = this.GetPrDispDef().rMargin;

    return rMargin;
};
CMathSettings.prototype.Get_IntLim = function()
{
    this.SetCompiledPr();
    return this.CompiledPr.intLim;
};
CMathSettings.prototype.Get_NaryLim = function()
{
    this.SetCompiledPr();
    return this.CompiledPr.naryLim;
};
CMathSettings.prototype.Get_DefJc = function()
{
    this.SetCompiledPr();
    return this.GetPrDispDef().defJc;
};
CMathSettings.prototype.Get_DispDef = function()
{
    this.SetCompiledPr();
    return this.CompiledPr.dispDef;
};
CMathSettings.prototype.Get_BrkBin = function()
{
    this.SetCompiledPr();
    return this.CompiledPr.brkBin;
};
CMathSettings.prototype.Get_WrapRight = function()
{
    this.SetCompiledPr();
    return this.CompiledPr.wrapRight;
};
CMathSettings.prototype.Get_SmallFrac = function()
{
    this.SetCompiledPr();
    return this.CompiledPr.smallFrac;
};
CMathSettings.prototype.Get_MenuProps = function()
{
    return new CMathMenuSettings(this.CompiledPr);
};
CMathSettings.prototype.Set_MenuProps = function(Props)
{
    if(Props.BrkBin !== undefined)
    {
        this.Pr.brkBin = Props.BrkBin == c_oAscMathInterfaceSettingsBrkBin.BreakAfter ? BREAK_AFTER : BREAK_BEFORE;
    }

    if(Props.Justification !== undefined)
    {
        switch(Props.Justification)
        {
            case c_oAscMathInterfaceSettingsAlign.Justify:
            {
                this.Pr.defJc = align_Justify;
                break;
            }
            case c_oAscMathInterfaceSettingsAlign.Center:
            {
                this.Pr.defJc = align_Center;
                break;
            }
            case c_oAscMathInterfaceSettingsAlign.Left:
            {
                this.Pr.defJc = align_Left;
                break;
            }
            case c_oAscMathInterfaceSettingsAlign.Right:
            {
                this.Pr.defJc = align_Right;
                break;
            }
        }
    }

    if(Props.UseSettings !== undefined)
    {
        this.Pr.dispDef = Props.UseSettings;
    }

    if(Props.IntLim !== undefined)
    {
        if(Props.IntLim == Asc.c_oAscMathInterfaceNaryLimitLocation.SubSup)
        {
            this.Pr.intLim = NARY_SubSup;
        }
        else if(Props.IntLim == Asc.c_oAscMathInterfaceNaryLimitLocation.UndOvr)
        {
            this.Pr.intLim = NARY_UndOvr;
        }
    }

    if(Props.NaryLim !== undefined)
    {
        if(Props.NaryLim == Asc.c_oAscMathInterfaceNaryLimitLocation.SubSup)
        {
            this.Pr.naryLim = NARY_SubSup;
        }
        else if(Props.NaryLim == Asc.c_oAscMathInterfaceNaryLimitLocation.UndOvr)
        {
            this.Pr.naryLim = NARY_UndOvr;
        }
    }

    if(Props.LeftMargin !== undefined && Props.LeftMargin == Props.LeftMargin + 0)
    {
        this.Pr.lMargin = Props.LeftMargin;
    }

    if(Props.RightMargin !== undefined && Props.RightMargin == Props.RightMargin + 0)
    {
        this.Pr.rMargin = Props.RightMargin;
    }

    if(Props.WrapIndent !== undefined && Props.WrapIndent == Props.WrapIndent + 0)
    {
        this.Pr.wrapIndent = Props.WrapIndent;
    }

    if(Props.WrapRight !== undefined && Props.WrapRight !== null)
    {
        this.Pr.wrapRight = Props.WrapRight;
    }

    this.bNeedCompile = true;

};
CMathSettings.prototype.Write_ToBinary = function(Writer)
{
    this.Pr.Write_ToBinary(Writer);
};
CMathSettings.prototype.Read_FromBinary = function(Reader)
{
    this.Pr.Read_FromBinary(Reader);
    this.bNeedCompile = true;
};


function CMathMenuSettings(oMathPr)
{
    if(oMathPr)
    {
        this.BrkBin = oMathPr.brkBin === BREAK_AFTER ? c_oAscMathInterfaceSettingsBrkBin.BreakAfter : c_oAscMathInterfaceSettingsBrkBin.BreakBefore;

        switch(oMathPr.defJc)
        {
            case align_Justify:
            {
                this.Justification  = c_oAscMathInterfaceSettingsAlign.Justify;
                break;
            }
            case align_Center:
            {
                this.Justification  = c_oAscMathInterfaceSettingsAlign.Center;
                break;
            }
            case align_Left:
            {
                this.Justification  = c_oAscMathInterfaceSettingsAlign.Left;
                break;
            }
            case align_Right :
            {
                this.Justification  = c_oAscMathInterfaceSettingsAlign.Right;
                break;
            }
            default:
            {
                this.Justification  = align_Justify;
                break;
            }
        }

        this.UseSettings    = oMathPr.dispDef;

        this.IntLim         = oMathPr.intLim === NARY_SubSup ? Asc.c_oAscMathInterfaceNaryLimitLocation.SubSup : Asc.c_oAscMathInterfaceNaryLimitLocation.UndOvr;
        this.NaryLim        = oMathPr.naryLim === NARY_SubSup ? Asc.c_oAscMathInterfaceNaryLimitLocation.SubSup : Asc.c_oAscMathInterfaceNaryLimitLocation.UndOvr;

        this.LeftMargin     = oMathPr.lMargin/10;
        this.RightMargin    = oMathPr.rMargin/10;
        this.WrapIndent     = oMathPr.wrapIndent/10;
        this.WrapRight      = oMathPr.wrapRight;
        this.SmallFraction  = oMathPr.smallFrac;
    }
    else
    {
        this.BrkBin          = undefined;
        this.Justification   = undefined;
        this.UseSettings     = undefined;
        this.IntLim          = undefined;
        this.NaryLim         = undefined;
        this.LeftMargin      = undefined;
        this.RightMargin     = undefined;
        this.WrapIndent      = undefined;
        this.WrapRight       = undefined;
        this.SmallFraction   = undefined;
    }
}
CMathMenuSettings.prototype.get_BreakBin = function(){ return this.BrkBin;};
CMathMenuSettings.prototype.put_BreakBin = function(BreakBin){ this.BrkBin = BreakBin;};
CMathMenuSettings.prototype.get_UseSettings = function(){ return this.UseSettings;};
CMathMenuSettings.prototype.put_UseSettings = function(UseSettings){ this.UseSettings = UseSettings;};
CMathMenuSettings.prototype.get_Justification = function(){ return this.Justification;};
CMathMenuSettings.prototype.put_Justification = function(Align){ this.Justification = Align;};
CMathMenuSettings.prototype.get_IntLim = function(){ return this.IntLim;};
CMathMenuSettings.prototype.put_IntLim = function(IntLim){ this.IntLim = IntLim;};
CMathMenuSettings.prototype.get_NaryLim = function(){ return this.NaryLim;};
CMathMenuSettings.prototype.put_NaryLim = function(NaryLim){ this.NaryLim = NaryLim;};
CMathMenuSettings.prototype.get_LeftMargin = function(){ return this.LeftMargin;};
CMathMenuSettings.prototype.put_LeftMargin = function(lMargin){ this.LeftMargin = lMargin;};
CMathMenuSettings.prototype.get_RightMargin = function(){ return this.RightMargin;};
CMathMenuSettings.prototype.put_RightMargin = function(rMargin){ this.RightMargin = rMargin;};
CMathMenuSettings.prototype.get_WrapIndent = function(){return this.WrapIndent;};
CMathMenuSettings.prototype.put_WrapIndent = function(WrapIndent){this.WrapIndent = WrapIndent;};
CMathMenuSettings.prototype.get_WrapRight = function(){ return this.WrapRight;};
CMathMenuSettings.prototype.put_WrapRight = function(WrapRight){ this.WrapRight = WrapRight;};
CMathMenuSettings.prototype.get_SmallFraction = function() {return this.SmallFraction;};
CMathMenuSettings.prototype.put_SmallFraction = function(SmallFrac) {this.SmallFraction = SmallFrac;};

window["CMathMenuSettings"]                         = CMathMenuSettings;
CMathMenuSettings.prototype["get_BreakBin"]        = CMathMenuSettings.prototype.get_BreakBin;
CMathMenuSettings.prototype["put_BreakBin"]        = CMathMenuSettings.prototype.put_BreakBin;
CMathMenuSettings.prototype["get_UseSettings"]     = CMathMenuSettings.prototype.get_UseSettings;
CMathMenuSettings.prototype["put_UseSettings"]     = CMathMenuSettings.prototype.put_UseSettings;
CMathMenuSettings.prototype["get_Justification"]   = CMathMenuSettings.prototype.get_Justification;
CMathMenuSettings.prototype["put_Justification"]   = CMathMenuSettings.prototype.put_Justification;
CMathMenuSettings.prototype["get_IntLim"]          = CMathMenuSettings.prototype.get_IntLim;
CMathMenuSettings.prototype["put_IntLim"]          = CMathMenuSettings.prototype.put_IntLim;
CMathMenuSettings.prototype["get_NaryLim"]         = CMathMenuSettings.prototype.get_NaryLim;
CMathMenuSettings.prototype["put_NaryLim"]         = CMathMenuSettings.prototype.put_NaryLim;
CMathMenuSettings.prototype["get_LeftMargin"]      = CMathMenuSettings.prototype.get_LeftMargin;
CMathMenuSettings.prototype["put_LeftMargin"]      = CMathMenuSettings.prototype.put_LeftMargin;
CMathMenuSettings.prototype["get_RightMargin"]     = CMathMenuSettings.prototype.get_RightMargin;
CMathMenuSettings.prototype["put_RightMargin"]     = CMathMenuSettings.prototype.put_RightMargin;
CMathMenuSettings.prototype["get_WrapIndent"]      = CMathMenuSettings.prototype.get_WrapIndent;
CMathMenuSettings.prototype["put_WrapIndent"]      = CMathMenuSettings.prototype.put_WrapIndent;
CMathMenuSettings.prototype["get_WrapRight"]       = CMathMenuSettings.prototype.get_WrapRight;
CMathMenuSettings.prototype["put_WrapRight"]       = CMathMenuSettings.prototype.put_WrapRight;
CMathMenuSettings.prototype["get_SmallFraction"]   = CMathMenuSettings.prototype.get_SmallFraction;
CMathMenuSettings.prototype["put_SmallFraction"]   = CMathMenuSettings.prototype.put_SmallFraction;


function Get_WordDocumentDefaultMathSettings()
{
    if (!editor || !editor.WordControl.m_oLogicDocument || !editor.WordControl.m_oLogicDocument.Settings)
        return new CMathSettings();

    return editor.WordControl.m_oLogicDocument.Settings.MathSettings;
}

function MathMenu(type)
{
	this.Type = para_Math;
	this.Menu = type == undefined ? c_oAscMathType.Default_Text : type;
}
MathMenu.prototype =
{
	Get_Type : function()
    {
        return this.Type;
    }
};

function CMathLineState()
{
    this.StyleLine        = MATH_LINE_WRAP;
    this.Width            = 0;
    this.SpaceAlign       = 0;
    this.MaxWidth         = 0;
    this.WrapState        = ALIGN_EMPTY;
}

function CMathLineInfo()
{
    this.StyleLine        = MATH_LINE_WRAP;
    this.Measure          = 0;
    this.SpaceAlign       = 0;
    this.bWordLarge       = false;
}
CMathLineInfo.prototype.Get_GeneralWidth = function()
{
    return this.Measure + this.SpaceAlign;
};

function CParaMathLineParameters(FirstLineNumber)
{
    this.FirstLineNumber  = FirstLineNumber;
    this.WrapState        = ALIGN_EMPTY;

    this.LineParameters    = [];

    this.MaxW             = 0;

    this.bMathWordLarge   = false;
    this.NeedUpdateWrap   = true;
}
CParaMathLineParameters.prototype.Update_Width = function(Line, W)
{
    var bUpdMaxWidth = false;
    var NumLine = this.private_GetNumberLine(Line);

    if(Math.abs(this.LineParameters[NumLine].Measure - W) > 0.00001)
    {
        var Max = this.MaxW;
        var CountLines = this.LineParameters.length;

        this.LineParameters[NumLine].Measure = W;

        this.MaxW = this.LineParameters[0].Get_GeneralWidth();

        for(var Pos = 1; Pos < CountLines; Pos++)
        {
            var GeneralWidth = this.LineParameters[Pos].Get_GeneralWidth();

            if(this.MaxW < GeneralWidth)
                this.MaxW = GeneralWidth;
        }

        bUpdMaxWidth = Math.abs(Max - this.MaxW) > 0.0001;
    }

    return bUpdMaxWidth;
};
CParaMathLineParameters.prototype.Set_WordLarge = function(Line, bWordLarge)
{
    var NumLine = this.private_GetNumberLine(Line);

    if(this.WrapState !== ALIGN_EMPTY)
        bWordLarge = false;

    if(bWordLarge)
    {
        this.bMathWordLarge = true;
        this.LineParameters[NumLine].bWordLarge = true;
    }
    else
    {
        this.bMathWordLarge = false;

        var CountLines = this.LineParameters.length;

        for(var Pos = 0; Pos < CountLines; Pos++)
        {
            if(this.LineParameters[Pos].bWordLarge == true)
            {
                this.bMathWordLarge = true;
                break;
            }
        }

        this.LineParameters[NumLine].bWordLarge = false;
    }
};
CParaMathLineParameters.prototype.Add_Line = function(Line, bStartLine, bStartPage, AlignAt)
{
    var bInsideBounds = true;

    var NumLine = this.private_GetNumberLine(Line);

    if(NumLine >= this.LineParameters.length)
    {
        this.LineParameters[NumLine] = new CMathLineInfo();

        if(bStartLine)
        {
            this.LineParameters[NumLine].StyleLine = MATH_LINE_START;
        }
        else if(AlignAt !== undefined && AlignAt !== null)
        {
            this.LineParameters[NumLine].StyleLine  = MATH_LINE_ALiGN_AT;
            this.LineParameters[NumLine].SpaceAlign = AlignAt;
        }
        else
        {
            var MathSettings = Get_WordDocumentDefaultMathSettings();

            this.LineParameters[NumLine].StyleLine  = MATH_LINE_WRAP;
            this.LineParameters[NumLine].SpaceAlign = bStartPage == true ? MathSettings.Get_WrapIndent(this.WrapState) : 0;
        }


        bInsideBounds = false;
    }

    return bInsideBounds;
};
CParaMathLineParameters.prototype.Is_Large = function()
{
    return this.bMathWordLarge;
};
CParaMathLineParameters.prototype.Get_MaxWidth = function()
{
    return this.MaxW;
};
CParaMathLineParameters.prototype.private_GetNumberLine = function(NumLine)
{
    return NumLine - this.FirstLineNumber;
};
CParaMathLineParameters.prototype.Get_LineState = function(Line)
{
    var NumLine = this.private_GetNumberLine(Line);

    var LineInfo  = this.LineParameters[NumLine];

    var LineState = new CMathLineState();
    LineState.StyleLine  = LineInfo.StyleLine;
    LineState.Width      = LineInfo.Measure;
    LineState.SpaceAlign = this.Get_SpaceAlign(Line);
    LineState.MaxWidth   = this.MaxW;
    LineState.WrapState  = this.WrapState;

    return LineState;
};
CParaMathLineParameters.prototype.Get_SpaceAlign = function(Line)
{
    var NumLine = this.private_GetNumberLine(Line);

    var SpaceAlign = 0;

    if(this.bMathWordLarge == false && (this.WrapState == ALIGN_MARGIN_WRAP || this.WrapState == ALIGN_WRAP))
        SpaceAlign = this.LineParameters[NumLine].SpaceAlign;

    return SpaceAlign;
};


function CMathPageInfo()
{
    this.WPages            = [];    // widths on page
    this.StartLine         = -1;
    this.StartPage         = -1;
    this.CurPage           = -1;
    this.RelativePage      = -1;
}
CMathPageInfo.prototype.Reset = function()
{
    this.StartLine         = -1;
    this.StartPage         = -1;
    this.CurPage           = -1;
    this.RelativePage      = -1;
    this.WPages.length     =  0;
};
CMathPageInfo.prototype.Reset_Page = function(_Page)
{
    if(this.StartPage >= 0) // если нет, то только начали расчет формулы
    {
        var Page = _Page - this.StartPage;

        if(Page < this.WPages.length) // если нет, то только начали расчет страницы
        {
            // уберем из массива информацию о страницах, начиная с текущей
            // не делаем Reset для текущей страницы, т.к. это приведет к тому, что выставятся только параметры по умолчанию
            // а проверка на стартовую позицию рассчитана именно на длину массива this.WPages
            this.WPages.length = Page;
        }
    }
};
CMathPageInfo.prototype.Set_StartPos = function(Page, StartLine)
{
    this.StartPage   = Page;
    this.StartLine   = StartLine;
};
CMathPageInfo.prototype.Update_RelativePage = function(RelativePage)
{
    this.RelativePage = RelativePage;
};
CMathPageInfo.prototype.Update_CurrentPage = function(Page, ParaLine)
{
    this.CurPage = Page - this.StartPage;

    var Lng = this.WPages.length;
    if(this.CurPage >= Lng)
    {
        var FirstLineOnPage = ParaLine - this.StartLine;
        this.WPages[this.CurPage] = new CParaMathLineParameters(FirstLineOnPage);
    }
};
CMathPageInfo.prototype.Update_CurrentWrap = function(DispDef, bInline)
{
    if(this.WPages[this.CurPage].NeedUpdateWrap == true)
    {
        var WrapState;

        if(DispDef == false || bInline == true)
            WrapState = ALIGN_EMPTY;
        else if(this.CurPage == 0)
            WrapState = ALIGN_MARGIN_WRAP;
        else
            WrapState = ALIGN_MARGIN;

        this.WPages[this.CurPage].WrapState = WrapState;
        this.WPages[this.CurPage].NeedUpdateWrap = false;
    }
};
CMathPageInfo.prototype.Set_NeedUpdateWrap = function()
{
    this.WPages[this.CurPage].NeedUpdateWrap = true;
};
CMathPageInfo.prototype.Set_CurrentWrapState = function(WrapState)
{
    this.WPages[this.CurPage].WrapState = WrapState;
};
CMathPageInfo.prototype.Set_NextWrapState = function()
{
    var InfoPage = this.WPages[this.CurPage];

    if(InfoPage.WrapState !== ALIGN_EMPTY)
        InfoPage.WrapState++;
};
CMathPageInfo.prototype.Set_StateWordLarge = function(_Line, bWordLarge)
{
    this.WPages[this.CurPage].Set_WordLarge(_Line - this.StartLine, bWordLarge);
};
CMathPageInfo.prototype.Get_CurrentWrapState = function()
{
    return this.WPages[this.CurPage].WrapState;
};
CMathPageInfo.prototype.Get_CurrentStateWordLarge = function()
{
    return this.WPages[this.CurPage].Is_Large();
};
CMathPageInfo.prototype.Update_CurrentWidth = function(_Line, Width)
{
    return this.WPages[this.CurPage].Update_Width(_Line - this.StartLine, Width);
};
CMathPageInfo.prototype.Get_MaxWidthOnCurrentPage = function()
{
    return this.WPages[this.CurPage].Get_MaxWidth();
};
CMathPageInfo.prototype.Get_FirstLineOnPage = function(_Page)
{
    var FirstLineOnPage = null;
    var Page = _Page - this.StartPage;

    if(Page >= 0 && Page < this.WPages.length)
        FirstLineOnPage = this.StartLine + this.WPages[Page].FirstLineNumber;

    return FirstLineOnPage;
};
CMathPageInfo.prototype.Is_ResetNextPage = function(_Page)
{
    var bReset = true;

    if(this.CurPage == -1)
    {
        bReset = false;
    }
    else
    {
        var Page = _Page - this.StartPage;
        bReset = this.CurPage < Page;
    }

    return bReset;
};
CMathPageInfo.prototype.Is_ResetRelativePage = function(_RelativePage)
{
    return this.CurPage == -1 ? false : _RelativePage !== this.RelativePage;
};
CMathPageInfo.prototype.Is_FirstLineOnPage = function(_Line, _Page)
{
    var bFirstLine = true;

    if(this.StartPage >= 0) // если нет, то только начали расчет формулы
    {
        var Page = _Page - this.StartPage;

        if(Page < this.WPages.length) // если нет, то только начали расчет страницы
            bFirstLine = _Line == this.Get_FirstLineOnPage(_Page);
    }

    return bFirstLine;
};
CMathPageInfo.prototype.Get_LineState = function(_Line, _Page)
{
    var Page = _Page - this.StartPage;

    return this.WPages[Page].Get_LineState(_Line - this.StartLine);
};
// создаем новый объект с параметрами, необходимые для рассчета линий в ф-ии ParaMath.private_UpdateXLimits
// именно в этой функции нужно получить смещения линий (Wrap, Align)
// это происходит до принятия ширины контента для текущей линии (функция Update_CurrentWidth) и до получения флага WordLarge (функция Set_StateWordLarge)
CMathPageInfo.prototype.Add_Line = function(_Line, _Page, AlignAt)
{
    var Page       = _Page - this.StartPage,
        Line       = _Line - this.StartLine,
        bStartLine = _Line == this.StartLine,
        bStartPage = _Page == this.StartPage;

    this.WPages[Page].Add_Line(Line, bStartLine, bStartPage, AlignAt);
};
CMathPageInfo.prototype.Get_SpaceAlign = function(_Line, _Page)
{
    var Page       = _Page - this.StartPage,
        Line       = _Line - this.StartLine;

    return this.WPages[Page].Get_SpaceAlign(Line);
};



/**
 *
 * @constructor
 * @extends {CParagraphContentWithContentBase}
 */
function ParaMath()
{
	CParagraphContentWithContentBase.call(this);

    this.Id                 = AscCommon.g_oIdCounter.Get_NewId();
    this.Type               = para_Math;

    this.Jc                 = undefined;

    this.Root               = new CMathContent();
    this.Root.bRoot         = true;
    this.Root.ParentElement = this;

    this.X                  = 0;
    this.Y                  = 0;

    this.FirstPage          = -1;
    this.PageInfo           = new CMathPageInfo();

    this.ParaMathRPI        = new CMathRecalculateInfo();

    this.bSelectionUse      = false;
    this.Paragraph          = null;
    this.bFastRecalculate   = true;

    this.NearPosArray       = [];

    this.Width              = 0;
    this.WidthVisible       = 0;
    this.Height             = 0;
    this.Ascent             = 0;
    this.Descent            = 0;

    this.DispositionOpers   = [];

    this.DefaultTextPr      = new CTextPr();

    this.DefaultTextPr.FontFamily = {Name  : "Cambria Math", Index : -1 };
    this.DefaultTextPr.RFonts.Set_All("Cambria Math", -1);

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
	g_oTableId.Add( this, this.Id );
}

ParaMath.prototype = Object.create(CParagraphContentWithContentBase.prototype);
ParaMath.prototype.constructor = ParaMath;
ParaMath.prototype.Get_Type = function()
{
    return this.Type;
};

ParaMath.prototype.Get_Id = function()
{
    return this.Id;
};

ParaMath.prototype.Copy = function(Selected)
{
    var NewMath = new ParaMath();
    NewMath.Root.bRoot = true;

    if(Selected)
    {
        var result = this.GetSelectContent();
        result.Content.CopyTo(NewMath.Root, Selected);
    }
    else
    {
        this.Root.CopyTo(NewMath.Root, Selected);
    }

    NewMath.Root.Correct_Content(true);

    return NewMath;
};
ParaMath.prototype.CopyContent = function(Selected)
{
    return [this.Copy(Selected)];
};
ParaMath.prototype.SetParagraph = function(Paragraph)
{
	this.Paragraph = Paragraph;
	this.Root.SetParagraph(Paragraph);
	this.Root.Set_ParaMath(this, null);
};
ParaMath.prototype.GetParagraph = function()
{
	return this.Paragraph;
};

ParaMath.prototype.Get_Text = function(Text)
{
	if (true === Text.BreakOnNonText)
		Text.Text = null;
};

ParaMath.prototype.Is_Empty = function(oPr)
{
	if (this.Root.Content.length <= 0)
		return true;

	var isSkipPlcHldr = oPr && undefined !== oPr.SkipPlcHldr ? oPr.SkipPlcHldr : true;

	for (var nIndex = 0, nCount = this.Root.Content.length; nIndex < nCount; ++nIndex)
	{
		var oItem = this.Root.Content[nIndex];
		if (para_Math_Run !== oItem.Type || !oItem.Is_Empty({SkipPlcHldr : isSkipPlcHldr}))
			return false;
	}

	return true;
};

ParaMath.prototype.Is_CheckingNearestPos = function()
{
    return this.Root.Is_CheckingNearestPos();
};

ParaMath.prototype.Is_StartFromNewLine = function()
{
    return false;
};

ParaMath.prototype.Get_TextPr = function(_ContentPos, Depth)
{
    var TextPr = new CTextPr();

    var mTextPr = this.Root.Get_TextPr(_ContentPos, Depth);
    TextPr.Merge( mTextPr );

    return TextPr;
};

ParaMath.prototype.Get_CompiledTextPr = function(Copy)
{
    var oContent = this.GetSelectContent();
    var mTextPr = oContent.Content.Get_CompiledTextPr(Copy);

    return mTextPr;
};

ParaMath.prototype.Add = function(Item)
{
    var LogicDocument  = (this.Paragraph ? this.Paragraph.LogicDocument : undefined);
    var TrackRevisions = (LogicDocument && true === LogicDocument.Is_TrackRevisions() ? true : false);

    var Type = Item.Type;
    var oSelectedContent = this.GetSelectContent();

    var oContent = oSelectedContent.Content;

    var StartPos = oSelectedContent.Start;
    var Run = oContent.Content[StartPos];

    // Мы вставляем только в Run
    if (para_Math_Run !== Run.Type)
        return;

    var NewElement = null;
    if (para_Text === Type)
    {
        // заглушка для текстовых настроек плейсхолдера

        if(oContent.bRoot == false && Run.IsPlaceholder())
        {
            var CtrRunPr = oContent.Get_ParentCtrRunPr(false); // ctrPrp (не копия)

            if (true === TrackRevisions)
                LogicDocument.Set_TrackRevisions(false);

            Run.Apply_TextPr(CtrRunPr, undefined, true);

            if (true === TrackRevisions)
                LogicDocument.Set_TrackRevisions(true);
        }

        if(Item.Value == 38)
        {
            NewElement = new CMathAmp();
            Run.Add(NewElement, true);
        }
        else
        {
            NewElement = new CMathText(false);
            NewElement.add(Item.Value);
            Run.Add(NewElement, true);
        }
    }
    else if (para_Space === Type)
    {
        NewElement = new CMathText(false);
        NewElement.add(32);
        Run.Add(NewElement, true);
    }
    else if (para_Math === Type)
    {
        var ContentPos = new CParagraphContentPos();

        if(this.bSelectionUse == true)
            this.Get_ParaContentPos(true, true, ContentPos);
        else
            this.Get_ParaContentPos(false, false, ContentPos);

        var TextPr = this.Root.GetMathTextPrForMenu(ContentPos, 0);
        var bPlh = oContent.IsPlaceholder();

        // Нам нужно разделить данный Run на 2 части
        var RightRun = Run.Split2(Run.State.ContentPos);

        oContent.Internal_Content_Add(StartPos + 1, RightRun, false);
        // Выставляем позицию в начало этого рана
        oContent.CurPos = StartPos + 1;
        RightRun.MoveCursorToStartPos();

        var lng = oContent.Content.length;
        oContent.Load_FromMenu(Item.Menu, this.Paragraph);
        oContent.Correct_ContentCurPos();

        var lng2 = oContent.Content.length;

        TextPr.RFonts.Set_All("Cambria Math", -1);

        if (true === TrackRevisions)
            LogicDocument.Set_TrackRevisions(false);

        if(bPlh)
            oContent.Apply_TextPr(TextPr, undefined, true);
        else
            oContent.Apply_TextPr(TextPr, undefined, false, StartPos + 1, StartPos + lng2 - lng);

        if (true === TrackRevisions)
            LogicDocument.Set_TrackRevisions(true);
    }

    if ((para_Text === Type || para_Space === Type) && null !== NewElement)
    {
        this.bFastRecalculate = oContent.bOneLine == false; // многострочный контент => можно осуществлять быстрый пересчет

        // Пробуем произвести автозамену
        oContent.Process_AutoCorrect(NewElement);
    }

    // Корректируем данный контент
    oContent.Correct_Content(true);
};

ParaMath.prototype.Get_AlignToLine = function(_CurLine, _CurRange, _Page, _X, _XLimit)
{
    // отступ первой строки не учитывается для неинлайновых формул
    var X = _X;

    var MathSettings = Get_WordDocumentDefaultMathSettings();

    // выставим сначала Position до пересчета выравнивания для формулы
    // для расчета смещений относительно операторов

    var PosInfo = new CMathPosInfo();

    PosInfo.CurLine  = _CurLine;
    PosInfo.CurRange = _CurRange;

    if(true == this.NeedDispOperators(_CurLine))
    {
        this.DispositionOpers.length = 0;
        PosInfo.DispositionOpers = this.DispositionOpers;
    }

    var pos   = new CMathPosition();
    this.Root.setPosition(pos, PosInfo);

    var XStart, XEnd;

    if(this.ParaMathRPI.bInline == false)
    {
        XStart = this.ParaMathRPI.XStart;
        XEnd   = this.ParaMathRPI.XEnd;
    }
    else
    {
        XStart = _X;
        XEnd   = _XLimit;
    }

    var Page = this.Paragraph == null ? 0 : this.Paragraph.Get_AbsolutePage(_Page);
    var LineState = this.PageInfo.Get_LineState(_CurLine, Page);
    var StyleLine = LineState.StyleLine,
        WidthLine = LineState.Width,
        MaxWidth  = LineState.MaxWidth,
        WrapLine  = LineState.SpaceAlign,
        WrapState = LineState.WrapState;

    XStart += MathSettings.Get_LeftMargin(WrapState);
    XEnd   -= MathSettings.Get_RightMargin(WrapState);

    var Jc = this.Get_Align();

    if(StyleLine == MATH_LINE_START || StyleLine == MATH_LINE_ALiGN_AT) // первая строка первой страницы, если строка разбивается на несколько отрезков, то это уже будет inline-формула => ф-ия Get_AlignToLine не будет вызвана
    {                                                                   // либо строка выровнена относительно первой строки
        switch(Jc)
        {
            case align_Left:    X = XStart + WrapLine; break;
            case align_Right:   X = Math.max(XEnd - WidthLine  + WrapLine, XStart); break;
            case align_Center:  X = Math.max(XStart + (XEnd - XStart - WidthLine)/2  + WrapLine, XStart); break;
            case align_Justify:
            {
                X = Math.max(XStart + (XEnd - XStart - MaxWidth)/2 + WrapLine , XStart);
                break;
            }
        }
    }
    else
    {
        if(true == MathSettings.Get_WrapRight()) // флаг свидетельствует о том, что строки кроме первой и строк, выровненных относительно первой, нужно размещать окол правой границы
        {
            X = Math.max(XEnd - WidthLine  + WrapLine, XStart);
        }
        else if(Jc == align_Justify)
        {
            X = XEnd - XStart > MaxWidth ? XStart + (XEnd - XStart - MaxWidth)/2 + WrapLine : XStart;
        }
        else
        {
            X = XEnd - XStart > MaxWidth ? XStart + WrapLine : XStart;
        }
    }


    return X;
};

ParaMath.prototype.Remove = function(Direction, bOnAddText)
{
    var TrackRevisions = null;
    if (this.Paragraph && this.Paragraph.LogicDocument)
        TrackRevisions = this.Paragraph.LogicDocument.Is_TrackRevisions();

    var oSelectedContent = this.GetSelectContent();

    var nStartPos = oSelectedContent.Start;
    var nEndPos = oSelectedContent.End;
    var oContent = oSelectedContent.Content;

    if (nStartPos === nEndPos)
    {
        var oElement = oContent.getElem(nStartPos);
        var ElementReviewType = oElement.Get_ReviewType();

        // Если данный элемент - ран, удаляем внутри рана, если нет, тогда удаляем целиком элемент
        if (para_Math_Run === oElement.Type)
        {
            if (true === oElement.IsPlaceholder() && oElement.Parent.bRoot == true)
            {
                this.Root.Remove_FromContent(0, 1);
                return true;
            }
            else if ((true === oElement.IsPlaceholder()) || (false === oElement.Remove(Direction) && true !== this.bSelectionUse))
            {
                if ((Direction > 0 && oContent.Content.length - 1 === nStartPos) || (Direction < 0 && 0 === nStartPos))
                {
                    // Проверяем находимся ли мы на верхнем уровне
                    if (oContent.bRoot)
                        return false;

                    // Значит мы в каком-то элементе, тогда надо выделить данный элемент
                    oContent.ParentElement.Select_WholeElement();

                    return true;
                }

                if (Direction > 0)
                {
                    var oNextElement = oContent.getElem(nStartPos + 1);
                    if (para_Math_Run === oNextElement.Type)
                    {
                        // Здесь мы не проверяем результат Remove, потому что ран не должен быть пустым после
                        // Correct_Content
                        oNextElement.MoveCursorToStartPos();
                        oNextElement.Remove(1);

                        if (oNextElement.Is_Empty())
                        {
                            oContent.Correct_Content();
                            oContent.Correct_ContentPos(1);
                        }

                        this.RemoveSelection();
                    }
                    else
                    {
                        oContent.Select_ElementByPos(nStartPos + 1, true);
                    }
                }
                else //if (Direction < 0)
                {
                    var oPrevElement = oContent.getElem(nStartPos - 1);
                    if (para_Math_Run === oPrevElement.Type)
                    {
                        // Здесь мы не проверяем результат Remove, потому что ран не должен быть пустым после
                        // Correct_Content
                        oPrevElement.MoveCursorToEndPos();
                        oPrevElement.Remove(-1);

                        if (oPrevElement.Is_Empty())
                        {
                            oContent.Correct_Content();
                            oContent.Correct_ContentPos(-1);
                        }

                        this.RemoveSelection();
                    }
                    else
                    {
                        oContent.Select_ElementByPos(nStartPos - 1, true);
                    }
                }
            }
            else
            {
                if (oElement.Is_Empty())
                {
                    oContent.CurPos = nStartPos;
                    oContent.Correct_Content();
                    oContent.Correct_ContentPos(-1); // -1, потому что нам надо встать перед элементом, а не после
                }

                this.RemoveSelection();
            }

            return true;
        }
        else
        {
            this.RemoveSelection();
            if (true === TrackRevisions)
            {
                if (reviewtype_Common === ElementReviewType)
                {
                    if (para_Math_Run === oElement.Type !== oElement.Type)
                        oElement.RejectRevisionChanges(c_oAscRevisionsChangeType.TextAdd, true);

                    oElement.Set_ReviewType(reviewtype_Remove);
                }
                else if (reviewtype_Add === ElementReviewType)
                {
                    oContent.Remove_FromContent(nStartPos, 1);
                    if (para_Math_Run === oContent.Content[nStartPos].Type)
                        oContent.Content[nStartPos].MoveCursorToStartPos();
                }
            }
            else
            {
                oContent.Remove_FromContent(nStartPos, 1);
                if (para_Math_Run === oContent.Content[nStartPos].Type)
                    oContent.Content[nStartPos].MoveCursorToStartPos();
            }
            oContent.CurPos = nStartPos;
            oContent.Correct_Content();
            oContent.Correct_ContentPos(-1); // -1, потому что нам надо встать перед элементом, а не после
        }
    }
    else
    {
        if (nStartPos > nEndPos)
        {
            var nTemp = nEndPos;
            nEndPos = nStartPos;
            nStartPos = nTemp;
        }

        // Проверяем начальный и конечный элементы
        var oStartElement = oContent.getElem(nStartPos);
        var oEndElement = oContent.getElem(nEndPos);

        if (true === TrackRevisions)
        {
            for (var CurPos = nEndPos; CurPos >= nStartPos; --CurPos)
            {
                var Element = oContent.getElem(CurPos);
                var ElementReviewType = Element.Get_ReviewType();

                if (para_Math_Run === Element.Type && (CurPos === nEndPos || CurPos === nStartPos))
                {
                    // Удаление разруливается внутри рана
                    Element.Remove(Direction);
                }
                else
                {
                    if (reviewtype_Common === ElementReviewType)
                    {
                        if (para_Math_Run === Element.Type !== Element.Type)
                            Element.RejectRevisionChanges(c_oAscRevisionsChangeType.TextAdd, true);

                        Element.Set_ReviewType(reviewtype_Remove);
                    }
                    else if (reviewtype_Add === ElementReviewType)
                    {
                        oContent.Remove_FromContent(CurPos, 1);
                        nEndPos--;
                    }
                }
            }

            this.RemoveSelection();
            if (Direction < 0)
            {
                oContent.CurPos = nStartPos;
            }
            else
            {
                oContent.CurPos = nEndPos;
                if (para_Math_Run === oContent.Content[nEndPos].Type)
                    oContent.Content[nEndPos].MoveCursorToStartPos();
            }
        }
        else
        {
            // Если последний элемент - ран, удаляем внутри, если нет, тогда удаляем целиком элемент
            if (para_Math_Run === oEndElement.Type)
                oEndElement.Remove(Direction);
            else
                oContent.Remove_FromContent(nEndPos, 1);

            // Удаляем все промежуточные элементы
            oContent.Remove_FromContent(nStartPos + 1, nEndPos - nStartPos - 1);

            // Если первый элемент - ран, удаляем внутри рана, если нет, тогда удаляем целиком элемент
            if (para_Math_Run === oStartElement.Type)
                oStartElement.Remove(Direction);
            else
                oContent.Remove_FromContent(nStartPos, 1);

            this.RemoveSelection();
            oContent.CurPos = nStartPos;
        }
        oContent.Correct_Content();
        oContent.Correct_ContentPos(Direction);
    }
};

ParaMath.prototype.GetSelectContent = function()
{
    return this.Root.GetSelectContent();
};

ParaMath.prototype.Get_CurrentParaPos = function()
{
    return this.Root.Get_CurrentParaPos();
};

ParaMath.prototype.Apply_TextPr = function(TextPr, IncFontSize, ApplyToAll)
{
    if(ApplyToAll == true) // для ситуации, когда ApplyToAll = true, в Root формулы при этом позиции селекта не проставлены
    {
        this.Root.Apply_TextPr(TextPr, IncFontSize, true);
    }
    else
    {
        var content = this.GetSelectContent().Content;

        var NewTextPr = new CTextPr();
        var bSetInRoot = false;


        if(IncFontSize == undefined)
        {
            if(TextPr.Underline !== undefined)
            {

                NewTextPr.Underline   = TextPr.Underline;
                bSetInRoot            = true;
            }

            if(TextPr.FontSize !== undefined && content.IsNormalTextInRuns() == false)
            {
                NewTextPr.FontSize    = TextPr.FontSize;
                bSetInRoot            = true;

            }

            content.Apply_TextPr(TextPr, IncFontSize, ApplyToAll);

            if(bSetInRoot)
                this.Root.Apply_TextPr(NewTextPr, IncFontSize, true);
        }
        else
        {

            if(content.IsNormalTextInRuns() == false)
                this.Root.Apply_TextPr(TextPr, IncFontSize, true);
            else
                content.Apply_TextPr(TextPr, IncFontSize, ApplyToAll);
        }
    }
};

ParaMath.prototype.Clear_TextPr = function()
{

};

ParaMath.prototype.Check_NearestPos = function(ParaNearPos, Depth)
{
    this.Root.Check_NearestPos(ParaNearPos, Depth);
};

ParaMath.prototype.Get_DrawingObjectRun = function(Id)
{
    return null;
};

ParaMath.prototype.Get_DrawingObjectContentPos = function(Id, ContentPos, Depth)
{
    return false;
};

ParaMath.prototype.Get_Layout = function(DrawingLayout, UseContentPos, ContentPos, Depth)
{
    if (true === UseContentPos)
        DrawingLayout.Layout = true;
    else
        DrawingLayout.X += this.Width;
};

ParaMath.prototype.CollectDocumentStatistics = function(ParaStats)
{
    // TODO: ParaMath.CollectDocumentStatistics
};

ParaMath.prototype.Create_FontMap = function(Map)
{
    // Styles.js
    // Document_CreateFontMap

    this.Root.Create_FontMap(Map);
};

ParaMath.prototype.Get_AllFontNames = function(AllFonts)
{
    // выставить для всех шрифтов, к-ые используются в AllFonts true
    AllFonts["Cambria Math"] = true;

    this.Root.Get_AllFontNames(AllFonts);
};

ParaMath.prototype.GetSelectedElementsInfo = function(Info, ContentPos, Depth)
{
    Info.Set_Math(this);
};

ParaMath.prototype.GetSelectedText = function(bAll, bClearText, oPr)
{
	if (true === bAll || true === this.IsSelectionUse())
	{
		if (true === bClearText)
			return null;

		var res = "";

		//TODO проверить!!! +  пересмотреть работу функции GetTextContent
		//включаю эту ветку только для copy/paste
		if(window['AscCommon'].g_clipboardBase && window['AscCommon'].g_clipboardBase.CopyPasteFocus)
		{
			var selectedContent = this.GetSelectContent();
			if(selectedContent && selectedContent.Content && selectedContent.Content.GetTextContent)
			{
				var textContent = selectedContent.Content.GetTextContent(!bAll);
				if(textContent && textContent.str)
				{
					res = textContent.str;
				}
			}
		}

		return res;
	}

	return "";
};

ParaMath.prototype.Get_SelectionDirection = function()
{
    return this.Root.Get_SelectionDirection();
};

ParaMath.prototype.Clear_TextFormatting = function( DefHyper )
{
};

ParaMath.prototype.Can_AddDropCap = function()
{
    return false;
};

ParaMath.prototype.Get_TextForDropCap = function(DropCapText, UseContentPos, ContentPos, Depth)
{
    if ( true === DropCapText.Check )
        DropCapText.Mixed = true;
};

ParaMath.prototype.Get_StartTabsCount = function(TabsCounter)
{
    return false;
};

ParaMath.prototype.Remove_StartTabs = function(TabsCounter)
{
    return false;
};

ParaMath.prototype.Add_ToContent = function(Pos, Item, UpdatePosition)
{

};

ParaMath.prototype.Get_MenuProps = function()
{
    return this.Root.Get_MenuProps();
};
ParaMath.prototype.Set_MenuProps = function(Props)
{
    if(Props != undefined)
        this.Root.Set_MenuProps(Props);
};
//-----------------------------------------------------------------------------------
// Функции пересчета
//-----------------------------------------------------------------------------------

ParaMath.prototype.Recalculate_Range = function(PRS, ParaPr, Depth)
{
    // Paragraph_Recalculate.js
    // private_RecalculateFastRange

    // Document.js
    // Recalculate
    // SimpleChanges

    // Paragraph.js
    // CRunRecalculateObject.Compare

    if(PRS.bFastRecalculate == true && this.bFastRecalculate == false)
        return;

    if( this.Paragraph !== PRS.Paragraph )
    {
        this.Paragraph = PRS.Paragraph;
        this.private_UpdateSpellChecking();
    }

    var Para         = PRS.Paragraph;
    var ParaLine     = PRS.Line;
    var ParaRange    = PRS.Range;
    var Page         = this.Paragraph == null ? 0 : this.Paragraph.Get_AbsolutePage(PRS.Page);
    var RelativePage = PRS.Page;

    var bStartRange    = this.Root.IsStartRange(ParaLine, ParaRange);

    // первый пересчет
    var PrevLineObject = PRS.RestartPageRecalcInfo.Object;
    var bCurrentObj = PrevLineObject == null || PrevLineObject == this;
    var PrevObject = bCurrentObj ? null : PrevLineObject;

    var bStartRecalculate = PrevLineObject == null && true == bStartRange && PRS.bFastRecalculate == false;
    var bContinueRecalc = this.ParaMathRPI.bInline == false && PRS.bContinueRecalc === true;

    var LDRecalcInfo  = this.Paragraph.Parent.RecalcInfo;

    if(bStartRecalculate == true && bContinueRecalc == false) // первый пересчет
    {
        // информация о пересчете
        var RPI = new CRPI();
        RPI.MergeMathInfo(this.ParaMathRPI);

        this.Root.PreRecalc(null, this, new CMathArgSize(), RPI);

        this.PageInfo.Reset();
        this.PageInfo.Set_StartPos(Page, ParaLine);
        this.PageInfo.Update_RelativePage(RelativePage);
        this.ParaMathRPI.Reset(PRS, ParaPr);
    }
    else
    {
        // true == this.PageInfo.Is_ResetNextPage(Page)
        /// при переходе на следующую страницу выставляем стартовые параметры для отрезка, в к-ом пересчитываем
        // может произойти в одной из 2-х ситуаций:
        // 1. первый раз пересчитываем формулу => для PageInfo ширины и др . параметры еще не рассчитали
        // 2. произошли изменения на пред страницах, их пересчитали, перешли к следующей => для PageInfo нужно выставить дефолтные настройки для параметров и обнулить массив ширин
        // параметры для ParaMathRPI выставляем дефолтные в любом из этих двух случаев

        // false == this.PageInfo.Is_ResetNextPage(Page) && true == this.PageInfo.Is_FirstLineOnPage(Line, Page)
        // т.е. рассчитываем текущую страницу с первой строки
        // может произойти, если вновь стали (PrevLineObject !== null) пересчитывать формулу на данной странице (из-за того что изменилась макс ширина и нужно заново пересчитать формулу на странице и т.п.)
        // или же произошли какие-то изменения на странице и вызвался пересчет для этой страницы (PrevLineObject == null) и отсутствует быстрый пересчет (PRS.bFastRecalculate == false)

        var bResetNextPage = true == this.PageInfo.Is_ResetNextPage(Page);
        var bResetPageInfo = PrevLineObject == null && bContinueRecalc == false && PRS.bFastRecalculate == false && true == this.PageInfo.Is_FirstLineOnPage(ParaLine, Page);

        if(bResetNextPage == true || bResetPageInfo == true)
        {
            this.ParaMathRPI.Reset(PRS, ParaPr);
            this.PageInfo.Reset_Page(Page);
        }

        if(true == this.PageInfo.Is_ResetRelativePage(PRS.Page))
        {
            this.ParaMathRPI.Reset(PRS, ParaPr);
            this.PageInfo.Update_RelativePage(RelativePage);
        }

    }

    PRS.MathNotInline = this.ParaMathRPI.bInline  == false; // если неинлайновая формула, то рассчитываем Ranges по максимальному измерению
    PRS.bPriorityOper = this.ParaMathRPI.bInline == false;

    if(this.ParaMathRPI.bInline == false)
    {
        PRS.RestartPageRecalcInfo.Object = this; // т.к. this.ParaMathRPI.bInline == false
                                                 // и чтобы на проверке bResetPageInfo не перебить параметры
    }


    // такая сиуация возможна, если разместили формулу под картинкой и нужно заново пересчитать формулу
    // для этого меняем PRS.Y и ждем пока не произойдет private_RecalculateLineCheckRangeY
    // т.к. в противном случае мы можем изменить Ranges на те, что находятся PRS.Y, который был до того как его изменили в данном блоке (возникает из-за того, что ф-ия private_RecalculateLineCheckRanges нах-ся выше ф-ии private_RecalculateLineCheckRangeY)
    if(this.ParaMathRPI.ShiftY - PRS.Y > 0 || PRS.bMathRangeY == true)
    {
        // выполняем перенос здесь для того, чтобы перенести под нужную картинку
        // к примеру, у нас есть нескоолько картинок с выравниванием по контору и картинка с выравниванием top_bottom(она расположена ниже всех остальных картинок) =>
        // нужно сделать перенос под картинку top_bottom и пересчитывать заново формулу
        //
        //this.Set_EmptyRange(PRS);
        PRS.bMathRangeY = true;
        PRS.ForceNewPage = true;
        this.private_UpdateRangeY(PRS, this.ParaMathRPI.ShiftY);
    }
    else
    {
        // такая ситуация возможна  когда пришел пересчет заново и кол-во отрезков выравнивания 0 (либо меньше, чем нужно)
        // при этом если это первый Range данной формулы, то пришел еще Reset, то есть пересчитать придется, при этом не меняем max ширину, т.к. если мы уже пересчитали с учетом Range, она не должна поменяться
        this.Root.SetParagraph(Para);
        this.Root.Set_ParaMath(this, null);

        this.PageInfo.Update_CurrentPage(Page, ParaLine);

        var bRecalcNormal = true;

        if(bCurrentObj == true && this.ParaMathRPI.bInline == false &&  PRS.bFastRecalculate == false) // меняем отрезки обтекания только для случая, когда пересчитываем текущий объект (а не вновь возвращаемся к последнему пересчету)
        {
            var UpdWrap = this.private_UpdateWrapSettings(PRS, ParaPr);

            if(UpdWrap == MATH_UPDWRAP_NEWRANGE)
            {
                // Уберем из массива информацию о рассчитанных ширинах, чтобы не учлась рассчитанная ранее максимальная ширина (в связи с тем, что отрезок, в к-ом нужно расположить, изменился по ширине)
                // выставляем EmptyLine = false, т.к. нужно сделать заново пересчет в новом отрезке (а не перенести формулу под картинку)
                // т.к. инициируем пересчет заново, то в проверку на ParaNewLine : if (true === NotInlineMath && true !== PRS.EmptyLine) не зайдем, т.к. NewRange = true
                this.PageInfo.Reset_Page(Page);
                this.ParaMathRPI.bInternalRanges = true;
                // не выставляем EmtyLine = false, т.к. так и так выйдем из пересчета данной строки при расчете Ranges, до пересчета картинок не дойдем, поэтому PRS.EmptyLine = false  выставлять не нужно
                //PRS.EmptyLine = false;
                this.private_SetRestartRecalcInfo(PRS);
            }
            else if(UpdWrap == MATH_UPDWRAP_UNDERFLOW)
            {
                // пересчитаем PRS.Y на след пересчете при this.ParaMathRPI.ShiftY - PRS.Y > 0
                // в блоке if(this.ParaMathRPI.ShiftY - PRS.Y > 0)
            }

            bRecalcNormal = UpdWrap == MATH_UPDWRAP_NOCHANGES; // пересчитываем всю строку заново, т.к. может получиться так, что добавилась еще одна картинка (+ к уже существующим) и нужно заново выбрать Range, в котором необходимо разместить формулу
        }

        if(bRecalcNormal == true) // пересчет в штатном режиме
        {
            var MathSettings = Get_WordDocumentDefaultMathSettings();

            var DispDef = MathSettings.Get_DispDef(),
                bInline = this.Is_Inline(); // учитываем, если формула внутристроковая или же разбивается плавающим объектом (в этом случае тоже нужно рассчитывать как инлайновую)

            //здесь обновляем WrapState, исходя из этого параметра будем считать WrapIndent
            this.PageInfo.Update_CurrentWrap(DispDef, bInline);


            // формулы не инлайновая, есть Ranges пересчитываем формулу в макс Range => private_RecalculateRangeInsideInterval
            if(this.ParaMathRPI.IntervalState !== MATH_INTERVAL_EMPTY && this.ParaMathRPI.bInternalRanges == true/*this.ParaMathRPI.bStartRanges == true*/) // картинки в другом параграфе и формула пересчитывается с учетом Ranges
            {
                // X и XEnd не перебиваем выше, т.к. они понадобятся для учета попадания в Range в ф-ии  private_RecalculateRangeInsideInterval
                this.private_RecalculateRangeInsideInterval(PRS, ParaPr, Depth);
            }
            else
            {
                this.private_RecalculateRangeWrap(PRS, ParaPr, Depth);
            }

            this.ParaMathRPI.ClearRecalculate();
        }
    }

    // обновляем LDRecalcInfo здесь, т.к. формула - многострочный мат объект, нельзя каждый раз изменять LDRecalcInfo => иначе для четных/нечетных сток будет чередование ParaMath = this/null
    if (PRS.RecalcResult & recalcresult_PrevLine && (true === LDRecalcInfo.Can_RecalcObject() || true === LDRecalcInfo.Check_ParaMath(this)))
    {
        LDRecalcInfo.Set_ParaMath(this);
    }
    else if(true === LDRecalcInfo.Check_ParaMath(this))
    {
        LDRecalcInfo.Reset();
    }
    else
    {

    }

    if(bCurrentObj == true)
    {
        // этот параметр необходим для пересчета нескольких неинлайновых (и инлайновых формул) внутри одного параграфа,
        // чтобы не перетирать параметры внутри пересчитанных формул (и соответственно избежать зацикливания)
        PRS.bContinueRecalc = true;

        if(PRS.NewRange == false)
        {
            // на случай когда у нас несколько неинлайновых формул в одном параграфе
            PRS.RestartPageRecalcInfo.Object = null;
        }
    }
    else
    {
        PRS.RestartPageRecalcInfo.Object = PrevObject; // возвращаем формулу, которая инициировала пересчет (если это была текущая формула, то null)
    }

};
ParaMath.prototype.private_UpdateWrapSettings = function(PRS)
{
    // запомним PRS.Ranges.Y для смещения, чтобы выставить потом смещение, т.к. возможен случай, что картинка, под которой нужно расположить формулу, будет не первой, которая встретиться, пр первом пересчете, или же будет отсутствовать в текущем пересчете
    // (т.к. надо расположить под картинков), отсюда проще запомнить смещение, чем гонять пересчет до конкретной строки, чтобы private_RecalculateLineCheckRangeY вернула нужное значение

    /// значение this.ParaMathRPI.bInternalRanges может изменить значение после того как будет вызвана данная функция

    var UpdateWrap = MATH_UPDWRAP_NOCHANGES;

    var LngR       = PRS.Ranges.length,
        Ranges     = PRS.Ranges;


    if(LngR > 0)
    {
        this.ParaMathRPI.IntervalState = MATH_INTERVAL_ON_SIDE;

        var  RY_NotWrap   = null;

        for(var Pos = 0; Pos < LngR; Pos++)
        {
            var WrapType = Ranges[Pos].typeLeft;

            if(WrapType !== WRAPPING_TYPE_SQUARE && WrapType !== WRAPPING_TYPE_THROUGH && WrapType !== WRAPPING_TYPE_TIGHT)
            {
                // выберем картинку с max RangeY c учетом данного условия, под которой попробуем расположить формулу
                if(RY_NotWrap == null || RY_NotWrap < Ranges[Pos].Y1)
                {
                    RY_NotWrap = Ranges[Pos].Y1;
                }

                this.ParaMathRPI.IntervalState = MATH_INTERVAL_EMPTY;
            }
        }

        if(this.ParaMathRPI.IntervalState == MATH_INTERVAL_ON_SIDE) // WrapType == WRAPPING_TYPE_SQUARE || WrapType == WRAPPING_TYPE_THROUGH || WrapType == WRAPPING_TYPE_TIGHT
        {
            // вычтем здесь Ind.Left для корректного сравнения (т.к.стартовый отрезок = граница Range + Ind.Left ), а также если XStart окажется левой границей (прибаится лишний Ind.Left)
            var XRange = this.ParaMathRPI.XRange - this.ParaMathRPI.IndLeft,
                XLimit = this.ParaMathRPI.XLimit;

            // рассчитываем XStart, XEnd
            var XStart = XRange,
                XEnd   = Ranges[0].X0;

            for(var Pos = 0; Pos < LngR - 1; Pos++)
            {
                if(XEnd - XStart < Ranges[Pos+1].X0 - Ranges[Pos].X1)
                {
                    XStart = Ranges[Pos].X1;
                    XEnd   = Ranges[Pos+1].X0;
                }
            }

            if(XEnd - XStart < XLimit - Ranges[LngR - 1].X1)
            {
                XStart = Ranges[LngR - 1].X1;
                XEnd   = XLimit;
            }

            // учтем Ind.Left
            // если впоследствии Ind.Left в word не будет учитываться, то нужно пересмотреть схему => в каких случаях и с какими параметрами рассчитыывать в Range

            XStart += this.ParaMathRPI.IndLeft;


            // в конце сравним с текущим отрезком, т.к. может произойти например след ситуация :
            // 2 плавающих объекта находятся в различных строках +> PRS.Ranges.length <=1
            // при этом формула должна расположится в макс по ширине из отрезков, образованными обоими плавающими мат объектами

            // учтем предыдущие отрезки:
            if(this.ParaMathRPI.XStart > XStart)
            {
                XStart = this.ParaMathRPI.XStart;
            }

            if(this.ParaMathRPI.XEnd < XEnd)
            {
                XEnd = this.ParaMathRPI.XEnd;
            }

            // рассчитываем RangeY

            var RangeY = Ranges[0].Y1;

            for(var Pos = 1; Pos < Ranges.length; Pos++)
            {
                if(Ranges[Pos].Y1 < RangeY)
                    RangeY = Ranges[Pos].Y1;
            }

            if(this.ParaMathRPI.RangeY == null || RangeY < this.ParaMathRPI.RangeY)
            {
                this.ParaMathRPI.RangeY = RangeY;
            }


            var DiffXStart = Math.abs(this.ParaMathRPI.XStart - XStart),
                DiffXEnd   = Math.abs(this.ParaMathRPI.XEnd - XEnd);

            if(DiffXStart > 0.001 || DiffXEnd > 0.001)
            {
                this.ParaMathRPI.XStart     = XStart;
                this.ParaMathRPI.XEnd       = XEnd;

                UpdateWrap = MATH_UPDWRAP_NEWRANGE;
            }
        }
        else
        {
            // если появился плавающий объект, относительно которого нельзя разместить формулу (в одном из Range, образованным плавающими объектами), то, соответсвенно, формула должна располагаться под плавающим объектом

            this.private_SetShiftY(PRS, RY_NotWrap);
            UpdateWrap = MATH_UPDWRAP_UNDERFLOW;
        }

    }

    return UpdateWrap;
};
ParaMath.prototype.private_RecalculateRangeInsideInterval = function(PRS, ParaPr, Depth)
{
    // var bInsideRange = PRS.X - 0.001 < this.ParaMathRPI.XStart && this.ParaMathRPI.XEnd < PRS.XEnd + 0.001;
    // наложим менее строгие условия попадания в отрезок
    var bNotInsideRange = this.ParaMathRPI.XStart > PRS.XEnd || this.ParaMathRPI.XEnd < PRS.X;
    var bNextRangeSide   = this.ParaMathRPI.IntervalState == MATH_INTERVAL_ON_SIDE && bNotInsideRange == true; // пересчитываем только в том отрезке, в котором находится формула

    // Номер  Range не влияет на UpdateWrapSettings, т.к. картинки могут располагаться одна под другой, и в одной ситуации это будет 0-ой Range,  в другой 1-ый

    if(bNextRangeSide) // при пересчете формулы между картинками/сбоку от картинки рассчитываем формулу в самом большом Range, остальные делаем пустыми
    {
        // переход к следующему Range
        this.Set_EmptyRange(PRS);
    }
    else
    {
        PRS.X = this.ParaMathRPI.XStart;
        PRS.XEnd = this.ParaMathRPI.XEnd;

        this.private_UpdateXLimits(PRS);

        this.private_RecalculateRoot(PRS, ParaPr, Depth);


        if(PRS.bMathWordLarge == true)
        {
            this.private_SetShiftY(PRS, this.ParaMathRPI.RangeY);
        }
        else if(PRS.NewRange == false && PRS.EmptyLine == true) // формула пересчиталась корректно, располагаем в данной строке => не разбивается на слова, выставим EmptyLine = false, чтобы не перенесли под картинку
        {
            PRS.EmptyLine = false;
        }

        PRS.RestartPageRecalcInfo.Object = this;

        if(PRS.NewRange == true && !(PRS.RecalcResult & recalcresult_PrevLine))
            PRS.ForceNewLine = true;
    }
};
ParaMath.prototype.private_RecalculateRangeWrap = function(PRS, ParaPr, Depth)
{
    // попадем сюда только, когда  либо нет плавающих объектов, привязанных к другому параграфу, нежели формула
    // либо когда не получилось расположить формулу в Range и формула пересчитывается обычным образом

    var PrevLineObject = PRS.RestartPageRecalcInfo.Object;

    if(PrevLineObject == null ||  PrevLineObject == this)
    {
        PRS.RecalcResult = recalcresult_NextLine;
        //PRS.Reset_RestartPageRecalcInfo();
        // не вызываем функцию Reset_RestartPageRecalcInfo, т.к. в данной функции учитывается флаг, что начали пересчитывать заново
        PRS.RestartPageRecalcInfo.Line   = 0;
        // выставляем только для инлайновых формул => может случится так, что в одном параграфе окажутся несколько формул и для того, чтобы при первом пересчете пересчитались настройки нужно возвращать null
        // при последующих пересчетах PRS.RestartPageRecalcInfo.Object будет выставлен null на Reset_RestartPageRecalcInfo в ф-ии private_RecalculatePage

        PRS.RestartPageRecalcInfo.Object = this.ParaMathRPI.bInline ? null : this;
    }

    if(this.ParaMathRPI.bInline == false)  // здесь перебивается для неинлайновых формул и отступ первой строки и тот случай, когда формула не пересекает область расположения картинки (FlowBounds), но тем неменее пришли
    {
        PRS.X = this.ParaMathRPI.XStart;
        PRS.XEnd = this.ParaMathRPI.XEnd;
    }

    this.private_UpdateXLimits(PRS);

    var bStartRange    = this.Root.IsStartRange(PRS.Line, PRS.Range);
    var bNotBrPosInLWord = this.ParaMathRPI.bInline == true && bStartRange == true && PRS.Ranges.length > 0 && PRS.Word == true;
    PRS.bBreakPosInLWord = bNotBrPosInLWord == false;  //не обновляем для инлайновой формулы, когда WordLarge (слово вышло за границы Range), перед формулой есть еще текст, чтобы не перебить LineBreakPos и выставить разбиение по тем меткам, которые были до пересчета формулы

    var bEmptyLine = PRS.EmptyLine;

    this.private_RecalculateRoot(PRS, ParaPr, Depth);

    var WrapState = this.PageInfo.Get_CurrentWrapState();

    this.PageInfo.Set_StateWordLarge(PRS.Line, PRS.bMathWordLarge);

    if(PRS.bMathWordLarge == true)
    {
        if(WrapState !== ALIGN_EMPTY)
        {
            this.private_SetRestartRecalcInfo(PRS);
            this.PageInfo.Set_NextWrapState();
        }
        else if(this.ParaMathRPI.bInline == true && PRS.Ranges.length > 0)
        {
            if(PRS.bBreakPosInLWord == true) // когда для инлайновой формулы WordLarge (слово вышло за границы Range), перед формулой есть еще текст, чтобы не перебить LineBreakPos и выставить разбиение по тем меткам, которые были до пересчета формулы
            {
                PRS.EmptyLine = bEmptyLine; // вернем пред знач-е
                this.Root.Math_Set_EmptyRange(PRS.Line, PRS.Range);
                PRS.bMathWordLarge = false;
                PRS.NewRange = true;
                PRS.MoveToLBP = false;
            }
            else
            {
                //не обновляем для инлайновой формулы, когда WordLarge, перед формулой есть еще текст, чтобы не перебить LineBreakPos и выставить по тем меткам, которые были до формулы разбиение
                PRS.MoveToLBP = true;
            }
        }
    }
};
ParaMath.prototype.private_RecalculateRoot = function(PRS, ParaPr, Depth)
{
    var Para      = PRS.Paragraph;
    var ParaLine  = PRS.Line;
    var ParaRange = PRS.Range;

    // заглушка для пересчета Gaps элементов в текущей строке
    // если быстрый пересчет проверим нужно ли пересчитывать gaps у элементов текущей строки
    if(PRS.bFastRecalculate == true)
    {
        this.Root.Math_UpdateGaps(ParaLine, ParaRange);
    }

    this.Root.Recalculate_Range(PRS, ParaPr, Depth);

    if(PRS.NewRange == false)
    {
        // обнуляем GapRight для операторов
        PRS.OperGapRight       = 0;

        var WidthLine = PRS.X - PRS.XRange + PRS.SpaceLen + PRS.WordLen;

        var bFirstItem =  PRS.FirstItemOnLine == true && true === Para.Internal_Check_Ranges(ParaLine, ParaRange);
        if(bFirstItem && PRS.X + PRS.SpaceLen + PRS.WordLen > PRS.XEnd)
        {
            PRS.bMathWordLarge = true;
        }

        this.UpdateWidthLine(PRS, WidthLine);
    }
};
ParaMath.prototype.private_SetRestartRecalcInfo = function(PRS)
{
    var Page = this.Paragraph == null ? 0 : this.Paragraph.Get_AbsolutePage(PRS.Page);
    var Line = this.PageInfo.Get_FirstLineOnPage(Page);
    PRS.Set_RestartPageRecalcInfo(Line, this);
    PRS.RecalcResult = recalcresult_PrevLine;
    PRS.NewRange = true;
};
ParaMath.prototype.Set_EmptyRange = function(PRS)
{
    // не выставляем PRS.EmptyLine = false, чтобы корректно не произошел перенос на след строку для ParaNewLine (PRS.EmptyLine == false && bInline == false)

    this.Root.Math_Set_EmptyRange(PRS.Line, PRS.Range);

    PRS.RecalcResult = recalcresult_NextLine;
    PRS.RestartPageRecalcInfo.Object = this;

    PRS.NewRange = true;
};
ParaMath.prototype.private_UpdateRangeY = function(PRS, RY)
{
    if (Math.abs(RY - PRS.Y) < 0.001)
        PRS.Y = RY + 1; // смещаемся по 1мм
    else
        PRS.Y = RY + 0.001; // Добавляем 0.001, чтобы избавиться от погрешности


    PRS.NewRange = true;
};
ParaMath.prototype.private_SetShiftY = function(PRS, RY)
{
    this.PageInfo.Set_NeedUpdateWrap();
    this.ParaMathRPI.UpdateShiftY(RY);
    this.ParaMathRPI.Reset_WrapSettings();
    this.private_SetRestartRecalcInfo(PRS);
};
ParaMath.prototype.private_UpdateXLimits = function(PRS)
{
    var MathSettings = Get_WordDocumentDefaultMathSettings();
    var WrapState = this.PageInfo.Get_CurrentWrapState();

    var Page = this.Paragraph == null ? 0 : this.Paragraph.Get_AbsolutePage(PRS.Page);

    PRS.X    += MathSettings.Get_LeftMargin(WrapState);
    PRS.XEnd -= MathSettings.Get_RightMargin(WrapState);


    PRS.WrapIndent = MathSettings.Get_WrapIndent(WrapState);

    PRS.bFirstLine = this.Root.IsStartLine(PRS.Line);

    var AlignAt;
    var Jc = this.Get_Align();

    var alignBrk = this.Root.Get_AlignBrk(PRS.Line, this.Is_BrkBinBefore());

    if(alignBrk !== null)
    {
        if(alignBrk == 0 || Jc == align_Right || Jc == align_Center)
        {
            AlignAt = 0;
        }
        else
        {
            var PosAln  = alignBrk < this.DispositionOpers.length ?  alignBrk - 1 : this.DispositionOpers.length - 1;
            AlignAt = this.DispositionOpers[PosAln];
        }
    }

    this.PageInfo.Add_Line(PRS.Line, Page, AlignAt);

    PRS.X += this.PageInfo.Get_SpaceAlign(PRS.Line, Page);

    PRS.XRange = PRS.X;
};
ParaMath.prototype.Save_MathInfo = function(Copy)
{
    var RecalculateObject = new CMathRecalculateObject();

    var StructRecalc =
    {
        bFastRecalculate:   this.bFastRecalculate,
        PageInfo:           this.PageInfo,
        bInline:            this.ParaMathRPI.bInline,
        Align:              this.Get_Align(),
        bEmptyFirstRange:   this.Root.Is_EmptyRange(this.Root.StartLine, this.Root.StartRange)
    };

    RecalculateObject.Fill(StructRecalc);

    return RecalculateObject;
};
ParaMath.prototype.Load_MathInfo = function(RecalculateObject)
{
    RecalculateObject.Load_MathInfo(this.PageInfo);
};
ParaMath.prototype.CompareMathInfo = function(RecalculateObject)
{
    return RecalculateObject.Compare(this.PageInfo);
};
ParaMath.prototype.Recalculate_Reset = function(CurRange, CurLine, RecalcResult)
{
    this.Root.Recalculate_Reset(CurRange, CurLine); // обновим StartLine и StartRange только для Root (в CParagraphContentWithContentBase), для внутренних элементов обновится на Recalculate_Range
};
ParaMath.prototype.Recalculate_Set_RangeEndPos = function(PRS, PRP, Depth)
{
    this.Root.Recalculate_Set_RangeEndPos(PRS, PRP, Depth);
};
ParaMath.prototype.Recalculate_LineMetrics = function(PRS, ParaPr, _CurLine, _CurRange)
{
    var ContentMetrics = new CMathBoundsMeasures();

    // обновляем LineAscent и LineDescent для пересчета инлайновой формулы с картинкой
    // если в формуле находится картинка, то может так получится, что в отрезках обтекания не будет ни одного элемента => PRS.Ascent и PRS.Descent равны 0
    // далее при вычилении отрезков (PRS.Ranges) для следующей строки  учитываются PRS.Ascent и PRS.Descent предыдщей строки, а они будут равны 0 , соответственно получим те же самые отрезки обтекания, что и в предыдущей строке
    // произойдет зацикливание

    this.Root.Recalculate_LineMetrics(PRS, ParaPr, _CurLine, _CurRange, ContentMetrics);

    var RootAscent  = this.Root.GetAscent(_CurLine, _CurRange),
        RootDescent = this.Root.GetDescent(_CurLine, _CurRange);


    if(PRS.LineAscent < RootAscent)
        PRS.LineAscent = RootAscent;

    if(PRS.LineDescent < RootDescent)
        PRS.LineDescent = RootDescent;

    this.Root.Math_UpdateLineMetrics(PRS, ParaPr);
};
ParaMath.prototype.Recalculate_Range_Width = function(PRSC, _CurLine, _CurRange)
{
    var SpaceLen   = PRSC.SpaceLen;

    var bBrkBefore = this.Is_BrkBinBefore();

    var bGapLeft  = bBrkBefore == true,
        bGapRight = bBrkBefore == false;

    this.Root.UpdateOperators(_CurLine, _CurRange, bGapLeft, bGapRight);

    this.Root.Recalculate_Range_Width(PRSC, _CurLine, _CurRange);

    PRSC.Range.W        += PRSC.SpaceLen - SpaceLen;
    PRSC.Range.SpaceLen = SpaceLen;

    PRSC.Words++;
};
ParaMath.prototype.UpdateWidthLine = function(PRS, Width)
{
    var PrevRecalcObject = PRS.RestartPageRecalcInfo.Object;

    if(PrevRecalcObject == null || PrevRecalcObject == this)
    {
        var W = Width - PRS.OperGapRight - PRS.OperGapLeft;

        var bChangeMaxW = this.PageInfo.Update_CurrentWidth(PRS.Line, W);

        if(bChangeMaxW == true && this.Is_Inline() == false && align_Justify == this.Get_Align())
        {
            var Page = this.Paragraph == null ? 0 : this.Paragraph.Get_AbsolutePage(PRS.Page);
            var Line = this.PageInfo.Get_FirstLineOnPage(Page);

            PRS.Set_RestartPageRecalcInfo(Line, this);
            PRS.RecalcResult = recalcresult_PrevLine;
            PRS.NewRange = true;
        }
    }
};
ParaMath.prototype.Recalculate_Range_Spaces = function(PRSA, _CurLine, _CurRange, _CurPage)
{
    // до пересчета Bounds для текущей строки ранее должны быть вызваны Recalculate_Range_Width (для ширины), Recalculate_LineMetrics(для высоты и аскента)

    // для инлайновой формулы не вызывается ф-ия setPosition, поэтому необходимо вызвать здесь
    // для неилайновой setPosition вызывается на Get_AlignToLine
    var PosInfo = new CMathPosInfo();

    PosInfo.CurLine  = _CurLine;
    PosInfo.CurRange = _CurRange;

    var pos   = new CMathPosition();
    this.Root.setPosition(pos, PosInfo);

    // страиницу для смещния параграфа относительно документа добавим на Get_Bounds, т.к. если формула находится в автофигуре, то для нее не прийдет Recalculate_Range_Spaces при перемещении автофигуры а другую страницу
    this.Root.UpdateBoundsPosInfo(PRSA, _CurLine, _CurRange, _CurPage);
    this.Root.Recalculate_Range_Spaces(PRSA, _CurLine, _CurRange, _CurPage);
};
ParaMath.prototype.Recalculate_PageEndInfo = function(PRSI, _CurLine, _CurRange)
{

};
ParaMath.prototype.SaveRecalculateObject = function(Copy)
{
	var RecalcObj = this.Root.SaveRecalculateObject(Copy);
	RecalcObj.Save_MathInfo(this, Copy);

	return RecalcObj;
};
ParaMath.prototype.LoadRecalculateObject = function(RecalcObj)
{
    RecalcObj.Load_MathInfo(this);
    this.Root.LoadRecalculateObject(RecalcObj);
};
ParaMath.prototype.PrepareRecalculateObject = function()
{
	this.Root.PrepareRecalculateObject();
};
ParaMath.prototype.Is_EmptyRange = function(_CurLine, _CurRange)
{
    return this.Root.Is_EmptyRange(_CurLine, _CurRange);
};
ParaMath.prototype.Check_Range_OnlyMath = function(Checker, CurRange, CurLine)
{
    if (null !== Checker.Math)
    {
        Checker.Math   = null;
        Checker.Result = false;
    }
    else
        Checker.Math = this;
};

ParaMath.prototype.Check_MathPara = function(Checker)
{
    Checker.Found  = true;
    Checker.Result = false;
};

ParaMath.prototype.Check_PageBreak = function()
{
    return false;
};

ParaMath.prototype.Check_BreakPageEnd = function(PBChecker)
{
    return false;
};
ParaMath.prototype.Get_ParaPosByContentPos = function(ContentPos, Depth)
{
    return this.Root.Get_ParaPosByContentPos(ContentPos, Depth);
};

ParaMath.prototype.Recalculate_CurPos = function(_X, Y, CurrentRun, _CurRange, _CurLine, _CurPage, UpdateCurPos, UpdateTarget, ReturnTarget)
{
    return this.Root.Recalculate_CurPos(_X, Y, CurrentRun, _CurRange, _CurLine, _CurPage, UpdateCurPos, UpdateTarget, ReturnTarget);
};

ParaMath.prototype.Refresh_RecalcData = function(Data)
{
    this.Paragraph.Refresh_RecalcData2(0);
};

ParaMath.prototype.Refresh_RecalcData2 = function(Data)
{
    this.Paragraph.Refresh_RecalcData2(0);
};

ParaMath.prototype.RecalculateMinMaxContentWidth = function(MinMax)
{
    var RPI = new CRPI();
    RPI.MergeMathInfo(this.ParaMathRPI);

    this.Root.PreRecalc(null, this, new CMathArgSize(), RPI);
    this.Root.RecalculateMinMaxContentWidth(MinMax);
};

ParaMath.prototype.Get_Range_VisibleWidth = function(RangeW, _CurLine, _CurRange)
{
    this.Root.Get_Range_VisibleWidth(RangeW, _CurLine, _CurRange);
};
ParaMath.prototype.Is_BrkBinBefore = function()
{
    var MathSettings = Get_WordDocumentDefaultMathSettings();

    return this.Is_Inline() ? false : MathSettings.Get_BrkBin() == BREAK_BEFORE;
};
ParaMath.prototype.Shift_Range = function(Dx, Dy, _CurLine, _CurRange)
{
    this.Root.Shift_Range(Dx, Dy, _CurLine, _CurRange);
};
//-----------------------------------------------------------------------------------
// Функция для работы с формулой
// в тч с  дефолтными текстовыми настройками и argSize
//-----------------------------------------------------------------------------------
ParaMath.prototype.Set_Inline = function(value)
{
    if(value !== this.ParaMathRPI.bInline)
    {
        this.ParaMathRPI.bChangeInline = true;
        this.ParaMathRPI.bInline = value;
        this.bFastRecalculate = false;          // после смены инлайновости, требуется полностью пересчитать формулу
    }
};
ParaMath.prototype.Get_Inline = function()
{
    return this.ParaMathRPI.bInline;
};
ParaMath.prototype.Is_Inline = function()
{
    return this.ParaMathRPI.bInline == true /*|| (this.ParaMathRPI.bInternalRanges == true && this.ParaMathRPI.bStartRanges == false)*/;
};
ParaMath.prototype.NeedDispOperators = function(Line)
{
    return false === this.Is_Inline() &&  true == this.Root.IsStartLine(Line);
};
ParaMath.prototype.Get_Align = function()
{
    var Jc;
    if(this.ParaMathRPI.bInline)
    {
        var ParaPr = this.Paragraph.Get_CompiledPr2(false).ParaPr;
        Jc = ParaPr.Jc;
    }
    else if (undefined !== this.Jc)
    {
        Jc = this.Jc;
    }
    else
    {
        var MathSettings = Get_WordDocumentDefaultMathSettings();

        Jc = MathSettings.Get_DefJc();
    }

    return Jc;
};
ParaMath.prototype.Set_Align = function(Align)
{
	if (this.Jc !== Align)
	{
		History.Add(new CChangesMathParaJc(this, this.Jc, Align));
		this.raw_SetAlign(Align);
	}
};
ParaMath.prototype.raw_SetAlign = function(Align)
{
    this.Jc = Align;
};
ParaMath.prototype.SetRecalcCtrPrp = function(Class)
{
    if(this.Root.Content.length > 0 && this.ParaMathRPI.bRecalcCtrPrp == false)
    {
        this.ParaMathRPI.bRecalcCtrPrp = this.Root.Content[0] == Class;
    }
};
ParaMath.prototype.MathToImageConverter = function(bCopy, _canvasInput, _widthPx, _heightPx, raster_koef)
{
    var bTurnOnId = false;
    if (false === g_oTableId.m_bTurnOff)
    {
        g_oTableId.m_bTurnOff = true;
        bTurnOnId = true;
    }

	History.TurnOff();

    var oldDefTabStop = AscCommonWord.Default_Tab_Stop;
	AscCommonWord.Default_Tab_Stop = 1;

    var oApi = Asc['editor'] || editor;
    if(!oApi || !oApi.textArtPreviewManager){
        return null;
    }
    var oShape = oApi.textArtPreviewManager.getShape();
    //var hdr = new CHeaderFooter(editor.WordControl.m_oLogicDocument.HdrFtr, editor.WordControl.m_oLogicDocument, editor.WordControl.m_oDrawingDocument, AscCommon.hdrftr_Header);
    var _dc = oShape.getDocContent();

    var par = _dc.Content[0];

    if (bCopy)
        par.Internal_Content_Add(0, this.Copy(false), false);
    else
        par.Internal_Content_Add(0, this, false);

   // _dc.Internal_Content_Add(0, par, false);

    par.Set_Align(align_Left);
    par.Set_Tabs(new CParaTabs());

    var _ind = new CParaInd();
    _ind.FirstLine = 0;
    _ind.Left = 0;
    _ind.Right = 0;
    par.Set_Ind(_ind, false);

    var _sp = new CParaSpacing();
    _sp.Line              = 1;
    _sp.LineRule          = Asc.linerule_Auto;
    _sp.Before            = 0;
    _sp.BeforeAutoSpacing = false;
    _sp.After             = 0;
    _sp.AfterAutoSpacing  = false;
    par.Set_Spacing(_sp, false);

    // берем Default настройки, т.к. функция MathToImageConverter вызывается для новой формулы (созданной при копировании)
    var XLimit = 210, YLimit = 10000;

    _dc.Reset(0, 0, XLimit, YLimit);
    _dc.Recalculate_Page(0, true);

    _dc.Reset(0, 0, par.Lines[0].Ranges[0].W + 0.001, 10000);
    _dc.Recalculate_Page(0, true);

	AscCommonWord.Default_Tab_Stop = oldDefTabStop;

    if (true === bTurnOnId)
        g_oTableId.m_bTurnOff = false;

    History.TurnOn();

    AscCommon.IsShapeToImageConverter = true;

    var dKoef = AscCommon.g_dKoef_mm_to_pix;

    var JointSize = this.Get_JointSize();

    var W = JointSize.W,
        H = JointSize.H;

    var w_mm = W;
    var h_mm = H;
    var w_px = (w_mm * dKoef) >> 0;
    var h_px = (h_mm * dKoef) >> 0;

    if (undefined !== raster_koef)
    {
        w_px *= raster_koef;
        h_px *= raster_koef;

        if (undefined !== _widthPx)
            _widthPx *= raster_koef;
        if (undefined !== _heightPx)
            _heightPx *= raster_koef;
    }

    var _canvas = (_canvasInput === undefined) ? document.createElement('canvas') : _canvasInput;

    _canvas.width   = (undefined == _widthPx) ? w_px : _widthPx;
    _canvas.height  = (undefined == _heightPx) ? h_px : _heightPx;

    var _ctx = _canvas.getContext('2d');

    var g = new AscCommon.CGraphics();
    g.init(_ctx, w_px, h_px, w_mm, h_mm);
    g.m_oFontManager = AscCommon.g_fontManager;

    g.m_oCoordTransform.tx = 0;
    g.m_oCoordTransform.ty = 0;

    if (_widthPx !== undefined && _heightPx !== undefined)
    {
        g.m_oCoordTransform.tx = (_widthPx - w_px) / 2;
        g.m_oCoordTransform.ty = (_heightPx - h_px) / 2;
    }

    g.transform(1,0,0,1,0,0);


    var bNeedSetParaMarks = false;
    if(AscCommon.isRealObject(editor) && editor.ShowParaMarks)
    {
        bNeedSetParaMarks = true;
        editor.ShowParaMarks = false;
    }

    par.Draw(0, g);

    if(bNeedSetParaMarks)
    {
        editor.ShowParaMarks = true;
    }

    AscCommon.IsShapeToImageConverter = false;

    if (undefined === _canvasInput)
    {
        var _ret = { ImageNative: _canvas, ImageUrl: "", w_px: _canvas.width, h_px: _canvas.height, w_mm: w_mm, h_mm: h_mm};
        try
        {
            _ret.ImageUrl = _canvas.toDataURL("image/png");
        }
        catch (err)
        {
            _ret.ImageUrl = "";
        }
        return _ret;
    }
    return null;
};
ParaMath.prototype.Get_FirstTextPr = function()
{
    return this.Root.Get_FirstTextPr();
};
ParaMath.prototype.GetFirstRPrp = function()
{
    return this.Root.getFirstRPrp();
};
ParaMath.prototype.GetShiftCenter = function(oMeasure, font)
{
    oMeasure.SetFont(font);
    var metrics = oMeasure.Measure2Code(0x2217); // "+"

    return 0.6*metrics.Height;
};
ParaMath.prototype.GetPlh = function(oMeasure, font)
{
    oMeasure.SetFont(font);

    return oMeasure.Measure2Code(0x2B1A).Height;
};
ParaMath.prototype.Get_Default_TPrp = function()
{
    return this.DefaultTextPr;
};
//-----------------------------------------------------------------------------------
// Функции отрисовки
//-----------------------------------------------------------------------------------
ParaMath.prototype.Draw_HighLights = function(PDSH)
{
    if(false == this.Root.IsEmptyRange(PDSH.Line, PDSH.Range))
    {
        var X  = PDSH.X;
        var Y0 = PDSH.Y0;
        var Y1 = PDSH.Y1;

        var Comm = PDSH.Save_Comm();
        var Coll = PDSH.Save_Coll();

        this.Root.Draw_HighLights(PDSH, false);

        var CommFirst = PDSH.Comm.Get_Next();
        var CollFirst = PDSH.Coll.Get_Next();

        PDSH.Load_Comm(Comm);
        PDSH.Load_Coll(Coll);

        if (null !== CommFirst)
        {
            var CommentsCount = PDSH.Comments.length;
            var CommentId     = ( CommentsCount > 0 ? PDSH.Comments[CommentsCount - 1] : null );
            var CommentsFlag  = PDSH.CommentsFlag;

            var Bounds = this.Root.Get_LineBound(PDSH.Line, PDSH.Range);
            Comm.Add(Bounds.Y, Bounds.Y + Bounds.H, Bounds.X, Bounds.X + Bounds.W, 0, 0, 0, 0, { Active : CommentsFlag === comments_ActiveComment ? true : false, CommentId : CommentId } );
        }

        if (null !== CollFirst)
        {
            var Bounds = this.Root.Get_LineBound(PDSH.Line, PDSH.Range);
            Coll.Add(Bounds.Y, Bounds.Y + Bounds.H, Bounds.X, Bounds.X + Bounds.W, 0, CollFirst.r, CollFirst.g, CollFirst.b);
        }

        PDSH.Y0 = Y0;
        PDSH.Y1 = Y1;
    }
};
ParaMath.prototype.Draw_Elements = function(PDSE)
{
    /*PDSE.Graphics.p_color(255,0,0, 255);
     PDSE.Graphics.drawHorLine(0, PDSE.Y - this.Ascent, PDSE.X - 30, PDSE.X + this.Width + 30 , 1);*/

    var X = PDSE.X;

    this.Root.Draw_Elements(PDSE);

    PDSE.X = X + this.Root.Get_Width(PDSE.Line, PDSE.Range);

    /*PDSE.Graphics.p_color(255,0,0, 255);
     PDSE.Graphics.drawHorLine(0, PDSE.Y - this.Ascent + this.Height, PDSE.X - 30, PDSE.X + this.Width + 30 , 1);*/
};
ParaMath.prototype.GetLinePosition = function(Line, Range)
{
    return this.Root.GetPos(Line, Range);
};
ParaMath.prototype.Draw_Lines = function(PDSL)
{
    if(false == this.Root.IsEmptyRange(PDSL.Line, PDSL.Range))
    {
        // Underline всей формулы
        var FirstRPrp = this.GetFirstRPrp();

        var Para = PDSL.Paragraph;

        var aUnderline  = PDSL.Underline;

        var X          = PDSL.X;
        var Y          = PDSL.Baseline;
        var UndOff     = PDSL.UnderlineOffset;
        var UnderlineY = Y + UndOff;
        var LineW      = (FirstRPrp.FontSize / 18) * g_dKoef_pt_to_mm;


        var BgColor = PDSL.BgColor;
        if ( undefined !== FirstRPrp.Shd && Asc.c_oAscShdNil !== FirstRPrp.Shd.Value )
            BgColor = FirstRPrp.Shd.Get_Color( Para );
        var AutoColor = ( undefined != BgColor && false === BgColor.Check_BlackAutoColor() ? new CDocumentColor( 255, 255, 255, false ) : new CDocumentColor( 0, 0, 0, false ) );
        var CurColor, RGBA, Theme = this.Paragraph.Get_Theme(), ColorMap = this.Paragraph.Get_ColorMap();

        // Выставляем цвет обводки
        if ( true === PDSL.VisitedHyperlink && ( undefined === FirstRPrp.Color && undefined === FirstRPrp.Unifill ) )
            CurColor = new CDocumentColor( 128, 0, 151 );
        else if ( true === FirstRPrp.Color.Auto && !FirstRPrp.Unifill)
            CurColor = new CDocumentColor( AutoColor.r, AutoColor.g, AutoColor.b );
        else
        {
            if(FirstRPrp.Unifill)
            {
                FirstRPrp.Unifill.check(Theme, ColorMap);
                RGBA = FirstRPrp.Unifill.getRGBAColor();
                CurColor = new CDocumentColor( RGBA.R, RGBA.G, RGBA.B );
            }
            else
            {
                CurColor = new CDocumentColor( FirstRPrp.Color.r, FirstRPrp.Color.g, FirstRPrp.Color.b );
            }
        }

        var Bound = this.Root.Get_LineBound(PDSL.Line, PDSL.Range),
            Width = Bound.W;

        if ( true === FirstRPrp.Underline )
            aUnderline.Add( UnderlineY, UnderlineY, X, X + Width, LineW, CurColor.r, CurColor.g, CurColor.b );


        this.Root.Draw_Lines(PDSL);

        PDSL.X = Bound.X + Width;
    }
};

//-----------------------------------------------------------------------------------
// Функции для работы с курсором
//-----------------------------------------------------------------------------------
ParaMath.prototype.Is_CursorPlaceable = function()
{
    return true;
};

ParaMath.prototype.Cursor_Is_Start = function()
{
    // TODO: ParaMath.Cursor_Is_Start

    return this.Root.Cursor_Is_Start();
};

ParaMath.prototype.Cursor_Is_NeededCorrectPos = function()
{
    return false;
};

ParaMath.prototype.Cursor_Is_End = function()
{
    // TODO: ParaMath.Cursor_Is_End

    return this.Root.Cursor_Is_End();
};

ParaMath.prototype.MoveCursorToStartPos = function()
{
	this.Root.MoveCursorToStartPos();
};

ParaMath.prototype.MoveCursorToEndPos = function(SelectFromEnd)
{
	this.Root.MoveCursorToEndPos(SelectFromEnd);
};

ParaMath.prototype.Get_ParaContentPosByXY = function(SearchPos, Depth, _CurLine, _CurRange, StepEnd, Flag) // получить логическую позицию по XY
{
	var Result = false;

	var CurX = SearchPos.CurX;

	var MathX = SearchPos.CurX;
	var MathW = this.Root.Get_Width(_CurLine, _CurRange);

	// Если мы попадаем четко в формулу, тогда ищем внутри нее, если нет, тогда не заходим внутрь
	if ((SearchPos.X > MathX && SearchPos.X < MathX + MathW) || SearchPos.DiffX > 1000000 - 1)
	{
		var bFirstItem = SearchPos.DiffX > 1000000 - 1 ? true : false;

		Result = this.Root.Get_ParaContentPosByXY(SearchPos, Depth, _CurLine, _CurRange, StepEnd);

		if (SearchPos.InText)
			SearchPos.DiffX = 0.001; // чтобы всегда встать в формулу, если попали в текст

		// TODO: Пересмотреть данную проверку. Надо выяснить насколько сильно она вообще нужна
		// Если мы попадаем в формулу, тогда не ищем позицию вне ее. За исключением, случая когда формула идет в начале
		// строки. Потому что в последнем случае из формулы 100% придет true, а позиция, возможно, находится за формулой.
		if (Result && !bFirstItem)
			SearchPos.DiffX = 0;
	}

	// Такое возможно, если все элементы до этого (в том числе и этот) были пустыми, тогда, чтобы не возвращать
	// неправильную позицию вернем позицию начала данного элемента.
	if (SearchPos.DiffX > 1000000 - 1)
	{
		this.Get_StartPos(SearchPos.Pos, Depth);
		Result = true;
	}

	SearchPos.CurX = CurX + MathW;
	return Result;
};

ParaMath.prototype.Get_ParaContentPos = function(bSelection, bStart, ContentPos, bUseCorrection)
{
    this.Root.Get_ParaContentPos(bSelection, bStart, ContentPos, bUseCorrection);
};

ParaMath.prototype.Set_ParaContentPos = function(ContentPos, Depth) // выставить логическую позицию в контенте
{
    this.Root.Set_ParaContentPos(ContentPos, Depth);
};

ParaMath.prototype.Get_PosByElement = function(Class, ContentPos, Depth, UseRange, Range, Line)
{
    if ( this === Class )
        return true;

    return this.Root.Get_PosByElement(Class, ContentPos, Depth, UseRange, Range, Line);
};

ParaMath.prototype.Get_ElementByPos = function(ContentPos, Depth)
{
    return this.Root.Get_ElementByPos(ContentPos, Depth);
};

ParaMath.prototype.Get_ClassesByPos = function(Classes, ContentPos, Depth)
{
    Classes.push(this);

    this.Root.Get_ClassesByPos(Classes, ContentPos, Depth);
};

ParaMath.prototype.Get_PosByDrawing = function(Id, ContentPos, Depth)
{
    return false;
};

ParaMath.prototype.Get_RunElementByPos = function(ContentPos, Depth)
{
    return null;
};

ParaMath.prototype.Get_LastRunInRange = function(_CurLine, _CurRange)
{
    return this.Root.Get_LastRunInRange(_CurLine, _CurRange);
};

ParaMath.prototype.Get_LeftPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
    return this.Root.Get_LeftPos(SearchPos, ContentPos, Depth, UseContentPos, false);
};

ParaMath.prototype.Get_RightPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
    return this.Root.Get_RightPos(SearchPos, ContentPos, Depth, UseContentPos, StepEnd, false);
};

ParaMath.prototype.Get_WordStartPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
    this.Root.Get_WordStartPos(SearchPos, ContentPos, Depth, UseContentPos, false);
};

ParaMath.prototype.Get_WordEndPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
    this.Root.Get_WordEndPos(SearchPos, ContentPos, Depth, UseContentPos, StepEnd, false);
};

ParaMath.prototype.Get_EndRangePos = function(_CurLine, _CurRange, SearchPos, Depth)
{
    return this.Root.Get_EndRangePos(_CurLine, _CurRange, SearchPos, Depth);
};

ParaMath.prototype.Get_StartRangePos = function(_CurLine, _CurRange, SearchPos, Depth)
{
    return this.Root.Get_StartRangePos(_CurLine, _CurRange, SearchPos, Depth);
};

ParaMath.prototype.Get_StartRangePos2 = function(_CurLine, _CurRange, ContentPos, Depth)
{
    return this.Root.Get_StartRangePos2(_CurLine, _CurRange, ContentPos, Depth);
};

ParaMath.prototype.Get_EndRangePos2 = function(_CurLine, _CurRange, ContentPos, Depth)
{
	return this.Root.Get_EndRangePos2(_CurLine, _CurRange, ContentPos, Depth);
};

ParaMath.prototype.Get_StartPos = function(ContentPos, Depth)
{
    this.Root.Get_StartPos(ContentPos, Depth);
};

ParaMath.prototype.Get_EndPos = function(BehindEnd, ContentPos, Depth)
{
    this.Root.Get_EndPos(BehindEnd, ContentPos, Depth);
};
//-----------------------------------------------------------------------------------
// Функции для работы с селектом
//-----------------------------------------------------------------------------------
ParaMath.prototype.Set_SelectionContentPos = function(StartContentPos, EndContentPos, Depth, StartFlag, EndFlag)
{
    this.Root.Set_SelectionContentPos(StartContentPos, EndContentPos, Depth, StartFlag, EndFlag);
    this.bSelectionUse = true;
};

ParaMath.prototype.IsSelectionUse = function()
{
    return this.bSelectionUse;
};

ParaMath.prototype.RemoveSelection = function()
{
    this.bSelectionUse = false;
    this.Root.RemoveSelection();
};

ParaMath.prototype.SelectAll = function(Direction)
{
    this.bSelectionUse = true;
    this.Root.SelectAll(Direction);
};

ParaMath.prototype.Selection_DrawRange = function(_CurLine, _CurRange, SelectionDraw)
{
    this.Root.Selection_DrawRange(_CurLine, _CurRange, SelectionDraw);
};

ParaMath.prototype.IsSelectionEmpty = function(CheckEnd)
{
    return this.Root.IsSelectionEmpty();
};

ParaMath.prototype.Selection_IsPlaceholder = function()
{
    var bPlaceholder = false;
    var result = this.GetSelectContent(),
        SelectContent = result.Content;
    var start = result.Start,
        end = result.End;

    if(start == end)
    {
        bPlaceholder = SelectContent.IsPlaceholder();
    }

    return bPlaceholder;
};

ParaMath.prototype.Selection_CheckParaEnd = function()
{
    return false;
};

ParaMath.prototype.Selection_CheckParaContentPos = function(ContentPos, Depth, bStart, bEnd)
{
    return this.Root.Selection_CheckParaContentPos(ContentPos, Depth, bStart, bEnd);
};

ParaMath.prototype.IsSelectedAll = function(Props)
{
	return this.Root.IsSelectedAll(Props);
};

ParaMath.prototype.Selection_CorrectLeftPos = function(Direction)
{
    return false;
};
//----------------------------------------------------------------------------------------------------------------------
// Функции совместного редактирования
//----------------------------------------------------------------------------------------------------------------------
ParaMath.prototype.Write_ToBinary2 = function(Writer)
{
    Writer.WriteLong( AscDFH.historyitem_type_Math );

    // String : this.Id
    // Long   : this.Type
    // String : Root.Id

    Writer.WriteString2(this.Id);
    Writer.WriteLong(this.Type);
    Writer.WriteString2(this.Root.Id);
};

ParaMath.prototype.Read_FromBinary2 = function(Reader)
{
    // String : this.Id
    // Long   : this.Type
    // String : Root.Id

    this.Id   = Reader.GetString2();
    this.Type = Reader.GetLong();
    this.Root = g_oTableId.Get_ById(Reader.GetString2());
    this.Root.bRoot = true;
    this.Root.ParentElement = this;
};

ParaMath.prototype.Get_ContentSelection = function()
{
    var Bounds = null;
    var oContent = this.GetSelectContent().Content;

    if (true == oContent.Can_GetSelection())
    {
        if(oContent.bOneLine)
        {
            Bounds = [];
            Bounds[0] = [];

            var ContentBounds = oContent.Get_Bounds();
            var oBound = ContentBounds[0][0];

            Bounds[0][0] =
            {
                X:      oBound.X,
                Y:      oBound.Y,
                W:      oBound.W,
                H:      oBound.H,
                Page:   this.Paragraph.Get_AbsolutePage(oBound.Page)
            };
        }
        else
        {
            Bounds = this.private_GetBounds(oContent);
        }
    }

    return Bounds;
};

ParaMath.prototype.Recalc_RunsCompiledPr = function()
{
    this.Root.Recalc_RunsCompiledPr();
};

/**
 * Проверяем находимся ли мы во внутреннем (не самом верхнем) контенте формулы.
 */
ParaMath.prototype.Is_InInnerContent = function()
{
    var oContent = this.GetSelectContent().Content;

    if (oContent.bRoot)
        return false;

    return true;
};

/**
 * Обработка нажатия Enter внутри формулы
 */
ParaMath.prototype.Handle_AddNewLine = function()
{
    var ContentPos = new CParagraphContentPos();

    var CurrContent = this.GetSelectContent().Content;

    if (true === CurrContent.bRoot)
        return false;

    CurrContent.Get_ParaContentPos(this.bSelectionUse, true, ContentPos);

    var NeedRecalculate = false;

    if(MATH_EQ_ARRAY === CurrContent.ParentElement.kind)
    {
        var oEqArray = CurrContent.Parent;

        oEqArray.Add_Row(oEqArray.CurPos + 1);
        oEqArray.CurPos++;

        NeedRecalculate = true;
    }
    else if(MATH_MATRIX !== CurrContent.ParentElement.kind)
    {
        var ctrPrp = CurrContent.Parent.CtrPrp.Copy();
        var props = {row: 2, ctrPrp: ctrPrp};
        var EqArray = new CEqArray(props);

        var FirstContent  = EqArray.getElementMathContent(0);
        var SecondContent = EqArray.getElementMathContent(1);

        CurrContent.SplitContent(SecondContent, ContentPos, 0);
        CurrContent.CopyTo(FirstContent, false);

        // вставим пустой Run в Content, чтобы не упала ф-ия Remove_FromContent
        // первый элемент всегда Run
        var Run = CurrContent.getElem(0);
        Run.Remove_FromContent(0, Run.Content.length, true);

        CurrContent.Remove_FromContent(1, CurrContent.Content.length);
        CurrContent.Add_ToContent(1, EqArray);
        CurrContent.Correct_Content(true);

        var CurrentContent = new CParagraphContentPos();
        this.Get_ParaContentPos(false, false, CurrentContent);

        var RightContentPos = new CParagraphSearchPos();
        this.Get_RightPos(RightContentPos, CurrentContent, 0, true);
        this.Set_ParaContentPos(RightContentPos.Pos, 0);

        EqArray.CurPos = 1;
        SecondContent.MoveCursorToStartPos();

        NeedRecalculate = true;
    }


    return NeedRecalculate;
};

/**
 * Разделение формулы на 2 части в заданной позиции. В текущем объекте остается левая часть формулы.
 * @param ContentPos Позиция
 * @param Depth
 * @returns Возвращается правая часть формулы.
 */
ParaMath.prototype.Split = function (ContentPos, Depth)
{
	if (this.Cursor_Is_End())
		return new ParaRun(this.Paragraph, false);

    var NewParaMath = new ParaMath();
    NewParaMath.Jc = this.Jc;

    this.Root.SplitContent(NewParaMath.Root, ContentPos, Depth);

    return NewParaMath;
};

/**
 * Пытаемся выполнить автозамену в формуле.
 * @returns {boolean} Выполнилась ли автозамена.
 */
ParaMath.prototype.Make_AutoCorrect = function()
{
    return false;
};

/**
 * Получаем рект формулы
 * @constructor
 */
ParaMath.prototype.Get_Bounds = function()
{
    if (undefined === this.Paragraph || null === this.Paragraph)
    {
        return [ [{X : 0, Y : 0, W : 0, H : 0, Page : 0}] ];
    }
    else
    {
        return this.private_GetBounds(this.Root);
    }
};
ParaMath.prototype.Get_JointSize = function()
{
    var W = 0, H = 0;

    var _bounds = this.Get_Bounds();

    for(var Line = 0; Line < _bounds.length; Line++)
    {
        if(_bounds[Line] === undefined)
            break;

        for(var Range = 0; Range < _bounds[Line].length; Range++)
        {
            W += _bounds[Line][Range].W;
            H += _bounds[Line][Range].H;
        }
    }

    return {W: W, H: H};
};
ParaMath.prototype.private_GetBounds = function(Content)
{
    var Bounds = [ [{X : 0, Y : 0, W : 0, H : 0, Page : 0}] ];
    var ContentBounds = Content.Get_Bounds();

    for(var Line = 0; Line < ContentBounds.length; Line++)
    {
        Bounds[Line] = [];
        var CurLine = Line + Content.StartLine;
        var HLine = this.Paragraph.Lines[CurLine].Bottom - this.Paragraph.Lines[CurLine].Top;
        var Height = HLine;
        var Y;

        for(var Range = 0; Range < ContentBounds[Line].length; Range++)
        {
            var oBound   = ContentBounds[Line][Range],
                ParaPage = oBound.Page,
                YLine    = this.Paragraph.Pages[ParaPage].Y + this.Paragraph.Lines[CurLine].Top;

            Y = YLine;

            if(Content.bRoot == false)
            {
                if(HLine < oBound.H) // сделано для случаев, когда межстрочный интервал небольшой
                {
                    Height = HLine;
                    Y = YLine;
                }
                else
                {
                    Height = oBound.H;
                    Y  = oBound.Y;
                }
            }

            Bounds[Line][Range] =
            {
                X:      oBound.X,
                Y:      Y,
                W:      oBound.W,
                H:      Height,
                Page:   this.Paragraph.Get_AbsolutePage(oBound.Page)
            };
        }
    }

    return Bounds;
};

ParaMath.prototype.getPropsForWrite = function()
{
    return {Jc : this.Jc};
};

/**
 * Обновляем состояние интерфейса.
 */
ParaMath.prototype.Document_UpdateInterfaceState = function()
{
    var MathProps = this.Get_MenuProps();
    editor.sync_MathPropCallback(MathProps);
};

/**
 * Проверяем используется ли заданный MathContent на текущем уровне формулы
 * @param MathContent
 */
ParaMath.prototype.Is_ContentUse  = function(MathContent)
{
    if (this.Root === MathContent)
        return true;

    return false;
};

/*
 * Выполняем коректировку формулы после конвертирования ее из старой формулы (Equation 2-3).
 */
ParaMath.prototype.Correct_AfterConvertFromEquation = function()
{
    this.ParaMathRPI.bCorrect_ConvertFontSize = true;
};

ParaMath.prototype.Check_RevisionsChanges = function(Checker, ContentPos, Depth)
{
    return this.Root.Check_RevisionsChanges(Checker, ContentPos, Depth);
};
ParaMath.prototype.AcceptRevisionChanges = function(Type, bAll)
{
    return this.Root.AcceptRevisionChanges(Type, bAll);
};
ParaMath.prototype.RejectRevisionChanges = function(Type, bAll)
{
    return this.Root.RejectRevisionChanges(Type, bAll);
};
ParaMath.prototype.Set_ReviewType = function(ReviewType, RemovePrChange)
{
    return this.Root.Set_ReviewType(ReviewType, RemovePrChange);
};
ParaMath.prototype.HandleTab = function(isForward)
{
    if(this.ParaMathRPI.bInline == false)
    {
        var CountOperators = this.DispositionOpers.length;
        var bBrkBefore = this.Is_BrkBinBefore();
        this.Root.Displace_BreakOperator(isForward, bBrkBefore, CountOperators);
    }
};
ParaMath.prototype.SetContentSelection = function(StartDocPos, EndDocPos, Depth, StartFlag, EndFlag)
{
    return this.Root.SetContentSelection(StartDocPos, EndDocPos, Depth, StartFlag, EndFlag);
};
ParaMath.prototype.SetContentPosition = function(DocPos, Depth, Flag)
{
    return this.Root.SetContentPosition(DocPos, Depth, Flag);
};
ParaMath.prototype.IsStopCursorOnEntryExit = function()
{
	return true;
};
ParaMath.prototype.RemoveTabsForTOC = function(isTab)
{
	return isTab;
};

function MatGetKoeffArgSize(FontSize, ArgSize)
{
    var FontKoef = 1;

    if(ArgSize == -1)
    {
        FontKoef = g_dMathArgSizeKoeff_1;
    }
    else if(ArgSize == -2)
    {
        FontKoef = g_dMathArgSizeKoeff_2;
    }

    if (1 !== FontKoef )
    {
        FontKoef = (((FontSize * FontKoef * 2 + 0.5) | 0) / 2) / FontSize;
    }

    return FontKoef;
}

function CMathRecalculateInfo()
{
    this.bInline                       = false;
    this.bChangeInline                 = true;
    this.bRecalcCtrPrp                 = false; // необходимо для пересчета CtrPrp (когда изменились текстовые настройки у первого элемнента, ctrPrp нужно пересчитать заново для всей формулы)
    this.bCorrect_ConvertFontSize      = false;

    this.IntervalState                  = MATH_INTERVAL_EMPTY;
    this.XStart                         = 0;
    this.XEnd                           = 0;
    this.XRange                         = 0;
    this.XLimit                         = 0;
    this.IndLeft                        = 0;
    this.bInternalRanges                = false;

    this.RangeY                         = null; // max среди нижних границ плавающих объектов
    this.ShiftY                         = 0;
}
CMathRecalculateInfo.prototype.Reset = function(PRS, ParaPr)
{
    this.XRange                 = PRS.XStart + ParaPr.Ind.Left;
    this.XLimit                 = PRS.XLimit;
    this.IndLeft                = ParaPr.Ind.Left;
    this.ShiftY                 = 0;

    this.Reset_WrapSettings();
};
CMathRecalculateInfo.prototype.Reset_WrapSettings = function()
{
    this.RangeY                 = null;

    this.bInternalRanges        = false;
    this.IntervalState          = MATH_INTERVAL_EMPTY;

    this.XStart                 = this.XRange;
    this.XEnd                   = this.XLimit;
};
CMathRecalculateInfo.prototype.UpdateShiftY = function(RY)
{
    this.ShiftY = RY;
};
CMathRecalculateInfo.prototype.ClearRecalculate = function()
{
    this.bChangeInline                  = false;
    this.bRecalcCtrPrp                  = false;
    this.bCorrect_ConvertFontSize       = false;
};

function CMathRecalculateObject()
{
    this.WrapState        = ALIGN_EMPTY;
    this.MaxW             = 0;              // для рассчета выравнивания формулы нужно учитывать изменилась ли максимальная ширина или нет
    this.bWordLarge       = false;          // если формула выходит за границы докумена, то не нужно учитывать выравнивание, а значит можно сделать быстрый пересчет
    this.bFastRecalculate = true;           /*если добавляем буквы во внутренний контент, который не бьется на строки, то отменяем быстрый пересчет,
                                            т.к. высота контента может поменяться (она рассчитывается точно исходя из размеров внутр элементов)*/

    this.bInline          = false;
    this.Align            = align_Justify;
    this.bEmptyFirstRange = false;
}
CMathRecalculateObject.prototype.Fill = function(StructRecalc)
{
    this.bFastRecalculate = StructRecalc.bFastRecalculate;
    this.bInline          = StructRecalc.bInline;
    this.Align            = StructRecalc.Align;

    var PageInfo          = StructRecalc.PageInfo;

    this.WrapState        = PageInfo.Get_CurrentWrapState();
    this.MaxW             = PageInfo.Get_MaxWidthOnCurrentPage();
    this.bWordLarge       = PageInfo.Get_CurrentStateWordLarge();

    this.bEmptyFirstRange = StructRecalc.bEmptyFirstRange;
};
CMathRecalculateObject.prototype.Load_MathInfo = function(PageInfo)
{
    PageInfo.Set_CurrentWrapState(this.WrapState);

    // текущая MaxW и MaxW в PageInfo это не одно и то же
    //PageInfo.SetCurrentMaxWidth(this.MaxW);
};
CMathRecalculateObject.prototype.Compare = function(PageInfo)
{
    var result = true;

    if(this.bFastRecalculate == false)
        result = false;

    if(this.WrapState !== PageInfo.Get_CurrentWrapState())
        result = false;

    if(this.bEmptyFirstRange !== PageInfo.bEmptyFirstRange)
        result = false;

    var DiffMaxW = this.MaxW - PageInfo.Get_MaxWidthOnCurrentPage();

    if(DiffMaxW < 0)
        DiffMaxW = -DiffMaxW;

    var LargeComposition = this.bWordLarge == true && true == PageInfo.Get_CurrentStateWordLarge();

    if(LargeComposition == false && this.bInline == false && this.Align == align_Justify && DiffMaxW > 0.001)
        result = false;

    return result;
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].MathMenu = MathMenu;
window['AscCommonWord'].ParaMath = ParaMath;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 09.11.2016
 * Time: 15:52
 */

AscDFH.changesFactory[AscDFH.historyitem_MathContent_AddItem]      = CChangesMathContentAddItem;
AscDFH.changesFactory[AscDFH.historyitem_MathContent_RemoveItem]   = CChangesMathContentRemoveItem;
AscDFH.changesFactory[AscDFH.historyitem_MathContent_ArgSize]      = CChangesMathContentArgSize;
AscDFH.changesFactory[AscDFH.historyitem_MathPara_Jc]              = CChangesMathParaJc;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_AddItems]        = CChangesMathBaseAddItems;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_RemoveItems]     = CChangesMathBaseRemoveItems;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_FontSize]        = CChangesMathBaseFontSize;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_Shd]             = CChangesMathBaseShd;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_Color]           = CChangesMathBaseColor;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_Unifill]         = CChangesMathBaseUnifill;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_Underline]       = CChangesMathBaseUnderline;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_Strikeout]       = CChangesMathBaseStrikeout;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_DoubleStrikeout] = CChangesMathBaseDoubleStrikeout;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_Italic]          = CChangesMathBaseItalic;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_Bold]            = CChangesMathBaseBold;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_RFontsAscii]     = CChangesMathBaseRFontsAscii;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_RFontsHAnsi]     = CChangesMathBaseRFontsHAnsi;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_RFontsCS]        = CChangesMathBaseRFontsCS;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_RFontsEastAsia]  = CChangesMathBaseRFontsEastAsia;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_RFontsHint]      = CChangesMathBaseRFontsHint;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_HighLight]       = CChangesMathBaseHighLight;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_ReviewType]      = CChangesMathBaseReviewType;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_TextFill]        = CChangesMathBaseTextFill;
AscDFH.changesFactory[AscDFH.historyitem_MathBase_TextOutline]     = CChangesMathBaseTextOutline;
AscDFH.changesFactory[AscDFH.historyitem_MathBox_AlnAt]            = CChangesMathBoxAlnAt;
AscDFH.changesFactory[AscDFH.historyitem_MathBox_ForcedBreak]      = CChangesMathBoxForcedBreak;
AscDFH.changesFactory[AscDFH.historyitem_MathFraction_Type]        = CChangesMathFractionType;
AscDFH.changesFactory[AscDFH.historyitem_MathRadical_HideDegree]   = CChangesMathRadicalHideDegree;
AscDFH.changesFactory[AscDFH.historyitem_MathNary_LimLoc]          = CChangesMathNaryLimLoc;
AscDFH.changesFactory[AscDFH.historyitem_MathNary_UpperLimit]      = CChangesMathNaryUpperLimit;
AscDFH.changesFactory[AscDFH.historyitem_MathNary_LowerLimit]      = CChangesMathNaryLowerLimit;
AscDFH.changesFactory[AscDFH.historyitem_MathDelimiter_BegOper]    = CChangesMathDelimBegOper;
AscDFH.changesFactory[AscDFH.historyitem_MathDelimiter_EndOper]    = CChangesMathDelimEndOper;
AscDFH.changesFactory[AscDFH.historyitem_MathDelimiter_Grow]       = CChangesMathDelimiterGrow;
AscDFH.changesFactory[AscDFH.historyitem_MathDelimiter_Shape]      = CChangesMathDelimiterShape;
AscDFH.changesFactory[AscDFH.historyitem_MathDelimiter_SetColumn]  = CChangesMathDelimiterSetColumn;
AscDFH.changesFactory[AscDFH.historyitem_MathGroupChar_Pr]         = CChangesMathGroupCharPr;
AscDFH.changesFactory[AscDFH.historyitem_MathLimit_Type]           = CChangesMathLimitType;
AscDFH.changesFactory[AscDFH.historyitem_MathBorderBox_Top]        = CChangesMathBorderBoxTop;
AscDFH.changesFactory[AscDFH.historyitem_MathBorderBox_Bot]        = CChangesMathBorderBoxBot;
AscDFH.changesFactory[AscDFH.historyitem_MathBorderBox_Left]       = CChangesMathBorderBoxLeft;
AscDFH.changesFactory[AscDFH.historyitem_MathBorderBox_Right]      = CChangesMathBorderBoxRight;
AscDFH.changesFactory[AscDFH.historyitem_MathBorderBox_Hor]        = CChangesMathBorderBoxHor;
AscDFH.changesFactory[AscDFH.historyitem_MathBorderBox_Ver]        = CChangesMathBorderBoxVer;
AscDFH.changesFactory[AscDFH.historyitem_MathBorderBox_TopLTR]     = CChangesMathBorderBoxTopLTR;
AscDFH.changesFactory[AscDFH.historyitem_MathBorderBox_TopRTL]     = CChangesMathBorderBoxTopRTL;
AscDFH.changesFactory[AscDFH.historyitem_MathBar_LinePos]          = CChangesMathBarLinePos;
AscDFH.changesFactory[AscDFH.historyitem_MathMatrix_AddRow]        = CChangesMathMatrixAddRow;
AscDFH.changesFactory[AscDFH.historyitem_MathMatrix_RemoveRow]     = CChangesMathMatrixRemoveRow;
AscDFH.changesFactory[AscDFH.historyitem_MathMatrix_AddColumn]     = CChangesMathMatrixAddColumn;
AscDFH.changesFactory[AscDFH.historyitem_MathMatrix_RemoveColumn]  = CChangesMathMatrixRemoveColumn;
AscDFH.changesFactory[AscDFH.historyitem_MathMatrix_BaseJc]        = CChangesMathMatrixBaseJc;
AscDFH.changesFactory[AscDFH.historyitem_MathMatrix_ColumnJc]      = CChangesMathMatrixColumnJc;
AscDFH.changesFactory[AscDFH.historyitem_MathMatrix_Interval]      = CChangesMathMatrixInterval;
AscDFH.changesFactory[AscDFH.historyitem_MathMatrix_Plh]           = CChangesMathMatrixPlh;
AscDFH.changesFactory[AscDFH.historyitem_MathDegree_SubSupType]    = CChangesMathDegreeSubSupType;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_MathContent_AddItem]      = [
	AscDFH.historyitem_MathContent_AddItem,
	AscDFH.historyitem_MathContent_RemoveItem
];
AscDFH.changesRelationMap[AscDFH.historyitem_MathContent_RemoveItem]   = [
	AscDFH.historyitem_MathContent_AddItem,
	AscDFH.historyitem_MathContent_RemoveItem
];
AscDFH.changesRelationMap[AscDFH.historyitem_MathContent_ArgSize]      = [AscDFH.historyitem_MathContent_ArgSize];
AscDFH.changesRelationMap[AscDFH.historyitem_MathPara_Jc]              = [AscDFH.historyitem_MathPara_Jc];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_AddItems]        = [
	AscDFH.historyitem_MathBase_AddItems,
	AscDFH.historyitem_MathBase_RemoveItems
];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_RemoveItems]     = [
	AscDFH.historyitem_MathBase_AddItems,
	AscDFH.historyitem_MathBase_RemoveItems
];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_FontSize]        = [AscDFH.historyitem_MathBase_FontSize];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_Shd]             = [AscDFH.historyitem_MathBase_Shd];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_Color]           = [AscDFH.historyitem_MathBase_Color];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_Unifill]         = [AscDFH.historyitem_MathBase_Unifill];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_Underline]       = [AscDFH.historyitem_MathBase_Underline];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_Strikeout]       = [AscDFH.historyitem_MathBase_Strikeout];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_DoubleStrikeout] = [AscDFH.historyitem_MathBase_DoubleStrikeout];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_Italic]          = [AscDFH.historyitem_MathBase_Italic];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_Bold]            = [AscDFH.historyitem_MathBase_Bold];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_RFontsAscii]     = [AscDFH.historyitem_MathBase_RFontsAscii];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_RFontsHAnsi]     = [AscDFH.historyitem_MathBase_RFontsHAnsi];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_RFontsCS]        = [AscDFH.historyitem_MathBase_RFontsCS];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_RFontsEastAsia]  = [AscDFH.historyitem_MathBase_RFontsEastAsia];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_RFontsHint]      = [AscDFH.historyitem_MathBase_RFontsHint];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_HighLight]       = [AscDFH.historyitem_MathBase_HighLight];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_ReviewType]      = [AscDFH.historyitem_MathBase_ReviewType];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_TextFill]        = [AscDFH.historyitem_MathBase_TextFill];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBase_TextOutline]     = [AscDFH.historyitem_MathBase_TextOutline];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBox_AlnAt]            = [AscDFH.historyitem_MathBox_AlnAt, AscDFH.historyitem_MathBox_ForcedBreak];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBox_ForcedBreak]      = [AscDFH.historyitem_MathBox_AlnAt, AscDFH.historyitem_MathBox_ForcedBreak];
AscDFH.changesRelationMap[AscDFH.historyitem_MathFraction_Type]        = [AscDFH.historyitem_MathFraction_Type];
AscDFH.changesRelationMap[AscDFH.historyitem_MathRadical_HideDegree]   = [AscDFH.historyitem_MathRadical_HideDegree];
AscDFH.changesRelationMap[AscDFH.historyitem_MathNary_LimLoc]          = [AscDFH.historyitem_MathNary_LimLoc];
AscDFH.changesRelationMap[AscDFH.historyitem_MathNary_UpperLimit]      = [AscDFH.historyitem_MathNary_UpperLimit];
AscDFH.changesRelationMap[AscDFH.historyitem_MathNary_LowerLimit]      = [AscDFH.historyitem_MathNary_LowerLimit];
AscDFH.changesRelationMap[AscDFH.historyitem_MathDelimiter_BegOper]    = [AscDFH.historyitem_MathDelimiter_BegOper];
AscDFH.changesRelationMap[AscDFH.historyitem_MathDelimiter_EndOper]    = [AscDFH.historyitem_MathDelimiter_EndOper];
AscDFH.changesRelationMap[AscDFH.historyitem_MathDelimiter_Grow]       = [AscDFH.historyitem_MathDelimiter_Grow];
AscDFH.changesRelationMap[AscDFH.historyitem_MathDelimiter_Shape]      = [AscDFH.historyitem_MathDelimiter_Shape];
AscDFH.changesRelationMap[AscDFH.historyitem_MathDelimiter_SetColumn]  = [AscDFH.historyitem_MathDelimiter_SetColumn];
AscDFH.changesRelationMap[AscDFH.historyitem_MathGroupChar_Pr]         = [AscDFH.historyitem_MathGroupChar_Pr];
AscDFH.changesRelationMap[AscDFH.historyitem_MathLimit_Type]           = [AscDFH.historyitem_MathLimit_Type];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBorderBox_Top]        = [AscDFH.historyitem_MathBorderBox_Top];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBorderBox_Bot]        = [AscDFH.historyitem_MathBorderBox_Bot];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBorderBox_Left]       = [AscDFH.historyitem_MathBorderBox_Left];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBorderBox_Right]      = [AscDFH.historyitem_MathBorderBox_Right];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBorderBox_Hor]        = [AscDFH.historyitem_MathBorderBox_Hor];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBorderBox_Ver]        = [AscDFH.historyitem_MathBorderBox_Ver];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBorderBox_TopLTR]     = [AscDFH.historyitem_MathBorderBox_TopLTR];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBorderBox_TopRTL]     = [AscDFH.historyitem_MathBorderBox_TopRTL];
AscDFH.changesRelationMap[AscDFH.historyitem_MathBar_LinePos]          = [AscDFH.historyitem_MathBar_LinePos];
AscDFH.changesRelationMap[AscDFH.historyitem_MathMatrix_AddRow]        = [
	AscDFH.historyitem_MathMatrix_AddRow,
	AscDFH.historyitem_MathMatrix_RemoveRow,
	AscDFH.historyitem_MathMatrix_AddColumn,
	AscDFH.historyitem_MathMatrix_RemoveColumn
];
AscDFH.changesRelationMap[AscDFH.historyitem_MathMatrix_RemoveRow]     = [
	AscDFH.historyitem_MathMatrix_AddRow,
	AscDFH.historyitem_MathMatrix_RemoveRow,
	AscDFH.historyitem_MathMatrix_AddColumn,
	AscDFH.historyitem_MathMatrix_RemoveColumn
];
AscDFH.changesRelationMap[AscDFH.historyitem_MathMatrix_AddColumn]     = [
	AscDFH.historyitem_MathMatrix_AddRow,
	AscDFH.historyitem_MathMatrix_RemoveRow,
	AscDFH.historyitem_MathMatrix_AddColumn,
	AscDFH.historyitem_MathMatrix_RemoveColumn
];
AscDFH.changesRelationMap[AscDFH.historyitem_MathMatrix_RemoveColumn]  = [
	AscDFH.historyitem_MathMatrix_AddRow,
	AscDFH.historyitem_MathMatrix_RemoveRow,
	AscDFH.historyitem_MathMatrix_AddColumn,
	AscDFH.historyitem_MathMatrix_RemoveColumn
];
AscDFH.changesRelationMap[AscDFH.historyitem_MathMatrix_BaseJc]        = [AscDFH.historyitem_MathMatrix_BaseJc];
AscDFH.changesRelationMap[AscDFH.historyitem_MathMatrix_ColumnJc]      = [AscDFH.historyitem_MathMatrix_ColumnJc];
AscDFH.changesRelationMap[AscDFH.historyitem_MathMatrix_Interval]      = [AscDFH.historyitem_MathMatrix_Interval];
AscDFH.changesRelationMap[AscDFH.historyitem_MathMatrix_Plh]           = [AscDFH.historyitem_MathMatrix_Plh];
AscDFH.changesRelationMap[AscDFH.historyitem_MathDegree_SubSupType]    = [AscDFH.historyitem_MathDegree_SubSupType];
//----------------------------------------------------------------------------------------------------------------------


/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesMathContentAddItem(Class, Pos, Items)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, true);
}
CChangesMathContentAddItem.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesMathContentAddItem.prototype.constructor = CChangesMathContentAddItem;
CChangesMathContentAddItem.prototype.Type = AscDFH.historyitem_MathContent_AddItem;
CChangesMathContentAddItem.prototype.Undo = function()
{
	var oMathContent = this.Class;
	oMathContent.Content.splice(this.Pos, this.Items.length);
};
CChangesMathContentAddItem.prototype.Redo = function()
{
	var oMathContent = this.Class;

	var Array_start = oMathContent.Content.slice(0, this.Pos);
	var Array_end   = oMathContent.Content.slice(this.Pos);

	oMathContent.Content = Array_start.concat(this.Items, Array_end);

	for (var nIndex = 0; nIndex < this.Items.length; ++nIndex)
	{
		this.Items[nIndex].Set_ParaMath(oMathContent.ParaMath);

		if (this.Items[nIndex].SetParagraph)
			this.Items[nIndex].SetParagraph(oMathContent.Paragraph);

		this.Items[nIndex].Recalc_RunsCompiledPr();
	}
};
CChangesMathContentAddItem.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesMathContentAddItem.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesMathContentAddItem.prototype.Load = function(Color)
{
	var oMathContent = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var Pos     = oMathContent.m_oContentChanges.Check(AscCommon.contentchanges_Add, this.PosArray[nIndex]);
		var Element = this.Items[nIndex];

		if (null != Element)
		{
			oMathContent.Content.splice(Pos, 0, Element);

			if (Element.SetParagraph)
				Element.SetParagraph(oMathContent.Paragraph);

			if (Element.Set_ParaMath)
				Element.Set_ParaMath(oMathContent.ParaMath);

			Element.Recalc_RunsCompiledPr();
			AscCommon.CollaborativeEditing.Update_DocumentPositionsOnAdd(oMathContent, Pos);
		}
	}
};
CChangesMathContentAddItem.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_MathContent_AddItem === oChanges.Type || AscDFH.historyitem_MathContent_RemoveItem === oChanges.Type))
		return true;

	return false;
};
CChangesMathContentAddItem.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesMathContentRemoveItem);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesMathContentRemoveItem(Class, Pos, Items)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, false);
}
CChangesMathContentRemoveItem.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesMathContentRemoveItem.prototype.constructor = CChangesMathContentRemoveItem;
CChangesMathContentRemoveItem.prototype.Type = AscDFH.historyitem_MathContent_RemoveItem;
CChangesMathContentRemoveItem.prototype.Undo = function()
{
	var oMathContent = this.Class;

	var Array_start = oMathContent.Content.slice(0, this.Pos);
	var Array_end   = oMathContent.Content.slice(this.Pos);

	oMathContent.Content = Array_start.concat(this.Items, Array_end);

	for (var nIndex = 0; nIndex < this.Items.length; ++nIndex)
	{
		this.Items[nIndex].Set_ParaMath(oMathContent.ParaMath);

		if (this.Items[nIndex].SetParagraph)
			this.Items[nIndex].SetParagraph(oMathContent.Paragraph);

		this.Items[nIndex].Recalc_RunsCompiledPr();
	}
};
CChangesMathContentRemoveItem.prototype.Redo = function()
{
	var oMathContent = this.Class;
	oMathContent.Content.splice(this.Pos, this.Items.length);
};
CChangesMathContentRemoveItem.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesMathContentRemoveItem.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesMathContentRemoveItem.prototype.Load = function(Color)
{
	var oMathContent = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var ChangesPos = oMathContent.m_oContentChanges.Check(AscCommon.contentchanges_Remove, this.PosArray[nIndex]);

		if (false === ChangesPos)
			continue;

		oMathContent.Content.splice(ChangesPos, 1);
		AscCommon.CollaborativeEditing.Update_DocumentPositionsOnRemove(oMathContent, ChangesPos, 1);
	}
};
CChangesMathContentRemoveItem.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_MathContent_AddItem === oChanges.Type || AscDFH.historyitem_MathContent_RemoveItem === oChanges.Type))
		return true;

	return false;
};
CChangesMathContentRemoveItem.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesMathContentAddItem);
};
/**
 * Изменение настроек ArgSize в классе CMathContent
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesMathContentArgSize(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesMathContentArgSize.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesMathContentArgSize.prototype.constructor = CChangesMathContentArgSize;
CChangesMathContentArgSize.prototype.Type = AscDFH.historyitem_MathContent_ArgSize;
CChangesMathContentArgSize.prototype.private_SetValue = function(Value)
{
	var oMathContent = this.Class;
	oMathContent.ArgSize.SetValue(Value);
	oMathContent.Recalc_RunsCompiledPr();
};

/**
 * Изменение прилегания всей формулы (ParaMath)
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesMathParaJc(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesMathParaJc.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesMathParaJc.prototype.constructor = CChangesMathParaJc;
CChangesMathParaJc.prototype.Type = AscDFH.historyitem_MathPara_Jc;
CChangesMathParaJc.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetAlign(Value);
};


/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesMathBaseAddItems(Class, Pos, Items)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, true);
}
CChangesMathBaseAddItems.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesMathBaseAddItems.prototype.constructor = CChangesMathBaseAddItems;
CChangesMathBaseAddItems.prototype.Type = AscDFH.historyitem_MathBase_AddItems;
CChangesMathBaseAddItems.prototype.Undo = function()
{
	this.Class.raw_RemoveFromContent(this.Pos, this.Items.length);
};
CChangesMathBaseAddItems.prototype.Redo = function()
{
	this.Class.raw_AddToContent(this.Pos, this.Items, false);
};
CChangesMathBaseAddItems.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesMathBaseAddItems.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesMathBaseAddItems.prototype.Load = function(Color)
{
	var oMathBase = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var Pos     = oMathBase.m_oContentChanges.Check(AscCommon.contentchanges_Add, this.PosArray[nIndex]);
		var Element = this.Items[nIndex];

		if (null !== Element)
		{
			oMathBase.Content.splice(Pos, 0, Element);

			if (Element.Set_ParaMath)
				Element.Set_ParaMath(oMathBase.ParaMath);

			if (Element.SetParagraph)
				Element.SetParagraph(oMathBase.Paragraph);

			Element.ParentElement = oMathBase;
			AscCommon.CollaborativeEditing.Update_DocumentPositionsOnAdd(oMathBase, Pos);
		}
	}

	oMathBase.fillContent();
};
CChangesMathBaseAddItems.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_MathBase_AddItems === oChanges.Type || AscDFH.historyitem_MathBase_RemoveItems === oChanges.Type))
		return true;

	return false;
};
CChangesMathBaseAddItems.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesMathBaseRemoveItems);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesMathBaseRemoveItems(Class, Pos, Items)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, false);
}
CChangesMathBaseRemoveItems.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesMathBaseRemoveItems.prototype.constructor = CChangesMathBaseRemoveItems;
CChangesMathBaseRemoveItems.prototype.Type = AscDFH.historyitem_MathBase_RemoveItems;
CChangesMathBaseRemoveItems.prototype.Undo = function()
{
	this.Class.raw_AddToContent(this.Pos, this.Items, false);
};
CChangesMathBaseRemoveItems.prototype.Redo = function()
{
	this.Class.raw_RemoveFromContent(this.Pos, this.Items.length);
};
CChangesMathBaseRemoveItems.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesMathBaseRemoveItems.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesMathBaseRemoveItems.prototype.Load = function()
{
	var oMathBase = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var ChangesPos = oMathBase.m_oContentChanges.Check(AscCommon.contentchanges_Remove, this.PosArray[nIndex]);
		if (false === ChangesPos)
			continue;

		oMathBase.Content.splice(ChangesPos, 1);
		AscCommon.CollaborativeEditing.Update_DocumentPositionsOnRemove(oMathBase, ChangesPos, 1);
	}
	oMathBase.fillContent();
};
CChangesMathBaseRemoveItems.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_MathBase_AddItems === oChanges.Type || AscDFH.historyitem_MathBase_RemoveItems === oChanges.Type))
		return true;

	return false;
};
CChangesMathBaseRemoveItems.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesMathBaseAddItems);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesMathBaseFontSize(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesMathBaseFontSize.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesMathBaseFontSize.prototype.constructor = CChangesMathBaseFontSize;
CChangesMathBaseFontSize.prototype.Type = AscDFH.historyitem_MathBase_FontSize;
CChangesMathBaseFontSize.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetFontSize(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesMathBaseShd(Class, Old, New)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New);
}
CChangesMathBaseShd.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesMathBaseShd.prototype.constructor = CChangesMathBaseShd;
CChangesMathBaseShd.prototype.Type = AscDFH.historyitem_MathBase_Shd;
CChangesMathBaseShd.prototype.private_CreateObject = function()
{
	return new CDocumentShd();
};
CChangesMathBaseShd.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetShd(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesMathBaseColor(Class, Old, New)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New);
}
CChangesMathBaseColor.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesMathBaseColor.prototype.constructor = CChangesMathBaseColor;
CChangesMathBaseColor.prototype.Type = AscDFH.historyitem_MathBase_Color;
CChangesMathBaseColor.prototype.private_CreateObject = function()
{
	return new CDocumentColor(0, 0, 0, false);
};
CChangesMathBaseColor.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetColor(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesMathBaseUnifill(Class, Old, New)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New);
}
CChangesMathBaseUnifill.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesMathBaseUnifill.prototype.constructor = CChangesMathBaseUnifill;
CChangesMathBaseUnifill.prototype.Type = AscDFH.historyitem_MathBase_Unifill;
CChangesMathBaseUnifill.prototype.private_CreateObject = function()
{
	return new AscFormat.CUniFill();
};
CChangesMathBaseUnifill.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetUnifill(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathBaseUnderline(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathBaseUnderline.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathBaseUnderline.prototype.constructor = CChangesMathBaseUnderline;
CChangesMathBaseUnderline.prototype.Type = AscDFH.historyitem_MathBase_Underline;
CChangesMathBaseUnderline.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetUnderline(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathBaseStrikeout(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathBaseStrikeout.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathBaseStrikeout.prototype.constructor = CChangesMathBaseStrikeout;
CChangesMathBaseStrikeout.prototype.Type = AscDFH.historyitem_MathBase_Strikeout;
CChangesMathBaseStrikeout.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetStrikeout(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathBaseDoubleStrikeout(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathBaseDoubleStrikeout.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathBaseDoubleStrikeout.prototype.constructor = CChangesMathBaseDoubleStrikeout;
CChangesMathBaseDoubleStrikeout.prototype.Type = AscDFH.historyitem_MathBase_DoubleStrikeout;
CChangesMathBaseDoubleStrikeout.prototype.private_SetValue = function(Value)
{
	this.Class.raw_Set_DoubleStrikeout(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathBaseItalic(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathBaseItalic.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathBaseItalic.prototype.constructor = CChangesMathBaseItalic;
CChangesMathBaseItalic.prototype.Type = AscDFH.historyitem_MathBase_Italic;
CChangesMathBaseItalic.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetItalic(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathBaseBold(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathBaseBold.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathBaseBold.prototype.constructor = CChangesMathBaseBold;
CChangesMathBaseBold.prototype.Type = AscDFH.historyitem_MathBase_Bold;
CChangesMathBaseBold.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetBold(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesMathBaseRFontsAscii(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesMathBaseRFontsAscii.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesMathBaseRFontsAscii.prototype.constructor = CChangesMathBaseRFontsAscii;
CChangesMathBaseRFontsAscii.prototype.Type = AscDFH.historyitem_MathBase_RFontsAscii;
CChangesMathBaseRFontsAscii.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetRFontsAscii(Value);
};
CChangesMathBaseRFontsAscii.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = 0;

	if (false !== this.Color)
		nFlags |= 1;

	if (undefined === this.New)
		nFlags |= 2;

	if (undefined === this.Old)
		nFlags |= 4;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New)
		Writer.WriteString2(this.New.Name);

	if (undefined !== this.Old)
		Writer.WriteString2(this.Old.Name);
};
CChangesMathBaseRFontsAscii.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is undefined Old ?
	// String : New
	// String : Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.Color = true;
	else
		this.Color = false;

	if (nFlags & 2)
	{
		this.New = undefined;
	}
	else
	{
		this.New = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}

	if (nFlags & 4)
	{
		this.Old = undefined;
	}
	else
	{
		this.Old = {
			Name  : Reader.GetString2(),
			Index : -1
		};
	}
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesMathBaseRFontsHAnsi(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesMathBaseRFontsHAnsi.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesMathBaseRFontsHAnsi.prototype.constructor = CChangesMathBaseRFontsHAnsi;
CChangesMathBaseRFontsHAnsi.prototype.Type = AscDFH.historyitem_MathBase_RFontsHAnsi;
CChangesMathBaseRFontsHAnsi.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetRFontsHAnsi(Value);
};
CChangesMathBaseRFontsHAnsi.prototype.WriteToBinary  = CChangesMathBaseRFontsAscii.prototype.WriteToBinary;
CChangesMathBaseRFontsHAnsi.prototype.ReadFromBinary = CChangesMathBaseRFontsAscii.prototype.ReadFromBinary;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesMathBaseRFontsCS(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesMathBaseRFontsCS.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesMathBaseRFontsCS.prototype.constructor = CChangesMathBaseRFontsCS;
CChangesMathBaseRFontsCS.prototype.Type = AscDFH.historyitem_MathBase_RFontsCS;
CChangesMathBaseRFontsCS.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetRFontsCS(Value);
};
CChangesMathBaseRFontsCS.prototype.WriteToBinary  = CChangesMathBaseRFontsAscii.prototype.WriteToBinary;
CChangesMathBaseRFontsCS.prototype.ReadFromBinary = CChangesMathBaseRFontsAscii.prototype.ReadFromBinary;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesMathBaseRFontsEastAsia(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesMathBaseRFontsEastAsia.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesMathBaseRFontsEastAsia.prototype.constructor = CChangesMathBaseRFontsEastAsia;
CChangesMathBaseRFontsEastAsia.prototype.Type = AscDFH.historyitem_MathBase_RFontsEastAsia;
CChangesMathBaseRFontsEastAsia.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetRFontsEastAsia(Value);
};
CChangesMathBaseRFontsEastAsia.prototype.WriteToBinary  = CChangesMathBaseRFontsAscii.prototype.WriteToBinary;
CChangesMathBaseRFontsEastAsia.prototype.ReadFromBinary = CChangesMathBaseRFontsAscii.prototype.ReadFromBinary;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesMathBaseRFontsHint(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesMathBaseRFontsHint.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesMathBaseRFontsHint.prototype.constructor = CChangesMathBaseRFontsHint;
CChangesMathBaseRFontsHint.prototype.Type = AscDFH.historyitem_MathBase_RFontsHint;
CChangesMathBaseRFontsHint.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetRFontsHint(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesMathBaseHighLight(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesMathBaseHighLight.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesMathBaseHighLight.prototype.constructor = CChangesMathBaseHighLight;
CChangesMathBaseHighLight.prototype.Type = AscDFH.historyitem_MathBase_HighLight;
CChangesMathBaseHighLight.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetHighLight(Value);
};
CChangesMathBaseHighLight.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is "none" New ?
	// 4-bit : Is undefined New ?
	// 5-bit : Is "none" New ?
	// Variable(?CDocumentColor) : New (если 2 и 3 биты нулевые)
	// Variable(?CDocumentColor) : Old (если 4 и 5 биты нулевые)

	var nFlags = 0;

	if (false !== this.Color)
		nFlags |= 1;

	if (undefined === this.New)
		nFlags |= 2;
	else if (highlight_None === this.New)
		nFlags |= 4;

	if (undefined === this.Old)
		nFlags |= 8;
	else if (highlight_None === this.Old)
		nFlags |= 16;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New && highlight_None !== this.New)
		this.New.Write_ToBinary(Writer);

	if (undefined !== this.Old && highlight_None !== this.Old)
		this.Old.Write_ToBinary(Writer);
};
CChangesMathBaseHighLight.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : Is undefined New ?
	// 3-bit : Is "none" New ?
	// 4-bit : Is undefined New ?
	// 5-bit : Is "none" New ?
	// Variable(?CDocumentColor) : New (если 2 и 3 биты нулевые)
	// Variable(?CDocumentColor) : Old (если 4 и 5 биты нулевые)

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.Color = true;
	else
		this.Color = false;

	if (nFlags & 2)
	{
		this.New = undefined;
	}
	else if (nFlags & 4)
	{
		this.New = highlight_None;
	}
	else
	{
		this.New = new CDocumentColor(0, 0, 0);
		this.New.Read_FromBinary(Reader);
	}

	if (nFlags & 8)
	{
		this.Old = undefined;
	}
	else if (nFlags & 16)
	{
		this.Old = highlight_None;
	}
	else
	{
		this.Old = new CDocumentColor(0, 0, 0);
		this.Old.Read_FromBinary(Reader);
	}
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesMathBaseReviewType(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesMathBaseReviewType.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesMathBaseReviewType.prototype.constructor = CChangesMathBaseReviewType;
CChangesMathBaseReviewType.prototype.Type = AscDFH.historyitem_MathBase_ReviewType;
CChangesMathBaseReviewType.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetReviewType(Value.Type, Value.Info);
};
CChangesMathBaseReviewType.prototype.WriteToBinary = function(Writer)
{
	// Long : Flags
	// 1-bit : New.Info is undefined?
	// 2-bit : Old.Info is undefined?
	// Long : New.Type
	// CReviewInfo: New.Info (1-bit is zero)
	// Long : Old.Type
	// CReviewInfo: Old.Info (1-bit is zero)

	var nFlags = 0;
	if (undefined === this.New.Info)
		nFlags |= 1;
	if (undefined === this.Old.Info)
		nFlags |= 2;

	Writer.WriteLong(nFlags);
	Writer.WriteLong(this.New.Type);
	if (undefined !== this.New.Info)
		this.New.Info.Write_ToBinary(Writer);
	Writer.WriteLong(this.Old.Type);
	if (undefined !== this.Old.Info)
		this.Old.Info.Write_ToBinary(Writer);
};
CChangesMathBaseReviewType.prototype.ReadFromBinary = function(Reader)
{
	// Long : Flags
	// 1-bit : New.Info is undefined?
	// 2-bit : Old.Info is undefined?
	// Long : New.Type
	// CReviewInfo: New.Info (1-bit is zero)
	// Long : Old.Type
	// CReviewInfo: Old.Info (1-bit is zero)

	var nFlags = Reader.GetLong();

	this.New = {
		Type : Reader.GetLong(),
		Info : undefined
	};

	if (!(nFlags & 1))
	{
		this.New.Info = new CReviewInfo();
		this.New.Info.Read_FromBinary(Reader);
	}

	this.Old = {
		Type : Reader.GetLong(),
		Info : undefined
	};

	if (!(nFlags & 2))
	{
		this.Old.Info = new CReviewInfo();
		this.Old.Info.Read_FromBinary(Reader);
	}
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesMathBaseTextFill(Class, Old, New)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New);
}
CChangesMathBaseTextFill.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesMathBaseTextFill.prototype.constructor = CChangesMathBaseTextFill;
CChangesMathBaseTextFill.prototype.Type = AscDFH.historyitem_MathBase_TextFill;
CChangesMathBaseTextFill.prototype.private_CreateObject = function()
{
	return new AscFormat.CUniFill();
};
CChangesMathBaseTextFill.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetTextFill(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesMathBaseTextOutline(Class, Old, New)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New);
}
CChangesMathBaseTextOutline.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesMathBaseTextOutline.prototype.constructor = CChangesMathBaseTextOutline;
CChangesMathBaseTextOutline.prototype.Type = AscDFH.historyitem_MathBase_TextOutline;
CChangesMathBaseTextOutline.prototype.private_CreateObject = function()
{
	return new AscFormat.CLn();
};
CChangesMathBaseTextOutline.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetTextOutline(Value);
};


/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesMathBoxAlnAt(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesMathBoxAlnAt.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesMathBoxAlnAt.prototype.constructor = CChangesMathBoxAlnAt;
CChangesMathBoxAlnAt.prototype.Type = AscDFH.historyitem_MathBox_AlnAt;
CChangesMathBoxAlnAt.prototype.private_SetValue = function(Value)
{
	this.Class.raw_setAlnAt(Value);
};
CChangesMathBoxAlnAt.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type || AscDFH.historyitem_MathBox_ForcedBreak === oChange.Type)
		return false;

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathBoxForcedBreak(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathBoxForcedBreak.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathBoxForcedBreak.prototype.constructor = CChangesMathBoxForcedBreak;
CChangesMathBoxForcedBreak.prototype.Type = AscDFH.historyitem_MathBox_ForcedBreak;
CChangesMathBoxForcedBreak.prototype.private_SetValue = function(Value)
{
	this.Class.raw_ForcedBreak(Value, this.Class.Pr.Get_AlnAt());
};
CChangesMathBoxForcedBreak.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type)
		return false;

	return true;
};


/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesMathFractionType(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesMathFractionType.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesMathFractionType.prototype.constructor = CChangesMathFractionType;
CChangesMathFractionType.prototype.Type = AscDFH.historyitem_MathFraction_Type;
CChangesMathFractionType.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetFractionType(Value);
};


/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathRadicalHideDegree(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathRadicalHideDegree.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathRadicalHideDegree.prototype.constructor = CChangesMathRadicalHideDegree;
CChangesMathRadicalHideDegree.prototype.Type = AscDFH.historyitem_MathRadical_HideDegree;
CChangesMathRadicalHideDegree.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetHideDegree(Value);
};


/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesMathNaryLimLoc(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesMathNaryLimLoc.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesMathNaryLimLoc.prototype.constructor = CChangesMathNaryLimLoc;
CChangesMathNaryLimLoc.prototype.Type = AscDFH.historyitem_MathNary_LimLoc;
CChangesMathNaryLimLoc.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetLimLoc(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathNaryUpperLimit(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathNaryUpperLimit.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathNaryUpperLimit.prototype.constructor = CChangesMathNaryUpperLimit;
CChangesMathNaryUpperLimit.prototype.Type = AscDFH.historyitem_MathNary_UpperLimit;
CChangesMathNaryUpperLimit.prototype.private_SetValue = function(Value)
{
	this.Class.raw_HideUpperIterator(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathNaryLowerLimit(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathNaryLowerLimit.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathNaryLowerLimit.prototype.constructor = CChangesMathNaryLowerLimit;
CChangesMathNaryLowerLimit.prototype.Type = AscDFH.historyitem_MathNary_LowerLimit;
CChangesMathNaryLowerLimit.prototype.private_SetValue = function(Value)
{
	this.Class.raw_HideLowerIterator(Value);
};


/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesMathDelimBegOper(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesMathDelimBegOper.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesMathDelimBegOper.prototype.constructor = CChangesMathDelimBegOper;
CChangesMathDelimBegOper.prototype.Type = AscDFH.historyitem_MathDelimiter_BegOper;
CChangesMathDelimBegOper.prototype.private_SetValue = function(Value)
{
	this.Class.raw_HideBegOperator(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesMathDelimEndOper(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesMathDelimEndOper.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesMathDelimEndOper.prototype.constructor = CChangesMathDelimEndOper;
CChangesMathDelimEndOper.prototype.Type = AscDFH.historyitem_MathDelimiter_EndOper;
CChangesMathDelimEndOper.prototype.private_SetValue = function(Value)
{
	this.Class.raw_HideEndOperator(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathDelimiterGrow(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathDelimiterGrow.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathDelimiterGrow.prototype.constructor = CChangesMathDelimiterGrow;
CChangesMathDelimiterGrow.prototype.Type = AscDFH.historyitem_MathDelimiter_Grow;
CChangesMathDelimiterGrow.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetGrow(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesMathDelimiterShape(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesMathDelimiterShape.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesMathDelimiterShape.prototype.constructor = CChangesMathDelimiterShape;
CChangesMathDelimiterShape.prototype.Type = AscDFH.historyitem_MathDelimiter_Shape;
CChangesMathDelimiterShape.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetShape(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesMathDelimiterSetColumn(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesMathDelimiterSetColumn.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesMathDelimiterSetColumn.prototype.constructor = CChangesMathDelimiterSetColumn;
CChangesMathDelimiterSetColumn.prototype.Type = AscDFH.historyitem_MathDelimiter_SetColumn;
CChangesMathDelimiterSetColumn.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetColumn(Value);
};


/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesMathGroupCharPr(Class, Old, New)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New);
}
CChangesMathGroupCharPr.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesMathGroupCharPr.prototype.constructor = CChangesMathGroupCharPr;
CChangesMathGroupCharPr.prototype.Type = AscDFH.historyitem_MathGroupChar_Pr;
CChangesMathGroupCharPr.prototype.private_CreateObject = function()
{
	return new CMathGroupChrPr();
};
CChangesMathGroupCharPr.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetPr(Value);
};


/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesMathLimitType(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesMathLimitType.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesMathLimitType.prototype.constructor = CChangesMathLimitType;
CChangesMathLimitType.prototype.Type = AscDFH.historyitem_MathLimit_Type;
CChangesMathLimitType.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetType(Value);
};


/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathBorderBoxTop(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathBorderBoxTop.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathBorderBoxTop.prototype.constructor = CChangesMathBorderBoxTop;
CChangesMathBorderBoxTop.prototype.Type = AscDFH.historyitem_MathBorderBox_Top;
CChangesMathBorderBoxTop.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetTop(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathBorderBoxBot(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathBorderBoxBot.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathBorderBoxBot.prototype.constructor = CChangesMathBorderBoxBot;
CChangesMathBorderBoxBot.prototype.Type = AscDFH.historyitem_MathBorderBox_Bot;
CChangesMathBorderBoxBot.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetBot(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathBorderBoxLeft(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathBorderBoxLeft.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathBorderBoxLeft.prototype.constructor = CChangesMathBorderBoxLeft;
CChangesMathBorderBoxLeft.prototype.Type = AscDFH.historyitem_MathBorderBox_Left;
CChangesMathBorderBoxLeft.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetLeft(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathBorderBoxRight(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathBorderBoxRight.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathBorderBoxRight.prototype.constructor = CChangesMathBorderBoxRight;
CChangesMathBorderBoxRight.prototype.Type = AscDFH.historyitem_MathBorderBox_Right;
CChangesMathBorderBoxRight.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetRight(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathBorderBoxHor(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathBorderBoxHor.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathBorderBoxHor.prototype.constructor = CChangesMathBorderBoxHor;
CChangesMathBorderBoxHor.prototype.Type = AscDFH.historyitem_MathBorderBox_Hor;
CChangesMathBorderBoxHor.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetHor(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathBorderBoxVer(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathBorderBoxVer.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathBorderBoxVer.prototype.constructor = CChangesMathBorderBoxVer;
CChangesMathBorderBoxVer.prototype.Type = AscDFH.historyitem_MathBorderBox_Ver;
CChangesMathBorderBoxVer.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetVer(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathBorderBoxTopLTR(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathBorderBoxTopLTR.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathBorderBoxTopLTR.prototype.constructor = CChangesMathBorderBoxTopLTR;
CChangesMathBorderBoxTopLTR.prototype.Type = AscDFH.historyitem_MathBorderBox_TopLTR;
CChangesMathBorderBoxTopLTR.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetTopLTR(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathBorderBoxTopRTL(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathBorderBoxTopRTL.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathBorderBoxTopRTL.prototype.constructor = CChangesMathBorderBoxTopRTL;
CChangesMathBorderBoxTopRTL.prototype.Type = AscDFH.historyitem_MathBorderBox_TopRTL;
CChangesMathBorderBoxTopRTL.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetTopRTL(Value);
};


/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesMathBarLinePos(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesMathBarLinePos.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesMathBarLinePos.prototype.constructor = CChangesMathBarLinePos;
CChangesMathBarLinePos.prototype.Type = AscDFH.historyitem_MathBar_LinePos;
CChangesMathBarLinePos.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetLinePos(Value);
};


/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesMathMatrixAddRow(Class, Pos, Items)
{
	AscDFH.CChangesBase.call(this, Class);

	this.Pos    = Pos;
	this.Items  = Items;

	this.UseArray = false;
	this.PosArray = [];
}
CChangesMathMatrixAddRow.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesMathMatrixAddRow.prototype.constructor = CChangesMathMatrixAddRow;
CChangesMathMatrixAddRow.prototype.Type = AscDFH.historyitem_MathMatrix_AddRow;
CChangesMathMatrixAddRow.prototype.Undo = function()
{
	this.Class.raw_RemoveRow(this.Pos, this.Items.length);
};
CChangesMathMatrixAddRow.prototype.Redo = function()
{
	this.Class.raw_AddRow(this.Pos, this.Items);
};
CChangesMathMatrixAddRow.prototype.WriteToBinary = function(Writer)
{
	// Long     : Количество элементов
	// Array of :
	//  {
	//    Long     : Позиция
	//    Variable : Id элемента
	//  }

	var bArray = this.UseArray;
	var nCount = this.Items.length;

	Writer.WriteLong(nCount);
	for (var nIndex = 0; nIndex < nCount; ++nIndex)
	{
		if (true === bArray)
			Writer.WriteLong(this.PosArray[nIndex]);
		else
			Writer.WriteLong(this.Pos + nIndex);

		Writer.WriteString2(this.Items[nIndex].Get_Id());
	}
};
CChangesMathMatrixAddRow.prototype.ReadFromBinary = function(Reader)
{
	// Long     : Количество элементов
	// Array of :
	//  {
	//    Long     : Позиция
	//    Variable : Id Элемента
	//  }

	this.UseArray = true;
	this.Items    = [];
	this.PosArray = [];

	var nCount = Reader.GetLong();
	for (var nIndex = 0; nIndex < nCount; ++nIndex)
	{
		this.PosArray[nIndex] = Reader.GetLong();
		this.Items[nIndex]    = AscCommon.g_oTableId.Get_ById(Reader.GetString2());
	}
};
CChangesMathMatrixAddRow.prototype.CreateReverseChange = function()
{
	// TODO: Это изменение надо целиком переделать
	return new CChangesMathMatrixRemoveRow(this.Class, this.Pos, this.Items);
};
CChangesMathMatrixAddRow.prototype.Merge = function(oChange)
{
	// TODO: Это изменение надо целиком переделать
	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesMathMatrixRemoveRow(Class, Pos, Items)
{
	AscDFH.CChangesBase.call(this, Class);

	this.Pos    = Pos;
	this.Items  = Items;

	this.UseArray = false;
	this.PosArray = [];
}
CChangesMathMatrixRemoveRow.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesMathMatrixRemoveRow.prototype.constructor = CChangesMathMatrixRemoveRow;
CChangesMathMatrixRemoveRow.prototype.Type = AscDFH.historyitem_MathMatrix_RemoveRow;
CChangesMathMatrixRemoveRow.prototype.Undo = function()
{
	this.Class.raw_AddRow(this.Pos, this.Items);
};
CChangesMathMatrixRemoveRow.prototype.Redo = function()
{
	this.Class.raw_RemoveRow(this.Pos, this.Items.length);
};
CChangesMathMatrixRemoveRow.prototype.WriteToBinary = function(Writer)
{
	// Long          : Количество удаляемых элементов
	// Array of
	// {
	//    Long : позиции удаляемых элементов
	//    String : id удаляемых элементов
	// }

	var bArray = this.UseArray;
	var nCount = this.Items.length;

	var nStartPos = Writer.GetCurPosition();
	Writer.Skip(4);
	var nRealCount = nCount;

	for (var nIndex = 0; nIndex < nCount; ++nIndex)
	{
		if (true === bArray)
		{
			if (false === this.PosArray[nIndex])
			{
				nRealCount--;
			}
			else
			{
				Writer.WriteLong(this.PosArray[nIndex]);
				Writer.WriteString2(this.Items[nIndex]);
			}
		}
		else
		{
			Writer.WriteLong(this.Pos);
			Writer.WriteString2(this.Items[nIndex]);
		}
	}

	var nEndPos = Writer.GetCurPosition();
	Writer.Seek(nStartPos);
	Writer.WriteLong(nRealCount);
	Writer.Seek(nEndPos);
};
CChangesMathMatrixRemoveRow.prototype.ReadFromBinary = function(Reader)
{
	// Long          : Количество удаляемых элементов
	// Array of
	// {
	//    Long : позиции удаляемых элементов
	//    String : id удаляемых элементов
	// }

	this.UseArray = true;
	this.Items    = [];
	this.PosArray = [];

	var nCount = Reader.GetLong();
	for (var nIndex = 0; nIndex < nCount; ++nIndex)
	{
		this.PosArray[nIndex] = Reader.GetLong();
		this.Items[nIndex]    = AscCommon.g_oTableId.Get_ById(Reader.GetString2());
	}
};
CChangesMathMatrixRemoveRow.prototype.CreateReverseChange = function()
{
	// TODO: Это изменение надо целиком переделать
	return new CChangesMathMatrixAddRow(this.Class, this.Pos, this.Items);
};
CChangesMathMatrixRemoveRow.prototype.Merge = function(oChange)
{
	// TODO: Это изменение надо целиком переделать
	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesMathMatrixAddColumn(Class, Pos, Items)
{
	AscDFH.CChangesBase.call(this, Class);

	this.Pos    = Pos;
	this.Items  = Items;

	this.UseArray = false;
	this.PosArray = [];
}
CChangesMathMatrixAddColumn.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesMathMatrixAddColumn.prototype.constructor = CChangesMathMatrixAddColumn;
CChangesMathMatrixAddColumn.prototype.Type = AscDFH.historyitem_MathMatrix_AddColumn;
CChangesMathMatrixAddColumn.prototype.Undo = function()
{
	this.Class.raw_RemoveColumn(this.Pos, this.Items.length);
};
CChangesMathMatrixAddColumn.prototype.Redo = function()
{
	this.Class.raw_AddColumn(this.Pos, this.Items);
};
CChangesMathMatrixAddColumn.prototype.WriteToBinary  = CChangesMathMatrixAddRow.prototype.WriteToBinary;
CChangesMathMatrixAddColumn.prototype.ReadFromBinary = CChangesMathMatrixAddRow.prototype.ReadFromBinary;
CChangesMathMatrixAddColumn.prototype.CreateReverseChange = function()
{
	// TODO: Это изменение надо целиком переделать
	return new CChangesMathMatrixRemoveColumn(this.Class, this.Pos, this.Items);
};
CChangesMathMatrixAddColumn.prototype.Merge = function(oChange)
{
	// TODO: Это изменение надо целиком переделать
	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesMathMatrixRemoveColumn(Class, Pos, Items)
{
	AscDFH.CChangesBase.call(this, Class);

	this.Pos    = Pos;
	this.Items  = Items;

	this.UseArray = false;
	this.PosArray = [];
}
CChangesMathMatrixRemoveColumn.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesMathMatrixRemoveColumn.prototype.constructor = CChangesMathMatrixRemoveColumn;
CChangesMathMatrixRemoveColumn.prototype.Type = AscDFH.historyitem_MathMatrix_RemoveColumn;
CChangesMathMatrixRemoveColumn.prototype.Undo = function()
{
	this.Class.raw_AddColumn(this.Pos, this.Items);
};
CChangesMathMatrixRemoveColumn.prototype.Redo = function()
{
	this.Class.raw_RemoveColumn(this.Pos, this.Items.length);
};
CChangesMathMatrixRemoveColumn.prototype.WriteToBinary  = CChangesMathMatrixRemoveRow.prototype.WriteToBinary;
CChangesMathMatrixRemoveColumn.prototype.ReadFromBinary = CChangesMathMatrixRemoveRow.prototype.ReadFromBinary;
CChangesMathMatrixRemoveColumn.prototype.CreateReverseChange = function()
{
	// TODO: Это изменение надо целиком переделать
	return new CChangesMathMatrixAddColumn(this.Class, this.Pos, this.Items);
};
CChangesMathMatrixRemoveColumn.prototype.Merge = function(oChange)
{
	// TODO: Это изменение надо целиком переделать
	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesMathMatrixBaseJc(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesMathMatrixBaseJc.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesMathMatrixBaseJc.prototype.constructor = CChangesMathMatrixBaseJc;
CChangesMathMatrixBaseJc.prototype.Type = AscDFH.historyitem_MathMatrix_BaseJc;
CChangesMathMatrixBaseJc.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetBaseJc(Value);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesMathMatrixColumnJc(Class, Old, New, ColumnIndex)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);

	this.ColumnIndex = ColumnIndex;
}
CChangesMathMatrixColumnJc.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesMathMatrixColumnJc.prototype.constructor = CChangesMathMatrixColumnJc;
CChangesMathMatrixColumnJc.prototype.Type = AscDFH.historyitem_MathMatrix_ColumnJc;
CChangesMathMatrixColumnJc.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetColumnJc(Value, this.ColumnIndex);
};
CChangesMathMatrixColumnJc.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : IsUndefined New
	// 3-bit : IsUndefined Old
	// long : New
	// long : Old
	// long : ColumnIndex

	var nFlags = 0;

	if (false !== this.Color)
		nFlags |= 1;

	if (undefined === this.New)
		nFlags |= 2;

	if (undefined === this.Old)
		nFlags |= 4;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New)
		Writer.WriteLong(this.New);

	if (undefined !== this.Old)
		Writer.WriteLong(this.Old);

	Writer.WriteLong(this.ColumnIndex);
};
CChangesMathMatrixColumnJc.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Подсвечивать ли данные изменения
	// 2-bit : IsUndefined New
	// 3-bit : IsUndefined Old
	// long : New
	// long : Old
	// long : ColumnIndex

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.Color = true;
	else
		this.Color = false;

	if (nFlags & 2)
		this.New = undefined;
	else
		this.New = Reader.GetLong();

	if (nFlags & 4)
		this.Old = undefined;
	else
		this.Old = Reader.GetLong();

	this.ColumnIndex = Reader.GetLong();
};
CChangesMathMatrixColumnJc.prototype.CreateReverseChange = function()
{
	return new CChangesMathMatrixColumnJc(this.Class, this.New, this.Old, this.ColumnIndex);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesMathMatrixInterval(Class, ItemType, OldRule, OldGap, NewRule, NewGap)
{
	AscDFH.CChangesBaseProperty.call(this, Class, {Rule : OldRule, Gap : OldGap}, {Rule : NewRule, Gap : NewGap});

	this.ItemType = ItemType;
}
CChangesMathMatrixInterval.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesMathMatrixInterval.prototype.constructor = CChangesMathMatrixInterval;
CChangesMathMatrixInterval.prototype.Type = AscDFH.historyitem_MathMatrix_Interval;
CChangesMathMatrixInterval.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetInterval(this.ItemType, Value.Rule, Value.Gap);
};
CChangesMathMatrixInterval.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Is undefined New.Rule?
	// 2-bit : Is undefined New.Gap?
	// 3-bit : Is undefined Old.Rule?
	// 4-bit : Is undefined Old.Gap?
	// long : ItemType
	// long : New.Rule (1bit is zero)
	// long : New.Gap (2bit is zero)
	// long : Old.Rule (3bit is zero)
	// long : Old.Gap (4bit is zero)

	var nFlags = 0;

	if (undefined !== this.New.Rule)
		nFlags |= 1;
	if (undefined !== this.New.Gap)
		nFlags |= 2;
	if (undefined !== this.Old.Rule)
		nFlags |= 4;
	if (undefined !== this.Old.Gap)
		nFlags |= 8;

	Writer.WriteLong(nFlags);
	Writer.WriteLong(this.ItemType);

	if (undefined !== this.New.Rule)
		Writer.WriteLong(this.New.Rule);
	if (undefined !== this.New.Gap)
		Writer.WriteLong(this.New.Gap);

	if (undefined !== this.Old.Rule)
		Writer.WriteLong(this.Old.Rule);
	if (undefined !== this.Old.Gap)
		Writer.WriteLong(this.Old.Gap);
};
CChangesMathMatrixInterval.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Is undefined New.Rule?
	// 2-bit : Is undefined New.Gap?
	// 3-bit : Is undefined Old.Rule?
	// 4-bit : Is undefined Old.Gap?
	// long : ItemType
	// long : New.Rule (1bit is zero)
	// long : New.Gap (2bit is zero)
	// long : Old.Rule (3bit is zero)
	// long : Old.Gap (4bit is zero)

	this.New = {
		Rule : undefined,
		Gap  : undefined
	};

	this.Old = {
		Rule : undefined,
		Gap  : undefined
	};

	var nFlags = Reader.GetLong();
	this.ItemType = Reader.GetLong();

	if (!(nFlags & 1))
		this.New.Rule = Reader.GetLong();

	if (!(nFlags & 2))
		this.New.Gap = Reader.GetLong();

	if (!(nFlags & 4))
		this.Old.Rule = Reader.GetLong();

	if (!(nFlags & 8))
		this.Old.Gap = Reader.GetLong();
};
CChangesMathMatrixInterval.prototype.CreateReverseChange = function()
{
	return new CChangesMathMatrixInterval(this.Class, this.ItemType, this.New.Rule, this.New.Gap, this.Old.Rule, this.Old.Gap);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesMathMatrixPlh(Class, Old, New)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New);
}
CChangesMathMatrixPlh.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesMathMatrixPlh.prototype.constructor = CChangesMathMatrixPlh;
CChangesMathMatrixPlh.prototype.Type = AscDFH.historyitem_MathMatrix_Plh;
CChangesMathMatrixPlh.prototype.private_SetValue = function(Value)
{
	this.Class.raw_HidePlh(Value);
};


/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesMathDegreeSubSupType(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesMathDegreeSubSupType.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesMathDegreeSubSupType.prototype.constructor = CChangesMathDegreeSubSupType;
CChangesMathDegreeSubSupType.prototype.Type = AscDFH.historyitem_MathDegree_SubSupType;
CChangesMathDegreeSubSupType.prototype.private_SetValue = function(Value)
{
	this.Class.raw_SetType(Value);
};





/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// TODO: Надо избавиться от ParaEnd внутри ParaRun, а сам ParaEnd держать также как и ParaNumbering, как параметр
//       внутри самого класса Paragraph

// TODO: Избавиться от функций Internal_GetStartPos, Internal_GetEndPos, Clear_CollaborativeMarks

// Import
var c_oAscLineDrawingRule = AscCommon.c_oAscLineDrawingRule;
var align_Right = AscCommon.align_Right;
var align_Left = AscCommon.align_Left;
var align_Center = AscCommon.align_Center;
var g_oTableId = AscCommon.g_oTableId;
var g_oTextMeasurer = AscCommon.g_oTextMeasurer;
var History = AscCommon.History;

var linerule_Exact = Asc.linerule_Exact;
var c_oAscRelativeFromV = Asc.c_oAscRelativeFromV;

var type_Paragraph = 0x0001;

var UnknownValue  = null;

var REVIEW_COLOR = new AscCommon.CColor(255, 0, 0, 255);

/**
 * Класс Paragraph
 * @constructor
 * @extends {CDocumentContentElementBase}
 */
function Paragraph(DrawingDocument, Parent, bFromPresentation)
{
	CDocumentContentElementBase.call(this, Parent);

    this.CompiledPr =
    {
        Pr         : null,  // Скомпилированный (окончательный стиль параграфа)
        NeedRecalc : true   // Нужно ли пересчитать скомпилированный стиль
    };
    this.Pr = new CParaPr();

    // Рассчитанное положение рамки
    this.CalculatedFrame =
    {
        L : 0,       // Внутренний рект, по которому идет рассчет
        T : 0,
        W : 0,
        H : 0,
        L2 : 0,      // Внешний рект, с учетом границ
        T2 : 0,
        W2 : 0,
        H2 : 0,
        PageIndex : 0
    };

    // Данный TextPr будет относится только к символу конца параграфа
    this.TextPr = new ParaTextPr();
    this.TextPr.Parent = this;

    // Настройки секции
    this.SectPr = undefined; // undefined или CSectionPr

    this.Bounds = new CDocumentBounds(0, 0, 0, 0);

    this.RecalcInfo = new CParaRecalcInfo();

    this.Pages = []; // Массив страниц (CParaPage)
    this.Lines = []; // Массив строк (CParaLine)

    if(!(bFromPresentation === true))
    {
        this.Numbering = new ParaNumbering();
    }
    else
    {
        this.Numbering = new ParaPresentationNumbering();
    }
    this.ParaEnd   =
    {
        Line  : 0,
        Range : 0
    }; //new ParaEnd();
    
    this.CurPos  =
    {
        X           : 0,
        Y           : 0,
        ContentPos  : 0,  // Ближайшая позиция в контенте (между элементами)
        Line        : -1,
        Range       : -1,
        RealX       : 0, // позиция курсора, без учета расположения букв
        RealY       : 0, // это актуально для клавиш вверх и вниз
        PagesPos    : 0  // позиция в массиве this.Pages
    };

    this.Selection = new CParagraphSelection();
    
    this.DrawingDocument = null;
    this.LogicDocument   = null;
    this.bFromDocument   = true;
    
    if ( undefined !== DrawingDocument && null !== DrawingDocument )
    {
        this.DrawingDocument = DrawingDocument;
        this.LogicDocument   = this.DrawingDocument.m_oLogicDocument;
        this.bFromDocument   = bFromPresentation === true ? false : !!this.LogicDocument;
    }   
    else
    {
        this.bFromDocument = !(true === bFromPresentation);
    }
    this.ApplyToAll = false; // Специальный параметр, используемый в ячейках таблицы.
    // True, если ячейка попадает в выделение по ячейкам.

    this.Lock = new AscCommon.CLock(); // Зажат ли данный параграф другим пользователем
    // TODO: Когда у g_oIdCounter будет тоже проверка на TurnOff заменить здесь
    if (this.bFromDocument && false === AscCommon.g_oIdCounter.m_bLoad && true === History.Is_On())
    {
        this.Lock.Set_Type(AscCommon.locktype_Mine, false);
        if (AscCommon.CollaborativeEditing)
            AscCommon.CollaborativeEditing.Add_Unlock2(this);
    }

    this.DeleteCommentOnRemove    = true; // Удаляем ли комменты в функциях Internal_Content_Remove

    this.m_oContentChanges = new AscCommon.CContentChanges(); // список изменений(добавление/удаление элементов)

    // Свойства необходимые для презентаций
    this.PresentationPr =
    {
        Level  : 0,
        Bullet : new CPresentationBullet()
    };

    this.FontMap =
    {
        Map        : {},
        NeedRecalc : true
    };

    this.SearchResults = {};

    this.SpellChecker  = new CParaSpellChecker(this);

    this.NearPosArray  = [];

    // Добавляем в контент элемент "конец параграфа"
    this.Content = [];
    var EndRun = new ParaRun(this);
    EndRun.Add_ToContent( 0, new ParaEnd() );

    this.Content[0] = EndRun;

    this.m_oPRSW = new CParagraphRecalculateStateWrap(this);
    this.m_oPRSC = new CParagraphRecalculateStateCounter();
    this.m_oPRSA = new CParagraphRecalculateStateAlign();
    this.m_oPRSI = new CParagraphRecalculateStateInfo();
    
    this.m_oPDSE = new CParagraphDrawStateElements();
    this.StartState = null;

    this.CollPrChange = false;

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    g_oTableId.Add( this, this.Id );
    if(bFromPresentation === true)
    {
        this.Save_StartState();
    }
}

Paragraph.prototype = Object.create(CDocumentContentElementBase.prototype);
Paragraph.prototype.constructor = Paragraph;

Paragraph.prototype.GetType = function()
{
	return type_Paragraph;
};
Paragraph.prototype.Save_StartState = function()
{
	this.StartState = new CParagraphStartState(this);
};
Paragraph.prototype.Use_Wrap = function()
{
	if (true !== this.Is_Inline())
		return false;

	return true;
};
Paragraph.prototype.Use_YLimit = function()
{
	if (undefined != this.Get_FramePr() && this.Parent instanceof CDocument)
		return false;

	return true;
};
Paragraph.prototype.Set_Pr = function(oNewPr)
{
	return this.SetDirectParaPr(oNewPr);
};
/**
 * Устанавливаем прямые настройки параграфа целиком
 * @param oParaPr {CParaPr}
 */
Paragraph.prototype.SetDirectParaPr = function(oParaPr)
{
	History.Add(new CChangesParagraphPr(this, this.Pr, oParaPr));

	this.Pr = oParaPr;

	this.Recalc_CompiledPr();
	this.private_UpdateTrackRevisionOnChangeParaPr(true);
	this.UpdateDocumentOutline();
};
/**
 * Устанавливаем прямые настройки для текста
 * @param oTextPr {CTextPr}
 */
Paragraph.prototype.SetDirectTextPr = function(oTextPr)
{
	// TODO: Пока мы пробегаемся только по верхним элементам параграфа (без поиска в глубину), т.к. данная функция используется
	//       только для новых параграфов

	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		var oRun = this.Content[nIndex];
		if (oRun.Type === para_Run)
		{
			oRun.Set_Pr(oTextPr.Copy());

			// TODO: Передалать ParaEnd
			if (nIndex === nCount - 1)
			{
				this.TextPr.Set_Value(oTextPr.Copy());
			}
		}
	}
};
Paragraph.prototype.Copy = function(Parent, DrawingDocument, oPr)
{
	var Para = new Paragraph(DrawingDocument ? DrawingDocument : this.DrawingDocument, Parent, !this.bFromDocument);

	if (!oPr)
		oPr = {};

	oPr.Paragraph = Para;

	// Копируем настройки
	Para.Set_Pr(this.Pr.Copy());

	if (this.LogicDocument && null !== this.LogicDocument.CopyNumberingMap && undefined !== Para.Pr.NumPr && undefined !== Para.Pr.NumPr.NumId)
	{
		var NewId = this.LogicDocument.CopyNumberingMap[Para.Pr.NumPr.NumId];
		if (undefined !== NewId)
			Para.SetNumPr(NewId, Para.Pr.NumPr.Lvl);
	}

	Para.TextPr.Set_Value(this.TextPr.Value.Copy());

	// Удаляем содержимое нового параграфа
	Para.Internal_Content_Remove2(0, Para.Content.length);

	// Копируем содержимое параграфа
	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		var Item = this.Content[Index];

		if (para_Comment === Item.Type && true === oPr.SkipComments)
			continue;

		Para.Internal_Content_Add(Para.Content.length, Item.Copy(false, oPr), false);
	}

	// TODO: Как только переделаем para_End, переделать тут
	// Поскольку в ране не копируется элемент para_End добавим его здесь отдельно

	var EndRun = new ParaRun(Para);
	EndRun.Add_ToContent(0, new ParaEnd());
	Para.Internal_Content_Add(Para.Content.length, EndRun, false);
	EndRun.Set_Pr(this.TextPr.Value.Copy());

	// Добавляем секцию в конце
	if (undefined !== this.SectPr)
	{
		var SectPr = new CSectionPr(this.SectPr.LogicDocument);
		SectPr.Copy(this.SectPr);
		Para.Set_SectionPr(SectPr);
	}

	Para.RemoveSelection();
	Para.MoveCursorToStartPos(false);

	return Para;
};
Paragraph.prototype.Copy2 = function(Parent)
{
	var Para = new Paragraph(this.DrawingDocument, Parent, true);

	// Копируем настройки
	Para.Set_Pr(this.Pr.Copy());

	Para.TextPr.Set_Value(this.TextPr.Value.Copy());

	// Удаляем содержимое нового параграфа
	Para.Internal_Content_Remove2(0, Para.Content.length);

	// Копируем содержимое параграфа
	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		var Item = this.Content[Index];
		Para.Internal_Content_Add(Para.Content.length, Item.Copy2(), false);
	}


	Para.RemoveSelection();
	Para.MoveCursorToStartPos(false);

	return Para;
};
Paragraph.prototype.Get_FirstRunPr = function()
{
	if (this.Content.length <= 0 || para_Run !== this.Content[0].Type)
		return this.TextPr.Value.Copy();

	return this.Content[0].Pr.Copy();
};
Paragraph.prototype.Get_FirstTextPr = function()
{
	if (this.Content.length <= 0 || para_Run !== this.Content[0].Type)
		return this.Get_CompiledPr2(false).TextPr;

	return this.Content[0].Get_CompiledPr();
};
Paragraph.prototype.Get_FirstTextPr2 = function()
{
	var HyperlinkPr;
	for(var i = 0; i < this.Content.length; ++i)
	{
		if(!this.Content[i].Is_Empty())
		{
			if(para_Run === this.Content[i].Type)
			{
				return this.Content[i].Get_CompiledPr();
			}
			else if(para_Hyperlink === this.Content[i].Type)
			{
                HyperlinkPr =  this.Content[i].Get_FirstTextPr2();
                if(HyperlinkPr)
				{
					return HyperlinkPr;
				}
			}
			else if(para_Math === this.Content[i].Type)
			{
				return this.Content[i].GetFirstRPrp();
			}
		}
	}
    return this.Get_CompiledPr2(false).TextPr;
};
Paragraph.prototype.GetAllDrawingObjects = function(DrawingObjs)
{
	if (undefined === DrawingObjs)
		DrawingObjs = [];

	var Count = this.Content.length;
	for (var Pos = 0; Pos < Count; Pos++)
	{
		var Item = this.Content[Pos];
		if (Item.GetAllDrawingObjects)
			Item.GetAllDrawingObjects(DrawingObjs);
	}

	return DrawingObjs;
};
Paragraph.prototype.GetAllComments = function(List)
{
	if (undefined === List)
		List = [];

	var Len = this.Content.length;
	for (var Pos = 0; Pos < Len; Pos++)
	{
		var Item = this.Content[Pos];

		if (para_Comment === Item.Type)
			List.push({Comment : Item, Paragraph : this});
	}

	return List;
};
Paragraph.prototype.GetAllMaths = function(List)
{
	if (undefined === List)
		List = [];

	var Len = this.Content.length;
	for (var Pos = 0; Pos < Len; Pos++)
	{
		var Item = this.Content[Pos];
		if (para_Math === Item.Type)
			List.push({Math : Item, Paragraph : this});
	}

	return List;
};
Paragraph.prototype.GetAllParagraphs = function(Props, ParaArray)
{
	var ContentLen = this.Content.length;
	for (var CurPos = 0; CurPos < ContentLen; CurPos++)
	{
		if (this.Content[CurPos].GetAllParagraphs)
			this.Content[CurPos].GetAllParagraphs(Props, ParaArray);
	}

	if (true === Props.All)
	{
		ParaArray.push(this);
	}
	else if (true === Props.Numbering)
	{
		var oCurNumPr = this.GetNumPr();
		if (!oCurNumPr)
			return;

		if (Props.NumPr instanceof CNumPr)
		{
			var oNumPr = Props.NumPr;
			if (oCurNumPr.NumId === oNumPr.NumId && (oCurNumPr.Lvl === oNumPr.Lvl || undefined === oNumPr.Lvl || null === oNumPr.Lvl))
				ParaArray.push(this);
		}
		else if (Props.NumPr instanceof Array)
		{
			for (var nIndex = 0, nCount = Props.NumPr.length; nIndex < nCount; ++nIndex)
			{
				var oNumPr = Props.NumPr[nIndex];
				if (oCurNumPr.NumId === oNumPr.NumId && (oCurNumPr.Lvl === oNumPr.Lvl || undefined === oNumPr.Lvl || null === oNumPr.Lvl))
				{
					ParaArray.push(this);
					break;
				}
			}
		}
	}
	else if (true === Props.Style)
	{
		for (var nIndex = 0, nCount = Props.StylesId.length; nIndex < nCount; nIndex++)
		{
			var StyleId = Props.StylesId[nIndex];
			if (this.Pr.PStyle === StyleId)
			{
				ParaArray.push(this);
				break;
			}
		}
	}
	else if (true === Props.Selected)
	{
		if (true === this.Selection.Use)
			ParaArray.push(this);
	}
};
Paragraph.prototype.Get_PageBounds = function(CurPage)
{
	if (!this.Pages[CurPage])
		return new CDocumentBounds(0, 0, 0, 0);

	return this.Pages[CurPage].Bounds;
};
Paragraph.prototype.GetContentBounds = function(CurPage)
{
	var oPage = this.Pages[CurPage];
	if (!oPage || oPage.StartLine > oPage.EndLine)
		return this.Get_PageBounds(CurPage).Copy();

	var isJustify = (this.Get_CompiledPr2(false).ParaPr.Jc === AscCommon.align_Justify) && this.Lines.length > 1;

	var oBounds = null;
	for (var CurLine = oPage.StartLine; CurLine <= oPage.EndLine; ++CurLine)
	{
		var oLine = this.Lines[CurLine];

		var Top    = oLine.Top + oPage.Y;
		var Bottom = oLine.Bottom + oPage.Y;

		var Left = null, Right = null;

		for (var CurRange = 0, RangesCount = oLine.Ranges.length; CurRange < RangesCount; ++CurRange)
		{
			var oRange = oLine.Ranges[CurRange];
			if (null === Left || Left > oRange.XVisible)
				Left = oRange.XVisible;

			if (isJustify)
			{
				if (null === Right || Right < oRange.XEnd)
					Right = oRange.XEnd;
			}
			else
			{
				if (null === Right || Right < oRange.XVisible + oRange.W + oRange.WEnd + oRange.WBreak)
					Right = oRange.XVisible + oRange.W + oRange.WEnd + oRange.WBreak;
			}
		}


		if (!oBounds)
		{
			oBounds = new CDocumentBounds(Left, Top, Right, Bottom);
		}
		else
		{
			if (oBounds.Top > Top)
				oBounds.Top = Top;

			if (oBounds.Bottom < Bottom)
				oBounds.Bottom = Bottom;

			if (oBounds.Left > Left)
				oBounds.Left = Left;

			if (oBounds.Right < Right)
				oBounds.Right = Right;
		}
	}

	return oBounds;
};
Paragraph.prototype.Get_EmptyHeight = function()
{
	var Pr        = this.Get_CompiledPr();
	var EndTextPr = Pr.TextPr.Copy();
	EndTextPr.Merge(this.TextPr.Value);

	g_oTextMeasurer.SetTextPr(EndTextPr, this.Get_Theme());
	g_oTextMeasurer.SetFontSlot(fontslot_ASCII);

	return g_oTextMeasurer.GetHeight();
};
Paragraph.prototype.Get_Theme = function()
{
	if (this.Parent)
		return this.Parent.Get_Theme();

	return null;
};
Paragraph.prototype.Get_ColorMap = function()
{
	if (this.Parent)
		return this.Parent.Get_ColorMap();

	return null;
};
Paragraph.prototype.Reset = function(X, Y, XLimit, YLimit, PageNum, ColumnNum, ColumnsCount)
{
	this.X      = X;
	this.Y      = Y;
	this.XLimit = XLimit;
	this.YLimit = YLimit;

	var ColumnNumOld = this.ColumnNum;
	var PageNumOld   = this.PageNum;

	this.PageNum      = PageNum;
	this.ColumnNum    = ColumnNum ? ColumnNum : 0;
	this.ColumnsCount = ColumnsCount ? ColumnsCount : 1;

	// При первом пересчете параграфа this.Parent.RecalcInfo.Can_RecalcObject() всегда будет true, а вот при повторных
	// уже нет Кроме случая, когда параграф меняет свое местоположение на страницах и колонках
	if (true === this.Parent.RecalcInfo.Can_RecalcObject() || ColumnNumOld !== this.ColumnNum || PageNumOld !== this.PageNum)
	{
		// Эти значения нужны для правильного рассчета положения картинок, смотри баг #34392
		var Ranges = this.Parent.CheckRange(X, Y, XLimit, Y, Y, Y, X, XLimit, this.PageNum, true);
		if (Ranges.length > 0)
		{
			if (Math.abs(Ranges[0].X0 - X) < 0.001)
				this.X_ColumnStart = Ranges[0].X1;
			else
				this.X_ColumnStart = X;

			if (Math.abs(Ranges[Ranges.length - 1].X1 - XLimit) < 0.001)
				this.X_ColumnEnd = Ranges[Ranges.length - 1].X0;
			else
				this.X_ColumnEnd = XLimit;

			// Ситуация, когда из-за обтекания строчка съезжает вниз целиком
			if (this.X_ColumnStart > this.X_ColumnEnd)
			{
				this.X_ColumnStart = X;
				this.X_ColumnEnd   = XLimit;
			}
		}
		else
		{
			this.X_ColumnStart = X;
			this.X_ColumnEnd   = XLimit;
		}
	}
};
/**
 * Копируем свойства параграфа
 */
Paragraph.prototype.CopyPr = function(OtherParagraph)
{
	return this.CopyPr_Open(OtherParagraph);
};
/**
 * Копируем свойства параграфа при открытии и копировании
 */
Paragraph.prototype.CopyPr_Open = function(OtherParagraph)
{
	OtherParagraph.X      = this.X;
	OtherParagraph.XLimit = this.XLimit;

	if ("undefined" != typeof(OtherParagraph.NumPr))
		OtherParagraph.RemoveNumPr();

	var NumPr = this.GetNumPr();
	if (undefined != NumPr)
	{
		OtherParagraph.SetNumPr(NumPr.NumId, NumPr.Lvl);
	}
	// Копируем прямые настройки параграфа в конце, потому что, например, нумерация может
	// их изменить.
	var oOldPr        = OtherParagraph.Pr;
	OtherParagraph.Pr = this.Pr.Copy();
	History.Add(new CChangesParagraphPr(OtherParagraph, oOldPr, OtherParagraph.Pr));
	OtherParagraph.private_UpdateTrackRevisionOnChangeParaPr(true);

	if (this.bFromDocument)
		OtherParagraph.Style_Add(this.Style_Get(), true);

	// TODO: Другой параграф, как правило новый, поэтому можно использовать функцию Apply, но на самом деле надо
	//       переделать на нормальную функцию Set_Pr.
	OtherParagraph.TextPr.Apply_TextPr(this.TextPr.Value);
};
/**
 * Добавляем элемент в содержимое параграфа. (Здесь передвигаются все позиции
 * CurPos.ContentPos, Selection.StartPos, Selection.EndPos)
 */
Paragraph.prototype.Internal_Content_Add = function(Pos, Item, bCorrectPos)
{
	History.Add(new CChangesParagraphAddItem(this, Pos, [Item]));
	this.Content.splice(Pos, 0, Item);
	this.private_UpdateTrackRevisions();
	this.private_CheckUpdateBookmarks([Item]);
	this.UpdateDocumentOutline();

	if (this.CurPos.ContentPos >= Pos)
	{
		this.CurPos.ContentPos++;

		if (this.CurPos.ContentPos >= this.Content.length)
			this.CurPos.ContentPos = this.Content.length - 1;
	}

	if (this.Selection.StartPos >= Pos)
	{
		this.Selection.StartPos++;

		if (this.Selection.StartPos >= this.Content.length)
			this.Selection.StartPos = this.Content.length - 1;
	}

	if (this.Selection.EndPos >= Pos)
	{
		this.Selection.EndPos++;

		if (this.Selection.EndPos >= this.Content.length)
			this.Selection.EndPos = this.Content.length - 1;
	}

	// Обновляем позиции в NearestPos
	var NearPosLen = this.NearPosArray.length;
	for (var Index = 0; Index < NearPosLen; Index++)
	{
		var ParaNearPos    = this.NearPosArray[Index];
		var ParaContentPos = ParaNearPos.NearPos.ContentPos;

		if (ParaContentPos.Data[0] >= Pos)
			ParaContentPos.Data[0]++;
	}

	// Обновляем позиции в SearchResults
	for (var Id in this.SearchResults)
	{
		var ContentPos = this.SearchResults[Id].StartPos;

		if (ContentPos.Data[0] >= Pos)
			ContentPos.Data[0]++;

		ContentPos = this.SearchResults[Id].EndPos;

		if (ContentPos.Data[0] >= Pos)
			ContentPos.Data[0]++;
	}

	// Передвинем все метки слов для проверки орфографии
	// Обновляем позиции в SearchResults
	var SpellingsCount = this.SpellChecker.Elements.length;
	for (var Pos = 0; Pos < SpellingsCount; Pos++)
	{
		var Element    = this.SpellChecker.Elements[Pos];
		var ContentPos = Element.StartPos;

		if (ContentPos.Data[0] >= Pos)
			ContentPos.Data[0]++;

		ContentPos = Element.EndPos;

		if (ContentPos.Data[0] >= Pos)
			ContentPos.Data[0]++;
	}

	this.SpellChecker.Update_OnAdd(this, Pos, Item);

	Item.SetParagraph(this);
};
Paragraph.prototype.Add_ToContent = function(Pos, Item)
{
	this.Internal_Content_Add(Pos, Item);
};
Paragraph.prototype.AddToContent = function(nPos, oItem)
{
	this.Add_ToContent(nPos, oItem);
};
Paragraph.prototype.Remove_FromContent = function(Pos, Count)
{
	this.Internal_Content_Remove2(Pos, Count);
};
Paragraph.prototype.RemoveFromContent = function(nPos, nCount)
{
	return this.Internal_Content_Remove2(nPos, nCount);
};
/**
 * Добавляем несколько элементов в конец параграфа
 */
Paragraph.prototype.Internal_Content_Concat = function(Items)
{
	var StartPos = this.Content.length;
	this.Content = this.Content.concat(Items);

	History.Add(new CChangesParagraphAddItem(this, StartPos, Items));
	this.private_UpdateTrackRevisions();
	this.private_CheckUpdateBookmarks(Items);
	this.UpdateDocumentOutline();

	// Нам нужно сбросить рассчет всех добавленных элементов и выставить у них родительский класс и параграф
	for (var CurPos = StartPos; CurPos < this.Content.length; CurPos++)
	{
		this.Content[CurPos].SetParagraph(this);
		if (this.Content[CurPos].Recalc_RunsCompiledPr)
			this.Content[CurPos].Recalc_RunsCompiledPr();
	}

	// Обновлять позиции в NearestPos не надо, потому что мы добавляем новые элементы в конец массива
	this.RecalcInfo.Set_Type_0_Spell(pararecalc_0_Spell_All);
};
/**
 * Удаляем элемент из содержимого параграфа. (Здесь передвигаются все позиции
 * CurPos.ContentPos, Selection.StartPos, Selection.EndPos)
 */
Paragraph.prototype.Internal_Content_Remove = function(Pos)
{
	var Item = this.Content[Pos];
	History.Add(new CChangesParagraphRemoveItem(this, Pos, [Item]));
	this.Content.splice(Pos, 1);
	this.private_UpdateTrackRevisions();
	this.private_CheckUpdateBookmarks([Item]);
	this.UpdateDocumentOutline();

	if (Item.PreDelete)
		Item.PreDelete();

	if (this.Selection.StartPos > Pos)
	{
		this.Selection.StartPos--;

		if (this.Selection.StartPos < 0)
			this.Selection.StartPos = 0;
	}

	if (this.Selection.EndPos >= Pos)
	{
		this.Selection.EndPos--;

		if (this.Selection.EndPos < 0)
			this.Selection.EndPos = 0;
	}

	if (this.CurPos.ContentPos > Pos)
	{
		this.CurPos.ContentPos--;

		if (this.CurPos.ContentPos < 0)
			this.CurPos.ContentPos = 0;
	}

	// Обновляем позиции в NearestPos
	var NearPosLen = this.NearPosArray.length;
	for (var Index = 0; Index < NearPosLen; Index++)
	{
		var ParaNearPos    = this.NearPosArray[Index];
		var ParaContentPos = ParaNearPos.NearPos.ContentPos;

		if (ParaContentPos.Data[0] > Pos)
			ParaContentPos.Data[0]--;
	}

	// Обновляем позиции в SearchResults
	for (var Id in this.SearchResults)
	{
		var ContentPos = this.SearchResults[Id].StartPos;

		if (ContentPos.Data[0] > Pos)
			ContentPos.Data[0]--;

		ContentPos = this.SearchResults[Id].EndPos;

		if (ContentPos.Data[0] > Pos)
			ContentPos.Data[0]--;
	}

	// Удаляем комментарий, если это необходимо
	if (true === this.DeleteCommentOnRemove && para_Comment === Item.Type)
		this.LogicDocument.RemoveComment(Item.CommentId, true, false);

	var SpellingsCount = this.SpellChecker.Elements.length;
	for (var Pos = 0; Pos < SpellingsCount; Pos++)
	{
		var Element    = this.SpellChecker.Elements[Pos];
		var ContentPos = Element.StartPos;

		if (ContentPos.Data[0] > Pos)
			ContentPos.Data[0]--;

		ContentPos = Element.EndPos;

		if (ContentPos.Data[0] > Pos)
			ContentPos.Data[0]--;
	}

	// Передвинем все метки слов для проверки орфографии
	this.SpellChecker.Update_OnRemove(this, Pos, 1);
};
/**
 * Удаляем несколько элементов
 */
Paragraph.prototype.Internal_Content_Remove2 = function(Pos, Count)
{
	var CommentsToDelete = [];
	if (true === this.DeleteCommentOnRemove && null !== this.LogicDocument && null != this.LogicDocument.Comments)
	{
		var DocumentComments = this.LogicDocument.Comments;
		for (var Index = Pos; Index < Pos + Count; Index++)
		{
			var Item = this.Content[Index];
			if (para_Comment === Item.Type)
			{
				var CommentId = Item.CommentId;
				var Comment   = DocumentComments.Get_ById(CommentId);

				if (null != Comment)
				{
					if (true === Item.Start)
						Comment.Set_StartId(null);
					else
						Comment.Set_EndId(null);
				}

				CommentsToDelete.push(CommentId);
			}
		}
	}

	for (var nIndex = Pos; nIndex < Pos + Count; ++nIndex)
	{
		if (this.Content[nIndex].PreDelete)
			this.Content[nIndex].PreDelete();
	}

	var DeletedItems = this.Content.slice(Pos, Pos + Count);
	History.Add(new CChangesParagraphRemoveItem(this, Pos, DeletedItems));
	this.private_UpdateTrackRevisions();
	this.private_CheckUpdateBookmarks(DeletedItems);
	this.UpdateDocumentOutline();

	if (this.Selection.StartPos > Pos + Count)
		this.Selection.StartPos -= Count;
	else if (this.Selection.StartPos > Pos)
		this.Selection.StartPos = Pos;

	if (this.Selection.EndPos > Pos + Count)
		this.Selection.EndPos -= Count;
	if (this.Selection.EndPos > Pos)
		this.Selection.EndPos = Pos;

	if (this.CurPos.ContentPos > Pos + Count)
		this.CurPos.ContentPos -= Count;
	else if (this.CurPos.ContentPos > Pos)
		this.CurPos.ContentPos = Pos;

	// Обновляем позиции в NearestPos
	var NearPosLen = this.NearPosArray.length;
	for (var Index = 0; Index < NearPosLen; Index++)
	{
		var ParaNearPos    = this.NearPosArray[Index];
		var ParaContentPos = ParaNearPos.NearPos.ContentPos;

		if (ParaContentPos.Data[0] > Pos + Count)
			ParaContentPos.Data[0] -= Count;
		else if (ParaContentPos.Data[0] > Pos)
			ParaContentPos.Data[0] = Math.max(0, Pos);
	}

	this.Content.splice(Pos, Count);

	// Комментарии удаляем после, чтобы не нарушить позиции
	var CountCommentsToDelete = CommentsToDelete.length;
	for (var Index = 0; Index < CountCommentsToDelete; Index++)
	{
		this.LogicDocument.RemoveComment(CommentsToDelete[Index], true, false);
	}

	// Передвинем все метки слов для проверки орфографии
	this.SpellChecker.Update_OnRemove(this, Pos, Count);
};
Paragraph.prototype.Clear_ContentChanges = function()
{
	this.m_oContentChanges.Clear();
};
Paragraph.prototype.Add_ContentChanges = function(Changes)
{
	this.m_oContentChanges.Add(Changes);
};
Paragraph.prototype.Refresh_ContentChanges = function()
{
	this.m_oContentChanges.Refresh();
};
Paragraph.prototype.Get_CurrentParaPos = function()
{
	// Сначала определим строку и отрезок
	var ParaPos = this.Content[this.CurPos.ContentPos].Get_CurrentParaPos();

	if (-1 !== this.CurPos.Line)
	{
		ParaPos.Line  = this.CurPos.Line;
		ParaPos.Range = this.CurPos.Range;
	}

	ParaPos.Page = this.Get_PageByLine(ParaPos.Line);

	return ParaPos;
};
Paragraph.prototype.Get_PageByLine = function(LineIndex)
{
	for (var CurPage = this.Pages.length - 1; CurPage >= 0; CurPage--)
	{
		var Page = this.Pages[CurPage];
		if (LineIndex >= Page.StartLine && LineIndex <= Page.EndLine)
			return CurPage;
	}

	return 0;
};
Paragraph.prototype.Get_ParaPosByContentPos = function(ContentPos)
{
	// Сначала определим строку и отрезок
	var ParaPos = this.Content[ContentPos.Get(0)].Get_ParaPosByContentPos(ContentPos, 1);
	var CurLine = ParaPos.Line;

	// Определим страницу
	var PagesCount = this.Pages.length;
	for (var CurPage = PagesCount - 1; CurPage >= 0; CurPage--)
	{
		var Page = this.Pages[CurPage];
		if (CurLine >= Page.StartLine && CurLine <= Page.EndLine)
		{
			ParaPos.Page = CurPage;
			return ParaPos;
		}
	}

	return ParaPos;
};
Paragraph.prototype.Check_Range_OnlyMath = function(CurRange, CurLine)
{
	var StartPos = this.Lines[CurLine].Ranges[CurRange].StartPos;
	var EndPos   = this.Lines[CurLine].Ranges[CurRange].EndPos;
	var Checker  = new CParagraphMathRangeChecker();

	for (var Pos = StartPos; Pos <= EndPos; Pos++)
	{
		this.Content[Pos].Check_Range_OnlyMath(Checker, CurRange, CurLine);

		if (false === Checker.Result)
			break;
	}

	if (true !== Checker.Result || null === Checker.Math || true === Checker.Math.Get_Inline())
		return null;

	return Checker.Math;
};
Paragraph.prototype.Check_MathPara = function(MathPos)
{
	if (undefined === this.Content[MathPos] || para_Math !== this.Content[MathPos].Type)
		return false;

	var MathParaChecker = new CParagraphMathParaChecker();

	// Нам надо пробежаться впереди назад и найти ближайшие элементы.
	MathParaChecker.Direction = -1;
	for (var CurPos = MathPos - 1; CurPos >= 0; CurPos--)
	{
		if (this.Content[CurPos].Check_MathPara)
		{
			this.Content[CurPos].Check_MathPara(MathParaChecker);

			if (false !== MathParaChecker.Found)
				break;
		}
	}

	// Нумерация привязанная к формуле делает ее inline.
	if (true !== MathParaChecker.Found)
	{
		if(this.bFromDocument)
		{
            if(undefined !== this.GetNumPr())
			{
				return false;
			}
		}
		else
		{
			if(undefined !== this.Get_CompiledPr2(false).ParaPr.Bullet)
			{
				return false;
			}
		}
	}

	if (true !== MathParaChecker.Result)
		return false;

	MathParaChecker.Direction = 1;
	MathParaChecker.Found     = false;

	var Count = this.Content.length;
	for (var CurPos = MathPos + 1; CurPos < Count; CurPos++)
	{
		if (this.Content[CurPos].Check_MathPara)
		{
			this.Content[CurPos].Check_MathPara(MathParaChecker);

			if (false !== MathParaChecker.Found)
				break;
		}
	}

	if (true !== MathParaChecker.Result)
		return false;

	return true;
};
Paragraph.prototype.GetEndInfo = function()
{
	var PagesCount = this.Pages.length;

	if (PagesCount > 0)
		return this.Pages[PagesCount - 1].EndInfo.Copy();
	else
		return null;
};
Paragraph.prototype.GetEndInfoByPage = function(CurPage)
{
	// Здесь может приходить отрицательное значение
	if (CurPage < 0)
		return this.Parent.GetPrevElementEndInfo(this);
	else
		return this.Pages[CurPage].EndInfo.Copy();
};
Paragraph.prototype.Recalculate_PageEndInfo = function(PRSW, CurPage)
{
	var PrevInfo = ( 0 === CurPage ? this.Parent.GetPrevElementEndInfo(this) : this.Pages[CurPage - 1].EndInfo.Copy() );

	var PRSI = this.m_oPRSI;

	PRSI.Reset(PrevInfo);

	var StartLine  = this.Pages[CurPage].StartLine;
	var EndLine    = this.Pages[CurPage].EndLine;

	for (var CurLine = StartLine; CurLine <= EndLine; CurLine++)
	{
		var RangesCount = this.Lines[CurLine].Ranges.length;
		for (var CurRange = 0; CurRange < RangesCount; CurRange++)
		{
			var StartPos = this.Lines[CurLine].Ranges[CurRange].StartPos;
			var EndPos   = this.Lines[CurLine].Ranges[CurRange].EndPos;
			for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
			{
				this.Content[CurPos].Recalculate_PageEndInfo(PRSI, CurLine, CurRange);
			}
		}
	}

	this.Pages[CurPage].EndInfo.SetFromPRSI(PRSI);

	if (PRSW)
		this.Pages[CurPage].EndInfo.RunRecalcInfo = PRSW.RunRecalcInfoBreak;
};
Paragraph.prototype.UpdateEndInfo = function()
{
	for (var CurPage = 0, PagesCount = this.Pages.length; CurPage < PagesCount; CurPage++)
	{
		this.Recalculate_PageEndInfo(null, CurPage);
	}
};
Paragraph.prototype.Recalculate_Drawing_AddPageBreak = function(CurLine, CurPage, RemoveDrawings)
{
	if (true === RemoveDrawings)
	{
		// Мы должны из соответствующих FlowObjects удалить все Flow-объекты, идущие до этого места в параграфе
		for (var TempPage = 0; TempPage <= CurPage; TempPage++)
		{
			var DrawingsLen = this.Pages[TempPage].Drawings.length;
			for (var CurPos = 0; CurPos < DrawingsLen; CurPos++)
			{
				var Item = this.Pages[TempPage].Drawings[CurPos];
				this.Parent.DrawingObjects.removeById(Item.PageNum, Item.Get_Id());
			}

			this.Pages[TempPage].Drawings = [];
		}
	}

	this.Pages[CurPage].Set_EndLine(CurLine - 1);

	if (0 === CurLine)
		this.Lines[-1] = new CParaLine(0);
};
/**
 * Проверяем есть ли в параграфе встроенные PageBreak
 * @return {bool}
 */
Paragraph.prototype.Check_PageBreak = function()
{
	//TODO: возможно стоит данную проверку проводить во время добавления/удаления элементов из параграфа
	var Count = this.Content.length;
	for (var Pos = 0; Pos < Count; Pos++)
	{
		if (true === this.Content[Pos].Check_PageBreak())
			return true;
	}

	return false;
};
Paragraph.prototype.Check_BreakPageEnd = function(Item)
{
	// Последний параграф с разрывом страницы не проверяем. Так делает Word.
	if (this.Parent instanceof CDocument && null === this.Get_DocumentNext())
		return false;

	var PBChecker = new CParagraphCheckPageBreakEnd(Item);

	var ContentLen = this.Content.length;
	for (var CurPos = 0; CurPos < ContentLen; CurPos++)
	{
		var Element = this.Content[CurPos];

		if (true !== Element.Check_BreakPageEnd(PBChecker))
			return false;
	}

	return true;
};
/**
 * Пересчитываем заданную позицию элемента или текущую позицию курсора.
 */
Paragraph.prototype.Internal_Recalculate_CurPos = function(Pos, UpdateCurPos, UpdateTarget, ReturnTarget)
{
	var Transform = this.Get_ParentTextTransform();

	if (!this.IsRecalculated() || this.Lines.length <= 0)
	{
		return {
			X         : 0,
			Y         : 0,
			Height    : 0,
			PageNum   : 0,
			Internal  : {Line : 0, Page : 0, Range : 0},
			Transform : Transform
		};
	}

	var LinePos = this.Get_CurrentParaPos();

	if (-1 === LinePos.Line || LinePos.Line >= this.Lines.length)
	{
		return {
			X         : 0,
			Y         : 0,
			Height    : 0,
			PageNum   : 0,
			Internal  : {Line : 0, Page : 0, Range : 0},
			Transform : Transform
		};
	}

	var CurLine  = LinePos.Line;
	var CurRange = LinePos.Range;
	var CurPage  = LinePos.Page;

	// Если в текущей позиции явно указана строка
	if (-1 != this.CurPos.Line)
	{
		CurLine  = this.CurPos.Line;
		CurRange = this.CurPos.Range;
	}

	if (this.Lines[CurLine].Ranges.length <= 0)
	{
		return {
			X         : 0,
			Y         : 0,
			Height    : 0,
			PageNum   : 0,
			Internal  : {Line : 0, Page : 0, Range : 0},
			Transform : Transform
		};
	}

	var X = this.Lines[CurLine].Ranges[CurRange].XVisible;
	var Y = this.Pages[CurPage].Y + this.Lines[CurLine].Y;

	var StartPos = this.Lines[CurLine].Ranges[CurRange].StartPos;
	var EndPos   = this.Lines[CurLine].Ranges[CurRange].EndPos;

	if (true === this.Numbering.Check_Range(CurRange, CurLine))
		X += this.Numbering.WidthVisible;

	for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
	{
		var Item = this.Content[CurPos];
		var Res  = Item.Recalculate_CurPos(X, Y, (CurPos === this.CurPos.ContentPos ? true : false), CurRange, CurLine, CurPage, UpdateCurPos, UpdateTarget, ReturnTarget);

		if (CurPos === this.CurPos.ContentPos)
		{
			Res.Transform = Transform;
			return Res;
		}
		else
		{
			X = Res.X;
		}
	}

	return {
		X         : X,
		Y         : Y,
		PageNum   : this.Get_AbsolutePage(CurPage),
		Internal  : {Line : CurLine, Page : CurPage, Range : CurRange},
		Transform : Transform
	};
};
/**
 * Проверяем не пустые ли границы
 */
Paragraph.prototype.Internal_Is_NullBorders = function(Borders)
{
	if (border_None != Borders.Top.Value || border_None != Borders.Bottom.Value ||
		border_None != Borders.Left.Value || border_None != Borders.Right.Value ||
		border_None != Borders.Between.Value)
		return false;

	return true;
};
Paragraph.prototype.Internal_Check_Ranges = function(CurLine, CurRange)
{
	var Ranges      = this.Lines[CurLine].Ranges;
	var RangesCount = Ranges.length;

	if (RangesCount <= 1)
		return true;
	else if (2 === RangesCount)
	{
		var Range0 = Ranges[0];
		var Range1 = Ranges[1];

		if (Range0.XEnd - Range0.X < 0.001 && 1 === CurRange && Range1.XEnd - Range1.X >= 0.001)
			return true;
		else if (Range1.XEnd - Range1.X < 0.001 && 0 === CurRange && Range0.XEnd - Range0.X >= 0.001)
			return true;
		else
			return false
	}
	else if (3 === RangesCount && 1 === CurRange)
	{
		var Range0 = Ranges[0];
		var Range2 = Ranges[2];

		if (Range0.XEnd - Range0.X < 0.001 && Range2.XEnd - Range2.X < 0.001)
			return true;
		else
			return false;
	}
	else
		return false;
};
/**
 * Получаем текущие текстовые настройки нумерации
 * @returns {CTextPr}
 */
Paragraph.prototype.GetNumberingTextPr = function()
{
	var oNumPr = this.GetNumPr();
	if (!oNumPr)
		return new CTextPr();

	var oNumbering = this.Parent.GetNumbering();
	var oNum       = oNumbering.GetNum(oNumPr.NumId);
	if (!oNum)
		return new CTextPr();

	var oLvl = oNum.GetLvl(oNumPr.Lvl);

	var oNumTextPr = this.Get_CompiledPr2(false).TextPr.Copy();
	oNumTextPr.Merge(this.TextPr.Value);
	oNumTextPr.Merge(oLvl.GetTextPr());

	oNumTextPr.FontFamily.Name = oNumTextPr.RFonts.Ascii.Name;

	return oNumTextPr;
};
Paragraph.prototype.Is_EmptyRange = function(CurLine, CurRange)
{
	var Line  = this.Lines[CurLine];
	var Range = Line.Ranges[CurRange];

	var StartPos = Range.StartPos;
	var EndPos   = Range.EndPos;

	for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
	{
		if (false === this.Content[CurPos].Is_EmptyRange(CurLine, CurRange))
			return false;
	}

	return true;
};
Paragraph.prototype.Reset_RecalculateCache = function()
{

};
Paragraph.prototype.RecalculateCurPos = function(bUpdateX, bUpdateY)
{
	var oCurPosInfo = this.Internal_Recalculate_CurPos(this.CurPos.ContentPos, true, true, false);

	if (bUpdateX)
		this.CurPos.RealX = oCurPosInfo.X;

	if (bUpdateY)
		this.CurPos.RealY = oCurPosInfo.Y;

	return oCurPosInfo;
};
Paragraph.prototype.RecalculateMinMaxContentWidth = function(isRotated)
{
	var MinMax = new CParagraphMinMaxContentWidth();

	var Count = this.Content.length;
	for (var Pos = 0; Pos < Count; Pos++)
	{
		var Item = this.Content[Pos];

		Item.SetParagraph(this);
		Item.RecalculateMinMaxContentWidth(MinMax);
	}

	var ParaPr = this.Get_CompiledPr2(false).ParaPr;
	var MinInd = ParaPr.Ind.Left + ParaPr.Ind.Right + ParaPr.Ind.FirstLine;

	MinMax.nMinWidth += MinInd;
	MinMax.nMaxWidth += MinInd;

	if (true === isRotated)
	{
		ParaPr = this.Get_CompiledPr().ParaPr;

		// Последний пустой параграф не идет в учет
		if (null === this.Get_DocumentNext() && true === this.Is_Empty())
			return {Min : 0, Max : 0};


		var Min = MinMax.nMaxHeight + ParaPr.Spacing.Before + ParaPr.Spacing.After;
		return {Min : Min, Max : Min};
	}

	// добавляем 0.001, чтобы избавиться от погрешностей
	return {
		Min : ( MinMax.nMinWidth > 0 ? MinMax.nMinWidth + 0.001 : 0 ),
		Max : ( MinMax.nMaxWidth > 0 ? MinMax.nMaxWidth + 0.001 : 0 )
	};
};
Paragraph.prototype.Draw = function(CurPage, pGraphics)
{
	// Параграф начинается с новой страницы
	if (this.Pages[CurPage].EndLine < 0)
		return;

	if (pGraphics.Start_Command)
	{
		pGraphics.Start_Command(AscFormat.DRAW_COMMAND_PARAGRAPH);
	}

	var Pr = this.Get_CompiledPr();

	// Задаем обрезку, если данный параграф является рамкой
	if (true !== this.Is_Inline())
	{
		var FramePr = this.Get_FramePr();
		if (undefined != FramePr && this.Parent instanceof CDocument)
		{
			var PixelError = editor.WordControl.m_oLogicDocument.DrawingDocument.GetMMPerDot(1);
			var BoundsL    = this.CalculatedFrame.L2 - PixelError;
			var BoundsT    = this.CalculatedFrame.T2 - PixelError;
			var BoundsH    = this.CalculatedFrame.H2 + 2 * PixelError;
			var BoundsW    = this.CalculatedFrame.W2 + 2 * PixelError;

			pGraphics.SaveGrState();
			pGraphics.AddClipRect(BoundsL, BoundsT, BoundsW, BoundsH);
		}
	}

	// Выясним какая заливка у нашего текста

	var Theme    = this.Get_Theme();
	var ColorMap = this.Get_ColorMap();
	var BgColor  = undefined;
	if (undefined !== Pr.ParaPr.Shd && Asc.c_oAscShdNil !== Pr.ParaPr.Shd.Value && true !== Pr.ParaPr.Shd.Color.Auto)
	{
		if (Pr.ParaPr.Shd.Unifill)
		{
			Pr.ParaPr.Shd.Unifill.check(this.Get_Theme(), this.Get_ColorMap());
			var RGBA = Pr.ParaPr.Shd.Unifill.getRGBAColor();
			BgColor  = new CDocumentColor(RGBA.R, RGBA.G, RGBA.B, false);
		}
		else
		{
			BgColor = Pr.ParaPr.Shd.Color;
		}
	}
	else
	{
		// Нам надо выяснить заливку у родительского класса (возможно мы находимся в ячейке таблицы с забивкой)
		BgColor = this.Parent.Get_TextBackGroundColor();
	}


	// 1 часть отрисовки :
	//    Рисуем слева от параграфа знак, если данный параграф зажат другим пользователем
	this.Internal_Draw_1(CurPage, pGraphics, Pr);

	// 2 часть отрисовки :
	//    Добавляем специальный символ слева от параграфа, для параграфов, у которых стоит хотя бы
	//    одна из настроек: не разрывать абзац(KeepLines), не отрывать от следующего(KeepNext),
	//    начать с новой страницы(PageBreakBefore)
	this.Internal_Draw_2(CurPage, pGraphics, Pr);

	// 3 часть отрисовки :
	//    Рисуем заливку параграфа и различные выделения текста (highlight, поиск, совместное редактирование).
	//    Кроме этого рисуем боковые линии обводки параграфа.
	this.Internal_Draw_3(CurPage, pGraphics, Pr);

	// 4 часть отрисовки :
	//    Рисуем сами элементы параграфа
	this.Internal_Draw_4(CurPage, pGraphics, Pr, BgColor, Theme, ColorMap);

	// 5 часть отрисовки :
	//    Рисуем различные подчеркивания и зачеркивания.
	this.Internal_Draw_5(CurPage, pGraphics, Pr, BgColor);

	// 6 часть отрисовки :
	//    Рисуем верхнюю, нижнюю и промежуточную границы
	this.Internal_Draw_6(CurPage, pGraphics, Pr);

	// Убираем обрезку
	if (undefined != FramePr && this.Parent instanceof CDocument)
	{
		pGraphics.RestoreGrState();
	}
	if (pGraphics.End_Command)
	{
		pGraphics.End_Command();
	}

};
Paragraph.prototype.Internal_Draw_1 = function(CurPage, pGraphics, Pr)
{
	if (this.bFromDocument && (pGraphics.RENDERER_PDF_FLAG !== true))
	{
		// Если данный параграф зажат другим пользователем, рисуем соответствующий знак
		if (AscCommon.locktype_None != this.Lock.Get_Type() && this.LogicDocument && !this.LogicDocument.IsViewModeInReview())
		{
			if (( CurPage > 0 || false === this.IsStartFromNewPage() || null === this.Get_DocumentPrev() ))
			{
				var X_min    = -1 + Math.min(this.Pages[CurPage].X, this.Pages[CurPage].X + Pr.ParaPr.Ind.Left, this.Pages[CurPage].X + Pr.ParaPr.Ind.Left + Pr.ParaPr.Ind.FirstLine);
				var Y_top    = this.Pages[CurPage].Bounds.Top;
				var Y_bottom = this.Pages[CurPage].Bounds.Bottom;

				if (true === editor.isCoMarksDraw || AscCommon.locktype_Mine != this.Lock.Get_Type())
					pGraphics.DrawLockParagraph(this.Lock.Get_Type(), X_min, Y_top, Y_bottom);
			}
		}

		// Если данный параграф был изменен другим пользователем, тогда рисуем знак
		var oColor = this.private_GetCollPrChange();
		if (false !== oColor)
		{
			if (( CurPage > 0 || false === this.IsStartFromNewPage() || null === this.Get_DocumentPrev() ))
			{
				var X_min    = -3 + Math.min(this.Pages[CurPage].X, this.Pages[CurPage].X + Pr.ParaPr.Ind.Left, this.Pages[CurPage].X + Pr.ParaPr.Ind.Left + Pr.ParaPr.Ind.FirstLine);
				var Y_top    = this.Pages[CurPage].Bounds.Top;
				var Y_bottom = this.Pages[CurPage].Bounds.Bottom;

				pGraphics.p_color(oColor.r, oColor.g, oColor.b, 255);
				pGraphics.drawVerLine(0, X_min, Y_top, Y_bottom, 0);
			}
		}

		// Если данный параграф был изменен в режиме рецензирования, тогда рисуем специальный знак
		if (true === this.Pr.Have_PrChange())
		{
			if (( CurPage > 0 || false === this.IsStartFromNewPage() || null === this.Get_DocumentPrev() ))
			{
				var X_min    = -3 + Math.min(this.Pages[CurPage].X, this.Pages[CurPage].X + Pr.ParaPr.Ind.Left, this.Pages[CurPage].X + Pr.ParaPr.Ind.Left + Pr.ParaPr.Ind.FirstLine);
				var Y_top    = this.Pages[CurPage].Bounds.Top;
				var Y_bottom = this.Pages[CurPage].Bounds.Bottom;

				var ReviewColor = this.Get_PrReviewColor();
				pGraphics.p_color(ReviewColor.r, ReviewColor.g, ReviewColor.b, 255);
				pGraphics.drawVerLine(0, X_min, Y_top, Y_bottom, 0);
			}
		}
	}
};
Paragraph.prototype.Internal_Draw_2 = function(CurPage, pGraphics, Pr)
{
	var isFirstPage = this.Check_FirstPage(CurPage);
	if (this.bFromDocument && !pGraphics.Start_Command && true === editor.ShowParaMarks && true === isFirstPage && ( true === Pr.ParaPr.KeepNext || true === Pr.ParaPr.KeepLines || true === Pr.ParaPr.PageBreakBefore ))
	{
		var SpecFont = {FontFamily : {Name : "Arial", Index : -1}, FontSize : 12, Italic : false, Bold : false};
		var SpecSym  = String.fromCharCode(0x25AA);
		pGraphics.SetFont(SpecFont);
		pGraphics.b_color1(0, 0, 0, 255);

		var CurLine  = this.Pages[CurPage].FirstLine;
		var CurRange = 0;
		var X        = this.Lines[CurLine].Ranges[CurRange].XVisible;
		var Y        = this.Pages[CurPage].Y + this.Lines[CurLine].Y;

		var SpecW = 2.5; // 2.5 mm
		var SpecX = Math.min(X, this.Pages[CurPage].X) - SpecW;

		pGraphics.FillText(SpecX, Y, SpecSym);
	}
};
Paragraph.prototype.Internal_Draw_3 = function(CurPage, pGraphics, Pr)
{
	var LogicDocument = this.LogicDocument;
	if (!this.bFromDocument || !LogicDocument)
		return;

	var bDrawBorders = this.Is_NeedDrawBorders();
	if (true === bDrawBorders && 0 === CurPage && true === this.private_IsEmptyPageWithBreak(CurPage))
		bDrawBorders = false;

	var PDSH = g_oPDSH;

	PDSH.ComplexFields.ResetPage(this, CurPage);

	var _Page = this.Pages[CurPage];

	var DocumentComments = LogicDocument.Comments;
	var Page_abs         = this.Get_AbsolutePage(CurPage);

	var DrawComm           = ( DocumentComments.Is_Use() && true !== LogicDocument.IsViewMode() && true !== this.LogicDocument.IsViewModeInReview());
	var DrawFind           = LogicDocument.SearchEngine.Selection;
	var DrawColl           = undefined !== pGraphics.RENDERER_PDF_FLAG;
	var DrawMMFields       = !!(this.LogicDocument && true === this.LogicDocument.Is_HighlightMailMergeFields());
	var DrawSolvedComments = ( DocumentComments.IsUseSolved() && true !== LogicDocument.IsViewMode() &&  true !== this.LogicDocument.IsViewModeInReview());
	var SdtHighlightColor  = this.LogicDocument.GetSdtGlobalShowHighlight() && undefined === pGraphics.RENDERER_PDF_FLAG ? this.LogicDocument.GetSdtGlobalColor() : null;

	PDSH.Reset(this, pGraphics, DrawColl, DrawFind, DrawComm, DrawMMFields, this.GetEndInfoByPage(CurPage - 1), DrawSolvedComments);

	var StartLine = _Page.StartLine;
	var EndLine   = _Page.EndLine;

	for (var CurLine = StartLine; CurLine <= EndLine; CurLine++)
	{
		var _Line        = this.Lines[CurLine];
		var _LineMetrics = _Line.Metrics;
		var EndLinePos   = _Line.EndPos;

		var Y0 = (_Page.Y + _Line.Y - _LineMetrics.Ascent);
		var Y1 = (_Page.Y + _Line.Y + _LineMetrics.Descent);
		if (_LineMetrics.LineGap < 0)
			Y1 += _LineMetrics.LineGap;

		var RangesCount = _Line.Ranges.length;
		for (var CurRange = 0; CurRange < RangesCount; CurRange++)
		{
			var _Range   = _Line.Ranges[CurRange];
			var X        = _Range.XVisible;
			var StartPos = _Range.StartPos;
			var EndPos   = _Range.EndPos;

			// Сначала проанализируем данную строку: в массивы aHigh, aColl, aFind
			// сохраним позиции начала и конца продолжительных одинаковых настроек
			// выделения, совместного редактирования и поиска соответственно.

			PDSH.Reset_Range(CurPage, CurLine, CurRange, X, Y0, Y1, _Range.Spaces);

			if (true === this.Numbering.Check_Range(CurRange, CurLine))
			{
				var NumberingType = this.Numbering.Type;
				var NumberingItem = this.Numbering;

				if (para_Numbering === NumberingType)
				{
					var NumPr = Pr.ParaPr.NumPr;
					if (undefined === NumPr || undefined === NumPr.NumId || 0 === NumPr.NumId || "0" === NumPr.NumId)
					{
						// Ничего не делаем
					}
					else
					{
						var oNumbering = this.Parent.GetNumbering();
						var oNumLvl    = oNumbering.GetNum(NumPr.NumId).GetLvl(NumPr.Lvl);
						var nNumJc     = oNumLvl.GetJc();
						var oNumTextPr = this.Get_CompiledPr2(false).TextPr.Copy();
						oNumTextPr.Merge(this.TextPr.Value);
						oNumTextPr.Merge(oNumLvl.GetTextPr());

						var X_start = X;

						if (align_Right === nNumJc)
							X_start = X - NumberingItem.WidthNum;
						else if (align_Center === nNumJc)
							X_start = X - NumberingItem.WidthNum / 2;

						// Если есть выделение текста, рисуем его сначала
						if (highlight_None != oNumTextPr.HighLight)
							PDSH.High.Add(Y0, Y1, X_start, X_start + NumberingItem.WidthNum + NumberingItem.WidthSuff, 0, oNumTextPr.HighLight.r, oNumTextPr.HighLight.g, oNumTextPr.HighLight.b, undefined, oNumTextPr);
					}
				}

				PDSH.X += this.Numbering.WidthVisible;
			}

			for (var Pos = StartPos; Pos <= EndPos; Pos++)
			{
				var Item = this.Content[Pos];
				Item.Draw_HighLights(PDSH);
			}

			//----------------------------------------------------------------------------------------------------------
			// Заливка параграфа
			//----------------------------------------------------------------------------------------------------------
			if ((_Range.W > 0.001 || true === this.IsEmpty() || true !== this.Is_EmptyRange(CurLine, CurRange) ) && ( ( this.Pages.length - 1 === CurPage ) || ( CurLine < this.Pages[CurPage + 1].FirstLine ) ) && Asc.c_oAscShdClear === Pr.ParaPr.Shd.Value && (Pr.ParaPr.Shd.Unifill || (Pr.ParaPr.Shd.Color && true !== Pr.ParaPr.Shd.Color.Auto)))
			{
				if (pGraphics.Start_Command)
				{
					pGraphics.Start_Command(AscFormat.DRAW_COMMAND_LINE, this.Lines[CurLine], CurLine, 4)
				}

				var TempX0 = this.Lines[CurLine].Ranges[CurRange].X;
				if (0 === CurRange)
					TempX0 = Math.min(TempX0, this.Pages[CurPage].X + Pr.ParaPr.Ind.Left, this.Pages[CurPage].X + Pr.ParaPr.Ind.Left + Pr.ParaPr.Ind.FirstLine);

				var TempX1 = this.Lines[CurLine].Ranges[CurRange].XEnd;

				var TempTop    = this.Lines[CurLine].Top;
				var TempBottom = this.Lines[CurLine].Bottom;

				if (0 === CurLine)
				{
					// Закрашиваем фон до параграфа, только если данный параграф не является первым
					// на странице, предыдущий параграф тоже имеет не пустой фон и у текущего и предыдущего
					// параграфов совпадают правая и левая границы фонов.

					var PrevEl = this.Get_DocumentPrev();
					var PrevPr = null;

					var PrevLeft  = 0;
					var PrevRight = 0;
					var CurLeft   = Math.min(Pr.ParaPr.Ind.Left, Pr.ParaPr.Ind.Left + Pr.ParaPr.Ind.FirstLine);
					var CurRight  = Pr.ParaPr.Ind.Right;
					if (null != PrevEl && type_Paragraph === PrevEl.GetType())
					{
						PrevPr    = PrevEl.Get_CompiledPr2();
						PrevLeft  = Math.min(PrevPr.ParaPr.Ind.Left, PrevPr.ParaPr.Ind.Left + PrevPr.ParaPr.Ind.FirstLine);
						PrevRight = PrevPr.ParaPr.Ind.Right;
					}

					// Если данный параграф находится в группе параграфов с одинаковыми границами(с хотябы одной
					// непустой), и он не первый, тогда закрашиваем вместе с расстоянием до параграфа
					if (true === Pr.ParaPr.Brd.First)
					{
						// Если следующий элемент таблица, тогда PrevPr = null
						if (null === PrevEl || true === this.IsStartFromNewPage() || null === PrevPr || Asc.c_oAscShdNil === PrevPr.ParaPr.Shd.Value || PrevLeft != CurLeft || CurRight != PrevRight || false === this.Internal_Is_NullBorders(PrevPr.ParaPr.Brd) || false === this.Internal_Is_NullBorders(Pr.ParaPr.Brd))
						{
							if (false === this.IsStartFromNewPage() || null === PrevEl)
								TempTop += Pr.ParaPr.Spacing.Before;
						}
					}
				}

				if (this.Lines.length - 1 === CurLine)
				{
					// Закрашиваем фон после параграфа, только если данный параграф не является последним,
					// на странице, следующий параграф тоже имеет не пустой фон и у текущего и следующего
					// параграфов совпадают правая и левая границы фонов.

					var NextEl = this.Get_DocumentNext();
					var NextPr = null;

					var NextLeft  = 0;
					var NextRight = 0;
					var CurLeft   = Math.min(Pr.ParaPr.Ind.Left, Pr.ParaPr.Ind.Left + Pr.ParaPr.Ind.FirstLine);
					var CurRight  = Pr.ParaPr.Ind.Right;
					if (null != NextEl && type_Paragraph === NextEl.GetType())
					{
						NextPr    = NextEl.Get_CompiledPr2();
						NextLeft  = Math.min(NextPr.ParaPr.Ind.Left, NextPr.ParaPr.Ind.Left + NextPr.ParaPr.Ind.FirstLine);
						NextRight = NextPr.ParaPr.Ind.Right;
					}

					if (null != NextEl && type_Paragraph === NextEl.GetType() && true === NextEl.IsStartFromNewPage())
					{
						TempBottom = this.Lines[CurLine].Y + this.Lines[CurLine].Metrics.Descent + this.Lines[CurLine].Metrics.LineGap;
					}
					// Если данный параграф находится в группе параграфов с одинаковыми границами(с хотябы одной
					// непустой), и он не последний, тогда закрашиваем вместе с расстоянием после параграфа
					else if (true === Pr.ParaPr.Brd.Last)
					{
						// Если следующий элемент таблица, тогда NextPr = null
						if (null === NextEl || true === NextEl.IsStartFromNewPage() || null === NextPr || Asc.c_oAscShdNil === NextPr.ParaPr.Shd.Value || NextLeft != CurLeft || CurRight != NextRight || false === this.Internal_Is_NullBorders(NextPr.ParaPr.Brd) || false === this.Internal_Is_NullBorders(Pr.ParaPr.Brd))
							TempBottom -= Pr.ParaPr.Spacing.After;
					}
				}

				if (0 === CurRange)
				{
					if (Pr.ParaPr.Brd.Left.Value === border_Single)
						TempX0 -= 0.5 + Pr.ParaPr.Brd.Left.Size + Pr.ParaPr.Brd.Left.Space;
					else
						TempX0 -= 0.5;
				}

				if (this.Lines[CurLine].Ranges.length - 1 === CurRange)
				{
					if (Pr.ParaPr.Brd.Right.Value === border_Single)
						TempX1 += 0.5 + Pr.ParaPr.Brd.Right.Size + Pr.ParaPr.Brd.Right.Space;
					else
						TempX1 += 0.5;
				}

				if (Pr.ParaPr.Shd.Unifill)
				{
					Pr.ParaPr.Shd.Unifill.check(this.Get_Theme(), this.Get_ColorMap());
					var RGBA = Pr.ParaPr.Shd.Unifill.getRGBAColor();
					pGraphics.b_color1(RGBA.R, RGBA.G, RGBA.B, 255);
				}
				else
				{
					pGraphics.b_color1(Pr.ParaPr.Shd.Color.r, Pr.ParaPr.Shd.Color.g, Pr.ParaPr.Shd.Color.b, 255);
				}
				if (pGraphics.SetShd)
				{
					pGraphics.SetShd(Pr.ParaPr.Shd);
				}
				pGraphics.rect(TempX0, this.Pages[CurPage].Y + TempTop, TempX1 - TempX0, TempBottom - TempTop);
				pGraphics.df();

				if (pGraphics.End_Command)
				{
					pGraphics.End_Command()
				}
			}

			//----------------------------------------------------------------------------------------------------------
			// Рисуем подсветку InlineSdt
			//----------------------------------------------------------------------------------------------------------
			if (SdtHighlightColor)
			{
				pGraphics.b_color1(SdtHighlightColor.r, SdtHighlightColor.g, SdtHighlightColor.b, 255);
				var oSdtBounds;
				for (var nSdtIndex = 0, nSdtCount = PDSH.InlineSdt.length; nSdtIndex < nSdtCount; ++nSdtIndex)
				{
					oSdtBounds = PDSH.InlineSdt[nSdtIndex].GetRangeBounds(CurLine, CurRange);
					if (oSdtBounds)
					{
						pGraphics.rect(oSdtBounds.X, oSdtBounds.Y, oSdtBounds.W, oSdtBounds.H);
						pGraphics.df();
					}
				}
			}
			//----------------------------------------------------------------------------------------------------------
			// Рисуем заливку текста
			//----------------------------------------------------------------------------------------------------------

			if (pGraphics.Start_Command)
			{
				pGraphics.Start_Command(AscFormat.DRAW_COMMAND_LINE, this.Lines[CurLine], CurLine, 2);
			}
			var aShd    = PDSH.Shd;
			var Element = aShd.Get_Next();
			while (null != Element)
			{
				pGraphics.b_color1(Element.r, Element.g, Element.b, 255);
				if (pGraphics.SetShd)
				{
					pGraphics.SetShd(Element.Additional2);
				}
				pGraphics.rect(Element.x0, Element.y0, Element.x1 - Element.x0, Element.y1 - Element.y0);
				pGraphics.df();
				Element = aShd.Get_Next();
			}

			//----------------------------------------------------------------------------------------------------------
			// Рисуем выделение текста
			//----------------------------------------------------------------------------------------------------------
			var aMMFields = PDSH.MMFields;
			var Element   = (pGraphics.RENDERER_PDF_FLAG === true ? null : aMMFields.Get_Next());
			while (null != Element)
			{
				pGraphics.drawMailMergeField(Element.x0, Element.y0, Element.x1 - Element.x0, Element.y1 - Element.y0, Element);
				Element = aMMFields.Get_Next();
			}

			//----------------------------------------------------------------------------------------------------------
			// Заливка сложных полей
			//----------------------------------------------------------------------------------------------------------
			var aCFields = PDSH.CFields;
			var Element   = (pGraphics.RENDERER_PDF_FLAG === true ? null : aCFields.Get_Next());
			while (null != Element)
			{
				pGraphics.drawMailMergeField(Element.x0, Element.y0, Element.x1 - Element.x0, Element.y1 - Element.y0, Element);
				Element = aCFields.Get_Next();
			}

			//----------------------------------------------------------------------------------------------------------
			// Рисуем выделение текста
			//----------------------------------------------------------------------------------------------------------
			var aHigh   = PDSH.High;
			var Element = aHigh.Get_Next();
			while (null != Element)
			{
				if (!pGraphics.set_fillColor)
				{
					pGraphics.b_color1(Element.r, Element.g, Element.b, 255);
				}
				else
				{
					pGraphics.set_fillColor(Element.r, Element.g, Element.b);
				}
				pGraphics.rect(Element.x0, Element.y0, Element.x1 - Element.x0, Element.y1 - Element.y0, Element.Additional2);
				pGraphics.df();
				Element = aHigh.Get_Next();
			}

			//----------------------------------------------------------------------------------------------------------
			// Рисуем комментарии
			//----------------------------------------------------------------------------------------------------------
			var aComm                 = PDSH.Comm;
			Element                   = ( pGraphics.RENDERER_PDF_FLAG === true ? null : aComm.Get_Next() );
			var ParentInvertTransform = Element && this.Get_ParentTextInvertTransform();
			while (null != Element)
			{
				if (!pGraphics.DrawTextArtComment)
				{
					if (Element.Additional.Active === true)
						pGraphics.b_color1(240, 200, 120, 255);
					else
						pGraphics.b_color1(248, 231, 195, 255);

					pGraphics.rect(Element.x0, Element.y0, Element.x1 - Element.x0, Element.y1 - Element.y0);
					pGraphics.df();

					DocumentComments.Add_DrawingRect(Element.x0, Element.y0, Element.x1 - Element.x0, Element.y1 - Element.y0, Page_abs, Element.Additional.CommentId, ParentInvertTransform);
				}
				else
				{
					pGraphics.DrawTextArtComment(Element);
				}
				Element = aComm.Get_Next();
			}


			if (pGraphics.End_Command)
			{
				pGraphics.End_Command()
			}

			//----------------------------------------------------------------------------------------------------------
			// Рисуем выделение совместного редактирования
			//----------------------------------------------------------------------------------------------------------
			var aColl = PDSH.Coll;
			Element   = aColl.Get_Next();
			while (null != Element)
			{
				pGraphics.drawCollaborativeChanges(Element.x0, Element.y0, Element.x1 - Element.x0, Element.y1 - Element.y0, Element);
				Element = aColl.Get_Next();
			}

			//----------------------------------------------------------------------------------------------------------
			// Рисуем выделение поиска
			//----------------------------------------------------------------------------------------------------------
			var aFind = PDSH.Find;
			Element   = aFind.Get_Next();
			while (null != Element)
			{
				pGraphics.drawSearchResult(Element.x0, Element.y0, Element.x1 - Element.x0, Element.y1 - Element.y0);
				Element = aFind.Get_Next();
			}
		}


		if (pGraphics.Start_Command)
		{
			pGraphics.Start_Command(AscFormat.DRAW_COMMAND_LINE, this.Lines[CurLine], CurLine, 1)
		}
		//----------------------------------------------------------------------------------------------------------
		// Рисуем боковые линии границы параграфа
		//----------------------------------------------------------------------------------------------------------
		if (true === bDrawBorders && ( ( this.Pages.length - 1 === CurPage ) || ( CurLine < this.Pages[CurPage + 1].FirstLine ) ))
		{
			var TempX0 = Math.min(this.Lines[CurLine].Ranges[0].X, this.Pages[CurPage].X + Pr.ParaPr.Ind.Left, this.Pages[CurPage].X + Pr.ParaPr.Ind.Left + Pr.ParaPr.Ind.FirstLine);
			var TempX1 = this.Lines[CurLine].Ranges[this.Lines[CurLine].Ranges.length - 1].XEnd;

			if (true === this.Is_LineDropCap())
			{
				TempX1 = TempX0 + this.Get_LineDropCapWidth();
			}

			var TempTop    = this.Lines[CurLine].Top;
			var TempBottom = this.Lines[CurLine].Bottom;

			if (0 === CurLine)
			{
				if (Pr.ParaPr.Brd.Top.Value === border_Single || Asc.c_oAscShdClear === Pr.ParaPr.Shd.Value)
				{
					if (( true === Pr.ParaPr.Brd.First && ( 0 === CurPage || true === this.Parent.IsTableCellContent() || true === Pr.ParaPr.PageBreakBefore ) ) ||
						( true !== Pr.ParaPr.Brd.First && ( ( 0 === CurPage && null === this.Get_DocumentPrev() ) || ( 1 === CurPage && true === this.IsStartFromNewPage() )  ) ))
						TempTop += Pr.ParaPr.Spacing.Before;
				}
			}

			if (this.Lines.length - 1 === CurLine)
			{
				var NextEl = this.Get_DocumentNext();
				if (null != NextEl && type_Paragraph === NextEl.GetType() && true === NextEl.IsStartFromNewPage())
					TempBottom = this.Lines[CurLine].Y + this.Lines[CurLine].Metrics.Descent + this.Lines[CurLine].Metrics.LineGap;
				else if ((true === Pr.ParaPr.Brd.Last || (null !== NextEl && (type_Table === NextEl.Get_Type() || true === NextEl.private_IsEmptyPageWithBreak(0)))) && ( Pr.ParaPr.Brd.Bottom.Value === border_Single || Asc.c_oAscShdClear === Pr.ParaPr.Shd.Value ))
					TempBottom -= Pr.ParaPr.Spacing.After;
			}


			if (Pr.ParaPr.Brd.Right.Value === border_Single)
			{
				var RGBA = Pr.ParaPr.Brd.Right.Get_Color(this);
				pGraphics.p_color(RGBA.r, RGBA.g, RGBA.b, 255);
				if (pGraphics.SetBorder)
				{
					pGraphics.SetBorder(Pr.ParaPr.Brd.Right);
				}
				pGraphics.drawVerLine(c_oAscLineDrawingRule.Right, TempX1 + 0.5 + Pr.ParaPr.Brd.Right.Size + Pr.ParaPr.Brd.Right.Space, this.Pages[CurPage].Y + TempTop, this.Pages[CurPage].Y + TempBottom, Pr.ParaPr.Brd.Right.Size);
			}

			if (Pr.ParaPr.Brd.Left.Value === border_Single)
			{
				var RGBA = Pr.ParaPr.Brd.Left.Get_Color(this);
				pGraphics.p_color(RGBA.r, RGBA.g, RGBA.b, 255);
				if (pGraphics.SetBorder)
				{
					pGraphics.SetBorder(Pr.ParaPr.Brd.Left);
				}
				pGraphics.drawVerLine(c_oAscLineDrawingRule.Left, TempX0 - 0.5 - Pr.ParaPr.Brd.Left.Size - Pr.ParaPr.Brd.Left.Space, this.Pages[CurPage].Y + TempTop, this.Pages[CurPage].Y + TempBottom, Pr.ParaPr.Brd.Left.Size);
			}
		}

		if (pGraphics.End_Command)
		{
			pGraphics.End_Command()
		}
	}
};
Paragraph.prototype.Internal_Draw_4 = function(CurPage, pGraphics, Pr, BgColor, Theme, ColorMap)
{
	var PDSE = this.m_oPDSE;
	PDSE.Reset(this, pGraphics, BgColor, Theme, ColorMap);
	PDSE.ComplexFields.ResetPage(this, CurPage);

	var StartLine = this.Pages[CurPage].StartLine;
	var EndLine   = this.Pages[CurPage].EndLine;

	for (var CurLine = StartLine; CurLine <= EndLine; CurLine++)
	{
		var Line        = this.Lines[CurLine];
		var RangesCount = Line.Ranges.length;
		if (pGraphics.Start_Command)
		{
			pGraphics.Start_Command(AscFormat.DRAW_COMMAND_LINE, Line, CurLine, 0);
		}

		for (var CurRange = 0; CurRange < RangesCount; CurRange++)
		{
			var Y = this.Pages[CurPage].Y + this.Lines[CurLine].Y;
			var X = this.Lines[CurLine].Ranges[CurRange].XVisible;

			var Range = Line.Ranges[CurRange];

			PDSE.Set_LineMetrics(Y, Y - Line.Metrics.Ascent, Y + Line.Metrics.Descent);
			PDSE.Reset_Range(CurPage, CurLine, CurRange, X, Y);

			var StartPos = Range.StartPos;
			var EndPos   = Range.EndPos;

			// Отрисовка нумерации
			if (true === this.Numbering.Check_Range(CurRange, CurLine))
			{
				var NumberingItem = this.Numbering;
				if (para_Numbering === NumberingItem.Type)
				{
					var NumPr = Pr.ParaPr.NumPr;
					if (undefined === NumPr || undefined === NumPr.NumId || 0 === NumPr.NumId || "0" === NumPr.NumId || ( undefined !== this.Get_SectionPr() && true === this.IsEmpty() ))
					{
						// Ничего не делаем
					}
					else
					{
						var oNumbering = this.Parent.GetNumbering();
						var oNumLvl    = oNumbering.GetNum(NumPr.NumId).GetLvl(NumPr.Lvl);
						var nNumSuff   = oNumLvl.GetSuff();
						var nNumJc     = oNumLvl.GetJc();
						var oNumTextPr = this.Get_CompiledPr2(false).TextPr.Copy();

						// Word не рисует подчеркивание у символа списка, если оно пришло из настроек для
						// символа параграфа.

						var oTextPrTemp = this.TextPr.Value.Copy();
						oTextPrTemp.Underline = undefined;

						oNumTextPr.Merge(oTextPrTemp);
						oNumTextPr.Merge(oNumLvl.GetTextPr());

						var X_start = X;

						if (align_Right === nNumJc)
							X_start = X - NumberingItem.WidthNum;
						else if (align_Center === nNumJc)
							X_start = X - NumberingItem.WidthNum / 2;

						var AutoColor = ( undefined != BgColor && false === BgColor.Check_BlackAutoColor() ? new CDocumentColor(255, 255, 255, false) : new CDocumentColor(0, 0, 0, false) );

						var RGBA;
						if (oNumTextPr.Unifill)
						{
							oNumTextPr.Unifill.check(PDSE.Theme, PDSE.ColorMap);
							RGBA = oNumTextPr.Unifill.getRGBAColor();
							pGraphics.b_color1(RGBA.R, RGBA.G, RGBA.B, 255);
						}
						else
						{
							if (true === oNumTextPr.Color.Auto)
								pGraphics.b_color1(AutoColor.r, AutoColor.g, AutoColor.b, 255);
							else
								pGraphics.b_color1(oNumTextPr.Color.r, oNumTextPr.Color.g, oNumTextPr.Color.b, 255);
						}

						// Рисуется только сам символ нумерации
						switch (nNumJc)
						{
							case align_Right:
								NumberingItem.Draw(X - NumberingItem.WidthNum, Y, pGraphics, oNumbering, oNumTextPr, NumPr, PDSE.Theme);
								break;

							case align_Center:
								NumberingItem.Draw(X - NumberingItem.WidthNum / 2, Y, pGraphics, oNumbering, oNumTextPr, NumPr, PDSE.Theme);
								break;

							case align_Left:
							default:
								NumberingItem.Draw(X, Y, pGraphics, oNumbering, oNumTextPr, NumPr, PDSE.Theme);
								break;
						}

						if (true === editor.ShowParaMarks && (Asc.c_oAscNumberingSuff.Tab === nNumSuff || oNumLvl.IsLegacy()))
						{
							var TempWidth     = NumberingItem.WidthSuff;
							var TempRealWidth = 3.143; // ширина символа "стрелка влево" в шрифте Wingding3,10

							var X1 = X;
							switch (nNumJc)
							{
								case align_Right:
									break;

								case align_Center:
									X1 += NumberingItem.WidthNum / 2;
									break;

								case align_Left:
								default:
									X1 += NumberingItem.WidthNum;
									break;
							}

							var X0 = TempWidth / 2 - TempRealWidth / 2;

							pGraphics.SetFont({
								FontFamily : {Name : "ASCW3", Index : -1},
								FontSize   : 10,
								Italic     : false,
								Bold       : false
							});

							if (X0 > 0)
								pGraphics.FillText2(X1 + X0, Y, String.fromCharCode(tab_Symbol), 0, TempWidth);
							else
								pGraphics.FillText2(X1, Y, String.fromCharCode(tab_Symbol), TempRealWidth - TempWidth, TempWidth);
						}

						if (true === oNumTextPr.Strikeout || true === oNumTextPr.Underline)
						{
							if (oNumTextPr.Unifill)
							{
								pGraphics.p_color(RGBA.R, RGBA.G, RGBA.B, 255);
							}
							else
							{
								if (true === oNumTextPr.Color.Auto)
									pGraphics.p_color(AutoColor.r, AutoColor.g, AutoColor.b, 255);
								else
									pGraphics.p_color(oNumTextPr.Color.r, oNumTextPr.Color.g, oNumTextPr.Color.b, 255);
							}
						}

						if (true === oNumTextPr.Strikeout)
							pGraphics.drawHorLine(0, (Y - oNumTextPr.FontSize * g_dKoef_pt_to_mm * 0.27), X_start, X_start + NumberingItem.WidthNum, (oNumTextPr.FontSize / 18) * g_dKoef_pt_to_mm);

						if (true === oNumTextPr.Underline)
							pGraphics.drawHorLine(0, (Y + this.Lines[CurLine].Metrics.TextDescent * 0.4), X_start, X_start + NumberingItem.WidthNum, (oNumTextPr.FontSize / 18) * g_dKoef_pt_to_mm);
					}
				}
				else if (para_PresentationNumbering === this.Numbering.Type)
				{
					if (true != this.IsEmpty())
					{
						if (Pr.ParaPr.Ind.FirstLine < 0)
							NumberingItem.Draw(X, Y, pGraphics, this.Get_FirstTextPr2(), PDSE);
						else
							NumberingItem.Draw(this.Pages[CurPage].X  + Pr.ParaPr.Ind.Left, Y, pGraphics, this.Get_FirstTextPr2(), PDSE);
					}
				}

				PDSE.X += NumberingItem.WidthVisible;
			}

			for (var Pos = StartPos; Pos <= EndPos; Pos++)
			{
				var Item = this.Content[Pos];
				PDSE.CurPos.Update(Pos, 0);

				Item.Draw_Elements(PDSE);
			}
		}

		if (pGraphics.End_Command)
		{
			pGraphics.End_Command();
		}
	}
};
Paragraph.prototype.Internal_Draw_5 = function(CurPage, pGraphics, Pr, BgColor)
{
	var PDSL = g_oPDSL;
	PDSL.Reset(this, pGraphics, BgColor);
	PDSL.ComplexFields.ResetPage(this, CurPage);

	var Page = this.Pages[CurPage];

	var StartLine = Page.StartLine;
	var EndLine   = Page.EndLine;

	var RunPrReview = null;

	var arrRunReviewAreasColors = [];
	var arrRunReviewAreas       = [];
	var arrRunReviewRects       = [];
	for (var CurLine = StartLine; CurLine <= EndLine; CurLine++)
	{
		var Line  = this.Lines[CurLine];
		var LineM = Line.Metrics;

		if (pGraphics.Start_Command)
		{
			pGraphics.Start_Command(AscFormat.DRAW_COMMAND_LINE, Line, CurLine, 3)
		}

		var Baseline        = Page.Y + Line.Y;
		var UnderlineOffset = LineM.TextDescent * 0.4;

		PDSL.Reset_Line(CurPage, CurLine, Baseline, UnderlineOffset);

		// Сначала проанализируем данную строку: в массивы aStrikeout, aDStrikeout, aUnderline
		// aSpelling сохраним позиции начала и конца продолжительных одинаковых настроек зачеркивания,
		// двойного зачеркивания, подчеркивания и подчеркивания орфографии.

		var RangesCount = Line.Ranges.length;
		for (var CurRange = 0; CurRange < RangesCount; CurRange++)
		{
			var Range = Line.Ranges[CurRange];
			var X     = Range.XVisible;

			PDSL.Reset_Range(CurRange, X, Range.Spaces);

			var StartPos = Range.StartPos;
			var EndPos   = Range.EndPos;

			// TODO: Нумерация подчеркивается и зачеркивается в Draw_Elements, неплохо бы сюда перенести
			if (true === this.Numbering.Check_Range(CurRange, CurLine))
				PDSL.X += this.Numbering.WidthVisible;

			for (var Pos = StartPos; Pos <= EndPos; Pos++)
			{
				PDSL.CurPos.Update(Pos, 0);
				PDSL.CurDepth = 1;

				var Item = this.Content[Pos];
				Item.Draw_Lines(PDSL);
			}
		}

		var aStrikeout  = PDSL.Strikeout;
		var aDStrikeout = PDSL.DStrikeout;
		var aUnderline  = PDSL.Underline;
		var aSpelling   = PDSL.Spelling;
		var aRunReview  = PDSL.RunReview;
		var aCollChange = PDSL.CollChange;

		// Рисуем зачеркивание
		var Element = aStrikeout.Get_Next();
		while (null != Element)
		{
			pGraphics.p_color(Element.r, Element.g, Element.b, 255);
			if (pGraphics.SetAdditionalProps)
			{
				pGraphics.SetAdditionalProps(Element.Additional2);
			}
			pGraphics.drawHorLine(c_oAscLineDrawingRule.Top, Element.y0, Element.x0, Element.x1, Element.w);
			Element = aStrikeout.Get_Next();
		}

		// Рисуем двойное зачеркивание
		Element = aDStrikeout.Get_Next();
		while (null != Element)
		{
			pGraphics.p_color(Element.r, Element.g, Element.b, 255);
			if (pGraphics.SetAdditionalProps)
			{
				pGraphics.SetAdditionalProps(Element.Additional2);
			}
			pGraphics.drawHorLine2(c_oAscLineDrawingRule.Top, Element.y0, Element.x0, Element.x1, Element.w);

			Element = aDStrikeout.Get_Next();
		}

		// Рисуем подчеркивание
		aUnderline.Correct_w_ForUnderline();
		Element = aUnderline.Get_Next();
		while (null != Element)
		{
			pGraphics.p_color(Element.r, Element.g, Element.b, 255);
			if (pGraphics.SetAdditionalProps)
			{
				pGraphics.SetAdditionalProps(Element.Additional2);
			}
			pGraphics.drawHorLine(0, Element.y0, Element.x0, Element.x1, Element.w);
			Element = aUnderline.Get_Next();
		}

		if (pGraphics.RENDERER_PDF_FLAG !== true)
		{
			// Рисуем красный рект вокруг измененных ранов
			var arrRunReviewRectsLine = [];
			Element                   = aRunReview.Get_NextForward();
			while (null !== Element)
			{
				if (null === RunPrReview || true !== RunPrReview.Is_Equal(Element.Additional.RunPr))
				{
					if (arrRunReviewRectsLine.length > 0 && arrRunReviewRects)
					{
						arrRunReviewRects.push(arrRunReviewRectsLine);
						arrRunReviewRectsLine = [];
					}
					RunPrReview       = Element.Additional.RunPr;
					arrRunReviewRects = [];
					arrRunReviewAreas.push(arrRunReviewRects);
					arrRunReviewAreasColors.push(new CDocumentColor(Element.r, Element.g, Element.b));
				}

				arrRunReviewRectsLine.push({
					X    : Element.x0,
					Y    : Page.Y + Line.Y - Line.Metrics.TextAscent,
					W    : Element.x1 - Element.x0,
					H    : Line.Metrics.TextDescent + Line.Metrics.TextAscent + Line.Metrics.LineGap,
					Page : 0
				});
				Element = aRunReview.Get_NextForward();
			}

			if (arrRunReviewRectsLine.length > 0)
				arrRunReviewRects.push(arrRunReviewRectsLine);

			if (this.bFromDocument)
			{
				// Рисуем рект вокруг измененных ранов (измененных другим пользователем)
				Element = aCollChange.Get_Next();
				while (null !== Element)
				{
					pGraphics.p_color(Element.r, Element.g, Element.b, 255);
					pGraphics.AddSmartRect(Element.x0, Page.Y + Line.Top, Element.x1 - Element.x0, Line.Bottom - Line.Top, 0);
					Element = aCollChange.Get_Next();
				}
			}
            // Рисуем подчеркивание орфографии
            if (editor && this.LogicDocument && true === this.LogicDocument.Spelling.Use && !(pGraphics.IsThumbnail === true || pGraphics.IsDemonstrationMode === true || AscCommon.IsShapeToImageConverter))
            {
                pGraphics.p_color(255, 0, 0, 255);
                var SpellingW = editor.WordControl.m_oDrawingDocument.GetMMPerDot(1);
                Element       = aSpelling.Get_Next();
                while (null != Element)
                {
                    pGraphics.DrawSpellingLine(Element.y0, Element.x0, Element.x1, SpellingW);
                    Element = aSpelling.Get_Next();
                }
            }
		}

		if (pGraphics.End_Command)
		{
			pGraphics.End_Command()
		}
	}

	if (pGraphics.DrawPolygon)
	{
		for (var ReviewAreaIndex = 0, ReviewAreasCount = arrRunReviewAreas.length; ReviewAreaIndex < ReviewAreasCount; ++ReviewAreaIndex)
		{
			var arrRunReviewRects = arrRunReviewAreas[ReviewAreaIndex];
			var oRunReviewColor   = arrRunReviewAreasColors[ReviewAreaIndex];
			var ReviewPolygon     = new CPolygon();
			ReviewPolygon.fill(arrRunReviewRects);
			var PolygonPaths = ReviewPolygon.GetPaths(0);
			pGraphics.p_color(oRunReviewColor.r, oRunReviewColor.g, oRunReviewColor.b, 255);
			for (var PolygonIndex = 0, PolygonsCount = PolygonPaths.length; PolygonIndex < PolygonsCount; ++PolygonIndex)
			{
				var Path = PolygonPaths[PolygonIndex];
				pGraphics.DrawPolygon(Path, 1, 0);
			}
		}
	}
};
Paragraph.prototype.Internal_Draw_6 = function(CurPage, pGraphics, Pr)
{
	if (true !== this.Is_NeedDrawBorders())
		return;

	var bEmpty  = this.IsEmpty();
	var X_left  = Math.min(this.Pages[CurPage].X + Pr.ParaPr.Ind.Left, this.Pages[CurPage].X + Pr.ParaPr.Ind.Left + Pr.ParaPr.Ind.FirstLine);
	var X_right = this.Pages[CurPage].XLimit - Pr.ParaPr.Ind.Right;

	if (true === this.Is_LineDropCap())
		X_right = X_left + this.Get_LineDropCapWidth();

	if (Pr.ParaPr.Brd.Left.Value === border_Single)
		X_left -= 0.5 + Pr.ParaPr.Brd.Left.Space;
	else
		X_left -= 0.5;

	if (Pr.ParaPr.Brd.Right.Value === border_Single)
		X_right += 0.5 + Pr.ParaPr.Brd.Right.Space;
	else
		X_right += 0.5;

	var LeftMW  = -( border_Single === Pr.ParaPr.Brd.Left.Value ? Pr.ParaPr.Brd.Left.Size : 0 );
	var RightMW = ( border_Single === Pr.ParaPr.Brd.Right.Value ? Pr.ParaPr.Brd.Right.Size : 0 );

	var RGBA;

	var bEmptyPagesWithBreakBefore = false;
	var bCurEmptyPageWithBreak     = false;
	var bEmptyPagesBefore          = true;
	var bEmptyPageCurrent          = true;

	for (var TempCurPage = 0; TempCurPage < CurPage; ++TempCurPage)
	{
		if (false === this.private_IsEmptyPageWithBreak(TempCurPage))
		{
			bEmptyPagesWithBreakBefore = false;
			break;
		}
		else
		{
			bEmptyPagesWithBreakBefore = true;
		}
	}
	bCurEmptyPageWithBreak = this.private_IsEmptyPageWithBreak(CurPage);

	for (var TempCurPage = 0; TempCurPage < CurPage; ++TempCurPage)
	{
		if (false === this.IsEmptyPage(TempCurPage))
		{
			bEmptyPagesBefore = false;
			break;
		}
	}
	bEmptyPageCurrent = this.IsEmptyPage(CurPage);

	var bDrawTop = false;
	if (border_Single === Pr.ParaPr.Brd.Top.Value
		&& ((true === Pr.ParaPr.Brd.First
		&& false === bCurEmptyPageWithBreak
		&& ((true === bEmptyPagesBefore
		&& true !== bEmptyPageCurrent)
		|| (true === bEmptyPagesWithBreakBefore
		&& false === bCurEmptyPageWithBreak)))
		|| (false === Pr.ParaPr.Brd.First
		&& true === bEmptyPagesWithBreakBefore
		&& false === bCurEmptyPageWithBreak)))
	{
		bDrawTop = true;
	}

	var bDrawBetween = false;
	if (border_Single === Pr.ParaPr.Brd.Between.Value
		&& false === bDrawTop
		&& false === bEmptyPageCurrent
		&& true === bEmptyPagesBefore
		&& false === Pr.ParaPr.Brd.First)
	{
		bDrawBetween = true;
	}

	if (bDrawTop)
	{
		var Y_top = this.Pages[CurPage].Y;
		if (0 === CurPage || true === this.Parent.IsTableCellContent() || true === Pr.ParaPr.PageBreakBefore)
			Y_top += Pr.ParaPr.Spacing.Before;

		RGBA = Pr.ParaPr.Brd.Top.Get_Color(this);
		pGraphics.p_color(RGBA.r, RGBA.g, RGBA.b, 255);

		if (pGraphics.SetBorder)
		{
			pGraphics.SetBorder(Pr.ParaPr.Brd.Top);
		}
		// Учтем разрывы из-за обтекания
		var StartLine = this.Pages[CurPage].StartLine;

		if (pGraphics.Start_Command)
		{
			pGraphics.Start_Command(AscFormat.DRAW_COMMAND_LINE, this.Lines[StartLine], StartLine, 1);
		}
		var RangesCount = this.Lines[StartLine].Ranges.length;
		for (var CurRange = 0; CurRange < RangesCount; CurRange++)
		{
			var X0 = ( 0 === CurRange ? X_left : this.Lines[StartLine].Ranges[CurRange].X );
			var X1 = ( RangesCount - 1 === CurRange ? X_right : this.Lines[StartLine].Ranges[CurRange].XEnd );

			if (false === this.Is_EmptyRange(StartLine, CurRange) || ( true === bEmpty && 1 === RangesCount ))
				pGraphics.drawHorLineExt(c_oAscLineDrawingRule.Top, Y_top, X0, X1, Pr.ParaPr.Brd.Top.Size, LeftMW, RightMW);
		}

		if (pGraphics.End_Command)
		{
			pGraphics.End_Command();
		}
	}

	if (true === bDrawBetween)
	{
		RGBA = Pr.ParaPr.Brd.Between.Get_Color(this);
		pGraphics.p_color(RGBA.r, RGBA.g, RGBA.b, 255);
		if (pGraphics.SetBorder)
		{
			pGraphics.SetBorder(Pr.ParaPr.Brd.Between);
		}
		var Size = Pr.ParaPr.Brd.Between.Size;
		var Y    = this.Pages[CurPage].Y + Pr.ParaPr.Spacing.Before;

		// Учтем разрывы из-за обтекания
		var StartLine   = this.Pages[CurPage].StartLine;
		var RangesCount = this.Lines[StartLine].Ranges.length;
		if (pGraphics.Start_Command)
		{
			pGraphics.Start_Command(AscFormat.DRAW_COMMAND_LINE, this.Lines[StartLine], StartLine, 1);
		}
		for (var CurRange = 0; CurRange < RangesCount; CurRange++)
		{
			var X0 = ( 0 === CurRange ? X_left : this.Lines[StartLine].Ranges[CurRange].X );
			var X1 = ( RangesCount - 1 === CurRange ? X_right : this.Lines[StartLine].Ranges[CurRange].XEnd );

			if (false === this.Is_EmptyRange(StartLine, CurRange) || ( true === bEmpty && 1 === RangesCount ))
				pGraphics.drawHorLineExt(c_oAscLineDrawingRule.Top, Y, X0, X1, Size, LeftMW, RightMW);
		}
		if (pGraphics.End_Command)
		{
			pGraphics.End_Command();
		}
	}

	var CurLine = this.Pages[CurPage].EndLine;
	var bEnd    = (this.Lines[CurLine].Info & paralineinfo_End ? true : false);

	var bDrawBottom = false;
	var NextEl      = this.Get_DocumentNext();
	if (border_Single === Pr.ParaPr.Brd.Bottom.Value
		&& true === bEnd
		&& (true === Pr.ParaPr.Brd.Last
		|| type_Table === NextEl.Get_Type()
		|| true === NextEl.private_IsEmptyPageWithBreak(0)))
	{
		bDrawBottom = true;
	}

	if (true === bDrawBottom)
	{
		var TempY        = this.Pages[CurPage].Y;
		var NextEl       = this.Get_DocumentNext();
		var DrawLineRule = c_oAscLineDrawingRule.Bottom;
		if (null != NextEl && type_Paragraph === NextEl.GetType() && true === NextEl.IsStartFromNewPage())
		{
			TempY        = this.Pages[CurPage].Y + this.Lines[CurLine].Y + this.Lines[CurLine].Metrics.Descent + this.Lines[CurLine].Metrics.LineGap;
			DrawLineRule = c_oAscLineDrawingRule.Top;
		}
		else
		{
			TempY        = this.Pages[CurPage].Y + this.Lines[CurLine].Bottom - Pr.ParaPr.Spacing.After;
			DrawLineRule = c_oAscLineDrawingRule.Bottom;
		}

		RGBA = Pr.ParaPr.Brd.Bottom.Get_Color(this);
		pGraphics.p_color(RGBA.r, RGBA.g, RGBA.b, 255);
		if (pGraphics.SetBorder)
		{
			pGraphics.SetBorder(Pr.ParaPr.Brd.Bottom);
		}
		// Учтем разрывы из-за обтекания
		var EndLine     = this.Pages[CurPage].EndLine;
		var RangesCount = this.Lines[EndLine].Ranges.length;
		if (pGraphics.Start_Command)
		{
			pGraphics.Start_Command(AscFormat.DRAW_COMMAND_LINE, this.Lines[EndLine], EndLine, 1);
		}
		for (var CurRange = 0; CurRange < RangesCount; CurRange++)
		{
			var X0 = ( 0 === CurRange ? X_left : this.Lines[EndLine].Ranges[CurRange].X );
			var X1 = ( RangesCount - 1 === CurRange ? X_right : this.Lines[EndLine].Ranges[CurRange].XEnd );

			if (false === this.Is_EmptyRange(EndLine, CurRange) || ( true === bEmpty && 1 === RangesCount ))
				pGraphics.drawHorLineExt(DrawLineRule, TempY, X0, X1, Pr.ParaPr.Brd.Bottom.Size, LeftMW, RightMW);
		}
		if (pGraphics.End_Command)
		{
			pGraphics.End_Command();
		}
	}
};
/**
 * Проверяем является ли данная страница параграфа пустой страницей с разрывом колонки или страницы.
 */
Paragraph.prototype.private_IsEmptyPageWithBreak = function(CurPage)
{
	//if (true === this.IsEmptyPage(CurPage))
	//    return true;

	if (this.Pages[CurPage].EndLine !== this.Pages[CurPage].StartLine)
		return false;

	var Info = this.Lines[this.Pages[CurPage].EndLine].Info;
	if (Info & paralineinfo_Empty && Info & paralineinfo_BreakPage)
		return true;

	return false;
};
Paragraph.prototype.Is_NeedDrawBorders = function()
{
	if (true === this.IsEmpty() && undefined !== this.SectPr)
		return false;

	return true;
};
Paragraph.prototype.ReDraw = function()
{
	this.Parent.OnContentReDraw(this.Get_AbsolutePage(0), this.Get_AbsolutePage(this.Pages.length - 1));
};
Paragraph.prototype.Shift = function(PageIndex, Dx, Dy)
{
	if (0 === PageIndex)
	{
		this.X += Dx;
		this.Y += Dy;
		this.XLimit += Dx;
		this.YLimit += Dy;

		this.X_ColumnStart += Dx;
		this.X_ColumnEnd += Dx;
	}

	this.Pages[PageIndex].Shift(Dx, Dy);

	var StartLine = this.Pages[PageIndex].StartLine;
	var EndLine   = this.Pages[PageIndex].EndLine;

	for (var CurLine = StartLine; CurLine <= EndLine; CurLine++)
		this.Lines[CurLine].Shift(Dx, Dy);

	// Пробегаемся по всем картинкам на данной странице и обновляем координаты
	for (var CurLine = StartLine; CurLine <= EndLine; CurLine++)
	{
		var Line        = this.Lines[CurLine];
		var RangesCount = Line.Ranges.length;

		for (var CurRange = 0; CurRange < RangesCount; CurRange++)
		{
			var Range    = Line.Ranges[CurRange];
			var StartPos = Range.StartPos;
			var EndPos   = Range.EndPos;

			for (var Pos = StartPos; Pos <= EndPos; Pos++)
			{
				var Item = this.Content[Pos];
				Item.Shift_Range(Dx, Dy, CurLine, CurRange);
			}
		}
	}
};
/**
 * Удаляем элементы параграфа
 * @param nCount - количество удаляемых элементов, > 0 удаляем элементы после курсора, < 0 удаляем элементы до курсора
 * @param bOnlyText - true: удаляем только текст и пробелы, false - Удаляем любые элементы
 * @param bRemoveOnlySelection
 * @param bOnAddText - удаление происходит на добавлении текста
 */
Paragraph.prototype.Remove = function(nCount, bOnlyText, bRemoveOnlySelection, bOnAddText)
{
	var Direction = nCount;
	var Result    = true;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;

		if (StartPos > EndPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		// Сразу проверим последний элемент на попадание ParaEnd в селект
		if (EndPos === this.Content.length - 1 && true === this.Content[EndPos].Selection_CheckParaEnd())
		{
			Result = false;

			// Если в данном параграфе было окончание секции, тогда удаляем его
			this.Set_SectionPr(undefined);
		}

		if (StartPos === EndPos)
		{
			this.Content[StartPos].Remove(nCount, bOnAddText);

			// TODO: Как только избавимся от para_End переделать здесь
			// Последние 2 элемента не удаляем (один для para_End, второй для всего остального)
			if (StartPos < this.Content.length - 2 && true === this.Content[StartPos].Is_Empty() && true !== this.Content[StartPos].Is_CheckingNearestPos() && !bOnAddText)
			{
				if (this.Selection.StartPos === this.Selection.EndPos)
					this.Selection.Use = false;

				this.Internal_Content_Remove(StartPos);

				this.CurPos.ContentPos = StartPos;
				this.Content[StartPos].MoveCursorToStartPos();
				this.Correct_ContentPos2();
			}
		}
		else
		{
			// Комментарии удаляем потом отдельно, чтобы не путались метки селекта
			var CommentsToDelete = {};
			for (var Pos = StartPos; Pos <= EndPos; Pos++)
			{
				var Item = this.Content[Pos];
				if (para_Comment === Item.Type)
					CommentsToDelete[Item.CommentId] = true;
			}

			this.DeleteCommentOnRemove = false;

			this.Content[EndPos].Remove(nCount, bOnAddText);

			// TODO: Как только избавимся от para_End переделать здесь
			// Последние 2 элемента не удаляем (один для para_End, второй для всего остального)
			if (EndPos < this.Content.length - 2 && true === this.Content[EndPos].Is_Empty() && true !== this.Content[EndPos].Is_CheckingNearestPos())
			{
				this.Internal_Content_Remove(EndPos);

				this.CurPos.ContentPos = EndPos;
				this.Content[EndPos].MoveCursorToStartPos();
			}

			if (this.LogicDocument && true === this.LogicDocument.Is_TrackRevisions())
			{
				for (var Pos = EndPos - 1; Pos >= StartPos + 1; Pos--)
				{
					if (para_Run == this.Content[Pos].Type && reviewtype_Add === this.Content[Pos].Get_ReviewType())
						this.Internal_Content_Remove2(Pos, 1);
					else
						this.Content[Pos].Set_ReviewType(reviewtype_Remove, false);
				}
			}
			else
				this.Internal_Content_Remove2(StartPos + 1, EndPos - StartPos - 1);

			var isFootnoteRefRun = (para_Run === this.Content[StartPos].Type && this.Content[StartPos].IsFootnoteReferenceRun());

			this.Content[StartPos].Remove(nCount, bOnAddText);

			// Мы не удаляем последний элемент с ParaEnd
			if (StartPos <= this.Content.length - 2 && true === this.Content[StartPos].Is_Empty() && true !== this.Content[StartPos].Is_CheckingNearestPos() && ((nCount > -1 && true !== bOnAddText) || para_Run !== this.Content[StartPos].Type))
			{
				if (this.Selection.StartPos === this.Selection.EndPos)
					this.Selection.Use = false;

				this.Internal_Content_Remove(StartPos);
			}
			else if (isFootnoteRefRun)
			{
				this.Content[StartPos].Set_RStyle(undefined);
			}

			if (this.LogicDocument && true === this.LogicDocument.Is_TrackRevisions())
			{
				var _StartPos = Math.max(0, StartPos);
				var _EndPos   = Math.min(this.Content.length - 1, EndPos);

				for (var Pos = _StartPos; Pos <= _EndPos; ++Pos)
				{
					this.Content[Pos].RemoveSelection();
				}

				this.CurPos.ContentPos = StartPos;
			}

			if (nCount > -1 && true !== bOnAddText)
			{
				this.Correct_ContentPos2();
			}
			else
			{
				this.CurPos.ContentPos  = StartPos;
				this.Selection.StartPos = StartPos;
				this.Selection.EndPos   = StartPos;
			}

			this.DeleteCommentOnRemove = true;

			for (var CommentId in CommentsToDelete)
			{
				this.LogicDocument.RemoveComment(CommentId, true, false);
			}
		}

		if (true !== this.Content[this.CurPos.ContentPos].IsSelectionUse())
		{
			this.RemoveSelection();

			if (nCount > -1 && true !== bOnAddText)
				this.Correct_Content();
		}
		else
		{
			this.Selection.Use      = true;
			this.Selection.Start    = false;
			this.Selection.Flag     = selectionflag_Common;
			this.Selection.StartPos = this.CurPos.ContentPos;
			this.Selection.EndPos   = this.CurPos.ContentPos;

			if (nCount > -1 && true !== bOnAddText)
				this.Correct_Content();

			this.Document_SetThisElementCurrent(false);

			return true;
		}
	}
	else
	{
		var ContentPos = this.CurPos.ContentPos;

		while (false === this.Content[ContentPos].Remove(Direction, bOnAddText))
		{
			if (Direction < 0)
				ContentPos--;
			else
				ContentPos++;

			if (ContentPos < 0 || ContentPos >= this.Content.length)
				break;

			if (Direction < 0)
				this.Content[ContentPos].MoveCursorToEndPos(false);
			else
				this.Content[ContentPos].MoveCursorToStartPos();

		}

		if (ContentPos < 0 || ContentPos >= this.Content.length)
			Result = false;
		else
		{
			if (true === this.Content[ContentPos].IsSelectionUse())
			{
				this.Selection.Use      = true;
				this.Selection.Start    = false;
				this.Selection.Flag     = selectionflag_Common;

				// TODO: Это плохой код, внутри классов должен выставляться селект целиком
				//       надо посмотреть для чего это было сделано

				//this.Selection.StartPos = ContentPos;
				//this.Selection.EndPos   = ContentPos;
				//this.Correct_Content(ContentPos, ContentPos);
				//this.Document_SetThisElementCurrent(false);
				return true;
			}

			// TODO: Как только избавимся от para_End переделать здесь
			// Последние 2 элемента не удаляем (один для para_End, второй для всего остального)
			if (ContentPos < this.Content.length - 2 && true === this.Content[ContentPos].Is_Empty())
			{
				this.Internal_Content_Remove(ContentPos);

				this.CurPos.ContentPos = ContentPos;
				this.Content[ContentPos].MoveCursorToStartPos();
				this.Correct_ContentPos2();
			}
			else
			{
				// TODO: В режиме рецензии элементы не удаляются, а позиция меняется прямо в ранах
				if (!this.LogicDocument || true !== this.LogicDocument.Is_TrackRevisions())
					this.CurPos.ContentPos = ContentPos;
			}
		}

		this.Correct_Content(ContentPos, ContentPos);

		if (Direction < 0 && false === Result)
		{
			// Мы стоим в начале параграфа и пытаемся удалить элемент влево. Действуем следующим образом:
			// 1. Если у нас параграф с нумерацией.
			//    1.1 Если нумерация нулевого уровня, тогда удаляем нумерацию, но при этом сохраняем
			//        значения отступов так как это делается в Word. (аналогично работаем с нумерацией в
			//        презентациях)
			//    1.2 Если нумерация не нулевого уровня, тогда уменьшаем уровень.
			// 2. Если у нас отступ первой строки ненулевой, тогда:
			//    2.1 Если он положительный делаем его нулевым.
			//    2.2 Если он отрицательный сдвигаем левый отступ на значение отступа первой строки,
			//        а сам отступ первой строки делаем нулевым.
			// 3. Если у нас ненулевой левый отступ, делаем его нулевым
			// 4. Если ничего из предыдущего не случается, тогда говорим родительскому классу, что удаление
			//    не было выполнено.

			Result = true;

			var Pr = this.Get_CompiledPr2(false).ParaPr;
			if (undefined != this.GetNumPr())
			{
				var NumPr = this.GetNumPr();

				if (0 === NumPr.Lvl)
				{
					this.RemoveNumPr();
					this.Set_Ind({FirstLine : 0, Left : Math.max(Pr.Ind.Left, Pr.Ind.Left + Pr.Ind.FirstLine)}, false);
				}
				else
				{
					this.IndDecNumberingLevel(false);
				}
			}
			else if (numbering_presentationnumfrmt_None != this.PresentationPr.Bullet.Get_Type())
			{
				this.Remove_PresentationNumbering();
			}
			else if(this.bFromDocument)
			{
             	if (align_Right === Pr.Jc)
                {
                    this.Set_Align(align_Center);
                }
                else if (align_Center === Pr.Jc)
                {
                    this.Set_Align(align_Left);
                }
                else if (Math.abs(Pr.Ind.FirstLine) > 0.001)
                {
                    if (Pr.Ind.FirstLine > 0)
                        this.Set_Ind({FirstLine : 0}, false);
                    else
                        this.Set_Ind({Left : Pr.Ind.Left + Pr.Ind.FirstLine, FirstLine : 0}, false);
                }
                else if (Math.abs(Pr.Ind.Left) > 0.001)
                {
                    this.Set_Ind({Left : 0}, false);
                }
                else
				{
                    Result = false;
				}
			}
			else
			{
                Result = false;
			}
		}
	}

	return Result;
};
Paragraph.prototype.Remove_ParaEnd = function()
{
	var ContentLen = this.Content.length;
	for (var CurPos = ContentLen - 1; CurPos >= 0; CurPos--)
	{
		var Element = this.Content[CurPos];

		// Предполагаем, что para_End лежит только в ране, который лежит только на самом верхнем уровне
		if (para_Run === Element.Type && true === Element.Remove_ParaEnd())
			return;
	}
};
/**
 * TODO: От этой функции надо избавиться
 * Ищем первый элемент, при промотке вперед
 */
Paragraph.prototype.Internal_FindForward = function(CurPos, arrId)
{
	var LetterPos = CurPos;
	var bFound    = false;
	var Type      = para_Unknown;

	if (CurPos < 0 || CurPos >= this.Content.length)
		return {Found : false};

	while (!bFound)
	{
		Type = this.Content[LetterPos].Type;

		for (var Id = 0; Id < arrId.length; Id++)
		{
			if (arrId[Id] == Type)
			{
				bFound = true;
				break;
			}
		}

		if (bFound)
			break;

		LetterPos++;
		if (LetterPos > this.Content.length - 1)
			break;
	}

	return {LetterPos : LetterPos, Found : bFound, Type : Type};
};
/**
 * TODO: От этой функции надо избавиться
 * Ищем первый элемент, при промотке назад
 *
 */
Paragraph.prototype.Internal_FindBackward = function(CurPos, arrId)
{
	var LetterPos = CurPos;
	var bFound    = false;
	var Type      = para_Unknown;

	if (CurPos < 0 || CurPos >= this.Content.length)
		return {Found : false};

	while (!bFound)
	{
		Type = this.Content[LetterPos].Type;
		for (var Id = 0; Id < arrId.length; Id++)
		{
			if (arrId[Id] == Type)
			{
				bFound = true;
				break;
			}
		}

		if (bFound)
			break;

		LetterPos--;
		if (LetterPos < 0)
			break;
	}

	return {LetterPos : LetterPos, Found : bFound, Type : Type};
};
Paragraph.prototype.Get_TextPr = function(_ContentPos)
{
	var ContentPos = ( undefined === _ContentPos ? this.Get_ParaContentPos(false, false) : _ContentPos );

	var CurPos = ContentPos.Get(0);

	return this.Content[CurPos].Get_TextPr(ContentPos, 1);
};
Paragraph.prototype.Internal_CalculateTextPr = function(LetterPos, StartPr)
{
	var Pr;
	if ("undefined" != typeof(StartPr))
	{
		Pr             = this.Get_CompiledPr();
		StartPr.ParaPr = Pr.ParaPr;
		StartPr.TextPr = Pr.TextPr;
	}
	else
	{
		Pr = this.Get_CompiledPr2(false);
	}

	// Выствляем начальные настройки текста у данного параграфа
	var TextPr = Pr.TextPr.Copy();

	// Ищем ближайший TextPr
	if (LetterPos < 0)
		return TextPr;

	// Ищем предыдущие записи с изменением текстовых свойств
	var Pos = this.Internal_FindBackward(LetterPos, [para_TextPr]);

	if (true === Pos.Found)
	{
		var CurTextPr = this.Content[Pos.LetterPos].Value;

		// Копируем настройки из символьного стиля
		if (undefined != CurTextPr.RStyle)
		{
			var Styles      = this.Parent.Get_Styles();
			var StyleTextPr = Styles.Get_Pr(CurTextPr.RStyle, styletype_Character).TextPr;
			TextPr.Merge(StyleTextPr);
		}

		// Копируем прямые настройки
		TextPr.Merge(CurTextPr);
	}

	TextPr.FontFamily.Name  = TextPr.RFonts.Ascii.Name;
	TextPr.FontFamily.Index = TextPr.RFonts.Ascii.Index;

	return TextPr;
};
Paragraph.prototype.Internal_GetLang = function(LetterPos)
{
	var Lang = this.Get_CompiledPr2(false).TextPr.Lang.Copy();

	// Ищем ближайший TextPr
	if (LetterPos < 0)
		return Lang;

	// Ищем предыдущие записи с изменением текстовых свойств
	var Pos = this.Internal_FindBackward(LetterPos, [para_TextPr]);

	if (true === Pos.Found)
	{
		var CurTextPr = this.Content[Pos.LetterPos].Value;

		// Копируем настройки из символьного стиля
		if (undefined != CurTextPr.RStyle)
		{
			var Styles      = this.Parent.Get_Styles();
			var StyleTextPr = Styles.Get_Pr(CurTextPr.RStyle, styletype_Character).TextPr;
			Lang.Merge(StyleTextPr.Lang);
		}

		// Копируем прямые настройки
		Lang.Merge(CurTextPr.Lang);
	}

	return Lang;
};
Paragraph.prototype.Internal_GetTextPr = function(LetterPos)
{
	var TextPr = new CTextPr();

	// Ищем ближайший TextPr
	if (LetterPos < 0)
		return TextPr;

	// Ищем предыдущие записи с изменением текстовых свойств
	var Pos = this.Internal_FindBackward(LetterPos, [para_TextPr]);

	if (true === Pos.Found)
	{
		var CurTextPr = this.Content[Pos.LetterPos].Value;
		TextPr.Merge(CurTextPr);
	}
	// Если ничего не нашли, то TextPr будет пустым, что тоже нормально

	return TextPr;
};
/**
 * Добавляем новый элемент к содержимому параграфа (на текущую позицию)
 */
Paragraph.prototype.Add = function(Item)
{
	// Выставляем родительский класс
	Item.Parent = this;

	if (Item.SetParagraph)
		Item.SetParagraph(this);

	switch (Item.Get_Type())
	{
		case para_Text:
		case para_Space:
		case para_PageNum:
		case para_Tab:
		case para_Drawing:
		case para_NewLine:
		case para_FootnoteReference:
		case para_FootnoteRef:
		case para_Separator:
		case para_ContinuationSeparator:
		default:
		{
			// Элементы данного типа добавляем во внутренний элемент
			this.Content[this.CurPos.ContentPos].Add(Item);

			break;
		}
		case para_TextPr:
		{
			var TextPr = Item.Value;

			if (undefined != TextPr.FontFamily)
			{
				var FName  = TextPr.FontFamily.Name;
				var FIndex = TextPr.FontFamily.Index;

				TextPr.RFonts          = new CRFonts();
				TextPr.RFonts.Ascii    = {Name : FName, Index : FIndex};
				TextPr.RFonts.EastAsia = {Name : FName, Index : FIndex};
				TextPr.RFonts.HAnsi    = {Name : FName, Index : FIndex};
				TextPr.RFonts.CS       = {Name : FName, Index : FIndex};
			}

			if (true === this.ApplyToAll)
			{
				// Применяем настройки ко всем элементам параграфа
				var ContentLen = this.Content.length;

				for (var CurPos = 0; CurPos < ContentLen; CurPos++)
				{
					this.Content[CurPos].Apply_TextPr(TextPr, undefined, true);
				}

				// Выставляем настройки для символа параграфа
				this.TextPr.Apply_TextPr(TextPr);
			}
			else
			{
				if (true === this.Selection.Use)
				{
					this.Apply_TextPr(TextPr);
				}
				else
				{
					var CurParaPos = this.Get_ParaContentPos(false, false);
					var CurPos     = CurParaPos.Get(0);

					// Сначала посмотрим на элемент слева и справа(текущий)
					var SearchLPos = new CParagraphSearchPos();
					this.Get_LeftPos(SearchLPos, CurParaPos);

					var RItem = this.Get_RunElementByPos(CurParaPos);
					var LItem = ( false === SearchLPos.Found ? null : this.Get_RunElementByPos(SearchLPos.Pos) );

					// 1. Если мы находимся в конце параграфа, тогда применяем заданную настройку к знаку параграфа
					//    и добавляем пустой ран с заданными настройками.
					// 2. Если мы находимся в середине слова (справа и слева текстовый элемент, причем оба не
					// пунктуация), тогда меняем настройки для данного слова. 3. Во всех остальных случаях вставляем
					// пустой ран с заданными настройкми и переносим курсор в этот ран, чтобы при последующем наборе
					// текст отрисовывался с нужными настройками.

					if (null === RItem || para_End === RItem.Type)
					{
						this.Apply_TextPr(TextPr);

						// Если параграф с нумерацией, тогда к символу конца параграфа не применяем стиль
						if (undefined === this.GetNumPr())
							this.TextPr.Apply_TextPr(TextPr);
					}
					else if (null !== RItem && null !== LItem && para_Text === RItem.Type && para_Text === LItem.Type && false === RItem.Is_Punctuation() && false === LItem.Is_Punctuation())
					{
						var SearchSPos = new CParagraphSearchPos();
						var SearchEPos = new CParagraphSearchPos();

						this.Get_WordStartPos(SearchSPos, CurParaPos);
						this.Get_WordEndPos(SearchEPos, CurParaPos);

						// Такого быть не должно, т.к. мы уже проверили, что справа и слева точно есть текст
						if (true !== SearchSPos.Found || true !== SearchEPos.Found)
							return;

						// Выставим временно селект от начала и до конца слова
						this.Selection.Use = true;
						this.Set_SelectionContentPos(SearchSPos.Pos, SearchEPos.Pos);

						this.Apply_TextPr(TextPr);

						// Убираем селект
						this.RemoveSelection();
					}
					else
					{
						this.Apply_TextPr(TextPr);
					}
				}
			}

			break;
		}
		case para_Math:
		{
			var ContentPos = this.Get_ParaContentPos(false, false);
			var CurPos     = ContentPos.Get(0);

			// Ран формула делит на части, а в остальные элементы формула добавляется целиком.
			if (para_Run === this.Content[CurPos].Type)
			{
				// Разделяем текущий элемент (возвращается правая часть)
				var NewElement = this.Content[CurPos].Split(ContentPos, 1);

				if (null !== NewElement)
					this.Internal_Content_Add(CurPos + 1, NewElement);

				var MathElement = new ParaMath();
				MathElement.Root.Load_FromMenu(Item.Menu, this);
				MathElement.Root.Correct_Content(true);

				this.Internal_Content_Add(CurPos + 1, MathElement);

				// Перемещаем кусор в конец формулы
				this.CurPos.ContentPos = CurPos + 1;
				this.Content[this.CurPos.ContentPos].MoveCursorToEndPos(false);
			}
			else
				this.Content[CurPos].Add(Item);

			break;
		}
		case para_Field:
		case para_InlineLevelSdt:
		case para_Hyperlink:
		{
			var ContentPos = this.Get_ParaContentPos(false, false);
			var CurPos     = ContentPos.Get(0);

			// Формулу и ран поле делит на части, в остальные элементы добавляется целиком.
			if (para_Run === this.Content[CurPos].Type || para_Math === this.Content[CurPos].Type)
			{
				// Разделяем текущий элемент (возвращается правая часть)
				var NewElement = this.Content[CurPos].Split(ContentPos, 1);

				if (null !== NewElement)
					this.Internal_Content_Add(CurPos + 1, NewElement);

				this.Internal_Content_Add(CurPos + 1, Item);

				// Перемещаем в начало следующейго элемента
				this.CurPos.ContentPos = CurPos + 2;
				this.Content[this.CurPos.ContentPos].MoveCursorToStartPos(false);
			}
			else
			{
				this.Content[CurPos].Add(Item);
			}

			break;
		}
		case para_Run :
		{
			var ContentPos = this.Get_ParaContentPos(false, false);
			var CurPos     = ContentPos.Get(0);

			var CurItem = this.Content[CurPos];

			switch (CurItem.Type)
			{
				case para_Run :
				{
					var NewRun = CurItem.Split(ContentPos, 1);

					this.Internal_Content_Add(CurPos + 1, Item);
					this.Internal_Content_Add(CurPos + 2, NewRun);
					this.CurPos.ContentPos = CurPos + 1;
					break;
				}

				case para_Math:
				case para_Hyperlink:
				{
					CurItem.Add(Item);
					break;
				}

				default:
				{
					this.Internal_Content_Add(CurPos + 1, Item);
					this.CurPos.ContentPos = CurPos + 1;
					break;
				}
			}

			Item.MoveCursorToEndPos(false);

			break;
		}
	}
};
/**
 * Данная функция вызывается, когда уже точно известно, что у нас либо выделение начинается с начала параграфа, либо мы
 * стоим курсором в начале параграфа
 * @param bShift
 */
Paragraph.prototype.Add_Tab = function(bShift)
{
	var NumPr = this.GetNumPr();

	if (undefined !== this.GetNumPr())
	{
		this.Shift_NumberingLvl(bShift);
	}
	else if (true === this.IsSelectionUse())
	{
		this.IncreaseDecreaseIndent(!bShift);
	}
	else
	{
		var ParaPr = this.Get_CompiledPr2(false).ParaPr;

		var nDefaultTabStop = AscCommonWord.Default_Tab_Stop;
		if (nDefaultTabStop < 0.001)
			return;

		var LD_PageFields = this.LogicDocument.Get_PageFields(this.Get_AbsolutePage(0));

		var nLeft  = ParaPr.Ind.Left;
		var nFirst = ParaPr.Ind.FirstLine;
		if (true != bShift)
		{
			if (nFirst < -0.001)
			{
				if (nLeft < -0.001)
				{
					this.Set_Ind({FirstLine : 0}, false);
				}
				else if (nLeft + nFirst < -0.001)
				{
					this.Set_Ind({FirstLine : -nLeft}, false);
				}
				else
				{
					var nNewPos = ((((nFirst + nLeft) / nDefaultTabStop + 0.5) | 0) + 1) * nDefaultTabStop;
					if (nNewPos < nLeft)
						this.Set_Ind({FirstLine : nNewPos - nLeft}, false);
					else
						this.Set_Ind({FirstLine : 0}, false);
				}
			}
			else
			{
				var nCurTabPos = (((nFirst + nLeft) / nDefaultTabStop + 0.001) | 0) * nDefaultTabStop;

				if (LD_PageFields.XLimit - LD_PageFields.X - ParaPr.Ind.Right < nLeft + nFirst + 1.5 * nDefaultTabStop)
					return;

				if (nLeft + nFirst < nCurTabPos - 0.001)
				{
					this.Set_Ind({FirstLine : (((nFirst + nLeft) / nDefaultTabStop + 0.001) | 0) * nDefaultTabStop - nLeft}, false);
				}
				else
				{
					if (Math.abs((((nFirst + nLeft) / nDefaultTabStop + 0.001) | 0) * nDefaultTabStop - (((nLeft) / nDefaultTabStop + 0.001) | 0) * nDefaultTabStop) < 0.001 && nFirst < nDefaultTabStop)
						this.Set_Ind({FirstLine : ((((nFirst + nLeft) / nDefaultTabStop + 0.001) | 0) + 1) * nDefaultTabStop - nLeft}, false);
					else
						this.Set_Ind({Left : ((((nFirst + nLeft) / nDefaultTabStop + 0.001) | 0) + 1) * nDefaultTabStop - nFirst}, false);
				}
			}
		}
		else
		{
			if (Math.abs(nFirst) < 0.001)
			{
				if (Math.abs(nLeft) < 0.001)
					return;
				else if (nLeft > 0)
				{
					var nCurTabPos = ((nLeft / nDefaultTabStop + 0.001) | 0) * nDefaultTabStop;
					if (Math.abs(nCurTabPos - nLeft) < 0.001)
						this.Set_Ind({Left : (((nLeft / nDefaultTabStop + 0.001) | 0) - 1) * nDefaultTabStop}, false);
					else
						this.Set_Ind({Left : nCurTabPos}, false);
				}
				else
				{
					this.Set_Ind({Left : 0}, false);
				}
			}
			else if (nFirst > 0)
			{
				var nCurTabPos = (((nFirst + nLeft) / nDefaultTabStop + 0.001) | 0) * nDefaultTabStop;
				if (Math.abs(nLeft + nFirst - nCurTabPos) < 0.001)
				{
					var nPrevTabPos = Math.max(0, ((((nFirst + nLeft) / nDefaultTabStop + 0.001) | 0) - 1) * nDefaultTabStop);
					if (nPrevTabPos > nLeft)
						this.Set_Ind({FirstLine : nPrevTabPos - nLeft}, false);
					else
						this.Set_Ind({FirstLine : 0}, false);

				}
				else
				{
					this.Set_Ind({FirstLine : nCurTabPos - nLeft}, false);
				}
			}
			else
			{
				if (Math.abs(nFirst + nLeft) < 0.001)
				{
					return;
				}
				else if (nFirst + nLeft < 0)
				{
					this.Set_Ind({Left : -nFirst}, false);
				}
				else
				{
					var nCurTabPos = (((nFirst + nLeft) / nDefaultTabStop + 0.001) | 0) * nDefaultTabStop;
					if (Math.abs(nLeft + nFirst - nCurTabPos) < 0.001)
					{
						var nPrevTabPos = Math.max(0, ((((nFirst + nLeft) / nDefaultTabStop + 0.001) | 0) - 1) * nDefaultTabStop);
						this.Set_Ind({Left : nPrevTabPos - nFirst}, false);
					}
					else
					{
						this.Set_Ind({Left : nCurTabPos - nFirst}, false);
					}
				}
			}
		}

		this.CompiledPr.NeedRecalc = true;
	}
};
/**
 * Расширяем параграф до позиции X
 */
Paragraph.prototype.Extend_ToPos = function(_X)
{
	var CompiledPr = this.Get_CompiledPr2(false).ParaPr;
	var Page       = this.Pages[this.Pages.length - 1];

	var X0 = Page.X;
	var X1 = Page.XLimit - X0;
	var X  = _X - X0;

	var Align = CompiledPr.Jc;

	if (X < 0 || X > X1 || ( X < 7.5 && align_Left === Align ) || ( X > X1 - 10 && align_Right === Align ) || ( Math.abs(X1 / 2 - X) < 10 && align_Center === Align ))
		return false;

	if (true === this.IsEmpty())
	{
		if (align_Left !== Align)
		{
			this.Set_Align(align_Left);
		}

		if (Math.abs(X - X1 / 2) < 12.5)
		{
			this.Set_Align(align_Center);
			return true;
		}
		else if (X > X1 - 12.5)
		{
			this.Set_Align(align_Right);
			return true;
		}
		else if (X < 17.5)
		{
			this.Set_Ind({FirstLine : 12.5}, false);
			return true;
		}
	}

	var Tabs = CompiledPr.Tabs.Copy();

	if (Math.abs(X - X1 / 2) < 12.5)
		Tabs.Add(new CParaTab(tab_Center, X1 / 2));
	else if (X > X1 - 12.5)
		Tabs.Add(new CParaTab(tab_Right, X1 - 0.001));
	else
		Tabs.Add(new CParaTab(tab_Left, X));

	this.Set_Tabs(Tabs);

	this.Set_ParaContentPos(this.Get_EndPos(false), false, -1, -1);
	this.Add(new ParaTab());

	return true;
};
Paragraph.prototype.IncDec_FontSize = function(bIncrease)
{
	if (true === this.ApplyToAll)
	{
		// Применяем настройки ко всем элементам параграфа
		var ContentLen = this.Content.length;

		for (var CurPos = 0; CurPos < ContentLen; CurPos++)
		{
			this.Content[CurPos].Apply_TextPr(undefined, bIncrease, true);
		}
	}
	else
	{
		if (true === this.Selection.Use)
		{
			this.Apply_TextPr(undefined, bIncrease, false);
		}
		else
		{
			var CurParaPos = this.Get_ParaContentPos(false, false);
			var CurPos     = CurParaPos.Get(0);

			// Сначала посмотрим на элемент слева и справа(текущий)
			var SearchLPos = new CParagraphSearchPos();
			this.Get_LeftPos(SearchLPos, CurParaPos);

			var RItem = this.Get_RunElementByPos(CurParaPos);
			var LItem = ( false === SearchLPos.Found ? null : this.Get_RunElementByPos(SearchLPos.Pos) );

			// 1. Если мы находимся в конце параграфа, тогда применяем заданную настройку к знаку параграфа
			//    и добавляем пустой ран с заданными настройками.
			// 2. Если мы находимся в середине слова (справа и слева текстовый элемент, причем оба не пунктуация),
			//    тогда меняем настройки для данного слова.
			// 3. Во всех остальных случаях вставляем пустой ран с заданными настройкми и переносим курсор в этот
			//    ран, чтобы при последующем наборе текст отрисовывался с нужными настройками.

			if (null === RItem || para_End === RItem.Type)
			{
				// Изменение настройки для символа параграфа делается внутри
				this.Apply_TextPr(undefined, bIncrease, false);
			}
			else if (null !== RItem && null !== LItem && para_Text === RItem.Type && para_Text === LItem.Type && false === RItem.Is_Punctuation() && false === LItem.Is_Punctuation())
			{
				var SearchSPos = new CParagraphSearchPos();
				var SearchEPos = new CParagraphSearchPos();

				this.Get_WordStartPos(SearchSPos, CurParaPos);
				this.Get_WordEndPos(SearchEPos, CurParaPos);

				// Такого быть не должно, т.к. мы уже проверили, что справа и слева точно есть текст
				if (true !== SearchSPos.Found || true !== SearchEPos.Found)
					return;

				// Выставим временно селект от начала и до конца слова
				this.Selection.Use = true;
				this.Set_SelectionContentPos(SearchSPos.Pos, SearchEPos.Pos);

				this.Apply_TextPr(undefined, bIncrease, false);

				// Убираем селект
				this.RemoveSelection();
			}
			else
			{
				this.Apply_TextPr(undefined, bIncrease, false);
			}
		}
	}

	return true;
};
Paragraph.prototype.Shift_NumberingLvl = function(bShift)
{
	var NumPr = this.GetNumPr();
	if (!NumPr)
		return;

	if (true != this.Selection.Use)
	{
		var NumId   = NumPr.NumId;
		var Lvl     = NumPr.Lvl;
		var NumInfo = this.Parent.CalculateNumberingValues(this, NumPr);

		if (0 === Lvl && NumInfo[Lvl] <= 1)
		{
			var oNumbering = this.Parent.GetNumbering();
			var oNum       = oNumbering.GetNum(NumId);

			var NumLvl    = oNum.GetLvl(Lvl);
			var NumParaPr = NumLvl.GetParaPr();

			var ParaPr = this.Get_CompiledPr2(false).ParaPr;

			if (undefined != NumParaPr.Ind && undefined != NumParaPr.Ind.Left)
			{
				var NewX = ParaPr.Ind.Left;
				if (true != bShift)
					NewX += AscCommonWord.Default_Tab_Stop;
				else
				{
					NewX -= AscCommonWord.Default_Tab_Stop;

					if (NewX < 0)
						NewX = 0;

					if (ParaPr.Ind.FirstLine < 0 && NewX + ParaPr.Ind.FirstLine < 0)
						NewX = -ParaPr.Ind.FirstLine;
				}

				oNum.ShiftLeftInd(NewX);

				this.private_AddPrChange();
				History.Add(new CChangesParagraphIndFirst(this, this.Pr.Ind.FirstLine, undefined));
				History.Add(new CChangesParagraphIndLeft(this, this.Pr.Ind.Left, undefined));

				// При добавлении списка в параграф, удаляем все собственные сдвиги
				this.Pr.Ind.FirstLine = undefined;
				this.Pr.Ind.Left      = undefined;

				// Надо пересчитать конечный стиль
				this.CompiledPr.NeedRecalc = true;

				this.private_UpdateTrackRevisionOnChangeParaPr(true);
			}
		}
		else
			this.IndDecNumberingLevel(!bShift);
	}
	else
		this.IndDecNumberingLevel(!bShift);
};
Paragraph.prototype.Can_IncreaseLevel = function(bIncrease)
{
	var CurLevel = AscFormat.isRealNumber(this.Pr.Lvl) ? this.Pr.Lvl : 0, NewPr, OldPr = this.Get_CompiledPr2(false).TextPr, DeltaFontSize, i, j, RunPr;
	if (bIncrease)
	{
		if (CurLevel >= 8)
		{
			return false;
		}
		NewPr = this.Internal_CompiledParaPrPresentation(CurLevel + 1).TextPr;
	}
	else
	{
		if (CurLevel <= 0)
		{
			return false;
		}
		NewPr = this.Internal_CompiledParaPrPresentation(CurLevel - 1).TextPr;
	}
	DeltaFontSize = NewPr.FontSize - OldPr.FontSize;
	if (this.Pr.DefaultRunPr && AscFormat.isRealNumber(this.Pr.DefaultRunPr.FontSize))
	{
		if (this.Pr.DefaultRunPr.FontSize + DeltaFontSize < 1)
		{
			return false;
		}
	}
	if (AscFormat.isRealNumber(this.TextPr.FontSize))
	{
		if (this.TextPr.FontSize + DeltaFontSize < 1)
		{
			return false;
		}
	}
	for (i = 0; i < this.Content.length; ++i)
	{
		if (this.Content[i].Type === para_Run)
		{
			RunPr = this.Content[i].Get_CompiledPr();
			if (RunPr.FontSize + DeltaFontSize < 1)
			{
				return false;
			}
		}
		else if (this.Content[i].Type === para_Hyperlink)
		{
			for (j = 0; j < this.Content[i].Content.length; ++j)
			{
				if (this.Content[i].Content[j].Type === para_Run)
				{
					RunPr = this.Content[i].Content[j].Get_CompiledPr();
					if (RunPr.FontSize + DeltaFontSize < 1)
					{
						return false;
					}
				}
			}
		}
	}
	return true;
};
Paragraph.prototype.Increase_Level = function(bIncrease)
{
	var CurLevel = AscFormat.isRealNumber(this.Pr.Lvl) ? this.Pr.Lvl : 0, NewPr, OldPr = this.Get_CompiledPr2(false).TextPr, DeltaFontSize, i, j, RunPr;
	if (bIncrease)
	{
		NewPr = this.Internal_CompiledParaPrPresentation(CurLevel + 1).TextPr;
		if (this.Pr.Ind && this.Pr.Ind.Left != undefined)
		{
			this.Set_Ind({FirstLine : this.Pr.Ind.FirstLine, Left : this.Pr.Ind.Left + 11.1125}, false);
		}
		this.Set_PresentationLevel(CurLevel + 1);
	}
	else
	{
		NewPr = this.Internal_CompiledParaPrPresentation(CurLevel - 1).TextPr;
		if (this.Pr.Ind && this.Pr.Ind.Left != undefined)
		{
			this.Set_Ind({FirstLine : this.Pr.Ind.FirstLine, Left : this.Pr.Ind.Left - 11.1125}, false);
		}
		this.Set_PresentationLevel(CurLevel - 1);
	}
	DeltaFontSize = NewPr.FontSize - OldPr.FontSize;
	if (DeltaFontSize !== 0)
	{
		if (this.Pr.DefaultRunPr && AscFormat.isRealNumber(this.Pr.DefaultRunPr.FontSize))
		{
			var NewParaPr = this.Pr.Copy();
			NewParaPr.DefaultRunPr.FontSize += DeltaFontSize;
			this.Set_Pr(NewParaPr);//Todo: сделать отдельный метод для выставления DefaultRunPr
		}
		if (AscFormat.isRealNumber(this.TextPr.FontSize))
		{
			this.TextPr.Set_FontSize(this.TextPr.FontSize + DeltaFontSize);
		}
		for (i = 0; i < this.Content.length; ++i)
		{
			if (this.Content[i].Type === para_Run)
			{
				if (AscFormat.isRealNumber(this.Content[i].Pr.FontSize))
				{
					this.Content[i].Set_FontSize(this.Content[i].Pr.FontSize + DeltaFontSize);
				}
			}
			else if (this.Content[i].Type === para_Hyperlink)
			{
				for (j = 0; j < this.Content[i].Content.length; ++j)
				{
					if (this.Content[i].Content[j].Type === para_Run)
					{
						if (AscFormat.isRealNumber(this.Content[i].Content[j].Pr.FontSize))
						{
							this.Content[i].Content[j].Set_FontSize(this.Content[i].Content[j].Pr.FontSize + DeltaFontSize);
						}
					}
				}
			}
		}
	}
};
Paragraph.prototype.IncreaseDecreaseIndent = function(bIncrease)
{
	if (undefined !== this.GetNumPr())
	{
		this.Shift_NumberingLvl(!bIncrease);
	}
	else
	{
		var ParaPr = this.Get_CompiledPr2(false).ParaPr;

		var LeftMargin = ParaPr.Ind.Left;
		if (UnknownValue === LeftMargin)
			LeftMargin = 0;
		else if (LeftMargin < 0)
		{
			this.Set_Ind({Left : 0}, false);
			return;
		}

		var LeftMargin_new = 0;
		if (true === bIncrease)
		{
			if (LeftMargin >= 0)
			{
				LeftMargin     = 12.5 * parseInt(10 * LeftMargin / 125);
				LeftMargin_new = ( (LeftMargin - (10 * LeftMargin) % 125 / 10) / 12.5 + 1) * 12.5;
			}

			if (LeftMargin_new < 0)
				LeftMargin_new = 12.5;
		}
		else
		{
			var TempValue  = (125 - (10 * LeftMargin) % 125);
			TempValue      = ( 125 === TempValue ? 0 : TempValue );
			LeftMargin_new = Math.max(( (LeftMargin + TempValue / 10) / 12.5 - 1 ) * 12.5, 0);
		}

		this.Set_Ind({Left : LeftMargin_new}, false);
	}

	var NewPresLvl = ( true === bIncrease ? Math.min(8, this.PresentationPr.Level + 1) : Math.max(0, this.PresentationPr.Level - 1) );
	this.Set_PresentationLevel(NewPresLvl);
};
/**
 * Корректируем позицию курсора: Если курсор находится в начале какого-либо рана, тогда мы его двигаем в конец
 * предыдущего рана
 */
Paragraph.prototype.Correct_ContentPos = function(CorrectEndLinePos)
{
	var Count  = this.Content.length;
	var CurPos = this.CurPos.ContentPos;

	// Если курсор попадает на конец строки, тогда мы его переносим в начало следующей
	if (true === CorrectEndLinePos && true === this.Content[CurPos].Cursor_Is_End())
	{
		var _CurPos = CurPos + 1;

		// Пропускаем пустые раны
		while (_CurPos < Count && true === this.Content[_CurPos].Is_Empty({SkipAnchor : true}))
			_CurPos++;

		if (_CurPos < Count && true === this.Content[_CurPos].Is_StartFromNewLine())
		{
			CurPos = _CurPos;
			this.Content[CurPos].MoveCursorToStartPos();
		}
	}

	while (CurPos > 0 && true === this.Content[CurPos].Cursor_Is_NeededCorrectPos() && para_Run === this.Content[CurPos - 1].Type)
	{
		CurPos--;
		this.Content[CurPos].MoveCursorToEndPos();
	}

	this.CurPos.ContentPos = CurPos;
};
Paragraph.prototype.Correct_ContentPos2 = function()
{
	var Count  = this.Content.length;
	var CurPos = Math.min(Math.max(0, this.CurPos.ContentPos), Count - 1);

	// Может так случиться, что текущий элемент окажется непригодным для расположения курсора, тогда мы ищем ближайший
	// пригодный
	while (CurPos > 0 && false === this.Content[CurPos].Is_CursorPlaceable())
	{
		CurPos--;
		this.Content[CurPos].MoveCursorToEndPos();
	}

	while (CurPos < Count && false === this.Content[CurPos].Is_CursorPlaceable())
	{
		CurPos++;
		this.Content[CurPos].MoveCursorToStartPos(false);
	}

	// Если курсор находится в начале или конце гиперссылки, тогда выводим его из гиперссылки
	while (CurPos > 0 && para_Run !== this.Content[CurPos].Type && para_Math !== this.Content[CurPos].Type && para_Field !== this.Content[CurPos].Type && para_InlineLevelSdt !== this.Content[CurPos].Type && true === this.Content[CurPos].Cursor_Is_Start())
	{
		if (false === this.Content[CurPos - 1].Is_CursorPlaceable())
			break;

		CurPos--;
		this.Content[CurPos].MoveCursorToEndPos();
	}

	while (CurPos < Count && para_Run !== this.Content[CurPos].Type && para_Math !== this.Content[CurPos].Type && para_Field !== this.Content[CurPos].Type && para_InlineLevelSdt !== this.Content[CurPos].Type && true === this.Content[CurPos].Cursor_Is_End())
	{
		if (false === this.Content[CurPos + 1].Is_CursorPlaceable())
			break;

		CurPos++;
		this.Content[CurPos].MoveCursorToStartPos(false);
	}

	this.private_CorrectCurPosRangeLine();

	this.CurPos.ContentPos = CurPos;
};
Paragraph.prototype.Get_ParaContentPos = function(bSelection, bStart, bUseCorrection)
{
	var ContentPos = new CParagraphContentPos();

	var Pos = ( true !== bSelection ? this.CurPos.ContentPos : ( false !== bStart ? this.Selection.StartPos : this.Selection.EndPos ) );

	ContentPos.Add(Pos);

	if (Pos < 0 || Pos >= this.Content.length)
		return ContentPos;

	this.Content[Pos].Get_ParaContentPos(bSelection, bStart, ContentPos, true === bUseCorrection ? true : false);
	return ContentPos;
};
Paragraph.prototype.Set_ParaContentPos = function(ContentPos, CorrectEndLinePos, Line, Range, bCorrectPos)
{
	var Pos = ContentPos.Get(0);

	if (Pos >= this.Content.length)
		Pos = this.Content.length - 1;

	if (Pos < 0)
		Pos = 0;

	this.CurPos.ContentPos = Pos;
	this.Content[Pos].Set_ParaContentPos(ContentPos, 1);

	if (false !== bCorrectPos)
	{
		this.Correct_ContentPos(CorrectEndLinePos);
		this.Correct_ContentPos2();
	}

	this.CurPos.Line  = Line;
	this.CurPos.Range = Range;
};
Paragraph.prototype.Set_SelectionContentPos = function(StartContentPos, EndContentPos, CorrectAnchor)
{
	var Depth = 0;

	var Direction = 1;
	if (StartContentPos.Compare(EndContentPos) > 0)
		Direction = -1;

	var OldStartPos = Math.max(0, Math.min(this.Selection.StartPos, this.Content.length - 1));
	var OldEndPos   = Math.max(0, Math.min(this.Selection.EndPos, this.Content.length - 1));

	if (OldStartPos > OldEndPos)
	{
		OldStartPos = this.Selection.EndPos;
		OldEndPos   = this.Selection.StartPos;
	}

	var StartPos = StartContentPos.Get(Depth);
	var EndPos   = EndContentPos.Get(Depth);

	this.Selection.StartPos = StartPos;
	this.Selection.EndPos   = EndPos;

	// Удалим отметки о старом селекте
	if (OldStartPos < StartPos && OldStartPos < EndPos)
	{
		var TempLimit = Math.min(StartPos, EndPos);
		for (var CurPos = OldStartPos; CurPos < TempLimit; CurPos++)
		{
			this.Content[CurPos].RemoveSelection();
		}
	}

	if (OldEndPos > StartPos && OldEndPos > EndPos)
	{
		var TempLimit = Math.max(StartPos, EndPos);
		for (var CurPos = TempLimit + 1; CurPos <= OldEndPos; CurPos++)
		{
			this.Content[CurPos].RemoveSelection();
		}
	}

	if (StartPos === EndPos)
	{
		this.Content[StartPos].Set_SelectionContentPos(StartContentPos, EndContentPos, Depth + 1, 0, 0);
	}
	else
	{
		if (StartPos > EndPos)
		{
			this.Content[StartPos].Set_SelectionContentPos(StartContentPos, null, Depth + 1, 0, 1);
			this.Content[EndPos].Set_SelectionContentPos(null, EndContentPos, Depth + 1, -1, 0);

			for (var CurPos = EndPos + 1; CurPos < StartPos; CurPos++)
				this.Content[CurPos].SelectAll(-1);
		}
		else// if ( StartPos < EndPos )
		{
			this.Content[StartPos].Set_SelectionContentPos(StartContentPos, null, Depth + 1, 0, -1);
			this.Content[EndPos].Set_SelectionContentPos(null, EndContentPos, Depth + 1, 1, 0);

			for (var CurPos = StartPos + 1; CurPos < EndPos; CurPos++)
				this.Content[CurPos].SelectAll(1);
		}

		// TODO: Реализовать выделение гиперссылки целиком (само выделение тут сделано, но непонятно как
		//       дальше обрабатывать Shift + влево/вправо)

		// Делаем как в Word: гиперссылка выделяется целиком, если выделение выходит за пределы гиперссылки
		//            if ( para_Hyperlink === this.Content[StartPos].Type && true !==
		// this.Content[StartPos].IsSelectionEmpty(true) ) this.Content[StartPos].SelectAll( StartPos > EndPos ? -1 :
		// 1 );  if ( para_Hyperlink === this.Content[EndPos].Type && true !==
		// this.Content[EndPos].IsSelectionEmpty(true) ) this.Content[EndPos].SelectAll( StartPos > EndPos ? -1 : 1
		// );
	}

	if (false !== CorrectAnchor)
	{
		// Дополнительная проверка. Если у нас визуально выделен весь параграф (т.е. весь текст и знак параграфа
		// обязательно!), тогда выделяем весь параграф целиком, чтобы в селект попадали и все привязанные объекты.
		// Но если у нас выделен параграф не целиком, тогда мы снимаем выделение с привязанных объектов, стоящих в
		// начале параграфа.

		if (true === this.Selection_CheckParaEnd())
		{
			// Эта ветка нужна для выделения плавающих объектов, стоящих в начале параграфа, когда параграф выделен весь

			var bNeedSelectAll = true;
			var StartPos       = Math.min(this.Selection.StartPos, this.Selection.EndPos);
			for (var Pos = 0; Pos <= StartPos; Pos++)
			{
				if (false === this.Content[Pos].IsSelectedAll({SkipAnchor : true}))
				{
					bNeedSelectAll = false;
					break;
				}
			}

			if (true === bNeedSelectAll)
			{
				if (1 === Direction)
					this.Selection.StartPos = 0;
				else
					this.Selection.EndPos = 0;

				for (var Pos = 0; Pos <= StartPos; Pos++)
				{
					this.Content[Pos].SelectAll(Direction);
				}
			}
		}
		else if (true !== this.IsSelectionEmpty(true) && ( ( 1 === Direction && true === this.Selection.StartManually ) || ( 1 !== Direction && true === this.Selection.EndManually ) ))
		{
			// Эта ветка нужна для снятие выделения с плавающих объектов, стоящих в начале параграфа, когда параграф
			// выделен не весь. Заметим, что это ветка имеет смысл, только при direction = 1, поэтому выделен весь
			// параграф или нет, проверяется попаданием para_End в селект. Кроме того, ничего не делаем с селектом,
			// если он пустой.

			var bNeedCorrectLeftPos = true;
			var _StartPos           = Math.min(StartPos, EndPos);
			var _EndPos             = Math.max(StartPos, EndPos);
			for (var Pos = 0; Pos < StartPos; Pos++)
			{
				if (true !== this.Content[Pos].Is_Empty({SkipAnchor : true}))
				{
					bNeedCorrectLeftPos = false;
					break;
				}
			}

			if (true === bNeedCorrectLeftPos)
			{
				for (var Pos = _StartPos; Pos <= EndPos; Pos++)
				{
					if (true === this.Content[Pos].Selection_CorrectLeftPos(Direction))
					{
						if (1 === Direction)
						{
							if (Pos + 1 > this.Selection.EndPos)
								break;

							this.Selection.StartPos = Pos + 1;
						}
						else
						{
							if (Pos + 1 > this.Selection.StartPos)
								break;

							this.Selection.EndPos = Pos + 1;
						}

						this.Content[Pos].RemoveSelection();
					}
					else
						break;
				}
			}

		}
	}
};
/**
 * Устанавливаем позиции селекта внутри данного параграфа
 * NB: Данная функция не стартует селект в параграфе, а лишь выставляет его границы!!!
 * @param oStartPos {CParagraphContentPos}
 * @param oEndPos {CParagraphContentPos}
 * @param isCorrectAnchor {boolean}
 */
Paragraph.prototype.SetSelectionContentPos = function(oStartPos, oEndPos, isCorrectAnchor)
{
	return this.Set_SelectionContentPos(oStartPos, oEndPos, isCorrectAnchor);
};
Paragraph.prototype.Get_ParaContentPosByXY = function(X, Y, PageIndex, bYLine, StepEnd, bCenterMode)
{
	var SearchPos        = new CParagraphSearchPosXY();
	SearchPos.CenterMode = (undefined === bCenterMode ? true : bCenterMode);

	if (this.Lines.length <= 0)
		return SearchPos;

	// Определим страницу
	var PNum = (-1 === PageIndex || undefined === PageIndex ? 0 : PageIndex);

	// Сначала определим на какую строку мы попали
	if (PNum >= this.Pages.length)
	{
		PNum   = this.Pages.length - 1;
		bYLine = true;
		Y      = this.Lines.length - 1;
	}
	else if (PNum < 0)
	{
		PNum   = 0;
		bYLine = true;
		Y      = 0;
	}

	var CurLine = 0;
	if (true === bYLine)
		CurLine = Y;
	else
	{
		CurLine = this.Pages[PNum].FirstLine;

		var bFindY   = false;
		var CurLineY = this.Pages[PNum].Y + this.Lines[CurLine].Y + this.Lines[CurLine].Metrics.Descent + this.Lines[CurLine].Metrics.LineGap;
		var LastLine = ( PNum >= this.Pages.length - 1 ? this.Lines.length - 1 : this.Pages[PNum + 1].FirstLine - 1 );

		while (!bFindY)
		{
			if (Y < CurLineY)
				break;
			if (CurLine >= LastLine)
				break;

			CurLine++;
			CurLineY = this.Lines[CurLine].Y + this.Pages[PNum].Y + this.Lines[CurLine].Metrics.Descent + this.Lines[CurLine].Metrics.LineGap;
		}
	}

	// Определим отрезок, в который мы попадаем
	var CurRange    = 0;
	var RangesCount = this.Lines[CurLine].Ranges.length;

	if (RangesCount <= 0)
	{
		return SearchPos;
	}
	else if (RangesCount > 1)
	{
		for (; CurRange < RangesCount - 1; CurRange++)
		{
			var _CurRange  = this.Lines[CurLine].Ranges[CurRange];
			var _NextRange = this.Lines[CurLine].Ranges[CurRange + 1];
			if (X < (_CurRange.XEnd + _NextRange.X) / 2)
				break;
		}
	}

	if (CurRange >= RangesCount)
		CurRange = Math.max(RangesCount - 1, 0);

	// Определим уже непосредственно позицию, куда мы попадаем
	var Range    = this.Lines[CurLine].Ranges[CurRange];
	var StartPos = Range.StartPos;
	var EndPos   = Range.EndPos;

	SearchPos.CurX = Range.XVisible;
	SearchPos.X    = X;
	SearchPos.Y    = Y;

	// Проверим попадание в нумерацию
	if (true === this.Numbering.Check_Range(CurRange, CurLine))
	{
		var oNumPr = this.GetNumPr();
		if (para_Numbering === this.Numbering.Type && oNumPr && oNumPr.IsValid())
		{
			var NumJc = this.Parent.GetNumbering().GetNum(oNumPr.NumId).GetLvl(oNumPr.Lvl).GetJc();

			var NumX0 = SearchPos.CurX;
			var NumX1 = SearchPos.CurX;

			switch (NumJc)
			{
				case align_Right:
				{
					NumX0 -= this.Numbering.WidthNum;
					break;
				}
				case align_Center:
				{
					NumX0 -= this.Numbering.WidthNum / 2;
					NumX1 += this.Numbering.WidthNum / 2;
					break;
				}
				case align_Left:
				default:
				{
					NumX1 += this.Numbering.WidthNum;
					break;
				}
			}

			if (SearchPos.X >= NumX0 && SearchPos.X <= NumX1)
			{
				SearchPos.Numbering = true;
			}
		}

		SearchPos.CurX += this.Numbering.WidthVisible;
	}

	for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
	{
		var Item = this.Content[CurPos];

		if (false === SearchPos.InText)
			SearchPos.InTextPos.Update2(CurPos, 0);

		if (true === Item.Get_ParaContentPosByXY(SearchPos, 1, CurLine, CurRange, StepEnd))
			SearchPos.Pos.Update2(CurPos, 0);
	}

	SearchPos.InTextX = SearchPos.InText;

	// По Х попали в какой-то элемент, проверяем по Y
	if (true === SearchPos.InText && Y >= this.Pages[PNum].Y + this.Lines[CurLine].Y - this.Lines[CurLine].Metrics.Ascent - 0.01 && Y <= this.Pages[PNum].Y + this.Lines[CurLine].Y + this.Lines[CurLine].Metrics.Descent + this.Lines[CurLine].Metrics.LineGap + 0.01)
		SearchPos.InText = true;
	else
		SearchPos.InText = false;

	// Такое возможно, если все раны до этого (в том числе и этот) были пустыми, тогда, чтобы не возвращать
	// неправильную позицию вернем позицию начала данного пустого рана.
	if (SearchPos.DiffX > 1000000 - 1)
	{
		SearchPos.Line  = -1;
		SearchPos.Range = -1;
	}
	else
	{
		SearchPos.Line  = CurLine;
		SearchPos.Range = CurRange;
	}

	return SearchPos;
};
Paragraph.prototype.GetCursorPosXY = function()
{
	return {X : this.CurPos.RealX, Y : this.CurPos.RealY};
};
Paragraph.prototype.MoveCursorLeft = function(AddToSelect, Word)
{
	if (true === this.Selection.Use)
	{
		var EndSelectionPos   = this.Get_ParaContentPos(true, false);
		var StartSelectionPos = this.Get_ParaContentPos(true, true);

		if (true !== AddToSelect)
		{
			// Иногда нужно скоректировать позицию, например в формулах
			var CorrectedStartPos = this.Get_ParaContentPos(true, true, true);
			var CorrectedEndPos   = this.Get_ParaContentPos(true, false, true);

			var SelectPos = CorrectedStartPos;
			if (CorrectedStartPos.Compare(CorrectedEndPos) > 0)
				SelectPos = CorrectedEndPos;

			this.RemoveSelection();
			this.Set_ParaContentPos(SelectPos, true, -1, -1);
		}
		else
		{
			var SearchPos          = new CParagraphSearchPos();
			SearchPos.ForSelection = true;

			if (true === Word)
				this.Get_WordStartPos(SearchPos, EndSelectionPos);
			else
				this.Get_LeftPos(SearchPos, EndSelectionPos);

			if (true === SearchPos.Found)
			{
				this.Set_SelectionContentPos(StartSelectionPos, SearchPos.Pos);
			}
			else
			{
				return false;
			}
		}
	}
	else
	{
		var SearchPos  = new CParagraphSearchPos();
		var ContentPos = this.Get_ParaContentPos(false, false);

		if (true === AddToSelect)
			SearchPos.ForSelection = true;

		if (true === Word)
			this.Get_WordStartPos(SearchPos, ContentPos);
		else
			this.Get_LeftPos(SearchPos, ContentPos);

		if (true === AddToSelect)
		{
			if (true === SearchPos.Found)
			{
				// Селекта еще нет, добавляем с текущей позиции
				this.Selection.Use = true;
				this.Set_SelectionContentPos(ContentPos, SearchPos.Pos);
			}
			else
			{
				this.Selection.Use = false;
				return false;
			}
		}
		else
		{
			if (true === SearchPos.Found)
			{
				this.Set_ParaContentPos(SearchPos.Pos, true, -1, -1);
			}
			else
			{
				return false;
			}
		}
	}

	// Обновляем текущую позицию X,Y. Если есть селект, тогда обновляем по концу селекта
	if (true === this.Selection.Use)
	{
		var SelectionEndPos = this.Get_ParaContentPos(true, false);
		this.Set_ParaContentPos(SelectionEndPos, false, -1, -1);
	}

	this.Internal_Recalculate_CurPos(this.CurPos.ContentPos, true, false, false);

	this.CurPos.RealX = this.CurPos.X;
	this.CurPos.RealY = this.CurPos.Y;

	return true;
};
Paragraph.prototype.MoveCursorLeftWithSelectionFromEnd = function(Word)
{
	this.MoveCursorToEndPos(true, true);
	this.MoveCursorLeft(true, Word);
};
Paragraph.prototype.MoveCursorRight = function(AddToSelect, Word)
{
	if (true === this.Selection.Use)
	{
		var EndSelectionPos   = this.Get_ParaContentPos(true, false);
		var StartSelectionPos = this.Get_ParaContentPos(true, true);

		if (true !== AddToSelect)
		{
			// Проверим, попал ли конец параграфа в выделение
			if (true === this.Selection_CheckParaEnd())
			{
				this.RemoveSelection();
				this.MoveCursorToEndPos(false);
				return false;
			}
			else
			{
				// Иногда нужно скоректировать позицию, например в формулах
				var CorrectedStartPos = this.Get_ParaContentPos(true, true, true);
				var CorrectedEndPos   = this.Get_ParaContentPos(true, false, true);

				var SelectPos = CorrectedEndPos;
				if (CorrectedStartPos.Compare(CorrectedEndPos) > 0)
					SelectPos = CorrectedStartPos;

				this.RemoveSelection();
				this.Set_ParaContentPos(SelectPos, true, -1, -1);
			}
		}
		else
		{
			var SearchPos          = new CParagraphSearchPos();
			SearchPos.ForSelection = true;

			if (true === Word)
				this.Get_WordEndPos(SearchPos, EndSelectionPos, true);
			else
				this.Get_RightPos(SearchPos, EndSelectionPos, true);

			if (true === SearchPos.Found)
			{
				this.Set_SelectionContentPos(StartSelectionPos, SearchPos.Pos);
			}
			else
			{
				return false;
			}
		}
	}
	else
	{
		var SearchPos  = new CParagraphSearchPos();
		var ContentPos = this.Get_ParaContentPos(false, false);

		if (true === AddToSelect)
			SearchPos.ForSelection = true;

		if (true === Word)
			this.Get_WordEndPos(SearchPos, ContentPos, AddToSelect);
		else
			this.Get_RightPos(SearchPos, ContentPos, AddToSelect);

		if (true === AddToSelect)
		{
			if (true === SearchPos.Found)
			{
				// Селекта еще нет, добавляем с текущей позиции
				this.Selection.Use = true;
				this.Set_SelectionContentPos(ContentPos, SearchPos.Pos);
			}
			else
			{
				this.Selection.Use = false;
				return false;
			}
		}
		else
		{
			if (true === SearchPos.Found)
			{
				this.Set_ParaContentPos(SearchPos.Pos, true, -1, -1);
			}
			else
			{
				return false;
			}
		}
	}

	// Обновляем текущую позицию X,Y. Если есть селект, тогда обновляем по концу селекта
	if (true === this.Selection.Use)
	{
		var SelectionEndPos = this.Get_ParaContentPos(true, false);
		this.Set_ParaContentPos(SelectionEndPos, false, -1, -1);
	}

	this.Internal_Recalculate_CurPos(this.CurPos.ContentPos, true, false, false);

	this.CurPos.RealX = this.CurPos.X;
	this.CurPos.RealY = this.CurPos.Y;

	return true;
};
Paragraph.prototype.MoveCursorRightWithSelectionFromStart = function(Word)
{
	this.MoveCursorToStartPos(false);
	this.MoveCursorRight(true, Word);
};
Paragraph.prototype.MoveCursorToXY = function(X, Y, bLine, bDontChangeRealPos, CurPage)
{
	var SearchPosXY = this.Get_ParaContentPosByXY(X, Y, CurPage, bLine, false);

	this.Set_ParaContentPos(SearchPosXY.Pos, false, SearchPosXY.Line, SearchPosXY.Range);
	this.Internal_Recalculate_CurPos(-1, false, false, false);

	if (bDontChangeRealPos != true)
	{
		this.CurPos.RealX = this.CurPos.X;
		this.CurPos.RealY = this.CurPos.Y;
	}

	if (true != bLine)
	{
		this.CurPos.RealX = X;
		this.CurPos.RealY = Y;
	}
};
/**
 * Находим позицию заданного элемента. (Данной функцией лучше пользоваться, когда параграф рассчитан)
 * @returns {null | CParagraphContentPos}
 */
Paragraph.prototype.Get_PosByElement = function(Class)
{
	var ContentPos = new CParagraphContentPos();

	// Сначала попробуем определить местоположение по данным рассчета
	var CurRange = Class.StartRange;
	var CurLine  = Class.StartLine;

	if (undefined !== this.Lines[CurLine] && undefined !== this.Lines[CurLine].Ranges[CurRange])
	{
		var StartPos = this.Lines[CurLine].Ranges[CurRange].StartPos;
		var EndPos   = this.Lines[CurLine].Ranges[CurRange].EndPos;

		if (0 <= StartPos && StartPos < this.Content.length && 0 <= EndPos && EndPos < this.Content.length)
		{
			for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
			{
				var Element = this.Content[CurPos];
				ContentPos.Update(CurPos, 0);

				if (true === Element.Get_PosByElement(Class, ContentPos, 1, true, CurRange, CurLine))
					return ContentPos;
			}
		}
	}

	// Если мы дошли до сюда, значит мы так и не нашли заданный класс. Попробуем его найти с помощью
	// поиска по всему параграфу, а не по заданному отрезку

	var ContentLen = this.Content.length;
	for (var CurPos = 0; CurPos < ContentLen; CurPos++)
	{
		var Element = this.Content[CurPos];

		ContentPos.Update(CurPos, 0);

		if (true === Element.Get_PosByElement(Class, ContentPos, 1, false, -1, -1))
			return ContentPos;
	}

	return null;
};
/**
 * Получаем список классов по заданной позиции
 */
Paragraph.prototype.Get_ClassesByPos = function(ContentPos)
{
	var Classes = [];

	var CurPos = ContentPos.Get(0);
	if (0 <= CurPos && CurPos <= this.Content.length - 1)
		this.Content[CurPos].Get_ClassesByPos(Classes, ContentPos, 1);

	return Classes;
};
/**
 * Получаем по заданной позиции элемент текста
 */
Paragraph.prototype.Get_RunElementByPos = function(ContentPos)
{
	var CurPos     = ContentPos.Get(0);
	var ContentLen = this.Content.length;

	// Сначала ищем в текущем элементе
	var Element = this.Content[CurPos].Get_RunElementByPos(ContentPos, 1);

	// Если заданная позиция была последней в текущем элементе, то ищем в следующем
	while (null === Element)
	{
		CurPos++;

		if (CurPos >= ContentLen)
			break;

		Element = this.Content[CurPos].Get_RunElementByPos();
	}

	return Element;
};
Paragraph.prototype.Get_PageStartPos = function(CurPage)
{
	var CurLine  = this.Pages[CurPage].StartLine;
	var CurRange = 0;

	return this.Get_StartRangePos2(CurLine, CurRange);
};
Paragraph.prototype.Get_LeftPos = function(SearchPos, ContentPos)
{
	SearchPos.InitComplexFields(this.GetComplexFieldsByPos(ContentPos, true));

	var Depth  = 0;
	var CurPos = ContentPos.Get(Depth);

	this.Content[CurPos].Get_LeftPos(SearchPos, ContentPos, Depth + 1, true);
	SearchPos.Pos.Update(CurPos, Depth);

	if (true === SearchPos.Found)
		return true;

	CurPos--;

	if (CurPos >= 0 && this.Content[CurPos + 1].IsStopCursorOnEntryExit())
	{
		// При выходе из формулы встаем в конец рана
		this.Content[CurPos].Get_EndPos(false, SearchPos.Pos, Depth + 1);
		SearchPos.Pos.Update(CurPos, Depth);
		SearchPos.Found = true;
		return true;
	}

	while (CurPos >= 0)
	{
		this.Content[CurPos].Get_LeftPos(SearchPos, ContentPos, Depth + 1, false);
		SearchPos.Pos.Update(CurPos, Depth);

		if (true === SearchPos.Found)
			return true;

		CurPos--;
	}

	return false;
};
Paragraph.prototype.Get_RightPos = function(SearchPos, ContentPos, StepEnd)
{
	SearchPos.InitComplexFields(this.GetComplexFieldsByPos(ContentPos, true));

	var Depth  = 0;
	var CurPos = ContentPos.Get(Depth);

	this.Content[CurPos].Get_RightPos(SearchPos, ContentPos, Depth + 1, true, StepEnd);
	SearchPos.Pos.Update(CurPos, Depth);

	if (true === SearchPos.Found)
		return true;

	CurPos++;

	var Count = this.Content.length;
	if (CurPos < Count && this.Content[CurPos - 1].IsStopCursorOnEntryExit())
	{
		// При выходе из формулы встаем в конец рана
		this.Content[CurPos].Get_StartPos(SearchPos.Pos, Depth + 1);
		SearchPos.Pos.Update(CurPos, Depth);
		SearchPos.Found = true;
		return true;
	}

	while (CurPos < Count)
	{
		this.Content[CurPos].Get_RightPos(SearchPos, ContentPos, Depth + 1, false, StepEnd);
		SearchPos.Pos.Update(CurPos, Depth);

		if (true === SearchPos.Found)
			return true;

		CurPos++;
	}

	return false;
};
Paragraph.prototype.Get_WordStartPos = function(SearchPos, ContentPos)
{
	SearchPos.InitComplexFields(this.GetComplexFieldsByPos(ContentPos, true));

	var Depth  = 0;
	var CurPos = ContentPos.Get(Depth);

	this.Content[CurPos].Get_WordStartPos(SearchPos, ContentPos, Depth + 1, true);

	if (true === SearchPos.UpdatePos)
		SearchPos.Pos.Update(CurPos, Depth);

	if (true === SearchPos.Found)
		return;

	CurPos--;

	var Count = this.Content.length;
	while (CurPos >= 0)
	{
		this.Content[CurPos].Get_WordStartPos(SearchPos, ContentPos, Depth + 1, false);

		if (true === SearchPos.UpdatePos)
			SearchPos.Pos.Update(CurPos, Depth);

		if (true === SearchPos.Found)
			return;

		CurPos--;
	}

	// Случай, когда слово шло с самого начала параграфа
	if (true === SearchPos.Shift)
	{
		SearchPos.Found = true;
	}
};
Paragraph.prototype.Get_WordEndPos = function(SearchPos, ContentPos, StepEnd)
{
	SearchPos.InitComplexFields(this.GetComplexFieldsByPos(ContentPos, true));

	var Depth  = 0;
	var CurPos = ContentPos.Get(Depth);

	this.Content[CurPos].Get_WordEndPos(SearchPos, ContentPos, Depth + 1, true, StepEnd);

	if (true === SearchPos.UpdatePos)
		SearchPos.Pos.Update(CurPos, Depth);

	if (true === SearchPos.Found)
		return;

	CurPos++;

	var Count = this.Content.length;
	while (CurPos < Count)
	{
		this.Content[CurPos].Get_WordEndPos(SearchPos, ContentPos, Depth + 1, false, StepEnd);

		if (true === SearchPos.UpdatePos)
			SearchPos.Pos.Update(CurPos, Depth);

		if (true === SearchPos.Found)
			return;

		CurPos++;
	}

	// Случай, когда слово шло с самого начала параграфа
	if (true === SearchPos.Shift)
	{
		SearchPos.Found = true;
	}
};
Paragraph.prototype.Get_EndRangePos = function(SearchPos, ContentPos)
{
	var LinePos = this.Get_ParaPosByContentPos(ContentPos);

	var CurLine  = LinePos.Line;
	var CurRange = LinePos.Range;

	var Range    = this.Lines[CurLine].Ranges[CurRange];
	var StartPos = Range.StartPos;
	var EndPos   = Range.EndPos;

	SearchPos.Line  = CurLine;
	SearchPos.Range = CurRange;

	// Ищем в данном отрезке
	for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
	{
		var Item = this.Content[CurPos];

		if (true === Item.Get_EndRangePos(CurLine, CurRange, SearchPos, 1))
			SearchPos.Pos.Update(CurPos, 0);
	}
};
Paragraph.prototype.Get_StartRangePos = function(SearchPos, ContentPos)
{
	var LinePos = this.Get_ParaPosByContentPos(ContentPos);

	var CurLine  = LinePos.Line;
	var CurRange = LinePos.Range;

	var Range    = this.Lines[CurLine].Ranges[CurRange];
	var StartPos = Range.StartPos;
	var EndPos   = Range.EndPos;

	SearchPos.Line  = CurLine;
	SearchPos.Range = CurRange;

	// Ищем в данном отрезке
	for (var CurPos = EndPos; CurPos >= StartPos; CurPos--)
	{
		var Item = this.Content[CurPos];

		if (true === Item.Get_StartRangePos(CurLine, CurRange, SearchPos, 1))
			SearchPos.Pos.Update(CurPos, 0);
	}
};
Paragraph.prototype.Get_StartRangePos2 = function(CurLine, CurRange)
{
	var ContentPos = new CParagraphContentPos();
	var Depth      = 0;

	var Pos = this.Lines[CurLine].Ranges[CurRange].StartPos;
	ContentPos.Update(Pos, Depth);

	this.Content[Pos].Get_StartRangePos2(CurLine, CurRange, ContentPos, Depth + 1);
	return ContentPos;
};
Paragraph.prototype.Get_EndRangePos2 = function(CurLine, CurRange)
{
	var ContentPos = new CParagraphContentPos();
	if (!this.Lines[CurLine] || !this.Lines[CurLine].Ranges[CurRange])
		return ContentPos;

	var Depth = 0;
	var Pos   = this.Lines[CurLine].Ranges[CurRange].EndPos;
	ContentPos.Update(Pos, Depth);
	this.Content[Pos].Get_EndRangePos2(CurLine, CurRange, ContentPos, Depth + 1);
	return ContentPos;
};
Paragraph.prototype.Get_StartPos = function()
{
	var ContentPos = new CParagraphContentPos();
	var Depth      = 0;

	ContentPos.Update(0, Depth);

	this.Content[0].Get_StartPos(ContentPos, Depth + 1);
	return ContentPos;
};
/**
 * Получаем начальную позицию в параграфе
 * @returns {CParagraphContentPos}
 */
Paragraph.prototype.GetStartPos = function()
{
	return this.Get_StartPos();
};
Paragraph.prototype.Get_EndPos = function(BehindEnd)
{
	var ContentPos = new CParagraphContentPos();
	var Depth      = 0;

	var ContentLen = this.Content.length;
	ContentPos.Update(ContentLen - 1, Depth);

	this.Content[ContentLen - 1].Get_EndPos(BehindEnd, ContentPos, Depth + 1);
	return ContentPos;
};
Paragraph.prototype.Get_EndPos2 = function(BehindEnd)
{
	var ContentPos = new CParagraphContentPos();
	var Depth      = 0;

	var ContentLen = this.Content.length;
	var Pos;
	if (this.Content.length > 1)
	{
		Pos = ContentLen - 2;
	}
	else
	{
		Pos = ContentLen - 1;
	}

	ContentPos.Update(Pos, Depth);

	this.Content[Pos].Get_EndPos(BehindEnd, ContentPos, Depth + 1);
	return ContentPos;
};
/**
 * Составляем список элементов рана, идущих после заданной позиции
 * @param oRunElements {CParagraphRunElements}
 */
Paragraph.prototype.GetNextRunElements = function(oRunElements)
{
	var ContentPos = oRunElements.ContentPos;
	var CurPos     = ContentPos.Get(0);
	var ContentLen = this.Content.length;

	oRunElements.UpdatePos(CurPos, 0);
	this.Content[CurPos].GetNextRunElements(oRunElements, true, 1);

	CurPos++;
	while (CurPos < ContentLen)
	{
		if (oRunElements.IsEnoughElements())
			break;

		oRunElements.UpdatePos(CurPos, 0);
		this.Content[CurPos].GetNextRunElements(oRunElements, false, 1);

		if (oRunElements.Count <= 0)
			break;

		CurPos++;
	}

	oRunElements.CheckEnd();
};
/**
 * Составляем список элементов рана, идущих до заданной позиции
 * @param oRunElements {CParagraphRunElements}
 */
Paragraph.prototype.GetPrevRunElements = function(oRunElements)
{
	var ContentPos = oRunElements.ContentPos;
	var CurPos     = ContentPos.Get(0);

	oRunElements.UpdatePos(CurPos, 0);
	this.Content[CurPos].GetPrevRunElements(oRunElements, true, 1);

	CurPos--;

	while (CurPos >= 0)
	{
		if (oRunElements.IsEnoughElements())
			break;

		oRunElements.UpdatePos(CurPos, 0);
		this.Content[CurPos].GetPrevRunElements(oRunElements, false, 1);

		CurPos--;
	}

	oRunElements.CheckEnd();
};
/**
 * Получаем следующий за курсором элемент рана
 * @returns {?CRunElementBase}
 */
Paragraph.prototype.GetNextRunElement = function()
{
	var oRunElements = new CParagraphRunElements(this.Get_ParaContentPos(this.Selection.Use, false, false), 1, null);
	this.GetNextRunElements(oRunElements);

	if (oRunElements.Elements.length <= 0)
		return null;

	return oRunElements.Elements[0];
};
/**
 * Получаем идущий до курсора элемент рана
 * @returns {?CRunElementBase}
 */
Paragraph.prototype.GetPrevRunElement = function()
{
	var oRunElements = new CParagraphRunElements(this.Get_ParaContentPos(this.Selection.Use, false, false), 1, null);
	this.GetPrevRunElements(oRunElements);

	if (oRunElements.Elements.length <= 0)
		return null;

	return oRunElements.Elements[0];
};
Paragraph.prototype.MoveCursorUp = function(AddToSelect)
{
	var Result = true;
	if (true === this.Selection.Use)
	{
		var SelectionStartPos = this.Get_ParaContentPos(true, true);
		var SelectionEndPos   = this.Get_ParaContentPos(true, false);

		if (true === AddToSelect)
		{
			var LinePos = this.Get_ParaPosByContentPos(SelectionEndPos);
			var CurLine = LinePos.Line;

			if (0 == CurLine)
			{
				EndPos = this.Get_StartPos();

				// Переходим в предыдущий элемент документа
				Result = false;
			}
			else
			{
				this.MoveCursorToXY(this.CurPos.RealX, CurLine - 1, true, true);
				EndPos = this.Get_ParaContentPos(false, false);
			}

			this.Selection.Use = true;
			this.Set_SelectionContentPos(SelectionStartPos, EndPos);
		}
		else
		{
			var TopPos = SelectionStartPos;
			if (SelectionStartPos.Compare(SelectionEndPos) > 0)
				TopPos = SelectionEndPos;

			var LinePos  = this.Get_ParaPosByContentPos(TopPos);
			var CurLine  = LinePos.Line;
			var CurRange = LinePos.Range;

			// Пересчитаем координату точки TopPos
			this.Set_ParaContentPos(TopPos, false, CurLine, CurRange);

			this.Internal_Recalculate_CurPos(0, true, false, false);
			this.CurPos.RealX = this.CurPos.X;
			this.CurPos.RealY = this.CurPos.Y;

			this.RemoveSelection();

			if (0 == CurLine)
			{
				return false;
			}
			else
			{
				this.MoveCursorToXY(this.CurPos.RealX, CurLine - 1, true, true);
			}
		}
	}
	else
	{
		var LinePos = this.Get_CurrentParaPos();
		var CurLine = LinePos.Line;

		if (true === AddToSelect)
		{
			var StartPos = this.Get_ParaContentPos(false, false);
			var EndPos   = null;

			if (0 == CurLine)
			{
				EndPos = this.Get_StartPos();

				// Переходим в предыдущий элемент документа
				Result = false;
			}
			else
			{
				this.MoveCursorToXY(this.CurPos.RealX, CurLine - 1, true, true);
				EndPos = this.Get_ParaContentPos(false, false);
			}

			this.Selection.Use = true;
			this.Set_SelectionContentPos(StartPos, EndPos);
		}
		else
		{
			if (0 == CurLine)
			{
				// Возвращяем значение false, это означает, что надо перейти в
				// предыдущий элемент контента документа.
				return false;
			}
			else
			{
				this.MoveCursorToXY(this.CurPos.RealX, CurLine - 1, true, true);
			}
		}
	}

	return Result;
};
Paragraph.prototype.MoveCursorDown = function(AddToSelect)
{
	var Result = true;
	if (true === this.Selection.Use)
	{
		var SelectionStartPos = this.Get_ParaContentPos(true, true);
		var SelectionEndPos   = this.Get_ParaContentPos(true, false);

		if (true === AddToSelect)
		{
			var LinePos = this.Get_ParaPosByContentPos(SelectionEndPos);
			var CurLine = LinePos.Line;

			if (this.Lines.length - 1 == CurLine)
			{
				EndPos = this.Get_EndPos(true);

				// Переходим в предыдущий элемент документа
				Result = false;
			}
			else
			{
				this.MoveCursorToXY(this.CurPos.RealX, CurLine + 1, true, true);
				EndPos = this.Get_ParaContentPos(false, false);
			}

			this.Selection.Use = true;
			this.Set_SelectionContentPos(SelectionStartPos, EndPos);
		}
		else
		{
			var BottomPos = SelectionEndPos;
			if (SelectionStartPos.Compare(SelectionEndPos) > 0)
				BottomPos = SelectionStartPos;

			var LinePos  = this.Get_ParaPosByContentPos(BottomPos);
			var CurLine  = LinePos.Line;
			var CurRange = LinePos.Range;

			// Пересчитаем координату BottomPos
			this.Set_ParaContentPos(BottomPos, false, CurLine, CurRange);

			this.Internal_Recalculate_CurPos(0, true, false, false);
			this.CurPos.RealX = this.CurPos.X;
			this.CurPos.RealY = this.CurPos.Y;

			this.RemoveSelection();

			if (this.Lines.length - 1 == CurLine)
			{
				return false;
			}
			else
			{
				this.MoveCursorToXY(this.CurPos.RealX, CurLine + 1, true, true);
			}
		}
	}
	else
	{
		var LinePos = this.Get_CurrentParaPos();
		var CurLine = LinePos.Line;

		if (true === AddToSelect)
		{
			var StartPos = this.Get_ParaContentPos(false, false);
			var EndPos   = null;

			if (this.Lines.length - 1 == CurLine)
			{
				EndPos = this.Get_EndPos(true);

				// Переходим в предыдущий элемент документа
				Result = false;
			}
			else
			{
				this.MoveCursorToXY(this.CurPos.RealX, CurLine + 1, true, true);
				EndPos = this.Get_ParaContentPos(false, false);
			}

			this.Selection.Use = true;
			this.Set_SelectionContentPos(StartPos, EndPos);
		}
		else
		{
			if (this.Lines.length - 1 == CurLine)
			{
				// Возвращяем значение false, это означает, что надо перейти в
				// предыдущий элемент контента документа.
				return false;
			}
			else
			{
				this.MoveCursorToXY(this.CurPos.RealX, CurLine + 1, true, true);
			}
		}
	}

	return Result;
};
Paragraph.prototype.MoveCursorToEndOfLine = function(AddToSelect)
{
	if (true === this.Selection.Use)
	{
		var EndSelectionPos   = this.Get_ParaContentPos(true, false);
		var StartSelectionPos = this.Get_ParaContentPos(true, true);

		if (true === AddToSelect)
		{
			var SearchPos = new CParagraphSearchPos();
			this.Get_EndRangePos(SearchPos, EndSelectionPos);

			this.Set_SelectionContentPos(StartSelectionPos, SearchPos.Pos);
		}
		else
		{
			var RightPos = EndSelectionPos;
			if (EndSelectionPos.Compare(StartSelectionPos) < 0)
				RightPos = StartSelectionPos;

			var SearchPos = new CParagraphSearchPos();
			this.Get_EndRangePos(SearchPos, RightPos);

			this.RemoveSelection();

			this.Set_ParaContentPos(SearchPos.Pos, false, SearchPos.Line, SearchPos.Range);
		}
	}
	else
	{
		var SearchPos  = new CParagraphSearchPos();
		var ContentPos = this.Get_ParaContentPos(false, false);
		this.Get_EndRangePos(SearchPos, ContentPos);

		if (true === AddToSelect)
		{
			this.Selection.Use = true;
			this.Set_SelectionContentPos(ContentPos, SearchPos.Pos);
		}
		else
		{
			this.Set_ParaContentPos(SearchPos.Pos, false, SearchPos.Line, SearchPos.Range);
		}
	}

	// Обновляем текущую позицию X,Y. Если есть селект, тогда обновляем по концу селекта
	if (true === this.Selection.Use)
	{
		var SelectionEndPos = this.Get_ParaContentPos(true, false);
		this.Set_ParaContentPos(SelectionEndPos, false, -1, -1);
	}

	this.Internal_Recalculate_CurPos(this.CurPos.ContentPos, true, false, false);

	this.CurPos.RealX = this.CurPos.X;
	this.CurPos.RealY = this.CurPos.Y;
};
Paragraph.prototype.MoveCursorToStartOfLine = function(AddToSelect)
{
	if (true === this.Selection.Use)
	{
		var EndSelectionPos   = this.Get_ParaContentPos(true, false);
		var StartSelectionPos = this.Get_ParaContentPos(true, true);

		if (true === AddToSelect)
		{
			var SearchPos = new CParagraphSearchPos();
			this.Get_StartRangePos(SearchPos, EndSelectionPos);

			this.Set_SelectionContentPos(StartSelectionPos, SearchPos.Pos);
		}
		else
		{
			var LeftPos = StartSelectionPos;
			if (StartSelectionPos.Compare(EndSelectionPos) > 0)
				LeftPos = EndSelectionPos;

			var SearchPos = new CParagraphSearchPos();
			this.Get_StartRangePos(SearchPos, LeftPos);

			this.RemoveSelection();

			this.Set_ParaContentPos(SearchPos.Pos, false, SearchPos.Line, SearchPos.Range);
		}
	}
	else
	{
		var SearchPos  = new CParagraphSearchPos();
		var ContentPos = this.Get_ParaContentPos(false, false);

		this.Get_StartRangePos(SearchPos, ContentPos);

		if (true === AddToSelect)
		{
			this.Selection.Use = true;
			this.Set_SelectionContentPos(ContentPos, SearchPos.Pos);
		}
		else
		{
			this.Set_ParaContentPos(SearchPos.Pos, false, SearchPos.Line, SearchPos.Range);
		}
	}

	// Обновляем текущую позицию X,Y. Если есть селект, тогда обновляем по концу селекта
	if (true === this.Selection.Use)
	{
		var SelectionEndPos = this.Get_ParaContentPos(true, false);
		this.Set_ParaContentPos(SelectionEndPos, false, -1, -1);
	}

	this.Internal_Recalculate_CurPos(this.CurPos.ContentPos, true, false, false);

	this.CurPos.RealX = this.CurPos.X;
	this.CurPos.RealY = this.CurPos.Y;
};
Paragraph.prototype.MoveCursorToStartPos = function(AddToSelect)
{
	if (true === AddToSelect)
	{
		var StartPos = null;

		if (true === this.Selection.Use)
			StartPos = this.Get_ParaContentPos(true, true);
		else
			StartPos = this.Get_ParaContentPos(false, false);

		var EndPos = this.Get_StartPos();

		this.Selection.Use   = true;
		this.Selection.Start = false;

		this.Set_SelectionContentPos(StartPos, EndPos);
	}
	else
	{
		this.RemoveSelection();

		this.CurPos.ContentPos = 0;
		this.CurPos.Line       = -1;
		this.CurPos.Range      = -1;
		this.Content[0].MoveCursorToStartPos();
		this.Correct_ContentPos(false);
		this.Correct_ContentPos2();
	}
};
Paragraph.prototype.MoveCursorToEndPos = function(AddToSelect, StartSelectFromEnd)
{
	if (true === AddToSelect)
	{
		var StartPos = null;

		if (true === this.Selection.Use)
			StartPos = this.Get_ParaContentPos(true, true);
		else if (true === StartSelectFromEnd)
			StartPos = this.Get_EndPos(true);
		else
			StartPos = this.Get_ParaContentPos(false, false);

		var EndPos = this.Get_EndPos(true);

		this.Selection.Use   = true;
		this.Selection.Start = false;

		this.Set_SelectionContentPos(StartPos, EndPos);
	}
	else
	{
		if (true === StartSelectFromEnd)
		{
			this.Selection.Use   = true;
			this.Selection.Start = false;

			this.Selection.StartPos = this.Content.length - 1;
			this.Selection.EndPos   = this.Content.length - 1;

			this.CurPos.ContentPos = this.Content.length - 1;

			this.Content[this.CurPos.ContentPos].MoveCursorToEndPos(true);
		}
		else
		{
			this.RemoveSelection();

			this.CurPos.ContentPos = this.Content.length - 1;
			this.CurPos.Line       = -1;
			this.CurPos.Range      = -1;
			this.Content[this.CurPos.ContentPos].MoveCursorToEndPos();
			this.Correct_ContentPos(false);
			this.Correct_ContentPos2();
		}
	}
};
Paragraph.prototype.Cursor_MoveToNearPos = function(NearPos)
{
	this.Set_ParaContentPos(NearPos.ContentPos, true, -1, -1);

	this.Selection.Use = true;
	this.Set_SelectionContentPos(NearPos.ContentPos, NearPos.ContentPos);

	var SelectionStartPos = this.Get_ParaContentPos(true, true);
	var SelectionEndPos   = this.Get_ParaContentPos(true, false);

	if (0 === SelectionStartPos.Compare(SelectionEndPos))
		this.RemoveSelection();
};
Paragraph.prototype.MoveCursorUpToLastRow = function(X, Y, AddToSelect)
{
	this.CurPos.RealX = X;
	this.CurPos.RealY = Y;

	// Перемещаем курсор в последнюю строку, с позицией, самой близкой по X
	this.MoveCursorToXY(X, this.Lines.length - 1, true, true, this.Pages.length - 1);

	if (true === AddToSelect)
	{
		if (false === this.Selection.Use)
		{
			this.Selection.Use = true;
			this.Set_SelectionContentPos(this.Get_EndPos(true), this.Get_ParaContentPos(false, false));
		}
		else
		{
			this.Set_SelectionContentPos(this.Get_ParaContentPos(true, true), this.Get_ParaContentPos(false, false));
		}
	}
};
Paragraph.prototype.MoveCursorDownToFirstRow = function(X, Y, AddToSelect)
{
	this.CurPos.RealX = X;
	this.CurPos.RealY = Y;

	// Перемещаем курсор в первую строку, с позицией, самой близкой по X
	this.MoveCursorToXY(X, 0, true, true, 0);

	if (true === AddToSelect)
	{
		if (false === this.Selection.Use)
		{
			this.Selection.Use = true;
			this.Set_SelectionContentPos(this.Get_StartPos(), this.Get_ParaContentPos(false, false));
		}
		else
		{
			this.Set_SelectionContentPos(this.Get_ParaContentPos(true, true), this.Get_ParaContentPos(false, false));
		}
	}
};
Paragraph.prototype.Cursor_MoveTo_Drawing = function(Id, bBefore)
{
	if (undefined === bBefore)
		bBefore = true;

	var ContentPos = new CParagraphContentPos();

	var ContentLen = this.Content.length;

	var bFind = false;

	for (var CurPos = 0; CurPos < ContentLen; CurPos++)
	{
		var Element = this.Content[CurPos];

		ContentPos.Update(CurPos, 0);

		if (true === Element.Get_PosByDrawing(Id, ContentPos, 1))
		{
			bFind = true;
			break;
		}
	}

	if (false === bFind || ContentPos.Depth <= 0)
		return;

	if (true != bBefore)
		ContentPos.Data[ContentPos.Depth - 1]++;

	this.RemoveSelection();
	this.Set_ParaContentPos(ContentPos, false, -1, -1);

	this.RecalculateCurPos();
	this.CurPos.RealX = this.CurPos.X;
	this.CurPos.RealY = this.CurPos.Y;
};
Paragraph.prototype.GetCurPosXY = function()
{
	return {X : this.CurPos.RealX, Y : this.CurPos.RealY};
};
Paragraph.prototype.IsSelectionUse = function()
{
	return this.Selection.Use;
};
Paragraph.prototype.IsSelectionToEnd = function()
{
	return this.Selection_CheckParaEnd();
};
/**
 * Функция определяет начальную позицию курсора в параграфе
 */
Paragraph.prototype.Internal_GetStartPos = function()
{
	var oPos = this.Internal_FindForward(0, [para_PageNum, para_Drawing, para_Tab, para_Text, para_Space, para_NewLine, para_End, para_Math]);
	if (true === oPos.Found)
		return oPos.LetterPos;

	return 0;
};
/**
 * Функция определяет конечную позицию в параграфе
 */
Paragraph.prototype.Internal_GetEndPos = function()
{
	var Res = this.Internal_FindBackward(this.Content.length - 1, [para_End]);
	if (true === Res.Found)
		return Res.LetterPos;

	return 0;
};
Paragraph.prototype.Correct_Content = function(_StartPos, _EndPos, bDoNotDeleteEmptyRuns)
{
	// Если у нас сейчас в данном параграфе используется ссылка на позицию, тогда мы не корректируем контент, чтобы
	// не удалить место, на которое идет ссылка.
	if (this.NearPosArray.length >= 1)
		return;

	// В данной функции мы корректируем содержимое параграфа:
	// 1. Спаренные пустые раны мы удаляем (удаляем 1 ран)
	// 2. Удаляем пустые гиперссылки, пустые формулы, пустые поля
	// 3. Добавляем пустой ран в место, где нет рана (например, между двумя идущими подряд гиперссылками)

	var StartPos = ( undefined === _StartPos || null === _StartPos ? 0 : Math.max(_StartPos - 1, 0) );
	var EndPos   = ( undefined === _EndPos || null === _EndPos ? this.Content.length - 1 : Math.min(_EndPos + 1, this.Content.length - 1) );

	for (var CurPos = EndPos; CurPos >= StartPos; CurPos--)
	{
		var CurElement = this.Content[CurPos];

		if ((para_Hyperlink === CurElement.Type || para_Math === CurElement.Type || para_Field === CurElement.Type || para_InlineLevelSdt === CurElement.Type) && true === CurElement.Is_Empty() && true !== CurElement.Is_CheckingNearestPos())
		{
			this.Internal_Content_Remove(CurPos);
		}
		else if (para_Run !== CurElement.Type)
		{
			if (CurPos === this.Content.length - 1 || para_Run !== this.Content[CurPos + 1].Type || CurPos === this.Content.length - 2)
			{
				var NewRun = new ParaRun(this);
				this.Internal_Content_Add(CurPos + 1, NewRun);
			}

			// Для начального элемента проверим еще и предыдущий
			if (StartPos === CurPos && ( 0 === CurPos || para_Run !== this.Content[CurPos - 1].Type  ))
			{
				var NewRun = new ParaRun(this);
				this.Internal_Content_Add(CurPos, NewRun);
			}
		}
		else
		{
			if (true !== bDoNotDeleteEmptyRuns)
			{
				// TODO (Para_End): Предпоследний элемент мы не проверяем, т.к. на ран с Para_End мы не ориентируемся
				if (true === CurElement.Is_Empty() && (0 < CurPos || para_Run !== this.Content[CurPos].Type) && CurPos < this.Content.length - 2 && para_Run === this.Content[CurPos + 1].Type)
					this.Internal_Content_Remove(CurPos);
			}
		}
	}

	// Проверим, чтобы предпоследний элемент был Run
	if (1 === this.Content.length || para_Run !== this.Content[this.Content.length - 2].Type)
	{
		var NewRun = new ParaRun(this);
		NewRun.Set_Pr(this.TextPr.Value.Copy());
		this.Internal_Content_Add(this.Content.length - 1, NewRun);
	}

	this.Correct_ContentPos2();
};
Paragraph.prototype.Apply_TextPr = function(TextPr, IncFontSize)
{
	// Данная функция работает по следующему принципу: если задано выделение, тогда применяем настройки к
	// выделенной части, а если выделения нет, тогда в текущее положение вставляем пустой ран с заданными настройками
	// и переносим курсор в данный ран.

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;

		if (StartPos === EndPos)
		{
			var NewElements = this.Content[EndPos].Apply_TextPr(TextPr, IncFontSize, false);

			if (para_Run === this.Content[EndPos].Type)
			{
				this.Internal_ReplaceRun(EndPos, NewElements);
			}
		}
		else
		{
			var Direction = 1;
			if (StartPos > EndPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;

				Direction = -1;
			}

			for (var CurPos = StartPos + 1; CurPos < EndPos; CurPos++)
			{
				this.Content[CurPos].Apply_TextPr(TextPr, IncFontSize, false);
			}

			var bCorrectContent = false;

			var NewElements = this.Content[EndPos].Apply_TextPr(TextPr, IncFontSize, false);
			if (para_Run === this.Content[EndPos].Type)
			{
				this.Internal_ReplaceRun(EndPos, NewElements);
				bCorrectContent = true;
			}

			var NewElements = this.Content[StartPos].Apply_TextPr(TextPr, IncFontSize, false);
			if (para_Run === this.Content[StartPos].Type)
			{
				this.Internal_ReplaceRun(StartPos, NewElements);
				bCorrectContent = true;
			}

			if (true === bCorrectContent)
				this.Correct_Content();
		}
	}
	else
	{
		var Pos         = this.CurPos.ContentPos;
		var Element     = this.Content[Pos];
		var NewElements = Element.Apply_TextPr(TextPr, IncFontSize, false);

		if (para_Run === Element.Type)
		{
			this.Internal_ReplaceRun(Pos, NewElements);
		}

		if (true === this.IsCursorAtEnd() && undefined === this.GetNumPr())
		{
			if (undefined === IncFontSize)
			{
				if (!TextPr.AscFill && !TextPr.AscLine && !TextPr.AscUnifill)
				{
					this.TextPr.Apply_TextPr(TextPr);
				}
				else
				{
					var EndTextPr = this.Get_CompiledPr2(false).TextPr.Copy();
					EndTextPr.Merge(this.TextPr.Value);
					if (TextPr.AscFill)
					{
						this.TextPr.Set_TextFill(AscFormat.CorrectUniFill(TextPr.AscFill, EndTextPr.TextFill, 1));
					}
					if (TextPr.AscUnifill)
					{
						this.TextPr.Set_Unifill(AscFormat.CorrectUniFill(TextPr.AscUnifill, EndTextPr.Unifill, 0));
					}
					if (TextPr.AscLine)
					{
						this.TextPr.Set_TextOutline(AscFormat.CorrectUniStroke(TextPr.AscLine, EndTextPr.TextOutline, 0));
					}
				}
			}
			else
			{
				// Выставляем настройки для символа параграфа
				var EndTextPr = this.Get_CompiledPr2(false).TextPr.Copy();
				EndTextPr.Merge(this.TextPr.Value);

				// TODO: Как только перенесем историю изменений TextPr в сам класс CTextPr, переделать тут
				this.TextPr.Set_FontSize(FontSize_IncreaseDecreaseValue(IncFontSize, EndTextPr.FontSize));
			}

			// TODO (ParaEnd): Переделать
			var LastElement = this.Content[this.Content.length - 1];
			if (para_Run === LastElement.Type)
				LastElement.Set_Pr(this.TextPr.Value.Copy());
		}
	}
};
/**
 * Применяем текстовые настройки к выделенной части параграфа
 * @param {CTextPr} oTextPr
 * @param {boolean | undefined} isIncFontSize
 */
Paragraph.prototype.ApplyTextPr = function(oTextPr, isIncFontSize)
{
	return this.Apply_TextPr(oTextPr, isIncFontSize);
};
Paragraph.prototype.Internal_ReplaceRun = function(Pos, NewRuns)
{
	// По логике, можно удалить Run, стоящий в позиции Pos и добавить все раны, которые не null в массиве NewRuns.
	// Но, согласно работе ParaRun.Apply_TextPr, в массиве всегда идет ровно 3 рана (возможно null). Второй ран
	// всегда не null. Первый не null ран и есть ран, идущий в позиции Pos.

	var LRun = NewRuns[0];
	var CRun = NewRuns[1];
	var RRun = NewRuns[2];

	// CRun - всегда не null
	var CenterRunPos = Pos;

	var OldSelectionStartPos = this.Selection.StartPos;
	var OldSelectionEndPos   = this.Selection.EndPos;
	var OldCurPos            = this.CurPos.ContentPos;

	if (null !== LRun)
	{
		this.Internal_Content_Add(Pos + 1, CRun);
		CenterRunPos = Pos + 1;
	}
	else
	{
		// Если LRun - null, значит CRun - это и есть тот ран который стоит уже в позиции Pos
	}

	if (null !== RRun)
	{
		this.Internal_Content_Add(CenterRunPos + 1, RRun);
	}

	if (OldCurPos > Pos)
	{
		if (null !== LRun && null !== RRun)
			this.CurPos.ContentPos = OldCurPos + 2;
		else if (null !== RRun || null !== RRun)
			this.CurPos.ContentPos = OldCurPos + 1;
	}
	else if (OldCurPos === Pos)
	{
		this.CurPos.ContentPos = CenterRunPos;
	}
	this.CurPos.Line = -1;

	if (OldSelectionStartPos > Pos)
	{
		if (null !== LRun && null !== RRun)
			this.Selection.StartPos = OldSelectionStartPos + 2;
		else if (null !== RRun || null !== RRun)
			this.Selection.StartPos = OldSelectionStartPos + 1;
	}
	else if (OldSelectionStartPos === Pos)
	{
		if (OldSelectionEndPos > OldSelectionStartPos)
		{
			this.Selection.StartPos = Pos;
		}
		else if (OldSelectionEndPos < OldSelectionStartPos)
		{
			if (null !== LRun && null !== RRun)
				this.Selection.StartPos = Pos + 2;
			else if (null !== LRun || null !== RRun)
				this.Selection.StartPos = Pos + 1;
			else
				this.Selection.StartPos = Pos;
		}
		else
		{
			// TODO: Тут надо бы выяснить направление селекта
			this.Selection.StartPos = Pos;

			if (null !== LRun && null !== RRun)
				this.Selection.EndPos = Pos + 2;
			else if (null !== LRun || null !== RRun)
				this.Selection.EndPos = Pos + 1;
			else
				this.Selection.EndPos = Pos;
		}
	}

	if (OldSelectionEndPos > Pos)
	{
		if (null !== LRun && null !== RRun)
			this.Selection.EndPos = OldSelectionEndPos + 2;
		else if (null !== RRun || null !== RRun)
			this.Selection.EndPos = OldSelectionEndPos + 1;
	}
	else if (OldSelectionEndPos === Pos)
	{
		if (OldSelectionEndPos > OldSelectionStartPos)
		{
			if (null !== LRun && null !== RRun)
				this.Selection.EndPos = Pos + 2;
			else if (null !== LRun || null !== RRun)
				this.Selection.EndPos = Pos + 1;
			else
				this.Selection.EndPos = Pos;
		}
		else if (OldSelectionEndPos < OldSelectionStartPos)
		{
			this.Selection.EndPos = Pos;
		}
	}

	return CenterRunPos;
};
Paragraph.prototype.CheckHyperlink = function(X, Y, CurPage)
{
	var oInfo = new CSelectedElementsInfo();
	this.GetElementsInfoByXY(oInfo, X, Y, CurPage);
	return oInfo.GetHyperlink();
};
/**
 * Добавляем гиперссылку
 * @param {CHyperlinkProperty} HyperProps
 */
Paragraph.prototype.AddHyperlink = function(HyperProps)
{
	if (true === this.Selection.Use)
	{
		// Создаем гиперссылку
		var Hyperlink = new ParaHyperlink();

		// Заполняем гиперссылку полями
		if (undefined !== HyperProps.Anchor && null !== HyperProps.Anchor)
		{
			Hyperlink.SetAnchor(HyperProps.Anchor);
			Hyperlink.SetValue("")
		}
		else if (undefined != HyperProps.Value && null != HyperProps.Value)
		{
			Hyperlink.SetValue(HyperProps.Value);
			Hyperlink.SetAnchor("");
		}

		if (undefined != HyperProps.ToolTip && null != HyperProps.ToolTip)
			Hyperlink.SetToolTip(HyperProps.ToolTip);

		// Разделяем содержимое по меткам селекта
		var StartContentPos = this.Get_ParaContentPos(true, true);
		var EndContentPos   = this.Get_ParaContentPos(true, false);

		if (StartContentPos.Compare(EndContentPos) > 0)
		{
			var Temp        = StartContentPos;
			StartContentPos = EndContentPos;
			EndContentPos   = Temp;
		}

		// Если у нас попадает комментарий в данную область, тогда удалим его.
		// TODO: Переделать здесь, когда комментарии смогут лежать во всех классах (например в Hyperlink)

		var StartPos = StartContentPos.Get(0);
		var EndPos   = EndContentPos.Get(0);

		var CommentsToDelete = {};
		for (var Pos = StartPos; Pos <= EndPos; Pos++)
		{
			var Item = this.Content[Pos];
			if (para_Comment === Item.Type)
				CommentsToDelete[Item.CommentId] = true;
		}

		for (var CommentId in CommentsToDelete)
		{
			this.LogicDocument.RemoveComment(CommentId, true, false);
		}

		// Еще раз обновим метки
		StartContentPos = this.Get_ParaContentPos(true, true);
		EndContentPos   = this.Get_ParaContentPos(true, false);

		if (StartContentPos.Compare(EndContentPos) > 0)
		{
			var Temp        = StartContentPos;
			StartContentPos = EndContentPos;
			EndContentPos   = Temp;
		}

		StartPos = StartContentPos.Get(0);
		EndPos   = EndContentPos.Get(0);

		// TODO: Как только избавимся от ParaEnd, здесь надо будет переделать.
		if (this.Content.length - 1 === EndPos && true === this.Selection_CheckParaEnd())
		{
			EndContentPos = this.Get_EndPos(false);
			EndPos        = EndContentPos.Get(0);
		}

		var NewElementE = this.Content[EndPos].Split(EndContentPos, 1);
		var NewElementS = this.Content[StartPos].Split(StartContentPos, 1);

		var HyperPos = 0;

		if (null !== NewElementS)
			Hyperlink.Add_ToContent(HyperPos++, NewElementS);

		for (var CurPos = StartPos + 1; CurPos <= EndPos; CurPos++)
		{
			Hyperlink.Add_ToContent(HyperPos++, this.Content[CurPos]);
		}

		if (0 === Hyperlink.Content.length)
		{
			Hyperlink.Add_ToContent(0, new ParaRun(this, false));
		}

		this.Internal_Content_Remove2(StartPos + 1, EndPos - StartPos);
		this.Internal_Content_Add(StartPos + 1, Hyperlink);

		if (null !== NewElementE)
			this.Internal_Content_Add(StartPos + 2, NewElementE);

		this.RemoveSelection();
		this.Selection.Use      = true;
		this.Selection.StartPos = StartPos + 1;
		this.Selection.EndPos   = StartPos + 1;

		Hyperlink.MoveCursorToStartPos();
		Hyperlink.SelectAll();

		// Выставляем специальную текстовую настройку
		var TextPr       = new CTextPr();
		TextPr.Color     = null;
		TextPr.Underline = null;
		TextPr.RStyle    = editor && editor.isDocumentEditor ? editor.WordControl.m_oLogicDocument.Get_Styles().GetDefaultHyperlink() : null;
		if (!this.bFromDocument)
		{
			//TextPr.Unifill   = AscFormat.CreateUniFillSchemeColorWidthTint(11, 0);
			TextPr.Underline = true;
		}
		Hyperlink.Apply_TextPr(TextPr, undefined, false);

		// Если мы находимся в режиме рецензирования, то пробегаемся по всему содержимому гиперссылки и
		// проставляем, что все раны новые.
		if (this.LogicDocument && true === this.LogicDocument.Is_TrackRevisions())
			Hyperlink.Set_ReviewType(reviewtype_Add, true);
	}
	else if (null !== HyperProps.Text && "" !== HyperProps.Text)
	{
		var ContentPos = this.Get_ParaContentPos(false, false);
		var CurPos     = ContentPos.Get(0);

		var TextPr = this.Get_TextPr(ContentPos);
		if (undefined !== HyperProps.TextPr && null !== HyperProps.TextPr)
			TextPr = HyperProps.TextPr;

		// Создаем гиперссылку
		var Hyperlink = new ParaHyperlink();

		// Заполняем гиперссылку полями
		if (undefined !== HyperProps.Anchor && null !== HyperProps.Anchor)
		{
			Hyperlink.SetAnchor(HyperProps.Anchor);
			Hyperlink.SetValue("")
		}
		else if (undefined != HyperProps.Value && null != HyperProps.Value)
		{
			Hyperlink.SetValue(HyperProps.Value);
			Hyperlink.SetAnchor("");
		}

		if (undefined != HyperProps.ToolTip && null != HyperProps.ToolTip)
			Hyperlink.SetToolTip(HyperProps.ToolTip);

		// Создаем текстовый ран в гиперссылке
		var HyperRun = new ParaRun(this);

		// Добавляем ран в гиперссылку
		Hyperlink.Add_ToContent(0, HyperRun, false);

		// Задаем текстовые настройки рана (те, которые шли в текущей позиции + стиль гиперссылки)
		if (this.bFromDocument)
		{
			var Styles = editor.WordControl.m_oLogicDocument.Get_Styles();
			HyperRun.Set_Pr(TextPr.Copy());
			HyperRun.Set_Color(undefined);
			HyperRun.Set_Underline(undefined);
			HyperRun.Set_RStyle(Styles.GetDefaultHyperlink());
		}
		else
		{
			HyperRun.Set_Pr(TextPr.Copy());
			HyperRun.Set_Color(undefined);
			//HyperRun.Set_Unifill(AscFormat.CreateUniFillSchemeColorWidthTint(11, 0));
			HyperRun.Set_Underline(true);
		}

		// Заполняем ран гиперссылки текстом
		HyperRun.AddText(HyperProps.Text);

		// Разделяем текущий элемент (возвращается правая часть)
		var NewElement = this.Content[CurPos].Split(ContentPos, 1);

		if (null !== NewElement)
			this.Internal_Content_Add(CurPos + 1, NewElement);

		// Добавляем гиперссылку в содержимое параграфа
		this.Internal_Content_Add(CurPos + 1, Hyperlink);

		// Перемещаем кусор в конец гиперссылки
		this.CurPos.ContentPos = CurPos + 1;
		Hyperlink.MoveCursorToEndPos(false);
	}

	this.Correct_Content();
};
/**
 * Изменяем гиперссылку
 * @param {CHyperlinkProperty} HyperProps
 * @returns {boolean}
 */
Paragraph.prototype.ModifyHyperlink = function(HyperProps)
{
	var HyperPos = -1;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (StartPos > EndPos)
		{
			StartPos = this.Selection.EndPos;
			EndPos   = this.Selection.StartPos;
		}

		for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
		{
			var Element = this.Content[CurPos];

			if (true !== Element.IsSelectionEmpty() && para_Hyperlink !== Element.Type)
				break;
			else if (true !== Element.IsSelectionEmpty() && para_Hyperlink === Element.Type)
			{
				if (-1 === HyperPos)
					HyperPos = CurPos;
				else
					break;
			}
		}

		if (this.Selection.StartPos === this.Selection.EndPos && para_Hyperlink === this.Content[this.Selection.StartPos].Type)
			HyperPos = this.Selection.StartPos;
	}
	else
	{
		if (para_Hyperlink === this.Content[this.CurPos.ContentPos].Type)
			HyperPos = this.CurPos.ContentPos;
	}

	if (-1 != HyperPos)
	{
		var Hyperlink = this.Content[HyperPos];

		if (undefined !== HyperProps.Anchor && null !== HyperProps.Anchor)
		{
			Hyperlink.SetAnchor(HyperProps.Anchor);
			Hyperlink.SetValue("")
		}
		else if (undefined != HyperProps.Value && null != HyperProps.Value)
		{
			Hyperlink.SetValue(HyperProps.Value);
			Hyperlink.SetAnchor("");
		}

		if (undefined != HyperProps.ToolTip && null != HyperProps.ToolTip)
			Hyperlink.SetToolTip(HyperProps.ToolTip);

		if (null != HyperProps.Text)
		{
			var TextPr = Hyperlink.Get_TextPr();

			// Удаляем все что было в гиперссылке
			Hyperlink.Remove_FromContent(0, Hyperlink.Content.length);

			// Создаем текстовый ран в гиперссылке
			var HyperRun = new ParaRun(this);

			// Добавляем ран в гиперссылку
			Hyperlink.Add_ToContent(0, HyperRun, false);

			// Задаем текстовые настройки рана (те, которые шли в текущей позиции + стиль гиперссылки)
			if (this.bFromDocument)
			{
				var Styles = editor.WordControl.m_oLogicDocument.Get_Styles();
				HyperRun.Set_Pr(TextPr.Copy());
				HyperRun.Set_Color(undefined);
				HyperRun.Set_Underline(undefined);
				HyperRun.Set_RStyle(Styles.GetDefaultHyperlink());
			}
			else
			{
				HyperRun.Set_Pr(TextPr.Copy());
				HyperRun.Set_Color(undefined);
				HyperRun.Set_Unifill(AscFormat.CreateUniFillSchemeColorWidthTint(11, 0));
				HyperRun.Set_Underline(true);
			}


			// Заполняем ран гиперссылки текстом
			HyperRun.AddText(HyperProps.Text);

			// Перемещаем кусор в конец гиперссылки

			if (true === this.Selection.Use)
			{
				this.Selection.StartPos = HyperPos;
				this.Selection.EndPos   = HyperPos;

				Hyperlink.SelectAll();
			}
			else
			{
				this.CurPos.ContentPos = HyperPos;
				Hyperlink.MoveCursorToEndPos(false);
			}

			return true;
		}

		return false;
	}

	return false;
};
Paragraph.prototype.RemoveHyperlink = function()
{
	// Сначала найдем гиперссылку, которую нужно удалить
	var HyperPos = -1;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (StartPos > EndPos)
		{
			StartPos = this.Selection.EndPos;
			EndPos   = this.Selection.StartPos;
		}

		for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
		{
			var Element = this.Content[CurPos];

			if (true !== Element.IsSelectionEmpty() && para_Hyperlink !== Element.Type)
				break;
			else if (true !== Element.IsSelectionEmpty() && para_Hyperlink === Element.Type)
			{
				if (-1 === HyperPos)
					HyperPos = CurPos;
				else
					break;
			}
		}

		if (this.Selection.StartPos === this.Selection.EndPos && para_Hyperlink === this.Content[this.Selection.StartPos].Type)
			HyperPos = this.Selection.StartPos;
	}
	else
	{
		if (para_Hyperlink === this.Content[this.CurPos.ContentPos].Type)
			HyperPos = this.CurPos.ContentPos;
	}

	if (-1 !== HyperPos)
	{
		var Hyperlink = this.Content[HyperPos];

		var ContentLen = Hyperlink.Content.length;

		this.Internal_Content_Remove(HyperPos);

		var TextPr       = new CTextPr();
		TextPr.RStyle    = null;
		TextPr.Underline = null;
		TextPr.Color     = null;
		TextPr.Unifill   = null;

		for (var CurPos = 0; CurPos < ContentLen; CurPos++)
		{
			var Element = Hyperlink.Content[CurPos];
			this.Internal_Content_Add(HyperPos + CurPos, Element);
			Element.Apply_TextPr(TextPr, undefined, true);
		}

		if (true === this.Selection.Use)
		{
			this.Selection.StartPos = HyperPos + Hyperlink.State.Selection.StartPos;
			this.Selection.EndPos   = HyperPos + Hyperlink.State.Selection.EndPos;
		}
		else
		{
			this.CurPos.ContentPos = HyperPos + Hyperlink.State.ContentPos;
		}

		return true;
	}

	return false;
};
Paragraph.prototype.CanAddHyperlink = function(bCheckInHyperlink)
{
	if (true === bCheckInHyperlink)
	{
		if (true === this.Selection.Use)
		{
			// Если у нас в выделение попадает начало или конец гиперссылки, или конец параграфа, или
			// у нас все выделение находится внутри гиперссылки, тогда мы не можем добавить новую. Во
			// всех остальных случаях разрешаем добавить.
			// Также, если начало или конец выделения попадает в элемент, который нельзя разделить, тогда мы тоже
			// запрещаем добавление гиперссылки.

			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (EndPos < StartPos)
			{
				StartPos = this.Selection.EndPos;
				EndPos   = this.Selection.StartPos;
			}

			if (false === this.Content[StartPos].CanSplit() || false === this.Content[EndPos].CanSplit())
				return false;

			// Проверяем не находимся ли мы внутри гиперссылки
			for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
			{
				var Element = this.Content[CurPos];
				if (para_Hyperlink === Element.Type || para_Math === Element.Type /*|| true === Element.Selection_CheckParaEnd()*/)
					return false;
			}

			return true;
		}
		else
		{
			// Если мы в элементе, который нельзя делить, тогда не разрешаем добавлять гиперссылку
			if (false === this.Content[this.CurPos.ContentPos].CanSplit())
				return false;

			// Внутри гиперссылки мы не можем задать ниперссылку
			var CurType = this.Content[this.CurPos.ContentPos].Type;
			if (para_Hyperlink === CurType || para_Math === CurType)
				return false;
			else
				return true;
		}
	}
	else
	{
		if (true === this.Selection.Use)
		{
			// Если у нас в выделение попадает несколько гиперссылок или конец параграфа, тогда
			// возвращаем false, во всех остальных случаях true
			// Также, если начало или конец выделения попадает в элемент, который нельзя разделить, тогда мы тоже
			// запрещаем добавление гиперссылки.

			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (EndPos < StartPos)
			{
				StartPos = this.Selection.EndPos;
				EndPos   = this.Selection.StartPos;
			}

			if (false === this.Content[StartPos].CanSplit() || false === this.Content[EndPos].CanSplit())
				return false;

			var bHyper = false;

			for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
			{
				var Element = this.Content[CurPos];
				if ((true === bHyper && para_Hyperlink === Element.Type) || para_Math === Element.Type /*|| true === Element.Selection_CheckParaEnd()*/)
					return false;
				else if (true !== bHyper && para_Hyperlink === Element.Type)
					bHyper = true;
			}

			return true;
		}
		else
		{
			// Если мы в элементе, который нельзя делить, тогда не разрешаем добавлять гиперссылку
			if (false === this.Content[this.CurPos.ContentPos].CanSplit())
				return false;

			// Внутри гиперссылки мы не можем задать ниперссылку
			var CurType = this.Content[this.CurPos.ContentPos].Type;
			if (para_Math === CurType)
				return false;
			else
				return true;
		}
	}
};
Paragraph.prototype.IsCursorInHyperlink = function(bCheckEnd)
{
	if (true === this.Selection.Use)
		return null;

	var oInfo = new CSelectedElementsInfo();
	this.GetSelectedElementsInfo(oInfo, this.Get_ParaContentPos(false), 0);
	return oInfo.GetHyperlink();
};
Paragraph.prototype.Selection_SetStart = function(X, Y, CurPage, bTableBorder)
{
	// Избавляемся от старого селекта
	if (true === this.Selection.Use)
		this.RemoveSelection();

	// Найдем позицию в контенте, в которую мы попали (для селекта ищем и за знаком параграфа, для курсора только перед)
	var SearchPosXY  = this.Get_ParaContentPosByXY(X, Y, CurPage, false, true);
	var SearchPosXY2 = this.Get_ParaContentPosByXY(X, Y, CurPage, false, false);

	// Начинаем селект
	this.Selection.Use           = true;
	this.Selection.Start         = true;
	this.Selection.Flag          = selectionflag_Common;
	this.Selection.StartManually = true;

	// Выставим текущую позицию
	this.Set_ParaContentPos(SearchPosXY2.Pos, true, SearchPosXY2.Line, SearchPosXY2.Range);

	// Выставляем селект
	this.Set_SelectionContentPos(SearchPosXY.Pos, SearchPosXY.Pos);

	if (true === SearchPosXY.Numbering && undefined != this.GetNumPr())
	{
		this.Set_ParaContentPos(this.Get_StartPos(), true, -1, -1);
		this.Parent.SelectNumbering(this.GetNumPr(), this);
	}
};
/**
 * Данная функция может использоваться как при движении, так и при окончательном выставлении селекта.
 * Если bEnd = true, тогда это конец селекта.
 */
Paragraph.prototype.Selection_SetEnd = function(X, Y, CurPage, MouseEvent, bTableBorder)
{
	var PagesCount = this.Pages.length;

	if (this.bFromDocument && this.LogicDocument && true === this.LogicDocument.CanEdit() && null === this.Parent.IsHdrFtr(true) && null == this.Get_DocumentNext() && CurPage >= PagesCount - 1 && Y > this.Pages[PagesCount - 1].Bounds.Bottom && MouseEvent.ClickCount >= 2)
		return this.Parent.Extend_ToPos(X, Y);

	// Обновляем позицию курсора
	this.CurPos.RealX = X;
	this.CurPos.RealY = Y;

	this.Selection.EndManually = true;

	// Найдем позицию в контенте, в которую мы попали (для селекта ищем и за знаком параграфа, для курсора только перед)
	var SearchPosXY = this.Get_ParaContentPosByXY(X, Y, CurPage, false, true);
	var SearchPosXY2 = this.Get_ParaContentPosByXY(X, Y, CurPage, false, false);

	// Выставим в полученном месте текущую позицию курсора
	this.Set_ParaContentPos(SearchPosXY2.Pos, true, SearchPosXY2.Line, SearchPosXY2.Range);

	if (true === SearchPosXY.End || true === this.Is_Empty())
	{
		var LastRange = this.Lines[this.Lines.length - 1].Ranges[this.Lines[this.Lines.length - 1].Ranges.length - 1];
		if (CurPage >= PagesCount - 1 && X > LastRange.W && MouseEvent.ClickCount >= 2 && Y <= this.Pages[PagesCount - 1].Bounds.Bottom)
		{
			if (this.bFromDocument && false === this.LogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_None, {
					Type      : AscCommon.changestype_2_Element_and_Type,
					Element   : this,
					CheckType : AscCommon.changestype_Paragraph_Content
				}))
			{
				History.Create_NewPoint(AscDFH.historydescription_Document_ParagraphExtendToPos);
				History.Set_Additional_ExtendDocumentToPos();

				if (true === this.Extend_ToPos(X))
				{
					this.MoveCursorToEndPos();
					this.Document_SetThisElementCurrent(true);
					this.LogicDocument.Recalculate();
					return;
				}
				else
				{
					History.Remove_LastPoint();
				}
			}
		}
	}

	// Выставляем селект
	this.Set_SelectionContentPos(this.Get_ParaContentPos(true, true), SearchPosXY.Pos);

	var SelectionStartPos = this.Get_ParaContentPos(true, true);
	var SelectionEndPos   = this.Get_ParaContentPos(true, false);

	if (0 === SelectionStartPos.Compare(SelectionEndPos) && AscCommon.g_mouse_event_type_up === MouseEvent.Type)
	{
		var oInfo = new CSelectedElementsInfo();
		this.GetSelectedElementsInfo(oInfo);
		var oField = oInfo.Get_Field();

		if (oField && fieldtype_FORMTEXT === oField.Get_FieldType())
		{
			// TODO: Пока у нас невложенные поля так будет работать нормально. Со вложенными нужно переделать.
			oField.SelectAll(1);
			this.Selection.Use = true;
		}
		else
		{
			var ClickCounter = MouseEvent.ClickCount % 2;

			if (1 >= MouseEvent.ClickCount)
			{
				// Убираем селект. Позицию курсора можно не выставлять, т.к. она у нас установлена на конец селекта
				this.RemoveSelection();
			}
			else if (0 == ClickCounter)
			{
				// Выделяем слово, в котором находимся
				var SearchPosS = new CParagraphSearchPos();
				var SearchPosE = new CParagraphSearchPos();

				this.Get_WordEndPos(SearchPosE, SearchPosXY.Pos);
				this.Get_WordStartPos(SearchPosS, SearchPosE.Pos);

				var StartPos = ( true === SearchPosS.Found ? SearchPosS.Pos : this.Get_StartPos() );
				var EndPos   = ( true === SearchPosE.Found ? SearchPosE.Pos : this.Get_EndPos(false) );

				this.Selection.Use = true;
				this.Set_SelectionContentPos(StartPos, EndPos);

				if (this.LogicDocument)
					this.LogicDocument.Set_WordSelection();
			}
			else // ( 1 == ClickCounter % 2 )
			{
				// Выделяем весь параграф целиком

				this.SelectAll(1);
			}
		}
	}
};
Paragraph.prototype.StopSelection = function()
{
	this.Selection.Start = false;
};
Paragraph.prototype.RemoveSelection = function()
{
	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;

		if (StartPos > EndPos)
		{
			StartPos = this.Selection.EndPos;
			EndPos   = this.Selection.StartPos;
		}

		StartPos = Math.max(0, StartPos);
		EndPos   = Math.min(this.Content.length - 1, EndPos);

		for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
		{
			this.Content[CurPos].RemoveSelection();
		}
	}

	this.Selection.Use      = false;
	this.Selection.Start    = false;
	this.Selection.Flag     = selectionflag_Common;
	this.Selection.StartPos = 0;
	this.Selection.EndPos   = 0;
};
Paragraph.prototype.DrawSelectionOnPage = function(CurPage)
{
	if (true != this.Selection.Use)
		return;

	if (CurPage < 0 || CurPage >= this.Pages.length)
		return;

	var PageAbs = this.private_GetAbsolutePageIndex(CurPage);

	if (0 === CurPage && this.Pages[0].EndLine < 0)
		return;

	switch (this.Selection.Flag)
	{
		case selectionflag_Common:
		{
			// Делаем подсветку
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;

			if (StartPos > EndPos)
			{
				StartPos = this.Selection.EndPos;
				EndPos   = this.Selection.StartPos;
			}

			var _StartLine = this.Pages[CurPage].StartLine;
			var _EndLine   = this.Pages[CurPage].EndLine;

			if (StartPos > this.Lines[_EndLine].Get_EndPos() || EndPos < this.Lines[_StartLine].Get_StartPos())
				return;
			else
			{
				StartPos = Math.max(StartPos, this.Lines[_StartLine].Get_StartPos());
				EndPos   = Math.min(EndPos, ( _EndLine != this.Lines.length - 1 ? this.Lines[_EndLine].Get_EndPos() : this.Content.length - 1 ));
			}

			var DrawSelection = new CParagraphDrawSelectionRange();

			var bInline = this.Is_Inline();

			for (var CurLine = _StartLine; CurLine <= _EndLine; CurLine++)
			{
				var Line        = this.Lines[CurLine];
				var RangesCount = Line.Ranges.length;

				// Определяем позицию и высоту строки
				DrawSelection.StartY = this.Pages[CurPage].Y + this.Lines[CurLine].Top;
				DrawSelection.H      = this.Lines[CurLine].Bottom - this.Lines[CurLine].Top;

				for (var CurRange = 0; CurRange < RangesCount; CurRange++)
				{
					var Range = Line.Ranges[CurRange];

					var RStartPos = Range.StartPos;
					var REndPos   = Range.EndPos;

					// Если пересечение пустое с селектом, тогда пропускаем данный отрезок
					if (StartPos > REndPos || EndPos < RStartPos)
						continue;

					DrawSelection.StartX    = this.Lines[CurLine].Ranges[CurRange].XVisible;
					DrawSelection.W         = 0;
					DrawSelection.FindStart = true;

					if (CurLine === this.Numbering.Line && CurRange === this.Numbering.Range)
						DrawSelection.StartX += this.Numbering.WidthVisible;

					for (var CurPos = RStartPos; CurPos <= REndPos; CurPos++)
					{
						var Item = this.Content[CurPos];
						Item.Selection_DrawRange(CurLine, CurRange, DrawSelection);
					}

					var StartX = DrawSelection.StartX;
					var W      = DrawSelection.W;

					var StartY = DrawSelection.StartY;
					var H      = DrawSelection.H;

					if (true !== bInline)
					{
						var Frame_X_min = this.CalculatedFrame.L2;
						var Frame_Y_min = this.CalculatedFrame.T2;
						var Frame_X_max = this.CalculatedFrame.L2 + this.CalculatedFrame.W2;
						var Frame_Y_max = this.CalculatedFrame.T2 + this.CalculatedFrame.H2;

						StartX = Math.min(Math.max(Frame_X_min, StartX), Frame_X_max);
						StartY = Math.min(Math.max(Frame_Y_min, StartY), Frame_Y_max);
						W      = Math.min(W, Frame_X_max - StartX);
						H      = Math.min(H, Frame_Y_max - StartY);
					}

					// Отрисовываем селект
					if (W > 0.001)
						this.DrawingDocument.AddPageSelection(PageAbs, StartX, StartY, W, H);
				}
			}

			break;
		}
		case selectionflag_Numbering:
		case selectionflag_NumberingCur:
		{
			var ParaNum      = this.Numbering;
			var NumberingRun = ParaNum.Run;

			if (null === NumberingRun)
				break;

			var CurLine  = ParaNum.Line;
			var CurRange = ParaNum.Range;

			if (CurLine < this.Pages[CurPage].StartLine || CurLine > this.Pages[CurPage].EndLine)
				break;

			var SelectY = this.Lines[CurLine].Top + this.Pages[CurPage].Y;
			var SelectX = this.Lines[CurLine].Ranges[CurRange].XVisible;
			var SelectW = ParaNum.WidthVisible;
			var SelectH = this.Lines[CurLine].Bottom - this.Lines[CurLine].Top;

			var SelectW2 = SelectW;

			var oNumPr = this.GetNumPr();
			var nNumJc = this.Parent.GetNumbering().GetNum(oNumPr.NumId).GetLvl(oNumPr.Lvl).GetJc();

			switch (nNumJc)
			{
				case align_Center:
				{
					SelectX = this.Lines[CurLine].Ranges[CurRange].XVisible - ParaNum.WidthNum / 2;
					SelectW = ParaNum.WidthVisible + ParaNum.WidthNum / 2;
					break;
				}
				case align_Right:
				{
					SelectX = this.Lines[CurLine].Ranges[CurRange].XVisible - ParaNum.WidthNum;
					SelectW = ParaNum.WidthVisible + ParaNum.WidthNum;
					break;
				}
				case align_Left:
				default:
				{
					SelectX = this.Lines[CurLine].Ranges[CurRange].XVisible;
					SelectW = ParaNum.WidthVisible;
					break;
				}
			}

			this.DrawingDocument.AddPageSelection(PageAbs, SelectX, SelectY, SelectW, SelectH);

			if (selectionflag_NumberingCur === this.Selection.Flag && this.DrawingDocument.AddPageSelection2)
				this.DrawingDocument.AddPageSelection2(PageAbs, SelectX, SelectY, SelectW2, SelectH);

			break;
		}
	}
};
Paragraph.prototype.Selection_CheckParaEnd = function()
{
	if (true !== this.Selection.Use)
		return false;

	var EndPos = ( this.Selection.StartPos > this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos );

	return this.Content[EndPos].Selection_CheckParaEnd();
};
Paragraph.prototype.CheckPosInSelection = function(X, Y, CurPage, NearPos)
{
	if (undefined !== NearPos)
	{
		if (this === NearPos.Paragraph && ((true === this.Selection.Use && true === this.Selection_CheckParaContentPos(NearPos.ContentPos)) || true === this.ApplyToAll))
			return true;

		return false;
	}
	else
	{
		if (CurPage < 0 || CurPage >= this.Pages.length || true != this.Selection.Use)
			return false;

		var SearchPosXY = this.Get_ParaContentPosByXY(X, Y, CurPage, false, false, false);

		if (true === SearchPosXY.InTextX)
		{
			return this.Selection_CheckParaContentPos(SearchPosXY.InTextPos);
		}

		return false;
	}
};
/**
 * Проверяем попадание заданной позиции в селект. Сравнение стартовой и конечной позиций с заданной не совпадает
 * с работой данной функии, например в формулах.
 * @param ContentPos Заданная позиция в параграфе.
 */
Paragraph.prototype.Selection_CheckParaContentPos = function(ContentPos)
{
	var CurPos = ContentPos.Get(0);

	if (this.Selection.StartPos <= CurPos && CurPos <= this.Selection.EndPos)
		return this.Content[CurPos].Selection_CheckParaContentPos(ContentPos, 1, this.Selection.StartPos === CurPos, CurPos === this.Selection.EndPos);
	else if (this.Selection.EndPos <= CurPos && CurPos <= this.Selection.StartPos)
		return this.Content[CurPos].Selection_CheckParaContentPos(ContentPos, 1, this.Selection.EndPos === CurPos, CurPos === this.Selection.StartPos);

	return false;
};
Paragraph.prototype.Selection_CalculateTextPr = function()
{
	if (true === this.Selection.Use || true === this.ApplyToAll)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;

		if (true === this.ApplyToAll)
		{
			StartPos = 0;
			EndPos   = this.Content.length - 1;
		}

		if (StartPos > EndPos)
		{
			var Temp = EndPos;
			EndPos   = StartPos;
			StartPos = Temp;
		}

		if (EndPos >= this.Content.length)
			EndPos = this.Content.length - 1;
		if (StartPos < 0)
			StartPos = 0;

		if (StartPos == EndPos)
			return this.Internal_CalculateTextPr(StartPos);

		while (this.Content[StartPos].Type == para_TextPr)
			StartPos++;

		var oEnd = this.Internal_FindBackward(EndPos - 1, [para_Text, para_Space]);

		if (oEnd.Found)
			EndPos = oEnd.LetterPos;
		else
		{
			while (this.Content[EndPos].Type == para_TextPr)
				EndPos--;
		}

		// Рассчитаем стиль в начале селекта
		var TextPr_start = this.Internal_CalculateTextPr(StartPos);
		var TextPr_vis   = TextPr_start;

		for (var Pos = StartPos + 1; Pos < EndPos; Pos++)
		{
			var Item = this.Content[Pos];
			if (para_TextPr == Item.Type && Pos < this.Content.length - 1 && para_TextPr != this.Content[Pos + 1].Type)
			{
				// Рассчитываем настройки в данной позиции
				var TextPr_cur = this.Internal_CalculateTextPr(Pos);
				TextPr_vis     = TextPr_vis.Compare(TextPr_cur);
			}
		}

		return TextPr_vis;
	}
	else
		return new CTextPr();
};
Paragraph.prototype.Selection_SelectNumbering = function()
{
	if (undefined != this.GetNumPr())
	{
		this.Selection.Use  = true;
		this.Selection.Flag = selectionflag_Numbering;
	}
};
Paragraph.prototype.SelectNumbering = function(isCurrent)
{
	if (this.HaveNumbering())
	{
		this.Selection.Use  = true;
		this.Selection.Flag = isCurrent ? selectionflag_NumberingCur : selectionflag_Numbering;
	}
};
/**
 * Выставляем начало/конец селекта в начало/конец параграфа
 */
Paragraph.prototype.Selection_SetBegEnd = function(StartSelection, StartPara)
{
	var ContentPos = ( true === StartPara ? this.Get_StartPos() : this.Get_EndPos(true) );

	if (true === StartSelection)
	{
		this.Selection.StartManually = false;
		this.Set_SelectionContentPos(ContentPos, this.Get_ParaContentPos(true, false));
	}
	else
	{
		this.Selection.EndManually = false;
		this.Set_SelectionContentPos(this.Get_ParaContentPos(true, true), ContentPos);
	}
};
Paragraph.prototype.SetSelectionUse = function(isUse)
{
	if (true === isUse)
		this.Selection.Use = true;
	else
		this.RemoveSelection();
};
Paragraph.prototype.SetSelectionToBeginEnd = function(isSelectionStart, isElementStart)
{
	this.Selection_SetBegEnd(isSelectionStart, isElementStart);
};
Paragraph.prototype.SelectAll = function(Direction)
{
	this.Selection.Use = true;

	var StartPos = null, EndPos = null;
	if (-1 === Direction)
	{
		StartPos = this.Get_EndPos(true);
		EndPos   = this.Get_StartPos();
	}
	else
	{
		StartPos = this.Get_StartPos();
		EndPos   = this.Get_EndPos(true);
	}

	this.Selection.StartManually = false;
	this.Selection.EndManually   = false;

	this.Set_SelectionContentPos(StartPos, EndPos);
};
Paragraph.prototype.Select_Math = function(ParaMath)
{
	for (var nPos = 0, nCount = this.Content.length; nPos < nCount; nPos++)
	{
		if (this.Content[nPos] === ParaMath)
		{
			this.Selection.Use           = true;
			this.Selection.StartManually = false;
			this.Selection.EndManually   = false;
			this.Selection.StartPos      = nPos;
			this.Selection.EndPos        = nPos;
			this.Selection.Flag          = selectionflag_Common;

			this.Document_SetThisElementCurrent(false);
			return;
		}
	}
};
Paragraph.prototype.GetSelectionBounds = function()
{
	if (this.Pages.length <= 0 || this.Lines.length <= 0)
	{
		return {
			Start     : {X : 0, Y : 0, W : 0, H : 0, Page : 0},
			End       : {X : 0, Y : 0, W : 0, H : 0, Page : 0},
			Direction : 1
		};
	}

	var X0 = this.X, X1 = this.XLimit, Y = this.Y;

	var BeginRect = null;
	var EndRect   = null;

	var StartPage = 0, EndPage = 0;
	var _StartX   = null, _StartY = null, _EndX = null, _EndY = null;
	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;

		if (StartPos > EndPos)
		{
			StartPos = this.Selection.EndPos;
			EndPos   = this.Selection.StartPos;
		}

		var LinesCount = this.Lines.length;
		var StartLine  = -1;
		var EndLine    = -1;

		for (var CurLine = 0; CurLine < LinesCount; CurLine++)
		{
			if (-1 === StartLine && StartPos >= this.Lines[CurLine].Get_StartPos() && StartPos <= this.Lines[CurLine].Get_EndPos())
				StartLine = CurLine;

			if (EndPos >= this.Lines[CurLine].Get_StartPos() && EndPos <= this.Lines[CurLine].Get_EndPos())
				EndLine = CurLine;
		}

		StartLine = Math.min(Math.max(0, StartLine), LinesCount - 1);
		EndLine   = Math.min(Math.max(0, EndLine), LinesCount - 1);

		StartPage = this.GetPageByLine(StartLine);
		EndPage   = this.GetPageByLine(EndLine);

		var PagesCount     = this.Pages.length;
		var DrawSelection  = new CParagraphDrawSelectionRange();
		DrawSelection.Draw = false;

		for (var CurLine = StartLine; CurLine <= EndLine; CurLine++)
		{
			var Line        = this.Lines[CurLine];
			var RangesCount = Line.Ranges.length;

			var CurPage = this.GetPageByLine(CurLine);

			// Определяем позицию и высоту строки
			DrawSelection.StartY = this.Pages[CurPage].Y + this.Lines[CurLine].Top;
			DrawSelection.H      = this.Lines[CurLine].Bottom - this.Lines[CurLine].Top;

			var Result = null;

			for (var CurRange = 0; CurRange < RangesCount; CurRange++)
			{
				var Range = Line.Ranges[CurRange];

				var RStartPos = Range.StartPos;
				var REndPos   = Range.EndPos;

				// Если пересечение пустое с селектом, тогда пропускаем данный отрезок
				if (StartPos > REndPos || EndPos < RStartPos)
					continue;

				DrawSelection.StartX    = this.Lines[CurLine].Ranges[CurRange].XVisible;
				DrawSelection.W         = 0;
				DrawSelection.FindStart = true;

				if (CurLine === this.Numbering.Line && CurRange === this.Numbering.Range)
					DrawSelection.StartX += this.Numbering.WidthVisible;

				for (var CurPos = RStartPos; CurPos <= REndPos; CurPos++)
				{
					var Item = this.Content[CurPos];
					Item.Selection_DrawRange(CurLine, CurRange, DrawSelection);
				}

				var StartX = DrawSelection.StartX;
				var W      = DrawSelection.W;

				var StartY = DrawSelection.StartY;
				var H      = DrawSelection.H;

				if (W > 0.001)
				{
					X0 = StartX;
					X1 = StartX + W;
					Y  = StartY;

					var Page = this.Get_AbsolutePage(CurPage);

					if (null === BeginRect)
						BeginRect = {X : StartX, Y : StartY, W : W, H : H, Page : Page};

					EndRect = {X : StartX, Y : StartY, W : W, H : H, Page : Page};
				}

				if (null === _StartX)
				{
					_StartX = StartX;
					_StartY = StartY;
				}

				_EndX = StartX;
				_EndY = StartY;
			}
		}
	}

	if (null === BeginRect)
		BeginRect = {
			X    : _StartX === null ? this.Pages[StartPage].X : _StartX,
			Y    : _StartY === null ? this.Pages[StartPage].Y : _StartY,
			W    : 0,
			H    : 0,
			Page : this.Get_AbsolutePage(StartPage)
		};

	if (null === EndRect)
		EndRect = {
			X    : _EndX === null ? this.Pages[StartPage].X : _EndX,
			Y    : _EndY === null ? this.Pages[StartPage].Y : _EndY,
			W    : 0,
			H    : 0,
			Page : this.Get_AbsolutePage(EndPage)
		};

	return {Start : BeginRect, End : EndRect, Direction : this.Get_SelectionDirection()};
};
Paragraph.prototype.Get_SelectionDirection = function()
{
	if (true !== this.Selection.Use)
		return 0;

	if (this.Selection.StartPos < this.Selection.EndPos)
		return 1;
	else if (this.Selection.StartPos > this.Selection.EndPos)
		return -1;

	return this.Content[this.Selection.StartPos].Get_SelectionDirection();
};
Paragraph.prototype.GetSelectionAnchorPos = function()
{
	var X0 = this.X, X1 = this.XLimit, Y = this.Y, Page = this.Get_AbsolutePage(0);
	if (true === this.ApplyToAll)
	{
		// Ничего не делаем
	}
	else if (true === this.Selection.Use)
	{
		// Делаем подсветку
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;

		if (StartPos > EndPos)
		{
			StartPos = this.Selection.EndPos;
			EndPos   = this.Selection.StartPos;
		}

		var LinesCount = this.Lines.length;
		var StartLine  = -1;
		var EndLine    = -1;

		for (var CurLine = 0; CurLine < LinesCount; CurLine++)
		{
			if (-1 === StartLine && StartPos >= this.Lines[CurLine].Get_StartPos() && StartPos <= this.Lines[CurLine].Get_EndPos())
				StartLine = CurLine;

			if (EndPos >= this.Lines[CurLine].Get_StartPos() && EndPos <= this.Lines[CurLine].Get_EndPos())
				EndLine = CurLine;
		}

		StartLine = Math.min(Math.max(0, StartLine), LinesCount - 1);
		EndLine   = Math.min(Math.max(0, EndLine), LinesCount - 1);

		var PagesCount     = this.Pages.length;
		var DrawSelection  = new CParagraphDrawSelectionRange();
		DrawSelection.Draw = false;

		for (var CurLine = StartLine; CurLine <= EndLine; CurLine++)
		{
			var Line        = this.Lines[CurLine];
			var RangesCount = Line.Ranges.length;

			// Определим номер страницы
			var CurPage = 0;
			for (; CurPage < PagesCount; CurPage++)
			{
				if (CurLine >= this.Pages[CurPage].StartLine && CurLine <= this.Pages[CurPage].EndLine)
					break;
			}

			CurPage = Math.min(PagesCount - 1, CurPage);

			// Определяем позицию и высоту строки
			DrawSelection.StartY = this.Pages[CurPage].Y + this.Lines[CurLine].Top;
			DrawSelection.H      = this.Lines[CurLine].Bottom - this.Lines[CurLine].Top;

			var Result = null;

			for (var CurRange = 0; CurRange < RangesCount; CurRange++)
			{
				var Range = Line.Ranges[CurRange];

				var RStartPos = Range.StartPos;
				var REndPos   = Range.EndPos;

				// Если пересечение пустое с селектом, тогда пропускаем данный отрезок
				if (StartPos > REndPos || EndPos < RStartPos)
					continue;

				DrawSelection.StartX    = this.Lines[CurLine].Ranges[CurRange].XVisible;
				DrawSelection.W         = 0;
				DrawSelection.FindStart = true;

				if (CurLine === this.Numbering.Line && CurRange === this.Numbering.Range)
					DrawSelection.StartX += this.Numbering.WidthVisible;

				for (var CurPos = RStartPos; CurPos <= REndPos; CurPos++)
				{
					var Item = this.Content[CurPos];
					Item.Selection_DrawRange(CurLine, CurRange, DrawSelection);
				}

				var StartX = DrawSelection.StartX;
				var W      = DrawSelection.W;

				var StartY = DrawSelection.StartY;
				var H      = DrawSelection.H;

				var StartX = DrawSelection.StartX;
				var W      = DrawSelection.W;

				var StartY = DrawSelection.StartY;
				var H      = DrawSelection.H;

				if (W > 0.001)
				{
					X0 = StartX;
					X1 = StartX + W;
					Y  = StartY;

					Page = this.Get_AbsolutePage(CurPage);

					if (null === Result)
						Result = {X0 : X0, X1 : X1, Y : Y, Page : Page};
					else
					{
						Result.X0 = Math.min(Result.X0, X0);
						Result.X1 = Math.max(Result.X1, X1);
					}
				}
			}

			if (null !== Result)
			{
				return Result;
			}
		}
	}
	else
	{
		// Текущая точка
		X0   = this.CurPos.X;
		X1   = this.CurPos.X;
		Y    = this.CurPos.Y;
		Page = this.Get_AbsolutePage(this.CurPos.PagesPos);
	}

	return {X0 : X0, X1 : X1, Y : Y, Page : Page};
};
/**
 * Возвращаем выделенный текст
 */
Paragraph.prototype.GetSelectedText = function(bClearText, oPr)
{
	var Str   = "";
	var Count = this.Content.length;
	for (var Pos = 0; Pos < Count; Pos++)
	{
		var _Str = this.Content[Pos].GetSelectedText(true === this.ApplyToAll, bClearText, oPr);

		if (null === _Str)
			return null;

		Str += _Str;
	}

	return Str;
};
Paragraph.prototype.GetSelectedElementsInfo = function(Info, ContentPos, Depth)
{
	Info.SetParagraph(this);

	if (ContentPos)
	{
		var Pos = ContentPos.Get(Depth);
		if (this.Content[Pos].GetSelectedElementsInfo)
			this.Content[Pos].GetSelectedElementsInfo(Info, ContentPos, Depth + 1);
	}
	else
	{
		if (true === this.Selection.Use && this.Selection.StartPos === this.Selection.EndPos && this.Content[this.Selection.EndPos].GetSelectedElementsInfo)
			this.Content[this.Selection.EndPos].GetSelectedElementsInfo(Info);
		else if (false === this.Selection.Use && this.Content[this.CurPos.ContentPos].GetSelectedElementsInfo)
			this.Content[this.CurPos.ContentPos].GetSelectedElementsInfo(Info);

		if (true !== this.Selection.Use)
		{
			var oNextElement = this.GetNextRunElement();
			var oPrevElement = this.GetPrevRunElement();

			if (oNextElement)
			{
				if (para_PageNum === oNextElement.Type)
				{
					Info.SetPageNum(oNextElement);
				}
				else if (para_PageCount === oNextElement.Type)
				{
					Info.SetPagesCount(oNextElement);
				}
			}

			if (oPrevElement)
			{
				if (para_PageNum === oPrevElement.Type)
				{
					Info.SetPageNum(oPrevElement);
				}
				else if (para_PageCount === oPrevElement.Type)
				{
					Info.SetPagesCount(oPrevElement);
				}
			}
		}
	}

	var arrComplexFields = this.GetComplexFieldsByPos(ContentPos ? ContentPos : (this.Selection.Use === true ? this.Get_ParaContentPos(false, false) : this.Get_ParaContentPos(false)), false);
	if (arrComplexFields.length > 0)
		Info.SetComplexFields(arrComplexFields);
};
Paragraph.prototype.GetElementsInfoByXY = function(oInfo, X, Y, CurPage)
{
	var SearchPosXY = this.Get_ParaContentPosByXY(X, Y, CurPage, false, false);
	this.GetSelectedElementsInfo(oInfo, SearchPosXY.Pos, 0);
};
Paragraph.prototype.GetSelectedContent = function(DocContent)
{
	if (true !== this.Selection.Use)
		return;

	var StartPos = this.Selection.StartPos;
	var EndPos   = this.Selection.EndPos;
	if (StartPos > EndPos)
	{
		StartPos = this.Selection.EndPos;
		EndPos   = this.Selection.StartPos;
	}

	var Para = null;
	if (true === this.Selection_IsFromStart(true) && true === this.Selection_CheckParaEnd())
	{
		Para = this.Copy(this.Parent);
		DocContent.Add(new CSelectedElement(Para, true));
	}
	else
	{
		Para = new Paragraph(this.DrawingDocument, this.Parent, !this.bFromDocument);

		// Копируем настройки
		Para.Set_Pr(this.Pr.Copy());
		Para.TextPr.Set_Value(this.TextPr.Value.Copy());

		// Копируем содержимое параграфа
		for (var Pos = StartPos; Pos <= EndPos; Pos++)
		{
			var Item = this.Content[Pos];

			if ((StartPos === Pos || EndPos === Pos) && true !== Item.IsSelectedAll())
			{
				var Content = Item.CopyContent(true);
				for (var ContentPos = 0, ContentLen = Content.length; ContentPos < ContentLen; ContentPos++)
				{
					Para.Internal_Content_Add(Pos - StartPos + ContentPos, Content[ContentPos], false);
				}
			}
			else
			{
				Para.Internal_Content_Add(Pos - StartPos, Item.Copy(false), false);
			}
		}

		// Добавляем секцию в конце
		if (undefined !== this.SectPr)
		{
			var SectPr = new CSectionPr(this.SectPr.LogicDocument);
			SectPr.Copy(this.SectPr);
			Para.Set_SectionPr(SectPr);
		}
		DocContent.Add(new CSelectedElement(Para, false));
	}
};
Paragraph.prototype.GetCalculatedTextPr = function()
{
	var TextPr;
	if (true === this.ApplyToAll)
	{
		this.SelectAll(1);

		var StartPos = 0;
		var Count    = this.Content.length;
		while (true !== this.Content[StartPos].Is_CursorPlaceable() && StartPos < Count - 1)
			StartPos++;

		TextPr    = this.Content[StartPos].Get_CompiledTextPr(true);
		var Count = this.Content.length;

		for (var CurPos = StartPos + 1; CurPos < Count; CurPos++)
		{
			var TempTextPr = this.Content[CurPos].Get_CompiledTextPr(false);
			if (null !== TempTextPr && undefined !== TempTextPr && true !== this.Content[CurPos].IsSelectionEmpty())
				TextPr = TextPr.Compare(TempTextPr);
		}

		this.RemoveSelection();
	}
	else
	{
		if (true === this.Selection.Use)
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;

			if (StartPos > EndPos)
			{
				StartPos = this.Selection.EndPos;
				EndPos   = this.Selection.StartPos;
			}

			// TODO: Как только избавимся от para_End переделать здесь.

			if (StartPos === EndPos && this.Content.length - 1 === EndPos)
			{
				TextPr = this.Get_CompiledPr2(false).TextPr.Copy();
				TextPr.Merge(this.TextPr.Value);
			}
			else
			{
				var bCheckParaEnd = false;
				if (this.Content.length - 1 === EndPos && true !== this.Content[EndPos].IsSelectionEmpty(true))
				{
					EndPos--;
					bCheckParaEnd = true;
				}

				// Сначала пропускаем все пустые элементы. После этой операции мы можем попасть в элемент, в котором
				// нельзя находиться курсору, поэтому ищем в обратном направлении первый подходящий элемент.
				var OldStartPos = StartPos;
				while (true === this.Content[StartPos].IsSelectionEmpty() && StartPos < EndPos)
					StartPos++;

				while (true !== this.Content[StartPos].Is_CursorPlaceable() && StartPos > OldStartPos)
					StartPos--;


				if (bCheckParaEnd && StartPos === EndPos && this.Content[StartPos].IsSelectionEmpty())
					TextPr = null;
				else
					TextPr = this.Content[StartPos].Get_CompiledTextPr(true);

				// Если все-так так сложилось, что мы находимся в элементе без настроек, тогда берем настройки для
				// символа конца параграфа.
				if (null === TextPr)
				{
					TextPr = this.Get_CompiledPr2(false).TextPr.Copy();
					TextPr.Merge(this.TextPr.Value);
				}

				for (var CurPos = StartPos + 1; CurPos <= EndPos; CurPos++)
				{
					var TempTextPr = this.Content[CurPos].Get_CompiledTextPr(false);

					if (null === TextPr || undefined === TextPr)
						TextPr = TempTextPr;
					else if (null !== TempTextPr && undefined !== TempTextPr && true !== this.Content[CurPos].IsSelectionEmpty())
						TextPr = TextPr.Compare(TempTextPr);
				}

				if (true === bCheckParaEnd)
				{
					var EndTextPr = this.Get_CompiledPr2(false).TextPr.Copy();
					EndTextPr.Merge(this.TextPr.Value);
					TextPr = TextPr.Compare(EndTextPr);
				}
			}
		}
		else
		{
			TextPr = this.Content[this.CurPos.ContentPos].Get_CompiledTextPr(true);

			var oRun = this.Get_ElementByPos(this.Get_ParaContentPos(false, false, false));
			if (para_Run === oRun.Type && oRun.private_IsCurPosNearFootnoteReference())
				TextPr.VertAlign = AscCommon.vertalign_Baseline;
		}
	}

	if (null === TextPr || undefined === TextPr)
		TextPr = this.TextPr.Value.Copy();

	// TODO: Пока возвращаем всегда шрифт лежащий в Ascii, в будущем надо будет это переделать
	if (undefined !== TextPr.RFonts && null !== TextPr.RFonts)
		TextPr.FontFamily = TextPr.RFonts.Ascii;

	return TextPr;
};
Paragraph.prototype.GetCalculatedParaPr = function()
{
	var ParaPr = this.Get_CompiledPr2(false).ParaPr;
	ParaPr.Locked = this.Lock.Is_Locked();
	return ParaPr;
};
/**
 * Проверяем пустой ли параграф
 */
Paragraph.prototype.Is_Empty = function(Props)
{
	var Pr = {SkipEnd : true};

	if (undefined !== Props)
	{
		if (undefined !== Props.SkipNewLine)
			Pr.SkipNewLine = true;

		if (Props.SkipComplexFields)
			Pr.SkipComplexFields = true;

		if (undefined !== Props.SkipPlcHldr)
			Pr.SkipPlcHldr = Props.SkipPlcHldr;
	}

	var ContentLen = this.Content.length;
	for (var CurPos = 0; CurPos < ContentLen; CurPos++)
	{
		if (false === this.Content[CurPos].Is_Empty(Pr))
			return false;
	}

	return true;
};
/**
 * Проверяем, попали ли мы в текст
 */
Paragraph.prototype.IsInText = function(X, Y, CurPage)
{
	if (CurPage < 0 || CurPage >= this.Pages.length)
		return null;

	var SearchPosXY = this.Get_ParaContentPosByXY(X, Y, CurPage, false, false);
	if (true === SearchPosXY.InText)
		return this;

	return null;
};
Paragraph.prototype.Is_UseInDocument = function(Id)
{
	if (Id !== undefined)
	{
		for (var i = 0; i < this.Content.length; ++i)
		{
			if (this.Content[i].Get_Id() === Id)
			{
				break;
			}
		}
		if (i < this.Content.length)
		{
			if (this.Parent)
			{
				return this.Parent.Is_UseInDocument(this.Get_Id());
			}
		}
		return false;
	}

	if (null != this.Parent)
		return this.Parent.Is_UseInDocument(this.Get_Id());

	return false;
};
/**
 * Проверяем пустой ли селект
 */
Paragraph.prototype.IsSelectionEmpty = function(bCheckHidden)
{
	if (undefined === bCheckHidden)
		bCheckHidden = true;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;

		if (StartPos > EndPos)
		{
			EndPos   = this.Selection.StartPos;
			StartPos = this.Selection.EndPos;
		}

		for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
		{
			if (true !== this.Content[CurPos].IsSelectionEmpty(bCheckHidden))
				return false;
		}
	}

	return true;
};
Paragraph.prototype.Get_StartTabsCount = function(TabsCounter)
{
	var ContentLen = this.Content.length;
	for (var Pos = 0; Pos < ContentLen; Pos++)
	{
		var Element = this.Content[Pos];
		if (false === Element.Get_StartTabsCount(TabsCounter))
			return false;
	}

	return true;
};
Paragraph.prototype.Remove_StartTabs = function(TabsCounter)
{
	var ContentLen = this.Content.length;
	for (var Pos = 0; Pos < ContentLen; Pos++)
	{
		var Element = this.Content[Pos];
		if (false === Element.Remove_StartTabs(TabsCounter))
			return false;
	}

	return true;
};
/**
 * Применяем заданную нумерацию к данному параграфу (учитываем отступы, количество табов в начале параграфа и т.д.)
 * @param sNumId {string}
 * @param nLvl {number} 0..8
 */
Paragraph.prototype.ApplyNumPr = function(sNumId, nLvl)
{
	var ParaPr    = this.Get_CompiledPr2(false).ParaPr;
	var NumPr_old = this.GetNumPr();

	var SelectionUse       = this.IsSelectionUse();
	var SelectedOneElement = this.Parent.IsSelectedSingleElement();

	// Когда выделено больше 1 параграфа, нумерация не добавляется к пустым параграфам без нумерации
	if (true === SelectionUse && true !== SelectedOneElement && true === this.Is_Empty() && !this.GetNumPr())
		return;

	this.RemoveNumPr();

	// Рассчитаем количество табов, идущих в начале параграфа
	var TabsCounter = new CParagraphTabsCounter();
	this.Get_StartTabsCount(TabsCounter);

	var TabsCount = TabsCounter.Count;
	var TabsPos   = TabsCounter.Pos;

	// Рассчитаем левую границу и сдвиг первой строки с учетом начальных табов
	var X = ParaPr.Ind.Left + ParaPr.Ind.FirstLine;
	if (TabsCount > 0 && ParaPr.Ind.FirstLine < 0)
	{
		X = ParaPr.Ind.Left;
		TabsCount--;
	}

	var ParaTabsCount = ParaPr.Tabs.Get_Count();
	while (TabsCount)
	{
		// Ищем ближайший таб

		var TabFound = false;
		for (var TabIndex = 0; TabIndex < ParaTabsCount; TabIndex++)
		{
			var Tab = ParaPr.Tabs.Get(TabIndex);

			if (Tab.Pos > X)
			{
				X        = Tab.Pos;
				TabFound = true;
				break;
			}
		}

		// Ищем по дефолтовому сдвигу
		if (false === TabFound)
		{
			var NewX = 0;
			while (X >= NewX)
				NewX += AscCommonWord.Default_Tab_Stop;

			X = NewX;
		}

		TabsCount--;
	}

	var oNumbering = this.Parent.GetNumbering();
	var oNum       = oNumbering.GetNum(sNumId);

	this.private_AddPrChange();

	// Если у параграфа не было никакой нумерации изначально
	if (undefined === NumPr_old)
	{
		if (true === SelectedOneElement || false === SelectionUse)
		{
			// Проверим сначала предыдущий элемент, если у него точно такая же нумерация, тогда копируем его сдвиги
			var Prev          = this.Get_DocumentPrev();
			var PrevNumbering = ( null != Prev ? (type_Paragraph === Prev.GetType() ? Prev.GetNumPr() : undefined) : undefined );
			if (undefined != PrevNumbering && sNumId === PrevNumbering.NumId && nLvl === PrevNumbering.Lvl)
			{
				var NewFirstLine = Prev.Pr.Ind.FirstLine;
				var NewLeft      = Prev.Pr.Ind.Left;
				History.Add(new CChangesParagraphIndFirst(this, this.Pr.Ind.FirstLine, NewFirstLine));
				History.Add(new CChangesParagraphIndLeft(this, this.Pr.Ind.Left, NewLeft));

				// При добавлении списка в параграф, удаляем все собственные сдвиги
				this.Pr.Ind.FirstLine = NewFirstLine;
				this.Pr.Ind.Left      = NewLeft;
			}
			else
			{
				// Выставляем заданную нумерацию и сдвиги. Сдвиг делаем на ближайшую остановку стандартного таба

				var oNumParaPr = oNum.GetLvl(nLvl).GetParaPr();
				if (undefined != oNumParaPr.Ind && undefined != oNumParaPr.Ind.Left)
				{
					oNum.ShiftLeftInd(X + 12.5);
					//oNum.ShiftLeftInd(X + oNumParaPr.Ind.Left);

					History.Add(new CChangesParagraphIndFirst(this, this.Pr.Ind.FirstLine, undefined));
					History.Add(new CChangesParagraphIndLeft(this, this.Pr.Ind.Left, undefined));

					// При добавлении списка в параграф, удаляем все собственные сдвиги
					this.Pr.Ind.FirstLine = undefined;
					this.Pr.Ind.Left      = undefined;
				}
			}

			this.Pr.NumPr = new CNumPr();
			this.Pr.NumPr.Set(sNumId, nLvl);
			History.Add(new CChangesParagraphNumbering(this, NumPr_old, this.Pr.NumPr));
			this.private_RefreshNumbering(NumPr_old);
			this.private_RefreshNumbering(this.Pr.NumPr);
		}
		else
		{
			// Если выделено несколько параграфов, тогда уже по сдвигу X определяем уровень данной нумерации

			var LvlFound  = -1;
			for (var LvlIndex = 0; LvlIndex < 9; ++LvlIndex)
			{
				var oNumLvl = oNum.GetLvl(LvlIndex);
				if (oNumLvl)
				{
					var oNumParaPr = oNumLvl.GetParaPr();

					if (undefined != oNumParaPr.Ind && undefined != oNumParaPr.Ind.Left && X <= oNumParaPr.Ind.Left)
					{
						LvlFound = LvlIndex;
						break;
					}
				}
			}

			if (-1 === LvlFound)
				LvlFound = 8;

			if (this.Pr.Ind && (undefined !== this.Pr.Ind || undefined !== this.Pr.Ind.Left))
			{
				History.Add(new CChangesParagraphIndFirst(this, this.Pr.Ind.FirstLine, undefined));
				History.Add(new CChangesParagraphIndLeft(this, this.Pr.Ind.Left, undefined));

				// При добавлении списка в параграф, удаляем все собственные сдвиги
				this.Pr.Ind.FirstLine = undefined;
				this.Pr.Ind.Left      = undefined;
			}

			this.Pr.NumPr = new CNumPr();
			this.Pr.NumPr.Set(sNumId, LvlFound);
			History.Add(new CChangesParagraphNumbering(this, NumPr_old, this.Pr.NumPr));
			this.private_RefreshNumbering(NumPr_old);
			this.private_RefreshNumbering(this.Pr.NumPr);
		}

		// Удалим все табы идущие в начале параграфа
		TabsCounter.Count = TabsCount;
		this.Remove_StartTabs(TabsCounter);
	}
	else
	{
		// просто меняем список, так чтобы он не двигался
		this.Pr.NumPr = new CNumPr();
		this.Pr.NumPr.Set(sNumId, nLvl);

		History.Add(new CChangesParagraphNumbering(this, NumPr_old, this.Pr.NumPr));
		this.private_RefreshNumbering(NumPr_old);
		this.private_RefreshNumbering(this.Pr.NumPr);

		var Left      = ( NumPr_old.Lvl === nLvl ? undefined : ParaPr.Ind.Left );
		var FirstLine = ( NumPr_old.Lvl === nLvl ? undefined : ParaPr.Ind.FirstLine );

		History.Add(new CChangesParagraphIndFirst(this, this.Pr.Ind.FirstLine, FirstLine));
		History.Add(new CChangesParagraphIndLeft(this, this.Pr.Ind.Left, Left));

		this.Pr.Ind.FirstLine = FirstLine;
		this.Pr.Ind.Left      = Left;
	}

	// Если у параграфа выставлен стиль, тогда не меняем его, если нет, тогда выставляем стандартный
	// стиль для параграфа с нумерацией.
	if (undefined === this.Style_Get())
	{
		if (this.bFromDocument)
			this.Style_Add(this.Parent.Get_Styles().Get_Default_ParaList());
	}

	// Надо пересчитать конечный стиль
	this.CompiledPr.NeedRecalc = true;
	this.private_UpdateTrackRevisionOnChangeParaPr(true);
};
/**
 * Добавляем нумерацию к данному параграфу, не делая никаких дополнительных действий
 * @param sNumId {?string} Если undefined или null, тогда убираем нумерацию
 * @param nLvl {number} 0..8
 */
Paragraph.prototype.SetNumPr = function(sNumId, nLvl)
{
	if (undefined === sNumId || null === sNumId)
	{
		if (undefined !== this.Pr.NumPr)
		{
			this.private_AddPrChange();

			History.Add(new CChangesParagraphNumbering(this, this.Pr.NumPr, undefined));
			this.private_RefreshNumbering(this.Pr.NumPr);

			this.Pr.NumPr = undefined;

			this.CompiledPr.NeedRecalc = true;
			this.private_UpdateTrackRevisionOnChangeParaPr(true);
		}
	}
	else
	{
		if (nLvl < 0 || nLvl > 8)
			nLvl = 0;

		var oNumPrOld = this.Pr.NumPr;
		this.Pr.NumPr = new CNumPr(sNumId, nLvl);

		this.private_AddPrChange();
		History.Add(new CChangesParagraphNumbering(this, oNumPrOld, this.Pr.NumPr));
		this.private_RefreshNumbering(oNumPrOld);
		this.private_RefreshNumbering(this.Pr.NumPr);

		// Надо пересчитать конечный стиль
		this.CompiledPr.NeedRecalc = true;
		this.private_UpdateTrackRevisionOnChangeParaPr(true);
	}
};
/**
 * Изменяем уровень нумерации
 * @param bIncrease {boolean}
 */
Paragraph.prototype.IndDecNumberingLevel = function(bIncrease)
{
	var NumPr = this.GetNumPr();
	if (undefined != NumPr)
	{
		var NewLvl;
		if (true === bIncrease)
			NewLvl = Math.min(8, NumPr.Lvl + 1);
		else
			NewLvl = Math.max(0, NumPr.Lvl - 1);

		this.Pr.NumPr = new CNumPr();
		this.Pr.NumPr.Set(NumPr.NumId, NewLvl);

		this.private_AddPrChange();
		History.Add(new CChangesParagraphNumbering(this, NumPr, this.Pr.NumPr));
		this.private_RefreshNumbering(NumPr);
		this.private_RefreshNumbering(this.Pr.NumPr);

		// Надо пересчитать конечный стиль
		this.CompiledPr.NeedRecalc = true;
		this.private_UpdateTrackRevisionOnChangeParaPr(true);
	}
};
/**
 * Получаем настройку нумерации у данного параграфа, если она есть
 * @returns {?CNumPr}
 */
Paragraph.prototype.GetNumPr = function()
{
	var oNumPr = this.Get_CompiledPr2(false).ParaPr.NumPr;
	if (oNumPr && oNumPr.IsValid())
		return oNumPr.Copy();

	return undefined;
};
/**
 * Удаляем нумерацию с учетом того, что она может быть задана в стиле
 */
Paragraph.prototype.RemoveNumPr = function()
{
	// Если у нас была задана нумерации в стиле, тогда чтобы ее отменить(не удаляя нумерацию в стиле)
	// мы проставляем NumPr с NumId undefined
	var OldNumPr = this.GetNumPr();
	var NewNumPr = undefined;
	if (undefined != this.CompiledPr.Pr.ParaPr.StyleNumPr)
	{
		NewNumPr = new CNumPr();
		NewNumPr.Set(0, 0);
	}

	this.private_AddPrChange();

	var OldNumPr = undefined != this.Pr.NumPr ? this.Pr.NumPr : undefined;

	History.Add(new CChangesParagraphNumbering(this, OldNumPr, NewNumPr));
	this.private_RefreshNumbering(OldNumPr);
	this.private_RefreshNumbering(NewNumPr);

	this.Pr.NumPr = NewNumPr;

	if (undefined != this.Pr.Ind && undefined != OldNumPr)
	{
		// При удалении нумерации из параграфа, если отступ первой строки > 0, тогда
		// увеличиваем левый отступ параграфа, а первую сторку  делаем 0, а если отступ
		// первой строки < 0, тогда просто делаем оступ первой строки 0.

		if (undefined === this.Pr.Ind.FirstLine || Math.abs(this.Pr.Ind.FirstLine) < 0.001)
		{
			if (undefined != OldNumPr && undefined != OldNumPr.NumId && this.Parent)
			{
				var oNum = this.Parent.GetNumbering().GetNum(OldNumPr.NumId);
				if (oNum)
				{
					var oLvl = oNum.GetLvl(OldNumPr.Lvl);
					var oLvlParaPr = oLvl ? oLvl.GetParaPr() : null;
					if (oLvlParaPr && undefined != oLvlParaPr.Ind && undefined != oLvlParaPr.Ind.Left)
					{
						var CurParaPr         = this.Get_CompiledPr2(false).ParaPr;
						var Left              = CurParaPr.Ind.Left + CurParaPr.Ind.FirstLine;
						var NumLeftCorrection = ( undefined != oLvlParaPr.Ind.FirstLine ? Math.abs(oLvlParaPr.Ind.FirstLine) : 0 );

						var NewFirstLine = 0;
						var NewLeft      = Left < 0 ? Left : Math.max(0, Left - NumLeftCorrection);

						History.Add(new CChangesParagraphIndLeft(this, this.Pr.Ind.Left, NewLeft));
						History.Add(new CChangesParagraphIndFirst(this, this.Pr.Ind.FirstLine, NewFirstLine));
						this.Pr.Ind.Left      = NewLeft;
						this.Pr.Ind.FirstLine = NewFirstLine;
					}
				}
			}
		}
		else if (this.Pr.Ind.FirstLine < 0)
		{
			History.Add(new CChangesParagraphIndFirst(this, this.Pr.Ind.FirstLine, 0));
			this.Pr.Ind.FirstLine = 0;
		}
		else if (undefined != this.Pr.Ind.Left && this.Pr.Ind.FirstLine > 0)
		{
			History.Add(new CChangesParagraphIndLeft(this, this.Pr.Ind.Left, this.Pr.Ind.Left + this.Pr.Ind.FirstLine));
			History.Add(new CChangesParagraphIndFirst(this, this.Pr.Ind.FirstLine, 0));
			this.Pr.Ind.Left += this.Pr.Ind.FirstLine;
			this.Pr.Ind.FirstLine = 0;
		}
	}

	// При удалении проверяем стиль. Если данный стиль является стилем по умолчанию
	// для параграфов с нумерацией, тогда удаляем запись и о стиле.
	var StyleId    = this.Style_Get();
	var NumStyleId = this.LogicDocument ? this.LogicDocument.Get_Styles().Get_Default_ParaList() : null;
	if (StyleId === NumStyleId)
		this.Style_Remove();

	// Надо пересчитать конечный стиль
	this.CompiledPr.NeedRecalc = true;
	this.private_UpdateTrackRevisionOnChangeParaPr(true);
};
/**
 * Проверяем есть ли у данного параграфа нумерация
 * @returns {boolean}
 */
Paragraph.prototype.HaveNumbering = function()
{
	return (!!this.GetNumPr());
};
/**
 * Получаем скомпилированные текстовые настройки для символа нумерации
 * @returns {?CTextPr}
 */
Paragraph.prototype.GetNumberingCompiledPr = function()
{
	var oNumPr = this.GetNumPr();
	if (!oNumPr || !this.LogicDocument)
		return null;

	var oNumbering = this.LogicDocument.GetNumbering();
	var oNumLvl    = oNumbering.GetNum(oNumPr.NumId).GetLvl(oNumPr.Lvl);

	var oTextPr = this.Get_CompiledPr2(false).TextPr.Copy();
	oTextPr.Merge(this.TextPr.Value);
	oTextPr.Merge(oNumLvl.GetTextPr());
	return oTextPr;
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с нумерацией параграфов в презентациях
//----------------------------------------------------------------------------------------------------------------------
Paragraph.prototype.Add_PresentationNumbering = function(_Bullet)
{
	var ParaPr                 = this.Get_CompiledPr2(false).ParaPr;
	var _OldBullet = this.Pr.Bullet;
	this.Pr.Bullet             = undefined;
	this.CompiledPr.NeedRecalc = true;

	var oBullet2;
	if (_Bullet)
	{
		oBullet2 = _Bullet;
	}
	else
	{
		oBullet2                 = new AscFormat.CBullet();
		oBullet2.bulletType      = new AscFormat.CBulletType();
		oBullet2.bulletType.type = AscFormat.BULLET_TYPE_BULLET_NONE;
	}
	var oTheme = this.Get_Theme();
	var oColorMap = this.Get_ColorMap();
	var oUndefParaPr = this.Get_CompiledPr2(false).ParaPr;
	var NewType      = oBullet2.getBulletType();
	var UndefType    = oUndefParaPr.Bullet ? oUndefParaPr.Bullet.getBulletType(oTheme, oColorMap) : numbering_presentationnumfrmt_None;
	var LeftInd;

	if (NewType === UndefType)
	{
		if (NewType === numbering_presentationnumfrmt_Char)//буллеты
		{
			var oUndefPresentationBullet = oUndefParaPr.Bullet.getPresentationBullet(oTheme, oColorMap);
			var oNewPresentationBullet   = oBullet2.getPresentationBullet(oTheme, oColorMap);
			if (oUndefPresentationBullet.m_sChar === oNewPresentationBullet.m_sChar)//символы совпали. ничего выставлять не надо.
			{
                this.Pr.Bullet = _OldBullet;
				this.Set_Bullet(undefined);
			}
			else
			{
                this.Pr.Bullet = _OldBullet;
				this.Set_Bullet(oBullet2.createDuplicate());//тип совпал, но не совпали символы. выставляем Bullet.
															// Indent в данном случае не выставляем как это делает
															// PowerPoint.
			}
		}
		else //нумерация или отсутствие нумерации
		{
            this.Pr.Bullet = _OldBullet;
			this.Set_Bullet(undefined);
		}
		this.Set_Ind({Left : undefined, FirstLine : undefined}, true);
	}
	else//тип не совпал. выставляем буллет, а также проверим нужно ли выставлять Indent.
	{
        this.Pr.Bullet = _OldBullet;
		this.Set_Bullet(oBullet2.createDuplicate());
		LeftInd = Math.min(ParaPr.Ind.Left, ParaPr.Ind.Left + ParaPr.Ind.FirstLine);
		var oFirstRunPr = this.Get_FirstTextPr2();
		var Indent = oFirstRunPr.FontSize*0.305954545 + 2.378363636;
		if (NewType === numbering_presentationnumfrmt_Char)
		{
			this.Set_Ind({Left : LeftInd + Indent, FirstLine : -Indent}, false);
		}
		else if (NewType === numbering_presentationnumfrmt_None)
		{
			this.Set_Ind({FirstLine : 0, Left : LeftInd}, false);
		}
		else
		{
			var oArabicAlphaMap =
					{
						numbering_presentationnumfrmt_ArabicPeriod  : true,
						numbering_presentationnumfrmt_ArabicParenR  : true,
						numbering_presentationnumfrmt_AlphaLcParenR : true,
						numbering_presentationnumfrmt_AlphaLcPeriod : true,
						numbering_presentationnumfrmt_AlphaUcParenR : true,
						numbering_presentationnumfrmt_AlphaUcPeriod : true
					};
			var oRomanMap       =
					{
						numbering_presentationnumfrmt_RomanUcPeriod : true,
						numbering_presentationnumfrmt_RomanLcPeriod : true
					};
			if (!(oArabicAlphaMap[NewType] && oArabicAlphaMap[UndefType] || oRomanMap[NewType] && oRomanMap[UndefType]))
			{
				if (oArabicAlphaMap[NewType])
				{
					this.Set_Ind({Left : LeftInd + Indent, FirstLine : -Indent}, false);
				}
				else
				{
					this.Set_Ind({Left : LeftInd + Indent, FirstLine : -Indent}, false);
				}
			}
			else
			{
				this.Set_Ind({Left : undefined, FirstLine : undefined}, true);
			}
		}
	}
};
Paragraph.prototype.Get_PresentationNumbering = function()
{
	this.Get_CompiledPr2(false);
	return this.PresentationPr.Bullet;
};
Paragraph.prototype.Remove_PresentationNumbering = function()
{
	var Bullet             = new AscFormat.CBullet();
	Bullet.bulletType      = new AscFormat.CBulletType();
	Bullet.bulletType.type = AscFormat.BULLET_TYPE_BULLET_NONE;
	this.Add_PresentationNumbering(Bullet);
};
Paragraph.prototype.Set_PresentationLevel = function(Level)
{
	if (this.Pr.Lvl != Level)
	{
		this.private_AddPrChange();
		History.Add(new CChangesParagraphPresentationPrLevel(this, this.Pr.Lvl, Level));
		this.Pr.Lvl                = Level;
		this.CompiledPr.NeedRecalc = true;
		this.Recalc_RunsCompiledPr();
		this.private_UpdateTrackRevisionOnChangeParaPr(true);
	}
};
//----------------------------------------------------------------------------------------------------------------------
/**
 * Формируем конечные свойства параграфа на основе стиля, возможной нумерации и прямых настроек.
 * Также учитываем настройки предыдущего и последующего параграфов.
 */
Paragraph.prototype.Get_CompiledPr = function()
{
	var Pr = this.Get_CompiledPr2();

	// При формировании конечных настроек параграфа, нужно учитывать предыдущий и последующий
	// параграфы. Например, для формирования интервала между параграфами.
	// max(Prev.After, Cur.Before) - реальное значение расстояния между параграфами.
	// Поэтому Prev.After = Prev.After (значение не меняем), а вот Cur.Before = max(Prev.After, Cur.Before) - Prev.After

	var StyleId = this.Style_Get();
	var NumPr   = this.GetNumPr();
	var FramePr = this.Get_FramePr();

	var PrevEl = this.Get_DocumentPrev();
	var NextEl = this.Get_DocumentNext();

	// Предыдущий и последующий параграфы - это не обязательно именно предыдущий и последующий. Если данный параграф
	// находится в рамке, тогда надо искать предыдущий и последующий только в текущей рамке, а если мы вне рамки, тогда
	// надо пропускать все параграфы находящиеся в рамке.
	if (undefined !== FramePr)
	{
		if (null === PrevEl || type_Paragraph !== PrevEl.GetType())
			PrevEl = null;
		else
		{
			var PrevFramePr = PrevEl.Get_FramePr();
			if (undefined === PrevFramePr || true !== FramePr.Compare(PrevFramePr))
				PrevEl = null;
		}

		if (null === NextEl || type_Paragraph !== NextEl.GetType())
			NextEl = null;
		else
		{
			var NextFramePr = NextEl.Get_FramePr();
			if (undefined === NextFramePr || true !== FramePr.Compare(NextFramePr))
				NextEl = null;
		}
	}
	else
	{
		while (null !== PrevEl && type_Paragraph === PrevEl.GetType() && undefined !== PrevEl.Get_FramePr())
			PrevEl = PrevEl.Get_DocumentPrev();

		while (null !== NextEl && type_Paragraph === NextEl.GetType() && undefined !== NextEl.Get_FramePr())
			NextEl = NextEl.Get_DocumentNext();
	}

	if (null != PrevEl && type_Paragraph === PrevEl.GetType())
	{
		var PrevStyle      = PrevEl.Style_Get();
		var Prev_Pr        = PrevEl.Get_CompiledPr2(false).ParaPr;
		var Prev_After     = Prev_Pr.Spacing.After;
		var Prev_AfterAuto = Prev_Pr.Spacing.AfterAutoSpacing;
		var Cur_Before     = Pr.ParaPr.Spacing.Before;
		var Cur_BeforeAuto = Pr.ParaPr.Spacing.BeforeAutoSpacing;
		var Prev_NumPr     = PrevEl.GetNumPr();

		if (PrevStyle === StyleId && true === Pr.ParaPr.ContextualSpacing)
		{
			Pr.ParaPr.Spacing.Before = 0;
		}
		else
		{
			if (true === Cur_BeforeAuto && PrevStyle === StyleId && undefined != Prev_NumPr && undefined != NumPr && Prev_NumPr.NumId === NumPr.NumId)
				Pr.ParaPr.Spacing.Before = 0;
			else
			{
				Cur_Before = this.Internal_CalculateAutoSpacing(Cur_Before, Cur_BeforeAuto, this);
				Prev_After = this.Internal_CalculateAutoSpacing(Prev_After, Prev_AfterAuto, this);

				if ((true === Prev_Pr.ContextualSpacing
					&& PrevStyle === StyleId)
					|| (true === Prev_AfterAuto
					&& PrevStyle === StyleId
					&& undefined != Prev_NumPr
					&& undefined != NumPr
					&& Prev_NumPr.NumId === NumPr.NumId))
					Prev_After = 0;

				Pr.ParaPr.Spacing.Before = Math.max(Prev_After, Cur_Before) - Prev_After;
			}
		}

		if (true === this.private_CompareBorderSettings(Prev_Pr, Pr.ParaPr) && undefined === PrevEl.Get_SectionPr() && true !== Pr.ParaPr.PageBreakBefore)
		{
			Pr.ParaPr.Brd.First   = false;
			Pr.ParaPr.Brd.Between = Prev_Pr.Brd.Between.Copy();
		}
		else
		{
			Pr.ParaPr.Brd.First = true;
		}
	}
	else if (null === PrevEl)
	{
		if (true === this.Parent.IsTableCellContent() && true === Pr.ParaPr.ContextualSpacing)
		{
			var Cell = this.Parent.IsTableCellContent(true);
			if (Cell)
			{
				var PrevEl = Cell.GetLastElementInPrevCell();
				if ((null !== PrevEl && type_Paragraph === PrevEl.GetType() && PrevEl.Style_Get() === StyleId) || (null === PrevEl && undefined === StyleId))
				{
					Pr.ParaPr.Spacing.Before = 0;
				}
			}
		}
		else if (true === Pr.ParaPr.Spacing.BeforeAutoSpacing || !(this.bFromDocument === true))
		{
			Pr.ParaPr.Spacing.Before = 0;
		}
	}
	else if (type_Table === PrevEl.GetType())
	{
		if (true === Pr.ParaPr.Spacing.BeforeAutoSpacing)
		{
			Pr.ParaPr.Spacing.Before = 14 * g_dKoef_pt_to_mm;
		}
	}

	if (null != NextEl)
	{
		if (type_Paragraph === NextEl.GetType())
		{
			var NextStyle       = NextEl.Style_Get();
			var Next_Pr         = NextEl.Get_CompiledPr2(false).ParaPr;
			var Next_Before     = Next_Pr.Spacing.Before;
			var Next_BeforeAuto = Next_Pr.Spacing.BeforeAutoSpacing;
			var Cur_After       = Pr.ParaPr.Spacing.After;
			var Cur_AfterAuto   = Pr.ParaPr.Spacing.AfterAutoSpacing;
			var Next_NumPr      = NextEl.GetNumPr();

			if (NextStyle === StyleId && true === Pr.ParaPr.ContextualSpacing)
			{
				Pr.ParaPr.Spacing.After = 0;
			}
			else
			{
				if (true === Cur_AfterAuto && NextStyle === StyleId && undefined != Next_NumPr && undefined != NumPr && Next_NumPr.NumId === NumPr.NumId)
					Pr.ParaPr.Spacing.After = 0;
				else
				{
					Pr.ParaPr.Spacing.After = this.Internal_CalculateAutoSpacing(Cur_After, Cur_AfterAuto, this);
				}
			}

			if (true === this.private_CompareBorderSettings(Next_Pr, Pr.ParaPr) && undefined === this.Get_SectionPr() && (undefined === NextEl.Get_SectionPr() || true !== NextEl.IsEmpty()) && true !== Next_Pr.PageBreakBefore)
				Pr.ParaPr.Brd.Last = false;
			else
				Pr.ParaPr.Brd.Last = true;
		}
		else if (type_Table === NextEl.GetType())
		{
			var TableFirstParagraph = NextEl.Get_FirstParagraph();
			if (null != TableFirstParagraph && undefined != TableFirstParagraph)
			{
				var NextStyle       = TableFirstParagraph.Style_Get();
				var Next_Before     = TableFirstParagraph.Get_CompiledPr2(false).ParaPr.Spacing.Before;
				var Next_BeforeAuto = TableFirstParagraph.Get_CompiledPr2(false).ParaPr.Spacing.BeforeAutoSpacing;
				var Cur_After       = Pr.ParaPr.Spacing.After;
				var Cur_AfterAuto   = Pr.ParaPr.Spacing.AfterAutoSpacing;
				if (NextStyle === StyleId && true === Pr.ParaPr.ContextualSpacing)
				{
					Cur_After   = this.Internal_CalculateAutoSpacing(Cur_After, Cur_AfterAuto, this);
					Next_Before = this.Internal_CalculateAutoSpacing(Next_Before, Next_BeforeAuto, this);

					Pr.ParaPr.Spacing.After = Math.max(Next_Before, Cur_After) - Cur_After;
				}
				else
				{
					Pr.ParaPr.Spacing.After = this.Internal_CalculateAutoSpacing(Pr.ParaPr.Spacing.After, Cur_AfterAuto, this);
				}
			}
		}
	}
	else
	{
		if (true === this.Parent.IsTableCellContent() && true === Pr.ParaPr.ContextualSpacing)
		{
			var Cell = this.Parent.IsTableCellContent(true);
			if (Cell)
			{
				var NextEl = Cell.GetFirstElementInNextCell();
				if ((null !== NextEl && type_Paragraph === NextEl.GetType() && NextEl.Style_Get() === StyleId) || (null === NextEl && StyleId === undefined))
				{
					Pr.ParaPr.Spacing.After = 0;
				}
			}
		}
		else if (true === this.Parent.IsTableCellContent() && true === Pr.ParaPr.Spacing.AfterAutoSpacing)
		{
			Pr.ParaPr.Spacing.After = 0;
		}
		else if (!(this.bFromDocument === true))
		{
			Pr.ParaPr.Spacing.After = 0;
		}
		else
		{
			Pr.ParaPr.Spacing.After = this.Internal_CalculateAutoSpacing(Pr.ParaPr.Spacing.After, Pr.ParaPr.Spacing.AfterAutoSpacing, this);
		}
	}

	return Pr;
};
Paragraph.prototype.Recalc_CompiledPr = function()
{
	this.CompiledPr.NeedRecalc = true;
};
/**
 * Сообщаем, что нужно пересчитать скомпилированные настройки параграфа
 */
Paragraph.prototype.RecalcCompiledPr = function()
{
	this.CompiledPr.NeedRecalc = true;
};
Paragraph.prototype.Recalc_RunsCompiledPr = function()
{
	var Count = this.Content.length;
	for (var Pos = 0; Pos < Count; Pos++)
	{
		var Element = this.Content[Pos];

		if (Element.Recalc_RunsCompiledPr)
			Element.Recalc_RunsCompiledPr();
	}
};
/**
 * Формируем конечные свойства параграфа на основе стиля, возможной нумерации и прямых настроек.
 * Без пересчета расстояния между параграфами.
 */
Paragraph.prototype.Get_CompiledPr2 = function(bCopy)
{
	this.Internal_CompileParaPr();

	if (false === bCopy)
		return this.CompiledPr.Pr;
	else
	{
		// Отдаем копию объекта, чтобы никто не поменял извне настройки скомпилированного стиля
		var Pr    = {};
		Pr.TextPr = this.CompiledPr.Pr.TextPr.Copy();
		Pr.ParaPr = this.CompiledPr.Pr.ParaPr.Copy();
		return Pr;
	}
};
Paragraph.prototype.Internal_CompileParaPr = function()
{
	if (true === this.CompiledPr.NeedRecalc)
	{
		if (undefined !== this.Parent && null !== this.Parent && true !== AscCommon.g_oIdCounter.m_bLoad && true !== AscCommon.g_oIdCounter.m_bRead)
		{
			this.CompiledPr.Pr = this.Internal_CompileParaPr2();
			if (!this.bFromDocument)
			{
				this.PresentationPr.Level  = AscFormat.isRealNumber(this.Pr.Lvl) ? this.Pr.Lvl : 0;
				this.PresentationPr.Bullet = this.CompiledPr.Pr.ParaPr.Get_PresentationBullet(this.Get_Theme(), this.Get_ColorMap());
				this.Numbering.Bullet      = this.PresentationPr.Bullet;
			}

			this.CompiledPr.NeedRecalc = false;
		}
		else
		{
			if (undefined === this.CompiledPr.Pr || null === this.CompiledPr.Pr)
			{
				this.CompiledPr.Pr =
					{
						ParaPr : g_oDocumentDefaultParaPr,
						TextPr : g_oDocumentDefaultTextPr
					};

				this.CompiledPr.Pr.ParaPr.StyleTabs  = new CParaTabs();
				this.CompiledPr.Pr.ParaPr.StyleNumPr = undefined;
			}

			this.CompiledPr.NeedRecalc = true;
		}
	}
};
/**
 * Формируем конечные свойства параграфа на основе стиля, возможной нумерации и прямых настроек.
 */
Paragraph.prototype.Internal_CompileParaPr2 = function()
{
	if (this.bFromDocument)
	{
		var Styles     = this.Parent.Get_Styles();
		var Numbering  = this.Parent.GetNumbering();
		var TableStyle = this.Parent.Get_TableStyleForPara();
		var ShapeStyle = this.Parent.Get_ShapeStyleForPara();
		var StyleId    = this.Style_Get();

		// Считываем свойства для текущего стиля
		var Pr = Styles.Get_Pr(StyleId, styletype_Paragraph, TableStyle, ShapeStyle);

		// Если в стиле была задана нумерация сохраним это в специальном поле
		if (undefined != Pr.ParaPr.NumPr)
			Pr.ParaPr.StyleNumPr = Pr.ParaPr.NumPr.Copy();

		var Lvl = -1;
		if (undefined != this.Pr.NumPr)
		{
			if (undefined != this.Pr.NumPr.NumId && 0 != this.Pr.NumPr.NumId)
			{
				Lvl = this.Pr.NumPr.Lvl;

				if (Lvl >= 0 && Lvl <= 8)
					Pr.ParaPr.Merge(Numbering.GetParaPr(this.Pr.NumPr.NumId, this.Pr.NumPr.Lvl));
				else
				{
					Lvl             = -1;
					Pr.ParaPr.NumPr = undefined;
				}
			}
			else if (0 === this.Pr.NumPr.NumId)
			{
				// Word значение 0 для NumId воспринимает как отсутствие нумерации
				Lvl             = -1;
				Pr.ParaPr.NumPr = undefined;

				Pr.ParaPr.Ind.Left      = 0;
				Pr.ParaPr.Ind.FirstLine = 0;
			}
		}
		else if (undefined != Pr.ParaPr.NumPr)
		{
			if (undefined != Pr.ParaPr.NumPr.NumId && 0 != Pr.ParaPr.NumPr.NumId)
			{
				var oNum = Numbering.GetNum(Pr.ParaPr.NumPr.NumId);

				var _StyleId            = StyleId;
				Lvl                     = oNum.GetLvlByStyle(_StyleId);
				var PassedStyleId       = {};
				PassedStyleId[_StyleId] = true;
				while (-1 === Lvl)
				{
					var Style = Styles.Get(_StyleId);
					if (!Style)
						break;

					_StyleId = Style.Get_BasedOn();
					if (!_StyleId || true === PassedStyleId[_StyleId])
						break;

					PassedStyleId[_StyleId] = true;
					Lvl                     = oNum.GetLvlByStyle(_StyleId);
				}

				if (-1 === Lvl)
					Pr.ParaPr.NumPr = undefined;
			}
		}

		Pr.ParaPr.StyleTabs = ( undefined != Pr.ParaPr.Tabs ? Pr.ParaPr.Tabs.Copy() : new CParaTabs() );

		// Копируем прямые настройки параграфа.
		Pr.ParaPr.Merge(this.Pr);

		if (-1 != Lvl && undefined != Pr.ParaPr.NumPr)
			Pr.ParaPr.NumPr.Lvl = Lvl;
		else
			Pr.ParaPr.NumPr = undefined;

		// Настройки рамки не наследуются
		if (undefined === this.Pr.FramePr)
			Pr.ParaPr.FramePr = undefined;
		else
			Pr.ParaPr.FramePr = this.Pr.FramePr.Copy();

		return Pr;
	}
	else
	{
		return this.Internal_CompiledParaPrPresentation();
	}
};
Paragraph.prototype.Internal_CompiledParaPrPresentation = function(Lvl, bNoMergeDefault)
{
	var _Lvl        = AscFormat.isRealNumber(Lvl) ? Lvl : (AscFormat.isRealNumber(this.Pr.Lvl) ? this.Pr.Lvl : 0);
	var styleObject = this.Parent.Get_Styles(_Lvl);
	var Styles      = styleObject.styles;

	// Считываем свойства для текущего стиля
	var Pr = Styles.Get_Pr(styleObject.lastId, styletype_Paragraph, null);

	var TableStyle = this.Parent.Get_TableStyleForPara();
	if (TableStyle && TableStyle.TextPr)
	{
		//var TextPr2 = new CTextPr();
		//TextPr2.Unifill = TableStyle.TextPr.Unifill;
		//TextPr2.RFonts = TableStyle.TextPr.RFonts;
		//TextPr2.Bold = TableStyle.TextPr.Bold;
		//TextPr2.Itali = TableStyle.TextPr.RFonts;
		Pr.TextPr.Merge(TableStyle.TextPr);
	}

	Pr.ParaPr.StyleTabs = ( undefined != Pr.ParaPr.Tabs ? Pr.ParaPr.Tabs.Copy() : new CParaTabs() );

	if(!(bNoMergeDefault === true)){
		// Копируем прямые настройки параграфа.
		Pr.ParaPr.Merge(this.Pr);
		if (this.Pr.DefaultRunPr)
			Pr.TextPr.Merge(this.Pr.DefaultRunPr);
	}
	Pr.TextPr.Color.Auto = false;

	return Pr;
};
/**
 * Сообщаем параграфу, что ему надо будет пересчитать скомпилированный стиль
 * (Такое может случится, если у данного параграфа есть нумерация или задан стиль,
 * которые меняются каким-то внешним образом)
 */
Paragraph.prototype.Recalc_CompileParaPr = function()
{
	this.CompiledPr.NeedRecalc = true;
};
Paragraph.prototype.Internal_CalculateAutoSpacing = function(Value, UseAuto, Para)
{
	var Result = Value;
	if (true === UseAuto)
		Result = 14 * g_dKoef_pt_to_mm;

	return Result;
};
Paragraph.prototype.GetDirectTextPr = function()
{
	var TextPr;
	if (true === this.ApplyToAll)
	{
		this.SelectAll(1);

		var Count    = this.Content.length;
		var StartPos = 0;
		while (true === this.Content[StartPos].IsSelectionEmpty() && StartPos < Count)
			StartPos++;

		TextPr = this.Content[StartPos].GetDirectTextPr();

		this.RemoveSelection();
	}
	else
	{
		if (true === this.Selection.Use)
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;

			if (StartPos > EndPos)
			{
				StartPos = this.Selection.EndPos;
				EndPos   = this.Selection.StartPos;
			}

			while (true === this.Content[StartPos].IsSelectionEmpty() && StartPos < EndPos)
				StartPos++;

			TextPr = this.Content[StartPos].GetDirectTextPr();
		}
		else
		{
			TextPr = this.Content[this.CurPos.ContentPos].GetDirectTextPr();
		}
	}

	if (TextPr)
		TextPr = TextPr.Copy();
	else
		TextPr = new CTextPr();

	return TextPr;
};
/**
 * Получаем прямые настройки параграфа
 * @param [isCopy=true] копировать ли настройки
 * @returns {CParaPr}
 */
Paragraph.prototype.GetDirectParaPr = function(isCopy)
{
	if (false === isCopy)
		return this.Pr;

	return this.Pr.Copy();
};
Paragraph.prototype.PasteFormatting = function(TextPr, oParaPr, ApplyPara)
{
	// Применяем текстовые настройки всегда
	if (TextPr)
	{
		var oParaTextPr = new ParaTextPr();
		oParaTextPr.Value.Set_FromObject(TextPr, true);
		this.Add(oParaTextPr);
	}

	// Применяем настройки параграфа
	if (oParaPr)
	{
		this.Set_ContextualSpacing(oParaPr.ContextualSpacing);

		if (oParaPr.Ind)
			this.Set_Ind(oParaPr.Ind, true);
		else
			this.Set_Ind(new CParaInd(), true);

		this.Set_Align(oParaPr.Jc);
		this.Set_KeepLines(oParaPr.KeepLines);
		this.Set_KeepNext(oParaPr.KeepNext);
		this.Set_PageBreakBefore(oParaPr.PageBreakBefore);

		if (oParaPr.Spacing)
			this.Set_Spacing(oParaPr.Spacing, true);
		else
			this.Set_Spacing(new CParaSpacing(), true);

		if (oParaPr.Shd)
			this.Set_Shd(oParaPr.Shd, true);
		else
			this.Set_Shd(undefined);

		this.Set_WidowControl(oParaPr.WidowControl);

		if (oParaPr.Tabs)
			this.Set_Tabs(oParaPr.Tabs);
		else
			this.Set_Tabs(new CParaTabs());


		if (this.bFromDocument)
		{
			if (oParaPr.NumPr)
				this.SetNumPr(oParaPr.NumPr.NumId, oParaPr.NumPr.Lvl);
			else
				this.RemoveNumPr();

			if (oParaPr.PStyle)
				this.Style_Add(oParaPr.PStyle, true);
			else
				this.Style_Remove();

			if (oParaPr.Brd)
				this.Set_Borders(oParaPr.Brd);
		}
		else
		{
			this.Set_Bullet(oParaPr.Bullet);
		}
	}
};
Paragraph.prototype.Style_Get = function()
{
	if (undefined != this.Pr.PStyle)
		return this.Pr.PStyle;

	return undefined;
};
Paragraph.prototype.Style_Add = function(Id, bDoNotDeleteProps)
{
	this.RecalcInfo.Set_Type_0(pararecalc_0_All);

	if (undefined !== this.Pr.PStyle)
		this.Style_Remove();

	if (null === Id)
		return;

	var oDefParaId = this.LogicDocument ? this.LogicDocument.Get_Styles().Get_Default_Paragraph() : null;

	// Надо пересчитать конечный стиль самого параграфа и всех текстовых блоков
	this.CompiledPr.NeedRecalc = true;
	this.Recalc_RunsCompiledPr();

	// Если стиль является стилем по умолчанию для параграфа, тогда не надо его записывать.
	if (Id != oDefParaId)
	{
		this.private_AddPrChange();
		History.Add(new CChangesParagraphPStyle(this, this.Pr.PStyle, Id));
		this.Pr.PStyle = Id;
		this.private_UpdateTrackRevisionOnChangeParaPr(true);
		this.UpdateDocumentOutline();
	}

	if (true === bDoNotDeleteProps)
		return;

	// TODO: По мере добавления элементов в стили параграфа и текста добавить их обработку здесь.

	// При выставлении стиля свойства буквицы(рамки) всегда сбрасываются
	if (undefined !== this.Get_FramePr())
	{
		this.Set_FramePr(undefined, true);
		this.Clear_TextFormatting();
	}

	// Не удаляем форматирование, при добавлении списка к данному параграфу
	var DefNumId = this.LogicDocument ? this.LogicDocument.Get_Styles().Get_Default_ParaList() : null;
	if (Id !== DefNumId)
	{
		this.SetNumPr(undefined);
		this.Set_ContextualSpacing(undefined);
		this.Set_Ind(new CParaInd(), true);
		this.Set_Align(undefined);
		this.Set_KeepLines(undefined);
		this.Set_KeepNext(undefined);
		this.Set_PageBreakBefore(undefined);
		this.Set_Spacing(new CParaSpacing(), true);
		this.Set_Shd(undefined, true);
		this.Set_WidowControl(undefined);
		this.Set_Tabs(new CParaTabs());
		this.Set_Border(undefined, AscDFH.historyitem_Paragraph_Borders_Between);
		this.Set_Border(undefined, AscDFH.historyitem_Paragraph_Borders_Bottom);
		this.Set_Border(undefined, AscDFH.historyitem_Paragraph_Borders_Left);
		this.Set_Border(undefined, AscDFH.historyitem_Paragraph_Borders_Right);
		this.Set_Border(undefined, AscDFH.historyitem_Paragraph_Borders_Top);
	}
};
/**
 * Добавление стиля в параграф при открытии и копировании
 */
Paragraph.prototype.Style_Add_Open = function(Id)
{
	this.Pr.PStyle = Id;

	// Надо пересчитать конечный стиль
	this.CompiledPr.NeedRecalc = true;
};
Paragraph.prototype.Style_Remove = function()
{
	if (undefined != this.Pr.PStyle)
	{
		this.private_AddPrChange();
		History.Add(new CChangesParagraphPStyle(this, this.Pr.PStyle, undefined));
		this.Pr.PStyle = undefined;
		this.UpdateDocumentOutline();
	}

	// Надо пересчитать конечный стиль
	this.CompiledPr.NeedRecalc = true;
	this.Recalc_RunsCompiledPr();
	this.private_UpdateTrackRevisionOnChangeParaPr(true);
};
/**
 * Проверяем находится ли курсор в конце параграфа
 */
Paragraph.prototype.IsCursorAtEnd = function(_ContentPos)
{
	// Просто попробуем переместится вправо от текущего положения, если мы не можем, значит
	// мы стоим в конце параграфа.

	var ContentPos = ( undefined === _ContentPos ? this.Get_ParaContentPos(false, false) : _ContentPos );
	var SearchPos  = new CParagraphSearchPos();

	this.Get_RightPos(SearchPos, ContentPos, false);

	if (true === SearchPos.Found)
		return false;
	else
		return true;
};
/**
 * Проверяем находится ли курсор в начале параграфа
 */
Paragraph.prototype.IsCursorAtBegin = function(_ContentPos, bCheckAnchors)
{
	// Просто попробуем переместится вправо от текущего положения, если мы не можем, значит
	// мы стоим в конце параграфа.

	var ContentPos = ( undefined === _ContentPos ? this.Get_ParaContentPos(false, false) : _ContentPos );
	var SearchPos  = new CParagraphSearchPos();
	if (true === bCheckAnchors)
		SearchPos.SetCheckAnchors();

	this.Get_LeftPos(SearchPos, ContentPos);

	if (true === SearchPos.Found)
		return false;
	else
		return true;
};
/**
 * Проверим, начинается ли выделение с начала параграфа
 */
Paragraph.prototype.Selection_IsFromStart = function(bCheckAnchors)
{
	if (true === this.IsSelectionUse())
	{
		var StartPos = this.Get_ParaContentPos(true, true);
		var EndPos   = this.Get_ParaContentPos(true, false);

		if (StartPos.Compare(EndPos) > 0)
			StartPos = EndPos;

		if (true != this.IsCursorAtBegin(StartPos, bCheckAnchors))
			return false;

		return true;
	}

	return false;
};
/**
 * Очищение форматирования параграфа
 */
Paragraph.prototype.Clear_Formatting = function()
{
	if (this.bFromDocument && this.Parent)
	{
		var oStyles    = this.Parent.Get_Styles();
		var oHdrFtr    = this.Parent.IsHdrFtr(true);
		var isFootnote = this.Parent.IsFootnote();
		if (null !== oHdrFtr)
		{
			var sHdrFtrStyleId = null;
			if (AscCommon.hdrftr_Header === oHdrFtr.Type)
				sHdrFtrStyleId = oStyles.Get_Default_Header();
			else
				sHdrFtrStyleId = oStyles.Get_Default_Footer();

			if (null !== sHdrFtrStyleId)
				this.Style_Add(sHdrFtrStyleId, true);
			else
				this.Style_Remove();
		}
		else if (isFootnote)
		{
			var sFootnoteStyleId = oStyles.GetDefaultFootnoteText();
			if (sFootnoteStyleId)
				this.Style_Add(sFootnoteStyleId, true);
			else
				this.Style_Remove();
		}
		else
		{
			this.Style_Remove();
		}

		this.RemoveNumPr();
	}

	this.Set_ContextualSpacing(undefined);
	this.Set_Ind(new CParaInd(), true);
	this.Set_Align(undefined, false);
	this.Set_KeepLines(undefined);
	this.Set_KeepNext(undefined);
	this.Set_PageBreakBefore(undefined);
	this.Set_Spacing(new CParaSpacing(), true);
	this.Set_Shd(new CDocumentShd(), true);
	this.Set_WidowControl(undefined);
	this.Set_Tabs(new CParaTabs());
	this.Set_Border(undefined, AscDFH.historyitem_Paragraph_Borders_Between);
	this.Set_Border(undefined, AscDFH.historyitem_Paragraph_Borders_Bottom);
	this.Set_Border(undefined, AscDFH.historyitem_Paragraph_Borders_Left);
	this.Set_Border(undefined, AscDFH.historyitem_Paragraph_Borders_Right);
	this.Set_Border(undefined, AscDFH.historyitem_Paragraph_Borders_Top);
	if (!(this.bFromDocument === true))
	{
		this.Set_Bullet(undefined);
	}
	// Надо пересчитать конечный стиль
	this.CompiledPr.NeedRecalc = true;
};
Paragraph.prototype.Clear_TextFormatting = function()
{
	var Styles, DefHyper;
	if (this.bFromDocument)
	{
		Styles   = this.Parent.Get_Styles();
		DefHyper = Styles.GetDefaultHyperlink();
	}

	for (var Index = 0; Index < this.Content.length; Index++)
	{
		var Item = this.Content[Index];
		Item.Clear_TextFormatting(DefHyper);
	}

	this.TextPr.Clear_Style();
};
Paragraph.prototype.Set_Ind = function(Ind, bDeleteUndefined)
{
	if (undefined === this.Pr.Ind)
		this.Pr.Ind = new CParaInd();

	if (( undefined != Ind.FirstLine || true === bDeleteUndefined ) && this.Pr.Ind.FirstLine !== Ind.FirstLine)
	{
		this.private_AddPrChange();
		History.Add(new CChangesParagraphIndFirst(this, this.Pr.Ind.FirstLine, Ind.FirstLine));
		this.Pr.Ind.FirstLine = Ind.FirstLine;
	}

	if (( undefined != Ind.Left || true === bDeleteUndefined ) && this.Pr.Ind.Left !== Ind.Left)
	{
		this.private_AddPrChange();
		History.Add(new CChangesParagraphIndLeft(this, this.Pr.Ind.Left, Ind.Left));
		this.Pr.Ind.Left = Ind.Left;
	}

	if (( undefined != Ind.Right || true === bDeleteUndefined ) && this.Pr.Ind.Right !== Ind.Right)
	{
		this.private_AddPrChange();
		History.Add(new CChangesParagraphIndRight(this, this.Pr.Ind.Right, Ind.Right));
		this.Pr.Ind.Right = Ind.Right;
	}

	// Надо пересчитать конечный стиль
	this.CompiledPr.NeedRecalc = true;
	this.private_UpdateTrackRevisionOnChangeParaPr(true);
};
Paragraph.prototype.Set_Spacing = function(Spacing, bDeleteUndefined)
{
	if (undefined === this.Pr.Spacing)
		this.Pr.Spacing = new CParaSpacing();

	if (( undefined != Spacing.Line || true === bDeleteUndefined ) && this.Pr.Spacing.Line !== Spacing.Line)
	{
		var LineValue = Spacing.Line;

		if (undefined !== Spacing.Line)
		{
			// TODO: Здесь делается корректировка значения, потому что при работе с буквицей могут возникать значения,
			//       которые неправильно записываются в файл, т.к. в docx это значение имеет тип Twips. Надо бы такую
			//       корректировку вынести в отдельную функцию и добавить ко всем параметрам.
			if ((undefined !== Spacing.LineRule && Spacing.LineRule !== linerule_Auto)
				|| (undefined === Spacing.LineRule && (linerule_Exact === this.Pr.Spacing.LineRule || linerule_AtLeast === this.Pr.Spacing.LineRule)))
				LineValue = AscCommon.CorrectMMToTwips(((Spacing.Line / 25.4 * 72 * 20) | 0) * 25.4 / 20 / 72);
		}

		this.private_AddPrChange();
		History.Add(new CChangesParagraphSpacingLine(this, this.Pr.Spacing.Line, LineValue));
		this.Pr.Spacing.Line = LineValue;
	}

	if (( undefined != Spacing.LineRule || true === bDeleteUndefined ) && this.Pr.Spacing.LineRule !== Spacing.LineRule)
	{
		this.private_AddPrChange();
		History.Add(new CChangesParagraphSpacingLineRule(this, this.Pr.Spacing.LineRule, Spacing.LineRule));
		this.Pr.Spacing.LineRule = Spacing.LineRule;
	}

	if (( undefined != Spacing.Before || true === bDeleteUndefined ) && this.Pr.Spacing.Before !== Spacing.Before)
	{
		this.private_AddPrChange();
		History.Add(new CChangesParagraphSpacingBefore(this, this.Pr.Spacing.Before, Spacing.Before));
		this.Pr.Spacing.Before = Spacing.Before;
	}

	if (( undefined != Spacing.After || true === bDeleteUndefined ) && this.Pr.Spacing.After !== Spacing.After)
	{
		this.private_AddPrChange();
		History.Add(new CChangesParagraphSpacingAfter(this, this.Pr.Spacing.After, Spacing.After));
		this.Pr.Spacing.After = Spacing.After;
	}

	if (( undefined != Spacing.AfterAutoSpacing || true === bDeleteUndefined ) && this.Pr.Spacing.AfterAutoSpacing !== Spacing.AfterAutoSpacing)
	{
		this.private_AddPrChange();
		History.Add(new CChangesParagraphSpacingAfterAutoSpacing(this, this.Pr.Spacing.AfterAutoSpacing, Spacing.AfterAutoSpacing));
		this.Pr.Spacing.AfterAutoSpacing = Spacing.AfterAutoSpacing;
	}

	if (( undefined != Spacing.BeforeAutoSpacing || true === bDeleteUndefined ) && this.Pr.Spacing.BeforeAutoSpacing !== Spacing.BeforeAutoSpacing)
	{
		this.private_AddPrChange();
		History.Add(new CChangesParagraphSpacingBeforeAutoSpacing(this, this.Pr.Spacing.BeforeAutoSpacing, Spacing.BeforeAutoSpacing));
		this.Pr.Spacing.BeforeAutoSpacing = Spacing.BeforeAutoSpacing;
	}

	// Надо пересчитать конечный стиль
	this.CompiledPr.NeedRecalc = true;
	this.private_UpdateTrackRevisionOnChangeParaPr(true);
};
Paragraph.prototype.Set_Align = function(Align)
{
	if (this.Pr.Jc != Align)
	{
		this.private_AddPrChange();

		History.Add(new CChangesParagraphAlign(this, this.Pr.Jc, Align));
		this.Pr.Jc = Align;

		// Надо пересчитать конечный стиль
		this.CompiledPr.NeedRecalc = true;
		this.private_UpdateTrackRevisionOnChangeParaPr(true);

		for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
		{
			var oElement = this.Content[nIndex];
			if (para_Math === oElement.Type && true !== oElement.Is_Inline())
				oElement.Set_Align(Align);
		}
	}
};
Paragraph.prototype.Set_DefaultTabSize = function(TabSize)
{
	if (this.Pr.DefaultTab != TabSize)
	{
		this.private_AddPrChange();

		History.Add(new CChangesParagraphDefaultTabSize(this, this.Pr.DefaultTab, TabSize));
		this.Pr.DefaultTab = TabSize;

		// Надо пересчитать конечный стиль
		this.CompiledPr.NeedRecalc = true;
		this.private_UpdateTrackRevisionOnChangeParaPr(true);

	}
};
Paragraph.prototype.Set_Shd = function(_Shd, bDeleteUndefined)
{
	if (undefined === _Shd)
	{
		if (undefined != this.Pr.Shd)
		{
			this.private_AddPrChange();
			History.Add(new CChangesParagraphShd(this, this.Pr.Shd, undefined));
			this.Pr.Shd = undefined;
		}
	}
	else
	{
		var Shd = new CDocumentShd();
		Shd.Set_FromObject(_Shd);

		if (undefined === this.Pr.Shd)
		{
			this.Pr.Shd = new CDocumentShd();
			History.Add(new CChangesParagraphShd(this, undefined, this.Pr.Shd));
		}

		if (( undefined != Shd.Value || true === bDeleteUndefined ) && this.Pr.Shd.Value !== Shd.Value)
		{
			this.private_AddPrChange();
			History.Add(new CChangesParagraphShdValue(this, this.Pr.Shd.Value, Shd.Value));
			this.Pr.Shd.Value = Shd.Value;
		}

		if (undefined != Shd.Color || true === bDeleteUndefined)
		{
			this.private_AddPrChange();
			History.Add(new CChangesParagraphShdColor(this, this.Pr.Shd.Color, Shd.Color));
			this.Pr.Shd.Color = Shd.Color;
		}

		if (undefined != Shd.Unifill || true === bDeleteUndefined)
		{
			this.private_AddPrChange();
			History.Add(new CChangesParagraphShdUnifill(this, this.Pr.Shd.Unifill, Shd.Unifill));
			this.Pr.Shd.Unifill = Shd.Unifill;
		}
	}

	// Надо пересчитать конечный стиль
	this.CompiledPr.NeedRecalc = true;
	this.private_UpdateTrackRevisionOnChangeParaPr(true);
};
Paragraph.prototype.Set_Tabs = function(Tabs)
{
	var _Tabs = new CParaTabs();

	var StyleTabs = this.Get_CompiledPr2(false).ParaPr.StyleTabs;

	// 1. Ищем табы, которые уже есть в стиле (такие добавлять не надо)
	for (var Index = 0; Index < Tabs.Tabs.length; Index++)
	{
		var Value = StyleTabs.Get_Value(Tabs.Tabs[Index].Pos);
		if (-1 === Value)
			_Tabs.Add(Tabs.Tabs[Index]);
	}

	// 2. Ищем табы в стиле, которые нужно отменить
	for (var Index = 0; Index < StyleTabs.Tabs.length; Index++)
	{
		var Value = _Tabs.Get_Value(StyleTabs.Tabs[Index].Pos);
		if (tab_Clear != StyleTabs.Tabs[Index] && -1 === Value)
			_Tabs.Add(new CParaTab(tab_Clear, StyleTabs.Tabs[Index].Pos));
	}

	this.private_AddPrChange();
	History.Add(new CChangesParagraphTabs(this, this.Pr.Tabs, _Tabs));
	this.Pr.Tabs = _Tabs;

	// Надо пересчитать конечный стиль
	this.CompiledPr.NeedRecalc = true;
	this.private_UpdateTrackRevisionOnChangeParaPr(true);
};
Paragraph.prototype.Set_ContextualSpacing = function(Value)
{
	if (Value != this.Pr.ContextualSpacing)
	{
		this.private_AddPrChange();
		History.Add(new CChangesParagraphContextualSpacing(this, this.Pr.ContextualSpacing, Value));
		this.Pr.ContextualSpacing = Value;

		// Надо пересчитать конечный стиль
		this.CompiledPr.NeedRecalc = true;
		this.private_UpdateTrackRevisionOnChangeParaPr(true);
	}
};
Paragraph.prototype.Set_PageBreakBefore = function(Value)
{
	if (Value != this.Pr.PageBreakBefore)
	{
		this.private_AddPrChange();
		History.Add(new CChangesParagraphPageBreakBefore(this, this.Pr.PageBreakBefore, Value));
		this.Pr.PageBreakBefore = Value;

		// Надо пересчитать конечный стиль
		this.CompiledPr.NeedRecalc = true;
		this.private_UpdateTrackRevisionOnChangeParaPr(true);
	}
};
Paragraph.prototype.Set_KeepLines = function(Value)
{
	if (Value != this.Pr.KeepLines)
	{
		this.private_AddPrChange();
		History.Add(new CChangesParagraphKeepLines(this, this.Pr.KeepLines, Value));
		this.Pr.KeepLines = Value;

		// Надо пересчитать конечный стиль
		this.CompiledPr.NeedRecalc = true;
		this.private_UpdateTrackRevisionOnChangeParaPr(true);
	}
};
Paragraph.prototype.Set_KeepNext = function(Value)
{
	if (Value != this.Pr.KeepNext)
	{
		this.private_AddPrChange();
		History.Add(new CChangesParagraphKeepNext(this, this.Pr.KeepNext, Value));
		this.Pr.KeepNext = Value;

		// Надо пересчитать конечный стиль
		this.CompiledPr.NeedRecalc = true;
		this.private_UpdateTrackRevisionOnChangeParaPr(true);
	}
};
Paragraph.prototype.IsKeepNext = function()
{
	return this.Get_CompiledPr2(false).ParaPr.KeepNext;
};
Paragraph.prototype.Set_WidowControl = function(Value)
{
	if (Value != this.Pr.WidowControl)
	{
		this.private_AddPrChange();
		History.Add(new CChangesParagraphWidowControl(this, this.Pr.WidowControl, Value));
		this.Pr.WidowControl = Value;

		// Надо пересчитать конечный стиль
		this.CompiledPr.NeedRecalc = true;
		this.private_UpdateTrackRevisionOnChangeParaPr(true);
	}
};
Paragraph.prototype.Set_Borders = function(Borders)
{
	if (undefined === Borders)
		return;

	var OldBorders = this.Get_CompiledPr2(false).ParaPr.Brd;

	if (undefined != Borders.Between)
	{
		var NewBorder = undefined;
		if (undefined != Borders.Between.Value /*&& border_Single === Borders.Between.Value*/)
		{
			NewBorder         = new CDocumentBorder();
			NewBorder.Color   = ( undefined != Borders.Between.Color ? new CDocumentColor(Borders.Between.Color.r, Borders.Between.Color.g, Borders.Between.Color.b) : new CDocumentColor(OldBorders.Between.Color.r, OldBorders.Between.Color.g, OldBorders.Between.Color.b) );
			NewBorder.Space   = ( undefined != Borders.Between.Space ? Borders.Between.Space : OldBorders.Between.Space );
			NewBorder.Size    = ( undefined != Borders.Between.Size ? Borders.Between.Size : OldBorders.Between.Size  );
			NewBorder.Value   = ( undefined != Borders.Between.Value ? Borders.Between.Value : OldBorders.Between.Value );
			NewBorder.Unifill = ( undefined != Borders.Between.Unifill ? Borders.Between.Unifill.createDuplicate() : OldBorders.Between.Unifill );
		}

		this.private_AddPrChange();
		History.Add(new CChangesParagraphBordersBetween(this, this.Pr.Brd.Between, NewBorder));
		this.Pr.Brd.Between = NewBorder;
	}

	if (undefined != Borders.Top)
	{
		var NewBorder = undefined;
		if (undefined != Borders.Top.Value /*&& border_Single === Borders.Top.Value*/)
		{
			NewBorder         = new CDocumentBorder();
			NewBorder.Color   = ( undefined != Borders.Top.Color ? new CDocumentColor(Borders.Top.Color.r, Borders.Top.Color.g, Borders.Top.Color.b) : new CDocumentColor(OldBorders.Top.Color.r, OldBorders.Top.Color.g, OldBorders.Top.Color.b) );
			NewBorder.Space   = ( undefined != Borders.Top.Space ? Borders.Top.Space : OldBorders.Top.Space );
			NewBorder.Size    = ( undefined != Borders.Top.Size ? Borders.Top.Size : OldBorders.Top.Size  );
			NewBorder.Value   = ( undefined != Borders.Top.Value ? Borders.Top.Value : OldBorders.Top.Value );
			NewBorder.Unifill = ( undefined != Borders.Top.Unifill ? Borders.Top.Unifill.createDuplicate() : OldBorders.Top.Unifill );

		}

		this.private_AddPrChange();
		History.Add(new CChangesParagraphBordersTop(this, this.Pr.Brd.Top, NewBorder));
		this.Pr.Brd.Top = NewBorder;
	}

	if (undefined != Borders.Right)
	{
		var NewBorder = undefined;
		if (undefined != Borders.Right.Value /*&& border_Single === Borders.Right.Value*/)
		{
			NewBorder         = new CDocumentBorder();
			NewBorder.Color   = ( undefined != Borders.Right.Color ? new CDocumentColor(Borders.Right.Color.r, Borders.Right.Color.g, Borders.Right.Color.b) : new CDocumentColor(OldBorders.Right.Color.r, OldBorders.Right.Color.g, OldBorders.Right.Color.b) );
			NewBorder.Space   = ( undefined != Borders.Right.Space ? Borders.Right.Space : OldBorders.Right.Space );
			NewBorder.Size    = ( undefined != Borders.Right.Size ? Borders.Right.Size : OldBorders.Right.Size  );
			NewBorder.Value   = ( undefined != Borders.Right.Value ? Borders.Right.Value : OldBorders.Right.Value );
			NewBorder.Unifill = ( undefined != Borders.Right.Unifill ? Borders.Right.Unifill.createDuplicate() : OldBorders.Right.Unifill );

		}

		this.private_AddPrChange();
		History.Add(new CChangesParagraphBordersRight(this, this.Pr.Brd.Right, NewBorder));
		this.Pr.Brd.Right = NewBorder;
	}

	if (undefined != Borders.Bottom)
	{
		var NewBorder = undefined;
		if (undefined != Borders.Bottom.Value /*&& border_Single === Borders.Bottom.Value*/)
		{
			NewBorder         = new CDocumentBorder();
			NewBorder.Color   = ( undefined != Borders.Bottom.Color ? new CDocumentColor(Borders.Bottom.Color.r, Borders.Bottom.Color.g, Borders.Bottom.Color.b) : new CDocumentColor(OldBorders.Bottom.Color.r, OldBorders.Bottom.Color.g, OldBorders.Bottom.Color.b) );
			NewBorder.Space   = ( undefined != Borders.Bottom.Space ? Borders.Bottom.Space : OldBorders.Bottom.Space );
			NewBorder.Size    = ( undefined != Borders.Bottom.Size ? Borders.Bottom.Size : OldBorders.Bottom.Size  );
			NewBorder.Value   = ( undefined != Borders.Bottom.Value ? Borders.Bottom.Value : OldBorders.Bottom.Value );
			NewBorder.Unifill = ( undefined != Borders.Bottom.Unifill ? Borders.Bottom.Unifill.createDuplicate() : OldBorders.Bottom.Unifill );
		}

		this.private_AddPrChange();
		History.Add(new CChangesParagraphBordersBottom(this, this.Pr.Brd.Bottom, NewBorder));
		this.Pr.Brd.Bottom = NewBorder;
	}

	if (undefined != Borders.Left)
	{
		var NewBorder = undefined;
		if (undefined != Borders.Left.Value /*&& border_Single === Borders.Left.Value*/)
		{
			NewBorder         = new CDocumentBorder();
			NewBorder.Color   = ( undefined != Borders.Left.Color ? new CDocumentColor(Borders.Left.Color.r, Borders.Left.Color.g, Borders.Left.Color.b) : new CDocumentColor(OldBorders.Left.Color.r, OldBorders.Left.Color.g, OldBorders.Left.Color.b) );
			NewBorder.Space   = ( undefined != Borders.Left.Space ? Borders.Left.Space : OldBorders.Left.Space );
			NewBorder.Size    = ( undefined != Borders.Left.Size ? Borders.Left.Size : OldBorders.Left.Size  );
			NewBorder.Value   = ( undefined != Borders.Left.Value ? Borders.Left.Value : OldBorders.Left.Value );
			NewBorder.Unifill = ( undefined != Borders.Left.Unifill ? Borders.Left.Unifill.createDuplicate() : OldBorders.Left.Unifill );

		}

		this.private_AddPrChange();
		History.Add(new CChangesParagraphBordersLeft(this, this.Pr.Brd.Left, NewBorder));
		this.Pr.Brd.Left = NewBorder;
	}

	// Надо пересчитать конечный стиль
	this.CompiledPr.NeedRecalc = true;
	this.private_UpdateTrackRevisionOnChangeParaPr(true);
};
Paragraph.prototype.Set_Border = function(Border, HistoryType)
{
	switch (HistoryType)
	{
		case AscDFH.historyitem_Paragraph_Borders_Between:
			History.Add(new CChangesParagraphBordersBetween(this, this.Pr.Brd.Between, Border));
			this.Pr.Brd.Between = Border;
			break;
		case AscDFH.historyitem_Paragraph_Borders_Bottom:
			History.Add(new CChangesParagraphBordersBottom(this, this.Pr.Brd.Bottom, Border));
			this.Pr.Brd.Bottom = Border;
			break;
		case AscDFH.historyitem_Paragraph_Borders_Left:
			History.Add(new CChangesParagraphBordersLeft(this, this.Pr.Brd.Left, Border));
			this.Pr.Brd.Left = Border;
			break;
		case AscDFH.historyitem_Paragraph_Borders_Right:
			History.Add(new CChangesParagraphBordersRight(this, this.Pr.Brd.Right, Border));
			this.Pr.Brd.Right = Border;
			break;
		case AscDFH.historyitem_Paragraph_Borders_Top:
			History.Add(new CChangesParagraphBordersTop(this, this.Pr.Brd.Top, Border));
			this.Pr.Brd.Top = Border;
			break;
	}

	this.private_AddPrChange();

	// Надо пересчитать конечный стиль
	this.CompiledPr.NeedRecalc = true;
	this.private_UpdateTrackRevisionOnChangeParaPr(true);
};
Paragraph.prototype.Set_Bullet = function(Bullet)
{
	this.private_AddPrChange();
	History.Add(new CChangesParagraphPresentationPrBullet(this, this.Pr.Bullet, Bullet));
	this.Pr.Bullet             = Bullet;
	this.CompiledPr.NeedRecalc = true;
	this.private_UpdateTrackRevisionOnChangeParaPr(true);
};
Paragraph.prototype.SetOutlineLvl = function(nLvl)
{
	this.private_AddPrChange();
	History.Add(new CChangesParagraphOutlineLvl(this, this.Pr.OutlineLvl, nLvl));
	this.Pr.OutlineLvl = nLvl;
	this.CompiledPr.NeedRecalc = true;
	this.private_UpdateTrackRevisionOnChangeParaPr(true);
};
Paragraph.prototype.GetOutlineLvl = function()
{
	// TODO: Заглушка со стилями заголовков тут временная
	var ParaPr = this.Get_CompiledPr2(false).ParaPr;
	var oStyles = this.LogicDocument.Get_Styles();
	for (var nIndex = 0; nIndex < 9; ++nIndex)
	{
		if (ParaPr.PStyle === oStyles.Get_Default_Heading(nIndex))
			return nIndex;
	}

	return ParaPr.OutlineLvl;
};
/**
 * Проверяем начинается ли текущий параграф с новой страницы.
 */
Paragraph.prototype.IsStartFromNewPage = function()
{
	// TODO: пока здесь стоит простая проверка. В будущем надо будет данную проверку улучшить.
	//       Например, сейчас не учитывается случай, когда в начале параграфа стоит PageBreak.

	if ((this.Pages.length > 1 && this.Pages[0].FirstLine === this.Pages[1].FirstLine) || (1 === this.Pages.length && -1 === this.Pages[0].EndLine) || (null === this.Get_DocumentPrev()))
		return true;

	return false;
};
/**
 * Возвращаем ран в котором лежит данный объект
 */
Paragraph.prototype.Get_DrawingObjectRun = function(Id)
{
	var Run        = null;
	var ContentLen = this.Content.length;
	for (var Index = 0; Index < ContentLen; Index++)
	{
		var Element = this.Content[Index];

		Run = Element.Get_DrawingObjectRun(Id);

		if (null !== Run)
			return Run;
	}

	return Run;
};
Paragraph.prototype.Get_DrawingObjectContentPos = function(Id)
{
	var ContentPos = new CParagraphContentPos();

	var ContentLen = this.Content.length;
	for (var Index = 0; Index < ContentLen; Index++)
	{
		var Element = this.Content[Index];

		if (true === Element.Get_DrawingObjectContentPos(Id, ContentPos, 1))
		{
			ContentPos.Update2(Index, 0);
			return ContentPos;
		}
	}

	return null;
};
Paragraph.prototype.Internal_CorrectAnchorPos = function(Result, Drawing)
{
	// Поправляем позицию
	var RelH = Drawing.PositionH.RelativeFrom;
	var RelV = Drawing.PositionV.RelativeFrom;

	var ContentPos = 0;

	if (Asc.c_oAscRelativeFromH.Character != RelH || c_oAscRelativeFromV.Line != RelV)
	{
		var CurLine = Result.Internal.Line;
		if (c_oAscRelativeFromV.Line != RelV)
		{
			var CurPage = Result.Internal.Page;
			CurLine     = this.Pages[CurPage].StartLine;
		}

		Result.X = this.Lines[CurLine].Ranges[0].X - 3.8;
	}

	if (c_oAscRelativeFromV.Line != RelV)
	{
		var CurPage = Result.Internal.Page;
		var CurLine = this.Pages[CurPage].StartLine;
		Result.Y    = this.Pages[CurPage].Y + this.Lines[CurLine].Y - this.Lines[CurLine].Metrics.Ascent;
	}

	if (Asc.c_oAscRelativeFromH.Character === RelH)
	{
		// Ничего не делаем
	}
	else if (c_oAscRelativeFromV.Line === RelV)
	{
		// Ничего не делаем, пусть ссылка будет в позиции, которая записана в NearPos
	}
	else if (0 === Result.Internal.Page)
	{
		// Перемещаем ссылку в начало параграфа
		Result.ContentPos = this.Get_StartPos();
	}
};
/**
 * Получем ближающую возможную позицию курсора
 */
Paragraph.prototype.Get_NearestPos = function(CurPage, X, Y, bAnchor, Drawing)
{
	var SearchPosXY = this.Get_ParaContentPosByXY(X, Y, CurPage, false, false);

	this.Set_ParaContentPos(SearchPosXY.Pos, true, SearchPosXY.Line, SearchPosXY.Range);
	var ContentPos = this.Get_ParaContentPos(false, false);

	ContentPos = this.private_CorrectNearestPos(ContentPos, bAnchor, Drawing);

	var Result = this.Internal_Recalculate_CurPos(ContentPos, false, false, true);

	// Сохраняем параграф и найденное место в параграфе
	Result.ContentPos = ContentPos;
	Result.SearchPos  = SearchPosXY.Pos;
	Result.Paragraph  = this;
	Result.transform  = this.Get_ParentTextTransform();

	if (true === bAnchor && undefined != Drawing && null != Drawing)
		this.Internal_CorrectAnchorPos(Result, Drawing);

	return Result;
};
Paragraph.prototype.private_CorrectNearestPos = function(ContentPos, Anchor, Drawing)
{
	// Не разрешаем вставлять и привязывать любые объекты к формуле
	if (undefined !== Drawing && null !== Drawing)
	{
		var CurPos = ContentPos.Get(0);
		if (para_Math === this.Content[CurPos].Type)
		{
			if (CurPos > 0)
			{
				CurPos--;

				ContentPos = new CParagraphContentPos();
				ContentPos.Update(CurPos, 0);
				this.Content[CurPos].Get_EndPos(false, ContentPos, 1);
				this.Set_ParaContentPos(ContentPos, false, -1, -1);
			}
			else
			{
				CurPos++;

				ContentPos = new CParagraphContentPos();
				ContentPos.Update(CurPos, 0);
				this.Content[CurPos].Get_StartPos(ContentPos, 1);
				this.Set_ParaContentPos(ContentPos, false, -1, -1);
			}
		}
	}

	return ContentPos;
};
Paragraph.prototype.Check_NearestPos = function(NearPos)
{
	var ParaNearPos     = new CParagraphNearPos();
	ParaNearPos.NearPos = NearPos;

	var Count = this.NearPosArray.length;
	for (var Index = 0; Index < Count; Index++)
	{
		if (this.NearPosArray[Index].NearPos === NearPos)
			return;
	}

	this.NearPosArray.push(ParaNearPos);
	ParaNearPos.Classes.push(this);

	var CurPos = NearPos.ContentPos.Get(0);
	this.Content[CurPos].Check_NearestPos(ParaNearPos, 1);
};
Paragraph.prototype.Clear_NearestPosArray = function()
{
	var ArrayLen = this.NearPosArray.length;

	for (var Pos = 0; Pos < ArrayLen; Pos++)
	{
		var ParaNearPos = this.NearPosArray[Pos];

		var ArrayLen2 = ParaNearPos.Classes.length;

		// 0 элемент это сам класс Paragraph, массив в нем очищаем в данной функции в конце
		for (var Pos2 = 1; Pos2 < ArrayLen2; Pos2++)
		{
			var Class          = ParaNearPos.Classes[Pos2];
			Class.NearPosArray = [];
		}
	}

	this.NearPosArray = [];
};
Paragraph.prototype.Get_ParaNearestPos = function(NearPos)
{
	var ArrayLen = this.NearPosArray.length;

	for (var Pos = 0; Pos < ArrayLen; Pos++)
	{
		var ParaNearPos = this.NearPosArray[Pos];

		if (NearPos === ParaNearPos.NearPos)
			return ParaNearPos;
	}

	return null;
};
Paragraph.prototype.Get_Layout = function(ContentPos, Drawing)
{
	var LinePos = this.Get_ParaPosByContentPos(ContentPos);

	var CurLine  = LinePos.Line;
	var CurRange = LinePos.Range;
	var CurPage  = LinePos.Page;

	var X = this.Lines[CurLine].Ranges[CurRange].XVisible;
	var Y = this.Pages[CurPage].Y + this.Lines[CurLine].Y;

	if (true === this.Numbering.Check_Range(CurRange, CurLine))
		X += this.Numbering.WidthVisible;

	var DrawingLayout = new CParagraphDrawingLayout(Drawing, this, X, Y, CurLine, CurRange, CurPage);

	var StartPos = this.Lines[CurLine].Ranges[CurRange].StartPos;
	var EndPos   = this.Lines[CurLine].Ranges[CurRange].EndPos;

	var CurContentPos = ContentPos.Get(0);

	for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
	{
		this.Content[CurPos].Get_Layout(DrawingLayout, ( CurPos === CurContentPos ? true : false ), ContentPos, 1);

		if (true === DrawingLayout.Layout)
		{
			var LogicDocument = this.LogicDocument;
			var LD_PageLimits = LogicDocument.Get_PageLimits(CurPage);
			var LD_PageFields = LogicDocument.Get_PageFields(CurPage);

			var Page_Width  = LD_PageLimits.XLimit;
			var Page_Height = LD_PageLimits.YLimit;

			var X_Left_Field   = LD_PageFields.X;
			var Y_Top_Field    = LD_PageFields.Y;
			var X_Right_Field  = LD_PageFields.XLimit;
			var Y_Bottom_Field = LD_PageFields.YLimit;

			var X_Left_Margin   = X_Left_Field;
			var X_Right_Margin  = Page_Width - X_Right_Field;
			var Y_Bottom_Margin = Page_Height - Y_Bottom_Field;
			var Y_Top_Margin    = Y_Top_Field;

			var CurPage = DrawingLayout.Page;
			var Drawing = DrawingLayout.Drawing;

			var PageAbs   = this.Get_AbsolutePage(CurPage);
			var ColumnAbs = this.Get_AbsoluteColumn(CurPage);
			var PageRel   = PageAbs - this.Parent.Get_AbsolutePage(0);

			var PageLimits = this.Parent.Get_PageLimits(PageRel);
			var PageFields = this.Parent.Get_PageFields(PageRel);

			var _CurPage = 0;
			if (0 !== PageAbs && CurPage > ColumnAbs)
				_CurPage = CurPage - ColumnAbs;

			var ColumnStartX = (0 === CurPage ? this.X_ColumnStart : this.Pages[_CurPage].X     );
			var ColumnEndX   = (0 === CurPage ? this.X_ColumnEnd : this.Pages[_CurPage].XLimit);

			var Top_Margin    = Y_Top_Margin;
			var Bottom_Margin = Y_Bottom_Margin;
			var Page_H        = Page_Height;

			if (true === this.Parent.IsTableCellContent() && undefined != Drawing && true == Drawing.Use_TextWrap())
			{
				Top_Margin    = 0;
				Bottom_Margin = 0;
				Page_H        = 0;
			}

			var PageLimitsOrigin = this.Parent.Get_PageLimits(PageRel);
			if (true === this.Parent.IsTableCellContent() && false === Drawing.IsLayoutInCell())
			{
				PageLimitsOrigin     = LogicDocument.Get_PageLimits(PageAbs);
				var PageFieldsOrigin = LogicDocument.Get_PageFields(PageAbs);
				ColumnStartX         = PageFieldsOrigin.X;
				ColumnEndX           = PageFieldsOrigin.XLimit;
			}

			if (undefined != Drawing && true != Drawing.Use_TextWrap())
			{
				PageFields = LD_PageFields;
				PageLimits = LD_PageLimits;
			}

			var ParagraphTop = (true != Drawing.Use_TextWrap() ? this.Lines[this.Pages[_CurPage].StartLine].Top + this.Pages[_CurPage].Y : this.Pages[_CurPage].Y);
			var Layout       = new CParagraphLayout(DrawingLayout.X, DrawingLayout.Y, this.Get_AbsolutePage(CurPage), DrawingLayout.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, this.Pages[CurPage].Y + this.Lines[CurLine].Y - this.Lines[CurLine].Metrics.Ascent, ParagraphTop);
			return {ParagraphLayout : Layout, PageLimits : PageLimits, PageLimitsOrigin : PageLimitsOrigin};
		}
	}

	return null;
};
Paragraph.prototype.Get_AnchorPos = function(Drawing)
{
	var ContentPos = this.Get_DrawingObjectContentPos(Drawing.Get_Id());

	if (null === ContentPos)
		return {X : 0, Y : 0, Height : 0};

	var ParaPos = this.Get_ParaPosByContentPos(ContentPos);

	// Можем не бояться изменить положение курсора, т.к. данная функция работает, только когда у нас идет
	// выделение автофигуры, а значит курсора нет на экране.

	this.Set_ParaContentPos(ContentPos, false, -1, -1);

	var Result = this.Internal_Recalculate_CurPos(ContentPos, false, false, true);

	Result.Paragraph  = this;
	Result.ContentPos = ContentPos;

	this.Internal_CorrectAnchorPos(Result, Drawing);

	return Result;
};
Paragraph.prototype.IsContentOnFirstPage = function()
{
	// Если параграф сразу переносится на новую страницу, тогда это значение обычно -1
	if (this.Pages[0].EndLine < 0)
		return false;

	return true;
};
Paragraph.prototype.Get_CurrentPage_Absolute = function()
{
	// Обновляем позицию
	this.Internal_Recalculate_CurPos(this.CurPos.ContentPos, true, false, false);
	return this.private_GetAbsolutePageIndex(this.CurPos.PagesPos);
};
Paragraph.prototype.Get_CurrentPage_Relative = function()
{
	// Обновляем позицию
	this.Internal_Recalculate_CurPos(this.CurPos.ContentPos, true, false, false);
	return this.private_GetRelativePageIndex(this.CurPos.PagesPos);
};
Paragraph.prototype.CollectDocumentStatistics = function(Stats)
{
	var ParaStats = new CParagraphStatistics(Stats);
	var Count     = this.Content.length;

	for (var Index = 0; Index < Count; Index++)
	{
		var Item = this.Content[Index];
		Item.CollectDocumentStatistics(ParaStats);
	}

	var oNumPr = this.GetNumPr();
	if (oNumPr)
	{
		ParaStats.EmptyParagraph = false;

		var oNum = this.Parent.GetNumbering().GetNum(oNumPr.NumId);
		if (oNum)
			oNum.GetLvl(oNumPr.Lvl).CollectDocumentStatistics(Stats);
	}

	if (false === ParaStats.EmptyParagraph)
		Stats.Add_Paragraph();
};
Paragraph.prototype.Set_ApplyToAll = function(bValue)
{
	this.ApplyToAll = bValue;
};
Paragraph.prototype.Get_ApplyToAll = function()
{
	return this.ApplyToAll;
};
Paragraph.prototype.Get_ParentTextTransform = function()
{
	return this.Parent.Get_ParentTextTransform();
};
Paragraph.prototype.Get_ParentTextInvertTransform = function()
{
	var CurDocContent = this.Parent;
	var oCell;
	while (oCell = CurDocContent.IsTableCellContent(true))
	{
		CurDocContent = oCell.Row.Table.Parent;
	}
	if (CurDocContent.Parent)
	{
		if (CurDocContent.Parent.invertTransformText)
		{
			return CurDocContent.Parent.invertTransformText;
		}
		if (CurDocContent.Parent.parent && CurDocContent.Parent.parent.invertTransformText)
		{
			return CurDocContent.Parent.parent.invertTransformText;
		}
	}
	if (CurDocContent.invertTransformText)
	{
		return CurDocContent.invertTransformText;
	}
	return null;
};
Paragraph.prototype.UpdateCursorType = function(X, Y, CurPage)
{
	CurPage            = Math.max(0, Math.min(CurPage, this.Pages.length - 1));
	var text_transform = this.Get_ParentTextTransform();
	var MMData         = new AscCommon.CMouseMoveData();
	var Coords         = this.DrawingDocument.ConvertCoordsToCursorWR(X, Y, this.Get_AbsolutePage(CurPage), text_transform);
	MMData.X_abs       = Coords.X;
	MMData.Y_abs       = Coords.Y;

	// TODO: Поиск гиперссылок и сносок нужно переделать через работу с SelectedElementsInfo
	var oInfo = new CSelectedElementsInfo();
	this.GetElementsInfoByXY(oInfo, X, Y, CurPage);

	var bPageRefLink = false;
	var arrComplexFields = this.GetComplexFieldsByXY(X, Y, CurPage);
	for (var nIndex = 0, nCount = arrComplexFields.length; nIndex < nCount; ++nIndex)
	{
		var oComplexField = arrComplexFields[nIndex];
		var oInstruction  = oComplexField.GetInstruction();
		if (oInstruction && fieldtype_PAGEREF === oInstruction.GetType() && oInstruction.IsHyperlink())
		{
			bPageRefLink = true;
			break;
		}
	}

	var oContentControl = oInfo.GetInlineLevelSdt();
	var oHyperlink      = oInfo.GetHyperlink();
	if (oContentControl)
		oContentControl.DrawContentControlsTrack(true);

	var Footnote  = this.CheckFootnote(X, Y, CurPage);

	if (null != oHyperlink && (Y <= this.Pages[CurPage].Bounds.Bottom && Y >= this.Pages[CurPage].Bounds.Top))
	{
		MMData.Type      = AscCommon.c_oAscMouseMoveDataTypes.Hyperlink;
		MMData.Hyperlink = new Asc.CHyperlinkProperty(oHyperlink);

		MMData.Hyperlink.ToolTip = oHyperlink.GetToolTip();
	}
	else if (null !== Footnote && this.Parent instanceof CDocument)
	{
		MMData.Type   = AscCommon.c_oAscMouseMoveDataTypes.Footnote;
		MMData.Text   = Footnote.GetHint();
		MMData.Number = Footnote.GetNumber();
	}
	else
		MMData.Type = AscCommon.c_oAscMouseMoveDataTypes.Common;

	if ((null != oHyperlink || bPageRefLink) && true === AscCommon.global_keyboardEvent.CtrlKey)
		this.DrawingDocument.SetCursorType("pointer", MMData);
	else
		this.DrawingDocument.SetCursorType("text", MMData);

	var Bounds = this.Pages[CurPage].Bounds;
	if (true === this.Lock.Is_Locked() && X < Bounds.Right && X > Bounds.Left && Y > Bounds.Top && Y < Bounds.Bottom && this.LogicDocument && !this.LogicDocument.IsViewModeInReview())
	{
		var _X = this.Pages[CurPage].X;
		var _Y = this.Pages[CurPage].Y;

		var MMData              = new AscCommon.CMouseMoveData();
		var Coords              = this.DrawingDocument.ConvertCoordsToCursorWR(_X, _Y, this.Get_AbsolutePage(CurPage), text_transform);
		MMData.X_abs            = Coords.X - 5;
		MMData.Y_abs            = Coords.Y;
		MMData.Type             = AscCommon.c_oAscMouseMoveDataTypes.LockedObject;
		MMData.UserId           = this.Lock.Get_UserId();
		MMData.HaveChanges      = this.Lock.Have_Changes();
		MMData.LockedObjectType = c_oAscMouseMoveLockedObjectType.Common;

		editor.sync_MouseMoveCallback(MMData);
	}
};
Paragraph.prototype.Document_CreateFontMap = function(FontMap)
{
	if (true === this.FontMap.NeedRecalc)
	{
		this.FontMap.Map = {};

		this.Internal_CompileParaPr();

		var FontScheme = this.Get_Theme().themeElements.fontScheme;
		var CurTextPr  = this.CompiledPr.Pr.TextPr.Copy();

		CurTextPr.Document_CreateFontMap(this.FontMap.Map, FontScheme);

		CurTextPr.Merge(this.TextPr.Value);
		CurTextPr.Document_CreateFontMap(this.FontMap.Map, FontScheme);

		var Count = this.Content.length;
		for (var Index = 0; Index < Count; Index++)
		{
			this.Content[Index].Create_FontMap(this.FontMap.Map);
		}

		this.FontMap.NeedRecalc = false;
	}

	for (var Key in this.FontMap.Map)
	{
		FontMap[Key] = this.FontMap.Map[Key];
	}
};
Paragraph.prototype.Document_CreateFontCharMap = function(FontCharMap)
{
	// TODO: Данная функция устарела и не используется
};
Paragraph.prototype.Document_Get_AllFontNames = function(AllFonts)
{
	// Смотрим на знак конца параграфа
	this.TextPr.Value.Document_Get_AllFontNames(AllFonts);
	if(this.Pr.Bullet)
	{
		this.Pr.Bullet.Get_AllFontNames(AllFonts);
	}
	if(this.Pr.DefaultRunPr)
	{
        this.Pr.DefaultRunPr.Document_Get_AllFontNames(AllFonts);
	}

	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		this.Content[Index].Get_AllFontNames(AllFonts);
	}
};
/**
 * Обновляем линейку
 */
Paragraph.prototype.Document_UpdateRulersState = function()
{
	if (true === this.Is_Inline())
	{
		if (this.Parent instanceof CDocument)
			this.LogicDocument.Document_UpdateRulersStateBySection();
	}
	else
	{
		var StartPage = this.Parent.Get_AbsolutePage(0);
		var Frame     = this.CalculatedFrame;
		this.Parent.DrawingDocument.Set_RulerState_Paragraph({
			L         : Frame.L,
			T         : Frame.T,
			R         : Frame.L + Frame.W,
			B         : Frame.T + Frame.H,
			PageIndex : StartPage + Frame.PageIndex,
			Frame     : this
		}, false);
	}
};
/**
 * Пока мы здесь проверяем только, находимся ли мы внутри гиперссылки
 */
Paragraph.prototype.Document_UpdateInterfaceState = function()
{
	var StartPos, EndPos;
	if (true === this.Selection.Use)
	{
		StartPos = this.Get_ParaContentPos(true, true);
		EndPos   = this.Get_ParaContentPos(true, false);
	}
	else
	{
		var CurPos = this.Get_ParaContentPos(false, false);
		StartPos   = CurPos;
		EndPos     = CurPos;
	}

	if (this.LogicDocument && true === this.LogicDocument.Spelling.Use && (selectionflag_Numbering !== this.Selection.Flag && selectionflag_NumberingCur !== this.Selection.Flag))
		this.SpellChecker.Document_UpdateInterfaceState(StartPos, EndPos);

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (StartPos > EndPos)
		{
			StartPos = this.Selection.EndPos;
			EndPos   = this.Selection.StartPos;
		}

		for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
		{
			var Element = this.Content[CurPos];

			if (true !== Element.IsSelectionEmpty() && Element.Document_UpdateInterfaceState)
				Element.Document_UpdateInterfaceState();
		}
	}
	else
	{
		var CurType = this.Content[this.CurPos.ContentPos].Type;
		if (this.Content[this.CurPos.ContentPos].Document_UpdateInterfaceState)
			this.Content[this.CurPos.ContentPos].Document_UpdateInterfaceState();
	}

	var arrComplexFields = this.GetCurrentComplexFields();
	for (var nIndex = 0, nCount = arrComplexFields.length; nIndex < nCount; ++nIndex)
	{
		var oInstruction = arrComplexFields[nIndex].GetInstruction();
		if (oInstruction && fieldtype_HYPERLINK === oInstruction.GetType())
		{
			var oHyperProps = new Asc.CHyperlinkProperty();
			oHyperProps.put_ToolTip(oInstruction.GetToolTip());
			oHyperProps.put_Value(oInstruction.GetValue());
			oHyperProps.put_Text(this.LogicDocument ? this.LogicDocument.GetComplexFieldTextValue(arrComplexFields[nIndex]) : null);
			oHyperProps.put_InternalHyperlink(oInstruction);
			editor.sync_HyperlinkPropCallback(oHyperProps);

		}
	}

	if (editor && this.bFromDocument)
	{
		var TrackManager = this.LogicDocument.Get_TrackRevisionsManager();

		if (this.Pages.length <= 0 && this.Lines.length <= 0)
			return;

		var ContentPos = this.Get_ParaContentPos(this.Selection.Use, true);
		var ParaPos    = this.Get_ParaPosByContentPos(ContentPos);

		if (this.Pages.length <= ParaPos.Page || this.Lines.length <= ParaPos.Line)
			return;

		var Page_abs      = this.Get_AbsolutePage(ParaPos.Page);
		var _Y            = this.Pages[ParaPos.Page].Y + this.Lines[ParaPos.Line].Top;
		var TextTransform = this.Get_ParentTextTransform();

		var _X     = (this.LogicDocument ? this.LogicDocument.Get_PageLimits(Page_abs).XLimit : 0);
		var Coords = this.DrawingDocument.ConvertCoordsToCursorWR(_X, _Y, Page_abs, TextTransform);

		if (this === TrackManager.Get_CurrentChangeParagraph())
		{
			var Change = TrackManager.Get_CurrentChange();
			if (null !== Change)
			{
				Change.put_InternalPos(_X, _Y, Page_abs);
				TrackManager.Add_VisibleChange(Change);
			}
		}
		else if (false === this.Selection.Use)
		{
			var Changes = TrackManager.Get_ParagraphChanges(this.Get_Id());
			if (Changes.length > 0)
			{
				for (var ChangeIndex = 0, ChangesCount = Changes.length; ChangeIndex < ChangesCount; ChangeIndex++)
				{
					var Change = Changes[ChangeIndex];
					var Type   = Change.get_Type();
					if ((c_oAscRevisionsChangeType.TextAdd !== Type
						&& c_oAscRevisionsChangeType.TextRem !== Type
						&& c_oAscRevisionsChangeType.TextPr !== Type)
						|| (StartPos.Compare(Change.get_StartPos()) >= 0
						&& StartPos.Compare(Change.get_EndPos()) <= 0))
					{
						Change.put_InternalPos(_X, _Y, Page_abs);
						TrackManager.Add_VisibleChange(Change);
					}
				}
			}
		}
	}
};
/**
 * Функция, которую нужно вызвать перед удалением данного элемента
 */
Paragraph.prototype.PreDelete = function()
{
	// Поскольку данный элемент удаляется, поэтому надо удалить все записи о
	// inline объектах в родительском классе, используемых в данном параграфе.
	// Кроме этого, если тут начинались или заканчивались комметарии, то их тоже
	// удаляем.

	for (var Index = 0; Index < this.Content.length; Index++)
	{
		var Item = this.Content[Index];

		if (Item.PreDelete)
			Item.PreDelete();

		if (para_Comment === Item.Type && this.LogicDocument && true === this.LogicDocument.RemoveCommentsOnPreDelete)
		{
			this.LogicDocument.RemoveComment(Item.CommentId, true, false);
		}
		else if (para_Bookmark === Item.Type)
		{
			this.LogicDocument.GetBookmarksManager().SetNeedUpdate(true);
		}
	}

	this.UpdateDocumentOutline();

	if (undefined !== this.Get_SectionPr() && this.LogicDocument)
	{
		// Чтобы при удалении параграфа с секцией автоматически запускался правильно пересчет секции, и правильно
		// пересчитывалось на Undo/Redo.
		this.Set_SectionPr(undefined);
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Дополнительные функции
//----------------------------------------------------------------------------------------------------------------------
Paragraph.prototype.Document_SetThisElementCurrent = function(bUpdateStates)
{
	this.Parent.Update_ContentIndexing();
	this.Parent.Set_CurrentElement(this.Index, bUpdateStates);
};
Paragraph.prototype.Is_ThisElementCurrent = function()
{
	var Parent = this.Parent;

	Parent.Update_ContentIndexing();
	if (docpostype_Content === Parent.Get_DocPosType() && false === Parent.Selection.Use && this.Index === Parent.CurPos.ContentPos && Parent.Content[this.Index] === this)
		return this.Parent.Is_ThisElementCurrent();

	return false;
};
Paragraph.prototype.Is_Inline = function()
{
	// Пустой элемент с разрывом секции мы считаем Inline параграфом.
	var PrevElement = this.Get_DocumentPrev();
	if (true === this.Is_Empty() && undefined !== this.Get_SectionPr() && null !== PrevElement && (type_Paragraph !== PrevElement.Get_Type() || undefined === PrevElement.Get_SectionPr()))
		return true;

	if (undefined === this.Parent || (!(this.Parent instanceof CDocument) && (undefined === this.Parent.Parent || !(this.Parent.Parent instanceof CHeaderFooter))))
		return true;

	if (undefined != this.Pr.FramePr && Asc.c_oAscYAlign.Inline !== this.Pr.FramePr.YAlign)
		return false;

	return true;
};
Paragraph.prototype.Get_FramePr = function()
{
	return this.Pr.FramePr;
};
Paragraph.prototype.Set_FramePr = function(FramePr, bDelete)
{
	var FramePr_old = this.Pr.FramePr;
	if (undefined === bDelete)
		bDelete = false;

	if (true === bDelete)
	{
		this.Pr.FramePr = undefined;
		this.private_AddPrChange();
		History.Add(new CChangesParagraphFramePr(this, FramePr_old, undefined));
		this.CompiledPr.NeedRecalc = true;
		this.private_UpdateTrackRevisionOnChangeParaPr(true);
		return;
	}

	var FrameParas = this.Internal_Get_FrameParagraphs();

	// Тут FramePr- объект класса из api.js asc_CParagraphFrame
	if (true === FramePr.FromDropCapMenu && 1 === FrameParas.length)
	{
		// Здесь мы смотрим только на количество строк, шрифт, тип и горизонтальный отступ от текста
		var NewFramePr = FramePr_old.Copy();

		if (undefined != FramePr.DropCap)
		{
			var OldLines = NewFramePr.Lines;
			NewFramePr.Init_Default_DropCap(FramePr.DropCap === Asc.c_oAscDropCap.Drop ? true : false);
			NewFramePr.Lines = OldLines;
		}

		if (undefined != FramePr.Lines)
		{
			var AnchorPara = this.Get_FrameAnchorPara();

			if (null === AnchorPara || AnchorPara.Lines.length <= 0)
				return;

			var Before = AnchorPara.Get_CompiledPr().ParaPr.Spacing.Before;
			var LineH  = AnchorPara.Lines[0].Bottom - AnchorPara.Lines[0].Top - Before;
			var LineTA = AnchorPara.Lines[0].Metrics.TextAscent2;
			var LineTD = AnchorPara.Lines[0].Metrics.TextDescent + AnchorPara.Lines[0].Metrics.LineGap;

			this.Set_Spacing({LineRule : linerule_Exact, Line : FramePr.Lines * LineH}, false);
			this.Update_DropCapByLines(this.Internal_CalculateTextPr(this.Internal_GetStartPos()), FramePr.Lines, LineH, LineTA, LineTD, Before);

			NewFramePr.Lines = FramePr.Lines;
		}

		if (undefined != FramePr.FontFamily)
		{
			var FF = new ParaTextPr({RFonts : {Ascii : {Name : FramePr.FontFamily.Name, Index : -1}}});
			this.SelectAll();
			this.Add(FF);
			this.RemoveSelection();
		}

		if (undefined != FramePr.HSpace)
			NewFramePr.HSpace = FramePr.HSpace;

		this.Pr.FramePr = NewFramePr;
	}
	else
	{
		var NewFramePr = FramePr_old.Copy();

		if (undefined != FramePr.H)
			NewFramePr.H = FramePr.H;

		if (undefined != FramePr.HAnchor)
			NewFramePr.HAnchor = FramePr.HAnchor;

		if (undefined != FramePr.HRule)
			NewFramePr.HRule = FramePr.HRule;

		if (undefined != FramePr.HSpace)
			NewFramePr.HSpace = FramePr.HSpace;

		if (undefined != FramePr.Lines)
			NewFramePr.Lines = FramePr.Lines;

		if (undefined != FramePr.VAnchor)
			NewFramePr.VAnchor = FramePr.VAnchor;

		if (undefined != FramePr.VSpace)
			NewFramePr.VSpace = FramePr.VSpace;

		// Потому что undefined - нормальное значение (и W всегда заполняется в интерфейсе)
		NewFramePr.W = FramePr.W;

		if (undefined != FramePr.X)
		{
			NewFramePr.X      = FramePr.X;
			NewFramePr.XAlign = undefined;
		}

		if (undefined != FramePr.XAlign)
		{
			NewFramePr.XAlign = FramePr.XAlign;
			NewFramePr.X      = undefined;
		}

		if (undefined != FramePr.Y)
		{
			NewFramePr.Y      = FramePr.Y;
			NewFramePr.YAlign = undefined;
		}

		if (undefined != FramePr.YAlign)
		{
			NewFramePr.YAlign = FramePr.YAlign;
			NewFramePr.Y      = undefined;
		}

		if (undefined !== FramePr.Wrap)
		{
			if (false === FramePr.Wrap)
				NewFramePr.Wrap = wrap_NotBeside;
			else if (true === FramePr.Wrap)
				NewFramePr.Wrap = wrap_Around;
			else
				NewFramePr.Wrap = FramePr.Wrap;
		}

		this.Pr.FramePr = NewFramePr;
	}

	if (undefined != FramePr.Brd)
	{
		var Count = FrameParas.length;
		for (var Index = 0; Index < Count; Index++)
		{
			FrameParas[Index].Set_Borders(FramePr.Brd);
		}
	}

	if (undefined != FramePr.Shd)
	{
		var Count = FrameParas.length;
		for (var Index = 0; Index < Count; Index++)
		{
			FrameParas[Index].Set_Shd(FramePr.Shd);
		}
	}

	this.private_AddPrChange();
	History.Add(new CChangesParagraphFramePr(this, FramePr_old, this.Pr.FramePr));
	this.CompiledPr.NeedRecalc = true;
	this.private_UpdateTrackRevisionOnChangeParaPr(true);
};
Paragraph.prototype.Set_FramePr2 = function(FramePr)
{
	this.private_AddPrChange();
	History.Add(new CChangesParagraphFramePr(this, this.Pr.FramePr, FramePr));
	this.Pr.FramePr            = FramePr;
	this.CompiledPr.NeedRecalc = true;
	this.private_UpdateTrackRevisionOnChangeParaPr(true);
};
Paragraph.prototype.Set_FrameParaPr = function(Para)
{
	Para.CopyPr(this);
	Para.Set_Ind({FirstLine : 0}, false);
	this.Set_Spacing({After : 0}, false);
	this.Set_Ind({Right : 0}, false);
	this.RemoveNumPr();
};
Paragraph.prototype.Get_FrameBounds = function(FrameX, FrameY, FrameW, FrameH)
{
	var X0 = FrameX, Y0 = FrameY, X1 = FrameX + FrameW, Y1 = FrameY + FrameH;

	var Paras   = this.Internal_Get_FrameParagraphs();
	var Count   = Paras.length;
	var FramePr = this.Get_FramePr();

	if (0 >= Count)
		return {X : X0, Y : Y0, W : X1 - X0, H : Y1 - Y0};

	for (var Index = 0; Index < Count; Index++)
	{
		var Para   = Paras[Index];
		var ParaPr = Para.Get_CompiledPr2(false).ParaPr;
		var Brd    = ParaPr.Brd;

		var _X0 = (undefined != Brd.Left && border_None != Brd.Left.Value ? Math.min(X0, X0 + ParaPr.Ind.Left, X0 + ParaPr.Ind.Left + ParaPr.Ind.FirstLine) : X0 + ParaPr.Ind.Left + ParaPr.Ind.FirstLine);

		if (undefined != Brd.Left && border_None != Brd.Left.Value)
			_X0 -= Brd.Left.Size + Brd.Left.Space + 1;

		if (_X0 < X0)
			X0 = _X0;

		var _X1 = X1 - ParaPr.Ind.Right;

		if (undefined != Brd.Right && border_None != Brd.Right.Value)
			_X1 += Brd.Right.Size + Brd.Right.Space + 1;

		if (_X1 > X1)
			X1 = _X1;
	}

	var _Y1          = Y1;
	var BottomBorder = Paras[Count - 1].Get_CompiledPr2(false).ParaPr.Brd.Bottom;
	if (undefined != BottomBorder && border_None != BottomBorder.Value)
		_Y1 += BottomBorder.Size + BottomBorder.Space;

	if (_Y1 > Y1 && ( Asc.linerule_Auto === FramePr.HRule || ( Asc.linerule_AtLeast === FramePr.HRule && FrameH >= FramePr.H ) ))
		Y1 = _Y1;

	return {X : X0, Y : Y0, W : X1 - X0, H : Y1 - Y0};
};
Paragraph.prototype.Set_CalculatedFrame = function(L, T, W, H, L2, T2, W2, H2, PageIndex)
{
	this.CalculatedFrame.T         = T;
	this.CalculatedFrame.L         = L;
	this.CalculatedFrame.W         = W;
	this.CalculatedFrame.H         = H;
	this.CalculatedFrame.T2        = T2;
	this.CalculatedFrame.L2        = L2;
	this.CalculatedFrame.W2        = W2;
	this.CalculatedFrame.H2        = H2;
	this.CalculatedFrame.PageIndex = PageIndex;
};
Paragraph.prototype.Get_CalculatedFrame = function()
{
	return this.CalculatedFrame;
};
Paragraph.prototype.Internal_Get_FrameParagraphs = function()
{
	var FrameParas = [];

	var FramePr = this.Get_FramePr();
	if (undefined === FramePr)
		return FrameParas;

	FrameParas.push(this);

	var Prev = this.Get_DocumentPrev();
	while (null != Prev)
	{
		if (type_Paragraph === Prev.GetType())
		{
			var PrevFramePr = Prev.Get_FramePr();
			if (undefined != PrevFramePr && true === FramePr.Compare(PrevFramePr))
			{
				FrameParas.push(Prev);
				Prev = Prev.Get_DocumentPrev();
			}
			else
				break;
		}
		else
			break;
	}

	var Next = this.Get_DocumentNext();
	while (null != Next)
	{
		if (type_Paragraph === Next.GetType())
		{
			var NextFramePr = Next.Get_FramePr();
			if (undefined != NextFramePr && true === FramePr.Compare(NextFramePr))
			{
				FrameParas.push(Next);
				Next = Next.Get_DocumentNext();
			}
			else
				break;
		}
		else
			break;
	}

	return FrameParas;
};
Paragraph.prototype.Is_LineDropCap = function()
{
	var FrameParas = this.Internal_Get_FrameParagraphs();
	if (1 !== FrameParas.length || 1 !== this.Lines.length)
		return false;

	return true;
};
Paragraph.prototype.Get_LineDropCapWidth = function()
{
	var W      = this.Lines[0].Ranges[0].W;
	var ParaPr = this.Get_CompiledPr2(false).ParaPr;
	W += ParaPr.Ind.Left + ParaPr.Ind.FirstLine;

	return W;
};
Paragraph.prototype.Change_Frame = function(X, Y, W, H, PageIndex)
{
	var LogicDocument = editor.WordControl.m_oLogicDocument;

	var FramePr = this.Get_FramePr();
	if (undefined === FramePr || ( Math.abs(Y - this.CalculatedFrame.T) < 0.001 && Math.abs(X - this.CalculatedFrame.L) < 0.001 && Math.abs(W - this.CalculatedFrame.W) < 0.001 && Math.abs(H - this.CalculatedFrame.H) < 0.001 && PageIndex === this.CalculatedFrame.PageIndex ))
		return;

	var FrameParas = this.Internal_Get_FrameParagraphs();
	if (false === LogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_None, {
			Type      : AscCommon.changestype_2_ElementsArray_and_Type,
			Elements  : FrameParas,
			CheckType : AscCommon.changestype_Paragraph_Content
		}))
	{
		History.Create_NewPoint(AscDFH.historydescription_Document_ParagraphChangeFrame);
		var NewFramePr = FramePr.Copy();

		if (Math.abs(X - this.CalculatedFrame.L) > 0.001)
		{
			NewFramePr.X       = X;
			NewFramePr.XAlign  = undefined;
			NewFramePr.HAnchor = Asc.c_oAscHAnchor.Page;
		}

		if (Math.abs(Y - this.CalculatedFrame.T) > 0.001)
		{
			NewFramePr.Y       = Y;
			NewFramePr.YAlign  = undefined;
			NewFramePr.VAnchor = Asc.c_oAscVAnchor.Page;
		}

		if (Math.abs(W - this.CalculatedFrame.W) > 0.001)
			NewFramePr.W = W;

		if (Math.abs(H - this.CalculatedFrame.H) > 0.001)
		{
			if (undefined != FramePr.DropCap && Asc.c_oAscDropCap.None != FramePr.DropCap && 1 === FrameParas.length)
			{
				var PageH        = this.LogicDocument.Get_PageLimits(PageIndex).YLimit;
				var _H           = Math.min(H, PageH);
				NewFramePr.Lines = this.Update_DropCapByHeight(_H);
				NewFramePr.HRule = linerule_Exact;
				NewFramePr.H     = H;
			}
			else
			{
				if (H <= this.CalculatedFrame.H)
					NewFramePr.HRule = linerule_Exact;
				else
					NewFramePr.HRule = Asc.linerule_AtLeast;

				NewFramePr.H = H;
			}
		}

		var Count = FrameParas.length;
		for (var Index = 0; Index < Count; Index++)
		{
			var Para = FrameParas[Index];
			Para.Set_FramePr(NewFramePr, false);
		}

		LogicDocument.Recalculate();
		LogicDocument.Document_UpdateInterfaceState();
		LogicDocument.Document_UpdateRulersState();
	}
};
Paragraph.prototype.Supplement_FramePr = function(FramePr)
{
	if (undefined != FramePr.DropCap && Asc.c_oAscDropCap.None != FramePr.DropCap)
	{
		var _FramePr       = this.Get_FramePr();
		var FirstFramePara = this;
		var Prev           = FirstFramePara.Get_DocumentPrev();
		while (null != Prev)
		{
			if (type_Paragraph === Prev.GetType())
			{
				var PrevFramePr = Prev.Get_FramePr();
				if (undefined != PrevFramePr && true === _FramePr.Compare(PrevFramePr))
				{
					FirstFramePara = Prev;
					Prev           = Prev.Get_DocumentPrev();
				}
				else
					break;
			}
			else
				break;
		}

		var TextPr = FirstFramePara.Get_FirstRunPr();

		if (undefined === TextPr.RFonts || undefined === TextPr.RFonts.Ascii)
		{
			TextPr = this.Get_CompiledPr2(false).TextPr;
		}

		FramePr.FontFamily =
			{
				Name  : TextPr.RFonts.Ascii.Name,
				Index : TextPr.RFonts.Ascii.Index
			};
	}

	var FrameParas = this.Internal_Get_FrameParagraphs();
	var Count      = FrameParas.length;

	var ParaPr = FrameParas[0].Get_CompiledPr2(false).ParaPr.Copy();
	for (var Index = 1; Index < Count; Index++)
	{
		var TempPr = FrameParas[Index].Get_CompiledPr2(false).ParaPr;
		ParaPr     = ParaPr.Compare(TempPr);
	}

	FramePr.Brd = ParaPr.Brd;
	FramePr.Shd = ParaPr.Shd;
};
Paragraph.prototype.Can_AddDropCap = function()
{
	var Count = this.Content.length;
	for (var Pos = 0; Pos < Count; Pos++)
	{
		var TempRes = this.Content[Pos].Can_AddDropCap();

		if (null !== TempRes)
			return TempRes;
	}

	return false;
};
Paragraph.prototype.Get_TextForDropCap = function(DropCapText, UseContentPos, ContentPos, Depth)
{
	var EndPos = ( true === UseContentPos ? ContentPos.Get(Depth) : this.Content.length - 1 );

	for (var Pos = 0; Pos <= EndPos; Pos++)
	{
		this.Content[Pos].Get_TextForDropCap(DropCapText, (true === UseContentPos && Pos === EndPos ? true : false), ContentPos, Depth + 1);

		if (true === DropCapText.Mixed && ( true === DropCapText.Check || DropCapText.Runs.length > 0 ))
			return;
	}
};
Paragraph.prototype.Split_DropCap = function(NewParagraph)
{
	// Если есть выделение, тогда мы проверяем элементы, идущие до конца выделения, если есть что-то кроме текста
	// тогда мы добавляем в буквицу только первый текстовый элемент, иначе добавляем все от начала параграфа и до
	// конца выделения, кроме этого в буквицу добавляем все табы идущие в начале.

	var DropCapText = new CParagraphGetDropCapText();
	if (true == this.Selection.Use && this.Parent.IsSelectedSingleElement())
	{
		var SelSP = this.Get_ParaContentPos(true, true);
		var SelEP = this.Get_ParaContentPos(true, false);

		if (0 <= SelSP.Compare(SelEP))
			SelEP = SelSP;

		DropCapText.Check = true;
		this.Get_TextForDropCap(DropCapText, true, SelEP, 0);

		DropCapText.Check = false;
		this.Get_TextForDropCap(DropCapText, true, SelEP, 0);
	}
	else
	{
		DropCapText.Mixed = true;
		DropCapText.Check = false;
		this.Get_TextForDropCap(DropCapText, false);
	}

	var Count   = DropCapText.Text.length;
	var PrevRun = null;
	var CurrRun = null;

	for (var Pos = 0, ParaPos = 0, RunPos = 0; Pos < Count; Pos++)
	{
		if (PrevRun !== DropCapText.Runs[Pos])
		{
			PrevRun = DropCapText.Runs[Pos];
			CurrRun = new ParaRun(NewParagraph);
			CurrRun.Set_Pr(DropCapText.Runs[Pos].Pr.Copy());

			NewParagraph.Internal_Content_Add(ParaPos++, CurrRun, false);

			RunPos = 0;
		}

		CurrRun.Add_ToContent(RunPos++, DropCapText.Text[Pos], false);
	}

	if (Count > 0)
		return DropCapText.Runs[Count - 1].Get_CompiledPr(true);

	return null;
};
Paragraph.prototype.Update_DropCapByLines = function(TextPr, Count, LineH, LineTA, LineTD, Before)
{
	if (null === TextPr)
		return;

	// Мы должны сделать так, чтобы высота данного параграфа была точно Count * LineH
	this.Set_Spacing({Before : Before, After : 0, LineRule : linerule_Exact, Line : Count * LineH - 0.001}, false);

	var FontSize = 72;
	TextPr.FontSize = FontSize;

	g_oTextMeasurer.SetTextPr(TextPr, this.Get_Theme());
	g_oTextMeasurer.SetFontSlot(fontslot_ASCII, 1);

	var TMetrics = {Ascent : null, Descent : null};
	this.private_RecalculateTextMetrics(TMetrics);

	var TDescent = TMetrics.Descent;
	var TAscent  = TMetrics.Ascent;

	var THeight = 0;
	if (null === TAscent || null === TDescent)
		THeight = g_oTextMeasurer.GetHeight();
	else
		THeight = -TDescent + TAscent;

	var EmHeight = THeight;

	var NewEmHeight = (Count - 1) * LineH + LineTA;
	var Koef        = NewEmHeight / EmHeight;

	var NewFontSize = TextPr.FontSize * Koef;
	TextPr.FontSize = parseInt(NewFontSize * 2) / 2;

	g_oTextMeasurer.SetTextPr(TextPr, this.Get_Theme());
	g_oTextMeasurer.SetFontSlot(fontslot_ASCII, 1);

	var TNewMetrics = {Ascent : null, Descent : null};
	this.private_RecalculateTextMetrics(TNewMetrics);

	var TNewDescent = TNewMetrics.Descent;
	var TNewAscent  = TNewMetrics.Ascent;

	var TNewHeight = 0;
	if (null === TNewAscent || null === TNewDescent)
		TNewHeight = g_oTextMeasurer.GetHeight();
	else
		TNewHeight = -TNewDescent + TNewAscent;

	var Descent = g_oTextMeasurer.GetDescender();
	var Ascent  = g_oTextMeasurer.GetAscender();

	var Dy = Descent * (LineH * Count) / ( Ascent - Descent ) + TNewHeight - TNewAscent + LineTD;

	var PTextPr = new ParaTextPr({
		RFonts   : {Ascii : {Name : TextPr.RFonts.Ascii.Name, Index : -1}},
		FontSize : TextPr.FontSize,
		Position : Dy
	});

	this.SelectAll();
	this.Add(PTextPr);
	this.RemoveSelection();
};
Paragraph.prototype.Update_DropCapByHeight = function(_Height)
{
	// Ищем следующий параграф, к которому относится буквица
	var AnchorPara = this.Get_FrameAnchorPara();
	if (null === AnchorPara || AnchorPara.Lines.length <= 0)
		return 1;

	var Before = AnchorPara.Get_CompiledPr().ParaPr.Spacing.Before;
	var LineH  = AnchorPara.Lines[0].Bottom - AnchorPara.Lines[0].Top - Before;
	var LineTA = AnchorPara.Lines[0].Metrics.TextAscent2;
	var LineTD = AnchorPara.Lines[0].Metrics.TextDescent + AnchorPara.Lines[0].Metrics.LineGap;

	var Height = _Height - Before;

	this.Set_Spacing({LineRule : linerule_Exact, Line : Height}, false);

	// Посчитаем количество строк
	var LinesCount = Math.ceil(Height / LineH);

	var TextPr = this.Internal_CalculateTextPr(this.Internal_GetStartPos());
	g_oTextMeasurer.SetTextPr(TextPr, this.Get_Theme());
	g_oTextMeasurer.SetFontSlot(fontslot_ASCII, 1);

	var TMetrics = {Ascent : null, Descent : null};
	this.private_RecalculateTextMetrics(TMetrics);

	var TDescent = TMetrics.Descent;
	var TAscent  = TMetrics.Ascent;

	var THeight = 0;
	if (null === TAscent || null === TDescent)
		THeight = g_oTextMeasurer.GetHeight();
	else
		THeight = -TDescent + TAscent;

	var Koef = (Height - LineTD) / THeight;

	var NewFontSize = TextPr.FontSize * Koef;
	TextPr.FontSize = parseInt(NewFontSize * 2) / 2;

	g_oTextMeasurer.SetTextPr(TextPr, this.Get_Theme());
	g_oTextMeasurer.SetFontSlot(fontslot_ASCII, 1);

	var TNewMetrics = {Ascent : null, Descent : null};
	this.private_RecalculateTextMetrics(TNewMetrics);

	var TNewDescent = TNewMetrics.Descent;
	var TNewAscent  = TNewMetrics.Ascent;

	var TNewHeight = 0;
	if (null === TNewAscent || null === TNewDescent)
		TNewHeight = g_oTextMeasurer.GetHeight();
	else
		TNewHeight = -TNewDescent + TNewAscent;

	var Descent = g_oTextMeasurer.GetDescender();
	var Ascent  = g_oTextMeasurer.GetAscender();

	var Dy = Descent * (Height) / ( Ascent - Descent ) + TNewHeight - TNewAscent + LineTD;

	var PTextPr = new ParaTextPr({
		RFonts   : {Ascii : {Name : TextPr.RFonts.Ascii.Name, Index : -1}},
		FontSize : TextPr.FontSize,
		Position : Dy
	});
	this.SelectAll();
	this.Add(PTextPr);
	this.RemoveSelection();

	return LinesCount;
};
Paragraph.prototype.Get_FrameAnchorPara = function()
{
	var FramePr = this.Get_FramePr();
	if (undefined === FramePr)
		return null;

	var Next = this.Get_DocumentNext();
	while (null != Next)
	{
		if (type_Paragraph === Next.GetType())
		{
			var NextFramePr = Next.Get_FramePr();
			if (undefined === NextFramePr || false === FramePr.Compare(NextFramePr))
				return Next;
		}

		Next = Next.Get_DocumentNext();
	}

	return Next;
};
/**
 * Разделяем данный параграф
 */
Paragraph.prototype.Split = function(NewParagraph, Pos)
{
	NewParagraph.DeleteCommentOnRemove = false;
	this.DeleteCommentOnRemove         = false;

	// Обнулим селект и курсор
	this.RemoveSelection();
	NewParagraph.RemoveSelection();

	// Переносим контент, идущий с текущей позиции в параграфе и до конца параграфа,
	// в новый параграф.

	var ContentPos = this.Get_ParaContentPos(false, false);
	var CurPos     = ContentPos.Get(0);

	var TextPr = this.Get_TextPr(ContentPos);

	// Разделяем текущий элемент (возвращается правая, отделившаяся часть, если она null, тогда заменяем
	// ее на пустой ран с заданными настройками).
	var NewElement = this.Content[CurPos].Split(ContentPos, 1);

	if (null === NewElement)
	{
		NewElement = new ParaRun(NewParagraph);
		NewElement.Set_Pr(TextPr.Copy());
	}

	// Теперь делим наш параграф на три части:
	// 1. До элемента с номером CurPos включительно (оставляем эту часть в исходном параграфе)
	// 2. После элемента с номером CurPos (добавляем эту часть в новый параграф)
	// 3. Новый элемент, полученный после разделения элемента с номером CurPos, который мы
	//    добавляем в начало нового параграфа.

	var NewContent = this.Content.slice(CurPos + 1);
	this.Internal_Content_Remove2(CurPos + 1, this.Content.length - CurPos - 1);

	// В старый параграф добавим ран с концом параграфа
	var EndRun = new ParaRun(this);
	EndRun.Add_ToContent(0, new ParaEnd());

	this.Internal_Content_Add(this.Content.length, EndRun);

	// Очищаем новый параграф и добавляем в него Right элемент и NewContent
	NewParagraph.Internal_Content_Remove2(0, NewParagraph.Content.length);
	NewParagraph.Internal_Content_Concat(NewContent);
	NewParagraph.Internal_Content_Add(0, NewElement);
	NewParagraph.Correct_Content();

	// Копируем все настройки в новый параграф. Делаем это после того как определили контент параграфов.
	// У нового параграфа настройки конца параграфа делаем, как у старого (происходит в функции CopyPr), а у старого
	// меняем их на настройки текущего рана.
	this.CopyPr(NewParagraph);
	this.TextPr.Clear_Style();
	this.TextPr.Apply_TextPr(TextPr);

	// Если на данном параграфе заканчивалась секция, тогда переносим конец секции на новый параграф
	var SectPr = this.Get_SectionPr();
	if (undefined !== SectPr)
	{
		this.Set_SectionPr(undefined);
		NewParagraph.Set_SectionPr(SectPr);
	}

	this.MoveCursorToEndPos(false, false);
	NewParagraph.MoveCursorToStartPos(false);

	NewParagraph.DeleteCommentOnRemove = true;
	this.DeleteCommentOnRemove         = true;
};
/**
 * Присоединяем контент параграфа Para к текущему параграфу
 */
Paragraph.prototype.Concat = function(Para)
{
	//var UpdateSelection = (true == this.Selection.Use || true === Para.Selection.Use);

	//var Para1SelectionStartPos =


	this.DeleteCommentOnRemove = false;
	Para.DeleteCommentOnRemove = false;

	// Убираем метку конца параграфа у данного параграфа
	this.Remove_ParaEnd();

	// Если в параграфе Para были точки NearPos, за которыми нужно следить перенесем их в этот параграф
	var NearPosCount = Para.NearPosArray.length;
	for (var Pos = 0; Pos < NearPosCount; Pos++)
	{
		var ParaNearPos = Para.NearPosArray[Pos];

		// Подменяем ссылки на параграф (вложенные ссылки менять не надо, т.к. мы добавляем объекты целиком)
		ParaNearPos.Classes[0]        = this;
		ParaNearPos.NearPos.Paragraph = this;
		ParaNearPos.NearPos.ContentPos.Data[0] += this.Content.length;

		this.NearPosArray.push(ParaNearPos);
	}

	// Добавляем содержимое второго параграфа к первому
	var NewContent = Para.Content.slice(0); // чтобы передать новый массив, а не ссылку на старый
	this.Internal_Content_Concat(NewContent);

	// Удалим из параграфа все элементы (это нужно, чтобы не лежали ссылки на одинаковые объекты в разных параграфах)
	Para.Internal_Content_Remove2(0, Para.Content.length);

	// Если на данном параграфе оканчивалась секция, тогда удаляем эту секцию
	this.Set_SectionPr(undefined);

	// Если на втором параграфе оканчивалась секция, тогда переносим конец секции на данный параграф
	var SectPr = Para.Get_SectionPr();
	if (undefined !== SectPr)
	{
		Para.Set_SectionPr(undefined);
		this.Set_SectionPr(SectPr);
	}

	this.DeleteCommentOnRemove = true;
	Para.DeleteCommentOnRemove = true;
};
/**
 * Копируем настройки параграфа и последние текстовые настройки в новый параграф
 */
Paragraph.prototype.Continue = function(NewParagraph)
{
	var TextPr;
	if (this.Is_Empty())
	{
		TextPr = this.Get_TextPr(this.Get_EndPos(false));
	}
	else
	{
		var EndPos = this.Get_EndPos2(false);
		var CurPos = this.Get_ParaContentPos(false, false);
		this.Set_ParaContentPos(EndPos, true, -1, -1);
		TextPr = this.Get_TextPr(this.Get_ParaContentPos(false, false)).Copy();
		this.Set_ParaContentPos(CurPos, false, -1, -1, false);
		TextPr.HighLight = highlight_None;
	}

	// Копируем настройки параграфа
	// У нового параграфа настройки конца параграфа делаем, как у старого (происходит в функции CopyPr), а у старого
	// меняем их на настройки текущего рана.
	this.CopyPr(NewParagraph);

	// Если в параграфе есть нумерация, то Word не копирует настройки последнего рана на конец параграфа
	if (!this.HaveNumbering() && !this.Lock.Is_Locked())
	{
		this.TextPr.Clear_Style();
		this.TextPr.Apply_TextPr(TextPr);
	}

	NewParagraph.Internal_Content_Add(0, new ParaRun(NewParagraph));
	NewParagraph.Correct_Content();
	NewParagraph.MoveCursorToStartPos(false);

	// Выставляем настройки у всех ранов
	// TODO: Вообще рана тут 2, 1 который только что создали, второй с para_End. как избавимся от второго тут
	// переделать.
	for (var Pos = 0, Count = NewParagraph.Content.length; Pos < Count; Pos++)
	{
		if (para_Run === NewParagraph.Content[Pos].Type)
			NewParagraph.Content[Pos].Set_Pr(TextPr.Copy());
	}

};
//----------------------------------------------------------------------------------------------------------------------
// Undo/Redo функции
//----------------------------------------------------------------------------------------------------------------------
Paragraph.prototype.GetSelectionState = function()
{
	var ParaState    = {};
	ParaState.CurPos = {
		X          : this.CurPos.X,
		Y          : this.CurPos.Y,
		Line       : this.CurPos.Line,
		ContentPos : this.Get_ParaContentPos(false, false),
		RealX      : this.CurPos.RealX,
		RealY      : this.CurPos.RealY,
		PagesPos   : this.CurPos.PagesPos
	};

	ParaState.Selection = {
		Start    : this.Selection.Start,
		Use      : this.Selection.Use,
		StartPos : 0,
		EndPos   : 0,
		Flag     : this.Selection.Flag
	};

	if (true === this.Selection.Use)
	{
		ParaState.Selection.StartPos = this.Get_ParaContentPos(true, true);
		ParaState.Selection.EndPos   = this.Get_ParaContentPos(true, false);
	}

	return [ParaState];
};
Paragraph.prototype.SetSelectionState = function(State, StateIndex)
{
	if (State.length <= 0)
		return;

	var ParaState = State[StateIndex];

	this.CurPos.X        = ParaState.CurPos.X;
	this.CurPos.Y        = ParaState.CurPos.Y;
	this.CurPos.Line     = ParaState.CurPos.Line;
	this.CurPos.RealX    = ParaState.CurPos.RealX;
	this.CurPos.RealY    = ParaState.CurPos.RealY;
	this.CurPos.PagesPos = ParaState.CurPos.PagesPos;

	this.Set_ParaContentPos(ParaState.CurPos.ContentPos, true, -1, -1);

	this.RemoveSelection();

	this.Selection.Start = ParaState.Selection.Start;
	this.Selection.Use   = ParaState.Selection.Use;
	this.Selection.Flag  = ParaState.Selection.Flag;

	if (true === this.Selection.Use)
		this.Set_SelectionContentPos(ParaState.Selection.StartPos, ParaState.Selection.EndPos);
};
Paragraph.prototype.Get_ParentObject_or_DocumentPos = function()
{
	this.Parent.Update_ContentIndexing();
	return this.Parent.Get_ParentObject_or_DocumentPos(this.Index);
};
Paragraph.prototype.Refresh_RecalcData = function(Data)
{
	var Type = Data.Type;

	var bNeedRecalc = false;

	var CurPage = 0;

	switch (Type)
	{
		case AscDFH.historyitem_Paragraph_AddItem:
		case AscDFH.historyitem_Paragraph_RemoveItem:
		{
			for (CurPage = this.Pages.length - 1; CurPage > 0; CurPage--)
			{
				if (Data.Pos > this.Lines[this.Pages[CurPage].StartLine].Get_StartPos())
					break;
			}

			this.RecalcInfo.Set_Type_0(pararecalc_0_All);
			bNeedRecalc = true;
			break;
		}
		case AscDFH.historyitem_Paragraph_Numbering:
		case AscDFH.historyitem_Paragraph_PStyle:
		case AscDFH.historyitem_Paragraph_Pr:
		case AscDFH.historyitem_Paragraph_PresentationPr_Bullet:
		case AscDFH.historyitem_Paragraph_PresentationPr_Level:
		{
			this.RecalcInfo.Set_Type_0(pararecalc_0_All);
			bNeedRecalc = true;

			this.CompiledPr.NeedRecalc = true;
			this.Recalc_RunsCompiledPr();

			break;
		}

		case AscDFH.historyitem_Paragraph_Align:
		case AscDFH.historyitem_Paragraph_DefaultTabSize:
		case AscDFH.historyitem_Paragraph_Ind_First:
		case AscDFH.historyitem_Paragraph_Ind_Left:
		case AscDFH.historyitem_Paragraph_Ind_Right:
		case AscDFH.historyitem_Paragraph_ContextualSpacing:
		case AscDFH.historyitem_Paragraph_KeepLines:
		case AscDFH.historyitem_Paragraph_KeepNext:
		case AscDFH.historyitem_Paragraph_PageBreakBefore:
		case AscDFH.historyitem_Paragraph_Spacing_Line:
		case AscDFH.historyitem_Paragraph_Spacing_LineRule:
		case AscDFH.historyitem_Paragraph_Spacing_Before:
		case AscDFH.historyitem_Paragraph_Spacing_After:
		case AscDFH.historyitem_Paragraph_Spacing_AfterAutoSpacing:
		case AscDFH.historyitem_Paragraph_Spacing_BeforeAutoSpacing:
		case AscDFH.historyitem_Paragraph_WidowControl:
		case AscDFH.historyitem_Paragraph_Tabs:
		case AscDFH.historyitem_Paragraph_Borders_Between:
		case AscDFH.historyitem_Paragraph_Borders_Bottom:
		case AscDFH.historyitem_Paragraph_Borders_Left:
		case AscDFH.historyitem_Paragraph_Borders_Right:
		case AscDFH.historyitem_Paragraph_Borders_Top:
		case AscDFH.historyitem_Paragraph_FramePr:
		{
			bNeedRecalc = true;
			break;
		}
		case AscDFH.historyitem_Paragraph_Shd_Value:
		case AscDFH.historyitem_Paragraph_Shd_Color:
		case AscDFH.historyitem_Paragraph_Shd_Unifill:
		case AscDFH.historyitem_Paragraph_Shd:
		{
			if (this.Parent)
			{
				var oDrawingShape = this.Parent.Is_DrawingShape(true);
				if (oDrawingShape && oDrawingShape.getObjectType && oDrawingShape.getObjectType() === AscDFH.historyitem_type_Shape)
				{
					if (oDrawingShape.chekBodyPrTransform(oDrawingShape.getBodyPr()) || oDrawingShape.checkContentWordArt(oDrawingShape.getDocContent()))
					{
						bNeedRecalc = true;
					}
				}

				// TODO: Когда пересчет заголовков таблицы будет переделан на нормальную схему, без копирования
				// нужно будет убрать эту заглушку
				if (this.Parent.IsTableHeader())
					bNeedRecalc = true;
			}
			break;
		}
		case AscDFH.historyitem_Paragraph_SectionPr:
		{
			if (this.Parent instanceof CDocument)
			{
				this.Parent.UpdateContentIndexing();
				var nSectionIndex = this.Parent.GetSectionIndexByElementIndex(this.GetIndex());
				var oFirstElement = this.Parent.GetFirstElementInSection(nSectionIndex);

				if (oFirstElement)
					this.Parent.Refresh_RecalcData2(oFirstElement.GetIndex(), oFirstElement.private_GetRelativePageIndex(0));
			}

			break;
		}
	}

	if (true === bNeedRecalc)
	{
		var Prev = this.Get_DocumentPrev();
		if (0 === CurPage && null != Prev && type_Paragraph === Prev.GetType() && true === Prev.Get_CompiledPr2(false).ParaPr.KeepNext)
			Prev.Refresh_RecalcData2(Prev.Pages.length - 1);

		// Сообщаем родительскому классу, что изменения произошли в элементе с номером this.Index и на странице
		// this.PageNum
		return this.Refresh_RecalcData2(CurPage);
	}
};
Paragraph.prototype.Refresh_RecalcData2 = function(CurPage)
{
	if (!CurPage)
		CurPage = 0;

	// Если Index < 0, значит данный элемент еще не был добавлен в родительский класс
	if (this.Index >= 0)
		this.Parent.Refresh_RecalcData2(this.Index, this.private_GetRelativePageIndex(CurPage));
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для совместного редактирования
//----------------------------------------------------------------------------------------------------------------------
Paragraph.prototype.Write_ToBinary2 = function(Writer)
{
	Writer.WriteLong(AscDFH.historyitem_type_Paragraph);

	// String2   : Id
	// Variable  : ParaPr
	// String2   : Id TextPr
	// Long      : количество элементов
	// Array of String2 : массив с Id элементами
	// Bool     : bFromDocument

	Writer.WriteString2("" + this.Id);

	var PrForWrite, TextPrForWrite;
	if (this.StartState)
	{
		PrForWrite     = this.StartState.Pr;
		TextPrForWrite = this.StartState.TextPr;
	}
	else
	{
		PrForWrite     = this.Pr;
		TextPrForWrite = this.TextPr;
	}

	PrForWrite.Write_ToBinary(Writer);
	Writer.WriteString2("" + TextPrForWrite.Get_Id());

	var Count = this.Content.length;
	Writer.WriteLong(Count);

	for (var Index = 0; Index < Count; Index++)
	{
		Writer.WriteString2("" + this.Content[Index].Get_Id());
	}

	Writer.WriteBool(this.bFromDocument);
};
Paragraph.prototype.Read_FromBinary2 = function(Reader)
{
	// String2   : Id
	// Variable  : ParaPr
	// String2   : Id TextPr
	// Long      : количество элементов
	// Array of String2 : массив с Id элементами
	// Bool     : bFromDocument

	this.Id = Reader.GetString2();

	this.Pr = new CParaPr();
	this.Pr.Read_FromBinary(Reader);
	this.TextPr = g_oTableId.Get_ById(Reader.GetString2());

	this.Next = null;
	this.Prev = null;

	this.Content = [];
	var Count    = Reader.GetLong();
	for (var Index = 0; Index < Count; Index++)
	{
		var Element = g_oTableId.Get_ById(Reader.GetString2());

		if (null != Element)
		{
			this.Content.push(Element);
			if (Element.SetParagraph)
				Element.SetParagraph(this);
		}
	}

	AscCommon.CollaborativeEditing.Add_NewObject(this);

	this.bFromDocument = Reader.GetBool();
	if (!this.bFromDocument)
	{
		this.Numbering = new ParaPresentationNumbering();
	}
	if (this.bFromDocument || (editor && editor.WordControl && editor.WordControl.m_oDrawingDocument))
	{
		var DrawingDocument = editor.WordControl.m_oDrawingDocument;
		if (undefined !== DrawingDocument && null !== DrawingDocument)
		{
			this.DrawingDocument = DrawingDocument;
			this.LogicDocument   = this.DrawingDocument.m_oLogicDocument;
		}
	}
	else
	{
		AscCommon.CollaborativeEditing.Add_LinkData(this, {});
	}

	this.PageNum = 0;
};
Paragraph.prototype.Load_LinkData = function(LinkData)
{
	if (this.Parent && this.Parent.Parent && this.Parent.Parent.getDrawingDocument)
	{
		this.DrawingDocument = this.Parent.Parent.getDrawingDocument();
	}
};
Paragraph.prototype.Get_SelectionState2 = function()
{
	var ParaState = {};

	ParaState.Id     = this.Get_Id();
	ParaState.CurPos =
		{
			X          : this.CurPos.X,
			Y          : this.CurPos.Y,
			Line       : this.CurPos.Line,
			ContentPos : this.Get_ParaContentPos(false, false),
			RealX      : this.CurPos.RealX,
			RealY      : this.CurPos.RealY,
			PagesPos   : this.CurPos.PagesPos
		};

	ParaState.Selection =
		{
			Start    : this.Selection.Start,
			Use      : this.Selection.Use,
			StartPos : 0,
			EndPos   : 0,
			Flag     : this.Selection.Flag
		};

	if (true === this.Selection.Use)
	{
		ParaState.Selection.StartPos = this.Get_ParaContentPos(true, true);
		ParaState.Selection.EndPos   = this.Get_ParaContentPos(true, false);
	}

	return ParaState;
};
Paragraph.prototype.Set_SelectionState2 = function(ParaState)
{
	this.CurPos.X        = ParaState.CurPos.X;
	this.CurPos.Y        = ParaState.CurPos.Y;
	this.CurPos.Line     = ParaState.CurPos.Line;
	this.CurPos.RealX    = ParaState.CurPos.RealX;
	this.CurPos.RealY    = ParaState.CurPos.RealY;
	this.CurPos.PagesPos = ParaState.CurPos.PagesPos;

	this.Set_ParaContentPos(ParaState.CurPos.ContentPos, true, -1, -1);

	this.RemoveSelection();

	this.Selection.Start = ParaState.Selection.Start;
	this.Selection.Use   = ParaState.Selection.Use;
	this.Selection.Flag  = ParaState.Selection.Flag;

	if (true === this.Selection.Use)
		this.Set_SelectionContentPos(ParaState.Selection.StartPos, ParaState.Selection.EndPos)
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с комментариями
//----------------------------------------------------------------------------------------------------------------------
Paragraph.prototype.AddComment = function(Comment, bStart, bEnd)
{
	if (true == this.ApplyToAll)
	{
		if (true === bEnd)
		{
			var EndContentPos = this.Get_EndPos(false);

			var CommentEnd = new ParaComment(false, Comment.Get_Id());

			var EndPos = EndContentPos.Get(0);

			// Любые другие элементы мы целиком включаем в комментарий
			if (para_Run === this.Content[EndPos].Type)
			{
				var NewElement = this.Content[EndPos].Split(EndContentPos, 1);

				if (null !== NewElement)
					this.Internal_Content_Add(EndPos + 1, NewElement);
			}

			this.Internal_Content_Add(EndPos + 1, CommentEnd);
		}

		if (true === bStart)
		{
			var StartContentPos = this.Get_StartPos();

			var CommentStart = new ParaComment(true, Comment.Get_Id());

			var StartPos = StartContentPos.Get(0);

			// Любые другие элементы мы целиком включаем в комментарий
			if (para_Run === this.Content[StartPos].Type)
			{
				var NewElement = this.Content[StartPos].Split(StartContentPos, 1);

				if (null !== NewElement)
					this.Internal_Content_Add(StartPos + 1, NewElement);

				this.Internal_Content_Add(StartPos + 1, CommentStart);
			}
			else
			{
				this.Internal_Content_Add(StartPos, CommentStart);
			}
		}
	}
	else
	{
		if (true === this.Selection.Use)
		{
			var StartContentPos = this.Get_ParaContentPos(true, true);
			var EndContentPos   = this.Get_ParaContentPos(true, false);

			if (StartContentPos.Compare(EndContentPos) > 0)
			{
				var Temp        = StartContentPos;
				StartContentPos = EndContentPos;
				EndContentPos   = Temp;
			}

			if (true === bEnd)
			{
				var CommentEnd = new ParaComment(false, Comment.Get_Id());

				var EndPos = EndContentPos.Get(0);

				// Любые другие элементы мы целиком включаем в комментарий
				if (para_Run === this.Content[EndPos].Type)
				{
					var NewElement = this.Content[EndPos].Split(EndContentPos, 1);

					if (null !== NewElement)
						this.Internal_Content_Add(EndPos + 1, NewElement);
				}

				this.Internal_Content_Add(EndPos + 1, CommentEnd);
				this.Selection.EndPos = EndPos + 1;
			}

			if (true === bStart)
			{
				var CommentStart = new ParaComment(true, Comment.Get_Id());

				var StartPos = StartContentPos.Get(0);

				// Любые другие элементы мы целиком включаем в комментарий
				if (para_Run === this.Content[StartPos].Type)
				{
					var NewElement = this.Content[StartPos].Split(StartContentPos, 1);

					if (null !== NewElement)
					{
						this.Internal_Content_Add(StartPos + 1, NewElement);
						NewElement.SelectAll();
					}

					this.Internal_Content_Add(StartPos + 1, CommentStart);
					this.Selection.StartPos = StartPos + 1;
				}
				else
				{
					this.Internal_Content_Add(StartPos, CommentStart);
					this.Selection.StartPos = StartPos;
				}
			}
		}
		else
		{
			var ContentPos = this.Get_ParaContentPos(false, false);

			if (true === bEnd)
			{
				var CommentEnd = new ParaComment(false, Comment.Get_Id());

				var EndPos = ContentPos.Get(0);

				// Любые другие элементы мы целиком включаем в комментарий
				if (para_Run === this.Content[EndPos].Type)
				{
					var NewElement = this.Content[EndPos].Split(ContentPos, 1);

					if (null !== NewElement)
						this.Internal_Content_Add(EndPos + 1, NewElement);
				}

				this.Internal_Content_Add(EndPos + 1, CommentEnd);
			}

			if (true === bStart)
			{
				var CommentStart = new ParaComment(true, Comment.Get_Id());

				var StartPos = ContentPos.Get(0);

				// Любые другие элементы мы целиком включаем в комментарий
				if (para_Run === this.Content[StartPos].Type)
				{
					var NewElement = this.Content[StartPos].Split(ContentPos, 1);

					if (null !== NewElement)
						this.Internal_Content_Add(StartPos + 1, NewElement);

					this.Internal_Content_Add(StartPos + 1, CommentStart);
				}
				else
				{
					this.Internal_Content_Add(StartPos, CommentStart);
				}
			}
		}
	}

	this.Correct_Content();
};
Paragraph.prototype.AddCommentToObject = function(Comment, ObjectId)
{
	// TODO: Реализовать добавление комментария по ID объекта
};
Paragraph.prototype.CanAddComment = function()
{
	if (true === this.Selection.Use && true != this.IsSelectionEmpty())
		return true;

	return false;
};
Paragraph.prototype.RemoveCommentMarks = function(Id)
{
	var Count = this.Content.length;
	for (var Pos = 0; Pos < Count; Pos++)
	{
		var Item = this.Content[Pos];
		if (para_Comment === Item.Type && Id === Item.CommentId)
		{
			this.Internal_Content_Remove(Pos);
			Pos--;
			Count--;
		}
	}
};
Paragraph.prototype.ReplaceMisspelledWord = function(Word, oElement)
{
	var Element = null;
	if (oElement)
	{
		for (var nWordId in this.SpellChecker.Elements)
		{
			if (oElement === this.SpellChecker.Elements[nWordId])
			{
				Element = oElement;
				break;
			}
		}
	}

	if (!Element)
		return;

	// Сначала вставим новое слово
	var Class = Element.StartRun;
	if (para_Run !== Class.Type || Element.StartPos.Data.Depth <= 0)
		return;

	var RunPos = Element.StartPos.Data[Element.StartPos.Depth - 1];
	Class.AddText(Word, RunPos);

	// Удалим старое слово
	var StartPos = Element.StartPos;
	var EndPos   = Element.EndPos;

	// Если комментарии попадают в текст, тогда сначала их надо отдельно удалить
	var CommentsToDelete = {};
	var EPos             = EndPos.Get(0);
	var SPos             = StartPos.Get(0);
	for (var Pos = SPos; Pos <= EPos; Pos++)
	{
		var Item = this.Content[Pos];
		if (para_Comment === Item.Type)
			CommentsToDelete[Item.CommentId] = true;
	}

	for (var CommentId in CommentsToDelete)
	{
		this.LogicDocument.RemoveComment(CommentId, true, false);
	}

	this.Set_SelectionContentPos(StartPos, EndPos);
	this.Selection.Use  = true;
	this.Selection.Flag = selectionflag_Common;

	this.Remove();

	this.RemoveSelection();
	this.Set_ParaContentPos(StartPos, true, -1, -1);

	this.RecalcInfo.Set_Type_0(pararecalc_0_All);

	Element.Checked = null;
};
Paragraph.prototype.IgnoreMisspelledWord = function(oElement)
{
	if (oElement)
	{
		for (var nWordId in this.SpellChecker.Elements)
		{
			if (oElement === this.SpellChecker.Elements[nWordId])
			{
				oElement.Checked = true;
				this.ReDraw();
			}
		}
	}
};
Paragraph.prototype.Get_SectionPr = function()
{
	return this.SectPr;
};
Paragraph.prototype.Set_SectionPr = function(SectPr, bUpdate)
{
	if (this.LogicDocument !== this.Parent && (!this.LogicDocument || true !== this.LogicDocument.ForceCopySectPr))
		return;

	if (SectPr !== this.SectPr)
	{
		History.Add(new CChangesParagraphSectPr(this, this.SectPr, SectPr));

		var oOldSectPr = this.SectPr;
		this.SectPr = SectPr;

		if (false !== bUpdate)
			this.LogicDocument.UpdateSectionInfo(oOldSectPr, SectPr, true);

		// TODO: Когда избавимся от ParaEnd переделать тут
		if (this.Content.length > 0 && para_Run === this.Content[this.Content.length - 1].Type)
		{
			var LastRun                = this.Content[this.Content.length - 1];
			LastRun.RecalcInfo.Measure = true;
		}
	}
};
Paragraph.prototype.GetLastRangeVisibleBounds = function()
{
	var CurLine = this.Lines.length - 1;
	var CurPage = this.Pages.length - 1;

	var Line        = this.Lines[CurLine];
	var RangesCount = Line.Ranges.length;

	var RangeW = new CParagraphRangeVisibleWidth();

	var CurRange = 0;
	for (; CurRange < RangesCount; CurRange++)
	{
		var Range    = Line.Ranges[CurRange];
		var StartPos = Range.StartPos;
		var EndPos   = Range.EndPos;

		RangeW.W   = 0;
		RangeW.End = false;

		if (true === this.Numbering.Check_Range(CurRange, CurLine))
			RangeW.W += this.Numbering.WidthVisible;

		for (var Pos = StartPos; Pos <= EndPos; Pos++)
		{
			var Item = this.Content[Pos];
			Item.Get_Range_VisibleWidth(RangeW, CurLine, CurRange);
		}

		if (true === RangeW.End || CurRange === RangesCount - 1)
			break;
	}

	// Определяем позицию и высоту строки
	var Y      = this.Pages[CurPage].Y + this.Lines[CurLine].Top;
	var H      = this.Lines[CurLine].Bottom - this.Lines[CurLine].Top;
	var X      = this.Lines[CurLine].Ranges[CurRange].XVisible;
	var W      = RangeW.W;
	var B      = this.Lines[CurLine].Y - this.Lines[CurLine].Top;
	var XLimit = this.Pages[CurPage].XLimit - this.Get_CompiledPr2(false).ParaPr.Ind.Right

	return {X : X, Y : Y, W : W, H : H, BaseLine : B, XLimit : XLimit};
};
Paragraph.prototype.FindNextFillingForm = function(isNext, isCurrent, isStart)
{
	var nCurPos = this.Selection.Use === true ? this.Selection.StartPos : this.CurPos.ContentPos;

	var nStartPos = 0, nEndPos = 0;
	if (isCurrent)
	{
		if (isStart)
		{
			nStartPos = nCurPos;
			nEndPos   = isNext ? this.Content.length - 1 : 0;
		}
		else
		{
			nStartPos = isNext ? 0 : this.Content.length - 1;
			nEndPos   = nCurPos;
		}
	}
	else
	{
		if (isNext)
		{
			nStartPos = 0;
			nEndPos   = this.Content.length - 1;
		}
		else
		{
			nStartPos = this.Content.length - 1;
			nEndPos   = 0;
		}
	}

	if (isNext)
	{
		for (var nIndex = nStartPos; nIndex <= nEndPos; ++nIndex)
		{
			if (this.Content[nIndex].FindNextFillingForm)
			{
				var oRes = this.Content[nIndex].FindNextFillingForm(true, isCurrent && nIndex === nCurPos ? true : false, isStart);
				if (oRes)
					return oRes;
			}
		}
	}
	else
	{
		for (var nIndex = nStartPos; nIndex >= nEndPos; --nIndex)
		{
			if (this.Content[nIndex].FindNextFillingForm)
			{
				var oRes = this.Content[nIndex].FindNextFillingForm(false, isCurrent && nIndex === nCurPos ? true : false, isStart);
				if (oRes)
					return oRes;
			}
		}
	}

	return null;
};
//----------------------------------------------------------------------------------------------------------------------
Paragraph.prototype.private_ResetSelection = function()
{
    this.Selection.StartPos      = 0;
    this.Selection.EndPos        = 0;
    this.Selection.StartManually = false;
    this.Selection.EndManually   = false;

    this.CurPos.ContentPos  = 0;
};
Paragraph.prototype.private_CorrectCurPosRangeLine = function()
{
    if (-1 !== this.CurPos.Line)
        return;

    // В данной функции мы подбираем для курсора подходящие физическое расположение, если логическое расположение
    // предполагает несколько физических позиций (например начало/конец строки или попадание между обтеканием).
    var ParaCurPos = this.Get_ParaContentPos(false, false);

    var Ranges = this.Get_RangesByPos(ParaCurPos);

    this.CurPos.Line  = -1;
    this.CurPos.Range = -1;

    for (var Index = 0, Count = Ranges.length; Index < Count; Index++)
    {
        var RangeIndex = Ranges[Index].Range;
        var LineIndex  = Ranges[Index].Line;

        if (undefined !== this.Lines[LineIndex] && undefined !== this.Lines[LineIndex].Ranges[RangeIndex])
        {
            var Range = this.Lines[LineIndex].Ranges[RangeIndex];
            if (Range.W > 0)
            {
                this.CurPos.Line = LineIndex;
                this.CurPos.Range = RangeIndex;
                break;
            }
        }
    }
};
/**
 * Получаем массив отрезков, в которые попадает заданная позиция. Их может быть больше 1, например,
 * на месте разрыва строки.
 * @param ContentPos - заданная позиция
 * @returns массив отрезков
 */
Paragraph.prototype.Get_RangesByPos = function(ContentPos)
{
    var Run = this.Get_ElementByPos(ContentPos);

    if (null === Run || para_Run !== Run.Type)
        return [];

    return Run.Get_RangesByPos(ContentPos.Get(ContentPos.Depth - 1));
};
/**
 * Получаем элемент по заданной позиции
 * @param ContentPos - заданная позиция
 * @returns ссылка на элемент
 */
Paragraph.prototype.Get_ElementByPos = function(ContentPos)
{
    if (ContentPos.Depth < 1)
        return this;

    var CurPos = ContentPos.Get(0);
    return this.Content[CurPos].Get_ElementByPos(ContentPos, 1);
};
Paragraph.prototype.private_RecalculateTextMetrics = function(TextMetrics)
{
    for (var Index = 0, Count = this.Content.length; Index < Count; Index++)
    {
        // TODO: Пока данная функция реализована только в ранах, ее надо реализовать во всех остальных классах
        if (this.Content[Index].Recalculate_Measure2)
            this.Content[Index].Recalculate_Measure2(TextMetrics);
    }
};
Paragraph.prototype.GetPageByLine = function(CurLine)
{
    var CurPage = 0;
    var PagesCount = this.Pages.length;
    for (; CurPage < PagesCount; CurPage++)
    {
        if (CurLine >= this.Pages[CurPage].StartLine && CurLine <= this.Pages[CurPage].EndLine)
            break;
    }

    return Math.min(PagesCount - 1, CurPage);
};
Paragraph.prototype.GetTopElement = function()
{
    if (true === this.Parent.Is_TopDocument(false))
        return this;

    return this.Parent.GetTopElement();
};
Paragraph.prototype.CompareDrawingsLogicPositions = function(CompareObject)
{
    var Run1 = this.Get_DrawingObjectRun(CompareObject.Drawing1.Get_Id());
    var Run2 = this.Get_DrawingObjectRun(CompareObject.Drawing2.Get_Id());

    if (Run1 && !Run2)
        CompareObject.Result = 1;
    else if (Run2 && !Run1)
        CompareObject.Result = -1;
    else if (Run1 && Run2)
    {
        var RunPos1 = this.Get_PosByElement(Run1);
        var RunPos2 = this.Get_PosByElement(Run2);

        var Result = RunPos2.Compare(RunPos1);

        if (0 !== Result)
            CompareObject.Result = Result;
        else
        {
            Run1.CompareDrawingsLogicPositions(CompareObject);
        }
    }
};
Paragraph.prototype.StartSelectionFromCurPos = function()
{
	var ContentPos = this.Get_ParaContentPos(false, false);

	this.Selection.Use           = true;
	this.Selection.Start         = false;
	this.Selection.StartManually = true;
	this.Selection.EndManually   = true;
	this.Set_SelectionContentPos(ContentPos, ContentPos);
};
/**
 *  Возвращается объект CParagraphContentPos по заданому Id ParaDrawing, если объект
 *  не найдет, вернется null.
 */
Paragraph.prototype.Get_PosByDrawing = function(Id)
{
    var ContentPos = new CParagraphContentPos();

    var ContentLen = this.Content.length;

    var bFind = false;
    for (var CurPos = 0; CurPos < ContentLen; CurPos++)
    {
        var Element = this.Content[CurPos];
        ContentPos.Update(CurPos, 0);

        if (true === Element.Get_PosByDrawing(Id, ContentPos, 1))
        {
            bFind = true;
            break;
        }
    }

    if (false === bFind || ContentPos.Depth <= 0)
        return null;

    return ContentPos;
};
Paragraph.prototype.GetStyleFromFormatting = function()
{
    // Получим настройки первого рана попавшего в выделение
    var TextPr = null;
    var CurPos = 0;
    if (true === this.Selection.Use)
    {
        var StartPos = this.Selection.StartPos > this.Selection.EndPos ? this.Selection.EndPos : this.Selection.StartPos;
        var EndPos   = this.Selection.StartPos > this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos;

        for (CurPos = StartPos; CurPos < EndPos; ++CurPos)
        {
            if (true !== this.Content[CurPos].IsSelectionEmpty())
                break;
        }
    }
    else
    {
        CurPos = this.CurPos.ContentPos;
    }
    TextPr = this.Content[CurPos].Get_FirstTextPr();

    // В стиль не добавляется HighLight
    if (undefined !== TextPr.HighLight)
    {
        TextPr = TextPr.Copy();
        TextPr.HighLight = undefined;
    }

    // Мы создаем стиль параграфа и стиль рана, линкуем их и возвращаем стиль параграфа.
    var oParaStyle = new asc_CStyle();
    oParaStyle.put_Type(styletype_Paragraph);
    oParaStyle.fill_ParaPr(this.Pr);

    var oStyles = this.Parent.Get_Styles();
    var oPStyle = oStyles.Get(this.Pr.PStyle);
    if (null !== oPStyle)
    {
        oParaStyle.put_BasedOn(oPStyle.Get_Name());
        var oPNextStyle = oStyles.Get(oPStyle.Get_Next());
        if (null !== oPNextStyle)
            oParaStyle.put_Next(oPNextStyle.Get_Name());
    }
    else
	{
		var oDefStyle = oStyles.Get(oStyles.GetDefaultParagraph());
		if (oDefStyle)
			oParaStyle.put_BasedOn(oDefStyle.GetName());
	}
    oParaStyle.fill_TextPr(TextPr);

    var oRunStyle = new asc_CStyle();
    oRunStyle.put_Type(styletype_Character);
    oRunStyle.fill_TextPr(TextPr);
    var oRStyle = oStyles.Get(TextPr.RStyle);
    if (null !== oRStyle)
    {

        oRunStyle.put_BasedOn(oRStyle.Get_Name());
        var oRNextStyle = oStyles.Get(oRStyle.Get_Next());
        if (null !== oRNextStyle)
            oRunStyle.put_Next(oRNextStyle.Get_Name());
    }

    // Линкуем стили
    oParaStyle.put_Link(oRunStyle);
    oRunStyle.put_Link(oParaStyle);

    return oParaStyle;
};
Paragraph.prototype.private_AddCollPrChange = function(Color)
{
    this.CollPrChange = Color;
    AscCommon.CollaborativeEditing.Add_ChangedClass(this);
};
Paragraph.prototype.private_GetCollPrChange = function()
{
    return this.CollPrChange;
};
Paragraph.prototype.Clear_CollaborativeMarks = function()
{
    this.CollPrChange = false;
};
Paragraph.prototype.Have_PrChange = function()
{
    return this.Pr.Have_PrChange();
};
Paragraph.prototype.Get_PrReviewColor = function()
{
    if (this.Pr.ReviewInfo)
        return this.Pr.ReviewInfo.Get_Color();

    return REVIEW_COLOR;
};
Paragraph.prototype.Accept_PrChange = function()
{
    this.Remove_PrChange();
};
Paragraph.prototype.Reject_PrChange = function()
{
    if (true === this.Have_PrChange())
    {
        this.Set_Pr(this.Pr.PrChange);
    }
};
Paragraph.prototype.Add_PrChange = function()
{
    if (false === this.Have_PrChange())
    {
        this.Pr.Add_PrChange();
		History.Add(new CChangesParagraphPrChange(this,
			{
				PrChange   : undefined,
				ReviewInfo : undefined
			},
			{
				PrChange   : this.Pr.PrChange,
				ReviewInfo : this.Pr.ReviewInfo
			}));
        this.private_UpdateTrackRevisions();
    }
};
Paragraph.prototype.Set_PrChange = function(PrChange, ReviewInfo)
{
	History.Add(new CChangesParagraphPrChange(this,
		{
			PrChange   : this.Pr.PrChange,
			ReviewInfo : this.Pr.ReviewInfo ? this.Pr.ReviewInfo.Copy() : undefined
		},
		{
			PrChange   : PrChange,
			ReviewInfo : ReviewInfo ? ReviewInfo.Copy() : undefined
		}));
    this.Pr.Set_PrChange(PrChange, ReviewInfo);
    this.private_UpdateTrackRevisions();
};
Paragraph.prototype.Remove_PrChange = function()
{
    if (true === this.Have_PrChange())
    {
		History.Add(new CChangesParagraphPrChange(this,
			{
				PrChange   : this.Pr.PrChange,
				ReviewInfo : this.Pr.ReviewInfo
			},
			{
				PrChange   : undefined,
				ReviewInfo : undefined
			}));
        this.Pr.Remove_PrChange();
        this.private_UpdateTrackRevisions();
    }
};
Paragraph.prototype.private_AddPrChange = function()
{
    if (this.LogicDocument && true === this.LogicDocument.Is_TrackRevisions() && true !== this.Have_PrChange())
        this.Add_PrChange();
};
Paragraph.prototype.Set_ReviewType = function(ReviewType)
{
    var EndRun = this.Get_ParaEndRun();
    EndRun.Set_ReviewType(ReviewType);
};
Paragraph.prototype.Get_ReviewType = function()
{
    var EndRun = this.Get_ParaEndRun();
    return EndRun.Get_ReviewType();
};
Paragraph.prototype.Get_ReviewInfo = function()
{
    var EndRun = this.Get_ParaEndRun();
    return EndRun.ReviewInfo;
};
Paragraph.prototype.Get_ParaEndRun = function()
{
    return this.Content[this.Content.length - 1];
};
Paragraph.prototype.Is_TrackRevisions = function()
{
    if (this.LogicDocument)
        return this.LogicDocument.Is_TrackRevisions();

    return false;
};
/**
 * Отличие данной функции от Get_SectionPr в том, что здесь возвращаются настройки секции, к которой
 * принадлежит данный параграф, а там конкретно настройки секции, которые лежат в данном параграфе.
 */
Paragraph.prototype.Get_SectPr = function()
{
    if (this.Parent && this.Parent.Get_SectPr)
    {
        this.Parent.Update_ContentIndexing();
        return this.Parent.Get_SectPr(this.Index);
    }

    return null;
};
Paragraph.prototype.Check_RevisionsChanges = function(RevisionsManager)
{
    var ParaId = this.Get_Id();

    var Change, StartPos, EndPos;
    if (true === this.Have_PrChange())
    {
        StartPos = this.Get_StartPos();
        EndPos   = this.Get_EndPos(true);

        Change = new CRevisionsChange();
        Change.put_Paragraph(this);
        Change.put_StartPos(StartPos);
        Change.put_EndPos(EndPos);
        Change.put_Type(c_oAscRevisionsChangeType.ParaPr);
        Change.put_Value(this.Pr.Get_DiffPrChange());
        Change.put_UserId(this.Pr.ReviewInfo.Get_UserId());
        Change.put_UserName(this.Pr.ReviewInfo.Get_UserName());
        Change.put_DateTime(this.Pr.ReviewInfo.Get_DateTime());
        RevisionsManager.Add_Change(ParaId, Change);
    }

    var Checker    = new CParagraphRevisionsChangesChecker(this, RevisionsManager);
    var ContentPos = new CParagraphContentPos();
    for (var CurPos = 0, Count = this.Content.length; CurPos < Count; CurPos++)
    {
        if (CurPos === Count - 1)
            Checker.Set_ParaEndRun();

        ContentPos.Update(CurPos, 0);
        this.Content[CurPos].Check_RevisionsChanges(Checker, ContentPos, 1);
    }

    Checker.Flush_AddRemoveChange();
    Checker.Flush_TextPrChange();

    var ReviewType = this.Get_ReviewType();
    var ReviewInfo = this.Get_ReviewInfo();
    if (reviewtype_Add == ReviewType)
    {
        StartPos = this.Get_EndPos(false);
        EndPos   = this.Get_EndPos(true);

        Change = new CRevisionsChange();
        Change.put_Paragraph(this);
        Change.put_StartPos(StartPos);
        Change.put_EndPos(EndPos);
        Change.put_Type(c_oAscRevisionsChangeType.ParaAdd);
        Change.put_UserId(ReviewInfo.Get_UserId());
        Change.put_UserName(ReviewInfo.Get_UserName());
        Change.put_DateTime(ReviewInfo.Get_DateTime());
        RevisionsManager.Add_Change(ParaId, Change);
    }
    else if (reviewtype_Remove == ReviewType)
    {
        StartPos = this.Get_EndPos(false);
        EndPos   = this.Get_EndPos(true);

        Change = new CRevisionsChange();
        Change.put_Paragraph(this);
        Change.put_StartPos(StartPos);
        Change.put_EndPos(EndPos);
        Change.put_Type(c_oAscRevisionsChangeType.ParaRem);
        Change.put_UserId(ReviewInfo.Get_UserId());
        Change.put_UserName(ReviewInfo.Get_UserName());
        Change.put_DateTime(ReviewInfo.Get_DateTime());
        RevisionsManager.Add_Change(ParaId, Change);
    }
};
Paragraph.prototype.private_UpdateTrackRevisionOnChangeParaPr = function(bUpdateInfo)
{
    if (true === this.Have_PrChange())
    {
        this.private_UpdateTrackRevisions();

        if (true === bUpdateInfo && this.LogicDocument && true === this.LogicDocument.Is_TrackRevisions())
        {
            var OldReviewInfo = this.Pr.ReviewInfo.Copy();
            this.Pr.ReviewInfo.Update();
            History.Add(new CChangesParagraphPrReviewInfo(this, OldReviewInfo, this.Pr.ReviewInfo.Copy()));
        }
    }
};
Paragraph.prototype.private_UpdateTrackRevisions = function()
{
    if (this.LogicDocument && this.LogicDocument.Get_TrackRevisionsManager)
    {
        var RevisionsManager = this.LogicDocument.Get_TrackRevisionsManager();
        RevisionsManager.Check_Paragraph(this);
    }
};
Paragraph.prototype.UpdateDocumentOutline = function()
{
	if (!this.LogicDocument || !this.Parent)
		return;

	var isCheck = true;
	var oParent = this.Parent;
	while (oParent)
	{
		if (oParent === this.LogicDocument)
		{
			break;
		}
		else if (oParent.IsBlockLevelSdtContent())
		{
			oParent = oParent.Parent.Parent;
		}
		else
		{
			isCheck = false;
			break;
		}
	}

	if (isCheck)
	{
		var oDocumentOutline = this.LogicDocument.GetDocumentOutline();
		if (oDocumentOutline.IsUse())
			oDocumentOutline.CheckParagraph(this);
	}
};
Paragraph.prototype.AcceptRevisionChanges = function(Type, bAll)
{
    if (true === this.Selection.Use || true === bAll)
    {
        var StartPos = this.Selection.StartPos;
        var EndPos   = this.Selection.EndPos;
        if (StartPos > EndPos)
        {
            StartPos = this.Selection.EndPos;
            EndPos   = this.Selection.StartPos;
        }

        if (true === bAll)
        {
            StartPos = 0;
            EndPos   = this.Content.length - 1;
        }

        // TODO: Как переделаем ParaEnd переделать здесь
        if (EndPos >= this.Content.length - 1)
        {
            EndPos = this.Content.length - 2;
            if (true === bAll || undefined === Type || c_oAscRevisionsChangeType.TextPr === Type)
                this.Content[this.Content.length - 1].Accept_PrChange();
        }

        // Начинаем с конца, потому что при выполнении данной фунцкции, количество элементов может изменяться
        for (var CurPos = EndPos; CurPos >= StartPos; CurPos--)
        {
            if (this.Content[CurPos].AcceptRevisionChanges)
                this.Content[CurPos].AcceptRevisionChanges(Type, bAll);
        }

        this.Correct_Content();
        this.Correct_ContentPos(false);
        this.private_UpdateTrackRevisions();
    }
};
Paragraph.prototype.RejectRevisionChanges = function(Type, bAll)
{
    if (true === this.Selection.Use || true === bAll)
    {
        var StartPos = this.Selection.StartPos;
        var EndPos   = this.Selection.EndPos;
        if (StartPos > EndPos)
        {
            StartPos = this.Selection.EndPos;
            EndPos   = this.Selection.StartPos;
        }

        if (true === bAll)
        {
            StartPos = 0;
            EndPos   = this.Content.length - 1;
        }

        // TODO: Как переделаем ParaEnd переделать здесь
        if (EndPos >= this.Content.length - 1)
        {
            EndPos = this.Content.length - 2;
            if (true === bAll || undefined === Type || c_oAscRevisionsChangeType.TextPr === Type)
                this.Content[this.Content.length - 1].Reject_PrChange();
        }

        // Начинаем с конца, потому что при выполнении данной фунцкции, количество элементов может изменяться
        for (var CurPos = EndPos; CurPos >= StartPos; CurPos--)
        {
            if (this.Content[CurPos].RejectRevisionChanges)
                this.Content[CurPos].RejectRevisionChanges(Type, bAll);
        }

        this.Correct_Content();
        this.Correct_ContentPos(false);
        this.private_UpdateTrackRevisions();
    }
};
Paragraph.prototype.GetRevisionsChangeParagraph = function(SearchEngine)
{
    if (true === SearchEngine.Is_Found())
        return;

    var Direction = SearchEngine.Get_Direction();
    if (Direction > 0)
    {
        var DrawingObjects = this.GetAllDrawingObjects();
        for (var DrawingIndex = 0, Count = DrawingObjects.length; DrawingIndex < Count; DrawingIndex++)
        {
            DrawingObjects[DrawingIndex].GetRevisionsChangeParagraph(SearchEngine);
            if (true === SearchEngine.Is_Found())
                return;
        }
    }

    if (true !== SearchEngine.Is_CurrentFound())
    {
        if (this === SearchEngine.GetCurrentParagraph())
            SearchEngine.Set_CurrentFound(this);
    }
    else
    {
        SearchEngine.Set_FoundedParagraph(this);
    }

    if (Direction < 0 && true !== SearchEngine.Is_Found())
    {
        var DrawingObjects = this.GetAllDrawingObjects();
        for (var DrawingIndex = DrawingObjects.length - 1; DrawingIndex >= 0; DrawingIndex--)
        {
            DrawingObjects[DrawingIndex].GetRevisionsChangeParagraph(SearchEngine);
            if (true === SearchEngine.Is_Found())
                return;
        }
    }
};
Paragraph.prototype.IsSelectedAll = function()
{
    var bStart = this.Selection_IsFromStart();
    var bEnd   = this.Selection_CheckParaEnd();

    return ((true === bStart && true === bEnd) || true === this.ApplyToAll ? true : false);
};
Paragraph.prototype.Get_HdrFtr = function()
{
    if (this.Parent)
        return this.Parent.IsHdrFtr(true);

    return null;
};
Paragraph.prototype.GetContentPosition = function(bSelection, bStart, PosArray)
{
    if (!PosArray)
        PosArray = [];

    var Index = PosArray.length;

    var ParaContentPos = this.Get_ParaContentPos(bSelection, bStart);

    var Depth = ParaContentPos.Get_Depth();
    while (Depth > 0)
    {
        var Pos = ParaContentPos.Get(Depth);
        ParaContentPos.Decrease_Depth(1);
        var Class = this.Get_ElementByPos(ParaContentPos);
        Depth--;

        PosArray.splice(Index, 0, {Class : Class, Position : Pos});
    }

    PosArray.splice(Index, 0, {Class : this, Position : ParaContentPos.Get(0)});
    return PosArray;
};
Paragraph.prototype.SetContentSelection = function(StartDocPos, EndDocPos, Depth, StartFlag, EndFlag)
{
    if ((0 === StartFlag && (!StartDocPos[Depth] || this !== StartDocPos[Depth].Class)) || (0 === EndFlag && (!EndDocPos[Depth] || this !== EndDocPos[Depth].Class)))
        return;

    var StartPos = 0, EndPos = 0;
    switch (StartFlag)
    {
        case 0 : StartPos = StartDocPos[Depth].Position; break;
        case 1 : StartPos = 0; break;
        case -1: StartPos = this.Content.length - 1; break;
    }

    switch (EndFlag)
    {
        case 0 : EndPos = EndDocPos[Depth].Position; break;
        case 1 : EndPos = 0; break;
        case -1: EndPos = this.Content.length - 1; break;
    }

    var _StartDocPos = StartDocPos, _StartFlag = StartFlag;
    if (null !== StartDocPos && true === StartDocPos[Depth].Deleted)
    {
        if (StartPos < this.Content.length)
        {
            _StartDocPos = null;
            _StartFlag = 1;
        }
        else if (StartPos > 0)
        {
            StartPos--;
            _StartDocPos = null;
            _StartFlag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    var _EndDocPos = EndDocPos, _EndFlag = EndFlag;
    if (null !== EndDocPos && true === EndDocPos[Depth].Deleted)
    {
        if (EndPos < this.Content.length)
        {
            _EndDocPos = null;
            _EndFlag = 1;
        }
        else if (EndPos > 0)
        {
            EndPos--;
            _EndDocPos = null;
            _EndFlag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    this.Selection.Use      = true;
    this.Selection.StartPos = StartPos;
    this.Selection.EndPos   = EndPos;

    if (StartPos !== EndPos)
    {
        if (this.Content[StartPos] && this.Content[StartPos].SetContentSelection)
        this.Content[StartPos].SetContentSelection(_StartDocPos, null, Depth + 1, _StartFlag, StartPos > EndPos ? 1 : -1);

        if (this.Content[EndPos] && this.Content[EndPos].SetContentSelection)
        this.Content[EndPos].SetContentSelection(null, _EndDocPos, Depth + 1, StartPos > EndPos ? -1 : 1, _EndFlag);

        var _StartPos = StartPos;
        var _EndPos = EndPos;
        var Direction = 1;

        if (_StartPos > _EndPos)
        {
            _StartPos = EndPos;
            _EndPos = StartPos;
            Direction = -1;
        }

        for (var CurPos = _StartPos + 1; CurPos < _EndPos; CurPos++)
        {
            this.Content[CurPos].SelectAll(Direction);
        }
    }
    else
    {
        if (this.Content[StartPos] && this.Content[StartPos].SetContentSelection)
        this.Content[StartPos].SetContentSelection(_StartDocPos, _EndDocPos, Depth + 1, _StartFlag, _EndFlag);
    }
};
Paragraph.prototype.SetContentPosition = function(DocPos, Depth, Flag)
{
    if (0 === Flag && (!DocPos[Depth] || this !== DocPos[Depth].Class))
        return;

    var Pos = 0;
    switch (Flag)
    {
        case 0 : Pos = DocPos[Depth].Position; break;
        case 1 : Pos = 0; break;
        case -1: Pos = this.Content.length - 1; break;
    }

    var _DocPos = DocPos, _Flag = Flag;
    if (null !== DocPos && true === DocPos[Depth].Deleted)
    {
        if (Pos < this.Content.length)
        {
            _DocPos = null;
            _Flag = 1;
        }
        else if (Pos > 0)
        {
            Pos--;
            _DocPos = null;
            _Flag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    // TODO: Как только разберемся с ParaEnd, исправить здесь.
    if (Pos === this.Content.length - 1 && this.Content.length > 1)
	{
		Pos     = this.Content.length - 2;
		_Flag   = -1;
		_DocPos = null;
	}

    this.CurPos.ContentPos = Pos;
    if (this.Content[Pos] && this.Content[Pos].SetContentPosition)
    	this.Content[Pos].SetContentPosition(_DocPos, Depth + 1, _Flag);
    else
        this.Correct_ContentPos2();
};
Paragraph.prototype.Get_XYByContentPos = function(ContentPos)
{
	var ParaContentPos = this.Get_ParaContentPos(false, false);
	this.Set_ParaContentPos(ContentPos, true, -1, -1);
	var Result = this.Internal_Recalculate_CurPos(-1, false, false, true);
	this.Set_ParaContentPos(ParaContentPos, true, this.CurPos.Line, this.CurPos.Range, false);
	return Result;
};
Paragraph.prototype.Get_Lock = function()
{
    return this.Lock;
};
Paragraph.prototype.Get_ContentLength = function()
{
    return this.Content.length;
};
Paragraph.prototype.Get_PagesCount = function()
{
    return this.Pages.length;
};
Paragraph.prototype.GetPagesCount = function()
{
	return this.Pages.length;
};
Paragraph.prototype.IsEmptyPage = function(CurPage, bSkipEmptyLinesWithBreak)
{
    if (!this.Pages[CurPage] || this.Pages[CurPage].EndLine < this.Pages[CurPage].StartLine)
        return true;

    if (true === bSkipEmptyLinesWithBreak
		&& this.Pages[CurPage].EndLine === this.Pages[CurPage].StartLine
		&& this.Lines[this.Pages[CurPage].EndLine]
		&& this.Lines[this.Pages[CurPage].EndLine].Info & paralineinfo_Empty
		&& this.Lines[this.Pages[CurPage].EndLine].Info & paralineinfo_BreakRealPage)
    	return true;

    return false;
};
Paragraph.prototype.Check_FirstPage = function(CurPage, bSkipEmptyLinesWithBreak)
{
    if (true === this.IsEmptyPage(CurPage, bSkipEmptyLinesWithBreak))
        return false;

    return this.Check_EmptyPages(CurPage - 1, bSkipEmptyLinesWithBreak);
};
Paragraph.prototype.Check_EmptyPages = function(CurPage, bSkipEmptyLinesWithBreak)
{
    for (var _CurPage = CurPage; _CurPage >= 0; --_CurPage)
    {
        if (true !== this.IsEmptyPage(_CurPage, bSkipEmptyLinesWithBreak))
            return false;
    }

    return true;
};
Paragraph.prototype.Get_CurrentColumn = function(CurPage)
{
    this.Internal_Recalculate_CurPos(this.CurPos.ContentPos, true, false, false);
    return this.Get_AbsoluteColumn(this.CurPos.PagesPos);
};
Paragraph.prototype.private_RefreshNumbering = function(NumPr)
{
    if (undefined === NumPr || null === NumPr)
        return;

    History.Add_RecalcNumPr(NumPr);
};
Paragraph.prototype.Get_NumberingPage = function()
{
    var ParaNum = this.Numbering;
    var NumberingRun = ParaNum.Run;

    if (null === NumberingRun)
        return -1;

    var NumLine = ParaNum.Line;
    for (var CurPage = 0, PagesCount = this.Pages.length; CurPage < PagesCount; ++CurPage)
    {
        if (NumLine >= this.Pages[CurPage].StartLine && NumLine <= this.Pages[CurPage].EndLine)
            return CurPage;
    }

    return -1;
};
Paragraph.prototype.Set_ParaPropsForVerticalTextInCell = function(isVerticalText)
{
    if (true === isVerticalText)
    {
        var Left  = (undefined === this.Pr.Ind.Left || this.Pr.Ind.Left < 0.001 ? 2 : undefined);
        var Right = (undefined === this.Pr.Ind.Right || this.Pr.Ind.Right < 0.001 ? 2 : undefined);

        this.Set_Ind({Left : Left, Right : Right}, false);
    }
    else
    {

        var Left  = (undefined !== this.Pr.Ind.Left && Math.abs(this.Pr.Ind.Left - 2) < 0.01 ? undefined : this.Pr.Ind.Left);
        var Right = (undefined !== this.Pr.Ind.Right && Math.abs(this.Pr.Ind.Right - 2) < 0.01 ? undefined : this.Pr.Ind.Right);
        var First = this.Pr.Ind.FirstLine;

        this.Set_Ind({Left : Left, Right : Right, FirstLine : First}, true);
    }
};
/**
 * Проверяем можно ли объединить границы двух параграфов с заданными настройками Pr1, Pr2.
 */
Paragraph.prototype.private_CompareBorderSettings = function(Pr1, Pr2)
{
	// Сначала сравним правую и левую границы параграфов
	var Left_1  = Math.min(Pr1.Ind.Left, Pr1.Ind.Left + Pr1.Ind.FirstLine);
	var Right_1 = Pr1.Ind.Right;
	var Left_2  = Math.min(Pr2.Ind.Left, Pr2.Ind.Left + Pr2.Ind.FirstLine);
	var Right_2 = Pr2.Ind.Right;

	if (Math.abs(Left_1 - Left_2) > 0.001 || Math.abs(Right_1 - Right_2) > 0.001)
		return false;

	// Почему то Word не сравнивает границы между параграфами.
	if (false === Pr1.Brd.Top.Compare(Pr2.Brd.Top)
		|| false === Pr1.Brd.Bottom.Compare(Pr2.Brd.Bottom)
		|| false === Pr1.Brd.Left.Compare(Pr2.Brd.Left)
		|| false === Pr1.Brd.Right.Compare(Pr2.Brd.Right))
		return false;

	return true;
};
Paragraph.prototype.Get_FootnotesList = function(oEngine)
{
	oEngine.SetCurrentParagraph(this);
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		if (this.Content[nIndex].Get_FootnotesList)
			this.Content[nIndex].Get_FootnotesList(oEngine);

		if (oEngine.IsRangeFull())
			return;
	}
};
Paragraph.prototype.GetAutoWidthForDropCap = function()
{
	if (this.Is_Empty())
	{
		var oEndRun = this.Content[this.Content.length - 1];
		if (!oEndRun || oEndRun.Type !== para_Run)
			return 0;

		var oParaEnd = oEndRun.GetParaEnd();
		if (!oParaEnd)
			return 0;

		return oParaEnd.Get_WidthVisible();
	}
	else
	{
		if (this.Lines.length <= 0 || this.Lines[0].Ranges.length <= 0)
			return 0;

		return this.Lines[0].Ranges[0].W;
	}
};
Paragraph.prototype.GotoFootnoteRef = function(isNext, isCurrent)
{
	var nPos = 0;

	if (true === isCurrent)
	{
		if (true === this.Selection.Use)
			nPos = Math.min(this.Selection.StartPos, this.Selection.EndPos);
		else
			nPos = this.CurPos.ContentPos;

	}
	else
	{
		if (true === isNext)
			nPos = 0;
		else
			nPos = this.Content.length - 1;
	}

	var isStepOver = false;
	if (true === isNext)
	{
		for (var nIndex = nPos, nCount = this.Content.length - 1; nIndex < nCount; ++nIndex)
		{
			var nRes = this.Content[nIndex].GotoFootnoteRef ? this.Content[nIndex].GotoFootnoteRef(true, true === isCurrent && nPos === nIndex, isStepOver) : 0;

			if (nRes > 0)
				isStepOver = true;
			else  if (-1 === nRes)
				return true;
		}
	}
	else
	{
		for (var nIndex = nPos; nIndex >= 0; --nIndex)
		{
			var nRes = this.Content[nIndex].GotoFootnoteRef ? this.Content[nIndex].GotoFootnoteRef(false, true === isCurrent && nPos === nIndex, isStepOver) : 0;

			if (nRes > 0)
				isStepOver = true;
			else  if (-1 === nRes)
				return true;
		}
	}

	return false;
};
Paragraph.prototype.GetText = function(oPr)
{
	var oText = new CParagraphGetText();
	oText.SetBreakOnNonText(false);
	oText.SetParaEndToSpace(true);

	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		if (this.Content[nIndex].Get_Text)
			this.Content[nIndex].Get_Text(oText);
	}

	return oText.Text;
};
Paragraph.prototype.CheckFootnote = function(X, Y, CurPage)
{
	var SearchPosXY = this.Get_ParaContentPosByXY(X, Y, CurPage, false, false);
	var CurLine = SearchPosXY.Line;

	if (true !== SearchPosXY.InText)
		return null;

	if (!this.Lines[CurLine])
	{
		return null;
	}
	else if (this.Lines[CurLine].Info & paralineinfo_Notes)
	{
		var arrFootnoteRefs = this.private_GetFootnoteRefsInLine(CurLine);
		var nMinDiff = 1000000000;
		var oNote = null;
		for (var nIndex = 0, nCount = arrFootnoteRefs.length; nIndex < nCount; ++nIndex)
		{
			var oFootnoteRef = arrFootnoteRefs[nIndex];
			var oFootnote    = oFootnoteRef.Get_Footnote();
			var oPosInfo     = oFootnote.GetPositionInfo();

			if (Math.abs(X - oPosInfo.X) < nMinDiff || Math.abs(X - (oPosInfo.X + oPosInfo.W)) < nMinDiff)
			{
				nMinDiff = Math.min(Math.abs(X - oPosInfo.X), Math.abs(X - (oPosInfo.X + oPosInfo.W)));
				oNote    = oFootnote;
			}
		}

		if (nMinDiff > 10)
			oNote = null;

		return oNote;
	}

	return null;
};
Paragraph.prototype.private_GetFootnoteRefsInLine = function(CurLine)
{
	var arrFootnotes = [];
	var oLine = this.Lines[CurLine];
	for (var CurRange = 0, RangesCount = oLine.Ranges.length; CurRange < RangesCount; ++CurRange)
	{
		var oRange = oLine.Ranges[CurRange];
		for (var CurPos = oRange.StartPos; CurPos <= oRange.EndPos; ++CurPos)
		{
			if (this.Content[CurPos].GetFootnoteRefsInRange)
				this.Content[CurPos].GetFootnoteRefsInRange(arrFootnotes, CurLine, CurRange);
		}
	}
	return arrFootnotes;
};
Paragraph.prototype.CheckParaEnd = function()
{
	// TODO (ParaEnd): Как избавимся от ParaEnd убрать эту проверку
	if (this.Content.length <= 0 || para_Run !== this.Content[this.Content.length - 1].Type || null === this.Content[this.Content.length - 1].GetParaEnd())
	{
		var oEndRun = new ParaRun(this);
		oEndRun.Set_Pr(this.TextPr.Value.Copy());
		oEndRun.Add_ToContent(0, new ParaEnd());
		this.Add_ToContent(this.Content.length, oEndRun);
	}
};
Paragraph.prototype.GetLineEndPos = function(CurLine)
{
	if (CurLine < 0 || CurLine >= this.Lines.length)
		return new CParagraphContentPos();

	var oLine = this.Lines[CurLine];
	if (!oLine || oLine.Ranges.length <= 0)
		return new CParagraphContentPos();

	return this.Get_EndRangePos2(CurLine, oLine.Ranges.length - 1);
};
Paragraph.prototype.CheckCommentStartEnd = function(sCommentId)
{
	var oResult = {Start : false, End : false};
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		var oElement = this.Content[nIndex];
		if (para_Comment === oElement.Type && sCommentId === oElement.GetCommentId())
		{
			if (oElement.IsCommentStart())
				oResult.Start = true;
			else
				oResult.End = true;
		}
	}

	return oResult;
};
Paragraph.prototype.IsColumnBreakOnLeft = function()
{
	var oRunElementsBefore = new CParagraphRunElements(this.Get_ParaContentPos(this.Selection.Use, false, false), 1, null);
	this.GetPrevRunElements(oRunElementsBefore);

	var arrElements = oRunElementsBefore.Elements;
	if (arrElements
		&& 1 === arrElements.length
		&& para_NewLine === arrElements[0].Type
		&& true === arrElements[0].IsColumnBreak())
		return true;

	return false;
};
Paragraph.prototype.Can_CopyCut = function()
{
	return true;
};
Paragraph.prototype.CanUpdateTarget = function(CurPage)
{
	if (this.Pages.length <= 0)
		return false;

	if (this.Pages.length <= CurPage)
		return true;

	if (!this.Pages[CurPage] || !this.Lines[this.Pages[CurPage].EndLine] || !this.Lines[this.Pages[CurPage].EndLine].Ranges.length <= 0)
		return false;

	var nPos = (this.IsSelectionUse() ? this.Selection.EndPos : this.CurPos.ContentPos);

	var oLastLine  = this.Lines[this.Pages[CurPage]];
	var oLastRange = oLastLine.Ranges[oLastLine.Ranges.length - 1];

	if (oLastRange.EndPos > nPos)
		return true;

	return false;
};
Paragraph.prototype.IsInDrawing = function(X, Y, CurPage)
{
	return false;
};
Paragraph.prototype.IsTableBorder = function(X, Y, CurPage)
{
	return null;
};
Paragraph.prototype.GetNumberingInfo = function(oNumberingEngine)
{
	if (!oNumberingEngine || oNumberingEngine.IsStop())
		return;

	oNumberingEngine.CheckParagraph(this);
};
Paragraph.prototype.ClearParagraphFormatting = function(isClearParaPr, isClearTextPr)
{
	if (isClearParaPr
		&& (!this.IsSelectionUse()
		|| this.IsSelectedAll()
		|| !this.Parent.IsSelectedSingleElement()))
	{
		this.Clear_Formatting();
	}

	if (isClearTextPr)
	{
		var oParaTextPr = new ParaTextPr();
		oParaTextPr.Value.Set_FromObject(new CTextPr(), true);

		// Highlight и Lang не сбрасываются при очистке текстовых настроек
		oParaTextPr.Value.Lang      = undefined;
		oParaTextPr.Value.HighLight = undefined;

		this.Add(oParaTextPr);
	}
};
Paragraph.prototype.SetParagraphAlign = function(Align)
{
	this.Set_Align(Align);
};
Paragraph.prototype.SetParagraphDefaultTabSize = function(TabSize)
{
	this.Set_DefaultTabSize(TabSize);
};
Paragraph.prototype.SetParagraphSpacing = function(Spacing)
{
	this.Set_Spacing(Spacing, false);
};
Paragraph.prototype.SetParagraphTabs = function(Tabs)
{
	this.Set_Tabs(Tabs);
};
Paragraph.prototype.GetParagraphTabs = function()
{
	return this.Get_CompiledPr2(false).ParaPr.Tabs;
};
Paragraph.prototype.SetParagraphIndent = function(Ind)
{
	var NumPr = this.GetNumPr();
	if (undefined !== Ind.ChangeLevel && 0 !== Ind.ChangeLevel && undefined !== NumPr)
	{
		if (Ind.ChangeLevel > 0)
			this.ApplyNumPr(NumPr.NumId, Math.min(8, NumPr.Lvl + 1));
		else
			this.ApplyNumPr(NumPr.NumId, Math.max(0, NumPr.Lvl - 1));
	}
	else
	{
		this.Set_Ind(Ind, false);
	}
};
Paragraph.prototype.SetParagraphShd = function(Shd)
{
	return this.Set_Shd(Shd);
};
Paragraph.prototype.SetParagraphStyle = function(Name)
{
	if (!this.LogicDocument)
		return;

	var StyleId = this.LogicDocument.Get_Styles().GetStyleIdByName(Name, true);
	this.Style_Add(StyleId);
};
Paragraph.prototype.GetParagraphStyle = function()
{
	return this.Style_Get();
};
Paragraph.prototype.SetParagraphStyleById = function(sStyleId)
{
	this.Style_Add(sStyleId);
};
Paragraph.prototype.SetParagraphContextualSpacing = function(Value)
{
	this.Set_ContextualSpacing(Value);
};
Paragraph.prototype.SetParagraphPageBreakBefore = function(Value)
{
	this.Set_PageBreakBefore(Value);
};
Paragraph.prototype.SetParagraphKeepLines = function(Value)
{
	this.Set_KeepLines(Value);
};
Paragraph.prototype.SetParagraphKeepNext = function(Value)
{
	this.Set_KeepNext(Value);
};
Paragraph.prototype.SetParagraphWidowControl = function(Value)
{
	this.Set_WidowControl(Value);
};
Paragraph.prototype.SetParagraphBorders = function(Borders)
{
	this.Set_Borders(Borders);
};
Paragraph.prototype.IncreaseDecreaseFontSize = function(bIncrease)
{
	this.IncDec_FontSize(bIncrease);
};
Paragraph.prototype.GetCurrentParagraph = function(bIgnoreSelection, arrSelectedParagraphs)
{
	if (arrSelectedParagraphs)
		arrSelectedParagraphs.push(this);

	return this;
};
Paragraph.prototype.Get_FirstParagraph = function()
{
	return this;
};
Paragraph.prototype.GetAllContentControls = function(arrContentControls)
{
	if (!arrContentControls)
		arrContentControls = [];

	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		if (this.Content[nIndex].GetAllContentControls)
			this.Content[nIndex].GetAllContentControls(arrContentControls);
	}

	return arrContentControls;
};
Paragraph.prototype.GetTargetPos = function()
{
	return this.Internal_Recalculate_CurPos(this.CurPos.ContentPos, false, false, true);
};
Paragraph.prototype.GetSelectedContentControls = function()
{
	var arrContentControls = [];

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (StartPos > EndPos)
		{
			StartPos = this.Selection.EndPos;
			EndPos   = this.Selection.StartPos;
		}

		for (var Index = StartPos; Index <= EndPos; ++Index)
		{
			if (this.Content[Index].GetSelectedContentControls)
				this.Content[Index].GetSelectedContentControls(arrContentControls);
		}
	}
	else
	{
		if (this.Content[this.CurPos.ContentPos] && this.Content[this.CurPos.ContentPos].GetSelectedContentControls)
			this.Content[this.CurPos.ContentPos].GetSelectedContentControls(arrContentControls);
	}

	return arrContentControls;
};
Paragraph.prototype.AddContentControl = function(nContentControlType)
{
	if (c_oAscSdtLevelType.Inline !== nContentControlType)
		return null;

	if (true === this.IsSelectionUse())
	{
		if (this.Selection.StartPos === this.Selection.EndPos && para_Run !== this.Content[this.Selection.StartPos].Type)
		{
			if (this.Content[this.Selection.StartPos].AddContentControl)
				return this.Content[this.Selection.StartPos].AddContentControl();

			return null;
		}
		else
		{
			var nStartPos = this.Selection.StartPos;
			var nEndPos   = this.Selection.EndPos;
			if (nEndPos < nStartPos)
			{
				nStartPos = this.Selection.EndPos;
				nEndPos   = this.Selection.StartPos;
			}

			for (var nIndex = nStartPos; nIndex <= nEndPos; ++nIndex)
			{
				if (para_Run !== this.Content[nIndex].Type)
				{
					// TODO: Вывести сообщение, что в данном месте нельзя добавить Plain text content control
					return null;
				}
			}

			// TODO: ParaEnd
			if (nEndPos === this.Content.length - 1)
			{
				nEndPos--;
				this.Content[this.Content.length - 1].RemoveSelection();
			}

			var oContentControl = new CInlineLevelSdt();

			if (nEndPos < nStartPos)
			{
				this.Add_ToContent(nStartPos, oContentControl);
				oContentControl.Add_ToContent(0, new ParaRun(this));
				this.Selection.StartPos = nStartPos;
				this.Selection.EndPos   = nStartPos;
			}
			else
			{
				var oNewRun = this.Content[nEndPos].Split_Run(Math.max(this.Content[nEndPos].Selection.StartPos, this.Content[nEndPos].Selection.EndPos));
				this.Add_ToContent(nEndPos + 1, oNewRun);

				oNewRun = this.Content[nStartPos].Split_Run(Math.min(this.Content[nStartPos].Selection.StartPos, this.Content[nStartPos].Selection.EndPos));
				this.Add_ToContent(nStartPos + 1, oNewRun);

				for (var nIndex = nEndPos + 1; nIndex >= nStartPos + 1; --nIndex)
				{
					oContentControl.Add_ToContent(0, this.Content[nIndex]);
					this.Remove_FromContent(nIndex, 1);
				}
				this.Add_ToContent(nStartPos + 1, oContentControl);
				this.Selection.StartPos = nStartPos + 1;
				this.Selection.EndPos   = nStartPos + 1;
			}

			oContentControl.MoveCursorToStartPos();
			oContentControl.SelectAll(1);
			return oContentControl;
		}
	}
	else
	{

		var oContentControl = new CInlineLevelSdt();
		oContentControl.Add_ToContent(0, new ParaRun());
		this.Add(oContentControl);

		var oContentControlPos = this.Get_PosByElement(oContentControl);
		if (oContentControlPos)
		{
			oContentControl.Get_StartPos(oContentControlPos, oContentControlPos.Get_Depth() + 1);
			this.Set_ParaContentPos(oContentControlPos, false, -1, -1);
		}

		return oContentControl;
	}
};
Paragraph.prototype.GetCurrentComplexFields = function(bReturnFieldPos)
{
	var arrComplexFields = [];

	var oInfo = this.GetEndInfoByPage(-1);
	if (oInfo)
	{
		for (var nIndex = 0, nCount = oInfo.ComplexFields.length; nIndex < nCount; ++nIndex)
		{
			var oComplexField = oInfo.ComplexFields[nIndex].ComplexField;
			if (oComplexField.IsUse())
			{
				if (bReturnFieldPos)
					arrComplexFields.push(oInfo.ComplexFields[nIndex]);
				else
					arrComplexFields.push(oComplexField);
			}
		}
	}

	var nEndPos = Math.min(this.CurPos.ContentPos, this.Content.length - 1);
	for (var nIndex = 0; nIndex <= nEndPos; ++nIndex)
	{
		if (this.Content[nIndex].GetCurrentComplexFields)
			this.Content[nIndex].GetCurrentComplexFields(arrComplexFields, nIndex === nEndPos, bReturnFieldPos);
	}

	return arrComplexFields;
};
Paragraph.prototype.GetComplexFieldsByPos = function(oParaPos, bReturnFieldPos)
{
	var nLine  = this.CurPos.Line;
	var nRange = this.CurPos.Range;

	var oCurrentPos = this.Get_ParaContentPos(false);
	this.Set_ParaContentPos(oParaPos, false, -1, -1, false);
	var arrComplexFields = this.GetCurrentComplexFields(bReturnFieldPos);
	this.Set_ParaContentPos(oCurrentPos, false, nLine, nRange, false);
	return arrComplexFields;
};
Paragraph.prototype.GetComplexFieldsByXY = function(X, Y, CurPage, bReturnFieldPos)
{
	var SearchPosXY = this.Get_ParaContentPosByXY(X, Y, CurPage, false, false);
	return this.GetComplexFieldsByPos(SearchPosXY.Pos, bReturnFieldPos);
};
Paragraph.prototype.GetOutlineParagraphs = function(arrOutline, oPr)
{
	if (this.IsEmpty({SkipNewLine : true, SkipComplexFields : true}) && (!oPr || false !== oPr.SkipEmptyParagraphs))
		return;

	var nOutlineLvl = this.GetOutlineLvl();
	if (undefined !== nOutlineLvl
		&& (!oPr
		|| -1 === oPr.OutlineStart
		|| -1 === oPr.OutlineEnd
		|| undefined === oPr.OutlineStart
		|| undefined === oPr.OutlineEnd
		|| (nOutlineLvl >= oPr.OutlineStart - 1 && nOutlineLvl <= oPr.OutlineEnd - 1)))
	{
		arrOutline.push({Paragraph : this, Lvl : nOutlineLvl});
	}
	else if (oPr && oPr.Styles && oPr.Styles.length > 0)
	{
		var oStyle = this.LogicDocument.Get_Styles().Get(this.Style_Get());
		if (!oStyle)
			return;

		var sStyleName = oStyle.Get_Name();

		for (var nIndex = 0, nCount = oPr.Styles.length; nIndex < nCount; ++nIndex)
		{
			if (oPr.Styles[nIndex].Name === sStyleName)
				return arrOutline.push({Paragraph : this, Lvl : oPr.Styles[nIndex].Lvl - 1});
		}
	}

	if (oPr && oPr.SkipDrawings)
		return;

	var arrDrawings = this.GetAllDrawingObjects();
	for (var nDrIndex = 0, nDrCount = arrDrawings.length; nDrIndex < nDrCount; ++nDrIndex)
	{
		var arrContents = arrDrawings[nDrIndex].GetAllDocContents();
		for (var nContentIndex = 0, nContentsCount = arrContents.length; nContentIndex < nContentsCount; ++nContentIndex)
		{
			arrContents[nContentIndex].GetOutlineParagraphs(arrOutline, oPr);
		}
	}
};
Paragraph.prototype.UpdateBookmarks = function(oManager)
{
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		this.Content[nIndex].UpdateBookmarks(oManager);
	}
};
Paragraph.prototype.GetSimilarNumbering = function(oContinueEngine)
{
	if (oContinueEngine.IsFound())
		return;

	oContinueEngine.CheckParagraph(this);
};
Paragraph.prototype.private_CheckUpdateBookmarks = function(Items)
{
	if (!Items)
		return;

	for (var nIndex = 0, nCount = Items.length; nIndex < nCount; ++nIndex)
	{
		if (para_Bookmark === Items[nIndex].Type)
		{
			this.LogicDocument.GetBookmarksManager().SetNeedUpdate(true);
			return;
		}
	}
};
Paragraph.prototype.GetTableOfContents = function(isUnique, isCheckFields)
{
	if (true !== isCheckFields)
		return null;

	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		var oResult = this.Content[nIndex].GetComplexField(fieldtype_TOC);
		if (oResult)
			return oResult;
	}

	return null;
};
Paragraph.prototype.GetComplexFieldsArrayByType = function(nType)
{
	var arrComplexFields = [];
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		this.Content[nIndex].GetComplexFieldsArray(nType, arrComplexFields);
	}

	return arrComplexFields;
};
Paragraph.prototype.AddBookmarkForTOC = function()
{
	if (!this.LogicDocument)
		return;

	var oBookmarksManager = this.LogicDocument.GetBookmarksManager();

	var sId   = oBookmarksManager.GetNewBookmarkId();
	var sName = oBookmarksManager.GetNewBookmarkNameTOC();

	this.Add_ToContent(0, new CParagraphBookmark(true, sId, sName));
	this.Add_ToContent(this.Content.length - 1, new CParagraphBookmark(false, sId, sName));

	this.Correct_Content();

	return sName;
};
Paragraph.prototype.AddBookmarkChar = function(oBookmarkChar, isUseSelection, isStartSelection)
{
	var oParaPos   = this.Get_ParaContentPos(isUseSelection, isStartSelection, false);
	var arrClasses = this.Get_ClassesByPos(oParaPos);

	var oRun, oParent;
	if (1 === arrClasses.length && arrClasses[arrClasses.length - 1].Type === para_Run)
	{
		oRun    = arrClasses[arrClasses.length - 1];
		oParent = this;
	}
	else if (arrClasses.length >= 2 && arrClasses[arrClasses.length - 1].Type === para_Run)
	{
		oRun    = arrClasses[arrClasses.length - 1];
		oParent = arrClasses[arrClasses.length - 2];
	}
	else
	{
		return false;
	}

	var oRunPos = oParaPos.Get(oParaPos.Get_Depth() - 1);
	oRun.Split2(oParaPos.Get(oParaPos.Get_Depth()), oParent, oRunPos);
	oParent.Add_ToContent(oRunPos + 1, oBookmarkChar);

	return true;
};
/**
 * Добавляем закладку привязанную к началу данного параграфа
 * @param {string} sBookmarkName
 */
Paragraph.prototype.AddBookmarkAtBegin = function(sBookmarkName)
{
	if (!this.LogicDocument)
		return;

	var oBookmarksManager = this.LogicDocument.GetBookmarksManager();

	var sId = oBookmarksManager.GetNewBookmarkId();

	this.Add_ToContent(0, new CParagraphBookmark(true, sId, sBookmarkName));
	this.Add_ToContent(1, new CParagraphBookmark(false, sId, sBookmarkName));

	this.Correct_Content();
};
/**
 * Проверяем есть ли у нас в заданной точке сложное поле типа PAGEREF с флагом hyperlink = true
 * @param X
 * @param Y
 * @param CurPage
 * @returns {?CComplexField}
 */
Paragraph.prototype.CheckPageRefLink = function(X, Y, CurPage)
{
	var arrComplexFields = this.GetComplexFieldsByXY(X, Y, CurPage);
	for (var nIndex = 0, nCount = arrComplexFields.length; nIndex < nCount; ++nIndex)
	{
		var oComplexField = arrComplexFields[nIndex];
		var oInstruction  = oComplexField.GetInstruction();
		if (oInstruction && fieldtype_PAGEREF === oInstruction.GetType() && oInstruction.IsHyperlink())
			return oComplexField;
	}

	return null;
};
/**
 * Получаем абсолютное значение первой не пустой страницы
 * @returns {number}
 */
Paragraph.prototype.GetFirstNonEmptyPageAbsolute = function()
{
	var nPagesCount = this.Pages.length;
	var nCurPage    = 0;

	while (this.IsEmptyPage(nCurPage, true))
	{
		if (nCurPage >= nPagesCount - 1)
			break;

		nCurPage++;
	}

	return this.Get_AbsolutePage(nCurPage);
};
/**
 * Удаляем все кроме первого таба в параграфе.
 * @returns {boolean} Был ли хоть один таб
 */
Paragraph.prototype.RemoveTabsForTOC = function()
{
	var isTab = false;
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		if (this.Content[nIndex].RemoveTabsForTOC(isTab))
			isTab = true;
	}

	return isTab;
};
/**
 * Проверяем лежит ли данный параграф в таблице
 * @returns {boolean}
 */
Paragraph.prototype.IsTableCellContent = function()
{
	return (this.Parent && this.Parent.IsTableCellContent() ? true : false);
};
/**
 * Получаем элемент содержимого параграфа
 * @param nIndex
 * @returns {?CParagraphContentBase}
 */
Paragraph.prototype.GetElement = function(nIndex)
{
	if (nIndex < 0 || nIndex >= this.Content.length)
		return null;

	return this.Content[nIndex];
};
/**
 * Получаем количество элементов содержимого параграфа
 * @returns {Number}
 */
Paragraph.prototype.GetElementsCount = function()
{
	// TODO: (ParaEnd) Возвращаем -1, т.к. последний ParaRun используется только для знака конца параграфа
	return this.Content.length - 1;
};
/**
 * Проверяем произошло ли простое изменение параграфа, сейчас это только добавление/удаление комментариев.
 * (можно не в массиве).
 */
Paragraph.prototype.IsParagraphSimpleChanges = function(_Changes)
{
	var Changes = _Changes;
	if (!_Changes.length)
		Changes = [_Changes];

	var ChangesCount = Changes.length;
	for (var ChangesIndex = 0; ChangesIndex < ChangesCount; ChangesIndex++)
	{
		var Data = Changes[ChangesIndex].Data;
		if (!Data.IsParagraphSimpleChanges())
			return false;
	}

	return true;
};
/**
 * Получаем скомпилированные настройки символа конца параграфа
 * @returns {CTextPr}
 */
Paragraph.prototype.GetParaEndCompiledPr = function()
{
	var oLogicDocument = this.bFromDocument ? this.LogicDocument : null;

	var oTextPr = this.Get_CompiledPr2(false).TextPr.Copy();
	if (oLogicDocument && undefined !== this.TextPr.Value.RStyle)
	{
		var oStyles = oLogicDocument.GetStyles();
		if (this.TextPr.Value.RStyle !== oStyles.GetDefaultHyperlink())
		{
			var oStyleTextPr = oStyles.Get_Pr(this.TextPr.Value.RStyle, styletype_Character).TextPr;
			oTextPr.Merge(oStyleTextPr);
		}
	}

	oTextPr.Merge(this.TextPr.Value);
	return oTextPr;
};
Paragraph.prototype.GetLastParagraph = function()
{
	return this;
};
Paragraph.prototype.GetFirstParagraph = function()
{
	return this;
};
/**
 * @returns {CParaSpellChecker}
 */
Paragraph.prototype.GetSpellChecker = function()
{
	return this.SpellChecker;
};
/**
 * Получаем номер страницы, на которой расположена нумерация
 * @param {boolean} isAbsolute возвращаем абсолютный номер страницы или нет
 * @returns {number}
 */
Paragraph.prototype.GetNumberingPage = function(isAbsolute)
{
	if (!this.HaveNumbering())
		return 0;

	return isAbsolute ? this.GetAbsolutePage(this.Numbering.Page) : this.Numbering.Page;
};
/**
 * Получаем рассчитанное значение для нумерованного списка
 * @returns {number} -1 - либо списка нет у данного параграфа, либо данный параграф не был рассчитан
 */
Paragraph.prototype.GetNumberingCalculatedValue = function()
{
	return this.Numbering.GetCalculatedValue();
};

var pararecalc_0_All  = 0;
var pararecalc_0_None = 1;

var pararecalc_0_Spell_All  = 0;
var pararecalc_0_Spell_Pos  = 1;
var pararecalc_0_Spell_Lang = 2;
var pararecalc_0_Spell_None = 3;

function CParaRecalcInfo()
{
    this.Recalc_0_Type = pararecalc_0_All;
    this.Recalc_0_Spell =
    {
        Type      : pararecalc_0_All,
        StartPos  : 0,
        EndPos    : 0
    };
}

CParaRecalcInfo.prototype =
{
    Set_Type_0 : function(Type)
    {
        this.Recalc_0_Type = Type;
    },

    Set_Type_0_Spell : function(Type, StartPos, EndPos)
    {
        if ( pararecalc_0_Spell_All === this.Recalc_0_Spell.Type )
            return;
        else if ( pararecalc_0_Spell_None === this.Recalc_0_Spell.Type || pararecalc_0_Spell_Lang === this.Recalc_0_Spell.Type )
        {
            this.Recalc_0_Spell.Type = Type;
            if ( pararecalc_0_Spell_Pos === Type )
            {
                this.Recalc_0_Spell.StartPos = StartPos;
                this.Recalc_0_Spell.EndPos   = EndPos;
            }
        }
        else if ( pararecalc_0_Spell_Pos === this.Recalc_0_Spell.Type )
        {
            if ( pararecalc_0_Spell_All === Type )
                this.Recalc_0_Spell.Type = Type;
            else if ( pararecalc_0_Spell_Pos === Type )
            {
                this.Recalc_0_Spell.StartPos = Math.min( StartPos, this.Recalc_0_Spell.StartPos );
                this.Recalc_0_Spell.EndPos   = Math.max( EndPos,   this.Recalc_0_Spell.EndPos   );
            }
        }
    },

    Update_Spell_OnChange : function(Pos, Count, bAdd)
    {
        if ( pararecalc_0_Spell_Pos === this.Recalc_0_Spell.Type )
        {
            if ( true === bAdd )
            {
                if ( this.Recalc_0_Spell.StartPos > Pos )
                    this.Recalc_0_Spell.StartPos++;

                if ( this.Recalc_0_Spell.EndPos >= Pos )
                    this.Recalc_0_Spell.EndPos++;
            }
            else
            {
                if ( this.Recalc_0_Spell.StartPos > Pos )
                {
                    if ( this.Recalc_0_Spell.StartPos > Pos + Count )
                        this.Recalc_0_Spell.StartPos -= Count;
                    else
                        this.Recalc_0_Spell.StartPos = Pos;
                }

                if ( this.Recalc_0_Spell.EndPos >= Pos )
                {
                    if ( this.Recalc_0_Spell.EndPos >= Pos + Count )
                        this.Recalc_0_Spell.EndPos -= Count;
                    else
                        this.Recalc_0_Spell.EndPos = Math.max( 0, Pos - 1 );
                }
            }
        }
    }
};

function CDocumentBounds(Left, Top, Right, Bottom)
{
    this.Bottom = Bottom;
    this.Left   = Left;
    this.Right  = Right;
    this.Top    = Top;
}

CDocumentBounds.prototype.CopyFrom = function(Bounds)
{
    if (!Bounds)
        return;

    this.Bottom = Bounds.Bottom;
    this.Left   = Bounds.Left;
    this.Right  = Bounds.Right;
    this.Top    = Bounds.Top;
};
CDocumentBounds.prototype.Shift = function(Dx, Dy)
{
    this.Bottom += Dy;
    this.Top    += Dy;
    this.Left   += Dx;
    this.Right  += Dx;
};
CDocumentBounds.prototype.Compare = function(Other)
{
    if (Math.abs(Other.Bottom - this.Bottom) > 0.001 || Math.abs(Other.Top - this.Top) > 0.001 || Math.abs(Other.Left - this.Left) > 0.001 || Math.abs(Other.Right - this.Right))
        return false;

    return true;
};
CDocumentBounds.prototype.Reset = function()
{
    this.Bottom = 0;
    this.Left   = 0;
    this.Right  = 0;
    this.Top    = 0;
};
CDocumentBounds.prototype.Copy = function()
{
	return new CDocumentBounds(this.Left, this.Top, this.Right, this.Bottom);
};

function CParagraphPageEndInfo()
{
    this.Comments      = []; // Массив незакрытых комментариев на данной странице
	this.ComplexFields = []; // Массив незакрытых полей на данной странице

    this.RunRecalcInfo = null;
}
CParagraphPageEndInfo.prototype.Copy = function()
{
	var oInfo = new CParagraphPageEndInfo();

	for (var nIndex = 0, nCount = this.Comments.length; nIndex < nCount; ++nIndex)
	{
		oInfo.Comments.push(this.Comments[nIndex]);
	}

	for (var nIndex = 0, nCount = this.ComplexFields.length; nIndex < nCount; ++nIndex)
	{
		if (this.ComplexFields[nIndex].ComplexField.IsUse())
			oInfo.ComplexFields.push(this.ComplexFields[nIndex].Copy());
	}

	return oInfo;
};
CParagraphPageEndInfo.prototype.SetFromPRSI = function(PRSI)
{
	this.Comments      = PRSI.Comments;
	this.ComplexFields = PRSI.ComplexFields;
};
CParagraphPageEndInfo.prototype.GetComplexFields = function()
{
	var arrComplexFields = [];
	for (var nIndex = 0, nCount = this.ComplexFields.length; nIndex < nCount; ++nIndex)
	{
		arrComplexFields[nIndex] = this.ComplexFields[nIndex].Copy();
	}
	return arrComplexFields;
};

function CParaPos(Range, Line, Page, Pos)
{
    this.Range = Range; // Номер промежутка в строке
    this.Line  = Line;  // Номер строки
    this.Page  = Page;  // Номер страницы
    this.Pos   = Pos;   // Позиция в общем массиве
}


// используется в Internal_Draw_3 и Internal_Draw_5
function CParaDrawingRangeLinesElement(y0, y1, x0, x1, w, r, g, b, Additional, Additional2)
{
    this.y0 = y0;
    this.y1 = y1;
    this.x0 = x0;
    this.x1 = x1;
    this.w  = w;
    this.r  = r;
    this.g  = g;
    this.b  = b;

    this.Additional = Additional;
    this.Additional2 = Additional2;
}


function CParaDrawingRangeLines()
{
    this.Elements = [];
}

CParaDrawingRangeLines.prototype =
{
    Clear : function()
    {
        this.Elements = [];
    },

    Add : function (y0, y1, x0, x1, w, r, g, b, Additional, Additional2)
    {
        this.Elements.push( new CParaDrawingRangeLinesElement(y0, y1, x0, x1, w, r, g, b, Additional, Additional2) );
    },

    Get_Next : function()
    {
        var Count = this.Elements.length;
        if ( Count <= 0 )
            return null;

        // Соединяем, начиная с конца, чтобы проще было обрезать массив
        var Element = this.Elements[Count - 1];
        Count--;

        while ( Count > 0 )
        {
            var PrevEl = this.Elements[Count - 1];

            if (this.private_CanUnionElements(PrevEl, Element))
            {
                Element.x0 = PrevEl.x0;
                Count--;
            }
            else
                break;
        }

        this.Elements.length = Count;

        return Element;
    },

    Get_NextForward : function()
    {
        var Count = this.Elements.length;
        if (Count <= 0)
            return null;

        var Element = this.Elements[0];
        var Pos = 1;

        while (Pos < Count)
        {
            var NextEl = this.Elements[Pos];

            if (this.private_CanUnionElements(NextEl, Element))
            {
                Element.x1 = NextEl.x1;
                Pos++;
            }
            else
                break;
        }

        this.Elements.splice(0, Pos);
        return Element;
    },

    private_CanUnionElements : function(PrevEl, Element)
	{
		if (Math.abs(PrevEl.y0 - Element.y0) < 0.001
			&& Math.abs(PrevEl.y1 - Element.y1) < 0.001
			&& Math.abs(PrevEl.x1 - Element.x0) < 0.001
			&& Math.abs(PrevEl.w - Element.w) < 0.001
			&& PrevEl.r === Element.r
			&& PrevEl.g === Element.g
			&& PrevEl.b === Element.b)
		{
			if (undefined === PrevEl.Additional && undefined === Element.Additional)
				return true;

			if (undefined === PrevEl.Additional || undefined === Element.Additional)
				return false;

			if (undefined !== PrevEl.Additional.Active && PrevEl.Additional.Active === Element.Additional.Active)
			{
				if (!PrevEl.Additional.CommentId
					|| !Element.Additional.CommentId
					|| PrevEl.Additional.CommentId.length !== Element.Additional.CommentId.length)
					return false;

				for (var nIndex = 0, nCount = PrevEl.Additional.CommentId.length; nIndex < nCount; ++nIndex)
				{
					if (PrevEl.Additional.CommentId[nIndex] !== Element.Additional.CommentId[nIndex])
						return false;
				}

				return true;
			}
			else if (undefined !== PrevEl.Additional.RunPr && true === Element.Additional.RunPr.Is_Equal(PrevEl.Additional.RunPr))
			{
				return true;
			}

			return false;
		}

		return false;
	},

    Correct_w_ForUnderline : function()
    {
        var Count = this.Elements.length;
        if ( Count <= 0 )
            return;

        var CurElements = [];
        for ( var Index = 0; Index < Count; Index++ )
        {
            var Element = this.Elements[Index];
            var CurCount = CurElements.length;

            if ( 0 === CurCount )
                CurElements.push( Element );
            else
            {
                var PrevEl = CurElements[CurCount - 1];

                if ( Math.abs( PrevEl.y0 - Element.y0 ) < 0.001 && Math.abs( PrevEl.y1 - Element.y1 ) < 0.001 && Math.abs( PrevEl.x1 - Element.x0 ) < 0.001 )
                {
                    // Сравниваем толщины линий
                    if ( Element.w > PrevEl.w )
                    {
                        for ( var Index2 = 0; Index2 < CurCount; Index2++ )
                            CurElements[Index2].w = Element.w;
                    }
                    else
                        Element.w = PrevEl.w;

                    CurElements.push( Element );
                }
                else
                {
                    CurElements.length = 0;
                    CurElements.push( Element );
                }
            }
        }
    }
};

function CParagraphSelection()
{
    this.Start     = false;
    this.Use       = false;
    this.StartPos  = 0;
    this.EndPos    = 0;
    this.Flag      = selectionflag_Common;
    
    this.StartManually = true; // true - через Selection_SetStart, false - через Selection_SetBegEnd
    this.EndManually   = true; // true - через Selection_SetEnd, афдыу - через Selection_SetBegEnd  
}

CParagraphSelection.prototype =
{
    Set_StartPos : function(Pos1, Pos2)
    {
        this.StartPos  = Pos1;
    },

    Set_EndPos : function(Pos1, Pos2)
    {
        this.EndPos  = Pos1;
    }
};

function CParagraphContentPos()
{
    this.Data  = [0, 0, 0];
    this.Depth = 0;
    this.bPlaceholder = false;
}

CParagraphContentPos.prototype =
{
    Add : function (Pos)
    {
        this.Data[this.Depth] = Pos;
        this.Depth++;
    },

    Update : function(Pos, Depth)
    {
        this.Data[Depth] = Pos;
        this.Depth = Depth + 1;
    },

    Update2 : function(Pos, Depth)
    {
        this.Data[Depth] = Pos;
    },

    Set : function(OtherPos)
    {
        // Копируем позицию
        var Len = OtherPos.Depth;
        for ( var Pos = 0; Pos < Len; Pos++ )
            this.Data[Pos] = OtherPos.Data[Pos];

        this.Depth = OtherPos.Depth;

        if ( this.Data.length > this.Depth )
            this.Data.length = this.Depth;
    },

    Get : function(Depth)
    {
        return this.Data[Depth];
    },

    Get_Depth : function()
    {
        return this.Depth - 1;
    },

    Decrease_Depth : function(nCount)
    {
        this.Depth = Math.max(0, this.Depth - nCount);
    },

    Copy : function ()
    {
        var PRPos = new CParagraphContentPos();

        var Count = this.Data.length;
        for (var Index = 0; Index < Count; Index++)
        {
            PRPos.Add( this.Data[Index] );
        }

        PRPos.Depth = this.Depth;

        return PRPos;
    },

    Copy_FromDepth : function(ContentPos, Depth)
    {
        var Count = ContentPos.Data.length;
        for (var CurDepth = Depth; CurDepth < Count; CurDepth++)
        {
            this.Update2(ContentPos.Data[CurDepth], CurDepth);
        }

        this.Depth = ContentPos.Depth;
    },

    /**
     * Сравниваем текущую позицию с заданной.
     * @param {CParagraphContentPos} Pos
     * @returns {number} 0 - позиции совпадают, 1 - текущая позиция дальше заданной, -1 - текущая позиция до заданной.
     */
    Compare : function(Pos)
    {
        var CurDepth = 0;

        var Len1 = this.Data.length;
        var Len2 = Pos.Data.length;
        var LenMin = Math.min( Len1, Len2 );

        while ( CurDepth < LenMin )
        {
            if ( this.Data[CurDepth] === Pos.Data[CurDepth] )
            {
                // Если попали в один и тот же элемент, тогда проверяем далее
                CurDepth++;
                continue;
            }
            else if ( this.Data[CurDepth] > Pos.Data[CurDepth] )
                return 1;
            else //if ( this.Data[CurDepth] < Pos.Data[CurDepth] )
                return -1;
        }

        // Такого не должно быть, но на всякий случай пошлем, что позиции не совпадают
        if ( Len1 !== Len2 )
            return -1;

        return 0;
    }
};
/**
 * Получаем текущую глубину позиции
 * @returns {number}
 */
CParagraphContentPos.prototype.GetDepth = function()
{
	return this.Depth - 1;
};

function CComplexFieldStatePos(oComplexField, isFieldCode)
{
	this.FieldCode    = undefined !== isFieldCode ? isFieldCode : true;
	this.ComplexField = oComplexField ? oComplexField : null;
}
CComplexFieldStatePos.prototype.Copy = function()
{
	return new CComplexFieldStatePos(this.ComplexField, this.FieldCode);
};
CComplexFieldStatePos.prototype.SetFieldCode = function(isFieldCode)
{
	this.FieldCode = isFieldCode;
};
CComplexFieldStatePos.prototype.IsFieldCode = function()
{
	return this.FieldCode;
};

function CParagraphComplexFieldsInfo()
{
	// Массив CComplexFieldStatePos
	this.CF = [];

	this.isHidden = null;
}
CParagraphComplexFieldsInfo.prototype.ResetPage = function(Paragraph, CurPage)
{
	this.isHidden = null;

	var PageEndInfo = Paragraph.GetEndInfoByPage(CurPage - 1);

	if (PageEndInfo)
		this.CF = PageEndInfo.GetComplexFields();
	else
		this.CF = [];
};
/**
 * Находимся ли мы внутри содержимого скрытого поля
 * @returns {boolean}
 */
CParagraphComplexFieldsInfo.prototype.IsHiddenFieldContent = function()
{
	if (null === this.isHidden)
		this.isHidden = this.private_IsHiddenFieldContent();

	return this.isHidden;
};
CParagraphComplexFieldsInfo.prototype.private_IsHiddenFieldContent = function()
{
	if (this.CF.length > 0)
	{
		for (var nIndex = 0, nCount = this.CF.length; nIndex < nCount; ++nIndex)
		{
			if (this.CF[nIndex].ComplexField.IsHidden())
				return true;
		}
	}

	return false;
};
/**
 * Данная функция используется при пересчете, когда мы собираем сложное поле.
 * @param oChar
 */
CParagraphComplexFieldsInfo.prototype.ProcessFieldCharAndCollectComplexField = function(oChar)
{
	this.isHidden = null;

	if (oChar.IsBegin())
	{
		var oComplexField = oChar.GetComplexField();
		if (!oComplexField)
		{
			oChar.SetUse(false);
		}
		else
		{
			oChar.SetUse(true);
			oComplexField.SetBeginChar(oChar);
			this.CF.push(new CComplexFieldStatePos(oComplexField, true));
		}
	}
	else if (oChar.IsEnd())
	{
		if (this.CF.length > 0)
		{
			oChar.SetUse(true);
			var oComplexField = this.CF[this.CF.length - 1].ComplexField;
			oComplexField.SetEndChar(oChar);
			this.CF.splice(this.CF.length - 1, 1);
		}
		else
		{
			oChar.SetUse(false);
		}
	}
	else if (oChar.IsSeparate())
	{
		if (this.CF.length > 0)
		{
			oChar.SetUse(true);
			var oComplexField = this.CF[this.CF.length - 1].ComplexField;
			oComplexField.SetSeparateChar(oChar);
			this.CF[this.CF.length - 1].SetFieldCode(false);
		}
		else
		{
			oChar.SetUse(false);
		}
	}
};
/**
 * Данная функция используется, когда мы просто хотим отследить где мы находимся, относительно сложных полей
 * @param oChar
 */
CParagraphComplexFieldsInfo.prototype.ProcessFieldChar = function(oChar)
{
	this.isHidden = null;

	if (!oChar || !oChar.IsUse())
		return;

	var oComplexField = oChar.GetComplexField();

	if (oChar.IsBegin())
	{
		this.CF.push(new CComplexFieldStatePos(oComplexField, true));
	}
	else if (oChar.IsSeparate())
	{
		for (var nIndex = 0, nCount = this.CF.length; nIndex < nCount; ++nIndex)
		{
			if (oComplexField === this.CF[nIndex].ComplexField)
			{
				this.CF[nIndex].SetFieldCode(false);
				break;
			}
		}
	}
	else if (oChar.IsEnd())
	{
		for (var nIndex = 0, nCount = this.CF.length; nIndex < nCount; ++nIndex)
		{
			if (oComplexField === this.CF[nIndex].ComplexField)
			{
				this.CF.splice(nIndex, 1);
				break;
			}
		}
	}
};
CParagraphComplexFieldsInfo.prototype.ProcessInstruction = function(oInstruction)
{
	if (this.CF.length <= 0)
		return;

	var oComplexField = this.CF[this.CF.length - 1].ComplexField;
	if (oComplexField && null === oComplexField.GetSeparateChar())
		oComplexField.SetInstruction(oInstruction);
};
CParagraphComplexFieldsInfo.prototype.IsComplexField = function()
{
	return (this.CF.length > 0 ? true : false);
};
CParagraphComplexFieldsInfo.prototype.IsComplexFieldCode = function()
{
	if (!this.IsComplexField())
		return false;

	for (var nIndex = 0, nCount = this.CF.length; nIndex < nCount; ++nIndex)
	{
		if (this.CF[nIndex].IsFieldCode())
			return true;
	}

	return false;
};
CParagraphComplexFieldsInfo.prototype.IsCurrentComplexField = function()
{
	for (var nIndex = 0, nCount = this.CF.length; nIndex < nCount; ++nIndex)
	{
		if (this.CF[nIndex].ComplexField.IsCurrent())
			return true;
	}

	return false;
};
CParagraphComplexFieldsInfo.prototype.IsHyperlinkField = function()
{
	var isHaveHyperlink = false,
		isOtherField    = false;

	for (var nIndex = 0, nCount = this.CF.length; nIndex < nCount; ++nIndex)
	{
		var oInstruction = this.CF[nIndex].ComplexField.GetInstruction();
		if (oInstruction && fieldtype_HYPERLINK === oInstruction.GetType())
			isHaveHyperlink = true;
		else
			isOtherField = true;

	}

	return (isHaveHyperlink && !isOtherField ? true : false);
};

function CParagraphDrawStateHighlights()
{
    this.Page   = 0;
    this.Line   = 0;
    this.Range  = 0;

    this.CurPos = new CParagraphContentPos();

    this.DrawColl     = false;
    this.DrawMMFields = false;

    this.High     = new CParaDrawingRangeLines();
    this.Coll     = new CParaDrawingRangeLines();
    this.Find     = new CParaDrawingRangeLines();
    this.Comm     = new CParaDrawingRangeLines();
    this.Shd      = new CParaDrawingRangeLines();
    this.MMFields = new CParaDrawingRangeLines();
    this.CFields  = new CParaDrawingRangeLines();

	this.DrawComments       = true;
	this.DrawSolvedComments = true;
	this.Comments           = [];
	this.CommentsFlag       = comments_NoComment;

    this.SearchCounter = 0;

    this.Paragraph = undefined;
    this.Graphics  = undefined;

    this.X  = 0;
    this.Y0 = 0;
    this.Y1 = 0;

    this.Spaces = 0;

    this.InlineSdt = [];

    this.ComplexFields = new CParagraphComplexFieldsInfo();
}
CParagraphDrawStateHighlights.prototype.Reset = function(Paragraph, Graphics, DrawColl, DrawFind, DrawComments, DrawMMFields, PageEndInfo, DrawSolvedComments)
{
	this.Paragraph = Paragraph;
	this.Graphics  = Graphics;

	this.DrawColl     = DrawColl;
	this.DrawFind     = DrawFind;
	this.DrawMMFields = DrawMMFields;

	this.CurPos = new CParagraphContentPos();

	this.SearchCounter = 0;

	this.DrawComments       = DrawComments;
	this.DrawSolvedComments = DrawSolvedComments;

	this.Comments = [];
	if (null !== PageEndInfo)
	{
		for (var nIndex = 0, nCount = PageEndInfo.Comments.length; nIndex < nCount; ++nIndex)
		{
			this.AddComment(PageEndInfo.Comments[nIndex]);
		}
	}

	this.Check_CommentsFlag();
};
CParagraphDrawStateHighlights.prototype.Reset_Range = function(Page, Line, Range, X, Y0, Y1, SpacesCount)
{
	this.Page  = Page;
	this.Line  = Line;
	this.Range = Range;

	this.High.Clear();
	this.Coll.Clear();
	this.Find.Clear();
	this.Comm.Clear();

	this.X  = X;
	this.Y0 = Y0;
	this.Y1 = Y1;

	this.Spaces = SpacesCount;

	this.InlineSdt = [];
};
CParagraphDrawStateHighlights.prototype.AddInlineSdt = function(oSdt)
{
	this.InlineSdt.push(oSdt);
};
CParagraphDrawStateHighlights.prototype.AddComment = function(Id)
{
	if (!this.DrawComments)
		return;

	var oComment = AscCommon.g_oTableId.Get_ById(Id);
	if (!oComment || (!this.DrawSolvedComments && oComment.IsSolved()))
		return;

	this.Comments.push(Id);
	this.Check_CommentsFlag();
};
CParagraphDrawStateHighlights.prototype.RemoveComment = function(Id)
{
	if (!this.DrawComments)
		return;

	var oComment = AscCommon.g_oTableId.Get_ById(Id);
	if (!oComment || (!this.DrawSolvedComments && oComment.IsSolved()))
		return;

	for (var nIndex = 0, nCount = this.Comments.length; nIndex < nCount; ++nIndex)
	{
		if (this.Comments[nIndex] === Id)
		{
			this.Comments.splice(nIndex, 1);
			break;
		}
	}

	this.Check_CommentsFlag();
};
CParagraphDrawStateHighlights.prototype.Check_CommentsFlag = function()
{
	// Проверяем флаг
	var Para             = this.Paragraph;
	var DocumentComments = Para.LogicDocument.Comments;
	var CurComment       = DocumentComments.Get_CurrentId();
	var CommLen          = this.Comments.length;

	// Сначала проверим есть ли вообще комментарии
	this.CommentsFlag = ( CommLen > 0 ? comments_NonActiveComment : comments_NoComment );

	// Проверим является ли какой-либо комментарий активным
	for (var CurPos = 0; CurPos < CommLen; CurPos++)
	{
		if (CurComment === this.Comments[CurPos])
		{
			this.CommentsFlag = comments_ActiveComment;
			break
		}
	}
};
CParagraphDrawStateHighlights.prototype.Save_Coll = function()
{
	var Coll  = this.Coll;
	this.Coll = new CParaDrawingRangeLines();
	return Coll;
};
CParagraphDrawStateHighlights.prototype.Save_Comm = function()
{
	var Comm  = this.Comm;
	this.Comm = new CParaDrawingRangeLines();
	return Comm;
};
CParagraphDrawStateHighlights.prototype.Load_Coll = function(Coll)
{
	this.Coll = Coll;
};
CParagraphDrawStateHighlights.prototype.Load_Comm = function(Comm)
{
	this.Comm = Comm;
};

function CParagraphDrawStateElements()
{
    this.Paragraph = undefined;
    this.Graphics  = undefined;
    this.BgColor   = undefined;

    this.Theme     = undefined;
    this.ColorMap  = undefined;

    this.CurPos = new CParagraphContentPos();

    this.VisitedHyperlink = false;
    this.Hyperlink = false;

    this.Page   = 0;
    this.Line   = 0;
    this.Range  = 0;

    this.X = 0;
    this.Y = 0;

    this.LineTop    = 0;
    this.LineBottom = 0;
    this.BaseLine   = 0;

    this.ComplexFields = new CParagraphComplexFieldsInfo();
}

CParagraphDrawStateElements.prototype =
{
    Reset : function(Paragraph, Graphics, BgColor, Theme, ColorMap)
    {
        this.Paragraph = Paragraph;
        this.Graphics  = Graphics;
        this.BgColor   = BgColor;
        this.Theme     = Theme;
        this.ColorMap  = ColorMap;

        this.VisitedHyperlink = false;
        this.Hyperlink = false;

        this.CurPos = new CParagraphContentPos();
    },

    Reset_Range : function(Page, Line, Range, X, Y)
    {
        this.Page  = Page;
        this.Line  = Line;
        this.Range = Range;

        this.X = X;
        this.Y = Y;
    },

    Set_LineMetrics : function(BaseLine, Top, Bottom)
    {
        this.LineTop    = Top;
        this.LineBottom = Bottom;
        this.BaseLine   = BaseLine;
    }
};

function CParagraphDrawStateLines()
{
    this.Paragraph = undefined;
    this.Graphics  = undefined;
    this.BgColor   = undefined;

    this.CurPos   = new CParagraphContentPos();
    this.CurDepth = 0;

    this.VisitedHyperlink = false;
    this.Hyperlink = false;

    this.Strikeout  = new CParaDrawingRangeLines();
    this.DStrikeout = new CParaDrawingRangeLines();
    this.Underline  = new CParaDrawingRangeLines();
    this.Spelling   = new CParaDrawingRangeLines();
    this.RunReview  = new CParaDrawingRangeLines();
    this.CollChange = new CParaDrawingRangeLines();

    this.Page  = 0;
    this.Line  = 0;
    this.Range = 0;

    this.X               = 0;
    this.BaseLine        = 0;
    this.UnderlineOffset = 0;
    this.Spaces          = 0;

    this.ComplexFields = new CParagraphComplexFieldsInfo();
}

CParagraphDrawStateLines.prototype =
{
    Reset : function(Paragraph, Graphics, BgColor)
    {
        this.Paragraph = Paragraph;
        this.Graphics  = Graphics;
        this.BgColor   = BgColor;

        this.VisitedHyperlink = false;
        this.Hyperlink = false;

		this.CurPos   = new CParagraphContentPos();
		this.CurDepth = 0;
    },

    Reset_Line : function(Page, Line, Baseline, UnderlineOffset)
    {
        this.Page  = Page;
        this.Line  = Line;

        this.Baseline        = Baseline;
        this.UnderlineOffset = UnderlineOffset;

        this.Strikeout.Clear();
        this.DStrikeout.Clear();
        this.Underline.Clear();
        this.Spelling.Clear();
    },

    Reset_Range : function(Range, X, Spaces)
    {
        this.Range  = Range;
        this.X      = X;
        this.Spaces = Spaces;
    }
};
/**
 * Получаем количество орфографических ошибок в данном месте
 * @returns {number}
 */
CParagraphDrawStateLines.prototype.GetSpellingErrorsCounter = function()
{
	var nCounter = 0;
	var oSpellChecker = this.Paragraph.GetSpellChecker();
	for (var nIndex = 0, nCount = oSpellChecker.GetElementsCount(); nIndex < nCount; ++nIndex)
	{
		var oSpellElement = oSpellChecker.GetElement(nIndex);

		var oStartPos = oSpellElement.GetStartPos();
		var oEndPos   = oSpellElement.GetEndPos();

		if (this.CurPos.Compare(oStartPos) > 0 && this.CurPos.Compare(oEndPos) < 0)
			nCounter++;
	}

	return nCounter;
};

var g_oPDSH = new CParagraphDrawStateHighlights();
//var g_oPDSE = new CParagraphDrawStateElements();
var g_oPDSL = new CParagraphDrawStateLines();

//----------------------------------------------------------------------------------------------------------------------
// Классы для работы с курсором
//----------------------------------------------------------------------------------------------------------------------

// Общий класс для нахождения позиции курсора слева/справа/начала и конца слова и т.д.
function CParagraphSearchPos()
{
    this.Pos   = new CParagraphContentPos(); // Искомая позиция
    this.Found = false;                      // Нашли или нет

    this.Line  = -1;
    this.Range = -1;

    this.Stage       = 0; // Номера этапов для поиска начала и конца слова
    this.Shift       = false;
    this.Punctuation = false;
    this.First       = true;
    this.UpdatePos   = false;
    
    this.ForSelection = false;

    this.CheckAnchors = false;

    this.ComplexFields = [];
}
CParagraphSearchPos.prototype.SetCheckAnchors = function(bCheck)
{
	this.CheckAnchors = bCheck;
};
CParagraphSearchPos.prototype.IsCheckAnchors = function()
{
	return this.CheckAnchors;
};
CParagraphSearchPos.prototype.ProcessComplexFieldChar = function(nDirection, oFieldChar)
{
	if (!oFieldChar || !oFieldChar.IsUse())
		return;


	if (nDirection > 0)
	{
		var oComplexField = oFieldChar.GetComplexField();
		if (oFieldChar.IsBegin())
		{
			this.ComplexFields.push(new CComplexFieldStatePos(oComplexField, true));
		}
		else if (oFieldChar.IsSeparate())
		{
			for (var nIndex = 0, nCount = this.ComplexFields.length; nIndex < nCount; ++nIndex)
			{
				if (oComplexField === this.ComplexFields[nIndex].ComplexField)
				{
					this.ComplexFields[nIndex].SetFieldCode(false);
					break;
				}
			}
		}
		else if (oFieldChar.IsEnd())
		{
			for (var nIndex = 0, nCount = this.ComplexFields.length; nIndex < nCount; ++nIndex)
			{
				if (oComplexField === this.ComplexFields[nIndex].ComplexField)
				{
					this.ComplexFields.splice(nIndex, 1);
					break;
				}
			}
		}
	}
	else
	{
		var oComplexField = oFieldChar.GetComplexField();
		if (oFieldChar.IsEnd())
		{
			this.ComplexFields.push(new CComplexFieldStatePos(oComplexField, false));
		}
		else if (oFieldChar.IsSeparate())
		{
			for (var nIndex = 0, nCount = this.ComplexFields.length; nIndex < nCount; ++nIndex)
			{
				if (oComplexField === this.ComplexFields[nIndex].ComplexField)
				{
					this.ComplexFields[nIndex].SetFieldCode(true);
					break;
				}
			}
		}
		else if (oFieldChar.IsBegin())
		{
			for (var nIndex = 0, nCount = this.ComplexFields.length; nIndex < nCount; ++nIndex)
			{
				if (oComplexField === this.ComplexFields[nIndex].ComplexField)
				{
					this.ComplexFields.splice(nIndex, 1);
					break;
				}
			}
		}
	}
};
CParagraphSearchPos.prototype.InitComplexFields = function(arrComplexFields)
{
	this.ComplexFields = arrComplexFields;
};
CParagraphSearchPos.prototype.IsComplexField = function()
{
	return (this.ComplexFields.length > 0 ? true : false);
};
CParagraphSearchPos.prototype.IsComplexFieldCode = function()
{
	if (!this.IsComplexField())
		return false;

	for (var nIndex = 0, nCount = this.ComplexFields.length; nIndex < nCount; ++nIndex)
	{
		if (this.ComplexFields[nIndex].IsFieldCode())
			return true;
	}

	return false;
};
CParagraphSearchPos.prototype.IsComplexFieldValue = function()
{
	if (!this.IsComplexField() || this.IsComplexFieldCode())
		return false;

	return true;
};
CParagraphSearchPos.prototype.IsHiddenComplexField = function()
{
	for (var nIndex = 0, nCount = this.ComplexFields.length; nIndex < nCount; ++nIndex)
	{
		if (this.ComplexFields[nIndex].ComplexField.IsHidden())
			return true;
	}

	return false;
};

function CParagraphSearchPosXY()
{
    this.Pos       = new CParagraphContentPos();
    this.InTextPos = new CParagraphContentPos();

    this.CenterMode     = true; // Ищем ближайший (т.е. ориентируемся по центру элемента), или ищем именно прохождение через элемент
    this.CurX           = 0;
    this.CurY           = 0;
    this.X              = 0;
    this.Y              = 0;
    this.DiffX          = 1000000; // километра для ограничения должно хватить
    this.NumberingDiffX = 1000000; // километра для ограничения должно хватить

    this.Line      = 0;
    this.Range     = 0;

    this.InTextX   = false;
    this.InText    = false;
    this.Numbering = false;
    this.End       = false;
    this.Field     = null;
}

//----------------------------------------------------------------------------------------------------------------------
// Классы для работы с селектом
//----------------------------------------------------------------------------------------------------------------------
function CParagraphDrawSelectionRange()
{
    this.StartX    = 0;
    this.W         = 0;

    this.StartY    = 0;
    this.H         = 0;

    this.FindStart = true;
    this.Draw      = true;
}

//----------------------------------------------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------------------------------------------
function CParagraphCheckPageBreakEnd(PageBreak)
{
    this.PageBreak = PageBreak;
    this.FindPB    = true;
}

function CParagraphGetText()
{
    this.Text = "";

    this.BreakOnNonText = true;
    this.ParaEndToSpace = false;
}
CParagraphGetText.prototype.SetBreakOnNonText = function(bValue)
{
	this.BreakOnNonText = bValue;
};
CParagraphGetText.prototype.SetParaEndToSpace = function(bValue)
{
	this.ParaEndToSpace = bValue;
};

function CParagraphNearPos()
{
    this.NearPos = null;
    this.Classes = [];
}

function CParagraphElementNearPos()
{
    this.NearPos = null;
    this.Depth   = 0;
}

function CParagraphDrawingLayout(Drawing, Paragraph, X, Y, Line, Range, Page)
{
    this.Paragraph = Paragraph;
    this.Drawing   = Drawing;
    this.Line      = Line;
    this.Range     = Range;
    this.Page      = Page;
    this.X         = X;
    this.Y         = Y;
    this.LastW     = 0;

    this.Layout    = false;
}

function CParagraphGetDropCapText()
{
    this.Runs  = [];
    this.Text  = [];
    this.Mixed = false;
    this.Check = true;
}

//----------------------------------------------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------------------------------------------

function CRunRecalculateObject(StartLine, StartRange)
{
    this.StartLine   = StartLine;
    this.StartRange  = StartRange;
    this.Lines       = [];
    this.Content     = [];

    this.MathInfo    = null;
}

CRunRecalculateObject.prototype =
{
    Save_Lines : function(Obj, Copy)
    {
        if ( true === Copy )
        {
            var Lines = Obj.Lines;
            var Count = Obj.Lines.length;
            for ( var Index = 0; Index < Count; Index++ )
                this.Lines[Index] = Lines[Index];
        }
        else
        {
            this.Lines = Obj.Lines;
        }
    },

    Save_Content : function(Obj, Copy)
    {
        var Content = Obj.Content;
        var ContentLen = Content.length;
        for ( var Index = 0; Index < ContentLen; Index++ )
        {
            this.Content[Index] = Content[Index].SaveRecalculateObject(Copy);
        }
    },

    Save_MathInfo: function(Obj, Copy)
    {
        this.MathInfo = Obj.Save_MathInfo(Copy);
    },

    Load_Lines : function(Obj)
    {
        Obj.StartLine  = this.StartLine;
        Obj.StartRange = this.StartRange;
        Obj.Lines      = this.Lines;
    },

    Load_Content : function(Obj)
    {
        var Count = Obj.Content.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            Obj.Content[Index].LoadRecalculateObject( this.Content[Index] );
        }
    },

    Load_MathInfo: function(Obj)
    {
        Obj.Load_MathInfo(this.MathInfo);
    },

    Save_RunContent : function(Run, Copy)
    {
        var ContentLen = Run.Content.length;
        for ( var Index = 0, Index2 = 0; Index < ContentLen; Index++ )
        {
            var Item = Run.Content[Index];

			if (para_PageNum === Item.Type || para_Drawing === Item.Type || para_FieldChar === Item.Type)
				this.Content[Index2++] = Item.SaveRecalculateObject(Copy);
        }
    },

    Load_RunContent : function(Run)
    {
        var Count = Run.Content.length;
        for ( var Index = 0, Index2 = 0; Index < Count; Index++ )
        {
            var Item = Run.Content[Index];

			if (para_PageNum === Item.Type || para_Drawing === Item.Type || para_FieldChar === Item.Type)
				Item.LoadRecalculateObject(this.Content[Index2++]);
        }
    },

    Get_DrawingFlowPos : function(FlowPos)
    {
        var Count = this.Content.length;
        for ( var Index = 0, Index2 = 0; Index < Count; Index++ )
        {
            var Item = this.Content[Index];

            if ( para_Drawing === Item.Type && undefined !== Item.FlowPos )
                FlowPos.push( Item.FlowPos );
        }
    },

    Compare : function(_CurLine, _CurRange, OtherLinesInfo)
    {
        var OLI = para_Math === OtherLinesInfo.Type ? OtherLinesInfo.Root : OtherLinesInfo;

        if(para_Math === OtherLinesInfo.Type && OtherLinesInfo.CompareMathInfo(this.MathInfo) == false /*this.WrapState !== OtherLinesInfo.GetCurrentWrapState()*/)
        {
            return false;
        }

        var CurLine = _CurLine - this.StartLine;
        var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

        // Специальная заглушка для элементов типа комментария
        if ( ( 0 === this.Lines.length || 0 === this.LinesLength ) && ( 0 === OLI.Lines.length || 0 === OLI.LinesLength ) )
            return true;

        // заглушка для однострочных контентов
        if(OLI.Type == para_Math_Content && OLI.bOneLine == true)
            return true;

        if ( this.StartLine !== OLI.StartLine || this.StartRange !== OLI.StartRange || CurLine < 0 || CurLine >= this.private_Get_LinesCount() || CurLine >= OLI.protected_GetLinesCount() || CurRange < 0 || CurRange >= this.private_Get_RangesCount(CurLine) || CurRange >= OLI.protected_GetRangesCount(CurLine) )
            return false;


        var ThisSP = this.private_Get_RangeStartPos(CurLine, CurRange);
        var ThisEP = this.private_Get_RangeEndPos(CurLine, CurRange);

        var OtherSP = OLI.protected_GetRangeStartPos(CurLine, CurRange);
        var OtherEP = OLI.protected_GetRangeEndPos(CurLine, CurRange);

        if ( ThisSP !== OtherSP || ThisEP !== OtherEP )
            return false;

        if ( ( (OLI.Content === undefined || para_Run === OLI.Type || para_Math_Run === OLI.Type) && this.Content.length > 0 ) || ( OLI.Content !== undefined && para_Run !== OLI.Type && para_Math_Run !== OLI.Type && OLI.Content.length !== this.Content.length) )
            return false;

        var ContentLen = this.Content.length;
        var StartPos = ThisSP;
        var EndPos   = Math.min( ContentLen - 1, ThisEP );

        for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
        {
            if ( false === this.Content[CurPos].Compare( _CurLine, _CurRange, OLI.Content[CurPos] ) )
                return false;
        }

        return true;
    },
    
    private_Get_RangeOffset : function(LineIndex, RangeIndex)
    {
        return (1 + this.Lines[0] + this.Lines[1 + LineIndex] + RangeIndex * 2);
    },
    
    private_Get_RangeStartPos : function(LineIndex, RangeIndex)
    { 
        return this.Lines[this.private_Get_RangeOffset(LineIndex, RangeIndex)];
    },

    private_Get_RangeEndPos : function(LineIndex, RangeIndex)
    {
        return this.Lines[this.private_Get_RangeOffset(LineIndex, RangeIndex) + 1];
    },
    
    private_Get_LinesCount : function()
    {
        return this.Lines[0];
    },
    
    private_Get_RangesCount : function(LineIndex)
    {
        if (LineIndex === this.Lines[0] - 1)
            return (this.Lines.length - this.Lines[1 + LineIndex]) / 2;
        else
            return (this.Lines[1 + LineIndex + 1] - this.Lines[1 + LineIndex]) / 2;
    }    
};

function CParagraphRunElements(ContentPos, Count, arrTypes, isReverse)
{
    this.ContentPos = ContentPos;
    this.Elements   = [];
    this.Count      = Count + 1; // Добавляем 1 для проверки достижения края параграфа
    this.Types      = arrTypes ? arrTypes : [];
    this.End        = false;
	this.Reverse    = undefined !== isReverse ? isReverse : false;

	this.CurContentPos        = new CParagraphContentPos();
	this.SaveContentPositions = false;
	this.ContentPositions     = [];
}
/**
 * Обновляем текущую позицию
 * @param nPos {number}
 * @param nDepth {number}
 */
CParagraphRunElements.prototype.UpdatePos = function(nPos, nDepth)
{
	this.CurContentPos.Update(nPos, nDepth);
};
/**
 * Сохранять ли позиции элементов
 * @param isSave {boolean}
 */
CParagraphRunElements.prototype.SetSaveContentPositions = function(isSave)
{
	this.SaveContentPositions = isSave;
};
/**
 * Получаем массив позиций элементов
 * @returns {Array}
 */
CParagraphRunElements.prototype.GetContentPositions = function()
{
	return this.ContentPositions;
};
/**
 * Проверяем элемент рана по типу
 * @param nType
 * @returns {boolean}
 */
CParagraphRunElements.prototype.CheckType = function(nType)
{
	if (this.Types.length <= 0)
		return true;

	for (var nIndex = 0, nCount = this.Types.length; nIndex < nCount; ++nIndex)
	{
		if (nType === this.Types[nIndex])
			return true;
	}

	return false;
};
/**
 * Добавляем данный элемент
 * @param oElement {CRunElementBase}
 */
CParagraphRunElements.prototype.Add = function(oElement)
{
	if (this.CheckType(oElement.Type))
	{
		if (this.Reverse)
		{
			if (this.SaveContentPositions)
				this.ContentPositions.splice(0, 0, this.CurContentPos.Copy());

			this.Elements.splice(0, 0, oElement);
		}
		else
		{
			if (this.SaveContentPositions)
				this.ContentPositions.push(this.CurContentPos.Copy());

			this.Elements.push(oElement);
		}

		this.Count--;
	}
};
/**
 * Окончен ли сбор элементов
 * @returns {boolean}
 */
CParagraphRunElements.prototype.IsEnoughElements = function()
{
	return (this.Count <= 0);
};
/**
 * Проверяем достиглили мы края параграфа
 * @param isEnd {boolean}
 */
CParagraphRunElements.prototype.CheckEnd = function(isEnd)
{
	if (this.Count <= 0)
	{
		this.End = false;
		if (this.Reverse)
			this.Elements.splice(0, 1);
		else
			this.Elements.splice(this.Elements.length - 1, 1);
	}
	else if (this.Count >= 1)
	{
		this.End = true;
	}
};
/**
 * Проверяем достигли ли мы конца параграфа
 * @returns {boolean}
 */
CParagraphRunElements.prototype.IsEnd = function()
{
	return this.End;
};
/**
 * Получаем список элементов
 * @returns {Array}
 */
CParagraphRunElements.prototype.GetElements = function()
{
	return this.Elements;
};

function CParagraphStatistics(Stats)
{
    this.Stats          = Stats;
    this.EmptyParagraph = true;
    this.Word           = false;

    this.Symbol  = false;
    this.Space   = false;
    this.NewWord = false;
}

function CParagraphMinMaxContentWidth()
{
    this.bWord        = false;
    this.nWordLen     = 0;
    this.nSpaceLen    = 0;
    this.nMinWidth    = 0;
    this.nMaxWidth    = 0;
    this.nCurMaxWidth = 0;
    this.bMath_OneLine = false; // for ParaMath
    this.nMaxHeight    = 0;
    this.nEndHeight    = 0;
}

function CParagraphRangeVisibleWidth()
{
    this.End = false;
    this.W   = 0;
}

function CParagraphMathRangeChecker()
{
    this.Math   = null; // Искомый элемент
    this.Result = true; // Если есть отличные от Math элементы, тогда false, если нет, тогда true 
}

function CParagraphMathParaChecker()
{
    this.Found     = false;
    this.Result    = true;
    this.Direction = 0;
}


function CParagraphStartState(Paragraph)
{
    this.Pr = Paragraph.Pr.Copy();
    this.TextPr = Paragraph.TextPr;
    this.Content = [];
    for(var i = 0; i < Paragraph.Content.length; ++i)
    {
        this.Content.push(Paragraph.Content[i]);
    }
}

function CParagraphTabsCounter()
{
    this.Count = 0;
    this.Pos   = [];
}

function CParagraphRevisionsChangesChecker(Para, RevisionsManager)
{
    this.Paragraph        = Para;
    this.ParaId           = Para.Get_Id();
    this.RevisionsManager = RevisionsManager;
    this.ParaEndRun       = false;
    this.CheckOnlyTextPr  = 0;

    // Блок информации для добавления/удаления текста
    this.AddRemove =
    {
        ChangeType : null,
        StartPos   : null,
        EndPos     : null,
        Value      : [],
        UserId     : "",
        UserName   : "",
        DateTime   : 0
    };

    // Блок информации для сбора изменений настроек текста
    this.TextPr =
    {
        Pr       : null,
        StartPos : null,
        EndPos   : null,
        UserId   : "",
        UserName : "",
        DateTime : 0
    };
}
CParagraphRevisionsChangesChecker.prototype.Flush_AddRemoveChange = function()
{
    var AddRemove = this.AddRemove;
    if (reviewtype_Add === AddRemove.ChangeType || reviewtype_Remove === AddRemove.ChangeType)
    {
        var Change = new CRevisionsChange();
        Change.put_Type(reviewtype_Add === AddRemove.ChangeType ? c_oAscRevisionsChangeType.TextAdd : c_oAscRevisionsChangeType.TextRem);
        Change.put_Paragraph(this.Paragraph);
        Change.put_Value(AddRemove.Value);
        Change.put_StartPos(AddRemove.StartPos);
        Change.put_EndPos(AddRemove.EndPos);
        Change.put_UserId(AddRemove.UserId);
        Change.put_UserName(AddRemove.UserName);
        Change.put_DateTime(AddRemove.DateTime);
        this.RevisionsManager.Add_Change(this.ParaId, Change);
    }

    AddRemove.ChangeType = null;
    AddRemove.StartPos   = null;
    AddRemove.EndPos     = null;
    AddRemove.Value      = [];
    AddRemove.UserId     = "";
    AddRemove.UserName   = "";
    AddRemove.DateTime   = 0;
};
CParagraphRevisionsChangesChecker.prototype.Flush_TextPrChange = function()
{
    var TextPr = this.TextPr;
    if (null !== TextPr.Pr)
    {
        var Change = new CRevisionsChange();
        Change.put_Type(c_oAscRevisionsChangeType.TextPr);
        Change.put_Value(TextPr.Pr);
        Change.put_Paragraph(this.Paragraph);
        Change.put_StartPos(TextPr.StartPos);
        Change.put_EndPos(TextPr.EndPos);
        Change.put_UserId(TextPr.UserId);
        Change.put_UserName(TextPr.UserName);
        Change.put_DateTime(TextPr.DateTime);
        this.RevisionsManager.Add_Change(this.ParaId, Change);
    }

    TextPr.Pr       = null;
    TextPr.StartPos = null;
    TextPr.EndPos   = null;
    TextPr.UserId   = "";
    TextPr.UserName = "";
    TextPr.DateTime = 0;

};
CParagraphRevisionsChangesChecker.prototype.Get_AddRemoveType = function()
{
    return this.AddRemove.ChangeType;
};
CParagraphRevisionsChangesChecker.prototype.Get_AddRemoveUserId = function()
{
    return this.AddRemove.UserId;
};
CParagraphRevisionsChangesChecker.prototype.Start_AddRemove = function(ChangeType, ContentPos)
{
    this.AddRemove.ChangeType = ChangeType;
    this.AddRemove.StartPos   = ContentPos.Copy();
    this.AddRemove.EndPos     = ContentPos.Copy();
    this.AddRemove.Value      = [];
};
CParagraphRevisionsChangesChecker.prototype.Set_AddRemoveEndPos = function(ContentPos)
{
    this.AddRemove.EndPos = ContentPos.Copy();
};
CParagraphRevisionsChangesChecker.prototype.Update_AddRemoveReviewInfo = function(ReviewInfo)
{
    if (ReviewInfo && this.AddRemove.DateTime <= ReviewInfo.Get_DateTime())
    {
        this.AddRemove.UserId   = ReviewInfo.Get_UserId();
        this.AddRemove.UserName = ReviewInfo.Get_UserName();
        this.AddRemove.DateTime = ReviewInfo.Get_DateTime();
    }
};
CParagraphRevisionsChangesChecker.prototype.Add_Text = function(Text)
{
    if (!Text || "" === Text)
        return;

    var Value = this.AddRemove.Value;
    var ValueLen = Value.length;
    if (ValueLen <= 0 || "string" !== typeof Value[ValueLen - 1])
    {
        Value.push("" + Text);
    }
    else
    {
        Value[ValueLen - 1] += Text;
    }
};
CParagraphRevisionsChangesChecker.prototype.Add_Math = function(MathElement)
{
    this.AddRemove.Value.push(c_oAscRevisionsObjectType.MathEquation);
};
CParagraphRevisionsChangesChecker.prototype.Add_Drawing = function(Drawing)
{
    if (Drawing)
    {
        var Type = Drawing.Get_ObjectType();
        switch (Type)
        {
            case AscDFH.historyitem_type_Chart:
            case AscDFH.historyitem_type_ChartSpace:
            {
                this.AddRemove.Value.push(c_oAscRevisionsObjectType.Chart);
                break;
            }
            case AscDFH.historyitem_type_ImageShape:
            case AscDFH.historyitem_type_Image:
            case AscDFH.historyitem_type_OleObject:
            {
                this.AddRemove.Value.push(c_oAscRevisionsObjectType.Image);
                break;
            }
            case AscDFH.historyitem_type_Shape:
            default:
            {
                this.AddRemove.Value.push(c_oAscRevisionsObjectType.Shape);
                break;
            }
        }
    }
};
CParagraphRevisionsChangesChecker.prototype.Have_PrChange = function()
{
    return (null === this.TextPr.Pr ? false : true);
};
CParagraphRevisionsChangesChecker.prototype.Compare_PrChange = function(PrChange)
{
    if (null === this.TextPr.Pr)
        return false;

    return this.TextPr.Pr.Is_Equal(PrChange);
};
CParagraphRevisionsChangesChecker.prototype.Start_PrChange = function(Pr, ContentPos)
{
    this.TextPr.Pr = Pr;
    this.TextPr.StartPos = ContentPos.Copy();
    this.TextPr.EndPos   = ContentPos.Copy();
};
CParagraphRevisionsChangesChecker.prototype.Set_PrChangeEndPos = function(ContentPos)
{
    this.TextPr.EndPos = ContentPos.Copy();
};
CParagraphRevisionsChangesChecker.prototype.Update_PrChangeReviewInfo = function(ReviewInfo)
{
    if (ReviewInfo && this.TextPr.DateTime <= ReviewInfo.Get_DateTime())
    {
        this.TextPr.UserId   = ReviewInfo.Get_UserId();
        this.TextPr.UserName = ReviewInfo.Get_UserName();
        this.TextPr.DateTime = ReviewInfo.Get_DateTime();
    }
};
CParagraphRevisionsChangesChecker.prototype.Is_ParaEndRun = function()
{
    return this.ParaEndRun;
};
CParagraphRevisionsChangesChecker.prototype.Set_ParaEndRun = function()
{
    this.ParaEndRun = true;
};
CParagraphRevisionsChangesChecker.prototype.Begin_CheckOnlyTextPr = function()
{
    this.CheckOnlyTextPr++;
};
CParagraphRevisionsChangesChecker.prototype.End_CheckOnlyTextPr = function()
{
    this.CheckOnlyTextPr--;
};
CParagraphRevisionsChangesChecker.prototype.Is_CheckOnlyTextPr = function()
{
    return (0 === this.CheckOnlyTextPr ? false : true);
};
CParagraphRevisionsChangesChecker.prototype.Get_PrChangeUserId = function()
{
    return this.TextPr.UserId;
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].Paragraph = Paragraph;
window['AscCommonWord'].UnknownValue = UnknownValue;
window['AscCommonWord'].type_Paragraph = type_Paragraph;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 27.10.2016
 * Time: 18:01
 */

AscDFH.changesFactory[AscDFH.historyitem_Paragraph_AddItem]                   = CChangesParagraphAddItem;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_RemoveItem]                = CChangesParagraphRemoveItem;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Numbering]                 = CChangesParagraphNumbering;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Align]                     = CChangesParagraphAlign;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Ind_First]                 = CChangesParagraphIndFirst;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Ind_Right]                 = CChangesParagraphIndRight;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Ind_Left]                  = CChangesParagraphIndLeft;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_ContextualSpacing]         = CChangesParagraphContextualSpacing;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_KeepLines]                 = CChangesParagraphKeepLines;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_KeepNext]                  = CChangesParagraphKeepNext;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_PageBreakBefore]           = CChangesParagraphPageBreakBefore;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Spacing_Line]              = CChangesParagraphSpacingLine;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Spacing_LineRule]          = CChangesParagraphSpacingLineRule;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Spacing_Before]            = CChangesParagraphSpacingBefore;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Spacing_After]             = CChangesParagraphSpacingAfter;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Spacing_AfterAutoSpacing]  = CChangesParagraphSpacingAfterAutoSpacing;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Spacing_BeforeAutoSpacing] = CChangesParagraphSpacingBeforeAutoSpacing;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Shd_Value]                 = CChangesParagraphShdValue;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Shd_Color]                 = CChangesParagraphShdColor;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Shd_Unifill]               = CChangesParagraphShdUnifill;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Shd]                       = CChangesParagraphShd;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_WidowControl]              = CChangesParagraphWidowControl;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Tabs]                      = CChangesParagraphTabs;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_PStyle]                    = CChangesParagraphPStyle;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Borders_Between]           = CChangesParagraphBordersBetween;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Borders_Bottom]            = CChangesParagraphBordersBottom;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Borders_Left]              = CChangesParagraphBordersLeft;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Borders_Right]             = CChangesParagraphBordersRight;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Borders_Top]               = CChangesParagraphBordersTop;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_Pr]                        = CChangesParagraphPr;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_PresentationPr_Bullet]     = CChangesParagraphPresentationPrBullet;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_PresentationPr_Level]      = CChangesParagraphPresentationPrLevel;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_FramePr]                   = CChangesParagraphFramePr;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_SectionPr]                 = CChangesParagraphSectPr;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_PrChange]                  = CChangesParagraphPrChange;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_PrReviewInfo]              = CChangesParagraphPrReviewInfo;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_OutlineLvl]                = CChangesParagraphOutlineLvl;
AscDFH.changesFactory[AscDFH.historyitem_Paragraph_DefaultTabSize]            = CChangesParagraphDefaultTabSize;

function private_ParagraphChangesOnLoadPr(oColor)
{
	this.Redo();

	if (oColor)
		this.Class.private_AddCollPrChange(oColor);
}

function private_ParagraphChangesOnSetValue(oParagraph)
{
	oParagraph.RecalcInfo.Set_Type_0(pararecalc_0_All);
	oParagraph.RecalcInfo.Set_Type_0_Spell(pararecalc_0_Spell_All);
}

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_AddItem]                   = [
	AscDFH.historyitem_Paragraph_AddItem,
	AscDFH.historyitem_Paragraph_RemoveItem
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_RemoveItem]                = [
	AscDFH.historyitem_Paragraph_AddItem,
	AscDFH.historyitem_Paragraph_RemoveItem
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Numbering]                 = [
	AscDFH.historyitem_Paragraph_Numbering,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Align]                     = [
	AscDFH.historyitem_Paragraph_Align,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_DefaultTabSize]            = [
	AscDFH.historyitem_Paragraph_DefaultTabSize,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Ind_First]                 = [
	AscDFH.historyitem_Paragraph_Ind_First,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Ind_Right]                 = [
	AscDFH.historyitem_Paragraph_Ind_Right,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Ind_Left]                  = [
	AscDFH.historyitem_Paragraph_Ind_Left,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_ContextualSpacing]         = [
	AscDFH.historyitem_Paragraph_ContextualSpacing,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_KeepLines]                 = [
	AscDFH.historyitem_Paragraph_KeepLines,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_KeepNext]                  = [
	AscDFH.historyitem_Paragraph_KeepNext,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_PageBreakBefore]           = [
	AscDFH.historyitem_Paragraph_PageBreakBefore,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Spacing_Line]              = [
	AscDFH.historyitem_Paragraph_Spacing_Line,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Spacing_LineRule]          = [
	AscDFH.historyitem_Paragraph_Spacing_LineRule,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Spacing_Before]            = [
	AscDFH.historyitem_Paragraph_Spacing_Before,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Spacing_After]             = [
	AscDFH.historyitem_Paragraph_Spacing_After,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Spacing_AfterAutoSpacing]  = [
	AscDFH.historyitem_Paragraph_Spacing_AfterAutoSpacing,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Spacing_BeforeAutoSpacing] = [
	AscDFH.historyitem_Paragraph_Spacing_BeforeAutoSpacing,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Shd_Value]                 = [
	AscDFH.historyitem_Paragraph_Shd_Value,
	AscDFH.historyitem_Paragraph_Shd,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Shd_Color]                 = [
	AscDFH.historyitem_Paragraph_Shd_Color,
	AscDFH.historyitem_Paragraph_Shd,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Shd_Unifill]               = [
	AscDFH.historyitem_Paragraph_Shd_Unifill,
	AscDFH.historyitem_Paragraph_Shd,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Shd]                       = [
	AscDFH.historyitem_Paragraph_Shd_Value,
	AscDFH.historyitem_Paragraph_Shd_Color,
	AscDFH.historyitem_Paragraph_Shd_Unifill,
	AscDFH.historyitem_Paragraph_Shd,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_WidowControl]              = [
	AscDFH.historyitem_Paragraph_WidowControl,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Tabs]                      = [
	AscDFH.historyitem_Paragraph_Tabs,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_PStyle]                    = [
	AscDFH.historyitem_Paragraph_PStyle,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Borders_Between]           = [
	AscDFH.historyitem_Paragraph_Borders_Between,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Borders_Bottom]            = [
	AscDFH.historyitem_Paragraph_Borders_Bottom,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Borders_Left]              = [
	AscDFH.historyitem_Paragraph_Borders_Left,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Borders_Right]             = [
	AscDFH.historyitem_Paragraph_Borders_Right,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Borders_Top]               = [
	AscDFH.historyitem_Paragraph_Borders_Top,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_Pr]                        = [
	AscDFH.historyitem_Paragraph_Pr,
	AscDFH.historyitem_Paragraph_Numbering,
	AscDFH.historyitem_Paragraph_Align,
	AscDFH.historyitem_Paragraph_DefaultTabSize,
	AscDFH.historyitem_Paragraph_Ind_First,
	AscDFH.historyitem_Paragraph_Ind_Right,
	AscDFH.historyitem_Paragraph_Ind_Left,
	AscDFH.historyitem_Paragraph_ContextualSpacing,
	AscDFH.historyitem_Paragraph_KeepLines,
	AscDFH.historyitem_Paragraph_KeepNext,
	AscDFH.historyitem_Paragraph_PageBreakBefore,
	AscDFH.historyitem_Paragraph_Spacing_Line,
	AscDFH.historyitem_Paragraph_Spacing_LineRule,
	AscDFH.historyitem_Paragraph_Spacing_Before,
	AscDFH.historyitem_Paragraph_Spacing_After,
	AscDFH.historyitem_Paragraph_Spacing_AfterAutoSpacing,
	AscDFH.historyitem_Paragraph_Spacing_BeforeAutoSpacing,
	AscDFH.historyitem_Paragraph_Shd_Value,
	AscDFH.historyitem_Paragraph_Shd_Color,
	AscDFH.historyitem_Paragraph_Shd_Unifill,
	AscDFH.historyitem_Paragraph_Shd,
	AscDFH.historyitem_Paragraph_WidowControl,
	AscDFH.historyitem_Paragraph_Tabs,
	AscDFH.historyitem_Paragraph_PStyle,
	AscDFH.historyitem_Paragraph_Borders_Between,
	AscDFH.historyitem_Paragraph_Borders_Bottom,
	AscDFH.historyitem_Paragraph_Borders_Left,
	AscDFH.historyitem_Paragraph_Borders_Right,
	AscDFH.historyitem_Paragraph_Borders_Top,
	AscDFH.historyitem_Paragraph_PresentationPr_Bullet,
	AscDFH.historyitem_Paragraph_PresentationPr_Level,
	AscDFH.historyitem_Paragraph_FramePr,
	AscDFH.historyitem_Paragraph_PrChange,
	AscDFH.historyitem_Paragraph_PrReviewInfo,
	AscDFH.historyitem_Paragraph_OutlineLvl
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_PresentationPr_Bullet]     = [
	AscDFH.historyitem_Paragraph_PresentationPr_Bullet,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_PresentationPr_Level]      = [
	AscDFH.historyitem_Paragraph_PresentationPr_Level,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_FramePr]                   = [
	AscDFH.historyitem_Paragraph_FramePr,
	AscDFH.historyitem_Paragraph_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_SectionPr]                 = [
	AscDFH.historyitem_Paragraph_SectionPr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_PrChange]                  = [
	AscDFH.historyitem_Paragraph_Pr,
	AscDFH.historyitem_Paragraph_PrChange,
	AscDFH.historyitem_Paragraph_PrReviewInfo
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_PrReviewInfo]              = [
	AscDFH.historyitem_Paragraph_Pr,
	AscDFH.historyitem_Paragraph_PrChange,
	AscDFH.historyitem_Paragraph_PrReviewInfo
];
AscDFH.changesRelationMap[AscDFH.historyitem_Paragraph_OutlineLvl]                = [
	AscDFH.historyitem_Paragraph_OutlineLvl
];

// Общая функция Merge для изменений, которые зависят только от себя и AscDFH.historyitem_Paragraph_Pr
function private_ParagraphChangesOnMergePr(oChange)
{
	if (oChange.Class !== this.Class)
		return true;

	if (oChange.Type === this.Type || oChange.Type === AscDFH.historyitem_Paragraph_Pr)
		return false;

	return true;
}
// Общая функция Merge для изменений, которые зависят от себя, AscDFH.historyitem_Paragraph_Shd, AscDFH.historyitem_Paragraph_Pr
function private_ParagraphChangesOnMergeShdPr(oChange)
{
	if (oChange.Class !== this.Class)
		return true;

	if (oChange.Type === this.Type || oChange.Type === AscDFH.historyitem_Paragraph_Pr || oChange.Type === AscDFH.historyitem_Paragraph_Shd)
		return false;

	return true;
}
//----------------------------------------------------------------------------------------------------------------------

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesParagraphAddItem(Class, Pos, Items)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, true);
}
CChangesParagraphAddItem.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesParagraphAddItem.prototype.constructor = CChangesParagraphAddItem;
CChangesParagraphAddItem.prototype.Type = AscDFH.historyitem_Paragraph_AddItem;
CChangesParagraphAddItem.prototype.Undo = function()
{
	var oParagraph = this.Class;
	oParagraph.Content.splice(this.Pos, this.Items.length);
	oParagraph.private_UpdateTrackRevisions();
	oParagraph.private_CheckUpdateBookmarks(this.Items);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphAddItem.prototype.Redo = function()
{
	var oParagraph  = this.Class;
	var Array_start = oParagraph.Content.slice(0, this.Pos);
	var Array_end   = oParagraph.Content.slice(this.Pos);

	oParagraph.Content = Array_start.concat(this.Items, Array_end);
	oParagraph.private_UpdateTrackRevisions();
	oParagraph.private_CheckUpdateBookmarks(this.Items);
	private_ParagraphChangesOnSetValue(this.Class);

	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var oItem = this.Items[nIndex];
		oItem.Parent = this.Class;
		if (oItem.SetParagraph)
			oItem.SetParagraph(this.Class);

		if (oItem.Recalc_RunsCompiledPr)
			oItem.Recalc_RunsCompiledPr();
	}
};
CChangesParagraphAddItem.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesParagraphAddItem.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesParagraphAddItem.prototype.Load = function(Color)
{
	var oParagraph = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var Pos     = oParagraph.m_oContentChanges.Check(AscCommon.contentchanges_Add, this.PosArray[nIndex]);
		var Element = this.Items[nIndex];

		if (null != Element)
		{
			if (para_Comment === Element.Type)
			{
				var Comment = AscCommon.g_oTableId.Get_ById(Element.CommentId);

				// При копировании не всегда сразу заполняется правильно CommentId
				if (null != Comment && Comment instanceof CComment)
				{
					if (true === Element.Start)
						Comment.Set_StartId(oParagraph.Get_Id());
					else
						Comment.Set_EndId(oParagraph.Get_Id());
				}
			}

			if (Element.SetParagraph)
				Element.SetParagraph(oParagraph);

			oParagraph.Content.splice(Pos, 0, Element);
			AscCommon.CollaborativeEditing.Update_DocumentPositionsOnAdd(oParagraph, Pos);

			if (Element.Recalc_RunsCompiledPr)
				Element.Recalc_RunsCompiledPr();
		}
	}

	oParagraph.private_ResetSelection();
	oParagraph.private_UpdateTrackRevisions();

	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphAddItem.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_Paragraph_AddItem === oChanges.Type || AscDFH.historyitem_Paragraph_RemoveItem === oChanges.Type))
		return true;

	return false;
};
CChangesParagraphAddItem.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesParagraphRemoveItem);
};
CChangesParagraphAddItem.prototype.IsParagraphSimpleChanges = function()
{
	// Простыми измененями считаем добавление комментариев и добавление ранов с простым текстом
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var oItem = this.Items[nIndex];
		if ((para_Run !== oItem.Type || !oItem.IsContentSuitableForParagraphSimpleChanges())
			&& para_Comment !== oItem.Type
			&& para_Bookmark !== oItem.Type)
		{
			return false;
		}
	}

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesParagraphRemoveItem(Class, Pos, Items)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, false);
}
CChangesParagraphRemoveItem.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesParagraphRemoveItem.prototype.constructor = CChangesParagraphRemoveItem;
CChangesParagraphRemoveItem.prototype.Type = AscDFH.historyitem_Paragraph_RemoveItem;
CChangesParagraphRemoveItem.prototype.Undo = function()
{
	var oParagraph  = this.Class;
	var Array_start = oParagraph.Content.slice(0, this.Pos);
	var Array_end   = oParagraph.Content.slice(this.Pos);

	oParagraph.Content = Array_start.concat(this.Items, Array_end);
	oParagraph.private_UpdateTrackRevisions();
	oParagraph.private_CheckUpdateBookmarks(this.Items);
	private_ParagraphChangesOnSetValue(this.Class);

	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var oItem = this.Items[nIndex];

		oItem.Parent = this.Class;
		if (oItem.SetParagraph)
			oItem.SetParagraph(this.Class);

		if (oItem.Recalc_RunsCompiledPr)
			oItem.Recalc_RunsCompiledPr();
	}
};
CChangesParagraphRemoveItem.prototype.Redo = function()
{
	var oParagraph  = this.Class;
	oParagraph.Content.splice(this.Pos, this.Items.length);
	oParagraph.private_UpdateTrackRevisions();
	oParagraph.private_CheckUpdateBookmarks(this.Items);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphRemoveItem.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesParagraphRemoveItem.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesParagraphRemoveItem.prototype.Load = function(Color)
{
	var oParagraph = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var ChangesPos = oParagraph.m_oContentChanges.Check(AscCommon.contentchanges_Remove, this.PosArray[nIndex]);

		if (false === ChangesPos)
			continue;

		oParagraph.Content.splice(ChangesPos, 1);
		AscCommon.CollaborativeEditing.Update_DocumentPositionsOnRemove(oParagraph, ChangesPos, 1);
	}
	oParagraph.private_ResetSelection();
	oParagraph.private_UpdateTrackRevisions();

	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphRemoveItem.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_Paragraph_AddItem === oChanges.Type || AscDFH.historyitem_Paragraph_RemoveItem === oChanges.Type))
		return true;

	return false;
};
CChangesParagraphRemoveItem.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesParagraphAddItem);
};
CChangesParagraphRemoveItem.prototype.IsParagraphSimpleChanges = function()
{
	// Простыми измененями считаем добавление комментариев и добавление ранов с простым текстом
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var oItem = this.Items[nIndex];
		if ((para_Run !== oItem.Type || !oItem.IsContentSuitableForParagraphSimpleChanges())
			&& para_Comment !== oItem.Type
			&& para_Bookmark !== oItem.Type)
		{
			return false;
		}
	}

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParagraphNumbering(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphNumbering.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParagraphNumbering.prototype.constructor = CChangesParagraphNumbering;
CChangesParagraphNumbering.prototype.Type = AscDFH.historyitem_Paragraph_Numbering;
CChangesParagraphNumbering.prototype.private_CreateObject = function()
{
	return new CNumPr();
};
CChangesParagraphNumbering.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.NumPr = Value;

	oParagraph.private_RefreshNumbering(oParagraph.Pr.NumPr);
	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);

	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphNumbering.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphNumbering.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesParagraphAlign(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphAlign.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesParagraphAlign.prototype.constructor = CChangesParagraphAlign;
CChangesParagraphAlign.prototype.Type = AscDFH.historyitem_Paragraph_Align;
CChangesParagraphAlign.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.Jc = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphAlign.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphAlign.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleProperty}
 */
function CChangesParagraphIndFirst(Class, Old, New, Color)
{
	AscDFH.CChangesBaseDoubleProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphIndFirst.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
CChangesParagraphIndFirst.prototype.constructor = CChangesParagraphIndFirst;
CChangesParagraphIndFirst.prototype.Type = AscDFH.historyitem_Paragraph_Ind_First;
CChangesParagraphIndFirst.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;

	if (undefined === oParagraph.Pr.Ind)
		oParagraph.Pr.Ind = new CParaInd();

	oParagraph.Pr.Ind.FirstLine = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphIndFirst.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphIndFirst.prototype.Load = private_ParagraphChangesOnLoadPr;

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleProperty}
 */
function CChangesParagraphDefaultTabSize(Class, Old, New, Color)
{
	AscDFH.CChangesBaseDoubleProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphDefaultTabSize.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
CChangesParagraphDefaultTabSize.prototype.constructor = CChangesParagraphDefaultTabSize;
CChangesParagraphDefaultTabSize.prototype.Type = AscDFH.historyitem_Paragraph_DefaultTabSize;
CChangesParagraphDefaultTabSize.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;


	oParagraph.Pr.DefaultTab = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphDefaultTabSize.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphDefaultTabSize.prototype.Load = private_ParagraphChangesOnLoadPr;

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleProperty}
 */
function CChangesParagraphIndLeft(Class, Old, New, Color)
{
	AscDFH.CChangesBaseDoubleProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphIndLeft.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
CChangesParagraphIndLeft.prototype.constructor = CChangesParagraphIndLeft;
CChangesParagraphIndLeft.prototype.Type = AscDFH.historyitem_Paragraph_Ind_Left;
CChangesParagraphIndLeft.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;

	if (undefined === oParagraph.Pr.Ind)
		oParagraph.Pr.Ind = new CParaInd();

	oParagraph.Pr.Ind.Left = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphIndLeft.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphIndLeft.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleProperty}
 */
function CChangesParagraphIndRight(Class, Old, New, Color)
{
	AscDFH.CChangesBaseDoubleProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphIndRight.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
CChangesParagraphIndRight.prototype.constructor = CChangesParagraphIndRight;
CChangesParagraphIndRight.prototype.Type = AscDFH.historyitem_Paragraph_Ind_Right;
CChangesParagraphIndRight.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;

	if (undefined === oParagraph.Pr.Ind)
		oParagraph.Pr.Ind = new CParaInd();

	oParagraph.Pr.Ind.Right = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphIndRight.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphIndRight.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesParagraphContextualSpacing(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphContextualSpacing.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesParagraphContextualSpacing.prototype.constructor = CChangesParagraphContextualSpacing;
CChangesParagraphContextualSpacing.prototype.Type = AscDFH.historyitem_Paragraph_ContextualSpacing;
CChangesParagraphContextualSpacing.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.ContextualSpacing = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphContextualSpacing.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphContextualSpacing.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesParagraphKeepLines(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphKeepLines.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesParagraphKeepLines.prototype.constructor = CChangesParagraphKeepLines;
CChangesParagraphKeepLines.prototype.Type = AscDFH.historyitem_Paragraph_KeepLines;
CChangesParagraphKeepLines.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.KeepLines = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphKeepLines.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphKeepLines.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesParagraphKeepNext(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphKeepNext.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesParagraphKeepNext.prototype.constructor = CChangesParagraphKeepNext;
CChangesParagraphKeepNext.prototype.Type = AscDFH.historyitem_Paragraph_KeepNext;
CChangesParagraphKeepNext.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.KeepNext = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphKeepNext.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphKeepNext.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesParagraphPageBreakBefore(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphPageBreakBefore.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesParagraphPageBreakBefore.prototype.constructor = CChangesParagraphPageBreakBefore;
CChangesParagraphPageBreakBefore.prototype.Type = AscDFH.historyitem_Paragraph_PageBreakBefore;
CChangesParagraphPageBreakBefore.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.PageBreakBefore = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphPageBreakBefore.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphPageBreakBefore.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleProperty}
 */
function CChangesParagraphSpacingLine(Class, Old, New, Color)
{
	AscDFH.CChangesBaseDoubleProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphSpacingLine.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
CChangesParagraphSpacingLine.prototype.constructor = CChangesParagraphSpacingLine;
CChangesParagraphSpacingLine.prototype.Type = AscDFH.historyitem_Paragraph_Spacing_Line;
CChangesParagraphSpacingLine.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;

	if (undefined === oParagraph.Pr.Spacing)
		oParagraph.Pr.Spacing = new CParaSpacing();

	oParagraph.Pr.Spacing.Line = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphSpacingLine.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphSpacingLine.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesParagraphSpacingLineRule(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphSpacingLineRule.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesParagraphSpacingLineRule.prototype.constructor = CChangesParagraphSpacingLineRule;
CChangesParagraphSpacingLineRule.prototype.Type = AscDFH.historyitem_Paragraph_Spacing_LineRule;
CChangesParagraphSpacingLineRule.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;

	if (undefined === oParagraph.Pr.Spacing)
		oParagraph.Pr.Spacing = new CParaSpacing();

	oParagraph.Pr.Spacing.LineRule = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphSpacingLineRule.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphSpacingLineRule.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleProperty}
 */
function CChangesParagraphSpacingBefore(Class, Old, New, Color)
{
	AscDFH.CChangesBaseDoubleProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphSpacingBefore.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
CChangesParagraphSpacingBefore.prototype.constructor = CChangesParagraphSpacingBefore;
CChangesParagraphSpacingBefore.prototype.Type = AscDFH.historyitem_Paragraph_Spacing_Before;
CChangesParagraphSpacingBefore.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;

	if (undefined === oParagraph.Pr.Spacing)
		oParagraph.Pr.Spacing = new CParaSpacing();

	oParagraph.Pr.Spacing.Before = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphSpacingBefore.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphSpacingBefore.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleProperty}
 */
function CChangesParagraphSpacingAfter(Class, Old, New, Color)
{
	AscDFH.CChangesBaseDoubleProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphSpacingAfter.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
CChangesParagraphSpacingAfter.prototype.constructor = CChangesParagraphSpacingAfter;
CChangesParagraphSpacingAfter.prototype.Type = AscDFH.historyitem_Paragraph_Spacing_After;
CChangesParagraphSpacingAfter.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;

	if (undefined === oParagraph.Pr.Spacing)
		oParagraph.Pr.Spacing = new CParaSpacing();

	oParagraph.Pr.Spacing.After = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphSpacingAfter.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphSpacingAfter.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesParagraphSpacingAfterAutoSpacing(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphSpacingAfterAutoSpacing.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesParagraphSpacingAfterAutoSpacing.prototype.constructor = CChangesParagraphSpacingAfterAutoSpacing;
CChangesParagraphSpacingAfterAutoSpacing.prototype.Type = AscDFH.historyitem_Paragraph_Spacing_AfterAutoSpacing;
CChangesParagraphSpacingAfterAutoSpacing.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;

	if (undefined === oParagraph.Pr.Spacing)
		oParagraph.Pr.Spacing = new CParaSpacing();

	oParagraph.Pr.Spacing.AfterAutoSpacing = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphSpacingAfterAutoSpacing.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphSpacingAfterAutoSpacing.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesParagraphSpacingBeforeAutoSpacing(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphSpacingBeforeAutoSpacing.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesParagraphSpacingBeforeAutoSpacing.prototype.constructor = CChangesParagraphSpacingBeforeAutoSpacing;
CChangesParagraphSpacingBeforeAutoSpacing.prototype.Type = AscDFH.historyitem_Paragraph_Spacing_BeforeAutoSpacing;
CChangesParagraphSpacingBeforeAutoSpacing.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;

	if (undefined === oParagraph.Pr.Spacing)
		oParagraph.Pr.Spacing = new CParaSpacing();

	oParagraph.Pr.Spacing.BeforeAutoSpacing = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphSpacingBeforeAutoSpacing.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphSpacingBeforeAutoSpacing.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseByteProperty}
 */
function CChangesParagraphShdValue(Class, Old, New, Color)
{
	AscDFH.CChangesBaseByteProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphShdValue.prototype = Object.create(AscDFH.CChangesBaseByteProperty.prototype);
CChangesParagraphShdValue.prototype.constructor = CChangesParagraphShdValue;
CChangesParagraphShdValue.prototype.Type = AscDFH.historyitem_Paragraph_Shd_Value;
CChangesParagraphShdValue.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;

	if (undefined === oParagraph.Pr.Shd)
		oParagraph.Pr.Shd = new CDocumentShd();

	oParagraph.Pr.Shd.Value = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphShdValue.prototype.Merge = private_ParagraphChangesOnMergeShdPr;
CChangesParagraphShdValue.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParagraphShdColor(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphShdColor.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParagraphShdColor.prototype.constructor = CChangesParagraphShdColor;
CChangesParagraphShdColor.prototype.Type = AscDFH.historyitem_Paragraph_Shd_Color;
CChangesParagraphShdColor.prototype.private_CreateObject = function()
{
	return new CDocumentColor(0, 0, 0);
};
CChangesParagraphShdColor.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;

	if (undefined === oParagraph.Pr.Shd)
		oParagraph.Pr.Shd = new CDocumentShd();

	oParagraph.Pr.Shd.Color = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphShdColor.prototype.Merge = private_ParagraphChangesOnMergeShdPr;
CChangesParagraphShdColor.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParagraphShdUnifill(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphShdUnifill.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParagraphShdUnifill.prototype.constructor = CChangesParagraphShdUnifill;
CChangesParagraphShdUnifill.prototype.Type = AscDFH.historyitem_Paragraph_Shd_Unifill;
CChangesParagraphShdUnifill.prototype.private_CreateObject = function()
{
	return new AscFormat.CUniFill();
};
CChangesParagraphShdUnifill.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;

	if (undefined === oParagraph.Pr.Shd)
		oParagraph.Pr.Shd = new CDocumentShd();

	oParagraph.Pr.Shd.Unifill = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphShdUnifill.prototype.Merge = private_ParagraphChangesOnMergeShdPr;
CChangesParagraphShdUnifill.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParagraphShd(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphShd.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParagraphShd.prototype.constructor = CChangesParagraphShd;
CChangesParagraphShd.prototype.Type = AscDFH.historyitem_Paragraph_Shd;
CChangesParagraphShd.prototype.private_CreateObject = function()
{
	return new CDocumentShd();
};
CChangesParagraphShd.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.Shd = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphShd.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type || oChange.Type === AscDFH.historyitem_Paragraph_Pr)
		return false;

	if (AscDFH.historyitem_Paragraph_Shd_Value === oChange.Type)
	{
		if (!this.New)
			this.New = new CDocumentShd();

		this.New.Value = oChange.New;
	}
	else if (AscDFH.historyitem_Paragraph_Shd_Color === oChange.Type)
	{
		if (!this.New)
			this.New = new CDocumentShd();

		this.New.Color = oChange.New;
	}
	else if (AscDFH.historyitem_Paragraph_Shd_Unifill === oChange.Type)
	{
		if (!this.New)
			this.New = new CDocumentShd();

		this.New.Unifill = oChange.New;
	}

	return true;
};
CChangesParagraphShd.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesParagraphWidowControl(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphWidowControl.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesParagraphWidowControl.prototype.constructor = CChangesParagraphWidowControl;
CChangesParagraphWidowControl.prototype.Type = AscDFH.historyitem_Paragraph_WidowControl;
CChangesParagraphWidowControl.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.WidowControl = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphWidowControl.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphWidowControl.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParagraphTabs(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphTabs.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParagraphTabs.prototype.constructor = CChangesParagraphTabs;
CChangesParagraphTabs.prototype.Type = AscDFH.historyitem_Paragraph_Tabs;
CChangesParagraphTabs.prototype.private_CreateObject = function()
{
	return new CParaTabs();
};
CChangesParagraphTabs.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.Tabs = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphTabs.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphTabs.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseStringProperty}
 */
function CChangesParagraphPStyle(Class, Old, New, Color)
{
	AscDFH.CChangesBaseStringProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphPStyle.prototype = Object.create(AscDFH.CChangesBaseStringProperty.prototype);
CChangesParagraphPStyle.prototype.constructor = CChangesParagraphPStyle;
CChangesParagraphPStyle.prototype.Type = AscDFH.historyitem_Paragraph_PStyle;
CChangesParagraphPStyle.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.PStyle = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	oParagraph.Recalc_RunsCompiledPr();
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphPStyle.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphPStyle.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParagraphBordersBetween(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphBordersBetween.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParagraphBordersBetween.prototype.constructor = CChangesParagraphBordersBetween;
CChangesParagraphBordersBetween.prototype.Type = AscDFH.historyitem_Paragraph_Borders_Between;
CChangesParagraphBordersBetween.prototype.private_CreateObject = function()
{
	return new CDocumentBorder();
};
CChangesParagraphBordersBetween.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.Brd.Between = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphBordersBetween.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphBordersBetween.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParagraphBordersBottom(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphBordersBottom.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParagraphBordersBottom.prototype.constructor = CChangesParagraphBordersBottom;
CChangesParagraphBordersBottom.prototype.Type = AscDFH.historyitem_Paragraph_Borders_Bottom;
CChangesParagraphBordersBottom.prototype.private_CreateObject = function()
{
	return new CDocumentBorder();
};
CChangesParagraphBordersBottom.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.Brd.Bottom = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphBordersBottom.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphBordersBottom.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParagraphBordersLeft(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphBordersLeft.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParagraphBordersLeft.prototype.constructor = CChangesParagraphBordersLeft;
CChangesParagraphBordersLeft.prototype.Type = AscDFH.historyitem_Paragraph_Borders_Left;
CChangesParagraphBordersLeft.prototype.private_CreateObject = function()
{
	return new CDocumentBorder();
};
CChangesParagraphBordersLeft.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.Brd.Left = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphBordersLeft.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphBordersLeft.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParagraphBordersRight(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphBordersRight.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParagraphBordersRight.prototype.constructor = CChangesParagraphBordersRight;
CChangesParagraphBordersRight.prototype.Type = AscDFH.historyitem_Paragraph_Borders_Right;
CChangesParagraphBordersRight.prototype.private_CreateObject = function()
{
	return new CDocumentBorder();
};
CChangesParagraphBordersRight.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.Brd.Right = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphBordersRight.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphBordersRight.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParagraphBordersTop(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphBordersTop.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParagraphBordersTop.prototype.constructor = CChangesParagraphBordersTop;
CChangesParagraphBordersTop.prototype.Type = AscDFH.historyitem_Paragraph_Borders_Top;
CChangesParagraphBordersTop.prototype.private_CreateObject = function()
{
	return new CDocumentBorder();
};
CChangesParagraphBordersTop.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.Brd.Top = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphBordersTop.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphBordersTop.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParagraphPr(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphPr.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParagraphPr.prototype.constructor = CChangesParagraphPr;
CChangesParagraphPr.prototype.Type = AscDFH.historyitem_Paragraph_Pr;
CChangesParagraphPr.prototype.private_CreateObject = function()
{
	return new CParaPr();
};
CChangesParagraphPr.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphPr.prototype.private_IsCreateEmptyObject = function()
{
	return true;
};
CChangesParagraphPr.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return;

	if (AscDFH.historyitem_Paragraph_Pr === oChange.Type)
		return false;

	if (!this.New)
		this.New = new CParaPr();

	switch (oChange.Type)
	{
		case AscDFH.historyitem_Paragraph_Numbering:
		{
			this.New.NumPr = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Align:
		{
			this.New.Jc = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_DefaultTabSize:
		{
			this.New.DefaultTab = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Ind_First:
		{
			if (!this.New.Ind)
				this.New.Ind = new CParaInd();

			this.New.Ind.FirstLine = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Ind_Right:
		{
			if (!this.New.Ind)
				this.New.Ind = new CParaInd();

			this.New.Ind.Right = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Ind_Left:
		{
			if (!this.New.Ind)
				this.New.Ind = new CParaInd();

			this.New.Ind.Left = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_ContextualSpacing:
		{
			this.New.ContextualSpacing = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_KeepLines:
		{
			this.New.KeepLines = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_KeepNext:
		{
			this.New.KeepNext = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_PageBreakBefore:
		{
			this.New.PageBreakBefore = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Spacing_Line:
		{
			if (!this.New.Spacing)
				this.New.Spacing = new CParaSpacing();

			this.New.Spacing.Line = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Spacing_LineRule:
		{
			if (!this.New.Spacing)
				this.New.Spacing = new CParaSpacing();

			this.New.Spacing.LineRule = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Spacing_Before:
		{
			if (!this.New.Spacing)
				this.New.Spacing = new CParaSpacing();

			this.New.Spacing.Before = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Spacing_After:
		{
			if (!this.New.Spacing)
				this.New.Spacing = new CParaSpacing();

			this.New.Spacing.After = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Spacing_AfterAutoSpacing:
		{
			if (!this.New.Spacing)
				this.New.Spacing = new CParaSpacing();

			this.New.Spacing.AfterAutoSpacing = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Spacing_BeforeAutoSpacing:
		{
			if (!this.New.Spacing)
				this.New.Spacing = new CParaSpacing();

			this.New.Spacing.BeforeAutoSpacing = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Shd_Value:
		{
			if (!this.New.Shd)
				this.New.Shd = new CDocumentShd();

			this.New.Shd.Value = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Shd_Color:
		{
			if (!this.New.Shd)
				this.New.Shd = new CDocumentShd();

			this.New.Shd.Color = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Shd_Unifill:
		{
			if (!this.New.Shd)
				this.New.Shd = new CDocumentShd();

			this.New.Shd.Unifill = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Shd:
		{
			this.New.Shd = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_WidowControl:
		{
			this.New.WidowControl = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Tabs:
		{
			this.New.Tabs = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_PStyle:
		{
			this.New.PStyle = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Borders_Between:
		{
			this.New.Brd.Between = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Borders_Bottom:
		{
			this.New.Brd.Bottom = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Borders_Left:
		{
			this.New.Brd.Left = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Borders_Right:
		{
			this.New.Brd.Right = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_Borders_Top:
		{
			this.New.Brd.Top = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_PresentationPr_Bullet:
		{
			this.New.Bullet = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_PresentationPr_Level:
		{
			this.New.Lvl = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_FramePr:
		{
			this.New.FramePr = oChange.New;
			break;
		}
		case AscDFH.historyitem_Paragraph_PrChange:
		{
			this.New.PrChange   = oChange.New.PrChange;
			this.New.ReviewInfo = oChange.New.ReviewInfo;
			break;
		}
		case AscDFH.historyitem_Paragraph_PrReviewInfo:
		{
			this.New.ReviewInfo = oChange.New;
			break;
		}
	}

	return true;
};
CChangesParagraphPr.prototype.Load = private_ParagraphChangesOnLoadPr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParagraphPresentationPrBullet(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphPresentationPrBullet.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParagraphPresentationPrBullet.prototype.constructor = CChangesParagraphPresentationPrBullet;
CChangesParagraphPresentationPrBullet.prototype.Type = AscDFH.historyitem_Paragraph_PresentationPr_Bullet;
CChangesParagraphPresentationPrBullet.prototype.private_CreateObject = function()
{
	return new AscFormat.CBullet();
};
CChangesParagraphPresentationPrBullet.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphPresentationPrBullet.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.Bullet = Value;
	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.Recalc_RunsCompiledPr();
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesParagraphPresentationPrLevel(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphPresentationPrLevel.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesParagraphPresentationPrLevel.prototype.constructor = CChangesParagraphPresentationPrLevel;
CChangesParagraphPresentationPrLevel.prototype.Type = AscDFH.historyitem_Paragraph_PresentationPr_Level;
CChangesParagraphPresentationPrLevel.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphPresentationPrLevel.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.Lvl = Value;
	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.Recalc_RunsCompiledPr();
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParagraphFramePr(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphFramePr.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParagraphFramePr.prototype.constructor = CChangesParagraphFramePr;
CChangesParagraphFramePr.prototype.Type = AscDFH.historyitem_Paragraph_FramePr;
CChangesParagraphFramePr.prototype.private_CreateObject = function()
{
	return new CFramePr();
};
CChangesParagraphFramePr.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.FramePr = Value;
	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphFramePr.prototype.Merge = private_ParagraphChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesParagraphSectPr(Class, Old, New)
{
	AscDFH.CChangesBase.call(this, Class);

	this.Old = Old;
	this.New = New;
}
CChangesParagraphSectPr.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesParagraphSectPr.prototype.constructor = CChangesParagraphSectPr;
CChangesParagraphSectPr.prototype.Type = AscDFH.historyitem_Paragraph_SectionPr;
CChangesParagraphSectPr.prototype.Undo = function()
{
	var oParagraph = this.Class;
	var oOldSectPr = oParagraph.SectPr;
	oParagraph.SectPr = this.Old;
	oParagraph.LogicDocument.UpdateSectionInfo(oOldSectPr, this.Old, false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphSectPr.prototype.Redo = function()
{
	var oParagraph = this.Class;
	var oOldSectPr = oParagraph.SectPr;
	oParagraph.SectPr = this.New;
	oParagraph.LogicDocument.UpdateSectionInfo(oOldSectPr, this.New, false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphSectPr.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : IsUndefined New
	// 2-bit : IsUndefined Old
	// String : Id of New
	// String : Id of Old

	var nFlags = 0;

	if (undefined === this.New)
		nFlags |= 1;

	if (undefined === this.Old)
		nFlags |= 2;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New)
		Writer.WriteString2(this.New.Get_Id());

	if (undefined !== this.Old)
		Writer.WriteString2(this.Old.Get_Id());
};
CChangesParagraphSectPr.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : IsUndefined New
	// 2-bit : IsUndefined Old
	// String : Id of New
	// String : Id of Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.New = undefined;
	else
		this.New = AscCommon.g_oTableId.Get_ById(Reader.GetString2());

	if (nFlags & 2)
		this.Old = undefined;
	else
		this.Old = AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesParagraphSectPr.prototype.CreateReverseChange = function()
{
	return new CChangesParagraphSectPr(this.Class, this.New, this.Old);
};
CChangesParagraphSectPr.prototype.Merge = function(oChange)
{
	if (oChange.Class === this.Class && oChange.Type === this.Type)
		return false;

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesParagraphPrChange(Class, Old, New)
{
	AscDFH.CChangesBase.call(this, Class);

	this.Old = Old;
	this.New = New;
}
CChangesParagraphPrChange.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesParagraphPrChange.prototype.constructor = CChangesParagraphPrChange;
CChangesParagraphPrChange.prototype.Type = AscDFH.historyitem_Paragraph_PrChange;
CChangesParagraphPrChange.prototype.Undo = function()
{
	var oParagraph = this.Class;
	oParagraph.Pr.PrChange   = this.Old.PrChange;
	oParagraph.Pr.ReviewInfo = this.Old.ReviewInfo;
	oParagraph.private_UpdateTrackRevisions();
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphPrChange.prototype.Redo = function()
{
	var oParagraph = this.Class;
	oParagraph.Pr.PrChange   = this.New.PrChange;
	oParagraph.Pr.ReviewInfo = this.New.ReviewInfo;
	oParagraph.private_UpdateTrackRevisions();
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphPrChange.prototype.WriteToBinary = function(Writer)
{
	// Long : Flags
	// 1-bit : is New.PrChange undefined ?
	// 2-bit : is New.ReviewInfo undefined ?
	// 3-bit : is Old.PrChange undefined ?
	// 4-bit : is Old.ReviewInfo undefined ?
	// Variable(CParaPr)     : New.PrChange   (1bit = 0)
	// Variable(CReviewInfo) : New.ReviewInfo (2bit = 0)
	// Variable(CParaPr)     : Old.PrChange   (3bit = 0)
	// Variable(CReviewInfo) : Old.ReviewInfo (4bit = 0)
	var nFlags = 0;
	if (undefined === this.New.PrChange)
		nFlags |= 1;

	if (undefined === this.New.ReviewInfo)
		nFlags |= 2;

	if (undefined === this.Old.PrChange)
		nFlags |= 4;

	if (undefined === this.Old.ReviewInfo)
		nFlags |= 8;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New.PrChange)
		this.New.PrChange.Write_ToBinary(Writer);

	if (undefined !== this.New.ReviewInfo)
		this.New.ReviewInfo.Write_ToBinary(Writer);

	if (undefined !== this.Old.PrChange)
		this.Old.PrChange.Write_ToBinary(Writer);

	if (undefined !== this.Old.ReviewInfo)
		this.Old.ReviewInfo.Write_ToBinary(Writer);
};
CChangesParagraphPrChange.prototype.ReadFromBinary = function(Reader)
{
	// Long : Flags
	// 1-bit : is New.PrChange undefined ?
	// 2-bit : is New.ReviewInfo undefined ?
	// 3-bit : is Old.PrChange undefined ?
	// 4-bit : is Old.ReviewInfo undefined ?
	// Variable(CParaPr)     : New.PrChange   (1bit = 0)
	// Variable(CReviewInfo) : New.ReviewInfo (2bit = 0)
	// Variable(CParaPr)     : Old.PrChange   (3bit = 0)
	// Variable(CReviewInfo) : Old.ReviewInfo (4bit = 0)
	var nFlags = Reader.GetLong();

	this.New = {
		PrChange   : undefined,
		ReviewInfo : undefined
	};

	this.Old = {
		PrChange   : undefined,
		ReviewInfo : undefined
	};

	if (nFlags & 1)
	{
		this.New.PrChange = undefined;
	}
	else
	{
		this.New.PrChange = new CParaPr();
		this.New.PrChange.Read_FromBinary(Reader);
	}

	if (nFlags & 2)
	{
		this.New.ReviewInfo = undefined;
	}
	else
	{
		this.New.ReviewInfo = new CReviewInfo();
		this.New.ReviewInfo.Read_FromBinary(Reader);
	}

	if (nFlags & 4)
	{
		this.Old.PrChange = undefined;
	}
	else
	{
		this.Old.PrChange = new CParaPr();
		this.Old.PrChange.Read_FromBinary(Reader);
	}

	if (nFlags & 8)
	{
		this.Old.ReviewInfo = undefined;
	}
	else
	{
		this.Old.ReviewInfo = new CReviewInfo();
		this.Old.ReviewInfo.Read_FromBinary(Reader);
	}
};
CChangesParagraphPrChange.prototype.CreateReverseChange = function()
{
	return new CChangesParagraphPrChange(this.Class, this.New, this.Old);
};
CChangesParagraphPrChange.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (oChange.Type === this.Type || AscDFH.historyitem_Paragraph_Pr === oChange.Type)
		return false;

	if (AscDFH.historyitem_Paragraph_PrReviewInfo === oChange.Type)
		this.New.ReviewInfo = oChange.New;

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesParagraphPrReviewInfo(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphPrReviewInfo.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesParagraphPrReviewInfo.prototype.constructor = CChangesParagraphPrReviewInfo;
CChangesParagraphPrReviewInfo.prototype.Type = AscDFH.historyitem_Paragraph_PrReviewInfo;
CChangesParagraphPrReviewInfo.prototype.private_CreateObject = function()
{
	return new CReviewInfo();
};
CChangesParagraphPrReviewInfo.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.ReviewInfo = Value;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphPrReviewInfo.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (oChange.Type === this.Type || AscDFH.historyitem_Paragraph_Pr === oChange.Type || AscDFH.historyitem_Paragraph_PrChange === oChange.Type)
		return false;

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesParagraphOutlineLvl(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesParagraphOutlineLvl.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesParagraphOutlineLvl.prototype.constructor = CChangesParagraphOutlineLvl;
CChangesParagraphOutlineLvl.prototype.Type = AscDFH.historyitem_Paragraph_OutlineLvl;
CChangesParagraphOutlineLvl.prototype.private_SetValue = function(Value)
{
	var oParagraph = this.Class;
	oParagraph.Pr.OutlineLvl = Value;

	oParagraph.CompiledPr.NeedRecalc = true;
	oParagraph.private_UpdateTrackRevisionOnChangeParaPr(false);
	private_ParagraphChangesOnSetValue(this.Class);
};
CChangesParagraphOutlineLvl.prototype.Merge = private_ParagraphChangesOnMergePr;
CChangesParagraphOutlineLvl.prototype.Load = private_ParagraphChangesOnLoadPr;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var g_oTextMeasurer = AscCommon.g_oTextMeasurer;

// TODO: В колонтитулах быстрые пересчеты отключены. Надо реализовать.

/**
 * Здесь мы пытаемся быстро пересчитать текущий параграф. Если быстрый пересчет срабатывает, тогда возвращаются
 * страницы, которые нужно перерисовать, в противном случае возвращается пустой массив.
 * @returns {*}
 */
Paragraph.prototype.Recalculate_FastWholeParagraph = function()
{
    if (this.Pages.length <= 0)
        return [];

    if (true === this.Parent.IsHdrFtr(false))
        return [];

    //Не запускаемм быстрый пересчет, когда параграф находится в автофигуре с выставленным флагом подбора размера по размеру контента,
    // т. к. при расчете контента потребуется пересчет в новых размерах.
    if(true === this.Parent.Check_AutoFit())
    {
        return [];
    }

    // TODO: Отключаем это ускорение в таблицах, т.к. в таблицах и так есть свое ускорение. Но можно и это ускорение
    // подключить, для этого надо проверять изменились ли MinMax ширины и набираем ли мы в строке заголовков.
    if (undefined === this.Parent || true === this.Parent.IsTableCellContent())
        return [];

    // Если изменения происходят в специальном пустом параграфе-конце секции, тогда запускаем обычный пересчет
    if (this.bFromDocument && this.LogicDocument && (!this.LogicDocument.Pages[this.Get_StartPage_Absolute()] || true === this.LogicDocument.Pages[this.Get_StartPage_Absolute()].Check_EndSectionPara(this)))
        return [];

    // Если параграф - рамка с автошириной, надо пересчитывать по обычному
    if (1 === this.Lines.length && true !== this.Is_Inline())
        return [];

    this.SetIsRecalculated(true);

    // Здесь мы отдельно обрабатываем случаи быстрого пересчета параграфов, которые были разбиты на 1-2
    // страницы. Если параграф был разбит более чем на 2 страницы, то такое ускорение уже не имеет смысла.
    if (1 === this.Pages.length)
    {
        // Если параграф был разбит на 1 страницу изначально, тогда мы проверяем, чтобы он после пересчета
        // был также разбит на 1 страницу, кроме этого проверяем изменились ли границы параграфа, и проверяем
        // последнюю строку на pageBreak/columnBreak, а во время пересчета смотрим изменяeтся ли положение
        // flow-объектов, привязанных к данному параграфу, кроме того, если по какой-то причине пересчет возвращает
        // не recalcresult_NextElement, тогда тоже отменяем быстрый пересчет

		this.m_oPRSW.SetFast(true);

        var OldBounds            = this.Pages[0].Bounds;
        var isPageBreakLastLine1 = this.Lines[this.Lines.length - 1].Info & paralineinfo_BreakPage;
        var isPageBreakLastLine2 = this.Lines[this.Lines.length - 1].Info & paralineinfo_BreakRealPage;
        var FastRecalcResult     = this.Recalculate_Page(0, true);

		this.m_oPRSW.SetFast(false);

        if (FastRecalcResult & recalcresult_NextElement
            && 1 === this.Pages.length
            && true === this.Pages[0].Bounds.Compare(OldBounds)
            && this.Lines.length > 0
            && isPageBreakLastLine1 === (this.Lines[this.Lines.length - 1].Info & paralineinfo_BreakPage)
            && isPageBreakLastLine2 === (this.Lines[this.Lines.length - 1].Info & paralineinfo_BreakRealPage))
        {
            //console.log("Recalc Fast WholeParagraph 1 page");
            return [this.Get_AbsolutePage(0)];
        }
    }
    else if (2 === this.Pages.length)
    {
        // Если параграф был разбит на 2 страницы изначально, тогда мы проверяем, чтобы он после пересчета
        // был также разбит на 2 страницы, кроме этого проверяем изменились ли границы параграфа на каждой странице,
        // а во время пересчета смотрим изменяeтся ли положение flow-объектов, привязанных к данному параграфу.
        // Кроме того, если по какой-то причине пересчет возвращает не recalcresult_NextPage на первой странице, или не
        // recalcresult_NextElement, тогда тоже отменяем быстрый пересчет.
        var OldBounds_0 = this.Pages[0].Bounds;
        var OldBounds_1 = this.Pages[1].Bounds;

        var isPageBreakLastLine1 = this.Lines[this.Lines.length - 1].Info & paralineinfo_BreakPage;
        var isPageBreakLastLine2 = this.Lines[this.Lines.length - 1].Info & paralineinfo_BreakRealPage;

        // Чтобы защититься от неправильной работы, связанной с переносом параграфа на новую страницу,
        // будем следить за тем, начинался ли изначально параграф с новой страницы, и начинается ли он с
        // новой страницы сейчас.
        var OldStartFromNewPage = this.Pages[0].StartLine < 0 ? true : false;

        // Чтобы защититься от неправильной работой с висячими строками, будем следить за количеством строк
        // если оно меньше либо равно 2 на какой-либо странице до/после пересчета.
        var OldLinesCount_0 = this.Pages[0].EndLine - this.Pages[0].StartLine + 1;
        var OldLinesCount_1 = this.Pages[1].EndLine - this.Pages[1].StartLine + 1;

		this.m_oPRSW.SetFast(true);
		var FastRecalcResult = this.Recalculate_Page(0, true);

		if (!(FastRecalcResult & recalcresult_NextPage))
		{
			this.m_oPRSW.SetFast(false);
			return [];
		}

        FastRecalcResult = this.Recalculate_Page(1);
		this.m_oPRSW.SetFast(false);
        if (!(FastRecalcResult & recalcresult_NextElement))
            return [];

        // Сравниваем количество страниц (хотя оно должно быть 2 к данному моменту) и границы каждой страницы
        if (2 !== this.Pages.length || true !== this.Pages[0].Bounds.Compare(OldBounds_0) || true !== this.Pages[1].Bounds.Compare(OldBounds_1))
            return [];

        // Сравниваем наличие pageBreak/columnBreak в последней строке
        if (this.Lines.length <= 0
            || isPageBreakLastLine1 !== (this.Lines[this.Lines.length - 1].Info & paralineinfo_BreakPage)
            || isPageBreakLastLine2 !== (this.Lines[this.Lines.length - 1].Info & paralineinfo_BreakRealPage))
            return [];

        // Проверяем пустую первую страницу
        var StartFromNewPage = this.Pages[0].StartLine < 0 ? true : false;
        if (StartFromNewPage !== OldStartFromNewPage)
            return [];

        // Если параграф начался с новой страницы, тогда у него не надо проверять висячие строки
        if (true !== StartFromNewPage)
        {
            var LinesCount_0 = this.Pages[0].EndLine - this.Pages[0].StartLine + 1;
            var LinesCount_1 = this.Pages[1].EndLine - this.Pages[1].StartLine + 1;

            if ((OldLinesCount_0 <= 2 || LinesCount_0 <= 2) && OldLinesCount_0 !== LinesCount_0)
                return [];

            if ((OldLinesCount_1 <= 2 || LinesCount_1 <= 2) && OldLinesCount_1 !== LinesCount_1)
                return [];
        }

        //console.log("Recalc Fast WholeParagraph 2 pages");

        // Если параграф начинается с новой страницы, тогда не надо перерисовывать первую страницу, т.к. она
        // изначально была пустая, и сейчас пустая.

        if (true === StartFromNewPage)
        {
            return [this.Get_AbsolutePage(1)];
        }
        else
        {
            var PageAbs0 = this.Get_AbsolutePage(0);
            var PageAbs1 = this.Get_AbsolutePage(1);
            if (PageAbs0 !== PageAbs1)
                return [PageAbs0, PageAbs1];
            else
                return [PageAbs0];
        }
    }

    return [];
};
/**
 * Пытаемся быстро рассчитать отрезок, в котором произошли изменения, и если ничего не съехало, тогда
 * перерисовываем страницу, в противном случаем запускаем обычный пересчет.
 * @param SimpleChanges
 * @returns {*} -1 если быстрый пересчет не получился, либо номер страницы, которую нужно перерисовать
 */
Paragraph.prototype.Recalculate_FastRange = function(SimpleChanges)
{
	if (this.Pages.length <= 0)
        return -1;

    if (true === this.Parent.IsHdrFtr(false))
        return -1;

    var Run = SimpleChanges[0].Class;
    var ParaPos = Run.Get_SimpleChanges_ParaPos(SimpleChanges);
    if ( null === ParaPos )
        return -1;

    var Line  = ParaPos.Line;
    var Range = ParaPos.Range;

    // Такое возможно, если у нас шел долгий пересчет (например, из-за изменений второго пользователя) и в это же время
	// запустился быстрый (ввод символа). Долгий пересчет успел сбросить рассчет данного параграфа, но не пересчитал параграф
	// до конца, а в это время у данного параграфа запросился быстрый пересчет.
    if (this.Lines.length <= ParaPos.Line)
    	return -1;

    // TODO: Отключаем это ускорение в таблицах, т.к. в таблицах и так есть свое ускорение. Но можно и это ускорение
    // подключить, для этого надо проверять изменились ли MinMax ширины и набираем ли мы в строке заголовков.
    if ( undefined === this.Parent || true === this.Parent.IsTableCellContent() )
        return -1;

    //Не запускаемм быстрый пересчет, когда параграф находится в автофигуре с выставленным флагом подбора размера по размеру контента,
    // т. к. при расчете контента потребуется пересчет в новых размерах.
    if(true === this.Parent.Check_AutoFit())
    {
        return -1;
    }

    // Если мы находимся в строке, которая была полностью перенесена из-за обтекания,  и мы добавляем пробел, или
    // удаляем символ, тогда нам запускать обычный пересчет, т.к. первое слово может начать убираться в промежутках
    // обтекания, которых у нас нет в отрезках строки
    if ( true === this.Lines[Line].RangeY )
    {
        // TODO: Сделать проверку на добавление пробела и удаление
        return -1;
    }

    // Если у нас есть PageBreak в строке, запускаем обычный пересчет, либо если это пустой параграф.
    if (this.Lines[Line].Info & paralineinfo_BreakPage || (this.Lines[Line].Info & paralineinfo_Empty &&  this.Lines[Line].Info & paralineinfo_End))
        return  -1;

    // Если у нас отрезок, в котором произошли изменения является отрезком с нумерацией, тогда надо запустить
    // обычный пересчет.
    if ( null !== this.Numbering.Item && ( Line < this.Numbering.Line || ( Line === this.Numbering.Line && Range <= this.Numbering.Range ) ))
    {
        // TODO: Сделать проверку на само изменение, переместилась ли нумерация
        var CompiledParaPr = this.Get_CompiledPr2(false).ParaPr;
        if(this.Numbering.Type === para_Numbering)
        {
            var NumPr = CompiledParaPr.NumPr;
            if(( undefined !== NumPr && undefined !== NumPr.NumId && 0 !== NumPr.NumId && "0" !== NumPr.NumId ))
            {
                return -1;
            }
        }
        else
        {
            var Bullet = this.Numbering.Bullet;
            if ( Bullet &&  null !== Bullet.m_oTextPr && null !== Bullet.m_nNum && null != Bullet.m_sString && Bullet.m_sString.length !== 0)
            {
                return -1;
            }
        }
    }

    if ( 0 === Line && 0 === Range && undefined !== this.Get_SectionPr() )
    {
        return -1;
    }

    // Если наш параграф является рамкой с авто шириной, тогда пересчитываем по обычному
    // TODO: Улучишить данную проверку
    if ( 1 === this.Lines.length && true !== this.Is_Inline() )
        return -1;

    // Мы должны пересчитать как минимум 3 отрезка: текущий, предыдущий и следующий, потому что при удалении элемента
    // или добавлении пробела первое слово в данном отрезке может убраться в предыдущем отрезке, и кроме того при
    // удалении возможен вариант, когда мы неправильно определили отрезок (т.е. более ранний взяли). Но возможен
    // вариант, при котором предыдущий или/и следующий отрезки - пустые, т.е. там нет ни одного текстового элемента
    // тогда мы начинаем проверять с отрезка, в котором есть хоть что-то.

    var PrevLine  = Line;
    var PrevRange = Range;

	this.m_oPRSW.SetFast(true);

    while ( PrevLine >= 0 )
    {
        PrevRange--;

        if ( PrevRange < 0 )
        {
            PrevLine--;

            if ( PrevLine < 0 )
                break;

            PrevRange = this.Lines[PrevLine].Ranges.length - 1;
        }

        if ( true === this.Is_EmptyRange( PrevLine, PrevRange ) )
            continue;
        else
            break;
    }

    if ( PrevLine < 0 )
    {
        PrevLine  = Line;
        PrevRange = Range;
    }

    var NextLine  = Line;
    var NextRange = Range;

    var LinesCount = this.Lines.length;

    while ( NextLine <= LinesCount - 1 )
    {
        NextRange++;

        if ( NextRange > this.Lines[NextLine].Ranges.length - 1 )
        {
            NextLine++

            if ( NextLine > LinesCount - 1 )
                break;

            NextRange = 0;
        }

        if ( true === this.Is_EmptyRange( NextLine, NextRange ) )
            continue;
        else
            break;
    }

    if ( NextLine > LinesCount - 1 )
    {
        NextLine  = Line;
        NextRange = Range;
    }

    var CurLine  = PrevLine;
    var CurRange = PrevRange;

    var Result;
    while ( ( CurLine < NextLine ) || ( CurLine === NextLine && CurRange <= NextRange ) )
    {
        var TempResult = this.private_RecalculateFastRange(CurRange, CurLine);
        if ( -1 === TempResult )
		{
			this.m_oPRSW.SetFast(false);
			return -1;
		}

        if ( CurLine === Line && CurRange === Range )
            Result = TempResult;

        CurRange++;

        if ( CurRange > this.Lines[CurLine].Ranges.length - 1 )
        {
            CurLine++;
            CurRange = 0;
        }
    }

    // Во время пересчета сбрасываем привязку курсора к строке.
    this.CurPos.Line  = -1;
    this.CurPos.Range = -1;

    this.Internal_CheckSpelling();
	this.SetIsRecalculated(true);

	//console.log("Recalc Fast Range");

	this.m_oPRSW.SetFast(false);
    return this.Get_AbsolutePage(Result);
};

/**
 * Функция для пересчета страницы параграфа.
 * @param {number} CurPage - Номер страницы, которую нужно пересчитать (относительный номер страницы для параграфа).
 * Предыдущая страница ДОЛЖНА быть пересчитана, если задано не нулевое значение.
 * @returns {*} Возвращается результат пересчета
 */
Paragraph.prototype.Recalculate_Page = function(CurPage)
{
    this.Clear_NearestPosArray();

    // Во время пересчета сбрасываем привязку курсора к строке.
    this.CurPos.Line  = -1;
    this.CurPos.Range = -1;
	this.SetIsRecalculated(true);

    this.FontMap.NeedRecalc = true;

    this.Internal_CheckSpelling();

    var RecalcResult = this.private_RecalculatePage( CurPage );

    this.private_CheckColumnBreak(CurPage);

    this.Parent.RecalcInfo.Reset_WidowControl();

    return RecalcResult;
};

/**
 * Функция для пересчета страницы параграфа, так чтобы на данной странице ничего не было. Применяется, когда из-за
 * пересчета плавающей автофигуры нужно сразу перейти на следующую страницу, пропустив несколько колонок.
 * @param {number} PageIndex - Номер страницы, пересчет которой мы пропускаем. (предыдущая страница ДОЛЖНА быть
 * пересчитана, если это не нулевое значение)
 */
Paragraph.prototype.Recalculate_SkipPage = function(PageIndex)
{
    if (0 === PageIndex)
    {
        this.StartFromNewPage();
    }
    else
    {
        var PrevPage = this.Pages[PageIndex - 1];

        var EndLine       = Math.max(PrevPage.StartLine, PrevPage.EndLine); // На случай, если предыдущая страница тоже пустая
        var NewPage       = new CParaPage(PrevPage.X, PrevPage.Y, PrevPage.XLimit, PrevPage.YLimit, EndLine);
        NewPage.StartLine = EndLine;
        NewPage.EndLine   = EndLine - 1;
        NewPage.TextPr    = PrevPage.TextPr;

        this.Pages[PageIndex] = NewPage;
    }
};

/**
 * Функция для сохранения объекта пересчета.
 * @returns {*} Возвращается объект (CParagraphRecalculateObject) с информацией о текущем пересчете параграфа
 */
Paragraph.prototype.SaveRecalculateObject = function()
{
	var RecalcObj = new CParagraphRecalculateObject();
	RecalcObj.Save(this);
	return RecalcObj;
};

/**
 * Загрузка сохраненного раннее пересчета.
 * @param RecalcObj (CParagraphRecalculateObject)
 */
Paragraph.prototype.LoadRecalculateObject = function(RecalcObj)
{
    RecalcObj.Load(this);
};

/**
 * Очистка рассчетных классов параграфа.
 */
Paragraph.prototype.PrepareRecalculateObject = function()
{
	this.Pages = [];
	this.Lines = [];

	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		this.Content[Index].PrepareRecalculateObject();
	}
};

/**
 * Пересчитываем первую страницу параграфа так, чтобы он начинался с новой страницы.
 */
Paragraph.prototype.StartFromNewPage = function()
{
    this.Pages.length = 1;
    this.Pages[0] = new CParaPage(this.X, this.Y, this.XLimit, this.YLimit, 0);

    // Добавляем разрыв страницы
    this.Pages[0].Set_EndLine(-1);
    this.Lines[-1] = new CParaLine();
};

Paragraph.prototype.private_RecalculateFastRange       = function(CurRange, CurLine)
{
    var PRS = this.m_oPRSW;

    var XStart, YStart, XLimit, YLimit;

    // Определим номер страницы
    var CurPage  = 0;
    var PagesLen = this.Pages.length;
    for ( var TempPage = 0; TempPage < PagesLen; TempPage++ )
    {
        var __Page = this.Pages[TempPage];
        if ( CurLine <= __Page.EndLine && CurLine >= __Page.FirstLine )
        {
            CurPage = TempPage;
            break;
        }
    }

    if ( -1 === CurPage )
        return -1;

    var ParaPr = this.Get_CompiledPr2(false).ParaPr;

    if ( 0 === CurPage )//|| ( undefined != this.Get_FramePr() && this.Parent instanceof CDocument ) )
    {
        XStart = this.X;
        YStart = this.Y;
        XLimit = this.XLimit;
        YLimit = this.YLimit;
    }
    else
    {
        var PageStart = this.Parent.Get_PageContentStartPos2(this.PageNum, this.ColumnNum, CurPage, this.Index);

        XStart = PageStart.X;
        YStart = PageStart.Y;
        XLimit = PageStart.XLimit;
        YLimit = PageStart.YLimit;
    }

    PRS.XStart = XStart;
    PRS.YStart = YStart;
    PRS.XLimit = XLimit - ParaPr.Ind.Right;
    PRS.YLimit = YLimit;

    // Обнуляем параметры PRS для строки и отрезка
    PRS.Reset_Line();

    PRS.Page  = CurPage;
    PRS.Line  = CurLine;
    PRS.Range = CurRange;

    PRS.Ranges      = this.Lines[CurLine].Ranges;
    PRS.RangesCount = this.Lines[CurLine].Ranges.length - 1;

    PRS.Paragraph = this;

    var RangesCount = PRS.RangesCount;

    var Line  = this.Lines[CurLine];
    var Range = Line.Ranges[CurRange];

    var StartPos = Range.StartPos;
    var EndPos   = Range.EndPos;

    // Обновляем состояние пересчета
    PRS.Reset_Range(Range.X, Range.XEnd);

    var ContentLen = this.Content.length;

    for ( var Pos = StartPos; Pos <= EndPos; Pos++ )
    {
        var Item = this.Content[Pos];

        if ( para_Math === Item.Type )
        {
            // TODO: Надо бы перенести эту проверку на изменение контента параграфа
            Item.Set_Inline(true === this.Check_MathPara(Pos)? false : true);
            PRS.bFastRecalculate = true; // чтобы не обновить случайно StartLine (Recalculate_Reset)
        }

        PRS.Update_CurPos( Pos, 0 );

        var SavedLines = Item.SaveRecalculateObject(true);

        Item.Recalculate_Range( PRS, ParaPr, 1 );

        if ( ( true === PRS.NewRange && Pos !== EndPos ) || ( Pos === EndPos && true !== PRS.NewRange ) )
            return -1;
        else if ( Pos === EndPos && true === PRS.NewRange && true === PRS.MoveToLBP )
        {
            var BreakPos = PRS.LineBreakPos.Get(0);
            if (BreakPos !== Pos)
                return -1;
            else
                Item.Recalculate_Set_RangeEndPos(PRS, PRS.LineBreakPos, 1);
        }

        // Нам нужно проверить только строку с номером CurLine
        if (false === SavedLines.Compare(CurLine, CurRange, Item))
            return -1;

        Item.LoadRecalculateObject(SavedLines, this);
    }

    // TODO: Здесь пересчеты идут целиком для строки, а не для конкретного отрезка.
    if (!(this.private_RecalculateLineAlign(CurLine, CurPage, PRS, ParaPr, true) & recalcresult_NextElement))
        return -1;

    return CurPage;
};

Paragraph.prototype.private_RecalculatePage            = function(CurPage, bFirstRecalculate)
{
    var PRS = this.m_oPRSW;
	PRS.Reset_Page(this, CurPage);

	this.m_oPRSW.ComplexFields.ResetPage(this, CurPage);
	this.m_oPRSC.ComplexFields.ResetPage(this, CurPage);
	this.m_oPRSA.ComplexFields.ResetPage(this, CurPage);

    var Pr     = this.Get_CompiledPr();
    var ParaPr = Pr.ParaPr;

    var CurLine = (CurPage > 0 ? this.Pages[CurPage - 1].EndLine + 1 : 0);
    //-------------------------------------------------------------------------------------------------------------
    // Обрабатываем настройку "не отрывать от следующего"
    //-------------------------------------------------------------------------------------------------------------
    if (false === this.private_RecalculatePageKeepNext(CurLine, CurPage, PRS, ParaPr))
        return PRS.RecalcResult;

    //-------------------------------------------------------------------------------------------------------------
    // Получаем начальные координаты параграфа
    //-------------------------------------------------------------------------------------------------------------
    this.private_RecalculatePageXY(CurLine, CurPage, PRS, ParaPr);

    //-------------------------------------------------------------------------------------------------------------
    // Делаем проверки, не нужно ли сразу перенести параграф на новую страницу
    //-------------------------------------------------------------------------------------------------------------
    if (false === this.private_RecalculatePageBreak(CurLine, CurPage, PRS,ParaPr))
	{
		this.Recalculate_PageEndInfo(null, CurPage);
		return PRS.RecalcResult;
	}

    // Изначально обнуляем промежутки обтекания и наличие переноса строки
    PRS.Reset_Ranges();

    if (false !== bFirstRecalculate)
    {
        PRS.Reset_RestartPageRecalcInfo();
        PRS.Reset_MathRecalcInfo();
		PRS.SaveFootnotesInfo();
    }
	else
	{
		PRS.LoadFootnotesInfo();
	}

    var RecalcResult;
    while (true)
    {
        PRS.Line = CurLine;
        PRS.RecalcResult = recalcresult_NextLine;

        this.private_RecalculateLine(CurLine, CurPage, PRS, ParaPr);

        RecalcResult = PRS.RecalcResult;

        if (RecalcResult & recalcresult_NextLine)
        {
            // В эту ветку мы попадаем, если строка пересчиталась в нормальном режиме и можно переходить к следующей.
            CurLine++;
            PRS.Reset_Ranges();
            PRS.Reset_RunRecalcInfo();
            PRS.Reset_MathRecalcInfo();
        }
        else if (RecalcResult & recalcresult_PrevLine)
        {
            if (PRS.Line < this.Pages[CurPage].StartLine)
                PRS.Restore_RunRecalcInfo();
            else
            {
                RecalcResult = this.private_RecalculatePage(CurPage, false);
                break;
            }
        }
        else if (RecalcResult & recalcresult_CurLine)
        {
            // В эту ветку мы попадаем, если нам необходимо заново пересчитать данную строку. Такое случается
            // когда у нас появляются плавающие объекты, относительно которых необходимо произвести обтекание.
            // В данном случае мы ничего не делаем, т.к. номер строки не меняется, а новые отрезки обтекания
            // были заполнены при последнем неудачном рассчете.

            PRS.Restore_RunRecalcInfo();
        }
        else if (RecalcResult & recalcresult_NextElement || RecalcResult & recalcresult_NextPage)
        {
            // В эту ветку мы попадаем, если мы достигли конца страницы или конца параграфа. Просто выходим
            // из цикла.
            break;
        }
        else if (RecalcResult & recalcresult_CurPagePara)
        {
            // В эту ветку мы попадаем, если в параграфе встретилась картинка, которая находится ниже данного
            // параграфа, и можно пересчитать заново данный параграф.
            RecalcResult = this.private_RecalculatePage(CurPage, false);
            break;
        }
        else //if (RecalcResult & recalcresult_CurPage || RecalcResult & recalcresult_PrevPage)
        {
            // В эту ветку мы попадаем, если в нашем параграфе встретилось, что-то из-за чего надо пересчитывать
            // эту страницу или предыдущую страницу. Поэтому далее можно ничего не делать, а сообщать верхнему
            // классу об этом.
            return RecalcResult;
        }
    }

    //-------------------------------------------------------------------------------------------------------------
    // Получаем некоторую информацию для следующей страницы (например незакрытые комментарии)
    //-------------------------------------------------------------------------------------------------------------
    this.Recalculate_PageEndInfo(PRS, CurPage);

    return RecalcResult;
};

Paragraph.prototype.private_RecalculatePageKeepNext    = function(CurLine, CurPage, PRS, ParaPr)
{
    // Такая настройка срабатывает в единственном случае:
    // У предыдущего параграфа выставлена данная настройка, а текущий параграф сразу начинается с новой страницы
    // ( при этом у него не выставлен флаг "начать с новой страницы", иначе будет зацикливание здесь ).
    if (1 === CurPage && true === this.Check_EmptyPages(0) && this.Parent instanceof CDocument && false === ParaPr.PageBreakBefore)
    {
        // Если у предыдущего параграфа стоит настройка "не отрывать от следующего".
        // И сам параграф не разбит на несколько страниц и не начинается с новой страницы,
        // тогда мы должны пересчитать предыдущую страницу, с учетом того, что предыдущий параграф
        // надо начать с новой страницы.
        var Curr = this.Get_DocumentPrev();
        while (null != Curr && type_Paragraph === Curr.GetType() && undefined === Curr.Get_SectionPr())
        {
            var CurrKeepNext = Curr.Get_CompiledPr2(false).ParaPr.KeepNext;
            if ((true === CurrKeepNext && Curr.Pages.length > 1) || false === CurrKeepNext || true !== Curr.Is_Inline() || true === Curr.Check_PageBreak())
            {
                break;
            }
            else
            {
                var Prev = Curr.Get_DocumentPrev();
                if (null === Prev || (type_Paragraph === Prev.GetType() && undefined !== Prev.Get_SectionPr()))
                    break;

                if (type_Paragraph != Prev.GetType() || false === Prev.Get_CompiledPr2(false).ParaPr.KeepNext)
                {
                    if (true === this.Parent.RecalcInfo.Can_RecalcObject())
                    {
                        this.Parent.RecalcInfo.Set_KeepNext(Curr, this);
                        PRS.RecalcResult = recalcresult_PrevPage | recalcresultflags_Column;
                        return false;
                    }
                    else
                        break;
                }
                else
                {
                    Curr = Prev;
                }
            }
        }
    }

    if (true === this.Parent.RecalcInfo.Check_KeepNextEnd(this))
    {
        // Дошли до сюда, значит уже пересчитали данную ситуацию.
        // Делаем Reset здесь, потому что Reset надо делать в том же месте, гды мы запросили пересчет заново.
        this.Parent.RecalcInfo.Reset();
    }

    return true;
};

Paragraph.prototype.private_RecalculatePageXY          = function(CurLine, CurPage, PRS, ParaPr)
{
    // Если это первая страница параграфа (CurPage = 0), тогда мы должны использовать координаты, которые нам
    // были заданы сверху, а если не первая, тогда координаты мы должны запросить у родительского класса.
    // TODO: Тут отдельно обрабатывается случай, когда рамка переносится на новую страницу, т.е. страница начинается
    //       сразу с рамки. Надо бы не разбивать в данной ситуации рамку на страницы, а просто новую страницу начать
    //       с нее на уровне DocumentContent.

    var XStart, YStart, XLimit, YLimit;
    if ( 0 === CurPage || ( undefined != this.Get_FramePr() && this.LogicDocument === this.Parent ) )
    {
        XStart = this.X;
        YStart = this.Y;
        XLimit = this.XLimit;
        YLimit = this.YLimit;
    }
    else
    {
        var PageStart = this.Parent.Get_PageContentStartPos2(this.PageNum, this.ColumnNum, CurPage, this.Index);

        XStart = PageStart.X;
        YStart = PageStart.Y;
        XLimit = PageStart.XLimit;
        YLimit = PageStart.YLimit;
    }

    PRS.XStart = XStart;
    PRS.YStart = YStart;
    PRS.XLimit = XLimit - ParaPr.Ind.Right;
    PRS.YLimit = YLimit;
    PRS.Y      = YStart;

    this.Pages.length   = CurPage + 1;
    this.Pages[CurPage] = new CParaPage(XStart, YStart, XLimit, YLimit, CurLine);
};

Paragraph.prototype.private_RecalculatePageBreak       = function(CurLine, CurPage, PRS, ParaPr)
{
	// Для пустых параграфов с разрывом секции не делаем переноса страницы
	if (undefined !== this.Get_SectionPr() && true === this.IsEmpty())
		return true;

	var isParentDocument = this.Parent instanceof CDocument;
	var isParentBlockSdt = this.Parent instanceof CDocumentContent
		&& this.Parent.Parent instanceof CBlockLevelSdt
		&& PRS.GetTopDocument() instanceof CDocument
		&& !PRS.IsInTable();

    if (isParentDocument || isParentBlockSdt)
    {
        // Начинаем параграф с новой страницы
        var PageRelative = this.private_GetRelativePageIndex(CurPage) - this.Get_StartPage_Relative();
        if (0 === PageRelative && true === ParaPr.PageBreakBefore)
        {
            // Если это первый элемент документа или секции, тогда не надо начинать его с новой страницы.
            // Кроме случая, когда у нас разрыв секции на текущей странице. Также не добавляем разрыв страницы для
            // особого пустого параграфа с разрывом секции.

            var bNeedPageBreak = true;

			var Prev = this.Get_DocumentPrev();
			if (!Prev && isParentBlockSdt)
			{
				var oSdt = this.Parent.Parent;
				while (oSdt instanceof CBlockLevelSdt)
				{
					Prev = oSdt.Get_DocumentPrev();
					if (Prev)
						break;

					if (oSdt.Parent instanceof CDocumentContent && oSdt.Parent.Parent instanceof CBlockLevelSdt)
						oSdt = oSdt.Parent.Parent;
					else
						oSdt = null;
				}
			}

			while (Prev && (Prev instanceof CBlockLevelSdt))
				Prev = Prev.GetLastElement();

            if ((true === this.IsEmpty() && undefined !== this.Get_SectionPr()) || null === Prev)
            {
                bNeedPageBreak = false;
            }
            else if (this.Parent === this.LogicDocument && type_Paragraph === Prev.GetType() && undefined !== Prev.Get_SectionPr())
            {
                var PrevSectPr = Prev.Get_SectionPr();
                var CurSectPr = this.LogicDocument.SectionsInfo.Get_SectPr(this.Index).SectPr;
                if (c_oAscSectionBreakType.Continuous !== CurSectPr.Get_Type() || true !== CurSectPr.Compare_PageSize(PrevSectPr))
                    bNeedPageBreak = false;
            }

            if (true === bNeedPageBreak)
            {
                // Добавляем разрыв страницы
                this.Pages[CurPage].Set_EndLine(CurLine - 1);

                if (0 === CurLine)
                    this.Lines[-1] = new CParaLine();

                PRS.RecalcResult = recalcresult_NextPage | recalcresultflags_Column;
                return false;
            }
        }
        else if (isParentDocument && true === this.Parent.RecalcInfo.Check_KeepNext(this) && 0 === CurPage && null != this.Get_DocumentPrev())
        {
            this.Pages[CurPage].Set_EndLine( CurLine - 1 );
            if ( 0 === CurLine )
                this.Lines[-1] = new CParaLine( 0 );

            PRS.RecalcResult = recalcresult_NextPage;
            return false;
        }
        else if (true === this.Is_Inline()) // Случай Flow разбирается в Document.js
        {
            // Проверяем PageBreak и ColumnBreak в предыдущей строке
            var isPageBreakOnPrevLine   = false;
            var isColumnBreakOnPrevLine = false;

            var PrevElement = this.Get_DocumentPrev();
            if (!PrevElement && isParentBlockSdt)
			{
				var oSdt = this.Parent.Parent;
				while (oSdt instanceof CBlockLevelSdt)
				{
					PrevElement = oSdt.Get_DocumentPrev();
					if (PrevElement)
						break;

					if (oSdt.Parent instanceof CDocumentContent && oSdt.Parent.Parent instanceof CBlockLevelSdt)
						oSdt = oSdt.Parent.Parent;
					else
						oSdt = null;
				}
			}

			while (PrevElement && (PrevElement instanceof CBlockLevelSdt))
				PrevElement = PrevElement.GetLastElement();

            if (null !== PrevElement && type_Paragraph === PrevElement.Get_Type() && true === PrevElement.Is_Empty() && undefined !== PrevElement.Get_SectionPr())
			{
				var PrevSectPr = PrevElement.Get_SectionPr();
				var CurSectPr  = this.LogicDocument.SectionsInfo.Get_SectPr(this.Index).SectPr;
				if (c_oAscSectionBreakType.Continuous === CurSectPr.Get_Type() && true === CurSectPr.Compare_PageSize(PrevSectPr))
					PrevElement = PrevElement.Get_DocumentPrev();
			}

			if (0 !== CurPage && true !== this.Check_EmptyPages(CurPage - 1))
			{
				var EndLine = this.Pages[CurPage - 1].EndLine;
				if (-1 !== EndLine && this.Lines[EndLine].Info & paralineinfo_BreakRealPage)
					isPageBreakOnPrevLine = true;
			}
			else if (null !== PrevElement && type_Paragraph === PrevElement.Get_Type())
			{
				var bNeedPageBreak = true;
				if (type_Paragraph === PrevElement.GetType() && undefined !== PrevElement.Get_SectionPr())
				{
					var PrevSectPr = PrevElement.Get_SectionPr();
					var CurSectPr  = this.LogicDocument.SectionsInfo.Get_SectPr(this.Index).SectPr;
					if (c_oAscSectionBreakType.Continuous !== CurSectPr.Get_Type() || true !== CurSectPr.Compare_PageSize(PrevSectPr))
						bNeedPageBreak = false;
				}

				if (true === bNeedPageBreak)
				{
					var EndLine = PrevElement.Pages[PrevElement.Pages.length - 1].EndLine;
					if (-1 !== EndLine && PrevElement.Lines[EndLine].Info & paralineinfo_BreakRealPage)
						isPageBreakOnPrevLine = true;
				}
			}

            // ColumnBreak для случая CurPage > 0 не разбираем здесь, т.к. он срабатывает автоматически
            if (0 === CurPage && null !== PrevElement && type_Paragraph === PrevElement.Get_Type())
            {
                var EndLine = PrevElement.Pages[PrevElement.Pages.length - 1].EndLine;
                if (-1 !== EndLine && !(PrevElement.Lines[EndLine].Info & paralineinfo_BreakRealPage) && PrevElement.Lines[EndLine].Info & paralineinfo_BreakPage)
                    isColumnBreakOnPrevLine = true;
            }

            // Здесь используем GetAbsoluteColumn, а не у текущего класса, т.к. в данную ветку мы попадаем только, если
			// верхний DocContent - документ и если не в таблице
            if ((true === isPageBreakOnPrevLine && (0 !== this.GetAbsoluteColumn(CurPage) || (0 === CurPage && null !== PrevElement)))
                || (true === isColumnBreakOnPrevLine && 0 === CurPage))
            {
                this.Pages[CurPage].Set_EndLine(CurLine - 1);

                if (0 === CurLine)
                    this.Lines[-1] = new CParaLine();

                PRS.RecalcResult = recalcresult_NextPage | recalcresultflags_Column;
                return false;
            }
        }
    }

    return true;
};

Paragraph.prototype.private_RecalculateLine            = function(CurLine, CurPage, PRS, ParaPr)
{
    // При пересчете любой строки обновляем эти поля
    this.ParaEnd.Line  = -1;
    this.ParaEnd.Range = -1;

    //-------------------------------------------------------------------------------------------------------------
    // 1. Добавляем новую строку в параграф
    //-------------------------------------------------------------------------------------------------------------
    this.Lines.length   = CurLine + 1;
    this.Lines[CurLine] = new CParaLine();

    //-------------------------------------------------------------------------------------------------------------
    // 2. Проверяем, является ли данная строка висячей
    //-------------------------------------------------------------------------------------------------------------
    if (false === this.private_RecalculateLineWidow(CurLine, CurPage, PRS, ParaPr))
        return;

    //-------------------------------------------------------------------------------------------------------------
    // 3. Заполняем строку отрезками обтекания
    //-------------------------------------------------------------------------------------------------------------
    this.private_RecalculateLineFillRanges(CurLine, CurPage, PRS, ParaPr);

    //-------------------------------------------------------------------------------------------------------------
    // 4. Пересчитываем отрезки данной строки
    //-------------------------------------------------------------------------------------------------------------
    if (false === this.private_RecalculateLineRanges(CurLine, CurPage, PRS, ParaPr))
        return;

    //-------------------------------------------------------------------------------------------------------------
    // 5. Заполняем информацию о строке
    //-------------------------------------------------------------------------------------------------------------
    this.private_RecalculateLineInfo(CurLine, CurPage, PRS, ParaPr);

    //-------------------------------------------------------------------------------------------------------------
    // 6. Пересчитываем метрики данной строки
    //-------------------------------------------------------------------------------------------------------------
    this.private_RecalculateLineMetrics(CurLine, CurPage, PRS, ParaPr);

    //-------------------------------------------------------------------------------------------------------------
    // 7. Рассчитываем высоту строки, а также положение верхней и нижней границ
    //-------------------------------------------------------------------------------------------------------------
    this.private_RecalculateLinePosition(CurLine, CurPage, PRS, ParaPr);

    //-------------------------------------------------------------------------------------------------------------
    // 8. Проверяем достигла ли данная строка конца страницы
    //-------------------------------------------------------------------------------------------------------------
    if (false === this.private_RecalculateLineBottomBound(CurLine, CurPage, PRS, ParaPr))
        return;

    //-------------------------------------------------------------------------------------------------------------
    // 9. Проверяем обтекание данной строки относительно плавающих объектов
    //-------------------------------------------------------------------------------------------------------------
    if (false === this.private_RecalculateLineCheckRanges(CurLine, CurPage, PRS, ParaPr))
        return;

    //-------------------------------------------------------------------------------------------------------------
    // 10. Выставляем вертикальное смещение данной строки
    //-------------------------------------------------------------------------------------------------------------
    this.private_RecalculateLineBaseLine(CurLine, CurPage, PRS, ParaPr);

    //-------------------------------------------------------------------------------------------------------------
    // 11. Проверяем не съехала ли вся строка из-за обтекания
    //-------------------------------------------------------------------------------------------------------------
    if (false === this.private_RecalculateLineCheckRangeY(CurLine, CurPage, PRS, ParaPr))
        return;

    //-------------------------------------------------------------------------------------------------------------
    // 12. Пересчитываем сдвиги элементов внутри параграфа и видимые ширины пробелов, в зависимости от align.
    //-------------------------------------------------------------------------------------------------------------
    if (!(this.private_RecalculateLineAlign(CurLine, CurPage, PRS, ParaPr, false) & recalcresult_NextElement))
        return;

    //-------------------------------------------------------------------------------------------------------------
    // 13. Последние проверки
    //-------------------------------------------------------------------------------------------------------------
    if (false === this.private_RecalculateLineEnd(CurLine, CurPage, PRS, ParaPr))
        return;

    //-------------------------------------------------------------------------------------------------------------
    // 14. Проверяем Последние проверки
    //-------------------------------------------------------------------------------------------------------------
    if (false === this.private_RecalculateLineCheckFootnotes(CurLine, CurPage, PRS, ParaPr))
        return;
};

Paragraph.prototype.private_RecalculateLineWidow       = function(CurLine, CurPage, PRS, ParaPr)
{
    // Висячие строки обрабатываются только внутри основного документа
    if ( this.Parent instanceof CDocument && true === this.Parent.RecalcInfo.Check_WidowControl(this, CurLine) )
    {
        this.Parent.RecalcInfo.Need_ResetWidowControl();

        this.Pages[CurPage].Set_EndLine(CurLine - 1);
        if (0 === CurLine)
        {
            this.Lines[-1] = new CParaLine(0);
        }

        PRS.RecalcResult = recalcresult_NextPage | recalcresultflags_Column;
        return false;
    }

    return true;
};

Paragraph.prototype.private_RecalculateLineFillRanges  = function(CurLine, CurPage, PRS, ParaPr)
{
    this.Lines[CurLine].Info = 0;

    // Параметры Ranges и RangesCount не обнуляются здесь, они задаются выше
    var Ranges      = PRS.Ranges;
    var RangesCount = PRS.RangesCount;

    // Обнуляем параметры PRS для строки
    PRS.Reset_Line();

    // Проверим, нужно ли в данной строке учитывать FirstLine (т.к. не всегда это первая строка должна быть)
    var UseFirstLine = true;
    for ( var TempCurLine = CurLine - 1; TempCurLine >= 0; TempCurLine-- )
    {
        var TempInfo = this.Lines[TempCurLine].Info;
        if (!(TempInfo & paralineinfo_BreakPage) || !(TempInfo & paralineinfo_Empty))
        {
            UseFirstLine = false;
            break;
        }
    }

    // Проверим неинлайн формулу в первой строке
    if (0 === CurLine && true === UseFirstLine)
    {
        var CurPos = 0;
        var Count = this.Content.length;
        while (CurPos < Count)
        {
            if (true === this.Check_MathPara(CurPos))
            {
                UseFirstLine = false;
                break;
            }
            else if (true !== this.Content[CurPos].Is_Empty())
            {
                break;
            }

            CurPos++;
        }
    }

    PRS.UseFirstLine = UseFirstLine;

    // Заполняем строку отрезками обтекания. Выставляем начальные сдвиги для отрезков. Начало промежутка = конец вырезаемого промежутка
    this.Lines[CurLine].Reset();
    this.Lines[CurLine].Add_Range( ( true === UseFirstLine ? PRS.XStart + ParaPr.Ind.Left + ParaPr.Ind.FirstLine : PRS.XStart + ParaPr.Ind.Left ), (RangesCount == 0 ? PRS.XLimit : Ranges[0].X0) );
    for ( var Index = 1; Index < Ranges.length + 1; Index++ )
    {
        this.Lines[CurLine].Add_Range( Ranges[Index - 1].X1, (RangesCount == Index ? PRS.XLimit : Ranges[Index].X0) );
    }

    if (true === PRS.RangeY)
    {
        PRS.RangeY = false;
        this.Lines[CurLine].Info |= paralineinfo_RangeY;
    }
};

Paragraph.prototype.private_RecalculateLineRanges      = function(CurLine, CurPage, PRS, ParaPr)
{
    var RangesCount = PRS.RangesCount;
    var CurRange = 0;
    while ( CurRange <= RangesCount )
    {
        PRS.Range = CurRange;
        this.private_RecalculateRange(CurRange, CurLine, CurPage, RangesCount, PRS, ParaPr);

        if ( true === PRS.ForceNewPage || true === PRS.NewPage || true === PRS.ForceNewLine )
        {
            // Поскольку мы выходим досрочно из цикла, нам надо удалить лишние отрезки обтекания
            this.Lines[CurLine].Ranges.length = CurRange + 1;
            break;
        }

        if ( -1 === this.ParaEnd.Line && true === PRS.End )
        {
            this.ParaEnd.Line  = CurLine;
            this.ParaEnd.Range = CurRange;
        }

        // Такое может случиться, если мы насильно переносим автофигуру на следующую страницу
        if (PRS.RecalcResult & recalcresult_NextPage || PRS.RecalcResult & recalcresult_PrevLine || PRS.RecalcResult & recalcresult_CurLine || PRS.RecalcResult & recalcresult_CurPagePara)
            return false;

        CurRange++;
    }

    return true;
};

Paragraph.prototype.private_RecalculateLineInfo        = function(CurLine, CurPage, PRS, ParaPr)
{
    if (true === PRS.BreakPageLine)
        this.Lines[CurLine].Info |= paralineinfo_BreakPage;

    if (true === PRS.BreakRealPageLine)
        this.Lines[CurLine].Info |= paralineinfo_BreakRealPage;

    if (true === PRS.EmptyLine)
        this.Lines[CurLine].Info |= paralineinfo_Empty;

    if (true === PRS.End)
        this.Lines[CurLine].Info |= paralineinfo_End;

    if (true === PRS.BadLeftTab)
        this.Lines[CurLine].Info |= paralineinfo_BadLeftTab;

    if (PRS.GetFootnoteReferencesCount(null, true) > 0)
    	this.Lines[CurLine].Info |= paralineinfo_Notes;

    if (true === PRS.TextOnLine)
    	this.Lines[CurLine].Info |= paralineinfo_TextOnLine;
};

Paragraph.prototype.private_RecalculateLineMetrics     = function(CurLine, CurPage, PRS, ParaPr)
{
    var Line = this.Lines[CurLine];
    var RangesCount = Line.Ranges.length;

    for (var CurRange = 0; CurRange < RangesCount; CurRange++)
    {
        var Range = Line.Ranges[CurRange];

        var StartPos = Range.StartPos;
        var EndPos   = Range.EndPos;

        for (var Pos = StartPos; Pos <= EndPos; Pos++)
        {
            this.Content[Pos].Recalculate_LineMetrics(PRS, ParaPr, CurLine, CurRange);
        }
    }

    // Строка пустая, у нее надо выставить ненулевую высоту. Делаем как Word, выставляем высоту по размеру
    // текста, на котором закончилась данная строка.
    if ( true === PRS.EmptyLine || PRS.LineAscent < 0.001 || (true === PRS.End && true !== PRS.TextOnLine))
	{
		var LastItem = (true === PRS.End ? this.Content[this.Content.length - 1] : this.Content[this.Lines[CurLine].Ranges[this.Lines[CurLine].Ranges.length - 1].EndPos]);

		if (true === PRS.End)
		{
			// TODO: Как только переделаем para_End переделать тут

			// Выставляем настройки для символа параграфа
			var EndTextPr = this.Get_CompiledPr2(false).TextPr.Copy();
			EndTextPr.Merge(this.TextPr.Value);

			g_oTextMeasurer.SetTextPr(EndTextPr, this.Get_Theme());
			g_oTextMeasurer.SetFontSlot(fontslot_ASCII);

			// Запрашиваем текущие метрики шрифта, под TextAscent мы будем понимать ascent + linegap(которые записаны в шрифте)
			var EndTextHeight  = g_oTextMeasurer.GetHeight();
			var EndTextDescent = Math.abs(g_oTextMeasurer.GetDescender());
			var EndTextAscent  = EndTextHeight - EndTextDescent;
			var EndTextAscent2 = g_oTextMeasurer.GetAscender();

			PRS.LineTextAscent  = EndTextAscent;
			PRS.LineTextAscent2 = EndTextAscent2;
			PRS.LineTextDescent = EndTextDescent;

			if (PRS.LineAscent < EndTextAscent)
				PRS.LineAscent = EndTextAscent;

			if (PRS.LineDescent < EndTextDescent)
				PRS.LineDescent = EndTextDescent;
		}
		else if (undefined !== LastItem)
		{
			var LastRun = LastItem.Get_LastRunInRange(PRS.Line, PRS.Range);
			if (undefined !== LastRun && null !== LastRun)
			{
				if (PRS.LineTextAscent < LastRun.TextAscent)
					PRS.LineTextAscent = LastRun.TextAscent;

				if (PRS.LineTextAscent2 < LastRun.TextAscent2)
					PRS.LineTextAscent2 = LastRun.TextAscent2;

				if (PRS.LineTextDescent < LastRun.TextDescent)
					PRS.LineTextDescent = LastRun.TextDescent;

				if (PRS.LineAscent < LastRun.TextAscent)
					PRS.LineAscent = LastRun.TextAscent;

				if (PRS.LineDescent < LastRun.TextDescent)
					PRS.LineDescent = LastRun.TextDescent;
			}
		}
	}

    // Рассчитаем метрики строки
    this.Lines[CurLine].Metrics.Update( PRS.LineTextAscent, PRS.LineTextAscent2, PRS.LineTextDescent, PRS.LineAscent, PRS.LineDescent, ParaPr );

	if (true === PRS.End && true !== PRS.EmptyLine && true !== PRS.TextOnLine && Math.abs(this.Lines[CurLine].Metrics.Descent - this.Lines[CurLine].Metrics.TextDescent) < 0.001)
		this.Lines[CurLine].Metrics.Descent = 0;
};

Paragraph.prototype.private_RecalculateLinePosition    = function(CurLine, CurPage, PRS, ParaPr)
{
    var BaseLineOffset = 0;
    if (CurLine === this.Pages[CurPage].FirstLine)
    {
        BaseLineOffset = this.Lines[CurLine].Metrics.Ascent;

        if (this.Check_FirstPage(CurPage, true))
        {
			// Добавляем расстояние до параграфа (Pr.Spacing.Before)
			if (this.private_CheckNeedBeforeSpacing(CurPage, PRS, ParaPr))
				BaseLineOffset += ParaPr.Spacing.Before;

            // Добавляем толщину границы параграфа (если граница задана)
            if ((true === ParaPr.Brd.First || 1 === CurPage) && border_Single === ParaPr.Brd.Top.Value)
                BaseLineOffset += ParaPr.Brd.Top.Size + ParaPr.Brd.Top.Space;
            else if (false === ParaPr.Brd.First && border_Single === ParaPr.Brd.Between.Value)
                BaseLineOffset += ParaPr.Brd.Between.Size + ParaPr.Brd.Between.Space;
        }

        PRS.BaseLineOffset = BaseLineOffset;
    }
    else
	{
		if (this.Lines[CurLine].Info & paralineinfo_RangeY)
			PRS.BaseLineOffset = this.Lines[CurLine].Metrics.Ascent;
		else
			BaseLineOffset = PRS.BaseLineOffset;
	}

    var Top, Bottom;
    var Top2, Bottom2; // верх и низ без Pr.Spacing

    var PrevBottom = this.Pages[CurPage].Bounds.Bottom;

    if (this.Lines[CurLine].Info & paralineinfo_RangeY)
    {
        Top  = PRS.Y;
        Top2 = PRS.Y;

        if (CurLine === this.Pages[CurPage].FirstLine && this.Check_FirstPage(CurPage, true))
        {
			if (this.private_CheckNeedBeforeSpacing(CurPage, PRS, ParaPr))
            {
                Top2    = Top + ParaPr.Spacing.Before;
                Bottom2 = Top + ParaPr.Spacing.Before + this.Lines[0].Metrics.Ascent + this.Lines[0].Metrics.Descent;

                if ( true === ParaPr.Brd.First && border_Single === ParaPr.Brd.Top.Value )
                {
                    Top2    += ParaPr.Brd.Top.Size + ParaPr.Brd.Top.Space;
                    Bottom2 += ParaPr.Brd.Top.Size + ParaPr.Brd.Top.Space;
                }
                else if ( false === ParaPr.Brd.First && border_Single === ParaPr.Brd.Between.Value )
                {
                    Top2    += ParaPr.Brd.Between.Size + ParaPr.Brd.Between.Space;
                    Bottom2 += ParaPr.Brd.Between.Size + ParaPr.Brd.Between.Space;
                }
            }
            else
            {
                // Параграф начинается с новой страницы
                Bottom2 = Top + this.Lines[0].Metrics.Ascent + this.Lines[0].Metrics.Descent;

                if ( border_Single === ParaPr.Brd.Top.Value )
                {
                    Top2    += ParaPr.Brd.Top.Size + ParaPr.Brd.Top.Space;
                    Bottom2 += ParaPr.Brd.Top.Size + ParaPr.Brd.Top.Space;
                }
            }
        }
        else
        {
            Bottom2 = Top + this.Lines[CurLine].Metrics.Ascent + this.Lines[CurLine].Metrics.Descent;
        }
    }
    else
    {
        if (CurLine !== this.Pages[CurPage].FirstLine || !this.Check_FirstPage(CurPage, true))
        {
            if ( CurLine !== this.Pages[CurPage].FirstLine )
            {
                Top     = PRS.Y + BaseLineOffset + this.Lines[CurLine - 1].Metrics.Descent + this.Lines[CurLine - 1].Metrics.LineGap;
                Top2    = Top;
                Bottom2 = Top + this.Lines[CurLine].Metrics.Ascent + this.Lines[CurLine].Metrics.Descent;
            }
            else
            {
                Top     = this.Pages[CurPage].Y;
                Top2    = Top;
                Bottom2 = Top + this.Lines[CurLine].Metrics.Ascent + this.Lines[CurLine].Metrics.Descent;
            }
        }
        else
        {
            Top  = PRS.Y;
            Top2 = PRS.Y;

			if (this.private_CheckNeedBeforeSpacing(CurPage, PRS, ParaPr))
            {
                Top2    = Top + ParaPr.Spacing.Before;
                Bottom2 = Top + ParaPr.Spacing.Before + this.Lines[CurLine].Metrics.Ascent + this.Lines[CurLine].Metrics.Descent;

                if ( true === ParaPr.Brd.First && border_Single === ParaPr.Brd.Top.Value )
                {
                    Top2    += ParaPr.Brd.Top.Size + ParaPr.Brd.Top.Space;
                    Bottom2 += ParaPr.Brd.Top.Size + ParaPr.Brd.Top.Space;
                }
                else if ( false === ParaPr.Brd.First && border_Single === ParaPr.Brd.Between.Value )
                {
                    Top2    += ParaPr.Brd.Between.Size + ParaPr.Brd.Between.Space;
                    Bottom2 += ParaPr.Brd.Between.Size + ParaPr.Brd.Between.Space;
                }
            }
            else
            {
                // Параграф начинается с новой страницы
                Bottom2 = Top + this.Lines[CurLine].Metrics.Ascent + this.Lines[CurLine].Metrics.Descent;

                if ( border_Single === ParaPr.Brd.Top.Value )
                {
                    Top2    += ParaPr.Brd.Top.Size + ParaPr.Brd.Top.Space;
                    Bottom2 += ParaPr.Brd.Top.Size + ParaPr.Brd.Top.Space;
                }
            }
        }
    }

    Bottom  = Bottom2;
    Bottom += this.Lines[CurLine].Metrics.LineGap;

    // Если данная строка последняя, тогда подкорректируем нижнюю границу
    if ( true === PRS.End )
    {
        Bottom += ParaPr.Spacing.After;

        // Если нижняя граница Between, тогда она учитывается в следующем параграфе
        if ( true === ParaPr.Brd.Last && border_Single === ParaPr.Brd.Bottom.Value )
        {
            Bottom += ParaPr.Brd.Bottom.Size + ParaPr.Brd.Bottom.Space;
        }
        else if ( border_Single === ParaPr.Brd.Between.Value )
        {
            Bottom += ParaPr.Brd.Between.Space;
        }

		// TODO: Здесь нужно сделать корректировку YLimit с учетом сносок. Надо разобраться почему вообще здесь
		// используется this.YLimit вместо Page.YLimit

        if ( false === this.Parent.IsTableCellContent() && Bottom > this.YLimit && Bottom - this.YLimit <= ParaPr.Spacing.After )
            Bottom = this.YLimit;
    }

    // Верхнюю границу мы сохраняем только для первой строки данной страницы
    if (CurLine === this.Pages[CurPage].FirstLine && !(this.Lines[CurLine].Info & paralineinfo_RangeY))
        this.Pages[CurPage].Bounds.Top = Top;

    this.Pages[CurPage].Bounds.Bottom = Bottom;

    this.Lines[CurLine].Top    = Top    - this.Pages[CurPage].Y;
    this.Lines[CurLine].Bottom = Bottom - this.Pages[CurPage].Y;

    PRS.LineTop        = AscCommon.CorrectMMToTwips(Top);
    PRS.LineBottom     = AscCommon.CorrectMMToTwips(Bottom);
    PRS.LineTop2       = AscCommon.CorrectMMToTwips(Top2);
    PRS.LineBottom2    = AscCommon.CorrectMMToTwips(Bottom2);
    PRS.LinePrevBottom = AscCommon.CorrectMMToTwips(PrevBottom);
};

Paragraph.prototype.private_RecalculateLineBottomBound = function(CurLine, CurPage, PRS, ParaPr)
{
    var Top     = PRS.LineTop;
    var Bottom2 = PRS.LineBottom2;

    // В ячейке перенос страницы происходит по нижней границе, т.е. с учетом Spacing.After и границы
    if ( true === this.Parent.IsTableCellContent() )
        Bottom2 = PRS.LineBottom;

    // Переносим строку по PageBreak. Если в строке ничего нет кроме PageBreak, и это не конец параграфа, тогда нам не надо проверять высоту строки и обтекание.
    var LineInfo = this.Lines[CurLine].Info;
    var BreakPageLineEmpty = (LineInfo & paralineinfo_BreakPage && LineInfo & paralineinfo_Empty && !(LineInfo & paralineinfo_End) ? true : false);
    PRS.BreakPageLineEmpty = BreakPageLineEmpty;

    var RealCurPage = this.private_GetRelativePageIndex(CurPage) - this.Get_StartPage_Relative();

    var YLimit = PRS.YLimit;
    var oTopDocument = PRS.TopDocument;
	var bNoFootnotes = true;
	if (oTopDocument instanceof CDocument)
	{
		// bNoFootnotes - означает есть или нет сноска на данной колонке
		var nHeight =  oTopDocument.Footnotes.GetHeight(PRS.PageAbs, PRS.ColumnAbs);
		if (nHeight > 0.001)
		{
			bNoFootnotes = false;

			// В таблицах граница разруливается по своему
			if (true !== PRS.IsInTable())
				YLimit -= nHeight;
		}
	}
    else if (oTopDocument instanceof CFootEndnote)
    {
		// bNoFootnotes - означает, первая или нет данная сноска в колонке. Если она не первая,
		// тогда если у нее не убирается первая строка первого параграфа, все равно надо делать перенос
        var oLogicDocument = this.LogicDocument;
        if (true !== oLogicDocument.Footnotes.IsEmptyPageColumn(PRS.PageAbs, PRS.ColumnAbs))
			bNoFootnotes = false;
    }

    // Сначала проверяем не нужно ли сделать перенос страницы в данном месте
    // Перенос не делаем, если это первая строка на новой странице
    if (true === this.Use_YLimit()
		&& (Top > YLimit || Bottom2 > YLimit)
		&& (CurLine != this.Pages[CurPage].FirstLine
		|| false === bNoFootnotes
		|| (0 === RealCurPage && (null != this.Get_DocumentPrev()
		|| (true === this.Parent.IsTableCellContent() && true !== this.Parent.IsTableFirstRowOnNewPage())
		|| (true === this.Parent.IsBlockLevelSdtContent() && true !== this.Parent.IsBlockLevelSdtFirstOnNewPage()))))
		&& false === BreakPageLineEmpty)
    {
		this.private_RecalculateMoveLineToNextPage(CurLine, CurPage, PRS, ParaPr);
		return false;
    }

    return true;
};

Paragraph.prototype.private_RecalculateLineCheckRanges = function(CurLine, CurPage, PRS, ParaPr)
{
    var Right   = this.Pages[CurPage].XLimit - ParaPr.Ind.Right;
    var Top     = PRS.LineTop;
    var Bottom  = PRS.LineBottom;
    var Top2    = PRS.LineTop2;
    var Bottom2 = PRS.LineBottom2;

    var Left;

    if(true === PRS.MathNotInline)
        Left = this.Pages[CurPage].X;
    else
        Left = false === PRS.UseFirstLine ? this.Pages[CurPage].X + ParaPr.Ind.Left : this.Pages[CurPage].X + ParaPr.Ind.Left + ParaPr.Ind.FirstLine;

	var PageFields = null;
    if (this.bFromDocument && PRS.GetTopDocument() === this.LogicDocument && !PRS.IsInTable())
	{
		// Заглушка для случая, когда параграф лежит в CBlockLevelSdt
		PageFields = this.LogicDocument.Get_ColumnFields(PRS.GetTopIndex(), this.Get_AbsoluteColumn(CurPage));
	}
	else
	{
		PageFields = this.Parent.Get_ColumnFields ? this.Parent.Get_ColumnFields(this.Get_Index(), this.Get_AbsoluteColumn(CurPage)) : this.Parent.Get_PageFields(this.private_GetRelativePageIndex(CurPage));
	}

    var Ranges = PRS.Ranges;
    var Ranges2;

    for (var nIndex = 0, nCount = Ranges.length; nIndex < nCount; ++nIndex)
	{
		Ranges[nIndex].Y1 = AscCommon.CorrectMMToTwips(Ranges[nIndex].Y1);
	}

    if ( true === this.Use_Wrap() )
        Ranges2 = this.Parent.CheckRange(Left, Top, Right, Bottom, Top2, Bottom2, PageFields.X, PageFields.XLimit, this.private_GetRelativePageIndex(CurPage), true, PRS.MathNotInline);
    else
        Ranges2 = [];

    // Проверяем совпали ли промежутки. Если совпали, тогда данная строчка рассчитана верно, и мы переходим к
    // следующей, если нет, тогда заново рассчитываем данную строчку, но с новыми промежутками.
    // Заметим, что тут возможен случай, когда Ranges2 меньше, чем Ranges, такое может случится при повторном
    // обсчете строки. (После первого расчета мы выяснили что Ranges < Ranges2, при повторном обсчете строки, т.к.
    // она стала меньше, то у нее и рассчитанная высота могла уменьшиться, а значит Ranges2 могло оказаться
    // меньше чем Ranges). В таком случае не надо делать повторный пересчет, иначе будет зависание.
    if (-1 === FlowObjects_CompareRanges(Ranges, Ranges2) && true === FlowObjects_CheckInjection(Ranges, Ranges2) && false === PRS.BreakPageLineEmpty)
    {
        // Выставляем новые отрезки обтекания и сообщаем, что надо заново персчитать данную строку
        PRS.Ranges       = Ranges2;
        PRS.RangesCount  = Ranges2.length;
        PRS.RecalcResult = recalcresult_CurLine;

        if (this.Lines[CurLine].Info & paralineinfo_RangeY)
            PRS.RangeY = true;

        return false;
    }

    return true;
};

Paragraph.prototype.private_RecalculateLineBaseLine    = function(CurLine, CurPage, PRS, ParaPr)
{
    if (this.Lines[CurLine].Info & paralineinfo_RangeY)
    {
        this.Lines[CurLine].Y = PRS.Y - this.Pages[CurPage].Y;
    }
    else
    {
        if (CurLine > 0)
        {
            // Первая линия на странице не должна двигаться
            if (CurLine != this.Pages[CurPage].FirstLine && ( true === PRS.End || true !== PRS.EmptyLine || PRS.RangesCount <= 0 || true === PRS.NewPage  ))
                PRS.Y += this.Lines[CurLine - 1].Metrics.Descent + this.Lines[CurLine - 1].Metrics.LineGap + this.Lines[CurLine].Metrics.Ascent;

            this.Lines[CurLine].Y = PRS.Y - this.Pages[CurPage].Y;
        }
        else
            this.Lines[0].Y = 0;
    }

    this.Lines[CurLine].Y += PRS.BaseLineOffset;
    if (this.Lines[CurLine].Metrics.LineGap < 0)
        this.Lines[CurLine].Y += this.Lines[CurLine].Metrics.LineGap;
};

Paragraph.prototype.private_RecalculateLineCheckRangeY = function(CurLine, CurPage, PRS, ParaPr)
{
    // Такое случается, когда у нас после пересчета Flow картинки, место к которому она была привязана перешло на
    // следующую страницу.
    if (PRS.RecalcResult & recalcresult_NextPage)
        return false;

    // Если строка пустая в следствии того, что у нас было обтекание, тогда мы не добавляем новую строку,
    // а просто текущую смещаем ниже.


    if(true === PRS.EmptyLine && true === PRS.bMathRangeY) // нужный PRS.Y выставляется в ParaMath
    {
        PRS.bMathRangeY = false;
        // Отмечаем, что данная строка переносится по Y из-за обтекания
        PRS.RangeY = true;

        // Пересчитываем заново данную строку
        PRS.Reset_Ranges();
        PRS.RecalcResult = recalcresult_CurLine;

        return false;
    }
    else if (true !== PRS.End && true === PRS.EmptyLine && PRS.RangesCount > 0)
    {
        // Найдем верхнюю точку объектов обтекания (т.е. так чтобы при новом обсчете не учитывался только
        // этот объект, заканчивающийся выше всех)

        var Ranges = PRS.Ranges;

        var RangesMaxY = Ranges[0].Y1;
        for (var Index = 1; Index < Ranges.length; Index++)
        {
            if (RangesMaxY > Ranges[Index].Y1)
                RangesMaxY = Ranges[Index].Y1;
        }

        if (Math.abs(RangesMaxY - PRS.Y) < 0.001)
            PRS.Y = RangesMaxY + 1; // смещаемся по 1мм
        else
            PRS.Y = RangesMaxY + (25.4 / 1440) + 0.001; // Добавляем 0.001, чтобы избавиться от погрешности

        // Отмечаем, что данная строка переносится по Y из-за обтекания
        PRS.RangeY = true;

        // Пересчитываем заново данную строку
        PRS.Reset_Ranges();
        PRS.RecalcResult = recalcresult_CurLine;

        return false;
    }

    return true;
};

Paragraph.prototype.private_RecalculateLineEnd         = function(CurLine, CurPage, PRS, ParaPr)
{
    if ( true === PRS.NewPage )
    {
        // Если это последний элемент параграфа, тогда нам не надо переносить текущий параграф
        // на новую страницу. Нам надо выставить границы так, чтобы следующий параграф начинался
        // с новой страницы.
        this.Pages[CurPage].Set_EndLine( CurLine );
        PRS.RecalcResult = recalcresult_NextPage;
        return false;
    }

    if (true !== PRS.End)
    {
        if ( true === PRS.ForceNewPage )
        {
            this.Pages[CurPage].Set_EndLine( CurLine - 1 );

            if ( 0 === CurLine )
                this.Lines[-1] = new CParaLine();

            PRS.RecalcResult = recalcresult_NextPage;
            return false;
        }
    }
    else
    {
        // В последней строке могут быть заполнены не все отрезки обтекания. Удаляем лишние.
        if (PRS.Range < PRS.RangesCount)
            this.Lines[CurLine].Ranges.length = PRS.Range + 1;

        // Проверим висячую строку
        if (true === ParaPr.WidowControl && CurLine === this.Pages[CurPage].StartLine && CurLine >= 1 && false === this.private_CheckSkipKeepLinesAndWidowControl(CurPage))
        {
            // Проверим не встречается ли в предыдущей строке BreakPage, если да, тогда не учитываем WidowControl
            var BreakPagePrevLine = (this.Lines[CurLine - 1].Info & paralineinfo_BreakPage) | 0;

            if (this.Parent instanceof CDocument
                && true === this.Parent.RecalcInfo.Can_RecalcWidowControl()
                && 0 === BreakPagePrevLine
                && (1 === CurPage && null != this.Get_DocumentPrev())
                && this.Lines[CurLine - 1].Ranges.length <= 1)
            {
                var bBreakPageFromStart = false;
                for (var Index = 0, Count = this.Pages[CurPage - 1].Drawings.length; Index < Count; Index++)
                {
                    var Drawing = this.Pages[CurPage - 1].Drawings[Index];
                    var DrawingLine = Drawing.LineNum;

                    if (DrawingLine >= CurLine - 1)
                    {
                        bBreakPageFromStart = true;
                        break;
                    }
                }

                // Если в строках, которые мы переносим есть картинки, либо, если у нас в параграфе 3 строки,
                // тогда сразу начинаем параграф с новой строки
                if (true === bBreakPageFromStart || CurLine <= 2)
                {
                    CurLine = 0;
                    // Вызываем данную функцию для удаления картинок с предыдущей страницы
                    this.Recalculate_Drawing_AddPageBreak(0, 0, true);
                }
                else
                    CurLine = CurLine - 1;

                this.Parent.RecalcInfo.Set_WidowControl(this, CurLine);
                PRS.RecalcResult = recalcresult_PrevPage | recalcresultflags_Column;
                return false;
            }
        }

        // Если у нас нумерация относится к знаку конца параграфа, тогда в такой
        // ситуации не рисуем нумерацию у такого параграфа.
        if (para_End === this.Numbering.Item.Type && this.Lines[CurLine].Info & paralineinfo_BreakPage)
        {
            this.Numbering.Item  = null;
            this.Numbering.Run   = null;
            this.Numbering.Line  = -1;
            this.Numbering.Range = -1;
        }

        this.Pages[CurPage].Set_EndLine( CurLine );
        PRS.RecalcResult = recalcresult_NextElement;
    }

    return true;
};

Paragraph.prototype.private_RecalculateLineAlign       = function(CurLine, CurPage, PRS, ParaPr, Fast)
{
    // Здесь мы пересчитываем ширину пробелов (и в особенных случаях дополнительное
    // расстояние между символами) с учетом прилегания параграфа.
    // 1. Если align = left, тогда внутри каждого промежутка текста выравниваем его
    //    к левой границе промежутка.
    // 2. Если align = right, тогда внутри каждого промежутка текста выравниваем его
    //    к правой границе промежутка.
    // 3. Если align = center, тогда внутри каждого промежутка текста выравниваем его
    //    по центру промежутка.
    // 4. Если align = justify, тогда
    //    4.1 Если внутри промежутка ровно 1 слово.
    //        4.1.1 Если промежуток в строке 1 и слово занимает почти всю строку,
    //              добавляем в слове к каждой букве дополнительное расстояние между
    //              символами, чтобы ширина слова совпала с шириной строки.
    //        4.1.2 Если промежуток первый, тогда слово приставляем к левой границе
    //              промежутка
    //        4.1.3 Если промежуток последний, тогда приставляем слово к правой
    //              границе промежутка
    //        4.1.4 Если промежуток ни первый, ни последний, тогда ставим слово по
    //              середине промежутка
    //    4.2 Если слов больше 1, тогда, исходя из количества пробелов между словами в
    //        промежутке, увеличиваем их на столько, чтобы правая граница последнего
    //        слова совпала с правой границей промежутка
    var PRSW = PRS;
    var PRSC = this.m_oPRSC;
    var PRSA = this.m_oPRSA;
    PRSA.Paragraph    = this;
    PRSA.LastW        = 0;
    PRSA.RecalcFast   = Fast;
    PRSA.RecalcResult = recalcresult_NextElement;
    PRSA.PageY        = this.Pages[CurPage].Bounds.Top;
    PRSA.PageX        = this.Pages[CurPage].Bounds.Left;

    var Line        = this.Lines[CurLine];
    var RangesCount = Line.Ranges.length;

    for (var CurRange = 0; CurRange < RangesCount; CurRange++)
    {
        var Range = Line.Ranges[CurRange];

        var StartPos = Range.StartPos;
        var EndPos   = Range.EndPos;

        PRSC.Reset( this, Range );

		PRSC.Range.W      = 0;
		PRSC.Range.WEnd   = 0;
		PRSC.Range.WBreak = 0;
        if ( true === this.Numbering.Check_Range(CurRange, CurLine) )
            PRSC.Range.W += this.Numbering.WidthVisible;

        for ( var Pos = StartPos; Pos <= EndPos; Pos++ )
        {
            var Item = this.Content[Pos];
            Item.Recalculate_Range_Width( PRSC, CurLine, CurRange );
        }

        var JustifyWord  = 0;
        var JustifySpace = 0;
        var RangeWidth   = Range.XEnd - Range.X;

        var X = 0;

        // Если данный отрезок содержит только формулу, тогда прилегание данного отрезка определяется формулой
        var ParaMath = this.Check_Range_OnlyMath(CurRange, CurLine);
        if (null !== ParaMath)
        {
            var Math_X      = ( 1 === RangesCount ? this.Pages[CurPage].X      + ParaPr.Ind.Left  : Range.X );
            var Math_XLimit = ( 1 === RangesCount ? this.Pages[CurPage].XLimit - ParaPr.Ind.Right : Range.XEnd );

            X = ParaMath.Get_AlignToLine(CurLine, CurRange, PRS.Page, Math_X, Math_XLimit);
        }
        else
        {
            if (this.Lines[CurLine].Info & paralineinfo_BadLeftTab)
            {
                X            = Range.X;
                JustifyWord  = 0;
                JustifySpace = 0;
            }
            else
            {
                // RangeWidth - ширина всего пространства в данном отрезке, а Range.W - ширина занимаемого пространства
                switch (ParaPr.Jc)
                {
                    case AscCommon.align_Left :
                    {
                        X = Range.X;
                        break;
                    }
                    case AscCommon.align_Right:
                    {
                        X = Math.max(Range.X + RangeWidth - Range.W, Range.X);
                        break;
                    }
                    case AscCommon.align_Center:
                    {
                        X = Math.max(Range.X + (RangeWidth - Range.W) / 2, Range.X);
                        break;
                    }
                    case AscCommon.align_Justify:
                    {
                        X = Range.X;

                        // Проверяем по количеству пробелов, т.к., например, в китайском языке пробелов нет, но
						// каждый иероглиф как отдельное слово идет.
                        if (1 == PRSC.Words || PRSC.Spaces <= 0)
                        {
                            if (1 == RangesCount && !(Line.Info & paralineinfo_End))
                            {
                                // Либо слово целиком занимает строку, либо не целиком, но разница очень мала
								// либо это набор китайских иероглифов (PRSC.Words > 1)
                                if ((RangeWidth - Range.W <= 0.05 * RangeWidth || PRSC.Words > 1) && PRSC.Letters > 1)
                                    JustifyWord = (RangeWidth - Range.W) / (PRSC.Letters - 1);
                            }
                            else if (0 == CurRange || Line.Info & paralineinfo_End)
                            {
                                // TODO: Здесь нужно улучшить проверку, т.к. отключено выравнивание по центру для всей
                                //       последней строки, а нужно отключить для последнего отрезка, в котором идет
                                //       конец параграфа.
                                
                                // Ничего не делаем (выравниваем текст по левой границе)
                            }
                            else if (CurRange == RangesCount - 1)
                            {
                                X = Range.X + RangeWidth - Range.W;
                            }
                            else
                            {
                                X = Range.X + (RangeWidth - Range.W) / 2;
                            }
                        }
                        else
                        {
                            // TODO: Переделать проверку последнего отрезка в последней строке (нужно выставлять флаг когда пришел PRS.End в отрезке)

                            // Последний промежуток последней строки не надо растягивать по ширине.
                            if (PRSC.Spaces > 0 && (!(Line.Info & paralineinfo_End) || CurRange != Line.Ranges.length - 1))
                                JustifySpace = (RangeWidth - Range.W) / PRSC.Spaces;
                            else
                                JustifySpace = 0;
                        }

                        break;
                    }
                    default:
                    {
                        X = Range.X;
                        break;
                    }
                }
            }

            // В последнем отрезке последней строки не делаем текст "по ширине"
            if (CurLine === this.ParaEnd.Line && CurRange === this.ParaEnd.Range)
            {
                JustifyWord  = 0;
                JustifySpace = 0;
            }
        }

        Range.Spaces = PRSC.Spaces + PRSC.SpacesSkip;

        PRSA.X    = X;
        PRSA.Y    = this.Pages[CurPage].Y + this.Lines[CurLine].Y;
        PRSA.XEnd = Range.XEnd;
        PRSA.JustifyWord   = JustifyWord;
        PRSA.JustifySpace  = JustifySpace;
        PRSA.SpacesCounter = PRSC.Spaces;
        PRSA.SpacesSkip    = PRSC.SpacesSkip;
        PRSA.LettersSkip   = PRSC.LettersSkip;
        PRSA.RecalcResult  = recalcresult_NextElement;

        var _LineMetrics = this.Lines[CurLine].Metrics;
        PRSA.Y0 = (this.Pages[CurPage].Y + this.Lines[CurLine].Y - _LineMetrics.Ascent);
        PRSA.Y1 = (this.Pages[CurPage].Y + this.Lines[CurLine].Y + _LineMetrics.Descent);
        if (_LineMetrics.LineGap < 0)
            PRSA.Y1 += _LineMetrics.LineGap;

        this.Lines[CurLine].Ranges[CurRange].XVisible = X;

        if ( 0 === CurRange )
            this.Lines[CurLine].X = X - PRSW.XStart;

        if ( true === this.Numbering.Check_Range(CurRange, CurLine) )
            PRSA.X += this.Numbering.WidthVisible;

        for ( var Pos = StartPos; Pos <= EndPos; Pos++ )
        {
            var Item = this.Content[Pos];
            Item.Recalculate_Range_Spaces(PRSA, CurLine, CurRange, CurPage);

            if (!(PRSA.RecalcResult & recalcresult_NextElement))
            {
                PRSW.RecalcResult = PRSA.RecalcResult;
                return PRSA.RecalcResult;
            }
        }
    }

    return PRSA.RecalcResult;
};

Paragraph.prototype.private_RecalculateLineCheckFootnotes = function(CurLine, CurPage, PRS, ParaPr)
{
    if (!((PRS.RecalcResult & recalcresult_NextElement) || (PRS.RecalcResult & recalcresult_NextLine)))
        return false;

	if (PRS.Fast)
		return true;

	var oTopDocument  = PRS.TopDocument;
	var arrFootnotes  = [];
	var oLineBreakPos = this.GetLineEndPos(CurLine);
	for (var nIndex = 0, nCount = PRS.Footnotes.length; nIndex < nCount; ++nIndex)
	{
		var oFootnote = PRS.Footnotes[nIndex].FootnoteReference.Get_Footnote();
		var oPos      = PRS.Footnotes[nIndex].Pos;

		// Проверим позицию
		if (oLineBreakPos.Compare(oPos) <= 0)
			continue;

		arrFootnotes.push(oFootnote);
	}

	if (oTopDocument instanceof CDocument)
	{
		if (!oTopDocument.Footnotes.RecalculateFootnotes(PRS.PageAbs, PRS.ColumnAbs, this.Pages[CurPage].Y + this.Lines[CurLine].Bottom, arrFootnotes))
		{
			this.private_RecalculateMoveLineToNextPage(CurLine, CurPage, PRS, ParaPr);
			return false;
		}
	}

	return true;
};

Paragraph.prototype.private_RecalculateRange           = function(CurRange, CurLine, CurPage, RangesCount, PRS, ParaPr)
{
    // Найдем начальную позицию данного отрезка
    var StartPos = 0;
    if ( 0 === CurLine && 0 === CurRange )
        StartPos = 0;
    else if ( CurRange > 0 )
        StartPos = this.Lines[CurLine].Ranges[CurRange - 1].EndPos;
    else
        StartPos = this.Lines[CurLine - 1].Ranges[ this.Lines[CurLine - 1].Ranges.length - 1 ].EndPos;

    var Line = this.Lines[CurLine];
    var Range = Line.Ranges[CurRange];

    this.Lines[CurLine].Set_RangeStartPos( CurRange, StartPos );

    if ( true === PRS.UseFirstLine && 0 !== CurRange && true === PRS.EmptyLine )
    {
        if ( ParaPr.Ind.FirstLine < 0 )
        {
            Range.X += ParaPr.Ind.Left + ParaPr.Ind.FirstLine;
        }
        else
        {
            Range.X += ParaPr.Ind.FirstLine;
        }
    }

    var X    = Range.X;
    var XEnd = ( CurRange == RangesCount ? PRS.XLimit : PRS.Ranges[CurRange].X0 );

    // Обновляем состояние пересчета
    PRS.Reset_Range(X, XEnd);

    var ContentLen = this.Content.length;

    var Pos = StartPos;
    for ( ;Pos < ContentLen; Pos++ )
    {
        var Item = this.Content[Pos];

        if ( para_Math === Item.Type )
        {
            var NotInlineMath = this.Check_MathPara(Pos);
            if (true === NotInlineMath && true !== PRS.EmptyLine)
            {
                PRS.ForceNewLine = true;
                PRS.NewRange = true;
                Pos--;
                break;
            }
            // TODO: Надо бы перенести эту проверку на изменение контента параграфа
            Item.Set_Inline(true === this.Check_MathPara(Pos)? false : true);
        }

        if ( ( 0 === Pos && 0 === CurLine && 0 === CurRange ) || Pos !== StartPos )
        {
            Item.Recalculate_Reset(CurRange, CurLine);
        }

        PRS.Update_CurPos( Pos, 0 );
        Item.Recalculate_Range( PRS, ParaPr, 1 );

        if ( true === PRS.NewRange )
        {
            break;
        }
    }

    if ( Pos >= ContentLen )
        Pos = ContentLen - 1;

    if (PRS.RecalcResult & recalcresult_NextLine)
    {
        // У нас отрезок пересчитался нормально и тут возможны 2 варианта :
        // 1. Отрезок закончился в данной позиции
        // 2. Не все убралось в заданный отрезок и перенос нужно поставить в позиции PRS.LineBreakPos

        if ( true === PRS.MoveToLBP )
        {
            // Отмечаем, что в заданной позиции заканчивается отрезок
            this.private_RecalculateRangeEndPos( PRS, PRS.LineBreakPos, 0 );
        }
        else
            this.Lines[CurLine].Set_RangeEndPos( CurRange, Pos );
    }
};

Paragraph.prototype.private_RecalculateRangeEndPos     = function(PRS, PRP, Depth)
{
    var CurLine  = PRS.Line;
    var CurRange = PRS.Range;
    var CurPos   = PRP.Get(Depth);

    this.Content[CurPos].Recalculate_Set_RangeEndPos(PRS, PRP, Depth + 1);
    this.Lines[CurLine].Set_RangeEndPos( CurRange, CurPos );
};

Paragraph.prototype.private_RecalculateGetTabPos = function(X, ParaPr, CurPage, NumTab)
{
    var PRS = this.m_oPRSW;

    var PageStart = this.Parent.Get_PageContentStartPos2(this.PageNum, this.ColumnNum, CurPage, this.Index);
    if ( undefined != this.Get_FramePr() )
        PageStart.X = 0;
    else if ( PRS.RangesCount > 0 && Math.abs(PRS.Ranges[0].X0 - PageStart.X) < 0.001 )
        PageStart.X = PRS.Ranges[0].X1;

    // Если у данного параграфа есть табы, тогда ищем среди них
    var TabsCount = ParaPr.Tabs.Get_Count();

    // Добавим в качестве таба левую границу
    var TabsPos = [];
    var bCheckLeft = true;
    for ( var Index = 0; Index < TabsCount; Index++ )
    {
        var Tab = ParaPr.Tabs.Get(Index);
        var TabPos = Tab.Pos + PageStart.X;

        if ( true === bCheckLeft && TabPos > PageStart.X + ParaPr.Ind.Left )
        {
            TabsPos.push( new CParaTab(tab_Left, ParaPr.Ind.Left ) );
            bCheckLeft = false;
        }

        if ( tab_Clear != Tab.Value )
            TabsPos.push( Tab );
    }

    if ( true === bCheckLeft )
        TabsPos.push( new CParaTab(tab_Left, ParaPr.Ind.Left ) );

    TabsCount = TabsPos.length;

    var Tab = null;
    for ( var Index = 0; Index < TabsCount; Index++ )
    {
        var TempTab = TabsPos[Index];

        // TODO: Пока здесь сделаем поправку на погрешность. Когда мы сделаем так, чтобы все наши значения хранились
        //       в тех же единицах, что и в формате Docx, тогда и здесь можно будет вернуть обычное сравнение (см. баг 22586)
        //       Разница с NumTab возникла из-за бага 22586, везде нестрогое оставлять нельзя из-за бага 32051.

        var twX      = AscCommon.MMToTwips(X);
        var twTabPos = AscCommon.MMToTwips(TempTab.Pos + PageStart.X);

        if ((true === NumTab && twX <= twTabPos) || (true !== NumTab && twX < twTabPos))
        {
            Tab = TempTab;
            break;
        }
    }

    var isTabToRightEdge = false;

    var NewX = 0;

    // Если табов нет, либо их позиции левее текущей позиции ставим таб по умолчанию
    var DefTab = ParaPr.DefaultTab != null ? ParaPr.DefaultTab : AscCommonWord.Default_Tab_Stop;
    if ( null === Tab )
    {
        if ( X < PageStart.X + ParaPr.Ind.Left )
        {
            NewX = PageStart.X + ParaPr.Ind.Left;
        }
        else if (DefTab < 0.001)
        {
            NewX = X;
        }
        else
        {
            NewX = PageStart.X;
            while ( X >= NewX - 0.001 )
                NewX += DefTab;
        }

		// Так работает Word: если таб начался в допустимом отрезке, а заканчивается вне его,
		// то мы ограничиваем его правым полем документа, но только если правый отступ параграфа
		// неположителен (<= 0). (смотри bug 32345)
        var twX      = AscCommon.MMToTwips(X);
        var twEndPos = AscCommon.MMToTwips(PageStart.XLimit);
        var twNewX   = AscCommon.MMToTwips(NewX);

        if (twX < twEndPos && twNewX >= twEndPos && AscCommon.MMToTwips(ParaPr.Ind.Right) <= 0)
		{
			NewX = PageStart.XLimit;
			isTabToRightEdge = true;
		}
    }
    else
    {
        NewX = Tab.Pos + PageStart.X;
    }

	return {
		NewX         : NewX,
		TabValue     : Tab ? Tab.Value : tab_Left,
		DefaultTab   : Tab ? false : true,
		TabLeader    : Tab ? Tab.Leader : Asc.c_oAscTabLeader.None,
		TabRightEdge : isTabToRightEdge,
		PageX        : PageStart.X,
		PageXLimit   : PageStart.XLimit
	};
};

Paragraph.prototype.private_CheckSkipKeepLinesAndWidowControl = function(CurPage)
{
    var bSkipWidowAndKeepLines = false;
    if (this.ColumnsCount > 1)
    {
        var bWrapDrawing = false;
        for (var TempPage = 0; TempPage <= CurPage; ++TempPage)
        {
            for (var DrawingIndex = 0, DrawingsCount = this.Pages[TempPage].Drawings.length; DrawingIndex < DrawingsCount; ++DrawingIndex)
            {
                if (this.Pages[TempPage].Drawings[DrawingIndex].Use_TextWrap())
                {
                    bWrapDrawing = true;
                    break;
                }
            }

            if (bWrapDrawing)
                break;
        }

        bSkipWidowAndKeepLines = bWrapDrawing;
    }

    return bSkipWidowAndKeepLines;
};

Paragraph.prototype.private_CheckColumnBreak = function(CurPage)
{
    if (this.IsEmptyPage(CurPage))
        return;

    var Page = this.Pages[CurPage];
    var Line = this.Lines[Page.EndLine];

    if (!Line)
        return;

    if (Line.Info & paralineinfo_BreakPage && !(Line.Info & paralineinfo_BreakRealPage))
    {
        if (this.bFromDocument && this.LogicDocument)
            this.LogicDocument.OnColumnBreak_WhileRecalculate();
    }
};

Paragraph.prototype.private_RecalculateMoveLineToNextPage = function(CurLine, CurPage, PRS, ParaPr)
{
	// TODO: Неразрывные абзацы и висячие строки внутри колонок вместе с плавающими объектами пока не обсчитываем
	var bSkipWidowAndKeepLines = this.private_CheckSkipKeepLinesAndWidowControl(CurPage);

	// Проверим висячую строку
	if (this.Parent instanceof CDocument
		&& false === bSkipWidowAndKeepLines
		&& true === this.Parent.RecalcInfo.Can_RecalcWidowControl()
		&& true === ParaPr.WidowControl
		&& CurLine - this.Pages[CurPage].StartLine <= 1
		&& CurLine >= 1 && true != PRS.BreakPageLine
		&& ( 0 === CurPage && null != this.Get_DocumentPrev() ) )
	{
		// Вызываем данную функцию для удаления картинок с предыдущей страницы
		this.Recalculate_Drawing_AddPageBreak(0, 0, true);

		// TODO: Здесь перенос нужно делать сразу же, если в строке не было объектов с обтеканием
		this.Parent.RecalcInfo.Set_WidowControl(this, CurLine - 1);
		PRS.RecalcResult = recalcresult_CurPage | recalcresultflags_Column;
		return false;
	}
	else
	{
		// Учитываем неразрывные абзацы:
		//   1. В Word2010 (версия <= 14) просто проверяем, если параграф разбивается на 2 страницы, тогда
		//      переносим его с новой страницы. Также не учитываем неразрывные параграфы внутри таблиц.
		//   2. В Word2016 (версия >= 15) в добавок к предыдущему ориентируемся на колонки: пытаемся текущую
		//      страницу параграфа разместить в какой либо колонке (пересчитывая их по очереди), если параграф
		//      все равно не рассчитан до конца, тогда размещаем его в первой колонке и делаем перенос на следующую
		//      страницу.
		if (true === ParaPr.KeepLines && this.LogicDocument && this.LogicDocument.GetCompatibilityMode && false === bSkipWidowAndKeepLines)
		{
			var CompatibilityMode = this.LogicDocument.GetCompatibilityMode();
			if (CompatibilityMode <= document_compatibility_mode_Word14)
			{
				if (null != this.Get_DocumentPrev() && true != this.Parent.IsTableCellContent() && 0 === CurPage)
					CurLine = 0;
			}
			else if (CompatibilityMode >= document_compatibility_mode_Word15)
			{
				// TODO: Разобраться с 2016 вордом
				if (null != this.Get_DocumentPrev() && 0 === CurPage)
					CurLine = 0;
			}
		}

		// Восстанавливаем позицию нижней границы предыдущей страницы
		this.Pages[CurPage].Bounds.Bottom = PRS.LinePrevBottom;
		this.Pages[CurPage].Set_EndLine( CurLine - 1 );

		if ( 0 === CurLine )
			this.Lines[-1] = new CParaLine(0);

		// Добавляем разрыв страницы
		PRS.RecalcResult = recalcresult_NextPage;
		return false;
	}
};

Paragraph.prototype.private_CheckNeedBeforeSpacing = function(CurPage, PRS, ParaPr)
{
	if (CurPage <= 0)
		return true;

	if (!this.Check_FirstPage(CurPage))
	{
		// Если на предыдущих страницах были только разрывы страниц и колонок, тогда добавляем расстояние
		if (this.Check_FirstPage(CurPage, true))
			return true;
		else
			return false;
	}

	if (true === ParaPr.PageBreakBefore)
		return true;

	if (!(PRS.Parent instanceof CDocument))
	{
		if (PRS.Parent instanceof AscFormat.CDrawingDocContent && 0 !== CurPage)
			return false;

		return true;
	}

	// Если дошли до этого места, то тут все зависит от того на какой мы странице. Если на первой странице данной секции
	// тогда добавляем расстояние, а если нет - нет. Но подсчет первой страницы здесь не совпадает с тем, как она
	// считается для нумерации. Если разрыв секции идет на текущей странице, то первой считается сразу данная страница.

	var LogicDocument = PRS.Parent;
	var SectionIndex = LogicDocument.GetSectionIndexByElementIndex(this.Get_Index());
	var FirstElement = LogicDocument.GetFirstElementInSection(SectionIndex);

	if (0 !== SectionIndex && (!FirstElement || FirstElement.Get_AbsolutePage(0) === PRS.GetPageAbs()))
		return true;

	return false;
};

var ERecalcPageType =
{
    START   : 0x00, // начать заново пересчет, с начала страницы
    ELEMENT : 0x01, // начать заново пересчет, начиная с заданного элемента
    Y       : 0x02  // начать заново пересчет, начиная с заданной позиции по вертикали
};

function CRecalcPageType()
{
    this.Type    = ERecalcPageType.START;
    this.Element = null;
    this.Y       = -1;
}

CRecalcPageType.prototype.Reset = function()
{
    this.Type    = ERecalcPageType.START;
    this.Element = null;
    this.Y       = -1;
};
CRecalcPageType.prototype.Set_Element = function(Element)
{
    this.Type    = ERecalcPageType.Element;
    this.Element = Element;
};
CRecalcPageType.prototype.Set_Y = function(Y)
{
    this.Type = ERecalcPageType.Y;
    this.Y    = Y;
};

var paralineinfo_BreakPage     = 0x0001; // В строке есть PageBreak или ColumnBreak
var paralineinfo_Empty         = 0x0002; // Строка пустая
var paralineinfo_End           = 0x0004; // Последняя строка параграфа
var paralineinfo_RangeY        = 0x0008; // Строка начинается после какого-либо объекта с обтеканием
var paralineinfo_BreakRealPage = 0x0010; // В строке есть PageBreak
var paralineinfo_BadLeftTab    = 0x0020; // В строке есть левый таб, который правее правой границы
var paralineinfo_Notes         = 0x0040; // В строке есть сноски
var paralineinfo_TextOnLine    = 0x0080; // Есть ли в строке текст

function CParaLine()
{
    this.Y       = 0; // Позиция BaseLine
    this.Top     = 0;
    this.Bottom  = 0;
    this.Metrics = new CParaLineMetrics();
    this.Ranges  = []; // Массив CParaLineRanges
    this.Info    = 0;  // Побитовая информация о строке:
                       // 1 бит : есть ли PageBreak в строке
                       // 2 бит : пустая ли строка (без учета PageBreak)
                       // 3 бит : последняя ли это строка (т.е. строка с ParaEnd)
                       // 4 бит : строка переносится по Y по обтекаемому объекту
}

CParaLine.prototype =
{
    Add_Range : function(X, XEnd)
    {
        this.Ranges.push(new CParaLineRange(X, XEnd));
    },

    Shift : function(Dx, Dy)
    {
        // По Y мы ничего не переносим, т.к. все значени по Y у строки относительно начала страницы данного параграфа
        for (var CurRange = 0, RangesCount = this.Ranges.length; CurRange < RangesCount; CurRange++)
        {
            this.Ranges[CurRange].Shift(Dx, Dy);
        }
    },

    Get_StartPos : function()
    {
        if (this.Ranges.length <= 0)
            return 0;

        return this.Ranges[0].StartPos;
    },

    Get_EndPos : function()
    {
        if (this.Ranges.length <= 0)
            return 0;

        return this.Ranges[this.Ranges.length - 1].EndPos;
    },

    Set_RangeStartPos : function(CurRange, StartPos)
    {
        this.Ranges[CurRange].StartPos = StartPos;
    },

    Set_RangeEndPos : function(CurRange, EndPos)
    {
        this.Ranges[CurRange].EndPos = EndPos;
    },

    Copy : function()
    {
        var NewLine = new CParaLine();

        NewLine.Y      = this.Y;
        NewLine.Top    = this.Top;
        NewLine.Bottom = this.Bottom;

        NewLine.Metrics.Ascent      = this.Ascent;
        NewLine.Metrics.Descent     = this.Descent;
        NewLine.Metrics.TextAscent  = this.TextAscent;
        NewLine.Metrics.TextAscent2 = this.TextAscent2;
        NewLine.Metrics.TextDescent = this.TextDescent;
        NewLine.Metrics.LineGap     = this.LineGap;

        for (var CurRange = 0, RangesCount = this.Ranges.length; CurRange < RangesCount; CurRange++)
        {
            NewLine.Ranges[CurRange] = this.Ranges[CurRange].Copy();
        }

        NewLine.Info = this.Info;

        return NewLine;
    },

    Reset : function()
    {
        //this.Y        = 0;
        this.Top      = 0;
        this.Bottom   = 0;
        this.Metrics  = new CParaLineMetrics();
        this.Ranges   = [];
        this.Info     = 0;
    }
};

function CParaLineMetrics()
{
    this.Ascent      = 0; // Высота над BaseLine
    this.Descent     = 0; // Высота после BaseLine
    this.TextAscent  = 0; // Высота текста над BaseLine
    this.TextAscent2 = 0; // Высота текста над BaseLine
    this.TextDescent = 0; // Высота текста после BaseLine
    this.LineGap     = 0; // Дополнительное расстояние между строками
}

CParaLineMetrics.prototype =
{
    Update : function(TextAscent, TextAscent2, TextDescent, Ascent, Descent, ParaPr)
    {
        if ( TextAscent > this.TextAscent )
            this.TextAscent = TextAscent;

        if ( TextAscent2 > this.TextAscent2 )
            this.TextAscent2 = TextAscent2;

        if ( TextDescent > this.TextDescent )
            this.TextDescent = TextDescent;

        if ( Ascent > this.Ascent )
            this.Ascent = Ascent;

        if ( Descent > this.Descent )
            this.Descent = Descent;

        if ( this.Ascent < this.TextAscent )
            this.Ascent = this.TextAscent;

        if ( this.Descent < this.TextDescent )
            this.Descent = this.TextDescent;

        this.LineGap = this.Recalculate_LineGap( ParaPr, this.TextAscent, this.TextDescent );

        if (Asc.linerule_AtLeast === ParaPr.Spacing.LineRule && (this.Ascent + this.Descent + this.LineGap) > (this.TextAscent + this.TextDescent))
        {
            // В такой ситуации Word располагает текст внизу строки
            this.Ascent  = this.Ascent + this.LineGap;
            this.LineGap = 0;
        }
    },

    Recalculate_LineGap : function(ParaPr, TextAscent, TextDescent)
    {
        var LineGap = 0;
        switch ( ParaPr.Spacing.LineRule )
        {
            case Asc.linerule_Auto:
            {
                LineGap = ( TextAscent + TextDescent ) * ( ParaPr.Spacing.Line - 1 );
                break;
            }
            case Asc.linerule_Exact:
            {
                var ExactValue = Math.max( 25.4 / 72, ParaPr.Spacing.Line );
                LineGap = ExactValue - ( TextAscent + TextDescent );

                var Gap = this.Ascent + this.Descent - ExactValue;

                if ( Gap > 0 )
                {
                    var DescentDiff = this.Descent - this.TextDescent;

                    if ( DescentDiff > 0 )
                    {
                        if ( DescentDiff < Gap )
                        {
                            this.Descent = this.TextDescent;
                            Gap -= DescentDiff;
                        }
                        else
                        {
                            this.Descent -= Gap;
                            Gap = 0;
                        }
                    }

                    var AscentDiff = this.Ascent - this.TextAscent;

                    if ( AscentDiff > 0 )
                    {
                        if ( AscentDiff < Gap )
                        {
                            this.Ascent = this.TextAscent;
                            Gap -= AscentDiff;
                        }
                        else
                        {
                            this.Ascent -= Gap;
                            Gap = 0;
                        }
                    }

                    if ( Gap > 0 )
                    {
                        // Уменьшаем пропорционально TextAscent и TextDescent
                        var OldTA = this.TextAscent;
                        var OldTD = this.TextDescent;

                        var Sum = OldTA + OldTD;

                        this.Ascent  = OldTA * (Sum - Gap) / Sum;
                        this.Descent = OldTD * (Sum - Gap) / Sum;
                    }
                }
                else
                {
                    this.Ascent -= Gap; // все в Ascent
                }

                LineGap = 0;


                break;
            }
            case Asc.linerule_AtLeast:
            {
                var TargetLineGap = ParaPr.Spacing.Line;
                var TextLineGap   = TextAscent + TextDescent;
                var RealLineGap   = this.Ascent + this.Descent;

                // Специальный случай, когда в строке нет никакого текста
                if (Math.abs(TextLineGap) < 0.001 || RealLineGap >= TargetLineGap)
                    LineGap = 0;
                else
                    LineGap = TargetLineGap - RealLineGap;

                break;
            }

        }
        return LineGap;
    }
};

function CParaLineRange(X, XEnd)
{
    this.X         = X;    // Начальная позиция отрезка без учета прилегания содержимого
    this.XVisible  = 0;    // Начальная позиция отрезка с учетом прилегания содержимого
    this.XEnd      = XEnd; // Предельное значение по X для данного отрезка
    this.StartPos  = 0;    // Позиция в контенте параграфа, с которой начинается данный отрезок
    this.EndPos    = 0;    // Позиция в контенте параграфа, на которой заканчиваетсяданный отрезок
    this.W         = 0;
    this.Spaces    = 0;    // Количество пробелов в отрезке, без учета пробелов в конце отрезка
	this.WEnd      = 0;    // Если есть знак конца параграфа в данном отрезке, то это его ширина
	this.WBreak    = 0;    // Если в конце отрезка есть разрыв строки/колонки/страницы
}

CParaLineRange.prototype =
{
    Shift : function(Dx, Dy)
    {
        this.X        += Dx;
        this.XEnd     += Dx;
        this.XVisible += Dx;
    },

    Copy : function()
    {
        var NewRange = new CParaLineRange();

        NewRange.X           = this.X;
        NewRange.XVisible    = this.XVisible;
        NewRange.XEnd        = this.XEnd;
        NewRange.StartPos    = this.StartPos;
        NewRange.EndPos      = this.EndPos;
        NewRange.W           = this.W;
        NewRange.Spaces      = this.Spaces;

        return NewRange;
    }
};

function CParaPage(X, Y, XLimit, YLimit, FirstLine)
{
    this.X         = X;
    this.Y         = Y;
    this.XLimit    = XLimit;
    this.YLimit    = YLimit;
    this.FirstLine = FirstLine;
    this.Bounds    = new CDocumentBounds( X, Y, XLimit, Y );
    this.StartLine = FirstLine; // Номер строки, с которой начинается данная страница
    this.EndLine   = FirstLine; // Номер последней строки на данной странице
    this.TextPr    = null;      // Расситанные текстовые настройки для начала страницы

    this.Drawings  = [];
    this.EndInfo   = new CParagraphPageEndInfo();
}

CParaPage.prototype =
{
    Reset : function(X, Y, XLimit, YLimit, FirstLine)
    {
        this.X         = X;
        this.Y         = Y;
        this.XLimit    = XLimit;
        this.YLimit    = YLimit;
        this.FirstLine = FirstLine;
        this.Bounds    = new CDocumentBounds( X, Y, XLimit, Y );
        this.StartLine = FirstLine;
        this.Drawings  = [];
    },

    Shift : function(Dx, Dy)
    {
        this.X      += Dx;
        this.Y      += Dy;
        this.XLimit += Dx;
        this.YLimit += Dy;
        this.Bounds.Shift( Dx, Dy );
    },

    Set_EndLine : function(EndLine)
    {
        this.EndLine = EndLine;
    },

    Add_Drawing : function(Item)
    {
        this.Drawings.push(Item);
    },

    Copy : function()
    {
        var NewPage = new CParaPage();

        NewPage.X             = this.X;
        NewPage.Y             = this.Y;
        NewPage.XLimit        = this.XLimit;
        NewPage.YLimit        = this.YLimit;
        NewPage.FirstLine     = this.FirstLine;

        NewPage.Bounds.Left   = this.Bounds.Left;
        NewPage.Bounds.Right  = this.Bounds.Right;
        NewPage.Bounds.Top    = this.Bounds.Top;
        NewPage.Bounds.Bottom = this.Bounds.Bottom;

        NewPage.StartLine     = this.StartLine;
        NewPage.EndLine       = this.EndLine;

        var Count = this.Drawings.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            NewPage.Drawings.push( this.Drawings[Index] );
        }

        NewPage.EndInfo = this.EndInfo.Copy();

        return NewPage;
    }
};

function CParagraphRecalculateTabInfo()
{
    this.TabPos =  0;
    this.X      =  0;
    this.Value  = -1;
    this.Item   = null;
}

CParagraphRecalculateTabInfo.prototype =
{
    Reset : function()
    {
        this.TabPos =  0;
        this.X      =  0;
        this.Value  = -1;
        this.Item   = null;
    }
};

function CParagraphRecalculateStateWrap(Para)
{
    // Общие параметры, которые заполняются 1 раз на пересчет всей страницы
    this.Paragraph       = Para;
    this.Parent          = null;
    this.TopDocument     = null;
    this.TopIndex        = -1;   // Номер элемента контейнера (содержащего данный параграф), либо номер данного параграфа в самом верхнем документе
    this.PageAbs         = 0;
    this.ColumnAbs       = 0;
	this.InTable         = false;
    this.SectPr          = null; // настройки секции, к которой относится данный параграф

	this.Fast            = false; // Быстрый ли пересчет

    //
    this.Page            = 0;
    this.Line            = 0;
    this.Range           = 0;

    this.Ranges          = [];
    this.RangesCount     = 0;

    this.FirstItemOnLine = true;
	this.PrevItemFirst   = false;
    this.EmptyLine       = true;
    this.StartWord       = false;
    this.Word            = false;
    this.AddNumbering    = true;
    this.TextOnLine      = false;

    this.BreakPageLine      = false; // Разрыв страницы (параграфа) в данной строке
    this.UseFirstLine       = false;
    this.BreakPageLineEmpty = false;
    this.BreakRealPageLine  = false; // Разрыв страницы документа (не только параграфа) в данной строке
    this.BadLeftTab         = false; // Левый таб правее правой границы

	this.ComplexFields = new CParagraphComplexFieldsInfo();

	this.WordLen         = 0;
    this.SpaceLen        = 0;
    this.SpacesCount     = 0;
    this.LastTab         = new CParagraphRecalculateTabInfo();

    this.LineTextAscent  = 0;
    this.LineTextDescent = 0;
    this.LineTextAscent2 = 0;
    this.LineAscent      = 0;
    this.LineDescent     = 0;

    this.LineTop        = 0;
    this.LineBottom     = 0;
    this.LineTop2       = 0;
    this.LineBottom2    = 0;
    this.LinePrevBottom = 0;

    this.XRange = 0; // Начальное положение по горизонтали для данного отрезка
    this.X      = 0; // Текущее положение по горизонтали
    this.XEnd   = 0; // Предельное значение по горизонтали для текущего отрезка

    this.Y      = 0; // Текущее положение по вертикали

    this.XStart = 0; // Начальное значение для X на данной страницы
    this.YStart = 0; // Начальное значение для Y на данной страницы
    this.XLimit = 0; // Предельное значение для X на данной страницы
    this.YLimit = 0; // Предельное значение для Y на данной страницы

    this.NewPage  = false; // Переходим на новую страницу
    this.NewRange = false; // Переходим к новому отрезку
    this.End      = false;
    this.RangeY   = false; // Текущая строка переносится по Y из-за обтекания

    this.CurPos       = new CParagraphContentPos();

    this.NumberingPos = new CParagraphContentPos(); // Позиция элемента вместе с которым идет нумерация

    this.MoveToLBP      = false;                      // Делаем ли разрыв в позиции this.LineBreakPos
	this.LineBreakFirst = true;                       // Последняя позиция для переноса - это первый элемент в отрезке
    this.LineBreakPos   = new CParagraphContentPos(); // Последняя позиция в которой можно будет добавить разрыв
                                                      // отрезка или строки, если что-то не умещается (например,
                                                      // если у нас не убирается слово, то разрыв ставим перед ним)
	this.LastItem       = null;                       // Последний непробельный элемент


    this.RunRecalcInfoLast  = null; // RecalcInfo последнего рана
    this.RunRecalcInfoBreak = null; // RecalcInfo рана, на котором произошел разрыв отрезка/строки

    this.BaseLineOffset = 0;

    this.RecalcResult = 0x00;//recalcresult_NextElement;

    this.RestartPageRecalcInfo =     // Информация о том, почему текущая страница параграфа пересчитывается заново
    {
        Line   : 0,           // Номер строки, начиная с которой надо пересчитать
        Object : null         // Объект, который вызвал пересчет
    };

    this.Footnotes                  = [];
	this.FootnotesRecalculateObject = null;

    // for ParaMath
    this.bMath_OneLine       = false;
    this.bMathWordLarge      = false;
    this.bEndRunToContent    = false;
    this.PosEndRun           = new CParagraphContentPos();

    // параметры, необходимые для расчета разбиения по операторам
    // у "крайних" в строке операторов/мат объектов сооответствующий Gap равен нулю
    this.OperGapRight        = 0;
    this.OperGapLeft         = 0;
    this.bPriorityOper       = true;  // есть ли в контенте операторы с высоким приоритетом разбиения
    this.WrapIndent          = 0;     // WrapIndent нужен для сравнения с длиной слова (когда слово разбивается по Compare Oper): ширина первой строки формулы не должна быть меньше WrapIndent
    this.bContainCompareOper = true;  // содержаться ли в текущем контенте операторы с высоким приоритетом
    this.MathFirstItem       = true;  // параметр необходим для принудительного переноса
    this.bFirstLine          = false;

    this.bNoOneBreakOperator = true;  // прежде чем обновлять позицию в контент Run, учтем были ли до этого break-операторы (проверки на Word == false не достаточно, т.к. формула мб инлайновая и тогда не нужно обновлять позицию)
    this.bForcedBreak        = false;
    this.bInsideOper         = false; // учитываем есть ли разбивка внутри мат объекта, чтобы случайно не вставить в конец пред оператора (при Brk_Before == false)
    this.bOnlyForcedBreak    = false; // учитывается, если возможна разбивка только по операторам выше уровням => в этом случае можно сделать принудительный разрыв во внутреннем контенте
    this.bBreakBox           = false;

    //-----------------------------//
    this.bFastRecalculate    = false;
    this.bBreakPosInLWord    = true; // обновляем LineBreakPos (Set_LineBreakPos) для WordLarge. Не обновляем для инлайновой формулы, перед формулой есть еще текст, чтобы не перебить LineBreakPos и выставить по тем меткам, которые были до формулы разбиение
    this.bContinueRecalc     = false;
    this.bMathRangeY         = false; // используется для переноса формулы под картинку
    this.MathNotInline       = null;
}

CParagraphRecalculateStateWrap.prototype =
{
    Reset_Page : function(Paragraph, CurPage)
    {
		this.Paragraph   = Paragraph;
		this.Parent      = Paragraph.Parent;
		this.TopDocument = Paragraph.Parent.GetTopDocumentContent();
		this.PageAbs     = Paragraph.Get_AbsolutePage(CurPage);
		this.ColumnAbs   = Paragraph.Get_AbsoluteColumn(CurPage);
		this.InTable     = Paragraph.Parent.IsTableCellContent();
        this.SectPr      = null;

		this.Page               = CurPage;
		this.RunRecalcInfoLast  = (0 === CurPage ? null : Paragraph.Pages[CurPage - 1].EndInfo.RunRecalcInfo);
		this.RunRecalcInfoBreak = this.RunRecalcInfoLast;
	},

    // Обнуляем некоторые параметры перед новой строкой
    Reset_Line : function()
    {
        this.RecalcResult        = recalcresult_NextLine;

        this.EmptyLine           = true;
        this.BreakPageLine       = false;
        this.End                 = false;
        this.UseFirstLine        = false;
        this.BreakRealPageLine   = false;
        this.BadLeftTab          = false
		this.TextOnLine          = false;

        this.LineTextAscent      = 0;
        this.LineTextAscent2     = 0;
        this.LineTextDescent     = 0;
        this.LineAscent          = 0;
        this.LineDescent         = 0;

        this.NewPage             = false;
        this.ForceNewPage        = false;
        this.ForceNewLine        = false;

        this.bMath_OneLine       = false;
        this.bMathWordLarge      = false;
        this.bEndRunToContent    = false;
        this.PosEndRun           = new CParagraphContentPos();
        this.Footnotes           = [];

        this.OperGapRight        = 0;
        this.OperGapLeft         = 0;
        this.WrapIndent          = 0;
        this.MathFirstItem       = true;
        this.bContainCompareOper = true;
        this.bInsideOper         = false;
        this.bOnlyForcedBreak    = false;
        this.bBreakBox           = false;
        this.bNoOneBreakOperator = true;
        this.bFastRecalculate    = false;
        this.bForcedBreak        = false;
        this.bBreakPosInLWord    = true;

        this.MathNotInline      = null;
    },

    // Обнуляем некоторые параметры перед новым отрезком
    Reset_Range : function(X, XEnd)
    {
        this.LastTab.Reset();

        this.SpaceLen        = 0;
        this.WordLen         = 0;
        this.SpacesCount     = 0;
        this.Word            = false;
        this.FirstItemOnLine = true;
        this.StartWord       = false;
        this.NewRange        = false;
        this.X               = X;
        this.XEnd            = XEnd;
        this.XRange          = X;

		this.MoveToLBP      = false;
		this.LineBreakPos   = new CParagraphContentPos();
		this.LineBreakFirst = true;
		this.LastItem       = null;

        // for ParaMath
        this.bMath_OneLine    = false;
        this.bMathWordLarge   = false;
        this.bEndRunToContent = false;
        this.PosEndRun        = new CParagraphContentPos();

        this.OperGapRight        = 0;
        this.OperGapLeft         = 0;
        this.WrapIndent          = 0;
        this.bContainCompareOper = true;
        this.bInsideOper         = false;
        this.bOnlyForcedBreak    = false;
        this.bBreakBox           = false;
        this.bNoOneBreakOperator = true;
        this.bForcedBreak        = false;
        this.bFastRecalculate    = false;
        this.bBreakPosInLWord    = true;
    },

    Reset_RestartPageRecalcInfo : function()
    {
        this.RestartPageRecalcInfo.Line   = 0;
        this.RestartPageRecalcInfo.Object = null;
    },

    Set_RestartPageRecalcInfo : function(Line, Object)
    {
        this.RestartPageRecalcInfo.Line   = Line;
        this.RestartPageRecalcInfo.Object = Object;
    },

    Set_LineBreakPos : function(PosObj, isFirstItemOnLine)
	{
		this.LineBreakPos.Set(this.CurPos);
		this.LineBreakPos.Add(PosObj);
		this.LineBreakFirst = isFirstItemOnLine;
	},

    Set_NumberingPos : function(PosObj, Item)
    {
        this.NumberingPos.Set( this.CurPos );
        this.NumberingPos.Add( PosObj );

        this.Paragraph.Numbering.Pos  = this.NumberingPos;
        this.Paragraph.Numbering.Item = Item;
    },

    Update_CurPos : function(PosObj, Depth)
    {
        this.CurPos.Update(PosObj, Depth);
    },

    Reset_Ranges : function()
    {
        this.Ranges      = [];
        this.RangesCount = 0;
    },

    Reset_RunRecalcInfo : function()
    {
        this.RunRecalcInfoBreak = this.RunRecalcInfoLast;
    },

    Reset_MathRecalcInfo: function()
    {
        this.bContinueRecalc = false;
    },

    Restore_RunRecalcInfo : function()
    {
        this.RunRecalcInfoLast = this.RunRecalcInfoBreak;
    },

    Recalculate_Numbering : function(Item, Run, ParaPr, _X)
    {
        var CurPage = this.Page, CurLine = this.Line, CurRange = this.Range;
        var Para = this.Paragraph;
        var X = _X, LineAscent = this.LineAscent;

        // Если нужно добавить нумерацию и на текущем элементе ее можно добавить, тогда добавляем её
        var NumberingItem = Para.Numbering;
        var NumberingType = Para.Numbering.Type;

        if ( para_Numbering === NumberingType )
		{
			var NumPr = ParaPr.NumPr;
			if (undefined === NumPr || undefined === NumPr.NumId || 0 === NumPr.NumId || "0" === NumPr.NumId || ( undefined !== Para.Get_SectionPr() && true === Para.IsEmpty() ))
			{
				// Так мы обнуляем все рассчитанные ширины данного элемента
				NumberingItem.Measure(g_oTextMeasurer, undefined);
			}
			else
			{
				var oNumbering  = Para.Parent.GetNumbering();
				var oNumLvl     = oNumbering.GetNum(NumPr.NumId).GetLvl(NumPr.Lvl);
				var nNumSuff    = oNumLvl.GetSuff();
				var nNumJc      = oNumLvl.GetJc();
				var oNumInfo    = Para.Parent.CalculateNumberingValues(Para, NumPr);
				var oNumTextPr  = Para.Get_CompiledPr2(false).TextPr.Copy();
				oNumTextPr.Merge(Para.TextPr.Value);
				oNumTextPr.Merge(oNumLvl.GetTextPr());


				// Здесь измеряется только ширина символов нумерации, без суффикса
				NumberingItem.Measure(g_oTextMeasurer, oNumbering, oNumInfo, oNumTextPr, NumPr, Para.Get_Theme());

				// При рассчете высоты строки, если у нас параграф со списком, то размер символа
				// в списке влияет только на высоту строки над Baseline, но не влияет на высоту строки
				// ниже baseline.
				if (LineAscent < NumberingItem.Height)
					LineAscent = NumberingItem.Height;

				switch (nNumJc)
				{
					case AscCommon.align_Right:
					{
						NumberingItem.WidthVisible = 0;
						break;
					}
					case AscCommon.align_Center:
					{
						NumberingItem.WidthVisible = NumberingItem.WidthNum / 2;
						break;
					}
					case AscCommon.align_Left:
					default:
					{
						NumberingItem.WidthVisible = NumberingItem.WidthNum;
						break;
					}
				}

				X += NumberingItem.WidthVisible;

				if (oNumLvl.IsLegacy())
				{
					var nLegacySpace  = AscCommon.TwipsToMM(oNumLvl.GetLegacySpace());
					var nLegacyIndent = AscCommon.TwipsToMM(oNumLvl.GetLegacyIndent());
					var nNumWidth     = NumberingItem.WidthNum;

					NumberingItem.WidthSuff = Math.max(nNumWidth, nLegacyIndent, nNumWidth + nLegacySpace) - nNumWidth;
				}
				else
				{
					switch (nNumSuff)
					{
						case Asc.c_oAscNumberingSuff.None:
						{
							// Ничего не делаем
							break;
						}
						case Asc.c_oAscNumberingSuff.Space:
						{
							var OldTextPr = g_oTextMeasurer.GetTextPr();


							var Theme = Para.Get_Theme();
							g_oTextMeasurer.SetTextPr(oNumTextPr, Theme);
							g_oTextMeasurer.SetFontSlot(fontslot_ASCII);
							NumberingItem.WidthSuff = g_oTextMeasurer.Measure(" ").Width;
							g_oTextMeasurer.SetTextPr(OldTextPr, Theme);
							break;
						}
						case Asc.c_oAscNumberingSuff.Tab:
						{
							var NewX = Para.private_RecalculateGetTabPos(X, ParaPr, CurPage, true).NewX;

							NumberingItem.WidthSuff = NewX - X;

							break;
						}
					}
				}

				NumberingItem.Width = NumberingItem.WidthNum;
				NumberingItem.WidthVisible += NumberingItem.WidthSuff;

				X += NumberingItem.WidthSuff;
			}
		}
        else if ( para_PresentationNumbering === NumberingType )
        {
            var Level = Para.PresentationPr.Level;
            var Bullet = Para.PresentationPr.Bullet;

            var BulletNum = 0;
            if (Bullet.Get_Type() >= numbering_presentationnumfrmt_ArabicPeriod)
            {
                var Prev = Para.Prev;
                while (null != Prev && type_Paragraph === Prev.GetType())
                {
                    var PrevLevel = Prev.PresentationPr.Level;
                    var PrevBullet = Prev.Get_PresentationNumbering();

                    // Если предыдущий параграф более низкого уровня, тогда его не учитываем
                    if (Level < PrevLevel)
                    {
                        Prev = Prev.Prev;
                        continue;
                    }
                    else if (Level > PrevLevel)
                        break;
                    else if (PrevBullet.Get_Type() === Bullet.Get_Type() && PrevBullet.Get_StartAt() === PrevBullet.Get_StartAt())
                    {
                        if (true != Prev.IsEmpty())
                            BulletNum++;

                        Prev = Prev.Prev;
                    }
                    else
                        break;
                }
            }

            // Найдем настройки для первого текстового элемента
            var FirstTextPr = Para.Get_FirstTextPr2();

            NumberingItem.Bullet = Bullet;
            NumberingItem.BulletNum = BulletNum + 1;
            NumberingItem.Measure(g_oTextMeasurer, FirstTextPr, Para.Get_Theme(), Para.Get_ColorMap());


            if ( numbering_presentationnumfrmt_None != Bullet.Get_Type() )
            {
                if ( ParaPr.Ind.FirstLine < 0 )
                    NumberingItem.WidthVisible = Math.max( NumberingItem.Width, Para.Pages[CurPage].X + ParaPr.Ind.Left + ParaPr.Ind.FirstLine - X, Para.Pages[CurPage].X + ParaPr.Ind.Left - X );
                else
                    NumberingItem.WidthVisible = Math.max(Para.Pages[CurPage].X + ParaPr.Ind.Left + NumberingItem.Width - X, Para.Pages[CurPage].X + ParaPr.Ind.Left + ParaPr.Ind.FirstLine - X, Para.Pages[CurPage].X + ParaPr.Ind.Left - X );
            }

            X += NumberingItem.WidthVisible;
        }

        // Заполним обратные данные в элементе нумерации
        NumberingItem.Item       = Item;
        NumberingItem.Run        = Run;
        NumberingItem.Line       = CurLine;
        NumberingItem.Range      = CurRange;
        NumberingItem.LineAscent = LineAscent;
        NumberingItem.Page       = CurPage;

        return X;
    }
};
CParagraphRecalculateStateWrap.prototype.IsFast = function()
{
	return this.Fast;
};
CParagraphRecalculateStateWrap.prototype.AddFootnoteReference = function(oFootnoteReference, oPos)
{
	// Ссылки могут добавляться несколько раз, если строка разбита на несколько отрезков
	for (var nIndex = 0, nCount = this.Footnotes.length; nIndex < nCount; ++nIndex)
	{
		if (this.Footnotes[nIndex].FootnoteReference === oFootnoteReference)
			return;
	}

	this.Footnotes.push({FootnoteReference : oFootnoteReference, Pos : oPos});
};
CParagraphRecalculateStateWrap.prototype.GetFootnoteReferencesCount = function(oFootnoteReference, isAllowCustom)
{
	var _isAllowCustom = (true === isAllowCustom ? true : false);

	// Если данную ссылку мы добавляли уже в строке, тогда ищем сколько было элементов до нее, если не добавляли,
	// тогда возвращаем просто количество ссылок. Ссылки с флагом CustomMarkFollows не учитываются

	var nRefsCount = 0;
	for (var nIndex = 0, nCount = this.Footnotes.length; nIndex < nCount; ++nIndex)
	{
		if (this.Footnotes[nIndex].FootnoteReference === oFootnoteReference)
			return nRefsCount;

		if (true === _isAllowCustom || true !== this.Footnotes[nIndex].FootnoteReference.IsCustomMarkFollows())
			nRefsCount++;
	}

	return nRefsCount;
};
CParagraphRecalculateStateWrap.prototype.SetFast = function(bValue)
{
	this.Fast = bValue;
};
CParagraphRecalculateStateWrap.prototype.IsFastRecalculate = function()
{
	return this.Fast;
};
CParagraphRecalculateStateWrap.prototype.GetPageAbs = function()
{
	return this.PageAbs;
};
CParagraphRecalculateStateWrap.prototype.GetColumnAbs = function()
{
	return this.ColumnAbs;
};
CParagraphRecalculateStateWrap.prototype.GetCurrentContentPos = function(nPos)
{
	var oContentPos = this.CurPos.Copy();
	oContentPos.Set(this.CurPos);
	oContentPos.Add(nPos);
	return oContentPos;
};
CParagraphRecalculateStateWrap.prototype.SaveFootnotesInfo = function()
{
	var oTopDocument = this.TopDocument;
	if (oTopDocument instanceof CDocument)
		this.FootnotesRecalculateObject = oTopDocument.Footnotes.SaveRecalculateObject(this.PageAbs, this.ColumnAbs);
};
CParagraphRecalculateStateWrap.prototype.LoadFootnotesInfo = function()
{
	var oTopDocument = this.TopDocument;
	if (oTopDocument instanceof CDocument && this.FootnotesRecalculateObject)
		oTopDocument.Footnotes.LoadRecalculateObject(this.PageAbs, this.ColumnAbs, this.FootnotesRecalculateObject);
};
CParagraphRecalculateStateWrap.prototype.IsInTable = function()
{
	return this.InTable;
};
CParagraphRecalculateStateWrap.prototype.GetSectPr = function()
{
	if (null === this.SectPr && this.Paragraph)
		this.SectPr = this.Paragraph.Get_SectPr();

	return this.SectPr;
};
CParagraphRecalculateStateWrap.prototype.GetTopDocument = function()
{
	return this.TopDocument;
};
CParagraphRecalculateStateWrap.prototype.GetTopIndex = function()
{
	if (-1 === this.TopIndex)
	{
		var arrPos = this.Paragraph.GetDocumentPositionFromObject();
		if (arrPos.length > 0)
			this.TopIndex = arrPos[0].Position;
	}

	return this.TopIndex;
};

function CParagraphRecalculateStateCounter()
{
    this.Paragraph   = undefined;
    this.Range       = undefined;
    this.Word        = false;
    this.SpaceLen    = 0;
    this.SpacesCount = 0;

    this.Words       = 0;
    this.Spaces      = 0;
    this.Letters     = 0;
    this.SpacesSkip  = 0;
    this.LettersSkip = 0;

    this.ComplexFields = new CParagraphComplexFieldsInfo();
}

CParagraphRecalculateStateCounter.prototype =
{
    Reset : function(Paragraph, Range)
    {
        this.Paragraph   = Paragraph;
        this.Range       = Range;
        this.Word        = false;
        this.SpaceLen    = 0;
        this.SpacesCount = 0;

        this.Words       = 0;
        this.Spaces      = 0;
        this.Letters     = 0;
        this.SpacesSkip  = 0;
        this.LettersSkip = 0;
    }
};

function CParagraphRecalculateStateAlign()
{
    this.X             = 0; // Текущая позиция по горизонтали
    this.Y             = 0; // Текущая позиция по вертикали
    this.XEnd          = 0; // Предельная позиция по горизонтали
    this.JustifyWord   = 0; // Добавочная ширина символов
    this.JustifySpace  = 0; // Добавочная ширина пробелов
    this.SpacesCounter = 0; // Счетчик пробелов с добавочной шириной (чтобы пробелы в конце строки не трогать)
    this.SpacesSkip    = 0; // Количество пробелов, которые мы пропускаем в начале строки
    this.LettersSkip   = 0; // Количество букв, которые мы пропускаем (из-за таба)
    this.LastW         = 0; // Ширина последнего элемента (необходимо для позиционирования картинки)
    this.Paragraph     = undefined;
    this.RecalcResult  = 0x00;//recalcresult_NextElement;

    this.Y0            = 0; // Верхняя граница строки
    this.Y1            = 0; // Нижняя граница строки

    this.CurPage       = 0;
    this.PageY         = 0;
    this.PageX         = 0;

    this.RecalcFast    = false; // Если пересчет быстрый, тогда все "плавающие" объекты мы не трогаем
    this.RecalcFast2   = false; // Второй вариант быстрого пересчета

	this.ComplexFields = new CParagraphComplexFieldsInfo();
}

function CParagraphRecalculateStateInfo()
{
    this.Comments      = [];
    this.ComplexFields = [];
}
CParagraphRecalculateStateInfo.prototype.Reset = function(PrevInfo)
{
	if (null !== PrevInfo && undefined !== PrevInfo)
	{
		this.Comments      = PrevInfo.Comments;
		this.ComplexFields = [];

		if (PrevInfo.ComplexFields)
		{
			for (var nIndex = 0, nCount = PrevInfo.ComplexFields.length; nIndex < nCount; ++nIndex)
			{
				this.ComplexFields[nIndex] = PrevInfo.ComplexFields[nIndex].Copy();
			}
		}
	}
	else
	{
		this.Comments      = [];
		this.ComplexFields = [];
	}
};
CParagraphRecalculateStateInfo.prototype.AddComment = function(Id)
{
	this.Comments.push(Id);
};
CParagraphRecalculateStateInfo.prototype.RemoveComment = function(Id)
{
	var CommentsLen = this.Comments.length;
	for (var CurPos = 0; CurPos < CommentsLen; CurPos++)
	{
		if (this.Comments[CurPos] === Id)
		{
			this.Comments.splice(CurPos, 1);
			break;
		}
	}
};
CParagraphRecalculateStateInfo.prototype.ProcessFieldChar = function(oFieldChar)
{
	if (!oFieldChar || !oFieldChar.IsUse())
		return;

	var oComplexField = oFieldChar.GetComplexField();

	if (oFieldChar.IsBegin())
	{
		this.ComplexFields.push(new CComplexFieldStatePos(oComplexField, true));
	}
	else if (oFieldChar.IsSeparate())
	{
		for (var nIndex = 0, nCount = this.ComplexFields.length; nIndex < nCount; ++nIndex)
		{
			if (oComplexField === this.ComplexFields[nIndex].ComplexField)
			{
				this.ComplexFields[nIndex].SetFieldCode(false);
				break;
			}
		}
	}
	else if (oFieldChar.IsEnd())
	{
		for (var nIndex = 0, nCount = this.ComplexFields.length; nIndex < nCount; ++nIndex)
		{
			if (oComplexField === this.ComplexFields[nIndex].ComplexField)
			{
				this.ComplexFields.splice(nIndex, 1);
				break;
			}
		}
	}
};
CParagraphRecalculateStateInfo.prototype.IsComplexField = function()
{
	return (this.ComplexFields.length > 0 ? true : false);
};
CParagraphRecalculateStateInfo.prototype.IsComplexFieldCode = function()
{
	if (!this.IsComplexField())
		return false;

	for (var nIndex = 0, nCount = this.ComplexFields.length; nIndex < nCount; ++nIndex)
	{
		if (this.ComplexFields[nIndex].IsFieldCode())
			return true;
	}

	return false;
};


function CParagraphRecalculateObject()
{
    this.X      = 0;
    this.Y      = 0;
    this.XLimit = 0;
    this.YLimit = 0;

    this.Pages   = [];
    this.Lines   = [];
    this.Content = [];
}

CParagraphRecalculateObject.prototype =
{
    Save : function(Para)
    {
        this.X      = Para.X;
        this.Y      = Para.Y;
        this.XLimit = Para.XLimit;
        this.YLimit = Para.YLimit;

        this.Pages  = Para.Pages;
        this.Lines  = Para.Lines;

        var Content = Para.Content;
        var Count = Content.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            this.Content[Index] = Content[Index].SaveRecalculateObject();
        }
    },

    Load : function(Para)
    {
        Para.X      = this.X;
        Para.Y      = this.Y;
        Para.XLimit = this.XLimit;
        Para.YLimit = this.YLimit;

        Para.Pages = this.Pages;
        Para.Lines = this.Lines;

        var Count = Para.Content.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            Para.Content[Index].LoadRecalculateObject(this.Content[Index], Para);
        }
    },

    Get_DrawingFlowPos : function(FlowPos)
    {
        var Count = this.Content.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            this.Content[Index].Get_DrawingFlowPos( FlowPos );
        }
    }
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

//     SectPr  : Настройки секци (размеры, поля)
//               PgSz : размеры страницы
//                     W, H, Orient
//               PgMar: отступы страницы
//                      Top, Left, Right, Bottom, Header, Footer
//

// Import
var g_oTableId = AscCommon.g_oTableId;
var History = AscCommon.History;

var section_borders_DisplayAllPages     = 0x00;
var section_borders_DisplayFirstPage    = 0x01;
var section_borders_DisplayNotFirstPage = 0x02;

var section_borders_OffsetFromPage = 0x00;
var section_borders_OffsetFromText = 0x01;

var section_borders_ZOrderBack  = 0x00;
var section_borders_ZOrderFront = 0x01;

var section_footnote_RestartContinuous = 0x00;
var section_footnote_RestartEachSect   = 0x01;
var section_footnote_RestartEachPage   = 0x02;

var section_footnote_PosBeneathText = 0x00;
var section_footnote_PosDocEnd      = 0x01;
var section_footnote_PosPageBottom  = 0x02;
var section_footnote_PosSectEnd     = 0x03;

function CSectionPr(LogicDocument)
{
    this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.Type          = 'undefined' !== typeof c_oAscSectionBreakType ? c_oAscSectionBreakType.NextPage : undefined;
    this.PageSize      = new CSectionPageSize();
    this.PageMargins   = new CSectionPageMargins();

    this.LogicDocument = LogicDocument;

    this.Borders       = new CSectionBorders();
    this.PageNumType   = new CSectionPageNumType();

    this.FooterFirst   = null;
    this.FooterEven    = null;
    this.FooterDefault = null;

    this.HeaderFirst   = null;
    this.HeaderEven    = null;
    this.HeaderDefault = null;

    this.TitlePage     = false;

    this.Columns       = new CSectionColumns(this);
	this.FootnotePr    = new CFootnotePr();

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    g_oTableId.Add( this, this.Id );
}

CSectionPr.prototype =
{
    Get_Id : function()
    {
        return this.Id;
    },

    Copy : function(Other, CopyHdrFtr)
    {
        if (!Other)
            return;

        // Тип
        this.Set_Type( Other.Type );

        // Настройки страницы
        this.Set_PageSize( Other.PageSize.W, Other.PageSize.H );
        this.Set_Orientation( Other.PageSize.Orient, false );

        // Настройки отступов
        this.Set_PageMargins( Other.PageMargins.Left, Other.PageMargins.Top, Other.PageMargins.Right, Other.PageMargins.Bottom );

        // Настройки границ
        this.Set_Borders_Left( Other.Borders.Left );
        this.Set_Borders_Top( Other.Borders.Top );
        this.Set_Borders_Right( Other.Borders.Right );
        this.Set_Borders_Bottom( Other.Borders.Bottom );
        this.Set_Borders_Display( Other.Borders.Display );
        this.Set_Borders_OffsetFrom( Other.Borders.OffsetFrom );
        this.Set_Borders_ZOrder( Other.Borders.ZOrder );

        // Колонтитулы
        if (true === CopyHdrFtr)
        {
            if (Other.HeaderFirst)
                this.Set_Header_First(Other.HeaderFirst.Copy());
            else
                this.Set_Header_First(null);

            if (Other.HeaderEven)
                this.Set_Header_Even(Other.HeaderEven.Copy());
            else
                this.Set_Header_Even(null);

            if (Other.HeaderDefault)
                this.Set_Header_Default(Other.HeaderDefault.Copy());
            else
                this.Set_Header_Default(null);

            if (Other.FooterFirst)
                this.Set_Footer_First(Other.FooterFirst.Copy());
            else
                this.Set_Footer_First(null);

            if (Other.FooterEven)
                this.Set_Footer_Even(Other.FooterEven.Copy());
            else
                this.Set_Footer_Even(null);

            if (Other.FooterDefault)
                this.Set_Footer_Default(Other.FooterDefault.Copy());
            else
                this.Set_Footer_Default(null);
        }
        else
        {
            this.Set_Header_First(Other.HeaderFirst);
            this.Set_Header_Even(Other.HeaderEven);
            this.Set_Header_Default(Other.HeaderDefault);
            this.Set_Footer_First(Other.FooterFirst);
            this.Set_Footer_Even(Other.FooterEven);
            this.Set_Footer_Default(Other.FooterDefault);
        }

        this.Set_PageNum_Start( Other.PageNumType.Start );

        this.Set_Columns_EqualWidth(Other.Columns.EqualWidth);
        this.Set_Columns_Num(Other.Columns.Num);
        this.Set_Columns_Sep(Other.Columns.Sep);
        this.Set_Columns_Space(Other.Columns.Space);
        for (var ColumnIndex = 0, ColumnsCount = Other.Columns.Cols.length; ColumnIndex < ColumnsCount; ++ColumnIndex)
        {
            var Column = Other.Columns.Cols[ColumnIndex];
            this.Set_Columns_Col(ColumnIndex, Column.W, Column.Space);
        }

        this.SetFootnotePos(Other.FootnotePr.Pos);
        this.SetFootnoteNumStart(Other.FootnotePr.NumStart);
        this.SetFootnoteNumRestart(Other.FootnotePr.NumRestart);
        this.SetFootnoteNumFormat(Other.FootnotePr.NumFormat);
    },
    
    Clear_AllHdrFtr : function()
    {
        this.Set_Header_First(null);
        this.Set_Header_Even(null);
        this.Set_Header_Default(null);
        this.Set_Footer_First(null);
        this.Set_Footer_Even(null);
        this.Set_Footer_Default(null);
    },

    Get_AllHdrFtrs : function(HdrFtrs)
    {
        if (!HdrFtrs)
            HdrFtrs = [];

        if (null !== this.HeaderFirst) HdrFtrs.push(this.HeaderFirst);
        if (null !== this.HeaderEven) HdrFtrs.push(this.HeaderEven);
        if (null !== this.HeaderDefault) HdrFtrs.push(this.HeaderDefault);

        if (null !== this.FooterFirst) HdrFtrs.push(this.FooterFirst);
        if (null !== this.FooterEven) HdrFtrs.push(this.FooterEven);
        if (null !== this.FooterDefault) HdrFtrs.push(this.FooterDefault);

        return HdrFtrs;
    },

    Compare_PageSize : function(OtherSectionPr)
    {
        var ThisPS = this.PageSize;
        var OtherPS = OtherSectionPr.PageSize;

        if ( Math.abs( ThisPS.W - OtherPS.W ) > 0.001 || Math.abs( ThisPS.H - OtherPS.H ) > 0.001 || ThisPS.Orient !== OtherPS.Orient )
            return false;

        return true;
    },

	Set_Type : function(Type)
	{
		if (this.Type !== Type)
		{
			History.Add(new CChangesSectionType(this, this.Type, Type));
			this.Type = Type;
		}
	},

    Get_Type : function()
    {
        return this.Type;
    },

	Set_PageSize : function(W, H)
	{
		if (Math.abs(W - this.PageSize.W) > 0.001 || Math.abs(H - this.PageSize.H) > 0.001)
		{
			H = Math.max(2.6, H);
			W = Math.max(12.7, W);

			History.Add(new CChangesSectionPageSize(this, {W : this.PageSize.W, H : this.PageSize.H}, {W : W, H : H}));

			this.PageSize.W = W;
			this.PageSize.H = H;
		}
	},

    Get_PageWidth : function()
    {
        return this.PageSize.W;
    },

    Get_PageHeight : function()
    {
        return this.PageSize.H;
    },

	Set_PageMargins : function(_L, _T, _R, _B)
	{
		// Значения могут прийти как undefined, в этом случае мы поля со значением undefined не меняем
		var L = ( undefined !== _L ? _L : this.PageMargins.Left );
		var T = ( undefined !== _T ? _T : this.PageMargins.Top );
		var R = ( undefined !== _R ? _R : this.PageMargins.Right );
		var B = ( undefined !== _B ? _B : this.PageMargins.Bottom );

		if (Math.abs(L - this.PageMargins.Left) > 0.001 || Math.abs(T - this.PageMargins.Top) > 0.001 || Math.abs(R - this.PageMargins.Right) > 0.001 || Math.abs(B - this.PageMargins.Bottom) > 0.001)
		{
			History.Add(new CChangesSectionPageMargins(this, {
				L : this.PageMargins.Left,
				T : this.PageMargins.Top,
				R : this.PageMargins.Right,
				B : this.PageMargins.Bottom
			}, {L : L, T : T, R : R, B : B}));

			this.PageMargins.Left   = L;
			this.PageMargins.Top    = T;
			this.PageMargins.Right  = R;
			this.PageMargins.Bottom = B;
		}
	},

    Get_PageMargin_Left : function()
    {
        return this.PageMargins.Left;
    },

    Get_PageMargin_Right : function()
    {
        return this.PageMargins.Right;
    },

    Get_PageMargin_Top : function()
    {
        return this.PageMargins.Top;
    },

    Get_PageMargin_Bottom : function()
    {
        return this.PageMargins.Bottom;
    },

	Set_Orientation : function(Orient, ApplySize)
	{
		var _Orient = this.Get_Orientation();
		if (_Orient !== Orient)
		{
			History.Add(new CChangesSectionPageOrient(this, this.PageSize.Orient, Orient));
			this.PageSize.Orient = Orient;

			if (true === ApplySize)
			{
				// При смене ориентации меняем местами высоту и ширину страницы и изменяем отступы

				var W = this.PageSize.W;
				var H = this.PageSize.H;

				var L = this.PageMargins.Left;
				var R = this.PageMargins.Right;
				var T = this.PageMargins.Top;
				var B = this.PageMargins.Bottom;

				this.Set_PageSize(H, W);

				if (Asc.c_oAscPageOrientation.PagePortrait === Orient)
					this.Set_PageMargins(T, R, B, L);
				else
					this.Set_PageMargins(B, L, T, R);
			}
		}
	},

    Get_Orientation : function()
    {
    	if (this.PageSize.W > this.PageSize.H)
    		return Asc.c_oAscPageOrientation.PageLandscape;

    	return Asc.c_oAscPageOrientation.PagePortrait;
    },

	Set_Borders_Left : function(Border)
	{
		if (true !== this.Borders.Left.Compare(Border))
		{
			History.Add(new CChangesSectionBordersLeft(this, this.Borders.Left, Border));
			this.Borders.Left = Border;
		}
	},

    Get_Borders_Left : function()
    {
        return this.Borders.Left;
    },

	Set_Borders_Top : function(Border)
	{
		if (true !== this.Borders.Top.Compare(Border))
		{
			History.Add(new CChangesSectionBordersTop(this, this.Borders.Top, Border));
			this.Borders.Top = Border;
		}
	},

    Get_Borders_Top : function()
    {
        return this.Borders.Top;
    },

	Set_Borders_Right : function(Border)
	{
		if (true !== this.Borders.Right.Compare(Border))
		{
			History.Add(new CChangesSectionBordersRight(this, this.Borders.Right, Border));
			this.Borders.Right = Border;
		}
	},

    Get_Borders_Right : function()
    {
        return this.Borders.Right;
    },

	Set_Borders_Bottom : function(Border)
	{
		if (true !== this.Borders.Bottom.Compare(Border))
		{
			History.Add(new CChangesSectionBordersBottom(this, this.Borders.Bottom, Border));
			this.Borders.Bottom = Border;
		}
	},

    Get_Borders_Bottom : function()
    {
        return this.Borders.Bottom;
    },

	Set_Borders_Display : function(Display)
	{
		if (Display !== this.Borders.Display)
		{
			History.Add(new CChangesSectionBordersDisplay(this, this.Borders.Display, Display));
			this.Borders.Display = Display;
		}
	},

    Get_Borders_Display : function()
    {
        return this.Borders.Display;
    },

	Set_Borders_OffsetFrom : function(OffsetFrom)
	{
		if (OffsetFrom !== this.Borders.OffsetFrom)
		{
			History.Add(new CChangesSectionBordersOffsetFrom(this, this.Borders.OffsetFrom, OffsetFrom));
			this.Borders.OffsetFrom = OffsetFrom;
		}
	},

    Get_Borders_OffsetFrom : function()
    {
        return this.Borders.OffsetFrom;
    },

	Set_Borders_ZOrder : function(ZOrder)
	{
		if (ZOrder !== this.Borders.ZOrder)
		{
			History.Add(new CChangesSectionBordersZOrder(this, this.Borders.ZOrder, ZOrder));
			this.Borders.ZOrder = ZOrder;
		}
	},

    Get_Borders_ZOrder : function()
    {
        return this.Borders.ZOrder;
    },

	Set_Footer_First : function(Footer)
	{
		if (Footer !== this.FooterFirst)
		{
			History.Add(new CChangesSectionFooterFirst(this, this.FooterFirst, Footer));
			this.FooterFirst = Footer;
		}
	},
    
    Get_Footer_First : function()
    {
        return this.FooterFirst;
    },

	Set_Footer_Even : function(Footer)
	{
		if (Footer !== this.FooterEven)
		{
			History.Add(new CChangesSectionFooterEven(this, this.FooterEven, Footer));
			this.FooterEven = Footer;
		}
	},

    Get_Footer_Even : function()
    {
        return this.FooterEven;
    },

	Set_Footer_Default : function(Footer)
	{
		if (Footer !== this.FooterDefault)
		{
			History.Add(new CChangesSectionFooterDefault(this, this.FooterDefault, Footer));
			this.FooterDefault = Footer;
		}
	},

    Get_Footer_Default : function()
    {
        return this.FooterDefault;
    },

	Set_Header_First : function(Header)
	{
		if (Header !== this.HeaderFirst)
		{
			History.Add(new CChangesSectionHeaderFirst(this, this.HeaderFirst, Header));
			this.HeaderFirst = Header;
		}
	},

    Get_Header_First : function()
    {
        return this.HeaderFirst;
    },

	Set_Header_Even : function(Header)
	{
		if (Header !== this.HeaderEven)
		{
			History.Add(new CChangesSectionHeaderEven(this, this.HeaderEven, Header));
			this.HeaderEven = Header;
		}
	},

    Get_Header_Even : function()
    {
        return this.HeaderEven;
    },

	Set_Header_Default : function(Header)
	{
		if (Header !== this.HeaderDefault)
		{
			History.Add(new CChangesSectionHeaderDefault(this, this.HeaderDefault, Header));
			this.HeaderDefault = Header;
		}
	},

    Get_Header_Default : function()
    {
        return this.HeaderDefault;
    },

	Set_TitlePage : function(Value)
	{
		if (Value !== this.TitlePage)
		{
			History.Add(new CChangesSectionTitlePage(this, this.TitlePage, Value));
			this.TitlePage = Value;
		}
	},
    
    Get_TitlePage : function()
    {
        return this.TitlePage;
    },

	Set_PageMargins_Header : function(Header)
	{
		if (Header !== this.PageMargins.Header)
		{
			History.Add(new CChangesSectionPageMarginsHeader(this, this.PageMargins.Header, Header));
			this.PageMargins.Header = Header;
		}
	},
    
    Get_PageMargins_Header : function()
    {
        return this.PageMargins.Header;
    },

	Set_PageMargins_Footer : function(Footer)
	{
		if (Footer !== this.PageMargins.Footer)
		{
			History.Add(new CChangesSectionPageMarginsFooter(this, this.PageMargins.Footer, Footer));
			this.PageMargins.Footer = Footer;
		}
	},

    Get_PageMargins_Footer : function()
    {
        return this.PageMargins.Footer;
    },
    
    Get_HdrFtr : function(bHeader, bFirst, bEven)
    {
        if ( true === bHeader )
        {
            if ( true === bFirst )
                return this.HeaderFirst;
            else if ( true === bEven )
                return this.HeaderEven;
            else
                return this.HeaderDefault;
        }
        else
        {
            if ( true === bFirst )
                return this.FooterFirst;
            else if ( true === bEven )
                return this.FooterEven;
            else
                return this.FooterDefault;
        }
    },
    
    Set_HdrFtr : function(bHeader, bFirst, bEven, HdrFtr)
    {
        if ( true === bHeader )
        {
            if ( true === bFirst )
                return this.Set_Header_First( HdrFtr );
            else if ( true === bEven )
                return this.Set_Header_Even( HdrFtr );
            else
                return this.Set_Header_Default( HdrFtr );
        }
        else
        {
            if ( true === bFirst )
                return this.Set_Footer_First( HdrFtr );
            else if ( true === bEven )
                return this.Set_Footer_Even( HdrFtr );
            else
                return this.Set_Footer_Default( HdrFtr );
        }
    },
    
    Get_HdrFtrInfo : function(HdrFtr)
    {
        if  ( HdrFtr === this.HeaderFirst )
            return { Header : true, First : true, Even : false };
        else if ( HdrFtr === this.HeaderEven )
            return { Header : true, First : false, Even : true };
        else if ( HdrFtr === this.HeaderDefault )
            return { Header : true, First : false, Even : false };
        else if ( HdrFtr === this.FooterFirst )
            return { Header : false, First : true, Even : false };
        else if ( HdrFtr === this.FooterEven )
            return { Header : false, First : false, Even : true };
        else if ( HdrFtr === this.FooterDefault )
            return { Header : false, First : false, Even : false };

        return null;
    },

	Set_PageNum_Start : function(Start)
	{
		if (Start !== this.PageNumType.Start)
		{
			History.Add(new CChangesSectionPageNumTypeStart(this, this.PageNumType.Start, Start));
			this.PageNumType.Start = Start;
		}
	},
    
    Get_PageNum_Start : function()
    {
        return this.PageNumType.Start;
    },

    Get_ColumnsCount : function()
    {
        return this.Columns.Get_Count();
    },

    Get_ColumnWidth : function(ColIndex)
    {
        return this.Columns.Get_ColumnWidth(ColIndex);
    },

    Get_ColumnSpace : function(ColIndex)
    {
        return this.Columns.Get_ColumnSpace(ColIndex);
    },

	Get_ColumnsSep : function()
	{
		return this.Columns.Sep;
	},

	Set_Columns_EqualWidth : function(Equal)
	{
		if (Equal !== this.Columns.Equal)
		{
			History.Add(new CChangesSectionColumnsEqualWidth(this, this.Columns.EqualWidth, Equal));
			this.Columns.EqualWidth = Equal;
		}
	},

	Set_Columns_Space : function(Space)
	{
		if (Space !== this.Columns.Space)
		{
			History.Add(new CChangesSectionColumnsSpace(this, this.Columns.Space, Space));
			this.Columns.Space = Space;
		}
	},

	Set_Columns_Num : function(_Num)
	{
		var Num = Math.max(_Num, 1);

		if (Num !== this.Columns.Num)
		{
			History.Add(new CChangesSectionColumnsNum(this, this.Columns.Num, Num));
			this.Columns.Num = Num;
		}
	},

	Set_Columns_Sep : function(Sep)
	{
		if (Sep !== this.Columns.Sep)
		{
			History.Add(new CChangesSectionColumnsSep(this, this.Columns.Sep, Sep));
			this.Columns.Sep = Sep;
		}
	},

	Set_Columns_Cols : function(Cols)
	{
		History.Add(new CChangesSectionColumnsSetCols(this, this.Columns.Cols, Cols));
		this.Columns.Cols = Cols;
	},

	Set_Columns_Col : function(Index, W, Space)
	{
		var OldCol = this.Columns.Cols[Index];

		if (undefined === OldCol || OldCol.Space !== Space || OldCol.W !== W)
		{
			var NewCol   = new CSectionColumn();
			NewCol.W     = W;
			NewCol.Space = Space;

			History.Add(new CChangesSectionColumnsCol(this, OldCol, NewCol, Index));
			this.Columns.Cols[Index] = NewCol;
		}
	},
    
    Get_LayoutInfo : function()
    {
        // Получаем информацию о колонках в данной секции
        
        var Margins = this.PageMargins;
        var H       = this.PageSize.H;
        var _W      = this.PageSize.W;
        var W       = _W - Margins.Left - Margins.Right;
        
        // Если так случилось, что правое и левое поля в сумме больше ширины, тогда оставляем для документа 1 см ширины.
        if ( W < 0 )
            W = 10;
        
        var Columns = this.Columns;
        
        var Layout = new CSectionLayoutInfo(Margins.Left, Margins.Top, _W - Margins.Right, H - Margins.Bottom);
        var ColumnsInfo = Layout.Columns;
        
        if ( true === Columns.EqualWidth )
        {
            var Num   = Math.max( Columns.Num, 1 );
            var Space = Columns.Space;
            
            var ColW  = (W - Space * ( Num - 1 )) / Num;
            
            // Если так случилось, что под колонки места не осталось, тогда делаем колонки шириной 0.3 мм, оставшееся 
            // свободное место распределяем под Space, но если и оставшегося места не осталось, тогда Space делаем 0, а
            // колонки пусть выходят за пределы W.
            if ( ColW < 0 )
            {
                ColW = 0.3;
                
                var __W = W - ColW * Num;
                
                if ( _W > 0 && Num > 1 )
                    Space = _W / ( Num - 1 );
                else
                    Space = 0;
            }
            
            var X = Margins.Left;
            for ( var Pos = 0; Pos < Num; Pos++ )
            {
                var X0 = X;
                var X1 = X + ColW;
                
                ColumnsInfo.push( new CSectionLayoutColumnInfo(X0, X1) );
                
                X += ColW + Space;
            }
        }
        else
        {
            var Num = Columns.Cols.length;
            
            // Когда задаются колонки не равномерно, то Word плюет на поля, заданные в документа и ориентируется только
            // по размеру колонок дальше. (если ни 1 колонка не задана, тогда Word добавляет 1 колонку шириной 17.09 см)
            
            if ( Num <= 0 )
            {
                ColumnsInfo.push( new CSectionLayoutColumnInfo(Margins.Left, Margins.Left + 170.9) );
            }
            else
            {
                var X = Margins.Left;
                for ( var Pos = 0; Pos < Num; Pos++ )
                {
                    var Col = this.Columns.Cols[Pos];
                    var X0 = X;
                    var X1 = X + Col.W;

                    ColumnsInfo.push( new CSectionLayoutColumnInfo(X0, X1) );
                    
                    X += Col.W + Col.Space;
                }
            }
        }       
        
        return Layout;
    },
//----------------------------------------------------------------------------------------------------------------------
// Undo/Redo функции
//----------------------------------------------------------------------------------------------------------------------
    Refresh_RecalcData : function(Data)
    {
        // Найдем данную секцию в документе
        var Index = this.LogicDocument.SectionsInfo.Find( this );

        if ( -1 === Index )
            return;

        // Здесь есть 1 исключение: когда мы добавляем колонтитул для первой страницы, может так получиться, что 
        // у данной секции флаг TitlePage = False, а значит пересчет надо запускать с места где данный колонтитул
        // первый раз начнет использоваться, а не с текущей секции.

        if ( (AscDFH.historyitem_Section_Header_First === Data.Type || AscDFH.historyitem_Section_Footer_First === Data.Type) && false === this.TitlePage )
        {
            var bHeader = AscDFH.historyitem_Section_Header_First === Data.Type ? true : false
            var SectionsCount = this.LogicDocument.SectionsInfo.Get_SectionsCount();
            while ( Index < SectionsCount - 1 )
            {
                Index++;

                var TempSectPr = this.LogicDocument.SectionsInfo.Get_SectPr2(Index).SectPr;

                // Если в следующей секции свой колонтитул, тогда наш добавленный колонтитул вообще ни на что не влияет
                if ( (true === bHeader && null !== TempSectPr.Get_Header_First()) || (true !== bHeader && null !== TempSectPr.Get_Footer_First()) )
                    break;

                // Если в следующей секции есть титульная страница, значит мы нашли нужную секцию
                if ( true === TempSectPr.Get_TitlePage() )
                {
                    if ( 0 === Index )
                    {
                        this.LogicDocument.Refresh_RecalcData2(0, 0);
                    }
                    else
                    {
                        var DocIndex = this.LogicDocument.SectionsInfo.Elements[Index - 1].Index + 1;
                        this.LogicDocument.Refresh_RecalcData2( DocIndex, 0 );
                    }
                }
            }
        }
        else
        {
            if ( 0 === Index )
            {
                // Первая секция, значит мы должны пересчитать начиная с самого начала документа
                this.LogicDocument.Refresh_RecalcData2(0, 0);
            }
            else
            {
                // Ищем номер элемента, на котором закончилась предыдущая секция, начиная со следующего после него элемента
                // и пересчитываем документ. 
                var DocIndex = this.LogicDocument.SectionsInfo.Elements[Index - 1].Index + 1;
                this.LogicDocument.Refresh_RecalcData2( DocIndex, 0 );
            }
        }
        
        // Дополнительно кроме этого мы должны обновить пересчет в колонтитулах, причем только начиная с данной секции
        this.LogicDocument.On_SectionChange( this );
    },
//----------------------------------------------------------------------------------------------------------------------
// Функции совместного редактирования
//----------------------------------------------------------------------------------------------------------------------
    Write_ToBinary2 : function(Writer)
    {
        Writer.WriteLong( AscDFH.historyitem_type_Section );

        // String2  : Id
        // String2  : Id LogicDocument
        // Variable : PageSize
        // Variable : PageMargins
        // Byte     : Type
        // Variable : Borders        
        // Колонтитулы не пишем в бинарник, при созданиии класса они всегда null, а TitlePage = false
        // Variable : PageNumType
        // Variable : CSectionColumns
		// Variable : CFootnotePr

        Writer.WriteString2( "" + this.Id );
        Writer.WriteString2( "" + this.LogicDocument.Get_Id() );
        this.PageSize.Write_ToBinary( Writer );
        this.PageMargins.Write_ToBinary( Writer );
        Writer.WriteByte( this.Type );
        this.Borders.Write_ToBinary( Writer );
        this.PageNumType.Write_ToBinary( Writer );
        this.Columns.Write_ToBinary(Writer);
		this.FootnotePr.WriteToBinary(Writer);
    },

    Read_FromBinary2 : function(Reader)
    {
        // String2  : Id
        // String2  : Id LogicDocument
        // Variable : PageSize
        // Variable : PageMargins
        // Byte     : Type
        // Variable : Borders
        // Колонтитулы не пишем в бинарник, при созданиии класса они всегда null, а TitlePage = false
        // Variable : PageNumType
        // Variable : CSectionColumns
		// Variable : CFootnotePr

        this.Id = Reader.GetString2();
        this.LogicDocument = g_oTableId.Get_ById( Reader.GetString2() );
        this.PageSize.Read_FromBinary( Reader );
        this.PageMargins.Read_FromBinary( Reader );
        this.Type = Reader.GetByte();
        this.Borders.Read_FromBinary( Reader );
        this.PageNumType.Read_FromBinary( Reader );
        this.Columns.Read_FromBinary(Reader);
		this.FootnotePr.ReadFromBinary(Reader);
    }
};
/**
 * Проверяем, есть ли хоть один колонтитул в данной секции
 * @returns {boolean}
 */
CSectionPr.prototype.IsAllHdrFtrNull = function()
{
	if (null !== this.FooterFirst
		|| null !== this.HeaderFirst
		|| null !== this.FooterDefault
		|| null !== this.HeaderDefault
		|| null !== this.FooterEven
		|| null !== this.HeaderEven)
		return false;

	return true;
};
CSectionPr.prototype.GetFootnotePr = function()
{
	return this.FootnotePr;
};
CSectionPr.prototype.SetFootnotePos = function(nPos)
{
	if (this.FootnotePr.Pos !== nPos)
	{
		History.Add(new CChangesSectionFootnotePos(this, this.FootnotePr.Pos, nPos));
		this.FootnotePr.Pos = nPos;
	}
};
CSectionPr.prototype.GetFootnotePos = function()
{
	if (undefined === this.FootnotePr.Pos)
		return section_footnote_PosPageBottom;

	return this.FootnotePr.Pos;
};
CSectionPr.prototype.SetFootnoteNumStart = function(nStart)
{
	if (this.FootnotePr.NumStart !== nStart)
	{
		History.Add(new CChangesSectionFootnoteNumStart(this, this.FootnotePr.NumStart, nStart));
		this.FootnotePr.NumStart = nStart;
	}
};
CSectionPr.prototype.GetFootnoteNumStart = function()
{
	if (undefined === this.FootnotePr.NumStart)
		return 1;

	return this.FootnotePr.NumStart;
};
CSectionPr.prototype.SetFootnoteNumRestart = function(nRestartType)
{
	if (this.FootnotePr.NumRestart !== nRestartType)
	{
		History.Add(new CChangesSectionFootnoteNumRestart(this, this.FootnotePr.NumRestart, nRestartType));
		this.FootnotePr.NumRestart = nRestartType;
	}
};
CSectionPr.prototype.GetFootnoteNumRestart = function()
{
	if (undefined === this.FootnotePr.NumRestart)
		return this.private_GetDocumentWideFootnotePr().NumRestart;

	return this.FootnotePr.NumRestart;
};
CSectionPr.prototype.SetFootnoteNumFormat = function(nFormatType)
{
	if (this.FootnotePr.NumFormat !== nFormatType)
	{
		History.Add(new CChangesSectionFootnoteNumFormat(this, this.FootnotePr.NumFormat, nFormatType));
		this.FootnotePr.NumFormat = nFormatType;
	}
};
CSectionPr.prototype.GetFootnoteNumFormat = function()
{
	if (undefined === this.FootnotePr.NumFormat)
		return this.private_GetDocumentWideFootnotePr().NumFormat;

	return this.FootnotePr.NumFormat;
};
CSectionPr.prototype.private_GetDocumentWideFootnotePr = function()
{
	return this.LogicDocument.Footnotes.FootnotePr;
};
CSectionPr.prototype.SetColumnProps = function(ColumnsProps)
{
	var EqualWidth = ColumnsProps.get_EqualWidth();
	this.Set_Columns_EqualWidth(ColumnsProps.get_EqualWidth());
	if (false === EqualWidth)
	{
		var X      = this.Get_PageMargin_Left();
		var XLimit = this.Get_PageWidth() - this.Get_PageMargin_Right();

		var Cols          = [];
		var SectionColumn = null;
		var Count         = ColumnsProps.get_ColsCount();
		for (var Index = 0; Index < Count; ++Index)
		{
			var Col             = ColumnsProps.get_Col(Index);
			SectionColumn       = new CSectionColumn();
			SectionColumn.W     = Col.get_W();
			SectionColumn.Space = Col.get_Space();

			if (X + SectionColumn.W > XLimit)
			{
				SectionColumn.W = XLimit - X;
				Cols.push(SectionColumn);
				X += SectionColumn.W;
				break;
			}

			X += SectionColumn.W;
			if (Index != Count - 1)
				X += SectionColumn.Space;

			Cols.push(SectionColumn);
		}

		if (SectionColumn && X < XLimit - 0.001)
		{
			SectionColumn.W += XLimit - X;
		}

		this.Set_Columns_Cols(Cols);
		this.Set_Columns_Num(Count);
	}
	else
	{
		this.Set_Columns_Num(ColumnsProps.get_Num());
		this.Set_Columns_Space(ColumnsProps.get_Space());
	}

	this.Set_Columns_Sep(ColumnsProps.get_Sep());
};

function CSectionPageSize()
{
    this.W      = 210;
    this.H      = 297;
    this.Orient = Asc.c_oAscPageOrientation.PagePortrait;
}

CSectionPageSize.prototype =
{
    Write_ToBinary : function(Writer)
    {
        // Double : W
        // Double : H
        // Byte   : Orient

        Writer.WriteDouble( this.W );
        Writer.WriteDouble( this.H );
        Writer.WriteByte( this.Orient );
    },

    Read_FromBinary : function(Reader)
    {
        // Double : W
        // Double : H
        // Byte   : Orient

        this.W      = Reader.GetDouble();
        this.H      = Reader.GetDouble();
        this.Orient = Reader.GetByte();
    }
};

function CSectionPageMargins()
{
    this.Left   = 30; // 3 cm
    this.Top    = 20; // 2 cm
    this.Right  = 15; // 1.5 cm
    this.Bottom = 20; // 2 cm
    
    this.Header = 12.5; // 1.25 cm
    this.Footer = 12.5; // 1.25 cm
}

CSectionPageMargins.prototype =
{
    Write_ToBinary : function(Writer)
    {
        // Double : Left
        // Double : Top
        // Double : Right
        // Double : Bottom
        // Double : Header
        // Double : Footer        

        Writer.WriteDouble( this.Left );
        Writer.WriteDouble( this.Top );
        Writer.WriteDouble( this.Right );
        Writer.WriteDouble( this.Bottom );
        Writer.WriteDouble( this.Header );
        Writer.WriteDouble( this.Footer );
    },

    Read_FromBinary : function(Reader)
    {
        // Double : Left
        // Double : Top
        // Double : Right
        // Double : Bottom
        // Double : Header
        // Double : Footer        

        this.Left   = Reader.GetDouble();
        this.Top    = Reader.GetDouble();
        this.Right  = Reader.GetDouble();
        this.Bottom = Reader.GetDouble();
        this.Header = Reader.GetDouble();
        this.Footer = Reader.GetDouble();
    }
};

function CSectionBorders()
{
    this.Top        = new CDocumentBorder();
    this.Bottom     = new CDocumentBorder();
    this.Left       = new CDocumentBorder();
    this.Right      = new CDocumentBorder();
    
    this.Display    = section_borders_DisplayAllPages;
    this.OffsetFrom = section_borders_OffsetFromPage;
    this.ZOrder     = section_borders_ZOrderFront;
}

CSectionBorders.prototype =
{
    Write_ToBinary : function(Writer)
    {
        // Variable : Left
        // Variable : Top
        // Variable : Right
        // Variable : Bottom
        // Byte     : Display
        // Byte     : OffsetFrom
        // Byte     : ZOrder

        this.Left.Write_ToBinary(Writer);
        this.Top.Write_ToBinary(Writer);
        this.Right.Write_ToBinary(Writer);
        this.Bottom.Write_ToBinary(Writer);
        Writer.WriteByte(this.Display);
        Writer.WriteByte(this.OffsetFrom);
        Writer.WriteByte(this.ZOrder);
    },

    Read_FromBinary : function(Reader)
    {
        // Variable : Left
        // Variable : Top
        // Variable : Right
        // Variable : Bottom
        // Byte     : Display
        // Byte     : OffsetFrom
        // Byte     : ZOrder

        this.Left.Read_FromBinary(Reader);
        this.Top.Read_FromBinary(Reader);
        this.Right.Read_FromBinary(Reader);
        this.Bottom.Read_FromBinary(Reader);

        this.Display    = Reader.GetByte();
        this.OffsetFrom = Reader.GetByte();
        this.ZOrder     = Reader.GetByte();
    }
};
CSectionBorders.prototype.IsEmptyBorders = function()
{
	if (this.Top.IsNone() && this.Bottom.IsNone() && this.Left.IsNone() && this.Right.IsNone())
		return true;

	return false;
};

function CSectionPageNumType()
{
    this.Start = -1;
}

CSectionPageNumType.prototype = 
{
    Write_ToBinary : function(Writer)
    {
        // Long : Start
        
        Writer.WriteLong( this.Start );
    },
    
    Read_FromBinary : function(Reader)
    {
        // Long : Start

        this.Start = Reader.GetLong();
    }    
};


function CSectionPageNumInfo(FP, CP, bFirst, bEven, PageNum)
{
    this.FirstPage = FP;
    this.CurPage   = CP;
    this.bFirst    = bFirst;
    this.bEven     = bEven;
    
    this.PageNum   = PageNum;
}

CSectionPageNumInfo.prototype =
{
    Compare : function(Other)
    {
        if ( undefined === Other || null === Other || this.CurPage !== Other.CurPage || this.bFirst !== Other.bFirst || this.bEven !== Other.bEven || this.PageNum !== Other.PageNum )
            return false;
        
        return true;
    }
};

function CSectionColumn()
{
	this.W     = 0;
	this.Space = 0;
}

CSectionColumn.prototype.Write_ToBinary  = function(Writer)
{
	// Double : W
	// Double : Space

	Writer.WriteDouble(this.W);
	Writer.WriteDouble(this.Space);
};
CSectionColumn.prototype.Read_FromBinary = function(Reader)
{
	// Double : W
	// Double : Space

	this.W     = Reader.GetDouble();
	this.Space = Reader.GetDouble();
};

function CSectionColumns(SectPr)
{
	this.SectPr     = SectPr;
	this.EqualWidth = true;
	this.Num        = 1;
	this.Sep        = false;
	this.Space      = 30;

	this.Cols = [];
}

CSectionColumns.prototype.Write_ToBinary  = function(Writer)
{
	// Bool   : Equal
	// Long   : Num
	// Bool   : Sep
	// Double : Space

	// Long   : Количество колонок
	// Variable : Сами колонки

	Writer.WriteBool(this.EqualWidth);
	Writer.WriteLong(this.Num);
	Writer.WriteBool(this.Sep);
	Writer.WriteDouble(this.Space);

	var Count = this.Cols.length;
	Writer.WriteLong(Count);

	for (var Pos = 0; Pos < Count; Pos++)
	{
		this.Cols[Pos].Write_ToBinary(Writer);
	}
};
CSectionColumns.prototype.Read_FromBinary = function(Reader)
{
	// Bool   : Equal
	// Long   : Num
	// Bool   : Sep
	// Double : Space

	// Long   : Количество колонок
	// Variable : Сами колонки

	this.EqualWidth = Reader.GetBool();
	this.Num        = Reader.GetLong();
	this.Sep        = Reader.GetBool();
	this.Space      = Reader.GetDouble();

	var Count = Reader.GetLong();
	this.Cols = [];

	for (var Pos = 0; Pos < Count; Pos++)
	{
		this.Cols[Pos] = new CSectionColumn();
		this.Cols[Pos].Read_FromBinary(Reader);
	}
};
CSectionColumns.prototype.Get_Count       = function()
{
	if (true === this.EqualWidth)
	{
		return this.Num;
	}
	else
	{
		if (this.Cols.length <= 0)
			return 1;

		return this.Cols.length;
	}
};
CSectionColumns.prototype.Get_ColumnWidth = function(ColIndex)
{
	if (true === this.EqualWidth)
	{
		var PageW   = this.SectPr.Get_PageWidth();
		var MarginL = this.SectPr.Get_PageMargin_Left();
		var MarginR = this.SectPr.Get_PageMargin_Right();
		return this.Num > 0 ? (PageW - MarginL - MarginR - this.Space * (this.Num - 1)) / this.Num : (PageW - MarginL - MarginR);
	}
	else
	{
		if (this.Cols.length <= 0)
			return 0;

		ColIndex = Math.max(0, Math.min(this.Cols.length - 1, ColIndex));
		if (ColIndex < 0)
			return 0;

		return this.Cols[ColIndex].W;
	}
};
CSectionColumns.prototype.Get_ColumnSpace = function(ColIndex)
{
	if (true === this.EqualWidth)
	{
		return this.Space;
	}
	else
	{
		if (this.Cols.length <= 0)
			return this.Space;

		ColIndex = Math.max(0, Math.min(this.Cols.length - 1, ColIndex));
		if (ColIndex < 0)
			return this.Space;

		return this.Cols[ColIndex].Space;
	}
};

function CSectionLayoutColumnInfo(X, XLimit)
{
    this.X      = X;
    this.XLimit = XLimit;
    
    this.Pos    = 0;
    this.EndPos = 0;
}

function CSectionLayoutInfo(X, Y, XLimit, YLimit)
{
    this.X       = X;
    this.Y       = Y;
    this.XLimit  = XLimit;
    this.YLimit  = YLimit;
    this.Columns = [];
}

function CFootnotePr()
{
	this.NumRestart = undefined;
	this.NumFormat  = undefined;
	this.NumStart   = undefined;
	this.Pos        = undefined;
}
CFootnotePr.prototype.InitDefault = function()
{
	this.NumFormat  = Asc.c_oAscNumberingFormat.Decimal;
	this.NumRestart = section_footnote_RestartContinuous;
	this.NumStart   = 1;
	this.Pos        = section_footnote_PosPageBottom;
};
CFootnotePr.prototype.WriteToBinary = function(Writer)
{
	var StartPos = Writer.GetCurPosition();
	Writer.Skip(4);
	var Flags = 0;

	if (undefined !== this.NumFormat)
	{
		Writer.WriteLong(this.NumFormat);
		Flags |= 1;
	}

	if (undefined !== this.NumRestart)
	{
		Writer.WriteLong(this.NumRestart);
		Flags |= 2;
	}

	if (undefined !== this.NumStart)
	{
		Writer.WriteLong(this.NumStart);
		Flags |= 4;
	}

	if (undefined !== this.Pos)
	{
		Writer.WriteLong(this.Pos);
		Flags |= 8;
	}

	var EndPos = Writer.GetCurPosition();
	Writer.Seek(StartPos);
	Writer.WriteLong(Flags);
	Writer.Seek(EndPos);
};
CFootnotePr.prototype.ReadFromBinary = function(Reader)
{
	var Flags = Reader.GetLong();

	if (Flags & 1)
		this.NumFormat = Reader.GetLong();
	else
		this.NumFormat = undefined;

	if (Flags & 2)
		this.NumRestart = Reader.GetLong();
	else
		this.NumRestart = undefined;

	if (Flags & 4)
		this.NumStart = Reader.GetLong();
	else
		this.NumStart = undefined;

	if (Flags & 8)
		this.Pos = Reader.GetLong();
	else
		this.Pos = undefined;
};


//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CSectionPr = CSectionPr;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 10.11.2016
 * Time: 14:24
 */


AscDFH.changesFactory[AscDFH.historyitem_Section_PageSize_Orient]     = CChangesSectionPageOrient;
AscDFH.changesFactory[AscDFH.historyitem_Section_PageSize_Size]       = CChangesSectionPageSize;
AscDFH.changesFactory[AscDFH.historyitem_Section_PageMargins]         = CChangesSectionPageMargins;
AscDFH.changesFactory[AscDFH.historyitem_Section_Type]                = CChangesSectionType;
AscDFH.changesFactory[AscDFH.historyitem_Section_Borders_Left]        = CChangesSectionBordersLeft;
AscDFH.changesFactory[AscDFH.historyitem_Section_Borders_Top]         = CChangesSectionBordersTop;
AscDFH.changesFactory[AscDFH.historyitem_Section_Borders_Right]       = CChangesSectionBordersRight;
AscDFH.changesFactory[AscDFH.historyitem_Section_Borders_Bottom]      = CChangesSectionBordersBottom;
AscDFH.changesFactory[AscDFH.historyitem_Section_Borders_Display]     = CChangesSectionBordersDisplay;
AscDFH.changesFactory[AscDFH.historyitem_Section_Borders_OffsetFrom]  = CChangesSectionBordersOffsetFrom;
AscDFH.changesFactory[AscDFH.historyitem_Section_Borders_ZOrder]      = CChangesSectionBordersZOrder;
AscDFH.changesFactory[AscDFH.historyitem_Section_Header_First]        = CChangesSectionHeaderFirst;
AscDFH.changesFactory[AscDFH.historyitem_Section_Header_Even]         = CChangesSectionHeaderEven;
AscDFH.changesFactory[AscDFH.historyitem_Section_Header_Default]      = CChangesSectionHeaderDefault;
AscDFH.changesFactory[AscDFH.historyitem_Section_Footer_First]        = CChangesSectionFooterFirst;
AscDFH.changesFactory[AscDFH.historyitem_Section_Footer_Even]         = CChangesSectionFooterEven;
AscDFH.changesFactory[AscDFH.historyitem_Section_Footer_Default]      = CChangesSectionFooterDefault;
AscDFH.changesFactory[AscDFH.historyitem_Section_TitlePage]           = CChangesSectionTitlePage;
AscDFH.changesFactory[AscDFH.historyitem_Section_PageMargins_Header]  = CChangesSectionPageMarginsHeader;
AscDFH.changesFactory[AscDFH.historyitem_Section_PageMargins_Footer]  = CChangesSectionPageMarginsFooter;
AscDFH.changesFactory[AscDFH.historyitem_Section_PageNumType_Start]   = CChangesSectionPageNumTypeStart;
AscDFH.changesFactory[AscDFH.historyitem_Section_Columns_EqualWidth]  = CChangesSectionColumnsEqualWidth;
AscDFH.changesFactory[AscDFH.historyitem_Section_Columns_Space]       = CChangesSectionColumnsSpace;
AscDFH.changesFactory[AscDFH.historyitem_Section_Columns_Num]         = CChangesSectionColumnsNum;
AscDFH.changesFactory[AscDFH.historyitem_Section_Columns_Sep]         = CChangesSectionColumnsSep;
AscDFH.changesFactory[AscDFH.historyitem_Section_Columns_Col]         = CChangesSectionColumnsCol;
AscDFH.changesFactory[AscDFH.historyitem_Section_Columns_SetCols]     = CChangesSectionColumnsSetCols;
AscDFH.changesFactory[AscDFH.historyitem_Section_Footnote_Pos]        = CChangesSectionFootnotePos;
AscDFH.changesFactory[AscDFH.historyitem_Section_Footnote_NumStart]   = CChangesSectionFootnoteNumStart;
AscDFH.changesFactory[AscDFH.historyitem_Section_Footnote_NumRestart] = CChangesSectionFootnoteNumRestart;
AscDFH.changesFactory[AscDFH.historyitem_Section_Footnote_NumFormat]  = CChangesSectionFootnoteNumFormat;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_Section_PageSize_Orient]     = [AscDFH.historyitem_Section_PageSize_Orient];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_PageSize_Size]       = [AscDFH.historyitem_Section_PageSize_Size];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_PageMargins]         = [AscDFH.historyitem_Section_PageMargins];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Type]                = [AscDFH.historyitem_Section_Type];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Borders_Left]        = [AscDFH.historyitem_Section_Borders_Left];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Borders_Top]         = [AscDFH.historyitem_Section_Borders_Top];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Borders_Right]       = [AscDFH.historyitem_Section_Borders_Right];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Borders_Bottom]      = [AscDFH.historyitem_Section_Borders_Bottom];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Borders_Display]     = [AscDFH.historyitem_Section_Borders_Display];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Borders_OffsetFrom]  = [AscDFH.historyitem_Section_Borders_OffsetFrom];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Borders_ZOrder]      = [AscDFH.historyitem_Section_Borders_ZOrder];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Header_First]        = [AscDFH.historyitem_Section_Header_First];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Header_Even]         = [AscDFH.historyitem_Section_Header_Even];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Header_Default]      = [AscDFH.historyitem_Section_Header_Default];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Footer_First]        = [AscDFH.historyitem_Section_Footer_First];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Footer_Even]         = [AscDFH.historyitem_Section_Footer_Even];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Footer_Default]      = [AscDFH.historyitem_Section_Footer_Default];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_TitlePage]           = [AscDFH.historyitem_Section_TitlePage];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_PageMargins_Header]  = [AscDFH.historyitem_Section_PageMargins_Header];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_PageMargins_Footer]  = [AscDFH.historyitem_Section_PageMargins_Footer];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_PageNumType_Start]   = [AscDFH.historyitem_Section_PageNumType_Start];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Columns_EqualWidth]  = [AscDFH.historyitem_Section_Columns_EqualWidth];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Columns_Space]       = [AscDFH.historyitem_Section_Columns_Space];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Columns_Num]         = [AscDFH.historyitem_Section_Columns_Num];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Columns_Sep]         = [AscDFH.historyitem_Section_Columns_Sep];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Columns_Col]         = [AscDFH.historyitem_Section_Columns_Col, AscDFH.historyitem_Section_Columns_SetCols];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Columns_SetCols]     = [AscDFH.historyitem_Section_Columns_Col, AscDFH.historyitem_Section_Columns_SetCols];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Footnote_Pos]        = [AscDFH.historyitem_Section_Footnote_Pos];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Footnote_NumStart]   = [AscDFH.historyitem_Section_Footnote_NumStart];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Footnote_NumRestart] = [AscDFH.historyitem_Section_Footnote_NumRestart];
AscDFH.changesRelationMap[AscDFH.historyitem_Section_Footnote_NumFormat]  = [AscDFH.historyitem_Section_Footnote_NumFormat];
//----------------------------------------------------------------------------------------------------------------------



/**
 * Базовый класс для изменения колонтитулов
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesSectionBaseHeaderFooter(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesSectionBaseHeaderFooter.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesSectionBaseHeaderFooter.prototype.constructor = CChangesSectionBaseHeaderFooter;
CChangesSectionBaseHeaderFooter.prototype.WriteToBinary = function(Writer)
{
	// Long : Flags
	// 1bit : is New null?
	// 2bit : is Old null?
	// 1bit == 0: String : New id
	// 2bit == 0: String : Old id

	var nFlags = 0;
	if (null === this.New)
		nFlags |= 1;
	if (null === this.Old)
		nFlags |= 2;

	Writer.WriteLong(nFlags);
	if (null !== this.New)
		Writer.WriteString2(this.New.Get_Id());
	if (null !== this.Old)
		Writer.WriteString2(this.Old.Get_Id());
};
CChangesSectionBaseHeaderFooter.prototype.ReadFromBinary = function(Reader)
{
	// Long : Flags
	// 1bit : is New null?
	// 2bit : is Old null?
	// 1bit == 0: String : New id
	// 2bit == 0: String : Old id

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.New = null;
	else
		this.New = AscCommon.g_oTableId.Get_ById(Reader.GetString2());

	if (nFlags & 2)
		this.Old = null;
	else
		this.Old = AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};


/**
 * @constructor
 * @extends {AscDFH.CChangesBaseByteValue}
 */
function CChangesSectionPageOrient(Class, Old, New)
{
	AscDFH.CChangesBaseByteValue.call(this, Class, Old, New);
}
CChangesSectionPageOrient.prototype = Object.create(AscDFH.CChangesBaseByteValue.prototype);
CChangesSectionPageOrient.prototype.constructor = CChangesSectionPageOrient;
CChangesSectionPageOrient.prototype.Type = AscDFH.historyitem_Section_PageSize_Orient;
CChangesSectionPageOrient.prototype.private_SetValue = function(Value)
{
	this.Class.PageSize.Orient = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesSectionPageSize(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesSectionPageSize.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesSectionPageSize.prototype.constructor = CChangesSectionPageSize;
CChangesSectionPageSize.prototype.Type = AscDFH.historyitem_Section_PageSize_Size;
CChangesSectionPageSize.prototype.private_SetValue = function(Value)
{
	this.Class.PageSize.W = Value.W;
	this.Class.PageSize.H = Value.H;
};
CChangesSectionPageSize.prototype.WriteToBinary = function(Writer)
{
	// Double : New.W
	// Double : New.H
	// Double : Old.W
	// Double : Old.H

	Writer.WriteDouble(this.New.W);
	Writer.WriteDouble(this.New.H);
	Writer.WriteDouble(this.Old.W);
	Writer.WriteDouble(this.Old.H);
};
CChangesSectionPageSize.prototype.ReadFromBinary = function(Reader)
{
	// Double : New.W
	// Double : New.H
	// Double : Old.W
	// Double : Old.H

	this.New = {
		W : Reader.GetDouble(),
		H : Reader.GetDouble()
	};

	this.Old = {
		W : Reader.GetDouble(),
		H : Reader.GetDouble()
	};
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesSectionPageMargins(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesSectionPageMargins.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesSectionPageMargins.prototype.constructor = CChangesSectionPageMargins;
CChangesSectionPageMargins.prototype.Type = AscDFH.historyitem_Section_PageMargins;
CChangesSectionPageMargins.prototype.private_SetValue = function(Value)
{
	this.Class.PageMargins.Left   = Value.L;
	this.Class.PageMargins.Top    = Value.T;
	this.Class.PageMargins.Right  = Value.R;
	this.Class.PageMargins.Bottom = Value.B;
};
CChangesSectionPageMargins.prototype.WriteToBinary = function(Writer)
{
	// Double : New.L
	// Double : New.T
	// Double : New.R
	// Double : New.B
	// Double : Old.L
	// Double : Old.T
	// Double : Old.R
	// Double : Old.B

	Writer.WriteDouble(this.New.L);
	Writer.WriteDouble(this.New.T);
	Writer.WriteDouble(this.New.R);
	Writer.WriteDouble(this.New.B);

	Writer.WriteDouble(this.Old.L);
	Writer.WriteDouble(this.Old.T);
	Writer.WriteDouble(this.Old.R);
	Writer.WriteDouble(this.Old.B);
};
CChangesSectionPageMargins.prototype.ReadFromBinary = function(Reader)
{
	// Double : New.L
	// Double : New.T
	// Double : New.R
	// Double : New.B
	// Double : Old.L
	// Double : Old.T
	// Double : Old.R
	// Double : Old.B

	this.New = {
		L : Reader.GetDouble(),
		T : Reader.GetDouble(),
		R : Reader.GetDouble(),
		B : Reader.GetDouble()
	};

	this.Old = {
		L : Reader.GetDouble(),
		T : Reader.GetDouble(),
		R : Reader.GetDouble(),
		B : Reader.GetDouble()
	};
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseByteValue}
 */
function CChangesSectionType(Class, Old, New)
{
	AscDFH.CChangesBaseByteValue.call(this, Class, Old, New);
}
CChangesSectionType.prototype = Object.create(AscDFH.CChangesBaseByteValue.prototype);
CChangesSectionType.prototype.constructor = CChangesSectionType;
CChangesSectionType.prototype.Type = AscDFH.historyitem_Section_Type;
CChangesSectionType.prototype.private_SetValue = function(Value)
{
	this.Class.Type = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectValue}
 */
function CChangesSectionBordersLeft(Class, Old, New)
{
	AscDFH.CChangesBaseObjectValue.call(this, Class, Old, New);
}
CChangesSectionBordersLeft.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesSectionBordersLeft.prototype.constructor = CChangesSectionBordersLeft;
CChangesSectionBordersLeft.prototype.Type = AscDFH.historyitem_Section_Borders_Left;
CChangesSectionBordersLeft.prototype.private_CreateObject = function()
{
	return new CDocumentBorder();
};
CChangesSectionBordersLeft.prototype.private_SetValue = function(Value)
{
	this.Class.Borders.Left = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectValue}
 */
function CChangesSectionBordersTop(Class, Old, New)
{
	AscDFH.CChangesBaseObjectValue.call(this, Class, Old, New);
}
CChangesSectionBordersTop.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesSectionBordersTop.prototype.constructor = CChangesSectionBordersTop;
CChangesSectionBordersTop.prototype.Type = AscDFH.historyitem_Section_Borders_Top;
CChangesSectionBordersTop.prototype.private_CreateObject = function()
{
	return new CDocumentBorder();
};
CChangesSectionBordersTop.prototype.private_SetValue = function(Value)
{
	this.Class.Borders.Top = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectValue}
 */
function CChangesSectionBordersRight(Class, Old, New)
{
	AscDFH.CChangesBaseObjectValue.call(this, Class, Old, New);
}
CChangesSectionBordersRight.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesSectionBordersRight.prototype.constructor = CChangesSectionBordersRight;
CChangesSectionBordersRight.prototype.Type = AscDFH.historyitem_Section_Borders_Right;
CChangesSectionBordersRight.prototype.private_CreateObject = function()
{
	return new CDocumentBorder();
};
CChangesSectionBordersRight.prototype.private_SetValue = function(Value)
{
	this.Class.Borders.Right = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectValue}
 */
function CChangesSectionBordersBottom(Class, Old, New)
{
	AscDFH.CChangesBaseObjectValue.call(this, Class, Old, New);
}
CChangesSectionBordersBottom.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesSectionBordersBottom.prototype.constructor = CChangesSectionBordersBottom;
CChangesSectionBordersBottom.prototype.Type = AscDFH.historyitem_Section_Borders_Bottom;
CChangesSectionBordersBottom.prototype.private_CreateObject = function()
{
	return new CDocumentBorder();
};
CChangesSectionBordersBottom.prototype.private_SetValue = function(Value)
{
	this.Class.Borders.Bottom = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseByteValue}
 */
function CChangesSectionBordersDisplay(Class, Old, New)
{
	AscDFH.CChangesBaseByteValue.call(this, Class, Old, New);
}
CChangesSectionBordersDisplay.prototype = Object.create(AscDFH.CChangesBaseByteValue.prototype);
CChangesSectionBordersDisplay.prototype.constructor = CChangesSectionBordersDisplay;
CChangesSectionBordersDisplay.prototype.Type = AscDFH.historyitem_Section_Borders_Display;
CChangesSectionBordersDisplay.prototype.private_SetValue = function(Value)
{
	this.Class.Borders.Display = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseByteValue}
 */
function CChangesSectionBordersOffsetFrom(Class, Old, New)
{
	AscDFH.CChangesBaseByteValue.call(this, Class, Old, New);
}
CChangesSectionBordersOffsetFrom.prototype = Object.create(AscDFH.CChangesBaseByteValue.prototype);
CChangesSectionBordersOffsetFrom.prototype.constructor = CChangesSectionBordersOffsetFrom;
CChangesSectionBordersOffsetFrom.prototype.Type = AscDFH.historyitem_Section_Borders_OffsetFrom;
CChangesSectionBordersOffsetFrom.prototype.private_SetValue = function(Value)
{
	this.Class.Borders.OffsetFrom = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseByteValue}
 */
function CChangesSectionBordersZOrder(Class, Old, New)
{
	AscDFH.CChangesBaseByteValue.call(this, Class, Old, New);
}
CChangesSectionBordersZOrder.prototype = Object.create(AscDFH.CChangesBaseByteValue.prototype);
CChangesSectionBordersZOrder.prototype.constructor = CChangesSectionBordersZOrder;
CChangesSectionBordersZOrder.prototype.Type = AscDFH.historyitem_Section_Borders_ZOrder;
CChangesSectionBordersZOrder.prototype.private_SetValue = function(Value)
{
	this.Class.Borders.ZOrder = Value;
};
/**
 * @constructor
 * @extends {CChangesSectionBaseHeaderFooter}
 */
function CChangesSectionHeaderFirst(Class, Old, New)
{
	CChangesSectionBaseHeaderFooter.call(this, Class, Old, New);
}
CChangesSectionHeaderFirst.prototype = Object.create(CChangesSectionBaseHeaderFooter.prototype);
CChangesSectionHeaderFirst.prototype.constructor = CChangesSectionHeaderFirst;
CChangesSectionHeaderFirst.prototype.Type = AscDFH.historyitem_Section_Header_First;
CChangesSectionHeaderFirst.prototype.private_SetValue = function(Value)
{
	this.Class.HeaderFirst = Value;
};
/**
 * @constructor
 * @extends {CChangesSectionBaseHeaderFooter}
 */
function CChangesSectionHeaderEven(Class, Old, New)
{
	CChangesSectionBaseHeaderFooter.call(this, Class, Old, New);
}
CChangesSectionHeaderEven.prototype = Object.create(CChangesSectionBaseHeaderFooter.prototype);
CChangesSectionHeaderEven.prototype.constructor = CChangesSectionHeaderEven;
CChangesSectionHeaderEven.prototype.Type = AscDFH.historyitem_Section_Header_Even;
CChangesSectionHeaderEven.prototype.private_SetValue = function(Value)
{
	this.Class.HeaderEven = Value;
};
/**
 * @constructor
 * @extends {CChangesSectionBaseHeaderFooter}
 */
function CChangesSectionHeaderDefault(Class, Old, New)
{
	CChangesSectionBaseHeaderFooter.call(this, Class, Old, New);
}
CChangesSectionHeaderDefault.prototype = Object.create(CChangesSectionBaseHeaderFooter.prototype);
CChangesSectionHeaderDefault.prototype.constructor = CChangesSectionHeaderDefault;
CChangesSectionHeaderDefault.prototype.Type = AscDFH.historyitem_Section_Header_Default;
CChangesSectionHeaderDefault.prototype.private_SetValue = function(Value)
{
	this.Class.HeaderDefault = Value;
};
/**
 * @constructor
 * @extends {CChangesSectionBaseHeaderFooter}
 */
function CChangesSectionFooterFirst(Class, Old, New)
{
	CChangesSectionBaseHeaderFooter.call(this, Class, Old, New);
}
CChangesSectionFooterFirst.prototype = Object.create(CChangesSectionBaseHeaderFooter.prototype);
CChangesSectionFooterFirst.prototype.constructor = CChangesSectionFooterFirst;
CChangesSectionFooterFirst.prototype.Type = AscDFH.historyitem_Section_Footer_First;
CChangesSectionFooterFirst.prototype.private_SetValue = function(Value)
{
	this.Class.FooterFirst = Value;
};
/**
 * @constructor
 * @extends {CChangesSectionBaseHeaderFooter}
 */
function CChangesSectionFooterEven(Class, Old, New)
{
	CChangesSectionBaseHeaderFooter.call(this, Class, Old, New);
}
CChangesSectionFooterEven.prototype = Object.create(CChangesSectionBaseHeaderFooter.prototype);
CChangesSectionFooterEven.prototype.constructor = CChangesSectionFooterEven;
CChangesSectionFooterEven.prototype.Type = AscDFH.historyitem_Section_Footer_Even;
CChangesSectionFooterEven.prototype.private_SetValue = function(Value)
{
	this.Class.FooterEven = Value;
};
/**
 * @constructor
 * @extends {CChangesSectionBaseHeaderFooter}
 */
function CChangesSectionFooterDefault(Class, Old, New)
{
	CChangesSectionBaseHeaderFooter.call(this, Class, Old, New);
}
CChangesSectionFooterDefault.prototype = Object.create(CChangesSectionBaseHeaderFooter.prototype);
CChangesSectionFooterDefault.prototype.constructor = CChangesSectionFooterDefault;
CChangesSectionFooterDefault.prototype.Type = AscDFH.historyitem_Section_Footer_Default;
CChangesSectionFooterDefault.prototype.private_SetValue = function(Value)
{
	this.Class.FooterDefault = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolValue}
 */
function CChangesSectionTitlePage(Class, Old, New)
{
	AscDFH.CChangesBaseBoolValue.call(this, Class, Old, New);
}
CChangesSectionTitlePage.prototype = Object.create(AscDFH.CChangesBaseBoolValue.prototype);
CChangesSectionTitlePage.prototype.constructor = CChangesSectionTitlePage;
CChangesSectionTitlePage.prototype.Type = AscDFH.historyitem_Section_TitlePage;
CChangesSectionTitlePage.prototype.private_SetValue = function(Value)
{
	this.Class.TitlePage = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleValue}
 */
function CChangesSectionPageMarginsHeader(Class, Old, New)
{
	AscDFH.CChangesBaseDoubleValue.call(this, Class, Old, New);
}
CChangesSectionPageMarginsHeader.prototype = Object.create(AscDFH.CChangesBaseDoubleValue.prototype);
CChangesSectionPageMarginsHeader.prototype.constructor = CChangesSectionPageMarginsHeader;
CChangesSectionPageMarginsHeader.prototype.Type = AscDFH.historyitem_Section_PageMargins_Header;
CChangesSectionPageMarginsHeader.prototype.private_SetValue = function(Value)
{
	this.Class.PageMargins.Header = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleValue}
 */
function CChangesSectionPageMarginsFooter(Class, Old, New)
{
	AscDFH.CChangesBaseDoubleValue.call(this, Class, Old, New);
}
CChangesSectionPageMarginsFooter.prototype = Object.create(AscDFH.CChangesBaseDoubleValue.prototype);
CChangesSectionPageMarginsFooter.prototype.constructor = CChangesSectionPageMarginsFooter;
CChangesSectionPageMarginsFooter.prototype.Type = AscDFH.historyitem_Section_PageMargins_Footer;
CChangesSectionPageMarginsFooter.prototype.private_SetValue = function(Value)
{
	this.Class.PageMargins.Footer = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongValue}
 */
function CChangesSectionPageNumTypeStart(Class, Old, New)
{
	AscDFH.CChangesBaseLongValue.call(this, Class, Old, New);
}
CChangesSectionPageNumTypeStart.prototype = Object.create(AscDFH.CChangesBaseLongValue.prototype);
CChangesSectionPageNumTypeStart.prototype.constructor = CChangesSectionPageNumTypeStart;
CChangesSectionPageNumTypeStart.prototype.Type = AscDFH.historyitem_Section_PageNumType_Start;
CChangesSectionPageNumTypeStart.prototype.private_SetValue = function(Value)
{
	this.Class.PageNumType.Start = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolValue}
 */
function CChangesSectionColumnsEqualWidth(Class, Old, New)
{
	AscDFH.CChangesBaseBoolValue.call(this, Class, Old, New);
}
CChangesSectionColumnsEqualWidth.prototype = Object.create(AscDFH.CChangesBaseBoolValue.prototype);
CChangesSectionColumnsEqualWidth.prototype.constructor = CChangesSectionColumnsEqualWidth;
CChangesSectionColumnsEqualWidth.prototype.Type = AscDFH.historyitem_Section_Columns_EqualWidth;
CChangesSectionColumnsEqualWidth.prototype.private_SetValue = function(Value)
{
	this.Class.Columns.EqualWidth = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleValue}
 */
function CChangesSectionColumnsSpace(Class, Old, New)
{
	AscDFH.CChangesBaseDoubleValue.call(this, Class, Old, New);
}
CChangesSectionColumnsSpace.prototype = Object.create(AscDFH.CChangesBaseDoubleValue.prototype);
CChangesSectionColumnsSpace.prototype.constructor = CChangesSectionColumnsSpace;
CChangesSectionColumnsSpace.prototype.Type = AscDFH.historyitem_Section_Columns_Space;
CChangesSectionColumnsSpace.prototype.private_SetValue = function(Value)
{
	this.Class.Columns.Space = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongValue}
 */
function CChangesSectionColumnsNum(Class, Old, New)
{
	AscDFH.CChangesBaseLongValue.call(this, Class, Old, New);
}
CChangesSectionColumnsNum.prototype = Object.create(AscDFH.CChangesBaseLongValue.prototype);
CChangesSectionColumnsNum.prototype.constructor = CChangesSectionColumnsNum;
CChangesSectionColumnsNum.prototype.Type = AscDFH.historyitem_Section_Columns_Num;
CChangesSectionColumnsNum.prototype.private_SetValue = function(Value)
{
	this.Class.Columns.Num = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolValue}
 */
function CChangesSectionColumnsSep(Class, Old, New)
{
	AscDFH.CChangesBaseBoolValue.call(this, Class, Old, New);
}
CChangesSectionColumnsSep.prototype = Object.create(AscDFH.CChangesBaseBoolValue.prototype);
CChangesSectionColumnsSep.prototype.constructor = CChangesSectionColumnsSep;
CChangesSectionColumnsSep.prototype.Type = AscDFH.historyitem_Section_Columns_Sep;
CChangesSectionColumnsSep.prototype.private_SetValue = function(Value)
{
	this.Class.Columns.Sep = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesSectionColumnsCol(Class, Old, New, Index)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);

	this.Index = Index;
}
CChangesSectionColumnsCol.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesSectionColumnsCol.prototype.constructor = CChangesSectionColumnsCol;
CChangesSectionColumnsCol.prototype.Type = AscDFH.historyitem_Section_Columns_Col;
CChangesSectionColumnsCol.prototype.private_SetValue = function(Value)
{
	this.Class.Columns.Cols[this.Index] = Value;
};
CChangesSectionColumnsCol.prototype.WriteToBinary = function(Writer)
{
	// Long : ColumnIndex
	// Long : flags
	// 1bit : is new undefined?
	// 2bit : is old undefined?
	// 1bit == 0 : CSectionColumn : New
	// 2bit == 0 : CSectionColumn : Old

	Writer.WriteLong(this.Index);

	var nFlags = 0;
	if (undefined === this.New)
		nFlags |= 1;

	if (undefined === this.Old)
		nFlags |= 2;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New)
		this.New.Write_ToBinary(Writer);

	if (undefined !== this.Old)
		this.Old.Write_ToBinary(Writer);
};
CChangesSectionColumnsCol.prototype.ReadFromBinary = function(Reader)
{
	// Long : ColumnIndex
	// Long : flags
	// 1bit : is new undefined?
	// 2bit : is old undefined?
	// 1bit == 0 : CSectionColumn : New
	// 2bit == 0 : CSectionColumn : Old

	this.Index = Reader.GetLong();

	var nFlags = Reader.GetLong();
	if (nFlags & 1)
	{
		this.New = undefined;
	}
	else
	{
		this.New = new CSectionColumn();
		this.New.Read_FromBinary(Reader);
	}

	if (nFlags & 2)
	{
		this.Old = undefined;
	}
	else
	{
		this.Old = new CSectionColumn();
		this.Old.Read_FromBinary(Reader);
	}
};
CChangesSectionColumnsCol.prototype.CreateReverseChange = function()
{
	return new CChangesSectionColumnsCol(this.Class, this.New, this.Old, this.Index);
};
CChangesSectionColumnsCol.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type)
	{
		if (this.Index !== oChange.Index)
			return true;
		else
			return false;
	}
	else if (AscDFH.historyitem_Section_Columns_SetCols === oChange.Type)
	{
		return false
	}

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesSectionColumnsSetCols(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesSectionColumnsSetCols.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesSectionColumnsSetCols.prototype.constructor = CChangesSectionColumnsSetCols;
CChangesSectionColumnsSetCols.prototype.Type = AscDFH.historyitem_Section_Columns_SetCols;
CChangesSectionColumnsSetCols.prototype.private_SetValue = function(Value)
{
	this.Class.Columns.Cols = Value;
};
CChangesSectionColumnsSetCols.prototype.WriteToBinary = function(Writer)
{
	// Long : Count of new column
	// Array of CSectionColumn: new columns
	// Long : Count of old column
	// Array of CSectionColumn: old columns


	var nCount = this.New.length;
	Writer.WriteLong(nCount);
	for (var nIndex = 0; nIndex < nCount; ++nIndex)
	{
		this.New[nIndex].Write_ToBinary(Writer);
	}

	nCount = this.Old.length;
	Writer.WriteLong(nCount);
	for (var nIndex = 0; nIndex < nCount; ++nIndex)
	{
		this.Old[nIndex].Write_ToBinary(Writer);
	}
};
CChangesSectionColumnsSetCols.prototype.ReadFromBinary = function(Reader)
{
	// Long : Count of new column
	// Array of CSectionColumn: new columns
	// Long : Count of old column
	// Array of CSectionColumn: old columns

	var nCount = Reader.GetLong();
	this.New = [];
	for (var nIndex = 0; nIndex < nCount; ++nIndex)
	{
		this.New[nIndex] = new CSectionColumn();
		this.New[nIndex].Read_FromBinary(Reader);
	}

	nCount = Reader.GetLong();
	this.Old = [];
	for (var nIndex = 0; nIndex < nCount; ++nIndex)
	{
		this.Old[nIndex] = new CSectionColumn();
		this.Old[nIndex].Read_FromBinary(Reader);
	}
};
CChangesSectionColumnsSetCols.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type)
		return false;

	if (AscDFH.historyitem_Section_Columns_Col === oChange.Type)
	{
		if (!this.New)
			this.New = [];

		this.New[oChange.Index] = oChange.New;
	}

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesSectionFootnotePos(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesSectionFootnotePos.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesSectionFootnotePos.prototype.constructor = CChangesSectionFootnotePos;
CChangesSectionFootnotePos.prototype.Type = AscDFH.historyitem_Section_Footnote_Pos;
CChangesSectionFootnotePos.prototype.private_SetValue = function(Value)
{
	this.Class.FootnotePr.Pos = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesSectionFootnoteNumStart(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesSectionFootnoteNumStart.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesSectionFootnoteNumStart.prototype.constructor = CChangesSectionFootnoteNumStart;
CChangesSectionFootnoteNumStart.prototype.Type = AscDFH.historyitem_Section_Footnote_NumStart;
CChangesSectionFootnoteNumStart.prototype.private_SetValue = function(Value)
{
	this.Class.FootnotePr.NumStart = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesSectionFootnoteNumRestart(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesSectionFootnoteNumRestart.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesSectionFootnoteNumRestart.prototype.constructor = CChangesSectionFootnoteNumRestart;
CChangesSectionFootnoteNumRestart.prototype.Type = AscDFH.historyitem_Section_Footnote_NumRestart;
CChangesSectionFootnoteNumRestart.prototype.private_SetValue = function(Value)
{
	this.Class.FootnotePr.NumRestart = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesSectionFootnoteNumFormat(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesSectionFootnoteNumFormat.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesSectionFootnoteNumFormat.prototype.constructor = CChangesSectionFootnoteNumFormat;
CChangesSectionFootnoteNumFormat.prototype.Type = AscDFH.historyitem_Section_Footnote_NumFormat;
CChangesSectionFootnoteNumFormat.prototype.private_SetValue = function(Value)
{
	this.Class.FootnotePr.NumFormat = Value;
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 08.05.2018
 * Time: 15:41
 */

var numbering_lvltext_Text = 1;
var numbering_lvltext_Num  = 2;

/** enum {number} */
var c_oAscMultiLevelNumbering = {
	Numbered    : 0,
	Bullet      : 1,

	MultiLevel1 : 101,
	MultiLevel2 : 102,
	MultiLevel3 : 103
};

/** enum {number} */
var c_oAscNumberingLevel = {
	None       : 0,
	Bullet     : 0x1000,
	Numbered   : 0x2000,

	DecimalBracket_Right    : 0x2001,
	DecimalBracket_Left     : 0x2002,
	DecimalDot_Right        : 0x2003,
	DecimalDot_Left         : 0x2004,
	UpperRomanDot_Right     : 0x2005,
	UpperLetterDot_Left     : 0x2006,
	LowerLetterBracket_Left : 0x2007,
	LowerLetterDot_Left     : 0x2008,
	LowerRomanDot_Right     : 0x2009,
	UpperRomanBracket_Left  : 0x200A,
	LowerRomanBracket_Left  : 0x200B,
	UpperLetterBracket_Left : 0x200C
};

// Преобразовываем число в буквенную строку :
//  1 -> a
//  2 -> b
//   ...
// 26 -> z
// 27 -> aa
//   ...
// 52 -> zz
// 53 -> aaa
//   ...
function Numbering_Number_To_Alpha(Num, bLowerCase)
{
	var _Num = Num - 1;
	var Count = (_Num - _Num % 26) / 26;
	var Ost   = _Num % 26;

	var T = "";

	var Letter;
	if ( true === bLowerCase )
		Letter = String.fromCharCode( Ost + 97 );
	else
		Letter = String.fromCharCode( Ost + 65 );

	for ( var Index2 = 0; Index2 < Count + 1; Index2++ )
		T += Letter;

	return T;
}

// Преобразовываем число в обычную строку :
function Numbering_Number_To_String(Num)
{
	return "" + Num;
}

// Преобразовываем число в римскую систему исчисления :
//    1 -> i
//    4 -> iv
//    5 -> v
//    9 -> ix
//   10 -> x
//   40 -> xl
//   50 -> l
//   90 -> xc
//  100 -> c
//  400 -> cd
//  500 -> d
//  900 -> cm
// 1000 -> m
function Numbering_Number_To_Roman(Num, bLowerCase)
{
	// Переводим число Num в римскую систему исчисления
	var Rims;

	if ( true === bLowerCase )
		Rims = [  'm', 'cm', 'd', 'cd', 'c', 'xc', 'l', 'xl', 'x', 'ix', 'v', 'iv', 'i', ' '];
	else
		Rims = [  'M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I', ' '];

	var Vals = [ 1000,  900, 500,  400, 100,   90,  50,   40,  10,    9,   5,    4,   1,   0];

	var T = "";
	var Index2 = 0;
	while ( Num > 0 )
	{
		while ( Vals[Index2] <= Num )
		{
			T   += Rims[Index2];
			Num -= Vals[Index2];
		}

		Index2++;

		if ( Index2 >= Rims.length )
			break;
	}

	return T;
}
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 08.05.2018
 * Time: 17:06
 */

function CNumberingLvl()
{
	this.Jc      = AscCommon.align_Left;
	this.Format  = Asc.c_oAscNumberingFormat.Bullet;
	this.PStyle  = undefined;
	this.Start   = 1;
	this.Restart = -1; // -1 - делаем нумерацию сначала всегда, 0 - никогда не начинаем нумерацию заново
	this.Suff    = Asc.c_oAscNumberingSuff.Tab;
	this.TextPr  = new CTextPr();
	this.ParaPr  = new CParaPr();
	this.LvlText = [];
	this.Legacy  = undefined;
}
/**
 * Доступ к типу прилегания данного уровня
 * @returns {AscCommon.align_Left | AscCommon.align_Right | AscCommon.align_Center}
 */
CNumberingLvl.prototype.GetJc = function()
{
	return this.Jc;
};
/**
 * Доступ к типу данного уровня
 * @returns {Asc.c_oAscNumberingFormat}
 */
CNumberingLvl.prototype.GetFormat = function()
{
	return this.Format;
};
/**
 * Доступ к связанному стилю
 * @returns {?string}
 */
CNumberingLvl.prototype.GetPStyle = function()
{
	return this.PStyle;
};
/**
 * Доступ к начальному значению для данного уровня
 * @returns {number}
 */
CNumberingLvl.prototype.GetStart = function()
{
	return this.Start;
};
/**
 * Доступ к параметру, означающему нужно ли перестартовывать нумерации при смене уровня или оставлять её сквозной
 * @returns {number}
 */
CNumberingLvl.prototype.GetRestart = function()
{
	return this.Restart;
};
/**
 * Доступ к типу разделителя между нумерацией и содержимым параграфа
 * @returns {Asc.c_oAscNumberingSuff}
 */
CNumberingLvl.prototype.GetSuff = function()
{
	return this.Suff;
};
/**
 * Доуступ к текстовым настройкам уровня
 * @returns {CTextPr}
 */
CNumberingLvl.prototype.GetTextPr = function()
{
	return this.TextPr;
};
/**
 * Доступ к настройкам параграфа данного уровня
 * @returns {CParaPr}
 */
CNumberingLvl.prototype.GetParaPr = function()
{
	return this.ParaPr;
};
/**
 * Доступ к содержимому нумерации
 * @returns {[CNumberingLvlTextString | CNumberingLvlTextNum]}
 */
CNumberingLvl.prototype.GetLvlText = function()
{
	return this.LvlText;
};
/**
 * Проверяем совместимость с устаревшей нумерацией
 * @returns {boolean}
 */
CNumberingLvl.prototype.IsLegacy = function()
{
	return !!(this.Legacy instanceof CNumberingLvlLegacy && this.Legacy.Legacy);
};
/**
 * Получаем расстояние между символом нумерации и текстом
 * @return {twips}
 */
CNumberingLvl.prototype.GetLegacySpace = function()
{
	if (this.Legacy)
		return this.Legacy.Space;

	return 0;
};
/**
 * Получаем расстояние выделенное под знак нумерации (вместе с расстоянием до текста)
 * @return {twips}
 */
CNumberingLvl.prototype.GetLegacyIndent = function()
{
	if (this.Legacy)
		return this.Legacy.Indent;

	return 0;
};
/**
 * Выставляем значения по умолчанию для заданного уровня
 * @param nLvl {number} 0..8
 * @param nType {c_oAscMultiLevelNumbering}
 */
CNumberingLvl.prototype.InitDefault = function(nLvl, nType)
{
	switch (nType)
	{
		case c_oAscMultiLevelNumbering.Numbered:
			this.private_InitDefaultNumbered(nLvl);
			break;
		case c_oAscMultiLevelNumbering.Bullet:
			this.private_InitDefaultBullet(nLvl);
			break;
		case c_oAscMultiLevelNumbering.MultiLevel1:
			this.private_InitDefaultMultilevel1(nLvl);
			break;
		case c_oAscMultiLevelNumbering.MultiLevel2:
			this.private_InitDefaultMultilevel2(nLvl);
			break;
		case c_oAscMultiLevelNumbering.MultiLevel3:
			this.private_InitDefaultMultiLevel3(nLvl);
			break;
		default:
			this.private_InitDefault(nLvl);
	}
};
CNumberingLvl.prototype.private_InitDefault = function(nLvl)
{
	this.Jc      = AscCommon.align_Left;
	this.Format  = Asc.c_oAscNumberingFormat.Bullet;
	this.PStyle  = undefined;
	this.Start   = 1;
	this.Restart = -1; // -1 - делаем нумерацию сначала всегда, 0 - никогда не начинаем нумерацию заново
	this.Suff    = Asc.c_oAscNumberingSuff.Tab;

	this.ParaPr               = new CParaPr();
	this.ParaPr.Ind.Left      = 36 * (nLvl + 1) * g_dKoef_pt_to_mm;
	this.ParaPr.Ind.FirstLine = -18 * g_dKoef_pt_to_mm;

	this.TextPr = new CTextPr();
	this.LvlText = [];

	if (0 == nLvl % 3)
	{
		this.TextPr.RFonts.Set_All("Symbol", -1);
		this.LvlText.push(new CNumberingLvlTextString(String.fromCharCode(0x00B7)));
	}
	else if (1 == nLvl % 3)
	{
		this.TextPr.RFonts.Set_All("Courier New", -1);
		this.LvlText.push(new CNumberingLvlTextString("o"));
	}
	else
	{
		this.TextPr.RFonts.Set_All("Wingdings", -1);
		this.LvlText.push(new CNumberingLvlTextString(String.fromCharCode(0x00A7)));
	}
};
/**
 * Выставляем значения по умолчанию для заданного уровня для нумерованного списка
 * @param nLvl {number} 0..8
 */
CNumberingLvl.prototype.private_InitDefaultNumbered = function(nLvl)
{
	this.Start   = 1;
	this.Restart = -1;
	this.Suff    = Asc.c_oAscNumberingSuff.Tab;

	var nLeft      = 36 * (nLvl + 1) * g_dKoef_pt_to_mm;
	var nFirstLine = -18 * g_dKoef_pt_to_mm;

	if (0 == nLvl % 3)
	{
		this.Jc     = AscCommon.align_Left;
		this.Format = Asc.c_oAscNumberingFormat.Decimal;
	}
	else if (1 == nLvl % 3)
	{
		this.Jc     = AscCommon.align_Left;
		this.Format = Asc.c_oAscNumberingFormat.LowerLetter;
	}
	else
	{
		this.Jc     = AscCommon.align_Right;
		this.Format = Asc.c_oAscNumberingFormat.LowerRoman;
		nFirstLine  = -9 * g_dKoef_pt_to_mm;
	}

	this.LvlText = [];
	this.LvlText.push(new CNumberingLvlTextNum(nLvl));
	this.LvlText.push(new CNumberingLvlTextString("."));

	this.ParaPr               = new CParaPr();
	this.ParaPr.Ind.Left      = nLeft;
	this.ParaPr.Ind.FirstLine = nFirstLine;

	this.TextPr = new CTextPr();
};
/**
 * Многоуровневый символьный список
 * @param nLvl {number} 0..8
 */
CNumberingLvl.prototype.private_InitDefaultBullet = function(nLvl)
{
	this.Start   = 1;
	this.Restart = -1;
	this.Suff    = Asc.c_oAscNumberingSuff.Tab;
	this.Jc      = AscCommon.align_Left;
	this.Format  = Asc.c_oAscNumberingFormat.Bullet;

	this.ParaPr               = new CParaPr();
	this.ParaPr.Ind.Left      = 36 * (nLvl + 1) * g_dKoef_pt_to_mm;
	this.ParaPr.Ind.FirstLine = -18 * g_dKoef_pt_to_mm;

	this.TextPr  = new CTextPr();
	this.LvlText = [];
	if (0 == nLvl % 3)
	{
		this.TextPr.RFonts.Set_All("Symbol", -1);
		this.LvlText.push(new CNumberingLvlTextString(String.fromCharCode(0x00B7)));
	}
	else if (1 == nLvl % 3)
	{
		this.TextPr.RFonts.Set_All("Courier New", -1);
		this.LvlText.push(new CNumberingLvlTextString("o"));
	}
	else
	{
		this.TextPr.RFonts.Set_All("Wingdings", -1);
		this.LvlText.push(new CNumberingLvlTextString(String.fromCharCode(0x00A7)));
	}
};
/**
 * Многоуровневый список 1) a) i) 1) a) i) 1) a) i)
 * @param nLvl {number} 0..8
 */
CNumberingLvl.prototype.private_InitDefaultMultilevel1 = function(nLvl)
{
	this.Start   = 1;
	this.Restart = -1;
	this.Suff    = Asc.c_oAscNumberingSuff.Tab;
	this.Jc      = AscCommon.align_Left;

	if (0 == nLvl % 3)
	{
		this.Format = Asc.c_oAscNumberingFormat.Decimal;
	}
	else if (1 == nLvl % 3)
	{
		this.Format = Asc.c_oAscNumberingFormat.LowerLetter;
	}
	else
	{
		this.Format = Asc.c_oAscNumberingFormat.LowerRoman;
	}

	this.LvlText = [];
	this.LvlText.push(new CNumberingLvlTextNum(nLvl));
	this.LvlText.push(new CNumberingLvlTextString(")"));

	var nLeft      = 18 * (nLvl + 1) * g_dKoef_pt_to_mm;
	var nFirstLine = -18 * g_dKoef_pt_to_mm;

	this.ParaPr               = new CParaPr();
	this.ParaPr.Ind.Left      = nLeft;
	this.ParaPr.Ind.FirstLine = nFirstLine;

	this.TextPr = new CTextPr();
};
/**
 * Многоуровневый список 1. 1.1. 1.1.1. и т.д.
 * @param nLvl {number} 0..8
 */
CNumberingLvl.prototype.private_InitDefaultMultilevel2 = function(nLvl)
{
	this.Jc     = AscCommon.align_Left;
	this.Format = Asc.c_oAscNumberingFormat.Decimal;
	this.Start   = 1;
	this.Restart = -1;
	this.Suff    = Asc.c_oAscNumberingSuff.Tab;

	var nLeft      = 0;
	var nFirstLine = 0;

	switch (nLvl)
	{
		case 0 :
			nLeft      = 18 * g_dKoef_pt_to_mm;
			nFirstLine = -18 * g_dKoef_pt_to_mm;
			break;
		case 1 :
			nLeft      = 39.6 * g_dKoef_pt_to_mm;
			nFirstLine = -21.6 * g_dKoef_pt_to_mm;
			break;
		case 2 :
			nLeft      = 61.2 * g_dKoef_pt_to_mm;
			nFirstLine = -25.2 * g_dKoef_pt_to_mm;
			break;
		case 3 :
			nLeft      = 86.4 * g_dKoef_pt_to_mm;
			nFirstLine = -32.4 * g_dKoef_pt_to_mm;
			break;
		case 4 :
			nLeft      = 111.6 * g_dKoef_pt_to_mm;
			nFirstLine = -39.6 * g_dKoef_pt_to_mm;
			break;
		case 5 :
			nLeft      = 136.8 * g_dKoef_pt_to_mm;
			nFirstLine = -46.8 * g_dKoef_pt_to_mm;
			break;
		case 6 :
			nLeft      = 162 * g_dKoef_pt_to_mm;
			nFirstLine = -54 * g_dKoef_pt_to_mm;
			break;
		case 7 :
			nLeft      = 187.2 * g_dKoef_pt_to_mm;
			nFirstLine = -61.2 * g_dKoef_pt_to_mm;
			break;
		case 8 :
			nLeft      = 216 * g_dKoef_pt_to_mm;
			nFirstLine = -72 * g_dKoef_pt_to_mm;
			break;
	}

	this.LvlText = [];
	for (var nIndex = 0; nIndex <= nLvl; ++nIndex)
	{
		this.LvlText.push(new CNumberingLvlTextNum(nIndex));
		this.LvlText.push(new CNumberingLvlTextString("."));
	}

	this.ParaPr               = new CParaPr();
	this.ParaPr.Ind.Left      = nLeft;
	this.ParaPr.Ind.FirstLine = nFirstLine;

	this.TextPr = new CTextPr();
};
/**
 * Многоуровневый символьный список
 * @param nLvl {number} 0..8
 */
CNumberingLvl.prototype.private_InitDefaultMultiLevel3 = function(nLvl)
{
	this.Start   = 1;
	this.Restart = -1;
	this.Suff    = Asc.c_oAscNumberingSuff.Tab;
	this.Format  = Asc.c_oAscNumberingFormat.Bullet;
	this.Jc      = AscCommon.align_Left;
	this.LvlText = [];

	switch (nLvl)
	{
		case 0:
			this.LvlText.push(new CNumberingLvlTextString(String.fromCharCode(0x0076)));
			break;
		case 1:
			this.LvlText.push(new CNumberingLvlTextString(String.fromCharCode(0x00D8)));
			break;
		case 2:
			this.LvlText.push(new CNumberingLvlTextString(String.fromCharCode(0x00A7)));
			break;
		case 3:
			this.LvlText.push(new CNumberingLvlTextString(String.fromCharCode(0x00B7)));
			break;
		case 4:
			this.LvlText.push(new CNumberingLvlTextString(String.fromCharCode(0x00A8)));
			break;
		case 5:
			this.LvlText.push(new CNumberingLvlTextString(String.fromCharCode(0x00D8)));
			break;
		case 6:
			this.LvlText.push(new CNumberingLvlTextString(String.fromCharCode(0x00A7)));
			break;
		case 7:
			this.LvlText.push(new CNumberingLvlTextString(String.fromCharCode(0x00B7)));
			break;
		case 8:
			this.LvlText.push(new CNumberingLvlTextString(String.fromCharCode(0x00A8)));
			break;
	}

	var nLeft      = 18 * (nLvl + 1) * g_dKoef_pt_to_mm;
	var nFirstLine = -18 * g_dKoef_pt_to_mm;

	this.ParaPr               = new CParaPr();
	this.ParaPr.Ind.Left      = nLeft;
	this.ParaPr.Ind.FirstLine = nFirstLine;

	this.TextPr = new CTextPr();
	if (3 === nLvl || 4 === nLvl || 7 === nLvl || 8 === nLvl)
		this.TextPr.RFonts.Set_All("Symbol", -1);
	else
		this.TextPr.RFonts.Set_All("Wingdings", -1);
};
/**
 * Создаем копию
 * @returns {CNumberingLvl}
 */
CNumberingLvl.prototype.Copy = function()
{
	var oLvl = new CNumberingLvl();

	oLvl.Jc      = this.Jc;
	oLvl.Format  = this.Format;
	oLvl.PStyle  = this.PStyle;
	oLvl.Start   = this.Start;
	oLvl.Restart = this.Restart;
	oLvl.Suff    = this.Suff;
	oLvl.LvlText = [];

	for (var nIndex = 0, nCount = this.LvlText.length; nIndex < nCount; ++nIndex)
	{
		oLvl.LvlText.push(this.LvlText[nIndex].Copy());
	}
	oLvl.TextPr = this.TextPr.Copy();
	oLvl.ParaPr = this.ParaPr.Copy();

	if (this.Legacy)
		oLvl.Legacy = this.Legacy.Copy();

	return oLvl;
};
/**
 * Выставляем значения по заданному пресету
 * @param nType {c_oAscNumberingLevel}
 * @param nLvl {number} 0..8
 * @param [sText=undefined] Используется для типа c_oAscNumberingLevel.Bullet
 * @param [oTextPr=undefined] {CTextPr} Используется для типа c_oAscNumberingLevel.Bullet
 */
CNumberingLvl.prototype.SetByType = function(nType, nLvl, sText, oTextPr)
{
	switch (nType)
	{
		case c_oAscNumberingLevel.None:
			this.Format  = Asc.c_oAscNumberingFormat.None;
			this.LvlText = [];
			this.TextPr  = new CTextPr();
			break;
		case c_oAscNumberingLevel.Bullet:
			this.Format  = Asc.c_oAscNumberingFormat.Bullet;
			this.TextPr  = oTextPr;
			this.LvlText = [];
			this.LvlText.push(new CNumberingLvlTextString(sText));
			break;
		case c_oAscNumberingLevel.DecimalBracket_Right:
			this.Jc      = AscCommon.align_Right;
			this.Format  = Asc.c_oAscNumberingFormat.Decimal;
			this.LvlText = [];
			this.LvlText.push(new CNumberingLvlTextNum(nLvl));
			this.LvlText.push(new CNumberingLvlTextString(")"));
			this.TextPr = new CTextPr();
			break;
		case c_oAscNumberingLevel.DecimalBracket_Left:
			this.Jc      = AscCommon.align_Left;
			this.Format  = Asc.c_oAscNumberingFormat.Decimal;
			this.LvlText = [];
			this.LvlText.push(new CNumberingLvlTextNum(nLvl));
			this.LvlText.push(new CNumberingLvlTextString(")"));
			this.TextPr = new CTextPr();
			break;
		case c_oAscNumberingLevel.DecimalDot_Right:
			this.Jc      = AscCommon.align_Right;
			this.Format  = Asc.c_oAscNumberingFormat.Decimal;
			this.LvlText = [];
			this.LvlText.push(new CNumberingLvlTextNum(nLvl));
			this.LvlText.push(new CNumberingLvlTextString("."));
			this.TextPr = new CTextPr();
			break;
		case c_oAscNumberingLevel.DecimalDot_Left:
			this.Jc      = AscCommon.align_Left;
			this.Format  = Asc.c_oAscNumberingFormat.Decimal;
			this.LvlText = [];
			this.LvlText.push(new CNumberingLvlTextNum(nLvl));
			this.LvlText.push(new CNumberingLvlTextString("."));
			this.TextPr = new CTextPr();
			break;
		case c_oAscNumberingLevel.UpperRomanDot_Right:
			this.Jc      = AscCommon.align_Right;
			this.Format  = Asc.c_oAscNumberingFormat.UpperRoman;
			this.LvlText = [];
			this.LvlText.push(new CNumberingLvlTextNum(nLvl));
			this.LvlText.push(new CNumberingLvlTextString("."));
			this.TextPr = new CTextPr();
			break;
		case c_oAscNumberingLevel.UpperLetterDot_Left:
			this.Jc      = AscCommon.align_Left;
			this.Format  = Asc.c_oAscNumberingFormat.UpperLetter;
			this.LvlText = [];
			this.LvlText.push(new CNumberingLvlTextNum(nLvl));
			this.LvlText.push(new CNumberingLvlTextString("."));
			this.TextPr = new CTextPr();
			break;
		case c_oAscNumberingLevel.LowerLetterBracket_Left:
			this.Jc      = AscCommon.align_Left;
			this.Format  = Asc.c_oAscNumberingFormat.LowerLetter;
			this.LvlText = [];
			this.LvlText.push(new CNumberingLvlTextNum(nLvl));
			this.LvlText.push(new CNumberingLvlTextString(")"));
			this.TextPr = new CTextPr();
			break;
		case c_oAscNumberingLevel.LowerLetterDot_Left:
			this.Jc      = AscCommon.align_Left;
			this.Format  = Asc.c_oAscNumberingFormat.LowerLetter;
			this.LvlText = [];
			this.LvlText.push(new CNumberingLvlTextNum(nLvl));
			this.LvlText.push(new CNumberingLvlTextString("."));
			this.TextPr = new CTextPr();
			break;
		case c_oAscNumberingLevel.LowerRomanDot_Right:
			this.Jc      = AscCommon.align_Right;
			this.Format  = Asc.c_oAscNumberingFormat.LowerRoman;
			this.LvlText = [];
			this.LvlText.push(new CNumberingLvlTextNum(nLvl));
			this.LvlText.push(new CNumberingLvlTextString("."));
			this.TextPr = new CTextPr();
			break;
		case c_oAscNumberingLevel.UpperRomanBracket_Left:
			this.Jc      = AscCommon.align_Left;
			this.Format  = Asc.c_oAscNumberingFormat.UpperRoman;
			this.LvlText = [];
			this.LvlText.push(new CNumberingLvlTextNum(nLvl));
			this.LvlText.push(new CNumberingLvlTextString(")"));
			this.TextPr = new CTextPr();
			break;
		case c_oAscNumberingLevel.LowerRomanBracket_Left:
			this.Jc      = AscCommon.align_Left;
			this.Format  = Asc.c_oAscNumberingFormat.LowerRoman;
			this.LvlText = [];
			this.LvlText.push(new CNumberingLvlTextNum(nLvl));
			this.LvlText.push(new CNumberingLvlTextString(")"));
			this.TextPr = new CTextPr();
			break;
		case c_oAscNumberingLevel.UpperLetterBracket_Left:
			this.Jc      = AscCommon.align_Left;
			this.Format  = Asc.c_oAscNumberingFormat.UpperLetter;
			this.LvlText = [];
			this.LvlText.push(new CNumberingLvlTextNum(nLvl));
			this.LvlText.push(new CNumberingLvlTextString(")"));
			this.TextPr = new CTextPr();
			break;
	}
};
/**
 * Получаем тип пресета (если это возможно)
 * @returns {{Type: number, SubType: number}}
 */
CNumberingLvl.prototype.GetPresetType = function()
{
	var nType    = -1;
	var nSubType = -1;

	if (Asc.c_oAscNumberingFormat.Bullet === this.Format)
	{
		nType    = 0;
		nSubType = 0;

		if (1 === this.LvlText.length && numbering_lvltext_Text === this.LvlText[0].Type)
		{
			var nNumVal = this.LvlText[0].Value.charCodeAt(0);

			if (0x00B7 === nNumVal)
				nSubType = 1;
			else if (0x006F === nNumVal)
				nSubType = 2;
			else if (0x00A7 === nNumVal)
				nSubType = 3;
			else if (0x0076 === nNumVal)
				nSubType = 4;
			else if (0x00D8 === nNumVal)
				nSubType = 5;
			else if (0x00FC === nNumVal)
				nSubType = 6;
			else if (0x00A8 === nNumVal)
				nSubType = 7;
			else if (0x2013 === nNumVal)
				nSubType = 8;
		}
	}
	else
	{
		nType    = 1;
		nSubType = 0;

		if (2 === this.LvlText.length && numbering_lvltext_Num === this.LvlText[0].Type && numbering_lvltext_Text === this.LvlText[1].Type)
		{
			var nNumVal2 = this.LvlText[1].Value;

			if (Asc.c_oAscNumberingFormat.Decimal === this.Format)
			{
				if ("." === nNumVal2)
					nSubType = 1;
				else if (")" === nNumVal2)
					nSubType = 2;
			}
			else if (Asc.c_oAscNumberingFormat.UpperRoman === this.Format)
			{
				if ("." === nNumVal2)
					nSubType = 3;
			}
			else if (Asc.c_oAscNumberingFormat.UpperLetter === this.Format)
			{
				if ("." === nNumVal2)
					nSubType = 4;
			}
			else if (Asc.c_oAscNumberingFormat.LowerLetter === this.Format)
			{
				if (")" === nNumVal2)
					nSubType = 5;
				else if ("." === nNumVal2)
					nSubType = 6;
			}
			else if (Asc.c_oAscNumberingFormat.LowerRoman === this.Format)
			{
				if ("." === nNumVal2)
					nSubType = 7;
			}
		}
	}

	return {Type : nType, SubType : nSubType};
};
/**
 * Выставляем значения по заданному формату
 * @param nLvl {number} 0..8
 * @param nType
 * @param sFormatText
 * @param nAlign
 */
CNumberingLvl.prototype.SetByFormat = function(nLvl, nType, sFormatText, nAlign)
{
	this.Jc      = nAlign;
	this.Format  = nType;
	this.LvlText = [];

	var nLastPos = 0;
	var nPos     = 0;
	while (-1 !== (nPos = sFormatText.indexOf("%", nPos)) && nPos < sFormatText.length)
	{
		if (nPos < sFormatText.length - 1 && sFormatText.charCodeAt(nPos + 1) >= 49 && sFormatText.charCodeAt(nPos + 1) <= 49 + nLvl)
		{
			if (nPos > nLastPos)
			{
				var sSubString = sFormatText.substring(nLastPos, nPos);
				for (var nSubIndex = 0, nSubLen = sSubString.length; nSubIndex < nSubLen; ++nSubIndex)
					this.LvlText.push(new CNumberingLvlTextString(sSubString.charAt(nSubIndex)));
			}

			this.LvlText.push(new CNumberingLvlTextNum(sFormatText.charCodeAt(nPos + 1) - 49));
			nPos += 2;
			nLastPos = nPos;
		}
		else
		{
			nPos++;
		}
	}
	nPos = sFormatText.length;
	if (nPos > nLastPos)
	{
		var sSubString = sFormatText.substring(nLastPos, nPos);
		for (var nSubIndex = 0, nSubLen = sSubString.length; nSubIndex < nSubLen; ++nSubIndex)
			this.LvlText.push(new CNumberingLvlTextString(sSubString.charAt(nSubIndex)));
	}

	this.TextPr = new CTextPr();
};
/**
 * Собираем статистику документа о количестве слов, букв и т.д.
 * @param oStats объект статистики
 */
CNumberingLvl.prototype.CollectDocumentStatistics = function(oStats)
{
	var bWord = false;
	for (var nIndex = 0, nCount = this.LvlText.length; nIndex < nCount; ++nIndex)
	{
		var bSymbol  = false;
		var bSpace   = false;
		var bNewWord = false;

		if (numbering_lvltext_Text === this.LvlText[nIndex].Type && (sp_string === this.LvlText[nIndex].Value || nbsp_string === this.LvlText[nIndex].Value))
		{
			bWord   = false;
			bSymbol = true;
			bSpace  = true;
		}
		else
		{
			if (false === bWord)
				bNewWord = true;

			bWord   = true;
			bSymbol = true;
			bSpace  = false;
		}

		if (true === bSymbol)
			oStats.Add_Symbol(bSpace);

		if (true === bNewWord)
			oStats.Add_Word();
	}

	if (Asc.c_oAscNumberingSuff.Tab === this.Suff || Asc.c_oAscNumberingSuff.Space === this.Suff)
		oStats.Add_Symbol(true);
};
/**
 * Все нумерованные значение переделываем на заданный уровень
 * @param nLvl {number} 0..8
 */
CNumberingLvl.prototype.ResetNumberedText = function(nLvl)
{
	for (var nIndex = 0, nCount = this.LvlText.length; nIndex < nCount; ++nIndex)
	{
		if (numbering_lvltext_Num === this.LvlText[nIndex].Type)
			this.LvlText[nIndex].Value = nLvl;
	}
};
/**
 * Проверяем, совпадает ли тип и текст в заданных нумерациях
 * @param oLvl {CNumberingLvl}
 * @returns {boolean}
 */
CNumberingLvl.prototype.IsSimilar = function(oLvl)
{
	if (this.Format !== oLvl.Format || this.LvlText.length !== oLvl.LvlText.length)
		return false;

	for (var nIndex = 0, nCount = this.LvlText.length; nIndex < nCount; ++nIndex)
	{
		if (this.LvlText[nIndex].Type !== oLvl.LvlText[nIndex].Type
			|| this.LvlText[nIndex].Value !== oLvl.LvlText[nIndex].Value)
			return false;
	}

	return true;
};
/**
 * Заполняем специальный класс для работы с интерфейсом
 * @param oAscLvl {CAscNumberingLvl}
 */
CNumberingLvl.prototype.FillToAscNumberingLvl = function(oAscLvl)
{
	oAscLvl.put_Format(this.GetFormat());
	oAscLvl.put_Align(this.GetJc());
	oAscLvl.put_Restart(this.GetRestart());
	oAscLvl.put_Start(this.GetStart());
	oAscLvl.put_Suff(this.GetSuff());

	var arrText = [];
	for (var nPos = 0, nCount = this.LvlText.length; nPos < nCount; ++nPos)
	{
		var oTextElement = this.LvlText[nPos];
		var oAscElement  = new Asc.CAscNumberingLvlText();

		if (numbering_lvltext_Text === oTextElement.Type)
			oAscElement.put_Type(Asc.c_oAscNumberingLvlTextType.Text);
		else
			oAscElement.put_Type(Asc.c_oAscNumberingLvlTextType.Num);

		oAscElement.put_Value(oTextElement.Value);
		arrText.push(oAscElement);
	}
	oAscLvl.put_Text(arrText);

	oAscLvl.TextPr = this.TextPr.Copy();
	oAscLvl.ParaPr = this.ParaPr.Copy();
};
/**
 * Заполняем настройки уровня из интерфейсного класса
 * @param oAscLvl {CAscNumberingLvl}
 */
CNumberingLvl.prototype.FillFromAscNumberingLvl = function(oAscLvl)
{
	if (undefined !== oAscLvl.get_Format())
		this.Format = oAscLvl.get_Format();

	if (undefined !== oAscLvl.get_Align())
		this.Jc = oAscLvl.get_Align();

	if (undefined !== oAscLvl.get_Restart())
		this.Restart = oAscLvl.get_Restart();

	if (undefined !== oAscLvl.get_Start())
		this.Start = oAscLvl.get_Start();

	if (undefined !== oAscLvl.get_Suff())
		this.Suff = oAscLvl.get_Suff();

	if (undefined !== oAscLvl.get_Text())
	{
		var arrAscText = oAscLvl.get_Text();
		for (var nPos = 0, nCount = arrAscText.length; nPos < nCount; ++nPos)
		{
			var oTextElement = arrAscText[nPos];
			var oElement;
			if (Asc.c_oAscNumberingLvlTextType.Text === oTextElement.get_Type())
			{
				oElement = new CNumberingLvlTextString(oTextElement.get_Value());
			}
			else if (Asc.c_oAscNumberingLvlTextType.Num === oTextElement.get_Type())
			{
				oElement = new CNumberingLvlTextNum(oTextElement.get_Value());
			}

			if (oElement)
				this.LvlText.push(oElement);
		}
	}

	if (undefined !== oAscLvl.get_TextPr())
		this.TextPr = oAscLvl.get_TextPr().Copy();

	if (undefined !== oAscLvl.get_ParaPr())
		this.ParaPr = oAscLvl.get_ParaPr().Copy();
};
CNumberingLvl.prototype.WriteToBinary = function(oWriter)
{
	// Long               : Jc
	// Long               : Format
	// String             : PStyle
	// Long               : Start
	// Long               : Restart
	// Long               : Suff
	// Variable           : TextPr
	// Variable           : ParaPr
	// Long               : количество элементов в LvlText
	// Array of variables : массив LvlText
	// Bool               : true -> CNumberingLegacy
	//                    : false -> Legacy = undefined

	oWriter.WriteLong(this.Jc);
	oWriter.WriteLong(this.Format);

	oWriter.WriteString2(this.PStyle ? this.PStyle : "");

	oWriter.WriteLong(this.Start);
	oWriter.WriteLong(this.Restart);
	oWriter.WriteLong(this.Suff);

	this.TextPr.WriteToBinary(oWriter);
	this.ParaPr.WriteToBinary(oWriter);

	var nCount = this.LvlText.length;
	oWriter.WriteLong(nCount);

	for (var nIndex = 0; nIndex < nCount; ++nIndex)
		this.LvlText[nIndex].WriteToBinary(oWriter);

	if (this.Legacy instanceof CNumberingLvlLegacy)
	{
		oWriter.WriteBool(true);
		this.Legacy.WriteToBinary(oWriter);
	}
	else
	{
		oWriter.WriteBool(false);
	}
};
CNumberingLvl.prototype.ReadFromBinary = function(oReader)
{
	// Long               : Jc
	// Long               : Format
	// String             : PStyle
	// Long               : Start
	// Long               : Restart
	// Long               : Suff
	// Variable           : TextPr
	// Variable           : ParaPr
	// Long               : количество элементов в LvlText
	// Array of variables : массив LvlText
	// Bool               : true -> CNumberingLegacy
	//                    : false -> Legacy = undefined


	this.Jc     = oReader.GetLong();
	this.Format = oReader.GetLong();

	this.PStyle = oReader.GetString2();
	if ("" === this.PStyle)
		this.PStyle = undefined;

	this.Start   = oReader.GetLong();
	this.Restart = oReader.GetLong();
	this.Suff    = oReader.GetLong();

	this.TextPr = new CTextPr();
	this.ParaPr = new CParaPr();
	this.TextPr.ReadFromBinary(oReader);
	this.ParaPr.ReadFromBinary(oReader);

	var nCount = oReader.GetLong();
	this.LvlText = [];
	for (var nIndex = 0; nIndex < nCount; ++nIndex)
	{
		var oElement = this.private_ReadLvlTextFromBinary(oReader);
		if (oElement)
			this.LvlText.push(oElement);
	}

	if (oReader.GetBool())
	{
		this.Legacy = new CNumberingLvlLegacy();
		this.Legacy.ReadFromBinary(oReader);
	}
};
CNumberingLvl.prototype.private_ReadLvlTextFromBinary = function(oReader)
{
	var nType = oReader.GetLong();

	var oElement = null;
	if (numbering_lvltext_Num === nType)
		oElement = new CNumberingLvlTextNum();
	else if (numbering_lvltext_Text === nType)
		oElement = new CNumberingLvlTextString();

	oElement.ReadFromBinary(oReader);
	return oElement;
};
/**
 * Проверяем является ли данный уровень маркированным
 * @returns {boolean}
 */
CNumberingLvl.prototype.IsBulleted = function()
{
	return this.GetFormat() === Asc.c_oAscNumberingFormat.Bullet;
};
/**
 * Проверяем является ли данный уровень нумерованным
 * @returns {boolean}
 */
CNumberingLvl.prototype.IsNumbered = function()
{
	var nFormat = this.GetFormat();
	return (nFormat !== Asc.c_oAscNumberingFormat.Bullet && nFormat !== Asc.c_oAscNumberingFormat.None);
};


function CNumberingLvlTextString(Val)
{
	if ("string" == typeof(Val))
		this.Value = Val;
	else
		this.Value = "";

	this.Type = numbering_lvltext_Text;
}
CNumberingLvlTextString.prototype.Copy = function()
{
	return new CNumberingLvlTextString(this.Value);
};
CNumberingLvlTextString.prototype.WriteToBinary = function(Writer)
{
	// Long   : numbering_lvltext_Text
	// String : Value

	Writer.WriteLong(numbering_lvltext_Text);
	Writer.WriteString2(this.Value);
};
CNumberingLvlTextString.prototype.ReadFromBinary = function(Reader)
{
	this.Value = Reader.GetString2();
};

function CNumberingLvlTextNum(Lvl)
{
	if ("number" == typeof(Lvl))
		this.Value = Lvl;
	else
		this.Value = 0;

	this.Type = numbering_lvltext_Num;
}
CNumberingLvlTextNum.prototype.Copy = function()
{
	return new CNumberingLvlTextNum(this.Value);
};
CNumberingLvlTextNum.prototype.WriteToBinary = function(Writer)
{
	// Long : numbering_lvltext_Text
	// Long : Value

	Writer.WriteLong(numbering_lvltext_Num);
	Writer.WriteLong(this.Value);
};
CNumberingLvlTextNum.prototype.ReadFromBinary = function(Reader)
{
	this.Value = Reader.GetLong();
};

function CNumberingLvlLegacy(isUse, twIndent, twSpace)
{
	this.Legacy = !!isUse;
	this.Indent = twIndent ? twIndent : 0; // Значение в твипсах
	this.Space  = twSpace ? twSpace : 0;   // Значение в твипсах
}
CNumberingLvlLegacy.prototype.Copy = function()
{
	return new CNumberingLvlLegacy(this.Legacy, this.Indent, this.Space);
};
CNumberingLvlLegacy.prototype.WriteToBinary = function(oWriter)
{
	// Bool : Legacy
	// Long : Indent
	// Long : Space
	oWriter.WriteBool(this.Legacy);
	oWriter.WriteLong(this.Indent);
	oWriter.WriteLong(this.Space);
};
CNumberingLvlLegacy.prototype.ReadFromBinary = function(oReader)
{
	// Bool : Legacy
	// Long : Indent
	// Long : Space
	this.Legacy = oReader.GetBool();
	this.Indent = oReader.GetLong();
	this.Space  = oReader.GetLong();
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 08.05.2018
 * Time: 15:08
 */

// Import
var g_oTextMeasurer = AscCommon.g_oTextMeasurer;
var History         = AscCommon.History;

/**
 * Класс реализующий w:abstractNum
 * @constructor
 */
function CAbstractNum()
{
	this.Id = AscCommon.g_oIdCounter.Get_NewId();

	this.Lock = new AscCommon.CLock();
	if (false === AscCommon.g_oIdCounter.m_bLoad)
	{
		this.Lock.Set_Type(AscCommon.locktype_Mine, false);
		if (typeof AscCommon.CollaborativeEditing !== "undefined")
			AscCommon.CollaborativeEditing.Add_Unlock2(this);
	}

	this.NumStyleLink = undefined;
	this.StyleLink    = undefined;

	this.Lvl = [];
	for (var nLvl = 0; nLvl < 9; ++nLvl)
	{
		this.Lvl[nLvl] = new CNumberingLvl();
		this.Lvl[nLvl].InitDefault(nLvl);
	}

	// Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
	AscCommon.g_oTableId.Add(this, this.Id);
}

CAbstractNum.prototype.Get_Id = function()
{
	return this.Id;
};
CAbstractNum.prototype.GetId = function()
{
	return this.Id;
};
CAbstractNum.prototype.Copy = function(oAbstractNum)
{
	this.SetStyleLink(oAbstractNum.StyleLink);
	this.SetNumStyleLink(oAbstractNum.NumStyleLink);

	for (var nLvl = 0; nLvl < 9; ++nLvl)
	{
		var oLvlNew = oAbstractNum.Lvl[nLvl].Copy();
		var oLvlOld = this.Lvl[nLvl];

		History.Add(new CChangesAbstractNumLvlChange(this, oLvlOld, oLvlNew, nLvl));
		this.Lvl[nLvl] = oLvlNew;
	}
};
CAbstractNum.prototype.SetStyleLink = function(sValue)
{
	if (sValue !== this.StyleLink)
	{
		History.Add(new CChangesAbstractNumStyleLink(this, this.StyleLink, sValue));
		this.StyleLink = sValue;
	}
};
CAbstractNum.prototype.GetStyleLink = function()
{
	return this.StyleLink;
};
CAbstractNum.prototype.SetNumStyleLink = function(sValue)
{
	if (sValue !== this.NumStyleLink)
	{
		History.Add(new CChangesAbstractNumNumStyleLink(this, this.NumStyleLink, sValue));
		this.NumStyleLink = sValue;
	}
};
CAbstractNum.prototype.GetNumStyleLink = function()
{
	return this.NumStyleLink;
};
CAbstractNum.prototype.private_RecalculateRelatedParagraphs = function(nLvl)
{
	if (nLvl < 0 || nLvl > 8)
		nLvl = undefined;

	var oLogicDocument = editor.WordControl.m_oLogicDocument;
	var arrParagraphs  = oLogicDocument.GetAllParagraphsByNumbering({NumId : this.Id, Lvl : nLvl});

	for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
	{
		arrParagraphs[nIndex].RecalcCompiledPr();
	}
};
/**
 * Получаем заданный уровень
 * @param nLvl {number}
 * @returns {CNumberingLvl}
 */
CAbstractNum.prototype.GetLvl = function(nLvl)
{
	if (!this.Lvl[nLvl])
		return this.Lvl[0];

	return this.Lvl[nLvl];
};
/**
 * Задаем уровень
 * @param nLvl {number}
 * @param oLvlNew {CNumberingLvl}
 */
CAbstractNum.prototype.SetLvl = function(nLvl, oLvlNew)
{
	if ("number" != typeof(nLvl) || nLvl < 0 || nLvl >= 9)
		return;

	var oLvlOld    = this.Lvl[nLvl];
	this.Lvl[nLvl] = oLvlNew;
	History.Add(new CChangesAbstractNumLvlChange(this, oLvlOld, oLvlNew, nLvl));
};
/**
 * Создаем многоуровневый список с заданным пресетом
 * @param nType {c_oAscMultiLevelNumbering}
 */
CAbstractNum.prototype.CreateDefault = function(nType)
{
	for (var nLvl = 0; nLvl < 9; ++nLvl)
	{
		var oLvlNew = new CNumberingLvl();
		oLvlNew.InitDefault(nLvl, nType);

		var oLvlOld = this.Lvl[nLvl].Copy();
		History.Add(new CChangesAbstractNumLvlChange(this, oLvlOld, oLvlNew.Copy(), nLvl));
		this.Lvl[nLvl] = oLvlNew;
	}
};
/**
 * Делаем заданный уровень заданного пресета
 * @param nLvl {number} 0..8
 * @param nType {c_oAscNumberingLevel}
 * @param [sText=undefined] Используется для типа c_oAscNumberingLevel.Bullet
 * @param [oTextPr=undefined] {CTextPr} Используется для типа c_oAscNumberingLevel.Bullet
 */
CAbstractNum.prototype.SetLvlByType = function(nLvl, nType, sText, oTextPr)
{
	if ("number" !== typeof(nLvl) || nLvl < 0 || nLvl >= 9)
		return;

	var oLvlOld = this.Lvl[nLvl].Copy();
	this.Lvl[nLvl].SetByType(nType, nLvl, sText, oTextPr);
	History.Add(new CChangesAbstractNumLvlChange(this, oLvlOld, this.Lvl[nLvl].Copy(), nLvl));
};
/**
 * Заполняем уровень по заданному формату
 * @param nLvl {number} 0..8
 * @param nType
 * @param sFormatText
 * @param nAlign
 */
CAbstractNum.prototype.SetLvlByFormat = function(nLvl, nType, sFormatText, nAlign)
{
	if ("number" !== typeof(nLvl) || nLvl < 0 || nLvl >= 9)
		return;

	var oLvlOld = this.Lvl[nLvl].Copy();
	this.Lvl[nLvl].SetByFormat(nLvl, nType, sFormatText, nAlign);

	History.Add(new CChangesAbstractNumLvlChange(this, oLvlOld, this.Lvl[nLvl].Copy(), nLvl));
};
/**
 * Выставляем является ли данный уровень сквозным или каждый раз перестартовывать нумерацию
 * @param nLvl {number} 0..8
 * @param isRestart {boolean}
 */
CAbstractNum.prototype.SetLvlRestart = function(nLvl, isRestart)
{
	if ("number" !== typeof(nLvl) || nLvl < 0 || nLvl >= 9)
		return;

	var oLvlOld = this.Lvl[nLvl].Copy();

	this.Lvl[nLvl].Restart = (isRestart ? -1 : 0);
	History.Add(new CChangesAbstractNumLvlChange(this, oLvlOld, this.Lvl[nLvl].Copy(), nLvl));
};
/**
 * Задаем начальное значения для данного уровня
 * @param nLvl {number} 0..8
 * @param nStart {number}
 */
CAbstractNum.prototype.SetLvlStart = function(nLvl, nStart)
{
	if ("number" !== typeof(nLvl) || nLvl < 0 || nLvl >= 9)
		return;

	var oLvlOld = this.Lvl[nLvl].Copy();

	this.Lvl[nLvl].Start = nStart;
	History.Add(new CChangesAbstractNumLvlChange(this, oLvlOld, this.Lvl[nLvl].Copy(), nLvl));
};
/**
 * Выставляем тип разделителя между табом и последующим текстом
 * @param nLvl {number} 0..8
 * @param nSuff {number}
 */
CAbstractNum.prototype.SetLvlSuff = function(nLvl, nSuff)
{
	if ("number" !== typeof(nLvl) || nLvl < 0 || nLvl >= 9)
		return;

	var oLvlOld = this.Lvl[nLvl].Copy();

	this.Lvl[nLvl].Suff = nSuff;
	History.Add(new CChangesAbstractNumLvlChange(this, oLvlOld, this.Lvl[nLvl].Copy(), nLvl));
};
/**
 * Применяем новые тектовые настройки к данной нумерации на заданном уровне
 * @param nLvl {number} 0..8
 * @param oTextPr {CTextPr}
 */
CAbstractNum.prototype.ApplyTextPr = function(nLvl, oTextPr)
{
	var oTextPrOld = this.Lvl[nLvl].TextPr.Copy();
	this.Lvl[nLvl].TextPr.Merge(oTextPr);
	History.Add(new CChangesAbstractNumTextPrChange(this, oTextPrOld, this.Lvl[nLvl].TextPr.Copy(), nLvl));
};
/**
 * Выставляем текстовые настройки для заданного уровня
 * @param nLvl {number} 0..8
 * @param oTextPr {CTextPr}
 */
CAbstractNum.prototype.SetTextPr = function(nLvl, oTextPr)
{
	History.Add(new CChangesAbstractNumTextPrChange(this, this.Lvl[nLvl].TextPr, oTextPr.Copy(), nLvl));
	this.Lvl[nLvl].TextPr = oTextPr;
};
/**
 * Выставляем настройки параграфа для заданного уровня
 * @param nLvl {number} 0..8
 * @param oParaPr {CParaPr}
 */
CAbstractNum.prototype.SetParaPr = function(nLvl, oParaPr)
{
	History.Add(new CChangesAbstractNumParaPrChange(this, this.Lvl[nLvl].ParaPr, oParaPr.Copy(), nLvl));
	this.Lvl[nLvl].ParaPr = oParaPr;
};
//----------------------------------------------------------------------------------------------------------------------
// Undo/Redo функции
//----------------------------------------------------------------------------------------------------------------------
CAbstractNum.prototype.Refresh_RecalcData = function(Data)
{
	var oHistory = History;
	if (!oHistory)
		return;

	if (!oHistory.AddChangedNumberingToRecalculateData(this.Get_Id(), Data.Index, this))
		return;

	var oLogicDocument = editor.WordControl.m_oLogicDocument;
	if (!oLogicDocument)
		return;

	var oNumbering = oLogicDocument.GetNumbering();
	var arrNumPr   = [];

	for (var sId in oNumbering.Num)
	{
		var oNum = oNumbering.Num[sId];
		if (this.Id === oNum.GetAbstractNumId())
		{
			arrNumPr.push(new CNumPr(oNum.GetId(), Data.Index));
		}
	}

	var arrAllParagraphs = oLogicDocument.GetAllParagraphsByNumbering(arrNumPr);

	for (var nIndex = 0, nCount = arrAllParagraphs.length; nIndex < nCount; ++nIndex)
	{
		arrAllParagraphs[nIndex].Refresh_RecalcData({Type : AscDFH.historyitem_Paragraph_Numbering});
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с совместным редактирования
//----------------------------------------------------------------------------------------------------------------------
CAbstractNum.prototype.Write_ToBinary2 = function(Writer)
{
	Writer.WriteLong(AscDFH.historyitem_type_AbstractNum);

	// String          : Id
	// String          : StyleLink
	// String          : NumStyleLink
	// Variable[9 Lvl] : 9 уровней

	Writer.WriteString2(this.Id);

	Writer.WriteString2(this.StyleLink ? this.StyleLink : "");
	Writer.WriteString2(this.NumStyleLink ? this.NumStyleLink : "");

	for (var nLvl = 0; nLvl < 9; ++nLvl)
		this.Lvl[nLvl].WriteToBinary(Writer);
};
CAbstractNum.prototype.Read_FromBinary2 = function(Reader)
{
	// String          : Id
	// String          : StyleLink
	// String          : NumStyleLink
	// Variable[9 Lvl] : 9 уровней

	this.Id           = Reader.GetString2();

	this.StyleLink    = Reader.GetString2();
	this.NumStyleLink = Reader.GetString2();

	if ("" === this.StyleLink)
		this.StyleLink = undefined;

	if ("" === this.NumStyleLink)
		this.NumStyleLink = undefined;

	for (var nLvl = 0; nLvl < 9; ++nLvl)
	{
		this.Lvl[nLvl] = new CNumberingLvl();
		this.Lvl[nLvl].ReadFromBinary(Reader);
	}

	// Добавим данный список в нумерацию
	var Numbering                  = editor.WordControl.m_oLogicDocument.Get_Numbering();
	Numbering.AbstractNum[this.Id] = this;
};
CAbstractNum.prototype.Process_EndLoad = function(Data)
{
	var iLvl = Data.iLvl;
	if (undefined !== iLvl)
	{
		// Пересчитываем стили у все параграфов с данной нумерацией
		this.Recalc_CompiledPr(iLvl);
	}
};
CAbstractNum.prototype.Recalc_CompiledPr = function(nLvl)
{
	// Ищем все параграфы, который используют данную нумерацию и проставляем у них, то что их стиль
	// нужно перекомпилировать.

	this.private_RecalculateRelatedParagraphs(nLvl);
};
CAbstractNum.prototype.isEqual = function(abstractNum)
{
	var lvlUsuallyAdd = this.Lvl;
	var lvlNew        = abstractNum.Lvl;
	for (var lvl = 0; lvl < lvlUsuallyAdd.length; lvl++)
	{
		var LvlTextEqual = null;
		var ParaPrEqual  = null;
		var TextPrEqual  = null;
		if (lvlUsuallyAdd[lvl].Format == lvlNew[lvl].Format && lvlUsuallyAdd[lvl].Jc == lvlNew[lvl].Jc && lvlUsuallyAdd[lvl].PStyle == lvlNew[lvl].PStyle && lvlUsuallyAdd[lvl].Restart == lvlNew[lvl].Restart && lvlUsuallyAdd[lvl].Start == lvlNew[lvl].Start && lvlUsuallyAdd[lvl].Suff == lvlNew[lvl].Suff)
		{
			LvlTextEqual = this._isEqualLvlText(lvlUsuallyAdd[lvl].LvlText, lvlNew[lvl].LvlText);
			ParaPrEqual  = lvlUsuallyAdd[lvl].ParaPr.isEqual(lvlUsuallyAdd[lvl].ParaPr, lvlNew[lvl].ParaPr);
			TextPrEqual  = lvlUsuallyAdd[lvl].TextPr.isEqual(lvlUsuallyAdd[lvl].TextPr, lvlNew[lvl].TextPr);
		}
		if (!LvlTextEqual || !ParaPrEqual || !TextPrEqual)
			return false;
	}
	return true;
};
CAbstractNum.prototype._isEqualLvlText = function(LvlTextOld, LvlTextNew)
{
	if (LvlTextOld.length !== LvlTextNew.length)
		return false;

	for (var LvlText = 0; LvlText < LvlTextOld.length; LvlText++)
	{
		if (LvlTextOld[LvlText].Type != LvlTextNew[LvlText].Type || LvlTextOld[LvlText].Value != LvlTextNew[LvlText].Value)
			return false;
	}
	return true;
};

//--------------------------------------------------------export--------------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CAbstractNum = CAbstractNum;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 08.11.2016
 * Time: 14:37
 */

AscDFH.changesFactory[AscDFH.historyitem_AbstractNum_LvlChange]    = CChangesAbstractNumLvlChange;
AscDFH.changesFactory[AscDFH.historyitem_AbstractNum_TextPrChange] = CChangesAbstractNumTextPrChange;
AscDFH.changesFactory[AscDFH.historyitem_AbstractNum_ParaPrChange] = CChangesAbstractNumParaPrChange;
AscDFH.changesFactory[AscDFH.historyitem_AbstractNum_StyleLink]    = CChangesAbstractNumStyleLink;
AscDFH.changesFactory[AscDFH.historyitem_AbstractNum_NumStyleLink] = CChangesAbstractNumNumStyleLink;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_AbstractNum_LvlChange]    = [
	AscDFH.historyitem_AbstractNum_LvlChange,
	AscDFH.historyitem_AbstractNum_TextPrChange,
	AscDFH.historyitem_AbstractNum_ParaPrChange
];
AscDFH.changesRelationMap[AscDFH.historyitem_AbstractNum_TextPrChange] = [
	AscDFH.historyitem_AbstractNum_LvlChange,
	AscDFH.historyitem_AbstractNum_TextPrChange
];
AscDFH.changesRelationMap[AscDFH.historyitem_AbstractNum_ParaPrChange] = [
	AscDFH.historyitem_AbstractNum_LvlChange,
	AscDFH.historyitem_AbstractNum_ParaPrChange
];
AscDFH.changesRelationMap[AscDFH.historyitem_AbstractNum_StyleLink] = [
	AscDFH.historyitem_AbstractNum_StyleLink
];
AscDFH.changesRelationMap[AscDFH.historyitem_AbstractNum_NumStyleLink] = [
	AscDFH.historyitem_AbstractNum_NumStyleLink
];
//----------------------------------------------------------------------------------------------------------------------


/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesAbstractNumLvlChange(Class, Old, New, Index)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);

	this.Index = Index;
}
CChangesAbstractNumLvlChange.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesAbstractNumLvlChange.prototype.constructor = CChangesAbstractNumLvlChange;
CChangesAbstractNumLvlChange.prototype.Type = AscDFH.historyitem_AbstractNum_LvlChange;
CChangesAbstractNumLvlChange.prototype.WriteToBinary = function(Writer)
{
	// Long          : Lvl index
	// CNumberingLvl : New Lvl
	// CNumberingLvl : Old Lvl

	Writer.WriteLong(this.Index);
	this.New.WriteToBinary(Writer);
	this.Old.WriteToBinary(Writer);
};
CChangesAbstractNumLvlChange.prototype.ReadFromBinary = function(Reader)
{
	// Long          : Lvl index
	// CNumberingLvl : New Lvl
	// CNumberingLvl : Old Lvl

	this.New = new CNumberingLvl();
	this.Old = new CNumberingLvl();

	this.Index = Reader.GetLong();
	this.New.ReadFromBinary(Reader);
	this.Old.ReadFromBinary(Reader);
};
CChangesAbstractNumLvlChange.prototype.private_SetValue = function(Value)
{
	var oAbstractNum = this.Class;
	oAbstractNum.Lvl[this.Index] = Value;
	oAbstractNum.Recalc_CompiledPr(this.Index);
};
CChangesAbstractNumLvlChange.prototype.Load = function(Color)
{
	var oAbstractNum = this.Class;
	oAbstractNum.Lvl[this.Index] = this.New;

	// Сразу нельзя запускать пересчет, т.к. возможно еще не все ссылки проставлены
	AscCommon.CollaborativeEditing.Add_EndActions(this.Class, {iLvl : this.Index});
};
CChangesAbstractNumLvlChange.prototype.CreateReverseChange = function()
{
	return new CChangesAbstractNumLvlChange(this.Class, this.New, this.Old, this.Index);
};
CChangesAbstractNumLvlChange.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type)
		return false;

	if (AscDFH.historyitem_AbstractNum_TextPrChange === oChange.Type)
	{
		this.New.TextPr = oChange.New;
	}
	else if (AscDFH.historyitem_AbstractNum_ParaPrChange === oChange.Type)
	{
		this.New.ParaPr = oChange.New;
	}

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesAbstractNumTextPrChange(Class, Old, New, Index)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);

	this.Index = Index;
}
CChangesAbstractNumTextPrChange.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesAbstractNumTextPrChange.prototype.constructor = CChangesAbstractNumTextPrChange;
CChangesAbstractNumTextPrChange.prototype.Type = AscDFH.historyitem_AbstractNum_TextPrChange;
CChangesAbstractNumTextPrChange.prototype.WriteToBinary = function(Writer)
{
	// Long : Lvl index
	// TextPr : New TextPr
	// TextPr : Old TextPr

	Writer.WriteLong(this.Index);
	this.New.Write_ToBinary(Writer);
	this.Old.Write_ToBinary(Writer);
};
CChangesAbstractNumTextPrChange.prototype.ReadFromBinary = function(Reader)
{
	// Long : Lvl index
	// TextPr : New TextPr
	// TextPr : Old TextPr

	this.New = new CTextPr();
	this.Old = new CTextPr();

	this.Index = Reader.GetLong();
	this.New.Read_FromBinary(Reader);
	this.Old.Read_FromBinary(Reader);
};
CChangesAbstractNumTextPrChange.prototype.private_SetValue = function(Value)
{
	var oAbstractNum = this.Class;
	oAbstractNum.Lvl[this.Index].TextPr = Value;
	oAbstractNum.Recalc_CompiledPr(this.Index);
};
CChangesAbstractNumTextPrChange.prototype.Load = function(Color)
{
	var oAbstractNum = this.Class;
	oAbstractNum.Lvl[this.Index].TextPr = this.New;

	// Сразу нельзя запускать пересчет, т.к. возможно еще не все ссылки проставлены
	AscCommon.CollaborativeEditing.Add_EndActions(this.Class, {iLvl : this.Index});
};
CChangesAbstractNumTextPrChange.prototype.CreateReverseChange = function()
{
	return new CChangesAbstractNumTextPrChange(this.Class, this.New, this.Old, this.Index);
};
CChangesAbstractNumTextPrChange.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type || oChange.Type === AscDFH.historyitem_AbstractNum_LvlChange)
		return false;

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesAbstractNumParaPrChange(Class, Old, New, Index)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);

	this.Index = Index;
}
CChangesAbstractNumParaPrChange.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesAbstractNumParaPrChange.prototype.constructor = CChangesAbstractNumParaPrChange;
CChangesAbstractNumParaPrChange.prototype.Type = AscDFH.historyitem_AbstractNum_ParaPrChange;
CChangesAbstractNumParaPrChange.prototype.WriteToBinary = function(Writer)
{
	// Long : Lvl index
	// ParaPr : New ParaPr
	// ParaPr : Old ParaPr

	Writer.WriteLong(this.Index);
	this.New.Write_ToBinary(Writer);
	this.Old.Write_ToBinary(Writer);
};
CChangesAbstractNumParaPrChange.prototype.ReadFromBinary = function(Reader)
{
	// Long : Lvl index
	// ParaPr : New ParaPr
	// ParaPr : Old ParaPr

	this.New = new CParaPr();
	this.Old = new CParaPr();

	this.Index = Reader.GetLong();
	this.New.Read_FromBinary(Reader);
	this.Old.Read_FromBinary(Reader);
};
CChangesAbstractNumParaPrChange.prototype.private_SetValue = function(Value)
{
	var oAbstractNum = this.Class;
	oAbstractNum.Lvl[this.Index].ParaPr = Value;
	oAbstractNum.Recalc_CompiledPr(this.Index);
};
CChangesAbstractNumParaPrChange.prototype.Load = function(Color)
{
	var oAbstractNum = this.Class;
	oAbstractNum.Lvl[this.Index].ParaPr = this.New;

	// Сразу нельзя запускать пересчет, т.к. возможно еще не все ссылки проставлены
	AscCommon.CollaborativeEditing.Add_EndActions(this.Class, {iLvl : this.Index});
};
CChangesAbstractNumParaPrChange.prototype.CreateReverseChange = function()
{
	return new CChangesAbstractNumParaPrChange(this.Class, this.New, this.Old, this.Index);
};
CChangesAbstractNumParaPrChange.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type || oChange.Type === AscDFH.historyitem_AbstractNum_LvlChange)
		return false;

	return true;
};

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseStringProperty}
 */
function CChangesAbstractNumStyleLink(Class, Old, New)
{
	AscDFH.CChangesBaseStringProperty.call(this, Class, Old, New);
}
CChangesAbstractNumStyleLink.prototype = Object.create(AscDFH.CChangesBaseStringProperty.prototype);
CChangesAbstractNumStyleLink.prototype.constructor = CChangesAbstractNumStyleLink;
CChangesAbstractNumStyleLink.prototype.Type = AscDFH.historyitem_AbstractNum_StyleLink;
CChangesAbstractNumStyleLink.prototype.private_SetValue = function(Value)
{
	this.Class.StyleLink = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseStringProperty}
 */
function CChangesAbstractNumNumStyleLink(Class, Old, New)
{
	AscDFH.CChangesBaseStringProperty.call(this, Class, Old, New);
}
CChangesAbstractNumNumStyleLink.prototype = Object.create(AscDFH.CChangesBaseStringProperty.prototype);
CChangesAbstractNumNumStyleLink.prototype.constructor = CChangesAbstractNumNumStyleLink;
CChangesAbstractNumNumStyleLink.prototype.Type = AscDFH.historyitem_AbstractNum_NumStyleLink;
CChangesAbstractNumNumStyleLink.prototype.private_SetValue = function(Value)
{
	this.Class.NumStyleLink = Value;
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 08.05.2018
 * Time: 15:08
 */

/**
 * Класс представляющий нумерацию параграфов в документах
 * @param {CNumbering} oNumbering - ссылка на главный объект нумерации в документах
 * @param {string} sAbstractNumId - идентификатор абстрактной нумерации
 * @constructor
 */
function CNum(oNumbering, sAbstractNumId)
{
	this.Id = AscCommon.g_oIdCounter.Get_NewId();

	this.Lock = new AscCommon.CLock();
	if (!AscCommon.g_oIdCounter.m_bLoad)
	{
		this.Lock.Set_Type(AscCommon.locktype_Mine, false);
		if (typeof AscCommon.CollaborativeEditing !== "undefined")
			AscCommon.CollaborativeEditing.Add_Unlock2(this);
	}

	this.AbstractNumId = sAbstractNumId ? sAbstractNumId : null;
	this.LvlOverride   = [];
	this.Numbering     = oNumbering;

	// Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
	AscCommon.g_oTableId.Add(this, this.Id);
}
CNum.prototype.Get_Id = function()
{
	return this.Id;
};
/**
 * Идентификатор данного объекта
 * @returns {string}
 */
CNum.prototype.GetId = function()
{
	return this.Id;
};
/**
 * Создаем копию данной нумерации
 * @returns {CNum}
 */
CNum.prototype.Copy = function()
{
	var oNum = this.Numbering.CreateNum();

	var oNewAbstractNum = this.Numbering.GetAbstractNum(oNum.AbstractNumId);
	var oAbstractNum    = this.Numbering.GetAbstractNum(this.AbstractNumId);

	if (oAbstractNum && oNewAbstractNum)
		oNewAbstractNum.Copy(oAbstractNum);

	for (var nLvl = 0; nLvl < 9; ++nLvl)
	{
		if (this.LvlOverride[nLvl])
			oNum.SetLvlOverride(this.LvlOverride[nLvl].GetLvl().Copy(), nLvl, this.LvlOverride[nLvl].GetStartOverride());
	}

	return oNum;
};
/**
 * Получаем заданный уровень
 * @param nLvl {number} 0..8
 * @returns {CNumberingLvl}
 */
CNum.prototype.GetLvl = function(nLvl)
{
	if (this.private_HaveLvlOverride(nLvl))
		return this.LvlOverride[nLvl].GetLvl();

	var oAbstractNum = this.Numbering.GetAbstractNum(this.AbstractNumId);
	if (!oAbstractNum)
		return new CNumberingLvl();

	return oAbstractNum.GetLvl(nLvl);
};
/**
 * Создаем многоуровневый список с заданным пресетом
 * @param nType {c_oAscMultiLevelNumbering}
 */
CNum.prototype.CreateDefault = function(nType)
{
	var oAbstractNum = this.Numbering.GetAbstractNum(this.AbstractNumId);
	if (!oAbstractNum)
		return;

	oAbstractNum.CreateDefault(nType);
	this.ClearAllLvlOverride();
};
/**
 * Задаем новый уровень нумерации
 * @param oNumberingLvl {CNumberingLvl}
 * @param nLvl {number} 0..8
 */
CNum.prototype.SetLvl = function(oNumberingLvl, nLvl)
{
	if ("number" !== typeof(nLvl) || nLvl < 0 || nLvl >= 9)
		return;

	if (this.private_HaveLvlOverride(nLvl))
	{
		this.SetLvlOverride(oNumberingLvl, nLvl);
	}
	else
	{
		var oAbstractNum = this.Numbering.GetAbstractNum(this.AbstractNumId);
		if (!oAbstractNum)
			return;

		oAbstractNum.SetLvl(nLvl, oNumberingLvl);
	}
};
/**
 * Делаем заданный уровень заданного пресета
 * @param nLvl {number} 0..8
 * @param nType {c_oAscNumberingLevel}
 * @param [sText=undefined] Используется для типа c_oAscNumberingLevel.Bullet
 * @param [oTextPr=undefined] {CTextPr} Используется для типа c_oAscNumberingLevel.Bullet
 */
CNum.prototype.SetLvlByType = function(nLvl, nType, sText, oTextPr)
{
	if ("number" !== typeof(nLvl) || nLvl < 0 || nLvl >= 9)
		return;

	if (this.private_HaveLvlOverride(nLvl))
	{
		var oNumberingLvl = new CNumberingLvl();
		oNumberingLvl.SetByType(nType, nLvl, sText, oTextPr);

		this.SetLvlOverride(oNumberingLvl, nLvl);
	}
	else
	{
		var oAbstractNum = this.Numbering.GetAbstractNum(this.AbstractNumId);
		if (!oAbstractNum)
			return;

		oAbstractNum.SetLvlByType(nLvl, nType, sText, oTextPr);
	}
};
/**
 * Заполняем уровень по заданному формату
 * @param nLvl {number} 0..8
 * @param nType
 * @param sFormatText
 * @param nAlign
 */
CNum.prototype.SetLvlByFormat = function(nLvl, nType, sFormatText, nAlign)
{
	if ("number" !== typeof(nLvl) || nLvl < 0 || nLvl >= 9)
		return;

	if (this.private_HaveLvlOverride(nLvl))
	{
		var oNumberingLvl = new CNumberingLvl();
		oNumberingLvl.SetByFormat(nLvl, nType, sFormatText, nAlign);

		this.SetLvlOverride(oNumberingLvl, nLvl);
	}
	else
	{
		var oAbstractNum = this.Numbering.GetAbstractNum(this.AbstractNumId);
		if (!oAbstractNum)
			return;

		oAbstractNum.SetLvlByFormat(nLvl, nType, sFormatText, nAlign);
	}
};
/**
 * Выставляем является ли данный уровень сквозным или каждый раз перестартовывать нумерацию
 * @param nLvl {number} 0..8
 * @param isRestart {boolean}
 */
CNum.prototype.SetLvlRestart = function(nLvl, isRestart)
{
	if ("number" !== typeof(nLvl) || nLvl < 0 || nLvl >= 9)
		return;

	if (this.private_HaveLvlOverride(nLvl))
	{
		var oNumberingLvl        = this.LvlOverride[nLvl].GetLvl();
		var oNewNumberingLvl     = oNumberingLvl.Copy();
		oNewNumberingLvl.Restart = (isRestart ? -1 : 0);
		this.SetLvlOverride(oNewNumberingLvl, nLvl);
	}
	else
	{
		var oAbstractNum = this.Numbering.GetAbstractNum(this.AbstractNumId);
		if (!oAbstractNum)
			return;

		oAbstractNum.SetLvlRestart(nLvl, isRestart);
	}
};
/**
 * Задаем начальное значения для данного уровня
 * @param nLvl {number} 0..8
 * @param nStart {number}
 */
CNum.prototype.SetLvlStart = function(nLvl, nStart)
{
	if ("number" !== typeof(nLvl) || nLvl < 0 || nLvl >= 9)
		return;

	if (this.private_HaveLvlOverride(nLvl))
	{
		var oNumberingLvl      = this.LvlOverride[nLvl].GetLvl();
		var oNewNumberingLvl   = oNumberingLvl.Copy();
		oNewNumberingLvl.Start = nStart;
		this.SetLvlOverride(oNewNumberingLvl, nLvl);
	}
	else
	{
		var oAbstractNum = this.Numbering.GetAbstractNum(this.AbstractNumId);
		if (!oAbstractNum)
			return;

		oAbstractNum.SetLvlStart(nLvl, nStart);
	}
};
/**
 * Выставляем тип разделителя между табом и последующим текстом
 * @param nLvl {number} 0..8
 * @param nSuff {number}
 */
CNum.prototype.SetLvlSuff = function(nLvl, nSuff)
{
	if ("number" !== typeof(nLvl) || nLvl < 0 || nLvl >= 9)
		return;

	if (this.private_HaveLvlOverride(nLvl))
	{
		var oNumberingLvl     = this.LvlOverride[nLvl].GetLvl();
		var oNewNumberingLvl  = oNumberingLvl.Copy();
		oNewNumberingLvl.Suff = nSuff;
		this.SetLvlOverride(oNewNumberingLvl, nLvl);
	}
	else
	{
		var oAbstractNum = this.Numbering.GetAbstractNum(this.AbstractNumId);
		if (!oAbstractNum)
			return;

		oAbstractNum.SetLvlSuff(nLvl, nSuff);
	}
};
/**
 * Устанавливаем новый уровень
 * @param oNumberingLvl {CNumberingLvl}
 * @param nLvl {number} 0..8
 * @param [nStartOverride=-1]
 */
CNum.prototype.SetLvlOverride = function(oNumberingLvl, nLvl, nStartOverride)
{
	if (nLvl < 0 || nLvl > 8)
		return;

	if (!oNumberingLvl && !this.LvlOverride[nLvl] && (-1 === nStartOverride || undefined == nStartOverride))
		return;

	var oLvlOverrideOld = this.LvlOverride[nLvl];
	var oLvlOverrideNew = new CLvlOverride(oNumberingLvl, nLvl, nStartOverride);

	AscCommon.History.Add(new CChangesNumLvlOverrideChange(this, oLvlOverrideOld, oLvlOverrideNew, nLvl));

	this.LvlOverride[nLvl] = oLvlOverrideNew;
	this.RecalculateRelatedParagraphs(nLvl);
};
/**
 * Удаляем все записи о перекрывании уровней
 */
CNum.prototype.ClearAllLvlOverride = function()
{
	for (var nLvl = 0; nLvl < 9; ++nLvl)
	{
		this.SetLvlOverride(undefined, nLvl);
	}
};
/**
 * Изменяем базовую нумерацию
 * @param sId {string}
 */
CNum.prototype.SetAbstractNumId = function(sId)
{
	if (sId !== this.AbstractNumId)
	{
		AscCommon.History.Add(new CChangesNumAbstractNum(this, this.AbstractNumId, sId));
		this.AbstractNumId = sId;
		this.RecalculateRelatedParagraphs(-1);
	}
};
/**
 * Сообщаем, что параграфы связанные с заданным уровнем нужно пересчитать
 * @param nLvl {number} 0..8 - заданный уровен, если -1 то для всех уровней
 */
CNum.prototype.RecalculateRelatedParagraphs = function(nLvl)
{
	if (nLvl < 0 || nLvl > 8)
		nLvl = undefined;

	var oLogicDocument = editor.WordControl.m_oLogicDocument;
	//добавляю проверку - при чтении из бинарника oLogicDocument - это CPresentation(вставка de->pe)
	var arrParagraphs  = oLogicDocument.GetAllParagraphsByNumbering ? oLogicDocument.GetAllParagraphsByNumbering({NumId : this.Id, Lvl : nLvl}) : [];

	for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
	{
		arrParagraphs[nIndex].RecalcCompiledPr();
	}
};
/**
 * Применяем новые тектовые настройки к данной нумерации на заданном уровне
 * @param nLvl {number} 0..8
 * @param oTextPr {CTextPr}
 */
CNum.prototype.ApplyTextPr = function(nLvl, oTextPr)
{
	if (nLvl < 0 || nLvl > 8)
		return;

	if (this.private_HaveLvlOverride(nLvl))
	{
		var oNumberingLvl = this.LvlOverride[nLvl].GetLvl();
		var oNewNumberingLvl = oNumberingLvl.Copy();
		oNewNumberingLvl.TextPr.Merge(oTextPr());
		this.SetLvlOverride(oNewNumberingLvl, nLvl);
	}
	else
	{
		var oAbstractNum = this.Numbering.GetAbstractNum(this.AbstractNumId);
		if (!oAbstractNum)
			return;

		oAbstractNum.ApplyTextPr(nLvl, oTextPr);
	}
};
/**
 * Сдвигаем все уровни на заданное значение (оно задается для нулевого уровня)
 * @param nLeftNew {number}
 */
CNum.prototype.ShiftLeftInd = function(nLeftNew)
{
	var oFirstLevel = this.GetLvl(0);
	var nLeftOld    = oFirstLevel.ParaPr.Ind.Left ? oFirstLevel.ParaPr.Ind.Left : 0;

	for (var nLvl = 0; nLvl < 9; ++nLvl)
	{
		var oLvlOld = this.GetLvl(nLvl);
		var oLvlNew = this.GetLvl(nLvl).Copy();

		oLvlNew.ParaPr.Ind.Left = oLvlOld.ParaPr.Ind.Left ? oLvlOld.ParaPr.Ind.Left - nLeftOld + nLeftNew : nLeftNew - nLeftOld;

		this.SetLvl(oLvlNew, nLvl);
	}
};
/**
 * Получаем Id NumStyleLink
 * @returns {null | string}
 */
CNum.prototype.GetNumStyleLink = function()
{
	var oAbstractNum = this.Numbering.GetAbstractNum(this.AbstractNumId);
	if (!oAbstractNum)
		return null;

	return oAbstractNum.GetNumStyleLink();
};
/**
 * Получаем Id StyleLink
 * @returns {null | string}
 */
CNum.prototype.GetStyleLink = function()
{
	var oAbstractNum = this.Numbering.GetAbstractNum(this.AbstractNumId);
	if (!oAbstractNum)
		return null;

	return oAbstractNum.GetStyleLink();
};
/**
 * Получаем уровень списка по заданном стилю
 * @param sStyleId {string}
 * @returns {number}
 */
CNum.prototype.GetLvlByStyle = function(sStyleId)
{
	for (var nLvl = 0; nLvl < 9; ++nLvl)
	{
		var oLvl = this.GetLvl(nLvl);
		if (oLvl && sStyleId === oLvl.GetPStyle())
			return nLvl;
	}

	return -1;
};
/**
 * Получаем нумерованное значение для заданного уровня с учетом заданого сдвига и формата данного уровня
 * @param nLvl {number} 0..8
 * @param nNumShift {number}
 */
CNum.prototype.private_GetNumberedLvlText = function(nLvl, nNumShift)
{
	var sResult = "";

	var oLvl = this.GetLvl(nLvl);
	switch (oLvl.GetFormat())
	{
		case Asc.c_oAscNumberingFormat.Bullet:
		{
			break;
		}

		case Asc.c_oAscNumberingFormat.Decimal:
		{
			sResult = "" + nNumShift;
			break;
		}

		case Asc.c_oAscNumberingFormat.DecimalZero:
		{
			sResult = "" + nNumShift;

			if (1 === sResult.length)
				sResult = "0" + sResult;
			break;
		}

		case Asc.c_oAscNumberingFormat.LowerLetter:
		case Asc.c_oAscNumberingFormat.UpperLetter:
		{
			// Формат: a,..,z,aa,..,zz,aaa,...,zzz,...
			var Num = nNumShift - 1;

			var Count = (Num - Num % 26) / 26;
			var Ost   = Num % 26;

			var Letter;
			if (Asc.c_oAscNumberingFormat.LowerLetter === oLvl.GetFormat())
				Letter = String.fromCharCode(Ost + 97);
			else
				Letter = String.fromCharCode(Ost + 65);

			for (var nIndex = 0; nIndex < Count + 1; ++nIndex)
				sResult += Letter;

			break;
		}

		case Asc.c_oAscNumberingFormat.LowerRoman:
		case Asc.c_oAscNumberingFormat.UpperRoman:
		{
			var Num = nNumShift;

			// Переводим число Num в римскую систему исчисления
			var Rims;

			if (Asc.c_oAscNumberingFormat.LowerRoman === oLvl.GetFormat())
				Rims = ['m', 'cm', 'd', 'cd', 'c', 'xc', 'l', 'xl', 'x', 'ix', 'v', 'iv', 'i', ' '];
			else
				Rims = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I', ' '];

			var Vals = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1, 0];

			var nIndex = 0;
			while (Num > 0)
			{
				while (Vals[nIndex] <= Num)
				{
					sResult += Rims[nIndex];
					Num -= Vals[nIndex];
				}

				nIndex++;

				if (nIndex >= Rims.length)
					break;
			}
			break;
		}
	}

	return sResult;
};
/**
 * Функция отрисовки заданного уровня нумерации в заданной позиции
 * @param nX
 * @param nY
 * @param oContext
 * @param nLvl
 * @param oNumInfo
 * @param oNumTextPr
 * @param oTheme
 */
CNum.prototype.Draw = function(nX, nY, oContext, nLvl, oNumInfo, oNumTextPr, oTheme)
{
	var oLvl    = this.GetLvl(nLvl);
	var arrText = oLvl.GetLvlText();

	oContext.SetTextPr(oNumTextPr, oTheme);
	oContext.SetFontSlot(fontslot_ASCII);
	g_oTextMeasurer.SetTextPr(oNumTextPr, oTheme);
	g_oTextMeasurer.SetFontSlot(fontslot_ASCII);

	for (var nTextIndex = 0, nTextLen = arrText.length; nTextIndex < nTextLen; ++nTextIndex)
	{
		switch (arrText[nTextIndex].Type)
		{
			case numbering_lvltext_Text:
			{
				var Hint = oNumTextPr.RFonts.Hint;
				var bCS  = oNumTextPr.CS;
				var bRTL = oNumTextPr.RTL;
				var lcid = oNumTextPr.Lang.EastAsia;

				var FontSlot = g_font_detector.Get_FontClass(arrText[nTextIndex].Value.charCodeAt(0), Hint, lcid, bCS, bRTL);

				oContext.SetFontSlot(FontSlot);
				g_oTextMeasurer.SetFontSlot(FontSlot);

				oContext.FillText(nX, nY, arrText[nTextIndex].Value);
				nX += g_oTextMeasurer.Measure(arrText[nTextIndex].Value).Width;

				break;
			}
			case numbering_lvltext_Num:
			{
				oContext.SetFontSlot(fontslot_ASCII);
				g_oTextMeasurer.SetFontSlot(fontslot_ASCII);

				var nCurLvl = arrText[nTextIndex].Value;
				var T = "";

				if (nCurLvl < oNumInfo.length)
					T = this.private_GetNumberedLvlText(nCurLvl, oNumInfo[nCurLvl]);

				for (var Index2 = 0; Index2 < T.length; Index2++)
				{
					var Char = T.charAt(Index2);
					oContext.FillText(nX, nY, Char);
					nX += g_oTextMeasurer.Measure(Char).Width;
				}

				break;
			}
		}
	}
};
/**
 * Функция пересчета заданного уровня нумерации
 * @param oContext
 * @param nLvl
 * @param oNumInfo
 * @param oNumTextPr
 * @param oTheme
 * @returns {{Width : number, Ascent : number}}
 */
CNum.prototype.Measure = function(oContext, nLvl, oNumInfo, oNumTextPr, oTheme)
{
	var nX = 0;

	var oLvl    = this.GetLvl(nLvl);
	var arrText = oLvl.GetLvlText();

	oContext.SetTextPr(oNumTextPr, oTheme);
	oContext.SetFontSlot(fontslot_ASCII);
	var nAscent = oContext.GetAscender();

	for (var nTextIndex = 0, nTextLen = arrText.length; nTextIndex < nTextLen; ++nTextIndex)
	{
		switch (arrText[nTextIndex].Type)
		{
			case numbering_lvltext_Text:
			{
				var Hint = oNumTextPr.RFonts.Hint;
				var bCS  = oNumTextPr.CS;
				var bRTL = oNumTextPr.RTL;
				var lcid = oNumTextPr.Lang.EastAsia;

				var FontSlot = g_font_detector.Get_FontClass(arrText[nTextIndex].Value.charCodeAt(0), Hint, lcid, bCS, bRTL);

				oContext.SetFontSlot(FontSlot);
				nX += oContext.Measure(arrText[nTextIndex].Value).Width;

				break;
			}
			case numbering_lvltext_Num:
			{
				oContext.SetFontSlot(fontslot_ASCII);
				var nCurLvl = arrText[nTextIndex].Value;

				var T = "";

				if (nCurLvl < oNumInfo.length)
					T = this.private_GetNumberedLvlText(nCurLvl, oNumInfo[nCurLvl]);

				for (var Index2 = 0; Index2 < T.length; Index2++)
				{
					var Char = T.charAt(Index2);
					nX += oContext.Measure(Char).Width;
				}

				break;
			}
		}
	}

	return {
		Width  : nX,
		Ascent : nAscent
	};
};
/**
 * Составляем список всех используемых символов
 * @param oFontCharMap
 * @param nLvl {number} 0..8
 * @param oNumInfo
 * @param oNumTextPr {CTextPr}
 */
CNum.prototype.CreateFontCharMap = function(oFontCharMap, nLvl, oNumInfo, oNumTextPr)
{
	oFontCharMap.StartFont(oNumTextPr.FontFamily.Name, oNumTextPr.Bold, oNumTextPr.Italic, oNumTextPr.FontSize);

	var arrText = this.GetLvl(nLvl).GetLvlText();
	for (var nIndex = 0, nCount = arrText.length; nIndex < nCount; ++nIndex)
	{
		switch (arrText[nIndex].Type)
		{
			case numbering_lvltext_Text:
			{
				oFontCharMap.AddChar(arrText[nIndex].Value);
				break;
			}
			case numbering_lvltext_Num:
			{
				var nCurLvl = arrText[nIndex].Value;

				var T = "";
				if (nCurLvl < oNumInfo.length)
					T = this.private_GetNumberedLvlText(nCurLvl, oNumInfo[nCurLvl]);

				for (var Index2 = 0; Index2 < T.length; Index2++)
				{
					var Char = T.charAt(Index2);
					oFontCharMap.AddChar(Char);
				}

				break;
			}
		}
	}
};
/**
 * Получаем список всех используемых шрифтов
 * @param arrAllFonts {array}
 */
CNum.prototype.GetAllFontNames = function(arrAllFonts)
{
	for (var nLvl = 0; nLvl < 9; ++nLvl)
	{
		var oLvl = this.GetLvl(nLvl);

		if (oLvl)
			oLvl.GetTextPr().GetAllFontNames(arrAllFonts);
	}
};
/**
 * Получаем текст нумерации для заданного уровня
 * @param nLvl {number} 0..8
 * @param oNumInfo
 * @returns {string}
 */
CNum.prototype.GetText = function(nLvl, oNumInfo)
{
	var oLvl    = this.GetLvl(nLvl);
	var arrText = oLvl.GetLvlText();

	var sResult = "";
	for (var Index = 0; Index < arrText.length; Index++)
	{
		switch (arrText[Index].Type)
		{
			case numbering_lvltext_Text:
			{
				sResult += arrText[Index].Value;
				break;
			}
			case numbering_lvltext_Num:
			{
				var nCurLvl = arrText[Index].Value;
				if (nCurLvl < oNumInfo.length)
					sResult += this.private_GetNumberedLvlText(nCurLvl, oNumInfo[nCurLvl]);

				break;
			}
		}
	}

	return sResult;
};
/**
 * Обрабатываем окончание загрузки изменений
 * @param oData
 */
CNum.prototype.Process_EndLoad = function(oData)
{
	if (undefined !== oData.Lvl)
		this.RecalculateRelatedParagraphs(oData.Lvl);
};
/**
 * Проверяем есть ли у нас LvlOverride с перезаписанным уровнем
 * @param nLvl {number} 0..8
 * @returns {boolean}
 */
CNum.prototype.private_HaveLvlOverride = function(nLvl)
{
	return !!(this.LvlOverride[nLvl] && this.LvlOverride[nLvl].GetLvl());
};
/**
 * Получаем связанную абстрактную нумерацию
 * @returns {CAbstractNum}
 */
CNum.prototype.GetAbstractNum = function()
{
	return this.Numbering.GetAbstractNum(this.AbstractNumId);
};
/**
 * Получаем идентификатор связанной абстрактной нумерации
 * @returns {string}
 */
CNum.prototype.GetAbstractNumId = function()
{
	return this.AbstractNumId;
};
/**
 * Получаем параметр StartOverride для заданного уровня
 * @param nLvl {number} 0..8
 * @returns {number} возвращаем -1, если данный параметр не задан
 */
CNum.prototype.GetStartOverride = function(nLvl)
{
	var oLvlOverride = this.LvlOverride[nLvl];
	if (!oLvlOverride)
		return -1;

	var nStartOverride = oLvlOverride.GetStartOverride();

	var oLvl = oLvlOverride.GetLvl();
	if (oLvl)
		nStartOverride = oLvl.GetStart();

	return nStartOverride;
};
/**
 * Проверяем есть ли у данной нумерации уровни с текстом, зависящим от других уровней
 * @returns {boolean}
 */
CNum.prototype.IsHaveRelatedLvlText = function()
{
	for (var nLvl = 0; nLvl < 9; ++nLvl)
	{
		var oLvl = this.GetLvl(nLvl);
		var arrLvlText = oLvl.GetLvlText();
		for (var nIndex = 0, nCount = arrLvlText.length; nIndex < nCount; ++nIndex)
		{
			var oLvlText = arrLvlText[nIndex];
			if (numbering_lvltext_Num === oLvlText.Type && nLvl !== oLvlText.Value)
				return true;
		}
	}

	return false;
};
/**
 * Выставляем текстовые настройки для заданного уровня
 * @param nLvl {number} 0..8
 * @param oTextPr {CTextPr}
 */
CNum.prototype.SetTextPr = function(nLvl, oTextPr)
{
	if (nLvl < 0 || nLvl > 8)
		return;

	if (this.private_HaveLvlOverride(nLvl))
	{
		var oNumberingLvl = this.LvlOverride[nLvl].GetLvl();
		var oNewNumberingLvl = oNumberingLvl.Copy();
		oNewNumberingLvl.TextPr = oTextPr;
		this.SetLvlOverride(oNewNumberingLvl, nLvl);
	}
	else
	{
		var oAbstractNum = this.Numbering.GetAbstractNum(this.AbstractNumId);
		if (!oAbstractNum)
			return;

		oAbstractNum.SetTextPr(nLvl, oTextPr);
	}
};
/**
 * Выставляем настройки параграфа для заданного уровня
 * @param nLvl {number} 0..8
 * @param oParaPr {CParaPr}
 */
CNum.prototype.SetParaPr = function(nLvl, oParaPr)
{
	if (nLvl < 0 || nLvl > 8)
		return;

	if (this.private_HaveLvlOverride(nLvl))
	{
		var oNumberingLvl = this.LvlOverride[nLvl].GetLvl();
		var oNewNumberingLvl = oNumberingLvl.Copy();
		oNewNumberingLvl.ParaPr = oParaPr;
		this.SetLvlOverride(oNewNumberingLvl, nLvl);
	}
	else
	{
		var oAbstractNum = this.Numbering.GetAbstractNum(this.AbstractNumId);
		if (!oAbstractNum)
			return;

		oAbstractNum.SetParaPr(nLvl, oParaPr);
	}
};
/**
 * Заполняем специальный класс для общения с интерфейсом
 * @param oAscNum {CAscNumbering}
 */
CNum.prototype.FillToAscNum = function(oAscNum)
{
	oAscNum.NumId = this.GetId();
	for (var nLvl = 0; nLvl < 9; ++nLvl)
	{
		var oLvl = this.GetLvl(nLvl);
		oLvl.FillToAscNumberingLvl(oAscNum.get_Lvl(nLvl));
	}
};
/**
 * Заполняем настройки нумерации из интерфейсного класса
 * @param oAscNum {CAscNumbering}
 */
CNum.prototype.FillFromAscNum = function(oAscNum)
{
	for (var nLvl = 0; nLvl < 9; ++nLvl)
	{
		var oLvl = new CNumberingLvl();
		var oAscLvl = oAscNum.get_Lvl(nLvl);
		oLvl.FillFromAscNumberingLvl(oAscLvl);
		this.SetLvl(oLvl, nLvl);
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Undo/Redo функции
//----------------------------------------------------------------------------------------------------------------------
CNum.prototype.Refresh_RecalcData = function(Data)
{
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с совместным редактирования
//----------------------------------------------------------------------------------------------------------------------
CNum.prototype.Write_ToBinary2 = function(oWriter)
{
	oWriter.WriteLong(AscDFH.historyitem_type_Num);

	// String          : Id
	// String          : AbstractNumId
	// Variable[9 Lvl] : LvlOverride

	oWriter.WriteString2(this.Id);
	oWriter.WriteString2(this.AbstractNumId);

	for (var nLvl = 0; nLvl < 9; ++nLvl)
	{
		if (this.LvlOverride[nLvl])
		{
			oWriter.WriteBool(true);
			this.LvlOverride[nLvl].WriteToBinary(oWriter);
		}
		else
		{
			oWriter.WriteBool(false);
		}
	}
};
CNum.prototype.Read_FromBinary2 = function(oReader)
{
	// String          : Id
	// String          : AbstractNumId
	// Variable[9 Lvl] : LvlOverride

	this.Id            = oReader.GetString2();
	this.AbstractNumId = oReader.GetString2();

	for (var nLvl = 0; nLvl < 9; ++nLvl)
	{
		if (oReader.GetBool())
		{
			this.LvlOverride[nLvl] = new CLvlOverride();
			this.LvlOverride[nLvl].ReadFromBinary();
		}
	}

	if (!this.Numbering)
		this.Numbering = editor.WordControl.m_oLogicDocument.GetNumbering();

	this.Numbering.AddNum(this);
};

/**
 * Класс реализующий замену уровня в нумерации CNum
 * @param oNumberingLvl {CNumberingLvl}
 * @param nLvl {number} 0..8
 * @param [nStartOverride=-1] {number}
 * @constructor
 */
function CLvlOverride(oNumberingLvl, nLvl, nStartOverride)
{
	this.NumberingLvl  = oNumberingLvl;
	this.Lvl           = nLvl;
	this.StartOverride = undefined !== nStartOverride ? nStartOverride : -1;
}
CLvlOverride.prototype.GetLvl = function()
{
	return this.NumberingLvl;
};
CLvlOverride.prototype.GetStartOverride = function()
{
	return this.StartOverride;
};
CLvlOverride.prototype.WriteToBinary = function(oWriter)
{
	// Long : Lvl
	// Long : StartOverride
	// bool : isUndefined NumberingLvl
	// false -> CNumberingLvl : NumberingLvl

	oWriter.WriteLong(this.Lvl);
	oWriter.WriteLong(this.StartOverride);

	if (this.NumberingLvl)
	{
		oWriter.WriteBool(false);
		this.NumberingLvl.WriteToBinary(oWriter);
	}
	else
	{
		oWriter.WriteBool(true);
	}
};
CLvlOverride.prototype.ReadFromBinary = function(oReader)
{
	// Long : Lvl
	// Long : StartOverride
	// bool : isUndefined NumberingLvl
	// false -> CNumberingLvl : NumberingLvl

	this.Lvl           = oReader.GetLong();
	this.StartOverride = oReader.GetLong();
	this.NumberingLvl  = undefined;

	if (!oReader.GetBool())
	{
		this.NumberingLvl = new CNumberingLvl();
		this.NumberingLvl.ReadFromBinary(oReader);
	}
};

//--------------------------------------------------------export--------------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CNum = CNum;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 14.05.2018
 * Time: 14:32
 */

AscDFH.changesFactory[AscDFH.historyitem_Num_LvlOverrideChange] = CChangesNumLvlOverrideChange;
AscDFH.changesFactory[AscDFH.historyitem_Num_AbstractNum]       = CChangesNumAbstractNum;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_Num_LvlOverrideChange] = [
	AscDFH.historyitem_Num_LvlOverrideChange
];

AscDFH.changesRelationMap[AscDFH.historyitem_Num_AbstractNum] = [
	AscDFH.historyitem_Num_AbstractNum
];
//----------------------------------------------------------------------------------------------------------------------

/**
 *
 * @param Class {CNum}
 * @param Old {?CLvlOverride}
 * @param New {?CLvlOverride}
 * @param nLvl {number} 0..8
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesNumLvlOverrideChange(Class, Old, New, nLvl)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);

	this.Lvl = nLvl;
}
CChangesNumLvlOverrideChange.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesNumLvlOverrideChange.prototype.constructor = CChangesNumLvlOverrideChange;
CChangesNumLvlOverrideChange.prototype.Type = AscDFH.historyitem_Num_LvlOverrideChange;
CChangesNumLvlOverrideChange.prototype.WriteToBinary = function(oWriter)
{
	// Long         : Lvl index
	// Long         : Flags
	// CLvlOverride : New
	// CLvlOverride : Old

	oWriter.WriteLong(this.Lvl);

	var nFlags = 0;

	if (undefined === this.New)
		nFlags |= 1;

	if (undefined === this.Old)
		nFlags |= 2;

	oWriter.WriteLong(nFlags);

	if (undefined !== this.New && this.New.WriteToBinary)
		this.New.WriteToBinary(oWriter);

	if (undefined !== this.Old && this.Old.WriteToBinary)
		this.Old.WriteToBinary(oWriter);
};
CChangesNumLvlOverrideChange.prototype.ReadFromBinary = function(oReader)
{
	// Long         : Lvl index
	// Long         : Flags
	// CLvlOverride : New
	// CLvlOverride : Old

	this.Lvl = oReader.GetLong();

	var nFlags = oReader.GetLong();

	if (nFlags & 1)
	{
		this.New = undefined;
	}
	else
	{
		this.New = new CLvlOverride();
		this.New.ReadFromBinary(oReader);
	}

	if (nFlags & 2)
	{
		this.Old = undefined;
	}
	else
	{
		this.Old = new CLvlOverride();
		this.Old.ReadFromBinary(oReader);
	}
};
CChangesNumLvlOverrideChange.prototype.private_SetValue = function(Value)
{
	var oNum = this.Class;
	oNum.LvlOverride[this.Lvl] = Value;
	oNum.RecalculateRelatedParagraphs(this.Lvl);
};
CChangesNumLvlOverrideChange.prototype.Load = function(Color)
{
	var oNum = this.Class;
	oNum.LvlOverride[this.Lvl] = this.New;

	// Сразу нельзя запускать пересчет, т.к. возможно еще не все ссылки проставлены
	AscCommon.CollaborativeEditing.Add_EndActions(this.Class, {Lvl : this.Lvl});
};
CChangesNumLvlOverrideChange.prototype.CreateReverseChange = function()
{
	return new CChangesNumLvlOverrideChange(this.Class, this.New, this.Old, this.Lvl);
};
CChangesNumLvlOverrideChange.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type)
		return false;

	return true;
};

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseStringProperty}
 */
function CChangesNumAbstractNum(Class, Old, New, Color)
{
	AscDFH.CChangesBaseStringProperty.call(this, Class, Old, New, Color);
}
CChangesNumAbstractNum.prototype = Object.create(AscDFH.CChangesBaseStringProperty.prototype);
CChangesNumAbstractNum.prototype.constructor = CChangesNumAbstractNum;
CChangesNumAbstractNum.prototype.Type = AscDFH.historyitem_Num_AbstractNum;
CChangesNumAbstractNum.prototype.private_SetValue = function(Value)
{
	this.Class.AbstractNumId = Value;
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 08.05.2018
 * Time: 15:52
 */

// Import
var g_oTextMeasurer = AscCommon.g_oTextMeasurer;
var History         = AscCommon.History;

var numbering_presentationnumfrmt_None          =     0;
var numbering_presentationnumfrmt_Char          =     1;
var numbering_presentationnumfrmt_ArabicPeriod  =   100;  // 1., 2., 3., ...
var numbering_presentationnumfrmt_ArabicParenR  =   101;  // 1), 2), 3), ...
var numbering_presentationnumfrmt_RomanUcPeriod =   102;  // I., II., III., ...
var numbering_presentationnumfrmt_RomanLcPeriod =   103;  // i., ii., iii., ...
var numbering_presentationnumfrmt_AlphaLcParenR =   104;  // a), b), c), ...
var numbering_presentationnumfrmt_AlphaLcPeriod =   105;  // a., b., c.,
var numbering_presentationnumfrmt_AlphaUcParenR =   106;  // A), B), C), ...
var numbering_presentationnumfrmt_AlphaUcPeriod =   107;  // A., B., C., ...


var g_NumberingArr = [];
g_NumberingArr[0] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[1] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[2] = numbering_presentationnumfrmt_AlphaLcPeriod;
g_NumberingArr[3] = numbering_presentationnumfrmt_AlphaUcParenR;
g_NumberingArr[4] = numbering_presentationnumfrmt_AlphaUcParenR;
g_NumberingArr[5] = numbering_presentationnumfrmt_AlphaUcPeriod;
g_NumberingArr[6] = numbering_presentationnumfrmt_ArabicPeriod;
g_NumberingArr[7] = numbering_presentationnumfrmt_ArabicPeriod;
g_NumberingArr[8] = numbering_presentationnumfrmt_ArabicPeriod;
g_NumberingArr[9] = numbering_presentationnumfrmt_ArabicPeriod;
g_NumberingArr[10] = numbering_presentationnumfrmt_ArabicParenR;
g_NumberingArr[11] = numbering_presentationnumfrmt_ArabicParenR;
g_NumberingArr[12] = numbering_presentationnumfrmt_ArabicPeriod;
g_NumberingArr[13] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[14] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[15] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[16] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[17] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[18] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[19] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[20] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[21] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[22] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[23] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[24] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[25] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[26] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[27] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[28] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[29] = numbering_presentationnumfrmt_RomanLcPeriod;
g_NumberingArr[30] = numbering_presentationnumfrmt_RomanLcPeriod;
g_NumberingArr[31] = numbering_presentationnumfrmt_RomanLcPeriod;
g_NumberingArr[32] = numbering_presentationnumfrmt_RomanUcPeriod;
g_NumberingArr[33] = numbering_presentationnumfrmt_RomanUcPeriod;
g_NumberingArr[34] = numbering_presentationnumfrmt_RomanUcPeriod;
g_NumberingArr[35] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[36] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[37] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[38] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[39] = numbering_presentationnumfrmt_AlphaLcParenR;
g_NumberingArr[40] = numbering_presentationnumfrmt_AlphaLcPeriod;

// Класс для работы с нумерацией в презентациях
function CPresentationBullet()
{
	this.m_nType    = numbering_presentationnumfrmt_None;  // Тип
	this.m_nStartAt = null;                                // Стартовое значение для нумерованных списков
	this.m_sChar    = null;                                // Значение для символьных списков

	this.m_oColor   = { r : 0, g : 0, b : 0, a: 255 };     // Цвет
	this.m_bColorTx = true;                                // Использовать ли цвет первого рана в параграфе
	this.Unifill    = null;

	this.m_sFont    = "Arial";                             // Шрифт
	this.m_bFontTx  = true;                                // Использовать ли шрифт первого рана в параграфе

	this.m_dSize    = 1;                                   // Размер шрифта, в пунктах или в процентах (зависит от флага m_bSizePct)
	this.m_bSizeTx  = false;                               // Использовать ли размер шрифта первого рана в параграфе
	this.m_bSizePct = true;                                // Задан ли размер шрифта в процентах

	this.m_oTextPr = null;
	this.m_nNum    = null;
	this.m_sString = null;
}

CPresentationBullet.prototype.Get_Type = function()
{
	return this.m_nType;
};
CPresentationBullet.prototype.Get_StartAt = function()
{
	return this.m_nStartAt;
};
CPresentationBullet.prototype.Measure = function(Context, FirstTextPr, _Num, Theme, ColorMap)
{
	var dFontSize = FirstTextPr.FontSize;
	if ( false === this.m_bSizeTx )
	{
		if ( true === this.m_bSizePct )
			dFontSize *= this.m_dSize;
		else
			dFontSize = this.m_dSize;
	}

	var RFonts;
	if(!this.m_bFontTx)
	{
		RFonts = {
			Ascii: {
				Name: this.m_sFont,
				Index: -1
			},
			EastAsia: {
				Name: this.m_sFont,
				Index: -1
			},
			CS: {
				Name: this.m_sFont,
				Index: -1
			},
			HAnsi: {
				Name: this.m_sFont,
				Index: -1
			}
		};
	}
	else
	{
		RFonts = FirstTextPr.RFonts;
	}


	var FirstTextPr_ = FirstTextPr.Copy();
	if(FirstTextPr_.Underline)
	{
		FirstTextPr_.Underline = false;
	}

	if ( true === this.m_bColorTx || !this.Unifill)
	{
		if(FirstTextPr.Unifill)
		{
			this.Unifill = FirstTextPr_.Unifill;
		}
		else
		{
			this.Unifill = AscFormat.CreteSolidFillRGB(FirstTextPr.Color.r, FirstTextPr.Color.g, FirstTextPr.Color.b);
		}
	}

	var TextPr_ = new CTextPr();
	TextPr_.Set_FromObject({
		RFonts: RFonts,
		Unifill: this.Unifill,
		FontSize : dFontSize,
		Bold     : ( this.m_nType >= numbering_presentationnumfrmt_ArabicPeriod ? FirstTextPr.Bold   : false ),
		Italic   : ( this.m_nType >= numbering_presentationnumfrmt_ArabicPeriod ? FirstTextPr.Italic : false )
	});
	FirstTextPr_.Merge(TextPr_);
	this.m_oTextPr = FirstTextPr_;

	var Num = _Num + this.m_nStartAt - 1;
	this.m_nNum = Num;

	var X = 0;




	var OldTextPr = Context.GetTextPr();


	var sT = "";

	switch ( this.m_nType )
	{
		case numbering_presentationnumfrmt_Char:
		{
			if ( null != this.m_sChar )
				sT = this.m_sChar;

			break;
		}

		case numbering_presentationnumfrmt_AlphaLcParenR:
		{
			sT = Numbering_Number_To_Alpha( Num, true ) + ")";
			break;
		}

		case numbering_presentationnumfrmt_AlphaLcPeriod:
		{
			sT = Numbering_Number_To_Alpha( Num, true ) + ".";
			break;
		}

		case numbering_presentationnumfrmt_AlphaUcParenR:
		{
			sT = Numbering_Number_To_Alpha( Num, false ) + ")";
			break;
		}

		case numbering_presentationnumfrmt_AlphaUcPeriod:
		{
			sT = Numbering_Number_To_Alpha( Num, false ) + ".";
			break;
		}

		case numbering_presentationnumfrmt_ArabicParenR:
		{
			sT += Numbering_Number_To_String(Num) + ")";
			break;
		}

		case numbering_presentationnumfrmt_ArabicPeriod:
		{
			sT += Numbering_Number_To_String(Num) + ".";
			break;
		}

		case numbering_presentationnumfrmt_RomanLcPeriod:
		{
			sT += Numbering_Number_To_Roman(Num, true) + ".";
			break;
		}

		case numbering_presentationnumfrmt_RomanUcPeriod:
		{
			sT += Numbering_Number_To_Roman(Num, false) + ".";
			break;
		}
	}

	this.m_sString = sT;

	var Hint =  this.m_oTextPr.RFonts.Hint;
	var bCS  =  this.m_oTextPr.CS;
	var bRTL =  this.m_oTextPr.RTL;
	var lcid =  this.m_oTextPr.Lang.EastAsia;

	var FontSlot = g_font_detector.Get_FontClass( sT.charCodeAt(0), Hint, lcid, bCS, bRTL );
	Context.SetTextPr( this.m_oTextPr, Theme );
	Context.SetFontSlot( FontSlot );
	for ( var Index2 = 0; Index2 < sT.length; Index2++ )
	{
		var Char = sT.charAt(Index2);
		X += Context.Measure( Char ).Width;
	}

	if(OldTextPr)
	{
		Context.SetTextPr( OldTextPr, Theme );
	}
	return { Width : X };
};
CPresentationBullet.prototype.Copy = function()
{
	var Bullet = new CPresentationBullet();

	Bullet.m_nType    = this.m_nType;
	Bullet.m_nStartAt = this.m_nStartAt;
	Bullet.m_sChar    = this.m_sChar;

	Bullet.m_oColor.r = this.m_oColor.r;
	Bullet.m_oColor.g = this.m_oColor.g;
	Bullet.m_oColor.b = this.m_oColor.b;
	Bullet.m_bColorTx = this.m_bColorTx;

	Bullet.m_sFont    = this.m_sFont;
	Bullet.m_bFontTx  = this.m_bFontTx;

	Bullet.m_dSize    = this.m_dSize;
	Bullet.m_bSizeTx  = this.m_bSizeTx;
	Bullet.m_bSizePct = this.m_bSizePct;

	return Bullet;
};
CPresentationBullet.prototype.Draw = function(X, Y, Context, FirstTextPr, PDSE)
{
	if ( null === this.m_oTextPr || null === this.m_nNum || null == this.m_sString || this.m_sString.length == 0)
		return;



	var OldTextPr  = Context.GetTextPr();
	var OldTextPr2 = g_oTextMeasurer.GetTextPr();

	var Hint =  this.m_oTextPr.RFonts.Hint;
	var bCS  =  this.m_oTextPr.CS;
	var bRTL =  this.m_oTextPr.RTL;
	var lcid =  this.m_oTextPr.Lang.EastAsia;

	var sT = this.m_sString;
	var FontSlot = g_font_detector.Get_FontClass( sT.charCodeAt(0), Hint, lcid, bCS, bRTL );

	if(this.m_oTextPr.Unifill){
		this.m_oTextPr.Unifill.check(PDSE.Theme, PDSE.ColorMap);
	}
	Context.SetTextPr( this.m_oTextPr, PDSE.Theme );
	Context.SetFontSlot( FontSlot );
	if(!Context.Start_Command){
		if(this.m_oTextPr.Unifill){
			var RGBA = this.m_oTextPr.Unifill.getRGBAColor();
			this.m_oColor.r = RGBA.R;
			this.m_oColor.g = RGBA.G;
			this.m_oColor.b = RGBA.B;
		}
		Context.p_color( this.m_oColor.r, this.m_oColor.g, this.m_oColor.b, 255 );
		Context.b_color1( this.m_oColor.r, this.m_oColor.g, this.m_oColor.b, 255 );
	}
	g_oTextMeasurer.SetTextPr( this.m_oTextPr, PDSE.Theme  );
	g_oTextMeasurer.SetFontSlot( FontSlot );


	for ( var Index2 = 0; Index2 < sT.length; Index2++ )
	{
		var Char = sT.charAt(Index2);
		Context.FillText( X, Y, Char );
		X += g_oTextMeasurer.Measure( Char ).Width;
	}

	if(OldTextPr)
	{
		Context.SetTextPr( OldTextPr, PDSE.Theme );
	}
	if(OldTextPr2)
	{
		g_oTextMeasurer.SetTextPr( OldTextPr2, PDSE.Theme  );
	}
};

//--------------------------------------------------------export--------------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].g_NumberingArr = g_NumberingArr;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 08.05.2018
 * Time: 15:08
 */

/**
 * Класс представляющий нумерацию в документе
 * @constructor
 */
function CNumbering()
{
	this.AbstractNum = {};
	this.Num         = {};
}

/**
 * Копируем все нумерации и абстрактные нумерации. Возвращаем новые объекты с мапом из старых Id в новые
 * @param oNumbering {CNumbering}
 * @returns {{AbstractNum: {}, AbstractMap: {}, Num: {}, NumMap: {}}}
 */
CNumbering.prototype.CopyAllNums = function(oNumbering)
{
	if (!oNumbering)
		oNumbering = this;

	var oAbstractMap     = {};
	var oNumMap          = {};
	var oNewAbstractNums = {};
	var oNewNums         = {}

	for (var sOldId in this.AbstractNum)
	{
		var oOldAbstractNum = this.AbstractNum[sOldId];
		var oNewAbstractNum = new CAbstractNum();

		var sNewId = oNewAbstractNum.GetId();
		oNewAbstractNum.Copy(oOldAbstractNum);

		oNewAbstractNums[sNewId] = oNewAbstractNum;
		oAbstractMap[sOldId]     = sNewId;
	}

	for (var sOldId in this.Num)
	{
		var oOldNum = this.Num[sOldId];
		var oNewNum = new CNum(oNumbering, oAbstractMap[oOldNum.AbstractNumId]);

		for (var nLvl = 0; nLvl < 9; ++nLvl)
		{
			if (oOldNum.LvlOverride[nLvl])
				oNewNum.SetLvlOverride(oOldNum.LvlOverride[nLvl].GetLvl().Copy(), nLvl, oOldNum.LvlOverride[nLvl].GetStartOverride());
		}

		var sNewId = oNewNum.GetId();

		oNewNums[sNewId] = oNewNum;
		oNumMap[sOldId]  = sNewId;
	}

	return {
		AbstractNum : oNewAbstractNums,
		AbstractMap : oAbstractMap,
		Num         : oNewNums,
		NumMap      : oNumMap
	};
};
/**
 * Удаляем все нумерации
 */
CNumbering.prototype.Clear = function()
{
	this.AbstractNum = {};
	this.Num         = {};
};
/**
 * Добавляем к текущим абстрактным нумеациям новые
 * @param oAbstractNums
 */
CNumbering.prototype.AppendAbstractNums = function(oAbstractNums)
{
	for (var sId in oAbstractNums)
	{
		if (undefined === this.AbstractNum[sId])
			this.AbstractNum[sId] = oAbstractNums[sId];
	}
};
/**
 * Добавляем к текущим нумеациям новые
 * @param oNums
 */
CNumbering.prototype.AppendNums = function(oNums)
{
	for (var sId in oNums)
	{
		if (undefined === this.Num[sId])
			this.Num[sId] = oNums[sId];
	}
};
/**
 * Создаем новую абстрактную нумерацию
 * @returns {CAbstractNum}
 */
CNumbering.prototype.CreateAbstractNum = function()
{
	var oAbstractNum                       = new CAbstractNum();
	this.AbstractNum[oAbstractNum.GetId()] = oAbstractNum;
	return oAbstractNum;
};
/**
 * Добавляем абстрактную нумерацию
 * @param oAbstractNum {CAbstractNum}
 * @returns {string} идентификатор нумерации
 */
CNumbering.prototype.AddAbstractNum = function(oAbstractNum)
{
	if (!(oAbstractNum instanceof CAbstractNum))
		return;

	var sId               = oAbstractNum.GetId();
	this.AbstractNum[sId] = oAbstractNum;

	return sId;
};
/**
 * Добавляем абстрактную нумерацию
 * @param oNum {CNum}
 * @returns {string} идентификатор нумерации
 */
CNumbering.prototype.AddNum = function(oNum)
{
	if (!(oNum instanceof CNum))
		return;

	var sNumId       = oNum.GetId();
	this.Num[sNumId] = oNum;

	return sNumId;
};
/**
 * Доступ к абстрактной нумерации по Id
 * @param sId
 * @returns {CAbstractNum}
 */
CNumbering.prototype.GetAbstractNum = function(sId)
{
	var oAbstractNum = this.AbstractNum[sId];
	if (oAbstractNum && oAbstractNum.GetNumStyleLink())
	{
		var oStyles   = editor.WordControl.m_oLogicDocument.GetStyles();
		var oNumStyle = oStyles.Get(oAbstractNum.GetNumStyleLink());

		if (oNumStyle && oNumStyle.ParaPr.NumPr && undefined !== oNumStyle.ParaPr.NumPr.NumId)
			return this.GetAbstractNum(oNumStyle.ParaPr.NumPr.NumId);
	}

	return oAbstractNum;
};
/**
 * Создаем новую нумерацию
 * @returns {CNum}
 */
CNumbering.prototype.CreateNum = function()
{
	var oAbstractNum = new CAbstractNum();
	this.AbstractNum[oAbstractNum.GetId()] = oAbstractNum;

	var oNum = new CNum(this, oAbstractNum.GetId());
	this.Num[oNum.GetId()] = oNum;

	return oNum;
};
/**
 * @param sId
 * @returns {CNum}
 */
CNumbering.prototype.GetNum = function(sId)
{
	if (this.Num[sId])
		return this.Num[sId];

	return null;
};
/**
 * Получаем настройки параграфа для заданного уровня заданной нумерации
 * @param sNumId {string}
 * @param nLvl {number} 0..8
 * @returns {CParaPr}
 */
CNumbering.prototype.GetParaPr = function(sNumId, nLvl)
{
	var oNum = this.GetNum(sNumId);
	if (oNum)
		return oNum.GetLvl(nLvl).GetParaPr();

	return new CParaPr();
};
/**
 * Получаем формат заданного уровня заданной нумерации
 * @param sNumId
 * @param nLvl
 * @returns {Asc.c_oAscNumberingFormat}
 */
CNumbering.prototype.GetNumFormat = function(sNumId, nLvl)
{
	var oNum = this.GetNum(sNumId);
	if (!oNum)
		return Asc.c_oAscNumberingFormat.Bullet;

	var oLvl = oNum.GetLvl(nLvl);
	if (!oLvl)
		return Asc.c_oAscNumberingFormat.Bullet;

	return oLvl.Format;
};
/**
 * Проверяем по типам Numbered и Bullet
 * @param sNumId {string}
 * @param nLvl {number}
 * @param nType {Asc.c_oAscNumberingFormat}
 * @returns {boolean}
 */
CNumbering.prototype.CheckFormat = function(sNumId, nLvl, nType)
{
	var nFormat = this.GetNumFormat(sNumId, nLvl);

	if ((Asc.c_oAscNumberingFormat.BulletFlag & nFormat && Asc.c_oAscNumberingFormat.BulletFlag & nType)
		|| (Asc.c_oAscNumberingFormat.NumberedFlag & nFormat && Asc.c_oAscNumberingFormat.NumberedFlag & nType))
		return true;

	return false;
};
CNumbering.prototype.Draw = function(sNumId, nLvl, nX, nY, oContext, oNumInfo, oTextPr, oTheme)
{
	var oNum = this.GetNum(sNumId);
	return oNum.Draw(nX, nY, oContext, nLvl, oNumInfo, oTextPr, oTheme);
};
CNumbering.prototype.Measure = function(sNumId, nLvl, oContext, oNumInfo, oTextPr, oTheme)
{
	var oNum = this.GetNum(sNumId);
	return oNum.Measure(oContext, nLvl, oNumInfo, oTextPr, oTheme);
};
/**
 * Получаем список всех символов используемых в заданном уровне заданной нумерации
 * @param oFontCharMap
 * @param oNumTextPr
 * @param oNumPr
 * @param oNumInfo
 */
CNumbering.prototype.CreateFontCharMap = function(oFontCharMap, oNumTextPr, oNumPr, oNumInfo)
{
	var oNum = this.GetNum(oNumPr.NumId);
	oNum.CreateFontCharMap(oFontCharMap, oNumPr.Lvl, oNumInfo, oNumTextPr);
};
/**
 * Получаем список всех используемых шрифтов
 * @param arrAllFonts {array}
 */
CNumbering.prototype.GetAllFontNames = function(arrAllFonts)
{
	for (var sNumId in this.Num)
	{
		var oNum = this.GetNum(sNumId);
		oNum.GetAllFontNames(arrAllFonts);
	}

	arrAllFonts["Symbol"]      = true;
	arrAllFonts["Courier New"] = true;
	arrAllFonts["Wingdings"]   = true;
};
/**
 * Получаем текст нумерации для заданного уровня
 * @param sNumId {string}
 * @param nLvl {number} 0..8
 * @param oNumInfo
 * @returns {string}
 */
CNumbering.prototype.GetText = function(sNumId, nLvl, oNumInfo)
{
	var oNum = this.GetNum(sNumId);
	return oNum.GetText(nLvl, oNumInfo);
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var hdrftr_Header = AscCommon.hdrftr_Header;
var hdrftr_Footer = AscCommon.hdrftr_Footer;
var g_oTableId = AscCommon.g_oTableId;
var History = AscCommon.History;

//-----------------------------------------------------------------------------------
// Класс работающий с одним колонтитулом
//-----------------------------------------------------------------------------------
function CHeaderFooter(Parent, LogicDocument, DrawingDocument, Type)
{
    this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.Parent          = Parent;
    this.DrawingDocument = DrawingDocument;
    this.LogicDocument   = LogicDocument;

    // Содержимое колонтитула

    if ( "undefined" != typeof(LogicDocument) && null != LogicDocument )
    {
        if ( Type === hdrftr_Header )
        {
            this.Content = new CDocumentContent( this, DrawingDocument, 0, 0, 0, 0, false, true );
            this.Content.Content[0].Style_Add( this.Get_Styles().Get_Default_Header() );
        }
        else
        {
            this.Content = new CDocumentContent( this, DrawingDocument, 0, 0, 0, 0, false, true );
            this.Content.Content[0].Style_Add( this.Get_Styles().Get_Default_Footer() );
        }
    }

    this.Type = Type;

    this.RecalcInfo =
    {
        CurPage       : -1, // Текущий выставленный номер страницы
        RecalcObj     : {}, // Постраничные объекты пересчета данного колонтитула
        NeedRecalc    : {}, // Объект с ключом - номером страницы, нужно ли пересчитывать данную страницу
        PageNumInfo   : {}, // Объект с ключом - номером страницы, значением - информация о нумерации
        SectPr        : {}  // Объект с ключом - номером страницы и полем - ссылкой на секцию
    };

	this.PageCountElements = [];

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    g_oTableId.Add( this, this.Id );
}

CHeaderFooter.prototype =
{
    Get_Id : function()
    {
        return this.Id;
    },


    Get_Theme: function()
    {
        return this.LogicDocument.Get_Theme();
    },

    Get_ColorMap: function()
    {
        return this.LogicDocument.Get_ColorMap();
    },
    
    Copy : function()
    {
        var NewHdrFtr = new CHeaderFooter(this.Parent, this.LogicDocument, this.DrawingDocument, this.Type);
        NewHdrFtr.Content.Copy2( this.Content );
        return NewHdrFtr;
    },

    Set_Page : function(Page_abs)
    {
        if (Page_abs !== this.RecalcInfo.CurPage && undefined !== this.LogicDocument.Pages[Page_abs])
        {
            // Возможна ситуация, когда у нас колонтитул был рассчитан для заданной страницы, но на ней сейчас данный
            // колонтитул не используется. Запрещаем менять у данного колонтитула текущую страницу на заданную.
            var HdrFtrController = this.Parent;
            var HdrFtrPage = this.Parent.Pages[Page_abs];
            if ( undefined === HdrFtrPage || ( this !== HdrFtrPage.Header && this !== HdrFtrPage.Footer ) )
                return;
            
            var RecalcObj = this.RecalcInfo.RecalcObj[Page_abs];
            if ( undefined !== RecalcObj )
            {
                this.RecalcInfo.CurPage = Page_abs;
                this.Content.LoadRecalculateObject( RecalcObj );
            }            
        }        
    },

	Is_NeedRecalculate : function(PageAbs)
	{
		var PageNumInfo = this.LogicDocument.Get_SectionPageNumInfo(PageAbs);

		if (true !== this.RecalcInfo.NeedRecalc[PageAbs] && true === PageNumInfo.Compare(this.RecalcInfo.PageNumInfo[PageAbs]) && undefined !== this.RecalcInfo.RecalcObj[PageAbs])
			return false;

		return true;
	},

    Recalculate : function(Page_abs, SectPr)
    {
        // Логика пересчета колонтитулов следующая:
        // 1. При пересчете страницы каждый раз пересчитывается колонтитул (всмысле заходим в функцию Recalculate,т.е. сюда)
        // 2. Далее мы смотрим, нужно ли вообще пересчитывать данную страницу RecalcInfo.NeedRecalc[Page_abs] если это значение
        //    не false, тогда пересчитывать нужно, а если нет, тогда выходим
        // 3. Если нужно пересчитывать, пересчитываем заново и смотрим, изменились ли границы пересчета и позиции плавающих
        //    картинок, и выставляем RecalcInfo.NeedRecalc[Page_abs] = false.
        
        var bChanges = false;                
        var RecalcObj = this.RecalcInfo.RecalcObj[Page_abs];
        
        var OldSumH    = 0;
        var OldBounds  = null;
        var OldFlowPos = [];
            
        if ( undefined === RecalcObj )
            bChanges = true;
        else
        {
            OldSumH   = RecalcObj.GetSummaryHeight();
            OldBounds = RecalcObj.Get_PageBounds(0);
            RecalcObj.Get_DrawingFlowPos( OldFlowPos );
        }
        
        // Пересчитаем заново данный колонтитул        
        this.Content.Set_StartPage( Page_abs );
        this.Content.PrepareRecalculateObject();

		this.Clear_PageCountElements();

        var CurPage = 0;
        var RecalcResult = recalcresult2_NextPage;
        while ( recalcresult2_End != RecalcResult  )
            RecalcResult = this.Content.Recalculate_Page( CurPage++, true );
        
        this.RecalcInfo.RecalcObj[Page_abs]   = this.Content.SaveRecalculateObject();
        this.RecalcInfo.PageNumInfo[Page_abs] = this.LogicDocument.Get_SectionPageNumInfo(Page_abs);
        this.RecalcInfo.SectPr[Page_abs]      = SectPr;
		this.RecalcInfo.NeedRecalc[Page_abs]  = false;
        
        // Если у нас до этого был какой-то пересчет, тогда сравним его с текущим.
        // 1. Сравним границы: у верхнего колонтитула смотрим на изменение нижней границы, а нижнего - верхней
        // 2. Сравним положение и размер Flow-объектов

        if ( false === bChanges )
        {
            var NewBounds = this.Content.Get_PageBounds( 0 );
            if ( ( Math.abs(NewBounds.Bottom - OldBounds.Bottom) > 0.001 && hdrftr_Header === this.Type ) || ( Math.abs(NewBounds.Top - OldBounds.Top) > 0.001 && hdrftr_Footer === this.Type ) )
                bChanges = true;
        }

        if ( false === bChanges )
        {
            var NewFlowPos = [];
            var AllDrawingObjects = this.Content.GetAllDrawingObjects();
            var Count = AllDrawingObjects.length;

            for ( var Index = 0; Index < Count; Index++ )
            {
                var Obj = AllDrawingObjects[Index];
                if ( drawing_Anchor === Obj.Get_DrawingType() && true === Obj.Use_TextWrap() )
                {
                    var oDistance = Obj.Get_Distance();
                    var FlowPos =
                    {
                        X : Obj.X - oDistance.L,
                        Y : Obj.Y - oDistance.T,
                        W : Obj.Width + oDistance.R,
                        H : Obj.Height + oDistance.B
                    };

                    NewFlowPos.push( FlowPos );
                }
            }

            Count = NewFlowPos.length;
            if ( Count != OldFlowPos.length )
                bChanges = true;
            else
            {
                for ( var Index = 0; Index < Count; Index++ )
                {
                    var OldObj = OldFlowPos[Index];
                    var NewObj = NewFlowPos[Index];
                    if ( Math.abs(OldObj.X - NewObj.X) > 0.001 || Math.abs(OldObj.Y - NewObj.Y) > 0.001 || Math.abs(OldObj.H - NewObj.H) > 0.001 || Math.abs(OldObj.W - NewObj.W) > 0.001 )
                    {
                        bChanges = true;
                        break;
                    }
                }
            }
        }

        if ( false === bChanges )
        {
            var NewSumH = this.Content.GetSummaryHeight();
            if ( Math.abs( OldSumH - NewSumH ) > 0.001 )
                bChanges = true;
        }
        
        // Ежели текущая страница не задана, тогда выставляем ту, которая оказалась пересчитанной первой. В противном
        // случае, выставляем рассчет страницы, которая была до этого.
        if ( -1 === this.RecalcInfo.CurPage || false === this.LogicDocument.Get_SectionPageNumInfo(this.RecalcInfo.CurPage).Compare( this.RecalcInfo.PageNumInfo[this.RecalcInfo.CurPage] ) )
        {
            this.RecalcInfo.CurPage = Page_abs;
            
            if ( docpostype_HdrFtr === this.LogicDocument.Get_DocPosType() )
            {
                // Обновляем интерфейс, чтобы обновить настройки колонтитула, т.к. мы могли попасть в новую секцию
                this.LogicDocument.Document_UpdateSelectionState();
                this.LogicDocument.Document_UpdateInterfaceState();
            }
        }
        else            
        {
            var RecalcObj = this.RecalcInfo.RecalcObj[this.RecalcInfo.CurPage];
            this.Content.LoadRecalculateObject( RecalcObj );
        }

        return bChanges;
    },
    
    Recalculate2 : function(Page_abs)
    {
        this.Content.Set_StartPage( Page_abs );
        this.Content.PrepareRecalculateObject();

        var CurPage = 0;
        var RecalcResult = recalcresult2_NextPage;
        while ( recalcresult2_End != RecalcResult  )
            RecalcResult = this.Content.Recalculate_Page( CurPage++, true );
    },

    Reset_RecalculateCache : function()
    {
        this.Refresh_RecalcData2();
        this.Content.Reset_RecalculateCache();
    },

    Get_Styles : function()
    {
        return this.LogicDocument.Get_Styles();
    },

    Get_TableStyleForPara : function()
    {
        return null;
    },

    Get_ShapeStyleForPara: function()
    {
        return null;
    },


    Get_TextBackGroundColor : function()
    {
        return undefined;
    },

    Get_PageContentStartPos : function ()
    {
        return { X : this.Content.X, Y : 0, XLimit : this.Content.XLimit, YLimit : 0 };
    },

    Set_CurrentElement : function(bUpdateStates, PageAbs)
    {
        var PageIndex = -1;

        if (undefined !== PageAbs && null !== PageAbs && this.Parent.Pages[PageAbs])
		{
			if ((this === this.Parent.Pages[PageAbs].Header || this === this.Parent.Pages[PageAbs].Footer))
				PageIndex = PageAbs;
		}

		if (-1 === PageIndex)
		{
			for (var Key in this.Parent.Pages)
			{
				var PIndex = Key | 0;
				if ((this === this.Parent.Pages[PIndex].Header || this === this.Parent.Pages[PIndex].Footer) && (-1 === PageIndex || PageIndex > PIndex))
					PageIndex = PIndex;
			}
		}

        this.Parent.CurHdrFtr = this;
        this.Parent.WaitMouseDown = true;
        this.Parent.CurPage = PageIndex;

        if (-1 === PageIndex)
            this.RecalcInfo.CurPage = -1;

        var OldDocPosType = this.LogicDocument.Get_DocPosType();
        this.LogicDocument.Set_DocPosType(docpostype_HdrFtr);

        if (true === bUpdateStates && -1 !== PageIndex)
        {
            this.Set_Page(PageIndex);

            this.LogicDocument.Document_UpdateInterfaceState();
            this.LogicDocument.Document_UpdateRulersState();
            this.LogicDocument.Document_UpdateSelectionState();
        }

        if (docpostype_HdrFtr !== OldDocPosType)
        {
            this.DrawingDocument.ClearCachePages();
            this.DrawingDocument.FirePaint();
        }
    },

    Is_ThisElementCurrent : function()
    {
        if (this === this.Parent.CurHdrFtr && docpostype_HdrFtr === this.LogicDocument.Get_DocPosType())
            return true;

        return false;
    },

    Reset : function(X,Y, XLimit, YLimit)
    {
        this.Content.Reset( X, Y, XLimit, YLimit );
    },

    Draw : function(nPageIndex, pGraphics)
    {
        this.Content.Draw( nPageIndex, pGraphics );
    },

    // Пришло сообщение о том, что контент изменился и пересчитался
    OnContentRecalculate : function(bChange, bForceRecalc)
    {
        return;
    },

    OnContentReDraw : function(StartPage, EndPage)
    {
        this.DrawingDocument.ClearCachePages();
        this.DrawingDocument.FirePaint();
    },

    RecalculateCurPos : function()
    {
        if (-1 !== this.RecalcInfo.CurPage)
            return this.Content.RecalculateCurPos();

        this.DrawingDocument.UpdateTarget(0, 0, this.Content.Get_StartPage_Absolute());
        return null;
    },

    Get_NearestPos : function(X, Y, bAnchor, Drawing)
    {
        return this.Content.Get_NearestPos(0, X, Y, bAnchor, Drawing);
    },

    Get_Numbering : function()
    {
        return this.LogicDocument.Get_Numbering();
    },

    Get_Bounds : function()
    {
        return this.Content.Get_PageBounds(0);
    },
    
    Get_DividingLine : function(PageIndex)
    {
        var OldPage = this.RecalcInfo.CurPage;
        
        this.Set_Page( PageIndex );
        var Bounds = this.Get_Bounds();
        
        if ( -1 !== OldPage )
            this.Set_Page( OldPage );
        
        if ( hdrftr_Footer === this.Type )
            return Bounds.Top;
        else
            return Bounds.Bottom;
    },

    Is_PointInDrawingObjects : function(X, Y)
    {
        return this.Content.Is_PointInDrawingObjects( X, Y, this.Content.Get_StartPage_Absolute() );
    },

	Is_PointInFlowTable : function(X, Y)
	{
		return this.Content.Is_PointInFlowTable(X, Y, this.Content.Get_StartPage_Absolute());
	},

    CheckRange : function(X0, Y0, X1, Y1, _Y0, _Y1, X_lf, X_rf, bMathWrap)
    {
        return this.Content.CheckRange( X0, Y0, X1, Y1, _Y0, _Y1, X_lf, X_rf, 0, false, bMathWrap );
    },

    AddPageNum : function(Align)
    {
        var StyleId = null;
        if ( this.Type === hdrftr_Header )
            StyleId = this.Get_Styles().Get_Default_Header();
        else
            StyleId = this.Get_Styles().Get_Default_Footer();

        this.Content.HdrFtr_AddPageNum( Align, StyleId );
    },

    IsCell : function(isReturnCell)
    {
    	if (true === isReturnCell)
    		return null;

        return false;
    },

    Check_AutoFit : function()
    {
        return false;
    },

    IsHdrFtr : function(bReturnHdrFtr)
	{
		if (true === bReturnHdrFtr)
			return this;

		return true;
	},

	IsFootnote : function(bReturnFootnote)
	{
		return (bReturnFootnote ? null : false);
	},

    Get_ParentTextTransform : function()
    {
        return null;
    },

    Is_DrawingShape : function(bRetShape)
    {
        if(bRetShape === true)
        {
            return null;
        }
        return false;
    },

    Is_TopDocument : function(bReturnTopDocument)
    {
        if ( true === bReturnTopDocument )
            return this.Content;

        return true;
    },

    Is_InTable : function(bReturnTopTable)
    {
        if ( true === bReturnTopTable )
            return null;

        return false;
    },

	IsSelectionUse : function()
	{
		return this.Content.IsSelectionUse();
	},

	IsNumberingSelection : function()
	{
		return this.Content.IsNumberingSelection();
	},

	IsTextSelectionUse : function()
	{
		return this.Content.IsTextSelectionUse();
	},

    Is_UseInDocument : function(Id)
    {
        if ( null != this.Parent )
            return this.Parent.Is_UseInDocument(this.Get_Id());

        return false;
    },

    Check_Page : function(PageIndex)
    {
        return this.Parent.Check_Page( this, PageIndex );
    },

	GetCurPosXY : function()
	{
		return this.Content.GetCurPosXY();
	},

	GetSelectedText : function(bClearText, oPr)
	{
		return this.Content.GetSelectedText(bClearText, oPr);
	},

	GetSelectedElementsInfo : function(Info)
	{
		this.Content.GetSelectedElementsInfo(Info);
	},

	GetSelectedContent : function(SelectedContent)
	{
		this.Content.GetSelectedContent(SelectedContent);
	},

	UpdateCursorType : function(X, Y, PageAbs)
    {
        if (PageAbs != this.Content.Get_StartPage_Absolute())
            this.DrawingDocument.SetCursorType("text", new AscCommon.CMouseMoveData());
        else
            return this.Content.UpdateCursorType(X, Y, 0);
    },

	IsTableBorder : function(X, Y, PageAbs)
    {
        this.Set_Page(PageAbs);
        return this.Content.IsTableBorder(X, Y, 0);
    },

	IsInText : function(X, Y, PageAbs)
    {
        this.Set_Page(PageAbs);
        return this.Content.IsInText(X, Y, 0);
    },

	IsInDrawing : function(X, Y, PageAbs)
    {
        this.Set_Page(PageAbs);
        return this.Content.IsInDrawing(X, Y, 0);
    },

    Document_UpdateInterfaceState : function()
    {
        this.Content.Document_UpdateInterfaceState();
    },

    Document_UpdateRulersState : function()
    {
        if ( -1 === this.RecalcInfo.CurPage )
            return;
        
        var Index  = this.LogicDocument.Pages[this.RecalcInfo.CurPage].Pos; 
        var SectPr = this.LogicDocument.SectionsInfo.Get_SectPr(Index).SectPr;
        var Bounds = this.Get_Bounds();
        
        // нужно обновить линейку
        if ( this.Type === hdrftr_Header )
        {
            this.DrawingDocument.Set_RulerState_HdrFtr( true, Bounds.Top, Math.max( Bounds.Bottom, SectPr.Get_PageMargin_Top() ) );
        }
        else
        {
            this.DrawingDocument.Set_RulerState_HdrFtr( false, Bounds.Top, SectPr.Get_PageHeight() );
        }

        this.Content.Document_UpdateRulersState( this.Content.Get_StartPage_Absolute() );
    },

    Document_UpdateSelectionState : function()
    {
        if (-1 === this.RecalcInfo.CurPage)
        {
            // Если колонтитул не рассчитан, либо данный колонтитул неиспользуется, тогда смещаемся к первой странице
            this.DrawingDocument.TargetEnd();
            this.DrawingDocument.SelectEnabled(false);
            this.LogicDocument.NeedUpdateTarget = true;
            return;
        }

        if ( docpostype_DrawingObjects == this.Content.CurPos.Type )
        {
            return this.LogicDocument.DrawingObjects.documentUpdateSelectionState();
        }
        else //if ( docpostype_Content === this.Content.CurPos.Type )
        {
            // Если у нас есть выделение, тогда убираем курсор и рисуем выделение.
            // Если никакого выделения нет, тогда убираем его и восстанавливаем курсор.
            if ( true === this.Content.IsSelectionUse() )
            {
                // Выделение нумерации
                if ( selectionflag_Numbering == this.Content.Selection.Flag )
                {
                    this.DrawingDocument.TargetEnd();
                    this.DrawingDocument.SelectEnabled(true);
                    this.DrawingDocument.SelectClear();
                    this.DrawingDocument.SelectShow();
                }
                // Обрабатываем движение границы у таблиц
                else if ( null != this.Content.Selection.Data && true === this.Content.Selection.Data.TableBorder && type_Table == this.Content.Content[this.Content.Selection.Data.Pos].GetType() )
                {
                    // Убираем курсор, если он был
                    this.DrawingDocument.TargetEnd();
                }
                else
                {
                    if ( false === this.Content.IsSelectionEmpty() )
                    {
                        if (true !== this.Content.Selection.Start)
                            this.RecalculateCurPos();

                        this.DrawingDocument.TargetEnd();
                        this.DrawingDocument.SelectEnabled(true);
                        this.DrawingDocument.SelectClear();
                        this.DrawingDocument.SelectShow();
                    }
                    else
                    {
                        this.DrawingDocument.SelectEnabled(false);
                        this.RecalculateCurPos();

                        this.DrawingDocument.TargetStart();
                        this.DrawingDocument.TargetShow();
                    }
                }
            }
            else
            {
                this.DrawingDocument.SelectEnabled(false);
                this.RecalculateCurPos();

                this.DrawingDocument.TargetStart();
                this.DrawingDocument.TargetShow();
            }
        }
    },

//-----------------------------------------------------------------------------------
// Функции для работы с контентом
//-----------------------------------------------------------------------------------
	AddNewParagraph : function()
	{
		this.Content.AddNewParagraph();
	},

	AddInlineImage : function(W, H, Img, Chart, bFlow)
    {
        this.Content.AddInlineImage(W,H,Img, Chart, bFlow);
    },
	AddImages : function(aImages)
    {
        this.Content.AddImages(aImages);
    },
    AddSignatureLine : function(oSignatureDrawing)
    {
        this.Content.AddSignatureLine(oSignatureDrawing);
    },

	AddOleObject : function(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId)
    {
        this.Content.AddOleObject(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId);
    },

	AddTextArt : function(nStyle)
    {
        this.Content.AddTextArt(nStyle);
    },

	EditChart : function(Chart)
    {
        this.Content.EditChart( Chart );
    },

	AddInlineTable : function(Cols, Rows)
    {
        this.Content.AddInlineTable( Cols, Rows );
    },

	AddToParagraph : function(ParaItem, bRecalculate)
	{
		this.Content.AddToParagraph(ParaItem, bRecalculate);
	},

	ClearParagraphFormatting : function(isClearParaPr, isClearTextPr)
	{
		this.Content.ClearParagraphFormatting(isClearParaPr, isClearTextPr);
	},

	PasteFormatting : function(TextPr, ParaPr, ApplyPara)
	{
		this.Content.PasteFormatting(TextPr, ParaPr, ApplyPara);
	},

    Remove : function(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd)
    {
        this.Content.Remove(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd);
    },

	GetCursorPosXY : function()
	{
		return this.Content.GetCursorPosXY();
	},

	MoveCursorLeft : function(AddToSelect, Word)
	{
		var bRetValue = this.Content.MoveCursorLeft(AddToSelect, Word);

		this.Document_UpdateInterfaceState();
		this.Document_UpdateRulersState();

		return bRetValue;
	},

	MoveCursorRight : function(AddToSelect, Word)
	{
		var bRetValue = this.Content.MoveCursorRight(AddToSelect, Word);

		this.Document_UpdateInterfaceState();
		this.Document_UpdateRulersState();

		return bRetValue;
	},

	MoveCursorUp : function(AddToSelect)
	{
		var bRetValue = this.Content.MoveCursorUp(AddToSelect);

		this.Document_UpdateInterfaceState();
		this.Document_UpdateRulersState();

		return bRetValue;
	},

	MoveCursorDown : function(AddToSelect)
	{
		var bRetValue = this.Content.MoveCursorDown(AddToSelect);

		this.Document_UpdateInterfaceState();
		this.Document_UpdateRulersState();

		return bRetValue;
	},

	MoveCursorToEndOfLine : function(AddToSelect)
	{
		var bRetValue = this.Content.MoveCursorToEndOfLine(AddToSelect);

		this.Document_UpdateInterfaceState();
		this.Document_UpdateRulersState();

		return bRetValue;
	},

	MoveCursorToStartOfLine : function(AddToSelect)
	{
		var bRetValue = this.Content.MoveCursorToStartOfLine(AddToSelect);

		this.Document_UpdateInterfaceState();
		this.Document_UpdateRulersState();

		return bRetValue;
	},

	MoveCursorToStartPos : function(AddToSelect)
	{
		var bRetValue = this.Content.MoveCursorToStartPos(AddToSelect);

		this.Document_UpdateInterfaceState();
		this.Document_UpdateRulersState();

		return bRetValue;
	},

	MoveCursorToEndPos : function(AddToSelect)
	{
		var bRetValue = this.Content.MoveCursorToEndPos(AddToSelect);

		this.Document_UpdateInterfaceState();
		this.Document_UpdateRulersState();

		return bRetValue;
	},

	MoveCursorToXY : function(X, Y, PageIndex, AddToSelect, bRemoveOldSelection)
	{
		this.Set_Page(PageIndex);
		return this.Content.MoveCursorToXY(X, Y, AddToSelect, bRemoveOldSelection, PageIndex);
	},

	MoveCursorToCell : function(bNext)
	{
		this.Content.MoveCursorToCell(bNext);
	},

	SetParagraphAlign : function(Align)
	{
		return this.Content.SetParagraphAlign(Align);
	},

	SetParagraphSpacing : function(Spacing)
	{
		return this.Content.SetParagraphSpacing(Spacing);
	},

	SetParagraphIndent : function(Ind)
	{
		return this.Content.SetParagraphIndent(Ind);
	},

	SetParagraphShd : function(Shd)
	{
		return this.Content.SetParagraphShd(Shd);
	},

	SetParagraphStyle : function(Name)
	{
		return this.Content.SetParagraphStyle(Name);
	},

	SetParagraphTabs : function(Tabs)
	{
		return this.Content.SetParagraphTabs(Tabs);
	},

	SetParagraphContextualSpacing : function(Value)
	{
		return this.Content.SetParagraphContextualSpacing(Value);
	},

	SetParagraphPageBreakBefore : function(Value)
	{
		return this.Content.SetParagraphPageBreakBefore(Value);
	},

	SetParagraphKeepLines : function(Value)
	{
		return this.Content.SetParagraphKeepLines(Value);
	},

	SetParagraphKeepNext : function(Value)
	{
		return this.Content.SetParagraphKeepNext(Value);
	},

	SetParagraphWidowControl : function(Value)
	{
		return this.Content.SetParagraphWidowControl(Value);
	},

	SetParagraphBorders : function(Value)
	{
		return this.Content.SetParagraphBorders(Value);
	},

	IncreaseDecreaseFontSize : function(bIncrease)
	{
		return this.Content.IncreaseDecreaseFontSize(bIncrease);
	},

	IncreaseDecreaseIndent : function(bIncrease)
	{
		return this.Content.IncreaseDecreaseIndent(bIncrease);
	},

	SetImageProps : function(Props)
	{
		return this.Content.SetImageProps(Props);
	},

	SetTableProps : function(Props)
	{
		return this.Content.SetTableProps(Props);
	},

	GetCalculatedParaPr : function()
	{
		return this.Content.GetCalculatedParaPr();
	},

	GetCalculatedTextPr : function()
	{
		return this.Content.GetCalculatedTextPr();
	},

	GetDirectTextPr : function()
	{
		return this.Content.GetDirectTextPr();
	},

	GetDirectParaPr : function()
	{
		return this.Content.GetDirectParaPr();
	},

    GetAllParagraphs : function(Props, ParaArray)
    {
        return this.Content.GetAllParagraphs(Props, ParaArray);
    },

	GetAllDrawingObjects : function(arrDrawings)
	{
		return this.Content.GetAllDrawingObjects(arrDrawings);
	},

	GetPrevElementEndInfo : function(CurElement)
    {
        return null;
    },

	RemoveSelection : function(bNoCheckDrawing)
	{
		return this.Content.RemoveSelection(bNoCheckDrawing);
	},

	DrawSelectionOnPage : function(CurPage)
    {
        return this.Content.DrawSelectionOnPage(0, true, true);
    },

    Selection_SetStart : function(X,Y, PageIndex, MouseEvent)
    {
        this.Set_Page( PageIndex );

        if ( true === editor.isStartAddShape )
        {
            this.Content.Set_DocPosType(docpostype_DrawingObjects);
            this.Content.Selection.Use   = true;
            this.Content.Selection.Start = true;

            if ( true != this.LogicDocument.DrawingObjects.isPolylineAddition() )
                this.LogicDocument.DrawingObjects.startAddShape( editor.addShapePreset );

            this.LogicDocument.DrawingObjects.OnMouseDown(MouseEvent, X, Y, PageIndex);
        }
        else
		{
			return this.Content.Selection_SetStart(X, Y, 0, MouseEvent);
		}
    },

    Selection_SetEnd : function(X, Y, PageIndex, MouseEvent)
    {
        this.Set_Page( PageIndex );
        return this.Content.Selection_SetEnd(X, Y, 0, MouseEvent);
    },

	IsMovingTableBorder : function()
    {
        return this.Content.IsMovingTableBorder();
    },

	CheckPosInSelection : function(X, Y, PageAbs, NearPos)
	{
		if (-1 === this.RecalcInfo.CurPage)
			return false;

		var HdrFtrPage = this.Content.Get_StartPage_Absolute();
		if (undefined !== NearPos || HdrFtrPage === PageAbs)
			return this.Content.CheckPosInSelection(X, Y, 0, NearPos);

		return false;
	},

	SelectAll : function()
	{
		return this.Content.SelectAll();
	},

	GetCurrentParagraph : function(bIgnoreSelection, arrSelectedParagraphs)
	{
		return this.Content.GetCurrentParagraph(bIgnoreSelection, arrSelectedParagraphs);
	},

	StartSelectionFromCurPos : function()
	{
		this.Content.StartSelectionFromCurPos();
	},
//-----------------------------------------------------------------------------------
// Функции для работы с номерами страниц
//-----------------------------------------------------------------------------------
    Get_StartPage_Absolute : function()
    {
        return 0;
    },

    Get_StartPage_Relative : function()
    {
        return 0;
    },

    Get_AbsolutePage : function(CurPage)
    {
        return CurPage;
    },

    Get_AbsoluteColumn : function(CurPage)
    {
        return 0;
    },
//-----------------------------------------------------------------------------------
// Функции для работы с таблицами
//-----------------------------------------------------------------------------------
	AddTableRow : function(bBefore)
	{
		this.Content.AddTableRow(bBefore);
	},

	AddTableColumn : function(bBefore)
    {
        this.Content.AddTableColumn( bBefore );
    },

	RemoveTableRow : function()
	{
		this.Content.RemoveTableRow();
	},

	RemoveTableColumn : function()
	{
		this.Content.RemoveTableColumn();
	},

	MergeTableCells : function()
	{
		this.Content.MergeTableCells();
	},

	SplitTableCells : function(Cols, Rows)
	{
		this.Content.SplitTableCells(Cols, Rows);
	},

	RemoveTable : function()
	{
		this.Content.RemoveTable();
	},

	SelectTable : function(Type)
	{
		this.Content.SelectTable(Type);
	},

	CanMergeTableCells : function()
	{
		return this.Content.CanMergeTableCells();
	},

	CanSplitTableCells : function()
	{
		return this.Content.CanSplitTableCells();
	},

	CheckTableCoincidence : function(Table)
    {
        return false;
    },

	DistributeTableCells : function(isHorizontally)
	{
		return this.Content.DistributeTableCells(isHorizontally);
	},
//-----------------------------------------------------------------------------------
// Undo/Redo функции
//-----------------------------------------------------------------------------------    
    Get_ParentObject_or_DocumentPos : function()
    {
        return { Type : AscDFH.historyitem_recalctype_HdrFtr, Data : this };
    },

    Refresh_RecalcData : function(Data)
    {
        this.Refresh_RecalcData2();
    },

    Refresh_RecalcData2 : function()
    {
        // Сохраняем пересчитаные страницы в старый пересчет, а текущий обнуляем
        this.RecalcInfo.PageNumInfo = {};
        this.RecalcInfo.SectPr      = {};
        this.RecalcInfo.CurPage     = -1;
		this.RecalcInfo.NeedRecalc  = {};
        
        History.RecalcData_Add( { Type : AscDFH.historyitem_recalctype_HdrFtr, Data : this } );
    },
    
    Refresh_RecalcData_BySection : function(SectPr)
    {
        // Найдем среди пересчитанных страниц те, которые пересчитывались в заданной секции,
        // и среди них найдем ключ с наименьшим номером. Далее, отметим все страницы с номером большим, чем найденный,
        // как не пересчитанные.
        
        var MinPageIndex = -1;
        for ( var PageIndex in this.RecalcInfo.PageNumInfo )
        {
            if ( SectPr === this.RecalcInfo.SectPr[PageIndex] && ( -1 === MinPageIndex || PageIndex < MinPageIndex ) )
                MinPageIndex = PageIndex;                
        }
        
        for ( var PageIndex in this.RecalcInfo.PageNumInfo )
        {
            if ( PageIndex >= MinPageIndex )
            {
                delete this.RecalcInfo.PageNumInfo[PageIndex];
                delete this.RecalcInfo.SectPr[PageIndex];
				delete this.RecalcInfo.NeedRecalc[PageIndex];
            }
        }
    },
//-----------------------------------------------------------------------------------
// Функции для работы с гиперссылками
//-----------------------------------------------------------------------------------
	AddHyperlink : function(HyperProps)
	{
		this.Content.AddHyperlink(HyperProps);
	},

	ModifyHyperlink : function(HyperProps)
	{
		this.Content.ModifyHyperlink(HyperProps);
	},

	RemoveHyperlink : function()
	{
		this.Content.RemoveHyperlink();
	},

	CanAddHyperlink : function(bCheckInHyperlink)
	{
		return this.Content.CanAddHyperlink(bCheckInHyperlink);
	},

	IsCursorInHyperlink : function(bCheckEnd)
	{
		return this.Content.IsCursorInHyperlink(bCheckEnd);
	},
//-----------------------------------------------------------------------------------
// Функции для работы с генерацией карты шрифтов
//-----------------------------------------------------------------------------------
    Document_CreateFontMap : function(FontMap)
    {
        this.Content.Document_CreateFontMap(FontMap);
    },

    Document_CrateFontCharMap : function(FontCharMap)
    {
        this.Content.Document_CreateFontCharMap( FontCharMap );
    },

    Document_Get_AllFontNames : function(AllFonts)
    {
        this.Content.Document_Get_AllFontNames(AllFonts);
    },
//-----------------------------------------------------------------------------------
// Функции для работы с совместным редактирования
//-----------------------------------------------------------------------------------
    Write_ToBinary2 : function(Writer)
    {
        Writer.WriteLong( AscDFH.historyitem_type_HdrFtr );

        // String   : Id
        // Long     : Type
        // String   : Content Id

        Writer.WriteString2( this.Id );
        Writer.WriteLong( this.Type );
        Writer.WriteString2( this.Content.Get_Id() );
    },

    Read_FromBinary2 : function(Reader)
    {
        // String   : Id
        // Long     : Type
        // String   : Content Id

        var LogicDocument = editor.WordControl.m_oLogicDocument;

        this.Parent          = LogicDocument.HdrFtr;
        this.DrawingDocument = LogicDocument.DrawingDocument;
        this.LogicDocument   = LogicDocument;

        this.Id      = Reader.GetString2();
        this.Type    = Reader.GetLong();

        this.Content = g_oTableId.Get_ById( Reader.GetString2() );        
    },
//-----------------------------------------------------------------------------------
// Функции для работы с комментариями
//-----------------------------------------------------------------------------------
	AddComment : function(Comment)
	{
		this.Content.AddComment(Comment, true, true);
	},

	CanAddComment : function()
	{
		return this.Content.CanAddComment();
	}
};
CHeaderFooter.prototype.Get_SectPr = function()
{
    if (this.LogicDocument)
    {
        var SectionsInfo = this.LogicDocument.SectionsInfo;
        var Index = SectionsInfo.Find_ByHdrFtr(this);
        if (-1 !== Index)
            return SectionsInfo.Get_SectPr2(Index).SectPr;
    }

    return null;
};
CHeaderFooter.prototype.SetParagraphFramePr = function(FramePr, bDelete)
{
    return this.Content.SetParagraphFramePr(FramePr, bDelete);
};
CHeaderFooter.prototype.GetRevisionsChangeParagraph = function(SearchEngine)
{
    return this.Content.GetRevisionsChangeParagraph(SearchEngine);
};
CHeaderFooter.prototype.GetSelectionBounds = function()
{
	if (-1 !== this.RecalcInfo.CurPage)
		return this.Content.GetSelectionBounds();

	return null;
};
CHeaderFooter.prototype.Get_DocumentContent = function()
{
    return this.Content;
};
CHeaderFooter.prototype.Add_PageCountElement = function(oElement)
{
	for (var nIndex = 0, nCount = this.PageCountElements.length; nIndex < nCount; ++nIndex)
	{
		if (oElement == this.PageCountElements[nIndex])
			return;
	}

	this.PageCountElements.push(oElement);
};
CHeaderFooter.prototype.Have_PageCountElement = function()
{
	return this.PageCountElements.length > 0 ? true : false;
};
CHeaderFooter.prototype.Clear_PageCountElements = function()
{
	this.PageCountElements = [];
};
CHeaderFooter.prototype.Update_PageCountElements = function(nPageCount)
{
	for (var nIndex = 0, nCount = this.PageCountElements.length; nIndex < nCount; ++nIndex)
	{
		this.PageCountElements[nIndex].SetNumValue(nPageCount);
	}
};
CHeaderFooter.prototype.ForceRecalculate = function(nPageAbs)
{
	this.RecalcInfo.NeedRecalc[nPageAbs] = true;
};
CHeaderFooter.prototype.GetAllContentControls = function(arrContentControls)
{
	return this.Content.GetAllContentControls(arrContentControls);
};
/**
 * * Получаем класс, управляющий содержимым колонтитула
 * @returns {CDocumentContent}
 */
CHeaderFooter.prototype.GetContent = function()
{
	return this.Content;
};

//-----------------------------------------------------------------------------------
// Класс для работы с колонтитулами
//-----------------------------------------------------------------------------------
function CHeaderFooterController(LogicDocument, DrawingDocument)
{
    this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.DrawingDocument = DrawingDocument;
    this.LogicDocument   = LogicDocument;

    // Текущий колонтитул
    this.CurHdrFtr = null;

    this.Pages   = {};
    this.CurPage = 0;
    this.ChangeCurPageOnEnd = true;

    this.WaitMouseDown = true;

    this.Lock = new AscCommon.CLock();   

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    g_oTableId.Add( this, this.Id );
}

CHeaderFooterController.prototype =
{
    Get_Id : function()
    {
        return this.Id;
    },
//-----------------------------------------------------------------------------------
// Функции для работы с колонтитулами
//-----------------------------------------------------------------------------------        
    GoTo_NextHdrFtr : function()
    {
        var CurHdrFtr = this.CurHdrFtr;
        if (null === CurHdrFtr || -1 === CurHdrFtr.RecalcInfo.CurPage)
            return;

        var CurPage = CurHdrFtr.RecalcInfo.CurPage;
        var Pages = this.Pages;

        if (hdrftr_Header === CurHdrFtr.Type && undefined !== Pages[CurPage].Footer)
            CurHdrFtr = Pages[CurPage].Footer;
        else
            CurHdrFtr = null;

        while (null === CurHdrFtr)
        {
            CurPage++;

            if (undefined === Pages[CurPage])
                break;
            else if (undefined !== Pages[CurPage].Header && null !== Pages[CurPage].Header)
                CurHdrFtr = Pages[CurPage].Header;
            else if (undefined !== Pages[CurPage].Footer && null !== Pages[CurPage].Footer)
                CurHdrFtr = Pages[CurPage].Footer;
        }

        if (null !== CurHdrFtr)
        {
            this.CurHdrFtr = CurHdrFtr;
            CurHdrFtr.Set_Page(CurPage);
            CurHdrFtr.Content.MoveCursorToStartPos(false);

            return true;
        }
        
        return false;
    },
    
    GoTo_PrevHdrFtr : function()
    {
        var CurHdrFtr = this.CurHdrFtr;
        if (null === CurHdrFtr || -1 === CurHdrFtr.RecalcInfo.CurPage)
            return;
        
        var CurPage = CurHdrFtr.RecalcInfo.CurPage;
        var Pages = this.Pages;
        
        if (hdrftr_Footer === CurHdrFtr.Type && undefined !== Pages[CurPage].Header)
            CurHdrFtr = Pages[CurPage].Header;
        else
            CurHdrFtr = null;
        
        while (null === CurHdrFtr)
        {
            CurPage--;
            
            if (undefined === Pages[CurPage])
                return;
            else if (undefined !== Pages[CurPage].Footer && null !== Pages[CurPage].Footer)
                CurHdrFtr = Pages[CurPage].Footer;
            else if (undefined !== Pages[CurPage].Header && null !== Pages[CurPage].Header)
                CurHdrFtr = Pages[CurPage].Header;
        }
        
        if (null !== CurHdrFtr)
        {
            this.CurHdrFtr = CurHdrFtr;
            CurHdrFtr.Set_Page(CurPage);
            CurHdrFtr.Content.MoveCursorToStartPos(false);
            
            return true;
        }
        
        return false;
    },
    
    Get_CurPage : function()
    {
        if ( null != this.CurHdrFtr )
            return this.CurHdrFtr.Content.Get_StartPage_Absolute();

        return 0;
    },

    // Получаем своства колонтитула для интерфейса
    Get_Props : function()
    {
        if ( null != this.CurHdrFtr && -1 !== this.CurHdrFtr.RecalcInfo.CurPage )
        {
            var Pr = {};
            Pr.Type = this.CurHdrFtr.Type;
            
            if ( undefined === this.LogicDocument.Pages[this.CurHdrFtr.RecalcInfo.CurPage] )
                return Pr;
            
            var Index  = this.LogicDocument.Pages[this.CurHdrFtr.RecalcInfo.CurPage].Pos;            
            var SectPr = this.LogicDocument.SectionsInfo.Get_SectPr(Index).SectPr;

            if ( hdrftr_Footer === Pr.Type )
                Pr.Position = SectPr.Get_PageMargins_Footer();
            else
                Pr.Position = SectPr.Get_PageMargins_Header();
            
            Pr.DifferentFirst   = SectPr.Get_TitlePage();
            Pr.DifferentEvenOdd = EvenAndOddHeaders;
            
            if ( SectPr === this.LogicDocument.SectionsInfo.Get_SectPr2(0).SectPr )
            {
                // У первой секции не может быть повторяющихся колонтитулов. Посылаем особое значение (null) в меню
                Pr.LinkToPrevious = null;
            }
            else
            {
                // Определим тип колонтитула, в котором мы находимся
                var PageIndex = this.CurHdrFtr.RecalcInfo.CurPage;
                var SectionPageInfo = this.LogicDocument.Get_SectionPageNumInfo( PageIndex );

                var bFirst  = ( true === SectionPageInfo.bFirst && true === SectPr.Get_TitlePage() ? true : false );
                var bEven   = ( true === SectionPageInfo.bEven  && true === EvenAndOddHeaders      ? true : false );
                var bHeader = ( hdrftr_Header === this.CurHdrFtr.Type ? true : false );

                Pr.LinkToPrevious = ( null === SectPr.Get_HdrFtr( bHeader, bFirst, bEven ) ? true : false );
            }

            Pr.Locked = this.Lock.Is_Locked();

			Pr.StartPageNumber = SectPr.Get_PageNum_Start();

            return Pr;
        }
        else
            return null;
    },

    Set_CurHdrFtr_ById : function(Id)
    {
        var HdrFtr = g_oTableId.Get_ById( Id );
        if ( -1 === this.LogicDocument.SectionsInfo.Find_ByHdrFtr( HdrFtr ) )
            return false;
        
        this.CurHdrFtr = HdrFtr;
        HdrFtr.Content.MoveCursorToStartPos();
              
        return true;
    },
//-----------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------   
    RecalculateCurPos : function(bUpdateX, bUpdateY)
	{
		if (this.CurHdrFtr)
			return this.CurHdrFtr.RecalculateCurPos(bUpdateX, bUpdateY);

		return null;
	},

    Recalculate : function(PageIndex)
    {
        // Определим четность страницы и является ли она первой в данной секции. Заметим, что четность страницы 
        // отсчитывается от начала текущей секции и не зависит от настроек нумерации страниц для данной секции.
        var SectionPageInfo = this.LogicDocument.Get_SectionPageNumInfo( PageIndex );
        
        var bFirst = SectionPageInfo.bFirst;
        var bEven  = SectionPageInfo.bEven;
        
        // Запросим нужный нам колонтитул 
        var HdrFtr = this.LogicDocument.Get_SectionHdrFtr( PageIndex, bFirst, bEven );
        
        var Header = HdrFtr.Header;
        var Footer = HdrFtr.Footer;
        var SectPr = HdrFtr.SectPr;

        this.Pages[PageIndex] = new CHdrFtrPage();
        this.Pages[PageIndex].Header = Header;
        this.Pages[PageIndex].Footer = Footer;
        var X, XLimit;
        
        var X      = SectPr.Get_PageMargin_Left();
        var XLimit = SectPr.Get_PageWidth() - SectPr.Get_PageMargin_Right();
        
        var bRecalcHeader = false;

        var HeaderDrawings, HeaderTables, FooterDrawings, FooterTables;
        // Рассчитываем верхний колонтитул
        if ( null !== Header )
        {
            if ( true === Header.Is_NeedRecalculate( PageIndex ) )
            {
                var Y      = SectPr.Get_PageMargins_Header();
                var YLimit = SectPr.Get_PageHeight() / 2;

                Header.Reset( X, Y, XLimit, YLimit );
                bRecalcHeader = Header.Recalculate(PageIndex, SectPr);
            }
            else
            {
               if ( -1 === Header.RecalcInfo.CurPage )
                    Header.Set_Page(PageIndex);
            }
            HeaderDrawings = Header.Content.GetAllDrawingObjects([]);
            HeaderTables = Header.Content.GetAllFloatElements();
        }
        
        var bRecalcFooter = false;
        
        // Рассчитываем нижний колонтитул
        if ( null !== Footer )
        {
            if ( true === Footer.Is_NeedRecalculate( PageIndex ) )
            {
                // Нижний колонтитул рассчитываем 2 раза. Сначала, с 0 позиции, чтобы рассчитать суммарную высоту колонитула.
                // Исходя из уже известной высоты располагаем и рассчитываем колонтитул.

                var Y      = 0;
                var YLimit = SectPr.Get_PageHeight();

                Footer.Reset( X, Y, XLimit, YLimit );
                Footer.Recalculate2(PageIndex);

                var SummaryHeight = Footer.Content.GetSummaryHeight();
                Y = Math.max( 2 * YLimit / 3, YLimit - SectPr.Get_PageMargins_Footer() - SummaryHeight );

                Footer.Reset( X, Y, XLimit, YLimit );
                bRecalcFooter = Footer.Recalculate(PageIndex, SectPr);
            }
            else
            {
                if ( -1 === Footer.RecalcInfo.CurPage )
                    Footer.Set_Page(PageIndex);
            }
            FooterDrawings = Footer.Content.GetAllDrawingObjects([]);
            FooterTables = Footer.Content.GetAllFloatElements();
        }

        // Подправляем позиции автофигур с учетом возможно изменившихся границ колонтитулов. Делаем это для всех автофигур,
        // потому что колонтитулы рассчитываются первыми на странице и внутри них нет обтекания.
        var PageLimits = this.LogicDocument.Get_PageContentStartPos(PageIndex);
        this.private_UpdateDrawingVerticalPositions(HeaderDrawings, PageLimits.Y, PageLimits.YLimit);
        this.private_UpdateDrawingVerticalPositions(FooterDrawings, PageLimits.Y, PageLimits.YLimit);

        this.private_MergeFlowObjectsFromHeaderAndFooter(PageIndex, HeaderDrawings, HeaderTables, FooterDrawings, FooterTables);

        if ( true === bRecalcHeader || true === bRecalcFooter )
            return true;
        
        return false;
    },

    private_UpdateDrawingVerticalPositions : function(Drawings, HeaderY, FooterY)
    {
        if (Drawings)
        {
            for (var Index = 0, Count = Drawings.length; Index < Count; ++Index)
            {
                var Drawing = Drawings[Index];
                Drawing.Update_PositionYHeaderFooter(HeaderY, FooterY);
            }
        }
    },

    private_MergeFlowObjectsFromHeaderAndFooter : function(nPageIndex, arrHeaderDrawings, arrHeaderTables, arrFooterDrawings, arrFooterTables)
    {
        var oHeader = this.Pages[nPageIndex].Header;
        var oFooter = this.Pages[nPageIndex].Footer;

        var nOldHeaderCurPage = null;
        var nOldFooterCurPage = null;

        if (oHeader)
        {
            nOldHeaderCurPage = oHeader.RecalcInfo.CurPage;
            oHeader.Set_Page(nPageIndex);
        }

        if (oFooter)
        {
            nOldFooterCurPage = oFooter.RecalcInfo.CurPage;
            oFooter.Set_Page(nPageIndex);
        }

        this.LogicDocument.DrawingObjects.mergeDrawings(nPageIndex, arrHeaderDrawings, arrHeaderTables, arrFooterDrawings, arrFooterTables);

        if (null !== nOldHeaderCurPage)
            oHeader.Set_Page(nOldHeaderCurPage);

        if (null !== nOldFooterCurPage)
            oFooter.Set_Page(nOldFooterCurPage);
    },

    // Отрисовка колонтитулов на данной странице
    Draw : function(nPageIndex, pGraphics)
    {
        var oHeader = this.Pages[nPageIndex].Header;
        var oFooter = this.Pages[nPageIndex].Footer;

        var nOldHeaderCurPage = null;
        var nOldFooterCurPage = null;

        if (oHeader)
        {
            nOldHeaderCurPage = oHeader.RecalcInfo.CurPage;
            oHeader.Set_Page(nPageIndex);
        }

        if (oFooter)
        {
            nOldFooterCurPage = oFooter.RecalcInfo.CurPage;
            oFooter.Set_Page(nPageIndex);
        }

        this.LogicDocument.DrawingObjects.drawBehindDocHdrFtr(nPageIndex, pGraphics);

        if (oHeader)
            oHeader.Draw(nPageIndex, pGraphics);

        if (oFooter)
            oFooter.Draw(nPageIndex, pGraphics);

        this.LogicDocument.DrawingObjects.drawBeforeObjectsHdrFtr(nPageIndex, pGraphics);

        if (null !== nOldHeaderCurPage)
            oHeader.Set_Page(nOldHeaderCurPage);

        if (null !== nOldFooterCurPage)
            oFooter.Set_Page(nOldFooterCurPage);
    },

    CheckRange : function(X0, Y0, X1, Y1, _Y0, _Y1, X_lf, X_rf, PageIndex, bMathWrap)
    {
        if (undefined === this.Pages[PageIndex])
            return [];

        var Header = this.Pages[PageIndex].Header;
        var Footer = this.Pages[PageIndex].Footer;              

        var HeaderRange = [];
        var FooterRange = [];

        if ( null != Header )
            HeaderRange = Header.CheckRange( X0, Y0, X1, Y1, _Y0, _Y1, X_lf, X_rf, bMathWrap );

        if ( null != Footer )
            FooterRange = Footer.CheckRange( X0, Y0, X1, Y1, _Y0, _Y1, X_lf, X_rf, bMathWrap );

        return HeaderRange.concat( FooterRange );
    },

    // Запрашиваем низ у верхнего колонтитула для данной страницы
    Get_HdrFtrLines : function(PageIndex)
    {
        var Header = null;
        var Footer = null;
        
        if ( undefined !== this.Pages[PageIndex] )
        {
            Header = this.Pages[PageIndex].Header;
            Footer = this.Pages[PageIndex].Footer;
        }
        
        var Top = null; 
        if ( null !== Header )
            Top = Header.Get_DividingLine(PageIndex);
        
        var Bottom = null;
        if ( null !== Footer )
            Bottom = Footer.Get_DividingLine(PageIndex);
        
        return { Top : Top, Bottom : Bottom };
    },

	UpdateCursorType : function( X, Y, PageNum_Abs )
    {
        if ( true === this.Lock.Is_Locked() )
        {
            var PageLimits = this.LogicDocument.Get_PageContentStartPos( PageNum_Abs );

            var MMData_header = new AscCommon.CMouseMoveData();
            var Coords = this.DrawingDocument.ConvertCoordsToCursorWR( PageLimits.X, PageLimits.Y, PageNum_Abs );
            MMData_header.X_abs            = Coords.X;
            MMData_header.Y_abs            = Coords.Y + 2;
            MMData_header.Type             = AscCommon.c_oAscMouseMoveDataTypes.LockedObject;
            MMData_header.UserId           = this.Lock.Get_UserId();
            MMData_header.HaveChanges      = this.Lock.Have_Changes();
            MMData_header.LockedObjectType = c_oAscMouseMoveLockedObjectType.Header;
            editor.sync_MouseMoveCallback( MMData_header );

            var MMData_footer = new AscCommon.CMouseMoveData();
            Coords = this.DrawingDocument.ConvertCoordsToCursorWR( PageLimits.X, PageLimits.YLimit, PageNum_Abs );
            MMData_footer.X_abs            = Coords.X;
            MMData_footer.Y_abs            = Coords.Y - 2;
            MMData_footer.Type             = AscCommon.c_oAscMouseMoveDataTypes.LockedObject;
            MMData_footer.UserId           = this.Lock.Get_UserId();
            MMData_footer.HaveChanges      = this.Lock.Have_Changes();
            MMData_footer.LockedObjectType = c_oAscMouseMoveLockedObjectType.Footer;
            editor.sync_MouseMoveCallback( MMData_footer );
        }

        // TODO: Сделать выбор в зависимости колонтитула от номера страница PageNum_Abs
        if ( null != this.CurHdrFtr )
        {
            // Если мы попадаем в заселекченную автофигуру, пусть она даже выходит за пределы
            if ( true === this.LogicDocument.DrawingObjects.pointInSelectedObject(X, Y, PageNum_Abs) )
            {
                var NewPos = this.DrawingDocument.ConvertCoordsToAnotherPage(X, Y, PageNum_Abs, this.CurPage);
                var _X = NewPos.X;
                var _Y = NewPos.Y;
                return this.CurHdrFtr.UpdateCursorType( _X, _Y, this.CurPage );
            }
            else
                return this.CurHdrFtr.UpdateCursorType( X, Y, PageNum_Abs );
        }
    },

	IsTableBorder : function( X, Y, PageNum_Abs )
    {
        var HdrFtr = this.Internal_GetContentByXY( X, Y, PageNum_Abs );
        if ( null != HdrFtr )
            return HdrFtr.IsTableBorder( X, Y, PageNum_Abs );

        return null;
    },

	IsInText : function(X,Y, PageNum_Abs)
    {
        var HdrFtr = this.Internal_GetContentByXY( X, Y, PageNum_Abs );
        if ( null != HdrFtr )
            return HdrFtr.IsInText( X, Y, PageNum_Abs );

        return null;
    },

	IsInDrawing : function(X,Y, PageNum_Abs)
    {
        var HdrFtr = this.Internal_GetContentByXY( X, Y, PageNum_Abs );
        if ( null != HdrFtr )
            return HdrFtr.IsInDrawing( X, Y, PageNum_Abs );

        return null;
    },

    Document_UpdateInterfaceState : function()
    {
        if ( null != this.CurHdrFtr )
            this.CurHdrFtr.Document_UpdateInterfaceState();
    },

    Document_UpdateRulersState : function(CurPage)
    {
        if ( null != this.CurHdrFtr )
            this.CurHdrFtr.Document_UpdateRulersState(CurPage);
    },

    Document_UpdateSelectionState : function()
    {
        if (null != this.CurHdrFtr)
            this.CurHdrFtr.Document_UpdateSelectionState();
    },

	IsSelectionUse : function()
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.IsSelectionUse();

		return false;
	},

	IsNumberingSelection : function()
	{
		if (this.CurHdrFtr)
			return this.CurHdrFtr.IsNumberingSelection();

		return false;
	},

	IsTextSelectionUse : function()
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.IsTextSelectionUse();

		return false;
	},

	Is_UseInDocument : function(Id)
	{
		var HdrFtr = g_oTableId.Get_ById(Id);
		if (-1 === this.LogicDocument.SectionsInfo.Find_ByHdrFtr(HdrFtr))
			return false;

		return true;
	},

    Check_Page : function(HdrFtr, PageIndex)
    {
        var Header = this.Pages[PageIndex].Header;
        var Footer = this.Pages[PageIndex].Footer;

        if ( HdrFtr === Header || HdrFtr === Footer )
            return true;

        return false;
    },

	GetCurPosXY : function()
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.GetCurPosXY();

		return {X : 0, Y : 0};
	},

	GetSelectedText : function(bClearText, oPr)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.GetSelectedText(bClearText, oPr);

		return null;
	},

	GetSelectedElementsInfo : function(Info)
	{
		if (null != this.CurHdrFtr)
			this.CurHdrFtr.GetSelectedElementsInfo(Info);
	},

	GetSelectedContent : function(SelectedContent)
	{
		if (null != this.CurHdrFtr)
			this.CurHdrFtr.GetSelectedContent(SelectedContent);
	},
//-----------------------------------------------------------------------------------
// Функции для работы с контентом
//-----------------------------------------------------------------------------------
	AddNewParagraph : function()
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.AddNewParagraph();
	},

	AddInlineImage : function(W, H, Img, Chart, bFlow)
    {
        if ( null != this.CurHdrFtr )
            return this.CurHdrFtr.AddInlineImage(W,H,Img, Chart, bFlow);
    },
	AddImages : function(aImages)
    {
        if ( null != this.CurHdrFtr )
            return this.CurHdrFtr.AddImages(aImages);
    },
    AddSignatureLine : function(oSignatureDrawing)
    {
        if ( null != this.CurHdrFtr )
            return this.CurHdrFtr.AddSignatureLine(oSignatureDrawing);
    },

	AddOleObject: function(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId)
    {
        if ( null != this.CurHdrFtr )
            return this.CurHdrFtr.AddOleObject(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId);
    },

	AddTextArt : function(nStyle)
    {
        if ( null != this.CurHdrFtr )
            return this.CurHdrFtr.AddTextArt(nStyle);
    },

	EditChart : function(Chart)
    {
        if ( null != this.CurHdrFtr )
            return this.CurHdrFtr.EditChart( Chart );
    },

	AddInlineTable : function(Cols, Rows)
    {
        if ( null != this.CurHdrFtr )
            return this.CurHdrFtr.AddInlineTable( Cols, Rows );
    },

	AddToParagraph : function(ParaItem, bRecalculate)
	{
		if (para_NewLine === ParaItem.Type && true === ParaItem.IsPageOrColumnBreak())
			return;

		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.AddToParagraph(ParaItem, bRecalculate);
	},

	ClearParagraphFormatting : function(isClearParaPr, isClearTextPr)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.ClearParagraphFormatting();
	},

	PasteFormatting : function(TextPr, ParaPr, ApplyPara)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.PasteFormatting(TextPr, ParaPr, ApplyPara);
	},

    Remove : function(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd)
    {
        if ( null != this.CurHdrFtr )
            return this.CurHdrFtr.Remove(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd);
    },

	GetCursorPosXY : function()
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.GetCursorPosXY();
	},

	MoveCursorLeft : function(AddToSelect, Word)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.MoveCursorLeft(AddToSelect, Word);
	},

	MoveCursorRight : function(AddToSelect, Word)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.MoveCursorRight(AddToSelect, Word);
	},

	MoveCursorUp : function(AddToSelect)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.MoveCursorUp(AddToSelect);
	},

	MoveCursorDown : function(AddToSelect)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.MoveCursorDown(AddToSelect);
	},

	MoveCursorToEndOfLine : function(AddToSelect)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.MoveCursorToEndOfLine(AddToSelect);
	},

	MoveCursorToStartOfLine : function(AddToSelect)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.MoveCursorToStartOfLine(AddToSelect);
	},

	MoveCursorToXY : function(X, Y, PageIndex, AddToSelect)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.MoveCursorToXY(X, Y, PageIndex, AddToSelect);
	},

	MoveCursorToStartPos : function(AddToSelect)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.MoveCursorToStartPos(AddToSelect);
	},

	MoveCursorToEndPos : function(AddToSelect)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.MoveCursorToEndPos(AddToSelect);
	},

	MoveCursorToCell : function(bNext)
	{
		if (null != this.CurHdrFtr)
			this.CurHdrFtr.MoveCursorToCell(bNext);
	},

	SetParagraphAlign : function(Align)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.SetParagraphAlign(Align);
	},

	SetParagraphSpacing : function(Spacing)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.SetParagraphSpacing(Spacing);
	},

	SetParagraphIndent : function(Ind)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.SetParagraphIndent(Ind);
	},

	SetParagraphShd : function(Shd)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.SetParagraphShd(Shd);
	},

	SetParagraphStyle : function(Name)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.SetParagraphStyle(Name);
	},

	SetParagraphTabs : function(Tabs)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.SetParagraphTabs(Tabs);
	},

	SetParagraphContextualSpacing : function(Value)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.SetParagraphContextualSpacing(Value);
	},

	SetParagraphPageBreakBefore : function(Value)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.SetParagraphPageBreakBefore(Value);
	},

	SetParagraphKeepLines : function(Value)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.SetParagraphKeepLines(Value);
	},

	SetParagraphKeepNext : function(Value)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.SetParagraphKeepNext(Value);
	},

	SetParagraphWidowControl : function(Value)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.SetParagraphWidowControl(Value);
	},

	SetParagraphBorders : function(Value)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.SetParagraphBorders(Value);
	},

	IncreaseDecreaseFontSize : function(bIncrease)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.IncreaseDecreaseFontSize(bIncrease);
	},

	IncreaseDecreaseIndent : function(bIncrease)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.IncreaseDecreaseIndent(bIncrease);
	},

	SetImageProps : function(Props)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.SetImageProps(Props);
	},

	SetTableProps : function(Props)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.SetTableProps(Props);
	},

	GetCalculatedParaPr : function()
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.GetCalculatedParaPr();
	},

	GetCalculatedTextPr : function()
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.GetCalculatedTextPr();
	},

	GetDirectTextPr : function()
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.GetDirectTextPr();

		return null;
	},

	GetDirectParaPr : function()
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.GetDirectParaPr();

		return null;
	},

	RemoveSelection : function(bNoCheckDrawing)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.RemoveSelection(bNoCheckDrawing);
	},

	DrawSelectionOnPage : function(CurPage)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.DrawSelectionOnPage(CurPage);
	},

    Selection_SetStart : function(X,Y, PageIndex, MouseEvent, bActivate)
    {
		var TempHdrFtr = null;
		// Если мы попадаем в заселекченную автофигуру, пусть она даже выходит за пределы
		if (true === this.LogicDocument.DrawingObjects.pointInSelectedObject(X, Y, PageIndex)
			|| (null !== (TempHdrFtr = this.Pages[PageIndex].Header) && true === TempHdrFtr.Is_PointInFlowTable(X, Y))
			|| (null !== (TempHdrFtr = this.Pages[PageIndex].Footer) && true === TempHdrFtr.Is_PointInFlowTable(X, Y)))
		{
			if (this.CurHdrFtr && ((null !== TempHdrFtr && TempHdrFtr !== this.CurHdrFtr) || this.CurPage !== PageIndex))
				this.CurHdrFtr.RemoveSelection();

			if (null !== TempHdrFtr)
				this.CurHdrFtr = TempHdrFtr;

			this.CurPage = PageIndex;
			this.CurHdrFtr.Selection_SetStart(X, Y, PageIndex, MouseEvent);
            this.ChangeCurPageOnEnd = false;

            this.WaitMouseDown = false;

            return true;
        }

        this.ChangeCurPageOnEnd = true;

        var OldPage = this.CurPage;

        // Сначала проверяем, не попали ли мы в контент документа. Если да, тогда надо
        // активировать работу с самим документом (просто вернуть false здесь)

        var PageMetrics = this.LogicDocument.Get_PageContentStartPos( PageIndex );
        
        if ( MouseEvent.ClickCount >= 2 && true != editor.isStartAddShape &&
            !( Y <= PageMetrics.Y      || ( null !== ( TempHdrFtr = this.Pages[PageIndex].Header ) && true === TempHdrFtr.Is_PointInDrawingObjects( X, Y ) ) ) &&
            !( Y >= PageMetrics.YLimit || ( null !== ( TempHdrFtr = this.Pages[PageIndex].Footer ) && true === TempHdrFtr.Is_PointInDrawingObjects( X, Y ) ) ) )
        {
            // Убираем селект, если он был
            if ( null != this.CurHdrFtr )
            {
                this.CurHdrFtr.RemoveSelection();
            }

            MouseEvent.ClickCount = 1;
            return false;
        }

        this.CurPage = PageIndex;

        var HdrFtr = null;

        // Проверяем попали ли мы в колонтитул, если он есть. Если мы попали в
        // область колонтитула, а его там нет, тогда добавим новый колонтитул.
        if ( Y <= PageMetrics.Y || ( null !== ( TempHdrFtr = this.Pages[PageIndex].Header ) && true === TempHdrFtr.Is_PointInDrawingObjects( X, Y ) ) || true === editor.isStartAddShape )
        {
            if ( null === this.Pages[PageIndex].Header )
            {
                if ( false === editor.WordControl.m_oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_HdrFtr) )
                {
                    // Меняем старый режим редактирования, чтобы при Undo/Redo возвращаться в режим редактирования документа
                    this.LogicDocument.Set_DocPosType(docpostype_Content);
                    History.Create_NewPoint(AscDFH.historydescription_Document_AddHeader);
                    this.LogicDocument.Set_DocPosType(docpostype_HdrFtr);
                    HdrFtr = this.LogicDocument.Create_SectionHdrFtr( hdrftr_Header, PageIndex );

                    if (this.CurHdrFtr)
                    	this.CurHdrFtr.RemoveSelection();

                    this.CurHdrFtr = HdrFtr;

                    this.LogicDocument.Recalculate();
                }
                else
                    return false;
            }
            else
                HdrFtr = this.Pages[PageIndex].Header;
        }
        else if ( Y >= PageMetrics.YLimit || ( null !== ( TempHdrFtr = this.Pages[PageIndex].Footer ) && true === TempHdrFtr.Is_PointInDrawingObjects( X, Y ) ) )
        {
            if ( null === this.Pages[PageIndex].Footer )
            {
                if ( false === editor.WordControl.m_oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_HdrFtr) )
                {
                    // Меняем старый режим редактирования, чтобы при Undo/Redo возвращаться в режим редактирования документа
                    this.LogicDocument.Set_DocPosType(docpostype_Content);
                    History.Create_NewPoint(AscDFH.historydescription_Document_AddFooter);
                    this.LogicDocument.Set_DocPosType(docpostype_HdrFtr);
                    HdrFtr = this.LogicDocument.Create_SectionHdrFtr( hdrftr_Footer, PageIndex );

					if (this.CurHdrFtr)
						this.CurHdrFtr.RemoveSelection();

					this.CurHdrFtr = HdrFtr;

                    this.LogicDocument.Recalculate();
                }
                else
                    return false;
            }
            else
                HdrFtr = this.Pages[PageIndex].Footer;
        }

        if ( null === HdrFtr )
        {
            // Ничего не делаем и отключаем дальнейшую обработку MouseUp и MouseMove
            this.WaitMouseDown = true;

            return true;
        }
        else
        {
            this.WaitMouseDown = false;
        }

        // В зависимости от страницы и позиции на странице мы активируем(делаем текущим)
        // соответствующий колонтитул

        var OldHdrFtr = this.CurHdrFtr;
        this.CurHdrFtr = HdrFtr;

        if ( null != OldHdrFtr && (OldHdrFtr != this.CurHdrFtr || OldPage != this.CurPage) )
        {
            // Удаляем селект, если он был на предыдущем колонтитуле
            OldHdrFtr.RemoveSelection();
        }

        if ( null != this.CurHdrFtr )
        {
            this.CurHdrFtr.Selection_SetStart( X, Y, PageIndex, MouseEvent );
            if ( true === bActivate )
            {
                var NewMouseEvent = {};
                NewMouseEvent.Type       = AscCommon.g_mouse_event_type_up;
                NewMouseEvent.ClickCount = 1;
                this.CurHdrFtr.Selection_SetEnd( X, Y, PageIndex, NewMouseEvent );
                this.CurHdrFtr.Content.MoveCursorToStartPos(false);
            }
        }

        return true;
    },

    Selection_SetEnd : function(X, Y, PageIndex, MouseEvent)
    {
        if ( true === this.WaitMouseDown )
            return;

        if ( null != this.CurHdrFtr )
        {
            // Селект может происходить только внутри одного колонтитула, а колонтитул
            // не может быть разбит на несколько страниц
            var ResY = Y;

            if (docpostype_DrawingObjects != this.CurHdrFtr.Content.Get_DocPosType())
            {
                if ( PageIndex > this.CurPage )
                    ResY = this.LogicDocument.Get_PageLimits(this.CurPage).YLimit + 10;
                else if ( PageIndex < this.CurPage )
                    ResY = -10;

                PageIndex = this.CurPage;
            }

            this.CurHdrFtr.Selection_SetEnd(X, ResY, PageIndex, MouseEvent);

            if ( false === this.ChangeCurPageOnEnd )
            {
                this.CurHdrFtr.Set_Page( this.CurPage );
            }
        }
    },

	IsMovingTableBorder : function()
    {
        if ( null != this.CurHdrFtr )
            return this.CurHdrFtr.IsMovingTableBorder();

        return false;
    },

	CheckPosInSelection : function(X, Y, PageAbs, NearPos)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.CheckPosInSelection(X, Y, PageAbs, NearPos);
	},

	IsSelectionEmpty : function(bCheckHidden)
	{
		if (null !== this.CurHdrFtr)
			return this.CurHdrFtr.Content.IsSelectionEmpty(bCheckHidden);

		return true;
	},

	SelectAll : function()
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.SelectAll();
	},

    Get_NearestPos : function(PageNum, X, Y, bAnchor, Drawing)
    {
        var HdrFtr = (true === editor.isStartAddShape ? this.CurHdrFtr : this.Internal_GetContentByXY( X, Y, PageNum ));
        
        if ( null != HdrFtr )
            return HdrFtr.Get_NearestPos( X, Y, bAnchor, Drawing );
        else
            return { X : -1, Y : -1, Height : -1 };
    },

	GetCurrentParagraph : function(bIgnoreSelection, arrSelectedParagraphs)
	{
		return this.CurHdrFtr.GetCurrentParagraph(bIgnoreSelection, arrSelectedParagraphs);
	},

	StartSelectionFromCurPos : function()
	{
		if (null !== this.CurHdrFtr)
			this.CurHdrFtr.StartSelectionFromCurPos();
	},
//-----------------------------------------------------------------------------------
// Внутренние(вспомогательные) функции
//-----------------------------------------------------------------------------------

    // Возвращаем колонтитул по данной позиции
    Internal_GetContentByXY : function( X, Y, PageIndex )
    {
        var Header = null;
        var Footer = null;

        if ( undefined !== this.Pages[PageIndex] )
        {
            Header = this.Pages[PageIndex].Header;
            Footer = this.Pages[PageIndex].Footer;
        }
        
        var PageH = this.LogicDocument.Get_PageLimits( PageIndex).YLimit;

        if ( Y <= PageH / 2 && null != Header )
            return Header;
        else if ( Y >= PageH / 2 && null != Footer )
            return Footer;
        else if ( null != Header )
            return Header;
        else
            return Footer;

        return null;
    },

//-----------------------------------------------------------------------------------
// Функции для работы с таблицами
//-----------------------------------------------------------------------------------
	AddTableRow : function(bBefore)
	{
		if (null != this.CurHdrFtr)
			this.CurHdrFtr.AddTableRow(bBefore);
	},

	AddTableColumn : function(bBefore)
	{
		if (null != this.CurHdrFtr)
			this.CurHdrFtr.AddTableColumn(bBefore);
	},

	RemoveTableRow : function()
	{
		if (null != this.CurHdrFtr)
			this.CurHdrFtr.RemoveTableRow();
	},

	RemoveTableColumn : function()
	{
		if (null != this.CurHdrFtr)
			this.CurHdrFtr.RemoveTableColumn();
	},

	MergeTableCells : function()
	{
		if (null != this.CurHdrFtr)
			this.CurHdrFtr.MergeTableCells();
	},

	SplitTableCells : function(Cols, Rows)
	{
		if (null != this.CurHdrFtr)
			this.CurHdrFtr.SplitTableCells(Cols, Rows);
	},

	RemoveTable : function()
	{
		if (null != this.CurHdrFtr)
			this.CurHdrFtr.RemoveTable();
	},

	SelectTable : function(Type)
	{
		if (null != this.CurHdrFtr)
			this.CurHdrFtr.SelectTable(Type);
	},

	CanMergeTableCells : function()
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.CanMergeTableCells();
	},

	CanSplitTableCells : function()
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.CanSplitTableCells();
	},

	DistributeTableCells : function(isHorizontally)
	{
		if (this.CurHdrFtr)
			return this.CurHdrFtr.DistributeTableCells(isHorizontally);

		return false;
	},

//-----------------------------------------------------------------------------------
// Undo/Redo функции
//-----------------------------------------------------------------------------------
	GetSelectionState : function()
	{
		var HdrFtrState       = {};
		HdrFtrState.CurHdrFtr = this.CurHdrFtr;

		var State = null;
		if (null != this.CurHdrFtr)
			State = this.CurHdrFtr.Content.GetSelectionState();
		else
			State = [];

		State.push(HdrFtrState);

		return State;
	},

	SetSelectionState : function(State, StateIndex)
	{
		if (State.length <= 0)
			return;

		var HdrFtrState = State[StateIndex];
		this.CurHdrFtr  = HdrFtrState.CurHdrFtr;

		if (null != this.CurHdrFtr)
			this.CurHdrFtr.Content.SetSelectionState(State, StateIndex - 1);
	},
//-----------------------------------------------------------------------------------
// Функции для работы с гиперссылками
//-----------------------------------------------------------------------------------
	AddHyperlink : function(HyperProps)
	{
		if (null != this.CurHdrFtr)
			this.CurHdrFtr.AddHyperlink(HyperProps);
	},

	ModifyHyperlink : function(HyperProps)
	{
		if (null != this.CurHdrFtr)
			this.CurHdrFtr.ModifyHyperlink(HyperProps);
	},

	RemoveHyperlink : function()
	{
		if (null != this.CurHdrFtr)
			this.CurHdrFtr.RemoveHyperlink();
	},

	CanAddHyperlink : function(bCheckInHyperlink)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.CanAddHyperlink(bCheckInHyperlink);

		return false;
	},

	IsCursorInHyperlink : function(bCheckEnd)
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.IsCursorInHyperlink(bCheckEnd);

		return null;
	},
//-----------------------------------------------------------------------------------
// Функции для работы с комментариями
//-----------------------------------------------------------------------------------
	AddComment : function(Comment)
	{
		if (null != this.CurHdrFtr)
		{
			// Отмечаем, что данный комментарий добавлен к колонтитулу
			Comment.Set_TypeInfo(comment_type_HdrFtr, this.CurHdrFtr);
			this.CurHdrFtr.AddComment(Comment);
		}
	},

	CanAddComment : function()
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.CanAddComment();

		return false;
	},

	GetSelectionAnchorPos : function()
	{
		if (null != this.CurHdrFtr)
			return this.CurHdrFtr.Content.GetSelectionAnchorPos();

		return {X : 0, Y : 0, Page : 0};
	}
};
CHeaderFooterController.prototype.GetStyleFromFormatting = function()
{
    if (null != this.CurHdrFtr)
        return this.CurHdrFtr.Content.GetStyleFromFormatting();

    return null;
};
CHeaderFooterController.prototype.GetSimilarNumbering = function(oEngine)
{
	if (this.CurHdrFtr)
		this.CurHdrFtr.Content.GetSimilarNumbering(oEngine)
};
CHeaderFooterController.prototype.SetParagraphFramePr = function(FramePr, bDelete)
{
    if (null !== this.CurHdrFtr)
        this.CurHdrFtr.SetParagraphFramePr(FramePr, bDelete);
};
CHeaderFooterController.prototype.GetSelectionBounds = function()
{
	if (null !== this.CurHdrFtr)
		return this.CurHdrFtr.GetSelectionBounds();

	return null;
};
CHeaderFooterController.prototype.Get_CurHdrFtr = function()
{
    return this.CurHdrFtr;
};
CHeaderFooterController.prototype.Set_CurHdrFtr = function(HdrFtr)
{
    if (null !== this.CurHdrFtr)
        this.CurHdrFtr.RemoveSelection();

    this.CurHdrFtr = HdrFtr;
};
CHeaderFooterController.prototype.RecalculatePageCountUpdate = function(nPageAbs, nPageCount)
{
	var oPage = this.Pages[nPageAbs];
	if (!oPage)
		return false;
	
	var oHeader = oPage.Header;
	var oFooter = oPage.Footer;

	var bNeedRecalc = false;
	if (oHeader && oHeader.Have_PageCountElement())
	{
		oHeader.Update_PageCountElements(nPageCount);
		bNeedRecalc = true;
	}

	if (false === bNeedRecalc && oFooter && oFooter.Have_PageCountElement())
	{
		oFooter.Update_PageCountElements(nPageCount);
		bNeedRecalc = true;
	}

	if (true === bNeedRecalc)
		return this.Recalculate(nPageAbs);

	return null;
};
CHeaderFooterController.prototype.HavePageCountElement = function()
{
	var nStartPage = -1;
	var nPagesCount = this.LogicDocument.Pages.length;
	for (var nPageAbs = 0; nPageAbs < nPagesCount; ++nPageAbs)
	{
		var oPage = this.Pages[nPageAbs];
		if (!oPage)
			continue;

		var oHeader = oPage.Header;
		var oFooter = oPage.Footer;

		if (oHeader && oHeader.Have_PageCountElement())
		{
			oHeader.ForceRecalculate(nPageAbs);
			if (-1 === nStartPage)
				nStartPage = nPageAbs;
		}

		if (oFooter && oFooter.Have_PageCountElement())
		{
			oFooter.ForceRecalculate(nPageAbs);
			if (-1 === nStartPage)
				nStartPage = nPageAbs;
		}
	}

	return nStartPage;
};

function CHdrFtrPage()
{
    this.Header = null;
    this.Footer = null;
}

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CHeaderFooter = CHeaderFooter;
window['AscCommonWord'].CHeaderFooterController = CHeaderFooterController;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

/**
 * Базовый класс для работы с содержимым документа (параграфы и таблицы).
 * @constructor
 */
function CDocumentContentBase()
{
	this.Id = null;

	this.StartPage = 0; // Номер стартовой страницы в родительском классе
	this.CurPage   = 0; // Номер текущей страницы

	this.Content = [];

	this.ReindexStartPos = 0;
}
CDocumentContentBase.prototype.Get_Id = function()
{
	return this.GetId();
};
CDocumentContentBase.prototype.GetId = function()
{
	return this.Id;
};
/**
 * Получаем ссылку на основной объект документа
 * @returns {CDocument}
 */
CDocumentContentBase.prototype.GetLogicDocument = function()
{
	if (this instanceof CDocument)
		return this;

	return this.LogicDocument;
};
/**
 * Получаем тип активной части документа.
 * @returns {(docpostype_Content | docpostype_HdrFtr | docpostype_DrawingObjects | docpostype_Footnotes)}
 */
CDocumentContentBase.prototype.Get_DocPosType = function()
{
	return this.CurPos.Type;
};
/**
 * Выставляем тип активной части документа.
 * @param {(docpostype_Content | docpostype_HdrFtr | docpostype_DrawingObjects | docpostype_Footnotes)} nType
 */
CDocumentContentBase.prototype.Set_DocPosType = function(nType)
{
	this.CurPos.Type = nType;

	if (this.Controller)
	{
		if (docpostype_HdrFtr === nType)
		{
			this.Controller = this.HeaderFooterController;
		}
		else if (docpostype_DrawingObjects === nType)
		{
			this.Controller = this.DrawingsController;
		}
		else if (docpostype_Footnotes === nType)
		{
			this.Controller = this.Footnotes;
		}
		else //if (docpostype_Content === nType)
		{
			this.Controller = this.LogicDocumentController;
		}
	}
};
/**
 * Обновляем индексы элементов.
 */
CDocumentContentBase.prototype.Update_ContentIndexing = function()
{
	if (-1 !== this.ReindexStartPos)
	{
		for (var Index = this.ReindexStartPos, Count = this.Content.length; Index < Count; Index++)
		{
			this.Content[Index].Index = Index;
		}

		this.ReindexStartPos = -1;
	}
};
CDocumentContentBase.prototype.UpdateContentIndexing = function()
{
	return this.Update_ContentIndexing();
};
/**
 * Получаем массив всех автофигур.
 * @param {Array} arrDrawings - Если задан массив, тогда мы дополняем данный массив и возвращаем его.
 * @returns {Array}
 */
CDocumentContentBase.prototype.GetAllDrawingObjects = function(arrDrawings)
{
	if (undefined === arrDrawings || null === arrDrawings)
		arrDrawings = [];

	if (this instanceof CDocument)
	{
		this.SectionsInfo.GetAllDrawingObjects(arrDrawings);
	}

	for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos)
	{
		this.Content[nPos].GetAllDrawingObjects(arrDrawings);
	}

	return arrDrawings;
};
/**
 * Получаем массив URL всех картинок в документе.
 * @param {Array} arrUrls - Если задан массив, тогда мы дополняем данный массив и возвращаем его.
 * @returns {Array}
 */
CDocumentContentBase.prototype.Get_AllImageUrls = function(arrUrls)
{
	if (undefined === arrDrawings || null === arrDrawings)
		arrUrls = [];

	var arrDrawings = this.GetAllDrawingObjects();
	for (var nIndex = 0, nCount = arrDrawings.length; nIndex < nCount; ++nIndex)
	{
		var oParaDrawing = arrDrawings[nIndex];
		oParaDrawing.GraphicObj.getAllRasterImages(arrUrls);
	}

	return arrUrls;
};
/**
 * Переназначаем ссылки на картинки.
 * @param {Object} mapUrls - Мап, в котором ключ - это старая ссылка, а значение - новая.
 */
CDocumentContentBase.prototype.Reassign_ImageUrls = function(mapUrls)
{
	var arrDrawings = this.GetAllDrawingObjects();
	for (var nIndex = 0, nCount = arrDrawings.length; nIndex < nCount; ++nIndex)
	{
		var oDrawing = arrDrawings[nIndex];
		oDrawing.Reassign_ImageUrls(mapUrls);
	}
};
/**
 * Находим отрезок сносок, заданный между сносками.
 * @param {?CFootEndnote} oFirstFootnote - если null, то иещм с начала документа
 * @param {?CFootEndnote} oLastFootnote - если null, то ищем до конца документа
 */
CDocumentContentBase.prototype.Get_FootnotesList = function(oFirstFootnote, oLastFootnote)
{
	var oEngine = new CDocumentFootnotesRangeEngine();
	oEngine.Init(oFirstFootnote, oLastFootnote);

	var arrFootnotes = [];

	var arrParagraphs = this.GetAllParagraphs({OnlyMainDocument : true, All : true});
	for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
	{
		var oParagraph = arrParagraphs[nIndex];

		if (true === oParagraph.Get_FootnotesList(oEngine))
			return arrFootnotes;
	}

	return oEngine.GetRange();
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Private area
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 * Сообщаем, что нужно провести переиндексацию элементов начиная с заданного.
 * @param StartPos
 */
CDocumentContentBase.prototype.private_ReindexContent = function(StartPos)
{
	if (-1 === this.ReindexStartPos || this.ReindexStartPos > StartPos)
		this.ReindexStartPos = StartPos;
};
/**
 * Специальная функия для рассчета пустого параграфа с разрывом секции.
 * @param Element
 * @param PrevElement
 * @param PageIndex
 * @param ColumnIndex
 * @param ColumnsCount
 */
CDocumentContentBase.prototype.private_RecalculateEmptySectionParagraph = function(Element, PrevElement, PageIndex, ColumnIndex, ColumnsCount)
{
	var LastVisibleBounds = PrevElement.GetLastRangeVisibleBounds();

	var ___X = LastVisibleBounds.X + LastVisibleBounds.W;
	var ___Y = LastVisibleBounds.Y;

	// Чтобы у нас знак разрыва секции рисовался красиво и где надо делаем небольшую хитрость:
	// перед пересчетом данного параграфа меняем в нем в скомпилированных настройках прилегание и
	// отступы, а после пересчета помечаем, что настройки нужно скомпилировать заново.
	var CompiledPr           = Element.Get_CompiledPr2(false).ParaPr;
	CompiledPr.Jc            = align_Left;
	CompiledPr.Ind.FirstLine = 0;
	CompiledPr.Ind.Left      = 0;
	CompiledPr.Ind.Right     = 0;

	// Делаем предел по X минимум 10 мм, чтобы всегда было видно элемент разрыва секции
	Element.Reset(___X, ___Y, Math.max(___X + 10, LastVisibleBounds.XLimit), 10000, PageIndex, ColumnIndex, ColumnsCount);
	Element.Recalculate_Page(0);

	Element.Recalc_CompiledPr();

	// Меняем насильно размер строки и страницы данного параграфа, чтобы у него границы попадания и
	// селект были ровно такие же как и у последней строки предыдущего элемента.
	Element.Pages[0].Y             = ___Y;
	Element.Lines[0].Top           = 0;
	Element.Lines[0].Y             = LastVisibleBounds.BaseLine;
	Element.Lines[0].Bottom        = LastVisibleBounds.H;
	Element.Pages[0].Bounds.Top    = ___Y;
	Element.Pages[0].Bounds.Bottom = ___Y + LastVisibleBounds.H;
};
/**
 * Передвигаем курсор (от текущего положения) к началу ссылки на сноску
 * @param isNext двигаемся вперед или назад
 * @param isCurrent находимся ли мы в текущем объекте
 * @returns {boolean}
 * @constructor
 */
CDocumentContentBase.prototype.GotoFootnoteRef = function(isNext, isCurrent)
{
	var nCurPos = 0;

	if (true === isCurrent)
	{
		if (true === this.Selection.Use)
			nCurPos = Math.min(this.Selection.StartPos, this.Selection.EndPos);
		else
			nCurPos = this.CurPos.ContentPos;
	}
	else
	{
		if (isNext)
			nCurPos = 0;
		else
			nCurPos = this.Content.length - 1;
	}

	if (isNext)
	{
		for (var nIndex = nCurPos, nCount = this.Content.length; nIndex < nCount; ++nIndex)
		{
			var oElement = this.Content[nIndex];
			if (oElement.GotoFootnoteRef(true, true === isCurrent && nIndex === nCurPos))
				return true;
		}
	}
	else
	{
		for (var nIndex = nCurPos; nIndex >= 0; --nIndex)
		{
			var oElement = this.Content[nIndex];
			if (oElement.GotoFootnoteRef(false, true === isCurrent && nIndex === nCurPos))
				return true;
		}
	}

	return false;
};
CDocumentContentBase.prototype.MoveCursorToNearestPos = function(oNearestPos)
{
	var oPara = oNearestPos.Paragraph;
	var oParent = oPara.Parent;
	if (oParent)
	{
		var oTopDocument = oParent.Is_TopDocument(true);
		if (oTopDocument)
			oTopDocument.RemoveSelection();
	}

	oPara.Set_ParaContentPos(oNearestPos.ContentPos, true, -1, -1);
	oPara.Document_SetThisElementCurrent(true);
};
CDocumentContentBase.prototype.private_CreateNewParagraph = function()
{
	var oPara = new Paragraph(this.DrawingDocument, this, this.bPresentation === true);
	oPara.Correct_Content();
	oPara.MoveCursorToStartPos(false);
	return oPara;
};
CDocumentContentBase.prototype.StopSelection = function()
{
	if (true !== this.Selection.Use)
		return;

	this.Selection.Start = false;

	if (this.Content[this.Selection.StartPos])
		this.Content[this.Selection.StartPos].StopSelection();
};
CDocumentContentBase.prototype.GetNumberingInfo = function(oNumberingEngine, oPara, oNumPr)
{
	if (undefined === oNumberingEngine || null === oNumberingEngine)
		oNumberingEngine = new CDocumentNumberingInfoEngine(oPara, oNumPr, this.GetNumbering());

	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		this.Content[nIndex].GetNumberingInfo(oNumberingEngine);
		if (oNumberingEngine.IsStop())
			break;
	}

	return oNumberingEngine.GetNumInfo();
};
CDocumentContentBase.prototype.private_Remove = function(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	this.RemoveNumberingSelection();

	var bRetValue = true;
	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (EndPos < StartPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		// Проверим, пустой ли селект в конечном элементе (для случая, когда конечный элемент параграф, и в нем
		// не заселекчен знак конца параграфа)
		if (StartPos !== EndPos && true === this.Content[EndPos].IsSelectionEmpty(true))
			EndPos--;

		if (true === this.Is_TrackRevisions())
		{
			// Если есть параграфы, которые были добавлены во время рецензирования, тогда мы их удаляем
			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				this.Content[Index].Remove(1, true, bRemoveOnlySelection, bOnTextAdd);
			}

			this.RemoveSelection();
			for (var Index = EndPos - 1; Index >= StartPos; Index--)
			{
				if (type_Paragraph === this.Content[Index].GetType() && reviewtype_Add === this.Content[Index].GetReviewType())
				{
					// Если параграф пустой, тогда удаляем параграф, если не пустой, тогда объединяем его со
					// следующим параграф. Если следующий элемент таблица, тогда ничего не делаем.
					if (this.Content[Index].IsEmpty())
					{
						this.Internal_Content_Remove(Index, 1);
					}
					else if (Index < this.Content.length - 1 && type_Paragraph === this.Content[Index + 1].GetType())
					{
						this.Content[Index].Concat(this.Content[Index + 1]);
						this.Internal_Content_Remove(Index + 1, 1);
					}
				}
				else
				{
					this.Content[Index].SetReviewType(reviewtype_Remove);
				}
			}

			this.CurPos.ContentPos = StartPos;
		}
		else
		{
			this.Selection.Use      = false;
			this.Selection.StartPos = 0;
			this.Selection.EndPos   = 0;

			if (StartPos !== EndPos)
			{
				var StartType = this.Content[StartPos].GetType();
				var EndType   = this.Content[EndPos].GetType();

				var bStartEmpty = false, bEndEmpty = false;
				if (type_Paragraph === StartType || type_BlockLevelSdt === StartType)
				{
					this.Content[StartPos].Remove(1, true);
					bStartEmpty = this.Content[StartPos].IsEmpty()
				}
				else if (type_Table === StartType)
				{
					bStartEmpty = !(this.Content[StartPos].Row_Remove2());
				}

				if (type_Paragraph === EndType || type_BlockLevelSdt === EndType)
				{
					this.Content[EndPos].Remove(1, true);
					bEndEmpty = this.Content[EndPos].IsEmpty()
				}
				else if (type_Table === EndType)
				{
					bEndEmpty = !(this.Content[EndPos].Row_Remove2());
				}

				if (!bStartEmpty && !bEndEmpty)
				{
					this.Internal_Content_Remove(StartPos + 1, EndPos - StartPos - 1);
					this.CurPos.ContentPos = StartPos;

					if (type_Paragraph === StartType && type_Paragraph === EndType && true === bOnTextAdd)
					{
						// Встаем в конец параграфа и удаляем 1 элемент (чтобы соединить параграфы)
						this.Content[StartPos].MoveCursorToEndPos(false, false);
						this.Remove(1, true);
					}
					else
					{
						if (true === bOnTextAdd && type_Paragraph !== this.Content[StartPos + 1].GetType() && type_Paragraph !== this.Content[StartPos].GetType())
						{
							this.Internal_Content_Add(StartPos + 1, this.private_CreateNewParagraph());
							this.CurPos.ContentPos = StartPos + 1;
							this.Content[StartPos + 1].MoveCursorToStartPos(false);
						}
						else if (true === bOnTextAdd && type_Paragraph !== this.Content[StartPos + 1].GetType())
						{
							this.CurPos.ContentPos = StartPos;
							this.Content[StartPos].MoveCursorToEndPos(false, false);
						}
						else
						{
							this.CurPos.ContentPos = StartPos + 1;
							this.Content[StartPos + 1].MoveCursorToStartPos(false);
						}
					}
				}
				else if (!bStartEmpty)
				{
					if (true === bOnTextAdd && type_Table === StartType)
					{
						if (EndType !== type_Paragraph)
							this.Internal_Content_Remove(StartPos + 1, EndPos - StartPos);
						else
							this.Internal_Content_Remove(StartPos + 1, EndPos - StartPos - 1);

						if (type_Table === this.Content[StartPos + 1].GetType() && true === bOnTextAdd)
							this.Internal_Content_Add(StartPos + 1, this.private_CreateNewParagraph());

						this.CurPos.ContentPos = StartPos + 1;
						this.Content[StartPos + 1].MoveCursorToStartPos(false);
					}
					else
					{
						this.Internal_Content_Remove(StartPos + 1, EndPos - StartPos);

						if (type_Table == StartType)
						{
							// У нас обязательно есть элемент после таблицы (либо снова таблица, либо параграф)
							// Встаем в начало следующего элемента.
							this.CurPos.ContentPos = StartPos + 1;
							this.Content[StartPos + 1].MoveCursorToStartPos(false);
						}
						else
						{
							this.CurPos.ContentPos = StartPos;
							this.Content[StartPos].MoveCursorToEndPos(false, false);
						}
					}
				}
				else if (!bEndEmpty)
				{
					this.Internal_Content_Remove(StartPos, EndPos - StartPos);

					if (type_Table === this.Content[StartPos].GetType() && true === bOnTextAdd)
						this.Internal_Content_Add(StartPos, this.private_CreateNewParagraph());

					this.CurPos.ContentPos = StartPos;
					this.Content[StartPos].MoveCursorToStartPos(false);
				}
				else
				{
					if (true === bOnTextAdd)
					{
						// Удаляем весь промежуточный контент, начальный элемент и конечный элемент, если это
						// таблица, поскольку таблица не может быть последним элементом в документе удаляем без проверок.
						if (type_Paragraph !== EndType)
							this.Internal_Content_Remove(StartPos, EndPos - StartPos + 1);
						else
							this.Internal_Content_Remove(StartPos, EndPos - StartPos);

						if (type_Table === this.Content[StartPos].GetType() && true === bOnTextAdd)
							this.Internal_Content_Add(StartPos, this.private_CreateNewParagraph());

						this.CurPos.ContentPos = StartPos;
						this.Content[StartPos].MoveCursorToStartPos();
					}
					else
					{
						// Удаляем весь промежуточный контент, начальный и конечный параграфы
						// При таком удалении надо убедиться, что в документе останется хотя бы один элемент
						if (0 === StartPos && (EndPos - StartPos + 1) >= this.Content.length)
						{
							this.Internal_Content_Add(0, this.private_CreateNewParagraph());
							this.Internal_Content_Remove(1, this.Content.length - 1);
							bRetValue = false;
						}
						else
						{
							this.Internal_Content_Remove(StartPos, EndPos - StartPos + 1);
						}

						// Выставляем текущую позицию
						if (StartPos >= this.Content.length)
						{
							this.CurPos.ContentPos = this.Content.length - 1;
							this.Content[this.CurPos.ContentPos].MoveCursorToEndPos(false, false);
						}
						else
						{
							this.CurPos.ContentPos = StartPos;
							this.Content[StartPos].MoveCursorToStartPos(false);
						}
					}
				}
			}
			else
			{
				this.CurPos.ContentPos = StartPos;
				if (Count < 0 && type_Table === this.Content[StartPos].GetType() && true === this.Content[StartPos].IsCellSelection() && true != bOnTextAdd)
				{
					this.RemoveTableRow();
				}
				else if (false === this.Content[StartPos].Remove(Count, true, bRemoveOnlySelection, bOnTextAdd))
				{
					// При добавлении текста, параграф не объединяется
					if (true !== bOnTextAdd)
					{
						// В ворде параграфы объединяются только когда у них все настройки совпадают.
						// (почему то при изменении и обратном изменении настроек параграфы перестают объединятся)
						// Пока у нас параграфы будут объединяться всегда и настройки будут браться из первого
						// параграфа, кроме случая, когда первый параграф полностью удаляется.

						if (true === this.Content[StartPos].IsEmpty() && this.Content.length > 1)
						{
							this.Internal_Content_Remove(StartPos, 1);

							// Выставляем текущую позицию
							if (StartPos >= this.Content.length)
							{
								// Документ не должен заканчиваться таблицей, поэтому здесь проверку не делаем
								this.CurPos.ContentPos = this.Content.length - 1;
								this.Content[this.CurPos.ContentPos].MoveCursorToEndPos(false, false);
							}
							else
							{
								this.CurPos.ContentPos = StartPos;
								this.Content[StartPos].MoveCursorToStartPos(false);
							}
						}
						else if (this.CurPos.ContentPos < this.Content.length - 1 && type_Paragraph === this.Content[this.CurPos.ContentPos].GetType() && type_Paragraph === this.Content[this.CurPos.ContentPos + 1].GetType())
						{
							// Соединяем текущий и предыдущий параграфы
							this.Content[StartPos].Concat(this.Content[StartPos + 1]);
							this.Internal_Content_Remove(StartPos + 1, 1);
						}
						else if (this.Content.length === 1 && true === this.Content[0].IsEmpty())
						{
							if (Count > 0)
							{
								this.Internal_Content_Add(0, this.private_CreateNewParagraph());
								this.Internal_Content_Remove(1, this.Content.length - 1);
							}

							bRetValue = false;
						}
					}
				}
			}
		}
	}
	else
	{
		if (true === bRemoveOnlySelection || true === bOnTextAdd)
			return true;

		if (type_Paragraph == this.Content[this.CurPos.ContentPos].GetType())
		{
			if (false === this.Content[this.CurPos.ContentPos].Remove(Count, bOnlyText))
			{
				if (Count < 0)
				{
					if (this.CurPos.ContentPos > 0 && type_Paragraph == this.Content[this.CurPos.ContentPos - 1].GetType())
					{
						var CurrFramePr = this.Content[this.CurPos.ContentPos].Get_FramePr();
						var PrevFramePr = this.Content[this.CurPos.ContentPos - 1].Get_FramePr();

						if ((undefined === CurrFramePr && undefined === PrevFramePr) || (undefined !== CurrFramePr && undefined !== PrevFramePr && true === CurrFramePr.Compare(PrevFramePr)))
						{
							if (true === this.Is_TrackRevisions() && reviewtype_Add !== this.Content[this.CurPos.ContentPos - 1].GetReviewType())
							{
								this.Content[this.CurPos.ContentPos - 1].SetReviewType(reviewtype_Remove);
								this.CurPos.ContentPos--;
								this.Content[this.CurPos.ContentPos].MoveCursorToEndPos(false, false);
							}
							else
							{
								if (true === this.Content[this.CurPos.ContentPos - 1].IsEmpty() && undefined === this.Content[this.CurPos.ContentPos - 1].GetNumPr())
								{
									// Просто удаляем предыдущий параграф
									this.Internal_Content_Remove(this.CurPos.ContentPos - 1, 1);
									this.CurPos.ContentPos--;
									this.Content[this.CurPos.ContentPos].MoveCursorToStartPos(false);
								}
								else
								{
									// Соединяем текущий и предыдущий параграфы
									var Prev = this.Content[this.CurPos.ContentPos - 1];

									// Смещаемся в конец до объединения параграфов, чтобы курсор стоял в месте
									// соединения.
									Prev.MoveCursorToEndPos(false, false);

									// Запоминаем новую позицию курсора, после совмещения параграфов
									Prev.Concat(this.Content[this.CurPos.ContentPos]);
									this.Internal_Content_Remove(this.CurPos.ContentPos, 1);
									this.CurPos.ContentPos--;
								}
							}
						}
					}
					else if (this.CurPos.ContentPos > 0 && type_BlockLevelSdt === this.Content[this.CurPos.ContentPos - 1].GetType())
					{
						this.CurPos.ContentPos--;
						this.Content[this.CurPos.ContentPos].MoveCursorToEndPos(false);
					}
					else if (0 === this.CurPos.ContentPos)
					{
						bRetValue = false;
					}
				}
				else if (Count > 0)
				{
					if (this.CurPos.ContentPos < this.Content.length - 1 && type_Paragraph == this.Content[this.CurPos.ContentPos + 1].GetType())
					{
						var CurrFramePr = this.Content[this.CurPos.ContentPos].Get_FramePr();
						var NextFramePr = this.Content[this.CurPos.ContentPos + 1].Get_FramePr();

						if ((undefined === CurrFramePr && undefined === NextFramePr) || ( undefined !== CurrFramePr && undefined !== NextFramePr && true === CurrFramePr.Compare(NextFramePr) ))
						{
							if (true === this.Is_TrackRevisions() && reviewtype_Add !== this.Content[this.CurPos.ContentPos].Get_ReviewType())
							{
								this.Content[this.CurPos.ContentPos].SetReviewType(reviewtype_Remove);
								this.CurPos.ContentPos++;
								this.Content[this.CurPos.ContentPos].MoveCursorToStartPos(false);
							}
							else
							{
								if (true === this.Content[this.CurPos.ContentPos].IsEmpty())
								{
									// Просто удаляем текущий параграф
									this.Internal_Content_Remove(this.CurPos.ContentPos, 1);
									this.Content[this.CurPos.ContentPos].MoveCursorToStartPos(false);
								}
								else
								{
									// Соединяем текущий и следующий параграфы
									var Cur = this.Content[this.CurPos.ContentPos];
									Cur.Concat(this.Content[this.CurPos.ContentPos + 1]);
									this.Internal_Content_Remove(this.CurPos.ContentPos + 1, 1);
								}
							}
						}
					}
					else if (this.CurPos.ContentPos < this.Content.length - 1 && type_BlockLevelSdt === this.Content[this.CurPos.ContentPos + 1].GetType())
					{
						this.CurPos.ContentPos++;
						this.Content[this.CurPos.ContentPos].MoveCursorToStartPos(false);
					}
					else if (true == this.Content[this.CurPos.ContentPos].IsEmpty() && this.CurPos.ContentPos == this.Content.length - 1 && this.CurPos.ContentPos != 0 && type_Paragraph === this.Content[this.CurPos.ContentPos - 1].GetType())
					{
						// Если данный параграф пустой, последний, не единственный и идущий перед
						// ним элемент не таблица, удаляем его
						this.Internal_Content_Remove(this.CurPos.ContentPos, 1);
						this.CurPos.ContentPos--;
						this.Content[this.CurPos.ContentPos].MoveCursorToEndPos(false, false);
					}
					else if (this.CurPos.ContentPos === this.Content.length - 1)
					{
						bRetValue = false;
					}
				}
			}

			var Item = this.Content[this.CurPos.ContentPos];
			if (type_Paragraph === Item.GetType())
			{
				Item.CurPos.RealX = Item.CurPos.X;
				Item.CurPos.RealY = Item.CurPos.Y;
			}
		}
		else if (type_BlockLevelSdt === this.Content[this.CurPos.ContentPos].GetType())
		{
			if (false === this.Content[this.CurPos.ContentPos].Remove(Count, bOnlyText))
			{
				var oLogicDocument = this.GetLogicDocument();
				if (oLogicDocument && true === oLogicDocument.IsFillingFormMode())
				{
					if (Count < 0 && this.CurPos.ContentPos > 0)
						this.Content[this.CurPos.ContentPos].MoveCursorToStartPos(false);
					else
						this.Content[this.CurPos.ContentPos].MoveCursorToEndPos(false);
				}
				else
				{
					if (this.Content[this.CurPos.ContentPos].IsEmpty())
					{
						this.RemoveFromContent(this.CurPos.ContentPos, 1);

						if ((Count < 0 && this.CurPos.ContentPos > 0) || this.CurPos.ContentPos >= this.Content.length)
						{
							this.CurPos.ContentPos--;
							this.Content[this.CurPos.ContentPos].MoveCursorToEndPos(false);
						}
						else
						{
							this.Content[this.CurPos.ContentPos].MoveCursorToStartPos(false);
						}
					}
					else
					{
						if (Count < 0 && this.CurPos.ContentPos > 0)
						{
							this.CurPos.ContentPos--;
							this.Content[this.CurPos.ContentPos].MoveCursorToEndPos(false);
						}
						else if (this.CurPos.ContentPos < this.Content.length - 1)
						{
							this.CurPos.ContentPos++;
							this.Content[this.CurPos.ContentPos].MoveCursorToStartPos(false);
						}
					}
				}
			}
		}
		else
		{
			this.Content[this.CurPos.ContentPos].Remove(Count, bOnlyText);
		}
	}

	return bRetValue;
};
CDocumentContentBase.prototype.IsBlockLevelSdtContent = function()
{
	return false;
};
CDocumentContentBase.prototype.IsBlockLevelSdtFirstOnNewPage = function()
{
	return false;
};
CDocumentContentBase.prototype.private_AddContentControl = function(nContentControlType)
{
	var oElement = this.Content[this.CurPos.ContentPos];

	if (c_oAscSdtLevelType.Block === nContentControlType)
	{
		if (true === this.IsSelectionUse())
		{
			if (this.Selection.StartPos === this.Selection.EndPos
				&& ((type_BlockLevelSdt === this.Content[this.Selection.StartPos].GetType()
				&& true !== this.Content[this.Selection.StartPos].IsSelectedAll())
				|| (type_Table === this.Content[this.Selection.StartPos].GetType()
				&& !this.Content[this.Selection.StartPos].IsCellSelection())))
			{
				return this.Content[this.Selection.StartPos].AddContentControl(nContentControlType);
			}
			else
			{
				var oSdt = new CBlockLevelSdt(editor.WordControl.m_oLogicDocument, this);

				var oLogicDocument = this instanceof CDocument ? this : this.LogicDocument;
				oLogicDocument.RemoveCommentsOnPreDelete = false;

				var nStartPos = this.Selection.StartPos;
				var nEndPos   = this.Selection.EndPos;
				if (nEndPos < nStartPos)
				{
					nEndPos   = this.Selection.StartPos;
					nStartPos = this.Selection.EndPos;
				}

				for (var nIndex = nEndPos; nIndex >= nStartPos; --nIndex)
				{
					oSdt.Content.Add_ToContent(0, this.Content[nIndex]);
					this.Remove_FromContent(nIndex, 1);
				}

				oSdt.Content.Remove_FromContent(oSdt.Content.GetElementsCount() - 1, 1);
				oSdt.Content.Selection.Use      = true;
				oSdt.Content.Selection.StartPos = 0;
				oSdt.Content.Selection.EndPos   = oSdt.Content.GetElementsCount() - 1;

				this.Add_ToContent(nStartPos, oSdt);
				this.Selection.StartPos = nStartPos;
				this.Selection.EndPos   = nStartPos;
				this.CurPos.ContentPos  = nStartPos;

				oLogicDocument.RemoveCommentsOnPreDelete = true;
				return oSdt;
			}
		}
		else
		{
			if (type_Paragraph === oElement.GetType())
			{
				var oSdt = new CBlockLevelSdt(editor.WordControl.m_oLogicDocument, this);

				if (oElement.IsCursorAtBegin())
				{
					this.Internal_Content_Add(this.CurPos.ContentPos, oSdt);
				}
				else if (oElement.IsCursorAtEnd())
				{
					this.Internal_Content_Add(this.CurPos.ContentPos + 1, oSdt);
					this.CurPos.ContentPos = this.CurPos.ContentPos + 1;
				}
				else
				{
					var oNewParagraph = new Paragraph(this.DrawingDocument, this);
					oElement.Split(oNewParagraph);

					this.Internal_Content_Add(this.CurPos.ContentPos + 1, oNewParagraph);
					this.Internal_Content_Add(this.CurPos.ContentPos + 1, oSdt);

					this.CurPos.ContentPos = this.CurPos.ContentPos + 1;
				}
				oSdt.MoveCursorToStartPos(false);
				return oSdt;
			}
			else
			{
				return oElement.AddContentControl(nContentControlType);
			}
		}
	}
	else
	{
		return oElement.AddContentControl(nContentControlType);
	}
};
CDocumentContentBase.prototype.RecalculateAllTables = function()
{
	for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos)
	{
		var Item = this.Content[nPos];
		Item.RecalculateAllTables();
	}
};
CDocumentContentBase.prototype.GetLastRangeVisibleBounds = function()
{
	if (this.Content.length <= 0)
		return {
			X        : 0,
			Y        : 0,
			W        : 0,
			H        : 0,
			BaseLine : 0,
			XLimit   : 0
		};

	return this.Content[this.Content.length - 1].GetLastRangeVisibleBounds();
};
CDocumentContentBase.prototype.FindNextFillingForm = function(isNext, isCurrent, isStart)
{
	var nCurPos = this.Selection.Use === true ? this.Selection.StartPos : this.CurPos.ContentPos;

	var nStartPos = 0;
	var nEndPos   = this.Content.length - 1;

	if (isCurrent)
	{
		if (isStart)
		{
			nStartPos = nCurPos;
			nEndPos   = isNext ? this.Content.length - 1 : 0;
		}
		else
		{
			nStartPos = isNext ? 0 : this.Content.length - 1;
			nEndPos   = nCurPos;
		}
	}
	else
	{
		if (isNext)
		{
			nStartPos = 0;
			nEndPos   = this.Content.length - 1;
		}
		else
		{
			nStartPos = this.Content.length - 1;
			nEndPos   = 0;
		}
	}

	if (isNext)
	{
		for (var nIndex = nStartPos; nIndex <= nEndPos; ++nIndex)
		{
			var oRes = this.Content[nIndex].FindNextFillingForm(true, isCurrent && nIndex === nCurPos ? true : false, isStart);
			if (oRes)
				return oRes;
		}
	}
	else
	{
		for (var nIndex = nStartPos; nIndex >= nEndPos; --nIndex)
		{
			var oRes = this.Content[nIndex].FindNextFillingForm(false, isCurrent && nIndex === nCurPos ? true : false, isStart);
			if (oRes)
				return oRes;

		}
	}

	return null;
};
/**
 * Данный запрос может прийти из внутреннего элемента(параграф, таблица), чтобы узнать происходил ли выделение в
 * пределах одного элеменета.
 * @returns {boolean}
 */
CDocumentContentBase.prototype.IsSelectedSingleElement = function()
{
	return (true === this.Selection.Use && docpostype_Content === this.Get_DocPosType() && this.Selection.Flag === selectionflag_Common && this.Selection.StartPos === this.Selection.EndPos)
};
CDocumentContentBase.prototype.GetOutlineParagraphs = function(arrOutline, oPr)
{
	if (!arrOutline)
		arrOutline = [];

	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		this.Content[nIndex].GetOutlineParagraphs(arrOutline, oPr);
	}

	return arrOutline;
};
/**
 * Обновляем список закладок
 * @param oManager
 */
CDocumentContentBase.prototype.UpdateBookmarks = function(oManager)
{
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		this.Content[nIndex].UpdateBookmarks(oManager);
	}
};
/**
 * @param StartDocPos
 * @param EndDocPos
 */
CDocumentContentBase.prototype.SetSelectionByContentPositions = function(StartDocPos, EndDocPos)
{
	this.RemoveSelection();

	this.Selection.Use   = true;
	this.Selection.Start = false;
	this.Selection.Flag  = selectionflag_Common;

	this.SetContentSelection(StartDocPos, EndDocPos, 0, 0, 0);

	if (this.Parent && this.LogicDocument)
	{
		this.Parent.Set_CurrentElement(false, this.Get_StartPage_Absolute(), this);
		this.LogicDocument.Selection.Use   = true;
		this.LogicDocument.Selection.Start = false;
	}
};
/**
 * Получем количество элементов
 * @return {number}
 */
CDocumentContentBase.prototype.GetElementsCount = function()
{
	return this.Content.length;
};
/**
 * Получаем элемент по заданной позици
 * @param nIndex
 * @returns {?CDocumentContentElementBase}
 */
CDocumentContentBase.prototype.GetElement = function(nIndex)
{
	if (this.Content[nIndex])
		return this.Content[nIndex];

	return null;
};
/**
 * Добавляем новый элемент (с записью в историю)
 * @param nPos
 * @param oItem
 */
CDocumentContentBase.prototype.AddToContent = function(nPos, oItem)
{
	this.Add_ToContent(nPos, oItem);
};
/**
 * Удаляем заданное количество элементов (с записью в историю)
 * @param {number} nPos
 * @param {number} [nCount=1]
 */
CDocumentContentBase.prototype.RemoveFromContent = function(nPos, nCount)
{
	if (undefined === nCount || null === nCount)
		nCount = 1;

	this.Remove_FromContent(nPos, nCount);
};
/**
 * Получаем текущий TableOfContents, это может быть просто поле или поле вместе с оберткой Sdt
 * @param isUnique ищем с параметром Unique = true
 * @param isCheckFields Проверять ли TableOfContents, заданные через сложные поля
 * @returns {CComplexField | CBlockLevelSdt | null}
 */
CDocumentContentBase.prototype.GetTableOfContents = function(isUnique, isCheckFields)
{
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		var oResult = this.Content[nIndex].GetTableOfContents(isUnique, isCheckFields);
		if (oResult)
			return oResult;
	}

	return null;
};
/**
 * Добавляем заданный текст в текущей позиции
 * @param {String} sText
 */
CDocumentContentBase.prototype.AddText = function(sText)
{
	for (var oIterator = sText.getUnicodeIterator(); oIterator.check(); oIterator.next())
	{
		var nCharCode = oIterator.value();

		if (9 === nCharCode) // \t
			this.AddToParagraph(new ParaTab(), false);
		if (10 === nCharCode) // \n
			this.AddToParagraph(new ParaNewLine(break_Line), false);
		else if (13 === nCharCode) // \r
			continue;
		else if (32 === nCharCode) // space
			this.AddToParagraph(new ParaSpace(), false);
		else
			this.AddToParagraph(new ParaText(nCharCode), false);
	}
};
/**
 * Проверяем находимся ли мы заголовке хоть какой-либо таблицы
 * @returns {boolean}
 */
CDocumentContentBase.prototype.IsTableHeader = function()
{
	return false;
};
/**
 * Получаем родительский класс
 */
CDocumentContentBase.prototype.GetParent = function()
{
	return null;
};
/**
 * Получаем последний параграф в данном контенте, если последний элемент не параграф, то запрашиваем у него
 * @returns {?Paragraph}
 */
CDocumentContentBase.prototype.GetLastParagraph = function()
{
	if (this.Content.length <= 0)
		return null;

	return this.Content[this.Content.length - 1].GetLastParagraph();
};
/**
 * Получаем первый параграф в данном контенте, если первый элемент не параграф, то запрашиваем у него
 * @returns {?Paragraph}
 * @constructor
 */
CDocumentContentBase.prototype.GetFirstParagraph = function()
{
	if (this.Content.length <= 0)
		return null;

	return this.Content[0].GetFirstParagraph();
};
/**
 * Получаем параграф, следующий за данным элементом
 * @returns {?Paragraph}
 */
CDocumentContentBase.prototype.GetNextParagraph = function()
{
	var oParent = this.GetParent();
	if (oParent && oParent.GetNextParagraph)
		return oParent.GetNextParagraph();

	return null;
};
/**
 * Получаем параграф, идущий перед данным элементом
 * @returns {?Paragraph}
 */
CDocumentContentBase.prototype.GetPrevParagraph = function()
{
	var oParent = this.GetParent();
	if (oParent && oParent.GetPrevParagraph)
		return oParent.GetPrevParagraph();

	return null;
};
/**
 * Находимся ли мы в колонтитуле
 * @param {boolean} [bReturnHdrFtr=false]
 * @returns {?CHeaderFooter | boolean}
 */
CDocumentContentBase.prototype.IsHdrFtr = function(bReturnHdrFtr)
{
	if (true === bReturnHdrFtr)
		return null;

	return false;
};
/**
 * Находимся ли мы в сноске
 * @param {boolean} [bReturnFootnote=false]
 * @returns {?CFootEndnote | boolean}
 */
CDocumentContentBase.prototype.IsFootnote = function(bReturnFootnote)
{
	if (bReturnFootnote)
		return null;

	return false;
};
/**
 * Проверяем находимся ли мы в последней ячейке таблицы
 * @param {boolean} isSelection
 * @returns {boolean}
 */
CDocumentContentBase.prototype.IsLastTableCellInRow = function(isSelection)
{
	return false;
};
/**
 * Получаем ссылку на главный класс нумерации
 * @returns {?CNumbering}
 */
CDocumentContentBase.prototype.GetNumbering = function()
{
	return null;
};
/**
 * Получаем верхний класс CDocumentContent
 * @returns {CDocumentContentBase}
 */
CDocumentContentBase.prototype.GetTopDocumentContent = function()
{
	return this;
};
/**
 * Получаем массив параграфов по заданному критерию
 * @param oProps
 * @param [arrParagraphs=undefined]
 * @returns {Paragraph[]}
 */
CDocumentContentBase.prototype.GetAllParagraphs = function(oProps, arrParagraphs)
{
	if (!arrParagraphs)
		arrParagraphs = [];

	return arrParagraphs;
};
/**
 * Получаем массив всех параграфов с заданной нумерацией
 * @param oNumPr {CNumPr | CNumPr[]}
 * @returns {Paragraph[]}
 */
CDocumentContentBase.prototype.GetAllParagraphsByNumbering = function(oNumPr)
{
	return this.GetAllParagraphs({Numbering : true, NumPr : oNumPr});
};
/**
 * Получаем массив параграфов из списка заданных стилей
 * @param arrStylesId {string[]}
 * @returns {Paragraph[]}
 */
CDocumentContentBase.prototype.GetAllParagraphsByStyle = function(arrStylesId)
{
	return this.GetAllParagraphs({Style : true, StylesId : arrStylesId});
};
/**
 * Выделяем заданную нумерацию
 * @param oNumPr {CNumPr}
 * @param oPara {Paragraph} - текущий парограф
 */
CDocumentContentBase.prototype.SelectNumbering = function(oNumPr, oPara)
{
	var oTopDocContent = this.GetTopDocumentContent();
	if (oTopDocContent === this)
	{
		this.RemoveSelection();

		oPara.Document_SetThisElementCurrent(false);

		this.Selection.Use      = true;
		this.Selection.Flag     = selectionflag_Numbering;
		this.Selection.StartPos = this.CurPos.ContentPos;
		this.Selection.EndPos   = this.CurPos.ContentPos;

		var arrParagraphs = this.GetAllParagraphsByNumbering(oNumPr);

		this.Selection.Data = {
			Paragraphs : arrParagraphs,
			CurPara    : oPara
		};

		for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
		{
			arrParagraphs[nIndex].SelectNumbering(arrParagraphs[nIndex] === oPara);
		}

		this.DrawingDocument.SelectEnabled(true);

		var oLogicDocument = this.GetLogicDocument();
		oLogicDocument.Document_UpdateSelectionState();
		oLogicDocument.Document_UpdateInterfaceState();
	}
	else
	{
		oTopDocContent.SelectNumbering(oNumPr, oPara);
	}
};
/**
 * Проверяем является ли текущее выделение выделением нумерации
 * @returns {boolean}
 */
CDocumentContentBase.prototype.IsNumberingSelection = function()
{
	return !!(this.IsSelectionUse() && this.Selection.Flag === selectionflag_Numbering);
};
/**
 * Убираем селект с нумерации
 */
CDocumentContentBase.prototype.RemoveNumberingSelection = function()
{
	if (this.IsNumberingSelection())
		this.RemoveSelection();
};
/**
 * Рассчитываем значение нумерованного списка для заданной нумерации
 * @param oPara {Paragraph}
 * @param oNumPr {CNumPr}
 * @returns {number[]}
 */
CDocumentContentBase.prototype.CalculateNumberingValues = function(oPara, oNumPr)
{
	var oTopDocument = this.GetTopDocumentContent();
	if (oTopDocument instanceof CFootEndnote)
		return oTopDocument.Parent.GetNumberingInfo(oPara, oNumPr, oTopDocument);

	return oTopDocument.GetNumberingInfo(null, oPara, oNumPr);
};
/**
 * Вплоть до заданного параграфа ищем последнюю похожую нумерацию
 * @param oContinueEngine {CDocumentNumberingContinueEngine}
 */
CDocumentContentBase.prototype.GetSimilarNumbering = function(oContinueEngine)
{
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		this.Content[nIndex].GetSimilarNumbering(oContinueEngine);

		if (oContinueEngine.IsFound())
			break;
	}
};


/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// TODO: Сейчас Paragraph.Recalculate_FastWholeParagraph работает только на добавлении текста, надо переделать
//       алгоритм определения изменений, чтобы данная функция работала и при других изменениях.

// Import
var c_oAscLineDrawingRule = AscCommon.c_oAscLineDrawingRule;
var align_Left = AscCommon.align_Left;
var hdrftr_Header = AscCommon.hdrftr_Header;
var hdrftr_Footer = AscCommon.hdrftr_Footer;
var c_oAscFormatPainterState = AscCommon.c_oAscFormatPainterState;
var changestype_None = AscCommon.changestype_None;
var changestype_Paragraph_Content = AscCommon.changestype_Paragraph_Content;
var changestype_2_Element_and_Type = AscCommon.changestype_2_Element_and_Type;
var changestype_2_ElementsArray_and_Type = AscCommon.changestype_2_ElementsArray_and_Type;
var g_oTableId = AscCommon.g_oTableId;
var History = AscCommon.History;

var c_oAscHAnchor = Asc.c_oAscHAnchor;
var c_oAscXAlign = Asc.c_oAscXAlign;
var c_oAscYAlign = Asc.c_oAscYAlign;
var c_oAscVAnchor = Asc.c_oAscVAnchor;

var Page_Width     = 210;
var Page_Height    = 297;

var X_Left_Margin   = 30;  // 3   cm
var X_Right_Margin  = 15;  // 1.5 cm
var Y_Bottom_Margin = 20;  // 2   cm
var Y_Top_Margin    = 20;  // 2   cm

var X_Right_Field  = Page_Width  - X_Right_Margin;
var Y_Bottom_Field = Page_Height - Y_Bottom_Margin;

var docpostype_Content        = 0x00;
var docpostype_HdrFtr         = 0x02;
var docpostype_DrawingObjects = 0x03;
var docpostype_Footnotes      = 0x04;

var selectionflag_Common        = 0x000;
var selectionflag_Numbering     = 0x001; // Выделена нумерация
var selectionflag_NumberingCur  = 0x002; // Выделена нумерация и данный параграф является текущим

var search_Common              = 0x0000; // Поиск в простом тексте
var search_Header              = 0x0100; // Поиск в верхнем колонтитуле
var search_Footer              = 0x0200; // Поиск в нижнем колонтитуле
var search_Footnote            = 0x0400; // Поиск в сноске

var search_HdrFtr_All          = 0x0001; // Поиск в колонтитуле, который находится на всех страницах
var search_HdrFtr_All_no_First = 0x0002; // Поиск в колонтитуле, который находится на всех страницах, кроме первой
var search_HdrFtr_First        = 0x0003; // Поиск в колонтитуле, который находится только на первой страниц
var search_HdrFtr_Even         = 0x0004; // Поиск в колонтитуле, который находится только на четных страницах
var search_HdrFtr_Odd          = 0x0005; // Поиск в колонтитуле, который находится только на нечетных страницах, включая первую
var search_HdrFtr_Odd_no_First = 0x0006; // Поиск в колонтитуле, который находится только на нечетных страницах, кроме первой

// Типы которые возвращают классы CParagraph и CTable после пересчета страницы
var recalcresult_NextElement = 0x01; // Пересчитываем следующий элемент
var recalcresult_PrevPage    = 0x02; // Пересчитываем заново предыдущую страницу
var recalcresult_CurPage     = 0x04; // Пересчитываем заново текущую страницу
var recalcresult_NextPage    = 0x08; // Пересчитываем следующую страницу
var recalcresult_NextLine    = 0x10; // Пересчитываем следующую строку
var recalcresult_CurLine     = 0x20; // Пересчитываем текущую строку
var recalcresult_CurPagePara = 0x40; // Специальный случай, когда мы встретили картинку в начале параграфа
var recalcresult_PrevLine    = 0x80; // Пересчитываем заново предыдущую строку (мб даже раньше, это должно идти в PRSW)

var recalcresultflags_Column            = 0x010000; // Пересчитываем только колонку
var recalcresultflags_Page              = 0x020000; // Пересчитываем всю страницу
var recalcresultflags_LastFromNewPage   = 0x040000; // Используется совсместно с recalcresult_NextPage, означает, что начало последнего элемента нужно перенести на новую страницу
var recalcresultflags_LastFromNewColumn = 0x080000; // Используется совсместно с recalcresult_NextPage, означает, что начало последнего элемента нужно перенести на новую колонку
var recalcresultflags_Footnotes         = 0x010000; // Сообщаем, что необходимо пересчитать сноски на данной странице

// Типы которые возвращают классы CDocument и CDocumentContent после пересчета страницы
var recalcresult2_End      = 0x00; // Документ рассчитан до конца
var recalcresult2_NextPage = 0x01; // Рассчет нужно продолжить
var recalcresult2_CurPage  = 0x02; // Нужно заново пересчитать данную страницу

var document_EditingType_Common = 0x00; // Обычный режим редактирования
var document_EditingType_Review = 0x01; // Режим рецензирования

var keydownflags_PreventDefault  = 0x0001;
var keydownflags_PreventKeyPress = 0x0002;

var keydownresult_PreventNothing  = 0x0000;
var keydownresult_PreventDefault  = 0x0001;
var keydownresult_PreventKeyPress = 0x0002;
var keydownresult_PreventAll      = 0xFFFF;

var MEASUREMENT_MAX_MM_VALUE = 1000; // Маскимальное значение в мм, используемое в документе (MS Word) - 55,87 см, или 558,7 мм.

function CDocumentColumnProps()
{
    this.W     = 0;
    this.Space = 0;
}
CDocumentColumnProps.prototype.put_W = function(W)
{
    this.W = W;
};
CDocumentColumnProps.prototype.get_W = function()
{
    return this.W;
};
CDocumentColumnProps.prototype.put_Space = function(Space)
{
    this.Space = Space;
};
CDocumentColumnProps.prototype.get_Space = function()
{
    return this.Space;
};

function CDocumentColumnsProps()
{
    this.EqualWidth = true;
    this.Num        = 1;
    this.Sep        = false;
    this.Space      = 30;

    this.Cols       = [];

    this.TotalWidth = 230;
}
CDocumentColumnsProps.prototype.From_SectPr = function(SectPr)
{
    var Columns = SectPr.Columns;

    this.TotalWidth = SectPr.Get_PageWidth() - SectPr.Get_PageMargin_Left() - SectPr.Get_PageMargin_Right();
    this.EqualWidth = Columns.EqualWidth;
    this.Num        = Columns.Num;
    this.Sep        = Columns.Sep;
    this.Space      = Columns.Space;

    for (var Index = 0, Count = Columns.Cols.length; Index < Count; ++Index)
    {
        var Col = new CDocumentColumnProps();
        Col.put_W(Columns.Cols[Index].W);
        Col.put_Space(Columns.Cols[Index].Space);
        this.Cols[Index] = Col;
    }
};
CDocumentColumnsProps.prototype.get_EqualWidth = function()
{
    return this.EqualWidth;
};
CDocumentColumnsProps.prototype.put_EqualWidth = function(EqualWidth)
{
    this.EqualWidth = EqualWidth;
};
CDocumentColumnsProps.prototype.get_Num = function()
{
    return this.Num;
};
CDocumentColumnsProps.prototype.put_Num = function(Num)
{
    this.Num = Num;
};
CDocumentColumnsProps.prototype.get_Sep = function()
{
    return this.Sep;
};
CDocumentColumnsProps.prototype.put_Sep = function(Sep)
{
    this.Sep = Sep;
};
CDocumentColumnsProps.prototype.get_Space = function()
{
    return this.Space;
};
CDocumentColumnsProps.prototype.put_Space = function(Space)
{
    this.Space = Space;
};
CDocumentColumnsProps.prototype.get_ColsCount = function()
{
    return this.Cols.length;
};
CDocumentColumnsProps.prototype.get_Col = function(Index)
{
    return this.Cols[Index];
};
CDocumentColumnsProps.prototype.put_Col = function(Index, Col)
{
    this.Cols[Index] = Col;
};
CDocumentColumnsProps.prototype.put_ColByValue = function(Index, W, Space)
{
    var Col = new CDocumentColumnProps();
    Col.put_W(W);
    Col.put_Space(Space);
    this.Cols[Index] = Col;
};
CDocumentColumnsProps.prototype.get_TotalWidth = function()
{
    return this.TotalWidth;
};

function CDocumentSectionProps(SectPr)
{
    if (SectPr)
    {
        this.W      = SectPr.Get_PageWidth();
        this.H      = SectPr.Get_PageHeight();
        this.Orient = SectPr.Get_Orientation();

        this.Left   = SectPr.Get_PageMargin_Left();
        this.Top    = SectPr.Get_PageMargin_Top();
        this.Right  = SectPr.Get_PageMargin_Right();
        this.Bottom = SectPr.Get_PageMargin_Bottom();

        this.Header = SectPr.Get_PageMargins_Header();
        this.Footer = SectPr.Get_PageMargins_Footer();
    }
    else
    {
        this.W      = undefined;
        this.H      = undefined;
        this.Orient = undefined;

        this.Left   = undefined;
        this.Top    = undefined;
        this.Right  = undefined;
        this.Bottom = undefined;

        this.Header = undefined;
        this.Footer = undefined;
    }
}
CDocumentSectionProps.prototype.get_W = function()
{
    return this.W;
};
CDocumentSectionProps.prototype.put_W = function(W)
{
    this.W = W;
};
CDocumentSectionProps.prototype.get_H = function()
{
    return this.H;
};
CDocumentSectionProps.prototype.put_H = function(H)
{
    this.H = H;
};
CDocumentSectionProps.prototype.get_Orientation = function()
{
    return this.Orient;
};
CDocumentSectionProps.prototype.put_Orientation = function(Orient)
{
    this.Orient = Orient;
};
CDocumentSectionProps.prototype.get_LeftMargin = function()
{
    return this.Left;
};
CDocumentSectionProps.prototype.put_LeftMargin = function(Left)
{
    this.Left = Left;
};
CDocumentSectionProps.prototype.get_TopMargin = function()
{
    return this.Top;
};
CDocumentSectionProps.prototype.put_TopMargin = function(Top)
{
    this.Top = Top;
};
CDocumentSectionProps.prototype.get_RightMargin = function()
{
    return this.Right;
};
CDocumentSectionProps.prototype.put_RightMargin = function(Right)
{
    this.Right = Right;
};
CDocumentSectionProps.prototype.get_BottomMargin = function()
{
    return this.Bottom;
};
CDocumentSectionProps.prototype.put_BottomMargin = function(Bottom)
{
    this.Bottom = Bottom;
};
CDocumentSectionProps.prototype.get_HeaderDistance = function()
{
    return this.Header;
};
CDocumentSectionProps.prototype.put_HeaderDistance = function(Header)
{
    this.Header = Header;
};
CDocumentSectionProps.prototype.get_FooterDistance = function()
{
    return this.Footer;
};
CDocumentSectionProps.prototype.put_FooterDistance = function(Footer)
{
    this.Footer = Footer;
};

function CSelectedElement(Element, SelectedAll)
{
    this.Element     = Element;
    this.SelectedAll = SelectedAll;
}

function CSelectedContent()
{
    this.Elements = [];

    this.DrawingObjects = [];
    this.Comments       = [];
    this.Maths          = [];

    this.HaveShape        = false;
    this.MoveDrawing      = false; // Только для переноса автофигур
    this.HaveMath         = false;
    this.HaveTable        = false;
    this.CanConvertToMath = false;

    this.InsertOptions = {
    	Table : Asc.c_oSpecialPasteProps.overwriteCells
	};
}

CSelectedContent.prototype =
{
    Reset : function()
    {
        this.Elements = [];

        this.DrawingObjects = [];
        this.Comments       = [];
        this.Maths          = [];

        this.HaveShape   = false;
        this.MoveDrawing = false; // Только для переноса автофигур
        this.HaveMath    = false;
    },

    Add : function(Element)
    {
        this.Elements.push( Element );
    },

    Set_MoveDrawing : function(Value)
    {
        this.MoveDrawing = Value;
    },

    On_EndCollectElements : function(LogicDocument, bFromCopy)
    {
        // Теперь пройдемся по всем найденным элементам и выясним есть ли автофигуры и комментарии
        var Count = this.Elements.length;

        var isNonParagraph = false;
        for (var Pos = 0; Pos < Count; Pos++)
        {
            var Element = this.Elements[Pos].Element;
            Element.GetAllDrawingObjects(this.DrawingObjects);
            Element.GetAllComments(this.Comments);
            Element.GetAllMaths(this.Maths);

            var nElementType = Element.GetType();

			if (type_Paragraph === nElementType && Count > 1)
				Element.Correct_Content();

			if (type_Table === nElementType)
				this.HaveTable = true;

			if (type_Paragraph !== nElementType)
				isNonParagraph = true;
        }

        this.HaveMath = (this.Maths.length > 0 ? true : false);

        // Проверка возможности конвертации имеющегося контента в контент для вставки в формулу.
		// Если формулы уже имеются, то ничего не конвертируем.
		if (!this.HaveMath && !isNonParagraph)
		{
			this.CanConvertToMath = true;
		}

        // Относительно картинок нас интересует только наличие автофигур с текстом.
        Count = this.DrawingObjects.length;
        for (var Pos = 0; Pos < Count; Pos++)
        {
            var DrawingObj = this.DrawingObjects[Pos];
            var ShapeType = DrawingObj.GraphicObj.getObjectType();

            if ( AscDFH.historyitem_type_Shape === ShapeType || AscDFH.historyitem_type_GroupShape === ShapeType )
            {
                this.HaveShape = true;
                break;
            }
        }

        // Если у комментария присутствует только начало или конец, тогда такой комментарий мы удяляем отсюда
        var Comments = {};
        Count = this.Comments.length;
        for (var Pos = 0; Pos < Count; Pos++)
        {
            var Element = this.Comments[Pos];

            var Id = Element.Comment.CommentId;
            if ( undefined === Comments[Id] )
                Comments[Id] = {};

            if ( true === Element.Comment.Start )
                Comments[Id].Start = Element.Paragraph;
            else
                Comments[Id].End   = Element.Paragraph;
        }

        // Пробегаемся по найденным комментариям и удаляем те, у которых нет начала или конца
        var NewComments = [];
        for (var Id in Comments)
        {
            var Element = Comments[Id];

            var Para = null;
            if ( undefined === Element.Start && undefined !== Element.End )
                Para = Element.End;
            else if ( undefined !== Element.Start && undefined === Element.End )
                Para = Element.Start;
            else if ( undefined !== Element.Start && undefined !== Element.End )
                NewComments.push(Id);

            if (null !== Para)
            {
                var OldVal = Para.DeleteCommentOnRemove;
                Para.DeleteCommentOnRemove = false;
                Para.RemoveCommentMarks(Id);
                Para.DeleteCommentOnRemove = OldVal;
            }
        }

        if (true !== bFromCopy)
        {
            // Новые комментарии мы дублируем и добавляем в список комментариев
            Count = NewComments.length;
            var Count2 = this.Comments.length;
            var DocumentComments = LogicDocument.Comments;
            for (var Pos = 0; Pos < Count; Pos++)
            {
                var Id = NewComments[Pos];
                var OldComment = DocumentComments.Get_ById(Id);

                if (null !== OldComment)
                {
                    var NewComment = OldComment.Copy();

                    if (History.Is_On())
                    {
                        DocumentComments.Add(NewComment);
                        editor.sync_AddComment(NewComment.Get_Id(), NewComment.Data);

                        // поправим Id в самих элементах ParaComment
                        for (var Pos2 = 0; Pos2 < Count2; Pos2++)
                        {
                            var Element = this.Comments[Pos2].Comment;
                            if (Id === Element.CommentId)
                            {
                                Element.Set_CommentId(NewComment.Get_Id());
                            }
                        }
                    }
                }
            }
        }
    }
};
CSelectedContent.prototype.SetInsertOptionForTable = function(nType)
{
	this.InsertOptions.Table = nType;
};
/**
 * Converts current content to ParaMath if it possible. Doesn't change current SelectedContent.
 * @returns {?AscCommonWord.ParaMath}
 * */
CSelectedContent.prototype.ConvertToMath = function()
{
	if (!this.CanConvertToMath)
		return null;

	var oParaMath = new AscCommonWord.ParaMath();
	oParaMath.Root.Remove_FromContent(0, oParaMath.Root.GetElementsCount());

	for (var nParaIndex = 0, nParasCount = this.Elements.length, nRunPos = 0; nParaIndex < nParasCount; ++nParaIndex)
	{
		var oParagraph = this.Elements[nParaIndex].Element;
		if (type_Paragraph !== oParagraph.GetType())
			continue;

		for (var nInParaPos = 0; nInParaPos < oParagraph.GetElementsCount(); ++nInParaPos)
		{
			var oElement = oParagraph.Content[nInParaPos];
			if (para_Run === oElement.GetType())
			{
				var oRun = new ParaRun(oParagraph, true);
				oParaMath.Root.Add_ToContent(nRunPos++, oRun);

				for (var nInRunPos = 0, nCount = oElement.GetElementsCount(); nInRunPos < nCount; ++nInRunPos)
				{
					var oItem = oElement.Content[nInRunPos];
					if (para_Text === oItem.Type)
					{
						if (38 === oItem.Value)
						{
							oRun.Add(new CMathAmp(), true);
						}
						else
						{
							var oMathText = new CMathText(false);
							oMathText.add(oItem.Value);
							oRun.Add(oMathText, true);
						}
					}
					else if (para_Space === oItem.Value)
					{
						var oMathText = new CMathText(false);
						oMathText.add(0x0032);
						oRun.Add(oMathText, true);
					}
				}

				oRun.Apply_Pr(oElement.Get_TextPr());
			}
		}
	}

	oParaMath.Root.Correct_Content(true);
	return oParaMath;
};

function CDocumentRecalculateState()
{
    this.Id           = null;

    this.PageIndex    = 0;
    this.SectionIndex = 0;
    this.ColumnIndex  = 0;
    this.Start        = true;
    this.StartIndex   = 0;
    this.StartPage    = 0;

    this.ResetStartElement = false;
    this.MainStartPos      = -1;
}

function CDocumentRecalculateHdrFtrPageCountState()
{
	this.Id        = null;
	this.PageIndex = 0;
	this.PageCount = -1;
}

function Document_Recalculate_Page()
{
    var LogicDocument = editor.WordControl.m_oLogicDocument;
    LogicDocument.Recalculate_Page();
}

function Document_Recalculate_HdrFtrPageCount()
{
	var LogicDocument = editor.WordControl.m_oLogicDocument;
	LogicDocument.private_RecalculateHdrFtrPageCountUpdate();
}

function CDocumentPageSection()
{
    this.Pos    = 0;
    this.EndPos = -1;

    this.Y      = 0;
    this.YLimit = 0;

    this.YLimit2 = 0;

    this.Columns = [];
    this.ColumnsSep = false;

    this.IterationsCount          = 0;
    this.CurrentY                 = 0;
    this.CanRecalculateBottomLine = true;
}
CDocumentPageSection.prototype.Copy = function()
{
    var NewSection = new CDocumentPageSection();

    NewSection.Pos    = this.Pos;
    NewSection.EndPos = this.EndPos;
    NewSection.Y      = this.Y;
    NewSection.YLimit = this.YLimit;

    for (var ColumnIndex = 0, Count = this.Columns.length; ColumnIndex < Count; ++ColumnIndex)
    {
		NewSection.Columns[ColumnIndex] = this.Columns[ColumnIndex].Copy();
    }

    return NewSection;
};
CDocumentPageSection.prototype.Shift = function(Dx, Dy)
{
    this.Y      += Dy;
    this.YLimit += Dy;

    for (var ColumnIndex = 0, Count = this.Columns.length; ColumnIndex < Count; ++ColumnIndex)
    {
        this.Columns[ColumnIndex].Shift(Dx, Dy);
    }
};
CDocumentPageSection.prototype.Is_CalculatingSectionBottomLine = function()
{
    if (this.IterationsCount > 0 && true === this.CanRecalculateBottomLine)
        return true;

    return false;
};
CDocumentPageSection.prototype.Can_RecalculateBottomLine = function()
{
    return this.CanRecalculateBottomLine;
};
CDocumentPageSection.prototype.Get_Y = function()
{
    return this.Y;
};
CDocumentPageSection.prototype.Get_YLimit = function()
{
    if (0 === this.IterationsCount)
        return this.YLimit;
    else
        return this.CurrentY;
};
CDocumentPageSection.prototype.Calculate_BottomLine = function(isIncrease)
{
    if (0 === this.IterationsCount)
    {
        var SumHeight = 0;
        for (var ColumnIndex = 0, ColumnsCount = this.Columns.length; ColumnIndex < ColumnsCount; ++ColumnIndex)
        {
            if (true !== this.Columns[ColumnIndex].Empty)
            {
                SumHeight += this.Columns[ColumnIndex].Bounds.Bottom - this.Y;
            }
        }

        this.CurrentY = this.Y + SumHeight / ColumnsCount;
    }
    else
    {
        if (false === isIncrease)
            this.CurrentY -= 5;
        else
            this.CurrentY += 5;
    }

    this.CurrentY = Math.min(this.CurrentY, this.YLimit2);

    this.IterationsCount++;
    return this.CurrentY;
};
CDocumentPageSection.prototype.Reset_Columns = function()
{
    for (var ColumnIndex = 0, Count = this.Columns.length; ColumnIndex < Count; ++ColumnIndex)
    {
        this.Columns[ColumnIndex].Reset();
    }
};
CDocumentPageSection.prototype.DoNotRecalc_BottomLine = function()
{
    this.CanRecalculateBottomLine = false;
};

function CDocumentPageColumn()
{
    this.Bounds = new CDocumentBounds(0, 0, 0, 0);
    this.Pos    = 0;
    this.EndPos = -1;
    this.Empty  = true;

    this.X      = 0;
    this.Y      = 0;
    this.XLimit = 0;
    this.YLimit = 0;

    this.SpaceBefore = 0;
    this.SpaceAfter  = 0;
}
CDocumentPageColumn.prototype.Copy = function()
{
    var NewColumn = new CDocumentPageColumn();

    NewColumn.Bounds.CopyFrom(this.Bounds);
    NewColumn.Pos    = this.Pos;
    NewColumn.EndPos = this.EndPos;
    NewColumn.X      = this.X;
    NewColumn.Y      = this.Y;
    NewColumn.XLimit = this.XLimit;
    NewColumn.YLimit = this.YLimit;

    return NewColumn;
};
CDocumentPageColumn.prototype.Shift = function(Dx, Dy)
{
    this.X      += Dx;
    this.XLimit += Dx;
    this.Y      += Dy;
    this.YLimit += Dy;

    this.Bounds.Shift(Dx, Dy);
};
CDocumentPageColumn.prototype.Reset = function()
{
    this.Bounds.Reset();
    this.Pos    = 0;
    this.EndPos = -1;
    this.Empty  = true;

    this.X      = 0;
    this.Y      = 0;
    this.XLimit = 0;
    this.YLimit = 0;
};
CDocumentPageColumn.prototype.IsEmpty = function()
{
	return this.Empty;
};

function CDocumentPage()
{
    this.Width   = 0;
    this.Height  = 0;
    this.Margins =
    {
        Left   : 0,
        Right  : 0,
        Top    : 0,
        Bottom : 0
    };

    this.Bounds = new CDocumentBounds(0,0,0,0);
    this.Pos    = 0;
    this.EndPos = -1;

    this.X      = 0;
    this.Y      = 0;
    this.XLimit = 0;
    this.YLimit = 0;

    this.Sections = [];

    this.EndSectionParas = [];

    this.ResetStartElement = false;
}

CDocumentPage.prototype.Update_Limits = function(Limits)
{
    this.X      = Limits.X;
    this.XLimit = Limits.XLimit;
    this.Y      = Limits.Y;
    this.YLimit = Limits.YLimit;
};
CDocumentPage.prototype.Shift = function(Dx, Dy)
{
    this.X      += Dx;
    this.XLimit += Dx;
    this.Y      += Dy;
    this.YLimit += Dy;

    this.Bounds.Shift(Dx, Dy);

    for (var SectionIndex = 0, Count = this.Sections.length; SectionIndex < Count; ++SectionIndex)
    {
        this.Sections[SectionIndex].Shift(Dx, Dy);
    }
};
CDocumentPage.prototype.Check_EndSectionPara = function(Element)
{
    var Count = this.EndSectionParas.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        if ( Element === this.EndSectionParas[Index] )
            return true;
    }

    return false;
};
CDocumentPage.prototype.Copy = function()
{
    var NewPage = new CDocumentPage();

    NewPage.Width          = this.Width;
    NewPage.Height         = this.Height;
    NewPage.Margins.Left   = this.Margins.Left;
    NewPage.Margins.Right  = this.Margins.Right;
    NewPage.Margins.Top    = this.Margins.Top;
    NewPage.Margins.Bottom = this.Margins.Bottom;

    NewPage.Bounds.CopyFrom(this.Bounds);
    NewPage.Pos    = this.Pos;
    NewPage.EndPos = this.EndPos;
    NewPage.X      = this.X;
    NewPage.Y      = this.Y;
    NewPage.XLimit = this.XLimit;
    NewPage.YLimit = this.YLimit;

    for (var SectionIndex = 0, Count = this.Sections.length; SectionIndex < Count; ++SectionIndex)
    {
        NewPage.Sections[SectionIndex] = this.Sections[SectionIndex].Copy();
    }

    return NewPage;
};

function CStatistics(LogicDocument)
{
    this.LogicDocument = LogicDocument;
    this.Api           = LogicDocument.Get_Api();

    this.Id       = null; // Id таймера для подсчета всего кроме страниц
    this.PagesId  = null; // Id таймера для подсчета страниц

    this.StartPos = 0;

    this.Pages           = 0;
    this.Words           = 0;
    this.Paragraphs      = 0;
    this.SymbolsWOSpaces = 0;
    this.SymbolsWhSpaces = 0;
}

CStatistics.prototype =
{
//-----------------------------------------------------------------------------------
// Функции для запуска и остановки сбора статистики
//-----------------------------------------------------------------------------------
    Start : function()
    {
        this.StartPos = 0;
        this.CurPage  = 0;

        this.Pages           = 0;
        this.Words           = 0;
        this.Paragraphs      = 0;
        this.SymbolsWOSpaces = 0;
        this.SymbolsWhSpaces = 0;


        var LogicDocument = this.LogicDocument;
        this.PagesId = setTimeout(function(){LogicDocument.Statistics_GetPagesInfo();}, 1);
        this.Id      = setTimeout(function(){LogicDocument.Statistics_GetParagraphsInfo();}, 1);
        this.Send();
    },

    Next_ParagraphsInfo : function(StartPos)
    {
        this.StartPos = StartPos;
        var LogicDocument = this.LogicDocument;
        clearTimeout(this.Id);
        this.Id = setTimeout(function(){LogicDocument.Statistics_GetParagraphsInfo();}, 1);
        this.Send();
    },

    Next_PagesInfo : function()
    {
        var LogicDocument = this.LogicDocument;
        clearTimeout(this.PagesId);
        this.PagesId = setTimeout(function(){LogicDocument.Statistics_GetPagesInfo();}, 100);
        this.Send();
    },

    Stop_PagesInfo : function()
    {
        if (null !== this.PagesId)
        {
            clearTimeout(this.PagesId);
            this.PagesId = null;
        }

        this.Check_Stop();
    },

    Stop_ParagraphsInfo : function()
    {
        if (null != this.Id)
        {
            clearTimeout(this.Id);
            this.Id = null;
        }

        this.Check_Stop();
    },

    Check_Stop : function()
    {
        if (null === this.Id && null === this.PagesId)
        {
            this.Send();
            this.Api.sync_GetDocInfoEndCallback();
        }
    },

    Send : function()
    {
        var Stats =
        {
            PageCount      : this.Pages,
            WordsCount     : this.Words,
            ParagraphCount : this.Paragraphs,
            SymbolsCount   : this.SymbolsWOSpaces,
            SymbolsWSCount : this.SymbolsWhSpaces
        };

        this.Api.sync_DocInfoCallback(Stats);
    },
//-----------------------------------------------------------------------------------
// Функции для пополнения статистики
//-----------------------------------------------------------------------------------
    Add_Paragraph : function (Count)
    {
        if ( "undefined" != typeof( Count ) )
            this.Paragraphs += Count;
        else
            this.Paragraphs++;
    },

    Add_Word : function(Count)
    {
        if ( "undefined" != typeof( Count ) )
            this.Words += Count;
        else
            this.Words++;
    },

    Update_Pages : function(PagesCount)
    {
        this.Pages = PagesCount;
    },

    Add_Symbol : function(bSpace)
    {
        this.SymbolsWhSpaces++;
        if ( true != bSpace )
            this.SymbolsWOSpaces++;
    }
};

function CDocumentRecalcInfo()
{
    this.FlowObject                = null;   // Текущий float-объект, который мы пересчитываем
    this.FlowObjectPageBreakBefore = false;  // Нужно ли перед float-объектом поставить pagebreak
    this.FlowObjectPage            = 0;      // Количество обработанных страниц
    this.FlowObjectElementsCount   = 0;      // Количество элементов подряд идущих в рамке (только для рамок)
    this.RecalcResult              = recalcresult_NextElement;

    this.WidowControlParagraph     = null;   // Параграф, который мы пересчитываем из-за висячих строк
    this.WidowControlLine          = -1;     // Номер строки, перед которой надо поставить разрыв страницы
    this.WidowControlReset         = false;  //

    this.KeepNextParagraph         = null;    // Параграф, который надо пересчитать из-за того, что следующий начался с новой страницы
    this.KeepNextEndParagraph      = null;    // Параграф, на котором определилось, что нужно делать пересчет предыдущих

    this.FrameRecalc               = false;   // Пересчитываем ли рамку
    this.ParaMath                  = null;

    this.FootnoteReference         = null;    // Ссылка на сноску, которую мы пересчитываем
    this.FootnotePage              = 0;
    this.FootnoteColumn            = 0;

    this.AdditionalInfo            = null;

    this.NeedRecalculateFromStart  = false;
}

CDocumentRecalcInfo.prototype =
{
    Reset : function()
    {
        this.FlowObject                = null;
        this.FlowObjectPageBreakBefore = false;
        this.FlowObjectPage            = 0;
        this.FlowObjectElementsCount   = 0;
        this.RecalcResult              = recalcresult_NextElement;

        this.WidowControlParagraph     = null;
        this.WidowControlLine          = -1;
        this.WidowControlReset         = false;

        this.KeepNextParagraph         = null;
        this.KeepNextEndParagraph      = null;

        this.ParaMath                  = null;

        this.FootnoteReference         = null;
        this.FootnotePage              = 0;
        this.FootnoteColumn            = 0;
    },

    Can_RecalcObject : function()
    {
        if (null === this.FlowObject && null === this.WidowControlParagraph && null === this.KeepNextParagraph && null == this.ParaMath && null === this.FootnoteReference)
            return true;

        return false;
    },

    Can_RecalcWidowControl : function()
    {
        // TODO: Пока нельзя отдельно проверять объекты, вызывающие пересчет страниц, потому что возможны зависания.
        //       Надо обдумать новую более грамотную схему, при которой можно будет вызывать независимые пересчеты заново.
        return this.Can_RecalcObject();
    },

    Set_FlowObject : function(Object, RelPage, RecalcResult, ElementsCount, AdditionalInfo)
    {
        this.FlowObject              = Object;
        this.FlowObjectPage          = RelPage;
        this.FlowObjectElementsCount = ElementsCount;
        this.RecalcResult            = RecalcResult;
        this.AdditionalInfo          = AdditionalInfo;
    },

    Set_ParaMath : function(Object)
    {
        this.ParaMath = Object;
    },

    Check_ParaMath: function(ParaMath)
    {
        if ( ParaMath === this.ParaMath )
            return true;

        return false;
    },

    Check_FlowObject : function(FlowObject)
    {
        if ( FlowObject === this.FlowObject )
            return true;

        return false;
    },

    Set_PageBreakBefore : function(Value)
    {
        this.FlowObjectPageBreakBefore = Value;
    },

    Is_PageBreakBefore : function()
    {
        return this.FlowObjectPageBreakBefore;
    },

    Set_KeepNext : function(Paragraph, EndParagraph)
    {
        this.KeepNextParagraph    = Paragraph;
        this.KeepNextEndParagraph = EndParagraph;
    },

    Check_KeepNext : function(Paragraph)
    {
        if ( Paragraph === this.KeepNextParagraph )
            return true;

        return false;
    },

    Check_KeepNextEnd : function(Paragraph)
    {
        if (Paragraph === this.KeepNextEndParagraph)
            return true;

        return false;
    },

    Need_ResetWidowControl : function()
    {
        this.WidowControlReset = true;
    },

    Reset_WidowControl : function()
    {
        if (true === this.WidowControlReset)
        {
            this.WidowControlParagraph = null;
            this.WidowControlLine      = -1;
            this.WidowControlReset     = false;
        }
    },

    Set_WidowControl : function(Paragraph, Line)
    {
        this.WidowControlParagraph = Paragraph;
        this.WidowControlLine      = Line;
    },

    Check_WidowControl : function(Paragraph, Line)
    {
        if (Paragraph === this.WidowControlParagraph && Line === this.WidowControlLine)
            return true;

        return false;
    },

    Set_FrameRecalc  : function(Value)
    {
        this.FrameRecalc = Value;
    },

    Set_FootnoteReference : function(oFootnoteReference, nPageAbs, nColumnAbs)
    {
        this.FootnoteReference = oFootnoteReference;
        this.FootnotePage      = nPageAbs;
		this.FootnoteColumn    = nColumnAbs;
    },

    Check_FootnoteReference : function(oFootnoteReference)
    {
        return (this.FootnoteReference === oFootnoteReference ? true : false);
    },

    Reset_FootnoteReference : function()
    {
        this.FootnoteReference         = null;
		this.FootnotePage              = 0;
		this.FootnoteColumn            = 0;
		this.FlowObjectPageBreakBefore = false;
    },

	Set_NeedRecalculateFromStart : function(isNeedRecalculate)
	{
		this.NeedRecalculateFromStart = isNeedRecalculate;
	},

	Is_NeedRecalculateFromStart : function()
	{
		return this.NeedRecalculateFromStart;
	}

};

function CDocumentFieldsManager()
{
	this.m_aFields = [];

	this.m_oMailMergeFields = {};

	this.m_aComplexFields = [];
	this.m_oCurrentComplexField = null;
}

CDocumentFieldsManager.prototype.Register_Field = function(oField)
{
    this.m_aFields.push(oField);

    var nFieldType = oField.Get_FieldType();
    if (fieldtype_MERGEFIELD === nFieldType)
    {
        var sName = oField.Get_Argument(0);
        if (undefined !== sName)
        {
            if (undefined === this.m_oMailMergeFields[sName])
                this.m_oMailMergeFields[sName] = [];

            this.m_oMailMergeFields[sName].push(oField);
        }
    }
};
CDocumentFieldsManager.prototype.Update_MailMergeFields = function(Map)
{
    for (var FieldName in this.m_oMailMergeFields)
    {
        for (var Index = 0, Count = this.m_oMailMergeFields[FieldName].length; Index < Count; Index++)
        {
            var oField = this.m_oMailMergeFields[FieldName][Index];
            oField.Map_MailMerge(Map[FieldName]);
        }
    }
};
CDocumentFieldsManager.prototype.Replace_MailMergeFields = function(Map)
{
    for (var FieldName in this.m_oMailMergeFields)
    {
        for (var Index = 0, Count = this.m_oMailMergeFields[FieldName].length; Index < Count; Index++)
        {
            var oField = this.m_oMailMergeFields[FieldName][Index];
            oField.Replace_MailMerge(Map[FieldName]);
        }
    }
};
CDocumentFieldsManager.prototype.Restore_MailMergeTemplate = function()
{
    if (true === AscCommon.CollaborativeEditing.Is_SingleUser())
    {
        // В такой ситуации мы восстанавливаем стандартный текст полей. Чтобы это сделать нам сначала надо пробежаться
        // по всем таким полям, определить параграфы, в которых необходимо восстановить поля. Залочить эти параграфы,
        // и произвести восстановление полей.

        var FieldsToRestore    = [];
        var FieldsRemain       = [];
        var ParagrapsToRestore = [];
        for (var FieldName in this.m_oMailMergeFields)
        {
            for (var Index = 0, Count = this.m_oMailMergeFields[FieldName].length; Index < Count; Index++)
            {
                var oField = this.m_oMailMergeFields[FieldName][Index];
                var oFieldPara = oField.GetParagraph();

                if (oFieldPara && oField.Is_NeedRestoreTemplate())
                {
                    var bNeedAddPara = true;
                    for (var ParaIndex = 0, ParasCount = ParagrapsToRestore.length; ParaIndex < ParasCount; ParaIndex++)
                    {
                        if (oFieldPara === ParagrapsToRestore[ParaIndex])
                        {
                            bNeedAddPara = false;
                            break;
                        }
                    }
                    if (true === bNeedAddPara)
                        ParagrapsToRestore.push(oFieldPara);

                    FieldsToRestore.push(oField);
                }
                else
                {
                    FieldsRemain.push(oField);
                }
            }
        }

        var LogicDocument = (ParagrapsToRestore.length > 0 ? ParagrapsToRestore[0].LogicDocument : null);
        if (LogicDocument && false === LogicDocument.Document_Is_SelectionLocked(changestype_None, { Type : changestype_2_ElementsArray_and_Type, Elements : ParagrapsToRestore, CheckType : changestype_Paragraph_Content }))
        {
            History.Create_NewPoint(AscDFH.historydescription_Document_RestoreFieldTemplateText);
            for (var nIndex = 0, nCount = FieldsToRestore.length; nIndex < nCount; nIndex++)
            {
                var oField = FieldsToRestore[nIndex];
                oField.Restore_StandardTemplate();
            }

            for (var nIndex = 0, nCount = FieldsRemain.length; nIndex < nCount; nIndex++)
            {
                var oField = FieldsRemain[nIndex];
                oField.Restore_Template();
            }
        }
        else
        {
            // Восстанавливать ничего не надо просто возващаем значения тимплейтов
            for (var FieldName in this.m_oMailMergeFields)
            {
                for (var Index = 0, Count = this.m_oMailMergeFields[FieldName].length; Index < Count; Index++)
                {
                    var oField = this.m_oMailMergeFields[FieldName][Index];
                    oField.Restore_Template();
                }
            }
        }
    }
    else
    {
        for (var FieldName in this.m_oMailMergeFields)
        {
            for (var Index = 0, Count = this.m_oMailMergeFields[FieldName].length; Index < Count; Index++)
            {
                var oField = this.m_oMailMergeFields[FieldName][Index];
                oField.Restore_Template();
            }
        }
    }
};
CDocumentFieldsManager.prototype.GetAllFieldsByType = function(nType)
{
	var arrFields = [];
	for (var nIndex = 0, nCount = this.m_aFields.length; nIndex < nCount; ++nIndex)
	{
		var oField = this.m_aFields[nIndex];
		if (nType === oField.Get_FieldType() && oField.Is_UseInDocument())
		{
			arrFields.push(oField);
		}
	}
	return arrFields;
};
CDocumentFieldsManager.prototype.RegisterComplexField = function(oComplexField)
{
	this.m_aComplexFields.push(oComplexField);
};
CDocumentFieldsManager.prototype.GetCurrentComplexField = function()
{
	return this.m_oCurrentComplexField;
};
CDocumentFieldsManager.prototype.SetCurrentComplexField = function(oComplexField)
{
	if (this.m_oCurrentComplexField === oComplexField)
		return false;

	if (this.m_oCurrentComplexField)
		this.m_oCurrentComplexField.SetCurrent(false);

	this.m_oCurrentComplexField = oComplexField;

	if (this.m_oCurrentComplexField)
		this.m_oCurrentComplexField.SetCurrent(true);

	return true;
};

var selected_None              = -1;
var selected_DrawingObject     = 0;
var selected_DrawingObjectText = 1;

function CSelectedElementsInfo(oPr)
{
	this.m_bSkipTOC = oPr && oPr.SkipTOC ? true : false;

	this.m_bTable           = false; // Находится курсор или выделение целиком в какой-нибудь таблице
	this.m_bMixedSelection  = false; // Попадает ли в выделение одновременно несколько элементов
	this.m_nDrawing         = selected_None;
	this.m_pParagraph       = null;  // Параграф, в котором находится выделение
	this.m_oMath            = null;  // Формула, в которой находится выделение
	this.m_oHyperlink       = null;  // Гиперссылка, в которой находится выделение
	this.m_oField           = null;  // Поле, в котором находится выделение
	this.m_oCell            = null;  // Выделенная ячейка (специальная ситуация, когда выделена ровно одна ячейка)
	this.m_oBlockLevelSdt   = null;  // Если мы находимся в классе CBlockLevelSdt
	this.m_oInlineLevelSdt  = null;  // Если мы находимся в классе CInlineLevelSdt (важно, что мы находимся внутри класса)
	this.m_arrComplexFields = [];
	this.m_oPageNum         = null;
	this.m_oPagesCount      = null;

    this.Reset = function()
    {
        this.m_bSelection      = false;
        this.m_bTable          = false;
        this.m_bMixedSelection = false;
        this.m_nDrawing        = -1;
    };

    this.Set_Math = function(Math)
    {
        this.m_oMath = Math;
    };

    this.Set_Field = function(Field)
    {
        this.m_oField = Field;
    };

    this.Get_Math = function()
    {
        return this.m_oMath;
    };

    this.Get_Field = function()
    {
        return this.m_oField;
    };

    this.Set_Table = function()
    {
        this.m_bTable = true;
    };

    this.Set_Drawing = function(nDrawing)
    {
        this.m_nDrawing = nDrawing;
    };

    this.Is_DrawingObjSelected = function()
    {
        return ( this.m_nDrawing === selected_DrawingObject ? true : false );
    };

    this.Set_MixedSelection = function()
    {
        this.m_bMixedSelection = true;
    };

    this.Is_InTable = function()
    {
        return this.m_bTable;
    };

    this.Is_MixedSelection = function()
    {
        return this.m_bMixedSelection;
    };

    this.Set_SingleCell = function(Cell)
    {
        this.m_oCell = Cell;
    };

    this.Get_SingleCell = function()
    {
        return this.m_oCell;
    };
}
CSelectedElementsInfo.prototype.IsSkipTOC = function()
{
	return this.m_bSkipTOC;
};
CSelectedElementsInfo.prototype.SetParagraph = function(Para)
{
	this.m_pParagraph = Para;
};
CSelectedElementsInfo.prototype.GetParagraph = function()
{
	return this.m_pParagraph;
};
CSelectedElementsInfo.prototype.SetBlockLevelSdt = function(oSdt)
{
	this.m_oBlockLevelSdt = oSdt;
};
/**
 * @returns {?CBlockLevelSdt}
 */
CSelectedElementsInfo.prototype.GetBlockLevelSdt = function()
{
	return this.m_oBlockLevelSdt;
};
CSelectedElementsInfo.prototype.SetInlineLevelSdt = function(oSdt)
{
	this.m_oInlineLevelSdt = oSdt;
};
/**
 * @returns {?CInlineLevelSdt}
 */
CSelectedElementsInfo.prototype.GetInlineLevelSdt = function()
{
	return this.m_oInlineLevelSdt;
};
CSelectedElementsInfo.prototype.SetComplexFields = function(arrComplexFields)
{
	this.m_arrComplexFields = arrComplexFields;
};
CSelectedElementsInfo.prototype.GetComplexFields = function()
{
	return this.m_arrComplexFields;
};
CSelectedElementsInfo.prototype.GetTableOfContents = function()
{
	for (var nIndex = this.m_arrComplexFields.length - 1; nIndex >= 0; --nIndex)
	{
		var oComplexField = this.m_arrComplexFields[nIndex];
		var oInstruction  = oComplexField.GetInstruction();

		if (AscCommonWord.fieldtype_TOC === oInstruction.GetType())
			return oComplexField;
	}

	if (this.m_oBlockLevelSdt && this.m_oBlockLevelSdt.IsBuiltInTableOfContents())
		return this.m_oBlockLevelSdt;

	return null;
};
CSelectedElementsInfo.prototype.SetHyperlink = function(oHyperlink)
{
	this.m_oHyperlink = oHyperlink;
};
CSelectedElementsInfo.prototype.GetHyperlink = function()
{
	if (this.m_oHyperlink)
		return this.m_oHyperlink;

	for (var nIndex = 0, nCount = this.m_arrComplexFields.length; nIndex < nCount; ++nIndex)
	{
		var oInstruction = this.m_arrComplexFields[nIndex].GetInstruction();
		if (oInstruction && fieldtype_HYPERLINK === oInstruction.GetType())
			return oInstruction;
	}

	return null;
};
CSelectedElementsInfo.prototype.SetPageNum = function(oElement)
{
	this.m_oPageNum = oElement;
};
CSelectedElementsInfo.prototype.GetPageNum = function()
{
	return this.m_oPageNum;
};
CSelectedElementsInfo.prototype.SetPagesCount = function(oElement)
{
	this.m_oPagesCount = oElement;
};
CSelectedElementsInfo.prototype.GetPagesCount = function()
{
	return this.m_oPagesCount;
};

var document_compatibility_mode_Word14  = 14;
var document_compatibility_mode_Word15  = 15;

var document_compatibility_mode_Current = 0xFFFF;

function CDocumentSettings()
{
    this.MathSettings      = undefined !== CMathSettings ? new CMathSettings() : {};
    this.CompatibilityMode = document_compatibility_mode_Current;
    this.SdtSettings       = new CSdtGlobalSettings();
}

/**
 * Основной класс для работы с документом в Word.
 * @param DrawingDocument
 * @param isMainLogicDocument
 * @constructor
 * @extends {CDocumentContentBase}
 */
function CDocument(DrawingDocument, isMainLogicDocument)
{
	CDocumentContentBase.call(this);

    //------------------------------------------------------------------------------------------------------------------
    //  Сохраняем ссылки на глобальные объекты
    //------------------------------------------------------------------------------------------------------------------
    this.History              = History;
    this.IdCounter            = AscCommon.g_oIdCounter;
    this.TableId              = g_oTableId;
    this.CollaborativeEditing = (("undefined" !== typeof(AscCommon.CWordCollaborativeEditing) && AscCommon.CollaborativeEditing instanceof AscCommon.CWordCollaborativeEditing) ? AscCommon.CollaborativeEditing : null);
    this.Api                  = editor;
    //------------------------------------------------------------------------------------------------------------------
    //  Выставляем ссылки на главный класс
    //------------------------------------------------------------------------------------------------------------------
    if (false !== isMainLogicDocument)
    {
        if (this.History)
            this.History.Set_LogicDocument(this);

        if (this.CollaborativeEditing)
            this.CollaborativeEditing.m_oLogicDocument = this;
    }
    //__________________________________________________________________________________________________________________

    this.Id = this.IdCounter.Get_NewId();

    // Сначала настраиваем размеры страницы и поля
    this.SectPr = new CSectionPr(this);
    this.SectionsInfo = new CDocumentSectionsInfo();

    this.Content[0] = new Paragraph(DrawingDocument, this);
    this.Content[0].Set_DocumentNext(null);
    this.Content[0].Set_DocumentPrev(null);

    this.Settings = new CDocumentSettings();

    this.CurPos  =
    {
        X          : 0,
        Y          : 0,
        ContentPos : 0, // в зависимости, от параметра Type: позиция в Document.Content
        RealX      : 0, // позиция курсора, без учета расположения букв
        RealY      : 0, // это актуально для клавиш вверх и вниз
        Type       : docpostype_Content
    };

	this.Selection =
    {
        Start    : false,
        Use      : false,
        StartPos : 0,
        EndPos   : 0,
        Flag     : selectionflag_Common,
        Data     : null,
        UpdateOnRecalc : false,
		WordSelected : false,
        DragDrop : { Flag : 0, Data : null }  // 0 - не drag-n-drop, и мы его проверяем, 1 - drag-n-drop, -1 - не проверять drag-n-drop
    };

    if (false !== isMainLogicDocument)
        this.ColumnsMarkup = new CColumnsMarkup();

    // Здесь мы храним инфрмацию, связанную с разбивкой на страницы и самими страницами
    this.Pages = [];

    this.RecalcInfo = new CDocumentRecalcInfo();

    this.RecalcId     = 0; // Номер пересчета
    this.FullRecalc   = new CDocumentRecalculateState(); // Объект полного пересчета
    this.HdrFtrRecalc = new CDocumentRecalculateHdrFtrPageCountState(); // Объект дополнительного пересчета колонтитулов после полного пересчета

    this.TurnOffRecalc          = 0;
    this.TurnOffInterfaceEvents = false;
    this.TurnOffRecalcCurPos    = false;

    this.CheckEmptyElementsOnSelection = true; // При выделении проверять или нет пустой параграф в конце/начале выделения.

    this.Numbering = new CNumbering();
    this.Styles    = new CStyles();
    this.Styles.Set_LogicDocument(this);

    this.DrawingDocument = DrawingDocument;

    this.NeedUpdateTarget = false;

    // Флаг, который контролирует нужно ли обновлять наш курсор у остальных редакторов нашего документа.
    // Также следим за частотой обновления, чтобы оно проходило не чаще одного раза в секунду.
    this.NeedUpdateTargetForCollaboration = true;
    this.LastUpdateTargetTime             = 0;

    this.ReindexStartPos = 0;

    // Класс для работы с колонтитулами
    this.HdrFtr = new CHeaderFooterController(this, this.DrawingDocument);

    // Класс для работы с поиском
    this.SearchInfo =
    {
        Id       : null,
        StartPos : 0,
        CurPage  : 0,
        String   : null
    };

    // Позция каретки
    this.TargetPos =
    {
        X       : 0,
        Y       : 0,
        PageNum : 0
    };

    this.CopyTextPr = null; // TextPr для копирования по образцу
    this.CopyParaPr = null; // ParaPr для копирования по образцу

    // Класс для работы со статискикой документа
    this.Statistics = new CStatistics( this );

    this.HighlightColor = null;

    if(typeof CComments !== "undefined")
        this.Comments = new CComments();

    this.Lock = new AscCommon.CLock();

    this.m_oContentChanges = new AscCommon.CContentChanges(); // список изменений(добавление/удаление элементов)

    // Массив укзателей на все инлайновые графические объекты
    this.DrawingObjects = null;

    if (typeof CGraphicObjects !== "undefined")
        this.DrawingObjects = new CGraphicObjects(this, this.DrawingDocument, this.Api);

    this.theme          = AscFormat.GenerateDefaultTheme(this);
    this.clrSchemeMap   = AscFormat.GenerateDefaultColorMap();

    // Класс для работы с поиском и заменой в документе
    this.SearchEngine = null;
    if (typeof CDocumentSearch !== "undefined")
        this.SearchEngine = new CDocumentSearch();

    // Параграфы, в которых есть ошибки в орфографии (объект с ключом - Id параграфа)
    this.Spelling = new CDocumentSpelling();

    // Дополнительные настройки
    this.UseTextShd                = true;  // Использовать ли заливку текста
    this.ForceCopySectPr           = false; // Копировать ли настройки секции, если родительский класс параграфа не документ
    this.CopyNumberingMap          = null;  // Мап старый индекс -> новый индекс для копирования нумерации
    this.CheckLanguageOnTextAdd    = false; // Проверять ли язык при добавлении текста в ран
	this.RemoveCommentsOnPreDelete = true; // Удалять ли комментарий при удалении объекта

    // Мап для рассылки
    this.MailMergeMap             = null;
    this.MailMergePreview         = false;
    this.MailMergeFieldsHighlight = false; // Подсвечивать ли все поля связанные с рассылкой
    this.MailMergeFields          = [];

    // Класс, управляющий полями
    this.FieldsManager = new CDocumentFieldsManager();

    // Класс, управляющий закладками
	if (typeof CBookmarksManager !== "undefined")
		this.BookmarksManager = new CBookmarksManager(this);

    // Режим рецензирования
    this.TrackRevisions = false;
    this.TrackRevisionsManager = new CTrackRevisionsManager(this);

    this.DocumentOutline = new CDocumentOutline(this);

    this.AutoCorrectSettings = {
    	SmartQuotes            : true,
		HyphensWithDash        : true,
    	AutomaticBulletedLists : true,
		AutomaticNumberedLists : true
	};

    // Контролируем изменения интерфейса
    this.ChangedStyles      = []; // Объект с Id стилями, которые были изменены/удалены/добавлены
	this.TurnOffPanelStyles = 0;  // == 0 - можно обновлять панельку со стилями, != 0 - нельзя обновлять

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    this.TableId.Add(this, this.Id);

	// Объект для составного ввода текста
	this.CompositeInput = null;

	// Нужно ли проверять тип лока у ContentControl при проверке залоченности выделенных объектов
	this.CheckContentControlsLock = true;

	this.ViewModeInReview = {
		mode                : 0,     // -1 - исходный, 0 - со всеми изменениями, 1 - результат
		isFastCollaboration : false
	};

	this.LastBulletList   = undefined; // Последний примененный маркированный список
	this.LastNumberedList = undefined; // Последний примененный нумерованный список

	// Класс для работы со сносками
	this.Footnotes               = new CFootnotesController(this);
	this.LogicDocumentController = new CLogicDocumentController(this);
	this.DrawingsController      = new CDrawingsController(this, this.DrawingObjects);
	this.HeaderFooterController  = new CHdrFtrController(this, this.HdrFtr);
	
	this.Controller = this.LogicDocumentController;

    this.StartTime = 0;

    // Кэш для некоторых запросов, которые могут за раз делаться несколько раз
    this.AllParagraphsList = null;
    this.AllFootnotesList  = null;

	//------------------------------------------------------------------------------------------------------------------
	//  Check StartCollaborationEditing
	//------------------------------------------------------------------------------------------------------------------
	if (this.CollaborativeEditing && !this.CollaborativeEditing.Is_SingleUser())
	{
		this.StartCollaborationEditing();
}
	//__________________________________________________________________________________________________________________
}
CDocument.prototype = Object.create(CDocumentContentBase.prototype);
CDocument.prototype.constructor = CDocument;

CDocument.prototype.Init                           = function()
{

};
CDocument.prototype.On_EndLoad                     = function()
{
    // Обновляем информацию о секциях
    this.UpdateAllSectionsInfo();

    // Проверяем последний параграф на наличие секции
    this.Check_SectionLastParagraph();

    // Специальная проверка плохо заданных нумераций через стиль. Когда ссылка на нумерацию в стиле есть,
    // а обратной ссылки в нумерации на стиль - нет.
    this.Styles.Check_StyleNumberingOnLoad(this.Numbering);

    // Перемещаем курсор в начало документа
    this.MoveCursorToStartPos(false);

    if (editor.DocInfo)
    {
        var TemplateReplacementData = editor.DocInfo.get_TemplateReplacement();
        if (null !== TemplateReplacementData)
        {
            this.private_ProcessTemplateReplacement(TemplateReplacementData);
        }
    }
    if (null !== this.CollaborativeEditing)
    {
        this.Set_FastCollaborativeEditing(true);
    }

    // Во вьювере показываем документ без изменений в рецензировании
    if (this.IsViewMode())
	{
		this.Start_SilentMode();
		this.private_RejectAllRevisionChanges();
		this.End_SilentMode(false);
	}
};
CDocument.prototype.Add_TestDocument               = function()
{
    this.Content   = [];
    var Text       = ["Comparison view helps you track down memory leaks, by displaying which objects have been correctly cleaned up by the garbage collector. Generally used to record and compare two (or more) memory snapshots of before and after an operation. The idea is that inspecting the delta in freed memory and reference count lets you confirm the presence and cause of a memory leak.", "Containment view provides a better view of object structure, helping us analyse objects referenced in the global namespace (i.e. window) to find out what is keeping them around. It lets you analyse closures and dive into your objects at a low level.", "Dominators view helps confirm that no unexpected references to objects are still hanging around (i.e that they are well contained) and that deletion/garbage collection is actually working."];
    var ParasCount = 50;
    var RunsCount  = Text.length;
    for (var ParaIndex = 0; ParaIndex < ParasCount; ParaIndex++)
    {
        var Para = new Paragraph(this.DrawingDocument, this);
        //var Run = new ParaRun(Para);
        for (var RunIndex = 0; RunIndex < RunsCount; RunIndex++)
        {

            var String    = Text[RunIndex];
            var StringLen = String.length;
            for (var TextIndex = 0; TextIndex < StringLen; TextIndex++)
            {
                var Run         = new ParaRun(Para);
                var TextElement = String[TextIndex];

                Run.AddText(TextElement);
                Para.AddToContent(0, Run);
            }


        }
        //Para.Add_ToContent(0, Run);
        this.Internal_Content_Add(this.Content.length, Para);
    }

	this.Recalculate_FromStart(true);
};
CDocument.prototype.LoadEmptyDocument              = function()
{
    this.DrawingDocument.TargetStart();
    this.Recalculate();

    this.Interface_Update_ParaPr();
    this.Interface_Update_TextPr();
};
CDocument.prototype.Set_CurrentElement = function(Index, bUpdateStates)
{
	var OldDocPosType = this.CurPos.Type;

	var ContentPos = Math.max(0, Math.min(this.Content.length - 1, Index));

	this.Set_DocPosType(docpostype_Content);
	this.CurPos.ContentPos = Math.max(0, Math.min(this.Content.length - 1, Index));

	this.Reset_WordSelection();
	if (true === this.Content[ContentPos].IsSelectionUse())
	{
		this.Selection.Flag     = selectionflag_Common;
		this.Selection.Use      = true;
		this.Selection.StartPos = ContentPos;
		this.Selection.EndPos   = ContentPos;
	}
	else
		this.RemoveSelection();

	if (false != bUpdateStates)
	{
		this.Document_UpdateInterfaceState();
		this.Document_UpdateRulersState();
		this.Document_UpdateSelectionState();
	}

	if (docpostype_HdrFtr === OldDocPosType)
	{
		this.DrawingDocument.ClearCachePages();
		this.DrawingDocument.FirePaint();
	}
};
CDocument.prototype.Is_ThisElementCurrent          = function()
{
    return true;
};
CDocument.prototype.Get_PageContentStartPos        = function(PageIndex, ElementIndex)
{
    if (undefined === ElementIndex && undefined !== this.Pages[PageIndex])
        ElementIndex = this.Pages[PageIndex].Pos;

    var SectPr = this.SectionsInfo.Get_SectPr(ElementIndex).SectPr;

    var Y      = Math.abs(SectPr.Get_PageMargin_Top());
    var YLimit = SectPr.Get_PageHeight() - Math.abs(SectPr.Get_PageMargin_Bottom());
    var X      = SectPr.Get_PageMargin_Left();
    var XLimit = SectPr.Get_PageWidth() - SectPr.Get_PageMargin_Right();

    var HdrFtrLine = this.HdrFtr.Get_HdrFtrLines(PageIndex);

    var YHeader = HdrFtrLine.Top;
    if (null !== YHeader && YHeader > Y && SectPr.Get_PageMargin_Top() >= 0)
        Y = YHeader;

    var YFooter = HdrFtrLine.Bottom;
    if (null !== YFooter && YFooter < YLimit && SectPr.Get_PageMargin_Bottom() >= 0)
        YLimit = YFooter;

    return {X : X, Y : Y, XLimit : XLimit, YLimit : YLimit};
};
CDocument.prototype.Get_PageContentStartPos2       = function(StartPageIndex, StartColumnIndex, ElementPageIndex, ElementIndex)
{
    if (undefined === ElementIndex && undefined !== this.Pages[StartPageIndex])
        ElementIndex = this.Pages[StartPageIndex].Pos;

    var SectPr = this.SectionsInfo.Get_SectPr(ElementIndex).SectPr;

    var ColumnsCount = SectPr.Get_ColumnsCount();
    var ColumnAbs    = (StartColumnIndex + ElementPageIndex) - ((StartColumnIndex + ElementPageIndex) / ColumnsCount | 0) * ColumnsCount;
    var PageAbs      = StartPageIndex + ((StartColumnIndex + ElementPageIndex) / ColumnsCount | 0);

	var Y      = Math.abs(SectPr.Get_PageMargin_Top());
	var YLimit = SectPr.Get_PageHeight() - Math.abs(SectPr.Get_PageMargin_Bottom());
	var X      = SectPr.Get_PageMargin_Left();
	var XLimit = SectPr.Get_PageWidth() - SectPr.Get_PageMargin_Right();


	var SectionIndex = this.FullRecalc.SectionIndex;
    if (this.Pages[PageAbs] && this.Pages[PageAbs].Sections[SectionIndex])
    {
        Y      = this.Pages[PageAbs].Sections[SectionIndex].Get_Y();
        YLimit = this.Pages[PageAbs].Sections[SectionIndex].Get_YLimit();
    }

    var HdrFtrLine = this.HdrFtr.Get_HdrFtrLines(PageAbs);

    for (var ColumnIndex = 0; ColumnIndex < ColumnAbs; ++ColumnIndex)
    {
        X += SectPr.Get_ColumnWidth(ColumnIndex);
        X += SectPr.Get_ColumnSpace(ColumnIndex);
    }

    if (ColumnsCount - 1 !== ColumnAbs)
        XLimit = X + SectPr.Get_ColumnWidth(ColumnAbs);

    var YHeader = HdrFtrLine.Top;
    if (null !== YHeader && YHeader > Y && SectPr.Get_PageMargin_Top() >= 0)
        Y = YHeader;

    var YFooter = HdrFtrLine.Bottom;
    if (null !== YFooter && YFooter < YLimit && SectPr.Get_PageMargin_Bottom() >= 0)
        YLimit = YFooter;

    var ColumnSpaceBefore = (ColumnAbs > 0 ? SectPr.Get_ColumnSpace(ColumnAbs - 1) : 0);
    var ColumnSpaceAfter  = (ColumnAbs < ColumnsCount - 1 ? SectPr.Get_ColumnSpace(ColumnAbs) : 0);

    return {
        X                 : X,
        Y                 : Y,
        XLimit            : XLimit,
        YLimit            : YLimit,
        ColumnSpaceBefore : ColumnSpaceBefore,
        ColumnSpaceAfter  : ColumnSpaceAfter
    };
};
CDocument.prototype.Get_PageLimits                 = function(PageIndex)
{
    var Index  = ( undefined !== this.Pages[PageIndex] ? this.Pages[PageIndex].Pos : 0 );
    var SectPr = this.SectionsInfo.Get_SectPr(Index).SectPr;

    var W = SectPr.Get_PageWidth();
    var H = SectPr.Get_PageHeight();

    return {X : 0, Y : 0, XLimit : W, YLimit : H};
};
CDocument.prototype.Get_PageFields                 = function(PageIndex)
{
    var Index  = ( undefined !== this.Pages[PageIndex] ? this.Pages[PageIndex].Pos : 0 );
    var SectPr = this.SectionsInfo.Get_SectPr(Index).SectPr;

    var Y      = SectPr.PageMargins.Top;
    var YLimit = SectPr.PageSize.H - SectPr.PageMargins.Bottom;
    var X      = SectPr.PageMargins.Left;
    var XLimit = SectPr.PageSize.W - SectPr.PageMargins.Right;

    return {X : X, Y : Y, XLimit : XLimit, YLimit : YLimit};
};
CDocument.prototype.Get_ColumnFields               = function(ElementIndex, ColumnIndex)
{
    var SectPr = this.SectionsInfo.Get_SectPr(ElementIndex).SectPr;

    var Y      = SectPr.Get_PageMargin_Top();
    var YLimit = SectPr.Get_PageHeight() - SectPr.Get_PageMargin_Bottom();
    var X      = SectPr.Get_PageMargin_Left();
    var XLimit = SectPr.Get_PageWidth() - SectPr.Get_PageMargin_Right();

    var ColumnsCount = SectPr.Get_ColumnsCount();
    if (ColumnIndex >= ColumnsCount)
        ColumnIndex = ColumnsCount - 1;

    for (var ColIndex = 0; ColIndex < ColumnIndex; ++ColIndex)
    {
        X += SectPr.Get_ColumnWidth(ColIndex);
        X += SectPr.Get_ColumnSpace(ColIndex);
    }

    if (ColumnsCount - 1 !== ColumnIndex)
        XLimit = X + SectPr.Get_ColumnWidth(ColumnIndex);

    return {X : X, XLimit : XLimit};
};
CDocument.prototype.Get_Theme                      = function()
{
    return this.theme;
};
CDocument.prototype.Get_ColorMap                   = function()
{
    return this.clrSchemeMap;
};
/**
 * Данная функция предназначена для отключения пересчета. Это может быть полезно, т.к. редактор всегда запускает
 * пересчет после каждого действия.
 */
CDocument.prototype.TurnOff_Recalculate = function()
{
    this.TurnOffRecalc++;
};
/**
 * Включаем пересчет, если он был отключен.
 * @param {boolean} bRecalculate Запускать ли пересчет
 */
CDocument.prototype.TurnOn_Recalculate = function(bRecalculate)
{
    this.TurnOffRecalc--;

    if (bRecalculate)
        this.Recalculate();
};
/**
 * Проверяем включен ли пересчет.
 * @returns {boolean}
 */
CDocument.prototype.Is_OnRecalculate = function()
{
    if (0 === this.TurnOffRecalc)
        return true;

    return false;
};
/**
 * Запускаем пересчет документа.
 * @param bOneParagraph
 * @param bRecalcContentLast
 * @param _RecalcData
 */
CDocument.prototype.Recalculate = function(bOneParagraph, bRecalcContentLast, _RecalcData)
{
	if (this.RecalcInfo.Is_NeedRecalculateFromStart())
	{
		this.RecalcInfo.Set_NeedRecalculateFromStart(false);
		this.Recalculate_FromStart();
		return;
	}

	this.DocumentOutline.Update();

    this.StartTime = new Date().getTime();

    if (true !== this.Is_OnRecalculate())
        return;

    // Останавливаем поиск
    if (false != this.SearchEngine.ClearOnRecalc)
    {
        var bOldSearch = ( this.SearchEngine.Count > 0 ? true : false );

        this.SearchEngine.Clear();

        if (true === bOldSearch)
        {
            editor.sync_SearchEndCallback();

            this.DrawingDocument.ClearCachePages();
            this.DrawingDocument.FirePaint();
        }
    }

    // Обновляем позицию курсора
    this.NeedUpdateTarget = true;

    // Увеличиваем номер пересчета
    this.RecalcId++;

    // Если задан параметр _RecalcData, тогда мы не можем ориентироваться на историю
    if (undefined === _RecalcData)
    {
        // Проверяем можно ли сделать быстрый пересчет
        var SimpleChanges = History.Is_SimpleChanges();
        if (1 === SimpleChanges.length)
        {
            var Run  = SimpleChanges[0].Class;
            var Para = Run.Paragraph;

            var PageIndex = Para.Recalculate_FastRange(SimpleChanges);
            if (-1 !== PageIndex && this.Pages[PageIndex])
            {
                // Если за данным параграфом следовал пустой параграф с новой секцией, тогда его тоже надо пересчитать.
                var NextElement = Para.Get_DocumentNext();
                if (null !== NextElement && true === this.Pages[PageIndex].Check_EndSectionPara(NextElement))
                    this.private_RecalculateEmptySectionParagraph(NextElement, Para, PageIndex, Para.Get_AbsoluteColumn(Para.Get_PagesCount() - 1), Para.Get_ColumnsCount());

                // Перерисуем страницу, на которой произошли изменения
                this.DrawingDocument.OnRecalculatePage(PageIndex, this.Pages[PageIndex]);
                this.DrawingDocument.OnEndRecalculate(false, true);
                History.Reset_RecalcIndex();
                this.private_UpdateCursorXY(true, true);

                if (Para.Parent && Para.Parent.GetTopDocumentContent)
				{
					var oTopDocument = Para.Parent.GetTopDocumentContent();
					if (oTopDocument instanceof CFootEndnote)
						oTopDocument.OnFastRecalculate();
				}

                return;
            }
        }

        // TODO: Тут надо вставить заглушку, что если у нас в долгом пересчете находится страница <= PageIndex + 1,
        //       по отношению к данной, тогда не надо делать быстрый пересчет.
        var SimplePara = History.IsParagraphSimpleChanges();
        if (null !== SimplePara)
        {
            var FastPages      = SimplePara.Recalculate_FastWholeParagraph();
            var FastPagesCount = FastPages.length;

            var bCanRecalc = true;
            for (var Index = 0; Index < FastPagesCount; Index++)
			{
				if (!this.Pages[FastPages[Index]])
				{
					bCanRecalc = false;
					break;
				}
			}

            if (FastPagesCount > 0 && true === bCanRecalc)
            {
                // Если изменения произошли на последней странице параграфа, и за данным параграфом следовал
                // пустой параграф с новой секцией, тогда его тоже надо пересчитать.
                var NextElement  = SimplePara.Get_DocumentNext();
                var LastFastPage = FastPages[FastPagesCount - 1];
                if (null !== NextElement && true === this.Pages[LastFastPage].Check_EndSectionPara(NextElement))
                    this.private_RecalculateEmptySectionParagraph(NextElement, SimplePara, LastFastPage, SimplePara.Get_AbsoluteColumn(SimplePara.Get_PagesCount() - 1), SimplePara.Get_ColumnsCount());

                for (var Index = 0; Index < FastPagesCount; Index++)
                {
                    var PageIndex = FastPages[Index];
                    this.DrawingDocument.OnRecalculatePage(PageIndex, this.Pages[PageIndex]);
                }

                this.DrawingDocument.OnEndRecalculate(false, true);
                History.Reset_RecalcIndex();
                this.private_UpdateCursorXY(true, true);

                if (SimplePara.Parent && SimplePara.Parent.GetTopDocumentContent)
				{
					var oTopDocument = SimplePara.Parent.GetTopDocumentContent();
					if (oTopDocument instanceof CFootEndnote)
						oTopDocument.OnFastRecalculate();
				}

				return;
            }
        }
    }

    //console.log( "Long Recalc " );

    var ChangeIndex = 0;
    var MainChange  = false;

    // Получаем данные об произошедших изменениях
    var RecalcData = History.Get_RecalcData(_RecalcData);

    History.Reset_RecalcIndex();

    this.DrawingObjects.recalculate_(RecalcData.Drawings);
    this.DrawingObjects.recalculateText_(RecalcData.Drawings);

    // 1. Пересчитываем все автофигуры, которые нужно пересчитать. Изменения в них ни на что не влияют.
    for (var GraphIndex = 0; GraphIndex < RecalcData.Flow.length; GraphIndex++)
    {
        RecalcData.Flow[GraphIndex].recalculateDocContent();
    }

    // 2. Просмотрим все колонтитулы, которые подверглись изменениям. Найдем стартовую страницу, с которой надо
    //    запустить пересчет.

    var SectPrIndex = -1;
    for (var HdrFtrIndex = 0; HdrFtrIndex < RecalcData.HdrFtr.length; HdrFtrIndex++)
    {
        var HdrFtr    = RecalcData.HdrFtr[HdrFtrIndex];
        var FindIndex = this.SectionsInfo.Find_ByHdrFtr(HdrFtr);

        if (-1 === FindIndex)
            continue;

        // Колонтитул может быть записан в данной секции, но в ней не использоваться. Нам нужно начинать пересчет
        // с места использования данного колонтитула.

        var SectPr     = this.SectionsInfo.Get_SectPr2(FindIndex).SectPr;
        var HdrFtrInfo = SectPr.Get_HdrFtrInfo(HdrFtr);

        if (null !== HdrFtrInfo)
        {
            var bHeader = HdrFtrInfo.Header;
            var bFirst  = HdrFtrInfo.First;
            var bEven   = HdrFtrInfo.Even;

            var CheckSectIndex = -1;

            if (true === bFirst)
            {
                var CurSectIndex = FindIndex;
                var SectCount    = this.SectionsInfo.Elements.length;

                while (CurSectIndex < SectCount)
                {
                    var CurSectPr = this.SectionsInfo.Get_SectPr2(CurSectIndex).SectPr;

                    if (FindIndex === CurSectIndex || null === CurSectPr.Get_HdrFtr(bHeader, bFirst, bEven))
                    {
                        if (true === CurSectPr.Get_TitlePage())
                        {
                            CheckSectIndex = CurSectIndex;
                            break;
                        }

                    }
                    else
                    {
                        // Если мы попали сюда, значит данный колонтитул нигде не используется
                        break;
                    }

                    CurSectIndex++;
                }
            }
            else if (true === bEven)
            {
                if (true === EvenAndOddHeaders)
                    CheckSectIndex = FindIndex;
            }
            else
            {
                CheckSectIndex = FindIndex;
            }

            if (-1 !== CheckSectIndex && ( -1 === SectPrIndex || CheckSectIndex < SectPrIndex ))
                SectPrIndex = CheckSectIndex;
        }
    }

	if (-1 === RecalcData.Inline.Pos && -1 === SectPrIndex)
	{
		// Никаких изменений не было ни с самим документом, ни секциями
		ChangeIndex               = -1;
		RecalcData.Inline.PageNum = 0;
	}
	else if (-1 === RecalcData.Inline.Pos)
	{
		// Были изменения только внутри секций
		MainChange = false;

		// Выставляем начало изменений на начало секции
		ChangeIndex               = ( 0 === SectPrIndex ? 0 : this.SectionsInfo.Get_SectPr2(SectPrIndex - 1).Index + 1 );
		RecalcData.Inline.PageNum = 0;
	}
	else if (-1 === SectPrIndex)
	{
		// Изменения произошли только внутри основного документа
		MainChange = true;

		ChangeIndex = RecalcData.Inline.Pos;
	}
	else
	{
		// Изменения произошли и внутри документа, и внутри секций. Смотрим на более ранюю точку начала изменений
		// для секций и основоной части документа.
		MainChange = true;

		ChangeIndex = RecalcData.Inline.Pos;

		var ChangeIndex2 = ( 0 === SectPrIndex ? 0 : this.SectionsInfo.Get_SectPr2(SectPrIndex - 1).Index + 1 );

		if (ChangeIndex2 <= ChangeIndex)
		{
			ChangeIndex               = ChangeIndex2;
			RecalcData.Inline.PageNum = 0;
		}
	}

	// Найдем начальную страницу, с которой мы начнем пересчет
	var StartPage  = 0;
	var StartIndex = 0;

	if (ChangeIndex < 0 && true === RecalcData.NotesEnd)
	{
		// Сюда мы попадаем при рассчете сносок, которые выходят за пределы самого документа
		StartIndex = this.Content.length;
		StartPage  = RecalcData.NotesEndPage;
		MainChange = true;
	}
	else
	{
		if (ChangeIndex < 0)
		{
			this.DrawingDocument.ClearCachePages();
			this.DrawingDocument.FirePaint();
			return;
		}
		else if (ChangeIndex >= this.Content.length)
		{
			ChangeIndex = this.Content.length - 1;
		}

		// Проверяем предыдущие элементы на наличие параметра KeepNext, но не более, чем на 1 страницу
		var nTempPage  = this.private_GetPageByPos(ChangeIndex);
		var nTempIndex = (-1 !== nTempPage && nTempPage > 1) ? this.Pages[nTempPage - 1].Pos : 0;
		while (ChangeIndex > nTempIndex)
		{
			var PrevElement = this.Content[ChangeIndex - 1];
			if (type_Paragraph === PrevElement.GetType() && PrevElement.IsKeepNext())
			{
				ChangeIndex--;
				RecalcData.Inline.PageNum = PrevElement.Get_AbsolutePage(PrevElement.GetPagesCount());
				// считаем, что изменилась последняя страница
			}
			else
			{
				break;
			}
		}

		var ChangedElement = this.Content[ChangeIndex];
		if (ChangedElement.GetPagesCount() > 0 && -1 !== ChangedElement.GetIndex() && ChangedElement.Get_StartPage_Absolute() < RecalcData.Inline.PageNum - 1)
		{
			StartIndex = ChangeIndex;
			StartPage  = RecalcData.Inline.PageNum - 1;
		}
		else
		{
			var nTempPage = this.private_GetPageByPos(ChangeIndex);
			if (-1 !== nTempPage)
			{
				StartPage  = nTempPage;
				StartIndex = this.Pages[nTempPage].Pos;
			}

			if (ChangeIndex === StartIndex && StartPage < RecalcData.Inline.PageNum)
				StartPage = RecalcData.Inline.PageNum - 1;
		}

		// Если у нас уже начался долгий пересчет, тогда мы его останавливаем, и запускаем новый с текущими параметрами.
		// Здесь возможен случай, когда мы долгий пересчет основной части документа останавливаем из-за пересчета
		// колонтитулов, в этом случае параметр MainContentPos не меняется, и мы будем пересчитывать только колонтитулы
		// либо до страницы, на которой они приводят к изменению основную часть документа, либо до страницы, где
		// остановился предыдущий пересчет.

		if (null != this.FullRecalc.Id)
		{
			if (this.FullRecalc.StartIndex < StartIndex || (this.FullRecalc.StartIndex === StartIndex && this.FullRecalc.PageIndex <= StartPage))
				return;

			clearTimeout(this.FullRecalc.Id);
			this.FullRecalc.Id = null;
			this.DrawingDocument.OnEndRecalculate(false);
		}
		else if (null !== this.HdrFtrRecalc.Id)
		{
			clearTimeout(this.HdrFtrRecalc.Id);
			this.HdrFtrRecalc.Id = null;
			this.DrawingDocument.OnEndRecalculate(false);
		}
	}

	this.HdrFtrRecalc.PageCount = -1;

    // Очищаем данные пересчета
    this.RecalcInfo.Reset();

    this.FullRecalc.PageIndex         = StartPage;
    this.FullRecalc.SectionIndex      = 0;
    this.FullRecalc.ColumnIndex       = 0;
    this.FullRecalc.StartIndex        = StartIndex;
    this.FullRecalc.Start             = true;
    this.FullRecalc.StartPage         = StartPage;
    this.FullRecalc.ResetStartElement = this.private_RecalculateIsNewSection(StartPage, StartIndex);

    // Если у нас произошли какие-либо изменения с основной частью документа, тогда начинаем его пересчитывать сразу,
    // а если изменения касались только секций, тогда пересчитываем основную часть документа только с того места, где
    // остановился предыдущий пересчет, либо с того места, где изменения секций приводят к пересчету документа.
    if (true === MainChange)
        this.FullRecalc.MainStartPos = StartIndex;

    this.DrawingDocument.OnStartRecalculate(StartPage);
    this.Recalculate_Page();
};
/**
 * Пересчитываем следующую страницу.
 */
CDocument.prototype.Recalculate_Page = function()
{
    var SectionIndex = this.FullRecalc.SectionIndex;
    var PageIndex    = this.FullRecalc.PageIndex;
    var ColumnIndex  = this.FullRecalc.ColumnIndex;
    var bStart       = this.FullRecalc.Start;        // флаг, который говорит о том, рассчитываем мы эту страницу первый раз или нет (за один общий пересчет)
    var StartIndex   = this.FullRecalc.StartIndex;

    if (0 === SectionIndex && 0 === ColumnIndex && true === bStart)
    {
        var OldPage = ( undefined !== this.Pages[PageIndex] ? this.Pages[PageIndex] : null );

        if (true === bStart)
        {
            var Page              = new CDocumentPage();
            this.Pages[PageIndex] = Page;
            Page.Pos              = StartIndex;

            if (true === this.HdrFtr.Recalculate(PageIndex))
                this.FullRecalc.MainStartPos = StartIndex;

            var SectPr = this.SectionsInfo.Get_SectPr(StartIndex).SectPr;

            Page.Width          = SectPr.PageSize.W;
            Page.Height         = SectPr.PageSize.H;
            Page.Margins.Left   = SectPr.PageMargins.Left;
            Page.Margins.Top    = Math.abs(SectPr.PageMargins.Top);
            Page.Margins.Right  = SectPr.PageSize.W - SectPr.PageMargins.Right;
            Page.Margins.Bottom = SectPr.PageSize.H - Math.abs(SectPr.PageMargins.Bottom);

            Page.Sections[0] = new CDocumentPageSection();
            var ColumnsCount = SectPr.Get_ColumnsCount();
            for (var ColumnIndex = 0; ColumnIndex < ColumnsCount; ++ColumnIndex)
            {
                Page.Sections[0].Columns[ColumnIndex] = new CDocumentPageColumn();
            }
            Page.Sections[0].ColumnsSep = SectPr.Get_ColumnsSep();
        }

        var Count = this.Content.length;

        // Проверяем нужно ли пересчитывать основную часть документа на данной странице
        var MainStartPos = this.FullRecalc.MainStartPos;
        if (null !== OldPage && ( -1 === MainStartPos || MainStartPos > StartIndex ))
        {
            if (OldPage.EndPos >= Count - 1 && PageIndex - this.Content[Count - 1].Get_StartPage_Absolute() >= this.Content[Count - 1].GetPagesCount() - 1)
            {
                //console.log( "HdrFtr Recalc " + PageIndex );

                this.Pages[PageIndex] = OldPage;
                this.DrawingDocument.OnRecalculatePage(PageIndex, this.Pages[PageIndex]);

                this.private_CheckCurPage();
                this.DrawingDocument.OnEndRecalculate(true);
                this.DrawingObjects.onEndRecalculateDocument(this.Pages.length);

                if (true === this.Selection.UpdateOnRecalc)
                {
                    this.Selection.UpdateOnRecalc = false;
                    this.DrawingDocument.OnSelectEnd();
                }

                this.FullRecalc.Id           = null;
                this.FullRecalc.MainStartPos = -1;

                return;
            }
            else if (undefined !== this.Pages[PageIndex + 1])
            {
                //console.log( "HdrFtr Recalc " + PageIndex );

                // Переходим к следующей странице
                this.Pages[PageIndex] = OldPage;
                this.DrawingDocument.OnRecalculatePage(PageIndex, this.Pages[PageIndex]);

                this.FullRecalc.PageIndex         = PageIndex + 1;
                this.FullRecalc.Start             = true;
                this.FullRecalc.StartIndex        = this.Pages[PageIndex + 1].Pos;
                this.FullRecalc.ResetStartElement = false;

                var CurSectInfo  = this.SectionsInfo.Get_SectPr(this.Pages[PageIndex + 1].Pos);
                var PrevSectInfo = this.SectionsInfo.Get_SectPr(this.Pages[PageIndex].EndPos);

                if (PrevSectInfo !== CurSectInfo)
                    this.FullRecalc.ResetStartElement = true;

                if (window["NATIVE_EDITOR_ENJINE_SYNC_RECALC"] === true)
                {
                    if (PageIndex + 1 > this.FullRecalc.StartPage + 2)
                    {
                        if (window["native"]["WC_CheckSuspendRecalculate"] !== undefined)
                        {
                            //if (window["native"]["WC_CheckSuspendRecalculate"]())
                            //    return;

                            this.FullRecalc.Id = setTimeout(Document_Recalculate_Page, 10);
                            return;
                        }
                    }

                    this.Recalculate_Page();
                    return;
                }

                if (PageIndex + 1 > this.FullRecalc.StartPage + 2)
                {
                    this.FullRecalc.Id = setTimeout(Document_Recalculate_Page, 20);
                }
                else
                    this.Recalculate_Page();

                return;
            }
        }
        else
        {
            if (true === bStart)
            {
                this.Pages.length = PageIndex + 1;

                this.DrawingObjects.createGraphicPage(PageIndex);
                this.DrawingObjects.resetDrawingArrays(PageIndex, this);
            }
        }

        //console.log( "Regular Recalc " + PageIndex );

        var StartPos = this.Get_PageContentStartPos(PageIndex, StartIndex);

		this.Footnotes.Reset(PageIndex, this.SectionsInfo.Get_SectPr(StartIndex).SectPr);

        this.Pages[PageIndex].ResetStartElement = this.FullRecalc.ResetStartElement;
        this.Pages[PageIndex].X                 = StartPos.X;
        this.Pages[PageIndex].XLimit            = StartPos.XLimit;
        this.Pages[PageIndex].Y                 = StartPos.Y;
        this.Pages[PageIndex].YLimit            = StartPos.YLimit;

        this.Pages[PageIndex].Sections[0].Y      = StartPos.Y;
        this.Pages[PageIndex].Sections[0].YLimit = StartPos.YLimit;
        this.Pages[PageIndex].Sections[0].Pos    = StartIndex;
        this.Pages[PageIndex].Sections[0].EndPos = StartIndex;
    }

    this.Recalculate_PageColumn();
};
/**
 * Пересчитываем следующую колоноку.
 */
CDocument.prototype.Recalculate_PageColumn                   = function()
{
    var PageIndex          = this.FullRecalc.PageIndex;
    var SectionIndex       = this.FullRecalc.SectionIndex;
    var ColumnIndex        = this.FullRecalc.ColumnIndex;
    var StartIndex         = this.FullRecalc.StartIndex;
    var bResetStartElement = this.FullRecalc.ResetStartElement;

     // console.log("Page " + PageIndex + " Section " + SectionIndex + " Column " + ColumnIndex + " Element " + StartIndex);
     // console.log(this.RecalcInfo);

    var StartPos = this.Get_PageContentStartPos2(PageIndex, ColumnIndex, 0, StartIndex);

    var X      = StartPos.X;
    var Y      = StartPos.Y;
    var YLimit = StartPos.YLimit;
    var XLimit = StartPos.XLimit;

    var Page        = this.Pages[PageIndex];
    var PageSection = Page.Sections[SectionIndex];
    var PageColumn  = PageSection.Columns[ColumnIndex];

    PageColumn.X           = X;
    PageColumn.XLimit      = XLimit;
    PageColumn.Y           = Y;
    PageColumn.YLimit      = YLimit;
    PageColumn.Pos         = StartIndex;
    PageColumn.Empty       = false;
    PageColumn.SpaceBefore = StartPos.ColumnSpaceBefore;
    PageColumn.SpaceAfter  = StartPos.ColumnSpaceAfter;

    this.Footnotes.ContinueElementsFromPreviousColumn(PageIndex, ColumnIndex, Y, YLimit);

    var SectElement  = this.SectionsInfo.Get_SectPr(StartIndex);
    var SectPr       = SectElement.SectPr;
    var ColumnsCount = SectPr.Get_ColumnsCount();

    var bReDraw             = true;
    var bContinue           = false;
    var _PageIndex          = PageIndex;
    var _ColumnIndex        = ColumnIndex;
    var _StartIndex         = StartIndex;
    var _SectionIndex       = SectionIndex;
    var _bStart             = false;
    var _bResetStartElement = false;

    var Count = this.Content.length;
    var Index;
    for (Index = StartIndex; Index < Count; ++Index)
    {
        // Пересчитываем элемент документа
        var Element = this.Content[Index];

        var RecalcResult = recalcresult_NextElement;
        var bFlow        = false;

        if (true !== Element.Is_Inline())
        {
            bFlow = true;

            // Проверяем PageBreak и ColumnBreak в предыдущей строке
            var isPageBreakOnPrevLine   = false;
            var isColumnBreakOnPrevLine = false;

            var PrevElement = Element.Get_DocumentPrev();

            if (null !== PrevElement && type_Paragraph === PrevElement.Get_Type() && true === PrevElement.Is_Empty() && undefined !== PrevElement.Get_SectionPr())
                PrevElement = PrevElement.Get_DocumentPrev();

            if (null !== PrevElement && type_Paragraph === PrevElement.Get_Type())
            {
                var bNeedPageBreak = true;
                if (undefined !== PrevElement.Get_SectionPr())
                {
                    var PrevSectPr = PrevElement.Get_SectionPr();
                    var CurSectPr  = this.SectionsInfo.Get_SectPr(Index).SectPr;
                    if (c_oAscSectionBreakType.Continuous !== CurSectPr.Get_Type() || true !== CurSectPr.Compare_PageSize(PrevSectPr))
                        bNeedPageBreak = false;
                }

                var EndLine = PrevElement.Pages[PrevElement.Pages.length - 1].EndLine;
                if (true === bNeedPageBreak && -1 !== EndLine && PrevElement.Lines[EndLine].Info & paralineinfo_BreakRealPage && Index !== Page.Pos)
                    isPageBreakOnPrevLine = true;

                if (-1 !== EndLine && !(PrevElement.Lines[EndLine].Info & paralineinfo_BreakRealPage) && PrevElement.Lines[EndLine].Info & paralineinfo_BreakPage && Index !== PageColumn.Pos)
                    isColumnBreakOnPrevLine = true;
            }

            if (true === isColumnBreakOnPrevLine)
            {
                RecalcResult = recalcresult_NextPage | recalcresultflags_LastFromNewColumn;
            }
            else if (true === isPageBreakOnPrevLine)
            {
                RecalcResult = recalcresult_NextPage | recalcresultflags_LastFromNewPage;
            }
            else
            {
                var RecalcInfo =
                    {
                        Element           : Element,
                        X                 : X,
                        Y                 : Y,
                        XLimit            : XLimit,
                        YLimit            : YLimit,
                        PageIndex         : PageIndex,
                        SectionIndex      : SectionIndex,
                        ColumnIndex       : ColumnIndex,
                        Index             : Index,
                        StartIndex        : StartIndex,
                        ColumnsCount      : ColumnsCount,
                        ResetStartElement : bResetStartElement,
                        RecalcResult      : RecalcResult
                    };

                if (type_Table === Element.GetType())
                    this.private_RecalculateFlowTable(RecalcInfo);
                else if (type_Paragraph === Element.Get_Type())
                    this.private_RecalculateFlowParagraph(RecalcInfo);

                Index        = RecalcInfo.Index;
                RecalcResult = RecalcInfo.RecalcResult;
            }
        }
        else
        {
            if ((0 === Index && 0 === PageIndex && 0 === ColumnIndex) || Index != StartIndex || (Index === StartIndex && true === bResetStartElement))
            {
                Element.Set_DocumentIndex(Index);
                Element.Reset(X, Y, XLimit, YLimit, PageIndex, ColumnIndex, ColumnsCount);
            }

            // Делаем как в Word: Обработаем особый случай, когда на данном параграфе заканчивается секция, и он
            // пустой. В такой ситуации этот параграф не добавляет смещения по Y, и сам приписывается в конец
            // предыдущего элемента. Второй подряд идущий такой же параграф обсчитывается по обычному.

            var SectInfoElement = this.SectionsInfo.Get_SectPr(Index);
            var PrevElement     = this.Content[Index - 1]; // может быть undefined, но в следующем условии сразу стоит проверка на Index > 0
            if (Index > 0 && ( Index !== StartIndex || true !== bResetStartElement ) && Index === SectInfoElement.Index && true === Element.IsEmpty() && ( type_Paragraph !== PrevElement.GetType() || undefined === PrevElement.Get_SectionPr() ))
            {
                RecalcResult = recalcresult_NextElement;

                this.private_RecalculateEmptySectionParagraph(Element, PrevElement, PageIndex, ColumnIndex, ColumnsCount);

                // Добавим в список особых параграфов
                this.Pages[PageIndex].EndSectionParas.push(Element);

                // Выставляем этот флаг, чтобы у нас не менялось значение по Y
                bFlow = true;
            }
            else
            {
                var ElementPageIndex = this.private_GetElementPageIndex(Index, PageIndex, ColumnIndex, ColumnsCount);
                RecalcResult         = Element.Recalculate_Page(ElementPageIndex);
            }
        }

        if (true != bFlow && (RecalcResult & recalcresult_NextElement || RecalcResult & recalcresult_NextPage))
        {
            var ElementPageIndex = this.private_GetElementPageIndex(Index, PageIndex, ColumnIndex, ColumnsCount);
            Y                    = Element.Get_PageBounds(ElementPageIndex).Bottom;
        }

        PageColumn.Bounds.Bottom = Y;

        if (RecalcResult & recalcresult_CurPage)
        {
            bReDraw       = false;
            bContinue     = true;
            _PageIndex    = PageIndex;
            _SectionIndex = SectionIndex;
            _bStart       = false;

            if (RecalcResult & recalcresultflags_Column)
            {
                _ColumnIndex = ColumnIndex;
                _StartIndex  = StartIndex;
            }
            else
            {
                _ColumnIndex = 0;
                _StartIndex  = this.Pages[_PageIndex].Sections[_SectionIndex].Columns[0].Pos;
            }

            break;
        }
        else if (RecalcResult & recalcresult_NextElement)
        {
            if (Index < Count - 1)
            {
                var CurSectInfo  = this.SectionsInfo.Get_SectPr(Index);
                var NextSectInfo = this.SectionsInfo.Get_SectPr(Index + 1);
                if (CurSectInfo !== NextSectInfo)
                {
                    PageColumn.EndPos  = Index;
                    PageSection.EndPos = Index;
                    Page.EndPos        = Index;

                    if (c_oAscSectionBreakType.Continuous === NextSectInfo.SectPr.Get_Type() && true === CurSectInfo.SectPr.Compare_PageSize(NextSectInfo.SectPr) && this.Footnotes.IsEmptyPage(PageIndex))
                    {
                        // Новая секция начинается на данной странице. Нам надо получить новые поля данной секции, но
                        // на данной странице мы будет использовать только новые горизонтальные поля, а поля по вертикали
                        // используем от предыдущей секции.

                        var SectionY = Y;
                        for (var TempColumnIndex = 0; TempColumnIndex < ColumnsCount; ++TempColumnIndex)
                        {
                            if (PageSection.Columns[TempColumnIndex].Bounds.Bottom > SectionY)
                                SectionY = PageSection.Columns[TempColumnIndex].Bounds.Bottom;
                        }

                        var RealYLimit     = PageSection.YLimit;
                        PageSection.YLimit = SectionY;

                        if (true !== PageSection.Is_CalculatingSectionBottomLine() && ColumnsCount > 1 && true === PageSection.Can_RecalculateBottomLine())
                        {
                            PageSection.YLimit2 = RealYLimit;
                            PageSection.Calculate_BottomLine(false);

                            bContinue           = true;
                            _PageIndex          = PageIndex;
                            _SectionIndex       = SectionIndex;
                            _ColumnIndex        = 0;
                            _StartIndex         = this.Pages[_PageIndex].Sections[_SectionIndex].Columns[0].Pos;
                            _bStart             = false;
                            _bResetStartElement = 0 === SectionIndex ? Page.ResetStartElement : true;

                            this.Pages[_PageIndex].Sections[_SectionIndex].Reset_Columns();

                            break;
                        }
                        else
                        {
                            bContinue           = true;
                            _PageIndex          = PageIndex;
                            _SectionIndex       = SectionIndex + 1;
                            _ColumnIndex        = 0;
                            _StartIndex         = Index + 1;
                            _bStart             = false;
                            _bResetStartElement = true;

                            var NewPageSection           = new CDocumentPageSection();
                            NewPageSection.Pos           = Index;
                            NewPageSection.EndPos        = Index;
                            NewPageSection.Y             = SectionY + 0.001;
                            NewPageSection.YLimit        = true === PageSection.Is_CalculatingSectionBottomLine() ? PageSection.YLimit2 : RealYLimit;
                            NewPageSection.ColumnsSep    = NextSectInfo.SectPr.Get_ColumnsSep();
                            Page.Sections[_SectionIndex] = NewPageSection;

                            var ColumnsCount = NextSectInfo.SectPr.Get_ColumnsCount();
                            for (var ColumnIndex = 0; ColumnIndex < ColumnsCount; ++ColumnIndex)
                            {
                                Page.Sections[_SectionIndex].Columns[ColumnIndex] = new CDocumentPageColumn();
                            }

                            break;
                        }
                    }
                    else
                    {
                        bContinue           = true;
                        _PageIndex          = PageIndex + 1;
                        _SectionIndex       = 0;
                        _ColumnIndex        = 0;
                        _StartIndex         = Index + 1;
                        _bStart             = true;
                        _bResetStartElement = true;
                        break;
                    }
                }
            }
        }
        else if (RecalcResult & recalcresult_NextPage)
        {
            if (true === PageSection.Is_CalculatingSectionBottomLine() && (RecalcResult & recalcresultflags_LastFromNewPage || ColumnIndex >= ColumnsCount - 1))
            {
                PageSection.Calculate_BottomLine(true);

                bContinue           = true;
                _PageIndex          = PageIndex;
                _SectionIndex       = SectionIndex;
                _ColumnIndex        = 0;
                _StartIndex         = this.Pages[_PageIndex].Sections[_SectionIndex].Columns[0].Pos;
                _bStart             = false;
                _bResetStartElement = 0 === SectionIndex ? Page.ResetStartElement : true;

                this.Pages[_PageIndex].Sections[_SectionIndex].Reset_Columns();

                bReDraw = false;
                break;
            }
            else if (RecalcResult & recalcresultflags_LastFromNewColumn)
            {
                PageColumn.EndPos  = Index - 1;
                PageSection.EndPos = Index - 1;
                Page.EndPos        = Index - 1;

                bContinue           = true;
                _SectionIndex       = SectionIndex;
                _ColumnIndex        = ColumnIndex + 1;
                _PageIndex          = PageIndex;
                _StartIndex         = Index;
                _bStart             = true;
                _bResetStartElement = true;

                if (_ColumnIndex >= ColumnsCount)
                {
                    _SectionIndex = 0;
                    _ColumnIndex  = 0;
                    _PageIndex    = PageIndex + 1;
                }
                else
                {
                    bReDraw = false;
                }

                break;
            }
            else if (RecalcResult & recalcresultflags_LastFromNewPage)
            {
                PageColumn.EndPos  = Index - 1;
                PageSection.EndPos = Index - 1;
                Page.EndPos        = Index - 1;

                bContinue = true;

                _SectionIndex       = 0;
                _ColumnIndex        = 0;
                _PageIndex          = PageIndex + 1;
                _StartIndex         = Index;
                _bStart             = true;
                _bResetStartElement = true;

                if (PageColumn.EndPos === PageColumn.Pos)
                {
                    var Element          = this.Content[PageColumn.Pos];
                    var ElementPageIndex = this.private_GetElementPageIndex(Index, PageIndex, ColumnIndex, ColumnsCount);
                    if (true === Element.IsEmptyPage(ElementPageIndex))
                        PageColumn.Empty = true;
                }

                for (var TempColumnIndex = ColumnIndex + 1; TempColumnIndex < ColumnsCount; ++TempColumnIndex)
                {
                    PageSection.Columns[TempColumnIndex].Empty  = true;
                    PageSection.Columns[TempColumnIndex].Pos    = Index;
                    PageSection.Columns[TempColumnIndex].EndPos = Index - 1;
                }

                break;
            }
            else if (RecalcResult & recalcresultflags_Page)
            {
                PageColumn.EndPos  = Index;
                PageSection.EndPos = Index;
                Page.EndPos        = Index;

                bContinue = true;

                _SectionIndex = 0;
                _ColumnIndex  = 0;
                _PageIndex    = PageIndex + 1;
                _StartIndex   = Index;
                _bStart       = true;

                if (PageColumn.EndPos === PageColumn.Pos)
                {
                    var Element          = this.Content[PageColumn.Pos];
                    var ElementPageIndex = this.private_GetElementPageIndex(Index, PageIndex, ColumnIndex, ColumnsCount);
                    if (true === Element.IsEmptyPage(ElementPageIndex))
                        PageColumn.Empty = true;
                }

                for (var TempColumnIndex = ColumnIndex + 1; TempColumnIndex < ColumnsCount; ++TempColumnIndex)
                {
                    var ElementPageIndex = this.private_GetElementPageIndex(Index, PageIndex, TempColumnIndex, ColumnsCount);
                    this.Content[Index].Recalculate_SkipPage(ElementPageIndex);

                    PageSection.Columns[TempColumnIndex].Empty  = true;
                    PageSection.Columns[TempColumnIndex].Pos    = Index;
                    PageSection.Columns[TempColumnIndex].EndPos = Index - 1;
                }

                break;
            }
            else
            {
                PageColumn.EndPos  = Index;
                PageSection.EndPos = Index;
                Page.EndPos        = Index;

                bContinue = true;

                _ColumnIndex = ColumnIndex + 1;
                if (_ColumnIndex >= ColumnsCount)
                {
                    _SectionIndex = 0;
                    _ColumnIndex  = 0;
                    _PageIndex    = PageIndex + 1;
                }
                else
                {
                    bReDraw = false;
                }

                _StartIndex = Index;
                _bStart     = true;

                if (PageColumn.EndPos === PageColumn.Pos)
                {
                    var Element          = this.Content[PageColumn.Pos];
                    var ElementPageIndex = this.private_GetElementPageIndex(Index, PageIndex, ColumnIndex, ColumnsCount);
                    if (true === Element.IsEmptyPage(ElementPageIndex))
                        PageColumn.Empty = true;
                }

                break;
            }
        }
        else if (RecalcResult & recalcresult_PrevPage)
        {
            bReDraw   = false;
            bContinue = true;
            if (RecalcResult & recalcresultflags_Column)
            {
                if (0 === ColumnIndex)
                {
                    _PageIndex    = Math.max(PageIndex - 1, 0);
                    _SectionIndex = this.Pages[_PageIndex].Sections.length - 1;
                    _ColumnIndex  = this.Pages[_PageIndex].Sections[_SectionIndex].Columns.length - 1;
                }
                else
                {
                    _PageIndex    = PageIndex;
                    _ColumnIndex  = ColumnIndex - 1;
                    _SectionIndex = SectionIndex;
                }
            }
            else
            {
                if (_SectionIndex > 0)
                {
                    // Сюда мы никогда не должны попадать
                }

                _PageIndex    = Math.max(PageIndex - 1, 0);
                _SectionIndex = this.Pages[_PageIndex].Sections.length - 1;
                _ColumnIndex  = 0;
            }

            _StartIndex = this.Pages[_PageIndex].Sections[_SectionIndex].Columns[_ColumnIndex].Pos;
            _bStart     = false;
            break;
        }

        if (docpostype_Content == this.Get_DocPosType() && Index === this.CurPos.ContentPos)
        {
            if (type_Paragraph === Element.GetType())
                this.CurPage = PageIndex;
            else
                this.CurPage = PageIndex; // TODO: переделать
        }

        if (docpostype_Content === this.Get_DocPosType() && ((true !== this.Selection.Use && Index > this.CurPos.ContentPos) || (true === this.Selection.Use && Index > this.Selection.EndPos && Index > this.Selection.StartPos)))
            this.private_UpdateCursorXY(true, true);
    }

    if (Index >= Count)
    {
        // До перерисовки селекта должны выставить
        Page.EndPos        = Count - 1;
        PageSection.EndPos = Count - 1;
        PageColumn.EndPos  = Count - 1;

        //console.log("LastRecalc: " + ((new Date().getTime() - this.StartTime) / 1000));
    }

    if (Index >= Count || _PageIndex > PageIndex || _ColumnIndex > ColumnIndex)
    {
        this.private_RecalculateShiftFootnotes(PageIndex, ColumnIndex, Y, SectPr);
    }

    if (true === bReDraw)
    {
        this.DrawingDocument.OnRecalculatePage(PageIndex, this.Pages[PageIndex]);
    }

    if (Index >= Count)
    {
		// Пересчет основной части документа законечен. Возможна ситуация, при которой последние сноски с данной
		// страницы переносятся на следующую (т.е. остались непересчитанные сноски). Эти сноски нужно пересчитать
		if (this.Footnotes.HaveContinuesFootnotes(PageIndex, ColumnIndex))
		{
			bContinue    = true;
			_PageIndex   = PageIndex;
			_ColumnIndex = ColumnIndex + 1;
			if (_ColumnIndex >= ColumnsCount)
			{
				_ColumnIndex = 0;
				_PageIndex   = PageIndex + 1;
			}

			_bStart     = true;
			_StartIndex = Count;
		}
		else
		{
			this.private_CheckUnusedFields();
			this.private_CheckCurPage();
			this.DrawingDocument.OnEndRecalculate(true);
			this.DrawingObjects.onEndRecalculateDocument(this.Pages.length);

			if (true === this.Selection.UpdateOnRecalc)
			{
				this.Selection.UpdateOnRecalc = false;
				this.DrawingDocument.OnSelectEnd();
			}

			this.FullRecalc.Id           = null;
			this.FullRecalc.MainStartPos = -1;

			// Основной пересчет окончен, если в колонтитулах есть элемент с количеством страниц, тогда нам надо
			// запустить дополнительный пересчет колонтитулов.
			// Если так случилось, что после повторного полного пересчета, вызванного изменением количества страниц и
			// изменением метрик колонтитула, новое количество страниц стало меньше, чем раньше, тогда мы не пересчитываем
			// дальше, чтобы избежать зацикливаний.

			if (-1 === this.HdrFtrRecalc.PageCount || this.HdrFtrRecalc.PageCount < this.Pages.length)
			{
				this.HdrFtrRecalc.PageCount = this.Pages.length;
				var nPageCountStartPage     = this.HdrFtr.HavePageCountElement();
				if (-1 !== nPageCountStartPage)
				{
					this.DrawingDocument.OnStartRecalculate(nPageCountStartPage);
					this.HdrFtrRecalc.PageIndex = nPageCountStartPage;
					this.private_RecalculateHdrFtrPageCountUpdate();
				}
			}

			//TODO функция не должна вызываться здесь! необходимо перенести(DrawingDocument.UpdateTarget)
			//TODO проверить баг 35764 -> убрал проверку на showSpecialPasteButton
			var specialPasteHelper = window['AscCommon'].g_specialPasteHelper;
			if(specialPasteHelper && specialPasteHelper.showButtonIdParagraph && !specialPasteHelper.pasteStart)
			{
				specialPasteHelper.SpecialPasteButtonById_Show();
			}
			specialPasteHelper.endRecalcDocument = true;
		}
    }

    if (true === bContinue)
    {
        this.FullRecalc.PageIndex         = _PageIndex;
        this.FullRecalc.SectionIndex      = _SectionIndex;
        this.FullRecalc.ColumnIndex       = _ColumnIndex;
        this.FullRecalc.StartIndex        = _StartIndex;
        this.FullRecalc.Start             = _bStart;
        this.FullRecalc.ResetStartElement = _bResetStartElement;
        this.FullRecalc.MainStartPos      = _StartIndex;

        if (window["NATIVE_EDITOR_ENJINE_SYNC_RECALC"] === true)
        {
            if (_PageIndex > this.FullRecalc.StartPage + 2)
            {
                if (window["native"]["WC_CheckSuspendRecalculate"] !== undefined)
                {
                    //if (window["native"]["WC_CheckSuspendRecalculate"]())
                    //    return;

                    this.FullRecalc.Id = setTimeout(Document_Recalculate_Page, 10);
                    return;
                }
            }

            this.Recalculate_Page();
            return;
        }

        if (_PageIndex > this.FullRecalc.StartPage + 2)
        {
            this.FullRecalc.Id = setTimeout(Document_Recalculate_Page, 20);
        }
        else
        {
            this.Recalculate_Page();
        }
    }
};
CDocument.prototype.private_RecalculateIsNewSection = function(nPageAbs, nContentIndex)
{
	// Определим, является ли данная страница первой в новой секции
	var bNewSection = ( 0 === nPageAbs ? true : false );
	if (0 !== nPageAbs)
	{
		var PrevStartIndex = this.Pages[nPageAbs - 1].Pos;
		var CurSectInfo    = this.SectionsInfo.Get_SectPr(nContentIndex);
		var PrevSectInfo   = this.SectionsInfo.Get_SectPr(PrevStartIndex);

		if (PrevSectInfo !== CurSectInfo && (c_oAscSectionBreakType.Continuous !== CurSectInfo.SectPr.Get_Type() || true !== CurSectInfo.SectPr.Compare_PageSize(PrevSectInfo.SectPr) ))
			bNewSection = true;
	}

	return bNewSection;
};
CDocument.prototype.private_RecalculateShiftFootnotes = function(nPageAbs, nColumnAbs, dY, oSectPr)
{
	var nPosType = oSectPr.GetFootnotePos();

	// section_footnote_PosDocEnd, section_footnote_PosSectEnd ненужные константы по логике, но Word воспринимает их
	// именно как section_footnote_PosBeneathText, в то время как все остальное (даже константа не по формату)
	// воспринимает как  section_footnote_PosPageBottom.
	if (section_footnote_PosBeneathText === nPosType || section_footnote_PosDocEnd === nPosType || section_footnote_PosSectEnd === nPosType)
	{
		this.Footnotes.Shift(nPageAbs, nColumnAbs, 0, dY);
	}
	else
	{
		var dFootnotesHeight = this.Footnotes.GetHeight(nPageAbs, nColumnAbs);
		var oPageMetrics     = this.Get_PageContentStartPos(nPageAbs);
		this.Footnotes.Shift(nPageAbs, nColumnAbs, 0, oPageMetrics.YLimit - dFootnotesHeight);
	}
};
CDocument.prototype.private_RecalculateFlowTable             = function(RecalcInfo)
{
    var Element            = RecalcInfo.Element;
    var X                  = RecalcInfo.X;
    var Y                  = RecalcInfo.Y;
    var XLimit             = RecalcInfo.XLimit;
    var YLimit             = RecalcInfo.YLimit;
    var PageIndex          = RecalcInfo.PageIndex;
    var ColumnIndex        = RecalcInfo.ColumnIndex;
    var Index              = RecalcInfo.Index;
    var StartIndex         = RecalcInfo.StartIndex;
    var ColumnsCount       = RecalcInfo.ColumnsCount;
    var bResetStartElement = RecalcInfo.ResetStartElement;
    var RecalcResult       = RecalcInfo.RecalcResult;

    // Когда у нас колонки мы не разбиваем плавающую таблицу на страницы.
    var isColumns = ColumnsCount > 1 ? true : false;
    if (true === isColumns)
        YLimit = 10000;

    if (true === this.RecalcInfo.Can_RecalcObject())
    {
        var ElementPageIndex = 0;
        if ((0 === Index && 0 === PageIndex) || Index != StartIndex || (Index === StartIndex && true === bResetStartElement))
        {
            Element.Set_DocumentIndex(Index);
            Element.Reset(X, Y, XLimit, YLimit, PageIndex, ColumnIndex, ColumnsCount);
            ElementPageIndex = 0;
        }
        else
        {
            ElementPageIndex = PageIndex - Element.PageNum;
        }

        var TempRecalcResult = Element.Recalculate_Page(ElementPageIndex);
        this.RecalcInfo.Set_FlowObject(Element, ElementPageIndex, TempRecalcResult, -1, {
            X      : X,
            Y      : Y,
            XLimit : XLimit,
            YLimit : YLimit
        });

        if (((0 === Index && 0 === PageIndex) || Index != StartIndex) && true != Element.IsContentOnFirstPage() && true !== isColumns)
        {
            this.RecalcInfo.Set_PageBreakBefore(true);
            RecalcResult = recalcresult_NextPage | recalcresultflags_LastFromNewPage;
        }
        else
        {
            var FlowTable = new CFlowTable(Element, PageIndex);
            this.DrawingObjects.addFloatTable(FlowTable);
            RecalcResult = recalcresult_CurPage;
        }
    }
    else if (true === this.RecalcInfo.Check_FlowObject(Element))
    {
        if (Element.PageNum === PageIndex)
        {
            if (true === this.RecalcInfo.Is_PageBreakBefore())
            {
                this.RecalcInfo.Reset();
                RecalcResult = recalcresult_NextPage | recalcresultflags_LastFromNewPage;
            }
            else
            {
                X      = this.RecalcInfo.AdditionalInfo.X;
                Y      = this.RecalcInfo.AdditionalInfo.Y;
                XLimit = this.RecalcInfo.AdditionalInfo.XLimit;
                YLimit = this.RecalcInfo.AdditionalInfo.YLimit;

                // Пересчет нужнен для обновления номеров колонок и страниц
                Element.Reset(X, Y, XLimit, YLimit, PageIndex, ColumnIndex, ColumnsCount);
                RecalcResult = Element.Recalculate_Page(0);
                this.RecalcInfo.FlowObjectPage++;

                if (true === isColumns)
                    RecalcResult = recalcresult_NextElement;

                if (RecalcResult & recalcresult_NextElement)
                    this.RecalcInfo.Reset();
            }
        }
        else if (Element.PageNum > PageIndex || (this.RecalcInfo.FlowObjectPage <= 0 && Element.PageNum < PageIndex))
        {
            this.DrawingObjects.removeFloatTableById(PageIndex - 1, Element.Get_Id());
            this.RecalcInfo.Set_PageBreakBefore(true);
            RecalcResult = recalcresult_PrevPage;
        }
        else
        {
            RecalcResult = Element.Recalculate_Page(PageIndex - Element.PageNum);
            this.RecalcInfo.FlowObjectPage++;
            this.DrawingObjects.addFloatTable(new CFlowTable(Element, PageIndex));

            if (RecalcResult & recalcresult_NextElement)
                this.RecalcInfo.Reset();
        }
    }
    else
    {
        RecalcResult = recalcresult_NextElement;
    }

    RecalcInfo.Index        = Index;
    RecalcInfo.RecalcResult = RecalcResult;
};
CDocument.prototype.private_RecalculateFlowParagraph         = function(RecalcInfo)
{
    var Element            = RecalcInfo.Element;
    var X                  = RecalcInfo.X;
    var Y                  = RecalcInfo.Y;
    var XLimit             = RecalcInfo.XLimit;
    var YLimit             = RecalcInfo.YLimit;
    var PageIndex          = RecalcInfo.PageIndex;
    var ColumnIndex        = RecalcInfo.ColumnIndex;
    var Index              = RecalcInfo.Index;
    var StartIndex         = RecalcInfo.StartIndex;
    var ColumnsCount       = RecalcInfo.ColumnsCount;
    var bResetStartElement = RecalcInfo.ResetStartElement;
    var RecalcResult       = RecalcInfo.RecalcResult;

    var Page = this.Pages[PageIndex];

    if (true === this.RecalcInfo.Can_RecalcObject())
    {
        var FramePr = Element.Get_FramePr();

        // Рассчитаем количество подряд идущих параграфов с одинаковыми FramePr
        var FlowCount = this.private_RecalculateFlowParagraphCount(Index);

        var Page_W = Page.Width;
        var Page_H = Page.Height;

        var Page_Field_L = Page.Margins.Left;
        var Page_Field_R = Page.Margins.Right;
        var Page_Field_T = Page.Margins.Top;
        var Page_Field_B = Page.Margins.Bottom;

        var Column_Field_L = X;
        var Column_Field_R = XLimit;

        //--------------------------------------------------------------------------------------------------
        // 1. Рассчитаем размер рамки
        //--------------------------------------------------------------------------------------------------
        var FrameH = 0;
        var FrameW = -1;

        var Frame_XLimit = FramePr.Get_W();
        var Frame_YLimit = FramePr.Get_H();

		var FrameHRule = ( undefined === FramePr.HRule ? Asc.linerule_Auto : FramePr.HRule );

        if (undefined === Frame_XLimit)
            Frame_XLimit = Page_Field_R - Page_Field_L;

        if (undefined === Frame_YLimit || Asc.linerule_Auto === FrameHRule)
            Frame_YLimit = Page_H;

        for (var TempIndex = Index; TempIndex < Index + FlowCount; ++TempIndex)
        {
            var TempElement = this.Content[TempIndex];
            TempElement.Set_DocumentIndex(TempIndex);

			var ElementPageIndex = 0;
			if ((0 === TempIndex && 0 === PageIndex) || TempIndex != StartIndex || (TempIndex === StartIndex && true === bResetStartElement))
			{
				TempElement.Set_DocumentIndex(TempIndex);
				TempElement.Reset(0, FrameH, Frame_XLimit, Frame_YLimit, PageIndex, ColumnIndex, ColumnsCount);
				ElementPageIndex = 0;
			}
			else
			{
				ElementPageIndex = PageIndex - Element.PageNum;
			}

            RecalcResult = TempElement.Recalculate_Page(ElementPageIndex);

            if (!(RecalcResult & recalcresult_NextElement))
                break;

            FrameH = TempElement.Get_PageBounds(0).Bottom;
        }

        if (-1 === FrameW && 1 === FlowCount && 1 === Element.Lines.length && undefined === FramePr.Get_W())
        {
			FrameW     = Element.GetAutoWidthForDropCap();
			var ParaPr = Element.Get_CompiledPr2(false).ParaPr;
			FrameW += ParaPr.Ind.Left + ParaPr.Ind.FirstLine;

            // Если прилегание в данном случае не к левой стороне, тогда пересчитываем параграф,
            // с учетом того, что ширина буквицы должна быть FrameW
            if (align_Left != ParaPr.Jc)
            {
                Element.Reset(0, 0, FrameW, Frame_YLimit, PageIndex, ColumnIndex, ColumnsCount);
                Element.Recalculate_Page(0);
                FrameH = TempElement.Get_PageBounds(0).Bottom;
            }
        }
        else if (-1 === FrameW)
        {
            FrameW = Frame_XLimit;
        }

        if ((Asc.linerule_AtLeast === FrameHRule && FrameH < FramePr.H) || Asc.linerule_Exact === FrameHRule)
        {
            FrameH = FramePr.H;
        }
        //--------------------------------------------------------------------------------------------------
        // 2. Рассчитаем положение рамки
        //--------------------------------------------------------------------------------------------------

        // Теперь зная размеры рамки можем рассчитать ее позицию
        var FrameHAnchor = ( FramePr.HAnchor === undefined ? c_oAscHAnchor.Margin : FramePr.HAnchor );
        var FrameVAnchor = ( FramePr.VAnchor === undefined ? c_oAscVAnchor.Text : FramePr.VAnchor );

        // Рассчитаем положение по горизонтали
        var FrameX = 0;
        if (undefined != FramePr.XAlign || undefined === FramePr.X)
        {
            var XAlign = c_oAscXAlign.Left;
            if (undefined != FramePr.XAlign)
                XAlign = FramePr.XAlign;

            switch (FrameHAnchor)
            {
                case c_oAscHAnchor.Page   :
                {
                    switch (XAlign)
                    {
                        case c_oAscXAlign.Inside  :
                        case c_oAscXAlign.Outside :
                        case c_oAscXAlign.Left    :
                            FrameX = Page_Field_L - FrameW;
                            break;
                        case c_oAscXAlign.Right   :
                            FrameX = Page_Field_R;
                            break;
                        case c_oAscXAlign.Center  :
                            FrameX = (Page_W - FrameW) / 2;
                            break;
                    }

                    break;
                }
                case c_oAscHAnchor.Text   :
                case c_oAscHAnchor.Margin :
                {
                    switch (XAlign)
                    {
                        case c_oAscXAlign.Inside  :
                        case c_oAscXAlign.Outside :
                        case c_oAscXAlign.Left    :
                            FrameX = Column_Field_L;
                            break;
                        case c_oAscXAlign.Right   :
                            FrameX = Column_Field_R - FrameW;
                            break;
                        case c_oAscXAlign.Center  :
                            FrameX = (Column_Field_R + Column_Field_L - FrameW) / 2;
                            break;
                    }

                    break;
                }
            }

        }
        else
        {
            switch (FrameHAnchor)
            {
                case c_oAscHAnchor.Page   :
                    FrameX = FramePr.X;
                    break;
                case c_oAscHAnchor.Text   :
                case c_oAscHAnchor.Margin :
                    FrameX = Page_Field_L + FramePr.X;
                    break;
            }
        }

        if (FrameW + FrameX > Page_W)
            FrameX = Page_W - FrameW;

        if (FrameX < 0)
            FrameX = 0;

        // Рассчитаем положение по вертикали
        var FrameY = 0;
        if (undefined != FramePr.YAlign)
        {
            var YAlign = FramePr.YAlign;
            // Случай c_oAscYAlign.Inline не обрабатывается, потому что такие параграфы считаются Inline

            switch (FrameVAnchor)
            {
                case c_oAscVAnchor.Page   :
                {
                    switch (YAlign)
                    {
                        case c_oAscYAlign.Inside  :
                        case c_oAscYAlign.Outside :
                        case c_oAscYAlign.Top     :
                            FrameY = 0;
                            break;
                        case c_oAscYAlign.Bottom  :
                            FrameY = Page_H - FrameH;
                            break;
                        case c_oAscYAlign.Center  :
                            FrameY = (Page_H - FrameH) / 2;
                            break;
                    }

                    break;
                }
                case c_oAscVAnchor.Text   :
                {
                    FrameY = Y;
                    break;
                }
                case c_oAscVAnchor.Margin :
                {
                    switch (YAlign)
                    {
                        case c_oAscYAlign.Inside  :
                        case c_oAscYAlign.Outside :
                        case c_oAscYAlign.Top     :
                            FrameY = Page_Field_T;
                            break;
                        case c_oAscYAlign.Bottom  :
                            FrameY = Page_Field_B - FrameH;
                            break;
                        case c_oAscYAlign.Center  :
                            FrameY = (Page_Field_B + Page_Field_T - FrameH) / 2;
                            break;
                    }

                    break;
                }
            }
        }
        else
        {
            var FramePrY = 0;
            if (undefined != FramePr.Y)
                FramePrY = FramePr.Y;

            switch (FrameVAnchor)
            {
                case c_oAscVAnchor.Page   :
                    FrameY = FramePrY;
                    break;
                case c_oAscVAnchor.Text   :
                    FrameY = FramePrY + Y;
                    break;
                case c_oAscVAnchor.Margin :
                    FrameY = FramePrY + Page_Field_T;
                    break;
            }
        }

        if (FrameH + FrameY > Page_H)
            FrameY = Page_H - FrameH;

        // TODO: Пересмотреть, почему эти погрешности возникают
        // Избавляемся от погрешности
        FrameY += 0.001;
        FrameH -= 0.002;

        if (FrameY < 0)
            FrameY = 0;

        var FrameBounds = this.Content[Index].Get_FrameBounds(FrameX, FrameY, FrameW, FrameH);
        var FrameX2     = FrameBounds.X, FrameY2 = FrameBounds.Y, FrameW2 = FrameBounds.W, FrameH2 = FrameBounds.H;

        if (!(RecalcResult & recalcresult_NextElement))
        {
            // Ничего не делаем здесь, пересчитываем текущую страницу заново, либо предыдущую

            if (RecalcResult & recalcresult_PrevPage)
                this.RecalcInfo.Set_FrameRecalc(false);

            // TODO: Если мы заново пересчитываем текущую страницу, проверить надо ли обнулять параметр RecalcInfo.FrameRecalc
        }
        else if ((FrameY2 + FrameH2 > YLimit || Y > YLimit - 0.001) && Index != StartIndex)
        {
            this.RecalcInfo.Set_FrameRecalc(true);
            RecalcResult = recalcresult_NextPage | recalcresultflags_LastFromNewColumn;
        }
        else
        {
            this.RecalcInfo.Set_FrameRecalc(false);
            for (var TempIndex = Index; TempIndex < Index + FlowCount; ++TempIndex)
            {
                var TempElement = this.Content[TempIndex];
                TempElement.Shift(TempElement.Pages.length - 1, FrameX, FrameY);
                TempElement.Set_CalculatedFrame(FrameX, FrameY, FrameW, FrameH, FrameX2, FrameY2, FrameW2, FrameH2, PageIndex);
            }

            var FrameDx = ( undefined === FramePr.HSpace ? 0 : FramePr.HSpace );
            var FrameDy = ( undefined === FramePr.VSpace ? 0 : FramePr.VSpace );

            this.DrawingObjects.addFloatTable(new CFlowParagraph(Element, FrameX2, FrameY2, FrameW2, FrameH2, FrameDx, FrameDy, Index, FlowCount, FramePr.Wrap));

            Index += FlowCount - 1;

            if (FrameY >= Y && FrameX >= X - 0.001)
            {
                RecalcResult = recalcresult_NextElement;
            }
            else
            {
                this.RecalcInfo.Set_FlowObject(Element, PageIndex, recalcresult_NextElement, FlowCount);
                RecalcResult = recalcresult_CurPage | recalcresultflags_Page;
            }
        }
    }
    else if (true === this.RecalcInfo.Check_FlowObject(Element) && true === this.RecalcInfo.Is_PageBreakBefore())
    {
        this.RecalcInfo.Reset();
        this.RecalcInfo.Set_FrameRecalc(true);
        RecalcResult = recalcresult_NextPage | recalcresultflags_LastFromNewPage;
    }
    else if (true === this.RecalcInfo.Check_FlowObject(Element))
    {
        if (this.RecalcInfo.FlowObjectPage !== PageIndex)
        {
            // Номер страницы не такой же (должен быть +1), значит нам надо заново персесчитать предыдущую страницу
            // с условием, что данная рамка начнется с новой страницы
            this.RecalcInfo.Set_PageBreakBefore(true);
            this.DrawingObjects.removeFloatTableById(this.RecalcInfo.FlowObjectPage, Element.Get_Id());
            RecalcResult = recalcresult_PrevPage | recalcresultflags_Page;
        }
        else
        {
            // Все нормально рассчиталось

            // В случае колонок может так случится, что логическое место окажется в другой колонке, поэтому мы делаем
            // Reset для обновления логической позиции, но физическую позицию не меняем.
            var FlowCount = this.RecalcInfo.FlowObjectElementsCount;
            for (var TempIndex = Index; TempIndex < Index + FlowCount; ++TempIndex)
            {
                var TempElement = this.Content[TempIndex];
                TempElement.Reset(TempElement.X, TempElement.Y, TempElement.XLimit, TempElement.YLimit, TempElement.PageNum, ColumnIndex, ColumnsCount);
            }


            Index += this.RecalcInfo.FlowObjectElementsCount - 1;
            this.RecalcInfo.Reset();
            RecalcResult = recalcresult_NextElement;
        }
    }
    else
    {
        // В случае колонок может так случится, что логическое место окажется в другой колонке, поэтому мы делаем
        // Reset для обновления логической позиции, но физическую позицию не меняем.
        var FlowCount = this.private_RecalculateFlowParagraphCount(Index);
        for (var TempIndex = Index; TempIndex < Index + FlowCount; ++TempIndex)
        {
            var TempElement = this.Content[TempIndex];
            TempElement.Reset(TempElement.X, TempElement.Y, TempElement.XLimit, TempElement.YLimit, PageIndex, ColumnIndex, ColumnsCount);
        }

        RecalcResult = recalcresult_NextElement;
    }

    RecalcInfo.Index        = Index;
    RecalcInfo.RecalcResult = RecalcResult;
};
CDocument.prototype.private_RecalculateFlowParagraphCount    = function(Index)
{
    var Element   = this.Content[Index];
    var FramePr   = Element.Get_FramePr();
    var FlowCount = 1;
    for (var TempIndex = Index + 1, Count = this.Content.length; TempIndex < Count; ++TempIndex)
    {
        var TempElement = this.Content[TempIndex];
        if (type_Paragraph === TempElement.GetType() && true != TempElement.Is_Inline())
        {
            var TempFramePr = TempElement.Get_FramePr();
            if (true === FramePr.Compare(TempFramePr))
                FlowCount++;
            else
                break;
        }
        else
            break;
    }

    return FlowCount;
};
CDocument.prototype.private_RecalculateHdrFtrPageCountUpdate = function()
{
	this.HdrFtrRecalc.Id = null;

	var nPageAbs    = this.HdrFtrRecalc.PageIndex;
	var nPagesCount = this.Pages.length;

	while (nPageAbs < nPagesCount)
	{
		var Result = this.HdrFtr.RecalculatePageCountUpdate(nPageAbs, nPagesCount);
		if (null === Result)
		{
			nPageAbs++;
		}
		else if (false === Result)
		{
			this.DrawingDocument.OnRecalculatePage(nPageAbs, this.Pages[nPageAbs]);

			if (nPageAbs < this.HdrFtrRecalc.PageIndex + 5)
			{
				nPageAbs++;
			}
			else
			{
				this.HdrFtrRecalc.PageIndex = nPageAbs + 1;
				this.HdrFtrRecalc.Id        = setTimeout(Document_Recalculate_HdrFtrPageCount, 20);
				return;
			}
		}
		else
		{
			this.RecalcInfo.Reset();
			this.FullRecalc.PageIndex         = nPageAbs;
			this.FullRecalc.SectionIndex      = 0;
			this.FullRecalc.ColumnIndex       = 0;
			this.FullRecalc.StartIndex        = this.Pages[nPageAbs].Pos;
			this.FullRecalc.Start             = true;
			this.FullRecalc.StartPage         = nPageAbs;
			this.FullRecalc.ResetStartElement = this.private_RecalculateIsNewSection(nPageAbs, this.Pages[nPageAbs].Pos);
			this.FullRecalc.MainStartPos      = this.Pages[nPageAbs].Pos;

			this.DrawingDocument.OnStartRecalculate(nPageAbs);
			this.Recalculate_Page();
			return;
		}
	}

	if (nPageAbs >= nPagesCount)
		this.DrawingDocument.OnEndRecalculate(false, true);
};
CDocument.prototype.private_CheckUnusedFields = function()
{
	if (this.Content.length <= 0)
		return;

	var oLastPara = this.Content[this.Content.length - 1];
	if (type_Paragraph !== oLastPara.GetType())
		return;

	var oInfo = oLastPara.GetEndInfoByPage(oLastPara.GetPagesCount() - 1);
	for (var nIndex = 0, nCount = oInfo.ComplexFields.length; nIndex < nCount; ++nIndex)
	{
		var oComplexField = oInfo.ComplexFields[nIndex].ComplexField;
		var oBeginChar    = oComplexField.GetBeginChar();
		var oEndChar      = oComplexField.GetEndChar();
		var oSeparateChar = oComplexField.GetSeparateChar();

		if (oBeginChar)
			oBeginChar.SetUse(false);

		if (oEndChar)
			oEndChar.SetUse(false);

		if (oSeparateChar)
			oSeparateChar.SetUse(false);
	}
};
/**
 * Получаем номер рассчитанной страницы, с которой начинается заданный элемент
 * @param nElementPos
 * @returns {number}
 */
CDocument.prototype.private_GetPageByPos = function(nElementPos)
{
	var nResultPage = -1;
	for (var nCurPage = 0, nPagesCount = this.Pages.length; nCurPage < nPagesCount; ++nCurPage)
	{
		if (nElementPos > this.Pages[nCurPage].Pos)
			nResultPage = nCurPage;
		else
			break;
	}

	return nResultPage;
};
CDocument.prototype.OnColumnBreak_WhileRecalculate           = function()
{
    var PageIndex    = this.FullRecalc.PageIndex;
    var SectionIndex = this.FullRecalc.SectionIndex;

    if (this.Pages[PageIndex] && this.Pages[PageIndex].Sections[SectionIndex])
        this.Pages[PageIndex].Sections[SectionIndex].DoNotRecalc_BottomLine();
};
CDocument.prototype.Reset_RecalculateCache                   = function()
{
    this.SectionsInfo.Reset_HdrFtrRecalculateCache();

    var Count = this.Content.length;
    for (var Index = 0; Index < Count; Index++)
    {
        this.Content[Index].Reset_RecalculateCache();
    }

    this.Footnotes.ResetRecalculateCache();
};
CDocument.prototype.Stop_Recalculate                         = function()
{
    if (null != this.FullRecalc.Id)
    {
        clearTimeout(this.FullRecalc.Id);
        this.FullRecalc.Id = null;
    }

    this.DrawingDocument.OnStartRecalculate(0);
};
CDocument.prototype.OnContentRecalculate                     = function(bNeedRecalc, PageNum, DocumentIndex)
{
    if (false === bNeedRecalc)
    {
        var Element = this.Content[DocumentIndex];
        // Просто перерисуем все страницы, на которых находится данный элеменет
        for (var PageNum = Element.PageNum; PageNum < Element.PageNum + Element.Pages.length; PageNum++)
        {
            this.DrawingDocument.OnRecalculatePage(PageNum, this.Pages[PageNum]);
        }

        this.DrawingDocument.OnEndRecalculate(false, true);

        this.Document_UpdateRulersState();
    }
    else
    {
        this.Recalculate(false, false);
    }
};
CDocument.prototype.OnContentReDraw                          = function(StartPage, EndPage)
{
    this.ReDraw(StartPage, EndPage);
};
CDocument.prototype.CheckTargetUpdate = function()
{
	// Проверим можно ли вообще пересчитывать текущее положение.
	if (this.DrawingDocument.UpdateTargetFromPaint === true)
	{
		if (true === this.DrawingDocument.UpdateTargetCheck)
			this.NeedUpdateTarget = this.DrawingDocument.UpdateTargetCheck;
		this.DrawingDocument.UpdateTargetCheck = false;
	}

	var bFlag = this.Controller.CanUpdateTarget();

	if (true === this.NeedUpdateTarget && true === bFlag && false === this.IsMovingTableBorder())
	{
		// Обновляем курсор сначала, чтобы обновить текущую страницу
		this.RecalculateCurPos();
		this.NeedUpdateTarget = false;
	}
};
CDocument.prototype.RecalculateCurPos = function()
{
	if (true === this.TurnOffRecalcCurPos)
		return;

	if (true === AscCommon.CollaborativeEditing.Get_GlobalLockSelection())
		return;

	this.DrawingDocument.UpdateTargetTransform(null);

	this.Controller.RecalculateCurPos();

	// TODO: Здесь добавлено обновление линейки, чтобы обновлялись границы рамки при наборе текста, а также чтобы
	//       обновлялись поля колонтитулов при наборе текста.
	this.Document_UpdateRulersState();
};
CDocument.prototype.private_CheckCurPage = function()
{
	if (true === this.TurnOffRecalcCurPos)
		return;

	if (true === AscCommon.CollaborativeEditing.Get_GlobalLockSelection())
		return;

	var nCurPage = this.Controller.GetCurPage();
	if (-1 !== nCurPage)
		this.CurPage = nCurPage;
};
CDocument.prototype.Set_TargetPos = function(X, Y, PageNum)
{
	this.TargetPos.X       = X;
	this.TargetPos.Y       = Y;
	this.TargetPos.PageNum = PageNum;
};
/**
 * Запрос на перерисовку заданного отрезка страниц.
 * @param StartPage
 * @param EndPage
 */
CDocument.prototype.ReDraw                                   = function(StartPage, EndPage)
{
    if ("undefined" === typeof(StartPage))
        StartPage = 0;
    if ("undefined" === typeof(EndPage))
        EndPage = this.DrawingDocument.m_lCountCalculatePages;

    for (var CurPage = StartPage; CurPage <= EndPage; CurPage++)
        this.DrawingDocument.OnRepaintPage(CurPage);
};
CDocument.prototype.DrawPage                                 = function(nPageIndex, pGraphics)
{
    this.Draw(nPageIndex, pGraphics);
};
CDocument.prototype.CanDrawPage = function(nPageAbs)
{
	if (null !== this.FullRecalc.Id && nPageAbs >= this.FullRecalc.PageIndex - 1)
		return false;

	return true;
};
/**
 * Перерисовка заданной страницы документа.
 * @param nPageIndex
 * @param pGraphics
 */
CDocument.prototype.Draw                                     = function(nPageIndex, pGraphics)
{
    // TODO: Пока делаем обновление курсоров при каждой отрисовке. Необходимо поменять
    this.CollaborativeEditing.Update_ForeignCursorsPositions();
    //--------------------------------------------------------------------------------------------------------------

    this.Comments.Reset_Drawing(nPageIndex);

    // Определим секцию
    var Page_StartPos = this.Pages[nPageIndex].Pos;
    var SectPr        = this.SectionsInfo.Get_SectPr(Page_StartPos).SectPr;

    if (docpostype_HdrFtr !== this.CurPos.Type && !this.IsViewMode())
        pGraphics.Start_GlobalAlpha();

    // Рисуем границы вокруг страницы (если границы надо рисовать под текстом)
    if (section_borders_ZOrderBack === SectPr.Get_Borders_ZOrder())
        this.Draw_Borders(pGraphics, SectPr);

    this.HdrFtr.Draw(nPageIndex, pGraphics);

    // Рисуем содержимое документа на данной странице
    if (docpostype_HdrFtr === this.CurPos.Type)
        pGraphics.put_GlobalAlpha(true, 0.4);
    else if (!this.IsViewMode())
        pGraphics.End_GlobalAlpha();

    this.DrawingObjects.drawBehindDoc(nPageIndex, pGraphics);

    this.Footnotes.Draw(nPageIndex, pGraphics);

    var Page = this.Pages[nPageIndex];
    for (var SectionIndex = 0, SectionsCount = Page.Sections.length; SectionIndex < SectionsCount; ++SectionIndex)
    {
        var PageSection = Page.Sections[SectionIndex];
        for (var ColumnIndex = 0, ColumnsCount = PageSection.Columns.length; ColumnIndex < ColumnsCount; ++ColumnIndex)
        {
            var Column         = PageSection.Columns[ColumnIndex];
            var ColumnStartPos = Column.Pos;
            var ColumnEndPos   = Column.EndPos;

            if (true === PageSection.ColumnsSep && ColumnIndex > 0 && !Column.IsEmpty())
			{

				var SepX = (Column.X + PageSection.Columns[ColumnIndex - 1].XLimit) / 2;
				pGraphics.p_color(0, 0, 0, 255);
				pGraphics.drawVerLine(c_oAscLineDrawingRule.Left, SepX, PageSection.Y, PageSection.YLimit, 0.75 * g_dKoef_pt_to_mm);
			}

            // Плавающие объекты не должны попадать в клип колонок
            var FlowElements = [];

            if (ColumnsCount > 1)
            {
                pGraphics.SaveGrState();

                var X    = ColumnIndex === 0 ? 0 : Column.X - Column.SpaceBefore / 2;
                var XEnd = (ColumnIndex >= ColumnsCount - 1 ? Page.Width : Column.XLimit + Column.SpaceAfter / 2);
                pGraphics.AddClipRect(X, 0, XEnd - X, Page.Height);
            }

            for (var ContentPos = ColumnStartPos; ContentPos <= ColumnEndPos; ++ContentPos)
            {
                if (true === this.Content[ContentPos].Is_Inline())
                {
                    var ElementPageIndex = this.private_GetElementPageIndex(ContentPos, nPageIndex, ColumnIndex, ColumnsCount);
                    this.Content[ContentPos].Draw(ElementPageIndex, pGraphics);
                }
                else
                {
                    FlowElements.push(ContentPos);
                }
            }

            if (ColumnsCount > 1)
            {
                pGraphics.RestoreGrState();
            }

            for (var FlowPos = 0, FlowsCount = FlowElements.length; FlowPos < FlowsCount; ++FlowPos)
            {
                var ContentPos       = FlowElements[FlowPos];
                var ElementPageIndex = this.private_GetElementPageIndex(ContentPos, nPageIndex, ColumnIndex, ColumnsCount);
                this.Content[ContentPos].Draw(ElementPageIndex, pGraphics);
            }
        }
    }

    this.DrawingObjects.drawBeforeObjects(nPageIndex, pGraphics);

    // Рисуем границы вокруг страницы (если границы надо рисовать перед текстом)
    if (section_borders_ZOrderFront === SectPr.Get_Borders_ZOrder())
        this.Draw_Borders(pGraphics, SectPr);

    if (docpostype_HdrFtr === this.CurPos.Type)
    {
        pGraphics.put_GlobalAlpha(false, 1.0);

        // Рисуем колонтитулы
        var SectIndex = this.SectionsInfo.Get_Index(Page_StartPos);
        var SectCount = this.SectionsInfo.Get_Count();

        var SectIndex = ( 1 === SectCount ? -1 : SectIndex );

        var Header = this.HdrFtr.Pages[nPageIndex].Header;
        var Footer = this.HdrFtr.Pages[nPageIndex].Footer;

        var RepH = ( null === Header || null !== SectPr.Get_HdrFtrInfo(Header) ? false : true );
        var RepF = ( null === Footer || null !== SectPr.Get_HdrFtrInfo(Footer) ? false : true );

        var HeaderInfo = undefined;
        if (null !== Header && undefined !== Header.RecalcInfo.PageNumInfo[nPageIndex])
        {
            var bFirst = Header.RecalcInfo.PageNumInfo[nPageIndex].bFirst;
            var bEven  = Header.RecalcInfo.PageNumInfo[nPageIndex].bEven;

            var HeaderSectPr = Header.RecalcInfo.SectPr[nPageIndex];

            if (undefined !== HeaderSectPr)
                bFirst = ( true === bFirst && true === HeaderSectPr.Get_TitlePage() ? true : false );

            HeaderInfo = {bFirst : bFirst, bEven : bEven};
        }

        var FooterInfo = undefined;
        if (null !== Footer && undefined !== Footer.RecalcInfo.PageNumInfo[nPageIndex])
        {
            var bFirst = Footer.RecalcInfo.PageNumInfo[nPageIndex].bFirst;
            var bEven  = Footer.RecalcInfo.PageNumInfo[nPageIndex].bEven;

            var FooterSectPr = Footer.RecalcInfo.SectPr[nPageIndex];

            if (undefined !== FooterSectPr)
                bFirst = ( true === bFirst && true === FooterSectPr.Get_TitlePage() ? true : false );

            FooterInfo = {bFirst : bFirst, bEven : bEven};
        }

		var oHdrFtrLine = this.HdrFtr.Get_HdrFtrLines(nPageIndex);
        var nHeaderY = this.Pages[nPageIndex].Y;
        if (oHdrFtrLine.Top > nHeaderY)
        	nHeaderY = oHdrFtrLine.Top;

		var nFooterY = this.Pages[nPageIndex].YLimit;
		if (oHdrFtrLine.Bottom < nFooterY)
			nFooterY = oHdrFtrLine.Bottom;

        pGraphics.DrawHeaderEdit(nHeaderY, this.HdrFtr.Lock.Get_Type(), SectIndex, RepH, HeaderInfo);
        pGraphics.DrawFooterEdit(nFooterY, this.HdrFtr.Lock.Get_Type(), SectIndex, RepF, FooterInfo);
    }
};
CDocument.prototype.Draw_Borders                             = function(Graphics, SectPr)
{
    var Orient = SectPr.Get_Orientation();
    var Offset = SectPr.Get_Borders_OffsetFrom();

    var LBorder = SectPr.Get_Borders_Left();
    var TBorder = SectPr.Get_Borders_Top();
    var RBorder = SectPr.Get_Borders_Right();
    var BBorder = SectPr.Get_Borders_Bottom();

    var W = SectPr.Get_PageWidth();
    var H = SectPr.Get_PageHeight();

    // Порядок отрисовки границ всегда одинаковый вне зависимости от цветы и толщины: сначала вертикальные,
    // потом горизонтальные поверх вертикальных

    if (section_borders_OffsetFromPage === Offset)
    {
        // Рисуем левую границу
        if (border_None !== LBorder.Value)
        {
            var X  = LBorder.Space + LBorder.Size / 2;
            var Y0 = ( border_None !== TBorder.Value ? TBorder.Space + TBorder.Size / 2 : 0 );
            var Y1 = ( border_None !== BBorder.Value ? H - BBorder.Space - BBorder.Size / 2 : H );

            Graphics.p_color(LBorder.Color.r, LBorder.Color.g, LBorder.Color.b, 255);
            Graphics.drawVerLine(c_oAscLineDrawingRule.Center, X, Y0, Y1, LBorder.Size);
        }

        // Рисуем правую границу
        if (border_None !== RBorder.Value)
        {
            var X  = W - RBorder.Space - RBorder.Size / 2;
            var Y0 = ( border_None !== TBorder.Value ? TBorder.Space + TBorder.Size / 2 : 0 );
            var Y1 = ( border_None !== BBorder.Value ? H - BBorder.Space - BBorder.Size / 2 : H );

            Graphics.p_color(RBorder.Color.r, RBorder.Color.g, RBorder.Color.b, 255);
            Graphics.drawVerLine(c_oAscLineDrawingRule.Center, X, Y0, Y1, RBorder.Size);
        }

        // Рисуем верхнюю границу
        if (border_None !== TBorder.Value)
        {
            var Y  = TBorder.Space;
            var X0 = ( border_None !== LBorder.Value ? LBorder.Space + LBorder.Size / 2 : 0 );
            var X1 = ( border_None !== RBorder.Value ? W - RBorder.Space - RBorder.Size / 2 : W );

            Graphics.p_color(TBorder.Color.r, TBorder.Color.g, TBorder.Color.b, 255);
            Graphics.drawHorLineExt(c_oAscLineDrawingRule.Top, Y, X0, X1, TBorder.Size, ( border_None !== LBorder.Value ? -LBorder.Size / 2 : 0 ), ( border_None !== RBorder.Value ? RBorder.Size / 2 : 0 ));
        }

        // Рисуем нижнюю границу
        if (border_None !== BBorder.Value)
        {
            var Y  = H - BBorder.Space;
            var X0 = ( border_None !== LBorder.Value ? LBorder.Space + LBorder.Size / 2 : 0 );
            var X1 = ( border_None !== RBorder.Value ? W - RBorder.Space - RBorder.Size / 2 : W );

            Graphics.p_color(BBorder.Color.r, BBorder.Color.g, BBorder.Color.b, 255);
            Graphics.drawHorLineExt(c_oAscLineDrawingRule.Bottom, Y, X0, X1, BBorder.Size, ( border_None !== LBorder.Value ? -LBorder.Size / 2 : 0 ), ( border_None !== RBorder.Value ? RBorder.Size / 2 : 0 ));
        }
    }
    else
    {
        var _X0 = SectPr.Get_PageMargin_Left();
        var _X1 = W - SectPr.Get_PageMargin_Right();
        var _Y0 = SectPr.Get_PageMargin_Top();
        var _Y1 = H - SectPr.Get_PageMargin_Bottom();

        // Рисуем левую границу
        if (border_None !== LBorder.Value)
        {
            var X  = _X0 - LBorder.Space;
            var Y0 = ( border_None !== TBorder.Value ? _Y0 - TBorder.Space - TBorder.Size / 2 : _Y0 );
            var Y1 = ( border_None !== BBorder.Value ? _Y1 + BBorder.Space + BBorder.Size / 2 : _Y1 );

            Graphics.p_color(LBorder.Color.r, LBorder.Color.g, LBorder.Color.b, 255);
            Graphics.drawVerLine(c_oAscLineDrawingRule.Right, X, Y0, Y1, LBorder.Size);
        }

        // Рисуем правую границу
        if (border_None !== RBorder.Value)
        {
            var X  = _X1 + RBorder.Space;
            var Y0 = ( border_None !== TBorder.Value ? _Y0 - TBorder.Space - TBorder.Size / 2 : _Y0 );
            var Y1 = ( border_None !== BBorder.Value ? _Y1 + BBorder.Space + BBorder.Size / 2 : _Y1 );

            Graphics.p_color(RBorder.Color.r, RBorder.Color.g, RBorder.Color.b, 255);
            Graphics.drawVerLine(c_oAscLineDrawingRule.Left, X, Y0, Y1, RBorder.Size);
        }

        // Рисуем верхнюю границу
        if (border_None !== TBorder.Value)
        {
            var Y  = _Y0 - TBorder.Space;
            var X0 = ( border_None !== LBorder.Value ? _X0 - LBorder.Space : _X0 );
            var X1 = ( border_None !== RBorder.Value ? _X1 + RBorder.Space : _X1 );

            Graphics.p_color(TBorder.Color.r, TBorder.Color.g, TBorder.Color.b, 255);
            Graphics.drawHorLineExt(c_oAscLineDrawingRule.Bottom, Y, X0, X1, TBorder.Size, ( border_None !== LBorder.Value ? -LBorder.Size : 0 ), ( border_None !== RBorder.Value ? RBorder.Size : 0 ));
        }

        // Рисуем нижнюю границу
        if (border_None !== BBorder.Value)
        {
            var Y  = _Y1 + BBorder.Space;
            var X0 = ( border_None !== LBorder.Value ? _X0 - LBorder.Space : _X0 );
            var X1 = ( border_None !== RBorder.Value ? _X1 + RBorder.Space : _X1 );

            Graphics.p_color(BBorder.Color.r, BBorder.Color.g, BBorder.Color.b, 255);
            Graphics.drawHorLineExt(c_oAscLineDrawingRule.Top, Y, X0, X1, BBorder.Size, ( border_None !== LBorder.Value ? -LBorder.Size : 0 ), ( border_None !== RBorder.Value ? RBorder.Size : 0 ));
        }
    }

    // TODO: Реализовать:
    //       1. ArtBorders
    //       2. Различные типы обычных границ. Причем, если пересакающиеся границы имеют одинаковый тип и размер,
    //          тогда надо специально отрисовывать места соединения данных линий.

};
/**
 *
 * @param bRecalculate
 * @param bForceAdd - добавляем параграф, пропуская всякие проверки типа пустого параграфа с нумерацией.
 */
CDocument.prototype.AddNewParagraph = function(bRecalculate, bForceAdd)
{
	this.Controller.AddNewParagraph(bRecalculate, bForceAdd);

	if (false !== bRecalculate)
		this.Recalculate();

	this.private_UpdateCursorXY(true, true);
};
/**
 * Расширяем документ до точки (X,Y) с помощью новых параграфов.
 * Y0 - низ последнего параграфа, YLimit - предел страницы.
 * @param X
 * @param Y
 */
CDocument.prototype.Extend_ToPos = function(X, Y)
{
    var LastPara  = this.Content[this.Content.length - 1];
    var LastPara2 = LastPara;

    this.Create_NewHistoryPoint(AscDFH.historydescription_Document_DocumentExtendToPos);
    this.History.Set_Additional_ExtendDocumentToPos();

    while (true)
    {
        var NewParagraph = new Paragraph(this.DrawingDocument, this);
        var NewRun       = new ParaRun(NewParagraph, false);
        NewParagraph.Add_ToContent(0, NewRun);

        var StyleId = LastPara.Style_Get();
        var NextId  = undefined;

        if (undefined != StyleId)
        {
            NextId = this.Styles.Get_Next(StyleId);

            if (null === NextId || undefined === NextId)
                NextId = StyleId;
        }

        // Простое добавление стиля, без дополнительных действий
        if (NextId === this.Styles.Get_Default_Paragraph() || NextId === this.Styles.Get_Default_ParaList())
            NewParagraph.Style_Remove();
        else
            NewParagraph.Style_Add(NextId, true);

        if (undefined != LastPara.TextPr.Value.FontSize || undefined !== LastPara.TextPr.Value.RFonts.Ascii)
        {
            var TextPr        = new CTextPr();
            TextPr.FontSize   = LastPara.TextPr.Value.FontSize;
            TextPr.FontSizeCS = LastPara.TextPr.Value.FontSize;
            TextPr.RFonts     = LastPara.TextPr.Value.RFonts.Copy();
            NewParagraph.SelectAll();
            NewParagraph.Apply_TextPr(TextPr);
        }

        LastPara.Set_DocumentNext(NewParagraph);

        NewParagraph.Set_DocumentPrev(LastPara);
        NewParagraph.Set_DocumentIndex(LastPara.Index + 1);

        var CurPage = LastPara.Pages.length - 1;
        var X0      = LastPara.Pages[CurPage].X;
        var Y0      = LastPara.Pages[CurPage].Bounds.Bottom;
        var XLimit  = LastPara.Pages[CurPage].XLimit;
        var YLimit  = LastPara.Pages[CurPage].YLimit;
        var PageNum = LastPara.PageNum;

        NewParagraph.Reset(X0, Y0, XLimit, YLimit, PageNum);
        var RecalcResult = NewParagraph.Recalculate_Page(0);

        if (recalcresult_NextElement != RecalcResult)
        {
            LastPara.Next = null;
            break;
        }

        this.Internal_Content_Add(this.Content.length, NewParagraph);

        if (NewParagraph.Pages[0].Bounds.Bottom > Y)
            break;

        LastPara = NewParagraph;
    }

    LastPara = this.Content[this.Content.length - 1];

    if (LastPara != LastPara2 || false === this.Document_Is_SelectionLocked(changestype_None, {
            Type      : changestype_2_Element_and_Type,
            Element   : LastPara,
            CheckType : changestype_Paragraph_Content
        }))
    {
        // Теперь нам нужно вставить таб по X
        LastPara.Extend_ToPos(X);
    }

    LastPara.MoveCursorToEndPos();
    LastPara.Document_SetThisElementCurrent(true);

    this.Recalculate();
};
CDocument.prototype.GroupGraphicObjects = function()
{
	if (this.CanGroup())
	{
		this.DrawingObjects.groupSelectedObjects();
	}
};
CDocument.prototype.UnGroupGraphicObjects = function()
{
	if (this.CanUnGroup())
	{
		this.DrawingObjects.unGroupSelectedObjects();
	}
};
CDocument.prototype.StartChangeWrapPolygon = function()
{
	this.DrawingObjects.startChangeWrapPolygon();
};
CDocument.prototype.CanChangeWrapPolygon = function()
{
	return this.DrawingObjects.canChangeWrapPolygon();
};
CDocument.prototype.CanGroup = function()
{
	return this.DrawingObjects.canGroup();
};
CDocument.prototype.CanUnGroup = function()
{
	return this.DrawingObjects.canUnGroup();
};
CDocument.prototype.AddInlineImage = function(W, H, Img, Chart, bFlow)
{
	if (undefined === bFlow)
		bFlow = false;


    this.TurnOff_InterfaceEvents();
    this.Controller.AddInlineImage(W, H, Img, Chart, bFlow);
    this.TurnOn_InterfaceEvents(true);
};

CDocument.prototype.AddImages = function(aImages){
    this.Controller.AddImages(aImages);
};

CDocument.prototype.AddOleObject  = function(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId)
{
	this.Controller.AddOleObject(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId);
};
CDocument.prototype.EditOleObject = function(oOleObject, sData, sImageUrl, nPixWidth, nPixHeight)
{
	oOleObject.setData(sData);
	var _blipFill           = new AscFormat.CBlipFill();
	_blipFill.RasterImageId = sImageUrl;
	oOleObject.setBlipFill(_blipFill);
	oOleObject.setPixSizes(nPixWidth, nPixHeight);
};
CDocument.prototype.AddTextArt = function(nStyle)
{
	this.Controller.AddTextArt(nStyle);
};

CDocument.prototype.AddSignatureLine = function(oSignatureDrawing){
    this.Controller.AddSignatureLine(oSignatureDrawing);
};

CDocument.prototype.EditChart = function(Chart)
{
	this.Controller.EditChart(Chart);
};
CDocument.prototype.GetChartObject = function(type)
{
    var W = null, H = null;
    if(type != null)
    {
        var oTargetContent = this.DrawingObjects.getTargetDocContent();
        if(oTargetContent && !oTargetContent.bPresentation)
        {
            W = oTargetContent.XLimit;
            H = W;
        }
        else
        {
            var oColumnSize = this.GetColumnSize();
            if(oColumnSize)
            {
                W = oColumnSize.W;
                H = oColumnSize.H;
            }
        }
    }
    return this.DrawingObjects.getChartObject(type, W, H);

};
CDocument.prototype.AddInlineTable = function(Cols, Rows)
{
	if (Cols <= 0 || Rows <= 0)
		return;

	this.Controller.AddInlineTable(Cols, Rows);

	this.Recalculate();

	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
	this.Document_UpdateRulersState();
};
CDocument.prototype.AddDropCap = function(bInText)
{
	// Определим параграф, к которому мы будем добавлять буквицу
	var Pos = -1;

	if (false === this.Selection.Use && type_Paragraph === this.Content[this.CurPos.ContentPos].GetType())
		Pos = this.CurPos.ContentPos;
	else if (true === this.Selection.Use && this.Selection.StartPos <= this.Selection.EndPos && type_Paragraph === this.Content[this.Selection.StartPos].GetType())
		Pos = this.Selection.StartPos;
	else if (true === this.Selection.Use && this.Selection.StartPos > this.Selection.EndPos && type_Paragraph === this.Content[this.Selection.EndPos].GetType())
		Pos = this.Selection.EndPos;

	if (-1 === Pos)
		return;

	var OldParagraph = this.Content[Pos];

	if (OldParagraph.Lines.length <= 0)
		return;

	if (false === this.Document_Is_SelectionLocked(changestype_None, {
			Type      : changestype_2_Element_and_Type,
			Element   : OldParagraph,
			CheckType : changestype_Paragraph_Content
		}))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddDropCap);

		var NewParagraph = new Paragraph(this.DrawingDocument, this);

		var TextPr = OldParagraph.Split_DropCap(NewParagraph);
		var Before = OldParagraph.Get_CompiledPr().ParaPr.Spacing.Before;
		var LineH  = OldParagraph.Lines[0].Bottom - OldParagraph.Lines[0].Top - Before;
		var LineTA = OldParagraph.Lines[0].Metrics.TextAscent2;
		var LineTD = OldParagraph.Lines[0].Metrics.TextDescent + OldParagraph.Lines[0].Metrics.LineGap;

		var FramePr = new CFramePr();
		FramePr.Init_Default_DropCap(bInText);
		NewParagraph.Set_FrameParaPr(OldParagraph);
		NewParagraph.Set_FramePr2(FramePr);
		NewParagraph.Update_DropCapByLines(TextPr, NewParagraph.Pr.FramePr.Lines, LineH, LineTA, LineTD, Before);

		this.Internal_Content_Add(Pos, NewParagraph);
		NewParagraph.MoveCursorToEndPos();

		this.RemoveSelection();
		this.CurPos.ContentPos = Pos;
		this.Set_DocPosType(docpostype_Content);

		this.Recalculate();
		this.Document_UpdateInterfaceState();
		this.Document_UpdateRulersState();
	}
};
CDocument.prototype.RemoveDropCap = function(bDropCap)
{
	var Pos = -1;

	if (false === this.Selection.Use && type_Paragraph === this.Content[this.CurPos.ContentPos].GetType())
		Pos = this.CurPos.ContentPos;
	else if (true === this.Selection.Use && this.Selection.StartPos <= this.Selection.EndPos && type_Paragraph === this.Content[this.Selection.StartPos].GetType())
		Pos = this.Selection.StartPos;
	else if (true === this.Selection.Use && this.Selection.StartPos > this.Selection.EndPos && type_Paragraph === this.Content[this.Selection.EndPos].GetType())
		Pos = this.Selection.EndPos;

	if (-1 === Pos)
		return;

	var Para    = this.Content[Pos];
	var FramePr = Para.Get_FramePr();

	// Возможно буквицой является предыдущий параграф
	if (undefined === FramePr && true === bDropCap)
	{
		var Prev = Para.Get_DocumentPrev();
		if (null != Prev && type_Paragraph === Prev.GetType())
		{
			var PrevFramePr = Prev.Get_FramePr();
			if (undefined != PrevFramePr && undefined != PrevFramePr.DropCap)
			{
				Para    = Prev;
				FramePr = PrevFramePr;
			}
			else
				return;
		}
		else
			return;
	}

	if (undefined === FramePr)
		return;

	var FrameParas = Para.Internal_Get_FrameParagraphs();

	if (false === bDropCap)
	{
		if (false === this.Document_Is_SelectionLocked(changestype_None, {
				Type      : changestype_2_ElementsArray_and_Type,
				Elements  : FrameParas,
				CheckType : changestype_Paragraph_Content
			}))
		{
			this.Create_NewHistoryPoint(AscDFH.historydescription_Document_RemoveDropCap);
			var Count = FrameParas.length;
			for (var Index = 0; Index < Count; Index++)
			{
				FrameParas[Index].Set_FramePr(undefined, true);
			}

			this.Recalculate();
			this.Document_UpdateInterfaceState();
			this.Document_UpdateRulersState();
		}
	}
	else
	{
		// Сначала найдем параграф, к которому относится буквица
		var Next = Para.Get_DocumentNext();
		var Last = Para;
		while (null != Next)
		{
			if (type_Paragraph != Next.GetType() || undefined === Next.Get_FramePr() || true != FramePr.Compare(Next.Get_FramePr()))
				break;

			Last = Next;
			Next = Next.Get_DocumentNext();
		}

		if (null != Next && type_Paragraph === Next.GetType())
		{
			FrameParas.push(Next);
			if (false === this.Document_Is_SelectionLocked(changestype_None, {
					Type      : changestype_2_ElementsArray_and_Type,
					Elements  : FrameParas,
					CheckType : changestype_Paragraph_Content
				}))
			{
				this.Create_NewHistoryPoint(AscDFH.historydescription_Document_RemoveDropCap);

				// Удалим ненужный элемент
				FrameParas.splice(FrameParas.length - 1, 1);

				// Передвинем курсор в начало следующего параграфа, и рассчитаем текстовые настройки и расстояния между строк
				Next.MoveCursorToStartPos();
				var Spacing = Next.Get_CompiledPr2(false).ParaPr.Spacing.Copy();
				var TextPr  = Next.Get_FirstRunPr();

				var Count = FrameParas.length;
				for (var Index = 0; Index < Count; Index++)
				{
					var FramePara = FrameParas[Index];
					FramePara.Set_FramePr(undefined, true);
					FramePara.Set_Spacing(Spacing, true);
					FramePara.SelectAll();
					FramePara.Clear_TextFormatting();
					FramePara.Apply_TextPr(TextPr, undefined);
				}


				Next.CopyPr(Last);
				Last.Concat(Next);

				this.Internal_Content_Remove(Next.Index, 1);

				Last.MoveCursorToStartPos();
				Last.Document_SetThisElementCurrent(true);

				this.Recalculate();
				this.Document_UpdateInterfaceState();
				this.Document_UpdateRulersState();
			}
		}
		else
		{
			if (false === this.Document_Is_SelectionLocked(changestype_None, {
					Type      : changestype_2_ElementsArray_and_Type,
					Elements  : FrameParas,
					CheckType : changestype_Paragraph_Content
				}))
			{
				this.Create_NewHistoryPoint(AscDFH.historydescription_Document_RemoveDropCap);
				var Count = FrameParas.length;
				for (var Index = 0; Index < Count; Index++)
				{
					FrameParas[Index].Set_FramePr(undefined, true);
				}

				this.Recalculate();
				this.Document_UpdateInterfaceState();
				this.Document_UpdateRulersState();
			}
		}
	}
};
CDocument.prototype.private_CheckFramePrLastParagraph = function()
{
    var Count = this.Content.length;
    if (Count <= 0)
        return;

    var Element = this.Content[Count - 1];
    if (type_Paragraph === Element.GetType() && undefined !== Element.Get_FramePr())
    {
        Element.Set_FramePr(undefined, true);
    }
};
CDocument.prototype.CheckRange = function(X0, Y0, X1, Y1, _Y0, _Y1, X_lf, X_rf, PageNum, Inner, bMathWrap)
{
	var HdrFtrRanges = this.HdrFtr.CheckRange(X0, Y0, X1, Y1, _Y0, _Y1, X_lf, X_rf, PageNum, bMathWrap);
	return this.DrawingObjects.CheckRange(X0, Y0, X1, Y1, _Y0, _Y1, X_lf, X_rf, PageNum, HdrFtrRanges, null, bMathWrap);
};
CDocument.prototype.AddToParagraph = function(ParaItem, bRecalculate)
{
	this.Controller.AddToParagraph(ParaItem, bRecalculate);
};
/**
 * Очищаем форматирование внутри селекта
 * {boolean} [isClearParaPr=true] Очищать ли настройки параграфа
 * {boolean} [isClearTextPr=true] Очищать ли настройки текста
 */
CDocument.prototype.ClearParagraphFormatting = function(isClearParaPr, isClearTextPr)
{
	if (false !== isClearParaPr)
		isClearParaPr = true;

	if (false !== isClearTextPr)
		isClearTextPr = true;

	this.Controller.ClearParagraphFormatting(isClearParaPr, isClearTextPr);

	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.Remove = function(nDirection, bOnlyText, bRemoveOnlySelection, bOnTextAdd)
{
	if (undefined === bRemoveOnlySelection)
		bRemoveOnlySelection = false;

	if (undefined === bOnTextAdd)
		bOnTextAdd = false;

	this.Controller.Remove(nDirection, bOnlyText, bRemoveOnlySelection, bOnTextAdd);

	this.Recalculate();

	this.Document_UpdateInterfaceState();
	this.Document_UpdateRulersState();
	this.Document_UpdateTracks();
};
CDocument.prototype.RemoveBeforePaste = function()
{
	if (docpostype_DrawingObjects === this.Get_DocPosType() && null === this.DrawingObjects.getTargetDocContent())
		this.RemoveSelection();
	else
		this.Remove(1, true, true, true);
};
CDocument.prototype.GetCursorPosXY = function()
{
	return this.Controller.GetCursorPosXY();
};
/**
 * Получаем точное физическое положение курсора
 * @returns {{X: number, Y: number}}
 */
CDocument.prototype.GetCursorRealPosition = function()
{
	return {
		X : this.CurPos.RealX,
		Y : this.CurPos.RealY
	};
};
CDocument.prototype.MoveCursorToStartPos = function(AddToSelect)
{
	this.Reset_WordSelection();
	this.private_UpdateTargetForCollaboration();

	this.Controller.MoveCursorToStartPos(AddToSelect);

	this.private_UpdateCursorXY(true, true);
};
CDocument.prototype.MoveCursorToEndPos = function(AddToSelect)
{
	this.Reset_WordSelection();
	this.private_UpdateTargetForCollaboration();

	this.Controller.MoveCursorToEndPos(AddToSelect);

	this.private_UpdateCursorXY(true, true);
};
CDocument.prototype.MoveCursorLeft = function(AddToSelect, Word)
{
	this.Reset_WordSelection();
	this.private_UpdateTargetForCollaboration();

	if (undefined === Word || null === Word)
		Word = false;

	this.Controller.MoveCursorLeft(AddToSelect, Word);

	this.Document_UpdateInterfaceState();
	this.Document_UpdateRulersState();
	this.private_UpdateCursorXY(true, true);
};
CDocument.prototype.MoveCursorRight = function(AddToSelect, Word, FromPaste)
{
	this.Reset_WordSelection();
	this.private_UpdateTargetForCollaboration();

	if (undefined === Word || null === Word)
		Word = false;

	this.Controller.MoveCursorRight(AddToSelect, Word, FromPaste);

	this.Document_UpdateInterfaceState();
	this.Document_UpdateSelectionState();
	this.private_UpdateCursorXY(true, true);
};
CDocument.prototype.MoveCursorUp = function(AddToSelect, CtrlKey)
{
	this.Reset_WordSelection();
	this.private_UpdateTargetForCollaboration();

	if (true === this.IsFillingFormMode())
		this.MoveToFillingForm(false);
	else
		this.Controller.MoveCursorUp(AddToSelect, CtrlKey);
};
CDocument.prototype.MoveCursorDown = function(AddToSelect, CtrlKey)
{
	this.Reset_WordSelection();
	this.private_UpdateTargetForCollaboration();

	if (true === this.IsFillingFormMode())
		this.MoveToFillingForm(true);
	else
		this.Controller.MoveCursorDown(AddToSelect, CtrlKey);
};
CDocument.prototype.MoveCursorToEndOfLine = function(AddToSelect)
{
	this.Reset_WordSelection();
	this.private_UpdateTargetForCollaboration();

	this.Controller.MoveCursorToEndOfLine(AddToSelect);

	this.Document_UpdateInterfaceState();
	this.private_UpdateCursorXY(true, true);
};
CDocument.prototype.MoveCursorToStartOfLine = function(AddToSelect)
{
	this.Reset_WordSelection();
	this.private_UpdateTargetForCollaboration();

	this.Controller.MoveCursorToStartOfLine(AddToSelect);

	this.Document_UpdateInterfaceState();
	this.private_UpdateCursorXY(true, true);
};
CDocument.prototype.MoveCursorToXY = function(X, Y, AddToSelect)
{
	this.Reset_WordSelection();
	this.private_UpdateTargetForCollaboration();
	this.Controller.MoveCursorToXY(X, Y, this.CurPage, AddToSelect);
};
CDocument.prototype.MoveCursorToCell = function(bNext)
{
	this.Reset_WordSelection();
	this.private_UpdateTargetForCollaboration();
	this.Controller.MoveCursorToCell(bNext);
};
CDocument.prototype.MoveCursorToSignature = function(sGuid)
{
    this.DrawingObjects.moveCursorToSignature(sGuid);
};
CDocument.prototype.SetParagraphAlign = function(Align)
{
	var SelectedInfo = this.GetSelectedElementsInfo();
	var Math         = SelectedInfo.Get_Math();
	if (null !== Math && true !== Math.Is_Inline())
	{
		Math.Set_Align(Align);
	}
	else
	{
		this.Controller.SetParagraphAlign(Align);
	}

	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.SetParagraphSpacing = function(Spacing)
{
	this.Controller.SetParagraphSpacing(Spacing);
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.SetParagraphTabs = function(Tabs)
{
	this.Controller.SetParagraphTabs(Tabs);
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
	this.Api.Update_ParaTab(AscCommonWord.Default_Tab_Stop, Tabs);
};
CDocument.prototype.SetParagraphIndent = function(Ind)
{
	this.Controller.SetParagraphIndent(Ind);
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.SetParagraphNumbering = function(NumInfo)
{
	if (this.private_SetParagraphNumbering(NumInfo))
	{
		this.Recalculate();
		this.Document_UpdateSelectionState();
		this.Document_UpdateInterfaceState();
	}
};
CDocument.prototype.private_SetParagraphNumbering = function(oNumInfo)
{
	var oNumPr = this.GetSelectedNum();

	var arrSelectedParagraphs;

	if (oNumPr)
		arrSelectedParagraphs = this.GetAllParagraphsByNumbering(oNumPr);
	else
		arrSelectedParagraphs = this.GetSelectedParagraphs();

	if (arrSelectedParagraphs.length <= 0)
		return false;

	if (oNumInfo.SubType < 0)
	{
		this.private_RemoveParagraphNumbering(arrSelectedParagraphs, oNumPr);
	}
	else
	{
		if (0 === oNumInfo.Type) // Bullet
		{
			if (0 === oNumInfo.SubType)
				this.private_SetParagraphNumberingSimpleBullet(arrSelectedParagraphs, oNumPr);
			else
				this.private_SetParagraphNumberingCustomBullet(arrSelectedParagraphs, oNumPr, oNumInfo.SubType)
		}
		else if (1 === oNumInfo.Type) // Numbered
		{
			if (0 === oNumInfo.SubType)
				this.private_SetParagraphNumberingSimpleNumbered(arrSelectedParagraphs, oNumPr);
			else
				this.private_SetParagraphNumberingCustomNumbered(arrSelectedParagraphs, oNumPr, oNumInfo.SubType);
		}
		else if (2 === oNumInfo.Type) // Multilevel
		{
			this.private_SetParagraphNumberingMultiLevel(arrSelectedParagraphs, oNumPr, oNumInfo.SubType);
		}
	}

	return true;
};
CDocument.prototype.private_RemoveParagraphNumbering = function(arrParagraphs, oNumPr)
{
	if (this.GetSelectedNum())
		this.RemoveSelection();

	for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
	{
		var oPara = arrParagraphs[nIndex];
		oPara.RemoveNumPr();
	}
};
CDocument.prototype.private_SetParagraphNumberingSimpleBullet = function(arrParagraphs, oNumPr)
{
	if (arrParagraphs.length <= 0)
		return;

	// 1. Пытаемся присоединить список к списку предыдущего параграфа (если только он маркированный)
	// 2. Пытаемся присоединить список к списку следующего параграфа (если он маркированный)
	// 3. Пытаемся добавить список, который добавлялся предыдущий раз
	// 4. Создаем новый маркированный список

	var sNumId  = null;
	var nNumLvl = 0;

	var oPrevPara = arrParagraphs[0].GetPrevParagraph();
	if (oPrevPara && oPrevPara.GetNumPr())
	{
		var oPrevNumPr = oPrevPara.GetNumPr();
		if (oPrevNumPr && this.Numbering.CheckFormat(oPrevNumPr.NumId, oPrevNumPr.Lvl, Asc.c_oAscNumberingFormat.Bullet))
		{
			sNumId  = oPrevNumPr.NumId;
			nNumLvl = oPrevNumPr.Lvl;
		}
	}

	if (!sNumId)
	{
		var oNextPara = arrParagraphs[arrParagraphs.length - 1].GetNextParagraph();
		if (oNextPara && oNextPara.GetNumPr())
		{
			var oNextNumPr = oNextPara.GetNumPr();
			if (oNextNumPr && this.Numbering.CheckFormat(oNextNumPr.NumId, oNextNumPr.Lvl, Asc.c_oAscNumberingFormat.Bullet))
			{
				sNumId  = oNextNumPr.NumId;
				nNumLvl = oNextNumPr.Lvl;
			}
		}
	}

	if (oNumPr && this.Numbering.GetNum(oNumPr.NumId))
	{
		var oNum = this.Numbering.GetNum(oNumPr.NumId);
		var oLvl;

		var oLastNumPr = this.GetLastBulletList();
		if (oLastNumPr && this.Numbering.GetNum(oLastNumPr.NumId) && this.Numbering.GetNum(oLastNumPr.NumId).GetLvl(oLastNumPr.Lvl).IsBulleted())
		{
			var oLastNum = this.Numbering.GetNum(oLastNumPr.NumId);
			oLvl         = oLastNum.GetLvl(oLastNumPr.Lvl).Copy();
		}
		else
		{
			oLvl = oNum.GetLvl(oNumPr.Lvl).Copy();

			var oTextPr = new CTextPr();
			oTextPr.RFonts.SetAll("Symbol");
			oLvl.SetByType(c_oAscNumberingLevel.Bullet, oNumPr.Lvl, String.fromCharCode(0x00B7), oTextPr);
		}

		oLvl.ParaPr = oNum.GetLvl(oNumPr.Lvl).ParaPr.Copy();

		oNum.SetLvl(oLvl, oNumPr.Lvl);
		this.SetLastBulletList(oNumPr.NumId, oNumPr.Lvl);
		return;
	}

	var isCheckPrev = false;
	if (!sNumId)
	{
		var oLastNumPr = this.GetLastBulletList();
		if (oLastNumPr && this.Numbering.GetNum(oLastNumPr.NumId) && this.Numbering.GetNum(oLastNumPr.NumId).GetLvl(0).IsBulleted())
		{
			var oPrevNum = this.Numbering.GetNum(oLastNumPr.NumId);

			var oNum = this.Numbering.CreateNum();
			oNum.CreateDefault(c_oAscMultiLevelNumbering.Bullet);
			oNum.SetLvl(oPrevNum.GetLvl(oLastNumPr.Lvl).Copy(), 0);

			sNumId  = oNum.GetId();
			nNumLvl = 0;

			isCheckPrev = true;
		}
	}


	if (!sNumId)
	{
		var oNum = this.Numbering.CreateNum();
		oNum.CreateDefault(c_oAscMultiLevelNumbering.Bullet);

		sNumId  = oNum.GetId();
		nNumLvl = 0;

		isCheckPrev = true;
	}

	if (isCheckPrev)
	{
		var oResult = this.private_CheckPrevNumberingOnAdd(arrParagraphs, sNumId, nNumLvl);
		if (oResult)
		{
			sNumId  = oResult.NumId;
			nNumLvl = oResult.Lvl;
		}
	}

	this.SetLastBulletList(sNumId, nNumLvl);

	// Если у параграфа уже была нумерация, тогда мы сохраняем её уровень, если нет - добавляем с новым значением nNumLvl
	for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
	{
		var oOldNumPr = arrParagraphs[nIndex].GetNumPr();

		if (oOldNumPr)
			arrParagraphs[nIndex].ApplyNumPr(sNumId, oOldNumPr.Lvl);
		else
			arrParagraphs[nIndex].ApplyNumPr(sNumId, nNumLvl);
	}
};
CDocument.prototype.private_SetParagraphNumberingCustomBullet = function(arrParagraphs, oNumPr, nType)
{
	if (arrParagraphs.length <= 0)
		return;

	// Для начала пробежимся и узнаем, есть ли у нас парграфы с разными списками и разными уровнями
	var bDiffLvl = false;
	var bDiffId  = false;
	var nPrevLvl = null;
	var sPrevId  = null;
	for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
	{
		var oTempNumPr = arrParagraphs[nIndex].GetNumPr();
		if (oTempNumPr)
		{
			if (null === nPrevLvl)
				nPrevLvl = oTempNumPr.Lvl;

			if (null === sPrevId)
				sPrevId = oTempNumPr.NumId;

			if (sPrevId !== oTempNumPr.NumId)
				bDiffId = true;

			if (nPrevLvl !== oTempNumPr.Lvl)
			{
				bDiffLvl = true;
				break;
			}
		}
		else
		{
			bDiffLvl = true;
			break;
		}
	}


	// 1. Если у нас есть параграфы со списками разных уровней, тогда мы
	//    делаем стандартный маркированный список, у которого первый(нулевой)
	//    уровень изменен на тот который задан через NumInfo.SubType
	// 2. Если все параграфы содержат списки одного уровня.
	//    2.1 Если у всех списков одинаковый Id, тогда мы создаем
	//        копию текущего списка и меняем в нем текущий уровень
	//        на тот, который задан через NumInfo.SubType
	//    2.2 Если у списков разные Id, тогда мы создаем стандартный
	//        маркированный список с измененным уровнем (равным текущему),
	//        на тот, который прописан в NumInfo.Subtype

	var sLvlText   = "";
	var oLvlTextPr = new CTextPr();
	oLvlTextPr.RFonts.SetAll("Times New Roman");
	switch (nType)
	{
		case 1:
		{
			sLvlText = String.fromCharCode(0x00B7);
			oLvlTextPr.RFonts.SetAll("Symbol");
			break;
		}
		case 2:
		{
			sLvlText = "o";
			oLvlTextPr.RFonts.SetAll("Courier New");
			break;
		}
		case 3:
		{
			sLvlText = String.fromCharCode(0x00A7);
			oLvlTextPr.RFonts.SetAll("Wingdings");
			break;
		}
		case 4:
		{
			sLvlText = String.fromCharCode(0x0076);
			oLvlTextPr.RFonts.SetAll("Wingdings");
			break;
		}
		case 5:
		{
			sLvlText = String.fromCharCode(0x00D8);
			oLvlTextPr.RFonts.SetAll("Wingdings");
			break;
		}
		case 6:
		{
			sLvlText = String.fromCharCode(0x00FC);
			oLvlTextPr.RFonts.SetAll("Wingdings");
			break;
		}
		case 7:
		{
			sLvlText = String.fromCharCode(0x00A8);
			oLvlTextPr.RFonts.SetAll("Symbol");
			break;
		}
		case 8:
		{
			sLvlText = String.fromCharCode(0x2013);
			oLvlTextPr.RFonts.SetAll("Arial");
			break;
		}
	}

	var isCheckPrev = false;

	var sNumId = null;
	if (oNumPr)
	{
		nPrevLvl = oNumPr.Lvl;

		oNum = this.Numbering.GetNum(oNumPr.NumId);
		if (oNum)
		{
			oNum.SetLvlByType(oNumPr.Lvl, c_oAscNumberingLevel.Bullet, sLvlText, oLvlTextPr);
		}

		this.SetLastBulletList(sPrevId, nPrevLvl);
	}
	else if (true === bDiffLvl)
	{
		nPrevLvl = 0;

		var oNum = this.Numbering.CreateNum();
		oNum.CreateDefault(c_oAscMultiLevelNumbering.Bullet);
		oNum.SetLvlByType(0, c_oAscNumberingLevel.Bullet, sLvlText, oLvlTextPr);

		sNumId = oNum.GetId();

		isCheckPrev = true;
	}
	else if (true === bDiffId || true != this.Numbering.CheckFormat(sPrevId, nPrevLvl, Asc.c_oAscNumberingFormat.Bullet))
	{
		var oNum = this.Numbering.CreateNum();
		oNum.CreateDefault(c_oAscMultiLevelNumbering.Bullet);
		oNum.SetLvlByType(nPrevLvl, c_oAscNumberingLevel.Bullet, sLvlText, oLvlTextPr);

		sNumId = oNum.GetId();

		isCheckPrev = true;
	}
	else
	{
		var oNum = this.Numbering.GetNum(sPrevId);
		if (oNum)
		{
			oNum.SetLvlByType(nPrevLvl, c_oAscNumberingLevel.Bullet, sLvlText, oLvlTextPr);
		}

		this.SetLastBulletList(sPrevId, nPrevLvl);
	}

	if (isCheckPrev)
	{
		var oResult = this.private_CheckPrevNumberingOnAdd(arrParagraphs, sNumId, nPrevLvl);
		if (oResult)
			sNumId = oResult.NumId;
	}

	if (sNumId)
	{
		// Параграфы, которые не содержали списка у них уровень выставляем 0,
		// а у тех которые содержали, мы уровень не меняем
		for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
		{
			var oOldNumPr = arrParagraphs[nIndex].GetNumPr();
			if (oOldNumPr)
				arrParagraphs[nIndex].ApplyNumPr(sNumId, oOldNumPr.Lvl);
			else
				arrParagraphs[nIndex].ApplyNumPr(sNumId, 0);
		}

		this.SetLastBulletList(sNumId, 0);
	}
};
CDocument.prototype.private_SetParagraphNumberingSimpleNumbered = function(arrParagraphs, oNumPr)
{
	if (arrParagraphs.length <= 0)
		return;

	// 1. Пытаемся присоединить список к списку предыдущего параграфа (если он нумерованный)
	// 2. Пытаемся присоединить список к списку следующего параграфа (если он нумерованный)
	// 3. Пытаемся добавить список, который добавлялся предыдущий раз (добавляем его копию, и опционально продолжаем)
	// 4. Создаем новый нумерованный список

	var sNumId  = null;
	var nNumLvl = 0;

	var oPrevPara = arrParagraphs[0].GetPrevParagraph();
	if (oPrevPara)
	{
		var oPrevNumPr = oPrevPara.GetNumPr();
		if (oPrevNumPr && true === this.Numbering.CheckFormat(oPrevNumPr.NumId, oPrevNumPr.Lvl, Asc.c_oAscNumberingFormat.Decimal))
		{
			sNumId  = oPrevNumPr.NumId;
			nNumLvl = oPrevNumPr.Lvl;
		}
	}

	if (!sNumId)
	{
		var oNextPara = arrParagraphs[arrParagraphs.length - 1].GetNextParagraph();
		if (oNextPara)
		{
			var oNextNumPr = oNextPara.GetNumPr();
			if (oNextNumPr && true == this.Numbering.CheckFormat(oNextNumPr.NumId, oNextNumPr.Lvl, Asc.c_oAscNumberingFormat.Decimal))
			{
				sNumId  = oNextNumPr.NumId;
				nNumLvl = oNextNumPr.Lvl;
			}
		}
	}

	if (oNumPr && this.Numbering.GetNum(oNumPr.NumId))
	{
		var oNum = this.Numbering.GetNum(oNumPr.NumId);
		var oLvl;

		var oLastNumPr = this.GetLastNumberedList();
		if (oLastNumPr && this.Numbering.GetNum(oLastNumPr.NumId) && this.Numbering.GetNum(oLastNumPr.NumId).GetLvl(oNumPr.Lvl).IsNumbered())
		{
			var oPrevNum = this.Numbering.GetNum(oLastNumPr.NumId);

			if (oPrevNum.IsHaveRelatedLvlText())
			{
				// В этом случае мы не можем подменить просто текущий уровень, меняем целиком весь список
				for (var nLvl = 0; nLvl < 9; ++nLvl)
				{
					oNum.SetLvl(oPrevNum.GetLvl(nLvl).Copy(), nLvl);
				}
			}
			else
			{
				oLvl        = oPrevNum.GetLvl(oLastNumPr.Lvl).Copy();
				oLvl.ParaPr = oNum.GetLvl(oNumPr.Lvl).ParaPr.Copy();
				oLvl.ResetNumberedText(oNumPr.Lvl);

				oNum.SetLvl(oLvl, oNumPr.Lvl);
				this.SetLastNumberedList(oNumPr.NumId, oNumPr.Lvl);
			}
		}
		else
		{
			oLvl = oNum.GetLvl(oNumPr.Lvl).Copy();
			oLvl.SetByType(c_oAscNumberingLevel.DecimalDot_Right, oNumPr.Lvl);
			oLvl.ParaPr = oNum.GetLvl(oNumPr.Lvl).ParaPr.Copy();

			oNum.SetLvl(oLvl, oNumPr.Lvl);
			this.SetLastNumberedList(oNumPr.NumId, oNumPr.Lvl);
		}

		return;
	}

	var isCheckPrev = false;

	if (!sNumId)
	{
		var oLastNumPr = this.GetLastNumberedList();
		if (oLastNumPr && this.Numbering.GetNum(oLastNumPr.NumId) && this.Numbering.GetNum(oLastNumPr.NumId).GetLvl(0).IsNumbered())
		{
			var oLastNum = this.Numbering.GetNum(oLastNumPr.NumId);

			var oNum = this.Numbering.CreateNum();

			if (oLastNum.IsHaveRelatedLvlText())
			{
				for (var nLvl = 0; nLvl < 9; ++nLvl)
				{
					oNum.SetLvl(oLastNum.GetLvl(nLvl).Copy(), nLvl);
				}
			}
			else
			{
				oNum.CreateDefault(c_oAscMultiLevelNumbering.Numbered);
				oNum.SetLvl(oLastNum.GetLvl(oLastNumPr.Lvl).Copy(), 0);
			}

			sNumId  = oNum.GetId();
			nNumLvl = 0;

			isCheckPrev = true;
		}
	}

	if (!sNumId)
	{
		var oNum = this.Numbering.CreateNum();
		oNum.CreateDefault(c_oAscMultiLevelNumbering.Numbered);

		sNumId  = oNum.GetId();
		nNumLvl = 0;

		isCheckPrev = true;
	}

	if (isCheckPrev)
	{
		var oResult = this.private_CheckPrevNumberingOnAdd(arrParagraphs, sNumId, nNumLvl);
		if (oResult)
		{
			sNumId  = oResult.NumId;
			nNumLvl = oResult.Lvl;
		}
	}

	this.SetLastNumberedList(sNumId, nNumLvl);

	// Если у параграфа уже была нумерация, тогда мы сохраняем её уровень, если нет - добавляем с новым значением nNumLvl
	for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
	{
		var oOldNumPr = arrParagraphs[nIndex].GetNumPr();
		if (oOldNumPr)
			arrParagraphs[nIndex].ApplyNumPr(sNumId, oOldNumPr.Lvl);
		else
			arrParagraphs[nIndex].ApplyNumPr(sNumId, nNumLvl);
	}
};
CDocument.prototype.private_SetParagraphNumberingCustomNumbered = function(arrParagraphs, oNumPr, nType)
{
	if (arrParagraphs.length <= 0)
		return;

	// Для начала пробежимся и узнаем, есть ли у нас парграфы с разными списками и разными уровнями
	var bDiffLvl = false;
	var bDiffId  = false;
	var nPrevLvl = null;
	var sPrevId  = null;
	for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
	{
		var oTempNumPr = arrParagraphs[nIndex].GetNumPr();
		if (oTempNumPr)
		{
			if (null === nPrevLvl)
				nPrevLvl = oTempNumPr.Lvl;

			if (null === sPrevId)
				sPrevId = oTempNumPr.NumId;

			if (sPrevId !== oTempNumPr.NumId)
				bDiffId = true;

			if (nPrevLvl !== oTempNumPr.Lvl)
			{
				bDiffLvl = true;
				break;
			}
		}
		else
		{
			bDiffLvl = true;
			break;
		}
	}

	// 1. Если у нас есть параграфы со списками разных уровней, тогда мы
	//    делаем стандартный нумерованный список, у которого первый(нулевой)
	//    уровень изменен на тот который задан через nType
	// 2. Если все параграфы содержат списки одного уровня.
	//    2.1 Если у всех списков одинаковый Id, тогда мы создаем
	//        копию текущего списка и меняем в нем текущий уровень
	//        на тот, который задан через NumInfo.SubType
	//    2.2 Если у списков разные Id, тогда мы создаем стандартный
	//        нумерованный список с измененным уровнем (равным текущему),
	//        на тот, который прописан в NumInfo.Subtype

	var oNum       = null;
	var sNumId     = null;
	var nChangeLvl = 0;

	var isCheckPrev = false;

	if (oNumPr)
	{
		oNum       = this.Numbering.GetNum(oNumPr.NumId);
		nChangeLvl = oNumPr.Lvl;
	}
	else if (true === bDiffLvl)
	{
		oNum = this.Numbering.CreateNum();
		oNum.CreateDefault(c_oAscMultiLevelNumbering.Numbered);

		sNumId     = oNum.GetId();
		nChangeLvl = 0;

		isCheckPrev = true;
	}
	else if (true === bDiffId)
	{
		oNum = this.Numbering.CreateNum();
		oNum.CreateDefault(c_oAscMultiLevelNumbering.Numbered);

		sNumId     = oNum.GetId();
		nChangeLvl = nPrevLvl;

		isCheckPrev = true;
	}
	else
	{
		oNum       = this.Numbering.GetNum(sPrevId);
		nChangeLvl = nPrevLvl;

		this.SetLastNumberedList(sPrevId, nPrevLvl);
	}

	switch (nType)
	{
		case 1:
		{
			oNum.SetLvlByType(nChangeLvl, c_oAscNumberingLevel.DecimalDot_Right);
			break;
		}
		case 2:
		{
			oNum.SetLvlByType(nChangeLvl, c_oAscNumberingLevel.DecimalBracket_Right);
			break;
		}
		case 3:
		{
			oNum.SetLvlByType(nChangeLvl, c_oAscNumberingLevel.UpperRomanDot_Right);
			break;
		}
		case 4:
		{
			oNum.SetLvlByType(nChangeLvl, c_oAscNumberingLevel.UpperLetterDot_Left);
			break;
		}
		case 5:
		{
			oNum.SetLvlByType(nChangeLvl, c_oAscNumberingLevel.LowerLetterBracket_Left);
			break;
		}
		case 6:
		{
			oNum.SetLvlByType(nChangeLvl, c_oAscNumberingLevel.LowerLetterDot_Left);
			break;
		}
		case 7:
		{
			oNum.SetLvlByType(nChangeLvl, c_oAscNumberingLevel.LowerRomanDot_Right);
			break;
		}
	}

	if (isCheckPrev)
	{
		var oResult = this.private_CheckPrevNumberingOnAdd(arrParagraphs, sNumId, nChangeLvl);
		if (oResult)
			sNumId = oResult.NumId;
	}

	if (sNumId)
	{
		// Параграфы, которые не содержали списка у них уровень выставляем 0,
		// а у тех которые содержали, мы уровень не меняем
		for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
		{
			var oOldNumPr = arrParagraphs[nIndex].GetNumPr();
			if (oOldNumPr)
				arrParagraphs[nIndex].ApplyNumPr(sNumId, oOldNumPr.Lvl);
			else
				arrParagraphs[nIndex].ApplyNumPr(sNumId, 0);
		}

		this.SetLastNumberedList(sNumId, 0);
	}
};
CDocument.prototype.private_SetParagraphNumberingMultiLevel = function(arrParagraphs, oNumPr, nType)
{
	if (arrParagraphs.length <= 0)
		return;

	var bDiffId = false;
	var sPrevId = null;
	for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
	{
		var oTempNumPr = arrParagraphs[nIndex].GetNumPr();
		if (oTempNumPr)
		{
			if (null === sPrevId)
				sPrevId = oTempNumPr.NumId;

			if (sPrevId !== oTempNumPr.NumId)
				bDiffId = true;
		}
		else
		{
			bDiffId = true;
			break;
		}
	}

	var oNum   = null;
	var sNumId = null;

	if (oNumPr)
	{
		oNum = this.Numbering.GetNum(oNumPr.NumId);
	}
	else if (bDiffId)
	{
		oNum   = this.Numbering.CreateNum();
		sNumId = oNum.GetId();
	}
	else
	{
		oNum = this.Numbering.GetNum(sPrevId);
	}

	switch (nType)
	{
		case 1:
		{
			oNum.CreateDefault(c_oAscMultiLevelNumbering.MultiLevel1);
			break;
		}
		case 2:
		{
			oNum.CreateDefault(c_oAscMultiLevelNumbering.MultiLevel2);
			break;
		}
		case 3:
		{
			oNum.CreateDefault(c_oAscMultiLevelNumbering.MultiLevel3);
			break;
		}
	}

	if (sNumId)
	{
		// Параграфы, которые не содержали списка у них уровень выставляем 0,
		// а у тех которые содержали, мы уровень не меняем
		for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
		{
			var oOldNumPr = arrParagraphs[nIndex].GetNumPr();
			if (oOldNumPr)
				arrParagraphs[nIndex].ApplyNumPr(sNumId, oOldNumPr.Lvl);
			else
				arrParagraphs[nIndex].ApplyNumPr(sNumId, 0);
		}
	}
};
CDocument.prototype.private_CheckPrevNumberingOnAdd = function(arrParagraphs, sNumId, nLvl)
{
	var sResultNumId = sNumId;
	var nResultLvl   = nLvl;

	if (arrParagraphs.length !== 1 || this.IsSelectionUse())
		return {NumId : sResultNumId, Lvl : nResultLvl};

	var oPrevPara = arrParagraphs[0].GetPrevParagraph();
	while (oPrevPara)
	{
		if (oPrevPara.GetNumPr() || !oPrevPara.IsEmpty())
			break;

		oPrevPara = oPrevPara.GetPrevParagraph();
	}

	if (oPrevPara && oPrevPara.GetNumPr())
	{
		var oPrevNumPr = oPrevPara.GetNumPr();
		var oPrevLvl   = this.Numbering.GetNum(oPrevNumPr.NumId).GetLvl(oPrevNumPr.Lvl);
		var oCurrLvl   = this.Numbering.GetNum(sNumId).GetLvl(nLvl);

		if (oPrevLvl.IsSimilar(oCurrLvl))
		{
			sResultNumId = oPrevNumPr.NumId;
			nResultLvl   = oPrevNumPr.Lvl;
		}
	}

	return {NumId : sResultNumId, Lvl : nResultLvl};
};
CDocument.prototype.SetParagraphShd = function(Shd)
{
	this.Controller.SetParagraphShd(Shd);
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
/**
 * Выставляем стиль для выделенных параграфов
 * @param {string} sName - название стиля
 * @param {boolean} [isCheckLinkedStyle=false] - если true и если выделен текст внутри одного параграфа, то мы выставляем линкованный стиль текста, если он есть
 */
CDocument.prototype.SetParagraphStyle = function(sName, isCheckLinkedStyle)
{
	if (isCheckLinkedStyle && this.IsSelectionUse())
	{
		var sStyleId = this.Styles.GetStyleIdByName(sName);
		var oStyle   = this.Styles.Get(sStyleId);

		var arrCurrentParagraphs = this.GetCurrentParagraph(false, true);
		if (1 === arrCurrentParagraphs.length && arrCurrentParagraphs[0].IsSelectedSingleElement() && true !== arrCurrentParagraphs[0].IsSelectedAll() && oStyle && oStyle.GetLink())
		{
			var oLinkedStyle = this.Styles.Get(oStyle.GetLink());
			if (oLinkedStyle && styletype_Character === oLinkedStyle.GetType())
			{
				var oTextPr = new CTextPr();
				oTextPr.Set_FromObject({RStyle : oLinkedStyle.GetId()}, true);
				arrCurrentParagraphs[0].ApplyTextPr(oTextPr);
				this.Recalculate();
				this.Document_UpdateSelectionState();
				this.Document_UpdateInterfaceState();
				return;
			}
		}
	}

	var oParaPr = this.GetCalculatedParaPr();
	if (oParaPr.PStyle && this.Styles.Get(oParaPr.PStyle) && this.Styles.Get(oParaPr.PStyle).GetName() === sName)
		this.Controller.ClearParagraphFormatting(false, true);
	else
		this.Controller.SetParagraphStyle(sName);

	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.SetParagraphContextualSpacing = function(Value)
{
	this.Controller.SetParagraphContextualSpacing(Value);
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.SetParagraphPageBreakBefore = function(Value)
{
	this.Controller.SetParagraphPageBreakBefore(Value);
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.SetParagraphKeepLines = function(Value)
{
	this.Controller.SetParagraphKeepLines(Value);
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.SetParagraphKeepNext = function(Value)
{
	this.Controller.SetParagraphKeepNext(Value);
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.SetParagraphWidowControl = function(Value)
{
	this.Controller.SetParagraphWidowControl(Value);
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.SetParagraphBorders = function(Borders)
{
	this.Controller.SetParagraphBorders(Borders);
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.SetParagraphFramePr = function(FramePr, bDelete)
{
	this.Controller.SetParagraphFramePr(FramePr, bDelete);
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateRulersState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.IncreaseDecreaseFontSize = function(bIncrease)
{
	this.Controller.IncreaseDecreaseFontSize(bIncrease);
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.IncreaseDecreaseIndent = function(bIncrease)
{
	this.Controller.IncreaseDecreaseIndent(bIncrease);
};
CDocument.prototype.Paragraph_SetHighlight = function(IsColor, r, g, b)
{
	if (true === this.IsTextSelectionUse())
	{
		if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
		{
			this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetTextHighlight);

			if (false === IsColor)
				this.AddToParagraph(new ParaTextPr({HighLight : highlight_None}));
			else
				this.AddToParagraph(new ParaTextPr({HighLight : new CDocumentColor(r, g, b)}));

			this.Document_UpdateInterfaceState();
			editor.sync_MarkerFormatCallback(false);
		}
	}
	else
	{
		if (false === IsColor)
			this.HighlightColor = highlight_None;
		else
			this.HighlightColor = new CDocumentColor(r, g, b);
	}
};
CDocument.prototype.SetImageProps = function(Props)
{
	this.Controller.SetImageProps(Props);
	this.Recalculate();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.ShapeApply = function(shapeProps)
{
	this.DrawingObjects.shapeApply(shapeProps);
};
CDocument.prototype.Select_Drawings = function(DrawingArray, TargetContent)
{
	this.private_UpdateTargetForCollaboration();

	if (DrawingArray.length === 1 && DrawingArray[0].Is_Inline())
		return;
	this.DrawingObjects.resetSelection();
	var hdr_ftr = TargetContent.IsHdrFtr(true);
	if (hdr_ftr)
	{
		hdr_ftr.Content.Set_DocPosType(docpostype_DrawingObjects);
		hdr_ftr.Set_CurrentElement(false);
	}
	else
	{
		this.Set_DocPosType(docpostype_DrawingObjects);
	}
	for (var i = 0; i < DrawingArray.length; ++i)
	{
		this.DrawingObjects.selectObject(DrawingArray[i].GraphicObj, 0);
	}
};
CDocument.prototype.SetTableProps = function(Props)
{
	this.Controller.SetTableProps(Props);
	this.Recalculate();
	this.Document_UpdateInterfaceState();
	this.Document_UpdateRulersState();
	this.Document_UpdateSelectionState();
};
/**
 * Получаем рассчитанные настройки параграфа (полностью заполненные)
 * @returns {CParaPr}
 */
CDocument.prototype.GetCalculatedParaPr = function()
{
	return this.Controller.GetCalculatedParaPr();
};
/**
 * Получаем рассчитанные настройки текста (полностью заполненные)
 * @returns {CTextPr}
 */
CDocument.prototype.GetCalculatedTextPr = function()
{
	var ret = this.Controller.GetCalculatedTextPr();
    if(ret)
    {

        if(ret.RFonts){
            var oTheme = this.Get_Theme();
            if(oTheme)
            {
                if(ret.RFonts.Ascii){
                    ret.RFonts.Ascii.Name = oTheme.themeElements.fontScheme.checkFont(ret.RFonts.Ascii.Name);
                }
                if(ret.RFonts.EastAsia){
                    ret.RFonts.EastAsia.Name = oTheme.themeElements.fontScheme.checkFont(ret.RFonts.EastAsia.Name);
                }
                if(ret.RFonts.HAnsi){
                    ret.RFonts.HAnsi.Name = oTheme.themeElements.fontScheme.checkFont(ret.RFonts.HAnsi.Name);
                }
                if(ret.RFonts.CS){
                    ret.RFonts.CS.Name = oTheme.themeElements.fontScheme.checkFont(ret.RFonts.CS.Name);
                }
                if(ret.FontFamily && ret.FontFamily.Name){
                    ret.FontFamily.Name = oTheme.themeElements.fontScheme.checkFont(ret.FontFamily.Name);
                }
            }
        }
        return ret;
    }
};
/**
 * Получаем прямые настройки параграфа, т.е. которые выставлены непосредственно у параграфа, без учета стилей
 * @returns {CParaPr}
 */
CDocument.prototype.GetDirectTextPr = function()
{
	return this.Controller.GetDirectTextPr();
};
/**
 * Получаем прямые настройки текста, т.е. которые выставлены непосредственно у рана, без учета стилей
 * @returns {CTextPr}
 */
CDocument.prototype.GetDirectParaPr = function()
{
	return this.Controller.GetDirectParaPr();
};
CDocument.prototype.Get_PageSizesByDrawingObjects = function()
{
	return this.DrawingObjects.getPageSizesByDrawingObjects();
};
CDocument.prototype.Set_DocumentMargin = function(MarPr)
{
	// TODO: Document.Set_DocumentOrientation Сделать в зависимости от выделения

	var CurPos = this.CurPos.ContentPos;
	var SectPr = this.SectionsInfo.Get_SectPr(CurPos).SectPr;

	var L = MarPr.Left;
	var T = MarPr.Top;
	var R = ( undefined === MarPr.Right ? undefined : SectPr.Get_PageWidth() - MarPr.Right );
	var B = ( undefined === MarPr.Bottom ? undefined : SectPr.Get_PageHeight() - MarPr.Bottom );

	SectPr.Set_PageMargins(L, T, R, B);
	this.DrawingObjects.CheckAutoFit();

	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
	this.Document_UpdateRulersState();
};
CDocument.prototype.Set_DocumentPageSize = function(W, H, bNoRecalc)
{
	// TODO: Document.Set_DocumentOrientation Сделать в зависимости от выделения

	var CurPos = this.CurPos.ContentPos;
	var SectPr = this.SectionsInfo.Get_SectPr(CurPos).SectPr;

	SectPr.Set_PageSize(W, H);

	this.DrawingObjects.CheckAutoFit();
	if (true != bNoRecalc)
	{
		this.Recalculate();
		this.Document_UpdateSelectionState();
		this.Document_UpdateInterfaceState();
		this.Document_UpdateRulersState();
	}
};
CDocument.prototype.Get_DocumentPageSize = function()
{
	// TODO: Document.Get_DocumentOrientation Сделать в зависимости от выделения

	var CurPos             = this.CurPos.ContentPos;
	var SectionInfoElement = this.SectionsInfo.Get_SectPr(CurPos);

	if (undefined === SectionInfoElement)
		return true;

	var SectPr = SectionInfoElement.SectPr;

	return {W : SectPr.Get_PageWidth(), H : SectPr.Get_PageHeight()};
};
CDocument.prototype.Set_DocumentOrientation = function(Orientation, bNoRecalc)
{
	// TODO: Document.Set_DocumentOrientation Сделать в зависимости от выделения

	var CurPos = this.CurPos.ContentPos;
	var SectPr = this.SectionsInfo.Get_SectPr(CurPos).SectPr;

	SectPr.Set_Orientation(Orientation, true);

	this.DrawingObjects.CheckAutoFit();
	if (true != bNoRecalc)
	{
		this.Recalculate();
		this.Document_UpdateSelectionState();
		this.Document_UpdateInterfaceState();
		this.Document_UpdateRulersState();
	}
};
CDocument.prototype.Get_DocumentOrientation = function()
{
	// TODO: Document.Get_DocumentOrientation Сделать в зависимости от выделения

	var CurPos             = this.CurPos.ContentPos;
	var SectionInfoElement = this.SectionsInfo.Get_SectPr(CurPos);

	if (undefined === SectionInfoElement)
		return true;

	var SectPr = SectionInfoElement.SectPr;

	return ( SectPr.Get_Orientation() === Asc.c_oAscPageOrientation.PagePortrait ? true : false );
};
CDocument.prototype.Set_DocumentDefaultTab = function(DTab)
{
	this.History.Add(new CChangesDocumentDefaultTab(this, AscCommonWord.Default_Tab_Stop, DTab));
	AscCommonWord.Default_Tab_Stop = DTab;
};
CDocument.prototype.Set_DocumentEvenAndOddHeaders = function(Value)
{
	if (Value !== EvenAndOddHeaders)
	{
		this.History.Add(new CChangesDocumentEvenAndOddHeaders(this, EvenAndOddHeaders, Value));
		EvenAndOddHeaders = Value;
	}
};
/**
 * Обновляем данные в интерфейсе о свойствах параграфа.
 */
CDocument.prototype.Interface_Update_ParaPr = function()
{
	if (!this.Api)
		return;

	var ParaPr = this.GetCalculatedParaPr();

	if (null != ParaPr)
	{
		// Проверим, можно ли добавить буквицу
		ParaPr.CanAddDropCap = false;

		if (docpostype_Content === this.Get_DocPosType())
		{
			var Para = null;
			if (false === this.Selection.Use && type_Paragraph === this.Content[this.CurPos.ContentPos].GetType())
				Para = this.Content[this.CurPos.ContentPos];
			else if (true === this.Selection.Use && this.Selection.StartPos <= this.Selection.EndPos && type_Paragraph === this.Content[this.Selection.StartPos].GetType())
				Para = this.Content[this.Selection.StartPos];
			else if (true === this.Selection.Use && this.Selection.StartPos > this.Selection.EndPos && type_Paragraph === this.Content[this.Selection.EndPos].GetType())
				Para = this.Content[this.Selection.EndPos];

			if (null != Para && undefined === Para.Get_FramePr())
			{
				var Prev = Para.Get_DocumentPrev();
				if ((null === Prev || type_Paragraph != Prev.GetType() || undefined === Prev.Get_FramePr() || undefined === Prev.Get_FramePr().DropCap) && true === Para.Can_AddDropCap())
					ParaPr.CanAddDropCap = true;
			}
		}

		var oSelectedInfo = this.GetSelectedElementsInfo();
		var Math          = oSelectedInfo.Get_Math();
		if (null !== Math)
			ParaPr.CanAddImage = false;
		else
			ParaPr.CanAddImage = true;

		if (undefined != ParaPr.Tabs)
			this.Api.Update_ParaTab(AscCommonWord.Default_Tab_Stop, ParaPr.Tabs);

		if (ParaPr.Shd && ParaPr.Shd.Unifill)
		{
			ParaPr.Shd.Unifill.check(this.theme, this.Get_ColorMap());
		}

		var SelectedInfo = this.GetSelectedElementsInfo();
		var Math         = SelectedInfo.Get_Math();
		if (null !== Math && true !== Math.Is_Inline())
			ParaPr.Jc = Math.Get_Align();

		this.Api.UpdateParagraphProp(ParaPr);
	}
};
/**
 * Обновляем данные в интерфейсе о свойствах текста.
 */
CDocument.prototype.Interface_Update_TextPr = function()
{
	if (!this.Api)
		return;

	var TextPr = this.GetCalculatedTextPr();

	if (null != TextPr)
	{
		var theme = this.Get_Theme();
		if (theme && theme.themeElements && theme.themeElements.fontScheme)
		{
			if (TextPr.FontFamily)
			{
				TextPr.FontFamily.Name = theme.themeElements.fontScheme.checkFont(TextPr.FontFamily.Name);
			}
			if (TextPr.RFonts)
			{
				if (TextPr.RFonts.Ascii)
					TextPr.RFonts.Ascii.Name = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.Ascii.Name);
				if (TextPr.RFonts.EastAsia)
					TextPr.RFonts.EastAsia.Name = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.EastAsia.Name);
				if (TextPr.RFonts.HAnsi)
					TextPr.RFonts.HAnsi.Name = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.HAnsi.Name);
				if (TextPr.RFonts.CS)
					TextPr.RFonts.CS.Name = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.CS.Name);
			}
		}
		if (TextPr.Unifill)
		{
			var RGBAColor = TextPr.Unifill.getRGBAColor();
			TextPr.Color  = new CDocumentColor(RGBAColor.R, RGBAColor.G, RGBAColor.B, false);
		}
		if (TextPr.Shd && TextPr.Shd.Unifill)
		{
			TextPr.Shd.Unifill.check(this.theme, this.Get_ColorMap());
		}
		this.Api.UpdateTextPr(TextPr);
	}
};
/**
 * Обновляем данные в интерфейсе о свойствах графики (картинки, автофигуры).
 * @param Flag
 * @returns {*}
 */
CDocument.prototype.Interface_Update_DrawingPr = function(Flag)
{
	var DrawingPr = this.DrawingObjects.Get_Props();

	if (true === Flag)
		return DrawingPr;
	else
	{
		if (this.Api)
		{
			for (var i = 0; i < DrawingPr.length; ++i)
				this.Api.sync_ImgPropCallback(DrawingPr[i]);
		}
	}
	if (Flag)
		return null;
};
/**
 * Обновляем данные в интерфейсе о свойствах таблицы.
 * @param Flag
 * @returns {*}
 */
CDocument.prototype.Interface_Update_TablePr = function(Flag)
{
	var TablePr = null;
	if (docpostype_Content == this.Get_DocPosType() && ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos) || false == this.Selection.Use))
	{
		if (true == this.Selection.Use)
			TablePr = this.Content[this.Selection.StartPos].GetTableProps();
		else
			TablePr = this.Content[this.CurPos.ContentPos].GetTableProps();
	}

	if (null !== TablePr)
		TablePr.CanBeFlow = true;

	if (true === Flag)
		return TablePr;
	else if (null != TablePr)
		this.Api.sync_TblPropCallback(TablePr);
};
/**
 * Обновляем данные в интерфейсе о свойствах колонотитулов.
 */
CDocument.prototype.Interface_Update_HdrFtrPr = function()
{
	if (docpostype_HdrFtr === this.Get_DocPosType())
	{
		this.Api.sync_HeadersAndFootersPropCallback(this.HdrFtr.Get_Props());
	}
};
CDocument.prototype.Internal_GetContentPosByXY = function(X, Y, nCurPage, ColumnsInfo)
{
    if (!ColumnsInfo)
        ColumnsInfo = {Column : 0, ColumnsCount : 1};

    if (undefined === nCurPage || null === nCurPage)
		nCurPage = this.CurPage;

    if (nCurPage >= this.Pages.length)
    	nCurPage = this.Pages.length - 1;
    else if (nCurPage < 0)
    	nCurPage = 0;

    // Сначала проверим Flow-таблицы
    var FlowTable = this.DrawingObjects.getTableByXY(X, Y, nCurPage, this);
    if (null != FlowTable)
    {
        var ElementPos;
        if (flowobject_Table === FlowTable.Get_Type())
        {
            ElementPos = FlowTable.Table.Index;
        }
        else
        {
            var Frame = FlowTable;

            var StartPos  = Frame.StartIndex;
            var FlowCount = Frame.FlowCount;

            for (var Pos = StartPos; Pos < StartPos + FlowCount; ++Pos)
            {
                var Item = this.Content[Pos];

                if (Y < Item.Pages[0].Bounds.Bottom)
                    return Pos;
            }

            ElementPos = StartPos + FlowCount - 1;
        }

        var Element              = this.Content[ElementPos];
        ColumnsInfo.Column       = Element.Get_StartColumn();
        ColumnsInfo.ColumnsCount = Element.Get_ColumnsCount();
        return ElementPos;
    }

    // Теперь проверим пустые параграфы с окончанием секций
    var SectCount = this.Pages[nCurPage].EndSectionParas.length;
    for (var Index = 0; Index < SectCount; ++Index)
    {
        var Item   = this.Pages[nCurPage].EndSectionParas[Index];
        var Bounds = Item.Pages[0].Bounds;

        if (Y < Bounds.Bottom && Y > Bounds.Top && X > Bounds.Left && X < Bounds.Right)
        {
            var Element              = this.Content[Item.Index];
            ColumnsInfo.Column       = Element.Get_StartColumn();
            ColumnsInfo.ColumnsCount = Element.Get_ColumnsCount();
            return Item.Index;
        }
    }

    // Сначала мы определим секцию и колонку, в которую попали
    var Page = this.Pages[nCurPage];

    var SectionIndex = 0;
    for (var SectionsCount = Page.Sections.length; SectionIndex < SectionsCount - 1; ++SectionIndex)
    {
        if (Y < Page.Sections[SectionIndex + 1].Y)
            break;
    }

    var PageSection  = this.Pages[nCurPage].Sections[SectionIndex];
    var ColumnsCount = PageSection.Columns.length;
    var ColumnIndex  = 0;
    for (; ColumnIndex < ColumnsCount - 1; ++ColumnIndex)
    {
        if (X < (PageSection.Columns[ColumnIndex].XLimit + PageSection.Columns[ColumnIndex + 1].X) / 2)
            break;
    }

    // TODO: Разобраться с ситуацией, когда пустые колонки стоят не только в конце
    while (ColumnIndex > 0 && true === PageSection.Columns[ColumnIndex].Empty)
        ColumnIndex--;

    ColumnsInfo.Column       = ColumnIndex;
    ColumnsInfo.ColumnsCount = ColumnsCount;

    var Column   = PageSection.Columns[ColumnIndex];
    var StartPos = Column.Pos;
    var EndPos   = Column.EndPos;

    // Сохраним позиции всех Inline элементов на данной странице
    var InlineElements = [];
    for (var Index = StartPos; Index <= EndPos; Index++)
    {
        var Item = this.Content[Index];

        var PrevItem       = Item.Get_DocumentPrev();
        var bEmptySectPara = (type_Paragraph === Item.GetType() && undefined !== Item.Get_SectionPr() && true === Item.IsEmpty() && null !== PrevItem && (type_Paragraph !== PrevItem.GetType() || undefined === PrevItem.Get_SectionPr())) ? true : false;

        if (false != Item.Is_Inline() && (type_Paragraph !== Item.GetType() || false === bEmptySectPara))
            InlineElements.push(Index);
    }

    var Count = InlineElements.length;
    if (Count <= 0)
        return Math.min(Math.max(0, Page.EndPos), this.Content.length - 1);

    for (var Pos = 0; Pos < Count - 1; ++Pos)
    {
        var Item = this.Content[InlineElements[Pos + 1]];

        var PageBounds = Item.GetPageBounds(0);
        if (Y < PageBounds.Top)
            return InlineElements[Pos];

        if (Item.GetPagesCount() > 1)
        {
            if (true !== Item.IsStartFromNewPage())
                return InlineElements[Pos + 1];

            return InlineElements[Pos];
        }

        if (Pos === Count - 2)
        {
            // Такое возможно, если страница заканчивается Flow-таблицей
            return InlineElements[Count - 1];
        }
    }

    return InlineElements[0];
};
CDocument.prototype.RemoveSelection = function(bNoCheckDrawing)
{
	this.Reset_WordSelection();
	this.Controller.RemoveSelection(bNoCheckDrawing);
};
CDocument.prototype.IsSelectionEmpty = function(bCheckHidden)
{
	return this.Controller.IsSelectionEmpty(bCheckHidden);
};
CDocument.prototype.DrawSelectionOnPage = function(PageAbs)
{
	this.DrawingDocument.UpdateTargetTransform(null);
	this.DrawingDocument.SetTextSelectionOutline(false);
	this.Controller.DrawSelectionOnPage(PageAbs);
};
CDocument.prototype.GetSelectionBounds = function()
{
	return this.Controller.GetSelectionBounds();
};
CDocument.prototype.Selection_SetStart         = function(X, Y, MouseEvent)
{
	this.Reset_WordSelection();

    var bInText      = (null === this.IsInText(X, Y, this.CurPage) ? false : true);
    var bTableBorder = (null === this.IsTableBorder(X, Y, this.CurPage) ? false : true);
    var nInDrawing   = this.DrawingObjects.IsInDrawingObject(X, Y, this.CurPage, this);
	var bFlowTable   = (null === this.DrawingObjects.getTableByXY(X, Y, this.CurPage, this) ? false : true);

    // Сначала посмотрим, попалили мы в текстовый селект (но при этом не в границу таблицы и не более чем одинарным кликом)
    if (-1 !== this.Selection.DragDrop.Flag && MouseEvent.ClickCount <= 1 && false === bTableBorder &&
        ( nInDrawing < 0 || ( nInDrawing === DRAWING_ARRAY_TYPE_BEHIND && true === bInText ) || ( nInDrawing > -1 && ( docpostype_DrawingObjects === this.CurPos.Type || ( docpostype_HdrFtr === this.CurPos.Type && docpostype_DrawingObjects === this.HdrFtr.CurHdrFtr.Content.CurPos.Type ) ) && true === this.DrawingObjects.isSelectedText() && null !== this.DrawingObjects.getMajorParaDrawing() && this.DrawingObjects.getGraphicInfoUnderCursor(this.CurPage, X, Y).cursorType === "text" ) ) &&
        true === this.CheckPosInSelection(X, Y, this.CurPage, undefined))
    {
        // Здесь мы сразу не начинаем перемещение текста. Его мы начинаем, курсор хотя бы немного изменит свою позицию,
        // это проверяется на MouseMove.
        // TODO: В ворде кроме изменения положения мыши, также запускается таймер для стартования drag-n-drop по времени,
        //       его можно здесь вставить.

        this.Selection.DragDrop.Flag = 1;
        this.Selection.DragDrop.Data = {X : X, Y : Y, PageNum : this.CurPage};
        return;
    }

    var bCheckHdrFtr = true;
	var bFootnotes = false;

	var nDocPosType = this.Get_DocPosType();
    if (docpostype_HdrFtr === nDocPosType)
    {
        bCheckHdrFtr         = false;
        this.Selection.Start = true;
        this.Selection.Use   = true;
        if (false != this.HdrFtr.Selection_SetStart(X, Y, this.CurPage, MouseEvent, false))
            return;

        this.Selection.Start = false;
        this.Selection.Use   = false;
        this.DrawingDocument.ClearCachePages();
        this.DrawingDocument.FirePaint();
        this.DrawingDocument.EndTrackTable(null, true);
    }
	else
	{
		bFootnotes = this.Footnotes.CheckHitInFootnote(X, Y, this.CurPage);
	}

    var PageMetrics = this.Get_PageContentStartPos(this.CurPage, this.Pages[this.CurPage].Pos);

	var oldDocPosType = this.Get_DocPosType();
    // Проверяем, не попали ли мы в колонтитул (если мы попадаем в Flow-объект, то попадание в колонтитул не проверяем)
    if (true != bFlowTable && nInDrawing < 0 && true === bCheckHdrFtr && MouseEvent.ClickCount >= 2 && ( Y <= PageMetrics.Y || Y > PageMetrics.YLimit ))
    {
        // Если был селект, тогда убираем его
        if (true === this.Selection.Use)
            this.RemoveSelection();

        this.Set_DocPosType(docpostype_HdrFtr);

        // Переходим к работе с колонтитулами
        MouseEvent.ClickCount = 1;
        this.HdrFtr.Selection_SetStart(X, Y, this.CurPage, MouseEvent, true);
        this.Interface_Update_HdrFtrPr();

        this.DrawingDocument.ClearCachePages();
        this.DrawingDocument.FirePaint();
        this.DrawingDocument.EndTrackTable(null, true);
    }
	else if (true !== bFlowTable && nInDrawing < 0 && true === bFootnotes)
	{
		this.RemoveSelection();
        this.Selection.Start = true;
        this.Selection.Use   = true;

		this.Set_DocPosType(docpostype_Footnotes);
		this.Footnotes.StartSelection(X, Y, this.CurPage, MouseEvent);
	}
    else if (nInDrawing === DRAWING_ARRAY_TYPE_BEFORE || nInDrawing === DRAWING_ARRAY_TYPE_INLINE || ( false === bTableBorder && false === bInText && nInDrawing >= 0 ))
    {
        if (docpostype_DrawingObjects != this.CurPos.Type)
            this.RemoveSelection();

        // Прячем курсор
        this.DrawingDocument.TargetEnd();
        this.DrawingDocument.SetCurrentPage(this.CurPage);

        this.Selection.Use   = true;
        this.Selection.Start = true;
        this.Selection.Flag  = selectionflag_Common;
        this.Set_DocPosType(docpostype_DrawingObjects);
        this.DrawingObjects.OnMouseDown(MouseEvent, X, Y, this.CurPage);
    }
    else
    {
        var bOldSelectionIsCommon = true;

        if (docpostype_DrawingObjects === this.CurPos.Type && (true != this.IsInDrawing(X, Y, this.CurPage) || ( nInDrawing === DRAWING_ARRAY_TYPE_BEHIND && true === bInText )))
        {
            this.DrawingObjects.resetSelection();
            bOldSelectionIsCommon = false;
        }

        var ContentPos = this.Internal_GetContentPosByXY(X, Y);

        if (docpostype_Content != this.CurPos.Type)
        {
            this.Set_DocPosType(docpostype_Content);
            this.CurPos.ContentPos = ContentPos;
            bOldSelectionIsCommon  = false;
        }

		var SelectionUse_old = this.Selection.Use;
		var Item             = this.Content[ContentPos];
		var ElementPageIndex = this.private_GetElementPageIndexByXY(ContentPos, X, Y, this.CurPage);
		var bTableBorder     = null === Item.IsTableBorder(X, Y, ElementPageIndex) ? false : true;

        // Убираем селект, кроме случаев либо текущего параграфа, либо при движении границ внутри таблицы
        if (!(true === SelectionUse_old && true === MouseEvent.ShiftKey && true === bOldSelectionIsCommon))
        {
            if ((selectionflag_Common != this.Selection.Flag) || ( true === this.Selection.Use && MouseEvent.ClickCount <= 1 && true != bTableBorder ))
                this.RemoveSelection();
        }

        this.Selection.Use   = true;
        this.Selection.Start = true;
        this.Selection.Flag  = selectionflag_Common;

		if (true === SelectionUse_old && true === MouseEvent.ShiftKey && true === bOldSelectionIsCommon)
		{
			this.Selection_SetEnd(X, Y, {Type : AscCommon.g_mouse_event_type_up, ClickCount : 1});
			this.Selection.Use    = true;
			this.Selection.Start  = true;
			this.Selection.EndPos = ContentPos;
			this.Selection.Data   = null;
		}
		else
		{
			var ElementPageIndex = this.private_GetElementPageIndexByXY(ContentPos, X, Y, this.CurPage);
			Item.Selection_SetStart(X, Y, ElementPageIndex, MouseEvent, bTableBorder);

			if (this.IsNumberingSelection())
			{
				// TODO: Можно сделать передвигание нумерации как в Word
				return;
			}

			Item.Selection_SetEnd(X, Y, ElementPageIndex, {
				Type       : AscCommon.g_mouse_event_type_move,
				ClickCount : 1
			}, bTableBorder);

			if (true !== bTableBorder)
			{
				this.Selection.Use      = true;
				this.Selection.StartPos = ContentPos;
				this.Selection.EndPos   = ContentPos;
				this.Selection.Data     = null;

				this.CurPos.ContentPos = ContentPos;

				if (type_Paragraph === Item.GetType() && true === MouseEvent.CtrlKey)
				{
					var oHyperlink   = Item.CheckHyperlink(X, Y, ElementPageIndex);
					var oPageRefLink = Item.CheckPageRefLink(X, Y, ElementPageIndex);
					if (null != oHyperlink)
					{
						this.Selection.Data = {
							Hyperlink : oHyperlink
						};
					}
					else if (null !== oPageRefLink)
					{
						this.Selection.Data = {
							PageRef : oPageRefLink
						};
					}
				}
			}
			else
			{
				this.Selection.Data = {
					TableBorder : true,
					Pos         : ContentPos,
					Selection   : SelectionUse_old
				};
			}
		}
	}

	//при переходе из колонтитула в контент(и обратно) необходимо скрывать иконку с/в
	var newDocPosType = this.Get_DocPosType();
    if((docpostype_HdrFtr === newDocPosType && docpostype_Content === oldDocPosType) || (docpostype_Content === newDocPosType && docpostype_HdrFtr === oldDocPosType))
    {
		window['AscCommon'].g_specialPasteHelper.SpecialPasteButton_Hide();
    }
};
/**
 * Данная функция может использоваться как при движении, так и при окончательном выставлении селекта.
 * Если bEnd = true, тогда это конец селекта.
 * @param X
 * @param Y
 * @param MouseEvent
 */
CDocument.prototype.Selection_SetEnd = function(X, Y, MouseEvent)
{
	this.Reset_WordSelection();

	// Работаем с колонтитулом
	if (docpostype_HdrFtr === this.CurPos.Type)
    {
        this.HdrFtr.Selection_SetEnd(X, Y, this.CurPage, MouseEvent);
        if (AscCommon.g_mouse_event_type_up == MouseEvent.Type)
        {
            if (true != this.DrawingObjects.isPolylineAddition())
                this.Selection.Start = false;
            else
                this.Selection.Start = true;
        }

        return;
    }
    else if (docpostype_DrawingObjects === this.CurPos.Type)
    {
        if (AscCommon.g_mouse_event_type_up == MouseEvent.Type)
        {
            this.DrawingObjects.OnMouseUp(MouseEvent, X, Y, this.CurPage);

            if (true != this.DrawingObjects.isPolylineAddition())
            {
                this.Selection.Start = false;
                this.Selection.Use   = true;
            }
            else
            {
                this.Selection.Start = true;
                this.Selection.Use   = true;
            }
        }
        else
        {
            this.DrawingObjects.OnMouseMove(MouseEvent, X, Y, this.CurPage);
        }
        return;
    }
	else if (docpostype_Footnotes === this.CurPos.Type)
	{
		this.Footnotes.EndSelection(X, Y, this.CurPage, MouseEvent);

		if (AscCommon.g_mouse_event_type_up == MouseEvent.Type)
			this.Selection.Start = false;

		return;
	}

    // Обрабатываем движение границы у таблиц
    if (true === this.IsMovingTableBorder())
    {
        var Item             = this.Content[this.Selection.Data.Pos];
        var ElementPageIndex = this.private_GetElementPageIndexByXY(this.Selection.Data.Pos, X, Y, this.CurPage);
        Item.Selection_SetEnd(X, Y, ElementPageIndex, MouseEvent, true);

        if (AscCommon.g_mouse_event_type_up == MouseEvent.Type)
        {
            this.Selection.Start = false;

            if (true != this.Selection.Data.Selection)
            {
                this.Selection.Use = false;
            }

            this.Selection.Data = null;
        }

        return;
    }

    if (false === this.Selection.Use)
        return;

    var ContentPos = this.Internal_GetContentPosByXY(X, Y);

    this.CurPos.ContentPos = ContentPos;
    var OldEndPos          = this.Selection.EndPos;
    this.Selection.EndPos  = ContentPos;

    // Удалим отметки о старом селекте
    if (OldEndPos < this.Selection.StartPos && OldEndPos < this.Selection.EndPos)
    {
        var TempLimit = Math.min(this.Selection.StartPos, this.Selection.EndPos);
        for (var Index = OldEndPos; Index < TempLimit; Index++)
        {
        	this.Content[Index].RemoveSelection();
        }
    }
    else if (OldEndPos > this.Selection.StartPos && OldEndPos > this.Selection.EndPos)
    {
        var TempLimit = Math.max(this.Selection.StartPos, this.Selection.EndPos);
        for (var Index = TempLimit + 1; Index <= OldEndPos; Index++)
        {
        	this.Content[Index].RemoveSelection();
        }
    }

    // Направление селекта: 1 - прямое, -1 - обратное, 0 - отмечен 1 элемент документа
    var Direction = ( ContentPos > this.Selection.StartPos ? 1 : ( ContentPos < this.Selection.StartPos ? -1 : 0 )  );

    if (AscCommon.g_mouse_event_type_up == MouseEvent.Type)
    	this.StopSelection();

    var Start, End;
    if (0 == Direction)
    {
        var Item             = this.Content[this.Selection.StartPos];
        var ElementPageIndex = this.private_GetElementPageIndexByXY(this.Selection.StartPos, X, Y, this.CurPage);
        Item.Selection_SetEnd(X, Y, ElementPageIndex, MouseEvent);

        if (this.IsNumberingSelection())
		{
			// Ничего не делаем
		}
        else if (false === Item.IsSelectionUse())
        {
            this.Selection.Use = false;

            if (null != this.Selection.Data && this.Selection.Data.Hyperlink)
            {
				var oHyperlink    = this.Selection.Data.Hyperlink;
				var sBookmarkName = oHyperlink.GetAnchor();
				var sValue        = oHyperlink.GetValue();

				if (oHyperlink.IsTopOfDocument())
				{
					this.MoveCursorToStartPos(false);
				}
				else if (sBookmarkName)
				{
					var oBookmark = this.BookmarksManager.GetBookmarkByName(sBookmarkName);
					if (oBookmark)
						oBookmark[0].GoToBookmark();
				}
				else if (sValue)
				{
					editor.sync_HyperlinkClickCallback(sValue);

					oHyperlink.SetVisited(true);
					for (var PageIdx = Item.Get_AbsolutePage(0); PageIdx < Item.Get_AbsolutePage(0) + Item.Get_PagesCount(); PageIdx++)
						this.DrawingDocument.OnRecalculatePage(PageIdx, this.Pages[PageIdx]);

					this.DrawingDocument.OnEndRecalculate(false, true);
				}
            }
            else if (null !== this.Selection.Data && this.Selection.Data.PageRef)
			{
				var oInstruction  = this.Selection.Data.PageRef.GetInstruction();
				if (oInstruction && fieldtype_PAGEREF === oInstruction.GetType())
				{
					var oBookmark = this.BookmarksManager.GetBookmarkByName(oInstruction.GetBookmarkName());
					if (oBookmark)
						oBookmark[0].GoToBookmark();
				}
			}
        }
        else
        {
            this.Selection.Use = true;
        }

        return;
    }
    else if (Direction > 0)
    {
        Start = this.Selection.StartPos;
        End   = this.Selection.EndPos;
    }
    else
    {
        End   = this.Selection.StartPos;
        Start = this.Selection.EndPos;
    }

    // TODO: Разрулить пустой селект
    // Чтобы не было эффекта, когда ничего не поселекчено, а при удалении соединяются параграфы

	for (var Index = Start; Index <= End; Index++)
	{
		var Item = this.Content[Index];
		Item.SetSelectionUse(true);

		switch (Index)
		{
			case Start:

				Item.SetSelectionToBeginEnd(Direction > 0 ? false : true, false);
				break;

			case End:

				Item.SetSelectionToBeginEnd(Direction > 0 ? true : false, true);
				break;

			default:

				Item.SelectAll(Direction);
				break;
		}
	}

    var ElementPageIndex = this.private_GetElementPageIndexByXY(ContentPos, X, Y, this.CurPage);
    this.Content[ContentPos].Selection_SetEnd(X, Y, ElementPageIndex, MouseEvent);

    // Проверяем, чтобы у нас в селект не попали элементы, в которых не выделено ничего
    if (true === this.Content[End].IsSelectionEmpty() && true === this.CheckEmptyElementsOnSelection)
    {
        this.Content[End].RemoveSelection();
        End--;
    }

    if (Start != End && true === this.Content[Start].IsSelectionEmpty() && true === this.CheckEmptyElementsOnSelection)
    {
        this.Content[Start].RemoveSelection();
        Start++;
    }

    if (Direction > 0)
    {
        this.Selection.StartPos = Start;
        this.Selection.EndPos   = End;
    }
    else
    {
        this.Selection.StartPos = End;
        this.Selection.EndPos   = Start;
    }
};
/**
 * Получаем направление селекта
 * @returns {number} Возвращается направление селекта. 1 - нормальное направление, -1 - обратное
 */
CDocument.prototype.GetSelectDirection = function()
{
	var oStartPos = this.GetContentPosition(true, true);
	var oEndPos   = this.GetContentPosition(true, false);

	for (var nPos = 0, nLen = Math.min(oStartPos.length, oEndPos.length); nPos < nLen; ++nPos)
	{
		if (!oEndPos[nPos] || !oStartPos[nPos] || oStartPos[nPos].Class !== oEndPos[nPos].Class)
			return 1;

		if (oStartPos[nPos].Position < oEndPos[nPos].Position)
			return 1;
		else if (oStartPos[nPos].Position > oEndPos[nPos].Position)
			return -1;
	}

	return 1;
};
CDocument.prototype.IsMovingTableBorder = function()
{
	return this.Controller.IsMovingTableBorder();
};
/**
 * Проверяем попали ли мы в селект.
 * @param X
 * @param Y
 * @param PageAbs
 * @param NearPos
 * @returns {boolean}
 */
CDocument.prototype.CheckPosInSelection = function(X, Y, PageAbs, NearPos)
{
	return this.Controller.CheckPosInSelection(X, Y, PageAbs, NearPos);
};
/**
 * Выделяем все содержимое, в зависимости от текущего положения курсора.
 */
CDocument.prototype.SelectAll = function()
{
	this.private_UpdateTargetForCollaboration();

	this.Reset_WordSelection();
	this.Controller.SelectAll();

	// TODO: Пока делаем Start = true, чтобы при Ctrl+A не происходил переход к концу селекта, надо будет
	//       сделать по нормальному
	this.Selection.Start = true;
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
	this.Document_UpdateRulersState();
	this.Selection.Start = false;

	// Отдельно обрабатываем это событие, потому что внутри него идет проверка на this.Selection.Start !== true
	this.Document_UpdateCopyCutState();

	this.private_UpdateCursorXY(true, true);
};
/**
 * Выделяем все элементы в заданном диапазоне
 * @param {number} nStartPos
 * @param {number} nEndPos
 */
CDocument.prototype.SelectRange = function(nStartPos, nEndPos)
{
	this.RemoveSelection();

	this.DrawingDocument.SelectEnabled(true);
	this.DrawingDocument.TargetEnd();

	this.Set_DocPosType(docpostype_Content);

	this.Selection.Use   = true;
	this.Selection.Start = false;
	this.Selection.Flag  = selectionflag_Common;

	this.Selection.StartPos = Math.max(0, Math.min(nStartPos, this.Content.length - 1));
	this.Selection.EndPos   = Math.max(this.Selection.StartPos, Math.min(nEndPos, this.Content.length - 1));

	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		this.Content[nIndex].SelectAll();
	}

	// TODO: Пока делаем Start = true, чтобы при Ctrl+A не происходил переход к концу селекта, надо будет
	//       сделать по нормальному
	this.Selection.Start = true;
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
	this.Document_UpdateRulersState();
	this.Selection.Start = false;

	// Отдельно обрабатываем это событие, потому что внутри него идет проверка на this.Selection.Start !== true
	this.Document_UpdateCopyCutState();

	this.private_UpdateCursorXY(true, true);
};
CDocument.prototype.OnEndTextDrag = function(NearPos, bCopy)
{
    if (true === this.Comments.Is_Use())
    {
        this.SelectComment(null, false);
        editor.sync_HideComment();
    }

    // Сначала нам надо проверить попадаем ли мы обратно в выделенный текст, если да, тогда ничего не делаем,
    // а если нет, тогда удаляем выделенный текст и вставляем его в заданное место.

    if (true === this.CheckPosInSelection(0, 0, 0, NearPos))
    {
        this.RemoveSelection();

        // Нам надо снять селект и поставить курсор в то место, где была ближайшая позиция
        var Paragraph = NearPos.Paragraph;
        Paragraph.Cursor_MoveToNearPos(NearPos);
        Paragraph.Document_SetThisElementCurrent(false);

        this.Document_UpdateSelectionState();
        this.Document_UpdateInterfaceState();
        this.Document_UpdateRulersState();
    }
    else
    {
        // Создаем сразу точку в истории, т.к. при выполнении функции GetSelectedContent нам надо, чтобы данная
        // точка уже набивалась изменениями. Если из-за совместного редактирования действие сделать невозможно будет,
        // тогда последнюю точку удаляем.
        History.Create_NewPoint(AscDFH.historydescription_Document_DragText);

        NearPos.Paragraph.Check_NearestPos(NearPos);

        // Получим копию выделенной части документа, которую надо перенести в новое место, одновременно с этим
        // удаляем эту выделенную часть (если надо).

        var DocContent = this.GetSelectedContent(true);

        if (false === this.Can_InsertContent(DocContent, NearPos))
        {
            this.History.Remove_LastPoint();
			NearPos.Paragraph.Clear_NearestPosArray();
            return;
        }

        var Para = NearPos.Paragraph;

        // Если мы копируем, тогда не надо проверять выделенные параграфы, а если переносим, тогда проверяем
        var CheckChangesType = (true !== bCopy ? AscCommon.changestype_Document_Content : changestype_None);
        if (false === this.Document_Is_SelectionLocked(CheckChangesType, {
                Type      : changestype_2_ElementsArray_and_Type,
                Elements  : [Para],
                CheckType : changestype_Paragraph_Content
            }, true))
        {
            // Если надо удаляем выделенную часть (пересчет отключаем на время удаления)
            if (true !== bCopy)
            {
                this.TurnOff_Recalculate();
                this.TurnOff_InterfaceEvents();
                this.Remove(1, false, false, false);
                this.TurnOn_Recalculate(false);
                this.TurnOn_InterfaceEvents(false);

                if (false === Para.Is_UseInDocument())
                {
                    this.Document_Undo();
                    this.History.Clear_Redo();
                    return;
                }
            }

            this.RemoveSelection(true);

            // Выделение выставляется внутри функции Insert_Content
            Para.Parent.Insert_Content(DocContent, NearPos);

            this.Recalculate();

            this.Document_UpdateSelectionState();
            this.Document_UpdateInterfaceState();
            this.Document_UpdateRulersState();
        }
        else
		{
			this.History.Remove_LastPoint();
			NearPos.Paragraph.Clear_NearestPosArray();
		}
    }
};
/**
 * В данной функции мы получаем выделенную часть документа в формате класса CSelectedContent.
 * @param bUseHistory - нужна ли запись в историю созданных классов. (при drag-n-drop нужна, при копировании не нужна)
 * @returns {CSelectedContent}
 */
CDocument.prototype.GetSelectedContent = function(bUseHistory)
{
	// При копировании нам не нужно, чтобы новые классы помечались как созданные в рецензировании, а при перетаскивании
	// нужно.
	var isTrack = this.Is_TrackRevisions() && !bUseHistory;
	if (isTrack)
		this.Set_TrackRevisions(false);

	var bNeedTurnOffTableId = g_oTableId.m_bTurnOff === false && true !== bUseHistory;
	if (!bUseHistory)
		History.TurnOff();

	if (bNeedTurnOffTableId)
	{
		g_oTableId.m_bTurnOff = true;
	}

	var SelectedContent = new CSelectedContent();
	this.Controller.GetSelectedContent(SelectedContent);
	SelectedContent.On_EndCollectElements(this, false);

	if (!bUseHistory)
		History.TurnOn();

	if (bNeedTurnOffTableId)
	{
		g_oTableId.m_bTurnOff = false;
	}

	if (isTrack)
		this.Set_TrackRevisions(true);

	return SelectedContent;
};
CDocument.prototype.Can_InsertContent = function(SelectedContent, NearPos)
{
	// Проверяем, что вставка не пустая
	if (SelectedContent.Elements.length <= 0)
		return false;

	var Para = NearPos.Paragraph;

	// Автофигуры не вставляем в другие автофигуры
	if (true === Para.Parent.Is_DrawingShape() && true === SelectedContent.HaveShape)
		return false;


	//В заголовки диаграмм не вставляем формулы и любые DrawingObjects
	if (Para.bFromDocument === false && (SelectedContent.DrawingObjects.length > 0 || SelectedContent.HaveMath || SelectedContent.HaveTable))
		return false;

	// Проверяем корректность места, куда вставляем
	var ParaNearPos = NearPos.Paragraph.Get_ParaNearestPos(NearPos);
	if (null === ParaNearPos || ParaNearPos.Classes.length < 2)
		return false;

	var LastClass = ParaNearPos.Classes[ParaNearPos.Classes.length - 1];
	if (para_Math_Run === LastClass.Type)
	{
		if (!SelectedContent.CanConvertToMath)
		{
			// Проверяем, что вставляемый контент тоже формула
			var Element = SelectedContent.Elements[0].Element;
			if (1 !== SelectedContent.Elements.length || type_Paragraph !== Element.GetType() || null === LastClass.Parent)
				return false;

			var Math  = null;
			var Count = Element.Content.length;
			for (var Index = 0; Index < Count; Index++)
			{
				var Item = Element.Content[Index];
				if (para_Math === Item.Type && null === Math)
					Math = Element.Content[Index];
				else if (true !== Item.Is_Empty({SkipEnd : true}))
					return false;
			}
		}
	}
	else if (para_Run !== LastClass.Type)
		return false;

	if (null === Para.Parent || undefined === Para.Parent)
		return false;

	return true;
};
CDocument.prototype.Insert_Content = function(SelectedContent, NearPos)
{
	var Para        = NearPos.Paragraph;
	var ParaNearPos = Para.Get_ParaNearestPos(NearPos);
	var LastClass   = ParaNearPos.Classes[ParaNearPos.Classes.length - 1];
	if (para_Math_Run === LastClass.Type)
	{
		var MathRun        = LastClass;
		var NewMathRun     = MathRun.Split(ParaNearPos.NearPos.ContentPos, ParaNearPos.Classes.length - 1);
		var MathContent    = ParaNearPos.Classes[ParaNearPos.Classes.length - 2];
		var MathContentPos = ParaNearPos.NearPos.ContentPos.Data[ParaNearPos.Classes.length - 2];
		var Element        = SelectedContent.Elements[0].Element;

		var InsertMathContent = null;
		for (var nPos = 0, nParaLen = Element.Content.length; nPos < nParaLen; nPos++)
		{
			if (para_Math === Element.Content[nPos].Type)
			{
				InsertMathContent = Element.Content[nPos];
				break;
			}
		}

        if(null === InsertMathContent)
        {
            //try to convert content to ParaMath in simple cases.
            InsertMathContent = SelectedContent.ConvertToMath();
        }

        if (null !== InsertMathContent)
		{
			MathContent.Add_ToContent(MathContentPos + 1, NewMathRun);
			MathContent.Insert_MathContent(InsertMathContent.Root, MathContentPos + 1, true);
		}
	}
	else if (para_Run === LastClass.Type)
	{
		var NearContentPos = NearPos.ContentPos;
		// Сначала найдем номер элемента, начиная с которого мы будем производить вставку
		var DstIndex       = -1;
		var Count          = this.Content.length;
		for (var Index = 0; Index < Count; Index++)
		{
			if (this.Content[Index] === Para)
			{
				DstIndex = Index;
				break;
			}
		}

		if (-1 === DstIndex)
			return false;

		var Elements      = SelectedContent.Elements;
		var ElementsCount = Elements.length;
		var FirstElement  = SelectedContent.Elements[0];
		if (1 === ElementsCount && true !== FirstElement.SelectedAll && type_Paragraph === FirstElement.Element.GetType() && true !== FirstElement.Element.Is_Empty())
		{
			// Нам нужно в заданный параграф вставить выделенный текст
			var NewPara          = FirstElement.Element;
			var NewElementsCount = NewPara.Content.length - 1; // Последний ран с para_End не добавляем

			var LastClass  = ParaNearPos.Classes[ParaNearPos.Classes.length - 1];
			var NewElement = LastClass.Split(ParaNearPos.NearPos.ContentPos, ParaNearPos.Classes.length - 1);
			var PrevClass  = ParaNearPos.Classes[ParaNearPos.Classes.length - 2];
			var PrevPos    = ParaNearPos.NearPos.ContentPos.Data[ParaNearPos.Classes.length - 2];

			PrevClass.Add_ToContent(PrevPos + 1, NewElement);

			// TODO: Заглушка для переноса автофигур и картинок. Когда разрулим ситуацию так, чтобы когда у нас
			//       в текста была выделена автофигура выделение шло для автофигур, тогда здесь можно будет убрать.
			var bNeedSelect = (true === SelectedContent.MoveDrawing ? false : true);

			for (var Index = 0; Index < NewElementsCount; Index++)
			{
				var Item = NewPara.Content[Index];
				PrevClass.Add_ToContent(PrevPos + 1 + Index, Item);

				if (true === bNeedSelect)
					Item.SelectAll();
			}

			if (true === bNeedSelect)
			{
				PrevClass.Selection.Use      = true;
				PrevClass.Selection.StartPos = PrevPos + 1;
				PrevClass.Selection.EndPos   = PrevPos + 1 + NewElementsCount - 1;

				for (var Index = 0; Index < ParaNearPos.Classes.length - 2; Index++)
				{
					var Class    = ParaNearPos.Classes[Index];
					var ClassPos = ParaNearPos.NearPos.ContentPos.Data[Index];

					Class.Selection.Use      = true;
					Class.Selection.StartPos = ClassPos;
					Class.Selection.EndPos   = ClassPos;
				}

				this.Selection.Use      = true;
				this.Selection.StartPos = DstIndex;
				this.Selection.EndPos   = DstIndex;
			}

			if (PrevClass.Correct_Content)
			{
				PrevClass.Correct_Content();
			}
		}
		else
		{
			var bConcatS   = ( type_Paragraph !== Elements[0].Element.GetType() ? false : true );
			var bConcatE   = ( type_Paragraph !== Elements[ElementsCount - 1].Element.GetType() || true === Elements[ElementsCount - 1].SelectedAll ? false : true );
			var ParaS      = Para;
			var ParaE      = Para;
			var ParaEIndex = DstIndex;

			// Нам надо разделить наш параграф в заданной позиции, если позиция в
			// начале или конце параграфа, тогда делить не надо
			Para.Cursor_MoveToNearPos(NearPos);
			Para.RemoveSelection();

			var bAddEmptyPara          = false;
			var bDoNotIncreaseDstIndex = false;

			if (true === Para.IsCursorAtEnd())
			{
				bConcatE = false;

				if (1 === ElementsCount && type_Paragraph === FirstElement.Element.GetType() && ( true === FirstElement.Element.Is_Empty() || true == FirstElement.SelectedAll ))
				{
					bConcatS = false;

					// TODO: Возможно флаг bDoNotIncreaseDstIndex не нужен, и здесь не нужно увеличивать индекс DstIndex
					if (type_Paragraph !== this.Content[DstIndex].Get_Type() || true !== this.Content[DstIndex].Is_Empty())
					{
						DstIndex++;
						bDoNotIncreaseDstIndex = true;
					}
				}
				else if (true === Elements[ElementsCount - 1].SelectedAll && true === bConcatS)
					bAddEmptyPara = true;
			}
			else if (true === Para.IsCursorAtBegin())
			{
				bConcatS = false;
			}
			else
			{
				// Создаем новый параграф
				var NewParagraph = new Paragraph(this.DrawingDocument, this);
				Para.Split(NewParagraph);
				this.Internal_Content_Add(DstIndex + 1, NewParagraph);

				ParaE      = NewParagraph;
				ParaEIndex = DstIndex + 1;
			}

			var NewEmptyPara = null;
			if (true === bAddEmptyPara && true !== SelectedContent.DoNotAddEmptyPara)
			{
				// Создаем новый параграф
				NewEmptyPara = new Paragraph(this.DrawingDocument, this);
				NewEmptyPara.Set_Pr(ParaS.Pr);
				NewEmptyPara.TextPr.Apply_TextPr(ParaS.TextPr.Value);
				this.Internal_Content_Add(DstIndex + 1, NewEmptyPara);
			}

			var StartIndex = 0;
			if (true === bConcatS)
			{
				// Вызываем так, чтобы выделить все внутренние элементы
				var _ParaS = Elements[0].Element;
				_ParaS.SelectAll();
				var _ParaSContentLen = _ParaS.Content.length;

				// Если мы присоединяем новый параграф, то и копируем все настройки параграфа (так делает Word)
				ParaS.Concat(Elements[0].Element);
				ParaS.Set_Pr(Elements[0].Element.Pr);
				ParaS.TextPr.Clear_Style();
				ParaS.TextPr.Apply_TextPr(Elements[0].Element.TextPr.Value);

				StartIndex++;

				ParaS.Selection.Use      = true;
				ParaS.Selection.StartPos = ParaS.Content.length - _ParaSContentLen;
				ParaS.Selection.EndPos   = ParaS.Content.length - 1;
			}
			else if (true !== Para.IsCursorAtBegin() && true !== bDoNotIncreaseDstIndex)
			{
				DstIndex++;
			}

			var EndIndex = ElementsCount - 1;
			if (true === bConcatE && StartIndex < EndIndex)
			{
				var _ParaE    = Elements[ElementsCount - 1].Element;
				var TempCount = _ParaE.Content.length - 1;

				_ParaE.SelectAll();
				_ParaE.Concat(ParaE);
				_ParaE.Set_Pr(ParaE.Pr);

				this.Internal_Content_Add(ParaEIndex, _ParaE);
				this.Internal_Content_Remove(ParaEIndex + 1, 1);

				_ParaE.Selection.Use      = true;
				_ParaE.Selection.StartPos = 0;
				_ParaE.Selection.EndPos   = TempCount;

				EndIndex--;
			}

			for (var Index = StartIndex; Index <= EndIndex; Index++)
			{
				this.Internal_Content_Add(DstIndex + Index, Elements[Index].Element);
				this.Content[DstIndex + Index].SelectAll();
			}

			var LastPos = DstIndex + ElementsCount - 1;
			if (NewEmptyPara && NewEmptyPara === this.Content[LastPos + 1])
			{
				LastPos++;
				this.Content[LastPos].SelectAll();
			}
			else if (LastPos + 1 < this.Content.length && false === bConcatE && type_Paragraph === this.Content[LastPos + 1].Get_Type())
			{
				LastPos++;
				this.Content[LastPos].Selection.Use = true;
				this.Content[LastPos].Selection_SetBegEnd(true, true);
				this.Content[LastPos].Selection_SetBegEnd(false, true);
			}

			this.Selection.Use      = true;
			this.Selection.StartPos = DstIndex;
			this.Selection.EndPos   = LastPos;
			this.CurPos.ContentPos  = LastPos;
		}

		if (docpostype_DrawingObjects !== this.CurPos.Type)
			this.Set_DocPosType(docpostype_Content);
	}
};
CDocument.prototype.UpdateCursorType = function(X, Y, PageAbs, MouseEvent)
{
	if (null !== this.FullRecalc.Id && this.FullRecalc.PageIndex <= PageAbs)
		return;

	this.Api.sync_MouseMoveStartCallback();

	this.DrawingDocument.OnDrawContentControl(null, c_oContentControlTrack.Hover);

	var nDocPosType = this.Get_DocPosType();
	if (docpostype_HdrFtr === nDocPosType)
	{
		this.HeaderFooterController.UpdateCursorType(X, Y, PageAbs, MouseEvent);
	}
	else if (docpostype_DrawingObjects === nDocPosType)
	{
		this.DrawingsController.UpdateCursorType(X, Y, PageAbs, MouseEvent);
	}
	else
	{
		if (true === this.Footnotes.CheckHitInFootnote(X, Y, PageAbs))
			this.Footnotes.UpdateCursorType(X, Y, PageAbs, MouseEvent);
		else
			this.LogicDocumentController.UpdateCursorType(X, Y, PageAbs, MouseEvent);
	}

	this.Api.sync_MouseMoveEndCallback();
};
/**
 * Проверяем попадание в границу таблицы.
 * @param X
 * @param Y
 * @param PageIndex
 * @returns {?CTable} null - не попали, а если попали возвращается указатель на таблицу
 */
CDocument.prototype.IsTableBorder = function(X, Y, PageIndex)
{
	if (PageIndex >= this.Pages.length || PageIndex < 0)
		return null;

	if (docpostype_HdrFtr === this.Get_DocPosType())
	{
		return this.HdrFtr.IsTableBorder(X, Y, PageIndex);
	}
	else
	{
		if (-1 != this.DrawingObjects.IsInDrawingObject(X, Y, PageIndex, this))
		{
			return null;
		}
		else if (true === this.Footnotes.CheckHitInFootnote(X, Y, PageIndex))
		{
			return this.Footnotes.IsTableBorder(X, Y, PageIndex);
		}
		else
		{
			var ColumnsInfo      = {};
			var ElementPos       = this.Internal_GetContentPosByXY(X, Y, PageIndex, ColumnsInfo);
			var Element          = this.Content[ElementPos];
			var ElementPageIndex = this.private_GetElementPageIndex(ElementPos, PageIndex, ColumnsInfo.Column, ColumnsInfo.Column, ColumnsInfo.ColumnsCount);
			return Element.IsTableBorder(X, Y, ElementPageIndex);
		}
	}
};
/**
 * Проверяем, попали ли мы четко в текст (не лежащий в автофигуре)
 * @param X
 * @param Y
 * @param PageIndex
 * @returns {*}
 */
CDocument.prototype.IsInText = function(X, Y, PageIndex)
{
	if (PageIndex >= this.Pages.length || PageIndex < 0)
		return null;

	if (docpostype_HdrFtr === this.Get_DocPosType())
	{
		return this.HdrFtr.IsInText(X, Y, PageIndex);
	}
	else
	{
		if (true === this.Footnotes.CheckHitInFootnote(X, Y, PageIndex))
		{
			return this.Footnotes.IsInText(X, Y, PageIndex);
		}
		else
		{
			var ContentPos       = this.Internal_GetContentPosByXY(X, Y, PageIndex);
			var ElementPageIndex = this.private_GetElementPageIndexByXY(ContentPos, X, Y, PageIndex);
			var Item             = this.Content[ContentPos];
			return Item.IsInText(X, Y, ElementPageIndex);
		}
	}
};
CDocument.prototype.Get_ParentTextTransform = function()
{
	return null;
};
/**
 * Проверяем, попали ли мы в автофигуру данного DocumentContent
 * @param X
 * @param Y
 * @param PageIndex
 * @returns {*}
 */
CDocument.prototype.IsInDrawing = function(X, Y, PageIndex)
{
	if (docpostype_HdrFtr === this.Get_DocPosType())
	{
		return this.HdrFtr.IsInDrawing(X, Y, PageIndex);
	}
	else
	{
		if (-1 != this.DrawingObjects.IsInDrawingObject(X, Y, this.CurPage, this))
		{
			return true;
		}
		else if (true === this.Footnotes.CheckHitInFootnote(X, Y, PageIndex))
		{
			return this.Footnotes.IsInDrawing(X, Y, PageIndex);
		}
		else
		{
			var ContentPos       = this.Internal_GetContentPosByXY(X, Y, PageIndex);
			var Item             = this.Content[ContentPos];
			var ElementPageIndex = this.private_GetElementPageIndexByXY(ContentPos, X, Y, PageIndex);
			return Item.IsInDrawing(X, Y, ElementPageIndex);
		}
	}
};
CDocument.prototype.Is_UseInDocument = function(Id)
{
	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		if (Id === this.Content[Index].GetId())
			return true;
	}

	return false;
};
CDocument.prototype.OnKeyDown = function(e)
{
    var OldRecalcId = this.RecalcId;

    // Если мы только что расширяли документ двойным щелчком, то сохраняем это действие
    if (true === this.History.Is_ExtendDocumentToPos())
        this.History.Clear_Additional();

    // Сбрасываем текущий элемент в поиске
    if (this.SearchEngine.Count > 0)
        this.SearchEngine.Reset_Current();

    var bUpdateSelection = true;
    var bRetValue        = keydownresult_PreventNothing;

    if (e.KeyCode == 8) // BackSpace
    {
        if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Remove, null, true, this.IsFormFieldEditing()))
        {
            this.Create_NewHistoryPoint(AscDFH.historydescription_Document_BackSpaceButton);

            var oSelectInfo = this.GetSelectedElementsInfo();
            if (oSelectInfo.GetInlineLevelSdt())
			{
				var oSdt = oSelectInfo.GetInlineLevelSdt();
				var sDefaultText = AscCommon.translateManager.getValue('Your text here');
				var sText        = oSdt.GetSelectedText(true, false);

				oSdt.Remove(-1, false);
				if (oSdt.IsEmpty())
				{
					if (sText === sDefaultText)
					{
						oSdt.RemoveContentControlWrapper();
					}
					else
					{
						oSdt.ReplaceAllWithText(sDefaultText);
						oSdt.SelectAll();
						oSdt.SelectThisElement(1);
					}
				}

				this.Recalculate();

				this.Document_UpdateInterfaceState();
				this.Document_UpdateRulersState();
			}
			else
			{
				this.Remove(-1, true);
			}
        }
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 9) // Tab
    {
        var SelectedInfo = this.GetSelectedElementsInfo();

        if (null !== SelectedInfo.Get_Math())
        {
            var ParaMath  = SelectedInfo.Get_Math();
            var Paragraph = ParaMath.GetParagraph();
            if (Paragraph && false === this.Document_Is_SelectionLocked(changestype_None, {
                    Type      : changestype_2_Element_and_Type,
                    Element   : Paragraph,
                    CheckType : changestype_Paragraph_Content
                }))
            {
                this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddTabToMath);
                ParaMath.HandleTab(!e.ShiftKey);
                this.Recalculate();
            }
        }
        else if (true === SelectedInfo.Is_InTable() && true != e.CtrlKey)
        {
            this.MoveCursorToCell(true === e.ShiftKey ? false : true);
        }
        else if (true === SelectedInfo.Is_DrawingObjSelected() && true != e.CtrlKey)
        {
            this.DrawingObjects.selectNextObject(( e.ShiftKey === true ? -1 : 1 ));
        }
        else
        {
            if (true === SelectedInfo.Is_MixedSelection())
            {
                if (true === e.ShiftKey)
                    this.DecreaseIndent();
                else
                    this.IncreaseIndent();
            }
            else
            {
                var Paragraph = SelectedInfo.GetParagraph();
                var ParaPr    = Paragraph ? Paragraph.Get_CompiledPr2(false).ParaPr : null;
                if (null != Paragraph && ( true === Paragraph.IsCursorAtBegin() || true === Paragraph.Selection_IsFromStart() ) && ( undefined != Paragraph.GetNumPr() || ( true != Paragraph.IsEmpty() && ParaPr.Tabs.Tabs.length <= 0 ) ))
                {
                    if (false === this.Document_Is_SelectionLocked(changestype_None, {
                            Type      : changestype_2_Element_and_Type,
                            Element   : Paragraph,
                            CheckType : AscCommon.changestype_Paragraph_Properties
                        }))
                    {
                        this.Create_NewHistoryPoint(AscDFH.historydescription_Document_MoveParagraphByTab);
                        Paragraph.Add_Tab(e.ShiftKey);
                        this.Recalculate();

                        this.Document_UpdateInterfaceState();
                        this.Document_UpdateSelectionState();
                    }
                }
                else if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
                {
                    this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddTab);
                    this.AddToParagraph(new ParaTab());
                }
            }
        }
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 13) // Enter
    {
        var Hyperlink = this.IsCursorInHyperlink(false);
        if (null != Hyperlink && false === e.ShiftKey)
        {
			var sBookmarkName = Hyperlink.GetAnchor();
			var sValue        = Hyperlink.GetValue();

			if (Hyperlink.IsTopOfDocument())
			{
				this.MoveCursorToStartPos(false);
			}
			else if (sBookmarkName)
			{
				var oBookmark = this.BookmarksManager.GetBookmarkByName(sBookmarkName);
				if (oBookmark)
					oBookmark[0].GoToBookmark();
			}
			else if (sValue)
			{
				editor.sync_HyperlinkClickCallback(sValue);
				Hyperlink.SetVisited(true);

				// TODO: Пока сделаем так, потом надо будет переделать
				this.DrawingDocument.ClearCachePages();
				this.DrawingDocument.FirePaint();
			}
        }
        else
		{


			var oSelectedInfo = this.GetSelectedElementsInfo();
			var CheckType = ( e.ShiftKey || e.CtrlKey ? changestype_Paragraph_Content : AscCommon.changestype_Document_Content_Add );

			var bCanPerform = true;
			if ((oSelectedInfo.GetInlineLevelSdt() && (!e.ShiftKey || e.CtrlKey)) || (oSelectedInfo.Get_Field() && oSelectedInfo.Get_Field().IsFillingForm()))
				bCanPerform = false;

            if (bCanPerform && (docpostype_DrawingObjects === this.CurPos.Type ||
                (docpostype_HdrFtr === this.CurPos.Type && null != this.HdrFtr.CurHdrFtr && docpostype_DrawingObjects === this.HdrFtr.CurHdrFtr.Content.CurPos.Type )))
            {
                var oTargetDocContent = this.DrawingObjects.getTargetDocContent();
                if(!oTargetDocContent){
                    var nRet = this.DrawingObjects.handleEnter();
                    bCanPerform = (nRet === 0);
                }
            }
			if (bCanPerform && false === this.Document_Is_SelectionLocked(CheckType, null, false, true !== e.CtrlKey && this.IsFormFieldEditing()))
			{
				this.Create_NewHistoryPoint(AscDFH.historydescription_Document_EnterButton);

				var oMath = oSelectedInfo.Get_Math();
				if (null !== oMath && oMath.Is_InInnerContent())
				{
					if (oMath.Handle_AddNewLine())
						this.Recalculate();
				}
				else
				{
					if (e.ShiftKey && e.CtrlKey)
					{
						this.AddToParagraph(new ParaNewLine(break_Column));
					}
					else if (e.ShiftKey)
					{
						this.AddToParagraph(new ParaNewLine(break_Line));
					}
					else if (e.CtrlKey)
					{
						this.AddToParagraph(new ParaNewLine(break_Page));
					}
					else
					{
						this.AddNewParagraph();
					}
				}
			}
		}

        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 27) // Esc
    {
        // 1. Если начался drag-n-drop сбрасываем его.
        // 2. Если у нас сейчас происходит выделение маркером, тогда его отменяем
        // 3. Если у нас сейчас происходит форматирование по образцу, тогда его отменяем
        // 4. Если у нас выделена автофигура (в колонтитуле или документе), тогда снимаем выделение с нее
        // 5. Если мы просто находимся в колонтитуле (автофигура не выделена) выходим из колонтитула
        if (true === this.DrawingDocument.IsTrackText())
        {
            // Сбрасываем проверку Drag-n-Drop
            this.Selection.DragDrop.Flag = 0;
            this.Selection.DragDrop.Data = null;

            this.DrawingDocument.CancelTrackText();
        }
        else if (true === editor.isMarkerFormat)
        {
            editor.sync_MarkerFormatCallback(false);
            this.UpdateCursorType(this.CurPos.RealX, this.CurPos.RealY, this.CurPage, new AscCommon.CMouseEventHandler());
        }
        else if (c_oAscFormatPainterState.kOff !== editor.isPaintFormat)
        {
            editor.sync_PaintFormatCallback(c_oAscFormatPainterState.kOff);
            this.UpdateCursorType(this.CurPos.RealX, this.CurPos.RealY, this.CurPage, new AscCommon.CMouseEventHandler());
        }
        else if (editor.isStartAddShape)
        {
            editor.sync_StartAddShapeCallback(false);
            editor.sync_EndAddShape();
            this.UpdateCursorType(this.CurPos.RealX, this.CurPos.RealY, this.CurPage, new AscCommon.CMouseEventHandler());
        }
        else if (docpostype_DrawingObjects === this.CurPos.Type || (docpostype_HdrFtr === this.CurPos.Type && null != this.HdrFtr.CurHdrFtr && docpostype_DrawingObjects === this.HdrFtr.CurHdrFtr.Content.CurPos.Type ))
        {
        	this.EndDrawingEditing();
        }
        else if (docpostype_HdrFtr == this.CurPos.Type)
        {
            this.EndHdrFtrEditing(true);
        }

		if(window['AscCommon'].g_specialPasteHelper.showSpecialPasteButton)
		{
			window['AscCommon'].g_specialPasteHelper.SpecialPasteButton_Hide();
		}

        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 32) // Space
    {
    	var bFillingForm = false;
    	if (this.IsFormFieldEditing() && ((true === e.ShiftKey && true === e.CtrlKey) || true !== e.CtrlKey))
			bFillingForm = true;

        if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content, null, true, bFillingForm))
        {
            this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SpaceButton);

            // Если мы находимся в формуле, тогда пытаемся выполнить автозамену

            var oSelectedInfo = this.GetSelectedElementsInfo();
            var oMath         = oSelectedInfo.Get_Math();

            if (null !== oMath && true === oMath.Make_AutoCorrect())
            {
                // Ничего тут не делаем. Все делается в автозамене
            }
            else
            {
                if (true === e.ShiftKey && true === e.CtrlKey)
                {
                    this.DrawingDocument.TargetStart();
                    this.DrawingDocument.TargetShow();

                    this.AddToParagraph(new ParaText(0x00A0));
                }
                else if (true === e.CtrlKey)
                {
                    this.ClearParagraphFormatting(false, true);
                }
                else
                {
                    this.DrawingDocument.TargetStart();
                    this.DrawingDocument.TargetShow();

                    this.CheckLanguageOnTextAdd = true;
                    this.AddToParagraph(new ParaSpace());
                    this.CheckLanguageOnTextAdd = false;
                }
            }
        }

        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 33) // PgUp
    {
        if (true === e.AltKey)
        {
            var MouseEvent = new AscCommon.CMouseEventHandler();

            MouseEvent.ClickCount = 1;
            MouseEvent.Type       = AscCommon.g_mouse_event_type_down;

            this.CurPage--;

            if (this.CurPage < 0)
                this.CurPage = 0;

            this.Selection_SetStart(0, 0, MouseEvent);

            MouseEvent.Type = AscCommon.g_mouse_event_type_up;
            this.Selection_SetEnd(0, 0, MouseEvent);
        }
        else
        {
            if (docpostype_HdrFtr === this.CurPos.Type)
            {
                if (true === this.HdrFtr.GoTo_PrevHdrFtr())
                {
                    this.Document_UpdateSelectionState();
                    this.Document_UpdateInterfaceState();
                }
            }
            else
            {
            	if (this.Controller !== this.LogicDocumentController)
				{
					this.RemoveSelection();
					this.Set_DocPosType(docpostype_Content);
				}

            	this.MoveCursorPageUp(true === e.ShiftKey, true === e.CtrlKey);
            }
        }

		this.private_CheckCursorPosInFillingFormMode();
        this.CheckComplexFieldsInSelection();
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 34) // PgDn
    {
        if (true === e.AltKey)
        {
            var MouseEvent = new AscCommon.CMouseEventHandler();

            MouseEvent.ClickCount = 1;
            MouseEvent.Type       = AscCommon.g_mouse_event_type_down;

            this.CurPage++;

            // TODO: переделать данную проверку
            if (this.CurPage >= this.DrawingDocument.m_lPagesCount)
                this.CurPage = this.DrawingDocument.m_lPagesCount - 1;

            this.Selection_SetStart(0, 0, MouseEvent);

            MouseEvent.Type = AscCommon.g_mouse_event_type_up;
            this.Selection_SetEnd(0, 0, MouseEvent);
        }
        else
        {
            if (docpostype_HdrFtr === this.CurPos.Type)
            {
                if (true === this.HdrFtr.GoTo_NextHdrFtr())
                {
                    this.Document_UpdateSelectionState();
                    this.Document_UpdateInterfaceState();
                }
            }
            else
            {
				if (this.Controller !== this.LogicDocumentController)
				{
					this.RemoveSelection();
					this.Set_DocPosType(docpostype_Content);
				}

				this.MoveCursorPageDown(true === e.ShiftKey, true === e.CtrlKey);
            }
        }

		this.private_CheckCursorPosInFillingFormMode();
		this.CheckComplexFieldsInSelection();
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 35) // клавиша End
    {
        if (true === e.CtrlKey) // Ctrl + End - переход в конец документа
        {
            this.MoveCursorToEndPos(true === e.ShiftKey);
        }
        else // Переходим в конец строки
        {
            this.MoveCursorToEndOfLine(true === e.ShiftKey);
        }

        this.Document_UpdateInterfaceState();
        this.Document_UpdateRulersState();

		this.private_CheckCursorPosInFillingFormMode();
		this.CheckComplexFieldsInSelection();
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 36) // клавиша Home
    {
        if (true === e.CtrlKey) // Ctrl + Home - переход в начало документа
        {
            this.MoveCursorToStartPos(true === e.ShiftKey);
        }
        else // Переходим в начало строки
        {
            this.MoveCursorToStartOfLine(true === e.ShiftKey);
        }

        this.Document_UpdateInterfaceState();
        this.Document_UpdateRulersState();

		this.private_CheckCursorPosInFillingFormMode();
		this.CheckComplexFieldsInSelection();
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 37) // Left Arrow
    {
        // Чтобы при зажатой клавише курсор не пропадал
        if (true != e.ShiftKey)
            this.DrawingDocument.TargetStart();

        this.DrawingDocument.UpdateTargetFromPaint = true;
        this.MoveCursorLeft(true === e.ShiftKey, true === e.CtrlKey);
		this.private_CheckCursorPosInFillingFormMode();
		this.CheckComplexFieldsInSelection();
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 38) // Top Arrow
    {
        // TODO: Реализовать Ctrl + Up/ Ctrl + Shift + Up
        // Чтобы при зажатой клавише курсор не пропадал
        if (true != e.ShiftKey)
            this.DrawingDocument.TargetStart();

        this.DrawingDocument.UpdateTargetFromPaint = true;
        this.MoveCursorUp(true === e.ShiftKey, true === e.CtrlKey);
		this.private_CheckCursorPosInFillingFormMode();
		this.CheckComplexFieldsInSelection();
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 39) // Right Arrow
    {
        // Чтобы при зажатой клавише курсор не пропадал
        if (true != e.ShiftKey)
            this.DrawingDocument.TargetStart();

        this.DrawingDocument.UpdateTargetFromPaint = true;
        this.MoveCursorRight(true === e.ShiftKey, true === e.CtrlKey);
		this.private_CheckCursorPosInFillingFormMode();
		this.CheckComplexFieldsInSelection();
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 40) // Bottom Arrow
    {
        // TODO: Реализовать Ctrl + Down/ Ctrl + Shift + Down
        // Чтобы при зажатой клавише курсор не пропадал
        if (true != e.ShiftKey)
            this.DrawingDocument.TargetStart();

        this.DrawingDocument.UpdateTargetFromPaint = true;
        this.MoveCursorDown(true === e.ShiftKey, true === e.CtrlKey);
		this.private_CheckCursorPosInFillingFormMode();
		this.CheckComplexFieldsInSelection();
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 46) // Delete
    {
        if (true != e.ShiftKey)
        {
            if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Delete, null, true, this.IsFormFieldEditing()))
            {
                this.Create_NewHistoryPoint(AscDFH.historydescription_Document_DeleteButton);

				var oSelectInfo = this.GetSelectedElementsInfo();
				if (oSelectInfo.GetInlineLevelSdt())
				{
					var oSdt = oSelectInfo.GetInlineLevelSdt();
					var sDefaultText = AscCommon.translateManager.getValue('Your text here');
					var sText        = oSdt.GetSelectedText(true, false);

					oSdt.Remove(1, false);
					if (oSdt.IsEmpty())
					{
						if (sText === sDefaultText)
						{
							oSdt.RemoveContentControlWrapper();
						}
						else
						{
							oSdt.ReplaceAllWithText(sDefaultText);
							oSdt.SelectAll();
							oSdt.SelectThisElement(1);
						}
					}

					this.Recalculate();

					this.Document_UpdateInterfaceState();
					this.Document_UpdateRulersState();
				}
				else
				{
					this.Remove(1, true);
				}
            }
            bRetValue = keydownresult_PreventAll;
        }
    }
    else if (e.KeyCode == 49 && true === e.AltKey && !e.AltGr) // Alt + Ctrl + Num1 - применяем стиль Heading1
    {
        if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Paragraph_Properties))
        {
            this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetStyleHeading1);
            this.SetParagraphStyle("Heading 1");
            this.Document_UpdateInterfaceState();
        }
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 50 && true === e.AltKey && !e.AltGr) // Alt + Ctrl + Num2 - применяем стиль Heading2
    {
        if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Paragraph_Properties))
        {
            this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetStyleHeading2);
            this.SetParagraphStyle("Heading 2");
            this.Document_UpdateInterfaceState();
        }
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 51 && true === e.AltKey && !e.AltGr) // Alt + Ctrl + Num3 - применяем стиль Heading3
    {
        if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Paragraph_Properties))
        {
            this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetStyleHeading3);
            this.SetParagraphStyle("Heading 3");
            this.Document_UpdateInterfaceState();
        }
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode === 53 && true === e.CtrlKey) // Ctrl + Num5 - зачеркиваем текст
    {
        var TextPr = this.GetCalculatedTextPr();
        if (null != TextPr)
        {
            if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
            {
                this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetTextStrikeoutHotKey);
                this.AddToParagraph(new ParaTextPr({Strikeout : TextPr.Strikeout === true ? false : true}));
                this.Document_UpdateInterfaceState();
            }
            bRetValue = keydownresult_PreventAll;
        }
    }
    else if (e.KeyCode === 56 && true === e.CtrlKey && true === e.ShiftKey) // Ctrl + Shift + Num8 показать/скрыть невидимые символы
	{
		var isShow = this.Api.get_ShowParaMarks();
		this.Api.put_ShowParaMarks(!isShow);
		this.Api.sync_ShowParaMarks();
		bRetValue = keydownresult_PreventAll;
	}
    else if (e.KeyCode == 65 && true === e.CtrlKey) // Ctrl + A - выделяем все
    {
        this.SelectAll();
        bUpdateSelection = false;
        bRetValue        = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 66 && true === e.CtrlKey) // Ctrl + B - делаем текст жирным
    {
        var TextPr = this.GetCalculatedTextPr();
        if (null != TextPr)
        {
            if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
            {
                this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetTextBoldHotKey);
                this.AddToParagraph(new ParaTextPr({Bold : TextPr.Bold === true ? false : true}));
                this.Document_UpdateInterfaceState();
            }
            bRetValue = keydownresult_PreventAll;
        }
    }
    else if (e.KeyCode == 67 && true === e.CtrlKey) // Ctrl + C + ...
    {
        if (true === e.ShiftKey) // Ctrl + Shift + C - копирование форматирования текста
        {
            this.Document_Format_Copy();
            bRetValue = keydownresult_PreventAll;
        }
    }
    else if (e.KeyCode == 69 && true === e.CtrlKey) // Ctrl + E + ...
    {
        if (true !== e.AltKey) // Ctrl + E - переключение прилегания параграфа между center и left
        {
            this.private_ToggleParagraphAlignByHotkey(AscCommon.align_Center);
            bRetValue = keydownresult_PreventAll;
        }
        else // Ctrl + Alt + E - добавляем знак евро €
        {
            if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
            {
                this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddEuroLetter);

                this.DrawingDocument.TargetStart();
                this.DrawingDocument.TargetShow();
                this.AddToParagraph(new ParaText(0x20AC));
            }
            bRetValue = keydownresult_PreventAll;
        }
    }
	else if (e.KeyCode == 70 && true === e.CtrlKey) // Ctrl + F + ...
	{
		if (true === e.AltKey)
		{
			this.AddFootnote();
			bRetValue = keydownresult_PreventAll;
		}
	}
    else if (e.KeyCode == 73 && true === e.CtrlKey) // Ctrl + I - делаем текст наклонным
    {
        var TextPr = this.GetCalculatedTextPr();
        if (null != TextPr)
        {
            if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
            {
                this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetTextItalicHotKey);
                this.AddToParagraph(new ParaTextPr({Italic : TextPr.Italic === true ? false : true}));
                this.Document_UpdateInterfaceState();
            }
            bRetValue = keydownresult_PreventAll;
        }
    }
    else if (e.KeyCode == 74 && true === e.CtrlKey) // Ctrl + J переключение прилегания параграфа между justify и left
    {
        this.private_ToggleParagraphAlignByHotkey(AscCommon.align_Justify);
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 75 && true === e.CtrlKey && false === e.ShiftKey) // Ctrl + K - добавление гиперссылки
    {
        if (true === this.CanAddHyperlink(false) && this.CanEdit())
            this.Api.sync_DialogAddHyperlink();

        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 76 && true === e.CtrlKey) // Ctrl + L + ...
    {
        if (true === e.ShiftKey) // Ctrl + Shift + L - добавляем список к данному параграфу
        {
            if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
            {
                this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetParagraphNumberingHotKey);
                this.SetParagraphNumbering({Type : 0, SubType : 1});
                this.Document_UpdateInterfaceState();
            }
            bRetValue = keydownresult_PreventAll;
        }
        else // Ctrl + L - переключение прилегания параграфа между left и justify
        {
            this.private_ToggleParagraphAlignByHotkey(align_Left);
            bRetValue = keydownresult_PreventAll;
        }
    }
    else if (e.KeyCode == 77 && true === e.CtrlKey) // Ctrl + M + ...
    {
        if (true === e.ShiftKey) // Ctrl + Shift + M - уменьшаем левый отступ
            this.DecreaseIndent();
        else // Ctrl + M - увеличиваем левый отступ
            this.IncreaseIndent();

        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 80 && true === e.CtrlKey) // Ctrl + P + ...
    {
        if (true === e.ShiftKey) // Ctrl + Shift + P - добавляем номер страницы в текущую позицию
        {
            if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
            {
                this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddPageNumHotKey);
                this.AddToParagraph(new ParaPageNum());
            }
            bRetValue = keydownresult_PreventAll;
        }
        else // Ctrl + P - print
        {
            this.DrawingDocument.m_oWordControl.m_oApi.onPrint();
            bRetValue = keydownresult_PreventAll;
        }
    }
    else if (e.KeyCode == 82 && true === e.CtrlKey) // Ctrl + R - переключение прилегания параграфа между right и left
    {
        this.private_ToggleParagraphAlignByHotkey(AscCommon.align_Right);
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 83 && false === this.IsViewMode() && true === e.CtrlKey) // Ctrl + S - save
    {
		this.Api.asc_Save(false);
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 85 && true === e.CtrlKey) // Ctrl + U - делаем текст подчеркнутым
    {
        var TextPr = this.GetCalculatedTextPr();
        if (null != TextPr)
        {
            if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
            {
                this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetTextUnderlineHotKey);
                this.AddToParagraph(new ParaTextPr({Underline : TextPr.Underline === true ? false : true}));
                this.Document_UpdateInterfaceState();
            }
            bRetValue = keydownresult_PreventAll;
        }
    }
	else if (e.KeyCode == 86 && true === e.CtrlKey) // Ctrl + V
	{
		if (true === e.ShiftKey) // Ctrl + Shift + V - вставка форматирования текста
		{
			if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
			{
				this.Create_NewHistoryPoint(AscDFH.historydescription_Document_FormatPasteHotKey);
				this.Document_Format_Paste();
			}
			bRetValue = keydownresult_PreventAll;
		}
	}
    else if (e.KeyCode == 89 && true === e.CtrlKey && (this.CanEdit() || this.IsEditCommentsMode() || this.IsFillingFormMode())) // Ctrl + Y - Redo
    {
        this.Document_Redo();
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 90 && true === e.CtrlKey && (this.CanEdit() || this.IsEditCommentsMode() || this.IsFillingFormMode())) // Ctrl + Z - Undo
    {
       	this.Document_Undo();
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 93 || 57351 == e.KeyCode /*в Opera такой код*/) // контекстное меню
    {
        var X_abs, Y_abs, oPosition, ConvertedPos;
        if (this.DrawingObjects.selectedObjects.length > 0)
        {
            oPosition    = this.DrawingObjects.getContextMenuPosition(this.CurPage);
            ConvertedPos = this.DrawingDocument.ConvertCoordsToCursorWR(oPosition.X, oPosition.Y, oPosition.PageIndex);
        }
        else
        {
            ConvertedPos = this.DrawingDocument.ConvertCoordsToCursorWR(this.TargetPos.X, this.TargetPos.Y, this.TargetPos.PageNum);
        }
        X_abs = ConvertedPos.X;
        Y_abs = ConvertedPos.Y;

        editor.sync_ContextMenuCallback({Type : Asc.c_oAscContextMenuTypes.Common, X_abs : X_abs, Y_abs : Y_abs});

        bUpdateSelection = false;
        bRetValue        = keydownresult_PreventAll;
    }
	// else if (e.KeyCode === 112 && true === e.CtrlKey)
	// {
	// 	// TODO: Добавлено для теста
	// 	//
	// 	// this.Create_NewHistoryPoint();
	// 	// this.AddField(fieldtype_TOC);
	// 	// this.Recalculate();
	//
	// 	this.ContinueNumbering();
	//
	// 	bRetValue = keydownresult_PreventAll;
	// }
	// else if (e.KeyCode === 113 && true === e.CtrlKey)
	// {
	// 	// TODO: Добавлено для теста
	// 	// var arrFields = this.GetComplexFieldsByContentPos(this.GetContentPosition(false));
	// 	// if (arrFields && arrFields.length > 0)
	// 	// 	this.UpdateComplexField(arrFields[arrFields.length - 1]);
	//
	// 	this.RestartNumbering(3);
	//
	// 	bRetValue = keydownresult_PreventAll;
	// }
	// else if (e.KeyCode === 114 && true === e.CtrlKey)
	// {
	// 	this.Create_NewHistoryPoint();
	// 	this.AddField(fieldtype_PAGEREF);
	// 	this.Recalculate();
	//
	// 	bRetValue = keydownresult_PreventAll;
	// }
	else if (e.KeyCode == 121 && true === e.ShiftKey) // Shift + F10 - контекстное меню
    {
        var X_abs, Y_abs, oPosition, ConvertedPos;
        if (this.DrawingObjects.selectedObjects.length > 0)
        {
            oPosition    = this.DrawingObjects.getContextMenuPosition(this.CurPage);
            ConvertedPos = this.DrawingDocument.ConvertCoordsToCursorWR(oPosition.X, oPosition.Y, oPosition.PageIndex);
        }
        else
        {
            ConvertedPos = this.DrawingDocument.ConvertCoordsToCursorWR(this.TargetPos.X, this.TargetPos.Y, this.TargetPos.PageNum);
        }
        X_abs = ConvertedPos.X;
        Y_abs = ConvertedPos.Y;

        editor.sync_ContextMenuCallback({Type : Asc.c_oAscContextMenuTypes.Common, X_abs : X_abs, Y_abs : Y_abs});

        bUpdateSelection = false;
        bRetValue        = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 144) // Num Lock
    {
        // Ничего не делаем
        bUpdateSelection = false;
        bRetValue        = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 145) // Scroll Lock
    {
        // Ничего не делаем
        bUpdateSelection = false;
        bRetValue        = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 187) // =
    {
        if (!e.CtrlKey && true === e.AltKey && !e.AltGr) // Alt + =
        {
            var oSelectedInfo = this.GetSelectedElementsInfo();
            var oMath         = oSelectedInfo.Get_Math();
            if (null === oMath)
            {
                if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
                {
                    this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddMathHotKey);
                    this.AddToParagraph(new MathMenu(-1));
                    bRetValue = keydownresult_PreventAll;
                }
            }
        }
    }
    else if (e.KeyCode == 188 && true === e.CtrlKey) // Ctrl + ,
    {
        var TextPr = this.GetCalculatedTextPr();
        if (null != TextPr)
        {
            if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
            {
                this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetTextVertAlignHotKey2);
                this.AddToParagraph(new ParaTextPr({VertAlign : TextPr.VertAlign === AscCommon.vertalign_SuperScript ? AscCommon.vertalign_Baseline : AscCommon.vertalign_SuperScript}));
                this.Document_UpdateInterfaceState();
            }
            bRetValue = keydownresult_PreventAll;
        }
    }
    else if (e.KeyCode == 189) // Клавиша Num-
    {
        if (true === e.CtrlKey && true === e.ShiftKey && false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content, null, true))
        {
            this.Create_NewHistoryPoint(AscDFH.historydescription_Document_MinusButton);

            this.DrawingDocument.TargetStart();
            this.DrawingDocument.TargetShow();

            var Item = new ParaText(0x002D);
            Item.Set_SpaceAfter(false);

            this.AddToParagraph(Item);
            bRetValue = keydownresult_PreventAll;
        }
    }
    else if (e.KeyCode == 190 && true === e.CtrlKey) // Ctrl + .
    {
        var TextPr = this.GetCalculatedTextPr();
        if (null != TextPr)
        {
            if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
            {
                this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetTextVertAlignHotKey3);
                this.AddToParagraph(new ParaTextPr({VertAlign : TextPr.VertAlign === AscCommon.vertalign_SubScript ? AscCommon.vertalign_Baseline : AscCommon.vertalign_SubScript}));
                this.Document_UpdateInterfaceState();
            }
            bRetValue = keydownresult_PreventAll;
        }
    }
    else if (e.KeyCode == 219 && true === e.CtrlKey) // Ctrl + [
    {
    	this.Api.FontSizeOut();
        this.Document_UpdateInterfaceState();
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 221 && true === e.CtrlKey) // Ctrl + ]
    {
        this.Api.FontSizeIn();
        this.Document_UpdateInterfaceState();
        bRetValue = keydownresult_PreventAll;
    }
    else if (e.KeyCode == 12288) // Space
    {
        if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content, null, true, this.IsFormFieldEditing()))
        {
            this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SpaceButton);

            this.DrawingDocument.TargetStart();
            this.DrawingDocument.TargetShow();

            this.CheckLanguageOnTextAdd = true;
            this.AddToParagraph(new ParaSpace());
            this.CheckLanguageOnTextAdd = false;
        }

        bRetValue = keydownresult_PreventAll;
    }

    // Если был пересчет, значит были изменения, а вместе с ними пересылается и новая позиция курсора
    if (bRetValue & keydownresult_PreventKeyPress && OldRecalcId === this.RecalcId)
        this.private_UpdateTargetForCollaboration();

    if (bRetValue & keydownflags_PreventKeyPress && true === bUpdateSelection)
        this.Document_UpdateSelectionState();

    return bRetValue;
};
CDocument.prototype.OnKeyPress = function(e)
{
	var Code;
	if (null != e.Which)
		Code = e.Which;
	else if (e.KeyCode)
		Code = e.KeyCode;
	else
		Code = 0;//special char

	var bRetValue = false;

	if (Code > 0x20)
	{
		if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Paragraph_AddText, null, true, this.IsFormFieldEditing()))
		{
			this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddLetter);

			this.DrawingDocument.TargetStart();
			this.DrawingDocument.TargetShow();

			this.CheckLanguageOnTextAdd = true;
			this.AddToParagraph(new ParaText(Code));
			this.CheckLanguageOnTextAdd = false;
		}
		bRetValue = true;
	}

	if (true == bRetValue)
		this.Document_UpdateSelectionState();

	return bRetValue;
};
CDocument.prototype.OnMouseDown = function(e, X, Y, PageIndex)
{
	if (PageIndex < 0)
		return;

	this.private_UpdateTargetForCollaboration();

	// Сбрасываем проверку Drag-n-Drop
	this.Selection.DragDrop.Flag = 0;
	this.Selection.DragDrop.Data = null;

	// Сбрасываем текущий элемент в поиске
	if (this.SearchEngine.Count > 0)
		this.SearchEngine.Reset_Current();

	// Обработка правой кнопки мыши происходит на событии MouseUp
	if (AscCommon.g_mouse_button_right === e.Button)
		return;

	// Если мы только что расширяли документ двойным щелчком, то отменяем это действие
	if (true === this.History.Is_ExtendDocumentToPos())
	{
		this.Document_Undo();

		// Заглушка на случай "неудачного" пересчета, когда после него страниц меньше, чем ту, по которое мы кликаем
		if (PageIndex >= this.Pages.length)
		{
			this.RemoveSelection();
			return;
		}
	}

	var OldCurPage = this.CurPage;
	this.CurPage   = PageIndex;

	if (true === editor.isStartAddShape && (docpostype_HdrFtr !== this.CurPos.Type || null !== this.HdrFtr.CurHdrFtr))
	{
		if (docpostype_HdrFtr !== this.CurPos.Type)
		{
			this.Set_DocPosType(docpostype_DrawingObjects);
			this.Selection.Use   = true;
			this.Selection.Start = true;
		}
		else
		{
			this.Selection.Use   = true;
			this.Selection.Start = true;

			this.HdrFtr.WaitMouseDown = false;
			var CurHdrFtr             = this.HdrFtr.CurHdrFtr;
			var DocContent            = CurHdrFtr.Content;

			DocContent.Set_DocPosType(docpostype_DrawingObjects);
			DocContent.Selection.Use   = true;
			DocContent.Selection.Start = true;
		}

		if (true != this.DrawingObjects.isPolylineAddition())
			this.DrawingObjects.startAddShape(editor.addShapePreset);

		this.DrawingObjects.OnMouseDown(e, X, Y, this.CurPage);
	}
	else
	{
		if (true === e.ShiftKey &&
			( (docpostype_DrawingObjects !== this.CurPos.Type && !(docpostype_HdrFtr === this.CurPos.Type && this.HdrFtr.CurHdrFtr && this.HdrFtr.CurHdrFtr.Content.CurPos.Type === docpostype_DrawingObjects))
			|| true === this.DrawingObjects.checkTextObject(X, Y, PageIndex) ))
		{
			if (true === this.IsSelectionUse())
				this.Selection.Start = false;
			else
				this.StartSelectionFromCurPos();

			this.Selection_SetEnd(X, Y, e);
			this.Document_UpdateSelectionState();
			return;
		}

		this.Selection_SetStart(X, Y, e);

		if (e.ClickCount <= 1 && 1 !== this.Selection.DragDrop.Flag)
		{
			this.RecalculateCurPos();
			this.Document_UpdateSelectionState();
		}
	}
};
CDocument.prototype.OnMouseUp = function(e, X, Y, PageIndex)
{
	if (PageIndex < 0)
		return;

	this.private_UpdateTargetForCollaboration();

	if (1 === this.Selection.DragDrop.Flag)
	{
		this.Selection.DragDrop.Flag = -1;
		var OldCurPage               = this.CurPage;
		this.CurPage                 = this.Selection.DragDrop.Data.PageNum;
		this.Selection_SetStart(this.Selection.DragDrop.Data.X, this.Selection.DragDrop.Data.Y, e);
		this.Selection.DragDrop.Flag = 0;
		this.Selection.DragDrop.Data = null;
	}

	// Если мы нажимали правую кнопку мыши, тогда нам надо сделать
	if (AscCommon.g_mouse_button_right === e.Button)
	{
		if (true === this.Selection.Start)
			return;

		var ConvertedPos = this.DrawingDocument.ConvertCoordsToCursorWR(X, Y, PageIndex);
		var X_abs        = ConvertedPos.X;
		var Y_abs        = ConvertedPos.Y;

		// Проверим попадание в значок таблицы, если в него попадаем, тогда выделяем таблицу
		if (true === this.DrawingDocument.IsCursorInTableCur(X, Y, PageIndex))
		{
			var Table = this.DrawingDocument.TableOutlineDr.TableOutline.Table;
			Table.SelectAll();
			Table.Document_SetThisElementCurrent(false);
			this.Document_UpdateSelectionState();
			this.Document_UpdateInterfaceState();
			editor.sync_ContextMenuCallback({Type : Asc.c_oAscContextMenuTypes.Common, X_abs : X_abs, Y_abs : Y_abs});
			return;
		}

		// Сначала проверим попадание в Flow-таблицы и автофигуры
		var pFlowTable = this.DrawingObjects.getTableByXY(X, Y, PageIndex, this);
		var nInDrawing = this.DrawingObjects.IsInDrawingObject(X, Y, PageIndex, this);

		if (docpostype_HdrFtr != this.CurPos.Type && -1 === nInDrawing && null === pFlowTable)
		{
			var PageMetrics = this.Get_PageContentStartPos(this.CurPage, this.Pages[this.CurPage].Pos);
			// Проверяем, не попали ли мы в колонтитул
			if (Y <= PageMetrics.Y)
			{
				editor.sync_ContextMenuCallback({
					Type    : Asc.c_oAscContextMenuTypes.ChangeHdrFtr,
					X_abs   : X_abs,
					Y_abs   : Y_abs,
					Header  : true,
					PageNum : PageIndex
				});
				return;
			}
			else if (Y > PageMetrics.YLimit)
			{
				editor.sync_ContextMenuCallback({
					Type    : Asc.c_oAscContextMenuTypes.ChangeHdrFtr,
					X_abs   : X_abs,
					Y_abs   : Y_abs,
					Header  : false,
					PageNum : PageIndex
				});
				return;
			}
		}

		// Проверяем попалили мы в селект
		if (false === this.CheckPosInSelection(X, Y, PageIndex, undefined))
		{
			this.CurPage = PageIndex;

			var MouseEvent_new =
				{
					// TODO : Если в MouseEvent будет использоваться что-то кроме ClickCount, Type и CtrlKey, добавить здесь
					ClickCount : 1,
					Type       : AscCommon.g_mouse_event_type_down,
					CtrlKey    : false,
					Button     : AscCommon.g_mouse_button_right
				};
			this.Selection_SetStart(X, Y, MouseEvent_new);

			MouseEvent_new.Type = AscCommon.g_mouse_event_type_up;
			this.Selection_SetEnd(X, Y, MouseEvent_new);

			this.Document_UpdateSelectionState();
			this.Document_UpdateRulersState();
			this.Document_UpdateInterfaceState();
		}

		editor.sync_ContextMenuCallback({Type : Asc.c_oAscContextMenuTypes.Common, X_abs : X_abs, Y_abs : Y_abs});
		this.private_UpdateCursorXY(true, true);

		return;
	}
	else if (AscCommon.g_mouse_button_left === e.Button)
	{
		if (true === this.Comments.Is_Use())
		{
			var Type = ( docpostype_HdrFtr === this.CurPos.Type ? comment_type_HdrFtr : comment_type_Common );

			// Проверяем не попали ли мы в комментарий
			var arrComments = this.Comments.Get_ByXY(PageIndex, X, Y, Type);

			var CommentsX     = null;
			var CommentsY     = null;
			var arrCommentsId = [];

			for (var nCommentIndex = 0, nCommentsCount = arrComments.length; nCommentIndex < nCommentsCount; ++nCommentIndex)
			{
				var Comment = arrComments[nCommentIndex];
				if (null != Comment && (this.Comments.IsUseSolved() || !Comment.IsSolved()))
				{
					if (null === CommentsX)
					{
						var Comment_PageNum = Comment.m_oStartInfo.PageNum;
						var Comment_Y       = Comment.m_oStartInfo.Y;
						var Comment_X       = this.Get_PageLimits(PageIndex).XLimit;
						var Para            = this.TableId.Get_ById(Comment.StartId);

						// Para может быть не задано, если комментарий добавлен к заголовку таблицы
						if (Para)
						{
							var TextTransform = Para.Get_ParentTextTransform();
							if (TextTransform)
							{
								Comment_Y = TextTransform.TransformPointY(Comment.m_oStartInfo.X, Comment.m_oStartInfo.Y);
							}

							var Coords = this.DrawingDocument.ConvertCoordsToCursorWR(Comment_X, Comment_Y, Comment_PageNum);
							this.SelectComment(Comment.Get_Id(), false);

							CommentsX = Coords.X;
							CommentsY = Coords.Y;
						}
					}

					arrCommentsId.push(Comment.Get_Id());
				}
			}

			if (null !== CommentsX && null !== CommentsY && arrCommentsId.length > 0)
			{
				this.Api.sync_ShowComment(arrCommentsId, CommentsX, CommentsY);
			}
			else
			{
				this.SelectComment(null, false);
				this.Api.sync_HideComment();
			}
		}
	}

	if (true === this.Selection.Start)
	{
		this.CurPage         = PageIndex;
		this.Selection.Start = false;
		this.Selection_SetEnd(X, Y, e);
		this.CheckComplexFieldsInSelection();
		this.Document_UpdateSelectionState();

		if (c_oAscFormatPainterState.kOff !== editor.isPaintFormat)
		{
			if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
			{
				this.Create_NewHistoryPoint(AscDFH.historydescription_Document_FormatPasteHotKey2);
				this.Document_Format_Paste();
			}

			if (c_oAscFormatPainterState.kOn === editor.isPaintFormat)
				editor.sync_PaintFormatCallback(c_oAscFormatPainterState.kOff);
		}
		else if (true === editor.isMarkerFormat && true === this.IsTextSelectionUse())
		{
			if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
			{
				this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetTextHighlight2);
				var ParaItem = null;
				if (this.HighlightColor != highlight_None)
				{
					var TextPr = this.GetCalculatedTextPr();
					if ("undefined" === typeof( TextPr.HighLight ) || null === TextPr.HighLight || highlight_None === TextPr.HighLight ||
						this.HighlightColor.r != TextPr.HighLight.r || this.HighlightColor.g != TextPr.HighLight.g || this.HighlightColor.b != TextPr.HighLight.b)
						ParaItem = new ParaTextPr({HighLight : this.HighlightColor});
					else
						ParaItem = new ParaTextPr({HighLight : highlight_None});
				}
				else
					ParaItem = new ParaTextPr({HighLight : this.HighlightColor});

				this.AddToParagraph(ParaItem);
				this.MoveCursorToXY(X, Y, false);
				this.Document_UpdateSelectionState();

				editor.sync_MarkerFormatCallback(true);
			}
		}
	}

	this.private_CheckCursorPosInFillingFormMode();

	this.private_UpdateCursorXY(true, true);
};
CDocument.prototype.OnMouseMove = function(e, X, Y, PageIndex)
{
	if (PageIndex < 0)
		return;

	if (true === this.Selection.Start)
		this.private_UpdateTargetForCollaboration();

	this.UpdateCursorType(X, Y, PageIndex, e);
	this.CollaborativeEditing.Check_ForeignCursorsLabels(X, Y, PageIndex);

	if (1 === this.Selection.DragDrop.Flag)
	{
		// Если курсор не изменил позицию, тогда ничего не делаем, а если изменил, тогда стартуем Drag-n-Drop
		if (Math.abs(this.Selection.DragDrop.Data.X - X) > 0.001 || Math.abs(this.Selection.DragDrop.Data.Y - Y) > 0.001)
		{
			this.Selection.DragDrop.Flag = 0;
			this.Selection.DragDrop.Data = null;

			// Вызываем стандартное событие mouseMove, чтобы сбросить различные подсказки, если они были
			this.Api.sync_MouseMoveStartCallback();
			this.Api.sync_MouseMoveCallback(new AscCommon.CMouseMoveData());
			this.Api.sync_MouseMoveEndCallback();

			this.DrawingDocument.StartTrackText();
		}

		return;
	}

	if (true === this.Selection.Use && true === this.Selection.Start)
	{
		this.CurPage = PageIndex;
		this.Selection_SetEnd(X, Y, e);
		this.Document_UpdateSelectionState();
	}
};
/**
 * Проверяем будет ли добавление текста на ивенте KeyDown
 * @param e
 * @returns {Number[]} Массив юникодных значений
 */
CDocument.prototype.GetAddedTextOnKeyDown = function(e)
{
	if (e.KeyCode === 32) // Space
	{
		var oSelectedInfo = this.GetSelectedElementsInfo();
		var oMath         = oSelectedInfo.Get_Math();

		if (!oMath)
		{
			if (true === e.ShiftKey && true === e.CtrlKey)
				return [0x00A0];
		}
	}
	else if (e.KeyCode == 69 && true === e.CtrlKey) // Ctrl + E + ...
	{
		if (true === e.AltKey) // Ctrl + Alt + E - добавляем знак евро €
			return [0x20AC];
	}
	else if (e.KeyCode == 189) // Клавиша Num-
	{
		if (true === e.CtrlKey && true === e.ShiftKey)
			return [0x2013];
	}

	return [];
};
CDocument.prototype.Get_Numbering = function()
{
	return this.Numbering;
};
CDocument.prototype.GetNumbering = function()
{
	return this.Numbering;
};
CDocument.prototype.Get_Styles = function()
{
	return this.Styles;
};
/**
 * Получаем ссылку на объект, работающий со стилями
 * @returns {CStyles}
 */
CDocument.prototype.GetStyles = function()
{
	return this.Styles;
};
CDocument.prototype.CopyStyle = function()
{
	return this.Styles.CopyStyle();
};
CDocument.prototype.Get_TableStyleForPara = function()
{
	return null;
};
CDocument.prototype.Get_ShapeStyleForPara = function()
{
	return null;
};
CDocument.prototype.Get_TextBackGroundColor = function()
{
	return undefined;
};
CDocument.prototype.Select_DrawingObject = function(Id)
{
	this.RemoveSelection();

	// Прячем курсор
	this.DrawingDocument.TargetEnd();
	this.DrawingDocument.SetCurrentPage(this.CurPage);

	this.Selection.Start = false;
	this.Selection.Use   = true;
	this.Set_DocPosType(docpostype_DrawingObjects);
	this.DrawingObjects.selectById(Id, this.CurPage);

	this.Document_UpdateInterfaceState();
	this.Document_UpdateSelectionState();
};
/**
 * Получем ближайшую возможную позицию курсора.
 * @param PageNum
 * @param X
 * @param Y
 * @param bAnchor
 * @param Drawing
 * @returns {*}
 */
CDocument.prototype.Get_NearestPos = function(PageNum, X, Y, bAnchor, Drawing)
{
	if (undefined === bAnchor)
		bAnchor = false;

	if (docpostype_HdrFtr === this.Get_DocPosType())
		return this.HdrFtr.Get_NearestPos(PageNum, X, Y, bAnchor, Drawing);

	var bInText    = (null === this.IsInText(X, Y, PageNum) ? false : true);
	var nInDrawing = this.DrawingObjects.IsInDrawingObject(X, Y, PageNum, this);

	if (true != bAnchor)
	{
		// Проверяем попадание в графические объекты
		var NearestPos = this.DrawingObjects.getNearestPos(X, Y, PageNum, Drawing);
		if (( nInDrawing === DRAWING_ARRAY_TYPE_BEFORE || nInDrawing === DRAWING_ARRAY_TYPE_INLINE || ( false === bInText && nInDrawing >= 0 ) ) && null != NearestPos)
			return NearestPos;

		NearestPos = true === this.Footnotes.CheckHitInFootnote(X, Y, PageNum) ? this.Footnotes.GetNearestPos(X, Y, PageNum, false, Drawing) : null;
		if (null !== NearestPos)
			return NearestPos;
	}

	var ContentPos = this.Internal_GetContentPosByXY(X, Y, PageNum);

	// Делаем логику как в ворде
	if (true === bAnchor && ContentPos > 0 && PageNum > 0 && ContentPos === this.Pages[PageNum].Pos && ContentPos === this.Pages[PageNum - 1].EndPos && this.Pages[PageNum].EndPos > this.Pages[PageNum].Pos && type_Paragraph === this.Content[ContentPos].GetType() && true === this.Content[ContentPos].IsContentOnFirstPage())
		ContentPos++;

	var ElementPageIndex = this.private_GetElementPageIndexByXY(ContentPos, X, Y, PageNum);
	return this.Content[ContentPos].GetNearestPos(ElementPageIndex, X, Y, bAnchor, Drawing);
};
CDocument.prototype.Internal_Content_Add = function(Position, NewObject, bCheckLastElement)
{
	// Position = this.Content.length  допускается
	if (Position < 0 || Position > this.Content.length)
		return;

	var PrevObj = this.Content[Position - 1] ? this.Content[Position - 1] : null;
	var NextObj = this.Content[Position] ? this.Content[Position] : null;

	this.private_RecalculateNumbering([NewObject]);
	this.History.Add(new CChangesDocumentAddItem(this, Position, [NewObject]));
	this.Content.splice(Position, 0, NewObject);
	NewObject.Set_Parent(this);
	NewObject.Set_DocumentNext(NextObj);
	NewObject.Set_DocumentPrev(PrevObj);

	if (null != PrevObj)
		PrevObj.Set_DocumentNext(NewObject);

	if (null != NextObj)
		NextObj.Set_DocumentPrev(NewObject);

	// Обновим информацию о секциях
	this.SectionsInfo.Update_OnAdd(Position, [NewObject]);

	// Проверим последний параграф
	this.Check_SectionLastParagraph();

	// Проверим, что последний элемент - параграф
	if (false !== bCheckLastElement && type_Paragraph !== this.Content[this.Content.length - 1].GetType())
		this.Internal_Content_Add(this.Content.length, new Paragraph(this.DrawingDocument, this));

	// Запоминаем, что нам нужно произвести переиндексацию элементов
	this.private_ReindexContent(Position);

	if (type_Paragraph === NewObject.GetType())
		this.DocumentOutline.CheckParagraph(NewObject);
};
CDocument.prototype.Internal_Content_Remove = function(Position, Count, bCheckLastElement)
{
	var ChangePos = -1;

	if (Position < 0 || Position >= this.Content.length || Count <= 0)
		return -1;

	var PrevObj = this.Content[Position - 1] ? this.Content[Position - 1] : null;
	var NextObj = this.Content[Position + Count] ? this.Content[Position + Count] : null;

	for (var Index = 0; Index < Count; Index++)
	{
		this.Content[Position + Index].PreDelete();
	}

	this.History.Add(new CChangesDocumentRemoveItem(this, Position, this.Content.slice(Position, Position + Count)));
	var Elements = this.Content.splice(Position, Count);
	this.private_RecalculateNumbering(Elements);

	if (null != PrevObj)
		PrevObj.Set_DocumentNext(NextObj);

	if (null != NextObj)
		NextObj.Set_DocumentPrev(PrevObj);

	// Проверим, что последний элемент - параграф
	if (false !== bCheckLastElement && (this.Content.length <= 0 || type_Paragraph !== this.Content[this.Content.length - 1].GetType()))
		this.Internal_Content_Add(this.Content.length, new Paragraph(this.DrawingDocument, this));

	// Обновим информацию о секциях
	this.SectionsInfo.Update_OnRemove(Position, Count, true);

	// Проверим последний параграф
	this.Check_SectionLastParagraph();

	// Проверим не является ли рамкой последний параграф
	this.private_CheckFramePrLastParagraph();

	// Запоминаем, что нам нужно произвести переиндексацию элементов
	this.private_ReindexContent(Position);

	return ChangePos;
};
CDocument.prototype.Clear_ContentChanges = function()
{
	this.m_oContentChanges.Clear();
};
CDocument.prototype.Add_ContentChanges = function(Changes)
{
	this.m_oContentChanges.Add(Changes);
};
CDocument.prototype.Refresh_ContentChanges = function()
{
	this.m_oContentChanges.Refresh();
};
/**
 * @param AlignV 0 - Верх, 1 - низ
 * @param AlignH стандартные значения align_Left, align_Center, align_Right
 */
CDocument.prototype.Document_AddPageNum = function(AlignV, AlignH)
{
	if (AlignV >= 0)
	{
		var PageIndex = this.CurPage;
		if (docpostype_HdrFtr === this.Get_DocPosType())
			PageIndex = this.HdrFtr.Get_CurPage();

		if (PageIndex < 0)
			PageIndex = this.CurPage;

		this.Create_HdrFtrWidthPageNum(PageIndex, AlignV, AlignH);
	}
	else
	{
		this.AddToParagraph(new ParaPageNum());
	}

	this.Document_UpdateInterfaceState();
};
CDocument.prototype.Document_SetHdrFtrFirstPage = function(Value)
{
	var CurHdrFtr = this.HdrFtr.CurHdrFtr;

	if (null === CurHdrFtr || -1 === CurHdrFtr.RecalcInfo.CurPage)
		return;

	var CurPage = CurHdrFtr.RecalcInfo.CurPage;
	var Index   = this.Pages[CurPage].Pos;
	var SectPr  = this.SectionsInfo.Get_SectPr(Index).SectPr;

	SectPr.Set_TitlePage(Value);

	if (true === Value)
	{
		// Если мы добавляем разные колонтитулы для первой страницы, а этих колонтитулов нет, тогда создаем их
		var FirstSectPr = this.SectionsInfo.Get_SectPr2(0).SectPr;
		var FirstHeader = FirstSectPr.Get_Header_First();
		var FirstFooter = FirstSectPr.Get_Footer_First();

		if (null === FirstHeader)
		{
			var Header = new CHeaderFooter(this.HdrFtr, this, this.DrawingDocument, hdrftr_Header);
			FirstSectPr.Set_Header_First(Header);

			this.HdrFtr.Set_CurHdrFtr(Header);
		}
		else
			this.HdrFtr.Set_CurHdrFtr(FirstHeader);

		if (null === FirstFooter)
		{
			var Footer = new CHeaderFooter(this.HdrFtr, this, this.DrawingDocument, hdrftr_Footer);
			FirstSectPr.Set_Footer_First(Footer);
		}
	}
	else
	{
		var TempSectPr = SectPr;
		var TempIndex  = Index;
		while (null === TempSectPr.Get_Header_Default())
		{
			TempIndex--;
			if (TempIndex < 0)
				break;

			TempSectPr = this.SectionsInfo.Get_SectPr(TempIndex).SectPr;
		}

		this.HdrFtr.Set_CurHdrFtr(TempSectPr.Get_Header_Default());
	}


	this.Recalculate();

	if (null !== this.HdrFtr.CurHdrFtr)
	{
		this.HdrFtr.CurHdrFtr.Content.MoveCursorToStartPos();
		this.HdrFtr.CurHdrFtr.Set_Page(CurPage);
	}

	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.Document_SetHdrFtrEvenAndOddHeaders = function(Value)
{
	this.Set_DocumentEvenAndOddHeaders(Value);

	var FirstSectPr;
	if (true === Value)
	{
		// Если мы добавляем разные колонтитулы для четных и нечетных страниц, а этих колонтитулов нет, тогда
		// создаем их в самой первой секции
		FirstSectPr = this.SectionsInfo.Get_SectPr2(0).SectPr;
		if (null === FirstSectPr.Get_Header_Even())
		{
			var Header = new CHeaderFooter(this.HdrFtr, this, this.DrawingDocument, hdrftr_Header);
			FirstSectPr.Set_Header_Even(Header);
		}

		if (null === FirstSectPr.Get_Footer_Even())
		{
			var Footer = new CHeaderFooter(this.HdrFtr, this, this.DrawingDocument, hdrftr_Footer);
			FirstSectPr.Set_Footer_Even(Footer);
		}
	}
	else
	{
		FirstSectPr = this.SectionsInfo.Get_SectPr2(0).SectPr;
	}

	if (null !== FirstSectPr.Get_Header_First() && true === FirstSectPr.TitlePage)
		this.HdrFtr.Set_CurHdrFtr(FirstSectPr.Get_Header_First());
	else
		this.HdrFtr.Set_CurHdrFtr(FirstSectPr.Get_Header_Default());


	this.Recalculate();

	if (null !== this.HdrFtr.CurHdrFtr)
		this.HdrFtr.CurHdrFtr.Content.MoveCursorToStartPos();

	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.Document_SetHdrFtrDistance = function(Value)
{
	var CurHdrFtr = this.HdrFtr.CurHdrFtr;

	if (null === CurHdrFtr)
		return;

	var CurPage = CurHdrFtr.RecalcInfo.CurPage;
	if (-1 === CurPage)
		return;

	var Index  = this.Pages[CurPage].Pos;
	var SectPr = this.SectionsInfo.Get_SectPr(Index).SectPr;

	if (hdrftr_Header === CurHdrFtr.Type)
		SectPr.Set_PageMargins_Header(Value);
	else
		SectPr.Set_PageMargins_Footer(Value);

	this.Recalculate();

	this.Document_UpdateRulersState();
	this.Document_UpdateInterfaceState();
	this.Document_UpdateSelectionState();
};
CDocument.prototype.Document_SetHdrFtrBounds = function(Y0, Y1)
{
	var CurHdrFtr = this.HdrFtr.CurHdrFtr;

	if (null === CurHdrFtr)
		return;

	var CurPage = CurHdrFtr.RecalcInfo.CurPage;
	if (-1 === CurPage)
		return;

	var Index  = this.Pages[CurPage].Pos;
	var SectPr = this.SectionsInfo.Get_SectPr(Index).SectPr;
	var Bounds = CurHdrFtr.Get_Bounds();

	if (hdrftr_Header === CurHdrFtr.Type)
	{
		if (null !== Y0)
			SectPr.Set_PageMargins_Header(Y0);

		if (null !== Y1)
			SectPr.Set_PageMargins(undefined, Y1, undefined, undefined);
	}
	else
	{
		if (null !== Y0)
		{
			var H   = Bounds.Bottom - Bounds.Top;
			var _Y1 = Y0 + H;

			SectPr.Set_PageMargins_Footer(SectPr.Get_PageHeight() - _Y1);
		}
	}

	this.Recalculate();

	this.Document_UpdateRulersState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.Document_SetHdrFtrLink = function(bLinkToPrevious)
{
	var CurHdrFtr = this.HdrFtr.CurHdrFtr;
	if (docpostype_HdrFtr !== this.Get_DocPosType() || null === CurHdrFtr || -1 === CurHdrFtr.RecalcInfo.CurPage)
		return;

	var PageIndex = CurHdrFtr.RecalcInfo.CurPage;

	var Index  = this.Pages[PageIndex].Pos;
	var SectPr = this.SectionsInfo.Get_SectPr(Index).SectPr;

	// У самой первой секции не может быть повторяющихся колонтитулов, поэтому не делаем ничего
	if (SectPr === this.SectionsInfo.Get_SectPr2(0).SectPr)
		return;

	// Определим тип колонтитула, в котором мы находимся
	var SectionPageInfo = this.Get_SectionPageNumInfo(PageIndex);

	var bFirst  = ( true === SectionPageInfo.bFirst && true === SectPr.Get_TitlePage() ? true : false );
	var bEven   = ( true === SectionPageInfo.bEven && true === EvenAndOddHeaders ? true : false );
	var bHeader = ( hdrftr_Header === CurHdrFtr.Type ? true : false );

	var _CurHdrFtr = SectPr.Get_HdrFtr(bHeader, bFirst, bEven);

	if (true === bLinkToPrevious)
	{
		// Если нам надо повторять колонтитул, а он уже изначально повторяющийся, тогда не делаем ничего
		if (null === _CurHdrFtr)
			return;

		// Очистим селект
		_CurHdrFtr.RemoveSelection();

		// Просто удаляем запись о данном колонтитуле в секции
		SectPr.Set_HdrFtr(bHeader, bFirst, bEven, null);

		var HdrFtr = this.Get_SectionHdrFtr(PageIndex, bFirst, bEven);

		// Заглушка. Вообще такого не должно быть, чтобы был колонтитул не в первой секции, и не было в первой,
		// но, на всякий случай, обработаем такую ситуацию.
		if (true === bHeader)
		{
			if (null === HdrFtr.Header)
				CurHdrFtr = this.Create_SectionHdrFtr(hdrftr_Header, PageIndex);
			else
				CurHdrFtr = HdrFtr.Header;
		}
		else
		{
			if (null === HdrFtr.Footer)
				CurHdrFtr = this.Create_SectionHdrFtr(hdrftr_Footer, PageIndex);
			else
				CurHdrFtr = HdrFtr.Footer;
		}


		this.HdrFtr.Set_CurHdrFtr(CurHdrFtr);
		this.HdrFtr.CurHdrFtr.MoveCursorToStartPos(false);
	}
	else
	{
		// Если данный колонтитул уже не повторяющийся, тогда ничего не делаем
		if (null !== _CurHdrFtr)
			return;

		var NewHdrFtr = CurHdrFtr.Copy();
		SectPr.Set_HdrFtr(bHeader, bFirst, bEven, NewHdrFtr);
		this.HdrFtr.Set_CurHdrFtr(NewHdrFtr);
		this.HdrFtr.CurHdrFtr.MoveCursorToStartPos(false);
	}

	this.Recalculate();

	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.SetSectionStartPage = function(nStartPage)
{
	var oCurHdrFtr = this.HdrFtr.CurHdrFtr;
	if (!oCurHdrFtr)
		return;

	var nCurPage = oCurHdrFtr.RecalcInfo.CurPage;
	if (-1 === nCurPage)
		return;

	var nIndex  = this.Pages[nCurPage].Pos;
	var oSectPr = this.SectionsInfo.Get_SectPr(nIndex).SectPr;

	oSectPr.Set_PageNum_Start(nStartPage);

	this.Recalculate();

	this.Document_UpdateRulersState();
	this.Document_UpdateInterfaceState();
	this.Document_UpdateSelectionState();
};
CDocument.prototype.Document_Format_Copy = function()
{
	this.CopyTextPr = this.GetDirectTextPr();
	this.CopyParaPr = this.GetDirectParaPr();
};
CDocument.prototype.EndHdrFtrEditing = function(bCanStayOnPage)
{
	if (docpostype_HdrFtr === this.Get_DocPosType())
	{
		this.Set_DocPosType(docpostype_Content);
		var CurHdrFtr = this.HdrFtr.Get_CurHdrFtr();
		if (null === CurHdrFtr || undefined === CurHdrFtr || true !== bCanStayOnPage)
		{
			this.MoveCursorToStartPos(false);
		}
		else
		{
			CurHdrFtr.RemoveSelection();

			if (hdrftr_Header == CurHdrFtr.Type)
				this.MoveCursorToXY(0, 0, false);
			else
				this.MoveCursorToXY(0, 100000, false); // TODO: Переделать здесь по-нормальному
		}

		this.DrawingDocument.ClearCachePages();
		this.DrawingDocument.FirePaint();

		this.Document_UpdateRulersState();
		this.Document_UpdateInterfaceState();
		this.Document_UpdateSelectionState();
	}
};
CDocument.prototype.EndFootnotesEditing = function()
{
	if (docpostype_Footnotes === this.Get_DocPosType())
	{
		this.Set_DocPosType(docpostype_Content);

		this.MoveCursorToStartPos(false);

		// TODO: Не всегда можно в данной функции использовать MoveCursorToXY, потому что
		//       данная страница еще может быть не рассчитана.
		//this.MoveCursorToXY(0, 0, false);

		this.DrawingDocument.ClearCachePages();
		this.DrawingDocument.FirePaint();

		this.Document_UpdateRulersState();
		this.Document_UpdateInterfaceState();
		this.Document_UpdateSelectionState();
	}
};
CDocument.prototype.EndDrawingEditing = function()
{
	if (docpostype_DrawingObjects === this.Get_DocPosType() || (docpostype_HdrFtr === this.Get_DocPosType() && null != this.HdrFtr.CurHdrFtr && docpostype_DrawingObjects === this.HdrFtr.CurHdrFtr.Content.CurPos.Type ))
	{
		this.DrawingObjects.resetSelection2();
		this.Document_UpdateInterfaceState();
		this.Document_UpdateSelectionState();
		this.private_UpdateCursorXY(true, true);
	}
};
CDocument.prototype.Document_Format_Paste = function()
{
	this.Controller.PasteFormatting(this.CopyTextPr, this.CopyParaPr);
	this.Recalculate();
	this.Document_UpdateInterfaceState();
	this.Document_UpdateSelectionState();
};
CDocument.prototype.IsTableCellContent = function(isReturnCell)
{
	if (true === isReturnCell)
		return null;

	return false;
};
CDocument.prototype.Check_AutoFit = function()
{
	return false;
};
CDocument.prototype.Is_TopDocument = function(bReturnTopDocument)
{
	if (true === bReturnTopDocument)
		return this;

	return true;
};
CDocument.prototype.Is_InTable = function(bReturnTopTable)
{
	if (true === bReturnTopTable)
		return null;

	return false;
};
CDocument.prototype.Is_DrawingShape = function(bRetShape)
{
	if (bRetShape === true)
	{
		return null;
	}
	return false;
};
CDocument.prototype.IsSelectionUse = function()
{
	return this.Controller.IsSelectionUse();
};
CDocument.prototype.IsNumberingSelection = function()
{
	return this.Controller.IsNumberingSelection();
};
CDocument.prototype.IsTextSelectionUse = function()
{
	return this.Controller.IsTextSelectionUse();
};
CDocument.prototype.GetCurPosXY = function()
{
	var TempXY = this.Controller.GetCurPosXY();
	this.private_CheckCurPage();
	return {X : TempXY.X, Y : TempXY.Y, PageNum : this.CurPage};
};
/**
 * Возвращаем выделенный текст, если в выделении не более 1 параграфа, и там нет картинок, нумерации страниц и т.д.
 * @param bClearText
 * @param oPr
 * @returns {?string}
 */
CDocument.prototype.GetSelectedText = function(bClearText, oPr)
{
	if (undefined === oPr)
		oPr = {};

	if (undefined === bClearText)
		bClearText = false;

	return this.Controller.GetSelectedText(bClearText, oPr);
};
/**
 * Получаем текущий параграф (или граничные параграфы селекта)
 * @param bIgnoreSelection Если true, тогда используется текущая позиция, даже если есть селект
 * @param bReturnSelectedArray (Используется, только если bIgnoreSelection==false) Если true, тогда возвращаем массив из
 * из параграфов, которые попали в выделение.
 * @returns {Paragraph | [Paragraph]}
 */
CDocument.prototype.GetCurrentParagraph = function(bIgnoreSelection, bReturnSelectedArray)
{
	if (true !== bIgnoreSelection && true === bReturnSelectedArray)
	{
		var arrSelectedParagraphs = [];
		this.Controller.GetCurrentParagraph(bIgnoreSelection, arrSelectedParagraphs);
		return arrSelectedParagraphs;
	}
	else
	{
		return this.Controller.GetCurrentParagraph(bIgnoreSelection, null);
	}
};
/**
 * Возвращаем массив параграфов, попавших в селект
 * @returns {Paragraph[]}
 */
CDocument.prototype.GetSelectedParagraphs = function()
{
	return this.GetCurrentParagraph(false, true);
};
/**
 * Получаем информацию о текущем выделении
 * @returns {CSelectedElementsInfo}
 */
CDocument.prototype.GetSelectedElementsInfo = function(oPr)
{
	var oInfo = new CSelectedElementsInfo(oPr);
	this.Controller.GetSelectedElementsInfo(oInfo);
	return oInfo;
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с таблицами
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.AddTableRow = function(bBefore)
{
	this.Controller.AddTableRow(bBefore);
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.AddTableColumn = function(bBefore)
{
	this.Controller.AddTableColumn(bBefore);
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.RemoveTableRow = function()
{
	this.Controller.RemoveTableRow();
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.RemoveTableColumn = function()
{
	this.Controller.RemoveTableColumn();
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.MergeTableCells = function()
{
	this.Controller.MergeTableCells();
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.SplitTableCells = function(Cols, Rows)
{
	this.Controller.SplitTableCells(Cols, Rows);
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.RemoveTable = function()
{
	this.Controller.RemoveTable();
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
	this.Document_UpdateRulersState();
};
CDocument.prototype.SelectTable = function(Type)
{
	this.Controller.SelectTable(Type);
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
	//this.Document_UpdateRulersState();
};
CDocument.prototype.CanMergeTableCells = function()
{
	return this.Controller.CanMergeTableCells();
};
CDocument.prototype.CanSplitTableCells = function()
{
	return this.Controller.CanSplitTableCells();
};
CDocument.prototype.CheckTableCoincidence = function(Table)
{
	return false;
};
CDocument.prototype.DistributeTableCells = function(isHorizontally)
{
	if (!this.Controller.DistributeTableCells(isHorizontally))
		return false;

	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();

	return true;
};
//----------------------------------------------------------------------------------------------------------------------
// Дополнительные функции
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.Document_CreateFontMap = function()
{
	var FontMap = {};
	this.SectionsInfo.Document_CreateFontMap(FontMap);

	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		this.Content[Index].CreateFontMap(FontMap);
	}
	AscFormat.checkThemeFonts(FontMap, this.theme.themeElements.fontScheme);
	return FontMap;
};
CDocument.prototype.Document_CreateFontCharMap = function(FontCharMap)
{
	this.SectionsInfo.Document_CreateFontCharMap(FontCharMap);
	this.DrawingObjects.documentCreateFontCharMap(FontCharMap);

	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		this.Content[Index].CreateFontCharMap(FontCharMap);
	}
};
CDocument.prototype.Document_Get_AllFontNames = function()
{
	var AllFonts = {};

	this.SectionsInfo.Document_Get_AllFontNames(AllFonts);
	this.Numbering.GetAllFontNames(AllFonts);
	this.Styles.Document_Get_AllFontNames(AllFonts);
	this.theme.Document_Get_AllFontNames(AllFonts);

	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		this.Content[nIndex].GetAllFontNames(AllFonts);
	}
	AscFormat.checkThemeFonts(AllFonts, this.theme.themeElements.fontScheme);
	return AllFonts;
};
/**
 * Обновляем текущее состояние (определяем где мы находимся, картинка/параграф/таблица/колонтитул)
 * @param bSaveCurRevisionChange
 */
CDocument.prototype.Document_UpdateInterfaceState = function(bSaveCurRevisionChange)
{
	if (true === this.TurnOffInterfaceEvents)
		return;

	if (true === AscCommon.CollaborativeEditing.Get_GlobalLockSelection())
		return;

	// Удаляем весь список
	this.Api.sync_BeginCatchSelectedElements();

	this.TrackRevisionsManager.Begin_CollectChanges(bSaveCurRevisionChange);

	// Уберем из интерфейса записи о том где мы находимся (параграф, таблица, картинка или колонтитул)
	this.Api.ClearPropObjCallback();

	this.Controller.UpdateInterfaceState();
	this.TrackRevisionsManager.End_CollectChanges(this.Api);

	// Сообщаем, что список составлен
	this.Api.sync_EndCatchSelectedElements();

	this.Document_UpdateUndoRedoState();
	this.Document_UpdateCanAddHyperlinkState();
	this.Document_UpdateSectionPr();
	this.Document_UpdateStylesPanel();
};
CDocument.prototype.Document_UpdateRulersState = function()
{
	if (true === this.TurnOffInterfaceEvents)
		return;

	if (true === AscCommon.CollaborativeEditing.Get_GlobalLockSelection())
		return;

	this.DrawingDocument.Set_RulerState_Start();
	this.Controller.UpdateRulersState();
	this.DrawingDocument.Set_RulerState_End();
};
CDocument.prototype.Document_UpdateRulersStateBySection = function(Pos)
{
	// В данной функции мы уже точно знаем, что нам секцию нужно выбирать исходя из текущего параграфа
	var CurPos = undefined === Pos ? ( this.Selection.Use === true ? this.Selection.EndPos : this.CurPos.ContentPos ) : Pos;

	var SectPr = this.SectionsInfo.Get_SectPr(CurPos).SectPr;

	var L = SectPr.Get_PageMargin_Left();
	var T = Math.abs(SectPr.Get_PageMargin_Top());
	var R = SectPr.Get_PageWidth() - SectPr.Get_PageMargin_Right();
	var B = SectPr.Get_PageHeight() - Math.abs(SectPr.Get_PageMargin_Bottom());

	var ColumnsCount = SectPr.Get_ColumnsCount();

	if (ColumnsCount > 1)
	{
		this.ColumnsMarkup.Update_FromSectPr(SectPr);

		var Element = this.Content[CurPos];
		if (type_Paragraph === Element.Get_Type())
			this.ColumnsMarkup.Set_CurCol(Element.Get_CurrentColumn());

		this.DrawingDocument.Set_RulerState_Columns(this.ColumnsMarkup);
	}
	else
	{
		this.DrawingDocument.Set_RulerState_Paragraph({L : L, T : T, R : R, B : B}, true);
	}
};
CDocument.prototype.Document_UpdateSelectionState = function()
{
	if (true === this.TurnOffInterfaceEvents)
		return;

	if (true === AscCommon.CollaborativeEditing.Get_GlobalLockSelection())
		return;

	this.DrawingDocument.UpdateTargetTransform(null);

	// TODO: Надо подумать как это вынести в верхнюю функцию внутренние реализации типа controller_UpdateSelectionState
	//       потому что они все очень похожие.

	this.Controller.UpdateSelectionState();

	this.UpdateDocumentOutlinePosition();

	// Обновим состояние кнопок Copy/Cut
	this.Document_UpdateCopyCutState();
};
CDocument.prototype.UpdateDocumentOutlinePosition = function()
{
	if (this.DocumentOutline.IsUse())
	{
		if (this.Controller !== this.LogicDocumentController)
		{
			this.DocumentOutline.UpdateCurrentPosition(null);
		}
		else
		{
			var oCurrentParagraph = this.GetCurrentParagraph(false, false);
			this.DocumentOutline.UpdateCurrentPosition(oCurrentParagraph.GetDocumentPositionFromObject());
		}
	}
};
CDocument.prototype.Document_UpdateTracks = function()
{
	if (true === this.TurnOffInterfaceEvents)
		return;

	if (true === AscCommon.CollaborativeEditing.Get_GlobalLockSelection())
		return;

	this.private_UpdateTracks(this.IsSelectionUse(), this.IsSelectionEmpty());
};
CDocument.prototype.private_UpdateTracks = function(bSelection, bEmptySelection)
{
	var Pos = (true === this.Selection.Use && selectionflag_Numbering !== this.Selection.Flag ? this.Selection.EndPos : this.CurPos.ContentPos);
	if (docpostype_Content === this.Get_DocPosType() && !(Pos >= 0 && (null === this.FullRecalc.Id || this.FullRecalc.StartIndex > Pos)))
		return;

	var oSelectedInfo = this.GetSelectedElementsInfo();

	var Math = oSelectedInfo.Get_Math();
	if (null !== Math)
		this.DrawingDocument.Update_MathTrack(true, (false === bSelection || true === bEmptySelection ? true : false), Math);
	else
		this.DrawingDocument.Update_MathTrack(false);

	var oBlockLevelSdt  = oSelectedInfo.GetBlockLevelSdt();
	var oInlineLevelSdt = oSelectedInfo.GetInlineLevelSdt();

	if (oInlineLevelSdt)
		oInlineLevelSdt.DrawContentControlsTrack(false);
	else if (oBlockLevelSdt)
		oBlockLevelSdt.DrawContentControlsTrack(false);
	else
		this.DrawingDocument.OnDrawContentControl(null, c_oContentControlTrack.In);

	var oField = oSelectedInfo.Get_Field();
	if (null !== oField && (fieldtype_MERGEFIELD !== oField.Get_FieldType() || true !== this.MailMergeFieldsHighlight))
	{
		var aBounds = oField.Get_Bounds();
		this.DrawingDocument.Update_FieldTrack(true, aBounds);
	}
	else
	{
		this.DrawingDocument.Update_FieldTrack(false);

		var arrComplexFields = oSelectedInfo.GetComplexFields();
		if ((arrComplexFields.length > 0 && this.FieldsManager.SetCurrentComplexField(arrComplexFields[arrComplexFields.length - 1]))
			|| (arrComplexFields.length <= 0 && this.FieldsManager.SetCurrentComplexField(null)))
		{
			this.DrawingDocument.ClearCachePages();
			this.DrawingDocument.FirePaint();
		}
	}
};
CDocument.prototype.Document_UpdateUndoRedoState = function()
{
	if (true === this.TurnOffInterfaceEvents)
		return;

	if (true === AscCommon.CollaborativeEditing.Get_GlobalLockSelection())
		return;

	// TODO: Возможно стоит перенсти эту проверку в класс CHistory и присылать
	//       данные события при изменении значения History.Index

	// Проверяем состояние Undo/Redo

	if (this.IsViewModeInReview())
	{
		this.Api.sync_CanUndoCallback(false);
		this.Api.sync_CanRedoCallback(false);
	}
	else
	{
		var bCanUndo = this.History.Can_Undo();
		if (true !== bCanUndo && this.Api && this.CollaborativeEditing && true === this.CollaborativeEditing.Is_Fast() && true !== this.CollaborativeEditing.Is_SingleUser())
			bCanUndo = this.CollaborativeEditing.CanUndo();

		this.Api.sync_CanUndoCallback(bCanUndo);
		this.Api.sync_CanRedoCallback(this.History.Can_Redo());
		this.Api.CheckChangedDocument();
	}
};
CDocument.prototype.Document_UpdateCopyCutState = function()
{
	if (true === this.TurnOffInterfaceEvents)
		return;

	if (true === AscCommon.CollaborativeEditing.Get_GlobalLockSelection())
		return;

	// Во время работы селекта не обновляем состояние
	if (true === this.Selection.Start)
		return;

	this.Api.sync_CanCopyCutCallback(this.Can_CopyCut());
};
CDocument.prototype.Document_UpdateCanAddHyperlinkState = function()
{
	if (true === this.TurnOffInterfaceEvents)
		return;

	if (true === AscCommon.CollaborativeEditing.Get_GlobalLockSelection())
		return;

	// Проверяем можно ли добавить гиперссылку
	this.Api.sync_CanAddHyperlinkCallback(this.CanAddHyperlink(false));
};
CDocument.prototype.Document_UpdateSectionPr = function()
{
	if (true === this.TurnOffInterfaceEvents)
		return;

	if (true === this.CollaborativeEditing.Get_GlobalLockSelection())
		return;

	// Обновляем ориентацию страницы
	this.Api.sync_PageOrientCallback(this.Get_DocumentOrientation());

	// Обновляем размер страницы
	var PageSize = this.Get_DocumentPageSize();
	this.Api.sync_DocSizeCallback(PageSize.W, PageSize.H);

	// Обновляем настройки колонок
	var CurPos = this.CurPos.ContentPos;
	var SectPr = this.SectionsInfo.Get_SectPr(CurPos).SectPr;

	if (SectPr)
	{
		var ColumnsPr = new CDocumentColumnsProps();
		ColumnsPr.From_SectPr(SectPr);
		this.Api.sync_ColumnsPropsCallback(ColumnsPr);
		this.Api.sync_SectionPropsCallback(new CDocumentSectionProps(SectPr));
	}
};
CDocument.prototype.Get_ColumnsProps = function()
{
	// Обновляем настройки колонок
	var CurPos = this.CurPos.ContentPos;
	var SectPr = this.SectionsInfo.Get_SectPr(CurPos).SectPr;

	var ColumnsPr = new CDocumentColumnsProps();
	if (SectPr)
	{
		ColumnsPr.From_SectPr(SectPr);
	}

	return ColumnsPr;
};
/**
 * Отключаем отсылку сообщений в интерфейс.
 */
CDocument.prototype.TurnOff_InterfaceEvents = function()
{
	this.TurnOffInterfaceEvents = true;
};
/**
 * Включаем отсылку сообщений в интерфейс.
 *
 * @param {bool} bUpdate Обновлять ли интерфейс
 */
CDocument.prototype.TurnOn_InterfaceEvents = function(bUpdate)
{
	this.TurnOffInterfaceEvents = false;

	if (true === bUpdate)
	{
		this.Document_UpdateInterfaceState();
		this.Document_UpdateSelectionState();
		this.Document_UpdateRulersState();
	}
};
CDocument.prototype.TurnOff_RecalculateCurPos = function()
{
	this.TurnOffRecalcCurPos = true;
};
CDocument.prototype.TurnOn_RecalculateCurPos = function(bUpdate)
{
	this.TurnOffRecalcCurPos = false;

	if (true === bUpdate)
		this.Document_UpdateSelectionState();
};
CDocument.prototype.Can_CopyCut = function()
{
	var bCanCopyCut = false;

	var LogicDocument  = null;
	var DrawingObjects = null;

	var nDocPosType = this.Get_DocPosType();
	if (docpostype_HdrFtr === nDocPosType)
	{
		var CurHdrFtr = this.HdrFtr.CurHdrFtr;
		if (null !== CurHdrFtr)
		{
			if (docpostype_DrawingObjects === CurHdrFtr.Content.Get_DocPosType())
				DrawingObjects = this.DrawingObjects;
			else
				LogicDocument = CurHdrFtr.Content;
		}
	}
	else if (docpostype_DrawingObjects === nDocPosType)
	{
		DrawingObjects = this.DrawingObjects;
	}
	else if (docpostype_Footnotes === nDocPosType)
	{
		if (0 === this.Footnotes.Selection.Direction)
		{
			var oFootnote = this.Footnotes.GetCurFootnote();
			if (oFootnote)
			{
				if (docpostype_DrawingObjects === oFootnote.Get_DocPosType())
				{
					DrawingObjects = this.DrawingObjects;
				}
				else
				{
					LogicDocument = oFootnote;
				}
			}
		}
		else
		{
			return true;
		}
	}
	else //if (docpostype_Content === nDocPosType)
	{
		LogicDocument = this;
	}

	if (null !== DrawingObjects)
	{
		if (true === DrawingObjects.isSelectedText())
			LogicDocument = DrawingObjects.getTargetDocContent();
		else
			bCanCopyCut = true;
	}

	if (null !== LogicDocument)
	{
		if (true === LogicDocument.IsSelectionUse() && true !== LogicDocument.IsSelectionEmpty(true))
		{
			if (selectionflag_Numbering === LogicDocument.Selection.Flag)
				bCanCopyCut = false;
			else if (LogicDocument.Selection.StartPos !== LogicDocument.Selection.EndPos)
				bCanCopyCut = true;
			else
				bCanCopyCut = LogicDocument.Content[LogicDocument.Selection.StartPos].Can_CopyCut();
		}
	}

	return bCanCopyCut;
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с номерами страниц
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.Get_StartPage_Absolute = function()
{
	return 0;
};
CDocument.prototype.Get_StartPage_Relative = function()
{
	return 0;
};
CDocument.prototype.Get_AbsolutePage = function(CurPage)
{
	return CurPage;
};
CDocument.prototype.Set_CurPage = function(PageNum)
{
	this.CurPage = Math.min(this.Pages.length - 1, Math.max(0, PageNum));
};
CDocument.prototype.Get_CurPage = function()
{
	// Работаем с колонтитулом
	if (docpostype_HdrFtr === this.Get_DocPosType())
		return this.HdrFtr.Get_CurPage();

	return this.CurPage;
};
//----------------------------------------------------------------------------------------------------------------------
// Undo/Redo функции
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.Create_NewHistoryPoint = function(Description)
{
	this.History.Create_NewPoint(Description);
};
CDocument.prototype.Document_Undo = function(Options)
{
	if (true === AscCommon.CollaborativeEditing.Get_GlobalLock() && true !== this.IsFillingFormMode())
		return;

	// Нужно сбрасывать, т.к. после Undo/Redo данные списки у нас будут в глобальной таблице, но не такие, какие нужны
	this.SetLastNumberedList(null);
	this.SetLastBulletList(null);

	if (true !== this.History.Can_Undo() && this.Api && this.CollaborativeEditing && true === this.CollaborativeEditing.Is_Fast() && true !== this.CollaborativeEditing.Is_SingleUser())
	{
		if (this.CollaborativeEditing.CanUndo() && true === this.Api.canSave)
		{
			this.CollaborativeEditing.Set_GlobalLock(true);
			this.Api.forceSaveUndoRequest = true;
		}
	}
	else
	{
		this.DrawingDocument.EndTrackTable(null, true);
		this.DrawingObjects.TurnOffCheckChartSelection();

		this.History.Undo(Options);
		this.DocumentOutline.UpdateAll(); // TODO: надо бы подумать как переделать на более легкий пересчет
		this.DrawingObjects.TurnOnCheckChartSelection();
		this.Recalculate(false, false, this.History.RecalculateData);

		this.Document_UpdateSelectionState();
		this.Document_UpdateInterfaceState();
		this.Document_UpdateRulersState();
	}
};
CDocument.prototype.Document_Redo = function()
{
	if (true === AscCommon.CollaborativeEditing.Get_GlobalLock() && true !== this.IsFillingFormMode())
		return;

	// Нужно сбрасывать, т.к. после Undo/Redo данные списки у нас будут в глобальной таблице, но не такие, какие нужны
	this.SetLastNumberedList(null);
	this.SetLastBulletList(null);

	this.DrawingDocument.EndTrackTable(null, true);
	this.DrawingObjects.TurnOffCheckChartSelection();

	this.History.Redo();
	this.DocumentOutline.UpdateAll(); // TODO: надо бы подумать как переделать на более легкий пересчет
	this.DrawingObjects.TurnOnCheckChartSelection();
	this.Recalculate(false, false, this.History.RecalculateData);

	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
	this.Document_UpdateRulersState();
};
CDocument.prototype.GetSelectionState = function()
{
	var DocState    = {};
	DocState.CurPos = {
		X          : this.CurPos.X,
		Y          : this.CurPos.Y,
		ContentPos : this.CurPos.ContentPos,
		RealX      : this.CurPos.RealX,
		RealY      : this.CurPos.RealY,
		Type       : this.CurPos.Type
	};

	DocState.Selection = {

		Start    : this.Selection.Start,
		Use      : this.Selection.Use,
		StartPos : this.Selection.StartPos,
		EndPos   : this.Selection.EndPos,
		Flag     : this.Selection.Flag,
		Data     : this.Selection.Data
	};

	DocState.CurPage    = this.CurPage;
	DocState.CurComment = this.Comments.Get_CurrentId();

	var State = null;
	if (true === editor.isStartAddShape && docpostype_DrawingObjects === this.Get_DocPosType())
	{
		DocState.CurPos.Type     = docpostype_Content;
		DocState.Selection.Start = false;
		DocState.Selection.Use   = false;

		this.Content[DocState.CurPos.ContentPos].RemoveSelection();
		State = this.Content[this.CurPos.ContentPos].GetSelectionState();
	}
	else
	{
		State = this.Controller.GetSelectionState();
	}

	if (null != this.Selection.Data && true === this.Selection.Data.TableBorder)
	{
		DocState.Selection.Data = null;
	}

	State.push(DocState);

	return State;
};
CDocument.prototype.SetSelectionState = function(State)
{
	if (docpostype_DrawingObjects === this.Get_DocPosType())
		this.DrawingObjects.resetSelection();

	if (State.length <= 0)
		return;

	var DocState = State[State.length - 1];

	this.CurPos.X          = DocState.CurPos.X;
	this.CurPos.Y          = DocState.CurPos.Y;
	this.CurPos.ContentPos = DocState.CurPos.ContentPos;
	this.CurPos.RealX      = DocState.CurPos.RealX;
	this.CurPos.RealY      = DocState.CurPos.RealY;
	this.Set_DocPosType(DocState.CurPos.Type);

	this.Selection.Start    = DocState.Selection.Start;
	this.Selection.Use      = DocState.Selection.Use;
	this.Selection.StartPos = DocState.Selection.StartPos;
	this.Selection.EndPos   = DocState.Selection.EndPos;
	this.Selection.Flag     = DocState.Selection.Flag;
	this.Selection.Data     = DocState.Selection.Data;

	this.Selection.DragDrop.Flag = 0;
	this.Selection.DragDrop.Data = null;

	this.CurPage = DocState.CurPage;
	this.Comments.Set_Current(DocState.CurComment);

	this.Controller.SetSelectionState(State, State.length - 2);
};
CDocument.prototype.Get_ParentObject_or_DocumentPos = function(Index)
{
	return {Type : AscDFH.historyitem_recalctype_Inline, Data : Index};
};
CDocument.prototype.Refresh_RecalcData = function(Data)
{
	var ChangePos         = -1;
	var bNeedRecalcHdrFtr = false;

	var Type = Data.Type;

	switch (Type)
	{
		case AscDFH.historyitem_Document_AddItem:
		case AscDFH.historyitem_Document_RemoveItem:
		{
			ChangePos = Data.Pos;
			break;
		}

		case AscDFH.historyitem_Document_DefaultTab:
		case AscDFH.historyitem_Document_EvenAndOddHeaders:
		case AscDFH.historyitem_Document_MathSettings:
		{
			ChangePos = 0;
			break;
		}
	}

	if (-1 != ChangePos)
	{
		this.History.RecalcData_Add({
			Type : AscDFH.historyitem_recalctype_Inline,
			Data : {Pos : ChangePos, PageNum : 0}
		});
	}
};
CDocument.prototype.Refresh_RecalcData2 = function(Index, Page_rel)
{
	this.History.RecalcData_Add({
		Type : AscDFH.historyitem_recalctype_Inline,
		Data : {Pos : Index, PageNum : Page_rel}
	});
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с гиперссылками
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.AddHyperlink = function(HyperProps)
{
	// Проверку, возможно ли добавить гиперссылку, должны были вызвать до этой функции
	if (null != HyperProps.Text && "" != HyperProps.Text && true === this.IsSelectionUse())
	{
		// Корректировка в данном случае пройдет при добавлении гиперссылки.
		var SelectionInfo = this.GetSelectedElementsInfo();
		var Para          = SelectionInfo.GetParagraph();
		if (null !== Para)
			HyperProps.TextPr = Para.Get_TextPr(Para.Get_ParaContentPos(true, true));

		this.Remove(1, false, false, true);
		this.RemoveTextSelection();
	}

	this.Controller.AddHyperlink(HyperProps);
	this.Recalculate();
	this.Document_UpdateInterfaceState();
	this.Document_UpdateSelectionState();
};
CDocument.prototype.ModifyHyperlink = function(oHyperProps)
{
	var sText    = oHyperProps.get_Text(),
		sValue   = oHyperProps.get_Value(),
		sToolTip = oHyperProps.get_ToolTip(),
		sAnchor  = oHyperProps.get_Bookmark();

	var oClass = oHyperProps.get_InternalHyperlink();
	if (oClass instanceof ParaHyperlink)
	{
		var oHyperlink = oClass;

		if (undefined !== sAnchor && null !== sAnchor && "" !== sAnchor)
		{
			oHyperlink.SetAnchor(sAnchor);
			oHyperlink.SetValue("");
		}
		else if (undefined !== sValue && null !== sValue)
		{
			oHyperlink.SetValue(sValue);
			oHyperlink.SetAnchor("");
		}

		if (undefined !== sToolTip && null !== sToolTip)
			oHyperlink.SetToolTip(sToolTip);

		if (null !== sText)
		{
			var oHyperRun = new ParaRun(oHyperlink.GetParagraph());
			oHyperRun.Set_Pr(oHyperlink.GetTextPr().Copy());
			oHyperRun.Set_Color(undefined);
			oHyperRun.Set_Underline(undefined);
			oHyperRun.Set_RStyle(this.GetStyles().GetDefaultHyperlink());
			oHyperRun.AddText(sText);

			oHyperlink.RemoveSelection();
			oHyperlink.RemoveAll();
			oHyperlink.AddToContent(0, oHyperRun, false);

			this.RemoveSelection();
			oHyperlink.MoveCursorOutsideElement(false);
		}
	}
	else if (oClass instanceof CFieldInstructionHYPERLINK)
	{
		var oInstruction = oClass;
		var oComplexField = oInstruction.GetComplexField();
		if (!oComplexField || oComplexField)
		{
			if (undefined !== sAnchor && null !== sAnchor && "" !== sAnchor)
			{
				oInstruction.SetBookmarkName(sAnchor);
				oInstruction.SetLink("");
			}
			else if (undefined !== sValue && null !== sValue)
			{
				oInstruction.SetLink(sValue);
				oInstruction.SetBookmarkName("");
			}

			if (undefined !== sToolTip && null !== sToolTip)
				oInstruction.SetToolTip(sToolTip);

			oComplexField.SelectFieldCode();
			var sInstruction = oInstruction.ToString();
			for (var oIterator = sInstruction.getUnicodeIterator(); oIterator.check(); oIterator.next())
			{
				this.AddToParagraph(new ParaInstrText(oIterator.value()));
			}

			if (null !== sText)
			{
				oComplexField.SelectFieldValue();
				var oTextPr = this.GetDirectTextPr();
				this.AddText(sText);
				oComplexField.SelectFieldValue();
				this.AddToParagraph(new ParaTextPr(oTextPr));
			}
			oComplexField.MoveCursorOutsideElement(false);
		}
	}
	else
	{
		return;
	}

	this.Recalculate();
    this.Document_UpdateSelectionState();
    this.Document_UpdateInterfaceState();
};
CDocument.prototype.RemoveHyperlink = function(oHyperProps)
{
	var oClass = oHyperProps.get_InternalHyperlink();
	if (oClass instanceof ParaHyperlink)
	{
		var oHyperlink = oClass;

		var oParent      = oHyperlink.GetParent();
		var nPosInParent = oHyperlink.GetPosInParent(oParent);

		if (!oParent)
			return;

		oParent.RemoveFromContent(nPosInParent, 1);

		var oTextPr       = new CTextPr();
		oTextPr.RStyle    = null;
		oTextPr.Underline = null;
		oTextPr.Color     = null;
		oTextPr.Unifill   = null;

		var oElement = null;
		for (var nPos = 0, nCount = oHyperlink.GetElementsCount(); nPos < nCount; ++nPos)
		{
			oElement = oHyperlink.GetElement(nPos);
			oParent.AddToContent(nPosInParent + nPos, oElement);
			oElement.ApplyTextPr(oTextPr, undefined, true);
		}

		this.RemoveSelection();
		if (oElement)
		{
			oElement.SetThisElementCurrent();
			oElement.MoveCursorToEndPos();
		}
	}
	else if (oClass instanceof CFieldInstructionHYPERLINK)
	{
		var oInstruction = oClass;
		var oComplexField = oInstruction.GetComplexField();
		if (!oComplexField || oComplexField)
		{
			var oTextPr       = new CTextPr();
			oTextPr.RStyle    = null;
			oTextPr.Underline = null;
			oTextPr.Color     = null;
			oTextPr.Unifill   = null;

			oComplexField.SelectFieldValue();
			this.AddToParagraph(new ParaTextPr(oTextPr));

			oComplexField.RemoveFieldWrap();
		}
	}
	else
	{
		return;
	}

	//this.Controller.RemoveHyperlink();
	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.CanAddHyperlink = function(bCheckInHyperlink)
{
	return this.Controller.CanAddHyperlink(bCheckInHyperlink);
};
/**
 * Проверяем, находимся ли мы в гиперссылке сейчас.
 * @param bCheckEnd
 * @returns {*}
 */
CDocument.prototype.IsCursorInHyperlink = function(bCheckEnd)
{
	if (undefined === bCheckEnd)
		bCheckEnd = true;

	return this.Controller.IsCursorInHyperlink(bCheckEnd);
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с совместным редактирования
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.Document_Is_SelectionLocked = function(CheckType, AdditionalData, DontLockInFastMode, isIgnoreCanEditFlag)
{
	return false;
};
CDocument.prototype.Get_SelectionState2 = function()
{
	this.RemoveSelection();

	// Сохраняем Id ближайшего элемента в текущем классе
	var State       = new CDocumentSelectionState();
	var nDocPosType = this.Get_DocPosType();
	if (docpostype_HdrFtr === nDocPosType)
	{
		State.Type = docpostype_HdrFtr;

		if (null != this.HdrFtr.CurHdrFtr)
			State.Id = this.HdrFtr.CurHdrFtr.Get_Id();
		else
			State.Id = null;
	}
	else if (docpostype_DrawingObjects === nDocPosType)
	{
		// TODO: запрашиваем параграф текущего выделенного элемента
		var X       = 0;
		var Y       = 0;
		var PageNum = this.CurPage;

		var ContentPos = this.Internal_GetContentPosByXY(X, Y, PageNum);

		State.Type = docpostype_Content;
		State.Id   = this.Content[ContentPos].GetId();
	}
	else if (docpostype_Footnotes === nDocPosType)
	{
		State.Type = docpostype_Footnotes;
		State.Id   = this.Footnotes.GetCurFootnote().Get_Id();
	}
	else // if (docpostype_Content === nDocPosType)
	{
		State.Id   = this.Get_Id();
		State.Type = docpostype_Content;

		var Element = this.Content[this.CurPos.ContentPos];
		State.Data  = Element.Get_SelectionState2();
	}

	return State;
};
CDocument.prototype.Set_SelectionState2 = function(State)
{
	this.RemoveSelection();

	var Id = State.Id;
	if (docpostype_HdrFtr === State.Type)
	{
		this.Set_DocPosType(docpostype_HdrFtr);

		if (null === Id || true != this.HdrFtr.Set_CurHdrFtr_ById(Id))
		{
			this.Set_DocPosType(docpostype_Content);
			this.CurPos.ContentPos = 0;

			this.Content[this.CurPos.ContentPos].MoveCursorToStartPos(false);
		}
	}
	else if (docpostype_Footnotes === State.Type)
	{
		this.Set_DocPosType(docpostype_Footnotes);
		var oFootnote = g_oTableId.Get_ById(State.Id);
		if (oFootnote && true === this.Footnotes.Is_UseInDocument(State.Id))
		{
			this.Footnotes.private_SetCurrentFootnoteNoSelection(oFootnote);
			oFootnote.MoveCursorToStartPos(false);
		}
		else
		{
			this.EndFootnotesEditing();
		}
	}
	else // if ( docpostype_Content === State.Type )
	{
		var CurId = State.Data.Id;

		var bFlag = false;

		var Pos = 0;

		// Найдем элемент с Id = CurId
		var Count = this.Content.length;
		for (Pos = 0; Pos < Count; Pos++)
		{
			if (this.Content[Pos].GetId() == CurId)
			{
				bFlag = true;
				break;
			}
		}

		if (true !== bFlag)
		{
			var TempElement = g_oTableId.Get_ById(CurId);
			Pos             = ( null != TempElement ? TempElement.Index : 0 );
			Pos             = Math.max(0, Math.min(Pos, this.Content.length - 1));
		}

		this.Selection.Start    = false;
		this.Selection.Use      = false;
		this.Selection.StartPos = Pos;
		this.Selection.EndPos   = Pos;
		this.Selection.Flag     = selectionflag_Common;

		this.Set_DocPosType(docpostype_Content);
		this.CurPos.ContentPos = Pos;

		if (true !== bFlag)
			this.Content[this.CurPos.ContentPos].MoveCursorToStartPos(false);
		else
			this.Content[this.CurPos.ContentPos].SetSelectionState2(State.Data);
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с комментариями
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.AddComment = function(CommentData, isForceGlobal)
{
	if (true === isForceGlobal || true != this.CanAddComment())
	{
		CommentData.Set_QuoteText(null);
		var Comment = new CComment(this.Comments, CommentData);
		this.Comments.Add(Comment);

		// Обновляем информацию для Undo/Redo
		this.Document_UpdateInterfaceState();
	}
	else
	{
		var QuotedText = this.GetSelectedText(false);
		if (null === QuotedText)
			QuotedText = "";
		CommentData.Set_QuoteText(QuotedText);

		var Comment = new CComment(this.Comments, CommentData);
		this.Comments.Add(Comment);
		this.Controller.AddComment(Comment);

		// TODO: Продумать, как избавиться от пересчета
		this.Recalculate();
		this.Document_UpdateInterfaceState();
	}

	return Comment;
};
CDocument.prototype.EditComment = function(Id, CommentData)
{
	if (!this.Comments.IsUseSolved() && this.Comments.Get_CurrentId() === Id)
	{
		var oComment = this.Comments.Get_ById(Id);
		if (oComment && !oComment.IsSolved() && CommentData.IsSolved())
		{
			this.Comments.Set_Current(null);
			this.Api.sync_HideComment();
			this.DrawingDocument.ClearCachePages();
			this.DrawingDocument.FirePaint();
		}
	}

	this.Comments.Set_CommentData(Id, CommentData);
	this.Document_UpdateInterfaceState();
};
CDocument.prototype.RemoveComment = function(Id, bSendEvent, bRecalculate)
{
	if (null === Id)
		return;

	if (true === this.Comments.Remove_ById(Id))
	{
		if (true === bRecalculate)
		{
			// TODO: Продумать как избавиться от пересчета при удалении комментария
			this.Recalculate();
			this.Document_UpdateInterfaceState();
		}

		if (true === bSendEvent)
			this.Api.sync_RemoveComment(Id);
	}
};
CDocument.prototype.CanAddComment = function()
{
	if (!this.CanEdit() && !this.IsEditCommentsMode())
		return false;

	if (true !== this.Comments.Is_Use())
		return false;

	return this.Controller.CanAddComment();
};
CDocument.prototype.SelectComment = function(Id, ScrollToComment)
{
	var OldId = this.Comments.Get_CurrentId();
	this.Comments.Set_Current(Id);

	var Comment = this.Comments.Get_ById(Id);
	if (null != Comment)
	{
		var Comment_PageNum = Comment.m_oStartInfo.PageNum;
		var Comment_Y       = Comment.m_oStartInfo.Y;
		var Comment_X       = Comment.m_oStartInfo.X;

		if (true === ScrollToComment)
			this.DrawingDocument.m_oWordControl.ScrollToPosition(Comment_X, Comment_Y, Comment_PageNum);
	}

	if (OldId != Id)
	{
		this.DrawingDocument.ClearCachePages();
		this.DrawingDocument.FirePaint();
	}
};
CDocument.prototype.ShowComment = function(arrId)
{
	var CommentsX     = null;
	var CommentsY     = null;
	var arrCommentsId = [];

	for (var nIndex = 0, nCount = arrId.length; nIndex < nCount; ++nIndex)
	{
		var Comment = this.Comments.Get_ById(arrId[nIndex]);
		if (null != Comment && null != Comment.StartId && null != Comment.EndId)
		{
			if (null === CommentsX)
			{
				var Comment_PageNum = Comment.m_oStartInfo.PageNum;
				var Comment_Y       = Comment.m_oStartInfo.Y;
				var Comment_X       = this.Get_PageLimits(Comment_PageNum).XLimit;

				var Coords = this.DrawingDocument.ConvertCoordsToCursorWR(Comment_X, Comment_Y, Comment_PageNum);

				CommentsX = Coords.X;
				CommentsY = Coords.Y;
			}

			arrCommentsId.push(Comment.Get_Id());
		}

	}

	if (null !== CommentsX && null !== CommentsY && arrCommentsId.length > 0)
	{
		this.Api.sync_ShowComment(arrCommentsId, CommentsX, CommentsY);
	}
	else
	{
		this.Api.sync_HideComment();
	}
};
CDocument.prototype.ShowComments = function(isShowSolved)
{
	if (false !== isShowSolved)
		isShowSolved = true;

	this.Comments.Set_Use(true);
	this.Comments.SetUseSolved(isShowSolved);
	this.DrawingDocument.ClearCachePages();
	this.DrawingDocument.FirePaint();
};
CDocument.prototype.HideComments = function()
{
	this.Comments.Set_Use(false);
	this.Comments.SetUseSolved(false);
	this.Comments.Set_Current(null);
	this.DrawingDocument.ClearCachePages();
	this.DrawingDocument.FirePaint();
};
CDocument.prototype.GetPrevElementEndInfo = function(CurElement)
{
    var PrevElement = CurElement.Get_DocumentPrev();

    if (null !== PrevElement && undefined !== PrevElement)
        return PrevElement.GetEndInfo();
    else
        return null;
};
CDocument.prototype.GetSelectionAnchorPos = function()
{
	var Result = this.Controller.GetSelectionAnchorPos();

	var PageLimit = this.Get_PageLimits(Result.Page);
	Result.X0     = PageLimit.X;
	Result.X1     = PageLimit.XLimit;

	var Coords0 = this.DrawingDocument.ConvertCoordsToCursorWR(Result.X0, Result.Y, Result.Page);
	var Coords1 = this.DrawingDocument.ConvertCoordsToCursorWR(Result.X1, Result.Y, Result.Page);

	return {X0 : Coords0.X, X1 : Coords1.X, Y : Coords0.Y};
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с textbox
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.TextBox_Put = function(sText, rFonts)
{
	if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddTextFromTextBox);

		// Отключаем пересчет, включим перед последним добавлением. Поскольку,
		// у нас все добавляется в 1 параграф, так можно делать.
		this.Start_SilentMode();

		if (undefined === rFonts)
		{
			this.AddText(sText);
		}
		else
		{
			var Para = this.GetCurrentParagraph();
			if (null === Para)
				return;

			var RunPr = Para.Get_TextPr();
			if (null === RunPr || undefined === RunPr)
				RunPr = new CTextPr();

			RunPr.RFonts = rFonts;

			var Run = new ParaRun(Para);
			Run.Set_Pr(RunPr);
			Run.AddText(sText);
			Para.Add(Run);
		}

		this.End_SilentMode(true);
	}
};
//----------------------------------------------------------------------------------------------------------------------
// события вьюера
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.Viewer_OnChangePosition = function()
{
	var Comment = this.Comments.Get_Current();
	if (null != Comment)
	{
		var Comment_PageNum = Comment.m_oStartInfo.PageNum;
		var Comment_Y       = Comment.m_oStartInfo.Y;
		var Comment_X       = this.Get_PageLimits(Comment_PageNum).XLimit;
		var Para            = g_oTableId.Get_ById(Comment.StartId);

		if (null !== Para)
		{
			var TextTransform = Para.Get_ParentTextTransform();
			if (TextTransform)
			{
				Comment_Y = TextTransform.TransformPointY(Comment.m_oStartInfo.X, Comment.m_oStartInfo.Y);
			}
		}

		var Coords = this.DrawingDocument.ConvertCoordsToCursorWR(Comment_X, Comment_Y, Comment_PageNum);
		this.Api.sync_UpdateCommentPosition(Comment.Get_Id(), Coords.X, Coords.Y);
	}
    window['AscCommon'].g_specialPasteHelper.SpecialPasteButton_Update_Position();
	this.TrackRevisionsManager.Update_VisibleChangesPosition(this.Api);
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с секциями
//----------------------------------------------------------------------------------------------------------------------
/**
 * Обновляем информацию о всех секциях в данном документе
 */
CDocument.prototype.UpdateAllSectionsInfo = function()
{
	this.SectionsInfo.Clear();

	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		var Element = this.Content[Index];
		if (type_Paragraph === Element.GetType() && undefined !== Element.Get_SectionPr())
			this.SectionsInfo.Add(Element.Get_SectionPr(), Index);
	}

	this.SectionsInfo.Add(this.SectPr, Count);

	// Когда полностью обновляются секции надо пересчитывать с самого начала
	this.RecalcInfo.Set_NeedRecalculateFromStart(true);
};
/**
 * Обновляем информацию о заданной секции
 * @param oSectPr {CSectionPr} - Если не задано, значит добавляется новая секция
 * @param oNewSectPr {CSectionPr} - Если не задано, тогда секция удаляется
 * @param isCheckHdrFtr {boolean} - Проверять ли колонтитулы при удалении секции
 */
CDocument.prototype.UpdateSectionInfo = function(oSectPr, oNewSectPr, isCheckHdrFtr)
{
	if (!this.SectionsInfo.UpdateSection(oSectPr, oNewSectPr, isCheckHdrFtr))
		this.UpdateAllSectionsInfo();
};
CDocument.prototype.Check_SectionLastParagraph = function()
{
	var Count = this.Content.length;
	if (Count <= 0)
		return;

	var Element = this.Content[Count - 1];
	if (type_Paragraph === Element.GetType() && undefined !== Element.Get_SectionPr())
		this.Internal_Content_Add(Count, new Paragraph(this.DrawingDocument, this));
};
CDocument.prototype.Add_SectionBreak = function(SectionBreakType)
{
	if (docpostype_Content !== this.Get_DocPosType())
		return false;

	if (true === this.Selection.Use)
	{
		// Если у нас есть селект, тогда ставим курсор в начало селекта
		this.MoveCursorLeft(false, false);
	}

	var Element = this.Content[this.CurPos.ContentPos];

	var CurSectPr = this.SectionsInfo.Get_SectPr(this.CurPos.ContentPos).SectPr;

	if (type_Paragraph === Element.GetType())
	{
		// Если мы стоим в параграфе, тогда делим данный параграф на 2 в текущей точке(даже если мы стоим в начале
		// или в конце параграфа) и к первому параграфу приписываем конец секкции.

		var NewParagraph = new Paragraph(this.DrawingDocument, this);

		Element.Split(NewParagraph);

		this.CurPos.ContentPos++;
		NewParagraph.MoveCursorToStartPos(false);

		this.Internal_Content_Add(this.CurPos.ContentPos, NewParagraph);

		// Заметим, что после функции Split, у параграфа Element не может быть окончания секции, т.к. если она
		// была в нем изначально, тогда после функции Split, окончание секции перенеслось в новый параграф.
	}
	else if (type_Table === Element.GetType())
	{
		// Если мы стоим в таблице, тогда делим данную таблицу на 2 по текущему ряду(текущий ряд попадает во
		// вторую таблицу). Вставляем между таблицами параграф, и к этому параграфу приписываем окончание
		// секции. Если мы стоим в первой строке таблицы, таблицу делить не надо, достаточно добавить новый
		// параграф перед ней.

		var NewParagraph = new Paragraph(this.DrawingDocument, this);
		var NewTable     = Element.Split_Table();

		if (null === NewTable)
		{
			this.Internal_Content_Add(this.CurPos.ContentPos, NewParagraph);
			this.CurPos.ContentPos++;
		}
		else
		{
			this.Internal_Content_Add(this.CurPos.ContentPos + 1, NewParagraph);
			this.Internal_Content_Add(this.CurPos.ContentPos + 2, NewTable);
			this.CurPos.ContentPos += 2;
		}

		this.Content[this.CurPos.ContentPos].MoveCursorToStartPos(false);

		Element = NewParagraph;
	}
	else
	{
		return false;
	}

	var SectPr = new CSectionPr(this);

	// В данном месте мы ставим разрыв секции. Чтобы до текущего места ничего не изменилось, мы у новой
	// для новой секции копируем все настройки из старой, а в старую секцию выставляем приходящий тип
	// разрыва секций. Заметим, что поскольку мы делаем все так, чтобы до текущей страницы ничего не
	// изменилось, надо сохранить эту информацию для пересчета, для этого мы помечаем все следующие изменения
	// как не влияющие на пересчет.

	this.History.MinorChanges = true;

	SectPr.Copy(CurSectPr);
	CurSectPr.Set_Type(SectionBreakType);
	CurSectPr.Set_PageNum_Start(-1);
	CurSectPr.Clear_AllHdrFtr();

	this.History.MinorChanges = false;

	Element.Set_SectionPr(SectPr);
	Element.Refresh_RecalcData2(0, 0);

	this.Recalculate();
	this.Document_UpdateInterfaceState();
	this.Document_UpdateSelectionState();

	return true;
};
CDocument.prototype.Get_SectionFirstPage = function(SectIndex, Page_abs)
{
	if (SectIndex <= 0)
		return 0;

	var StartIndex = this.SectionsInfo.Get_SectPr2(SectIndex - 1).Index;

	// Ищем номер страницы, на которой закончилась предыдущая секция
	var CurPage = Page_abs;
	for (; CurPage > 0; CurPage--)
	{
		if (this.Pages[CurPage].EndPos >= StartIndex && this.Pages[CurPage].Pos <= StartIndex)
			break;
	}

	return CurPage + 1;
};
CDocument.prototype.Get_SectionPageNumInfo = function(Page_abs)
{
	var PageNumInfo = this.Get_SectionPageNumInfo2(Page_abs);

	var FP = PageNumInfo.FirstPage;
	var CP = PageNumInfo.CurPage;

	// Первая страница учитывается, только если параграф, идущий сразу за разрывом секции, начинается с новой страницы
	var bCheckFP  = true;
	var SectIndex = PageNumInfo.SectIndex;
	if (SectIndex > 0)
	{
		var CurSectInfo  = this.SectionsInfo.Get_SectPr2(SectIndex);
		var PrevSectInfo = this.SectionsInfo.Get_SectPr2(SectIndex - 1);

		if (CurSectInfo !== PrevSectInfo && c_oAscSectionBreakType.Continuous === CurSectInfo.SectPr.Get_Type() && true === CurSectInfo.SectPr.Compare_PageSize(PrevSectInfo.SectPr))
		{
			var ElementIndex = PrevSectInfo.Index;
			if (ElementIndex < this.Content.length - 1 && true !== this.Content[ElementIndex + 1].IsStartFromNewPage())
				bCheckFP = false;
		}
	}


	var bFirst = ( FP === CP && true === bCheckFP ? true : false );
	var bEven  = ( 0 === CP % 2 ? true : false ); // Четность/нечетность проверяется по текущему номеру страницы в секции, с учетом нумерации в секциях

	return new CSectionPageNumInfo(FP, CP, bFirst, bEven, Page_abs);
};
CDocument.prototype.Get_SectionPageNumInfo2 = function(Page_abs)
{
	var StartIndex = 0;

	// Такое может случится при первом рассчете документа, и когда мы находимся в автофигуре
	if (undefined !== this.Pages[Page_abs])
		StartIndex = this.Pages[Page_abs].Pos;

	var SectIndex      = this.SectionsInfo.Get_Index(StartIndex);
	var StartSectIndex = SectIndex;

	if (0 === SectIndex)
	{
		var PageNumStart = this.SectionsInfo.Get_SectPr2(0).SectPr.Get_PageNum_Start();
		var BT           = this.SectionsInfo.Get_SectPr2(0).SectPr.Get_Type();

		// Нумерация начинается с 1, если начальное значение не задано. Заметим, что в Word нумерация может начинаться и
		// со значения 0, а все отрицательные значения воспринимаются как продолжение нумерации с предыдущей секции.
		if (PageNumStart < 0)
			PageNumStart = 1;

		if ((c_oAscSectionBreakType.OddPage === BT && 0 === PageNumStart % 2) || (c_oAscSectionBreakType.EvenPage === BT && 1 === PageNumStart % 2))
			PageNumStart++;

		return {FirstPage : PageNumStart, CurPage : Page_abs + PageNumStart, SectIndex : StartSectIndex};
	}

	var SectionFirstPage = this.Get_SectionFirstPage(SectIndex, Page_abs);

	var FirstPage    = SectionFirstPage;
	var PageNumStart = this.SectionsInfo.Get_SectPr2(SectIndex).SectPr.Get_PageNum_Start();
	var BreakType    = this.SectionsInfo.Get_SectPr2(SectIndex).SectPr.Get_Type();

	var StartInfo = [];
	StartInfo.push({FirstPage : FirstPage, BreakType : BreakType});

	while ((PageNumStart < 0 || c_oAscSectionBreakType.Continuous === BreakType) && SectIndex > 0)
	{
		SectIndex--;

		FirstPage    = this.Get_SectionFirstPage(SectIndex, Page_abs);
		PageNumStart = this.SectionsInfo.Get_SectPr2(SectIndex).SectPr.Get_PageNum_Start();
		BreakType    = this.SectionsInfo.Get_SectPr2(SectIndex).SectPr.Get_Type();

		StartInfo.splice(0, 0, {FirstPage : FirstPage, BreakType : BreakType});
	}

	// Нумерация начинается с 1, если начальное значение не задано. Заметим, что в Word нумерация может начинаться и
	// со значения 0, а все отрицательные значения воспринимаются как продолжение нумерации с предыдущей секции.
	if (PageNumStart < 0)
		PageNumStart = 1;

	var InfoIndex = 0;
	var InfoCount = StartInfo.length;

	var FP     = StartInfo[0].FirstPage;
	var BT     = StartInfo[0].BreakType;
	var PrevFP = StartInfo[0].FirstPage;

	while (InfoIndex < InfoCount)
	{
		FP = StartInfo[InfoIndex].FirstPage;
		BT = StartInfo[InfoIndex].BreakType;

		PageNumStart += FP - PrevFP;
		PrevFP = FP;

		if ((c_oAscSectionBreakType.OddPage === BT && 0 === PageNumStart % 2) || (c_oAscSectionBreakType.EvenPage === BT && 1 === PageNumStart % 2))
			PageNumStart++;

		InfoIndex++;
	}

	if (FP > Page_abs)
		Page_abs = FP;

	var _FP = PageNumStart;
	var _CP = PageNumStart + Page_abs - FP;	// TODO: Здесь есть баг с рассчетом (чтобы его поправить добавил следующий комментарий,
											// но такой рассчет оказался неверным)
											// + 1 потому что FP начинает считать от 1, а Page_abs от 0

	return {FirstPage : _FP, CurPage : _CP, SectIndex : StartSectIndex};
};
CDocument.prototype.Get_SectionHdrFtr = function(Page_abs, _bFirst, _bEven)
{
	var StartIndex = this.Pages[Page_abs].Pos;
	var SectIndex  = this.SectionsInfo.Get_Index(StartIndex);
	var CurSectPr  = this.SectionsInfo.Get_SectPr2(SectIndex).SectPr;

	var bEven  = ( true === _bEven && true === EvenAndOddHeaders ? true : false );
	var bFirst = ( true === _bFirst && true === CurSectPr.TitlePage ? true : false );

	var CurSectIndex = SectIndex;

	// Ищем верхний и нижний колонтитулы. Если они не находятся в текущей секции, тогда ищем в предыдущей.
	var Header = null, Footer = null;
	while (CurSectIndex >= 0)
	{
		var SectPr = this.SectionsInfo.Get_SectPr2(CurSectIndex).SectPr;

		if (null === Header)
		{
			if (true === bFirst)
				Header = SectPr.Get_Header_First();
			else if (true === bEven)
				Header = SectPr.Get_Header_Even();
			else
				Header = SectPr.Get_Header_Default();
		}

		if (null === Footer)
		{
			if (true === bFirst)
				Footer = SectPr.Get_Footer_First();
			else if (true === bEven)
				Footer = SectPr.Get_Footer_Even();
			else
				Footer = SectPr.Get_Footer_Default();
		}

		if (null !== Header && null !== Footer)
			break;

		CurSectIndex--;
	}

	return {Header : Header, Footer : Footer, SectPr : CurSectPr};
};
CDocument.prototype.Create_SectionHdrFtr = function(Type, PageIndex)
{
	// Данная функция используется, когда у нас нет колонтитула вообще. Это значит, что его нет ни в 1 секции. Следовательно,
	// создаем колонтитул в первой секции, а в остальных он будет повторяться. По текущей секции нам надо будет
	// определить какой конкретно колонтитул мы собираемся создать.

	var SectionPageInfo = this.Get_SectionPageNumInfo(PageIndex);

	var _bFirst = SectionPageInfo.bFirst;
	var _bEven  = SectionPageInfo.bEven;

	var StartIndex = this.Pages[PageIndex].Pos;
	var SectIndex  = this.SectionsInfo.Get_Index(StartIndex);
	var CurSectPr  = this.SectionsInfo.Get_SectPr2(SectIndex).SectPr;

	var bEven  = ( true === _bEven && true === EvenAndOddHeaders ? true : false );
	var bFirst = ( true === _bFirst && true === CurSectPr.TitlePage ? true : false );

	var SectPr = this.SectionsInfo.Get_SectPr2(0).SectPr;
	var HdrFtr = new CHeaderFooter(this.HdrFtr, this, this.DrawingDocument, Type);

	if (hdrftr_Header === Type)
	{
		if (true === bFirst)
			SectPr.Set_Header_First(HdrFtr);
		else if (true === bEven)
			SectPr.Set_Header_Even(HdrFtr);
		else
			SectPr.Set_Header_Default(HdrFtr);
	}
	else
	{
		if (true === bFirst)
			SectPr.Set_Footer_First(HdrFtr);
		else if (true === bEven)
			SectPr.Set_Footer_Even(HdrFtr);
		else
			SectPr.Set_Footer_Default(HdrFtr);
	}

	return HdrFtr;
};
CDocument.prototype.On_SectionChange = function(_SectPr)
{
	var Index = this.SectionsInfo.Find(_SectPr);
	if (-1 === Index)
		return;

	var SectPr  = null;
	var HeaderF = null, HeaderD = null, HeaderE = null, FooterF = null, FooterD = null, FooterE = null;

	while (Index >= 0)
	{
		SectPr = this.SectionsInfo.Get_SectPr2(Index).SectPr;

		if (null === HeaderF)
			HeaderF = SectPr.Get_Header_First();

		if (null === HeaderD)
			HeaderD = SectPr.Get_Header_Default();

		if (null === HeaderE)
			HeaderE = SectPr.Get_Header_Even();

		if (null === FooterF)
			FooterF = SectPr.Get_Footer_First();

		if (null === FooterD)
			FooterD = SectPr.Get_Footer_Default();

		if (null === FooterE)
			FooterE = SectPr.Get_Footer_Even();

		Index--;
	}

	if (null !== HeaderF)
		HeaderF.Refresh_RecalcData_BySection(_SectPr);

	if (null !== HeaderD)
		HeaderD.Refresh_RecalcData_BySection(_SectPr);

	if (null !== HeaderE)
		HeaderE.Refresh_RecalcData_BySection(_SectPr);

	if (null !== FooterF)
		FooterF.Refresh_RecalcData_BySection(_SectPr);

	if (null !== FooterD)
		FooterD.Refresh_RecalcData_BySection(_SectPr);

	if (null !== FooterE)
		FooterE.Refresh_RecalcData_BySection(_SectPr);
};
CDocument.prototype.Create_HdrFtrWidthPageNum = function(PageIndex, AlignV, AlignH)
{
	// Определим четность страницы и является ли она первой в данной секции. Заметим, что четность страницы
	// отсчитывается от начала текущей секции и не зависит от настроек нумерации страниц для данной секции.
	var SectionPageInfo = this.Get_SectionPageNumInfo(PageIndex);

	var bFirst = SectionPageInfo.bFirst;
	var bEven  = SectionPageInfo.bEven;

	// Запросим нужный нам колонтитул
	var HdrFtr = this.Get_SectionHdrFtr(PageIndex, bFirst, bEven);

	switch (AlignV)
	{
		case hdrftr_Header :
		{
			var Header = HdrFtr.Header;

			if (null === Header)
				Header = this.Create_SectionHdrFtr(hdrftr_Header, PageIndex);

			Header.AddPageNum(AlignH);

			break;
		}

		case hdrftr_Footer :
		{
			var Footer = HdrFtr.Footer;

			if (null === Footer)
				Footer = this.Create_SectionHdrFtr(hdrftr_Footer, PageIndex);

			Footer.AddPageNum(AlignH);

			break;
		}
	}

	this.Recalculate();
};
CDocument.prototype.GetCurrentSectionPr = function()
{
	var oSectPr = this.Controller.GetCurrentSectionPr();
	if (null === oSectPr)
		return this.controller_GetCurrentSectionPr();

	return oSectPr;
};
CDocument.prototype.GetFirstElementInSection = function(SectionIndex)
{
	if (SectionIndex <= 0)
		return this.Content[0] ? this.Content[0] : null;

	var nElementPos = this.SectionsInfo.Get_SectPr2(SectionIndex - 1).Index + 1;
	return this.Content[nElementPos] ? this.Content[nElementPos] : null;
};
CDocument.prototype.GetSectionIndexByElementIndex = function(ElementIndex)
{
	return this.SectionsInfo.Get_Index(ElementIndex);
};

/**
 * Определяем использовать ли заливку текста в особых случаях, когда вызывается заливка параграфа.
 * @param bUse
 */
CDocument.prototype.Set_UseTextShd = function(bUse)
{
	this.UseTextShd = bUse;
};
CDocument.prototype.Recalculate_FromStart = function(bUpdateStates)
{
	var RecalculateData = {
		Inline   : {Pos : 0, PageNum : 0},
		Flow     : [],
		HdrFtr   : [],
		Drawings : {All : true, Map : {}}
	};

	this.Reset_RecalculateCache();
	this.Recalculate(false, false, RecalculateData);

	if (true === bUpdateStates)
	{
		this.Document_UpdateInterfaceState();
		this.Document_UpdateSelectionState();
	}
};
CDocument.prototype.Register_Field = function(oField)
{
	this.FieldsManager.Register_Field(oField);
};
CDocument.prototype.Is_MailMergePreviewResult = function()
{
	return this.MailMergePreview;
};
CDocument.prototype.Is_HighlightMailMergeFields = function()
{
	return this.MailMergeFieldsHighlight;
};
CDocument.prototype.CompareDrawingsLogicPositions = function(Drawing1, Drawing2)
{
	var ParentPara1 = Drawing1.GetParagraph();
	var ParentPara2 = Drawing2.GetParagraph();

	if (!ParentPara1 || !ParentPara2 || !ParentPara1.Parent || !ParentPara2.Parent)
		return 0;

	var TopDocument1 = ParentPara1.Parent.Is_TopDocument(true);
	var TopDocument2 = ParentPara2.Parent.Is_TopDocument(true);

	if (TopDocument1 !== TopDocument2 || !TopDocument1)
		return 0;

	var TopElement1 = ParentPara1.GetTopElement();
	var TopElement2 = ParentPara2.GetTopElement();

	if (!TopElement1 || !TopElement2)
		return 0;

	var TopIndex1 = TopElement1.Get_Index();
	var TopIndex2 = TopElement2.Get_Index();

	if (TopIndex1 < TopIndex2)
		return 1;
	else if (TopIndex1 > TopIndex2)
		return -1;

	if (undefined !== TopDocument1.Content[TopIndex1])
	{
		var CompareEngine = new CDocumentCompareDrawingsLogicPositions(Drawing1, Drawing2);
		TopDocument1.Content[TopIndex1].CompareDrawingsLogicPositions(CompareEngine);
		return CompareEngine.Result;
	}

	return 0;
};
CDocument.prototype.GetTopElement = function()
{
	return null;
};
CDocument.prototype.private_StopSelection = function()
{
	this.Selection.Start = false;
};
CDocument.prototype.private_UpdateCurPage = function()
{
	if (true === this.TurnOffRecalcCurPos)
		return;

	this.private_CheckCurPage();
};
CDocument.prototype.private_UpdateCursorXY = function(bUpdateX, bUpdateY)
{
	this.private_UpdateCurPage();

	var NewCursorPos = null;

	if (true !== this.IsSelectionUse() || true === this.IsSelectionEmpty())
	{
		NewCursorPos = this.Controller.RecalculateCurPos(bUpdateX, bUpdateY);
		if (NewCursorPos && NewCursorPos.Transform)
		{
			var x = NewCursorPos.Transform.TransformPointX(NewCursorPos.X, NewCursorPos.Y);
			var y = NewCursorPos.Transform.TransformPointY(NewCursorPos.X, NewCursorPos.Y);

			NewCursorPos.X = x;
			NewCursorPos.Y = y;
		}
	}
	else
	{
		// Обновляем всегда по концу селекта
		var SelectionBounds = this.GetSelectionBounds();
		if (null !== SelectionBounds)
		{
			NewCursorPos = {};
			if (-1 === SelectionBounds.Direction)
			{
				NewCursorPos.X = SelectionBounds.Start.X;
				NewCursorPos.Y = SelectionBounds.Start.Y;

				if (this.CurPage < SelectionBounds.Start.Page)
					NewCursorPos.Y = this.Pages[this.CurPage].Height;
			}
			else
			{
				NewCursorPos.X = SelectionBounds.End.X + SelectionBounds.End.W;
				NewCursorPos.Y = SelectionBounds.End.Y + SelectionBounds.End.H;

				if (this.CurPage > SelectionBounds.End.Page)
					NewCursorPos.Y = 0;
			}
		}
	}

	if (null === NewCursorPos || undefined === NewCursorPos)
		return;

	if (bUpdateX)
		this.CurPos.RealX = NewCursorPos.X;

	if (bUpdateY)
		this.CurPos.RealY = NewCursorPos.Y;

	if (true === this.Selection.Use && true !== this.Selection.Start)
		this.private_OnSelectionEnd();
};
CDocument.prototype.private_MoveCursorDown = function(StartX, StartY, AddToSelect)
{
	var StartPage = this.CurPage;
	var CurY      = StartY;

	// Если данная страница еще не успела пересчитаться, тогда не даем смещаться
	if (StartPage >= this.Pages.length)
		return true;

	var PageH = this.Pages[this.CurPage].Height;

	this.TurnOff_InterfaceEvents();
	this.CheckEmptyElementsOnSelection = false;

	var Result = false;
	while (true)
	{
		CurY += 0.1;

		if (CurY > PageH || this.CurPage > StartPage)
		{
			this.CurPage = StartPage;
			if (this.Pages.length - 1 <= this.CurPage)
			{
				Result = false;
				break;
			}
			else
			{
				this.CurPage++;
				StartY = 0;

				var NewPage = this.CurPage;
				var bBreak = false;
				while (true)
				{
					this.MoveCursorToXY(StartX, StartY, AddToSelect);
					this.private_UpdateCursorXY(false, true);

					if (this.CurPage < NewPage)
					{
						StartY += 0.1;
						if (StartY > this.Pages[NewPage].Height)
						{
							NewPage++;
							if (this.Pages.length - 1 < NewPage)
							{
								Result = false;
								break;
							}

							StartY = 0;
						}
						else
						{
							StartY += 0.1;
						}
						this.CurPage = NewPage;
					}
					else
					{
						Result = true;
						bBreak = true;
						break;
					}
				}

				if (false === Result || true === bBreak)
					break;

				CurY = StartY;
			}
		}


		this.MoveCursorToXY(StartX, CurY, AddToSelect);
		this.private_UpdateCursorXY(false, true);

		if (this.CurPos.RealY > StartY + 0.001)
		{
			Result = true;
			break;
		}
	}

	this.CheckEmptyElementsOnSelection = true;
	this.TurnOn_InterfaceEvents(true);
	return Result;
};
CDocument.prototype.private_MoveCursorUp = function(StartX, StartY, AddToSelect)
{
	var StartPage = this.CurPage;
	var CurY      = StartY;

	// Если данная страница еще не успела пересчитаться, тогда не даем смещаться
	if (StartPage >= this.Pages.length)
		return true;

	var PageH = this.Pages[this.CurPage].Height;

	this.TurnOff_InterfaceEvents();
	this.CheckEmptyElementsOnSelection = false;

	var Result = false;
	while (true)
	{
		CurY -= 0.1;

		if (CurY < 0 || this.CurPage < StartPage)
		{
			this.CurPage = StartPage;
			if (0 === this.CurPage)
			{
				Result = false;
				break;
			}
			else
			{
				this.CurPage--;
				StartY = this.Pages[this.CurPage].Height;

				var NewPage = this.CurPage;
				var bBreak  = false;
				while (true)
				{
					this.MoveCursorToXY(StartX, StartY, AddToSelect);
					this.private_UpdateCursorXY(false, true);

					if (this.CurPage > NewPage)
					{
						this.CurPage = NewPage;
						StartY -= 0.1;

						if (StartY < 0)
						{
							// Защита от полностью пустой страницы
							if (0 === this.CurPage)
							{
								Result = false;
								bBreak = true;
								break;
							}
							else
							{
								this.CurPage--;
								StartY = this.Pages[this.CurPage].Height;

								NewPage = this.CurPage;
							}
						}
					}
					else
					{
						Result = true;
						bBreak = true;
						break;
					}
				}

				if (false === Result || true === bBreak)
					break;

				CurY = StartY;
			}
		}

		this.MoveCursorToXY(StartX, CurY, AddToSelect);
		this.private_UpdateCursorXY(false, true);

		if (this.CurPos.RealY < StartY - 0.001)
		{
			Result = true;
			break;
		}
	}

	this.CheckEmptyElementsOnSelection = true;
	this.TurnOn_InterfaceEvents(true);
	return Result;
};
CDocument.prototype.MoveCursorPageDown = function(AddToSelect, NextPage)
{
	if (this.Pages.length <= 0)
		return;

	if (true === this.IsSelectionUse() && true !== AddToSelect)
		this.MoveCursorRight(false, false);

	var bStopSelection = false;
	if (true !== this.IsSelectionUse() && true === AddToSelect && true !== NextPage)
	{
		bStopSelection = true;
		this.StartSelectionFromCurPos();
	}

	this.private_UpdateCursorXY(false, true);
	var Result = this.private_MoveCursorPageDown(this.CurPos.RealX, this.CurPos.RealY, AddToSelect, NextPage);

	if (true === AddToSelect && true !== NextPage && true !== Result)
		this.MoveCursorToEndPos(true);

	if (bStopSelection)
		this.private_StopSelection();
};
CDocument.prototype.private_MoveCursorPageDown = function(StartX, StartY, AddToSelect, NextPage)
{
	if (this.Pages.length <= 0)
		return true;

	var Dy        = 0;
	var StartPage = this.CurPage;
	if (NextPage)
	{
		if (this.CurPage >= this.Pages.length - 1)
		{
			this.MoveCursorToXY(0, 0, false);
			this.private_UpdateCursorXY(false, true);
			return;
		}

		this.CurPage++;
		StartX = 0;
		StartY = 0;
	}
	else
	{
		if (this.CurPage >= this.Pages.length)
		{
			this.CurPage    = this.Pages.length - 1;
			var LastElement = this.Content[this.Pages[this.CurPage].EndPos];
			Dy              = LastElement.GetPageBounds(LastElement.GetPagesCount() - 1).Bottom;
			StartPage       = this.CurPage;
		}
		else
		{
			Dy = this.DrawingDocument.GetVisibleMMHeight();
			if (StartY + Dy > this.Get_PageLimits(this.CurPage).YLimit)
			{
				this.CurPage++;
				var PageH = this.Get_PageLimits(this.CurPage).YLimit;
				Dy -= PageH - StartY;
				StartY    = 0;
				while (Dy > PageH)
				{
					Dy -= PageH;
					this.CurPage++;
				}

				if (this.CurPage >= this.Pages.length)
				{
					this.CurPage    = this.Pages.length - 1;
					var LastElement = this.Content[this.Pages[this.CurPage].EndPos];
					Dy              = LastElement.GetPageBounds(LastElement.GetPagesCount() - 1).Bottom;
				}

				StartPage = this.CurPage;
			}
		}
	}

	this.MoveCursorToXY(StartX, StartY + Dy, AddToSelect);
	this.private_UpdateCursorXY(false, true);

	if (this.CurPage > StartPage || (this.CurPos.RealY > StartY + 0.001 && this.CurPage === StartPage))
		return true;

	return this.private_MoveCursorDown(this.CurPos.RealX, this.CurPos.RealY, AddToSelect);
};
CDocument.prototype.MoveCursorPageUp = function(AddToSelect, PrevPage)
{
	if (this.Pages.length <= 0)
		return;

	if (true === this.IsSelectionUse() && true !== AddToSelect)
		this.MoveCursorRight(false, false);

	var bStopSelection = false;
	if (true !== this.IsSelectionUse() && true === AddToSelect && true !== PrevPage)
	{
		bStopSelection = true;
		this.StartSelectionFromCurPos();
	}

	this.private_UpdateCursorXY(false, true);
	var Result = this.private_MoveCursorPageUp(this.CurPos.RealX, this.CurPos.RealY, AddToSelect, PrevPage);

	if (true === AddToSelect && true !== PrevPage && true !== Result)
		this.MoveCursorToEndPos(true);

	if (bStopSelection)
		this.private_StopSelection();
};
CDocument.prototype.private_MoveCursorPageUp = function(StartX, StartY, AddToSelect, PrevPage)
{
	if (this.Pages.length <= 0)
		return true;

	if (this.CurPage >= this.Pages.length)
	{
		this.CurPage    = this.Pages.length - 1;
		var LastElement = this.Content[this.Pages[this.CurPage].EndPos];
		StartY          = LastElement.GetPageBounds(LastElement.GetPagesCount() - 1).Bottom;
	}

	var Dy        = 0;
	var StartPage = this.CurPage;
	if (PrevPage)
	{
		if (this.CurPage <= 0)
		{
			this.MoveCursorToXY(0, 0, false);
			this.private_UpdateCursorXY(false, true);
			return;
		}

		this.CurPage--;
		StartX = 0;
		StartY = 0;
	}
	else
	{
		Dy = this.DrawingDocument.GetVisibleMMHeight();
		if (StartY - Dy < 0)
		{
			this.CurPage--;
			var PageH = this.Get_PageLimits(this.CurPage).YLimit;

			Dy -= StartY;
			StartY = PageH;
			while (Dy > PageH)
			{
				Dy -= PageH;
				this.CurPage--;
			}

			if (this.CurPage < 0)
			{
				this.CurPage = 0;
				var oElement = this.Content[0];
				Dy           = PageH - oElement.GetPageBounds(oElement.GetPagesCount() - 1).Top;
			}

			StartPage = this.CurPage;
		}
	}

	this.MoveCursorToXY(StartX, StartY - Dy, AddToSelect);
	this.private_UpdateCursorXY(false, true);

	if (this.CurPage < StartPage || (this.CurPos.RealY < StartY - 0.001 && this.CurPage === StartPage))
		return true;

	return this.private_MoveCursorUp(this.CurPos.RealX, this.CurPos.RealY, AddToSelect);
};
CDocument.prototype.private_ProcessTemplateReplacement = function(TemplateReplacementData)
{
	for (var Id in TemplateReplacementData)
	{
		this.Search(Id, {MatchCase : true}, false);
		this.SearchEngine.Replace_All(TemplateReplacementData[Id], false);
	}
};
CDocument.prototype.Reset_WordSelection = function()
{
	this.Selection.WordSelected = false;
};
CDocument.prototype.Set_WordSelection = function()
{
	this.Selection.WordSelected = true;
};
CDocument.prototype.Is_WordSelection = function()
{
	return this.Selection.WordSelected;
};
CDocument.prototype.Get_EditingType = function()
{
	return this.EditingType;
};
CDocument.prototype.Set_EditingType = function(EditingType)
{
	this.EditingType = EditingType;
};
CDocument.prototype.Is_TrackRevisions = function()
{
	return this.TrackRevisions;
};
CDocument.prototype.Get_TrackRevisionsManager = function()
{
	return this.TrackRevisionsManager;
};
CDocument.prototype.Start_SilentMode = function()
{
	this.TurnOff_Recalculate();
	this.TurnOff_InterfaceEvents();
	this.TurnOff_RecalculateCurPos();
};
CDocument.prototype.End_SilentMode = function(bUpdate)
{
	this.TurnOn_Recalculate(bUpdate);
	this.TurnOn_RecalculateCurPos(bUpdate);
	this.TurnOn_InterfaceEvents(bUpdate);
};
/**
 * Начинаем селект с текущей точки. Если селект уже есть, тогда ничего не делаем.
 */
CDocument.prototype.StartSelectionFromCurPos = function()
{
	if (true === this.IsSelectionUse())
		return true;

	this.Selection.Use   = true;
	this.Selection.Start = false;

	this.Controller.StartSelectionFromCurPos();
};
CDocument.prototype.Is_TrackingDrawingObjects = function()
{
	return this.DrawingObjects.Check_TrackObjects();
};
CDocument.prototype.Add_ChangedStyle = function(arrStylesId)
{
	for (var nIndex = 0, nCount = arrStylesId.length; nIndex < nCount; nIndex++)
	{
		this.ChangedStyles[arrStylesId[nIndex]] = true;
	}
};
CDocument.prototype.Document_UpdateStylesPanel = function()
{
	if (0 !== this.TurnOffPanelStyles)
		return;

	var bNeedUpdate = false;
	for (var StyleId in this.ChangedStyles)
	{
		bNeedUpdate = true;
		break;
	}

	this.ChangedStyles = {};

	if (true === bNeedUpdate)
	{
		editor.GenerateStyles();
	}
};
CDocument.prototype.LockPanelStyles = function()
{
	this.TurnOffPanelStyles++;
};
CDocument.prototype.UnlockPanelStyles = function(isUpdate)
{
	this.TurnOffPanelStyles = Math.max(0, this.TurnOffPanelStyles - 1);

	if (true === isUpdate)
		this.Document_UpdateStylesPanel();
};
CDocument.prototype.GetAllParagraphs = function(Props, ParaArray)
{
	if (Props && true === Props.OnlyMainDocument && true === Props.All && null !== this.AllParagraphsList)
		return this.AllParagraphsList;

	if (!ParaArray)
		ParaArray = [];

	if (true === Props.OnlyMainDocument)
	{
		var Count = this.Content.length;
		for (var Index = 0; Index < Count; Index++)
		{
			var Element = this.Content[Index];
			Element.GetAllParagraphs(Props, ParaArray);
		}
	}
	else
	{
		this.SectionsInfo.GetAllParagraphs(Props, ParaArray);

		var Count = this.Content.length;
		for (var Index = 0; Index < Count; Index++)
		{
			var Element = this.Content[Index];
			Element.GetAllParagraphs(Props, ParaArray);
		}

		this.Footnotes.GetAllParagraphs(Props, ParaArray);
	}

	if (Props && true === Props.OnlyMainDocument && true === Props.All)
		this.AllParagraphsList = ParaArray;

	return ParaArray;
};
CDocument.prototype.TurnOffHistory = function()
{
	this.History.TurnOff();
	this.TableId.TurnOff();
};
CDocument.prototype.TurnOnHistory = function()
{
	this.TableId.TurnOn();
	this.History.TurnOn();
};
CDocument.prototype.Get_SectPr = function(Index)
{
	return this.SectionsInfo.Get_SectPr(Index).SectPr;
};
CDocument.prototype.Add_ToContent = function(Pos, Item)
{
	this.Internal_Content_Add(Pos, Item);
};
CDocument.prototype.Remove_FromContent = function(Pos, Count)
{
	this.Internal_Content_Remove(Pos, Count);
};
CDocument.prototype.Concat_Paragraphs = function(Pos)
{
	if (Pos < this.Content.length - 1 && type_Paragraph === this.Content[Pos].Get_Type() && type_Paragraph === this.Content[Pos + 1].Get_Type())
	{
		var Para1 = this.Content[Pos];
		var Para2 = this.Content[Pos + 1];

		var OldSelectionStartPos = this.Selection.StartPos;
		var OldSelectionEndPos   = this.Selection.EndPos;
		var OldCurPos            = this.CurPos.ContentPos;

		Para1.Concat(Para2);
		this.Remove_FromContent(Pos + 1, 1);

		if (OldCurPos > Pos)
			this.CurPos.ContentPos = OldCurPos - 1;

		if (OldSelectionStartPos > Pos)
			this.Selection.StartPos = OldSelectionStartPos - 1;

		if (OldSelectionEndPos > Pos)
			this.Selection.EndPos = OldSelectionEndPos - 1;
	}
};
CDocument.prototype.Set_FastCollaborativeEditing = function(isOn)
{
	this.CollaborativeEditing.Set_Fast(isOn);

	if (c_oAscCollaborativeMarksShowType.LastChanges === this.Api.GetCollaborativeMarksShowType())
		this.Api.SetCollaborativeMarksShowType(c_oAscCollaborativeMarksShowType.All);
};
CDocument.prototype.Continue_FastCollaborativeEditing = function()
{
	if (true === this.CollaborativeEditing.Get_GlobalLock())
	{
		if (this.Api.forceSaveUndoRequest)
			this.Api.asc_Save(true);

		return;
	}

	if (this.Api.isLongAction())
		return;

	if (true !== this.CollaborativeEditing.Is_Fast() || true === this.CollaborativeEditing.Is_SingleUser())
		return;

	if (true === this.IsMovingTableBorder() || true === this.Api.isStartAddShape || this.DrawingObjects.checkTrackDrawings() || this.Api.isOpenedChartFrame)
		return;

	var HaveChanges = this.History.Have_Changes(true);
	if (true !== HaveChanges && (true === this.CollaborativeEditing.Have_OtherChanges() || 0 !== this.CollaborativeEditing.getOwnLocksLength()))
	{
		// Принимаем чужие изменения. Своих нет, но функцию отсылки надо вызвать, чтобы снять локи.
		this.CollaborativeEditing.Apply_Changes();
		this.CollaborativeEditing.Send_Changes();
	}
	else if (true === HaveChanges || true === this.CollaborativeEditing.Have_OtherChanges())
	{
		this.Api.asc_Save(true);
	}

	var CurTime = new Date().getTime();
	if (true === this.NeedUpdateTargetForCollaboration && (CurTime - this.LastUpdateTargetTime > 1000))
	{
		this.NeedUpdateTargetForCollaboration = false;
		if (true !== HaveChanges)
		{
			var CursorInfo = this.History.Get_DocumentPositionBinary();
			if (null !== CursorInfo)
			{
				this.Api.CoAuthoringApi.sendCursor(CursorInfo);
				this.LastUpdateTargetTime = CurTime;
			}
		}
		else
		{
			this.LastUpdateTargetTime = CurTime;
		}
	}
};
CDocument.prototype.Save_DocumentStateBeforeLoadChanges = function()
{
	var State = {};

	State.CurPos =
	{
		X     : this.CurPos.X,
		Y     : this.CurPos.Y,
		RealX : this.CurPos.RealX,
		RealY : this.CurPos.RealY,
		Type  : this.CurPos.Type
	};

	State.Selection =
	{
		Start          : this.Selection.Start,
		Use            : this.Selection.Use,
		Flag           : this.Selection.Flag,
		UpdateOnRecalc : this.Selection.UpdateOnRecalc,
		DragDrop       : {
			Flag : this.Selection.DragDrop.Flag,
			Data : null === this.Selection.DragDrop.Data ? null : {
				X       : this.Selection.DragDrop.Data.X,
				Y       : this.Selection.DragDrop.Data.Y,
				PageNum : this.Selection.DragDrop.Data.PageNum
			}
		}
	};

	State.SingleCell = this.GetSelectedElementsInfo().Get_SingleCell();
	State.Pos        = [];
	State.StartPos   = [];
	State.EndPos     = [];

	this.Controller.SaveDocumentStateBeforeLoadChanges(State);
	this.RemoveSelection();
	return State;
};
CDocument.prototype.Load_DocumentStateAfterLoadChanges = function(State)
{
	this.RemoveSelection();

	this.CurPos.X     = State.CurPos.X;
	this.CurPos.Y     = State.CurPos.Y;
	this.CurPos.RealX = State.CurPos.RealX;
	this.CurPos.RealY = State.CurPos.RealY;
	this.Set_DocPosType(State.CurPos.Type);

	this.Selection.Start          = State.Selection.Start;
	this.Selection.Use            = State.Selection.Use;
	this.Selection.Flag           = State.Selection.Flag;
	this.Selection.UpdateOnRecalc = State.Selection.UpdateOnRecalc;
	this.Selection.DragDrop.Flag  = State.Selection.DragDrop.Flag;
	this.Selection.DragDrop.Data  = State.Selection.DragDrop.Data === null ? null : {
		X       : State.Selection.DragDrop.Data.X,
		Y       : State.Selection.DragDrop.Data.Y,
		PageNum : State.Selection.DragDrop.Data.PageNum
	};

	this.Controller.RestoreDocumentStateAfterLoadChanges(State);

	if (true === this.Selection.Use && null !== State.SingleCell && undefined !== State.SingleCell)
	{
		var Cell  = State.SingleCell;
		var Table = Cell.Get_Table();
		if (Table && true === Table.Is_UseInDocument())
		{
			Table.Set_CurCell(Cell);
			Table.RemoveSelection();
			Table.SelectTable(c_oAscTableSelectionType.Cell);
		}
	}
};
CDocument.prototype.SaveDocumentState = function()
{
	return this.Save_DocumentStateBeforeLoadChanges();
};
CDocument.prototype.LoadDocumentState = function(oState)
{
	return this.Load_DocumentStateAfterLoadChanges(oState);
};
CDocument.prototype.SetContentSelection = function(StartDocPos, EndDocPos, Depth, StartFlag, EndFlag)
{
	if ((0 === StartFlag && (!StartDocPos[Depth] || this !== StartDocPos[Depth].Class)) || (0 === EndFlag && (!EndDocPos[Depth] || this !== EndDocPos[Depth].Class)))
		return;

	var StartPos = 0, EndPos = 0;
	switch (StartFlag)
	{
		case 0 :
			StartPos = StartDocPos[Depth].Position;
			break;
		case 1 :
			StartPos = 0;
			break;
		case -1:
			StartPos = this.Content.length - 1;
			break;
	}

	switch (EndFlag)
	{
		case 0 :
			EndPos = EndDocPos[Depth].Position;
			break;
		case 1 :
			EndPos = 0;
			break;
		case -1:
			EndPos = this.Content.length - 1;
			break;
	}

	var _StartDocPos = StartDocPos, _StartFlag = StartFlag;
	if (null !== StartDocPos && true === StartDocPos[Depth].Deleted)
	{
		if (StartPos < this.Content.length)
		{
			_StartDocPos = null;
			_StartFlag   = 1;
		}
		else if (StartPos > 0)
		{
			StartPos--;
			_StartDocPos = null;
			_StartFlag   = -1;
		}
		else
		{
			// Такого не должно быть
			return;
		}
	}

	var _EndDocPos = EndDocPos, _EndFlag = EndFlag;
	if (null !== EndDocPos && true === EndDocPos[Depth].Deleted)
	{
		if (EndPos < this.Content.length)
		{
			_EndDocPos = null;
			_EndFlag   = 1;
		}
		else if (EndPos > 0)
		{
			EndPos--;
			_EndDocPos = null;
			_EndFlag   = -1;
		}
		else
		{
			// Такого не должно быть
			return;
		}
	}

	this.Selection.StartPos = StartPos;
	this.Selection.EndPos   = EndPos;

	if (StartPos !== EndPos)
	{
		this.Content[StartPos].SetContentSelection(_StartDocPos, null, Depth + 1, _StartFlag, StartPos > EndPos ? 1 : -1);
		this.Content[EndPos].SetContentSelection(null, _EndDocPos, Depth + 1, StartPos > EndPos ? -1 : 1, _EndFlag);

		var _StartPos = StartPos;
		var _EndPos   = EndPos;
		var Direction = 1;

		if (_StartPos > _EndPos)
		{
			_StartPos = EndPos;
			_EndPos   = StartPos;
			Direction = -1;
		}

		for (var CurPos = _StartPos + 1; CurPos < _EndPos; CurPos++)
		{
			this.Content[CurPos].SelectAll(Direction);
		}
	}
	else
	{
		this.Content[StartPos].SetContentSelection(_StartDocPos, _EndDocPos, Depth + 1, _StartFlag, _EndFlag);
	}
};
CDocument.prototype.GetContentPosition = function(bSelection, bStart, PosArray)
{
	if (undefined === PosArray)
		PosArray = [];

	var Pos = (true === bSelection ? (true === bStart ? this.Selection.StartPos : this.Selection.EndPos) : this.CurPos.ContentPos);
	PosArray.push({Class : this, Position : Pos});

	if (undefined !== this.Content[Pos] && this.Content[Pos].GetContentPosition)
		this.Content[Pos].GetContentPosition(bSelection, bStart, PosArray);

	return PosArray;
};
CDocument.prototype.SetContentPosition = function(DocPos, Depth, Flag)
{
	if (0 === Flag && (!DocPos[Depth] || this !== DocPos[Depth].Class))
		return;

	var Pos = 0;
	switch (Flag)
	{
		case 0 :
			Pos = DocPos[Depth].Position;
			break;
		case 1 :
			Pos = 0;
			break;
		case -1:
			Pos = this.Content.length - 1;
			break;
	}

	var _DocPos = DocPos, _Flag = Flag;
	if (null !== DocPos && true === DocPos[Depth].Deleted)
	{
		if (Pos < this.Content.length)
		{
			_DocPos = null;
			_Flag   = 1;
		}
		else if (Pos > 0)
		{
			Pos--;
			_DocPos = null;
			_Flag   = -1;
		}
		else
		{
			// Такого не должно быть
			return;
		}
	}

	this.CurPos.ContentPos = Pos;

	if (this.Content[Pos])
		this.Content[Pos].SetContentPosition(_DocPos, Depth + 1, _Flag);
};
CDocument.prototype.GetDocumentPositionFromObject = function(PosArray)
{
	if (!PosArray)
		PosArray = [];

	return PosArray;
};
CDocument.prototype.Get_CursorLogicPosition = function()
{
	var nDocPosType = this.Get_DocPosType();
	if (docpostype_HdrFtr === nDocPosType)
	{
		var HdrFtr = this.HdrFtr.Get_CurHdrFtr();
		if (HdrFtr)
		{
			return this.private_GetLogicDocumentPosition(HdrFtr.Get_DocumentContent());
		}
	}
	else if (docpostype_Footnotes === nDocPosType)
	{
		var oFootnote = this.Footnotes.GetCurFootnote();
		if (oFootnote)
			return this.private_GetLogicDocumentPosition(oFootnote);
	}
	else
	{
		return this.private_GetLogicDocumentPosition(this);
	}

	return null;
};
CDocument.prototype.private_GetLogicDocumentPosition = function(LogicDocument)
{
	if (!LogicDocument)
		return null;

	if (docpostype_DrawingObjects === LogicDocument.Get_DocPosType())
	{
		var ParaDrawing    = this.DrawingObjects.getMajorParaDrawing();
		var DrawingContent = this.DrawingObjects.getTargetDocContent();
		if (!ParaDrawing)
			return null;

		if (DrawingContent)
		{
			return DrawingContent.GetContentPosition(DrawingContent.IsSelectionUse(), false);
		}
		else
		{
			var Run = ParaDrawing.Get_Run();
			if (null === Run)
				return null;

			var DrawingInRunPos = Run.Get_DrawingObjectSimplePos(ParaDrawing.Get_Id());
			if (-1 === DrawingInRunPos)
				return null;

			var DocPos = [{Class : Run, Position : DrawingInRunPos}];
			Run.GetDocumentPositionFromObject(DocPos);
			return DocPos;
		}
	}
	else
	{
		return LogicDocument.GetContentPosition(LogicDocument.IsSelectionUse(), false);
	}
};
CDocument.prototype.Get_DocumentPositionInfoForCollaborative = function()
{
	var DocPos = this.Get_CursorLogicPosition();
	if (!DocPos || DocPos.length <= 0)
		return null;

	var Last = DocPos[DocPos.length - 1];
	if (!(Last.Class instanceof ParaRun))
		return null;

	return Last;
};
CDocument.prototype.Update_ForeignCursor = function(CursorInfo, UserId, Show, UserShortId)
{
	if (!this.Api.User)
		return;

	if (UserId === this.Api.CoAuthoringApi.getUserConnectionId())
		return;

	// "" - это означает, что курсор нужно удалить
	if (!CursorInfo || "" === CursorInfo)
	{
		this.Remove_ForeignCursor(UserId);
		return;
	}

	var Changes = new AscCommon.CCollaborativeChanges();
	var Reader  = Changes.GetStream(CursorInfo, 0, CursorInfo.length);

	var RunId    = Reader.GetString2();
	var InRunPos = Reader.GetLong();

	var Run = this.TableId.Get_ById(RunId);
	if (!Run)
	{
		this.Remove_ForeignCursor(UserId);
		return;
	}

	var CursorPos = [{Class : Run, Position : InRunPos}];
	Run.GetDocumentPositionFromObject(CursorPos);
	this.CollaborativeEditing.Add_ForeignCursor(UserId, CursorPos, UserShortId);

	if (true === Show)
		this.CollaborativeEditing.Update_ForeignCursorPosition(UserId, Run, InRunPos, true);
};
CDocument.prototype.Remove_ForeignCursor = function(UserId)
{
	this.CollaborativeEditing.Remove_ForeignCursor(UserId);
};
CDocument.prototype.private_UpdateTargetForCollaboration = function()
{
	this.NeedUpdateTargetForCollaboration = true;
};
CDocument.prototype.Get_HdrFtr = function()
{
	return this.HdrFtr;
};
CDocument.prototype.Get_DrawingDocument = function()
{
	return this.DrawingDocument;
};
CDocument.prototype.GetDrawingDocument = function()
{
	return this.DrawingDocument;
};
CDocument.prototype.Get_Api = function()
{
	return this.Api;
};
CDocument.prototype.GetApi = function()
{
	return this.Api;
};
CDocument.prototype.Get_IdCounter = function()
{
	return this.IdCounter;
};
CDocument.prototype.Get_TableId = function()
{
	return this.TableId;
};
CDocument.prototype.Get_History = function()
{
	return this.History;
};
CDocument.prototype.GetHistory = function()
{
	return this.History;
};
CDocument.prototype.Get_CollaborativeEditing = function()
{
	return this.CollaborativeEditing;
};
CDocument.prototype.GetDocumentOutline = function()
{
	return this.DocumentOutline;
};
CDocument.prototype.private_CorrectDocumentPosition = function()
{
	if (this.CurPos.ContentPos < 0 || this.CurPos.ContentPos >= this.Content.length)
	{
		this.RemoveSelection();
		if (this.CurPos.ContentPos < 0)
		{
			this.CurPos.ContentPos = 0;
			this.Content[0].MoveCursorToStartPos(false);
		}
		else
		{
			this.CurPos.ContentPos = this.Content.length - 1;
			this.Content[this.CurPos.ContentPos].MoveCursorToEndPos(false);
		}
	}
};
CDocument.prototype.private_ToggleParagraphAlignByHotkey = function(Align)
{
	var SelectedInfo = this.GetSelectedElementsInfo();
	var Math         = SelectedInfo.Get_Math();
	if (null !== Math && true !== Math.Is_Inline())
	{
		var MathAlign = Math.Get_Align();
		if (Align !== MathAlign)
		{
			if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
			{
				this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetParagraphAlignHotKey);
				Math.Set_Align(Align);
				this.Recalculate();
				this.Document_UpdateInterfaceState();
			}
		}
	}
	else
	{
		var ParaPr = this.GetCalculatedParaPr();
		if (null != ParaPr)
		{
			if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Paragraph_Properties))
			{
				this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetParagraphAlignHotKey);
				this.SetParagraphAlign(ParaPr.Jc === Align ? (Align === align_Left ? AscCommon.align_Justify : align_Left) : Align);
				this.Document_UpdateInterfaceState();
			}
		}
	}
};
CDocument.prototype.Is_ShowParagraphMarks = function()
{
	return this.Api.ShowParaMarks;
};
CDocument.prototype.Set_ShowParagraphMarks = function(isShow, isRedraw)
{
	this.Api.ShowParaMarks = isShow;

	if (true === isRedraw)
	{
		this.DrawingDocument.ClearCachePages();
		this.DrawingDocument.FirePaint();
	}
};
CDocument.prototype.Get_StyleNameById = function(StyleId)
{
	if (!this.Styles)
		return "";

	var Style = this.Styles.Get(StyleId);
	if (!Style)
		return "";

	return Style.Get_Name();
};
CDocument.prototype.private_GetElementPageIndex = function(ElementPos, PageIndex, ColumnIndex, ColumnsCount)
{
	var Element = this.Content[ElementPos];
	if (!Element)
		return 0;

	var StartPage   = Element.Get_StartPage_Relative();
	var StartColumn = Element.Get_StartColumn();

	return ColumnIndex - StartColumn + (PageIndex - StartPage) * ColumnsCount;
};
CDocument.prototype.private_GetElementPageIndexByXY = function(ElementPos, X, Y, PageIndex)
{
	var Element = this.Content[ElementPos];
	if (!Element)
		return 0;

	var Page = this.Pages[PageIndex];
	if (!Page)
		return 0;

	var PageSection = null;
	for (var SectionIndex = 0, SectionsCount = Page.Sections.length; SectionIndex < SectionsCount; ++SectionIndex)
	{
		if (Page.Sections[SectionIndex].Pos <= ElementPos && ElementPos <= Page.Sections[SectionIndex].EndPos)
		{
			PageSection = Page.Sections[SectionIndex];
			break;
		}
	}

	if (!PageSection)
		return 0;

	var ElementStartPage   = Element.Get_StartPage_Relative();
	var ElementStartColumn = Element.Get_StartColumn();
	var ElementPagesCount  = Element.Get_PagesCount();

	var ColumnsCount = PageSection.Columns.length;
	var StartColumn  = 0;
	var EndColumn    = ColumnsCount - 1;

	if (PageIndex === ElementStartPage)
	{
		StartColumn = Element.Get_StartColumn();
		EndColumn   = Math.min(ElementStartColumn + ElementPagesCount - 1, ColumnsCount - 1);
	}
	else
	{
		StartColumn = 0;
		EndColumn   = Math.min(ElementPagesCount - ElementStartColumn + (PageIndex - ElementStartPage) * ColumnsCount, ColumnsCount - 1);
	}

	// TODO: Разобраться с ситуацией, когда пустые колонки стоят не только в конце
	while (true === PageSection.Columns[EndColumn].Empty && EndColumn > StartColumn)
		EndColumn--;

	var ResultColumn = EndColumn;
	for (var ColumnIndex = StartColumn; ColumnIndex < EndColumn; ++ColumnIndex)
	{
		if (X < (PageSection.Columns[ColumnIndex].XLimit + PageSection.Columns[ColumnIndex + 1].X) / 2)
		{
			ResultColumn = ColumnIndex;
			break;
		}
	}

	return this.private_GetElementPageIndex(ElementPos, PageIndex, ResultColumn, ColumnsCount);
};
CDocument.prototype.Get_DocumentPagePositionByContentPosition = function(ContentPosition)
{
	if (!ContentPosition)
		return null;

	var Para    = null;
	var ParaPos = 0;
	var Count   = ContentPosition.length;
	for (; ParaPos < Count; ++ParaPos)
	{
		var Element = ContentPosition[ParaPos].Class;
		if (Element instanceof Paragraph)
		{
			Para = Element;
			break;
		}
	}

	if (!Para)
		return null;

	var ParaContentPos = new CParagraphContentPos();
	for (var Pos = ParaPos; Pos < Count; ++Pos)
	{
		ParaContentPos.Update(ContentPosition[Pos].Position, Pos - ParaPos);
	}

	var ParaPos = Para.Get_ParaPosByContentPos(ParaContentPos);
	if (!ParaPos)
		return;

	var Result    = new CDocumentPagePosition();
	Result.Page   = Para.Get_AbsolutePage(ParaPos.Page);
	Result.Column = Para.Get_AbsoluteColumn(ParaPos.Page);

	return Result;
};
CDocument.prototype.private_GetPageSectionByContentPosition = function(PageIndex, ContentPosition)
{
	var Page = this.Pages[PageIndex];
	if (!Page || !Page.Sections || Page.Sections.length <= 1)
		return 0;

	var SectionIndex = 0;
	for (var SectionsCount = Page.Sections.length; SectionIndex < SectionsCount; ++SectionIndex)
	{
		var Section = Page.Sections[SectionIndex];
		if (Section.Pos <= ContentPosition && ContentPosition <= Section.EndPos)
			break;
	}

	if (SectionIndex >= Page.Sections.length)
		return 0;

	return SectionIndex;
};
CDocument.prototype.Update_ColumnsMarkupFromRuler = function(NewMarkup)
{
	var SectPr = NewMarkup.SectPr;
	if (!SectPr)
		return;

	if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Document_SectPr))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetColumnsFromRuler);

		SectPr.Set_Columns_EqualWidth(NewMarkup.EqualWidth);
		SectPr.Set_PageMargins(NewMarkup.X, undefined, SectPr.Get_PageWidth() - NewMarkup.R, undefined);
		if (false === NewMarkup.EqualWidth)
		{
			for (var Index = 0, Count = NewMarkup.Cols.length; Index < Count; ++Index)
			{
				SectPr.Set_Columns_Col(Index, NewMarkup.Cols[Index].W, NewMarkup.Cols[Index].Space);
			}
		}
		else
		{
			SectPr.Set_Columns_Space(NewMarkup.Space);
			SectPr.Set_Columns_Num(NewMarkup.Num);
		}

		this.Recalculate();
		this.Document_UpdateSelectionState();
		this.Document_UpdateInterfaceState();
		this.Document_UpdateRulersState();
	}
};
CDocument.prototype.Set_ColumnsProps = function(ColumnsProps)
{
	if (this.IsSelectionUse())
	{
		if (docpostype_DrawingObjects === this.Get_DocPosType())
			return;

		// К селекту мы применяем колонки не так как ворд.
		// Элементы попавшие в селект полностью входят в  новую секцию, даже если они выделены частично.
		
		var nStartPos  = this.Selection.StartPos;
		var nEndPos    = this.Selection.EndPos;
		var nDirection = 1;

		if (nEndPos < nStartPos)
		{
			nStartPos  = this.Selection.EndPos;
			nEndPos    = this.Selection.StartPos;
			nDirection = -1;
		}

		var oStartSectPr = this.SectionsInfo.Get_SectPr(nStartPos).SectPr;
		var oEndSectPr   = this.SectionsInfo.Get_SectPr(nEndPos).SectPr;
		if (!oStartSectPr || !oEndSectPr)
			return;

		if (this.Document_Is_SelectionLocked(AscCommon.changestype_Document_SectPr))
			return;

		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetColumnsProps);

		var oEndParagraph = null;
		if (type_Paragraph !== this.Content[nEndPos].GetType())
		{
			oEndParagraph = new Paragraph(this.DrawingDocument, this);
			this.Add_ToContent(nEndPos + 1, oEndParagraph);
		}
		else
		{
			oEndParagraph = this.Content[nEndPos];
		}

		if (nStartPos > 0
			&& (type_Paragraph !== this.Content[nStartPos - 1].GetType()
			|| !this.Content[nStartPos - 1].Get_SectionPr()))
		{
			var oSectPr = new CSectionPr(this);
			oSectPr.Copy(oStartSectPr, false);

			var oStartParagraph = new Paragraph(this.DrawingDocument, this);
			this.Add_ToContent(nStartPos, oStartParagraph);
			oStartParagraph.Set_SectionPr(oSectPr, true);

			nStartPos++;
			nEndPos++;
		}

		oEndSectPr.Set_Type(c_oAscSectionBreakType.Continuous);
		var oSectPr = new CSectionPr(this);
		oSectPr.Copy(oEndSectPr, false);
		oEndParagraph.Set_SectionPr(oSectPr, true);

		oSectPr.SetColumnProps(ColumnsProps);

		for (var nIndex = nStartPos; nIndex < nEndPos; ++nIndex)
		{
			var oElement = this.Content[nIndex];
			if (type_Paragraph === oElement.GetType())
			{
				var oCurSectPr = oElement.Get_SectionPr();
				if (oCurSectPr)
					oCurSectPr.SetColumnProps(ColumnsProps);
			}
		}

		if (nDirection >= 0)
		{
			this.Selection.StartPos = nStartPos;
			this.Selection.EndPos   = nEndPos;
		}
		else
		{
			this.Selection.StartPos = nEndPos;
			this.Selection.EndPos   = nStartPos;
		}

		this.Recalculate();
		this.Document_UpdateSelectionState();
		this.Document_UpdateInterfaceState();
		this.Document_UpdateRulersState();
	}
	else
	{
		var CurPos = this.CurPos.ContentPos;
		var SectPr = this.SectionsInfo.Get_SectPr(CurPos).SectPr;

		if (!SectPr)
			return;

		if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Document_SectPr))
		{
			this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetColumnsProps);

			SectPr.SetColumnProps(ColumnsProps);

			this.Recalculate();
			this.Document_UpdateSelectionState();
			this.Document_UpdateInterfaceState();
			this.Document_UpdateRulersState();
		}
	}
};
CDocument.prototype.GetTopDocumentContent = function()
{
	return this;
};
CDocument.prototype.private_RecalculateNumbering = function(Elements)
{
	if (true === AscCommon.g_oIdCounter.m_bLoad)
		return;

	for (var Index = 0, Count = Elements.length; Index < Count; ++Index)
	{
		var Element = Elements[Index];
		if (type_Paragraph === Element.Get_Type())
			this.History.Add_RecalcNumPr(Element.GetNumPr());
		else if (type_Paragraph === Element.Get_Type())
		{
			var ParaArray = [];
			Element.GetAllParagraphs({All : true}, ParaArray);

			for (var ParaIndex = 0, ParasCount = ParaArray.length; ParaIndex < ParasCount; ++ParaIndex)
			{
				var Para = ParaArray[ParaIndex];
				this.History.Add_RecalcNumPr(Element.GetNumPr());
			}
		}
	}
};
CDocument.prototype.Set_SectionProps = function(Props)
{
	var CurPos = this.CurPos.ContentPos;
	var SectPr = this.SectionsInfo.Get_SectPr(CurPos).SectPr;

	if (SectPr && false === this.Document_Is_SelectionLocked(AscCommon.changestype_Document_SectPr))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetSectionProps);

		if (undefined !== Props.get_W() || undefined !== Props.get_H())
		{
			var PageW = undefined !== Props.get_W() ? Props.get_W() : SectPr.Get_PageWidth();
			var PageH = undefined !== Props.get_H() ? Props.get_H() : SectPr.Get_PageHeight();
			SectPr.Set_PageSize(PageW, PageH);
		}

		if (undefined !== Props.get_Orientation())
		{
			SectPr.Set_Orientation(Props.get_Orientation(), false);
		}

		if (undefined !== Props.get_LeftMargin() || undefined !== Props.get_TopMargin() || undefined !== Props.get_RightMargin() || undefined !== Props.get_BottomMargin())
		{
			// Внутри функции идет разруливания, если какое то значение undefined
			SectPr.Set_PageMargins(Props.get_LeftMargin(), Props.get_TopMargin(), Props.get_RightMargin(), Props.get_BottomMargin());
		}

		if (undefined !== Props.get_HeaderDistance())
		{
			SectPr.Set_PageMargins_Header(Props.get_HeaderDistance());
		}

		if (undefined !== Props.get_FooterDistance())
		{
			SectPr.Set_PageMargins_Footer(Props.get_FooterDistance());
		}

		if (true === this.History.Is_LastPointEmpty())
		{
			this.History.Remove_LastPoint();
		}
		else
		{
			this.Recalculate();
			this.Document_UpdateSelectionState();
			this.Document_UpdateInterfaceState();
			this.Document_UpdateRulersState();
		}
	}
};
CDocument.prototype.Get_SectionProps = function()
{
	var CurPos = this.CurPos.ContentPos;
	var SectPr = this.SectionsInfo.Get_SectPr(CurPos).SectPr;

	return new Asc.CDocumentSectionProps(SectPr);
};
/**
 * Получаем ширину текущей колонки
 * @returns {number}
 */
CDocument.prototype.GetCurrentColumnWidth = function()
{
	var nCurPos = 0;
	if (this.Controller === this.LogicDocumentController)
		nCurPos = this.Selection.Use ? this.Selection.EndPos : this.CurPos.ContentPos;
	else
		nCurPos = this.CurPos.ContentPos;

	var oSectPr       = this.SectionsInfo.Get_SectPr(nCurPos).SectPr;
	var nColumnsCount = oSectPr.Get_ColumnsCount();

	if (nColumnsCount > 1)
	{
		var oParagraph = this.GetCurrentParagraph();
		if (!oParagraph)
			return 0;

		var nCurrentColumn = oParagraph.Get_CurrentColumn();
		return oSectPr.Get_ColumnWidth(nCurrentColumn);
	}

	return oSectPr.Get_PageWidth() - oSectPr.Get_PageMargin_Right() - oSectPr.Get_PageMargin_Left();
};
CDocument.prototype.Get_FirstParagraph = function()
{
	if (type_Paragraph == this.Content[0].GetType())
		return this.Content[0];
	else if (type_Table == this.Content[0].GetType())
		return this.Content[0].Get_FirstParagraph();

	return null;
};
/**
 * Обработчик нажатия кнопки IncreaseIndent в меню.
 */
CDocument.prototype.IncreaseIndent = function()
{
	if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Paragraph_Properties))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_IncParagraphIndent);
		this.IncreaseDecreaseIndent(true);
		this.Document_UpdateSelectionState();
		this.Document_UpdateInterfaceState();
		this.Recalculate();
	}
};
/**
 * Обработчик нажатия кнопки DecreaseIndent в меню.
 */
CDocument.prototype.DecreaseIndent = function()
{
	if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Paragraph_Properties))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_DecParagraphIndent);
		this.IncreaseDecreaseIndent(false);
		this.Document_UpdateSelectionState();
		this.Document_UpdateInterfaceState();
		this.Recalculate();
	}
};
/**
 * Получаем размеры текущей колонки (используется при вставке изображения).
 */
CDocument.prototype.GetColumnSize = function()
{
	return this.Controller.GetColumnSize();
};
CDocument.prototype.private_OnSelectionEnd = function()
{
	this.Api.sendEvent("asc_onSelectionEnd");
};
CDocument.prototype.AddPageCount = function()
{
	if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddPageCount);
		this.AddToParagraph(new ParaPageCount(this.Pages.length));
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Settings
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.GetCompatibilityMode = function()
{
	return this.Settings.CompatibilityMode;
};
CDocument.prototype.GetSdtGlobalColor = function()
{
	return this.Settings.SdtSettings.Color;
};
CDocument.prototype.SetSdtGlobalColor = function(r, g, b)
{
	var oNewColor = new CDocumentColor(r, g, b);
	if (!oNewColor.Compare(this.Settings.SdtSettings.Color))
	{
		var oNewSettings = this.Settings.SdtSettings.Copy();
		oNewSettings.Color = oNewColor;

		this.History.Add(new CChangesDocumentSdtGlobalSettings(this, this.Settings.SdtSettings, oNewSettings));
		this.Settings.SdtSettings = oNewSettings;

		this.OnChangeSdtGlobalSettings();
	}
};
CDocument.prototype.GetSdtGlobalShowHighlight = function()
{
	return this.Settings.SdtSettings.ShowHighlight;
};
CDocument.prototype.SetSdtGlobalShowHighlight = function(isShow)
{
	if (this.Settings.SdtSettings.ShowHighlight !== isShow)
	{
		var oNewSettings = this.Settings.SdtSettings.Copy();
		oNewSettings.ShowHighlight = isShow;

		this.History.Add(new CChangesDocumentSdtGlobalSettings(this, this.Settings.SdtSettings, oNewSettings));
		this.Settings.SdtSettings = oNewSettings;

		this.OnChangeSdtGlobalSettings();
	}
};
CDocument.prototype.OnChangeSdtGlobalSettings = function()
{
	this.GetApi().sync_OnChangeSdtGlobalSettings();
};
/**
 * Проверяем все ли параметры SdtSettings выставлены по умолчанию
 * @returns {boolean}
 */
CDocument.prototype.IsSdtGlobalSettingsDefault = function()
{
	return this.Settings.SdtSettings.IsDefault();
};
//----------------------------------------------------------------------------------------------------------------------
// Math
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.Set_MathProps = function(MathProps)
{
	var SelectedInfo = this.GetSelectedElementsInfo();
	if (null !== SelectedInfo.Get_Math() && false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetMathProps);

		var ParaMath = SelectedInfo.Get_Math();
		ParaMath.Set_MenuProps(MathProps);

		this.Recalculate();
		this.Document_UpdateSelectionState();
		this.Document_UpdateInterfaceState();
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Statistics (Функции для работы со статистикой)
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.Statistics_Start = function()
{
	this.Statistics.Start();
};
CDocument.prototype.Statistics_GetParagraphsInfo = function()
{
	var Count   = this.Content.length;
	var CurPage = this.Statistics.CurPage;

	var Index    = 0;
	var CurIndex = 0;
	for (Index = this.Statistics.StartPos; Index < Count; ++Index, ++CurIndex)
	{
		var Element = this.Content[Index];
		Element.CollectDocumentStatistics(this.Statistics);

		if (CurIndex > 20)
		{
			this.Statistics.Next_ParagraphsInfo(Index + 1);
			break;
		}
	}

	if (Index >= Count)
		this.Statistics.Stop_ParagraphsInfo();
};
CDocument.prototype.Statistics_GetPagesInfo = function()
{
	this.Statistics.Update_Pages(this.Pages.length);

	if (null !== this.FullRecalc.Id)
	{
		this.Statistics.Next_PagesInfo();
	}
	else
	{
		for (var CurPage = 0, PagesCount = this.Pages.length; CurPage < PagesCount; ++CurPage)
		{
			this.DrawingObjects.documentStatistics(CurPage, this.Statistics);
		}

		this.Statistics.Stop_PagesInfo();
	}
};
CDocument.prototype.Statistics_Stop = function()
{
	this.Statistics.Stop();
};
//----------------------------------------------------------------------------------------------------------------------
// Private
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.EndPreview_MailMergeResult = function(){};
CDocument.prototype.ContinueTrackRevisions = function(){};
CDocument.prototype.Set_TrackRevisions = function(bTrack){};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с составным вводом
//----------------------------------------------------------------------------------------------------------------------
/**
 * Сообщаем о начале составного ввода текста.
 * @returns {boolean} Начался или нет составной ввод.
 */
CDocument.prototype.Begin_CompositeInput = function()
{
	if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content, null, true, this.IsFormFieldEditing()))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_CompositeInput);
		this.DrawingObjects.CreateDocContent();
		this.DrawingDocument.TargetStart();
		this.DrawingDocument.TargetShow();

		if (true === this.IsSelectionUse())
		{
			if (docpostype_DrawingObjects === this.Get_DocPosType() && null === this.DrawingObjects.getTargetDocContent())
				this.RemoveSelection();
			else
				this.Remove(1, true, false, true);
		}

		var oPara = this.GetCurrentParagraph();
		if (!oPara)
		{
			this.History.Remove_LastPoint();
			return false;
		}

		var oRun = oPara.Get_ElementByPos(oPara.Get_ParaContentPos(false, false));
		if (!oRun || !(oRun instanceof ParaRun))
		{
			this.History.Remove_LastPoint();
			return false;
		}

		var oTrackRun = oRun.CheckTrackRevisionsBeforeAdd();
		if (oTrackRun)
		{
			oRun = oTrackRun;
			oRun.Make_ThisElementCurrent();
		}

		this.CompositeInput = {
			Run     : oRun,
			Pos     : oRun.State.ContentPos,
			Length  : 0,
			CanUndo : true
		};

		oRun.Set_CompositeInput(this.CompositeInput);

		return true;
	}

	return false;
};
CDocument.prototype.Replace_CompositeText = function(arrCharCodes)
{
	if (null === this.CompositeInput)
		return;

	this.Create_NewHistoryPoint(AscDFH.historydescription_Document_CompositeInputReplace);
	this.Start_SilentMode();
	this.private_RemoveCompositeText(this.CompositeInput.Length);
	for (var nIndex = 0, nCount = arrCharCodes.length; nIndex < nCount; ++nIndex)
	{
		this.private_AddCompositeText(arrCharCodes[nIndex]);
	}
	this.End_SilentMode(false);

	this.Recalculate();
	this.Document_UpdateSelectionState();
	this.Document_UpdateUndoRedoState();

	this.private_UpdateCursorXY(true, true);

	if (!this.History.CheckUnionLastPoints())
		this.CompositeInput.CanUndo = false;
};
CDocument.prototype.Set_CursorPosInCompositeText = function(nPos)
{
	if (null === this.CompositeInput)
		return;

	var oRun = this.CompositeInput.Run;

	var nInRunPos = Math.max(Math.min(this.CompositeInput.Pos + nPos, this.CompositeInput.Pos + this.CompositeInput.Length, oRun.Content.length), this.CompositeInput.Pos);
	oRun.State.ContentPos = nInRunPos;
	this.Document_UpdateSelectionState();
};
CDocument.prototype.Get_CursorPosInCompositeText = function()
{
	if (null === this.CompositeInput)
		return 0;

	var oRun = this.CompositeInput.Run;
	var nInRunPos = oRun.State.ContentPos;
	var nPos = Math.min(this.CompositeInput.Length, Math.max(0, nInRunPos - this.CompositeInput.Pos));
	return nPos;
};
CDocument.prototype.End_CompositeInput = function()
{
	if (null === this.CompositeInput)
		return;

	var nLen = this.CompositeInput.Length;
	
	var oRun = this.CompositeInput.Run;
	oRun.Set_CompositeInput(null);
	
	if (0 === nLen && true === this.History.CanRemoveLastPoint() && true === this.CompositeInput.CanUndo)
	{
		this.Document_Undo();
		this.History.Clear_Redo();
	}

	this.CompositeInput = null;

    var oController = this.DrawingObjects;
    if(oController)
    {
        var oTargetTextObject = AscFormat.getTargetTextObject(oController);
        if(oTargetTextObject && oTargetTextObject.txWarpStructNoTransform)
        {
            oTargetTextObject.recalcInfo.recalculateTxBoxContent = true;
            oTargetTextObject.recalculateText();
        }
    }

	this.Document_UpdateInterfaceState();

    this.private_UpdateCursorXY(true, true);

	this.DrawingDocument.ClearCachePages();
	this.DrawingDocument.FirePaint();
};
CDocument.prototype.Get_MaxCursorPosInCompositeText = function()
{
	if (null === this.CompositeInput)
		return 0;

	return this.CompositeInput.Length;
};
CDocument.prototype.private_AddCompositeText = function(nCharCode)
{
	var oRun = this.CompositeInput.Run;
	var nPos = this.CompositeInput.Pos + this.CompositeInput.Length;
	var oChar;

	if (para_Math_Run === oRun.Type)
	{
		oChar = new CMathText();
		oChar.add(nCharCode);
	}
	else
	{
		if (32 == nCharCode || 12288 == nCharCode)
			oChar = new ParaSpace();
		else
			oChar = new ParaText(nCharCode);
	}

	oRun.AddToContent(nPos, oChar, true);
	this.CompositeInput.Length++;

	this.Recalculate();
	this.Document_UpdateSelectionState();
};
CDocument.prototype.private_RemoveCompositeText = function(nCount)
{
	var oRun = this.CompositeInput.Run;
	var nPos = this.CompositeInput.Pos + this.CompositeInput.Length;

	var nDelCount = Math.max(0, Math.min(nCount, this.CompositeInput.Length, oRun.Content.length, nPos));
	oRun.Remove_FromContent(nPos - nDelCount, nDelCount, true);
	this.CompositeInput.Length -= nDelCount;

	this.Recalculate();
	this.Document_UpdateSelectionState();
};
CDocument.prototype.Check_CompositeInputRun = function()
{
	if (null === this.CompositeInput)
		return;

	var oRun = this.CompositeInput.Run;
	if (true !== oRun.Is_UseInDocument())
		AscCommon.g_inputContext.externalEndCompositeInput();
};
CDocument.prototype.Is_CursorInsideCompositeText = function()
{
	if (null === this.CompositeInput)
		return false;

	var oCurrentParagraph = this.GetCurrentParagraph();
	if (!oCurrentParagraph)
		return false;

	var oParaPos   = oCurrentParagraph.Get_ParaContentPos(false, false, false);
	var arrClasses = oCurrentParagraph.Get_ClassesByPos(oParaPos);

	if (arrClasses.length <= 0 || arrClasses[arrClasses.length - 1] !== this.CompositeInput.Run)
		return false;

	var nInRunPos = oParaPos.Get(oParaPos.Get_Depth());
	if (nInRunPos >= this.CompositeInput.Pos && nInRunPos <= this.CompositeInput.Pos + this.CompositeInput.Length)
		return true;

	return false;
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы со сносками
//----------------------------------------------------------------------------------------------------------------------
/**
 * Переходим к редактированию сносок на заданной странице. Если сносок на заданной странице нет, тогда ничего не делаем.
 * @param {number} nPageIndex
 * @returns {boolean}
 */
CDocument.prototype.GotoFootnotesOnPage = function(nPageIndex)
{
	if (this.Footnotes.IsEmptyPage(nPageIndex))
		return false;

	this.Set_DocPosType(docpostype_Footnotes);
	this.Footnotes.GotoPage(nPageIndex);
	this.Document_UpdateSelectionState();

	return true;
};
CDocument.prototype.AddFootnote = function(sText)
{
	var nDocPosType = this.Get_DocPosType();
	if (docpostype_Content !== nDocPosType && docpostype_Footnotes !== nDocPosType)
		return;

	if (false === this.Document_Is_SelectionLocked(changestype_Paragraph_Content))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddFootnote);

		var nDocPosType = this.Get_DocPosType();
		if (docpostype_Content === nDocPosType)
		{
			var oFootnote = this.Footnotes.CreateFootnote();
			oFootnote.AddDefaultFootnoteContent(sText);

			if (true === this.IsSelectionUse())
			{
				this.MoveCursorRight(false, false, false);
				this.RemoveSelection();
			}

			if (sText)
				this.AddToParagraph(new ParaFootnoteReference(oFootnote, sText));
			else
				this.AddToParagraph(new ParaFootnoteReference(oFootnote));

			this.Set_DocPosType(docpostype_Footnotes);
			this.Footnotes.Set_CurrentElement(true, 0, oFootnote);
		}
		else if (docpostype_Footnotes === nDocPosType)
		{
			this.Footnotes.AddFootnoteRef();
			this.Recalculate();
		}
	}
};
CDocument.prototype.RemoveAllFootnotes = function()
{
	var nDocPosType = this.Get_DocPosType();

	var oEngine = new CDocumentFootnotesRangeEngine(true);
	oEngine.Init(null, null);

	var arrParagraphs = this.GetAllParagraphs({OnlyMainDocument : true, All : true});
	for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
	{
		arrParagraphs[nIndex].Get_FootnotesList(oEngine);
	}

	var arrFootnotes  = oEngine.GetRange();
	var arrParagraphs = oEngine.GetParagraphs();
	var arrRuns       = oEngine.GetRuns();
	var arrRefs       = oEngine.GetRefs();

	if (arrRuns.length !== arrRefs.length || arrFootnotes.length !== arrRuns.length)
		return;

	if (false === this.Document_Is_SelectionLocked(changestype_None, { Type : changestype_2_ElementsArray_and_Type, Elements : arrParagraphs, CheckType : changestype_Paragraph_Content }, true))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_RemoveAllFootnotes);

		for (var nIndex = 0, nCount = arrFootnotes.length; nIndex < nCount; ++nIndex)
		{
			var oRef = arrRefs[nIndex];
			var oRun = arrRuns[nIndex];

			oRun.RemoveElement(oRef);
		}

		this.Recalculate();

		if (docpostype_Footnotes === nDocPosType)
		{
			this.CurPos.Type = docpostype_Content;
			if (arrRuns.length > 0)
				arrRuns[0].Make_ThisElementCurrent();
		}
	}
};
CDocument.prototype.GotoFootnote = function(isNext)
{
	var nDocPosType = this.Get_DocPosType();

	if (docpostype_Footnotes === nDocPosType)
	{
		if (isNext)
			this.Footnotes.GotoNextFootnote();
		else
			this.Footnotes.GotoPrevFootnote();

		this.Document_UpdateSelectionState();
		this.Document_UpdateInterfaceState();

		return;
	}

	if (docpostype_HdrFtr == this.CurPos.Type)
	{
		this.EndHdrFtrEditing(true);
	}
	else if (docpostype_DrawingObjects === nDocPosType)
	{
		this.DrawingObjects.resetSelection2();
		this.private_UpdateCursorXY(true, true);

		this.CurPos.Type = docpostype_Content;

		this.Document_UpdateInterfaceState();
		this.Document_UpdateSelectionState();
	}

	return this.GotoFootnoteRef(isNext, true);
};
CDocument.prototype.GetFootnotesController = function()
{
	return this.Footnotes;
};
CDocument.prototype.SetFootnotePr = function(oFootnotePr, bApplyToAll)
{
	var nNumStart   = oFootnotePr.get_NumStart();
	var nNumRestart = oFootnotePr.get_NumRestart();
	var nNumFormat  = oFootnotePr.get_NumFormat();
	var nPos        = oFootnotePr.get_Pos();
	if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Document_SectPr))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetFootnotePr);

		if (bApplyToAll)
		{
			for (var nIndex = 0, nCount = this.SectionsInfo.Get_SectionsCount(); nIndex < nCount; ++nIndex)
			{
				var oSectPr = this.SectionsInfo.Get_SectPr2(nIndex).SectPr;
				if (undefined !== nNumStart)
					oSectPr.SetFootnoteNumStart(nNumStart);

				if (undefined !== nNumRestart)
					oSectPr.SetFootnoteNumRestart(nNumRestart);

				if (undefined !== nNumFormat)
					oSectPr.SetFootnoteNumFormat(nNumFormat);

				if (undefined !== nPos)
					oSectPr.SetFootnotePos(nPos);
			}
		}
		else
		{
			var oSectPr = this.GetCurrentSectionPr();
			if (undefined !== nNumStart)
				oSectPr.SetFootnoteNumStart(nNumStart);

			if (undefined !== nNumRestart)
				oSectPr.SetFootnoteNumRestart(nNumRestart);

			if (undefined !== nNumFormat)
				oSectPr.SetFootnoteNumFormat(nNumFormat);

			if (undefined !== nPos)
				oSectPr.SetFootnotePos(nPos);
		}

		this.Recalculate();
	}
};
CDocument.prototype.GetFootnotePr = function()
{
	var oSectPr     = this.GetCurrentSectionPr();
	var oFootnotePr = new Asc.CAscFootnotePr();
	oFootnotePr.put_Pos(oSectPr.GetFootnotePos());
	oFootnotePr.put_NumStart(oSectPr.GetFootnoteNumStart());
	oFootnotePr.put_NumRestart(oSectPr.GetFootnoteNumRestart());
	oFootnotePr.put_NumFormat(oSectPr.GetFootnoteNumFormat());
	return oFootnotePr;
};
CDocument.prototype.IsCursorInFootnote = function()
{
	return (docpostype_Footnotes === this.Get_DocPosType() ? true : false);
};
CDocument.prototype.Get_FootnotesList = function(oFirstFootnote, oLastFootnote)
{
	if (null === oFirstFootnote && null === oLastFootnote && null !== this.AllFootnotesList)
		return this.AllFootnotesList;

	var arrFootnotes = CDocumentContentBase.prototype.Get_FootnotesList.apply(this, arguments);

	if (null === oFirstFootnote && null === oLastFootnote)
		this.AllFootnotesList = arrFootnotes;

	return arrFootnotes;
};
CDocument.prototype.TurnOffCheckChartSelection = function()
{
	if (this.DrawingObjects)
	{
		this.DrawingObjects.TurnOffCheckChartSelection();
	}
};
CDocument.prototype.TurnOnCheckChartSelection = function()
{
	if (this.DrawingObjects)
	{
		this.DrawingObjects.TurnOnCheckChartSelection();
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Функции, которые вызываются из CLogicDocumentController
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.controller_CanUpdateTarget = function()
{
	if (null != this.FullRecalc.Id && this.FullRecalc.StartIndex < this.CurPos.ContentPos)
	{
		return false;
	}
	else if (null !== this.FullRecalc.Id && this.FullRecalc.StartIndex === this.CurPos.ContentPos)
	{
		if (this.IsNumberingSelection())
			return this.Selection.Data.CurPara.CanUpdateTarget(0);

		var nPos         = (true === this.Selection.Use ? this.Selection.EndPos : this.CurPos.ContentPos);
		var oElement     = this.Content[nPos];
		var nElementPage = this.private_GetElementPageIndex(nPos, this.FullRecalc.PageIndex, this.FullRecalc.ColumnIndex, oElement.Get_ColumnsCount());
		return oElement.CanUpdateTarget(nElementPage);
	}

	return true;
};
CDocument.prototype.controller_RecalculateCurPos = function(bUpdateX, bUpdateY)
{
	if (this.controller_CanUpdateTarget())
	{
		if (this.IsNumberingSelection())
			return this.Selection.Data.CurPara.RecalculateCurPos(bUpdateX, bUpdateY);

		var nPos = (true === this.Selection.Use ? this.Selection.EndPos : this.CurPos.ContentPos);
		this.private_CheckCurPage();
		return this.Content[nPos].RecalculateCurPos(bUpdateX, bUpdateY);
	}

	return {X : 0, Y : 0, Height : 0, PageNum : 0, Internal : {Line : 0, Page : 0, Range : 0}, Transform : null};
};
CDocument.prototype.controller_GetCurPage = function()
{
	if (this.IsNumberingSelection())
		return this.Selection.Data.CurPara.Get_CurrentPage_Absolute();

	var Pos = ( true === this.Selection.Use ? this.Selection.EndPos : this.CurPos.ContentPos );
	if (Pos >= 0 && ( null === this.FullRecalc.Id || this.FullRecalc.StartIndex > Pos ))
		return this.Content[Pos].Get_CurrentPage_Absolute();

	return -1;
};
CDocument.prototype.controller_AddNewParagraph = function(bRecalculate, bForceAdd)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	// Сначала удаляем заселекченую часть
	if (true === this.Selection.Use)
	{
		this.Remove(1, true, false, true);
	}

	// Добавляем новый параграф
	var Item = this.Content[this.CurPos.ContentPos];

	// Если мы внутри параграфа, тогда:
	// 1. Если мы в середине параграфа, разделяем данный параграф на 2.
	//    При этом полностью копируем все настройки из исходного параграфа.
	// 2. Если мы в конце данного параграфа, тогда добавляем новый пустой параграф.
	//    Стиль у него проставляем такой какой указан у текущего в Style.Next.
	//    Если при этом у нового параграфа стиль будет такой же как и у старого,
	//    в том числе если стиля нет у обоих, тогда копируем еще все прямые настройки.
	//    (Т.е. если стили разные, а у исходный параграф был параграфом со списком, тогда
	//    новый параграф будет без списка).
	if (type_Paragraph === Item.GetType())
	{
		// Если текущий параграф пустой и с нумерацией, тогда удаляем нумерацию и отступы левый и первой строки
		if (true !== bForceAdd && undefined != Item.GetNumPr() && true === Item.IsEmpty({SkipNewLine : true}) && true === Item.IsCursorAtBegin())
		{
			Item.RemoveNumPr();
			Item.Set_Ind({FirstLine : undefined, Left : undefined, Right : Item.Pr.Ind.Right}, true);
		}
		else
		{
			var ItemReviewType = Item.Get_ReviewType();
			// Создаем новый параграф
			var NewParagraph   = new Paragraph(this.DrawingDocument, this);

			// Проверим позицию в текущем параграфе
			if (true === Item.IsCursorAtEnd())
			{
				var StyleId = Item.Style_Get();
				var NextId  = undefined;

				if (undefined != StyleId)
				{
					NextId = this.Styles.Get_Next(StyleId);

					var oNextStyle = this.Styles.Get(NextId);
					if (!NextId || !oNextStyle || !oNextStyle.IsParagraphStyle())
						NextId = StyleId;
				}

				if (StyleId === NextId)
				{
					// Продолжаем (в плане настроек) новый параграф
					Item.Continue(NewParagraph);
				}
				else
				{
					// Простое добавление стиля, без дополнительных действий
					if (NextId === this.Styles.Get_Default_Paragraph())
						NewParagraph.Style_Remove();
					else
						NewParagraph.Style_Add(NextId, true);
				}

				var SectPr = Item.Get_SectionPr();
				if (undefined !== SectPr)
				{
					Item.Set_SectionPr(undefined);
					NewParagraph.Set_SectionPr(SectPr);
				}

				var LastRun = Item.Content[Item.Content.length - 1];
				if (LastRun && LastRun.Pr.Lang && LastRun.Pr.Lang.Val)
				{
					NewParagraph.SelectAll();
					NewParagraph.Add(new ParaTextPr({Lang : LastRun.Pr.Lang.Copy()}));
					NewParagraph.RemoveSelection();
				}
			}
			else
			{
				Item.Split(NewParagraph);
			}

			NewParagraph.Correct_Content();
			NewParagraph.MoveCursorToStartPos();

			this.Internal_Content_Add(this.CurPos.ContentPos + 1, NewParagraph);
			this.CurPos.ContentPos++;

			if (true === this.Is_TrackRevisions())
			{
				NewParagraph.Remove_PrChange();
				NewParagraph.Set_ReviewType(ItemReviewType);
				Item.Set_ReviewType(reviewtype_Add);
			}
			else if (reviewtype_Common !== ItemReviewType)
			{
				NewParagraph.Set_ReviewType(ItemReviewType);
				Item.Set_ReviewType(reviewtype_Common);
			}
		}
	}
	else if (type_Table === Item.GetType() || type_BlockLevelSdt === Item.GetType())
	{
		// Если мы находимся в начале первого параграфа первой ячейки, и
		// данная таблица - первый элемент, тогда добавляем параграф до таблицы.

		if (0 === this.CurPos.ContentPos && Item.IsCursorAtBegin(true))
		{
			// Создаем новый параграф
			var NewParagraph = new Paragraph(this.DrawingDocument, this);
			this.Internal_Content_Add(0, NewParagraph);
			this.CurPos.ContentPos = 0;

			if (true === this.Is_TrackRevisions())
			{
				NewParagraph.Remove_PrChange();
				NewParagraph.Set_ReviewType(reviewtype_Add);
			}
		}
		else
		{
			Item.AddNewParagraph();
		}
	}
};
CDocument.prototype.controller_AddInlineImage = function(W, H, Img, Chart, bFlow)
{
	if (true == this.Selection.Use)
		this.Remove(1, true);

	var Item = this.Content[this.CurPos.ContentPos];
	if (type_Paragraph == Item.GetType())
	{
		var Drawing;
		if (!AscCommon.isRealObject(Chart))
		{
			Drawing   = new ParaDrawing(W, H, null, this.DrawingDocument, this, null);
			var Image = this.DrawingObjects.createImage(Img, 0, 0, W, H);
			Image.setParent(Drawing);
			Drawing.Set_GraphicObject(Image);
		}
		else
		{
			Drawing   = new ParaDrawing(W, H, null, this.DrawingDocument, this, null);
			var Image = this.DrawingObjects.getChartSpace2(Chart, null);
			Image.setParent(Drawing);
			Drawing.Set_GraphicObject(Image);
			Drawing.setExtent(Image.spPr.xfrm.extX, Image.spPr.xfrm.extY);
		}
		if (true === bFlow)
		{
			Drawing.Set_DrawingType(drawing_Anchor);
			Drawing.Set_WrappingType(WRAPPING_TYPE_SQUARE);
			Drawing.Set_BehindDoc(false);
			Drawing.Set_Distance(3.2, 0, 3.2, 0);
			Drawing.Set_PositionH(Asc.c_oAscRelativeFromH.Column, false, 0, false);
			Drawing.Set_PositionV(Asc.c_oAscRelativeFromV.Paragraph, false, 0, false);
		}
		this.AddToParagraph(Drawing);
		this.Select_DrawingObject(Drawing.Get_Id());
	}
	else
	{
		Item.AddInlineImage(W, H, Img, Chart, bFlow);
	}
};
CDocument.prototype.controller_AddImages = function(aImages)
{
    if (true === this.Selection.Use)
        this.Remove(1, true);

    var Item = this.Content[this.CurPos.ContentPos];
    if (type_Paragraph === Item.GetType())
    {
        var Drawing, W, H;
        var ColumnSize = this.GetColumnSize();
        for(var i = 0; i < aImages.length; ++i){

            W = Math.max(1, ColumnSize.W);
            H = Math.max(1, ColumnSize.H);

            var _image = aImages[i];
            var __w = Math.max((_image.Image.width * AscCommon.g_dKoef_pix_to_mm), 1);
            var __h = Math.max((_image.Image.height * AscCommon.g_dKoef_pix_to_mm), 1);
            W      = Math.max(5, Math.min(W, __w));
            H      = Math.max(5, Math.min((W * __h / __w)));
            Drawing   = new ParaDrawing(W, H, null, this.DrawingDocument, this, null);
            var Image = this.DrawingObjects.createImage(_image.src, 0, 0, W, H);
            Image.setParent(Drawing);
            Drawing.Set_GraphicObject(Image);
            this.AddToParagraph(Drawing);
        }
        if(aImages.length === 1)
        {
            if(Drawing)
            {
                this.Select_DrawingObject(Drawing.Get_Id());
            }
        }
    }
    else
    {
        Item.AddImages(aImages);
    }
};
CDocument.prototype.controller_AddOleObject = function(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId)
{
	if (true == this.Selection.Use)
		this.Remove(1, true);

	var Item = this.Content[this.CurPos.ContentPos];
	if (type_Paragraph == Item.GetType())
	{
		var Drawing   = new ParaDrawing(W, H, null, this.DrawingDocument, this, null);
		var Image = this.DrawingObjects.createOleObject(Data, sApplicationId, Img, 0, 0, W, H, nWidthPix, nHeightPix);
		Image.setParent(Drawing);
		Drawing.Set_GraphicObject(Image);
		this.AddToParagraph(Drawing);
		this.Select_DrawingObject(Drawing.Get_Id());
	}
	else
	{
		Item.AddOleObject(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId);
	}
};
CDocument.prototype.controller_AddTextArt = function(nStyle)
{
	var Item = this.Content[this.CurPos.ContentPos];
	if (type_Paragraph == Item.GetType())
	{
		var Drawing = new ParaDrawing(1828800 / 36000, 1828800 / 36000, null, this.DrawingDocument, this, null);
		var TextArt = this.DrawingObjects.createTextArt(nStyle, true);
		TextArt.setParent(Drawing);
		Drawing.Set_GraphicObject(TextArt);
		Drawing.Set_DrawingType(drawing_Anchor);
		Drawing.Set_WrappingType(WRAPPING_TYPE_NONE);
		Drawing.Set_BehindDoc(false);
		Drawing.Set_Distance(3.2, 0, 3.2, 0);
		Drawing.Set_PositionH(Asc.c_oAscRelativeFromH.Column, false, 0, false);
		Drawing.Set_PositionV(Asc.c_oAscRelativeFromV.Paragraph, false, 0, false);

		if (true == this.Selection.Use)
			this.Remove(1, true);

		this.AddToParagraph(Drawing);
		if (TextArt.bSelectedText)
		{
			this.Select_DrawingObject(Drawing.Get_Id());
		}
		else
		{
			var oContent = Drawing.GraphicObj.getDocContent();
			oContent.Content[0].Document_SetThisElementCurrent(false);
			this.SelectAll();
		}
	}
	else
	{
		Item.AddTextArt(nStyle);
	}
};
CDocument.prototype.controller_AddSignatureLine = function(oSignatureDrawing)
{
	var Item = this.Content[this.CurPos.ContentPos];
	if (type_Paragraph == Item.GetType())
	{
		var Drawing = oSignatureDrawing;

		if (true == this.Selection.Use)
			this.Remove(1, true);

		this.AddToParagraph(Drawing);
        this.Select_DrawingObject(Drawing.Get_Id());
	}
	else
	{
		Item.AddSignatureLine(oSignatureDrawing);
	}
};
CDocument.prototype.controller_AddInlineTable = function(Cols, Rows)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	// Сначала удаляем заселекченую часть
	if (true === this.Selection.Use)
	{
		this.Remove(1, true);
	}

	// Добавляем таблицу
	var Item = this.Content[this.CurPos.ContentPos];

	// Если мы внутри параграфа, тогда разрываем его и на месте разрыва добавляем таблицу.
	// А если мы внутри таблицы, тогда добавляем таблицу внутрь текущей таблицы.
	if (type_Paragraph === Item.GetType())
	{
		// Ширину таблицы делаем по минимальной ширине колонки.
		var Page   = this.Pages[this.CurPage];
		var SectPr = this.SectionsInfo.Get_SectPr(this.CurPos.ContentPos).SectPr;

		var PageFields = this.Get_PageFields(this.CurPage);

		// Создаем новую таблицу
		var W    = (PageFields.XLimit - PageFields.X + 2 * 1.9);
		var Grid = [];

		if (SectPr.Get_ColumnsCount() > 1)
		{
			for (var CurCol = 0, ColsCount = SectPr.Get_ColumnsCount(); CurCol < ColsCount; ++CurCol)
			{
				var ColumnWidth = SectPr.Get_ColumnWidth(CurCol);
				if (W > ColumnWidth)
					W = ColumnWidth;
			}

			W += 2 * 1.9;
		}

		W = Math.max(W, Cols * 2 * 1.9);

		for (var Index = 0; Index < Cols; Index++)
			Grid[Index] = W / Cols;

		var NewTable = new CTable(this.DrawingDocument, this, true, Rows, Cols, Grid);
		NewTable.Set_ParagraphPrOnAdd(Item);

		// Проверим позицию в текущем параграфе
		if (true === Item.IsCursorAtEnd() && undefined === Item.Get_SectionPr())
		{
			// Выставляем курсор в начало таблицы
			NewTable.MoveCursorToStartPos(false);
			this.Internal_Content_Add(this.CurPos.ContentPos + 1, NewTable);

			this.CurPos.ContentPos++;
		}
		else
		{
			// Создаем новый параграф
			var NewParagraph = new Paragraph(this.DrawingDocument, this);
			Item.Split(NewParagraph);

			// Добавляем новый параграф
			this.Internal_Content_Add(this.CurPos.ContentPos + 1, NewParagraph);

			// Выставляем курсор в начало таблицы
			NewTable.MoveCursorToStartPos(false);
			this.Internal_Content_Add(this.CurPos.ContentPos + 1, NewTable);

			this.CurPos.ContentPos++;
		}

	}
	else
	{
		Item.AddInlineTable(Cols, Rows);
	}

	this.Recalculate();
};
CDocument.prototype.controller_ClearParagraphFormatting = function(isClearParaPr, isClearTextPr)
{
	if (true === this.Selection.Use)
	{
		if (selectionflag_Common === this.Selection.Flag)
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (StartPos > EndPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;
			}

			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				this.Content[Index].ClearParagraphFormatting(isClearParaPr, isClearTextPr);
			}
		}
	}
	else
	{
		this.Content[this.CurPos.ContentPos].ClearParagraphFormatting(isClearParaPr, isClearTextPr);
	}
};
CDocument.prototype.controller_AddToParagraph = function(ParaItem, bRecalculate)
{
	if (true === this.Selection.Use)
	{
		var bAddSpace = this.Is_WordSelection();

		var Type = ParaItem.Get_Type();
		switch (Type)
		{
			case para_Math:
			case para_NewLine:
			case para_Text:
			case para_Space:
			case para_Tab:
			case para_PageNum:
			case para_Field:
			case para_FootnoteReference:
			case para_FootnoteRef:
			case para_Separator:
			case para_ContinuationSeparator:
			case para_InstrText:
			{
				// Если у нас что-то заселекчено и мы вводим текст или пробел
				// и т.д., тогда сначала удаляем весь селект.
				this.Remove(1, true, false, true);

				if (true === bAddSpace)
				{
					this.AddToParagraph(new ParaSpace());
					this.MoveCursorLeft(false, false);
				}
				break;
			}
			case para_TextPr:
			{
				switch (this.Selection.Flag)
				{
					case selectionflag_Common:
					{
						// Текстовые настройки применяем ко всем параграфам, попавшим
						// в селект.
						var StartPos = this.Selection.StartPos;
						var EndPos   = this.Selection.EndPos;
						if (EndPos < StartPos)
						{
							var Temp = StartPos;
							StartPos = EndPos;
							EndPos   = Temp;
						}

						for (var Index = StartPos; Index <= EndPos; Index++)
						{
							this.Content[Index].Add(ParaItem.Copy());
						}

						if (false != bRecalculate)
						{
							// Если в TextPr только HighLight, тогда не надо ничего пересчитывать, только перерисовываем
							if (true === ParaItem.Value.Check_NeedRecalc())
							{
								this.Recalculate();
							}
							else
							{
								// Просто перерисовываем нужные страницы
								var StartPage = this.Content[StartPos].Get_StartPage_Absolute();
								var EndPage   = this.Content[EndPos].Get_StartPage_Absolute() + this.Content[EndPos].GetPagesCount() - 1;
								this.ReDraw(StartPage, EndPage);
							}
						}

						break;
					}
					case selectionflag_Numbering:
					{
						// Текстовые настройки применяем к конкретной нумерации
						if (!this.Selection.Data || !this.Selection.Data.CurPara)
							break;

						if (undefined != ParaItem.Value.FontFamily)
						{
							var FName  = ParaItem.Value.FontFamily.Name;
							var FIndex = ParaItem.Value.FontFamily.Index;

							ParaItem.Value.RFonts          = new CRFonts();
							ParaItem.Value.RFonts.Ascii    = {Name : FName, Index : FIndex};
							ParaItem.Value.RFonts.EastAsia = {Name : FName, Index : FIndex};
							ParaItem.Value.RFonts.HAnsi    = {Name : FName, Index : FIndex};
							ParaItem.Value.RFonts.CS       = {Name : FName, Index : FIndex};
						}

						var oNumPr = this.Selection.Data.CurPara.GetNumPr();
						var oNum   = this.GetNumbering().GetNum(oNumPr.NumId);
						oNum.ApplyTextPr(oNumPr.Lvl, ParaItem.Value);

						if (false != bRecalculate)
						{
							this.Recalculate();
						}

						break;
					}
				}

				this.Document_UpdateSelectionState();
				this.Document_UpdateUndoRedoState();

				return;
			}
		}
	}

	var Item     = this.Content[this.CurPos.ContentPos];
	var ItemType = Item.GetType();

	if (para_NewLine === ParaItem.Type && true === ParaItem.IsPageOrColumnBreak())
	{
		if (type_Paragraph === ItemType)
		{
			if (true === Item.IsCursorAtBegin())
			{
				if (ParaItem.IsColumnBreak())
				{
					this.Content[this.CurPos.ContentPos].Add(ParaItem);
				}
				else
				{
					this.AddNewParagraph(undefined, true);
					var CurPos = this.CurPos.ContentPos - 1;
					this.Content[CurPos].MoveCursorToStartPos(false);
					this.Content[CurPos].AddToParagraph(ParaItem);
					this.Content[CurPos].Clear_Formatting();
				}
			}
			else
			{
				if (ParaItem.IsColumnBreak())
				{
					var oCurElement = this.Content[this.CurPos.ContentPos];
					var CurPos = this.CurPos.ContentPos;
					if (oCurElement && type_Paragraph === oCurElement.Get_Type() && oCurElement.IsColumnBreakOnLeft())
					{
						oCurElement.AddToParagraph(ParaItem);
					}
					else
					{
						this.AddNewParagraph(undefined, true);
						CurPos = this.CurPos.ContentPos;

						this.Content[CurPos].MoveCursorToStartPos(false);
						this.Content[CurPos].AddToParagraph(ParaItem);
					}
				}
				else
				{
					this.AddNewParagraph(undefined, true);
					this.AddNewParagraph(undefined, true);
					var CurPos = this.CurPos.ContentPos - 1;
					this.Content[CurPos].MoveCursorToStartPos(false);
					this.Content[CurPos].AddToParagraph(ParaItem);
					this.Content[CurPos].Clear_Formatting();
				}
			}

			if (false != bRecalculate)
			{
				this.Recalculate();

				Item.CurPos.RealX = Item.CurPos.X;
				Item.CurPos.RealY = Item.CurPos.Y;
			}
		}
		else if (type_BlockLevelSdt === Item.GetType())
		{
			Item.AddToParagraph(ParaItem);
		}
		else
		{
			// TODO: PageBreak в таблице не ставим
			return;
		}
	}
	else
	{
		Item.AddToParagraph(ParaItem);

		if (false != bRecalculate && type_Paragraph == Item.GetType())
		{
			if (para_TextPr === ParaItem.Type && false === ParaItem.Value.Check_NeedRecalc())
			{
				// Просто перерисовываем нужные страницы
				var StartPage = Item.Get_StartPage_Absolute();
				var EndPage   = StartPage + Item.Pages.length - 1;
				this.ReDraw(StartPage, EndPage);
			}
			else
			{
				// Нам нужно пересчитать все изменения, начиная с текущего элемента
				this.Recalculate(true);
			}

			if (false === this.TurnOffRecalcCurPos)
			{
				Item.RecalculateCurPos();
				Item.CurPos.RealX = Item.CurPos.X;
				Item.CurPos.RealY = Item.CurPos.Y;
			}
		}

		this.Document_UpdateSelectionState();
		this.Document_UpdateInterfaceState();
	}

	// Специальная заглушка для функции TextBox_Put
	if (true === this.Is_OnRecalculate())
		this.Document_UpdateUndoRedoState();
};
CDocument.prototype.controller_Remove = function(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd)
{
	// Делаем так, чтобы при выделении нумерации удалялась нумерация. А она удаляется по backspace.
	if (this.IsNumberingSelection())
		return this.Selection.Data.CurPara.Remove(-1, bOnlyText, bRemoveOnlySelection, bOnTextAdd);

	this.private_Remove(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd);
};
CDocument.prototype.controller_GetCursorPosXY = function()
{
	if (true === this.Selection.Use)
	{
		if (selectionflag_Common === this.Selection.Flag)
			return this.Content[this.Selection.EndPos].GetCursorPosXY();

		return {X : 0, Y : 0};
	}
	else
	{
		return this.Content[this.CurPos.ContentPos].GetCursorPosXY();
	}
};
CDocument.prototype.controller_MoveCursorToStartPos = function(AddToSelect)
{
	if (true === AddToSelect)
	{
		var StartPos = ( true === this.Selection.Use ? this.Selection.StartPos : this.CurPos.ContentPos );
		var EndPos   = 0;

		this.Selection.Start    = false;
		this.Selection.Use      = true;
		this.Selection.StartPos = StartPos;
		this.Selection.EndPos   = EndPos;
		this.Selection.Flag     = selectionflag_Common;

		this.CurPos.ContentPos = 0;
		this.Set_DocPosType(docpostype_Content);

		for (var Index = StartPos - 1; Index >= EndPos; Index--)
		{
			this.Content[Index].SelectAll(-1);
		}

		this.Content[StartPos].MoveCursorToStartPos(true);
	}
	else
	{
		this.RemoveSelection();

		this.Selection.Start    = false;
		this.Selection.Use      = false;
		this.Selection.StartPos = 0;
		this.Selection.EndPos   = 0;
		this.Selection.Flag     = selectionflag_Common;

		this.CurPos.ContentPos = 0;
		this.Set_DocPosType(docpostype_Content);
		this.Content[0].MoveCursorToStartPos(false);
	}
};
CDocument.prototype.controller_MoveCursorToEndPos = function(AddToSelect)
{
	if (true === AddToSelect)
	{
		var StartPos = ( true === this.Selection.Use ? this.Selection.StartPos : this.CurPos.ContentPos );
		var EndPos   = this.Content.length - 1;

		this.Selection.Start    = false;
		this.Selection.Use      = true;
		this.Selection.StartPos = StartPos;
		this.Selection.EndPos   = EndPos;
		this.Selection.Flag     = selectionflag_Common;

		this.CurPos.ContentPos = this.Content.length - 1;
		this.Set_DocPosType(docpostype_Content);

		for (var Index = StartPos + 1; Index <= EndPos; Index++)
		{
			this.Content[Index].SelectAll(1);
		}

		this.Content[StartPos].MoveCursorToEndPos(true, false);
	}
	else
	{
		this.RemoveSelection();

		this.Selection.Start    = false;
		this.Selection.Use      = false;
		this.Selection.StartPos = 0;
		this.Selection.EndPos   = 0;
		this.Selection.Flag     = selectionflag_Common;

		this.CurPos.ContentPos = this.Content.length - 1;
		this.Set_DocPosType(docpostype_Content);
		this.Content[this.CurPos.ContentPos].MoveCursorToEndPos(false);
	}
};
CDocument.prototype.controller_MoveCursorLeft = function(AddToSelect, Word)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	this.RemoveNumberingSelection();
	if (true === this.Selection.Use)
	{
		if (true === AddToSelect)
		{
			if (false === this.Content[this.Selection.EndPos].MoveCursorLeft(true, Word))
			{
				if (0 !== this.Selection.EndPos)
				{
					this.Selection.EndPos--;
					this.CurPos.ContentPos = this.Selection.EndPos;

					var Item = this.Content[this.Selection.EndPos];
					Item.MoveCursorLeftWithSelectionFromEnd(Word);
				}
			}

			// Проверяем не обнулился ли селект в последнем элементе. Такое могло быть, если была
			// заселекчена одна буква в последнем параграфе, а мы убрали селект последним действием.
			if (this.Selection.EndPos != this.Selection.StartPos && false === this.Content[this.Selection.EndPos].IsSelectionUse())
			{
				// Такая ситуация возможна только при прямом селекте (сверху вниз), поэтому вычитаем
				this.Selection.EndPos--;
				this.CurPos.ContentPos = this.Selection.EndPos;
			}

			// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
			if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
			{
				this.Selection.Use     = false;
				this.CurPos.ContentPos = this.Selection.EndPos;
			}
		}
		else
		{
			// Нам нужно переместить курсор в левый край селекта, и отменить весь селект
			var Start = this.Selection.StartPos;
			if (Start > this.Selection.EndPos)
				Start = this.Selection.EndPos;

			this.CurPos.ContentPos = Start;
			this.Content[this.CurPos.ContentPos].MoveCursorLeft(false, Word);
			this.RemoveSelection();
		}
	}
	else
	{
		if (true === AddToSelect)
		{
			this.Selection.Use      = true;
			this.Selection.StartPos = this.CurPos.ContentPos;
			this.Selection.EndPos   = this.CurPos.ContentPos;

			if (false === this.Content[this.CurPos.ContentPos].MoveCursorLeft(true, Word))
			{
				// Нужно перейти в конец предыдущего элемент
				if (0 != this.CurPos.ContentPos)
				{
					this.CurPos.ContentPos--;
					this.Selection.EndPos = this.CurPos.ContentPos;

					var Item = this.Content[this.CurPos.ContentPos];
					Item.MoveCursorLeftWithSelectionFromEnd(Word);
				}
			}

			// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
			if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
			{
				this.Selection.Use     = false;
				this.CurPos.ContentPos = this.Selection.EndPos;
			}
		}
		else
		{
			if (false === this.Content[this.CurPos.ContentPos].MoveCursorLeft(false, Word))
			{
				// Нужно перейти в конец предыдущего элемент
				if (0 != this.CurPos.ContentPos)
				{
					this.CurPos.ContentPos--;
					this.Content[this.CurPos.ContentPos].MoveCursorToEndPos(false, false);
				}
			}
		}
	}
};
CDocument.prototype.controller_MoveCursorRight = function(AddToSelect, Word)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	this.RemoveNumberingSelection();
	if (true === this.Selection.Use)
	{
		if (true === AddToSelect)
		{
			// Добавляем к селекту
			if (false === this.Content[this.Selection.EndPos].MoveCursorRight(true, Word))
			{
				// Нужно перейти в начало следующего элемента
				if (this.Content.length - 1 != this.Selection.EndPos)
				{
					this.Selection.EndPos++;
					this.CurPos.ContentPos = this.Selection.EndPos;

					var Item = this.Content[this.Selection.EndPos];
					Item.MoveCursorRightWithSelectionFromStart(Word);
				}
			}

			// Проверяем не обнулился ли селект в последнем параграфе. Такое могло быть, если была
			// заселекчена одна буква в последнем параграфе, а мы убрали селект последним действием.
			if (this.Selection.EndPos != this.Selection.StartPos && false === this.Content[this.Selection.EndPos].IsSelectionUse())
			{
				// Такая ситуация возможна только при обратном селекте (снизу вверх), поэтому вычитаем
				this.Selection.EndPos++;
				this.CurPos.ContentPos = this.Selection.EndPos;
			}

			// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
			if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
			{
				this.Selection.Use     = false;
				this.CurPos.ContentPos = this.Selection.EndPos;
			}
		}
		else
		{
			// Нам нужно переместить курсор в правый край селекта, и отменить весь селект
			var End = this.Selection.EndPos;
			if (End < this.Selection.StartPos)
				End = this.Selection.StartPos;

			this.CurPos.ContentPos = End;

			if (true === this.Content[this.CurPos.ContentPos].IsSelectionToEnd() && this.CurPos.ContentPos < this.Content.length - 1)
			{
				this.CurPos.ContentPos = End + 1;
				this.Content[this.CurPos.ContentPos].MoveCursorToStartPos(false);
			}
			else
			{
				this.Content[this.CurPos.ContentPos].MoveCursorRight(false, Word);
			}

			this.RemoveSelection();
		}
	}
	else
	{
		if (true === AddToSelect)
		{
			this.Selection.Use      = true;
			this.Selection.StartPos = this.CurPos.ContentPos;
			this.Selection.EndPos   = this.CurPos.ContentPos;

			if (false === this.Content[this.CurPos.ContentPos].MoveCursorRight(true, Word))
			{
				// Нужно перейти в конец предыдущего элемента
				if (this.Content.length - 1 != this.CurPos.ContentPos)
				{
					this.CurPos.ContentPos++;
					this.Selection.EndPos = this.CurPos.ContentPos;

					var Item = this.Content[this.CurPos.ContentPos];
					Item.MoveCursorRightWithSelectionFromStart(Word);
				}
			}

			// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
			if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
			{
				this.Selection.Use     = false;
				this.CurPos.ContentPos = this.Selection.EndPos;
			}
		}
		else
		{
			if (false === this.Content[this.CurPos.ContentPos].MoveCursorRight(false, Word))
			{
				// Нужно перейти в начало следующего элемента
				if (this.Content.length - 1 != this.CurPos.ContentPos)
				{
					this.CurPos.ContentPos++;
					this.Content[this.CurPos.ContentPos].MoveCursorToStartPos(false);
				}
			}
		}
	}
};
CDocument.prototype.controller_MoveCursorUp = function(AddToSelect)
{
	if (true === this.IsSelectionUse() && true !== AddToSelect)
		this.MoveCursorLeft(false, false);

	var bStopSelection = false;
	if (true !== this.IsSelectionUse() && true === AddToSelect)
	{
		bStopSelection = true;
		this.StartSelectionFromCurPos();
	}

	this.private_UpdateCursorXY(false, true);
	var Result = this.private_MoveCursorUp(this.CurPos.RealX, this.CurPos.RealY, AddToSelect);

	// TODO: Вообще Word селектит до начала данной колонки в таком случае, а не до начала документа
	if (true === AddToSelect && true !== Result)
		this.MoveCursorToStartPos(true);

	if (bStopSelection)
		this.private_StopSelection();
};
CDocument.prototype.controller_MoveCursorDown = function(AddToSelect)
{
	if (true === this.IsSelectionUse() && true !== AddToSelect)
		this.MoveCursorRight(false, false);

	var bStopSelection = false;
	if (true !== this.IsSelectionUse() && true === AddToSelect)
	{
		bStopSelection = true;
		this.StartSelectionFromCurPos();
	}

	this.private_UpdateCursorXY(false, true);
	var Result = this.private_MoveCursorDown(this.CurPos.RealX, this.CurPos.RealY, AddToSelect);

	if (true === AddToSelect && true !== Result)
		this.MoveCursorToEndPos(true);

	if (bStopSelection)
		this.private_StopSelection();
};
CDocument.prototype.controller_MoveCursorToEndOfLine = function(AddToSelect)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	this.RemoveNumberingSelection();
	if (true === this.Selection.Use)
	{
		if (true === AddToSelect)
		{
			var Item = this.Content[this.Selection.EndPos];
			Item.MoveCursorToEndOfLine(AddToSelect);

			// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
			if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
			{
				this.Selection.Use     = false;
				this.CurPos.ContentPos = this.Selection.EndPos;
			}
		}
		else
		{
			var Pos                = ( this.Selection.EndPos >= this.Selection.StartPos ? this.Selection.EndPos : this.Selection.StartPos );
			this.CurPos.ContentPos = Pos;

			var Item = this.Content[Pos];
			Item.MoveCursorToEndOfLine(AddToSelect);

			this.RemoveSelection();
		}
	}
	else
	{
		if (true === AddToSelect)
		{
			this.Selection.Use      = true;
			this.Selection.StartPos = this.CurPos.ContentPos;
			this.Selection.EndPos   = this.CurPos.ContentPos;

			var Item = this.Content[this.CurPos.ContentPos];
			Item.MoveCursorToEndOfLine(AddToSelect);

			// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
			if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
			{
				this.Selection.Use     = false;
				this.CurPos.ContentPos = this.Selection.EndPos;
			}
		}
		else
		{
			var Item = this.Content[this.CurPos.ContentPos];
			Item.MoveCursorToEndOfLine(AddToSelect);
		}
	}

	this.Document_UpdateInterfaceState();
	this.private_UpdateCursorXY(true, true);
};
CDocument.prototype.controller_MoveCursorToStartOfLine = function(AddToSelect)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	this.RemoveNumberingSelection();
	if (true === this.Selection.Use)
	{
		if (true === AddToSelect)
		{
			var Item = this.Content[this.Selection.EndPos];
			Item.MoveCursorToStartOfLine(AddToSelect);

			// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
			if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
			{
				this.Selection.Use     = false;
				this.CurPos.ContentPos = this.Selection.EndPos;
			}
		}
		else
		{
			var Pos                = ( this.Selection.StartPos <= this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos );
			this.CurPos.ContentPos = Pos;

			var Item = this.Content[Pos];
			Item.MoveCursorToStartOfLine(AddToSelect);

			this.RemoveSelection();
		}
	}
	else
	{
		if (true === AddToSelect)
		{
			this.Selection.Use      = true;
			this.Selection.StartPos = this.CurPos.ContentPos;
			this.Selection.EndPos   = this.CurPos.ContentPos;

			var Item = this.Content[this.CurPos.ContentPos];
			Item.MoveCursorToStartOfLine(AddToSelect);

			// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
			if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
			{
				this.Selection.Use     = false;
				this.CurPos.ContentPos = this.Selection.EndPos;
			}
		}
		else
		{
			var Item = this.Content[this.CurPos.ContentPos];
			Item.MoveCursorToStartOfLine(AddToSelect);
		}
	}

	this.Document_UpdateInterfaceState();
	this.private_UpdateCursorXY(true, true);
};
CDocument.prototype.controller_MoveCursorToXY = function(X, Y, PageAbs, AddToSelect)
{
	this.CurPage = PageAbs;

	this.RemoveNumberingSelection();
	if (true === this.Selection.Use)
	{
		if (true === AddToSelect)
		{
			this.Selection_SetEnd(X, Y, true);
		}
		else
		{
			this.RemoveSelection();

			var ContentPos         = this.Internal_GetContentPosByXY(X, Y);
			this.CurPos.ContentPos = ContentPos;
			var ElementPageIndex   = this.private_GetElementPageIndexByXY(ContentPos, X, Y, PageAbs);
			this.Content[ContentPos].MoveCursorToXY(X, Y, false, false, ElementPageIndex);

			this.Document_UpdateInterfaceState();
		}
	}
	else
	{
		if (true === AddToSelect)
		{
			this.StartSelectionFromCurPos();
			var oMouseEvent  = new AscCommon.CMouseEventHandler();
			oMouseEvent.Type = AscCommon.g_mouse_event_type_up;
			this.Selection_SetEnd(X, Y, oMouseEvent);
		}
		else
		{
			var ContentPos         = this.Internal_GetContentPosByXY(X, Y);
			this.CurPos.ContentPos = ContentPos;
			var ElementPageIndex   = this.private_GetElementPageIndexByXY(ContentPos, X, Y, PageAbs);
			this.Content[ContentPos].MoveCursorToXY(X, Y, false, false, ElementPageIndex);

			this.Document_UpdateInterfaceState();
		}
	}
};
CDocument.prototype.controller_MoveCursorToCell = function(bNext)
{
	if (true === this.Selection.Use)
	{
		if (this.Selection.StartPos === this.Selection.EndPos)
			this.Content[this.Selection.StartPos].MoveCursorToCell(bNext);
	}
	else
	{
		this.Content[this.CurPos.ContentPos].MoveCursorToCell(bNext);
	}
};
CDocument.prototype.controller_SetParagraphAlign = function(Align)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (EndPos < StartPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		for (var Index = StartPos; Index <= EndPos; Index++)
		{
			var Item = this.Content[Index];
			Item.SetParagraphAlign(Align);
		}
	}
	else
	{
		var Item = this.Content[this.CurPos.ContentPos];
		Item.SetParagraphAlign(Align);
	}
};
CDocument.prototype.controller_SetParagraphSpacing = function(Spacing)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (EndPos < StartPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		for (var Index = StartPos; Index <= EndPos; Index++)
		{
			var Item = this.Content[Index];
			Item.SetParagraphSpacing(Spacing);
		}
	}
	else
	{
		var Item = this.Content[this.CurPos.ContentPos];
		Item.SetParagraphSpacing(Spacing);
	}
};
CDocument.prototype.controller_SetParagraphTabs = function(Tabs)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (EndPos < StartPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		for (var Index = StartPos; Index <= EndPos; Index++)
		{
			var Item = this.Content[Index];
			Item.SetParagraphTabs(Tabs);
		}
	}
	else
	{
		var Item = this.Content[this.CurPos.ContentPos];
		Item.SetParagraphTabs(Tabs);
	}
};
CDocument.prototype.controller_SetParagraphIndent = function(Ind)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (EndPos < StartPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		for (var Index = StartPos; Index <= EndPos; Index++)
		{
			var Item = this.Content[Index];
			Item.SetParagraphIndent(Ind);
		}
	}
	else
	{
		var Item = this.Content[this.CurPos.ContentPos];
		Item.SetParagraphIndent(Ind);
	}
};
CDocument.prototype.controller_SetParagraphShd = function(Shd)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;

		if (true === this.UseTextShd && StartPos === EndPos && type_Paragraph === this.Content[StartPos].GetType() && false === this.Content[StartPos].Selection_CheckParaEnd() && selectionflag_Common === this.Selection.Flag)
		{
			this.AddToParagraph(new ParaTextPr({Shd : Shd}));
		}
		else
		{
			if (EndPos < StartPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;
			}

			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				var Item = this.Content[Index];
				Item.SetParagraphShd(Shd);
			}
		}
	}
	else
	{
		var Item = this.Content[this.CurPos.ContentPos];
		Item.SetParagraphShd(Shd);
	}
};
CDocument.prototype.controller_SetParagraphStyle = function(Name)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	if (true === this.Selection.Use)
	{
		this.RemoveNumberingSelection();

		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (EndPos < StartPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		for (var Index = StartPos; Index <= EndPos; Index++)
		{
			var Item = this.Content[Index];
			Item.SetParagraphStyle(Name);
		}
	}
	else
	{
		var Item = this.Content[this.CurPos.ContentPos];
		Item.SetParagraphStyle(Name);
	}
};
CDocument.prototype.controller_SetParagraphContextualSpacing = function(Value)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (EndPos < StartPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		for (var Index = StartPos; Index <= EndPos; Index++)
		{
			var Item = this.Content[Index];
			Item.SetParagraphContextualSpacing(Value);
		}
	}
	else
	{
		var Item = this.Content[this.CurPos.ContentPos];
		Item.SetParagraphContextualSpacing(Value);
	}
};
CDocument.prototype.controller_SetParagraphPageBreakBefore = function(Value)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (EndPos < StartPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		for (var Index = StartPos; Index <= EndPos; Index++)
		{
			var Item = this.Content[Index];
			Item.SetParagraphPageBreakBefore(Value);
		}
	}
	else
	{
		var Item = this.Content[this.CurPos.ContentPos];
		Item.SetParagraphPageBreakBefore(Value);
	}
};
CDocument.prototype.controller_SetParagraphKeepLines = function(Value)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (EndPos < StartPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		for (var Index = StartPos; Index <= EndPos; Index++)
		{
			var Item = this.Content[Index];
			Item.SetParagraphKeepLines(Value);
		}
	}
	else
	{
		var Item = this.Content[this.CurPos.ContentPos];
		Item.SetParagraphKeepLines(Value);
	}
};
CDocument.prototype.controller_SetParagraphKeepNext = function(Value)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (EndPos < StartPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		for (var Index = StartPos; Index <= EndPos; Index++)
		{
			var Item = this.Content[Index];
			Item.SetParagraphKeepNext(Value);
		}
	}
	else
	{
		var Item = this.Content[this.CurPos.ContentPos];
		Item.SetParagraphKeepNext(Value);
	}
};
CDocument.prototype.controller_SetParagraphWidowControl = function(Value)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (EndPos < StartPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		for (var Index = StartPos; Index <= EndPos; Index++)
		{
			var Item = this.Content[Index];
			Item.SetParagraphWidowControl(Value);
		}
	}
	else
	{
		var Item = this.Content[this.CurPos.ContentPos];
		Item.SetParagraphWidowControl(Value);
	}
};
CDocument.prototype.controller_SetParagraphBorders = function(Borders)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (EndPos < StartPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		for (var Index = StartPos; Index <= EndPos; Index++)
		{
			var Item = this.Content[Index];
			Item.SetParagraphBorders(Borders);
		}
	}
	else
	{
		var Item = this.Content[this.CurPos.ContentPos];
		if (type_Paragraph == Item.GetType())
		{
			// Мы должны выставить границу для всех параграфов, входящих в текущую группу параграфов
			// с одинаковыми границами

			var StartPos = Item.Index;
			var EndPos   = Item.Index;
			var CurBrd   = Item.Get_CompiledPr().ParaPr.Brd;

			while (true != CurBrd.First)
			{
				StartPos--;
				if (StartPos < 0)
				{
					StartPos = 0;
					break;
				}

				var TempItem = this.Content[StartPos];
				if (type_Paragraph !== TempItem.GetType())
				{
					StartPos++;
					break;
				}

				CurBrd = TempItem.Get_CompiledPr().ParaPr.Brd;
			}

			CurBrd = Item.Get_CompiledPr().ParaPr.Brd;
			while (true != CurBrd.Last)
			{
				EndPos++;
				if (EndPos >= this.Content.length)
				{
					EndPos = this.Content.length - 1;
					break;
				}

				var TempItem = this.Content[EndPos];
				if (type_Paragraph !== TempItem.GetType())
				{
					EndPos--;
					break;
				}

				CurBrd = TempItem.Get_CompiledPr().ParaPr.Brd;
			}

			for (var Index = StartPos; Index <= EndPos; Index++)
				this.Content[Index].SetParagraphBorders(Borders);
		}
		else
		{
			Item.SetParagraphBorders(Borders);
		}
	}
};
CDocument.prototype.controller_SetParagraphFramePr = function(FramePr, bDelete)
{
	if (true === this.Selection.Use)
	{
		if (this.Selection.StartPos === this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType())
		{
			this.Content[this.Selection.StartPos].SetParagraphFramePr(FramePr, bDelete);
			return;
		}

		// Проверим, если у нас все выделенные элементы - параграфы, с одинаковыми настройками
		// FramePr, тогда мы можем применить новую настройку FramePr

		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;

		if (StartPos > EndPos)
		{
			StartPos = this.Selection.EndPos;
			EndPos   = this.Selection.StartPos;
		}

		var Element = this.Content[StartPos];

		if (type_Paragraph !== Element.GetType() || undefined === Element.Get_FramePr())
			return;

		var FramePr = Element.Get_FramePr();
		for (var Pos = StartPos + 1; Pos < EndPos; Pos++)
		{
			var TempElement = this.Content[Pos];

			if (type_Paragraph !== TempElement.GetType() || undefined === TempElement.Get_FramePr() || true != FramePr.Compare(TempElement.Get_FramePr()))
				return;
		}

		// Раз дошли до сюда, значит можно у всех выделенных параграфов менять настройку рамки
		var FrameParas = this.Content[StartPos].Internal_Get_FrameParagraphs();
		var FrameCount = FrameParas.length;
		for (var Pos = 0; Pos < FrameCount; Pos++)
		{
			FrameParas[Pos].Set_FramePr(FramePr, bDelete);
		}
	}
	else
	{
		var Element = this.Content[this.CurPos.ContentPos];

		if (type_Paragraph !== Element.GetType())
		{
			Element.SetParagraphFramePr(FramePr, bDelete);
			return;
		}

		// Возможно, предыдущий элемент является буквицей
		if (undefined === Element.Get_FramePr())
		{
			var PrevElement = Element.Get_DocumentPrev();

			if (type_Paragraph !== PrevElement.GetType() || undefined === PrevElement.Get_FramePr() || undefined === PrevElement.Get_FramePr().DropCap)
				return;

			Element = PrevElement;
		}

		var FrameParas = Element.Internal_Get_FrameParagraphs();
		var FrameCount = FrameParas.length;
		for (var Pos = 0; Pos < FrameCount; Pos++)
		{
			FrameParas[Pos].Set_FramePr(FramePr, bDelete);
		}
	}
};
CDocument.prototype.controller_IncreaseDecreaseFontSize = function(bIncrease)
{
	if (this.CurPos.ContentPos < 0)
		return false;

	if (true === this.Selection.Use)
	{
		switch (this.Selection.Flag)
		{
			case selectionflag_Common:
			{
				var StartPos = this.Selection.StartPos;
				var EndPos   = this.Selection.EndPos;
				if (EndPos < StartPos)
				{
					var Temp = StartPos;
					StartPos = EndPos;
					EndPos   = Temp;
				}

				for (var Index = StartPos; Index <= EndPos; Index++)
				{
					var Item = this.Content[Index];
					Item.IncreaseDecreaseFontSize(bIncrease);
				}
				break;
			}
			case  selectionflag_Numbering:
			{
				var OldFontSize = this.GetCalculatedTextPr().FontSize;
				var NewFontSize = FontSize_IncreaseDecreaseValue(bIncrease, OldFontSize);
				var TextPr      = new CTextPr();
				TextPr.FontSize = NewFontSize;
				this.AddToParagraph(new ParaTextPr(TextPr), true);
				break;
			}
		}
	}
	else
	{
		var Item = this.Content[this.CurPos.ContentPos];
		Item.IncreaseDecreaseFontSize(bIncrease);
	}
};
CDocument.prototype.controller_IncreaseDecreaseIndent = function(bIncrease)
{
	if (true === this.Selection.Use && selectionflag_Common === this.Selection.Flag)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (EndPos < StartPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		for (var Index = StartPos; Index <= EndPos; Index++)
		{
			this.Content[Index].IncreaseDecreaseIndent(bIncrease);
		}
	}
	else
	{
		this.Content[this.CurPos.ContentPos].IncreaseDecreaseIndent(bIncrease);
	}
};
CDocument.prototype.controller_SetImageProps = function(Props)
{
	if ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Table == this.Content[this.Selection.StartPos].GetType())
		|| (false == this.Selection.Use && type_Table == this.Content[this.CurPos.ContentPos].GetType()))
	{
		if (true == this.Selection.Use)
			this.Content[this.Selection.StartPos].SetImageProps(Props);
		else
			this.Content[this.CurPos.ContentPos].SetImageProps(Props);
	}
};
CDocument.prototype.controller_SetTableProps = function(Props)
{
	var Pos = -1;
	if (true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos)
		Pos = this.Selection.StartPos;
	else if (false === this.Selection.Use)
		Pos = this.CurPos.ContentPos;

	if (-1 !== Pos)
		this.Content[Pos].SetTableProps(Props);
};
CDocument.prototype.controller_GetCalculatedParaPr = function()
{
	var Result_ParaPr = new CParaPr();
	if (true === this.Selection.Use && selectionflag_Common === this.Selection.Flag)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (EndPos < StartPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		var StartPr = this.Content[StartPos].GetCalculatedParaPr();
		var Pr      = StartPr.Copy();
		Pr.Locked   = StartPr.Locked;

		for (var Index = StartPos + 1; Index <= EndPos; Index++)
		{
			var Item   = this.Content[Index];
			var TempPr = Item.GetCalculatedParaPr();
			Pr         = Pr.Compare(TempPr);
		}

		if (undefined === Pr.Ind.Left)
			Pr.Ind.Left = StartPr.Ind.Left;

		if (undefined === Pr.Ind.Right)
			Pr.Ind.Right = StartPr.Ind.Right;

		if (undefined === Pr.Ind.FirstLine)
			Pr.Ind.FirstLine = StartPr.Ind.FirstLine;

		Result_ParaPr             = Pr;
		Result_ParaPr.CanAddTable = ( true === Pr.Locked ? false : true );

		// Если мы находимся в рамке, тогда дополняем ее свойства настройками границы и настройкой текста (если это буквица)
		if (undefined != Result_ParaPr.FramePr && type_Paragraph === this.Content[StartPos].GetType())
		{
			this.Content[StartPos].Supplement_FramePr(Result_ParaPr.FramePr);
		}
		else if (StartPos === EndPos && StartPos > 0 && type_Paragraph === this.Content[StartPos - 1].GetType())
		{
			var PrevFrame = this.Content[StartPos - 1].Get_FramePr();
			if (undefined != PrevFrame && undefined != PrevFrame.DropCap)
			{
				Result_ParaPr.FramePr = PrevFrame.Copy();
				this.Content[StartPos - 1].Supplement_FramePr(Result_ParaPr.FramePr);
			}
		}

	}
	else
	{
		var Item = this.Content[this.CurPos.ContentPos];
		if (type_Paragraph == Item.GetType())
		{
			var ParaPr = Item.Get_CompiledPr2(false).ParaPr;
			var Locked = Item.Lock.Is_Locked();

			Result_ParaPr             = ParaPr.Copy();
			Result_ParaPr.Locked      = Locked;
			Result_ParaPr.CanAddTable = ( ( true === Locked ) ? ( ( true === Item.IsCursorAtEnd() ) ? true : false ) : true );

			// Если мы находимся в рамке, тогда дополняем ее свойства настройками границы и настройкой текста (если это буквица)
			if (undefined != Result_ParaPr.FramePr)
			{
				Item.Supplement_FramePr(Result_ParaPr.FramePr);
			}
			else if (this.CurPos.ContentPos > 0 && type_Paragraph === this.Content[this.CurPos.ContentPos - 1].GetType())
			{
				var PrevFrame = this.Content[this.CurPos.ContentPos - 1].Get_FramePr();
				if (undefined != PrevFrame && undefined != PrevFrame.DropCap)
				{
					Result_ParaPr.FramePr = PrevFrame.Copy();
					this.Content[this.CurPos.ContentPos - 1].Supplement_FramePr(Result_ParaPr.FramePr);
				}
			}
		}
		else
		{
			Result_ParaPr = Item.GetCalculatedParaPr();
		}
	}

	if (Result_ParaPr.Shd && Result_ParaPr.Shd.Unifill)
	{
		Result_ParaPr.Shd.Unifill.check(this.theme, this.Get_ColorMap());
	}

	return Result_ParaPr;
};
CDocument.prototype.controller_GetCalculatedTextPr = function()
{
	var Result_TextPr = null;
	if (true === this.Selection.Use)
	{
		var VisTextPr;
		switch (this.Selection.Flag)
		{
			case selectionflag_Common:
			{
				var StartPos = this.Selection.StartPos;
				var EndPos   = this.Selection.EndPos;
				if (EndPos < StartPos)
				{
					var Temp = StartPos;
					StartPos = EndPos;
					EndPos   = Temp;
				}

				VisTextPr = this.Content[StartPos].GetCalculatedTextPr();

				for (var Index = StartPos + 1; Index <= EndPos; Index++)
				{
					var CurPr = this.Content[Index].GetCalculatedTextPr();
					VisTextPr = VisTextPr.Compare(CurPr);
				}

				break;
			}
			case selectionflag_Numbering:
			{
				if (!this.Selection.Data || !this.Selection.Data.CurPara)
					break;

				VisTextPr = this.Selection.Data.CurPara.GetNumberingTextPr();
				break;
			}
		}

		Result_TextPr = VisTextPr;
	}
	else
	{
		Result_TextPr = this.Content[this.CurPos.ContentPos].GetCalculatedTextPr();
	}

	return Result_TextPr;
};
CDocument.prototype.controller_GetDirectParaPr = function()
{
	var Result_ParaPr = null;

	if (true === this.Selection.Use)
	{
		switch (this.Selection.Flag)
		{
			case selectionflag_Common:
			{
				var StartPos = this.Selection.StartPos;
				if (this.Selection.EndPos < StartPos)
					StartPos = this.Selection.EndPos;

				var Item      = this.Content[StartPos];
				Result_ParaPr = Item.GetDirectParaPr();

				break;
			}
			case selectionflag_Numbering:
			{
				if (!this.Selection.Data || !this.Selection.Data.CurPara)
					break;

				var oNumPr    = this.Selection.Data.CurPara.GetNumPr();
				Result_ParaPr = this.GetNumbering().GetNum(oNumPr.NumId).GetLvl(oNumPr.Lvl).GetParaPr();

				break;
			}
		}
	}
	else
	{
		var Item      = this.Content[this.CurPos.ContentPos];
		Result_ParaPr = Item.GetDirectParaPr();
	}

	return Result_ParaPr;
};
CDocument.prototype.controller_GetDirectTextPr = function()
{
	var Result_TextPr = null;

	if (true === this.Selection.Use)
	{
		var VisTextPr;
		switch (this.Selection.Flag)
		{
			case selectionflag_Common:
			{
				var StartPos = this.Selection.StartPos;
				if (this.Selection.EndPos < StartPos)
					StartPos = this.Selection.EndPos;

				var Item  = this.Content[StartPos];
				VisTextPr = Item.GetDirectTextPr();

				break;
			}
			case selectionflag_Numbering:
			{
				if (!this.Selection.Data || !this.Selection.Data.CurPara)
					break;

				var oNumPr = this.Selection.Data.CurPara.GetNumPr();
				VisTextPr  = this.GetNumbering().GetNum(oNumPr.NumId).GetLvl(oNumPr.Lvl).GetTextPr();

				break;
			}
		}

		Result_TextPr = VisTextPr;
	}
	else
	{
		var Item      = this.Content[this.CurPos.ContentPos];
		Result_TextPr = Item.GetDirectTextPr();
	}

	return Result_TextPr;
};
CDocument.prototype.controller_RemoveSelection = function(bNoCheckDrawing)
{
	if (true === this.Selection.Use)
	{
		switch (this.Selection.Flag)
		{
			case selectionflag_Common:
			{
				var Start = this.Selection.StartPos;
				var End   = this.Selection.EndPos;

				if (Start > End)
				{
					var Temp = Start;
					Start    = End;
					End      = Temp;
				}

				Start = Math.max(0, Start);
				End   = Math.min(this.Content.length - 1, End);

				for (var Index = Start; Index <= End; Index++)
				{
					this.Content[Index].RemoveSelection();
				}

				this.Selection.Use   = false;
				this.Selection.Start = false;

				this.Selection.StartPos = 0;
				this.Selection.EndPos   = 0;

				// Убираем селект и возвращаем курсор
				this.DrawingDocument.SelectEnabled(false);
				this.DrawingDocument.TargetStart();
				this.DrawingDocument.TargetShow();

				break;
			}
			case selectionflag_Numbering:
			{
				if (!this.Selection.Data)
					break;

				for (var nIndex = 0, nCount = this.Selection.Data.Paragraphs.length; nIndex < nCount; ++nIndex)
				{
					this.Selection.Data.Paragraphs[nIndex].RemoveSelection();
				}

				if (this.Selection.Data.CurPara)
					this.Selection.Data.CurPara.RemoveSelection();

				this.Selection.Use   = false;
				this.Selection.Start = false;
				this.Selection.Flag  = selectionflag_Common;

				// Убираем селект и возвращаем курсор
				this.DrawingDocument.SelectEnabled(false);
				this.DrawingDocument.TargetStart();
				this.DrawingDocument.TargetShow();

				break;
			}
		}
	}
};
CDocument.prototype.controller_IsSelectionEmpty = function(bCheckHidden)
{
	if (true === this.Selection.Use)
	{
		if (selectionflag_Numbering == this.Selection.Flag)
			return false;
		else if (true === this.IsMovingTableBorder())
			return false;
		else
		{
			if (this.Selection.StartPos === this.Selection.EndPos)
				return this.Content[this.Selection.StartPos].IsSelectionEmpty(bCheckHidden);
			else
				return false;
		}
	}

	return true;
};
CDocument.prototype.controller_DrawSelectionOnPage = function(PageAbs)
{
	if (true !== this.Selection.Use)
		return;

	var Page = this.Pages[PageAbs];
	for (var SectionIndex = 0, SectionsCount = Page.Sections.length; SectionIndex < SectionsCount; ++SectionIndex)
	{
		var PageSection = Page.Sections[SectionIndex];
		for (var ColumnIndex = 0, ColumnsCount = PageSection.Columns.length; ColumnIndex < ColumnsCount; ++ColumnIndex)
		{
			var Pos_start = this.Pages[PageAbs].Pos;
			var Pos_end   = this.Pages[PageAbs].EndPos;

			switch (this.Selection.Flag)
			{
				case selectionflag_Common:
				{
					var Start = this.Selection.StartPos;
					var End   = this.Selection.EndPos;

					if (Start > End)
					{
						Start = this.Selection.EndPos;
						End   = this.Selection.StartPos;
					}

					var Start = Math.max(Start, Pos_start);
					var End   = Math.min(End, Pos_end);

					for (var Index = Start; Index <= End; ++Index)
					{
						var ElementPage = this.private_GetElementPageIndex(Index, PageAbs, ColumnIndex, ColumnsCount);
						this.Content[Index].DrawSelectionOnPage(ElementPage);
					}

					if (PageAbs >= 2 && End < this.Pages[PageAbs - 2].EndPos)
					{
						this.Selection.UpdateOnRecalc = false;
						this.DrawingDocument.OnSelectEnd();
					}

					break;
				}
				case selectionflag_Numbering:
				{
					if (!this.Selection.Data)
						break;

					for (var nIndex = 0, nCount = this.Selection.Data.Paragraphs.length; nIndex < nCount; ++nIndex)
					{
						var oPara = this.Selection.Data.Paragraphs[nIndex];
						if (oPara.GetNumberingPage(true) === PageAbs)
							oPara.DrawSelectionOnPage(oPara.GetNumberingPage(false));
					}

					if (PageAbs >= 2 && this.Selection.Data[this.Selection.Data.length - 1] < this.Pages[PageAbs - 2].EndPos)
					{
						this.Selection.UpdateOnRecalc = false;
						this.DrawingDocument.OnSelectEnd();
					}

					break;
				}
			}
		}
	}
};
CDocument.prototype.controller_GetSelectionBounds = function()
{
	if (true === this.Selection.Use && selectionflag_Common === this.Selection.Flag)
	{
		var Start = this.Selection.StartPos;
		var End   = this.Selection.EndPos;

		if (Start > End)
		{
			Start = this.Selection.EndPos;
			End   = this.Selection.StartPos;
		}

		if (Start === End)
			return this.Content[Start].GetSelectionBounds();
		else
		{
			var Result       = {};
			Result.Start     = this.Content[Start].GetSelectionBounds().Start;
			Result.End       = this.Content[End].GetSelectionBounds().End;
			Result.Direction = (this.Selection.StartPos > this.Selection.EndPos ? -1 : 1);
			return Result;
		}
	}

	return null;
};
CDocument.prototype.controller_IsMovingTableBorder = function()
{
	if (null != this.Selection.Data && true === this.Selection.Data.TableBorder)
		return true;

	return false;
};
CDocument.prototype.controller_CheckPosInSelection = function(X, Y, PageAbs, NearPos)
{
	if (true === this.Footnotes.CheckHitInFootnote(X, Y, PageAbs))
		return false;

	if (true === this.Selection.Use)
	{
		switch (this.Selection.Flag)
		{
			case selectionflag_Common:
			{
				var Start = this.Selection.StartPos;
				var End   = this.Selection.EndPos;

				if (Start > End)
				{
					Start = this.Selection.EndPos;
					End   = this.Selection.StartPos;
				}

				if (undefined !== NearPos)
				{
					for (var Index = Start; Index <= End; Index++)
					{
						if (true === this.Content[Index].CheckPosInSelection(0, 0, 0, NearPos))
							return true;
					}

					return false;
				}
				else
				{
					var ContentPos = this.Internal_GetContentPosByXY(X, Y, PageAbs, NearPos);
					if (ContentPos > Start && ContentPos < End)
					{
						return true;
					}
					else if (ContentPos < Start || ContentPos > End)
					{
						return false;
					}
					else
					{
						var ElementPageIndex = this.private_GetElementPageIndexByXY(ContentPos, X, Y, PageAbs);
						return this.Content[ContentPos].CheckPosInSelection(X, Y, ElementPageIndex, undefined);
					}
				}
			}
			case selectionflag_Numbering:
			{
				return false;
			}
		}

		return false;
	}

	return false;
};
CDocument.prototype.controller_SelectAll = function()
{
	if (true === this.Selection.Use)
		this.RemoveSelection();

	this.DrawingDocument.SelectEnabled(true);
	this.DrawingDocument.TargetEnd();

	this.Set_DocPosType(docpostype_Content);

	this.Selection.Use   = true;
	this.Selection.Start = false;
	this.Selection.Flag  = selectionflag_Common;

	this.Selection.StartPos = 0;
	this.Selection.EndPos   = this.Content.length - 1;

	for (var Index = 0; Index < this.Content.length; Index++)
	{
		this.Content[Index].SelectAll();
	}
};
CDocument.prototype.controller_GetSelectedContent = function(SelectedContent)
{
	if (true !== this.Selection.Use || this.Selection.Flag !== selectionflag_Common)
		return;

	var StartPos = this.Selection.StartPos;
	var EndPos   = this.Selection.EndPos;
	if (StartPos > EndPos)
	{
		StartPos = this.Selection.EndPos;
		EndPos   = this.Selection.StartPos;
	}

	for (var Index = StartPos; Index <= EndPos; Index++)
	{
		this.Content[Index].GetSelectedContent(SelectedContent);
	}
};
CDocument.prototype.controller_UpdateCursorType = function(X, Y, PageAbs, MouseEvent)
{
	var bInText      = (null === this.IsInText(X, Y, PageAbs) ? false : true);
	var bTableBorder = (null === this.IsTableBorder(X, Y, PageAbs) ? false : true);

	// Ничего не делаем
	if (true === this.DrawingObjects.updateCursorType(PageAbs, X, Y, MouseEvent, ( true === bInText || true === bTableBorder ? true : false )))
		return;

	var ContentPos       = this.Internal_GetContentPosByXY(X, Y, PageAbs);
	var Item             = this.Content[ContentPos];
	var ElementPageIndex = this.private_GetElementPageIndexByXY(ContentPos, X, Y, PageAbs);
	Item.UpdateCursorType(X, Y, ElementPageIndex);
};
CDocument.prototype.controller_PasteFormatting = function(TextPr, ParaPr)
{
	if (true === this.Selection.Use)
	{
		if (selectionflag_Common === this.Selection.Flag)
		{
			var Start = this.Selection.StartPos;
			var End   = this.Selection.EndPos;
			if (Start > End)
			{
				Start = this.Selection.EndPos;
				End   = this.Selection.StartPos;
			}

			for (var Pos = Start; Pos <= End; Pos++)
			{
				this.Content[Pos].PasteFormatting(TextPr, ParaPr, Start === End ? false : true);
			}
		}
	}
	else
	{
		this.Content[this.CurPos.ContentPos].PasteFormatting(TextPr, ParaPr, true);
	}
};
CDocument.prototype.controller_IsSelectionUse = function()
{
	if (true === this.Selection.Use)
		return true;

	return false;
};
CDocument.prototype.controller_IsNumberingSelection = function()
{
	return CDocumentContentBase.prototype.IsNumberingSelection.apply(this, arguments);
};
CDocument.prototype.controller_IsTextSelectionUse = function()
{
	return this.Selection.Use;
};
CDocument.prototype.controller_GetCurPosXY = function()
{
	if (true === this.Selection.Use)
	{
		if (selectionflag_Numbering === this.Selection.Flag)
			return {X : 0, Y : 0};
		else
			return this.Content[this.Selection.EndPos].GetCurPosXY();
	}
	else
	{
		return this.Content[this.CurPos.ContentPos].GetCurPosXY();
	}
};
CDocument.prototype.controller_GetSelectedText = function(bClearText, oPr)
{
	if ((true === this.Selection.Use && selectionflag_Common === this.Selection.Flag) || false === this.Selection.Use)
	{
		if (true === bClearText && this.Selection.StartPos === this.Selection.EndPos)
		{
			var Pos = ( true == this.Selection.Use ? this.Selection.StartPos : this.CurPos.ContentPos );
			return this.Content[Pos].GetSelectedText(true, oPr);
		}
		else if (false === bClearText)
		{
			var StartPos = ( true == this.Selection.Use ? Math.min(this.Selection.StartPos, this.Selection.EndPos) : this.CurPos.ContentPos );
			var EndPos   = ( true == this.Selection.Use ? Math.max(this.Selection.StartPos, this.Selection.EndPos) : this.CurPos.ContentPos );

			var ResultText = "";

			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				ResultText += this.Content[Index].GetSelectedText(false, oPr);
			}

			return ResultText;
		}
	}

	return null;
};
CDocument.prototype.controller_GetCurrentParagraph = function(bIgnoreSelection, arrSelectedParagraphs)
{
	if (null !== arrSelectedParagraphs)
	{
		if (true === this.Selection.Use)
		{
			var nStartPos = this.Selection.StartPos <= this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos;
			var nEndPos   = this.Selection.StartPos <= this.Selection.EndPos ? this.Selection.EndPos : this.Selection.StartPos;
			for (var nPos = nStartPos; nPos <= nEndPos; ++nPos)
			{
				this.Content[nPos].GetCurrentParagraph(false, arrSelectedParagraphs);
			}
		}
		else
		{
			this.Content[this.CurPos.ContentPos].GetCurrentParagraph(false, arrSelectedParagraphs);
		}
	}
	else
	{
		var Pos = true === this.Selection.Use && true !== bIgnoreSelection ? this.Selection.StartPos : this.CurPos.ContentPos;
		if (Pos < 0 || Pos >= this.Content.length)
			return null;

		return this.Content[Pos].GetCurrentParagraph(bIgnoreSelection, null);
	}
};
CDocument.prototype.controller_GetSelectedElementsInfo = function(Info)
{
	if (true === this.Selection.Use)
	{
		if (selectionflag_Numbering === this.Selection.Flag)
		{
			if (this.Selection.Data && this.Selection.Data.CurPara)
			{
				this.Selection.Data.CurPara.GetSelectedElementsInfo(Info);
			}
		}
		else
		{
			if (this.Selection.StartPos != this.Selection.EndPos)
				Info.Set_MixedSelection();
			else
				this.Content[this.Selection.StartPos].GetSelectedElementsInfo(Info);
		}
	}
	else
	{
		this.Content[this.CurPos.ContentPos].GetSelectedElementsInfo(Info);
	}
};
CDocument.prototype.controller_AddTableRow = function(bBefore)
{
	if ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType())
		|| (false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType()))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		this.Content[Pos].AddTableRow(bBefore);

		if (false === this.Selection.Use && true === this.Content[Pos].IsSelectionUse())
		{
			this.Selection.Use      = true;
			this.Selection.StartPos = Pos;
			this.Selection.EndPos   = Pos;
		}
	}
};
CDocument.prototype.controller_AddTableColumn = function(bBefore)
{
	if ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType())
		|| (false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType()))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		this.Content[Pos].AddTableColumn(bBefore);

		if (false === this.Selection.Use && true === this.Content[Pos].IsSelectionUse())
		{
			this.Selection.Use      = true;
			this.Selection.StartPos = Pos;
			this.Selection.EndPos   = Pos;
		}
	}
};
CDocument.prototype.controller_RemoveTableRow = function()
{
	if ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType())
		|| (false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType()))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		if (false === this.Content[Pos].RemoveTableRow())
			this.controller_RemoveTable();
	}
};
CDocument.prototype.controller_RemoveTableColumn = function()
{
	if ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType())
		|| (false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType()))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		if (false === this.Content[Pos].RemoveTableColumn())
			this.controller_RemoveTable();
	}
};
CDocument.prototype.controller_MergeTableCells = function()
{
	if ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType())
		|| (false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType()))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		this.Content[Pos].MergeTableCells();
	}
};
CDocument.prototype.controller_DistributeTableCells = function(isHorizontally)
{
	if ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType())
		|| (false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType()))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		return this.Content[Pos].DistributeTableCells(isHorizontally);
	}

	return false;
};
CDocument.prototype.controller_SplitTableCells = function(Cols, Rows)
{
	if ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType())
		|| (false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType()))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		this.Content[Pos].SplitTableCells(Rows, Cols);
	}
};
CDocument.prototype.controller_RemoveTable = function()
{
	if ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType())
		|| (false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType()))
	{
		var Pos;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		var Table = this.Content[Pos];

		if (type_Table === Table.GetType())
		{
			if (true === Table.IsInnerTable())
			{
				Table.RemoveInnerTable();
			}
			else
			{
				this.RemoveSelection();
				Table.PreDelete();
				this.Internal_Content_Remove(Pos, 1);

				if (Pos >= this.Content.length - 1)
					Pos--;

				if (Pos < 0)
					Pos = 0;

				this.Set_DocPosType(docpostype_Content);
				this.CurPos.ContentPos = Pos;
				this.Content[Pos].MoveCursorToStartPos();
			}
		}
		else
		{
			Table.RemoveTable();
		}
	}
};
CDocument.prototype.controller_SelectTable = function(Type)
{
	if ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType())
		|| (false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType()))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		this.Content[Pos].SelectTable(Type);
		if (false === this.Selection.Use && true === this.Content[Pos].IsSelectionUse())
		{
			this.Selection.Use      = true;
			this.Selection.StartPos = Pos;
			this.Selection.EndPos   = Pos;
		}
	}
};
CDocument.prototype.controller_CanMergeTableCells = function()
{
	if ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType())
		|| (false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType()))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		return this.Content[Pos].CanMergeTableCells();
	}

	return false;
};
CDocument.prototype.controller_CanSplitTableCells = function()
{
	if ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType())
		|| (false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType()))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		return this.Content[Pos].CanSplitTableCells();
	}

	return false;
};
CDocument.prototype.controller_UpdateInterfaceState = function()
{
	if ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType())
		|| (false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType()))
	{
		this.Interface_Update_TablePr();

		if (true == this.Selection.Use)
			this.Content[this.Selection.StartPos].Document_UpdateInterfaceState();
		else
			this.Content[this.CurPos.ContentPos].Document_UpdateInterfaceState();
	}
	else
	{
		this.Interface_Update_ParaPr();
		this.Interface_Update_TextPr();

		// Если у нас в выделении находится 1 параграф, или курсор находится в параграфе
		if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph == this.Content[this.Selection.StartPos].GetType() ) || ( false == this.Selection.Use && type_Paragraph == this.Content[this.CurPos.ContentPos].GetType() ) ))
		{
			if (true == this.Selection.Use)
				this.Content[this.Selection.StartPos].Document_UpdateInterfaceState();
			else
				this.Content[this.CurPos.ContentPos].Document_UpdateInterfaceState();
		}
	}
};
CDocument.prototype.controller_UpdateRulersState = function()
{
	this.Document_UpdateRulersStateBySection();

	if (true === this.Selection.Use)
	{
		if (this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType())
		{
			var PagePos = this.Get_DocumentPagePositionByContentPosition(this.GetContentPosition(true, true));

			var Page   = PagePos ? PagePos.Page : this.CurPage;
			var Column = PagePos ? PagePos.Column : 0;

			var ElementPos       = this.Selection.StartPos;
			var Element          = this.Content[ElementPos];
			var ElementPageIndex = this.private_GetElementPageIndex(ElementPos, Page, Column, Element.Get_ColumnsCount());
			Element.Document_UpdateRulersState(ElementPageIndex);
		}
		else
		{
			var StartPos = ( this.Selection.EndPos <= this.Selection.StartPos ? this.Selection.EndPos : this.Selection.StartPos );
			var EndPos   = ( this.Selection.EndPos <= this.Selection.StartPos ? this.Selection.StartPos : this.Selection.EndPos );

			var FramePr = undefined;

			for (var Pos = StartPos; Pos <= EndPos; Pos++)
			{
				var Element = this.Content[Pos];
				if (type_Paragraph != Element.GetType())
				{
					FramePr = undefined;
					break;
				}
				else
				{
					var TempFramePr = Element.Get_FramePr();
					if (undefined === FramePr)
					{
						if (undefined === TempFramePr)
							break;

						FramePr = TempFramePr;
					}
					else if (undefined === TempFramePr || false === FramePr.Compare(TempFramePr))
					{
						FramePr = undefined;
						break;
					}
				}
			}

			if (undefined !== FramePr)
				this.Content[StartPos].Document_UpdateRulersState();
		}
	}
	else
	{
		this.private_CheckCurPage();

		if (this.CurPos.ContentPos >= 0 && (null === this.FullRecalc.Id || this.FullRecalc.StartIndex > this.CurPos.ContentPos))
		{
			var PagePos = this.Get_DocumentPagePositionByContentPosition(this.GetContentPosition(false));

			var Page   = PagePos ? PagePos.Page : this.CurPage;
			var Column = PagePos ? PagePos.Column : 0;

			var ElementPos       = this.CurPos.ContentPos;
			var Element          = this.Content[ElementPos];
			var ElementPageIndex = this.private_GetElementPageIndex(ElementPos, Page, Column, Element.Get_ColumnsCount());
			Element.Document_UpdateRulersState(ElementPageIndex);
		}
	}
};
CDocument.prototype.controller_UpdateSelectionState = function()
{
	if (true === this.Selection.Use)
	{
		// Выделение нумерации
		if (selectionflag_Numbering == this.Selection.Flag)
		{
			this.DrawingDocument.TargetEnd();
			this.DrawingDocument.SelectEnabled(true);
			this.DrawingDocument.SelectShow();
		}
		// Обрабатываем движение границы у таблиц
		else if (true === this.IsMovingTableBorder())
		{
			// Убираем курсор, если он был
			this.DrawingDocument.TargetEnd();
			this.DrawingDocument.SetCurrentPage(this.CurPage);
		}
		else
		{
			if (false === this.IsSelectionEmpty())
			{
				if (true !== this.Selection.Start)
				{
					this.private_CheckCurPage();
					this.RecalculateCurPos();
				}
				this.private_UpdateTracks(true, false);

				this.DrawingDocument.TargetEnd();
				this.DrawingDocument.SelectEnabled(true);
				this.DrawingDocument.SelectShow();
			}
			else
			{
				if (true !== this.Selection.Start)
				{
					this.RemoveSelection();
				}

				this.private_CheckCurPage();
				this.RecalculateCurPos();
				this.private_UpdateTracks(true, true);

				this.DrawingDocument.SelectEnabled(false);
				this.DrawingDocument.TargetStart();
				this.DrawingDocument.TargetShow();
			}
		}
	}
	else
	{
		this.RemoveSelection();
		this.private_CheckCurPage();
		this.RecalculateCurPos();
		this.private_UpdateTracks(false, false);

		this.DrawingDocument.SelectEnabled(false);
		this.DrawingDocument.TargetShow();
	}
};
CDocument.prototype.controller_GetSelectionState = function()
{
	var State;
	if (true === this.Selection.Use)
	{
		// Выделение нумерации
		if (selectionflag_Numbering == this.Selection.Flag)
			State = [];
		else
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (StartPos > EndPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;
			}

			State = [];

			var TempState = [];
			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				TempState.push(this.Content[Index].GetSelectionState());
			}

			State.push(TempState);
		}
	}
	else
	{
		State = this.Content[this.CurPos.ContentPos].GetSelectionState();
	}

	return State;
};
CDocument.prototype.controller_SetSelectionState = function(State, StateIndex)
{
	if (true === this.Selection.Use)
	{
		// Выделение нумерации
		if (selectionflag_Numbering == this.Selection.Flag)
		{
			if (type_Paragraph === this.Content[this.Selection.StartPos].Get_Type())
			{
				var NumPr = this.Content[this.Selection.StartPos].GetNumPr();
				if (undefined !== NumPr)
					this.SelectNumbering(NumPr, this.Content[this.Selection.StartPos]);
				else
					this.RemoveSelection();
			}
			else
				this.RemoveSelection();
		}
		else
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (StartPos > EndPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;
			}

			var CurState = State[StateIndex];
			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				this.Content[Index].SetSelectionState(CurState[Index - StartPos], CurState[Index - StartPos].length - 1);
			}
		}
	}
	else
	{
		this.Content[this.CurPos.ContentPos].SetSelectionState(State, StateIndex);
	}
};
CDocument.prototype.controller_AddHyperlink = function(Props)
{
	if (false === this.Selection.Use || this.Selection.StartPos === this.Selection.EndPos)
	{
		var Pos = ( true == this.Selection.Use ? this.Selection.StartPos : this.CurPos.ContentPos );
		this.Content[Pos].AddHyperlink(Props);
	}
};
CDocument.prototype.controller_ModifyHyperlink = function(Props)
{
	if (false == this.Selection.Use || this.Selection.StartPos == this.Selection.EndPos)
	{
		var Pos = ( true == this.Selection.Use ? this.Selection.StartPos : this.CurPos.ContentPos );
		this.Content[Pos].ModifyHyperlink(Props);
	}
};
CDocument.prototype.controller_RemoveHyperlink = function()
{
	if (false == this.Selection.Use || this.Selection.StartPos == this.Selection.EndPos)
	{
		var Pos = ( true == this.Selection.Use ? this.Selection.StartPos : this.CurPos.ContentPos );
		this.Content[Pos].RemoveHyperlink();
	}
};
CDocument.prototype.controller_CanAddHyperlink = function(bCheckInHyperlink)
{
	if (true === this.Selection.Use)
	{
		if (selectionflag_Common === this.Selection.Flag)
		{
			if (this.Selection.StartPos != this.Selection.EndPos)
				return false;

			return this.Content[this.Selection.StartPos].CanAddHyperlink(bCheckInHyperlink);
		}
	}
	else
	{
		return this.Content[this.CurPos.ContentPos].CanAddHyperlink(bCheckInHyperlink);
	}

	return false;
};
CDocument.prototype.controller_IsCursorInHyperlink = function(bCheckEnd)
{
	if (true === this.Selection.Use)
	{
		if (selectionflag_Common === this.Selection.Flag)
		{
			if (this.Selection.StartPos != this.Selection.EndPos)
				return null;

			return this.Content[this.Selection.StartPos].IsCursorInHyperlink(bCheckEnd);
		}
	}
	else
	{
		return this.Content[this.CurPos.ContentPos].IsCursorInHyperlink(bCheckEnd);
	}

	return null;
};
CDocument.prototype.controller_AddComment = function(Comment)
{
	if (selectionflag_Numbering === this.Selection.Flag)
		return;

	if (true === this.Selection.Use)
	{
		var StartPos, EndPos;
		if (this.Selection.StartPos < this.Selection.EndPos)
		{
			StartPos = this.Selection.StartPos;
			EndPos   = this.Selection.EndPos;
		}
		else
		{
			StartPos = this.Selection.EndPos;
			EndPos   = this.Selection.StartPos;
		}

		if (StartPos === EndPos)
		{
			this.Content[StartPos].AddComment(Comment, true, true);
		}
		else
		{
			this.Content[StartPos].AddComment(Comment, true, false);
			this.Content[EndPos].AddComment(Comment, false, true);
		}
	}
	else
	{
		this.Content[this.CurPos.ContentPos].AddComment(Comment, true, true);
	}
};
CDocument.prototype.controller_CanAddComment = function()
{
	if (selectionflag_Common === this.Selection.Flag)
	{
		if (true === this.Selection.Use && this.Selection.StartPos != this.Selection.EndPos)
		{
			return true;
		}
		else
		{
			var Pos     = ( this.Selection.Use === true ? this.Selection.StartPos : this.CurPos.ContentPos );
			var Element = this.Content[Pos];
			return Element.CanAddComment();
		}
	}

	return false;
};
CDocument.prototype.controller_GetSelectionAnchorPos = function()
{
	var Pos = ( true === this.Selection.Use ? ( this.Selection.StartPos < this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos ) : this.CurPos.ContentPos );
	return this.Content[Pos].GetSelectionAnchorPos();
};
CDocument.prototype.controller_StartSelectionFromCurPos = function()
{
	this.Selection.StartPos = this.CurPos.ContentPos;
	this.Selection.EndPos   = this.CurPos.ContentPos;
	this.Content[this.CurPos.ContentPos].StartSelectionFromCurPos();
};
CDocument.prototype.controller_SaveDocumentStateBeforeLoadChanges = function(State)
{
	State.Pos      = this.GetContentPosition(false, false);
	State.StartPos = this.GetContentPosition(true, true);
	State.EndPos   = this.GetContentPosition(true, false);
};
CDocument.prototype.controller_RestoreDocumentStateAfterLoadChanges = function(State)
{
	if (true === this.Selection.Use)
	{
		this.SetContentPosition(State.StartPos, 0, 0);
		this.SetContentSelection(State.StartPos, State.EndPos, 0, 0, 0);
	}
	else
	{
		this.SetContentPosition(State.Pos, 0, 0);
		this.NeedUpdateTarget = true;
	}
};
CDocument.prototype.controller_GetColumnSize = function()
{
	var ContentPos = true === this.Selection.Use ? ( this.Selection.StartPos < this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos ) : this.CurPos.ContentPos;

	var PagePos   = this.Get_DocumentPagePositionByContentPosition(this.GetContentPosition(this.Selection.Use, false));
	var ColumnAbs = PagePos ? PagePos.Column : 0;

	var SectPr = this.Get_SectPr(ContentPos);
	var Y      = SectPr.Get_PageMargin_Top();
	var YLimit = SectPr.Get_PageHeight() - SectPr.Get_PageMargin_Bottom();
	var X      = SectPr.Get_PageMargin_Left();
	var XLimit = SectPr.Get_PageWidth() - SectPr.Get_PageMargin_Right();

	var ColumnsCount = SectPr.Get_ColumnsCount();
	for (var ColumnIndex = 0; ColumnIndex < ColumnAbs; ++ColumnIndex)
	{
		X += SectPr.Get_ColumnWidth(ColumnIndex);
		X += SectPr.Get_ColumnSpace(ColumnIndex);
	}

	if (ColumnsCount - 1 !== ColumnAbs)
		XLimit = X + SectPr.Get_ColumnWidth(ColumnAbs);

	return {
		W : XLimit - X,
		H : YLimit - Y
	};
};
CDocument.prototype.controller_GetCurrentSectionPr = function()
{
	var nContentPos = this.CurPos.ContentPos;
	return this.SectionsInfo.Get_SectPr(nContentPos).SectPr;
};
CDocument.prototype.controller_AddContentControl = function(nContentControlType)
{
	return this.private_AddContentControl(nContentControlType);
};
CDocument.prototype.controller_GetStyleFromFormatting = function()
{
	if (true == this.Selection.Use)
	{
		if (this.Selection.StartPos > this.Selection.EndPos)
			return this.Content[this.Selection.EndPos].GetStyleFromFormatting();
		else
			return this.Content[this.Selection.StartPos].GetStyleFromFormatting();
	}
	else
	{
		return this.Content[this.CurPos.ContentPos].GetStyleFromFormatting();
	}
};
CDocument.prototype.controller_GetSimilarNumbering = function(oContinueEngine)
{
	this.GetSimilarNumbering(oContinueEngine);
};
//----------------------------------------------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.RemoveTextSelection = function()
{
	this.Controller.RemoveTextSelection();
};
CDocument.prototype.AddFormTextField = function(sName, sDefaultText)
{
	if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Paragraph_Content))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddMailMergeField);

		var oField = new ParaField(fieldtype_FORMTEXT);
		var oRun = new ParaRun();
		oField.SetFormFieldName(sName);
		oField.SetFormFieldDefaultText(sDefaultText);
		oRun.AddText(sDefaultText);
		oField.Add_ToContent(0, oRun);

		this.Register_Field(oField);
		this.AddToParagraph(oField);
		this.Document_UpdateInterfaceState();
	}
};
CDocument.prototype.GetAllFormTextFields = function()
{
	return this.FieldsManager.GetAllFieldsByType(fieldtype_FORMTEXT);
};
CDocument.prototype.IsFillingFormMode = function()
{
	return this.Api.isRestrictionForms();
};
CDocument.prototype.IsInFormField = function()
{
	var oSelectedInfo = this.GetSelectedElementsInfo();
	var oField        = oSelectedInfo.Get_Field();
	var oInlineSdt    = oSelectedInfo.GetInlineLevelSdt();
	var oBlockSdt     = oSelectedInfo.GetBlockLevelSdt();

	return (oBlockSdt || oInlineSdt || (oField && fieldtype_FORMTEXT === oField.Get_FieldType())) ? true : false;
};
CDocument.prototype.IsFormFieldEditing = function()
{
	if (true === this.IsFillingFormMode() && true === this.IsInFormField())
		return true;

	return false;
};
CDocument.prototype.MoveToFillingForm = function(isNext)
{
	var oRes = this.FindNextFillingForm(isNext, true, true);

	if (!oRes)
		oRes = this.FindNextFillingForm(isNext, true, false);

	if (oRes)
	{
		this.RemoveSelection();

		if (oRes instanceof CBlockLevelSdt || oRes instanceof CInlineLevelSdt)
		{
			oRes.SelectContentControl();
		}
		else if (oRes instanceof ParaField)
		{
			oRes.SelectThisElement();
		}
	}
};
CDocument.prototype.OnContentControlTrackEnd = function(Id, NearestPos, isCopy)
{
	return this.OnEndTextDrag(NearestPos, isCopy);
};
CDocument.prototype.AddContentControl = function(nContentControlType)
{
	return this.Controller.AddContentControl(nContentControlType);
};
CDocument.prototype.GetAllContentControls = function()
{
	var arrContentControls = [];

	this.SectionsInfo.GetAllContentControls(arrContentControls);

	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		this.Content[nIndex].GetAllContentControls(arrContentControls);
	}
	return arrContentControls;
};
CDocument.prototype.RemoveContentControl = function(Id)
{
	var oContentControl = this.TableId.Get_ById(Id);
	if (!oContentControl)
		return;

	if (c_oAscSdtLevelType.Block === oContentControl.GetContentControlType() && oContentControl.Parent)
	{
		this.RemoveSelection();
		var oDocContent = oContentControl.Parent;
		oDocContent.Update_ContentIndexing();
		var nIndex = oContentControl.GetIndex();

		var nCurPos = oDocContent.CurPos.ContentPos;
		oDocContent.Remove_FromContent(nIndex, 1);

		if (nIndex === nCurPos)
		{
			if (nIndex >= oDocContent.GetElementsCount())
			{
				oDocContent.MoveCursorToEndPos();
			}
			else
			{
				oDocContent.CurPos.ContentPos = Math.max(0, Math.min(oDocContent.GetElementsCount() - 1, nIndex));;
				oDocContent.Content[oDocContent.CurPos.ContentPos].MoveCursorToStartPos();
			}
		}
		else if (nIndex < nCurPos)
		{
			oDocContent.CurPos.ContentPos = Math.max(0, Math.min(oDocContent.GetElementsCount() - 1, nCurPos - 1));
		}
	}
	else if (c_oAscSdtLevelType.Inline === oContentControl.GetContentControlType())
	{
		this.SelectContentControl(Id);
		this.RemoveBeforePaste();
	}
};
CDocument.prototype.RemoveContentControlWrapper = function(Id)
{
	var oContentControl = this.TableId.Get_ById(Id);
	if (!oContentControl)
		return;

	this.History.Create_NewPoint();

	oContentControl.RemoveContentControlWrapper();
	this.Recalculate();
	this.Document_UpdateInterfaceState();
	this.Document_UpdateSelectionState();
};
CDocument.prototype.GetContentControl = function(Id)
{
	return this.TableId.Get_ById(Id);
};
CDocument.prototype.ClearContentControl = function(Id)
{
	var oContentControl = this.TableId.Get_ById(Id);
	if (!oContentControl)
		return null;

	this.RemoveSelection();

	if (oContentControl.GetContentControlType
		&& (c_oAscSdtLevelType.Block === oContentControl.GetContentControlType()
		|| c_oAscSdtLevelType.Inline === oContentControl.GetContentControlType()))
	{
		oContentControl.ClearContentControl();
		oContentControl.SetThisElementCurrent();
		oContentControl.MoveCursorToStartPos();
	}

	return oContentControl;
};
/**
 * Выделяем содержимое внутри заданного контейнера
 * @param {string} sId
 */
CDocument.prototype.SelectContentControl = function(sId)
{
	var oContentControl = this.TableId.Get_ById(sId);
	if (!oContentControl)
		return;

	if (oContentControl.GetContentControlType
		&& (c_oAscSdtLevelType.Block === oContentControl.GetContentControlType()
		|| c_oAscSdtLevelType.Inline === oContentControl.GetContentControlType()))
	{
		this.RemoveSelection();

		oContentControl.SelectContentControl();
		this.Document_UpdateSelectionState();
		this.Document_UpdateRulersState();
		this.Document_UpdateInterfaceState();
		this.Document_UpdateTracks();

		this.private_UpdateCursorXY(true, true);
	}
};
CDocument.prototype.GetAllSignatures = function()
{
    return this.DrawingObjects.getAllSignatures();
};
CDocument.prototype.CallSignatureDblClickEvent = function(sGuid)
{
    var ret = [], allSpr = [];
    allSpr = allSpr.concat(allSpr.concat(this.DrawingObjects.getAllSignatures2(ret, this.DrawingObjects.getDrawingArray())));
    for(var i = 0; i < allSpr.length; ++i){
        if(allSpr[i].signatureLine && allSpr[i].signatureLine.id === sGuid){
            this.Api.sendEvent("asc_onSignatureDblClick", sGuid, allSpr[i].extX, allSpr[i].extY);
        }
    }
};
CDocument.prototype.SetCheckContentControlsLock = function(isLocked)
{
	this.CheckContentControlsLock = isLocked;
};
CDocument.prototype.IsCheckContentControlsLock = function()
{
	return this.CheckContentControlsLock;
};
CDocument.prototype.IsEditCommentsMode = function()
{
	return this.Api.isRestrictionComments();
};
CDocument.prototype.IsViewMode = function()
{
	return this.Api.getViewMode();
};
CDocument.prototype.IsEditSignaturesMode = function()
{
	return this.Api.isRestrictionSignatures();
};
CDocument.prototype.IsViewModeInEditor = function()
{
	return this.Api.isRestrictionView();
};
CDocument.prototype.CanEdit = function()
{
	return this.Api.canEdit();
};
CDocument.prototype.private_CheckCursorPosInFillingFormMode = function()
{
	if (this.IsFillingFormMode() && !this.IsInFormField())
	{
		this.MoveToFillingForm(true);
		this.Document_UpdateSelectionState();
		this.Document_UpdateInterfaceState();
	}
};
CDocument.prototype.OnEndLoadScript = function()
{
	this.UpdateAllSectionsInfo();
	this.Check_SectionLastParagraph();
	this.Styles.Check_StyleNumberingOnLoad(this.Numbering);

	var arrParagraphs = this.GetAllParagraphs({All : true});
	for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
	{
		arrParagraphs[nIndex].Recalc_CompiledPr();
		arrParagraphs[nIndex].Recalc_RunsCompiledPr();
	}
};
CDocument.prototype.BeginViewModeInReview = function(isResult)
{
	if (0 !== this.ViewModeInReview.mode)
		this.EndViewModeInReview();

	this.ViewModeInReview.mode = isResult ? 1 : -1;

	this.ViewModeInReview.isFastCollaboration = this.CollaborativeEditing.Is_Fast();
	this.CollaborativeEditing.Set_Fast(false);

	this.History.SaveRedoPoints();
	if (isResult)
		this.Accept_AllRevisionChanges(true);
	else
		this.Reject_AllRevisionChanges(true);

	this.CollaborativeEditing.Set_GlobalLock(true);
};
CDocument.prototype.EndViewModeInReview = function()
{
	if (0 === this.ViewModeInReview.mode)
		return;

	this.ViewModeInReview.mode = 0;

	this.CollaborativeEditing.Set_GlobalLock(false);

	this.Document_Undo();
	this.History.Clear_Redo();
	this.History.PopRedoPoints();

	if (this.ViewModeInReview.isFastCollaboration)
		this.CollaborativeEditing.Set_Fast(true);
};
CDocument.prototype.StartCollaborationEditing = function()
{
	this.DrawingDocument.Start_CollaborationEditing();
	this.EndViewModeInReview();
};
CDocument.prototype.IsViewModeInReview = function()
{
	return 0 !== this.ViewModeInReview.mode ? true : false;
};
CDocument.prototype.AddField = function(nType, oPr)
{
	if (fieldtype_PAGENUM === nType)
	{
		return this.AddFieldWithInstruction("PAGE");
	}
	else if (fieldtype_TOC === nType)
	{
		return this.AddFieldWithInstruction("TOC");
	}
	else if (fieldtype_PAGEREF === nType)
	{
		return this.AddFieldWithInstruction("PAGEREF Test \\p");
	}

	return false;
};
CDocument.prototype.AddFieldWithInstruction = function(sInstruction)
{
	var oParagraph = this.GetCurrentParagraph();
	if (!oParagraph)
		return null;

	var nIndex = -1;

	var oBeginChar    = new ParaFieldChar(fldchartype_Begin, this),
		oSeparateChar = new ParaFieldChar(fldchartype_Separate, this),
		oEndChar      = new ParaFieldChar(fldchartype_End, this);

	var oRun = new ParaRun();
	oRun.AddToContent(-1, oBeginChar);
	oRun.AddInstrText(sInstruction);
	oRun.AddToContent(-1, oSeparateChar);
	oRun.AddToContent(-1, oEndChar);
	oParagraph.Add(oRun);

	oBeginChar.SetRun(oRun);
	oSeparateChar.SetRun(oRun);
	oEndChar.SetRun(oRun);

	var oComplexField = oBeginChar.GetComplexField();
	oComplexField.SetBeginChar(oBeginChar);
	oComplexField.SetInstructionLine(sInstruction);
	oComplexField.SetSeparateChar(oSeparateChar);
	oComplexField.SetEndChar(oEndChar);
	oComplexField.Update(false);

	return oComplexField;
};
CDocument.prototype.UpdateComplexField = function(oField)
{
	if (!oField)
		return;

	oField.Update(true);
};
CDocument.prototype.GetCurrentComplexFields = function()
{
	var oParagraph = this.GetCurrentParagraph();
	if (!oParagraph)
		return [];

	return oParagraph.GetCurrentComplexFields();
};
CDocument.prototype.IsFastCollaboartionBeforeViewModeInReview = function()
{
	return this.ViewModeInReview.isFastCollaboration;
};
CDocument.prototype.CheckComplexFieldsInSelection = function()
{
	if (true !== this.Selection.Use || this.Controller !== this.LogicDocumentController)
		return;

	// Смотрим сколько полей открытых в начальной и конечной позициях.
	var oStartPos = this.GetContentPosition(true, true);
	var oEndPos   = this.GetContentPosition(true, false);

	var arrStartComplexFields = this.GetComplexFieldsByContentPos(oStartPos);
	var arrEndComplexFields   = this.GetComplexFieldsByContentPos(oEndPos);

	var arrStartFields = [];
	for (var nIndex = 0, nCount = arrStartComplexFields.length; nIndex < nCount; ++nIndex)
	{
		var bAdd = true;
		for (var nIndex2 = 0, nCount2 = arrEndComplexFields.length; nIndex2 < nCount2; ++nIndex2)
		{
			if (arrStartComplexFields[nIndex] === arrEndComplexFields[nIndex2])
			{
				bAdd = false;
				break;
			}
		}

		if (bAdd)
		{
			arrStartFields.push(arrStartComplexFields[nIndex]);
		}
	}

	var arrEndFields = [];
	for (var nIndex = 0, nCount = arrEndComplexFields.length; nIndex < nCount; ++nIndex)
	{
		var bAdd = true;
		for (var nIndex2 = 0, nCount2 = arrStartComplexFields.length; nIndex2 < nCount2; ++nIndex2)
		{
			if (arrEndComplexFields[nIndex] === arrStartComplexFields[nIndex2])
			{
				bAdd = false;
				break;
			}
		}

		if (bAdd)
		{
			arrEndFields.push(arrEndComplexFields[nIndex]);
		}
	}

	var nDirection = this.GetSelectDirection();
	if (nDirection > 0)
	{
		if (arrStartFields.length > 0 && arrStartFields[0].IsValid())
			oStartPos = arrStartFields[0].GetStartDocumentPosition();

		if (arrEndFields.length > 0 && arrEndFields[0].IsValid())
			oEndPos = arrEndFields[0].GetEndDocumentPosition();
	}
	else
	{
		if (arrStartFields.length > 0 && arrStartFields[0].IsValid())
			oStartPos = arrStartFields[0].GetEndDocumentPosition();

		if (arrEndFields.length > 0 && arrEndFields[0].IsValid())
			oEndPos = arrEndFields[0].GetStartDocumentPosition();
	}

	this.SetContentSelection(oStartPos, oEndPos, 0, 0, 0);
};
/**
 * Получаем текст, который лежит внутри заданного сложного поля. Если внутри текста есть объекты, то возвращается null.
 * @param {CComplexField} oComplexField
 * @returns {?string}
 */
CDocument.prototype.GetComplexFieldTextValue = function(oComplexField)
{
	if (!oComplexField)
		return null;

	var oState = this.SaveDocumentState();
	oComplexField.SelectFieldValue();
	var sResult = this.GetSelectedText();
	this.LoadDocumentState(oState);
	this.Document_UpdateSelectionState();

	return sResult;
};
/**
 * Получаем прямые текстовые настройки заданного сложного поля.
 * @param oComplexField
 * @returns {CTextPr}
 */
CDocument.prototype.GetComplexFieldTextPr = function(oComplexField)
{
	if (!oComplexField)
		return new CTextPr();

	var oState = this.SaveDocumentState();
	oComplexField.SelectFieldValue();
	var oTextPr = this.GetDirectTextPr();
	this.LoadDocumentState(oState);
	this.Document_UpdateSelectionState();

	return oTextPr;
};
CDocument.prototype.GetFieldsManager = function()
{
	return this.FieldsManager;
};
CDocument.prototype.GetComplexFieldsByContentPos = function(oDocPos)
{
	if (!oDocPos)
		return [];

	var oCurrentDocPos = this.GetContentPosition(false);
	this.SetContentPosition(oDocPos, 0, 0);

	var oCurrentParagraph = this.controller_GetCurrentParagraph(true, null);
	if (!oCurrentParagraph)
		return [];

	var arrComplexFields = oCurrentParagraph.GetCurrentComplexFields();
	this.SetContentPosition(oCurrentDocPos, 0, 0);

	return arrComplexFields;
};
/**
 * Получаем ссылку на класс, управляющий закладками
 * @returns {CBookmarksManager}
 */
CDocument.prototype.GetBookmarksManager = function()
{
	return this.BookmarksManager;
};
CDocument.prototype.UpdateBookmarks = function()
{
	if (!this.BookmarksManager.IsNeedUpdate())
		return;

	this.BookmarksManager.BeginCollectingProcess();

	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		this.Content[nIndex].UpdateBookmarks(this.BookmarksManager);
	}

	this.BookmarksManager.EndCollectingProcess();
};
CDocument.prototype.AddBookmark = function(sName)
{
	var arrBookmarkChars = this.BookmarksManager.GetBookmarkByName(sName);

	var oStartPara = null,
		oEndPara   = null;
	var arrParagraphs = [];
	if (true === this.IsSelectionUse())
	{
		var arrSelectedParagraphs = this.GetCurrentParagraph(false, true);
		if (arrSelectedParagraphs.length > 1)
		{
			arrParagraphs.push(arrSelectedParagraphs[0]);
			arrParagraphs.push(arrSelectedParagraphs[arrSelectedParagraphs.length - 1]);

			oStartPara = arrSelectedParagraphs[0];
			oEndPara   = arrSelectedParagraphs[arrSelectedParagraphs.length - 1];
		}
		else if (arrSelectedParagraphs.length === 1)
		{
			arrParagraphs.push(arrSelectedParagraphs[0]);

			oStartPara = arrSelectedParagraphs[0];
			oEndPara   = arrSelectedParagraphs[0];
		}
	}
	else
	{
		var oCurrentParagraph = this.GetCurrentParagraph(true);
		if (oCurrentParagraph)
		{
			arrParagraphs.push(oCurrentParagraph);
			oStartPara = oCurrentParagraph;
		}
	}

	if (arrParagraphs.length <= 0)
		return;

	if (arrBookmarkChars)
	{
		var oStartPara = arrBookmarkChars[0].GetParagraph();
		var oEndPara   = arrBookmarkChars[1].GetParagraph();

		if (oStartPara)
			arrParagraphs.push(oStartPara);

		if (oEndPara)
			arrParagraphs.push(oEndPara);
	}

	if (false === this.Document_Is_SelectionLocked(changestype_None, {Type : AscCommon.changestype_2_ElementsArray_and_Type, Elements : arrParagraphs, CheckType : changestype_Paragraph_Content}, true))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddBookmark);

		if (this.BookmarksManager.HaveBookmark(sName))
			this.private_RemoveBookmark(sName);

		var sBookmarkId = this.BookmarksManager.GetNewBookmarkId();

		if (true === this.IsSelectionUse())
		{
			var nDirection = this.GetSelectDirection();
			if (nDirection > 0)
			{
				oEndPara.AddBookmarkChar(new CParagraphBookmark(false, sBookmarkId, sName), true, false);
				oStartPara.AddBookmarkChar(new CParagraphBookmark(true, sBookmarkId, sName), true, true);
			}
			else
			{
				oEndPara.AddBookmarkChar(new CParagraphBookmark(false, sBookmarkId, sName), true, true);
				oStartPara.AddBookmarkChar(new CParagraphBookmark(true, sBookmarkId, sName), true, false);
			}
		}
		else
		{
			oStartPara.AddBookmarkChar(new CParagraphBookmark(false, sBookmarkId, sName), false);
			oStartPara.AddBookmarkChar(new CParagraphBookmark(true, sBookmarkId, sName), false);
		}

		// TODO: Здесь добавляются просто метки закладок, нужно сделать упрощенный пересчет
		this.Recalculate();
	}

};
CDocument.prototype.RemoveBookmark = function(sName)
{
	var arrBookmarkChars = this.BookmarksManager.GetBookmarkByName(sName);

	var arrParagraphs = [];
	if (arrBookmarkChars)
	{
		var oStartPara = arrBookmarkChars[0].GetParagraph();
		var oEndPara   = arrBookmarkChars[1].GetParagraph();

		if (oStartPara)
			arrParagraphs.push(oStartPara);

		if (oEndPara)
			arrParagraphs.push(oEndPara);
	}

	if (false === this.Document_Is_SelectionLocked(changestype_None, {Type : AscCommon.changestype_2_ElementsArray_and_Type, Elements : arrParagraphs, CheckType : changestype_Paragraph_Content}, true))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_RemoveBookmark);

		this.private_RemoveBookmark(sName);

		// TODO: Здесь добавляются просто метки закладок, нужно сделать упрощенный пересчет
		this.Recalculate();
	}
};
CDocument.prototype.private_RemoveBookmark = function(sName)
{
	var arrBookmarkChars = this.BookmarksManager.GetBookmarkByName(sName);
	if (!arrBookmarkChars)
		return;

	arrBookmarkChars[1].RemoveBookmark();
	arrBookmarkChars[0].RemoveBookmark();
};
CDocument.prototype.AddTableOfContents = function(sHeading, oPr, oSdt)
{
	if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Document_Content))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddTableOfContents);

        if(this.DrawingObjects.selectedObjects.length > 0)
        {
            var oContent = this.DrawingObjects.getTargetDocContent();
            if(!oContent || oContent.bPresentation)
            {
                this.DrawingObjects.resetInternalSelection();
            }
        }

        if (oSdt instanceof CBlockLevelSdt)
		{
			oSdt.ClearContentControl();
		}
		else
		{
			this.Remove(1, true, true, true);
			var oSdt = this.AddContentControl(c_oAscSdtLevelType.Block);

			if (sHeading)
			{
				var oParagraph = oSdt.GetCurrentParagraph();
				oParagraph.Style_Add(this.Get_Styles().GetDefaultTOCHeading());
				for (var oIterator = sHeading.getUnicodeIterator(); oIterator.check(); oIterator.next())
				{
					var nCharCode = oIterator.value();
					if (0x0020 === nCharCode)
						oParagraph.Add(new ParaSpace());
					else
						oParagraph.Add(new ParaText(nCharCode));
				}
				oSdt.AddNewParagraph(false, true);
			}
		}

		oSdt.SetThisElementCurrent();

		var oComplexField = this.AddFieldWithInstruction("TOC \\o \"1-3\" \\h \\z \\u");
		oSdt.SetDocPartObj(undefined, "Table of Contents", true);

		if (oPr)
		{
			oComplexField.SetPr(oPr);
			oComplexField.Update();
		}

		var oNextParagraph = oSdt.GetNextParagraph();
		if (oNextParagraph)
		{
			oNextParagraph.MoveCursorToStartPos(false);
			oNextParagraph.Document_SetThisElementCurrent();
		}
		else
		{
			oSdt.MoveCursorToEndPos(false);
		}

		this.Recalculate();

		this.Document_UpdateInterfaceState();
		this.Document_UpdateSelectionState();
		this.Document_UpdateRulersState();
	}
};
CDocument.prototype.GetPagesCount = function()
{
	return this.Pages.length;
};
/**
 * Данная функция получает первую таблицу TOC по схеме Word
 * @param {boolean} [isCurrent=false] Ищем только в текущем месте или с начала документа
 * @returns {CBlockLevelSdt | CComplexField | null}
 */
CDocument.prototype.GetTableOfContents = function(isCurrent)
{
	if (true === isCurrent)
	{
		var oSelectedInfo = this.GetSelectedElementsInfo();
		return oSelectedInfo.GetTableOfContents();
	}
	else
	{
		// 1. Ищем среди CBlockLevelSdt с параметром Unique = true
		// 2. Ищем среди CBlockLevelSdt
		// 3. Ищем потом просто в сложных полях

		for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
		{
			var oResult = this.Content[nIndex].GetTableOfContents(true, false);
			if (oResult)
				return oResult;
		}

		for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
		{
			var oResult = this.Content[nIndex].GetTableOfContents(false, true);
			if (oResult)
				return oResult;
		}
	}

	return null;
};
/**
 * Получаем текущее сложное поле
 * @returns {CComplexField | ParaPageNum | ParaPageCount | null}
 */
CDocument.prototype.GetCurrentComplexField = function()
{
	var oSelectedInfo = this.GetSelectedElementsInfo();
	var arrComplexFields = oSelectedInfo.GetComplexFields();

	if (arrComplexFields.length > 0)
		return arrComplexFields[arrComplexFields.length - 1];

	var oPageNum = oSelectedInfo.GetPageNum();
	if (oPageNum)
		return oPageNum;

	var oPagesCount = oSelectedInfo.GetPagesCount();
	if (oPagesCount)
		return oPagesCount;

	return null;
};
/**
 * Событие, которое вызывается на содании новой точки в истории
 */
CDocument.prototype.OnCreateNewHistoryPoint = function()
{
	this.AllParagraphsList = null;
	this.AllFootnotesList  = null;
};
/**
 * Получаем массив положений, к которым можно привязать гиперссылку
 * @returns {CHyperlinkAnchor[]}
 */
CDocument.prototype.GetHyperlinkAnchors = function()
{
	var arrAnchors = [];

	var arrOutline = [];
	this.GetOutlineParagraphs(arrOutline, {SkipEmptyParagraphs : true});
	var nIndex = 0, nCount = arrOutline.length;
	for (nIndex = 0; nIndex < nCount; ++nIndex)
	{
		arrAnchors.push(new CHyperlinkAnchor(c_oAscHyperlinkAnchor.Heading, arrOutline[nIndex]));
	}

	this.BookmarksManager.Update();
	nCount = this.BookmarksManager.GetCount();
	for (nIndex = 0; nIndex < nCount; ++nIndex)
	{
		var sName =  this.BookmarksManager.GetName(nIndex);
		if (!this.BookmarksManager.IsHiddenBookmark(sName) && !this.BookmarksManager.IsInternalUseBookmark(sName))
			arrAnchors.push(new CHyperlinkAnchor(c_oAscHyperlinkAnchor.Bookmark, sName));
	}

	return arrAnchors;
};
/**
 * Получаем последний примененный маркированный список
 * @returns {?CNumPr}
 */
CDocument.prototype.GetLastBulletList = function()
{
	return this.LastBulletList;
};
/**
 * Запоминаем последний примененный маркированный список
 * @param sNumId {string}
 * @param nLvl {number} 0..8
 */
CDocument.prototype.SetLastBulletList = function(sNumId, nLvl)
{
	if (!sNumId)
		this.LastBulletList = undefined;
	else
		this.LastBulletList = new CNumPr(sNumId, nLvl);
};
/**
 * Получаем последний примененный нумерованный список
 * @returns {?CNumPr}
 */
CDocument.prototype.GetLastNumberedList = function()
{
	return this.LastNumberedList;
};
/**
 * Запоминаем последний примененный нумерованный список
 * @param sNumId {string}
 * @param nLvl {number} 0..8
 */
CDocument.prototype.SetLastNumberedList = function(sNumId, nLvl)
{
	if (!sNumId)
		this.LastNumberedList = undefined;
	else
		this.LastNumberedList = new CNumPr(sNumId, nLvl);
};
/**
 * Получаем текущую выделенную нумерацию
 * @param [isCheckSelection=false] {boolean} - проверять ли по селекту
 * @returns {?CNumPr} Если выделено несколько параграфов с одним NumId, но с разными уровнями, то Lvl = null
 */
CDocument.prototype.GetSelectedNum = function(isCheckSelection)
{
	if (true === isCheckSelection)
	{
		var arrParagraphs = this.GetCurrentParagraph(false, true);
		if (arrParagraphs.length <= 0)
			return null;

		var oStartNumPr = arrParagraphs[0].GetNumPr();
		if (!oStartNumPr)
			return null;

		var oNumPr = oStartNumPr.Copy();
		for (var nIndex = 1, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
		{
			var oCurNumPr = arrParagraphs[nIndex].GetNumPr();
			if (!oCurNumPr || oCurNumPr.NumId !== oStartNumPr.NumId)
				return null;

			if (oCurNumPr.Lvl !== oStartNumPr.Lvl)
				oNumPr.Lvl = null;
		}

		return oNumPr;
	}
	else
	{
		var oCurrentPara = this.GetCurrentParagraph(true);
		if (!oCurrentPara)
			return null;

		var oDocContent = oCurrentPara.GetParent();
		if (!oDocContent)
			return null;

		var oTopDocContent = oDocContent.GetTopDocumentContent();
		if (!oTopDocContent || !oTopDocContent.IsNumberingSelection())
			return null;

		oCurrentPara = oTopDocContent.Selection.Data.CurPara;
		if (!oCurrentPara)
			return null;

		return oCurrentPara.GetNumPr();
	}
};
/**
 * Продолжаем нумерацию в текущем параграфе
 * @returns {boolean}
 */
CDocument.prototype.ContinueNumbering = function()
{
	var isNumberingSelection = this.IsNumberingSelection();

	var oParagraph = this.GetCurrentParagraph(true);
	if (!oParagraph || !oParagraph.GetNumPr() || (this.IsSelectionUse() && !isNumberingSelection))
		return false;

	var oNumPr = oParagraph.GetNumPr();

	var oEngine = new CDocumentNumberingContinueEngine(oParagraph, oNumPr, this.GetNumbering());
	this.Controller.GetSimilarNumbering(oEngine);
	var oSimilarNumPr = oEngine.GetNumPr();
	if (!oSimilarNumPr || oSimilarNumPr.NumId === oNumPr.NumId)
		return false;

	var bFind                 = false;
	var arrParagraphs         = this.GetAllParagraphsByNumbering(new CNumPr(oNumPr.NumId, null));
	var arrParagraphsToChange = [];

	var isRelated = this.GetNumbering().GetNum(oNumPr.NumId).IsHaveRelatedLvlText();

	for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
	{
		var oPara = arrParagraphs[nIndex];

		if (!bFind && oPara === oParagraph)
			bFind = true;

		if (bFind)
		{
			var oCurNumPr = oPara.GetNumPr();
			if (!oCurNumPr)
				continue;

			if (!isRelated)
			{
				if (oCurNumPr.Lvl < oNumPr.Lvl)
					break;
				else if (oCurNumPr.Lvl > oNumPr.Lvl)
					continue;
			}

			arrParagraphsToChange.push(oPara);
		}
	}

	if (!this.Document_Is_SelectionLocked(changestype_None, {
			Type      : changestype_2_ElementsArray_and_Type,
			Elements  : arrParagraphsToChange,
			CheckType : AscCommon.changestype_Paragraph_Properties
		}))
	{
		this.Create_NewHistoryPoint(AscDFH.historydescription_Document_ContinueNumbering);

		for (var nIndex = 0, nCount = arrParagraphsToChange.length; nIndex < nCount; ++nIndex)
		{
			var oPara     = arrParagraphsToChange[nIndex];
			var oCurNumPr = oPara.GetNumPr();

			oPara.SetNumPr(oSimilarNumPr.NumId, oCurNumPr.Lvl);
		}

		this.Recalculate();
		this.Document_UpdateInterfaceState();
		this.Document_UpdateSelectionState();
	}

	return true;
};
/**
 * Начинаем нумерацию занового с текущего параграфа с заданного значения
 * @param [nRestartValue=1] {number}
 * @returns {boolean}
 */
CDocument.prototype.RestartNumbering = function(nRestartValue)
{
	if (undefined === nRestartValue || null === nRestartValue)
		nRestartValue = 1;

	var isNumberingSelection = this.IsNumberingSelection();

	var oParagraph = this.GetCurrentParagraph(true);
	if (!oParagraph || !oParagraph.GetNumPr() || (this.IsSelectionUse() && !isNumberingSelection))
		return false;

	var oNumPr = oParagraph.GetNumPr();

	var bFind                 = false;
	var nPrevLvl              = null;
	var isFirstParaOnLvl      = false;
	var arrParagraphs         = this.GetAllParagraphsByNumbering(new CNumPr(oNumPr.NumId, null));
	var arrParagraphsToChange = [];
	var isRelated             = this.Numbering.GetNum(oNumPr.NumId).IsHaveRelatedLvlText();

	for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
	{
		var oPara = arrParagraphs[nIndex];

		if (!bFind && oPara === oParagraph)
		{
			bFind = true;

			if (null === nPrevLvl || nPrevLvl < oNumPr.Lvl)
				isFirstParaOnLvl = true;
		}

		var oCurNumPr = oPara.GetNumPr();

		if (bFind)
		{
			if (!oCurNumPr)
				continue;

			if (0 !== oNumPr.Lvl && !isRelated)
			{
				if (oCurNumPr.Lvl < oNumPr.Lvl)
					break;
				else if (oCurNumPr.Lvl > oNumPr.Lvl)
					continue;
			}

			arrParagraphsToChange.push(oPara);
		}

		if (oCurNumPr)
			nPrevLvl = oCurNumPr.Lvl;
	}

	var oNum = this.Numbering.GetNum(oNumPr.NumId);
	if (isFirstParaOnLvl)
	{
		if (Asc.c_oAscNumberingFormat.Bullet === oNum.GetLvl(oNumPr.Lvl).GetFormat())
			return;

		if (!this.Document_Is_SelectionLocked(changestype_None, {
				Type      : changestype_2_ElementsArray_and_Type,
				Elements  : [oNum],
				CheckType : AscCommon.changestype_Paragraph_Properties
			}))
		{
			this.Create_NewHistoryPoint(AscDFH.historydescription_Document_RestartNumbering);

			var oLvl   = oNum.GetLvl(oNumPr.Lvl).Copy();
			oLvl.Start = nRestartValue;
			oNum.SetLvl(oLvl, oNumPr.Lvl);

			this.Recalculate();
			this.Document_UpdateInterfaceState();
			this.Document_UpdateSelectionState();
		}
	}
	else
	{
		if (!this.Document_Is_SelectionLocked(changestype_None, {
				Type      : changestype_2_ElementsArray_and_Type,
				Elements  : arrParagraphsToChange,
				CheckType : AscCommon.changestype_Paragraph_Properties
			}))
		{
			this.Create_NewHistoryPoint(AscDFH.historydescription_Document_RestartNumbering);

			var oNewNum = oNum.Copy();
			if (Asc.c_oAscNumberingFormat.Bullet !== oNum.GetLvl(oNumPr.Lvl).GetFormat())
			{
				var oLvl   = oNewNum.GetLvl(oNumPr.Lvl).Copy();
				oLvl.Start = nRestartValue;
				oNewNum.SetLvl(oLvl, oNumPr.Lvl);
			}

			var sNewId = oNewNum.GetId();

			for (var nIndex = 0, nCount = arrParagraphsToChange.length; nIndex < nCount; ++nIndex)
			{
				var oPara     = arrParagraphsToChange[nIndex];
				var oCurNumPr = oPara.GetNumPr();

				oPara.SetNumPr(sNewId, oCurNumPr.Lvl);
			}

			if (isNumberingSelection)
				this.SelectNumbering(oParagraph.GetNumPr(), oParagraph);

			this.Recalculate();
			this.Document_UpdateInterfaceState();
			this.Document_UpdateSelectionState();
		}
	}

	return true;
};
/**
 * Устанавливаем настройку автосоздания маркированных списков
 * @param isAuto {boolean}
 */
CDocument.prototype.SetAutomaticBulletedLists = function(isAuto)
{
	this.AutoCorrectSettings.AutomaticBulletedLists = isAuto;
};
/**
 * Запрашиваем настройку автосоздания маркированных списков
 * @returns {boolean}
 */
CDocument.prototype.IsAutomaticBulletedLists = function()
{
	return this.AutoCorrectSettings.AutomaticBulletedLists;
};
/**
 * Устанавливаем настройку автосоздания нумерованных списков
 * @param isAuto {boolean}
 */
CDocument.prototype.SetAutomaticNumberedLists = function(isAuto)
{
	this.AutoCorrectSettings.AutomaticNumberedLists = isAuto;
};
/**
 * Запрашиваем настройку автосоздания нумерованных списков
 * @returns {boolean}
 */
CDocument.prototype.IsAutomaticNumberedLists = function()
{
	return this.AutoCorrectSettings.AutomaticNumberedLists;
};
/**
 * Устанавливаем параметр автозамены: заменять ли прямые кавычки "умными"
 * @param isSmartQuotes {boolean}
 */
CDocument.prototype.SetAutoCorrectSmartQuotes = function(isSmartQuotes)
{
	this.AutoCorrectSettings.SmartQuotes = isSmartQuotes;
};
/**
 * Запрашиваем настройку автозамены: заменять ли прямые кавычки "умными"
 * @returns {boolean}
 */
CDocument.prototype.IsAutoCorrectSmartQuotes = function()
{
	return this.AutoCorrectSettings.SmartQuotes;
};
/**
 * Устанавливаем параметр автозамены двух дефисов на тире
 * @param isReplace {boolean}
 */
CDocument.prototype.SetAutoCorrectHyphensWithDash = function(isReplace)
{
	this.AutoCorrectSettings.HyphensWithDash = isReplace;
};
/**
 * Запрашиваем настройку автозамены двух дефисов на тире
 * @returns {boolean}
 */
CDocument.prototype.IsAutoCorrectHyphensWithDash = function()
{
	return this.AutoCorrectSettings.HyphensWithDash;
};
/**
 * Получаем идентификатор текущего пользователя
 * @param [isConnectionId=false] {boolean} true - Id соединения пользователя или false - Id пользователя
 * @returns {string}
 */
CDocument.prototype.GetUserId = function(isConnectionId)
{
	if (isConnectionId)
		return this.GetApi().CoAuthoringApi.getUserConnectionId();

	return this.GetApi().DocInfo.get_UserId();
};

function CDocumentSelectionState()
{
    this.Id        = null;
    this.Type      = docpostype_Content;
    this.Data      = {}; // Объект с текущей позицией
}

function CDocumentSectionsInfo()
{
    this.Elements = [];
}

CDocumentSectionsInfo.prototype =
{
    Add : function( SectPr, Index )
    {
        this.Elements.push( new CDocumentSectionsInfoElement( SectPr, Index ) );
    },

    Get_SectionsCount : function()
    {
        return this.Elements.length;
    },

    Clear : function()
    {
        this.Elements.length = 0;
    },

    Find_ByHdrFtr : function(HdrFtr)
    {
        var Count = this.Elements.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            var SectPr = this.Elements[Index].SectPr;

            if ( HdrFtr === SectPr.Get_Header_First() || HdrFtr === SectPr.Get_Header_Default() || HdrFtr === SectPr.Get_Header_Even() ||
                 HdrFtr === SectPr.Get_Footer_First() || HdrFtr === SectPr.Get_Footer_Default() || HdrFtr === SectPr.Get_Footer_Even() )
                    return Index;
        }

        return -1;
    },

    Get_AllHdrFtrs : function()
    {
        var HdrFtrs = [];

        var Count = this.Elements.length;
        for (var Index = 0; Index < Count; Index++)
        {
            var SectPr = this.Elements[Index].SectPr;
            SectPr.Get_AllHdrFtrs(HdrFtrs);
        }

        return HdrFtrs;
    },

    Reset_HdrFtrRecalculateCache : function()
    {
        var Count = this.Elements.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            var SectPr = this.Elements[Index].SectPr;

            if ( null != SectPr.HeaderFirst )
                SectPr.HeaderFirst.Reset_RecalculateCache();

            if ( null != SectPr.HeaderDefault )
                SectPr.HeaderDefault.Reset_RecalculateCache();

            if ( null != SectPr.HeaderEven )
                SectPr.HeaderEven.Reset_RecalculateCache();

            if ( null != SectPr.FooterFirst )
                SectPr.FooterFirst.Reset_RecalculateCache();

            if ( null != SectPr.FooterDefault )
                SectPr.FooterDefault.Reset_RecalculateCache();

            if ( null != SectPr.FooterEven )
                SectPr.FooterEven.Reset_RecalculateCache();
        }
    },

    GetAllParagraphs : function(Props, ParaArray)
    {
        var Count = this.Elements.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            var SectPr = this.Elements[Index].SectPr;

            if ( null != SectPr.HeaderFirst )
                SectPr.HeaderFirst.GetAllParagraphs(Props, ParaArray);

            if ( null != SectPr.HeaderDefault )
                SectPr.HeaderDefault.GetAllParagraphs(Props, ParaArray);

            if ( null != SectPr.HeaderEven )
                SectPr.HeaderEven.GetAllParagraphs(Props, ParaArray);

            if ( null != SectPr.FooterFirst )
                SectPr.FooterFirst.GetAllParagraphs(Props, ParaArray);

            if ( null != SectPr.FooterDefault )
                SectPr.FooterDefault.GetAllParagraphs(Props, ParaArray);

            if ( null != SectPr.FooterEven )
                SectPr.FooterEven.GetAllParagraphs(Props, ParaArray);
        }
    },

	GetAllDrawingObjects : function(arrDrawings)
    {
        for (var nIndex = 0, nCount = this.Elements.length; nIndex < nCount; ++nIndex)
        {
            var SectPr = this.Elements[nIndex].SectPr;

            if (null != SectPr.HeaderFirst)
                SectPr.HeaderFirst.GetAllDrawingObjects(arrDrawings);

            if (null != SectPr.HeaderDefault)
                SectPr.HeaderDefault.GetAllDrawingObjects(arrDrawings);

            if (null != SectPr.HeaderEven)
                SectPr.HeaderEven.GetAllDrawingObjects(arrDrawings);

            if (null != SectPr.FooterFirst)
                SectPr.FooterFirst.GetAllDrawingObjects(arrDrawings);

            if (null != SectPr.FooterDefault)
                SectPr.FooterDefault.GetAllDrawingObjects(arrDrawings);

            if (null != SectPr.FooterEven)
                SectPr.FooterEven.GetAllDrawingObjects(arrDrawings);
        }
    },

    Document_CreateFontMap : function(FontMap)
    {
        var Count = this.Elements.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            var SectPr = this.Elements[Index].SectPr;

            if ( null != SectPr.HeaderFirst )
                SectPr.HeaderFirst.Document_CreateFontMap(FontMap);

            if ( null != SectPr.HeaderDefault )
                SectPr.HeaderDefault.Document_CreateFontMap(FontMap);

            if ( null != SectPr.HeaderEven )
                SectPr.HeaderEven.Document_CreateFontMap(FontMap);

            if ( null != SectPr.FooterFirst )
                SectPr.FooterFirst.Document_CreateFontMap(FontMap);

            if ( null != SectPr.FooterDefault )
                SectPr.FooterDefault.Document_CreateFontMap(FontMap);

            if ( null != SectPr.FooterEven )
                SectPr.FooterEven.Document_CreateFontMap(FontMap);
        }
    },

    Document_CreateFontCharMap : function(FontCharMap)
    {
        var Count = this.Elements.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            var SectPr = this.Elements[Index].SectPr;

            if ( null != SectPr.HeaderFirst )
                SectPr.HeaderFirst.Document_CreateFontCharMap(FontCharMap);

            if ( null != SectPr.HeaderDefault )
                SectPr.HeaderDefault.Document_CreateFontCharMap(FontCharMap);

            if ( null != SectPr.HeaderEven )
                SectPr.HeaderEven.Document_CreateFontCharMap(FontCharMap);

            if ( null != SectPr.FooterFirst )
                SectPr.FooterFirst.Document_CreateFontCharMap(FontCharMap);

            if ( null != SectPr.FooterDefault )
                SectPr.FooterDefault.Document_CreateFontCharMap(FontCharMap);

            if ( null != SectPr.FooterEven )
                SectPr.FooterEven.Document_CreateFontCharMap(FontCharMap);
        }
    },

    Document_Get_AllFontNames : function ( AllFonts )
    {
        var Count = this.Elements.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            var SectPr = this.Elements[Index].SectPr;

            if ( null != SectPr.HeaderFirst )
                SectPr.HeaderFirst.Document_Get_AllFontNames(AllFonts);

            if ( null != SectPr.HeaderDefault )
                SectPr.HeaderDefault.Document_Get_AllFontNames(AllFonts);

            if ( null != SectPr.HeaderEven )
                SectPr.HeaderEven.Document_Get_AllFontNames(AllFonts);

            if ( null != SectPr.FooterFirst )
                SectPr.FooterFirst.Document_Get_AllFontNames(AllFonts);

            if ( null != SectPr.FooterDefault )
                SectPr.FooterDefault.Document_Get_AllFontNames(AllFonts);

            if ( null != SectPr.FooterEven )
                SectPr.FooterEven.Document_Get_AllFontNames(AllFonts);
        }
    },

    Get_Index : function(Index)
    {
        var Count = this.Elements.length;

        for ( var Pos = 0; Pos < Count; Pos++ )
        {
            if ( Index <= this.Elements[Pos].Index )
                return Pos;
        }

        // Последний элемент здесь это всегда конечная секция документа
        return (Count - 1);
    },

    Get_Count : function()
    {
        return this.Elements.length;
    },

    Get_SectPr : function(Index)
    {
        var Count = this.Elements.length;

        for ( var Pos = 0; Pos < Count; Pos++ )
        {
            if ( Index <= this.Elements[Pos].Index )
                return this.Elements[Pos];
        }

        // Последний элемент здесь это всегда конечная секция документа
        return this.Elements[Count - 1];
    },

    Get_SectPr2 : function(Index)
    {
        return this.Elements[Index];
    },

    Find : function(SectPr)
    {
        var Count = this.Elements.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            var Element = this.Elements[Index];
            if ( Element.SectPr === SectPr )
                return Index;
        }

        return -1;
    },

    Update_OnAdd : function(Pos, Items)
    {
        var Count = Items.length;
        var Len = this.Elements.length;

        // Сначала обновим старые метки
        for (var Index = 0; Index < Len; Index++)
        {
            if ( this.Elements[Index].Index >= Pos )
                this.Elements[Index].Index += Count;
        }

        // Если среди новых элементов были параграфы с настройками секции, тогда добавим их здесь
        for (var Index = 0; Index < Count; Index++ )
        {
            var Item = Items[Index];
            var SectPr = ( type_Paragraph === Item.GetType() ? Item.Get_SectionPr() : undefined );

            if ( undefined !== SectPr )
            {
                var TempPos = 0;
                for ( ; TempPos < Len; TempPos++ )
                {
                    if ( Pos + Index <= this.Elements[TempPos].Index )
                        break;
                }

                this.Elements.splice( TempPos, 0, new CDocumentSectionsInfoElement( SectPr, Pos + Index ) );
                Len++;
            }
        }
    },

    Update_OnRemove : function(Pos, Count, bCheckHdrFtr)
    {
        var Len = this.Elements.length;

        for (var Index = 0; Index < Len; Index++)
        {
            var CurPos = this.Elements[Index].Index;

            if (CurPos >= Pos && CurPos < Pos + Count)
            {
                // Копируем поведение Word: Если у следующей секции не задан вообще ни один колонтитул,
                // тогда копируем ссылки на колонтитулы из удаляемой секции. Если задан хоть один колонтитул,
                // тогда этого не делаем.
                if (true === bCheckHdrFtr && Index < Len - 1)
                {
                    var CurrSectPr = this.Elements[Index].SectPr;
                    var NextSectPr = this.Elements[Index + 1].SectPr;
                    if (true === NextSectPr.IsAllHdrFtrNull() && true !== CurrSectPr.IsAllHdrFtrNull())
                    {
                        NextSectPr.Set_Header_First(CurrSectPr.Get_Header_First());
                        NextSectPr.Set_Header_Even(CurrSectPr.Get_Header_Even());
                        NextSectPr.Set_Header_Default(CurrSectPr.Get_Header_Default());
                        NextSectPr.Set_Footer_First(CurrSectPr.Get_Footer_First());
                        NextSectPr.Set_Footer_Even(CurrSectPr.Get_Footer_Even());
                        NextSectPr.Set_Footer_Default(CurrSectPr.Get_Footer_Default());
                    }
                }

                this.Elements.splice(Index, 1);
                Len--;
                Index--;


            }
            else if (CurPos >= Pos + Count)
                this.Elements[Index].Index -= Count;
        }
    }
};
CDocumentSectionsInfo.prototype.GetAllContentControls = function(arrContentControls)
{
	for (var nIndex = 0, nCount = this.Elements.length; nIndex < nCount; ++nIndex)
	{
		var SectPr = this.Elements[nIndex].SectPr;

		if (null != SectPr.HeaderFirst)
			SectPr.HeaderFirst.GetAllContentControls(arrContentControls);

		if (null != SectPr.HeaderDefault)
			SectPr.HeaderDefault.GetAllContentControls(arrContentControls);

		if (null != SectPr.HeaderEven)
			SectPr.HeaderEven.GetAllContentControls(arrContentControls);

		if (null != SectPr.FooterFirst)
			SectPr.FooterFirst.GetAllContentControls(arrContentControls);

		if (null != SectPr.FooterDefault)
			SectPr.FooterDefault.GetAllContentControls(arrContentControls);

		if (null != SectPr.FooterEven)
			SectPr.FooterEven.GetAllContentControls(arrContentControls);
	}
};
/**
 * Обновляем заданную секцию
 * @param oSectPr {CSectionPr} - Секция, которую нужно обновить
 * @param oNewSectPr {?CSectionPr} - Либо новое значение секции, либо undefined для удалении секции
 * @param isCheckHdrFtr {boolean} - Нужно ли проверять колонтитулы при удалении секции
 * @returns {boolean} Если не смогли обновить, возвращаем false
 */
CDocumentSectionsInfo.prototype.UpdateSection = function(oSectPr, oNewSectPr, isCheckHdrFtr)
{
	if (oSectPr === oNewSectPr || !oSectPr)
		return false;

	for (var nIndex = 0, nCount = this.Elements.length; nIndex < nCount; ++nIndex)
	{
		if (oSectPr === this.Elements[nIndex].SectPr)
		{
			if (!oNewSectPr)
			{
				// Копируем поведение Word: Если у следующей секции не задан вообще ни один колонтитул,
				// тогда копируем ссылки на колонтитулы из удаляемой секции. Если задан хоть один колонтитул,
				// тогда этого не делаем.
				if (true === isCheckHdrFtr && nIndex < nCount - 1)
				{
					var oCurrSectPr = this.Elements[nIndex].SectPr;
					var oNextSectPr = this.Elements[nIndex + 1].SectPr;

					if (true === oNextSectPr.IsAllHdrFtrNull() && true !== oCurrSectPr.IsAllHdrFtrNull())
					{
						oNextSectPr.Set_Header_First(oCurrSectPr.Get_Header_First());
						oNextSectPr.Set_Header_Even(oCurrSectPr.Get_Header_Even());
						oNextSectPr.Set_Header_Default(oCurrSectPr.Get_Header_Default());
						oNextSectPr.Set_Footer_First(oCurrSectPr.Get_Footer_First());
						oNextSectPr.Set_Footer_Even(oCurrSectPr.Get_Footer_Even());
						oNextSectPr.Set_Footer_Default(oCurrSectPr.Get_Footer_Default());
					}
				}

				this.Elements.splice(nIndex, 1);
			}
			else
			{
				this.Elements[nIndex].SectPr = oNewSectPr;
			}

			return true;
		}
	}

	return false;
};

function CDocumentSectionsInfoElement(SectPr, Index)
{
    this.SectPr = SectPr;
    this.Index  = Index;
}

function CDocumentCompareDrawingsLogicPositions(Drawing1, Drawing2)
{
    this.Drawing1 = Drawing1;
    this.Drawing2 = Drawing2;
    this.Result   = 0;
}

function CTrackRevisionsManager(LogicDocument)
{
    this.LogicDocument = LogicDocument;
    this.CheckPara     = {}; // Параграфы, которые нужно проверить
    this.Changes       = {}; // Объект с ключом - Id параграфа, в котором лежит массив изменений

    this.CurChange     = null; // Текущеее изменение
    this.CurPara       = null; // Параграф с текущим изменением

    this.VisibleChanges = []; // Изменения, которые отображаются в сплывающем окне
    this.OldVisibleChanges = [];
}

CTrackRevisionsManager.prototype.Check_Paragraph = function(Para)
{
    var ParaId = Para.Get_Id();
    if (undefined == this.CheckPara[ParaId])
        this.CheckPara[ParaId] = 1;
    else
        this.CheckPara[ParaId]++;
};
CTrackRevisionsManager.prototype.Add_Change = function(ParaId, Change)
{
    if (undefined === this.Changes[ParaId])
        this.Changes[ParaId] = [];

    this.Changes[ParaId].push(Change);
};
CTrackRevisionsManager.prototype.Get_ParagraphChanges = function(ParaId)
{
    if (this.Changes[ParaId])
        return this.Changes[ParaId];

    return [];
};
CTrackRevisionsManager.prototype.ContinueTrackRevisions = function()
{
	// За раз обрабатываем не больше 50 параграфов, чтобы не подвешивать клиент на открытии файлов
	var nMaxCounter = 50,
		nCounter    = 0;

	var bNeedUpdate = false;
	for (var sParaId in this.CheckPara)
	{
		if (this.private_TrackChangesForParagraph(sParaId))
			bNeedUpdate = true;

		++nCounter;
		if (nCounter >= nMaxCounter)
			break;
	}

	if (bNeedUpdate)
		this.LogicDocument.Document_UpdateInterfaceState();
};
CTrackRevisionsManager.prototype.Get_NextChange = function()
{
    var OldCurChange = this.CurChange;
    var OldCurPara   = this.CurPara;

    var NextPara = null;
    if (null !== this.CurChange && null !== this.CurPara && this.Changes[this.CurPara.GetId()])
    {
        var ChangesArray = this.Changes[this.CurPara.GetId()];
        var ChangeIndex = -1;
        for (var Index = 0, Count = ChangesArray.length; Index < Count; Index++)
        {
            if (this.CurChange === ChangesArray[Index])
            {
                ChangeIndex = Index;
                break;
            }
        }

        if (-1 !== ChangeIndex && ChangeIndex < ChangesArray.length - 1)
        {
            this.CurChange = ChangesArray[ChangeIndex + 1];
            return this.CurChange;
        }

        NextPara = this.LogicDocument.GetRevisionsChangeParagraph(1, this.CurPara);
    }
    else
    {
        var SearchEngine = this.LogicDocument.private_GetRevisionsChangeParagraph(1, null);
        NextPara = SearchEngine.Get_FoundedParagraph();
        if (null !== NextPara && NextPara === SearchEngine.GetCurrentParagraph())
        {
            var NextChangesArray = this.Changes[NextPara.Get_Id()];
            if (undefined !== NextChangesArray && NextChangesArray.length > 0)
            {
                var ParaContentPos = NextPara.Get_ParaContentPos(NextPara.IsSelectionUse(), true);
                for (var ChangeIndex = 0, Count = NextChangesArray.length; ChangeIndex < Count; ChangeIndex++)
                {
                    var ChangeEndPos = NextChangesArray[ChangeIndex].get_EndPos();
                    if (ParaContentPos.Compare(ChangeEndPos) <= 0)
                    {
                        this.CurChange = NextChangesArray[ChangeIndex];
                        this.CurPara   = NextPara;
                        return this.CurChange;
                    }
                }
                NextPara = this.LogicDocument.GetRevisionsChangeParagraph(1, NextPara);
            }
        }
    }

    if (null !== NextPara)
    {
        var NextChangesArray = this.Changes[NextPara.Get_Id()];
        if (undefined !== NextChangesArray && NextChangesArray.length > 0)
        {
            this.CurChange = NextChangesArray[0];
            this.CurPara   = NextPara;
            return this.CurChange;
        }
    }

    if (null !== OldCurChange && null !== OldCurPara)
    {
        this.CurChange = OldCurChange;
        this.CurPara   = OldCurPara;
        return OldCurChange;
    }

    this.CurChange = null;
    this.CurPara   = null;
    return null;
};
CTrackRevisionsManager.prototype.Get_PrevChange = function()
{
    var OldCurChange = this.CurChange;
    var OldCurPara   = this.CurPara;

    var PrevPara = null;
    if (null !== this.CurChange && null !== this.CurPara)
    {
        var ChangesArray = this.Changes[this.CurPara.Get_Id()];
        var ChangeIndex = -1;
        for (var Index = 0, Count = ChangesArray.length; Index < Count; Index++)
        {
            if (this.CurChange === ChangesArray[Index])
            {
                ChangeIndex = Index;
                break;
            }
        }

        if (-1 !== ChangeIndex && ChangeIndex > 0)
        {
            this.CurChange = ChangesArray[ChangeIndex - 1];
            return this.CurChange;
        }

        PrevPara = this.LogicDocument.GetRevisionsChangeParagraph(-1, this.CurPara);
    }
    else
    {
        var SearchEngine = this.LogicDocument.private_GetRevisionsChangeParagraph(-1, null);
        PrevPara = SearchEngine.Get_FoundedParagraph();
        if (null !== PrevPara && PrevPara === SearchEngine.GetCurrentParagraph())
        {
            var PrevChangesArray = this.Changes[PrevPara.Get_Id()];
            if (undefined !== PrevChangesArray && PrevChangesArray.length > 0)
            {
                var ParaContentPos = PrevPara.Get_ParaContentPos(PrevPara.IsSelectionUse(), true);
                for (var ChangeIndex = PrevChangesArray.length - 1; ChangeIndex >= 0; ChangeIndex--)
                {
                    var ChangeStartPos = PrevChangesArray[ChangeIndex].get_StartPos();
                    if (ParaContentPos.Compare(ChangeStartPos) >= 0)
                    {
                        this.CurChange = PrevChangesArray[ChangeIndex];
                        this.CurPara   = PrevPara;
                        return this.CurChange;
                    }
                }

                PrevPara = this.LogicDocument.GetRevisionsChangeParagraph(-1, PrevPara);
            }
        }
    }

    if (null !== PrevPara)
    {
        var PrevChangesArray = this.Changes[PrevPara.Get_Id()];
        if (undefined !== PrevChangesArray && PrevChangesArray.length > 0)
        {
            this.CurChange = PrevChangesArray[PrevChangesArray.length - 1];
            this.CurPara = PrevPara;
            return this.CurChange;
        }
    }

    if (null !== OldCurChange && null !== OldCurPara)
    {
        this.CurChange = OldCurChange;
        this.CurPara   = OldCurPara;
        return OldCurChange;
    }

    this.CurChange = null;
    this.CurPara   = null;
    return null;
};
CTrackRevisionsManager.prototype.Have_Changes = function()
{
    for (var ParaId in this.Changes)
    {
        if (this.Changes[ParaId].length > 0)
            return true;
    }

    return false;
};
/**
 * Проверяем есть ли изменения, сделанные другими пользователями
 * @returns {boolean}
 */
CTrackRevisionsManager.prototype.HaveOtherUsersChanges = function()
{
	var sUserId = this.LogicDocument.GetUserId(false);
	for (var sParaId in this.Changes)
	{
		var oParagraph = AscCommon.g_oTableId.Get_ById(sParaId);
		if (!oParagraph || !oParagraph.Is_UseInDocument())
			continue;

		for (var nIndex = 0, nCount = this.Changes[sParaId].length; nIndex < nCount; ++nIndex)
		{
			var oChange = this.Changes[sParaId][nIndex];
			if (oChange.get_UserId() !== sUserId)
				return true;
		}
	}

	return false;
};
CTrackRevisionsManager.prototype.Clear_CurrentChange = function()
{
    this.CurChange = null;
    this.CurPara   = null;
};
CTrackRevisionsManager.prototype.Get_CurrentChangeParagraph = function()
{
    return this.CurPara;
};
CTrackRevisionsManager.prototype.Get_CurrentChange = function()
{
    return this.CurChange;
};
CTrackRevisionsManager.prototype.Clear_VisibleChanges = function()
{
	if (this.VisibleChanges.length > 0)
	{
		var oEditorApi = this.LogicDocument.Get_Api();
		oEditorApi.sync_BeginCatchRevisionsChanges();
		oEditorApi.sync_EndCatchRevisionsChanges();
	}

    this.VisibleChanges = [];
};
CTrackRevisionsManager.prototype.Add_VisibleChange = function(Change)
{
    this.VisibleChanges.push(Change);
};
CTrackRevisionsManager.prototype.Get_VisibleChanges = function()
{
    return this.VisibleChanges;
};
CTrackRevisionsManager.prototype.Begin_CollectChanges = function(bSaveCurrentChange)
{
    if (true === this.private_HaveParasToCheck())
        return;

    if (true !== bSaveCurrentChange)
        this.Clear_CurrentChange();

    this.OldVisibleChanges = this.VisibleChanges;
    this.VisibleChanges = [];
};
CTrackRevisionsManager.prototype.End_CollectChanges = function(oEditor)
{
    if (true === this.private_HaveParasToCheck())
        return;

    if (null !== this.CurChange)
        this.VisibleChanges = [this.CurChange];

    var bMove = false;
    var bChange = false;

    var Len = this.VisibleChanges.length;
    if (this.OldVisibleChanges.length !== Len)
    {
        bChange = true;
    }
    else if (0 !== Len)
    {
        for (var ChangeIndex = 0; ChangeIndex < Len; ChangeIndex++)
        {
            if (this.OldVisibleChanges[ChangeIndex] !== this.VisibleChanges[ChangeIndex])
            {
                bChange = true;
                break;
            }
            else if (true !== this.VisibleChanges[ChangeIndex].ComparePrevPosition())
            {
                bMove = true;
            }
        }
    }

    if (true === bChange)
    {
        oEditor.sync_BeginCatchRevisionsChanges();

        if (Len > 0)
        {
            var Pos = this.private_GetVisibleChangesXY();
            for (var ChangeIndex = 0; ChangeIndex < Len; ChangeIndex++)
            {
                var Change = this.VisibleChanges[ChangeIndex];
                Change.put_XY(Pos.X, Pos.Y);
                oEditor.sync_AddRevisionsChange(Change);
            }
        }
        oEditor.sync_EndCatchRevisionsChanges();
    }
    else if (true === bMove)
    {
        this.Update_VisibleChangesPosition(oEditor);
    }
};
CTrackRevisionsManager.prototype.Update_VisibleChangesPosition = function(oEditor)
{
    if (this.VisibleChanges.length > 0)
    {
        var Pos = this.private_GetVisibleChangesXY();
        oEditor.sync_UpdateRevisionsChangesPosition(Pos.X, Pos.Y);
    }
};
CTrackRevisionsManager.prototype.private_GetVisibleChangesXY = function()
{
    if (this.VisibleChanges.length > 0)
    {
        var Change = this.VisibleChanges[0];
        var Change_X       = Change.get_InternalPosX();
        var Change_Y       = Change.get_InternalPosY();
        var Change_PageNum = Change.get_InternalPosPageNum();
        var Change_Para    = Change.get_Paragraph();
        if (Change_Para && Change_Para.DrawingDocument)
        {
            var TextTransform = (Change_Para ? Change_Para.Get_ParentTextTransform() : undefined);
            if (TextTransform)
                Change_Y = TextTransform.TransformPointY(Change_X, Change_Y);

            var Coords = Change_Para.DrawingDocument.ConvertCoordsToCursorWR(Change_X, Change_Y, Change_PageNum);
            return {X : Coords.X, Y : Coords.Y};
        }
    }

    return {X : 0, Y : 0};
};
CTrackRevisionsManager.prototype.Get_AllChangesLogicDocuments = function()
{
	this.CompleteTrackChanges();
    var LogicDocuments = {};

    for (var ParaId in this.Changes)
    {
        var Para = g_oTableId.Get_ById(ParaId);
        if (Para && Para.Get_Parent())
        {
            LogicDocuments[Para.Get_Parent().Get_Id()] = true;
        }
    }

    return LogicDocuments;
};
CTrackRevisionsManager.prototype.GetChangeRelatedParagraphs = function(oChange, bAccept)
{
    var RelatedParas = {};
    this.private_GetChangeRelatedParagraphs(oChange, bAccept, RelatedParas);
    return this.private_ConvertParagraphsObjectToArray(RelatedParas);
};
CTrackRevisionsManager.prototype.private_GetChangeRelatedParagraphs = function(Change, bAccept, RelatedParas)
{
    if (undefined !== Change)
    {
        var Type = Change.get_Type();
        var Para = Change.get_Paragraph();
        if (Para)
        {
            RelatedParas[Para.Get_Id()] = true;
            if ((c_oAscRevisionsChangeType.ParaAdd === Type && true !== bAccept) || (c_oAscRevisionsChangeType.ParaRem === Type && true === bAccept))
            {
                var LogicDocument = Para.Get_Parent();
                var ParaIndex = Para.Get_Index();

                if (LogicDocument && -1 !== ParaIndex)
                {
                    if (ParaIndex < LogicDocument.GetElementsCount() - 1)
                    {
                        var Element = LogicDocument.GetElement(ParaIndex + 1);
                        if (Element && type_Paragraph === Element.Get_Type())
                            RelatedParas[Element.Get_Id()] = true;
                    }
                }
            }
        }
    }
};
CTrackRevisionsManager.prototype.private_ConvertParagraphsObjectToArray = function(ParagraphsObject)
{
    var ParagraphsArray = [];
    for (var ParaId in ParagraphsObject)
    {
        var Para = g_oTableId.Get_ById(ParaId);
        if (null !== Para)
        {
            ParagraphsArray.push(Para);
        }
    }
    return ParagraphsArray;
};
CTrackRevisionsManager.prototype.Get_AllChangesRelatedParagraphs = function(bAccept)
{
    var RelatedParas = {};
    for (var ParaId in this.Changes)
    {
        for (var ChangeIndex = 0, ChangesCount = this.Changes[ParaId].length; ChangeIndex < ChangesCount; ++ChangeIndex)
        {
            var Change = this.Changes[ParaId][ChangeIndex];
            this.private_GetChangeRelatedParagraphs(Change, bAccept, RelatedParas);
        }
    }
    return this.private_ConvertParagraphsObjectToArray(RelatedParas);
};
CTrackRevisionsManager.prototype.Get_AllChangesRelatedParagraphsBySelectedParagraphs = function(SelectedParagraphs, bAccept)
{
    var RelatedParas = {};
    for (var ParaIndex = 0, ParasCount = SelectedParagraphs.length; ParaIndex < ParasCount; ++ParaIndex)
    {
        var Para = SelectedParagraphs[ParaIndex];
        var ParaId = Para.Get_Id();
        if (this.Changes[ParaId] && this.Changes[ParaId].length > 0)
        {
            RelatedParas[ParaId] = true;
            if (true === Para.Selection_CheckParaEnd())
            {
                var CheckNext = false;
                for (var ChangeIndex = 0, ChangesCount = this.Changes[ParaId].length; ChangeIndex < ChangesCount; ++ChangeIndex)
                {
                    var ChangeType = this.Changes[ParaId][ChangeIndex].get_Type();
                    if ((c_oAscRevisionsChangeType.ParaAdd === ChangeType && true !== bAccept) || (c_oAscRevisionsChangeType.ParaRem === ChangeType && true === bAccept))
                    {
                        CheckNext = true;
                        break;
                    }
                }

                if (true === CheckNext)
                {
                    var NextElement = Para.Get_DocumentNext();
                    if (null !== NextElement && type_Paragraph === NextElement.Get_Type())
                    {
                        RelatedParas[NextElement.Get_Id()] = true;
                    }
                }
            }
        }
    }
    return this.private_ConvertParagraphsObjectToArray(RelatedParas);
};
CTrackRevisionsManager.prototype.private_HaveParasToCheck = function()
{
    for (var ParaId in this.CheckPara)
    {
        var Para = g_oTableId.Get_ById(ParaId);
        if (Para && Para instanceof Paragraph && Para.Is_UseInDocument())
            return true;
    }

    return false;
};
CTrackRevisionsManager.prototype.Get_AllChanges = function()
{
	this.CompleteTrackChanges();
	return this.Changes;
};
CTrackRevisionsManager.prototype.private_IsAllParagraphsChecked = function()
{
	for (var ParaId in this.CheckPara)
	{
		return false;
	}

	return true;
};
/**
 * Завершаем проверку всех элементов на наличие рецензирования
 */
CTrackRevisionsManager.prototype.CompleteTrackChanges = function()
{
	while (!this.private_IsAllParagraphsChecked())
		this.ContinueTrackRevisions();
};
/**
 * Завершаем проверку рецензирования для заданных элементов
 * @param arrElements
 * @returns {boolean}
 */
CTrackRevisionsManager.prototype.CompleteTrackChangesForElements = function(arrElements)
{
	var isChecked = false;
	for (var nIndex = 0, nCount = arrElements.length; nIndex < nCount; ++nIndex)
	{
		var sElementId = arrElements[nIndex].GetId();
		if (this.private_TrackChangesForParagraph(sElementId))
			isChecked = true;
	}

	return isChecked;
};
CTrackRevisionsManager.prototype.private_TrackChangesForParagraph = function(sParaId)
{
	if (this.CheckPara[sParaId])
	{
		delete this.CheckPara[sParaId];
		var oParagraph = g_oTableId.Get_ById(sParaId);
		if (oParagraph && oParagraph instanceof Paragraph && oParagraph.Is_UseInDocument())
		{
			delete this.Changes[sParaId];
			oParagraph.Check_RevisionsChanges(this);
			return true;
		}
	}

	return false;
};

function CRevisionsChangeParagraphSearchEngine(Direction, CurrentPara, TrackManager)
{
    this.TrackManager = TrackManager;
    this.Direction    = Direction;
    this.CurrentPara  = CurrentPara;
    this.CurrentFound = false;

    this.Para         = null;
}
CRevisionsChangeParagraphSearchEngine.prototype.Set_CurrentFound = function(Para)
{
    this.CurrentFound = true;
};
CRevisionsChangeParagraphSearchEngine.prototype.Set_CurrentParagraph = function(Para)
{
    this.CurrentPara = Para;
};
CRevisionsChangeParagraphSearchEngine.prototype.Is_CurrentFound = function()
{
    return this.CurrentFound;
};
CRevisionsChangeParagraphSearchEngine.prototype.GetCurrentParagraph = function()
{
    return this.CurrentPara;
};
CRevisionsChangeParagraphSearchEngine.prototype.Set_FoundedParagraph = function(Para)
{
    if (this.TrackManager.Get_ParagraphChanges(Para.Get_Id()).length > 0)
        this.Para = Para;
};
CRevisionsChangeParagraphSearchEngine.prototype.Is_Found = function()
{
    return (null === this.Para ? false : true);
};
CRevisionsChangeParagraphSearchEngine.prototype.Get_FoundedParagraph = function()
{
    return this.Para;
};
CRevisionsChangeParagraphSearchEngine.prototype.Get_Direction = function()
{
    return this.Direction;
};

function CDocumentPagePosition()
{
    this.Page   = 0;
    this.Column = 0;
}

/**
 * Класс для рассчета значение номера для нумерации заданного параграфа
 * @param oPara {Paragraph}
 * @param oNumPr {CNumPr}
 * @param oNumbering {CNumbering}
 * @constructor
 */
function CDocumentNumberingInfoEngine(oPara, oNumPr, oNumbering)
{
	this.Paragraph   = oPara;
	this.NumId       = oNumPr.NumId;
	this.Lvl         = oNumPr.Lvl;
	this.Numbering   = oNumbering;
	this.NumInfo     = new Array(this.Lvl + 1);
	this.Restart     = [-1, -1, -1, -1, -1, -1, -1, -1, -1]; // Этот параметр контролирует уровень, начиная с которого делаем рестарт для текущего уровня
	this.PrevLvl     = -1;
	this.Found       = false;
	this.AbstractNum = null;
	this.Nums        = {}; // Список Num, которые использовались. Нужно для обработки startOverride
	this.Start       = [];

	for (var nIndex = 0; nIndex < 9; ++nIndex)
		this.NumInfo[nIndex] = undefined;

	if (!this.Numbering)
		return;

	var oNum = this.Numbering.GetNum(this.NumId);
	if (!oNum)
		return;

	var oAbstractNum = oNum.GetAbstractNum();
	if (oAbstractNum)
	{
		for (var nLvl = 0; nLvl < 9; ++nLvl)
		{
			this.Restart[nLvl] = oAbstractNum.GetLvl(nLvl).GetRestart();
			this.Start[nLvl]   = oAbstractNum.GetLvl(nLvl).GetStart() - 1;
		}
	}

	this.AbstractNum = oAbstractNum;
}

/**
 * Проверяем закончилось ли вычисление номера
 * @returns {boolean}
 * @constructor
 */
CDocumentNumberingInfoEngine.prototype.IsStop = function()
{
    return this.Found;
};
/**
 * Проверяем параграф
 * @param oPara {Paragraph}
 */
CDocumentNumberingInfoEngine.prototype.CheckParagraph = function(oPara)
{
	if (!this.Numbering)
		return;

	var oParaNumPr = oPara.GetNumPr();
	if (!oParaNumPr)
		return;

	var oNum         = this.Numbering.GetNum(oParaNumPr.NumId);
	var oAbstractNum = oNum.GetAbstractNum();

	if (oAbstractNum === this.AbstractNum && (undefined === oPara.Get_SectionPr() || true !== oPara.IsEmpty()))
	{
		if (-1 === this.PrevLvl)
		{
			for (var nLvl = 0; nLvl < 9; ++nLvl)
			{
				this.NumInfo[nLvl] = this.Start[nLvl];
			}
		}
		else if (oParaNumPr.Lvl < this.PrevLvl)
		{
			for (var nLvl = 0; nLvl < 9; ++nLvl)
			{
				if (nLvl > oParaNumPr.Lvl && 0 !== this.Restart[nLvl] && (-1 === this.Restart[nLvl] || oParaNumPr.Lvl <= this.Restart[nLvl] - 1))
					this.NumInfo[nLvl] = this.Start[nLvl];
			}
		}
		else if (oParaNumPr.Lvl > this.PrevLvl)
		{
			for (var nLvl = this.PrevLvl + 1; nLvl < oParaNumPr.Lvl; ++nLvl)
			{
				this.NumInfo[nLvl]++;
			}
		}

		this.NumInfo[oParaNumPr.Lvl]++;

		if (this.private_CheckNum(oNum))
		{
			var nForceStart = oNum.GetStartOverride(oParaNumPr.Lvl);
			if (-1 !== nForceStart)
        		this.NumInfo[oParaNumPr.Lvl] = nForceStart;
		}

        for (var nIndex = oParaNumPr.Lvl - 1; nIndex >= 0; --nIndex)
        {
            if (undefined === this.NumInfo[nIndex] || 0 === this.NumInfo[nIndex])
                this.NumInfo[nIndex] = 1;
        }

        this.PrevLvl = oParaNumPr.Lvl;
    }

    if (this.Paragraph === oPara)
        this.Found = true;
};
CDocumentNumberingInfoEngine.prototype.GetNumInfo = function()
{
    return this.NumInfo;
};
CDocumentNumberingInfoEngine.prototype.private_CheckNum = function(oNum)
{
	if (this.Nums[oNum.GetId()])
		return false;

	this.Nums[oNum.GetId()] = oNum;

	return true;
};

function CDocumentFootnotesRangeEngine(bExtendedInfo)
{
	this.m_oFirstFootnote = null; // Если не задана ищем с начала
	this.m_oLastFootnote  = null; // Если не задана ищем до конца

	this.m_arrFootnotes  = [];
	this.m_bForceStop    = false;

	this.m_bExtendedInfo = (true === bExtendedInfo ? true : false);
	this.m_arrParagraphs = [];
	this.m_oCurParagraph = null;
	this.m_arrRuns       = [];
	this.m_arrRefs       = [];
}
CDocumentFootnotesRangeEngine.prototype.Init = function(oFirstFootnote, oLastFootnote)
{
	this.m_oFirstFootnote = oFirstFootnote ? oFirstFootnote : null;
	this.m_oLastFootnote  = oLastFootnote ? oLastFootnote : null;
};
CDocumentFootnotesRangeEngine.prototype.Add = function(oFootnote, oFootnoteRef, oRun)
{
	if (!oFootnote || true === this.m_bForceStop)
		return;

	if (this.m_arrFootnotes.length <= 0 && null !== this.m_oFirstFootnote)
	{
		if (this.m_oFirstFootnote === oFootnote)
			this.private_AddFootnote(oFootnote, oFootnoteRef, oRun);
		else if (this.m_oLastFootnote === oFootnote)
			this.m_bForceStop = true;
	}
	else if (this.m_arrFootnotes.length >= 1 && null !== this.m_oLastFootnote)
	{
		if (this.m_oLastFootnote !== this.m_arrFootnotes[this.m_arrFootnotes.length - 1])
			this.private_AddFootnote(oFootnote, oFootnoteRef, oRun);
	}
	else
	{
		this.private_AddFootnote(oFootnote, oFootnoteRef, oRun);
	}
};
CDocumentFootnotesRangeEngine.prototype.IsRangeFull = function()
{
	if (true === this.m_bForceStop)
		return true;

	if (null !== this.m_oLastFootnote && this.m_arrFootnotes.length >= 1 && this.m_oLastFootnote === this.m_arrFootnotes[this.m_arrFootnotes.length - 1])
		return true;

	return false;
};
CDocumentFootnotesRangeEngine.prototype.GetRange = function()
{
	return this.m_arrFootnotes;
};
CDocumentFootnotesRangeEngine.prototype.GetParagraphs = function()
{
	return this.m_arrParagraphs;
};
CDocumentFootnotesRangeEngine.prototype.SetCurrentParagraph = function(oParagraph)
{
	this.m_oCurParagraph = oParagraph;
};
CDocumentFootnotesRangeEngine.prototype.private_AddFootnote = function(oFootnote, oFootnoteRef, oRun)
{
	this.m_arrFootnotes.push(oFootnote);

	if (true === this.m_bExtendedInfo)
	{
		this.m_arrRuns.push(oRun);
		this.m_arrRefs.push(oFootnoteRef);

		// Добавляем в общий список используемых параграфов
		var nCount = this.m_arrParagraphs.length;
		if (nCount <= 0 || this.m_arrParagraphs[nCount - 1] !== this.m_oCurParagraph)
			this.m_arrParagraphs[nCount] = this.m_oCurParagraph;
	}
};
CDocumentFootnotesRangeEngine.prototype.GetRuns = function()
{
	return this.m_arrRuns;
};
CDocumentFootnotesRangeEngine.prototype.GetRefs = function()
{
	return this.m_arrRefs;
};

/**
 * Класс для поиска подходящей нумерации в документе
 * @param oParagraph {Paragraph}
 * @param oNumPr {CNumPr}
 * @param oNumbering {CNumbering}
 */
function CDocumentNumberingContinueEngine(oParagraph, oNumPr, oNumbering)
{
	this.Paragraph = oParagraph;
	this.NumPr     = oNumPr;
	this.Numbering = oNumbering;

	this.Found        = false;
	this.SimilarNumPr = null;
	this.LastNumPr    = null; // Для случая нулевого уровня, когда не получилось подобрать подходящий
}
/**
 * Проверем, дошли ли мы до заданного параграфа
 * @returns {boolean}
 */
CDocumentNumberingContinueEngine.prototype.IsFound = function()
{
	return this.Found;
};
/**
 * Проверяем параграф на совпадение нумераций
 * @param oParagraph {Paragraph}
 */
CDocumentNumberingContinueEngine.prototype.CheckParagraph = function(oParagraph)
{
	if (this.IsFound())
		return;

	if (oParagraph === this.Paragraph)
	{
		this.Found = true;
	}
	else
	{
		var oNumPr = oParagraph.GetNumPr();
		if (oNumPr && oNumPr.Lvl === this.NumPr.Lvl)
		{
			if (oNumPr.Lvl > 0)
			{
				this.SimilarNumPr = new CNumPr(oNumPr.NumId, this.NumPr.Lvl);
			}
			else
			{
				var oCurLvl = this.Numbering.GetNum(oNumPr.NumId).GetLvl(0);
				var oLvl    = this.Numbering.GetNum(this.NumPr.NumId).GetLvl(0);

				if (oCurLvl.IsSimilar(oLvl) || (oCurLvl.GetFormat() === oLvl.GetFormat() && Asc.c_oAscNumberingFormat.Bullet === oCurLvl.GetFormat()))
					this.SimilarNumPr = new CNumPr(oNumPr.NumId, 0);
			}

			this.LastNumPr = new CNumPr(oNumPr.NumId, this.NumPr.Lvl);
		}
	}
};
/**
 * Получаем подходящую нумерацию
 * @returns {?CNumPr}
 */
CDocumentNumberingContinueEngine.prototype.GetNumPr = function()
{
	return this.SimilarNumPr ? this.SimilarNumPr : this.LastNumPr;
};


//-------------------------------------------------------------export---------------------------------------------------
window['Asc'] = window['Asc'] || {};
window['AscCommon'] = window['AscCommon'] || {};
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CDocument = CDocument;
window['AscCommonWord'].docpostype_Content        = docpostype_Content;
window['AscCommonWord'].docpostype_HdrFtr         = docpostype_HdrFtr;
window['AscCommonWord'].docpostype_DrawingObjects = docpostype_DrawingObjects;
window['AscCommonWord'].docpostype_Footnotes      = docpostype_Footnotes;

window['AscCommon'].Page_Width = Page_Width;
window['AscCommon'].Page_Height = Page_Height;
window['AscCommon'].X_Left_Margin = X_Left_Margin;
window['AscCommon'].X_Right_Margin = X_Right_Margin;
window['AscCommon'].Y_Bottom_Margin = Y_Bottom_Margin;
window['AscCommon'].Y_Top_Margin = Y_Top_Margin;
window['AscCommon'].selectionflag_Common = selectionflag_Common;

CDocumentColumnProps.prototype['put_W']     = CDocumentColumnProps.prototype.put_W;
CDocumentColumnProps.prototype['get_W']     = CDocumentColumnProps.prototype.get_W;
CDocumentColumnProps.prototype['put_Space'] = CDocumentColumnProps.prototype.put_Space;
CDocumentColumnProps.prototype['get_Space'] = CDocumentColumnProps.prototype.get_Space;

window['Asc']['CDocumentColumnsProps'] = CDocumentColumnsProps;
CDocumentColumnsProps.prototype['get_EqualWidth'] = CDocumentColumnsProps.prototype.get_EqualWidth;
CDocumentColumnsProps.prototype['put_EqualWidth'] = CDocumentColumnsProps.prototype.put_EqualWidth;
CDocumentColumnsProps.prototype['get_Num']        = CDocumentColumnsProps.prototype.get_Num       ;
CDocumentColumnsProps.prototype['put_Num']        = CDocumentColumnsProps.prototype.put_Num       ;
CDocumentColumnsProps.prototype['get_Sep']        = CDocumentColumnsProps.prototype.get_Sep       ;
CDocumentColumnsProps.prototype['put_Sep']        = CDocumentColumnsProps.prototype.put_Sep       ;
CDocumentColumnsProps.prototype['get_Space']      = CDocumentColumnsProps.prototype.get_Space     ;
CDocumentColumnsProps.prototype['put_Space']      = CDocumentColumnsProps.prototype.put_Space     ;
CDocumentColumnsProps.prototype['get_ColsCount']  = CDocumentColumnsProps.prototype.get_ColsCount ;
CDocumentColumnsProps.prototype['get_Col']        = CDocumentColumnsProps.prototype.get_Col       ;
CDocumentColumnsProps.prototype['put_Col']        = CDocumentColumnsProps.prototype.put_Col       ;
CDocumentColumnsProps.prototype['put_ColByValue'] = CDocumentColumnsProps.prototype.put_ColByValue;
CDocumentColumnsProps.prototype['get_TotalWidth'] = CDocumentColumnsProps.prototype.get_TotalWidth;

window['Asc']['CDocumentSectionProps'] = window['Asc'].CDocumentSectionProps = CDocumentSectionProps;
CDocumentSectionProps.prototype["get_W"]              = CDocumentSectionProps.prototype.get_W;
CDocumentSectionProps.prototype["put_W"]              = CDocumentSectionProps.prototype.put_W;
CDocumentSectionProps.prototype["get_H"]              = CDocumentSectionProps.prototype.get_H;
CDocumentSectionProps.prototype["put_H"]              = CDocumentSectionProps.prototype.put_H;
CDocumentSectionProps.prototype["get_Orientation"]    = CDocumentSectionProps.prototype.get_Orientation;
CDocumentSectionProps.prototype["put_Orientation"]    = CDocumentSectionProps.prototype.put_Orientation;
CDocumentSectionProps.prototype["get_LeftMargin"]     = CDocumentSectionProps.prototype.get_LeftMargin;
CDocumentSectionProps.prototype["put_LeftMargin"]     = CDocumentSectionProps.prototype.put_LeftMargin;
CDocumentSectionProps.prototype["get_TopMargin"]      = CDocumentSectionProps.prototype.get_TopMargin;
CDocumentSectionProps.prototype["put_TopMargin"]      = CDocumentSectionProps.prototype.put_TopMargin;
CDocumentSectionProps.prototype["get_RightMargin"]    = CDocumentSectionProps.prototype.get_RightMargin;
CDocumentSectionProps.prototype["put_RightMargin"]    = CDocumentSectionProps.prototype.put_RightMargin;
CDocumentSectionProps.prototype["get_BottomMargin"]   = CDocumentSectionProps.prototype.get_BottomMargin;
CDocumentSectionProps.prototype["put_BottomMargin"]   = CDocumentSectionProps.prototype.put_BottomMargin;
CDocumentSectionProps.prototype["get_HeaderDistance"] = CDocumentSectionProps.prototype.get_HeaderDistance;
CDocumentSectionProps.prototype["put_HeaderDistance"] = CDocumentSectionProps.prototype.put_HeaderDistance;
CDocumentSectionProps.prototype["get_FooterDistance"] = CDocumentSectionProps.prototype.get_FooterDistance;
CDocumentSectionProps.prototype["put_FooterDistance"] = CDocumentSectionProps.prototype.put_FooterDistance;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 19.12.2017
 * Time: 14:41
 */

/**
 * Класс для работы со структурой документа
 * @param {CDocument} oLogicDocument
 */
function CDocumentOutline(oLogicDocument)
{
	this.LogicDocument = oLogicDocument;
	this.Use           = false;
	this.Elements      = [];
	this.CurPos        = -1;

	this.ParagraphsToUpdate = {};
}
CDocumentOutline.prototype.SetUse = function(isUse)
{
	this.Use = isUse;
	if (this.Use)
		this.UpdateAll();
};
CDocumentOutline.prototype.IsUse = function()
{
	return this.Use;
};
CDocumentOutline.prototype.UpdateAll = function()
{
	if (!this.Use)
		return;

	this.ParagraphsToUpdate = {};
	this.Elements           = [];
	this.LogicDocument.GetOutlineParagraphs(this.Elements, {SkipEmptyParagraphs : false, SkipTables : true, SkipDrawings : true});

	if (this.Elements.length > 0)
	{
		this.LogicDocument.UpdateContentIndexing();
		if (0 !== this.Elements[0].Paragraph.GetIndex())
		{
			this.Elements.splice(0, 0, {Paragraph : null, Lvl : 0});
		}
	}

	this.CurPos = -1;

	this.LogicDocument.GetApi().sync_OnDocumentOutlineUpdate(this);
	this.LogicDocument.UpdateDocumentOutlinePosition();
};
CDocumentOutline.prototype.CheckParagraph = function(oParagraph)
{
	if ((-1 !== this.private_FindElementByParagraph(oParagraph)
		|| undefined !== oParagraph.GetOutlineLvl())
		&& !this.ParagraphsToUpdate[oParagraph.GetId()])
	{
		this.ParagraphsToUpdate[oParagraph.GetId()] = oParagraph;
	}
};
CDocumentOutline.prototype.Update = function()
{
	// TODO: Надо проверить нумерацию

	var arrParagraphs = [];
	for (var sId in this.ParagraphsToUpdate)
	{
		arrParagraphs.push(this.ParagraphsToUpdate[sId]);
	}

	if (arrParagraphs.length > 0)
	{
		this.LogicDocument.UpdateContentIndexing();
		for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
		{
			var oParagraph = arrParagraphs[nIndex];

			var nPos   = this.private_FindElementByParagraph(oParagraph);
			var nLevel = oParagraph.GetOutlineLvl();
			var isUse  = oParagraph.Is_UseInDocument();

			if (undefined !== nLevel && isUse)
			{
				if (-1 === nPos)
				{
					nPos = this.private_GetParagraphPosition(oParagraph);

					if (0 === nPos && this.Elements[0] && null === this.Elements[0].Paragraph)
					{
						this.Elements.splice(0, 1);
						this.LogicDocument.GetApi().sync_OnDocumentOutlineUpdateRemove(0);
					}

					this.Elements.splice(nPos, 0, {Paragraph : oParagraph, Lvl : nLevel});
					this.LogicDocument.GetApi().sync_OnDocumentOutlineUpdateAdd(nPos);

					if (0 === nPos)
					{
						this.LogicDocument.UpdateContentIndexing();
						if (0 !== this.Elements[0].Paragraph.GetIndex())
						{
							this.Elements.splice(0, 0, {Paragraph : null, Lvl : 0});
							this.LogicDocument.GetApi().sync_OnDocumentOutlineUpdateAdd(0);
						}
					}
				}
				else
				{
					this.Elements[nPos].Lvl = nLevel;
					this.LogicDocument.GetApi().sync_OnDocumentOutlineUpdateChange(nPos);
				}
			}
			else if (-1 !== nPos && (undefined === nLevel || !isUse))
			{
				this.Elements.splice(nPos, 1);
				this.LogicDocument.GetApi().sync_OnDocumentOutlineUpdateRemove(nPos);

				if (0 === nPos && (!this.Elements[0] || (null !== this.Elements[0].Paragraph && 0 !== this.Elements[0].Paragraph.GetIndex())))
				{
					this.Elements.splice(0, 0, {Paragraph : null, Lvl : 0});
					this.LogicDocument.GetApi().sync_OnDocumentOutlineUpdateAdd(0);
				}

				if (1 === this.Elements.length && this.Elements[0].Paragraph === null)
				{
					this.Elements.splice(0, 1);
					this.LogicDocument.GetApi().sync_OnDocumentOutlineUpdateRemove(0);
				}
			}
		}
	}

	this.ParagraphsToUpdate = {};
};
CDocumentOutline.prototype.private_FindElementByParagraph = function(oParagraph)
{
	for (var nIndex = 0, nCount = this.Elements.length; nIndex < nCount; ++nIndex)
	{
		if (this.Elements[nIndex].Paragraph === oParagraph)
			return nIndex;
	}

	return -1;
};
CDocumentOutline.prototype.private_GetParagraphPosition = function(oParagraph)
{
	var arrParaPos = oParagraph.GetDocumentPositionFromObject();
	for (var nIndex = 0, nCount = this.Elements.length; nIndex < nCount; ++nIndex)
	{
		if ((this.Elements[nIndex].Paragraph && this.private_CompareDocumentPositions(arrParaPos, this.Elements[nIndex].Paragraph.GetDocumentPositionFromObject()) <= 0)
			|| (!this.Elements[nIndex].Paragraph && this.private_IsStartDocumentPosition(arrParaPos)))
			return nIndex;
	}

	return this.Elements.length;
};
CDocumentOutline.prototype.private_CompareDocumentPositions = function(arrDocPos1, arrDocPos2)
{
	var nLen1 = arrDocPos1.length;
	var nLen2 = arrDocPos2.length;

	for (var nPos = 0; nPos < nLen1; ++nPos)
	{
		if (nLen2 <= nPos)
			return 1;

		if (arrDocPos1[nPos].Position < arrDocPos2[nPos].Position)
			return -1;
		else if (arrDocPos1[nPos].Position > arrDocPos2[nPos].Position)
			return 1;
	}

	if (nLen2 > nLen1)
		return -1;

	return 0;
};
CDocumentOutline.prototype.private_IsStartDocumentPosition = function(arrDocPos)
{
	if (arrDocPos.length <= 0)
		return false;

	for (var nIndex = 0, nCount = arrDocPos.length; nIndex < nCount; ++nIndex)
	{
		if (0 !== arrDocPos[nIndex].Position)
			return false;
	}

	return true;
};
CDocumentOutline.prototype.GetElementsCount = function()
{
	return this.Elements.length;
};
CDocumentOutline.prototype.GetText = function(nIndex)
{
	if (nIndex < 0 || nIndex >= this.Elements.length)
		return "";

	if (!this.Elements[nIndex].Paragraph)
		return "";

	return this.Elements[nIndex].Paragraph.GetText();
};
CDocumentOutline.prototype.GetLevel = function(nIndex)
{
	if (nIndex < 0 || nIndex >= this.Elements.length)
		return -1;

	return this.Elements[nIndex].Lvl;
};
CDocumentOutline.prototype.GoTo = function(nIndex)
{
	if (nIndex < 0 || nIndex >= this.Elements.length)
		return -1;

	var oParagraph = this.Elements[nIndex].Paragraph;

	this.LogicDocument.RemoveSelection();

	if (!oParagraph)
	{
		this.LogicDocument.MoveCursorToStartPos(false);
	}
	else
	{
		oParagraph.MoveCursorToStartPos();
		oParagraph.Document_SetThisElementCurrent(true);
	}
};
CDocumentOutline.prototype.Demote = function(nIndex)
{
	this.private_PromoteDemote(nIndex, false);
};
CDocumentOutline.prototype.Promote = function(nIndex)
{
	this.private_PromoteDemote(nIndex, true);
};
CDocumentOutline.prototype.private_PromoteDemote = function(nIndex, isPromote)
{
	if (nIndex < 0 || nIndex >= this.Elements.length)
		return;

	var nLevel     = this.Elements[nIndex].Lvl;
	var oParagraph = this.Elements[nIndex].Paragraph;

	if (!oParagraph)
		return;

	if (isPromote && (nLevel <= 0 || nLevel > 8) || (!isPromote && (nLevel >= 8 || nLevel < 0)))
		return;

	var arrParagraphs = [oParagraph];
	var arrLevels     = [nLevel];

	nIndex++;
	while (nIndex < this.Elements.length)
	{
		var nCurLevel     = this.Elements[nIndex].Lvl;
		var oCurParagraph = this.Elements[nIndex].Paragraph;

		if (nCurLevel <= nLevel)
			break;

		arrParagraphs.push(oCurParagraph);
		arrLevels.push(nCurLevel);

		nIndex++;
	}

	if (false === this.LogicDocument.Document_Is_SelectionLocked(changestype_None, {
			Type      : AscCommon.changestype_2_ElementsArray_and_Type,
			Elements  : arrParagraphs,
			CheckType : AscCommon.changestype_Paragraph_Properties
		}))
	{
		AscCommon.History.Create_NewPoint(AscDFH.historydescription_Document_ChangeOutlineLevel);

		for (var nPos = 0, nCount = arrParagraphs.length; nPos < nCount; ++nPos)
		{
			var nCurLevel = arrLevels[nPos];
			if (isPromote && nCurLevel > 0 && nCurLevel <= 8)
				nCurLevel--;
			else if (!isPromote && nCurLevel < 8 && nCurLevel >= 0)
				nCurLevel++;
			else
				continue;

			var sStyleId = this.LogicDocument.GetStyles().GetDefaultHeading(nCurLevel);
			arrParagraphs[nPos].SetParagraphStyleById(sStyleId);
		}

		this.LogicDocument.Recalculate();
		this.LogicDocument.Document_UpdateInterfaceState();
	}
};
CDocumentOutline.prototype.InsertHeader = function(nIndex, isBefore)
{
	if (nIndex < 0 || nIndex >= this.Elements.length)
		return;

	var nPos   = this.private_GetPositionForInsertHeaderBefore(isBefore ? nIndex : this.private_GetNextSiblingOrHigher(nIndex));
	var nLevel = this.GetLevel(nIndex);

	// Локов особо проверять не нужно, т.к. мы добавляем параграф в верхний класс, но возможно есть глобальный лок,
	// так что проверка нужна все равно, но без типа изменения.
	if (false === this.LogicDocument.Document_Is_SelectionLocked(changestype_None))
	{
		this.LogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddElementToOutline);

		var oParagraph = new Paragraph(this.LogicDocument.GetDrawingDocument(), this.LogicDocument);
		oParagraph.SetParagraphStyleById(this.LogicDocument.GetStyles().GetDefaultHeading(nLevel));
		this.LogicDocument.AddToContent(nPos, oParagraph);
		this.LogicDocument.Recalculate();

		oParagraph.MoveCursorToStartPos(false);
		oParagraph.Document_SetThisElementCurrent(true);
	}
};
CDocumentOutline.prototype.InsertSubHeader = function(nIndex)
{
	if (nIndex < 0 || nIndex >= this.Elements.length)
		return;

	var nPos   = this.private_GetPositionForInsertHeaderBefore(this.private_GetNextSiblingOrHigher(nIndex));
	var nLevel = this.GetLevel(nIndex);

	if (nLevel >= 8)
		return;

	// Локов особо проверять не нужно, т.к. мы добавляем параграф в верхний класс, но возможно есть глобальный лок,
	// так что проверка нужна все равно, но без типа изменения.
	if (false === this.LogicDocument.Document_Is_SelectionLocked(changestype_None))
	{
		this.LogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddElementToOutline);

		var oParagraph = new Paragraph(this.LogicDocument.GetDrawingDocument(), this.LogicDocument);
		oParagraph.SetParagraphStyleById(this.LogicDocument.GetStyles().GetDefaultHeading(nLevel + 1));
		this.LogicDocument.AddToContent(nPos, oParagraph);
		this.LogicDocument.Recalculate();

		oParagraph.MoveCursorToStartPos(false);
		oParagraph.Document_SetThisElementCurrent(true);
	}
};
CDocumentOutline.prototype.private_GetPositionForInsertHeaderBefore = function(nIndex)
{
	if (nIndex === this.Elements.length)
		return this.LogicDocument.GetElementsCount();

	var oParagraph = this.Elements[nIndex].Paragraph;
	if (!oParagraph)
		return 0;

	this.LogicDocument.UpdateContentIndexing();
	return oParagraph.GetIndex();
};
CDocumentOutline.prototype.private_GetNextSiblingOrHigher = function(nIndex)
{
	if (nIndex < 0 || nIndex >= this.Elements.length)
		return 0;

	var nLevel = this.GetLevel(nIndex);
	var nPos = nIndex + 1;
	while (nPos < this.Elements.length)
	{
		if (nLevel >= this.GetLevel(nPos))
			return nPos;

		nPos++;
	}

	return this.Elements.length;
};
CDocumentOutline.prototype.IsFirstItemNotHeader = function()
{
	return (this.Elements.length <= 0 || !this.Elements[0].Paragraph ? true : false);
};
CDocumentOutline.prototype.SelectContent = function(nIndex)
{
	if (nIndex < 0 || nIndex >= this.Elements.length)
		return;

	var oStartParagraph = this.Elements[nIndex].Paragraph,
		oEndParagraph   = null;

	var nNextIndex = this.private_GetNextSiblingOrHigher(nIndex);
	if (nNextIndex < this.Elements.length)
		oEndParagraph = this.Elements[nNextIndex].Paragraph;

	this.LogicDocument.UpdateContentIndexing();

	var nStartPos = (oStartParagraph ? oStartParagraph.GetIndex() : 0);
	var nEndPos   = (oEndParagraph ? oEndParagraph.GetIndex() : this.LogicDocument.GetElementsCount()) - 1;

	this.LogicDocument.RemoveSelection();
	this.LogicDocument.SelectRange(nStartPos, nEndPos);
};
CDocumentOutline.prototype.UpdateCurrentPosition = function(arrDocPos)
{
	if (null === arrDocPos)
	{
		this.LogicDocument.GetApi().sync_OnDocumentOutlineCurrentPosition(null);
		return;
	}

	this.LogicDocument.UpdateContentIndexing();

	var nFindIndex = this.Elements.length - 1;
	for (var nIndex = 0, nCount = this.Elements.length; nIndex < nCount; ++nIndex)
	{
		var oParagraph = this.Elements[nIndex].Paragraph;

		// Такое может случиться только для первого элемента списка
		if (!oParagraph)
			continue;

		if (this.private_CompareDocumentPositions(oParagraph.GetDocumentPositionFromObject(), arrDocPos) > 0)
		{
			nFindIndex = nIndex - 1;
			break;
		}
	}

	if (nFindIndex !== this.CurPos)
	{
		this.CurPos = nFindIndex;
		this.LogicDocument.GetApi().sync_OnDocumentOutlineCurrentPosition(nFindIndex);
	}
};
CDocumentOutline.prototype.IsEmptyItem = function(nIndex)
{
	if (nIndex < 0 || nIndex >= this.Elements.length || !this.Elements[nIndex].Paragraph)
		return true;

	return this.Elements[nIndex].Paragraph.IsEmpty();
};
CDocumentOutline.prototype.GetCurrentPosition = function()
{
	return this.CurPos;
};

//-------------------------------------------------------------export---------------------------------------------------
CDocumentOutline.prototype["get_ElementsCount"]    = CDocumentOutline.prototype.GetElementsCount;
CDocumentOutline.prototype["get_Text"]             = CDocumentOutline.prototype.GetText;
CDocumentOutline.prototype["get_Level"]            = CDocumentOutline.prototype.GetLevel;
CDocumentOutline.prototype["get_CurrentPosition"]  = CDocumentOutline.prototype.GetCurrentPosition;
CDocumentOutline.prototype["goto"]                 = CDocumentOutline.prototype.GoTo;
CDocumentOutline.prototype["promote"]              = CDocumentOutline.prototype.Promote;
CDocumentOutline.prototype["demote"]               = CDocumentOutline.prototype.Demote;
CDocumentOutline.prototype["insertHeader"]         = CDocumentOutline.prototype.InsertHeader;
CDocumentOutline.prototype["insertSubHeader"]      = CDocumentOutline.prototype.InsertSubHeader;
CDocumentOutline.prototype["isFirstItemNotHeader"] = CDocumentOutline.prototype.IsFirstItemNotHeader;
CDocumentOutline.prototype["selectContent"]        = CDocumentOutline.prototype.SelectContent;
CDocumentOutline.prototype["isEmptyItem"]          = CDocumentOutline.prototype.IsEmptyItem;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 27.10.2016
 * Time: 13:02
 */

AscDFH.changesFactory[AscDFH.historyitem_Document_AddItem]           = CChangesDocumentAddItem;
AscDFH.changesFactory[AscDFH.historyitem_Document_RemoveItem]        = CChangesDocumentRemoveItem;
AscDFH.changesFactory[AscDFH.historyitem_Document_DefaultTab]        = CChangesDocumentDefaultTab;
AscDFH.changesFactory[AscDFH.historyitem_Document_EvenAndOddHeaders] = CChangesDocumentEvenAndOddHeaders;
AscDFH.changesFactory[AscDFH.historyitem_Document_DefaultLanguage]   = CChangesDocumentDefaultLanguage;
AscDFH.changesFactory[AscDFH.historyitem_Document_MathSettings]      = CChangesDocumentMathSettings;
AscDFH.changesFactory[AscDFH.historyitem_Document_SdtGlobalSettings] = CChangesDocumentSdtGlobalSettings;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_Document_AddItem]           = [
	AscDFH.historyitem_Document_AddItem,
	AscDFH.historyitem_Document_RemoveItem
];
AscDFH.changesRelationMap[AscDFH.historyitem_Document_RemoveItem]        = [
	AscDFH.historyitem_Document_AddItem,
	AscDFH.historyitem_Document_RemoveItem
];
AscDFH.changesRelationMap[AscDFH.historyitem_Document_DefaultTab]        = [AscDFH.historyitem_Document_DefaultTab];
AscDFH.changesRelationMap[AscDFH.historyitem_Document_EvenAndOddHeaders] = [AscDFH.historyitem_Document_EvenAndOddHeaders];
AscDFH.changesRelationMap[AscDFH.historyitem_Document_DefaultLanguage]   = [AscDFH.historyitem_Document_DefaultLanguage];
AscDFH.changesRelationMap[AscDFH.historyitem_Document_MathSettings]      = [AscDFH.historyitem_Document_MathSettings];
AscDFH.changesRelationMap[AscDFH.historyitem_Document_SdtGlobalSettings] = [AscDFH.historyitem_Document_SdtGlobalSettings];
//----------------------------------------------------------------------------------------------------------------------

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesDocumentAddItem(Class, Pos, Items)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, true);
}
CChangesDocumentAddItem.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesDocumentAddItem.prototype.constructor = CChangesDocumentAddItem;
CChangesDocumentAddItem.prototype.Type = AscDFH.historyitem_Document_AddItem;
CChangesDocumentAddItem.prototype.Undo = function()
{
	var oDocument = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var Pos = true !== this.UseArray ? this.Pos : this.PosArray[nIndex];
		var Elements = oDocument.Content.splice(Pos, 1);
		oDocument.private_RecalculateNumbering(Elements);
		if (oDocument.SectionsInfo)
		{
			oDocument.SectionsInfo.Update_OnRemove(Pos, 1);
		}

		if (Pos > 0)
		{
			if (Pos <= oDocument.Content.length - 1)
			{
				oDocument.Content[Pos - 1].Next = oDocument.Content[Pos];
				oDocument.Content[Pos].Prev     = oDocument.Content[Pos - 1];
			}
			else
			{
				oDocument.Content[Pos - 1].Next = null;
			}
		}
		else if (Pos <= oDocument.Content.length - 1)
		{
			oDocument.Content[Pos].Prev = null;
		}
	}
};
CChangesDocumentAddItem.prototype.Redo = function()
{
	var oDocument = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var Element = this.Items[nIndex];
		var Pos     = true !== this.UseArray ? this.Pos + nIndex : this.PosArray[nIndex];

		oDocument.Content.splice(Pos, 0, Element);
		oDocument.private_RecalculateNumbering([Element]);
		if (oDocument.SectionsInfo)
		{
			oDocument.SectionsInfo.Update_OnAdd(Pos, [Element]);
		}

		if (Pos > 0)
		{
			oDocument.Content[Pos - 1].Next = Element;
			Element.Prev                    = oDocument.Content[Pos - 1];
		}
		else
		{
			Element.Prev = null;
		}

		if (Pos < oDocument.Content.length - 1)
		{
			oDocument.Content[Pos + 1].Prev = Element;
			Element.Next                    = oDocument.Content[Pos + 1];
		}
		else
		{
			Element.Next = null;
		}

		Element.Parent = oDocument;
	}
};
CChangesDocumentAddItem.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesDocumentAddItem.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesDocumentAddItem.prototype.Load = function(Color)
{
	var oDocument = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var Pos     = oDocument.m_oContentChanges.Check(AscCommon.contentchanges_Add, true !== this.UseArray ? this.Pos + nIndex : this.PosArray[nIndex]);
		var Element = this.Items[nIndex];

		Pos = Math.min(Pos, oDocument.Content.length);

		if (null != Element)
		{
			if (Pos > 0)
			{
				oDocument.Content[Pos - 1].Next = Element;
				Element.Prev                    = oDocument.Content[Pos - 1];
			}
			else
			{
				Element.Prev = null;
			}

			if (Pos <= oDocument.Content.length - 1)
			{
				oDocument.Content[Pos].Prev = Element;
				Element.Next                = oDocument.Content[Pos];
			}
			else
			{
				Element.Next = null;
			}

			Element.Parent = oDocument;

			oDocument.Content.splice(Pos, 0, Element);
			oDocument.private_RecalculateNumbering([Element]);
			if (oDocument.SectionsInfo)
			{
				oDocument.SectionsInfo.Update_OnAdd(Pos, [Element]);
			}
			oDocument.private_ReindexContent(Pos);

			AscCommon.CollaborativeEditing.Update_DocumentPositionsOnAdd(oDocument, Pos);
		}
	}
};
CChangesDocumentAddItem.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_Document_AddItem === oChanges.Type || AscDFH.historyitem_Document_RemoveItem === oChanges.Type))
		return true;

	return false;
};
CChangesDocumentAddItem.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesDocumentRemoveItem);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesDocumentRemoveItem(Class, Pos, Items)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, false);
}
CChangesDocumentRemoveItem.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesDocumentRemoveItem.prototype.constructor = CChangesDocumentRemoveItem;
CChangesDocumentRemoveItem.prototype.Type = AscDFH.historyitem_Document_RemoveItem;
CChangesDocumentRemoveItem.prototype.Undo = function()
{
	var oDocument = this.Class;

	var Array_start = oDocument.Content.slice(0, this.Pos);
	var Array_end   = oDocument.Content.slice(this.Pos);

	oDocument.private_RecalculateNumbering(this.Items);
	oDocument.Content = Array_start.concat(this.Items, Array_end);

	if(oDocument.SectionsInfo)
	{
        oDocument.SectionsInfo.Update_OnAdd(this.Pos, this.Items);
	}


	var nStartIndex = Math.max(this.Pos - 1, 0);
	var nEndIndex   = Math.min(oDocument.Content.length - 1, this.Pos + this.Items.length + 1);
	for (var nIndex = nStartIndex; nIndex <= nEndIndex; ++nIndex)
	{
		var oElement = oDocument.Content[nIndex];
		if (nIndex > 0)
			oElement.Prev = oDocument.Content[nIndex - 1];
		else
			oElement.Prev = null;

		if (nIndex < oDocument.Content.length - 1)
			oElement.Next = oDocument.Content[nIndex + 1];
		else
			oElement.Next = null;

		oElement.Parent = oDocument;
	}
};
CChangesDocumentRemoveItem.prototype.Redo = function()
{
	var oDocument = this.Class;
	var Elements = oDocument.Content.splice(this.Pos, this.Items.length);
	oDocument.private_RecalculateNumbering(Elements);
	if(oDocument.SectionsInfo)
	{
        oDocument.SectionsInfo.Update_OnRemove(this.Pos, this.Items.length);
	}


	var Pos = this.Pos;
	if (Pos > 0)
	{
		if (Pos <= oDocument.Content.length - 1)
		{
			oDocument.Content[Pos - 1].Next = oDocument.Content[Pos];
			oDocument.Content[Pos].Prev     = oDocument.Content[Pos - 1];
		}
		else
		{
			oDocument.Content[Pos - 1].Next = null;
		}
	}
	else if (Pos <= oDocument.Content.length - 1)
	{
		oDocument.Content[Pos].Prev = null;
	}
};
CChangesDocumentRemoveItem.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesDocumentRemoveItem.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesDocumentRemoveItem.prototype.Load = function(Color)
{
	var oDocument = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var Pos = oDocument.m_oContentChanges.Check(AscCommon.contentchanges_Remove, true !== this.UseArray ? this.Pos : this.PosArray[nIndex]);

		// действие совпало, не делаем его
		if (false === Pos)
			continue;

		var Elements = oDocument.Content.splice(Pos, 1);
		oDocument.private_RecalculateNumbering(Elements);
		AscCommon.CollaborativeEditing.Update_DocumentPositionsOnRemove(oDocument, Pos, 1);

		if (Pos > 0)
		{
			if (Pos <= oDocument.Content.length - 1)
			{
				oDocument.Content[Pos - 1].Next = oDocument.Content[Pos];
				oDocument.Content[Pos].Prev     = oDocument.Content[Pos - 1];
			}
			else
			{
				oDocument.Content[Pos - 1].Next = null;
			}
		}
		else if (Pos <= oDocument.Content.length - 1)
		{
			oDocument.Content[Pos].Prev = null;
		}

		if (0 <= Pos && Pos <= oDocument.Content.length - 1)
		{
			if (oDocument.SectionsInfo)
			{
				oDocument.SectionsInfo.Update_OnRemove(Pos, 1);
			}

			oDocument.private_ReindexContent(Pos);
		}
	}
};
CChangesDocumentRemoveItem.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_Document_AddItem === oChanges.Type || AscDFH.historyitem_Document_RemoveItem === oChanges.Type))
		return true;

	return false;
};
CChangesDocumentRemoveItem.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesDocumentAddItem);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesDocumentDefaultTab(Class, Old, New)
{
	AscDFH.CChangesBase.call(this, Class);

	this.Old = Old;
	this.New = New;
}
CChangesDocumentDefaultTab.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesDocumentDefaultTab.prototype.constructor = CChangesDocumentDefaultTab;
CChangesDocumentDefaultTab.prototype.Type = AscDFH.historyitem_Document_DefaultTab;
CChangesDocumentDefaultTab.prototype.Undo = function()
{
	AscCommonWord.Default_Tab_Stop = this.Old;
};
CChangesDocumentDefaultTab.prototype.Redo = function()
{
	AscCommonWord.Default_Tab_Stop = this.New;
};
CChangesDocumentDefaultTab.prototype.WriteToBinary = function(Writer)
{
	// Double : New
	// Double : Old
	Writer.WriteDouble(this.New);
	Writer.WriteDouble(this.Old);
};
CChangesDocumentDefaultTab.prototype.ReadFromBinary = function(Reader)
{
	// Double : New
	// Double : Old
	this.New = Reader.GetDouble();
	this.Old = Reader.GetDouble();
};
CChangesDocumentDefaultTab.prototype.CreateReverseChange = function()
{
	return new CChangesDocumentDefaultTab(this.Class, this.New, this.Old);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesDocumentEvenAndOddHeaders(Class, Old, New)
{
	AscDFH.CChangesBase.call(this, Class);

	this.Old = Old;
	this.New = New;
}
CChangesDocumentEvenAndOddHeaders.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesDocumentEvenAndOddHeaders.prototype.constructor = CChangesDocumentEvenAndOddHeaders;
CChangesDocumentEvenAndOddHeaders.prototype.Type = AscDFH.historyitem_Document_EvenAndOddHeaders;
CChangesDocumentEvenAndOddHeaders.prototype.Undo = function()
{
	EvenAndOddHeaders = this.Old;
};
CChangesDocumentEvenAndOddHeaders.prototype.Redo = function()
{
	EvenAndOddHeaders = this.New;
};
CChangesDocumentEvenAndOddHeaders.prototype.WriteToBinary = function(Writer)
{
	// Bool : New
	// Bool : Old
	Writer.WriteBool(this.New);
	Writer.WriteBool(this.Old);
};
CChangesDocumentEvenAndOddHeaders.prototype.ReadFromBinary = function(Reader)
{
	// Bool : New
	// Bool : Old
	this.New = Reader.GetBool();
	this.Old = Reader.GetBool();
};
CChangesDocumentEvenAndOddHeaders.prototype.CreateReverseChange = function()
{
	return new CChangesDocumentEvenAndOddHeaders(this.Class, this.New, this.Old);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesDocumentDefaultLanguage(Class, Old, New)
{
	AscDFH.CChangesBase.call(this, Class);

	this.Old = Old;
	this.New = New;
}
CChangesDocumentDefaultLanguage.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesDocumentDefaultLanguage.prototype.constructor = CChangesDocumentDefaultLanguage;
CChangesDocumentDefaultLanguage.prototype.Type = AscDFH.historyitem_Document_DefaultLanguage;
CChangesDocumentDefaultLanguage.prototype.Undo = function()
{
	var oDocument = this.Class;
	oDocument.Styles.Default.TextPr.Lang.Val = this.Old;
	oDocument.Restart_CheckSpelling();
};
CChangesDocumentDefaultLanguage.prototype.Redo = function()
{
	var oDocument = this.Class;
	oDocument.Styles.Default.TextPr.Lang.Val = this.New;
	oDocument.Restart_CheckSpelling();
};
CChangesDocumentDefaultLanguage.prototype.WriteToBinary = function(Writer)
{
	// Long : New
	// Long : Old
	Writer.WriteLong(this.New);
	Writer.WriteLong(this.Old);
};
CChangesDocumentDefaultLanguage.prototype.ReadFromBinary = function(Reader)
{
	// Long : New
	// Long : Old
	this.New = Reader.GetLong();
	this.Old = Reader.GetLong();
};
CChangesDocumentDefaultLanguage.prototype.CreateReverseChange = function()
{
	return new CChangesDocumentDefaultLanguage(this.Class, this.New, this.Old);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesDocumentMathSettings(Class, Old, New)
{
	AscDFH.CChangesBase.call(this, Class);

	this.Old = Old;
	this.New = New;
}
CChangesDocumentMathSettings.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesDocumentMathSettings.prototype.constructor = CChangesDocumentMathSettings;
CChangesDocumentMathSettings.prototype.Type = AscDFH.historyitem_Document_MathSettings;
CChangesDocumentMathSettings.prototype.Undo = function()
{
	var oDocument = this.Class;
	oDocument.Settings.MathSettings.SetPr(this.Old);
};
CChangesDocumentMathSettings.prototype.Redo = function()
{
	var oDocument = this.Class;
	oDocument.Settings.MathSettings.SetPr(this.New);
};
CChangesDocumentMathSettings.prototype.WriteToBinary = function(Writer)
{
	// Variable : New
	// Variable : Old
	this.New.Write_ToBinary(Writer);
	this.Old.Write_ToBinary(Writer);
};
CChangesDocumentMathSettings.prototype.ReadFromBinary = function(Reader)
{
	// Variable : New
	// Variable : Old
	this.New = new CMathSettings();
	this.New.Read_FromBinary(Reader);
	this.Old = new CMathSettings();
	this.Old.Read_FromBinary(Reader);
};
CChangesDocumentMathSettings.prototype.CreateReverseChange = function()
{
	return new CChangesDocumentMathSettings(this.Class, this.New, this.Old);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesDocumentSdtGlobalSettings(Class, Old, New)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class);

	this.Old = Old;
	this.New = New;
}
CChangesDocumentSdtGlobalSettings.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesDocumentSdtGlobalSettings.prototype.constructor = CChangesDocumentSdtGlobalSettings;
CChangesDocumentSdtGlobalSettings.prototype.Type = AscDFH.historyitem_Document_SdtGlobalSettings;
CChangesDocumentSdtGlobalSettings.prototype.private_SetValue = function(Value)
{
	this.Class.Settings.SdtSettings = Value;
	this.Class.OnChangeSdtGlobalSettings();
};
CChangesDocumentSdtGlobalSettings.prototype.private_CreateObject = function()
{
	return new CSdtGlobalSettings();
};
CChangesDocumentSdtGlobalSettings.prototype.private_IsCreateEmptyObject = function()
{
	return true;
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var g_oTableId = AscCommon.g_oTableId;
var History = AscCommon.History;

var c_oAscHAnchor = Asc.c_oAscHAnchor;
var c_oAscXAlign = Asc.c_oAscXAlign;
var c_oAscYAlign = Asc.c_oAscYAlign;
var c_oAscVAnchor = Asc.c_oAscVAnchor;


/**
 * Класс CDocumentContent. Данный класс используется для работы с контентом ячеек таблицы, колонтитулов, сносок,
 * надписей.
 * @param Parent
 * @param DrawingDocument
 * @param X
 * @param Y
 * @param XLimit
 * @param YLimit
 * @param Split
 * @param TurnOffInnerWrap
 * @param bPresentation
 * @constructor
 * @extends {CDocumentContentBase}
 */
function CDocumentContent(Parent, DrawingDocument, X, Y, XLimit, YLimit, Split, TurnOffInnerWrap, bPresentation)
{
	CDocumentContentBase.call(this);

    this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.X = X;
    this.Y = Y;
    this.XLimit = XLimit;
    this.YLimit = YLimit;

	this.StartPage    = 0;
	this.StartColumn  = 0;
	this.ColumnsCount = 1;

    this.Parent = Parent;
    
    this.DrawingDocument = null;
    this.LogicDocument   = null;
    this.Styles          = null;
    this.Numbering       = null;
    this.DrawingObjects  = null;
    
    if ( undefined !== DrawingDocument && null !== DrawingDocument )
    {
        this.DrawingDocument = DrawingDocument;
        
        if ( undefined !== editor && true === editor.isDocumentEditor && !(bPresentation === true) && DrawingDocument.m_oLogicDocument )
        {
            this.LogicDocument   = DrawingDocument.m_oLogicDocument;
            this.Styles          = DrawingDocument.m_oLogicDocument.Get_Styles();
            this.Numbering       = DrawingDocument.m_oLogicDocument.Get_Numbering();
            this.DrawingObjects  = DrawingDocument.m_oLogicDocument.DrawingObjects; // Массив укзателей на все инлайновые графические объекты
        }
    }

    if ( "undefined" === typeof(TurnOffInnerWrap) )
        TurnOffInnerWrap = false;

    this.TurnOffInnerWrap = TurnOffInnerWrap;

    this.Pages = [];

    this.RecalcInfo = new CDocumentRecalcInfo();

    this.Split = Split; // Разделяем ли на страницы
    this.bPresentation = bPresentation; // Разделяем ли на страницы

    this.Content[0] = new Paragraph( DrawingDocument, this, bPresentation );
    this.Content[0].Correct_Content();
    this.Content[0].Set_DocumentNext( null );
    this.Content[0].Set_DocumentPrev( null );

    this.CurPos  =
    {
        X          : 0,
        Y          : 0,
        ContentPos : 0, // в зависимости, от параметра Type: позиция в Document.Content
        RealX      : 0, // позиция курсора, без учета расположения букв
        RealY      : 0, // это актуально для клавиш вверх и вниз
        Type       : docpostype_Content,
        TableMove  : 0  // специльный параметр для переноса таблиц
    };

    this.Selection =
    {
        Start    : false,
        Use      : false,
        StartPos : 0,
        EndPos   : 0,
        Flag     : selectionflag_Common,
        Data     : null
    };

    this.ClipInfo = [];

    this.ApplyToAll = false; // Специальный параметр, используемый в ячейках таблицы.
                             // True, если ячейка попадает в выделение по ячейкам.

    this.TurnOffRecalc = false;

    this.m_oContentChanges = new AscCommon.CContentChanges(); // список изменений(добавление/удаление элементов)
    this.StartState = null;

    this.ReindexStartPos = 0;

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    g_oTableId.Add( this, this.Id );

    if(this.bPresentation)
    {
        this.Save_StartState();
    }
}
CDocumentContent.prototype = Object.create(CDocumentContentBase.prototype);
CDocumentContent.prototype.constructor = CDocumentContent;

CDocumentContent.prototype.Save_StartState = function()
{
    this.StartState = new CDocumentContentStartState(this);
};
CDocumentContent.prototype.Copy = function(Parent, DrawingDocument)
{
	var DC = new CDocumentContent(Parent, DrawingDocument ? DrawingDocument : this.DrawingDocument, 0, 0, 0, 0, this.Split, this.TurnOffInnerWrap, this.bPresentation);

	// Копируем содержимое
	DC.Internal_Content_RemoveAll();

	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		DC.Internal_Content_Add(Index, this.Content[Index].Copy(DC, DrawingDocument), false);
	}

	return DC;
};
CDocumentContent.prototype.Copy2 = function(OtherDC)
{
	// Копируем содержимое
	this.Internal_Content_RemoveAll();

	var Count = OtherDC.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		this.Internal_Content_Add(Index, OtherDC.Content[Index].Copy(this), false);
	}
};
CDocumentContent.prototype.Copy3 = function(Parent)//для заголовков диаграмм
{
	var DC = new CDocumentContent(Parent, this.DrawingDocument, 0, 0, 0, 0, this.Split, this.TurnOffInnerWrap, true);

	// Копируем содержимое
	DC.Internal_Content_RemoveAll();

	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		DC.Internal_Content_Add(Index, this.Content[Index].Copy2(DC), false);
	}
	return DC;
};
//-----------------------------------------------------------------------------------
// Функции, к которым идет обращение из контента
//-----------------------------------------------------------------------------------
CDocumentContent.prototype.Get_PageContentStartPos = function(PageNum)
{
	return this.Parent.Get_PageContentStartPos(PageNum);
};
CDocumentContent.prototype.Get_PageContentStartPos2 = function(StartPageIndex, StartColumnIndex, ElementPageIndex, ElementIndex)
{
    return this.Get_PageContentStartPos(StartPageIndex + ElementPageIndex);
};
CDocumentContent.prototype.Get_Theme = function()
{
	if (this.Parent)
		return this.Parent.Get_Theme();

	return null;
};
CDocumentContent.prototype.Get_ColorMap = function()
{
	if (this.Parent)
		return this.Parent.Get_ColorMap();

	return null;
};
CDocumentContent.prototype.Get_PageLimits = function(PageIndex)
{
	if (true === this.Parent.IsCell())
	{
		var Margins = this.Parent.GetMargins();

		var Y      = this.Pages[PageIndex].Y - Margins.Top.W;
		var YLimit = this.Pages[PageIndex].YLimit + Margins.Bottom.W;
		var X      = this.Pages[PageIndex].X - Margins.Left.W;
		var XLimit = this.Pages[PageIndex].XLimit + Margins.Right.W;

		return {X : X, XLimit : XLimit, Y : Y, YLimit : YLimit}
	}
	else
	{
		if (null === this.LogicDocument)
			return {X : 0, Y : 0, XLimit : 0, YLimit : 0};

		var Page_abs = this.Get_StartPage_Absolute() + PageIndex;
		var Index    = ( undefined !== this.LogicDocument.Pages[Page_abs] ? this.LogicDocument.Pages[Page_abs].Pos : 0 );
		var SectPr   = this.LogicDocument.SectionsInfo.Get_SectPr(Index).SectPr;
		var Orient   = SectPr.Get_Orientation();

		var W = SectPr.Get_PageWidth();
		var H = SectPr.Get_PageHeight();

		return {X : 0, Y : 0, XLimit : W, YLimit : H};
	}
};
CDocumentContent.prototype.Get_PageFields = function(PageIndex)
{
	if (true === this.Parent.IsCell() || (undefined !== AscFormat.CShape && this.Parent instanceof AscFormat.CShape))
	{
		if (PageIndex < this.Pages.length && PageIndex >= 0)
		{
			var Y      = this.Pages[PageIndex].Y;
			var YLimit = this.Pages[PageIndex].YLimit;
			var X      = this.Pages[PageIndex].X;
			var XLimit = this.Pages[PageIndex].XLimit;

			return {X : X, XLimit : XLimit, Y : Y, YLimit : YLimit}
		}
		else
		{
			if (null === this.LogicDocument)
				return {X : 0, Y : 0, XLimit : 0, YLimit : 0};

			var Page_abs = this.Get_AbsolutePage(PageIndex);
			var Index    = ( undefined !== this.LogicDocument.Pages[Page_abs] ? this.LogicDocument.Pages[Page_abs].Pos : 0 );
			var SectPr   = this.LogicDocument.SectionsInfo.Get_SectPr(Index).SectPr;
			var Orient   = SectPr.Get_Orientation();

			var W = SectPr.Get_PageWidth();
			var H = SectPr.Get_PageHeight();

			return {X : 0, Y : 0, XLimit : W, YLimit : H};
		}
	}
	else
	{
		if (null === this.LogicDocument)
			return {X : 0, Y : 0, XLimit : 0, YLimit : 0};

		var Page_abs = this.Get_AbsolutePage(PageIndex);
		var Index    = ( undefined !== this.LogicDocument.Pages[Page_abs] ? this.LogicDocument.Pages[Page_abs].Pos : 0 );
		var SectPr   = this.LogicDocument.SectionsInfo.Get_SectPr(Index).SectPr;
		var Orient   = SectPr.Get_Orientation();

		var Y      = SectPr.PageMargins.Top;
		var YLimit = SectPr.PageSize.H - SectPr.PageMargins.Bottom;
		var X      = SectPr.PageMargins.Left;
		var XLimit = SectPr.PageSize.W - SectPr.PageMargins.Right;

		return {X : X, Y : Y, XLimit : XLimit, YLimit : YLimit};
	}

};
CDocumentContent.prototype.Get_EmptyHeight = function()
{
	var Count = this.Content.length;
	if (Count <= 0)
		return 0;

	var Element = this.Content[Count - 1];

	if (type_Paragraph === Element.GetType())
		return Element.Get_EmptyHeight();
	else
		return 0;
};
/**
 * Inner = true  - запрос пришел из содержимого,
 *         false - запрос пришел от родительского класса
 *         Запрос от родительского класса нужен, например, для колонтитулов, потому
 *         что у них врапится текст не колонтитула, а документа.
 */
CDocumentContent.prototype.CheckRange = function(X0, Y0, X1, Y1, _Y0, _Y1, X_lf, X_rf, CurPage, Inner, bMathWrap)
{
	if (undefined === Inner)
		Inner = true;

	if (this.IsBlockLevelSdtContent() && true === Inner)
		return this.Parent.CheckRange(X0, Y0, X1, Y1, _Y0, _Y1, X_lf, X_rf, CurPage, true, bMathWrap);

	if (this.LogicDocument && editor && editor.isDocumentEditor)
	{
		var oDocContent = this;
		if (this.Parent && this.Parent instanceof CBlockLevelSdt)
			oDocContent = this.Parent.Parent;

		if ((false === this.TurnOffInnerWrap && true === Inner) || (false === Inner))
			return this.LogicDocument.DrawingObjects.CheckRange(X0, Y0, X1, Y1, _Y0, _Y1, X_lf, X_rf, this.Get_AbsolutePage(CurPage), [], this, bMathWrap);
	}

	return [];
};
CDocumentContent.prototype.Is_PointInDrawingObjects = function(X, Y, Page_Abs)
{
	return this.LogicDocument && this.LogicDocument.DrawingObjects.pointInObjInDocContent(this, X, Y, Page_Abs);
};
CDocumentContent.prototype.Is_PointInFlowTable = function(X, Y, PageAbs)
{
	return this.LogicDocument && null !== this.LogicDocument.DrawingObjects.getTableByXY(X, Y, PageAbs, this);
};
CDocumentContent.prototype.Get_Numbering = function()
{
	return this.Parent.Get_Numbering();
};
CDocumentContent.prototype.GetNumbering = function()
{
	if (this.LogicDocument)
		return this.LogicDocument.GetNumbering();

	return this.Get_Numbering();
};
CDocumentContent.prototype.Get_Styles = function(lvl)
{
	if(!this.bPresentation)
	{
		return this.Styles;
	}
	else
	{
		return this.Parent.Get_Styles(lvl);
	}
};
CDocumentContent.prototype.Get_TableStyleForPara = function()
{
	return this.Parent.Get_TableStyleForPara();
};
CDocumentContent.prototype.Get_ShapeStyleForPara = function()
{
	return this.Parent.Get_ShapeStyleForPara();
};
CDocumentContent.prototype.Get_TextBackGroundColor = function()
{
	return this.Parent.Get_TextBackGroundColor();
};
CDocumentContent.prototype.Recalc_AllParagraphs_CompiledPr = function()
{
	var Count = this.Content.length;
	for (var Pos = 0; Pos < Count; Pos++)
	{
		var Item = this.Content[Pos];
		if (type_Paragraph === Item.GetType())
		{
			Item.Recalc_CompiledPr();
			Item.Recalc_RunsCompiledPr();
		}
		else if (type_Table === Item.GetType())
			Item.Recalc_CompiledPr2();
	}
};
CDocumentContent.prototype.Set_CurrentElement = function(Index, bUpdateStates)
{
	var ContentPos = Math.max(0, Math.min(this.Content.length - 1, Index));
	this.Set_DocPosType(docpostype_Content);

	var CurPos = Math.max(0, Math.min(this.Content.length - 1, Index));

	this.Selection.Use      = false;
	this.Selection.Start    = false;
	this.Selection.Flag     = selectionflag_Common;
	this.Selection.StartPos = CurPos;
	this.Selection.EndPos   = CurPos;
	this.CurPos.ContentPos  = CurPos;

	if (true === this.Content[ContentPos].IsSelectionUse())
	{
		this.Selection.Use      = true;
		this.Selection.StartPos = ContentPos;
		this.Selection.EndPos   = ContentPos;
	}

	this.Parent.Set_CurrentElement(bUpdateStates, this.Get_StartPage_Absolute(), this);
};
CDocumentContent.prototype.Is_ThisElementCurrent = function()
{
	return this.Parent.Is_ThisElementCurrent(this);
};
// Получем ближающую возможную позицию курсора
CDocumentContent.prototype.Get_NearestPos = function(CurPage, X, Y, bAnchor, Drawing)
{
	// TODO: Возможно лучше вернуть null, и разобраться с ситуациями, когда Get_NearestPos возвращает null
	if (CurPage < 0)
	{
		Y       = 0;
		CurPage = 0;
	}
	else if (CurPage >= this.Pages.length)
	{
		CurPage = this.Pages.length - 1;
		Y       = 10000;
	}

	var PageAbs = this.Get_AbsolutePage(CurPage);

	if (this.Parent && this.Parent instanceof CHeaderFooter)
	{
		var bInText    = (null === this.IsInText(X, Y, CurPage) ? false : true);
		var nInDrawing = this.LogicDocument.DrawingObjects.IsInDrawingObject(X, Y, PageAbs, this);

		if (true != bAnchor)
		{
			// Проверяем попадание в графические объекты
			var NearestPos = this.LogicDocument.DrawingObjects.getNearestPos(X, Y, PageAbs, Drawing);
			if (( nInDrawing === DRAWING_ARRAY_TYPE_BEFORE || nInDrawing === DRAWING_ARRAY_TYPE_INLINE || ( false === bInText && nInDrawing >= 0 ) ) && null != NearestPos)
				return NearestPos;
		}
	}

	var ContentPos = this.Internal_GetContentPosByXY(X, Y, CurPage);

	// Делаем логику как в ворде
	if (true != bAnchor && (0 < ContentPos || CurPage > 0) && ContentPos === this.Pages[CurPage].Pos && this.Pages[CurPage].EndPos > this.Pages[CurPage].Pos && type_Paragraph === this.Content[ContentPos].GetType() && true === this.Content[ContentPos].IsContentOnFirstPage())
		ContentPos++;

	var ElementPageIndex = this.private_GetElementPageIndexByXY(ContentPos, X, Y, CurPage);
	return this.Content[ContentPos].Get_NearestPos(ElementPageIndex, X, Y, bAnchor, Drawing);
};
// Проверяем, описывает ли данный класс содержимое ячейки
CDocumentContent.prototype.IsTableCellContent = function(isReturnCell)
{
	return this.Parent.IsCell(isReturnCell);
};
CDocumentContent.prototype.IsLastTableCellInRow = function(isSelection)
{
	if (!this.Parent.IsCell())
		return false;

	return this.Parent.IsLastTableCellInRow(isSelection);
};
/**
 * Проверяем находимся ли мы заголовке хоть какой-либо таблицы
 * @returns {boolean}
 */
CDocumentContent.prototype.IsTableHeader = function()
{
	var oCell = this.IsTableCellContent(true);
	if (oCell)
		return oCell.IsInHeader(true);

	return false;
};
CDocumentContent.prototype.IsTableFirstRowOnNewPage = function()
{
	if (false === this.Parent.IsCell())
		return false;

	return this.Parent.IsTableFirstRowOnNewPage();
};
CDocumentContent.prototype.Check_AutoFit = function()
{
	return this.Parent.Check_AutoFit();
};
// Проверяем, лежит ли данный класс в таблице
CDocumentContent.prototype.Is_InTable = function(bReturnTopTable)
{
	return this.Parent.Is_InTable(bReturnTopTable);
};
// Проверяем, является ли данный класс верхним, по отношению к другим классам DocumentContent, Document
CDocumentContent.prototype.Is_TopDocument = function(bReturnTopDocument)
{
	return this.Parent.Is_TopDocument(bReturnTopDocument);
};
// Проверяем, используется ли данный элемент в документе
CDocumentContent.prototype.Is_UseInDocument = function(Id)
{
	var bUse = false;

	if (null != Id)
	{
		var Count = this.Content.length;
		for (var Index = 0; Index < Count; Index++)
		{
			if (Id === this.Content[Index].Get_Id())
			{
				bUse = true;
				break;
			}
		}
	}
	else
		bUse = true;

	if (true === bUse && null != this.Parent)
		return this.Parent.Is_UseInDocument(this.Get_Id());

	return false;
};
CDocumentContent.prototype.IsHdrFtr = function(bReturnHdrFtr)
{
	if (this.Parent)
		return this.Parent.IsHdrFtr(bReturnHdrFtr);
	else
		return (bReturnHdrFtr ? null : false);
};
CDocumentContent.prototype.IsFootnote = function(bReturnFootnote)
{
	if (this instanceof CFootEndnote)
		return true;

	if (this.Parent)
		return this.Parent.IsFootnote(bReturnFootnote);

	return (bReturnFootnote ? null : false);
};
CDocumentContent.prototype.Is_DrawingShape = function(bRetShape)
{
	if (this.Parent)
		return this.Parent.Is_DrawingShape(bRetShape);
	else
		return (bRetShape ? null : false);
};
CDocumentContent.prototype.IsMovingTableBorder = function()
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.DrawingObjects.selectionIsTableBorder();
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (null != this.Selection.Data && true === this.Selection.Data.TableBorder)
			return true;
	}

	return false;
};
CDocumentContent.prototype.CheckTableCoincidence = function(Table)
{
	return this.Parent.CheckTableCoincidence(Table);
};
//-----------------------------------------------------------------------------------
// Основные функции, к которым идет обращение от родительского класса
//-----------------------------------------------------------------------------------
CDocumentContent.prototype.Reset = function(X, Y, XLimit, YLimit)
{
	this.X      = X;
	this.Y      = Y;
	this.XLimit = XLimit;
	this.YLimit = YLimit;

	// Заглушка для работы курсора в новой таблице
	if (0 === this.CurPos.X && 0 === this.CurPos.Y)
	{
		this.CurPos.X = X;
		this.CurPos.Y = Y;

		this.CurPos.RealX = X;
		this.CurPos.RealY = Y;
	}

	this.ClipInfo = [];
};
CDocumentContent.prototype.Recalculate                    = function()
{
    if (typeof(editor) !== "undefined" && editor.isDocumentEditor)
    {
        editor.WordControl.m_oLogicDocument.bRecalcDocContent    = true;
        editor.WordControl.m_oLogicDocument.recalcDocumentConten = this;
        editor.WordControl.m_oLogicDocument.Recalculate();
    }
};
CDocumentContent.prototype.Reset_RecalculateCache = function()
{
	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		this.Content[Index].Reset_RecalculateCache();
	}
};
// Пересчитываем отдельную страницу DocumentContent
CDocumentContent.prototype.Recalculate_Page               = function(PageIndex, bStart)
{
    if (0 === PageIndex && true === bStart && true !== this.IsBlockLevelSdtContent())
    {
        this.RecalcInfo.FlowObject                = null;
        this.RecalcInfo.FlowObjectPageBreakBefore = false;
    }

    var StartIndex = 0;
    if (PageIndex > 0)
        StartIndex = this.Pages[PageIndex - 1].EndPos;

    if (true === bStart)
    {
        this.Pages.length         = PageIndex;
        this.Pages[PageIndex]     = new CDocumentPage();
        this.Pages[PageIndex].Pos = StartIndex;
        if (this.LogicDocument)
            this.LogicDocument.DrawingObjects.resetDrawingArrays(this.Get_AbsolutePage(PageIndex), this);
    }

    var Count = this.Content.length;

    var StartPos;
    if (0 === PageIndex)
    {
        StartPos = {
            X      : this.X,
            Y      : this.Y,
            XLimit : this.XLimit,
            YLimit : this.YLimit
        }
    }
    else
    {
		StartPos = this.Get_PageContentStartPos(PageIndex);
    }

    this.Pages[PageIndex].Update_Limits(StartPos);

    var X      = StartPos.X;
    var StartY = StartPos.Y;
    var Y      = StartY;
    var YLimit = StartPos.YLimit;
    var XLimit = StartPos.XLimit;

    var Result = recalcresult2_End;

    for (var Index = StartIndex; Index < Count; Index++)
    {
        // Пересчитываем элемент документа
        var Element = this.Content[Index];

        var RecalcResult = recalcresult_NextElement;
        var bFlow        = false;
        if (type_Table === Element.GetType() && true != Element.Is_Inline())
        {
            bFlow = true;
            if (true === this.RecalcInfo.Can_RecalcObject())
            {
                Element.Set_DocumentIndex(Index);
                Element.Reset(X, Y, XLimit, YLimit, PageIndex, 0, 1);
                var TempRecalcResult = Element.Recalculate_Page(0);
                this.RecalcInfo.Set_FlowObject(Element, 0, TempRecalcResult, -1, {
                    X      : X,
                    Y      : Y,
                    XLimit : XLimit,
                    YLimit : YLimit
                });

                if (this.DrawingObjects)
                    this.DrawingObjects.addFloatTable(new CFlowTable(Element, PageIndex));

                RecalcResult = recalcresult_CurPage;
            }
            else if (true === this.RecalcInfo.Check_FlowObject(Element))
            {
                // Если у нас текущая страница совпадает с той, которая указана в таблице, тогда пересчитываем дальше
                if (Element.PageNum > PageIndex || ( this.RecalcInfo.FlowObjectPage <= 0 && Element.PageNum < PageIndex ) || Element.PageNum === PageIndex)
                {
                    if (true === this.RecalcInfo.FlowObjectPageBreakBefore)
                    {
                        // Добавляем начало таблицы в конец страницы так, чтобы не убралось ничего
                        Element.Set_DocumentIndex(Index);
                        Element.Reset(X, YLimit, XLimit, YLimit, PageIndex, 0, 1);
                        Element.Recalculate_Page(0);

                        this.RecalcInfo.FlowObjectPage++;
                        RecalcResult = recalcresult_NextPage;
                    }
                    else
                    {
                        X      = this.RecalcInfo.AdditionalInfo.X;
                        Y      = this.RecalcInfo.AdditionalInfo.Y;
                        XLimit = this.RecalcInfo.AdditionalInfo.XLimit;
                        YLimit = this.RecalcInfo.AdditionalInfo.YLimit;

                        // Пересчет нужнен для обновления номеров колонок и страниц
                        Element.Reset(X, Y, XLimit, YLimit, PageIndex, 0, 1);
                        RecalcResult = Element.Recalculate_Page(0);
                        this.RecalcInfo.FlowObjectPage++;

                        if (RecalcResult & recalcresult_NextElement)
                            this.RecalcInfo.Reset();
                    }
                }
                else
                {
                    RecalcResult = Element.Recalculate_Page(PageIndex - Element.PageNum);
                    this.RecalcInfo.FlowObjectPage++;

                    if (this.DrawingObjects)
                        this.DrawingObjects.addFloatTable(new CFlowTable(Element, PageIndex));

                    if (RecalcResult & recalcresult_NextElement)
                        this.RecalcInfo.Reset();
                }
            }
            else
            {
                RecalcResult = recalcresult_NextElement;
            }
        }
        else if (type_Paragraph === Element.GetType() && true != Element.Is_Inline())
        {
            // TODO: Пока обрабатываем рамки только внутри верхнего класса внутри колонтитулов. Разобраться как и
            //       главное когда они работают внутри таблиц и автофигур.

            bFlow = true;

            if (true === this.RecalcInfo.Can_RecalcObject())
            {
                var FramePr = Element.Get_FramePr();

                // Рассчитаем количество подряд идущих параграфов с одинаковыми FramePr
                var FlowCount = 1;
                for (var TempIndex = Index + 1; TempIndex < Count; TempIndex++)
                {
                    var TempElement = this.Content[TempIndex];
                    if (type_Paragraph === TempElement.GetType() && true != TempElement.Is_Inline())
                    {
                        var TempFramePr = TempElement.Get_FramePr();
                        if (true === FramePr.Compare(TempFramePr))
                            FlowCount++;
                        else
                            break;
                    }
                    else
                        break;
                }

                var LD_PageLimits = this.LogicDocument.Get_PageLimits(PageIndex + this.Get_StartPage_Absolute());
                var LD_PageFields = this.LogicDocument.Get_PageFields(PageIndex + this.Get_StartPage_Absolute());

                var Page_W = LD_PageLimits.XLimit;
                var Page_H = LD_PageLimits.YLimit;

                var Page_Field_L = LD_PageFields.X;
                var Page_Field_R = LD_PageFields.XLimit;
                var Page_Field_T = LD_PageFields.Y;
                var Page_Field_B = LD_PageFields.YLimit;

                //--------------------------------------------------------------------------------------------------
                // 1. Рассчитаем размер рамки
                //--------------------------------------------------------------------------------------------------
                var FrameH = 0;
                var FrameW = -1;

                var Frame_XLimit = FramePr.Get_W();
                var Frame_YLimit = FramePr.Get_H();

				var FrameHRule = ( undefined === FramePr.HRule ? Asc.linerule_Auto : FramePr.HRule );

				if (undefined === Frame_XLimit)
                    Frame_XLimit = Page_Field_R - Page_Field_L;

                if (undefined === Frame_YLimit || Asc.linerule_Auto === FrameHRule)
                    Frame_YLimit = Page_H;

                for (var TempIndex = Index; TempIndex < Index + FlowCount; TempIndex++)
                {
                    var TempElement = this.Content[TempIndex];
                    // Получим параметры расположения рамки
                    TempElement.Set_DocumentIndex(TempIndex);

                    if (Index != TempIndex || ( true != this.RecalcInfo.FrameRecalc && ( ( 0 === Index && 0 === PageIndex ) || Index != StartIndex ) ))
                        TempElement.Reset(0, FrameH, Frame_XLimit, Frame_YLimit, PageIndex);

                    TempElement.Recalculate_Page(PageIndex);

                    FrameH = TempElement.Get_PageBounds(PageIndex - TempElement.Get_StartPage_Relative()).Bottom;
                }

                // Обработаем "авто" ширину рамки. Ширина "авто" может быть в случае, когда значение W в FramePr
                // отсутствует, когда, у нас ровно 1 параграф, с 1 строкой.
                if (-1 === FrameW && 1 === FlowCount && 1 === Element.Lines.length && undefined === FramePr.Get_W())
                {
                    FrameW     = Element.GetAutoWidthForDropCap();
                    var ParaPr = Element.Get_CompiledPr2(false).ParaPr;
                    FrameW += ParaPr.Ind.Left + ParaPr.Ind.FirstLine;

                    // Если прилегание в данном случае не к левой стороне, тогда пересчитываем параграф,
                    // с учетом того, что ширина буквицы должна быть FrameW
                    if (AscCommon.align_Left != ParaPr.Jc)
                    {
                        TempElement.Reset(0, 0, FrameW, Frame_YLimit, PageIndex);
                        TempElement.Recalculate_Page(PageIndex);
                        FrameH = TempElement.Get_PageBounds(PageIndex - TempElement.Get_StartPage_Relative()).Bottom;
                    }
                }
                else if (-1 === FrameW)
                    FrameW = Frame_XLimit;

                switch (FrameHRule)
                {
                    case Asc.linerule_Auto :
                        break;
                    case Asc.linerule_AtLeast :
                    {
                        if (FrameH < FramePr.H)
                            FrameH = FramePr.H;

                        break;
                    }

                    case Asc.linerule_Exact:
                    {
                        FrameH = FramePr.H;
                        break;
                    }
                }

                //--------------------------------------------------------------------------------------------------
                // 2. Рассчитаем положение рамки
                //--------------------------------------------------------------------------------------------------

                // Теперь зная размеры рамки можем рассчитать ее позицию
                var FrameHAnchor = ( FramePr.HAnchor === undefined ? c_oAscHAnchor.Margin : FramePr.HAnchor );
                var FrameVAnchor = ( FramePr.VAnchor === undefined ? c_oAscVAnchor.Text : FramePr.VAnchor );

                // Рассчитаем положение по горизонтали
                var FrameX = 0;
                if (undefined != FramePr.XAlign || undefined === FramePr.X)
                {
                    var XAlign = c_oAscXAlign.Left;
                    if (undefined != FramePr.XAlign)
                        XAlign = FramePr.XAlign;

                    switch (FrameHAnchor)
                    {
                        case c_oAscHAnchor.Page   :
                        {
                            switch (XAlign)
                            {
                                case c_oAscXAlign.Inside  :
                                case c_oAscXAlign.Outside :
                                case c_oAscXAlign.Left    :
                                    FrameX = Page_Field_L - FrameW;
                                    break;
                                case c_oAscXAlign.Right   :
                                    FrameX = Page_Field_R;
                                    break;
                                case c_oAscXAlign.Center  :
                                    FrameX = (Page_W - FrameW) / 2;
                                    break;
                            }

                            break;
                        }
                        case c_oAscHAnchor.Text   :
                        case c_oAscHAnchor.Margin :
                        {
                            switch (XAlign)
                            {
                                case c_oAscXAlign.Inside  :
                                case c_oAscXAlign.Outside :
                                case c_oAscXAlign.Left    :
                                    FrameX = Page_Field_L;
                                    break;
                                case c_oAscXAlign.Right   :
                                    FrameX = Page_Field_R - FrameW;
                                    break;
                                case c_oAscXAlign.Center  :
                                    FrameX = (Page_Field_R + Page_Field_L - FrameW) / 2;
                                    break;
                            }

                            break;
                        }
                    }

                }
                else
                {
                    switch (FrameHAnchor)
                    {
                        case c_oAscHAnchor.Page   :
                            FrameX = FramePr.X;
                            break;
                        case c_oAscHAnchor.Text   :
                        case c_oAscHAnchor.Margin :
                            FrameX = Page_Field_L + FramePr.X;
                            break;
                    }
                }

                if (FrameW + FrameX > Page_W)
                    FrameX = Page_W - FrameW;

                if (FrameX < 0)
                    FrameX = 0;

                // Рассчитаем положение по вертикали
                var FrameY = 0;
                if (undefined != FramePr.YAlign)
                {
                    var YAlign = FramePr.YAlign;
                    // Случай c_oAscYAlign.Inline не обрабатывается, потому что такие параграфы считаются Inline

                    switch (FrameVAnchor)
                    {
                        case c_oAscVAnchor.Page   :
                        {
                            switch (YAlign)
                            {
                                case c_oAscYAlign.Inside  :
                                case c_oAscYAlign.Outside :
                                case c_oAscYAlign.Top     :
                                    FrameY = 0;
                                    break;
                                case c_oAscYAlign.Bottom  :
                                    FrameY = Page_H - FrameH;
                                    break;
                                case c_oAscYAlign.Center  :
                                    FrameY = (Page_H - FrameH) / 2;
                                    break;
                            }

                            break;
                        }
                        case c_oAscVAnchor.Text   :
                        {
                            FrameY = Y;
                            break;
                        }
                        case c_oAscVAnchor.Margin :
                        {
                            switch (YAlign)
                            {
                                case c_oAscYAlign.Inside  :
                                case c_oAscYAlign.Outside :
                                case c_oAscYAlign.Top     :
                                    FrameY = Page_Field_T;
                                    break;
                                case c_oAscYAlign.Bottom  :
                                    FrameY = Page_Field_B - FrameH;
                                    break;
                                case c_oAscYAlign.Center  :
                                    FrameY = (Page_Field_B + Page_Field_T - FrameH) / 2;
                                    break;
                            }

                            break;
                        }
                    }
                }
                else
                {
                    var FramePrY = 0;
                    if (undefined != FramePr.Y)
                        FramePrY = FramePr.Y;

                    switch (FrameVAnchor)
                    {
                        case c_oAscVAnchor.Page   :
                            FrameY = FramePrY;
                            break;
                        case c_oAscVAnchor.Text   :
                            FrameY = FramePrY + Y;
                            break;
                        case c_oAscVAnchor.Margin :
                            FrameY = FramePrY + Page_Field_T;
                            break;
                    }
                }

                if (FrameH + FrameY > Page_H)
                    FrameY = Page_H - FrameH;

                // TODO: Пересмотреть, почему эти погрешности возникают
                // Избавляемся от погрешности
                FrameY += 0.001;
                FrameH -= 0.002;

                if (FrameY < 0)
                    FrameY = 0;

                var FrameBounds = this.Content[Index].Get_FrameBounds(FrameX, FrameY, FrameW, FrameH);
                var FrameX2     = FrameBounds.X, FrameY2 = FrameBounds.Y, FrameW2 = FrameBounds.W, FrameH2 = FrameBounds.H;

                if ((FrameY2 + FrameH2 > YLimit || Y > YLimit - 0.001 ) && Index != StartIndex)
                {
                    this.RecalcInfo.Set_FrameRecalc(true);
                    this.Content[Index].StartFromNewPage();
                    RecalcResult = recalcresult_NextPage;
                }
                else
                {
                    this.RecalcInfo.Set_FrameRecalc(false);
                    for (var TempIndex = Index; TempIndex < Index + FlowCount; TempIndex++)
                    {
                        var TempElement = this.Content[TempIndex];
                        TempElement.Shift(TempElement.Pages.length - 1, FrameX, FrameY);
                        TempElement.Set_CalculatedFrame(FrameX, FrameY, FrameW, FrameH, FrameX2, FrameY2, FrameW2, FrameH2, PageIndex);
                    }

                    var FrameDx = ( undefined === FramePr.HSpace ? 0 : FramePr.HSpace );
                    var FrameDy = ( undefined === FramePr.VSpace ? 0 : FramePr.VSpace );

                    this.DrawingObjects.addFloatTable(new CFlowParagraph(Element, FrameX2, FrameY2, FrameW2, FrameH2, FrameDx, FrameDy, Index, FlowCount, FramePr.Wrap));

                    Index += FlowCount - 1;

                    if (FrameY >= Y)
                        RecalcResult = recalcresult_NextElement;
                    else
                    {
                        this.RecalcInfo.Set_FlowObject(Element, FlowCount, recalcresult_NextElement, FlowCount);
                        RecalcResult = recalcresult_CurPage;
                    }
                }
            }
            else if (true === this.RecalcInfo.Check_FlowObject(Element))
            {
                Index += this.RecalcInfo.FlowObjectPage - 1;
                this.RecalcInfo.Reset();
                RecalcResult = recalcresult_NextElement;
            }
            else
            {
                // Пропускаем
                RecalcResult = recalcresult_NextElement;
            }
        }
        else
        {
            if (( 0 === Index && 0 === PageIndex ) || Index != StartIndex)
            {
                Element.Set_DocumentIndex(Index);
                Element.Reset(X, Y, XLimit, YLimit, PageIndex, 0, 1);
            }

            if (Index === Count - 1 && Index > 0 && type_Paragraph === Element.GetType() && type_Table === this.Content[Index - 1].GetType() && true === Element.IsEmpty() && true === this.IsTableCellContent())
            {
                RecalcResult = recalcresult_NextElement;

                this.private_RecalculateEmptySectionParagraph(Element, this.Content[Index - 1], PageIndex, 0, 1);

                // Добавим в список особых параграфов
                this.Pages[PageIndex].EndSectionParas.push(Element);

                // Выставляем этот флаг, чтобы у нас не менялось значение по Y
                bFlow = true;
            }
            else
            {

                var ElementPageIndex = this.private_GetElementPageIndex(Index, PageIndex, 0, 1);
                RecalcResult         = Element.Recalculate_Page(ElementPageIndex);
            }
        }

        if (true != bFlow)
        {
            var ElementPageIndex = this.private_GetElementPageIndex(Index, PageIndex, 0, 1);
            Y                    = Element.Get_PageBounds(ElementPageIndex).Bottom;
        }

        if (RecalcResult & recalcresult_CurPage)
        {
        	if (true === this.IsBlockLevelSdtContent())
        		return recalcresult2_CurPage;

            // Такое не должно приходить в автофигурах, только в таблицах основного документа. Проверка на это находится в параграфе.
            if (RecalcResult & recalcresultflags_Footnotes)
				return recalcresult2_CurPage | recalcresultflags_Column | recalcresultflags_Footnotes;

            return this.Recalculate_Page(PageIndex, false);
        }
        else if (RecalcResult & recalcresult_NextElement)
        {
            // Ничего не делаем
        }
        else if (RecalcResult & recalcresult_NextPage)
        {
            this.Pages[PageIndex].EndPos = Index;
            Result                       = recalcresult2_NextPage;
            break;
        }
    }

    this.Pages[PageIndex].Bounds.Left   = X;
    this.Pages[PageIndex].Bounds.Top    = StartY;
    this.Pages[PageIndex].Bounds.Right  = XLimit;
    this.Pages[PageIndex].Bounds.Bottom = Y;

    if (Index >= Count)
    {
        this.Pages[PageIndex].EndPos = Count - 1;
        if (undefined != this.Parent.OnEndRecalculate_Page)
            this.Parent.OnEndRecalculate_Page(true);
    }
    else
    {
        if (undefined != this.Parent.OnEndRecalculate_Page)
            this.Parent.OnEndRecalculate_Page(false);
    }
    return Result;
};
CDocumentContent.prototype.RecalculateContent = function(fWidth, fHeight, nStartPage)
{
    this.Set_StartPage(nStartPage);
    this.Reset(0, 0, fWidth, 20000);
    var nRecalcResult = recalcresult2_NextPage;
    var nCurPage = 0;
    while ( recalcresult2_End !== nRecalcResult  )
        nRecalcResult = this.Recalculate_Page( nCurPage++, true );
};
CDocumentContent.prototype.RecalculateMinMaxContentWidth = function(isRotated)
{
	var Min   = 0;
	var Max   = 0;
	var Count = this.Content.length;

	if (true === isRotated)
	{
		for (var Pos = 0; Pos < Count; ++Pos)
		{
			var Element   = this.Content[Pos];
			var CurMinMax = Element.RecalculateMinMaxContentWidth(isRotated);

			Min += CurMinMax.Min;
			Max += CurMinMax.Max;
		}
	}
	else
	{
		for (var Pos = 0; Pos < Count; Pos++)
		{
			var Element   = this.Content[Pos];
			var CurMinMax = Element.RecalculateMinMaxContentWidth(isRotated);

			if (Min < CurMinMax.Min)
				Min = CurMinMax.Min;

			if (Max < CurMinMax.Max)
				Max = CurMinMax.Max;
		}
	}

	return {Min : Min, Max : Max};
};
CDocumentContent.prototype.SaveRecalculateObject = function()
{
	var RecalcObj = new CDocumentRecalculateObject();
	RecalcObj.Save(this);
	return RecalcObj;
};
CDocumentContent.prototype.LoadRecalculateObject = function(RecalcObj)
{
	RecalcObj.Load(this);
};
CDocumentContent.prototype.PrepareRecalculateObject = function()
{
	this.ClipInfo = [];
	this.Pages    = [];
	var Count     = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		this.Content[Index].PrepareRecalculateObject();
	}
};
CDocumentContent.prototype.ReDraw = function(StartPage, EndPage)
{
	if ("undefined" === typeof(StartPage))
		StartPage = this.Get_StartPage_Absolute();
	if ("undefined" === typeof(EndPage))
		EndPage = StartPage + this.Pages.length - 1;

	this.Parent.OnContentReDraw(StartPage, EndPage);
};
CDocumentContent.prototype.OnContentRecalculate = function(bNeedRecalc, PageNum, DocumentIndex)
{
	if (false === bNeedRecalc)
	{
		this.Parent.OnContentRecalculate(false, false);
	}
	else
	{
		// Ставим номер +1, потому что текущий элемент уже рассчитан
		this.Recalculate(false, DocumentIndex + 1);
	}
};
CDocumentContent.prototype.OnContentReDraw = function(StartPage, EndPage)
{
	this.Parent.OnContentReDraw(StartPage, EndPage);
};
CDocumentContent.prototype.Draw                           = function(nPageIndex, pGraphics)
{
    var CurPage = nPageIndex - this.StartPage;
    if (CurPage < 0 || CurPage >= this.Pages.length)
        return;

    if (pGraphics.Start_Command)
    {
        pGraphics.Start_Command(AscFormat.DRAW_COMMAND_CONTENT);
    }

    var ClipInfo = this.ClipInfo[CurPage];
    if (ClipInfo)
    {
        // TODO: При клипе, как правило, обрезается сверху и снизу по 1px, поэтому введем небольшую коррекцию
        var Correction = 0;
        if (null !== this.DrawingDocument)
            Correction = this.DrawingDocument.GetMMPerDot(1);

        var Bounds = this.Pages[CurPage].Bounds;
        pGraphics.SaveGrState();
        pGraphics.AddClipRect(ClipInfo.X0, Bounds.Top - Correction, Math.abs(ClipInfo.X1 - ClipInfo.X0), Bounds.Bottom - Bounds.Top + Correction);
    }

    if (this.LogicDocument)
        this.LogicDocument.DrawingObjects.drawBehindObjectsByContent(this.Get_AbsolutePage(CurPage), pGraphics, this);

    var Page_StartPos = this.Pages[CurPage].Pos;
    var Page_EndPos   = this.Pages[CurPage].EndPos;
    for (var Index = Page_StartPos; Index <= Page_EndPos; Index++)
    {
        var ElementPageIndex = this.private_GetElementPageIndex(Index, CurPage, 0, 1);
        this.Content[Index].Draw(ElementPageIndex, pGraphics);
    }


	if (this.LogicDocument)
		this.LogicDocument.DrawingObjects.drawBeforeObjectsByContent(this.Get_AbsolutePage(CurPage), pGraphics, this);

    if (ClipInfo)
    {
        pGraphics.RestoreGrState();
    }

    if (pGraphics.End_Command)
    {
        pGraphics.End_Command();
    }
};
CDocumentContent.prototype.GetAllComments = function(AllComments)
{
	if (undefined === AllComments)
		AllComments = [];

	var Count = this.Content.length;
	for (var Pos = 0; Pos < Count; Pos++)
	{
		var Item = this.Content[Pos];
		Item.GetAllComments(AllComments);
	}

	return AllComments;
};
CDocumentContent.prototype.GetAllMaths = function(AllMaths)
{
	if (undefined === AllMaths)
		AllMaths = [];

	var Count = this.Content.length;
	for (var Pos = 0; Pos < Count; Pos++)
	{
		var Item = this.Content[Pos];
		Item.GetAllMaths(AllMaths);
	}

	return AllMaths;
};
CDocumentContent.prototype.GetAllFloatElements = function(FloatObjs)
{
	if (undefined === FloatObjs)
		FloatObjs = [];

	var Count = this.Content.length;
	for (var Pos = 0; Pos < Count; Pos++)
	{
		var Item = this.Content[Pos];

		if (true !== Item.Is_Inline())
			FloatObjs.push(Item);

		Item.GetAllFloatElements(FloatObjs);
	}

	return FloatObjs;
};
CDocumentContent.prototype.Shift = function(CurPage, Dx, Dy)
{
	this.Pages[CurPage].Shift(Dx, Dy);

	if (this.ClipInfo[CurPage])
	{
		this.ClipInfo[CurPage].X0 += Dx;
		this.ClipInfo[CurPage].X1 += Dx;
	}

	var StartPos = this.Pages[CurPage].Pos;
	var EndPos   = this.Pages[CurPage].EndPos;
	for (var Index = StartPos; Index <= EndPos; Index++)
	{
		var Element          = this.Content[Index];
		var ElementPageIndex = this.private_GetElementPageIndex(Index, CurPage, 0, 1);
		Element.Shift(ElementPageIndex, Dx, Dy);
	}
};
CDocumentContent.prototype.UpdateEndInfo = function()
{
	for (var Index = 0, Count = this.Content.length; Index < Count; Index++)
	{
		this.Content[Index].UpdateEndInfo();
	}
};
CDocumentContent.prototype.RecalculateCurPos = function(bUpdateX, bUpdateY)
{
	var oCurPosInfo = null;

	if (docpostype_Content === this.CurPos.Type)
	{
		if (this.CurPos.ContentPos >= 0 && undefined != this.Content[this.CurPos.ContentPos])
		{
			this.private_CheckCurPage();

			if (this.CurPage > 0 && true === this.Parent.IsHdrFtr(false))
			{
				this.CurPage = 0;
				this.DrawingDocument.TargetEnd();
			}
			else
			{
				oCurPosInfo = this.Content[this.CurPos.ContentPos].RecalculateCurPos(bUpdateX, bUpdateY);
			}
		}
	}
	else // if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		oCurPosInfo = this.LogicDocument.DrawingObjects.recalculateCurPos(bUpdateX, bUpdateY);
	}

	if (oCurPosInfo)
	{
		if (bUpdateX)
			this.CurPos.RealX = oCurPosInfo.X;

		if (bUpdateY)
			this.CurPos.RealY = oCurPosInfo.Y;
	}

	return oCurPosInfo;
};
CDocumentContent.prototype.Get_PageBounds = function(CurPage, Height, bForceCheckDrawings)
{
	if (this.Pages.length <= 0)
		return new CDocumentBounds(0, 0, 0, 0);

	if (CurPage < 0)
		CurPage = 0;

	if (CurPage >= this.Pages.length)
		CurPage = this.Pages.length - 1;

	var Bounds  = this.Pages[CurPage].Bounds;
	var PageAbs = this.Get_AbsolutePage(CurPage);

	// В колонтитуле не учитывается.
	if ((true != this.IsHdrFtr(false) && true !== this.IsBlockLevelSdtContent()) || true === bForceCheckDrawings)
	{
		// Учитываем все Drawing-объекты с обтеканием. Объекты без обтекания (над и под текстом) учитываем только в
		// случае, когда начальная точка (левый верхний угол) попадает в this.Y + Height

		var AllDrawingObjects = this.GetAllDrawingObjects();
		var Count             = AllDrawingObjects.length;
		for (var Index = 0; Index < Count; Index++)
		{
			var Obj = AllDrawingObjects[Index];
			if (PageAbs === Obj.Get_PageNum())
			{
				var ObjBounds = Obj.Get_Bounds();
				if (true === Obj.Use_TextWrap())
				{
					if (ObjBounds.Bottom > Bounds.Bottom)
						Bounds.Bottom = ObjBounds.Bottom;
				}
				else if (undefined !== Height && ObjBounds.Top < this.Y + Height)
				{
					if (ObjBounds.Bottom >= this.Y + Height)
						Bounds.Bottom = this.Y + Height;
					else if (ObjBounds.Bottom > Bounds.Bottom)
						Bounds.Bottom = ObjBounds.Bottom;
				}
			}
		}

		// Кроме этого пробежимся по всем Flow-таблицам и учтем их границы
		var Count = this.Content.length;
		for (var Index = 0; Index < Count; Index++)
		{
			var Element          = this.Content[Index];
			var ElementPageIndex = this.private_GetElementPageIndex(Index, CurPage, 0, 1);
			if (type_Table === Element.GetType() && true != Element.Is_Inline() && 0 <= ElementPageIndex && ElementPageIndex < Element.Get_PagesCount())
			{
				var TableBounds = Element.Get_PageBounds(ElementPageIndex);
				if (TableBounds.Bottom > Bounds.Bottom)
					Bounds.Bottom = TableBounds.Bottom;
			}
		}
	}

	return Bounds;
};
CDocumentContent.prototype.GetContentBounds = function(CurPage)
{
	var oPage = this.Pages[CurPage];
	if (!oPage || oPage.Pos > oPage.EndPos)
		return this.Get_PageBounds(CurPage);

	var oBounds = null;
	for (var nIndex = oPage.Pos; nIndex <= oPage.EndPos; ++nIndex)
	{
		var oElement          = this.Content[nIndex];
		var nElementPageIndex = this.private_GetElementPageIndex(nIndex, CurPage, 0, 1);

		var oElementBounds = oElement.GetContentBounds(nElementPageIndex);

		if (null === oBounds)
		{
			oBounds = oElementBounds.Copy();
		}
		else
		{
			if (oElementBounds.Bottom > oBounds.Bottom)
				oBounds.Bottom = oElementBounds.Bottom;

			if (oElementBounds.Top < oBounds.Top)
				oBounds.Top = oElementBounds.Top;

			if (oElementBounds.Right > oBounds.Right)
				oBounds.Right = oElementBounds.Right;

			if (oElementBounds.Left < oBounds.Left)
				oBounds.Left = oElementBounds.Left;
		}
	}

	return oBounds;
};
CDocumentContent.prototype.Get_PagesCount = function()
{
	return this.Pages.length;
};
CDocumentContent.prototype.GetSummaryHeight = function()
{
	var Height = 0;
	for (var Page = 0; Page < this.Get_PagesCount(); Page++)
	{
		var Bounds = this.Get_PageBounds(Page);
		Height += Bounds.Bottom - Bounds.Top;
	}

	return Height;
};
CDocumentContent.prototype.Get_FirstParagraph = function()
{
	if (this.Content.length > 0)
		return this.Content[0].Get_FirstParagraph();

	return null;
};
CDocumentContent.prototype.GetAllParagraphs = function(Props, ParaArray)
{
	var arrParagraphs = (ParaArray ? ParaArray : []);

	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		var Element = this.Content[Index];
		Element.GetAllParagraphs(Props, arrParagraphs);
	}

	return arrParagraphs;
};
// Специальная функция, используемая в колонтитулах для добавления номера страницы
// При этом удаляются все параграфы. Добавляются два новых
CDocumentContent.prototype.HdrFtr_AddPageNum             = function(Align, StyleId)
{
    this.RemoveSelection();

    this.CurPos =
    {
        X          : 0,
        Y          : 0,
        ContentPos : 0,
        RealX      : 0,
        RealY      : 0,
        Type       : docpostype_Content
    };

    this.Selection.Use = false;

    // Удаляем все элементы
    this.Internal_Content_RemoveAll();

    // Добавляем 2 новых параграфа
    var Para1 = new Paragraph(this.DrawingDocument, this, this.bPresentation === true);
    var Para2 = new Paragraph(this.DrawingDocument, this, this.bPresentation === true);

    this.Internal_Content_Add(0, Para1);
    this.Internal_Content_Add(1, Para2);

    Para1.Set_DocumentPrev(null);
    Para1.Set_DocumentNext(Para2);
    Para2.Set_DocumentPrev(Para1);
    Para2.Set_DocumentNext(null);

    Para1.Style_Add(StyleId);
    Para2.Style_Add(StyleId);

    Para1.Set_Align(Align, false);
    var Run = new ParaRun(Para1, false);
    Run.Add_ToContent(0, new ParaPageNum());
    Para1.Add_ToContent(0, Run);

    this.Recalculate();
};
CDocumentContent.prototype.Clear_Content                 = function()
{
    this.RemoveSelection();

    this.CurPos =
    {
        X          : 0,
        Y          : 0,
        ContentPos : 0,
        RealX      : 0,
        RealY      : 0,
        Type       : docpostype_Content
    };

    this.Selection.Use = false;

    // Удаляем все элементы
    this.Internal_Content_RemoveAll();

    // Добавляем новый параграф
    var Para = new Paragraph(this.DrawingDocument, this, this.bPresentation === true);
    this.Internal_Content_Add(0, Para);
};
CDocumentContent.prototype.Add_Content = function(OtherContent)
{
	return this.AddContent(OtherContent.Content);
};
/**
 * Полностью очищаем содержимое
 * @param {boolean} [isAddEmptyPara=true] добавлять ли пустой параграф
 */
CDocumentContent.prototype.ClearContent = function(isAddEmptyPara)
{
	this.Selection.Start    = false;
	this.Selection.Use      = false;
	this.Selection.StartPos = 0;
	this.Selection.EndPos   = 0;
	this.Selection.Flag     = selectionflag_Common;
	this.Selection.Data     = null;

	this.CurPos.X          = 0;
	this.CurPos.Y          = 0;
	this.CurPos.ContentPos = 0;
	this.CurPos.RealX      = 0;
	this.CurPos.RealY      = 0;
	this.CurPos.Type       = docpostype_Content;

	this.Internal_Content_RemoveAll();

	if (false !== isAddEmptyPara)
		this.Internal_Content_Add(0, new Paragraph(this.DrawingDocument, this, this.bPresentation === true));
};
/**
 * Присоединяем к содержимому массив новых элементов (параграфов, таблиц)
 * @param {Paragraph, CTable} arrElements[]
 */
CDocumentContent.prototype.AddContent = function(arrElements)
{
	if (!arrElements || arrElements.length <= 0)
		return;

	if (this.Content.length <= 0 || true === this.IsEmpty())
	{
		if (this.Content.length > 0)
			this.Internal_Content_RemoveAll();

		for (var nIndex = 0, nCount = arrElements.length; nIndex < nCount; ++nIndex)
			this.Internal_Content_Add(nIndex, arrElements[nIndex]);
	}
	else
	{
		this.Content[this.Content.length - 1].Set_DocumentNext(arrElements[0]);
		arrElements[0].Set_DocumentPrev(this.Content[this.Content.length - 1]);

		for (var nIndex = 0, nCount = arrElements.length; nIndex < nCount; ++nIndex)
			this.Internal_Content_Add(this.Content.length, arrElements[nIndex]);
	}
};
CDocumentContent.prototype.Is_Empty = function()
{
	if (this.Content.length > 1 || type_Paragraph !== this.Content[0].GetType())
		return false;

	return this.Content[0].IsEmpty({SkipPlcHldr : false});
};
CDocumentContent.prototype.IsEmpty = function()
{
	return this.Is_Empty();
};
CDocumentContent.prototype.Is_CurrentElementTable = function()
{
	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.isCurrentElementTable();
	}
	else if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Table == this.Content[this.Selection.StartPos].GetType() ) || ( false == this.Selection.Use && type_Table == this.Content[this.CurPos.ContentPos].GetType() ) ))
	{
		return true;
	}
	return false;
};
CDocumentContent.prototype.Is_CurrentElementParagraph = function()
{
	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.isCurrentElementParagraph();
	}
	else if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Table == this.Content[this.Selection.StartPos].GetType() ) || ( false == this.Selection.Use && type_Table == this.Content[this.CurPos.ContentPos].GetType() ) ))
	{
		return false;
	}

	return true;
};
CDocumentContent.prototype.GetCurrentParagraph = function(bIgnoreSelection, arrSelectedParagraphs)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.getCurrentParagraph(bIgnoreSelection, arrSelectedParagraphs);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (arrSelectedParagraphs)
		{
			if (true === this.ApplyToAll)
			{
				for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos)
				{
					this.Content[nPos].Set_ApplyToAll(true);
					this.Content[nPos].GetCurrentParagraph(false, arrSelectedParagraphs);
					this.Content[nPos].Set_ApplyToAll(false);
				}
			}
			else if (true === this.Selection.Use)
			{
				var nStartPos = this.Selection.StartPos <= this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos;
				var nEndPos   = this.Selection.StartPos <= this.Selection.EndPos ? this.Selection.EndPos : this.Selection.StartPos;
				for (var nPos = nStartPos; nPos <= nEndPos; ++nPos)
				{
					this.Content[nPos].GetCurrentParagraph(false, arrSelectedParagraphs);
				}
			}
			else
			{
				this.Content[this.CurPos.ContentPos].GetCurrentParagraph(false, arrSelectedParagraphs);
			}
		}
		else
		{
			var Pos = true === this.Selection.Use && true !== bIgnoreSelection ? this.Selection.StartPos : this.CurPos.ContentPos;
			if (Pos < 0 || Pos >= this.Content.length)
				return null;

			return this.Content[Pos].GetCurrentParagraph(bIgnoreSelection, null);
		}
	}

	return null;
};
CDocumentContent.prototype.IsContentOnFirstPage = function()
{
	if (this.Content.length <= 0)
		return false;

	var Element = this.Content[0];
	return Element.IsContentOnFirstPage();
};
CDocumentContent.prototype.StartFromNewPage = function()
{
	this.Pages.length = 1;
	this.Pages[0]     = new CDocumentPage();

	var Element = this.Content[0];
	Element.StartFromNewPage();
};
CDocumentContent.prototype.Get_ParentTextTransform = function()
{
	if (this.Parent)
		return this.Parent.Get_ParentTextTransform();

	return null;
};
CDocumentContent.prototype.IsTableBorder = function(X, Y, CurPage)
{
	CurPage = Math.max(0, Math.min(this.Pages.length - 1, CurPage));

	var ElementPos       = this.Internal_GetContentPosByXY(X, Y, CurPage);
	var Element          = this.Content[ElementPos];
	var ElementPageIndex = this.private_GetElementPageIndex(ElementPos, CurPage, 0, 1);
	return Element.IsTableBorder(X, Y, ElementPageIndex);
};
CDocumentContent.prototype.IsInText = function(X, Y, CurPage)
{
	if (CurPage < 0 || CurPage >= this.Pages.length)
		CurPage = 0;

	var ContentPos       = this.Internal_GetContentPosByXY(X, Y, CurPage);
	var Item             = this.Content[ContentPos];
	var ElementPageIndex = this.private_GetElementPageIndexByXY(ContentPos, X, Y, CurPage);
	return Item.IsInText(X, Y, ElementPageIndex);
};
CDocumentContent.prototype.IsInDrawing = function(X, Y, CurPage)
{
	if (-1 != this.DrawingObjects.IsInDrawingObject(X, Y, this.Get_AbsolutePage(CurPage), this))
	{
		return true;
	}
	else
	{
		if (CurPage < 0 || CurPage >= this.Pages.length)
			CurPage = 0;

		var ContentPos = this.Internal_GetContentPosByXY(X, Y, CurPage);
		var Item       = this.Content[ContentPos];
		if (type_Table == Item.GetType())
		{
			var ElementPageIndex = this.private_GetElementPageIndexByXY(ContentPos, X, Y, CurPage);
			return Item.IsInDrawing(X, Y, ElementPageIndex);
		}

		return false;
	}
};
CDocumentContent.prototype.Get_CurrentPage_Absolute = function()
{
	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.getCurrentPageAbsolute();
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.IsNumberingSelection())
			return this.Selection.Data.CurPara.Get_CurrentPage_Absolute();

		var Pos = ( true === this.Selection.Use ? this.Selection.EndPos : this.CurPos.ContentPos );
		if (Pos >= 0 && Pos < this.Content.length)
			return this.Content[Pos].Get_CurrentPage_Absolute();
	}

	return 0;
};
CDocumentContent.prototype.Get_CurrentPage_Relative = function()
{
	return this.CurPage;
};
CDocumentContent.prototype.CollectDocumentStatistics = function(Stats)
{
	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		var Element = this.Content[Index];
		Element.CollectDocumentStatistics(Stats);
	}
};
CDocumentContent.prototype.Document_CreateFontMap = function(FontMap)
{
	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		var Element = this.Content[Index];
		Element.Document_CreateFontMap(FontMap);
	}
};
CDocumentContent.prototype.Document_CreateFontCharMap = function(FontCharMap)
{
	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		var Element = this.Content[Index];
		Element.Document_CreateFontCharMap(FontCharMap);
	}
};
CDocumentContent.prototype.Document_Get_AllFontNames = function(AllFonts)
{
	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		var Element = this.Content[Index];
		Element.Document_Get_AllFontNames(AllFonts);
	}
};
CDocumentContent.prototype.Document_UpdateInterfaceState = function()
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		var oDrawingObjects = this.LogicDocument.DrawingObjects;
		var oTargetTextObject = AscFormat.getTargetTextObject(oDrawingObjects);
		if (oTargetTextObject)
		{
			this.LogicDocument.Interface_Update_DrawingPr();
			oDrawingObjects.documentUpdateInterfaceState();
		}
		else
		{
			oDrawingObjects.resetInterfaceTextPr();
			oDrawingObjects.updateTextPr();
			this.LogicDocument.Interface_Update_DrawingPr();
			oDrawingObjects.updateParentParagraphParaPr();
		}
	}
	else //if (docpostype_Content === this.CurPos.Type)
	{
		if ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType())
			|| (false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType()))
		{
			this.Interface_Update_TablePr();
			if (true == this.Selection.Use)
				this.Content[this.Selection.StartPos].Document_UpdateInterfaceState();
			else
				this.Content[this.CurPos.ContentPos].Document_UpdateInterfaceState();
		}
		else
		{
			this.Interface_Update_ParaPr();
			this.Interface_Update_TextPr();

			// Если у нас в выделении находится 1 параграф, или курсор находится в параграфе
			if ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph == this.Content[this.Selection.StartPos].GetType())
				|| (false == this.Selection.Use && type_Paragraph == this.Content[this.CurPos.ContentPos].GetType()))
			{
				if (true == this.Selection.Use)
					this.Content[this.Selection.StartPos].Document_UpdateInterfaceState();
				else
					this.Content[this.CurPos.ContentPos].Document_UpdateInterfaceState();
			}
		}
	}
};
CDocumentContent.prototype.Document_UpdateRulersState = function(CurPage)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		this.LogicDocument.DrawingObjects.documentUpdateRulersState(CurPage);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (true === this.Selection.Use)
		{
			if (this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType())
			{
				var ElementPos       = this.Selection.StartPos;
				var Element          = this.Content[ElementPos];
				var ElementPageIndex = this.private_GetElementPageIndex(ElementPos, this.CurPage, Element.Get_StartColumn(), Element.Get_ColumnsCount());
				Element.Document_UpdateRulersState(ElementPageIndex);
			}
			else
			{
				var StartPos = ( this.Selection.EndPos <= this.Selection.StartPos ? this.Selection.EndPos : this.Selection.StartPos );
				var EndPos   = ( this.Selection.EndPos <= this.Selection.StartPos ? this.Selection.StartPos : this.Selection.EndPos );

				var FramePr = undefined;

				for (var Pos = StartPos; Pos <= EndPos; Pos++)
				{
					var Element = this.Content[Pos];
					if (type_Paragraph != Element.GetType())
					{
						FramePr = undefined;
						break;
					}
					else
					{
						var TempFramePr = Element.Get_FramePr();
						if (undefined === FramePr)
						{
							if (undefined === TempFramePr)
								break;

							FramePr = TempFramePr;
						}
						else if (undefined === TempFramePr || false === FramePr.Compare(TempFramePr))
						{
							FramePr = undefined;
							break;
						}
					}
				}

				if (undefined !== FramePr)
					this.Content[StartPos].Document_UpdateRulersState();
			}
		}
		else
		{
			var ElementPos       = this.CurPos.ContentPos;
			var Element          = this.Content[ElementPos];
			var ElementPageIndex = this.private_GetElementPageIndex(ElementPos, this.CurPage, Element.Get_StartColumn(), Element.Get_ColumnsCount());
			Element.Document_UpdateRulersState(ElementPageIndex);
		}
	}
};
CDocumentContent.prototype.Can_CopyCut = function()
{
	var bCanCopyCut = false;

	var LogicDocument  = null;
	var DrawingObjects = null;

	// Работаем с колонтитулом
	if (docpostype_DrawingObjects === this.CurPos.Type)
		DrawingObjects = this.DrawingObjects;
	else
		LogicDocument = this;

	if (null !== DrawingObjects)
	{
		if (true === DrawingObjects.isSelectedText())
			LogicDocument = DrawingObjects.getTargetDocContent();
		else
			bCanCopyCut = true;
	}

	if (null !== LogicDocument)
	{
		if (true === LogicDocument.IsSelectionUse())
		{
			if (selectionflag_Numbering === LogicDocument.Selection.Flag)
				bCanCopyCut = false;
			else if (LogicDocument.Selection.StartPos !== LogicDocument.Selection.EndPos)
				bCanCopyCut = true;
			else
				bCanCopyCut = LogicDocument.Content[LogicDocument.Selection.StartPos].Can_CopyCut();
		}
	}

	return bCanCopyCut;
};
CDocumentContent.prototype.MoveCursorToStartPos = function(AddToSelect)
{
	if (true === AddToSelect)
	{
		if (docpostype_DrawingObjects === this.CurPos.Type)
		{
			// TODO: Пока ничего не делаем, в дальнейшем надо будет делать в зависимости от селекта внутри
			//       автофигуры: если селект текста внутри, то делать для текста внутри, а если выделена
			//       сама автофигура, тогда мы перемещаем курсор влево от нее в контенте параграфа и выделяем все до конца
		}
		else if (docpostype_Content === this.CurPos.Type)
		{
			var StartPos = ( true === this.Selection.Use ? this.Selection.StartPos : this.CurPos.ContentPos );
			var EndPos   = 0;

			this.Selection.Start    = false;
			this.Selection.Use      = true;
			this.Selection.StartPos = StartPos;
			this.Selection.EndPos   = EndPos;
			this.Selection.Flag     = selectionflag_Common;

			this.CurPos.ContentPos = 0;
			this.Set_DocPosType(docpostype_Content);

			for (var Index = StartPos - 1; Index >= EndPos; Index--)
			{
				this.Content[Index].SelectAll(-1);
			}

			this.Content[StartPos].MoveCursorToStartPos(true);
		}
	}
	else
	{
		this.RemoveSelection();

		this.Selection.Start    = false;
		this.Selection.Use      = false;
		this.Selection.StartPos = 0;
		this.Selection.EndPos   = 0;
		this.Selection.Flag     = selectionflag_Common;

		this.CurPos.ContentPos = 0;
		this.Set_DocPosType(docpostype_Content);
		this.Content[0].MoveCursorToStartPos(false);
	}
};
CDocumentContent.prototype.MoveCursorToEndPos = function(AddToSelect, StartSelectFromEnd)
{
	if (true === AddToSelect)
	{
		if (docpostype_DrawingObjects === this.CurPos.Type)
		{
			// TODO: Пока ничего не делаем, в дальнейшем надо будет делать в зависимости от селекта внутри
			//       автофигуры: если селект текста внутри, то делать для текста внутри, а если выделена
			//       сама автофигура, тогда мы перемещаем курсор влево от нее в контенте параграфа и выделяем все до конца
		}
		else if (docpostype_Content === this.CurPos.Type)
		{
			var StartPos = ( true === this.Selection.Use ? this.Selection.StartPos : this.CurPos.ContentPos )
			var EndPos   = this.Content.length - 1;

			this.Selection.Start    = false;
			this.Selection.Use      = true;
			this.Selection.StartPos = StartPos;
			this.Selection.EndPos   = EndPos;
			this.Selection.Flag     = selectionflag_Common;

			this.CurPos.ContentPos = this.Content.length - 1;
			this.Set_DocPosType(docpostype_Content);

			for (var Index = StartPos + 1; Index <= EndPos; Index++)
			{
				this.Content[Index].SelectAll(1);
			}

			this.Content[StartPos].MoveCursorToEndPos(true);
		}
	}
	else
	{
		if (true === StartSelectFromEnd)
		{
			this.Selection.Start    = false;
			this.Selection.Use      = true;
			this.Selection.StartPos = this.Content.length - 1;
			this.Selection.EndPos   = this.Content.length - 1;
			this.Selection.Flag     = selectionflag_Common;
			this.CurPos.ContentPos  = this.Content.length - 1;
			this.Set_DocPosType(docpostype_Content);
			this.Content[this.Content.length - 1].MoveCursorToEndPos(false, true);
		}
		else
		{
			this.RemoveSelection();

			this.Selection.Start    = false;
			this.Selection.Use      = false;
			this.Selection.StartPos = 0;
			this.Selection.EndPos   = 0;
			this.Selection.Flag     = selectionflag_Common;

			this.CurPos.ContentPos = this.Content.length - 1;
			this.Set_DocPosType(docpostype_Content);
			this.Content[this.CurPos.ContentPos].MoveCursorToEndPos(false);
		}
	}
};
CDocumentContent.prototype.MoveCursorUpToLastRow = function(X, Y, AddToSelect)
{
	this.SetCurPosXY(X, Y);
	if (true === AddToSelect)
	{
		if (true !== this.Selection.Use)
		{
			this.CurPos.ContentPos = this.Content.length - 1;
			this.Set_DocPosType(docpostype_Content);
			this.Selection.Use      = true;
			this.Selection.Start    = false;
			this.Selection.StartPos = this.CurPos.ContentPos;
			this.Selection.EndPos   = this.CurPos.ContentPos;
			this.Selection.Flag     = selectionflag_Common;

			this.Content[this.CurPos.ContentPos].MoveCursorToEndPos(false, true);
			this.Content[this.CurPos.ContentPos].MoveCursorUpToLastRow(X, Y, true);
		}
		else
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Content.length - 1;

			this.CurPos.ContentPos = EndPos;

			// Очистим старый селект кроме начального элемента
			var _S = this.Selection.StartPos <= this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos;
			var _E = this.Selection.StartPos <= this.Selection.EndPos ? this.Selection.EndPos : this.Selection.StartPos;
			for (var nPos = _S; nPos <= _E; ++nPos)
			{
				if (nPos !== StartPos)
					this.Content[nPos].RemoveSelection();
			}

			if (StartPos === EndPos)
			{
				this.Selection.StartPos = StartPos;
				this.Selection.EndPos   = StartPos;
				this.Content[StartPos].MoveCursorUpToLastRow(X, Y, true);
			}
			else
			{
				this.Content[StartPos].MoveCursorToEndPos(true);
				for (var nPos = StartPos + 1; nPos <= EndPos; ++nPos)
				{
					this.Content[nPos].SelectAll(1);
				}

				this.Content[EndPos].MoveCursorUpToLastRow(X, Y, true);
			}
		}
	}
	else
	{
		this.CurPos.ContentPos = this.Content.length - 1;
		this.Content[this.CurPos.ContentPos].MoveCursorUpToLastRow(X, Y, false);
	}
};
CDocumentContent.prototype.MoveCursorDownToFirstRow = function(X, Y, AddToSelect)
{
	this.SetCurPosXY(X, Y);
	if (true === AddToSelect)
	{
		if (true !== this.Selection.Use)
		{
			this.CurPos.ContentPos = 0;
			this.Set_DocPosType(docpostype_Content);
			this.Selection.Use      = true;
			this.Selection.Start    = false;
			this.Selection.StartPos = 0;
			this.Selection.EndPos   = 0;
			this.Selection.Flag     = selectionflag_Common;

			this.Content[0].MoveCursorToStartPos(false);
			this.Content[0].MoveCursorDownToFirstRow(X, Y, true);
		}
		else
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = 0;

			this.CurPos.ContentPos = EndPos;

			// Очистим старый селект кроме начального элемента
			var _S = this.Selection.StartPos <= this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos;
			var _E = this.Selection.StartPos <= this.Selection.EndPos ? this.Selection.EndPos : this.Selection.StartPos;
			for (var nPos = _S; nPos <= _E; ++nPos)
			{
				if (nPos !== StartPos)
					this.Content[nPos].RemoveSelection();
			}

			if (StartPos === EndPos)
			{
				this.Selection.StartPos = StartPos;
				this.Selection.EndPos   = StartPos;
				this.Content[StartPos].MoveCursorDownToFirstRow(X, Y, true);
			}
			else
			{
				this.Content[StartPos].MoveCursorToStartPos(true);
				for (var nPos = EndPos; nPos < StartPos; ++nPos)
				{
					this.Content[nPos].SelectAll(-1);
				}

				this.Content[EndPos].MoveCursorDownToFirstRow(X, Y, true);
			}
		}
	}
	else
	{
		this.CurPos.ContentPos = 0;
		this.Content[this.CurPos.ContentPos].MoveCursorDownToFirstRow(X, Y, false);
	}
};
CDocumentContent.prototype.MoveCursorToCell = function(bNext)
{
	if (true === this.ApplyToAll)
	{
		if (1 === this.Content.length)
			this.Content[0].MoveCursorToCell(bNext);
	}
	else
	{
		if (docpostype_DrawingObjects == this.CurPos.Type)
		{
			this.LogicDocument.DrawingObjects.cursorMoveToCell(bNext);
		}
		else //if ( docpostype_Content == this.CurPos.Type )
		{
			if (true === this.Selection.Use)
			{
				if (this.Selection.StartPos === this.Selection.EndPos)
					this.Content[this.Selection.StartPos].MoveCursorToCell(bNext);
			}
			else
			{
				this.Content[this.CurPos.ContentPos].MoveCursorToCell(bNext);
			}
		}
	}
};
CDocumentContent.prototype.Set_ClipInfo = function(CurPage, X0, X1)
{
	this.ClipInfo[CurPage] = {X0 : X0, X1 : X1};
};
CDocumentContent.prototype.Set_ApplyToAll = function(bValue)
{
	this.ApplyToAll = bValue;
};
CDocumentContent.prototype.Get_ApplyToAll = function()
{
	return this.ApplyToAll;
};
CDocumentContent.prototype.UpdateCursorType = function(X, Y, CurPage)
{
	if (CurPage < 0 || CurPage >= this.Pages.length)
		return this.DrawingDocument.SetCursorType("text", new AscCommon.CMouseMoveData());

	var bInText      = (null === this.IsInText(X, Y, CurPage) ? false : true);
	var bTableBorder = (null === this.IsTableBorder(X, Y, CurPage) ? false : true);

	// Ничего не делаем
	if (this.Parent instanceof CHeaderFooter && true === this.LogicDocument.DrawingObjects.updateCursorType(this.Get_AbsolutePage(CurPage), X, Y, {}, ( true === bInText || true === bTableBorder ? true : false )))
		return;

	var ContentPos       = this.Internal_GetContentPosByXY(X, Y, CurPage);
	var Item             = this.Content[ContentPos];
	var ElementPageIndex = this.private_GetElementPageIndexByXY(ContentPos, X, Y, CurPage);
	Item.UpdateCursorType(X, Y, ElementPageIndex);
};
//-----------------------------------------------------------------------------------
// Функции для работы с контентом
//-----------------------------------------------------------------------------------
CDocumentContent.prototype.AddNewParagraph = function()
{
    if (docpostype_DrawingObjects === this.CurPos.Type)
    {
        return this.DrawingObjects.addNewParagraph();
    }
    else //if ( docpostype_Content == this.CurPos.Type )
    {
        if (this.CurPos.ContentPos < 0)
            return false;

        // Сначала удаляем заселекченую часть
        if (true === this.Selection.Use)
        {
            this.Remove(1, true, false, true);
        }

        // Добавляем новый параграф
        var Item = this.Content[this.CurPos.ContentPos];

        // Если мы внутри параграфа, тогда:
        // 1. Если мы в середине параграфа, разделяем данный параграф на 2.
        //    При этом полностью копируем все настройки из исходного параграфа.
        // 2. Если мы в конце данного параграфа, тогда добавляем новый пустой параграф.
        //    Стиль у него проставляем такой какой указан у текущего в Style.Next.
        //    Если при этом у нового параграфа стиль будет такой же как и у старого,
        //    в том числе если стиля нет у обоих, тогда копируем еще все прямые настройки.
        //    (Т.е. если стили разные, а у исходный параграф был параграфом со списком, тогда
        //    новый параграф будет без списка).
        if (type_Paragraph === Item.GetType())
        {
            // Если текущий параграф пустой и с нумерацией, тогда удаляем нумерацию и отступы левый и первой строки
            if (undefined != Item.GetNumPr() && true === Item.IsEmpty({SkipNewLine : true}) && true === Item.IsCursorAtBegin())
            {
                Item.RemoveNumPr();
                Item.Set_Ind({FirstLine : undefined, Left : undefined, Right : Item.Pr.Ind.Right}, true);
            }
            else
            {
                var ItemReviewType = Item.Get_ReviewType();
                // Создаем новый параграф
                var NewParagraph   = new Paragraph(this.DrawingDocument, this, this.bPresentation === true);

                // Проверим позицию в текущем параграфе
                if (true === Item.IsCursorAtEnd())
                {
                    var StyleId = Item.Style_Get();
                    var NextId  = undefined;

                    if (undefined != StyleId)
                    {
                        var Styles = this.Parent.Get_Styles();
                        NextId     = Styles.Get_Next(StyleId);

						var oNextStyle = Styles.Get(NextId);
						if (!NextId || !oNextStyle || !oNextStyle.IsParagraphStyle())
							NextId = StyleId;
                    }


                    if (StyleId === NextId)
                    {
                        // Продолжаем (в плане настроек) новый параграф
                        Item.Continue(NewParagraph);
                    }
                    else
                    {
                        // Простое добавление стиля, без дополнительных действий
                        if (NextId === this.Get_Styles().Get_Default_Paragraph())
                            NewParagraph.Style_Remove();
                        else
                            NewParagraph.Style_Add(NextId, true);
                    }

					var LastRun = Item.Content[Item.Content.length - 1];
					if (LastRun && LastRun.Pr.Lang && LastRun.Pr.Lang.Val)
					{
						NewParagraph.SelectAll();
						NewParagraph.Add(new ParaTextPr({Lang : LastRun.Pr.Lang.Copy()}));
						NewParagraph.RemoveSelection();
					}
                }
                else
				{
					Item.Split(NewParagraph);
				}

				NewParagraph.Correct_Content();
                NewParagraph.MoveCursorToStartPos();

                this.Internal_Content_Add(this.CurPos.ContentPos + 1, NewParagraph);
                this.CurPos.ContentPos++;

                if (true === this.Is_TrackRevisions())
                {
                    NewParagraph.Remove_PrChange();
                    NewParagraph.Set_ReviewType(ItemReviewType);
                    Item.Set_ReviewType(reviewtype_Add);
                }
                else if (reviewtype_Common !== ItemReviewType)
                {
                    NewParagraph.Set_ReviewType(ItemReviewType);
                    Item.Set_ReviewType(reviewtype_Common);
                }
            }
        }
        else if (type_Table === Item.GetType() || type_BlockLevelSdt === Item.GetType())
        {
            // Если мы находимся в начале первого параграфа первой ячейки, и
            // данная таблица - первый элемент, тогда добавляем параграф до таблицы.

            if (0 === this.CurPos.ContentPos && Item.IsCursorAtBegin(true))
            {
                // Создаем новый параграф
                var NewParagraph = new Paragraph(this.DrawingDocument, this, this.bPresentation === true);
                this.Internal_Content_Add(0, NewParagraph);
                this.CurPos.ContentPos = 0;

				if (true === this.Is_TrackRevisions())
				{
					NewParagraph.Remove_PrChange();
					NewParagraph.Set_ReviewType(reviewtype_Add);
				}
            }
            else
			{
				Item.AddNewParagraph();
			}
        }
    }
};
// Расширяем документ до точки (X,Y) с помощью новых параграфов
// Y0 - низ последнего параграфа, YLimit - предел страницы
CDocumentContent.prototype.Extend_ToPos                       = function(X, Y)
{
    var LastPara  = this.Content[this.Content.length - 1];
    var LastPara2 = LastPara;

    History.Create_NewPoint(AscDFH.historydescription_Document_DocumentContentExtendToPos);
    History.Set_Additional_ExtendDocumentToPos();

    while (true)
    {
        var NewParagraph = new Paragraph(this.DrawingDocument, this, this.bPresentation === true);
		var NewRun       = new ParaRun(NewParagraph, false);
		NewParagraph.Add_ToContent(0, NewRun);

        var StyleId = LastPara.Style_Get();
        var NextId  = undefined;

        if (undefined != StyleId)
        {
            NextId = this.Styles.Get_Next(StyleId);

            if (null === NextId || undefined === NextId)
                NextId = StyleId;
        }

        // Простое добавление стиля, без дополнительных действий
        if (NextId === this.Styles.Get_Default_Paragraph())
            NewParagraph.Style_Remove();
        else
            NewParagraph.Style_Add(NextId, true);

        if (undefined != LastPara.TextPr.Value.FontSize || undefined !== LastPara.TextPr.Value.RFonts.Ascii)
        {
            var TextPr        = new CTextPr();
            TextPr.FontSize   = LastPara.TextPr.Value.FontSize;
            TextPr.FontSizeCS = LastPara.TextPr.Value.FontSize;
            TextPr.RFonts     = LastPara.TextPr.Value.RFonts.Copy();
            NewParagraph.SelectAll();
            NewParagraph.Apply_TextPr(TextPr);
        }

        LastPara.Set_DocumentNext(NewParagraph);

        NewParagraph.Set_DocumentPrev(LastPara);
        NewParagraph.Set_DocumentIndex(LastPara.Index + 1);

        var CurPage = LastPara.Pages.length - 1;
        var X0      = LastPara.Pages[CurPage].X;
        var Y0      = LastPara.Pages[CurPage].Bounds.Bottom;
        var XLimit  = LastPara.Pages[CurPage].XLimit;
        var YLimit  = LastPara.Pages[CurPage].YLimit;
        var PageNum = LastPara.PageNum;

        NewParagraph.Reset(X0, Y0, XLimit, YLimit, PageNum);
        var RecalcResult = NewParagraph.Recalculate_Page(0);

        if (!(RecalcResult & recalcresult_NextElement))
        {
            LastPara.Next = null;
            break;
        }

        this.Internal_Content_Add(this.Content.length, NewParagraph);

        if (NewParagraph.Pages[0].Bounds.Bottom > Y)
            break;

        LastPara = NewParagraph;
    }

    LastPara = this.Content[this.Content.length - 1];

    if (LastPara != LastPara2 || false === this.LogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_None, {
            Type      : AscCommon.changestype_2_Element_and_Type,
            Element   : LastPara,
            CheckType : AscCommon.changestype_Paragraph_Content
        }))
    {
        // Теперь нам нужно вставить таб по X
        LastPara.Extend_ToPos(X);
    }

    LastPara.MoveCursorToEndPos();
    LastPara.Document_SetThisElementCurrent(true);

    this.LogicDocument.Recalculate();
};
CDocumentContent.prototype.AddInlineImage = function(W, H, Img, Chart, bFlow)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.DrawingObjects.addInlineImage(W, H, Img, Chart, bFlow);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (true == this.Selection.Use)
			this.Remove(1, true);

		var Item = this.Content[this.CurPos.ContentPos];
		if (type_Paragraph == Item.GetType())
		{
			var Drawing;
			if (!AscCommon.isRealObject(Chart))
			{
				Drawing   = new ParaDrawing(W, H, null, this.DrawingDocument, this, null);
				var Image = this.DrawingObjects.createImage(Img, 0, 0, W, H);
				Image.setParent(Drawing);
				Drawing.Set_GraphicObject(Image);
			}
			else
			{
				Drawing   = new ParaDrawing(W, H, null, this.DrawingDocument, this, null);
				var Image = this.DrawingObjects.getChartSpace2(Chart, null);
				Image.setParent(Drawing);
				Drawing.Set_GraphicObject(Image);
				Drawing.setExtent(Image.spPr.xfrm.extX, Image.spPr.xfrm.extY);
			}
			if (true === bFlow)
			{
				Drawing.Set_DrawingType(drawing_Anchor);
				Drawing.Set_WrappingType(WRAPPING_TYPE_SQUARE);
				Drawing.Set_BehindDoc(false);
				Drawing.Set_Distance(3.2, 0, 3.2, 0);
				Drawing.Set_PositionH(Asc.c_oAscRelativeFromH.Column, false, 0, false);
				Drawing.Set_PositionV(Asc.c_oAscRelativeFromV.Paragraph, false, 0, false);
			}
			this.AddToParagraph(Drawing);
			this.Select_DrawingObject(Drawing.Get_Id());
		}
		else
		{
			Item.AddInlineImage(W, H, Img, Chart, bFlow);
		}
	}
};

CDocumentContent.prototype.AddImages = function(aImages){
    if (docpostype_DrawingObjects === this.CurPos.Type)
    {
        return this.DrawingObjects.addImages(aImages);
    }
    else //if ( docpostype_Content === this.CurPos.Type )
    {
        if (true === this.Selection.Use)
            this.Remove(1, true);

        var Item = this.Content[this.CurPos.ContentPos];
        if (type_Paragraph === Item.GetType())
        {
            var Drawing, W, H;
            var ColumnSize = this.LogicDocument.GetColumnSize();
        	for(var i = 0; i < aImages.length; ++i){

                W = Math.max(1, ColumnSize.W);
                H = Math.max(1, ColumnSize.H);

                var _image = aImages[i];
                var __w = Math.max((_image.Image.width * AscCommon.g_dKoef_pix_to_mm), 1);
                var __h = Math.max((_image.Image.height * AscCommon.g_dKoef_pix_to_mm), 1);
                W      = Math.max(5, Math.min(W, __w));
                H      = Math.max(5, Math.min((W * __h / __w)));
                Drawing   = new ParaDrawing(W, H, null, this.DrawingDocument, this, null);
                var Image = this.DrawingObjects.createImage(_image.src, 0, 0, W, H);
                Image.setParent(Drawing);
                Drawing.Set_GraphicObject(Image);
                this.AddToParagraph(Drawing);
			}

			if(aImages.length === 1)
			{
				if(Drawing)
				{
					this.Select_DrawingObject(Drawing.Get_Id());
				}
			}
        }
        else
        {
            Item.AddImages(aImages);
        }
    }
};

CDocumentContent.prototype.AddOleObject = function(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.DrawingObjects.addOleObject(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (true == this.Selection.Use)
			this.Remove(1, true);

		var Item = this.Content[this.CurPos.ContentPos];
		if (type_Paragraph == Item.GetType())
		{
			var Drawing = new ParaDrawing(W, H, null, this.DrawingDocument, this, null);
			var Image   = this.DrawingObjects.createOleObject(Data, sApplicationId, Img, 0, 0, W, H, nWidthPix, nHeightPix);
			Image.setParent(Drawing);
			Drawing.Set_GraphicObject(Image);

			this.AddToParagraph(Drawing);
			this.Select_DrawingObject(Drawing.Get_Id());
		}
		else
		{
			Item.AddOleObject(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId);
		}
	}
};
CDocumentContent.prototype.AddTextArt = function(nStyle)
{
	if (docpostype_DrawingObjects !== this.CurPos.Type)
	{
		var Item = this.Content[this.CurPos.ContentPos];
		if (type_Paragraph == Item.GetType())
		{
			var Drawing = new ParaDrawing(1828800 / 36000, 1828800 / 36000, null, this.DrawingDocument, this, null);
			var TextArt = this.DrawingObjects.createTextArt(nStyle, true);
			TextArt.setParent(Drawing);
			Drawing.Set_GraphicObject(TextArt);
			Drawing.Set_DrawingType(drawing_Anchor);
			Drawing.Set_WrappingType(WRAPPING_TYPE_NONE);
			Drawing.Set_BehindDoc(false);
			Drawing.Set_Distance(3.2, 0, 3.2, 0);
			Drawing.Set_PositionH(Asc.c_oAscRelativeFromH.Column, false, 0, false);
			Drawing.Set_PositionV(Asc.c_oAscRelativeFromV.Paragraph, false, 0, false);
			if (true == this.Selection.Use)
				this.Remove(1, true);
			this.AddToParagraph(Drawing);
			if (TextArt.bSelectedText)
			{
				this.Select_DrawingObject(Drawing.Get_Id());
			}
			else
			{
				var oContent = Drawing.GraphicObj.getDocContent();
				oContent.Content[0].Document_SetThisElementCurrent(false);
				this.LogicDocument.SelectAll();
			}
		}
		else
		{
			Item.AddTextArt(nStyle);
		}
	}
};
CDocumentContent.prototype.AddSignatureLine = function(oSignatureDrawing)
{
	if (docpostype_DrawingObjects !== this.CurPos.Type)
	{
        var Item = this.Content[this.CurPos.ContentPos];
        if (type_Paragraph == Item.GetType())
        {
            var Drawing = oSignatureDrawing;

            if (true == this.Selection.Use)
                this.Remove(1, true);

            this.AddToParagraph(Drawing);
            this.Select_DrawingObject(Drawing.Get_Id());
        }
        else
        {
            Item.AddSignatureLine(oSignatureDrawing);
        }
	}
};
CDocumentContent.prototype.EditChart = function(Chart)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.editChart(Chart);
	}
};
CDocumentContent.prototype.AddInlineTable = function(Cols, Rows)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.addInlineTable(Cols, Rows);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		if (true === this.Selection.Use)
			this.Remove(1, true);

		// Добавляем таблицу
		var Item = this.Content[this.CurPos.ContentPos];

		// Если мы внутри параграфа, тогда разрываем его и на месте разрыва добавляем таблицу.
		// А если мы внутри таблицы, тогда добавляем таблицу внутрь текущей таблицы.
		if (type_Paragraph === Item.GetType())
		{
			// Создаем новую таблицу
			var W = 0;
			if (true === this.IsTableCellContent())
				W = this.XLimit - this.X;
			else
				W = ( this.XLimit - this.X + 2 * 1.9 );

			W = Math.max(W, Cols * 2 * 1.9);

			var Grid = [];

			for (var Index = 0; Index < Cols; Index++)
				Grid[Index] = W / Cols;

			var NewTable = new CTable(this.DrawingDocument, this, true, Rows, Cols, Grid);
			NewTable.Set_ParagraphPrOnAdd(Item);

			// Проверим позицию в текущем параграфе
			if (true === Item.IsCursorAtEnd())
			{
				// Выставляем курсор в начало таблицы
				NewTable.MoveCursorToStartPos();
				this.Internal_Content_Add(this.CurPos.ContentPos + 1, NewTable);
				this.CurPos.ContentPos++;
			}
			else
			{
				// Создаем новый параграф
				var NewParagraph = new Paragraph(this.DrawingDocument, this, this.bPresentation === true);
				Item.Split(NewParagraph);

				// Добавляем новый параграф
				this.Internal_Content_Add(this.CurPos.ContentPos + 1, NewParagraph);

				// Выставляем курсор в начало таблицы
				NewTable.MoveCursorToStartPos();
				this.Internal_Content_Add(this.CurPos.ContentPos + 1, NewTable);

				this.CurPos.ContentPos++;
			}
		}
		else
		{
			Item.AddInlineTable(Cols, Rows);
		}
	}
};
CDocumentContent.prototype.AddToParagraph = function(ParaItem, bRecalculate)
{
	if (true === this.ApplyToAll)
	{
		if (para_TextPr === ParaItem.Type)
		{
			for (var Index = 0; Index < this.Content.length; Index++)
			{
				var Item = this.Content[Index];
				Item.Set_ApplyToAll(true);
				Item.AddToParagraph(ParaItem);
				Item.Set_ApplyToAll(false);
			}
		}

		return;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.paragraphAdd(ParaItem, bRecalculate);
	}
	else // if ( docpostype_Content === this.CurPos.Type )
	{
		if (true === this.Selection.Use)
		{
			var bAddSpace = this.LogicDocument ? this.LogicDocument.Is_WordSelection() : false;
			var Type      = ParaItem.Get_Type();
			switch (Type)
			{
				case para_Math:
				case para_NewLine:
				case para_Text:
				case para_Space:
				case para_Tab:
				case para_PageNum:
				case para_Field:
				case para_FootnoteReference:
				case para_FootnoteRef:
				case para_Separator:
				case para_ContinuationSeparator:
				case para_InstrText:
				{
					// Если у нас что-то заселекчено и мы вводим текст или пробел
					// и т.д., тогда сначала удаляем весь селект.
					this.Remove(1, true, false, true);

					if (true === bAddSpace)
					{
						this.AddToParagraph(new ParaSpace());
						this.MoveCursorLeft(false, false);
					}

					break;
				}
				case para_TextPr:
				{
					switch (this.Selection.Flag)
					{
						case selectionflag_Common:
						{
							// Текстовые настройки применяем ко всем параграфам, попавшим
							// в селект.
							var StartPos = this.Selection.StartPos;
							var EndPos   = this.Selection.EndPos;
							if (EndPos < StartPos)
							{
								var Temp = StartPos;
								StartPos = EndPos;
								EndPos   = Temp;
							}

							for (var Index = StartPos; Index <= EndPos; Index++)
							{
								this.Content[Index].AddToParagraph(ParaItem.Copy());
							}

							if (false != bRecalculate)
							{
								// Если в TextPr только HighLight, тогда не надо ничего пересчитывать, только перерисовываем
								if (true === ParaItem.Value.Check_NeedRecalc())
								{
									this.Recalculate();
								}
								else
								{
									// Просто перерисовываем нужные страницы
									var StartPage = this.Content[StartPos].Get_StartPage_Absolute();
									var EndPage   = this.Content[EndPos].Get_StartPage_Absolute() + this.Content[EndPos].GetPagesCount() - 1;
									this.ReDraw(StartPage, EndPage);
								}
							}

							break;
						}
						case selectionflag_Numbering:
						{
							// Текстовые настройки применяем к конкретной нумерации
							if (!this.Selection.Data || !this.Selection.Data.CurPara)
								break;

							if (undefined != ParaItem.Value.FontFamily)
							{
								var FName  = ParaItem.Value.FontFamily.Name;
								var FIndex = ParaItem.Value.FontFamily.Index;

								ParaItem.Value.RFonts          = new CRFonts();
								ParaItem.Value.RFonts.Ascii    = {Name : FName, Index : FIndex};
								ParaItem.Value.RFonts.EastAsia = {Name : FName, Index : FIndex};
								ParaItem.Value.RFonts.HAnsi    = {Name : FName, Index : FIndex};
								ParaItem.Value.RFonts.CS       = {Name : FName, Index : FIndex};
							}

							var oNumPr = this.Selection.Data.CurPara.GetNumPr();
							var oNum   = this.GetNumbering().GetNum(oNumPr.NumId);
							oNum.ApplyTextPr(oNumPr.Lvl, ParaItem.Value);

							if (false != bRecalculate)
							{
								this.Recalculate();
							}

							break;
						}
					}

					return;
				}
			}
		}

		var Item     = this.Content[this.CurPos.ContentPos];
		var ItemType = Item.GetType();

		if (para_NewLine === ParaItem.Type && true === ParaItem.IsPageOrColumnBreak())
		{
			if (type_Paragraph === ItemType)
			{
				if (true === Item.IsCursorAtBegin())
				{
					this.AddNewParagraph();
					this.Content[this.CurPos.ContentPos - 1].AddToParagraph(ParaItem);
					this.Content[this.CurPos.ContentPos - 1].Clear_Formatting();
				}
				else
				{
					this.AddNewParagraph();
					this.AddNewParagraph();
					this.Content[this.CurPos.ContentPos - 1].AddToParagraph(ParaItem);
					this.Content[this.CurPos.ContentPos - 1].Clear_Formatting();
				}

				if (false != bRecalculate)
				{
					this.Recalculate();

					Item.CurPos.RealX = Item.CurPos.X;
					Item.CurPos.RealY = Item.CurPos.Y;
				}
			}
			else if (type_BlockLevelSdt === Item.GetType())
			{
				Item.AddToParagraph(ParaItem);
			}
			else
			{
				// TODO: PageBreak в таблице не ставим
				return;
			}
		}
		else
		{
			Item.AddToParagraph(ParaItem);

			if (false != bRecalculate)
			{
				if (para_TextPr === ParaItem.Type && false === ParaItem.Value.Check_NeedRecalc())
				{
					// Просто перерисовываем нужные страницы
					var StartPage = Item.Get_StartPage_Absolute();
					var EndPage   = StartPage + Item.GetPagesCount() - 1;
					this.ReDraw(StartPage, EndPage);
				}
				else
				{
					this.Recalculate();
				}

				if (type_Paragraph === ItemType)
				{
					Item.RecalculateCurPos();
					Item.CurPos.RealX = Item.CurPos.X;
					Item.CurPos.RealY = Item.CurPos.Y;
				}
			}
		}
	}
};
CDocumentContent.prototype.ClearParagraphFormatting = function(isClearParaPr, isClearTextPr)
{
	if (false !== isClearParaPr)
		isClearParaPr = true;

	if (false !== isClearTextPr)
		isClearTextPr = true;

	if (true === this.ApplyToAll)
	{
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Item = this.Content[Index];
			Item.Set_ApplyToAll(true);
			Item.ClearParagraphFormatting(isClearParaPr, isClearTextPr);
			Item.Set_ApplyToAll(false);
		}

		return;
	}

	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.paragraphClearFormatting(isClearParaPr, isClearTextPr);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (true === this.Selection.Use)
		{
			if (selectionflag_Common === this.Selection.Flag)
			{
				var StartPos = this.Selection.StartPos;
				var EndPos   = this.Selection.EndPos;
				if (StartPos > EndPos)
				{
					var Temp = StartPos;
					StartPos = EndPos;
					EndPos   = Temp;
				}

				for (var Index = StartPos; Index <= EndPos; Index++)
				{
					var Item = this.Content[Index];
					Item.ClearParagraphFormatting(isClearParaPr, isClearTextPr);
				}
			}
		}
		else
		{
			var Item = this.Content[this.CurPos.ContentPos];
			Item.ClearParagraphFormatting(isClearParaPr, isClearTextPr);
		}
	}
};
CDocumentContent.prototype.Remove = function(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd)
{
	if (true === this.ApplyToAll)
	{
		this.Internal_Content_RemoveAll();
		this.Internal_Content_Add(0, this.private_CreateNewParagraph());

		this.CurPos = {
			X          : 0,
			Y          : 0,
			ContentPos : 0, // в зависимости, от параметра Type: озиция в Document.Content
			RealX      : 0, // позиция курсора, без учета расположения букв
			RealY      : 0, // это актуально для клавиш вверх и вниз
			Type       : docpostype_Content
		};

		this.Selection = {
			Start    : false,
			Use      : false,
			StartPos : 0,
			EndPos   : 0,
			Flag     : selectionflag_Common,
			Data     : null
		};

		return false;
	}

	if (undefined === bRemoveOnlySelection)
		bRemoveOnlySelection = false;

	if (undefined === bOnTextAdd)
		bOnTextAdd = false;

	if (docpostype_DrawingObjects === this.CurPos.Type)
		return this.LogicDocument.DrawingObjects.remove(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd);
	else //if ( docpostype_Content === this.CurPos.Type )
		return this.private_Remove(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd);
};
CDocumentContent.prototype.GetCursorPosXY = function()
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.cursorGetPos();
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (true === this.Selection.Use)
		{
			if (selectionflag_Common === this.Selection.Flag)
			{
				return this.Content[this.Selection.EndPos].GetCursorPosXY();
			}

			return {X : 0, Y : 0};
		}
		else
		{
			return this.Content[this.CurPos.ContentPos].GetCursorPosXY();
		}
	}
};
CDocumentContent.prototype.MoveCursorLeft = function(AddToSelect, Word)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.cursorMoveLeft(AddToSelect, Word);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		var ReturnValue = true;

		this.RemoveNumberingSelection();
		if (true === this.Selection.Use)
		{
			if (true === AddToSelect)
			{
				// Добавляем к селекту
				if (false === this.Content[this.Selection.EndPos].MoveCursorLeft(true, Word))
				{
					// Нужно перейти в конец предыдущего элемента
					if (0 != this.Selection.EndPos)
					{
						this.Selection.EndPos--;
						this.CurPos.ContentPos = this.Selection.EndPos;

						var Item = this.Content[this.Selection.EndPos];
						Item.MoveCursorLeftWithSelectionFromEnd(Word);
					}
					else
					{
						// Сообщаем родительскому классу, что надо выйти из данного элемента
						ReturnValue = false;
					}
				}

				// Проверяем не обнулился ли селект в последнем параграфе. Такое могло быть, если была
				// заселекчена одна буква в последнем параграфе, а мы убрали селект последним действием.
				if (this.Selection.EndPos != this.Selection.StartPos && false === this.Content[this.Selection.EndPos].IsSelectionUse())
				{
					// Такая ситуация возможна только при прямом селекте (сверху вниз), поэтому вычитаем
					this.Selection.EndPos--;
					this.CurPos.ContentPos = this.Selection.EndPos;
				}

				// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
				if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
				{
					this.Selection.Use     = false;
					this.CurPos.ContentPos = this.Selection.EndPos;
				}
			}
			else
			{
				// Нам нужно переместить курсор в левый край селекта, и отменить весь селект
				var Start = this.Selection.StartPos;
				if (Start > this.Selection.EndPos)
					Start = this.Selection.EndPos;

				this.CurPos.ContentPos = Start;
				this.Content[this.CurPos.ContentPos].MoveCursorLeft(false, Word);

				this.RemoveSelection();
			}
		}
		else
		{
			if (true === AddToSelect)
			{
				this.Selection.Use      = true;
				this.Selection.StartPos = this.CurPos.ContentPos;
				this.Selection.EndPos   = this.CurPos.ContentPos;

				if (false === this.Content[this.CurPos.ContentPos].MoveCursorLeft(true, Word))
				{
					// Нужно перейти в конец предыдущего элемент
					if (0 != this.CurPos.ContentPos)
					{
						this.CurPos.ContentPos--;
						this.Selection.EndPos = this.CurPos.ContentPos;

						var Item = this.Content[this.CurPos.ContentPos];
						Item.MoveCursorLeftWithSelectionFromEnd(Word);
					}
					else
					{
						// Сообщаем родительскому классу, что надо выйти из данного элемента
						ReturnValue = false;
					}
				}

				// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
				if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
				{
					this.Selection.Use     = false;
					this.CurPos.ContentPos = this.Selection.EndPos;
				}
			}
			else
			{
				if (false === this.Content[this.CurPos.ContentPos].MoveCursorLeft(false, Word))
				{
					// Нужно перейти в конец предыдущего элемент
					if (0 != this.CurPos.ContentPos)
					{
						this.CurPos.ContentPos--;
						this.Content[this.CurPos.ContentPos].MoveCursorToEndPos(false, false);
					}
					else
					{
						// Сообщаем родительскому классу, что надо выйти из данного элемента
						ReturnValue = false;
					}
				}
			}
		}

		return ReturnValue;
	}
};
CDocumentContent.prototype.MoveCursorLeftWithSelectionFromEnd = function(Word)
{
	this.RemoveSelection();

	if (this.Content.length <= 0)
		return;

	this.Selection.Use      = true;
	this.Selection.Start    = false;
	this.Selection.Data     = null;
	this.Selection.Flag     = selectionflag_Common;
	this.Selection.StartPos = this.Content.length - 1;
	this.Selection.EndPos   = this.Content.length - 1;

	this.Content[this.Content.length - 1].MoveCursorLeftWithSelectionFromEnd(Word);
};
CDocumentContent.prototype.MoveCursorRight = function(AddToSelect, Word, FromPaste)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.cursorMoveRight(AddToSelect, Word);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		var ReturnValue = true;

		this.RemoveNumberingSelection();
		if (true === this.Selection.Use)
		{
			if (true === AddToSelect)
			{
				// Добавляем к селекту
				if (false === this.Content[this.Selection.EndPos].MoveCursorRight(true, Word))
				{
					// Нужно перейти в конец предыдущего элемента
					if (this.Content.length - 1 != this.Selection.EndPos)
					{
						this.Selection.EndPos++;
						this.CurPos.ContentPos = this.Selection.EndPos;

						var Item = this.Content[this.Selection.EndPos];
						Item.MoveCursorRightWithSelectionFromStart(Word);
					}
					else
					{
						// Сообщаем родительскому классу, что надо выйти из данного элемента
						ReturnValue = false;
					}
				}

				// Проверяем не обнулился ли селект в последнем параграфе. Такое могло быть, если была
				// заселекчена одна буква в последнем параграфе, а мы убрали селект последним действием.
				if (this.Selection.EndPos != this.Selection.StartPos && false === this.Content[this.Selection.EndPos].IsSelectionUse())
				{
					// Такая ситуация возможна только при обратном селекте (снизу вверх), поэтому вычитаем
					this.Selection.EndPos++;
					this.CurPos.ContentPos = this.Selection.EndPos;
				}

				// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
				if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
				{
					this.Selection.Use     = false;
					this.CurPos.ContentPos = this.Selection.EndPos;
				}
			}
			else
			{
				// Нам нужно переместить курсор в правый край селекта, и отменить весь селект
				var End = this.Selection.EndPos;
				if (End < this.Selection.StartPos)
					End = this.Selection.StartPos;


				this.CurPos.ContentPos = End;

				if (true === this.Content[this.CurPos.ContentPos].IsSelectionToEnd() && this.CurPos.ContentPos < this.Content.length - 1)
				{
					this.CurPos.ContentPos = End + 1;
					this.Content[this.CurPos.ContentPos].MoveCursorToStartPos(false);
				}
				else
				{
					this.Content[this.CurPos.ContentPos].MoveCursorRight(false, Word);
				}

				this.RemoveSelection();
			}
		}
		else
		{
			if (true === AddToSelect)
			{
				this.Selection.Use      = true;
				this.Selection.StartPos = this.CurPos.ContentPos;
				this.Selection.EndPos   = this.CurPos.ContentPos;

				if (false === this.Content[this.CurPos.ContentPos].MoveCursorRight(true, Word))
				{
					// Нужно перейти в конец предыдущего элемента
					if (this.Content.length - 1 != this.CurPos.ContentPos)
					{
						this.CurPos.ContentPos++;
						this.Selection.EndPos = this.CurPos.ContentPos;

						var Item = this.Content[this.CurPos.ContentPos];
						Item.MoveCursorRightWithSelectionFromStart(Word);
					}
					else
					{
						// Сообщаем родительскому классу, что надо выйти из данного элемента
						ReturnValue = false;
					}
				}

				// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
				if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
				{
					this.Selection.Use     = false;
					this.CurPos.ContentPos = this.Selection.EndPos;
				}
			}
			else
			{
				if (false === this.Content[this.CurPos.ContentPos].MoveCursorRight(false, Word))
				{
					// Нужно перейти в начало следующего элемента
					if (this.Content.length - 1 != this.CurPos.ContentPos)
					{
						this.CurPos.ContentPos++;
						this.Content[this.CurPos.ContentPos].MoveCursorToStartPos(false);
					}
					else
					{
						// Сообщаем родительскому классу, что надо выйти из данного элемента
						ReturnValue = false;
					}
				}
			}
		}

		return ReturnValue;
	}
};
CDocumentContent.prototype.MoveCursorRightWithSelectionFromStart = function(Word)
{
	this.RemoveSelection();

	if (this.Content.length <= 0)
		return;

	this.Selection.Use      = true;
	this.Selection.Start    = false;
	this.Selection.Data     = null;
	this.Selection.Flag     = selectionflag_Common;
	this.Selection.StartPos = 0;
	this.Selection.EndPos   = 0;

	this.Content[0].MoveCursorRightWithSelectionFromStart(Word);
};
CDocumentContent.prototype.MoveCursorUp = function(AddToSelect)
{
	if (docpostype_DrawingObjects == this.CurPos.Type)
		return this.LogicDocument.DrawingObjects.cursorMoveUp(AddToSelect);
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		var ReturnValue = true;

		this.RemoveNumberingSelection();
		if (true === this.Selection.Use)
		{
			if (true === AddToSelect)
			{
				var SelectDirection = this.Selection.StartPos === this.Selection.EndPos ? 0 : this.Selection.StartPos < this.Selection.EndPos ? 1 : -1;

				var Item = this.Content[this.Selection.EndPos];
				if (false === Item.MoveCursorUp(true))
				{
					if (0 != this.Selection.EndPos)
					{
						var TempXY        = Item.GetCurPosXY();
						this.CurPos.RealX = TempXY.X;
						this.CurPos.RealY = TempXY.Y;

						if (1 === SelectDirection)
							Item.RemoveSelection();

						this.Selection.EndPos--;
						Item = this.Content[this.Selection.EndPos];
						Item.MoveCursorUpToLastRow(this.CurPos.RealX, this.CurPos.RealY, true);
					}
					else
					{
						// Сообщаем родительскому классу, что надо выйти из данного элемента
						ReturnValue = false;
					}
				}

				// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
				if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
					this.Selection.Use = false;

				this.CurPos.ContentPos = this.Selection.EndPos;
			}
			else
			{
				// Мы должны переместиться на строку выше, чем начало селекта
				var Start = this.Selection.StartPos;
				if (Start > this.Selection.EndPos)
					Start = this.Selection.EndPos;

				this.CurPos.ContentPos = Start;

				var Item = this.Content[this.CurPos.ContentPos];
				if (false === this.Content[this.CurPos.ContentPos].MoveCursorUp(false))
				{
					if (0 != this.CurPos.ContentPos)
					{
						var TempXY        = Item.GetCurPosXY();
						this.CurPos.RealX = TempXY.X;
						this.CurPos.RealY = TempXY.Y;

						this.CurPos.ContentPos--;
						Item = this.Content[this.CurPos.ContentPos];
						Item.MoveCursorUpToLastRow(this.CurPos.RealX, this.CurPos.RealY, false);
					}
					else
					{
						// Сообщаем родительскому классу, что надо выйти из данного элемента
						ReturnValue = false;
					}
				}

				this.RemoveSelection();
			}
		}
		else
		{
			if (true === AddToSelect)
			{
				this.Selection.Use      = true;
				this.Selection.StartPos = this.CurPos.ContentPos;
				this.Selection.EndPos   = this.CurPos.ContentPos;

				var Item = this.Content[this.CurPos.ContentPos];
				if (false === Item.MoveCursorUp(true))
				{
					if (0 != this.CurPos.ContentPos)
					{
						var TempXY        = Item.GetCurPosXY();
						this.CurPos.RealX = TempXY.X;
						this.CurPos.RealY = TempXY.Y;

						this.CurPos.ContentPos--;
						Item = this.Content[this.CurPos.ContentPos];
						Item.MoveCursorUpToLastRow(this.CurPos.RealX, this.CurPos.RealY, true);
						this.Selection.EndPos = this.CurPos.ContentPos;
					}
					else
					{
						// Сообщаем родительскому классу, что надо выйти из данного элемента
						ReturnValue = false;
					}
				}

				// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
				if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
					this.Selection.Use = false;

				this.CurPos.ContentPos = this.Selection.EndPos;
			}
			else
			{
				var Item = this.Content[this.CurPos.ContentPos];
				if (false === Item.MoveCursorUp(false))
				{
					if (0 != this.CurPos.ContentPos)
					{
						var TempXY        = Item.GetCurPosXY();
						this.CurPos.RealX = TempXY.X;
						this.CurPos.RealY = TempXY.Y;

						this.CurPos.ContentPos--;
						Item = this.Content[this.CurPos.ContentPos];
						Item.MoveCursorUpToLastRow(this.CurPos.RealX, this.CurPos.RealY, false);
					}
					else
					{
						// Сообщаем родительскому классу, что надо выйти из данного элемента
						ReturnValue = false;
					}
				}
			}
		}

		return ReturnValue;
	}
};
CDocumentContent.prototype.MoveCursorDown = function(AddToSelect)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
		return this.LogicDocument.DrawingObjects.cursorMoveDown(AddToSelect);
	else if (docpostype_Content === this.CurPos.Type)
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		var ReturnValue = true;
		this.RemoveNumberingSelection();

		if (true === this.Selection.Use)
		{
			if (true === AddToSelect)
			{
				var SelectDirection = this.Selection.StartPos === this.Selection.EndPos ? 0 : this.Selection.StartPos < this.Selection.EndPos ? 1 : -1;

				var Item = this.Content[this.Selection.EndPos];
				if (false === Item.MoveCursorDown(true))
				{
					if (this.Content.length - 1 != this.Selection.EndPos)
					{
						var TempXY        = Item.GetCurPosXY();
						this.CurPos.RealX = TempXY.X;
						this.CurPos.RealY = TempXY.Y;

						if (-1 === SelectDirection)
							Item.RemoveSelection();

						this.Selection.EndPos++;
						Item = this.Content[this.Selection.EndPos];
						Item.MoveCursorDownToFirstRow(this.CurPos.RealX, this.CurPos.RealY, true);
					}
					else
					{
						// Сообщаем родительскому классу, что надо выйти из данного элемента
						ReturnValue = false;
					}
				}

				// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
				if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
					this.Selection.Use = false;

				this.CurPos.ContentPos = this.Selection.EndPos;
			}
			else
			{
				// Мы должны переместиться на строку ниже, чем конец селекта
				var End = this.Selection.EndPos;
				if (End < this.Selection.StartPos)
					End = this.Selection.StartPos;

				this.CurPos.ContentPos = End;

				var Item = this.Content[this.CurPos.ContentPos];
				if (false === this.Content[this.CurPos.ContentPos].MoveCursorDown(false))
				{
					if (this.Content.length - 1 != this.CurPos.ContentPos)
					{
						var TempXY        = Item.GetCurPosXY();
						this.CurPos.RealX = TempXY.X;
						this.CurPos.RealY = TempXY.Y;

						this.CurPos.ContentPos++;
						Item = this.Content[this.CurPos.ContentPos];
						Item.MoveCursorDownToFirstRow(this.CurPos.RealX, this.CurPos.RealY, false);
					}
					else
					{
						// Сообщаем родительскому классу, что надо выйти из данного элемента
						ReturnValue = false;
					}
				}

				this.RemoveSelection();
			}
		}
		else
		{
			if (true === AddToSelect)
			{
				this.Selection.Use      = true;
				this.Selection.StartPos = this.CurPos.ContentPos;
				this.Selection.EndPos   = this.CurPos.ContentPos;

				var Item = this.Content[this.CurPos.ContentPos];
				if (false === Item.MoveCursorDown(true))
				{
					if (this.Content.length - 1 != this.CurPos.ContentPos)
					{
						var TempXY        = Item.GetCurPosXY();
						this.CurPos.RealX = TempXY.X;
						this.CurPos.RealY = TempXY.Y;

						this.CurPos.ContentPos++;
						Item = this.Content[this.CurPos.ContentPos];
						Item.MoveCursorDownToFirstRow(this.CurPos.RealX, this.CurPos.RealY, true);
						this.Selection.EndPos = this.CurPos.ContentPos;
					}
					else
					{
						// Сообщаем родительскому классу, что надо выйти из данного элемента
						ReturnValue = false;
					}
				}

				// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
				if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
					this.Selection.Use = false;

				this.CurPos.ContentPos = this.Selection.EndPos;
			}
			else
			{
				var Item = this.Content[this.CurPos.ContentPos];

				if (false === Item.MoveCursorDown(AddToSelect))
				{
					if (this.Content.length - 1 != this.CurPos.ContentPos)
					{
						var TempXY        = Item.GetCurPosXY();
						this.CurPos.RealX = TempXY.X;
						this.CurPos.RealY = TempXY.Y;

						this.CurPos.ContentPos++;
						Item = this.Content[this.CurPos.ContentPos];
						Item.MoveCursorDownToFirstRow(this.CurPos.RealX, this.CurPos.RealY, false);
					}
					else
					{
						// Сообщаем родительскому классу, что надо выйти из данного элемента
						ReturnValue = false;
					}
				}
			}
		}

		return ReturnValue;
	}
};
CDocumentContent.prototype.MoveCursorToEndOfLine = function(AddToSelect)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
		return this.LogicDocument.DrawingObjects.cursorMoveEndOfLine(AddToSelect);
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		this.RemoveNumberingSelection();
		if (true === this.Selection.Use)
		{
			if (true === AddToSelect)
			{
				var Item = this.Content[this.Selection.EndPos];
				Item.MoveCursorToEndOfLine(AddToSelect);

				// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
				if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
				{
					this.Selection.Use     = false;
					this.CurPos.ContentPos = this.Selection.EndPos;
				}
			}
			else
			{
				var Pos                = ( this.Selection.EndPos >= this.Selection.StartPos ? this.Selection.EndPos : this.Selection.StartPos );
				this.CurPos.ContentPos = Pos;

				var Item = this.Content[Pos];
				Item.MoveCursorToEndOfLine(AddToSelect);

				this.RemoveSelection();
			}
		}
		else
		{
			if (true === AddToSelect)
			{
				this.Selection.Use      = true;
				this.Selection.StartPos = this.CurPos.ContentPos;
				this.Selection.EndPos   = this.CurPos.ContentPos;

				var Item = this.Content[this.CurPos.ContentPos];
				Item.MoveCursorToEndOfLine(AddToSelect);

				// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
				if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
				{
					this.Selection.Use     = false;
					this.CurPos.ContentPos = this.Selection.EndPos;
				}
			}
			else
			{
				var Item = this.Content[this.CurPos.ContentPos];
				Item.MoveCursorToEndOfLine(AddToSelect);
			}
		}
	}
};
CDocumentContent.prototype.MoveCursorToStartOfLine = function(AddToSelect)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
		return this.LogicDocument.DrawingObjects.cursorMoveStartOfLine(AddToSelect);
	else // if( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		this.RemoveNumberingSelection();
		if (true === this.Selection.Use)
		{
			if (true === AddToSelect)
			{
				var Item = this.Content[this.Selection.EndPos];
				Item.MoveCursorToStartOfLine(AddToSelect);

				// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
				if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
				{
					this.Selection.Use     = false;
					this.CurPos.ContentPos = this.Selection.EndPos;
				}
			}
			else
			{
				var Pos                = ( this.Selection.StartPos <= this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos );
				this.CurPos.ContentPos = Pos;

				var Item = this.Content[Pos];
				Item.MoveCursorToStartOfLine(AddToSelect);

				this.RemoveSelection();
			}
		}
		else
		{
			if (true === AddToSelect)
			{
				this.Selection.Use      = true;
				this.Selection.StartPos = this.CurPos.ContentPos;
				this.Selection.EndPos   = this.CurPos.ContentPos;

				var Item = this.Content[this.CurPos.ContentPos];
				Item.MoveCursorToStartOfLine(AddToSelect);

				// Проверяем не обнулился ли селект (т.е. ничего не заселекчено)
				if (this.Selection.StartPos == this.Selection.EndPos && false === this.Content[this.Selection.StartPos].IsSelectionUse())
				{
					this.Selection.Use     = false;
					this.CurPos.ContentPos = this.Selection.EndPos;
				}
			}
			else
			{
				var Item = this.Content[this.CurPos.ContentPos];
				Item.MoveCursorToStartOfLine(AddToSelect);
			}
		}
	}
};
CDocumentContent.prototype.MoveCursorToXY = function(X, Y, AddToSelect, bRemoveOldSelection, CurPage)
{
	if (this.Pages.length <= 0)
		return;

	if (undefined !== CurPage)
	{
		if (CurPage < 0)
		{
			CurPage = 0;
			Y       = 0;
		}
		else if (CurPage >= this.Pages.length)
		{
			CurPage = this.Pages.length - 1;
			Y       = this.Pages[CurPage].YLimit;
		}

		this.CurPage = CurPage;
	}

	if (false != bRemoveOldSelection)
	{
		this.RemoveNumberingSelection();
	}

	if (true === this.Selection.Use)
	{
		if (true === AddToSelect)
		{
			var oMouseEvent  = new AscCommon.CMouseEventHandler();
			oMouseEvent.Type = AscCommon.g_mouse_event_type_up;
			this.Selection_SetEnd(X, Y, this.CurPage, oMouseEvent);
		}
		else
		{
			this.RemoveSelection();

			var ContentPos         = this.Internal_GetContentPosByXY(X, Y);
			this.CurPos.ContentPos = ContentPos;
			var ElementPageIndex   = this.private_GetElementPageIndexByXY(ContentPos, X, Y, this.CurPage);
			this.Content[ContentPos].MoveCursorToXY(X, Y, false, false, ElementPageIndex);

			this.Interface_Update_ParaPr();
			this.Interface_Update_TextPr();
		}
	}
	else
	{
		if (true === AddToSelect)
		{
			this.StartSelectionFromCurPos();
			var oMouseEvent  = new AscCommon.CMouseEventHandler();
			oMouseEvent.Type = AscCommon.g_mouse_event_type_up;
			this.Selection_SetEnd(X, Y, this.CurPage, oMouseEvent);
		}
		else
		{
			var ContentPos         = this.Internal_GetContentPosByXY(X, Y);
			this.CurPos.ContentPos = ContentPos;
			var ElementPageIndex   = this.private_GetElementPageIndexByXY(ContentPos, X, Y, this.CurPage);
			this.Content[ContentPos].MoveCursorToXY(X, Y, false, false, ElementPageIndex);

			this.Interface_Update_ParaPr();
			this.Interface_Update_TextPr();
		}
	}
};
CDocumentContent.prototype.IsCursorAtBegin = function(bOnlyPara)
{
	if (undefined === bOnlyPara)
		bOnlyPara = false;

	if (true === bOnlyPara && true != this.Is_CurrentElementParagraph())
		return false;

	if (docpostype_DrawingObjects === this.CurPos.Type)
		return false;
	else if (false != this.Selection.Use || 0 != this.CurPos.ContentPos)
		return false;

	var Item = this.Content[0];
	return Item.IsCursorAtBegin();
};
CDocumentContent.prototype.IsCursorAtEnd = function()
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
		return false;
	else if (false != this.Selection.Use || 0 != this.CurPos.ContentPos)
		return false;

	var Item = this.Content[this.Content.length - 1];
	return Item.IsCursorAtEnd();
};
CDocumentContent.prototype.GetCurPosXY = function()
{
	return {X : this.CurPos.RealX, Y : this.CurPos.RealY};
};
CDocumentContent.prototype.SetCurPosXY = function(X, Y)
{
	this.CurPos.RealX = X;
	this.CurPos.RealY = Y;
};
CDocumentContent.prototype.IsSelectionUse = function()
{
	if (docpostype_DrawingObjects === this.Get_DocPosType())
		return this.DrawingObjects.isSelectionUse();

	if (true === this.Selection.Use)
		return true;

	return false;
};
CDocumentContent.prototype.IsSelectionToEnd = function()
{
	if (true !== this.Selection.Use)
		return false;

	if ((this.Selection.StartPos === this.Content.length - 1 || this.Selection.EndPos === this.Content.length - 1) && true === this.Content[this.Content.length - 1].IsSelectionToEnd())
		return true;

	return false;
};
CDocumentContent.prototype.IsTextSelectionUse = function()
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
		return this.LogicDocument.DrawingObjects.isTextSelectionUse();

	return this.IsSelectionUse();
};
/**
 * Возвращаем выделенный текст, если в выделении не более 1 параграфа, и там нет картинок, нумерации страниц и т.д.
 * @param bClearText
 * @param oPr
 * @returns {?string}
 */
CDocumentContent.prototype.GetSelectedText = function(bClearText, oPr)
{
	if (true === this.ApplyToAll)
	{
		if (true === bClearText && this.Content.length <= 1)
		{
			this.Content[0].Set_ApplyToAll(true);
			var ResultText = this.Content[0].GetSelectedText(true, oPr);
			this.Content[0].Set_ApplyToAll(false);
			return ResultText;
		}
		else if (true != bClearText)
		{
			var ResultText = "";
			var Count      = this.Content.length;
			for (var Index = 0; Index < Count; Index++)
			{
				this.Content[Index].Set_ApplyToAll(true);
				ResultText += this.Content[Index].GetSelectedText(false, oPr);
				this.Content[Index].Set_ApplyToAll(false);
			}

			return ResultText;
		}
	}
	else
	{
		if (docpostype_DrawingObjects === this.CurPos.Type)
			return this.LogicDocument.DrawingObjects.getSelectedText(bClearText, oPr);

		// Либо у нас нет выделения, либо выделение внутри одного элемента
		if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && selectionflag_Common === this.Selection.Flag ) || false === this.Selection.Use ))
		{
			if (true === bClearText && (this.Selection.StartPos === this.Selection.EndPos || false === this.Selection.Use ))
			{
				var Pos = ( true == this.Selection.Use ? this.Selection.StartPos : this.CurPos.ContentPos );
				return this.Content[Pos].GetSelectedText(true, oPr);
			}
			else if (false === bClearText)
			{
				var StartPos = ( true == this.Selection.Use ? Math.min(this.Selection.StartPos, this.Selection.EndPos) : this.CurPos.ContentPos );
				var EndPos   = ( true == this.Selection.Use ? Math.max(this.Selection.StartPos, this.Selection.EndPos) : this.CurPos.ContentPos );

				var ResultText = "";

				for (var Index = StartPos; Index <= EndPos; Index++)
				{
					ResultText += this.Content[Index].GetSelectedText(false, oPr);
				}

				return ResultText;
			}
		}
	}

	return null;
};
CDocumentContent.prototype.GetSelectedElementsInfo = function(Info)
{
	if (true === this.ApplyToAll)
	{
		var Count = this.Content.length;
		if (Count > 1)
			Info.Set_MixedSelection();
		else if (Count === 1)
			this.Content[0].GetSelectedElementsInfo(Info);
	}
	else
	{
		if (docpostype_DrawingObjects === this.CurPos.Type)
			this.LogicDocument.DrawingObjects.getSelectedElementsInfo(Info);
		else //if ( docpostype_Content == this.CurPos.Type )
		{
			if (selectionflag_Numbering === this.Selection.Flag)
			{
				if (this.Selection.Data && this.Selection.Data.CurPara)
				{
					this.Selection.Data.CurPara.GetSelectedElementsInfo(Info);
				}
			}
			else
			{
				if (true === this.Selection.Use)
				{
					if (this.Selection.StartPos != this.Selection.EndPos)
						Info.Set_MixedSelection();
					else
					{
						this.Content[this.Selection.StartPos].GetSelectedElementsInfo(Info);
					}
				}
				else
				{
					this.Content[this.CurPos.ContentPos].GetSelectedElementsInfo(Info);
				}
			}
		}
	}
};
CDocumentContent.prototype.GetSelectedContent = function(SelectedContent)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.DrawingObjects.GetSelectedContent(SelectedContent);
	}
	else
	{
		if (true !== this.Selection.Use || this.Selection.Flag !== selectionflag_Common)
			return;

		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (StartPos > EndPos)
		{
			StartPos = this.Selection.EndPos;
			EndPos   = this.Selection.StartPos;
		}

		for (var Index = StartPos; Index <= EndPos; Index++)
		{
			this.Content[Index].GetSelectedContent(SelectedContent);
		}
	}
};
CDocumentContent.prototype.Insert_Content                     = function(SelectedContent, NearPos)
{
    var Para        = NearPos.Paragraph;
    var ParaNearPos = Para.Get_ParaNearestPos(NearPos);
    var LastClass   = ParaNearPos.Classes[ParaNearPos.Classes.length - 1];
    if (para_Math_Run === LastClass.Type)
    {
        var MathRun        = LastClass;
        var NewMathRun     = MathRun.Split(ParaNearPos.NearPos.ContentPos, ParaNearPos.Classes.length - 1);
        var MathContent    = ParaNearPos.Classes[ParaNearPos.Classes.length - 2];
        var MathContentPos = ParaNearPos.NearPos.ContentPos.Data[ParaNearPos.Classes.length - 2];
        var Element        = SelectedContent.Elements[0].Element;

        var InsertMathContent = null;
        for (var nPos = 0, nParaLen = Element.Content.length; nPos < nParaLen; nPos++)
        {
            if (para_Math === Element.Content[nPos].Type)
            {
                InsertMathContent = Element.Content[nPos];
                break;
            }
        }

        if (null !== InsertMathContent)
        {
            MathContent.Add_ToContent(MathContentPos + 1, NewMathRun);
            MathContent.Insert_MathContent(InsertMathContent.Root, MathContentPos + 1, true);
        }
    }
    else if (para_Run === LastClass.Type)
    {
        var Elements = SelectedContent.Elements;

        var Para     = NearPos.Paragraph;
        // Сначала найдем номер элемента, начиная с которого мы будем производить вставку
        var DstIndex = -1;
        var Count    = this.Content.length;
        for (var Index = 0; Index < Count; Index++)
        {
            if (this.Content[Index] === Para)
            {
                DstIndex = Index;
                break;
            }
        }

        if (-1 === DstIndex)
            return;

        var bNeedSelect = true;

        var Elements      = SelectedContent.Elements;
        var ElementsCount = Elements.length;
        var FirstElement  = SelectedContent.Elements[0];
        if (1 === ElementsCount && true !== FirstElement.SelectedAll && type_Paragraph === FirstElement.Element.GetType())
        {
            // Нам нужно в заданный параграф вставить выделенный текст
            var NewPara          = FirstElement.Element;
            var NewElementsCount = NewPara.Content.length - 1; // Последний ран с para_End не добавляем

            var NewElement = LastClass.Split(ParaNearPos.NearPos.ContentPos, ParaNearPos.Classes.length - 1);
            var PrevClass  = ParaNearPos.Classes[ParaNearPos.Classes.length - 2];
            var PrevPos    = ParaNearPos.NearPos.ContentPos.Data[ParaNearPos.Classes.length - 2];

            PrevClass.Add_ToContent(PrevPos + 1, NewElement);

            // TODO: Заглушка для переноса автофигур и картинок. Когда разрулим ситуацию так, чтобы когда у нас
            //       в текста была выделена автофигура выделение шло для автофигур, тогда здесь можно будет убрать.
            bNeedSelect = (true === SelectedContent.MoveDrawing ? false : true);

            for (var Index = 0; Index < NewElementsCount; Index++)
            {
                var Item = NewPara.Content[Index];
                PrevClass.Add_ToContent(PrevPos + 1 + Index, Item);

                if (true === bNeedSelect)
                    Item.SelectAll();
            }

            if (true === bNeedSelect)
            {
                PrevClass.Selection.Use      = true;
                PrevClass.Selection.StartPos = PrevPos + 1;
                PrevClass.Selection.EndPos   = PrevPos + 1 + NewElementsCount - 1;

                for (var Index = 0; Index < ParaNearPos.Classes.length - 2; Index++)
                {
                    var Class    = ParaNearPos.Classes[Index];
                    var ClassPos = ParaNearPos.NearPos.ContentPos.Data[Index];

                    Class.Selection.Use      = true;
                    Class.Selection.StartPos = ClassPos;
                    Class.Selection.EndPos   = ClassPos;
                }

                this.Selection.Use      = true;
                this.Selection.StartPos = DstIndex;
                this.Selection.EndPos   = DstIndex;
            }

            if (PrevClass.Correct_Content)
            {
                PrevClass.Correct_Content();
            }
        }
		else if (Asc.c_oSpecialPasteProps.overwriteCells === SelectedContent.InsertOptions.Table && 1 === ElementsCount && type_Table === FirstElement.Element.GetType() && this.Parent && this.Parent instanceof CTableCell)
		{
			return this.Parent.InsertTableContent(FirstElement.Element);
		}
        else
        {
            var bConcatS   = ( type_Paragraph !== Elements[0].Element.GetType() ? false : true );
            var bConcatE   = ( type_Paragraph !== Elements[ElementsCount - 1].Element.GetType() || true === Elements[ElementsCount - 1].SelectedAll ? false : true );
            var ParaS      = Para;
            var ParaE      = Para;
            var ParaEIndex = DstIndex;

            // Нам надо разделить наш параграф в заданной позиции, если позиция в
            // начале или конце параграфа, тогда делить не надо
            Para.Cursor_MoveToNearPos(NearPos);
            Para.RemoveSelection();

            var bAddEmptyPara = false;

            if (true === Para.IsCursorAtEnd())
            {
                bConcatE = false;

                if (1 === ElementsCount && type_Paragraph === FirstElement.Element.GetType() && ( true === FirstElement.Element.Is_Empty() || true == FirstElement.SelectedAll ))
                {
                    bConcatS = false;

                    if (type_Paragraph !== this.Content[DstIndex].Get_Type() || true !== this.Content[DstIndex].Is_Empty())
                        DstIndex++;
                }
                else if (true === Elements[ElementsCount - 1].SelectedAll && true === bConcatS)
                    bAddEmptyPara = true;
            }
            else if (true === Para.IsCursorAtBegin())
            {
                bConcatS = false;
            }
            else
            {
                // Создаем новый параграф
                var NewParagraph = new Paragraph(this.DrawingDocument, this, this.bPresentation === true);
                Para.Split(NewParagraph);
                this.Internal_Content_Add(DstIndex + 1, NewParagraph);

                ParaE      = NewParagraph;
                ParaEIndex = DstIndex + 1;
            }

            var NewEmptyPara = null;
            if (true === bAddEmptyPara && true !== SelectedContent.DoNotAddEmptyPara)
            {
                // Создаем новый параграф
				NewEmptyPara = new Paragraph(this.DrawingDocument, this, this.bPresentation === true);
				NewEmptyPara.Set_Pr(ParaS.Pr);
				NewEmptyPara.TextPr.Apply_TextPr(ParaS.TextPr.Value);
                this.Internal_Content_Add(DstIndex + 1, NewEmptyPara);
            }

            var StartIndex = 0;
            if (true === bConcatS)
            {
                // Вызываем так, чтобы выделить все внутренние элементы
                var _ParaS = Elements[0].Element;
                _ParaS.SelectAll();
                var _ParaSContentLen = _ParaS.Content.length;

                // Если мы присоединяем новый параграф, то и копируем все настройки параграфа (так делает Word)
                ParaS.Concat(Elements[0].Element);
                ParaS.Set_Pr(Elements[0].Element.Pr);
                ParaS.TextPr.Clear_Style();
                ParaS.TextPr.Apply_TextPr(Elements[0].Element.TextPr.Value);

                StartIndex++;

                ParaS.Selection.Use      = true;
                ParaS.Selection.StartPos = ParaS.Content.length - _ParaSContentLen;
                ParaS.Selection.EndPos   = ParaS.Content.length - 1;
            }

            var EndIndex = ElementsCount - 1;
            if (true === bConcatE)
            {
                var _ParaE    = Elements[ElementsCount - 1].Element;
                var TempCount = _ParaE.Content.length - 1;

                _ParaE.SelectAll();
                _ParaE.Concat(ParaE);
                _ParaE.Set_Pr(ParaE.Pr);

                this.Internal_Content_Add(ParaEIndex, _ParaE);
                this.Internal_Content_Remove(ParaEIndex + 1, 1);

                _ParaE.Selection.Use      = true;
                _ParaE.Selection.StartPos = 0;
                _ParaE.Selection.EndPos   = TempCount;

                EndIndex--;
            }


            for (var Index = StartIndex; Index <= EndIndex; Index++)
            {
                this.Internal_Content_Add(DstIndex + Index, Elements[Index].Element);
                this.Content[DstIndex + Index].SelectAll();
            }

			var LastPos = DstIndex + ElementsCount - 1;
			if (NewEmptyPara && NewEmptyPara === this.Content[LastPos + 1])
			{
				LastPos++;
				this.Content[LastPos].SelectAll();
			}
			else if (LastPos + 1 < this.Content.length && false === bConcatE && type_Paragraph === this.Content[LastPos + 1].Get_Type())
			{
				LastPos++;
				this.Content[LastPos].Selection.Use = true;
				this.Content[LastPos].Selection_SetBegEnd(true, true);
				this.Content[LastPos].Selection_SetBegEnd(false, true);
			}

            this.Selection.Start    = false;
            this.Selection.Use      = true;
            this.Selection.StartPos = DstIndex;
            this.Selection.EndPos   = LastPos;
			this.CurPos.ContentPos  = LastPos;
        }

        if (true === bNeedSelect)
            this.Parent.Set_CurrentElement(false, this.Get_StartPage_Absolute(), this);
        else if (null !== this.LogicDocument && docpostype_HdrFtr === this.LogicDocument.CurPos.Type)
        {
            this.Parent.Set_CurrentElement(false, this.Get_StartPage_Absolute(), this);
            var DocContent = this;
            var HdrFtr     = this.IsHdrFtr(true);
            if (null !== HdrFtr)
                DocContent = HdrFtr.Content;

            DocContent.Set_DocPosType(docpostype_DrawingObjects);
            DocContent.Selection.Use   = true;
            DocContent.Selection.Start = false;
        }
    }
};
CDocumentContent.prototype.SetParagraphAlign = function(Align)
{
	if (true === this.ApplyToAll)
	{
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Item = this.Content[Index];
			Item.Set_ApplyToAll(true);
			Item.SetParagraphAlign(Align);
			Item.Set_ApplyToAll(false);
		}

		return;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.setParagraphAlign(Align);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		if (true === this.Selection.Use)
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (EndPos < StartPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;
			}

			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				var Item = this.Content[Index];
				Item.SetParagraphAlign(Align);
			}
		}
		else
		{
			this.Content[this.CurPos.ContentPos].SetParagraphAlign(Align);
		}
	}
};
CDocumentContent.prototype.SetParagraphDefaultTabSize = function(TabSize)
{
	if (true === this.ApplyToAll)
	{
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Item = this.Content[Index];
			Item.Set_ApplyToAll(true);
			Item.SetParagraphDefaultTabSize(TabSize);
			Item.Set_ApplyToAll(false);
		}

		return;
	}

	if (this.CurPos.ContentPos < 0)
		return false;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (EndPos < StartPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		for (var Index = StartPos; Index <= EndPos; Index++)
		{
			var Item = this.Content[Index];
			Item.SetParagraphDefaultTabSize(TabSize);
		}
	}
	else
	{
		this.Content[this.CurPos.ContentPos].SetParagraphDefaultTabSize(TabSize);
	}
};
CDocumentContent.prototype.SetParagraphSpacing = function(Spacing)
{
	if (true === this.ApplyToAll)
	{
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Item = this.Content[Index];
			Item.Set_ApplyToAll(true);
			Item.SetParagraphSpacing(Spacing);
			Item.Set_ApplyToAll(false);
		}

		return;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.setParagraphSpacing(Spacing);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		if (true === this.Selection.Use)
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (EndPos < StartPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;
			}

			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				var Item = this.Content[Index];
				Item.SetParagraphSpacing(Spacing);
			}
		}
		else
		{
			this.Content[this.CurPos.ContentPos].SetParagraphSpacing(Spacing);
		}
	}
};
CDocumentContent.prototype.SetParagraphIndent = function(Ind)
{
	if (true === this.ApplyToAll)
	{
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Item = this.Content[Index];
			Item.Set_ApplyToAll(true);
			Item.SetParagraphIndent(Ind);
			Item.Set_ApplyToAll(false);
		}

		return;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.setParagraphIndent(Ind);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		if (true === this.Selection.Use)
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (EndPos < StartPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;
			}

			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				var Item = this.Content[Index];
				Item.SetParagraphIndent(Ind);
			}
		}
		else
		{
			var Item = this.Content[this.CurPos.ContentPos];
			Item.SetParagraphIndent(Ind);
		}
	}
};
CDocumentContent.prototype.Set_ParagraphPresentationNumbering = function(Bullet)
{
    if (true === this.ApplyToAll)
    {
        for (var Index = 0; Index < this.Content.length; Index++)
        {
            this.Content[Index].Add_PresentationNumbering(Bullet);
        }
        return;
    }

    if (this.CurPos.ContentPos < 0)
        return false;

    if (true === this.Selection.Use)
    {
        var StartPos = this.Selection.StartPos;
        var EndPos   = this.Selection.EndPos;
        if (EndPos < StartPos)
        {
            var Temp = StartPos;
            StartPos = EndPos;
            EndPos   = Temp;
        }

        for (var Index = StartPos; Index <= EndPos; Index++)
        {
            this.Content[Index].Add_PresentationNumbering(Bullet);
        }
        this.Recalculate();
        return;
    }
    this.Content[this.CurPos.ContentPos].Add_PresentationNumbering(Bullet);
    this.Recalculate();
};
CDocumentContent.prototype.Can_IncreaseParagraphLevel         = function(bIncrease)
{
    if (true === this.ApplyToAll)
    {
        for (var Index = 0; Index < this.Content.length; Index++)
        {
            if (!this.Content[Index].Can_IncreaseLevel(bIncrease))
                return false;
        }
        return true;
    }

    if (this.CurPos.ContentPos < 0)
        return false;

    if (true === this.Selection.Use)
    {
        var StartPos = this.Selection.StartPos;
        var EndPos   = this.Selection.EndPos;
        if (EndPos < StartPos)
        {
            var Temp = StartPos;
            StartPos = EndPos;
            EndPos   = Temp;
        }

        for (var Index = StartPos; Index <= EndPos; Index++)
        {
            if (!this.Content[Index].Can_IncreaseLevel(bIncrease))
            {
                return false;
            }
        }

        return true;
    }
    return this.Content[this.CurPos.ContentPos].Can_IncreaseLevel(bIncrease);
};
CDocumentContent.prototype.Increase_ParagraphLevel            = function(bIncrease)
{
    if (!this.Can_IncreaseParagraphLevel(bIncrease))
        return;
    if (true === this.ApplyToAll)
    {
        for (var Index = 0; Index < this.Content.length; Index++)
        {
            this.Content[Index].Increase_Level(bIncrease);
        }
        return;
    }

    if (this.CurPos.ContentPos < 0)
        return false;

    if (true === this.Selection.Use)
    {
        var StartPos = this.Selection.StartPos;
        var EndPos   = this.Selection.EndPos;
        if (EndPos < StartPos)
        {
            var Temp = StartPos;
            StartPos = EndPos;
            EndPos   = Temp;
        }

        for (var Index = StartPos; Index <= EndPos; Index++)
        {
            this.Content[Index].Increase_Level(bIncrease);
        }
        this.Recalculate();
        return;
    }
    this.Content[this.CurPos.ContentPos].Increase_Level(bIncrease);
    this.Recalculate();
};
CDocumentContent.prototype.SetParagraphShd = function(Shd)
{
	if (true === this.ApplyToAll)
	{
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			// При изменении цвета фона параграфа, не надо ничего пересчитывать
			var Item = this.Content[Index];
			Item.Set_ApplyToAll(true);
			Item.SetParagraphShd(Shd);
			Item.Set_ApplyToAll(false);
		}

		return;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.setParagraphShd(Shd);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		if (true === this.Selection.Use)
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;

			if (undefined !== this.LogicDocument && true === this.LogicDocument.UseTextShd && StartPos === EndPos && type_Paragraph === this.Content[StartPos].GetType() && false === this.Content[StartPos].Selection_CheckParaEnd() && selectionflag_Common === this.Selection.Flag)
			{
				this.AddToParagraph(new ParaTextPr({Shd : Shd}));
			}
			else
			{
				if (EndPos < StartPos)
				{
					var Temp = StartPos;
					StartPos = EndPos;
					EndPos   = Temp;
				}

				for (var Index = StartPos; Index <= EndPos; Index++)
				{
					var Item = this.Content[Index];
					Item.SetParagraphShd(Shd);
				}
			}
		}
		else
		{
			var Item = this.Content[this.CurPos.ContentPos];
			Item.SetParagraphShd(Shd);
		}
	}
};
CDocumentContent.prototype.SetParagraphStyle = function(Name)
{
	if (true === this.ApplyToAll)
	{
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Item = this.Content[Index];
			Item.Set_ApplyToAll(true);
			Item.SetParagraphStyle(Name);
			Item.Set_ApplyToAll(false);
		}

		return;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.setParagraphStyle(Name);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		if (true === this.Selection.Use)
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (EndPos < StartPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;
			}

			this.RemoveNumberingSelection();

			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				var Item = this.Content[Index];
				Item.SetParagraphStyle(Name);
			}
		}
		else
		{
			var Item = this.Content[this.CurPos.ContentPos];
			Item.SetParagraphStyle(Name);
		}
	}
};
CDocumentContent.prototype.SetParagraphTabs = function(Tabs)
{
	if (true === this.ApplyToAll)
	{
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Item = this.Content[Index];
			Item.Set_ApplyToAll(true);
			Item.SetParagraphTabs(Tabs);
			Item.Set_ApplyToAll(false);
		}

		return;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.setParagraphTabs(Tabs);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		if (true === this.Selection.Use)
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (EndPos < StartPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;
			}

			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				var Item = this.Content[Index];
				Item.SetParagraphTabs(Tabs);
			}
		}
		else
		{
			var Item = this.Content[this.CurPos.ContentPos];
			Item.SetParagraphTabs(Tabs);
		}
	}
};
CDocumentContent.prototype.SetParagraphContextualSpacing = function(Value)
{
	if (true === this.ApplyToAll)
	{
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Item = this.Content[Index];
			Item.Set_ApplyToAll(true);
			Item.SetParagraphContextualSpacing(Value);
			Item.Set_ApplyToAll(false);
		}

		return;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.setParagraphContextualSpacing(Value);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		if (true === this.Selection.Use)
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (EndPos < StartPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;
			}

			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				var Item = this.Content[Index];
				Item.SetParagraphContextualSpacing(Value);
			}
		}
		else
		{
			var Item = this.Content[this.CurPos.ContentPos];
			Item.SetParagraphContextualSpacing(Value);
		}
	}
};
CDocumentContent.prototype.SetParagraphPageBreakBefore = function(Value)
{
	// В таблице или вне самого верхнего документа нет смысла ставить PageBreak
	if (docpostype_Content !== this.Get_DocPosType() || this.Is_InTable() || this.GetTopDocumentContent() !== this.LogicDocument)
		return;

	if (this.CurPos.ContentPos < 0)
		return false;

	if (true === this.Selection.Use)
	{
		var StartPos = this.Selection.StartPos;
		var EndPos   = this.Selection.EndPos;
		if (EndPos < StartPos)
		{
			var Temp = StartPos;
			StartPos = EndPos;
			EndPos   = Temp;
		}

		for (var Index = StartPos; Index <= EndPos; Index++)
		{
			var Item = this.Content[Index];
			Item.SetParagraphPageBreakBefore(Value);
		}
	}
	else
	{
		var Item = this.Content[this.CurPos.ContentPos];
		Item.SetParagraphPageBreakBefore(Value);
	}
};
CDocumentContent.prototype.SetParagraphKeepLines = function(Value)
{
	if (true === this.ApplyToAll)
	{
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Item = this.Content[Index];
			Item.Set_ApplyToAll(true);
			Item.SetParagraphKeepLines(Value);
			Item.Set_ApplyToAll(false);
		}

		return;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.setParagraphKeepLines(Value);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		if (true === this.Selection.Use)
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (EndPos < StartPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;
			}

			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				var Item = this.Content[Index];
				Item.SetParagraphKeepLines(Value);
			}
		}
		else
		{
			var Item = this.Content[this.CurPos.ContentPos];
			Item.SetParagraphKeepLines(Value);
		}
	}
};
CDocumentContent.prototype.SetParagraphKeepNext = function(Value)
{
	if (true === this.ApplyToAll)
	{
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Item = this.Content[Index];
			Item.Set_ApplyToAll(true);
			Item.SetParagraphKeepNext(Value);
			Item.Set_ApplyToAll(false);
		}

		return;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.setParagraphKeepNext(Value);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		if (true === this.Selection.Use)
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (EndPos < StartPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;
			}

			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				var Item = this.Content[Index];
				Item.SetParagraphKeepNext(Value);
			}
		}
		else
		{
			var Item = this.Content[this.CurPos.ContentPos];
			Item.SetParagraphKeepNext(Value);
		}
	}
};
CDocumentContent.prototype.SetParagraphWidowControl = function(Value)
{
	if (true === this.ApplyToAll)
	{
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Item = this.Content[Index];
			Item.Set_ApplyToAll(true);
			Item.SetParagraphWidowControl(Value);
			Item.Set_ApplyToAll(false);
		}

		return;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.setParagraphWidowControl(Value);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		if (true === this.Selection.Use)
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (EndPos < StartPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;
			}

			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				var Item = this.Content[Index];
				Item.SetParagraphWidowControl(Value);
			}
		}
		else
		{
			var Item = this.Content[this.CurPos.ContentPos];
			Item.SetParagraphWidowControl(Value);
		}
	}
};
CDocumentContent.prototype.SetParagraphBorders = function(Borders)
{
	if (true === this.ApplyToAll)
	{
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Item = this.Content[Index];
			Item.Set_ApplyToAll(true);
			Item.SetParagraphBorders(Borders);
			Item.Set_ApplyToAll(false);
		}

		return;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.setParagraphBorders(Borders);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		if (true === this.Selection.Use)
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (EndPos < StartPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;
			}

			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				var Item = this.Content[Index];
				Item.SetParagraphBorders(Borders);
			}
		}
		else
		{
			var Item = this.Content[this.CurPos.ContentPos];
			if (type_Paragraph === Item.GetType())
			{
				// Мы должны выставить границу для всех параграфов, входящих в текущую группу параграфов
				// с одинаковыми границами

				var StartPos = Item.Index;
				var EndPos   = Item.Index;
				var CurBrd   = Item.Get_CompiledPr().ParaPr.Brd;

				while (true != CurBrd.First)
				{
					StartPos--;
					if (StartPos < 0)
					{
						StartPos = 0;
						break;
					}

					var TempItem = this.Content[StartPos];
					if (type_Paragraph !== TempItem.GetType())
					{
						StartPos++;
						break;
					}

					CurBrd = TempItem.Get_CompiledPr().ParaPr.Brd;
				}

				CurBrd = Item.Get_CompiledPr().ParaPr.Brd;
				while (true != CurBrd.Last)
				{
					EndPos++;
					if (EndPos >= this.Content.length)
					{
						EndPos = this.Content.length - 1;
						break;
					}

					var TempItem = this.Content[EndPos];
					if (type_Paragraph !== TempItem.GetType())
					{
						EndPos--;
						break;
					}

					CurBrd = TempItem.Get_CompiledPr().ParaPr.Brd;
				}

				for (var Index = StartPos; Index <= EndPos; Index++)
					this.Content[Index].SetParagraphBorders(Borders);
			}
			else
			{
				Item.SetParagraphBorders(Borders);
			}
		}
	}
};
CDocumentContent.prototype.IncreaseDecreaseFontSize = function(bIncrease)
{
	if (true === this.ApplyToAll)
	{
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Item = this.Content[Index];
			Item.Set_ApplyToAll(true);
			Item.IncreaseDecreaseFontSize(bIncrease);
			Item.Set_ApplyToAll(false);
		}

		return;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.paragraphIncDecFontSize(bIncrease);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (this.CurPos.ContentPos < 0)
			return false;

		if (true === this.Selection.Use)
		{
			switch (this.Selection.Flag)
			{
				case selectionflag_Common:
				{
					var StartPos = this.Selection.StartPos;
					var EndPos   = this.Selection.EndPos;
					if (EndPos < StartPos)
					{
						var Temp = StartPos;
						StartPos = EndPos;
						EndPos   = Temp;
					}

					for (var Index = StartPos; Index <= EndPos; Index++)
					{
						var Item = this.Content[Index];
						Item.IncreaseDecreaseFontSize(bIncrease);
					}
					break;
				}
				case  selectionflag_Numbering:
				{
					var OldFontSize = this.GetCalculatedTextPr().FontSize;
					var NewFontSize = FontSize_IncreaseDecreaseValue(bIncrease, OldFontSize);
					var TextPr      = new CTextPr();
					TextPr.FontSize = NewFontSize;
					this.AddToParagraph(new ParaTextPr(TextPr), true);
					break;
				}
			}
		}
		else
		{
			var Item = this.Content[this.CurPos.ContentPos];
			Item.IncreaseDecreaseFontSize(bIncrease);
		}
	}
};
CDocumentContent.prototype.IncreaseDecreaseIndent = function(bIncrease)
{
	if (true === this.ApplyToAll)
	{
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Item = this.Content[Index];
			Item.Set_ApplyToAll(true);
			Item.IncreaseDecreaseIndent(bIncrease);
			Item.Set_ApplyToAll(false);
		}

		return;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		if (true != this.LogicDocument.DrawingObjects.isSelectedText())
		{
			var ParaDrawing = this.LogicDocument.DrawingObjects.getMajorParaDrawing();
			if (null != ParaDrawing)
			{
				var Paragraph = ParaDrawing.Parent;
				Paragraph.IncreaseDecreaseIndent(bIncrease);
			}
		}
		else
		{
			this.DrawingObjects.paragraphIncDecIndent(bIncrease);
		}
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (true === this.Selection.Use && selectionflag_Common === this.Selection.Flag)
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (EndPos < StartPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;
			}

			for (var Index = StartPos; Index <= EndPos; Index++)
			{
				this.Content[Index].IncreaseDecreaseIndent(bIncrease);
			}
		}
		else
		{
			this.Content[this.CurPos.ContentPos].IncreaseDecreaseIndent(bIncrease);
		}
	}
};
CDocumentContent.prototype.PasteFormatting = function(TextPr, ParaPr, ApplyPara)
{
	if (true === this.ApplyToAll)
	{
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Item = this.Content[Index];
			Item.Set_ApplyToAll(true);
			Item.PasteFormatting(TextPr, ParaPr, true);
			Item.Set_ApplyToAll(false);
		}

		return;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.paragraphFormatPaste(TextPr, ParaPr, ApplyPara);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (true === this.Selection.Use)
		{
			switch (this.Selection.Flag)
			{
				case selectionflag_Numbering    :
					return;
				case selectionflag_Common:
				{
					var Start = this.Selection.StartPos;
					var End   = this.Selection.EndPos;
					if (Start > End)
					{
						Start = this.Selection.EndPos;
						End   = this.Selection.StartPos;
					}

					for (var Pos = Start; Pos <= End; Pos++)
					{
						this.Content[Pos].PasteFormatting(TextPr, ParaPr, ( Start === End ? false : true ));
					}
					break;
				}
			}
		}
		else
		{
			this.Content[this.CurPos.ContentPos].PasteFormatting(TextPr, ParaPr, true);
		}
	}
};
CDocumentContent.prototype.SetImageProps = function(Props)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		this.LogicDocument.DrawingObjects.setProps(Props);
		this.Document_UpdateInterfaceState();
	}
	else if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Table == this.Content[this.Selection.StartPos].GetType() ) || ( false == this.Selection.Use && type_Table == this.Content[this.CurPos.ContentPos].GetType() ) ))
	{
		if (true == this.Selection.Use)
			this.Content[this.Selection.StartPos].SetImageProps(Props);
		else
			this.Content[this.CurPos.ContentPos].SetImageProps(Props);
	}
};
CDocumentContent.prototype.SetTableProps = function(Props)
{
	if (true === this.ApplyToAll)
		return false;

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.setTableProps(Props);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		var Pos = -1;
		if (true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos)
			Pos = this.Selection.StartPos;
		else if (false === this.Selection.Use)
			Pos = this.CurPos.ContentPos;

		if (-1 !== Pos)
			return this.Content[Pos].SetTableProps(Props);

		return false;
	}
};
CDocumentContent.prototype.GetTableProps = function()
{
	var TablePr = null;
	if (docpostype_Content == this.Get_DocPosType() && ((true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos) || false == this.Selection.Use))
	{
		if (true == this.Selection.Use)
			TablePr = this.Content[this.Selection.StartPos].GetTableProps();
		else
			TablePr = this.Content[this.CurPos.ContentPos].GetTableProps();
	}

	if (null !== TablePr)
		TablePr.CanBeFlow = true;

	return TablePr;
};
CDocumentContent.prototype.GetCalculatedParaPr = function()
{
	var Result_ParaPr = new CParaPr();

	if (true === this.ApplyToAll)
	{
		var StartPr = this.Content[0].GetCalculatedParaPr();
		var Pr      = StartPr.Copy();
		Pr.Locked   = StartPr.Locked;

		for (var Index = 1; Index < this.Content.length; Index++)
		{
			var TempPr = this.Content[Index].GetCalculatedParaPr();
			Pr         = Pr.Compare(TempPr);
		}

		if (Pr.Ind.Left == UnknownValue)
			Pr.Ind.Left = StartPr.Ind.Left;

		if (Pr.Ind.Right == UnknownValue)
			Pr.Ind.Right = StartPr.Ind.Right;

		if (Pr.Ind.FirstLine == UnknownValue)
			Pr.Ind.FirstLine = StartPr.Ind.FirstLine;

		Result_ParaPr             = Pr;
		Result_ParaPr.CanAddTable = ( true === Pr.Locked ? false : true ) && !(this.bPresentation === true);
		if (Result_ParaPr.Shd && Result_ParaPr.Shd.Unifill)
		{
			Result_ParaPr.Shd.Unifill.check(this.Get_Theme(), this.Get_ColorMap());
		}
		return Result_ParaPr;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.getParagraphParaPr();
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (true === this.Selection.Use && selectionflag_Common === this.Selection.Flag)
		{
			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;
			if (EndPos < StartPos)
			{
				var Temp = StartPos;
				StartPos = EndPos;
				EndPos   = Temp;
			}

			var StartPr = this.Content[StartPos].GetCalculatedParaPr();
			var Pr      = StartPr.Copy();
			Pr.Locked   = StartPr.Locked;

			for (var Index = StartPos + 1; Index <= EndPos; Index++)
			{
				var TempPr = this.Content[Index].GetCalculatedParaPr();
				Pr         = Pr.Compare(TempPr);
			}

			if (undefined === Pr.Ind.Left)
				Pr.Ind.Left = StartPr.Ind.Left;

			if (undefined === Pr.Ind.Right)
				Pr.Ind.Right = StartPr.Ind.Right;

			if (undefined === Pr.Ind.FirstLine)
				Pr.Ind.FirstLine = StartPr.Ind.FirstLine;

			Result_ParaPr             = Pr;
			Result_ParaPr.CanAddTable = ( true === Pr.Locked ? false : true ) && !(this.bPresentation === true);
		}
		else
		{
			var Item = this.Content[this.CurPos.ContentPos];
			if (type_Paragraph == Item.GetType())
			{
				var ParaPr = Item.Get_CompiledPr2(false).ParaPr;
				var Locked = Item.Lock.Is_Locked();

				Result_ParaPr             = ParaPr.Copy();
				Result_ParaPr.Locked      = Locked;
				Result_ParaPr.CanAddTable = ( ( true === Locked ) ? ( ( true === Item.IsCursorAtEnd() ) ? true : false ) : true ) && !(this.bPresentation === true);
			}
			else
			{
				Result_ParaPr = Item.GetCalculatedParaPr();
			}
		}

		if (Result_ParaPr.Shd && Result_ParaPr.Shd.Unifill)
		{
			Result_ParaPr.Shd.Unifill.check(this.Get_Theme(), this.Get_ColorMap());
		}
		return Result_ParaPr;
	}
};
CDocumentContent.prototype.GetCalculatedTextPr = function()
{
	var Result_TextPr = null;

	if (true === this.ApplyToAll)
	{
		var VisTextPr;
		this.Content[0].Set_ApplyToAll(true);
		VisTextPr = this.Content[0].GetCalculatedTextPr();
		this.Content[0].Set_ApplyToAll(false);

		var Count = this.Content.length;
		for (var Index = 1; Index < Count; Index++)
		{
			this.Content[Index].Set_ApplyToAll(true);
			var CurPr = this.Content[Index].GetCalculatedTextPr();
			VisTextPr = VisTextPr.Compare(CurPr);
			this.Content[Index].Set_ApplyToAll(false);
		}

		Result_TextPr = VisTextPr;

		return Result_TextPr;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
		return this.LogicDocument.DrawingObjects.getParagraphTextPr();
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (true === this.Selection.Use)
		{
			var VisTextPr;
			switch (this.Selection.Flag)
			{
				case selectionflag_Common:
				{
					var StartPos = this.Selection.StartPos;
					var EndPos   = this.Selection.EndPos;
					if (EndPos < StartPos)
					{
						var Temp = StartPos;
						StartPos = EndPos;
						EndPos   = Temp;
					}

					VisTextPr = this.Content[StartPos].GetCalculatedTextPr();

					for (var Index = StartPos + 1; Index <= EndPos; Index++)
					{
						var CurPr = this.Content[Index].GetCalculatedTextPr();
						VisTextPr = VisTextPr.Compare(CurPr);
					}

					break;
				}
				case selectionflag_Numbering:
				{
					if (!this.Selection.Data || !this.Selection.Data.CurPara)
						break;

					VisTextPr = this.Selection.Data.CurPara.GetNumberingTextPr();
					break;
				}
			}

			Result_TextPr = VisTextPr;
		}
		else
		{
			Result_TextPr = this.Content[this.CurPos.ContentPos].GetCalculatedTextPr();
		}

		return Result_TextPr;
	}
};
CDocumentContent.prototype.GetDirectTextPr = function()
{
	var Result_TextPr = null;

	if (true === this.ApplyToAll)
	{
		var Item      = this.Content[0];
		Result_TextPr = Item.GetDirectTextPr();
		return Result_TextPr;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.getParagraphTextPrCopy();
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (true === this.Selection.Use)
		{
			var VisTextPr;
			switch (this.Selection.Flag)
			{
				case selectionflag_Common:
				{
					var StartPos = this.Selection.StartPos;
					if (this.Selection.EndPos < StartPos)
						StartPos = this.Selection.EndPos;

					var Item  = this.Content[StartPos];
					VisTextPr = Item.GetDirectTextPr();

					break;
				}
				case selectionflag_Numbering:
				{
					if (!this.Selection.Data || !this.Selection.Data.CurPara)
						break;

					var oNumPr = this.Selection.Data.CurPara.GetNumPr();
					VisTextPr  = this.GetNumbering().GetNum(oNumPr.NumId).GetLvl(oNumPr.Lvl).GetTextPr();

					break;
				}
			}

			Result_TextPr = VisTextPr;
		}
		else
		{
			var Item      = this.Content[this.CurPos.ContentPos];
			Result_TextPr = Item.GetDirectTextPr();
		}

		return Result_TextPr;
	}
};
CDocumentContent.prototype.GetDirectParaPr = function()
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.getParagraphParaPrCopy();
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		var Result_ParaPr = null;

		// Inline объекты
		if (docpostype_Content == this.CurPos.Type)
		{
			if (true === this.Selection.Use)
			{
				switch (this.Selection.Flag)
				{
					case selectionflag_Common:
					{
						var StartPos = this.Selection.StartPos;
						if (this.Selection.EndPos < StartPos)
							StartPos = this.Selection.EndPos;

						var Item      = this.Content[StartPos];
						Result_ParaPr = Item.GetDirectParaPr();

						break;
					}
					case selectionflag_Numbering:
					{
						if (!this.Selection.Data || !this.Selection.Data.CurPara)
							break;

						var oNumPr    = this.Selection.Data.CurPara.GetNumPr();
						Result_ParaPr = this.GetNumbering().GetNum(oNumPr.NumId).GetLvl(oNumPr.Lvl).GetParaPr();

						break;
					}
				}
			}
			else
			{
				var Item      = this.Content[this.CurPos.ContentPos];
				Result_ParaPr = Item.GetDirectParaPr();
			}
		}

		return Result_ParaPr;
	}
};
//-----------------------------------------------------------------------------------
// Функции для работы с интерфейсом
//-----------------------------------------------------------------------------------

// Обновляем данные в интерфейсе о свойствах параграфа
CDocumentContent.prototype.Interface_Update_ParaPr    = function()
{
    var ParaPr = this.GetCalculatedParaPr();

    if (null != ParaPr)
    {
        ParaPr.CanAddDropCap = false;

        if (this.LogicDocument)
        {
            var oSelectedInfo = this.LogicDocument.GetSelectedElementsInfo();
            var Math          = oSelectedInfo.Get_Math();
            if (null !== Math)
                ParaPr.CanAddImage = false;
            else
                ParaPr.CanAddImage = true;
        }

        if (undefined != ParaPr.Tabs && editor){
			var DefaultTab = ParaPr.DefaultTab != null ? ParaPr.DefaultTab : AscCommonWord.Default_Tab_Stop;
			editor.Update_ParaTab(DefaultTab, ParaPr.Tabs);
		}

        if (this.LogicDocument)
        {
            var SelectedInfo = this.LogicDocument.GetSelectedElementsInfo();
            var Math         = SelectedInfo.Get_Math();
            if (null !== Math && true !== Math.Is_Inline())
                ParaPr.Jc = Math.Get_Align();

            // Если мы находимся внутри автофигуры, тогда нам надо проверить лок параграфа, в котором находится автофигура
            if (docpostype_DrawingObjects === this.LogicDocument.CurPos.Type && true !== ParaPr.Locked)
            {
                var ParaDrawing = this.LogicDocument.DrawingObjects.getMajorParaDrawing();
                if (ParaDrawing)
                {
                    ParaPr.Locked = ParaDrawing.Lock.Is_Locked();
                }
            }
        }

        if (editor)
            editor.UpdateParagraphProp(ParaPr);
    }
};
// Обновляем данные в интерфейсе о свойствах текста
CDocumentContent.prototype.Interface_Update_TextPr    = function()
{
    var TextPr = this.GetCalculatedTextPr();


    if (null != TextPr)
    {
        var theme = this.Get_Theme();
        if (theme && theme.themeElements && theme.themeElements.fontScheme)
        {
            if (TextPr.FontFamily)
            {
                TextPr.FontFamily.Name = theme.themeElements.fontScheme.checkFont(TextPr.FontFamily.Name);
            }
            if (TextPr.RFonts)
            {
                if (TextPr.RFonts.Ascii)
                    TextPr.RFonts.Ascii.Name = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.Ascii.Name);
                if (TextPr.RFonts.EastAsia)
                    TextPr.RFonts.EastAsia.Name = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.EastAsia.Name);
                if (TextPr.RFonts.HAnsi)
                    TextPr.RFonts.HAnsi.Name = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.HAnsi.Name);
                if (TextPr.RFonts.CS)
                    TextPr.RFonts.CS.Name = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.CS.Name);
            }
        }
        editor.UpdateTextPr(TextPr);
    }
};
CDocumentContent.prototype.Interface_Update_DrawingPr = function(Flag)
{
    var ImagePr = {};

    if (docpostype_DrawingObjects === this.CurPos.Type)
        ImagePr = this.LogicDocument.DrawingObjects.getProps();

    if (true === Flag)
        return ImagePr;
    else
        editor.sync_ImgPropCallback(ImagePr);

};
CDocumentContent.prototype.Interface_Update_TablePr   = function(Flag)
{
    var TablePr = null;
    if (docpostype_DrawingObjects == this.CurPos.Type)
    {
        TablePr = this.LogicDocument.DrawingObjects.getTableProps();
    }
    else if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Table == this.Content[this.Selection.StartPos].GetType() ) || ( false == this.Selection.Use && type_Table == this.Content[this.CurPos.ContentPos].GetType() ) ))
    {
        if (true == this.Selection.Use)
            TablePr = this.Content[this.Selection.StartPos].Get_Props();
        else
            TablePr = this.Content[this.CurPos.ContentPos].Get_Props();
    }

    if (true === Flag)
        return TablePr;
    else if (null != TablePr)
        editor.sync_TblPropCallback(TablePr);
};
//-----------------------------------------------------------------------------------
// Функции для работы с селектом
//-----------------------------------------------------------------------------------
CDocumentContent.prototype.RemoveSelection = function(bNoCheckDrawing)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.resetSelection(undefined, bNoCheckDrawing);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (true === this.Selection.Use)
		{
			switch (this.Selection.Flag)
			{
				case selectionflag_Common:
				{
					var Start = this.Selection.StartPos;
					var End   = this.Selection.EndPos;

					if (Start > End)
					{
						var Temp = Start;
						Start    = End;
						End      = Temp;
					}

					Start = Math.max(0, Start);
					End   = Math.min(this.Content.length - 1, End);

					for (var Index = Start; Index <= End; Index++)
					{
						this.Content[Index].RemoveSelection();
					}
					break;
				}
				case selectionflag_Numbering:
				{
					if (!this.Selection.Data)
						break;

					for (var nIndex = 0, nCount = this.Selection.Data.Paragraphs.length; nIndex < nCount; ++nIndex)
					{
						this.Selection.Data.Paragraphs[nIndex].RemoveSelection();
					}

					break;
				}
			}
		}

		this.Selection.StartPos = 0;
		this.Selection.EndPos   = 0;

		this.Selection.Use   = false;
		this.Selection.Start = false;
		this.Selection.Flag  = selectionflag_Common;
	}
};
CDocumentContent.prototype.DrawSelectionOnPage = function(PageIndex)
{
    var CurPage = PageIndex;
    if (CurPage < 0 || CurPage >= this.Pages.length)
        return;

    if (docpostype_DrawingObjects === this.CurPos.Type)
    {
        this.DrawingDocument.SetTextSelectionOutline(true);
        var PageAbs = CurPage + this.Get_StartPage_Absolute();
        this.LogicDocument.DrawingObjects.drawSelectionPage(PageAbs);
    }
    else
    {
        var Pos_start = this.Pages[CurPage].Pos;
        var Pos_end   = this.Pages[CurPage].EndPos;

        if (true === this.Selection.Use)
        {
            switch (this.Selection.Flag)
            {
                case selectionflag_Common:
                {
                    var Start = this.Selection.StartPos;
                    var End   = this.Selection.EndPos;

                    if (Start > End)
                    {
                        Start = this.Selection.EndPos;
                        End   = this.Selection.StartPos;
                    }

                    var Start = Math.max(Start, Pos_start);
                    var End   = Math.min(End, Pos_end);

                    for (var Index = Start; Index <= End; Index++)
                    {
                        var ElementPageIndex = this.private_GetElementPageIndex(Index, CurPage, 0, 1);
                        this.Content[Index].DrawSelectionOnPage(ElementPageIndex);
                    }

                    break;
                }
                case selectionflag_Numbering:
                {
                    if (!this.Selection.Data)
                        break;

					var nPageAbs = this.Get_AbsolutePage(CurPage);
                    for (var nIndex = 0, nCount = this.Selection.Data.Paragraphs.length; nIndex < nCount; ++nIndex)
					{
						var oParagraph = this.Selection.Data.Paragraphs[nIndex];
						var nParaPageAbs = oParagraph.GetNumberingPage(true);
						if (nParaPageAbs === nPageAbs)
							oParagraph.DrawSelectionOnPage(oParagraph.GetNumberingPage(false));
					}

                    break;
                }
            }
        }
    }
};
CDocumentContent.prototype.Selection_SetStart = function(X, Y, CurPage, MouseEvent)
{
	if (this.Pages.length <= 0)
		return;

	if (CurPage < 0)
	{
		CurPage = 0;
		Y       = 0;
	}
	else if (CurPage >= this.Pages.length)
	{
		CurPage = this.Pages.length - 1;
		Y       = this.Pages[CurPage].YLimit;
	}

	this.CurPage = CurPage;
	var AbsPage  = this.Get_AbsolutePage(this.CurPage);

	// Сначала проверим, не попали ли мы в один из "плавающих" объектов
	var bInText      = (null === this.IsInText(X, Y, AbsPage) ? false : true);
	var bTableBorder = (null === this.IsTableBorder(X, Y, AbsPage) ? false : true);
	var nInDrawing   = this.LogicDocument && this.LogicDocument.DrawingObjects.IsInDrawingObject(X, Y, AbsPage, this);

	if (this.Parent instanceof CHeaderFooter && ( nInDrawing === DRAWING_ARRAY_TYPE_BEFORE || nInDrawing === DRAWING_ARRAY_TYPE_INLINE || ( false === bTableBorder && false === bInText && nInDrawing >= 0 ) ))
	{
		if (docpostype_DrawingObjects != this.CurPos.Type)
			this.RemoveSelection();

		// Прячем курсор
		this.DrawingDocument.TargetEnd();
		this.DrawingDocument.SetCurrentPage(AbsPage);

		var HdrFtr = this.IsHdrFtr(true);
		if (null === HdrFtr)
		{
			this.LogicDocument.Selection.Use   = true;
			this.LogicDocument.Selection.Start = true;
			this.LogicDocument.Selection.Flag  = selectionflag_Common;
			this.LogicDocument.Set_DocPosType(docpostype_DrawingObjects);
		}
		else
		{
			HdrFtr.Content.Selection.Use   = true;
			HdrFtr.Content.Selection.Start = true;
			HdrFtr.Content.Selection.Flag  = selectionflag_Common;
			HdrFtr.Content.Set_DocPosType(docpostype_DrawingObjects);
		}

		this.LogicDocument.DrawingObjects.OnMouseDown(MouseEvent, X, Y, AbsPage);
	}
	else
	{
		var bOldSelectionIsCommon = true;

		if (docpostype_DrawingObjects === this.CurPos.Type && true != this.IsInDrawing(X, Y, AbsPage))
		{
			this.LogicDocument.DrawingObjects.resetSelection();
			bOldSelectionIsCommon = false;
		}

		var ContentPos = this.Internal_GetContentPosByXY(X, Y);

		if (docpostype_Content != this.CurPos.Type)
		{
			this.Set_DocPosType(docpostype_Content);
			this.CurPos.ContentPos = ContentPos;
			bOldSelectionIsCommon  = false;
		}

		var SelectionUse_old = this.Selection.Use;
		var Item             = this.Content[ContentPos];
		var bTableBorder     = (null != Item.IsTableBorder(X, Y, AbsPage) ? true : false);

		// Убираем селект, кроме случаев либо текущего параграфа, либо при движении границ внутри таблицы
		if (!(true === SelectionUse_old && true === MouseEvent.ShiftKey && true === bOldSelectionIsCommon))
		{
			if ((selectionflag_Common != this.Selection.Flag) || ( true === this.Selection.Use && MouseEvent.ClickCount <= 1 && true != bTableBorder ))
				this.RemoveSelection();
		}

		this.Selection.Use   = true;
		this.Selection.Start = true;
		this.Selection.Flag  = selectionflag_Common;

		if (true === SelectionUse_old && true === MouseEvent.ShiftKey && true === bOldSelectionIsCommon)
		{
			this.Selection_SetEnd(X, Y, this.CurPage, {Type : AscCommon.g_mouse_event_type_up, ClickCount : 1});
			this.Selection.Use    = true;
			this.Selection.Start  = true;
			this.Selection.EndPos = ContentPos;
			this.Selection.Data   = null;
		}
		else
		{
			var ElementPageIndex = this.private_GetElementPageIndexByXY(ContentPos, X, Y, this.CurPage);
			Item.Selection_SetStart(X, Y, ElementPageIndex, MouseEvent);

			if (this.IsNumberingSelection())
			{
				// TODO: Можно сделать передвигание нумерации как в Word
				return;
			}

			Item.Selection_SetEnd(X, Y, ElementPageIndex, {Type : AscCommon.g_mouse_event_type_move, ClickCount : 1});

			if (true !== bTableBorder)
			{
				this.Selection.Use      = true;
				this.Selection.StartPos = ContentPos;
				this.Selection.EndPos   = ContentPos;
				this.Selection.Data     = null;

				this.CurPos.ContentPos = ContentPos;

				if (type_Paragraph === Item.GetType() && true === MouseEvent.CtrlKey)
				{
					var oHyperlink   = Item.CheckHyperlink(X, Y, ElementPageIndex);
					var oPageRefLink = Item.CheckPageRefLink(X, Y, ElementPageIndex);
					if (null != oHyperlink)
					{
						this.Selection.Data = {
							Hyperlink : oHyperlink
						};
					}
					else if (null !== oPageRefLink)
					{
						this.Selection.Data = {
							PageRef : oPageRefLink
						};
					}
				}
			}
			else
			{
				this.Selection.Data = {
					TableBorder : true,
					Pos         : ContentPos,
					Selection   : SelectionUse_old
				};
			}
		}
	}
};
// Данная функция может использоваться как при движении, так и при окончательном выставлении селекта.
// Если bEnd = true, тогда это конец селекта.
CDocumentContent.prototype.Selection_SetEnd = function(X, Y, CurPage, MouseEvent)
{
	if (this.Pages.length <= 0)
		return;

	if (CurPage < 0)
	{
		CurPage = 0;
		Y       = 0;
	}
	else if (CurPage >= this.Pages.length)
	{
		CurPage = this.Pages.length - 1;
		Y       = this.Pages[CurPage].YLimit;
	}

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		var PageAbs = this.Get_StartPage_Absolute(CurPage);
		if (AscCommon.g_mouse_event_type_up == MouseEvent.Type)
		{
			this.LogicDocument.DrawingObjects.OnMouseUp(MouseEvent, X, Y, PageAbs);
			this.Selection.Start = false;
			this.Selection.Use   = true;
		}
		else
		{
			this.LogicDocument.DrawingObjects.OnMouseMove(MouseEvent, X, Y, PageAbs);
		}
		return;
	}

	this.CurPage = CurPage;

	if (selectionflag_Numbering === this.Selection.Flag)
		return;

	// Обрабатываем движение границы у таблиц
	if (null != this.Selection.Data && true === this.Selection.Data.TableBorder && type_Table == this.Content[this.Selection.Data.Pos].GetType())
	{
		var Item             = this.Content[this.Selection.Data.Pos];
		var ElementPageIndex = this.private_GetElementPageIndexByXY(this.Selection.Data.Pos, X, Y, this.CurPage);
		Item.Selection_SetEnd(X, Y, ElementPageIndex, MouseEvent);

		if (AscCommon.g_mouse_event_type_up == MouseEvent.Type)
		{
			this.Selection.Start = false;

			if (true != this.Selection.Data.Selection)
			{
				this.Selection.Use = false;
			}
			this.Selection.Data = null;
		}

		return;
	}

	if (false === this.Selection.Use)
		return;

	var ContentPos = this.Internal_GetContentPosByXY(X, Y);

	this.CurPos.ContentPos = ContentPos;
	var OldEndPos          = this.Selection.EndPos;
	this.Selection.EndPos  = ContentPos;

	// Удалим отметки о старом селекте
	if (OldEndPos < this.Selection.StartPos && OldEndPos < this.Selection.EndPos)
	{
		var TempLimit = Math.min(this.Selection.StartPos, this.Selection.EndPos);
		for (var Index = OldEndPos; Index < TempLimit; Index++)
		{
			this.Content[Index].RemoveSelection();
		}
	}
	else if (OldEndPos > this.Selection.StartPos && OldEndPos > this.Selection.EndPos)
	{
		var TempLimit = Math.max(this.Selection.StartPos, this.Selection.EndPos);
		for (var Index = TempLimit + 1; Index <= OldEndPos; Index++)
		{
			this.Content[Index].RemoveSelection();
		}
	}

	// Направление селекта: 1 - прямое, -1 - обратное, 0 - отмечен 1 элемент документа
	var Direction = ( ContentPos > this.Selection.StartPos ? 1 : ( ContentPos < this.Selection.StartPos ? -1 : 0 )  );

	if (AscCommon.g_mouse_event_type_up == MouseEvent.Type)
		this.StopSelection();

	var Start, End;
	if (0 == Direction)
	{
		var Item             = this.Content[this.Selection.StartPos];
		var ElementPageIndex = this.private_GetElementPageIndexByXY(this.Selection.StartPos, X, Y, this.CurPage);
		Item.Selection_SetEnd(X, Y, ElementPageIndex, MouseEvent);

		if (this.IsNumberingSelection())
		{
			// Ничего не делаем
		}
		else if (false === Item.IsSelectionUse())
		{
			this.Selection.Use = false;

			if (null != this.Selection.Data && this.Selection.Data.Hyperlink)
			{
				var oHyperlink    = this.Selection.Data.Hyperlink;
				var sBookmarkName = oHyperlink.GetAnchor();
				var sValue        = oHyperlink.GetValue();
				if (sBookmarkName)
				{
					var oBookmarksManagers = this.LogicDocument && this.LogicDocument.GetBookmarksManager ? this.LogicDocument.GetBookmarksManager() : null;
					var oBookmark = oBookmarksManagers ? oBookmarksManagers.GetBookmarkByName(sBookmarkName) : null;
					if (oBookmark)
						oBookmark[0].GoToBookmark();
				}
				else if (sValue)
				{
					editor && editor.sync_HyperlinkClickCallback(sValue);
					this.Selection.Data.Hyperlink.SetVisited(true);
					if (this.DrawingDocument.m_oLogicDocument)
					{
						if (editor.isDocumentEditor)
						{
							for (var PageIdx = Item.Get_AbsolutePage(0); PageIdx < Item.Get_AbsolutePage(0) + Item.Get_PagesCount(); PageIdx++)
								this.DrawingDocument.OnRecalculatePage(PageIdx, this.DrawingDocument.m_oLogicDocument.Pages[PageIdx]);
						}
						else
						{
							this.DrawingDocument.OnRecalculatePage(PageIdx, this.DrawingDocument.m_oLogicDocument.Slides[PageIdx]);
						}
						this.DrawingDocument.OnEndRecalculate(false, true);
					}
				}
			}
			else if (null !== this.Selection.Data && this.Selection.Data.PageRef)
			{
				var oInstruction  = this.Selection.Data.PageRef.GetInstruction();
				if (oInstruction && fieldtype_PAGEREF === oInstruction.GetType())
				{
					var oBookmarksManagers = this.LogicDocument && this.LogicDocument.GetBookmarksManager ? this.LogicDocument.GetBookmarksManager() : null;
					var oBookmark = oBookmarksManagers ? oBookmarksManagers.GetBookmarkByName(oInstruction.GetBookmarkName()) : null;
					if (oBookmark)
						oBookmark[0].GoToBookmark();
				}
			}
		}
		else
		{
			this.Selection.Use = true;
		}

		return;
	}
	else if (Direction > 0)
	{
		Start = this.Selection.StartPos;
		End   = this.Selection.EndPos;
	}
	else
	{
		End   = this.Selection.StartPos;
		Start = this.Selection.EndPos;
	}

	// Чтобы не было эффекта, когда ничего не поселекчено, а при удалении соединяются параграфы
	if (Direction > 0 && type_Paragraph === this.Content[Start].GetType() && true === this.Content[Start].IsSelectionEmpty() && this.Content[Start].Selection.StartPos == this.Content[Start].Content.length - 1)
	{
		this.Content[Start].Selection.StartPos = this.Content[Start].Internal_GetEndPos();
		this.Content[Start].Selection.EndPos   = this.Content[Start].Content.length - 1;
	}

	var ElementPageIndex = this.private_GetElementPageIndexByXY(ContentPos, X, Y, this.CurPage);
	this.Content[ContentPos].Selection_SetEnd(X, Y, ElementPageIndex, MouseEvent);

	for (var Index = Start; Index <= End; Index++)
	{
		var Item = this.Content[Index];
		Item.SetSelectionUse(true);

		switch (Index)
		{
			case Start:

				Item.SetSelectionToBeginEnd(Direction > 0 ? false : true, false);
				break;

			case End:

				Item.SetSelectionToBeginEnd(Direction > 0 ? true : false, true);
				break;

			default:

				Item.SelectAll(Direction);
				break;
		}
	}
};
CDocumentContent.prototype.CheckPosInSelection = function(X, Y, CurPage, NearPos)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.DrawingObjects.selectionCheck(X, Y, this.Get_AbsolutePage(CurPage), NearPos);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (true === this.Selection.Use || true === this.ApplyToAll)
		{
			switch (this.Selection.Flag)
			{
				case selectionflag_Common:
				{
					var Start = this.Selection.StartPos;
					var End   = this.Selection.EndPos;

					if (Start > End)
					{
						Start = this.Selection.EndPos;
						End   = this.Selection.StartPos;
					}

					if (undefined !== NearPos)
					{
						if (true === this.ApplyToAll)
						{
							Start = 0;
							End   = this.Content.length - 1;
						}

						for (var Index = Start; Index <= End; Index++)
						{
							if (true === this.ApplyToAll)
								this.Content[Index].Set_ApplyToAll(true);

							if (true === this.Content[Index].CheckPosInSelection(0, 0, 0, NearPos))
							{
								if (true === this.ApplyToAll)
									this.Content[Index].Set_ApplyToAll(false);

								return true;
							}

							if (true === this.ApplyToAll)
								this.Content[Index].Set_ApplyToAll(false);
						}

						return false;
					}
					else
					{
						var ContentPos = this.Internal_GetContentPosByXY(X, Y, CurPage);
						if (ContentPos > Start && ContentPos < End)
						{
							return true;
						}
						else if (ContentPos < Start || ContentPos > End)
						{
							return false;
						}
						else
						{
							var ElementPageIndex = this.private_GetElementPageIndexByXY(ContentPos, X, Y, CurPage);
							return this.Content[ContentPos].CheckPosInSelection(X, Y, ElementPageIndex, NearPos);
						}

						return false;
					}
				}
				case selectionflag_Numbering :
					return false;
			}

			return false;
		}

		return false;
	}
};
CDocumentContent.prototype.IsSelectionEmpty = function(bCheckHidden)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.selectionIsEmpty(bCheckHidden);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (true === this.Selection.Use)
		{
			// Выделение нумерации
			if (selectionflag_Numbering == this.Selection.Flag)
				return false;
			// Обрабатываем движение границы у таблиц
			else if (null != this.Selection.Data && true === this.Selection.Data.TableBorder && type_Table == this.Content[this.Selection.Data.Pos].GetType())
				return false;
			else
			{
				if (this.Selection.StartPos === this.Selection.EndPos)
					return this.Content[this.Selection.StartPos].IsSelectionEmpty(bCheckHidden);
				else
					return false;
			}
		}

		return true;
	}
};
CDocumentContent.prototype.SelectAll = function()
{
	if (docpostype_DrawingObjects === this.CurPos.Type && true === this.DrawingObjects.isSelectedText())
	{
		this.DrawingObjects.selectAll();
	}
	else
	{
		if (true === this.Selection.Use)
			this.RemoveSelection();

		this.Set_DocPosType(docpostype_Content);
		this.Selection.Use   = true;
		this.Selection.Start = false;
		this.Selection.Flag  = selectionflag_Common;

		this.Selection.StartPos = 0;
		this.Selection.EndPos   = this.Content.length - 1;

		for (var Index = 0; Index < this.Content.length; Index++)
		{
			this.Content[Index].SelectAll();
		}
	}
};
CDocumentContent.prototype.SetSelectionUse = function(isUse)
{
	if (true === isUse)
		this.Selection.Use = true;
	else
		this.RemoveSelection();
};
CDocumentContent.prototype.SetSelectionToBeginEnd = function(isSelectionStart, isElementStart)
{
	if (this.Content.length <= 0)
		return;

	if (true === isElementStart)
	{
		this.Content[0].SetSelectionUse(true);
		this.Content[0].SetSelectionToBeginEnd(isSelectionStart, true);
		if (isSelectionStart)
		{
			this.Selection.StartPos = 0;
			this.Selection.EndPos   = this.CurPos.ContentPos;
		}
		else
		{
			this.Selection.StartPos = this.CurPos.ContentPos;
			this.Selection.EndPos   = 0;
		}
	}
	else
	{
		this.Content[this.Content.length - 1].SetSelectionUse(true);
		this.Content[this.Content.length - 1].SetSelectionToBeginEnd(isSelectionStart, false);

		if (isSelectionStart)
		{
			this.Selection.StartPos = this.Content.length - 1;
			this.Selection.EndPos   = this.CurPos.ContentPos;
		}
		else
		{
			this.Selection.StartPos = this.CurPos.ContentPos;
			this.Selection.EndPos   = this.Content.length - 1;
		}
	}
};
CDocumentContent.prototype.Select_DrawingObject      = function(Id)
{
    this.RemoveSelection();

    this.Parent.Set_CurrentElement(true, this.Get_StartPage_Absolute() + this.CurPage, this);

    // Прячем курсор
    this.DrawingDocument.TargetEnd();
    this.DrawingDocument.SetCurrentPage(this.Get_StartPage_Absolute() + this.CurPage);

    var HdrFtr = this.IsHdrFtr(true);
    if (null != HdrFtr)
    {
        HdrFtr.Content.Set_DocPosType(docpostype_DrawingObjects);
        HdrFtr.Content.Selection.Use   = true;
        HdrFtr.Content.Selection.Start = false;

        this.LogicDocument.Selection.Use   = true;
        this.LogicDocument.Selection.Start = false;
    }
    else
    {
        this.LogicDocument.Set_DocPosType(docpostype_DrawingObjects);
        this.LogicDocument.Selection.Use   = true;
        this.LogicDocument.Selection.Start = false;
    }

    this.LogicDocument.DrawingObjects.selectById(Id, this.Get_StartPage_Absolute() + this.CurPage);

    // TODO: Пока сделаем так, в будущем надо сделать функцию, которая у родительского класса обновляет Select
    editor.WordControl.m_oLogicDocument.Document_UpdateSelectionState();
    editor.WordControl.m_oLogicDocument.Document_UpdateInterfaceState();
};
//-----------------------------------------------------------------------------------
// Функции для работы с таблицами
//-----------------------------------------------------------------------------------
CDocumentContent.prototype.AddTableRow = function(bBefore)
{
	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.tableAddRow(bBefore);
	}
	else if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType() ) || ( false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType() ) ))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		this.Content[Pos].AddTableRow(bBefore);
		if (false === this.Selection.Use && true === this.Content[Pos].IsSelectionUse())
		{
			this.Selection.Use      = true;
			this.Selection.StartPos = Pos;
			this.Selection.EndPos   = Pos;
		}

		return true;
	}

	return false;
};
CDocumentContent.prototype.AddTableColumn = function(bBefore)
{
	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.tableAddCol(bBefore);
	}
	else if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType() ) || ( false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType() ) ))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		this.Content[Pos].AddTableColumn(bBefore);
		if (false === this.Selection.Use && true === this.Content[Pos].IsSelectionUse())
		{
			this.Selection.Use      = true;
			this.Selection.StartPos = Pos;
			this.Selection.EndPos   = Pos;
		}

		return true;
	}

	return false;
};
CDocumentContent.prototype.RemoveTableRow = function()
{
	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.tableRemoveRow();
	}
	else if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType() ) || ( false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType() ) ))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		if (false === this.Content[Pos].RemoveTableRow())
			this.RemoveTable();

		return true;
	}

	return false;
};
CDocumentContent.prototype.RemoveTableColumn = function()
{
	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.tableRemoveCol();
	}
	else if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType() ) || ( false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType() ) ))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		if (false === this.Content[Pos].RemoveTableColumn())
			this.RemoveTable();

		return true;
	}

	return false;
};
CDocumentContent.prototype.MergeTableCells = function()
{
	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.tableMergeCells();
	}
	else if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType() ) || ( false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType() ) ))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		this.Content[Pos].MergeTableCells();
		return true;
	}

	return false;
};
CDocumentContent.prototype.SplitTableCells = function(Cols, Rows)
{
	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.tableSplitCell();
	}
	else if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType() ) || ( false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType() ) ))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		this.Content[Pos].SplitTableCells(Rows, Cols);
		return true;
	}

	return false;
};
CDocumentContent.prototype.RemoveTable = function()
{
    if (docpostype_DrawingObjects == this.CurPos.Type)
    {
        return this.LogicDocument.DrawingObjects.tableRemoveTable();
    }
    else if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType() ) || ( false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType() ) ))
    {
        var Pos;
        if (true === this.Selection.Use)
            Pos = this.Selection.StartPos;
        else
            Pos = this.CurPos.ContentPos;

        var Table = this.Content[Pos];
        if (type_Table === Table.GetType())
		{
			if (true === Table.IsInnerTable())
			{
				Table.RemoveInnerTable();
			}
			else
			{
				this.RemoveSelection();
				Table.PreDelete();
				this.Internal_Content_Remove(Pos, 1);

				if (Pos >= this.Content.length - 1)
					Pos--;

				if (Pos < 0)
					Pos = 0;

				this.Set_DocPosType(docpostype_Content);
				this.CurPos.ContentPos = Pos;
				this.Content[Pos].MoveCursorToStartPos();
			}

			return true;
		}
		else
		{
			return Table.RemoveTable();
		}
    }
    return false;
};
CDocumentContent.prototype.SelectTable = function(Type)
{
	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.tableSelect(Type);
	}
	else if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType() ) || ( false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType() ) ))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		this.Content[Pos].SelectTable(Type);
		if (false === this.Selection.Use && true === this.Content[Pos].IsSelectionUse())
		{
			this.Selection.Use      = true;
			this.Selection.StartPos = Pos;
			this.Selection.EndPos   = Pos;
		}
		return true;
	}

	return false;
};
CDocumentContent.prototype.CanMergeTableCells = function()
{
	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.tableCheckMerge();
	}
	else if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType() ) || ( false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType() ) ))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		return this.Content[Pos].CanMergeTableCells();
	}

	return false;
};
CDocumentContent.prototype.CanSplitTableCells = function()
{
	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.tableCheckSplit();
	}
	else if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType() ) || ( false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType() ) ))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		return this.Content[Pos].CanSplitTableCells();
	}

	return false;
};
CDocumentContent.prototype.DistributeTableCells = function(isHorizontally)
{
	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.distributeTableCells(isHorizontally);
	}
	else if (docpostype_Content == this.CurPos.Type && ( ( true === this.Selection.Use && this.Selection.StartPos == this.Selection.EndPos && type_Paragraph !== this.Content[this.Selection.StartPos].GetType() ) || ( false == this.Selection.Use && type_Paragraph !== this.Content[this.CurPos.ContentPos].GetType() ) ))
	{
		var Pos = 0;
		if (true === this.Selection.Use)
			Pos = this.Selection.StartPos;
		else
			Pos = this.CurPos.ContentPos;

		return this.Content[Pos].DistributeTableCells(isHorizontally);
	}

	return false;
};
//-----------------------------------------------------------------------------------
// Вспомогательные(внутренние ) функции
//-----------------------------------------------------------------------------------
CDocumentContent.prototype.Internal_GetContentPosByXY = function(X, Y, PageNum)
{
    if (undefined === PageNum || null === PageNum)
        PageNum = this.CurPage;

    PageNum = Math.max(0, Math.min(PageNum, this.Pages.length - 1));

    // Сначала проверим Flow-таблицы
    var FlowTable = this.LogicDocument && this.LogicDocument.DrawingObjects.getTableByXY(X, Y, PageNum + this.Get_StartPage_Absolute(), this);
    if (null != FlowTable)
        return FlowTable.Table.Index;

    // Теперь проверим пустые параграфы с окончанием секций (в нашем случае это пустой параграф послей таблицы внутри таблицы)
    var SectCount = this.Pages[PageNum].EndSectionParas.length;
    for (var Index = 0; Index < SectCount; ++Index)
    {
        var Item   = this.Pages[PageNum].EndSectionParas[Index];
        var Bounds = Item.Pages[0].Bounds;

        if (Y < Bounds.Bottom && Y > Bounds.Top && X > Bounds.Left && X < Bounds.Right)
            return Item.Index;
    }

    var StartPos = Math.min(this.Pages[PageNum].Pos, this.Content.length - 1);
    var EndPos   = this.Content.length - 1;

    if (PageNum < this.Pages.length - 1)
        EndPos = Math.min(this.Pages[PageNum + 1].Pos, EndPos);

    // Сохраним позиции всех Inline элементов на данной странице
    var InlineElements = [];
    for (var Index = StartPos; Index <= EndPos; Index++)
    {
        var Item = this.Content[Index];
        var bEmptySectPara = this.Pages[PageNum].Check_EndSectionPara(Item);

        if (false != Item.Is_Inline() && (type_Paragraph !== Item.GetType() || false === bEmptySectPara))
            InlineElements.push(Index);
    }

    var Count = InlineElements.length;
    if (Count <= 0)
        return StartPos;

    for (var Pos = 0; Pos < Count - 1; Pos++)
    {
        var Item = this.Content[InlineElements[Pos + 1]];

		if (Item.GetPagesCount() <= 0 || Y < Item.GetPageBounds(0).Top)
			return InlineElements[Pos];

        if (Item.GetPagesCount() > 1)
        {
            if (true !== Item.IsStartFromNewPage())
                return InlineElements[Pos + 1];

            return InlineElements[Pos];
        }

        if (Pos === Count - 2)
        {
            // Такое возможно, если страница заканчивается Flow-таблицей
            return InlineElements[Count - 1];
        }
    }

    return InlineElements[0];
};
CDocumentContent.prototype.private_CheckCurPage = function()
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		// TODO: переделать
		this.CurPage = 0;
	}
	else if (docpostype_Content === this.CurPos.Type)
	{
		if (true === this.Selection.Use)
		{
			this.CurPage = this.Content[this.Selection.EndPos].Get_CurrentPage_Relative();
		}
		else if (this.CurPos.ContentPos >= 0)
		{
			this.CurPage = this.Content[this.CurPos.ContentPos].Get_CurrentPage_Relative();
		}
	}
};
CDocumentContent.prototype.Internal_Content_Add = function(Position, NewObject, bCheckLastElement)
{
	// Position = this.Content.length  допускается
	if (Position < 0 || Position > this.Content.length)
		return;

	var PrevObj = this.Content[Position - 1] ? this.Content[Position - 1] : null;
	var NextObj = this.Content[Position] ? this.Content[Position] : null;

	this.private_RecalculateNumbering([NewObject]);
	History.Add(new CChangesDocumentContentAddItem(this, Position, [NewObject]));
	this.Content.splice(Position, 0, NewObject);
	NewObject.Set_Parent(this);
	NewObject.Set_DocumentNext(NextObj);
	NewObject.Set_DocumentPrev(PrevObj);

	if (null != PrevObj)
		PrevObj.Set_DocumentNext(NewObject);

	if (null != NextObj)
		NextObj.Set_DocumentPrev(NewObject);

	if (Position <= this.CurPos.TableMove)
		this.CurPos.TableMove++;

	// Проверим, что последний элемент - параграф или SdtBlockLevel
	if (false != bCheckLastElement
		&& type_Paragraph !== this.Content[this.Content.length - 1].GetType()
		&& type_BlockLevelSdt !== this.Content[this.Content.length - 1].GetType())
		this.Internal_Content_Add(this.Content.length, new Paragraph(this.DrawingDocument, this, this.bPresentation === true));

	this.private_ReindexContent(Position);
};
CDocumentContent.prototype.Internal_Content_Remove = function(Position, Count, bCheckLastElement)
{
	if (Position < 0 || Position >= this.Content.length || Count <= 0)
		return;

	var PrevObj = this.Content[Position - 1] ? this.Content[Position - 1] : null;
	var NextObj = this.Content[Position + Count] ? this.Content[Position + Count] : null;

	for (var Index = 0; Index < Count; Index++)
		this.Content[Position + Index].PreDelete();

	History.Add(new CChangesDocumentContentRemoveItem(this, Position, this.Content.slice(Position, Position + Count)));
	var Elements = this.Content.splice(Position, Count);
	this.private_RecalculateNumbering(Elements);

	if (null != PrevObj)
		PrevObj.Set_DocumentNext(NextObj);

	if (null != NextObj)
		NextObj.Set_DocumentPrev(PrevObj);

	// Проверим, что последний элемент - параграф
	if (false !== bCheckLastElement
		&& (this.Content.length <= 0
		|| (type_Paragraph !== this.Content[this.Content.length - 1].GetType()
		&& type_BlockLevelSdt !== this.Content[this.Content.length - 1].GetType())))
		this.Internal_Content_Add(this.Content.length, new Paragraph(this.DrawingDocument, this, this.bPresentation === true));

	this.private_ReindexContent(Position);
};
CDocumentContent.prototype.Clear_ContentChanges = function()
{
	this.m_oContentChanges.Clear();
};
CDocumentContent.prototype.Add_ContentChanges = function(Changes)
{
	this.m_oContentChanges.Add(Changes);
};
CDocumentContent.prototype.Refresh_ContentChanges = function()
{
	this.m_oContentChanges.Refresh();
};
CDocumentContent.prototype.Internal_Content_RemoveAll = function()
{
	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
		this.Content[Index].PreDelete();

	History.Add(new CChangesDocumentRemoveItem(this, 0, this.Content.slice(0, this.Content.length)));
	this.Content = [];
};
//-----------------------------------------------------------------------------------
// Функции для работы с номерами страниц
//-----------------------------------------------------------------------------------
CDocumentContent.prototype.Get_StartPage_Absolute = function()
{
	return this.Get_AbsolutePage(0);
};
CDocumentContent.prototype.Get_StartPage_Relative = function()
{
	return this.StartPage;
};
CDocumentContent.prototype.Get_StartColumn_Absolute = function()
{
	return this.Get_AbsoluteColumn(0);
};
CDocumentContent.prototype.Set_StartPage = function(StartPage, StartColumn, ColumnsCount)
{
	this.StartPage    = StartPage;
	this.StartColumn  = undefined !== StartColumn ? StartColumn : 0;
	this.ColumnsCount = undefined !== ColumnsCount ? ColumnsCount : 1;
};
CDocumentContent.prototype.Get_ColumnsCount = function()
{
	return this.ColumnsCount;
};
CDocumentContent.prototype.private_GetRelativePageIndex = function(CurPage)
{
	if (!this.ColumnsCount || 0 === this.ColumnsCount)
		return this.StartPage + CurPage;

	return this.StartPage + ((this.StartColumn + CurPage) / this.ColumnsCount | 0);
};
CDocumentContent.prototype.private_GetAbsolutePageIndex = function(CurPage)
{
	return this.Parent.Get_AbsolutePage(this.private_GetRelativePageIndex(CurPage));
};
CDocumentContent.prototype.Get_StartColumn = function()
{
	return this.StartColumn;
};
CDocumentContent.prototype.Get_AbsolutePage = function(CurPage)
{
	return this.private_GetAbsolutePageIndex(CurPage);
};
CDocumentContent.prototype.Get_AbsoluteColumn = function(CurPage)
{
	return this.private_GetColumnIndex(CurPage);
};
CDocumentContent.prototype.private_GetColumnIndex = function(CurPage)
{
	// TODO: Разобраться здесь нужно ли данное условие. Оно появилось из-за параграфов в таблице в
	//       основной части документа и из-за параграфов в сносках.
	if (1 === this.ColumnsCount)
    	return this.Parent.Get_AbsoluteColumn(this.private_GetRelativePageIndex(CurPage));

	return (this.StartColumn + CurPage) - (((this.StartColumn + CurPage) / this.ColumnsCount | 0) * this.ColumnsCount);
};
//-----------------------------------------------------------------------------------
// Undo/Redo функции
//-----------------------------------------------------------------------------------
CDocumentContent.prototype.GetSelectionState = function()
{
	var DocState    = {};
	DocState.CurPos = {
		X          : this.CurPos.X,
		Y          : this.CurPos.Y,
		ContentPos : this.CurPos.ContentPos,
		RealX      : this.CurPos.RealX,
		RealY      : this.CurPos.RealY,
		Type       : this.CurPos.Type
	};

	DocState.Selection = {

		Start    : this.Selection.Start,
		Use      : this.Selection.Use,
		StartPos : this.Selection.StartPos,
		EndPos   : this.Selection.EndPos,
		Flag     : this.Selection.Flag,
		Data     : this.Selection.Data
	};

	DocState.CurPage = this.CurPage;

	var State = null;

	if (this.LogicDocument && true === editor.isStartAddShape && docpostype_DrawingObjects === this.CurPos.Type)
	{
		DocState.CurPos.Type     = docpostype_Content;
		DocState.Selection.Start = false;
		DocState.Selection.Use   = false;

		this.Content[DocState.CurPos.ContentPos].RemoveSelection();
		State = this.Content[this.CurPos.ContentPos].GetSelectionState();
	}
	else
	{
		// Работаем с колонтитулом
		if (docpostype_DrawingObjects === this.CurPos.Type)
			State = this.LogicDocument.DrawingObjects.getSelectionState();
		else if (docpostype_Content === this.CurPos.Type)
		{
			if (true === this.Selection.Use)
			{
				// Выделение нумерации
				if (selectionflag_Numbering == this.Selection.Flag)
					State = [];
				else
				{
					var StartPos = this.Selection.StartPos;
					var EndPos   = this.Selection.EndPos;
					if (StartPos > EndPos)
					{
						var Temp = StartPos;
						StartPos = EndPos;
						EndPos   = Temp;
					}

					State = [];

					var TempState = [];
					for (var Index = StartPos; Index <= EndPos; Index++)
					{
						TempState.push(this.Content[Index].GetSelectionState());
					}

					State.push(TempState);
				}
			}
			else
				State = this.Content[this.CurPos.ContentPos].GetSelectionState();
		}
	}

	if (null != this.Selection.Data && true === this.Selection.Data.TableBorder)
	{
		DocState.Selection.Data = null;
	}

	State.push(DocState);
	return State;
};
CDocumentContent.prototype.SetSelectionState = function(State, StateIndex)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
		this.LogicDocument.DrawingObjects.resetSelection();

	if (State.length <= 0)
		return;

	var DocState = State[StateIndex];

	this.CurPos = {
		X          : DocState.CurPos.X,
		Y          : DocState.CurPos.Y,
		ContentPos : DocState.CurPos.ContentPos,
		RealX      : DocState.CurPos.RealX,
		RealY      : DocState.CurPos.RealY,
		Type       : DocState.CurPos.Type
	};

	this.Set_DocPosType(DocState.CurPos.Type);

	this.Selection = {

		Start    : DocState.Selection.Start,
		Use      : DocState.Selection.Use,
		StartPos : DocState.Selection.StartPos,
		EndPos   : DocState.Selection.EndPos,
		Flag     : DocState.Selection.Flag,
		Data     : DocState.Selection.Data
	};

	this.CurPage = DocState.CurPage;

	var NewStateIndex = StateIndex - 1;

	// Работаем с колонтитулом
	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		this.LogicDocument.DrawingObjects.setSelectionState(State, NewStateIndex);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (true === this.Selection.Use)
		{
			if (selectionflag_Numbering == this.Selection.Flag)
			{
				if (type_Paragraph === this.Content[this.Selection.StartPos].Get_Type())
				{
					var NumPr = this.Content[this.Selection.StartPos].GetNumPr();
					if (undefined !== NumPr)
						this.SelectNumbering(NumPr, this.Content[this.Selection.StartPos]);
					else
						this.LogicDocument.RemoveSelection();
				}
				else
					this.LogicDocument.RemoveSelection();
			}
			else
			{
				var StartPos = this.Selection.StartPos;
				var EndPos   = this.Selection.EndPos;
				if (StartPos > EndPos)
				{
					var Temp = StartPos;
					StartPos = EndPos;
					EndPos   = Temp;
				}

				var CurState = State[NewStateIndex];

				for (var Index = StartPos; Index <= EndPos; Index++)
				{
					this.Content[Index].SetSelectionState(CurState[Index - StartPos], CurState[Index - StartPos].length - 1);
				}
			}
		}
		else
		{
			this.Content[this.CurPos.ContentPos].SetSelectionState(State, NewStateIndex);
		}
	}
};
CDocumentContent.prototype.Get_ParentObject_or_DocumentPos = function()
{
    return this.Parent.Get_ParentObject_or_DocumentPos();
};
CDocumentContent.prototype.Refresh_RecalcData = function(Data)
{
	var bNeedRecalc = false;

	var Type = Data.Type;

	var CurPage = 0;

	switch (Type)
	{
		case AscDFH.historyitem_DocumentContent_AddItem:
		case AscDFH.historyitem_DocumentContent_RemoveItem:
		{
			for (CurPage = this.Pages.length - 1; CurPage > 0; CurPage--)
			{
				if (Data.Pos > this.Pages[CurPage].Pos)
					break;
			}

			bNeedRecalc = true;
			break;
		}
	}

	this.Refresh_RecalcData2(0, CurPage);
};
CDocumentContent.prototype.Refresh_RecalcData2 = function(Index, Page_rel)
{
	this.Parent.Refresh_RecalcData2(this.StartPage + Page_rel);
};
//-----------------------------------------------------------------------------------
// Функции для работы с гиперссылками
//-----------------------------------------------------------------------------------
CDocumentContent.prototype.AddHyperlink = function(HyperProps)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.hyperlinkAdd(HyperProps);
	}
	else if (docpostype_Content === this.CurPos.Type
		&& (false === this.Selection.Use || this.Selection.StartPos === this.Selection.EndPos))
	{
		var Pos = ( true == this.Selection.Use ? this.Selection.StartPos : this.CurPos.ContentPos );
		this.Content[Pos].AddHyperlink(HyperProps);
	}
};
CDocumentContent.prototype.ModifyHyperlink = function(HyperProps)
{
	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.hyperlinkModify(HyperProps);
	}
	else if (docpostype_Content == this.CurPos.Type
		&& (false === this.Selection.Use || this.Selection.StartPos === this.Selection.EndPos))
	{
		var Pos = ( true == this.Selection.Use ? this.Selection.StartPos : this.CurPos.ContentPos );
		this.Content[Pos].ModifyHyperlink(HyperProps);
	}
};
CDocumentContent.prototype.RemoveHyperlink = function()
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.hyperlinkRemove();
	}
	else if (docpostype_Content == this.CurPos.Type
		&& (false === this.Selection.Use || this.Selection.StartPos === this.Selection.EndPos))
	{
		var Pos = ( true == this.Selection.Use ? this.Selection.StartPos : this.CurPos.ContentPos );
		this.Content[Pos].RemoveHyperlink();
	}
};
CDocumentContent.prototype.CanAddHyperlink = function(bCheckInHyperlink)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.hyperlinkCanAdd(bCheckInHyperlink);
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (true === this.Selection.Use)
		{
			switch (this.Selection.Flag)
			{
				case selectionflag_Numbering:
					return false;
				case selectionflag_Common:
				{
					if (this.Selection.StartPos != this.Selection.EndPos)
						return false;

					return this.Content[this.Selection.StartPos].CanAddHyperlink(bCheckInHyperlink);
				}
			}
		}
		else
			return this.Content[this.CurPos.ContentPos].CanAddHyperlink(bCheckInHyperlink);
	}

	return false;
};
CDocumentContent.prototype.IsCursorInHyperlink = function(bCheckEnd)
{
	if (docpostype_DrawingObjects == this.CurPos.Type)
	{
		return this.LogicDocument.DrawingObjects.hyperlinkCheck(bCheckEnd);
	}
	else //if ( docpostype_Content == this.CurPos.Type )
	{
		if (true === this.Selection.Use)
		{
			switch (this.Selection.Flag)
			{
				case selectionflag_Numbering:
					return null;
				case selectionflag_Common:
				{
					if (this.Selection.StartPos != this.Selection.EndPos)
						return null;

					return this.Content[this.Selection.StartPos].IsCursorInHyperlink(bCheckEnd);
				}
			}
		}
		else
		{
			return this.Content[this.CurPos.ContentPos].IsCursorInHyperlink(bCheckEnd);
		}
	}

	return null;
};
//-----------------------------------------------------------------------------------
// Функции для работы с совместным редактирования
//-----------------------------------------------------------------------------------
CDocumentContent.prototype.Write_ToBinary2 = function(Writer)
{
	Writer.WriteLong(AscDFH.historyitem_type_DocumentContent);

	// String : Id текущего элемента
	// Long   : StartPage
	// String : Id родительского класса
	// Bool   : TurnOffInnerWrap
	// Bool   : Split
	// Long   : Количество элементов в массиве this.Content
	// Array of string : массив Id элементов

	Writer.WriteString2(this.Id);
	Writer.WriteLong(this.StartPage);
	Writer.WriteString2(this.Parent.Get_Id());
	Writer.WriteBool(this.TurnOffInnerWrap);
	Writer.WriteBool(this.Split);
	AscFormat.writeBool(Writer, this.bPresentation);


	var ContentToWrite;
	if (this.StartState)
	{
		ContentToWrite = this.StartState.Content;
	}
	else
	{
		ContentToWrite = this.Content;
	}

	var Count = ContentToWrite.length;
	Writer.WriteLong(Count);
	for (var Index = 0; Index < Count; Index++)
		Writer.WriteString2(ContentToWrite[Index].Get_Id());

	if (this.Parent && this.Parent.Get_Worksheet)
	{
		Writer.WriteBool(true);
		var worksheet = this.Parent.Get_Worksheet();
		if (worksheet)
		{
			Writer.WriteBool(true);
			Writer.WriteString2(worksheet.getId())
		}
		else
		{
			Writer.WriteBool(false);
		}
	}
	else
	{
		Writer.WriteBool(false);
	}
};
CDocumentContent.prototype.Read_FromBinary2 = function(Reader)
{
	// String : Id текущего элемента
	// Long   : StartPage
	// String : Id родительского класса
	// Bool   : TurnOffInnerWrap
	// Bool   : Split
	// Long   : Количество элементов в массиве this.Content
	// Array of string : массив Id элементов

	var LinkData = {};

	this.Id               = Reader.GetString2();
	this.StartPage        = Reader.GetLong();
	LinkData.Parent       = Reader.GetString2();
	this.TurnOffInnerWrap = Reader.GetBool();
	this.Split            = Reader.GetBool();
	this.bPresentation    = AscFormat.readBool(Reader);

	var Count    = Reader.GetLong();
	this.Content = [];
	for (var Index = 0; Index < Count; Index++)
	{
		var Element = g_oTableId.Get_ById(Reader.GetString2());
		if (null != Element)
		{
			this.Content.push(Element);
			Element.Parent = this;
		}
	}

	AscCommon.CollaborativeEditing.Add_LinkData(this, LinkData);

	var b_worksheet = Reader.GetBool();
	if (b_worksheet)
	{
		this.Parent        = g_oTableId.Get_ById(LinkData.Parent);
		var b_worksheet_id = Reader.GetBool();
		if (b_worksheet_id)
		{
			var id  = Reader.GetString2();
			var api = window["Asc"]["editor"];
			if (api.wb)
			{
				var worksheet = api.wbModel.getWorksheetById(id);
				if (worksheet)
				{
					this.DrawingDocument = worksheet.DrawingDocument;
				}
			}
		}
	}
	else
	{
		var DrawingDocument;
		if (editor && editor.WordControl && editor.WordControl.m_oDrawingDocument)
			DrawingDocument = editor.WordControl.m_oDrawingDocument;
		if (undefined !== DrawingDocument && null !== DrawingDocument)
		{
			this.DrawingDocument = DrawingDocument;

			if (undefined !== editor && true === editor.isDocumentEditor)
			{
				this.LogicDocument  = DrawingDocument.m_oLogicDocument;
				this.Styles         = DrawingDocument.m_oLogicDocument.Get_Styles();
				this.Numbering      = DrawingDocument.m_oLogicDocument.Get_Numbering();
				this.DrawingObjects = DrawingDocument.m_oLogicDocument.DrawingObjects; // Массив укзателей на все инлайновые графические объекты
			}
		}
	}
};
CDocumentContent.prototype.Load_LinkData = function(LinkData)
{
	if ("undefined" != typeof(LinkData.Parent))
		this.Parent = g_oTableId.Get_ById(LinkData.Parent);

	if (this.Parent.getDrawingDocument)
	{
		this.DrawingDocument = this.Parent.getDrawingDocument();
		for (var i = 0; i < this.Content.length; ++i)
		{
			this.Content[i].DrawingDocument = this.DrawingDocument;
		}
	}
};
CDocumentContent.prototype.Get_SelectionState2 = function()
{
    // Сохраняем Id ближайшего элемента в текущем классе
    var State = new CDocumentSelectionState();

    State.Id   = this.Get_Id();
    State.Type = docpostype_Content;

    var Element = this.Content[this.CurPos.ContentPos];
    State.Data  = Element.Get_SelectionState2();

    return State;
};
CDocumentContent.prototype.Set_SelectionState2 = function(State)
{
    var ElementId = State.Data.Id;

    var CurId = ElementId;

    var bFlag = false;

    var Pos = 0;

    // Найдем элемент с Id = CurId
    var Count = this.Content.length;
    for (Pos = 0; Pos < Count; Pos++)
    {
        if (this.Content[Pos].Get_Id() == CurId)
        {
            bFlag = true;
            break;
        }
    }

    if (true !== bFlag)
    {
        var TempElement = g_oTableId.Get_ById(CurId);
        Pos             = ( null != TempElement ? Math.min(this.Content.length - 1, TempElement.Index) : 0 );
    }

    this.Selection.Start    = false;
    this.Selection.Use      = false;
    this.Selection.StartPos = Pos;
    this.Selection.EndPos   = Pos;
    this.Selection.Flag     = selectionflag_Common;

    this.Set_DocPosType(docpostype_Content);
    this.CurPos.ContentPos = Pos;

    if (true !== bFlag)
        this.Content[this.CurPos.ContentPos].MoveCursorToStartPos();
    else
    {
        this.Content[this.CurPos.ContentPos].Set_SelectionState2(State.Data);
    }
};
//-----------------------------------------------------------------------------------
// Функции для работы с комментариями
//-----------------------------------------------------------------------------------
CDocumentContent.prototype.AddComment = function(Comment, bStart, bEnd)
{
	if (true === this.ApplyToAll)
	{
		if (this.Content.length <= 1 && true === bStart && true === bEnd)
		{
			this.Content[0].Set_ApplyToAll(true);
			this.Content[0].AddComment(Comment, true, true);
			this.Content[0].Set_ApplyToAll(false);
		}
		else
		{
			if (true === bStart)
			{
				this.Content[0].Set_ApplyToAll(true);
				this.Content[0].AddComment(Comment, true, false);
				this.Content[0].Set_ApplyToAll(false);
			}

			if (true === bEnd)
			{
				this.Content[this.Content.length - 1].Set_ApplyToAll(true);
				this.Content[this.Content.length - 1].AddComment(Comment, false, true);
				this.Content[this.Content.length - 1].Set_ApplyToAll(true);
			}
		}
	}
	else
	{
		if (docpostype_DrawingObjects === this.CurPos.Type)
		{
			return this.LogicDocument.DrawingObjects.addComment(Comment);
		}
		else //if ( docpostype_Content === this.CurPos.Type )
		{
			if (selectionflag_Numbering === this.Selection.Flag)
				return;

			if (true === this.Selection.Use)
			{
				var StartPos, EndPos;
				if (this.Selection.StartPos < this.Selection.EndPos)
				{
					StartPos = this.Selection.StartPos;
					EndPos   = this.Selection.EndPos;
				}
				else
				{
					StartPos = this.Selection.EndPos;
					EndPos   = this.Selection.StartPos;
				}

				if (StartPos === EndPos)
					this.Content[StartPos].AddComment(Comment, bStart, bEnd);
				else
				{
					if (true === bStart)
						this.Content[StartPos].AddComment(Comment, true, false);

					if (true === bEnd)
						this.Content[EndPos].AddComment(Comment, false, true);
				}
			}
			else
			{
				this.Content[this.CurPos.ContentPos].AddComment(Comment, bStart, bEnd);
			}
		}
	}
};
CDocumentContent.prototype.CanAddComment = function()
{
	if (true === this.ApplyToAll)
	{
		if (this.Content.length > 1)
			return true;
		else
			return this.Content[0].CanAddComment();
	}
	else
	{
		if (docpostype_DrawingObjects === this.CurPos.Type)
		{
			if (true != this.LogicDocument.DrawingObjects.isSelectedText())
				return true;
			else
				return this.LogicDocument.DrawingObjects.canAddComment();
		}
		else //if ( docpostype_Content === this.CurPos.Type )
		{
			switch (this.Selection.Flag)
			{
				case selectionflag_Numbering:
					return false;
				case selectionflag_Common:
				{
					if (true === this.Selection.Use && this.Selection.StartPos != this.Selection.EndPos)
						return true;
					else
					{
						var Pos     = ( this.Selection.Use === true ? this.Selection.StartPos : this.CurPos.ContentPos );
						var Element = this.Content[Pos];
						return Element.CanAddComment();
					}
				}
			}
		}
	}

	return false;
};
CDocumentContent.prototype.GetSelectionBounds = function()
{
	if (true === this.Selection.Use && selectionflag_Common === this.Selection.Flag)
	{
		var Start = this.Selection.StartPos;
		var End   = this.Selection.EndPos;

		if (Start > End)
		{
			Start = this.Selection.EndPos;
			End   = this.Selection.StartPos;
		}

		if (Start === End)
			return this.Content[Start].GetSelectionBounds();
		else
		{
			var Result       = {};
			Result.Start     = this.Content[Start].GetSelectionBounds().Start;
			Result.End       = this.Content[End].GetSelectionBounds().End;
			Result.Direction = (this.Selection.StartPos > this.Selection.EndPos ? -1 : 1);
			return Result;
		}
	}

	return null;
};
CDocumentContent.prototype.GetSelectionAnchorPos = function()
{
	var Pos = ( true === this.Selection.Use ? ( this.Selection.StartPos < this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos ) : this.CurPos.ContentPos );
	return this.Content[Pos].GetSelectionAnchorPos();
};
CDocumentContent.prototype.GetEndInfo = function()
{
	var ContentLen = this.Content.length;
	if (ContentLen > 0)
		return this.Content[ContentLen - 1].GetEndInfo();
	else
		return null;
};
CDocumentContent.prototype.GetPrevElementEndInfo = function(CurElement)
{
	var PrevElement = CurElement.Get_DocumentPrev();

	if (null !== PrevElement && undefined !== PrevElement)
	{
		return PrevElement.GetEndInfo();
	}
	else
	{
		return this.Parent.GetPrevElementEndInfo(this);
	}
};
CDocumentContent.prototype.GetTopElement = function()
{
    if (this.Parent)
        return this.Parent.GetTopElement();

    return null;
};
CDocumentContent.prototype.CompareDrawingsLogicPositions = function(CompareObject)
{
    for (var Index = 0, Count = this.Content.length; Index < Count; Index++)
    {
        var Element = this.Content[Index];
        Element.CompareDrawingsLogicPositions(CompareObject);

        if (0 !== CompareObject.Result)
            return;
    }
};
CDocumentContent.prototype.StartSelectionFromCurPos = function()
{
    if (docpostype_DrawingObjects === this.CurPos.Type)
    {
        return this.DrawingObjects.startSelectionFromCurPos();
    }
    else //if (docpostype_Content === this.CurPos.Type)
    {
        this.Selection.Use      = true;
        this.Selection.Start    = false;
        this.Selection.StartPos = this.CurPos.ContentPos;
        this.Selection.EndPos   = this.CurPos.ContentPos;
        this.Content[this.CurPos.ContentPos].StartSelectionFromCurPos();
    }
};
CDocumentContent.prototype.GetStyleFromFormatting = function()
{
    if (docpostype_DrawingObjects === this.CurPos.Type)
    {
        return this.DrawingObjects.GetStyleFromFormatting();
    }
    else //if (docpostype_Content === this.CurPos.Type)
    {
        if (true == this.Selection.Use)
        {
            if (this.Selection.StartPos > this.Selection.EndPos)
                return this.Content[this.Selection.EndPos].GetStyleFromFormatting();
            else
                return this.Content[this.Selection.StartPos].GetStyleFromFormatting();
        }
        else
        {
            return this.Content[this.CurPos.ContentPos].GetStyleFromFormatting();
        }
    }
};
CDocumentContent.prototype.Is_TrackRevisions = function()
{
    if (this.LogicDocument)
        return this.LogicDocument.Is_TrackRevisions();

    return false;
};
CDocumentContent.prototype.Get_SectPr = function()
{
    if (this.Parent && this.Parent.Get_SectPr)
        return this.Parent.Get_SectPr();

    return null;
};
CDocumentContent.prototype.SetParagraphFramePr = function(FramePr, bDelete)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		// Не добавляем и не работаем с рамками в автофигурах
		return;
	}
	else //if ( docpostype_Content === this.CurPos.Type )
	{
		if (true === this.Selection.Use)
		{
			// Проверим, если у нас все выделенные элементы - параграфы, с одинаковыми настройками
			// FramePr, тогда мы можем применить новую настройку FramePr

			var StartPos = this.Selection.StartPos;
			var EndPos   = this.Selection.EndPos;

			if (StartPos > EndPos)
			{
				StartPos = this.Selection.EndPos;
				EndPos   = this.Selection.StartPos;
			}

			var Element = this.Content[StartPos];

			if (type_Paragraph !== Element.GetType() || undefined === Element.Get_FramePr())
				return;

			var FramePr = Element.Get_FramePr();
			for (var Pos = StartPos + 1; Pos < EndPos; Pos++)
			{
				var TempElement = this.Content[Pos];

				if (type_Paragraph !== TempElement.GetType() || undefined === TempElement.Get_FramePr() || true != FramePr.Compare(TempElement.Get_FramePr()))
					return;
			}

			// Раз дошли до сюда, значит можно у всех выделенных параграфов менять настройку рамки
			var FrameParas = this.Content[StartPos].Internal_Get_FrameParagraphs();
			var FrameCount = FrameParas.length;
			for (var Pos = 0; Pos < FrameCount; Pos++)
			{
				FrameParas[Pos].Set_FramePr(FramePr, bDelete);
			}
		}
		else
		{
			var Element = this.Content[this.CurPos.ContentPos];

			if (type_Paragraph !== Element.GetType())
				return;

			// Возможно, предыдущий элемент является буквицей
			if (undefined === Element.Get_FramePr())
			{
				var PrevElement = Element.Get_DocumentPrev();

				if (type_Paragraph !== PrevElement.GetType() || undefined === PrevElement.Get_FramePr() || undefined === PrevElement.Get_FramePr().DropCap)
					return;

				Element = PrevElement;
			}

			var FrameParas = Element.Internal_Get_FrameParagraphs();
			var FrameCount = FrameParas.length;
			for (var Pos = 0; Pos < FrameCount; Pos++)
			{
				FrameParas[Pos].Set_FramePr(FramePr, bDelete);
			}
		}
	}
};
CDocumentContent.prototype.Add_ToContent = function(Pos, Item)
{
    this.Internal_Content_Add(Pos, Item);
};
CDocumentContent.prototype.Remove_FromContent = function(Pos, Count)
{
    this.Internal_Content_Remove(Pos, Count);
};
CDocumentContent.prototype.Concat_Paragraphs = function(Pos)
{
    if (Pos < this.Content.length - 1 && type_Paragraph === this.Content[Pos].Get_Type() && type_Paragraph === this.Content[Pos + 1].Get_Type())
    {
        var Para1 = this.Content[Pos];
        var Para2 = this.Content[Pos + 1];

        var OldSelectionStartPos = this.Selection.StartPos;
        var OldSelectionEndPos   = this.Selection.EndPos;
        var OldCurPos            = this.CurPos.ContentPos;

        Para1.Concat(Para2);
        this.Remove_FromContent(Pos + 1, 1);

        if (OldCurPos > Pos)
            this.CurPos.ContentPos = OldCurPos - 1;

        if (OldSelectionStartPos > Pos)
            this.Selection.StartPos = OldSelectionStartPos - 1;

        if (OldSelectionEndPos > Pos)
            this.Selection.EndPos = OldSelectionEndPos - 1;
    }
};
CDocumentContent.prototype.GetContentPosition = function(bSelection, bStart, PosArray)
{
    if (undefined === PosArray)
        PosArray = [];

    var Pos = (true === bSelection ? (true === bStart ? this.Selection.StartPos : this.Selection.EndPos) : this.CurPos.ContentPos);
    PosArray.push({Class : this, Position : Pos});

    if (undefined !== this.Content[Pos] && this.Content[Pos].GetContentPosition)
        this.Content[Pos].GetContentPosition(bSelection, bStart, PosArray);

    return PosArray;
};
CDocumentContent.prototype.GetDocumentPositionFromObject = function(PosArray)
{
    if (!PosArray)
        PosArray = [];

    if (this.Parent && this.Parent.GetDocumentPositionFromObject)
        this.Parent.GetDocumentPositionFromObject(PosArray);

    return PosArray;
};
CDocumentContent.prototype.SetContentSelection = function(StartDocPos, EndDocPos, Depth, StartFlag, EndFlag)
{
    if ((0 === StartFlag && (!StartDocPos[Depth] || this !== StartDocPos[Depth].Class)) || (0 === EndFlag && (!EndDocPos[Depth] || this !== EndDocPos[Depth].Class)))
        return;

    if (this.Content.length <= 0)
        return;

    var StartPos = 0, EndPos = 0;
    switch (StartFlag)
    {
        case 0 : StartPos = StartDocPos[Depth].Position; break;
        case 1 : StartPos = 0; break;
        case -1: StartPos = this.Content.length - 1; break;
    }

    switch (EndFlag)
    {
        case 0 : EndPos = EndDocPos[Depth].Position; break;
        case 1 : EndPos = 0; break;
        case -1: EndPos = this.Content.length - 1; break;
    }

    var _StartDocPos = StartDocPos, _StartFlag = StartFlag;
    if (null !== StartDocPos && true === StartDocPos[Depth].Deleted)
    {
        if (StartPos < this.Content.length)
        {
            _StartDocPos = null;
            _StartFlag = 1;
        }
        else if (StartPos > 0)
        {
            StartPos--;
            _StartDocPos = null;
            _StartFlag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    var _EndDocPos = EndDocPos, _EndFlag = EndFlag;
    if (null !== EndDocPos && true === EndDocPos[Depth].Deleted)
    {
        if (EndPos < this.Content.length)
        {
            _EndDocPos = null;
            _EndFlag = 1;
        }
        else if (EndPos > 0)
        {
            EndPos--;
            _EndDocPos = null;
            _EndFlag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    StartPos = Math.min(this.Content.length - 1, Math.max(0, StartPos));
    EndPos   = Math.min(this.Content.length - 1, Math.max(0, EndPos));

    this.Selection.Use      = true;
    this.Selection.StartPos = StartPos;
    this.Selection.EndPos   = EndPos;

    if (StartPos !== EndPos)
    {
        this.Content[StartPos].SetContentSelection(_StartDocPos, null, Depth + 1, _StartFlag, StartPos > EndPos ? 1 : -1);
        this.Content[EndPos].SetContentSelection(null, _EndDocPos, Depth + 1, StartPos > EndPos ? -1 : 1, _EndFlag);

        var _StartPos = StartPos;
        var _EndPos = EndPos;
        var Direction = 1;

        if (_StartPos > _EndPos)
        {
            _StartPos = EndPos;
            _EndPos = StartPos;
            Direction = -1;
        }

        for (var CurPos = _StartPos + 1; CurPos < _EndPos; CurPos++)
        {
            this.Content[CurPos].SelectAll(Direction);
        }
    }
    else
    {
        this.Content[StartPos].SetContentSelection(_StartDocPos, _EndDocPos, Depth + 1, _StartFlag, _EndFlag);
    }
};
CDocumentContent.prototype.SetContentPosition = function(DocPos, Depth, Flag)
{
    if (0 === Flag && (!DocPos[Depth] || this !== DocPos[Depth].Class))
        return;

    if (this.Content.length <= 0)
        return;

    var Pos = 0;
    switch (Flag)
    {
        case 0 : Pos = DocPos[Depth].Position; break;
        case 1 : Pos = 0; break;
        case -1: Pos = this.Content.length - 1; break;
    }

    var _DocPos = DocPos, _Flag = Flag;
    if (null !== DocPos && true === DocPos[Depth].Deleted)
    {
        if (Pos < this.Content.length)
        {
            _DocPos = null;
            _Flag = 1;
        }
        else if (Pos > 0)
        {
            Pos--;
            _DocPos = null;
            _Flag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    Pos = Math.min(this.Content.length - 1, Math.max(0, Pos));
    this.CurPos.ContentPos = Pos;
    this.Content[Pos].SetContentPosition(_DocPos, Depth + 1, _Flag);
};
CDocumentContent.prototype.private_GetElementPageIndex = function(ElementPos, PageIndex, ColumnIndex, ColumnsCount)
{
    var Element = this.Content[ElementPos];
    if (!Element || Element.GetPagesCount() <= 0)
        return 0;

    var StartPage   = Element.Get_StartPage_Relative();
    var StartColumn = Element.Get_StartColumn();

    return ColumnIndex - StartColumn + (PageIndex - StartPage) * ColumnsCount;
};
CDocumentContent.prototype.private_GetElementPageIndexByXY = function(ElementPos, X, Y, PageIndex)
{
    return this.private_GetElementPageIndex(ElementPos, PageIndex, 0, 1);
};
CDocumentContent.prototype.GetTopDocumentContent = function()
{
    var TopDocument = null;
    if (this.Parent && this.Parent.GetTopDocumentContent)
        TopDocument = this.Parent.GetTopDocumentContent();

    if (null !== TopDocument && undefined !== TopDocument)
        return TopDocument;

    return this;
};
CDocumentContent.prototype.private_RecalculateNumbering = function(Elements)
{
    if (true === AscCommon.g_oIdCounter.m_bLoad || true === AscCommon.g_oIdCounter.m_bRead || true === this.bPresentation)
        return;

    for (var Index = 0, Count = Elements.length; Index < Count; ++Index)
    {
        var Element = Elements[Index];
        if (type_Paragraph === Element.Get_Type())
            History.Add_RecalcNumPr(Element.GetNumPr());
        else if (type_Paragraph === Element.Get_Type())
        {
            var ParaArray = [];
            Element.GetAllParagraphs({All : true}, ParaArray);

            for (var ParaIndex = 0, ParasCount = ParaArray.length; ParaIndex < ParasCount; ++ParaIndex)
            {
                var Para = ParaArray[ParaIndex];
                History.Add_RecalcNumPr(Para.GetNumPr());
            }
        }
    }
};
CDocumentContent.prototype.Set_ParaPropsForVerticalTextInCell = function(isVerticalText)
{
    for (var Pos = 0, Count = this.Content.length; Pos < Count; ++Pos)
    {
        var Element = this.Content[Pos];
        if (type_Paragraph === Element.Get_Type())
            Element.Set_ParaPropsForVerticalTextInCell(isVerticalText);
    }
};
CDocumentContent.prototype.Set_LogicDocument = function(oLogicDocument)
{
    this.LogicDocument   = oLogicDocument;
    this.Styles          = oLogicDocument.Get_Styles();
    this.Numbering       = oLogicDocument.Get_Numbering();
    this.DrawingObjects  = oLogicDocument.DrawingObjects;
};
CDocumentContent.prototype.Get_LogicDocument = function()
{
	return this.LogicDocument;
};
CDocumentContent.prototype.RemoveTextSelection = function()
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		this.DrawingObjects.removeTextSelection();
	}
	else
	{
		this.RemoveSelection();
	}
};
CDocumentContent.prototype.CanUpdateTarget = function(CurPage)
{
	if (this.Pages.length <= 0)
		return false;

	if (this.Pages.length <= CurPage)
		return true;

	var nPos = (this.Selection.Use ? this.Selection.EndPos : this.CurPos.ContentPos);


	if (this.Pages[CurPage].EndPos > nPos)
		return true;
	else if (this.Pages[CurPage].EndPos < nPos)
		return false;

	var nElementPageIndex = this.private_GetElementPageIndex(nPos, CurPage, 0, 1);
	return this.Content[nPos].CanUpdateTarget(nElementPageIndex);
};
CDocumentContent.prototype.IsStartFromNewPage = function()
{
	if (this.Content.length <= 0)
		return false;

	return this.Content[0].IsStartFromNewPage();
};
CDocumentContent.prototype.PreDelete = function()
{
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		this.Content[nIndex].PreDelete();
	}
};
CDocumentContent.prototype.IsBlockLevelSdtContent = function()
{
	return (this.Parent && this.Parent instanceof CBlockLevelSdt);
};
CDocumentContent.prototype.IsBlockLevelSdtFirstOnNewPage = function()
{
	if (this.Parent && this.Parent instanceof CBlockLevelSdt)
		return this.Parent.IsBlockLevelSdtFirstOnNewPage();

	return false;
};
CDocumentContent.prototype.IsSelectedAll = function()
{
	if (true === this.Selection.Use
		&& ((0 === this.Selection.StartPos && this.Content.length - 1 === this.Selection.EndPos)
		|| (0 === this.Selection.EndPos && this.Content.length - 1 === this.Selection.StartPos))
		&& true === this.Content[0].IsSelectedAll()
		&& true === this.Content[this.Content.length - 1].IsSelectedAll())
		return true;

	return false;
};
CDocumentContent.prototype.AddContentControl = function(nContentControlType)
{
	if (docpostype_DrawingObjects === this.CurPos.Type)
		return this.DrawingObjects.AddContentControl(nContentControlType);
	else
		return this.private_AddContentControl(nContentControlType);
};
CDocumentContent.prototype.GetAllContentControls = function(arrContentControls)
{
	if (!arrContentControls)
		arrContentControls = [];

	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		this.Content[nIndex].GetAllContentControls(arrContentControls);
	}

	return arrContentControls;
};
CDocumentContent.prototype.GetMargins = function()
{
	if (this.Parent.GetMargins)
		return this.Parent.GetMargins();

	return {
		Top    : new CTableMeasurement(tblwidth_Mm, 0),
		Left   : new CTableMeasurement(tblwidth_Mm, 0),
		Bottom : new CTableMeasurement(tblwidth_Mm, 0),
		Right  : new CTableMeasurement(tblwidth_Mm, 0)
	};
};
CDocumentContent.prototype.IsEmptyPage = function(nCurPage)
{
	if (nCurPage < 0 || nCurPage >= this.Pages.length)
		return true;

	var nStartPos = this.Pages[nCurPage].Pos;
	var nEndPos   = this.Pages[nCurPage].EndPos;

	if (nStartPos > nEndPos)
		return true;

	if (nStartPos < nEndPos)
		return false;

	var nElementPageIndex = this.private_GetElementPageIndex(nStartPos, nCurPage, 0, 1);
	return this.Content[nStartPos].IsEmptyPage(nElementPageIndex);
};
CDocumentContent.prototype.GetParent = function()
{
	return this.Parent;
};

function CDocumentContentStartState(DocContent)
{
    this.Content = [];
    for(var i = 0; i < DocContent.Content.length; ++i)
    {
        this.Content.push(DocContent.Content[i]);
    }
}

function CDocumentRecalculateObject()
{
    this.StartPage = 0;
    
    this.Pages    = [];
    this.Content  = [];
    this.ClipInfo = [];
}

CDocumentRecalculateObject.prototype = 
{
    Save : function(Doc)
    {
        this.StartPage = Doc.StartPage;        
        this.Pages     = Doc.Pages;
        this.ClipInfo  = Doc.ClipInfo;

        var Content = Doc.Content;
        var Count = Content.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            this.Content[Index] = Content[Index].SaveRecalculateObject();
        }
    },
        
    Load : function(Doc)
    {
        Doc.StartPage = this.StartPage;
        Doc.Pages     = this.Pages;
        Doc.ClipInfo  = this.ClipInfo;
        
        var Count = Doc.Content.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            Doc.Content[Index].LoadRecalculateObject( this.Content[Index] );
        }
    },

	GetSummaryHeight : function()
    {
        var Height = 0;
        var PagesCount = this.Pages.length;
        for ( var Page = 0; Page < PagesCount; Page++ )
        {
            var Bounds = this.Get_PageBounds( Page );
            Height += Bounds.Bottom - Bounds.Top;
        }

        return Height;
    },
    
    Get_PageBounds : function(PageNum)
    {
        if ( this.Pages.length <= 0 )
            return { Top : 0, Left : 0, Right : 0, Bottom : 0 };

        if ( PageNum < 0 || PageNum > this.Pages.length )
            return this.Pages[0].Bounds;

        var Bounds = this.Pages[PageNum].Bounds;        

        return Bounds;
    },
    
    Get_DrawingFlowPos : function(FlowPos)
    {
        var Count = this.Content.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            this.Content[Index].Get_DrawingFlowPos( FlowPos );
        }
    }
        
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CDocumentContent = CDocumentContent;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 08.11.2016
 * Time: 14:03
 */

AscDFH.changesFactory[AscDFH.historyitem_DocumentContent_AddItem]    = CChangesDocumentContentAddItem;
AscDFH.changesFactory[AscDFH.historyitem_DocumentContent_RemoveItem] = CChangesDocumentContentRemoveItem;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_DocumentContent_AddItem]    = [
	AscDFH.historyitem_DocumentContent_AddItem,
	AscDFH.historyitem_DocumentContent_RemoveItem
];
AscDFH.changesRelationMap[AscDFH.historyitem_DocumentContent_RemoveItem] = [
	AscDFH.historyitem_DocumentContent_AddItem,
	AscDFH.historyitem_DocumentContent_RemoveItem
];
//----------------------------------------------------------------------------------------------------------------------

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesDocumentContentAddItem(Class, Pos, Items)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, true);
}
CChangesDocumentContentAddItem.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesDocumentContentAddItem.prototype.constructor = CChangesDocumentContentAddItem;
CChangesDocumentContentAddItem.prototype.Type = AscDFH.historyitem_DocumentContent_AddItem;
CChangesDocumentContentAddItem.prototype.Undo = function()
{
	var oDocument = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var Pos = true !== this.UseArray ? this.Pos : this.PosArray[nIndex];
		var Elements = oDocument.Content.splice(Pos, 1);
		oDocument.private_RecalculateNumbering(Elements);

		if (Pos > 0)
		{
			if (Pos <= oDocument.Content.length - 1)
			{
				oDocument.Content[Pos - 1].Next = oDocument.Content[Pos];
				oDocument.Content[Pos].Prev     = oDocument.Content[Pos - 1];
			}
			else
			{
				oDocument.Content[Pos - 1].Next = null;
			}
		}
		else if (Pos <= oDocument.Content.length - 1)
		{
			oDocument.Content[Pos].Prev = null;
		}
	}
};
CChangesDocumentContentAddItem.prototype.Redo = function()
{
	var oDocument = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var Element = this.Items[nIndex];
		var Pos     = true !== this.UseArray ? this.Pos + nIndex : this.PosArray[nIndex];

		oDocument.Content.splice(Pos, 0, Element);
		oDocument.private_RecalculateNumbering([Element]);

		if (Pos > 0)
		{
			oDocument.Content[Pos - 1].Next = Element;
			Element.Prev                    = oDocument.Content[Pos - 1];
		}
		else
		{
			Element.Prev = null;
		}

		if (Pos < oDocument.Content.length - 1)
		{
			oDocument.Content[Pos + 1].Prev = Element;
			Element.Next                    = oDocument.Content[Pos + 1];
		}
		else
		{
			Element.Next = null;
		}

		Element.Parent = oDocument;
	}
};
CChangesDocumentContentAddItem.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesDocumentContentAddItem.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesDocumentContentAddItem.prototype.Load = function(Color)
{
	if (this.PosArray.length <= 0 || this.Items.length <= 0)
		return;

	var oDocument = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var Pos     = oDocument.m_oContentChanges.Check(AscCommon.contentchanges_Add, true !== this.UseArray ? this.Pos + nIndex : this.PosArray[nIndex]);
		var Element = this.Items[nIndex];

		Pos = Math.min(Pos, oDocument.Content.length);

		if (null != Element)
		{
			if (Pos > 0)
			{
				oDocument.Content[Pos - 1].Next = Element;
				Element.Prev                    = oDocument.Content[Pos - 1];
			}
			else
			{
				Element.Prev = null;
			}

			if (Pos <= oDocument.Content.length - 1)
			{
				oDocument.Content[Pos].Prev = Element;
				Element.Next                = oDocument.Content[Pos];
			}
			else
			{
				Element.Next = null;
			}

			Element.Parent = oDocument;

			oDocument.Content.splice(Pos, 0, Element);
			oDocument.private_RecalculateNumbering([Element]);
			oDocument.private_ReindexContent(Pos);

			AscCommon.CollaborativeEditing.Update_DocumentPositionsOnAdd(oDocument, Pos);
		}
	}
};
CChangesDocumentContentAddItem.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_DocumentContent_AddItem === oChanges.Type || AscDFH.historyitem_DocumentContent_RemoveItem === oChanges.Type))
		return true;

	return false;
};
CChangesDocumentContentAddItem.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesDocumentContentRemoveItem);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesDocumentContentRemoveItem(Class, Pos, Items)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Items, false);
}
CChangesDocumentContentRemoveItem.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesDocumentContentRemoveItem.prototype.constructor = CChangesDocumentContentRemoveItem;
CChangesDocumentContentRemoveItem.prototype.Type = AscDFH.historyitem_DocumentContent_RemoveItem;
CChangesDocumentContentRemoveItem.prototype.Undo = function()
{
	if (!this.Items || this.Items.length <= 0)
		return;

	var oDocument = this.Class;

	var Array_start = oDocument.Content.slice(0, this.Pos);
	var Array_end   = oDocument.Content.slice(this.Pos);

	oDocument.private_RecalculateNumbering(this.Items);
	oDocument.Content = Array_start.concat(this.Items, Array_end);

	var nStartIndex = Math.max(this.Pos - 1, 0);
	var nEndIndex   = Math.min(oDocument.Content.length - 1, this.Pos + this.Items.length + 1);
	for (var nIndex = nStartIndex; nIndex <= nEndIndex; ++nIndex)
	{
		var oElement = oDocument.Content[nIndex];
		if (nIndex > 0)
			oElement.Prev = oDocument.Content[nIndex - 1];
		else
			oElement.Prev = null;

		if (nIndex < oDocument.Content.length - 1)
			oElement.Next = oDocument.Content[nIndex + 1];
		else
			oElement.Next = null;

		oElement.Parent = oDocument;
	}
};
CChangesDocumentContentRemoveItem.prototype.Redo = function()
{
	if (!this.Items || this.Items.length <= 0)
		return;

	var oDocument = this.Class;
	var Elements = oDocument.Content.splice(this.Pos, this.Items.length);
	oDocument.private_RecalculateNumbering(Elements);

	var Pos = this.Pos;
	if (Pos > 0)
	{
		if (Pos <= oDocument.Content.length - 1)
		{
			oDocument.Content[Pos - 1].Next = oDocument.Content[Pos];
			oDocument.Content[Pos].Prev     = oDocument.Content[Pos - 1];
		}
		else
		{
			oDocument.Content[Pos - 1].Next = null;
		}
	}
	else if (Pos <= oDocument.Content.length - 1)
	{
		oDocument.Content[Pos].Prev = null;
	}
};
CChangesDocumentContentRemoveItem.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesDocumentContentRemoveItem.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesDocumentContentRemoveItem.prototype.Load = function(Color)
{
	var oDocument = this.Class;
	for (var nIndex = 0, nCount = this.Items.length; nIndex < nCount; ++nIndex)
	{
		var Pos = oDocument.m_oContentChanges.Check(AscCommon.contentchanges_Remove, true !== this.UseArray ? this.Pos : this.PosArray[nIndex]);

		// действие совпало, не делаем его
		if (false === Pos)
			continue;

		var Elements = oDocument.Content.splice(Pos, 1);
		oDocument.private_RecalculateNumbering(Elements);
		AscCommon.CollaborativeEditing.Update_DocumentPositionsOnRemove(oDocument, Pos, 1);

		if (Pos > 0)
		{
			if (Pos <= oDocument.Content.length - 1)
			{
				oDocument.Content[Pos - 1].Next = oDocument.Content[Pos];
				oDocument.Content[Pos].Prev     = oDocument.Content[Pos - 1];
			}
			else
			{
				if (oDocument.Content[Pos - 1])
					oDocument.Content[Pos - 1].Next = null;
			}
		}
		else if (Pos <= oDocument.Content.length - 1)
		{
			oDocument.Content[Pos].Prev = null;
		}

		oDocument.private_ReindexContent(Pos);
	}
};
CChangesDocumentContentRemoveItem.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_DocumentContent_AddItem === oChanges.Type || AscDFH.historyitem_DocumentContent_RemoveItem === oChanges.Type))
		return true;

	return false;
};
CChangesDocumentContentRemoveItem.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesDocumentContentAddItem);
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

/**
 * Интерфейс для классов, которые работают с колонтитулами/автофигурами/сносками
 * @param {CDocument} LogicDocument - Ссылка на главный документ.
 * @constructor
 */
function CDocumentControllerBase(LogicDocument)
{
	this.LogicDocument   = LogicDocument;
	this.DrawingDocument = LogicDocument.Get_DrawingDocument();
}

/**
 * Получаем ссылку на CDocument.
 * @returns {CDocument}
 */
CDocumentControllerBase.prototype.Get_LogicDocument = function()
{
	return this.LogicDocument;
};
/**
 * Получаем ссылку на CDrawingDocument.
 * @returns {CDrawingDocument}
 */
CDocumentControllerBase.prototype.Get_DrawingDocument = function()
{
	return this.DrawingDocument;
};
/**
 * Является ли данный класс контроллером для колонтитулов.
 * @param {boolean} bReturnHdrFtr Если true, тогда возвращаем ссылку на колонтитул.
 * @returns {boolean | CHeaderFooter}
 */
CDocumentControllerBase.prototype.IsHdrFtr = function(bReturnHdrFtr)
{
	if (bReturnHdrFtr)
		return null;

	return false;
};
/**
 * Является ли данный класс контроллером для сносок
 * @param {boolean} bReturnFootnote Если true, тогда возвращаем ссылку на колонтитул
 * @returns {boolean | CFootEndnote}
 */
CDocumentControllerBase.prototype.IsFootnote = function(bReturnFootnote)
{
	if (bReturnFootnote)
		return null;

	return false;
};
/**
 * Является ли данный класс контроллером для автофигур.
 * @param {boolean} bReturnShape Если true, тогда возвращаем ссылку на автофигуру.
 * @returns {boolean | CShape}
 */
CDocumentControllerBase.prototype.Is_DrawingShape = function(bReturnShape)
{
	if (bReturnShape)
		return null;

	return false;
};
/**
 * Получаем абосолютный номер страницы по относительному.
 * @param {number} CurPage
 * @returns {number}
 */
CDocumentControllerBase.prototype.Get_AbsolutePage = function(CurPage)
{
	return CurPage;
};
/**
 * Получаем абосолютный номер колноки по относительному номеру страницы.
 * @param {number} CurPage
 * @returns {number}
 */
CDocumentControllerBase.prototype.Get_AbsoluteColumn = function(CurPage)
{
	return 0;
};
/**
 * Проверяем, является ли данный класс верхним, по отношению к другим классам DocumentContent, Document
 * @param {boolean} bReturnTopDocument Если true, тогда возвращаем ссылку на документ.
 * @returns {СDocument | CDocumentContent | null}
 */
CDocumentControllerBase.prototype.Is_TopDocument = function(bReturnTopDocument)
{
	if (bReturnTopDocument)
		return null;

	return false;
};
/**
 * Получаем ссылку на объект, работающий с нумерацией.
 * @returns {CNumbering}
 */
CDocumentControllerBase.prototype.Get_Numbering = function()
{
	return this.LogicDocument.Get_Numbering();
};
/**
 * Получаем ссылку на объект, работающий со стилями.
 * @returns {CStyles}
 */
CDocumentControllerBase.prototype.Get_Styles = function()
{
	return this.LogicDocument.Get_Styles();
};
/**
 * Получаем ссылку на табличный стиль для параграфа.
 * @returns {null}
 */
CDocumentControllerBase.prototype.Get_TableStyleForPara = function()
{
	return null;
};
/**
 * Получаем ссылку на стиль автофигур для параграфа.
 * @returns {null}
 */
CDocumentControllerBase.prototype.Get_ShapeStyleForPara = function()
{
	return null;
};
/**
 * Запрашиваем цвет заливки.
 * @returns {null}
 */
CDocumentControllerBase.prototype.Get_TextBackGroundColor = function()
{
	return undefined;
};
/**
 * Является ли данный класс ячейкой.
 * @returns {false}
 */
CDocumentControllerBase.prototype.IsCell = function(isReturnCell)
{
	if (true === isReturnCell)
		return null;

	return false;
};
/**
 * Получаем настройки темы для документа.
 */
CDocumentControllerBase.prototype.Get_Theme = function()
{
	return this.LogicDocument.Get_Theme();
};
/**
 * Получаем мап цветов.
 */
CDocumentControllerBase.prototype.Get_ColorMap = function()
{
	return this.LogicDocument.Get_ColorMap();
};
/**
 * Запрашиваем информацию о конце пересчета предыдущего элемента.
 * @param CurElement
 * @returns {null}
 */
CDocumentControllerBase.prototype.GetPrevElementEndInfo = function(CurElement)
{
	return null;
};
/**
 * Получаем текущее преобразование.
 * @returns {null}
 */
CDocumentControllerBase.prototype.Get_ParentTextTransform = function()
{
	return null;
};
/**
 * Данная функция приходит из таблицы. Проверяет рассчитывается ли таблица по содержимому.
 * @returns {boolean}
 */
CDocumentControllerBase.prototype.Check_AutoFit = function()
{
	return false;
};
/**
 * Данная функция нужна для обновления информации о предстоящем пересчете.
 */
CDocumentControllerBase.prototype.Refresh_RecalcData2 = function()
{
};
/**
 * Проверяем находимся ли мы в таблице.
 * @param {boolean} bReturnTopTable - Возвращается объект или true/false
 * @returns {boolean | CTable}
 */
CDocumentControllerBase.prototype.Is_InTable = function(bReturnTopTable)
{
	if (true === bReturnTopTable)
		return null;

	return false;
};
/**
 * Проверяем находимся ли мы в автофигуре.
 * @param {boolean} bRetShape - возвращается объект или true/false
 * @returns {boolean | ParaDrawing}
 */
CDocumentControllerBase.prototype.Is_DrawingShape = function(bRetShape)
{
	if (bRetShape === true)
	{
		return null;
	}
	return false;
};
/**
 * Событие о том, что контент изменился и пересчитался.
 * @param bChange
 * @param bForceRecalc
 */
CDocumentControllerBase.prototype.OnContentRecalculate = function(bChange, bForceRecalc)
{
	return;
};
/**
 * Получаем стартовую позицию для заданной страницы.
 * @returns {{X: number, Y: number, XLimit: number, YLimit: number}}
 */
CDocumentControllerBase.prototype.Get_PageContentStartPos = function(PageAbs)
{
	return {X : 0, Y : 0, XLimit : 0, YLimit : 0};
};
/**
 * Выставляем текущий элемент в данном классе.
 * @param bUpdateStates
 * @param PageAbs
 * @param oClass - ссылка на дочерний класс, из которого вызывалась данная функция
 */
CDocumentControllerBase.prototype.Set_CurrentElement = function(bUpdateStates, PageAbs, oClass)
{
};
//----------------------------------------------------------------------------------------------------------------------
// Чисто виртуальные функции
//----------------------------------------------------------------------------------------------------------------------
/**
 * Можно ли обновлять позицию курсора.
 * @returns {boolean}
 */
CDocumentControllerBase.prototype.CanUpdateTarget = function(){return true;};
/**
 * Пересчитываем текущую позицию.
 * @returns {{X: number, Y: number, Height: number, PageNum: number, Internal: {Line: number, Page: number, Range: number}, Transform: null}}
 */
CDocumentControllerBase.prototype.RecalculateCurPos = function(bUpdateX, bUpdateY){return {X : 0, Y : 0, Height : 0, PageNum : 0, Internal : {Line : 0, Page : 0, Range : 0}, Transform : null};};
/**
 * Получаем текущий номер страницы.
 * @returns {number} -1 - значит, номер страницы определеить невозможно
 */
CDocumentControllerBase.prototype.GetCurPage = function(){return -1;};
/**
 * Добавляем новый параграф.
 * @param {boolean} bRecalculate - Пересчитывать или нет.
 * @param {boolean} bForceAdd    - Добавляем параграф, пропуская всякие проверки типа пустого параграфа с нумерацией.
 */
CDocumentControllerBase.prototype.AddNewParagraph = function(bRecalculate, bForceAdd){return false;};
/**
 * Добавляем встроенное изображение
 * @param {number} nW - ширина
 * @param {number} nH - высота
 * @param oImage - ссылка на объект изображения
 * @param oChart - ссылка на объект диаграммы
 * @param {boolean} bFlow - инлайн объект или "плавающий"
 */
CDocumentControllerBase.prototype.AddInlineImage = function(nW, nH, oImage, oChart, bFlow){};

/**
 * Добавляем несколько изображений
 * @param {Array} aImages - массив объектов типа CImage
 * */
CDocumentControllerBase.prototype.AddImages = function(aImages){};
/**
 * Добавляем OLE-объект.
 * @param nW
 * @param nH
 * @param nWidthPix
 * @param nHeightPix
 * @param oImage
 * @param oData
 * @param sApplicationId
 */
CDocumentControllerBase.prototype.AddOleObject = function(nW, nH, nWidthPix, nHeightPix, oImage, oData, sApplicationId){};
/**
 * Добавляем графический объект TextArt.
 * @param nStyle
 */
CDocumentControllerBase.prototype.AddTextArt = function(nStyle){};
/**
 * Вставляем объект SignatureLine
 * @param oSignatureDrawing
 */
CDocumentControllerBase.prototype.AddSignatureLine = function(oSignatureDrawing){};
/**
 * Редактируем диаграмму.
 * @param Chart
 */
CDocumentControllerBase.prototype.EditChart = function(Chart){};
/**
 * Добавляем инлайн таблицу.
 * @param nCols
 * @param nRows
 */
CDocumentControllerBase.prototype.AddInlineTable = function(nCols, nRows){};
/**
 * Очищаем форматирование внутри селекта
 * {boolean} [isClearParaPr=true] Очищать ли настройки параграфа
 * {boolean} [isClearTextPr=true] Очищать ли настройки текста
 */
CDocumentControllerBase.prototype.ClearParagraphFormatting = function(isClearParaPr, isClearTextPr){};
/**
 * Добавляем элемент в параграф.
 * @param oItem
 * @param {boolean} bRecalculate - Пересчитывать ли после выполнения данной функции.
 */
CDocumentControllerBase.prototype.AddToParagraph = function(oItem, bRecalculate){};
/**
 * Производим удаление выделенной части документа или исходя из позиции курсора.
 * @param {number} nDirection направление удаления
 * @param {boolean} bOnlyText - удаляем только текст
 * @param {boolean} bRemoveOnlySelection - удаляем только по селекту
 * @param {boolean} bOnAddText - удаление происходит во время добавления текста (особый тип удаления)
 * @returns {boolean} Выполнилось ли удаление.
 */
CDocumentControllerBase.prototype.Remove = function(nDirection, bOnlyText, bRemoveOnlySelection, bOnAddText){return true;};
/**
 * Получаем физическую позицию курсора на странице.
 */
CDocumentControllerBase.prototype.GetCursorPosXY = function(){return {X : 0, Y : 0};};
/**
 * Перемещаем курсор в начало.
 * @param {boolean} AddToSelect - добавляем ли все промежуточное к селекту
 */
CDocumentControllerBase.prototype.MoveCursorToStartPos = function(AddToSelect){};
/**
 * Перемещаем курсор в конец.
 * @param {boolean} AddToSelect - добавляем ли все промежуточное к селекту
 */
CDocumentControllerBase.prototype.MoveCursorToEndPos = function(AddToSelect){};
/**
 * Смещаем курсор влево
 * @param {boolean} AddToSelect Добавлять ли к селекту смещение
 * @param {boolean} Word Осуществлять ли переход по целому слову
 * @returns {boolean} Получилось ли перемещение, или мы достигли предела.
 */
CDocumentControllerBase.prototype.MoveCursorLeft = function(AddToSelect, Word){return false;};
/**
 * Смещаем курсор вправо
 * @param {boolean} AddToSelect Добавлять ли к селекту смещение
 * @param {boolean} Word Осуществлять ли переход по целому слову
 * @param {boolean} FromPaste Пришла ли данная комнда после "вставки"
 * @returns {boolean} Получилось ли перемещение, или мы достигли предела.
 */
CDocumentControllerBase.prototype.MoveCursorRight = function(AddToSelect, Word){return false;};
/**
 * Смещаем курсор вверх.
 * @param AddToSelect Добавлять ли к селекту смещение
 * @returns {boolean} Получилось ли перемещение, или мы достигли предела.
 */
CDocumentControllerBase.prototype.MoveCursorUp = function(AddToSelect){return false;};
/**
 * Смещаем курсор вниз.
 * @param AddToSelect Добавлять ли к селекту смещение
 * @returns {boolean} Получилось ли перемещение, или мы достигли предела.
 */
CDocumentControllerBase.prototype.MoveCursorDown = function(AddToSelect){return false;};
/**
 * Смещаем курсор в конец строки.
 * @param AddToSelect Добавлять ли к селекту смещение
 * @returns {boolean} Получилось ли перемещение, или мы достигли предела.
 */
CDocumentControllerBase.prototype.MoveCursorToEndOfLine = function(AddToSelect){return false;};
/**
 * Смещаем курсор в начало строки.
 * @param AddToSelect Добавлять ли к селекту смещение
 * @returns {boolean} Получилось ли перемещение, или мы достигли предела.
 */
CDocumentControllerBase.prototype.MoveCursorToStartOfLine = function(AddToSelect){return false;};
/**
 * Перемещаем курсор в заданную позицию на странице.
 * @param X
 * @param Y
 * @param PageAbs - абсолютный номер страницы
 * @param AddToSelect Добавлять ли к селекту смещение
 */
CDocumentControllerBase.prototype.MoveCursorToXY = function(X, Y, PageAbs, AddToSelect){};
/**
 * Перемещаем курсор в следующую или предыдущую ячейку.
 * @param {boolean} bNext
 */
CDocumentControllerBase.prototype.MoveCursorToCell = function(bNext){};
/**
 * Устанавливаем прилегание параграфа.
 * @param Align - тип прилегания
 */
CDocumentControllerBase.prototype.SetParagraphAlign = function(Align){};
/**
 * Установить межстрочные расстояния для параграфа.
 * @param Spacing
 */
CDocumentControllerBase.prototype.SetParagraphSpacing = function (Spacing){};
/**
 * Установить табы параграфа.
 * @param Tabs
 */
CDocumentControllerBase.prototype.SetParagraphTabs = function(Tabs){};
/**
 * Установить отступы параграфа.
 * @param Ind
 */
CDocumentControllerBase.prototype.SetParagraphIndent = function(Ind){};
/**
 * Установить заливку параграфа.
 * @param Shd
 */
CDocumentControllerBase.prototype.SetParagraphShd = function(Shd){};
/**
 * Установить стиль параграфа.
 * @param Name - название стиля
 */
CDocumentControllerBase.prototype.SetParagraphStyle = function(Name){};
/**
 * Устанавливаем применять или нет расстояние между парграфами одного стиля.
 * @param {boolean} Value
 */
CDocumentControllerBase.prototype.SetParagraphContextualSpacing = function(Value){};
/**
 * Устанавливаем разрыв пере параграфом.
 * @param {boolean} Value
 */
CDocumentControllerBase.prototype.SetParagraphPageBreakBefore = function(Value){};
/**
 * Устанавливаем является ли параграф неразрывным.
 * @param {boolean} Value
 */
CDocumentControllerBase.prototype.SetParagraphKeepLines = function(Value){};
/**
 * Устанавливаем отрывать ли данный параграф от следующего.
 * @param {boolean} Value
 */
CDocumentControllerBase.prototype.SetParagraphKeepNext = function(Value){};
/**
 * Устанавливаем обработку висячих строк в парагрфе.
 * @param {boolean} Value
 */
CDocumentControllerBase.prototype.SetParagraphWidowControl = function(Value){};
/**
 * Устанавливаем границы параграфа
 * @param Borders
 */
CDocumentControllerBase.prototype.SetParagraphBorders = function(Borders){};
/**
 * Превращаем параграф в рамку (плавающий параграф).
 * @param FramePr
 * @param bDelete
 */
CDocumentControllerBase.prototype.SetParagraphFramePr = function(FramePr, bDelete){};
/**
 * Уменьшаем или увеличиваем (по специальной таблице) размер шрифта в параграфе.
 * @param {boolean} bIncrease
 */
CDocumentControllerBase.prototype.IncreaseDecreaseFontSize = function(bIncrease){};
/**
 * Уменьшаем или увеличиваем (по специальной таблице) отступы в параграфе.
 * @param {boolean} bIncrease
 */
CDocumentControllerBase.prototype.IncreaseDecreaseIndent = function(bIncrease){};
/**
 * Устанавливаем настройки для изображений.
 * @param Props
 */
CDocumentControllerBase.prototype.SetImageProps = function(Props){};
/**
 * Устанавливаем настройки для таблиц.
 * @param Props
 */
CDocumentControllerBase.prototype.SetTableProps = function(Props){};
/**
 * Получаем текущие настройки параграфа.
 * @returns {CParaPr}
 */
CDocumentControllerBase.prototype.GetCalculatedParaPr = function(){var oParaPr = new CParaPr(); oParaPr.Init_Default(); return oParaPr};
/**
 * Получаем текущие настройки текста.
 * @returns {CTextPr}
 */
CDocumentControllerBase.prototype.GetCalculatedTextPr = function(){var oTextPr = new CTextPr(); oTextPr.Init_Default(); return oTextPr};
/**
 * Получаем прямые настройки параграфа.
 * @returns {CParaPr}
 */
CDocumentControllerBase.prototype.GetDirectParaPr = function(){var oParaPr = new CParaPr(); oParaPr.Init_Default(); return oParaPr};
/**
 * Получаем прямые настройки текста.
 * @returns {CTextPr}
 */
CDocumentControllerBase.prototype.GetDirectTextPr = function(){var oTextPr = new CTextPr(); oTextPr.Init_Default(); return oTextPr};
/**
 * Убираем селект.
 * @param bNoCheckDrawing
 */
CDocumentControllerBase.prototype.RemoveSelection = function(bNoCheckDrawing){};
/**
 * Проверяем пустой ли селект.
 * @returns {boolean}
 */
CDocumentControllerBase.prototype.IsSelectionEmpty = function(bCheckHidden){return true;};
/**
 * Рисуем селект на заданно странице.
 * @param PageAbs
 */
CDocumentControllerBase.prototype.DrawSelectionOnPage = function(PageAbs){};
/**
 * Получаем границы селекта.
 * @returns {*}
 */
CDocumentControllerBase.prototype.GetSelectionBounds = function(){return null;};
/**
 * Проверяем осуществляется ли сейчас движение таблицы.
 * @returns {boolean}
 */
CDocumentControllerBase.prototype.IsMovingTableBorder = function(){return false;};
/**
 * Проверяем попадает ли заданная позиция в селект.
 * @param X
 * @param Y
 * @param PageAbs
 * @param NearPos
 * @returns {boolean}
 */
CDocumentControllerBase.prototype.CheckPosInSelection = function(X, Y, PageAbs, NearPos){return false;};
/**
 * Выделяем все содержимое.
 */
CDocumentControllerBase.prototype.SelectAll = function(){};
/**
 * Получаем выделенный контент.
 * @param SelectedContent
 */
CDocumentControllerBase.prototype.GetSelectedContent = function(SelectedContent){};
/**
 * Обновляем вид курсора.
 */
CDocumentControllerBase.prototype.UpdateCursorType = function(X, Y, PageAbs, MouseEvent){};
/**
 * Вставляем форматирование.
 * @param TextPr
 * @param ParaPr
 */
CDocumentControllerBase.prototype.PasteFormatting = function(TextPr, ParaPr){};
/**
 * Проверяем используется ли в данный момент селект.
 * @returns {boolean}
 */
CDocumentControllerBase.prototype.IsSelectionUse = function(){return false;};
/**
 * Проверяем выделена ли у нас нумерация в данный момент
 * @returns {boolean}
 */
CDocumentControllerBase.prototype.IsNumberingSelection = function(){return false;};
/**
 * Проверяем выделен ли именно текст сейчас.
 * @returns {boolean}
 */
CDocumentControllerBase.prototype.IsTextSelectionUse = function(){return false;};
/**
 * Получаем XY текущей позиции.
 * @returns {{X: number, Y: number}}
 */
CDocumentControllerBase.prototype.GetCurPosXY = function(){return {X : 0, Y : 0};};
/**
 * Получаем выделенный текст.
 * @param {boolean} bClearText
 * @param {object} oPr
 * @returns {String}
 */
CDocumentControllerBase.prototype.GetSelectedText = function(bClearText, oPr){return "";};
/**
 * Получаем текущий параграф.
 * @returns {?Paragraph}
 */
CDocumentControllerBase.prototype.GetCurrentParagraph = function(bIgnoreSelection, arrSelectedParagraphs){return null};
/**
 * Собираем информацию о выделенной части документа.
 * @param oInfo
 */
CDocumentControllerBase.prototype.GetSelectedElementsInfo = function(oInfo){};
/**
 * Добавляем строку таблицы.
 * @param bBefore
 */
CDocumentControllerBase.prototype.AddTableRow = function(bBefore){};
/**
 * Добавляем столбец таблицы.
 * @param bBefore
 */
CDocumentControllerBase.prototype.AddTableColumn = function(bBefore){};
/**
 * Удаляем строку таблицы.
 */
CDocumentControllerBase.prototype.RemoveTableRow = function(){};
/**
 * Удаляем колонку таблицы.
 */
CDocumentControllerBase.prototype.RemoveTableColumn = function(){};
/**
 * Объединяем ячейки таблицы.
 */
CDocumentControllerBase.prototype.MergeTableCells = function(){};
/**
 * Разбить ячейки таблицы.
 */
CDocumentControllerBase.prototype.SplitTableCells = function(Cols, Rows){};
/**
 * Удаляем таблицу.
 */
CDocumentControllerBase.prototype.RemoveTable = function(){};
/**
 * Выделяем таблицу или ее часть.
 * @param Type тип выделения
 */
CDocumentControllerBase.prototype.SelectTable = function(Type){};
/**
 * Проверяем можем ли мы произвести объединение ячеек таблицы.
 * @returns {boolean}
 */
CDocumentControllerBase.prototype.CanMergeTableCells = function(){return false;};
/**
 * Проверяем можем ли мы произвести разделение ячеек таблицы.
 * @returns {boolean}
 */
CDocumentControllerBase.prototype.CanSplitTableCells = function(){return false;};
/**
 * Распределяем ячейки таблицы по ширине или высоте.
 * @returns {boolean}
 */
CDocumentControllerBase.prototype.DistributeTableCells = function(isHorizontally)
{
	return false;
};
/**
 * Обновляем состояние интерфейса.
 */
CDocumentControllerBase.prototype.UpdateInterfaceState = function(){};
/**
 * Обновляем состояние линеек.
 */
CDocumentControllerBase.prototype.UpdateRulersState = function(){};
/**
 * Обновляем состояние селекта и курсора.
 */
CDocumentControllerBase.prototype.UpdateSelectionState = function(){};
/**
 * Получаем текущее состоянии селекта и курсора.
 */
CDocumentControllerBase.prototype.GetSelectionState = function(){return [];};
/**
 * Выставляем текущее состояние селекта и курсора.
 * @param State
 * @param StateIndex
 */
CDocumentControllerBase.prototype.SetSelectionState = function(State, StateIndex){};
/**
 * Добавляем гиперссылку.
 * @param Props
 */
CDocumentControllerBase.prototype.AddHyperlink = function(Props){};
/**
 * Изменяем гиперссылку.
 * @param Props
 */
CDocumentControllerBase.prototype.ModifyHyperlink = function(Props){};
/**
 * Удаляем гиперссылку.
 */
CDocumentControllerBase.prototype.RemoveHyperlink = function(){};
/**
 * Проверяем можно ли добавить гиперссылку.
 * @returns {boolean}
 */
CDocumentControllerBase.prototype.CanAddHyperlink = function(bCheckInHyperlink){return false;};
/**
 * Проверяем находится ли курсор сейчас в гиперссылке.
 * @returns {?ParaHyperlink}
 */
CDocumentControllerBase.prototype.IsCursorInHyperlink = function(bCheckEnd){return false;};
/**
 * Добавляем комментарий.
 * @param Comment
 */
CDocumentControllerBase.prototype.AddComment = function(Comment){};
/**
 * Проверяем, можно ли добавить комментарий.
 * @returns {boolean}
 */
CDocumentControllerBase.prototype.CanAddComment = function(){return false;};
/**
 * Получаем физическую позицию на странице для якоря по селекту.
 * @returns {{X0: number, X1: number, Y: number, Page: number}}
 */
CDocumentControllerBase.prototype.GetSelectionAnchorPos = function(){return {X0 : 0, X1 : 0, Y : 0, Page : 0};};
/**
 * Начинаем селект с текущей позиции.
 */
CDocumentControllerBase.prototype.StartSelectionFromCurPos = function(){};
/**
 * Сохраняем состояние документа изменения перед принятием чужих изменений.
 * @param State
 */
CDocumentControllerBase.prototype.SaveDocumentStateBeforeLoadChanges = function(State){};
/**
 * Восстанавливаем состояние документа после загрузки изменений.
 * @param State
 */
CDocumentControllerBase.prototype.RestoreDocumentStateAfterLoadChanges = function(State){};
/**
 * Получаем размеры текущей колонки.
 * @returns {{W: number, H: number}}
 */
CDocumentControllerBase.prototype.GetColumnSize = function(){return {W : 0, H : 0};};
/**
 * Получаем настройки текущей секции
 * @returns {?CSectionPr}
 */
CDocumentControllerBase.prototype.GetCurrentSectionPr = function(){return null;};
/**
 * Отличие от RemoveSelection в том, что сбрасываем селект с текста, но не сбрасываем с автофигур
 */
CDocumentControllerBase.prototype.RemoveTextSelection = function(){};
/**
 * Добавляем класс CBlockLevelSdt в текущую позицию курсора.
 */
CDocumentControllerBase.prototype.AddContentControl = function(nContentControlType){return null;};
/**
 * Получаем стиль по выделенному фрагменту
 */
CDocumentControllerBase.prototype.GetStyleFromFormatting = function(){return null;};
/**
 * Вплоть до заданного параграфа ищем последнюю похожую нумерацию
 * @param oContinueEngine {CDocumentNumberingContinueEngine}
 */
CDocumentControllerBase.prototype.GetSimilarNumbering = function(oContinueEngine){};
"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 10.06.2016
 * Time: 15:25
 */

/**
 * Специальный класс-обработчик команд для основной части документа
 * @param {CDocument} LogicDocument - Ссылка на главный документ.
 * @constructor
 * @extends {CDocumentControllerBase}
 */
function CLogicDocumentController(LogicDocument)
{
	CDocumentControllerBase.call(this, LogicDocument);
}
CLogicDocumentController.prototype = Object.create(CDocumentControllerBase.prototype);
CLogicDocumentController.prototype.constructor = CLogicDocumentController;

CLogicDocumentController.prototype.CanUpdateTarget = function()
{
	return this.LogicDocument.controller_CanUpdateTarget();
};
CLogicDocumentController.prototype.RecalculateCurPos = function(bUpdateX, bUpdateY)
{
	return this.LogicDocument.controller_RecalculateCurPos(bUpdateX, bUpdateY);
};
CLogicDocumentController.prototype.GetCurPage = function()
{
	return this.LogicDocument.controller_GetCurPage();
};
CLogicDocumentController.prototype.AddNewParagraph = function(bRecalculate, bForceAdd)
{
	return this.LogicDocument.controller_AddNewParagraph(bRecalculate, bForceAdd);
};
CLogicDocumentController.prototype.AddInlineImage = function(nW, nH, oImage, oChart, bFlow)
{
	this.LogicDocument.controller_AddInlineImage(nW, nH, oImage, oChart, bFlow);
};
CLogicDocumentController.prototype.AddImages = function(aImages)
{
	this.LogicDocument.controller_AddImages(aImages);
};
CLogicDocumentController.prototype.AddOleObject = function(nW, nH, nWidthPix, nHeightPix, oImage, oData, sApplicationId)
{
	this.LogicDocument.controller_AddOleObject(nW, nH, nWidthPix, nHeightPix, oImage, oData, sApplicationId);
};
CLogicDocumentController.prototype.AddTextArt = function(nStyle)
{
	this.LogicDocument.controller_AddTextArt(nStyle);
};
CLogicDocumentController.prototype.EditChart = function(Chart)
{
	// Ничего не делаем
};
CLogicDocumentController.prototype.AddSignatureLine = function(oSignatureDrawing)
{
    this.LogicDocument.controller_AddSignatureLine(oSignatureDrawing);
};


CLogicDocumentController.prototype.AddInlineTable = function(nCols, nRows)
{
	this.LogicDocument.controller_AddInlineTable(nCols, nRows);
};
CLogicDocumentController.prototype.ClearParagraphFormatting = function(isClearParaPr, isClearTextPr)
{
	this.LogicDocument.controller_ClearParagraphFormatting(isClearParaPr, isClearTextPr);
};
CLogicDocumentController.prototype.AddToParagraph = function(oItem)
{
	this.LogicDocument.controller_AddToParagraph(oItem);
};
CLogicDocumentController.prototype.Remove = function(nDirection, bOnlyText, bRemoveOnlySelection, bOnAddText)
{
	return this.LogicDocument.controller_Remove(nDirection, bOnlyText, bRemoveOnlySelection, bOnAddText);
};
CLogicDocumentController.prototype.GetCursorPosXY = function()
{
	return this.LogicDocument.controller_GetCursorPosXY();
};
CLogicDocumentController.prototype.MoveCursorToStartPos = function(bAddToSelect)
{
	this.LogicDocument.controller_MoveCursorToStartPos(bAddToSelect);
};
CLogicDocumentController.prototype.MoveCursorToEndPos = function(AddToSelect)
{
	this.LogicDocument.controller_MoveCursorToEndPos(AddToSelect);
};
CLogicDocumentController.prototype.MoveCursorLeft = function(AddToSelect, Word)
{
	return this.LogicDocument.controller_MoveCursorLeft(AddToSelect, Word);
};
CLogicDocumentController.prototype.MoveCursorRight = function(AddToSelect, Word)
{
	return this.LogicDocument.controller_MoveCursorRight(AddToSelect, Word);
};
CLogicDocumentController.prototype.MoveCursorUp = function(AddToSelect)
{
	return this.LogicDocument.controller_MoveCursorUp(AddToSelect);
};
CLogicDocumentController.prototype.MoveCursorDown = function(AddToSelect)
{
	return this.LogicDocument.controller_MoveCursorDown(AddToSelect);
};
CLogicDocumentController.prototype.MoveCursorToEndOfLine = function(AddToSelect)
{
	return this.LogicDocument.controller_MoveCursorToEndOfLine(AddToSelect);
};
CLogicDocumentController.prototype.MoveCursorToStartOfLine = function(AddToSelect)
{
	return this.LogicDocument.controller_MoveCursorToStartOfLine(AddToSelect);
};
CLogicDocumentController.prototype.MoveCursorToXY = function(X, Y, PageAbs, AddToSelect)
{
	return this.LogicDocument.controller_MoveCursorToXY(X, Y, PageAbs, AddToSelect);
};
CLogicDocumentController.prototype.MoveCursorToCell = function(bNext)
{
	return this.LogicDocument.controller_MoveCursorToCell(bNext);
};
CLogicDocumentController.prototype.SetParagraphAlign = function(Align)
{
	this.LogicDocument.controller_SetParagraphAlign(Align);
};
CLogicDocumentController.prototype.SetParagraphSpacing = function (Spacing)
{
	this.LogicDocument.controller_SetParagraphSpacing(Spacing);
};
CLogicDocumentController.prototype.SetParagraphTabs = function(Tabs)
{
	this.LogicDocument.controller_SetParagraphTabs(Tabs);
};
CLogicDocumentController.prototype.SetParagraphIndent = function(Ind)
{
	this.LogicDocument.controller_SetParagraphIndent(Ind);
};
CLogicDocumentController.prototype.SetParagraphShd = function(Shd)
{
	this.LogicDocument.controller_SetParagraphShd(Shd);
};
CLogicDocumentController.prototype.SetParagraphStyle = function(Name)
{
	this.LogicDocument.controller_SetParagraphStyle(Name);
};
CLogicDocumentController.prototype.SetParagraphContextualSpacing = function(Value)
{
	this.LogicDocument.controller_SetParagraphContextualSpacing(Value);
};
CLogicDocumentController.prototype.SetParagraphPageBreakBefore = function(Value)
{
	this.LogicDocument.controller_SetParagraphPageBreakBefore(Value);
};
CLogicDocumentController.prototype.SetParagraphKeepLines = function(Value)
{
	this.LogicDocument.controller_SetParagraphKeepLines(Value);
};
CLogicDocumentController.prototype.SetParagraphKeepNext = function(Value)
{
	this.LogicDocument.controller_SetParagraphKeepNext(Value);
};
CLogicDocumentController.prototype.SetParagraphWidowControl = function(Value)
{
	this.LogicDocument.controller_SetParagraphWidowControl(Value);
};
CLogicDocumentController.prototype.SetParagraphBorders = function(Borders)
{
	this.LogicDocument.controller_SetParagraphBorders(Borders);
};
CLogicDocumentController.prototype.SetParagraphFramePr = function(FramePr, bDelete)
{
	this.LogicDocument.controller_SetParagraphFramePr(FramePr, bDelete);
};
CLogicDocumentController.prototype.IncreaseDecreaseFontSize = function(bIncrease)
{
	this.LogicDocument.controller_IncreaseDecreaseFontSize(bIncrease);
};
CLogicDocumentController.prototype.IncreaseDecreaseIndent = function(bIncrease)
{
	this.LogicDocument.controller_IncreaseDecreaseIndent(bIncrease);
};
CLogicDocumentController.prototype.SetImageProps = function(Props)
{
	this.LogicDocument.controller_SetImageProps(Props);
};
CLogicDocumentController.prototype.SetTableProps = function(Props)
{
	this.LogicDocument.controller_SetTableProps(Props);
};
CLogicDocumentController.prototype.GetCalculatedParaPr = function()
{
	return this.LogicDocument.controller_GetCalculatedParaPr();
};
CLogicDocumentController.prototype.GetCalculatedTextPr = function()
{
	return this.LogicDocument.controller_GetCalculatedTextPr();
};
CLogicDocumentController.prototype.GetDirectParaPr = function()
{
	return this.LogicDocument.controller_GetDirectParaPr();
};
CLogicDocumentController.prototype.GetDirectTextPr = function()
{
	return this.LogicDocument.controller_GetDirectTextPr();
};
CLogicDocumentController.prototype.RemoveSelection = function(bNoCheckDrawing)
{
	this.LogicDocument.controller_RemoveSelection(bNoCheckDrawing);
};
CLogicDocumentController.prototype.IsSelectionEmpty = function(bCheckHidden)
{
	return this.LogicDocument.controller_IsSelectionEmpty(bCheckHidden);
};
CLogicDocumentController.prototype.DrawSelectionOnPage = function(PageAbs)
{
	this.LogicDocument.controller_DrawSelectionOnPage(PageAbs);
};
CLogicDocumentController.prototype.GetSelectionBounds = function()
{
	return this.LogicDocument.controller_GetSelectionBounds();
};
CLogicDocumentController.prototype.IsMovingTableBorder = function()
{
	return this.LogicDocument.controller_IsMovingTableBorder();
};
CLogicDocumentController.prototype.CheckPosInSelection = function(X, Y, PageAbs, NearPos)
{
	return this.LogicDocument.controller_CheckPosInSelection(X, Y, PageAbs, NearPos);
};
CLogicDocumentController.prototype.SelectAll = function()
{
	this.LogicDocument.controller_SelectAll();
};
CLogicDocumentController.prototype.GetSelectedContent = function(SelectedContent)
{
	this.LogicDocument.controller_GetSelectedContent(SelectedContent);
};
CLogicDocumentController.prototype.UpdateCursorType = function(X, Y, PageAbs, MouseEvent)
{
	this.LogicDocument.controller_UpdateCursorType(X, Y, PageAbs, MouseEvent);
};
CLogicDocumentController.prototype.PasteFormatting = function(TextPr, ParaPr)
{
	this.LogicDocument.controller_PasteFormatting(TextPr, ParaPr);
};
CLogicDocumentController.prototype.IsSelectionUse = function()
{
	return this.LogicDocument.controller_IsSelectionUse();
};
CLogicDocumentController.prototype.IsNumberingSelection = function()
{
	return this.LogicDocument.controller_IsNumberingSelection();
};
CLogicDocumentController.prototype.IsTextSelectionUse = function()
{
	return this.LogicDocument.controller_IsTextSelectionUse();
};
CLogicDocumentController.prototype.GetCurPosXY = function()
{
	return this.LogicDocument.controller_GetCurPosXY();
};
CLogicDocumentController.prototype.GetSelectedText = function(bClearText, oPr)
{
	return this.LogicDocument.controller_GetSelectedText(bClearText, oPr);
};
CLogicDocumentController.prototype.GetCurrentParagraph = function(bIgnoreSelection, arrSelectedParagraphs)
{
	return this.LogicDocument.controller_GetCurrentParagraph(bIgnoreSelection, arrSelectedParagraphs);
};
CLogicDocumentController.prototype.GetSelectedElementsInfo = function(oInfo)
{
	this.LogicDocument.controller_GetSelectedElementsInfo(oInfo);
};
CLogicDocumentController.prototype.AddTableRow = function(bBefore)
{
	this.LogicDocument.controller_AddTableRow(bBefore);
};
CLogicDocumentController.prototype.AddTableColumn = function(bBefore)
{
	this.LogicDocument.controller_AddTableColumn(bBefore);
};
CLogicDocumentController.prototype.RemoveTableRow = function()
{
	this.LogicDocument.controller_RemoveTableRow();
};
CLogicDocumentController.prototype.RemoveTableColumn = function()
{
	this.LogicDocument.controller_RemoveTableColumn();
};
CLogicDocumentController.prototype.MergeTableCells = function()
{
	this.LogicDocument.controller_MergeTableCells();
};
CLogicDocumentController.prototype.DistributeTableCells = function(isHorizontally)
{
	return this.LogicDocument.controller_DistributeTableCells(isHorizontally);
};
CLogicDocumentController.prototype.SplitTableCells = function(Cols, Rows)
{
	this.LogicDocument.controller_SplitTableCells(Cols, Rows);
};
CLogicDocumentController.prototype.RemoveTable = function()
{
	this.LogicDocument.controller_RemoveTable();
};
CLogicDocumentController.prototype.SelectTable = function(Type)
{
	this.LogicDocument.controller_SelectTable(Type);
};
CLogicDocumentController.prototype.CanMergeTableCells = function()
{
	return this.LogicDocument.controller_CanMergeTableCells();
};
CLogicDocumentController.prototype.CanSplitTableCells = function()
{
	return this.LogicDocument.controller_CanSplitTableCells();
};
CLogicDocumentController.prototype.UpdateInterfaceState = function()
{
	this.LogicDocument.controller_UpdateInterfaceState();
};
CLogicDocumentController.prototype.UpdateRulersState = function()
{
	this.LogicDocument.controller_UpdateRulersState();
};
CLogicDocumentController.prototype.UpdateSelectionState = function()
{
	this.LogicDocument.controller_UpdateSelectionState();
};
CLogicDocumentController.prototype.GetSelectionState = function()
{
	return this.LogicDocument.controller_GetSelectionState();
};
CLogicDocumentController.prototype.SetSelectionState = function(State, StateIndex)
{
	this.LogicDocument.controller_SetSelectionState(State, StateIndex);
};
CLogicDocumentController.prototype.AddHyperlink = function(Props)
{
	this.LogicDocument.controller_AddHyperlink(Props);
};
CLogicDocumentController.prototype.ModifyHyperlink = function(Props)
{
	this.LogicDocument.controller_ModifyHyperlink(Props);
};
CLogicDocumentController.prototype.RemoveHyperlink = function()
{
	this.LogicDocument.controller_RemoveHyperlink();
};
CLogicDocumentController.prototype.CanAddHyperlink = function(bCheckInHyperlink)
{
	return this.LogicDocument.controller_CanAddHyperlink(bCheckInHyperlink);
};
CLogicDocumentController.prototype.IsCursorInHyperlink = function(bCheckEnd)
{
	return this.LogicDocument.controller_IsCursorInHyperlink(bCheckEnd);
};
CLogicDocumentController.prototype.AddComment = function(Comment)
{
	this.LogicDocument.controller_AddComment(Comment);
};
CLogicDocumentController.prototype.CanAddComment = function()
{
	return this.LogicDocument.controller_CanAddComment();
};
CLogicDocumentController.prototype.GetSelectionAnchorPos = function()
{
	return this.LogicDocument.controller_GetSelectionAnchorPos();
};
CLogicDocumentController.prototype.StartSelectionFromCurPos = function()
{
	this.LogicDocument.controller_StartSelectionFromCurPos();
};
CLogicDocumentController.prototype.SaveDocumentStateBeforeLoadChanges = function(State)
{
	this.LogicDocument.controller_SaveDocumentStateBeforeLoadChanges(State);
};
CLogicDocumentController.prototype.RestoreDocumentStateAfterLoadChanges = function(State)
{
	this.LogicDocument.controller_RestoreDocumentStateAfterLoadChanges(State);
};
CLogicDocumentController.prototype.GetColumnSize = function()
{
	return this.LogicDocument.controller_GetColumnSize();
};
CLogicDocumentController.prototype.GetCurrentSectionPr = function()
{
	return this.LogicDocument.controller_GetCurrentSectionPr();
};
CLogicDocumentController.prototype.RemoveTextSelection = function()
{
	return this.RemoveSelection();
};
CLogicDocumentController.prototype.AddContentControl = function(nContentControlType)
{
	return this.LogicDocument.controller_AddContentControl(nContentControlType);
};
CLogicDocumentController.prototype.GetStyleFromFormatting = function()
{
	return this.LogicDocument.controller_GetStyleFromFormatting();
};
CLogicDocumentController.prototype.GetSimilarNumbering = function(oContinueEngine)
{
	this.LogicDocument.controller_GetSimilarNumbering(oContinueEngine);
};
"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 10.06.2016
 * Time: 15:31
 */

/**
 * Специальный класс-обработчик команд в автофигурах
 * @param {CDocument} LogicDocument - Ссылка на главный документ.
 * @param {CDrawingsObjects} DrawingsObjects - ССылка на объект, работающий с автофигурами
 * @constructor
 * @extends {CDocumentControllerBase}
 */
function CDrawingsController(LogicDocument, DrawingsObjects)
{
	CDocumentControllerBase.call(this, LogicDocument);

	this.DrawingObjects = DrawingsObjects;
}
CDrawingsController.prototype = Object.create(CDocumentControllerBase.prototype);
CDrawingsController.prototype.constructor = CDrawingsController;

CDrawingsController.prototype.CanUpdateTarget = function()
{
	return true;
};
CDrawingsController.prototype.RecalculateCurPos = function(bUpdateX, bUpdateY)
{
	return this.DrawingObjects.recalculateCurPos(bUpdateX, bUpdateY);
};
CDrawingsController.prototype.GetCurPage = function()
{
	var ParaDrawing = this.DrawingObjects.getMajorParaDrawing();
	if (null !== ParaDrawing)
		return ParaDrawing.PageNum;

	return -1;
};
CDrawingsController.prototype.AddNewParagraph = function(bRecalculate, bForceAdd)
{
	return this.DrawingObjects.addNewParagraph(bRecalculate, bForceAdd);
};
CDrawingsController.prototype.AddInlineImage = function(nW, nH, oImage, oChart, bFlow)
{
	return this.DrawingObjects.addInlineImage(nW, nH, oImage, oChart, bFlow);
};
CDrawingsController.prototype.AddImages = function(aImages)
{
	return this.DrawingObjects.addImages(aImages);
};
CDrawingsController.prototype.AddSignatureLine = function(oSignatureDrawing)
{
	return this.DrawingObjects.addSignatureLine(oSignatureDrawing);
};
CDrawingsController.prototype.AddOleObject = function(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId)
{
	this.DrawingObjects.addOleObject(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId);
};
CDrawingsController.prototype.AddTextArt = function(nStyle)
{
	// ничего не делаем
};
CDrawingsController.prototype.EditChart = function(Chart)
{
	this.DrawingObjects.editChart(Chart);
};
CDrawingsController.prototype.AddInlineTable = function(Cols, Rows)
{
	this.DrawingObjects.addInlineTable(Cols, Rows);
};
CDrawingsController.prototype.ClearParagraphFormatting = function(isClearParaPr, isClearTextPr)
{
	this.DrawingObjects.paragraphClearFormatting(isClearParaPr, isClearTextPr);
};
CDrawingsController.prototype.AddToParagraph = function(oItem, bRecalculate)
{
	if (para_NewLine === oItem.Type && true === oItem.IsPageOrColumnBreak())
		return;

	this.DrawingObjects.paragraphAdd(oItem, bRecalculate);
	this.LogicDocument.Document_UpdateSelectionState();
	this.LogicDocument.Document_UpdateUndoRedoState();
	this.LogicDocument.Document_UpdateInterfaceState();
};
CDrawingsController.prototype.Remove = function(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd)
{
	return this.DrawingObjects.remove(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd);
};
CDrawingsController.prototype.GetCursorPosXY = function()
{
	return this.DrawingObjects.cursorGetPos();
};
CDrawingsController.prototype.MoveCursorToStartPos = function(AddToSelect)
{
	if (true === AddToSelect)
	{
		// TODO: Пока ничего не делаем, в дальнейшем надо будет делать в зависимости от селекта внутри
		//       автофигуры: если селект текста внутри, то делать для текста внутри, а если выделена
		//       сама автофигура, тогда мы перемещаем курсор влево от нее в контенте параграфа и выделяем все до конца
	}
	else
	{
		this.LogicDocument.controller_MoveCursorToStartPos(false);
	}
};
CDrawingsController.prototype.MoveCursorToEndPos = function(AddToSelect)
{
	if (true === AddToSelect)
	{
		// TODO: Пока ничего не делаем, в дальнейшем надо будет делать в зависимости от селекта внутри
		//       автофигуры: если селект текста внутри, то делать для текста внутри, а если выделена
		//       сама автофигура, тогда мы перемещаем курсор влево от нее в контенте параграфа и выделяем все до конца
	}
	else
	{
		this.LogicDocument.controller_MoveCursorToEndPos(false);
	}
};
CDrawingsController.prototype.MoveCursorLeft = function(AddToSelect, Word)
{
	// Заглушка от передвижения автофигур внутри больщих таблиц
	if (!this.LogicDocument.Pages[this.LogicDocument.CurPage])
		return true;

	return this.DrawingObjects.cursorMoveLeft(AddToSelect, Word);
};
CDrawingsController.prototype.MoveCursorRight = function(AddToSelect, Word, FromPaste)
{
	// Заглушка от передвижения автофигур внутри больщих таблиц
	if (!this.LogicDocument.Pages[this.LogicDocument.CurPage])
		return true;

	return this.DrawingObjects.cursorMoveRight(AddToSelect, Word, FromPaste);
};
CDrawingsController.prototype.MoveCursorUp = function(AddToSelect, CtrlKey)
{
	// Заглушка от передвижения автофигур внутри больщих таблиц
	if (!this.LogicDocument.Pages[this.LogicDocument.CurPage])
		return true;

	var RetValue = this.DrawingObjects.cursorMoveUp(AddToSelect, CtrlKey);
	this.LogicDocument.Document_UpdateInterfaceState();
	this.LogicDocument.Document_UpdateSelectionState();
	return RetValue;
};
CDrawingsController.prototype.MoveCursorDown = function(AddToSelect, CtrlKey)
{
	// Заглушка от передвижения автофигур внутри больщих таблиц
	if (!this.LogicDocument.Pages[this.LogicDocument.CurPage])
		return true;

	var RetValue = this.DrawingObjects.cursorMoveDown(AddToSelect, CtrlKey);
	this.LogicDocument.Document_UpdateInterfaceState();
	this.LogicDocument.Document_UpdateSelectionState();
	return RetValue;
};
CDrawingsController.prototype.MoveCursorToEndOfLine = function(AddToSelect)
{
	return this.DrawingObjects.cursorMoveEndOfLine(AddToSelect);
};
CDrawingsController.prototype.MoveCursorToStartOfLine = function(AddToSelect)
{
	return this.DrawingObjects.cursorMoveStartOfLine(AddToSelect);
};
CDrawingsController.prototype.MoveCursorToXY = function(X, Y, PageAbs, AddToSelect)
{
	return this.DrawingObjects.cursorMoveAt(X, Y, AddToSelect);
};
CDrawingsController.prototype.MoveCursorToCell = function(bNext)
{
	return this.DrawingObjects.cursorMoveToCell(bNext);
};
CDrawingsController.prototype.SetParagraphAlign = function(Align)
{
	if (true != this.DrawingObjects.isSelectedText())
	{
		var ParaDrawing = this.DrawingObjects.getMajorParaDrawing();
		if (null != ParaDrawing)
		{
			var Paragraph = ParaDrawing.Parent;
			Paragraph.Set_Align(Align);
		}
	}
	else
	{
		this.DrawingObjects.setParagraphAlign(Align);
	}
};
CDrawingsController.prototype.SetParagraphSpacing = function (Spacing)
{
	if (true != this.DrawingObjects.isSelectedText())
	{
		var ParaDrawing = this.DrawingObjects.getMajorParaDrawing();
		if (null != ParaDrawing)
		{
			var Paragraph = ParaDrawing.Parent;
			Paragraph.Set_Spacing(Spacing, false);
			this.LogicDocument.Recalculate();
		}
	}
	else
	{
		this.DrawingObjects.setParagraphSpacing(Spacing);
	}
};
CDrawingsController.prototype.SetParagraphTabs = function(Tabs)
{
	this.DrawingObjects.setParagraphTabs(Tabs);
};
CDrawingsController.prototype.SetParagraphIndent = function(Ind)
{
	this.DrawingObjects.setParagraphIndent(Ind);
};
CDrawingsController.prototype.SetParagraphShd = function(Shd)
{
	this.DrawingObjects.setParagraphShd(Shd);
};
CDrawingsController.prototype.SetParagraphStyle = function(Name)
{
	this.DrawingObjects.setParagraphStyle(Name);
};
CDrawingsController.prototype.SetParagraphContextualSpacing = function(Value)
{
	this.DrawingObjects.setParagraphContextualSpacing(Value);
};
CDrawingsController.prototype.SetParagraphPageBreakBefore = function(Value)
{
	this.DrawingObjects.setParagraphPageBreakBefore(Value);
};
CDrawingsController.prototype.SetParagraphKeepLines = function(Value)
{
	this.DrawingObjects.setParagraphKeepLines(Value);
};
CDrawingsController.prototype.SetParagraphKeepNext = function(Value)
{
	this.DrawingObjects.setParagraphKeepNext(Value);
};
CDrawingsController.prototype.SetParagraphWidowControl = function(Value)
{
	this.DrawingObjects.setParagraphWidowControl(Value);
};
CDrawingsController.prototype.SetParagraphBorders = function(Borders)
{
	this.DrawingObjects.setParagraphBorders(Borders);
};
CDrawingsController.prototype.SetParagraphFramePr = function(FramePr, bDelete)
{
	// Не добавляем и не работаем с рамками в автофигурах
};
CDrawingsController.prototype.IncreaseDecreaseFontSize = function(bIncrease)
{
	this.DrawingObjects.paragraphIncDecFontSize(bIncrease);
};
CDrawingsController.prototype.IncreaseDecreaseIndent = function(bIncrease)
{
	if (true != this.DrawingObjects.isSelectedText())
	{
		var ParaDrawing = this.DrawingObjects.getMajorParaDrawing();
		if (null != ParaDrawing)
		{
			var Paragraph = ParaDrawing.Parent;
			Paragraph.IncreaseDecreaseIndent(bIncrease);
		}
	}
	else
	{
		this.DrawingObjects.paragraphIncDecIndent(bIncrease);
	}
};
CDrawingsController.prototype.SetImageProps = function(Props)
{
	this.DrawingObjects.setProps(Props);
};
CDrawingsController.prototype.SetTableProps = function(Props)
{
	this.DrawingObjects.setTableProps(Props);
};
CDrawingsController.prototype.GetCalculatedParaPr = function()
{
	return this.DrawingObjects.getParagraphParaPr();
};
CDrawingsController.prototype.GetCalculatedTextPr = function()
{
	return this.DrawingObjects.getParagraphTextPr();
};
CDrawingsController.prototype.GetDirectParaPr = function()
{
	return this.DrawingObjects.getParagraphParaPrCopy();
};
CDrawingsController.prototype.GetDirectTextPr = function()
{
	return this.DrawingObjects.getParagraphTextPrCopy();
};
CDrawingsController.prototype.RemoveSelection = function(bNoCheckDrawing)
{
	var ParaDrawing = this.DrawingObjects.getMajorParaDrawing();
	if (ParaDrawing)
	{
		ParaDrawing.GoTo_Text(undefined, false);
	}
	return this.DrawingObjects.resetSelection(undefined, bNoCheckDrawing);
};
CDrawingsController.prototype.IsSelectionEmpty = function(bCheckHidden)
{
	return false;
};
CDrawingsController.prototype.DrawSelectionOnPage = function(PageAbs)
{
	this.DrawingDocument.SetTextSelectionOutline(true);
	this.DrawingObjects.drawSelectionPage(PageAbs);
};
CDrawingsController.prototype.GetSelectionBounds = function()
{
	return this.DrawingObjects.GetSelectionBounds();
};
CDrawingsController.prototype.IsMovingTableBorder = function()
{
	return this.DrawingObjects.selectionIsTableBorder();
};
CDrawingsController.prototype.CheckPosInSelection = function(X, Y, PageAbs, NearPos)
{
	return this.DrawingObjects.selectionCheck(X, Y, PageAbs, NearPos);
};
CDrawingsController.prototype.SelectAll = function()
{
	this.DrawingObjects.selectAll();
};
CDrawingsController.prototype.GetSelectedContent = function(SelectedContent)
{
	this.DrawingObjects.GetSelectedContent(SelectedContent);
};
CDrawingsController.prototype.UpdateCursorType = function(X, Y, PageAbs, MouseEvent)
{
	// TODO: Надо вызывать не у LogicDocument, а у DocumentContent заданного
	this.LogicDocument.controller_UpdateCursorType(X, Y, PageAbs, MouseEvent);
};
CDrawingsController.prototype.PasteFormatting = function(TextPr, ParaPr)
{
	this.DrawingObjects.paragraphFormatPaste(TextPr, ParaPr, false);
};
CDrawingsController.prototype.IsSelectionUse = function()
{
	return this.DrawingObjects.isSelectionUse();
};
CDrawingsController.prototype.IsNumberingSelection = function()
{
	var oTargetDocContent = this.DrawingObjects.getTargetDocContent();
	if (oTargetDocContent && oTargetDocContent.IsNumberingSelection)
		return  oTargetDocContent.IsNumberingSelection();

	return false;
};
CDrawingsController.prototype.IsTextSelectionUse = function()
{
	return this.DrawingObjects.isTextSelectionUse();
};
CDrawingsController.prototype.GetCurPosXY = function()
{
	return this.DrawingObjects.getCurPosXY();
};
CDrawingsController.prototype.GetSelectedText = function(bClearText, oPr)
{
	return this.DrawingObjects.getSelectedText(bClearText, oPr);
};
CDrawingsController.prototype.GetCurrentParagraph = function(bIgnoreSelection, arrSelectedParagraphs)
{
	return this.DrawingObjects.getCurrentParagraph(bIgnoreSelection, arrSelectedParagraphs);
};
CDrawingsController.prototype.GetSelectedElementsInfo = function(oInfo)
{
	this.DrawingObjects.getSelectedElementsInfo(oInfo);
};
CDrawingsController.prototype.AddTableRow = function(bBefore)
{
	this.DrawingObjects.tableAddRow(bBefore);
};
CDrawingsController.prototype.AddTableColumn = function(bBefore)
{
	this.DrawingObjects.tableAddCol(bBefore);
};
CDrawingsController.prototype.RemoveTableRow = function()
{
	this.DrawingObjects.tableRemoveRow();
};
CDrawingsController.prototype.RemoveTableColumn = function()
{
	this.DrawingObjects.tableRemoveCol();
};
CDrawingsController.prototype.MergeTableCells = function()
{
	this.DrawingObjects.tableMergeCells();
};
CDrawingsController.prototype.SplitTableCells = function(Cols, Rows)
{
	this.DrawingObjects.tableSplitCell(Cols, Rows);
};
CDrawingsController.prototype.RemoveTable = function()
{
	this.DrawingObjects.tableRemoveTable();
};
CDrawingsController.prototype.SelectTable = function(Type)
{
	this.DrawingObjects.tableSelect(Type);
};
CDrawingsController.prototype.CanMergeTableCells = function()
{
	return this.DrawingObjects.tableCheckMerge();
};
CDrawingsController.prototype.CanSplitTableCells = function()
{
	return this.DrawingObjects.tableCheckSplit();
};
CDrawingsController.prototype.DistributeTableCells = function(isHorizontally)
{
	return this.DrawingObjects.distributeTableCells(isHorizontally);
};
CDrawingsController.prototype.UpdateInterfaceState = function()
{
	var oTargetTextObject = AscFormat.getTargetTextObject(this.DrawingObjects);
	if (oTargetTextObject)
	{
		this.LogicDocument.Interface_Update_DrawingPr();
		this.DrawingObjects.documentUpdateInterfaceState();
	}
	else
	{
		this.DrawingObjects.resetInterfaceTextPr();
		this.DrawingObjects.updateTextPr();
		this.LogicDocument.Interface_Update_DrawingPr();
		this.DrawingObjects.updateParentParagraphParaPr();
	}
};
CDrawingsController.prototype.UpdateRulersState = function()
{
	// Вызываем данную функцию, чтобы убрать рамку буквицы
	this.DrawingDocument.Set_RulerState_Paragraph(null);
	this.LogicDocument.Document_UpdateRulersStateBySection(this.LogicDocument.CurPos.ContentPos);
	this.DrawingObjects.documentUpdateRulersState();
};
CDrawingsController.prototype.UpdateSelectionState = function()
{
	this.DrawingObjects.documentUpdateSelectionState();
	this.LogicDocument.Document_UpdateTracks();
};
CDrawingsController.prototype.GetSelectionState = function()
{
	return this.DrawingObjects.getSelectionState();
};
CDrawingsController.prototype.SetSelectionState = function(State, StateIndex)
{
	this.DrawingObjects.setSelectionState(State, StateIndex);
};
CDrawingsController.prototype.AddHyperlink = function(Props)
{
	this.DrawingObjects.hyperlinkAdd(Props);
};
CDrawingsController.prototype.ModifyHyperlink = function(Props)
{
	this.DrawingObjects.hyperlinkModify(Props);
};
CDrawingsController.prototype.RemoveHyperlink = function()
{
	this.DrawingObjects.hyperlinkRemove();
};
CDrawingsController.prototype.CanAddHyperlink = function(bCheckInHyperlink)
{
	return this.DrawingObjects.hyperlinkCanAdd(bCheckInHyperlink);
};
CDrawingsController.prototype.IsCursorInHyperlink = function(bCheckEnd)
{
	return this.DrawingObjects.hyperlinkCheck(bCheckEnd);
};
CDrawingsController.prototype.AddComment = function(Comment)
{
	if (true !== this.DrawingObjects.isSelectedText())
	{
		var ParaDrawing = this.DrawingObjects.getMajorParaDrawing();
		if (null != ParaDrawing)
		{
			var Paragraph = ParaDrawing.Parent;
			Paragraph.AddCommentToObject(Comment, ParaDrawing.Get_Id());
		}
	}
	else
	{
		this.DrawingObjects.addComment(Comment);
	}
};
CDrawingsController.prototype.CanAddComment = function()
{
	if (true != this.DrawingObjects.isSelectedText())
		return true;
	else
		return this.DrawingObjects.canAddComment();
};
CDrawingsController.prototype.GetSelectionAnchorPos = function()
{
	var ParaDrawing = this.DrawingObjects.getMajorParaDrawing();
	return {
		X0   : ParaDrawing.GraphicObj.x,
		Y    : ParaDrawing.GraphicObj.y,
		X1   : ParaDrawing.GraphicObj.x + ParaDrawing.GraphicObj.extX,
		Page : ParaDrawing.PageNum
	};
};
CDrawingsController.prototype.StartSelectionFromCurPos = function()
{
	this.DrawingObjects.startSelectionFromCurPos();
};
CDrawingsController.prototype.SaveDocumentStateBeforeLoadChanges = function(State)
{
	this.DrawingObjects.Save_DocumentStateBeforeLoadChanges(State);
};
CDrawingsController.prototype.RestoreDocumentStateAfterLoadChanges = function(State)
{
	if (true !== this.DrawingObjects.Load_DocumentStateAfterLoadChanges(State))
	{
		var LogicDocument = this.LogicDocument;
		LogicDocument.Set_DocPosType(docpostype_Content);

		var ContentPos = 0;
		if (LogicDocument.Pages[LogicDocument.CurPage])
			ContentPos = LogicDocument.Pages[LogicDocument.CurPage].Pos + 1;
		else
			ContentPos = 0;

		ContentPos = Math.max(0, Math.min(LogicDocument.Content.length - 1, ContentPos));
		LogicDocument.CurPos.ContentPos = ContentPos;
		LogicDocument.Content[ContentPos].MoveCursorToStartPos(false);
	}
};
CDrawingsController.prototype.GetColumnSize = function()
{
	// TODO: Переделать
	var _w = Math.max(1, AscCommon.Page_Width - (AscCommon.X_Left_Margin + AscCommon.X_Right_Margin));
	var _h = Math.max(1, AscCommon.Page_Height - (AscCommon.Y_Top_Margin + AscCommon.Y_Bottom_Margin));

	return {
		W : AscCommon.Page_Width - (AscCommon.X_Left_Margin + AscCommon.X_Right_Margin),
		H : AscCommon.Page_Height - (AscCommon.Y_Top_Margin + AscCommon.Y_Bottom_Margin)
	};
};
CDrawingsController.prototype.GetCurrentSectionPr = function()
{
	return null;
};
CDrawingsController.prototype.RemoveTextSelection = function()
{
	this.DrawingObjects.removeTextSelection();
};
CDrawingsController.prototype.AddContentControl = function(nContentControlType)
{
	return this.DrawingObjects.AddContentControl(nContentControlType);
};
CDrawingsController.prototype.GetStyleFromFormatting = function()
{
	return this.DrawingObjects.GetStyleFromFormatting();
};
CDrawingsController.prototype.GetSimilarNumbering = function(oEngine)
{
	var oDocContent = this.DrawingObjects.getTargetDocContent();

	if (oDocContent && oDocContent.GetSimilarNumbering)
		oDocContent.GetSimilarNumbering(oEngine);
};
"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 10.06.2016
 * Time: 15:33
 */


// TODO: На самом деле этот класс не нужен. Его нужно совместить с классом CHeaderFooterController, пока он будет сделан
// как оберточный класс над CHeaderFooterController

/**
 * Специальный класс-обработчик команд в колонтитулах
 * @param {CDocument} LogicDocument - Ссылка на главный документ.
 * @param {CHeaderFooterController} HdrFtr - ССылка на объект, управляющий колонтитулами
 * @constructor
 * @extends {CDocumentControllerBase}
 */
function CHdrFtrController(LogicDocument, HdrFtr)
{
	CDocumentControllerBase.call(this, LogicDocument);
	this.HdrFtr = HdrFtr;
}
CHdrFtrController.prototype = Object.create(CDocumentControllerBase.prototype);
CHdrFtrController.prototype.constructor = CHdrFtrController;

CHdrFtrController.prototype.CanUpdateTarget = function()
{
	return true;
};
CHdrFtrController.prototype.RecalculateCurPos = function(bUpdateX, bUpdateY)
{
	return this.HdrFtr.RecalculateCurPos(bUpdateX, bUpdateY);
};
CHdrFtrController.prototype.GetCurPage = function()
{
	var CurHdrFtr = this.HdrFtr.CurHdrFtr;
	if (null !== CurHdrFtr && -1 !== CurHdrFtr.RecalcInfo.CurPage)
		return CurHdrFtr.RecalcInfo.CurPage;

	return -1;
};
CHdrFtrController.prototype.AddNewParagraph = function(bRecalculate, bForceAdd)
{
	return this.HdrFtr.AddNewParagraph(bRecalculate, bForceAdd);
};
CHdrFtrController.prototype.AddSignatureLine = function(oSignatureDrawing)
{
	this.HdrFtr.AddSignatureLine(oSignatureDrawing);
};
CHdrFtrController.prototype.AddInlineImage = function(nW, nH, oImage, oChart, bFlow)
{
	this.HdrFtr.AddInlineImage(nW, nH, oImage, oChart, bFlow);
};
CHdrFtrController.prototype.AddImages = function(aImages)
{
	this.HdrFtr.AddImages(aImages);
};
CHdrFtrController.prototype.AddOleObject = function(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId)
{
	this.HdrFtr.AddOleObject(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId);
};
CHdrFtrController.prototype.AddTextArt = function(nStyle)
{
	this.HdrFtr.AddTextArt(nStyle);
};
CHdrFtrController.prototype.EditChart = function(Chart)
{
	this.HdrFtr.EditChart(Chart);
};
CHdrFtrController.prototype.AddInlineTable = function(Cols, Rows)
{
	this.HdrFtr.AddInlineTable(Cols, Rows);
};
CHdrFtrController.prototype.ClearParagraphFormatting = function(isClearParaPr, isClearTextPr)
{
	this.HdrFtr.ClearParagraphFormatting(isClearParaPr, isClearTextPr);
};
CHdrFtrController.prototype.AddToParagraph = function(oItem, bRecalculate)
{
	if (para_NewLine === oItem.Type && true === oItem.IsPageOrColumnBreak())
		return;

	this.HdrFtr.AddToParagraph(oItem, bRecalculate);
	this.LogicDocument.Document_UpdateSelectionState();
	this.LogicDocument.Document_UpdateUndoRedoState();
};
CHdrFtrController.prototype.Remove = function(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd)
{
	var nResult = this.HdrFtr.Remove(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd);

	// TODO: Проверить зачем была добавлена эта заглушка. При удалении могут быть выставлены новые позиции курсора
	//       и селекта, поэтому странно убирать селект здесь.

	// if (null !== this.HdrFtr.CurHdtr && docpostype_DrawingObjects !== this.HdrFtr.CurHdrFtr.Content.CurPos.Type)
	// {
	// 	this.LogicDocument.RemoveSelection();
	// 	this.LogicDocument.Selection.Use = false;
	// }

	return nResult;
};
CHdrFtrController.prototype.GetCursorPosXY = function()
{
	return this.HdrFtr.GetCursorPosXY();
};
CHdrFtrController.prototype.MoveCursorToStartPos = function(AddToSelect)
{
	this.HdrFtr.MoveCursorToStartPos(AddToSelect);
};
CHdrFtrController.prototype.MoveCursorToEndPos = function(AddToSelect)
{
	this.HdrFtr.MoveCursorToEndPos(AddToSelect);
};
CHdrFtrController.prototype.MoveCursorLeft = function(AddToSelect, Word)
{
	return this.HdrFtr.MoveCursorLeft(AddToSelect, Word);
};
CHdrFtrController.prototype.MoveCursorRight = function(AddToSelect, Word, FromPaste)
{
	return this.HdrFtr.MoveCursorRight(AddToSelect, Word, FromPaste);
};
CHdrFtrController.prototype.MoveCursorUp = function(AddToSelect)
{
	var RetValue = this.HdrFtr.MoveCursorUp(AddToSelect);
	this.LogicDocument.Document_UpdateInterfaceState();
	this.LogicDocument.Document_UpdateSelectionState();
	return RetValue;
};
CHdrFtrController.prototype.MoveCursorDown = function(AddToSelect)
{
	var RetValue = this.HdrFtr.MoveCursorDown(AddToSelect);
	this.LogicDocument.Document_UpdateInterfaceState();
	this.LogicDocument.Document_UpdateSelectionState();
	return RetValue;
};
CHdrFtrController.prototype.MoveCursorToEndOfLine = function(AddToSelect)
{
	return this.HdrFtr.MoveCursorToEndOfLine(AddToSelect);
};
CHdrFtrController.prototype.MoveCursorToStartOfLine = function(AddToSelect)
{
	return this.HdrFtr.MoveCursorToStartOfLine(AddToSelect);
};
CHdrFtrController.prototype.MoveCursorToXY = function(X, Y, PageAbs, AddToSelect)
{
	return this.HdrFtr.MoveCursorToXY(X, Y, PageAbs, AddToSelect);
};
CHdrFtrController.prototype.MoveCursorToCell = function(bNext)
{
	return this.HdrFtr.MoveCursorToCell(bNext);
};
CHdrFtrController.prototype.SetParagraphAlign = function(Align)
{
	this.HdrFtr.SetParagraphAlign(Align);
};
CHdrFtrController.prototype.SetParagraphSpacing = function (Spacing)
{
	this.HdrFtr.SetParagraphSpacing(Spacing);
};
CHdrFtrController.prototype.SetParagraphTabs = function(Tabs)
{
	this.HdrFtr.SetParagraphTabs(Tabs);
};
CHdrFtrController.prototype.SetParagraphIndent = function(Ind)
{
	this.HdrFtr.SetParagraphIndent(Ind);
};
CHdrFtrController.prototype.SetParagraphShd = function(Shd)
{
	this.HdrFtr.SetParagraphShd(Shd);
};
CHdrFtrController.prototype.SetParagraphStyle = function(Name)
{
	this.HdrFtr.SetParagraphStyle(Name);
};
CHdrFtrController.prototype.SetParagraphContextualSpacing = function(Value)
{
	this.HdrFtr.SetParagraphContextualSpacing(Value);
};
CHdrFtrController.prototype.SetParagraphPageBreakBefore = function(Value)
{
	this.HdrFtr.SetParagraphPageBreakBefore(Value);
};
CHdrFtrController.prototype.SetParagraphKeepLines = function(Value)
{
	this.HdrFtr.SetParagraphKeepLines(Value);
};
CHdrFtrController.prototype.SetParagraphKeepNext = function(Value)
{
	this.HdrFtr.SetParagraphKeepNext(Value);
};
CHdrFtrController.prototype.SetParagraphWidowControl = function(Value)
{
	this.HdrFtr.SetParagraphWidowControl(Value);
};
CHdrFtrController.prototype.SetParagraphBorders = function(Borders)
{
	this.HdrFtr.SetParagraphBorders(Borders);
};
CHdrFtrController.prototype.SetParagraphFramePr = function(FramePr, bDelete)
{
	this.HdrFtr.SetParagraphFramePr(FramePr, bDelete);
};
CHdrFtrController.prototype.IncreaseDecreaseFontSize = function(bIncrease)
{
	this.HdrFtr.IncreaseDecreaseFontSize(bIncrease);
};
CHdrFtrController.prototype.IncreaseDecreaseIndent = function(bIncrease)
{
	this.HdrFtr.IncreaseDecreaseIndent(bIncrease);
};
CHdrFtrController.prototype.SetImageProps = function(Props)
{
	this.HdrFtr.SetImageProps(Props);
};
CHdrFtrController.prototype.SetTableProps = function(Props)
{
	this.HdrFtr.SetTableProps(Props);
};
CHdrFtrController.prototype.GetCalculatedParaPr = function()
{
	return this.HdrFtr.GetCalculatedParaPr();
};
CHdrFtrController.prototype.GetCalculatedTextPr = function()
{
	return this.HdrFtr.GetCalculatedTextPr();
};
CHdrFtrController.prototype.GetDirectParaPr = function()
{
	return this.HdrFtr.GetDirectParaPr();
};
CHdrFtrController.prototype.GetDirectTextPr = function()
{
	return this.HdrFtr.GetDirectTextPr();
};
CHdrFtrController.prototype.RemoveSelection = function(bNoCheckDrawing)
{
	this.HdrFtr.RemoveSelection(bNoCheckDrawing);
};
CHdrFtrController.prototype.IsSelectionEmpty = function(bCheckHidden)
{
	return this.HdrFtr.IsSelectionEmpty(bCheckHidden);
};
CHdrFtrController.prototype.DrawSelectionOnPage = function(PageAbs)
{
	this.HdrFtr.DrawSelectionOnPage(PageAbs);
};
CHdrFtrController.prototype.GetSelectionBounds = function()
{
	return this.HdrFtr.GetSelectionBounds();
};
CHdrFtrController.prototype.IsMovingTableBorder = function()
{
	return this.HdrFtr.IsMovingTableBorder();
};
CHdrFtrController.prototype.CheckPosInSelection = function(X, Y, PageAbs, NearPos)
{
	return this.HdrFtr.CheckPosInSelection(X, Y, PageAbs, NearPos);
};
CHdrFtrController.prototype.SelectAll = function()
{
	this.HdrFtr.SelectAll();
};
CHdrFtrController.prototype.GetSelectedContent = function(SelectedContent)
{
	this.HdrFtr.GetSelectedContent(SelectedContent);
};
CHdrFtrController.prototype.UpdateCursorType = function(X, Y, PageAbs, MouseEvent)
{
	this.HdrFtr.UpdateCursorType(X, Y, PageAbs, MouseEvent);
};
CHdrFtrController.prototype.PasteFormatting = function(TextPr, ParaPr)
{
	this.HdrFtr.PasteFormatting(TextPr, ParaPr, false);
};
CHdrFtrController.prototype.IsSelectionUse = function()
{
	return this.HdrFtr.IsSelectionUse();
};
CHdrFtrController.prototype.IsNumberingSelection = function()
{
	return this.HdrFtr.IsNumberingSelection();
};
CHdrFtrController.prototype.IsTextSelectionUse = function()
{
	return this.HdrFtr.IsTextSelectionUse();
};
CHdrFtrController.prototype.GetCurPosXY = function()
{
	return this.HdrFtr.GetCurPosXY();
};
CHdrFtrController.prototype.GetSelectedText = function(bClearText, oPr)
{
	return this.HdrFtr.GetSelectedText(bClearText, oPr);
};
CHdrFtrController.prototype.GetCurrentParagraph = function(bIgnoreSelection, arrSelectedParagraphs)
{
	return this.HdrFtr.GetCurrentParagraph(bIgnoreSelection, arrSelectedParagraphs);
};
CHdrFtrController.prototype.GetSelectedElementsInfo = function(oInfo)
{
	this.HdrFtr.GetSelectedElementsInfo(oInfo);
};
CHdrFtrController.prototype.AddTableRow = function(bBefore)
{
	this.HdrFtr.AddTableRow(bBefore);
};
CHdrFtrController.prototype.AddTableColumn = function(bBefore)
{
	this.HdrFtr.AddTableColumn(bBefore);
};
CHdrFtrController.prototype.RemoveTableRow = function()
{
	this.HdrFtr.RemoveTableRow();
};
CHdrFtrController.prototype.RemoveTableColumn = function()
{
	this.HdrFtr.RemoveTableColumn();
};
CHdrFtrController.prototype.MergeTableCells = function()
{
	this.HdrFtr.MergeTableCells();
};
CHdrFtrController.prototype.SplitTableCells = function(Cols, Rows)
{
	this.HdrFtr.SplitTableCells(Cols, Rows);
};
CHdrFtrController.prototype.RemoveTable = function()
{
	this.HdrFtr.RemoveTable();
};
CHdrFtrController.prototype.SelectTable = function(Type)
{
	this.HdrFtr.SelectTable(Type);
};
CHdrFtrController.prototype.CanMergeTableCells = function()
{
	return this.HdrFtr.CanMergeTableCells();
};
CHdrFtrController.prototype.CanSplitTableCells = function()
{
	return this.HdrFtr.CanSplitTableCells();
};
CHdrFtrController.prototype.UpdateInterfaceState = function()
{
	this.LogicDocument.Interface_Update_HdrFtrPr();
	this.HdrFtr.Document_UpdateInterfaceState();
};
CHdrFtrController.prototype.UpdateRulersState = function()
{
	this.DrawingDocument.Set_RulerState_Paragraph(null);
	this.HdrFtr.Document_UpdateRulersState(this.LogicDocument.CurPage);
};
CHdrFtrController.prototype.UpdateSelectionState = function()
{
	this.HdrFtr.Document_UpdateSelectionState();
	this.LogicDocument.Document_UpdateTracks();
};
CHdrFtrController.prototype.GetSelectionState = function()
{
	return this.HdrFtr.GetSelectionState();
};
CHdrFtrController.prototype.SetSelectionState = function(State, StateIndex)
{
	this.HdrFtr.SetSelectionState(State, StateIndex);
};
CHdrFtrController.prototype.AddHyperlink = function(Props)
{
	this.HdrFtr.AddHyperlink(Props);
};
CHdrFtrController.prototype.ModifyHyperlink = function(Props)
{
	this.HdrFtr.ModifyHyperlink(Props);
};
CHdrFtrController.prototype.RemoveHyperlink = function()
{
	this.HdrFtr.RemoveHyperlink();
};
CHdrFtrController.prototype.CanAddHyperlink = function(bCheckInHyperlink)
{
	return this.HdrFtr.CanAddHyperlink(bCheckInHyperlink);
};
CHdrFtrController.prototype.IsCursorInHyperlink = function(bCheckEnd)
{
	return this.HdrFtr.IsCursorInHyperlink(bCheckEnd);
};
CHdrFtrController.prototype.AddComment = function(Comment)
{
	this.HdrFtr.AddComment(Comment);
};
CHdrFtrController.prototype.CanAddComment = function()
{
	return this.HdrFtr.CanAddComment();
};
CHdrFtrController.prototype.GetSelectionAnchorPos = function()
{
	return this.HdrFtr.GetSelectionAnchorPos();
};
CHdrFtrController.prototype.StartSelectionFromCurPos = function()
{
	this.HdrFtr.StartSelectionFromCurPos();
};
CHdrFtrController.prototype.SaveDocumentStateBeforeLoadChanges = function(State)
{
	var HdrFtr = this.HdrFtr.Get_CurHdrFtr();
	if (null !== HdrFtr)
	{
		var HdrFtrContent = HdrFtr.Get_DocumentContent();
		State.HdrFtr      = HdrFtr;

		State.HdrFtrDocPosType = HdrFtrContent.CurPos.Type;
		State.HdrFtrSelection  = HdrFtrContent.Selection.Use;

		if (docpostype_Content === HdrFtrContent.Get_DocPosType())
		{
			State.Pos      = HdrFtrContent.GetContentPosition(false, false, undefined);
			State.StartPos = HdrFtrContent.GetContentPosition(true, true, undefined);
			State.EndPos   = HdrFtrContent.GetContentPosition(true, false, undefined);
		}
		else if (docpostype_DrawingObjects === HdrFtrContent.Get_DocPosType())
		{
			this.LogicDocument.DrawingObjects.Save_DocumentStateBeforeLoadChanges(State);
		}
	}
};
CHdrFtrController.prototype.RestoreDocumentStateAfterLoadChanges = function(State)
{
	var HdrFtr = State.HdrFtr;
	if (null !== HdrFtr && undefined !== HdrFtr && true === HdrFtr.Is_UseInDocument())
	{
		this.HdrFtr.Set_CurHdrFtr(HdrFtr);
		var HdrFtrContent = HdrFtr.Get_DocumentContent();
		if (docpostype_Content === State.HdrFtrDocPosType)
		{
			HdrFtrContent.Set_DocPosType(docpostype_Content);
			HdrFtrContent.Selection.Use = State.HdrFtrSelection;
			if (true === HdrFtrContent.Selection.Use)
			{
				HdrFtrContent.SetContentPosition(State.StartPos, 0, 0);
				HdrFtrContent.SetContentSelection(State.StartPos, State.EndPos, 0, 0, 0);
			}
			else
			{
				HdrFtrContent.SetContentPosition(State.Pos, 0, 0);
				this.LogicDocument.NeedUpdateTarget = true;
			}
		}
		else if (docpostype_DrawingObjects === State.HdrFtrDocPosType)
		{
			HdrFtrContent.Set_DocPosType(docpostype_DrawingObjects);

			if (true !== this.LogicDocument.DrawingObjects.Load_DocumentStateAfterLoadChanges(State))
			{
				HdrFtrContent.Set_DocPosType(docpostype_Content);
				HdrFtrContent.MoveCursorToStartPos();
			}
		}
	}
	else
	{
		this.LogicDocument.EndHdrFtrEditing(false);
	}
};
CHdrFtrController.prototype.GetColumnSize = function()
{
	var CurHdrFtr = this.HdrFtr.CurHdrFtr;
	if (null !== CurHdrFtr && -1 !== CurHdrFtr.RecalcInfo.CurPage)
	{
		var Page   = this.LogicDocument.Pages[CurHdrFtr.RecalcInfo.CurPage];
		var SectPr = this.LogicDocument.Get_SectPr(Page.Pos);

		var Y      = SectPr.Get_PageMargin_Top();
		var YLimit = SectPr.Get_PageHeight() - SectPr.Get_PageMargin_Bottom();
		var X      = SectPr.Get_PageMargin_Left();
		var XLimit = SectPr.Get_PageWidth() - SectPr.Get_PageMargin_Right();

		return {
			W : XLimit - X,
			H : YLimit - Y
		};
	}

	return {W : 0, H : 0};
};
CHdrFtrController.prototype.GetCurrentSectionPr = function()
{
	return null;
};
CHdrFtrController.prototype.RemoveTextSelection = function()
{
	var CurHdrFtr = this.HdrFtr.CurHdrFtr;
	if (null != CurHdrFtr)
		return CurHdrFtr.Content.RemoveTextSelection();
};
CHdrFtrController.prototype.AddContentControl = function(nContentControlType)
{
	var CurHdrFtr = this.HdrFtr.CurHdrFtr;
	if (null != CurHdrFtr)
		return CurHdrFtr.Content.AddContentControl(nContentControlType);

	return null;
};
CHdrFtrController.prototype.GetStyleFromFormatting = function()
{
	return this.HdrFtr.GetStyleFromFormatting();
};
CHdrFtrController.prototype.GetSimilarNumbering = function(oEngine)
{
	this.HdrFtr.GetSimilarNumbering(oEngine)
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Функция копирует объект или массив. (Обычное равенство в javascript приравнивает указатели)
function Common_CopyObj(Obj)
{
    if( !Obj || !('object' == typeof(Obj) || 'array' == typeof(Obj)) )
    {
        return Obj;
    }

    var c = 'function' === typeof Obj.pop ? [] : {};
    var p, v;
    for(p in Obj)
    {
        if(Obj.hasOwnProperty(p))
        {
            v = Obj[p];
            if(v && 'object' === typeof v )
            {
                c[p] = Common_CopyObj(v);
            }
            else
            {
                c[p] = v;
            }
        }
    }
    return c;
}
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// TODO: При расчете таблиц есть один баг, который надо будет поправить в будущем:
//       при разбиении строки на страницы возможен вариант, когда у каких-то ячеек
//       убирается содержимое на первой странице, а у каких-то - нет. В данном случае
//       надо для всех ячеек содержимое переносить на новую страницу(как в Word).

// TODO: Несовсем правильно(всмысле не как в Word) обрабатывается верхнее поле ячеек:
//       особенно это проявляется в таблицах с ненулевым расстоянием между ячейками.

    
// TODO: Оказалось, что параметр "не отрывать от следующего" влияет и на таблицы, если 
//       после параграфа с таким параметром идет таблица. (см. MSFT_FY11Q3_10Q.docx стр. 3)
    
// TODO: Поскольку, расстояния до/после параграфа для первого и последнего параграфов 
//       в ячейке зависит от следующей и предыдущей ячеек, надо включать их в пересчет

// Import
var align_Left = AscCommon.align_Left;
var CMouseMoveData = AscCommon.CMouseMoveData;
var g_oTableId = AscCommon.g_oTableId;
var History = AscCommon.History;

var linerule_AtLeast = Asc.linerule_AtLeast;
var c_oAscError = Asc.c_oAscError;
var c_oAscHAnchor = Asc.c_oAscHAnchor;
var c_oAscXAlign = Asc.c_oAscXAlign;
var c_oAscYAlign = Asc.c_oAscYAlign;
var c_oAscVAnchor = Asc.c_oAscVAnchor;
var c_oAscCellTextDirection = Asc.c_oAscCellTextDirection;
    

var table_Selection_Cell = 0x00; // Селектим целыми ячейками
var table_Selection_Text = 0x01; // Селектим текст внутри текущей ячейки

var table_Selection_Common            = 0x00;
var table_Selection_Border            = 0x01;
var table_Selection_Border_InnerTable = 0x02;
var table_Selection_Rows              = 0x03; // Селектим по строкам
var table_Selection_Columns           = 0x04; // Селектим по колонкам
var table_Selection_Cells             = 0x05; // Селектим только по ячейкам

var type_Table = 0x0002;


/**
 * Класс CTable
 * @constructor
 * @extends {CDocumentContentElementBase}
 */
function CTable(DrawingDocument, Parent, Inline, Rows, Cols, TableGrid, bPresentation)
{
	CDocumentContentElementBase.call(this, Parent);

    this.Markup = new AscCommon.CTableMarkup(this);

    this.Inline = Inline;

    this.Lock = new AscCommon.CLock();
    // TODO: Когда у g_oIdCounter будет тоже проверка на TurnOff заменить здесь
    if (false === AscCommon.g_oIdCounter.m_bLoad && true === History.Is_On())
    {
        this.Lock.Set_Type(AscCommon.locktype_Mine, false);
        if (AscCommon.CollaborativeEditing)
            AscCommon.CollaborativeEditing.Add_Unlock2(this);
    }
    
    this.DrawingDocument = null;
    this.LogicDocument   = null;
    
    if ( undefined !== DrawingDocument && null !== DrawingDocument )
    {
        this.DrawingDocument = DrawingDocument;
        this.LogicDocument   = this.DrawingDocument.m_oLogicDocument;
    }
    
    this.CompiledPr =
    {
        Pr         : null,  // Скомпилированный (окончательный стиль)
        NeedRecalc : true   // Нужно ли пересчитать скомпилированный стиль
    };

    this.Pr = new CTablePr();
    this.Pr.TableW = new CTableMeasurement(tblwidth_Auto, 0);

    this.TableGridNeedRecalc = true;
    this.bPresentation = bPresentation === true;

    // TODO: TableLook и TableStyle нужно перемесить в TablePr
    this.TableStyle = (undefined !== this.DrawingDocument && null !== this.DrawingDocument && this.DrawingDocument.m_oLogicDocument && this.DrawingDocument.m_oLogicDocument.Styles ? this.DrawingDocument.m_oLogicDocument.Styles.Get_Default_TableGrid() : null);
    this.TableLook  = new CTableLook(true, true, false, false, true, false);

    this.TableSumGrid  = []; // данный массив будет заполнен после private_RecalculateGrid
    this.TableGrid     = TableGrid ? TableGrid : [];
    this.TableGridCalc = this.private_CopyTableGrid();

    this.RecalcInfo = new CTableRecalcInfo();

    this.Rows = Rows;
    this.Cols = Cols;

    // Массив строк
    this.Content = [];
    for ( var Index = 0; Index < Rows; Index++ )
    {
        this.Content[Index] = new CTableRow( this, Cols, TableGrid );
    }

    this.Internal_ReIndexing(0);

    // Информация о строках (расположение, высота и остальные метрики)
    this.RowsInfo = [];
    this.TableRowsBottom = [];
    this.HeaderInfo =
    {
		HeaderRecalculate : false, // В данный момент идет пересчет самих заголовков
		Count             : 0,     // Количество строк, входящих в заголовок
		H                 : 0,     // Суммарная высота, занимаемая заголовком
		PageIndex         : 0,     // Страница, на которой лежит исходный заголовок (либо 0, либо 1)
		Pages             : []
	};

    this.Selection =
    {
        Start    : false,
        Use      : false,
        StartPos :
        {
            Pos        : { Row : 0, Cell : 0 },
            X          : 0,
            Y          : 0,
            PageIndex  : 0,
            MouseEvent : { ClickCount : 1, Type : AscCommon.g_mouse_event_type_down, CtrlKey : false }
        },
        EndPos   :
        {
            Pos        : { Row : 0, Cell : 0 },
            X          : 0,
            Y          : 0,
            PageIndex  : 0,
            MouseEvent : { ClickCount : 1, Type : AscCommon.g_mouse_event_type_down, CtrlKey : false }
        },
        Type     : table_Selection_Text,
        Data     : null,
        Type2    : table_Selection_Common,
        Data2    : null,
        CurRow   : 0  // Специальный параметр, используемый для стрелок вправо/влево
    };

    // this.X_origin - точка, которую нам задали как начальную для рисования таблицы
    // this.X        - фактическая начальная точка для рисования и обсчета таблицы
    this.X_origin = 0;

    this.AllowOverlap = true;

    // Позиция по горизонтали
    this.PositionH =
    {
        RelativeFrom : c_oAscHAnchor.Page, // Относительно чего вычисляем координаты
        Align        : true,               // true : В поле Value лежит тип прилегания, false - в поле Value лежит точное значени
        Value        : c_oAscXAlign.Center //
    };

    this.PositionH_Old = undefined;

    // Позиция по горизонтали
    this.PositionV =
    {
        RelativeFrom : c_oAscVAnchor.Page, // Относительно чего вычисляем координаты
        Align        : true,               // true : В поле Value лежит тип прилегания, false - в поле Value лежит точное значени
        Value        : c_oAscYAlign.Center //
    };

    this.PositionV_Old = undefined;

    // Расстояние до окружающего текста
    this.Distance =
    {
        T : 0,
        B : 0,
        L : 0,
        R : 0
    };

    this.AnchorPosition = new CTableAnchorPosition();
    
    this.Pages    = [];
    this.Pages[0] = new CTablePage(0, 0, 0, 0, 0, 0);

    this.MaxTopBorder = [];
    this.MaxBotBorder = [];
    this.MaxBotMargin = [];

    // Выставляем текущую ячейку
    if ( this.Content.length > 0 )
        this.CurCell = this.Content[0].Get_Cell( 0 );
    else
        this.CurCell = null;

    this.TurnOffRecalc = false;

    this.ApplyToAll = false; // Специальный параметр, используемый в ячейках таблицы.
                             // True, если ячейка попадает в выделение по ячейкам.

    this.m_oContentChanges = new AscCommon.CContentChanges(); // список изменений(добавление/удаление элементов)
    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    g_oTableId.Add( this, this.Id );
}

CTable.prototype = Object.create(CDocumentContentElementBase.prototype);
CTable.prototype.constructor = CTable;

CTable.prototype.GetType = function()
{
	return type_Table;
};
//----------------------------------------------------------------------------------------------------------------------
// Общие функции
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.Get_Theme = function()
{
	return this.Parent.Get_Theme();
};
CTable.prototype.Get_ColorMap = function()
{
	return this.Parent.Get_ColorMap();
};
CTable.prototype.Get_Props = function()
{
	var TablePr = this.Get_CompiledPr(false).TablePr;

	var Pr = {};

	if (tblwidth_Auto === TablePr.TableW.Type)
		Pr.TableWidth = null;
	else if (tblwidth_Mm === TablePr.TableW.Type)
		Pr.TableWidth = TablePr.TableW.W;
	else// if (tblwidth_Pct === TablePr.TableW.Type)
		Pr.TableWidth = -TablePr.TableW.W;

	Pr.AllowOverlap = this.AllowOverlap;

	// Пока у нас во всей таблицы одинаковый Spacing
	Pr.TableSpacing = this.Content[0].Get_CellSpacing();

	Pr.TableDefaultMargins = {
		Left   : TablePr.TableCellMar.Left.W,
		Right  : TablePr.TableCellMar.Right.W,
		Top    : TablePr.TableCellMar.Top.W,
		Bottom : TablePr.TableCellMar.Bottom.W
	};

	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		Pr.CellSelect = true;

		var CellMargins    = null;
		var CellMarginFlag = false;

		var Border_left    = null;
		var Border_right   = null;
		var Border_top     = null;
		var Border_bottom  = null;
		var Border_insideH = null;
		var Border_insideV = null;

		var CellShd        = null;
		var CellWidth      = undefined;
		var CellWidthStart = undefined;

		var Prev_row  = -1;
		var bFirstRow = true;

		var VAlign        = null;
		var TextDirection = null;
		var NoWrap        = null;

		var nRowHeight = null;

		for (var Index = 0; Index < this.Selection.Data.length; Index++)
		{
			var Pos          = this.Selection.Data[Index];
			var Row          = this.Content[Pos.Row];
			var Cell         = Row.Get_Cell(Pos.Cell);
			var Cell_borders = Cell.Get_Borders();
			var Cell_margins = Cell.GetMargins();
			var Cell_shd     = Cell.Get_Shd();
			var Cell_w       = Cell.Get_W();

			if (0 === Index)
			{
				VAlign        = Cell.Get_VAlign();
				TextDirection = Cell.Get_TextDirection();
				NoWrap        = Cell.Get_NoWrap();
			}
			else
			{
				if (VAlign !== Cell.Get_VAlign())
					VAlign = null;

				if (TextDirection !== Cell.Get_TextDirection())
					TextDirection = null;

				if (NoWrap !== Cell.Get_NoWrap())
					NoWrap = null;
			}

			if (0 === Index)
			{
				CellShd = Cell_shd;
			}
			else
			{
				if (null != CellShd && ( CellShd.Value != Cell_shd.Value || CellShd.Color.r != Cell_shd.Color.r || CellShd.Color.g != Cell_shd.Color.g || CellShd.Color.b != Cell_shd.Color.b ))
					CellShd = null;
			}

			var _CellWidth;
			if (tblwidth_Auto === Cell_w.Type)
				_CellWidth = null;
			else if (tblwidth_Mm === Cell_w.Type)
				_CellWidth = Cell_w.W;
			else// if (tblwidth_Pct === Cell_w.Type)
				_CellWidth = -Cell_w.W;

			if (0 === Index)
			{
				CellWidthStart = _CellWidth;
			}
			else
			{

				if ((tblwidth_Auto === Cell_w.Type && null !== CellWidth)
					|| (undefined === CellWidth
					|| null === CellWidth
					|| Math.abs(CellWidth - _CellWidth) > 0.001))
					CellWidth = undefined;
			}

			// Крайняя левая ли данная ячейка в выделении?
			if (0 === Index || this.Selection.Data[Index - 1].Row != Pos.Row)
			{
				if (null === Border_left)
					Border_left = Cell_borders.Left;
				else
					Border_left = this.Internal_CompareBorders2(Border_left, Cell_borders.Left);
			}
			else
			{
				if (null === Border_insideV)
					Border_insideV = Cell_borders.Left;
				else
					Border_insideV = this.Internal_CompareBorders2(Border_insideV, Cell_borders.Left);
			}

			// Крайняя правая ли данная ячейка в выделении?
			if (this.Selection.Data.length - 1 === Index || this.Selection.Data[Index + 1].Row != Pos.Row)
			{
				if (null === Border_right)
					Border_right = Cell_borders.Right;
				else
					Border_right = this.Internal_CompareBorders2(Border_right, Cell_borders.Right);
			}
			else
			{
				if (null === Border_insideV)
					Border_insideV = Cell_borders.Right;
				else
					Border_insideV = this.Internal_CompareBorders2(Border_insideV, Cell_borders.Right);
			}

			if (Prev_row != Pos.Row)
			{
				if (-1 != Prev_row)
					bFirstRow = false;

				if (false === bFirstRow)
				{
					if (null === Border_insideH)
					{
						Border_insideH = Border_bottom;
						Border_insideH = this.Internal_CompareBorders2(Border_insideH, Cell_borders.Top);
					}
					else
					{
						Border_insideH = this.Internal_CompareBorders2(Border_insideH, Border_bottom);
						Border_insideH = this.Internal_CompareBorders2(Border_insideH, Cell_borders.Top);
					}
				}
				else
				{
					if (null === Border_top)
						Border_top = Cell_borders.Top;
				}

				Border_bottom = Cell_borders.Bottom;
				Prev_row      = Pos.Row;
			}
			else
			{
				if (false === bFirstRow)
				{
					if (null === Border_insideH)
						Border_insideH = Cell_borders.Top;
					else
						Border_insideH = this.Internal_CompareBorders2(Border_insideH, Cell_borders.Top);
				}
				else
				{
					if (null === Border_top)
						Border_top = Cell_borders.Top;
					else
						Border_top = this.Internal_CompareBorders2(Border_top, Cell_borders.Top);
				}

				Border_bottom = this.Internal_CompareBorders2(Border_bottom, Cell_borders.Bottom);
			}

			if (true != Cell.Is_TableMargins())
			{
				if (null === CellMargins)
				{
					CellMargins = Common_CopyObj(Cell_margins);
				}
				else
				{
					if (CellMargins.Left.W != Cell_margins.Left.W)
						CellMargins.Left.W = null;

					if (CellMargins.Right.W != Cell_margins.Right.W)
						CellMargins.Right.W = null;

					if (CellMargins.Top.W != Cell_margins.Top.W)
						CellMargins.Top.W = null;

					if (CellMargins.Bottom.W != Cell_margins.Bottom.W)
						CellMargins.Bottom.W = null;
				}
			}
			else
			{
				CellMarginFlag = true;
			}


			var nCurRowHeight;
			var oRowH = Row.GetHeight();
			if (oRowH.IsAuto())
			{
				var oRow    = Row;
				var nCurRow = oRow.GetIndex();

				var nRowSummaryH = 0;

				// Проверка на случай непересчитанной таблицы
				if (this.RowsInfo[nCurRow])
				{
					for (var nCurPage in this.RowsInfo[nCurRow].H)
						nRowSummaryH += this.RowsInfo[nCurRow].H[nCurPage];

					if (null !== Pr.TableSpacing)
						nRowSummaryH += Pr.TableSpacing;
					else if (this.RowsInfo[nCurRow].TopDy[0])
						nRowSummaryH -= this.RowsInfo[nCurRow].TopDy[0];

					nRowSummaryH -= oRow.GetTopMargin() + oRow.GetBottomMargin();
				}

				nCurRowHeight = nRowSummaryH;
			}
			else
			{
				nCurRowHeight = oRowH.GetValue();
			}

			if (null === nRowHeight)
				nRowHeight = nCurRowHeight;
			else if (undefined !== nRowHeight && Math.abs(nRowHeight - nCurRowHeight) > 0.001)
				nRowHeight = undefined;
		}

		Pr.CellsVAlign        = VAlign;
		Pr.CellsTextDirection = TextDirection;
		Pr.CellsNoWrap        = NoWrap;

		if (undefined === CellWidth)
		{
			Pr.CellsWidth         = CellWidthStart;
			Pr.CellsWidthNotEqual = true;
		}
		else
		{
			Pr.CellsWidth         = CellWidthStart;
			Pr.CellsWidthNotEqual = false;
		}

		Pr.RowHeight   = nRowHeight;

		Pr.CellBorders = {
			Left    : Border_left.Copy(),
			Right   : Border_right.Copy(),
			Top     : Border_top.Copy(),
			Bottom  : Border_bottom.Copy(),
			InsideH : null === Border_insideH ? null : Border_insideH.Copy(),
			InsideV : null === Border_insideV ? null : Border_insideV.Copy()
		};

		if (null === CellShd)
			Pr.CellsBackground = null;
		else
			Pr.CellsBackground = CellShd.Copy();

		if (null === CellMargins)
		{
			Pr.CellMargins = {
				Flag : 0
			};
		}
		else
		{
			var Flag = 2;
			if (true === CellMarginFlag)
				Flag = 1;

			Pr.CellMargins = {
				Left   : CellMargins.Left.W,
				Right  : CellMargins.Right.W,
				Top    : CellMargins.Top.W,
				Bottom : CellMargins.Bottom.W,
				Flag   : Flag
			};
		}
	}
	else
	{
		Pr.CellSelect = false;

		var Cell        = this.CurCell;
		var CellMargins = Cell.GetMargins();
		var CellBorders = Cell.Get_Borders();
		var CellShd     = Cell.Get_Shd();
		var CellW       = Cell.Get_W();

		if (true === Cell.Is_TableMargins())
		{
			Pr.CellMargins = {
				Flag : 0
			};
		}
		else
		{
			Pr.CellMargins = {
				Left   : CellMargins.Left.W,
				Right  : CellMargins.Right.W,
				Top    : CellMargins.Top.W,
				Bottom : CellMargins.Bottom.W,
				Flag   : 2
			};
		}

		Pr.CellsVAlign        = Cell.Get_VAlign();
		Pr.CellsTextDirection = Cell.Get_TextDirection();
		Pr.CellsNoWrap        = Cell.Get_NoWrap();

		Pr.CellsBackground = CellShd.Copy();

		if (tblwidth_Auto === CellW.Type)
			Pr.CellsWidth = null;
		else if (tblwidth_Mm === CellW.Type)
			Pr.CellsWidth = CellW.W;
		else// if (tblwidth_Pct === CellW.Type)
			Pr.CellsWidth = -CellW.W;

		Pr.CellsWidthNotEqual = false;

		var Spacing = this.Content[0].Get_CellSpacing();

		var Border_left    = null;
		var Border_right   = null;
		var Border_top     = null;
		var Border_bottom  = null;
		var Border_insideH = null;
		var Border_insideV = null;

		var CellShd = null;

		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			var Row         = this.Content[CurRow];
			var Cells_Count = Row.Get_CellsCount();

			for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
			{
				var Cell         = Row.Get_Cell(CurCell);
				var Cell_borders = Cell.Get_Borders();
				var Cell_shd     = Cell.Get_Shd();
				var oCellW       = Cell.GetW();

				if (0 === CurCell && Cells_Count)
				{
					CellShd = Cell_shd;
				}
				else
				{
					if (null != CellShd && ( CellShd.Value != Cell_shd.Value || CellShd.Color.r != Cell_shd.Color.r || CellShd.Color.g != Cell_shd.Color.g || CellShd.Color.b != Cell_shd.Color.b ))
						CellShd = null;
				}

				// Крайняя левая ли данная ячейка в выделении?
				if (0 === CurCell)
				{
					if (null === Border_left)
						Border_left = Cell_borders.Left;
					else
						Border_left = this.Internal_CompareBorders2(Border_left, Cell_borders.Left);
				}
				else
				{
					if (null === Border_insideV)
						Border_insideV = Cell_borders.Left;
					else
						Border_insideV = this.Internal_CompareBorders2(Border_insideV, Cell_borders.Left);
				}

				// Крайняя правая ли данная ячейка в выделении?
				if (Cells_Count - 1 === CurCell)
				{
					if (null === Border_right)
						Border_right = Cell_borders.Right;
					else
						Border_right = this.Internal_CompareBorders2(Border_right, Cell_borders.Right);
				}
				else
				{
					if (null === Border_insideV)
						Border_insideV = Cell_borders.Right;
					else
						Border_insideV = this.Internal_CompareBorders2(Border_insideV, Cell_borders.Right);
				}

				if (0 === CurCell)
				{
					if (0 != CurRow)
					{
						if (null === Border_insideH)
						{
							Border_insideH = Border_bottom;
							Border_insideH = this.Internal_CompareBorders2(Border_insideH, Cell_borders.Top);
						}
						else
						{
							Border_insideH = this.Internal_CompareBorders2(Border_insideH, Border_bottom);
							Border_insideH = this.Internal_CompareBorders2(Border_insideH, Cell_borders.Top);
						}
					}
					else
					{
						if (null === Border_top)
							Border_top = Cell_borders.Top;
					}

					Border_bottom = Cell_borders.Bottom;
				}
				else
				{
					if (0 != CurRow)
					{
						if (null === Border_insideH)
							Border_insideH = Cell_borders.Top;
						else
							Border_insideH = this.Internal_CompareBorders2(Border_insideH, Cell_borders.Top);
					}
					else
					{
						if (null === Border_top)
							Border_top = Cell_borders.Top;
						else
							Border_top = this.Internal_CompareBorders2(Border_top, Cell_borders.Top);
					}

					Border_bottom = this.Internal_CompareBorders2(Border_bottom, Cell_borders.Bottom);
				}
			}
		}

		Pr.CellBorders = {
			Left    : Border_left.Copy(),
			Right   : Border_right.Copy(),
			Top     : Border_top.Copy(),
			Bottom  : Border_bottom.Copy(),
			InsideH : null === Border_insideH ? null : Border_insideH.Copy(),
			InsideV : null === Border_insideV ? null : Border_insideV.Copy()
		};

		var oRowH = this.CurCell.Row.GetHeight();
		if (oRowH.IsAuto())
		{
			var oRow    = this.CurCell.GetRow();
			var nCurRow = oRow.GetIndex();

			var nRowSummaryH = 0;

			if (this.RowsInfo[nCurRow])
			{
				for (var nCurPage in this.RowsInfo[nCurRow].H)
					nRowSummaryH += this.RowsInfo[nCurRow].H[nCurPage];

				if (null !== Pr.TableSpacing)
					nRowSummaryH += Pr.TableSpacing;
				else if (this.RowsInfo[nCurRow].TopDy[0])
					nRowSummaryH -= this.RowsInfo[nCurRow].TopDy[0];

				nRowSummaryH -= oRow.GetTopMargin() + oRow.GetBottomMargin();
			}

			Pr.RowHeight = nRowSummaryH;
		}
		else
		{
			Pr.RowHeight = oRowH.GetValue();
		}
	}

	var arrSelectedCells = this.GetSelectionArray();

	var oCells = {};
	for (var nIndex = 0, nCount = arrSelectedCells.length; nIndex < nCount; ++nIndex)
	{
		var nCurCell = arrSelectedCells[nIndex].Cell;
		if (!oCells[nCurCell])
			oCells[nCurCell] = 1;
	}

	var nColumnWidth = null;

	var arrRowsInfo = this.private_GetRowsInfo();
	for (var nCurRow = 0, nCount = arrRowsInfo.length; nCurRow < nCount; ++nCurRow)
	{
		var nAdd = -1 === arrRowsInfo[nCurRow][0].Type ? 1 : 0;

		for (var nCurCell in oCells)
		{
			var _nCurCell = nCurCell | 0;
			if (arrRowsInfo[nCurRow][_nCurCell + nAdd])
			{
				if (null === nColumnWidth)
				{
					nColumnWidth = arrRowsInfo[nCurRow][_nCurCell + nAdd].W;
				}
				else if (Math.abs(nColumnWidth - arrRowsInfo[nCurRow][_nCurCell + nAdd].W) > 0.001)
				{
					nColumnWidth = undefined;
					break;
				}
			}
		}

		if (undefined === nColumnWidth)
			break;
	}

	Pr.ColumnWidth = nColumnWidth;

	switch (Pr.CellsVAlign)
	{
		case vertalignjc_Top    :
			Pr.CellsVAlign = c_oAscVertAlignJc.Top;
			break;
		case vertalignjc_Bottom :
			Pr.CellsVAlign = c_oAscVertAlignJc.Bottom;
			break;
		case vertalignjc_Center :
			Pr.CellsVAlign = c_oAscVertAlignJc.Center;
			break;
		default                 :
			Pr.CellsVAlign = null;
			break;
	}

	switch (Pr.CellsTextDirection)
	{
		case textdirection_LRTB  :
			Pr.CellsTextDirection = c_oAscCellTextDirection.LRTB;
			break;
		case textdirection_TBRL  :
			Pr.CellsTextDirection = c_oAscCellTextDirection.TBRL;
			break;
		case textdirection_BTLR  :
			Pr.CellsTextDirection = c_oAscCellTextDirection.BTLR;
			break;
		default                  :
			Pr.CellsTextDirection = null;
			break;
	}

	var oSelectionRowsRange = this.GetSelectedRowsRange();
	var nRowsInHeader       = this.GetRowsCountInHeader();

	if (oSelectionRowsRange.Start > nRowsInHeader)
		Pr.RowsInHeader = null;
	else if (oSelectionRowsRange.End < nRowsInHeader)
		Pr.RowsInHeader = true;
	else
		Pr.RowsInHeader = false;

	if (true === this.Is_Inline())
	{
		Pr.TableAlignment     = ( align_Left === TablePr.Jc ? 0 : ( AscCommon.align_Center === TablePr.Jc ? 1 : 2 ) );
		Pr.TableIndent        = TablePr.TableInd;
		Pr.TableWrappingStyle = AscCommon.c_oAscWrapStyle.Inline;

		Pr.Position = {
			X : this.X,
			Y : this.Y
		};

		Pr.TablePaddings = {
			Top    : 0,
			Bottom : 0,
			Left   : 3.2,
			Right  : 3.2
		};
	}
	else
	{
		var LD_PageFields = this.LogicDocument.Get_PageFields(this.Get_StartPage_Absolute());

		Pr.TableAlignment     = 0; // align_Left
		Pr.TableIndent        = this.X_origin - LD_PageFields.X;
		Pr.TableWrappingStyle = AscCommon.c_oAscWrapStyle.Flow;

		Pr.PositionH              = {};
		Pr.PositionH.RelativeFrom = this.PositionH.RelativeFrom;
		Pr.PositionH.UseAlign     = this.PositionH.Align;
		Pr.PositionH.Align        = ( true === Pr.PositionH.UseAlign ? this.PositionH.Value : undefined );
		Pr.PositionH.Value        = ( true === Pr.PositionH.UseAlign ? 0 : this.PositionH.Value );

		Pr.PositionV              = {};
		Pr.PositionV.RelativeFrom = this.PositionV.RelativeFrom;
		Pr.PositionV.UseAlign     = this.PositionV.Align;
		Pr.PositionV.Align        = ( true === Pr.PositionV.UseAlign ? this.PositionV.Value : undefined );
		Pr.PositionV.Value        = ( true === Pr.PositionV.UseAlign ? 0 : this.PositionV.Value );

		Pr.Position = {
			X : this.Parent.X,
			Y : this.Parent.Y
		};

		Pr.TablePaddings = {
			Left   : this.Distance.L,
			Right  : this.Distance.R,
			Top    : this.Distance.T,
			Bottom : this.Distance.B
		};
	}

	Pr.Internal_Position = this.AnchorPosition;

	Pr.TableBorders = Common_CopyObj(TablePr.TableBorders);

	Pr.TableBackground = TablePr.Shd.Copy();

	Pr.TableStyle = this.TableStyle;
	Pr.TableLook  = this.TableLook;

	if (true === this.Parent.Is_DrawingShape())
		Pr.CanBeFlow = false;
	else
		Pr.CanBeFlow = true;

	Pr.Locked = this.Lock.Is_Locked();

	if (true === this.Parent.Is_InTable())
		Pr.TableLayout = undefined;
	else
		Pr.TableLayout = (TablePr.TableLayout === tbllayout_AutoFit ? c_oAscTableLayout.AutoFit : c_oAscTableLayout.Fixed );

	if (!this.bPresentation)
	{
		this.DrawingDocument.CheckTableStyles(new Asc.CTablePropLook(this.TableLook));
	}

	Pr.PercentFullWidth = this.private_RecalculatePercentWidth();
	Pr.TableDescription = this.Get_TableDescription();
	Pr.TableCaption     = this.Get_TableCaption();

	return Pr;
};
CTable.prototype.Set_Props = function(Props)
{
	var TablePr            = this.Get_CompiledPr(false).TablePr;
	var bApplyToInnerTable = false;

	if (true != this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
	{
		bApplyToInnerTable = this.CurCell.Content.SetTableProps(Props);
	}

	if (true === bApplyToInnerTable)
		return true;

	var bRecalc_All = false;
	var bRedraw     = false;

	// TableStyle (стиль таблицы)
	if (undefined !== Props.TableStyle)
	{
		this.Set_TableStyle(Props.TableStyle);
		bRecalc_All = true;
	}

	// TableLook
	if ("undefined" != typeof(Props.TableLook))
	{
		var NewLook = new CTableLook(Props.TableLook.FirstCol, Props.TableLook.FirstRow, Props.TableLook.LastCol, Props.TableLook.LastRow, Props.TableLook.BandHor, Props.TableLook.BandVer);
		this.Set_TableLook(NewLook);
		bRecalc_All = true;
	}

	// AllowOverlap
	if (undefined != Props.AllowOverlap)
	{
		this.Set_AllowOverlap(Props.AllowOverlap);
		bRecalc_All = true;
	}

	// RowsInHeader
	if (undefined !== Props.RowsInHeader && null !== Props.RowsInHeader)
	{
		var oSelectionRowsRange = this.GetSelectedRowsRange();
		var nRowsInHeader       = this.GetRowsCountInHeader();

		if (oSelectionRowsRange.Start <= nRowsInHeader)
		{
			for (var nCurRow = oSelectionRowsRange.Start, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
			{
				if (nCurRow <= oSelectionRowsRange.End)
					this.Content[nCurRow].SetHeader(Props.RowsInHeader ? true : false);
				else
					this.Content[nCurRow].SetHeader(false);
			}
		}
	}

	// TableSpacing (расстояние между ячейками)
	if ("undefined" != typeof(Props.TableSpacing))
	{
		var NeedChange = false;
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			if (Props.TableSpacing != this.Content[Index].Get_CellSpacing())
			{
				NeedChange = true;
				break;
			}
		}

		if (true === NeedChange)
		{
			var OldSpacing = this.Content[0].Get_CellSpacing();
			var Diff       = Props.TableSpacing - ( null === OldSpacing ? 0 : OldSpacing );

			for (var Index = 0; Index < this.Content.length; Index++)
				this.Content[Index].Set_CellSpacing(Props.TableSpacing);

			bRecalc_All = true;

			// При изменении Spacing мы должны изменить сетку таблицы
			var GridKoeff = [];
			var ColsCount = this.TableGridCalc.length;
			for (var Index = 0; Index < ColsCount; Index++)
				GridKoeff.push(1);

			for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
			{
				var Row        = this.Content[CurRow];
				var GridBefore = Row.Get_Before().GridBefore;
				var GridAfter  = Row.Get_After().GridAfter;

				GridKoeff[Math.min(GridBefore, GridKoeff.length - 1)]    = 1.5;
				GridKoeff[Math.max(GridKoeff.length - 1 - GridAfter, 0)] = 1.5;
			}

			var arrNewGrid = [];
			for (var Index = 0; Index < ColsCount; Index++)
			{
				arrNewGrid[Index] = this.TableGridCalc[Index] + GridKoeff[Index] * Diff;
			}
			this.SetTableGrid(arrNewGrid);
		}
	}

	// Определим, есть ли у таблицы Spacing, уже с учетом новых настроек
	var bSpacing = null === this.Content[0].Get_CellSpacing() ? false : true;

	// TableDefaultMargins (отступы в ячейках по умолчанию)
	if ("undefined" != typeof(Props.TableDefaultMargins))
	{
		var UsingDefaultMar = false;
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Row        = this.Content[Index];
			var CellsCount = Row.Get_CellsCount();
			for (var CurCell = 0; CurCell < CellsCount; CurCell++)
			{
				var Cell = Row.Get_Cell(CurCell);
				if (null === Cell.Pr.TableCellMar)
				{
					UsingDefaultMar = true;
					break;
				}
			}
		}

		var NeedChange = false;

		var TDM        = Props.TableDefaultMargins;
		var Left_new   = ( "undefined" != typeof(TDM.Left) ? ( null != TDM.Left ? TDM.Left : TablePr.TableCellMar.Left.W   ) : TablePr.TableCellMar.Left.W   );
		var Right_new  = ( "undefined" != typeof(TDM.Right) ? ( null != TDM.Right ? TDM.Right : TablePr.TableCellMar.Right.W  ) : TablePr.TableCellMar.Right.W  );
		var Top_new    = ( "undefined" != typeof(TDM.Top) ? ( null != TDM.Top ? TDM.Top : TablePr.TableCellMar.Top.W    ) : TablePr.TableCellMar.Top.W    );
		var Bottom_new = ( "undefined" != typeof(TDM.Bottom) ? ( null != TDM.Bottom ? TDM.Bottom : TablePr.TableCellMar.Bottom.W ) : TablePr.TableCellMar.Bottom.W );

		if (Left_new != TablePr.TableCellMar.Left.W || Right_new != TablePr.TableCellMar.Right.W || Top_new != TablePr.TableCellMar.Top.W || Bottom_new != TablePr.TableCellMar.Bottom.W)
			NeedChange = true;

		if (true === NeedChange)
		{
			this.Set_TableCellMar(Left_new, Top_new, Right_new, Bottom_new);

			if (true === UsingDefaultMar)
			{
				bRecalc_All = true;
			}
		}
	}

	// CellMargins (отступы в ячейках)
	if ("undefined" != typeof(Props.CellMargins) && null != Props.CellMargins)
	{
		var NeedChange = false;

		switch (Props.CellMargins.Flag)
		{
			case 0:
			{
				if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
				{
					for (var Index = 0; Index < this.Selection.Data.length; Index++)
					{
						var Pos  = this.Selection.Data[Index];
						var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);

						if (null != Cell.Pr.TableCellMar)
						{
							Cell.Set_Margins(null);
							NeedChange = true;
						}
					}
				}
				else
				{
					var Cell = this.CurCell;

					if (null != Cell.Pr.TableCellMar)
					{
						Cell.Set_Margins(null);
						NeedChange = true;
					}
				}

				break;
			}
			case 1:
			{
				if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
				{
					for (var Index = 0; Index < this.Selection.Data.length; Index++)
					{
						var Pos  = this.Selection.Data[Index];
						var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);

						// Ячейки, у которых маргины дефелтовые, мы не трогаем
						if (true != Cell.Is_TableMargins())
						{
							if (null != Props.CellMargins.Left)
								Cell.Set_Margins({W : Props.CellMargins.Left, Type : tblwidth_Mm}, 3);

							if (null != Props.CellMargins.Right)
								Cell.Set_Margins({W : Props.CellMargins.Right, Type : tblwidth_Mm}, 1);

							if (null != Props.CellMargins.Top)
								Cell.Set_Margins({W : Props.CellMargins.Top, Type : tblwidth_Mm}, 0);

							if (null != Props.CellMargins.Bottom)
								Cell.Set_Margins({W : Props.CellMargins.Bottom, Type : tblwidth_Mm}, 2);

							NeedChange = true;
						}
					}
				}
				else
				{
					// Сюда вообще не должны заходить, но на всякий случай реализуем.
					var Cell = this.CurCell;
					if (true != Cell.Is_TableMargins())
					{
						if (null != Props.CellMargins.Left)
							Cell.Set_Margins({W : Props.CellMargins.Left, Type : tblwidth_Mm}, 3);

						if (null != Props.CellMargins.Right)
							Cell.Set_Margins({W : Props.CellMargins.Right, Type : tblwidth_Mm}, 1);

						if (null != Props.CellMargins.Top)
							Cell.Set_Margins({W : Props.CellMargins.Top, Type : tblwidth_Mm}, 0);

						if (null != Props.CellMargins.Bottom)
							Cell.Set_Margins({W : Props.CellMargins.Bottom, Type : tblwidth_Mm}, 2);
					}
					else
					{
						if (null != Props.CellMargins.Left)
							Cell.Set_Margins({W : Props.CellMargins.Left, Type : tblwidth_Mm}, 3);
						else
							Cell.Set_Margins({W : TablePr.TableCellMar.Left.W, Type : tblwidth_Mm}, 3);

						if (null != Props.CellMargins.Right)
							Cell.Set_Margins({W : Props.CellMargins.Right, Type : tblwidth_Mm}, 1);
						else
							Cell.Set_Margins({W : TablePr.TableCellMar.Right.W, Type : tblwidth_Mm}, 1);

						if (null != Props.CellMargins.Top)
							Cell.Set_Margins({W : Props.CellMargins.Top, Type : tblwidth_Mm}, 0);
						else
							Cell.Set_Margins({W : TablePr.TableCellMar.Top.W, Type : tblwidth_Mm}, 0);

						if (null != Props.CellMargins.Bottom)
							Cell.Set_Margins({W : Props.CellMargins.Bottom, Type : tblwidth_Mm}, 2);
						else
							Cell.Set_Margins({W : TablePr.TableCellMar.Bottom.W, Type : tblwidth_Mm}, 2);
					}

					NeedChange = true;
				}

				break;
			}
			case 2:
			{
				NeedChange = true;

				if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
				{
					for (var Index = 0; Index < this.Selection.Data.length; Index++)
					{
						var Pos  = this.Selection.Data[Index];
						var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);

						// Ячейки, у которых маргины дефелтовые, мы не трогаем
						if (true != Cell.Is_TableMargins())
						{
							if (null != Props.CellMargins.Left)
								Cell.Set_Margins({W : Props.CellMargins.Left, Type : tblwidth_Mm}, 3);

							if (null != Props.CellMargins.Right)
								Cell.Set_Margins({W : Props.CellMargins.Right, Type : tblwidth_Mm}, 1);

							if (null != Props.CellMargins.Top)
								Cell.Set_Margins({W : Props.CellMargins.Top, Type : tblwidth_Mm}, 0);

							if (null != Props.CellMargins.Bottom)
								Cell.Set_Margins({W : Props.CellMargins.Bottom, Type : tblwidth_Mm}, 2);
						}
						else
						{
							if (null != Props.CellMargins.Left)
								Cell.Set_Margins({W : Props.CellMargins.Left, Type : tblwidth_Mm}, 3);
							else
								Cell.Set_Margins({W : TablePr.TableCellMar.Left.W, Type : tblwidth_Mm}, 3);

							if (null != Props.CellMargins.Right)
								Cell.Set_Margins({W : Props.CellMargins.Right, Type : tblwidth_Mm}, 1);
							else
								Cell.Set_Margins({W : TablePr.TableCellMar.Right.W, Type : tblwidth_Mm}, 1);

							if (null != Props.CellMargins.Top)
								Cell.Set_Margins({W : Props.CellMargins.Top, Type : tblwidth_Mm}, 0);
							else
								Cell.Set_Margins({W : TablePr.TableCellMar.Top.W, Type : tblwidth_Mm}, 0);

							if (null != Props.CellMargins.Bottom)
								Cell.Set_Margins({W : Props.CellMargins.Bottom, Type : tblwidth_Mm}, 2);
							else
								Cell.Set_Margins({W : TablePr.TableCellMar.Bottom.W, Type : tblwidth_Mm}, 2);
						}
					}
				}
				else
				{
					var Cell = this.CurCell;
					if (true != Cell.Is_TableMargins())
					{
						if (null != Props.CellMargins.Left)
							Cell.Set_Margins({W : Props.CellMargins.Left, Type : tblwidth_Mm}, 3);

						if (null != Props.CellMargins.Right)
							Cell.Set_Margins({W : Props.CellMargins.Right, Type : tblwidth_Mm}, 1);

						if (null != Props.CellMargins.Top)
							Cell.Set_Margins({W : Props.CellMargins.Top, Type : tblwidth_Mm}, 0);

						if (null != Props.CellMargins.Bottom)
							Cell.Set_Margins({W : Props.CellMargins.Bottom, Type : tblwidth_Mm}, 2);
					}
					else
					{
						if (null != Props.CellMargins.Left)
							Cell.Set_Margins({W : Props.CellMargins.Left, Type : tblwidth_Mm}, 3);
						else
							Cell.Set_Margins({W : TablePr.TableCellMar.Left.W, Type : tblwidth_Mm}, 3);

						if (null != Props.CellMargins.Right)
							Cell.Set_Margins({W : Props.CellMargins.Right, Type : tblwidth_Mm}, 1);
						else
							Cell.Set_Margins({W : TablePr.TableCellMar.Right.W, Type : tblwidth_Mm}, 1);

						if (null != Props.CellMargins.Top)
							Cell.Set_Margins({W : Props.CellMargins.Top, Type : tblwidth_Mm}, 0);
						else
							Cell.Set_Margins({W : TablePr.TableCellMar.Top.W, Type : tblwidth_Mm}, 0);

						if (null != Props.CellMargins.Bottom)
							Cell.Set_Margins({W : Props.CellMargins.Bottom, Type : tblwidth_Mm}, 2);
						else
							Cell.Set_Margins({W : TablePr.TableCellMar.Bottom.W, Type : tblwidth_Mm}, 2);
					}

					NeedChange = true;
				}

				break;
			}
		}

		if (true === NeedChange)
			bRecalc_All = true;
	}

	// TableWidth (ширина таблицы)
	if (undefined !== Props.TableWidth)
	{
		if (null === Props.TableWidth)
		{
			if (tblwidth_Auto != TablePr.TableW.Type)
			{
				this.Set_TableW(tblwidth_Auto, 0);
				bRecalc_All = true;
			}
		}
		else if (Props.TableWidth > -0.001)
		{
			this.Set_TableW(tblwidth_Mm, Props.TableWidth);
			bRecalc_All = true;
		}
		else
		{
			this.Set_TableW(tblwidth_Pct, Math.abs(Props.TableWidth));
			bRecalc_All = true;
		}
	}

	// TableLayout
	if (undefined != Props.TableLayout)
	{
		this.SetTableLayout(( Props.TableLayout === c_oAscTableLayout.AutoFit ? tbllayout_AutoFit : tbllayout_Fixed ));
		bRecalc_All = true;
	}

	// TableWrappingStyle
	if (undefined != Props.TableWrappingStyle)
	{
		// При изменении flow на inline или наоборот, пересчет таблицы будет запущен позже
		if (0 === Props.TableWrappingStyle && true != this.Inline)
		{
			this.Set_Inline(true);
			bRecalc_All = true;
		}
		else if (1 === Props.TableWrappingStyle && false != this.Inline)
		{
			this.Set_Inline(false);

			if (undefined === Props.PositionH)
				this.Set_PositionH(c_oAscHAnchor.Page, false, this.AnchorPosition.Calculate_X_Value(c_oAscHAnchor.Page));

			if (undefined === Props.PositionV)
			{
				// Сдвигаемся на 1 twips вниз, чтобы не было пересечения с предыдущей строкой
				var ValueY = AscCommon.CorrectMMToTwips(this.AnchorPosition.Calculate_Y_Value(c_oAscVAnchor.Page)) + AscCommon.TwipsToMM(1);
				this.Set_PositionV(c_oAscVAnchor.Page, false, ValueY);
			}

			if (undefined === Props.TablePaddings)
				this.Set_Distance(3.2, 0, 3.2, 0);

			this.Set_TableInd(0);

			bRecalc_All = true;
		}
	}

	var _Jc = TablePr.Jc; // Запоминаем, чтобы не пересчитывать стиль
	// TableAlignment (прилегание таблицы)
	if ("undefined" != typeof(Props.TableAlignment) && true === this.Is_Inline())
	{
		var NewJc = ( 0 === Props.TableAlignment ? align_Left : ( 1 === Props.TableAlignment ? AscCommon.align_Center : AscCommon.align_Right ) );
		if (TablePr.Jc != NewJc)
		{
			_Jc = NewJc;
			this.Set_TableAlign(NewJc);
			bRecalc_All = true;
		}
	}

	// TableIndent (отступ слева)
	if ("undefined" != typeof(Props.TableIndent) && true === this.Is_Inline() && align_Left === _Jc)
	{
		if (Props.TableIndent != TablePr.TableInd)
		{
			this.Set_TableInd(Props.TableIndent);
			bRecalc_All = true;
		}
	}

	// Position
	if (undefined != Props.Position)
	{
		this.PositionH.RelativeFrom = c_oAscHAnchor.Page;
		this.PositionH.Align        = true;
		this.PositionV.RelativeFrom = c_oAscVAnchor.Page;
		this.PositionH.Align        = true;

		this.PositionH.Value = c_oAscXAlign.Center;
		this.PositionV.Value = c_oAscYAlign.Center;

		//this.PositionH.Value        = ( "undefined" != typeof(Props.Position.X) ? ( null != Props.Position.X ?
		// Props.Position.X : this.X ) : this.X ); this.PositionV.Value        = ( "undefined" !=
		// typeof(Props.Position.Y) ? ( null != Props.Position.Y ? Props.Position.Y : this.Y ) : this.Y );

		bRecalc_All = true;
	}

	if (undefined != Props.PositionH)
	{
		this.Set_PositionH(Props.PositionH.RelativeFrom, Props.PositionH.UseAlign, (true === Props.PositionH.UseAlign) ? Props.PositionH.Align : Props.PositionH.Value);
	}

	if (undefined != Props.PositionV)
	{
		this.Set_PositionV(Props.PositionV.RelativeFrom, Props.PositionV.UseAlign, (true === Props.PositionV.UseAlign) ? Props.PositionV.Align : Props.PositionV.Value);
	}

	// TablePaddings
	if (undefined != Props.TablePaddings)
	{
		var TP          = Props.TablePaddings;
		var CurPaddings = this.Distance;

		var NewPaggings_left   = ( undefined != TP.Left ? ( null != TP.Left ? TP.Left : CurPaddings.L ) : CurPaddings.L );
		var NewPaggings_right  = ( undefined != TP.Right ? ( null != TP.Right ? TP.Right : CurPaddings.R ) : CurPaddings.R );
		var NewPaggings_top    = ( undefined != TP.Top ? ( null != TP.Top ? TP.Top : CurPaddings.T ) : CurPaddings.T );
		var NewPaggings_bottom = ( undefined != TP.Bottom ? ( null != TP.Bottom ? TP.Bottom : CurPaddings.B ) : CurPaddings.B );

		if (Math.abs(CurPaddings.L - NewPaggings_left) > 0.001 || Math.abs(CurPaddings.R - NewPaggings_right) > 0.001 || Math.abs(CurPaddings.T - NewPaggings_top) > 0.001 || Math.abs(CurPaddings.B - NewPaggings_bottom) > 0.001)
		{
			this.Set_Distance(NewPaggings_left, NewPaggings_top, NewPaggings_right, NewPaggings_bottom);
			bRecalc_All = true;
		}
	}

	// TableBorders(границы таблицы)
	if ("undefined" != typeof(Props.TableBorders) && null != Props.TableBorders)
	{
		if (false === this.Internal_CheckNullBorder(Props.TableBorders.Top) && false === this.Internal_CompareBorders3(Props.TableBorders.Top, TablePr.TableBorders.Top))
		{
			this.Set_TableBorder_Top(Props.TableBorders.Top);
			bRecalc_All = true;

			if (true != bSpacing)
			{
				var Row = this.Content[0];
				for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
				{
					var Cell = Row.Get_Cell(CurCell);
					Cell.Set_Border(null, 0);
				}
			}
		}

		if (false === this.Internal_CheckNullBorder(Props.TableBorders.Bottom) && false === this.Internal_CompareBorders3(Props.TableBorders.Bottom, TablePr.TableBorders.Bottom))
		{
			this.Set_TableBorder_Bottom(Props.TableBorders.Bottom);
			bRecalc_All = true;

			if (true != bSpacing)
			{
				var Row = this.Content[this.Content.length - 1];
				for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
				{
					var Cell = Row.Get_Cell(CurCell);
					Cell.Set_Border(null, 2);
				}
			}
		}

		if (false === this.Internal_CheckNullBorder(Props.TableBorders.Left) && false === this.Internal_CompareBorders3(Props.TableBorders.Left, TablePr.TableBorders.Left))
		{
			this.Set_TableBorder_Left(Props.TableBorders.Left);
			bRecalc_All = true;

			if (true != bSpacing)
			{
				for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
				{
					var Cell = this.Content[CurRow].Get_Cell(0);
					Cell.Set_Border(null, 3);
				}
			}
		}

		if (false === this.Internal_CheckNullBorder(Props.TableBorders.Right) && false === this.Internal_CompareBorders3(Props.TableBorders.Right, TablePr.TableBorders.Right))
		{
			this.Set_TableBorder_Right(Props.TableBorders.Right);
			bRecalc_All = true;

			if (true != bSpacing)
			{
				for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
				{
					var Cell = this.Content[CurRow].Get_Cell(this.Content[CurRow].Get_CellsCount() - 1);
					Cell.Set_Border(null, 1);
				}
			}
		}

		if (false === this.Internal_CheckNullBorder(Props.TableBorders.InsideH) && false === this.Internal_CompareBorders3(Props.TableBorders.InsideH, TablePr.TableBorders.InsideH))
		{
			this.Set_TableBorder_InsideH(Props.TableBorders.InsideH);
			bRecalc_All = true;

			for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
			{
				var Row         = this.Content[CurRow];
				var Cells_Count = Row.Get_CellsCount();

				for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
				{
					var Cell = Row.Get_Cell(CurCell);

					if ((0 === CurRow && true === bSpacing) || 0 != CurRow)
						Cell.Set_Border(null, 0);

					if (( this.Content.length - 1 === CurRow && true === bSpacing ) || this.Content.length - 1 != CurRow)
						Cell.Set_Border(null, 2);

				}
			}
		}

		if (false === this.Internal_CheckNullBorder(Props.TableBorders.InsideV) && false === this.Internal_CompareBorders3(Props.TableBorders.InsideV, TablePr.TableBorders.InsideV))
		{
			this.Set_TableBorder_InsideV(Props.TableBorders.InsideV);
			bRecalc_All = true;

			for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
			{
				var Row         = this.Content[CurRow];
				var Cells_Count = Row.Get_CellsCount();

				for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
				{
					var Cell = Row.Get_Cell(CurCell);

					if ((0 === CurCell && true === bSpacing) || 0 != CurCell)
						Cell.Set_Border(null, 3);

					if (( Cells_Count - 1 === CurCell && true === bSpacing ) || Cells_Count - 1 != CurCell)
						Cell.Set_Border(null, 1);
				}
			}
		}
	}

	// CellBorders (границы ячеек)
	if ("undefined" != typeof(Props.CellBorders) && null != Props.CellBorders)
	{
		var Cells_array = null;

		// Переделаем идеальный вариант, на новый
		if (true === bSpacing)
		{
			if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
			{
				Cells_array = [];
				for (var Index = 0, Count = this.Selection.Data.length; Index < Count; Index++)
				{
					var RowIndex  = this.Selection.Data[Index].Row;
					var CellIndex = this.Selection.Data[Index].Cell;

					var StartGridCol    = this.Content[RowIndex].Get_CellInfo(CellIndex).StartGridCol;
					var GridSpan        = this.Content[RowIndex].Get_Cell(CellIndex).Get_GridSpan();
					var TempCells_array = this.private_GetCellsPosArrayByCellsArray(this.private_GetMergedCells(RowIndex, StartGridCol, GridSpan));
					Cells_array         = Cells_array.concat(TempCells_array);
				}
			}
			else if (false === Props.CellSelect)
			{
				Cells_array = [];
				for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
				{
					var Row         = this.Content[CurRow];
					var Cells_count = Row.Get_CellsCount();
					for (var CurCell = 0; CurCell < Cells_count; CurCell++)
					{
						var Cell = Row.Get_Cell(CurCell);
						if (vmerge_Continue === Cell.GetVMerge())
							continue;

						var StartGridCol    = this.Content[CurRow].Get_CellInfo(CurCell).StartGridCol;
						var GridSpan        = this.Content[CurRow].Get_Cell(CurCell).Get_GridSpan();
						var TempCells_array = this.private_GetCellsPosArrayByCellsArray(this.private_GetMergedCells(CurRow, StartGridCol, GridSpan));

						Cells_array = Cells_array.concat(TempCells_array);
					}
				}
			}
			else
			{
				var RowIndex     = this.CurCell.Row.Index;
				var CellIndex    = this.CurCell.Index;
				var StartGridCol = this.Content[RowIndex].Get_CellInfo(CellIndex).StartGridCol;
				var GridSpan     = this.Content[RowIndex].Get_Cell(CellIndex).Get_GridSpan();
				Cells_array      = this.private_GetCellsPosArrayByCellsArray(this.private_GetMergedCells(RowIndex, StartGridCol, GridSpan));
			}
		}
		else
		{
			if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
			{
				Cells_array = [];
				for (var Index = 0, Count = this.Selection.Data.length; Index < Count; Index++)
				{
					var RowIndex  = this.Selection.Data[Index].Row;
					var CellIndex = this.Selection.Data[Index].Cell;

					var StartGridCol    = this.Content[RowIndex].Get_CellInfo(CellIndex).StartGridCol;
					var GridSpan        = this.Content[RowIndex].Get_Cell(CellIndex).Get_GridSpan();
					var TempCells_array = this.private_GetCellsPosArrayByCellsArray(this.private_GetMergedCells(RowIndex, StartGridCol, GridSpan));
					Cells_array         = Cells_array.concat(TempCells_array);
				}
			}
			else
			{
				var RowIndex     = this.CurCell.Row.Index;
				var CellIndex    = this.CurCell.Index;
				var StartGridCol = this.Content[RowIndex].Get_CellInfo(CellIndex).StartGridCol;
				var GridSpan     = this.Content[RowIndex].Get_Cell(CellIndex).Get_GridSpan();
				Cells_array      = this.private_GetCellsPosArrayByCellsArray(this.private_GetMergedCells(RowIndex, StartGridCol, GridSpan));
			}
		}

		//if ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type )
		//    Cells_array = this.Selection.Data;
		//else
		//{
		//    // TODO: Если данная ячейка имеет вертикальное объединение, тогда нам надо добавить
		//    //       все ячейки в него попадающие
		//    Cells_array = [ { Row : this.CurCell.Row.Index, Cell : this.CurCell.Index } ];
		//}

		var Pos_first = Cells_array[0];
		var Pos_last  = Cells_array[Cells_array.length - 1];
		var Row_first = Pos_first.Row;
		var Row_last  = Pos_last.Row;

		var bBorder_top     = ( false === this.Internal_CheckNullBorder(Props.CellBorders.Top) ? true : false );
		var bBorder_bottom  = ( false === this.Internal_CheckNullBorder(Props.CellBorders.Bottom) ? true : false );
		var bBorder_left    = ( false === this.Internal_CheckNullBorder(Props.CellBorders.Left) ? true : false );
		var bBorder_right   = ( false === this.Internal_CheckNullBorder(Props.CellBorders.Right) ? true : false );
		var bBorder_insideh = ( false === this.Internal_CheckNullBorder(Props.CellBorders.InsideH) ? true : false );
		var bBorder_insidev = ( false === this.Internal_CheckNullBorder(Props.CellBorders.InsideV) ? true : false );

		if (true != bSpacing)
		{
			// Узначем GridCol начала и конца первой и последней строк
			var Grid_row_first_start = 0, Grid_row_first_end = 0, Grid_row_last_start = 0, Grid_row_last_end = 0;
			var Pos                  = {Row : 0, Cell : 0};

			var CurRow           = Row_first;
			var Index            = 0;
			Grid_row_first_start = this.Content[Pos_first.Row].Get_CellInfo(Pos_first.Cell).StartGridCol;
			while (Index < Cells_array.length)
			{
				Pos = Cells_array[Index];
				if (Pos.Row != Row_first)
					break;

				var Row  = this.Content[Pos.Row];
				var Cell = Row.Get_Cell(Pos.Cell);

				Grid_row_first_end = Row.Get_CellInfo(Pos.Cell).StartGridCol + Cell.Get_GridSpan() - 1;
				Index++;
			}

			Index = 0;
			while (Index < Cells_array.length)
			{
				Pos = Cells_array[Index];
				if (Pos.Row === Row_last)
					break;

				Index++;
			}

			Grid_row_last_start = this.Content[Pos.Row].Get_CellInfo(Pos.Cell).StartGridCol;
			Grid_row_last_end   = this.Content[Pos_last.Row].Get_CellInfo(Pos_last.Cell).StartGridCol + this.Content[Pos_last.Row].Get_Cell(Pos_last.Cell).Get_GridSpan() - 1;

			if (Row_first > 0 && true === bBorder_top)
			{
				var Cell_start = 0, Cell_end = 0;
				var bStart     = false;
				var bEnd       = false;

				var Row = this.Content[Row_first - 1];
				for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
				{
					var StartGridCol = Row.Get_CellInfo(CurCell).StartGridCol;
					var EndGridCol   = StartGridCol + Row.Get_Cell(CurCell).Get_GridSpan() - 1;

					if (false === bStart)
					{
						if (StartGridCol < Grid_row_first_start)
							continue;
						else if (StartGridCol > Grid_row_first_start)
							break;
						else //if ( StartGridCol === Grid_row_first_start )
						{
							Cell_start = CurCell;
							bStart     = true;

							if (EndGridCol < Grid_row_first_end)
								continue;
							else if (EndGridCol > Grid_row_first_end)
								break;
							else
							{
								Cell_end = CurCell;
								bEnd     = true;
								break;
							}
						}
					}

					if (false === bEnd)
					{
						if (EndGridCol < Grid_row_first_end)
							continue;
						else if (EndGridCol > Grid_row_first_end)
							break;
						else //if ( EndGridCol === Grid_row_first_end )
						{
							Cell_end = CurCell;
							bEnd     = true;
							break;
						}
					}
				}

				if (true === bStart && true === bEnd)
				{
					for (var CurCell = Cell_start; CurCell <= Cell_end; CurCell++)
					{
						var Cell = Row.Get_Cell(CurCell);
						Cell.Set_Border(Props.CellBorders.Top, 2);
					}
					bRecalc_All = true;
				}
			}

			if (Row_last < this.Content.length - 1 && true === bBorder_bottom)
			{
				var Cell_start = 0, Cell_end = 0;
				var bStart     = false;
				var bEnd       = false;

				var Row = this.Content[Row_last + 1];
				for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
				{
					var StartGridCol = Row.Get_CellInfo(CurCell).StartGridCol;
					var EndGridCol   = StartGridCol + Row.Get_Cell(CurCell).Get_GridSpan() - 1;

					if (false === bStart)
					{
						if (StartGridCol < Grid_row_last_start)
							continue;
						else if (StartGridCol > Grid_row_last_start)
							break;
						else //if ( StartGridCol === Grid_row_last_start )
						{
							Cell_start = CurCell;
							bStart     = true;

							if (EndGridCol < Grid_row_last_end)
								continue;
							else if (EndGridCol > Grid_row_last_end)
								break;
							else
							{
								Cell_end = CurCell;
								bEnd     = true;
								break;
							}
						}
					}

					if (false === bEnd)
					{
						if (EndGridCol < Grid_row_last_end)
							continue;
						else if (EndGridCol > Grid_row_last_end)
							break;
						else //if ( EndGridCol === Grid_row_last_end )
						{
							Cell_end = CurCell;
							bEnd     = true;
							break;
						}
					}
				}

				if (true === bStart && true === bEnd)
				{
					for (var CurCell = Cell_start; CurCell <= Cell_end; CurCell++)
					{
						var Cell = Row.Get_Cell(CurCell);
						Cell.Set_Border(Props.CellBorders.Bottom, 0);
					}
					bRecalc_All = true;
				}
			}
		}

		var PrevRow    = Row_first;
		var Cell_start = Pos_first.Cell, Cell_end = Pos_first.Cell;
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos = Cells_array[Index];
			Row     = this.Content[Pos.Row];
			Cell    = Row.Get_Cell(Pos.Cell);

			if (PrevRow != Pos.Row)
			{
				var Row_temp = this.Content[PrevRow];

				if (true != bSpacing && Cell_start > 0 && true === bBorder_left)
				{
					Row_temp.Get_Cell(Cell_start - 1).Set_Border(Props.CellBorders.Left, 1);
					bRecalc_All = true;
				}

				if (true != bSpacing && Cell_end < Row_temp.Get_CellsCount() - 1 && true === bBorder_right)
				{
					Row_temp.Get_Cell(Cell_end + 1).Set_Border(Props.CellBorders.Right, 3);
					bRecalc_All = true;
				}

				for (var CurCell = Cell_start; CurCell <= Cell_end; CurCell++)
				{
					var Cell_temp = Row_temp.Get_Cell(CurCell);

					if (Row_first === PrevRow && true === bBorder_top)
					{
						Cell_temp.Set_Border(Props.CellBorders.Top, 0);
						bRecalc_All = true;
					}
					else if (Row_first != PrevRow && true === bBorder_insideh)
					{
						Cell_temp.Set_Border(Props.CellBorders.InsideH, 0);
						bRecalc_All = true;
					}

					if (Row_last === PrevRow && true === bBorder_bottom)
					{
						Cell_temp.Set_Border(Props.CellBorders.Bottom, 2);
						bRecalc_All = true;
					}
					else if (Row_last != PrevRow && true === bBorder_insideh)
					{
						Cell_temp.Set_Border(Props.CellBorders.InsideH, 2);
						bRecalc_All = true;
					}

					if (CurCell === Cell_start && true === bBorder_left)
					{
						Cell_temp.Set_Border(Props.CellBorders.Left, 3);
						bRecalc_All = true;
					}
					else if (CurCell != Cell_start && true === bBorder_insidev)
					{
						Cell_temp.Set_Border(Props.CellBorders.InsideV, 3);
						bRecalc_All = true;
					}

					if (CurCell === Cell_end && true === bBorder_right)
					{
						Cell_temp.Set_Border(Props.CellBorders.Right, 1);
						bRecalc_All = true;
					}
					else if (CurCell != Cell_end && true === bBorder_insidev)
					{
						Cell_temp.Set_Border(Props.CellBorders.InsideV, 1);
						bRecalc_All = true;
					}
				}

				Cell_start = Pos.Cell;
				Cell_end   = Pos.Cell;
				PrevRow    = Pos.Row;
			}
			else
				Cell_end = Pos.Cell;


			if (Cells_array.length - 1 === Index)
			{
				var Row_temp = this.Content[PrevRow];
				if (true != bSpacing && Cell_start > 0 && true === bBorder_left)
				{
					Row_temp.Get_Cell(Cell_start - 1).Set_Border(Props.CellBorders.Left, 1);
					bRecalc_All = true;
				}

				if (true != bSpacing && Cell_end < Row_temp.Get_CellsCount() - 1 && true === bBorder_right)
				{
					Row_temp.Get_Cell(Cell_end + 1).Set_Border(Props.CellBorders.Right, 3);
					bRecalc_All = true;
				}

				for (var CurCell = Cell_start; CurCell <= Cell_end; CurCell++)
				{
					var Cell_temp = Row_temp.Get_Cell(CurCell);

					if (Row_first === Pos.Row && true === bBorder_top)
					{
						Cell_temp.Set_Border(Props.CellBorders.Top, 0);
						bRecalc_All = true;
					}
					else if (Row_first != Pos.Row && true === bBorder_insideh)
					{
						Cell_temp.Set_Border(Props.CellBorders.InsideH, 0);
						bRecalc_All = true;
					}

					if (Row_last === Pos.Row && true === bBorder_bottom)
					{
						Cell_temp.Set_Border(Props.CellBorders.Bottom, 2);
						bRecalc_All = true;
					}
					else if (Row_last != Pos.Row && true === bBorder_insideh)
					{
						Cell_temp.Set_Border(Props.CellBorders.InsideH, 2);
						bRecalc_All = true;
					}

					if (CurCell === Cell_start && true === bBorder_left)
					{
						Cell_temp.Set_Border(Props.CellBorders.Left, 3);
						bRecalc_All = true;
					}
					else if (CurCell != Cell_start && true === bBorder_insidev)
					{
						Cell_temp.Set_Border(Props.CellBorders.InsideV, 3);
						bRecalc_All = true;
					}

					if (CurCell === Cell_end && true === bBorder_right)
					{
						Cell_temp.Set_Border(Props.CellBorders.Right, 1);
						bRecalc_All = true;
					}
					else if (CurCell != Cell_end && true === bBorder_insidev)
					{
						Cell_temp.Set_Border(Props.CellBorders.InsideV, 1);
						bRecalc_All = true;
					}
				}
			}
		}
	}

	// TableBackground  (заливка таблицы)
	if ("undefined" != typeof(Props.TableBackground))
	{
		if (Props.TableBackground.Value != TablePr.Shd.Value || Props.TableBackground.Color.r != TablePr.Shd.Color.r || Props.TableBackground.Color.g != TablePr.Shd.Color.g || Props.TableBackground.Color.b != TablePr.Shd.Color.b)
		{
			this.Set_TableShd(Props.TableBackground.Value, Props.TableBackground.Color.r, Props.TableBackground.Color.g, Props.TableBackground.Color.b);
			bRedraw = true;
		}

		// Удаляем собственную заливку ячеек
		if (false === Props.CellSelect && false === bSpacing)
		{
			for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
			{
				var Row = this.Content[CurRow];
				for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
				{
					var Cell = Row.Get_Cell(CurCell);
					Cell.Set_Shd({Value : Asc.c_oAscShdNil, Color : {r : 0, g : 0, b : 0}});
				}
			}
		}
	}

	// CellsBackground (заливка ячеек)
	if ("undefined" != typeof(Props.CellsBackground) && null != Props.CellsBackground)
	{
		if (false === Props.CellSelect && true === bSpacing)
		{
			for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
			{
				var Row = this.Content[CurRow];
				for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
				{
					var Cell   = Row.Get_Cell(CurCell);
					var NewShd =
							{
								Value : Props.CellsBackground.Value,
								Color : {
									r : Props.CellsBackground.Color.r,
									g : Props.CellsBackground.Color.g,
									b : Props.CellsBackground.Color.b
								},

								Unifill : Props.CellsBackground.Unifill.createDuplicate()
							};

					Cell.Set_Shd(NewShd);

					bRedraw = true;
				}
			}
		}
		else if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		{
			for (var Index = 0; Index < this.Selection.Data.length; Index++)
			{
				var Pos      = this.Selection.Data[Index];
				var Cell     = this.Content[Pos.Row].Get_Cell(Pos.Cell);
				var Cell_shd = Cell.Get_Shd();

				if (Props.CellsBackground.Value != Cell_shd.Value || Props.CellsBackground.Color.r != Cell_shd.Color.r || Props.CellsBackground.Color.g != Cell_shd.Color.g || Props.CellsBackground.Color.b != Cell_shd.Color.b || !AscFormat.CompareUnifillBool(Props.CellsBackground.Unifill, Cell_shd.Unifill))
				{
					var NewShd =
							{
								Value : Props.CellsBackground.Value,
								Color : {
									r : Props.CellsBackground.Color.r,
									g : Props.CellsBackground.Color.g,
									b : Props.CellsBackground.Color.b
								},

								Unifill : Props.CellsBackground.Unifill.createDuplicate()
							};

					Cell.Set_Shd(NewShd);

					bRedraw = true;
				}
			}
		}
		else
		{
			var Cell     = this.CurCell;
			var Cell_shd = Cell.Get_Shd();

			if (Props.CellsBackground.Value != Cell_shd.Value || Props.CellsBackground.Color.r != Cell_shd.Color.r || Props.CellsBackground.Color.g != Cell_shd.Color.g || Props.CellsBackground.Color.b != Cell_shd.Color.b || !AscFormat.CompareUnifillBool(Props.CellsBackground.Unifill, Cell_shd.Unifill))
			{
				var NewShd =
						{
							Value : Props.CellsBackground.Value,
							Color : {
								r : Props.CellsBackground.Color.r,
								g : Props.CellsBackground.Color.g,
								b : Props.CellsBackground.Color.b
							},

							Unifill : Props.CellsBackground.Unifill.createDuplicate()
						};

				Cell.Set_Shd(NewShd);

				bRedraw = true;
			}
		}
	}

	// CellsVAlign (вертикальное выравнивание ячеек)
	if (undefined != Props.CellsVAlign && null != Props.CellsVAlign)
	{
		if (this.Selection.Use === true && table_Selection_Cell === this.Selection.Type)
		{
			var Count = this.Selection.Data.length;
			for (var Index = 0; Index < Count; Index++)
			{
				var Pos  = this.Selection.Data[Index];
				var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
				Cell.Set_VAlign(Props.CellsVAlign);
			}
		}
		else
		{
			this.CurCell.Set_VAlign(Props.CellsVAlign);
		}

		bRecalc_All = true;
	}

	// CellsTextDirection
	if (undefined !== Props.CellsTextDirection && null !== Props.CellsTextDirection)
	{
		var TextDirection = undefined;
		switch (Props.CellsTextDirection)
		{
			case c_oAscCellTextDirection.LRTB:
				TextDirection = textdirection_LRTB;
				break;
			case c_oAscCellTextDirection.TBRL:
				TextDirection = textdirection_TBRL;
				break;
			case c_oAscCellTextDirection.BTLR:
				TextDirection = textdirection_BTLR;
				break;
		}

		if (undefined !== TextDirection)
		{
			if (this.Selection.Use === true && table_Selection_Cell === this.Selection.Type)
			{
				var Count = this.Selection.Data.length;
				for (var Index = 0; Index < Count; ++Index)
				{
					var Pos  = this.Selection.Data[Index];
					var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
					Cell.Set_TextDirectionFromApi(TextDirection);
				}
			}
			else
			{
				this.CurCell.Set_TextDirectionFromApi(TextDirection);
			}
		}
	}

	// CellsNoWrap
	if (undefined !== Props.CellsNoWrap && null !== Props.CellsNoWrap)
	{
		if (this.Selection.Use === true && table_Selection_Cell === this.Selection.Type)
		{
			var Count = this.Selection.Data.length;
			for (var Index = 0; Index < Count; ++Index)
			{
				var Pos  = this.Selection.Data[Index];
				var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
				Cell.Set_NoWrap(Props.CellsNoWrap);
			}
		}
		else
		{
			this.CurCell.Set_NoWrap(Props.CellsNoWrap);
		}
	}

	// CellsWidth
	if (undefined !== Props.CellsWidth)
	{
		var CellsWidth = Props.CellsWidth;
		if (null !== CellsWidth && Math.abs(CellsWidth) < 0.001)
			CellsWidth = null;

		if (this.Selection.Use === true && table_Selection_Cell === this.Selection.Type)
		{
			var Count = this.Selection.Data.length;
			for (var Index = 0; Index < Count; ++Index)
			{
				var Pos  = this.Selection.Data[Index];
				var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);

				if (null === CellsWidth)
					Cell.Set_W(new CTableMeasurement(tblwidth_Auto, 0));
				else if (CellsWidth > -0.001)
					Cell.Set_W(new CTableMeasurement(tblwidth_Mm, CellsWidth));
				else
					Cell.Set_W(new CTableMeasurement(tblwidth_Pct, Math.abs(CellsWidth)));
			}
		}
		else
		{
			if (null === CellsWidth)
				this.CurCell.Set_W(new CTableMeasurement(tblwidth_Auto, 0));
			else if (CellsWidth > -0.001)
				this.CurCell.Set_W(new CTableMeasurement(tblwidth_Mm, CellsWidth));
			else
				this.CurCell.Set_W(new CTableMeasurement(tblwidth_Pct, Math.abs(CellsWidth)));
		}
	}

	// TableDescription
	if (undefined !== Props.TableDescription && null !== Props.TableDescription)
	{
		this.Set_TableDescription(Props.TableDescription);
	}

	// TableCaption
	if (undefined !== Props.TableCaption && null !== Props.TableCaption)
	{
		this.Set_TableCaption(Props.TableCaption);
	}

	if (undefined !== Props.RowHeight)
		this.SetRowHeight(Props.RowHeight);

	if (undefined !== Props.ColumnWidth)
		this.SetColumnWidth(Props.ColumnWidth);

	return true;
};
CTable.prototype.Get_Styles = function(Lvl)
{
	return this.Parent.Get_Styles(Lvl);
};
CTable.prototype.Get_TextBackGroundColor = function()
{
	// Сначала проверим заливку данной таблицы, если ее нет, тогда спрашиваем у родительского класса
	var Shd = this.Get_Shd();

	if (Asc.c_oAscShdNil !== Shd.Value)
		return Shd.Get_Color2(this.Get_Theme(), this.Get_ColorMap());

	return this.Parent.Get_TextBackGroundColor();
};
CTable.prototype.Get_Numbering = function()
{
	return this.Parent.Get_Numbering();
};
CTable.prototype.Get_PageBounds = function(CurPage)
{
	return this.Pages[CurPage].Bounds;
};
CTable.prototype.GetPageBounds = function(nCurPage)
{
	return this.Get_PageBounds(nCurPage);
};
CTable.prototype.GetContentBounds = function(CurPage)
{
	return this.Get_PageBounds(CurPage);
};
CTable.prototype.Get_PagesCount = function()
{
	return this.Pages.length;
};
CTable.prototype.GetAllDrawingObjects = function(DrawingObjs)
{
	if (undefined === DrawingObjs)
		DrawingObjs = [];

	var Rows_Count = this.Content.length;
	for (var CurRow = 0; CurRow < Rows_Count; CurRow++)
	{
		var Row         = this.Content[CurRow];
		var Cells_Count = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			Cell.Content.GetAllDrawingObjects(DrawingObjs);
		}
	}

	return DrawingObjs;
};
CTable.prototype.GetAllComments = function(AllComments)
{
	if (undefined === AllComments)
		AllComments = [];

	var Rows_Count = this.Content.length;
	for (var CurRow = 0; CurRow < Rows_Count; CurRow++)
	{
		var Row         = this.Content[CurRow];
		var Cells_Count = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			Cell.Content.GetAllComments(AllComments);
		}
	}

	return AllComments;
};
CTable.prototype.GetAllMaths = function(AllMaths)
{
	if (undefined === AllMaths)
		AllMaths = [];

	var Rows_Count = this.Content.length;
	for (var CurRow = 0; CurRow < Rows_Count; CurRow++)
	{
		var Row         = this.Content[CurRow];
		var Cells_Count = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			Cell.Content.GetAllMaths(AllMaths);
		}
	}

	return AllMaths;
};
CTable.prototype.GetAllFloatElements = function(FloatObjs)
{
	if (undefined === FloatObjs)
		FloatObjs = [];

	var Rows_Count = this.Content.length;
	for (var CurRow = 0; CurRow < Rows_Count; CurRow++)
	{
		var Row         = this.Content[CurRow];
		var Cells_Count = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			Cell.Content.GetAllFloatElements(FloatObjs);
		}
	}

	return FloatObjs;
};
/**
 * Данная функция запрашивает новую позицию для содержимого у ячейки, разбивающейся на несколько страниц
 */
CTable.prototype.Get_PageContentStartPos = function(CurPage, RowIndex, CellIndex)
{
	var Row      = this.Content[RowIndex];
	var Cell     = Row.Get_Cell(CellIndex);
	var CellMar  = Cell.GetMargins();
	var CellInfo = Row.Get_CellInfo(CellIndex);

	var VMerge_count = this.Internal_GetVertMergeCount(RowIndex, CellInfo.StartGridCol, Cell.Get_GridSpan());

	// Возможно первая ячейка, для которой мы рассчитваем перенос на следующую страницу
	// имеет вертикальное объединение. Поэтому строка, по которой идет перенос не RowIndex,
	// а последняя строка в объединении.
	RowIndex = RowIndex + VMerge_count - 1;
	Row      = this.Content[RowIndex];

	var Pos = this.Parent.Get_PageContentStartPos2(this.PageNum, this.ColumnNum, CurPage, this.Index);

	// На момент обращения к данной функции, у всех ячеек всех строк до текущей (включительно) должны быть
	// просчитаны верхние границы. И также должен быть просчитан заголовок на данной странице, если он есть.

	var bHeader = false;
	var Y       = Pos.Y;
	if (true !== this.HeaderInfo.HeaderRecalculate && -1 != this.HeaderInfo.PageIndex && this.HeaderInfo.Count > 0 && CurPage > this.HeaderInfo.PageIndex && true === this.HeaderInfo.Pages[CurPage].Draw)
	{
		Y       = this.HeaderInfo.Pages[CurPage].RowsInfo[this.HeaderInfo.Count - 1].TableRowsBottom;
		bHeader = true;
	}

	var CellSpacing = Row.Get_CellSpacing();
	if (null != CellSpacing)
	{
		var Table_Border_Top = this.Get_Borders().Top;
		if (border_Single === Table_Border_Top.Value)
			Y += Table_Border_Top.Size;

		if (true === bHeader || 0 === CurPage || ( 1 === CurPage && true != this.RowsInfo[0].FirstPage ))
			Y += CellSpacing;
		else
			Y += CellSpacing / 2;
	}

	// Далее вычислим маскимальную ширину верхней границы всех ячеек в данной
	// строке, учитывая ячейки, учавствующие в вертикальном объединении.

	var MaxTopBorder = 0;
	var CellsCount   = Row.Get_CellsCount();
	var TableBorders = this.Get_Borders();
	for (var CurCell = 0; CurCell < CellsCount; CurCell++)
	{
		var Cell   = Row.Get_Cell(CurCell);
		var VMerge = Cell.GetVMerge();

		if (vmerge_Continue === VMerge)
			Cell = this.Internal_Get_StartMergedCell(RowIndex, Row.Get_CellInfo(CurCell).StartGridCol, Cell.Get_GridSpan());

		var BorderInfo_Top = Cell.Get_BorderInfo().Top;
		if (null === BorderInfo_Top)
			continue;

		for (var Index = 0; Index < BorderInfo_Top.length; Index++)
		{
			var CurBorder = BorderInfo_Top[Index];

			var ResultBorder = this.Internal_CompareBorders(CurBorder, TableBorders.Top, false, true);

			if (border_Single === ResultBorder.Value && MaxTopBorder < ResultBorder.Size)
				MaxTopBorder = ResultBorder.Size;
		}
	}

	Pos.X = this.Pages[CurPage].X;

	Y += MaxTopBorder;

	// Учтем верхнее поле ячейки
	Y += CellMar.Top.W;

	var YLimit = Pos.YLimit;

	YLimit -= this.Pages[CurPage].FootnotesH;

	// TODO: Здесь надо учитывать нижнюю границу ячейки и вычесть ее ширину из YLimit
	return {X        : Pos.X + CellInfo.X_content_start,
		XLimit       : Pos.X + CellInfo.X_content_end,
		Y            : Y,
		YLimit       : YLimit,
		MaxTopBorder : MaxTopBorder
	};
};
CTable.prototype.Get_MaxTopBorder = function(RowIndex)
{
	// Вычислим маскимальную ширину верхней границы всех ячеек в данной
	// строке, учитывая ячейки, учавствующие в вертикальном объединении.

	var Row = this.Content[RowIndex];

	var MaxTopBorder = 0;
	var CellsCount   = Row.Get_CellsCount();
	var TableBorders = this.Get_Borders();
	for (var CurCell = 0; CurCell < CellsCount; CurCell++)
	{
		var Cell   = Row.Get_Cell(CurCell);
		var VMerge = Cell.GetVMerge();

		if (vmerge_Continue === VMerge)
			Cell = this.Internal_Get_StartMergedCell(RowIndex, Row.Get_CellInfo(CurCell).StartGridCol, Cell.Get_GridSpan());

		var BorderInfo_Top = Cell.Get_BorderInfo().Top;
		if (null === BorderInfo_Top)
			continue;

		for (var Index = 0; Index < BorderInfo_Top.length; Index++)
		{
			var CurBorder = BorderInfo_Top[Index];

			var ResultBorder = this.Internal_CompareBorders(CurBorder, TableBorders.Top, false, true);

			if (border_Single === ResultBorder.Value && MaxTopBorder < ResultBorder.Size)
				MaxTopBorder = ResultBorder.Size;
		}
	}

	return MaxTopBorder;
};
/**
 * Вычисляем небольшое смещение по X, необходимое для совместимости с Word разных версий
 */
CTable.prototype.GetTableOffsetCorrection = function()
{
	var X = 0;

	if (true === this.Parent.IsTableCellContent())
		return 0;

	var Row     = this.Content[0];
	var Cell    = Row.Get_Cell(0);
	var Margins = Cell.GetMargins();

	var CellSpacing = Row.Get_CellSpacing();
	if (null != CellSpacing)
	{
		var TableBorder_Left = this.Get_Borders().Left;
		if (border_None != TableBorder_Left.Value)
			X += TableBorder_Left.Size / 2;

		X += CellSpacing;

		var CellBorder_Left = Cell.Get_Borders().Left;
		if (border_None != CellBorder_Left.Value)
			X += CellBorder_Left.Size;

		X += Margins.Left.W;
	}
	else
	{
		var TableBorder_Left = this.Get_Borders().Left;
		var CellBorder_Left  = Cell.Get_Borders().Left;
		var Result_Border    = this.Internal_CompareBorders(TableBorder_Left, CellBorder_Left, true, false);

		if (border_None != Result_Border.Value)
			X += Math.max(Result_Border.Size / 2, Margins.Left.W);
		else
			X += Margins.Left.W;
	}

	return -X;
};
CTable.prototype.GetRightTableOffsetCorrection = function()
{
	var X = 0;

	if (true === this.Parent.IsTableCellContent())
		return 0;

	var Row         = this.Content[0];
	var Cell        = Row.Get_Cell(Row.Get_CellsCount() - 1);
	var Margins     = Cell.GetMargins();
	var CellSpacing = Row.Get_CellSpacing();
	if (null != CellSpacing)
	{
		var TableBorder_Right = this.Get_Borders().Right;
		if (border_None != TableBorder_Right.Value)
			X += TableBorder_Right.Size / 2;

		X += CellSpacing;

		var CellBorder_Right = Cell.Get_Borders().Right;
		if (border_None != CellBorder_Right.Value)
			X += CellBorder_Right.Size;

		X += Margins.Right.W;
	}
	else
	{
		var TableBorder_Right = this.Get_Borders().Right;
		var CellBorder_Right  = Cell.Get_Borders().Right;
		var Result_Border     = this.Internal_CompareBorders(TableBorder_Right, CellBorder_Right, true, false);

		if (border_None != Result_Border.Value)
			X += Math.max(Result_Border.Size / 2, Margins.Right.W);
		else
			X += Margins.Right.W;
	}

	return X;
};
/**
 * Получаем первый параграф первой ячейки. (Нужно, например, для контроля ContextualSpacing)
 */
CTable.prototype.Get_FirstParagraph = function()
{
	if (this.Content.length <= 0 || this.Content[0].Content.length <= 0)
		return null;

	return this.Content[0].Content[0].Content.Get_FirstParagraph();
};
CTable.prototype.GetAllParagraphs = function(Props, ParaArray)
{
	var Count = this.Content.length;
	for (var CurRow = 0; CurRow < Count; CurRow++)
	{
		var Row         = this.Content[CurRow];
		var Cells_Count = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			Cell.Content.GetAllParagraphs(Props, ParaArray);
		}
	}
};
CTable.prototype.GetEndInfo = function()
{
	var RowsCount = this.Content.length;
	if (RowsCount > 0)
		return this.Content[RowsCount - 1].GetEndInfo();

	return null;
};
CTable.prototype.GetPrevElementEndInfo = function(RowIndex)
{
	if (0 === RowIndex)
		return this.Parent.GetPrevElementEndInfo(this);
	else
		return this.Content[RowIndex - 1].GetEndInfo();
};
//----------------------------------------------------------------------------------------------------------------------
// Функции к которым идет обращение из родительского класса
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.Copy = function(Parent)
{
	var TableGrid = this.private_CopyTableGrid();
	var Table     = new CTable(this.DrawingDocument, Parent, this.Inline, 0, 0, TableGrid, this.bPresentation);

	Table.Set_Distance(this.Distance.L, this.Distance.T, this.Distance.R, this.Distance.B);
	Table.Set_PositionH(this.PositionH.RelativeFrom, this.PositionH.Align, this.PositionH.Value);
	Table.Set_PositionV(this.PositionV.RelativeFrom, this.PositionV.Align, this.PositionV.Value);

	// Копируем настройки
	Table.Set_TableStyle(this.TableStyle);
	Table.Set_TableLook(this.TableLook.Copy());
	Table.Set_Pr(this.Pr.Copy());

	Table.Rows = this.Rows;
	Table.Cols = this.Cols;

	// Копируем строки
	var Rows = this.Content.length;
	for (var Index = 0; Index < Rows; Index++)
	{
		Table.Content[Index] = this.Content[Index].Copy(Table);
		History.Add(new CChangesTableAddRow(Table, Index, [Table.Content[Index]]));
	}

	Table.Internal_ReIndexing(0);

	if (Table.Content.length > 0 && Table.Content[0].Get_CellsCount() > 0)
		Table.CurCell = Table.Content[0].Get_Cell(0);

	return Table;
};
CTable.prototype.Shift = function(CurPage, Dx, Dy)
{
	this.Pages[CurPage].Shift(Dx, Dy);

	if (0 === CurPage)
	{
		this.X_origin += Dx;
		this.X += Dx;
		this.Y += Dy;
		this.XLimit += Dx;
		this.YLimit += Dy;
	}

	var StartRow = this.Pages[CurPage].FirstRow;
	var LastRow  = this.Pages[CurPage].LastRow;
	for (var CurRow = StartRow; CurRow <= LastRow; CurRow++)
	{
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell          = Row.Get_Cell(CurCell);
			var CellPageIndex = CurPage - Cell.Content.Get_StartPage_Relative();
			if (vmerge_Restart === Cell.GetVMerge())
			{
				Cell.Content_Shift(CellPageIndex, Dx, Dy);
			}
		}

		this.RowsInfo[CurRow].Y[CurPage] += Dy;
		this.TableRowsBottom[CurRow][CurPage] += Dy;
	}
};
CTable.prototype.UpdateEndInfo = function()
{
	for (var RowIndex = 0, RowsCount = this.Content.length; RowIndex < RowsCount; RowIndex++)
	{
		var Row = this.Content[RowIndex];
		for (var CellIndex = 0, CellsCount = Row.Get_CellsCount(); CellIndex < CellsCount; CellIndex++)
		{
			var Cell = Row.Get_Cell(CellIndex);
			Cell.Content.UpdateEndInfo();
		}
	}
};
CTable.prototype.Internal_UpdateFlowPosition = function(X, Y)
{
	this.X_origin = X;
	var Dx        = this.GetTableOffsetCorrection();

	this.X = X + Dx;
	this.Y = Y;

	this.Set_PositionH(c_oAscHAnchor.Page, false, this.X_origin);
	this.Set_PositionV(c_oAscVAnchor.Page, false, this.Y);
};
CTable.prototype.Move = function(X, Y, PageNum, NearestPos)
{
	var oLogicDocument = editor.WordControl.m_oLogicDocument;

	this.Document_SetThisElementCurrent(false);
	this.MoveCursorToStartPos();

	var oTargetTable = this;
	if (true != this.Is_Inline())
	{
		if (false === oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_Table_Properties, null, true))
		{
			oLogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_MoveInlineTable);

			// Переносим привязку (если получается, что заносим таблицу саму в себя, тогда привязку не меняем)
			var NewDocContent = NearestPos.Paragraph.Parent;
			var OldDocContent = this.Parent;

			if (true != NewDocContent.CheckTableCoincidence(this))
			{
				var OldIndex = this.Index;
				var NewIndex = NearestPos.Paragraph.Index;

				// Проверим можем ли мы добавить таблицу перед параграфом так, чтобы таблица осталась на данной странице
				if (PageNum > NearestPos.Paragraph.Get_StartPage_Absolute())
				{
					if (NearestPos.Paragraph.Pages.length > 2)
					{
						// Параграф начинается до заданной страницы и заканчивается после. Нам нужно разделить его на
						// 2 параграфа в заданной точке.

						var NewParagraph = new Paragraph(NewDocContent.DrawingDocument, NewDocContent);
						NearestPos.Paragraph.Split(NewParagraph, NearestPos.ContentPos);
						NewDocContent.Internal_Content_Add(NewIndex + 1, NewParagraph);

						// Если все происходило в одном классе-документе, тогда проверяем индексы
						if (NewDocContent === OldDocContent && NewIndex + 1 <= OldIndex)
							OldIndex++;

						NewIndex++;
					}
					else
					{
						// Вставляем таблицу после найденного параграфа. Если параграф последний, тогда
						// в конец добавляем новый пустой параграф
						NewIndex++;
						if (NewIndex >= NewDocContent.Content.length - 1)
							NewDocContent.Internal_Content_Add(NewDocContent.Content.length, new Paragraph(NewDocContent.DrawingDocument, NewDocContent));
					}

				}

				oTargetTable = AscCommon.CollaborativeEditing.Is_SingleUser() ? this : this.Copy(NewDocContent);
				if (NewDocContent != OldDocContent)
				{
					// Сначала добавляем таблицу в новый класс
					NewDocContent.Internal_Content_Add(NewIndex, oTargetTable);

					// Удаляем таблицу из родительского класса
					OldDocContent.Internal_Content_Remove(OldIndex, 1);

					oTargetTable.Parent = NewDocContent;
				}
				else
				{
					if (NearestPos.Paragraph.Index > this.Index)
					{
						NewDocContent.Internal_Content_Add(NewIndex, oTargetTable);
						OldDocContent.Internal_Content_Remove(OldIndex, 1);
					}
					else
					{
						OldDocContent.Internal_Content_Remove(OldIndex, 1);
						NewDocContent.Internal_Content_Add(NewIndex, oTargetTable);
					}
				}
			}

			// Обновляем координаты

			// Здесь мы должны для первого рассчета оставить привязку относительно страницы, а после рассчета
			// изменить привязку на старую, при этом пересчитав координаты так, чтобы картинка не изменила
			// своего положения.

			oTargetTable.PositionH_Old = {
				RelativeFrom : oTargetTable.PositionH.RelativeFrom,
				Align        : oTargetTable.PositionH.Align,
				Value        : oTargetTable.PositionH.Value
			};

			oTargetTable.PositionV_Old = {
				RelativeFrom : oTargetTable.PositionV.RelativeFrom,
				Align        : oTargetTable.PositionV.Align,
				Value        : oTargetTable.PositionV.Value
			};

			oTargetTable.PositionH.RelativeFrom = c_oAscHAnchor.PageInternal;
			oTargetTable.PositionH.Align        = false;
			oTargetTable.PositionH.Value        = X;

			oTargetTable.PositionV.RelativeFrom = c_oAscVAnchor.Page;
			oTargetTable.PositionV.Align        = false;
			oTargetTable.PositionV.Value        = Y;

			oTargetTable.PageNum = PageNum;

			var nTableInd = oTargetTable.Get_TableInd();
			if (Math.abs(nTableInd) > 0.001)
				oTargetTable.Set_TableInd(0);

			editor.WordControl.m_oLogicDocument.Recalculate();
			oTargetTable.Start_TrackTable();
		}
	}
	else
	{
		// Проверяем, можно ли двигать данную таблицу
		if (false === oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_Table_Properties, {
				Type    : AscCommon.changestype_2_InlineObjectMove,
				PageNum : PageNum,
				X       : X,
				Y       : Y
			}, true))
		{
			oLogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_MoveFlowTable);

			var NewDocContent = NearestPos.Paragraph.Parent;
			var OldDocContent = this.Parent;

			if (true != NewDocContent.CheckTableCoincidence(this))
			{
				var TarParagraph   = NearestPos.Paragraph;
				var ParaContentPos = NearestPos.ContentPos;

				var OldIndex = this.Index;
				var NewIndex = NearestPos.Paragraph.Index;

				// Если позиция в начале параграфа, тогда добавляем таблицу до параграфа, если в конце, тогда
				// после параграфа, в противном случае разделяем параграф.
				if (true === TarParagraph.IsCursorAtEnd(ParaContentPos))
				{
					NewIndex++;
				}
				else if (true != TarParagraph.IsCursorAtBegin(ParaContentPos))
				{
					var NewParagraph = new Paragraph(NewDocContent.DrawingDocument, NewDocContent);
					NearestPos.Paragraph.Split(NewParagraph, NearestPos.ContentPos);
					NewDocContent.Internal_Content_Add(NewIndex + 1, NewParagraph);

					// Если все происходило в одном классе-документе, тогда проверяем индексы
					if (NewDocContent === OldDocContent && NewIndex + 1 <= OldIndex)
						OldIndex++;

					NewIndex++;
				}

				var oTargetTable = AscCommon.CollaborativeEditing.Is_SingleUser() ? this : this.Copy(NewDocContent);
				if (NewDocContent != OldDocContent)
				{
					// Сначала добавляем таблицу в новый класс
					NewDocContent.Internal_Content_Add(NewIndex, oTargetTable);

					// Удаляем таблицу из родительского класса
					OldDocContent.Internal_Content_Remove(OldIndex, 1);

					oTargetTable.Parent = NewDocContent;
				}
				else
				{
					if (NearestPos.Paragraph.Index > this.Index)
					{
						NewDocContent.Internal_Content_Add(NewIndex, oTargetTable);
						OldDocContent.Internal_Content_Remove(OldIndex, 1);
					}
					else
					{
						OldDocContent.Internal_Content_Remove(OldIndex, 1);
						NewDocContent.Internal_Content_Add(NewIndex, oTargetTable);
					}
				}

				editor.WordControl.m_oLogicDocument.Recalculate();
			}
			oTargetTable.Start_TrackTable();
		}
	}
	editor.WordControl.m_oLogicDocument.RemoveSelection();
	oTargetTable.Document_SetThisElementCurrent(true);
	oTargetTable.MoveCursorToStartPos();
	editor.WordControl.m_oLogicDocument.Document_UpdateSelectionState();
};
CTable.prototype.Reset = function(X, Y, XLimit, YLimit, PageNum, ColumnNum, ColumnsCount)
{
	if (this.Parent.RecalcInfo.FlowObject === this && c_oAscVAnchor.Text === this.PositionV.RelativeFrom)
	{
		this.Y -= this.PositionV.Value;
		this.YLimit -= this.PositionV.Value;
		return;
	}

	this.X_origin = X;
	this.X        = X;
	this.Y        = Y + 0.001; // Погрешность для Flow-таблиц
	this.XLimit   = XLimit;
	this.YLimit   = YLimit;

	this.PageNum      = PageNum;
	this.ColumnNum    = ColumnNum ? ColumnNum : 0;
	this.ColumnsCount = ColumnsCount ? ColumnsCount : 1;

	this.Pages.length = 1;
	this.Pages[0]     = new CTablePage(X, Y, XLimit, YLimit, 0, 0);
};
CTable.prototype.Recalculate = function()
{
	// Пересчитываем сетку колонок
	this.private_RecalculateGrid();
	this.Internal_Recalculate_1();
};
CTable.prototype.Reset_RecalculateCache = function()
{
	this.RecalcInfo.Reset(true);

	var RowsCount = this.Content.length;
	for (var RowIndex = 0; RowIndex < RowsCount; RowIndex++)
	{
		var Row        = this.Content[RowIndex];
		var CellsCount = Row.Get_CellsCount();
		for (var CellIndex = 0; CellIndex < CellsCount; CellIndex++)
		{
			var Cell = Row.Get_Cell(CellIndex);
			Cell.Content.Reset_RecalculateCache();
		}
	}
};
CTable.prototype.RecalculateCurPos = function(bUpdateX, bUpdateY)
{
	if (this.CurCell)
		return this.CurCell.Content_RecalculateCurPos(bUpdateX, bUpdateY);

	return null;
};
CTable.prototype.RecalculateMinMaxContentWidth = function(isRotated)
{
	this.private_RecalculateGrid();

	if (true === isRotated)
	{
		var MinMargin = [], MinContent = [], MaxContent = [];

		var RowsCount = this.Content.length;
		for (var CurRow = 0; CurRow < RowsCount; ++CurRow)
		{
			MinMargin[CurRow]  = 0;
			MinContent[CurRow] = 0;
			MaxContent[CurRow] = 0;
		}

		for (var CurRow = 0; CurRow < RowsCount; CurRow++)
		{
			var Row        = this.Content[CurRow];
			var CellsCount = Row.Get_CellsCount();
			for (var CurCell = 0; CurCell < CellsCount; CurCell++)
			{
				var Cell         = Row.Get_Cell(CurCell);
				var CellMinMax   = Cell.Content_RecalculateMinMaxContentWidth(isRotated);
				var CellMin      = CellMinMax.Min;
				var CellMax      = CellMinMax.Max;
				var CellMargins  = Cell.GetMargins();
				var CellMarginsW = CellMargins.Top.W + CellMargins.Bottom.W;

				if (MinMargin[CurRow] < CellMarginsW)
					MinMargin[CurRow] = CellMarginsW;

				if (MinContent[CurRow] < CellMin)
					MinContent[CurRow] = CellMin;

				if (MaxContent[CurRow] < CellMax)
					MaxContent[CurRow] = CellMax;
			}

			var RowH = Row.Get_Height();
			if (Asc.linerule_Exact === RowH.HRule || (linerule_AtLeast === RowH.HRule && MinContent[CurRow] < RowH.Value))
				MinContent[CurRow] = RowH.Value;

			if (Asc.linerule_Exact === RowH.HRule || (linerule_AtLeast === RowH.HRule && MaxContent[CurRow] < RowH.Value))
				MaxContent[CurRow] = RowH.Value;
		}

		var Min = 0;
		var Max = 0;
		for (var CurRow = 0; CurRow < RowsCount; ++CurRow)
		{
			Min += MinMargin[CurRow] + MinContent[CurRow];
			Max += MinMargin[CurRow] + MaxContent[CurRow];
		}

		return {Min : Min, Max : Max};
	}
	else
	{
		var MinMargin = [], MinContent = [], MaxContent = [], MaxFlags = [];

		var GridCount = this.TableGridCalc.length;
		for (var CurCol = 0; CurCol < GridCount; CurCol++)
		{
			MinMargin[CurCol]  = 0;
			MinContent[CurCol] = 0;
			MaxContent[CurCol] = 0;
			MaxFlags[CurCol]   = false; // false - ориентируемся на содержимое ячеек, true - ориентируемся только на
										// ширину ячеек записанную в свойствах
		}

		var RowsCount = this.Content.length;
		for (var CurRow = 0; CurRow < RowsCount; CurRow++)
		{
			var Row = this.Content[CurRow];

			// Смотрим на ширину пропущенных колонок сетки в начале строки
			var BeforeInfo = Row.Get_Before();
			var CurGridCol = BeforeInfo.GridBefore;

			var CellsCount = Row.Get_CellsCount();
			for (var CurCell = 0; CurCell < CellsCount; CurCell++)
			{
				var Cell         = Row.Get_Cell(CurCell);
				var CellMinMax   = Cell.Content_RecalculateMinMaxContentWidth(isRotated);
				var CellMin      = CellMinMax.Min;
				var CellMax      = CellMinMax.Max;
				var GridSpan     = Cell.Get_GridSpan();
				var CellMargins  = Cell.GetMargins();
				var CellMarginsW = CellMargins.Left.W + CellMargins.Right.W;
				var CellW        = Cell.Get_W();
				var CellWW       = null;

				if (tblwidth_Mm === CellW.Type)
					CellWW = CellW.W;
				else if (tblwidth_Pct === CellW.Type)
					CellWW = (this.XLimit - this.X) * CellW.W / 100;

				// Если GridSpan > 1, тогда все равно маргины учитываются в первую колоноку спана
				if (MinMargin[CurGridCol] < CellMarginsW)
					MinMargin[CurGridCol] = CellMarginsW;

				// На самом деле, случай 1 === GridSpan нормально обработается и как случай GridSpan > 1,
				// но поскольку он наиболее распространен, делаем его обработку максимально быстрой (без циклов)
				if (1 === GridSpan)
				{
					if (MinContent[CurGridCol] < CellMin)
						MinContent[CurGridCol] = CellMin;

					if (false === MaxFlags[CurGridCol] && MaxContent[CurGridCol] < CellMax)
						MaxContent[CurGridCol] = CellMax;

					if (null !== CellWW)
					{
						if (false === MaxFlags[CurGridCol])
						{
							MaxFlags[CurGridCol]   = true;
							MaxContent[CurGridCol] = Math.max(CellWW, CellMin);
						}
						else
						{
							MaxContent[CurGridCol] = Math.max(MaxContent[CurGridCol], CellWW, CellMin);
						}
					}
				}
				else
				{
					var SumSpanMinContent = 0;
					var SumSpanMaxContent = 0;
					for (var CurSpan = CurGridCol; CurSpan < CurGridCol + GridSpan; CurSpan++)
					{
						SumSpanMinContent += MinContent[CurSpan];
						SumSpanMaxContent += MaxContent[CurSpan];
					}

					if (SumSpanMinContent < CellMin)
					{
						var TempAdd = (CellMin - SumSpanMinContent) / GridSpan;
						for (var CurSpan = CurGridCol; CurSpan < CurGridCol + GridSpan; CurSpan++)
							MinContent[CurSpan] += TempAdd;
					}

					// Если у нас в объединении несколько колонок, тогда явно записанная ширина ячейки не
					// перекрывает ширину ни одной из колонок, она всего лишь участвует в определении
					// максимальной ширины.
					if (null !== CellWW && CellWW > CellMax)
						CellMax = CellWW;

					if (SumSpanMaxContent < CellMax)
					{
						// TODO: На самом деле, распределение здесь идет в каком-то отношении.
						//       Неплохо было бы выяснить как именно.
						var TempAdd = (CellMax - SumSpanMaxContent) / GridSpan;
						for (var CurSpan = CurGridCol; CurSpan < CurGridCol + GridSpan; CurSpan++)
							MaxContent[CurSpan] += TempAdd;
					}
				}

				CurGridCol += GridSpan;
			}
		}

		var Min = 0;
		var Max = 0;
		for (var CurCol = 0; CurCol < GridCount; CurCol++)
		{
			Min += MinMargin[CurCol] + MinContent[CurCol];

			if (false === MaxFlags[CurCol])
				Max += MinMargin[CurCol] + MaxContent[CurCol];
			else
				Max += MaxContent[CurCol];
		}

		var oTableW = this.GetTableW();
		if (oTableW)
		{
			var nValue = oTableW.GetValue();
			if (oTableW.IsMM())
			{
				if (Min < nValue)
					Min = nValue;

				if (Max < nValue)
					Max = nValue;
			}
			else if (oTableW.IsPercent())
			{
				var nPercentWidth = this.private_RecalculatePercentWidth();
				var mmValue = nValue  / 100 * nPercentWidth;

				if (Min < mmValue)
					Min = mmValue;

				if (Max < mmValue)
					Max = mmValue;
			}
		}

		return {Min : Min, Max : Max};
	}
};
CTable.prototype.RecalculateAllTables = function()
{
	this.private_RecalculateGrid();
	this.private_RecalculateBorders();

	var RowsCount = this.Content.length;
	for (var CurRow = 0; CurRow < RowsCount; CurRow++)
	{
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			Cell.Content.RecalculateAllTables();
		}
	}
};
CTable.prototype.GetLastRangeVisibleBounds = function()
{
	var CurPage = this.Pages.length - 1;
	var Page    = this.Pages[CurPage];
	var CurRow  = this.Content.length - 1;
	var Row     = this.Content[CurRow];

	// Ищем границы по горизонтали для последней ячейки
	var CurCell = Row.Get_CellsCount() - 1;

	var Cell     = Row.Get_Cell(CurCell);
	var CellInfo = Row.Get_CellInfo(CurCell);
	var CellMar  = Cell.GetMargins();

	var X_start = Page.X + CellInfo.X_cell_start;
	var X_end   = Page.X + CellInfo.X_cell_end;

	var Cell_PageRel = CurPage - Cell.Content.Get_StartPage_Relative();

	// Не все ячейки могут иметь страницу с номером Cell_PageRel, но хотя бы одна такая должна быть (иначе переноса
	// на новую страницу не было бы)
	var CellsCount = Row.Get_CellsCount();
	for (CurCell = 0; CurCell < CellsCount; CurCell++)
	{
		Cell = Row.Get_Cell(CurCell);

		if (Cell_PageRel <= Cell.PagesCount - 1)
			break;
	}

	if (CurCell >= CellsCount)
		return {X : X_start, Y : 0, W : X_end - X_start, H : 0, BaseLine : 0, XLimit : Page.XLimit};

	var Bounds   = Cell.Content_Get_PageBounds(Cell_PageRel);
	var Y_offset = Cell.Temp.Y_VAlign_offset[Cell_PageRel];

	var Y = 0;
	var H = 0;
	if (0 != Cell_PageRel)
	{
		// мы должны определить ряд, на котором случился перенос на новую страницу
		var TempRowIndex = this.Pages[CurPage].FirstRow;

		Y = this.RowsInfo[TempRowIndex].Y[CurPage] + this.RowsInfo[TempRowIndex].TopDy[CurPage] + CellMar.Top.W + Y_offset;
		H = this.RowsInfo[TempRowIndex].H[CurPage];
	}
	else
	{
		Y = this.RowsInfo[CurRow].Y[CurPage] + this.RowsInfo[CurRow].TopDy[CurPage] + CellMar.Top.W + Y_offset;
		H = this.RowsInfo[CurRow].H[CurPage];
	}

	return {X : X_start, Y : Y, W : X_end - X_start, H : H, BaseLine : H, XLimit : Page.XLimit};
};
CTable.prototype.FindNextFillingForm = function(isNext, isCurrent, isStart)
{
	var nCurRow  = this.Selection.Use === true ? this.Selection.StartPos.Pos.Row  : this.CurCell.Row.Index;
	var nCurCell = this.Selection.Use === true ? this.Selection.StartPos.Pos.Cell : this.CurCell.Index;

	var nStartRow = 0, nStartCell = 0, nEndRow = 0, nEndCell = 0;

	if (isCurrent)
	{
		if (isStart)
		{
			nStartRow  = nCurRow;
			nStartCell = nCurCell;

			nEndRow  = isNext ? this.Content.length - 1 : 0;
			nEndCell = isNext ? this.Content[nEndRow].Get_CellsCount() - 1 : 0;
		}
		else
		{
			nStartRow  = isNext ? 0 : this.Content.length - 1;
			nStartCell = isNext ? 0 : this.Content[nStartRow].Get_CellsCount() - 1;

			nEndRow  = nCurRow;
			nEndCell = nCurCell;
		}
	}
	else
	{
		if (isNext)
		{
			nStartRow  = 0;
			nStartCell = 0;
			nEndRow    = this.Content.length - 1;
			nEndCell   = this.Content[nEndRow].Get_CellsCount() - 1;
		}
		else
		{
			nStartRow  = this.Content.length - 1;
			nStartCell = this.Content[nEndRow].Get_CellsCount() - 1;
			nEndRow    = 0;
			nEndCell   = 0;
		}
	}

	if (isNext)
	{
		for (var nRowIndex = nStartRow; nRowIndex <= nEndRow; ++nRowIndex)
		{
			var _nStartCell = nRowIndex === nStartRow ? nStartCell : 0;
			var _nEndCell   = nRowIndex === nEndRow ? nEndCell : this.Content[nRowIndex].Get_CellsCount() - 1;
			for (var nCellIndex = _nStartCell; nCellIndex <= _nEndCell; ++nCellIndex)
			{
				var oCell = this.Content[nRowIndex].Get_Cell(nCellIndex);
				var oRes  = oCell.Content.FindNextFillingForm(true, isCurrent && nCellIndex === nCurCell && nRowIndex === nCurRow ? true : false, isStart);
				if (oRes)
					return oRes;
			}
		}
	}
	else
	{
		for (var nRowIndex = nStartRow; nRowIndex >= nEndRow; --nRowIndex)
		{
			var _nStartCell = nRowIndex === nStartRow ? nStartCell : this.Content[nRowIndex].Get_CellsCount() - 1;
			var _nEndCell   = nRowIndex === nEndRow ? nEndCell : 0;
			for (var nCellIndex = _nStartCell; nCellIndex >= _nEndCell; --nCellIndex)
			{
				var oCell = this.Content[nRowIndex].Get_Cell(nCellIndex);
				var oRes  = oCell.Content.FindNextFillingForm(false, isCurrent && nCellIndex === nCurCell && nRowIndex === nCurRow ? true : false, isStart);
				if (oRes)
					return oRes;
			}
		}
	}

	return null;
};
CTable.prototype.Get_NearestPos = function(CurPage, X, Y, bAnchor, Drawing)
{
	var Pos  = this.Internal_GetCellByXY(X, Y, CurPage);
	var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);

	return Cell.Content_Get_NearestPos(CurPage - Cell.Content.Get_StartPage_Relative(), X, Y, bAnchor, Drawing);
};
CTable.prototype.Get_ParentTextTransform = function()
{
	return this.Parent.Get_ParentTextTransform();
};
/**
 * Проверяем начинается ли текущий параграф с новой страницы.
 */
CTable.prototype.IsStartFromNewPage = function()
{
	if ((this.Pages.length > 1 && true === this.IsEmptyPage(0)) || (null === this.Get_DocumentPrev() && true === this.Parent.Is_TopDocument()))
		return true;

	return false;
};
CTable.prototype.IsContentOnFirstPage = function()
{
	if (this.Pages.length >= 1 && true === this.RowsInfo[0].FirstPage && this.Pages[0].LastRow >= this.Pages[0].FirstRow)
		return true;

	return false;
};
CTable.prototype.IsTableBorder = function(X, Y, CurPage)
{
	if (true === this.DrawingDocument.IsMobileVersion())
		return null;

	CurPage = Math.max(0, Math.min(this.Pages.length - 1, CurPage));

	if (true === this.IsEmptyPage(CurPage))
		return null;

	var Result = this.private_CheckHitInBorder(X, Y, CurPage);
	if (Result.Border != -1)
	{
		return this;
	}
	else
	{
		var Cell = this.Content[Result.Pos.Row].Get_Cell(Result.Pos.Cell);
		return Cell.Content_Is_TableBorder(X, Y, CurPage - Cell.Content.Get_StartPage_Relative());
	}
};
CTable.prototype.IsInText = function(X, Y, CurPage)
{
	if (CurPage < 0 || CurPage >= this.Pages.length)
		CurPage = 0;

	var Result = this.private_CheckHitInBorder(X, Y, CurPage);
	if (Result.Border != -1)
	{
		return null;
	}
	else
	{
		var Cell = this.Content[Result.Pos.Row].Get_Cell(Result.Pos.Cell);
		return Cell.Content_Is_InText(X, Y, CurPage - Cell.Content.Get_StartPage_Relative());
	}
};
CTable.prototype.IsInDrawing  = function(X, Y, CurPage)
{
	if (CurPage < 0 || CurPage >= this.Pages.length)
		CurPage = 0;

	var Result = this.private_CheckHitInBorder(X, Y, CurPage);
	if (Result.Border != -1)
	{
		return null;
	}
	else
	{
		var Cell = this.Content[Result.Pos.Row].Get_Cell(Result.Pos.Cell);
		return Cell.Content_Is_InDrawing(X, Y, CurPage - Cell.Content.Get_StartPage_Relative());
	}
};
CTable.prototype.IsInnerTable = function()
{
	if (this.Content.length <= 0)
		return false;

	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
		return this.CurCell.Content.Is_CurrentElementTable();

	return false;
};
CTable.prototype.Is_UseInDocument = function(Id)
{
	var bUse = false;
	if (null != Id)
	{
		var RowsCount = this.Content.length;
		for (var Index = 0; Index < RowsCount; Index++)
		{
			if (Id === this.Content[Index].Get_Id())
			{
				bUse = true;
				break;
			}
		}
	}
	else
		bUse = true;

	if (true === bUse && null != this.Parent)
		return this.Parent.Is_UseInDocument(this.Get_Id());

	return false;
};
CTable.prototype.Get_CurrentPage_Absolute = function()
{
	if (true === this.ApplyToAll || (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0))
	{
		// Проходимся по всей последней выделенной строке и находим текущую страницу с наибольшим значением
		// Если мы будет брать текущую страницу просто у последней ячейки выделения, тогда нужно переделать функцию
		// CDocument.GetCurPage

		var nCurPage = 0;
		var nRow = this.Selection.EndPos.Pos.Row;
		if (this.RowsInfo[nRow])
			nCurPage = this.RowsInfo[nRow].StartPage + this.RowsInfo[nRow].Pages - 1;

		return this.Get_AbsolutePage(nCurPage);
	}
	else
	{
		return this.CurCell.Content.Get_CurrentPage_Absolute();
	}
};
CTable.prototype.Get_CurrentPage_Relative = function()
{
	if (true === this.Selection.Use)
		return 0;

	return this.CurCell.Content.Get_CurrentPage_Absolute() - this.Get_StartPage_Absolute();
};
CTable.prototype.UpdateCursorType = function(X, Y, CurPage)
{
	if (CurPage < 0 || CurPage >= this.Pages.length)
		CurPage = 0;

	if (true === this.Lock.Is_Locked())
	{
		var _X = this.Pages[CurPage].Bounds.Left;
		var _Y = this.Pages[CurPage].Bounds.Top;

		var MMData              = new CMouseMoveData();
		var Coords              = this.DrawingDocument.ConvertCoordsToCursorWR(_X, _Y, this.Get_AbsolutePage(CurPage));
		MMData.X_abs            = Coords.X - 5;
		MMData.Y_abs            = Coords.Y - 5;
		MMData.Type             = AscCommon.c_oAscMouseMoveDataTypes.LockedObject;
		MMData.UserId           = this.Lock.Get_UserId();
		MMData.HaveChanges      = this.Lock.Have_Changes();
		MMData.LockedObjectType = c_oAscMouseMoveLockedObjectType.Common;

		editor.sync_MouseMoveCallback(MMData);
	}

	if (true === this.Selection.Start || table_Selection_Border === this.Selection.Type2 || table_Selection_Border_InnerTable === this.Selection.Type2)
		return;

	// Случай, когда у нас уже есть трэк вложенной таблицы и курсор выходит во внешнюю. Чтобы трэк сразу не пропадал,
	// пока курсор находится в области табличного трэка для вложенной таблицы.
	if (true !== this.DrawingDocument.IsCursorInTableCur(X, Y, this.GetAbsolutePage(CurPage))
		&& true === this.Check_EmptyPages(CurPage - 1)
		&& true !== this.IsEmptyPage(CurPage))
	{
		this.private_StartTrackTable(CurPage);
	}

	var oHitInfo = this.private_CheckHitInBorder(X, Y, CurPage);
	if (true === oHitInfo.RowSelection)
	{
		return this.DrawingDocument.SetCursorType("select-table-row", new CMouseMoveData());
	}
	else if (true === oHitInfo.ColumnSelection)
	{
		return this.DrawingDocument.SetCursorType("select-table-column", new CMouseMoveData());
	}
	else if (true === oHitInfo.CellSelection)
	{
		return this.DrawingDocument.SetCursorType("select-table-cell", new CMouseMoveData());
	}
	else if (-1 !== oHitInfo.Border)
	{
		var Transform = this.Get_ParentTextTransform();
		if (null !== Transform)
		{
			var dX = Math.abs(Transform.TransformPointX(0, 0) - Transform.TransformPointX(0, 1));
			var dY = Math.abs(Transform.TransformPointY(0, 0) - Transform.TransformPointY(0, 1));

			if (Math.abs(dY) > Math.abs(dX))
			{
				switch (oHitInfo.Border)
				{
					case 0:
					case 2:
						return this.DrawingDocument.SetCursorType("row-resize", new CMouseMoveData());
					case 1:
					case 3:
						return this.DrawingDocument.SetCursorType("col-resize", new CMouseMoveData());
				}
			}
			else
			{
				switch (oHitInfo.Border)
				{
					case 0:
					case 2:
						return this.DrawingDocument.SetCursorType("col-resize", new CMouseMoveData());
					case 1:
					case 3:
						return this.DrawingDocument.SetCursorType("row-resize", new CMouseMoveData());
				}
			}
		}
		else
		{
			switch (oHitInfo.Border)
			{
				case 0:
				case 2:
					return this.DrawingDocument.SetCursorType("row-resize", new CMouseMoveData());
				case 1:
				case 3:
					return this.DrawingDocument.SetCursorType("col-resize", new CMouseMoveData());
			}
		}
	}

	var Cell_Pos = this.Internal_GetCellByXY(X, Y, CurPage);
	var Cell     = this.Content[Cell_Pos.Row].Get_Cell(Cell_Pos.Cell);
	Cell.Content_UpdateCursorType(X, Y, CurPage - Cell.Content.Get_StartPage_Relative());
};
CTable.prototype.Start_TrackTable = function()
{
	var CurPage = 0;
	while (CurPage < this.Pages.length)
	{
		if (true != this.IsEmptyPage(CurPage))
			break;

		CurPage++;
	}

	this.private_StartTrackTable(CurPage);
};
CTable.prototype.CollectDocumentStatistics = function(Stats)
{
	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			Row.Get_Cell(CurCell).Content.CollectDocumentStatistics(Stats);
		}
	}
};
CTable.prototype.Document_CreateFontMap = function(FontMap)
{
	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			Row.Get_Cell(CurCell).Content_Document_CreateFontMap(FontMap);
		}
	}
};
CTable.prototype.Document_CreateFontCharMap = function(FontCharMap)
{
	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			Row.Get_Cell(CurCell).Content.Document_CreateFontCharMap(0x00B7);
		}
	}
};
CTable.prototype.Document_Get_AllFontNames = function(AllFonts)
{
	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			Row.Get_Cell(CurCell).Content.Document_Get_AllFontNames(AllFonts);
		}
	}
};
CTable.prototype.Document_UpdateInterfaceState = function()
{
	// Если у нас выделено несколько ячеек, тогда данная таблица - нижний уровень
	if (true != this.Selection.Use || table_Selection_Cell != this.Selection.Type)
	{
		this.CurCell.Content.Document_UpdateInterfaceState();
	}
	else
	{
		var ParaPr         = this.GetCalculatedParaPr();
		ParaPr.CanAddTable = false;
		if (null != ParaPr)
			editor.UpdateParagraphProp(ParaPr);

		var TextPr = this.GetCalculatedTextPr();
		if (null != TextPr)
		{
			var theme = this.Get_Theme();
			if (theme && theme.themeElements && theme.themeElements.fontScheme)
			{
				if (TextPr.FontFamily)
				{
					TextPr.FontFamily.Name = theme.themeElements.fontScheme.checkFont(TextPr.FontFamily.Name);
				}
				if (TextPr.RFonts)
				{
					if (TextPr.RFonts.Ascii)
						TextPr.RFonts.Ascii.Name = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.Ascii.Name);
					if (TextPr.RFonts.EastAsia)
						TextPr.RFonts.EastAsia.Name = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.EastAsia.Name);
					if (TextPr.RFonts.HAnsi)
						TextPr.RFonts.HAnsi.Name = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.HAnsi.Name);
					if (TextPr.RFonts.CS)
						TextPr.RFonts.CS.Name = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.CS.Name);
				}
			}
			editor.UpdateTextPr(TextPr);
		}
	}
};
CTable.prototype.Document_UpdateRulersState = function(CurPage)
{
	if (CurPage < 0 || CurPage >= this.Pages.length)
		CurPage = 0;

	if (true == this.Selection.Use && table_Selection_Cell == this.Selection.Type)
	{
		this.private_UpdateTableMarkup(this.Selection.EndPos.Pos.Row, this.Selection.EndPos.Pos.Cell, CurPage);
	}
	else
	{
		this.private_UpdateTableMarkup(this.CurCell.Row.Index, this.CurCell.Index, CurPage);
		this.CurCell.Content.Document_UpdateRulersState(CurPage - this.CurCell.Content.Get_StartPage_Relative());
	}
};
CTable.prototype.Document_SetThisElementCurrent = function(bUpdateStates)
{
	this.Parent.Update_ContentIndexing();
	this.Parent.Set_CurrentElement(this.Index, bUpdateStates);
};
CTable.prototype.Can_CopyCut = function()
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		return true;
	else
		return this.CurCell.Content.Can_CopyCut();
};
CTable.prototype.Set_Inline = function(Value)
{
	History.Add(new CChangesTableInline(this, this.Inline, Value));
	this.Inline = Value;
};
CTable.prototype.Is_Inline = function()
{
	if (this.Parent && true === this.Parent.Is_DrawingShape())
		return true;

	return this.Inline;
};
CTable.prototype.Set_ApplyToAll = function(bValue)
{
	this.ApplyToAll = bValue;
};
CTable.prototype.Get_ApplyToAll = function()
{
	return this.ApplyToAll;
};
/**
 * Функция, которую нужно вызвать перед удалением данного элемента
 */
CTable.prototype.PreDelete = function()
{
	this.DrawingDocument.EndTrackTable(this, false);

	var RowsCount = this.Content.length;
	for (var CurRow = 0; CurRow < RowsCount; CurRow++)
	{
		var Row = this.Content[CurRow];
		Row.PreDelete();
	}
};
CTable.prototype.RemoveInnerTable = function()
{
	this.CurCell.Content.RemoveTable();
};
CTable.prototype.SelectTable = function(Type)
{
	if (true === this.IsInnerTable())
	{
		this.CurCell.Content.SelectTable(Type);
		if (true === this.CurCell.Content.IsSelectionUse())
		{
			this.Selection.Use   = true;
			this.Selection.Start = false;
			this.Selection.Type  = table_Selection_Text;
			this.Selection.Data  = null;
			this.Selection.Type2 = table_Selection_Common;
			this.Selection.Data2 = null;
		}

		return;
	}

	var NewSelectionData = [];

	switch (Type)
	{
		case c_oAscTableSelectionType.Table :
		{
			for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
			{
				var Row         = this.Content[CurRow];
				var Cells_Count = Row.Get_CellsCount();
				for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
				{
					var Cell   = Row.Get_Cell(CurCell);
					var Vmerge = Cell.GetVMerge();

					if (vmerge_Continue === Vmerge)
						continue;

					NewSelectionData.push({Row : CurRow, Cell : CurCell});
				}
			}

			break;
		}

		case c_oAscTableSelectionType.Row :
		{
			var Rows_to_select = [];

			if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
			{
				var Row_prev = -1;
				for (var Index = 0; Index < this.Selection.Data.length; Index++)
				{
					var Pos = this.Selection.Data[Index];
					if (-1 === Row_prev || Row_prev != Pos.Row)
					{
						Rows_to_select.push(Pos.Row);
						Row_prev = Pos.Row;
					}
				}
			}
			else
			{
				Rows_to_select.push(this.CurCell.Row.Index);
			}

			for (var Index = 0; Index < Rows_to_select.length; Index++)
			{
				var Row         = this.Content[Rows_to_select[Index]];
				var Cells_Count = Row.Get_CellsCount();
				for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
				{
					var Cell   = Row.Get_Cell(CurCell);
					var Vmerge = Cell.GetVMerge();
					if (vmerge_Continue === Vmerge)
						continue;

					NewSelectionData.push({Cell : CurCell, Row : Rows_to_select[Index]});
				}
			}

			break;
		}

		case c_oAscTableSelectionType.Column :
		{
			var Grid_start = -1;
			var Grid_end   = -1;

			if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
			{
				for (var Index = 0; Index < this.Selection.Data.length; Index++)
				{
					var Pos  = this.Selection.Data[Index];
					var Row  = this.Content[Pos.Row];
					var Cell = Row.Get_Cell(Pos.Cell);

					var StartGridCol = Row.Get_CellInfo(Pos.Cell).StartGridCol;
					var EndGridCol   = StartGridCol + Cell.Get_GridSpan() - 1;

					if (-1 === Grid_start || Grid_start > StartGridCol)
						Grid_start = StartGridCol;

					if (-1 === Grid_end || Grid_end < EndGridCol)
						Grid_end = EndGridCol;
				}
			}
			else
			{
				Grid_start = this.Content[this.CurCell.Row.Index].Get_CellInfo(this.CurCell.Index).StartGridCol;
				Grid_end   = Grid_start + this.CurCell.Get_GridSpan() - 1;
			}


			for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
			{
				var Row         = this.Content[CurRow];
				var Cells_Count = Row.Get_CellsCount();

				for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
				{
					var Cell   = Row.Get_Cell(CurCell);
					var Vmerge = Cell.GetVMerge();
					if (vmerge_Continue === Vmerge)
						continue;

					var StartGridCol = Row.Get_CellInfo(CurCell).StartGridCol;
					var EndGridCol   = StartGridCol + Cell.Get_GridSpan() - 1;

					if (EndGridCol >= Grid_start && StartGridCol <= Grid_end)
						NewSelectionData.push({Cell : CurCell, Row : CurRow});
				}
			}

			break;
		}

		case c_oAscTableSelectionType.Cell :
		default :
		{
			if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
				NewSelectionData = this.Selection.Data;
			else
				NewSelectionData.push({Row : this.CurCell.Row.Index, Cell : this.CurCell.Index});
			break;
		}
	}

	this.Selection.Use   = true;
	this.Selection.Start = false;
	this.Selection.Type  = table_Selection_Cell;
	this.Selection.Data  = NewSelectionData;
	this.Selection.Type2 = table_Selection_Common;
	this.Selection.Data2 = null;

	this.Selection.StartPos.Pos = {Row : NewSelectionData[0].Row, Cell : NewSelectionData[0].Cell};
	this.Selection.EndPos.Pos   = {
		Row  : NewSelectionData[NewSelectionData.length - 1].Row,
		Cell : NewSelectionData[NewSelectionData.length - 1].Cell
	};

};
CTable.prototype.CanSplitTableCells = function()
{
	if (true === this.IsInnerTable())
		return this.CurCell.Content.CanSplitTableCells();

	// Разделение ячейки работает, только если выделена ровно одна ячейка.
	if (!( false === this.Selection.Use || ( true === this.Selection.Use && ( table_Selection_Text === this.Selection.Type || ( table_Selection_Cell === this.Selection.Type && 1 === this.Selection.Data.length  ) ) ) ))
		return false;

	return true;
};
CTable.prototype.CanMergeTableCells = function()
{
	if (true === this.IsInnerTable())
		return this.CurCell.Content.CanMergeTableCells();

	if (true != this.Selection.Use || table_Selection_Cell != this.Selection.Type || this.Selection.Data.length <= 1)
		return false;

	return this.Internal_CheckMerge().bCanMerge;
};
//----------------------------------------------------------------------------------------------------------------------
// Undo/Redo функции
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.GetSelectionState = function()
{
	var TableState       = {};
	TableState.Selection = {
		Start    : this.Selection.Start,
		Use      : this.Selection.Use,
		StartPos : {
			Pos        : {Row : this.Selection.StartPos.Pos.Row, Cell : this.Selection.StartPos.Pos.Cell},
			X          : this.Selection.StartPos.X,
			Y          : this.Selection.StartPos.Y,
			PageIndex  : this.Selection.StartPos.PageIndex,
			MouseEvent : {
				// TODO : Если в MouseEvent будет использоваться что-то кроме ClickCount, Type и CtrlKey, добавить
				// здесь
				ClickCount : this.Selection.StartPos.MouseEvent.ClickCount,
				Type       : this.Selection.StartPos.MouseEvent.Type,
				CtrlKey    : this.Selection.StartPos.MouseEvent.CtrlKey
			}
		},
		EndPos   : {
			Pos        : {Row : this.Selection.EndPos.Pos.Row, Cell : this.Selection.EndPos.Pos.Cell},
			X          : this.Selection.EndPos.X,
			Y          : this.Selection.EndPos.Y,
			PageIndex  : this.Selection.EndPos.PageIndex,
			MouseEvent : {
				// TODO : Если в MouseEvent будет использоваться что-то кроме ClickCount, Type и CtrlKey, добавить
				// здесь
				ClickCount : this.Selection.EndPos.MouseEvent.ClickCount,
				Type       : this.Selection.EndPos.MouseEvent.Type,
				CtrlKey    : this.Selection.EndPos.MouseEvent.CtrlKey
			}
		},
		Type     : this.Selection.Type,
		Data     : null,
		Type2    : table_Selection_Common,
		Data2    : null,
		CurRow   : this.Selection.CurRow
	};

	TableState.Selection.Data = [];
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		for (var Index = 0; Index < this.Selection.Data.length; Index++)
			TableState.Selection.Data[Index] = {
				Row  : this.Selection.Data[Index].Row,
				Cell : this.Selection.Data[Index].Cell
			};
	}

	TableState.CurCell = {Row : this.CurCell.Row.Index, Cell : this.CurCell.Index};

	var State = this.CurCell.Content.GetSelectionState();
	State.push(TableState);
	return State;
};
CTable.prototype.SetSelectionState = function(State, StateIndex)
{
	if (State.length <= 0)
		return;

	var TableState = State[StateIndex];

	this.Selection = {
		Start    : TableState.Selection.Start,
		Use      : TableState.Selection.Use,
		StartPos : {
			Pos        : {
				Row  : TableState.Selection.StartPos.Pos.Row,
				Cell : TableState.Selection.StartPos.Pos.Cell
			},
			X          : TableState.Selection.StartPos.X,
			Y          : TableState.Selection.StartPos.Y,
			PageIndex  : TableState.Selection.StartPos.PageIndex,
			MouseEvent : {
				// TODO : Если в MouseEvent будет использоваться что-то кроме ClickCount, Type и CtrlKey, добавить
				// здесь
				ClickCount : TableState.Selection.StartPos.MouseEvent.ClickCount,
				Type       : TableState.Selection.StartPos.MouseEvent.Type,
				CtrlKey    : TableState.Selection.StartPos.MouseEvent.CtrlKey
			}
		},
		EndPos   : {
			Pos        : {Row : TableState.Selection.EndPos.Pos.Row, Cell : TableState.Selection.EndPos.Pos.Cell},
			X          : TableState.Selection.EndPos.X,
			Y          : TableState.Selection.EndPos.Y,
			PageIndex  : TableState.Selection.EndPos.PageIndex,
			MouseEvent : {
				// TODO : Если в MouseEvent будет использоваться что-то кроме ClickCount, Type и CtrlKey, добавить
				// здесь
				ClickCount : TableState.Selection.EndPos.MouseEvent.ClickCount,
				Type       : TableState.Selection.EndPos.MouseEvent.Type,
				CtrlKey    : TableState.Selection.EndPos.MouseEvent.CtrlKey
			}
		},
		Type     : TableState.Selection.Type,
		Data     : null,
		Type2    : table_Selection_Common,
		Data2    : null,
		CurRow   : TableState.Selection.CurRow
	};

	this.Selection.Data = [];
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		for (var Index = 0; Index < TableState.Selection.Data.length; Index++)
			this.Selection.Data[Index] = {
				Row  : TableState.Selection.Data[Index].Row,
				Cell : TableState.Selection.Data[Index].Cell
			};
	}

	this.CurCell = this.Content[TableState.CurCell.Row].Get_Cell(TableState.CurCell.Cell);
	this.CurCell.Content.SetSelectionState(State, StateIndex - 1);
};
CTable.prototype.Get_ParentObject_or_DocumentPos = function()
{
	return this.Parent.Get_ParentObject_or_DocumentPos(this.Index);
};
CTable.prototype.Refresh_RecalcData = function(Data)
{
	var Type = Data.Type;

	var bNeedRecalc = false;
	var nRowIndex   = 0;

	switch (Type)
	{
		case AscDFH.historyitem_Table_TableShd:
		{
			break;
		}

		case AscDFH.historyitem_Table_TableW:
		case AscDFH.historyitem_Table_TableLayout:
		case AscDFH.historyitem_Table_TableCellMar:
		case AscDFH.historyitem_Table_TableAlign:
		case AscDFH.historyitem_Table_TableInd:
		case AscDFH.historyitem_Table_TableBorder_Left:
		case AscDFH.historyitem_Table_TableBorder_Right:
		case AscDFH.historyitem_Table_TableBorder_Top:
		case AscDFH.historyitem_Table_TableBorder_Bottom:
		case AscDFH.historyitem_Table_TableBorder_InsideH:
		case AscDFH.historyitem_Table_TableBorder_InsideV:
		case AscDFH.historyitem_Table_Inline:
		case AscDFH.historyitem_Table_AllowOverlap:
		case AscDFH.historyitem_Table_PositionH:
		case AscDFH.historyitem_Table_PositionV:
		case AscDFH.historyitem_Table_Distance:
		case AscDFH.historyitem_Table_TableStyleColBandSize:
		case AscDFH.historyitem_Table_TableStyleRowBandSize:
		case AscDFH.historyitem_Table_Pr:
		{
			bNeedRecalc = true;
			break;
		}
		case AscDFH.historyitem_Table_AddRow:
		case AscDFH.historyitem_Table_RemoveRow:
		{
			bNeedRecalc = true;
			nRowIndex   = Data.Pos;
			break;
		}
		case AscDFH.historyitem_Table_TableGrid:
		{
			bNeedRecalc = true;
			break;
		}
		case AscDFH.historyitem_Table_TableStyle:
		case AscDFH.historyitem_Table_TableLook:
		{
			var Count = this.Content.length;
			for (var CurRow = 0; CurRow < Count; CurRow++)
			{
				var Row         = this.Content[CurRow];
				var Cells_Count = Row.Get_CellsCount();
				for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
				{
					var Cell = Row.Get_Cell(CurCell);
					Cell.Recalc_CompiledPr();
				}
				Row.Recalc_CompiledPr();
			}
			this.Recalc_CompiledPr();
			bNeedRecalc = true;
			break;
		}
	}

	this.RecalcInfo.Recalc_AllCells();
	this.RecalcInfo.Recalc_Borders();

	if (true === bNeedRecalc)
	{
		History.Add_RecalcTableGrid(this.Get_Id());
		this.Refresh_RecalcData2(nRowIndex, 0);
	}
};
CTable.prototype.Refresh_RecalcData2 = function(nRowIndex, nCurPage)
{
	// Если Index < 0, значит данный элемент еще не был добавлен в родительский класс
	if (this.Index >= 0)
	{

		if (Math.min(nRowIndex, this.RowsInfo.length - 1) < 0)
			this.Parent.Refresh_RecalcData2(this.Index, this.private_GetRelativePageIndex(0));
		else
			this.Parent.Refresh_RecalcData2(this.Index, this.private_GetRelativePageIndex(nCurPage));
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с совместным редактирования
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.Write_ToBinary2 = function(Writer)
{
	Writer.WriteLong(AscDFH.historyitem_type_Table);

	// Long               : type_Table
	// String             : Id самой таблицы
	// String             : Id стиля (если стока пустая, то null)
	// Bool               : Inline
	// Long               : количество элементов в TableGrid
	// Array of doubles   : массив TableGrid
	// Double             : X_origin
	// Double             : X
	// Double             : Y
	// Double             : XLimit
	// Double             : YLimit
	// Variable           : свойства таблицы (TablePr)
	// Long               : количество строк
	// Array of Strings   : массив Id строк

	Writer.WriteLong(type_Table);
	Writer.WriteString2(this.Id);
	Writer.WriteString2(null === this.TableStyle ? "" : this.TableStyle);
	Writer.WriteBool(this.Inline);

	var GridCount = this.TableGrid.length;
	Writer.WriteLong(GridCount);
	for (var Index = 0; Index < GridCount; Index++)
		Writer.WriteDouble(this.TableGrid[Index]);

	Writer.WriteDouble(this.X_origin);
	Writer.WriteDouble(this.X);
	Writer.WriteDouble(this.Y);
	Writer.WriteDouble(this.XLimit);
	Writer.WriteDouble(this.YLimit);

	this.Pr.Write_ToBinary(Writer);

	var RowsCount = this.Content.length;
	Writer.WriteLong(RowsCount);
	for (var Index = 0; Index < RowsCount; Index++)
		Writer.WriteString2(this.Content[Index].Get_Id());
	Writer.WriteBool(this.bPresentation);
};
CTable.prototype.Read_FromBinary2 = function(Reader)
{
	// Long               : type_Table
	// String             : Id самой таблицы
	// String             : Id стиля (если стока пустая, то null)
	// Bool               : Inline
	// Long               : количество элементов в TableGrid
	// Array of doubles   : массив TableGrid
	// Double             : X_origin
	// Double             : X
	// Double             : Y
	// Double             : XLimit
	// Double             : YLimit
	// Variable           : свойства таблицы (TablePr)
	// Long               : количество строк
	// Array of Strings   : массив Id строк

	this.Prev = null;
	this.Next = null;

	Reader.GetLong();
	this.Id = Reader.GetString2();

	var TableStyleId = Reader.GetString2();
	this.TableStyle  = ( TableStyleId === "" ? null : TableStyleId );

	this.Inline = Reader.GetBool();

	var GridCount  = Reader.GetLong();
	this.TableGrid = [];
	for (var Index = 0; Index < GridCount; Index++)
		this.TableGrid.push(Reader.GetDouble());

	this.X_origin = Reader.GetDouble();
	this.X        = Reader.GetDouble();
	this.Y        = Reader.GetDouble();
	this.XLimit   = Reader.GetDouble();
	this.YLimit   = Reader.GetDouble();

	this.Pr = new CTablePr();
	this.Pr.Read_FromBinary(Reader);
	this.Recalc_CompiledPr();

	var Count    = Reader.GetLong();
	this.Content = [];
	for (var Index = 0; Index < Count; Index++)
	{
		var Row = g_oTableId.Get_ById(Reader.GetString2());
		this.Content.push(Row);
	}
	this.bPresentation = Reader.GetBool();

	this.Internal_ReIndexing();

	AscCommon.CollaborativeEditing.Add_NewObject(this);

	var DrawingDocument = editor.WordControl.m_oDrawingDocument;
	if (undefined !== DrawingDocument && null !== DrawingDocument)
	{
		this.DrawingDocument = DrawingDocument;
		this.LogicDocument   = this.DrawingDocument.m_oLogicDocument;
	}

	// Добавляем, чтобы в конце выставить CurCell
	var LinkData     = {};
	LinkData.CurCell = true;
	AscCommon.CollaborativeEditing.Add_LinkData(this, LinkData);
};
CTable.prototype.Load_LinkData = function(LinkData)
{
	if ("undefined" != typeof(LinkData) && "undefined" != typeof(LinkData.CurCell))
	{
		if (this.Content.length > 0 && this.Content[0].Get_CellsCount() > 0)
			this.CurCell = this.Content[0].Get_Cell(0);
	}
};
CTable.prototype.Get_SelectionState2 = function()
{
	var TableState = {};

	TableState.Id = this.Get_Id();

	TableState.CellId = ( null !== this.CurCell ? this.CurCell.Get_Id() : null );
	TableState.Data   = ( null !== this.CurCell ? this.CurCell.Content.Get_SelectionState2() : null );

	return TableState;
};
CTable.prototype.Set_SelectionState2 = function(TableState)
{
	var CellId = TableState.CellId;

	var CurCell = null;
	var Pos     = {Cell : 0, Row : 0};

	var RowsCount = this.Content.length;
	for (var RowIndex = 0; RowIndex < RowsCount; RowIndex++)
	{
		var Row        = this.Content[RowIndex];
		var CellsCount = Row.Get_CellsCount();
		for (var CellIndex = 0; CellIndex < CellsCount; CellIndex++)
		{
			var Cell = Row.Get_Cell(CellIndex);

			if (Cell.Get_Id() === CellId)
			{
				CurCell = Cell;

				Pos.Cell = CellIndex;
				Pos.Row  = RowIndex;

				break;
			}
		}

		if (null !== CurCell)
			break;
	}

	if (null == CurCell)
	{
		this.MoveCursorToStartPos(false);
	}
	else
	{
		this.CurCell = CurCell;

		this.Selection.Start        = false;
		this.Selection.Use          = false;
		this.Selection.StartPos.Pos = {Row : Pos.Row, Cell : Pos.Cell};
		this.Selection.EndPos.Pos   = {Row : Pos.Row, Cell : Pos.Cell};
		this.Selection.Type         = table_Selection_Common;
		this.Selection.Type2        = table_Selection_Common;
		this.Selection.Data         = null;
		this.Selection.Data2        = null;
		this.Selection.CurRow       = 0;

		this.CurCell.Content.Set_SelectionState2(TableState.Data);
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с гиперссылками
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.AddHyperlink = function(HyperProps)
{
	// Выделения по ячейкам быть не должно
	return this.CurCell.Content.AddHyperlink(HyperProps);
};
CTable.prototype.ModifyHyperlink = function(HyperProps)
{
	if (false === this.Selection.Use || (true === this.Selection.Use && table_Selection_Text === this.Selection.Type))
		this.CurCell.Content.ModifyHyperlink(HyperProps);

	return false;
};
CTable.prototype.RemoveHyperlink = function()
{
	if (false === this.Selection.Use || (true === this.Selection.Use && table_Selection_Text === this.Selection.Type))
		this.CurCell.Content.RemoveHyperlink();
};
CTable.prototype.CanAddHyperlink = function(bCheckInHyperlink)
{
	if (false === this.Selection.Use || (true === this.Selection.Use && table_Selection_Text === this.Selection.Type))
		return this.CurCell.Content.CanAddHyperlink(bCheckInHyperlink);

	return false;
};
CTable.prototype.IsCursorInHyperlink = function(bCheckEnd)
{
	if (false === this.Selection.Use || (true === this.Selection.Use && table_Selection_Text === this.Selection.Type))
		return this.CurCell.Content.IsCursorInHyperlink(bCheckEnd);

	return null;
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с комментариями
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.AddComment = function(Comment, bStart, bEnd)
{
	if (true === this.ApplyToAll)
	{
		var RowsCount  = this.Content.length;
		var CellsCount = this.Content[RowsCount - 1].Get_CellsCount();

		if (true === bStart && true === bEnd && RowsCount <= 1 && CellsCount <= 1)
		{
			var Cell_Content = this.Content[0].Get_Cell(0).Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell_Content.AddComment(Comment, true, true);
			Cell_Content.Set_ApplyToAll(false);
		}
		else
		{
			if (true === bStart)
			{
				var Cell_Content = this.Content[0].Get_Cell(0).Content;
				Cell_Content.Set_ApplyToAll(true);
				Cell_Content.AddComment(Comment, true, false);
				Cell_Content.Set_ApplyToAll(false);
			}

			if (true === bEnd)
			{
				var Cell_Content = this.Content[RowsCount - 1].Get_Cell(CellsCount - 1).Content;
				Cell_Content.Set_ApplyToAll(true);
				Cell_Content.AddComment(Comment, false, true);
				Cell_Content.Set_ApplyToAll(false);
			}

			// TODO: Пока нам приходится пересчитывать ячейки после добавления комментариев. Как только
			//       избавимся от этого, то надо будет переделать здесь.

			var RowsCount = this.Content.length;
			for (var RowIndex = 0; RowIndex < RowsCount; RowIndex++)
			{
				var Row        = this.Content[RowIndex];
				var CellsCount = Row.Get_CellsCount();

				for (var CellIndex = 0; CellIndex < CellsCount; CellIndex++)
				{
					var Cell = Row.Get_Cell(CellIndex);
					this.RecalcInfo.Add_Cell(Cell);
				}
			}
		}
	}
	else
	{
		if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		{
			if (true === bStart && true === bEnd && this.Selection.Data.length <= 1)
			{
				var Pos          = this.Selection.Data[0];
				var Cell_Content = this.Content[Pos.Row].Get_Cell(Pos.Cell).Content;
				Cell_Content.Set_ApplyToAll(true);
				Cell_Content.AddComment(Comment, true, true);
				Cell_Content.Set_ApplyToAll(false);
			}
			else
			{
				var StartPos = null, EndPos = null;

				if (true === bStart)
				{
					StartPos         = this.Selection.Data[0];
					var Cell_Content = this.Content[StartPos.Row].Get_Cell(StartPos.Cell).Content;
					Cell_Content.Set_ApplyToAll(true);
					Cell_Content.AddComment(Comment, true, false);
					Cell_Content.Set_ApplyToAll(false);
				}

				if (true === bEnd)
				{
					EndPos           = this.Selection.Data[this.Selection.Data.length - 1];
					var Cell_Content = this.Content[EndPos.Row].Get_Cell(EndPos.Cell).Content;
					Cell_Content.Set_ApplyToAll(true);
					Cell_Content.AddComment(Comment, false, true);
					Cell_Content.Set_ApplyToAll(false);
				}

				// TODO: Пока нам приходится пересчитывать ячейки после добавления комментариев. Как только
				//       избавимся от этого, то надо будет переделать здесь.

				var StartRow = 0, EndRow = -1, StartCell = 0, EndCell = -1;
				if (null !== StartPos && null !== EndPos)
				{
					StartRow  = StartPos.Row;
					EndRow    = EndPos.Row;
					StartCell = StartPos.Cell;
					EndCell   = EndPos.Cell;
				}
				else if (null !== StartPos)
				{
					StartRow  = StartPos.Row;
					StartCell = StartPos.Cell;
					EndRow    = this.Content.length - 1;
					EndCell   = this.Content[EndRow].Get_CellsCount() - 1;
				}
				else if (null !== EndPos)
				{
					StartRow  = 0;
					StartCell = 0;
					EndRow    = EndPos.Row;
					EndCell   = EndPos.Cell;
				}

				for (var RowIndex = StartRow; RowIndex <= EndRow; RowIndex++)
				{
					var Row = this.Content[RowIndex];

					var _StartCell = ( RowIndex === StartRow ? StartCell : 0 );
					var _EndCell   = ( RowIndex === EndRow ? EndCell : Row.Get_CellsCount() - 1 );

					for (var CellIndex = _StartCell; CellIndex <= _EndCell; CellIndex++)
					{
						var Cell = Row.Get_Cell(CellIndex);
						this.RecalcInfo.Add_Cell(Cell);
					}
				}
			}
		}
		else
		{
			this.CurCell.Content.AddComment(Comment, bStart, bEnd);
		}
	}
};
CTable.prototype.CanAddComment = function()
{
	if (true === this.ApplyToAll)
	{
		if (this.Content.length > 1 || this.Content[0].Get_CellsCount() > 1)
			return true;

		this.Content[0].Get_Cell(0).Content.Set_ApplyToAll(true);
		var Result = this.Content[0].Get_Cell(0).Content.CanAddComment();
		this.Content[0].Get_Cell(0).Content.Set_ApplyToAll(false);
		return Result;
	}
	else
	{
		if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		{
			if (this.Selection.Data.length > 1)
				return true;
			else
			{
				var Pos  = this.Selection.Data[0];
				var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
				return Cell.Content.CanAddComment();
			}
		}
		else
		{
			return this.CurCell.Content.CanAddComment();
		}
	}
};
CTable.prototype.Can_IncreaseParagraphLevel = function(bIncrease)
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		if (this.Selection.Data.length > 0)
		{
			var Data = this.Selection.Data;
			for (var i = 0; i < Data.length; ++i)
			{
				var Pos          = Data[i];
				var Cell_Content = this.Content[Pos.Row].Get_Cell(Pos.Cell).Content;
				if (Cell_Content)
				{
					Cell_Content.Set_ApplyToAll(true);
					var bCan = Cell_Content.Can_IncreaseParagraphLevel(bIncrease);
					Cell_Content.Set_ApplyToAll(false);
					if (!bCan)
					{
						return false;
					}
				}
			}
			return true;
		}
		else
		{
			return false;
		}
	}
	else
	{
		this.CurCell.Content.Can_IncreaseParagraphLevel(bIncrease);
	}
};
CTable.prototype.GetSelectionBounds = function()
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();

		var StartPos = Cells_array[0];

		var Row  = this.Content[StartPos.Row];
		var Cell = Row.Get_Cell(StartPos.Cell);

		var X0 = Cell.Metrics.X_cell_start;
		var X1 = Cell.Metrics.X_cell_end;

		var CurPage = this.RowsInfo[StartPos.Row].StartPage;

		var Y = this.RowsInfo[StartPos.Row].Y[CurPage];
		var H = this.RowsInfo[StartPos.Row].H[CurPage];

		var TableX = this.Pages[CurPage].X + this.RowsInfo[StartPos.Row].X0;

		var BeginRect = {X : TableX + X0, Y : Y, W : X1 - X0, H : H, Page : CurPage + this.Get_StartPage_Absolute()};

		var EndPos = Cells_array[Cells_array.length - 1];

		Row  = this.Content[EndPos.Row];
		Cell = Row.Get_Cell(EndPos.Cell);

		X0 = Cell.Metrics.X_cell_start;
		X1 = Cell.Metrics.X_cell_end;

		CurPage = this.RowsInfo[EndPos.Row].StartPage + this.RowsInfo[EndPos.Row].Pages - 1;

		Y = this.RowsInfo[EndPos.Row].Y[CurPage];
		H = this.RowsInfo[EndPos.Row].H[CurPage];

		var Direction = 1;
		if (this.Selection.StartPos.Pos.Row < this.Selection.EndPos.Pos.Row || (this.Selection.StartPos.Pos.Row === this.Selection.EndPos.Pos.Row && this.Selection.StartPos.Pos.Cell <= this.Selection.EndPos.Pos.Cell))
			Direction = 1;
		else
			Direction = -1;

		var EndRect = {X : TableX + X0, Y : Y, W : X1 - X0, H : H, Page : CurPage + this.Get_StartPage_Absolute()};

		return {Start : BeginRect, End : EndRect, Direction : Direction};
	}
	else
	{
		return this.CurCell.Content.GetSelectionBounds();
	}
};
CTable.prototype.GetSelectionAnchorPos = function()
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();

		var Pos  = Cells_array[0];
		var Row  = this.Content[Pos.Row];
		var Cell = Row.Get_Cell(Pos.Cell);

		var X0 = Cell.Metrics.X_cell_start;
		var X1 = Cell.Metrics.X_cell_end;

		var Y    = this.RowsInfo[Pos.Row].Y[this.RowsInfo[Pos.Row].StartPage];
		var Page = this.RowsInfo[Pos.Row].StartPage + this.Get_StartPage_Absolute();

		return {X0 : X0, X1 : X1, Y : Y, Page : Page};
	}
	else
	{
		return this.CurCell.Content.GetSelectionAnchorPos();
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Работаем с текущей позицией и селектом таблицы
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.MoveCursorToXY = function(X, Y, bLine, bDontChangeRealPos, CurPage)
{
	var Pos  = this.Internal_GetCellByXY(X, Y, CurPage);
	var Row  = this.Content[Pos.Row];
	var Cell = Row.Get_Cell(Pos.Cell);

	this.Selection.Type         = table_Selection_Text;
	this.Selection.Type2        = table_Selection_Common;
	this.Selection.StartPos.Pos = {Row : Pos.Row, Cell : Pos.Cell};
	this.Selection.EndPos.Pos   = {Row : Pos.Row, Cell : Pos.Cell};
	this.Selection.CurRow       = Pos.Row;

	// Устанавливаем найденную ячейку текущей и перемещаемся в контент ячейки по координатам X,Y
	this.CurCell = Cell;
	this.DrawingDocument.TargetStart();
	this.DrawingDocument.TargetShow();
	this.CurCell.Content_MoveCursorToXY(X, Y, false, true, CurPage - this.CurCell.Content.Get_StartPage_Relative());
	if (this.LogicDocument)
	{
		this.LogicDocument.RecalculateCurPos();
	}
};
CTable.prototype.Selection_SetStart = function(X, Y, CurPage, MouseEvent)
{
	if (CurPage < 0 || CurPage >= this.Pages.length)
		CurPage = 0;

	var Page = this.Pages[CurPage];

	var oHitInfo = this.private_CheckHitInBorder(X, Y, CurPage);

	var Pos = oHitInfo.Pos;
	if (oHitInfo.ColumnSelection || oHitInfo.RowSelection || oHitInfo.CellSelection)
	{
		this.RemoveSelection();

		this.CurCell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
		this.CurCell.Content_Selection_SetStart(X, Y, CurPage - this.CurCell.Content.Get_StartPage_Relative(), MouseEvent);

		this.Selection.Use   = true;
		this.Selection.Start = true;
		this.Selection.Type  = table_Selection_Cell;
		this.Selection.Type2 = table_Selection_Cells;
		this.Selection.Data2 = null;

		this.Selection.StartPos.Pos        = Pos;
		this.Selection.StartPos.X          = X;
		this.Selection.StartPos.Y          = Y;
		this.Selection.StartPos.PageIndex  = CurPage;
		this.Selection.StartPos.MouseEvent = {
			// TODO : Если в MouseEvent будет использоваться что-то кроме ClickCount, Type и CtrlKey, добавить
			// здесь
			ClickCount : MouseEvent.ClickCount,
			Type       : MouseEvent.Type,
			CtrlKey    : MouseEvent.CtrlKey
		};

		var oEndPos = {
			Row  : Pos.Row,
			Cell : Pos.Cell
		};

		if (oHitInfo.RowSelection)
		{
			oEndPos.Cell = this.GetRow(Pos.Row).GetCellsCount() - 1;
			this.Selection.Type2 = table_Selection_Rows;
		}
		else if (oHitInfo.ColumnSelection)
		{
			var oRow     = this.GetRow(Pos.Row);
			var nEndRow  = this.GetRowsCount() - 1;
			var nEndCell = this.private_GetCellIndexByStartGridCol(nEndRow, oRow.GetCellInfo(Pos.Cell).StartGridCol, true);

			if (-1 !== nEndCell)
			{
				oEndPos.Row  = nEndRow;
				oEndPos.Cell = nEndCell;
				this.Selection.Type2 = table_Selection_Columns;
			}
		}

		this.Selection.EndPos.Pos        = oEndPos;
		this.Selection.EndPos.X          = X;
		this.Selection.EndPos.Y          = Y;
		this.Selection.EndPos.PageIndex  = CurPage;
		this.Selection.EndPos.MouseEvent = {
			// TODO : Если в MouseEvent будет использоваться что-то кроме ClickCount, Type и CtrlKey, добавить
			// здесь
			ClickCount : MouseEvent.ClickCount,
			Type       : MouseEvent.Type,
			CtrlKey    : MouseEvent.CtrlKey
		};


		this.Selection.Type = table_Selection_Cell;
		this.private_UpdateSelectedCellsArray();
	}
	else if (-1 === oHitInfo.Border)
	{
		var bInnerTableBorder = ( null != this.IsTableBorder(X, Y, CurPage) ? true : false );
		if (true === bInnerTableBorder)
		{
			// Значит двигается граница внутренней таблицы, мы не должны отменять селект
			var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
			Cell.Content_Selection_SetStart(X, Y, CurPage - Cell.Content.Get_StartPage_Relative(), MouseEvent);

			this.Selection.Type2 = table_Selection_Border_InnerTable;
			this.Selection.Data2 = Cell;
		}
		else
		{
			this.RemoveSelection();

			this.CurCell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
			this.CurCell.Content_Selection_SetStart(X, Y, CurPage - this.CurCell.Content.Get_StartPage_Relative(), MouseEvent);

			this.Selection.Use   = true;
			this.Selection.Start = true;
			this.Selection.Type  = table_Selection_Text;
			this.Selection.Type2 = table_Selection_Common;
			this.Selection.Data2 = null;

			this.Selection.StartPos.Pos        = Pos;
			this.Selection.StartPos.X          = X;
			this.Selection.StartPos.Y          = Y;
			this.Selection.StartPos.PageIndex  = CurPage;
			this.Selection.StartPos.MouseEvent = {
				// TODO : Если в MouseEvent будет использоваться что-то кроме ClickCount, Type и CtrlKey, добавить
				// здесь
				ClickCount : MouseEvent.ClickCount,
				Type       : MouseEvent.Type,
				CtrlKey    : MouseEvent.CtrlKey
			};
		}
	}
	else
	{
		this.private_UpdateTableMarkup(Pos.Row, Pos.Cell, CurPage);
		this.Selection.Type2         = table_Selection_Border;
		this.Selection.Data2         = {};
		this.Selection.Data2.PageNum = CurPage;

		var Row = this.Content[Pos.Row];

		var _X = X;
		var _Y = Y;

		if (0 === oHitInfo.Border || 2 === oHitInfo.Border)
		{
			var PageH = this.LogicDocument.Get_PageLimits(this.Get_StartPage_Absolute()).YLimit;

			var Y_min = 0;
			var Y_max = PageH;

			this.Selection.Data2.bCol = false;

			var Row_start = this.Pages[CurPage].FirstRow;
			var Row_end   = this.Pages[CurPage].LastRow;
			if (0 === oHitInfo.Border)
				this.Selection.Data2.Index = Pos.Row - Row_start;
			else
				this.Selection.Data2.Index = oHitInfo.Row - Row_start + 1;

			if (0 != this.Selection.Data2.Index)
			{
				var TempRow = this.Selection.Data2.Index + Row_start - 1;
				Y_min       = this.RowsInfo[TempRow].Y[CurPage];
			}

			// Подправим Y, чтобы первоначально точно по границе проходила линия
			if (this.Selection.Data2.Index !== Row_end - Row_start + 1)
				_Y = this.RowsInfo[this.Selection.Data2.Index + Row_start].Y[CurPage];
			else
				_Y = this.RowsInfo[this.Selection.Data2.Index + Row_start - 1].Y[CurPage] + this.RowsInfo[this.Selection.Data2.Index + Row_start - 1].H[CurPage];

			this.Selection.Data2.Min = Y_min;
			this.Selection.Data2.Max = Y_max;

			this.Selection.Data2.Pos =
				{
					Row  : Pos.Row,
					Cell : Pos.Cell
				};

			if (null != this.Selection.Data2.Min)
				_Y = Math.max(_Y, this.Selection.Data2.Min);

			if (null != this.Selection.Data2.Max)
				_Y = Math.min(_Y, this.Selection.Data2.Max);
		}
		else
		{
			var CellsCount  = Row.Get_CellsCount();
			var CellSpacing = ( null === Row.Get_CellSpacing() ? 0 : Row.Get_CellSpacing() );
			var X_min       = null;
			var X_max       = null;

			this.Selection.Data2.bCol = true;
			if (3 === oHitInfo.Border)
				this.Selection.Data2.Index = Pos.Cell;
			else
				this.Selection.Data2.Index = Pos.Cell + 1;

			if (0 != this.Selection.Data2.Index)
			{
				var Margins = Row.Get_Cell(this.Selection.Data2.Index - 1).GetMargins();
				if (0 != this.Selection.Data2.Index - 1 && this.Selection.Data2.Index != CellsCount)
					X_min = Page.X + Row.Get_CellInfo(this.Selection.Data2.Index - 1).X_grid_start + Margins.Left.W + Margins.Right.W + CellSpacing;
				else
					X_min = Page.X + Row.Get_CellInfo(this.Selection.Data2.Index - 1).X_grid_start + Margins.Left.W + Margins.Right.W + 1.5 * CellSpacing;
			}

			if (CellsCount != this.Selection.Data2.Index)
			{
				var Margins = Row.Get_Cell(this.Selection.Data2.Index).GetMargins();
				if (CellsCount - 1 != this.Selection.Data2.Index)
					X_max = Page.X + Row.Get_CellInfo(this.Selection.Data2.Index).X_grid_end - (Margins.Left.W + Margins.Right.W + CellSpacing);
				else
					X_max = Page.X + Row.Get_CellInfo(this.Selection.Data2.Index).X_grid_end - (Margins.Left.W + Margins.Right.W + 1.5 * CellSpacing);
			}

			// Подправим значение по X, чтобы первоначально точно по границе проходила линия
			if (CellsCount != this.Selection.Data2.Index)
				_X = Page.X + Row.Get_CellInfo(this.Selection.Data2.Index).X_grid_start;
			else
				_X = Page.X + Row.Get_CellInfo(this.Selection.Data2.Index - 1).X_grid_end;

			this.Selection.Data2.Min = X_min;
			this.Selection.Data2.Max = X_max;

			this.Selection.Data2.Pos =
				{
					Row  : Pos.Row,
					Cell : Pos.Cell
				};

			if (null != this.Selection.Data2.Min)
				_X = Math.max(_X, this.Selection.Data2.Min);

			if (null != this.Selection.Data2.Max)
				_X = Math.min(_X, this.Selection.Data2.Max);
		}

		this.Selection.Data2.X = _X;
		this.Selection.Data2.Y = _Y;

		this.Selection.Data2.StartCX = _X; // Начальная позиция скорректированная относительно положения границы
		this.Selection.Data2.StartCY = _Y;
		this.Selection.Data2.StartX  = X; // Начальная позиция нажатия мыши (без корректировки)
		this.Selection.Data2.StartY  = Y;
		this.Selection.Data2.Start   = true;

		this.DrawingDocument.LockCursorTypeCur();
	}
};
CTable.prototype.Selection_SetEnd = function(X, Y, CurPage, MouseEvent)
{
	var TablePr = this.Get_CompiledPr(false).TablePr;
	if (CurPage < 0 || CurPage >= this.Pages.length)
		CurPage = 0;

	var Page = this.Pages[CurPage];
	if (this.Selection.Type2 === table_Selection_Border)
	{
		var LogicDocument = this.LogicDocument;
		if (!LogicDocument || true !== LogicDocument.CanEdit() || this.Selection.Data2.PageNum != CurPage)
			return;

		var _X = X;
		var _Y = Y;

		// Проверяем, случайное нажатие на границу. (т.е. случайное однократное нажатие или с малым смещением)
		if (true !== this.Selection.Data2.Start || Math.abs(X - this.Selection.Data2.StartX) > 0.05 || Math.abs(Y - this.Selection.Data2.StartY) > 0.05)
		{
			_X                         = this.DrawingDocument.CorrectRulerPosition(X);
			_Y                         = this.DrawingDocument.CorrectRulerPosition(Y);
			this.Selection.Data2.Start = false;
		}
		else
		{
			_X = this.Selection.Data2.X;
			_Y = this.Selection.Data2.Y;
		}

		if (true === this.Selection.Data2.bCol)
			_X = this.private_UpdateTableRulerOnBorderMove(_X);
		else
			_Y = this.private_UpdateTableRulerOnBorderMove(_Y);

		this.Selection.Data2.X = _X;
		this.Selection.Data2.Y = _Y;

		if (MouseEvent.Type === AscCommon.g_mouse_event_type_up)
		{
			// Обрабатываем случай, когда граница не изменила своего первоначального положения
			if (Math.abs(_X - this.Selection.Data2.StartCX) < 0.001 && Math.abs(_Y - this.Selection.Data2.StartCY) < 0.001)
			{
				this.Selection.Type2 = table_Selection_Common;
				this.Selection.Data2 = null;

				return;
			}

			if (false === LogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_None, {
					Type      : AscCommon.changestype_2_Element_and_Type,
					Element   : this,
					CheckType : AscCommon.changestype_Table_Properties
				}))
			{
				History.Create_NewPoint(AscDFH.historydescription_Document_MoveTableBorder);

				if (true === this.Selection.Data2.bCol)
				{
					// Найдем колонку в TableGrid, с которой мы работаем
					var Index  = this.Selection.Data2.Index;
					var CurRow = this.Selection.Data2.Pos.Row;
					var Row    = this.Content[CurRow];

					var Col = 0;

					// границ на 1 больше, чем самих ячеек в строке
					if (Index === this.Markup.Cols.length)
						Col = Row.Get_CellInfo(Index - 1).StartGridCol + Row.Get_Cell(Index - 1).Get_GridSpan();
					else
						Col = Row.Get_CellInfo(Index).StartGridCol;

					var Dx = _X - (Page.X + this.TableSumGrid[Col - 1]);

					// Строим новую секту для таблицы
					var Rows_info = [];

					// Если граница, которую мы двигаем не попадает в селект, тогда работает, как будто селекта и нет
					var bBorderInSelection = false;
					if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 && !this.bPresentation)
					{
						var CellsFlag = [];
						for (CurRow = 0; CurRow < this.Content.length; CurRow++)
						{
							CellsFlag[CurRow] = [];
							Row               = this.Content[CurRow];
							var CellsCount    = Row.Get_CellsCount();
							for (var CurCell = 0; CurCell < CellsCount; CurCell++)
							{
								CellsFlag[CurRow][CurCell] = 0;
							}
						}

						var CurSelectedCell  = this.Selection.Data[0];
						var CurSelectedIndex = 0;
						for (CurRow = 0; CurRow < this.Content.length; CurRow++)
						{
							Row            = this.Content[CurRow];
							var CellsCount = Row.Get_CellsCount();
							for (var CurCell = 0; CurCell < CellsCount; CurCell++)
							{
								if (CurSelectedCell.Cell === CurCell && CurSelectedCell.Row === CurRow)
								{
									CellsFlag[CurRow][CurCell] = 1;

									var StartGridCol = Row.Get_CellInfo(CurCell).StartGridCol;
									var GridSpan     = Row.Get_Cell(CurCell).Get_GridSpan();
									var VMergeCount  = this.Internal_GetVertMergeCount(CurRow, StartGridCol, GridSpan);

									if (CurRow === this.Selection.Data2.Pos.Row && Col >= StartGridCol && Col <= StartGridCol + GridSpan)
										bBorderInSelection = true;

									for (var TempIndex = 1; TempIndex < VMergeCount; TempIndex++)
									{
										var TempCell = this.private_GetCellIndexByStartGridCol(CurRow + TempIndex, StartGridCol);
										if (-1 != TempCell)
										{
											CellsFlag[CurRow + TempIndex][TempCell] = 1;

											if (CurRow + TempIndex === this.Selection.Data2.Pos.Row && Col >= StartGridCol && Col <= StartGridCol + GridSpan)
												bBorderInSelection = true;
										}
									}

									if (CurSelectedIndex < this.Selection.Data.length - 1)
										CurSelectedCell = this.Selection.Data[++CurSelectedIndex];
									else
										CurSelectedCell = {Row : -1, Cell : -1};
								}
							}
						}

					}

					var OldTableInd = TablePr.TableInd;
					var NewTableInd = TablePr.TableInd;
					if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && true === bBorderInSelection && !this.bPresentation)
					{
						var BeforeFlag   = false;
						var BeforeSpace2 = null;
						if (0 === Col)
						{
							BeforeSpace2 = _X - Page.X;

							if (BeforeSpace2 < 0)
							{
								Page.X += BeforeSpace2;

								if (true === this.Is_Inline())
									NewTableInd = NewTableInd + BeforeSpace2;
								else
									this.Internal_UpdateFlowPosition(Page.X, Page.Y);
							}
						}

						var BeforeSpace = null;
						if (0 === Index && 0 != Col && _X < Page.X)
						{
							BeforeSpace = Page.X - _X;
							Page.X -= BeforeSpace;

							if (true === this.Is_Inline())
								NewTableInd = NewTableInd - BeforeSpace;
							else
								this.Internal_UpdateFlowPosition(Page.X, Page.Y);
						}

						for (CurRow = 0; CurRow < this.Content.length; CurRow++)
						{
							Rows_info[CurRow] = [];
							Row               = this.Content[CurRow];
							var Before_Info   = Row.Get_Before();

							var WBefore = 0;

							if (null === BeforeSpace2)
							{
								if (Before_Info.GridBefore > 0 && Col === Before_Info.GridBefore && 1 === CellsFlag[CurRow][0])
									WBefore = this.TableSumGrid[Before_Info.GridBefore - 1] + Dx;
								else
								{
									if (null != BeforeSpace)
										WBefore = this.TableSumGrid[Before_Info.GridBefore - 1] + BeforeSpace;
									else
										WBefore = this.TableSumGrid[Before_Info.GridBefore - 1];
								}
							}
							else
							{
								if (BeforeSpace2 > 0)
								{
									if (0 === Before_Info.GridBefore && 1 === CellsFlag[CurRow][0])
										WBefore = BeforeSpace2;
									else if (0 != Before_Info.GridBefore)
										WBefore = this.TableSumGrid[Before_Info.GridBefore - 1];
								}
								else
								{
									if (0 === Before_Info.GridBefore && 1 != CellsFlag[CurRow][0])
										WBefore = -BeforeSpace2;
									else if (0 != Before_Info.GridBefore)
										WBefore = -BeforeSpace2 + this.TableSumGrid[Before_Info.GridBefore - 1];
								}
							}

							if (WBefore > 0.001)
								Rows_info[CurRow].push({W : WBefore, Type : -1, GridSpan : 1});


							var CellsCount = Row.Get_CellsCount();
							var TempDx     = Dx;
							for (var CurCell = 0; CurCell < CellsCount; CurCell++)
							{
								var Cell           = Row.Get_Cell(CurCell);
								var CellMargins    = Cell.GetMargins();
								var Cur_Grid_start = Row.Get_CellInfo(CurCell).StartGridCol;
								var Cur_Grid_end   = Cur_Grid_start + Cell.Get_GridSpan() - 1;

								var W = 0;
								if (Cur_Grid_end + 1 === Col && ( 1 === CellsFlag[CurRow][CurCell] || ( CurCell + 1 < CellsCount && 1 === CellsFlag[CurRow][CurCell + 1] ) ))
									W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1] + Dx;
								else if (Cur_Grid_start === Col && ( 1 === CellsFlag[CurRow][CurCell] || ( CurCell > 0 && 1 === CellsFlag[CurRow][CurCell - 1] ) ))
									W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1] - TempDx;
								else
									W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1];

								W = Math.max(1, Math.max(W, CellMargins.Left.W + CellMargins.Right.W));
								if (Cur_Grid_end + 1 === Col && ( 1 === CellsFlag[CurRow][CurCell] || ( CurCell + 1 < CellsCount && 1 === CellsFlag[CurRow][CurCell + 1] ) ))
									TempDx = W - (this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1]);

								Rows_info[CurRow].push({W : W, Type : 0, GridSpan : 1});
							}
						}

						// Возможно, что во всех рядах RowsInfo в начале есть запись BeforeGrid
						var MinBefore = 0;
						for (CurRow = 0; CurRow < this.Content.length; CurRow++)
						{
							if (-1 != Rows_info[CurRow][0].Type)
							{
								MinBefore = 0;
								break;
							}

							if (0 === MinBefore || MinBefore > Rows_info[CurRow][0].W)
								MinBefore = Rows_info[CurRow][0].W;
						}

						if (0 != MinBefore)
						{
							for (CurRow = 0; CurRow < this.Content.length; CurRow++)
							{
								if (Math.abs(MinBefore - Rows_info[CurRow][0].W) < 0.001)
									Rows_info[CurRow].splice(0, 1);
								else // if ( MinBefore < Rows_info[CurRow][0].W )
									Rows_info[CurRow][0].W -= MinBefore;
							}

							Page.X += MinBefore;
							if (true === this.Is_Inline())
								NewTableInd = NewTableInd + MinBefore;
							else
								this.Internal_UpdateFlowPosition(Page.X, Page.Y);
						}
					}
					else
					{
						var BeforeFlag   = false;
						var BeforeSpace2 = null;
						if (0 === Col)
						{
							BeforeSpace2 = Page.X - _X;

							if (-BeforeSpace2 > this.TableSumGrid[0])
							{
								BeforeFlag = true;
								Page.X += this.TableSumGrid[0];
							}
							else
								Page.X += Dx;

							if (true === this.Is_Inline())
							{
								if (-BeforeSpace2 > this.TableSumGrid[0])
									NewTableInd = NewTableInd + this.TableSumGrid[0];
								else
									NewTableInd = NewTableInd + Dx;
							}
							else
								this.Internal_UpdateFlowPosition(Page.X, Page.Y);
						}

						var BeforeSpace = null;
						if (0 === Index && 0 != Col && _X < Page.X)
						{
							BeforeSpace = Page.X - _X;
							Page.X -= BeforeSpace;
							if (true === this.Is_Inline())
								NewTableInd = NewTableInd - BeforeSpace;
							else
								this.Internal_UpdateFlowPosition(Page.X, Page.Y);
						}

						for (CurRow = 0; CurRow < this.Content.length; CurRow++)
						{
							Rows_info[CurRow] = [];
							Row               = this.Content[CurRow];
							var Before_Info   = Row.Get_Before();

							var WBefore = 0;

							if (Before_Info.GridBefore > 0 && Col === Before_Info.GridBefore)
								WBefore = this.TableSumGrid[Before_Info.GridBefore - 1] + Dx;
							else
							{
								if (null != BeforeSpace)
									WBefore = this.TableSumGrid[Before_Info.GridBefore - 1] + BeforeSpace;
								else
									WBefore = this.TableSumGrid[Before_Info.GridBefore - 1];

								if (null != BeforeSpace2)
								{
									if (Before_Info.GridBefore > 0)
									{
										if (true === BeforeFlag)
											WBefore = this.TableSumGrid[Before_Info.GridBefore - 1] - this.TableSumGrid[0];
										else
											WBefore = this.TableSumGrid[Before_Info.GridBefore - 1] + BeforeSpace2;

									}
									else if (0 === Before_Info.GridBefore && true === BeforeFlag)
										WBefore = ( -BeforeSpace2 ) - this.TableSumGrid[0];
								}
							}

							if (WBefore > 0.001)
								Rows_info[CurRow].push({W : WBefore, Type : -1, GridSpan : 1});

							var CellsCount = Row.Get_CellsCount();
							var TempDx     = Dx;
							for (var CurCell = 0; CurCell < CellsCount; CurCell++)
							{
								var Cell           = Row.Get_Cell(CurCell);
								var CellMargins    = Cell.GetMargins();
								var Cur_Grid_start = Row.Get_CellInfo(CurCell).StartGridCol;
								var Cur_Grid_end   = Cur_Grid_start + Cell.Get_GridSpan() - 1;

								var W = 0;
								if (Cur_Grid_end + 1 === Col)
									W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1] + Dx;
								else if (Cur_Grid_start === Col)
									W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1] - TempDx;
								else
									W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1];

								W = Math.max(1, Math.max(W, CellMargins.Left.W + CellMargins.Right.W));
								if (Cur_Grid_end + 1 === Col)
									TempDx = W - (this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1]);

								Rows_info[CurRow].push({W : W, Type : 0, GridSpan : 1});
							}
						}
					}

					if (Math.abs(NewTableInd - OldTableInd) > 0.001)
						this.Set_TableInd(NewTableInd);

					var oTablePr = this.Get_CompiledPr(false).TablePr;
					if (tbllayout_AutoFit === oTablePr.TableLayout)
						this.SetTableLayout(tbllayout_Fixed);

					this.Internal_CreateNewGrid(Rows_info);

					if (undefined !== oTablePr.TableW && tblwidth_Auto !== oTablePr.TableW.Type)
					{
						var nTableW = 0;
						for (var nCurCol = 0, nColsCount = this.TableGrid.length; nCurCol < nColsCount; ++nCurCol)
							nTableW += this.TableGrid[nCurCol];

						if (tblwidth_Pct === oTablePr.TableW.Type)
						{
							var nPctWidth = this.private_RecalculatePercentWidth();
							if (nPctWidth < 0.01)
								this.Set_TableW(tblwidth_Auto, 0);
							else
								this.Set_TableW(tblwidth_Pct, nTableW / nPctWidth * 100);
						}
						else
						{
							this.Set_TableW(tblwidth_Mm, nTableW);
						}
					}

					this.private_RecalculateGrid();
				}
				else
				{
					var RowIndex = this.Pages[this.Selection.Data2.PageNum].FirstRow + this.Selection.Data2.Index;
					if (0 === RowIndex)
					{
						if (true === this.Is_Inline())
						{
							// Ничего не делаем
						}
						else
						{
							var Dy = _Y - this.Markup.Rows[0].Y;
							Page.Y += Dy;
							this.Internal_UpdateFlowPosition(Page.X, Page.Y);

							//var NewH = this.Markup.Rows[0].H + Dy;
							//this.Content[0].Set_Height( NewH, Asc.linerule_AtLeast );
						}
					}
					else
					{
						if (this.Selection.Data2.PageNum > 0 && 0 === this.Selection.Data2.Index)
						{
							// Ничего не делаем
						}
						else
						{
							var _Y_old = this.Markup.Rows[this.Selection.Data2.Index - 1].Y + this.Markup.Rows[this.Selection.Data2.Index - 1].H;
							var Dy     = _Y - _Y_old;
							var NewH   = this.Markup.Rows[this.Selection.Data2.Index - 1].H + Dy;
							this.Content[RowIndex - 1].Set_Height(NewH, linerule_AtLeast);
						}
					}
				}

				this.Internal_Recalculate_1();
			}

			this.Selection.Type2 = table_Selection_Common;
			this.Selection.Data2 = null;
		}

		return;
	}
	else if (table_Selection_Border_InnerTable === this.Selection.Type2)
	{
		var Cell = this.Selection.Data2;
		Cell.Content_Selection_SetEnd(X, Y, CurPage - Cell.Content.Get_StartPage_Relative(), MouseEvent);

		if (MouseEvent.Type === AscCommon.g_mouse_event_type_up)
		{
			this.Selection.Type2 = table_Selection_Common;
			this.Selection.Data2 = null;
		}

		return;
	}

	var oTempPos = this.Internal_GetCellByXY(X, Y, CurPage);

	var Pos = {
		Row  : oTempPos.Row,
		Cell : oTempPos.Cell
	};

	if (table_Selection_Rows === this.Selection.Type2)
	{
		Pos.Cell = this.GetRow(Pos.Row).GetCellsCount() - 1;
	}
	else if (table_Selection_Columns === this.Selection.Type2)
	{
		var oRow     = this.GetRow(oTempPos.Row);
		var nEndRow  = this.GetRowsCount() - 1;
		var nEndCell = this.private_GetCellIndexByStartGridCol(nEndRow, oRow.GetCellInfo(oTempPos.Cell).StartGridCol, true);

		if (-1 !== nEndCell)
		{
			Pos.Row  = nEndRow;
			Pos.Cell = nEndCell;
		}
	}

	this.Content[Pos.Row].Get_Cell(Pos.Cell).Content_SetCurPosXY(X, Y);
	this.Selection.Data              = null;
	this.Selection.EndPos.Pos        = Pos;
	this.Selection.EndPos.X          = X;
	this.Selection.EndPos.Y          = Y;
	this.Selection.EndPos.PageIndex  = CurPage;
	this.Selection.EndPos.MouseEvent = MouseEvent;
	this.Selection.CurRow            = Pos.Row;

	// При селекте внутри ячейки мы селектим содержимое ячейки
	if (table_Selection_Common === this.Selection.Type2 && this.Parent.IsSelectedSingleElement() && this.Selection.StartPos.Pos.Row === this.Selection.EndPos.Pos.Row && this.Selection.StartPos.Pos.Cell === this.Selection.EndPos.Pos.Cell)
	{
		this.CurCell.Content_Selection_SetStart(this.Selection.StartPos.X, this.Selection.StartPos.Y, this.Selection.StartPos.PageIndex - this.CurCell.Content.Get_StartPage_Relative(), this.Selection.StartPos.MouseEvent);

		this.Selection.Type = table_Selection_Text;

		this.CurCell.Content_Selection_SetEnd(X, Y, CurPage - this.CurCell.Content.Get_StartPage_Relative(), MouseEvent);

		if (AscCommon.g_mouse_event_type_up == MouseEvent.Type)
			this.Selection.Start = false;

		if (false === this.CurCell.Content.Selection.Use)
		{
			this.Selection.Use   = false;
			this.Selection.Start = false;
			this.MoveCursorToXY(X, Y, false, false, CurPage);
			return;
		}
	}
	else
	{
		if (AscCommon.g_mouse_event_type_up === MouseEvent.Type)
		{
			this.Selection.Start = false;
			this.CurCell         = this.Content[Pos.Row].Get_Cell(Pos.Cell);

			if (table_Selection_Cells === this.Selection.Type2
				&& this.Selection.StartPos.Pos.Cell === this.Selection.EndPos.Pos.Cell
				&& this.Selection.StartPos.Pos.Row === this.Selection.EndPos.Pos.Row
				&& MouseEvent.ClickCount > 1
				&& 0 === MouseEvent.ClickCount % 2)
			{
				this.Selection.StartPos.Pos.Cell = 0;
				this.Selection.EndPos.Pos.Cell   = this.GetRow(this.Selection.StartPos.Pos.Row).GetCellsCount() - 1;
			}
		}

		this.Selection.Type = table_Selection_Cell;
		this.private_UpdateSelectedCellsArray(table_Selection_Rows === this.Selection.Type2 ? true : false);
	}
};
CTable.prototype.Selection_Stop = function()
{
	if (true != this.Selection.Use)
		return;

	this.Selection.Start = false;
	var Cell             = this.Content[this.Selection.StartPos.Pos.Row].Get_Cell(this.Selection.StartPos.Pos.Cell);
	Cell.Content_Selection_Stop();
};
CTable.prototype.DrawSelectionOnPage = function(CurPage)
{
	if (false === this.Selection.Use)
		return;

	if (CurPage < 0 || CurPage >= this.Pages.length)
		return;

	var Page    = this.Pages[CurPage];
	var PageAbs = this.private_GetAbsolutePageIndex(CurPage);

	switch (this.Selection.Type)
	{
		case table_Selection_Cell:
		{
			for (var Index = 0; Index < this.Selection.Data.length; ++Index)
			{
				var Pos      = this.Selection.Data[Index];
				var Row      = this.Content[Pos.Row];
				var Cell     = Row.Get_Cell(Pos.Cell);
				var CellInfo = Row.Get_CellInfo(Pos.Cell);
				var CellMar  = Cell.GetMargins();

				var X_start = (0 === Pos.Cell ? Page.X + CellInfo.X_content_start : Page.X + CellInfo.X_cell_start);
				var X_end   = Page.X + CellInfo.X_cell_end;

				var Cell_Pages   = Cell.Content_Get_PagesCount();
				var Cell_PageRel = CurPage - Cell.Content.Get_StartPage_Relative();
				if (Cell_PageRel < 0 || Cell_PageRel >= Cell_Pages)
					continue;

				var Bounds   = Cell.Content_Get_PageBounds(Cell_PageRel);
				var Y_offset = Cell.Temp.Y_VAlign_offset[Cell_PageRel];

				var RowIndex = 0 != Cell_PageRel ? this.Pages[CurPage].FirstRow : Pos.Row;

				if (true === Cell.Is_VerticalText())
				{
					var X_start       = Page.X + CellInfo.X_cell_start;
					var TextDirection = Cell.Get_TextDirection();

					var MergeCount = this.private_GetVertMergeCountOnPage(CurPage, RowIndex, CellInfo.StartGridCol, Cell.Get_GridSpan());
					if (MergeCount <= 0)
						continue;

					var LastRow = Math.min(RowIndex + MergeCount - 1, this.Pages[CurPage].LastRow);
					var Y_start = this.RowsInfo[RowIndex].Y[CurPage] + this.RowsInfo[RowIndex].TopDy[CurPage] + CellMar.Top.W;
					var Y_end   = this.TableRowsBottom[LastRow][CurPage] - CellMar.Bottom.W;

					if (TextDirection === textdirection_BTLR)
					{
						var SelectionW = Math.min(X_end - X_start - CellMar.Left.W, Bounds.Bottom - Bounds.Top);
						this.DrawingDocument.AddPageSelection(PageAbs, X_start + CellMar.Left.W + Y_offset, Y_start, SelectionW, Y_end - Y_start);
					}
					else if (TextDirection === textdirection_TBRL)
					{
						var SelectionW = Math.min(X_end - X_start - CellMar.Right.W, Bounds.Bottom - Bounds.Top);
						this.DrawingDocument.AddPageSelection(PageAbs, X_end - CellMar.Right.W - Y_offset - SelectionW, Y_start, SelectionW, Y_end - Y_start);
					}
				}
				else
				{
					this.DrawingDocument.AddPageSelection(PageAbs, X_start, this.RowsInfo[RowIndex].Y[CurPage] + this.RowsInfo[RowIndex].TopDy[CurPage] + CellMar.Top.W + Y_offset, X_end - X_start, Bounds.Bottom - Bounds.Top);
				}
			}
			break;
		}
		case table_Selection_Text:
		{
			var Cell         = this.Content[this.Selection.StartPos.Pos.Row].Get_Cell(this.Selection.StartPos.Pos.Cell);
			var Cell_PageRel = CurPage - Cell.Content.Get_StartPage_Relative();
			Cell.Content_DrawSelectionOnPage(Cell_PageRel);
			break;
		}
	}
};
CTable.prototype.RemoveSelection = function()
{
	if (false === this.Selection.Use)
		return;

	if (this.Content.length <= 0)
	{
		this.CurCell = null;
	}
	else
	{
		if (table_Selection_Text === this.Selection.Type)
		{
			this.CurCell = this.Content[this.Selection.StartPos.Pos.Row].Get_Cell(this.Selection.StartPos.Pos.Cell);
			this.CurCell.Content.RemoveSelection();
		}
		else if (this.Content.length > 0 && this.Content[0].Get_CellsCount() > 0)
		{
			this.CurCell = this.Content[0].Get_Cell(0);
			this.CurCell.Content.RemoveSelection();
		}
	}

	this.Selection.Use   = false;
	this.Selection.Start = false;

	this.Selection.StartPos.Pos = {Row : 0, Cell : 0};
	this.Selection.EndPos.Pos   = {Row : 0, Cell : 0};

	this.Markup.Internal.RowIndex  = 0;
	this.Markup.Internal.CellIndex = 0;
	this.Markup.Internal.PageNum   = 0;
};
CTable.prototype.CheckPosInSelection = function(X, Y, CurPage, NearPos)
{
	if (undefined != NearPos)
	{
		if ((true === this.Selection.Use && table_Selection_Cell === this.Selection.Type) || true === this.ApplyToAll)
		{
			var Cells_array = this.Internal_Get_SelectionArray();
			for (var Index = 0; Index < Cells_array.length; Index++)
			{
				var CurPos      = Cells_array[Index];
				var CurCell     = this.Content[CurPos.Row].Get_Cell(CurPos.Cell);
				var CellContent = CurCell.Content;

				CellContent.Set_ApplyToAll(true);

				if (true === CellContent.CheckPosInSelection(0, 0, 0, NearPos))
				{
					CellContent.Set_ApplyToAll(false);
					return true;
				}

				CellContent.Set_ApplyToAll(false);
			}
		}
		else
			return this.CurCell.Content_CheckPosInSelection(0, 0, 0, NearPos);

		return false;
	}
	else
	{
		if (CurPage < 0 || CurPage >= this.Pages.length)
			return false;

		var oHitInfo = this.private_CheckHitInBorder(X, Y, CurPage);
		if (oHitInfo.CellSelection || oHitInfo.RowSelection || oHitInfo.ColumnSelection)
			return false;

		var CellPos = this.Internal_GetCellByXY(X, Y, CurPage);
		if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		{
			for (var Index = 0; Index < this.Selection.Data.length; Index++)
			{
				var CurPos = this.Selection.Data[Index];

				if (CurPos.Cell === CellPos.Cell && CurPos.Row === CellPos.Row)
					return true;
			}

			return false;
		}
		else if (CellPos.Cell === this.CurCell.Index && CellPos.Row === this.CurCell.Row.Index)
			return this.CurCell.Content_CheckPosInSelection(X, Y, CurPage - this.CurCell.Content.Get_StartPage_Relative(), undefined);

		return false;
	}
};
CTable.prototype.IsSelectionEmpty = function(bCheckHidden)
{
	if (true === this.Selection.Use)
	{
		if (table_Selection_Cell === this.Selection.Type)
			return false;
		else
			return this.CurCell.Content.IsSelectionEmpty(bCheckHidden);
	}

	return true;
};
CTable.prototype.SelectAll = function(nDirection)
{
	this.Selection.Use   = true;
	this.Selection.Start = false;
	this.Selection.Type  = table_Selection_Cell;
	this.Selection.Type2 = table_Selection_Common;

	this.Selection.Data2 = null;

	if (nDirection && nDirection < 0)
	{
		this.Selection.EndPos.Pos       = {
			Row  : 0,
			Cell : 0
		};
		this.Selection.EndPos.PageIndex = 0;

		this.Selection.StartPos.Pos       = {
			Row  : this.Content.length - 1,
			Cell : this.Content[this.Content.length - 1].Get_CellsCount() - 1
		};
		this.Selection.StartPos.PageIndex = this.Pages.length - 1;
	}
	else
	{
		this.Selection.StartPos.Pos       = {
			Row  : 0,
			Cell : 0
		};
		this.Selection.StartPos.PageIndex = 0;

		this.Selection.EndPos.Pos       = {
			Row  : this.Content.length - 1,
			Cell : this.Content[this.Content.length - 1].Get_CellsCount() - 1
		};
		this.Selection.EndPos.PageIndex = this.Pages.length - 1;
	}

	this.private_UpdateSelectedCellsArray();
};
/**
 * В данной функции проверяется идет ли выделение таблицы до конца таблицы.
 */
CTable.prototype.IsSelectionToEnd = function()
{
	if (true === this.ApplyToAll || (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		var Len         = Cells_array.length;

		if (Len < 1)
			return false;

		var Pos = Cells_array[Len - 1];
		if (Pos.Row !== this.Content.length - 1 || Pos.Cell !== this.Content[Pos.Row].Get_CellsCount() - 1)
			return false;

		return true;
	}
	else
		return false;
};
CTable.prototype.SetSelectionUse = function(isUse)
{
	if (true === isUse)
		this.Selection.Use = true;
	else
		this.RemoveSelection();
};
CTable.prototype.SetSelectionToBeginEnd = function(isSelectionStart, isElementStart)
{
	var Pos;
	if (false === isElementStart)
	{
		var Row  = this.Content.length - 1;
		var Cell = this.Content[Row].Get_CellsCount() - 1;

		Pos = {Row : Row, Cell : Cell};
	}
	else
	{
		Pos = {Row : 0, Cell : 0};
	}

	if (isSelectionStart)
		this.Selection.StartPos.Pos = Pos;
	else
		this.Selection.EndPos.Pos = Pos;


	this.private_UpdateSelectedCellsArray();
};
CTable.prototype.MoveCursorToStartPos = function(AddToSelect)
{
	if (true === AddToSelect)
	{
		var StartRow = ( true === this.Selection.Use ? this.Selection.StartPos.Pos.Row : this.CurCell.Row.Index );
		var EndRow   = 0;

		this.Selection.Use          = true;
		this.Selection.Start        = false;
		this.Selection.Type         = table_Selection_Cell;
		this.Selection.Type2        = table_Selection_Common;
		this.Selection.StartPos.Pos = {Row : StartRow, Cell : this.Content[StartRow].Get_CellsCount() - 1};
		this.Selection.EndPos.Pos   = {Row : EndRow, Cell : 0};
		this.Selection.CurRow       = EndRow;

		this.private_UpdateSelectedCellsArray();
	}
	else
	{
		this.CurCell = this.Content[0].Get_Cell(0);

		this.Selection.Use          = false;
		this.Selection.Start        = false;
		this.Selection.StartPos.Pos = {Row : 0, Cell : 0};
		this.Selection.EndPos.Pos   = {Row : 0, Cell : 0};
		this.Selection.CurRow       = 0;

		this.CurCell.Content_MoveCursorToStartPos();
	}
};
CTable.prototype.MoveCursorToEndPos = function(AddToSelect)
{
	if (true === AddToSelect)
	{
		var StartRow = ( true === this.Selection.Use ? this.Selection.StartPos.Pos.Row : this.CurCell.Row.Index );
		var EndRow   = this.Content.length - 1;

		this.Selection.Use          = true;
		this.Selection.Start        = false;
		this.Selection.Type         = table_Selection_Cell;
		this.Selection.Type2        = table_Selection_Common;
		this.Selection.StartPos.Pos = {Row : StartRow, Cell : 0};
		this.Selection.EndPos.Pos   = {Row : EndRow, Cell : this.Content[EndRow].Get_CellsCount() - 1};
		this.Selection.CurRow       = EndRow;

		this.private_UpdateSelectedCellsArray();
	}
	else
	{
		var Row      = this.Content[this.Content.length - 1];
		this.CurCell = Row.Get_Cell(Row.Get_CellsCount() - 1);

		this.Selection.Use          = false;
		this.Selection.Start        = false;
		this.Selection.StartPos.Pos = {Row : Row.Index, Cell : this.CurCell.Index};
		this.Selection.EndPos.Pos   = {Row : Row.Index, Cell : this.CurCell.Index};
		this.Selection.CurRow       = Row.Index;

		this.CurCell.Content_MoveCursorToEndPos();
	}
};
CTable.prototype.IsCursorAtBegin = function(bOnlyPara)
{
	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
	{
		if (0 === this.CurCell.Index && 0 === this.CurCell.Row.Index)
		{
			return this.CurCell.Content.IsCursorAtBegin(bOnlyPara);
		}
	}

	return false;
};
CTable.prototype.IsCursorAtEnd = function()
{
	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
	{
		if (0 === this.CurCell.Index && 0 === this.CurCell.Row.Index)
		{
			return this.CurCell.Content.IsCursorAtEnd();
		}
	}

	return false;
};
//----------------------------------------------------------------------------------------------------------------------
// Работаем с содержимым таблицы
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.AddNewParagraph = function()
{
	this.CurCell.Content.AddNewParagraph();
};
CTable.prototype.AddInlineImage = function(W, H, Img, Chart, bFlow)
{
	this.Selection.Use  = true;
	this.Selection.Type = table_Selection_Text;
	this.CurCell.Content.AddInlineImage(W, H, Img, Chart, bFlow);
};
CTable.prototype.AddImages = function(aImages)
{
	this.Selection.Use  = true;
	this.Selection.Type = table_Selection_Text;
	this.CurCell.Content.AddImages(aImages);
};
CTable.prototype.AddSignatureLine = function(oSignatureDrawing)
{
	this.Selection.Use  = true;
	this.Selection.Type = table_Selection_Text;
	this.CurCell.Content.AddSignatureLine(oSignatureDrawing);
};
CTable.prototype.AddOleObject = function(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId)
{
	this.Selection.Use  = true;
	this.Selection.Type = table_Selection_Text;
	this.CurCell.Content.AddOleObject(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId);
};
CTable.prototype.AddTextArt = function(nStyle)
{
	this.Selection.Use  = true;
	this.Selection.Type = table_Selection_Text;
	this.CurCell.Content.AddTextArt(nStyle);
};
CTable.prototype.AddInlineTable = function(Cols, Rows)
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		return;

	this.CurCell.Content.AddInlineTable(Cols, Rows);
};
CTable.prototype.Add = function(ParaItem, bRecalculate)
{
	this.AddToParagraph(ParaItem, bRecalculate);
};
CTable.prototype.AddToParagraph = function(ParaItem, bRecalculate)
{
	if (para_TextPr === ParaItem.Type && ( true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ) ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.AddToParagraph(ParaItem, bRecalculate);
			Cell_Content.Set_ApplyToAll(false);
		}

		// Если в TextPr только HighLight, тогда не надо ничего пересчитывать, только перерисовываем
		if (true === ParaItem.Value.Check_NeedRecalc())
		{
			if (Cells_array[0].Row - 1 >= 0)
				this.Internal_RecalculateFrom(Cells_array[0].Row - 1, 0, true, true);
			else
			{
				this.Internal_Recalculate_1();
			}
		}
		else
		{
			this.Parent.OnContentReDraw(this.Get_AbsolutePage(0), this.Get_AbsolutePage(this.Pages.length - 1));
		}
	}
	else
	{
		this.CurCell.Content.AddToParagraph(ParaItem, bRecalculate);
	}
};
CTable.prototype.ClearParagraphFormatting = function(isClearParaPr, isClearTextPr)
{
	if (true === this.ApplyToAll || (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.ClearParagraphFormatting(isClearParaPr, isClearTextPr);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		this.CurCell.Content.ClearParagraphFormatting(isClearParaPr, isClearTextPr);
	}
};
CTable.prototype.PasteFormatting = function(TextPr, ParaPr, ApplyPara)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.PasteFormatting(TextPr, ParaPr, true);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		this.CurCell.Content.PasteFormatting(TextPr, ParaPr, false);
	}
};
CTable.prototype.Remove = function(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();

		if (true === bOnTextAdd && Cells_array.length > 0)
		{
			// Снимаем выделением со всех ячеек, кроме первой, попавшей в выделение
			var Pos  = Cells_array[0];
			var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
			Cell.Content.SelectAll();
			Cell.Content.Remove(Count, bOnlyText, bRemoveOnlySelection, true);

			this.CurCell = Cell;

			this.Selection.Use   = false;
			this.Selection.Start = false;

			this.Selection.StartPos.Pos = {Row : Cell.Row.Index, Cell : Cell.Index};
			this.Selection.EndPos.Pos   = {Row : Cell.Row.Index, Cell : Cell.Index};

			this.Document_SetThisElementCurrent(true);

			editor.WordControl.m_oLogicDocument.Recalculate();
		}
		else
		{
			var Cells_array = this.Internal_Get_SelectionArray();
			for (var Index = 0; Index < Cells_array.length; Index++)
			{
				var Pos  = Cells_array[Index];
				var Row  = this.Content[Pos.Row];
				var Cell = Row.Get_Cell(Pos.Cell);

				var Cell_Content = Cell.Content;
				Cell_Content.Set_ApplyToAll(true);
				Cell.Content.Remove(Count, bOnlyText, bRemoveOnlySelection, false);
				Cell_Content.Set_ApplyToAll(false);
			}

			// Снимаем выделение
			var Pos      = Cells_array[0];
			var Cell     = this.Content[Pos.Row].Get_Cell(Pos.Cell);
			this.CurCell = Cell;

			this.Selection.Use   = false;
			this.Selection.Start = false;

			this.Selection.StartPos.Pos = {Row : Cell.Row.Index, Cell : Cell.Index};
			this.Selection.EndPos.Pos   = {Row : Cell.Row.Index, Cell : Cell.Index};

			if (Cells_array[0].Row - 1 >= 0)
				this.Internal_RecalculateFrom(Cells_array[0].Row - 1, 0, true, true);
			else
			{
				this.Internal_Recalculate_1();
			}
		}
	}
	else
	{
		this.CurCell.Content.Remove(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd);

		if (false === this.CurCell.Content.IsSelectionUse())
		{
			var Cell = this.CurCell;

			this.Selection.Use   = false;
			this.Selection.Start = false;

			this.Selection.StartPos.Pos = {Row : Cell.Row.Index, Cell : Cell.Index};
			this.Selection.EndPos.Pos   = {Row : Cell.Row.Index, Cell : Cell.Index};
		}
	}
};
CTable.prototype.GetCursorPosXY = function()
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		if (this.Selection.Data.length < 0)
			return {X : 0, Y : 0};

		var Pos  = this.Selection.Data[0];
		var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
		var Para = Cell.Content.Get_FirstParagraph();

		return {X : Para.X, Y : Para.Y}
	}
	else
		return this.CurCell.Content.GetCursorPosXY();
};
CTable.prototype.MoveCursorLeft = function(AddToSelect, Word)
{
	if (true === this.Selection.Use && this.Selection.Type === table_Selection_Cell)
	{
		if (true === AddToSelect)
		{
			var StartPos = this.Selection.StartPos.Pos;
			var EndPos   = this.Selection.EndPos.Pos;

			if (StartPos.Cell == EndPos.Cell && StartPos.Row == EndPos.Row && this.Parent.IsSelectedSingleElement())
			{
				// Если была выделена одна ячейка, тогда мы убираем выделение по ячейкам
				this.Selection.Type = table_Selection_Text;
				return true;
			}
			else
			{
				// Если текущая ячейка - первая в первой строке и данная таблица - первый элемент, тогда мы ничего не
				// делаем
				if (0 == EndPos.Cell && 0 == EndPos.Row && ( null === this.Get_DocumentPrev() && true === this.Parent.Is_TopDocument() ))
					return false;

				// Если текущая ячейка - первая в первой строке (и таблица не первый элемент документа),
				// тогда мы выделаяем первую строку

				var bRet = true;
				if (0 == EndPos.Cell && 0 == EndPos.Row || ( !this.Parent.IsSelectedSingleElement() && 0 == EndPos.Row && 0 == StartPos.Row ))
				{
					this.Selection.EndPos.Pos = {Cell : 0, Row : 0};
					bRet                      = false;
				}
				else if (EndPos.Cell > 0 && this.Parent.IsSelectedSingleElement())
					this.Selection.EndPos.Pos = {Cell : EndPos.Cell - 1, Row : EndPos.Row};
				else
					this.Selection.EndPos.Pos = {Cell : 0, Row : EndPos.Row - 1};

				var bForceSelectByLines = false;
				if (false === bRet && true == this.Is_Inline())
					bForceSelectByLines = true;

				this.private_UpdateSelectedCellsArray(bForceSelectByLines);

				return bRet;
			}
		}
		else
		{
			// Перемещаем курсор в начало первой выделенной ячейки
			this.Selection.Use = false;
			var Pos            = this.Selection.Data[0];
			this.CurCell       = this.Content[Pos.Row].Get_Cell(Pos.Cell);
			this.CurCell.Content_MoveCursorToStartPos();
			return true;
		}
	}
	else
	{
		if (false === this.CurCell.Content.MoveCursorLeft(AddToSelect, Word))
		{
			if (false === AddToSelect)
			{
				var nCurCell = this.CurCell.GetIndex();
				var nCurRow  = this.CurCell.GetRow().GetIndex();
				if (0 !== nCurCell || 0 !== nCurRow)
				{
					while (true)
					{
						if (nCurCell > 0)
						{
							nCurCell--;
						}
						else if (nCurRow > 0)
						{
							nCurRow--;
							nCurCell = this.GetRow(nCurRow).GetCellsCount() - 1;
						}
						else
						{
							this.CurCell = this.GetRow(0).GetCell(0);
							break;
						}

						var oTempCell = this.GetRow(nCurRow).GetCell(nCurCell);
						if (vmerge_Restart !== oTempCell.GetVMerge())
							continue;

						this.CurCell = oTempCell;
						break;
					}

					this.CurCell.Content.MoveCursorToEndPos();
				}
				else
				{
					return false;
				}
			}
			else
			{
				// Если текущая ячейка - первая в первой строке и данная таблица - первый элемент, тогда мы ничего не
				// делаем
				if (0 == this.CurCell.Index && 0 == this.CurCell.Row.Index && ( null === this.Get_DocumentPrev() && true === this.Parent.Is_TopDocument() ))
					return false;

				this.Selection.Use  = true;
				this.Selection.Type = table_Selection_Cell;

				// Если текущая ячейка - первая в первой строке (и таблица не первый элемент документа),
				// тогда мы выделаяем первую строку

				var bRet                    = true;
				this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};

				if (0 == this.CurCell.Index && 0 == this.CurCell.Row.Index)
				{
					this.Selection.EndPos.Pos = {Cell : this.CurCell.Row.Get_CellsCount() - 1, Row : 0};
					bRet                      = false;
				}
				else if (this.CurCell.Index > 0)
					this.Selection.EndPos.Pos = {Cell : this.CurCell.Index - 1, Row : this.CurCell.Row.Index};
				else
					this.Selection.EndPos.Pos = {Cell : 0, Row : this.CurCell.Row.Index - 1};

				this.private_UpdateSelectedCellsArray();

				return bRet;
			}
		}
		else
		{
			if (true === AddToSelect)
			{
				this.Selection.Use          = true;
				this.Selection.Type         = table_Selection_Text;
				this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
				this.Selection.EndPos.Pos   = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
			}

			return true;
		}
	}
};
CTable.prototype.MoveCursorLeftWithSelectionFromEnd = function(Word)
{
	if (true === this.IsSelectionUse())
		this.RemoveSelection();

	if (this.Content.length <= 0)
		return;

	var LastRow = this.Content[this.Content.length - 1];

	// Нам нужно выделить последний ряд таблицы

	this.Selection.Use          = true;
	this.Selection.Type         = table_Selection_Cell;
	this.Selection.StartPos.Pos = {
		Row  : LastRow.Index,
		Cell : LastRow.Get_CellsCount() - 1
	};
	this.Selection.EndPos.Pos   = {
		Row  : LastRow.Index,
		Cell : 0
	};
	this.CurCell                = LastRow.Get_Cell(0);
	this.Selection.Data         = [];

	for (var CellIndex = 0; CellIndex < LastRow.Get_CellsCount(); CellIndex++)
	{
		this.Selection.Data.push({Cell : CellIndex, Row : LastRow.Index});
	}
};
CTable.prototype.MoveCursorRight = function(AddToSelect, Word, FromPaste)
{
	if (true === this.Selection.Use && this.Selection.Type === table_Selection_Cell)
	{
		if (true === AddToSelect)
		{
			var StartPos = this.Selection.StartPos.Pos;
			var EndPos   = this.Selection.EndPos.Pos;

			if (StartPos.Cell == EndPos.Cell && StartPos.Row == EndPos.Row && this.Parent.IsSelectedSingleElement())
			{
				// Если была выделена одна ячейка, тогда мы убираем выделение по ячейкам
				this.Selection.Type = table_Selection_Text;
				return true;
			}
			else
			{
				// Если текущая ячейка - последняя в последней строке, тогда мы выделаяем последнюю строку
				var oLastRow = this.GetRow(this.GetRowsCount() - 1);
				var oEndRow  = this.GetRow(EndPos.Row);

				var bRet = true;

				if (EndPos.Cell < oEndRow.GetCellsCount() - 1 && this.Parent.IsSelectedSingleElement())
				{
					this.Selection.EndPos.Pos = {
						Cell : EndPos.Cell + 1,
						Row  : EndPos.Row
					};
				}
				else if (this.GetRowsCount() - 1 <= EndPos.Row)
				{
					this.Selection.EndPos.Pos = {
						Cell : oLastRow.GetCellsCount() - 1,
						Row  : oLastRow.Index
					};

					bRet = false;
				}
				else
				{
					this.Selection.EndPos.Pos = {
						Cell : this.GetRow(EndPos.Row + 1).GetCellsCount() - 1,
						Row  : EndPos.Row + 1
					};
				}

				var bForceSelectByLines = false;
				if (false === bRet && true == this.Is_Inline())
					bForceSelectByLines = true;

				this.private_UpdateSelectedCellsArray(bForceSelectByLines);

				return bRet;
			}
		}
		else
		{
			// Перемещаем курсор в конец последней выделенной ячейки
			this.Selection.Use = false;
			var Pos            = this.Selection.Data[this.Selection.Data.length - 1];
			this.CurCell       = this.Content[Pos.Row].Get_Cell(Pos.Cell);
			this.CurCell.Content_MoveCursorToEndPos();
			return true;
		}
	}
	else
	{
		if (false === this.CurCell.Content.MoveCursorRight(AddToSelect, Word, FromPaste))
		{
			if (false === AddToSelect)
			{
				var nCurCell    = this.CurCell.GetIndex();
				var nCurRow     = this.CurCell.GetRow().GetIndex();
				var nCellsCount = this.GetRow(nCurRow).GetCellsCount();
				var nRowsCount  = this.GetRowsCount();
				if (this.Content.length - 1 > nCurRow || nCellsCount - 1 > nCurCell)
				{
					while (true)
					{
						if (nCurCell < nCellsCount - 1)
						{
							nCurCell++;
						}
						else if (nCurRow < nRowsCount - 1)
						{
							nCurRow++;
							nCurCell = 0;
							nCellsCount = this.GetRow(nCurRow).GetCellsCount();
						}
						else
						{
							var oLastRow = this.GetRow(this.GetRowsCount() - 1);
							this.CurCell = oLastRow.GetCell(oLastRow.GetCellsCount() - 1);
							break;
						}

						var oTempCell = this.GetRow(nCurRow).GetCell(nCurCell);
						if (vmerge_Restart !== oTempCell.GetVMerge())
							continue;

						this.CurCell = oTempCell;
						break;
					}

					this.CurCell.Content.MoveCursorToStartPos();
				}
				else
				{
					return false;
				}
			}
			else
			{
				this.Selection.Use  = true;
				this.Selection.Type = table_Selection_Cell;

				// Если текущая ячейка - последняя в последней строке, тогда мы выделаяем последнюю строку
				var oLastRow = this.GetRow(this.GetRowsCount() - 1);
				var oCurRow  = this.CurCell.Row;

				this.Selection.StartPos.Pos = {
					Cell : this.CurCell.Index,
					Row  : this.CurCell.Row.Index
				};

				var bRet = true;

				if (this.CurCell.Index < oCurRow.Get_CellsCount() - 1)
				{
					this.Selection.EndPos.Pos = {
						Cell : this.CurCell.Index + 1,
						Row  : this.CurCell.Row.Index
					};
				}
				else if (this.CurCell.Row.Index >= this.GetRowsCount() - 1)
				{
					this.Selection.EndPos.Pos = {
						Cell : oLastRow.GetCellsCount() - 1,
						Row  : oLastRow.Index
					};

					bRet = false;
				}
				else
				{
					this.Selection.EndPos.Pos = {
						Cell : this.GetRow(this.CurCell.Row.Index + 1).GetCellsCount() - 1,
						Row  : this.CurCell.Row.Index + 1
					};
				}

				var bForceSelectByLines = false;
				if (false === bRet && true == this.Is_Inline())
					bForceSelectByLines = true;

				this.private_UpdateSelectedCellsArray(bForceSelectByLines);

				return bRet;
			}
		}
		else
		{
			if (true === AddToSelect)
			{
				this.Selection.Use          = true;
				this.Selection.Type         = table_Selection_Text;
				this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
				this.Selection.EndPos.Pos   = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};

			}

			return true;
		}
	}
};
CTable.prototype.MoveCursorRightWithSelectionFromStart = function(Word)
{
	if (true === this.IsSelectionUse())
		this.RemoveSelection();

	if (this.Content.length <= 0)
		return;

	var FirstRow = this.Content[0];

	// Нам нужно выделить первый ряд таблицы
	this.Selection.Use          = true;
	this.Selection.Type         = table_Selection_Cell;
	this.Selection.StartPos.Pos = {
		Row  : 0,
		Cell : 0
	};
	this.Selection.EndPos.Pos   = {
		Row  : 0,
		Cell : FirstRow.Get_CellsCount() - 1
	};
	this.CurCell                = FirstRow.Get_Cell(FirstRow.Get_CellsCount() - 1);
	this.Selection.Data         = [];

	for (var CellIndex = 0; CellIndex < FirstRow.Get_CellsCount(); CellIndex++)
	{
		this.Selection.Data.push({Cell : CellIndex, Row : 0});
	}
};
CTable.prototype.MoveCursorUp = function(AddToSelect)
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		if (true === AddToSelect)
		{
			var bRetValue = true;
			var EndPos    = this.Selection.EndPos.Pos;
			if (0 === EndPos.Row)
			{
				bRetValue = false;
			}
			else
			{
				var EndCell = this.Content[EndPos.Row].Get_Cell(EndPos.Cell);

				var X = EndCell.Content_GetCurPosXY().X;
				var Y = EndCell.Content_GetCurPosXY().Y;

				var PrevRow = this.Content[EndPos.Row - 1];
				var Cell    = null;
				for (var CurCell = 0; CurCell < PrevRow.Get_CellsCount(); CurCell++)
				{
					Cell         = PrevRow.Get_Cell(CurCell);
					var CellInfo = PrevRow.Get_CellInfo(CurCell);
					if (X <= CellInfo.X_grid_end)
						break;
				}

				if (null === Cell)
					return true;

				Cell.Content_SetCurPosXY(X, Y);
				this.CurCell              = Cell;
				this.Selection.EndPos.Pos = {Cell : Cell.Index, Row : Cell.Row.Index};
			}

			var bForceSelectByLines = false;
			if (false === bRetValue && true === this.Is_Inline())
				bForceSelectByLines = true;

			this.private_UpdateSelectedCellsArray(bForceSelectByLines);
			return bRetValue;
		}
		else
		{
			if (this.Selection.Data.length < 0)
				return true;

			var Pos  = this.Selection.Data[0];
			var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
			var Para = Cell.Content.Get_FirstParagraph();
			var X    = Para.X;
			var Y    = Para.Y;

			this.Selection.Use = false;
			if (0 === Pos.Row)
			{
				this.CurCell = Cell;
				this.CurCell.Content.MoveCursorToStartPos();
				this.CurCell.Content_SetCurPosXY(X, Y);

				return false;
			}
			else
			{
				var PrevRow  = this.Content[Pos.Row - 1];
				var PrevCell = null;
				for (var CurCell = 0; CurCell < PrevRow.Get_CellsCount(); CurCell++)
				{
					PrevCell     = PrevRow.Get_Cell(CurCell);
					var CellInfo = PrevRow.Get_CellInfo(CurCell);
					if (X <= CellInfo.X_grid_end)
						break;
				}

				if (null === PrevCell)
					return true;

				PrevCell.Content_MoveCursorUpToLastRow(X, Y, false);
				this.CurCell = PrevCell;
				return true;
			}

		}
	}
	else
	{
		if (false === this.CurCell.Content.MoveCursorUp(AddToSelect))
		{
			// Ничего не делаем, если это "плавающая" таблица или первый элемент документа
			if (0 === this.CurCell.Row.Index && (false === this.Is_Inline() || ( null === this.Get_DocumentPrev() && true === this.Parent.Is_TopDocument() )))
				return true;

			if (true === AddToSelect)
			{
				this.Selection.Use          = true;
				this.Selection.Type         = table_Selection_Cell;
				this.Selection.StartPos.Pos = {Row : this.CurCell.Row.Index, Cell : this.CurCell.Index};

				var bRetValue = true;
				if (0 === this.CurCell.Row.Index)
				{
					this.Selection.EndPos.Pos = {Row : 0, Cell : 0};
					bRetValue                 = false;
				}
				else
				{
					var X       = this.CurCell.Content_GetCurPosXY().X;
					var Y       = this.CurCell.Content_GetCurPosXY().Y;
					var PrevRow = this.Content[this.CurCell.Row.Index - 1];
					var Cell    = null;
					for (var CurCell = 0; CurCell < PrevRow.Get_CellsCount(); CurCell++)
					{
						Cell         = PrevRow.Get_Cell(CurCell);
						var CellInfo = PrevRow.Get_CellInfo(CurCell);
						if (X <= CellInfo.X_grid_end)
							break;
					}

					if (null === Cell)
						return true;

					Cell.Content_SetCurPosXY(X, Y);
					this.CurCell              = Cell;
					this.Selection.EndPos.Pos = {Cell : Cell.Index, Row : Cell.Row.Index};
				}

				var bForceSelectByLines = false;
				if (false === bRetValue && true === this.Is_Inline())
					bForceSelectByLines = true;

				this.private_UpdateSelectedCellsArray(bForceSelectByLines);
				return bRetValue;
			}
			else
			{
				if (0 === this.CurCell.Row.Index)
					return false;
				else
				{
					var X       = this.CurCell.Content_GetCurPosXY().X;
					var Y       = this.CurCell.Content_GetCurPosXY().Y;
					var PrevRow = this.Content[this.CurCell.Row.Index - 1];
					var Cell    = null;
					for (var CurCell = 0; CurCell < PrevRow.Get_CellsCount(); CurCell++)
					{
						Cell         = PrevRow.Get_Cell(CurCell);
						var CellInfo = PrevRow.Get_CellInfo(CurCell);
						if (X <= CellInfo.X_grid_end)
							break;
					}

					if (null === Cell)
						return true;

					Cell = this.Internal_Get_StartMergedCell2(Cell.Index, Cell.Row.Index);
					Cell.Content_MoveCursorUpToLastRow(X, Y, false);
					this.CurCell              = Cell;
					this.Selection.EndPos.Pos = {Cell : Cell.Index, Row : Cell.Row.Index};
					this.Selection.CurRow     = Cell.Row.Index;

					return true;
				}
			}
		}
		else
		{
			if (true === AddToSelect)
			{
				this.Selection.Use          = true;
				this.Selection.Type         = table_Selection_Text;
				this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
				this.Selection.EndPos.Pos   = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
			}

			return true;
		}
	}
};
CTable.prototype.MoveCursorDown = function(AddToSelect)
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		if (true === AddToSelect)
		{
			var bRetValue = true;
			var EndPos    = this.Selection.EndPos.Pos;
			if (this.Content.length - 1 === EndPos.Row)
			{
				bRetValue = false;
			}
			else
			{
				var EndCell = this.Content[EndPos.Row].Get_Cell(EndPos.Cell);

				var X = EndCell.Content_GetCurPosXY().X;
				var Y = EndCell.Content_GetCurPosXY().Y;

				var NextRow = this.Content[EndPos.Row + 1];
				var Cell    = null;
				for (var CurCell = 0; CurCell < NextRow.Get_CellsCount(); CurCell++)
				{
					Cell         = NextRow.Get_Cell(CurCell);
					var CellInfo = NextRow.Get_CellInfo(CurCell);
					if (X <= CellInfo.X_grid_end)
						break;
				}

				if (null === Cell)
					return true;

				Cell.Content_SetCurPosXY(X, Y);
				this.CurCell              = Cell;
				this.Selection.EndPos.Pos = {Cell : Cell.Index, Row : Cell.Row.Index};
			}

			var bForceSelectByLines = false;
			if (false === bRetValue && true === this.Is_Inline())
				bForceSelectByLines = true;

			this.private_UpdateSelectedCellsArray(bForceSelectByLines);
			return bRetValue;
		}
		else
		{
			if (this.Selection.Data.length < 0)
				return true;

			var Pos  = this.Selection.Data[this.Selection.Data.length - 1];
			var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
			var Para = Cell.Content.Get_FirstParagraph();
			var X    = Para.X;
			var Y    = Para.Y;

			this.Selection.Use = false;
			if (this.Content.length - 1 === Pos.Row)
			{
				this.CurCell = Cell;
				this.CurCell.Content.MoveCursorToStartPos();
				this.CurCell.Content_SetCurPosXY(X, Y);

				return false;
			}
			else
			{
				var NextRow  = this.Content[Pos.Row + 1];
				var NextCell = null;
				for (var CurCell = 0; CurCell < NextRow.Get_CellsCount(); CurCell++)
				{
					NextCell     = NextRow.Get_Cell(CurCell);
					var CellInfo = NextRow.Get_CellInfo(CurCell);
					if (X <= CellInfo.X_grid_end)
						break;
				}

				if (null === NextCell)
					return true;

				NextCell.Content_MoveCursorDownToFirstRow(X, Y, false);
				this.CurCell = NextCell;
				return true;
			}

		}
	}
	else
	{
		if (false === this.CurCell.Content.MoveCursorDown(AddToSelect))
		{
			if (true === AddToSelect)
			{
				this.Selection.Use          = true;
				this.Selection.Type         = table_Selection_Cell;
				this.Selection.StartPos.Pos = {Row : this.CurCell.Row.Index, Cell : this.CurCell.Index};

				var bRetValue = true;
				if (this.Content.length - 1 === this.CurCell.Row.Index)
				{
					this.Selection.EndPos.Pos = {
						Row  : this.Content.length - 1,
						Cell : this.Content[this.Content.length - 1].Get_CellsCount() - 1
					};
					bRetValue                 = false;
				}
				else
				{
					var X       = this.CurCell.Content_GetCurPosXY().X;
					var Y       = this.CurCell.Content_GetCurPosXY().Y;
					var NextRow = this.Content[this.CurCell.Row.Index + 1];
					var Cell    = null;
					for (var CurCell = 0; CurCell < NextRow.Get_CellsCount(); CurCell++)
					{
						Cell         = NextRow.Get_Cell(CurCell);
						var CellInfo = NextRow.Get_CellInfo(CurCell);
						if (X <= CellInfo.X_grid_end)
							break;
					}

					if (null === Cell)
						return true;

					Cell.Content_SetCurPosXY(X, Y);
					this.CurCell              = Cell;
					this.Selection.EndPos.Pos = {Cell : Cell.Index, Row : Cell.Row.Index};
				}

				var bForceSelectByLines = false;
				if (false === bRetValue && true === this.Is_Inline())
					bForceSelectByLines = true;

				this.private_UpdateSelectedCellsArray(bForceSelectByLines);
				return bRetValue;
			}
			else
			{
				var VMerge_count = this.Internal_GetVertMergeCount(this.CurCell.Row.Index, this.CurCell.Row.Get_CellInfo(this.CurCell.Index).StartGridCol, this.CurCell.Get_GridSpan());

				if (this.Content.length - 1 === this.CurCell.Row.Index + VMerge_count - 1)
					return false;
				else
				{
					var X = this.CurCell.Content_GetCurPosXY().X;
					var Y = this.CurCell.Content_GetCurPosXY().Y;

					var NextRow = this.Content[this.CurCell.Row.Index + VMerge_count];
					var Cell    = null;
					for (var CurCell = 0; CurCell < NextRow.Get_CellsCount(); CurCell++)
					{
						Cell         = NextRow.Get_Cell(CurCell);
						var CellInfo = NextRow.Get_CellInfo(CurCell);
						if (X <= CellInfo.X_grid_end)
							break;
					}

					if (null === Cell)
						return true;

					Cell.Content_MoveCursorDownToFirstRow(X, Y, false);
					this.CurCell              = Cell;
					this.Selection.EndPos.Pos = {Cell : Cell.Index, Row : Cell.Row.Index};
					this.Selection.CurRow     = Cell.Row.Index;

					return true;
				}
			}
		}
		else
		{
			if (true === AddToSelect)
			{
				this.Selection.Use          = true;
				this.Selection.Type         = table_Selection_Text;
				this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
				this.Selection.EndPos.Pos   = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
			}

			return true;
		}
	}
};
CTable.prototype.MoveCursorToEndOfLine = function(AddToSelect)
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		return this.MoveCursorRight(AddToSelect, false);
	else
	{
		var bRetValue = this.CurCell.Content.MoveCursorToEndOfLine(AddToSelect);
		if (true === this.CurCell.Content.IsSelectionUse())
		{
			this.Selection.Use          = true;
			this.Selection.Type         = table_Selection_Text;
			this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
			this.Selection.EndPos.Pos   = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
		}
		else
		{
			this.Selection.Use = false;
		}

		return bRetValue;
	}
};
CTable.prototype.MoveCursorToStartOfLine = function(AddToSelect)
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		return this.MoveCursorLeft(AddToSelect, false);
	else
	{
		var bRetValue = this.CurCell.Content.MoveCursorToStartOfLine(AddToSelect);
		if (true === this.CurCell.Content.IsSelectionUse())
		{
			this.Selection.Use          = true;
			this.Selection.Type         = table_Selection_Text;
			this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
			this.Selection.EndPos.Pos   = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
		}
		else
		{
			this.Selection.Use = false;
		}

		return bRetValue;
	}
};
CTable.prototype.MoveCursorUpToLastRow = function(X, Y, AddToSelect)
{
	if (true === AddToSelect)
	{
		if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		{
			var Row  = this.Content[this.Content.length - 1];
			var Cell = null;
			for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
			{
				Cell         = Row.Get_Cell(CurCell);
				var CellInfo = Row.Get_CellInfo(CurCell);
				if (X <= CellInfo.X_grid_end)
					break;
			}

			if (null === Cell)
				return true;

			Cell.Content_SetCurPosXY(X, Y);
			this.CurCell              = Cell;
			this.Selection.EndPos.Pos = {Cell : Cell.Index, Row : Cell.Row.Index};
			this.private_UpdateSelectedCellsArray();
		}
		else
		{
			this.Selection.Use          = true;
			this.Selection.Type         = table_Selection_Cell;
			this.Selection.StartPos.Pos = {
				Row  : this.Content.length - 1,
				Cell : this.Content[this.Content.length - 1].Get_CellsCount() - 1
			};
			this.Selection.EndPos.Pos   = {Row : this.Content.length - 1, Cell : 0};

			this.private_UpdateSelectedCellsArray();

			// У последней ячейки у первого параграфа, мы выставим RealX, RealY
			var Cell = this.Content[this.Content.length - 1].Get_Cell(0);
			Cell.Content_SetCurPosXY(X, Y);
		}
	}
	else
	{
		this.RemoveSelection();
		var Row  = this.Content[this.Content.length - 1];
		var Cell = null;
		for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
		{
			Cell         = Row.Get_Cell(CurCell);
			var CellInfo = Row.Get_CellInfo(CurCell);
			if (X <= CellInfo.X_grid_end)
				break;
		}

		if (null === Cell)
			return;
		Cell = this.Internal_Get_StartMergedCell2(Cell.Index, Cell.Row.Index);
		Cell.Content_MoveCursorUpToLastRow(X, Y, false);
		this.Selection.CurRow = Cell.Row.Index;

		this.CurCell = Cell;
	}
};
CTable.prototype.MoveCursorDownToFirstRow = function(X, Y, AddToSelect)
{
	if (true === AddToSelect)
	{
		if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		{
			var Row  = this.Content[0];
			var Cell = null;
			for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
			{
				Cell         = Row.Get_Cell(CurCell);
				var CellInfo = Row.Get_CellInfo(CurCell);
				if (X <= CellInfo.X_grid_end)
					break;
			}

			if (null === Cell)
				return true;

			Cell.Content_SetCurPosXY(X, Y);
			this.CurCell              = Cell;
			this.Selection.EndPos.Pos = {Cell : Cell.Index, Row : Cell.Row.Index};
			this.private_UpdateSelectedCellsArray();
		}
		else
		{
			this.Selection.Use          = true;
			this.Selection.Type         = table_Selection_Cell;
			this.Selection.StartPos.Pos = {Row : 0, Cell : 0};
			this.Selection.EndPos.Pos   = {Row : 0, Cell : this.Content[0].Get_CellsCount() - 1};

			this.private_UpdateSelectedCellsArray();

			// У последней ячейки у первого параграфа, мы выставим RealX, RealY
			var Cell = this.Content[0].Get_Cell(0);
			Cell.Content_SetCurPosXY(X, Y);
		}
	}
	else
	{
		this.RemoveSelection();
		var Row  = this.Content[0];
		var Cell = null;
		for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
		{
			Cell         = Row.Get_Cell(CurCell);
			var CellInfo = Row.Get_CellInfo(CurCell);
			if (X <= CellInfo.X_grid_end)
				break;
		}

		if (null === Cell)
			return;

		Cell.Content_MoveCursorDownToFirstRow(X, Y, false);
		this.Selection.CurRow = Cell.Row.Index;
		this.CurCell          = Cell;
	}
};
CTable.prototype.MoveCursorToCell = function(bNext)
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		var Pos             = this.Selection.Data[0];
		this.Selection.Type = table_Selection_Text;
		this.CurCell        = this.Content[Pos.Row].Get_Cell(Pos.Cell);
		this.CurCell.Content.SelectAll();
	}
	else
	{
		if (true === this.IsInnerTable())
			return this.CurCell.Content.MoveCursorToCell(bNext);

		var CurCell = this.CurCell;
		var Pos_c   = this.CurCell.Index;
		var Pos_r   = this.CurCell.Row.Index;
		var Pos     = {
			Cell : Pos_c,
			Row  : Pos_r
		};

		if (true === bNext)
		{
			var TempCell = this.Internal_Get_NextCell(Pos);
			while (null != TempCell && vmerge_Restart != TempCell.GetVMerge())
				TempCell = this.Internal_Get_NextCell(Pos);

			if (null != TempCell)
				CurCell = TempCell;
			else
			{
				if (false == editor.WordControl.m_oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_None, {
						Type      : AscCommon.changestype_2_Element_and_Type,
						Element   : this,
						CheckType : AscCommon.changestype_Table_Properties
					}))
				{
					History.Create_NewPoint(AscDFH.historydescription_Document_TableAddNewRowByTab);
					this.AddTableRow(false);
					this.LogicDocument.Recalculate();
				}
				else
					return;

				var TempCell = this.Internal_Get_NextCell(Pos);
				while (null != TempCell && vmerge_Restart != TempCell.GetVMerge())
					TempCell = this.Internal_Get_NextCell(Pos);

				if (null != TempCell)
					CurCell = TempCell;
			}
		}
		else
		{
			var TempCell = this.Internal_Get_PrevCell(Pos);
			while (null != TempCell && vmerge_Restart != TempCell.GetVMerge())
				TempCell = this.Internal_Get_PrevCell(Pos);

			if (null != TempCell)
				CurCell = TempCell;
		}

		// Предварительно очистим текущий селект
		editor.WordControl.m_oLogicDocument.RemoveSelection();

		this.CurCell = CurCell;
		this.CurCell.Content.SelectAll();

		if (true === this.CurCell.Content.IsSelectionEmpty(false))
		{
			this.CurCell.Content.MoveCursorToStartPos();

			this.Selection.Use    = false;
			this.Selection.Type   = table_Selection_Text;
			this.Selection.CurRow = CurCell.Row.Index;
		}
		else
		{
			this.Selection.Use          = true;
			this.Selection.Type         = table_Selection_Text;
			this.Selection.StartPos.Pos = {Row : CurCell.Row.Index, Cell : CurCell.Index};
			this.Selection.EndPos.Pos   = {Row : CurCell.Row.Index, Cell : CurCell.Index};
			this.Selection.CurRow       = CurCell.Row.Index;
		}

		this.Document_SetThisElementCurrent(true);
	}
};
CTable.prototype.GetCurPosXY = function()
{
	var Cell = null;
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		Cell = this.Content[this.Selection.EndPos.Pos.Row].Get_Cell(this.Selection.EndPos.Pos.Cell);
	else
		Cell = this.CurCell;

	return Cell.Content_GetCurPosXY();
};
CTable.prototype.IsSelectionUse = function()
{
	if ((true == this.Selection.Use && table_Selection_Cell == this.Selection.Type) || table_Selection_Border == this.Selection.Type2 || table_Selection_Border_InnerTable == this.Selection.Type2)
		return true;
	else if (true == this.Selection.Use)
		return this.CurCell.Content.IsSelectionUse();

	return false;
};
CTable.prototype.IsTextSelectionUse = function()
{
	if ((true == this.Selection.Use && table_Selection_Cell == this.Selection.Type) || table_Selection_Border == this.Selection.Type2 || table_Selection_Border_InnerTable == this.Selection.Type2)
		return true;
	else if (true == this.Selection.Use)
		return this.CurCell.Content.IsTextSelectionUse();

	return false;
};
CTable.prototype.GetSelectedText = function(bClearText, oPr)
{
	if (true === bClearText && ( (true == this.Selection.Use && table_Selection_Text == this.Selection.Type) || false === this.Selection.Use ))
	{
		return this.CurCell.Content.GetSelectedText(true, oPr);
	}
	else if (false === bClearText)
	{
		if (this.IsCellSelection())
		{
			var arrSelectedCells = this.GetSelectionArray();

			var sResultText = "";
			for (var nIndex = 0, nCount = arrSelectedCells.length; nIndex < nCount; ++nIndex)
			{
				var oPos  = arrSelectedCells[nIndex];
				var oCell = this.GetRow(oPos.Row).GetCell(oPos.Cell);

				var oCellContent = oCell.GetContent();

				oCellContent.Set_ApplyToAll(true);
				sResultText += oCellContent.GetSelectedText(false, oPr);
				oCellContent.Set_ApplyToAll(false);
			}

			return sResultText;
		}
		else
		{
			return this.CurCell.Content.GetSelectedText(false, oPr);
		}
	}

	return null;
};
CTable.prototype.GetSelectedElementsInfo = function(Info)
{
	Info.Set_Table();

	if (false === this.Selection.Use || (true === this.Selection.Use && table_Selection_Text === this.Selection.Type))
	{
		this.CurCell.Content.GetSelectedElementsInfo(Info);
	}
	else if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.StartPos.Pos.Row === this.Selection.EndPos.Pos.Row && this.Selection.StartPos.Pos.Cell === this.Selection.EndPos.Pos.Cell)
	{
		var Row = this.Get_Row(this.Selection.StartPos.Pos.Row);
		if (!Row)
			return;

		var Cell = Row.Get_Cell(this.Selection.StartPos.Pos.Cell);
		if (!Cell)
			return;

		Info.Set_SingleCell(Cell);
	}
};
CTable.prototype.GetSelectedContent = function(SelectedContent)
{
	if (true !== this.Selection.Use)
		return;

	if (table_Selection_Cell === this.Selection.Type || true === this.ApplyToAll)
	{
		// Сначала проверим выделена ли таблица целиком, если да, тогда просто копируем ее.
		if (true === this.ApplyToAll)
		{
			SelectedContent.Add(new CSelectedElement(this.Copy(this.Parent), true));
			return;
		}

		var bAllSelected  = true;
		var SelectedCount = this.Selection.Data.length;

		// Собираем информацию по строкам
		var RowsInfoArray = [];

		var RowsCount = this.Content.length;
		for (var CurRow = 0; CurRow < RowsCount; CurRow++)
		{
			var Row        = this.Content[CurRow];
			var CellsCount = Row.Get_CellsCount();

			var CellsInfoArray = [];

			var bSelectedRow = false;

			CellsInfoArray.push({GridSpan : Row.Get_Before().GridBefore, Cell : null, Selected : false});

			for (var CurCell = 0; CurCell < CellsCount; CurCell++)
			{
				var Cell     = Row.Get_Cell(CurCell);
				var GridSpan = Cell.Get_GridSpan();
				var VMerge   = Cell.GetVMerge();

				var bSelected = false;
				if (VMerge === vmerge_Restart)
				{
					// Ищем текущую ячейку среди выделенных

					for (var Index = 0; Index < SelectedCount; Index++)
					{
						var TempPos = this.Selection.Data[Index];
						if (CurCell === TempPos.Cell && CurRow === TempPos.Row)
						{
							bSelected = true;
							break;
						}
						else if (CurRow < TempPos.Row)
							break;
					}
				}
				else
				{
					// Данная ячейка попала в вертикальное объединение, находим ячейку, с которой это объединение
					// началось и проверяем была ли она выделена (эту ячейку мы уже проверяли, т.к. она находится
					// выше).

					var StartMergedCell = this.Internal_Get_StartMergedCell2(CurCell, CurRow);
					bSelected           = RowsInfoArray[StartMergedCell.Row.Index].CellsInfoArray[StartMergedCell.Index + 1].Selected;
				}

				if (false === bSelected)
					bAllSelected = false;
				else
					bSelectedRow = true;

				CellsInfoArray.push({GridSpan : GridSpan, Cell : Cell, Selected : bSelected});
			}

			CellsInfoArray.push({GridSpan : Row.Get_After().GridAfter, Cell : null, Selected : false});

			RowsInfoArray.push({CellsInfoArray : CellsInfoArray, Selected : bSelectedRow});
		}

		if (true === bAllSelected)
		{
			SelectedContent.Add(new CSelectedElement(this.Copy(this.Parent), true));
			return;
		}


		var TableGrid = this.Internal_Copy_Grid(this.TableGridCalc);

		// Посчитаем сколько слева и справа пустых спанов
		var MinBefore = -1;
		var MinAfter  = -1;
		for (var CurRow = 0; CurRow < RowsCount; CurRow++)
		{
			var CellsInfoArray = RowsInfoArray[CurRow].CellsInfoArray;

			if (true !== RowsInfoArray[CurRow].Selected)
				continue;

			var bBefore        = true;
			var BeforeGrid     = 0, AfterGrid = 0;
			var CellsInfoCount = CellsInfoArray.length;
			for (var CellIndex = 0, CurCell = 0; CellIndex < CellsInfoCount; CellIndex++)
			{
				var CellInfo = CellsInfoArray[CellIndex];
				if (true === CellInfo.Selected)
				{
					bBefore = false;
				}
				else if (true === bBefore)
				{
					BeforeGrid += CellInfo.GridSpan;
				}
				else
				{
					AfterGrid += CellInfo.GridSpan;
				}
			}

			if (MinBefore > BeforeGrid || -1 === MinBefore)
				MinBefore = BeforeGrid;

			if (MinAfter > AfterGrid || -1 === MinAfter)
				MinAfter = AfterGrid;
		}

		for (var CurRow = 0; CurRow < RowsCount; CurRow++)
		{
			var CellsInfoArray = RowsInfoArray[CurRow].CellsInfoArray;

			if (true === RowsInfoArray[CurRow].Selected)
			{
				CellsInfoArray[0].GridSpan -= MinBefore;
				CellsInfoArray[CellsInfoArray.length - 1].GridSpan -= MinAfter;
			}
		}

		if (MinAfter > 0)
			TableGrid.splice(TableGrid.length - MinAfter, MinAfter); // TableGrid.length - (MinAfter - 1) - 1

		if (MinBefore > 0)
			TableGrid.splice(0, MinBefore);

		// Формируем новую таблицу, по выделенно части.
		var Table = new CTable(this.DrawingDocument, this.Parent, this.Inline, 0, 0, TableGrid, this.bPresentation);

		// Копируем настройки
		Table.Set_TableStyle(this.TableStyle);
		Table.Set_TableLook(this.TableLook.Copy());
		Table.Set_PositionH(this.PositionH.RelativeFrom, this.PositionH.Align, this.PositionH.Value);
		Table.Set_PositionV(this.PositionV.RelativeFrom, this.PositionV.Align, this.PositionV.Value);
		Table.Set_Distance(this.Distance.L, this.Distance.T, this.Distance.R, this.Distance.B);
		Table.Set_Pr(this.Pr.Copy());

		// Копируем строки
		for (var CurRow = 0, CurRow2 = 0; CurRow < RowsCount; CurRow++)
		{
			var RowInfo = RowsInfoArray[CurRow];
			if (true !== RowInfo.Selected)
				continue;

			var CellsInfoArray = RowInfo.CellsInfoArray;

			var Row = new CTableRow(Table, 0);

			// Копируем настройки строки
			Row.Set_Pr(this.Content[CurRow].Pr.Copy());

			var bMergedRow     = true;
			var bBefore        = true;
			var BeforeGrid     = 0, AfterGrid = 0;
			var CellsInfoCount = CellsInfoArray.length;
			for (var CellIndex = 0, CurCell = 0; CellIndex < CellsInfoCount; CellIndex++)
			{
				var CellInfo = CellsInfoArray[CellIndex];
				if (true === CellInfo.Selected)
				{
					bBefore = false;

					// Добавляем ячейку
					Row.Content[CurCell] = CellInfo.Cell.Copy(Row);
					History.Add(new CChangesTableRowAddCell(Row, CurCell, [Row.Content[CurCell]]));
					CurCell++;

					var VMerge = CellInfo.Cell.GetVMerge();
					if (VMerge === vmerge_Restart)
						bMergedRow = false;
				}
				else if (true === bBefore)
				{
					BeforeGrid += CellInfo.GridSpan;
				}
				else
				{
					AfterGrid += CellInfo.GridSpan;
				}
			}

			// Строку, составленную полностью из вертикально объединенных ячеек не добавляем
			if (true === bMergedRow)
				continue;

			Row.Set_Before(BeforeGrid);
			Row.Set_After(AfterGrid);

			Row.Internal_ReIndexing();

			// Добавляем строку в новую таблицу
			Table.Content[CurRow2] = Row;
			History.Add(new CChangesTableAddRow(Table, CurRow2, [Table.Content[CurRow2]]));
			CurRow2++;
		}

		Table.Internal_ReIndexing(0);

		if (Table.Content.length > 0 && Table.Content[0].Get_CellsCount() > 0)
			Table.CurCell = Table.Content[0].Get_Cell(0);

		SelectedContent.Add(new CSelectedElement(Table, false));
	}
	else
	{
		this.CurCell.Content.GetSelectedContent(SelectedContent);
	}
};
CTable.prototype.Set_ParagraphPrOnAdd = function(Para)
{
	this.ApplyToAll = true;

	// Добавляем стиль во все параграфы
	var PStyleId = Para.Style_Get();
	if (undefined !== PStyleId && null !== this.LogicDocument)
	{
		var Styles = this.LogicDocument.Get_Styles();
		this.SetParagraphStyle(Styles.Get_Name(PStyleId));
	}

	// Добавляем текстовые настройки во все параграфы
	var TextPr = Para.Get_TextPr();
	this.AddToParagraph(new ParaTextPr(TextPr));

	this.ApplyToAll = false;
};
CTable.prototype.SetParagraphAlign = function(Align)
{
	if (true === this.ApplyToAll || (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphAlign(Align);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphAlign(Align);
	}
};
CTable.prototype.SetParagraphDefaultTabSize = function(TabSize)
{
	if (true === this.ApplyToAll || (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphDefaultTabSize(TabSize);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphDefaultTabSize(TabSize);
	}
};
CTable.prototype.SetParagraphSpacing = function(Spacing)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphSpacing(Spacing);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphSpacing(Spacing);
	}
};
CTable.prototype.SetParagraphIndent = function(Ind)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphIndent(Ind);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphIndent(Ind);
	}
};
CTable.prototype.Set_ParagraphPresentationNumbering = function(NumInfo)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.Set_ParagraphPresentationNumbering(NumInfo);
			Cell_Content.Set_ApplyToAll(false);
		}

		if (Cells_array[0].Row - 1 >= 0)
			this.Internal_RecalculateFrom(Cells_array[0].Row - 1, 0, true, true);
		else
		{
			this.Internal_Recalculate_1();
		}
	}
	else
		return this.CurCell.Content.Set_ParagraphPresentationNumbering(NumInfo);
};
CTable.prototype.Increase_ParagraphLevel = function(bIncrease)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.Increase_ParagraphLevel(bIncrease);
			Cell_Content.Set_ApplyToAll(false);
		}

		if (Cells_array[0].Row - 1 >= 0)
			this.Internal_RecalculateFrom(Cells_array[0].Row - 1, 0, true, true);
		else
		{
			this.Internal_Recalculate_1();
		}
	}
	else
		return this.CurCell.Content.Increase_ParagraphLevel(bIncrease);
};
CTable.prototype.SetParagraphShd = function(Shd)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphShd(Shd);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphShd(Shd);
	}
};
CTable.prototype.SetParagraphStyle = function(Name)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphStyle(Name);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphStyle(Name);
	}
};
CTable.prototype.SetParagraphTabs = function(Tabs)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphTabs(Tabs);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphTabs(Tabs);
	}
};
CTable.prototype.SetParagraphContextualSpacing = function(Value)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphContextualSpacing(Value);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphContextualSpacing(Value);
	}
};
CTable.prototype.SetParagraphPageBreakBefore = function(Value)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphPageBreakBefore(Value);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphPageBreakBefore(Value);
	}
};
CTable.prototype.SetParagraphKeepLines = function(Value)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphKeepLines(Value);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphKeepLines(Value);
	}
};
CTable.prototype.SetParagraphKeepNext = function(Value)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphKeepNext(Value);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphKeepNext(Value);
	}
};
CTable.prototype.SetParagraphWidowControl = function(Value)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphWidowControl(Value);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphWidowControl(Value);
	}
};
CTable.prototype.SetParagraphBorders = function(Borders)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphBorders(Borders);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphBorders(Borders);
	}
};
CTable.prototype.SetParagraphFramePr = function(FramePr, bDelete)
{
	if (true !== this.ApplyToAll && (true !== this.Selection.Use || table_Selection_Cell !== this.Selection.Type))
	{
		this.CurCell.Content.SetParagraphFramePr(FramePr, bDelete);
	}
};
CTable.prototype.IncreaseDecreaseFontSize = function(bIncrease)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.IncreaseDecreaseFontSize(bIncrease);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.IncreaseDecreaseFontSize(bIncrease);
	}
};
CTable.prototype.IncreaseDecreaseIndent = function(bIncrease)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var TablePr = this.Get_CompiledPr(false).TablePr;

		var LeftIndOld = TablePr.TableInd;
		if (undefined === LeftIndOld || null === LeftIndOld)
		{
			LeftIndOld = 0;
		}
		else if (LeftIndOld < 0)
		{
			this.Set_TableInd(0);
			return;
		}

		var LeftIndNew = 0;
		if (true === bIncrease)
		{
			if (LeftIndOld >= 0)
			{
				LeftIndOld = 12.5 * parseInt(10 * LeftIndOld / 125);
				LeftIndNew = ( (LeftIndOld - (10 * LeftIndOld) % 125 / 10) / 12.5 + 1) * 12.5;
			}

			if (LeftIndNew < 0)
				LeftIndNew = 12.5;
		}
		else
		{
			var TempValue = (125 - (10 * LeftIndOld) % 125);
			TempValue     = ( 125 === TempValue ? 0 : TempValue );
			LeftIndNew    = Math.max(( (LeftIndOld + TempValue / 10) / 12.5 - 1 ) * 12.5, 0);
		}

		this.Set_TableInd(LeftIndNew);
	}
	else
	{
		this.CurCell.Content.IncreaseDecreaseIndent(bIncrease);
	}
};
CTable.prototype.GetCalculatedParaPr = function()
{
	if (true === this.ApplyToAll)
	{
		var Row  = this.Content[0];
		var Cell = Row.Get_Cell(0);

		Cell.Content.Set_ApplyToAll(true);
		var Result_ParaPr = Cell.Content.GetCalculatedParaPr();
		Cell.Content.Set_ApplyToAll(false);

		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			Row            = this.Content[CurRow];
			var CellsCount = Row.Get_CellsCount();
			var StartCell  = ( CurRow === 0 ? 1 : 0 );

			for (var CurCell = StartCell; CurCell < CellsCount; CurCell++)
			{
				Cell = Row.Get_Cell(CurCell);
				Cell.Content.Set_ApplyToAll(true);
				var CurPr = Cell.Content.GetCalculatedParaPr();
				Cell.Content.Set_ApplyToAll(false);

				Result_ParaPr = Result_ParaPr.Compare(CurPr);
			}
		}

		return Result_ParaPr;
	}

	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		var Pos  = this.Selection.Data[0];
		var Row  = this.Content[Pos.Row];
		var Cell = Row.Get_Cell(Pos.Cell);

		Cell.Content.Set_ApplyToAll(true);
		var Result_ParaPr = Cell.Content.GetCalculatedParaPr();
		Cell.Content.Set_ApplyToAll(false);

		for (var Index = 1; Index < this.Selection.Data.length; Index++)
		{
			Pos  = this.Selection.Data[Index];
			Row  = this.Content[Pos.Row];
			Cell = Row.Get_Cell(Pos.Cell);

			Cell.Content.Set_ApplyToAll(true);
			var CurPr = Cell.Content.GetCalculatedParaPr();
			Cell.Content.Set_ApplyToAll(false);

			Result_ParaPr = Result_ParaPr.Compare(CurPr);
		}

		return Result_ParaPr;
	}

	return this.CurCell.Content.GetCalculatedParaPr();
};
CTable.prototype.GetCalculatedTextPr = function()
{
	if (true === this.ApplyToAll)
	{
		var Row  = this.Content[0];
		var Cell = Row.Get_Cell(0);

		Cell.Content.Set_ApplyToAll(true);
		var Result_TextPr = Cell.Content.GetCalculatedTextPr();
		Cell.Content.Set_ApplyToAll(false);

		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			Row            = this.Content[CurRow];
			var CellsCount = Row.Get_CellsCount();
			var StartCell  = ( CurRow === 0 ? 1 : 0 );

			for (var CurCell = StartCell; CurCell < CellsCount; CurCell++)
			{
				Cell = Row.Get_Cell(CurCell);
				Cell.Content.Set_ApplyToAll(true);
				var CurPr = Cell.Content.GetCalculatedTextPr();
				Cell.Content.Set_ApplyToAll(false);

				Result_TextPr = Result_TextPr.Compare(CurPr);
			}
		}

		return Result_TextPr;
	}

	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		var Pos  = this.Selection.Data[0];
		var Row  = this.Content[Pos.Row];
		var Cell = Row.Get_Cell(Pos.Cell);

		Cell.Content.Set_ApplyToAll(true);
		var Result_TextPr = Cell.Content.GetCalculatedTextPr();
		Cell.Content.Set_ApplyToAll(false);

		for (var Index = 1; Index < this.Selection.Data.length; Index++)
		{
			Pos  = this.Selection.Data[Index];
			Row  = this.Content[Pos.Row];
			Cell = Row.Get_Cell(Pos.Cell);

			Cell.Content.Set_ApplyToAll(true);
			var CurPr = Cell.Content.GetCalculatedTextPr();
			Cell.Content.Set_ApplyToAll(false);

			Result_TextPr = Result_TextPr.Compare(CurPr);
		}

		return Result_TextPr;
	}

	return this.CurCell.Content.GetCalculatedTextPr();
};
CTable.prototype.GetDirectTextPr = function()
{
	if (true === this.ApplyToAll)
	{
		var Row  = this.Content[0];
		var Cell = Row.Get_Cell(0);

		Cell.Content.Set_ApplyToAll(true);
		var Result_TextPr = Cell.Content.GetDirectTextPr();
		Cell.Content.Set_ApplyToAll(false);

		return Result_TextPr;
	}

	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		var Pos  = this.Selection.Data[0];
		var Row  = this.Content[Pos.Row];
		var Cell = Row.Get_Cell(Pos.Cell);

		Cell.Content.Set_ApplyToAll(true);
		var Result_TextPr = Cell.Content.GetDirectTextPr();
		Cell.Content.Set_ApplyToAll(false);

		return Result_TextPr;
	}

	return this.CurCell.Content.GetDirectTextPr();
};
CTable.prototype.GetDirectParaPr = function()
{
	if (true === this.ApplyToAll)
	{
		var Row  = this.Content[0];
		var Cell = Row.Get_Cell(0);

		Cell.Content.Set_ApplyToAll(true);
		var Result_TextPr = Cell.Content.GetDirectParaPr();
		Cell.Content.Set_ApplyToAll(false);

		return Result_TextPr;
	}

	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		var Pos  = this.Selection.Data[0];
		var Row  = this.Content[Pos.Row];
		var Cell = Row.Get_Cell(Pos.Cell);

		Cell.Content.Set_ApplyToAll(true);
		var Result_TextPr = Cell.Content.GetDirectParaPr();
		Cell.Content.Set_ApplyToAll(false);

		return Result_TextPr;
	}

	return this.CurCell.Content.GetDirectParaPr();
};
CTable.prototype.GetCurrentParagraph = function(bIgnoreSelection, arrSelectedParagraphs)
{
	if (arrSelectedParagraphs)
	{
		var arrSelectionArray = this.GetSelectionArray();
		for (var nIndex = 0, nCount = arrSelectionArray.length; nIndex < nCount; ++nIndex)
		{
			var nCurCell = arrSelectionArray[nIndex].Cell;
			var nCurRow  = arrSelectionArray[nIndex].Row;

			var oCellContent = this.GetRow(nCurRow).GetCell(nCurCell).GetContent();

			if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
			{
				oCellContent.Set_ApplyToAll(true);
				oCellContent.GetCurrentParagraph(false, arrSelectedParagraphs);
				oCellContent.Set_ApplyToAll(false);
			}
			else
			{
				oCellContent.GetCurrentParagraph(false, arrSelectedParagraphs);
			}
		}

		return arrSelectedParagraphs;
	}
	else if (true === bIgnoreSelection)
	{
		if (this.CurCell)
			return this.CurCell.Content.GetCurrentParagraph(bIgnoreSelection, null);
		else
			null;
	}
	else
	{
		var arrSelectionArray = this.GetSelectionArray();
		if (arrSelectionArray.length > 0)
		{
			var nCurCell = arrSelectionArray[0].Cell;
			var nCurRow  = arrSelectionArray[0].Row;

			var oCellContent = this.GetRow(nCurRow).GetCell(nCurCell).GetContent();

			if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
			{
				oCellContent.Set_ApplyToAll(true);
				var oRes = oCellContent.GetCurrentParagraph(bIgnoreSelection, null);
				oCellContent.Set_ApplyToAll(false);
				return oRes;
			}
			else
			{
				return oCellContent.GetCurrentParagraph(bIgnoreSelection, null);
			}
		}
	}

	return null;
};
CTable.prototype.SetImageProps = function(Props)
{
	if ((true === this.Selection.Use && table_Selection_Text === this.Selection.Type) || false === this.Selection.Use)
	{
		return this.CurCell.Content.SetImageProps(Props);
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Работаем со стилем таблицы
//----------------------------------------------------------------------------------------------------------------------
/**
 * Сообщаем таблице, что ей надо будет пересчитать скомпилированный стиль
 * (Такое может случится, если у данной таблицы задан стиль,
 * который меняется каким-то внешним образом)
 *
 */
CTable.prototype.Recalc_CompiledPr = function()
{
	this.CompiledPr.NeedRecalc = true;
};
CTable.prototype.Recalc_CompiledPr2 = function()
{
	this.Recalc_CompiledPr();

	var RowsCount = this.Content.length;
	for (var CurRow = 0; CurRow < RowsCount; CurRow++)
	{
		var Row = this.Content[CurRow];
		Row.Recalc_CompiledPr();

		var CellsCount = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			Cell.Recalc_CompiledPr();
		}
	}
};
/**
 * Формируем конечные свойства параграфа на основе стиля и прямых настроек.
 */
CTable.prototype.Get_CompiledPr = function(bCopy)
{
	if (true === this.CompiledPr.NeedRecalc)
	{
		if (true === AscCommon.g_oIdCounter.m_bLoad && true === AscCommon.g_oIdCounter.m_bRead)
		{
			this.CompiledPr.Pr         = {
				TextPr : g_oDocumentDefaultTextPr,
				ParaPr : g_oDocumentDefaultParaPr,

				TablePr     : g_oDocumentDefaultTablePr,
				TableRowPr  : g_oDocumentDefaultTableRowPr,
				TableCellPr : g_oDocumentDefaultTableCellPr,

				TableFirstCol   : g_oDocumentDefaultTableStylePr,
				TableFirstRow   : g_oDocumentDefaultTableStylePr,
				TableLastCol    : g_oDocumentDefaultTableStylePr,
				TableLastRow    : g_oDocumentDefaultTableStylePr,
				TableBand1Horz  : g_oDocumentDefaultTableStylePr,
				TableBand1Vert  : g_oDocumentDefaultTableStylePr,
				TableBand2Horz  : g_oDocumentDefaultTableStylePr,
				TableBand2Vert  : g_oDocumentDefaultTableStylePr,
				TableTLCell     : g_oDocumentDefaultTableStylePr,
				TableTRCell     : g_oDocumentDefaultTableStylePr,
				TableBLCell     : g_oDocumentDefaultTableStylePr,
				TableBRCell     : g_oDocumentDefaultTableStylePr,
				TableWholeTable : g_oDocumentDefaultTableStylePr
			};
			this.CompiledPr.NeedRecalc = true;
		}
		else
		{
			this.CompiledPr.Pr         = this.Internal_Compile_Pr();
			this.CompiledPr.NeedRecalc = false;
		}
	}

	if (false === bCopy)
		return this.CompiledPr.Pr;
	else
	{
		var Pr    = {};
		Pr.TextPr = this.CompiledPr.Pr.TextPr.Copy();
		Pr.ParaPr = this.CompiledPr.Pr.ParaPr.Copy();

		Pr.TablePr     = this.CompiledPr.Pr.TablePr.Copy();
		Pr.TableRowPr  = this.CompiledPr.Pr.TableRowPr.Copy();
		Pr.TableCellPr = this.CompiledPr.Pr.TableCellPr.Copy();

		Pr.TableFirstCol   = this.CompiledPr.Pr.TableFirstCol.Copy();
		Pr.TableFirstRow   = this.CompiledPr.Pr.TableFirstRow.Copy();
		Pr.TableLastCol    = this.CompiledPr.Pr.TableLastCol.Copy();
		Pr.TableLastRow    = this.CompiledPr.Pr.TableLastRow.Copy();
		Pr.TableBand1Horz  = this.CompiledPr.Pr.TableBand1Horz.Copy();
		Pr.TableBand1Vert  = this.CompiledPr.Pr.TableBand1Vert.Copy();
		Pr.TableBand2Horz  = this.CompiledPr.Pr.TableBand2Horz.Copy();
		Pr.TableBand2Vert  = this.CompiledPr.Pr.TableBand2Vert.Copy();
		Pr.TableTLCell     = this.CompiledPr.Pr.TableTLCell.Copy();
		Pr.TableTRCell     = this.CompiledPr.Pr.TableTRCell.Copy();
		Pr.TableBLCell     = this.CompiledPr.Pr.TableBLCell.Copy();
		Pr.TableBRCell     = this.CompiledPr.Pr.TableBRCell.Copy();
		Pr.TableWholeTable = this.CompiledPr.Pr.TableWholeTable.Copy();

		return Pr; // Отдаем копию объекта, чтобы никто не поменял извне настройки стиля
	}
};
CTable.prototype.Get_Style = function()
{
	if ("undefined" != typeof(this.TableStyle))
		return this.TableStyle;

	return null;
};
CTable.prototype.Set_Style = function(Id)
{
	this.Style_Remove();
	if (null === Id)
		return;

	// Если стиль является стилем по умолчанию для таблицы, тогда не надо его записывать.
	if (Id != this.Get_Styles().Get_Default_Table())
		this.TableStyle = Id;

	// Надо пересчитать конечный стиль
	this.CompiledPr.NeedRecalc = true;
};
CTable.prototype.Remove_Style = function()
{
	if ("undefined" != typeof(this.TableStyle))
		delete this.TableStyle;

	// Надо пересчитать конечный стиль
	this.CompiledPr.NeedRecalc = true;
};
/**
 * Формируем конечные свойства таблицы на основе стиля и прямых настроек.
 */
CTable.prototype.Internal_Compile_Pr = function()
{
	var Styles  = this.Get_Styles();
	var StyleId = this.Get_Style();

	// Считываем свойства для текущего стиля
	var Pr = Styles.Get_Pr(StyleId, styletype_Table);
	if (this.bPresentation)
	{
		this.Check_PresentationPr(Pr);
	}
	// Копируем прямые настройки параграфа.
	Pr.TablePr.Merge(this.Pr);

	return Pr;
};
CTable.prototype.Check_PresentationPr = function(Pr)
{
	var Theme = this.Get_Theme();
	Pr.TablePr.Check_PresentationPr(Theme);
	Pr.TextPr.Check_PresentationPr(Theme);
	Pr.TableCellPr.Check_PresentationPr(Theme);
	Pr.TableFirstCol.Check_PresentationPr(Theme);
	Pr.TableFirstRow.Check_PresentationPr(Theme);
	Pr.TableLastCol.Check_PresentationPr(Theme);
	Pr.TableLastRow.Check_PresentationPr(Theme);
	Pr.TableBand1Horz.Check_PresentationPr(Theme);
	Pr.TableBand1Vert.Check_PresentationPr(Theme);
	Pr.TableBand2Horz.Check_PresentationPr(Theme);
	Pr.TableBand2Vert.Check_PresentationPr(Theme);
	Pr.TableTLCell.Check_PresentationPr(Theme);
	Pr.TableTRCell.Check_PresentationPr(Theme);
	Pr.TableBLCell.Check_PresentationPr(Theme);
	Pr.TableBRCell.Check_PresentationPr(Theme);
};
//----------------------------------------------------------------------------------------------------------------------
// Устанавливаем прямые настройки таблицы
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.Clear_DirectFormatting = function(bClearMerge)
{
	// Очищаем все прямые настройки таблицы, всех ее строк и всех ее ячеек

	this.Set_TableStyleRowBandSize(undefined);
	this.Set_TableStyleColBandSize(undefined);
	this.Set_TableAlign(undefined);
	this.Set_TableShd(undefined);
	this.Set_TableBorder_Bottom(undefined);
	this.Set_TableBorder_Left(undefined);
	this.Set_TableBorder_Right(undefined);
	this.Set_TableBorder_Top(undefined);
	this.Set_TableBorder_InsideV(undefined);
	this.Set_TableBorder_InsideH(undefined);
	this.Set_TableCellMar(undefined, undefined, undefined, undefined);
	this.Set_TableInd(undefined);

	if (false !== bClearMerge)
		this.Set_TableW(undefined, undefined);

	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		this.Content[Index].Clear_DirectFormatting(bClearMerge);
	}
};
CTable.prototype.Set_Pr = function(TablePr)
{
	History.Add(new CChangesTablePr(this, this.Pr, TablePr));
	this.Pr = TablePr;
	this.Recalc_CompiledPr2();
};
CTable.prototype.Set_TableStyle = function(StyleId, bNoClearFormatting)
{
	// Здесь мы не проверяем изменился ли стиль, потому что при выставлении стиля нужно сбрасывать
	// прямые настройки, даже если мы выставляем тот же самый стиль.

	History.Add(new CChangesTableTableStyle(this, this.TableStyle, StyleId));
	this.TableStyle = StyleId;

	// Очищаем все прямое форматирование таблицы
	if (!(bNoClearFormatting === true))
	{
		this.Clear_DirectFormatting(false);
	}
	this.Recalc_CompiledPr2();
};
CTable.prototype.Set_TableStyle2 = function(StyleId)
{
	if (this.TableStyle != StyleId)
	{
		History.Add(new CChangesTableTableStyle(this, this.TableStyle, StyleId));
		this.TableStyle = StyleId;

		this.Recalc_CompiledPr2();
	}
};
CTable.prototype.Get_TableStyle = function()
{
	return this.TableStyle;
};
CTable.prototype.Set_TableLook = function(TableLook)
{
	History.Add(new CChangesTableTableLook(this, this.TableLook, TableLook));
	this.TableLook = TableLook;
	this.Recalc_CompiledPr2();
};
CTable.prototype.Get_TableLook = function()
{
	return this.TableLook;
};
CTable.prototype.Set_AllowOverlap = function(AllowOverlap)
{
	History.Add(new CChangesTableAllowOverlap(this, this.AllowOverlap, AllowOverlap));
	this.AllowOverlap = AllowOverlap;
};
CTable.prototype.Get_AllowOverlap = function()
{
	return this.AllowOverlap;
};
CTable.prototype.Set_PositionH = function(RelativeFrom, Align, Value)
{
	History.Add(new CChangesTablePositionH(this,
		{
			RelativeFrom : this.PositionH.RelativeFrom,
			Align        : this.PositionH.Align,
			Value        : this.PositionH.Value
		},
		{
			RelativeFrom : RelativeFrom,
			Align        : Align,
			Value        : Value
		}));

	this.PositionH.RelativeFrom = RelativeFrom;
	this.PositionH.Align        = Align;
	this.PositionH.Value        = Value;
};
CTable.prototype.Set_PositionV = function(RelativeFrom, Align, Value)
{
	History.Add(new CChangesTablePositionV(this,
		{
			RelativeFrom : this.PositionV.RelativeFrom,
			Align        : this.PositionV.Align,
			Value        : this.PositionV.Value
		},
		{
			RelativeFrom : RelativeFrom,
			Align        : Align,
			Value        : Value
		}));

	this.PositionV.RelativeFrom = RelativeFrom;
	this.PositionV.Align        = Align;
	this.PositionV.Value        = Value;
};
CTable.prototype.Set_Distance = function(L, T, R, B)
{
	if (null === L || undefined === L)
		L = this.Distance.L;

	if (null === T || undefined === T)
		T = this.Distance.T;

	if (null === R || undefined === R)
		R = this.Distance.R;

	if (null === B || undefined === B)
		B = this.Distance.B;

	History.Add(new CChangesTableDistance(this, {
		Left   : this.Distance.L,
		Top    : this.Distance.T,
		Right  : this.Distance.R,
		Bottom : this.Distance.B
	}, {
		Left   : L,
		Top    : T,
		Right  : R,
		Bottom : B
	}));
	this.Distance.L = L;
	this.Distance.R = R;
	this.Distance.T = T;
	this.Distance.B = B;
};
CTable.prototype.Set_TableStyleRowBandSize = function(Value)
{
	if (this.Pr.TableStyleRowBandSize === Value)
		return;

	History.Add(new CChangesTableTableStyleRowBandSize(this, this.Pr.TableStyleRowBandSize, Value));
	this.Pr.TableStyleRowBandSize = Value;
	this.Recalc_CompiledPr();
};
CTable.prototype.Get_TableStyleRowBandSize = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableStyleRowBandSize;
};
CTable.prototype.Set_TableStyleColBandSize = function(Value)
{
	if (this.Pr.TableStyleColBandSize === Value)
		return;

	History.Add(new CChangesTableTableStyleColBandSize(this, this.Pr.TableStyleColBandSize, Value));
	this.Pr.TableStyleColBandSize = Value;
	this.Recalc_CompiledPr();
};
CTable.prototype.Get_TableStyleColBandSize = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableStyleColBandSize;
};
CTable.prototype.Get_ShapeStyleForPara = function()
{
	return this.Parent.Get_ShapeStyleForPara();
};
CTable.prototype.Set_TableW = function(Type, W)
{
	if (undefined === Type)
	{
		if (undefined === this.Pr.TableW)
			return;

		History.Add(new CChangesTableTableW(this, this.Pr.TableW, undefined));
		this.Pr.TableW = undefined;
		this.Recalc_CompiledPr();
	}
	else if (undefined === this.Pr.TableW)
	{
		var TableW = new CTableMeasurement(Type, W);
		History.Add(new CChangesTableTableW(this, undefined, TableW));
		this.Pr.TableW = TableW;
		this.Recalc_CompiledPr();
	}
	else if (Type != this.Pr.TableW.Type || Math.abs(this.Pr.TableW.W - W) > 0.001)
	{
		var TableW = new CTableMeasurement(Type, W);
		History.Add(new CChangesTableTableW(this, this.Pr.TableW, TableW));
		this.Pr.TableW = TableW;
		this.Recalc_CompiledPr();
	}
};
CTable.prototype.Get_TableW = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableW;
};
/**
 * Задаем предпочитаемую ширину таблицы
 * @param nType
 * @param nW
 */
CTable.prototype.SetTableW = function(nType, nW)
{
	this.Set_TableW(nType, nW);
};
/**
 * Получаем предпочитаемую ширину таблицы
 * @returns {CTableMeasurement}
 */
CTable.prototype.GetTableW = function()
{
	return this.Get_TableW();
};
CTable.prototype.SetTableLayout = function(Value)
{
	if (this.Pr.TableLayout === Value)
		return;

	History.Add(new CChangesTableTableLayout(this, this.Pr.TableLayout, Value));
	this.Pr.TableLayout = Value;
	this.Recalc_CompiledPr();
};
CTable.prototype.GetTableLayout = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableLayout;
};
CTable.prototype.Set_TableCellMar = function(Left, Top, Right, Bottom)
{
	var old_Left   = ( undefined === this.Pr.TableCellMar.Left ? undefined : this.Pr.TableCellMar.Left   );
	var old_Right  = ( undefined === this.Pr.TableCellMar.Right ? undefined : this.Pr.TableCellMar.Right  );
	var old_Top    = ( undefined === this.Pr.TableCellMar.Top ? undefined : this.Pr.TableCellMar.Top    );
	var old_Bottom = ( undefined === this.Pr.TableCellMar.Bottom ? undefined : this.Pr.TableCellMar.Bottom );

	var new_Left   = ( undefined === Left ? undefined : new CTableMeasurement(tblwidth_Mm, Left) );
	var new_Right  = ( undefined === Right ? undefined : new CTableMeasurement(tblwidth_Mm, Right) );
	var new_Top    = ( undefined === Top ? undefined : new CTableMeasurement(tblwidth_Mm, Top) );
	var new_Bottom = ( undefined === Bottom ? undefined : new CTableMeasurement(tblwidth_Mm, Bottom) );

	History.Add(new CChangesTableTableCellMar(this,
		{
			Left   : old_Left,
			Right  : old_Right,
			Top    : old_Top,
			Bottom : old_Bottom
		},
		{
			Left   : new_Left,
			Right  : new_Right,
			Top    : new_Top,
			Bottom : new_Bottom
		})
	);

	this.Pr.TableCellMar.Left   = new_Left;
	this.Pr.TableCellMar.Right  = new_Right;
	this.Pr.TableCellMar.Top    = new_Top;
	this.Pr.TableCellMar.Bottom = new_Bottom;

	this.Recalc_CompiledPr();
};
CTable.prototype.Get_TableCellMar = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableCellMar;
};
CTable.prototype.Set_TableAlign = function(Align)
{
	if (undefined === Align)
	{
		if (undefined === this.Pr.Jc)
			return;

		History.Add(new CChangesTableTableAlign(this, this.Pr.Jc, undefined));
		this.Pr.Jc = undefined;
		this.Recalc_CompiledPr();
	}
	else if (undefined === this.Pr.Jc)
	{
		History.Add(new CChangesTableTableAlign(this, undefined, Align));
		this.Pr.Jc = Align;
		this.Recalc_CompiledPr();
	}
	else if (Align != this.Pr.Jc)
	{
		History.Add(new CChangesTableTableAlign(this, this.Pr.Jc, Align));
		this.Pr.Jc = Align;
		this.Recalc_CompiledPr();
	}
};
CTable.prototype.Get_TableAlign = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.Jc;
};
CTable.prototype.Set_TableInd = function(Ind)
{
	if (undefined === Ind)
	{
		if (undefined === this.Pr.TableInd)
			return;

		History.Add(new CChangesTableTableInd(this, this.Pr.TableInd, undefined));
		this.Pr.TableInd = undefined;
		this.Recalc_CompiledPr();
	}
	else if (undefined === this.Pr.TableInd)
	{
		History.Add(new CChangesTableTableInd(this, undefined, Ind));
		this.Pr.TableInd = Ind;
		this.Recalc_CompiledPr();
	}
	else if (Math.abs(this.Pr.TableInd - Ind) > 0.001)
	{
		History.Add(new CChangesTableTableInd(this, this.Pr.TableInd, Ind));
		this.Pr.TableInd = Ind;
		this.Recalc_CompiledPr();
	}
};
CTable.prototype.Get_TableInd = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableInd;
};
CTable.prototype.Set_TableBorder_Left = function(Border)
{
	if (undefined === this.Pr.TableBorders.Left && undefined === Border)
		return;

	var _Border = Border;
	if (undefined !== _Border)
	{
		_Border = new CDocumentBorder();
		_Border.Set_FromObject(Border);
	}

	History.Add(new CChangesTableTableBorderLeft(this, this.Pr.TableBorders.Left, _Border));
	this.Pr.TableBorders.Left = _Border;
	this.Recalc_CompiledPr();
};
CTable.prototype.Set_TableBorder_Right = function(Border)
{
	if (undefined === this.Pr.TableBorders.Right && undefined === Border)
		return;

	var _Border = Border;
	if (undefined !== _Border)
	{
		_Border = new CDocumentBorder();
		_Border.Set_FromObject(Border);
	}

	History.Add(new CChangesTableTableBorderRight(this, this.Pr.TableBorders.Right, _Border));
	this.Pr.TableBorders.Right = _Border;
	this.Recalc_CompiledPr();
};
CTable.prototype.Set_TableBorder_Top = function(Border)
{
	if (undefined === this.Pr.TableBorders.Top && undefined === Border)
		return;

	var _Border = Border;
	if (undefined !== _Border)
	{
		_Border = new CDocumentBorder();
		_Border.Set_FromObject(Border);
	}

	History.Add(new CChangesTableTableBorderTop(this, this.Pr.TableBorders.Top, _Border));
	this.Pr.TableBorders.Top = _Border;
	this.Recalc_CompiledPr();
};
CTable.prototype.Set_TableBorder_Bottom = function(Border)
{
	if (undefined === this.Pr.TableBorders.Bottom && undefined === Border)
		return;

	var _Border = Border;
	if (undefined !== _Border)
	{
		_Border = new CDocumentBorder();
		_Border.Set_FromObject(Border);
	}

	History.Add(new CChangesTableTableBorderBottom(this, this.Pr.TableBorders.Bottom, _Border));
	this.Pr.TableBorders.Bottom = _Border;
	this.Recalc_CompiledPr();
};
CTable.prototype.Set_TableBorder_InsideH = function(Border)
{
	if (undefined === this.Pr.TableBorders.InsideH && undefined === Border)
		return;

	var _Border = Border;
	if (undefined !== _Border)
	{
		_Border = new CDocumentBorder();
		_Border.Set_FromObject(Border);
	}

	History.Add(new CChangesTableTableBorderInsideH(this, this.Pr.TableBorders.InsideH, _Border));
	this.Pr.TableBorders.InsideH = _Border;
	this.Recalc_CompiledPr();
};
CTable.prototype.Set_TableBorder_InsideV = function(Border)
{
	if (undefined === this.Pr.TableBorders.InsideV && undefined === Border)
		return;

	var _Border = Border;
	if (undefined !== _Border)
	{
		_Border = new CDocumentBorder();
		_Border.Set_FromObject(Border);
	}

	History.Add(new CChangesTableTableBorderInsideV(this, this.Pr.TableBorders.InsideV, _Border));
	this.Pr.TableBorders.InsideV = _Border;
	this.Recalc_CompiledPr();
};
CTable.prototype.Get_TableBorders = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableBorders;
};
CTable.prototype.GetTopTableBorder = function()
{
	return this.Get_CompiledPr(false).TablePr.TableBorders.Top;
};
CTable.prototype.GetBottomTableBorder = function()
{
	return this.Get_CompiledPr(false).TablePr.TableBorders.Bottom;
};
CTable.prototype.Set_TableShd = function(Value, r, g, b)
{
	if (undefined === Value && undefined === this.Pr.Shd)
		return;

	var _Shd = undefined;
	if (undefined !== Value)
	{
		_Shd       = new CDocumentShd();
		_Shd.Value = Value;
		_Shd.Color.Set(r, g, b);
	}

	History.Add(new CChangesTableTableShd(this, this.Pr.Shd, _Shd));
	this.Pr.Shd = _Shd;
	this.Recalc_CompiledPr();
};
CTable.prototype.Get_Shd = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.Shd;
};
CTable.prototype.Get_Borders = function()
{
	return this.Get_TableBorders();
};
CTable.prototype.Set_TableDescription = function(sDescription)
{
	History.Add(new CChangesTableTableDescription(this, this.Pr.TableDescription, sDescription));
	this.Pr.TableDescription = sDescription;
	this.Recalc_CompiledPr();
};
CTable.prototype.Get_TableDescription = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableDescription;
};
CTable.prototype.Set_TableCaption = function(sCaption)
{
	History.Add(new CChangesTableTableCaption(this, this.Pr.TableCaption, sCaption));
	this.Pr.TableCaption = sCaption;
	this.Recalc_CompiledPr();
};
CTable.prototype.Get_TableCaption = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableCaption;
};
//----------------------------------------------------------------------------------------------------------------------
// Работаем с сеткой таблицы
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.Split_Table = function()
{
	// Пока данная функция используется только при добавлении секции. В этом случае мы делим таблицу на 2 части по
	// текущей строке. Если текущая строка первая, тогда не делим таблицу.

	var CurRow = this.CurCell.Row.Index;

	if (0 === CurRow)
		return null;

	var NewTable = new CTable(this.DrawingDocument, this.Parent, this.Inline, 0, 0, this.private_CopyTableGrid());

	var Len = this.Content.length;
	for (var RowIndex = CurRow; RowIndex < Len; RowIndex++)
	{
		NewTable.Internal_Add_Row(RowIndex - CurRow, 0, false, this.Content[CurRow]);
		this.Internal_Remove_Row(CurRow);
	}

	NewTable.ReIndexing(0);
	this.ReIndexing(0);

	NewTable.Set_Pr(this.Pr.Copy());
	NewTable.Set_TableStyle2(this.TableStyle);
	NewTable.Set_TableLook(this.TableLook.Copy());

	// Сбросим селект и текущую позицию в таблицах
	this.MoveCursorToStartPos(false);
	NewTable.MoveCursorToStartPos(false);

	return NewTable;
};
CTable.prototype.Internal_CheckMerge = function()
{
	var bCanMerge = true;

	var Grid_start = -1;
	var Grid_end   = -1;

	var RowsInfo = [];
	var nRowMin  = -1;
	var nRowMax  = -1;

	for (var Index = 0; Index < this.Selection.Data.length; Index++)
	{
		var Pos  = this.Selection.Data[Index];
		var Row  = this.Content[Pos.Row];
		var Cell = Row.GetCell(Pos.Cell);

		var CellInfo     = Row.GetCellInfo(Pos.Cell);
		var StartGridCol = CellInfo.StartGridCol;
		var EndGridCol   = StartGridCol + Cell.GetGridSpan() - 1;

		var VMergeCount = this.Internal_GetVertMergeCount(Pos.Row, CellInfo.StartGridCol, Cell.GetGridSpan());

		for (var RowIndex = Pos.Row; RowIndex <= Pos.Row + VMergeCount - 1; RowIndex++)
		{
			if ("undefined" === typeof(RowsInfo[RowIndex]))
			{
				RowsInfo[RowIndex] = {
					Grid_start : StartGridCol,
					Grid_end   : EndGridCol
				};

				if (-1 === nRowMax || RowIndex > nRowMax)
					nRowMax = RowIndex;

				if (-1 === nRowMin || RowIndex < nRowMin)
					nRowMin = RowIndex;
			}
			else
			{
				if (StartGridCol < RowsInfo[RowIndex].Grid_start)
					RowsInfo[RowIndex].Grid_start = StartGridCol;

				if (EndGridCol > RowsInfo[RowIndex].Grid_end)
					RowsInfo[RowIndex].Grid_end = EndGridCol;
			}
		}
	}

	// Проверим, что селект строк идет без пропусков
	for (var nRowIndex = nRowMin; nRowIndex <= nRowMax; ++nRowIndex)
	{
		if (!RowsInfo[nRowIndex])
		{
			bCanMerge = false;
			break;
		}
	}

	for (var Index in RowsInfo)
	{
		if (-1 === Grid_start)
			Grid_start = RowsInfo[Index].Grid_start;
		else if (Grid_start != RowsInfo[Index].Grid_start)
		{
			bCanMerge = false;
			break;
		}

		if (-1 === Grid_end)
			Grid_end = RowsInfo[Index].Grid_end;
		else if (Grid_end != RowsInfo[Index].Grid_end)
		{
			bCanMerge = false;
			break;
		}
	}

	if (true === bCanMerge)
	{
		// Далее, мы должны убедиться, что у выеделенных ячеек верхние и нижние поля также
		// ровные (т.е. без выступов).
		// Для этого для каждой колонки, попавшей в отрезок [Grid_start, Grid_end] находим
		// верхнюю и нижнюю ячейку и смотрим на верхнюю и нижнюю строки данных ячеек,
		// соответственно

		var TopRow = -1;
		var BotRow = -1;

		for (var GridIndex = Grid_start; GridIndex <= Grid_end; GridIndex++)
		{
			var Pos_top = null;
			var Pos_bot = null;
			for (var Index = 0; Index < this.Selection.Data.length; Index++)
			{
				var Pos  = this.Selection.Data[Index];
				var Row  = this.Content[Pos.Row];
				var Cell = Row.Get_Cell(Pos.Cell);

				var StartGridCol = Row.Get_CellInfo(Pos.Cell).StartGridCol;
				var EndGridCol   = StartGridCol + Cell.Get_GridSpan() - 1;

				if (GridIndex >= StartGridCol && GridIndex <= EndGridCol)
				{
					if (null === Pos_top || Pos_top.Row > Pos.Row)
						Pos_top = Pos;

					if (null === Pos_bot || Pos_bot.Row < Pos.Row)
						Pos_bot = Pos;
				}
			}

			if (null === Pos_top || null === Pos_bot)
			{
				bCanMerge = false;
				break;
			}

			if (-1 === TopRow)
				TopRow = Pos_top.Row;
			else if (TopRow != Pos_top.Row)
			{
				bCanMerge = false;
				break;
			}

			var Row  = this.Content[Pos_bot.Row];
			var Cell = Row.Get_Cell(Pos_bot.Cell);

			var VMergeCount = this.Internal_GetVertMergeCount(Pos_bot.Row, Row.Get_CellInfo(Pos_bot.Cell).StartGridCol, Cell.Get_GridSpan());
			var CurBotRow   = Pos_bot.Row + VMergeCount - 1;

			if (-1 === BotRow)
				BotRow = CurBotRow;
			else if (BotRow != CurBotRow)
			{
				bCanMerge = false;
				break;
			}
		}

		// Объединенные ячейки образуют прямоугольник, но возможно в нем есть вырезы,
		// т.е. выделение такое, что в него попала строка с GridBefore или GridAfter > 0
		if (true === bCanMerge)
		{
			for (var RowIndex = TopRow; RowIndex <= BotRow; RowIndex++)
			{
				var Row         = this.Content[RowIndex];
				var Grid_before = Row.Get_Before().GridBefore;
				var Grid_after  = Row.Get_After().GridAfter;

				if (Grid_after <= 0 && Grid_before <= 0)
					continue;

				if (Grid_start < Grid_before)
				{
					bCanMerge = false;
					break;
				}

				var Cell         = Row.Get_Cell(Row.Get_CellsCount() - 1);
				var Row_grid_end = Cell.Get_GridSpan() - 1 + Row.Get_CellInfo(Row.Get_CellsCount() - 1).StartGridCol;
				if (Grid_end > Row_grid_end)
				{
					bCanMerge = false;
					break;
				}
			}
		}
	}

	return {Grid_start : Grid_start, Grid_end : Grid_end, RowsInfo : RowsInfo, bCanMerge : bCanMerge};
};
/**
 * Объединяем выделенные ячейки таблицы.
 * @param isClearMerge - используем или нет рассчетные данные (true - не используем, false - default value)
 */
CTable.prototype.MergeTableCells = function(isClearMerge)
{
	var bApplyToInnerTable = false;
	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
		bApplyToInnerTable = this.CurCell.Content.MergeTableCells();

	if (true === bApplyToInnerTable)
		return false;

	if (true != this.Selection.Use || table_Selection_Cell != this.Selection.Type || this.Selection.Data.length <= 1)
		return false;

	// В массиве this.Selection.Data идет список ячеек по строкам (без разрывов)
	// Перед объединением мы должны проверить совпадают ли начальная и конечная колонки
	// в сетке TableGrid для каждого ряда.
	var Temp       = this.Internal_CheckMerge();
	var bCanMerge  = Temp.bCanMerge;
	var Grid_start = Temp.Grid_start;
	var Grid_end   = Temp.Grid_end;
	var RowsInfo   = Temp.RowsInfo;

	if (false === bCanMerge)
		return false;

	// Объединяем содержимое всех ячеек в левую верхнюю ячейку. (Все выделенные
	// ячейки идут у нас последовательно, начиная с левой верхней), и объединяем
	// сами ячейки.

	var Pos_tl  = this.Selection.Data[0];
	var Cell_tl = this.Content[Pos_tl.Row].Get_Cell(Pos_tl.Cell);

	for (var Index = 0; Index < this.Selection.Data.length; Index++)
	{
		var Pos  = this.Selection.Data[Index];
		var Row  = this.Content[Pos.Row];
		var Cell = Row.Get_Cell(Pos.Cell);

		// Добавляем содержимое данной ячейки к содержимому левой верхней ячейки
		if (0 != Index)
		{
			Cell_tl.Content_Merge(Cell.Content);
			Cell.Content.Clear_Content();
		}
	}

	if (true !== isClearMerge)
	{
		// Выставим ширину результируещей ячейки
		var SumW = 0;
		for (var CurGridCol = Grid_start; CurGridCol <= Grid_end; CurGridCol++)
		{
			SumW += this.TableGridCalc[CurGridCol];
		}
		Cell_tl.Set_W(new CTableMeasurement(tblwidth_Mm, SumW));
	}

	// Теперь нам надо удалить лишние ячейки и добавить ячейки с
	// вертикальным объединением.
	for (var RowIndex in RowsInfo)
	{
		var Row = this.Content[RowIndex];
		for (var CellIndex = 0; CellIndex < Row.Get_CellsCount(); CellIndex++)
		{
			var Cell_grid_start = Row.Get_CellInfo(CellIndex).StartGridCol;

			if (Grid_start === Cell_grid_start)
			{
				if (RowIndex != Pos_tl.Row)
				{
					var Cell = Row.Get_Cell(CellIndex);
					Cell.Set_GridSpan(Grid_end - Grid_start + 1);
					Cell.SetVMerge(vmerge_Continue);
				}
				else
				{
					Cell_tl.Set_GridSpan(Grid_end - Grid_start + 1);
				}
			}
			else if (Cell_grid_start > Grid_start && Cell_grid_start <= Grid_end)
			{
				Row.Remove_Cell(CellIndex);
				CellIndex--;
			}
			else if (Cell_grid_start > Grid_end)
				break;
		}
	}

	// Удаляем лишние строки
	this.Internal_Check_TableRows(true !== isClearMerge ? true : false);
	for (var PageNum = 0; PageNum < this.Pages.length - 1; PageNum++)
	{
		if (Pos_tl.Row <= this.Pages[PageNum + 1].FirstRow)
			break;
	}

	// Выделяем полученную ячейку
	this.Selection.Use          = true;
	this.Selection.StartPos.Pos = Pos_tl;
	this.Selection.EndPos.Pos   = Pos_tl;
	this.Selection.Type         = table_Selection_Cell;
	this.Selection.Data         = [Pos_tl];

	this.CurCell = Cell_tl;

	if (true !== isClearMerge)
	{
		// Запускаем пересчет
		this.Internal_Recalculate_1();
	}

	return true;
};
/**
 * Разделяем текущую ячейку
 */
CTable.prototype.SplitTableCells = function(Rows, Cols)
{
	var bApplyToInnerTable = false;
	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
		bApplyToInnerTable = this.CurCell.Content.SplitTableCells(Cols, Rows);

	if (true === bApplyToInnerTable)
		return true;

	// Разделение ячейки работает, только если выделена ровно одна ячейка.
	if (!( false === this.Selection.Use || ( true === this.Selection.Use && ( table_Selection_Text === this.Selection.Type || ( table_Selection_Cell === this.Selection.Type && 1 === this.Selection.Data.length  ) ) ) ))
		return false;

	var Cell_pos = null;
	var Cell     = null;

	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
	{
		Cell     = this.CurCell;
		Cell_pos =
			{
				Cell : Cell.Index,
				Row  : Cell.Row.Index
			};
	}
	else
	{
		Cell_pos = this.Selection.Data[0];
		Cell     = this.Content[Cell_pos.Row].Get_Cell(Cell_pos.Cell);
	}

	var Row = this.Content[Cell_pos.Row];

	var Grid_start = Row.Get_CellInfo(Cell_pos.Cell).StartGridCol;
	var Grid_span  = Cell.Get_GridSpan();

	var VMerge_count = this.Internal_GetVertMergeCount(Cell_pos.Row, Grid_start, Grid_span);

	// Если данная ячейка имеет вертикальное объединение, тогда по вертикали мы
	// ее разбиваем максимально на VMerge_count частей, если значение Rows превышает
	// заданное максимально допустимое значение или Rows не является делителем
	// числа VMerge_count - выдаем ошибку.
	// Если данная ячейка не учавствует в вертикальном объединении, тогда мы спокойно
	// можем делить ячейку на любое количество строк.
	if (VMerge_count > 1)
	{
		if (Rows > VMerge_count)
		{
			// Сообщение об ошибке : "Value Rows must be between 1 and " + VMerge_count
			var ErrData = new AscCommon.CErrorData();
			ErrData.put_Value(VMerge_count);
			editor.sendEvent("asc_onError", c_oAscError.ID.SplitCellMaxRows, c_oAscError.Level.NoCritical, ErrData);
			return false;
		}
		else if (0 != VMerge_count % Rows)
		{
			// Сообщение об ошибке : "Value must be a divisor of the number " + VMerge_count
			var ErrData = new AscCommon.CErrorData();
			ErrData.put_Value(VMerge_count);
			editor.sendEvent("asc_onError", c_oAscError.ID.SplitCellRowsDivider, c_oAscError.Level.NoCritical, ErrData);
			return false;
		}
	}

	// Сделаем оценку макимального количества колонок
	if (Cols > 1)
	{
		var Sum_before = this.TableSumGrid[Grid_start - 1];
		var Sum_with   = this.TableSumGrid[Grid_start + Grid_span - 1];

		var Span_width = Sum_with - Sum_before;
		var Grid_width = Span_width / Cols;

		var CellSpacing = Row.Get_CellSpacing();
		var CellMar     = Cell.GetMargins();

		var MinW = CellSpacing + CellMar.Right.W + CellMar.Left.W;

		if (Grid_width < MinW)
		{
			var MaxCols = Math.floor(Span_width / MinW);

			// Сообщение об ошибке : "Value Cols must be a between 1 and " + MaxCols
			var ErrData = new AscCommon.CErrorData();
			ErrData.put_Value(MaxCols);
			editor.sendEvent("asc_onError", c_oAscError.ID.SplitCellMaxCols, c_oAscError.Level.NoCritical, ErrData);
			return false;
		}
	}


	var Cells     = [];
	var Cells_pos = [];
	var Rows_     = [];

	if (Rows <= 1)
	{
		for (var Index = 0; Index < VMerge_count; Index++)
		{
			var TempRow = this.Content[Cell_pos.Row + Index];

			Rows_[Index]     = TempRow;
			Cells[Index]     = null;
			Cells_pos[Index] = null;

			// Ищем ячейку, начинающуюся с Grid_start

			var CellsCount = TempRow.Get_CellsCount();
			for (var CurCell = 0; CurCell < CellsCount; CurCell++)
			{
				var StartGridCol = TempRow.Get_CellInfo(CurCell).StartGridCol;
				if (StartGridCol === Grid_start)
				{
					Cells[Index]     = TempRow.Get_Cell(CurCell);
					Cells_pos[Index] = {Row : Cell_pos.Row + Index, Cell : CurCell};
				}
			}
		}
	}
	else
	{
		if (VMerge_count > 1)
		{
			var New_VMerge_Count = VMerge_count / Rows;

			for (var Index = 0; Index < VMerge_count; Index++)
			{
				var TempRow = this.Content[Cell_pos.Row + Index];

				Rows_[Index]     = TempRow;
				Cells[Index]     = null;
				Cells_pos[Index] = null;

				// Ищем ячейку, начинающуюся с Grid_start
				var CellsCount = TempRow.Get_CellsCount();
				for (var CurCell = 0; CurCell < CellsCount; CurCell++)
				{
					var StartGridCol = TempRow.Get_CellInfo(CurCell).StartGridCol;
					if (StartGridCol === Grid_start)
					{
						var TempCell     = TempRow.Get_Cell(CurCell);
						Cells[Index]     = TempCell;
						Cells_pos[Index] = {Row : Cell_pos.Row + Index, Cell : CurCell};

						if (0 === Index % New_VMerge_Count)
							TempCell.SetVMerge(vmerge_Restart);
						else
							TempCell.SetVMerge(vmerge_Continue);
					}
				}
			}
		}
		else
		{
			// Делаем разбиение по вертикали

			// Нам нужно добавить несколько точных копий текущей строки, только все ячейки,
			// кроме текущей, должны быть объединены по вертикали.

			Rows_[0]     = Row;
			Cells[0]     = Cell;
			Cells_pos[0] = Cell_pos;

			var CellsCount = Row.Get_CellsCount();
			for (var Index = 1; Index < Rows; Index++)
			{
				var NewRow = this.Internal_Add_Row(Cell_pos.Row + Index, CellsCount);
				NewRow.Copy_Pr(Row.Pr);

				Rows_[Index]     = NewRow;
				Cells[Index]     = null;
				Cells_pos[Index] = null;

				// Копируем настройки всех ячеек исходной строки в новую строку
				for (var CurCell = 0; CurCell < CellsCount; CurCell++)
				{
					var New_Cell = NewRow.Get_Cell(CurCell);
					var Old_Cell = Row.Get_Cell(CurCell);

					New_Cell.Copy_Pr(Old_Cell.Pr);

					if (CurCell === Cell_pos.Cell)
					{
						Cells[Index]     = New_Cell;
						Cells_pos[Index] = {Row : Cell_pos.Row + Index, Cell : CurCell};
					}
					else
					{
						New_Cell.SetVMerge(vmerge_Continue);
					}
				}
			}
		}
	}

	// Сделаем разбиение по горизонтали
	if (Cols > 1)
	{
		// Найдем позиции новых колонок в сетке
		var Sum_before = this.TableSumGrid[Grid_start - 1];
		var Sum_with   = this.TableSumGrid[Grid_start + Grid_span - 1];

		var Span_width = Sum_with - Sum_before;
		var Grid_width = Span_width / Cols;

		// Данный массив содержит информацию о том сколько новых колонок
		// было добавлено после i-ой колонки
		var Grid_Info = [];
		for (var Index = 0; Index < this.TableGridCalc.length; Index++)
			Grid_Info[Index] = 0;

		// Массив содержит информацию о том сколько промежутков будет в
		// новых ячейках
		var Grid_Info_new = [];
		for (var Index = 0; Index < Cols; Index++)
			Grid_Info_new[Index] = 1;

		var Grid_Info_start = [];
		for (var Index = 0; Index < this.TableGridCalc.length; Index++)
			Grid_Info_start[Index] = this.TableGridCalc[Index];

		var NewCol_Index = 0;

		var CurWidth = Sum_before + Grid_width;
		for (var Grid_index = Grid_start; Grid_index < Grid_start + Grid_span; Grid_index++)
		{
			var bNewCol = true;

			// Если мы попали в уже имеющуюся границу не добавляем новую точку
			if (Math.abs(CurWidth - this.TableSumGrid[Grid_index]) < 0.001)
			{
				NewCol_Index++;
				CurWidth += Grid_width;
				bNewCol = false;
				continue;
			}

			while (CurWidth < this.TableSumGrid[Grid_index])
			{
				if (0 === Grid_Info[Grid_index])
					Grid_Info_start[Grid_index] = CurWidth - this.TableSumGrid[Grid_index - 1];
				Grid_Info[Grid_index] += 1;

				NewCol_Index++
				CurWidth += Grid_width;

				// Если мы попали в уже имеющуюся границу не добавляем новую точку
				if (Math.abs(CurWidth - this.TableSumGrid[Grid_index]) < 0.001)
				{
					NewCol_Index++;
					CurWidth += Grid_width;
					bNewCol = false;
					break;
				}
			}

			if (true === bNewCol)
				Grid_Info_new[NewCol_Index] += 1;
		}

		// Добавим в данной строке (Cols - 1) ячеек, с теми же настроками,
		// что и исходной. Значение GridSpan мы берем из массива Grid_Info_new

		for (var Index2 = 0; Index2 < Rows_.length; Index2++)
		{
			if (null != Cells[Index2] && null != Cells_pos[Index2])
			{
				var TempRow      = Rows_[Index2];
				var TempCell     = Cells[Index2];
				var TempCell_pos = Cells_pos[Index2];

				TempCell.Set_GridSpan(Grid_Info_new[0]);
				TempCell.Set_W(new CTableMeasurement(tblwidth_Mm, Grid_width));

				for (var Index = 1; Index < Cols; Index++)
				{
					var NewCell = TempRow.Add_Cell(TempCell_pos.Cell + Index, TempRow, null, false);
					NewCell.Copy_Pr(TempCell.Pr);
					NewCell.Set_GridSpan(Grid_Info_new[Index]);
					NewCell.Set_W(new CTableMeasurement(tblwidth_Mm, Grid_width));
				}
			}
		}

		var OldTableGridLen = this.TableGridCalc.length;
		var arrNewGrid      = this.private_CopyTableGrid();

		// Добавим новые колонки в TableGrid
		// начинаем с конца, чтобы не пересчитывать номера
		for (var Index = OldTableGridLen - 1; Index >= 0; Index--)
		{
			var Summary = this.TableGridCalc[Index];

			if (Grid_Info[Index] > 0)
			{
				arrNewGrid[Index] = Grid_Info_start[Index];
				Summary -= Grid_Info_start[Index] - Grid_width;

				for (var NewIndex = 0; NewIndex < Grid_Info[Index]; NewIndex++)
				{
					Summary -= Grid_width;

					if (NewIndex != Grid_Info[Index] - 1)
						arrNewGrid.splice(Index + NewIndex + 1, 0, Grid_width);
					else
						arrNewGrid.splice(Index + NewIndex + 1, 0, Summary);
				}
			}
		}
		this.SetTableGrid(arrNewGrid);

		// Проходим по всем строкам и изменяем у ячеек GridSpan, в
		// соответствии со значениями массива Grid_Info
		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			if (CurRow >= Cells_pos[0].Row && CurRow <= Cells_pos[Cells_pos.length - 1].Row)
				continue;

			var TempRow = this.Content[CurRow];

			var GridBefore = TempRow.Get_Before().GridBefore;
			var GridAfter  = TempRow.Get_After().GridAfter;

			if (GridBefore > 0)
			{
				var SummaryGridSpan = GridBefore;
				for (var CurGrid = 0; CurGrid < GridBefore; CurGrid++)
					SummaryGridSpan += Grid_Info[CurGrid];

				TempRow.Set_Before(SummaryGridSpan);
			}

			var LastGrid = 0;

			for (var CurCell = 0; CurCell < TempRow.Get_CellsCount(); CurCell++)
			{
				var TempCell      = TempRow.Get_Cell(CurCell);
				var TempGridSpan  = TempCell.Get_GridSpan();
				var TempStartGrid = TempRow.Get_CellInfo(CurCell).StartGridCol;

				var SummaryGridSpan = TempGridSpan;

				LastGrid = TempStartGrid + TempGridSpan;

				for (var CurGrid = TempStartGrid; CurGrid < TempStartGrid + TempGridSpan; CurGrid++)
					SummaryGridSpan += Grid_Info[CurGrid];

				TempCell.Set_GridSpan(SummaryGridSpan);
			}

			if (GridAfter > 0)
			{
				var SummaryGridSpan = GridAfter;
				for (var CurGrid = LastGrid; CurGrid < OldTableGridLen; CurGrid++)
					SummaryGridSpan += Grid_Info[CurGrid];

				TempRow.Set_After(SummaryGridSpan);
			}
		}
	}

	this.ReIndexing();
	this.Recalc_CompiledPr2();
	this.private_RecalculateGrid();
	this.Internal_Recalculate_1();

	return true;
};
/**
 * Добавление строки.
 * @param bBefore - true - до(сверху) первой выделенной строки, false - после(снизу) последней выделенной строки.
 */
CTable.prototype.AddTableRow = function(bBefore)
{
	if ("undefined" === typeof(bBefore))
		bBefore = true;

	var bApplyToInnerTable = false;
	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
		bApplyToInnerTable = this.CurCell.Content.AddTableRow(bBefore);

	if (true === bApplyToInnerTable)
		return;

	var Cells_pos = [];

	// Количество, вставляемых строк зависит от того сколько содержится
	// строк в выделении. Если вставляем до, тогда копируем верхнюю строку
	// выделения, а если после, тогда последнюю.
	var Count = 1;
	var RowId = 0;

	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		Cells_pos = this.Selection.Data;

		var Prev_row = -1;
		Count        = 0;
		for (var Index = 0; Index < this.Selection.Data.length; Index++)
		{
			if (Prev_row != this.Selection.Data[Index].Row)
			{
				Count++;
				Prev_row = this.Selection.Data[Index].Row;
			}
		}
	}
	else
	{
		Cells_pos[0] = {Row : this.CurCell.Row.Index, Cell : this.CurCell.Index};
		Count        = 1;
	}

	if (Cells_pos.length <= 0)
		return;

	if (true === bBefore)
		RowId = Cells_pos[0].Row;
	else
		RowId = Cells_pos[Cells_pos.length - 1].Row;

	var Row        = this.Content[RowId];
	var CellsCount = Row.Get_CellsCount();

	// Сначала пробежимся по строке, которую мы будем копировать, и получим
	// всю необходимую информацию.
	var Cells_info = [];
	for (var CurCell = 0; CurCell < CellsCount; CurCell++)
	{
		var Cell      = Row.GetCell(CurCell);
		var Cell_info = Row.Get_CellInfo(CurCell);

		var Cell_grid_start = Cell_info.StartGridCol;
		var Cell_grid_span  = Cell.Get_GridSpan();

		var VMerge_count_before = this.Internal_GetVertMergeCount2(RowId, Cell_grid_start, Cell_grid_span);
		var VMerge_count_after  = this.Internal_GetVertMergeCount(RowId, Cell_grid_start, Cell_grid_span);

		Cells_info[CurCell] = {
			VMerge_count_before : VMerge_count_before,
			VMerge_count_after  : VMerge_count_after
		};
	}

	// TODO: Пока делаем одинаковый CellSpacing
	var CellSpacing = this.Content[0].Get_CellSpacing();

	for (var Index = 0; Index < Count; Index++)
	{
		var New_Row = null;

		if (true === bBefore)
			New_Row = this.Internal_Add_Row(RowId, CellsCount, true);
		else
			New_Row = this.Internal_Add_Row(RowId + 1, CellsCount, true);

		New_Row.Copy_Pr(Row.Pr);
		New_Row.Set_CellSpacing(CellSpacing);

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var New_Cell = New_Row.Get_Cell(CurCell);
			var Old_Cell = Row.Get_Cell(CurCell);

			New_Cell.Copy_Pr(Old_Cell.Pr);

			// Копируем также текстовые настройки и настройки параграфа
			var oFirstPara = Old_Cell.GetContent().GetFirstParagraph();
			if (oFirstPara)
			{
				var oNewCellContent = New_Cell.GetContent();

				var arrAllParagraphs = oNewCellContent.GetAllParagraphs({All : true});
				for (var nParaIndex = 0, nParasCount = arrAllParagraphs.length; nParaIndex < nParasCount; ++nParaIndex)
				{
					var oTempPara = arrAllParagraphs[nParaIndex];
					oTempPara.SetDirectParaPr(oFirstPara.GetDirectParaPr(true));
					oTempPara.SetDirectTextPr(oFirstPara.Get_FirstRunPr(), false);
				}
			}

			if (true === bBefore)
			{
				if (Cells_info[CurCell].VMerge_count_before > 1)
					New_Cell.SetVMerge(vmerge_Continue);
				else
					New_Cell.SetVMerge(vmerge_Restart);
			}
			else
			{
				if (Cells_info[CurCell].VMerge_count_after > 1)
					New_Cell.SetVMerge(vmerge_Continue);
				else
					New_Cell.SetVMerge(vmerge_Restart);
			}
		}
	}

	// Выделим новые строки
	this.Selection.Use = true;

	if (null != this.Selection.Data)
		this.Selection.Data.length = 0;
	else
		this.Selection.Data = [];

	this.Selection.Use  = true;
	this.Selection.Type = table_Selection_Cell;

	var StartRow = ( true === bBefore ? RowId : RowId + 1 );
	for (var Index = 0; Index < Count; Index++)
	{
		var Row        = this.Content[StartRow + Index];
		var CellsCount = Row.Get_CellsCount();

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			if (vmerge_Continue === Cell.GetVMerge())
				continue;

			this.Selection.Data.push({Row : StartRow + Index, Cell : CurCell});
		}
	}

	this.Recalc_CompiledPr2();
};
/**
 * Удаление строки либо по номеру Ind, либо по выделению Selection, либо по текущей ячейке.
 */
CTable.prototype.RemoveTableRow = function(Ind)
{
	var bApplyToInnerTable = false;
	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
		bApplyToInnerTable = this.CurCell.Content.RemoveTableRow(Ind);

	if (true === bApplyToInnerTable)
		return true;

	var Rows_to_delete = [];

	if ("undefined" === typeof(Ind) || null === Ind)
	{
		if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		{
			var Counter = 0;
			var PrevRow = -1;
			for (var Index = 0; Index < this.Selection.Data.length; Index++)
			{
				var CurPos = this.Selection.Data[Index];
				if (CurPos.Row != PrevRow)
					Rows_to_delete[Counter++] = CurPos.Row;

				PrevRow = CurPos.Row;
			}
		}
		else
			Rows_to_delete[0] = this.CurCell.Row.Index;
	}
	else
		Rows_to_delete[0] = Ind;

	if (Rows_to_delete.length <= 0)
		return;

	// Строки мы удаляем либо по 1, либо непрервным блоком. При удалении мы
	// смотрим на следующую строку после удаляемого блока и проверяем, если
	// какая-либо из ячеек данной строки учавствует в вертикальном объединении,
	// тогда проверяем где оно началось. Если начало объединения выше
	// строк, тогда ничего не делаем, в противном случае начинаем вертикальное
	// объединение с текущей ячейки.

	var FirstRow_to_delete = Rows_to_delete[0];
	var CurRow             = Rows_to_delete[Rows_to_delete.length - 1] + 1;
	if (CurRow < this.Content.length)
	{
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell   = Row.Get_Cell(CurCell);
			var VMerge = Cell.GetVMerge();

			if (vmerge_Continue != VMerge)
				continue;

			// Данная ячейка продолжает вертикальное объединение ячеек
			// Найдем строку, с которой начинается данное объединение.
			var VMerge_count = this.Internal_GetVertMergeCount2(CurRow, Row.Get_CellInfo(CurCell).StartGridCol, Cell.Get_GridSpan());
			if (CurRow - ( VMerge_count - 1 ) >= FirstRow_to_delete)
				Cell.SetVMerge(vmerge_Restart);
		}
	}

	this.RemoveSelection();

	// Удаляем строки.
	for (var Index = Rows_to_delete.length - 1; Index >= 0; Index--)
	{
		this.Internal_Remove_Row(Rows_to_delete[Index]);
	}

	// Возвращаем курсор
	this.DrawingDocument.TargetStart();
	this.DrawingDocument.TargetShow();

	this.DrawingDocument.SelectEnabled(false);

	// При удалении последней строки, надо сообщить об этом родительскому классу
	if (this.Content.length <= 0)
		return false;

	// Перемещаем курсор в начало следующей строки
	var CurRow   = Math.min(Rows_to_delete[0], this.Content.length - 1);
	var Row      = this.Content[CurRow];
	this.CurCell = Row.Get_Cell(0);
	this.CurCell.Content.MoveCursorToStartPos();

	var PageNum = 0;
	for (PageNum = 0; PageNum < this.Pages.length - 1; PageNum++)
	{
		if (CurRow <= this.Pages[PageNum + 1].FirstRow)
			break;
	}

	this.Markup.Internal.RowIndex  = CurRow;
	this.Markup.Internal.CellIndex = 0;
	this.Markup.Internal.PageNum   = PageNum;

	this.Recalc_CompiledPr2();

	this.Internal_Recalculate_1();

	return true;
};
/**
 * Специальная функция для удаления строк таблицы, когда выделены одновременно параграф и таблица
 */
CTable.prototype.Row_Remove2 = function()
{
	if (false == this.Selection.Use || table_Selection_Text == this.Selection.Type)
		return true;

	var Rows_to_delete = [];
	for (var Index = 0; Index < this.Content.length; Index++)
		Rows_to_delete[Index] = 0;

	for (var Index = 0; Index < this.Selection.Data.length; Index++)
	{
		var Pos = this.Selection.Data[Index];
		if (0 == Rows_to_delete[Pos.Row])
			Rows_to_delete[Pos.Row] = 1;
	}

	// Удаляем строки.
	for (var Index = this.Content.length - 1; Index >= 0; Index--)
	{
		if (0 != Rows_to_delete[Index])
			this.Internal_Remove_Row(Index);
	}

	// При удалении последней строки, надо сообщить об этом родительскому классу
	if (this.Content.length <= 0)
		return false;

	// Проверяем текущую ячейку
	if (this.CurCell.Row.Index >= this.Content.length)
		this.CurCell = this.Content[this.Content.length - 1].Get_Cell(0);

	this.RemoveSelection();

	return true;
};
/**
 * Удаление колонки либо по выделению Selection, либо по текущей ячейке.
 */
CTable.prototype.RemoveTableColumn = function()
{
	var bApplyToInnerTable = false;
	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
		bApplyToInnerTable = this.CurCell.Content.RemoveTableColumn();

	if (true === bApplyToInnerTable)
		return true;

	// Найдем правую и левую границы выделенных ячеек.
	var Cells_pos = [];

	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		Cells_pos = this.Selection.Data;
	else
		Cells_pos[0] = {Row : this.CurCell.Row.Index, Cell : this.CurCell.Index};

	if (Cells_pos.length <= 0)
		return;

	var Grid_start = -1;
	var Grid_end   = -1;
	for (var Index = 0; Index < Cells_pos.length; Index++)
	{
		var Row  = this.Content[Cells_pos[Index].Row];
		var Cell = Row.Get_Cell(Cells_pos[Index].Cell);

		var Cur_Grid_start = Row.Get_CellInfo(Cells_pos[Index].Cell).StartGridCol;
		var Cur_Grid_end   = Cur_Grid_start + Cell.Get_GridSpan() - 1;

		if (-1 === Grid_start || ( -1 != Grid_start && Grid_start > Cur_Grid_start ))
			Grid_start = Cur_Grid_start;

		if (-1 === Grid_end || ( -1 != Grid_end && Grid_end < Cur_Grid_end ))
			Grid_end = Cur_Grid_end;
	}

	// Пробегаемся по всем строкам и смотрим, если у какой либо ячейки
	// есть пересечение с отрезком [Grid_start, Grid_end], тогда удаляем
	// данную ячейку.

	var Delete_info = [];
	var Rows_info   = [];

	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		Delete_info[CurRow] = [];
		Rows_info[CurRow]   = [];

		var Row = this.Content[CurRow];

		var Before_Info = Row.Get_Before();
		if (Before_Info.GridBefore > 0)
			Rows_info[CurRow].push({W : this.TableSumGrid[Before_Info.GridBefore - 1], Type : -1, GridSpan : 1});

		var CellsCount = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell           = Row.Get_Cell(CurCell);
			var Cur_Grid_start = Row.Get_CellInfo(CurCell).StartGridCol;
			var Cur_Grid_end   = Cur_Grid_start + Cell.Get_GridSpan() - 1;

			if (Cur_Grid_start <= Grid_end && Cur_Grid_end >= Grid_start)
			{
				Delete_info[CurRow].push(CurCell);
			}
			else
			{
				var W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1];
				Rows_info[CurRow].push({W : W, Type : 0, GridSpan : 1});
			}
		}
	}

	// Удалим все ячейки
	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var Row = this.Content[CurRow];
		for (var Index = Delete_info[CurRow].length - 1; Index >= 0; Index--)
		{
			var CurCell = Delete_info[CurRow][Index];
			Row.Remove_Cell(CurCell);
		}
	}

	// При удалении колонки возможен случай, когда удаляется строка целиком
	for (var CurRow = this.Content.length - 1; CurRow >= 0; CurRow--)
	{
		// Строка удалена целиком, если в RowsInfo нет ни одной записи
		// о ячейках (т.е. с типом равным 0)
		var bRemove = true;
		for (var Index = 0; Index < Rows_info[CurRow].length; Index++)
		{
			if (0 === Rows_info[CurRow][Index].Type)
			{
				bRemove = false;
				break;
			}
		}

		if (true === bRemove)
		{
			this.Internal_Remove_Row(CurRow);
			Rows_info.splice(CurRow, 1);
		}
	}

	// Возвращаем курсор
	this.DrawingDocument.TargetStart();
	this.DrawingDocument.TargetShow();

	this.DrawingDocument.SelectEnabled(false);

	// При удалении последней строки, надо сообщить об этом родительскому классу
	if (this.Content.length <= 0)
		return false;

	// TODO: При удалении колонки надо запоминать информацию об вертикально
	//       объединенных ячейках, и в новой сетке объединять ячейки только
	//       если они были объединены изначально. Сейчас если ячейка была
	//       объединена с какой-либо ячейков, то она может после удаления колонки
	//       объединиться с совсем другой ячейкой.

	this.Internal_CreateNewGrid(Rows_info);

	// Пробегаемся по всем ячейкам и смотрим на их вертикальное объединение, было ли оно нарушено
	this.private_CorrectVerticalMerge();

	// Возможен случай, когда у нас остались строки, полностью состоящие из объединенных вертикально ячеек
	for (var CurRow = this.Content.length - 1; CurRow >= 0; CurRow--)
	{
		var bRemove    = true;
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			if (vmerge_Continue != Cell.GetVMerge())
			{
				bRemove = false;
				break;
			}
		}

		if (true === bRemove)
		{
			this.Internal_Remove_Row(CurRow);
		}
	}

	// Перемещаем курсор в начало следующей колонки
	var CurRow     = 0;
	var Row        = this.Content[CurRow];
	var CellsCount = Row.Get_CellsCount();
	var CurCell    = Delete_info[0][0] === undefined ? CellsCount - 1 : Math.min(Delete_info[0][0], CellsCount - 1);

	this.CurCell = Row.Get_Cell(CurCell);
	this.CurCell.Content.MoveCursorToStartPos();
	var PageNum = 0;

	this.Markup.Internal.RowIndex  = CurRow;
	this.Markup.Internal.CellIndex = CurCell;
	this.Markup.Internal.PageNum   = PageNum;

	this.Selection.Use          = false;
	this.Selection.Start        = false;
	this.Selection.StartPos.Pos = {Row : CurRow, Cell : CurCell};
	this.Selection.EndPos.Pos   = {Row : CurRow, Cell : CurCell};
	this.Selection.CurRow       = CurRow;

	this.private_RecalculateGrid();
	this.Internal_Recalculate_1();

	return true;
};
/**
 * Добавление колонки.
 * @param bBefore - true - до(слева) первой выделенной колонки, false - после(справа) последней выделенной колонки.
 */
CTable.prototype.AddTableColumn = function(bBefore)
{
	if ("undefined" === typeof(bBefore))
		bBefore = true;

	var bApplyToInnerTable = false;
	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
		bApplyToInnerTable = this.CurCell.Content.AddTableColumn(bBefore);

	if (true === bApplyToInnerTable)
		return;

	var Cells_pos = [];

	// Количество, вставляемых столбцов зависит от того сколько содержится
	// ячеек в первой строке выделения. Ширина берется у первой ячейки, если
	// bBefore = true, и у последней, если bBefore = false.
	var Count = 1;
	var Width = 0;

	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		Cells_pos = this.Selection.Data;

		var Prev_row = -1;
		Count        = 0;
		for (var Index = 0; Index < this.Selection.Data.length; Index++)
		{
			if (-1 != Prev_row)
			{
				if (Prev_row === this.Selection.Data[Index].Row)
					Count++;
				else
					break;
			}
			else
			{
				Count++;
				Prev_row = this.Selection.Data[Index].Row;
			}
		}
	}
	else
	{
		Cells_pos[0] = {Row : this.CurCell.Row.Index, Cell : this.CurCell.Index};
		Count        = 1;
	}

	if (Cells_pos.length <= 0)
		return;

	if (true === bBefore)
	{
		// Вычислим ширину первой ячейки
		var FirstCell_Grid_start = this.Content[Cells_pos[0].Row].Get_CellInfo(Cells_pos[0].Cell).StartGridCol;
		var FirstCell_Grid_end   = FirstCell_Grid_start + this.Content[Cells_pos[0].Row].Get_Cell(Cells_pos[0].Cell).Get_GridSpan() - 1;
		Width                    = this.TableSumGrid[FirstCell_Grid_end] - this.TableSumGrid[FirstCell_Grid_start - 1];
	}
	else
	{
		// Вычислим ширину последней ячейки
		var LastPos = Cells_pos.length - 1;

		var LastCell_Grid_start = this.Content[Cells_pos[LastPos].Row].Get_CellInfo(Cells_pos[LastPos].Cell).StartGridCol;
		var LastCell_Grid_end   = LastCell_Grid_start + this.Content[Cells_pos[LastPos].Row].Get_Cell(Cells_pos[LastPos].Cell).Get_GridSpan() - 1;
		Width                   = this.TableSumGrid[LastCell_Grid_end] - this.TableSumGrid[LastCell_Grid_start - 1];
	}

	var Rows_info = [];
	var Add_info  = [];
	if (true === bBefore)
	{
		// Ищем левую границу выделенных ячеек
		var Grid_start = -1;
		for (var Index = 0; Index < Cells_pos.length; Index++)
		{
			var Row  = this.Content[Cells_pos[Index].Row];
			var Cell = Row.Get_Cell(Cells_pos[Index].Cell);

			var Cur_Grid_start = Row.Get_CellInfo(Cells_pos[Index].Cell).StartGridCol;

			if (-1 === Grid_start || ( -1 != Grid_start && Grid_start > Cur_Grid_start ))
				Grid_start = Cur_Grid_start;
		}

		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			var Row           = this.Content[CurRow];
			Rows_info[CurRow] = [];
			Add_info[CurRow]  = 0;

			var Before_Info = Row.Get_Before();
			if (Before_Info.GridBefore > 0)
				Rows_info[CurRow].push({W : this.TableSumGrid[Before_Info.GridBefore - 1], Type : -1, GridSpan : 1});

			var CellsCount = Row.Get_CellsCount();
			for (var CurCell = 0; CurCell < CellsCount; CurCell++)
			{
				var Cell           = Row.Get_Cell(CurCell);
				var Cur_Grid_start = Row.Get_CellInfo(CurCell).StartGridCol;
				var Cur_Grid_end   = Cur_Grid_start + Cell.Get_GridSpan() - 1;

				if (Cur_Grid_start <= Grid_start)
					Add_info[CurRow] = CurCell;

				var W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1];
				Rows_info[CurRow].push({W : W, Type : 0, GridSpan : 1});
			}

			var After_Info = Row.Get_After();
			if (After_Info.GridAfter > 0)
			{
				if (Row.Get_CellInfo(CellsCount - 1).StartGridCol + Row.Get_Cell(CellsCount - 1).Get_GridSpan() <= Grid_start)
					Add_info[CurRow] = CellsCount;
			}
		}

		// Теперь нам надо добавить ячейки в найденные позиции, и в те же позиции
		// добавить элементы в массиве Rows_info
		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			var Row = this.Content[CurRow];

			var bBefore2 = false;
			if (Rows_info.length > 0 && Rows_info[CurRow][0].Type === -1)
				bBefore2 = true;

			for (var Index = 0; Index < Count; Index++)
			{
				var NewCell = Row.Add_Cell(Add_info[CurRow], Row, null, false);

				// Скопируем свойства следующуй ячейки в данной строке, а если мы добавляем в конец, то предыдущей
				var NextCell = ( Add_info[CurRow] >= Row.Get_CellsCount() - 1 ? Row.Get_Cell(Add_info[CurRow] - 1) : Row.Get_Cell(Add_info[CurRow] + 1) );
				NewCell.Copy_Pr(NextCell.Pr, true);

				// Скопируем текстовые настройки
				var FirstPara = NextCell.Content.Get_FirstParagraph();
				var TextPr    = FirstPara.Get_FirstRunPr();
				NewCell.Content.Set_ApplyToAll(true);

				// Добавляем стиль во все параграфы
				var PStyleId = FirstPara.Style_Get();
				if (undefined !== PStyleId && null !== this.LogicDocument)
				{
					var Styles = this.LogicDocument.Get_Styles();
					NewCell.Content.SetParagraphStyle(Styles.Get_Name(PStyleId));
				}

				NewCell.Content.AddToParagraph(new ParaTextPr(TextPr));
				NewCell.Content.Set_ApplyToAll(false);

				if (false === bBefore2)
					Rows_info[CurRow].splice(Add_info[CurRow], 0, {W : Width, Type : 0, GridSpan : 1});
				else
					Rows_info[CurRow].splice(Add_info[CurRow] + 1, 0, {W : Width, Type : 0, GridSpan : 1});
			}
		}
	}
	else
	{
		// Ищем правую границу выделенных ячеек
		var Grid_end = -1;
		for (var Index = 0; Index < Cells_pos.length; Index++)
		{
			var Row  = this.Content[Cells_pos[Index].Row];
			var Cell = Row.Get_Cell(Cells_pos[Index].Cell);

			var Cur_Grid_start = Row.Get_CellInfo(Cells_pos[Index].Cell).StartGridCol;
			var Cur_Grid_end   = Cur_Grid_start + Cell.Get_GridSpan() - 1;

			if (-1 === Grid_end || ( -1 != Grid_end && Grid_end < Cur_Grid_end ))
				Grid_end = Cur_Grid_end;
		}

		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			var Row           = this.Content[CurRow];
			Rows_info[CurRow] = [];
			Add_info[CurRow]  = -1;

			var Before_Info = Row.Get_Before();
			if (Before_Info.GridBefore > 0)
				Rows_info[CurRow].push({W : this.TableSumGrid[Before_Info.GridBefore - 1], Type : -1, GridSpan : 1});

			var CellsCount = Row.Get_CellsCount();
			for (var CurCell = 0; CurCell < CellsCount; CurCell++)
			{
				var Cell           = Row.Get_Cell(CurCell);
				var Cur_Grid_start = Row.Get_CellInfo(CurCell).StartGridCol;
				var Cur_Grid_end   = Cur_Grid_start + Cell.Get_GridSpan() - 1;

				if (Cur_Grid_end <= Grid_end)
					Add_info[CurRow] = CurCell;

				var W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1];
				Rows_info[CurRow].push({W : W, Type : 0, GridSpan : 1});
			}
		}

		// Теперь нам надо добавить ячейки в найденные позиции, и в те же позиции
		// добавить элементы в массиве Rows_info
		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			var Row = this.Content[CurRow];

			var bBefore2 = false;
			if (Rows_info.length > 0 && Rows_info[CurRow][0].Type === -1)
				bBefore2 = true;

			for (var Index = 0; Index < Count; Index++)
			{
				var NewCell = Row.Add_Cell(Add_info[CurRow] + 1, Row, null, false);

				// Скопируем свойства следующуй ячейки в данной строке, а если мы добавляем в конец, то предыдущей
				var NextCell = ( Add_info[CurRow] + 1 >= Row.Get_CellsCount() - 1 ? Row.Get_Cell(Add_info[CurRow]) : Row.Get_Cell(Add_info[CurRow] + 2) );
				NewCell.Copy_Pr(NextCell.Pr, true);

				// Скопируем текстовые настройки
				var FirstPara = NextCell.Content.Get_FirstParagraph();
				var TextPr    = FirstPara.Get_FirstRunPr();
				NewCell.Content.Set_ApplyToAll(true);

				// Добавляем стиль во все параграфы
				var PStyleId = FirstPara.Style_Get();
				if (undefined !== PStyleId && null !== this.LogicDocument)
				{
					var Styles = this.LogicDocument.Get_Styles();
					NewCell.Content.SetParagraphStyle(Styles.Get_Name(PStyleId));
				}

				NewCell.Content.AddToParagraph(new ParaTextPr(TextPr));
				NewCell.Content.Set_ApplyToAll(false);


				if (false === bBefore2)
					Rows_info[CurRow].splice(Add_info[CurRow] + 1, 0, {W : Width, Type : 0, GridSpan : 1});
				else
					Rows_info[CurRow].splice(Add_info[CurRow] + 2, 0, {W : Width, Type : 0, GridSpan : 1});
			}
		}
	}

	this.Internal_CreateNewGrid(Rows_info);

	// Выделим новые строки
	this.Selection.Use = true;

	if (null != this.Selection.Data)
		this.Selection.Data.length = 0;
	else
		this.Selection.Data = [];

	this.Selection.Use  = true;
	this.Selection.Type = table_Selection_Cell;

	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var StartCell = ( true === bBefore ? Add_info[CurRow] : Add_info[CurRow] + 1 );
		for (var Index = 0; Index < Count; Index++)
		{
			this.Selection.Data.push({Row : CurRow, Cell : StartCell + Index});
		}
	}

	this.private_RecalculateGrid();
	this.Internal_Recalculate_1();
};
/**
 * @param NewMarkup - новая разметка таблицы
 * @param bCol      - где произошли изменения (в колонках или строках)
 * @param Index     - номер границы колонок(строк), у которой произошли изменения
 */
CTable.prototype.Update_TableMarkupFromRuler = function(NewMarkup, bCol, Index)
{
	var TablePr = this.Get_CompiledPr(false).TablePr;
	if (true === bCol)
	{
		var RowIndex = NewMarkup.Internal.RowIndex;
		var Row      = this.Content[RowIndex];
		var Col      = 0;

		var Dx = 0;

		// границ на 1 больше, чем самих ячеек в строке
		if (Index === NewMarkup.Cols.length)
		{
			Col = Row.Get_CellInfo(Index - 1).StartGridCol + Row.Get_Cell(Index - 1).Get_GridSpan();

			Dx = NewMarkup.Cols[Index - 1] - this.Markup.Cols[Index - 1];
		}
		else
		{
			Col = Row.Get_CellInfo(Index).StartGridCol;

			if (0 != Index)
				Dx = NewMarkup.Cols[Index - 1] - this.Markup.Cols[Index - 1];
			else
				Dx = NewMarkup.X - this.Markup.X;
		}

		if (0 === Dx)
			return;

		// Пока сделаем так, в будущем надо будет менять ширину таблицы
		if (0 != Index && TablePr.TableW.Type != tblwidth_Auto)
		{
			var TableW   = TablePr.TableW.W;
			var MinWidth = this.Internal_Get_TableMinWidth();

			if (TableW < MinWidth)
				TableW = MinWidth;

			this.Set_TableW(tblwidth_Mm, TableW + Dx);
		}

		if (0 === Col)
		{
			Dx = this.Markup.X - NewMarkup.X;
			this.X_origin -= Dx;

			if (true === this.Is_Inline())
			{
				this.Set_TableAlign(align_Left);
				this.Set_TableInd(TablePr.TableInd - Dx);
				this.private_SetTableLayoutFixedAndUpdateCellsWidth(-1);
				this.SetTableGrid(this.private_CopyTableGridCalc());
			}
			else
			{
				this.Internal_UpdateFlowPosition(this.X_origin, this.Y);
			}
		}
		else
		{
			var GridSpan = 1;
			if (Dx > 0)
			{
				if (Index != NewMarkup.Cols.length)
				{
					var Cell = Row.Get_Cell(Index);
					GridSpan = Cell.Get_GridSpan();
				}
				else
				{
					var GridAfter = Row.Get_After().GridAfter;
					GridSpan      = GridAfter;
				}

				this.TableGridCalc[Col - 1] = this.TableGridCalc[Col - 1] + Dx;
				this.Internal_UpdateCellW(Col - 1);
				this.private_SetTableLayoutFixedAndUpdateCellsWidth(Col - 1);
				this.SetTableGrid(this.private_CopyTableGridCalc());
			}
			else
			{
				if (0 != Index)
				{
					var Cell = Row.Get_Cell(Index - 1);
					GridSpan = Cell.Get_GridSpan();
				}
				else
				{
					var GridBefore = Row.Get_Before().GridBefore;
					// Если GridBefore = 0, тогда мы попадем в случай 0 === Col
					GridSpan       = GridBefore;
				}

				if (1 === GridSpan || -Dx < this.TableSumGrid[Col - 1] - this.TableSumGrid[Col - 2])
				{
					this.TableGridCalc[Col - 1] = this.TableGridCalc[Col - 1] + Dx;
					this.Internal_UpdateCellW(Col - 1);
					this.private_SetTableLayoutFixedAndUpdateCellsWidth(Col - 1);
					this.SetTableGrid(this.private_CopyTableGridCalc());
				}
				else
				{
					var Rows_info = [];

					for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
					{
						Rows_info[CurRow] = [];

						var Row = this.Content[CurRow];

						var Before_Info = Row.Get_Before();


						if (Before_Info.GridBefore > 0)
						{
							if (Before_Info.GridBefore >= Col)
							{
								var W = Math.max(0, this.TableSumGrid[Before_Info.GridBefore - 1] + Dx);
								if (W > 0.001)
									Rows_info[CurRow].push({W : W, Type : -1, GridSpan : 1});
							}
							else
								Rows_info[CurRow].push({
									W        : this.TableSumGrid[Before_Info.GridBefore - 1],
									Type     : -1,
									GridSpan : 1
								});
						}

						var CellsCount = Row.Get_CellsCount();
						for (var CurCell = 0; CurCell < CellsCount; CurCell++)
						{
							var Cell           = Row.Get_Cell(CurCell);
							var CellMargins    = Cell.GetMargins();
							var Cur_Grid_start = Row.Get_CellInfo(CurCell).StartGridCol;
							var Cur_Grid_end   = Cur_Grid_start + Cell.Get_GridSpan() - 1;

							if (Cur_Grid_start <= Col - 1 && Cur_Grid_end >= Col - 1)
							{
								var W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1] + Dx;

								W = Math.max(1, Math.max(W, CellMargins.Left.W + CellMargins.Right.W));
								Rows_info[CurRow].push({W : W, Type : 0, GridSpan : 1});
							}
							else
							{
								var W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1];

								W = Math.max(1, Math.max(W, CellMargins.Left.W + CellMargins.Right.W));
								Rows_info[CurRow].push({W : W, Type : 0, GridSpan : 1});
							}
						}
					}

					this.Internal_CreateNewGrid(Rows_info);
				}
			}

			this.private_RecalculateGrid();
		}
	}
	else
	{
		var RowIndex = this.Pages[NewMarkup.Internal.PageNum].FirstRow + Index;
		if (0 === RowIndex)
		{
			if (true === this.Is_Inline())
			{
				// ничего не делаем, позиция по Y в инлайновой таблице изменить нельзя таким способом
			}
			else
			{
				var Dy = this.Markup.Rows[0].Y - NewMarkup.Rows[0].Y;
				this.Y -= Dy;
				this.Internal_UpdateFlowPosition(this.X_origin, this.Y);
				var NewH = NewMarkup.Rows[0].H;
				this.Content[0].Set_Height(NewH, linerule_AtLeast);
			}
		}
		else
		{
			if (NewMarkup.Internal.PageNum > 0 && 0 === Index)
			{
				// ничего не делаем
			}
			else
			{
				var NewH = NewMarkup.Rows[Index - 1].H;
				this.Content[RowIndex - 1].Set_Height(NewH, linerule_AtLeast);
			}
		}
	}

	this.Internal_Recalculate_1();
	editor.WordControl.m_oLogicDocument.Document_UpdateSelectionState();
};
/**
 * Распраделяем выделенные ячейки по ширине или высоте
 * @param isHorizontally
 * @returns {boolean} Возвращаем false, если операция невозможна
 */
CTable.prototype.DistributeTableCells = function(isHorizontally)
{
	if (isHorizontally)
		return this.DistributeColumns();
	else
		return this.DistributeRows();
};
//----------------------------------------------------------------------------------------------------------------------
// Внутренние функции
//----------------------------------------------------------------------------------------------------------------------
/**
 * TODO: Удалить данную функцию
 */
CTable.prototype.Internal_Recalculate_1 = function()
{
	return editor.WordControl.m_oLogicDocument.Recalculate();
};
/**
 * TODO: Удалить данную функцию
 * Данная функция вызывается после изменений внутри ячейки, а это означает, что с момента
 * последнего пересчета не изменилась ни сетка, ни границы, и ни расстояние между ячейками в таблицу.
 * Следовательно, нам надо пересчитать высоту ячейки, в которой произошли изменения,  и если
 * это приведет к изменению высоты строки, то пересчитываем все строки дальше.
 */
CTable.prototype.Internal_RecalculateFrom = function(RowIndex, CellIndex, bChange, bForceRecalc)
{
	return editor.WordControl.m_oLogicDocument.Recalculate();
};
CTable.prototype.Internal_GetCellByXY = function(X, Y, PageIndex)
{
	// Сначала определяем колонку в которую мы попали
	var CurGrid = 0;

	var CurPage   = Math.min(this.Pages.length - 1, Math.max(0, PageIndex));
	var Page      = this.Pages[CurPage];
	var ColsCount = this.TableGridCalc.length;

	var twX     = AscCommon.MMToTwips(X);
	var twPageX = AscCommon.MMToTwips(Page.X);
	if (twX >= twPageX)
	{
		for (CurGrid = 0; CurGrid < ColsCount; CurGrid++)
		{
			var twColStart = AscCommon.MMToTwips(Page.X + this.TableSumGrid[CurGrid - 1]);
			var twColEnd   = AscCommon.MMToTwips(Page.X + this.TableSumGrid[CurGrid]);
			if (twColStart <= twX && twX < twColEnd)
				break;
		}
	}

	if (CurGrid >= ColsCount)
		CurGrid = ColsCount - 1;

	// Найдем промежуток строк по PageIndex среди которых нам надо искать
	var PNum = PageIndex;

	var Row_start, Row_last;

	if (PNum < 0)
	{
		Row_start = 0;
		Row_last  = 0;
	}
	else if (PNum >= this.Pages.length)
	{
		Row_start = this.Content.length - 1;
		Row_last  = this.Content.length - 1;
	}
	else
	{
		Row_start = this.Pages[PNum].FirstRow;
		Row_last  = this.Pages[PNum].LastRow;
	}

	if (Row_last < Row_start)
		return {Row : 0, Cell : 0};

	for (var CurRow = Row_start; CurRow <= Row_last; CurRow++)
	{
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();
		var BeforeInfo = Row.Get_Before();
		var CurGridCol = BeforeInfo.GridBefore;

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell     = Row.Get_Cell(CurCell);
			var GridSpan = Cell.Get_GridSpan();
			var Vmerge   = Cell.GetVMerge();

			// Обсчет такик ячеек произошел ранее
			if (vmerge_Continue === Vmerge && Row_start != CurRow)
			{
				CurGridCol += GridSpan;
				continue;
			}

			var VMergeCount = this.private_GetVertMergeCountOnPage(PNum, CurRow, CurGridCol, GridSpan);
			if (VMergeCount <= 0)
			{
				CurGridCol += GridSpan;
				continue;
			}

			// Проверяем по X
			if (CurGrid >= CurGridCol && CurGrid < CurGridCol + GridSpan)
			{
				// Проверяем по Y
				if ("undefined" != typeof(this.RowsInfo[CurRow + VMergeCount - 1].Y[PNum]) && "undefined" != typeof(this.RowsInfo[CurRow + VMergeCount - 1].H[PNum]) && (Y <= (this.RowsInfo[CurRow + VMergeCount - 1].Y[PNum] + this.RowsInfo[CurRow + VMergeCount - 1].H[PNum]) || CurRow + VMergeCount - 1 >= Row_last ))
				{
					if (vmerge_Continue === Vmerge && Row_start === CurRow)
					{
						Cell = this.Internal_Get_StartMergedCell(CurRow, CurGridCol, GridSpan);
						if (null != Cell)
							return {Row : Cell.Row.Index, Cell : Cell.Index};
						else
							return {Row : 0, Cell : 0};
					}
					else
						return {Row : CurRow, Cell : CurCell};
				}
			}

			CurGridCol += GridSpan;
		}
	}

	return {Row : 0, Cell : 0};
};
/**
 * Считаем количество соединенных вертикально ячеек
 */
CTable.prototype.Internal_GetVertMergeCount = function(StartRow, StartGridCol, GridSpan)
{
	// начинаем с 1, потому что предполагается, что соединение начинается с исходной ячейки
	var VmergeCount = 1;
	for (var Index = StartRow + 1; Index < this.Content.length; Index++)
	{
		var Row        = this.Content[Index];
		var BeforeInfo = Row.Get_Before();
		var CurGridCol = BeforeInfo.GridBefore;
		var CurCell    = 0;
		var CellsCount = Row.Get_CellsCount();

		var bWasMerged = false;
		while (CurGridCol <= StartGridCol && CurCell < CellsCount)
		{
			var Cell         = Row.Get_Cell(CurCell);
			var CellGridSpan = Cell.Get_GridSpan();
			var Vmerge       = Cell.GetVMerge();

			if (CurGridCol === StartGridCol && GridSpan === CellGridSpan && vmerge_Continue === Vmerge)
			{
				bWasMerged = true;
				VmergeCount++;
				break;
			}
			else if (CurGridCol === StartGridCol && GridSpan === CellGridSpan && vmerge_Continue != Vmerge)
			{
				bWasMerged = true;
				return VmergeCount;
			}
			// Если данная ячейка имеет пересечение с заданным промежутком, но польностью с ним не совпадает
			else if (CurGridCol <= StartGridCol + GridSpan - 1 && CurGridCol + CellGridSpan - 1 >= StartGridCol)
				break;

			CurGridCol += CellGridSpan;
			CurCell++;
		}

		if (false === bWasMerged)
			break;
	}

	return VmergeCount;
};
/**
 * Считаем количество соединенных вертикально ячеек, но в обратную сторону (т.е. снизу вверх)
 */
CTable.prototype.Internal_GetVertMergeCount2 = function(StartRow, StartGridCol, GridSpan)
{
	// начинаем с 1, потому что предполагается, что соединение начинается с исходной ячейки
	var VmergeCount = 1;

	// сначала проверим VMerge текущей ячейки
	var Start_Row        = this.Content[StartRow];
	var Start_VMerge     = vmerge_Restart;
	var Start_CellsCount = Start_Row.Get_CellsCount();
	for (var Index = 0; Index < Start_CellsCount; Index++)
	{
		var Temp_Grid_start = Start_Row.Get_CellInfo(Index).StartGridCol;
		if (Temp_Grid_start === StartGridCol)
		{
			Start_VMerge = Start_Row.Get_Cell(Index).GetVMerge();
			break;
		}
	}

	if (vmerge_Restart === Start_VMerge)
		return VmergeCount;

	for (var Index = StartRow - 1; Index >= 0; Index--)
	{
		var Row        = this.Content[Index];
		var BeforeInfo = Row.Get_Before();
		var CurGridCol = BeforeInfo.GridBefore;
		var CurCell    = 0;
		var CellsCount = Row.Get_CellsCount();

		var bWasMerged = false;
		while (CurGridCol <= StartGridCol && CurCell < CellsCount)
		{
			var Cell         = Row.Get_Cell(CurCell);
			var CellGridSpan = Cell.Get_GridSpan();
			var Vmerge       = Cell.GetVMerge();

			if (CurGridCol === StartGridCol && GridSpan === CellGridSpan && vmerge_Continue === Vmerge)
			{
				bWasMerged = true;
				VmergeCount++;
				break;
			}
			else if (CurGridCol === StartGridCol && GridSpan === CellGridSpan && vmerge_Continue != Vmerge)
			{
				bWasMerged = true;
				VmergeCount++;
				return VmergeCount;
			}
			// Если данная ячейка имеет пересечение с заданным промежутком, но польностью с ним не совпадает
			else if (CurGridCol <= StartGridCol + GridSpan - 1 && CurGridCol + CellGridSpan - 1 >= StartGridCol)
				break;

			CurGridCol += CellGridSpan;
			CurCell++;
		}

		if (false === bWasMerged)
			break;
	}

	return VmergeCount;
};
/**
 * Проверяем, нужно ли удалить ненужные строки из нашей таблицы.
 * Такое может произойти после объединения ячеек или после изменения сетки
 * таблицы.
 * True  - в таблице произошли изменения
 * False - ничего не изменилось
 */
CTable.prototype.Internal_Check_TableRows = function(bSaveHeight)
{
	// Пробегаемся по всем строкам, если в какой-то строке у всех ячеек стоит
	// вертикальное объединение, тогда такую строку удаляем, а у предыдущей
	// строки выставляем минимальную высоту - сумму высот этих двух строк.
	// Кроме этого нам надо выставить минимальную высоту у строк, в которых
	// все ячейки состоят в вертикальном объединении, а у самой строки
	// параметр WBefore или WAfter ненулевой

	// Сначала пробежимся по строкам и узнаем, какие строки нужно удалить
	var Rows_to_Delete = [];
	var Rows_to_CalcH  = [];
	var Rows_to_CalcH2 = [];
	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var Row = this.Content[CurRow];

		var bVmerge_Restart  = false;
		var bVmerge_Continue = false;
		var bNeedDeleteRow   = true;
		var bNeedCalcHeight  = false;

		if (Row.Get_Before().GridBefore > 0 || Row.Get_After().GridAfter > 0)
			bNeedCalcHeight = true;

		for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
		{
			var Cell   = Row.Get_Cell(CurCell);
			var VMerge = Cell.GetVMerge();

			if (VMerge != vmerge_Continue)
			{
				var VMergeCount = this.Internal_GetVertMergeCount(CurRow, Row.Get_CellInfo(CurCell).StartGridCol, Cell.Get_GridSpan());
				if (VMergeCount > 1)
					bVmerge_Restart = true;

				bNeedDeleteRow = false;

				if (true === bNeedCalcHeight)
				{
					if (1 === VMergeCount)
						bNeedCalcHeight = false;
				}
			}
			else
				bVmerge_Continue = true;
		}

		if (true === bVmerge_Continue && true === bVmerge_Restart)
			Rows_to_CalcH2.push(CurRow);
		else if (true === bNeedCalcHeight)
			Rows_to_CalcH.push(CurRow);

		if (true === bNeedDeleteRow)
			Rows_to_Delete.push(CurRow);
	}

	// Сначала разберемся со строками, у которых надо проставить минимальную высоту
	for (var Index = 0; Index < Rows_to_CalcH2.length; Index++)
	{
		var RowIndex  = Rows_to_CalcH2[Index];
		var MinHeight = -1;

		var Row        = this.Content[RowIndex];
		var CellsCount = Row.Get_CellsCount()
		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell   = Row.Get_Cell(CurCell);
			var VMerge = Cell.GetVMerge();
			if (vmerge_Restart === VMerge)
			{
				var CurMinHeight = Cell.Content.Get_EmptyHeight();
				if (CurMinHeight < MinHeight || MinHeight === -1)
					MinHeight = CurMinHeight;
			}
		}

		var OldHeight = this.Content[RowIndex].Get_Height();

		if (undefined === OldHeight || Asc.linerule_Auto == OldHeight.HRule || ( MinHeight > OldHeight.Value ))
			this.Content[RowIndex].Set_Height(MinHeight, linerule_AtLeast);
	}

	if (Rows_to_Delete.length <= 0)
		return false;

	if (true === bSaveHeight)
	{
		// Сначала разберемся со строками, у которых надо проставить минимальную высоту
		for (var Index = 0; Index < Rows_to_CalcH.length; Index++)
		{
			var RowIndex = Rows_to_CalcH[Index];
			this.Content[RowIndex].Set_Height(this.RowsInfo[RowIndex].H, linerule_AtLeast);
		}

		// Рассчитаем высоты строк, так чтобы после удаления, общий вид таблицы не менялся
		for (var Counter = 0; Counter < Rows_to_Delete.length;)
		{
			var CurRowSpan = 1;

			var StartRow = Rows_to_Delete[Counter];
			while (Counter + CurRowSpan < Rows_to_Delete.length && Rows_to_Delete[Counter] + CurRowSpan === Rows_to_Delete[Counter + CurRowSpan])
				CurRowSpan++;

			if (this.RowsInfo[StartRow - 1 + CurRowSpan].StartPage === this.RowsInfo[StartRow - 1].StartPage)
			{
				var StartPage      = this.RowsInfo[StartRow - 1 + CurRowSpan].StartPage;
				var Summary_Height = this.RowsInfo[StartRow - 1 + CurRowSpan].H[StartPage] + this.RowsInfo[StartRow - 1 + CurRowSpan].Y[StartPage] - this.RowsInfo[StartRow - 1].Y[StartPage];
				this.Content[StartRow - 1].Set_Height(Summary_Height, linerule_AtLeast);
			}

			Counter += CurRowSpan;
		}
	}

	// Удаляем, начиная с последней строки, чтобы не пересчитывать номера строк
	for (var Index = Rows_to_Delete.length - 1; Index >= 0; Index--)
	{
		var Row_to_Delete = Rows_to_Delete[Index];
		this.Internal_Remove_Row(Row_to_Delete);
	}

	return true;
};
CTable.prototype.Internal_Remove_Row = function(Index)
{
	if (Index >= this.Content.length || Index < 0)
		return;

	this.Content[Index].PreDelete();

	History.Add(new CChangesTableRemoveRow(this, Index, [this.Content[Index]]));

	this.Rows--;
	this.Content.splice(Index, 1);
	this.TableRowsBottom.splice(Index, 1);
	this.RowsInfo.splice(Index, 1);

	this.Internal_ReIndexing(Index);
};
CTable.prototype.Internal_Add_Row = function(Index, CellsCount, bReIndexing, _NewRow)
{
	if (Index < 0)
		Index = 0;

	if (Index >= this.Content.length)
		Index = this.Content.length;

	this.Rows++;

	var NewRow = ( undefined === _NewRow ? new CTableRow(this, CellsCount) : _NewRow );

	History.Add(new CChangesTableAddRow(this, Index, [NewRow]));

	this.Content.splice(Index, 0, NewRow);
	this.TableRowsBottom.splice(Index, 0, {});
	this.RowsInfo.splice(Index, 0, new CTableRowsInfo());

	if (true === bReIndexing)
	{
		this.Internal_ReIndexing(Index);
	}
	else
	{
		if (Index > 0)
		{
			this.Content[Index - 1].Next = NewRow;
			NewRow.Prev                  = this.Content[Index - 1];
		}
		else
			NewRow.Prev = null;

		if (Index < this.Content.length - 1)
		{
			this.Content[Index + 1].Prev = NewRow;
			NewRow.Next                  = this.Content[Index + 1];
		}
		else
			NewRow.Next = null;
	}

	NewRow.Table = this;

	return NewRow;
};
CTable.prototype.Clear_ContentChanges = function()
{
	this.m_oContentChanges.Clear();
};
CTable.prototype.Add_ContentChanges = function(Changes)
{
	this.m_oContentChanges.Add(Changes);
};
CTable.prototype.Refresh_ContentChanges = function()
{
	this.m_oContentChanges.Refresh();
};
CTable.prototype.Internal_ReIndexing = function(StartIndex)
{
	if ("undefined" === typeof(StartIndex))
		StartIndex = 0;

	for (var Ind = StartIndex; Ind < this.Content.length; Ind++)
	{
		this.Content[Ind].Set_Index(Ind);
		this.Content[Ind].Prev  = ( Ind > 0 ? this.Content[Ind - 1] : null );
		this.Content[Ind].Next  = ( Ind < this.Content.length - 1 ? this.Content[Ind + 1] : null );
		this.Content[Ind].Table = this;
	}
};
CTable.prototype.ReIndexing = function(StartIndex)
{
	this.Internal_ReIndexing(0);

	var Count = this.Content.length;
	for (var Ind = StartIndex; Ind < Count; Ind++)
	{
		this.Content[Ind].Internal_ReIndexing(0);
	}
};
/**
 * Переделываем сетку таблицы заново, исходя из массива RowsInfo
 * В данном массиве заданы для каждой строки ширины всех ячеек (либо
 * пропусков до или после строк GridBefore/GridAfter).
 * На выходе мы отдаем новую сетку TableGrid и массив RowsInfo, в
 * котором для каждой ячейки(пропуска) указан GridSpan.
 */
CTable.prototype.private_CreateNewGrid = function(arrRowsInfo)
{
	return this.Internal_CreateNewGrid(arrRowsInfo);
};
CTable.prototype.Internal_CreateNewGrid = function(RowsInfo)
{
	var nCellSpacing = this.Content[0].GetCellSpacing();

	var CurPos = [];
	var CurX   = [];
	for (var Index = 0; Index < RowsInfo.length; Index++)
	{
		CurPos[Index] = 0;
		CurX[Index]   = RowsInfo[Index][0].W;

		for (var Index2 = 0; Index2 < RowsInfo[Index].length; Index2++)
		{
			RowsInfo[Index][Index2].GridSpan = 1;

			// Последние элемент всегда должен означать GridAfter, но с
			// нулевыем начальным значением.
			if (1 != RowsInfo[Index][RowsInfo[Index].length - 1].Type)
			{
				RowsInfo[Index].push({W : 0, Type : 1, GridSpan : 0});
			}
			else
			{
				RowsInfo[Index][RowsInfo[Index].length - 1] = {W : 0, Type : 1, GridSpan : 0};
			}
		}
	}

	var TableGrid = [];
	var bEnd      = false;
	var PrevX     = 0;
	while (true != bEnd)
	{
		var MinX = -1;
		for (var Index = 0; Index < RowsInfo.length; Index++)
		{
			if ((MinX === -1 || CurX[Index] < MinX) && !( RowsInfo[Index].length - 1 === CurPos[Index] && 1 === RowsInfo[Index][CurPos[Index]].Type ))
				MinX = CurX[Index];
		}

		for (var Index = 0; Index < RowsInfo.length; Index++)
		{
			if (RowsInfo[Index].length - 1 === CurPos[Index] && 1 === RowsInfo[Index][CurPos[Index]].Type)
				RowsInfo[Index][CurPos[Index]].GridSpan++;
			else
			{
				if (Math.abs(MinX - CurX[Index]) < 0.001)
				{
					CurPos[Index]++;
					CurX[Index] += RowsInfo[Index][CurPos[Index]].W;
				}
				else
				{
					RowsInfo[Index][CurPos[Index]].GridSpan++;
				}
			}
		}

		TableGrid.push(MinX - PrevX);
		PrevX = MinX;

		bEnd = true;
		for (var Index = 0; Index < RowsInfo.length; Index++)
		{
			if (RowsInfo[Index].length - 1 != CurPos[Index])
			{
				bEnd = false;
				break;
			}
		}
	}

	for (var CurRow = 0; CurRow < RowsInfo.length; CurRow++)
	{
		var RowInfo = RowsInfo[CurRow];
		var Row     = this.Content[CurRow];

		var CurIndex = 0;
		if (-1 === RowInfo[0].Type)
		{
			if (RowInfo[0].GridSpan > 0)
			{
				Row.Set_Before(RowInfo[0].GridSpan);
			}
			CurIndex++;
		}
		else
		{
			Row.Set_Before(0);
		}

		for (var CurCell = 0; CurIndex < RowInfo.length; CurIndex++, CurCell++)
		{
			if (1 === RowInfo[CurIndex].Type)
				break;

			var Cell = Row.Get_Cell(CurCell);
			Cell.Set_GridSpan(RowInfo[CurIndex].GridSpan);
			var WType = Cell.Get_W().Type;
			if (tblwidth_Auto != WType && tblwidth_Nil != WType)
			{
				var nW = RowInfo[CurIndex].W;
				if (null !== nCellSpacing)
				{
					if (0 === CurCell || (1 === CurCell && RowInfo[0].Type === -1))
						nW -= nCellSpacing / 2;

					nW -= nCellSpacing;

					if (RowInfo.length - 2 === CurCell)
						nW -= nCellSpacing / 2;
				}

				Cell.Set_W(new CTableMeasurement(tblwidth_Mm, nW));
			}
		}

		CurIndex = RowInfo.length - 1;
		if (1 === RowInfo[CurIndex].Type)
		{
			Row.Set_After(RowInfo[CurIndex].GridSpan);
		}
		else
		{
			Row.Set_After(0);
		}
	}
	this.SetTableGrid(TableGrid);
	return TableGrid;
};
/**
 * Получаем информацию о всех строках, используемую для генерации ширин колонок
 * @returns {Array}
 */
CTable.prototype.private_GetRowsInfo = function()
{
	var arrRowsInfo = [];

	for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
	{
		arrRowsInfo[nCurRow] = [];

		var oRow = this.Content[nCurRow];

		var oBeforeInfo = oRow.Get_Before();
		if (oBeforeInfo.GridBefore > 0)
			arrRowsInfo[nCurRow].push({W : this.TableSumGrid[oBeforeInfo.GridBefore - 1], Type : -1, GridSpan : 1});

		for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			var oCell     = oRow.GetCell(nCurCell);
			var oCellInfo = oRow.GetCellInfo(nCurCell);

			if (!oCellInfo)
			{
				arrRowsInfo[nCurRow].push({
					W        : 0,
					Type     : 0,
					GridSpan : 1
				});
			}
			else
			{
				var nCurGridStart = oCellInfo.StartGridCol;
				var nCurGridEnd   = nCurGridStart + oCell.Get_GridSpan() - 1;

				arrRowsInfo[nCurRow].push({
					W        : this.TableSumGrid[nCurGridEnd] - this.TableSumGrid[nCurGridStart - 1],
					Type     : 0,
					GridSpan : 1
				});
			}
		}
	}

	return arrRowsInfo;
};
/**
 * Добавляем в массив информации о строках новую ячейку в заданной строке
 * @param arrRowsInfo
 * @param nRowIndex
 * @param nCellIndex
 * @param {number} nW - заданная ширина ячейка
 * @returns {boolean} Удалось ли добавить информацию
 */
CTable.prototype.private_AddCellToRowsInfo = function(arrRowsInfo, nRowIndex, nCellIndex, nW)
{
	if (!arrRowsInfo || !arrRowsInfo[nRowIndex])
		return false;

	var nPos = nCellIndex;
	if (-1 === arrRowsInfo[nRowIndex][0].Type)
		nPos++;

	if (nPos > arrRowsInfo[nRowIndex].length)
		return false;

	arrRowsInfo[nRowIndex].splice(nPos, 0, {
		W        : nW,
		Type     : 0,
		GridSpan : 1
	});

	return true;
};
CTable.prototype.Internal_UpdateCellW = function(Col)
{
	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var Row         = this.Content[CurRow];
		var Cells_Count = Row.Get_CellsCount();
		var CurGridCol  = Row.Get_Before().GridBefore;

		for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
		{
			var Cell     = Row.Get_Cell(CurCell);
			var GridSpan = Cell.Get_GridSpan();

			if (Col >= CurGridCol && Col < CurGridCol + GridSpan)
			{
				var CellWType = Cell.Get_W().Type;
				if (tblwidth_Auto != CellWType && tblwidth_Nil != CellWType)
				{
					var W = 0;
					for (var CurSpan = CurGridCol; CurSpan < CurGridCol + GridSpan; CurSpan++)
						W += this.TableGridCalc[CurSpan];

					Cell.Set_W(new CTableMeasurement(tblwidth_Mm, W));
				}

				break;
			}

			CurGridCol += GridSpan;
		}
	}
};
/**
 * Сравниваем границы двух соседних ячеек.
 * @param Border1
 * @param Border2
 * @param bTableBorder1 - является ли граница границей всей таблицы
 * @param bTableBorder2 - является ли граница границей всей таблицы
 */
CTable.prototype.Internal_CompareBorders = function(Border1, Border2, bTableBorder1, bTableBorder2)
{
	if ("undefined" === typeof(bTableBorder1))
		bTableBorder1 = false;

	if ("undefined" === typeof(bTableBorder2))
		bTableBorder2 = false;

	// Граница ячейки всегда побеждает границу таблицы, если первая задана
	if (true === bTableBorder1)
		return Border2;

	if (true === bTableBorder2)
		return Border1;

	// Всегда побеждает непустая граница
	if (border_None === Border1.Value)
		return Border2;

	if (border_None === Border2.Value)
		return Border1;

	// TODO: Как только мы реализуем рисование не только простых границ,
	//       сделать здесь обработку. W_b = Border.Size * Border_Num,
	//       где Border_Num зависит от Border.Value

	var W_b_1 = Border1.Size;
	var W_b_2 = Border2.Size;
	if (W_b_1 > W_b_2)
		return Border1;
	else if (W_b_2 > W_b_1)
		return Border2;

	var Brightness_1_1 = Border1.Color.r + Border1.Color.b + 2 * Border1.Color.g;
	var Brightness_1_2 = Border2.Color.r + Border2.Color.b + 2 * Border2.Color.g;

	if (Brightness_1_1 < Brightness_1_2)
		return Border1;
	else if (Brightness_1_2 < Brightness_1_1)
		return Border2;

	var Brightness_2_1 = Border1.Color.b + 2 * Border1.Color.g;
	var Brightness_2_2 = Border2.Color.b + 2 * Border2.Color.g;

	if (Brightness_2_1 < Brightness_2_2)
		return Border1;
	else if (Brightness_2_2 < Brightness_2_1)
		return Border2;

	var Brightness_3_1 = Border1.Color.g;
	var Brightness_3_2 = Border2.Color.g;

	if (Brightness_3_1 < Brightness_3_2)
		return Border1;
	else if (Brightness_3_2 < Brightness_3_1)
		return Border2;

	// Две границы функционально идентичны, нам все равно какую рисовать.
	return Border1;
};
/**
 * Получаем левую верхнюю ячейку в текущем объединении
 */
CTable.prototype.Internal_Get_StartMergedCell = function(StartRow, StartGridCol, GridSpan)
{
	var Result = null;
	for (var Index = StartRow; Index >= 0; Index--)
	{
		var Row        = this.Content[Index];
		var BeforeInfo = Row.Get_Before();
		var CurGridCol = BeforeInfo.GridBefore;
		var CurCell    = 0;
		var CellsCount = Row.Get_CellsCount();

		var bWasMerged = false;
		while (CurGridCol <= StartGridCol && CurCell < CellsCount)
		{
			var Cell         = Row.Get_Cell(CurCell);
			var CellGridSpan = Cell.Get_GridSpan();
			var Vmerge       = Cell.GetVMerge();

			if (CurGridCol === StartGridCol && GridSpan === CellGridSpan && vmerge_Continue === Vmerge)
			{
				bWasMerged = true;
				Result     = Cell;
				break;
			}
			else if (CurGridCol === StartGridCol && GridSpan === CellGridSpan && vmerge_Continue != Vmerge)
			{
				bWasMerged = true;
				Result     = Cell;
				return Result;
			}
			// Если данная ячейка имеет пересечение с заданным промежутком, но польностью с ним не совпадает
			else if (CurGridCol <= StartGridCol + GridSpan - 1 && CurGridCol + CellGridSpan - 1 >= StartGridCol)
				break;

			CurGridCol += CellGridSpan;
			CurCell++;
		}

		if (false === bWasMerged)
			break;
	}

	return Result;
};
/**
 * Получаем левую верхнюю ячейку в текущем объединении
 */
CTable.prototype.Internal_Get_EndMergedCell = function(StartRow, StartGridCol, GridSpan)
{
	var Result = null;
	for (var Index = StartRow, Count = this.Content.length; Index < Count; Index++)
	{
		var Row        = this.Content[Index];
		var BeforeInfo = Row.Get_Before();
		var CurGridCol = BeforeInfo.GridBefore;
		var CurCell    = 0;
		var CellsCount = Row.Get_CellsCount();

		var bWasMerged = false;
		while (CurGridCol <= StartGridCol && CurCell < CellsCount)
		{
			var Cell         = Row.Get_Cell(CurCell);
			var CellGridSpan = Cell.Get_GridSpan();
			var Vmerge       = Cell.GetVMerge();

			if (CurGridCol === StartGridCol && GridSpan === CellGridSpan)
			{
				if (vmerge_Continue === Vmerge || Index === StartRow)
				{
					bWasMerged = true;
					Result     = Cell;
					break;
				}
				else
					return Result;
			}
			// Если данная ячейка имеет пересечение с заданным промежутком, но польностью с ним не совпадает
			else if (CurGridCol <= StartGridCol + GridSpan - 1 && CurGridCol + CellGridSpan - 1 >= StartGridCol)
				break;

			CurGridCol += CellGridSpan;
			CurCell++;
		}

		if (false === bWasMerged)
			break;
	}

	return Result;
};
/**
 * Получаем массив ячеек попадающих в заданное вертикальное объединение
 */
CTable.prototype.private_GetMergedCells = function(RowIndex, StartGridCol, GridSpan)
{
	// Сначала проверим данну строку
	var Row       = this.Content[RowIndex];
	var CellIndex = this.private_GetCellIndexByStartGridCol(RowIndex, StartGridCol);
	if (-1 === CellIndex)
		return [];

	var Cell = Row.Get_Cell(CellIndex);
	if (GridSpan !== Cell.Get_GridSpan())
		return [];

	var CellsArray = [Cell];

	// Ищем ячейки вверх
	for (var Index = RowIndex - 1; Index >= 0; Index--)
	{
		var CellIndex = this.private_GetCellIndexByStartGridCol(Index, StartGridCol);
		if (-1 === CellIndex)
			break;

		var Cell = this.Content[Index].Get_Cell(CellIndex);
		if (GridSpan !== Cell.Get_GridSpan())
			break;

		var Vmerge = Cell.GetVMerge();
		if (vmerge_Continue !== Vmerge)
			break;

		CellsArray.splice(0, 0, Cell);
	}

	// Ищем ячейки вниз
	for (var Index = RowIndex + 1, Count = this.Content.length; Index < Count; Index++)
	{
		var CellIndex = this.private_GetCellIndexByStartGridCol(Index, StartGridCol);
		if (-1 === CellIndex)
			break;

		var Cell = this.Content[Index].Get_Cell(CellIndex);
		if (GridSpan !== Cell.Get_GridSpan())
			break;

		var Vmerge = Cell.GetVMerge();
		if (vmerge_Continue !== Vmerge)
			break;

		CellsArray.push(Cell);
	}

	return CellsArray;
};
CTable.prototype.private_GetCellsPosArrayByCellsArray = function(CellsArray)
{
	var Result = [];
	for (var Index = 0, Count = CellsArray.length; Index < Count; Index++)
	{
		var Cell = CellsArray[Index];
		Result.push({Cell : Cell.Index, Row : Cell.Row.Index});
	}

	return Result;
};
/**
 * Получаем левую верхнюю ячейку в текущем объединении
 * @returns {CTableCell}
 */
CTable.prototype.GetStartMergedCell = function(nCellIndex, nRowIndex)
{
	return this.Internal_Get_StartMergedCell2(nCellIndex, nRowIndex);
};
CTable.prototype.Internal_Get_StartMergedCell2 = function(CellIndex, RowIndex)
{
	var Row      = this.Content[RowIndex];
	var Cell     = Row.Get_Cell(CellIndex);
	var CellInfo = Row.Get_CellInfo(CellIndex);

	return this.Internal_Get_StartMergedCell(RowIndex, CellInfo.StartGridCol, Cell.Get_GridSpan());
};
/**
 * Получаем количество ячеек (=количество строк) попавших в вертикальное объединения, начиная с заданной ячейки внизю
 * @param nCellIndex номер ячейки в строке
 * @param nRowIndex номер строки
 * @returns {number}
 */
CTable.prototype.GetVMergeCount = function(nCellIndex, nRowIndex)
{
	var oRow = this.GetRow(nRowIndex);
	if (!oRow)
		return 1;

	var oCell = oRow.GetCell(nCellIndex);
	if (!oCell)
		return 1;

	var oCellInfo = oRow.GetCellInfo(nCellIndex);
	if (!oCellInfo)
		return 1;

	return this.Internal_GetVertMergeCount(nRowIndex, oCellInfo.StartGridCol, oCell.GetGridSpan());
};
/**
 * Получаем номер ячейки в заданной строке по заданной колонке
 * @param {number} nCurRow
 * @param {number} nStartGridCol
 * @param {boolean} [isAllowOverlap = false] true - ищем ячейку, в которой началась данная колонка, false - ищем ячейку, строго начавшуюся с заданной колонки
 * @returns {number} Возвращаем -1, если не найдена ячейка
 */
CTable.prototype.private_GetCellIndexByStartGridCol = function(nCurRow, nStartGridCol, isAllowOverlap)
{
	var oRow = this.GetRow(nCurRow);
	if (!oRow)
		return -1;

	var nCurGridCol = oRow.GetBefore().Grid;
	if (isAllowOverlap)
	{
		for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			if (nStartGridCol === nCurGridCol)
				return nCurCell;
			else if (nCurGridCol > nStartGridCol)
				return nCurCell - 1;

			var oCell = oRow.GetCell(nCurCell);
			nCurGridCol += oCell.GetGridSpan();
		}

		return oRow.GetCellsCount() - 1;
	}
	else
	{
		for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			if (nStartGridCol === nCurGridCol)
				return nCurCell;
			else if (nCurGridCol > nStartGridCol)
				return -1;

			var oCell = oRow.GetCell(nCurCell);
			nCurGridCol += oCell.GetGridSpan();
		}
	}

	return -1;
};
CTable.prototype.private_UpdateTableMarkup = function(nRowIndex, nCellIndex, nCurPage)
{
	this.Markup.Internal = {
		RowIndex  : nRowIndex,
		CellIndex : nCellIndex,
		PageNum   : nCurPage
	};

	var oPage = this.Pages[nCurPage];
	if (!oPage)
		return;

	this.Markup.X = oPage.X;

	var oRow         = this.GetRow(nRowIndex);
	var nCellSpacing = null === oRow.GetCellSpacing() ? 0 : oRow.GetCellSpacing();
	var nCellsCount  = oRow.GetCellsCount();
	var nGridBefore  = oRow.GetBefore().Grid;

	this.Markup.X += this.TableSumGrid[nGridBefore - 1];
	this.Markup.Cols    = [];
	this.Markup.Margins = [];

	for (var nCurCell = 0; nCurCell < nCellsCount; ++nCurCell)
	{
		var oCell     = oRow.GetCell(nCurCell);
		var oCellInfo = oRow.GetCellInfo(nCurCell);

		var nStartGridCol = oCellInfo.StartGridCol;
		var nGridSpan     = oCell.GetGridSpan();
		var oCellMargin   = oCell.GetMargins();

		this.Markup.Cols.push(this.TableSumGrid[nStartGridCol + nGridSpan - 1] - this.TableSumGrid[nStartGridCol - 1]);

		var nMarginLeft  = oCellMargin.Left.W;
		var nMarginRight = oCellMargin.Right.W;

		if (0 === nCurCell)
			nMarginLeft += nCellSpacing;
		else
			nMarginLeft += nCellSpacing / 2;

		if (nCellsCount - 1 === nCurCell)
			nMarginRight += nCellSpacing;
		else
			nMarginRight += nCellSpacing / 2;

		this.Markup.Margins.push({Left : nMarginLeft, Right : nMarginRight});
	}

	// Определим какие строки попадают на данную страницу
	var Row_start = this.Pages[nCurPage].FirstRow;
	var Row_last  = Row_start;

	if (nCurPage + 1 < this.Pages.length)
	{
		Row_last = this.Pages[nCurPage + 1].FirstRow;

		// Возможно, на данной странице строку, с которой началось разбиение на стрнице,
		// не надо рисовать. (Если начальная и конечная строки совпадают, тогда это 2
		// или более страница данной строки)
		if ((Row_start != Row_last || ( 0 === Row_start && 0 === Row_last ) ) && false === this.RowsInfo[Row_last].FirstPage)
			Row_last--;
	}
	else
		Row_last = this.Content.length - 1;

	this.Markup.Rows = [];
	for (var CurRow = Row_start; CurRow <= Row_last; CurRow++)
	{
		if (this.RowsInfo[CurRow] && this.RowsInfo[CurRow].Y[nCurPage] && this.RowsInfo[CurRow].H[nCurPage])
			this.Markup.Rows.push({Y : this.RowsInfo[CurRow].Y[nCurPage], H : this.RowsInfo[CurRow].H[nCurPage]});
	}

	this.Markup.CurCol = nCellIndex;
	this.Markup.CurRow = nRowIndex - Row_start;

	var Transform = this.Get_ParentTextTransform();
	this.DrawingDocument.Set_RulerState_Table(this.Markup, Transform);
};
/**
 * Проверяем попадание в границу и определяем дополнительно попадание во вспомогательные области
 * Значения для поля Border: -1 - не попали в границу
 *      0
 *    |---|
 *   3|   |1
 *    |---|
 *      2
 * @param X
 * @param Y
 * @param nCurPage
 * @returns {{Pos: {Row, Cell}, Border: number, Row: number, RowSelection: boolean, ColumnSelection: boolean, CellSelection: boolean}}
 */
CTable.prototype.private_CheckHitInBorder = function(X, Y, nCurPage)
{
	// Сначала определим ячейку, у которой границы мы будем проверять
	var oCellPos = this.Internal_GetCellByXY(X, Y, nCurPage);

	var oResult = {
		Pos             : oCellPos,
		Border          : -1,
		Row             : oCellPos.Row,
		RowSelection    : false,
		ColumnSelection : false,
		CellSelection   : false
	};

	var nCurRow  = oCellPos.Row;
	var nCurCell = oCellPos.Cell;

	var oRow      = this.GetRow(nCurRow);
	var oCell     = oRow.GetCell(nCurCell);
	var oCellInfo = oRow.GetCellInfo(nCurCell);

	var nVMergeCount       = this.GetVMergeCount(nCurCell, nCurRow);
	var nVMergeCountOnPage = this.private_GetVertMergeCountOnPage(nCurPage, nCurRow, oCellInfo.StartGridCol, oCell.GetGridSpan());
	if (nVMergeCountOnPage <= 0)
		return oResult;

	var oPage = this.Pages[nCurPage];

	var X_cell_start = oPage.X + oCellInfo.X_grid_start;
	var X_cell_end   = oPage.X + oCellInfo.X_grid_end;

	var Y_cell_start = this.RowsInfo[nCurRow].Y[nCurPage];
	var Y_cell_end   = this.RowsInfo[nCurRow + nVMergeCountOnPage - 1].Y[nCurPage] + this.RowsInfo[nCurRow + nVMergeCountOnPage - 1].H[nCurPage];

	var nRadius = this.DrawingDocument.GetMMPerDot(3); // 3 px

	if (Y <= Y_cell_start + nRadius && Y >= Y_cell_start - nRadius)
	{
		oResult.Border = 0;
	}
	else if (Y <= Y_cell_end + nRadius && Y >= Y_cell_end - nRadius)
	{
		if (nVMergeCountOnPage !== nVMergeCount)
		{
			oResult.Border = -1;
		}
		else
		{
			oResult.Border = 2;
			oResult.Row    = nCurRow + nVMergeCount - 1;
		}
	}
	else if (X <= X_cell_start + nRadius && X >= X_cell_start - nRadius)
	{
		oResult.Border = 3;
	}
	else if (X <= X_cell_end + nRadius && X >= X_cell_end - nRadius)
	{
		oResult.Border = 1;
	}

	if (0 === nCurCell && X <= X_cell_start)
	{
		oResult.RowSelection = true;
		oResult.Border       = -1;
	}
	else if (0 === nCurRow && Y <= Y_cell_start + nRadius)
	{
		oResult.ColumnSelection = true;
		oResult.Border          = -1;
	}
	else if (X_cell_start + nRadius <= X && X <= X_cell_end)
	{
		var oLeftMargin   = oCell.GetMargins().Left;
		var nCellSpacing  = oRow.GetCellSpacing();
		var nSpacingShift = null === nCellSpacing ? 0 : nCellSpacing / 2;

		if (X <= X_cell_start + nSpacingShift + oLeftMargin.W)
		{
			oResult.CellSelection = true;
			oResult.Border        = -1;
		}
	}

	return oResult;
};
/**
 * Обновляем массив выделенных ячеек
 * @param {boolean} [bForceSelectByLines=false] использовать ли выделение по строкам
 */
CTable.prototype.private_UpdateSelectedCellsArray = function(bForceSelectByLines)
{
	if (undefined === bForceSelectByLines)
		bForceSelectByLines = false;

	this.Selection.Type = table_Selection_Cell;
	this.Selection.Data = [];

	if (this.Parent.IsSelectedSingleElement() && false == bForceSelectByLines)
	{
		// Определяем ячейки, которые попали в наш селект
		// Алгоритм следующий:
		//  1. Находим максимальную левую и правую границы, у начальной и конечной
		//     ячеек селекта. Границы мы находим по сетке таблицы (TableGrid).
		//  2. Бежим по строкам и добавляем все ячейки, которые имеют непустое пересечение
		//     с нашим диапазоном в сетке.

		var StartRow  = this.Selection.StartPos.Pos.Row;
		var StartCell = this.Selection.StartPos.Pos.Cell;
		var EndRow    = this.Selection.EndPos.Pos.Row;
		var EndCell   = this.Selection.EndPos.Pos.Cell;

		if (EndRow < StartRow)
		{
			var TempRow = StartRow;
			StartRow    = EndRow;
			EndRow      = TempRow;

			var TempCell = StartCell;
			StartCell    = EndCell;
			EndCell      = TempCell;
		}

		if (StartRow === EndRow)
		{
			if (EndCell < StartCell)
			{
				var TempCell = StartCell;
				StartCell    = EndCell;
				EndCell      = TempCell;
			}

			var Row = this.Content[StartRow];
			for (var CurCell = StartCell; CurCell <= EndCell; CurCell++)
			{
				var Cell   = Row.Get_Cell(CurCell);
				var Vmerge = Cell.GetVMerge();

				// Обсчет такик ячеек произошел ранее
				if (vmerge_Continue === Vmerge)
					continue;

				this.Selection.Data.push({Row : StartRow, Cell : CurCell});
			}
		}
		else
		{
			var Cell_s = this.Content[StartRow].Get_Cell(StartCell);
			var Cell_e = this.Content[EndRow].Get_Cell(EndCell);

			var GridCol_cs_start = this.Content[StartRow].Get_StartGridCol(StartCell);
			var GridCol_cs_end   = Cell_s.Get_GridSpan() - 1 + GridCol_cs_start;
			var GridCol_ce_start = this.Content[EndRow].Get_StartGridCol(EndCell);
			var GridCol_ce_end   = Cell_e.Get_GridSpan() - 1 + GridCol_ce_start;

			var GridCol_start = GridCol_cs_start;
			if (GridCol_ce_start < GridCol_start)
				GridCol_start = GridCol_ce_start;

			var GridCol_end = GridCol_cs_end;
			if (GridCol_end < GridCol_ce_end)
				GridCol_end = GridCol_ce_end;

			for (var CurRow = StartRow; CurRow <= EndRow; CurRow++)
			{
				var Row        = this.Content[CurRow];
				var BeforeInfo = Row.Get_Before();
				var CurGridCol = BeforeInfo.GridBefore;
				var CellsCount = Row.Get_CellsCount();
				for (var CurCell = 0; CurCell < CellsCount; CurCell++)
				{
					var Cell     = Row.Get_Cell(CurCell);
					var GridSpan = Cell.Get_GridSpan();
					var Vmerge   = Cell.GetVMerge();

					// Обсчет такик ячеек произошел ранее
					if (vmerge_Continue === Vmerge)
					{
						CurGridCol += GridSpan;
						continue;
					}

					// У первой строки мы не селектим ячейки до начальной.
					// Аналогично, у последней строки мы не селектим ничего после
					// конечной ячейки.
					if (( StartRow === CurRow /*&& CurCell >= StartCell*/ ) || ( EndRow === CurRow /*&& CurCell <= EndCell*/ ) || ( CurRow > StartRow && CurRow < EndRow ))
					{
						if (( CurGridCol >= GridCol_start && CurGridCol <= GridCol_end ) || ( CurGridCol + GridSpan - 1 >= GridCol_start && CurGridCol + GridSpan - 1 <= GridCol_end ))
							this.Selection.Data.push({Row : CurRow, Cell : CurCell});
					}

					CurGridCol += GridSpan;
				}
			}
		}
	}
	else
	{
		var RowsCount = this.Content.length;

		var StartRow = Math.min(Math.max(0, this.Selection.StartPos.Pos.Row), RowsCount - 1);
		var EndRow   = Math.min(Math.max(0, this.Selection.EndPos.Pos.Row), RowsCount - 1);

		if (EndRow < StartRow)
		{
			var TempRow = StartRow;
			StartRow    = EndRow;
			EndRow      = TempRow;
		}

		for (var CurRow = StartRow; CurRow <= EndRow; CurRow++)
		{
			var Row        = this.Content[CurRow];
			var CellsCount = Row.Get_CellsCount();
			for (var CurCell = 0; CurCell < CellsCount; CurCell++)
			{
				var Cell   = Row.Get_Cell(CurCell);
				var Vmerge = Cell.GetVMerge();

				if (vmerge_Continue === Vmerge)
					continue;

				this.Selection.Data.push({Row : CurRow, Cell : CurCell});
			}
		}
	}

	if (this.Selection.Data.length > 1)
		this.Selection.CurRow = this.Selection.Data[this.Selection.Data.length - 1].Row;

	// В "flow" таблице обновляем значения настроек для параграфа и текста
	if (true != this.Is_Inline() && true === this.Selection.Use && false === this.Selection.Start)
	{
		var ParaPr = this.GetCalculatedParaPr();
		if (null != ParaPr)
			editor.UpdateParagraphProp(ParaPr);

		var TextPr = this.GetCalculatedTextPr();
		if (null != TextPr)
			editor.UpdateTextPr(TextPr);
	}
};
CTable.prototype.Internal_CompareBorders2 = function(Border1, Border2)
{
	var ResultBorder = new CDocumentBorder();
	if (Border1.Value != Border2.Value)
		ResultBorder.Value = undefined;
	else
		ResultBorder.Value = Border1.Value;

	if (Border1.Size != Border2.Size)
		ResultBorder.Size = undefined;
	else
		ResultBorder.Size = Border1.Size;

	if (undefined === Border1.Color || undefined === Border2.Color || Border1.Color.r != Border2.Color.r || Border1.Color.g != Border2.Color.g || Border1.Color.b != Border2.Color.b)
		ResultBorder.Color = undefined;
	else
		ResultBorder.Color.Set(Border1.Color.r, Border1.Color.g, Border1.Color.b);

	return ResultBorder;
};
CTable.prototype.Internal_CompareBorders3 = function(Border1, Border2)
{
	if (Border1.Value != Border2.Value)
		return false;

	if (Border1.Size != Border2.Size)
		return false;

	if (Border1.Color.r != Border2.Color.r || Border1.Color.g != Border2.Color.g || Border1.Color.b != Border2.Color.b)
		return false;

	return true;
};
CTable.prototype.Internal_CheckNullBorder = function(Border)
{
	if (null === Border || undefined === Border)
		return true;

	if (null != Border.Value)
		return false;

	if (null != Border.Size)
		return false;

	if (null != Border.Color && ( null != Border.Color.r || null != Border.Color.g || null != Border.Color.b ) || Border.Unifill != null)
		return false;

	return true;
};
CTable.prototype.Internal_Get_SelectionArray = function()
{
	var SelectionArray = null;
	if (true === this.ApplyToAll)
	{
		SelectionArray = [];
		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			var Row = this.Content[CurRow];
			for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
			{
				var Cell   = Row.Get_Cell(CurCell);
				var Vmerge = Cell.GetVMerge();

				if (vmerge_Continue === Vmerge)
					continue;

				SelectionArray.push({Cell : CurCell, Row : CurRow});
			}
		}
	}
	else if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		SelectionArray = this.Selection.Data;
	else
		SelectionArray = [{Cell : this.CurCell.Index, Row : this.CurCell.Row.Index}];

	return SelectionArray;
};
CTable.prototype.Internal_Get_TableMinWidth = function()
{
	var MinWidth = 0;
	// Оценим минимально возможную ширину
	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var Row         = this.Content[CurRow];
		var Cells_Count = Row.Get_CellsCount();

		var CellSpacing = Row.Get_CellSpacing();
		if (null === CellSpacing)
			CellSpacing = 0;

		var RowWidth = CellSpacing * ( Cells_Count + 1 );

		for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
		{
			var Cell         = Row.Get_Cell(CurCell);
			var Cell_Margins = Cell.GetMargins();

			RowWidth += Cell_Margins.Left.W + Cell_Margins.Right.W;
		}

		if (MinWidth < RowWidth)
			MinWidth = RowWidth;
	}

	return MinWidth;
};
CTable.prototype.Internal_Get_MinSumGrid = function()
{
	var ColsCount = this.TableGridCalc.length;
	var SumGrid   = [];
	for (var Index = -1; Index < ColsCount; Index++)
		SumGrid[Index] = 0;

	var RowsCount = this.Content.length;
	for (var CurRow = 0; CurRow < RowsCount; CurRow++)
	{
		var Row         = this.Content[CurRow];
		var Cells_Count = Row.Get_CellsCount();

		var CellSpacing = Row.Get_CellSpacing();
		if (null === CellSpacing)
			CellSpacing = 0;

		var CurGridCol = 0;

		for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
		{
			var Cell         = Row.Get_Cell(CurCell);
			var Cell_Margins = Cell.GetMargins();
			var GridSpan     = Cell.Get_GridSpan();

			var Cell_MinWidth = Cell_Margins.Left.W + Cell_Margins.Right.W;
			if (0 === CurCell || Cells_Count - 1 === CurCell)
				Cell_MinWidth += CellSpacing * 1.5;
			else
				Cell_MinWidth += CellSpacing;

			if (SumGrid[CurGridCol + GridSpan - 1] < SumGrid[CurGridCol - 1] + Cell_MinWidth)
				SumGrid[CurGridCol + GridSpan - 1] = SumGrid[CurGridCol - 1] + Cell_MinWidth;

			CurGridCol += GridSpan;
		}
	}

	return SumGrid;
};
CTable.prototype.Internal_ScaleTableWidth = function(SumGrid, TableW)
{
	var SumGrid_min = this.Internal_Get_MinSumGrid();

	// Массив означает, какие колонки таблицы нам надо изменить
	var Grids_to_scale = [];
	for (var Index = 0; Index < SumGrid.length; Index++)
		Grids_to_scale[Index] = true;

	var Grids_to_scale_count = Grids_to_scale.length;

	var TableGrid = [];
	TableGrid[0]  = SumGrid[0];
	for (var Index = 1; Index < SumGrid.length; Index++)
		TableGrid[Index] = SumGrid[Index] - SumGrid[Index - 1];

	var TableGrid_min = [];
	TableGrid_min[0]  = SumGrid_min[0];
	for (var Index = 1; Index < SumGrid_min.length; Index++)
		TableGrid_min[Index] = SumGrid_min[Index] - SumGrid_min[Index - 1];

	var CurrentW = SumGrid[SumGrid.length - 1];
	while (Grids_to_scale_count > 0 && CurrentW > 0.001)
	{
		// Пробуем ужать колонки таблицы
		var Koef = TableW / CurrentW;

		var TableGrid_cur = [];
		for (var Index = 0; Index < TableGrid.length; Index++)
			TableGrid_cur[Index] = TableGrid[Index];

		for (var AddIndex = 0; AddIndex <= TableGrid_cur.length - 1; AddIndex++)
		{
			if (true === Grids_to_scale[AddIndex])
				TableGrid_cur[AddIndex] = TableGrid_cur[AddIndex] * Koef;
		}

		var bBreak = true;

		// Проверяем, не стали ли некоторые колонки меньше минимально возможной ширины
		for (var AddIndex = 0; AddIndex <= TableGrid_cur.length - 1; AddIndex++)
		{
			if (true === Grids_to_scale[AddIndex] && TableGrid_cur[AddIndex] - TableGrid_min[AddIndex] < 0.001)
			{
				bBreak                   = false;
				Grids_to_scale[AddIndex] = false;
				Grids_to_scale_count--;

				CurrentW -= TableGrid[AddIndex];
				TableW -= TableGrid_min[AddIndex];

				TableGrid[AddIndex] = TableGrid_min[AddIndex];
			}
		}

		if (true === bBreak)
		{
			for (var AddIndex = 0; AddIndex <= TableGrid_cur.length - 1; AddIndex++)
			{
				if (true === Grids_to_scale[AddIndex])
					TableGrid[AddIndex] = TableGrid_cur[AddIndex];
			}

			break;
		}
	}

	var SumGrid_new = [];
	SumGrid_new[-1] = 0;
	for (var Index = 0; Index < TableGrid.length; Index++)
		SumGrid_new[Index] = TableGrid[Index] + SumGrid_new[Index - 1];

	return SumGrid_new;
};
CTable.prototype.Internal_Get_NextCell = function(Pos)
{
	var Cell_Index = Pos.Cell;
	var Row_Index  = Pos.Row;

	if (Cell_Index < this.Content[Row_Index].Get_CellsCount() - 1)
	{
		Pos.Cell = Cell_Index + 1;
		return this.Content[Pos.Row].Get_Cell(Pos.Cell);
	}
	else if (Row_Index < this.Content.length - 1)
	{
		Pos.Row  = Row_Index + 1;
		Pos.Cell = 0;
		return this.Content[Pos.Row].Get_Cell(Pos.Cell);
	}
	else
		return null;
};
CTable.prototype.Internal_Get_PrevCell = function(Pos)
{
	var Cell_Index = Pos.Cell;
	var Row_Index  = Pos.Row;

	if (Cell_Index > 0)
	{
		Pos.Cell = Cell_Index - 1;
		return this.Content[Pos.Row].Get_Cell(Pos.Cell);
	}
	else if (Row_Index > 0)
	{
		Pos.Row  = Row_Index - 1;
		Pos.Cell = this.Content[Row_Index - 1].Get_CellsCount() - 1;
		return this.Content[Pos.Row].Get_Cell(Pos.Cell);
	}
	else
		return null;
};
CTable.prototype.Internal_Copy_Grid = function(Grid)
{
	if (undefined !== Grid && null !== Grid)
	{
		var Count   = Grid.length;
		var NewGrid = new Array(Count);
		var Index   = 0;
		for (; Index < Count; Index++)
			NewGrid[Index] = Grid[Index];

		return NewGrid;
	}

	return [];
};
CTable.prototype.private_UpdateTableRulerOnBorderMove = function(Pos)
{
	if (null != this.Selection.Data2.Min)
		Pos = Math.max(Pos, this.Selection.Data2.Min);

	if (null != this.Selection.Data2.Max)
		Pos = Math.min(Pos, this.Selection.Data2.Max);

	// Обновляем Markup по ячейке в которой мы двигаем границу. Так делаем, потому что мы можем находится изначально
	// на другой странице данной таблице, а там Markup может быть совершенно другим. В конце движения границы
	// произойдет обновление селекта, и Markup обновится по текущему положению курсора.
	this.private_UpdateTableMarkup(this.Selection.Data2.Pos.Row, this.Selection.Data2.Pos.Cell, this.Selection.Data2.PageNum);
	this.DrawingDocument.UpdateTableRuler(this.Selection.Data2.bCol, this.Selection.Data2.Index, Pos);

	return Pos;
};
/**
 * Получаем массив позиций ячеек, попавших в выделение
 * @returns {{Cell : number, Row : number}[]}
 */
CTable.prototype.GetSelectionArray = function()
{
	return this.Internal_Get_SelectionArray();
};
/**
 * Считаем количество соединенных вертикально ячеек на заданной странице
 */
CTable.prototype.private_GetVertMergeCountOnPage = function(CurPage, CurRow, StartGridCol, GridSpan)
{
	var VMergeCount = this.Internal_GetVertMergeCount(CurRow, StartGridCol, GridSpan);

	if (true !== this.IsEmptyPage(CurPage) && CurRow + VMergeCount - 1 >= this.Pages[CurPage].LastRow)
	{
		VMergeCount = this.Pages[CurPage].LastRow + 1 - CurRow;
		if (false === this.RowsInfo[CurRow + VMergeCount - 1].FirstPage && CurPage === this.RowsInfo[CurRow + VMergeCount - 1].StartPage)
			VMergeCount--;
	}

	return VMergeCount;
};
/**
 * Получаем отрезок выделенных строк
 * @returns {{Start: number, End: number}}
 */
CTable.prototype.GetSelectedRowsRange = function()
{
	var arrSelectedCells = this.GetSelectionArray();

	var nStartRow = -1,
		nEndRow   = -2;

	for (var nIndex = 0, nCount = arrSelectedCells.length; nIndex < nCount; ++nIndex)
	{
		var nRowIndex = arrSelectedCells[nIndex].Row;

		if (-1 === nStartRow || nStartRow > nRowIndex)
			nStartRow = nRowIndex;

		if (-1 === nEndRow || nEndRow < nRowIndex)
			nEndRow = nRowIndex;
	}

	return {
		Start : nStartRow,
		End   : nEndRow
	};
};
/**
 * Получаем количество строк в заголовке таблицы
 * @returns {number}
 */
CTable.prototype.GetRowsCountInHeader = function()
{
	var nRowsInHeader = 0;
	for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
	{
		if (true === this.Content[nCurRow].IsHeader())
			nRowsInHeader++;
		else
			break;
	}

	return nRowsInHeader;
};
CTable.prototype.GetTopElement = function()
{
    if (!this.Parent)
        return null;

    if (true === this.Parent.Is_TopDocument(false))
        return this;

    return this.Parent.GetTopElement();
};
CTable.prototype.Get_RowsCount = function()
{
    return this.Content.length;
};
CTable.prototype.Get_Row = function(Index)
{
    return this.Content[Index];
};
CTable.prototype.GetRowsCount = function()
{
	return this.Content.length;
};
/**
 * Получаем строку с заданным номером
 * @param {number} nIndex
 * @returns {CTableRow}
 */
CTable.prototype.GetRow = function(nIndex)
{
	return this.Get_Row(nIndex);
};
CTable.prototype.CompareDrawingsLogicPositions = function(CompareObject)
{
    for (var CurRow = 0, RowsCount = this.Get_RowsCount(); CurRow < RowsCount; CurRow++)
    {
        var Row = this.Get_Row(CurRow);
        for (var CurCell = 0, CellsCount = Row.Get_CellsCount(); CurCell < CellsCount; CurCell++)
        {
            var Cell = Row.Get_Cell(CurCell);
            Cell.Content.CompareDrawingsLogicPositions(CompareObject);

            if (0 !== CompareObject.Result)
                return;
        }
    }
};
CTable.prototype.StartSelectionFromCurPos = function()
{
	this.Selection.Use = true;

	this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
	this.Selection.EndPos.Pos   = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
	this.private_UpdateSelectedCellsArray();

	var oLogicDocument = this.LogicDocument;
	if (oLogicDocument)
	{
		var oRealPos              = oLogicDocument.GetCursorRealPosition();
		this.Selection.StartPos.X = oRealPos.X;
		this.Selection.StartPos.Y = oRealPos.Y;
	}

	// В функции private_UpdateSelectedCellsArray выставляется тип по ячеейкам, но нам нужен внутри ячейки изначальный селект
	this.Selection.Type   = table_Selection_Text;
	this.Selection.CurRow = this.CurCell.Row.Index;


	this.CurCell.Content.StartSelectionFromCurPos();
};
CTable.prototype.GetStyleFromFormatting = function()
{
    var SelectionArray = this.Internal_Get_SelectionArray();
    if (SelectionArray.length > 0)
    {
        var Pos = SelectionArray[0];
        var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
        return Cell.Content.GetStyleFromFormatting();
    }
    return null;
};
CTable.prototype.Set_ReviewType = function(ReviewType)
{

};
CTable.prototype.Get_ReviewType = function()
{
    return reviewtype_Common;
};
CTable.prototype.Get_SectPr = function()
{
    if (this.Parent && this.Parent.Get_SectPr)
    {
        this.Parent.Update_ContentIndexing();
        return this.Parent.Get_SectPr(this.Index);
    }

    return null;
};
CTable.prototype.IsSelectedAll = function()
{
    if (true !== this.Selection.Use)
        return false;

    var ArrayPos = 0;
    var SelectionArray = this.Selection.Data;
    for (var CurRow = 0, RowsCount = this.Content.length; CurRow < RowsCount; CurRow++)
    {
        var Row = this.Content[CurRow];
        for (var CurCell = 0, CellsCount = Row.Get_CellsCount(); CurCell < CellsCount; CurCell++, ArrayPos++)
        {
            if (ArrayPos >= SelectionArray.length)
                return false;

            var Pos = SelectionArray[ArrayPos];
            if (Pos.Row !== CurRow || Pos.Cell !== CurCell)
                return false;
        }
    }

    return true;
};
CTable.prototype.AcceptRevisionChanges = function(Type, bAll)
{
    if (true === this.ApplyToAll || (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0))
    {
        var Cells_array = this.Internal_Get_SelectionArray();
        for (var Index = 0, Count = Cells_array.length; Index < Count; Index++)
        {
            var Pos = Cells_array[Index];
            var Row = this.Content[Pos.Row];
            var Cell = Row.Get_Cell(Pos.Cell);
            var Cell_Content = Cell.Content;

            Cell.Content.AcceptRevisionChanges(Type, true);
        }
    }
    else
        return this.CurCell.Content.AcceptRevisionChanges(Type, bAll);
};
CTable.prototype.RejectRevisionChanges = function(Type, bAll)
{
    if (true === this.ApplyToAll || (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0))
    {
        var Cells_array = this.Internal_Get_SelectionArray();
        for (var Index = 0, Count = Cells_array.length; Index < Count; Index++)
        {
            var Pos = Cells_array[Index];
            var Row = this.Content[Pos.Row];
            var Cell = Row.Get_Cell(Pos.Cell);
            var Cell_Content = Cell.Content;

            Cell_Content.RejectRevisionChanges(Type, true);
        }
    }
    else
        return this.CurCell.Content.RejectRevisionChanges(Type, bAll);
};
CTable.prototype.GetRevisionsChangeParagraph = function(SearchEngine)
{
    if (true === SearchEngine.Is_Found())
        return;

    var CurCell = 0, CurRow = 0;
    if (true !== SearchEngine.Is_CurrentFound())
    {
        var Cells_array = this.Internal_Get_SelectionArray();
        if (Cells_array.length <= 0)
            return;

        CurRow  = Cells_array[0].Row;
        CurCell = Cells_array[0].Cell;
    }
    else
    {
        if (SearchEngine.Get_Direction() > 0)
        {
            CurRow  = 0;
            CurCell = 0;
        }
        else
        {
            CurRow  = this.Get_RowsCount() - 1;
            CurCell = this.Get_Row(CurRow).Get_CellsCount() - 1;
        }
    }

    var Cell = this.Get_Row(CurRow).Get_Cell(CurCell);

    while (null != Cell && vmerge_Restart != Cell.GetVMerge())
        Cell = this.private_GetPrevCell(CurRow, CurCell);

    Cell.Content.GetRevisionsChangeParagraph(SearchEngine);
    while (true !== SearchEngine.Is_Found())
    {
        if (SearchEngine.Get_Direction() > 0)
        {
            Cell = this.private_GetNextCell(Cell.Row.Index, Cell.Index);
            while (null != Cell && vmerge_Restart != Cell.GetVMerge())
                Cell = this.private_GetNextCell(Cell.Row.Index, Cell.Index);
        }
        else
        {
            Cell = this.private_GetPrevCell(Cell.Row.Index, Cell.Index);
            while (null != Cell && vmerge_Restart != Cell.GetVMerge())
                Cell = this.private_GetPrevCell(Cell.Row.Index, Cell.Index);
        }

        if (null === Cell)
            break;

        Cell.Content.GetRevisionsChangeParagraph(SearchEngine);
    }
};
CTable.prototype.private_GetNextCell = function(RowIndex, CellIndex)
{
    return this.Internal_Get_NextCell({Cell : CellIndex, Row : RowIndex});
};
CTable.prototype.private_GetPrevCell = function(RowIndex, CellIndex)
{
    return this.Internal_Get_PrevCell({Cell : CellIndex, Row : RowIndex});
};
CTable.prototype.Check_ChangedTableGrid = function()
{
    var TableGrid_old = this.Internal_Copy_Grid(this.TableGridCalc);
    this.private_RecalculateGrid();
    var TableGrid_new = this.TableGridCalc;
    for (var CurCol = 0, ColsCount = this.TableGridCalc.length; CurCol < ColsCount; CurCol++)
    {
        if (Math.abs(TableGrid_old[CurCol] - TableGrid_new[CurCol]) > 0.001)
        {
            this.RecalcInfo.TableBorders = true;
            return true;
        }
    }

    return false;
};
CTable.prototype.GetContentPosition = function(bSelection, bStart, PosArray)
{
    if (!PosArray)
        PosArray = [];

    var CurRow  = (true === bSelection ? (true === bStart ? this.Selection.StartPos.Pos.Row  : this.Selection.EndPos.Pos.Row)  : this.CurCell.Row.Index);
    var CurCell = (true === bSelection ? (true === bStart ? this.Selection.StartPos.Pos.Cell : this.Selection.EndPos.Pos.Cell) : this.CurCell.Index);

    var Row = this.Get_Row(CurRow);
    PosArray.push({Class : this, Position : CurRow, Type : this.Selection.Type, Type2 : this.Selection.Type2});
    PosArray.push({Class : this.Get_Row(CurRow), Position : CurCell});

    if (Row && CurCell >= 0 && CurCell < Row.Get_CellsCount())
    {
        var Cell = Row.Get_Cell(CurCell);
        Cell.Content.GetContentPosition(bSelection, bStart, PosArray);
    }

    return PosArray;
};
CTable.prototype.Get_Index = function()
{
    if (!this.Parent)
        return -1;

    this.Parent.Update_ContentIndexing();
    return this.Index;
};
CTable.prototype.SetContentSelection = function(StartDocPos, EndDocPos, Depth, StartFlag, EndFlag)
{
    if ((0 === StartFlag && (!StartDocPos[Depth] || this !== StartDocPos[Depth].Class)) || (0 === EndFlag && (!EndDocPos[Depth] || this !== EndDocPos[Depth].Class)))
        return;

    var isOneElement = true;
    var StartRow = 0;
    switch (StartFlag)
    {
        case 0 : StartRow = StartDocPos[Depth].Position; break;
        case 1 : StartRow = 0; isOneElement = false; break;
        case -1: StartRow = this.Content.length - 1; isOneElement = false; break;
    }

    var EndRow = 0;
    switch (EndFlag)
    {
        case 0 : EndRow = EndDocPos[Depth].Position; break;
        case 1 : EndRow = 0; isOneElement = false; break;
        case -1: EndRow = this.Content.length - 1; isOneElement = false; break;
    }

    var _StartDocPos = StartDocPos, _StartFlag = StartFlag;
    if (null !== StartDocPos && true === StartDocPos[Depth].Deleted)
    {
        if (StartRow < this.Content.length)
        {
            _StartDocPos = null;
            _StartFlag = 1;
        }
        else if (StartRow > 0)
        {
            StartRow--;
            _StartDocPos = null;
            _StartFlag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    var _EndDocPos = EndDocPos, _EndFlag = EndFlag;
    if (null !== EndDocPos && true === EndDocPos[Depth].Deleted)
    {
        if (EndRow < this.Content.length)
        {
            _EndDocPos = null;
            _EndFlag = 1;
        }
        else if (EndRow > 0)
        {
            EndRow--;
            _EndDocPos = null;
            _EndFlag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    var StartCell = 0;
    switch (_StartFlag)
    {
        case 0 : StartCell = _StartDocPos[Depth + 1].Position; break;
        case 1 : StartCell = 0; break;
        case -1: StartCell = this.Content[StartRow].Get_CellsCount() - 1; break;
    }

    var EndCell = 0;
    switch (_EndFlag)
    {
        case 0 : EndCell = _EndDocPos[Depth + 1].Position; break;
        case 1 : EndCell = 0; break;
        case -1: EndCell = this.Content[EndRow].Get_CellsCount() - 1; break;
    }

    var __StartDocPos = _StartDocPos, __StartFlag = _StartFlag;
    if (null !== _StartDocPos && true === _StartDocPos[Depth + 1].Deleted)
    {
        if (StartCell < this.Content[StartRow].Get_CellsCount())
        {
            __StartDocPos = null;
            __StartFlag = 1;
        }
        else if (StartCell > 0)
        {
            StartCell--;
            __StartDocPos = null;
            __StartFlag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    var __EndDocPos = _EndDocPos, __EndFlag = _EndFlag;
    if (null !== _EndDocPos && true === _EndDocPos[Depth + 1].Deleted)
    {
        if (EndCell < this.Content[EndCell].Get_CellsCount())
        {
            __EndDocPos = null;
            __EndFlag   = 1;
        }
        else if (EndCell > 0)
        {
            EndCell--;
            __EndDocPos = null;
            __EndFlag   = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    this.Selection.Use          = true;
    this.Selection.StartPos.Pos = {Row : StartRow, Cell : StartCell};
    this.Selection.EndPos.Pos   = {Row : EndRow, Cell : EndCell};
    this.Selection.CurRow       = EndRow;
    this.Selection.Data         = null;
    this.Selection.Type2        = table_Selection_Common;
    this.Selection.Data2        = null;

    if (StartRow === EndRow && StartCell === EndCell)
    {
        this.CurCell = this.Get_Row(StartRow).Get_Cell(StartCell);
        this.Selection.Type = table_Selection_Text;
        this.CurCell.Content.SetContentSelection(__StartDocPos, __EndDocPos, Depth + 2, __StartFlag, __EndFlag);
    }
    else
    {
        this.Selection.Type = table_Selection_Cell;
        this.private_UpdateSelectedCellsArray(isOneElement ? false : true);
    }

    if (null !== EndDocPos && undefined !== EndDocPos[Depth].Type && undefined !== EndDocPos[Depth].Type2)
	{
		this.Selection.Type  = EndDocPos[Depth].Type;
		this.Selection.Type2 = EndDocPos[Depth].Type2;

		if (table_Selection_Cell === this.Selection.Type)
			this.private_UpdateSelectedCellsArray(!isOneElement || table_Selection_Rows === this.Selection.Type2 ? true : false);
	}
};
CTable.prototype.SetContentPosition = function(DocPos, Depth, Flag)
{
	if (this.GetRowsCount() <= 0)
		return;

    if (0 === Flag && (!DocPos[Depth] || this !== DocPos[Depth].Class))
        return;

    var CurRow = 0;
    switch (Flag)
    {
        case 0 : CurRow = DocPos[Depth].Position; break;
        case 1 : CurRow = 0; break;
        case -1: CurRow = this.Content.length - 1; break;
    }

    var _DocPos = DocPos, _Flag = Flag;
    if (null !== DocPos && true === DocPos[Depth].Deleted)
    {
        if (CurRow < this.Content.length)
        {
            _DocPos = null;
            _Flag = 1;
        }
        else if (CurRow > 0)
        {
            CurRow--;
            _DocPos = null;
            _Flag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    if (CurRow >= this.GetRowsCount())
	{
		CurRow  = this.GetRowsCount() - 1;
		_DocPos = null;
		_Flag   = -1;
	}
	else if (CurRow < 0)
	{
		CurRow  = 0;
		_DocPos = null;
		_Flag   = 1;
	}

	var Row = this.GetRow(CurRow);
    if (!Row)
    	return;

    var CurCell = 0;
    switch (_Flag)
    {
        case 0 : CurCell = _DocPos[Depth + 1].Position; break;
        case 1 : CurCell = 0; break;
        case -1: CurCell = Row.GetCellsCount() - 1; break;
    }

    var __DocPos = _DocPos, __Flag = _Flag;
    if (null !== _DocPos && true === _DocPos[Depth + 1].Deleted)
    {
        if (CurCell < Row.GetCellsCount())
        {
            __DocPos = null;
            __Flag = 1;
        }
        else if (CurCell > 0)
        {
            CurCell--;
            __DocPos = null;
            __Flag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    if (CurCell >= Row.GetCellsCount())
	{
		CurCell  = Row.GetCellsCount() - 1;
		__DocPos = null;
		__Flag   = -1;
	}
	else if (CurCell < 0)
	{
		CurCell  = 0;
		__DocPos = null;
		__Flag   = 1;
	}

    var Cell = Row.GetCell(CurCell);
    if (!Cell)
        return;

    this.CurCell = Cell;
    this.CurCell.Content.SetContentPosition(__DocPos, Depth + 2, __Flag);
};
CTable.prototype.Set_CurCell = function(Cell)
{
    if (!Cell || this !== Cell.Get_Table())
        return;

    this.CurCell = Cell;
};
CTable.prototype.IsEmptyPage = function(CurPage)
{
    if (!this.Pages[CurPage]
        || (this.Pages[CurPage].LastRow < this.Pages[CurPage].FirstRow)
        || (0 === CurPage && true !== this.RowsInfo[0].FirstPage))
        return true;

    return false;
};
CTable.prototype.Check_EmptyPages = function(CurPage)
{
    for (var _CurPage = CurPage; _CurPage >= 0; --_CurPage)
    {
        if (true !== this.IsEmptyPage(_CurPage))
            return false;
    }

    return true;
};
CTable.prototype.private_StartTrackTable = function(CurPage)
{
    if (CurPage < 0 || CurPage >= this.Pages.length)
        return;

    var Bounds     = this.Get_PageBounds(CurPage);
    var NewOutline = new AscCommon.CTableOutline(this, this.Get_AbsolutePage(CurPage), Bounds.Left, Bounds.Top, Bounds.Right - Bounds.Left, Bounds.Bottom - Bounds.Top);

    var Transform = this.Get_ParentTextTransform();
    this.DrawingDocument.StartTrackTable(NewOutline, Transform);
};
CTable.prototype.Correct_BadTable = function()
{
    // TODO: Пока оставим эту заглушку на случай загрузки плохих таблиц. В будущем надо будет
    //       сделать нормальный обсчет для случая, когда у нас есть "пустые" строки (составленные
    //       из вертикально объединенных ячеек).
    this.Internal_Check_TableRows(false);
	this.CorrectBadGrid();
	this.CorrectHMerge();
	this.CorrectVMerge();
};
/**
 * Специальная функция, которая обрабатывает устаревший параметр HMerge и заменяет его на GridSpan во время открытия файла
 */
CTable.prototype.CorrectHMerge = function()
{
	// HACK: При загрузке мы запрещаем компилировать стили, но нам все-таки это здесь нужно
	var bLoad = AscCommon.g_oIdCounter.m_bLoad;
	var bRead = AscCommon.g_oIdCounter.m_bRead;
	AscCommon.g_oIdCounter.m_bLoad = false;
	AscCommon.g_oIdCounter.m_bRead = false;

	var nColsCount = this.TableGrid.length;

	for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
	{
		var oRow = this.GetRow(nCurRow);

		var nCurGridCol = oRow.GetBefore().Grid;
		for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			var oCell = oRow.GetCell(nCurCell);

			var nGridSpan = oCell.GetGridSpan();

			var nWType    = oCell.GetW().Type;
			var nWValue   = oCell.GetW().W;

			if (nCurCell < nCellsCount - 1)
			{
				var nNextCurCell = nCurCell + 1;
				while (nNextCurCell < nCellsCount)
				{
					var oNextCell = oRow.GetCell(nNextCurCell);

					if (vmerge_Continue === oNextCell.GetHMerge())
					{
						nGridSpan += oNextCell.GetGridSpan();
						oRow.RemoveCell(nNextCurCell);
						nCellsCount--;
						nNextCurCell--;

						if (nWType === oNextCell.GetW().Type)
							nWValue += oNextCell.GetW().Value;
					}
					else
					{
						break;
					}

					nNextCurCell++;
				}
			}

			if (nGridSpan !== oCell.GetGridSpan())
			{
				if (nGridSpan + nCurGridCol > nColsCount)
					nGridSpan = Math.max(1, nColsCount - nCurGridCol);

				oCell.SetGridSpan(nGridSpan);
				oCell.SetW(new CTableMeasurement(nWType, nWValue));
			}

			nCurGridCol += nGridSpan;
		}
	}

	// HACK: Восстанавливаем флаги и выставляем, что стиль всей таблицы нужно пересчитать
	AscCommon.g_oIdCounter.m_bLoad = bLoad;
	AscCommon.g_oIdCounter.m_bRead = bRead;
	this.Recalc_CompiledPr2();
};
/**
 * Специальная функция, проверяющая, чтобы в первой строке не было ячеек с параметром vmerge_Continue
 * @constructor
 */
CTable.prototype.CorrectVMerge = function()
{
	if (this.GetRowsCount() <= 0)
		return;

	// HACK: При загрузке мы запрещаем компилировать стили, но нам все-таки это здесь нужно
	var bLoad = AscCommon.g_oIdCounter.m_bLoad;
	var bRead = AscCommon.g_oIdCounter.m_bRead;
	AscCommon.g_oIdCounter.m_bLoad = false;
	AscCommon.g_oIdCounter.m_bRead = false;

	var oRow = this.GetRow(0);

	for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
	{
		var oCell   = oRow.GetCell(nCurCell);
		var nVMerge = oCell.GetVMerge();

		if (vmerge_Continue === oCell.GetVMerge())
			oCell.SetVMerge(vmerge_Restart);
	}

	// HACK: Восстанавливаем флаги и выставляем, что стиль всей таблицы нужно пересчитать
	AscCommon.g_oIdCounter.m_bLoad = bLoad;
	AscCommon.g_oIdCounter.m_bRead = bRead;
	this.Recalc_CompiledPr2();
};
CTable.prototype.GetNumberingInfo = function(oNumberingEngine)
{
    if (oNumberingEngine.IsStop())
        return;

    for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
    {
        var oRow = this.GetRow(nCurRow);
        for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
        {
            var oCell = oRow.GetCell(nCurCell);
            oCell.GetContent().GetNumberingInfo(oNumberingEngine);

            if (oNumberingEngine.IsStop())
                return;
        }
    }
};
CTable.prototype.IsTableFirstRowOnNewPage = function(CurRow)
{
    for (var CurPage = 0, PagesCount = this.Pages.length; CurPage < PagesCount; ++CurPage)
    {
        if (CurRow === this.Pages[CurPage].FirstRow && CurRow <= this.Pages[CurPage].LastRow)
        {
            if (0 === CurPage
				&& (null != this.Get_DocumentPrev()
				|| (true === this.Parent.IsTableCellContent() && true !== this.Parent.IsTableFirstRowOnNewPage())
				|| (true === this.Parent.IsBlockLevelSdtContent() && true !== this.Parent.IsBlockLevelSdtFirstOnNewPage())))
                return false;

            return true;
        }
    }

    return false;
};
CTable.prototype.private_UpdateCellsGrid = function()
{
    for (var nCurRow = 0, nRowsCount = this.Content.length; nCurRow < nRowsCount; ++nCurRow)
    {
        var Row        = this.Content[nCurRow];
        var BeforeInfo = Row.Get_Before();
        var CurGridCol = BeforeInfo.GridBefore;

        for (var nCurCell = 0, nCellsCount = Row.Get_CellsCount(); nCurCell < nCellsCount; ++nCurCell)
        {
            var Cell = Row.Get_Cell(nCurCell);
            var GridSpan = Cell.Get_GridSpan();
            Cell.Set_Metrics(CurGridCol, 0, 0, 0, 0, 0, 0);
            Row.Update_CellInfo(nCurCell);
            CurGridCol += GridSpan;
        }
    }
};
CTable.prototype.SetTableGrid = function(arrGrid)
{
	History.Add(new CChangesTableTableGrid(this, this.TableGrid, arrGrid));
	this.TableGrid = arrGrid;
};
/**
 * Получаем ширину заданного промежутка в сетке таблицы
 * @param nStartCol
 * @param nGridSpan
 * @returns {number}
 */
CTable.prototype.GetSpanWidth = function(nStartCol, nGridSpan)
{
	if (nStartCol < 0 || nStartCol + nGridSpan < 0 || nGridSpan <= 0 || nStartCol + nGridSpan > this.TableGrid.length)
		return 0;

	var nSum = 0;
	for (var nCurCol = nStartCol; nCurCol < nStartCol + nGridSpan; ++nCurCol)
	{
		nSum += this.TableGrid[nCurCol];
	}

	return nSum;
};
CTable.prototype.private_CopyTableGrid = function()
{
	var arrGrid = [];
	for (var nIndex = 0, nCount = this.TableGrid.length; nIndex < nCount; ++nIndex)
	{
		arrGrid[nIndex] = this.TableGrid[nIndex];
	}
	return arrGrid;
};
CTable.prototype.private_CopyTableGridCalc = function()
{
	var arrGrid = [];
	for (var nIndex = 0, nCount = this.TableGridCalc.length; nIndex < nCount; ++nIndex)
	{
		arrGrid[nIndex] = this.TableGridCalc[nIndex];
	}
	return arrGrid;
};
CTable.prototype.CorrectBadGrid = function()
{
	// HACK: При загрузке мы запрещаем компилировать стили, но нам все-таки это здесь нужно
	var bLoad = AscCommon.g_oIdCounter.m_bLoad;
	var bRead = AscCommon.g_oIdCounter.m_bRead;
	AscCommon.g_oIdCounter.m_bLoad = false;
	AscCommon.g_oIdCounter.m_bRead = false;

	// Сначала пробежимся по всем ячейкам и посмотрим, чтобы у них были корректные GridSpan (т.е. >= 1)
	for (var Index = 0; Index < this.Content.length; Index++)
	{
		var Row        = this.Content[Index];
		var CellsCount = Row.Get_CellsCount();
		for (var CellIndex = 0; CellIndex < CellsCount; CellIndex++)
		{
			var Cell     = Row.Get_Cell(CellIndex);
			var GridSpan = Cell.Get_GridSpan();
			if (GridSpan <= 0)
				Cell.Set_GridSpan(1);
		}
	}

	var RowGrid   = [];
	var GridCount = 0;
	for (var Index = 0; Index < this.Content.length; Index++)
	{
		var Row = this.Content[Index];
		Row.Set_Index(Index);

		// Смотрим на ширину пропущенных колонок сетки в начале строки
		var BeforeInfo = Row.Get_Before();
		var CurGridCol = BeforeInfo.GridBefore;

		var CellsCount = Row.Get_CellsCount();
		for (var CellIndex = 0; CellIndex < CellsCount; CellIndex++)
		{
			var Cell     = Row.Get_Cell(CellIndex);
			var GridSpan = Cell.Get_GridSpan();
			CurGridCol += GridSpan;
		}

		// Смотрим на ширину пропущенных колонок сетки в конце строки
		var AfterInfo = Row.Get_After();
		CurGridCol += AfterInfo.GridAfter;

		if (GridCount < CurGridCol)
			GridCount = CurGridCol;

		RowGrid[Index] = CurGridCol;
	}

	for (var Index = 0; Index < this.Content.length; Index++)
	{
		var Row       = this.Content[Index];
		var AfterInfo = Row.Get_After();

		if (RowGrid[Index] < GridCount)
		{
			Row.Set_After(AfterInfo.GridAfter + GridCount - RowGrid[Index], AfterInfo.WAfter);
		}
	}

	var arrGrid = this.private_CopyTableGrid();
	if (arrGrid.length != GridCount)
	{
		if (arrGrid.length < GridCount)
		{
			for (var nIndex = 0; nIndex < GridCount; ++nIndex)
				arrGrid[nIndex] = 20;
		}
		else
		{
			arrGrid.splice(GridCount, arrGrid.length - GridCount);
		}
		this.SetTableGrid(arrGrid);
	}

	// HACK: Восстанавливаем флаги и выставляем, что стиль всей таблицы нужно пересчитать
	AscCommon.g_oIdCounter.m_bLoad = bLoad;
	AscCommon.g_oIdCounter.m_bRead = bRead;
	this.Recalc_CompiledPr2();
};
CTable.prototype.private_CorrectVerticalMerge = function()
{
	// Пробегаемся по всем ячейкам и смотрим на их вертикальное объединение, было ли оно нарушено
	for (var nCurRow = 0, nRowsCount = this.Content.length; nCurRow < nRowsCount; ++nCurRow)
	{
		var oRow     = this.Content[nCurRow];
		var nGridCol = oRow.Get_Before().GridBefore;
		for (var nCurCell = 0, nCellsCount = oRow.Get_CellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			var oCell       = oRow.Get_Cell(nCurCell);
			var nVMergeType = oCell.GetVMerge();
			var nGridSpan   = oCell.Get_GridSpan();

			if (vmerge_Continue === nVMergeType)
			{
				var bNeedReset = true;
				if (0 !== nCurRow)
				{
					var oPrevRow     = this.Content[nCurRow - 1];
					var nPrevGridCol = oPrevRow.Get_Before().GridBefore;
					for (var nPrevCell = 0, nPrevCellsCount = oPrevRow.Get_CellsCount(); nPrevCell < nPrevCellsCount; ++nPrevCell)
					{
						var oPrevCell     = oPrevRow.Get_Cell(nPrevCell);
						var nPrevGridSpan = oPrevCell.Get_GridSpan();

						if (nPrevGridCol === nGridCol)
						{
							if (nPrevGridSpan === nGridSpan)
								bNeedReset = false;

							break;
						}
						else if (nPrevGridCol > nGridCol)
							break;

						nPrevGridCol += nPrevGridSpan;
					}
				}

				if (true === bNeedReset)
					oCell.SetVMerge(vmerge_Restart);
			}

			nGridCol += nGridSpan;
		}
	}
};
CTable.prototype.private_SetTableLayoutFixedAndUpdateCellsWidth = function(nExceptColNum)
{
	if (tbllayout_AutoFit === this.Get_CompiledPr(false).TablePr.TableLayout)
	{
		this.SetTableLayout(tbllayout_Fixed);

		// Обновляем ширины ячеек
		var nColsCount = this.TableGrid.length;
		for (var nColIndex = 0; nColIndex < nColsCount; nColIndex++)
		{
			if (nColIndex != nExceptColNum)
				this.Internal_UpdateCellW(nColIndex);
		}
	}
};
CTable.prototype.GotoFootnoteRef = function(isNext, isCurrent)
{
	var nRow = 0, nCell = 0;
	if (true === isCurrent)
	{
		if (true === this.Selection.Use)
		{
			var nStartRow  = this.Selection.StartPos.Pos.Row;
			var nStartCell = this.Selection.StartPos.Pos.Cell;

			var nEndRow  = this.Selection.EndPos.Pos.Row;
			var nEndCell = this.Selection.EndPos.Pos.Cell;

			if (nStartRow < nEndRow || (nStartRow === nEndRow && nStartCell <= nEndCell))
			{
				nRow  = nStartRow;
				nCell = nStartCell;
			}
			else
			{
				nRow  = nEndRow;
				nCell = nEndCell;
			}
		}
		else
		{
			nCell = this.CurCell.Index;
			nRow  = this.CurCell.Row.Index;
		}
	}
	else
	{
		if (true === isNext)
		{
			nRow = 0;
			nCell = 0;
		}
		else
		{
			nRow  = this.Content.length - 1;
			nCell = this.Content[nRow].Get_CellsCount() - 1;
		}
	}

	if (true === isNext)
	{
		for (var nCurRow = nRow, nRowsCount = this.Content.length; nCurRow < nRowsCount; ++nCurRow)
		{
			var oRow = this.Content[nCurRow];
			var nStartCell = (nCurRow === nRow ? nCell : 0);
			for (var nCurCell = nStartCell, nCellsCount = oRow.Get_CellsCount(); nCurCell < nCellsCount; ++nCurCell)
			{
				var oCell = oRow.Get_Cell(nCurCell);
				if (oCell.Content.GotoFootnoteRef(true, true === isCurrent && nCurRow === nRow && nCurCell === nCell))
					return true;
			}
		}
	}
	else
	{
		for (var nCurRow = nRow; nCurRow >= 0; --nCurRow)
		{
			var oRow = this.Content[nCurRow];
			var nStartCell = (nCurRow === nRow ? nCell : oRow.Get_CellsCount() - 1);
			for (var nCurCell = nStartCell; nCurCell >= 0; --nCurCell)
			{
				var oCell = oRow.Get_Cell(nCurCell);
				if (oCell.Content.GotoFootnoteRef(false, true === isCurrent && nCurRow === nRow && nCurCell === nCell))
					return true;
			}
		}
	}

	return false;
};
/**
 * Проверяем можно ли обновлять положение курсора на заданной странице
 * @param nCurPage
 * @returns {boolean}
 */
CTable.prototype.CanUpdateTarget = function(nCurPage)
{
	if (this.Pages.length <= 0 || !this.Pages[nCurPage])
		return false;

	var oRow, oCell;
	if (this.IsSelectionUse())
	{
		oRow  = this.GetRow(this.Selection.EndPos.Pos.Row);
		oCell = oRow.GetCell(this.Selection.EndPos.Pos.Cell);
	}
	else
	{
		oCell = this.CurCell;
		oRow  = this.CurCell.GetRow();
	}

	if (!oRow || !oCell)
		return false;

	if (this.Pages[nCurPage].LastRow > oRow.Index)
		return true;
	else if (this.Pages[nCurPage].LastRow < oRow.Index)
		return false;

	return oCell.Content.CanUpdateTarget(nCurPage - oCell.Content.Get_StartPage_Relative());
};
/**
 * Проверяем, выделение идет по  ячейкам или нет
 * @returns {boolean}
 */
CTable.prototype.IsCellSelection = function()
{
	if (true === this.ApplyToAll
		|| (this.IsSelectionUse()
		&& table_Selection_Cell === this.Selection.Type
		&& this.Selection.Data.length > 0))
		return true;

	return false;
};
CTable.prototype.SetTableProps = function(oProps)
{
	return this.Set_Props(oProps);
};
CTable.prototype.GetTableProps = function()
{
	return this.Get_Props();
};
CTable.prototype.AddContentControl = function(nContentControlType)
{
	if (this.CurCell)
		return this.CurCell.Content.AddContentControl(nContentControlType);

	return null;
};
CTable.prototype.GetAllContentControls = function(arrContentControls)
{
	for (var nCurRow = 0, nRowsCount = this.Content.length; nCurRow < nRowsCount; ++nCurRow)
	{
		var oRow = this.Content[nCurRow];
		for (var nCurCell = 0, nCellsCount = oRow.Get_CellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			var oCell = oRow.Get_Cell(nCurCell);
			oCell.Content.GetAllContentControls(arrContentControls);
		}
	}
};
CTable.prototype.GetOutlineParagraphs = function(arrOutline, oPr)
{
	if (oPr && oPr.SkipTables)
		return;

	for (var nCurRow = 0, nRowsCount = this.Content.length; nCurRow < nRowsCount; ++nCurRow)
	{
		var oRow = this.Content[nCurRow];
		for (var nCurCell = 0, nCellsCount = oRow.Get_CellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			var oCell = oRow.Get_Cell(nCurCell);
			if (oCell)
				oCell.Content.GetOutlineParagraphs(arrOutline, oPr);
		}
	}
};
CTable.prototype.GetSimilarNumbering = function(oContinueNumbering)
{
	if (oContinueNumbering.IsFound())
		return;

	for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
	{
		var oRow = this.GetRow(nCurRow);
		for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			oRow.GetCell(nCurCell).GetContent().GetSimilarNumbering(oContinueNumbering);

			if (oContinueNumbering.IsFound())
				break;
		}
	}
};
CTable.prototype.UpdateBookmarks = function(oManager)
{
	for (var nCurRow = 0, nRowsCount = this.Content.length; nCurRow < nRowsCount; ++nCurRow)
	{
		var oRow = this.Content[nCurRow];
		for (var nCurCell = 0, nCellsCount = oRow.Get_CellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			oRow.Get_Cell(nCurCell).Content.UpdateBookmarks(oManager);
		}
	}
};
/**
 * Вставляем содержимое заданной таблицы в текущую (специальная вставка)
 * @param _nRowIndex - Номер
 * @param _nCellIndex
 * @param oTable
 */
CTable.prototype.InsertTableContent = function(_nCellIndex, _nRowIndex, oTable)
{
	// Нужно пересчитать сетку, чтобы если придется добавлять новые ячейки сетка была рассчитана
	oTable.private_RecalculateGrid();
	oTable.private_RecalculateGridCols();

	var oCell = this.GetStartMergedCell(_nCellIndex, _nRowIndex);
	if (!oCell)
		return;

	var nCellIndex = oCell.Index;
	var nRowIndex  = oCell.Row.Index;

	if (nRowIndex >= this.GetRowsCount())
		return;

	// Добавляем новые строки, если необходимо
	var nAddRows = oTable.GetRowsCount() + nRowIndex - this.GetRowsCount();
	while (nAddRows > 0)
	{
		this.RemoveSelection();
		this.CurCell = this.GetRow(this.GetRowsCount() - 1).GetCell(0);
		this.AddTableRow(false);
		nAddRows--;

		this.private_RecalculateGridCols();
	}

	var arrClearedCells = [];
	function private_IsProcessedCell(oCell)
	{
		for (var nIndex = 0, nCount = arrClearedCells.length; nIndex < nCount; ++nIndex)
		{
			if (arrClearedCells[nIndex] === oCell)
				return true;
		}

		return false;
	}

	var isNeedRebuildGrid = false,
		arrRowsInfo       = this.private_GetRowsInfo();

	var oFirstCell = null;
	for (var nCurRow = 0, nRowsCount = oTable.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
	{
		var oInsertedRow = oTable.GetRow(nCurRow);
		var oCurRow = this.GetRow(nRowIndex + nCurRow);
		for (var nCurCell = 0, nCellsCount = oInsertedRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			var oCell = oCurRow.GetCell(nCellIndex + nCurCell);
			var oInsertedCell = oInsertedRow.GetCell(nCurCell);

			if (!oFirstCell)
				oFirstCell = oCell;

			if (!oCell)
			{
				var nCellPos = oCurRow.GetCellsCount();
				oCell = oInsertedCell.Copy(oCurRow);
				oCurRow.AddCell(nCellPos, oCurRow, oCell, true);
				isNeedRebuildGrid = true;
				this.private_AddCellToRowsInfo(arrRowsInfo, oCurRow.Index, nCellPos, oInsertedCell.GetCalculatedW());
			}
			else if (oCell)
			{
				var oTopCell = this.GetStartMergedCell(oCell.Index, oCell.Row.Index);
				if (oTopCell === oCell)
				{
					oCell.Content.ClearContent(false);
					oCell.Content.AddContent(oInsertedCell.Content.Content);
					arrClearedCells.push(oCell);
				}
				else
				{
					if (private_IsProcessedCell(oTopCell))
						oTopCell.Content.AddContent(oInsertedCell.Content.Content);
				}
			}
		}
	}

	if (true === isNeedRebuildGrid)
		this.private_CreateNewGrid(arrRowsInfo);


	this.RemoveSelection();
	if (oFirstCell)
	{
		this.CurCell = oFirstCell;
		this.SelectTable(c_oAscTableSelectionType.Cell);
	}
	else
	{
		this.MoveCursorToStartPos(false);
	}
	this.Document_SetThisElementCurrent(false);
};
/**
 * Изменяем размер тширину и высоту таблицы
 * @param nWidth
 * @param nHeight
 */
CTable.prototype.Resize = function(nWidth, nHeight)
{
	var nMinWidth  = this.GetMinWidth();
	var nMinHeight = this.GetMinHeight();

	var nSummaryHeight = this.GetSummaryHeight();

	var nCellSpacing = this.Content[0].GetCellSpacing();
	if (null !== nCellSpacing)
	{
		nSummaryHeight -= nCellSpacing * (this.GetRowsCount() + 1);
		nMinHeight     -= nCellSpacing * (this.GetRowsCount() + 1);

		for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
		{
			if (!this.RowsInfo[nCurRow])
				continue;

			nSummaryHeight -= this.RowsInfo[nCurRow].MaxTopBorder[0] + this.RowsInfo[nCurRow].MaxBotBorder;
			nMinHeight     -= this.RowsInfo[nCurRow].MaxTopBorder[0] + this.RowsInfo[nCurRow].MaxBotBorder;
		}

		var oTopBorder    = this.GetTopTableBorder();
		var oBottomBorder = this.GetBottomTableBorder();

		nSummaryHeight -= oTopBorder.GetWidth() + oBottomBorder.GetWidth();
		nMinHeight     -= oTopBorder.GetWidth() + oBottomBorder.GetWidth();
	}
	else
	{
		nSummaryHeight -= this.RowsInfo[this.RowsInfo.length - 1].MaxBotBorder;
		nMinHeight     -= this.RowsInfo[this.RowsInfo.length - 1].MaxBotBorder;
	}

	if (this.Pages.length <= 0)
		return;

	var oBounds = this.GetPageBounds(this.Pages.length - 1);
	var nDiffX  = nWidth - oBounds.Right + oBounds.Left;
	var nDiffY  = nHeight - oBounds.Bottom + oBounds.Top;

	var nSummaryWidth = oBounds.Right - oBounds.Left;

	if (nSummaryWidth + nDiffX < nMinWidth)
		nDiffX = nMinWidth - nSummaryWidth;

	if (nSummaryHeight + nDiffY < nMinHeight)
		nDiffY = nMinHeight - nSummaryHeight;

	if (nDiffY > 0.01)
	{
		var arrRowsH   = [];
		var nTableSumH = 0;

		for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
		{
			var nRowSummaryH = 0;
			for (var nCurPage in this.RowsInfo[nCurRow].H)
				nRowSummaryH += this.RowsInfo[nCurRow].H[nCurPage];

			arrRowsH[nCurRow] = nRowSummaryH;
			nTableSumH += nRowSummaryH;
		}

		for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
		{
			var oRow  = this.GetRow(nCurRow);
			var oRowH = oRow.GetHeight();
			var nNewH = arrRowsH[nCurRow] / nTableSumH * (nSummaryHeight + nDiffY);

			if (null !== nCellSpacing)
				nNewH += nCellSpacing;
			else if (this.RowsInfo[nCurRow] && this.RowsInfo[nCurRow].TopDy[0])
				nNewH -= this.RowsInfo[nCurRow].TopDy[0];

			var nTopMargin = 0,
				nBotMargin = 0;
			for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
			{
				var oCell    = oRow.GetCell(nCurCell);
				var oMargins = oCell.GetMargins();

				if (oMargins.Top.W > nTopMargin)
					nTopMargin = oMargins.Top.W;

				if (oMargins.Bottom.W > nBotMargin)
					nBotMargin = oMargins.Bottom.W;
			}

			nNewH -= nTopMargin + nBotMargin;

			oRow.SetHeight(nNewH, oRowH.HRule === Asc.linerule_Exact ? Asc.linerule_Exact : Asc.linerule_AtLeast);
		}
	}
	else if (nDiffY < -0.01)
	{
		var nNewTableH  = nSummaryHeight + nDiffY;
		var arrRowsMinH = [];
		var arrRowsH    = [];
		var nTableSumH  = 0;
		var arrRowsFlag = [];

		for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
		{
			var nRowSummaryH = 0;
			for (var nCurPage in this.RowsInfo[nCurRow].H)
				nRowSummaryH += this.RowsInfo[nCurRow].H[nCurPage];

			arrRowsH[nCurRow]    = nRowSummaryH;
			arrRowsMinH[nCurRow] = this.GetMinRowHeight(nCurRow);
			arrRowsFlag[nCurRow] = true;
			nTableSumH += nRowSummaryH;
		}

		var arrNewH = [];
		while (true)
		{
			var isForceBreak = false;
			var isContinue   = false;
			for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
			{
				if (arrRowsFlag[nCurRow])
				{
					arrNewH[nCurRow] = arrRowsH[nCurRow] / nTableSumH * nNewTableH;
					if (arrNewH[nCurRow] < arrRowsMinH[nCurRow])
					{
						nTableSumH -= arrRowsH[nCurRow];
						nNewTableH -= arrRowsMinH[nCurRow];
						arrNewH[nCurRow]  = arrRowsMinH[nCurRow];
						arrRowsFlag[nCurRow] = false;

						if (nNewTableH < 0.01 || nTableSumH < 0.01)
							isForceBreak = true;

						isContinue = true;
					}
				}
			}

			if (isForceBreak || !isContinue)
				break;
		}

		for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
		{
			if (undefined !== arrNewH[nCurRow])
			{
				var oRow  = this.GetRow(nCurRow);
				var oRowH = oRow.GetHeight();
				var nNewH = arrNewH[nCurRow];

				if (null !== nCellSpacing)
					nNewH += nCellSpacing;
				else if (this.RowsInfo[nCurRow] && this.RowsInfo[nCurRow].TopDy[0])
					nNewH -= this.RowsInfo[nCurRow].TopDy[0];

				var nTopMargin = 0,
					nBotMargin = 0;
				for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
				{
					var oCell    = oRow.GetCell(nCurCell);
					var oMargins = oCell.GetMargins();

					if (oMargins.Top.W > nTopMargin)
						nTopMargin = oMargins.Top.W;

					if (oMargins.Bottom.W > nBotMargin)
						nBotMargin = oMargins.Bottom.W;
				}

				nNewH -= nTopMargin + nBotMargin;

				oRow.SetHeight(nNewH, oRowH.HRule === Asc.linerule_Exact ? Asc.linerule_Exact : Asc.linerule_AtLeast);
			}
		}
	}

	this.private_RecalculateGrid();

	var nFinalTableSum = null;
	if (nDiffX > 0.001)
	{
		var arrColsW   = [];
		var nTableSumW = 0;

		for (var nCurCol = 0, nColsCount = this.TableGridCalc.length; nCurCol < nColsCount; ++nCurCol)
		{
			arrColsW[nCurCol] = this.TableGridCalc[nCurCol];
			nTableSumW       += arrColsW[nCurCol];
		}

		nFinalTableSum = 0;
		var arrNewGrid = [];
		for (var nCurCol = 0, nColsCount = this.TableGridCalc.length; nCurCol < nColsCount; ++nCurCol)
		{
			arrNewGrid[nCurCol] = arrColsW[nCurCol] / nTableSumW * (nTableSumW + nDiffX);
			nFinalTableSum += arrNewGrid[nCurCol];
		}

		this.SetTableGrid(arrNewGrid);
	}
	else if (nDiffX < -0.01)
	{
		var arrColsMinW = this.GetMinWidth(true);
		var arrColsW    = [];
		var nTableSumW  = 0;
		var arrColsFlag = [];

		for (var nCurCol = 0, nColsCount = this.TableGridCalc.length; nCurCol < nColsCount; ++nCurCol)
		{
			arrColsW[nCurCol]    = this.TableGridCalc[nCurCol];
			nTableSumW          += arrColsW[nCurCol];
			arrColsFlag[nCurCol] = true;
		}

		var nNewTableW = nTableSumW + nDiffX;
		var arrNewGrid = [];
		while (true)
		{
			var isForceBreak = false;
			var isContinue   = false;
			for (var nCurCol = 0, nColsCount = this.TableGridCalc.length; nCurCol < nColsCount; ++nCurCol)
			{
				if (arrColsFlag[nCurCol])
				{
					arrNewGrid[nCurCol] = arrColsW[nCurCol] / nTableSumW * nNewTableW;
					if (arrNewGrid[nCurCol] < arrColsMinW[nCurCol])
					{
						nTableSumW -= arrColsW[nCurCol];
						nNewTableW -= arrColsMinW[nCurCol];
						arrNewGrid[nCurCol]  = arrColsMinW[nCurCol];
						arrColsFlag[nCurCol] = false;

						if (nNewTableW < 0.01 || nTableSumW < 0.01)
							isForceBreak = true;

						isContinue = true;
					}
				}
			}

			if (isForceBreak || !isContinue)
				break;
		}

		nFinalTableSum = 0;
		for (var nCurCol = 0, nColsCount = this.TableGridCalc.length; nCurCol < nColsCount; ++nCurCol)
		{
			nFinalTableSum += arrNewGrid[nCurCol];
		}

		this.SetTableGrid(arrNewGrid);
	}

	var nPercentWidth = this.private_RecalculatePercentWidth();
	if (null !== nFinalTableSum)
	{
		for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
		{
			var oRow    = this.GetRow(nCurRow);
			var oBefore = oRow.GetBefore();
			if (oBefore.W && oBefore.Grid > 0)
			{
				var nW = this.GetSpanWidth(0, oBefore.Grid);
				if (oBefore.W.IsMM())
					oRow.SetBefore(oBefore.Grid, new CTableMeasurement(tblwidth_Mm, nW));
				else if (oBefore.W.IsPercent() && nPercentWidth > 0.001)
					oRow.SetBefore(oBefore.Grid, new CTableMeasurement(tblwidth_Pct, nW / nPercentWidth * 100));
				else
					oRow.SetBefore(oBefore.Grid, new CTableMeasurement(tblwidth_Auto, 0));
			}

			var nCellSpacing = oRow.GetCellSpacing();
			var nCurCol      = oBefore.Grid;
			for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
			{
				var oCell     = oRow.GetCell(nCurCell);
				var oCellW    = oCell.GetW();
				var nGridSpan = oCell.GetGridSpan();

				if (oCellW)
				{
					var nW = this.GetSpanWidth(nCurCol, nGridSpan);

					if (null !== nCellSpacing)
					{
						if (0 === nCurCell)
							nW -= nCellSpacing / 2;

						nW -= nCellSpacing;

						if (nCellsCount - 1 === nCurCell)
							nW -= nCellSpacing / 2;
					}

					if (oCellW.IsMM())
						oCell.SetW(new CTableMeasurement(tblwidth_Mm, nW));
					else if (oCellW.IsPercent() && nPercentWidth > 0.001)
						oCell.SetW(new CTableMeasurement(tblwidth_Pct, nW / nPercentWidth * 100));
					else
						oCell.SetW(new CTableMeasurement(tblwidth_Auto, 0));
				}

				nCurCol += nGridSpan;
			}

			var oAfter = oRow.GetAfter();
			if (oAfter.W && oAfter.Grid > 0)
			{
				var nW = this.GetSpanWidth(nCurCol, oAfter.Grid);
				if (oAfter.W.IsMM())
					oRow.SetAfter(oAfter.Grid, new CTableMeasurement(tblwidth_Mm, nW));
				else if (oAfter.W.IsPercent() && nPercentWidth > 0.001)
					oRow.SetAfter(oAfter.Grid, new CTableMeasurement(tblwidth_Pct, nW / nPercentWidth * 100));
				else
					oRow.SetAfter(oAfter.Grid, new CTableMeasurement(tblwidth_Auto, 0));
			}

		}

		var oTableW = this.GetTableW();
		if (oTableW)
		{
			if (oTableW.IsMM())
				this.SetTableW(tblwidth_Mm, nFinalTableSum);
			else if (oTableW.IsPercent() && nPercentWidth > 0.001)
				this.SetTableW(tblwidth_Pct, nFinalTableSum / nPercentWidth * 100);
			else
				this.SetTableW(tblwidth_Auto, 0);
		}
	}
};
/**
 * Изменяем размер тширину и высоту таблицы в документе (создается точка в истории и запускается пересчет)
 * @param nWidth
 * @param nHeight
 */
CTable.prototype.ResizeTableInDocument = function(nWidth, nHeight)
{
	if (!this.LogicDocument)
		return;

	if (true === this.LogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_Table_Properties, null, true))
		return;

	this.LogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_ResizeTable);

	this.Resize(nWidth, nHeight);

	this.LogicDocument.Recalculate();
	this.Start_TrackTable();
	this.LogicDocument.Document_UpdateSelectionState();
};
/**
 * Получаем минимальную ширину таблицы
 * @param {number} [isReturnByColumns=false]
 * @returns {number}
 */
CTable.prototype.GetMinWidth = function(isReturnByColumns)
{
	var arrMinMargin = [];

	var nGridCount = this.TableGrid.length;
	for (var nCurCol = 0; nCurCol < nGridCount; ++nCurCol)
	{
		arrMinMargin[nCurCol]  = 0;
	}

	for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
	{
		var oRow = this.Content[nCurRow];

		var nSpacing  = oRow.GetCellSpacing();

		var nCurGridCol = oRow.Get_Before().GridBefore;
		for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			var oCell         = oRow.GetCell(nCurCell);
			var nGridSpan     = oCell.GetGridSpan();
			var oCellMargins  = oCell.GetMargins();
			var oCellRBorder  = oCell.GetBorder(1);
			var oCellLBorder  = oCell.GetBorder(3);

			var nCellMarginsLeftW = 0, nCellMarginsRightW = 0;
			if (null !== nSpacing)
			{
				nCellMarginsLeftW  = oCellMargins.Left.W;
				nCellMarginsRightW = oCellMargins.Right.W;

				if (border_None !== oCellRBorder.Value)
					nCellMarginsRightW += oCellRBorder.Size;

				if (border_None !== oCellLBorder.Value)
					nCellMarginsLeftW += oCellLBorder.Size;
			}
			else
			{
				if (border_None !== oCellRBorder.Value)
					nCellMarginsRightW += Math.max(oCellRBorder.Size / 2, oCellMargins.Right.W);
				else
					nCellMarginsRightW += oCellMargins.Right.W;

				if (border_None !== oCellLBorder.Value)
					nCellMarginsLeftW += Math.max(oCellLBorder.Size / 2, oCellMargins.Left.W);
				else
					nCellMarginsLeftW += oCellMargins.Left.W;
			}

			if (nGridSpan <= 1)
			{
				if (arrMinMargin[nCurGridCol] < nCellMarginsLeftW + nCellMarginsRightW)
					arrMinMargin[nCurGridCol] = nCellMarginsLeftW + nCellMarginsRightW;
			}
			else
			{
				if (arrMinMargin[nCurGridCol] < nCellMarginsLeftW)
					arrMinMargin[nCurGridCol] = nCellMarginsLeftW;

				if (arrMinMargin[nCurGridCol + nGridSpan - 1] < nCellMarginsRightW)
					arrMinMargin[nCurGridCol + nGridSpan - 1] = nCellMarginsRightW;
			}

			nCurGridCol += nGridSpan;
		}
	}

	if (isReturnByColumns)
		return arrMinMargin;

	var nSumMin = 0;
	for (var nCurCol = 0; nCurCol < nGridCount; ++nCurCol)
	{
		nSumMin += arrMinMargin[nCurCol];
	}

	return nSumMin;
};
/**
 * Получаем минимальную высоту таблицы
 * @returns {number}
 */
CTable.prototype.GetMinHeight = function()
{
	var nSumMin = 0;
	for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
	{
		var oRow = this.Content[nCurRow];

		var nSpacing = oRow.GetCellSpacing();

		var nMaxTopMargin    = 0,
			nMaxBottomMargin = 0,
			nMaxTopBorder    = 0,
			nMaxBottomBorder = 0;

		for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			var oCell         = oRow.GetCell(nCurCell);
			var oCellMargins  = oCell.GetMargins();
			var oCellTBorder  = oCell.GetBorder(0);
			var oCellBBorder  = oCell.GetBorder(2);


			if (border_None !== oCellTBorder.Value && nMaxTopBorder < oCellTBorder.Size)
				nMaxTopBorder = oCellTBorder.Size;

			if (border_None !== oCellBBorder.Value && nMaxBottomBorder < oCellBBorder.Size)
				nMaxBottomBorder = oCellBBorder.Size;

			if (nMaxTopMargin < oCellMargins.Top.W)
				nMaxTopMargin = oCellMargins.Top.W;

			if (nMaxBottomMargin < oCellMargins.Bottom.W)
				nMaxBottomMargin = oCellMargins.Bottom.W;
		}

		nSumMin += 4.5; // Стандартная минимальная высота строки в таблице без учета границ и отступов

		if (null !== nSpacing)
		{
			if (0 === nCurRow)
				nSumMin += this.GetTopTableBorder().GetWidth();

			nSumMin += nSpacing;
			nSumMin += nMaxTopBorder;
			nSumMin += nMaxTopMargin;
			nSumMin += nMaxBottomMargin;
			nSumMin += nMaxBottomBorder;
			nSumMin += nRowsCount - 1 === nCurRow ? nSpacing : 0;

			if (nRowsCount - 1 === nCurRow)
				nSumMin += this.GetBottomTableBorder().GetWidth();
		}
		else
		{
			nSumMin += Math.max(nMaxTopBorder, nMaxTopMargin);
			nSumMin += nMaxBottomMargin;

			if (nRowsCount - 1 === nCurRow)
				nSumMin += nMaxBottomBorder;
		}
	}

	return nSumMin;
};
/**
 * Получаем минимальную высоту для заданной строки таблицы
 * @param nCurRow
 * @returns {number}
 */
CTable.prototype.GetMinRowHeight = function(nCurRow)
{
	var nSumMin = 0;
	var oRow    = this.Content[nCurRow];

	var nMaxTopMargin    = 0,
		nMaxBottomMargin = 0,
		nMaxTopBorder    = 0;

	for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
	{
		var oCell        = oRow.GetCell(nCurCell);
		var oCellMargins = oCell.GetMargins();
		var oCellTBorder = oCell.GetBorder(0);
		var oCellBBorder = oCell.GetBorder(2);

		if (border_None !== oCellTBorder.Value && nMaxTopBorder < oCellTBorder.Size)
			nMaxTopBorder = oCellTBorder.Size;

		if (nMaxTopMargin < oCellMargins.Top.W)
			nMaxTopMargin = oCellMargins.Top.W;

		if (nMaxBottomMargin < oCellMargins.Bottom.W)
			nMaxBottomMargin = oCellMargins.Bottom.W;
	}

	nSumMin += 4.5; // Стандартная минимальная высота строки в таблице без учета границ и отступов

	nSumMin += Math.max(nMaxTopBorder, nMaxTopMargin);
	nSumMin += nMaxBottomMargin;

	return nSumMin;
};
/**
 * Получаем суммарную высоту таблицы, с учетом ее разбиения на нескольких страницах
 * @returns {number}
 */
CTable.prototype.GetSummaryHeight = function()
{
	var nSum = 0;
	for (var nCurPage = 0, nPagesCount = this.Pages.length; nCurPage < nPagesCount; ++nCurPage)
	{
		var oBounds = this.GetPageBounds(nCurPage);
		nSum += oBounds.Bottom - oBounds.Top;
	}

	return nSum;
};
CTable.prototype.GetTableOfContents = function(isUnique, isCheckFields)
{
	for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
	{
		var oRow = this.GetRow(nCurRow);
		for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			var oResult = oRow.GetCell(nCurCell).Content.GetTableOfContents(isUnique, isCheckFields);
			if (oResult)
				return oResult;
		}
	}

	return null;
};
/**
 * Делаем выделенные ячейки равными по ширине
 * @returns {boolean} Возрвщаем false, если операция невозможна
 */
CTable.prototype.DistributeColumns = function()
{
	var isApplyToAll = this.ApplyToAll;
	if (!this.Selection.Use || table_Selection_Text === this.Selection.Type)
		this.ApplyToAll = true;

	var arrSelectedCells = this.GetSelectionArray();
	this.ApplyToAll = isApplyToAll;

	if (arrSelectedCells.length <= 1)
		return false;

	var arrRows = [];
	var arrCheckMergedCells = [];
	for (var nIndex = 0, nCount = arrSelectedCells.length; nIndex < nCount; ++nIndex)
	{
		var nCurCell = arrSelectedCells[nIndex].Cell;
		var nCurRow  = arrSelectedCells[nIndex].Row;
		if (!arrRows[nCurRow])
		{
			arrRows[nCurRow] = {
				Start : nCurCell,
				End   : nCurCell
			};
		}
		else
		{
			if (arrRows[nCurRow].Start > nCurCell)
				arrRows[nCurRow].Start = nCurCell;

			if (arrRows[nCurRow].End < nCurCell)
				arrRows[nCurRow].End = nCurCell;
		}

		var oCell = this.Content[nCurRow].GetCell(nCurCell);
		if (oCell)
		{
			var oCellInfo      = this.Content[nCurRow].GetCellInfo(nCurCell);
			var arrMergedCells = this.private_GetMergedCells(nCurRow, oCellInfo.StartGridCol, oCell.GetGridSpan());

			if (arrMergedCells.length > 1)
			{
				arrCheckMergedCells.push([nCurRow]);
			}


			for (var nMergeIndex = 1, nMergedCount = arrMergedCells.length; nMergeIndex < nMergedCount; ++nMergeIndex)
			{
				var nCurCell2 = arrMergedCells[nMergeIndex].Index;
				var nCurRow2  = arrMergedCells[nMergeIndex].Row.Index;

				if (!arrRows[nCurRow2])
				{
					arrRows[nCurRow2] = {
						Start : nCurCell2,
						End   : nCurCell2
					};
				}
				else
				{
					if (arrRows[nCurRow2].Start > nCurCell2)
						arrRows[nCurRow2].Start = nCurCell2;

					if (arrRows[nCurRow2].End < nCurCell2)
						arrRows[nCurRow2].End = nCurCell2;
				}

				arrCheckMergedCells[arrCheckMergedCells.length - 1].push(nCurRow2);
			}
		}
	}

	for (var nIndex = 0, nCount = arrCheckMergedCells.length; nIndex < nCount; ++nIndex)
	{
		var nFirstStartGridCol = null,
			arrFirstGridSpans  = null;

		for (var nRowIndex = 0, nRowsCount = arrCheckMergedCells[nIndex].length; nRowIndex < nRowsCount; ++nRowIndex)
		{
			var nCurRow = arrCheckMergedCells[nIndex][nRowIndex];
			var oRow = this.GetRow(nCurRow);

			var nStartGridCol = this.Content[nCurRow].GetBefore().Grid;
			var arrGridSpans  = [];

			for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
			{
				var nGridSpan = oRow.GetCell(nCurCell).GetGridSpan();
				if (nCurCell < arrRows[nCurRow].Start)
					nStartGridCol += nGridSpan;
				else if (nCurCell <= arrRows[nCurRow].End)
					arrGridSpans.push(nGridSpan);
				else
					break;
			}


			if (null === nFirstStartGridCol)
			{
				nFirstStartGridCol = nStartGridCol;
				arrFirstGridSpans  = arrGridSpans;
			}
			else
			{
				if (nStartGridCol !== nFirstStartGridCol || arrFirstGridSpans.length !== arrGridSpans.length)
				{
					return false;
				}
				else
				{
					for (var nSpanIndex = 0, nSpansCount = arrGridSpans.length; nSpanIndex < nSpansCount; ++nSpanIndex)
					{
						if (arrFirstGridSpans[nSpanIndex] !== arrGridSpans[nSpanIndex])
							return false;
					}
				}
			}
		}
	}

	var isAutofitLayout    = this.GetTableLayout() === tbllayout_AutoFit;
	var isNeedChangeLayout = false;
	var arrRowsInfo        = this.private_GetRowsInfo();
	for (nCurRow in arrRows)
	{
		if (!arrRowsInfo[nCurRow] || arrRowsInfo[nCurRow].length <= 0)
			continue;

		var nStartCell = arrRows[nCurRow].Start;
		var nEndCell   = arrRows[nCurRow].End;

		var nSum = 0;
		var nAdd = -1 === arrRowsInfo[nCurRow][0].Type ? 1 : 0;

		for (var nCurCell = nStartCell; nCurCell <= nEndCell; ++nCurCell)
		{
			nSum += arrRowsInfo[nCurRow][nCurCell + nAdd].W;
		}

		for (var nCurCell = nStartCell; nCurCell <= nEndCell; ++nCurCell)
		{
			var nNewW = nSum / (nEndCell - nStartCell + 1);
			arrRowsInfo[nCurRow][nCurCell + nAdd].W = nNewW;

			// TODO: Надо поправить баг в рассчете AutoFit из-за которого тут сдвиг происходит
			var oRow = this.GetRow(nCurRow);
			if (!oRow)
				continue;

			var oCell = oRow.GetCell(nCurCell);
			if (!oCell)
				continue;

			if (isAutofitLayout
				&& !isNeedChangeLayout
				&& oCell.Content_RecalculateMinMaxContentWidth(false).Max - 0.001 > nNewW)
					isNeedChangeLayout = true;
		}
	}

	if (isAutofitLayout && isNeedChangeLayout)
		this.SetTableLayout(tbllayout_Fixed);

	this.private_CreateNewGrid(arrRowsInfo);
	this.private_RecalculateGrid();

	return true;
};
/**
 * Делаем выделенные ячейки равными по высоте
 * @returns {boolean}
 */
CTable.prototype.DistributeRows = function()
{
	var isApplyToAll = this.ApplyToAll;
	if (!this.Selection.Use || table_Selection_Text === this.Selection.Type)
		this.ApplyToAll = true;

	var arrSelectedCells = this.GetSelectionArray();
	this.ApplyToAll = isApplyToAll;

	if (arrSelectedCells.length <= 1)
		return false;

	var arrRows = [], nRowsCount = 0;
	for (var nIndex = 0, nCount = arrSelectedCells.length; nIndex < nCount; ++nIndex)
	{
		if (true !== arrRows[arrSelectedCells[nIndex].Row])
		{
			arrRows[arrSelectedCells[nIndex].Row] = true;
			nRowsCount++;
		}

		var oCell = this.GetStartMergedCell(arrSelectedCells[nIndex].Cell, arrSelectedCells[nIndex].Row);
		if (oCell)
		{
			var nVMergeCount = this.GetVMergeCount(oCell.Index, oCell.Row.Index);
			if (nVMergeCount > 1)
			{
				for (var nCurRow = oCell.Row.Index; nCurRow < oCell.Row.Index + nVMergeCount - 1; ++nCurRow)
				{
					if (true !== arrRows[nCurRow])
					{
						arrRows[nCurRow] = true;
						nRowsCount++;
					}
				}
			}
		}
	}

	if (nRowsCount <= 0)
		return false;

	var nCellSpacing = this.GetRow(0).GetCellSpacing();

	var nSumH = 0;
	for (var nCurRow in arrRows)
	{
		var nRowSummaryH = 0;
		for (var nCurPage in this.RowsInfo[nCurRow].H)
			nRowSummaryH += this.RowsInfo[nCurRow].H[nCurPage];

		for (var nCurPage in this.RowsInfo[nCurRow].TopDy)
			nRowSummaryH -= this.RowsInfo[nCurRow].TopDy[nCurPage];

		var oRow      = this.GetRow(nCurRow);
		nRowSummaryH -= oRow.GetTopMargin() + oRow.GetBottomMargin();

		nSumH += nRowSummaryH;
	}

	var nNewValueH = nSumH / nRowsCount;
	for (var nCurRow in arrRows)
	{
		nCurRow = parseInt(nCurRow);

		var oRow = this.GetRow(nCurRow);

		for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			var oCell = oRow.GetCell(nCurCell);
			if (vmerge_Restart !== oCell.GetVMerge())
				continue;

			var nVMergeCount = this.GetVMergeCount(nCurCell, nCurRow);

			var nNewH = nNewValueH;

			if (null !== nCellSpacing)
				nNewH += nCellSpacing;

			var nContentH = oCell.GetContent().GetSummaryHeight();
			if (nNewH * nVMergeCount < nContentH)
				nNewValueH += (nContentH / nVMergeCount - nNewH);
		}
	}

	for (var nCurRow in arrRows)
	{
		nCurRow = parseInt(nCurRow);

		var oRow  = this.GetRow(nCurRow);
		var oRowH = oRow.GetHeight();
		var nNewH = nNewValueH;

		if (null !== nCellSpacing)
			nNewH += nCellSpacing;

		oRow.SetHeight(nNewH, oRowH.HRule === Asc.linerule_Exact ? Asc.linerule_Exact : Asc.linerule_AtLeast);
	}

	return true;
};
/**
 * Выставляем ширину текущей колонки
 * @param nWidth
 */
CTable.prototype.SetColumnWidth = function(nWidth)
{
	if (nWidth < 4.2)
		nWidth = 4.2;

	if (nWidth > 558.8)
		nWidth = 558.8;

	var arrSelectedCells = this.GetSelectionArray();

	var oCells = {};
	for (var nIndex = 0, nCount = arrSelectedCells.length; nIndex < nCount; ++nIndex)
	{
		var nCurCell = arrSelectedCells[nIndex].Cell;
		if (!oCells[nCurCell])
			oCells[nCurCell] = 1;
	}

	var arrRowsInfo = this.private_GetRowsInfo();
	for (var nCurRow = 0, nCount = arrRowsInfo.length; nCurRow < nCount; ++nCurRow)
	{
		var nAdd = -1 === arrRowsInfo[nCurRow][0].Type ? 1 : 0;

		for (var nCurCell in oCells)
		{
			var _nCurCell = nCurCell | 0;
			if (arrRowsInfo[nCurRow][_nCurCell + nAdd])
				arrRowsInfo[nCurRow][_nCurCell + nAdd].W = nWidth;
		}
	}

	this.private_CreateNewGrid(arrRowsInfo);
};
/**
 * Выставляем высоту текущей строки
 * @param nHeight
 */
CTable.prototype.SetRowHeight = function(nHeight)
{
	var oRowsRange = this.GetSelectedRowsRange();

	for (var nCurRow = oRowsRange.Start; nCurRow <= oRowsRange.End; ++nCurRow)
	{
		var oRow  = this.GetRow(nCurRow);
		var oRowH = oRow.GetHeight();

		if (oRowH.IsAuto())
			oRow.SetHeight(nHeight, Asc.linerule_AtLeast);
		else
			oRow.SetHeight(nHeight, oRowH.GetRule());
	}
};
/**
 * Проверяем попадает ли данная строка в заголовок таблицы
 * @param nRow
 * @returns {boolean}
 */
CTable.prototype.IsInHeader = function(nRow)
{
	for (var nCurRow = 0; nCurRow <= nRow; ++nCurRow)
	{
		var oRow = this.GetRow(nCurRow);
		if (!oRow.IsHeader())
			return false;
	}

	return true;
};
CTable.prototype.GetLastParagraph = function()
{
	var nRowsCount = this.GetRowsCount();
	if (nRowsCount <= 0)
		return null;

	var oRow = this.GetRow(nRowsCount - 1);
	var nCellsCount = oRow.GetCellsCount();
	if (nCellsCount <= 0)
		return null;

	return oRow.GetCell(nCellsCount - 1).GetContent().GetLastParagraph();
};
//----------------------------------------------------------------------------------------------------------------------
// Класс  CTableLook
//----------------------------------------------------------------------------------------------------------------------
function CTableLook(bFC, bFR, bLC, bLR, bBH, bBV)
{
    this.m_bFirst_Col = ( true === bFC ? true : false );
    this.m_bFirst_Row = ( true === bFR ? true : false );
    this.m_bLast_Col  = ( true === bLC ? true : false );
    this.m_bLast_Row  = ( true === bLR ? true : false );
    this.m_bBand_Hor  = ( true === bBH ? true : false );
    this.m_bBand_Ver  = ( true === bBV ? true : false );
}
CTableLook.prototype =
{

    Set : function(bFC, bFR, bLC, bLR, bBH, bBV)
    {
        this.m_bFirst_Col = ( true === bFC ? true : false );
        this.m_bFirst_Row = ( true === bFR ? true : false );
        this.m_bLast_Col  = ( true === bLC ? true : false );
        this.m_bLast_Row  = ( true === bLR ? true : false );
        this.m_bBand_Hor  = ( true === bBH ? true : false );
        this.m_bBand_Ver  = ( true === bBV ? true : false );
    },

    Copy : function()
    {
        return new CTableLook( this.m_bFirst_Col, this.m_bFirst_Row, this.m_bLast_Col, this.m_bLast_Row, this.m_bBand_Hor, this.m_bBand_Ver );
    },

    Is_FirstCol : function()
    {
        return this.m_bFirst_Col;
    },

    Is_FirstRow : function()
    {
        return this.m_bFirst_Row;
    },

    Is_LastCol : function()
    {
        return this.m_bLast_Col;
    },

    Is_LastRow : function()
    {
        return this.m_bLast_Row;
    },

    Is_BandHor : function()
    {
        return this.m_bBand_Hor;
    },

    Is_BandVer : function()
    {
        return this.m_bBand_Ver;
    },

    Write_ToBinary : function(Writer)
    {
        // Bool : m_bFirst_Col
        // Bool : m_bFirst_Row
        // Bool : m_bLast_Col
        // Bool : m_bLast_Row
        // Bool : m_bBand_Hor
        // Bool : m_bBand_Ver

        Writer.WriteBool( this.m_bFirst_Col );
        Writer.WriteBool( this.m_bFirst_Row );
        Writer.WriteBool( this.m_bLast_Col );
        Writer.WriteBool( this.m_bLast_Row );
        Writer.WriteBool( this.m_bBand_Hor );
        Writer.WriteBool( this.m_bBand_Ver );
    },

    Read_FromBinary : function(Reader)
    {
        // Bool : m_bFirst_Col
        // Bool : m_bFirst_Row
        // Bool : m_bLast_Col
        // Bool : m_bLast_Row
        // Bool : m_bBand_Hor
        // Bool : m_bBand_Ver

        this.m_bFirst_Col = Reader.GetBool();
        this.m_bFirst_Row = Reader.GetBool();
        this.m_bLast_Col  = Reader.GetBool();
        this.m_bLast_Row  = Reader.GetBool();
        this.m_bBand_Hor  = Reader.GetBool();
        this.m_bBand_Ver  = Reader.GetBool();
    }
};
//----------------------------------------------------------------------------------------------------------------------
// Класс  CTableAnchorPosition
//----------------------------------------------------------------------------------------------------------------------
function CTableAnchorPosition()
{
    // Рассчитанные координаты
    this.CalcX         = 0;
    this.CalcY         = 0;

    // Данные для Flow-объектов
    this.W             = 0;
    this.H             = 0;
    this.X             = 0;
    this.Y             = 0;
    this.Left_Margin   = 0;
    this.Right_Margin  = 0;
    this.Top_Margin    = 0;
    this.Bottom_Margin = 0;
    this.Page_W        = 0;
    this.Page_H        = 0;

    this.Page_Top      = 0;
    this.Page_Bottom   = 0;

    this.X_min         = 0;
    this.Y_min         = 0;
    this.X_max         = 0;
    this.Y_max         = 0;
}
CTableAnchorPosition.prototype =
{
    Set_X : function(W, X, Left_Margin, Right_Margin, Page_W, X_min, X_max)
    {
        this.W             = W;
        this.X             = X;
        this.Left_Margin   = Left_Margin;
        this.Right_Margin  = Right_Margin;
        this.Page_W        = Page_W;
        this.X_min         = X_min;
        this.X_max         = X_max;
    },

    Set_Y : function(H, Y, Top_Margin, Bottom_Margin, Page_H, Y_min, Y_max, Page_Top, Page_Bottom)
    {
        this.H             = H;
        this.Y             = Y;
        this.Top_Margin    = Top_Margin;
        this.Bottom_Margin = Bottom_Margin;
        this.Page_H        = Page_H;
        this.Y_min         = Y_min;
        this.Y_max         = Y_max;
        this.Page_Top      = Page_Top;
        this.Page_Bottom   = Page_Bottom;
    },

    Calculate_X : function(RelativeFrom, bAlign, Value)
    {
        // Вычисляем координату по X
        switch(RelativeFrom)
        {
            // TODO: пока нет колонок варианты Text и Margin ничем не отличаются,
            //       когда появятся колонки доделать тут
            case c_oAscHAnchor.Text:
            case c_oAscHAnchor.Margin:
            {
                if ( true === bAlign )
                {
                    switch ( Value )
                    {
                        case c_oAscXAlign.Center:
                        {
                            this.CalcX = (this.Left_Margin + this.Right_Margin - this.W) / 2;
                            break;
                        }

                        case c_oAscXAlign.Inside:
                        case c_oAscXAlign.Outside:
                        case c_oAscXAlign.Left:
                        {
                            this.CalcX = this.Left_Margin;
                            break;
                        }

                        case c_oAscXAlign.Right:
                        {
                            this.CalcX = this.Right_Margin - this.W;
                            break;
                        }
                    }
                }
                else
                    this.CalcX = this.Left_Margin + Value;

                break;
            }

            case c_oAscHAnchor.Page:
            {
                var W = this.X_max - this.X_min;
                if ( true === bAlign )
                {
                    switch ( Value )
                    {
                        case c_oAscXAlign.Center:
                        {
                            this.CalcX = this.X_min + (W - this.W) / 2;
                            break;
                        }

                        case c_oAscXAlign.Inside:
                        case c_oAscXAlign.Outside:
                        case c_oAscXAlign.Left:
                        {
                            this.CalcX = this.X_min;
                            break;
                        }

                        case c_oAscXAlign.Right:
                        {
                            this.CalcX = this.X_max - this.W;
                            break;
                        }
                    }
                }
                else
                    this.CalcX = this.X_min + Value;

                break;
            }

            case c_oAscHAnchor.PageInternal:
            {
                if ( true === bAlign )
                {
                    switch ( Value )
                    {
                        case c_oAscXAlign.Center:
                        {
                            this.CalcX = (this.Page_W - this.W) / 2;
                            break;
                        }

                        case c_oAscXAlign.Inside:
                        case c_oAscXAlign.Outside:
                        case c_oAscXAlign.Left:
                        {
                            this.CalcX = 0;
                            break;
                        }

                        case c_oAscXAlign.Right:
                        {
                            this.CalcX = this.Page_W - this.W;
                            break;
                        }
                    }
                }
                else
                    this.CalcX = Value;

                break;
            }
        }

        return this.CalcX;
    },

    Calculate_Y : function(RelativeFrom, bAlign, Value)
    {
        // Вычисляем координату по Y
        switch(RelativeFrom)
        {
            case c_oAscVAnchor.Margin:
            {
                if ( true === bAlign )
                {
                    switch(Value)
                    {
                        case c_oAscYAlign.Bottom:
                        {
                            this.CalcY = this.Bottom_Margin - this.H;
                            break;
                        }
                        case c_oAscYAlign.Center:
                        {
                            this.CalcY = (this.Bottom_Margin + this.Top_Margin - this.H) / 2;
                            break;
                        }
                        case c_oAscYAlign.Inline:
                        case c_oAscYAlign.Inside:
                        case c_oAscYAlign.Outside:
                        case c_oAscYAlign.Top:
                        {
                            this.CalcY = this.Top_Margin;
                            break;
                        }
                    }
                }
                else
                    this.CalcY = this.Top_Margin + Value;

                break;
            }

            case c_oAscVAnchor.Page:
            {
                if ( true === bAlign )
                {
                    switch(Value)
                    {
                        case c_oAscYAlign.Bottom:
                        {
                            this.CalcY = this.Page_Bottom - this.H;
                            break;
                        }
                        case c_oAscYAlign.Center:
                        {
                            this.CalcY = (this.Page_Bottom - this.H) / 2;
                            break;
                        }
                        case c_oAscYAlign.Inline:
                        case c_oAscYAlign.Inside:
                        case c_oAscYAlign.Outside:
                        case c_oAscYAlign.Top:
                        {
                            this.CalcY = this.Page_Top;
                            break;
                        }
                    }
                }
                else
                    this.CalcY = this.Page_Top + Value;

                break;
            }

            case c_oAscVAnchor.Text:
            {
                if ( true === bAlign )
                {
                    // Word не дает делать прилегания в данном случае
                    this.CalcY = this.Y;
                }
                else
                    this.CalcY = this.Y + Value;

                break;
            }
        }

        return this.CalcY;
    },

    Correct_Values : function(X_min, Y_min, X_max, Y_max, AllowOverlap, OtherFlowTables, CurTable)
    {
        var W = this.W;
        var H = this.H;

        var CurX = this.CalcX;
        var CurY = this.CalcY;

        var bBreak = false;
        while ( true != bBreak )
        {
            bBreak = true;
            for ( var Index = 0; Index < OtherFlowTables.length; Index++ )
            {
                var FlowTable = OtherFlowTables[Index];

                if ( FlowTable.Table != CurTable && ( false === AllowOverlap || false === FlowTable.Table.Get_AllowOverlap() ) && ( CurX <= FlowTable.X + FlowTable.W && CurX + W >= FlowTable.X && CurY <= FlowTable.Y + FlowTable.H && CurY + H >= FlowTable.Y ) )
                {
                    /*
                     // Если убирается справа, размещаем справа от картинки
                     if ( FlowTable.X + FlowTable.W < X_max - W - 0.001 )
                     CurX = FlowTable.X + FlowTable.W + 0.001;
                     else
                     {
                     CurX = this.CalcX;
                     CurY = FlowTable.Y + FlowTable.H + 0.001;
                     }
                     */

                    // TODO: Пока у нас смещение по X плохо работает(смотри CTable.Shift), поэтому смещаем таблицу сразу по Y
                    CurY = FlowTable.Y + FlowTable.H + 0.001;

                    bBreak = false;
                }
            }
        }

        // TODO: Пока у нас смещение по X плохо работает(смотри CTable.Shift), поэтому смещаем таблицу сразу по Y
        /*
         // Скорректируем рассчитанную позицию, так чтобы объект не выходил за заданные пределы
         if ( CurX + W > X_max )
         CurX = X_max - W;

         if ( CurX < X_min )
         CurX = X_min;
         */

        // Скорректируем рассчитанную позицию, так чтобы объект не выходил за заданные пределы
        if ( CurY + H > Y_max )
            CurY = Y_max - H;

        if ( CurY < this.Y_min )
            CurY = this.Y_min;

        this.CalcY = CurY;
        this.CalcX = CurX;
    },

    // По значению CalcX получем Value
    Calculate_X_Value : function(RelativeFrom)
    {
        var Value = 0;

        switch(RelativeFrom)
        {
            case c_oAscHAnchor.Text:
            case c_oAscHAnchor.Margin:
            {
                Value = this.CalcX - this.Left_Margin;

                break;
            }

            case c_oAscHAnchor.Page:
            {
                Value = this.CalcX - this.X_min;

                break;
            }

            case c_oAscHAnchor.PageInternal:
            {
                Value = this.CalcX;
                break;
            }
        }

        return Value;
    },

    // По значению CalcY и заданному RelativeFrom получем Value
    Calculate_Y_Value : function(RelativeFrom)
    {
        var Value = 0;

        switch(RelativeFrom)
        {
            case c_oAscVAnchor.Margin:
            {
                Value = this.CalcY - this.Top_Margin;

                break;
            }

            case c_oAscVAnchor.Page:
            {
                Value = this.CalcY - this.Page_Top;

                break;
            }

            case c_oAscVAnchor.Text:
            {
                Value = this.CalcY - this.Y;

                break;
            }
        }

        return Value;
    }
};

function CTableRowsInfo()
{
	this.Pages        = 1;
	this.Y            = [];
	this.H            = [];
	this.TopDy        = [];
	this.MaxTopBorder = [];
	this.FirstPage    = true;
	this.StartPage    = 0;
	this.X0           = 0;
	this.X1           = 0;
	this.MaxBotBorder = 0;
}
CTableRowsInfo.prototype.Init = function()
{
	this.Y[0]            = 0.0;
	this.H[0]            = 0.0;
	this.TopDy[0]        = 0.0;
	this.MaxTopBorder[0] = 0.0;
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CTable = CTable;
window['AscCommonWord'].type_Table = type_Table;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 03.11.2016
 * Time: 16:43
 */

AscDFH.changesFactory[AscDFH.historyitem_Table_TableW]                = CChangesTableTableW;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableCellMar]          = CChangesTableTableCellMar;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableAlign]            = CChangesTableTableAlign;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableInd]              = CChangesTableTableInd;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableBorder_Left]      = CChangesTableTableBorderLeft;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableBorder_Top]       = CChangesTableTableBorderTop;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableBorder_Right]     = CChangesTableTableBorderRight;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableBorder_Bottom]    = CChangesTableTableBorderBottom;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableBorder_InsideH]   = CChangesTableTableBorderInsideH;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableBorder_InsideV]   = CChangesTableTableBorderInsideV;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableShd]              = CChangesTableTableShd;
AscDFH.changesFactory[AscDFH.historyitem_Table_Inline]                = CChangesTableInline;
AscDFH.changesFactory[AscDFH.historyitem_Table_AddRow]                = CChangesTableAddRow;
AscDFH.changesFactory[AscDFH.historyitem_Table_RemoveRow]             = CChangesTableRemoveRow;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableGrid]             = CChangesTableTableGrid;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableLook]             = CChangesTableTableLook;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableStyleRowBandSize] = CChangesTableTableStyleRowBandSize;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableStyleColBandSize] = CChangesTableTableStyleColBandSize;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableStyle]            = CChangesTableTableStyle;
AscDFH.changesFactory[AscDFH.historyitem_Table_AllowOverlap]          = CChangesTableAllowOverlap;
AscDFH.changesFactory[AscDFH.historyitem_Table_PositionH]             = CChangesTablePositionH;
AscDFH.changesFactory[AscDFH.historyitem_Table_PositionV]             = CChangesTablePositionV;
AscDFH.changesFactory[AscDFH.historyitem_Table_Distance]              = CChangesTableDistance;
AscDFH.changesFactory[AscDFH.historyitem_Table_Pr]                    = CChangesTablePr;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableLayout]           = CChangesTableTableLayout;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableDescription]      = CChangesTableTableDescription;
AscDFH.changesFactory[AscDFH.historyitem_Table_TableCaption]          = CChangesTableTableCaption;
//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableW]                = [
	AscDFH.historyitem_Table_TableW,
	AscDFH.historyitem_Table_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableCellMar]          = [
	AscDFH.historyitem_Table_TableCellMar,
	AscDFH.historyitem_Table_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableAlign]            = [
	AscDFH.historyitem_Table_TableAlign,
	AscDFH.historyitem_Table_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableInd]              = [
	AscDFH.historyitem_Table_TableInd,
	AscDFH.historyitem_Table_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableBorder_Left]      = [
	AscDFH.historyitem_Table_TableBorder_Left,
	AscDFH.historyitem_Table_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableBorder_Top]       = [
	AscDFH.historyitem_Table_TableBorder_Top,
	AscDFH.historyitem_Table_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableBorder_Right]     = [
	AscDFH.historyitem_Table_TableBorder_Right,
	AscDFH.historyitem_Table_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableBorder_Bottom]    = [
	AscDFH.historyitem_Table_TableBorder_Bottom,
	AscDFH.historyitem_Table_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableBorder_InsideH]   = [
	AscDFH.historyitem_Table_TableBorder_InsideH,
	AscDFH.historyitem_Table_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableBorder_InsideV]   = [
	AscDFH.historyitem_Table_TableBorder_InsideV,
	AscDFH.historyitem_Table_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableShd]              = [
	AscDFH.historyitem_Table_TableShd,
	AscDFH.historyitem_Table_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_Inline]                = [
	AscDFH.historyitem_Table_Inline
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_AddRow]                = [
	AscDFH.historyitem_Table_AddRow,
	AscDFH.historyitem_Table_RemoveRow
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_RemoveRow]             = [
	AscDFH.historyitem_Table_AddRow,
	AscDFH.historyitem_Table_RemoveRow
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableGrid]             = [
	AscDFH.historyitem_Table_TableGrid
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableLook]             = [
	AscDFH.historyitem_Table_TableLook
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableStyleRowBandSize] = [
	AscDFH.historyitem_Table_TableStyleRowBandSize,
	AscDFH.historyitem_Table_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableStyleColBandSize] = [
	AscDFH.historyitem_Table_TableStyleColBandSize,
	AscDFH.historyitem_Table_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableStyle]            = [
	AscDFH.historyitem_Table_TableStyle
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_AllowOverlap]          = [
	AscDFH.historyitem_Table_AllowOverlap
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_PositionH]             = [
	AscDFH.historyitem_Table_PositionH
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_PositionV]             = [
	AscDFH.historyitem_Table_PositionV
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_Distance]              = [
	AscDFH.historyitem_Table_Distance
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_Pr]                    = [
	AscDFH.historyitem_Table_TableW,
	AscDFH.historyitem_Table_TableCellMar,
	AscDFH.historyitem_Table_TableAlign,
	AscDFH.historyitem_Table_TableInd,
	AscDFH.historyitem_Table_TableBorder_Left,
	AscDFH.historyitem_Table_TableBorder_Top,
	AscDFH.historyitem_Table_TableBorder_Right,
	AscDFH.historyitem_Table_TableBorder_Bottom,
	AscDFH.historyitem_Table_TableBorder_InsideH,
	AscDFH.historyitem_Table_TableBorder_InsideV,
	AscDFH.historyitem_Table_TableShd,
	AscDFH.historyitem_Table_TableStyleRowBandSize,
	AscDFH.historyitem_Table_TableStyleColBandSize,
	AscDFH.historyitem_Table_Pr,
	AscDFH.historyitem_Table_TableLayout,
	AscDFH.historyitem_Table_TableDescription,
	AscDFH.historyitem_Table_TableCaption
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableLayout]           = [
	AscDFH.historyitem_Table_TableLayout,
	AscDFH.historyitem_Table_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableDescription] = [
	AscDFH.historyitem_Table_TableDescription,
	AscDFH.historyitem_Table_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_Table_TableCaption]     = [
	AscDFH.historyitem_Table_TableCaption,
	AscDFH.historyitem_Table_Pr
];

/**
 * Общая функция объединения изменений, которые зависят только от себя и AscDFH.historyitem_Table_Pr
 * @param oChange
 * @returns {boolean}
 */
function private_TableChangesOnMergePr(oChange)
{
	if (oChange.Class !== this.Class)
		return true;

	if (oChange.Type === this.Type || oChange.Type === AscDFH.historyitem_Table_Pr)
		return false;

	return true;
}
//----------------------------------------------------------------------------------------------------------------------

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesTableTableW(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesTableTableW.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesTableTableW.prototype.constructor = CChangesTableTableW;
CChangesTableTableW.prototype.Type = AscDFH.historyitem_Table_TableW;
CChangesTableTableW.prototype.private_CreateObject = function()
{
	return new CTableMeasurement(tblwidth_Auto, 0);
};
CChangesTableTableW.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr.TableW = Value;
	oTable.Recalc_CompiledPr();
};
CChangesTableTableW.prototype.Merge = private_TableChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesTableTableCellMar(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesTableTableCellMar.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesTableTableCellMar.prototype.constructor = CChangesTableTableCellMar;
CChangesTableTableCellMar.prototype.Type = AscDFH.historyitem_Table_TableCellMar;
CChangesTableTableCellMar.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Is New.Left undefined?
	// 2-bit : Is New.Top undefined?
	// 3-bit : Is New.Right undefined?
	// 4-bit : Is New.Bottom undefined?
	// 5-bit : Is Old.Left undefined?
	// 6-bit : Is Old.Top undefined?
	// 7-bit : Is Old.Right undefined?
	// 8-bit : Is Old.Bottom undefined?
	// Variable(?CTableMeasurement) : New.Left (1 бит нулевой)
	// Variable(?CTableMeasurement) : New.Top (2 бит нулевой)
	// Variable(?CTableMeasurement) : New.Right (3 бит нулевой)
	// Variable(?CTableMeasurement) : New.Bottom (4 бит нулевой)
	// Variable(?CTableMeasurement) : Old.Left (5 бит нулевой)
	// Variable(?CTableMeasurement) : Old.Top (6 бит нулевой)
	// Variable(?CTableMeasurement) : Old.Right (7 бит нулевой)
	// Variable(?CTableMeasurement) : Old.Bottom (8 бит нулевой)

	var nFlags = 0;

	if (undefined === this.New.Left)
		nFlags |= 1;
	if (undefined === this.New.Top)
		nFlags |= 2;
	if (undefined === this.New.Right)
		nFlags |= 4;
	if (undefined === this.New.Bottom)
		nFlags |= 8;
	if (undefined === this.Old.Left)
		nFlags |= 16;
	if (undefined === this.Old.Top)
		nFlags |= 32;
	if (undefined === this.Old.Right)
		nFlags |= 64;
	if (undefined === this.Old.Bottom)
		nFlags |= 128;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New.Left)
		this.New.Left.Write_ToBinary(Writer);
	if (undefined !== this.New.Top)
		this.New.Top.Write_ToBinary(Writer);
	if (undefined !== this.New.Right)
		this.New.Right.Write_ToBinary(Writer);
	if (undefined !== this.New.Bottom)
		this.New.Bottom.Write_ToBinary(Writer);
	if (undefined !== this.Old.Left)
		this.Old.Left.Write_ToBinary(Writer);
	if (undefined !== this.Old.Top)
		this.Old.Top.Write_ToBinary(Writer);
	if (undefined !== this.Old.Right)
		this.Old.Right.Write_ToBinary(Writer);
	if (undefined !== this.Old.Bottom)
		this.Old.Bottom.Write_ToBinary(Writer);
};
CChangesTableTableCellMar.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Is New.Left undefined?
	// 2-bit : Is New.Top undefined?
	// 3-bit : Is New.Right undefined?
	// 4-bit : Is New.Bottom undefined?
	// 5-bit : Is Old.Left undefined?
	// 6-bit : Is Old.Top undefined?
	// 7-bit : Is Old.Right undefined?
	// 8-bit : Is Old.Bottom undefined?
	// Variable(?CTableMeasurement) : New.Left (1 бит нулевой)
	// Variable(?CTableMeasurement) : New.Top (2 бит нулевой)
	// Variable(?CTableMeasurement) : New.Right (3 бит нулевой)
	// Variable(?CTableMeasurement) : New.Bottom (4 бит нулевой)
	// Variable(?CTableMeasurement) : Old.Left (5 бит нулевой)
	// Variable(?CTableMeasurement) : Old.Top (6 бит нулевой)
	// Variable(?CTableMeasurement) : Old.Right (7 бит нулевой)
	// Variable(?CTableMeasurement) : Old.Bottom (8 бит нулевой)

	this.New = {};
	this.Old = {};
	var nFlags = Reader.GetLong();

	if (nFlags & 1)
	{
		this.New.Left = undefined;
	}
	else
	{
		this.New.Left = new CTableMeasurement(tblwidth_Mm, 0);
		this.New.Left.Read_FromBinary(Reader);
	}

	if (nFlags & 2)
	{
		this.New.Top = undefined;
	}
	else
	{
		this.New.Top = new CTableMeasurement(tblwidth_Mm, 0);
		this.New.Top.Read_FromBinary(Reader);
	}

	if (nFlags & 4)
	{
		this.New.Right = undefined;
	}
	else
	{
		this.New.Right = new CTableMeasurement(tblwidth_Mm, 0);
		this.New.Right.Read_FromBinary(Reader);
	}

	if (nFlags & 8)
	{
		this.New.Bottom = undefined;
	}
	else
	{
		this.New.Bottom = new CTableMeasurement(tblwidth_Mm, 0);
		this.New.Bottom.Read_FromBinary(Reader);
	}

	if (nFlags & 16)
	{
		this.Old.Left = undefined;
	}
	else
	{
		this.Old.Left = new CTableMeasurement(tblwidth_Mm, 0);
		this.Old.Left.Read_FromBinary(Reader);
	}

	if (nFlags & 32)
	{
		this.Old.Top = undefined;
	}
	else
	{
		this.Old.Top = new CTableMeasurement(tblwidth_Mm, 0);
		this.Old.Top.Read_FromBinary(Reader);
	}

	if (nFlags & 64)
	{
		this.Old.Right = undefined;
	}
	else
	{
		this.Old.Right = new CTableMeasurement(tblwidth_Mm, 0);
		this.Old.Right.Read_FromBinary(Reader);
	}

	if (nFlags & 128)
	{
		this.Old.Bottom = undefined;
	}
	else
	{
		this.Old.Bottom = new CTableMeasurement(tblwidth_Mm, 0);
		this.Old.Bottom.Read_FromBinary(Reader);
	}
};
CChangesTableTableCellMar.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;

	oTable.Pr.TableCellMar.Left   = Value.Left;
	oTable.Pr.TableCellMar.Right  = Value.Right;
	oTable.Pr.TableCellMar.Top    = Value.Top;
	oTable.Pr.TableCellMar.Bottom = Value.Bottom;

	oTable.Recalc_CompiledPr();
};
CChangesTableTableCellMar.prototype.Merge = private_TableChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesTableTableAlign(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesTableTableAlign.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesTableTableAlign.prototype.constructor = CChangesTableTableAlign;
CChangesTableTableAlign.prototype.Type = AscDFH.historyitem_Table_TableAlign;
CChangesTableTableAlign.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr.Jc = Value;
	oTable.Recalc_CompiledPr();
};
CChangesTableTableAlign.prototype.Merge = private_TableChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseDoubleProperty}
 */
function CChangesTableTableInd(Class, Old, New, Color)
{
	AscDFH.CChangesBaseDoubleProperty.call(this, Class, Old, New, Color);
}
CChangesTableTableInd.prototype = Object.create(AscDFH.CChangesBaseDoubleProperty.prototype);
CChangesTableTableInd.prototype.constructor = CChangesTableTableInd;
CChangesTableTableInd.prototype.Type = AscDFH.historyitem_Table_TableInd;
CChangesTableTableInd.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr.TableInd = Value;
	oTable.Recalc_CompiledPr();
};
CChangesTableTableInd.prototype.Merge = private_TableChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesTableTableBorderLeft(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesTableTableBorderLeft.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesTableTableBorderLeft.prototype.constructor = CChangesTableTableBorderLeft;
CChangesTableTableBorderLeft.prototype.Type = AscDFH.historyitem_Table_TableBorder_Left;
CChangesTableTableBorderLeft.prototype.private_CreateObject = function()
{
	return new CDocumentBorder();
};
CChangesTableTableBorderLeft.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr.TableBorders.Left = Value;
	oTable.Recalc_CompiledPr2();
};
CChangesTableTableBorderLeft.prototype.Merge = private_TableChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesTableTableBorderTop(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesTableTableBorderTop.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesTableTableBorderTop.prototype.constructor = CChangesTableTableBorderTop;
CChangesTableTableBorderTop.prototype.Type = AscDFH.historyitem_Table_TableBorder_Top;
CChangesTableTableBorderTop.prototype.private_CreateObject = function()
{
	return new CDocumentBorder();
};
CChangesTableTableBorderTop.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr.TableBorders.Top = Value;
	oTable.Recalc_CompiledPr2();
};
CChangesTableTableBorderTop.prototype.Merge = private_TableChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesTableTableBorderRight(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesTableTableBorderRight.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesTableTableBorderRight.prototype.constructor = CChangesTableTableBorderRight;
CChangesTableTableBorderRight.prototype.Type = AscDFH.historyitem_Table_TableBorder_Right;
CChangesTableTableBorderRight.prototype.private_CreateObject = function()
{
	return new CDocumentBorder();
};
CChangesTableTableBorderRight.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr.TableBorders.Right = Value;
	oTable.Recalc_CompiledPr2();
};
CChangesTableTableBorderRight.prototype.Merge = private_TableChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesTableTableBorderBottom(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesTableTableBorderBottom.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesTableTableBorderBottom.prototype.constructor = CChangesTableTableBorderBottom;
CChangesTableTableBorderBottom.prototype.Type = AscDFH.historyitem_Table_TableBorder_Bottom;
CChangesTableTableBorderBottom.prototype.private_CreateObject = function()
{
	return new CDocumentBorder();
};
CChangesTableTableBorderBottom.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr.TableBorders.Bottom = Value;
	oTable.Recalc_CompiledPr2();
};
CChangesTableTableBorderBottom.prototype.Merge = private_TableChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesTableTableBorderInsideH(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesTableTableBorderInsideH.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesTableTableBorderInsideH.prototype.constructor = CChangesTableTableBorderInsideH;
CChangesTableTableBorderInsideH.prototype.Type = AscDFH.historyitem_Table_TableBorder_InsideH;
CChangesTableTableBorderInsideH.prototype.private_CreateObject = function()
{
	return new CDocumentBorder();
};
CChangesTableTableBorderInsideH.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr.TableBorders.InsideH = Value;
	oTable.Recalc_CompiledPr2();
};
CChangesTableTableBorderInsideH.prototype.Merge = private_TableChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesTableTableBorderInsideV(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesTableTableBorderInsideV.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesTableTableBorderInsideV.prototype.constructor = CChangesTableTableBorderInsideV;
CChangesTableTableBorderInsideV.prototype.Type = AscDFH.historyitem_Table_TableBorder_InsideV;
CChangesTableTableBorderInsideV.prototype.private_CreateObject = function()
{
	return new CDocumentBorder();
};
CChangesTableTableBorderInsideV.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr.TableBorders.InsideV = Value;
	oTable.Recalc_CompiledPr2();
};
CChangesTableTableBorderInsideV.prototype.Merge = private_TableChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesTableTableShd(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesTableTableShd.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesTableTableShd.prototype.constructor = CChangesTableTableShd;
CChangesTableTableShd.prototype.Type = AscDFH.historyitem_Table_TableShd;
CChangesTableTableShd.prototype.private_CreateObject = function()
{
	return new CDocumentShd();
};
CChangesTableTableShd.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr.Shd = Value;
	oTable.Recalc_CompiledPr2();
};
CChangesTableTableShd.prototype.Merge = private_TableChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolValue}
 */
function CChangesTableInline(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolValue.call(this, Class, Old, New, Color);
}
CChangesTableInline.prototype = Object.create(AscDFH.CChangesBaseBoolValue.prototype);
CChangesTableInline.prototype.constructor = CChangesTableInline;
CChangesTableInline.prototype.Type = AscDFH.historyitem_Table_Inline;
CChangesTableInline.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Inline = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesTableAddRow(Class, Pos, Rows)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Rows, true);
}
CChangesTableAddRow.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesTableAddRow.prototype.constructor = CChangesTableAddRow;
CChangesTableAddRow.prototype.Type = AscDFH.historyitem_Table_AddRow;
CChangesTableAddRow.prototype.Undo = function()
{
	var oTable = this.Class;

	oTable.Content[this.Pos].Set_Index(-1);
	oTable.Content.splice(this.Pos, 1);
	oTable.TableRowsBottom.splice(this.Pos, 1);
	oTable.RowsInfo.splice(this.Pos, 1);

	oTable.Internal_ReIndexing(this.Pos);
	oTable.Recalc_CompiledPr2();
};
CChangesTableAddRow.prototype.Redo = function()
{
	if (this.Items.length <= 0)
		return;

	var oTable = this.Class;

	oTable.Content.splice(this.Pos, 0, this.Items[0]);
	oTable.TableRowsBottom.splice(this.Pos, 0, {});
	oTable.RowsInfo.splice(this.Pos, 0, new CTableRowsInfo());

	oTable.Internal_ReIndexing(this.Pos);
	oTable.Recalc_CompiledPr2();
};
CChangesTableAddRow.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesTableAddRow.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesTableAddRow.prototype.Load = function(Color)
{
	if (this.PosArray.length <= 0 || this.Items.length <= 0)
		return;

	var oTable = this.Class;

	var Pos     = oTable.m_oContentChanges.Check(AscCommon.contentchanges_Add, this.PosArray[0]);
	var Element = this.Items[0];

	if (null != Element)
	{
		oTable.Content.splice(Pos, 0, Element);
		AscCommon.CollaborativeEditing.Update_DocumentPositionsOnAdd(oTable, Pos);
	}

	oTable.Internal_ReIndexing();
	oTable.Recalc_CompiledPr2();
};
CChangesTableAddRow.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_Table_AddRow === oChanges.Type || AscDFH.historyitem_Table_RemoveRow === oChanges.Type))
		return true;

	return false;
};
CChangesTableAddRow.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesTableRemoveRow);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesTableRemoveRow(Class, Pos, Rows)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Rows, false);
}
CChangesTableRemoveRow.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesTableRemoveRow.prototype.constructor = CChangesTableRemoveRow;
CChangesTableRemoveRow.prototype.Type = AscDFH.historyitem_Table_RemoveRow;
CChangesTableRemoveRow.prototype.Undo = function()
{
	if (this.Items.length <= 0)
		return;

	var oTable = this.Class;

	oTable.Content.splice(this.Pos, 0, this.Items[0]);
	oTable.TableRowsBottom.splice(this.Pos, 0, {});
	oTable.RowsInfo.splice(this.Pos, 0, new CTableRowsInfo());

	oTable.Internal_ReIndexing(this.Pos);
	oTable.Recalc_CompiledPr2();
};
CChangesTableRemoveRow.prototype.Redo = function()
{
	if (this.Items.length <= 0)
		return;

	var oTable = this.Class;

	oTable.Content[this.Pos].Set_Index(-1);
	oTable.Content.splice(this.Pos, 1);
	oTable.TableRowsBottom.splice(this.Pos, 1);
	oTable.RowsInfo.splice(this.Pos, 1);

	oTable.Internal_ReIndexing(this.Pos);
	oTable.Recalc_CompiledPr2();
};
CChangesTableRemoveRow.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesTableRemoveRow.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesTableRemoveRow.prototype.Load = function(Color)
{
	if (this.PosArray.length <= 0 || this.Items.length <= 0)
		return;

	var oTable = this.Class;

	var Pos = oTable.m_oContentChanges.Check(AscCommon.contentchanges_Remove, this.PosArray[0]);
	if (false === Pos)
		return;

	oTable.Content[Pos].Set_Index(-1);
	oTable.Content.splice(Pos, 1);
	AscCommon.CollaborativeEditing.Update_DocumentPositionsOnRemove(oTable, Pos, 1);

	oTable.Internal_ReIndexing();
	oTable.Recalc_CompiledPr2();
};
CChangesTableRemoveRow.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_Table_AddRow === oChanges.Type || AscDFH.historyitem_Table_RemoveRow === oChanges.Type))
		return true;

	return false;
};
CChangesTableRemoveRow.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesTableAddRow);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesTableTableGrid(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesTableTableGrid.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesTableTableGrid.prototype.constructor = CChangesTableTableGrid;
CChangesTableTableGrid.prototype.Type = AscDFH.historyitem_Table_TableGrid;
CChangesTableTableGrid.prototype.WriteToBinary = function(Writer)
{
	// Long : Count of the columns in the new grid
	// Array of double : widths of columns in the new grid
	// Long : Count of the columns in the old grid
	// Array of double : widths of columns in the old grid

	var nNewCount = this.New.length;
	Writer.WriteLong(nNewCount);
	for (var nIndex = 0; nIndex < nNewCount; ++nIndex)
		Writer.WriteDouble(this.New[nIndex]);

	var nOldCount = this.Old.length;
	Writer.WriteLong(nOldCount);
	for (var nIndex = 0; nIndex < nOldCount; ++nIndex)
		Writer.WriteDouble(this.Old[nIndex]);
};
CChangesTableTableGrid.prototype.ReadFromBinary = function(Reader)
{
	// Long : Count of the columns in the new grid
	// Array of double : widths of columns in the new grid
	// Long : Count of the columns in the old grid
	// Array of double : widths of columns in the old grid

	var nCount = Reader.GetLong();
	this.New = [];
	for (var nIndex = 0; nIndex < nCount; ++nIndex)
		this.New[nIndex] = Reader.GetDouble();

	nCount = Reader.GetLong();
	this.Old = [];
	for (var nIndex = 0; nIndex < nCount; ++nIndex)
		this.Old[nIndex] = Reader.GetDouble();
};
CChangesTableTableGrid.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.TableGrid = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectValue}
 */
function CChangesTableTableLook(Class, Old, New)
{
	AscDFH.CChangesBaseObjectValue.call(this, Class, Old, New);
}
CChangesTableTableLook.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesTableTableLook.prototype.constructor = CChangesTableTableLook;
CChangesTableTableLook.prototype.Type = AscDFH.historyitem_Table_TableLook;
CChangesTableTableLook.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.TableLook = Value;
	oTable.Recalc_CompiledPr2();
};
CChangesTableTableLook.prototype.private_CreateObject = function()
{
	return new CTableLook();
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesTableTableStyleRowBandSize(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesTableTableStyleRowBandSize.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesTableTableStyleRowBandSize.prototype.constructor = CChangesTableTableStyleRowBandSize;
CChangesTableTableStyleRowBandSize.prototype.Type = AscDFH.historyitem_Table_TableStyleRowBandSize;
CChangesTableTableStyleRowBandSize.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr.TableStyleRowBandSize = Value;
	oTable.Recalc_CompiledPr();
};
CChangesTableTableStyleRowBandSize.prototype.Merge = private_TableChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesTableTableStyleColBandSize(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesTableTableStyleColBandSize.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesTableTableStyleColBandSize.prototype.constructor = CChangesTableTableStyleColBandSize;
CChangesTableTableStyleColBandSize.prototype.Type = AscDFH.historyitem_Table_TableStyleColBandSize;
CChangesTableTableStyleColBandSize.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr.TableStyleColBandSize = Value;
	oTable.Recalc_CompiledPr();
};
CChangesTableTableStyleColBandSize.prototype.Merge = private_TableChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesTableTableStyle(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);
}
CChangesTableTableStyle.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesTableTableStyle.prototype.constructor = CChangesTableTableStyle;
CChangesTableTableStyle.prototype.Type = AscDFH.historyitem_Table_TableStyle;
CChangesTableTableStyle.prototype.WriteToBinary = function(Writer)
{
	// Long : Flags
	// 1-bit : Is new null?
	// 2-bit : Is old null?
	// String : id of new style (1bit = 0)
	// String : id of old style (2bit = 0)

	var nFlags = 0;
	if (null === this.New)
		nFlags |= 1;
	if (null === this.Old)
		nFlags |= 2;

	Writer.WriteLong(nFlags);

	if (null !== this.New)
		Writer.WriteString2(this.New);

	if (null !== this.Old)
		Writer.WriteString2(this.Old);
};
CChangesTableTableStyle.prototype.ReadFromBinary = function(Reader)
{
	// Long : Flags
	// 1-bit : Is new null?
	// 2-bit : Is old null?
	// String : id of new style (1bit = 0)
	// String : id of old style (2bit = 0)

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.New = null;
	else
		this.New = Reader.GetString2();

	if (nFlags & 2)
		this.Old = null;
	else
		this.Old = Reader.GetString2();
};
CChangesTableTableStyle.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.TableStyle = Value;
	oTable.Recalc_CompiledPr2();
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolValue}
 */
function CChangesTableAllowOverlap(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolValue.call(this, Class, Old, New, Color);
}
CChangesTableAllowOverlap.prototype = Object.create(AscDFH.CChangesBaseBoolValue.prototype);
CChangesTableAllowOverlap.prototype.constructor = CChangesTableAllowOverlap;
CChangesTableAllowOverlap.prototype.Type = AscDFH.historyitem_Table_AllowOverlap;
CChangesTableAllowOverlap.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.AllowOverlap = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesTablePositionH(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesTablePositionH.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesTablePositionH.prototype.constructor = CChangesTablePositionH;
CChangesTablePositionH.prototype.Type = AscDFH.historyitem_Table_PositionH;
CChangesTablePositionH.prototype.WriteToBinary = function(Writer)
{
	// Long : New.RelativeFrom
	// Bool : New.Align
	//   true  -> Long   : New.Value
	//   false -> Double : New.Value
	// Long : Old.RelativeFrom
	// Bool : Old.Align
	//   true  -> Long   : Old.Value
	//   false -> Double : Old.Value

	Writer.WriteLong(this.New.RelativeFrom);
	Writer.WriteBool(this.New.Align);
	if (true === this.New.Align)
		Writer.WriteLong(this.New.Value);
	else
		Writer.WriteDouble(this.New.Value);

	Writer.WriteLong(this.Old.RelativeFrom);
	Writer.WriteBool(this.Old.Align);
	if (true === this.Old.Align)
		Writer.WriteLong(this.Old.Value);
	else
		Writer.WriteDouble(this.Old.Value);
};
CChangesTablePositionH.prototype.ReadFromBinary = function(Reader)
{
	// Long : New.RelativeFrom
	// Bool : New.Align
	//   true  -> Long   : New.Value
	//   false -> Double : New.Value
	// Long : Old.RelativeFrom
	// Bool : Old.Align
	//   true  -> Long   : Old.Value
	//   false -> Double : Old.Value

	this.New = {};
	this.Old = {};

	this.New.RelativeFrom = Reader.GetLong();
	this.New.Align        = Reader.GetBool();

	if (true === this.New.Align)
		this.New.Value = Reader.GetLong();
	else
		this.New.Value = Reader.GetDouble();

	this.Old.RelativeFrom = Reader.GetLong();
	this.Old.Align        = Reader.GetBool();

	if (true === this.Old.Align)
		this.Old.Value = Reader.GetLong();
	else
		this.Old.Value = Reader.GetDouble();
};
CChangesTablePositionH.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;

	oTable.PositionH.RelativeFrom = Value.RelativeFrom;
	oTable.PositionH.Align        = Value.Align;
	oTable.PositionH.Value        = Value.Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesTablePositionV(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesTablePositionV.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesTablePositionV.prototype.constructor = CChangesTablePositionV;
CChangesTablePositionV.prototype.Type = AscDFH.historyitem_Table_PositionV;
CChangesTablePositionV.prototype.WriteToBinary = function(Writer)
{
	// Long : New.RelativeFrom
	// Bool : New.Align
	//   true  -> Long   : New.Value
	//   false -> Double : New.Value
	// Long : Old.RelativeFrom
	// Bool : Old.Align
	//   true  -> Long   : Old.Value
	//   false -> Double : Old.Value

	Writer.WriteLong(this.New.RelativeFrom);
	Writer.WriteBool(this.New.Align);
	if (true === this.New.Align)
		Writer.WriteLong(this.New.Value);
	else
		Writer.WriteDouble(this.New.Value);

	Writer.WriteLong(this.Old.RelativeFrom);
	Writer.WriteBool(this.Old.Align);
	if (true === this.Old.Align)
		Writer.WriteLong(this.Old.Value);
	else
		Writer.WriteDouble(this.Old.Value);
};
CChangesTablePositionV.prototype.ReadFromBinary = function(Reader)
{
	// Long : New.RelativeFrom
	// Bool : New.Align
	//   true  -> Long   : New.Value
	//   false -> Double : New.Value
	// Long : Old.RelativeFrom
	// Bool : Old.Align
	//   true  -> Long   : Old.Value
	//   false -> Double : Old.Value

	this.New = {};
	this.Old = {};

	this.New.RelativeFrom = Reader.GetLong();
	this.New.Align        = Reader.GetBool();

	if (true === this.New.Align)
		this.New.Value = Reader.GetLong();
	else
		this.New.Value = Reader.GetDouble();

	this.Old.RelativeFrom = Reader.GetLong();
	this.Old.Align        = Reader.GetBool();

	if (true === this.Old.Align)
		this.Old.Value = Reader.GetLong();
	else
		this.Old.Value = Reader.GetDouble();
};
CChangesTablePositionV.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;

	oTable.PositionV.RelativeFrom = Value.RelativeFrom;
	oTable.PositionV.Align        = Value.Align;
	oTable.PositionV.Value        = Value.Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesTableDistance(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesTableDistance.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesTableDistance.prototype.constructor = CChangesTableDistance;
CChangesTableDistance.prototype.Type = AscDFH.historyitem_Table_Distance;
CChangesTableDistance.prototype.WriteToBinary = function(Writer)
{
	// Double : New.Left
	// Double : New.Top
	// Double : New.Right
	// Double : New.Bottom
	// Double : Old.Left
	// Double : Old.Top
	// Double : Old.Right
	// Double : Old.Bottom

	Writer.WriteDouble(this.New.Left);
	Writer.WriteDouble(this.New.Top);
	Writer.WriteDouble(this.New.Right);
	Writer.WriteDouble(this.New.Bottom);
	Writer.WriteDouble(this.Old.Left);
	Writer.WriteDouble(this.Old.Top);
	Writer.WriteDouble(this.Old.Right);
	Writer.WriteDouble(this.Old.Bottom);
};
CChangesTableDistance.prototype.ReadFromBinary = function(Reader)
{
	// Double : New.Left
	// Double : New.Top
	// Double : New.Right
	// Double : New.Bottom
	// Double : Old.Left
	// Double : Old.Top
	// Double : Old.Right
	// Double : Old.Bottom

	this.New = {
		Left   : 0,
		Top    : 0,
		Right  : 0,
		Bottom : 0
	};

	this.Old = {
		Left   : 0,
		Top    : 0,
		Right  : 0,
		Bottom : 0
	};

	this.New.Left   = Reader.GetDouble();
	this.New.Top    = Reader.GetDouble();
	this.New.Right  = Reader.GetDouble();
	this.New.Bottom = Reader.GetDouble();
	this.Old.Left   = Reader.GetDouble();
	this.Old.Top    = Reader.GetDouble();
	this.Old.Right  = Reader.GetDouble();
	this.Old.Bottom = Reader.GetDouble();
};
CChangesTableDistance.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;

	oTable.Distance.L = Value.Left;
	oTable.Distance.T = Value.Top;
	oTable.Distance.R = Value.Right;
	oTable.Distance.B = Value.Bottom;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectValue}
 */
function CChangesTablePr(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectValue.call(this, Class, Old, New, Color);
}
CChangesTablePr.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesTablePr.prototype.constructor = CChangesTablePr;
CChangesTablePr.prototype.Type = AscDFH.historyitem_Table_Pr;
CChangesTablePr.prototype.private_CreateObject = function()
{
	return new CTablePr();
};
CChangesTablePr.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr = Value;
	oTable.Recalc_CompiledPr2();
};
CChangesTablePr.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type)
		return false;

	if (!this.New)
		this.New = new CTablePr();

	switch (oChange.Type)
	{
		case AscDFH.historyitem_Table_TableW:
		{
			this.New.TableW = oChange.New;
			break;
		}
		case AscDFH.historyitem_Table_TableCellMar:
		{
			this.New.TableCellMar.Left   = oChange.New.Left;
			this.New.TableCellMar.Right  = oChange.New.Right;
			this.New.TableCellMar.Top    = oChange.New.Top;
			this.New.TableCellMar.Bottom = oChange.New.Bottom;
			break;
		}
		case AscDFH.historyitem_Table_TableAlign:
		{
			this.New.Jc = oChange.New;
			break;
		}
		case AscDFH.historyitem_Table_TableInd:
		{
			this.New.TableInd = oChange.New;
			break;
		}
		case AscDFH.historyitem_Table_TableBorder_Left:
		{
			this.New.TableBorders.Left = oChange.New;
			break;
		}
		case AscDFH.historyitem_Table_TableBorder_Top:
		{
			this.New.TableBorders.Top = oChange.New;
			break;
		}
		case AscDFH.historyitem_Table_TableBorder_Right:
		{
			this.New.TableBorders.Right = oChange.New;
			break;
		}
		case AscDFH.historyitem_Table_TableBorder_Bottom:
		{
			this.New.TableBorders.Bottom = oChange.New;
			break;
		}
		case AscDFH.historyitem_Table_TableBorder_InsideH:
		{
			this.New.TableBorders.InsideH = oChange.New;
			break;
		}
		case AscDFH.historyitem_Table_TableBorder_InsideV:
		{
			this.New.TableBorders.InsideV = oChange.New;
			break;
		}
		case AscDFH.historyitem_Table_TableShd:
		{
			this.New.Shd = oChange.New;
			break;
		}
		case AscDFH.historyitem_Table_TableStyleRowBandSize:
		{
			this.New.TableStyleRowBandSize = oChange.New;
			break;
		}
		case AscDFH.historyitem_Table_TableStyleColBandSize:
		{
			this.New.TableStyleColBandSize = oChange.New;
			break;
		}
		case AscDFH.historyitem_Table_TableLayout:
		{
			this.New.TableLayout = oChange.New;
			break;
		}
		case AscDFH.historyitem_Table_TableDescription:
		{
			this.New.TableDescription = oChange.New;
			break;
		}
		case AscDFH.historyitem_Table_TableCaption:
		{
			this.New.TableCaption = oChange.New;
			break;
		}
	}

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesTableTableLayout(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesTableTableLayout.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesTableTableLayout.prototype.constructor = CChangesTableTableLayout;
CChangesTableTableLayout.prototype.Type = AscDFH.historyitem_Table_TableLayout;
CChangesTableTableLayout.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr.TableLayout = Value;
	oTable.Recalc_CompiledPr2();
};
CChangesTableTableLayout.prototype.Merge = private_TableChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseStringProperty}
 */
function CChangesTableTableDescription(Class, Old, New, Color)
{
	AscDFH.CChangesBaseStringProperty.call(this, Class, Old, New, Color);
}
CChangesTableTableDescription.prototype = Object.create(AscDFH.CChangesBaseStringProperty.prototype);
CChangesTableTableDescription.prototype.constructor = CChangesTableTableDescription;
CChangesTableTableDescription.prototype.Type = AscDFH.historyitem_Table_TableDescription;
CChangesTableTableDescription.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr.TableDescription = Value;
	oTable.Recalc_CompiledPr2();
};
CChangesTableTableDescription.prototype.Merge = private_TableChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseStringProperty}
 */
function CChangesTableTableCaption(Class, Old, New, Color)
{
	AscDFH.CChangesBaseStringProperty.call(this, Class, Old, New, Color);
}
CChangesTableTableCaption.prototype = Object.create(AscDFH.CChangesBaseStringProperty.prototype);
CChangesTableTableCaption.prototype.constructor = CChangesTableTableCaption;
CChangesTableTableCaption.prototype.Type = AscDFH.historyitem_Table_TableCaption;
CChangesTableTableCaption.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr.TableCaption = Value;
	oTable.Recalc_CompiledPr2();
};
CChangesTableTableCaption.prototype.Merge = private_TableChangesOnMergePr;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
CTable.prototype.Recalculate_Page = function(PageIndex)
{
	if (0 === PageIndex)
	{
		// TODO: Внутри функции private_RecalculateBorders происходит персчет метрик каждой ячейки, это надо бы
		//       вынести в отдельную функцию. Из-за этого функцию private_RecalculateHeader приходится запускать позже.

		this.private_RecalculateGrid();
		this.private_RecalculateBorders();
		this.private_RecalculateHeader();
	}

	this.private_RecalculatePageXY(PageIndex);

	if (true !== this.private_RecalculateCheckPageColumnBreak(PageIndex))
		return recalcresult_NextPage | recalcresultflags_Column;

	this.private_RecalculatePositionX(PageIndex);

	var Result = this.private_RecalculatePage(PageIndex);
	if (Result & recalcresult_CurPage)
		return Result;

	this.private_RecalculatePositionY(PageIndex);

	if (Result & recalcresult_NextElement)
		this.RecalcInfo.Reset(false);

	return Result;
};
CTable.prototype.Recalculate_SkipPage = function(PageIndex)
{
	if (0 === PageIndex)
	{
		this.StartFromNewPage();
	}
	else
	{
		var PrevPage = this.Pages[PageIndex - 1];

		var LastRow      = Math.max(PrevPage.FirstRow, PrevPage.LastRow); // На случай, если предыдущая страница тоже пустая
		var NewPage      = new CTablePage(PrevPage.X, PrevPage.Y, PrevPage.XLimit, PrevPage.YLimit, LastRow, PrevPage.MaxTopBorder);
		NewPage.FirstRow = LastRow;
		NewPage.LastRow  = LastRow - 1;

		this.Pages[PageIndex] = NewPage;
	}
};
CTable.prototype.Recalculate_Grid = function()
{
	this.private_RecalculateGrid();
};
CTable.prototype.SaveRecalculateObject = function()
{
	var RecalcObj = new CTableRecalculateObject();
	RecalcObj.Save(this);
	return RecalcObj;
};
CTable.prototype.LoadRecalculateObject = function(RecalcObj)
{
	RecalcObj.Load(this);
};
CTable.prototype.PrepareRecalculateObject = function()
{
	this.TableSumGrid  = [];
	this.TableGridCalc = [];

	this.TableRowsBottom = [];
	this.RowsInfo        = [];

	this.HeaderInfo = {
		Count     : 0,
		H         : 0,
		PageIndex : 0,
		Pages     : []
	};

	this.Pages = [];

	this.MaxTopBorder = [];
	this.MaxBotBorder = [];
	this.MaxBotMargin = [];

	this.RecalcInfo.Reset(true);

	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		this.Content[Index].PrepareRecalculateObject();
	}
};
CTable.prototype.StartFromNewPage = function()
{
	this.Pages.length     = 1;
	this.Pages[0]         = new CTablePage(0, 0, 0, 0, 0, 0);
	this.Pages[0].LastRow = -1;

	this.HeaderInfo.Pages[0]      = {};
	this.HeaderInfo.Pages[0].Draw = false;

	this.RowsInfo[0] = new CTableRowsInfo();
	this.RowsInfo[0].Init();

	// Обнуляем таблицу суммарных высот ячеек
	for (var Index = -1; Index < this.Content.length; Index++)
	{
		this.TableRowsBottom[Index]    = [];
		this.TableRowsBottom[Index][0] = 0;
	}

	this.Pages[0].MaxBotBorder = 0;
	this.Pages[0].BotBorders   = [];

	if (this.Content.length > 0)
	{
		var CellsCount = this.Content[0].Get_CellsCount();
		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell = this.Content[0].Get_Cell(CurCell);
			Cell.Content.StartFromNewPage();
			Cell.PagesCount = 2;
		}
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Приватные функции связанные с рассчетом таблицы.
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.private_RecalculateCheckPageColumnBreak = function(CurPage)
{
    if (true !== this.Is_Inline()) // Случай Flow разбирается в Document.js
        return true;

    if (!this.LogicDocument || this.Parent !== this.LogicDocument)
        return true;

    var isPageBreakOnPrevLine   = false;
    var isColumnBreakOnPrevLine = false;

    var PrevElement = this.Get_DocumentPrev();

	while (PrevElement && (PrevElement instanceof CBlockLevelSdt))
		PrevElement = PrevElement.GetLastElement();

    if (null !== PrevElement && type_Paragraph === PrevElement.Get_Type() && true === PrevElement.Is_Empty() && undefined !== PrevElement.Get_SectionPr())
	{
		var PrevSectPr = PrevElement.Get_SectionPr();
		var CurSectPr  = this.LogicDocument.SectionsInfo.Get_SectPr(this.Index).SectPr;
		if (c_oAscSectionBreakType.Continuous === CurSectPr.Get_Type() && true === CurSectPr.Compare_PageSize(PrevSectPr))
			PrevElement = PrevElement.Get_DocumentPrev();
	}

    if ((0 === CurPage || true === this.Check_EmptyPages(CurPage - 1)) && null !== PrevElement && type_Paragraph === PrevElement.Get_Type())
    {
        var bNeedPageBreak = true;
        if (undefined !== PrevElement.Get_SectionPr())
        {
            var PrevSectPr = PrevElement.Get_SectionPr();
            var CurSectPr  = this.LogicDocument.SectionsInfo.Get_SectPr(this.Index).SectPr;
            if (c_oAscSectionBreakType.Continuous !== CurSectPr.Get_Type() || true !== CurSectPr.Compare_PageSize(PrevSectPr))
                bNeedPageBreak = false;
        }

        if (true === bNeedPageBreak)
        {
            var EndLine = PrevElement.Pages[PrevElement.Pages.length - 1].EndLine;
            if (-1 !== EndLine && PrevElement.Lines[EndLine].Info & paralineinfo_BreakRealPage)
                isPageBreakOnPrevLine = true;
        }
    }

    // ColumnBreak для случая CurPage > 0 не разбираем здесь, т.к. он срабатывает автоматически
    if (0 === CurPage && null !== PrevElement && type_Paragraph === PrevElement.Get_Type())
    {
        var EndLine = PrevElement.Pages[PrevElement.Pages.length - 1].EndLine;
        if (-1 !== EndLine && !(PrevElement.Lines[EndLine].Info & paralineinfo_BreakRealPage) && PrevElement.Lines[EndLine].Info & paralineinfo_BreakPage)
            isColumnBreakOnPrevLine = true;
    }

    if ((true === isPageBreakOnPrevLine && (0 !== this.private_GetColumnIndex(CurPage) || (0 === CurPage && null !== PrevElement)))
        || (true === isColumnBreakOnPrevLine && 0 === CurPage))
    {
        this.private_RecalculateSkipPage(CurPage);
        return false;
    }

    return true;
};
CTable.prototype.private_RecalculateGrid = function()
{
    //if ( true != this.RecalcInfo.TableGrid )
    //    return;

    if ( this.Content.length <= 0 )
        return;

    //---------------------------------------------------------------------------
    // 1 часть пересчета ширины таблицы : Рассчитываем фиксированную ширину
    //---------------------------------------------------------------------------
    var TablePr = this.Get_CompiledPr(false).TablePr;

    var Grid    = this.TableGrid;
    var SumGrid = [];

    var TempSum = 0;
    SumGrid[-1] = 0;
    for ( var Index = 0; Index < Grid.length; Index++ )
    {
        TempSum += Grid[Index];
        SumGrid[Index] = TempSum;
    }

    var PctWidth = this.private_RecalculatePercentWidth();
    var MinWidth = this.Internal_Get_TableMinWidth();
    var TableW = 0;
    if (tblwidth_Auto === TablePr.TableW.Type)
    {
        TableW = 0;
    }
    else if (tblwidth_Nil === TablePr.TableW.Type)
    {
        TableW = MinWidth;
    }
    else
    {
        if (tblwidth_Pct === TablePr.TableW.Type)
        {
            TableW = PctWidth * TablePr.TableW.W / 100;
        }
        else
        {
            TableW = TablePr.TableW.W
        }

        if (TableW < MinWidth)
            TableW = MinWidth;
    }

	var CurGridCol = 0;
	for (var Index = 0; Index < this.Content.length; Index++)
	{
		var Row = this.Content[Index];
		Row.Set_Index(Index);

		// Смотрим на ширину пропущенных колонок сетки в начале строки
		var BeforeInfo = Row.Get_Before();
		CurGridCol     = BeforeInfo.GridBefore;
		if (CurGridCol > 0 && SumGrid[CurGridCol - 1] < BeforeInfo.WBefore.W)
		{
			var nTempDiff = BeforeInfo.WBefore.W - SumGrid[CurGridCol - 1];
			for (var nTempIndex = CurGridCol - 1; nTempIndex < SumGrid.length; ++nTempIndex)
				SumGrid[nTempIndex] += nTempDiff;
		}

		var nCellSpacing = Row.GetCellSpacing();

		var CellsCount = Row.Get_CellsCount();
		for (var CellIndex = 0; CellIndex < CellsCount; CellIndex++)
		{
			var Cell = Row.Get_Cell(CellIndex);
			Cell.Set_Index(CellIndex);
			var CellW    = Cell.Get_W();
			var GridSpan = Cell.Get_GridSpan();

			if (CurGridCol + GridSpan - 1 > SumGrid.length)
			{
				for (var AddIndex = SumGrid.length; AddIndex <= CurGridCol + GridSpan - 1; AddIndex++)
					SumGrid[AddIndex] = SumGrid[AddIndex - 1] + 20; // Добавляем столбик шириной в 2 см
			}

			if (tblwidth_Auto !== CellW.Type && tblwidth_Nil !== CellW.Type)
			{
				var CellWidth = 0;
				if (tblwidth_Pct === CellW.Type)
					CellWidth = PctWidth * CellW.W / 100;
				else
					CellWidth = CellW.W;

				if (null !== nCellSpacing)
				{
					if (0 === CellIndex)
						CellWidth += nCellSpacing / 2;

					CellWidth += nCellSpacing;

					if (CellsCount - 1 === CellIndex)
						CellWidth += nCellSpacing / 2;
				}

				if (CellWidth + SumGrid[CurGridCol - 1] > SumGrid[CurGridCol + GridSpan - 1])
				{
					var nTempDiff = CellWidth + SumGrid[CurGridCol - 1] - SumGrid[CurGridCol + GridSpan - 1];
					for (var nTempIndex = CurGridCol + GridSpan - 1; nTempIndex < SumGrid.length; ++nTempIndex)
						SumGrid[nTempIndex] += nTempDiff;
				}
			}

			CurGridCol += GridSpan;
		}

		// Смотрим на ширину пропущенных колонок сетки в конце строки
		var AfterInfo = Row.Get_After();
		if (CurGridCol + AfterInfo.GridAfter - 1 > SumGrid.length)
		{
			for (var AddIndex = SumGrid.length; AddIndex <= CurGridCol + AfterInfo.GridAfter - 1; AddIndex++)
				SumGrid[AddIndex] = SumGrid[AddIndex - 1] + 20; // Добавляем столбик шириной в 2 см
		}

		if (SumGrid[CurGridCol + AfterInfo.GridAfter - 1] < AfterInfo.WAfter + SumGrid[CurGridCol - 1])
		{
			var nTempDiff = AfterInfo.WAfter + SumGrid[CurGridCol - 1] - SumGrid[CurGridCol + AfterInfo.GridAfter - 1];
			for (var nTempIndex = CurGridCol + AfterInfo.GridAfter - 1; nTempIndex < SumGrid.length; ++nTempIndex)
				SumGrid[nTempIndex] += nTempDiff;
		}
	}

    // TODO: разобраться с минимальной шириной таблицы и ячеек

    // Задана общая ширина таблицы и последняя ячейка вышла за пределы
    // данной ширины. Уменьшаем все столбцы сетки пропорционально, чтобы
    // суммарная ширина стала равной заданной ширине таблицы.
    if ( TableW > 0 && Math.abs( SumGrid[SumGrid.length - 1] - TableW ) > 0.01 )
    {
        SumGrid = this.Internal_ScaleTableWidth( SumGrid, TableW );
    }
    else if ( MinWidth > SumGrid[SumGrid.length - 1] )
        SumGrid = this.Internal_ScaleTableWidth( SumGrid, SumGrid[SumGrid.length - 1] );

    // По массиву SumGrid восстанавливаем ширины самих колонок
    this.TableGridCalc = [];
	this.TableGridCalc[0] = SumGrid[0];
    for ( var Index = 1; Index < SumGrid.length; Index++ )
		this.TableGridCalc[Index] = SumGrid[Index] - SumGrid[Index - 1];

    this.TableSumGrid = SumGrid;

    var TopTable = this.Parent.Is_InTable(true);
    if ( ( null === TopTable && tbllayout_AutoFit === TablePr.TableLayout) || ( null != TopTable && tbllayout_AutoFit === TopTable.Get_CompiledPr(false).TablePr.TableLayout ) )
    {
        //---------------------------------------------------------------------------
        // 2 часть пересчета ширины таблицы : Рассчитываем ширину по содержимому
        //---------------------------------------------------------------------------
        var MinMargin = [], MinContent = [], MaxContent = [], MaxFlags = [];

        var GridCount = this.TableGridCalc.length;
        for ( var CurCol = 0; CurCol < GridCount; CurCol++ )
        {
            MinMargin[CurCol]  = 0;
            MinContent[CurCol] = 0;
            MaxContent[CurCol] = 0;
            MaxFlags[CurCol]   = false; // false - ориентируемся на содержимое ячеек, true - ориентируемся только на ширину ячеек записанную в свойствах
        }

        // 1. Рассчитаем MinContent и MinMargin для всех колонок таблицы, причем, если
        //    у ячейки GridSpan > 1, тогда MinMargin учитывается только в первую колнонку,
        //    а MinContent распределяется равномерно по всем колонкам.

        var LeftMargin = 0, RightMargin = 0;
        var RowsCount = this.Content.length;
        for ( var CurRow = 0; CurRow < RowsCount; CurRow++ )
        {
            var Row = this.Content[CurRow];

            var Spacing  = Row.Get_CellSpacing();
            var SpacingW = ( null != Spacing ? Spacing : 0 );

            var CurGridCol = 0;

            // Смотрим на ширину пропущенных колонок сетки в начале строки
            var BeforeInfo = Row.Get_Before();
            var GridBefore = BeforeInfo.GridBefore;
            var WBefore    = BeforeInfo.WBefore;

            var WBeforeW   = null;
            if (tblwidth_Mm === WBefore.Type)
                WBeforeW = WBefore.W;
            else if (tblwidth_Pct === WBefore.Type)
                WBeforeW = PctWidth * WBefore.W / 100;

            if ( 1 === GridBefore )
            {
                if (null !== WBeforeW)
                {
                    if (MinContent[CurGridCol] < WBeforeW)
                        MinContent[CurGridCol] = WBeforeW;

                    if (false === MaxFlags[CurGridCol])
                    {
                        MaxFlags[CurGridCol] = true;
                        MaxContent[CurGridCol] = WBeforeW;
                    }
                    else if (MaxContent[CurGridCol] < WBeforeW)
                        MaxContent[CurGridCol] = WBeforeW;
                }
            }
            else if ( GridBefore > 1 )
            {
                var SumSpanMinContent = 0;
                var SumSpanMaxContent = 0;
                var SumSpanCurContent = 0;
                var SumSpanMinMargin  = 0;
                for ( var CurSpan = CurGridCol; CurSpan < CurGridCol + GridBefore; CurSpan++ )
                {
                    SumSpanMinContent += MinContent[CurSpan];
                    SumSpanMaxContent += MaxContent[CurSpan];
                    SumSpanMinMargin  += MinMargin[CurSpan];
                    SumSpanCurContent += this.TableGridCalc[CurSpan];
                }

                if (null !== WBeforeW && SumSpanMinContent < WBeforeW - SumSpanMinMargin)
                {
					for (var CurSpan = CurGridCol; CurSpan < CurGridCol + GridSpan; CurSpan++)
						MinContent[CurSpan] = WBeforeW * this.TableGridCalc[CurSpan] / SumSpanCurContent - MinMargin[CurSpan];
                }

                // Если у нас в объединении несколько колонок, тогда явно записанная ширина ячейки не
                // перекрывает ширину ни одной из колонок, она всего лишь учавствует в определении
                // максимальной ширины.
                if (null !== WBeforeW && WBeforeW > SumSpanMaxContent)
                {
                    // TODO: На самом деле, распределение здесь идет в каком-то отношении.
                    //       Неплохо было бы выяснить как именно.
                    for ( var CurSpan = CurGridCol; CurSpan < CurGridCol + GridBefore; CurSpan++ )
                        MaxContent[CurSpan] = WBeforeW * this.TableGridCalc[CurSpan] / SumSpanCurContent;
                }
            }


            CurGridCol = BeforeInfo.GridBefore;

            var CellsCount = Row.Get_CellsCount();
            for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
            {
                var Cell         = Row.Get_Cell( CurCell );
                var CellMinMax   = Cell.Content_RecalculateMinMaxContentWidth(false);
                var CellMin      = CellMinMax.Min;
                var CellMax      = CellMinMax.Max;
                var GridSpan     = Cell.Get_GridSpan();
                var CellMargins  = Cell.GetMargins();
                var CellW        = Cell.Get_W();
                var CellRBorder  = Cell.Get_Border(1);
                var CellLBorder  = Cell.Get_Border(3);
                var CellWW       = null;

                var Add = ( ( 0 === CurCell || CellsCount - 1 === CurCell ) ? 3 / 2 * SpacingW : SpacingW );

                CellMin += Add;
                CellMax += Add;

                if (tblwidth_Mm === CellW.Type)
                    CellWW = CellW.W + Add;
                else if (tblwidth_Pct === CellW.Type)
                    CellWW = PctWidth * CellW.W / 100 + Add;

				var CellMarginsLeftW = 0, CellMarginsRightW = 0;
				if (null !== Spacing)
				{
					CellMarginsLeftW  = CellMargins.Left.W;
					CellMarginsRightW = CellMargins.Right.W;

					if (border_None !== CellRBorder.Value)
						CellMarginsRightW += CellRBorder.Size;

					if (border_None !== CellLBorder.Value)
						CellMarginsLeftW += CellLBorder.Size;
				}
				else
				{
					if (border_None !== CellRBorder.Value)
						CellMarginsRightW += Math.max(CellRBorder.Size / 2, CellMargins.Right.W);
					else
						CellMarginsRightW += CellMargins.Right.W;

					if (border_None !== CellLBorder.Value)
						CellMarginsLeftW += Math.max(CellLBorder.Size / 2, CellMargins.Left.W);
					else
						CellMarginsLeftW += CellMargins.Left.W;
				}

				if (GridSpan <= 1)
				{
					if (MinMargin[CurGridCol] < CellMarginsLeftW + CellMarginsRightW)
						MinMargin[CurGridCol] = CellMarginsLeftW + CellMarginsRightW;
				}
				else
				{
					if (MinMargin[CurGridCol] < CellMarginsLeftW)
						MinMargin[CurGridCol] = CellMarginsLeftW;

					if (MinMargin[CurGridCol + GridSpan - 1] < CellMarginsRightW)
						MinMargin[CurGridCol + GridSpan - 1] = CellMarginsRightW;
				}

                // На самом деле, случай 1 === GridSpan нормально обработается и как случай GridSpan > 1,
                // но поскольку он наиболее распространен, делаем его обработку максимально быстрой (без циклов)
                if ( 1 === GridSpan )
                {
                    if ( MinContent[CurGridCol] < CellMin )
                        MinContent[CurGridCol] = CellMin;

                    if ( false === MaxFlags[CurGridCol] && MaxContent[CurGridCol] < CellMax )
                        MaxContent[CurGridCol] = CellMax;

                    // Согласно спецификации, если где-то задана ширина, то используется только первое значение
                    if (null !== CellWW && false === MaxFlags[CurGridCol])
                    {
						MaxFlags[CurGridCol]   = true;
						MaxContent[CurGridCol] = CellWW;
                    }
                }
                else
                {
                    var SumSpanMinContent = 0;
                    var SumSpanMaxContent = 0;
                    var SumSpanCurContent = 0;
                    var SumSpanMinMargin  = 0;
                    for ( var CurSpan = CurGridCol; CurSpan < CurGridCol + GridSpan; CurSpan++ )
                    {
                        SumSpanMinContent += MinContent[CurSpan];
                        SumSpanMaxContent += MaxContent[CurSpan];
                        SumSpanMinMargin  += MinMargin[CurSpan];
                        SumSpanCurContent += this.TableGridCalc[CurSpan];
                    }

					if (SumSpanMinContent < CellMin - SumSpanMinMargin)
					{
						for (var CurSpan = CurGridCol; CurSpan < CurGridCol + GridSpan; CurSpan++)
							MinContent[CurSpan] = CellMin * this.TableGridCalc[CurSpan] / SumSpanCurContent - MinMargin[CurSpan];
					}

                    // Если у нас в объединении несколько колонок, тогда явно записанная ширина ячейки не
                    // перекрывает ширину ни одной из колонок, она всего лишь учавствует в определении
                    // максимальной ширины.
                    if (null !== CellWW && CellWW > CellMax)
					{
						CellMax = CellWW;
						for (var CurSpan = CurGridCol; CurSpan < CurGridCol + GridSpan; ++CurSpan)
						{
							// Согласно спецификации, если где-то задана ширина, то используется только первое значение
							if (false === MaxFlags[CurSpan])
							{
								MaxFlags[CurSpan]   = true;
								MaxContent[CurSpan] = this.TableGridCalc[CurSpan];
							}
						}
					}
					else
					{
						if (SumSpanMaxContent < CellMax)
						{
							// TODO: На самом деле, распределение здесь идет в каком-то отношении.
							//       Неплохо было бы выяснить как именно.
							for (var CurSpan = CurGridCol; CurSpan < CurGridCol + GridSpan; CurSpan++)
							{
								// Согласно спецификации, если где-то задана ширина, то используется только первое значение
								if (true !== MaxFlags[CurSpan])
									MaxContent[CurSpan] = CellMax * this.TableGridCalc[CurSpan] / SumSpanCurContent;
							}
						}
					}
                }

                if ( 0 === CurRow && 0 === CurCell )
                    LeftMargin = CellMargins.Left.W;

                if ( 0 === CurRow && CellsCount - 1 === CurCell )
                    RightMargin = CellMargins.Right.W;

                CurGridCol += GridSpan;
            }

            var AfterInfo = Row.Get_After();
            var GridAfter = AfterInfo.GridAfter;
            var WAfter    = AfterInfo.WAfter;

            var WAfterW   = null;
            if (tblwidth_Mm === WAfter.Type)
                WAfterW = WAfter.W;
            else if (tblwidth_Pct === WAfter.Type)
                WAfterW = PctWidth * WAfter.W / 100;

            if ( 1 === GridAfter )
            {
                if (null !== WAfterW)
                {
                    if (MinContent[CurGridCol] < WAfterW)
                        MinContent[CurGridCol] = WAfterW;

                    if ( false === MaxFlags[CurGridCol] )
                    {
                        MaxFlags[CurGridCol] = true;
                        MaxContent[CurGridCol] = WAfterW;
                    }
                    else if (MaxContent[CurGridCol] < WAfterW)
                    {
                        MaxContent[CurGridCol] = WAfterW;
                    }
                }
            }
            else if ( GridAfter > 1 )
            {
                var SumSpanMinContent = 0;
                var SumSpanMaxContent = 0;
                var SumSpanCurContent = 0;
                for ( var CurSpan = CurGridCol; CurSpan < CurGridCol + GridAfter; CurSpan++ )
                {
                    SumSpanMinContent += MinContent[CurSpan];
                    SumSpanMaxContent += MaxContent[CurSpan];
                    SumSpanCurContent += this.TableGridCalc[CurSpan];
                }

                if (null !== WAfterW && SumSpanMinContent < WAfterW)
                {
                    for ( var CurSpan = CurGridCol; CurSpan < CurGridCol + GridSpan; CurSpan++ )
                        MinContent[CurSpan] = WAfterW * this.TableGridCalc[CurSpan] / SumSpanCurContent;
                }

                // Если у нас в объединении несколько колонок, тогда явно записанная ширина ячейки не
                // перекрывает ширину ни одной из колонок, она всего лишь учавствует в определении
                // максимальной ширины.
                if (null !== WAfterW && WAfterW > SumSpanMaxContent )
                {
                    // TODO: На самом деле, распределение здесь идет в каком-то отношении.
                    //       Неплохо было бы выяснить как именно.
                    for ( var CurSpan = CurGridCol; CurSpan < CurGridCol + GridAfter; CurSpan++ )
                        MaxContent[CurSpan] = WAfterW * this.TableGridCalc[CurSpan] / SumSpanCurContent;
                }
            }
        }

        for ( var CurCol = 0; CurCol < GridCount; CurCol++ )
        {
            if ( true === MaxFlags[CurCol] )
                MaxContent[CurCol] = Math.max( 0, MaxContent[CurCol] - MinMargin[CurCol] );

            if (MaxContent[CurCol] < MinContent[CurCol])
                MaxContent[CurCol] = MinContent[CurCol];
        }

        // 2. Проследим, чтобы значения MinContent + MinMargin и MaxContent + MinMargin не превосходили
        //    значение 55,87см(так работает Word)
        for ( var CurCol = 0; CurCol < GridCount; CurCol++ )
        {
            if ( MinMargin[CurCol] + MinContent[CurCol] > 558.7 )
                MinContent[CurCol] = Math.max(558.7 - MinMargin[CurCol] , 0);

            if ( MinMargin[CurCol] + MaxContent[CurCol] > 558.7 )
                MaxContent[CurCol] = Math.max(558.7 - MinMargin[CurCol] , 0);
        }

        // 3. Рассчитаем максимально допустимую ширину под всю таблицу
        var PageFields = this.Parent.Get_ColumnFields ? this.Parent.Get_ColumnFields(this.Get_Index(), this.Get_AbsoluteColumn(this.PageNum)) : this.Parent.Get_PageFields(this.private_GetRelativePageIndex(this.PageNum));
        var MaxTableW = PageFields.XLimit - PageFields.X - TablePr.TableInd;
        if ( null === TopTable )
            MaxTableW += LeftMargin + RightMargin; // Добавляем левый маргин первой ячейки + правый маргин правой ячейки для верхних таблиц

        var TableSpacing = this.Content[0].Get_CellSpacing();
        if ( null != TableSpacing )
            MaxTableW += 2 * TableSpacing;

        // 4. Рассчитаем желаемую ширину таблицы таблицы
        // Цифра 2 означает добавочная разница
        var MaxContent2 = [];
        var SumMin = 0, SumMinMargin = 0, SumMinContent = 0, SumMax = 0, SumMaxContent2 = 0;
        var TableGrid2 = [];
        for ( var CurCol = 0; CurCol < GridCount; CurCol++ )
        {
            var Temp = MinMargin[CurCol] + MinContent[CurCol];
            TableGrid2[CurCol] = this.TableGridCalc[CurCol];
            if ( Temp < this.TableGridCalc[CurCol] )
            {
                TableGrid2[CurCol] = this.TableGridCalc[CurCol];
            }
            else
            {
                TableGrid2[CurCol] = Temp;
            }

            MaxContent2[CurCol] = Math.max( 0, MaxContent[CurCol] - MinContent[CurCol] );

            SumMin         += Temp;
            SumMaxContent2 += MaxContent2[CurCol];
            SumMinMargin   += MinMargin[CurCol];
            SumMinContent  += MinContent[CurCol];
            SumMax         += MinMargin[CurCol] + MinContent[CurCol] + MaxContent2[CurCol];
        }

        if ((tblwidth_Mm === TablePr.TableW.Type || tblwidth_Pct === TablePr.TableW.Type) && MaxTableW < TableW)
            MaxTableW = TableW;

        if ( SumMin < MaxTableW )
        {
            // SumMin < MaxTableW, значит у нас есть свободное пространство для распределения
            // У нас есть три типа ширины: Min < Preffered < Max

            var SumMin = 0, SumPreffered = 0, SumMax = 0;
            var PreffOverMin = [], MaxOverPreff = [];
            var SumPreffOverMin = 0, SumMaxOverPreff = 0;
            var PreffContent = [];

            for (var CurCol = 0; CurCol < GridCount; ++CurCol)
            {
                var MinW   = MinMargin[CurCol] + MinContent[CurCol];
                var MaxW   = MinMargin[CurCol] + MaxContent[CurCol];
                var PreffW = (true === MaxFlags[CurCol] ? MaxW : MinW);

                SumMin       += MinW;
                SumPreffered += PreffW;
                SumMax       += MaxW;

                PreffContent[CurCol] = PreffW - MinMargin[CurCol];
                PreffOverMin[CurCol] = Math.max(0, PreffW - MinW);
                MaxOverPreff[CurCol] = Math.max(0, MaxW - PreffW);

                SumPreffOverMin += PreffOverMin[CurCol];
                SumMaxOverPreff += MaxOverPreff[CurCol];
            }

            if ( SumMax <= MaxTableW || SumMaxContent2 < 0.001 )
            {
                for ( var CurCol = 0; CurCol < GridCount; CurCol++ )
                {
                    this.TableGridCalc[CurCol] = MinMargin[CurCol] + Math.max(MinContent[CurCol], MaxContent[CurCol]);
                }
            }
            else
            {
                for ( var CurCol = 0; CurCol < GridCount; CurCol++ )
                {
                    this.TableGridCalc[CurCol] = MinMargin[CurCol] + MinContent[CurCol] + (MaxTableW - SumMin) * MaxContent2[CurCol] / SumMaxContent2;
                }
            }

            // Если у таблицы задана ширина, тогда ориентируемся по ширине, а если нет, тогда ориентируемся по
            // максимальным значениям.
            if (tblwidth_Mm === TablePr.TableW.Type || tblwidth_Pct === TablePr.TableW.Type)
            {
                if (SumMin < 0.001 && SumMax < 0.001)
                {
                    // Распределяем ширину по количеству колонок
                    for (var CurCol = 0; CurCol < GridCount; ++CurCol)
                    {
                        this.TableGridCalc[CurCol] = TableW / GridCount;
                    }
                }
                else if (SumMin >= TableW)
                {
                    // Выставляем минимальные значения
                    for (var CurCol = 0; CurCol < GridCount; ++CurCol)
                    {
                        this.TableGridCalc[CurCol] = MinMargin[CurCol] + MinContent[CurCol];
                    }
                }
                else if (SumPreffered >= TableW && SumPreffOverMin > 0.001)
                {
                    // Растягиваем только те колонки, в которых заданы предпочитаемые ширины
                    for (var CurCol = 0; CurCol < GridCount; ++CurCol)
                    {
                        this.TableGridCalc[CurCol] = MinMargin[CurCol] + MinContent[CurCol] + (TableW - SumMin) * PreffOverMin[CurCol] / SumPreffOverMin;
                    }
                }
                else
                {
                    // Если данное условие выполняется, значит у нас все ячейки с предпочитаемыми значениями, тогда
                    // мы растягиваем все ячейки равномерно. Если не выполняется, значит есть ячейки, в которых
                    // предпочитаемое значение не задано, и тогда растягиваем только такие ячейки.
                    if (Math.abs(SumMax - SumPreffered) < 0.001)
                    {
                        if (SumMax >= TableW)
                        {
                            for (var CurCol = 0; CurCol < GridCount; ++CurCol)
                            {
                                this.TableGridCalc[CurCol] = MinMargin[CurCol] + MinContent[CurCol] + (TableW - SumMin) * MaxContent2[CurCol] / SumMaxContent2;
                            }
                        }
                        else
                        {
                            for (var CurCol = 0; CurCol < GridCount; CurCol++)
                            {
                                this.TableGridCalc[CurCol] = MinMargin[CurCol] + MaxContent[CurCol] + (TableW - SumMax) * (MinMargin[CurCol] + MaxContent[CurCol]) / SumMax;
                            }
                        }
                    }
                    else
                    {
                        for (var CurCol = 0; CurCol < GridCount; ++CurCol)
                        {
                            this.TableGridCalc[CurCol] = MinMargin[CurCol] + PreffContent[CurCol] + (TableW - SumPreffered) * MaxOverPreff[CurCol] / SumMaxOverPreff;
                        }
                    }
                }
            }
        }
        else
        {
            // 5. Если в таблице сделать все ячейки нулевой ширины (для контента), и все равно она получается шире
            //    максимальной допустимой ширины, тогда выставляем ширины всех колоно по минимальному значению
            //    маргинов и оставляем так как есть
            if (MaxTableW - SumMinMargin < 0.001)
            {
                for ( var CurCol = 0; CurCol < GridCount; CurCol++ )
                {
                    this.TableGridCalc[CurCol] = MinMargin[CurCol];
                }
            }
            else
            {
                // 6. Равномерно уменьшаем все колонки до достижения суммарного значения MaxTableW
                var ColsDiff = [];
                var SumColsDiff = 0;
                for ( var CurCol = 0; CurCol < GridCount; CurCol++ )
                {
                    var Temp = TableGrid2[CurCol] - MinMargin[CurCol];
                    ColsDiff[CurCol] = Temp;
                    SumColsDiff += Temp;
                }

                for ( var CurCol = 0; CurCol < GridCount; CurCol++ )
                {
                    TableGrid2[CurCol] = MinMargin[CurCol] + (MaxTableW - SumMinMargin) * ColsDiff[CurCol] / SumColsDiff;
                }

                // 7. Ищем колонки, у которых текущая ширина меньше MinContent (заодно ищем недостоющую сумму).
                //    Также запоминаем остальные колонки и находим у них избыточную сумму.
                var SumN = 0, SumI = 0;
                var GridCols = [];
                for ( var CurCol = 0; CurCol < GridCount; CurCol++ )
                {
                    var Temp = TableGrid2[CurCol] - (MinMargin[CurCol] + MinContent[CurCol]);
                    if ( Temp >= 0 )
                    {
                        GridCols[CurCol] = Temp;
                        SumI += Temp;
                    }
                    else
                    {
                        GridCols[CurCol] = -1;
                        SumN -= Temp;
                    }
                }

                // 8. Если недостающего пространста больше, чем избыточного, тогда ищем разницу
                //    (MaxTableW - SumMinMargin) и распределяем ее в отношении, как соотносятся
                //    значения MinContent между собой.
                if (SumN > SumI || SumI < 0.001)
                {
                    if (SumMinContent > 0.001)
                    {
                        var SumDiff = MaxTableW - SumMinMargin;
                        for (var CurCol = 0; CurCol < GridCount; CurCol++)
                        {
                            this.TableGridCalc[CurCol] = MinMargin[CurCol] + SumDiff * MinContent[CurCol] / SumMinContent;
                        }
                    }
                    else
                    {
                        for (var CurCol = 0; CurCol < GridCount; CurCol++)
                        {
                            this.TableGridCalc[CurCol] = MinMargin[CurCol];
                        }
                    }
                }
                else
                {
                    for ( var CurCol = 0; CurCol < GridCount; CurCol++ )
                    {
                        if ( GridCols[CurCol] < 0 )
                        {
                            this.TableGridCalc[CurCol] = MinMargin[CurCol] + MinContent[CurCol];
                        }
                        else
                        {
                            this.TableGridCalc[CurCol] = TableGrid2[CurCol] - SumN * GridCols[CurCol] / SumI;
                        }
                    }
                }
            }
        }


        this.TableSumGrid[-1] = 0;
        for ( var CurCol = 0; CurCol < GridCount; CurCol++ )
            this.TableSumGrid[CurCol] = this.TableSumGrid[CurCol - 1] + this.TableGridCalc[CurCol];
    }

    this.RecalcInfo.TableGrid = false;
};
CTable.prototype.private_RecalculateBorders = function()
{
    if ( true != this.RecalcInfo.TableBorders )
        return;

    // Обнуляем таблицу суммарных высот ячеек
    for ( var Index = -1; Index < this.Content.length; Index++ )
    {
        this.TableRowsBottom[Index] = [];
        this.TableRowsBottom[Index][0] = 0;
    }

    // Изначально найдем верхние границы и (если нужно) нижние границы
    // для каждой ячейки.
    var MaxTopBorder = [];
    var MaxBotBorder = [];
    var MaxBotMargin = [];

    for ( var Index = 0; Index < this.Content.length; Index++ )
    {
        MaxBotBorder[Index] = 0;
        MaxTopBorder[Index] = 0;
        MaxBotMargin[Index] = 0;
    }

    var TablePr = this.Get_CompiledPr(false).TablePr;
    var TableBorders = this.Get_Borders();

    for ( var CurRow = 0; CurRow < this.Content.length; CurRow++ )
    {
        var Row         = this.Content[CurRow];
        var CellsCount  = Row.Get_CellsCount();
        var CellSpacing = Row.Get_CellSpacing();

        var BeforeInfo = Row.Get_Before();
        var AfterInfo  = Row.Get_After();
        var CurGridCol = BeforeInfo.GridBefore;

        // Нам нужно пробежаться по текущей строке и выяснить максимальное значение ширины верхней
        // границы и ширины нижней границы, заодно рассчитаем вид границы у каждой ячейки,
        // также надо рассчитать максимальное значение нижнего отступа всей строки.

        var bSpacing_Top = false;
        var bSpacing_Bot = false;

        if ( null != CellSpacing )
        {
            bSpacing_Bot = true;
            bSpacing_Top = true;
        }
        else
        {
            if ( 0 != CurRow )
            {
                var PrevCellSpacing = this.Content[CurRow - 1].Get_CellSpacing();
                if ( null != PrevCellSpacing )
                    bSpacing_Top = true;
            }

            if ( this.Content.length - 1 != CurRow )
            {
                var NextCellSpacing = this.Content[CurRow + 1].Get_CellSpacing();
                if ( null != NextCellSpacing )
                    bSpacing_Bot = true;
            }
        }

        Row.Set_SpacingInfo( bSpacing_Top, bSpacing_Bot );

        for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
        {
            var Cell     = Row.Get_Cell( CurCell );
            var GridSpan = Cell.Get_GridSpan();
            var Vmerge   = Cell.GetVMerge();

            Row.Set_CellInfo( CurCell, CurGridCol, 0, 0, 0, 0, 0, 0 );

            // Bug 32418 ячейки, участвующие в вертикальном объединении, все равно участвуют в определении границы
            // строки, поэтому здесь мы их не пропускаем.

            var VMergeCount = this.Internal_GetVertMergeCount( CurRow, CurGridCol, GridSpan );

            var CellMargins = Cell.GetMargins();
            if ( CellMargins.Bottom.W > MaxBotMargin[CurRow + VMergeCount - 1] )
                MaxBotMargin[CurRow + VMergeCount - 1] = CellMargins.Bottom.W;

            var CellBorders = Cell.Get_Borders();
            if ( true === bSpacing_Top )
            {
                if ( border_Single === CellBorders.Top.Value && MaxTopBorder[CurRow] < CellBorders.Top.Size )
                    MaxTopBorder[CurRow] = CellBorders.Top.Size;

                Cell.Set_BorderInfo_Top( [ CellBorders.Top ] );
            }
            else
            {
                if ( 0 === CurRow )
                {
                    // Сравним границы
                    var Result_Border = this.Internal_CompareBorders( TableBorders.Top, CellBorders.Top, true, false );
                    if ( border_Single === Result_Border.Value && MaxTopBorder[CurRow] < Result_Border.Size )
                        MaxTopBorder[CurRow] = Result_Border.Size;

                    var BorderInfo_Top = [];
                    for ( var TempIndex = 0; TempIndex < GridSpan; TempIndex++ )
                        BorderInfo_Top.push( Result_Border );

                    Cell.Set_BorderInfo_Top( BorderInfo_Top );
                }
                else
                {
                    // Ищем в предыдущей строке первую ячейку, пересекающуюся с [CurGridCol, CurGridCol + GridSpan]
                    var Prev_Row = this.Content[CurRow - 1];
                    var Prev_CellsCount = Prev_Row.Get_CellsCount();
                    var Prev_BeforeInfo = Prev_Row.Get_Before();
                    var Prev_AfterInfo  = Prev_Row.Get_After();

                    var Prev_Pos = -1;

                    var Prev_GridCol = Prev_BeforeInfo.GridBefore;
                    for ( var PrevCell = 0; PrevCell < Prev_CellsCount; PrevCell++ )
                    {
                        var Prev_Cell      = Prev_Row.Get_Cell( PrevCell );
                        var Prev_GridSpan  = Prev_Cell.Get_GridSpan();

                        if ( Prev_GridCol <= CurGridCol + GridSpan - 1 && Prev_GridCol + Prev_GridSpan - 1 >= CurGridCol )
                        {
                            Prev_Pos = PrevCell;
                            break;
                        }

                        Prev_GridCol += Prev_GridSpan;
                    }

                    var Border_Top_Info = [];

                    // Сначала посмотрим пересечение с GridBefore предыдущей строки
                    if ( CurGridCol <= Prev_BeforeInfo.GridBefore - 1 )
                    {
                        var Result_Border = this.Internal_CompareBorders( TableBorders.Left, CellBorders.Top, true, false );
                        if ( border_Single === Result_Border.Value && MaxTopBorder[CurRow] < Result_Border.Size )
                            MaxTopBorder[CurRow] = Result_Border.Size;

                        var AddCount = Math.min( Prev_BeforeInfo.GridBefore - CurGridCol, GridSpan );
                        for ( var TempIndex = 0; TempIndex < AddCount; TempIndex++ )
                            Border_Top_Info.push( Result_Border );
                    }

                    if ( -1 != Prev_Pos )
                    {
                        while ( Prev_GridCol <= CurGridCol + GridSpan - 1 && Prev_Pos < Prev_CellsCount )
                        {
                            var Prev_Cell      = Prev_Row.Get_Cell( Prev_Pos );
                            var Prev_GridSpan  = Prev_Cell.Get_GridSpan();

                            // Если данная ячейка учавствует в вертикальном объединении,
                            // тогда найдем нижнюю ячейку.

                            var Prev_VMerge = Prev_Cell.GetVMerge();
                            if ( vmerge_Continue === Prev_VMerge )
                                Prev_Cell = this.Internal_Get_EndMergedCell(CurRow - 1, Prev_GridCol, Prev_GridSpan);

                            var PrevBorders = Prev_Cell.Get_Borders();

                            // Сравним границы
                            var Result_Border = this.Internal_CompareBorders( PrevBorders.Bottom, CellBorders.Top, false, false );
                            if ( border_Single === Result_Border.Value && MaxTopBorder[CurRow] < Result_Border.Size )
                                MaxTopBorder[CurRow] = Result_Border.Size;

                            // Надо добавить столько раз, сколько колонок находится в пересечении этих двух ячееки
                            var AddCount = 0;
                            if ( Prev_GridCol >= CurGridCol )
                            {
                                if ( Prev_GridCol + Prev_GridSpan - 1 > CurGridCol + GridSpan - 1 )
                                    AddCount = CurGridCol + GridSpan - Prev_GridCol;
                                else
                                    AddCount = Prev_GridSpan;
                            }
                            else if ( Prev_GridCol + Prev_GridSpan - 1 > CurGridCol + GridSpan - 1 )
                                AddCount = GridSpan;
                            else
                                AddCount = Prev_GridCol + Prev_GridSpan - CurGridCol;

                            for ( var TempIndex = 0; TempIndex < AddCount; TempIndex++ )
                                Border_Top_Info.push( Result_Border );

                            Prev_Pos++;
                            Prev_GridCol += Prev_GridSpan;
                        }
                    }

                    // Посмотрим пересечение с GridAfter предыдущей строки
                    if ( Prev_AfterInfo.GridAfter > 0 )
                    {
                        var StartAfterGrid = Prev_Row.Get_CellInfo( Prev_CellsCount - 1 ).StartGridCol + Prev_Row.Get_Cell( Prev_CellsCount - 1 ).Get_GridSpan();

                        if ( CurGridCol + GridSpan - 1 >= StartAfterGrid )
                        {
                            var Result_Border = this.Internal_CompareBorders( TableBorders.Right, CellBorders.Top, true, false );
                            if ( border_Single === Result_Border.Value && MaxTopBorder[CurRow] < Result_Border.Size )
                                MaxTopBorder[CurRow] = Result_Border.Size;

                            var AddCount = Math.min( CurGridCol + GridSpan - StartAfterGrid, GridSpan );
                            for ( var TempIndex = 0; TempIndex < AddCount; TempIndex++ )
                                Border_Top_Info.push( Result_Border );
                        }
                    }

                    Cell.Set_BorderInfo_Top( Border_Top_Info );
                }
            }

            var CellBordersBottom = CellBorders.Bottom;
            if (VMergeCount > 1)
            {
                // Берем нижнюю границу нижней ячейки вертикального объединения.
                var BottomCell = this.Internal_Get_EndMergedCell(CurRow, CurGridCol, GridSpan);
                if (null !== BottomCell)
                    CellBordersBottom = BottomCell.Get_Borders().Bottom;
            }

            if ( true === bSpacing_Bot )
            {
                Cell.Set_BorderInfo_Bottom( [CellBordersBottom], -1, -1 );

                if ( border_Single === CellBordersBottom.Value && CellBordersBottom.Size > MaxBotBorder[CurRow + VMergeCount - 1] )
                    MaxBotBorder[CurRow + VMergeCount - 1] = CellBordersBottom.Size;
            }
            else
            {
                if ( this.Content.length - 1 === CurRow + VMergeCount - 1 )
                {
                    // Сравним границы
                    var Result_Border = this.Internal_CompareBorders( TableBorders.Bottom, CellBordersBottom, true, false );

                    if ( border_Single === Result_Border.Value && Result_Border.Size > MaxBotBorder[CurRow + VMergeCount - 1] )
                        MaxBotBorder[CurRow + VMergeCount - 1] = Result_Border.Size;

                    if ( GridSpan > 0 )
                    {
                        for ( var TempIndex = 0; TempIndex < GridSpan; TempIndex++ )
                            Cell.Set_BorderInfo_Bottom( [ Result_Border ], -1, -1 );
                    }
                    else
                        Cell.Set_BorderInfo_Bottom( [ ], -1, -1 );
                }
                else
                {
                    // Мы должны проверить нижнюю границу ячейки, на предмет того, что со следующей строкой
                    // она может пересекаться по GridBefore и/или GridAfter. Везде в таких местах мы должны
                    // нарисовать нижнюю границу. Пересечение с ячейками нам неинтересено, потому что этот
                    // случай будет учтен при обсчете следующей строки (там будет случай bSpacing_Top = false
                    // и 0 != CurRow )

                    var Next_Row = this.Content[CurRow + VMergeCount];
                    var Next_CellsCount = Next_Row.Get_CellsCount();
                    var Next_BeforeInfo = Next_Row.Get_Before();
                    var Next_AfterInfo  = Next_Row.Get_After();

                    var Border_Bottom_Info = [];

                    // Сначала посмотрим пересечение с GridBefore предыдущей строки
                    var BeforeCount = 0;
                    if ( CurGridCol <= Next_BeforeInfo.GridBefore - 1 )
                    {
                        var Result_Border = this.Internal_CompareBorders( TableBorders.Left, CellBordersBottom, true, false );
                        BeforeCount = Math.min( Next_BeforeInfo.GridBefore - CurGridCol, GridSpan );

                        for ( var TempIndex = 0; TempIndex < BeforeCount; TempIndex++ )
                            Border_Bottom_Info.push( Result_Border );
                    }

                    var Next_GridCol = Next_BeforeInfo.GridBefore;
                    for ( var NextCell = 0; NextCell < Next_CellsCount; NextCell++ )
                    {
                        var Next_Cell     = Next_Row.Get_Cell( NextCell );
                        var Next_GridSpan = Next_Cell.Get_GridSpan();
                        Next_GridCol += Next_GridSpan;
                    }

                    // Посмотрим пересечение с GridAfter предыдущей строки
                    var AfterCount = 0;
                    if ( Next_AfterInfo.GridAfter > 0 )
                    {
                        var StartAfterGrid = Next_GridCol;

                        if ( CurGridCol + GridSpan - 1 >= StartAfterGrid )
                        {
                            var Result_Border = this.Internal_CompareBorders( TableBorders.Right, CellBordersBottom, true, false );
                            AfterCount = Math.min( CurGridCol + GridSpan - StartAfterGrid, GridSpan );
                            for ( var TempIndex = 0; TempIndex < AfterCount; TempIndex++ )
                                Border_Bottom_Info.push( Result_Border );
                        }
                    }

                    Cell.Set_BorderInfo_Bottom( Border_Bottom_Info, BeforeCount, AfterCount );
                }
            }

            CurGridCol += GridSpan;
        }
    }

    this.MaxTopBorder = MaxTopBorder;
    this.MaxBotBorder = MaxBotBorder;
    this.MaxBotMargin = MaxBotMargin;

    // Также для каждой ячейки обсчитаем ее метрики и левую и правую границы
    for ( var CurRow = 0; CurRow < this.Content.length; CurRow++  )
    {
        var Row         = this.Content[CurRow];
        var CellsCount  = Row.Get_CellsCount();
        var CellSpacing = Row.Get_CellSpacing();

        var BeforeInfo  = Row.Get_Before();
        var AfterInfo   = Row.Get_After();
        var CurGridCol  = BeforeInfo.GridBefore;

        var Row_x_max = 0;
        var Row_x_min = 0;

        for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
        {
            var Cell     = Row.Get_Cell( CurCell );
            var GridSpan = Cell.Get_GridSpan();
            var Vmerge   = Cell.GetVMerge();

            // начальная и конечная точки данного GridSpan'a
            var X_grid_start = this.TableSumGrid[CurGridCol - 1];
            var X_grid_end   = this.TableSumGrid[CurGridCol + GridSpan - 1];

            // границы самой ячейки
            var X_cell_start = X_grid_start;
            var X_cell_end   = X_grid_end;

            if ( null != CellSpacing )
            {

                if ( 0 === CurCell )
                {
                    if ( 0 === BeforeInfo.GridBefore )
                    {
                        if ( border_None === TableBorders.Left.Value || CellSpacing > TableBorders.Left.Size / 2 )
                            X_cell_start += CellSpacing;
                        else
                            X_cell_start += TableBorders.Left.Size / 2;
                    }
                    else
                    {
                        if ( border_None === TableBorders.Left.Value || CellSpacing > TableBorders.Left.Size ) // CellSpacing / 2 > TableBorders.Left.Size / 2
                            X_cell_start += CellSpacing / 2;
                        else
                            X_cell_start += TableBorders.Left.Size / 2;
                    }
                }
                else
                    X_cell_start += CellSpacing / 2;

                if ( CellsCount - 1 === CurCell )
                {
                    if ( 0 === AfterInfo.GridAfter )
                    {
                        if ( border_None === TableBorders.Right.Value || CellSpacing > TableBorders.Right.Size / 2 )
                            X_cell_end -= CellSpacing;
                        else
                            X_cell_end -= TableBorders.Right.Size / 2;
                    }
                    else
                    {
                        if ( border_None === TableBorders.Right.Value || CellSpacing > TableBorders.Right.Size ) // CellSpacing / 2 > TableBorders.Right.Size / 2
                            X_cell_end -= CellSpacing / 2;
                        else
                            X_cell_end -= TableBorders.Right.Size / 2;
                    }
                }
                else
                    X_cell_end -= CellSpacing / 2;
            }

            var CellMar = Cell.GetMargins();

            var VMergeCount = this.Internal_GetVertMergeCount( CurRow, CurGridCol, GridSpan );

            // начальная и конечная точка для содержимого данной ячейки
            var X_content_start = X_cell_start;
            var X_content_end   = X_cell_end;

            // Левая и правая границы ячейки рисуются вовнутрь ячейки, если Spacing != null.
            var CellBorders = Cell.Get_Borders();
            if ( null != CellSpacing )
            {
                X_content_start += CellMar.Left.W;
                X_content_end   -= CellMar.Right.W;

                if ( border_Single === CellBorders.Left.Value )
                    X_content_start += CellBorders.Left.Size;

                if ( border_Single === CellBorders.Right.Value )
                    X_content_end -= CellBorders.Right.Size;
            }
            else
            {
                if ( vmerge_Continue === Vmerge )
                {
                    X_content_start += CellMar.Left.W;
                    X_content_end   -= CellMar.Right.W;
                }
                else
                {
                    // Линии правой и левой границы рисуются ровно по сетке
                    // (середина линии(всмысле толщины линии) совпадает с линией сетки).
                    // Мы должны найти максимальную толщину линии, учавствущую в правой/левой
                    // границах. Если данная толщина меньше соответствующего отступа, тогда
                    // она не влияет на расположение содержимого ячейки, в противном случае,
                    // максимальная толщина линии и задает отступ для содержимого.

                    // Поэтому первым шагом определим максимальную толщину правой и левой границ.

                    var Max_r_w = 0;
                    var Max_l_w = 0;
                    var Borders_Info =
                        {
                            Right     : [],
                            Left      : [],

                            Right_Max : 0,
                            Left_Max  : 0
                        };

                    for ( var Temp_CurRow = 0; Temp_CurRow < VMergeCount; Temp_CurRow++ )
                    {
                        var Temp_Row = this.Content[CurRow + Temp_CurRow];
                        var Temp_CellsCount = Temp_Row.Get_CellsCount();

                        // ищем ячейку текущего объединения
                        var Temp_CurCell = this.private_GetCellIndexByStartGridCol( CurRow + Temp_CurRow, CurGridCol );
                        if ( Temp_CurCell < 0 )
                            continue;

                        // левая граница
                        if ( 0 === Temp_CurCell )
                        {
                            var LeftBorder = this.Internal_CompareBorders( TableBorders.Left, CellBorders.Left, true, false );
                            if ( border_Single === LeftBorder.Value && LeftBorder.Size > Max_l_w )
                                Max_l_w = LeftBorder.Size;

                            Borders_Info.Left.push( LeftBorder );
                        }
                        else
                        {
                            var Temp_Prev_Cell = Temp_Row.Get_Cell( Temp_CurCell - 1 );
                            var Temp_Prev_VMerge = Temp_Prev_Cell.GetVMerge();
                            if ( 0 != Temp_CurRow && vmerge_Continue === Temp_Prev_VMerge )
                            {
                                Borders_Info.Left.push( Borders_Info.Left[Borders_Info.Left.length - 1] );
                            }
                            else
                            {
                                var Temp_Prev_Main_Cell = this.Internal_Get_StartMergedCell( CurRow + Temp_CurRow, CurGridCol - Temp_Prev_Cell.Get_GridSpan(), Temp_Prev_Cell.Get_GridSpan() );
                                var Temp_Prev_Main_Cell_Borders = Temp_Prev_Main_Cell.Get_Borders();

                                var LeftBorder = this.Internal_CompareBorders( Temp_Prev_Main_Cell_Borders.Right, CellBorders.Left, false, false );
                                if ( border_Single === LeftBorder.Value && LeftBorder.Size > Max_l_w )
                                    Max_l_w = LeftBorder.Size;

                                Borders_Info.Left.push( LeftBorder );
                            }
                        }

                        if ( Temp_CellsCount - 1 === Temp_CurCell )
                        {
                            var RightBorder = this.Internal_CompareBorders( TableBorders.Right, CellBorders.Right, true, false );
                            if ( border_Single === RightBorder.Value && RightBorder.Size > Max_r_w )
                                Max_r_w = RightBorder.Size;

                            Borders_Info.Right.push( RightBorder );
                        }
                        else
                        {
                            var Temp_Next_Cell = Temp_Row.Get_Cell( Temp_CurCell + 1 );
                            var Temp_Next_VMerge = Temp_Next_Cell.GetVMerge();
                            if ( 0 != Temp_CurRow && vmerge_Continue === Temp_Next_VMerge )
                            {
                                Borders_Info.Right.push( Borders_Info.Right[Borders_Info.Right.length - 1] );
                            }
                            else
                            {
                                var Temp_Next_Main_Cell = this.Internal_Get_StartMergedCell( CurRow + Temp_CurRow, CurGridCol + GridSpan, Temp_Next_Cell.Get_GridSpan() );
                                var Temp_Next_Main_Cell_Borders = Temp_Next_Main_Cell.Get_Borders();

                                var RightBorder = this.Internal_CompareBorders( Temp_Next_Main_Cell_Borders.Left, CellBorders.Right, false, false );
                                if ( border_Single === RightBorder.Value && RightBorder.Size > Max_r_w )
                                    Max_r_w = RightBorder.Size;

                                Borders_Info.Right.push( RightBorder );
                            }
                        }
                    }

                    Borders_Info.Right_Max = Max_r_w;
                    Borders_Info.Left_Max  = Max_l_w;

                    if ( Max_l_w / 2 > CellMar.Left.W )
                        X_content_start += Max_l_w / 2;
                    else
                        X_content_start += CellMar.Left.W;

                    if ( Max_r_w / 2 > CellMar.Right.W )
                        X_content_end -= Max_r_w / 2;
                    else
                        X_content_end -= CellMar.Right.W;

                    Cell.Set_BorderInfo_Left ( Borders_Info.Left,  Max_l_w );
                    Cell.Set_BorderInfo_Right( Borders_Info.Right, Max_r_w );
                }
            }

            if ( 0 === CurCell )
            {
                if ( null != CellSpacing )
                {
                    Row_x_min = X_grid_start;
                    if ( border_Single === TableBorders.Left.Value )
                        Row_x_min -= TableBorders.Left.Size / 2;
                }
                else
                {
                    var BorderInfo = Cell.Get_BorderInfo();
                    Row_x_min = X_grid_start - BorderInfo.MaxLeft / 2;
                }
            }

            if ( CellsCount - 1 === CurCell )
            {
                if ( null != CellSpacing )
                {
                    Row_x_max = X_grid_end;
                    if ( border_Single === TableBorders.Right.Value )
                        Row_x_max += TableBorders.Right.Size / 2;
                }
                else
                {
                    var BorderInfo = Cell.Get_BorderInfo();
                    Row_x_max = X_grid_end + BorderInfo.MaxRight / 2;
                }
            }

            Cell.Set_Metrics( CurGridCol, X_grid_start, X_grid_end, X_cell_start, X_cell_end, X_content_start, X_content_end );

            CurGridCol += GridSpan;
        }

        Row.Set_Metrics_X( Row_x_min, Row_x_max );
    }

    this.RecalcInfo.TableBorders = false;
};
CTable.prototype.private_RecalculateHeader = function()
{
    // Если у нас таблица внутри таблицы, тогда в ней заголовочных строк не должно быть,
    // потому что так делает Word.
    if ( true === this.Parent.IsTableCellContent() )
    {
        this.HeaderInfo.Count = 0;
        return;
    }

    // Здесь мы подготавливаем информацию для пересчета заголовка таблицы
    var Header_RowsCount = 0;
    var Rows_Count = this.Content.length;
    for ( var Index = 0; Index < Rows_Count; Index++ )
    {
        var Row = this.Content[Index];
        if ( true != Row.IsHeader() )
            break;

        Header_RowsCount++;
    }

    // Избавимся от строк, в которых есть вертикально объединенные ячейки, которые одновременно есть в заголовке
    // и не в заголовке
    for ( var CurRow = Header_RowsCount - 1; CurRow >= 0; CurRow-- )
    {
        var Row = this.Content[CurRow];
        var Cells_Count = Row.Get_CellsCount();

        var bContinue = false;
        for ( var CurCell = 0; CurCell < Cells_Count; CurCell++ )
        {
            var Cell        = Row.Get_Cell( CurCell );
            var GridSpan    = Cell.Get_GridSpan();
            var CurGridCol  = Cell.Metrics.StartGridCol;
            var VMergeCount = this.Internal_GetVertMergeCount( CurRow, CurGridCol, GridSpan );

            // В данной строке нашли вертикально объединенную ячейку с ячейкой не из заголовка
            // Поэтому выкидываем данную строку и проверяем предыдущую
            if ( VMergeCount > 1 )
            {
                Header_RowsCount--;
                bContinue = true;
                break;
            }
        }

        if ( true != bContinue )
        {
            // Если дошли до этого места, значит данная строка, а, следовательно, и все строки выше
            // нормальные в плане объединенных вертикально ячеек.
            break;
        }
    }

    this.HeaderInfo.Count = Header_RowsCount;
};
CTable.prototype.private_RecalculatePageXY = function(CurPage)
{
    var FirstRow = 0;
    if (0 !== CurPage)
    {
        if (true === this.IsEmptyPage(CurPage - 1))
            FirstRow = this.Pages[CurPage - 1].FirstRow;
        else if (true === this.Pages[CurPage - 1].LastRowSplit)
            FirstRow = this.Pages[CurPage - 1].LastRow;
        else
            FirstRow = Math.min(this.Pages[CurPage - 1].LastRow + 1, this.Content.length - 1);
    }

    var TempMaxTopBorder = this.Get_MaxTopBorder(FirstRow);
    this.Pages.length = Math.max(CurPage, 0);
    if (0 === CurPage)
    {
        this.Pages[CurPage] = new CTablePage(this.X, this.Y, this.XLimit, this.YLimit, FirstRow, TempMaxTopBorder);
    }
    else
    {
        var StartPos = this.Parent.Get_PageContentStartPos2(this.PageNum, this.ColumnNum, CurPage, this.Index);
        this.Pages[CurPage] = new CTablePage(StartPos.X, StartPos.Y, StartPos.XLimit, StartPos.YLimit, FirstRow, TempMaxTopBorder);
    }
};
CTable.prototype.private_RecalculatePositionX = function(CurPage)
{
    var TablePr = this.Get_CompiledPr(false).TablePr;
    var PageLimits = this.Parent.Get_PageLimits(this.PageNum);
    var PageFields = this.Parent.Get_PageFields(this.PageNum);

    var LD_PageLimits = this.LogicDocument.Get_PageLimits( this.Get_StartPage_Absolute() );
    var LD_PageFields = this.LogicDocument.Get_PageFields( this.Get_StartPage_Absolute() );

    if ( true === this.Is_Inline() )
    {
        var Page = this.Pages[CurPage];
        if (0 === CurPage)
        {
            this.AnchorPosition.CalcX = this.X_origin + TablePr.TableInd;
            this.AnchorPosition.Set_X(this.TableSumGrid[this.TableSumGrid.length - 1], this.X_origin, LD_PageFields.X, LD_PageFields.XLimit, LD_PageLimits.XLimit, PageLimits.X, PageLimits.XLimit);
        }

        switch (TablePr.Jc)
        {
            case AscCommon.align_Left :
            {
                Page.X = Page.X_origin + this.GetTableOffsetCorrection() + TablePr.TableInd;
                break;
            }
            case AscCommon.align_Right :
            {
                var TableWidth = this.TableSumGrid[this.TableSumGrid.length - 1];

                if (false === this.Parent.IsTableCellContent())
                    Page.X = Page.XLimit - TableWidth + 1.9; // 1.9мм всегда добавляется справа от таблицы
                else
                    Page.X = Page.XLimit - TableWidth;
                break;
            }
            case AscCommon.align_Center :
            {
                var TableWidth = this.TableSumGrid[this.TableSumGrid.length - 1];
                var RangeWidth = Page.XLimit - Page.X_origin;

                Page.X = Page.X_origin + ( RangeWidth - TableWidth ) / 2;
                break;
            }
        }
    }
    else
    {
        if (0 === CurPage)
        {
            var OffsetCorrection_Left  = 0;
            var OffsetCorrection_Right = 0;

            if (true !== this.bPresentation)
            {
                OffsetCorrection_Left  = this.GetTableOffsetCorrection();
                OffsetCorrection_Right = this.GetRightTableOffsetCorrection();
            }

            this.X = this.X_origin + this.GetTableOffsetCorrection();
            this.AnchorPosition.Set_X(this.TableSumGrid[this.TableSumGrid.length - 1], this.X_origin, PageFields.X + OffsetCorrection_Left, PageFields.XLimit + OffsetCorrection_Right, LD_PageLimits.XLimit, PageLimits.X - OffsetCorrection_Left, PageLimits.XLimit + OffsetCorrection_Right);

            // Непонятно по какой причине, но Word для плавающих таблиц добаляется значение TableInd
			this.AnchorPosition.Calculate_X(this.PositionH.RelativeFrom, this.PositionH.Align, this.PositionH.Value);
			this.AnchorPosition.CalcX += TablePr.TableInd;

            this.X        = this.AnchorPosition.CalcX;
            this.X_origin = this.X - this.GetTableOffsetCorrection();

            if (undefined != this.PositionH_Old)
            {
                // Восстанови старые значения, чтобы в историю изменений все нормально записалось
                this.PositionH.RelativeFrom = this.PositionH_Old.RelativeFrom;
                this.PositionH.Align        = this.PositionH_Old.Align;
                this.PositionH.Value        = this.PositionH_Old.Value;

                // Рассчитаем сдвиг с учетом старой привязки
                var Value = this.AnchorPosition.Calculate_X_Value(this.PositionH_Old.RelativeFrom);
                this.Set_PositionH(this.PositionH_Old.RelativeFrom, false, Value);

                // На всякий случай пересчитаем заново координату
				this.X        = this.AnchorPosition.Calculate_X(this.PositionH.RelativeFrom, this.PositionH.Align, this.PositionH.Value);
                this.X_origin = this.X - this.GetTableOffsetCorrection();

                this.PositionH_Old = undefined;
            }
        }

        this.Pages[CurPage].X        = this.X;
        this.Pages[CurPage].XLimit   = this.XLimit;
        this.Pages[CurPage].X_origin = this.X_origin;
    }
};
CTable.prototype.private_RecalculatePage = function(CurPage)
{
    if ( true === this.TurnOffRecalc )
        return;

	var isInnerTable       = this.Parent.IsTableCellContent();
	var oTopDocument       = this.Parent.Is_TopDocument(true);
	var isTopLogicDocument = (oTopDocument instanceof CDocument ? true : false);
	var oFootnotes         = (isTopLogicDocument && !isInnerTable ? oTopDocument.Footnotes : null);
	var nPageAbs           = this.Get_AbsolutePage(CurPage);
	var nColumnAbs         = this.Get_AbsoluteColumn(CurPage);

    this.TurnOffRecalc = true;

    var FirstRow = 0;
    var LastRow  = 0;

    var ResetStartElement = false;
    if ( 0 === CurPage )
    {
        // Обнуляем таблицу суммарных высот ячеек
        for ( var Index = -1; Index < this.Content.length; Index++ )
        {
            this.TableRowsBottom[Index] = [];
            this.TableRowsBottom[Index][0] = 0;
        }
    }
    else
    {
        if (true === this.IsEmptyPage(CurPage - 1))
        {
            ResetStartElement = false;
            FirstRow = this.Pages[CurPage - 1].FirstRow;
        }
        else if (true === this.Pages[CurPage - 1].LastRowSplit)
        {
            ResetStartElement = false;
            FirstRow = this.Pages[CurPage - 1].LastRow;
        }
        else
        {
            ResetStartElement = true;
            FirstRow = Math.min(this.Pages[CurPage - 1].LastRow + 1, this.Content.length - 1);
        }

        LastRow = FirstRow;
    }

    var MaxTopBorder     = this.MaxTopBorder;
    var MaxBotBorder     = this.MaxBotBorder;
    var MaxBotMargin     = this.MaxBotMargin;

    var StartPos = this.Pages[CurPage];
    if (true === this.Check_EmptyPages(CurPage - 1))
        this.HeaderInfo.PageIndex = -1;

    var Page = this.Pages[CurPage];
    var TempMaxTopBorder = Page.MaxTopBorder;

    var Y = StartPos.Y;
    var TableHeight = 0;

    var TableBorders = this.Get_Borders();

    var X_max = -1;
    var X_min = -1;
    if ( this.HeaderInfo.Count > 0 && this.HeaderInfo.PageIndex != -1 && CurPage > this.HeaderInfo.PageIndex )
    {
    	this.HeaderInfo.HeaderRecalculate = true;
        this.HeaderInfo.Pages[CurPage] = {};
        this.HeaderInfo.Pages[CurPage].RowsInfo = [];
        var HeaderPage = this.HeaderInfo.Pages[CurPage];

        // Рисуем ли заголовок на данной странице
        HeaderPage.Draw = true;

        // Скопируем целиком строки
        HeaderPage.Rows = [];

        // Временно отключаем регистрацию новых классов
        AscCommon.g_oTableId.m_bTurnOff = true;
        AscCommon.History.TurnOff();

        var aContentDrawings = [];
        for ( var Index = 0; Index < this.HeaderInfo.Count; Index++ )
        {
            HeaderPage.Rows[Index] = this.Content[Index].Copy(this);
            HeaderPage.Rows[Index].Index = Index;
            for(var CellIndex = 0; CellIndex < HeaderPage.Rows[Index].Content.length; ++CellIndex)
            {
                HeaderPage.Rows[Index].Content[CellIndex].Content.GetAllDrawingObjects(aContentDrawings);
            }
        }
        for(var DrawingIndex = 0; DrawingIndex < aContentDrawings.length; ++DrawingIndex)
        {
            if(aContentDrawings[DrawingIndex] && aContentDrawings[DrawingIndex].GraphicObj)
            {
                aContentDrawings[DrawingIndex].GraphicObj.recalculate();
                if(aContentDrawings[DrawingIndex].GraphicObj.recalculateText)
                {
                    aContentDrawings[DrawingIndex].GraphicObj.recalculateText();
                }
            }
        }

        AscCommon.g_oTableId.m_bTurnOff = false;
        AscCommon.History.TurnOn();

        var bHeaderNextPage = false;
        for ( var CurRow = 0; CurRow < this.HeaderInfo.Count; CurRow++  )
        {
            HeaderPage.RowsInfo[CurRow] = {};
            HeaderPage.RowsInfo[CurRow].Y               = 0;
            HeaderPage.RowsInfo[CurRow].H               = 0;
            HeaderPage.RowsInfo[CurRow].TopDy           = 0;
            HeaderPage.RowsInfo[CurRow].MaxTopBorder    = 0;
            HeaderPage.RowsInfo[CurRow].TableRowsBottom = 0;

            var Row         = HeaderPage.Rows[CurRow];
            var CellsCount  = Row.Get_CellsCount();
            var CellSpacing = Row.Get_CellSpacing();

            var BeforeInfo  = Row.Get_Before();
            var CurGridCol  = BeforeInfo.GridBefore;

            // Добавляем ширину верхней границы у текущей строки (используем MaxTopBorder самой таблицы)
            Y           += MaxTopBorder[CurRow];
            TableHeight += MaxTopBorder[CurRow];

            // Если таблица с расстоянием между ячейками, тогда добавляем его
            if ( 0 === CurRow )
            {
                if ( null != CellSpacing )
                {
                    var TableBorder_Top = this.Get_Borders().Top;
                    if ( border_Single === TableBorder_Top.Value )
                    {
                        Y           += TableBorder_Top.Size;
                        TableHeight += TableBorder_Top.Size;
                    }

                    Y           += CellSpacing;
                    TableHeight += CellSpacing;
                }
            }
            else
            {
                var PrevCellSpacing = HeaderPage.Rows[CurRow - 1].Get_CellSpacing();

                if ( null != CellSpacing && null != PrevCellSpacing )
                {
                    Y           += (PrevCellSpacing + CellSpacing) / 2;
                    TableHeight += (PrevCellSpacing + CellSpacing) / 2;
                }
                else if ( null != CellSpacing )
                {
                    Y           += CellSpacing / 2;
                    TableHeight += CellSpacing / 2;
                }
                else if ( null != PrevCellSpacing )
                {
                    Y           += PrevCellSpacing / 2;
                    TableHeight += PrevCellSpacing / 2;
                }
            }

            var Row_x_max = Row.Metrics.X_max;
            var Row_x_min = Row.Metrics.X_min;

            if ( -1 === X_min || Row_x_min < X_min )
                X_min = Row_x_min;

            if ( -1 === X_max || Row_x_max > X_max )
                X_max = Row_x_max;

            // Дополнительный параметр для случая, если данная строка начнется с новой страницы.
            // Мы запоминаем максимальное значение нижней границы(первой страницы (текущей)) у ячеек,
            // объединенных вертикально так, чтобы это объединение заканчивалось на данной строке.
            // И если данная строка начнется сразу с новой страницы (Pages > 0, FirstPage = false), тогда
            // мы должны данный параметр сравнить со значением нижней границы предыдущей строки.
            var MaxBotValue_vmerge = -1;

            var RowH = Row.Get_Height();
            var VerticallCells = [];

            for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
            {
                var Cell     = Row.Get_Cell( CurCell );
                var GridSpan = Cell.Get_GridSpan();
                var Vmerge   = Cell.GetVMerge();
                var CellMar  = Cell.GetMargins();

                Row.Update_CellInfo(CurCell);

                var CellMetrics = Row.Get_CellInfo( CurCell );

                var X_content_start = Page.X + CellMetrics.X_content_start;
                var X_content_end   = Page.X + CellMetrics.X_content_end;

                var Y_content_start = Y + CellMar.Top.W;
                var Y_content_end   = this.Pages[CurPage].YLimit;

                // TODO: При расчете YLimit для ячейки сделать учет толщины нижних
                //       границ ячейки и таблицы
                if ( null != CellSpacing )
                {
                    if ( this.Content.length - 1 === CurRow )
                        Y_content_end -= CellSpacing;
                    else
                        Y_content_end -= CellSpacing / 2;
                }

                var VMergeCount = this.Internal_GetVertMergeCount( CurRow, CurGridCol, GridSpan );
                var BottomMargin = this.MaxBotMargin[CurRow + VMergeCount - 1];
                Y_content_end -= BottomMargin;

                // Такие ячейки мы обсчитываем, если либо сейчас происходит переход на новую страницу, либо
                // это последняя ячейка в объединении.
                // Обсчет такик ячеек произошел ранее

                Cell.Temp.Y = Y_content_start;

                if ( VMergeCount > 1 )
                {
                    CurGridCol += GridSpan;
                    continue;
                }
                else
                {
                    // Возьмем верхнюю ячейку теккущего объединения
                    if ( vmerge_Restart != Vmerge )
                    {
                        // Найдем ячейку в самой таблице, а дальше по индексам ячейки и строки получим ее в скопированном заголовке
                        Cell    = this.Internal_Get_StartMergedCell( CurRow, CurGridCol, GridSpan );
                        var cIndex = Cell.Index;
                        var rIndex = Cell.Row.Index;

                        Cell = HeaderPage.Rows[rIndex].Get_Cell( cIndex );

                        CellMar = Cell.GetMargins();

                        Y_content_start = Cell.Temp.Y + CellMar.Top.W;
                    }
                }

                if (true === Cell.Is_VerticalText())
                {
                    VerticallCells.push(Cell);
                    CurGridCol += GridSpan;
                    continue;
                }

                Cell.Content.Set_StartPage( CurPage );
                Cell.Content.Reset( X_content_start, Y_content_start, X_content_end, Y_content_end );
                Cell.Content.Set_ClipInfo(0, Page.X + CellMetrics.X_cell_start, Page.X + CellMetrics.X_cell_end);

                if ( recalcresult2_NextPage === Cell.Content.Recalculate_Page( 0, true ) )
                {
                    bHeaderNextPage = true;
                    break;
                }

                var CellContentBounds = Cell.Content.Get_PageBounds( 0, undefined, true );
                var CellContentBounds_Bottom = CellContentBounds.Bottom + BottomMargin;

                if ( undefined === HeaderPage.RowsInfo[CurRow].TableRowsBottom || HeaderPage.RowsInfo[CurRow].TableRowsBottom < CellContentBounds_Bottom )
                    HeaderPage.RowsInfo[CurRow].TableRowsBottom = CellContentBounds_Bottom;

                if ( vmerge_Continue === Vmerge )
                {
                    if ( -1 === MaxBotValue_vmerge || MaxBotValue_vmerge < CellContentBounds_Bottom )
                        MaxBotValue_vmerge = CellContentBounds_Bottom;
                }

                CurGridCol += GridSpan;
            }

            // Если заголовок целиком на странице не убирается, тогда мы его попросту не рисуем на данной странице
            if ( true === bHeaderNextPage )
            {
                Y = StartPos.Y;
                TableHeight = 0;
                HeaderPage.Draw = false;
                break;
            }


            // Здесь мы выставляем только начальную координату строки (для каждой страницы)
            // высоту строки(для каждой страницы) мы должны обсчитать после общего цикла, т.к.
            // в одной из следйющих строк может оказаться ячейка с вертикальным объединением,
            // захватывающим данную строку. Значит, ее содержимое может изменить высоту нашей строки.
            var TempY            = Y;
            var TempMaxTopBorder = MaxTopBorder[CurRow];

            if ( null != CellSpacing )
            {
                HeaderPage.RowsInfo[CurRow].Y            = TempY;
                HeaderPage.RowsInfo[CurRow].TopDy        = 0;
                HeaderPage.RowsInfo[CurRow].X0           = Row_x_min;
                HeaderPage.RowsInfo[CurRow].X1           = Row_x_max;
                HeaderPage.RowsInfo[CurRow].MaxTopBorder = TempMaxTopBorder;
                HeaderPage.RowsInfo[CurRow].MaxBotBorder = MaxBotBorder[CurRow];
            }
            else
            {
                HeaderPage.RowsInfo[CurRow].Y            = TempY - TempMaxTopBorder;
                HeaderPage.RowsInfo[CurRow].TopDy        = TempMaxTopBorder;
                HeaderPage.RowsInfo[CurRow].X0           = Row_x_min;
                HeaderPage.RowsInfo[CurRow].X1           = Row_x_max;
                HeaderPage.RowsInfo[CurRow].MaxTopBorder = TempMaxTopBorder;
                HeaderPage.RowsInfo[CurRow].MaxBotBorder = MaxBotBorder[CurRow];
            }

            var CellHeight = HeaderPage.RowsInfo[CurRow].TableRowsBottom - Y;

            // TODO: улучшить проверку на высоту строки (для строк разбитых на страницы)
            if (false === bHeaderNextPage && (Asc.linerule_AtLeast === RowH.HRule || Asc.linerule_Exact === RowH.HRule) && CellHeight < RowH.Value - MaxTopBorder[CurRow])
            {
                CellHeight = RowH.Value - MaxTopBorder[CurRow];
                HeaderPage.RowsInfo[CurRow].TableRowsBottom = Y + CellHeight;
            }

            // Рассчитываем ячейки с вертикальным текстом
            var CellsCount2 = VerticallCells.length;
            for (var TempCellIndex = 0; TempCellIndex < CellsCount2; TempCellIndex++)
            {
                var Cell       = VerticallCells[TempCellIndex];
                var CurCell    = Cell.Index;
                var GridSpan   = Cell.Get_GridSpan();
                var CurGridCol = Cell.Metrics.StartGridCol;

                // Возьмем верхнюю ячейку текущего объединения
                Cell = this.Internal_Get_StartMergedCell(CurRow, CurGridCol, GridSpan);
                var cIndex = Cell.Index;
                var rIndex = Cell.Row.Index;
                Cell = HeaderPage.Rows[rIndex].Get_Cell( cIndex );

                var CellMar     = Cell.GetMargins();
                var CellMetrics = Cell.Row.Get_CellInfo(CurCell);

                var X_content_start = Page.X + CellMetrics.X_content_start;
                var X_content_end   = Page.X + CellMetrics.X_content_end;
                var Y_content_start = Cell.Temp.Y;
                var Y_content_end   = HeaderPage.RowsInfo[CurRow].TableRowsBottom;

                // TODO: При расчете YLimit для ячейки сделать учет толщины нижних
                //       границ ячейки и таблицы
                if (null != CellSpacing)
                {
                    if (this.Content.length - 1 === CurRow)
                        Y_content_end -= CellSpacing;
                    else
                        Y_content_end -= CellSpacing / 2;
                }

                var VMergeCount = this.Internal_GetVertMergeCount(CurRow, CurGridCol, GridSpan);
                var BottomMargin = this.MaxBotMargin[CurRow + VMergeCount - 1];
                Y_content_end -= BottomMargin;

                Cell.PagesCount = 1;
                Cell.Content.Set_StartPage(CurPage);
                Cell.Content.Reset(0, 0, Y_content_end - Y_content_start, 10000);
                Cell.Temp.X_start = X_content_start;
                Cell.Temp.Y_start = Y_content_start;
                Cell.Temp.X_end   = X_content_end;
                Cell.Temp.Y_end   = Y_content_end;

                Cell.Temp.X_cell_start = Page.X + CellMetrics.X_cell_start;
                Cell.Temp.X_cell_end   = Page.X + CellMetrics.X_cell_end;
                Cell.Temp.Y_cell_start = Y_content_start - CellMar.Top.W;
                Cell.Temp.Y_cell_end   = Y_content_end + BottomMargin;


                // Какие-то ячейки в строке могут быть не разбиты на строки, а какие то разбиты.
                // Здесь контролируем этот момент, чтобы у тех, которые не разбиты не вызывать
                // Recalculate_Page от несуществующих страниц.
                var CellPageIndex = CurPage - Cell.Content.Get_StartPage_Relative();
                if (0 === CellPageIndex)
                {
                    Cell.Content.Recalculate_Page(CellPageIndex, true);
                }
            }

            if ( null != CellSpacing )
                HeaderPage.RowsInfo[CurRow].H = CellHeight;
            else
                HeaderPage.RowsInfo[CurRow].H = CellHeight + TempMaxTopBorder;

            Y           += CellHeight;
            TableHeight += CellHeight;

            Row.Height   = CellHeight;

            Y           += MaxBotBorder[CurRow];
            TableHeight += MaxBotBorder[CurRow];

            // Сделаем вертикальное выравнивание ячеек в таблице. Делаем как Word, если ячейка разбилась на несколько
            // страниц, тогда вертикальное выравнивание применяем только к первой странице.
        }

        if ( false === bHeaderNextPage )
        {
            // Сделаем вертикальное выравнивание ячеек в таблице. Делаем как Word, если ячейка разбилась на несколько
            // страниц, тогда вертикальное выравнивание применяем только к первой странице.
            // Делаем это не в общем цикле, потому что объединенные вертикально ячейки могут вносить поправки в значения
            // this.TableRowsBottom, в последней строке.
            for ( var CurRow = 0; CurRow < this.HeaderInfo.Count; CurRow++ )
            {
                var Row = HeaderPage.Rows[CurRow];
                var CellsCount = Row.Get_CellsCount();
                for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
                {
                    var Cell = Row.Get_Cell( CurCell );
                    var VMergeCount = this.Internal_GetVertMergeCount( CurRow, Cell.Metrics.StartGridCol, Cell.Get_GridSpan() );

                    if ( VMergeCount > 1 )
                        continue;
                    else
                    {
                        var Vmerge = Cell.GetVMerge();
                        // Возьмем верхнюю ячейку теккущего объединения
                        if ( vmerge_Restart != Vmerge )
                        {
                            Cell = this.Internal_Get_StartMergedCell( CurRow, Cell.Metrics.StartGridCol, Cell.Get_GridSpan() );
                            var cIndex = Cell.Index;
                            var rIndex = Cell.Row.Index;

                            Cell = HeaderPage.Rows[rIndex].Get_Cell( cIndex );
                        }
                    }

                    var CellMar       = Cell.GetMargins();
                    var VAlign        = Cell.Get_VAlign();
                    var CellPageIndex = CurPage - Cell.Content.Get_StartPage_Relative();

                    if ( CellPageIndex >= Cell.PagesCount )
                        continue;

                    // Для прилегания к верху или для второй страницы ничего не делаем (так изначально рассчитывалось)
                    if ( vertalignjc_Top === VAlign || CellPageIndex > 1 )
                    {
                        Cell.Temp.Y_VAlign_offset[CellPageIndex] = 0;
                        continue;
                    }

                    // Рассчитаем имеющуюся в распоряжении высоту ячейки
                    var TempCurRow = Cell.Row.Index;
                    var TempCellSpacing = HeaderPage.Rows[TempCurRow].Get_CellSpacing();
                    var Y_0 = HeaderPage.RowsInfo[TempCurRow].Y;

                    if ( null === TempCellSpacing )
                        Y_0 += MaxTopBorder[TempCurRow];

                    Y_0 += CellMar.Top.W;

                    var Y_1 = HeaderPage.RowsInfo[CurRow].TableRowsBottom - CellMar.Bottom.W;
                    var CellHeight = Y_1 - Y_0;

                    var CellContentBounds = Cell.Content.Get_PageBounds( CellPageIndex, CellHeight, true );
                    var ContentHeight = CellContentBounds.Bottom - CellContentBounds.Top;

                    var Dy = 0;

                    if (true === Cell.Is_VerticalText())
                    {
                        var CellMetrics = Cell.Row.Get_CellInfo(Cell.Index);
                        CellHeight = CellMetrics.X_cell_end - CellMetrics.X_cell_start - CellMar.Left.W - CellMar.Right.W;
                    }

                    if ( CellHeight - ContentHeight > 0.001 )
                    {
                        if ( vertalignjc_Bottom === VAlign )
                            Dy = CellHeight - ContentHeight;
                        else if ( vertalignjc_Center === VAlign )
                            Dy = (CellHeight - ContentHeight) / 2;

                        Cell.Content.Shift( CellPageIndex, 0, Dy );
                    }

                    Cell.Temp.Y_VAlign_offset[CellPageIndex] = Dy;
                }
            }
        }
    }
    else
    {
        this.HeaderInfo.Pages[CurPage] = {};
        this.HeaderInfo.Pages[CurPage].Draw = false;
    }
    this.HeaderInfo.HeaderRecalculate = false;

    var bNextPage = false;

    // Блок переменных для учета сносок
	var nFootnotesHeight     = 0;
	var arrSavedY            = [];
	var arrSavedTableHeight  = [];
	var arrFootnotesObject   = [];
	var nResetFootnotesIndex = -1;

    for (var CurRow = FirstRow; CurRow < this.Content.length; ++CurRow)
    {
		if (oFootnotes && (-1 === nResetFootnotesIndex || CurRow > nResetFootnotesIndex))
		{
			nFootnotesHeight            = oFootnotes.GetHeight(nPageAbs, nColumnAbs);
			arrFootnotesObject[CurRow]  = oFootnotes.SaveRecalculateObject(nPageAbs, nColumnAbs);
			arrSavedY[CurRow]           = Y;
			arrSavedTableHeight[CurRow] = TableHeight;

			this.Pages[CurPage].FootnotesH = nFootnotesHeight;
		}

		if ((0 === CurRow && true === this.Check_EmptyPages(CurPage - 1)) || CurRow != FirstRow || (CurRow === FirstRow && true === ResetStartElement))
        {
            this.RowsInfo[CurRow] = new CTableRowsInfo();
            this.RowsInfo[CurRow].StartPage = CurPage;
            this.TableRowsBottom[CurRow]    = [];
        }
        else
        {
            this.RowsInfo[CurRow].Pages = CurPage - this.RowsInfo[CurRow].StartPage + 1;
        }

        this.TableRowsBottom[CurRow][CurPage] = Y;

        var Row         = this.Content[CurRow];
        var CellsCount  = Row.Get_CellsCount();
        var CellSpacing = Row.Get_CellSpacing();

        var BeforeInfo  = Row.Get_Before();
        var AfterInfo   = Row.Get_After();
        var CurGridCol  = BeforeInfo.GridBefore;

        // Добавляем ширину верхней границы у текущей строки
        Y           += MaxTopBorder[CurRow];
        TableHeight += MaxTopBorder[CurRow];

        // Если таблица с расстоянием между ячейками, тогда добавляем его
        if (FirstRow === CurRow)
        {
            if (null != CellSpacing)
            {
                var TableBorder_Top = this.Get_Borders().Top;
                if (border_Single === TableBorder_Top.Value)
                {
                    Y           += TableBorder_Top.Size;
                    TableHeight += TableBorder_Top.Size;
                }

                if (true === this.HeaderInfo.Pages[CurPage].Draw || (0 === CurRow && (0 === CurPage || (1 === CurPage && false === this.RowsInfo[0].FirstPage))))
                {
                    Y           += CellSpacing;
                    TableHeight += CellSpacing;
                }
                else
                {
                    Y           += CellSpacing / 2;
                    TableHeight += CellSpacing / 2;
                }
            }
        }
        else
        {
            var PrevCellSpacing = this.Content[CurRow - 1].Get_CellSpacing();

            if (null != CellSpacing && null != PrevCellSpacing)
            {
                Y           += (PrevCellSpacing + CellSpacing) / 2;
                TableHeight += (PrevCellSpacing + CellSpacing) / 2;
            }
            else if (null != CellSpacing)
            {
                Y           += CellSpacing / 2;
                TableHeight += CellSpacing / 2;
            }
            else if (null != PrevCellSpacing)
            {
                Y           += PrevCellSpacing / 2;
                TableHeight += PrevCellSpacing / 2;
            }
        }

        var Row_x_max = Row.Metrics.X_max;
        var Row_x_min = Row.Metrics.X_min;

        if (-1 === X_min || Row_x_min < X_min)
            X_min = Row_x_min;

        if (-1 === X_max || Row_x_max > X_max)
            X_max = Row_x_max;

		var MaxTopMargin = 0;

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell    = Row.Get_Cell(CurCell);
			var Vmerge  = Cell.GetVMerge();
			var CellMar = Cell.GetMargins();
			if (vmerge_Restart === Vmerge && CellMar.Top.W > MaxTopMargin)
				MaxTopMargin = CellMar.Top.W;
		}

		var RowH = Row.Get_Height();
		var RowHValue = RowH.Value;
		// В данном значении не учитываются маргины
		RowHValue = RowH.Value + this.MaxBotMargin[CurRow] + MaxTopMargin;

		// В таблице с отступами размер отступа входит в значение высоты строки
		if (null !== CellSpacing)
			RowHValue -= CellSpacing;

		if (oFootnotes && (Asc.linerule_AtLeast === RowH.HRule || Asc.linerule_Exact == RowH.HRule))
		{
			oFootnotes.PushCellLimit(Y + RowHValue);
		}

        // Дополнительный параметр для случая, если данная строка начнется с новой страницы.
        // Мы запоминаем максимальное значение нижней границы(первой страницы (текущей)) у ячеек,
        // объединенных вертикально так, чтобы это объединение заканчивалось на данной строке.
        // И если данная строка начнется сразу с новой страницы (Pages > 0, FirstPage = false), тогда
        // мы должны данный параметр сравнить со значением нижней границы предыдущей строки.
        var MaxBotValue_vmerge = -1;

        var Merged_Cell  = [];
        var VerticallCells = [];
        var bAllCellsVertical = true;
        var bFootnoteBreak = false;
        for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
        {
            var Cell     = Row.Get_Cell( CurCell );
            var GridSpan = Cell.Get_GridSpan();
            var Vmerge   = Cell.GetVMerge();
            var CellMar  = Cell.GetMargins();

            Row.Update_CellInfo(CurCell);

            var CellMetrics   = Row.Get_CellInfo( CurCell );

            var X_content_start = Page.X + CellMetrics.X_content_start;
            var X_content_end   = Page.X + CellMetrics.X_content_end;

            var Y_content_start = Y + CellMar.Top.W;
            var Y_content_end   = this.Pages[CurPage].YLimit - nFootnotesHeight;

            // TODO: При расчете YLimit для ячейки сделать учет толщины нижних
            //       границ ячейки и таблицы
            if ( null != CellSpacing )
            {
                if ( this.Content.length - 1 === CurRow )
                    Y_content_end -= CellSpacing;
                else
                    Y_content_end -= CellSpacing / 2;
            }

            var VMergeCount = this.Internal_GetVertMergeCount( CurRow, CurGridCol, GridSpan );
            var BottomMargin = this.MaxBotMargin[CurRow + VMergeCount - 1];
            Y_content_end -= BottomMargin;

            // Такие ячейки мы обсчитываем, если либо сейчас происходит переход на новую страницу, либо
            // это последняя ячейка в объединении.
            // Обсчет такик ячеек произошел ранее

            Cell.Temp.Y = Y_content_start;

            if ( VMergeCount > 1 )
            {
                CurGridCol += GridSpan;
                Merged_Cell.push( Cell );
                continue;
            }
            else
            {
                // Возьмем верхнюю ячейку теккущего объединения
                if ( vmerge_Restart != Vmerge )
                {
                    Cell = this.Internal_Get_StartMergedCell( CurRow, CurGridCol, GridSpan );
                    CellMar = Cell.GetMargins();

                    Y_content_start = Cell.Temp.Y + CellMar.Top.W;
                }
            }

            if (true === Cell.Is_VerticalText())
            {
                VerticallCells.push(Cell);
                CurGridCol += GridSpan;
                continue;
            }

            bAllCellsVertical = false;

            var bCanShift = false;
            var ShiftDy   = 0;
            var ShiftDx   = 0;

            if ((0 === Cell.Row.Index && true === this.Check_EmptyPages(CurPage - 1)) || Cell.Row.Index > FirstRow || (Cell.Row.Index === FirstRow && true === ResetStartElement))
            {
                Cell.Content.Set_StartPage( CurPage );

                if (  true === this.Is_Inline() && 1 === Cell.PagesCount && 1 === Cell.Content.Pages.length && true != this.RecalcInfo.Check_Cell( Cell ) )
                {
                    var X_content_start_old  = Cell.Content.Pages[0].X;
                    var X_content_end_old    = Cell.Content.Pages[0].XLimit;
                    var Y_content_height_old = Cell.Content.Pages[0].Bounds.Bottom - Cell.Content.Pages[0].Bounds.Top;

					// Проверим по X, Y
                    if ( Math.abs( X_content_start - X_content_start_old ) < 0.001 && Math.abs( X_content_end_old - X_content_end ) < 0.001 && Y_content_start + Y_content_height_old < Y_content_end )
                    {
                        bCanShift = true;
                        ShiftDy   = -Cell.Content.Pages[0].Y + Y_content_start;

						// Если в ячейке есть ссылки на сноски, тогда такую ячейку нужно пересчитывать
						var arrFootnotes = Cell.Content.Get_FootnotesList(null, null);
						if (arrFootnotes && arrFootnotes.length > 0)
							bCanShift = false;
                    }
                }

                Cell.PagesCount = 1;
                Cell.Content.Reset(X_content_start, Y_content_start, X_content_end, Y_content_end);
            }

            // Какие-то ячейки в строке могут быть не разбиты на строки, а какие то разбиты.
            // Здесь контролируем этот момент, чтобы у тех, которые не разбиты не вызывать
            // Recalculate_Page от несуществующих страниц.
            var CellPageIndex = CurPage - Cell.Content.Get_StartPage_Relative();
            Cell.Content.Set_ClipInfo(CellPageIndex, Page.X + CellMetrics.X_cell_start, Page.X + CellMetrics.X_cell_end);
            if ( CellPageIndex < Cell.PagesCount )
            {
                if ( true === bCanShift )
                {
                    Cell.Content.Shift( 0, ShiftDx, ShiftDy );
                    Cell.Content.UpdateEndInfo();
                }
                else
                {
					var RecalcResult = Cell.Content.Recalculate_Page(CellPageIndex, true);
					if (recalcresult2_CurPage & RecalcResult)
					{
						var _RecalcResult = recalcresult_CurPage;

						if (RecalcResult & recalcresultflags_Column)
							_RecalcResult |= recalcresultflags_Column;

						if (RecalcResult & recalcresultflags_Footnotes)
							_RecalcResult |= recalcresultflags_Footnotes;

						this.TurnOffRecalc = false;
						return _RecalcResult;
					}
					else if (recalcresult2_NextPage & RecalcResult)
					{
						Cell.PagesCount = Cell.Content.Pages.length + 1;
						bNextPage       = true;
					}
					else if (recalcresult2_End & RecalcResult)
					{
						// Ничего не делаем
					}
                }

                var CellContentBounds = Cell.Content.Get_PageBounds( CellPageIndex, undefined, true );
                var CellContentBounds_Bottom = CellContentBounds.Bottom + BottomMargin;

                if ( undefined === this.TableRowsBottom[CurRow][CurPage] || this.TableRowsBottom[CurRow][CurPage] < CellContentBounds_Bottom )
                    this.TableRowsBottom[CurRow][CurPage] = CellContentBounds_Bottom;

                if ( vmerge_Continue === Vmerge )
                {
                    if ( -1 === MaxBotValue_vmerge || MaxBotValue_vmerge < CellContentBounds_Bottom )
                        MaxBotValue_vmerge = CellContentBounds_Bottom;
                }
            }

			var nCurFootnotesHeight = oFootnotes ? oFootnotes.GetHeight(nPageAbs, nColumnAbs) : 0;
			if (oFootnotes && nCurFootnotesHeight > nFootnotesHeight + 0.001)
			{
				this.Pages[CurPage].FootnotesH = nCurFootnotesHeight;

				nFootnotesHeight     = nCurFootnotesHeight;
				nResetFootnotesIndex = CurRow;
				Y                    = arrSavedY[Cell.Row.Index];
				TableHeight          = arrSavedTableHeight[Cell.Row.Index];
				oFootnotes.LoadRecalculateObject(nPageAbs, nColumnAbs, arrFootnotesObject[Cell.Row.Index]);

				CurRow = Cell.Row.Index - 1;

				bFootnoteBreak = true;
				break;
			}

            CurGridCol += GridSpan;
        }

		if (oFootnotes && (Asc.linerule_AtLeast === RowH.HRule || Asc.linerule_Exact == RowH.HRule))
		{
			oFootnotes.PopCellLimit();
		}

		if (bFootnoteBreak)
			continue;

        if (undefined === this.TableRowsBottom[CurRow][CurPage])
            this.TableRowsBottom[CurRow][CurPage] = Y;

        // Если в строке все ячейки с вертикальным выравниванием
        if (true === bAllCellsVertical && Asc.linerule_Auto === RowH.HRule)
            this.TableRowsBottom[CurRow][CurPage] = Y + 4.5 + this.MaxBotMargin[CurRow] + MaxTopMargin;

        if ((Asc.linerule_AtLeast === RowH.HRule || Asc.linerule_Exact == RowH.HRule) && Y + RowHValue > Y_content_end && ((0 === CurRow && 0 === CurPage && (null !== this.Get_DocumentPrev() || true === this.Parent.IsTableCellContent())) || CurRow != FirstRow))
        {
            bNextPage = true;

            for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
            {
                var Cell   = Row.Get_Cell( CurCell );
                var Vmerge = Cell.GetVMerge();

                var VMergeCount = this.Internal_GetVertMergeCount( CurRow, Cell.Metrics.StartGridCol, Cell.Get_GridSpan() );

                // Проверяем только начальные ячейки вертикального объединения..
                if ( vmerge_Continue === Vmerge || VMergeCount > 1 )
                    continue;

                Cell.Content.StartFromNewPage();
                Cell.PagesCount = 2;
            }
        }

        // Данная строка разбилась на несколько страниц. Нам нужно сделать несколько дополнительных действий:
        // 1. Проверяем есть ли хоть какой-либо контент данной строки на первой странице, т.е. реально данная
        //    строка начинается со 2-ой страницы.
        // 2. Пересчитать все смерженные вертикально ячейки, которые также разбиваются на несколько страниц,
        //    но у которых вертикальное объединение не заканчивается на данной странице.
        if ( true === bNextPage )
        {
            var bContentOnFirstPage   = false;
            var bNoContentOnFirstPage = false;
            for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
            {
                var Cell   = Row.Get_Cell( CurCell );
                var Vmerge = Cell.GetVMerge();

                var VMergeCount = this.Internal_GetVertMergeCount( CurRow, Cell.Metrics.StartGridCol, Cell.Get_GridSpan() );

                // Проверяем только начальные ячейки вертикального объединения..
                if ( vmerge_Continue === Vmerge || VMergeCount > 1 )
                    continue;

                if (true === Cell.Is_VerticalText() || true === Cell.Content_Is_ContentOnFirstPage())
                {
                    bContentOnFirstPage = true;
                }
                else
                {
                    bNoContentOnFirstPage = true;
                }
            }

            if ( true === bContentOnFirstPage && true === bNoContentOnFirstPage )
            {
                for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
                {
                    var Cell   = Row.Get_Cell( CurCell );
                    var Vmerge = Cell.GetVMerge();

                    var VMergeCount = this.Internal_GetVertMergeCount( CurRow, Cell.Metrics.StartGridCol, Cell.Get_GridSpan() );

                    // Проверяем только начальные ячейки вертикального объединения..
                    if ( vmerge_Continue === Vmerge || VMergeCount > 1 )
                        continue;

                    Cell.Content.StartFromNewPage();
                    Cell.PagesCount = 2;
                }

                bContentOnFirstPage = false;
            }

            this.RowsInfo[CurRow].FirstPage = bContentOnFirstPage;

            // Не сраниваем MaxBotValue_vmerge с -1, т.к. значения в this.TableRowsBottom в любом случае неотрицательные
            if ( 0 != CurRow && false === this.RowsInfo[CurRow].FirstPage )
            {
                if ( this.TableRowsBottom[CurRow - 1][CurPage] < MaxBotValue_vmerge )
                {
                    // Поскольку мы правим настройку не текущей строки, надо подправить и
                    // запись о рассчитанной высоте строки
                    var Diff = MaxBotValue_vmerge - this.TableRowsBottom[CurRow - 1][CurPage];
                    this.TableRowsBottom[CurRow - 1][CurPage] = MaxBotValue_vmerge;
                    this.RowsInfo[CurRow - 1].H[CurPage] += Diff;
                }
            }

            // Здесь мы должны рассчитать ячейки, которые попали в вертикальное объединение и из-за этого не были рассчитаны
            var CellsCount2 = Merged_Cell.length;
            var bFootnoteBreak = false;
            for (var TempCellIndex = 0; TempCellIndex < CellsCount2; TempCellIndex++)
            {
                var Cell = Merged_Cell[TempCellIndex];
                var CurCell = Cell.Index;
                var GridSpan = Cell.Get_GridSpan();
                var CurGridCol = Cell.Metrics.StartGridCol;

                // Возьмем верхнюю ячейку теккущего объединения
                Cell = this.Internal_Get_StartMergedCell(CurRow, CurGridCol, GridSpan);

                if (true === Cell.Is_VerticalText())
                {
                    VerticallCells.push(Cell);
                    CurGridCol += GridSpan;
                    continue;
                }

                var CellMar = Cell.GetMargins();
                var CellMetrics = Row.Get_CellInfo(CurCell);

                var X_content_start = Page.X + CellMetrics.X_content_start;
                var X_content_end   = Page.X + CellMetrics.X_content_end;

                // Если в текущей строке на данной странице не убралось ничего из других ячеек, тогда
                // рассчитываем вертикально объединенные ячейки до начала данной строки.
                var Y_content_start = Cell.Temp.Y;
                var Y_content_end   = false === bContentOnFirstPage ? Y : this.Pages[CurPage].YLimit - nFootnotesHeight;

                // TODO: При расчете YLimit для ячейки сделать учет толщины нижних
                //       границ ячейки и таблицы
                if (null != CellSpacing)
                {
                    if (this.Content.length - 1 === CurRow)
                        Y_content_end -= CellSpacing;
                    else
                        Y_content_end -= CellSpacing / 2;
                }

                var VMergeCount = this.Internal_GetVertMergeCount(CurRow, CurGridCol, GridSpan);
                var BottomMargin = this.MaxBotMargin[CurRow + VMergeCount - 1];
                Y_content_end -= BottomMargin;

                if ((0 === Cell.Row.Index && 0 === CurPage) || Cell.Row.Index > FirstRow)
                {
                    Cell.PagesCount = 1;
                    Cell.Content.Set_StartPage(CurPage);
                    Cell.Content.Reset(X_content_start, Y_content_start, X_content_end, Y_content_end);
                }

                // Какие-то ячейки в строке могут быть не разбиты на строки, а какие то разбиты.
                // Здесь контролируем этот момент, чтобы у тех, которые не разбиты не вызывать
                // Recalculate_Page от несуществующих страниц.
                var CellPageIndex = CurPage - Cell.Content.Get_StartPage_Relative();
                if (CellPageIndex < Cell.PagesCount)
                {
                    if (recalcresult2_NextPage === Cell.Content.Recalculate_Page(CellPageIndex, true))
                    {
                        Cell.PagesCount = Cell.Content.Pages.length + 1;
                        bNextPage = true;
                    }

                    var CellContentBounds = Cell.Content.Get_PageBounds(CellPageIndex, undefined, true);
                    var CellContentBounds_Bottom = CellContentBounds.Bottom + BottomMargin;

                    if (0 != CurRow && false === this.RowsInfo[CurRow].FirstPage)
                    {
                        if (this.TableRowsBottom[CurRow - 1][CurPage] < CellContentBounds_Bottom)
                        {
                            // Поскольку мы правим настройку не текущей строки, надо подправить и
                            // запись о рассчитанной высоте строки
                            var Diff = CellContentBounds_Bottom - this.TableRowsBottom[CurRow - 1][CurPage];
                            this.TableRowsBottom[CurRow - 1][CurPage] = CellContentBounds_Bottom;
                            this.RowsInfo[CurRow - 1].H[CurPage] += Diff;
                        }
                    }
                    else
                    {
                        if (undefined === this.TableRowsBottom[CurRow][CurPage] || this.TableRowsBottom[CurRow][CurPage] < CellContentBounds_Bottom)
                            this.TableRowsBottom[CurRow][CurPage] = CellContentBounds_Bottom;
                    }
                }

				// Проверяем наличие сносок, т.к. они могли появится в смерженных ячейках
				var nCurFootnotesHeight = oFootnotes ? oFootnotes.GetHeight(nPageAbs, nColumnAbs) : 0;
				if (oFootnotes && nCurFootnotesHeight > nFootnotesHeight + 0.001 && Cell.Row.Index >= FirstRow)
				{
					this.Pages[CurPage].FootnotesH = nCurFootnotesHeight;

					nFootnotesHeight     = nCurFootnotesHeight;
					nResetFootnotesIndex = CurRow;
					Y                    = arrSavedY[Cell.Row.Index];
					TableHeight          = arrSavedTableHeight[Cell.Row.Index];
					oFootnotes.LoadRecalculateObject(nPageAbs, nColumnAbs, arrFootnotesObject[Cell.Row.Index]);

					CurRow = Cell.Row.Index - 1;

					bFootnoteBreak = true;
					break;
				}

                CurGridCol += GridSpan;
            }

            if (bFootnoteBreak)
				continue;


            // Еще раз обновляем параметр, есть ли текст на первой странице
            bContentOnFirstPage = false;
            for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
            {
                var Cell   = Row.Get_Cell( CurCell );
                var Vmerge = Cell.GetVMerge();

                // Проверяем только начальные ячейки вертикального объединения..
                if ( vmerge_Continue === Vmerge )
                    continue;

                if (true === Cell.Is_VerticalText())
                    continue;

                if ( true === Cell.Content_Is_ContentOnFirstPage() )
                {
                    bContentOnFirstPage = true;
                    break;
                }
            }

            this.RowsInfo[CurRow].FirstPage = bContentOnFirstPage;
        }

        // Выставляем так, чтобы высота была равна 0
        if (true !== this.RowsInfo[CurRow].FirstPage && CurPage === this.RowsInfo[CurRow].StartPage)
            this.TableRowsBottom[CurRow][CurPage] = Y;

        // Здесь мы выставляем только начальную координату строки (для каждой страницы)
        // высоту строки(для каждой страницы) мы должны обсчитать после общего цикла, т.к.
        // в одной из следйющих строк может оказаться ячейка с вертикальным объединением,
        // захватывающим данную строку. Значит, ее содержимое может изменить высоту нашей строки.
        var TempY            = Y;
        var TempMaxTopBorder = MaxTopBorder[CurRow];

        if ( null != CellSpacing )
        {
            this.RowsInfo[CurRow].Y[CurPage]            = TempY;
            this.RowsInfo[CurRow].TopDy[CurPage]        = 0;
            this.RowsInfo[CurRow].X0                    = Row_x_min;
            this.RowsInfo[CurRow].X1                    = Row_x_max;
            this.RowsInfo[CurRow].MaxTopBorder[CurPage] = TempMaxTopBorder;
            this.RowsInfo[CurRow].MaxBotBorder          = MaxBotBorder[CurRow];
        }
        else
        {
            this.RowsInfo[CurRow].Y[CurPage]            = TempY - TempMaxTopBorder;
            this.RowsInfo[CurRow].TopDy[CurPage]        = TempMaxTopBorder;
            this.RowsInfo[CurRow].X0                    = Row_x_min;
            this.RowsInfo[CurRow].X1                    = Row_x_max;
            this.RowsInfo[CurRow].MaxTopBorder[CurPage] = TempMaxTopBorder;
            this.RowsInfo[CurRow].MaxBotBorder          = MaxBotBorder[CurRow];
        }

        var CellHeight = this.TableRowsBottom[CurRow][CurPage] - Y;

		// TODO: улучшить проверку на высоту строки (для строк разбитых на страницы)
		// Условие Y + RowHValue < Y_content_end добавлено из-за сносок.
		if (false === bNextPage && (Asc.linerule_AtLeast === RowH.HRule || Asc.linerule_Exact === RowH.HRule) && CellHeight < RowHValue && (nFootnotesHeight < 0.001 || Y + RowHValue < Y_content_end))
		{
			CellHeight                            = RowHValue;
			this.TableRowsBottom[CurRow][CurPage] = Y + CellHeight;
		}

        // Рассчитываем ячейки с вертикальным текстом
        var CellsCount2 = VerticallCells.length;
        for (var TempCellIndex = 0; TempCellIndex < CellsCount2; TempCellIndex++)
        {
            var Cell       = VerticallCells[TempCellIndex];
            var CurCell    = Cell.Index;
            var GridSpan   = Cell.Get_GridSpan();
            var CurGridCol = Cell.Metrics.StartGridCol;

            // Возьмем верхнюю ячейку текущего объединения
            Cell = this.Internal_Get_StartMergedCell(CurRow, CurGridCol, GridSpan);

            var CellMar     = Cell.GetMargins();
            var CellMetrics = Cell.Row.Get_CellInfo(Cell.Index);

            var X_content_start = Page.X + CellMetrics.X_content_start;
            var X_content_end   = Page.X + CellMetrics.X_content_end;
            var Y_content_start = Cell.Temp.Y;
            var Y_content_end   = this.TableRowsBottom[CurRow][CurPage];

            // TODO: При расчете YLimit для ячейки сделать учет толщины нижних
            //       границ ячейки и таблицы
            if (null != CellSpacing)
            {
                if (this.Content.length - 1 === CurRow)
                    Y_content_end -= CellSpacing;
                else
                    Y_content_end -= CellSpacing / 2;
            }

            var VMergeCount = this.Internal_GetVertMergeCount(CurRow, CurGridCol, GridSpan);
            var BottomMargin = this.MaxBotMargin[CurRow + VMergeCount - 1];
            Y_content_end -= BottomMargin;

            if ((0 === Cell.Row.Index && true === this.Check_EmptyPages(CurPage - 1)) || Cell.Row.Index > FirstRow || (Cell.Row.Index === FirstRow && true === ResetStartElement))
            {
                // TODO: Здесь надо сделать, чтобы ячейка не билась на страницы
                Cell.PagesCount = 1;
                Cell.Content.Set_StartPage(CurPage);
                Cell.Content.Reset(0, 0, Y_content_end - Y_content_start, 10000);
                Cell.Temp.X_start = X_content_start;
                Cell.Temp.Y_start = Y_content_start;
                Cell.Temp.X_end   = X_content_end;
                Cell.Temp.Y_end   = Y_content_end;

                Cell.Temp.X_cell_start = Page.X + CellMetrics.X_cell_start;
                Cell.Temp.X_cell_end   = Page.X + CellMetrics.X_cell_end;
                Cell.Temp.Y_cell_start = Y_content_start - CellMar.Top.W;
                Cell.Temp.Y_cell_end   = Y_content_end + BottomMargin;
            }

            // Какие-то ячейки в строке могут быть не разбиты на строки, а какие то разбиты.
            // Здесь контролируем этот момент, чтобы у тех, которые не разбиты не вызывать
            // Recalculate_Page от несуществующих страниц.
            var CellPageIndex = CurPage - Cell.Content.Get_StartPage_Relative();
            if (0 === CellPageIndex)
            {
                Cell.Content.Recalculate_Page(CellPageIndex, true);
            }
        }

		// Еще раз проверим, были ли сноски
		var nCurFootnotesHeight = oFootnotes ? oFootnotes.GetHeight(nPageAbs, nColumnAbs) : 0;
		if (oFootnotes && nCurFootnotesHeight > nFootnotesHeight + 0.001)
		{
			this.Pages[CurPage].FootnotesH = nCurFootnotesHeight;

			nFootnotesHeight     = nCurFootnotesHeight;
			nResetFootnotesIndex = CurRow;
			Y                    = arrSavedY[CurRow];
			TableHeight          = arrSavedTableHeight[CurRow];
			oFootnotes.LoadRecalculateObject(nPageAbs, nColumnAbs, arrFootnotesObject[CurRow]);

			CurRow--;
			continue;
		}

        if ( null != CellSpacing )
            this.RowsInfo[CurRow].H[CurPage] = CellHeight;
        else
            this.RowsInfo[CurRow].H[CurPage] = CellHeight + TempMaxTopBorder;

        Y           += CellHeight;
        TableHeight += CellHeight;

        Row.Height   = CellHeight;

        Y           += MaxBotBorder[CurRow];
        TableHeight += MaxBotBorder[CurRow];

        if ( this.Content.length - 1 === CurRow )
        {
            if ( null != CellSpacing )
            {
                TableHeight += CellSpacing;

                var TableBorder_Bottom = this.Get_Borders().Bottom;
                if ( border_Single === TableBorder_Bottom.Value )
                    TableHeight += TableBorder_Bottom.Size;
            }
        }

        if ( true === bNextPage )
        {
            LastRow = CurRow;
            this.Pages[CurPage].LastRow = CurRow;

            if  ( -1 === this.HeaderInfo.PageIndex && this.HeaderInfo.Count > 0 && CurRow >= this.HeaderInfo.Count )
                this.HeaderInfo.PageIndex = CurPage;

            break;
        }
        else if ( this.Content.length - 1 === CurRow )
        {
            LastRow = this.Content.length - 1;
            this.Pages[CurPage].LastRow = this.Content.length - 1;
        }
    }

    // Сделаем вертикальное выравнивание ячеек в таблице. Делаем как Word, если ячейка разбилась на несколько
    // страниц, тогда вертикальное выравнивание применяем только к первой странице.
    // Делаем это не в общем цикле, потому что объединенные вертикально ячейки могут вносить поправки в значения
    // this.TableRowsBottom, в последней строке.
    for ( var CurRow = FirstRow; CurRow <= LastRow; CurRow++ )
    {
        var Row = this.Content[CurRow];
        var CellsCount = Row.Get_CellsCount();
        for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
        {
            var Cell = Row.Get_Cell( CurCell );
            var VMergeCount = this.Internal_GetVertMergeCount( CurRow, Cell.Metrics.StartGridCol, Cell.Get_GridSpan() );

            if ( VMergeCount > 1 && CurRow != LastRow )
                continue;
            else
            {
                var Vmerge = Cell.GetVMerge();
                // Возьмем верхнюю ячейку текущего объединения
                if ( vmerge_Restart != Vmerge )
                {
                    Cell = this.Internal_Get_StartMergedCell( CurRow, Cell.Metrics.StartGridCol, Cell.Get_GridSpan() );
                }
            }

            var CellMar       = Cell.GetMargins();
            var VAlign        = Cell.Get_VAlign();
            var CellPageIndex = CurPage - Cell.Content.Get_StartPage_Relative();

            if ( CellPageIndex >= Cell.PagesCount )
                continue;

            // Рассчитаем имеющуюся в распоряжении высоту ячейки
            var TempCurRow = Cell.Row.Index;

            // Для прилегания к верху или для второй страницы ничего не делаем (так изначально рассчитывалось)
            if ( vertalignjc_Top === VAlign || CellPageIndex > 1 || (1 === CellPageIndex && true === this.RowsInfo[TempCurRow].FirstPage ) )
            {
                Cell.Temp.Y_VAlign_offset[CellPageIndex] = 0;
                continue;
            }

            var TempCellSpacing = this.Content[TempCurRow].Get_CellSpacing();
            var Y_0 = this.RowsInfo[TempCurRow].Y[CurPage];

            if ( null === TempCellSpacing )
                Y_0 += MaxTopBorder[TempCurRow];

            Y_0 += CellMar.Top.W;

            var Y_1 = this.TableRowsBottom[CurRow][CurPage] - CellMar.Bottom.W;
            var CellHeight = Y_1 - Y_0;

            var CellContentBounds = Cell.Content.Get_PageBounds( CellPageIndex, CellHeight, true );
            var ContentHeight = CellContentBounds.Bottom - CellContentBounds.Top;

            var Dy = 0;

            if (true === Cell.Is_VerticalText())
            {
                var CellMetrics = Row.Get_CellInfo(CurCell);
                CellHeight = CellMetrics.X_cell_end - CellMetrics.X_cell_start - CellMar.Left.W - CellMar.Right.W;
            }

            if (CellHeight - ContentHeight > 0.001)
            {
                if (vertalignjc_Bottom === VAlign)
                    Dy = CellHeight - ContentHeight;
                else if (vertalignjc_Center === VAlign)
                    Dy = (CellHeight - ContentHeight) / 2;

                Cell.Content.Shift(CellPageIndex, 0, Dy);
            }

            Cell.Temp.Y_VAlign_offset[CellPageIndex] = Dy;
        }
    }


    // Просчитаем нижнюю границу таблицы на данной странице
    var CurRow = LastRow;
    if ( 0 === CurRow && false === this.RowsInfo[CurRow].FirstPage && 0 === CurPage )
    {
        // Таблица сразу переносится на следующую страницу
        this.Pages[0].MaxBotBorder = 0;
        this.Pages[0].BotBorders   = [];
    }
    else
    {
        // Если последняя строка на данной странице не имеет контента, тогда рассчитываем
        // границу у предыдущей строки.
        if ( false === this.RowsInfo[CurRow].FirstPage && CurPage === this.RowsInfo[CurRow].StartPage )
            CurRow--;

        var MaxBotBorder = 0;
        var BotBorders   = [];

        if (CurRow >= this.Pages[CurPage].FirstRow)
        {
            // Для ряда CurRow вычисляем нижнюю границу
            if (this.Content.length - 1 === CurRow)
            {
                // Для последнего ряда уже есть готовые нижние границы
                var Row        = this.Content[CurRow];
                var CellsCount = Row.Get_CellsCount();
                for (var CurCell = 0; CurCell < CellsCount; CurCell++)
                {
                    var Cell = Row.Get_Cell(CurCell);
                    if (vmerge_Continue === Cell.GetVMerge())
                        Cell = this.Internal_Get_StartMergedCell(CurRow, Row.Get_CellInfo(CurCell).StartGridCol, Cell.Get_GridSpan());

                    var Border_Info = Cell.Get_BorderInfo().Bottom;

                    for (var BorderId = 0; BorderId < Border_Info.length; BorderId++)
                    {
                        var Border = Border_Info[BorderId];
                        if (border_Single === Border.Value && MaxBotBorder < Border.Size)
                            MaxBotBorder = Border.Size;

                        BotBorders.push(Border);
                    }
                }
            }
            else
            {
                var Row         = this.Content[CurRow];
                var CellSpacing = Row.Get_CellSpacing();
                var CellsCount  = Row.Get_CellsCount();

                if (null != CellSpacing)
                {
                    // BotBorders можно не заполнять, т.к. у каждой ячейки своя граница,
                    // нам надо только посчитать максимальную толщину.
                    for (var CurCell = 0; CurCell < CellsCount; CurCell++)
                    {
                        var Cell   = Row.Get_Cell(CurCell);
                        var Border = Cell.Get_Borders().Bottom;

                        if (border_Single === Border.Value && MaxBotBorder < Border.Size)
                            MaxBotBorder = Border.Size;
                    }
                }
                else
                {
                    // Сравниваем нижнюю границу ячейки и нижнюю границу таблицы
                    for (var CurCell = 0; CurCell < CellsCount; CurCell++)
                    {
                        var Cell = Row.Get_Cell(CurCell);

                        if (vmerge_Continue === Cell.GetVMerge())
                        {
                            Cell = this.Internal_Get_StartMergedCell(CurRow, Row.Get_CellInfo(CurCell).StartGridCol, Cell.Get_GridSpan());
                            if (null === Cell)
                            {
                                BotBorders.push(TableBorders.Bottom);
                                continue;
                            }
                        }

                        var Border = Cell.Get_Borders().Bottom;

                        // Сравним границы
                        var Result_Border = this.Internal_CompareBorders(Border, TableBorders.Bottom, false, true);
                        if (border_Single === Result_Border.Value && MaxBotBorder < Result_Border.Size)
                            MaxBotBorder = Result_Border.Size;

                        BotBorders.push(Result_Border);
                    }
                }
            }
        }

        this.Pages[CurPage].MaxBotBorder = MaxBotBorder;
        this.Pages[CurPage].BotBorders   = BotBorders;
    }

    this.Pages[CurPage].Bounds.Bottom = this.Pages[CurPage].Bounds.Top + TableHeight;
    this.Pages[CurPage].Bounds.Left   = X_min + this.Pages[CurPage].X;
    this.Pages[CurPage].Bounds.Right  = X_max + this.Pages[CurPage].X;
    this.Pages[CurPage].Height        = TableHeight;

    if (true === bNextPage)
    {
        var LastRow = this.Pages[CurPage].LastRow;
        if (false === this.RowsInfo[LastRow].FirstPage)
            this.Pages[CurPage].LastRow = LastRow - 1;
        else
            this.Pages[CurPage].LastRowSplit = true;
    }

    this.TurnOffRecalc = false;

    this.Bounds = this.Pages[this.Pages.length - 1].Bounds;

    if ( true == bNextPage )
        return recalcresult_NextPage;
    else
        return recalcresult_NextElement;
};
CTable.prototype.private_RecalculatePositionY = function(CurPage)
{
    var PageLimits = this.Parent.Get_PageLimits(this.PageNum + CurPage);
    var PageFields = this.Parent.Get_PageFields(this.PageNum + CurPage);
    var LD_PageFields = this.LogicDocument.Get_PageFields(this.Get_StartPage_Absolute() + CurPage);
    var LD_PageLimits = this.LogicDocument.Get_PageLimits(this.Get_StartPage_Absolute() + CurPage);

    if ( true === this.Is_Inline() && 0 === CurPage )
    {
        this.AnchorPosition.CalcY = this.Y;
        this.AnchorPosition.Set_Y(this.Pages[CurPage].Height, this.Y, LD_PageFields.Y, LD_PageFields.YLimit, LD_PageLimits.YLimit, PageLimits.Y, PageLimits.YLimit, PageLimits.Y, PageLimits.YLimit);
    }
    else if ( true != this.Is_Inline() && ( 0 === CurPage || ( 1 === CurPage && false === this.RowsInfo[0].FirstPage ) ) )
    {
        this.AnchorPosition.Set_Y(this.Pages[CurPage].Height, this.Pages[CurPage].Y, PageFields.Y, PageFields.YLimit, LD_PageLimits.YLimit, PageLimits.Y, PageLimits.YLimit, PageLimits.Y, PageLimits.YLimit);

        var OtherFlowTables = !this.bPresentation ? editor.WordControl.m_oLogicDocument.DrawingObjects.getAllFloatTablesOnPage( this.Get_StartPage_Absolute() ) : [];
        this.AnchorPosition.Calculate_Y(this.PositionV.RelativeFrom, this.PositionV.Align, this.PositionV.Value);
        this.AnchorPosition.Correct_Values( PageLimits.X, PageLimits.Y, PageLimits.XLimit, PageLimits.YLimit, this.AllowOverlap, OtherFlowTables, this );

        if ( undefined != this.PositionV_Old )
        {
            // Восстанови старые значения, чтобы в историю изменений все нормально записалось
            this.PositionV.RelativeFrom = this.PositionV_Old.RelativeFrom;
            this.PositionV.Align        = this.PositionV_Old.Align;
            this.PositionV.Value        = this.PositionV_Old.Value;

            // Рассчитаем сдвиг с учетом старой привязки
            var Value = this.AnchorPosition.Calculate_Y_Value(this.PositionV_Old.RelativeFrom);
            this.Set_PositionV( this.PositionV_Old.RelativeFrom, false, Value );
            // На всякий случай пересчитаем заново координату
            this.AnchorPosition.Calculate_Y(this.PositionV.RelativeFrom, this.PositionV.Align, this.PositionV.Value);

            this.PositionV_Old = undefined;
        }

        var NewX = this.AnchorPosition.CalcX;
        var NewY = this.AnchorPosition.CalcY;

        this.Shift( CurPage, NewX - this.Pages[CurPage].X, NewY - this.Pages[CurPage].Y );
    }
};
CTable.prototype.private_RecalculateSkipPage = function(CurPage)
{
    this.HeaderInfo.Pages[CurPage] = {};
    this.HeaderInfo.Pages[CurPage].Draw = false;

    for ( var Index = -1; Index < this.Content.length; Index++ )
    {
        if (!this.TableRowsBottom[Index])
            this.TableRowsBottom[Index] = [];

        this.TableRowsBottom[Index][CurPage] = 0;
    }

    this.Pages[CurPage].MaxBotBorder = 0;
    this.Pages[CurPage].BotBorders   = [];

    if (0 === CurPage)
    {
        this.Pages[CurPage].FirstRow = 0;
        this.Pages[CurPage].LastRow  = -1;
    }
    else
    {
        var FirstRow;
        if (true === this.IsEmptyPage(CurPage - 1))
            FirstRow = this.Pages[CurPage - 1].FirstRow;
        else
            FirstRow = this.Pages[CurPage - 1].LastRow;

        this.Pages[CurPage].FirstRow = FirstRow;
        this.Pages[CurPage].LastRow  = FirstRow -1;
    }
};
CTable.prototype.private_RecalculatePercentWidth = function()
{
    return this.XLimit - this.X - this.GetTableOffsetCorrection() + this.GetRightTableOffsetCorrection();
};
CTable.prototype.private_RecalculateGridCols = function()
{
	for (var nCurRow = 0, nRowsCount = this.Content.length; nCurRow < nRowsCount; ++nCurRow)
	{
		var oRow        = this.Content[nCurRow];
		var oBeforeInfo = oRow.Get_Before();
		var nCurGridCol = oBeforeInfo.GridBefore;

		for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			var oCell = oRow.GetCell(nCurCell);
			oRow.Set_CellInfo(nCurCell, nCurGridCol, 0, 0, 0, 0, 0, 0);
			oCell.Set_Metrics(nCurGridCol, 0, 0, 0, 0, 0, 0);
			nCurGridCol += oCell.Get_GridSpan();
		}
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Класс CTablePage
//----------------------------------------------------------------------------------------------------------------------
function CTablePage(X, Y, XLimit, YLimit, FirstRow, MaxTopBorder)
{
    this.X_origin     = X;
    this.X            = X;
    this.Y            = Y;
    this.XLimit       = XLimit;
    this.YLimit       = YLimit;
    this.Bounds       = new CDocumentBounds(X, Y, XLimit, Y);
    this.MaxTopBorder = MaxTopBorder;
    this.FirstRow     = FirstRow;
    this.LastRow      = FirstRow;
    this.Height       = 0;
    this.LastRowSplit = false;
	this.FootnotesH   = 0;
}
CTablePage.prototype.Shift = function(Dx, Dy)
{
    this.X += Dx;
    this.Y += Dy;
    this.XLimit += Dx;
    this.YLimit += Dy;
    this.Bounds.Shift(Dx, Dy);
};
//----------------------------------------------------------------------------------------------------------------------
// Класс CTableRecalcInfo
//----------------------------------------------------------------------------------------------------------------------
function CTableRecalcInfo()
{
    this.TableGrid     = true;
    this.TableBorders  = true;

    this.CellsToRecalc = {};
    this.CellsAll      = true;
}
CTableRecalcInfo.prototype.Recalc_Borders = function()
{
    this.TableBorders = true;
};
CTableRecalcInfo.prototype.Add_Cell = function(Cell)
{
    this.CellsToRecalc[Cell.Get_Id()] = Cell;
};
CTableRecalcInfo.prototype.Check_Cell = function(Cell)
{
    if ( true === this.CellsAll || undefined != this.CellsToRecalc[Cell.Get_Id()] )
        return true;

    return false;
};
CTableRecalcInfo.prototype.Recalc_AllCells = function()
{
    this.CellsAll = true;
};
CTableRecalcInfo.prototype.Reset = function(bCellsAll)
{
    this.TableGrid     = true;
    this.TableBorders  = true;
    this.CellsAll      = bCellsAll;
    this.CellsToRecalc = {};
};
//----------------------------------------------------------------------------------------------------------------------
// Класс CTableRecalculateObject
//----------------------------------------------------------------------------------------------------------------------
function CTableRecalculateObject()
{
    this.TableSumGrid    = [];
    this.TableGridCalc   = [];

    this.TableRowsBottom = [];
    this.HeaderInfo      = {};
    this.RowsInfo        = [];

    this.X_origin = 0;
    this.X        = 0;
    this.Y        = 0;
    this.XLimit   = 0;
    this.YLimit   = 0;

    this.Pages    = [];

    this.MaxTopBorder = [];
    this.MaxBotBorder = [];
    this.MaxBotMargin = [];

    this.Content = [];
}
CTableRecalculateObject.prototype.Save = function(Table)
{
    this.TableSumGrid    = Table.TableSumGrid;
    this.TableGridCalc   = Table.TableGridCalc;

    this.TableRowsBottom = Table.TableRowsBottom;
    this.HeaderInfo      = Table.HeaderInfo;
    this.RowsInfo        = Table.RowsInfo;

    this.X_origin        = Table.X_origin;
    this.X               = Table.X;
    this.Y               = Table.Y;
    this.XLimit          = Table.XLimit;
    this.YLimit          = Table.YLimit;

    this.Pages           = Table.Pages;

    this.MaxTopBorder    = Table.MaxTopBorder;
    this.MaxBotBorder    = Table.MaxBotBorder;
    this.MaxBotMargin    = Table.MaxBotBorder;

    var Count = Table.Content.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        this.Content[Index] = Table.Content[Index].SaveRecalculateObject();
    }
};
CTableRecalculateObject.prototype.Load = function(Table)
{
    Table.TableSumGrid    = this.TableSumGrid;
    Table.TableGridCalc   = this.TableGridCalc;

    Table.TableRowsBottom = this.TableRowsBottom;
    Table.HeaderInfo      = this.HeaderInfo;
    Table.RowsInfo        = this.RowsInfo;

    Table.X_origin        = this.X_origin;
    Table.X               = this.X;
    Table.Y               = this.Y;
    Table.XLimit          = this.XLimit;
    Table.YLimit          = this.YLimit;

    Table.Pages           = this.Pages;

    Table.MaxTopBorder    = this.MaxTopBorder;
    Table.MaxBotBorder    = this.MaxBotBorder;
    Table.MaxBotMargin    = this.MaxBotBorder;

    var Count = this.Content.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        Table.Content[Index].LoadRecalculateObject( this.Content[Index] );
    }
};
CTableRecalculateObject.prototype.Get_DrawingFlowPos = function(FlowPos)
{
    var Count = this.Content.length;
    for (var Index = 0; Index < Count; Index++)
    {
        this.Content[Index].Get_DrawingFlowPos(FlowPos);
    }
};

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var c_oAscLineDrawingRule = AscCommon.c_oAscLineDrawingRule;
var global_MatrixTransformer = AscCommon.global_MatrixTransformer;

CTable.prototype.ReDraw = function()
{
    this.Parent.OnContentReDraw( this.Get_StartPage_Absolute(), this.Get_StartPage_Absolute() + this.Pages.length - 1 );
};
CTable.prototype.Draw = function(CurPage, pGraphics)
{
    if (CurPage < 0 || CurPage >= this.Pages.length)
        return 0;

    if (true === this.IsEmptyPage(CurPage))
        return;

    var Page = this.Pages[CurPage];

    // Определим какие строки попадают на данную страницу
    var Row_start = this.Pages[CurPage].FirstRow;
    var Row_last  = this.Pages[CurPage].LastRow;

    if (Row_last < Row_start)
        return -1;

    // Возможно, на данной странице строку, с которой началось разбиение на странице,
    // не надо рисовать. (Если начальная и конечная строки совпадают, тогда это 2
    // или более страница данной строки)
    if ((Row_start != Row_last || (0 === Row_start && 0 === Row_last && 0 === CurPage)) && false === this.RowsInfo[Row_last].FirstPage)
        Row_last--;

    if (Row_last < Row_start)
        return -1;

    // Данный случай добавлен из-за сносок. Когда у таблицы на данной страницы ничего не убирается.
	// TODO: Надо улучшить данную проверку, т.к. она не учитывает ситуацию с вложенными таблицами.
    if (Row_start === Row_last && Math.abs(this.RowsInfo[Row_last].H[CurPage] - this.RowsInfo[Row_last].TopDy[CurPage]) < 0.001)
        return -1;

    pGraphics.SaveGrState();

    var bIsSmartGrForcing = false;
    if (pGraphics.StartCheckTableDraw)
        bIsSmartGrForcing = pGraphics.StartCheckTableDraw();

    //-------------------------------------------------------------------------------------
    // 1. Сначала заливаем таблицу и если есть Spacing, тогда обводим внешнюю рамку таблицы
    //-------------------------------------------------------------------------------------
    this.private_DrawTableBackgroundAndOuterBorder(pGraphics, CurPage, Row_start, Row_last);
    //-------------------------------------------------------------------------------------
    // 2. Рисуем заливку всех ячеек таблицы
    //-------------------------------------------------------------------------------------
    this.private_DrawCellsBackground(pGraphics, CurPage, Row_start, Row_last);
    //-------------------------------------------------------------------------------------
    // 3. Рисуем содержимое ячеек
    //-------------------------------------------------------------------------------------
    this.private_DrawCellsContent(pGraphics, CurPage, Row_start, Row_last);
    //-------------------------------------------------------------------------------------
    // 4. Рисуем границы всех ячеек таблицы
    //-------------------------------------------------------------------------------------
    this.private_DrawCellsBorders(pGraphics, CurPage, Row_start, Row_last);

    if (pGraphics.EndCheckTableDraw)
        pGraphics.EndCheckTableDraw(bIsSmartGrForcing);

    pGraphics.RestoreGrState();

    if (CurPage < this.Pages.length - 1)
        return -1;

    return 0;
};
CTable.prototype.private_DrawTableBackgroundAndOuterBorder = function(pGraphics, PNum, Row_start, Row_last)
{
    var CurPage = PNum;
    var TableShd = this.Get_Shd();

    var X_left_old  = null;
    var X_right_old = null;

    var Page = this.Pages[CurPage];

    var Y_top    = this.Pages[PNum].Bounds.Top;
    var Y_bottom = this.Pages[PNum].Bounds.Top;

    var LockType = this.Lock.Get_Type();
    if ( AscCommon.locktype_None != LockType )
    {
        pGraphics.DrawLockObjectRect(this.Lock.Get_Type(), this.Pages[PNum].Bounds.Left, this.Pages[PNum].Bounds.Top, this.Pages[PNum].Bounds.Right - this.Pages[PNum].Bounds.Left, this.Pages[PNum].Bounds.Bottom - this.Pages[PNum].Bounds.Top );
    }

    var TableBorders = this.Get_Borders();

    // Заголовок
    var bHeader = false;
    if(this.bPresentation)
    {
        var Row         = this.Content[0];
        var CellSpacing = Row.Get_CellSpacing();
        var CellsCount  = Row.Get_CellsCount();
        var X_left_new  = Page.X + Row.Get_CellInfo(0).X_grid_start;
        var X_right_new = Page.X + Row.Get_CellInfo(CellsCount - 1).X_grid_end;
        pGraphics.SaveGrState();
        pGraphics.SetIntegerGrid(false);
        var ShapeDrawer = new AscCommon.CShapeDrawer();
        TableShd.Unifill && TableShd.Unifill.check(this.Get_Theme(), this.Get_ColorMap());
        var Transform = this.Parent.transform.CreateDublicate();
        global_MatrixTransformer.TranslateAppend(Transform, Math.min(X_left_new, X_right_new), Math.min(Y_top, Y_bottom));
        pGraphics.transform3(Transform, false);
        ShapeDrawer.fromShape2(new AscFormat.ObjectToDraw(TableShd.Unifill, null, Math.abs(X_right_new - X_left_new), Math.abs(this.Pages[0].Bounds.Bottom - Y_top), null, Transform), pGraphics, null);
        ShapeDrawer.draw(null);
        pGraphics.RestoreGrState();
    }
    if ( this.HeaderInfo.Count > 0 && PNum > this.HeaderInfo.PageIndex && true === this.HeaderInfo.Pages[PNum].Draw )
    {
        bHeader = true;

        var HeaderPage = this.HeaderInfo.Pages[PNum];
        for ( var CurRow = 0; CurRow < this.HeaderInfo.Count; CurRow++ )
        {
            var Row         = HeaderPage.Rows[CurRow];
            var CellSpacing = Row.Get_CellSpacing();
            var CellsCount  = Row.Get_CellsCount();
            var X_left_new  = Page.X + Row.Get_CellInfo(0).X_grid_start;
            var X_right_new = Page.X + Row.Get_CellInfo(CellsCount - 1).X_grid_end;

            Y_bottom = HeaderPage.RowsInfo[CurRow].Y + HeaderPage.RowsInfo[CurRow].H;

            var PrevCellSpacing = ( CurRow < this.HeaderInfo.Count - 1 ? HeaderPage.Rows[CurRow + 1].Get_CellSpacing() : this.Content[Row_start].Get_CellSpacing() );
            Y_bottom += (PrevCellSpacing + CellSpacing) / 4;

            this.private_DrawRowBackgroundAndOuterBorder(pGraphics, TableShd, (null != CellSpacing ? true : false), TableBorders, X_left_new, X_left_old, X_right_new, X_right_old, Y_top, Y_bottom, ( 0 === CurRow ? true : false), false );

            X_left_old  = X_left_new;
            X_right_old = X_right_new;

            Y_top = Y_bottom;
        }
    }

    for ( var CurRow = Row_start; CurRow <= Row_last; CurRow++ )
    {
        var Row         = this.Content[CurRow];
        var CellSpacing = Row.Get_CellSpacing();
        var CellsCount  = Row.Get_CellsCount();
        var X_left_new  = Page.X + Row.Get_CellInfo(0).X_grid_start;
        var X_right_new = Page.X + Row.Get_CellInfo(CellsCount - 1).X_grid_end;

        Y_bottom = this.RowsInfo[CurRow].Y[PNum] + this.RowsInfo[CurRow].H[PNum];
        if ( this.Content.length - 1 === CurRow )
        {
            Y_bottom += Row.Get_CellSpacing();
        }
        else
        {
            var CellSpacing = Row.Get_CellSpacing();
            var PrevCellSpacing = this.Content[CurRow + 1].Get_CellSpacing();
            Y_bottom += (PrevCellSpacing + CellSpacing) / 4;
        }

        Y_bottom += this.RowsInfo[CurRow].MaxBotBorder;

        if ( null != CellSpacing && PNum != this.Pages.length - 1 && CurRow === Row_last )
            Y_bottom += this.Pages[PNum].MaxBotBorder;

        this.private_DrawRowBackgroundAndOuterBorder(pGraphics, TableShd, (null != CellSpacing ? true : false), TableBorders, X_left_new, X_left_old, X_right_new, X_right_old, Y_top, Y_bottom, ( true != bHeader && Row_start === CurRow ? true : false), (Row_last === CurRow ? true : false) );

        X_left_old  = X_left_new;
        X_right_old = X_right_new;

        Y_top = Y_bottom;
    }
};
CTable.prototype.private_DrawRowBackgroundAndOuterBorder = function(pGraphics, TableShd, bBorder, TableBorders, X_left_new, X_left_old, X_right_new, X_right_old, Y_top, Y_bottom, bStartRow, bLastRow)
{
    var Theme = this.Get_Theme();
    var ColorMap = this.Get_ColorMap();
    var RGBA;
    // Рисуем рамку и заливку самой таблицы
    if ( Asc.c_oAscShdNil != TableShd.Value )
    {
        if(!this.bPresentation)
        {
            RGBA = TableShd.Get_Color2(Theme, ColorMap);
            if(pGraphics.SetShd)
            {
                pGraphics.SetShd(TableShd);

            }
            pGraphics.b_color1( RGBA.r, RGBA.g, RGBA.b, 255 );
            pGraphics.TableRect(Math.min(X_left_new, X_right_new), Math.min(Y_top, Y_bottom), Math.abs(X_right_new - X_left_new), Math.abs(Y_bottom - Y_top));
        }
        // else
        // {
        //     pGraphics.SaveGrState();
        //     pGraphics.SetIntegerGrid(false);
        //     var ShapeDrawer = new CShapeDrawer();
        //     TableShd.Unifill && TableShd.Unifill.check(Theme, ColorMap);
        //     var Transform = this.Parent.transform.CreateDublicate();
        //     global_MatrixTransformer.TranslateAppend(Transform, Math.min(X_left_new, X_right_new), Math.min(Y_top, Y_bottom));
        //     pGraphics.transform3(Transform, false);
        //     ShapeDrawer.fromShape2(new ObjectToDraw(TableShd.Unifill, null, Math.abs(X_right_new - X_left_new), Math.abs(Y_bottom - Y_top), null, Transform), pGraphics, null);
        //     ShapeDrawer.draw(null);
        //     pGraphics.RestoreGrState();
        // }
    }

    if ( true === bBorder )
    {
        // Левая граница
        if ( border_Single === TableBorders.Left.Value )
        {
            RGBA = TableBorders.Left.Get_Color2(Theme, ColorMap);
            pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
            if(pGraphics.SetBorder)
            {
                pGraphics.SetBorder(TableBorders.Left);
            }
            if ( null === X_left_old || Math.abs( X_left_new - X_left_old ) < 0.001 )
            {
                pGraphics.drawVerLine( c_oAscLineDrawingRule.Center, X_left_new, Y_top, Y_bottom, TableBorders.Left.Size );
            }
            else
            {
                if ( X_left_new > X_left_old )
                {
                    pGraphics.drawHorLineExt( c_oAscLineDrawingRule.Top,    Y_top, X_left_old, X_left_new, TableBorders.Left.Size, -TableBorders.Left.Size / 2, 0 );
                }
                else
                {
                    pGraphics.drawHorLineExt( c_oAscLineDrawingRule.Bottom, Y_top, X_left_old, X_left_new, TableBorders.Left.Size, +TableBorders.Left.Size / 2, -TableBorders.Left.Size / 2 );
                }

                pGraphics.drawVerLine( c_oAscLineDrawingRule.Center, X_left_new, Y_top, Y_bottom, TableBorders.Left.Size );
            }
        }
        else //if ( border_None === TableBorders.Left.Value )
        {
            if ( null === X_left_old || Math.abs( X_left_new - X_left_old ) < 0.001 )
            {
                pGraphics.DrawEmptyTableLine( X_left_new, Y_top, X_left_new, Y_bottom );
            }
            else
            {
                pGraphics.DrawEmptyTableLine( X_left_old, Y_top, X_left_new, Y_top    );
                pGraphics.DrawEmptyTableLine( X_left_new, Y_top, X_left_new, Y_bottom );
            }
        }

        // Правая граница
        if ( border_Single === TableBorders.Right.Value )
        {
            RGBA =  TableBorders.Right.Get_Color2(Theme, ColorMap);
            pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
            if(pGraphics.SetBorder)
            {
                pGraphics.SetBorder(TableBorders.Right);
            }
            if ( null === X_right_old || Math.abs( X_right_new - X_right_old ) < 0.001 )
            {
                pGraphics.drawVerLine( c_oAscLineDrawingRule.Center, X_right_new, Y_top, Y_bottom, TableBorders.Right.Size );
            }
            else
            {
                if ( X_right_new > X_right_old )
                {
                    pGraphics.drawHorLineExt( c_oAscLineDrawingRule.Bottom, Y_top, X_right_old, X_right_new, TableBorders.Right.Size, - TableBorders.Right.Size / 2, +TableBorders.Right.Size / 2 );
                }
                else
                {
                    pGraphics.drawHorLineExt( c_oAscLineDrawingRule.Top, Y_top, X_right_old, X_right_new, TableBorders.Right.Size, + TableBorders.Right.Size / 2, 0 );
                }

                pGraphics.drawVerLine( c_oAscLineDrawingRule.Center, X_right_new, Y_top, Y_bottom, TableBorders.Right.Size );
            }
        }
        else //if ( border_None === TableBorders.Right.Value )
        {
            if ( null === X_right_old || Math.abs( X_right_new - X_right_old ) < 0.001 )
            {
                pGraphics.DrawEmptyTableLine( X_right_new, Y_top, X_right_new, Y_bottom );
            }
            else
            {
                pGraphics.DrawEmptyTableLine( X_right_old, Y_top, X_right_new, Y_top    );
                pGraphics.DrawEmptyTableLine( X_right_new, Y_top, X_right_new, Y_bottom );
            }
        }

        if ( true === bStartRow )
        {
            // Верхняя граница
            if ( border_Single === TableBorders.Top.Value )
            {
                RGBA =  TableBorders.Top.Get_Color2(Theme, ColorMap);
                pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                if(pGraphics.SetBorder)
                {
                    pGraphics.SetBorder(TableBorders.Top);
                }
                // Добавочные значения толщины правой и левой границ
                var LeftMW = 0;
                if ( border_Single === TableBorders.Left.Value )
                    LeftMW = - TableBorders.Left.Size / 2;

                var RightMW = 0;
                if ( border_Single === TableBorders.Right.Value )
                    RightMW = + TableBorders.Right.Size / 2;

                pGraphics.drawHorLineExt( c_oAscLineDrawingRule.Top, Y_top, X_left_new, X_right_new, TableBorders.Top.Size, LeftMW, RightMW );
            }
            else //if ( border_None === TableBorders.Top.Value )
            {
                pGraphics.DrawEmptyTableLine( X_left_new, Y_top, X_right_new, Y_top );
            }
        }

        if ( true === bLastRow )
        {
            // Нижняя граница
            if ( border_Single === TableBorders.Bottom.Value )
            {
                RGBA =  TableBorders.Bottom.Get_Color2(Theme, ColorMap);
                pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                if(pGraphics.SetBorder)
                {
                    pGraphics.SetBorder(TableBorders.Bottom);
                }
                // Добавочные значения толщины правой и левой границ
                var LeftMW = 0;
                if ( border_Single === TableBorders.Left.Value )
                    LeftMW = - TableBorders.Left.Size / 2;

                var RightMW = 0;
                if ( border_Single === TableBorders.Right.Value )
                    RightMW = + TableBorders.Right.Size / 2;

                pGraphics.drawHorLineExt( c_oAscLineDrawingRule.Top, Y_bottom, X_left_new, X_right_new, TableBorders.Bottom.Size, LeftMW, RightMW );
            }
            else //if ( border_None === TableBorders.Bottom.Value )
            {
                pGraphics.DrawEmptyTableLine( X_left_new, Y_bottom, X_right_new, Y_bottom );
            }
        }
    }

};
CTable.prototype.private_DrawCellsBackground = function(pGraphics, PNum, Row_start, Row_last)
{
    var CurPage = PNum;
    var Page = this.Pages[CurPage];

    // Рисуем заливку всех ячеек на странице
    var Theme = this.Get_Theme();
    var ColorMap = this.Get_ColorMap();
    if(this.bPresentation)
    {
        pGraphics.SaveGrState();
        pGraphics.SetIntegerGrid(false);
    }
    if ( this.HeaderInfo.Count > 0 && PNum > this.HeaderInfo.PageIndex && true === this.HeaderInfo.Pages[PNum].Draw )
    {
        var HeaderPage = this.HeaderInfo.Pages[PNum];
        // Рисуем заливку всех ячеек на странице
        for ( var CurRow = 0; CurRow < this.HeaderInfo.Count; CurRow++ )
        {
            var Row        = HeaderPage.Rows[CurRow];
            var CellsCount = Row.Get_CellsCount();
            var Y          = HeaderPage.RowsInfo[CurRow].Y;

            // Рисуем ячейки начиная с последней, потому что левая ячейка
            // должна рисоваться поверх правой при конфликте границ.
            for ( var CurCell = CellsCount - 1; CurCell >= 0; CurCell-- )
            {
                var Cell       = Row.Get_Cell( CurCell );
                var GridSpan   = Cell.Get_GridSpan();
                var VMerge     = Cell.GetVMerge();
                var CurGridCol = Row.Get_CellInfo( CurCell ).StartGridCol;

                if ( vmerge_Continue === VMerge )
                    continue;

                var CellInfo     = Row.Get_CellInfo( CurCell );
                var X_cell_start = Page.X + CellInfo.X_cell_start;
                var X_cell_end   = Page.X + CellInfo.X_cell_end;

                var VMergeCount  = this.Internal_GetVertMergeCount( CurRow, CurGridCol, GridSpan );
                var RealHeight   = HeaderPage.RowsInfo[CurRow + VMergeCount - 1].Y + HeaderPage.RowsInfo[CurRow + VMergeCount - 1].H - Y;

                // Заливаем ячейку
                var CellShd = Cell.Get_Shd();
                if(!this.bPresentation)
                {
                    var RGBA = CellShd.Get_Color2(Theme, ColorMap);
                    if (true !== RGBA.Auto)
                    {
                        pGraphics.b_color1(RGBA.r, RGBA.g, RGBA.b, 255);
                        if(pGraphics.SetShd)
                        {
                            pGraphics.SetShd(CellShd);

                        }
                        pGraphics.TableRect(Math.min(X_cell_start, X_cell_end), Math.min(Y, Y + RealHeight), Math.abs(X_cell_end - X_cell_start), Math.abs(RealHeight));
                    }
                }
                else
                {
                    if(CellShd.Unifill && CellShd.Unifill.fill)
                    {
                        //if(CellShd.Unifill.fill.type === FILL_TYPE_SOLID)
                        //{
                        //    var Alpha, RGBA = CellShd.Get_Color3(Theme, ColorMap);
                        //    if(AscFormat.isRealNumber(CellShd.Unifill.transparent))
                        //    {
                        //        Alpha = CellShd.Unifill.transparent;
                        //    }
                        //    else
                        //    {
                        //        Alpha = 255;
                        //    }
                        //    pGraphics.b_color1( RGBA.R, RGBA.G, RGBA.B, Alpha );
                        //    pGraphics.TableRect(Math.min(X_cell_start, X_cell_end), Math.min(Y, Y + RealHeight), Math.abs(X_cell_end - X_cell_start), Math.abs(RealHeight));
                        //}
                        //else TODO: Сделать нормальную отрисовку.
                        {
                            var ShapeDrawer = new AscCommon.CShapeDrawer();
                            CellShd.Unifill.check(Theme, ColorMap);
                            var Transform = this.Parent.transform.CreateDublicate();
                            global_MatrixTransformer.TranslateAppend(Transform, Math.min(X_cell_start, X_cell_end), Math.min(Y, Y + RealHeight));

                            pGraphics.transform3(Transform, false);
                            ShapeDrawer.fromShape2(new AscFormat.ObjectToDraw(CellShd.Unifill, null, Math.abs(X_cell_end - X_cell_start), Math.abs(RealHeight), null, Transform), pGraphics, null);
                            ShapeDrawer.draw(null);
                        }
                    }
                }
            }
        }
    }


    // Рисуем заливку всех ячеек на странице
    for ( var CurRow = Row_start; CurRow <= Row_last; CurRow++ )
    {
        var Row = this.Content[CurRow];
        var CellsCount = Row.Get_CellsCount();
        var Y = this.RowsInfo[CurRow].Y[PNum];

        // Рисуем ячейки начиная с последней, потому что левая ячейка
        // должна рисоваться поверх правой при конфликте границ.
        for ( var CurCell = CellsCount - 1; CurCell >= 0; CurCell-- )
        {
            var Cell = Row.Get_Cell( CurCell );
            var GridSpan = Cell.Get_GridSpan();
            var VMerge = Cell.GetVMerge();
            var CurGridCol = Row.Get_CellInfo( CurCell ).StartGridCol;

            if ( vmerge_Continue === VMerge )
            {
                if ( Row_start === CurRow  )
                {
                    Cell = this.Internal_Get_StartMergedCell( CurRow, CurGridCol, GridSpan );
                    if ( null === Cell )
                        continue;

                    // Параметры GridSpan и CurGridCol должны остаться такими же
                }
                else
                    continue;
            }

            var CellInfo     = Row.Get_CellInfo( CurCell );
            var X_cell_start = Page.X + CellInfo.X_cell_start;
            var X_cell_end   = Page.X + CellInfo.X_cell_end;

            var VMergeCount = this.private_GetVertMergeCountOnPage(PNum, CurRow, CurGridCol, GridSpan);
            if (VMergeCount <= 0)
                continue;

            var RealHeight  = this.RowsInfo[CurRow + VMergeCount - 1].Y[PNum] + this.RowsInfo[CurRow + VMergeCount - 1].H[PNum] - Y;

            // Заливаем ячейку
            var CellShd = Cell.Get_Shd();
            if ( Asc.c_oAscShdNil != CellShd.Value )
            {
                if(!this.bPresentation)
                {
                    var RGBA = CellShd.Get_Color2(Theme, ColorMap);
                    if (true !== RGBA.Auto)
                    {
                        pGraphics.b_color1(RGBA.r, RGBA.g, RGBA.b, 255);
                        if(pGraphics.SetShd)
                        {
                            pGraphics.SetShd(CellShd);

                        }
                        pGraphics.TableRect(Math.min(X_cell_start, X_cell_end), Math.min(Y, Y + RealHeight), Math.abs(X_cell_end - X_cell_start), Math.abs(RealHeight));
                    }
                }
                else
                {
                    if(CellShd.Unifill && CellShd.Unifill.fill)
                    {
                        //if(CellShd.Unifill.fill.type === FILL_TYPE_SOLID)
                        //{
                        //    var Alpha, RGBA = CellShd.Get_Color3(Theme, ColorMap);
                        //    if(AscFormat.isRealNumber(CellShd.Unifill.transparent))
                        //    {
                        //        Alpha = CellShd.Unifill.transparent;
                        //    }
                        //    else
                        //    {
                        //        Alpha = 255;
                        //    }
                        //    pGraphics.b_color1( RGBA.R, RGBA.G, RGBA.B, Alpha );
                        //    pGraphics.TableRect(Math.min(X_cell_start, X_cell_end), Math.min(Y, Y + RealHeight), Math.abs(X_cell_end - X_cell_start), Math.abs(RealHeight));
                        //}
                        //else TODO: Сделать нормальную отрисовку.
                        {
                            var ShapeDrawer = new AscCommon.CShapeDrawer();
                            CellShd.Unifill.check(Theme, ColorMap);
                            var Transform = this.Parent.transform.CreateDublicate();
                            global_MatrixTransformer.TranslateAppend(Transform, Math.min(X_cell_start, X_cell_end), Math.min(Y, Y + RealHeight));
                            pGraphics.transform3(Transform, false);
                            ShapeDrawer.fromShape2(new AscFormat.ObjectToDraw(CellShd.Unifill, null, Math.abs(X_cell_end - X_cell_start), Math.abs(RealHeight), null, Transform), pGraphics, null);
                            ShapeDrawer.draw(null);
                        }
                    }
                }
            }
        }
    }

    if(this.bPresentation)
    {
        pGraphics.RestoreGrState();
    }
};
CTable.prototype.private_DrawCellsContent = function(pGraphics, PNum, Row_start, Row_last)
{
    if ( this.HeaderInfo.Count > 0 && PNum > this.HeaderInfo.PageIndex && true === this.HeaderInfo.Pages[PNum].Draw )
    {
        if(pGraphics.Start_Command)
        {
            pGraphics.Start_Command(AscFormat.DRAW_COMMAND_TABLE_ROW);
        }
        var HeaderPage = this.HeaderInfo.Pages[PNum];
        for ( var CurRow = 0; CurRow < this.HeaderInfo.Count; CurRow++ )
        {
            var Row        = HeaderPage.Rows[CurRow];
            var CellsCount = Row.Get_CellsCount();

            for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
            {
                var Cell   = Row.Get_Cell( CurCell );
                var VMerge = Cell.GetVMerge();

                if ( vmerge_Continue === VMerge )
                    continue;

                // Выводим содержимое таблицы
                Cell.Content_Draw(PNum, pGraphics);
            }
        }
        if(pGraphics.End_Command)
        {
            pGraphics.End_Command();
        }
    }

    // Рисуем содержимое всех ячеек. Его рисуем в нормальном порядке, потому что некоторые элементы
    // могут начинаться внутри одной ячейки, а заканчиваться в другой
    for ( var CurRow = Row_start; CurRow <= Row_last; CurRow++ )
    {
        var Row = this.Content[CurRow];
        var CellsCount = Row.Get_CellsCount();

        if(pGraphics.Start_Command)
        {
            pGraphics.Start_Command(AscFormat.DRAW_COMMAND_TABLE_ROW);
        }
        for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
        {
            var Cell = Row.Get_Cell( CurCell );
            var GridSpan = Cell.Get_GridSpan();
            var VMerge = Cell.GetVMerge();
            var CurGridCol = Row.Get_CellInfo( CurCell ).StartGridCol;

            if ( vmerge_Continue === VMerge )
            {
                if ( Row_start === CurRow  )
                {
                    Cell = this.Internal_Get_StartMergedCell( CurRow, CurGridCol, GridSpan );
                    if ( null === Cell )
                        continue;

                    // Параметры GridSpan и CurGridCol должны остаться такими же
                }
                else
                    continue;
            }

            var VMergeCount = this.private_GetVertMergeCountOnPage(PNum, CurRow, CurGridCol, GridSpan);
            if (VMergeCount <= 0)
                continue;

            // Выводим содержимое таблицы
            Cell.Content_Draw(PNum, pGraphics);
        }

        if(pGraphics.End_Command)
        {
            pGraphics.End_Command();
        }
    }
};
CTable.prototype.private_DrawCellsBorders = function(pGraphics, PNum, Row_start, Row_last)
{
    var CurPage = PNum;
    var Page = this.Pages[CurPage];

    var TableBorders = this.Get_Borders();
    var Theme = this.Get_Theme();
    var ColorMap = this.Get_ColorMap();
    var RGBA;
    if ( this.HeaderInfo.Count > 0 && PNum > this.HeaderInfo.PageIndex && true === this.HeaderInfo.Pages[PNum].Draw )
    {
        var Y = this.Y;
        var HeaderPage = this.HeaderInfo.Pages[PNum];
        for ( var CurRow = 0; CurRow < this.HeaderInfo.Count; CurRow++ )
        {
            var Row         = HeaderPage.Rows[CurRow];
            var CellsCount  = Row.Get_CellsCount();
            var CellSpacing = Row.Get_CellSpacing();

            Y = HeaderPage.RowsInfo[CurRow].Y;

            var LastBorderTop = { W : 0, L : 0 };

            // Рисуем ячейки начиная с последней, потому что левая ячейка
            // должна рисоваться поверх правой при конфликте границ.
            for ( var CurCell = CellsCount - 1; CurCell >= 0; CurCell-- )
            {
                var Cell = Row.Get_Cell( CurCell );
                var GridSpan = Cell.Get_GridSpan();
                var VMerge = Cell.GetVMerge();
                var CurGridCol = Row.Get_CellInfo( CurCell ).StartGridCol;

                if ( vmerge_Continue === VMerge )
                {
                    LastBorderTop = { W : 0, L : 0 };
                    continue;
                }

                var CellInfo     = Row.Get_CellInfo( CurCell );
                var X_cell_start = Page.X + CellInfo.X_cell_start;
                var X_cell_end   = Page.X + CellInfo.X_cell_end;
                var VMergeCount  = this.Internal_GetVertMergeCount( CurRow, CurGridCol, GridSpan );
                var RealHeight   = HeaderPage.RowsInfo[CurRow + VMergeCount - 1].Y + HeaderPage.RowsInfo[CurRow + VMergeCount - 1].H - Y;

                // Обводим ячейку
                var CellBorders = Cell.Get_Borders();

                if ( null != CellSpacing )
                {
                    // Левая граница
                    if ( border_Single === CellBorders.Left.Value )
                    {
                        RGBA = CellBorders.Left.Get_Color2(Theme, ColorMap);
                        pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                        if(pGraphics.SetBorder)
                        {
                            pGraphics.SetBorder(CellBorders.Left);
                        }
                        pGraphics.drawVerLine( c_oAscLineDrawingRule.Left, X_cell_start, Y, Y + RealHeight, CellBorders.Left.Size );
                    }
                    else //if ( border_None === CellBorders.Left.Value )
                    {
                        pGraphics.DrawEmptyTableLine( X_cell_start, Y, X_cell_start, Y + RealHeight );
                    }

                    // Правая граница
                    if ( border_Single === CellBorders.Right.Value )
                    {
                        RGBA = CellBorders.Right.Get_Color2(Theme, ColorMap);
                        pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                        if(pGraphics.SetBorder)
                        {
                            pGraphics.SetBorder(CellBorders.Right);
                        }
                        pGraphics.drawVerLine( c_oAscLineDrawingRule.Right, X_cell_end, Y, Y + RealHeight, CellBorders.Right.Size );
                    }
                    else //if ( border_None === CellBorders.Right.Value )
                    {
                        pGraphics.DrawEmptyTableLine( X_cell_end, Y, X_cell_end, Y + RealHeight );
                    }

                    // Верхняя граница
                    if ( border_Single === CellBorders.Top.Value )
                    {
                        RGBA = CellBorders.Top.Get_Color2(Theme, ColorMap);
                        pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                        if(pGraphics.SetBorder)
                        {
                            pGraphics.SetBorder(CellBorders.Top);
                        }
                        pGraphics.drawHorLineExt( c_oAscLineDrawingRule.Top, Y - CellBorders.Top.Size, X_cell_start, X_cell_end, CellBorders.Top.Size, 0, 0 );
                    }
                    else //if ( border_None === CellBorders.Top.Value )
                    {
                        pGraphics.DrawEmptyTableLine( X_cell_start, Y, X_cell_end, Y );
                    }

                    // Нижняя граница
                    if ( border_Single === CellBorders.Bottom.Value )
                    {
                        RGBA = CellBorders.Bottom.Get_Color2(Theme, ColorMap);
                        pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                        if(pGraphics.SetBorder)
                        {
                            pGraphics.SetBorder(CellBorders.Bottom);
                        }
                        pGraphics.drawHorLineExt( c_oAscLineDrawingRule.Bottom, Y + RealHeight + CellBorders.Bottom.Size, X_cell_start, X_cell_end, CellBorders.Bottom.Size, 0, 0 );
                    }
                    else //if ( border_None === CellBorders.Bottom.Value )
                    {
                        pGraphics.DrawEmptyTableLine( X_cell_start, Y + RealHeight, X_cell_end, Y + RealHeight );
                    }
                }
                else
                {
                    var CellBordersInfo = Cell.Get_BorderInfo();

                    // Левая граница
                    var BorderInfo_Left = CellBordersInfo.Left;
                    // Это значение может не совпадать с CurRow
                    var TempCurRow = Cell.Row.Index;

                    var Row_side_border_start = 0;
                    var Row_side_border_end   = BorderInfo_Left.length - 1;

                    for ( var Index = Row_side_border_start; Index <= Row_side_border_end; Index++ )
                    {
                        var CurBorderInfo = BorderInfo_Left[Index];
                        var Y0 = HeaderPage.RowsInfo[TempCurRow + Index].Y;
                        var Y1 = HeaderPage.RowsInfo[TempCurRow + Index].Y + HeaderPage.RowsInfo[TempCurRow + Index].H;

                        if ( border_Single === CurBorderInfo.Value )
                        {
                            RGBA = CurBorderInfo.Get_Color2(Theme, ColorMap);
                            pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                            if(pGraphics.SetBorder)
                            {
                                pGraphics.SetBorder(CurBorderInfo);
                            }
                            pGraphics.drawVerLine( c_oAscLineDrawingRule.Center, X_cell_start, Y0, Y1, CurBorderInfo.Size );
                        }
                        else //if ( border_None === CurBorderInfo.Value )
                        {
                            if ( 0 === CurCell )
                            {
                                pGraphics.DrawEmptyTableLine( X_cell_start, Y0, X_cell_start, Y1 );
                            }

                            // Для остальных ячеек невидимые границы мы рисуем как правые
                        }
                    }

                    // Правая граница
                    var BorderInfo_Right = CellBordersInfo.Right;
                    for ( var Index = Row_side_border_start; Index <= Row_side_border_end; Index++ )
                    {
                        var CurBorderInfo = BorderInfo_Right[Index];
                        var Y0 = HeaderPage.RowsInfo[TempCurRow + Index].Y;
                        var Y1 = HeaderPage.RowsInfo[TempCurRow + Index].Y + HeaderPage.RowsInfo[TempCurRow + Index].H;

                        // Мы должны проверить последняя ли данная ячейка в строке
                        var TempCellIndex  = this.private_GetCellIndexByStartGridCol( TempCurRow + Index, CellInfo.StartGridCol );
                        var TempCellsCount = HeaderPage.Rows[TempCurRow + Index].Get_CellsCount();

                        if ( TempCellsCount - 1 === TempCellIndex )
                        {
                            if ( border_Single === CurBorderInfo.Value )
                            {
                                RGBA = CurBorderInfo.Get_Color2(Theme, ColorMap);
                                pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                                if(pGraphics.SetBorder)
                                {
                                    pGraphics.SetBorder(CurBorderInfo);
                                }
                                pGraphics.drawVerLine( c_oAscLineDrawingRule.Center, X_cell_end, Y0, Y1, CurBorderInfo.Size );
                            }
                            else //if ( border_None === CurBorderInfo.Value )
                            {
                                pGraphics.DrawEmptyTableLine( X_cell_end, Y0, X_cell_end, Y1 );
                            }
                        }
                        else if ( border_None === CurBorderInfo.Value )
                        {
                            pGraphics.DrawEmptyTableLine( X_cell_end, Y0, X_cell_end, Y1 );
                        }
                    }

                    // Верхняя граница
                    var LastBorderTop_prev = { W : LastBorderTop.W, H : LastBorderTop.H };
                    var BorderInfo_Top = CellBordersInfo.Top;
                    for ( var Index = 0; Index < BorderInfo_Top.length; Index++ )
                    {
                        var CurBorderInfo = BorderInfo_Top[Index];

                        // Верхняя граница первой строки на новой странице должна рисоваться, либо
                        // как задано в ячейке, либо как задано в таблице.
                        if ( 0 != PNum && CurRow === Row_start )
                            CurBorderInfo = this.Internal_CompareBorders( TableBorders.Top, CurBorderInfo, true, false );

                        var X0 = Page.X + this.TableSumGrid[Index + CurGridCol - 1];
                        var X1 = Page.X + this.TableSumGrid[Index + CurGridCol];

                        var LeftMW = 0;
                        var RightMW = 0;
                        if ( BorderInfo_Top.length - 1 === Index )
                        {
                            var Max_r = 0;
                            if ( 0 != CurRow )
                            {
                                var Prev_Row = HeaderPage.Rows[CurRow - 1];
                                var Prev_CellsCount = Prev_Row.Get_CellsCount();
                                for ( var TempIndex = 0; TempIndex < Prev_CellsCount; TempIndex++ )
                                {
                                    var Prev_Cell = Prev_Row.Get_Cell( TempIndex );
                                    var Prev_GridCol = Prev_Row.Get_CellInfo( TempIndex ).StartGridCol;
                                    var Prev_GridSpan = Prev_Cell.Get_GridSpan();

                                    var bLeft = null;
                                    if ( Prev_GridCol === Index + CurGridCol + 1 )
                                    {
                                        bLeft = true;
                                    }
                                    else if ( Prev_GridCol + Prev_GridSpan === Index + CurGridCol + 1 )
                                    {
                                        bLeft = false;
                                    }
                                    else if ( Prev_GridCol > CurGridCol )
                                        break;

                                    if ( null != bLeft )
                                    {
                                        var Prev_VMerge = Prev_Cell.GetVMerge();
                                        if ( vmerge_Continue === Prev_VMerge )
                                            Prev_Cell = this.Internal_Get_StartMergedCell( CurRow - 1, Prev_GridCol, Prev_GridSpan );

                                        if ( null === Prev_Cell )
                                            break;

                                        var Num = CurRow - 1 - Prev_Cell.Row.Index;
                                        if ( Num < 0 )
                                            break;

                                        if ( true === bLeft )
                                        {
                                            var Prev_Cell_BorderInfo_Left = Prev_Cell.Get_BorderInfo().Left;
                                            if( null != Prev_Cell_BorderInfo_Left && Prev_Cell_BorderInfo_Left.length > Num && border_Single === Prev_Cell_BorderInfo_Left[Num].Value )
                                                Max_r = Prev_Cell_BorderInfo_Left[Num].Size / 2;
                                        }
                                        else
                                        {
                                            var Prev_Cell_BorderInfo_Right = Prev_Cell.Get_BorderInfo().Right;
                                            if( null != Prev_Cell_BorderInfo_Right && Prev_Cell_BorderInfo_Right.length > Num && border_Single === Prev_Cell_BorderInfo_Right[Num].Value )
                                                Max_r = Prev_Cell_BorderInfo_Right[Num].Size / 2;
                                        }

                                        break;
                                    }
                                }
                            }

                            if ( BorderInfo_Right.length > 0 && border_Single === BorderInfo_Right[0].Value && BorderInfo_Right[0].Size / 2 > Max_r )
                                Max_r = BorderInfo_Right[0].Size / 2;

                            // Отдаем предпочтение более широкой границе
                            if ( border_Single === CurBorderInfo.Value && CurBorderInfo.Size > LastBorderTop_prev.W )
                                RightMW = Max_r;
                            else
                                RightMW = -Max_r;
                        }

                        if ( 0 === Index )
                        {
                            var Max_l = 0;
                            if ( 0 != CurRow )
                            {
                                var Prev_Row = this.Content[CurRow - 1];
                                var Prev_CellsCount = Prev_Row.Get_CellsCount();
                                for ( var TempIndex = 0; TempIndex < Prev_CellsCount; TempIndex++ )
                                {
                                    var Prev_Cell = Prev_Row.Get_Cell( TempIndex );
                                    var Prev_GridCol = Prev_Row.Get_CellInfo( TempIndex ).StartGridCol;
                                    var Prev_GridSpan = Prev_Cell.Get_GridSpan();

                                    var bLeft = null;
                                    if ( Prev_GridCol === CurGridCol )
                                    {
                                        bLeft = true;
                                    }
                                    else if ( Prev_GridCol + Prev_GridSpan === CurGridCol )
                                    {
                                        bLeft = false;
                                    }
                                    else if ( Prev_GridCol > CurGridCol )
                                        break;

                                    if ( null != bLeft )
                                    {
                                        var Prev_VMerge = Prev_Cell.GetVMerge();
                                        if ( vmerge_Continue === Prev_VMerge )
                                            Prev_Cell = this.Internal_Get_StartMergedCell( CurRow - 1, Prev_GridCol, Prev_GridSpan );

                                        if ( null === Prev_Cell )
                                            break;

                                        var Num = CurRow - 1 - Prev_Cell.Row.Index;
                                        if ( Num < 0 )
                                            break;

                                        if ( true === bLeft )
                                        {
                                            var Prev_Cell_BorderInfo_Left = Prev_Cell.Get_BorderInfo().Left;
                                            if( null != Prev_Cell_BorderInfo_Left && Prev_Cell_BorderInfo_Left.length > Num && border_Single === Prev_Cell_BorderInfo_Left[Num].Value )
                                                Max_l = Prev_Cell_BorderInfo_Left[Num].Size / 2;

                                        }
                                        else
                                        {
                                            var Prev_Cell_BorderInfo_Right = Prev_Cell.Get_BorderInfo().Right;
                                            if( null != Prev_Cell_BorderInfo_Right && Prev_Cell_BorderInfo_Right.length > Num && border_Single === Prev_Cell_BorderInfo_Right[Num].Value )
                                                Max_l = Prev_Cell_BorderInfo_Right[Num].Size / 2;
                                        }

                                        break;
                                    }
                                }
                            }

                            if( BorderInfo_Left.length > 0 && border_Single === BorderInfo_Left[0].Value && BorderInfo_Left[0].Size / 2 > Max_l )
                                Max_l = BorderInfo_Left[0].Size / 2;

                            LastBorderTop.L = Max_l;
                            LastBorderTop.W = 0;

                            if ( border_Single === CurBorderInfo.Value )
                                LastBorderTop.W = CurBorderInfo.Size;
                        }

                        if ( border_Single === CurBorderInfo.Value )
                        {
                            RGBA = CurBorderInfo.Get_Color2(Theme, ColorMap);
                            pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                            if(pGraphics.SetBorder)
                            {
                                pGraphics.SetBorder(CurBorderInfo);
                            }
                            pGraphics.drawHorLineExt( c_oAscLineDrawingRule.Top, Y, X0, X1, CurBorderInfo.Size, LeftMW, RightMW );
                        }
                        else //if ( border_None === CurBorderInfo.Value )
                        {
                            pGraphics.DrawEmptyTableLine( X0 + LeftMW, Y, X1 + RightMW , Y );
                        }
                    }
                }
            }
        }
    }

    var Y = this.Y;
    for ( var CurRow = Row_start; CurRow <= Row_last; CurRow++ )
    {
        var Row = this.Content[CurRow];
        var CellsCount = Row.Get_CellsCount();
        Y = this.RowsInfo[CurRow].Y[PNum];
        var CellSpacing = Row.Get_CellSpacing();

        var LastBorderTop = { W : 0, L : 0 };

        // Рисуем ячейки начиная с последней, потому что левая ячейка
        // должна рисоваться поверх правой при конфликте границ.
        for ( var CurCell = CellsCount - 1; CurCell >= 0; CurCell-- )
        {
            var Cell = Row.Get_Cell( CurCell );
            var GridSpan = Cell.Get_GridSpan();
            var VMerge = Cell.GetVMerge();
            var CurGridCol = Row.Get_CellInfo( CurCell ).StartGridCol;

            if ( vmerge_Continue === VMerge )
            {
                if ( Row_start === CurRow  )
                {
                    Cell = this.Internal_Get_StartMergedCell( CurRow, CurGridCol, GridSpan );
                    if ( null === Cell )
                    {
                        LastBorderTop = { W : 0, L : 0 };
                        continue;
                    }

                    // Параметры GridSpan и CurGridCol должны остаться такими же
                }
                else
                {
                    LastBorderTop = { W : 0, L : 0 };
                    continue;
                }
            }

            var CellInfo     = Row.Get_CellInfo( CurCell );
            var X_cell_start = Page.X + CellInfo.X_cell_start;
            var X_cell_end   = Page.X + CellInfo.X_cell_end;

            var VMergeCount = this.private_GetVertMergeCountOnPage(PNum, CurRow, CurGridCol, GridSpan);
            if (VMergeCount <= 0)
            {
                LastBorderTop = {W : 0, L : 0};
                continue;
            }

            var RealHeight  = this.RowsInfo[CurRow + VMergeCount - 1].Y[PNum] + this.RowsInfo[CurRow + VMergeCount - 1].H[PNum] - Y;

            // Обводим ячейку
            var CellBorders = Cell.Get_Borders();

            if ( null != CellSpacing )
            {
                // Левая граница
                if ( border_Single === CellBorders.Left.Value )
                {
                    RGBA =  CellBorders.Left.Get_Color2(Theme, ColorMap);
                    pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                    if(pGraphics.SetBorder)
                    {
                        pGraphics.SetBorder(CellBorders.Left);
                    }
                    pGraphics.drawVerLine( c_oAscLineDrawingRule.Left, X_cell_start, Y, Y + RealHeight, CellBorders.Left.Size );
                }
                else //if ( border_None === CellBorders.Left.Value )
                {
                    pGraphics.DrawEmptyTableLine( X_cell_start, Y, X_cell_start, Y + RealHeight );
                }

                // Правая граница
                if ( border_Single === CellBorders.Right.Value )
                {
                    RGBA =  CellBorders.Right.Get_Color2(Theme, ColorMap);
                    pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                    if(pGraphics.SetBorder)
                    {
                        pGraphics.SetBorder(CellBorders.Right);
                    }
                    pGraphics.drawVerLine( c_oAscLineDrawingRule.Right, X_cell_end, Y, Y + RealHeight, CellBorders.Right.Size );
                }
                else //if ( border_None === CellBorders.Right.Value )
                {
                    pGraphics.DrawEmptyTableLine( X_cell_end, Y, X_cell_end, Y + RealHeight );
                }

                // Верхняя граница
                if ( border_Single === CellBorders.Top.Value )
                {

                    RGBA =  CellBorders.Top.Get_Color2(Theme, ColorMap);
                    pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                    if(pGraphics.SetBorder)
                    {
                        pGraphics.SetBorder(CellBorders.Top);
                    }
                    pGraphics.drawHorLineExt( c_oAscLineDrawingRule.Top, Y - CellBorders.Top.Size, X_cell_start, X_cell_end, CellBorders.Top.Size, 0, 0 );
                }
                else //if ( border_None === CellBorders.Top.Value )
                {
                    pGraphics.DrawEmptyTableLine( X_cell_start, Y, X_cell_end, Y );
                }

                // Нижняя граница
                if ( border_Single === CellBorders.Bottom.Value )
                {
                    RGBA =  CellBorders.Bottom.Get_Color2(Theme, ColorMap);
                    pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                    if(pGraphics.SetBorder)
                    {
                        pGraphics.SetBorder(CellBorders.Bottom);
                    }
                    pGraphics.drawHorLineExt( c_oAscLineDrawingRule.Bottom, Y + RealHeight + CellBorders.Bottom.Size, X_cell_start, X_cell_end, CellBorders.Bottom.Size, 0, 0 );
                }
                else //if ( border_None === CellBorders.Bottom.Value )
                {
                    pGraphics.DrawEmptyTableLine( X_cell_start, Y + RealHeight, X_cell_end, Y + RealHeight );
                }
            }
            else
            {
                var CellBordersInfo = Cell.Get_BorderInfo();

                // Левая граница
                var BorderInfo_Left  = CellBordersInfo.Left;

                // Это значение может не совпадать с CurRow
                var TempCurRow = Cell.Row.Index;

                var Row_side_border_start = ( TempCurRow < Row_start ? Row_start - TempCurRow : 0 );
                var Row_side_border_end   = ( BorderInfo_Left.length - 1 + TempCurRow > Row_last ? Row_last - TempCurRow + 1 : BorderInfo_Left.length - 1 );
                for ( var Index = Row_side_border_start; Index <= Row_side_border_end; Index++ )
                {
                    var CurBorderInfo = BorderInfo_Left[Index];
                    var Y0 = this.RowsInfo[TempCurRow + Index].Y[PNum];
                    var Y1 = this.RowsInfo[TempCurRow + Index].Y[PNum] + this.RowsInfo[TempCurRow + Index].H[PNum];

                    if ( border_Single === CurBorderInfo.Value )
                    {
                        RGBA =  CurBorderInfo.Get_Color2(Theme, ColorMap);
                        pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                        //pGraphics.p_width( CurBorderInfo.Size * 1000 );
                        //pGraphics._s();
                        if(pGraphics.SetBorder)
                        {
                            pGraphics.SetBorder(CurBorderInfo);
                        }

                        pGraphics.drawVerLine( c_oAscLineDrawingRule.Center, X_cell_start, Y0, Y1, CurBorderInfo.Size );
                        //pGraphics._m( X_cell_start * 100, Y0 * 100 );
                        //pGraphics._l( X_cell_start * 100, Y1 * 100 );

                        //pGraphics.ds();
                    }
                    else //if ( border_None === CurBorderInfo.Value )
                    {
                        if ( 0 === CurCell )
                        {
                            pGraphics.DrawEmptyTableLine( X_cell_start, Y0, X_cell_start, Y1 );
                        }

                        // Для остальных ячеек невидимые границы мы рисуем как правые
                    }
                }


                // Правая граница
                var BorderInfo_Right = CellBordersInfo.Right;
                for ( var Index = Row_side_border_start; Index <= Row_side_border_end; Index++ )
                {
                    var CurBorderInfo = BorderInfo_Right[Index];
                    var Y0 = this.RowsInfo[TempCurRow + Index].Y[PNum];
                    var Y1 = this.RowsInfo[TempCurRow + Index].Y[PNum] + this.RowsInfo[TempCurRow + Index].H[PNum];

                    // Мы должны проверить последняя ли данная ячейка в строке
                    var TempCellIndex  = this.private_GetCellIndexByStartGridCol( TempCurRow + Index, CellInfo.StartGridCol );
                    var TempCellsCount = this.Content[TempCurRow + Index].Get_CellsCount();

                    if ( TempCellsCount - 1 === TempCellIndex )
                    {
                        if ( border_Single === CurBorderInfo.Value )
                        {

                            RGBA =  CurBorderInfo.Get_Color2(Theme, ColorMap);
                            pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                            //pGraphics.p_width( CurBorderInfo.Size * 1000 );
                            //pGraphics._s();
                            if(pGraphics.SetBorder)
                            {
                                pGraphics.SetBorder(CurBorderInfo);
                            }

                            pGraphics.drawVerLine( c_oAscLineDrawingRule.Center, X_cell_end, Y0, Y1, CurBorderInfo.Size );
                            //pGraphics._m( X_cell_end * 100, Y0 * 100 );
                            //pGraphics._l( X_cell_end * 100, Y1 * 100 );

                            //pGraphics.ds();
                        }
                        else //if ( border_None === CurBorderInfo.Value )
                        {
                            pGraphics.DrawEmptyTableLine( X_cell_end, Y0, X_cell_end, Y1 );
                        }
                    }
                    else if ( border_None === CurBorderInfo.Value )
                    {
                        pGraphics.DrawEmptyTableLine( X_cell_end, Y0, X_cell_end, Y1 );
                    }
                }


                // Верхняя граница
                var BorderInfo_Top   = CellBordersInfo.Top;
                var LastBorderTop_prev = { W : LastBorderTop.W, H : LastBorderTop.H };
                for ( var Index = 0; Index < BorderInfo_Top.length; Index++ )
                {
                    var CurBorderInfo = BorderInfo_Top[Index];

                    // Верхняя граница первой строки на новой странице должна рисоваться, либо
                    // как задано в ячейке, либо как задано в таблице.
                    if ( 0 != PNum && CurRow === Row_start )
                        CurBorderInfo = this.Internal_CompareBorders( TableBorders.Top, CurBorderInfo, true, false );

                    var X0 = Page.X + this.TableSumGrid[Index + CurGridCol - 1];
                    var X1 = Page.X + this.TableSumGrid[Index + CurGridCol];

                    var LeftMW = 0;
                    var RightMW = 0;
                    if ( BorderInfo_Top.length - 1 === Index )
                    {
                        var Max_r = 0;
                        if ( 0 != CurRow )
                        {
                            var Prev_Row = this.Content[CurRow - 1];
                            var Prev_CellsCount = Prev_Row.Get_CellsCount();
                            for ( var TempIndex = 0; TempIndex < Prev_CellsCount; TempIndex++ )
                            {
                                var Prev_Cell = Prev_Row.Get_Cell( TempIndex );
                                var Prev_GridCol = Prev_Row.Get_CellInfo( TempIndex ).StartGridCol;
                                var Prev_GridSpan = Prev_Cell.Get_GridSpan();

                                var bLeft = null;
                                if ( Prev_GridCol === Index + CurGridCol + 1 )
                                {
                                    bLeft = true;
                                }
                                else if ( Prev_GridCol + Prev_GridSpan === Index + CurGridCol + 1 )
                                {
                                    bLeft = false;
                                }
                                else if ( Prev_GridCol > CurGridCol )
                                    break;

                                if ( null != bLeft )
                                {
                                    var Prev_VMerge = Prev_Cell.GetVMerge();
                                    if ( vmerge_Continue === Prev_VMerge )
                                        Prev_Cell = this.Internal_Get_StartMergedCell( CurRow - 1, Prev_GridCol, Prev_GridSpan );

                                    if ( null === Prev_Cell )
                                        break;

                                    var Num = CurRow - 1 - Prev_Cell.Row.Index;
                                    if ( Num < 0 )
                                        break;

                                    if ( true === bLeft )
                                    {
                                        var Prev_Cell_BorderInfo_Left = Prev_Cell.Get_BorderInfo().Left;
                                        if( null != Prev_Cell_BorderInfo_Left && Prev_Cell_BorderInfo_Left.length > Num && border_Single === Prev_Cell_BorderInfo_Left[Num].Value )
                                            Max_r = Prev_Cell_BorderInfo_Left[Num].Size / 2;
                                    }
                                    else
                                    {
                                        var Prev_Cell_BorderInfo_Right = Prev_Cell.Get_BorderInfo().Right;
                                        if( null != Prev_Cell_BorderInfo_Right && Prev_Cell_BorderInfo_Right.length > Num && border_Single === Prev_Cell_BorderInfo_Right[Num].Value )
                                            Max_r = Prev_Cell_BorderInfo_Right[Num].Size / 2;
                                    }

                                    break;
                                }
                            }
                        }

                        if ( BorderInfo_Right.length > 0 && border_Single === BorderInfo_Right[0].Value && BorderInfo_Right[0].Size / 2 > Max_r )
                            Max_r = BorderInfo_Right[0].Size / 2;

                        // Отдаем предпочтение более широкой границе
                        if ( border_Single === CurBorderInfo.Value && CurBorderInfo.Size > LastBorderTop_prev.W )
                            RightMW = Max_r;//X1 += Max_r;
                        else
                            RightMW = -Max_r;//X1 -= Max_r;

                        if ( border_Single === BorderInfo_Right[0].Value && CurBorderInfo.Size <= BorderInfo_Right[0].Size )
                            RightMW = -BorderInfo_Right[0].Size / 2;
                    }

                    if ( 0 === Index )
                    {
                        var Max_l = 0;
                        if ( 0 != CurRow )
                        {
                            var Prev_Row = this.Content[CurRow - 1];
                            var Prev_CellsCount = Prev_Row.Get_CellsCount();
                            for ( var TempIndex = 0; TempIndex < Prev_CellsCount; TempIndex++ )
                            {
                                var Prev_Cell = Prev_Row.Get_Cell( TempIndex );
                                var Prev_GridCol = Prev_Row.Get_CellInfo( TempIndex ).StartGridCol;
                                var Prev_GridSpan = Prev_Cell.Get_GridSpan();

                                var bLeft = null;
                                if ( Prev_GridCol === CurGridCol )
                                {
                                    bLeft = true;
                                }
                                else if ( Prev_GridCol + Prev_GridSpan === CurGridCol )
                                {
                                    bLeft = false;
                                }
                                else if ( Prev_GridCol > CurGridCol )
                                    break;

                                if ( null != bLeft )
                                {
                                    var Prev_VMerge = Prev_Cell.GetVMerge();
                                    if ( vmerge_Continue === Prev_VMerge )
                                        Prev_Cell = this.Internal_Get_StartMergedCell( CurRow - 1, Prev_GridCol, Prev_GridSpan );

                                    if ( null === Prev_Cell )
                                        break;

                                    var Num = CurRow - 1 - Prev_Cell.Row.Index;
                                    if ( Num < 0 )
                                        break;

                                    if ( true === bLeft )
                                    {
                                        var Prev_Cell_BorderInfo_Left = Prev_Cell.Get_BorderInfo().Left;
                                        if( null != Prev_Cell_BorderInfo_Left && Prev_Cell_BorderInfo_Left.length > Num && border_Single === Prev_Cell_BorderInfo_Left[Num].Value )
                                            Max_l = Prev_Cell_BorderInfo_Left[Num].Size / 2;

                                    }
                                    else
                                    {
                                        var Prev_Cell_BorderInfo_Right = Prev_Cell.Get_BorderInfo().Right;
                                        if( null != Prev_Cell_BorderInfo_Right && Prev_Cell_BorderInfo_Right.length > Num && border_Single === Prev_Cell_BorderInfo_Right[Num].Value )
                                            Max_l = Prev_Cell_BorderInfo_Right[Num].Size / 2;
                                    }

                                    break;
                                }
                            }
                        }

                        if( BorderInfo_Left.length > 0 && border_Single === BorderInfo_Left[0].Value && BorderInfo_Left[0].Size / 2 > Max_l )
                            Max_l = BorderInfo_Left[0].Size / 2;

                        //X0 -= Max_l;
                        LeftMW = -Max_l;

                        if ( border_Single === BorderInfo_Left[0].Value && CurBorderInfo.Size <= BorderInfo_Left[0].Size )
                            LeftMW = BorderInfo_Left[0].Size / 2;

                        LastBorderTop.L = Max_l;
                        LastBorderTop.W = 0;

                        if ( border_Single === CurBorderInfo.Value )
                            LastBorderTop.W = CurBorderInfo.Size;
                    }

                    if ( border_Single === CurBorderInfo.Value )
                    {

                        RGBA =  CurBorderInfo.Get_Color2(Theme, ColorMap);
                        pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                        //pGraphics.p_width( CurBorderInfo.Size * 1000 );
                        //pGraphics._s();
                        if(pGraphics.SetBorder)
                        {
                            pGraphics.SetBorder(CurBorderInfo);
                        }

                        pGraphics.drawHorLineExt( c_oAscLineDrawingRule.Top, Y, X0, X1, CurBorderInfo.Size, LeftMW, RightMW );
                        //pGraphics._m( X0 * 100, ( Y + CurBorderInfo.Size / 2 ) * 100 );
                        //pGraphics._l( X1 * 100, ( Y + CurBorderInfo.Size / 2 ) * 100 );

                        //pGraphics.ds();
                    }
                    else //if ( border_None === CurBorderInfo.Value )
                    {
                        pGraphics.DrawEmptyTableLine( X0 + LeftMW, Y, X1 + RightMW , Y );
                        //pGraphics.DrawEmptyTableLine( X0, Y, X1, Y );
                    }
                }

                // Нижняя граница
                if ( PNum != this.Pages.length - 1 && CurRow + VMergeCount - 1 === Row_last )
                {
                    var X0 = X_cell_start;
                    var X1 = X_cell_end;

                    var LowerCell = this.private_GetCellIndexByStartGridCol( CurRow + VMergeCount - 1, Row.Get_CellInfo( CurCell ).StartGridCol );

                    var BottomBorder = ( -1 === LowerCell ? this.Pages[PNum].BotBorders[0] : this.Pages[PNum].BotBorders[LowerCell] );
                    if ( border_Single === BottomBorder.Value )
                    {

                        RGBA =  BottomBorder.Get_Color2(Theme, ColorMap);
                        pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                        //pGraphics.p_width( BottomBorder.Size * 1000 );
                        //pGraphics._s();
                        if(pGraphics.SetBorder)
                        {
                            pGraphics.SetBorder(BottomBorder);
                        }

                        var X0 = X_cell_start;
                        var X1 = X_cell_end;

                        var LeftMW = 0;
                        if ( BorderInfo_Left.length > 0 && border_Single === BorderInfo_Left[BorderInfo_Left.length - 1].Value )
                            LeftMW = -BorderInfo_Left[BorderInfo_Left.length - 1].Size / 2;

                        var RightMW = 0;
                        if ( BorderInfo_Right.length > 0 && border_Single === BorderInfo_Right[BorderInfo_Right.length - 1].Value )
                            RightMW = +BorderInfo_Right[BorderInfo_Right.length - 1].Size / 2;

                        pGraphics.drawHorLineExt( c_oAscLineDrawingRule.Top, Y + RealHeight, X0, X1, BottomBorder.Size, LeftMW, RightMW );

                        //var X0 = X_cell_start;
                        //var X1 = X_cell_end;

                        //if ( BorderInfo_Left.length > 0 && border_Single === BorderInfo_Left[BorderInfo_Left.length - 1].Value )
                        //    X0 -= BorderInfo_Left[BorderInfo_Left.length - 1].Size / 2;

                        //if ( BorderInfo_Right.length > 0 && border_Single === BorderInfo_Right[BorderInfo_Right.length - 1].Value )
                        //    X1 += BorderInfo_Right[BorderInfo_Right.length - 1].Size / 2;

                        //pGraphics._m( X0 * 100, ( Y + RealHeight + BottomBorder.Size / 2 ) * 100 );
                        //pGraphics._l( X1 * 100, ( Y + RealHeight + BottomBorder.Size / 2 ) * 100 );

                        //pGraphics.ds();
                    }
                    else //if ( border_None === CellBorders.Bottom.Value )
                    {
                        pGraphics.DrawEmptyTableLine( X_cell_start, Y + RealHeight, X_cell_end, Y + RealHeight );
                    }
                }
                else
                {
                    var BorderInfo_Bottom = CellBordersInfo.Bottom;
                    var BorderInfo_Bottom_BeforeCount = CellBordersInfo.Bottom_BeforeCount;
                    var BorderInfo_Bottom_AfterCount  = CellBordersInfo.Bottom_AfterCount;

                    if ( null != BorderInfo_Bottom && BorderInfo_Bottom.length > 0 )
                    {
                        // Значит это последняя строка
                        if ( -1 === BorderInfo_Bottom_BeforeCount && -1 === BorderInfo_Bottom_AfterCount )
                        {
                            var BottomBorder = BorderInfo_Bottom[0];
                            if ( border_Single === BottomBorder.Value )
                            {

                                RGBA =  BottomBorder.Get_Color2(Theme, ColorMap);
                                pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                                //pGraphics.p_width( BottomBorder.Size * 1000 );
                                //pGraphics._s();
                                if(pGraphics.SetBorder)
                                {
                                    pGraphics.SetBorder(BottomBorder);
                                }

                                var X0 = X_cell_start;
                                var X1 = X_cell_end;

                                var LeftMW = 0;
                                if ( BorderInfo_Left.length > 0 && border_Single === BorderInfo_Left[BorderInfo_Left.length - 1].Value )
                                    LeftMW = -BorderInfo_Left[BorderInfo_Left.length - 1].Size / 2;

                                var RightMW = 0;
                                if ( BorderInfo_Right.length > 0 && border_Single === BorderInfo_Right[BorderInfo_Right.length - 1].Value )
                                    RightMW = +BorderInfo_Right[BorderInfo_Right.length - 1].Size / 2;

                                pGraphics.drawHorLineExt( c_oAscLineDrawingRule.Top, Y + RealHeight, X0, X1, BottomBorder.Size, LeftMW, RightMW );

                                //var X0 = X_cell_start;
                                //var X1 = X_cell_end;

                                //if ( BorderInfo_Left.length > 0 && border_Single === BorderInfo_Left[BorderInfo_Left.length - 1].Value )
                                //    X0 -= BorderInfo_Left[BorderInfo_Left.length - 1].Size / 2;

                                //if ( BorderInfo_Right.length > 0 && border_Single === BorderInfo_Right[BorderInfo_Right.length - 1].Value )
                                //    X1 += BorderInfo_Right[BorderInfo_Right.length - 1].Size / 2;

                                //pGraphics._m( X0 * 100, ( Y + RealHeight + BottomBorder.Size / 2 ) * 100 );
                                //pGraphics._l( X1 * 100, ( Y + RealHeight + BottomBorder.Size / 2 ) * 100 );

                                //pGraphics.ds();
                            }
                            else //if ( border_None === CellBorders.Bottom.Value )
                            {
                                pGraphics.DrawEmptyTableLine( X_cell_start, Y + RealHeight, X_cell_end, Y + RealHeight );
                            }
                        }
                        else
                        {
                            for ( var Index = 0; Index < BorderInfo_Bottom_BeforeCount; Index++ )
                            {
                                var BottomBorder = BorderInfo_Bottom[Index];

                                if ( border_Single === BottomBorder.Value )
                                {

                                    RGBA =  BottomBorder.Get_Color2(Theme, ColorMap);
                                    pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                                    if(pGraphics.SetBorder)
                                    {
                                        pGraphics.SetBorder(BottomBorder);
                                    }

                                    pGraphics.p_width( BottomBorder.Size * 1000 );
                                    pGraphics._s();

                                    var X0 = Page.X + this.TableSumGrid[Index + CurGridCol - 1];
                                    var X1 = Page.X + this.TableSumGrid[Index + CurGridCol];

                                    var LeftMW = 0;
                                    if ( 0 === Index && BorderInfo_Left.length > 0 && border_Single === BorderInfo_Left[BorderInfo_Left.length - 1].Value )
                                        LeftMW = -BorderInfo_Left[BorderInfo_Left.length - 1].Size / 2;

                                    pGraphics.drawHorLineExt( c_oAscLineDrawingRule.Top, Y + RealHeight, X0, X1, BottomBorder.Size, LeftMW, 0 );

                                    //var X0 = Page.X + this.TableSumGrid[Index + CurGridCol - 1];
                                    //var X1 = Page.X + this.TableSumGrid[Index + CurGridCol];

                                    //if ( 0 === Index && BorderInfo_Left.length > 0 && border_Single === BorderInfo_Left[BorderInfo_Left.length - 1].Value )
                                    //    X0 -= BorderInfo_Left[BorderInfo_Left.length - 1].Size / 2;

                                    //pGraphics._m( X0 * 100, ( Y + RealHeight + BottomBorder.Size / 2 ) * 100 );
                                    //pGraphics._l( X1 * 100, ( Y + RealHeight + BottomBorder.Size / 2 ) * 100 );

                                    //pGraphics.ds();
                                }
                                else //if ( border_None === CellBorders.Bottom.Value )
                                {
                                    pGraphics.DrawEmptyTableLine( X_cell_start, Y + RealHeight, X_cell_end, Y + RealHeight );
                                }
                            }

                            for ( var Index = 0; Index < BorderInfo_Bottom_AfterCount; Index++ )
                            {
                                var BottomBorder = BorderInfo_Bottom[BorderInfo_Bottom.length - 1 - Index];

                                if ( border_Single === BottomBorder.Value )
                                {
                                    RGBA =  BottomBorder.Get_Color2(Theme, ColorMap);
                                    pGraphics.p_color( RGBA.r, RGBA.g, RGBA.b, 255 );
                                    if(pGraphics.SetBorder)
                                    {
                                        pGraphics.SetBorder(BottomBorder);
                                    }

                                    pGraphics.p_width( BottomBorder.Size * 1000 );
                                    pGraphics._s();

                                    var X0 = Page.X + this.TableSumGrid[CurGridCol + GridSpan - 2 - Index];
                                    var X1 = Page.X + this.TableSumGrid[CurGridCol + GridSpan - 1 - Index];

                                    var RightMW = 0;
                                    if ( 0 === Index && BorderInfo_Right.length > 0 && border_Single === BorderInfo_Right[BorderInfo_Right.length - 1].Value )
                                        RightMW = +BorderInfo_Right[BorderInfo_Right.length - 1].Size / 2;

                                    pGraphics.drawHorLineExt( c_oAscLineDrawingRule.Top, Y + RealHeight, X0, X1, BottomBorder.Size, 0, RightMW );

                                    //var X0 = Page.X + this.TableSumGrid[CurGridCol + GridSpan - 2 - Index];
                                    //var X1 = Page.X + this.TableSumGrid[CurGridCol + GridSpan - 1 - Index];

                                    //if ( 0 === Index && BorderInfo_Right.length > 0 && border_Single === BorderInfo_Right[BorderInfo_Right.length - 1].Value )
                                    //    X1 += BorderInfo_Right[BorderInfo_Right.length - 1].Size / 2;

                                    //pGraphics._m( X0 * 100, ( Y + RealHeight + BottomBorder.Size / 2 ) * 100 );
                                    //pGraphics._l( X1 * 100, ( Y + RealHeight + BottomBorder.Size / 2 ) * 100 );

                                    //pGraphics.ds();
                                }
                                else //if ( border_None === CellBorders.Bottom.Value )
                                {
                                    pGraphics.DrawEmptyTableLine( X_cell_start, Y + RealHeight, X_cell_end, Y + RealHeight );
                                }
                            }
                        }
                    }
                }
            }
        }
    }
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var History = AscCommon.History;

//----------------------------------------------------------------------------------------------------------------------
// Класс CTableRow
//----------------------------------------------------------------------------------------------------------------------
function CTableRow(Table, Cols, TableGrid)
{
    this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.Table = Table; // Родительский класс таблицы

    this.Next = null;
    this.Prev = null;

    this.Content = [];
    for ( var Index = 0; Index < Cols; Index++ )
    {
        var ColW = ( undefined != TableGrid && undefined != TableGrid[Index] ? TableGrid[Index] : undefined );
        this.Content[Index] = new CTableCell( this, ColW );
    }

    this.Internal_ReIndexing();

    // Информация о рассчитанных метриках ячеек
    this.CellsInfo = [];

    // Метрика строки
    this.Metrics =
    {
        X_min : 0,
        X_max : 0
    };

    // Информация о spacing до и после текущей строки
    this.SpacingInfo = { Top : false, Bottom : false };

    this.CompiledPr =
    {
        Pr         : null,
        NeedRecalc : true
    };

    this.Pr = new CTableRowPr();

    // Данные два параметра нужны для контроля кардинальности изменений, которые
    // происходят внутри ячеек данной строки.
    this.Height     = 0;
    this.PagesCount = 1;

    // Добавляем данный класс в список DocumentContent'ов
    if (typeof AscCommon.CollaborativeEditing !== "undefined")
        AscCommon.CollaborativeEditing.Add_NewDC(this);
    this.m_oContentChanges = new AscCommon.CContentChanges(); // список изменений(добавление/удаление элементов)

    this.Index = 0;

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    AscCommon.g_oTableId.Add( this, this.Id );
}

CTableRow.prototype =
{
    Get_Id : function()
    {
        return this.Id;
    },

	// Создаем копию данного объекта
	Copy : function(Table)
	{
		var Row = new CTableRow(Table, 0);

		// Копируем настройки строки
		Row.Set_Pr(this.Pr.Copy());

		// Копируем ячейки
		var CellsCount = this.Content.length;
		for (var Index = 0; Index < CellsCount; Index++)
		{
			Row.Content[Index] = this.Content[Index].Copy(Row);
			History.Add(new CChangesTableRowAddCell(Row, Index, [Row.Content[Index]]));
		}

		Row.Internal_ReIndexing();

		return Row;
	},

    Is_UseInDocument : function(Id)
    {
        var bUse = false;
        if ( null != Id )
        {
            var Count = this.Content.length;
            for ( var Index = 0; Index < Count; Index++ )
            {
                if ( Id === this.Content[Index].Get_Id() )
                {
                    bUse = true;
                    break;
                }
            }
        }
        else
            bUse = true;

        if ( true === bUse && null != this.Table )
            return this.Table.Is_UseInDocument(this.Get_Id());

        return false;
    },

    Set_Index : function(Index)
    {
        if ( Index != this.Index )
        {
            this.Index = Index;
            this.Recalc_CompiledPr();
        }
    },

    Set_Metrics_X : function(x_min, x_max)
    {
        this.Metrics.X_min = x_min;
        this.Metrics.X_max = x_max;
    },

	GetEndInfo : function()
    {
        var CellsCount = this.Content.length;
        if ( CellsCount > 0 )
            return this.Content[CellsCount - 1].GetEndInfo();
        else
            return null;
    },

	GetPrevElementEndInfo : function(CellIndex)
	{
		if (0 === CellIndex)
			return this.Table.GetPrevElementEndInfo(this.Index);
		else
			return this.Content[CellIndex - 1].GetEndInfo();
	},

	SaveRecalculateObject : function()
	{
		var RecalcObj = new CTableRowRecalculateObject();
		RecalcObj.Save(this);
		return RecalcObj;
	},

	LoadRecalculateObject : function(RecalcObj)
    {
        RecalcObj.Load(this);
    },

	PrepareRecalculateObject : function()
	{
		this.CellsInfo   = [];
		this.Metrics     = {X_min : 0, X_max : 0};
		this.SpacingInfo = {Top : false, Bottom : false};

		var Count = this.Content.length;
		for (var Index = 0; Index < Count; Index++)
		{
			this.Content[Index].PrepareRecalculateObject();
		}
	},

    PreDelete : function()
    {
        var CellsCount = this.Get_CellsCount();
        for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
        {
            var Cell = this.Get_Cell( CurCell );

            var CellContent = Cell.Content.Content;
            var ContentCount = CellContent.length;
            for ( var Pos = 0; Pos < ContentCount; Pos++ )
            {
                CellContent[Pos].PreDelete();
            }
        }
    },
    //-----------------------------------------------------------------------------------
    // Работаем с стилем строки
    //-----------------------------------------------------------------------------------
    Recalc_CompiledPr : function()
    {
        this.CompiledPr.NeedRecalc = true;
    },

    // Формируем конечные свойства параграфа на основе стиля и прямых настроек.
    Get_CompiledPr : function(bCopy)
    {
        if ( true === this.CompiledPr.NeedRecalc )
        {
            if (true === AscCommon.g_oIdCounter.m_bLoad || true === AscCommon.g_oIdCounter.m_bRead)
            {
                this.CompiledPr.Pr         = g_oDocumentDefaultTableRowPr;
                this.CompiledPr.NeedRecalc = true;
            }
            else
            {
                this.CompiledPr.Pr         = this.Internal_Compile_Pr();
                this.CompiledPr.NeedRecalc = false;
            }
        }

        if ( false === bCopy )
            return this.CompiledPr.Pr;
        else
            return this.CompiledPr.Pr.Copy(); // Отдаем копию объекта, чтобы никто не поменял извне настройки стиля
    },

    Internal_Compile_Pr : function()
    {
        var TablePr   = this.Table.Get_CompiledPr(false);
        var TableLook = this.Table.Get_TableLook();
        var CurIndex  = this.Index;

        // Сначала возьмем настройки по умолчанию для строки
        var RowPr = TablePr.TableRowPr.Copy();
        if (undefined !== TablePr.TablePr.TableCellSpacing)
            RowPr.TableCellSpacing = TablePr.TablePr.TableCellSpacing;

        // Совместим настройки с настройками для групп строк
        if ( true === TableLook.Is_BandHor() )
        {
            var RowBandSize = TablePr.TablePr.TableStyleRowBandSize;
            var _CurIndex   = ( true != TableLook.Is_FirstRow() ? CurIndex : CurIndex - 1 );
            var GroupIndex = ( 1 != RowBandSize ? Math.floor( _CurIndex / RowBandSize ) : _CurIndex );
            if ( 0 === GroupIndex % 2 )
                RowPr.Merge(TablePr.TableBand1Horz.TableRowPr);
            else
                RowPr.Merge(TablePr.TableBand2Horz.TableRowPr);
        }

        // Совместим настройки с настройками для последней строки
        if ( true === TableLook.Is_LastRow() && this.Table.Content.length - 1 === CurIndex )
        {
            RowPr.Merge(TablePr.TableLastRow.TableRowPr);
        }

        // Совместим настройки с настройками для первой строки
        if ( true === TableLook.Is_FirstRow() && ( 0 === CurIndex || true === this.Pr.TableHeader )  )
        {
            RowPr.Merge(TablePr.TableFirstRow.TableRowPr);
        }

        // Полученные настройки совместим с прямыми настройками
        RowPr.Merge(this.Pr);

        return RowPr;
    },
    //-----------------------------------------------------------------------------------
    // Работаем с настройками строки
    //-----------------------------------------------------------------------------------
    Clear_DirectFormatting : function(bClearMerge)
    {
        // Очищаем все строки и всех ее ячеек
        if (true === bClearMerge)
        {
            this.Set_After(undefined, undefined);
            this.Set_Before(undefined, undefined);
            this.Set_Height(undefined, undefined);
        }

        this.Set_CellSpacing(undefined);

        var Count = this.Content.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            this.Content[Index].Clear_DirectFormatting(bClearMerge);
        }
    },

	Set_Pr : function(RowPr)
	{
		History.Add(new CChangesTableRowPr(this, this.Pr, RowPr));
		this.Pr = RowPr;
		this.Recalc_CompiledPr();
	},

    Get_Before : function()
    {
        var RowPr = this.Get_CompiledPr( false );

		var Before = {
			WBefore    : RowPr.WBefore.Copy(),
			GridBefore : RowPr.GridBefore
		};

        return Before;
    },

	Set_Before : function(GridBefore, WBefore)
	{
		// Если парметр WBefore === false, значит значение WBefore мы не меняем
		if (this.Pr.GridBefore !== GridBefore || this.Pr.WBefore !== WBefore)
		{
			var OldBefore = {
				GridBefore : this.Pr.GridBefore,
				WBefore    : this.Pr.WBefore
			};

			var NewBefore = {
				GridBefore : GridBefore,
				WBefore    : WBefore
			};

			if (false === WBefore)
			{
				NewBefore.WBefore = OldBefore.WBefore;
			}
			else if (undefined != WBefore)
			{
				NewBefore.WBefore = new CTableMeasurement(tblwidth_Auto, 0);
				NewBefore.WBefore.Set_FromObject(WBefore);
			}

			History.Add(new CChangesTableRowBefore(this, OldBefore, NewBefore));

			this.Pr.GridBefore = GridBefore;
			this.Pr.WBefore    = NewBefore.WBefore;
			this.Recalc_CompiledPr();
		}
	},

    Get_After : function()
    {
        var RowPr = this.Get_CompiledPr( false );

		var After = {
			WAfter    : RowPr.WAfter.Copy(),
			GridAfter : RowPr.GridAfter
		};

        return After;
    },

	Set_After : function(GridAfter, WAfter)
	{
		// Если парметр WAfter === false, значит значение WAfter мы не меняем
		if (this.Pr.GridAfter !== GridAfter || this.Pr.WAfter !== WAfter)
		{
			var OldAfter = {
				GridAfter : this.Pr.GridAfter,
				WAfter    : this.Pr.WAfter
			};

			var NewAfter = {
				GridAfter : GridAfter,
				WAfter    : WAfter
			};

			if (false === WAfter)
			{
				NewAfter.WAfter = OldAfter.WAfter;
			}
			else if (undefined != WAfter)
			{
				NewAfter.WAfter = new CTableMeasurement(tblwidth_Auto, 0);
				NewAfter.WAfter.Set_FromObject(WAfter);
			}

			History.Add(new CChangesTableRowAfter(this, OldAfter, NewAfter));

			this.Pr.GridAfter = GridAfter;
			this.Pr.WAfter    = NewAfter.WAfter;
			this.Recalc_CompiledPr();
		}
	},

    Get_CellSpacing : function()
    {
        return this.Get_CompiledPr(false).TableCellSpacing;
    },

	Set_CellSpacing : function(Value)
	{
		if (this.Pr.TableCellSpacing === Value)
			return;

		History.Add(new CChangesTableRowCellSpacing(this, this.Pr.TableCellSpacing, Value));
		this.Pr.TableCellSpacing = Value;

		this.Recalc_CompiledPr();
	},

    Get_Height : function()
    {
        var RowPr = this.Get_CompiledPr( false );
        return RowPr.Height;
    },

	Set_Height : function(Value, HRule)
	{
		if ((undefined === this.Pr.Height && undefined === Value) || (undefined != this.Pr.Height && HRule === this.Pr.Height.HRule && Math.abs(Value - this.Pr.Height.Value) < 0.001))
			return;

		var OldHeight = this.Pr.Height;
		var NewHeight = undefined != Value ? new CTableRowHeight(Value, HRule) : undefined;

		History.Add(new CChangesTableRowHeight(this, OldHeight, NewHeight));
		this.Pr.Height = NewHeight;
		this.Recalc_CompiledPr();
	},

    Copy_Pr : function(OtherPr)
    {
        // Before
        if ( undefined === OtherPr.WBefore )
            this.Set_Before( OtherPr.GridBefore, undefined );
        else
            this.Set_Before( OtherPr.GridBefore, { W : OtherPr.WBefore.W, Type : OtherPr.WBefore.Type } );

        // After
        if ( undefined === OtherPr.WAfter )
            this.Set_After( OtherPr.GridAfter, undefined );
        else
            this.Set_After( OtherPr.GridAfter, { W : OtherPr.WAfter.W, Type : OtherPr.WAfter.Type } );

        // Height
        if ( undefined === OtherPr.Height )
            this.Set_Height( undefined, undefined );
        else
            this.Set_Height( OtherPr.Height.Value, OtherPr.Height.HRule );

        // CellSpacing
        if ( undefined != OtherPr.TableCellSpacing )
            this.Set_CellSpacing( OtherPr.TableCellSpacing );
        else
            this.Set_CellSpacing( undefined );

        // TableHeader
        if ( undefined != OtherPr.TableHeader )
            this.SetHeader( OtherPr.TableHeader );
        else
            this.SetHeader( undefined );
    },

    Set_SpacingInfo : function(bSpacingTop, bSpacingBot)
    {
        this.SpacingInfo =
        {
            Top    : bSpacingTop,
            Bottom : bSpacingBot
        };
    },

    Get_SpacingInfo : function()
    {
        return this.SpacingInfo;
    },

    //-----------------------------------------------------------------------------------
    // Работаем с ячейками строки
    //-----------------------------------------------------------------------------------
    Get_Cell : function(Index)
    {
        if ( Index < 0 || Index >= this.Content.length )
            return null;

        return this.Content[Index];
    },

    Get_CellsCount : function()
    {
        return this.Content.length;
    },

    Set_CellInfo : function(Index,  StartGridCol, X_grid_start, X_grid_end, X_cell_start, X_cell_end, X_content_start, X_content_end)
    {
        this.CellsInfo[Index] =
        {
            StartGridCol    : StartGridCol,
            X_grid_start    : X_grid_start,
            X_grid_end      : X_grid_end,
            X_cell_start    : X_cell_start,
            X_cell_end      : X_cell_end,
            X_content_start : X_content_start,
            X_content_end   : X_content_end
        };
    },

    Update_CellInfo : function(Index)
    {
        var Cell = this.Content[Index];

        var StartGridCol    = Cell.Metrics.StartGridCol;
        var X_grid_start    = Cell.Metrics.X_grid_start;
        var X_grid_end      = Cell.Metrics.X_grid_end;
        var X_cell_start    = Cell.Metrics.X_cell_start;
        var X_cell_end      = Cell.Metrics.X_cell_end;
        var X_content_start = Cell.Metrics.X_content_start;
        var X_content_end   = Cell.Metrics.X_content_end;

        this.Set_CellInfo(Index, StartGridCol, X_grid_start, X_grid_end, X_cell_start, X_cell_end, X_content_start, X_content_end);
    },

    Get_CellInfo : function(Index)
    {
    	if (!this.CellsInfo[Index] || undefined === this.CellsInfo[Index].StartGridCol)
			this.GetTable().private_RecalculateGridCols();

        return this.CellsInfo[Index];
    },

    Get_StartGridCol : function(Index)
    {
        var Max = Math.min( this.Content.length - 1, Index - 1);
        var CurGridCol = this.Get_Before().GridBefore;
        for ( var CurCell = 0; CurCell <= Max; CurCell++ )
        {
            var Cell = this.Get_Cell( CurCell );
            var GridSpan = Cell.Get_GridSpan();

            CurGridCol += GridSpan;
        }

        return CurGridCol;
    },

	Remove_Cell : function(Index)
	{
		History.Add(new CChangesTableRowRemoveCell(this, Index, [this.Content[Index]]));

		this.Content.splice(Index, 1);
		this.CellsInfo.splice(Index, 1);

		this.Internal_ReIndexing(Index);
	},

	Add_Cell : function(Index, Row, Cell, bReIndexing)
	{
		if ("undefined" === typeof(Cell) || null === Cell)
			Cell = new CTableCell(Row);

		History.Add(new CChangesTableRowAddCell(this, Index, [Cell]));

		this.Content.splice(Index, 0, Cell);
		this.CellsInfo.splice(Index, 0, {});

		if (true === bReIndexing)
		{
			this.Internal_ReIndexing(Index);
		}
		else
		{
			if (Index > 0)
			{
				this.Content[Index - 1].Next = Cell;
				Cell.Prev                    = this.Content[Index - 1];
			}
			else
				Cell.Prev = null;

			if (Index < this.Content.length - 1)
			{
				this.Content[Index + 1].Prev = Cell;
				Cell.Next                    = this.Content[Index + 1];
			}
			else
				Cell.Next = null;
		}

		return Cell;
	},

    Clear_ContentChanges : function()
    {
        this.m_oContentChanges.Clear();
    },

    Add_ContentChanges : function(Changes)
    {
        this.m_oContentChanges.Add( Changes );
    },

    Refresh_ContentChanges : function()
    {
        this.m_oContentChanges.Refresh();
    },
    //-----------------------------------------------------------------------------------
    // Внутренние функции
    //-----------------------------------------------------------------------------------
    Internal_ReIndexing : function(StartIndex)
    {
        if ( "undefined" === typeof(StartIndex) )
            StartIndex = 0;

        for ( var Ind = StartIndex; Ind < this.Content.length; Ind++ )
        {
            this.Content[Ind].Set_Index( Ind );
            this.Content[Ind].Prev = ( Ind > 0 ? this.Content[Ind - 1] : null );
            this.Content[Ind].Next = ( Ind < this.Content.length - 1 ? this.Content[Ind + 1] : null );
            this.Content[Ind].Row  = this;
        }
    },

    //-----------------------------------------------------------------------------------
    // Undo/Redo функции
    //-----------------------------------------------------------------------------------
    Get_ParentObject_or_DocumentPos : function()
    {
        return this.Table.Get_ParentObject_or_DocumentPos(this.Table.Index);
    },

    Refresh_RecalcData : function(Data)
    {
        var bNeedRecalc = false;

        var Type = Data.Type;

        switch ( Type )
        {
            case AscDFH.historyitem_TableRow_Before:
            case AscDFH.historyitem_TableRow_After:
            case AscDFH.historyitem_TableRow_CellSpacing:
            case AscDFH.historyitem_TableRow_Height:
            case AscDFH.historyitem_TableRow_AddCell:
            case AscDFH.historyitem_TableRow_RemoveCell:
            case AscDFH.historyitem_TableRow_TableHeader:
            case AscDFH.historyitem_TableRow_Pr:
            {
                bNeedRecalc = true;
                break;
            }
        }

        // Добавляем все ячейки для пересчета
        var CellsCount = this.Get_CellsCount();
        for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
        {
            this.Table.RecalcInfo.Add_Cell( this.Get_Cell(CurCell) );
        }

        this.Table.RecalcInfo.Recalc_Borders();

        if ( true === bNeedRecalc )
            this.Refresh_RecalcData2( 0, 0 );
    },

    Refresh_RecalcData2 : function(CellIndex, Page_rel)
    {
        this.Table.Refresh_RecalcData2( this.Index, Page_rel );
    },
    //-----------------------------------------------------------------------------------
    // Функции для работы с совместным редактирования
    //-----------------------------------------------------------------------------------
    Write_ToBinary2 : function(Writer)
    {
        Writer.WriteLong( AscDFH.historyitem_type_TableRow );

        // String          : Id строки
        // Variable        : свойства строки
        // Long            : количество ячеек
        // Array strings   : Id ячеек

        Writer.WriteString2(this.Id);
        this.Pr.Write_ToBinary( Writer );

        var Count = this.Content.length;
        Writer.WriteLong( Count );
        for ( var Index = 0; Index < Count; Index++ )
            Writer.WriteString2( this.Content[Index].Get_Id() );
    },

    Read_FromBinary2 : function(Reader)
    {
        // String          : Id строки
        // Variable        : свойства строки
        // Long            : количество ячеек
        // Array variables : сами ячейки

        this.Id = Reader.GetString2();
        this.Pr = new CTableRowPr()
        this.Pr.Read_FromBinary( Reader );
        this.Recalc_CompiledPr();

        var Count = Reader.GetLong();
        this.Content = [];
        for ( var Index = 0; Index < Count; Index++ )
        {
            var Cell = AscCommon.g_oTableId.Get_ById( Reader.GetString2() );
            this.Content.push(Cell);
        }

        this.Internal_ReIndexing();

        AscCommon.CollaborativeEditing.Add_NewObject(this);
    },

    Load_LinkData : function(LinkData)
    {
    }
};
/**
 * Доступ к родительской таблице
 * @returns {null | CTable}
 */
CTableRow.prototype.GetTable = function()
{
	return this.Table;
};
/**
 * Получаем номер данной строки в родительской таблице
 * @returns {number}
 */
CTableRow.prototype.GetIndex = function()
{
	return this.Index;
};
CTableRow.prototype.GetDocumentPositionFromObject = function(PosArray)
{
    if (!PosArray)
        PosArray = [];

    if (this.Table)
    {
        PosArray.splice(0, 0, {Class : this.Table, Position : this.Index});
        this.Table.GetDocumentPositionFromObject(PosArray);
    }

    return PosArray;
};
/**
 * Получаем ячейку с заданным номером в строке
 * @param nCellIndex
 * @returns {CTableCell}
 */
CTableRow.prototype.GetCell = function(nCellIndex)
{
	return this.Get_Cell(nCellIndex);
};
CTableRow.prototype.GetCellsCount = function()
{
	return this.Get_CellsCount()
};
CTableRow.prototype.AddCell = function(nIndex, oRow, oCell, isReIndexing)
{
	this.Add_Cell(nIndex, oRow, oCell, isReIndexing);
};
CTableRow.prototype.RemoveCell = function(nIndex)
{
	this.Remove_Cell(nIndex);
};
CTableRow.prototype.GetCellInfo = function(nIndex)
{
	return this.Get_CellInfo(nIndex);
};
CTableRow.prototype.GetCellSpacing = function()
{
	return this.Get_CellSpacing();
};
/**
 * Получаем высоту строки
 * @returns {CTableRowHeight}
 */
CTableRow.prototype.GetHeight = function()
{
	return this.Get_Height();
};
/**
 * Устанавливаем высоту строки
 * @param nValue
 * @param nHRule
 */
CTableRow.prototype.SetHeight = function(nValue, nHRule)
{
	return this.Set_Height(nValue, nHRule);
};
/**
 * Получаем информацию о отступе сетки в начале строки
 * @returns {{W, Grid}}
 */
CTableRow.prototype.GetBefore = function()
{
	var oRowPr = this.Get_CompiledPr(false);

	return {
		W    : oRowPr.WBefore.Copy(),
		Grid : oRowPr.GridBefore
	};
};
/**
 * Задаем информацию об отступе сетки в начале строки
 * @param {number} Grid - сколько колонок занимает отступ
 * @param {CTableMeasurement | 'false'} W - желаемая ширина (если задано значение false, тогда не меняем ширину)
 */
CTableRow.prototype.SetBefore = function(Grid, W)
{
	this.Set_Before(Grid, W);
};
/**
 * Получаем информацию об отступе сетки в конце строки
 * @returns {{W, Grid}}
 */
CTableRow.prototype.GetAfter = function()
{
	var oRowPr = this.Get_CompiledPr(false);

	return {
		W    : oRowPr.WAfter.Copy(),
		Grid : oRowPr.GridAfter
	};
};
/**
 * Задаем информацию об отступе сетки в конце строки
 * @param {number} Grid - сколько колонок занимает отступ
 * @param {CTableMeasurement | 'false'} W - желаемая ширина (если задано значение false, тогда не меняем ширину)
 */
CTableRow.prototype.SetAfter = function(Grid, W)
{
	this.Set_After(Grid, W);
};
/**
 * Получаем общий отступ сверху у строки (максимальный отступ сверху среди всех ячеек)
 * @returns {number}
 */
CTableRow.prototype.GetTopMargin = function()
{
	var nTopMargin = 0;

	for (var nCurCell = 0, nCellsCount = this.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
	{
		var oCell = this.GetCell(nCurCell);

		if (vmerge_Restart != oCell.GetVMerge())
			continue;

		var oMargins = oCell.GetMargins();

		if (oMargins.Top.W > nTopMargin)
			nTopMargin = oMargins.Top.W;
	}

	return nTopMargin;
};
/**
 * Получаем общий отступ снизу у строки (максимальный отступ снизу среди всех ячеек)
 * @returns {number}
 */
CTableRow.prototype.GetBottomMargin = function()
{
	// Ячейки, участвующие в вертикальном объединении, не влияют на отступ снизу

	var nBottomMargin = 0;

	for (var nCurCell = 0, nCellsCount = this.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
	{
		var oCell = this.GetCell(nCurCell);

		if (vmerge_Restart != oCell.GetVMerge())
			continue;

		var nVMergeCount = this.Table.GetVMergeCount(nCurCell, this.Index);
		if (nVMergeCount > 1)
			continue;

		var oMargins = oCell.GetMargins();

		if (oMargins.Bottom.W > nBottomMargin)
			nBottomMargin = oMargins.Bottom.W;
	}

	return nBottomMargin;
};
/**
 * Проверяем является ли данная строка строкой заголовка таблицы
 * @returns {boolean}
 */
CTableRow.prototype.IsHeader = function()
{
	return this.Get_CompiledPr(false).TableHeader;
};
/**
 * Устанавливаем является ли данная строка строкой заголовка таблицы
 * @param isHeader {boolean}
 */
CTableRow.prototype.SetHeader = function(isHeader)
{
	if (isHeader === this.Pr.TableHeader)
		return;

	History.Add(new CChangesTableRowTableHeader(this, this.Pr.TableHeader, isHeader));
	this.Pr.TableHeader = isHeader;
	this.Recalc_CompiledPr();
};




function CTableRowRecalculateObject()
{
    this.CellsInfo   = [];
    this.Metrics     = {};
    this.SpacingInfo = {};

    this.Height      = 0;
    this.PagesCount  = 0;

    this.Content = [];
}

CTableRowRecalculateObject.prototype =
{
    Save : function(Row)
    {
        this.CellsInfo   = Row.CellsInfo;
        this.Metrics     = Row.Metrics;
        this.SpacingInfo = Row.SpacingInfo;

        this.Height      = Row.Height;
        this.PagesCount  = Row.PagesCount;

        var Count = Row.Content.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            this.Content[Index] = Row.Content[Index].SaveRecalculateObject();
        }
    },

    Load : function(Row)
    {
        Row.CellsInfo   = this.CellsInfo;
        Row.Metrics     = this.Metrics;
        Row.SpacingInfo = this.SpacingInfo;

        Row.Height      = this.Height;
        Row.PagesCount  = this.PagesCount;

        var Count = Row.Content.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            Row.Content[Index].LoadRecalculateObject( this.Content[Index] );
        }
    },

    Get_DrawingFlowPos : function(FlowPos)
    {
        var Count = this.Content.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            this.Content[Index].Get_DrawingFlowPos( FlowPos );
        }
    }
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CTableRow = CTableRow;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 07.11.2016
 * Time: 14:21
 */

AscDFH.changesFactory[AscDFH.historyitem_TableRow_Before]      = CChangesTableRowBefore;
AscDFH.changesFactory[AscDFH.historyitem_TableRow_After]       = CChangesTableRowAfter;
AscDFH.changesFactory[AscDFH.historyitem_TableRow_CellSpacing] = CChangesTableRowCellSpacing;
AscDFH.changesFactory[AscDFH.historyitem_TableRow_Height]      = CChangesTableRowHeight;
AscDFH.changesFactory[AscDFH.historyitem_TableRow_AddCell]     = CChangesTableRowAddCell;
AscDFH.changesFactory[AscDFH.historyitem_TableRow_RemoveCell]  = CChangesTableRowRemoveCell;
AscDFH.changesFactory[AscDFH.historyitem_TableRow_TableHeader] = CChangesTableRowTableHeader;
AscDFH.changesFactory[AscDFH.historyitem_TableRow_Pr]          = CChangesTableRowPr;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_TableRow_Before]      = [
	AscDFH.historyitem_TableRow_Before,
	AscDFH.historyitem_TableRow_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableRow_After]       = [
	AscDFH.historyitem_TableRow_After,
	AscDFH.historyitem_TableRow_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableRow_CellSpacing] = [
	AscDFH.historyitem_TableRow_CellSpacing,
	AscDFH.historyitem_TableRow_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableRow_Height]      = [
	AscDFH.historyitem_TableRow_Height,
	AscDFH.historyitem_TableRow_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableRow_AddCell]     = [
	AscDFH.historyitem_TableRow_AddCell,
	AscDFH.historyitem_TableRow_RemoveCell
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableRow_RemoveCell]  = [
	AscDFH.historyitem_TableRow_AddCell,
	AscDFH.historyitem_TableRow_RemoveCell
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableRow_TableHeader] = [
	AscDFH.historyitem_TableRow_TableHeader,
	AscDFH.historyitem_TableRow_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableRow_Pr]          = [
	AscDFH.historyitem_TableRow_Before,
	AscDFH.historyitem_TableRow_After,
	AscDFH.historyitem_TableRow_CellSpacing,
	AscDFH.historyitem_TableRow_Height,
	AscDFH.historyitem_TableRow_TableHeader,
	AscDFH.historyitem_TableRow_Pr
];
/**
 * Общая функция объединения изменений, которые зависят только от себя и AscDFH.historyitem_TableRow_Pr
 * @param oChange
 * @returns {boolean}
 */
function private_TableRowChangesOnMergePr(oChange)
{
	if (oChange.Class !== this.Class)
		return true;

	if (oChange.Type === this.Type || oChange.Type === AscDFH.historyitem_TableRow_Pr)
		return false;

	return true;
}
//----------------------------------------------------------------------------------------------------------------------

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesTableRowBefore(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesTableRowBefore.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesTableRowBefore.prototype.constructor = CChangesTableRowBefore;
CChangesTableRowBefore.prototype.Type = AscDFH.historyitem_TableRow_Before;
CChangesTableRowBefore.prototype.WriteToBinary = function(Writer)
{
	// Long : Flags
	// 1-bit : is New.GridBefore undefined?
	// 2-bit : is New.WBefore undefined?
	// 3-bit : is Old.GridBefore undefined?
	// 4-bit : is Old.WBefore undefined?
	// Long : New.GridBefore
	// CTableMeasurement : New.WBefore
	// Long : Old.GridBefore
	// CTableMeasurement : Old.WBefore

	var nFlags = 0;
	if (undefined === this.New.GridBefore)
		nFlags |= 1;
	if (undefined === this.New.WBefore)
		nFlags |= 2;
	if (undefined === this.Old.GridBefore)
		nFlags |= 4;
	if (undefined === this.Old.WBefore)
		nFlags |= 8;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New.GridBefore)
		Writer.WriteLong(this.New.GridBefore);
	if (undefined !== this.New.WBefore)
		this.New.WBefore.Write_ToBinary(Writer);
	if (undefined !== this.Old.GridBefore)
		Writer.WriteLong(this.Old.GridBefore);
	if (undefined !== this.Old.WBefore)
		this.Old.WBefore.Write_ToBinary(Writer);
};
CChangesTableRowBefore.prototype.ReadFromBinary = function(Reader)
{
	// Long : Flags
	// 1-bit : is New.GridBefore undefined?
	// 2-bit : is New.WBefore undefined?
	// 3-bit : is Old.GridBefore undefined?
	// 4-bit : is Old.WBefore undefined?
	// Long : New.GridBefore
	// CTableMeasurement : New.WBefore
	// Long : Old.GridBefore
	// CTableMeasurement : Old.WBefore

	var nFlags = Reader.GetLong();

	this.New = {
		GridBefore : undefined,
		WBefore    : undefined
	};

	this.Old = {
		GridBefore : undefined,
		WBefore    : undefined
	};

	if (nFlags & 1)
		this.New.GridBefore = undefined;
	else
		this.New.GridBefore = Reader.GetLong();

	if (nFlags & 2)
	{
		this.New.WBefore = undefined;
	}
	else
	{
		this.New.WBefore = new CTableMeasurement(tblwidth_Auto, 0);
		this.New.WBefore.Read_FromBinary(Reader);
	}

	if (nFlags & 4)
		this.Old.GridBefore = undefined;
	else
		this.Old.GridBefore = Reader.GetLong();

	if (nFlags & 8)
	{
		this.Old.WBefore = undefined;
	}
	else
	{
		this.Old.WBefore = new CTableMeasurement(tblwidth_Auto, 0);
		this.Old.WBefore.Read_FromBinary(Reader);
	}
};
CChangesTableRowBefore.prototype.private_SetValue = function(Value)
{
	var oTableRow = this.Class;

	oTableRow.Pr.GridBefore = Value.GridBefore;
	oTableRow.Pr.WBefore    = Value.WBefore;
	oTableRow.Recalc_CompiledPr();
};
CChangesTableRowBefore.prototype.Merge = private_TableRowChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesTableRowAfter(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesTableRowAfter.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesTableRowAfter.prototype.constructor = CChangesTableRowAfter;
CChangesTableRowAfter.prototype.Type = AscDFH.historyitem_TableRow_After;
CChangesTableRowAfter.prototype.WriteToBinary = function(Writer)
{
	// Long : Flags
	// 1-bit : is New.GridAfter undefined?
	// 2-bit : is New.WAfter undefined?
	// 3-bit : is Old.GridAfter undefined?
	// 4-bit : is Old.WAfter undefined?
	// Long : New.GridBefore
	// CTableMeasurement : New.WBefore
	// Long : Old.GridBefore
	// CTableMeasurement : Old.WBefore

	var nFlags = 0;
	if (undefined === this.New.GridAfter)
		nFlags |= 1;
	if (undefined === this.New.WAfter)
		nFlags |= 2;
	if (undefined === this.Old.GridAfter)
		nFlags |= 4;
	if (undefined === this.Old.WAfter)
		nFlags |= 8;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New.GridAfter)
		Writer.WriteLong(this.New.GridAfter);
	if (undefined !== this.New.WAfter)
		this.New.WAfter.Write_ToBinary(Writer);
	if (undefined !== this.Old.GridAfter)
		Writer.WriteLong(this.Old.GridAfter);
	if (undefined !== this.Old.WAfter)
		this.Old.WAfter.Write_ToBinary(Writer);
};
CChangesTableRowAfter.prototype.ReadFromBinary = function(Reader)
{
	// Long : Flags
	// 1-bit : is New.GridAfter undefined?
	// 2-bit : is New.WAfter undefined?
	// 3-bit : is Old.GridAfter undefined?
	// 4-bit : is Old.WAfter undefined?
	// Long : New.GridAfter
	// CTableMeasurement : New.WAfter
	// Long : Old.GridAfter
	// CTableMeasurement : Old.WAfter

	var nFlags = Reader.GetLong();

	this.New = {
		GridAfter : undefined,
		WAfter    : undefined
	};

	this.Old = {
		GridAfter : undefined,
		WAfter    : undefined
	};

	if (nFlags & 1)
		this.New.GridAfter = undefined;
	else
		this.New.GridAfter = Reader.GetLong();

	if (nFlags & 2)
	{
		this.New.WAfter = undefined;
	}
	else
	{
		this.New.WAfter = new CTableMeasurement(tblwidth_Auto, 0);
		this.New.WAfter.Read_FromBinary(Reader);
	}

	if (nFlags & 4)
		this.Old.GridAfter = undefined;
	else
		this.Old.GridAfter = Reader.GetLong();

	if (nFlags & 8)
	{
		this.Old.WAfter = undefined;
	}
	else
	{
		this.Old.WAfter = new CTableMeasurement(tblwidth_Auto, 0);
		this.Old.WAfter.Read_FromBinary(Reader);
	}
};
CChangesTableRowAfter.prototype.private_SetValue = function(Value)
{
	var oTableRow = this.Class;

	oTableRow.Pr.GridAfter = Value.GridAfter;
	oTableRow.Pr.WAfter    = Value.WAfter;
	oTableRow.Recalc_CompiledPr();
};
CChangesTableRowAfter.prototype.Merge = private_TableRowChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesTableRowCellSpacing(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesTableRowCellSpacing.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesTableRowCellSpacing.prototype.constructor = CChangesTableRowCellSpacing;
CChangesTableRowCellSpacing.prototype.Type = AscDFH.historyitem_TableRow_CellSpacing;
CChangesTableRowCellSpacing.prototype.WriteToBinary = function(Writer)
{
	// Long : Flags
	// 1-bit : is New undefined?
	// 2-bit : is New null?
	// 3-bit : is Old undefined?
	// 4-bit : is Old null?
	// Double : New (1,2 bits are clear)
	// Double : Old (3,4 bits are clear)

	var nFlags = 0;
	if (undefined === this.New)
		nFlags |= 1;
	else if (null === this.New)
		nFlags |= 2;

	if (undefined === this.Old)
		nFlags |= 4;
	else if (null === this.Old)
		nFlags |= 8;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New && null !== this.New)
		Writer.WriteDouble(this.New);
	if (undefined !== this.Old && null !== this.Old)
		Writer.WriteDouble(this.Old);
};
CChangesTableRowCellSpacing.prototype.ReadFromBinary = function(Reader)
{
	// Long : Flags
	// 1-bit : is New undefined?
	// 2-bit : is New null?
	// 3-bit : is Old undefined?
	// 4-bit : is Old null?
	// Double : New (1,2 bits are clear)
	// Double : Old (3,4 bits are clear)

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.New = undefined;
	else if (nFlags & 2)
		this.New = null;
	else
		this.New = Reader.GetDouble();

	if (nFlags & 4)
		this.Old = undefined;
	else if (nFlags & 8)
		this.Old = null;
	else
		this.Old = Reader.GetDouble();
};
CChangesTableRowCellSpacing.prototype.private_SetValue = function(Value)
{
	var oTableRow = this.Class;
	oTableRow.Pr.TableCellSpacing = Value;
	oTableRow.Recalc_CompiledPr();
};
CChangesTableRowCellSpacing.prototype.Merge = private_TableRowChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesTableRowHeight(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesTableRowHeight.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesTableRowHeight.prototype.constructor = CChangesTableRowHeight;
CChangesTableRowHeight.prototype.Type = AscDFH.historyitem_TableRow_Height;
CChangesTableRowHeight.prototype.private_CreateObject = function()
{
	return new CTableRowHeight(0, Asc.linerule_Auto);
};
CChangesTableRowHeight.prototype.private_SetValue = function(Value)
{
	var oTable = this.Class;
	oTable.Pr.Height = Value;
	oTable.Recalc_CompiledPr();
};
CChangesTableRowHeight.prototype.Merge = private_TableRowChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesTableRowAddCell(Class, Pos, Cells)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Cells, true);
}
CChangesTableRowAddCell.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesTableRowAddCell.prototype.constructor = CChangesTableRowAddCell;
CChangesTableRowAddCell.prototype.Type = AscDFH.historyitem_TableRow_AddCell;
CChangesTableRowAddCell.prototype.Undo = function()
{
	if (this.Items.length <= 0)
		return;

	var oRow = this.Class;
	oRow.Content[this.Pos].Set_Index(-1);
	oRow.Content.splice(this.Pos, 1);
	oRow.CellsInfo.splice(this.Pos, 1);
	oRow.Internal_ReIndexing(this.Pos);
};
CChangesTableRowAddCell.prototype.Redo = function()
{
	if (this.Items.length <= 0)
		return;

	var oRow = this.Class;
	oRow.Content.splice(this.Pos, 0, this.Items[0]);
	oRow.CellsInfo.splice(this.Pos, 0, {});
	oRow.Internal_ReIndexing(this.Pos);
};
CChangesTableRowAddCell.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesTableRowAddCell.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesTableRowAddCell.prototype.Load = function(Color)
{
	if (this.Items.length <= 0 || this.PosArray.length <= 0)
		return;

	var oRow = this.Class;

	var Pos     = oRow.m_oContentChanges.Check(AscCommon.contentchanges_Add, this.PosArray[0]);
	var Element = this.Items[0];

	if (null != Element)
	{
		oRow.Content.splice(Pos, 0, Element);
		AscCommon.CollaborativeEditing.Update_DocumentPositionsOnAdd(oRow, Pos);
	}

	oRow.Internal_ReIndexing();
};
CChangesTableRowAddCell.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_TableRow_AddCell === oChanges.Type || AscDFH.historyitem_TableRow_RemoveCell === oChanges.Type))
		return true;

	return false;
};
CChangesTableRowAddCell.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesTableRowRemoveCell);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseContentChange}
 */
function CChangesTableRowRemoveCell(Class, Pos, Cells)
{
	AscDFH.CChangesBaseContentChange.call(this, Class, Pos, Cells, false);
}
CChangesTableRowRemoveCell.prototype = Object.create(AscDFH.CChangesBaseContentChange.prototype);
CChangesTableRowRemoveCell.prototype.constructor = CChangesTableRowRemoveCell;
CChangesTableRowRemoveCell.prototype.Type = AscDFH.historyitem_TableRow_RemoveCell;
CChangesTableRowRemoveCell.prototype.Undo = function()
{
	if (this.Items.length <= 0)
		return;

	var oRow = this.Class;
	oRow.Content.splice(this.Pos, 0, this.Items[0]);
	oRow.CellsInfo.splice(this.Pos, 0, {});
	oRow.Internal_ReIndexing(this.Pos);
};
CChangesTableRowRemoveCell.prototype.Redo = function()
{
	if (this.Items.length <= 0)
		return;

	var oRow = this.Class;
	oRow.Content[this.Pos].Set_Index(-1);
	oRow.Content.splice(this.Pos, 1);
	oRow.CellsInfo.splice(this.Pos, 1);
	oRow.Internal_ReIndexing(this.Pos);
};
CChangesTableRowRemoveCell.prototype.private_WriteItem = function(Writer, Item)
{
	Writer.WriteString2(Item.Get_Id());
};
CChangesTableRowRemoveCell.prototype.private_ReadItem = function(Reader)
{
	return AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
CChangesTableRowRemoveCell.prototype.Load = function(Color)
{
	if (this.Items.length <= 0 || this.PosArray.length <= 0)
		return;

	var oRow = this.Class;

	var Pos = oRow.m_oContentChanges.Check(AscCommon.contentchanges_Remove, this.PosArray[0]);
	if (false === Pos)
		return;

	oRow.Content[Pos].Set_Index(-1);
	oRow.Content.splice(Pos, 1);
	AscCommon.CollaborativeEditing.Update_DocumentPositionsOnRemove(oRow, Pos, 1);

	oRow.Internal_ReIndexing();
};
CChangesTableRowRemoveCell.prototype.IsRelated = function(oChanges)
{
	if (this.Class === oChanges.Class && (AscDFH.historyitem_TableRow_AddCell === oChanges.Type || AscDFH.historyitem_TableRow_RemoveCell === oChanges.Type))
		return true;

	return false;
};
CChangesTableRowRemoveCell.prototype.CreateReverseChange = function()
{
	return this.private_CreateReverseChange(CChangesTableRowAddCell);
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesTableRowTableHeader(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesTableRowTableHeader.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesTableRowTableHeader.prototype.constructor = CChangesTableRowTableHeader;
CChangesTableRowTableHeader.prototype.Type = AscDFH.historyitem_TableRow_TableHeader;
CChangesTableRowTableHeader.prototype.private_SetValue = function(Value)
{
	var oRow = this.Class;
	oRow.Pr.TableHeader = Value;
	oRow.Recalc_CompiledPr();
};
CChangesTableRowTableHeader.prototype.Merge = private_TableRowChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectValue}
 */
function CChangesTableRowPr(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectValue.call(this, Class, Old, New, Color);
}
CChangesTableRowPr.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesTableRowPr.prototype.constructor = CChangesTableRowPr;
CChangesTableRowPr.prototype.Type = AscDFH.historyitem_TableRow_Pr;
CChangesTableRowPr.prototype.private_CreateObject = function()
{
	return new CTableRowPr()
};
CChangesTableRowPr.prototype.private_SetValue = function(Value)
{
	var oRow = this.Class;
	oRow.Pr = Value;
	oRow.Recalc_CompiledPr();
};
CChangesTableRowPr.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type)
		return false;

	if (!this.New)
		this.New = new CTableRowPr();

	switch (oChange.Type)
	{
		case AscDFH.historyitem_TableRow_Before:
		{
			this.New.GridBefore = oChange.New.GridBefore;
			this.New.WBefore    = oChange.New.WBefore;
			break;
		}
		case AscDFH.historyitem_TableRow_After:
		{
			this.New.GridAfter = oChange.New.GridAfter;
			this.New.WAfter    = oChange.New.WAfter;
			break;
		}
		case AscDFH.historyitem_TableRow_CellSpacing:
		{
			this.New.TableCellSpacing = oChange.New;
			break;
		}
		case AscDFH.historyitem_TableRow_Height:
		{
			this.New.Height = oChange.New;
			break;
		}
		case AscDFH.historyitem_TableRow_TableHeader:
		{
			this.New.TableHeader = oChange.New;
			break;
		}
	}

	return true;
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var History = AscCommon.History;
var global_MatrixTransformer = AscCommon.global_MatrixTransformer;

//----------------------------------------------------------------------------------------------------------------------
// Класс CTableCell
//----------------------------------------------------------------------------------------------------------------------
function CTableCell(Row, ColW)
{
    this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.Row = Row;

    this.Prev = null;
    this.Next = null;
    this.Content = new CDocumentContent(this, (undefined !== this.Row ? this.Row.Table.DrawingDocument : undefined), 0, 0, 0, 0, false, false, undefined !== this.Row ? this.Row.Table.bPresentation : undefined);
    this.Content.Set_StartPage( ( Row ? this.Row.Table.PageNum : 0 ) );

    this.CompiledPr =
    {
        Pr         : null, // настройки ячейки
        TextPr     : null, // настройки текста
        ParaPr     : null, // настройки параграфа
        NeedRecalc : true
    };
    this.Pr = new CTableCellPr();

    if ( undefined != ColW )
        this.Pr.TableCellW = new CTableMeasurement(tblwidth_Mm, ColW);

    // Массивы с рассчитанными стилями для границ данной ячейки.
    // В каждом элементе лежит массив стилей.
    this.BorderInfo =
    {
        Top    : null,
        Left   : null,
        Right  : null,
        Bottom : null,            // Используется для последней строки таблицы,
        Bottom_BeforeCount : -1,  // когда Spacing = null(у последней строки) или когда в следущей строке
        Bottom_AfterCount  : -1,  // GridBefore и/или GridAfter отлично от 0.
        MaxLeft  : 0,
        MaxRight : 0
    };

    // Метрики данной ячейки(они все относительные, а не абсолютные). Абсолютные хранятся в строке
    this.Metrics =
    {
        StartGridCol    : 0,
        X_grid_start    : 0,
        X_grid_end      : 0,
        X_cell_start    : 0,
        X_cell_end      : 0,
        X_content_start : 0,
        X_content_end   : 0
    };


    this.Temp =
    {
        Y       : 0,
        CurPage : 0,

        X_start : 0,
        Y_start : 0,
        X_end   : 0,
        Y_end   : 0,

        X_cell_start : 0,
        X_cell_end   : 0,
        Y_cell_start : 0,
        Y_cell_end   : 0,

        Y_VAlign_offset : [] // Сдвиг, который нужно сделать из-за VAlign (массив по страницам)
    };

    this.Index = 0;

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    AscCommon.g_oTableId.Add( this, this.Id );
}

CTableCell.prototype =
{
    Get_Id : function()
    {
        return this.Id;
    },

    Get_Theme : function()
    {
        return this.Row.Table.Get_Theme();
    },

    Get_ColorMap: function()
    {
        return this.Row.Table.Get_ColorMap();
    },


    Copy : function(Row)
    {
        var Cell = new CTableCell(Row);

        // Копируем настройки ячейки
        Cell.Copy_Pr( this.Pr.Copy(), false );

        // Копируем содержимое ячейки
        Cell.Content.Copy2( this.Content );

        // Скопируем BorderInfo и метрики, чтобы при копировании строки целиком не надо было их пересчитывать
        Cell.BorderInfo.Top                = this.BorderInfo.Top;
        Cell.BorderInfo.Left               = this.BorderInfo.Left;
        Cell.BorderInfo.Right              = this.BorderInfo.Right;
        Cell.BorderInfo.Bottom             = this.BorderInfo.Bottom;
        Cell.BorderInfo.Bottom_BeforeCount = this.BorderInfo.Bottom_BeforeCount;
        Cell.BorderInfo.Bottom_AfterCount  = this.BorderInfo.Bottom_AfterCount;
        Cell.BorderInfo.MaxLeft            = this.BorderInfo.MaxLeft;
        Cell.BorderInfo.MaxRight           = this.BorderInfo.MaxRight;

        Cell.Metrics.StartGridCol    = this.Metrics.StartGridCol;
        Cell.Metrics.X_grid_start    = this.Metrics.X_grid_start;
        Cell.Metrics.X_grid_end      = this.Metrics.X_grid_end;
        Cell.Metrics.X_cell_start    = this.Metrics.X_cell_start;
        Cell.Metrics.X_cell_end      = this.Metrics.X_cell_end;
        Cell.Metrics.X_content_start = this.Metrics.X_content_start;
        Cell.Metrics.X_content_end   = this.Metrics.X_content_end;

        return Cell;
    },

    Set_Index : function(Index)
    {
        if ( Index != this.Index )
        {
            this.Index = Index;
            this.Recalc_CompiledPr();
        }
    },

    Set_Metrics : function(StartGridCol, X_grid_start, X_grid_end, X_cell_start, X_cell_end, X_content_start, X_content_end )
    {
        this.Metrics.StartGridCol    = StartGridCol;
        this.Metrics.X_grid_start    = X_grid_start;
        this.Metrics.X_grid_end      = X_grid_end;
        this.Metrics.X_cell_start    = X_cell_start;
        this.Metrics.X_cell_end      = X_cell_end;
        this.Metrics.X_content_start = X_content_start;
        this.Metrics.X_content_end   = X_content_end;
    },

	GetEndInfo : function()
    {
        return this.Content.GetEndInfo();
    },

	GetPrevElementEndInfo : function(CurElement)
    {
        return this.Row.GetPrevElementEndInfo( this.Index );
    },

	SaveRecalculateObject : function()
    {
        var RecalcObj = new CTableCellRecalculateObject();
        RecalcObj.Save( this );
        return RecalcObj;
    },

	LoadRecalculateObject : function(RecalcObj)
    {
        RecalcObj.Load(this);
    },

	PrepareRecalculateObject : function()
    {
        this.BorderInfo =
        {
            Top    : null,
            Left   : null,
            Right  : null,
            Bottom : null,            // Используется для последней строки таблицы,
            Bottom_BeforeCount : -1,  // когда Spacing = null(у последней строки) или когда в следущей строке
            Bottom_AfterCount  : -1,  // GridBefore и/или GridAfter отлично от 0.
            MaxLeft  : 0,
            MaxRight : 0
        };

        // Метрики данной ячейки(они все относительные, а не абсолютные). Абсолютные хранятся в строке
        this.Metrics =
        {
            StartGridCol    : 0,
            X_grid_start    : 0,
            X_grid_end      : 0,
            X_cell_start    : 0,
            X_cell_end      : 0,
            X_content_start : 0,
            X_content_end   : 0
        };

        this.Temp =
        {
            Y       : 0,
            CurPage : 0,
            Y_VAlign_offset : [] // Сдвиг, который нужно сделать из-за VAlign (массив по страницам)
        };

        this.Content.PrepareRecalculateObject();
    },
    //-----------------------------------------------------------------------------------
    // Работаем с стилем ячейки
    //-----------------------------------------------------------------------------------
    Recalc_CompiledPr : function()
    {
        this.CompiledPr.NeedRecalc = true;
        this.Content.Recalc_AllParagraphs_CompiledPr();
    },

    // Формируем конечные свойства параграфа на основе стиля и прямых настроек.
    Get_CompiledPr : function(bCopy)
    {
        if ( true === this.CompiledPr.NeedRecalc )
        {
            if (true === AscCommon.g_oIdCounter.m_bLoad || true === AscCommon.g_oIdCounter.m_bRead)
            {
                this.CompiledPr.Pr     = g_oDocumentDefaultTableCellPr;
                this.CompiledPr.ParaPr = g_oDocumentDefaultParaPr;
                this.CompiledPr.TextPr = g_oDocumentDefaultTextPr;
                this.CompiledPr.NeedRecalc = true;
            }
            else
            {
                // TODO: Возможно стоит разделить рассчет стиля для ячейки и для текста
                var FullPr                 = this.Internal_Compile_Pr();
                this.CompiledPr.Pr         = FullPr.CellPr;
                this.CompiledPr.ParaPr     = FullPr.ParaPr;
                this.CompiledPr.TextPr     = FullPr.TextPr;
                this.CompiledPr.NeedRecalc = false;
            }
        }

        if ( false === bCopy )
            return this.CompiledPr.Pr;
        else
            return this.CompiledPr.Pr.Copy(); // Отдаем копию объекта, чтобы никто не поменял извне настройки стиля
    },

    Internal_Compile_Pr : function()
    {
        var Table     = this.Row.Table;
        var TablePr   = Table.Get_CompiledPr(false);
        var TableLook = Table.Get_TableLook();
        var CellIndex = this.Index;
        var RowIndex  = this.Row.Index;

        // Сначала возьмем настройки по умолчанию для всей таблицы
        var CellPr = TablePr.TableCellPr.Copy();
        var ParaPr = TablePr.ParaPr.Copy();
        var TextPr;
        if(!Table.bPresentation)
        {
            TextPr = TablePr.TextPr.Copy();
        }
        else
        {
            TextPr = TablePr.TableWholeTable.TextPr.Copy();
        }

        // Совместим настройки с настройками для групп строк. Сначала группы строк, потом группы колонок.
        if ( true === TableLook.Is_BandHor() )
        {
            var RowBandSize = TablePr.TablePr.TableStyleRowBandSize;
            var __RowIndex  = ( true != TableLook.Is_FirstRow() ? RowIndex : RowIndex - 1 );
            var _RowIndex = ( 1 != RowBandSize ? Math.floor( __RowIndex / RowBandSize ) : __RowIndex );
            var TableBandStyle = null;
            if ( 0 === _RowIndex % 2 )
                TableBandStyle = TablePr.TableBand1Horz;
            else
                TableBandStyle = TablePr.TableBand2Horz;

            CellPr.Merge( TableBandStyle.TableCellPr );
            TextPr.Merge( TableBandStyle.TextPr );
            ParaPr.Merge( TableBandStyle.ParaPr );
        }

		// Совместим с настройками для групп колонок
		// Согласно спецификации DOCX, совмещать надо всегда. Word проверяет наличие первой колонки не только
		// через флаг TableLook.Is_FirstCol(), но и самим наличием непустого стиля для первой колонки.
		if (true === TableLook.Is_BandVer())
		{
			var bFirstCol = false;
			if (true === TableLook.Is_FirstCol())
			{
				var oTableStyle = this.Get_Styles().Get(this.Row.Table.Get_TableStyle());
				if (oTableStyle && styletype_Table === oTableStyle.Get_Type() && oTableStyle.TableFirstCol)
				{
					var oCondStyle = oTableStyle.TableFirstCol;
					if (true !== oCondStyle.TableCellPr.Is_Empty()
						|| true !== oCondStyle.ParaPr.Is_Empty()
						|| true !== oCondStyle.TextPr.Is_Empty())
					{
						bFirstCol = true;
					}
				}
			}

			var ColBandSize    = TablePr.TablePr.TableStyleColBandSize;
			var _ColIndex      = ( true != bFirstCol ? CellIndex : CellIndex - 1 );
			var ColIndex       = ( 1 != ColBandSize ? Math.floor(_ColIndex / ColBandSize) : _ColIndex );
			var TableBandStyle = null;
			if (0 === ColIndex % 2)
				TableBandStyle = TablePr.TableBand1Vert;
			else
				TableBandStyle = TablePr.TableBand2Vert;

			CellPr.Merge(TableBandStyle.TableCellPr);
			TextPr.Merge(TableBandStyle.TextPr);
			ParaPr.Merge(TableBandStyle.ParaPr);
		}


        // Совместим настройки с настройками для последней колонки
        if ( true === TableLook.Is_LastCol() && this.Row.Get_CellsCount() - 1 === CellIndex )
        {
            CellPr.Merge( TablePr.TableLastCol.TableCellPr );
            TextPr.Merge( TablePr.TableLastCol.TextPr );
            ParaPr.Merge( TablePr.TableLastCol.ParaPr );
        }

        // Совместим настройки с настройками для первой колонки
        if ( true === TableLook.Is_FirstCol() && 0 === CellIndex )
        {
            CellPr.Merge( TablePr.TableFirstCol.TableCellPr );
            TextPr.Merge( TablePr.TableFirstCol.TextPr );
            ParaPr.Merge( TablePr.TableFirstCol.ParaPr );
        }

        // Совместим настройки с настройками для последней строки
        if ( true === TableLook.Is_LastRow() && Table.Content.length - 1 === RowIndex )
        {
            CellPr.Merge( TablePr.TableLastRow.TableCellPr );
            TextPr.Merge( TablePr.TableLastRow.TextPr );
            ParaPr.Merge( TablePr.TableLastRow.ParaPr );
        }

        // Совместим настройки с настройками для первой строки
        if ( true === TableLook.Is_FirstRow() && ( 0 === RowIndex || true === this.Row.Pr.TableHeader )  )
        {
            CellPr.Merge( TablePr.TableFirstRow.TableCellPr );
            TextPr.Merge( TablePr.TableFirstRow.TextPr );
            ParaPr.Merge( TablePr.TableFirstRow.ParaPr );
        }

        // Совместим настройки с настройками для правой нижней ячейки
        if ( this.Row.Get_CellsCount() - 1 === CellIndex && Table.Content.length - 1 === RowIndex && (!Table.bPresentation || true === TableLook.Is_LastRow() && true === TableLook.Is_LastCol()))
        {
            CellPr.Merge( TablePr.TableBRCell.TableCellPr );
            TextPr.Merge( TablePr.TableBRCell.TextPr );
            ParaPr.Merge( TablePr.TableBRCell.ParaPr );
        }

        // Совместим настройки с настройками для левой нижней ячейки
        if ( 0 === CellIndex && Table.Content.length - 1 === RowIndex && (!Table.bPresentation || true === TableLook.Is_LastRow() && true === TableLook.Is_FirstCol()))
        {
            CellPr.Merge( TablePr.TableBLCell.TableCellPr );
            TextPr.Merge( TablePr.TableBLCell.TextPr );
            ParaPr.Merge( TablePr.TableBLCell.ParaPr );
        }

        // Совместим настройки с настройками для правой верхней ячейки
        if ( this.Row.Get_CellsCount() - 1 === CellIndex && 0 === RowIndex && (!Table.bPresentation || true === TableLook.Is_FirstRow() && true === TableLook.Is_LastCol()) )
        {
            CellPr.Merge( TablePr.TableTRCell.TableCellPr );
            TextPr.Merge( TablePr.TableTRCell.TextPr );
            ParaPr.Merge( TablePr.TableTRCell.ParaPr );
        }

        // Совместим настройки с настройками для левой верхней ячейки
        if ( 0 === CellIndex && 0 === RowIndex && (!Table.bPresentation || true === TableLook.Is_FirstRow() && true === TableLook.Is_FirstCol()))
        {
            CellPr.Merge( TablePr.TableTLCell.TableCellPr );
            TextPr.Merge( TablePr.TableTLCell.TextPr );
            ParaPr.Merge( TablePr.TableTLCell.ParaPr );
        }

        if ( null === CellPr.TableCellMar && undefined != this.Pr.TableCellMar && null != this.Pr.TableCellMar )
            CellPr.TableCellMar = {};
        // Полученные настройки совместим с прямыми настройками ячейки
        CellPr.Merge( this.Pr );

        if(Table.bPresentation)
        {
            CellPr.Check_PresentationPr(Table.Get_Theme())
        }

        return { CellPr : CellPr, ParaPr : ParaPr, TextPr : TextPr };
    },

    //-----------------------------------------------------------------------------------
    // Функции, к которым идет обращение из контента
    //-----------------------------------------------------------------------------------
    OnContentRecalculate : function(bChange, bForceRecalc)
    {
        this.Row.Table.Internal_RecalculateFrom( this.Row.Index, this.Index, bChange, false );
    },

    OnContentReDraw : function(StartPage, EndPage)
    {
        this.Row.Table.Parent.OnContentReDraw( StartPage, EndPage );
    },

    Get_Styles : function(Lvl)
    {
        return this.Row.Table.Get_Styles(Lvl);
    },

    Get_TableStyleForPara : function()
    {
        this.Get_CompiledPr(false);

        var TextPr = this.CompiledPr.TextPr.Copy();
        var ParaPr = this.CompiledPr.ParaPr.Copy();

        return { TextPr : TextPr, ParaPr : ParaPr };
    },


    Get_ShapeStyleForPara: function()
    {
        return this.Row.Table.Get_ShapeStyleForPara();
    },


    Get_TextBackGroundColor : function()
    {
        // Сначала проверим заливку данной ячейки, если ее нет, тогда спрашиваем у таблицы
        var Shd = this.Get_Shd();

        if ( Asc.c_oAscShdNil !== Shd.Value )
            return Shd.Get_Color2(this.Get_Theme(), this.Get_ColorMap());

        return this.Row.Table.Get_TextBackGroundColor();
    },

    Get_Numbering : function()
    {
        return this.Row.Table.Get_Numbering();
    },

    IsCell : function(isReturnCell)
    {
    	if (true === isReturnCell)
    		return this;

    	return true;
    },

	IsTableFirstRowOnNewPage : function()
    {
        return this.Row.Table.IsTableFirstRowOnNewPage(this.Row.Index);
    },

    Check_AutoFit : function()
    {
        return false;
    },

    Is_DrawingShape : function(bRetShape)
    {
        return this.Row.Table.Parent.Is_DrawingShape(bRetShape);
    },

    IsHdrFtr : function(bReturnHdrFtr)
	{
		return this.Row.Table.Parent.IsHdrFtr(bReturnHdrFtr);
	},

	IsFootnote : function(bReturnFootnote)
	{
		return this.Row.Table.Parent.IsFootnote(bReturnFootnote);
	},

    Is_TopDocument : function(bReturnTopDocument)
    {
        if ( true === bReturnTopDocument )
            return this.Row.Table.Parent.Is_TopDocument( bReturnTopDocument );

        return false;
    },

    Is_InTable : function(bReturnTopTable)
    {
        if ( true === bReturnTopTable )
        {
            var CurTable = this.Row.Table;
            var TopTable = CurTable.Parent.Is_InTable(true);
            if ( null === TopTable )
                return CurTable;
            else
                return TopTable;
        }

        return true;
    },

    Is_UseInDocument : function(Id)
    {
        if ( null != this.Row )
            return this.Row.Is_UseInDocument(this.Get_Id());

        return false;
    },

    Get_PageContentStartPos : function(PageNum)
    {
        return this.Row.Table.Get_PageContentStartPos(PageNum + this.Content.StartPage, this.Row.Index, this.Index, true );
    },

    Set_CurrentElement : function(bUpdateStates)
    {
        var Table = this.Row.Table;

        // Делаем данную ячейку текущей в таблице
        Table.Selection.Start = false;
        Table.Selection.Type  = table_Selection_Text;
        Table.Selection.Use   = this.Content.IsSelectionUse();

        Table.Selection.StartPos.Pos = { Row : this.Row.Index, Cell : this.Index };
        Table.Selection.EndPos.Pos   = { Row : this.Row.Index, Cell : this.Index };

        Table.Markup.Internal.RowIndex  = 0;
        Table.Markup.Internal.CellIndex = 0;
        Table.Markup.Internal.PageNum   = 0;

        Table.CurCell = this;

        // Делаем таблицу текущим элементом в документе
        Table.Document_SetThisElementCurrent(bUpdateStates);
    },

    Is_ThisElementCurrent : function()
    {
        var Table = this.Row.Table;
        if ( false === Table.Selection.Use && this === Table.CurCell )
        {
            var Parent = Table.Parent;
            if ((Parent instanceof AscFormat.CGraphicFrame) || docpostype_Content === Parent.Get_DocPosType() && false === Parent.Selection.Use && this.Index === Parent.CurPos.ContentPos )
                return Table.Parent.Is_ThisElementCurrent();
        }

        return false;
    },

	CheckTableCoincidence : function(Table)
	{
		var CurTable = this.Row.Table;
		if (Table === CurTable)
			return true;
		else
			return CurTable.Parent.CheckTableCoincidence(Table);
	},
    //-----------------------------------------------------------------------------------
    // Функции для работы с номерами страниц
    //-----------------------------------------------------------------------------------
    Get_StartPage_Absolute : function()
    {
        return this.Row.Table.Get_StartPage_Absolute();
    },

    Get_StartPage_Relative : function()
    {
        return this.Row.Table.Get_StartPage_Relative();
    },

    Get_AbsolutePage : function(CurPage)
    {
        return this.Row.Table.Get_AbsolutePage(CurPage);
    },

    Get_AbsoluteColumn : function(CurPage)
    {
        return this.Row.Table.Get_AbsoluteColumn(CurPage);
    },
    //-----------------------------------------------------------------------------------
    // Работаем с содержимым ячейки
    //-----------------------------------------------------------------------------------

    Get_ParentTextTransform: function()
    {
        var oParentTransform = this.Row.Table.Get_ParentTextTransform();
        var oOwnTransform = this.private_GetTextDirectionTransform();
        if(oOwnTransform && oParentTransform)
        {
            global_MatrixTransformer.MultiplyAppend(oOwnTransform, oParentTransform);
            return oOwnTransform;
        }
        return oParentTransform || oOwnTransform;
    },

    Content_Reset : function(X, Y, XLimit, YLimit)
    {
        this.Content.Reset( X, Y, XLimit, YLimit );
        this.Content.SetCurPosXY( X, Y );
    },

    Content_Get_PageBounds : function(PageIndex)
    {
        return this.Content.Get_PageBounds(PageIndex);
    },

    Content_Get_PagesCount : function()
    {
        return this.Content.Get_PagesCount();
    },

    Content_Draw : function(PageIndex, pGraphics)
    {
        var TextDirection = this.Get_TextDirection();
        var bNeedRestore = false;
        var _transform = undefined;
        if (textdirection_BTLR === TextDirection || textdirection_TBRL === TextDirection)
        {
            bNeedRestore = true;
            pGraphics.SaveGrState();
            pGraphics.AddClipRect(this.Temp.X_cell_start, this.Temp.Y_cell_start, this.Temp.X_cell_end - this.Temp.X_cell_start, this.Temp.Y_cell_end - this.Temp.Y_cell_start);

            _transform = this.Get_ParentTextTransform();
            if (pGraphics.CheckUseFonts2 !== undefined)
                pGraphics.CheckUseFonts2(_transform);
            pGraphics.transform3(_transform);
        }

        this.Content.Draw(PageIndex, pGraphics);
        if (bNeedRestore)
        {
            pGraphics.RestoreGrState();
            if (pGraphics.UncheckUseFonts2 !== undefined && _transform)
                pGraphics.UncheckUseFonts2(_transform);
        }
    },

    Content_Selection_SetStart : function(X, Y, CurPage, MouseEvent)
    {
        var _X = X, _Y = Y;
        var Transform = this.private_GetTextDirectionTransform();
        if (null !== Transform)
        {
            Transform = global_MatrixTransformer.Invert(Transform);
            _X = Transform.TransformPointX(X, Y);
            _Y = Transform.TransformPointY(X, Y);
        }

        this.Content.Selection_SetStart(_X, _Y, CurPage, MouseEvent);
    },

    Content_Selection_SetEnd : function(X, Y, CurPage, MouseEvent)
    {
        var _X = X, _Y = Y;
        var Transform = this.private_GetTextDirectionTransform();
        if (null !== Transform)
        {
            Transform = global_MatrixTransformer.Invert(Transform);
            _X = Transform.TransformPointX(X, Y);
            _Y = Transform.TransformPointY(X, Y);
        }

        this.Content.Selection_SetEnd(_X, _Y, CurPage, MouseEvent);
    },

    Content_Selection_Stop : function()
    {
        return this.Content.Selection_Stop();
    },

    Content_CheckPosInSelection : function(X, Y, CurPage, NearPos)
    {
        var _X = X, _Y = Y;
        var Transform = this.private_GetTextDirectionTransform();
        if (null !== Transform)
        {
            Transform = global_MatrixTransformer.Invert(Transform);
            _X = Transform.TransformPointX(X, Y);
            _Y = Transform.TransformPointY(X, Y);
        }
        return this.Content.CheckPosInSelection(_X, _Y, CurPage, NearPos);
    },

    Content_MoveCursorToXY : function(X, Y, bLine, bDontChangeRealPos, CurPage)
    {
        var _X = X, _Y = Y;
        var Transform = this.private_GetTextDirectionTransform();
        if (null !== Transform)
        {
            Transform = global_MatrixTransformer.Invert(Transform);
            _X = Transform.TransformPointX(X, Y);
            _Y = Transform.TransformPointY(X, Y);
        }

        this.Content.MoveCursorToXY(_X, _Y, bLine, bDontChangeRealPos, CurPage);
    },

    Content_UpdateCursorType : function(X, Y, CurPage)
    {
        var _X = X, _Y = Y;
        var Transform = this.private_GetTextDirectionTransform();
        if (null !== Transform)
        {
            Transform = global_MatrixTransformer.Invert(Transform);
            _X = Transform.TransformPointX(X, Y);
            _Y = Transform.TransformPointY(X, Y);
        }

        this.Content.UpdateCursorType(_X, _Y, CurPage);
    },

	Content_DrawSelectionOnPage : function(CurPage)
	{
		var Transform       = this.private_GetTextDirectionTransform();
		var DrawingDocument = this.Row.Table.DrawingDocument;
		if (null !== Transform && DrawingDocument)
			DrawingDocument.MultiplyTargetTransform(Transform);

		this.Content.DrawSelectionOnPage(CurPage);
	},

    Content_RecalculateCurPos : function(bUpdateX, bUpdateY)
    {
        var Transform = this.private_GetTextDirectionTransform();
        var DrawingDocument = this.Row.Table.DrawingDocument;
        if (null !== Transform && DrawingDocument)
            DrawingDocument.MultiplyTargetTransform(Transform);

        return this.Content.RecalculateCurPos(bUpdateX, bUpdateY);
    },

    Content_Get_NearestPos : function(CurPage, X, Y, bAnchor, Drawing)
    {
        var _X = X, _Y = Y;
        var Transform = this.private_GetTextDirectionTransform();
        if (null !== Transform)
        {
            Transform = global_MatrixTransformer.Invert(Transform);
            _X = Transform.TransformPointX(X, Y);
            _Y = Transform.TransformPointY(X, Y);
        }

        return this.Content.Get_NearestPos(CurPage, _X, _Y, bAnchor, Drawing);
    },

    Content_Is_TableBorder : function(X, Y, CurPage)
    {
        var _X = X, _Y = Y;
        var Transform = this.private_GetTextDirectionTransform();
        if (null !== Transform)
        {
            Transform = global_MatrixTransformer.Invert(Transform);
            _X = Transform.TransformPointX(X, Y);
            _Y = Transform.TransformPointY(X, Y);
        }
        return this.Content.IsTableBorder(_X, _Y, CurPage);
    },

    Content_Is_InText : function(X, Y, CurPage)
    {
        var _X = X, _Y = Y;
        var Transform = this.private_GetTextDirectionTransform();
        if (null !== Transform)
        {
            Transform = global_MatrixTransformer.Invert(Transform);
            _X = Transform.TransformPointX(X, Y);
            _Y = Transform.TransformPointY(X, Y);
        }
        return this.Content.IsInText(_X, _Y, CurPage);
    },

    Content_Is_InDrawing : function(X, Y, CurPage)
    {
        var _X = X, _Y = Y;
        var Transform = this.private_GetTextDirectionTransform();
        if (null !== Transform)
        {
            Transform = global_MatrixTransformer.Invert(Transform);
            _X = Transform.TransformPointX(X, Y);
            _Y = Transform.TransformPointY(X, Y);
        }
        return this.Content.IsInDrawing(_X, _Y, CurPage);
    },

    Content_GetCurPosXY : function()
    {
        return this.Content.GetCurPosXY();
    },

    Content_SetCurPosXY : function(X, Y)
    {
        var _X = X, _Y = Y;
        var Transform = this.private_GetTextDirectionTransform();
        if (null !== Transform)
        {
            Transform = global_MatrixTransformer.Invert(Transform);
            _X = Transform.TransformPointX(X, Y);
            _Y = Transform.TransformPointY(X, Y);
        }
        return this.Content.SetCurPosXY(_X, _Y);
    },

    Content_MoveCursorUpToLastRow : function(X, Y, AddToSelect)
    {
        var _X = X, _Y = Y;
        var Transform = this.private_GetTextDirectionTransform();
        if (null !== Transform)
        {
            Transform = global_MatrixTransformer.Invert(Transform);
            _X = Transform.TransformPointX(X, Y);
            _Y = Transform.TransformPointY(X, Y);
        }
        return this.Content.MoveCursorUpToLastRow(_X, _Y, AddToSelect);
    },

    Content_MoveCursorDownToFirstRow : function(X, Y, AddToSelect)
    {
        var _X = X, _Y = Y;
        var Transform = this.private_GetTextDirectionTransform();
        if (null !== Transform)
        {
            Transform = global_MatrixTransformer.Invert(Transform);
            _X = Transform.TransformPointX(X, Y);
            _Y = Transform.TransformPointY(X, Y);
        }
        return this.Content.MoveCursorDownToFirstRow(_X, _Y, AddToSelect);
    },

    Content_RecalculateMinMaxContentWidth : function(isRotated)
    {
        if (undefined === isRotated)
            isRotated = false;

        if (true === this.Is_VerticalText())
            isRotated = true === isRotated ? false : true;

        var Result = this.Content.RecalculateMinMaxContentWidth(isRotated);

        if (true !== isRotated && true === this.Get_NoWrap())
            Result.Min = Math.max(Result.Min, Result.Max);

        return Result;
    },

    Content_Shift : function(CurPage, dX, dY)
    {
        if (true === this.Is_VerticalText())
        {
            this.Temp.X_start += dX;
            this.Temp.Y_start += dY;
            this.Temp.X_end   += dX;
            this.Temp.Y_end   += dY;

            this.Temp.X_cell_start += dX;
            this.Temp.Y_cell_start += dY;
            this.Temp.X_cell_end   += dX;
            this.Temp.Y_cell_end   += dY;

            this.Temp.Y += dY;
        }
        else
        {
            this.Content.Shift(CurPage, dX, dY);
        }
    },

    private_GetTextDirectionTransform : function()
    {
        var Transform = null;
        var TextDirection = this.Get_TextDirection();

        if (textdirection_BTLR === TextDirection)
        {
            Transform = new AscCommon.CMatrix();
            global_MatrixTransformer.RotateRadAppend(Transform, 0.5 *  Math.PI);
            global_MatrixTransformer.TranslateAppend(Transform, this.Temp.X_start, this.Temp.Y_end);
        }
        else if (textdirection_TBRL === TextDirection)
        {
            var Transform = new AscCommon.CMatrix();
            global_MatrixTransformer.RotateRadAppend(Transform, -0.5 *  Math.PI);
            global_MatrixTransformer.TranslateAppend(Transform, this.Temp.X_end, this.Temp.Y_start);
        }

        return Transform;
    },

    Recalculate : function()
    {
        this.Content.Recalculate(false);
    },

    Content_Merge : function(OtherContent)
    {
        this.Content.Add_Content( OtherContent );
    },

    Content_Is_ContentOnFirstPage : function()
    {
        return this.Content.IsContentOnFirstPage();
    },

    Content_Set_StartPage : function(PageNum)
    {
        this.Content.Set_StartPage(PageNum);
    },

    Content_Document_CreateFontMap : function(FontMap)
    {
        this.Content.Document_CreateFontMap( FontMap );
    },

    Content_MoveCursorToStartPos : function()
    {
        this.Content.MoveCursorToStartPos();
    },

    Content_MoveCursorToEndPos : function()
    {
        this.Content.MoveCursorToEndPos();
    },
    //-----------------------------------------------------------------------------------
    // Работаем с настройками ячейки
    //-----------------------------------------------------------------------------------
    Clear_DirectFormatting : function(bClearMerge)
    {
        // Очищаем все строки и всех ее ячеек

        this.Set_Shd( undefined );
        this.Set_Margins( undefined );
        this.Set_Border( undefined, 0 );
        this.Set_Border( undefined, 1 );
        this.Set_Border( undefined, 2 );
        this.Set_Border( undefined, 3 );

        if ( true === bClearMerge )
        {
            this.Set_GridSpan( undefined );
            this.SetVMerge( undefined );
        }
    },

	Set_Pr : function(CellPr)
	{
		History.Add(new CChangesTableCellPr(this, this.Pr, CellPr));
		this.Pr = CellPr;
		this.Recalc_CompiledPr();
	},

    Copy_Pr : function(OtherPr, bCopyOnlyVisualProps)
    {
        if ( true != bCopyOnlyVisualProps )
        {
            // GridSpan
            if ( undefined === OtherPr.GridSpan )
                this.Set_GridSpan( undefined );
            else
                this.Set_GridSpan( OtherPr.GridSpan );
        }

        // Shd
        if ( undefined === OtherPr.Shd )
            this.Set_Shd( undefined );
        else
        {
            var Shd_new =
                {
                    Value : OtherPr.Shd.Value,
                    Color : { r : OtherPr.Shd.Color.r, g : OtherPr.Shd.Color.g, b : OtherPr.Shd.Color.b },
                    Unifill : OtherPr.Shd.Unifill ? OtherPr.Shd.Unifill.createDuplicate() : undefined
                };

            this.Set_Shd( Shd_new );
        }

        if ( true != bCopyOnlyVisualProps )
        {
            // VMerge
            this.SetVMerge(OtherPr.VMerge);
        }

        // Border Top
        if ( undefined === OtherPr.TableCellBorders.Top )
            this.Set_Border( undefined, 0 );
        else
        {
            var Border_top_new = ( null === OtherPr.TableCellBorders.Top ? null : OtherPr.TableCellBorders.Top.Copy() );

            this.Set_Border( Border_top_new, 0 );
        }

        // Border bottom
        if ( undefined === OtherPr.TableCellBorders.Bottom )
            this.Set_Border( undefined, 2 );
        else
        {
            var Border_bottom_new = ( null === OtherPr.TableCellBorders.Bottom ? null : OtherPr.TableCellBorders.Bottom.Copy() );

            this.Set_Border( Border_bottom_new, 2 );
        }

        // Border left
        if ( undefined === OtherPr.TableCellBorders.Left )
            this.Set_Border( undefined, 3 );
        else
        {
            var Border_left_new = ( null === OtherPr.TableCellBorders.Left ? null : OtherPr.TableCellBorders.Left.Copy() );

            this.Set_Border( Border_left_new, 3 );
        }

        // Border right
        if ( undefined === OtherPr.TableCellBorders.Right )
            this.Set_Border( undefined, 1 );
        else
        {
            var Border_right_new = ( null === OtherPr.TableCellBorders.Right ? null : OtherPr.TableCellBorders.Right.Copy() );

            this.Set_Border( Border_right_new, 1 );
        }

        // Margins
        if (!OtherPr.TableCellMar)
		{
			this.Set_Margins(undefined);
		}
        else
        {
        	var oMarginsNew = {};

        	if (OtherPr.TableCellMar.Top)
			{
				oMarginsNew.Top = {
					W    : OtherPr.TableCellMar.Top.W,
					Type : OtherPr.TableCellMar.Top.Type
				};
			}

			if (OtherPr.TableCellMar.Left)
			{
				oMarginsNew.Left = {
					W    : OtherPr.TableCellMar.Left.W,
					Type : OtherPr.TableCellMar.Left.Type
				};
			}

			if (OtherPr.TableCellMar.Bottom)
			{
				oMarginsNew.Bottom = {
					W    : OtherPr.TableCellMar.Bottom.W,
					Type : OtherPr.TableCellMar.Bottom.Type
				};
			}

			if (OtherPr.TableCellMar.Right)
			{
				oMarginsNew.Right = {
					W    : OtherPr.TableCellMar.Right.W,
					Type : OtherPr.TableCellMar.Right.Type
				};
			}

            this.Set_Margins(oMarginsNew, -1);
        }

        // W
        if ( undefined === OtherPr.TableCellW )
            this.Set_W( undefined );
        else
            this.Set_W( OtherPr.TableCellW.Copy() );

        // VAlign
        this.Set_VAlign(OtherPr.VAlign);

        // TextDirection
        this.Set_TextDirection(OtherPr.TextDirection);

        // NoWrap
        this.Set_NoWrap(OtherPr.NoWrap);
    },

    Get_W : function()
    {
        var W = this.Get_CompiledPr(false).TableCellW;
        return W.Copy();
    },

	Set_W : function(CellW)
	{
		History.Add(new CChangesTableCellW(this, this.Pr.TableCellW, CellW));
		this.Pr.TableCellW = CellW;
		this.Recalc_CompiledPr();
	},

    Get_GridSpan : function()
    {
        var GridSpan = this.Get_CompiledPr(false).GridSpan;
        return GridSpan;
    },

	Set_GridSpan : function(Value)
	{
		if (this.Pr.GridSpan === Value)
			return;

		History.Add(new CChangesTableCellGridSpan(this, this.Pr.GridSpan, Value));
		this.Pr.GridSpan = Value;
		this.Recalc_CompiledPr();
	},

	GetMargins : function()
	{
		var TableCellMar = this.Get_CompiledPr(false).TableCellMar;

		if (null === TableCellMar)
		{
			return this.Row.Table.Get_TableCellMar();
		}
		else
		{
			var TableCellDefMargins = this.Row.Table.Get_TableCellMar();

			var Margins = {
				Top    : undefined != TableCellMar.Top ? TableCellMar.Top : TableCellDefMargins.Top,
				Bottom : undefined != TableCellMar.Bottom ? TableCellMar.Bottom : TableCellDefMargins.Bottom,
				Left   : undefined != TableCellMar.Left ? TableCellMar.Left : TableCellDefMargins.Left,
				Right  : undefined != TableCellMar.Right ? TableCellMar.Right : TableCellDefMargins.Right
			};

			return Margins;
		}
	},

    Is_TableMargins : function()
    {
        var TableCellMar = this.Get_CompiledPr(false).TableCellMar;

        if ( null === TableCellMar )
            return true;
        else
            return false;
    },

	Set_Margins : function(Margin, Type)
	{
		var OldValue = ( undefined === this.Pr.TableCellMar ? undefined : this.Pr.TableCellMar );

		if (undefined === Margin || null === Margin)
		{
			if (Margin !== this.Pr.TableCellMar)
			{
				History.Add(new CChangesTableCellMargins(this, OldValue, Margin));
				this.Pr.TableCellMar = undefined;
				this.Recalc_CompiledPr();
			}

			return;
		}

		var Margins_new = this.Pr.TableCellMar;

		var bNeedChange  = false;
		var TableMargins = this.Row.Table.Get_TableCellMar();
		if (null === Margins_new || undefined === Margins_new)
		{
			Margins_new = {
				Left   : TableMargins.Left.Copy(),
				Right  : TableMargins.Right.Copy(),
				Top    : TableMargins.Top.Copy(),
				Bottom : TableMargins.Bottom.Copy()
			};

			bNeedChange = true;
		}

		switch (Type)
		{
			case -1 :
			{
				bNeedChange = true;

				if (Margin.Top)
				{
					Margins_new.Top.W    = Margin.Top.W;
					Margins_new.Top.Type = Margin.Top.Type;
				}

				if (Margin.Right)
				{
					Margins_new.Right.W    = Margin.Right.W;
					Margins_new.Right.Type = Margin.Right.Type;
				}

				if (Margin.Bottom)
				{
					Margins_new.Bottom.W    = Margin.Bottom.W;
					Margins_new.Bottom.Type = Margin.Bottom.Type;
				}

				if (Margin.Left)
				{
					Margins_new.Left.W    = Margin.Left.W;
					Margins_new.Left.Type = Margin.Left.Type;
				}

				break;
			}
			case 0:
			{
				if (true != bNeedChange && Margins_new.Top.W != Margin.W || Margins_new.Top.Type != Margin.Type)
					bNeedChange = true;

				Margins_new.Top.W    = Margin.W;
				Margins_new.Top.Type = Margin.Type;
				break;
			}
			case 1:
			{
				if (true != bNeedChange && Margins_new.Right.W != Margin.W || Margins_new.Right.Type != Margin.Type)
					bNeedChange = true;

				Margins_new.Right.W    = Margin.W;
				Margins_new.Right.Type = Margin.Type;
				break;
			}
			case 2:
			{
				if (true != bNeedChange && Margins_new.Bottom.W != Margin.W || Margins_new.Bottom.Type != Margin.Type)
					bNeedChange = true;

				Margins_new.Bottom.W    = Margin.W;
				Margins_new.Bottom.Type = Margin.Type;
				break;
			}
			case 3:
			{
				if (true != bNeedChange && Margins_new.Left.W != Margin.W || Margins_new.Left.Type != Margin.Type)
					bNeedChange = true;

				Margins_new.Left.W    = Margin.W;
				Margins_new.Left.Type = Margin.Type;
				break;
			}
		}

		if (true === bNeedChange)
		{
			History.Add(new CChangesTableCellMargins(this, OldValue, Margins_new));
			this.Pr.TableCellMar = Margins_new;
			this.Recalc_CompiledPr();
		}
	},

    Get_Shd : function()
    {
        var Shd = this.Get_CompiledPr(false).Shd;
        return Shd;
    },

	Set_Shd : function(Shd)
	{
		if (undefined === Shd && undefined === this.Pr.Shd)
			return;

		if (undefined === Shd)
		{
			History.Add(new CChangesTableCellShd(this, this.Pr.Shd, undefined));
			this.Pr.Shd = undefined;
			this.Recalc_CompiledPr();
		}
		else if (undefined === this.Pr.Shd || false === this.Pr.Shd.Compare(Shd))
		{
			var _Shd = new CDocumentShd();
			_Shd.Set_FromObject(Shd);
			History.Add(new CChangesTableCellShd(this, this.Pr.Shd, _Shd));
			this.Pr.Shd = _Shd;
			this.Recalc_CompiledPr();
		}
	},

    Get_VAlign : function()
    {
        var VAlign = this.Get_CompiledPr(false).VAlign;
        return VAlign;
    },

	Set_VAlign : function(Value)
	{
		if (Value === this.Pr.VAlign)
			return;

		History.Add(new CChangesTableCellVAlign(this, this.Pr.VAlign, Value));
		this.Pr.VAlign = Value;
		this.Recalc_CompiledPr();
	},

    Get_NoWrap : function()
    {
        return this.Get_CompiledPr(false).NoWrap;
    },

	Set_NoWrap : function(Value)
	{
		if (this.Pr.NoWrap !== Value)
		{
			History.Add(new CChangesTableCellNoWrap(this, this.Pr.NoWrap, Value));
			this.Pr.NoWrap = Value;
			this.Recalc_CompiledPr();
		}
	},

    Is_VerticalText : function()
    {
        var TextDirection = this.Get_TextDirection();
        if (textdirection_BTLR === TextDirection || textdirection_TBRL === TextDirection)
            return true;

        return false;
    },

    Get_TextDirection : function()
    {
        return this.Get_CompiledPr(false).TextDirection;
    },

	Set_TextDirection : function(Value)
	{
		if (Value !== this.Pr.TextDirection)
		{
			History.Add(new CChangesTableCellTextDirection(this, this.Pr.TextDirection, Value));
			this.Pr.TextDirection = Value;
			this.Recalc_CompiledPr();
		}
	},

    Set_TextDirectionFromApi : function(TextDirection)
    {
        var isVerticalText = (textdirection_BTLR === TextDirection || textdirection_TBRL === TextDirection) ? true : false;

        // Во время изменения направления текста меняем высоту строки, если надо и отступы и параграфов внутри ячейки.
        var OldTextDirection = this.Get_TextDirection();
        this.Set_TextDirection(TextDirection);

        if (OldTextDirection !== TextDirection)
        {
            if (true === isVerticalText)
            {
                var Row  = this.Row;
                var RowH = this.Row.Get_Height();

                if (Asc.linerule_Auto === RowH.HRule)
                    Row.Set_Height(20, Asc.linerule_AtLeast);
                else if (RowH.Value < 20)
                    Row.Set_Height(20, RowH.HRule);
            }

            this.Content.Set_ParaPropsForVerticalTextInCell(isVerticalText);
        }

    },

    Get_Borders : function()
    {
        var CellBorders =
            {
                Top    : this.Get_Border( 0 ),
                Right  : this.Get_Border( 1 ),
                Bottom : this.Get_Border( 2 ),
                Left   : this.Get_Border( 3 )
            };

        return CellBorders;
    },

    // 0 - Top, 1 - Right, 2- Bottom, 3- Left
    Get_Border : function(Type)
    {
        var TableBorders = this.Row.Table.Get_TableBorders();
        var Borders = this.Get_CompiledPr(false).TableCellBorders;
        var Border = null;
        switch (Type)
        {
            case 0 :
            {
                if ( null != Borders.Top )
                    Border = Borders.Top;
                else
                {
                    if ( 0 != this.Row.Index || null != this.Row.Get_CellSpacing() )
                        Border = TableBorders.InsideH;
                    else
                        Border = TableBorders.Top;
                }

                break;
            }
            case 1 :
            {
                if ( null != Borders.Right )
                    Border = Borders.Right;
                else
                {
                    if ( this.Row.Content.length - 1 != this.Index || null != this.Row.Get_CellSpacing() )
                        Border = TableBorders.InsideV;
                    else
                        Border = TableBorders.Right;
                }

                break;
            }
            case 2 :
            {
                if ( null != Borders.Bottom )
                    Border = Borders.Bottom;
                else
                {
                    if ( this.Row.Table.Content.length - 1 != this.Row.Index || null != this.Row.Get_CellSpacing() )
                        Border = TableBorders.InsideH;
                    else
                        Border = TableBorders.Bottom;
                }

                break;
            }
            case 3 :
            {
                if ( null != Borders.Left )
                    Border = Borders.Left;
                else
                {
                    if ( 0 != this.Index || null != this.Row.Get_CellSpacing() )
                        Border = TableBorders.InsideV;
                    else
                        Border = TableBorders.Left;
                }

                break;
            }
        }

        return Border;
    },

    // 0 - Top, 1 - Right, 2- Bottom, 3- Left
	Set_Border : function(Border, Type)
	{
		var DstBorder = this.Pr.TableCellBorders.Top;
		switch (Type)
		{
			case 0 :
				DstBorder = this.Pr.TableCellBorders.Top;
				break;
			case 1 :
				DstBorder = this.Pr.TableCellBorders.Right;
				break;
			case 2 :
				DstBorder = this.Pr.TableCellBorders.Bottom;
				break;
			case 3 :
				DstBorder = this.Pr.TableCellBorders.Left;
				break;
		}

		if (undefined === Border || null === Border)
		{
			if (Border === DstBorder)
				return;

			switch (Type)
			{
				case 0:
				{
					History.Add(new CChangesTableCellBorderTop(this, this.Pr.TableCellBorders.Top, Border));
					this.Pr.TableCellBorders.Top = undefined;
					break;
				}
				case 1 :
				{
					History.Add(new CChangesTableCellBorderRight(this, this.Pr.TableCellBorders.Right, Border));
					this.Pr.TableCellBorders.Right = undefined;
					break;
				}
				case 2 :
				{
					History.Add(new CChangesTableCellBorderBottom(this, this.Pr.TableCellBorders.Bottom, Border));
					this.Pr.TableCellBorders.Bottom = undefined;
					break;
				}
				case 3 :
				{
					History.Add(new CChangesTableCellBorderLeft(this, this.Pr.TableCellBorders.Left, Border));
					this.Pr.TableCellBorders.Left = undefined;
					break;
				}
			}

			this.Recalc_CompiledPr();
		}
		else if (null === DstBorder)
		{
			var NewBorder = this.Get_Border(Type).Copy();

			NewBorder.Value   = null != Border.Value ? Border.Value : NewBorder.Value;
			NewBorder.Size    = null != Border.Size ? Border.Size : NewBorder.Size;
			NewBorder.Color.r = null != Border.Color ? Border.Color.r : NewBorder.Color.r;
			NewBorder.Color.g = null != Border.Color ? Border.Color.g : NewBorder.Color.g;
			NewBorder.Color.b = null != Border.Color ? Border.Color.b : NewBorder.Color.b;
			NewBorder.Unifill = null != Border.Unifill ? Border.Unifill : NewBorder.Unifill;

			switch (Type)
			{
				case 0:
				{
					History.Add(new CChangesTableCellBorderTop(this, this.Pr.TableCellBorders.Top, NewBorder));
					this.Pr.TableCellBorders.Top = NewBorder;
					break;
				}
				case 1 :
				{
					History.Add(new CChangesTableCellBorderRight(this, this.Pr.TableCellBorders.Right, NewBorder));
					this.Pr.TableCellBorders.Right = NewBorder;
					break;
				}
				case 2 :
				{
					History.Add(new CChangesTableCellBorderBottom(this, this.Pr.TableCellBorders.Bottom, NewBorder));
					this.Pr.TableCellBorders.Bottom = NewBorder;
					break;
				}
				case 3 :
				{
					History.Add(new CChangesTableCellBorderLeft(this, this.Pr.TableCellBorders.Left, NewBorder));
					this.Pr.TableCellBorders.Left = NewBorder;
					break;
				}
			}

			this.Recalc_CompiledPr();
		}
		else
		{
			var NewBorder = new CDocumentBorder();

			var DefBorder = DstBorder;
			if (undefined === DefBorder)
				DefBorder = new CDocumentBorder();

			NewBorder.Value   = null != Border.Value ? Border.Value : DefBorder.Value;
			NewBorder.Size    = null != Border.Size ? Border.Size : DefBorder.Size;
			NewBorder.Color.r = null != Border.Color ? Border.Color.r : DefBorder.Color.r;
			NewBorder.Color.g = null != Border.Color ? Border.Color.g : DefBorder.Color.g;
			NewBorder.Color.b = null != Border.Color ? Border.Color.b : DefBorder.Color.b;
			NewBorder.Unifill = null != Border.Unifill ? Border.Unifill : DefBorder.Unifill;

			switch (Type)
			{
				case 0:
				{
					History.Add(new CChangesTableCellBorderTop(this, this.Pr.TableCellBorders.Top, NewBorder));
					this.Pr.TableCellBorders.Top = NewBorder;
					break;
				}
				case 1 :
				{
					History.Add(new CChangesTableCellBorderRight(this, this.Pr.TableCellBorders.Right, NewBorder));
					this.Pr.TableCellBorders.Right = NewBorder;
					break;
				}
				case 2 :
				{
					History.Add(new CChangesTableCellBorderBottom(this, this.Pr.TableCellBorders.Bottom, NewBorder));
					this.Pr.TableCellBorders.Bottom = NewBorder;
					break;
				}
				case 3 :
				{
					History.Add(new CChangesTableCellBorderLeft(this, this.Pr.TableCellBorders.Left, NewBorder));
					this.Pr.TableCellBorders.Left = NewBorder;
					break;
				}
			}

			this.Recalc_CompiledPr();
		}
	},

    Set_BorderInfo_Top : function( TopInfo )
    {
        this.BorderInfo.Top = TopInfo;
    },

    Set_BorderInfo_Bottom : function(BottomInfo, BeforeCount, AfterCount)
    {
        this.BorderInfo.Bottom = BottomInfo;
        this.BorderInfo.Bottom_BeforeCount = BeforeCount;
        this.BorderInfo.Bottom_AfterCount  = AfterCount;
    },

    Set_BorderInfo_Left : function(LeftInfo, Max)
    {
        this.BorderInfo.Left = LeftInfo;
        this.BorderInfo.MaxLeft = Max;
    },

    Set_BorderInfo_Right : function(RightInfo, Max)
    {
        this.BorderInfo.Right = RightInfo;
        this.BorderInfo.MaxRight = Max;
    },

    Get_BorderInfo : function()
    {
        return this.BorderInfo;
    },

    //-----------------------------------------------------------------------------------
    // Undo/Redo функции
    //-----------------------------------------------------------------------------------
    Get_ParentObject_or_DocumentPos : function()
    {
        return this.Row.Table.Get_ParentObject_or_DocumentPos(this.Row.Table.Index);
    },

    Refresh_RecalcData : function(Data)
    {
        var bNeedRecalc = false;

        var Type = Data.Type;
        switch ( Type )
        {
            case AscDFH.historyitem_TableCell_GridSpan:
            case AscDFH.historyitem_TableCell_Margins:
            case AscDFH.historyitem_TableCell_VMerge:
            case AscDFH.historyitem_TableCell_Border_Left:
            case AscDFH.historyitem_TableCell_Border_Right:
            case AscDFH.historyitem_TableCell_Border_Top:
            case AscDFH.historyitem_TableCell_Border_Bottom:
            case AscDFH.historyitem_TableCell_VAlign:
            case AscDFH.historyitem_TableCell_W:
            case AscDFH.historyitem_TableCell_Pr:
            case AscDFH.historyitem_TableCell_TextDirection:
            case AscDFH.historyitem_TableCell_NoWrap:
            {
                bNeedRecalc = true;
                break;
            }
            case AscDFH.historyitem_TableCell_Shd:
            {
                // Пересчитывать этот элемент не надо при таких изменениях
                break;
            }
        }

        this.Row.Table.RecalcInfo.Recalc_Borders();

        this.Refresh_RecalcData2( 0, 0 );
    },

    Refresh_RecalcData2 : function(Page_Rel)
    {
    	var oRow   = this.GetRow();
    	var oTable = this.GetTable();
    	if (!oRow || !oTable)
    		return;

    	oTable.RecalcInfo.Add_Cell(this);

        // Изменения в текущей ячейке могут вызвать изменения в следующей или предыдущей ячейках.
		// Например, когда у нас сквозная есть нумерация внутри ячеек
		var nCurCell = this.GetIndex();
		if (nCurCell > 0)
			oTable.RecalcInfo.Add_Cell(oRow.GetCell(nCurCell - 1));

		if (nCurCell < oRow.GetCellsCount() - 1)
			oTable.RecalcInfo.Add_Cell(oRow.GetCell(nCurCell + 1));

        var TablePr = oTable.Get_CompiledPr(false).TablePr;
        if (tbllayout_AutoFit === TablePr.TableLayout)
        {
            if (oTable.Parent.Pages.length > 0)
            {
                // Если изменение внутри ячейки влечет за собой изменение сетки таблицы, тогда
                // пересчитывать таблицу надо с самого начала.
                History.Add_RecalcTableGrid(oTable.Get_Id());
            }
            else
			{
				return oTable.Refresh_RecalcData2(0, 0);
			}
        }

        oRow.Refresh_RecalcData2(nCurCell, Page_Rel);
    },
    //-----------------------------------------------------------------------------------
    // Функции для работы с совместным редактирования
    //-----------------------------------------------------------------------------------
    Write_ToBinary2 : function(Writer)
    {
        Writer.WriteLong( AscDFH.historyitem_type_TableCell );

        // String   : Id ячейки
        // Variable : TableCell.Pr
        // String   : Id DocumentContent

        Writer.WriteString2( this.Id );
        this.Pr.Write_ToBinary( Writer );
        Writer.WriteString2( this.Content.Get_Id() );
    },

    Read_FromBinary2 : function(Reader)
    {
        // String   : Id ячейки
        // Variable : TableCell.Pr
        // String   : Id DocumentContent

        this.Id = Reader.GetString2();
        this.Pr = new CTableCellPr();
        this.Pr.Read_FromBinary( Reader );
        this.Recalc_CompiledPr();

        this.Content = AscCommon.g_oTableId.Get_ById( Reader.GetString2() );

        AscCommon.CollaborativeEditing.Add_NewObject( this );
    },

    Load_LinkData : function(LinkData)
    {
    }
};
/**
 * Доступ к содержимому ячейки
 * @returns {CDocumentContent}
 */
CTableCell.prototype.GetContent = function()
{
	return this.Content;
};
/**
 * Доступ к родительской строке
 * @returns {null | CTableRow}
 */
CTableCell.prototype.GetRow = function()
{
	return this.Row;
};
/**
 * Доступ к родительской таблице
 * @returns {null | CTable}
 */
CTableCell.prototype.GetTable = function()
{
	var oRow = this.GetRow();
	if (!oRow)
		return null;

	return oRow.GetTable();
};
/**
 * Получаем номер данной ячейки в родительской строке
 * @returns {number}
 */
CTableCell.prototype.GetIndex = function()
{
	return this.Index;
};
CTableCell.prototype.private_TransformXY = function(X, Y)
{
	// TODO: Везде, где идет такой код заменить на данную функцию

	var _X = X, _Y = Y;
	var Transform = this.private_GetTextDirectionTransform();
	if (null !== Transform)
	{
		Transform = global_MatrixTransformer.Invert(Transform);
		_X = Transform.TransformPointX(X, Y);
		_Y = Transform.TransformPointY(X, Y);
	}

	return {X : _X, Y : _Y};
};
CTableCell.prototype.GetTopElement = function()
{
    if (this.Row && this.Row.Table)
        return this.Row.Table.GetTopElement();

    return null;
};
CTableCell.prototype.Is_EmptyFirstPage = function()
{
    if (!this.Row || !this.Row.Table || !this.Row.Table.RowsInfo[this.Row.Index] || true === this.Row.Table.RowsInfo[this.Row.Index].FirstPage)
        return true;

    return false;
};
CTableCell.prototype.Get_SectPr = function()
{
    if (this.Row && this.Row.Table && this.Row.Table)
        return this.Row.Table.Get_SectPr();

    return null;
};
CTableCell.prototype.GetDocumentPositionFromObject = function(PosArray)
{
    if (!PosArray)
        PosArray = [];

    if (this.Row)
    {
        PosArray.splice(0, 0, {Class : this.Row, Position : this.Index});
        this.Row.GetDocumentPositionFromObject(PosArray);
    }

    return PosArray;
};
CTableCell.prototype.Get_Table = function()
{
    var Row = this.Row;
    if (!Row)
        return null;

    var Table = Row.Table;
    if (!Table)
        return null;

    return Table;
};
CTableCell.prototype.GetTopDocumentContent = function()
{
    if (this.Row && this.Row.Table && this.Row.Table.Parent)
        return this.Row.Table.Parent.GetTopDocumentContent();

    return null;
};
/**
 * Специальная вставка таблицы в таблицу. Данная функция вызывается из CDocumentContent
 * @param oTable
 */
CTableCell.prototype.InsertTableContent = function(oTable)
{
	if (!this.Row || !this.Row.Table)
		return;

	this.Row.Table.InsertTableContent(this.Index, this.Row.Index, oTable);
};
/**
 * Получаем ширину ячейки исходя из таблицы TableGrid
 * @returns {number}
 */
CTableCell.prototype.GetCalculatedW = function()
{
	var oRow   = this.Row,
		oTable = oRow.Table;

	var nCurGridStart = oRow.GetCellInfo(this.Index).StartGridCol;
	var nCurGridEnd   = nCurGridStart + this.Get_GridSpan() - 1;

	if (oTable.TableSumGrid.length > nCurGridEnd)
		return oTable.TableSumGrid[nCurGridEnd] - oTable.TableSumGrid[nCurGridStart - 1];

	return 3.8; // 1.9 + 1.9 стандартные отступы справа и слева
};
/**
 * Получаем количество промежутков, которое занимает данная ячейка
 * @returns {number}
 */
CTableCell.prototype.GetGridSpan = function()
{
	return this.Get_GridSpan();
};
/**
 * Выставляем количество промежутков, которое занимает данная ячейка
 * @param nGridSpan
 */
CTableCell.prototype.SetGridSpan = function(nGridSpan)
{
	return this.Set_GridSpan(nGridSpan);
};
/**
 * Получаем информацию о границе ячейки
 * @param {number} nType - 0 - Top, 1 - Right, 2- Bottom, 3- Left
 */
CTableCell.prototype.GetBorder = function(nType)
{
	return this.Get_Border(nType);
};
/**
 * Проверяем, является ли данная ячейка последней в строке
 * @returns {boolean}
 */
CTableCell.prototype.IsLastTableCellInRow = function(isSelection)
{
	if (true !== isSelection)
		return !!(this.Row && this.Row.GetCellsCount() - 1 === this.Index);

	if (!this.Row || !this.Row.Table)
		return false;

	var nCurCell = this.Index;
	var nCurRow  = this.Row.Index;

	var oTable = this.Row.Table;
	var arrSelectionArray = oTable.GetSelectionArray();
	for (var nIndex = 0, nCount = arrSelectionArray.length; nIndex < nCount; ++nIndex)
	{
		var nRow  = arrSelectionArray[nIndex].Row;
		var nCell = arrSelectionArray[nIndex].Cell;

		if (nRow === nCurRow && nCell > nCurCell)
			return false;
	}

	return true;
};
/**
 * Получаем скомпилированную настройку ширины ячейки
 * @returns {?CTableMeasurement}
 */
CTableCell.prototype.GetW = function()
{
	return this.Get_W();
};
/**
 * Задаем предпочитаемую ширину ячейки
 * @param {CTableMeasurement} oCellW
 */
CTableCell.prototype.SetW = function(oCellW)
{
	return this.Set_W(oCellW);
};
/**
 * Участвует ли в вертикальном объединении данная ячейка
 * @returns {vmerge_Restart | vmerge_Continue}
 */
CTableCell.prototype.GetVMerge = function()
{
	return this.Get_CompiledPr(false).VMerge;
};
/**
 * Задаем настройку участия данной ячейки в вертикальном объединении
 * @param {vmerge_Restart | vmerge_Continue} nType
 */
CTableCell.prototype.SetVMerge = function(nType)
{
	if (nType === this.Pr.VMerge)
		return;

	History.Add(new CChangesTableCellVMerge(this, this.Pr.VMerge, nType));
	this.Pr.VMerge = nType;
	this.Recalc_CompiledPr();
};
/**
 * Проверяем находится ли данная ячейка в заголовке таблицы
 * @param {boolean} [isDeep=false] Если данная ячейка не в заголовке своей таблицы, то смотрим ли у родительского класса таблицы
 * @returns {boolean}
 */
CTableCell.prototype.IsInHeader = function(isDeep)
{
	var isInHeader = this.Row.Table.IsInHeader(this.Row.GetIndex());
	if (isInHeader)
		return true;

	if (true === isDeep && this.Row.Table.Parent && this.Row.Table.Parent.IsTableHeader)
		return this.Row.Table.Parent.IsTableHeader();

	return false;
};
/**
 * Получаем последний элемент в предыдущей ячейке данной строки
 * @returns {?CDocumentContentElementBase}
 */
CTableCell.prototype.GetLastElementInPrevCell = function()
{
	var nCurCell = this.GetIndex();
	var oRow     = this.GetRow();

	if (!oRow)
		return null;

	// TODO: Разобраться, что делать в данном случае
	if (0 === nCurCell)
	{
		var oTable = this.GetTable();
		if (0 === oRow.GetIndex() && oTable)
			return oTable.Get_DocumentPrev();

		return null;
	}

	var oPrevCell = oRow.GetCell(nCurCell - 1);
	var oCellContent = oPrevCell.GetContent();

	var nCount = oCellContent.GetElementsCount();
	if (nCount <= 0)
		return null;

	return oCellContent.GetElement(nCount - 1);
};
/**
 * Получаем первый элемент в следующей ячейке
 * @returns {?CDocumentContentElementBase}
 */
CTableCell.prototype.GetFirstElementInNextCell = function()
{
	var nCurCell = this.GetIndex();
	var oRow     = this.GetRow();

	if (!oRow)
		return null;

	// TODO: Разобраться, что делать в данном случае
	if (nCurCell >= oRow.GetCellsCount() - 1)
		return null;

	var oCellContent = oRow.GetCell(nCurCell + 1).GetContent();
	var nCount = oCellContent.GetElementsCount();
	if (nCount <= 0)
		return null;

	return oCellContent.GetElement(0);
};
/**
 * Получаем предыдущий параграф
 * @returns {?Paragraph}
 */
CTableCell.prototype.GetPrevParagraph = function()
{
	var oTable     = this.GetTable();
	var oRow       = this.GetRow();
	var nCellIndex = this.GetIndex();

	if (0 === nCellIndex)
	{
		var nRowIndex = oRow.GetIndex();

		if (0 === nRowIndex)
		{
			return oTable.GetPrevParagraph();
		}
		else
		{
			var oPrevRow  = oTable.GetRow(nRowIndex - 1);
			var oPrevCell = oPrevRow.GetCell(oPrevRow.GetCellsCount() - 1);

			if (!oPrevCell)
				return null;

			return oPrevCell.GetContent().GetLastParagraph();
		}
	}
	else
	{
		var oPrevCell = oRow.GetCell(nCellIndex - 1);

		if (!oPrevCell)
			return null;

		return oPrevCell.GetContent().GetLastParagraph();
	}
};
/**
 * Участвует ли в вертикальном объединении данная ячейка
 * @returns {vmerge_Restart | vmerge_Continue}
 */
CTableCell.prototype.GetHMerge = function()
{
	return this.Get_CompiledPr(false).HMerge;
};
/**
 * Задаем настройку участия данной ячейки в вертикальном объединении
 * @param {vmerge_Restart | vmerge_Continue} nType
 */
CTableCell.prototype.SetHMerge = function(nType)
{
	if (nType === this.Pr.HMerge)
		return;

	History.Add(new CChangesTableCellHMerge(this, this.Pr.HMerge, nType));
	this.Pr.HMerge = nType;
	this.Recalc_CompiledPr();
};


function CTableCellRecalculateObject()
{
    this.BorderInfo = null;
    this.Metrics    = null;
    this.Temp       = null;

    this.Content    = null;
}

CTableCellRecalculateObject.prototype =
{
    Save : function(Cell)
    {
        this.BorderInfo = Cell.BorderInfo;
        this.Metrics    = Cell.Metrics;
        this.Temp       = Cell.Temp;

        this.Content = Cell.Content.SaveRecalculateObject();
    },

    Load : function(Cell)
    {
        Cell.BorderInfo = this.BorderInfo;
        Cell.Metrics    = this.Metrics;
        Cell.Temp       = this.Temp;

        Cell.Content.LoadRecalculateObject( this.Content );
    },

    Get_DrawingFlowPos : function(FlowPos)
    {
        this.Content.Get_DrawingFlowPos( FlowPos );
    }

};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CTableCell = CTableCell;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 07.11.2016
 * Time: 16:57
 */

AscDFH.changesFactory[AscDFH.historyitem_TableCell_GridSpan]      = CChangesTableCellGridSpan;
AscDFH.changesFactory[AscDFH.historyitem_TableCell_Margins]       = CChangesTableCellMargins;
AscDFH.changesFactory[AscDFH.historyitem_TableCell_Shd]           = CChangesTableCellShd;
AscDFH.changesFactory[AscDFH.historyitem_TableCell_VMerge]        = CChangesTableCellVMerge;
AscDFH.changesFactory[AscDFH.historyitem_TableCell_Border_Left]   = CChangesTableCellBorderLeft;
AscDFH.changesFactory[AscDFH.historyitem_TableCell_Border_Right]  = CChangesTableCellBorderRight;
AscDFH.changesFactory[AscDFH.historyitem_TableCell_Border_Top]    = CChangesTableCellBorderTop;
AscDFH.changesFactory[AscDFH.historyitem_TableCell_Border_Bottom] = CChangesTableCellBorderBottom;
AscDFH.changesFactory[AscDFH.historyitem_TableCell_VAlign]        = CChangesTableCellVAlign;
AscDFH.changesFactory[AscDFH.historyitem_TableCell_W]             = CChangesTableCellW;
AscDFH.changesFactory[AscDFH.historyitem_TableCell_Pr]            = CChangesTableCellPr;
AscDFH.changesFactory[AscDFH.historyitem_TableCell_TextDirection] = CChangesTableCellTextDirection;
AscDFH.changesFactory[AscDFH.historyitem_TableCell_NoWrap]        = CChangesTableCellNoWrap;
AscDFH.changesFactory[AscDFH.historyitem_TableCell_HMerge]        = CChangesTableCellHMerge;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_TableCell_GridSpan]      = [
	AscDFH.historyitem_TableCell_GridSpan,
	AscDFH.historyitem_TableCell_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableCell_Margins]       = [
	AscDFH.historyitem_TableCell_Margins,
	AscDFH.historyitem_TableCell_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableCell_Shd]           = [
	AscDFH.historyitem_TableCell_Shd,
	AscDFH.historyitem_TableCell_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableCell_VMerge]        = [
	AscDFH.historyitem_TableCell_VMerge,
	AscDFH.historyitem_TableCell_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableCell_Border_Left]   = [
	AscDFH.historyitem_TableCell_Border_Left,
	AscDFH.historyitem_TableCell_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableCell_Border_Right]  = [
	AscDFH.historyitem_TableCell_Border_Right,
	AscDFH.historyitem_TableCell_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableCell_Border_Top]    = [
	AscDFH.historyitem_TableCell_Border_Top,
	AscDFH.historyitem_TableCell_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableCell_Border_Bottom] = [
	AscDFH.historyitem_TableCell_Border_Bottom,
	AscDFH.historyitem_TableCell_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableCell_VAlign]        = [
	AscDFH.historyitem_TableCell_VAlign,
	AscDFH.historyitem_TableCell_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableCell_W]             = [
	AscDFH.historyitem_TableCell_W,
	AscDFH.historyitem_TableCell_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableCell_Pr]            = [
	AscDFH.historyitem_TableCell_GridSpan,
	AscDFH.historyitem_TableCell_Margins,
	AscDFH.historyitem_TableCell_Shd,
	AscDFH.historyitem_TableCell_VMerge,
	AscDFH.historyitem_TableCell_Border_Left,
	AscDFH.historyitem_TableCell_Border_Right,
	AscDFH.historyitem_TableCell_Border_Top,
	AscDFH.historyitem_TableCell_Border_Bottom,
	AscDFH.historyitem_TableCell_VAlign,
	AscDFH.historyitem_TableCell_W,
	AscDFH.historyitem_TableCell_Pr,
	AscDFH.historyitem_TableCell_TextDirection,
	AscDFH.historyitem_TableCell_NoWrap,
	AscDFH.historyitem_TableCell_HMerge
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableCell_TextDirection] = [
	AscDFH.historyitem_TableCell_TextDirection,
	AscDFH.historyitem_TableCell_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableCell_NoWrap]        = [
	AscDFH.historyitem_TableCell_NoWrap,
	AscDFH.historyitem_TableCell_Pr
];
AscDFH.changesRelationMap[AscDFH.historyitem_TableCell_HMerge]        = [
	AscDFH.historyitem_TableCell_HMerge,
	AscDFH.historyitem_TableCell_Pr
];
/**
 * Общая функция объединения изменений, которые зависят только от себя и AscDFH.historyitem_TableCell_Pr
 * @param oChange
 * @returns {boolean}
 */
function private_TableCellChangesOnMergePr(oChange)
{
	if (oChange.Class !== this.Class)
		return true;

	if (oChange.Type === this.Type || oChange.Type === AscDFH.historyitem_TableCell_Pr)
		return false;

	return true;
}
//----------------------------------------------------------------------------------------------------------------------

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesTableCellGridSpan(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesTableCellGridSpan.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesTableCellGridSpan.prototype.constructor = CChangesTableCellGridSpan;
CChangesTableCellGridSpan.prototype.Type = AscDFH.historyitem_TableCell_GridSpan;
CChangesTableCellGridSpan.prototype.private_SetValue = function(Value)
{
	var oCell = this.Class;
	oCell.Pr.GridSpan = Value;
	oCell.Recalc_CompiledPr();
};
CChangesTableCellGridSpan.prototype.Merge = private_TableCellChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesTableCellMargins(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesTableCellMargins.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesTableCellMargins.prototype.constructor = CChangesTableCellMargins;
CChangesTableCellMargins.prototype.Type = AscDFH.historyitem_TableCell_Margins;
CChangesTableCellMargins.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Is New undefined?
	// 2-bit : Is New null?
	// 3-bit : Is Old undefined?
	// 4-bit : Is Old null?

	// CTableMeasure : New.Left
	// CTableMeasure : New.Top
	// CTableMeasure : New.Right
	// CTableMeasure : New.Bottom
	// CTableMeasure : Old.Left
	// CTableMeasure : Old.Top
	// CTableMeasure : Old.Right
	// CTableMeasure : Old.Bottom

	var nFlags = 0;

	if (undefined === this.New)
		nFlags |= 1;
	if (null === this.New)
		nFlags |= 2;
	if (undefined === this.Old)
		nFlags |= 4;
	if (null === this.Old)
		nFlags |= 8;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New && null !== this.New)
	{
		this.New.Left.Write_ToBinary(Writer);
		this.New.Top.Write_ToBinary(Writer);
		this.New.Right.Write_ToBinary(Writer);
		this.New.Bottom.Write_ToBinary(Writer);
	}

	if (undefined !== this.Old && null !== this.Old)
	{
		this.Old.Left.Write_ToBinary(Writer);
		this.Old.Top.Write_ToBinary(Writer);
		this.Old.Right.Write_ToBinary(Writer);
		this.Old.Bottom.Write_ToBinary(Writer);
	}
};
CChangesTableCellMargins.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Is New undefined?
	// 2-bit : Is New null?
	// 3-bit : Is Old undefined?
	// 4-bit : Is Old null?

	// CTableMeasure : New.Left
	// CTableMeasure : New.Top
	// CTableMeasure : New.Right
	// CTableMeasure : New.Bottom
	// CTableMeasure : Old.Left
	// CTableMeasure : Old.Top
	// CTableMeasure : Old.Right
	// CTableMeasure : Old.Bottom

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
	{
		this.New = undefined;
	}
	else if (nFlags & 2)
	{
		this.New = null;
	}
	else
	{
		this.New = {
			Left   : new CTableMeasurement(tblwidth_Auto, 0),
			Top    : new CTableMeasurement(tblwidth_Auto, 0),
			Right  : new CTableMeasurement(tblwidth_Auto, 0),
			Bottom : new CTableMeasurement(tblwidth_Auto, 0)
		};

		this.New.Left.Read_FromBinary(Reader);
		this.New.Top.Read_FromBinary(Reader);
		this.New.Right.Read_FromBinary(Reader);
		this.New.Bottom.Read_FromBinary(Reader);
	}

	if (nFlags & 4)
	{
		this.Old = undefined;
	}
	else if (nFlags & 8)
	{
		this.Old = null;
	}
	else
	{
		this.Old = {
			Left   : new CTableMeasurement(tblwidth_Auto, 0),
			Top    : new CTableMeasurement(tblwidth_Auto, 0),
			Right  : new CTableMeasurement(tblwidth_Auto, 0),
			Bottom : new CTableMeasurement(tblwidth_Auto, 0)
		};

		this.Old.Left.Read_FromBinary(Reader);
		this.Old.Top.Read_FromBinary(Reader);
		this.Old.Right.Read_FromBinary(Reader);
		this.Old.Bottom.Read_FromBinary(Reader);
	}
};
CChangesTableCellMargins.prototype.private_SetValue = function(Value)
{
	var oCell = this.Class;
	oCell.Pr.TableCellMar = Value;
	oCell.Recalc_CompiledPr();
};
CChangesTableCellMargins.prototype.Merge = private_TableCellChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesTableCellShd(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New, Color);
}
CChangesTableCellShd.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesTableCellShd.prototype.constructor = CChangesTableCellShd;
CChangesTableCellShd.prototype.Type = AscDFH.historyitem_TableCell_Shd;
CChangesTableCellShd.prototype.private_CreateObject = function()
{
	return new CDocumentShd();
};
CChangesTableCellShd.prototype.private_SetValue = function(Value)
{
	var oCell = this.Class;
	oCell.Pr.Shd = Value;
	oCell.Recalc_CompiledPr();
};
CChangesTableCellShd.prototype.Merge = private_TableCellChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesTableCellVMerge(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesTableCellVMerge.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesTableCellVMerge.prototype.constructor = CChangesTableCellVMerge;
CChangesTableCellVMerge.prototype.Type = AscDFH.historyitem_TableCell_VMerge;
CChangesTableCellVMerge.prototype.private_SetValue = function(Value)
{
	var oCell = this.Class;
	oCell.Pr.VMerge = Value;
	oCell.Recalc_CompiledPr();
};
CChangesTableCellVMerge.prototype.Merge = private_TableCellChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesTableCellBorderLeft(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesTableCellBorderLeft.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesTableCellBorderLeft.prototype.constructor = CChangesTableCellBorderLeft;
CChangesTableCellBorderLeft.prototype.Type = AscDFH.historyitem_TableCell_Border_Left;
CChangesTableCellBorderLeft.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Is New undefined?
	// 2-bit : Is New null?
	// 3-bit : Is Old undefined?
	// 4-bit : Is Old null?

	// CDocumentBorder : New
	// CDocumentBorder : Old

	var nFlags = 0;

	if (undefined === this.New)
		nFlags |= 1;
	if (null === this.New)
		nFlags |= 2;
	if (undefined === this.Old)
		nFlags |= 4;
	if (null === this.Old)
		nFlags |= 8;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New && null !== this.New)
		this.New.Write_ToBinary(Writer);

	if (undefined !== this.Old && null !== this.Old)
		this.Old.Write_ToBinary(Writer);
};
CChangesTableCellBorderLeft.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Is New undefined?
	// 2-bit : Is New null?
	// 3-bit : Is Old undefined?
	// 4-bit : Is Old null?

	// CDocumentBorder : New
	// CDocumentBorder : Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
	{
		this.New = undefined;
	}
	else if (nFlags & 2)
	{
		this.New = null;
	}
	else
	{
		this.New = new CDocumentBorder();
		this.New.Read_FromBinary(Reader);
	}

	if (nFlags & 4)
	{
		this.Old = undefined;
	}
	else if (nFlags & 8)
	{
		this.Old = null;
	}
	else
	{
		this.Old = new CDocumentBorder();
		this.Old.Read_FromBinary(Reader);
	}
};
CChangesTableCellBorderLeft.prototype.private_SetValue = function(Value)
{
	var oCell = this.Class;
	oCell.Pr.TableCellBorders.Left = Value;
	oCell.Recalc_CompiledPr();
};
CChangesTableCellBorderLeft.prototype.Merge = private_TableCellChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesTableCellBorderTop(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesTableCellBorderTop.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesTableCellBorderTop.prototype.constructor = CChangesTableCellBorderTop;
CChangesTableCellBorderTop.prototype.Type = AscDFH.historyitem_TableCell_Border_Top;
CChangesTableCellBorderTop.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Is New undefined?
	// 2-bit : Is New null?
	// 3-bit : Is Old undefined?
	// 4-bit : Is Old null?

	// CDocumentBorder : New
	// CDocumentBorder : Old

	var nFlags = 0;

	if (undefined === this.New)
		nFlags |= 1;
	if (null === this.New)
		nFlags |= 2;
	if (undefined === this.Old)
		nFlags |= 4;
	if (null === this.Old)
		nFlags |= 8;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New && null !== this.New)
		this.New.Write_ToBinary(Writer);

	if (undefined !== this.Old && null !== this.Old)
		this.Old.Write_ToBinary(Writer);
};
CChangesTableCellBorderTop.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Is New undefined?
	// 2-bit : Is New null?
	// 3-bit : Is Old undefined?
	// 4-bit : Is Old null?

	// CDocumentBorder : New
	// CDocumentBorder : Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
	{
		this.New = undefined;
	}
	else if (nFlags & 2)
	{
		this.New = null;
	}
	else
	{
		this.New = new CDocumentBorder();
		this.New.Read_FromBinary(Reader);
	}

	if (nFlags & 4)
	{
		this.Old = undefined;
	}
	else if (nFlags & 8)
	{
		this.Old = null;
	}
	else
	{
		this.Old = new CDocumentBorder();
		this.Old.Read_FromBinary(Reader);
	}
};
CChangesTableCellBorderTop.prototype.private_SetValue = function(Value)
{
	var oCell = this.Class;
	oCell.Pr.TableCellBorders.Top = Value;
	oCell.Recalc_CompiledPr();
};
CChangesTableCellBorderTop.prototype.Merge = private_TableCellChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesTableCellBorderRight(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesTableCellBorderRight.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesTableCellBorderRight.prototype.constructor = CChangesTableCellBorderRight;
CChangesTableCellBorderRight.prototype.Type = AscDFH.historyitem_TableCell_Border_Right;
CChangesTableCellBorderRight.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Is New undefined?
	// 2-bit : Is New null?
	// 3-bit : Is Old undefined?
	// 4-bit : Is Old null?

	// CDocumentBorder : New
	// CDocumentBorder : Old

	var nFlags = 0;

	if (undefined === this.New)
		nFlags |= 1;
	if (null === this.New)
		nFlags |= 2;
	if (undefined === this.Old)
		nFlags |= 4;
	if (null === this.Old)
		nFlags |= 8;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New && null !== this.New)
		this.New.Write_ToBinary(Writer);

	if (undefined !== this.Old && null !== this.Old)
		this.Old.Write_ToBinary(Writer);
};
CChangesTableCellBorderRight.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Is New undefined?
	// 2-bit : Is New null?
	// 3-bit : Is Old undefined?
	// 4-bit : Is Old null?

	// CDocumentBorder : New
	// CDocumentBorder : Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
	{
		this.New = undefined;
	}
	else if (nFlags & 2)
	{
		this.New = null;
	}
	else
	{
		this.New = new CDocumentBorder();
		this.New.Read_FromBinary(Reader);
	}

	if (nFlags & 4)
	{
		this.Old = undefined;
	}
	else if (nFlags & 8)
	{
		this.Old = null;
	}
	else
	{
		this.Old = new CDocumentBorder();
		this.Old.Read_FromBinary(Reader);
	}
};
CChangesTableCellBorderRight.prototype.private_SetValue = function(Value)
{
	var oCell = this.Class;
	oCell.Pr.TableCellBorders.Right = Value;
	oCell.Recalc_CompiledPr();
};
CChangesTableCellBorderRight.prototype.Merge = private_TableCellChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesTableCellBorderBottom(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesTableCellBorderBottom.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesTableCellBorderBottom.prototype.constructor = CChangesTableCellBorderBottom;
CChangesTableCellBorderBottom.prototype.Type = AscDFH.historyitem_TableCell_Border_Bottom;
CChangesTableCellBorderBottom.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Is New undefined?
	// 2-bit : Is New null?
	// 3-bit : Is Old undefined?
	// 4-bit : Is Old null?

	// CDocumentBorder : New
	// CDocumentBorder : Old

	var nFlags = 0;

	if (undefined === this.New)
		nFlags |= 1;
	if (null === this.New)
		nFlags |= 2;
	if (undefined === this.Old)
		nFlags |= 4;
	if (null === this.Old)
		nFlags |= 8;

	Writer.WriteLong(nFlags);

	if (undefined !== this.New && null !== this.New)
		this.New.Write_ToBinary(Writer);

	if (undefined !== this.Old && null !== this.Old)
		this.Old.Write_ToBinary(Writer);
};
CChangesTableCellBorderBottom.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Is New undefined?
	// 2-bit : Is New null?
	// 3-bit : Is Old undefined?
	// 4-bit : Is Old null?

	// CDocumentBorder : New
	// CDocumentBorder : Old

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
	{
		this.New = undefined;
	}
	else if (nFlags & 2)
	{
		this.New = null;
	}
	else
	{
		this.New = new CDocumentBorder();
		this.New.Read_FromBinary(Reader);
	}

	if (nFlags & 4)
	{
		this.Old = undefined;
	}
	else if (nFlags & 8)
	{
		this.Old = null;
	}
	else
	{
		this.Old = new CDocumentBorder();
		this.Old.Read_FromBinary(Reader);
	}
};
CChangesTableCellBorderBottom.prototype.private_SetValue = function(Value)
{
	var oCell = this.Class;
	oCell.Pr.TableCellBorders.Bottom = Value;
	oCell.Recalc_CompiledPr();
};
CChangesTableCellBorderBottom.prototype.Merge = private_TableCellChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesTableCellVAlign(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesTableCellVAlign.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesTableCellVAlign.prototype.constructor = CChangesTableCellVAlign;
CChangesTableCellVAlign.prototype.Type = AscDFH.historyitem_TableCell_VAlign;
CChangesTableCellVAlign.prototype.private_SetValue = function(Value)
{
	var oCell = this.Class;
	oCell.Pr.VAlign = Value;
	oCell.Recalc_CompiledPr();
};
CChangesTableCellVAlign.prototype.Merge = private_TableCellChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectValue}
 */
function CChangesTableCellW(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectValue.call(this, Class, Old, New, Color);
}
CChangesTableCellW.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesTableCellW.prototype.constructor = CChangesTableCellW;
CChangesTableCellW.prototype.Type = AscDFH.historyitem_TableCell_W;
CChangesTableCellW.prototype.private_CreateObject = function()
{
	return new CTableMeasurement(tblwidth_Auto, 0);
};
CChangesTableCellW.prototype.private_SetValue = function(Value)
{
	var oCell = this.Class;
	oCell.Pr.TableCellW = Value;
	oCell.Recalc_CompiledPr();
};
CChangesTableCellW.prototype.Merge = private_TableCellChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectValue}
 */
function CChangesTableCellPr(Class, Old, New, Color)
{
	AscDFH.CChangesBaseObjectValue.call(this, Class, Old, New, Color);
}
CChangesTableCellPr.prototype = Object.create(AscDFH.CChangesBaseObjectValue.prototype);
CChangesTableCellPr.prototype.constructor = CChangesTableCellPr;
CChangesTableCellPr.prototype.Type = AscDFH.historyitem_TableCell_Pr;
CChangesTableCellPr.prototype.private_CreateObject = function()
{
	return new CTableCellPr();
};
CChangesTableCellPr.prototype.private_SetValue = function(Value)
{
	var oCell = this.Class;
	oCell.Pr = Value;
	oCell.Recalc_CompiledPr();
};
CChangesTableCellPr.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type)
		return false;

	if (!this.New)
		this.New = new CTableCellPr();

	switch(oChange.Type)
	{
		case AscDFH.historyitem_TableCell_GridSpan:
		{
			this.New.GridSpan = oChange.New;
			break;
		}
		case AscDFH.historyitem_TableCell_Margins:
		{
			this.New.TableCellMar = oChange.New;
			break;
		}
		case AscDFH.historyitem_TableCell_Shd:
		{
			this.New.Shd = oChange.New;
			break;
		}
		case AscDFH.historyitem_TableCell_VMerge:
		{
			this.New.VMerge = oChange.New;
			break;
		}
		case AscDFH.historyitem_TableCell_Border_Left:
		{
			this.New.TableCellBorders.Left = oChange.New;
			break;
		}
		case AscDFH.historyitem_TableCell_Border_Right:
		{
			this.New.TableCellBorders.Right = oChange.New;
			break;
		}
		case AscDFH.historyitem_TableCell_Border_Top:
		{
			this.New.TableCellBorders.Top = oChange.New;
			break;
		}
		case AscDFH.historyitem_TableCell_Border_Bottom:
		{
			this.New.TableCellBorders.Bottom = oChange.New;
			break;
		}
		case AscDFH.historyitem_TableCell_VAlign:
		{
			this.New.VAlign = oChange.New;
			break;
		}
		case AscDFH.historyitem_TableCell_W:
		{
			this.New.TableCellW = oChange.New;
			break;
		}
		case AscDFH.historyitem_TableCell_TextDirection:
		{
			this.New.TextDirection = oChange.New;
			break;
		}
		case AscDFH.historyitem_TableCell_NoWrap:
		{
			this.New.NoWrap = oChange.New;
			break;
		}
		case AscDFH.historyitem_TableCell_HMerge:
		{
			this.New.HMerge = oChange.New;
			break;
		}
	}

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesTableCellTextDirection(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesTableCellTextDirection.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesTableCellTextDirection.prototype.constructor = CChangesTableCellTextDirection;
CChangesTableCellTextDirection.prototype.Type = AscDFH.historyitem_TableCell_TextDirection;
CChangesTableCellTextDirection.prototype.private_SetValue = function(Value)
{
	var oCell = this.Class;
	oCell.Pr.TextDirection = Value;
	oCell.Recalc_CompiledPr();
};
CChangesTableCellTextDirection.prototype.Merge = private_TableCellChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseBoolProperty}
 */
function CChangesTableCellNoWrap(Class, Old, New, Color)
{
	AscDFH.CChangesBaseBoolProperty.call(this, Class, Old, New, Color);
}
CChangesTableCellNoWrap.prototype = Object.create(AscDFH.CChangesBaseBoolProperty.prototype);
CChangesTableCellNoWrap.prototype.constructor = CChangesTableCellNoWrap;
CChangesTableCellNoWrap.prototype.Type = AscDFH.historyitem_TableCell_NoWrap;
CChangesTableCellNoWrap.prototype.private_SetValue = function(Value)
{
	var oCell = this.Class;
	oCell.Pr.NoWrap = Value;
	oCell.Recalc_CompiledPr();
};
CChangesTableCellNoWrap.prototype.Merge = private_TableCellChangesOnMergePr;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesTableCellHMerge(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesTableCellHMerge.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesTableCellHMerge.prototype.constructor = CChangesTableCellHMerge;
CChangesTableCellHMerge.prototype.Type = AscDFH.historyitem_TableCell_HMerge;
CChangesTableCellHMerge.prototype.private_SetValue = function(Value)
{
	var oCell = this.Class;
	oCell.Pr.HMerge = Value;
	oCell.Recalc_CompiledPr();
};
CChangesTableCellHMerge.prototype.Merge = private_TableCellChangesOnMergePr;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 04.04.2017
 * Time: 17:00
 */

var type_BlockLevelSdt = 0x0003;

/**
 * @param oParent - родительский класс
 * @param oLogicDocument {CDocument} - главный класс документа
 * @constructor
 * @extends {CDocumentContentElementBase}
 */
function CBlockLevelSdt(oLogicDocument, oParent)
{
	CDocumentContentElementBase.call(this, oParent);

	this.LogicDocument = oLogicDocument;
	this.Content       = new CDocumentContent(this, oLogicDocument ? oLogicDocument.Get_DrawingDocument() : null, 0, 0, 0, 0, true, false, false);
	this.Pr            = new CSdtPr();
	this.Lock          = new AscCommon.CLock();

	// Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
	g_oTableId.Add(this, this.Id);
}

CBlockLevelSdt.prototype = Object.create(CDocumentContentElementBase.prototype);
CBlockLevelSdt.prototype.constructor = CBlockLevelSdt;

CBlockLevelSdt.prototype.Copy = function(Parent)
{
	var oNew = new CBlockLevelSdt(this.LogicDocument, Parent ? Parent : this.Parent);
	oNew.Content.Copy2(this.Content);
	oNew.SetPr(this.Pr);
	return oNew;
};
CBlockLevelSdt.prototype.GetType = function()
{
	return type_BlockLevelSdt;
};
/**
 * Получаем содержимое данного контейнера
 * @returns {CDocumentContent}
 */
CBlockLevelSdt.prototype.GetContent = function()
{
	return this.Content;
};
CBlockLevelSdt.prototype.Is_Inline = function()
{
	return true;
};
CBlockLevelSdt.prototype.Reset = function(X, Y, XLimit, YLimit, PageAbs, ColumnAbs, ColumnsCount)
{
	this.Content.Reset(X, Y, XLimit, YLimit);
	this.Content.Set_StartPage(0);

	this.X            = X;
	this.Y            = Y;
	this.XLimit       = XLimit;
	this.YLimit       = YLimit;
	this.PageNum      = PageAbs;
	this.ColumnNum    = ColumnAbs ? ColumnAbs : 0;
	this.ColumnsCount = ColumnsCount ? ColumnsCount : 1;
};
CBlockLevelSdt.prototype.Recalculate_Page = function(CurPage)
{
	this.Content.RecalcInfo = this.Parent.RecalcInfo;

	var RecalcResult = this.Content.Recalculate_Page(CurPage, true);

	if (recalcresult2_End === RecalcResult)
		return recalcresult_NextElement;
	else if (recalcresult2_NextPage === RecalcResult)
		return recalcresult_NextPage;
	else if (recalcresult2_CurPage === RecalcResult)
		return recalcresult_CurPage;
};
CBlockLevelSdt.prototype.Get_PageBounds = function(CurPage)
{
	return this.Content.Get_PageBounds(CurPage);
};
CBlockLevelSdt.prototype.GetContentBounds = function(CurPage)
{
	return this.Content.GetContentBounds(CurPage);
};
CBlockLevelSdt.prototype.IsEmptyPage = function(nCurPage)
{
	return this.Content.IsEmptyPage(nCurPage);
};
CBlockLevelSdt.prototype.Get_PagesCount = function()
{
	return this.Content.Get_PagesCount();
};
CBlockLevelSdt.prototype.Reset_RecalculateCache = function()
{
	this.Content.Reset_RecalculateCache();
};
CBlockLevelSdt.prototype.Write_ToBinary2 = function(Writer)
{
	Writer.WriteLong(AscDFH.historyitem_type_BlockLevelSdt);
	// String : Id
	// String : Content id
	Writer.WriteString2(this.GetId());
	Writer.WriteString2(this.Content.GetId());
};
CBlockLevelSdt.prototype.Read_FromBinary2 = function(Reader)
{
	this.LogicDocument = editor.WordControl.m_oLogicDocument;

	// String : Id
	// String : Content id
	this.Id      = Reader.GetString2();
	this.Content = this.LogicDocument.Get_TableId().Get_ById(Reader.GetString2());
};
CBlockLevelSdt.prototype.Draw = function(CurPage, oGraphics)
{
	if (this.LogicDocument.GetSdtGlobalShowHighlight() && undefined === oGraphics.RENDERER_PDF_FLAG)
	{
		var oBounds = this.GetContentBounds(CurPage);
		var oColor  = this.LogicDocument.GetSdtGlobalColor();

		oGraphics.b_color1(oColor.r, oColor.g, oColor.b, 255);
		oGraphics.rect(oBounds.Left, oBounds.Top, oBounds.Right - oBounds.Left, oBounds.Bottom - oBounds.Top);
		oGraphics.df();
	}

	this.Content.Draw(CurPage, oGraphics);

	if (AscCommon.locktype_None !== this.Lock.Get_Type())
	{
		var oBounds = this.GetContentBounds(CurPage);
		oGraphics.DrawLockObjectRect(this.Lock.Get_Type(), oBounds.Left, oBounds.Top, oBounds.Right - oBounds.Left, oBounds.Bottom - oBounds.Top);
	}
};
CBlockLevelSdt.prototype.Get_CurrentPage_Absolute = function()
{
	return this.Content.Get_CurrentPage_Absolute();
};
CBlockLevelSdt.prototype.Get_CurrentPage_Relative = function()
{
	return this.Content.Get_CurrentPage_Relative();
};
CBlockLevelSdt.prototype.IsInText = function(X, Y, CurPage)
{
	return this.Content.IsInText(X, Y, CurPage);
};
CBlockLevelSdt.prototype.IsInDrawing = function(X, Y, CurPage)
{
	return this.Content.IsInDrawing(X, Y, CurPage);
};
CBlockLevelSdt.prototype.IsTableBorder = function(X, Y, CurPage)
{
	return this.Content.IsTableBorder(X, Y, CurPage);
};
CBlockLevelSdt.prototype.UpdateCursorType = function(X, Y, CurPage)
{
	var oBounds = this.GetContentBounds(CurPage);
	if (true === this.Lock.Is_Locked() && X < oBounds.Right && X > oBounds.Left && Y > oBounds.Top && Y < oBounds.Bottom)
	{
		var MMData              = new AscCommon.CMouseMoveData();
		var Coords              = this.LogicDocument.DrawingDocument.ConvertCoordsToCursorWR(oBounds.Left, oBounds.Top, this.Get_AbsolutePage(CurPage), this.Get_ParentTextTransform());
		MMData.X_abs            = Coords.X - 5;
		MMData.Y_abs            = Coords.Y;
		MMData.Type             = AscCommon.c_oAscMouseMoveDataTypes.LockedObject;
		MMData.UserId           = this.Lock.Get_UserId();
		MMData.HaveChanges      = this.Lock.Have_Changes();
		MMData.LockedObjectType = c_oAscMouseMoveLockedObjectType.Common;
		this.LogicDocument.Api.sync_MouseMoveCallback(MMData);
	}

	this.DrawContentControlsTrack(true);
	return this.Content.UpdateCursorType(X, Y, CurPage);
};
CBlockLevelSdt.prototype.Selection_SetStart = function(X, Y, CurPage, MouseEvent, isTableBorder)
{
	this.Content.Selection_SetStart(X, Y, CurPage, MouseEvent, isTableBorder);
};
CBlockLevelSdt.prototype.Selection_SetEnd = function(X, Y, CurPage, MouseEvent, isTableBorder)
{
	this.Content.Selection_SetEnd(X, Y, CurPage, MouseEvent, isTableBorder);
};
CBlockLevelSdt.prototype.IsSelectionEmpty = function(isCheckHidden)
{
	return this.Content.IsSelectionEmpty(isCheckHidden);
};
CBlockLevelSdt.prototype.GetSelectedElementsInfo = function(oInfo)
{
	if (!oInfo.IsSkipTOC() || !this.IsBuiltInTableOfContents())
		oInfo.SetBlockLevelSdt(this);

	this.Content.GetSelectedElementsInfo(oInfo);
};
CBlockLevelSdt.prototype.IsSelectionUse = function()
{
	return this.Content.IsSelectionUse();
};
CBlockLevelSdt.prototype.IsSelectionToEnd = function()
{
	return this.Content.IsSelectionToEnd();
};
CBlockLevelSdt.prototype.RemoveSelection = function()
{
	this.Content.RemoveSelection();
};
CBlockLevelSdt.prototype.SetSelectionUse = function(isUse)
{
	this.Content.SetSelectionUse(isUse);
};
CBlockLevelSdt.prototype.SetSelectionToBeginEnd = function(isSelectionStart, isElementStart)
{
	this.Content.SetSelectionToBeginEnd(isSelectionStart, isElementStart);
};
CBlockLevelSdt.prototype.SelectAll = function(nDirection)
{
	this.Content.SelectAll(nDirection);
};
CBlockLevelSdt.prototype.GetCalculatedTextPr = function()
{
	return this.Content.GetCalculatedTextPr();
};
CBlockLevelSdt.prototype.GetCalculatedParaPr = function()
{
	return this.Content.GetCalculatedParaPr();
};
CBlockLevelSdt.prototype.GetDirectParaPr = function()
{
	return this.Content.GetDirectParaPr();
};
CBlockLevelSdt.prototype.GetDirectTextPr = function()
{
	return this.Content.GetDirectTextPr();
};
CBlockLevelSdt.prototype.DrawSelectionOnPage = function(CurPage)
{
	this.Content.DrawSelectionOnPage(CurPage);
};
CBlockLevelSdt.prototype.GetSelectionBounds = function()
{
	return this.Content.GetSelectionBounds();
};
CBlockLevelSdt.prototype.RecalculateCurPos = function(bUpdateX, bUpdateY)
{
	return this.Content.RecalculateCurPos(bUpdateX, bUpdateY);
};
CBlockLevelSdt.prototype.Can_CopyCut = function()
{
	return this.Content.Can_CopyCut();
};
CBlockLevelSdt.prototype.CheckPosInSelection = function(X, Y, CurPage, NearPos)
{
	return this.Content.CheckPosInSelection(X, Y, CurPage, NearPos);
};
CBlockLevelSdt.prototype.Get_NearestPos = function(CurPage, X, Y, bAnchor, Drawing)
{
	return this.Content.Get_NearestPos(CurPage, X, Y, bAnchor, Drawing);
};
CBlockLevelSdt.prototype.CanUpdateTarget = function(CurPage)
{
	return this.Content.CanUpdateTarget(CurPage);
};
CBlockLevelSdt.prototype.MoveCursorLeft = function(AddToSelect, Word)
{
	var bResult = this.Content.MoveCursorLeft(AddToSelect, Word);
	if (!bResult && this.LogicDocument.IsFillingFormMode())
		return true;

	return bResult;
};
CBlockLevelSdt.prototype.MoveCursorLeftWithSelectionFromEnd = function(Word)
{
	return this.Content.MoveCursorLeftWithSelectionFromEnd(Word);
};
CBlockLevelSdt.prototype.MoveCursorRight = function(AddToSelect, Word)
{
	var bResult = this.Content.MoveCursorRight(AddToSelect, Word, false);
	if (!bResult && this.LogicDocument.IsFillingFormMode())
		return true;

	return bResult;
};
CBlockLevelSdt.prototype.MoveCursorRightWithSelectionFromStart = function(Word)
{
	return this.Content.MoveCursorRightWithSelectionFromStart(Word);
};
CBlockLevelSdt.prototype.MoveCursorToStartPos = function(AddToSelect)
{
	return this.Content.MoveCursorToStartPos(AddToSelect);
};
CBlockLevelSdt.prototype.MoveCursorToEndPos = function(AddToSelect, StartSelectFromEnd)
{
	return this.Content.MoveCursorToEndPos(AddToSelect, StartSelectFromEnd);
};
CBlockLevelSdt.prototype.MoveCursorUp = function(AddToSelect)
{
	return this.Content.MoveCursorUp(AddToSelect);
};
CBlockLevelSdt.prototype.MoveCursorUpToLastRow = function(X, Y, AddToSelect)
{
	return this.Content.MoveCursorUpToLastRow(X, Y, AddToSelect);
};
CBlockLevelSdt.prototype.MoveCursorDown = function(AddToSelect)
{
	return this.Content.MoveCursorDown(AddToSelect);
};
CBlockLevelSdt.prototype.MoveCursorDownToFirstRow = function(X, Y, AddToSelect)
{
	return this.Content.MoveCursorDownToFirstRow(X, Y, AddToSelect);
};
CBlockLevelSdt.prototype.MoveCursorToEndOfLine = function(AddToSelect)
{
	return this.Content.MoveCursorToEndOfLine(AddToSelect);
};
CBlockLevelSdt.prototype.MoveCursorToStartOfLine = function(AddToSelect)
{
	return this.Content.MoveCursorToStartOfLine(AddToSelect);
};
CBlockLevelSdt.prototype.MoveCursorToXY = function(X, Y, bLine, bDontChangeRealPos, CurPage)
{
	return this.Content.MoveCursorToXY(X, Y, bLine, bDontChangeRealPos, CurPage);
};
CBlockLevelSdt.prototype.MoveCursorToCell = function(bNext)
{
	return this.Content.MoveCursorToCell(bNext);
};
CBlockLevelSdt.prototype.GetSelectionState = function()
{
	return this.Content.GetSelectionState();
};
CBlockLevelSdt.prototype.SetSelectionState = function(State, StateIndex)
{
	return this.Content.SetSelectionState(State, StateIndex);
};
CBlockLevelSdt.prototype.IsCursorAtBegin = function(bOnlyPara)
{
	return this.Content.IsCursorAtBegin(bOnlyPara);
};
CBlockLevelSdt.prototype.IsCursorAtEnd = function()
{
	return this.Content.IsCursorAtEnd();
};
CBlockLevelSdt.prototype.AddNewParagraph = function()
{
	return this.Content.AddNewParagraph();
};
CBlockLevelSdt.prototype.Get_SelectionState2 = function()
{
	var oState  = new CDocumentSelectionState();
	oState.Id   = this.GetId();
	oState.Data = this.Content.Get_SelectionState2();
	return oState;
};
CBlockLevelSdt.prototype.Set_SelectionState2 = function(State)
{
	if (State.Data)
		this.Content.Set_SelectionState2(State.Data);
};
CBlockLevelSdt.prototype.IsStartFromNewPage = function()
{
	this.Content.IsStartFromNewPage();
};
CBlockLevelSdt.prototype.GetAllParagraphs = function(Props, ParaArray)
{
	return this.Content.GetAllParagraphs(Props, ParaArray);
};
CBlockLevelSdt.prototype.SetContentSelection = function(StartDocPos, EndDocPos, Depth, StartFlag, EndFlag)
{
	this.Content.SetContentSelection(StartDocPos, EndDocPos, Depth, StartFlag, EndFlag);
};
CBlockLevelSdt.prototype.GetContentPosition = function(bSelection, bStart, PosArray)
{
	return this.Content.GetContentPosition(bSelection, bStart, PosArray);
};
CBlockLevelSdt.prototype.SetContentPosition = function(DocPos, Depth, Flag)
{
	this.Content.SetContentPosition(DocPos, Depth, Flag);
};
CBlockLevelSdt.prototype.GetNumberingInfo = function(oNumberingEngine)
{
	return this.Content.GetNumberingInfo(oNumberingEngine);
};
CBlockLevelSdt.prototype.AddInlineImage = function(W, H, Img, Chart, bFlow)
{
	this.Content.AddInlineImage(W, H, Img, Chart, bFlow);
};
CBlockLevelSdt.prototype.AddImages = function(aImages)
{
	this.Content.AddImages(aImages);
};
CBlockLevelSdt.prototype.AddSignatureLine = function(oSignatureDrawing)
{
	this.Content.AddSignatureLine(oSignatureDrawing);
};
CBlockLevelSdt.prototype.AddOleObject = function(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId)
{
	this.Content.AddOleObject(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId);
};
CBlockLevelSdt.prototype.AddTextArt = function(nStyle)
{
	this.Content.AddTextArt(nStyle);
};
CBlockLevelSdt.prototype.AddInlineTable = function(nCols, nRows)
{
	this.Content.AddInlineTable(nCols, nRows);
};
CBlockLevelSdt.prototype.Remove = function(nCount, bOnlyText, bRemoveOnlySelection, bOnAddText)
{
	var Res = this.Content.Remove(nCount, bOnlyText, bRemoveOnlySelection, bOnAddText);

	if (this.Is_Empty() && !bOnAddText && this.LogicDocument && true === this.LogicDocument.IsFillingFormMode())
	{
		var oParagraph = new Paragraph(this.LogicDocument.Get_DrawingDocument(), this.Content);
		this.Content.Add_ToContent(0, oParagraph);
		this.Content.Remove_FromContent(1, this.Content.GetElementsCount() - 1);
		this.Content.MoveCursorToStartPos(false);
		return true;
	}

	return Res;
};
CBlockLevelSdt.prototype.Is_Empty = function()
{
	return this.Content.Is_Empty();
};
CBlockLevelSdt.prototype.Add = function(oParaItem)
{
	return this.Content.AddToParagraph(oParaItem);
};
CBlockLevelSdt.prototype.PreDelete = function()
{
	this.Content.PreDelete();
};
CBlockLevelSdt.prototype.ClearParagraphFormatting = function(isClearParaPr, isClearTextPr)
{
	this.Content.ClearParagraphFormatting(isClearParaPr, isClearTextPr);
};
CBlockLevelSdt.prototype.GetCursorPosXY = function()
{
	return this.Content.GetCursorPosXY();
};
CBlockLevelSdt.prototype.StartSelectionFromCurPos = function()
{
	this.Content.StartSelectionFromCurPos();
};
CBlockLevelSdt.prototype.SetParagraphAlign = function(Align)
{
	return this.Content.SetParagraphAlign(Align);
};
CBlockLevelSdt.prototype.SetParagraphSpacing = function(Spacing)
{
	return this.Content.SetParagraphSpacing(Spacing);
};
CBlockLevelSdt.prototype.SetParagraphTabs = function(Tabs)
{
	return this.Content.SetParagraphTabs(Tabs);
};
CBlockLevelSdt.prototype.SetParagraphIndent = function(Ind)
{
	return this.Content.SetParagraphIndent(Ind);
};
CBlockLevelSdt.prototype.SetParagraphShd = function(Shd)
{
	return this.Content.SetParagraphShd(Shd);
};
CBlockLevelSdt.prototype.SetParagraphStyle = function(Name)
{
	return this.Content.SetParagraphStyle(Name);
};
CBlockLevelSdt.prototype.SetParagraphContextualSpacing = function(Value)
{
	return this.Content.SetParagraphContextualSpacing(Value);
};
CBlockLevelSdt.prototype.SetParagraphPageBreakBefore = function(Value)
{
	return this.Content.SetParagraphPageBreakBefore(Value);
};
CBlockLevelSdt.prototype.SetParagraphKeepLines = function(Value)
{
	return this.Content.SetParagraphKeepLines(Value);
};
CBlockLevelSdt.prototype.SetParagraphKeepNext = function(Value)
{
	return this.Content.SetParagraphKeepNext(Value);
};
CBlockLevelSdt.prototype.SetParagraphWidowControl = function(Value)
{
	return this.Content.SetParagraphWidowControl(Value);
};
CBlockLevelSdt.prototype.SetParagraphBorders = function(Borders)
{
	return this.Content.SetParagraphBorders(Borders);
};
CBlockLevelSdt.prototype.SetParagraphFramePr = function(FramePr, bDelete)
{
	return this.Content.SetParagraphFramePr(FramePr, bDelete);
};
CBlockLevelSdt.prototype.IncreaseDecreaseFontSize = function(bIncrease)
{
	return this.Content.IncreaseDecreaseFontSize(bIncrease);
};
CBlockLevelSdt.prototype.IncreaseDecreaseIndent = function(bIncrease)
{
	return this.Content.IncreaseDecreaseIndent(bIncrease);
};
CBlockLevelSdt.prototype.SetImageProps = function(oProps)
{
	return this.Content.SetImageProps(oProps);
};
CBlockLevelSdt.prototype.SetTableProps = function(oProps)
{
	return this.Content.SetTableProps(oProps);
};
CBlockLevelSdt.prototype.GetSelectedContent = function(oSelectedContent)
{
	if (this.Content.IsSelectedAll())
	{
		oSelectedContent.Add(new CSelectedElement(this.Copy(this.Parent)));
	}
	else
	{
		return this.Content.GetSelectedContent(oSelectedContent);
	}
};
CBlockLevelSdt.prototype.PasteFormatting = function(TextPr, ParaPr, ApplyPara)
{
	return this.Content.PasteFormatting(TextPr, ParaPr, ApplyPara);
};
CBlockLevelSdt.prototype.GetCurPosXY = function()
{
	return this.Content.GetCurPosXY();
};
CBlockLevelSdt.prototype.GetSelectedText = function(bClearText, oPr)
{
	return this.Content.GetSelectedText(bClearText, oPr);
};
CBlockLevelSdt.prototype.GetCurrentParagraph = function(bIgnoreSelection, arrSelectedParagraphs)
{
	return this.Content.GetCurrentParagraph(bIgnoreSelection, arrSelectedParagraphs);
};
CBlockLevelSdt.prototype.AddTableRow = function(bBefore)
{
	return this.Content.AddTableRow(bBefore);
};
CBlockLevelSdt.prototype.AddTableColumn = function(bBefore)
{
	return this.Content.AddTableColumn(bBefore);
};
CBlockLevelSdt.prototype.RemoveTableRow = function(nRowIndex)
{
	return this.Content.RemoveTableRow(nRowIndex);
};
CBlockLevelSdt.prototype.RemoveTableColumn = function()
{
	return this.Content.RemoveTableColumn();
};
CBlockLevelSdt.prototype.MergeTableCells = function()
{
	return this.Content.MergeTableCells();
};
CBlockLevelSdt.prototype.SplitTableCells = function(nColsCount, nRowsCount)
{
	return this.Content.SplitTableCells(nColsCount, nRowsCount);
};
CBlockLevelSdt.prototype.RemoveTable = function()
{
	return this.Content.RemoveTable();
};
CBlockLevelSdt.prototype.SelectTable = function(Type)
{
	return this.Content.SelectTable(Type);
};
CBlockLevelSdt.prototype.CanMergeTableCells = function()
{
	return this.Content.CanMergeTableCells();
};
CBlockLevelSdt.prototype.CanSplitTableCells = function()
{
	return this.Content.CanSplitTableCells();
};
CBlockLevelSdt.prototype.DistributeTableCells = function(isHorizontally)
{
	return this.Content.DistributeTableCells(isHorizontally);
};
CBlockLevelSdt.prototype.Document_UpdateInterfaceState = function()
{
	if (!this.IsBuiltInTableOfContents())
		this.LogicDocument.Api.sync_ContentControlCallback(this.GetContentControlPr());

	this.Content.Document_UpdateInterfaceState();
};
CBlockLevelSdt.prototype.Document_UpdateRulersState = function(CurPage)
{
	this.Content.Document_UpdateRulersState(CurPage);
};
CBlockLevelSdt.prototype.GetTableProps = function()
{
	return this.Content.GetTableProps();
};
CBlockLevelSdt.prototype.AddHyperlink = function(Props)
{
	return this.Content.AddHyperlink(Props);
};
CBlockLevelSdt.prototype.ModifyHyperlink = function(Props)
{
	this.Content.ModifyHyperlink(Props);
};
CBlockLevelSdt.prototype.RemoveHyperlink = function()
{
	this.Content.RemoveHyperlink();
};
CBlockLevelSdt.prototype.CanAddHyperlink = function(bCheckInHyperlink)
{
	return this.Content.CanAddHyperlink(bCheckInHyperlink);
};
CBlockLevelSdt.prototype.IsCursorInHyperlink = function(bCheckEnd)
{
	return this.Content.IsCursorInHyperlink(bCheckEnd);
};
CBlockLevelSdt.prototype.AddComment = function(Comment, bStart, bEnd)
{
	return this.Content.AddComment(Comment, bStart, bEnd);
};
CBlockLevelSdt.prototype.CanAddComment = function()
{
	return this.Content.CanAddComment();
};
CBlockLevelSdt.prototype.GetSelectionAnchorPos = function()
{
	return this.Content.GetSelectionAnchorPos();
};
CBlockLevelSdt.prototype.DrawContentControlsTrack = function(isHover)
{
	var oDrawingDocument = this.LogicDocument.Get_DrawingDocument();
	var arrRects = [];

	if (Asc.c_oAscSdtAppearance.Hidden === this.GetAppearance())
	{
		oDrawingDocument.OnDrawContentControl(null, isHover ? c_oContentControlTrack.Hover : c_oContentControlTrack.In);
		return;
	}

	for (var nCurPage = 0, nPagesCount = this.GetPagesCount(); nCurPage < nPagesCount; ++nCurPage)
	{
		if (this.IsEmptyPage(nCurPage))
			continue;

		var nPageAbs = this.Get_AbsolutePage(nCurPage);
		var oBounds = this.Content.GetContentBounds(nCurPage);
		arrRects.push({X : oBounds.Left, Y : oBounds.Top, R : oBounds.Right, B : oBounds.Bottom, Page : nPageAbs});
	}

	var sName      = this.GetAlias();
	var isBuiltIn  = false;
	var arrButtons = [];

	if (this.IsBuiltInTableOfContents())
	{
		sName      = AscCommon.translateManager.getValue("Table of Contents");
		isBuiltIn  = true;
		arrButtons.push(1);
	}

	oDrawingDocument.OnDrawContentControl(this.GetId(), isHover ? c_oContentControlTrack.Hover : c_oContentControlTrack.In, arrRects, this.Get_ParentTextTransform(), sName, isBuiltIn, arrButtons, this.GetColor());
};
CBlockLevelSdt.prototype.AddContentControl = function(nContentControlType)
{
	return this.Content.AddContentControl(nContentControlType);
};
CBlockLevelSdt.prototype.RecalculateMinMaxContentWidth = function(isRotated)
{
	return this.Content.RecalculateMinMaxContentWidth(isRotated);
};
CBlockLevelSdt.prototype.Shift = function(CurPage, dX, dY)
{
	this.Content.Shift(CurPage, dX, dY);
};
CBlockLevelSdt.prototype.UpdateEndInfo = function()
{
	this.Content.UpdateEndInfo();
};
CBlockLevelSdt.prototype.PrepareRecalculateObject = function()
{
	this.Content.PrepareRecalculateObject();
};
CBlockLevelSdt.prototype.SaveRecalculateObject = function()
{
	return this.Content.SaveRecalculateObject();
};
CBlockLevelSdt.prototype.LoadRecalculateObject = function(RecalcObj)
{
	return this.Content.LoadRecalculateObject(RecalcObj);
};
CBlockLevelSdt.prototype.Set_ApplyToAll = function(bValue)
{
	this.Content.Set_ApplyToAll(bValue);
};
CBlockLevelSdt.prototype.RecalculateAllTables = function()
{
	this.Content.RecalculateAllTables();
};
CBlockLevelSdt.prototype.GetAllFloatElements = function(FloatObjects)
{
	return this.Content.GetAllFloatElements(FloatObjects);
};
CBlockLevelSdt.prototype.Get_FirstParagraph = function()
{
	return this.Content.Get_FirstParagraph();
};
CBlockLevelSdt.prototype.StartFromNewPage = function()
{
	this.Content.StartFromNewPage();
};
CBlockLevelSdt.prototype.CollectDocumentStatistics = function(Stats)
{
	return this.Content.CollectDocumentStatistics(Stats);
};
CBlockLevelSdt.prototype.CompareDrawingsLogicPositions = function(CompareObject)
{
	return this.Content.CompareDrawingsLogicPositions(CompareObject);
};
CBlockLevelSdt.prototype.GetStyleFromFormatting = function()
{
	return this.Content.GetStyleFromFormatting();
};
CBlockLevelSdt.prototype.GetAllContentControls = function(arrContentControls)
{
	arrContentControls.push(this);
	this.Content.GetAllContentControls(arrContentControls);
};
CBlockLevelSdt.prototype.IsSelectedAll = function()
{
	return this.Content.IsSelectedAll();
};
CBlockLevelSdt.prototype.GetLastRangeVisibleBounds = function()
{
	return this.Content.GetLastRangeVisibleBounds();
};
CBlockLevelSdt.prototype.FindNextFillingForm = function(isNext, isCurrent, isStart)
{
	if (isCurrent && true === this.IsSelectedAll())
	{
		if (isNext)
			return this.Content.FindNextFillingForm(isNext, isCurrent, isStart);

		return null;
	}

	if (!isCurrent && isNext)
		return this;

	var oRes = this.Content.FindNextFillingForm(isNext, isCurrent, isStart);
	if (oRes)
		return oRes;

	if (!isNext)
		return this;

	return null;
};
CBlockLevelSdt.prototype.GetRevisionsChangeParagraph = function(SearchEngine)
{
	return this.Content.GetRevisionsChangeParagraph(SearchEngine);
};
CBlockLevelSdt.prototype.AcceptRevisionChanges = function(Type, bAll)
{
	this.Content.AcceptRevisionChanges(Type, bAll);
};
CBlockLevelSdt.prototype.RejectRevisionChanges = function(Type, bAll)
{
	this.Content.RejectRevisionChanges(Type, bAll);
};
CBlockLevelSdt.prototype.IsContentOnFirstPage = function()
{
	return this.Content.IsContentOnFirstPage();
};
//----------------------------------------------------------------------------------------------------------------------
CBlockLevelSdt.prototype.IsHdrFtr = function(bReturnHdrFtr)
{
	return this.Parent.IsHdrFtr(bReturnHdrFtr);
};
CBlockLevelSdt.prototype.IsFootnote = function(bReturnFootnote)
{
	return this.Parent.IsFootnote(bReturnFootnote);
};
CBlockLevelSdt.prototype.Is_TopDocument = function(bReturnTopDocument)
{
	return this.Parent.Is_TopDocument(bReturnTopDocument);
};
CBlockLevelSdt.prototype.IsCell = function(isReturnCell)
{
	return this.Parent.IsTableCellContent(isReturnCell);
};
CBlockLevelSdt.prototype.Is_DrawingShape = function()
{
	return this.Parent.Is_DrawingShape();
};
CBlockLevelSdt.prototype.Get_Numbering = function()
{
	return this.LogicDocument.Get_Numbering();
};
CBlockLevelSdt.prototype.Get_Styles = function()
{
	return this.LogicDocument.Get_Styles();
};
CBlockLevelSdt.prototype.Get_TableStyleForPara = function()
{
	return this.Parent.Get_TableStyleForPara();
};
CBlockLevelSdt.prototype.Get_ShapeStyleForPara = function()
{
	return this.Parent.Get_ShapeStyleForPara();
};
CBlockLevelSdt.prototype.Get_Theme = function()
{
	return this.Parent.Get_Theme();
};
CBlockLevelSdt.prototype.GetPrevElementEndInfo = function()
{
	return this.Parent.GetPrevElementEndInfo(this);
};
CBlockLevelSdt.prototype.GetEndInfo = function()
{
	return this.Content.GetEndInfo();
};
CBlockLevelSdt.prototype.Is_UseInDocument = function(Id)
{
	if (Id === this.Content.GetId())
		return this.Parent.Is_UseInDocument(this.GetId());

	return false;
};
CBlockLevelSdt.prototype.Get_ColorMap = function()
{
	return this.Parent.Get_ColorMap();
};
CBlockLevelSdt.prototype.Get_TextBackGroundColor = function()
{
	return this.Parent.Get_TextBackGroundColor();
};
CBlockLevelSdt.prototype.Is_ThisElementCurrent = function(oElement)
{
	if (oElement === this.Content)
		return this.Parent.Is_ThisElementCurrent();

	return false;
};
CBlockLevelSdt.prototype.OnContentReDraw = function(StartPageAbs, EndPageAbs)
{
	this.Parent.OnContentReDraw(StartPageAbs, EndPageAbs);
};
CBlockLevelSdt.prototype.Document_CreateFontMap = function(FontMap)
{
	this.Content.Document_CreateFontMap(FontMap);
};
CBlockLevelSdt.prototype.Document_CreateFontCharMap = function(FontCharMap)
{
	this.Content.Document_CreateFontCharMap(FontCharMap);
};
CBlockLevelSdt.prototype.Document_Get_AllFontNames = function(AllFonts)
{
	this.Content.Document_Get_AllFontNames(AllFonts);
};
CBlockLevelSdt.prototype.Get_ParentTextTransform = function()
{
	return this.Parent.Get_ParentTextTransform();
};
CBlockLevelSdt.prototype.Set_CurrentElement = function(bUpdateStates, PageAbs, oDocContent)
{
	if (oDocContent === this.Content)
	{
		this.Parent.Update_ContentIndexing();
		this.Parent.Set_CurrentElement(this.Index, bUpdateStates);
	}
};
CBlockLevelSdt.prototype.Refresh_RecalcData2 = function(CurPage)
{
	this.Parent.Refresh_RecalcData2(this.Index, CurPage);
};
CBlockLevelSdt.prototype.Refresh_RecalcData = function(Data)
{
};
CBlockLevelSdt.prototype.Check_AutoFit = function()
{
	return this.Parent.Check_AutoFit();
};
CBlockLevelSdt.prototype.Is_InTable = function(bReturnTopTable)
{
	return this.Parent.Is_InTable(bReturnTopTable);
};
CBlockLevelSdt.prototype.Get_PageContentStartPos = function(CurPage)
{
	var StartPage   = this.Get_AbsolutePage(0);
	var StartColumn = this.Get_AbsoluteColumn(0);

	if (this.Parent instanceof CDocumentContent)
	{
		StartPage   = this.Parent.Get_AbsolutePage(0) - StartPage;
		StartColumn = this.Parent.StartColumn;

		// Такого не должно быть, но на всякий случай
		if (StartPage < 0)
			StartPage = 0;
	}

	return this.Parent.Get_PageContentStartPos2(StartPage, StartColumn, CurPage, this.Index);
};
CBlockLevelSdt.prototype.CheckTableCoincidence = function(Table)
{
	return this.Parent.CheckTableCoincidence(Table);
};
CBlockLevelSdt.prototype.CheckRange = function(X0, Y0, X1, Y1, _Y0, _Y1, X_lf, X_rf, CurPage, Inner, bMathWrap)
{
	if (true === Inner)
	{
		var PageRel = this.Get_AbsolutePage(CurPage) - this.Get_AbsolutePage(0) + this.Get_StartPage_Relative();
		return this.Parent.CheckRange(X0, Y0, X1, Y1, _Y0, _Y1, X_lf, X_rf, PageRel, Inner, bMathWrap);
	}
	else
	{
		return this.Content.CheckRange(X0, Y0, X1, Y1, _Y0, _Y1, X_lf, X_rf, CurPage, Inner, bMathWrap);
	}
};
CBlockLevelSdt.prototype.GetTopDocumentContent = function()
{
	return this.Parent.GetTopDocumentContent();
};
CBlockLevelSdt.prototype.GetAllDrawingObjects = function(AllDrawingObjects)
{
	return this.Content.GetAllDrawingObjects(AllDrawingObjects);
};
CBlockLevelSdt.prototype.GetAllComments = function(AllComments)
{
	return this.Content.GetAllComments(AllComments);
};
CBlockLevelSdt.prototype.GetAllMaths = function(AllMaths)
{
	return this.Content.GetAllMaths(AllMaths);
};
CBlockLevelSdt.prototype.Get_ParentTextTransform = function()
{
	return this.Parent.Get_ParentTextTransform();
};
CBlockLevelSdt.prototype.Get_SectPr = function()
{
	if (this.Parent && this.Parent.Get_SectPr)
	{
		this.Parent.Update_ContentIndexing();
		return this.Parent.Get_SectPr(this.Index);
	}

	return null;
};
CBlockLevelSdt.prototype.GetTopElement = function()
{
	if (true === this.Parent.Is_TopDocument(false))
		return this;

	return this.Parent.GetTopElement();
};
CBlockLevelSdt.prototype.GetMargins = function()
{
	return this.Parent.GetMargins();
};
CBlockLevelSdt.prototype.SelectContentControl = function()
{
	this.SelectAll(1);
	this.Set_CurrentElement(false, 0, this.Content);
};
CBlockLevelSdt.prototype.SetThisElementCurrent = function()
{
	this.Set_CurrentElement(false, 0, this.Content);
};
CBlockLevelSdt.prototype.RemoveContentControlWrapper = function()
{
	if (!this.Parent)
		return;

	this.Parent.Update_ContentIndexing();
	var nElementPos = this.GetIndex();

	if (this.Parent.Content[nElementPos] !== this)
		return;

	var nParentCurPos            = this.Parent.CurPos.ContentPos;
	var nParentSelectionStartPos = this.Parent.Selection.StartPos;
	var nParentSelectionEndPos   = this.Parent.Selection.EndPos;

	this.Parent.Remove_FromContent(nElementPos, 1);
	for (var nIndex = 0, nCount = this.Content.Content.length; nIndex < nCount; ++nIndex)
	{
		this.Parent.Add_ToContent(nElementPos + nIndex, this.Content.Content[nIndex]);
	}

	if (nParentCurPos === nElementPos)
		this.Parent.CurPos.ContentPos = nParentCurPos + this.Content.CurPos.ContentPos;
	else if (nParentCurPos > nElementPos)
		this.Parent.CurPos.ContentPos = nParentCurPos + nCount - 1;

	if (nParentSelectionStartPos === nElementPos)
		this.Parent.Selection.StartPos = nParentSelectionStartPos + this.Content.Selection.StartPos;
	else if (nParentSelectionStartPos > nElementPos)
		this.Parent.Selection.StartPos = nParentSelectionStartPos + nCount - 1;

	if (nParentSelectionEndPos === nElementPos)
		this.Parent.Selection.EndPos = nParentSelectionEndPos + this.Content.Selection.EndPos;
	else if (nParentSelectionEndPos > nElementPos)
		this.Parent.Selection.EndPos = nParentSelectionEndPos + nCount - 1;

	this.Content.Remove_FromContent(0, this.Content.Content.length - 1);
};
CBlockLevelSdt.prototype.IsTableFirstRowOnNewPage = function()
{
	return this.Parent.IsTableFirstRowOnNewPage();
};
CBlockLevelSdt.prototype.UpdateBookmarks = function(oManager)
{
	this.Content.UpdateBookmarks(oManager);
};
CBlockLevelSdt.prototype.GetSimilarNumbering = function(oContinueEngine)
{
	if (oContinueEngine.IsFound())
		return;

	this.Content.GetSimilarNumbering(oContinueEngine);
};
CBlockLevelSdt.prototype.GetTableOfContents = function(isUnique, isCheckFields)
{
	if (this.IsBuiltInTableOfContents() && (!isUnique || this.IsBuiltInUnique()))
		return this;

	return this.Content.GetTableOfContents(isCheckFields);
};
CBlockLevelSdt.prototype.GetInnerTableOfContents = function()
{
	var oTOC = this.Content.GetTableOfContents(false, true);
	if (oTOC instanceof CBlockLevelSdt)
		return oTOC.GetInnerTableOfContents();

	return oTOC;
};
CBlockLevelSdt.prototype.IsBlockLevelSdtFirstOnNewPage = function()
{
	if (null !== this.Get_DocumentPrev()
		|| (true === this.Parent.IsTableCellContent() && true !== this.Parent.IsTableFirstRowOnNewPage())
		|| (true === this.Parent.IsBlockLevelSdtContent() && true !== this.Parent.IsBlockLevelSdtFirstOnNewPage()))
		return false;

	return true;
};
//----------------------------------------------------------------------------------------------------------------------
CBlockLevelSdt.prototype.GetContentControlType = function()
{
	return c_oAscSdtLevelType.Block;
};
CBlockLevelSdt.prototype.SetPr = function(oPr)
{
	if (!oPr || this.IsBuiltInTableOfContents())
		return;

	this.SetAlias(oPr.Alias);
	this.SetTag(oPr.Tag);
	this.SetLabel(oPr.Label);
	this.SetContentControlLock(oPr.Lock);
	this.SetContentControlId(oPr.Id);

	if (undefined !== oPr.DocPartObj)
		this.SetDocPartObj(oPr.DocPartObj.Category, oPr.DocPartObj.Gallery, oPr.DocPartObj.Unique);

	if (undefined !== oPr.Appearance)
		this.SetAppearance(oPr.Appearance);

	if (undefined !== oPr.Color)
		this.SetColor(oPr.Color);
};
CBlockLevelSdt.prototype.SetAlias = function(sAlias)
{
	if (sAlias !== this.Pr.Alias)
	{
		History.Add(new CChangesSdtPrAlias(this, this.Pr.Alias, sAlias));
		this.Pr.Alias = sAlias;
	}
};
CBlockLevelSdt.prototype.GetAlias = function()
{
	return (undefined !== this.Pr.Alias ? this.Pr.Alias : "");
};
CBlockLevelSdt.prototype.SetContentControlId = function(Id)
{
	if (this.Pr.Id !== Id)
	{
		History.Add(new CChangesSdtPrId(this, this.Pr.Id, Id));
		this.Pr.Id = Id;
	}
};
CBlockLevelSdt.prototype.GetContentControlId = function()
{
	return this.Pr.Id;
};
CBlockLevelSdt.prototype.SetTag = function(sTag)
{
	if (this.Pr.Tag !== sTag)
	{
		History.Add(new CChangesSdtPrTag(this, this.Pr.Tag, sTag));
		this.Pr.Tag = sTag;
	}
};
CBlockLevelSdt.prototype.GetTag = function()
{
	return (undefined !== this.Pr.Tag ? this.Pr.Tag : "");
};
CBlockLevelSdt.prototype.SetLabel = function(sLabel)
{
	if (this.Pr.Label !== sLabel)
	{
		History.Add(new CChangesSdtPrLabel(this, this.Pr.Label, sLabel));
		this.Pr.Label = sLabel;
	}
};
CBlockLevelSdt.prototype.GetLabel = function()
{
	return (undefined !== this.Pr.Label ? this.Pr.Label : "");
};
CBlockLevelSdt.prototype.SetAppearance = function(nType)
{
	if (this.Pr.Appearance !== nType)
	{
		History.Add(new CChangesSdtPrAppearance(this, this.Pr.Appearance, nType));
		this.Pr.Appearance = nType;
	}
};
CBlockLevelSdt.prototype.GetAppearance = function()
{
	return this.Pr.Appearance;
};
CBlockLevelSdt.prototype.SetColor = function(oColor)
{
	if (null === oColor || undefined === oColor)
	{
		if (undefined !== this.Pr.Color)
		{
			History.Add(new CChangesSdtPrColor(this, this.Pr.Color, undefined));
			this.Pr.Color = undefined;
		}
	}
	else
	{
		History.Add(new CChangesSdtPrColor(this, this.Pr.Color, oColor));
		this.Pr.Color = oColor;
	}
};
CBlockLevelSdt.prototype.GetColor = function()
{
	return this.Pr.Color;
};
CBlockLevelSdt.prototype.SetDocPartObj = function(sCategory, sGallery, isUnique)
{
	History.Add(new CChangesSdtPrDocPartObj(this, this.Pr.DocPartObj, {Category : sCategory, Gallery : sGallery, Unique : isUnique}));
	this.Pr.DocPartObj.Category = sCategory;
	this.Pr.DocPartObj.Gallery  = sGallery;
	this.Pr.DocPartObj.Unique   = isUnique;
};
CBlockLevelSdt.prototype.IsBuiltInTableOfContents = function()
{
	return this.Pr.DocPartObj.Gallery === "Table of Contents";
};
CBlockLevelSdt.prototype.IsBuiltInUnique = function()
{
	return true === this.Pr.DocPartObj.Unique;
};
CBlockLevelSdt.prototype.SetContentControlLock = function(nLockType)
{
	if (this.Pr.Lock !== nLockType)
	{
		History.Add(new CChangesSdtPrLock(this, this.Pr.Lock, nLockType));
		this.Pr.Lock = nLockType;
	}
};
CBlockLevelSdt.prototype.GetContentControlLock = function()
{
	return (undefined !== this.Pr.Lock ? this.Pr.Lock : c_oAscSdtLockType.Unlocked);
};
CBlockLevelSdt.prototype.SetContentControlPr = function(oPr)
{
	if (!oPr || this.IsBuiltInTableOfContents())
		return;

	if (undefined !== oPr.Tag)
		this.SetTag(oPr.Tag);

	if (undefined !== oPr.Id)
		this.SetContentControlId(oPr.Id);

	if (undefined !== oPr.Lock)
		this.SetContentControlLock(oPr.Lock);

	if (undefined !== oPr.Alias)
		this.SetAlias(oPr.Alias);

	if (undefined !== oPr.Appearance)
		this.SetAppearance(oPr.Appearance);

	if (undefined !== oPr.Color)
		this.SetColor(oPr.Color);
};
CBlockLevelSdt.prototype.GetContentControlPr = function()
{
	var oPr = new CContentControlPr(c_oAscSdtLevelType.Block);

	oPr.Tag        = this.GetTag();
	oPr.Id         = this.Pr.Id;
	oPr.Lock       = this.Pr.Lock;
	oPr.InternalId = this.GetId();
	oPr.Alias      = this.GetAlias();
	oPr.Appearance = this.GetAppearance();
	oPr.Color      = this.GetColor();

	return oPr;
};
CBlockLevelSdt.prototype.Restart_CheckSpelling = function()
{
	this.Content.Restart_CheckSpelling();
};
CBlockLevelSdt.prototype.ClearContentControl = function()
{
	var oPara = new Paragraph(this.LogicDocument.Get_DrawingDocument(), this.Content);
	oPara.Correct_Content();

	this.Content.Add_ToContent(0, oPara);
	this.Content.Remove_FromContent(1, this.Content.GetElementsCount() - 1);
	this.Content.MoveCursorToStartPos(false);
};
CBlockLevelSdt.prototype.GotoFootnoteRef = function(isNext, isCurrent)
{
	return this.Content.GotoFootnoteRef(isNext, isCurrent);
};
/**
 * Получаем последний элемент содержимого
 * @returns {?CDocumentContentElementBase}
 */
CBlockLevelSdt.prototype.GetLastElement = function()
{
	var nCount = this.Content.GetElementsCount();
	if (nCount <= 0)
		return null;

	return this.Content.GetElement(nCount - 1);
};
CBlockLevelSdt.prototype.GetLastParagraph = function()
{
	return this.Content.GetLastParagraph();
};
CBlockLevelSdt.prototype.GetOutlineParagraphs = function(arrOutline, oPr)
{
	this.Content.GetOutlineParagraphs(arrOutline, oPr);
};
CBlockLevelSdt.prototype.IsLastTableCellInRow = function(isSelection)
{
	return this.Parent.IsLastTableCellInRow(isSelection);
};
//--------------------------------------------------------export--------------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CBlockLevelSdt = CBlockLevelSdt;
window['AscCommonWord'].type_BlockLevelSdt = type_BlockLevelSdt;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 11.05.2017
 * Time: 16:48
 */

/**
 * @constructor
 * @extends {CParagraphContentWithParagraphLikeContent}
 */
function CInlineLevelSdt()
{
	this.Id = AscCommon.g_oIdCounter.Get_NewId();

	CParagraphContentWithParagraphLikeContent.call(this);

	this.Pr   = new CSdtPr();
	this.Type = para_InlineLevelSdt;

	this.BoundsPaths          = null;
	this.BoundsPathsStartPage = -1;

	// Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
	g_oTableId.Add(this, this.Id);
}

CInlineLevelSdt.prototype = Object.create(CParagraphContentWithParagraphLikeContent.prototype);
CInlineLevelSdt.prototype.constructor = CInlineLevelSdt;


CInlineLevelSdt.prototype.Get_Id = function()
{
	return this.Id;
};
CInlineLevelSdt.prototype.GetId = function()
{
	return this.Get_Id();
};
CInlineLevelSdt.prototype.Copy = function(Selected, oPr)
{
	var oContentControl = CParagraphContentWithParagraphLikeContent.prototype.Copy.apply(this, arguments);

	oContentControl.SetLabel(this.GetLabel());
	oContentControl.SetTag(this.GetTag());
	oContentControl.SetAlias(this.GetAlias());
	oContentControl.SetContentControlLock(this.GetContentControlLock());
	oContentControl.SetAppearance(this.GetAppearance());
	oContentControl.SetColor(this.GetColor());

	return oContentControl;
};
CInlineLevelSdt.prototype.GetSelectedElementsInfo = function(Info)
{
	Info.SetInlineLevelSdt(this);
	CParagraphContentWithParagraphLikeContent.prototype.GetSelectedElementsInfo.apply(this, arguments);
};
CInlineLevelSdt.prototype.Add_ToContent = function(Pos, Item, UpdatePosition)
{
	History.Add(new CChangesParaFieldAddItem(this, Pos, [Item]));
	CParagraphContentWithParagraphLikeContent.prototype.Add_ToContent.apply(this, arguments);
};
CInlineLevelSdt.prototype.Remove_FromContent = function(Pos, Count, UpdatePosition)
{
	// Получим массив удаляемых элементов
	var DeletedItems = this.Content.slice(Pos, Pos + Count);
	History.Add(new CChangesParaFieldRemoveItem(this, Pos, DeletedItems));

	CParagraphContentWithParagraphLikeContent.prototype.Remove_FromContent.apply(this, arguments);
};
CInlineLevelSdt.prototype.Split = function (ContentPos, Depth)
{
	// Не даем разделять
	return null;
};
CInlineLevelSdt.prototype.CanSplit = function()
{
	return false;
};
CInlineLevelSdt.prototype.Recalculate_Range_Spaces = function(PRSA, _CurLine, _CurRange, _CurPage)
{
	var CurLine  = _CurLine - this.StartLine;
	var CurRange = (0 === _CurLine ? _CurRange - this.StartRange : _CurRange);

	if (0 === CurLine && 0 === CurRange && true !== PRSA.RecalcFast)
		this.Bounds = {};

	var oParagraph = PRSA.Paragraph;
	var Y0         = oParagraph.Lines[_CurLine].Top + oParagraph.Pages[_CurPage].Y;
	var Y1         = oParagraph.Lines[_CurLine].Bottom + oParagraph.Pages[_CurPage].Y;
	var X0         = PRSA.X;

	CParagraphContentWithParagraphLikeContent.prototype.Recalculate_Range_Spaces.apply(this, arguments);

	var X1 = PRSA.X;

	this.Bounds[((CurLine << 16) & 0xFFFF0000) | (CurRange & 0x0000FFFF)] = {
		X            : X0,
		W            : X1 - X0,
		Y            : Y0,
		H            : Y1 - Y0,
		Page         : PRSA.Paragraph.Get_AbsolutePage(_CurPage),
		PageInternal : _CurPage
	};

	this.BoundsPaths = null;
};
CInlineLevelSdt.prototype.Draw_HighLights = function(PDSH)
{
	PDSH.AddInlineSdt(this);
	CParagraphContentWithParagraphLikeContent.prototype.Draw_HighLights.apply(this, arguments);
};
CInlineLevelSdt.prototype.GetRangeBounds = function(_CurLine, _CurRange)
{
	var CurLine  = _CurLine - this.StartLine;
	var CurRange = (0 === _CurLine ? _CurRange - this.StartRange : _CurRange);

	return this.Bounds[((CurLine << 16) & 0xFFFF0000) | (CurRange & 0x0000FFFF)];
};
CInlineLevelSdt.prototype.Get_LeftPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
	if (false === UseContentPos && this.Content.length > 0)
	{
		// При переходе в новый контент встаем в его конец
		var CurPos = this.Content.length - 1;
		this.Content[CurPos].Get_EndPos(false, SearchPos.Pos, Depth + 1);
		SearchPos.Pos.Update(CurPos, Depth);
		SearchPos.Found = true;
		return true;
	}

	var bResult = CParagraphContentWithParagraphLikeContent.prototype.Get_LeftPos.call(this, SearchPos, ContentPos, Depth, UseContentPos);

	if (true !== bResult && this.Paragraph && this.Paragraph.LogicDocument && true === this.Paragraph.LogicDocument.IsFillingFormMode())
	{
		this.Get_StartPos(SearchPos.Pos, Depth);
		SearchPos.Found = true;
		return true;
	}

	return bResult;
};
CInlineLevelSdt.prototype.Get_RightPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
	if (false === UseContentPos && this.Content.length > 0)
	{
		// При переходе в новый контент встаем в его начало
		this.Content[0].Get_StartPos(SearchPos.Pos, Depth + 1);
		SearchPos.Pos.Update(0, Depth);
		SearchPos.Found = true;
		return true;
	}

	var bResult = CParagraphContentWithParagraphLikeContent.prototype.Get_RightPos.call(this, SearchPos, ContentPos, Depth, UseContentPos, StepEnd);

	if (true !== bResult && this.Paragraph && this.Paragraph.LogicDocument && true === this.Paragraph.LogicDocument.IsFillingFormMode())
	{
		this.Get_EndPos(false, SearchPos.Pos, Depth);
		SearchPos.Found = true;
		return true;
	}

	return bResult;
};
CInlineLevelSdt.prototype.Remove = function(nDirection, bOnAddText)
{
	CParagraphContentWithParagraphLikeContent.prototype.Remove.call(this, nDirection, bOnAddText);

	if (this.Is_Empty() && !bOnAddText && this.Paragraph && this.Paragraph.LogicDocument && true === this.Paragraph.LogicDocument.IsFillingFormMode())
	{
		var sDefaultText = "     ";
		this.ReplaceAllWithText(sDefaultText);
	}
};
CInlineLevelSdt.prototype.Shift_Range = function(Dx, Dy, _CurLine, _CurRange)
{
	CParagraphContentWithParagraphLikeContent.prototype.Shift_Range.call(this, Dx, Dy, _CurLine, _CurRange);

	var CurLine = _CurLine - this.StartLine;
	var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

	var oRangeBounds = this.Bounds[((CurLine << 16) & 0xFFFF0000) | (CurRange & 0x0000FFFF)];
	if (oRangeBounds)
	{
		oRangeBounds.X += Dx;
		oRangeBounds.Y += Dy;
	}

	if (this.BoundsPaths)
		this.BoundsPaths = null;
};
CInlineLevelSdt.prototype.Get_WordStartPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
	CParagraphContentWithParagraphLikeContent.prototype.Get_WordStartPos.call(this, SearchPos, ContentPos, Depth, UseContentPos);

	if (true !== SearchPos.Found && this.Paragraph && this.Paragraph.LogicDocument && true === this.Paragraph.LogicDocument.IsFillingFormMode())
	{
		this.Get_StartPos(SearchPos.Pos, Depth);
		SearchPos.UpdatePos = true;
		SearchPos.Found     = true;

	}
};
CInlineLevelSdt.prototype.Get_WordEndPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
	CParagraphContentWithParagraphLikeContent.prototype.Get_WordEndPos.call(this, SearchPos, ContentPos, Depth, UseContentPos, StepEnd);

	if (true !== SearchPos.Found && this.Paragraph && this.Paragraph.LogicDocument && true === this.Paragraph.LogicDocument.IsFillingFormMode())
	{
		this.Get_EndPos(false, SearchPos.Pos, Depth);
		SearchPos.UpdatePos = true;
		SearchPos.Found     = true;

	}
};
CInlineLevelSdt.prototype.GetBoundingPolygon = function()
{
	var StartPage = this.Paragraph.Get_StartPage_Absolute();
	if (null === this.BoundsPaths || StartPage !== this.BoundsPathsStartPage)
	{
		var arrBounds = [], arrRects = [], CurPage = -1;
		for (var Key in this.Bounds)
		{
			if (CurPage !== this.Bounds[Key].PageInternal)
			{
				arrRects = [];
				arrBounds.push(arrRects);
				CurPage  = this.Bounds[Key].PageInternal;
			}
			this.Bounds[Key].Page = this.Paragraph.Get_AbsolutePage(this.Bounds[Key].PageInternal);
			arrRects.push(this.Bounds[Key]);
		}

		this.BoundsPaths = [];
		for (var nIndex = 0, nCount = arrBounds.length; nIndex < nCount; ++nIndex)
		{
			var oPolygon = new CPolygon();
			oPolygon.fill([arrBounds[nIndex]]);
			this.BoundsPaths = this.BoundsPaths.concat(oPolygon.GetPaths(0));
		}

		this.BoundsPathsStartPage = StartPage;
	}

	return this.BoundsPaths;
};
CInlineLevelSdt.prototype.DrawContentControlsTrack = function(isHover)
{
	if (!this.Paragraph && this.Paragraph.LogicDocument)
		return;

	var oDrawingDocument = this.Paragraph.LogicDocument.Get_DrawingDocument();

	if (Asc.c_oAscSdtAppearance.Hidden === this.GetAppearance())
	{
		oDrawingDocument.OnDrawContentControl(null, isHover ? c_oContentControlTrack.Hover : c_oContentControlTrack.In);
		return;
	}

	var sName      = this.GetAlias();
	var isBuiltIn  = false;
	var arrButtons = [];

	oDrawingDocument.OnDrawContentControl(this.GetId(), isHover ? c_oContentControlTrack.Hover : c_oContentControlTrack.In, this.GetBoundingPolygon(), this.Paragraph.Get_ParentTextTransform(), sName, isBuiltIn, arrButtons, this.GetColor());
};
CInlineLevelSdt.prototype.SelectContentControl = function()
{
	this.SelectThisElement(1);
};
CInlineLevelSdt.prototype.RemoveContentControlWrapper = function()
{
	var oParent = this.Get_Parent();
	if (!oParent)
		return;

	var nElementPos = this.Get_PosInParent(oParent);
	if (-1 === nElementPos)
		return;

	var nParentCurPos            = oParent instanceof Paragraph ? oParent.CurPos.ContentPos : oParent.State.ContentPos;
	var nParentSelectionStartPos = oParent.Selection.StartPos;
	var nParentSelectionEndPos   = oParent.Selection.EndPos;

	var nCount = this.Content.length;
	oParent.Remove_FromContent(nElementPos, 1);
	for (var nIndex = 0; nIndex < nCount; ++nIndex)
	{
		oParent.Add_ToContent(nElementPos + nIndex, this.Content[nIndex]);
	}

	if (nParentCurPos === nElementPos)
	{
		if (oParent instanceof Paragraph)
			oParent.CurPos.ContentPos = nParentCurPos + this.State.ContentPos;
		else
			oParent.State.ContentPos = nParentCurPos + this.State.ContentPos;

	}
	else if (nParentCurPos > nElementPos)
	{
		if (oParent instanceof Paragraph)
			oParent.CurPos.ContentPos = nParentCurPos + nCount - 1;
		else
			oParent.State.ContentPos = nParentCurPos + nCount - 1;
	}

	if (nParentSelectionStartPos === nElementPos)
		oParent.Selection.StartPos = nParentSelectionStartPos + this.Selection.StartPos;
	else if (nParentSelectionStartPos > nElementPos)
		oParent.Selection.StartPos = nParentSelectionStartPos + nCount - 1;

	if (nParentSelectionEndPos === nElementPos)
		oParent.Selection.EndPos = nParentSelectionEndPos + this.Selection.EndPos;
	else if (nParentSelectionEndPos > nElementPos)
		oParent.Selection.EndPos = nParentSelectionEndPos + nCount - 1;

	this.Remove_FromContent(0, this.Content.length);
};
CInlineLevelSdt.prototype.FindNextFillingForm = function(isNext, isCurrent, isStart)
{
	if (isCurrent && true === this.IsSelectedAll())
	{
		if (isNext)
			return CParagraphContentWithParagraphLikeContent.prototype.FindNextFillingForm.apply(this, arguments);

		return null;
	}

	if (!isCurrent && isNext)
		return this;

	var oRes = CParagraphContentWithParagraphLikeContent.prototype.FindNextFillingForm.apply(this, arguments);
	if (!oRes && !isNext)
		return this;

	return null;
};
CInlineLevelSdt.prototype.GetAllContentControls = function(arrContentControls)
{
	arrContentControls.push(this);
	CParagraphContentWithParagraphLikeContent.prototype.GetAllContentControls.apply(this, arguments);
};
CInlineLevelSdt.prototype.Document_UpdateInterfaceState = function()
{
	if (this.Paragraph && this.Paragraph.LogicDocument)
		this.Paragraph.LogicDocument.Api.sync_ContentControlCallback(this.GetContentControlPr());

	CParagraphContentWithParagraphLikeContent.prototype.Document_UpdateInterfaceState.apply(this, arguments);
};
//----------------------------------------------------------------------------------------------------------------------
// Выставление настроек
//----------------------------------------------------------------------------------------------------------------------
CInlineLevelSdt.prototype.GetContentControlType = function()
{
	return c_oAscSdtLevelType.Inline;
};
CInlineLevelSdt.prototype.SetPr = function(oPr)
{
	this.SetAlias(oPr.Alias);
	this.SetTag(oPr.Tag);
	this.SetLabel(oPr.Label);
	this.SetContentControlLock(oPr.Lock);
	this.SetContentControlId(oPr.Id);

	if (undefined !== oPr.Appearance)
		this.SetAppearance(oPr.Appearance);

	if (undefined !== oPr.Color)
		this.SetColor(oPr.Color);
};
CInlineLevelSdt.prototype.SetAlias = function(sAlias)
{
	if (sAlias !== this.Pr.Alias)
	{
		History.Add(new CChangesSdtPrAlias(this, this.Pr.Alias, sAlias));
		this.Pr.Alias = sAlias;
	}
};
CInlineLevelSdt.prototype.GetAlias = function()
{
	return (undefined !== this.Pr.Alias ? this.Pr.Alias : "");
};
CInlineLevelSdt.prototype.SetAppearance = function(nType)
{
	if (this.Pr.Appearance !== nType)
	{
		History.Add(new CChangesSdtPrAppearance(this, this.Pr.Appearance, nType));
		this.Pr.Appearance = nType;
	}
};
CInlineLevelSdt.prototype.GetAppearance = function()
{
	return this.Pr.Appearance;
};
CInlineLevelSdt.prototype.SetColor = function(oColor)
{
	if (null === oColor || undefined === oColor)
	{
		if (undefined !== this.Pr.Color)
		{
			History.Add(new CChangesSdtPrColor(this, this.Pr.Color, undefined));
			this.Pr.Color = undefined;
		}
	}
	else
	{
		History.Add(new CChangesSdtPrColor(this, this.Pr.Color, oColor));
		this.Pr.Color = oColor;
	}
};
CInlineLevelSdt.prototype.GetColor = function()
{
	return this.Pr.Color;
};
CInlineLevelSdt.prototype.SetContentControlId = function(Id)
{
	if (this.Pr.Id !== Id)
	{
		History.Add(new CChangesSdtPrId(this, this.Pr.Id, Id));
		this.Pr.Id = Id;
	}
};
CInlineLevelSdt.prototype.GetContentControlId = function()
{
	return this.Pr.Id;
};
CInlineLevelSdt.prototype.SetTag = function(sTag)
{
	if (this.Pr.Tag !== sTag)
	{
		History.Add(new CChangesSdtPrTag(this, this.Pr.Tag, sTag));
		this.Pr.Tag = sTag;
	}
};
CInlineLevelSdt.prototype.GetTag = function()
{
	return (undefined !== this.Pr.Tag ? this.Pr.Tag : "");
};
CInlineLevelSdt.prototype.SetLabel = function(sLabel)
{
	if (this.Pr.Label !== sLabel)
	{
		History.Add(new CChangesSdtPrLabel(this, this.Pr.Label, sLabel));
		this.Pr.Label = sLabel;
	}
};
CInlineLevelSdt.prototype.GetLabel = function()
{
	return (undefined !== this.Pr.Label ? this.Pr.Label : "");
};
CInlineLevelSdt.prototype.SetContentControlLock = function(nLockType)
{
	if (this.Pr.Lock !== nLockType)
	{
		History.Add(new CChangesSdtPrLock(this, this.Pr.Lock, nLockType));
		this.Pr.Lock = nLockType;
	}
};
CInlineLevelSdt.prototype.GetContentControlLock = function()
{
	return (undefined !== this.Pr.Lock ? this.Pr.Lock : c_oAscSdtLockType.Unlocked);
};
CInlineLevelSdt.prototype.SetContentControlPr = function(oPr)
{
	if (!oPr)
		return;

	if (undefined !== oPr.Tag)
		this.SetTag(oPr.Tag);

	if (undefined !== oPr.Id)
		this.SetContentControlId(oPr.Id);

	if (undefined !== oPr.Lock)
		this.SetContentControlLock(oPr.Lock);

	if (undefined !== oPr.Alias)
		this.SetAlias(oPr.Alias);

	if (undefined !== oPr.Appearance)
		this.SetAppearance(oPr.Appearance);

	if (undefined !== oPr.Color)
		this.SetColor(oPr.Color);
};
CInlineLevelSdt.prototype.GetContentControlPr = function()
{
	var oPr = new CContentControlPr(c_oAscSdtLevelType.Inline);

	oPr.Tag        = this.GetTag();
	oPr.Id         = this.Pr.Id;
	oPr.Lock       = this.Pr.Lock;
	oPr.InternalId = this.GetId();
	oPr.Alias      = this.GetAlias();
	oPr.Appearance = this.GetAppearance();
	oPr.Color      = this.GetColor();

	return oPr;
};
//----------------------------------------------------------------------------------------------------------------------
// Функции совместного редактирования
//----------------------------------------------------------------------------------------------------------------------
CInlineLevelSdt.prototype.Write_ToBinary2 = function(Writer)
{
	Writer.WriteLong(AscDFH.historyitem_type_InlineLevelSdt);

	// String : Id
	// Long   : Количество элементов
	// Array of Strings : массив с Id элементов

	Writer.WriteString2(this.Id);

	var Count = this.Content.length;
	Writer.WriteLong(Count);
	for (var Index = 0; Index < Count; Index++)
		Writer.WriteString2(this.Content[Index].Get_Id());
};
CInlineLevelSdt.prototype.Read_FromBinary2 = function(Reader)
{
	// String : Id
	// Long   : Количество элементов
	// Array of Strings : массив с Id элементов

	this.Id = Reader.GetString2();

	var Count = Reader.GetLong();
	this.Content = [];
	for (var Index = 0; Index < Count; Index++)
	{
		var Element = AscCommon.g_oTableId.Get_ById(Reader.GetString2());
		if (null !== Element)
			this.Content.push(Element);
	}
};
CInlineLevelSdt.prototype.Write_ToBinary = function(Writer)
{
	// Long   : Type
	// String : Id

	Writer.WriteLong(this.Type);
	Writer.WriteString2(this.Id);
};
//----------------------------------------------------------------------------------------------------------------------
CInlineLevelSdt.prototype.IsStopCursorOnEntryExit = function()
{
	return true;
};
CInlineLevelSdt.prototype.GetSelectedContentControls = function(arrContentControls)
{
	arrContentControls.push(this);
	CParagraphContentWithParagraphLikeContent.prototype.GetSelectedContentControls.call(this, arrContentControls);
};
CInlineLevelSdt.prototype.ClearContentControl = function()
{
	this.Add_ToContent(0, new ParaRun(this.GetParagraph(), false));
	this.Remove_FromContent(1, this.Content.length - 1);
};
//--------------------------------------------------------export--------------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CInlineLevelSdt = CInlineLevelSdt;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 03.05.2017
 * Time: 12:12
 */

function CSdtPr()
{
	this.Alias = undefined;
	this.Id    = undefined;
	this.Tag   = undefined;
	this.Label = undefined;
	this.Lock  = undefined;

	this.DocPartObj = {
		Gallery  : undefined,
		Category : undefined,
		Unique   : undefined
	};

	this.Appearance = Asc.c_oAscSdtAppearance.Frame;
	this.Color      = undefined;
}

CSdtPr.prototype.Copy = function()
{
	var oPr = new CSdtPr();

	oPr.Alias      = this.Alias;
	oPr.Id         = this.Id;
	oPr.Tag        = this.Tag;
	oPr.Label      = this.Label;
	oPr.Lock       = this.Lock;
	oPr.Appearance = this.Appearance;
	oPr.Color      = (this.Color ? this.Color.Copy() : undefined);

	return oPr;
};
CSdtPr.prototype.Write_ToBinary = function(Writer)
{
	var StartPos = Writer.GetCurPosition();
	Writer.Skip(4);
	var Flags = 0;

	if (undefined !== this.Alias)
	{
		Writer.WriteString2(this.Alias);
		Flags |= 1;
	}

	if (undefined !== this.Id)
	{
		Writer.WriteLong(this.Id);
		Flags |= 2;
	}

	if (undefined !== this.Tag)
	{
		Writer.WriteString2(this.Tag);
		Flags |= 4;
	}

	if (undefined !== this.Label)
	{
		Writer.WriteLong(this.Tag);
		Flags |= 8;
	}

	if (undefined !== this.Lock)
	{
		Writer.WriteLong(this.Lock);
		Flags |= 16;
	}

	if (undefined !== this.DocPartObj.Unique)
	{
		Writer.WriteBool(this.DocPartObj.Unique);
		Flags |= 32;
	}

	if (undefined !== this.DocPartObj.Gallery)
	{
		Writer.WriteString2(this.DocPartObj.Gallery);
		Flags |= 64;
	}

	if (undefined !== this.DocPartObj.Category)
	{
		Writer.WriteString2(this.DocPartObj.Category);
		Flags |= 128;
	}

	if (undefined !== this.Appearance)
	{
		Writer.WriteLong(this.Appearance);
		Flags |= 256;
	}

	if (undefined !== this.Color)
	{
		this.Color.WriteToBinary();
		Flags |= 512;
	}


	var EndPos = Writer.GetCurPosition();
	Writer.Seek( StartPos );
	Writer.WriteLong( Flags );
	Writer.Seek( EndPos );
};
CSdtPr.prototype.Read_FromBinary = function(Reader)
{
	var Flags = Reader.GetLong();

	if (Flags & 1)
		this.Alias = Reader.GetString2();

	if (Flags & 2)
		this.Id = Reader.GetLong();

	if (Flags & 4)
		this.Tag = Reader.GetString2();

	if (Flags & 8)
		this.Tag = Reader.GetLong();

	if (Flags & 16)
		this.Lock = Reader.GetLong();

	if (Flags & 32)
		this.DocPartObj.Unique = Reader.GetBool();

	if (Flags & 64)
		this.DocPartObj.Gallery = Reader.GetString2();

	if (Flags & 128)
		this.DocPartObj.Category = Reader.GetString2();

	if (Flags & 256)
		this.Appearance = Reader.GetLong();

	if (Flags & 512)
	{
		this.Color = new CDocumentColor();
		this.Color.ReadFromBinary(oReader);
	}
};
CSdtPr.prototype.IsBuiltInDocPart = function()
{
	if (this.DocPartObj && (this.DocPartObj.Category || this.DocPartObj.Gallery))
		return true;

	return false;
};

function CContentControlPr(nType)
{
	this.Id         = undefined;
	this.Tag        = undefined;
	this.Alias      = undefined;
	this.Lock       = undefined;
	this.InternalId = undefined;
	this.CCType     = undefined !== nType ? nType : c_oAscSdtLevelType.Inline;

	this.Appearance = Asc.c_oAscSdtAppearance.Frame;
	this.Color      = undefined;
}
CContentControlPr.prototype.get_Id = function()
{
	return this.Id;
};
CContentControlPr.prototype.put_Id = function(Id)
{
	this.Id = Id;
};
CContentControlPr.prototype.get_Tag = function()
{
	return this.Tag;
};
CContentControlPr.prototype.put_Tag = function(sTag)
{
	this.Tag = sTag;
};
CContentControlPr.prototype.get_Lock = function()
{
	return this.Lock;
};
CContentControlPr.prototype.put_Lock = function(nLock)
{
	this.Lock = nLock;
};
CContentControlPr.prototype.get_InternalId = function()
{
	return this.InternalId;
};
CContentControlPr.prototype.get_ContentControlType = function()
{
	return this.CCType;
};
CContentControlPr.prototype.get_Alias = function()
{
	return this.Alias;
};
CContentControlPr.prototype.put_Alias = function(sAlias)
{
	this.Alias = sAlias;
};
CContentControlPr.prototype.get_Appearance = function()
{
	return this.Appearance;
};
CContentControlPr.prototype.put_Appearance = function(nAppearance)
{
	this.Appearance = nAppearance;
};
CContentControlPr.prototype.get_Color = function()
{
	if (!this.Color)
		return null;

	return new Asc.asc_CColor(this.Color.r, this.Color.g, this.Color.b);
};
CContentControlPr.prototype.put_Color = function(r, g, b)
{
	if (undefined === r || null === r)
		this.Color = undefined;
	else
		this.Color = new CDocumentColor(r, g, b);
};

/**
 * Класс с глобальными настройками для всех контейнеров
 * @constructor
 */
function CSdtGlobalSettings()
{
	this.Color         = new AscCommonWord.CDocumentColor(220, 220, 220);
	this.ShowHighlight = false;
}
/**
 * Проверяем все ли параметры выставлены по умолчанию
 * @returns {boolean}
 */
CSdtGlobalSettings.prototype.IsDefault = function()
{
	if (!this.Color
		|| 220 !== this.Color.r
		|| 220 !== this.Color.g
		|| 220 !== this.Color.b
		|| false !== this.ShowHighlight)
		return false;

	return true;
};
CSdtGlobalSettings.prototype.Copy = function()
{
	var oSettings = new CSdtGlobalSettings();

	oSettings.Color         = this.Color.Copy();
	oSettings.ShowHighlight = this.ShowHighlight;

	return oSettings;
};
CSdtGlobalSettings.prototype.Write_ToBinary = function(oWriter)
{
	// CDocumentColor : Color
	// Bool           : ShowHighlight

	this.Color.WriteToBinary(oWriter);
	oWriter.WriteBool(this.ShowHighlight);
};
CSdtGlobalSettings.prototype.Read_FromBinary = function(oReader)
{
	this.Color.ReadFromBinary(oReader);
	this.ShowHighlight = oReader.GetBool();
};

//--------------------------------------------------------export--------------------------------------------------------
window['AscCommonWord']        = window['AscCommonWord'] || {};
window['AscCommonWord'].CSdtPr = CSdtPr;

window['AscCommon'] = window['AscCommon'] || {};

window['AscCommon'].CContentControlPr    = CContentControlPr;
window['AscCommon']['CContentControlPr'] = CContentControlPr;

CContentControlPr.prototype['get_Id']                 = CContentControlPr.prototype.get_Id;
CContentControlPr.prototype['put_Id']                 = CContentControlPr.prototype.put_Id;
CContentControlPr.prototype['get_Tag']                = CContentControlPr.prototype.get_Tag;
CContentControlPr.prototype['put_Tag']                = CContentControlPr.prototype.put_Tag;
CContentControlPr.prototype['get_Lock']               = CContentControlPr.prototype.get_Lock;
CContentControlPr.prototype['put_Lock']               = CContentControlPr.prototype.put_Lock;
CContentControlPr.prototype['get_InternalId']         = CContentControlPr.prototype.get_InternalId;
CContentControlPr.prototype['get_ContentControlType'] = CContentControlPr.prototype.get_ContentControlType;
CContentControlPr.prototype['get_Alias']              = CContentControlPr.prototype.get_Alias;
CContentControlPr.prototype['put_Alias']              = CContentControlPr.prototype.put_Alias;
CContentControlPr.prototype['get_Appearance']         = CContentControlPr.prototype.get_Appearance;
CContentControlPr.prototype['put_Appearance']         = CContentControlPr.prototype.put_Appearance;
CContentControlPr.prototype['get_Color']              = CContentControlPr.prototype.get_Color;
CContentControlPr.prototype['put_Color']              = CContentControlPr.prototype.put_Color;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 03.05.2017
 * Time: 14:58
 */

AscDFH.changesFactory[AscDFH.historyitem_SdtPr_Alias]      = CChangesSdtPrAlias;
AscDFH.changesFactory[AscDFH.historyitem_SdtPr_Id]         = CChangesSdtPrId;
AscDFH.changesFactory[AscDFH.historyitem_SdtPr_Tag]        = CChangesSdtPrTag;
AscDFH.changesFactory[AscDFH.historyitem_SdtPr_Label]      = CChangesSdtPrLabel;
AscDFH.changesFactory[AscDFH.historyitem_SdtPr_Lock]       = CChangesSdtPrLock;
AscDFH.changesFactory[AscDFH.historyitem_SdtPr_DocPartObj] = CChangesSdtPrDocPartObj;
AscDFH.changesFactory[AscDFH.historyitem_SdtPr_Appearance] = CChangesSdtPrAppearance;
AscDFH.changesFactory[AscDFH.historyitem_SdtPr_Color]      = CChangesSdtPrColor;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_SdtPr_Alias] = [
	AscDFH.historyitem_SdtPr_Alias
];
AscDFH.changesRelationMap[AscDFH.historyitem_SdtPr_Id]    = [
	AscDFH.historyitem_SdtPr_Id
];
AscDFH.changesRelationMap[AscDFH.historyitem_SdtPr_Tag]   = [
	AscDFH.historyitem_SdtPr_Tag
];
AscDFH.changesRelationMap[AscDFH.historyitem_SdtPr_Label] = [
	AscDFH.historyitem_SdtPr_Label
];
AscDFH.changesRelationMap[AscDFH.historyitem_SdtPr_Lock]  = [
	AscDFH.historyitem_SdtPr_Lock
];
AscDFH.changesRelationMap[AscDFH.historyitem_SdtPr_DocPartObj] = [
	AscDFH.historyitem_SdtPr_DocPartObj
];
AscDFH.changesRelationMap[AscDFH.historyitem_SdtPr_Appearance] = [
	AscDFH.historyitem_SdtPr_Appearance
];
AscDFH.changesRelationMap[AscDFH.historyitem_SdtPr_Color] = [
	AscDFH.historyitem_SdtPr_Color
];
//----------------------------------------------------------------------------------------------------------------------

/**
 * @constructor
 * @extends {AscDFH.CChangesBaseStringProperty}
 */
function CChangesSdtPrAlias(Class, Old, New)
{
	AscDFH.CChangesBaseStringProperty.call(this, Class, Old, New);
}
CChangesSdtPrAlias.prototype = Object.create(AscDFH.CChangesBaseStringProperty.prototype);
CChangesSdtPrAlias.prototype.constructor = CChangesSdtPrAlias;
CChangesSdtPrAlias.prototype.Type = AscDFH.historyitem_SdtPr_Alias;
CChangesSdtPrAlias.prototype.private_SetValue = function(Value)
{
	this.Class.Pr.Alias = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesSdtPrId(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesSdtPrId.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesSdtPrId.prototype.constructor = CChangesSdtPrId;
CChangesSdtPrId.prototype.Type = AscDFH.historyitem_SdtPr_Id;
CChangesSdtPrId.prototype.private_SetValue = function(Value)
{
	this.Class.Pr.Id = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseStringProperty}
 */
function CChangesSdtPrTag(Class, Old, New)
{
	AscDFH.CChangesBaseStringProperty.call(this, Class, Old, New);
}
CChangesSdtPrTag.prototype = Object.create(AscDFH.CChangesBaseStringProperty.prototype);
CChangesSdtPrTag.prototype.constructor = CChangesSdtPrTag;
CChangesSdtPrTag.prototype.Type = AscDFH.historyitem_SdtPr_Tag;
CChangesSdtPrTag.prototype.private_SetValue = function(Value)
{
	this.Class.Pr.Tag = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesSdtPrLabel(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesSdtPrLabel.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesSdtPrLabel.prototype.constructor = CChangesSdtPrLabel;
CChangesSdtPrLabel.prototype.Type = AscDFH.historyitem_SdtPr_Label;
CChangesSdtPrLabel.prototype.private_SetValue = function(Value)
{
	this.Class.Pr.Label = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesSdtPrLock(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesSdtPrLock.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesSdtPrLock.prototype.constructor = CChangesSdtPrLock;
CChangesSdtPrLock.prototype.Type = AscDFH.historyitem_SdtPr_Lock;
CChangesSdtPrLock.prototype.private_SetValue = function(Value)
{
	this.Class.Pr.Lock = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesSdtPrDocPartObj(Class, Old, New)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New);

	this.Old = {
		Category : Old ? Old.Category : undefined,
		Gallery  : Old ? Old.Gallery : undefined,
		Unique   : Old ? Old.Unique : undefined
	};

	this.New = {
		Category : New ? New.Category : undefined,
		Gallery  : New ? New.Gallery : undefined,
		Unique   : New ? New.Unique : undefined
	};
}
CChangesSdtPrDocPartObj.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesSdtPrDocPartObj.prototype.constructor = CChangesSdtPrDocPartObj;
CChangesSdtPrDocPartObj.prototype.Type = AscDFH.historyitem_SdtPr_DocPartObj;
CChangesSdtPrDocPartObj.prototype.private_SetValue = function(Value)
{
	this.Class.Pr.DocPartObj.Category = Value.Category;
	this.Class.Pr.DocPartObj.Gallery  = Value.Gallery;
	this.Class.Pr.DocPartObj.Unique   = Value.Unique;
};
CChangesSdtPrDocPartObj.prototype.WriteToBinary = function(Writer)
{
	// Long  : Flag
	// 1-bit : Old.Category is undefined
	// 2-bit : Old.Gallery is undefined
	// 3-bit : Old.Unique is undefined
	// 4-bit : New.Category is undefined
	// 5-bit : New.Gallery is undefined
	// 6-bit : New.Unique is undefined
	// String : Old.Category
	// String : Old.Gallery
	// Bool   : Old.Unique
	// String : New.Category
	// String : New.Gallery
	// Bool   : New.Unique

	var nFlags = 0;

	if (undefined !== this.Old.Category)
		nFlags |= 1;

	if (undefined !== this.Old.Gallery)
		nFlags |= 2;

	if (undefined !== this.Old.Unique)
		nFlags |= 4;

	if (undefined !== this.New.Category)
		nFlags |= 8;

	if (undefined !== this.New.Gallery)
		nFlags |= 16;

	if (undefined !== this.New.Unique)
		nFlags |= 32;

	Writer.WriteLong(nFlags);

	if (undefined !== this.Old.Category)
		Writer.WriteString2(this.Old.Category);

	if (undefined !== this.Old.Gallery)
		Writer.WriteString2(this.Old.Gallery);

	if (undefined !== this.Old.Unique)
		Writer.WriteBool(this.Old.Unique);

	if (undefined !== this.New.Category)
		Writer.WriteString2(this.New.Category);

	if (undefined !== this.New.Gallery)
		Writer.WriteString2(this.New.Gallery);

	if (undefined !== this.New.Unique)
		Writer.WriteBool(this.New.Unique);
};
CChangesSdtPrDocPartObj.prototype.ReadFromBinary = function(Reader)
{
	// Long  : Flag
	// 1-bit : Old.Category is undefined
	// 2-bit : Old.Gallery is undefined
	// 3-bit : Old.Unique is undefined
	// 4-bit : New.Category is undefined
	// 5-bit : New.Gallery is undefined
	// 6-bit : New.Unique is undefined
	// String : Old.Category
	// String : Old.Gallery
	// Bool   : Old.Unique
	// String : New.Category
	// String : New.Gallery
	// Bool   : New.Unique

	var nFlags = Reader.GetLong();

	this.Old = {
		Category : undefined,
		Gallery  : undefined,
		Unique   : undefined
	};

	this.New = {
		Category : undefined,
		Gallery  : undefined,
		Unique   : undefined
	};

	if (nFlags & 1)
		this.Old.Category = Reader.GetString2();

	if (nFlags & 2)
		this.Old.Gallery = Reader.GetString2();

	if (nFlags & 4)
		this.Old.Unique = Reader.GetBool();

	if (nFlags & 8)
		this.New.Category = Reader.GetString2();

	if (nFlags & 16)
		this.New.Gallery = Reader.GetString2();

	if (nFlags & 32)
		this.New.Unique = Reader.GetBool();
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesSdtPrAppearance(Class, Old, New)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New);
}
CChangesSdtPrAppearance.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesSdtPrAppearance.prototype.constructor = CChangesSdtPrAppearance;
CChangesSdtPrAppearance.prototype.Type = AscDFH.historyitem_SdtPr_Appearance;
CChangesSdtPrAppearance.prototype.private_SetValue = function(Value)
{
	this.Class.Pr.Appearance = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseObjectProperty}
 */
function CChangesSdtPrColor(Class, Old, New)
{
	AscDFH.CChangesBaseObjectProperty.call(this, Class, Old, New);
}
CChangesSdtPrColor.prototype = Object.create(AscDFH.CChangesBaseObjectProperty.prototype);
CChangesSdtPrColor.prototype.constructor = CChangesSdtPrColor;
CChangesSdtPrColor.prototype.Type = AscDFH.historyitem_SdtPr_Color;
CChangesSdtPrColor.prototype.private_SetValue = function(Value)
{
	this.Class.Pr.Color = Value;
};
CChangesSdtPrColor.prototype.private_CreateObject = function()
{
	return new CDocumentColor();
};

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var g_memory = AscFonts.g_memory;
var FontStyle = AscFonts.FontStyle;
var DecodeBase64Char = AscFonts.DecodeBase64Char;
var b64_decode = AscFonts.b64_decode;
var g_fontApplication = AscFonts.g_fontApplication;

var align_Right = AscCommon.align_Right;
var align_Left = AscCommon.align_Left;
var align_Center = AscCommon.align_Center;
var align_Justify = AscCommon.align_Justify;
var c_oAscWrapStyle = AscCommon.c_oAscWrapStyle;
var Binary_CommonReader = AscCommon.Binary_CommonReader;
var BinaryCommonWriter = AscCommon.BinaryCommonWriter;
var c_oSerPaddingType = AscCommon.c_oSerPaddingType;
var c_oSerBordersType = AscCommon.c_oSerBordersType;
var c_oSerBorderType = AscCommon.c_oSerBorderType;
var c_oSerPropLenType = AscCommon.c_oSerPropLenType;
var c_oSerConstants = AscCommon.c_oSerConstants;
var pptx_content_loader = AscCommon.pptx_content_loader;
var pptx_content_writer = AscCommon.pptx_content_writer;

var c_oAscXAlign = Asc.c_oAscXAlign;
var c_oAscYAlign = Asc.c_oAscYAlign;

//dif:
//Version:2 добавлены свойства стилей qFormat, uiPriority, hidden, semiHidden, unhideWhenUsed, для более ранних бинарников считаем qFormat = true
//Version:3 все рисованные обьекты открываются через презентации
//Version:4 добавилось свойство CTablePr.TableLayout(проблема в том что если оно отсутствует, то это tbllayout_AutoFit, а у нас в любом случае считалось tbllayout_Fixed)
//Version:5 добавлены секции, учитываются флаги title и EvenAndOddHeaders, изменен формат chart
var c_oSerTableTypes = {
    Signature:0,
    Info:1,
    Media:2,
    Numbering:3,
    HdrFtr:4,
    Style:5,
    Document:6,
    Other:7,
	Comments: 8,
	Settings: 9,
	Footnotes: 10,
	Endnotes: 11,
	Background: 12,
	VbaProject: 13,
	App: 14
};
var c_oSerSigTypes = {
    Version:0
};
var c_oSerHdrFtrTypes = {
    Header:0,
    Footer:1,
    HdrFtr_First:2,
    HdrFtr_Even:3,
    HdrFtr_Odd:4,
    HdrFtr_Content:5,
    HdrFtr_Y2:6,
    HdrFtr_Y:7
};
var c_oSerNumTypes = {
    AbstractNums:0,
    AbstractNum:1,
    AbstractNum_Id:2,
    AbstractNum_Type:3,
    AbstractNum_Lvls:4,
    Lvl:5,
    lvl_Format:6,
    lvl_Jc:7,
    lvl_LvlText:8,
    lvl_LvlTextItem:9,
    lvl_LvlTextItemText:10,
    lvl_LvlTextItemNum:11,
    lvl_Restart:12,
    lvl_Start:13,
    lvl_Suff:14,
    lvl_ParaPr:15,
    lvl_TextPr:16,
    Nums: 17,
    Num: 18,
    Num_ANumId: 19,
    Num_NumId: 20,
	lvl_PStyle: 21,
	NumStyleLink: 22,
	StyleLink: 23,
	lvl_NumFmt: 24,
	NumFmtVal: 25,
	NumFmtFormat: 26,
	Num_LvlOverride : 27,
	StartOverride: 28,
	ILvl: 29,
	Tentative: 30,
	Tplc: 31,
	IsLgl: 32,
	LvlLegacy: 33,
	Legacy: 34,
	LegacyIndent: 35,
	LegacySpace: 36
};
var c_oSerOtherTableTypes = {
    ImageMap:0,
    ImageMap_Src:1,
	DocxTheme: 3
};
var c_oSerFontsTypes = {
    Name:0
};
var c_oSerImageMapTypes = {
    Src:0
};
var c_oSerStyleTypes = {
    Name:0,
    BasedOn:1,
    Next:2
};
var c_oSer_st = {
    DefpPr:0,
    DefrPr:1,
    Styles:2
};
var c_oSer_sts = {
    Style:0,
    Style_Id:1,
    Style_Name:2,
    Style_BasedOn:3,
    Style_Next:4,
    Style_TextPr:5,
    Style_ParaPr:6,
    Style_TablePr:7,
    Style_Default:8,
    Style_Type:9,
    Style_qFormat:10,
    Style_uiPriority:11,
    Style_hidden:12,
    Style_semiHidden:13,
    Style_unhideWhenUsed:14,
	Style_RowPr: 15,
	Style_CellPr: 16,
	Style_TblStylePr: 17,
	Style_Link: 18,
	Style_CustomStyle: 19,
	Style_Aliases: 20,
	Style_AutoRedefine: 21,
	Style_Locked: 22,
	Style_Personal: 23,
	Style_PersonalCompose: 24,
	Style_PersonalReply: 25
};
var c_oSerProp_tblStylePrType = {
	TblStylePr: 0,
	Type: 1,
	RunPr: 2,
	ParPr: 3,
	TblPr: 4,
	TrPr: 5,
	TcPr: 6
};
var c_oSerProp_tblPrType = {
    Rows:0,
    Cols:1,
    Jc:2,
    TableInd:3,
    TableW:4,
    TableCellMar:5,
    TableBorders:6,
    Shd:7,
    tblpPr:8,
	Look: 9,
	Style: 10,
	tblpPr2: 11,
	Layout: 12,
	tblPrChange: 13,
	TableCellSpacing: 14,
	RowBandSize: 15,
	ColBandSize: 16,
	tblCaption: 17,
	tblDescription: 18
};
var c_oSer_tblpPrType = {
    Page:0,
    X:1,//начиная с версии 2, отсчитывается от начала текста(как в docx), раньше отсчитывался от левой границы.
    Y:2,
    Paddings:3
};
var c_oSer_tblpPrType2 = {
	HorzAnchor: 0,
	TblpX: 1,
	TblpXSpec: 2,
	VertAnchor: 3,
	TblpY: 4,
	TblpYSpec: 5,
	Paddings: 6
};
var c_oSerProp_pPrType = {
    contextualSpacing:0,
    Ind:1,
    Ind_Left:2,
    Ind_Right:3,
    Ind_FirstLine:4,
    Jc:5,
    KeepLines:6,
    KeepNext:7,
    PageBreakBefore:8,
    Spacing:9,
    Spacing_Line:10,
    Spacing_LineRule:11,
    Spacing_Before:12,
    Spacing_After:13,
    Shd:14,
    Tab:17,
    Tab_Item:18,
    Tab_Item_Pos:19,
    Tab_Item_Val:20,
    ParaStyle:21,
    numPr: 22,
    numPr_lvl: 23,
    numPr_id: 24,
    WidowControl:25,
    pPr_rPr: 26,
    pBdr: 27,
    Spacing_BeforeAuto: 28,
    Spacing_AfterAuto: 29,
	FramePr: 30,
	SectPr: 31,
	numPr_Ins: 32,
	pPrChange: 33,
	outlineLvl: 34,
	Tab_Item_Leader: 35
};
var c_oSerProp_rPrType = {
    Bold:0,
    Italic:1,
    Underline:2,
    Strikeout:3,
    FontAscii:4,
    FontHAnsi:5,
    FontAE:6,
    FontCS:7,
    FontSize:8,
    Color:9,
    VertAlign:10,
    HighLight:11,
    HighLightTyped:12,
	RStyle: 13,
	Spacing: 14,
	DStrikeout: 15,
	Caps: 16,
	SmallCaps: 17,
	Position: 18,
	FontHint: 19,
	BoldCs: 20,
	ItalicCs: 21,
	FontSizeCs: 22,
	Cs: 23,
	Rtl: 24,
	Lang: 25,
	LangBidi: 26,
	LangEA: 27,
	ColorTheme: 28,
	Shd: 29,
	Vanish: 30,
	TextOutline: 31,
	TextFill : 32,
	Del: 33,
	Ins: 34,
	rPrChange: 35,
	MoveFrom: 36,
	MoveTo: 37
};
var c_oSerProp_rowPrType = {
    CantSplit:0,
    GridAfter:1,
    GridBefore:2,
    Jc:3,
    TableCellSpacing:4,
    Height:5,
    Height_Rule:6,
    Height_Value:7,
    WAfter:8,
    WBefore:9,
    WAfterBefore_W:10,
    WAfterBefore_Type:11,
    After:12,
    Before:13,
    TableHeader:14,
    Del: 15,
    Ins: 16,
    trPrChange: 17
};
var c_oSerProp_cellPrType = {
    GridSpan:0,
    Shd:1,
    TableCellBorders:2,
    TableCellW:3,
    VAlign:4,
    VMerge:5,
    CellMar:6,
    CellDel: 7,
    CellIns: 8,
    CellMerge: 9,
    tcPrChange: 10,
    textDirection: 11,
    hideMark: 12,
    noWrap:13,
    tcFitText: 14,
	HMerge:15
};
var c_oSerProp_secPrType = {
    pgSz: 0,
    pgMar: 1,
    setting: 2,
	headers: 3,
	footers: 4,
	hdrftrelem: 5,
	pageNumType: 6,
	sectPrChange: 7,
	cols: 8,
	pgBorders: 9,
	footnotePr: 10,
	endnotePr: 11
};
var c_oSerProp_secPrSettingsType = {
    titlePg: 0,
    EvenAndOddHeaders: 1,
	SectionType: 2
};
var c_oSerProp_secPrPageNumType = {
	start: 0
};
var c_oSerProp_Columns = {
	EqualWidth: 0,
	Num: 1,
	Sep: 2,
	Space: 3,
	Column: 4,
	ColumnSpace: 5,
	ColumnW: 6
};
var c_oSerParType = {
    Par:0,
    pPr:1,
    Content:2,
    Table:3,
    sectPr: 4,
    Run: 5,
	CommentStart: 6,
	CommentEnd: 7,
	OMathPara: 8,
	OMath: 9,
    Hyperlink: 10,
	FldSimple: 11,
	Del: 12,
	Ins: 13,
	Background: 14,
	Sdt: 15,
	MoveFrom: 16,
	MoveTo: 17,
	MoveFromRangeStart: 18,
	MoveFromRangeEnd: 19,
	MoveToRangeStart: 20,
	MoveToRangeEnd: 21,
	JsaProject: 22,
	BookmarkStart: 23,
	BookmarkEnd: 24,
	MRun: 25
};
var c_oSerDocTableType = {
    tblPr:0,
    tblGrid:1,
    tblGrid_Item:2,
    Content:3,
    Row: 4,
    Row_Pr: 4,
    Row_Content: 5,
    Cell: 6,
    Cell_Pr: 7,
    Cell_Content: 8,
    tblGridChange: 9,
	Sdt: 10,
	BookmarkStart: 11,
	BookmarkEnd: 12
};
var c_oSerRunType = {
    run:0,
    rPr:1,
    tab:2,
    pagenum:3,
    pagebreak:4,
    linebreak:5,
    image:6,
    table:7,
    Content:8,
	fldstart_deprecated: 9,
	fldend_deprecated: 10,
	CommentReference: 11,
	pptxDrawing: 12,
	_LastRun: 13, //для копирования через бинарник
	object: 14,
	delText: 15,
    del: 16,
    ins: 17,
    columnbreak: 18,
	cr: 19,
	nonBreakHyphen: 20,
	softHyphen: 21,
	separator: 22,
	continuationSeparator: 23,
	footnoteRef: 24,
	endnoteRef: 25,
	footnoteReference: 26,
	endnoteReference: 27,
	arPr: 28,
	fldChar: 29,
	instrText: 30,
	delInstrText: 31
};
var c_oSerImageType = {
    MediaId:0,
    Type:1,
    Width:2,
    Height:3,
    X:4,
    Y:5,
    Page:6,
    Padding:7
};
var c_oSerImageType2 = {
	Type: 0,
	PptxData: 1,
	AllowOverlap: 2,
	BehindDoc: 3,
	DistB: 4,
	DistL: 5,
	DistR: 6,
	DistT: 7,
	Hidden: 8,
	LayoutInCell: 9,
	Locked: 10,
	RelativeHeight: 11,
	BSimplePos: 12,
	EffectExtent: 13,
	Extent: 14,
	PositionH: 15,
	PositionV: 16,
	SimplePos: 17,
	WrapNone: 18,
	WrapSquare: 19,
	WrapThrough: 20,
	WrapTight: 21,
	WrapTopAndBottom: 22,
	Chart: 23,
	ChartImg: 24,
	Chart2: 25,
	CachedImage: 26,
	SizeRelH: 27,
	SizeRelV: 28,
	GraphicFramePr: 30,
	DocPr: 31
};
var c_oSerEffectExtent = {
	Left: 0,
	Top: 1,
	Right: 2,
	Bottom: 3
};
var c_oSerExtent = {
	Cx: 0,
	Cy: 1
};
var c_oSerPosHV = {
	RelativeFrom: 0,
	Align: 1,
	PosOffset: 2,
	PctOffset: 3
};
var c_oSerSizeRelHV = {
	RelativeFrom: 0,
	Pct: 1
};
var c_oSerSimplePos = {
	X: 0,
	Y: 1
};
var c_oSerWrapSquare = {
	DistL: 0,
	DistT: 1,
	DistR: 2,
	DistB: 3,
	WrapText: 4,
	EffectExtent: 5
};
var c_oSerWrapThroughTight = {
	DistL: 0,
	DistR: 1,
	WrapText: 2,
	WrapPolygon: 3
};
var c_oSerWrapTopBottom = {
	DistT: 0,
	DistB: 1,
	EffectExtent: 2
};
var c_oSerWrapPolygon = {
	Edited: 0,
	Start: 1,
	ALineTo: 2,
	LineTo: 3
};
var c_oSerPoint2D = {
	X: 0,
	Y: 1
};
var c_oSerMarginsType = {
    left:0,
    top:1,
    right:2,
    bottom:3
};
var c_oSerWidthType = {
    Type:0,
    W:1,
	WDocx: 2
};
var c_oSer_pgSzType = {
    W:0,
    H:1,
    Orientation:2
};
var c_oSer_pgMarType = {
    Left:0,
    Top:1,
    Right:2,
    Bottom:3,
    Header:4,
    Footer:5
};
var c_oSer_CommentsType = {
	Comment: 0,
	Id: 1,
	Initials: 2,
	UserName: 3,
	UserId: 4,
	Date: 5,
	Text: 6,
	QuoteText: 7,
	Solved: 8,
	Replies: 9,
	OOData: 10
};

var c_oSer_StyleType = {
    Character: 1,
    Numbering: 2,
	Paragraph: 3,
	Table: 4
};
var c_oSer_SettingsType = {
	ClrSchemeMapping: 0,
	DefaultTabStop: 1,
	MathPr: 2,
	TrackRevisions: 3,
	FootnotePr: 4,
	EndnotePr: 5,
	SdtGlobalColor: 6,
	SdtGlobalShowHighlight: 7,
	Compat: 8
};
var c_oSer_MathPrType = {
	BrkBin: 0,
	BrkBinSub: 1,
	DefJc: 2,
	DispDef: 3,
	InterSp: 4,
	IntLim: 5,
	IntraSp: 6,
	LMargin: 7,
	MathFont: 8,
	NaryLim: 9,
	PostSp: 10,
	PreSp: 11,
	RMargin: 12,
	SmallFrac: 13,
	WrapIndent: 14,
	WrapRight: 15
};
var c_oSer_ClrSchemeMappingType = {
	Accent1: 0,
	Accent2: 1,
	Accent3: 2,
	Accent4: 3,
	Accent5: 4,
	Accent6: 5,
	Bg1: 6,
	Bg2: 7,
	FollowedHyperlink: 8,
	Hyperlink: 9,
	T1: 10,
	T2: 11
};
var c_oSer_FramePrType = {
	DropCap: 0,
	H: 1,
	HAnchor: 2,
	HRule: 3,
	HSpace: 4,
	Lines: 5,
	VAnchor: 6,
	VSpace: 7,
	W: 8,
	Wrap: 9,
	X: 10,
	XAlign: 11,
	Y: 12,
	YAlign: 13
};
var c_oSer_OMathBottomNodesType = {
	Aln: 0,
	AlnScr: 1,
	ArgSz: 2,
	BaseJc: 3,
	BegChr: 4,
	Brk: 5,
	CGp: 6,
	CGpRule: 7,
	Chr: 8,
	Count: 9,
	CSp: 10,
	CtrlPr: 11,
	DegHide: 12,
	Diff: 13,
	EndChr: 14,
	Grow: 15,
	HideBot: 16,
	HideLeft: 17,
	HideRight: 18,
	HideTop: 19,
	MJc: 20,
	LimLoc: 21,
	Lit: 22,
	MaxDist: 23,
	McJc: 24,
	Mcs: 25,
	NoBreak: 26,
	Nor: 27,
	ObjDist: 28,
	OpEmu: 29,
	PlcHide: 30,
	Pos: 31,
	RSp: 32,
	RSpRule: 33,
	Scr: 34,
	SepChr: 35,
	Show: 36,
	Shp: 37,
	StrikeBLTR: 38,
	StrikeH: 39,
	StrikeTLBR: 40,
	StrikeV: 41,
	Sty: 42,
	SubHide: 43,
	SupHide: 44,
	Transp: 45,
	Type: 46,
	VertJc: 47,
	ZeroAsc: 48,
	ZeroDesc: 49,
	ZeroWid: 50,	
	Column: 51,
	Row: 52
};
var c_oSer_OMathBottomNodesValType = {
	Val: 0,
	AlnAt: 1
};
var c_oSer_OMathChrType =
{
    Chr    : 0,
    BegChr : 1,
    EndChr : 2,
    SepChr : 3
};
var c_oSer_OMathContentType = {		
	Acc: 0,
	AccPr: 1,
	ArgPr: 2,
	Bar: 3,
	BarPr: 4,
	BorderBox: 5,
	BorderBoxPr: 6,
	Box: 7,
	BoxPr: 8,
	Deg: 9,
	Den: 10,
	Delimiter: 11,
	DelimiterPr: 12,
	Element: 13,
	EqArr: 14,
	EqArrPr: 15,
	FName: 16,
	Fraction: 17,
	FPr: 18,
	Func: 19,
	FuncPr: 20,
	GroupChr: 21,
	GroupChrPr: 22,
	Lim: 23,
	LimLow: 24,
	LimLowPr: 25,
	LimUpp: 26,
	LimUppPr: 27,
	Matrix: 28,
	MathPr: 29,
	Mc: 30,
	McPr: 31,		
	MPr: 32,
	Mr: 33,
	Nary: 34,
	NaryPr: 35,
	Num: 36,
	OMath: 37,
	OMathPara: 38,
	OMathParaPr: 39,
	Phant: 40,
	PhantPr: 41,
	MRun: 42,
	Rad: 43,
	RadPr: 44,
	RPr: 45,
	MRPr: 46,
	SPre: 47,
	SPrePr: 48,
	SSub: 49,
	SSubPr: 50,
	SSubSup: 51,
	SSubSupPr: 52,
	SSup: 53,
	SSupPr: 54,
	Sub: 55,
	Sup: 56,
	MText: 57,
	CtrlPr: 58,
	pagebreak: 59,
	linebreak: 60,
	Run: 61,
    Ins: 62,
	Del: 63,
	columnbreak: 64,
	ARPr: 65,
	BookmarkStart: 66,
	BookmarkEnd: 67
};
var c_oSer_HyperlinkType = {
    Content: 0,
    Link: 1,
    Anchor: 2,
    Tooltip: 3,
    History: 4,
    DocLocation: 5,
    TgtFrame: 6
};
var c_oSer_FldSimpleType = {
	Content: 0,
	Instr: 1,
	FFData: 2,
	CharType: 3
};
var c_oSerProp_RevisionType = {
    Author: 0,
    Date: 1,
    Id: 2,
	UserId: 3,
    Content: 4,
    VMerge: 5,
    VMergeOrigin: 6,
    pPrChange: 7,
    rPrChange: 8,
    sectPrChange: 9,
    tblGridChange: 10,
    tblPrChange: 11,
    tcPrChange: 12,
    trPrChange: 13,
    ContentRun: 14
};
var c_oSerPageBorders = {
	Display: 0,
	OffsetFrom: 1,
	ZOrder: 2,
	Bottom: 3,
	Left: 4,
	Right: 5,
	Top: 6,
	Color: 7,
	Frame: 8,
	Id: 9,
	Shadow: 10,
	Space: 11,
	Sz: 12,
	ColorTheme: 13,
	Val: 16
};
var c_oSerGraphicFramePr = {
	NoChangeAspect: 0,
	NoDrilldown: 1,
	NoGrp: 2,
	NoMove: 3,
	NoResize: 4,
	NoSelect: 5
};
var c_oSerNotes = {
	Note: 0,
	NoteType: 1,
	NoteId: 2,
	NoteContent: 3,
	RefCustomMarkFollows: 4,
	RefId: 5,
	PrFmt: 6,
	PrRestart: 7,
	PrStart: 8,
	PrFntPos: 9,
	PrEndPos: 10,
	PrRef: 11
};
var c_oSerApp = {
	Application: 0,
	AppVersion: 1
};
var c_oSerDocPr = {
	Id: 0,
	Name: 1,
	Hidden: 2,
	Title: 3,
	Descr: 4
};
var c_oSerBackgroundType = {
	Color: 0,
	ColorTheme: 1,
	pptxDrawing: 2
};
var c_oSerSdt = {
	Pr: 0,
	EndPr: 1,
	Content: 2,
	Type: 3,
	Alias: 4,
	ComboBox: 5,
	LastValue: 6,
	SdtListItem: 7,
	DisplayText: 8,
	Value: 9,
	DataBinding: 10,
	PrefixMappings: 11,
	StoreItemID: 12,
	XPath: 13,
	PrDate: 14,
	FullDate: 15,
	Calendar: 16,
	DateFormat: 17,
	Lid: 18,
	StoreMappedDataAs: 19,
	DocPartList: 20,
	DocPartObj: 21,
	DocPartCategory: 22,
	DocPartGallery: 23,
	DocPartUnique: 24,
	DropDownList: 25,
	Id: 26,
	Label: 27,
	Lock: 28,
	PlaceHolder: 29,
	RPr: 30,
	ShowingPlcHdr: 31,
	TabIndex: 32,
	Tag: 33,
	Temporary: 34,
	MultiLine: 35,
	Appearance: 36,
	Color: 37
};
var c_oSerFFData = {
	CalcOnExit: 0,
	CheckBox: 1,
	DDList: 2,
	Enabled: 3,
	EntryMacro: 4,
	ExitMacro: 5,
	HelpText: 6,
	Label: 7,
	Name: 8,
	StatusText: 9,
	TabIndex: 10,
	TextInput: 11,
	CBChecked: 12,
	CBDefault: 13,
	CBSize: 14,
	CBSizeAuto: 15,
	DLDefault: 16,
	DLResult: 17,
	DLListEntry: 18,
	HTType: 19,
	HTVal: 20,
	TIDefault: 21,
	TIFormat: 22,
	TIMaxLength: 23,
	TIType: 24
};
var c_oSerCompat = {
	CompatSetting: 0,
	CompatName: 1,
	CompatUri: 2,
	CompatValue: 3
};
var ETblStyleOverrideType = {
	tblstyleoverridetypeBand1Horz:  0,
	tblstyleoverridetypeBand1Vert:  1,
	tblstyleoverridetypeBand2Horz:  2,
	tblstyleoverridetypeBand2Vert:  3,
	tblstyleoverridetypeFirstCol:  4,
	tblstyleoverridetypeFirstRow:  5,
	tblstyleoverridetypeLastCol:  6,
	tblstyleoverridetypeLastRow:  7,
	tblstyleoverridetypeNeCell:  8,
	tblstyleoverridetypeNwCell:  9,
	tblstyleoverridetypeSeCell: 10,
	tblstyleoverridetypeSwCell: 11,
	tblstyleoverridetypeWholeTable: 12
};
var EWmlColorSchemeIndex = {
	wmlcolorschemeindexAccent1:  0,
	wmlcolorschemeindexAccent2:  1,
	wmlcolorschemeindexAccent3:  2,
	wmlcolorschemeindexAccent4:  3,
	wmlcolorschemeindexAccent5:  4,
	wmlcolorschemeindexAccent6:  5,
	wmlcolorschemeindexDark1:  6,
	wmlcolorschemeindexDark2:  7,
	wmlcolorschemeindexFollowedHyperlink:  8,
	wmlcolorschemeindexHyperlink:  9,
	wmlcolorschemeindexLight1: 10,
	wmlcolorschemeindexLight2: 11
};
var EHint = {
	hintCs: 0,
	hintDefault: 1,
	hintEastAsia: 2
};
var ETblLayoutType = {
	tbllayouttypeAutofit: 1,
	tbllayouttypeFixed: 2
};
var ESectionMark = {
	sectionmarkContinuous: 0,
	sectionmarkEvenPage: 1,
	sectionmarkNextColumn: 2,
	sectionmarkNextPage: 3,
	sectionmarkOddPage: 4
};
var EThemeColor = {
	themecolorAccent1:  0,
	themecolorAccent2:  1,
	themecolorAccent3:  2,
	themecolorAccent4:  3,
	themecolorAccent5:  4,
	themecolorAccent6:  5,
	themecolorBackground1:  6,
	themecolorBackground2:  7,
	themecolorDark1:  8,
	themecolorDark2:  9,
	themecolorFollowedHyperlink: 10,
	themecolorHyperlink: 11,
	themecolorLight1: 12,
	themecolorLight2: 13,
	themecolorNone: 14,
	themecolorText1: 15,
	themecolorText2: 16
};
var EWrap = {
	wrapAround: 0,
	wrapAuto: 1,
	wrapNone: 2,
	wrapNotBeside: 3,
	wrapThrough: 4,
	wrapTight: 5
};

// math
var c_oAscLimLoc = {
  SubSup: 0x00,
  UndOvr: 0x01
};
var c_oAscMathJc = {
  Center: 0x00,
  CenterGroup: 0x01,
  Left: 0x02,
  Right: 0x03
};
var c_oAscTopBot = {
  Bot: 0x00,
  Top: 0x01
};
var c_oAscScript = {
  DoubleStruck: 0x00,
  Fraktur: 0x01,
  Monospace: 0x02,
  Roman: 0x03,
  SansSerif: 0x04,
  Script: 0x05
};
var c_oAscShp = {
  Centered: 0x00,
  Match: 0x01
};
var c_oAscSty = {
  Bold: 0x00,
  BoldItalic: 0x01,
  Italic: 0x02,
  Plain: 0x03
};
var c_oAscFType = {
  Bar: 0x00,
  Lin: 0x01,
  NoBar: 0x02,
  Skw: 0x03
};
var c_oAscBrkBin = {
  After: 0x00,
  Before: 0x01,
  Repeat: 0x02
};
var c_oAscBrkBinSub = {
  PlusMinus: 0x00,
  MinusPlus: 0x01,
  MinusMinus: 0x02
};

var g_sErrorCharCountMessage = "g_sErrorCharCountMessage";
var g_nErrorCharCount = 30000;
var g_nErrorParagraphCount = 1000;

	function getCommentAdditionalData (comment) {
		var AdditionalData = "";
		if(null != comment.m_sOOTime && "" != comment.m_sOOTime)
		{
			AdditionalData += "teamlab_data:";
			var dateStr = new Date(comment.m_sOOTime - 0).toISOString().slice(0, 19) + 'Z';
			AdditionalData += "0;" + dateStr.length + ";" + dateStr + ";";
		}
		return AdditionalData;
	};
	function ReadNextInteger(_parsed)
	{
		var _len = _parsed.data.length;
		var _found = -1;

		var _Found = ";".charCodeAt(0);
		for (var i = _parsed.pos; i < _len; i++)
		{
			if (_Found == _parsed.data.charCodeAt(i))
			{
				_found = i;
				break;
			}
		}

		if (-1 == _found)
			return -1;

		var _ret = parseInt(_parsed.data.substr(_parsed.pos, _found - _parsed.pos));
		if (isNaN(_ret))
			return -1;

		_parsed.pos = _found + 1;
		return _ret;
	};

	function ParceAdditionalData(AdditionalData, _comment_data)
	{
		if (AdditionalData.indexOf("teamlab_data:") != 0)
			return;

		var _parsed = { data : AdditionalData, pos : "teamlab_data:".length };

		while (true)
		{
			var _attr = ReadNextInteger(_parsed);
			if (-1 == _attr)
				break;

			var _len = ReadNextInteger(_parsed);
			if (-1 == _len)
				break;

			var _value = _parsed.data.substr(_parsed.pos, _len);
			_parsed.pos += (_len + 1);

			if (0 == _attr){
				var dateMs = Date.parse(_value);
				if (isNaN(dateMs)) {
					dateMs = new Date().getTime();
				}
				_comment_data.OODate = dateMs + "";
			}
		}
	}

function CreateThemeUnifill(color, tint, shade){
	var ret = null;
	if(null != color){
		var id;
		switch(color){
			case EThemeColor.themecolorAccent1: id = 0;break;
			case EThemeColor.themecolorAccent2: id = 1;break;
			case EThemeColor.themecolorAccent3: id = 2;break;
			case EThemeColor.themecolorAccent4: id = 3;break;
			case EThemeColor.themecolorAccent5: id = 4;break;
			case EThemeColor.themecolorAccent6: id = 5;break;
			case EThemeColor.themecolorBackground1: id = 6;break;
			case EThemeColor.themecolorBackground2: id = 7;break;
			case EThemeColor.themecolorDark1: id = 8;break;
			case EThemeColor.themecolorDark2: id = 9;break;
			case EThemeColor.themecolorFollowedHyperlink: id = 10;break;
			case EThemeColor.themecolorHyperlink: id = 11;break;
			case EThemeColor.themecolorLight1: id = 12;break;
			case EThemeColor.themecolorLight2: id = 13;break;
			case EThemeColor.themecolorNone: return null;break;
			case EThemeColor.themecolorText1: id = 15;break;
			case EThemeColor.themecolorText2: id = 16;break;
		}
		ret = new AscFormat.CUniFill();
		ret.setFill(new AscFormat.CSolidFill());
		ret.fill.setColor(new AscFormat.CUniColor());
		ret.fill.color.setColor(new AscFormat.CSchemeColor());
		ret.fill.color.color.setId(id);
		if(null != tint || null != shade){
			ret.fill.color.setMods(new AscFormat.CColorModifiers());
			var mod;
			if(null != tint){
				mod = new AscFormat.CColorMod();
				mod.setName("wordTint");
				mod.setVal(tint /** 100000.0 / 0xff*/);
				ret.fill.color.Mods.addMod(mod);
			}
			if(null != shade){
				mod = new AscFormat.CColorMod();
				mod.setName("wordShade");
				mod.setVal(shade /** 100000.0 / 0xff*/);
				ret.fill.color.Mods.addMod(mod);
			}
		}
	}
	return ret;
}

function WriteTrackRevision(bs, Id, reviewInfo, options) {
    if(null != reviewInfo.UserName){
        bs.memory.WriteByte(c_oSerProp_RevisionType.Author);
        bs.memory.WriteString2(reviewInfo.UserName);
    }
    if(reviewInfo.DateTime > 0){
        var dateStr = new Date(reviewInfo.DateTime).toISOString().slice(0, 19) + 'Z';
        bs.memory.WriteByte(c_oSerProp_RevisionType.Date);
        bs.memory.WriteString2(dateStr);
    }
    //increment id
    bs.WriteItem(c_oSerProp_RevisionType.Id, function(){bs.memory.WriteLong(Id);});
    
    if(null != reviewInfo.UserId){
        bs.memory.WriteByte(c_oSerProp_RevisionType.UserId);
        bs.memory.WriteString2(reviewInfo.UserId);
    }
    if(options){
        if (null != options.run) {
            var delText = reviewtype_Remove == options.ReviewType;
            bs.WriteItem(c_oSerProp_RevisionType.Content, function(){options.bdtw.WriteRun(options.run, options.bUseSelection, delText);});
        }
        if (null != options.runContent) {
            bs.WriteItem(c_oSerProp_RevisionType.ContentRun, function(){options.bmw.WriteMRunContent(options.runContent);});
        }
        if (null != options.rPr) {
            bs.WriteItem(c_oSerProp_RevisionType.rPrChange, function(){options.brPrs.Write_rPr(options.rPr, null, null);});
        }
        if (null != options.pPr) {
            bs.WriteItem(c_oSerProp_RevisionType.pPrChange, function(){options.bpPrs.Write_pPr(options.pPr);});
        }
    }
};

function ReadTrackRevision(type, length, stream, reviewInfo, options) {
    var res = c_oSerConstants.ReadOk;
    if(c_oSerProp_RevisionType.Author == type) {
        reviewInfo.UserName = stream.GetString2LE(length);
    } else if(c_oSerProp_RevisionType.Date == type) {
        var dateStr = stream.GetString2LE(length);
        var dateMs = Date.parse(dateStr);
        if (isNaN(dateMs)) {
            dateMs = new Date().getTime();
        }
        reviewInfo.DateTime = dateMs;
    } else if(c_oSerProp_RevisionType.UserId == type) {
        reviewInfo.UserId = stream.GetString2LE(length);
    } else if(options) {
        if(c_oSerProp_RevisionType.Content == type) {
            res = options.bdtr.bcr.Read1(length, function (t, l) {
                return options.bdtr.ReadParagraphContent(t, l, options.parStruct);
            });
        } else if(c_oSerProp_RevisionType.ContentRun == type) {
            res = options.bmr.bcr.Read1(length, function(t, l){
                return options.bmr.ReadMathMRun(t, l, options.run, options.props, options.oElem, options.parStruct);
            });
        } else if(c_oSerProp_RevisionType.rPrChange == type) {
            res = options.brPrr.Read(length, options.rPr, null);
        } else if(c_oSerProp_RevisionType.pPrChange == type) {
            res = options.bpPrr.Read(length, options.pPr, null);
        } else {
            res = c_oSerConstants.ReadUnknown;
        }
    } else
        res = c_oSerConstants.ReadUnknown;
    return res;
};
function initMathRevisions(elem ,props) {
    if(props.del) {
        elem.Set_ReviewTypeWithInfo(reviewtype_Remove, props.del);
    } else if(props.ins) {
        elem.Set_ReviewTypeWithInfo(reviewtype_Add, props.ins);
    }
};

function BinaryFileWriter(doc, bMailMergeDocx, bMailMergeHtml)
{
    this.memory = new AscCommon.CMemory();
    this.Document = doc;
    this.nLastFilePos = 0;
    this.nRealTableCount = 0;
	this.nStart = 0;
    this.bs = new BinaryCommonWriter(this.memory);
	this.copyParams = {
		bLockCopyElems: null,
		itemCount: null,
		bdtw: null,
		oUsedNumIdMap: null,
		nNumIdIndex: null,
		oUsedStyleMap: null
	};
	this.saveParams = new DocSaveParams(bMailMergeDocx, bMailMergeHtml);
    this.Write = function(noBase64, onlySaveBase64)
    {
        pptx_content_writer._Start();
		if (noBase64) {
			this.memory.WriteXmlString(this.WriteFileHeader(0, Asc.c_nVersionNoBase64));
		}
        this.WriteMainTable();
        pptx_content_writer._End();
		if (noBase64) {
			if (onlySaveBase64) {
				return this.memory.GetBase64Memory();
			} else {
				return this.memory.GetData();
			}
		} else {
			return this.GetResult();
		}
    }
	this.GetResult = function()
	{
		return this.WriteFileHeader(this.memory.GetCurPosition(), AscCommon.c_oSerFormat.Version) + this.memory.GetBase64Memory();
	}
    this.WriteFileHeader = function(nDataSize, version)
    {
        return AscCommon.c_oSerFormat.Signature + ";v" + version + ";" + nDataSize  + ";";
    }
    this.WriteMainTable = function()
    {
        this.WriteMainTableStart();
		this.WriteMainTableContent();
		this.WriteMainTableEnd();
    }
	this.WriteMainTableStart = function()
    {
        var nTableCount = 128;//Специально ставим большое число, чтобы не увеличивать его при добавлении очередной таблицы.
        this.nRealTableCount = 0;
        this.nStart = this.memory.GetCurPosition();
        //вычисляем с какой позиции можно писать таблицы
        var nmtItemSize = 5;//5 byte
        this.nLastFilePos = this.nStart + nTableCount * nmtItemSize;
        //Write mtLen 
        this.memory.WriteByte(0);
    }
	this.WriteMainTableContent = function()
    {
        //Write SignatureTable
        this.WriteTable(c_oSerTableTypes.Signature, new BinarySigTableWriter(this.memory, this.Document));
		
		//Write Settings
		this.WriteTable(c_oSerTableTypes.Settings, new BinarySettingsTableWriter(this.memory, this.Document, this.saveParams));
		
		//Write Comments
		var oMapCommentId = {};
		this.WriteTable(c_oSerTableTypes.Comments, new BinaryCommentsTableWriter(this.memory, this.Document, oMapCommentId));
        //Write Numbering
		var oNumIdMap = {};
        this.WriteTable(c_oSerTableTypes.Numbering, new BinaryNumberingTableWriter(this.memory, this.Document, oNumIdMap, null, this.saveParams));
        //Write StyleTable
        this.WriteTable(c_oSerTableTypes.Style, new BinaryStyleTableWriter(this.memory, this.Document, oNumIdMap, null, this.saveParams));
        //Write DocumentTable
		var oBinaryHeaderFooterTableWriter = new BinaryHeaderFooterTableWriter(this.memory, this.Document, oNumIdMap, oMapCommentId, this.saveParams);
        this.WriteTable(c_oSerTableTypes.Document, new BinaryDocumentTableWriter(this.memory, this.Document, oMapCommentId, oNumIdMap, null, this.saveParams, oBinaryHeaderFooterTableWriter));
        //Write HeaderFooter
        this.WriteTable(c_oSerTableTypes.HdrFtr, oBinaryHeaderFooterTableWriter);
		//Write Footnotes
		if (this.saveParams.footnotesIndex > 0) {
			this.WriteTable(c_oSerTableTypes.Footnotes, new BinaryNotesTableWriter(this.memory, this.Document, oNumIdMap, oMapCommentId, null, this.saveParams));
		}
        //Write OtherTable
		var oBinaryOtherTableWriter = new BinaryOtherTableWriter(this.memory, this.Document)
        this.WriteTable(c_oSerTableTypes.Other, oBinaryOtherTableWriter);
    }
	this.WriteMainTableEnd = function()
    {
        //Пишем количество таблиц
        this.memory.Seek(this.nStart);
        this.memory.WriteByte(this.nRealTableCount);
        
        //seek в конец, потому что GetBase64Memory заканчивает запись на текущей позиции.
        this.memory.Seek(this.nLastFilePos);
    }
	this.CopyStart = function()
    {
		var api = this.Document.DrawingDocument.m_oWordControl.m_oApi;
		pptx_content_writer.Start_UseFullUrl();
        if (api.ThemeLoader) {
            pptx_content_writer.Start_UseDocumentOrigin(api.ThemeLoader.ThemesUrlAbs);
        }

        pptx_content_writer._Start();
		this.copyParams.bLockCopyElems = 0;
		this.copyParams.itemCount = 0;
		this.copyParams.oUsedNumIdMap = {};
		this.copyParams.nNumIdIndex = 1;
		this.copyParams.oUsedStyleMap = {};
		this.copyParams.bdtw = new BinaryDocumentTableWriter(this.memory, this.Document, null, this.copyParams.oUsedNumIdMap, this.copyParams, this.saveParams, null);
		this.copyParams.nDocumentWriterTablePos = 0;
		this.copyParams.nDocumentWriterPos = 0;
		
		this.WriteMainTableStart();
		
		var oMapCommentId = {};
		this.WriteTable(c_oSerTableTypes.Comments, new BinaryCommentsTableWriter(this.memory, this.Document, oMapCommentId));
		this.copyParams.bdtw.oMapCommentId = oMapCommentId;
		
		this.copyParams.nDocumentWriterTablePos = this.WriteTableStart(c_oSerTableTypes.Document);
		this.copyParams.nDocumentWriterPos = this.bs.WriteItemWithLengthStart();
	}
	this.CopyParagraph = function(Item, selectedAll)
    {
		//сами параграфы скопируются в методе CopyTable, нужно только проанализировать стили
		if(this.copyParams.bLockCopyElems > 0)
			return;
		var oThis = this;
        this.bs.WriteItem(c_oSerParType.Par, function(){oThis.copyParams.bdtw.WriteParapraph(Item, false, selectedAll);});
		this.copyParams.itemCount++;
	}
	this.CopyTable = function(Item, aRowElems, nMinGrid, nMaxGrid)
    {
		//сама таблица скопируются в методе CopyTable у родительской таблицы, нужно только проанализировать стили
		if(this.copyParams.bLockCopyElems > 0)
			return;
		var oThis = this;
        this.bs.WriteItem(c_oSerParType.Table, function(){oThis.copyParams.bdtw.WriteDocTable(Item, aRowElems, nMinGrid, nMaxGrid);});
		this.copyParams.itemCount++;
	}
	this.CopySdt = function(Item)
	{
		if(this.copyParams.bLockCopyElems > 0)
			return;
		var oThis = this;
		this.bs.WriteItem(c_oSerParType.Sdt, function(){oThis.copyParams.bdtw.WriteSdt(Item, 0);});
		this.copyParams.itemCount++;
	}
	this.CopyEnd = function()
    {
		this.bs.WriteItemWithLengthEnd(this.copyParams.nDocumentWriterPos);
		this.WriteTableEnd(this.copyParams.nDocumentWriterTablePos);

		//Write Footnotes
		if (this.saveParams.footnotesIndex > 0) {
			this.WriteTable(c_oSerTableTypes.Footnotes, new BinaryNotesTableWriter(this.memory, this.Document, this.copyParams.oUsedNumIdMap, null, this.copyParams, this.saveParams));
		}
        this.WriteTable(c_oSerTableTypes.Numbering, new BinaryNumberingTableWriter(this.memory, this.Document, {}, this.copyParams.oUsedNumIdMap, this.saveParams));
        this.WriteTable(c_oSerTableTypes.Style, new BinaryStyleTableWriter(this.memory, this.Document, this.copyParams.oUsedNumIdMap, this.copyParams, this.saveParams));
		
		this.WriteMainTableEnd();
		pptx_content_writer._End();
		pptx_content_writer.End_UseFullUrl();
	}
    this.WriteTable = function(type, oTableSer)
    {
		var nCurPos = this.WriteTableStart(type);
        oTableSer.Write();
		this.WriteTableEnd(nCurPos);
    }
	this.WriteTableStart = function(type)
    {
        //Write mtItem
        //Write mtiType
        this.memory.WriteByte(type);
        //Write mtiOffBits
        this.memory.WriteLong(this.nLastFilePos);
        
        //Write table
        //Запоминаем позицию в MainTable
        var nCurPos = this.memory.GetCurPosition();
        //Seek в свободную область
        this.memory.Seek(this.nLastFilePos);
		return nCurPos;
	}
	this.WriteTableEnd = function(nCurPos)
    {
		//сдвигаем позицию куда можно следующую таблицу
        this.nLastFilePos = this.memory.GetCurPosition();
        //Seek вобратно в MainTable
        this.memory.Seek(nCurPos);
        
        this.nRealTableCount++;
	}
}
function BinarySigTableWriter(memory)
{
    this.memory = memory;
    this.Write = function()
    {
        //Write stVersion
        this.memory.WriteByte(c_oSerSigTypes.Version);
        this.memory.WriteByte(c_oSerPropLenType.Long);
        this.memory.WriteLong(AscCommon.c_oSerFormat.Version);
    }
};
function BinaryStyleTableWriter(memory, doc, oNumIdMap, copyParams, saveParams)
{
    this.memory = memory;
    this.Document = doc;
	this.copyParams = copyParams;
    this.bs = new BinaryCommonWriter(this.memory);
	this.btblPrs = new Binary_tblPrWriter(this.memory, oNumIdMap, saveParams);
    this.bpPrs = new Binary_pPrWriter(this.memory, oNumIdMap, null, saveParams);
    this.brPrs = new Binary_rPrWriter(this.memory, saveParams);
    this.Write = function()
    {
        var oThis = this;
        this.bs.WriteItemWithLength(function(){oThis.WriteStylesContent();});
    };
    this.WriteStylesContent = function()
    {
        var oThis = this;
        var oStyles = this.Document.Styles;
        var oDef_pPr = oStyles.Default.ParaPr;
        var oDef_rPr = oStyles.Default.TextPr;
        
        //default pPr
        this.bs.WriteItem(c_oSer_st.DefpPr, function(){oThis.bpPrs.Write_pPr(oDef_pPr);});
        //default rPr
        this.bs.WriteItem(c_oSer_st.DefrPr, function(){oThis.brPrs.Write_rPr(oDef_rPr, null, null);});
        //styles
        this.bs.WriteItem(c_oSer_st.Styles, function(){oThis.WriteStyles(oStyles.Style, oStyles.Default);});
    };
    this.WriteStyles = function(styles, oDefault)
    {
        var oThis = this;
		var oStyleToWrite = styles;
		if(this.copyParams && this.copyParams.oUsedStyleMap)
			oStyleToWrite = this.copyParams.oUsedStyleMap;
        for(var styleId in oStyleToWrite)
        {
            var style = styles[styleId];
            var bDefault = false;
			if(styleId == oDefault.Character)
                bDefault = true;
            else if(styleId == oDefault.Paragraph)
                bDefault = true;
            else if(styleId == oDefault.Numbering)
                bDefault = true;
            else if(styleId == oDefault.Table)
                bDefault = true;
            this.bs.WriteItem(c_oSer_sts.Style, function(){oThis.WriteStyle(styleId, style, bDefault);});
        }
    };
    this.WriteStyle = function(id, style, bDefault)
    {
        var oThis = this;
		var compilePr = this.copyParams ? this.Document.Styles.Get_Pr(id, style.Get_Type()) : style;
		
        //ID
        if(null != id)
        {
            this.memory.WriteByte(c_oSer_sts.Style_Id);
            this.memory.WriteString2(id.toString());
        }
        //Name
        if(null != style.Name)
        {
            this.memory.WriteByte(c_oSer_sts.Style_Name);
            this.memory.WriteString2(style.Name.toString());
        }
        //Type
        if(null != style.Type)
		{
			var nSerStyleType = c_oSer_StyleType.Paragraph;
			switch(style.Type)
			{
				case styletype_Character: nSerStyleType = c_oSer_StyleType.Character;break;
				case styletype_Numbering: nSerStyleType = c_oSer_StyleType.Numbering;break;
				case styletype_Paragraph: nSerStyleType = c_oSer_StyleType.Paragraph;break;
				case styletype_Table: nSerStyleType = c_oSer_StyleType.Table;break;
			}
            this.bs.WriteItem(c_oSer_sts.Style_Type, function(){oThis.memory.WriteByte(nSerStyleType);});
		}
        //Default
        if(true == bDefault)
            this.bs.WriteItem(c_oSer_sts.Style_Default, function(){oThis.memory.WriteBool(bDefault);});
        //BasedOn
        if(null != style.BasedOn)
        {
            this.memory.WriteByte(c_oSer_sts.Style_BasedOn);
            this.memory.WriteString2(style.BasedOn.toString());
        }
        //Next
        if(null != style.Next)
        {
            this.memory.WriteByte(c_oSer_sts.Style_Next);
            this.memory.WriteString2(style.Next.toString());
        }
		if(null != style.Link)
		{
			this.memory.WriteByte(c_oSer_sts.Style_Link);
			this.memory.WriteString2(style.Link);
		}
        //qFormat
        if(null != style.qFormat)
            this.bs.WriteItem(c_oSer_sts.Style_qFormat, function(){oThis.memory.WriteBool(style.qFormat);});
        //uiPriority
        if(null != style.uiPriority)
            this.bs.WriteItem(c_oSer_sts.Style_uiPriority, function(){oThis.memory.WriteLong(style.uiPriority);});
        //hidden
        if(null != style.hidden)
            this.bs.WriteItem(c_oSer_sts.Style_hidden, function(){oThis.memory.WriteBool(style.hidden);});
        //semiHidden
        if(null != style.semiHidden)
            this.bs.WriteItem(c_oSer_sts.Style_semiHidden, function(){oThis.memory.WriteBool(style.semiHidden);});
        //unhideWhenUsed
        if(null != style.unhideWhenUsed)
            this.bs.WriteItem(c_oSer_sts.Style_unhideWhenUsed, function(){oThis.memory.WriteBool(style.unhideWhenUsed);});

		//'style' is CStyle, 'compilePr' is object with some properties from CStyle, therefore get some property from style anyway
		//TextPr
        if(null != compilePr.TextPr)
            this.bs.WriteItem(c_oSer_sts.Style_TextPr, function(){oThis.brPrs.Write_rPr(compilePr.TextPr, null, null);});
        //ParaPr
        if(null != compilePr.ParaPr)
            this.bs.WriteItem(c_oSer_sts.Style_ParaPr, function(){oThis.bpPrs.Write_pPr(compilePr.ParaPr);});
		if(styletype_Table == style.Type){
			//TablePr
			if(null != compilePr.TablePr)
				this.bs.WriteItem(c_oSer_sts.Style_TablePr, function(){oThis.btblPrs.WriteTblPr(compilePr.TablePr, null);});
			//TableRowPr
			if(null != compilePr.TableRowPr)
				this.bs.WriteItem(c_oSer_sts.Style_RowPr, function(){oThis.btblPrs.WriteRowPr(compilePr.TableRowPr);});
			//TableCellPr
			if(null != compilePr.TableCellPr)
				this.bs.WriteItem(c_oSer_sts.Style_CellPr, function(){oThis.btblPrs.WriteCellPr(compilePr.TableCellPr);});
			//TblStylePr
			var aTblStylePr = [];
			if(null != compilePr.TableBand1Horz)
				aTblStylePr.push({type: ETblStyleOverrideType.tblstyleoverridetypeBand1Horz, val: compilePr.TableBand1Horz});
			if(null != compilePr.TableBand1Vert)
				aTblStylePr.push({type: ETblStyleOverrideType.tblstyleoverridetypeBand1Vert, val: compilePr.TableBand1Vert});
			if(null != compilePr.TableBand2Horz)
				aTblStylePr.push({type: ETblStyleOverrideType.tblstyleoverridetypeBand2Horz, val: compilePr.TableBand2Horz});
			if(null != compilePr.TableBand2Vert)
				aTblStylePr.push({type: ETblStyleOverrideType.tblstyleoverridetypeBand2Vert, val: compilePr.TableBand2Vert});
			if(null != compilePr.TableFirstCol)
				aTblStylePr.push({type: ETblStyleOverrideType.tblstyleoverridetypeFirstCol, val: compilePr.TableFirstCol});
			if(null != compilePr.TableFirstRow)
				aTblStylePr.push({type: ETblStyleOverrideType.tblstyleoverridetypeFirstRow, val: compilePr.TableFirstRow});
			if(null != compilePr.TableLastCol)
				aTblStylePr.push({type: ETblStyleOverrideType.tblstyleoverridetypeLastCol, val: compilePr.TableLastCol});
			if(null != compilePr.TableLastRow)
				aTblStylePr.push({type: ETblStyleOverrideType.tblstyleoverridetypeLastRow, val: compilePr.TableLastRow});
			if(null != compilePr.TableTLCell)
				aTblStylePr.push({type: ETblStyleOverrideType.tblstyleoverridetypeNwCell, val: compilePr.TableTLCell});
			if(null != compilePr.TableTRCell)
				aTblStylePr.push({type: ETblStyleOverrideType.tblstyleoverridetypeNeCell, val: compilePr.TableTRCell});
			if(null != compilePr.TableBLCell)
				aTblStylePr.push({type: ETblStyleOverrideType.tblstyleoverridetypeSwCell, val: compilePr.TableBLCell});
			if(null != compilePr.TableBRCell)
				aTblStylePr.push({type: ETblStyleOverrideType.tblstyleoverridetypeSeCell, val: compilePr.TableBRCell});
			if(null != compilePr.TableWholeTable)
				aTblStylePr.push({type: ETblStyleOverrideType.tblstyleoverridetypeWholeTable, val: compilePr.TableWholeTable});
			if(aTblStylePr.length > 0)
				this.bs.WriteItem(c_oSer_sts.Style_TblStylePr, function(){oThis.WriteTblStylePr(aTblStylePr);});
		}
		if(style.IsCustom())
			this.bs.WriteItem(c_oSer_sts.Style_CustomStyle, function(){oThis.memory.WriteBool(true);});
		// if(null != style.Aliases){
		// 	this.memory.WriteByte(c_oSer_sts.Style_Aliases);
		// 	this.memory.WriteString2(style.Aliases);
		// }
		// if(null != style.AutoRedefine)
		// 	this.bs.WriteItem(c_oSer_sts.Style_AutoRedefine, function(){oThis.memory.WriteBool(style.AutoRedefine);});
		// if(null != style.Locked)
		// 	this.bs.WriteItem(c_oSer_sts.Style_Locked, function(){oThis.memory.WriteBool(style.Locked);});
		// if(null != style.Personal)
		// 	this.bs.WriteItem(c_oSer_sts.Style_Personal, function(){oThis.memory.WriteBool(style.Personal);});
		// if(null != style.PersonalCompose)
		// 	this.bs.WriteItem(c_oSer_sts.Style_PersonalCompose, function(){oThis.memory.WriteBool(style.PersonalCompose);});
		// if(null != style.PersonalReply)
		// 	this.bs.WriteItem(c_oSer_sts.Style_PersonalReply, function(){oThis.memory.WriteBool(style.PersonalReply);});
    };
	this.WriteTblStylePr = function(aTblStylePr)
    {
		var oThis = this;
		for(var i = 0, length = aTblStylePr.length; i < length; ++i)
			this.bs.WriteItem(c_oSerProp_tblStylePrType.TblStylePr, function(){oThis.WriteTblStyleProperty(aTblStylePr[i]);});
	};
	this.WriteTblStyleProperty = function(oProp)
	{
		var oThis = this;
		var type = oProp.type;
		var val = oProp.val;
		this.bs.WriteItem(c_oSerProp_tblStylePrType.Type, function(){oThis.memory.WriteByte(type);});
		if(null != val.TextPr)
			this.bs.WriteItem(c_oSerProp_tblStylePrType.RunPr, function(){oThis.brPrs.Write_rPr(val.TextPr, null, null);});
		if(null != val.ParaPr)
			this.bs.WriteItem(c_oSerProp_tblStylePrType.ParPr, function(){oThis.bpPrs.Write_pPr(val.ParaPr);});
		if(null != val.TablePr)
			this.bs.WriteItem(c_oSerProp_tblStylePrType.TblPr, function(){oThis.btblPrs.WriteTblPr(val.TablePr, null);});
		if(null != val.TableRowPr)
			this.bs.WriteItem(c_oSerProp_tblStylePrType.TrPr, function(){oThis.btblPrs.WriteRowPr(val.TableRowPr);});
		if(null != val.TableCellPr)
			this.bs.WriteItem(c_oSerProp_tblStylePrType.TcPr, function(){oThis.btblPrs.WriteCellPr(val.TableCellPr);});
	};
};
function Binary_pPrWriter(memory, oNumIdMap, oBinaryHeaderFooterTableWriter, saveParams)
{
    this.memory = memory;
	this.oNumIdMap = oNumIdMap;
    this.saveParams = saveParams;
	this.oBinaryHeaderFooterTableWriter = oBinaryHeaderFooterTableWriter;
    this.bs = new BinaryCommonWriter(this.memory);
    this.brPrs = new Binary_rPrWriter(this.memory, saveParams);
    this.Write_pPr = function(pPr, pPr_rPr, EndRun, SectPr, oDocument)
    {
        var oThis = this;
        //Стили надо писать первыми, потому что применение стиля при открытии уничтажаются настройки параграфа
        if(null != pPr.PStyle)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.ParaStyle);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.memory.WriteString2(pPr.PStyle);
        }
        //Списки надо писать после стилей, т.к. при открытии в методах добавления списка проверяются стили
        if(null != pPr.NumPr)
        {
			var numPr = pPr.NumPr;
			var id = null;
			if(null != this.oNumIdMap && null != numPr.NumId)
			{
				id = this.oNumIdMap[numPr.NumId];
				if(null == id)
					id = 0;
			}
			if(null != numPr.Lvl || null != id)
			{
				this.memory.WriteByte(c_oSerProp_pPrType.numPr);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.bs.WriteItemWithLength(function(){oThis.WriteNumPr(id, numPr.Lvl);});
			}
        }
        //contextualSpacing
        if(null != pPr.ContextualSpacing)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.contextualSpacing);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(pPr.ContextualSpacing);
        }
        //Ind
        if(null != pPr.Ind)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.Ind);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.WriteInd(pPr.Ind);});
        }
        //Jc
        if(null != pPr.Jc)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.Jc);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(pPr.Jc);
        }
        //KeepLines
        if(null != pPr.KeepLines)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.KeepLines);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(pPr.KeepLines);
        }
        //KeepNext
        if(null != pPr.KeepNext)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.KeepNext);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(pPr.KeepNext);
        }
        //PageBreakBefore
        if(null != pPr.PageBreakBefore)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.PageBreakBefore);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(pPr.PageBreakBefore);
        }
        //Spacing
        if(null != pPr.Spacing)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.Spacing);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.WriteSpacing(pPr.Spacing);});
        }
        //Shd
        if(null != pPr.Shd)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.Shd);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.bs.WriteShd(pPr.Shd);});
        }
        //WidowControl
        if(null != pPr.WidowControl)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.WidowControl);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(pPr.WidowControl);
        }
        //Tabs
        if(null != pPr.Tabs && pPr.Tabs.Get_Count() > 0)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.Tab);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.WriteTabs(pPr.Tabs.Tabs);});
        }
        //EndRun
        if(null != pPr_rPr && null != EndRun)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.pPr_rPr);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.brPrs.Write_rPr(pPr_rPr, EndRun.Pr, EndRun);});
        }
        //pBdr
        if(null != pPr.Brd)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.pBdr);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.bs.WriteBorders(pPr.Brd);});
        }
		//FramePr
        if(null != pPr.FramePr)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.FramePr);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.WriteFramePr(pPr.FramePr);});
        }
        //SectPr
        if(null != SectPr && null != oDocument)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.SectPr);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.WriteSectPr(SectPr, oDocument);});
        }

        if(null != pPr.PrChange && pPr.ReviewInfo)
        {
            var bpPrs = new Binary_pPrWriter(this.memory, this.oNumIdMap, this.oBinaryHeaderFooterTableWriter, this.saveParams);
            this.memory.WriteByte(c_oSerProp_pPrType.pPrChange);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){WriteTrackRevision(oThis.bs, oThis.saveParams.trackRevisionId++, pPr.ReviewInfo, {bpPrs: bpPrs, pPr: pPr.PrChange});});
        }
		if(null != pPr.OutlineLvl)
		{
			this.memory.WriteByte(c_oSerProp_pPrType.outlineLvl);
			this.memory.WriteByte(c_oSerPropLenType.Long);
			this.memory.WriteLong(pPr.OutlineLvl);
		}
    };
    this.WriteInd = function(Ind)
    {
        //Left
        if(null != Ind.Left)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.Ind_Left);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble(Ind.Left);
        }
        //Right
        if(null != Ind.Right)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.Ind_Right);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble(Ind.Right);
        }
        //FirstLine
        if(null != Ind.FirstLine)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.Ind_FirstLine);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble(Ind.FirstLine);
        }
    };
    this.WriteSpacing = function(Spacing)
    {
        //Line
        if(null != Spacing.Line)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.Spacing_Line);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble(Spacing.Line);
        }
        //LineRule
        if(null != Spacing.LineRule)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.Spacing_LineRule);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(Spacing.LineRule);
        }
        //Before
        if(null != Spacing.BeforeAutoSpacing)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.Spacing_BeforeAuto);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(Spacing.BeforeAutoSpacing);
        }
        if(null != Spacing.Before)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.Spacing_Before);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble(Spacing.Before);
        }
        //After
        if(null != Spacing.AfterAutoSpacing)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.Spacing_AfterAuto);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(Spacing.AfterAutoSpacing);
        }
        if(null != Spacing.After)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.Spacing_After);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble(Spacing.After);
        }
    };
    this.WriteTabs = function(Tab)
    {
        var oThis = this;
        //Len
        var nLen = Tab.length;
        for(var i = 0; i < nLen; ++i)
        {
            var tab = Tab[i];
            this.memory.WriteByte(c_oSerProp_pPrType.Tab_Item);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.WriteTabItem(tab);});
        }
    };
    this.WriteTabItem = function(TabItem)
    {
        //type
        this.memory.WriteByte(c_oSerProp_pPrType.Tab_Item_Val);
        this.memory.WriteByte(c_oSerPropLenType.Byte);
		switch(TabItem.Value)
		{
			case tab_Right: this.memory.WriteByte(AscCommon.g_tabtype_right);break;
			case tab_Center: this.memory.WriteByte(AscCommon.g_tabtype_center);break;
			case tab_Clear: this.memory.WriteByte(AscCommon.g_tabtype_clear);break;
			default:this.memory.WriteByte(AscCommon.g_tabtype_left);
		}
        
        //pos
        this.memory.WriteByte(c_oSerProp_pPrType.Tab_Item_Pos);
        this.memory.WriteByte(c_oSerPropLenType.Double);
        this.memory.WriteDouble(TabItem.Pos);

		this.memory.WriteByte(c_oSerProp_pPrType.Tab_Item_Leader);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteByte(TabItem.Leader);
    };
    this.WriteNumPr = function(id, lvl)
    {
        //type
        if(null != lvl)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.numPr_lvl);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(lvl);
        }
        //pos
        if(null != id)
        {
            this.memory.WriteByte(c_oSerProp_pPrType.numPr_id);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(id);
        }
    };
	this.WriteFramePr = function(oFramePr)
    {
        if(null != oFramePr.DropCap)
        {
            this.memory.WriteByte(c_oSer_FramePrType.DropCap);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(oFramePr.DropCap);
        }
		if(null != oFramePr.H)
        {
            this.memory.WriteByte(c_oSer_FramePrType.H);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(g_dKoef_mm_to_twips * oFramePr.H);
        }
		if(null != oFramePr.HAnchor)
        {
            this.memory.WriteByte(c_oSer_FramePrType.HAnchor);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(oFramePr.HAnchor);
        }
		if(null != oFramePr.HRule)
        {
            this.memory.WriteByte(c_oSer_FramePrType.HRule);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(oFramePr.HRule);
        }
		if(null != oFramePr.HSpace)
        {
            this.memory.WriteByte(c_oSer_FramePrType.HSpace);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(g_dKoef_mm_to_twips * oFramePr.HSpace);
        }
		if(null != oFramePr.Lines)
        {
            this.memory.WriteByte(c_oSer_FramePrType.Lines);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(oFramePr.Lines);
        }
		if(null != oFramePr.VAnchor)
        {
            this.memory.WriteByte(c_oSer_FramePrType.VAnchor);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(oFramePr.VAnchor);
        }
		if(null != oFramePr.VSpace)
        {
            this.memory.WriteByte(c_oSer_FramePrType.VSpace);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(g_dKoef_mm_to_twips * oFramePr.VSpace);
        }
		if(null != oFramePr.W)
        {
            this.memory.WriteByte(c_oSer_FramePrType.W);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(g_dKoef_mm_to_twips * oFramePr.W);
        }
		if(null != oFramePr.Wrap)
        {
			var nFormatWrap = EWrap.None;
			switch(oFramePr.Wrap){
				case wrap_Around: nFormatWrap = EWrap.wrapAround;break;
				case wrap_Auto: nFormatWrap = EWrap.wrapAuto;break;
				case wrap_None: nFormatWrap = EWrap.wrapNone;break;
				case wrap_NotBeside: nFormatWrap = EWrap.wrapNotBeside;break;
				case wrap_Through: nFormatWrap = EWrap.wrapThrough;break;
				case wrap_Tight: nFormatWrap = EWrap.wrapTight;break;
			}
            this.memory.WriteByte(c_oSer_FramePrType.Wrap);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(nFormatWrap);
        }
		if(null != oFramePr.X)
        {
            this.memory.WriteByte(c_oSer_FramePrType.X);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(g_dKoef_mm_to_twips * oFramePr.X);
        }
		if(null != oFramePr.XAlign)
        {
            this.memory.WriteByte(c_oSer_FramePrType.XAlign);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(oFramePr.XAlign);
        }
		if(null != oFramePr.Y)
        {
            this.memory.WriteByte(c_oSer_FramePrType.Y);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(g_dKoef_mm_to_twips * oFramePr.Y);
        }
		if(null != oFramePr.YAlign)
        {
            this.memory.WriteByte(c_oSer_FramePrType.YAlign);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(oFramePr.YAlign);
        }
    };
	this.WriteSectPr = function(sectPr, oDocument)
    {
        var oThis = this;
        //pgSz
        this.bs.WriteItem(c_oSerProp_secPrType.pgSz, function(){oThis.WritePageSize(sectPr, oDocument);});
        //pgMar
        this.bs.WriteItem(c_oSerProp_secPrType.pgMar, function(){oThis.WritePageMargin(sectPr, oDocument);});
		//setting
        this.bs.WriteItem(c_oSerProp_secPrType.setting, function(){oThis.WritePageSetting(sectPr, oDocument);});
		//header
		if(null != sectPr.HeaderFirst || null != sectPr.HeaderEven || null != sectPr.HeaderDefault)
			this.bs.WriteItem(c_oSerProp_secPrType.headers, function(){oThis.WriteHdr(sectPr);});
		//footer
		if(null != sectPr.FooterFirst || null != sectPr.FooterEven || null != sectPr.FooterDefault)
			this.bs.WriteItem(c_oSerProp_secPrType.footers, function(){oThis.WriteFtr(sectPr);});
		var PageNumType = sectPr.Get_PageNum_Start();
		if(-1 != PageNumType)
			this.bs.WriteItem(c_oSerProp_secPrType.pageNumType, function(){oThis.WritePageNumType(PageNumType);});
		if(null != sectPr.Columns)
			this.bs.WriteItem(c_oSerProp_secPrType.cols, function(){oThis.WriteColumns(sectPr.Columns);});
		if(null != sectPr.Borders && !sectPr.Borders.IsEmptyBorders())
			this.bs.WriteItem(c_oSerProp_secPrType.pgBorders, function(){oThis.WritePgBorders(sectPr.Borders);});
		if(null != sectPr.FootnotePr)
			this.bs.WriteItem(c_oSerProp_secPrType.footnotePr, function(){oThis.WriteFootnotePr(sectPr.FootnotePr);});
    };
	this.WriteFootnotePr = function(footnotePr)
	{
		var oThis = this;
		if (null != footnotePr.NumRestart) {
			this.bs.WriteItem(c_oSerNotes.PrRestart, function(){oThis.memory.WriteByte(footnotePr.NumRestart);});
		}
		if (null != footnotePr.NumFormat) {
			this.bs.WriteItem(c_oSerNotes.PrFmt, function(){oThis.WriteNumFmt(footnotePr.NumFormat);});
		}
		if (null != footnotePr.NumStart) {
			this.bs.WriteItem(c_oSerNotes.PrStart, function(){oThis.memory.WriteLong(footnotePr.NumStart);});
		}
		if (null != footnotePr.Pos) {
			this.bs.WriteItem(c_oSerNotes.PrFntPos, function(){oThis.memory.WriteByte(footnotePr.Pos);});
		}
	};
	this.WriteNumFmt = function(fmt)
	{
		var oThis = this;
		if (fmt) {
			var val;
			switch (fmt) {
				case Asc.c_oAscNumberingFormat.None: val = 48; break;
				case Asc.c_oAscNumberingFormat.Bullet: val = 5; break;
				case Asc.c_oAscNumberingFormat.Decimal: val = 13; break;
				case Asc.c_oAscNumberingFormat.LowerRoman: val = 47; break;
				case Asc.c_oAscNumberingFormat.UpperRoman: val = 61; break;
				case Asc.c_oAscNumberingFormat.LowerLetter: val = 46; break;
				case Asc.c_oAscNumberingFormat.UpperLetter: val = 60; break;
				case Asc.c_oAscNumberingFormat.DecimalZero: val = 21; break;
				default: val = 13; break;
			}
			this.bs.WriteItem(c_oSerNumTypes.NumFmtVal, function(){oThis.memory.WriteByte(val);});
		}
	};
    this.WritePageSize = function(sectPr, oDocument)
    {
        var oThis = this;
        //W
        this.memory.WriteByte(c_oSer_pgSzType.W);
        this.memory.WriteByte(c_oSerPropLenType.Double);
        this.memory.WriteDouble(sectPr.Get_PageWidth());
        //H
        this.memory.WriteByte(c_oSer_pgSzType.H);
        this.memory.WriteByte(c_oSerPropLenType.Double);
        this.memory.WriteDouble(sectPr.Get_PageHeight());
        //Orientation
        this.memory.WriteByte(c_oSer_pgSzType.Orientation);
        this.memory.WriteByte(c_oSerPropLenType.Byte);
        this.memory.WriteByte(sectPr.Get_Orientation());
    };
    this.WritePageMargin = function(sectPr, oDocument)
    {
        //Left
        this.memory.WriteByte(c_oSer_pgMarType.Left);
        this.memory.WriteByte(c_oSerPropLenType.Double);
        this.memory.WriteDouble(sectPr.Get_PageMargin_Left());
        //Top
        this.memory.WriteByte(c_oSer_pgMarType.Top);
        this.memory.WriteByte(c_oSerPropLenType.Double);
        this.memory.WriteDouble(sectPr.Get_PageMargin_Top());
        //Right
        this.memory.WriteByte(c_oSer_pgMarType.Right);
        this.memory.WriteByte(c_oSerPropLenType.Double);
        this.memory.WriteDouble(sectPr.Get_PageMargin_Right());
        //Bottom
        this.memory.WriteByte(c_oSer_pgMarType.Bottom);
        this.memory.WriteByte(c_oSerPropLenType.Double);
        this.memory.WriteDouble(sectPr.Get_PageMargin_Bottom());
        
        //Header
        this.memory.WriteByte(c_oSer_pgMarType.Header);
        this.memory.WriteByte(c_oSerPropLenType.Double);
        this.memory.WriteDouble(sectPr.Get_PageMargins_Header());
        //Footer
        this.memory.WriteByte(c_oSer_pgMarType.Footer);
        this.memory.WriteByte(c_oSerPropLenType.Double);
        this.memory.WriteDouble(sectPr.Get_PageMargins_Footer());
    };
	this.WritePageSetting = function(sectPr, oDocument)
    {
		var titlePg = sectPr.Get_TitlePage();
        //titlePg
		if(titlePg)
		{
			this.memory.WriteByte(c_oSerProp_secPrSettingsType.titlePg);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(titlePg);
		}
        //EvenAndOddHeaders
		if(EvenAndOddHeaders)
		{
			this.memory.WriteByte(c_oSerProp_secPrSettingsType.EvenAndOddHeaders);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(EvenAndOddHeaders);
		}
		var nFormatType = null;
		switch(sectPr.Get_Type())
		{
			case c_oAscSectionBreakType.Continuous: nFormatType = ESectionMark.sectionmarkContinuous;break;
			case c_oAscSectionBreakType.EvenPage: nFormatType = ESectionMark.sectionmarkEvenPage;break;
			case c_oAscSectionBreakType.Column: nFormatType = ESectionMark.sectionmarkNextColumn;break;
			case c_oAscSectionBreakType.NextPage: nFormatType = ESectionMark.sectionmarkNextPage;break;
			case c_oAscSectionBreakType.OddPage: nFormatType = ESectionMark.sectionmarkOddPage;break;
		}
		if(null != nFormatType)
		{
			this.memory.WriteByte(c_oSerProp_secPrSettingsType.SectionType);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteByte(nFormatType);
		}
    };
	this.WriteHdr = function(sectPr)
	{
		var oThis = this;
		var nIndex;
		if(null != this.oBinaryHeaderFooterTableWriter){
			if(null != sectPr.HeaderDefault){
				nIndex = this.oBinaryHeaderFooterTableWriter.aHeaders.length;
				this.bs.WriteItem(c_oSerProp_secPrType.hdrftrelem, function(){oThis.memory.WriteLong(nIndex);});
				this.oBinaryHeaderFooterTableWriter.aHeaders.push({type: c_oSerHdrFtrTypes.HdrFtr_Odd, elem: sectPr.HeaderDefault});
			}
			if(null != sectPr.HeaderEven){
				nIndex = this.oBinaryHeaderFooterTableWriter.aHeaders.length;
				this.bs.WriteItem(c_oSerProp_secPrType.hdrftrelem, function(){oThis.memory.WriteLong(nIndex);});
				this.oBinaryHeaderFooterTableWriter.aHeaders.push({type: c_oSerHdrFtrTypes.HdrFtr_Even, elem: sectPr.HeaderEven});
			}
			if(null != sectPr.HeaderFirst){
				nIndex = this.oBinaryHeaderFooterTableWriter.aHeaders.length;
				this.bs.WriteItem(c_oSerProp_secPrType.hdrftrelem, function(){oThis.memory.WriteLong(nIndex);});
				this.oBinaryHeaderFooterTableWriter.aHeaders.push({type: c_oSerHdrFtrTypes.HdrFtr_First, elem: sectPr.HeaderFirst});
			}
		}
	}
	this.WriteFtr = function(sectPr)
	{
		var oThis = this;
		var nIndex;
		if(null != this.oBinaryHeaderFooterTableWriter){
			if(null != sectPr.FooterDefault){
				nIndex = this.oBinaryHeaderFooterTableWriter.aFooters.length;
				this.bs.WriteItem(c_oSerProp_secPrType.hdrftrelem, function(){oThis.memory.WriteLong(nIndex);});
				this.oBinaryHeaderFooterTableWriter.aFooters.push({type: c_oSerHdrFtrTypes.HdrFtr_Odd, elem: sectPr.FooterDefault});
			}
			if(null != sectPr.FooterEven){
				nIndex = this.oBinaryHeaderFooterTableWriter.aFooters.length;
				this.bs.WriteItem(c_oSerProp_secPrType.hdrftrelem, function(){oThis.memory.WriteLong(nIndex);});
				this.oBinaryHeaderFooterTableWriter.aFooters.push({type: c_oSerHdrFtrTypes.HdrFtr_Even, elem: sectPr.FooterEven});
			}
			if(null != sectPr.FooterFirst){
				nIndex = this.oBinaryHeaderFooterTableWriter.aFooters.length;
				this.bs.WriteItem(c_oSerProp_secPrType.hdrftrelem, function(){oThis.memory.WriteLong(nIndex);});
				this.oBinaryHeaderFooterTableWriter.aFooters.push({type: c_oSerHdrFtrTypes.HdrFtr_First, elem: sectPr.FooterFirst});
			}
		}
	}
	this.WritePageNumType = function(PageNumType)
	{
		var oThis = this;
		this.bs.WriteItem(c_oSerProp_secPrPageNumType.start, function(){oThis.memory.WriteLong(PageNumType);});
	}
    this.WriteColumns = function(cols)
    {
        var oThis = this;
        if (null != cols.EqualWidth) {
            this.bs.WriteItem(c_oSerProp_Columns.EqualWidth, function(){oThis.memory.WriteBool(cols.EqualWidth);});
        }
        if (null != cols.Num) {
            this.bs.WriteItem(c_oSerProp_Columns.Num, function(){oThis.memory.WriteLong(cols.Num);});
        }
        if (null != cols.Sep) {
            this.bs.WriteItem(c_oSerProp_Columns.Sep, function(){oThis.memory.WriteBool(cols.Sep);});
        }
        if (null != cols.Space) {
            this.bs.WriteItem(c_oSerProp_Columns.Space, function(){oThis.memory.WriteLong(g_dKoef_mm_to_twips * cols.Space);});
        }
        for (var i = 0; i < cols.Cols.length; ++i) {
            this.bs.WriteItem(c_oSerProp_Columns.Column, function(){oThis.WriteColumn(cols.Cols[i]);});
        }
	}
    this.WriteColumn = function(col)
    {
        var oThis = this;
        if (null != col.Space) {
            this.bs.WriteItem(c_oSerProp_Columns.ColumnSpace, function(){oThis.memory.WriteLong(g_dKoef_mm_to_twips * col.Space);});
        }
        if (null != col.W) {
            this.bs.WriteItem(c_oSerProp_Columns.ColumnW, function(){oThis.memory.WriteLong(g_dKoef_mm_to_twips * col.W);});
        }
    }
	this.WritePgBorders = function(pageBorders)
	{
		var oThis = this;
		if (null != pageBorders.Display) {
			this.bs.WriteItem(c_oSerPageBorders.Display, function(){oThis.memory.WriteByte(pageBorders.Display);});
		}
		if (null != pageBorders.OffsetFrom) {
			this.bs.WriteItem(c_oSerPageBorders.OffsetFrom, function(){oThis.memory.WriteByte(pageBorders.OffsetFrom);});
		}
		if (null != pageBorders.ZOrder) {
			this.bs.WriteItem(c_oSerPageBorders.ZOrder, function(){oThis.memory.WriteByte(pageBorders.ZOrder);});
		}
		if (null != pageBorders.Bottom && !pageBorders.Bottom.IsNone()) {
			this.bs.WriteItem(c_oSerPageBorders.Bottom, function(){oThis.WritePgBorder(pageBorders.Bottom);});
		}
		if (null != pageBorders.Left && !pageBorders.Left.IsNone()) {
			this.bs.WriteItem(c_oSerPageBorders.Left, function(){oThis.WritePgBorder(pageBorders.Left);});
		}
		if (null != pageBorders.Right && !pageBorders.Right.IsNone()) {
			this.bs.WriteItem(c_oSerPageBorders.Right, function(){oThis.WritePgBorder(pageBorders.Right);});
		}
		if (null != pageBorders.Top && !pageBorders.Top.IsNone()) {
			this.bs.WriteItem(c_oSerPageBorders.Top, function(){oThis.WritePgBorder(pageBorders.Top);});
		}
	}
	this.WritePgBorder = function(border)
	{
		var _this = this;
		if(null != border.Value)
		{
			var color = null;
			if (null != border.Color)
				color = border.Color;
			else if (null != border.Unifill && editor && editor.WordControl && editor.WordControl.m_oLogicDocument) {
				var doc = editor.WordControl.m_oLogicDocument;
				border.Unifill.check(doc.Get_Theme(), doc.Get_ColorMap());
				var RGBA = border.Unifill.getRGBAColor();
				color = new AscCommonWord.CDocumentColor(RGBA.R, RGBA.G, RGBA.B);
			}
			if (null != color && !color.Auto)
				this.bs.WriteColor(c_oSerPageBorders.Color, color);
			if (null != border.Space) {
				this.memory.WriteByte(c_oSerPageBorders.Space);
				this.memory.WriteByte(c_oSerPropLenType.Long);
				this.memory.WriteLong(Math.round(g_dKoef_mm_to_pt * border.Space));
			}
			if (null != border.Size) {
				this.memory.WriteByte(c_oSerPageBorders.Sz);
				this.memory.WriteByte(c_oSerPropLenType.Long);
				this.memory.WriteLong(Math.round(8 * g_dKoef_mm_to_pt * border.Size));
			}
			if (null != border.Unifill || (null != border.Color && border.Color.Auto)) {
				this.memory.WriteByte(c_oSerPageBorders.ColorTheme);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.bs.WriteItemWithLength(function () { _this.bs.WriteColorTheme(border.Unifill, border.Color); });
			}

			this.memory.WriteByte(c_oSerPageBorders.Val);
			this.memory.WriteByte(c_oSerPropLenType.Long);
			if(border_None == border.Value){
				this.memory.WriteLong(-1);
			} else {
				this.memory.WriteLong(1);
			}
		}
	}
};
function Binary_rPrWriter(memory, saveParams)
{
    this.memory = memory;
    this.saveParams = saveParams;
    this.bs = new BinaryCommonWriter(this.memory);
    this.Write_rPr = function(rPr, rPrReview, EndRun)
    {
		var _this = this;
        //Bold
        if(null != rPr.Bold)
        {
            var bold = rPr.Bold;
            this.memory.WriteByte(c_oSerProp_rPrType.Bold);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(bold);
        }
        //Italic
        if(null != rPr.Italic)
        {
            var italic = rPr.Italic;
            this.memory.WriteByte(c_oSerProp_rPrType.Italic);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(italic);
        }
        //Underline
        if(null != rPr.Underline)
        {
            this.memory.WriteByte(c_oSerProp_rPrType.Underline);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(rPr.Underline);
        }
        //Strikeout
        if(null != rPr.Strikeout)
        {
            this.memory.WriteByte(c_oSerProp_rPrType.Strikeout);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(rPr.Strikeout);
        }
        //FontFamily
        if(null != rPr.RFonts)
        {
            var font = rPr.RFonts;
			if(null != font.Ascii)
			{
				this.memory.WriteByte(c_oSerProp_rPrType.FontAscii);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.memory.WriteString2(font.Ascii.Name);
			}
            if(null != font.HAnsi)
			{
				this.memory.WriteByte(c_oSerProp_rPrType.FontHAnsi);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.memory.WriteString2(font.HAnsi.Name);
			}
            if(null != font.CS)
			{
				this.memory.WriteByte(c_oSerProp_rPrType.FontCS);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.memory.WriteString2(font.CS.Name);
			}
            if(null != font.EastAsia)
			{
				this.memory.WriteByte(c_oSerProp_rPrType.FontAE);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.memory.WriteString2(font.EastAsia.Name);
			}
			if(null != font.Hint)
			{
				var nHint;
				switch(font.Hint)
				{
					case fonthint_CS:nHint = EHint.hintCs;break;
					case fonthint_EastAsia:nHint = EHint.hintEastAsia;break;
					default :nHint = EHint.hintDefault;break;
				}
				this.memory.WriteByte(c_oSerProp_rPrType.FontHint);
				this.memory.WriteByte(c_oSerPropLenType.Byte);
				this.memory.WriteByte(nHint);
			}
        }
        //FontSize
        if(null != rPr.FontSize)
        {
            this.memory.WriteByte(c_oSerProp_rPrType.FontSize);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(rPr.FontSize * 2);
        }
        //Color
        var color = null;
        if (null != rPr.Color )
            color = rPr.Color;
		else if (null != rPr.Unifill && editor && editor.WordControl && editor.WordControl.m_oLogicDocument) {
            var doc = editor.WordControl.m_oLogicDocument;
            rPr.Unifill.check(doc.Get_Theme(), doc.Get_ColorMap());
            var RGBA = rPr.Unifill.getRGBAColor();
            color = new CDocumentColor(RGBA.R, RGBA.G, RGBA.B);
        }
        if (null != color && !color.Auto)
            this.bs.WriteColor(c_oSerProp_rPrType.Color, color);
        //VertAlign
        if(null != rPr.VertAlign)
        {
            this.memory.WriteByte(c_oSerProp_rPrType.VertAlign);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(rPr.VertAlign);
        }
        //HighLight
        if(null != rPr.HighLight)
        {
            if(highlight_None == rPr.HighLight)
            {
                this.memory.WriteByte(c_oSerProp_rPrType.HighLightTyped);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteByte(AscCommon.c_oSer_ColorType.Auto);
            }
            else
            {
                this.bs.WriteColor(c_oSerProp_rPrType.HighLight, rPr.HighLight);
            }
        }
		//RStyle
        if(null != rPr.RStyle)
        {
		    this.memory.WriteByte(c_oSerProp_rPrType.RStyle);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.memory.WriteString2(rPr.RStyle);
		}
		//Spacing
        if(null != rPr.Spacing)
        {
		    this.memory.WriteByte(c_oSerProp_rPrType.Spacing);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble(rPr.Spacing);
		}
		//DStrikeout
        if(null != rPr.DStrikeout)
        {
		    this.memory.WriteByte(c_oSerProp_rPrType.DStrikeout);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(rPr.DStrikeout);
		}
		//Caps
        if(null != rPr.Caps)
        {
		    this.memory.WriteByte(c_oSerProp_rPrType.Caps);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(rPr.Caps);
		}
		//SmallCaps
        if(null != rPr.SmallCaps)
        {
		    this.memory.WriteByte(c_oSerProp_rPrType.SmallCaps);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(rPr.SmallCaps);
		}
		//Position
        if(null != rPr.Position)
        {
		    this.memory.WriteByte(c_oSerProp_rPrType.Position);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble(rPr.Position);
		}
		//BoldCs
		if(null != rPr.BoldCS)
		{
			this.memory.WriteByte(c_oSerProp_rPrType.BoldCs);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(rPr.BoldCS);
		}
		//ItalicCS
		if(null != rPr.ItalicCS)
		{
			this.memory.WriteByte(c_oSerProp_rPrType.ItalicCs);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(rPr.ItalicCS);
		}
		//FontSizeCS
		if(null != rPr.FontSizeCS)
		{
			this.memory.WriteByte(c_oSerProp_rPrType.FontSizeCs);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(rPr.FontSizeCS * 2);
		}
		//CS
		if(null != rPr.CS)
		{
			this.memory.WriteByte(c_oSerProp_rPrType.Cs);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(rPr.CS);
		}
		//RTL
		if(null != rPr.RTL)
		{
			this.memory.WriteByte(c_oSerProp_rPrType.Rtl);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(rPr.RTL);
		}
		//Lang
		if(null != rPr.Lang)
		{
			if(null != rPr.Lang.Val)
			{
				this.memory.WriteByte(c_oSerProp_rPrType.Lang);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.memory.WriteString2(g_oLcidIdToNameMap[rPr.Lang.Val]);
			}
			if(null != rPr.Lang.Bidi)
			{
				this.memory.WriteByte(c_oSerProp_rPrType.LangBidi);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.memory.WriteString2(g_oLcidIdToNameMap[rPr.Lang.Bidi]);
			}
			if(null != rPr.Lang.EastAsia)
			{
				this.memory.WriteByte(c_oSerProp_rPrType.LangEA);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.memory.WriteString2(g_oLcidIdToNameMap[rPr.Lang.EastAsia]);
			}
		}
		if (null != rPr.Unifill || (null != rPr.Color && rPr.Color.Auto)) {
		    this.memory.WriteByte(c_oSerProp_rPrType.ColorTheme);
		    this.memory.WriteByte(c_oSerPropLenType.Variable);
		    this.bs.WriteItemWithLength(function () { _this.bs.WriteColorTheme(rPr.Unifill, rPr.Color); });
		}
		if(null != rPr.Shd)
		{
			this.memory.WriteByte(c_oSerProp_rPrType.Shd);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function () { _this.bs.WriteShd(rPr.Shd); });
		}
		if(null != rPr.Vanish)
		{
			this.memory.WriteByte(c_oSerProp_rPrType.Vanish);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(rPr.Vanish);
		}
		if(null != rPr.TextOutline)
		{
			this.memory.WriteByte(c_oSerProp_rPrType.TextOutline);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
			this.bs.WriteItemWithLength(function () { pptx_content_writer.WriteSpPr(_this.memory, rPr.TextOutline, 0); });
		}
		if(null != rPr.TextFill)
		{
			this.memory.WriteByte(c_oSerProp_rPrType.TextFill);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            if(null != rPr.TextFill.transparent)
            {
                rPr.TextFill.transparent = 255 - rPr.TextFill.transparent;
            }
			this.bs.WriteItemWithLength(function () { pptx_content_writer.WriteSpPr(_this.memory, rPr.TextFill, 1); });
            if(null != rPr.TextFill.transparent)
            {
                rPr.TextFill.transparent = 255 - rPr.TextFill.transparent;
            }
		}
        if (rPrReview && rPrReview.PrChange && rPrReview.ReviewInfo) {
            var brPrs = new Binary_rPrWriter(this.memory, this.saveParams);
            this.memory.WriteByte(c_oSerProp_rPrType.rPrChange);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){WriteTrackRevision(_this.bs, _this.saveParams.trackRevisionId++, rPrReview.ReviewInfo, {brPrs: brPrs, rPr: rPrReview.PrChange});});
        }
        if (EndRun && EndRun.ReviewInfo) {
            var ReviewType = EndRun.Get_ReviewType();
            if (reviewtype_Remove == ReviewType) {
                this.memory.WriteByte(c_oSerProp_rPrType.Del);
                this.memory.WriteByte(c_oSerPropLenType.Variable);
                this.bs.WriteItemWithLength(function(){WriteTrackRevision(_this.bs, _this.saveParams.trackRevisionId++, EndRun.ReviewInfo);});
            } else if (reviewtype_Add == ReviewType) {
                this.memory.WriteByte(c_oSerProp_rPrType.Ins);
                this.memory.WriteByte(c_oSerPropLenType.Variable);
                this.bs.WriteItemWithLength(function(){WriteTrackRevision(_this.bs, _this.saveParams.trackRevisionId++, EndRun.ReviewInfo);});
            }
        }
    };
};
function Binary_oMathWriter(memory, oMathPara, saveParams)
{
    this.memory = memory;
    this.saveParams = saveParams;
    this.bs = new BinaryCommonWriter(this.memory);
	this.brPrs = new Binary_rPrWriter(this.memory, saveParams);
	
	this.WriteMathElem = function(item, isSingle)
	{
		var oThis = this;
		switch ( item.Type )
		{
			case para_Math_Composition:
				{
					switch (item.kind)
					{
						case MATH_ACCENT			: this.bs.WriteItem(c_oSer_OMathContentType.Acc, function(){oThis.WriteAcc(item);});			break;
						case MATH_BAR				: this.bs.WriteItem(c_oSer_OMathContentType.Bar, function(){oThis.WriteBar(item);});			break;
						case MATH_BORDER_BOX		: this.bs.WriteItem(c_oSer_OMathContentType.BorderBox, function(){oThis.WriteBorderBox(item);});break;
						case MATH_BOX				: this.bs.WriteItem(c_oSer_OMathContentType.Box, function(){oThis.WriteBox(item);});			break;
						case "CCtrlPr"				: this.bs.WriteItem(c_oSer_OMathContentType.CtrlPr, function(){oThis.WriteCtrlPr(item);});		break;
						case MATH_DELIMITER			: this.bs.WriteItem(c_oSer_OMathContentType.Delimiter, function(){oThis.WriteDelimiter(item);});break;
						case MATH_EQ_ARRAY			: this.bs.WriteItem(c_oSer_OMathContentType.EqArr, function(){oThis.WriteEqArr(item);});		break;
						case MATH_FRACTION			: this.bs.WriteItem(c_oSer_OMathContentType.Fraction, function(){oThis.WriteFraction(item);});	break;
						case MATH_FUNCTION			: this.bs.WriteItem(c_oSer_OMathContentType.Func, function(){oThis.WriteFunc(item);});			break;
						case MATH_GROUP_CHARACTER	: this.bs.WriteItem(c_oSer_OMathContentType.GroupChr, function(){oThis.WriteGroupChr(item);});	break;
						case MATH_LIMIT				: 
							if (LIMIT_LOW  == item.Pr.type)
								this.bs.WriteItem(c_oSer_OMathContentType.LimLow, function(){oThis.WriteLimLow(item);});
							else if (LIMIT_UP == item.Pr.type)
								this.bs.WriteItem(c_oSer_OMathContentType.LimUpp, function(){oThis.WriteLimUpp(item);});
							break;
						case MATH_MATRIX			: this.bs.WriteItem(c_oSer_OMathContentType.Matrix, function(){oThis.WriteMatrix(item);});		break;
						case MATH_NARY			: this.bs.WriteItem(c_oSer_OMathContentType.Nary, function(){oThis.WriteNary(item);});			break;
						case "OMath"			: this.bs.WriteItem(c_oSer_OMathContentType.OMath, function(){oThis.WriteArgNodes(item);});			break;
						case "OMathPara"		: this.bs.WriteItem(c_oSer_OMathContentType.OMathPara, function(){oThis.WriteOMathPara(item);});break;
						case MATH_PHANTOM		: this.bs.WriteItem(c_oSer_OMathContentType.Phant, function(){oThis.WritePhant(item);});		break;
						case MATH_RUN			: this.WriteMRunWrap(item, isSingle);break;
						case MATH_RADICAL		: this.bs.WriteItem(c_oSer_OMathContentType.Rad, function(){oThis.WriteRad(item);});			break;
						case MATH_DEGREESubSup	: 
							if (DEGREE_PreSubSup == item.Pr.type)
								this.bs.WriteItem(c_oSer_OMathContentType.SPre, function(){oThis.WriteSPre(item);});	
							else if (DEGREE_SubSup == item.Pr.type)
								this.bs.WriteItem(c_oSer_OMathContentType.SSubSup, function(){oThis.WriteSSubSup(item);});
							break;
						case MATH_DEGREE		: 
							if (DEGREE_SUBSCRIPT == item.Pr.type)
								this.bs.WriteItem(c_oSer_OMathContentType.SSub, function(){oThis.WriteSSub(item);});
							else if (DEGREE_SUPERSCRIPT == item.Pr.type)
								this.bs.WriteItem(c_oSer_OMathContentType.SSup, function(){oThis.WriteSSup(item);});
							break;
					}
					break;
				}		
			case para_Math_Text:
			case para_Math_BreakOperator:
				this.bs.WriteItem(c_oSer_OMathContentType.MText, function(){ oThis.memory.WriteString2(AscCommon.convertUnicodeToUTF16([item.value]));}); //m:t
				break;
			case para_Math_Run:
				this.WriteMRunWrap(item, isSingle);
				break;
			default:		
				break;
		}
	},
    this.WriteArgNodes = function(oElem)
	{
		if (oElem)
		{			
			var oThis = this;
			var nStart = 0;
			var nEnd   = oElem.Content.length;
			
			var argSz = oElem.GetArgSize();
			if (argSz)
				this.bs.WriteItem(c_oSer_OMathContentType.ArgPr, function(){oThis.WriteArgPr(argSz);});
			
			var isSingle = (nStart === nEnd - 1);
			for(var i = nStart; i <= nEnd - 1; i++)
			{
				var item = oElem.Content[i];
				this.WriteMathElem(item, isSingle);
			}
		}
		
	}
	this.WriteMRunWrap = function(oMRun, isSingle)
	{
		var oThis = this;
		if (!isSingle && oMRun.Is_Empty()) {
			//don't write empty run(in Excel empty run is editable and has size).Write only if it is single single in Content
			return;
		}
		this.bs.WriteItem(c_oSer_OMathContentType.MRun, function(){oThis.WriteMRun(oMRun);});
	}
	this.WriteMRun = function(oMRun)
	{
		var oThis = this;
        var ReviewType = oMRun.Get_ReviewType();
        if (reviewtype_Remove == ReviewType) {
            this.bs.WriteItem(c_oSer_OMathContentType.Del,function(){WriteTrackRevision(oThis.bs, oThis.saveParams.trackRevisionId++, oMRun.ReviewInfo, {bmw: oThis, runContent: oMRun, ReviewType: ReviewType});});
        } else if (reviewtype_Add == ReviewType) {
            this.bs.WriteItem(c_oSer_OMathContentType.Ins,function(){WriteTrackRevision(oThis.bs, oThis.saveParams.trackRevisionId++, oMRun.ReviewInfo, {bmw: oThis, runContent: oMRun, ReviewType: ReviewType});});
        } else {
            this.WriteMRunContent(oMRun);
        }
    }
    this.WriteMRunContent = function(oMRun)
    {
        var oThis = this;
		var props = oMRun.getPropsForWrite();
		var oText = "";
		var ContentLen = oMRun.Content.length;
        for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
		{
			var Item = oMRun.Content[CurPos];
			switch ( Item.Type )
            {	
				case para_Math_Ampersand :		oText += "&"; break;
				case para_Math_BreakOperator:
				case para_Math_Text :			oText += AscCommon.convertUnicodeToUTF16([Item.value]); break;
            	case para_Space:
            	case para_Tab : 				oText += " "; break;
            }
		}

		if(null != props.wRPrp){
            this.bs.WriteItem(c_oSer_OMathContentType.RPr,	function(){oThis.brPrs.Write_rPr(props.wRPrp, null, null);}); // w:rPr
        }
		this.bs.WriteItem(c_oSer_OMathContentType.MRPr,	function(){oThis.WriteMRPr(props.mathRPrp);}); // m:rPr
        if(null != props.prRPrp){
            this.bs.WriteItem(c_oSer_OMathContentType.ARPr,	function(){
                pptx_content_writer.WriteRunProperties(oThis.memory, props.prRPrp);
            });
        }
		this.bs.WriteItem(c_oSer_OMathContentType.MText,function(){oThis.WriteMText(oText.toString());}); // m:t
	}
	this.WriteMText = function(sText)
	{
		if ("" != sText)
		{
			this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
			this.memory.WriteByte(c_oSerPropLenType.Variable);
			this.memory.WriteString2(sText);
		}
	}
	this.WriteAcc = function(oAcc)
	{
		var oThis = this;
		var oElem = oAcc.getBase();
		var props = oAcc.getPropsForWrite();
		
		this.bs.WriteItem(c_oSer_OMathContentType.AccPr, function(){oThis.WriteAccPr(props, oAcc);});
		this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});
	}
	this.WriteAccPr = function(props,oAcc)
	{
		var oThis = this;
		if (null != props.chr)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Chr, function(){oThis.WriteChr(props.chr);});
		if (null != oAcc.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oAcc);});
	}
	this.WriteAln = function(Aln)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(Aln);
	}	
	this.WriteAlnScr = function(AlnScr)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(AlnScr);
	}
	this.WriteArgPr = function(nArgSz)
	{
		var oThis = this;
		this.bs.WriteItem(c_oSer_OMathBottomNodesType.ArgSz, function(){oThis.WriteArgSz(nArgSz);});
	}
	this.WriteArgSz = function(ArgSz)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Long);
		this.memory.WriteLong(ArgSz);
	}
	this.WriteBar = function(oBar)
	{
		var oThis = this;
		var oElem = oBar.getBase();
		var props = oBar.getPropsForWrite();
		
		this.bs.WriteItem(c_oSer_OMathContentType.BarPr, function(){oThis.WriteBarPr(props, oBar);});
		this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});
	}
	this.WriteBarPr = function(props,oBar)
	{
		var oThis = this;
		if (null != props.pos)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Pos, function(){oThis.WritePos(props.pos);});
		if (null != oBar.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oBar);});
	}
	this.WriteBaseJc = function(BaseJc)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);		
		var val = c_oAscYAlign.Center;
		switch (BaseJc)
		{
			case BASEJC_BOTTOM: val = c_oAscYAlign.Bottom; break;
			case BASEJC_CENTER: val = c_oAscYAlign.Center; break;
			case BASEJC_TOP:	val = c_oAscYAlign.Top;
		}
		this.memory.WriteByte(val);
	}
	this.WriteBorderBox = function(oBorderBox)
	{
		var oThis = this;
		var oElem = oBorderBox.getBase();
		var props = oBorderBox.getPropsForWrite();
		
		this.bs.WriteItem(c_oSer_OMathContentType.BorderBoxPr, function(){oThis.WriteBorderBoxPr(props, oBorderBox);});
		this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});
	}
	this.WriteBorderBoxPr = function(props,oBorderBox)
	{		
		var oThis = this;
		if (null != props.hideBot)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.HideBot, function(){oThis.WriteHideBot(props.hideBot);});
		if (null != props.hideLeft)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.HideLeft, function(){oThis.WriteHideLeft(props.hideLeft);});
		if (null != props.hideRight)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.HideRight, function(){oThis.WriteHideRight(props.hideRight);});
		if (null != props.hideTop)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.HideTop, function(){oThis.WriteHideTop(props.hideTop);});
		if (null != props.strikeBLTR)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.StrikeBLTR, function(){oThis.WriteStrikeBLTR(props.strikeBLTR);});
		if (null != props.strikeH)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.StrikeH, function(){oThis.WriteStrikeH(props.strikeH);});
		if (null != props.strikeTLBR)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.StrikeTLBR, function(){oThis.WriteStrikeTLBR(props.strikeTLBR);});
		if (null != props.strikeV)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.StrikeV, function(){oThis.WriteStrikeV(props.strikeV);});
		if (null != oBorderBox.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oBorderBox);});
	}
	this.WriteBox = function(oBox)
	{
		var oThis = this;
		var oElem = oBox.getBase();
		var props = oBox.getPropsForWrite();
		
		this.bs.WriteItem(c_oSer_OMathContentType.BoxPr, function(){oThis.WriteBoxPr(props, oBox);});
		this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});
	}
	this.WriteBoxPr = function(props,oBox)
	{
		var oThis = this;
		if (null != props.aln)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Aln, function(){oThis.WriteAln(props.aln);});
		if (null != props.brk)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Brk, function(){oThis.WriteBrk(props.brk);});
		if (null != props.diff)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Diff, function(){oThis.WriteDiff(props.diff);});
		if (null != props.noBreak)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.NoBreak, function(){oThis.WriteNoBreak(props.noBreak);});
		if (null != props.opEmu)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.OpEmu, function(){oThis.WriteOpEmu(props.opEmu);});
		if (null != oBox.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oBox);});
	}	
	this.WriteBrk = function(Brk)
	{
		if (Brk.alnAt)
		{
			this.memory.WriteByte(c_oSer_OMathBottomNodesValType.AlnAt);
			this.memory.WriteByte(c_oSerPropLenType.Long);
			this.memory.WriteLong(Brk.alnAt);
		}
		else
		{
			this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(false);
		}
	}
	this.WriteCGp = function(CGp)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Long);
		this.memory.WriteLong(CGp);
	}
	this.WriteCGpRule = function(CGpRule)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Long);
		this.memory.WriteLong(CGpRule);
	}
	this.WriteChr = function(Chr)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Variable);

        if (OPERATOR_EMPTY === Chr)
            this.memory.WriteString2("");
        else
		    this.memory.WriteString2(AscCommon.convertUnicodeToUTF16([Chr]));
	}
	this.WriteCount = function(Count)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Long);
		this.memory.WriteLong(Count);
	}
	this.WriteCSp = function(CSp)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Long);
		this.memory.WriteLong(CSp);
	}
	this.WriteCtrlPr = function(oElem)
	{
		var oThis = this;
        var ReviewType = reviewtype_Common;
        if (oElem.Get_ReviewType) {
            ReviewType = oElem.Get_ReviewType();
        }
		if (oElem.Is_FromDocument()) {
			if (reviewtype_Remove == ReviewType || reviewtype_Add == ReviewType && oElem.ReviewInfo) {
				var brPrs = new Binary_rPrWriter(this.memory, this.saveParams);
				var recordType = reviewtype_Remove == ReviewType ? c_oSerRunType.del : c_oSerRunType.ins;
				this.bs.WriteItem(recordType, function(){WriteTrackRevision(oThis.bs, oThis.saveParams.trackRevisionId++, oElem.ReviewInfo, {brPrs: brPrs, rPr: oElem.CtrPrp});});
			} else {
				this.bs.WriteItem(c_oSerRunType.rPr, function(){oThis.brPrs.Write_rPr(oElem.CtrPrp, null, null);});
			}
		} else {
			this.bs.WriteItem(c_oSerRunType.arPr, function() {
				pptx_content_writer.WriteRunProperties(oThis.memory, oElem.CtrPrp);
			});
		}
	}
	this.WriteDegHide = function(DegHide)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(DegHide);
	}
	this.WriteDiff = function(Diff)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(Diff);
	}
	this.WriteDelimiter = function(oDelimiter)
	{
		var oThis = this;
		var nStart = 0;
        var nEnd   = oDelimiter.nCol;
		var props = oDelimiter.getPropsForWrite();
		
		this.bs.WriteItem(c_oSer_OMathContentType.DelimiterPr, function(){oThis.WriteDelimiterPr(props, oDelimiter);});
		
		for(var i = nStart; i < nEnd; i++)	
		{
			var oElem = oDelimiter.getBase(i);
			this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});
		}
	}
	this.WriteDelimiterPr = function(props,oDelimiter)
	{
		var oThis = this;
		if (null != props.column)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Column, function(){oThis.WriteCount(props.column);});
		if (null != props.begChr)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.BegChr, function(){oThis.WriteChr(props.begChr);});
		if (null != props.endChr)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.EndChr, function(){oThis.WriteChr(props.endChr);});
		if (null != props.grow)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Grow, function(){oThis.WriteGrow(props.grow);});
		if (null != props.sepChr)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.SepChr, function(){oThis.WriteChr(props.sepChr);});
		if (null != props.shp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Shp, function(){oThis.WriteShp(props.shp);});
		if (null != oDelimiter.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oDelimiter);});
	}
	this.WriteEqArr = function(oEqArr)
	{
		var oThis = this;
		var nStart = 0;
        var nEnd   = oEqArr.elements.length;
		var props = oEqArr.getPropsForWrite();
		
		this.bs.WriteItem(c_oSer_OMathContentType.EqArrPr, function(){oThis.WriteEqArrPr(props, oEqArr);});
		
		for(var i = nStart; i < nEnd; i++)	
		{
			var oElem = oEqArr.getElement(i);
			this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});
		}
	}
	this.WriteEqArrPr = function(props,oEqArr)
	{
		var oThis = this;
		if (null != props.row)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Row, function(){oThis.WriteCount(props.row);});
		if (null != props.baseJc)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.BaseJc, function(){oThis.WriteBaseJc(props.baseJc);});
		if (null != props.maxDist)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.MaxDist, function(){oThis.WriteMaxDist(props.maxDist);});
		if (null != props.objDist)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.ObjDist, function(){oThis.WriteObjDist(props.objDist);});
		if (null != props.rSp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.RSp, function(){oThis.WriteRSp(props.rSp);});
		if (null != props.rSpRule)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.RSpRule, function(){oThis.WriteRSpRule(props.rSpRule);});
		if (null != oEqArr.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oEqArr);});
	}	
	this.WriteFraction = function(oFraction)
	{
		var oThis = this;
		var oDen = oFraction.getDenominator();
		var oNum = oFraction.getNumerator();	
		var props = oFraction.getPropsForWrite();
		
		this.bs.WriteItem(c_oSer_OMathContentType.FPr, function(){oThis.WriteFPr(props, oFraction);});
        this.bs.WriteItem(c_oSer_OMathContentType.Num, function(){oThis.WriteArgNodes(oNum);});
		this.bs.WriteItem(c_oSer_OMathContentType.Den, function(){oThis.WriteArgNodes(oDen);});
	}
	this.WriteFPr = function(props,oFraction)
	{
		var oThis = this;
		if (null != props.type)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Type, function(){oThis.WriteType(props.type);});
		if (null != oFraction.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oFraction);});
	}
	this.WriteFunc = function(oFunc)
	{
		var oThis = this;
		var oFName = oFunc.getFName();
		var oElem = oFunc.getArgument();	
		
		this.bs.WriteItem(c_oSer_OMathContentType.FuncPr, function(){oThis.WriteFuncPr(oFunc);});		
		this.bs.WriteItem(c_oSer_OMathContentType.FName, function(){oThis.WriteArgNodes(oFName);});
		this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});
	}
	this.WriteFuncPr = function(oFunc)
	{
		var oThis = this;
		if (null != oFunc.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oFunc);});
	}
	this.WriteGroupChr = function(oGroupChr)
	{
		var oThis = this;		
		var oElem = oGroupChr.getBase();
		var props = oGroupChr.getPropsForWrite();
		
		this.bs.WriteItem(c_oSer_OMathContentType.GroupChrPr, function(){oThis.WriteGroupChrPr(props, oGroupChr);});
		this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});
	}
	this.WriteGroupChrPr = function(props,oGroupChr)
	{
		var oThis = this;
		if (null != props.chr)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Chr, function(){oThis.WriteChr(props.chr);});
		if (null != props.pos)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Pos, function(){oThis.WritePos(props.pos);});
		if (null != props.vertJc)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.VertJc, function(){oThis.WriteVertJc(props.vertJc);});
		if (null != oGroupChr.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oGroupChr);});
	}
	this.WriteGrow = function(Grow)
	{
		if (!Grow)
		{
			this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(Grow);
		}
	}
	this.WriteHideBot = function(HideBot)
	{
		if (HideBot)
		{
			this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(HideBot);
		}
	}
	this.WriteHideLeft = function(HideLeft)
	{
		if (HideLeft)
		{
			this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(HideLeft);
		}
	}
	this.WriteHideRight = function(HideRight)
	{
		if (HideRight)
		{
			this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(HideRight);
		}
	}
	this.WriteHideTop = function(HideTop)
	{
		if (HideTop)
		{
			this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(HideTop);
		}
	}
	this.WriteLimLoc = function(LimLoc)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		var val = c_oAscLimLoc.SubSup;
		switch (LimLoc)
		{
			case NARY_SubSup: val = c_oAscLimLoc.SubSup; break;
			case NARY_UndOvr: val = c_oAscLimLoc.UndOvr;
		}
		this.memory.WriteByte(val);		
	}
	this.WriteLimLow = function(oLimLow)
	{
		var oThis = this;		
		var oElem = oLimLow.getFName();
		var oLim  = oLimLow.getIterator();
		
		this.bs.WriteItem(c_oSer_OMathContentType.LimLowPr, function(){oThis.WriteLimLowPr(oLimLow);});
		this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});
		this.bs.WriteItem(c_oSer_OMathContentType.Lim, function(){oThis.WriteArgNodes(oLim);});
	}
	this.WriteLimLowPr = function(oLimLow)
	{
		var oThis = this;
		if (null != oLimLow.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oLimLow);});
	}
	this.WriteLimUpp = function(oLimUpp)
	{
		var oThis = this;		
		var oElem = oLimUpp.getFName();
		var oLim  = oLimUpp.getIterator();
		
		this.bs.WriteItem(c_oSer_OMathContentType.LimUppPr, function(){oThis.WriteLimUppPr(oLimUpp);});
		this.bs.WriteItem(c_oSer_OMathContentType.Lim, function(){oThis.WriteArgNodes(oLim);});
		this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});		
	}
	this.WriteLimUppPr = function(oLimUpp)
	{
		var oThis = this;
		if (null != oLimUpp.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oLimUpp);});
	}
	this.WriteLit = function(Lit)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(Lit);
	}
	this.WriteMaxDist = function(MaxDist)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(MaxDist);
	}
	this.WriteMatrix = function(oMatrix)
	{
		var oThis 	= this;		
		var nStart = 0;
        var nEnd   = oMatrix.nRow;
		var props = oMatrix.getPropsForWrite();
		
		this.bs.WriteItem(c_oSer_OMathContentType.MPr, function(){oThis.WriteMPr(props, oMatrix);});
		
		for(var i = nStart; i < nEnd; i++)	
		{	
			this.bs.WriteItem(c_oSer_OMathContentType.Mr, function(){oThis.WriteMr(oMatrix,i);});
		}
	}
	this.WriteMc = function(props)
	{
		var oThis = this;
		this.bs.WriteItem(c_oSer_OMathContentType.McPr, function(){oThis.WriteMcPr(props);});
	}
	this.WriteMJc = function(MJc)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		var val = c_oAscXAlign.Left;
		switch (MJc)
		{
			case align_Center: 	val = c_oAscMathJc.Center; break;
			case align_Justify: val = c_oAscMathJc.CenterGroup; break;
			case align_Left: 	val = c_oAscMathJc.Left; break;
			case align_Right: 	val = c_oAscMathJc.Right;
		}
		this.memory.WriteByte(val);
	}
	this.WriteMcPr = function(props)
	{
		var oThis = this;
		if (null != props.mcJc)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.McJc, function(){oThis.WriteMcJc(props.mcJc);});
		if (null != props.count)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Count, function(){oThis.WriteCount(props.count);});
	}
    this.WriteMcJc = function(MJc)
    {
        this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
        this.memory.WriteByte(c_oSerPropLenType.Byte);
		
		var val = c_oAscXAlign.Center;
		switch (MJc)
		{
			case MCJC_CENTER: 	val = c_oAscXAlign.Center; 	break;
			case MCJC_INSIDE: 	val = c_oAscXAlign.Inside; 	break;
			case MCJC_LEFT: 	val = c_oAscXAlign.Left; 	break;
			case MCJC_OUTSIDE: 	val = c_oAscXAlign.Outside; break;
			case MCJC_RIGHT: 	val = c_oAscXAlign.Right; 	break;
		}
		this.memory.WriteByte(val);
		
    }
	this.WriteMcs = function(props)
	{
		var oThis = this;
		for(var Index = 0, Count = props.mcs.length; Index < Count; Index++)
			this.bs.WriteItem(c_oSer_OMathContentType.Mc, function(){oThis.WriteMc(props.mcs[Index]);});
	}
	this.WriteMPr = function(props,oMatrix)
	{
		var oThis = this;

		if (null != props.row)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Row, function(){oThis.WriteCount(props.row);});
		if (null != props.baseJc)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.BaseJc, function(){oThis.WriteBaseJc(props.baseJc);});
		if (null != props.cGp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CGp, function(){oThis.WriteCGp(props.cGp);});
		if (null != props.cGpRule)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CGpRule, function(){oThis.WriteCGpRule(props.cGpRule);});
		if (null != props.cSp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CSp, function(){oThis.WriteCSp(props.cSp);});
		if (null != props.mcs)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Mcs, function(){oThis.WriteMcs(props);});
		if (null != props.plcHide)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.PlcHide, function(){oThis.WritePlcHide(props.plcHide);});
		if (null != props.rSp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.RSp, function(){oThis.WriteRSp(props.rSp);});
		if (null != props.rSpRule)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.RSpRule, function(){oThis.WriteRSpRule(props.rSpRule);});
		if (null != oMatrix.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oMatrix);});
	}
	this.WriteMr = function(oMatrix, nRow)
	{
		var oThis 	= this;		
		var nStart = 0;
        var nEnd   = oMatrix.nCol;

		for(var i = nStart; i < nEnd; i++)	
		{	
			var oElem = oMatrix.getElement(nRow,i);
			this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});
		}
	}
	this.WriteNary = function(oNary)
	{
		var oThis = this;
		var oElem = oNary.getBase();
		var oSub = oNary.getLowerIterator();
		var oSup = oNary.getUpperIterator();
		var props = oNary.getPropsForWrite();
		
		this.bs.WriteItem(c_oSer_OMathContentType.NaryPr, function(){oThis.WriteNaryPr(props, oNary);});
		this.bs.WriteItem(c_oSer_OMathContentType.Sub, function(){oThis.WriteArgNodes(oSub);});
		this.bs.WriteItem(c_oSer_OMathContentType.Sup, function(){oThis.WriteArgNodes(oSup);});
		this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});		
	}
	this.WriteNaryPr = function(props,oNary)
	{
		var oThis = this;
		if (null != props.chr)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Chr, function(){oThis.WriteChr(props.chr);});
		if (null != props.grow)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Grow, function(){oThis.WriteGrow(props.grow);});
		if (null != props.limLoc)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.LimLoc, function(){oThis.WriteLimLoc(props.limLoc);});
		if (null != props.subHide)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.SubHide, function(){oThis.WriteSubHide(props.subHide);});
		if (null != props.supHide)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.SupHide, function(){oThis.WriteSupHide(props.supHide);});
		if (null != oNary.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oNary);});
	}	
	this.WriteNoBreak = function(NoBreak)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(NoBreak);
	}
	this.WriteNor = function(Nor)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(Nor);
	}
	this.WriteObjDist = function(ObjDist)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(ObjDist);
	}	
	this.WriteOMathPara = function(oOMathPara)
	{
		var oThis = this;
		var props = oOMathPara.getPropsForWrite();
		
		oThis.bs.WriteItem(c_oSer_OMathContentType.OMathParaPr, function(){oThis.WriteOMathParaPr(props);});	
		oThis.bs.WriteItem(c_oSer_OMathContentType.OMath, function(){oThis.WriteArgNodes(oOMathPara.Root);});
		//oThis.bs.WriteRun(item, bUseSelection);
	};
	this.WriteOMathParaPr = function(props)
	{
		var oThis = this;
		if (null != props.Jc)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.MJc, function(){oThis.WriteMJc(props.Jc);});
	}
	this.WriteOpEmu = function(OpEmu)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(OpEmu);
	}
	this.WritePhant = function(oPhant)
	{
		var oThis = this;
		var oElem = oPhant.getBase();
		var props = oPhant.getPropsForWrite();
		
		this.bs.WriteItem(c_oSer_OMathContentType.PhantPr, function(){oThis.WritePhantPr(props, oPhant);});
		this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});
	}
	this.WritePhantPr = function(props,oPhant)
	{
		var oThis = this;
		if (null != props.show)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Show, function(){oThis.WriteShow(props.show);});
		if (null != props.transp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Transp, function(){oThis.WriteTransp(props.transp);});
		if (null != props.zeroAsc)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.ZeroAsc, function(){oThis.WriteZeroAsc(props.zeroAsc);});
		if (null != props.zeroDesc)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.ZeroDesc, function(){oThis.WriteZeroDesc(props.zeroDesc);});
		if (null != props.zeroWid)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.ZeroWid, function(){oThis.WriteZeroWid(props.zeroWid);});
		if (null != oPhant.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oPhant);});
	}
	this.WritePlcHide = function(PlcHide)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(PlcHide);
	}
	this.WritePos = function(Pos)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		var val = c_oAscTopBot.Bot;
		switch (Pos)
		{
			case LOCATION_BOT: 	val = c_oAscTopBot.Bot; break;
			case LOCATION_TOP: 	val = c_oAscTopBot.Top;
		}
		this.memory.WriteByte(val);
	}
	this.WriteMRPr = function(props)
	{
		var oThis = this;
		if (null != props.aln)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Aln, function(){oThis.WriteAln(props.aln);});
		if (null != props.brk)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Brk, function(){oThis.WriteBrk(props.brk);});
		if (null != props.lit)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Lit, function(){oThis.WriteLit(props.lit);});
		if (null != props.nor)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Nor, function(){oThis.WriteNor(props.nor);});
		if (null != props.scr)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Scr, function(){oThis.WriteScr(props.scr);});
		if (null != props.sty)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.Sty, function(){oThis.WriteSty(props.sty);});
	}
	this.WriteRad = function(oRad)
	{
		var oThis = this;
		var oElem = oRad.getBase();
		var oDeg  = oRad.getDegree();
		var props = oRad.getPropsForWrite();
		
		this.bs.WriteItem(c_oSer_OMathContentType.RadPr, function(){oThis.WriteRadPr(props, oRad);});
		this.bs.WriteItem(c_oSer_OMathContentType.Deg, function(){oThis.WriteArgNodes(oDeg);});
		this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});
	}
	this.WriteRadPr = function(props,oRad)
	{
		var oThis = this;
		if (null != props.degHide)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.DegHide, function(){oThis.WriteDegHide(props.degHide);});
		if (null != oRad.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oRad);});
	}	
	this.WriteRSp = function(RSp)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Long);
		this.memory.WriteLong(RSp);
	}
	this.WriteRSpRule = function(RSpRule)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Long);
		this.memory.WriteLong(RSpRule);
	}
	this.WriteScr = function(Scr)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		var val = c_oAscScript.Roman;
		switch (Scr)
		{
			case TXT_DOUBLE_STRUCK: val = c_oAscScript.DoubleStruck; break;
			case TXT_FRAKTUR: 		val = c_oAscScript.Fraktur; break;
			case TXT_MONOSPACE: 	val = c_oAscScript.Monospace; break;
			case TXT_ROMAN: 		val = c_oAscScript.Roman; break;
			case TXT_SANS_SERIF: 	val = c_oAscScript.SansSerif; break;
			case TXT_SCRIPT: 		val = c_oAscScript.Script; break;
		}
		this.memory.WriteByte(val);
	}
	this.WriteShow = function(Show)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(Show);
	}
	this.WriteShp = function(Shp)
	{
		if (Shp != 1)
		{
			this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			var val = c_oAscShp.Centered;
			switch (Shp)
			{
				case DELIMITER_SHAPE_CENTERED: 	val = c_oAscShp.Centered; break;
				case DELIMITER_SHAPE_MATCH: 	val = c_oAscShp.Match;
			}
			this.memory.WriteByte(val);
		}
	}
	this.WriteSPre = function(oSPre)
	{
		var oThis = this;
		var oSub  = oSPre.getLowerIterator();
		var oSup  = oSPre.getUpperIterator();
		var oElem = oSPre.getBase();	
		
		this.bs.WriteItem(c_oSer_OMathContentType.SPrePr, function(){oThis.WriteSPrePr(oSPre);});		
		this.bs.WriteItem(c_oSer_OMathContentType.Sub, function(){oThis.WriteArgNodes(oSub);});
		this.bs.WriteItem(c_oSer_OMathContentType.Sup, function(){oThis.WriteArgNodes(oSup);});
		this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});		
	}
	this.WriteSPrePr = function(oSPre)
	{
		var oThis = this;
		if (null != oSPre.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oSPre);});
	}
	this.WriteSSub = function(oSSub)
	{
		var oThis = this;
		var oSub  = oSSub.getLowerIterator();
		var oElem = oSSub.getBase();
		
		this.bs.WriteItem(c_oSer_OMathContentType.SSubPr, function(){oThis.WriteSSubPr(oSSub);});
		this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});
		this.bs.WriteItem(c_oSer_OMathContentType.Sub, function(){oThis.WriteArgNodes(oSub);});		
	}
	this.WriteSSubPr = function(oSSub)
	{
		var oThis = this;
		if (null != oSSub.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oSSub);});
	}
	this.WriteSSubSup = function(oSSubSup)
	{
		var oThis = this;
		var oSub  = oSSubSup.getLowerIterator();
		var oSup  = oSSubSup.getUpperIterator();
		var oElem = oSSubSup.getBase();
		var props = oSSubSup.getPropsForWrite();
		
		this.bs.WriteItem(c_oSer_OMathContentType.SSubSupPr, function(){oThis.WriteSSubSupPr(props, oSSubSup);});
		this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});
		this.bs.WriteItem(c_oSer_OMathContentType.Sub, function(){oThis.WriteArgNodes(oSub);});
		this.bs.WriteItem(c_oSer_OMathContentType.Sup, function(){oThis.WriteArgNodes(oSup);});		
	}
	this.WriteSSubSupPr = function(props, oSSubSup)
	{
		var oThis = this;
		if (null != props.alnScr)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.AlnScr, function(){oThis.WriteAlnScr(props.alnScr);});
		if (null != oSSubSup.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oSSubSup);});
	}
	this.WriteSSup = function(oSSup)
	{
		var oThis = this;
		var oSup  = oSSup.getUpperIterator();
		var oElem = oSSup.getBase();
		
		this.bs.WriteItem(c_oSer_OMathContentType.SSupPr, function(){oThis.WriteSSupPr(oSSup);});
		this.bs.WriteItem(c_oSer_OMathContentType.Element, function(){oThis.WriteArgNodes(oElem);});
		this.bs.WriteItem(c_oSer_OMathContentType.Sup, function(){oThis.WriteArgNodes(oSup);});		
	}
	this.WriteSSupPr = function(oSSup)
	{
		var oThis = this;
		if (null != oSSup.CtrPrp)
			this.bs.WriteItem(c_oSer_OMathBottomNodesType.CtrlPr, function(){oThis.WriteCtrlPr(oSSup);});
	}
	this.WriteStrikeBLTR = function(StrikeBLTR)
	{
		if (StrikeBLTR)
		{
			this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(StrikeBLTR);
		}
	}
	this.WriteStrikeH = function(StrikeH)
	{
		if (StrikeH)
		{
			this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(StrikeH);
		}
	}
	this.WriteStrikeTLBR = function(StrikeTLBR)
	{
		if (StrikeTLBR)
		{
			this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(StrikeTLBR);
		}
	}
	this.WriteStrikeV = function(StrikeV)
	{
		if (StrikeV)
		{
			this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(StrikeV);
		}
	}
	this.WriteSty = function(Sty)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		var val = c_oAscSty.BoldItalic;
		switch (Sty)
		{
			case STY_BOLD: 		val = c_oAscSty.Bold; break;
			case STY_BI: 		val = c_oAscSty.BoldItalic; break;
			case STY_ITALIC: 	val = c_oAscSty.Italic; break;
			case STY_PLAIN: 	val = c_oAscSty.Plain;
		}
		this.memory.WriteByte(val);
	}
	this.WriteSubHide = function(SubHide)
	{
		if (SubHide)
		{
			this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(SubHide);
		}
	}
	this.WriteSupHide = function(SupHide)
	{
		if (SupHide)
		{
			this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(SupHide);
		}
	}
	this.WriteTransp = function(Transp)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(Transp);
	}
	this.WriteType = function(Type)
	{
		if ( Type != 0)
		{
			this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			var val = c_oAscFType.Bar;
			switch (Type)
			{
				case BAR_FRACTION: 		val = c_oAscFType.Bar; break;
				case LINEAR_FRACTION: 	val = c_oAscFType.Lin; break;
				case NO_BAR_FRACTION: 	val = c_oAscFType.NoBar; break;
				case SKEWED_FRACTION: 	val = c_oAscFType.Skw;
			}
			this.memory.WriteByte(val);
		}
	}	
	this.WriteVertJc = function(VertJc)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		var val = c_oAscTopBot.Bot;
		switch (VertJc)
		{
			case VJUST_BOT: 	val = c_oAscTopBot.Bot; break;
			case VJUST_TOP: 	val = c_oAscTopBot.Top;
		}
		this.memory.WriteByte(val);
	}
	this.WriteZeroAsc = function(ZeroAsc)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(ZeroAsc);
	}
	this.WriteZeroDesc = function(ZeroDesc)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(ZeroDesc);
	}
	this.WriteZeroWid = function(ZeroWid)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(ZeroWid);
	}
};
function Binary_tblPrWriter(memory, oNumIdMap, saveParams)
{
    this.memory = memory;
    this.bs = new BinaryCommonWriter(this.memory);
    this.bpPrs = new Binary_pPrWriter(this.memory, oNumIdMap, null, saveParams);
}
Binary_tblPrWriter.prototype = 
{
	WriteTbl: function(table)
    {
		var oThis = this;
		this.WriteTblPr(table.Pr, table);
		//Look
		var oLook = table.Get_TableLook();
		if(null != oLook)
		{
			var nLook = 0;
			if(oLook.Is_FirstCol())
				nLook |= 0x0080;
			if(oLook.Is_FirstRow())
				nLook |= 0x0020;
			if(oLook.Is_LastCol())
				nLook |= 0x0100;
			if(oLook.Is_LastRow())
				nLook |= 0x0040;
			if(!oLook.Is_BandHor())
				nLook |= 0x0200;
			if(!oLook.Is_BandVer())
				nLook |= 0x0400;
			this.bs.WriteItem(c_oSerProp_tblPrType.Look, function(){oThis.memory.WriteLong(nLook);});
		}
		//Style
		var sStyle = table.Get_TableStyle();
		if(null != sStyle && "" != sStyle)
		{
			this.memory.WriteByte(c_oSerProp_tblPrType.Style);
            this.memory.WriteString2(sStyle);
		}
	},
    WriteTblPr: function(tblPr, table)
    {
        var oThis = this;
		if (null != tblPr.TableStyleRowBandSize) {
			this.bs.WriteItem(c_oSerProp_tblPrType.RowBandSize, function(){oThis.memory.WriteLong(tblPr.TableStyleRowBandSize);});
		}
		if (null != tblPr.TableStyleColBandSize) {
			this.bs.WriteItem(c_oSerProp_tblPrType.ColBandSize, function(){oThis.memory.WriteLong(tblPr.TableStyleColBandSize);});
		}
        //Jc
        if(null != tblPr.Jc)
        {
            this.bs.WriteItem(c_oSerProp_tblPrType.Jc, function(){oThis.memory.WriteByte(tblPr.Jc);});
        }
        //TableInd
        if(null != tblPr.TableInd)
        {
            this.bs.WriteItem(c_oSerProp_tblPrType.TableInd, function(){oThis.memory.WriteDouble(tblPr.TableInd);});
        }
        //TableW
        if(null != tblPr.TableW)
        {
            this.bs.WriteItem(c_oSerProp_tblPrType.TableW, function(){oThis.WriteW(tblPr.TableW);});
        }
        //TableCellMar
        if(null != tblPr.TableCellMar)
        {
            this.bs.WriteItem(c_oSerProp_tblPrType.TableCellMar, function(){oThis.WriteCellMar(tblPr.TableCellMar);});
        }
        //TableBorders
        if(null != tblPr.TableBorders)
        {
            this.bs.WriteItem(c_oSerProp_tblPrType.TableBorders, function(){oThis.bs.WriteBorders(tblPr.TableBorders);});
        }
        //Shd
        if(null != tblPr.Shd && Asc.c_oAscShdNil != tblPr.Shd.Value)
        {
            this.bs.WriteItem(c_oSerProp_tblPrType.Shd, function(){oThis.bs.WriteShd(tblPr.Shd);});
        }
        if(null != tblPr.TableLayout)
        {
			var nLayout = ETblLayoutType.tbllayouttypeAutofit;
			switch(tblPr.TableLayout)
			{
				case tbllayout_AutoFit: nLayout = ETblLayoutType.tbllayouttypeAutofit;break;
				case tbllayout_Fixed: nLayout = ETblLayoutType.tbllayouttypeFixed;break;
			}
            this.bs.WriteItem(c_oSerProp_tblPrType.Layout, function(){oThis.memory.WriteByte(nLayout);});
        }
        //tblpPr
        if(null != table && false == table.Inline)
        {
            this.bs.WriteItem(c_oSerProp_tblPrType.tblpPr2, function(){oThis.Write_tblpPr2(table);});
        }
		if(null != tblPr.TableCellSpacing)
		{
			this.bs.WriteItem(c_oSerProp_tblPrType.TableCellSpacing, function(){oThis.memory.WriteDouble(tblPr.TableCellSpacing);});
		}
		if(null != tblPr.TableCaption)
		{
			this.memory.WriteByte(c_oSerProp_tblPrType.tblCaption);
			this.memory.WriteString2(tblPr.TableCaption);
		}
		if(null != tblPr.TableDescription)
		{
			this.memory.WriteByte(c_oSerProp_tblPrType.tblDescription);
			this.memory.WriteString2(tblPr.TableDescription);
		}
    },
    WriteCellMar: function(cellMar)
    {
        var oThis = this;
        //Left
        if(null != cellMar.Left)
        {
            this.bs.WriteItem(c_oSerMarginsType.left, function(){oThis.WriteW(cellMar.Left);});
        }
        //Top
        if(null != cellMar.Top)
        {
            this.bs.WriteItem(c_oSerMarginsType.top, function(){oThis.WriteW(cellMar.Top);});
        }
        //Right
        if(null != cellMar.Right)
        {
            this.bs.WriteItem(c_oSerMarginsType.right, function(){oThis.WriteW(cellMar.Right);});
        }
        //Bottom
        if(null != cellMar.Bottom)
        {
            this.bs.WriteItem(c_oSerMarginsType.bottom, function(){oThis.WriteW(cellMar.Bottom);});
        }
    },
    Write_tblpPr2: function(table)
    {
        var oThis = this;
        if(null != table.PositionH)
        {
			var PositionH = table.PositionH;
			if(null != PositionH.RelativeFrom)
			{
				this.memory.WriteByte(c_oSer_tblpPrType2.HorzAnchor);
				this.memory.WriteByte(c_oSerPropLenType.Byte);
				this.memory.WriteByte(PositionH.RelativeFrom);
			}
			if(true == PositionH.Align)
			{
				this.memory.WriteByte(c_oSer_tblpPrType2.TblpXSpec);
				this.memory.WriteByte(c_oSerPropLenType.Byte);
				this.memory.WriteByte(PositionH.Value);
			}
			else
			{
				this.memory.WriteByte(c_oSer_tblpPrType2.TblpX);
				this.memory.WriteByte(c_oSerPropLenType.Double);
				this.memory.WriteDouble(PositionH.Value);
			}
        }
		if(null != table.PositionV)
        {
			var PositionV = table.PositionV;
			if(null != PositionV.RelativeFrom)
			{
				this.memory.WriteByte(c_oSer_tblpPrType2.VertAnchor);
				this.memory.WriteByte(c_oSerPropLenType.Byte);
				this.memory.WriteByte(PositionV.RelativeFrom);
			}
			if(true == PositionV.Align)
			{
				this.memory.WriteByte(c_oSer_tblpPrType2.TblpYSpec);
				this.memory.WriteByte(c_oSerPropLenType.Byte);
				this.memory.WriteByte(PositionV.Value);
			}
			else
			{
				this.memory.WriteByte(c_oSer_tblpPrType2.TblpY);
				this.memory.WriteByte(c_oSerPropLenType.Double);
				this.memory.WriteDouble(PositionV.Value);
			}
        }
		if(null != table.Distance)
		{
			this.memory.WriteByte(c_oSer_tblpPrType2.Paddings);
			this.memory.WriteByte(c_oSerPropLenType.Variable);
			this.bs.WriteItemWithLength(function(){oThis.bs.WritePaddings(table.Distance);});
		}
    },
    WriteRowPr: function(rowPr)
    {
        var oThis = this;
        //CantSplit
        if(null != rowPr.CantSplit)
        {
            this.memory.WriteByte(c_oSerProp_rowPrType.CantSplit);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(rowPr.CantSplit);
        }
        //After
        if(null != rowPr.GridAfter || null != rowPr.WAfter)
        {
            this.memory.WriteByte(c_oSerProp_rowPrType.After);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.WriteAfter(rowPr);});
        }
        //Before
        if(null != rowPr.GridBefore || null != rowPr.WBefore)
        {
            this.memory.WriteByte(c_oSerProp_rowPrType.Before);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.WriteBefore(rowPr);});
        }
        //Jc
        if(null != rowPr.Jc)
        {
            this.memory.WriteByte(c_oSerProp_rowPrType.Jc);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(rowPr.Jc);
        }
        //TableCellSpacing
        if(null != rowPr.TableCellSpacing)
        {
            this.memory.WriteByte(c_oSerProp_rowPrType.TableCellSpacing);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble(rowPr.TableCellSpacing);
        }
        //Height
        if(null != rowPr.Height && Asc.linerule_Auto != rowPr.Height.HRule)
        {
            this.memory.WriteByte(c_oSerProp_rowPrType.Height);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.WriteRowHeight(rowPr.Height);});
        }
        //Header
        if(true == rowPr.TableHeader)
        {
            this.memory.WriteByte(c_oSerProp_rowPrType.TableHeader);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(rowPr.TableHeader);
        }
    },
    WriteAfter: function(After)
    {
        var oThis = this;
        //GridAfter
        if(null != After.GridAfter)
        {
            this.memory.WriteByte(c_oSerProp_rowPrType.GridAfter);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(After.GridAfter);
        }
        //WAfter
        if(null != After.WAfter)
        {
            this.memory.WriteByte(c_oSerProp_rowPrType.WAfter);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.WriteW(After.WAfter);});
        }
    },
    WriteBefore: function(Before)
    {
        var oThis = this;
        //GridBefore
        if(null != Before.GridBefore)
        {
            this.memory.WriteByte(c_oSerProp_rowPrType.GridBefore);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(Before.GridBefore);
        }
        //WBefore
        if(null != Before.WBefore)
        {
            this.memory.WriteByte(c_oSerProp_rowPrType.WBefore);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.WriteW(Before.WBefore);});
        }
    },
    WriteRowHeight: function(rowHeight)
    {
        //HRule
        if(null != rowHeight.HRule)
        {
            this.memory.WriteByte(c_oSerProp_rowPrType.Height_Rule);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(rowHeight.HRule);
        }
        //Value
        if(null != rowHeight.Value)
        {
            this.memory.WriteByte(c_oSerProp_rowPrType.Height_Value);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble(rowHeight.Value);
        }
    },
    WriteW: function(WAfter)
    {
		//Type
		if(null != WAfter.Type)
		{
			this.memory.WriteByte(c_oSerWidthType.Type);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteByte(WAfter.Type);
		}
		//W
		if(null != WAfter.W)
		{
			var nVal = WAfter.W;
			if(tblwidth_Mm == WAfter.Type)
				nVal = Math.round(g_dKoef_mm_to_twips * WAfter.W);
			else if(tblwidth_Pct == WAfter.Type)
				nVal = Math.round(100 * WAfter.W / 2);
			this.memory.WriteByte(c_oSerWidthType.WDocx);
			this.memory.WriteByte(c_oSerPropLenType.Long);
			this.memory.WriteLong(nVal);
		}
    },
    WriteCellPr: function(cellPr, vMerge, cell)
    {
        var oThis = this;
        //GridSpan
        if(null != cellPr.GridSpan)
        {
            this.memory.WriteByte(c_oSerProp_cellPrType.GridSpan);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(cellPr.GridSpan);
        }
        //Shd
        if(null != cellPr.Shd && Asc.c_oAscShdNil != cellPr.Shd.Value)
        {
            this.memory.WriteByte(c_oSerProp_cellPrType.Shd);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.bs.WriteShd(cellPr.Shd);});
        }
        //TableCellBorders
        if(null != cellPr.TableCellBorders)
        {
            this.memory.WriteByte(c_oSerProp_cellPrType.TableCellBorders);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.bs.WriteBorders(cellPr.TableCellBorders);});
        }
        //CellMar
        if(null != cellPr.TableCellMar)
        {
            this.memory.WriteByte(c_oSerProp_cellPrType.CellMar);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.WriteCellMar(cellPr.TableCellMar);});
        }
        //TableCellW
        if(null != cellPr.TableCellW)
        {
            this.memory.WriteByte(c_oSerProp_cellPrType.TableCellW);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.WriteW(cellPr.TableCellW);});
        }
        //VAlign
        if(null != cellPr.VAlign)
        {
            this.memory.WriteByte(c_oSerProp_cellPrType.VAlign);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(cellPr.VAlign);
        }
        //VMerge
		var nVMerge = null;
        if(null != cellPr.VMerge)
			nVMerge = cellPr.VMerge;
		else if(null != vMerge)
			nVMerge = vMerge;
		if(null != nVMerge)
        {
            this.memory.WriteByte(c_oSerProp_cellPrType.VMerge);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(nVMerge);
        }
		if(null != cellPr.HMerge)
		{
			this.memory.WriteByte(c_oSerProp_cellPrType.HMerge);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteByte(cellPr.HMerge);
		}
        var textDirection = cell ? cell.Get_TextDirection() : null;
        if(null != textDirection)
        {
            this.memory.WriteByte(c_oSerProp_cellPrType.textDirection);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(textDirection);
        }
        var noWrap = cell ? cell.Get_NoWrap() : null;
        if(null != noWrap)
        {
            this.memory.WriteByte(c_oSerProp_cellPrType.noWrap);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteBool(noWrap);
    }
    }
};
function BinaryHeaderFooterTableWriter(memory, doc, oNumIdMap, oMapCommentId, saveParams)
{
    this.memory = memory;
    this.Document = doc;
	this.oNumIdMap = oNumIdMap;
	this.oMapCommentId = oMapCommentId;
	this.aHeaders = [];
	this.aFooters = [];
	this.saveParams = saveParams;
    this.bs = new BinaryCommonWriter(this.memory);
    this.Write = function()
    {
        var oThis = this;
        this.bs.WriteItemWithLength(function(){oThis.WriteHeaderFooterContent();});
    };
    this.WriteHeaderFooterContent = function()
    {
        var oThis = this;
        //Header
        if(this.aHeaders.length > 0)
            this.bs.WriteItem(c_oSerHdrFtrTypes.Header,function(){oThis.WriteHdrFtrContent(oThis.aHeaders);});
        //Footer
        if(this.aFooters.length > 0)
            this.bs.WriteItem(c_oSerHdrFtrTypes.Footer,function(){oThis.WriteHdrFtrContent(oThis.aFooters);});
    };
    this.WriteHdrFtrContent = function(aHdrFtr)
    {
        var oThis = this;
		for(var i = 0, length = aHdrFtr.length; i < length; ++i)
		{
			var item = aHdrFtr[i];
			this.bs.WriteItem(item.type, function(){oThis.WriteHdrFtrItem(item.elem);});
		}
    };
    this.WriteHdrFtrItem = function(item)
    {
        var oThis = this;
        //Content
        var dtw = new BinaryDocumentTableWriter(this.memory, this.Document, this.oMapCommentId, this.oNumIdMap, null, this.saveParams, null);
        this.bs.WriteItem(c_oSerHdrFtrTypes.HdrFtr_Content, function(){dtw.WriteDocumentContent(item.Content);});
    };
};
function BinaryNumberingTableWriter(memory, doc, oNumIdMap, oUsedNumIdMap, saveParams)
{
    this.memory = memory;
    this.Document = doc;
	this.oNumIdMap = oNumIdMap;
	this.oUsedNumIdMap = oUsedNumIdMap;
	this.oANumIdToBin = {};
    this.bs = new BinaryCommonWriter(this.memory);
    this.bpPrs = new Binary_pPrWriter(this.memory, null != this.oUsedNumIdMap ? this.oUsedNumIdMap : this.oNumIdMap, null, saveParams);
    this.brPrs = new Binary_rPrWriter(this.memory, saveParams);
    this.Write = function()
    {
        var oThis = this;
        this.bs.WriteItemWithLength(function(){oThis.WriteNumberingContent();});
    };
    this.WriteNumberingContent = function()
    {
        var oThis = this;
        if(null != this.Document.Numbering)
        {
            //ANums
            this.bs.WriteItem(c_oSerNumTypes.AbstractNums, function(){oThis.WriteAbstractNums();});
            //Nums
            this.bs.WriteItem(c_oSerNumTypes.Nums, function(){oThis.WriteNums();});
        }
    };
    this.WriteNums = function()
    {
        var oThis = this;
		var i;
		var nums = this.Document.Numbering.Num;
		if(null != this.oUsedNumIdMap)
		{
			for (i in this.oUsedNumIdMap) {
				if (this.oUsedNumIdMap.hasOwnProperty(i) && nums[i]) {
					this.bs.WriteItem(c_oSerNumTypes.Num, function(){oThis.WriteNum(nums[i], oThis.oUsedNumIdMap[i]);});
				}
			}
		}
		else
		{
			var index = 1;
			for (i in nums) {
				if (nums.hasOwnProperty(i)) {
					this.bs.WriteItem(c_oSerNumTypes.Num, function(){oThis.WriteNum(nums[i], index);});
					index++;
				}
			}
		}
    };
    this.WriteNum = function(num, index)
    {
        var oThis = this;
		var ANumId = this.oANumIdToBin[num.AbstractNumId];
		if (undefined !== ANumId) {
			this.memory.WriteByte(c_oSerNumTypes.Num_ANumId);
			this.memory.WriteByte(c_oSerPropLenType.Long);
			this.memory.WriteLong(ANumId);
		}
            
        this.memory.WriteByte(c_oSerNumTypes.Num_NumId);
        this.memory.WriteByte(c_oSerPropLenType.Long);
        this.memory.WriteLong(index);
		this.oNumIdMap[num.GetId()] = index;

		for (var nLvl = 0; nLvl < 9; ++nLvl)
		{
			if (num.LvlOverride[nLvl])
			{
				this.memory.WriteByte(c_oSerNumTypes.Num_LvlOverride);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.bs.WriteItemWithLength(function(){oThis.WriteLvlOverride(num.LvlOverride[nLvl]);});
			}
		}

    };
	this.WriteLvlOverride = function(lvlOverride)
	{
		var oThis = this;
		if (lvlOverride.Lvl >= 0) {
			this.bs.WriteItem(c_oSerNumTypes.ILvl, function(){oThis.memory.WriteLong(lvlOverride.Lvl);});
		}
		if (lvlOverride.StartOverride >= 0) {
			this.bs.WriteItem(c_oSerNumTypes.StartOverride, function(){oThis.memory.WriteLong(lvlOverride.StartOverride);});
		}
		if (lvlOverride.NumberingLvl && lvlOverride.Lvl >= 0) {
			this.bs.WriteItem(c_oSerNumTypes.Lvl, function(){oThis.WriteLevel(lvlOverride.NumberingLvl, lvlOverride.Lvl);});
		}
	};
    this.WriteAbstractNums = function(ANum)
    {
        var oThis = this;
		var i;
		var index = 0;
		var ANums = this.Document.Numbering.AbstractNum;
		var nums = this.Document.Numbering.Num;
		if(null != this.oUsedNumIdMap)
		{
			for (i in this.oUsedNumIdMap) {
				if (this.oUsedNumIdMap.hasOwnProperty(i) && nums[i]) {
					var ANum = ANums[nums[i].AbstractNumId];
					if (null != ANum) {
						this.bs.WriteItem(c_oSerNumTypes.AbstractNum, function(){oThis.WriteAbstractNum(ANum, index);});
						index++;
					}
				}
			}
		}
		else
		{
			for (i in ANums) {
				if (ANums.hasOwnProperty(i)) {
					this.bs.WriteItem(c_oSerNumTypes.AbstractNum, function(){oThis.WriteAbstractNum(ANums[i], index);});
					index++;
				}
			}
		}
    };
    this.WriteAbstractNum = function(num, index)
    {
        var oThis = this;
        //Id
		this.bs.WriteItem(c_oSerNumTypes.AbstractNum_Id, function(){oThis.memory.WriteLong(index);});
		this.oANumIdToBin[num.GetId()] = index;

		if(null != num.NumStyleLink)
		{
            this.memory.WriteByte(c_oSerNumTypes.NumStyleLink);
            this.memory.WriteString2(num.NumStyleLink);
		}
        if(null != num.StyleLink)
		{
            this.memory.WriteByte(c_oSerNumTypes.StyleLink);
            this.memory.WriteString2(num.StyleLink);
		}
        //Lvl
        if(null != num.Lvl)
            this.bs.WriteItem(c_oSerNumTypes.AbstractNum_Lvls, function(){oThis.WriteLevels(num.Lvl);});
    };
    this.WriteLevels = function(lvls)
    {
        var oThis = this;    
        for(var i = 0, length = lvls.length; i < length; i++)
        {
            var lvl = lvls[i];
            this.bs.WriteItem(c_oSerNumTypes.Lvl, function(){oThis.WriteLevel(lvl, i);});
        }
    };
    this.WriteLevel = function(lvl, ILvl)
    {
        var oThis = this;
        //Format
        if(null != lvl.Format)
        {
            this.memory.WriteByte(c_oSerNumTypes.lvl_Format);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(lvl.Format);
        }
        //Jc
        if(null != lvl.Jc)
        {
            this.memory.WriteByte(c_oSerNumTypes.lvl_Jc);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(lvl.Jc);
        }
        //LvlText
        if(null != lvl.LvlText)
        {
            this.memory.WriteByte(c_oSerNumTypes.lvl_LvlText);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.WriteLevelText(lvl.LvlText);});
        }
        //Restart
        if(lvl.Restart >= 0)
        {
            this.memory.WriteByte(c_oSerNumTypes.lvl_Restart);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(lvl.Restart);
        }
        //Start
        if(null != lvl.Start)
        {
            this.memory.WriteByte(c_oSerNumTypes.lvl_Start);
            this.memory.WriteByte(c_oSerPropLenType.Long);
            this.memory.WriteLong(lvl.Start);
        }
        //Suff
        if(null != lvl.Suff)
        {
            this.memory.WriteByte(c_oSerNumTypes.lvl_Suff);
            this.memory.WriteByte(c_oSerPropLenType.Byte);
            this.memory.WriteByte(lvl.Suff);
        }
		//PStyle
        if(null != lvl.PStyle)
        {
            this.memory.WriteByte(c_oSerNumTypes.lvl_PStyle);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.memory.WriteString2(lvl.PStyle);
        }
        //ParaPr
        if(null != lvl.ParaPr)
        {
            this.memory.WriteByte(c_oSerNumTypes.lvl_ParaPr);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.bpPrs.Write_pPr(lvl.ParaPr);});
        }
        //TextPr
        if(null != lvl.TextPr)
        {
            this.memory.WriteByte(c_oSerNumTypes.lvl_TextPr);
            this.memory.WriteByte(c_oSerPropLenType.Variable);
            this.bs.WriteItemWithLength(function(){oThis.brPrs.Write_rPr(lvl.TextPr, null, null);});
        }
		if(null != ILvl)
		{
			this.memory.WriteByte(c_oSerNumTypes.ILvl);
			this.memory.WriteByte(c_oSerPropLenType.Long);
			this.memory.WriteLong(ILvl);
		}
		// if(null != lvl.Tentative)
		// {
		// 	this.memory.WriteByte(c_oSerNumTypes.Tentative);
		// 	this.memory.WriteByte(c_oSerPropLenType.Byte);
		// 	this.memory.WriteBool(lvl.Tentative);
		// }
		// if(null != lvl.Tplc)
		// {
		// 	this.memory.WriteByte(c_oSerNumTypes.Tplc);
		// 	this.memory.WriteByte(c_oSerPropLenType.Long);
		// 	this.memory.WriteLong(AscFonts.FT_Common.UintToInt(lvl.Tplc));
		// }
		// if(null != lvl.IsLgl)
		// {
		// 	this.memory.WriteByte(c_oSerNumTypes.IsLgl);
		// 	this.memory.WriteByte(c_oSerPropLenType.Byte);
		// 	this.memory.WriteBool(lvl.IsLgl);
		// }
		if(null != lvl.Legacy)
		{
			this.memory.WriteByte(c_oSerNumTypes.LvlLegacy);
			this.memory.WriteByte(c_oSerPropLenType.Variable);
			this.bs.WriteItemWithLength(function(){oThis.WriteLvlLegacy(lvl.Legacy);});
		}
    };
	this.WriteLvlLegacy = function(lvlLegacy)
	{
		var oThis = this;
		if (null != lvlLegacy.Legacy) {
			this.bs.WriteItem(c_oSerNumTypes.Legacy, function(){oThis.memory.WriteBool(lvlLegacy.Legacy);});
		}
		if (null != lvlLegacy.Indent) {
			this.bs.WriteItem(c_oSerNumTypes.LegacyIndent, function(){oThis.memory.WriteLong(lvlLegacy.Indent);});
		}
		if (null != lvlLegacy.Space) {
			this.bs.WriteItem(c_oSerNumTypes.LegacySpace, function(){oThis.memory.WriteLong(AscFonts.FT_Common.UintToInt(lvlLegacy.Space))});
		}
	};
    this.WriteLevelText = function(aText)
    {
        var oThis = this;
        for(var i = 0, length = aText.length; i < length; i++)
        {
            var item = aText[i];
            this.bs.WriteItem(c_oSerNumTypes.lvl_LvlTextItem, function(){oThis.WriteLevelTextItem(item);});
        }
    };
    this.WriteLevelTextItem = function(oTextItem)
    {
        var oThis = this;
        if(numbering_lvltext_Text == oTextItem.Type)
        {
            this.memory.WriteByte(c_oSerNumTypes.lvl_LvlTextItemText);
            oThis.memory.WriteString2(oTextItem.Value.toString());
        }
        else if(numbering_lvltext_Num == oTextItem.Type)
        {
            this.memory.WriteByte(c_oSerNumTypes.lvl_LvlTextItemNum);
            this.bs.WriteItemWithLength(function(){oThis.memory.WriteByte(oTextItem.Value);});
        }
    };
};
function BinaryDocumentTableWriter(memory, doc, oMapCommentId, oNumIdMap, copyParams, saveParams, oBinaryHeaderFooterTableWriter)
{
    this.memory = memory;
    this.Document = doc;
	this.oNumIdMap = oNumIdMap;
    this.bs = new BinaryCommonWriter(this.memory);
	this.btblPrs = new Binary_tblPrWriter(this.memory, oNumIdMap, saveParams);
    this.bpPrs = new Binary_pPrWriter(this.memory, oNumIdMap, oBinaryHeaderFooterTableWriter, saveParams);
    this.brPrs = new Binary_rPrWriter(this.memory, saveParams);
	this.boMaths = new Binary_oMathWriter(this.memory, null, saveParams);
	this.oMapCommentId = oMapCommentId;
	this.copyParams = copyParams;
	this.saveParams = saveParams;
    this.Write = function()
    {
        var oThis = this;
        this.bs.WriteItemWithLength(function(){oThis.WriteDocumentContent(oThis.Document, true);});
    };
    this.WriteDocumentContent = function(oDocument, bIsMainDoc)
    {
        var Content = oDocument.Content;
        var oThis = this;
        for ( var i = 0, length = Content.length; i < length; ++i )
        {
            var item = Content[i];
            if ( type_Paragraph === item.GetType() )
            {
                this.memory.WriteByte(c_oSerParType.Par);
                this.bs.WriteItemWithLength(function(){oThis.WriteParapraph(item);});
            }
            else if(type_Table === item.GetType())
            {
                this.memory.WriteByte(c_oSerParType.Table);
                this.bs.WriteItemWithLength(function(){oThis.WriteDocTable(item);});
            }
			else if(type_BlockLevelSdt === item.GetType())
			{
				this.memory.WriteByte(c_oSerParType.Sdt);
				this.bs.WriteItemWithLength(function(){oThis.WriteSdt(item, 0);});
			}
        }
        if(bIsMainDoc)
        {
            //sectPr
            this.bs.WriteItem(c_oSerParType.sectPr, function(){oThis.bpPrs.WriteSectPr(oThis.Document.SectPr, oThis.Document);});
			if (oThis.Document.Background) {
				this.bs.WriteItem(c_oSerParType.Background, function(){oThis.WriteBackground(oThis.Document.Background);});
			}
			var macros = this.Document.DrawingDocument.m_oWordControl.m_oApi.macros.GetData();
			if (macros) {
				this.bs.WriteItem(c_oSerParType.JsaProject, function() {
					oThis.memory.WriteXmlString(macros);
				});
			}
		}
    };
	this.WriteBackground = function(oBackground) {
		var oThis = this;
		var color = null;
		if (null != oBackground.Color)
			color = oBackground.Color;
		else if (null != oBackground.Unifill) {
			var doc = editor.WordControl.m_oLogicDocument;
			oBackground.Unifill.check(doc.Get_Theme(), doc.Get_ColorMap());
			var RGBA = oBackground.Unifill.getRGBAColor();
			color = new AscCommonWord.CDocumentColor(RGBA.R, RGBA.G, RGBA.B);
		}
		if (null != color && !color.Auto)
			this.bs.WriteColor(c_oSerBackgroundType.Color, color);
		if (null != oBackground.Unifill || (null != oBackground.Color && oBackground.Color.Auto)) {
			this.memory.WriteByte(c_oSerBackgroundType.ColorTheme);
			this.memory.WriteByte(c_oSerPropLenType.Variable);
			this.bs.WriteItemWithLength(function () { oThis.bs.WriteColorTheme(oBackground.Unifill, oBackground.Color); });
		}
		if (oBackground.shape) {
			this.memory.WriteByte(c_oSerBackgroundType.pptxDrawing);
			this.memory.WriteByte(c_oSerPropLenType.Variable);
			this.bs.WriteItemWithLength(function(){oThis.WriteGraphicObj(oBackground.shape);});
		}
	}
    this.WriteParapraph = function(par, bUseSelection, selectedAll)
    {
        var oThis = this;
		if(null != this.copyParams)
        {
			//анализируем используемые списки и стили
			var sParaStyle = par.Style_Get();
			if(null != sParaStyle)
				this.copyParams.oUsedStyleMap[sParaStyle] = 1;
			var oNumPr = par.GetNumPr();
			if(oNumPr && oNumPr.IsValid())
			{
				if(null == this.copyParams.oUsedNumIdMap[oNumPr.NumId])
				{
					this.copyParams.oUsedNumIdMap[oNumPr.NumId] = this.copyParams.nNumIdIndex;
					this.copyParams.nNumIdIndex++;
					//проверяем PStyle уровней списка
					var Numbering = par.Parent.Get_Numbering();
					var oNum = null;
					if(null != Numbering)
						oNum = Numbering.GetNum(oNumPr.NumId);
					if(null != oNum)
					{
						if (null != oNum.GetNumStyleLink()) {
							this.copyParams.oUsedStyleMap[oNum.GetNumStyleLink()] = 1;
						}
						if (null != oNum.GetStyleLink()) {
							this.copyParams.oUsedStyleMap[oNum.GetStyleLink()] = 1;
						}
						for(var i = 0, length = 9; i < length; ++i)
						{
							var oLvl = oNum.GetLvl(i);
							if(oLvl && oLvl.GetPStyle())
								this.copyParams.oUsedStyleMap[oLvl.GetPStyle()] = 1;
						}
					}
				}
			}
        }
        //pPr
        var ParaStyle = par.Style_Get();
        var pPr = par.Pr;
        if(null != pPr || null != ParaStyle)
        {
            if(null == pPr)
                pPr = {};
            var EndRun = par.Get_ParaEndRun();
            this.memory.WriteByte(c_oSerParType.pPr);
            this.bs.WriteItemWithLength(function(){oThis.bpPrs.Write_pPr(pPr, par.TextPr.Value, EndRun, par.Get_SectionPr(), oThis.Document);});
        }
        //Content
        if(null != par.Content)
        {
            this.memory.WriteByte(c_oSerParType.Content);
            this.bs.WriteItemWithLength(function(){oThis.WriteParagraphContent(par, bUseSelection ,true, selectedAll);});
        }
    };
    this.WriteParagraphContent = function (par, bUseSelection, bLastRun, selectedAll)
    {
        var ParaStart = 0;
        var ParaEnd = par.Content.length - 1;
        if (true == bUseSelection) {
            ParaStart = par.Selection.StartPos;
            ParaEnd = par.Selection.EndPos;
            if (ParaStart > ParaEnd) {
                var Temp2 = ParaEnd;
                ParaEnd = ParaStart;
                ParaStart = Temp2;
            }
        };
		
		//TODO Стоит пересмотреть флаг bUseSelection и учитывать внутри Selection флаг use.
		if(ParaEnd < 0)
			ParaEnd = 0;
		if(ParaStart < 0)
			ParaStart = 0;	
		
		var Content = par.Content;
        //todo commentStart для копирования
        var oThis = this;
        for ( var i = ParaStart; i <= ParaEnd && i < Content.length; ++i )
        {
            var item = Content[i];
            switch ( item.Type )
            {
                case para_Run:
                    var ReviewType = item.Get_ReviewType();
                    if (reviewtype_Remove == ReviewType || reviewtype_Add == ReviewType) {
                        var recordType = reviewtype_Remove == ReviewType ? c_oSerParType.Del : c_oSerParType.Ins;
                        this.bs.WriteItem(recordType, function () {WriteTrackRevision(oThis.bs, oThis.saveParams.trackRevisionId++, item.ReviewInfo, {bdtw: oThis, run: item, bUseSelection: bUseSelection, ReviewType: ReviewType});});
                    } else {
                        this.WriteRun(item, bUseSelection, false);
                    }
                    break;
				case para_Field:
					var Instr = null;
					var oFFData = null;
					if (fieldtype_MERGEFIELD == item.FieldType) {
						Instr = "MERGEFIELD";
					} else if (fieldtype_FORMTEXT === item.Get_FieldType()) {
						Instr = "FORMTEXT";
						oFFData = {};
					}
					if (null !== Instr) {
						if(this.saveParams && this.saveParams.bMailMergeDocx)
							oThis.WriteParagraphContent(item, bUseSelection, false);
						else
						{
							for(var j = 0; j < item.Arguments.length; ++j){
								var argument = item.Arguments[j];
								argument = argument.replace(/(\\|")/g, "\\$1");
								if(-1 != argument.indexOf(' '))
									argument = "\"" + argument + "\"";
								Instr += " " + argument;
							}
							for(var j = 0; j < item.Switches.length; ++j)
								Instr += " \\" + item.Switches[j];
							this.bs.WriteItem(c_oSerParType.FldSimple, function () {
								oThis.WriteFldSimple(Instr, oFFData, function(){oThis.WriteParagraphContent(item, bUseSelection, false);});
							});
						}
					}
                    break;
				case para_Hyperlink:
                    this.bs.WriteItem(c_oSerParType.Hyperlink, function () {
                        oThis.WriteHyperlink(item, bUseSelection);
                    });
                    break;
                case para_Comment:
					if(null != this.oMapCommentId)
					{
					    if (item.Start) {
					        var commentId = this.oMapCommentId[item.CommentId];
					        if (null != commentId)
					            this.bs.WriteItem(c_oSerParType.CommentStart, function () {
					                oThis.bs.WriteItem(c_oSer_CommentsType.Id, function () {
					                    oThis.memory.WriteLong(commentId);
					                })
					            });
					    }
					    else
					    {
					        var commentId = this.oMapCommentId[item.CommentId];
					        if (null != commentId) {
					            this.bs.WriteItem(c_oSerParType.CommentEnd, function () {
					                oThis.bs.WriteItem(c_oSer_CommentsType.Id, function () {
					                    oThis.memory.WriteLong(commentId);
					                })
					            });
					            this.WriteRun2(function () {
					                oThis.bs.WriteItem(c_oSerRunType.CommentReference, function () {
					                    oThis.bs.WriteItem(c_oSer_CommentsType.Id, function () {
					                        oThis.memory.WriteLong(commentId);
					                    })
					                });
					            });
					        }
					    }
					}
                    break;
				case para_Math:
					{
						if (null != item.Root)
						{
							if(this.saveParams && this.saveParams.bMailMergeHtml)
							{
								//заменяем на картинку, если бы был аналог CachedImage не надо было бы заменять
								var sSrc = item.MathToImageConverter();
								if (null != sSrc && null != sSrc.ImageUrl && sSrc.w_mm > 0 && sSrc.h_mm > 0){
									var doc = this.Document;
									//todo paragraph
									var drawing = new ParaDrawing(sSrc.w_mm, sSrc.h_mm, null, this.Document.DrawingDocument, this.Document, par);
									var Image = editor.WordControl.m_oLogicDocument.DrawingObjects.createImage(sSrc.ImageUrl, 0, 0, sSrc.w_mm, sSrc.h_mm);
									Image.cachedImage = sSrc.ImageUrl;
									drawing.Set_GraphicObject(Image);
									Image.setParent(drawing);
									this.WriteRun2( function () {
										oThis.bs.WriteItem(c_oSerRunType.pptxDrawing, function () { oThis.WriteImage(drawing); });
									});
								}
							}
							else 
								this.bs.WriteItem(c_oSerParType.OMathPara, function(){oThis.boMaths.WriteOMathPara(item);});	
						}
					}
					break;
				case para_InlineLevelSdt:
					this.bs.WriteItem(c_oSerParType.Sdt, function () {
						oThis.WriteSdt(item, 1);
					});
					break;
				case para_Bookmark:
					var typeBookmark = item.IsStart() ? c_oSerParType.BookmarkStart : c_oSerParType.BookmarkEnd;
					this.bs.WriteItem(typeBookmark, function () {
						oThis.bs.WriteBookmark(item);
					});
					break;
            }
        }
        if ((bLastRun && bUseSelection && !par.Selection_CheckParaEnd()) || (selectedAll != undefined && selectedAll === false) )
		{
            this.WriteRun2( function () {
                oThis.memory.WriteByte(c_oSerRunType._LastRun);
                oThis.memory.WriteLong(c_oSerPropLenType.Null);
            });
        }
    };
    this.WriteHyperlink = function (oHyperlink, bUseSelection) {
        var oThis = this;
        var sTooltip = oHyperlink.GetToolTip();
		if (oHyperlink.IsAnchor()) {
			this.memory.WriteByte(c_oSer_HyperlinkType.Anchor);
			this.memory.WriteString2(oHyperlink.GetAnchor());
		} else {
			this.memory.WriteByte(c_oSer_HyperlinkType.Link);
			this.memory.WriteString2(oHyperlink.GetValue());
		}
        //Tooltip
        if (null != sTooltip && "" != sTooltip)
        {
            this.memory.WriteByte(c_oSer_HyperlinkType.Tooltip);
            this.memory.WriteString2(sTooltip);
        }
        this.bs.WriteItem(c_oSer_HyperlinkType.History, function(){
            oThis.memory.WriteBool(true);
        });	
        //Content
        this.bs.WriteItem(c_oSer_HyperlinkType.Content, function () {
            oThis.WriteParagraphContent(oHyperlink, bUseSelection, false);
        });
    }
	this.WriteText = function (sCurText, type)
    {
        if("" != sCurText)
        {
			this.memory.WriteByte(type);
            this.memory.WriteString2(sCurText.toString());
            sCurText = "";
        }
        return sCurText;
    };
    this.WriteRun2 = function (fWriter, oRun) {
        var oThis = this;
        this.bs.WriteItem(c_oSerParType.Run, function () {
            //rPr
            if (null != oRun && null != oRun.Pr)
                oThis.bs.WriteItem(c_oSerRunType.rPr, function () { oThis.brPrs.Write_rPr(oRun.Pr, oRun.Pr, null); });
            //Content
            oThis.bs.WriteItem(c_oSerRunType.Content, function () {
                fWriter();
            });
        });
    }
    this.WriteRun = function (oRun, bUseSelection, delText) {
        //Paragraph.Selection последний элемент входит в выделение
        //Run.Selection последний элемент не входит в выделение
        var oThis = this;
		if(null != this.copyParams)
        {
			//анализируем используемые стили
			var runStyle = oRun.Pr.RStyle !== undefined ? oRun.Pr.RStyle : null;
			if(null != runStyle)
				this.copyParams.oUsedStyleMap[runStyle] = 1;
        }
		
        var ParaStart = 0;
        var ParaEnd = oRun.Content.length;
        if (true == bUseSelection) {
            ParaStart = oRun.Selection.StartPos;
            ParaEnd = oRun.Selection.EndPos;
            if (ParaStart > ParaEnd) {
                var Temp2 = ParaEnd;
                ParaEnd = ParaStart;
                ParaStart = Temp2;
            }
        }
        //разбиваем по para_PageNum на массив диапазонов.
        var nPrevIndex = ParaStart;
        var aRunRanges = [];
        for (var i = ParaStart; i < ParaEnd && i < oRun.Content.length; i++) {
            var item = oRun.Content[i];
            if (item.Type == para_PageNum || item.Type == para_PageCount) {
                var elem;
                if (nPrevIndex < i)
                    elem = { nStart: nPrevIndex, nEnd: i, pageNum: item };
                else
                    elem = { nStart: null, nEnd: null, pageNum: item };
                nPrevIndex = i + 1;
                aRunRanges.push(elem);
            }
        }
        if (nPrevIndex <= ParaEnd)
            aRunRanges.push({ nStart: nPrevIndex, nEnd: ParaEnd, pageNum: null });
        for (var i = 0, length = aRunRanges.length; i < length; i++) {
            var elem = aRunRanges[i];
            if (null != elem.nStart && null != elem.nEnd) {
                this.bs.WriteItem(c_oSerParType.Run, function () {
                    //rPr
                    if (null != oRun.Pr)
                        oThis.bs.WriteItem(c_oSerRunType.rPr, function () { oThis.brPrs.Write_rPr(oRun.Pr, oRun.Pr, null); });
                    //Content
                    oThis.bs.WriteItem(c_oSerRunType.Content, function () {
                        oThis.WriteRunContent(oRun, elem.nStart, elem.nEnd, delText);
                    });
                });
            }
            if (null != elem.pageNum) {
				var Instr;
				if (elem.pageNum.Type == para_PageCount) {
					Instr = "NUMPAGES \\* MERGEFORMAT";
				} else {
					Instr = "PAGE \\* MERGEFORMAT";
				}
				this.bs.WriteItem(c_oSerParType.FldSimple, function(){oThis.WriteFldSimple(Instr, null, function(){
                    oThis.WriteRun2(function () {
                        //todo не писать через fldsimple
						var num = elem.pageNum.Type == para_PageCount ? elem.pageNum.GetPageCountValue() : elem.pageNum.GetPageNumValue();
						var textType = delText ? c_oSerRunType.delText : c_oSerRunType.run;
						oThis.WriteText(num.toString(), textType);
                    }, oRun);
				});});
            }
        }
    }
	this.WriteFldChar = function (fldChar)
	{
		var oThis = this;
		this.bs.WriteItem(c_oSer_FldSimpleType.CharType, function() {
			oThis.memory.WriteByte(fldChar.CharType);
		});
	};
	this.WriteFldSimple = function (Instr, oFFData, fWriteContent)
    {
		var oThis = this;
		//порядок записи важен
		//Instr
		this.memory.WriteByte(c_oSer_FldSimpleType.Instr);
        this.memory.WriteString2(Instr);
		//FFData
		if (null !== oFFData) {
			this.bs.WriteItem(c_oSer_FldSimpleType.FFData, function() {
				oThis.WriteFFData(oFFData);
			});
		}
		//Content
		this.bs.WriteItem(c_oSer_FldSimpleType.Content, fWriteContent);
    };
	this.WriteFFData = function(oFFData) {
		var oThis = this;
		if (null != oFFData.CalcOnExit) {
			this.bs.WriteItem(c_oSerFFData.CalcOnExit, function() {
				oThis.memory.WriteBool(oFFData.CalcOnExit);
			});
		}
		if (null != oFFData.CheckBox) {
			this.bs.WriteItem(c_oSerFFData.CheckBox, function() {
				oThis.WriteFFCheckBox(oFFData.CheckBox);
			});
		}
		if (null != oFFData.DDList) {
			this.bs.WriteItem(c_oSerFFData.DDList, function() {
				oThis.WriteDDList(oFFData.DDList);
			});
		}
		if (null != oFFData.Enabled) {
			this.bs.WriteItem(c_oSerFFData.Enabled, function() {
				oThis.memory.WriteBool(oFFData.Enabled);
			});
		}
		if (null != oFFData.EntryMacro) {
			this.memory.WriteByte(c_oSerFFData.EntryMacro);
			this.memory.WriteString2(oFFData.EntryMacro);
		}
		if (null != oFFData.ExitMacro) {
			this.memory.WriteByte(c_oSerFFData.ExitMacro);
			this.memory.WriteString2(oFFData.ExitMacro);
		}
		if (null != oFFData.HelpText) {
			this.bs.WriteItem(c_oSerFFData.HelpText, function() {
				oThis.WriteFFHelpText(oFFData.HelpText);
			});
		}
		if (null != oFFData.Label) {
			this.bs.WriteItem(c_oSerFFData.Label, function() {
				oThis.memory.WriteLong(oFFData.Label);
			});
		}
		if (null != oFFData.Name) {
			this.memory.WriteByte(c_oSerFFData.Name);
			this.memory.WriteString2(oFFData.Name);
		}
		if (null != oFFData.StatusText) {
			this.bs.WriteItem(c_oSerFFData.StatusText, function() {
				oThis.WriteFFHelpText(oFFData.StatusText);
			});
		}
		if (null != oFFData.TabIndex) {
			this.bs.WriteItem(c_oSerFFData.TabIndex, function() {
				oThis.memory.WriteLong(oFFData.TabIndex);
			});
		}
		if (null != oFFData.TabIndex) {
			this.bs.WriteItem(c_oSerFFData.TabIndex, function() {
				oThis.memory.WriteLong(oFFData.TabIndex);
			});
		}
		if (null != oFFData.TextInput) {
			this.bs.WriteItem(c_oSerFFData.TextInput, function() {
				oThis.WriteTextInput(oFFData.TextInput);
			});
		}
	};
	this.WriteFFCheckBox = function(oCheckBox) {
		var oThis = this;
		if (null != oCheckBox.CBChecked) {
			this.bs.WriteItem(c_oSerFFData.CBChecked, function() {
				oThis.memory.WriteBool(oCheckBox.CBChecked);
			});
		}
		if (null != oCheckBox.CBDefault) {
			this.bs.WriteItem(c_oSerFFData.CBDefault, function() {
				oThis.memory.WriteBool(oCheckBox.CBDefault);
			});
		}
		if (null != oCheckBox.CBSize) {
			this.bs.WriteItem(c_oSerFFData.CBSize, function() {
				oThis.memory.WriteLong(oCheckBox.CBSize);
			});
		}
		if (null != oCheckBox.CBSizeAuto) {
			this.bs.WriteItem(c_oSerFFData.CBSizeAuto, function() {
				oThis.memory.WriteBool(oCheckBox.CBSizeAuto);
			});
		}
	};
	this.WriteDDList = function(oDDList) {
		var oThis = this;
		if (null != oDDList.DLDefault) {
			this.bs.WriteItem(c_oSerFFData.DLDefault, function() {
				oThis.memory.WriteLong(oDDList.DLDefault);
			});
		}
		if (null != oDDList.DLResult) {
			this.bs.WriteItem(c_oSerFFData.DLResult, function() {
				oThis.memory.WriteLong(oDDList.DLResult);
			});
		}
		for (var i = 0; i < oDDList.DLListEntry.length; ++i) {
			this.memory.WriteByte(c_oSerFFData.DLListEntry);
			this.memory.WriteString2(oDDList.DLListEntry[i]);
		}
	};
	this.WriteFFHelpText = function(oHelpText) {
		var oThis = this;
		if (null != oHelpText.HTType) {
			this.bs.WriteItem(c_oSerFFData.HTType, function() {
				oThis.memory.WriteByte(oHelpText.HTType);
			});
		}
		if (null != oHelpText.HTVal) {
			this.memory.WriteByte(c_oSerFFData.HTVal);
			this.memory.WriteString2(oHelpText.HTVal);
		}
	};
	this.WriteTextInput = function(oTextInput) {
		var oThis = this;
		if (null != oTextInput.TIDefault) {
			this.memory.WriteByte(c_oSerFFData.TIDefault);
			this.memory.WriteString2(oTextInput.TIDefault);
		}
		if (null != oTextInput.TIFormat) {
			this.memory.WriteByte(c_oSerFFData.TIFormat);
			this.memory.WriteString2(oTextInput.TIFormat);
		}
		if (null != oTextInput.TIMaxLength) {
			this.bs.WriteItem(c_oSerFFData.TIMaxLength, function() {
				oThis.memory.WriteLong(oTextInput.TIMaxLength);
			});
		}
		if (null != oTextInput.TIType) {
			this.bs.WriteItem(c_oSerFFData.TIType, function() {
				oThis.memory.WriteByte(oTextInput.TIType);
			});
		}
	};

    this.WriteRunContent = function (oRun, nStart, nEnd, delText)
    {
        var oThis = this;
        
        var Content = oRun.Content;
        var sCurText = "";
		var sCurInstrText = "";
		var textType = delText ? c_oSerRunType.delText : c_oSerRunType.run;
		var instrTextType = delText ? c_oSerRunType.delInstrText : c_oSerRunType.instrText;
        for (var i = nStart; i < nEnd && i < Content.length; ++i)
        {
            var item = Content[i];
            switch ( item.Type )
            {
                case para_Text:
					sCurInstrText = this.WriteText(sCurInstrText, instrTextType);
                    if (item.IsNoBreakHyphen()) {
						sCurText = this.WriteText(sCurText, textType);
                        oThis.memory.WriteByte(c_oSerRunType.nonBreakHyphen);
                        oThis.memory.WriteLong(c_oSerPropLenType.Null);
                    } else {
                        sCurText += AscCommon.encodeSurrogateChar(item.Value);
                    }
                    break;
                case para_Space:
                    sCurText += " ";
                    break;
                case para_Tab:
					sCurText = this.WriteText(sCurText, textType);
					sCurInstrText = this.WriteText(sCurInstrText, instrTextType);
                    oThis.memory.WriteByte(c_oSerRunType.tab);
                    oThis.memory.WriteLong(c_oSerPropLenType.Null);
                    break;
                case para_NewLine:
					sCurText = this.WriteText(sCurText, textType);
					sCurInstrText = this.WriteText(sCurInstrText, instrTextType);
                    switch (item.BreakType) {
                        case break_Column:
                            oThis.memory.WriteByte(c_oSerRunType.columnbreak);
                            break;
                        case break_Page:
                            oThis.memory.WriteByte(c_oSerRunType.pagebreak);
                            break;
                        default:
                            oThis.memory.WriteByte(c_oSerRunType.linebreak);
                            break;
                    }
                    oThis.memory.WriteLong(c_oSerPropLenType.Null);
                    break;
				case para_Separator:
					sCurText = this.WriteText(sCurText, textType);
					sCurInstrText = this.WriteText(sCurInstrText, instrTextType);
					oThis.memory.WriteByte(c_oSerRunType.separator);
					oThis.memory.WriteLong(c_oSerPropLenType.Null);
					break;
				case para_ContinuationSeparator:
					sCurText = this.WriteText(sCurText, textType);
					sCurInstrText = this.WriteText(sCurInstrText, instrTextType);
					oThis.memory.WriteByte(c_oSerRunType.continuationSeparator);
					oThis.memory.WriteLong(c_oSerPropLenType.Null);
					break;
				case para_FootnoteRef:
					sCurText = this.WriteText(sCurText, textType);
					sCurInstrText = this.WriteText(sCurInstrText, instrTextType);
					oThis.memory.WriteByte(c_oSerRunType.footnoteRef);
					oThis.memory.WriteLong(c_oSerPropLenType.Null);
					break;
				case para_FootnoteReference:
					sCurText = this.WriteText(sCurText, textType);
					sCurInstrText = this.WriteText(sCurInstrText, instrTextType);
					oThis.bs.WriteItem(c_oSerRunType.footnoteReference, function() {oThis.WriteFootnoteRef(item);});
					break;
				case para_FieldChar:
					sCurText = this.WriteText(sCurText, textType);
					sCurInstrText = this.WriteText(sCurInstrText, instrTextType);
					oThis.bs.WriteItem(c_oSerRunType.fldChar, function() {oThis.WriteFldChar(item);});
					break;
				case para_InstrText:
					sCurText = this.WriteText(sCurText, textType);
					sCurInstrText += AscCommon.encodeSurrogateChar(item.Value);
					break;
                case para_Drawing:
					sCurText = this.WriteText(sCurText, textType);
					sCurInstrText = this.WriteText(sCurInstrText, instrTextType);
                    //if (item.Extent && item.GraphicObj && item.GraphicObj.spPr && item.GraphicObj.spPr.xfrm) {
                    //    item.Extent.W = item.GraphicObj.spPr.xfrm.extX;
                    //    item.Extent.H = item.GraphicObj.spPr.xfrm.extY;
                    //}
                    if(this.copyParams)
                    {
                        AscFormat.ExecuteNoHistory(function(){
                          AscFormat.CheckSpPrXfrm2(item.GraphicObj);
                        }, this, []);
                    }
					
					if(this.copyParams && item.ParaMath)
					{
						oThis.bs.WriteItem(c_oSerRunType.object, function () { oThis.WriteObject(item); });
					}
					else
					{
						oThis.bs.WriteItem(c_oSerRunType.pptxDrawing, function () { oThis.WriteImage(item); });
					}
                    break;
            }
        }
		sCurText = this.WriteText(sCurText, textType);
		sCurInstrText = this.WriteText(sCurInstrText, instrTextType);
    };
	this.WriteFootnoteRef = function(footnoteReference)
	{
		var oThis = this;
		var footnote = footnoteReference.Get_Footnote();
		if (null != footnoteReference.CustomMark) {
			this.bs.WriteItem(c_oSerNotes.RefCustomMarkFollows, function() {oThis.memory.WriteBool(footnoteReference.CustomMark);});
		}
		var index = this.saveParams.footnotesIndex++;
		this.saveParams.footnotes[index] = {type: null, content: footnote};
		this.bs.WriteItem(c_oSerNotes.RefId, function () { oThis.memory.WriteLong(index); });
	};
	this.WriteGraphicObj = function(graphicObj) {
		var oThis = this;
		this.memory.WriteByte(c_oSerImageType2.PptxData);
		this.memory.WriteByte(c_oSerPropLenType.Variable);
		this.bs.WriteItemWithLength(function(){pptx_content_writer.WriteDrawing(oThis.memory, graphicObj, oThis.Document, oThis.oMapCommentId, oThis.oNumIdMap, oThis.copyParams, oThis.saveParams);});
	}
    this.WriteImage = function(img)
    {
		var oThis = this;
		if(drawing_Inline == img.DrawingType)
		{
			this.memory.WriteByte(c_oSerImageType2.Type);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteByte(c_oAscWrapStyle.Inline);
			
			this.memory.WriteByte(c_oSerImageType2.Extent);
			this.memory.WriteByte(c_oSerPropLenType.Variable);
			this.bs.WriteItemWithLength(function(){oThis.WriteExtent(img.Extent);});
			if(img.EffectExtent)
			{
				this.memory.WriteByte(c_oSerImageType2.EffectExtent);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.bs.WriteItemWithLength(function(){oThis.WriteEffectExtent(img.EffectExtent);});
			}
			if (null != img.GraphicObj.locks) {
				this.memory.WriteByte(c_oSerImageType2.GraphicFramePr);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.bs.WriteItemWithLength(function(){oThis.WriteGraphicFramePr(img.GraphicObj.locks);});
			}
			if (null != img.docPr) {
				this.memory.WriteByte(c_oSerImageType2.DocPr);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.bs.WriteItemWithLength(function(){oThis.WriteDocPr(img.docPr);});
			}
			if(null != img.GraphicObj.chart)
			{
				this.memory.WriteByte(c_oSerImageType2.Chart2);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				
				var oBinaryChartWriter = new AscCommon.BinaryChartWriter(this.memory);
				this.bs.WriteItemWithLength(function () { oBinaryChartWriter.WriteCT_ChartSpace(img.GraphicObj); });
			} else {
				this.WriteGraphicObj(img.GraphicObj);
			}
		}
		else
		{
			this.memory.WriteByte(c_oSerImageType2.Type);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteByte(c_oAscWrapStyle.Flow);
			
			if(null != img.behindDoc)
			{
				this.memory.WriteByte(c_oSerImageType2.BehindDoc);
				this.memory.WriteByte(c_oSerPropLenType.Byte);
				this.memory.WriteBool(img.behindDoc);
			}
			if(null != img.Distance.L)
			{
				this.memory.WriteByte(c_oSerImageType2.DistL);
				this.memory.WriteByte(c_oSerPropLenType.Double);
				this.memory.WriteDouble(img.Distance.L);
			}
			if(null != img.Distance.T)
			{
				this.memory.WriteByte(c_oSerImageType2.DistT);
				this.memory.WriteByte(c_oSerPropLenType.Double);
				this.memory.WriteDouble(img.Distance.T);
			}
			if(null != img.Distance.R)
			{
				this.memory.WriteByte(c_oSerImageType2.DistR);
				this.memory.WriteByte(c_oSerPropLenType.Double);
				this.memory.WriteDouble(img.Distance.R);
			}
			if(null != img.Distance.B)
			{
				this.memory.WriteByte(c_oSerImageType2.DistB);
				this.memory.WriteByte(c_oSerPropLenType.Double);
				this.memory.WriteDouble(img.Distance.B);
			}
            if(null != img.LayoutInCell)
            {
                this.memory.WriteByte(c_oSerImageType2.LayoutInCell);
                this.memory.WriteByte(c_oSerPropLenType.Byte);
                this.memory.WriteBool(img.LayoutInCell);
            }
			if(null != img.RelativeHeight)
			{
				this.memory.WriteByte(c_oSerImageType2.RelativeHeight);
				this.memory.WriteByte(c_oSerPropLenType.Long);
				this.memory.WriteLong(img.RelativeHeight);
			}
			if(null != img.SimplePos.Use)
			{
				this.memory.WriteByte(c_oSerImageType2.BSimplePos);
				this.memory.WriteByte(c_oSerPropLenType.Byte);
				this.memory.WriteBool(img.SimplePos.Use);
			}
			if(img.EffectExtent)
			{
				this.memory.WriteByte(c_oSerImageType2.EffectExtent);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.bs.WriteItemWithLength(function(){oThis.WriteEffectExtent(img.EffectExtent);});
			}
			if(null != img.Extent)
			{
				this.memory.WriteByte(c_oSerImageType2.Extent);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.bs.WriteItemWithLength(function(){oThis.WriteExtent(img.Extent);});
			}
			if(null != img.PositionH)
			{
				this.memory.WriteByte(c_oSerImageType2.PositionH);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.bs.WriteItemWithLength(function(){oThis.WritePositionHV(img.PositionH);});
			}
			if(null != img.PositionV)
			{
				this.memory.WriteByte(c_oSerImageType2.PositionV);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.bs.WriteItemWithLength(function(){oThis.WritePositionHV(img.PositionV);});
			}
			if(null != img.SimplePos)
			{
				this.memory.WriteByte(c_oSerImageType2.SimplePos);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.bs.WriteItemWithLength(function(){oThis.WriteSimplePos(img.SimplePos);});
			}
			if(null != img.SizeRelH)
			{
				 this.memory.WriteByte(c_oSerImageType2.SizeRelH);
				 this.memory.WriteByte(c_oSerPropLenType.Variable);
				 this.bs.WriteItemWithLength(function(){oThis.WriteSizeRelHV(img.SizeRelH);});
			}
			if(null != img.SizeRelV)
			{
				this.memory.WriteByte(c_oSerImageType2.SizeRelV);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.bs.WriteItemWithLength(function(){oThis.WriteSizeRelHV(img.SizeRelV);});
			}
			switch(img.wrappingType)
			{
				case WRAPPING_TYPE_NONE:
					this.memory.WriteByte(c_oSerImageType2.WrapNone);
					this.memory.WriteByte(c_oSerPropLenType.Null);
					break;
				case WRAPPING_TYPE_SQUARE:
					this.memory.WriteByte(c_oSerImageType2.WrapSquare);
					this.memory.WriteByte(c_oSerPropLenType.Null);
					break;
				case WRAPPING_TYPE_THROUGH:
					this.memory.WriteByte(c_oSerImageType2.WrapThrough);
					this.memory.WriteByte(c_oSerPropLenType.Variable);
					this.bs.WriteItemWithLength(function(){oThis.WriteWrapThroughTight(img.wrappingPolygon, img.getWrapContour());});
					break;
				case WRAPPING_TYPE_TIGHT:
					this.memory.WriteByte(c_oSerImageType2.WrapTight);
					this.memory.WriteByte(c_oSerPropLenType.Variable);
					this.bs.WriteItemWithLength(function(){oThis.WriteWrapThroughTight(img.wrappingPolygon, img.getWrapContour());});
					break;
				case WRAPPING_TYPE_TOP_AND_BOTTOM:
					this.memory.WriteByte(c_oSerImageType2.WrapTopAndBottom);
					this.memory.WriteByte(c_oSerPropLenType.Null);
					break;
			}
			if (null != img.GraphicObj.locks) {
				this.memory.WriteByte(c_oSerImageType2.GraphicFramePr);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.bs.WriteItemWithLength(function(){oThis.WriteGraphicFramePr(img.GraphicObj.locks);});
			}
			if (null != img.docPr) {
				this.memory.WriteByte(c_oSerImageType2.DocPr);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.bs.WriteItemWithLength(function(){oThis.WriteDocPr(img.docPr);});
			}
			if(null != img.GraphicObj.chart)
			{
				this.memory.WriteByte(c_oSerImageType2.Chart2);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				var oBinaryChartWriter = new AscCommon.BinaryChartWriter(this.memory);
				this.bs.WriteItemWithLength(function () { oBinaryChartWriter.WriteCT_ChartSpace(img.GraphicObj); });
			} else {
				this.WriteGraphicObj(img.GraphicObj);
			}
		}
		if(this.saveParams && this.saveParams.bMailMergeHtml)
		{
			this.memory.WriteByte(c_oSerImageType2.CachedImage);
			this.memory.WriteByte(c_oSerPropLenType.Variable);
			this.memory.WriteString2(img.getBase64Img());
		}
    };
	this.WriteGraphicFramePr = function(locks)
	{
		if (locks & AscFormat.LOCKS_MASKS.noChangeAspect) {
			this.memory.WriteByte(c_oSerGraphicFramePr.NoChangeAspect);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(!!(locks & AscFormat.LOCKS_MASKS.noChangeAspect << 1));
		}
		if (locks & AscFormat.LOCKS_MASKS.noDrilldown) {
			this.memory.WriteByte(c_oSerGraphicFramePr.NoDrilldown);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(!!(locks & AscFormat.LOCKS_MASKS.noDrilldown << 1));
		}
		if (locks & AscFormat.LOCKS_MASKS.noGrp) {
			this.memory.WriteByte(c_oSerGraphicFramePr.NoGrp);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(!!(locks & AscFormat.LOCKS_MASKS.noGrp << 1));
		}
		if (locks & AscFormat.LOCKS_MASKS.noMove) {
			this.memory.WriteByte(c_oSerGraphicFramePr.NoMove);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(!!(locks & AscFormat.LOCKS_MASKS.noMove << 1));
		}
		if (locks & AscFormat.LOCKS_MASKS.noResize) {
			this.memory.WriteByte(c_oSerGraphicFramePr.NoResize);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(!!(locks & AscFormat.LOCKS_MASKS.noResize << 1));
		}
		if (locks & AscFormat.LOCKS_MASKS.noSelect) {
			this.memory.WriteByte(c_oSerGraphicFramePr.NoSelect);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteBool(!!(locks & AscFormat.LOCKS_MASKS.noSelect << 1));
		}
	}
	this.WriteDocPr = function(docPr)
	{
		var oThis = this;
		this.bs.WriteItem(c_oSerDocPr.Id, function(){oThis.memory.WriteLong(oThis.saveParams.docPrId++);});
		if (null != docPr.name) {
			this.memory.WriteByte(c_oSerDocPr.Name);
			this.memory.WriteString2(docPr.name);
		}
		if (null != docPr.isHidden) {
			this.bs.WriteItem(c_oSerDocPr.Hidden, function(){oThis.memory.WriteBool(docPr.isHidden);});
		}
		if (null != docPr.title) {
			this.memory.WriteByte(c_oSerDocPr.Title);
			this.memory.WriteString2(docPr.title);
		}
		if (null != docPr.descr) {
			this.memory.WriteByte(c_oSerDocPr.Descr);
			this.memory.WriteString2(docPr.descr);
		}
	}
	this.WriteEffectExtent = function(EffectExtent)
	{
		if(null != EffectExtent.L)
		{
			this.memory.WriteByte(c_oSerEffectExtent.Left);
			this.memory.WriteByte(c_oSerPropLenType.Double);
			this.memory.WriteDouble(EffectExtent.L);
		}
		if(null != EffectExtent.T)
		{
			this.memory.WriteByte(c_oSerEffectExtent.Top);
			this.memory.WriteByte(c_oSerPropLenType.Double);
			this.memory.WriteDouble(EffectExtent.T);
		}
		if(null != EffectExtent.R)
		{
			this.memory.WriteByte(c_oSerEffectExtent.Right);
			this.memory.WriteByte(c_oSerPropLenType.Double);
			this.memory.WriteDouble(EffectExtent.R);
		}
		if(null != EffectExtent.B)
		{
			this.memory.WriteByte(c_oSerEffectExtent.Bottom);
			this.memory.WriteByte(c_oSerPropLenType.Double);
			this.memory.WriteDouble(EffectExtent.B);
		}
	}
	this.WriteExtent = function(Extent)
	{
		if(null != Extent.W)
		{
			this.memory.WriteByte(c_oSerExtent.Cx);
			this.memory.WriteByte(c_oSerPropLenType.Double);
			this.memory.WriteDouble(Extent.W);
		}
		if(null != Extent.H)
		{
			this.memory.WriteByte(c_oSerExtent.Cy);
			this.memory.WriteByte(c_oSerPropLenType.Double);
			this.memory.WriteDouble(Extent.H);
		}
	}
	this.WritePositionHV = function(PositionH)
	{
		if(null != PositionH.RelativeFrom)
		{
			this.memory.WriteByte(c_oSerPosHV.RelativeFrom);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteByte(PositionH.RelativeFrom);
		}
		if(true == PositionH.Align)
		{
			this.memory.WriteByte(c_oSerPosHV.Align);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteByte(PositionH.Value);
		}
		else
		{
			if (true == PositionH.Percent) {
				this.memory.WriteByte(c_oSerPosHV.PctOffset);
			} else {
				this.memory.WriteByte(c_oSerPosHV.PosOffset);
			}
			this.memory.WriteByte(c_oSerPropLenType.Double);
			this.memory.WriteDouble(PositionH.Value);
		}
	}
	this.WriteSizeRelHV = function(SizeRelHV)
	{
		if(null != SizeRelHV.RelativeFrom) {
			this.memory.WriteByte(c_oSerSizeRelHV.RelativeFrom);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteByte(SizeRelHV.RelativeFrom);
		}
		if (null != SizeRelHV.Percent) {
			this.memory.WriteByte(c_oSerSizeRelHV.Pct);
			this.memory.WriteByte(c_oSerPropLenType.Double);
			this.memory.WriteDouble((SizeRelHV.Percent*100) >> 0);
		}
	}
	this.WriteSimplePos = function(oSimplePos)
	{
		if(null != oSimplePos.X)
		{
			this.memory.WriteByte(c_oSerSimplePos.X);
			this.memory.WriteByte(c_oSerPropLenType.Double);
			this.memory.WriteDouble(oSimplePos.X);
		}
		if(null != oSimplePos.Y)
		{
			this.memory.WriteByte(c_oSerSimplePos.Y);
			this.memory.WriteByte(c_oSerPropLenType.Double);
			this.memory.WriteDouble(oSimplePos.Y);
		}
	}
	this.WriteWrapThroughTight = function(wrappingPolygon, Contour)
	{
		var oThis = this;
		this.memory.WriteByte(c_oSerWrapThroughTight.WrapPolygon);
		this.memory.WriteByte(c_oSerPropLenType.Variable);
		this.bs.WriteItemWithLength(function(){oThis.WriteWrapPolygon(wrappingPolygon, Contour)});
	}
	this.WriteWrapPolygon = function(wrappingPolygon, Contour)
	{
		var oThis = this;
		//всегда пишем Edited == true потому что наш контур отличается от word.
		this.memory.WriteByte(c_oSerWrapPolygon.Edited);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(true);
		if(Contour.length > 0)
		{
			this.memory.WriteByte(c_oSerWrapPolygon.Start);
			this.memory.WriteByte(c_oSerPropLenType.Variable);
			this.bs.WriteItemWithLength(function(){oThis.WritePolygonPoint(Contour[0]);});
			
			if(Contour.length > 1)
			{
				this.memory.WriteByte(c_oSerWrapPolygon.ALineTo);
				this.memory.WriteByte(c_oSerPropLenType.Variable);
				this.bs.WriteItemWithLength(function(){oThis.WriteLineTo(Contour);});
			}
		}
	}
	this.WriteLineTo = function(Contour)
	{
		var oThis = this;
		for(var i = 1, length = Contour.length; i < length; ++i)
		{
			this.memory.WriteByte(c_oSerWrapPolygon.LineTo);
			this.memory.WriteByte(c_oSerPropLenType.Variable);
			this.bs.WriteItemWithLength(function(){oThis.WritePolygonPoint(Contour[i]);});
		}
	}
	this.WritePolygonPoint = function(oPoint)
	{
		if(null != oPoint.x)
		{
			this.memory.WriteByte(c_oSerPoint2D.X);
			this.memory.WriteByte(c_oSerPropLenType.Double);
			this.memory.WriteDouble(oPoint.x);
		}
		if(null != oPoint.y)
		{
			this.memory.WriteByte(c_oSerPoint2D.Y);
			this.memory.WriteByte(c_oSerPropLenType.Double);
			this.memory.WriteDouble(oPoint.y);
		}
	}
	this.WriteDocTable = function(table, aRowElems, nMinGrid, nMaxGrid)
    {
        var oThis = this;
		if(null != this.copyParams)
		{
			//анализируем используемые списки и стили
			var sTableStyle = table.Get_TableStyle();
			if(null != sTableStyle)
				this.copyParams.oUsedStyleMap[sTableStyle] = 1;
		}
        //tblPr
        //tblPr должна идти раньше Content
        if(null != table.Pr)
            this.bs.WriteItem(c_oSerDocTableType.tblPr, function(){oThis.btblPrs.WriteTbl(table);});
        //tblGrid
        if(null != table.TableGrid)
		{
			var aGrid = table.TableGrid;
			if(null != nMinGrid && null != nMaxGrid && 0 != nMinGrid && aGrid.length - 1 != nMaxGrid)
				aGrid = aGrid.slice( nMinGrid, nMaxGrid + 1);
            this.bs.WriteItem(c_oSerDocTableType.tblGrid, function(){oThis.WriteTblGrid(aGrid);});
		}
        //Content
        if(null != table.Content && table.Content.length > 0)
            this.bs.WriteItem(c_oSerDocTableType.Content, function(){oThis.WriteTableContent(table.Content, aRowElems);});
    };
    this.WriteTblGrid = function(grid)
    {
        var oThis = this;
        for(var i = 0, length = grid.length; i < length; i++)
        {
            this.memory.WriteByte(c_oSerDocTableType.tblGrid_Item);
            this.memory.WriteByte(c_oSerPropLenType.Double);
            this.memory.WriteDouble(grid[i]);
        }
    };
    this.WriteTableContent = function(Content, aRowElems)
    {
        var oThis = this;
		var nStart = 0;
		var nEnd = Content.length - 1;
		if(null != aRowElems && aRowElems.length > 0)
		{
			nStart = aRowElems[0].row;
			nEnd = aRowElems[aRowElems.length - 1].row;
		}
        for(var i = nStart; i <= nEnd && i < Content.length; ++i)
		{
			var oRowElem = null;
			if(null != aRowElems)
				oRowElem = aRowElems[i - nStart];
            this.bs.WriteItem(c_oSerDocTableType.Row, function(){oThis.WriteRow(Content[i], i, oRowElem);});
		}
    };
    this.WriteRow = function(Row, nRowIndex, oRowElem)
    {
        var oThis = this;
        //Pr
        if(null != Row.Pr)
        {
			var oRowPr = Row.Pr;
			if(null != oRowElem)
			{
				oRowPr = oRowPr.Copy();
				oRowPr.WAfter = null;
				oRowPr.WBefore = null;
				if(null != oRowElem.after)
					oRowPr.GridAfter = oRowElem.after;
				else
					oRowPr.GridAfter = null;
				if(null != oRowElem.before)
					oRowPr.GridBefore = oRowElem.before;
				else
					oRowPr.GridBefore = null;
			}
            this.bs.WriteItem(c_oSerDocTableType.Row_Pr, function(){oThis.btblPrs.WriteRowPr(oRowPr);});
        }
        //Content
        if(null != Row.Content)
        {
            this.bs.WriteItem(c_oSerDocTableType.Row_Content, function(){oThis.WriteRowContent(Row.Content, nRowIndex, oRowElem);});
        }
    };
    this.WriteRowContent = function(Content, nRowIndex, oRowElem)
    {
        var oThis = this;
		var nStart = 0;
		var nEnd = Content.length - 1;
		if(null != oRowElem)
		{
			nStart = oRowElem.indexStart;
			nEnd = oRowElem.indexEnd;
		}
        for(var i = nStart; i <= nEnd && i < Content.length; i++)
        {
            this.bs.WriteItem(c_oSerDocTableType.Cell, function(){oThis.WriteCell(Content[i], nRowIndex, i);});
        }
    };
    this.WriteCell = function(cell, nRowIndex, nColIndex)
    {
        var oThis = this;
        //Pr
        if(null != cell.Pr)
        {
			var vMerge = null;
			if(vmerge_Continue != cell.Pr.VMerge)
			{
				var row = cell.Row;
				var table = row.Table;
				var oCellInfo = row.Get_CellInfo( nColIndex );
				var StartGridCol = 0;
				if(null != oCellInfo)
					StartGridCol = oCellInfo.StartGridCol;
				else
				{
					var BeforeInfo = row.Get_Before();
					StartGridCol = BeforeInfo.GridBefore;
					for(var i = 0; i < nColIndex; ++i)
					{
						var cellTemp = row.Get_Cell( i );
						StartGridCol += cellTemp.Get_GridSpan();
					}
				}
				if(table.Internal_GetVertMergeCount( nRowIndex, StartGridCol, cell.Get_GridSpan() ) > 1)
					vMerge = vmerge_Restart;
			}
			this.bs.WriteItem(c_oSerDocTableType.Cell_Pr, function(){oThis.btblPrs.WriteCellPr(cell.Pr, vMerge, cell);});
        }
        //Content
        if(null != cell.Content)
        {
            var oInnerDocument = new BinaryDocumentTableWriter(this.memory, this.Document, this.oMapCommentId, this.oNumIdMap, this.copyParams, this.saveParams, this.oBinaryHeaderFooterTableWriter);
            this.bs.WriteItem(c_oSerDocTableType.Cell_Content, function(){oInnerDocument.WriteDocumentContent(cell.Content);});
        }
    };
	this.WriteObject = function (obj)
    {
        var oThis = this;
		
		oThis.bs.WriteItem(c_oSerParType.OMath, function(){oThis.boMaths.WriteArgNodes(obj.ParaMath.Root);});
		oThis.bs.WriteItem(c_oSerRunType.pptxDrawing, function () { oThis.WriteImage(obj); });
	};
	this.WriteSdt = function (oSdt, type)
	{
		var oThis = this;
		if (oSdt.Pr) {
			oThis.bs.WriteItem(c_oSerSdt.Pr, function () { oThis.WriteSdtPr(oSdt.Pr); });
		}
		// if (oSdt.EndPr) {
		// 	this.bs.WriteItem(c_oSerSdt.EndPr, function(){oThis.brPrs.Write_rPr(oSdt.EndPr, null, null);});
		// }
		if (0 === type) {
			var oInnerDocument = new BinaryDocumentTableWriter(this.memory, this.Document, this.oMapCommentId, this.oNumIdMap, this.copyParams, this.saveParams, this.oBinaryHeaderFooterTableWriter);
			this.bs.WriteItem(c_oSerSdt.Content, function(){oInnerDocument.WriteDocumentContent(oSdt.Content);});
		} else if (1 === type) {
			this.bs.WriteItem(c_oSerSdt.Content, function(){oThis.WriteParagraphContent(oSdt, false, false);});
		}
	};
	this.WriteSdtPr = function (val)
	{
		var oThis = this;
		var type;
		if (null != val.Alias) {
			this.memory.WriteByte(c_oSerSdt.Alias);
			this.memory.WriteString2(val.Alias);
		}
		if (null != val.Appearance) {
			oThis.bs.WriteItem(c_oSerSdt.Appearance, function (){oThis.memory.WriteByte(val.Appearance);});
		}
		// if (null != val.ComboBox) {
		// 	oThis.bs.WriteItem(c_oSerSdt.ComboBox, function (){oThis.WriteSdtComboBox(val.ComboBox);});
		// }
		if (null != val.Color) {
			var rPr = new CTextPr();
			rPr.Color = val.Color;
			oThis.bs.WriteItem(c_oSerSdt.Color, function (){oThis.brPrs.Write_rPr(rPr, null, null);});
		}
		// if (null != val.DataBinding) {
		// 	oThis.bs.WriteItem(c_oSerSdt.DataBinding, function (){oThis.WriteSdtPrDataBinding(val.DataBinding);});
		// }
		// if (null != val.PrDate) {
		// 	oThis.bs.WriteItem(c_oSerSdt.PrDate, function (){oThis.WriteSdtPrDate(val.PrDate);});
		// }
		// if (null != val.DocPartList) {
		// 	oThis.bs.WriteItem(c_oSerSdt.DocPartList, function (){oThis.WriteDocPartList(val.DocPartList);});
		// }
		if (val.IsBuiltInDocPart()) {
			type = 5;
			oThis.bs.WriteItem(c_oSerSdt.DocPartObj, function (){oThis.WriteDocPartList(val.DocPartObj);});
		}
		// if (null != val.DropDownList) {
		// 	oThis.bs.WriteItem(c_oSerSdt.DropDownList, function (){oThis.WriteSdtComboBox(val.DropDownList);});
		// }
		if (null != val.Id) {
			oThis.bs.WriteItem(c_oSerSdt.Id, function (){oThis.memory.WriteLong(val.Id);});
		}
		if (null != val.Label) {
			oThis.bs.WriteItem(c_oSerSdt.Label, function (){oThis.memory.WriteLong(val.Label);});
		}
		if (null != val.Lock) {
			oThis.bs.WriteItem(c_oSerSdt.Lock, function (){oThis.memory.WriteByte(val.Lock);});
		}
		// if (null != val.PlaceHolder) {
		// 	this.memory.WriteByte(c_oSerSdt.PlaceHolder);
		// 	this.memory.WriteString2(val.PlaceHolder);
		// }
		// if (null != val.RPr) {
		// 	this.bs.WriteItem(c_oSerSdt.RPr, function(){oThis.brPrs.Write_rPr(val.RPr, null, null);});
		// }
		// if (null != val.ShowingPlcHdr) {
		// 	oThis.bs.WriteItem(c_oSerSdt.ShowingPlcHdr, function (){oThis.memory.WriteBool(val.ShowingPlcHdr);});
		// }
		// if (null != val.TabIndex) {
		// 	oThis.bs.WriteItem(c_oSerSdt.TabIndex, function (){oThis.memory.WriteLong(val.TabIndex);});
		// }
		if (null != val.Tag) {
			this.memory.WriteByte(c_oSerSdt.Tag);
			this.memory.WriteString2(val.Tag);
		}
		// if (null != val.Temporary) {
		// 	oThis.bs.WriteItem(c_oSerSdt.Temporary, function (){oThis.memory.WriteBool(val.Temporary);});
		// }
		// if (null != val.MultiLine) {
		// 	oThis.bs.WriteItem(c_oSerSdt.MultiLine, function (){oThis.memory.WriteBool(val.MultiLine);});
		// }
		if (undefined !== type) {
			oThis.bs.WriteItem(c_oSerSdt.Type, function (){oThis.memory.WriteByte(type);});
		}
	};
	this.WriteSdtComboBox = function (val)
	{
		var oThis = this;
		if (null != val.LastValue) {
			this.memory.WriteByte(c_oSerSdt.LastValue);
			this.memory.WriteString2(val.LastValue);
		}
		if (null != val.List) {
			for(var  i = 0 ; i < val.List.length; ++i){
				oThis.bs.WriteItem(c_oSerSdt.SdtListItem, function (){oThis.WriteSdtListItem(val.List[i]);});
			}
		}
	};
	this.WriteSdtListItem = function (val)
	{
		var oThis = this;
		if (null != val.DisplayText) {
			this.memory.WriteByte(c_oSerSdt.DisplayText);
			this.memory.WriteString2(val.DisplayText);
		}
		if (null != val.Value) {
			this.memory.WriteByte(c_oSerSdt.Value);
			this.memory.WriteString2(val.Value);
		}
	};
	this.WriteSdtPrDataBinding = function (val)
	{
		var oThis = this;
		if (null != val.PrefixMappings) {
			this.memory.WriteByte(c_oSerSdt.PrefixMappings);
			this.memory.WriteString2(val.PrefixMappings);
		}
		if (null != val.StoreItemID) {
			this.memory.WriteByte(c_oSerSdt.StoreItemID);
			this.memory.WriteString2(val.StoreItemID);
		}
		if (null != val.XPath) {
			this.memory.WriteByte(c_oSerSdt.XPath);
			this.memory.WriteString2(val.XPath);
		}
	};
	this.WriteSdtPrDate = function (val)
	{
		var oThis = this;
		if (null != val.FullDate) {
			this.memory.WriteByte(c_oSerSdt.FullDate);
			this.memory.WriteString2(val.FullDate);
		}
		if (null != val.Calendar) {
			oThis.bs.WriteItem(c_oSerSdt.Calendar, function (){oThis.memory.WriteByte(val.Calendar);});
		}
		if (null != val.DateFormat) {
			this.memory.WriteByte(c_oSerSdt.DateFormat);
			this.memory.WriteString2(val.DateFormat);
		}
		if (null != val.Lid) {
			this.memory.WriteByte(c_oSerSdt.Lid);
			this.memory.WriteString2(val.Lid);
		}
		if (null != val.StoreMappedDataAs) {
			oThis.bs.WriteItem(c_oSerSdt.StoreMappedDataAs, function (){oThis.memory.WriteByte(val.StoreMappedDataAs);});
		}
	};
	this.WriteDocPartList = function (val)
	{
		var oThis = this;
		if (null != val.Category) {
			this.memory.WriteByte(c_oSerSdt.DocPartCategory);
			this.memory.WriteString2(val.Category);
		}
		if (null != val.Gallery) {
			this.memory.WriteByte(c_oSerSdt.DocPartGallery);
			this.memory.WriteString2(val.Gallery);
		}
		if (null != val.Unique) {
			oThis.bs.WriteItem(c_oSerSdt.DocPartUnique, function (){oThis.memory.WriteBool(val.Unique);});
		}
	};
};
function BinaryOtherTableWriter(memory, doc)
{
    this.memory = memory;
    this.Document = doc;
    this.bs = new BinaryCommonWriter(this.memory);
    this.Write = function()
    {
        var oThis = this;
        this.bs.WriteItemWithLength(function(){oThis.WriteOtherContent();});
    };
    this.WriteOtherContent = function()
    {
        var oThis = this;
        //delete ImageMap
		//DocxTheme
		this.bs.WriteItem(c_oSerOtherTableTypes.DocxTheme, function(){pptx_content_writer.WriteTheme(oThis.memory, oThis.Document.theme);});
    };
};
function BinaryCommentsTableWriter(memory, doc, oMapCommentId)
{
    this.memory = memory;
    this.Document = doc;
    this.oMapCommentId = oMapCommentId;
    this.bs = new BinaryCommonWriter(this.memory);
    this.Write = function()
    {
        var oThis = this;
        this.bs.WriteItemWithLength(function(){oThis.WriteComments();});
    };
    this.WriteComments = function()
    {
        var oThis = this;
		var nIndex = 0;
        for(var i in this.Document.Comments.m_aComments)
		{
			var oComment = this.Document.Comments.m_aComments[i];
			this.bs.WriteItem(c_oSer_CommentsType.Comment, function () { oThis.WriteComment(oComment.Data, oComment.Id, nIndex++); });
		}
    };
    this.WriteComment = function(comment, sCommentId, nFileId)
    {
		var oThis = this;
        if(null != sCommentId && null != nFileId)
		{
			this.oMapCommentId[sCommentId] = nFileId;
			this.bs.WriteItem(c_oSer_CommentsType.Id, function(){oThis.memory.WriteLong(nFileId);});
		}
		if(null != comment.m_sUserName && "" != comment.m_sUserName)
		{
			this.memory.WriteByte(c_oSer_CommentsType.UserName);
			this.memory.WriteString2(comment.m_sUserName);
		}
		if(null != comment.m_sUserId && "" != comment.m_sUserId)
		{
			this.memory.WriteByte(c_oSer_CommentsType.UserId);
			this.memory.WriteString2(comment.m_sUserId);
		}
		if(null != comment.m_sTime && "" != comment.m_sTime)
		{
			var dateStr = new Date(comment.m_sTime - 0).toISOString().slice(0, 19) + 'Z';
			this.memory.WriteByte(c_oSer_CommentsType.Date);
			this.memory.WriteString2(dateStr);
		}
		if(null != comment.m_bSolved)
		{
			this.bs.WriteItem(c_oSer_CommentsType.Solved, function(){oThis.memory.WriteBool(comment.m_bSolved);});
		}
		if(null != comment.m_sText && "" != comment.m_sText)
		{
			this.memory.WriteByte(c_oSer_CommentsType.Text);
			this.memory.WriteString2(comment.m_sText);
		}
		if(null != comment.m_aReplies && comment.m_aReplies.length > 0)
		{
			this.bs.WriteItem(c_oSer_CommentsType.Replies, function(){oThis.WriteReplies(comment.m_aReplies);});
		}
		var dataStr = getCommentAdditionalData(comment);
		if (dataStr)
		{
			this.memory.WriteByte(c_oSer_CommentsType.OOData);
			this.memory.WriteString2(dataStr);
		}
    };
	this.WriteReplies = function(aComments)
	{
        var oThis = this;
		var nIndex = 0;
        for(var i  = 0, length = aComments.length;  i < length; ++i)
            this.bs.WriteItem(c_oSer_CommentsType.Comment, function(){oThis.WriteComment(aComments[i]);});
	}
};
function BinarySettingsTableWriter(memory, doc, saveParams)
{
    this.memory = memory;
    this.Document = doc;
	this.saveParams = saveParams;
    this.bs = new BinaryCommonWriter(this.memory);
	this.bpPrs = new Binary_pPrWriter(this.memory, null, null, saveParams);
	this.brPrs = new Binary_rPrWriter(this.memory, saveParams);
    this.Write = function()
    {
        var oThis = this;
        this.bs.WriteItemWithLength(function(){oThis.WriteSettings();});
    }
    this.WriteSettings = function()
    {
        var oThis = this;
		this.bs.WriteItem(c_oSer_SettingsType.ClrSchemeMapping, function(){oThis.WriteColorSchemeMapping();});
		this.bs.WriteItem(c_oSer_SettingsType.DefaultTabStop, function(){oThis.memory.WriteDouble(AscCommonWord.Default_Tab_Stop);});
		this.bs.WriteItem(c_oSer_SettingsType.MathPr, function(){oThis.WriteMathPr();});
		this.bs.WriteItem(c_oSer_SettingsType.TrackRevisions, function(){oThis.memory.WriteBool(oThis.Document.Is_TrackRevisions());});
		this.bs.WriteItem(c_oSer_SettingsType.FootnotePr, function(){oThis.WriteFootnotePr();});
		if (!oThis.Document.IsSdtGlobalSettingsDefault()) {
			var rPr = new CTextPr();
			rPr.Color = oThis.Document.GetSdtGlobalColor();
			this.bs.WriteItem(c_oSer_SettingsType.SdtGlobalColor, function (){oThis.brPrs.Write_rPr(rPr, null, null);});
			this.bs.WriteItem(c_oSer_SettingsType.SdtGlobalShowHighlight, function(){oThis.memory.WriteBool(oThis.Document.GetSdtGlobalShowHighlight());});
		}
    }
	this.WriteFootnotePr = function()
	{
		var oThis = this;
		this.bpPrs.WriteFootnotePr(this.Document.Footnotes.FootnotePr);
		var index = -1;
		if (this.Document.Footnotes.SeparatorFootnote) {
			this.saveParams.footnotes[index] = {type: 3, content: this.Document.Footnotes.SeparatorFootnote};
			this.bs.WriteItem(c_oSerNotes.PrRef, function() {oThis.memory.WriteLong(index);});
			index++
		}
		if (this.Document.Footnotes.ContinuationSeparatorFootnote) {
			this.saveParams.footnotes[index] = {type: 1, content: this.Document.Footnotes.ContinuationSeparatorFootnote};
			this.bs.WriteItem(c_oSerNotes.PrRef, function() {oThis.memory.WriteLong(index);});
			index++
		}
		if (this.Document.Footnotes.ContinuationNoticeFootnote) {
			this.saveParams.footnotes[index] = {type: 0, content: this.Document.Footnotes.ContinuationNoticeFootnote};
			this.bs.WriteItem(c_oSerNotes.PrRef, function() {oThis.memory.WriteLong(index);});
			index++
		}
		if (index > this.saveParams.footnotesIndex) {
			this.saveParams.footnotesIndex = index;
		}
	}
	this.WriteMathPr = function()
	{
		var oThis = this;
		var oMathPr = editor.WordControl.m_oLogicDocument.Settings.MathSettings.GetPr();
		if ( null != oMathPr.brkBin)
			this.bs.WriteItem(c_oSer_MathPrType.BrkBin, function(){oThis.WriteMathBrkBin(oMathPr.brkBin);});
		if ( null != oMathPr.brkBinSub)
			this.bs.WriteItem(c_oSer_MathPrType.BrkBinSub, function(){oThis.WriteMathBrkBinSub(oMathPr.brkBinSub);});
		if ( null != oMathPr.defJc)
			this.bs.WriteItem(c_oSer_MathPrType.DefJc, function(){oThis.WriteMathDefJc(oMathPr.defJc);});
		if ( null != oMathPr.dispDef)
			this.bs.WriteItem(c_oSer_MathPrType.DispDef, function(){oThis.WriteMathDispDef(oMathPr.dispDef);});
		if ( null != oMathPr.interSp)
			this.bs.WriteItem(c_oSer_MathPrType.InterSp, function(){oThis.WriteMathInterSp(oMathPr.interSp);});
		if ( null != oMathPr.intLim)
			this.bs.WriteItem(c_oSer_MathPrType.IntLim, function(){oThis.WriteMathIntLim(oMathPr.intLim);});
		if ( null != oMathPr.intraSp)
			this.bs.WriteItem(c_oSer_MathPrType.IntraSp, function(){oThis.WriteMathIntraSp(oMathPr.intraSp);});	
		if ( null != oMathPr.lMargin)
			this.bs.WriteItem(c_oSer_MathPrType.LMargin, function(){oThis.WriteMathLMargin(oMathPr.lMargin);});	
		if ( null != oMathPr.mathFont)
			this.bs.WriteItem(c_oSer_MathPrType.MathFont, function(){oThis.WriteMathMathFont(oMathPr.mathFont);});	
		if ( null != oMathPr.naryLim)
			this.bs.WriteItem(c_oSer_MathPrType.NaryLim, function(){oThis.WriteMathNaryLim(oMathPr.naryLim);});	
		if ( null != oMathPr.postSp)
			this.bs.WriteItem(c_oSer_MathPrType.PostSp, function(){oThis.WriteMathPostSp(oMathPr.postSp);});	
		if ( null != oMathPr.preSp)
			this.bs.WriteItem(c_oSer_MathPrType.PreSp, function(){oThis.WriteMathPreSp(oMathPr.preSp);});	
		if ( null != oMathPr.rMargin)
			this.bs.WriteItem(c_oSer_MathPrType.RMargin, function(){oThis.WriteMathRMargin(oMathPr.rMargin);});
		if ( null != oMathPr.smallFrac)
			this.bs.WriteItem(c_oSer_MathPrType.SmallFrac, function(){oThis.WriteMathSmallFrac(oMathPr.smallFrac);});
		if ( null != oMathPr.wrapIndent)
			this.bs.WriteItem(c_oSer_MathPrType.WrapIndent, function(){oThis.WriteMathWrapIndent(oMathPr.wrapIndent);});
		if ( null != oMathPr.wrapRight)
			this.bs.WriteItem(c_oSer_MathPrType.WrapRight, function(){oThis.WriteMathWrapRight(oMathPr.wrapRight);});
	}
	this.WriteMathBrkBin = function(BrkBin)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		var val = c_oAscBrkBin.Repeat;
		switch (BrkBin)
		{
			case BREAK_AFTER: 	val = c_oAscBrkBin.After; break;
			case BREAK_BEFORE: 	val = c_oAscBrkBin.Before;	break;
			case BREAK_REPEAT: 	val = c_oAscBrkBin.Repeat; 
		}
		this.memory.WriteByte(val);
	}
	this.WriteMathBrkBinSub = function(BrkBinSub)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		var val = c_oAscBrkBinSub.MinusMinus;
		switch (BrkBinSub)
		{
			case BREAK_PLUS_MIN: 	val = c_oAscBrkBinSub.PlusMinus; break;
			case BREAK_MIN_PLUS: 	val = c_oAscBrkBinSub.MinusPlus;	break;
			case BREAK_MIN_MIN: 	val = c_oAscBrkBinSub.MinusMinus; 
		}
		this.memory.WriteByte(val);
	}
	this.WriteMathDefJc = function(DefJc)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		var val = c_oAscMathJc.CenterGroup;
		switch (DefJc)
		{
			case align_Center: 			val = c_oAscMathJc.Center; break;
			case align_Justify: 		val = c_oAscMathJc.CenterGroup;	break;
			case align_Left: 			val = c_oAscMathJc.Left;	break;
			case align_Right: 			val = c_oAscMathJc.Right; 
		}
		this.memory.WriteByte(val);
	}
	this.WriteMathDispDef = function(DispDef)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(DispDef);
	}
	this.WriteMathInterSp = function(InterSp)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Double);
		this.memory.WriteDouble(InterSp);
	}
	this.WriteMathIntLim = function(IntLim)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		var val = c_oAscLimLoc.SubSup;
		switch (IntLim)
		{
			case NARY_SubSup: 	val = c_oAscLimLoc.SubSup; break;
			case NARY_UndOvr: 	val = c_oAscLimLoc.UndOvr;
		}
		this.memory.WriteByte(val);
	}
	this.WriteMathIntraSp = function(IntraSp)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Double);
		this.memory.WriteDouble(IntraSp);
	}
	this.WriteMathLMargin = function(LMargin)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Double);
		this.memory.WriteDouble(LMargin);
	}
	this.WriteMathMathFont = function(MathFont)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Variable);
		this.memory.WriteString2(MathFont.Name);
	}
	this.WriteMathNaryLim = function(NaryLim)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		var val = c_oAscLimLoc.SubSup;
		switch (NaryLim)
		{
			case NARY_SubSup: 	val = c_oAscLimLoc.SubSup; break;
			case NARY_UndOvr: 	val = c_oAscLimLoc.UndOvr;
		}
		this.memory.WriteByte(val);
	}
	this.WriteMathPostSp = function(PostSp)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Double);
		this.memory.WriteDouble(PostSp);
	}
	this.WriteMathPreSp = function(PreSp)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Double);
		this.memory.WriteDouble(PreSp);
	}
	this.WriteMathRMargin = function(RMargin)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Double);
		this.memory.WriteDouble(RMargin);
	}
	this.WriteMathSmallFrac = function(SmallFrac)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(SmallFrac);
	}
	this.WriteMathWrapIndent = function(WrapIndent)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Double);
		this.memory.WriteDouble(WrapIndent);
	}
	this.WriteMathWrapRight = function(WrapRight)
	{
		this.memory.WriteByte(c_oSer_OMathBottomNodesValType.Val);
		this.memory.WriteByte(c_oSerPropLenType.Byte);
		this.memory.WriteBool(WrapRight);
	}
    this.WriteColorSchemeMapping = function()
    {
		var oThis = this;
		for(var i in this.Document.clrSchemeMap.color_map)
		{
			var nScriptType = i - 0;
			var nScriptVal = this.Document.clrSchemeMap.color_map[i];
			var nFileType = c_oSer_ClrSchemeMappingType.Accent1;
			var nFileVal = EWmlColorSchemeIndex.wmlcolorschemeindexAccent1;
			switch(nScriptType)
			{
				case 0: nFileType = c_oSer_ClrSchemeMappingType.Accent1; break;
				case 1: nFileType = c_oSer_ClrSchemeMappingType.Accent2; break;
				case 2: nFileType = c_oSer_ClrSchemeMappingType.Accent3; break;
				case 3: nFileType = c_oSer_ClrSchemeMappingType.Accent4; break;
				case 4: nFileType = c_oSer_ClrSchemeMappingType.Accent5; break;
				case 5: nFileType = c_oSer_ClrSchemeMappingType.Accent6; break;
				case 6: nFileType = c_oSer_ClrSchemeMappingType.Bg1; break;
				case 7: nFileType = c_oSer_ClrSchemeMappingType.Bg2; break;
				case 10: nFileType = c_oSer_ClrSchemeMappingType.FollowedHyperlink; break;
				case 11: nFileType = c_oSer_ClrSchemeMappingType.Hyperlink; break;
				case 15: nFileType = c_oSer_ClrSchemeMappingType.T1; break;
				case 16: nFileType = c_oSer_ClrSchemeMappingType.T2; break;
			}
			switch(nScriptVal)
			{
				case 0: nFileVal = EWmlColorSchemeIndex.wmlcolorschemeindexAccent1; break;
				case 1: nFileVal = EWmlColorSchemeIndex.wmlcolorschemeindexAccent2; break;
				case 2: nFileVal = EWmlColorSchemeIndex.wmlcolorschemeindexAccent3; break;
				case 3: nFileVal = EWmlColorSchemeIndex.wmlcolorschemeindexAccent4; break;
				case 4: nFileVal = EWmlColorSchemeIndex.wmlcolorschemeindexAccent5; break;
				case 5: nFileVal = EWmlColorSchemeIndex.wmlcolorschemeindexAccent6; break;
				case 8: nFileVal = EWmlColorSchemeIndex.wmlcolorschemeindexDark1; break;
				case 9: nFileVal = EWmlColorSchemeIndex.wmlcolorschemeindexDark2; break;
				case 10: nFileVal = EWmlColorSchemeIndex.wmlcolorschemeindexFollowedHyperlink; break;
				case 11: nFileVal = EWmlColorSchemeIndex.wmlcolorschemeindexHyperlink; break;
				case 12: nFileVal = EWmlColorSchemeIndex.wmlcolorschemeindexLight1; break;
				case 13: nFileVal = EWmlColorSchemeIndex.wmlcolorschemeindexLight2; break;
			}
			this.memory.WriteByte(nFileType);
			this.memory.WriteByte(c_oSerPropLenType.Byte);
			this.memory.WriteByte(nFileVal);
		}
    }
}
function BinaryNotesTableWriter(memory, doc, oNumIdMap, oMapCommentId, copyParams, saveParams)
{
	this.memory = memory;
	this.Document = doc;
	this.oNumIdMap = oNumIdMap;
	this.oMapCommentId = oMapCommentId;
	this.saveParams = saveParams;
	this.copyParams = copyParams;
	this.bs = new BinaryCommonWriter(this.memory);
	this.Write = function()
	{
		var oThis = this;
		this.bs.WriteItemWithLength(function(){oThis.WriteNotes();});
	};
	this.WriteNotes = function()
	{
		var oThis = this;
		var indexes = [];
		for (var i in this.saveParams.footnotes) {
			indexes.push(i);
		}
		indexes.sort(AscCommon.fSortAscending);
		var nIndex = 0;
		for (var i = 0; i < indexes.length; ++i) {
			var index = indexes[i];
			var footnote = this.saveParams.footnotes[index];
			this.bs.WriteItem(c_oSerNotes.Note, function() {oThis.WriteNote(index, footnote.type, footnote.content);});
		}
	};
	this.WriteNote = function(index, type, footnote) {
		var oThis = this;
		if (null != type) {
			this.bs.WriteItem(c_oSerNotes.NoteType, function() {oThis.memory.WriteByte(type);});
		}
		this.bs.WriteItem(c_oSerNotes.NoteId, function() {oThis.memory.WriteLong(index);});
		var dtw = new BinaryDocumentTableWriter(this.memory, this.Document, this.oMapCommentId, this.oNumIdMap, this.copyParams, this.saveParams, null);
		this.bs.WriteItem(c_oSerNotes.NoteContent, function(){dtw.WriteDocumentContent(footnote);});
	};
};
function BinaryFileReader(doc, openParams)
{
    this.Document = doc;
	this.openParams = openParams;
    this.stream;
	this.oReadResult = new DocReadResult(doc);
    
    this.getbase64DecodedData = function(szSrc)
    {
		var isBase64 = typeof szSrc === 'string';
        var srcLen = isBase64 ? szSrc.length : szSrc.length;
        var nWritten = 0;

        var nType = 0;
        var index = AscCommon.c_oSerFormat.Signature.length;
        var version = "";
        var dst_len = "";
        while (true)
        {
            index++;
            var _c = isBase64 ? szSrc.charCodeAt(index) : szSrc[index];
            if (_c == ";".charCodeAt(0))
            {
                
                if(0 == nType)
                {
                    nType = 1;
                    continue;
                }
                else
                {
                    index++;
                    break;
                }
            }
            if(0 == nType)
                version += String.fromCharCode(_c);
            else
                dst_len += String.fromCharCode(_c);
        }
		if(version.length > 1)
        {
            var nTempVersion = version.substring(1) - 0;
            if(nTempVersion)
              AscCommon.CurFileVersion = nTempVersion;
        }
		var stream;
		if (Asc.c_nVersionNoBase64 !== AscCommon.CurFileVersion) {
			var dstLen = parseInt(dst_len);

			var pointer = g_memory.Alloc(dstLen);
			stream = new AscCommon.FT_Stream2(pointer.data, dstLen);
			stream.obj = pointer.obj;

			var dstPx = stream.data;

			if (window.chrome)
			{
				while (index < srcLen)
				{
					var dwCurr = 0;
					var i;
					var nBits = 0;
					for (i=0; i<4; i++)
					{
						if (index >= srcLen)
							break;
						var nCh = DecodeBase64Char(isBase64 ? szSrc.charCodeAt(index++) : szSrc[index++]);
						if (nCh == -1)
						{
							i--;
							continue;
						}
						dwCurr <<= 6;
						dwCurr |= nCh;
						nBits += 6;
					}

					dwCurr <<= 24-nBits;
					for (i=0; i<nBits/8; i++)
					{
						dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
						dwCurr <<= 8;
					}
				}
			}
			else
			{
				var p = b64_decode;
				while (index < srcLen)
				{
					var dwCurr = 0;
					var i;
					var nBits = 0;
					for (i=0; i<4; i++)
					{
						if (index >= srcLen)
							break;
						var nCh = p[isBase64 ? szSrc.charCodeAt(index++) : szSrc[index++]];
						if (nCh == undefined)
						{
							i--;
							continue;
						}
						dwCurr <<= 6;
						dwCurr |= nCh;
						nBits += 6;
					}

					dwCurr <<= 24-nBits;
					for (i=0; i<nBits/8; i++)
					{
						dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
						dwCurr <<= 8;
					}
				}
			}
		} else {
			stream = new AscCommon.FT_Stream2(szSrc, szSrc.length);
			//skip header
			stream.EnterFrame(index);
			stream.Seek(index);
		}
        return stream;
    };
    this.Read = function(data)
    {
		try{
			this.stream = this.getbase64DecodedData(data);
			this.PreLoadPrepare();
			this.ReadMainTable();
			this.PostLoadPrepare();
		}
		catch(e)
		{
			if(e.message == g_sErrorCharCountMessage)
				return false;
			else
				throw e;
		}
		return true;
    };
	this.PreLoadPrepare = function()
	{
		var styles = this.Document.Styles.Style;
        
        var stDefault = this.Document.Styles.Default;
		stDefault.Character = null;
        stDefault.Numbering = null;
        stDefault.Paragraph = null;
		stDefault.Table = null;

        //надо сбросить то, что остался после открытия документа(повторное открытие в Version History)
        pptx_content_loader.Clear();
	}
    this.ReadMainTable = function()
	{	
        var res = c_oSerConstants.ReadOk;
        //mtLen
        res = this.stream.EnterFrame(1);
        if(c_oSerConstants.ReadOk != res)
            return res;
        var mtLen = this.stream.GetUChar();
        var aSeekTable = [];
        var nOtherTableSeek = -1;
        var nNumberingTableSeek = -1;
		var nCommentTableSeek = -1;
		var nSettingTableSeek = -1;
		var nDocumentTableSeek = -1;
		var nFootnoteTableSeek = -1;
        for(var i = 0; i < mtLen; ++i)
        {
            //mtItem
            res = this.stream.EnterFrame(5);
            if(c_oSerConstants.ReadOk != res)
                return res;
            var mtiType = this.stream.GetUChar();
            var mtiOffBits = this.stream.GetULongLE();
            if(c_oSerTableTypes.Other == mtiType)
                nOtherTableSeek = mtiOffBits;
            else if(c_oSerTableTypes.Numbering == mtiType)
                nNumberingTableSeek = mtiOffBits;
			else if(c_oSerTableTypes.Comments == mtiType)
                nCommentTableSeek = mtiOffBits;
			else if(c_oSerTableTypes.Settings == mtiType)
                nSettingTableSeek = mtiOffBits;
			else if(c_oSerTableTypes.Document == mtiType)
                nDocumentTableSeek = mtiOffBits;
			else if(c_oSerTableTypes.Footnotes == mtiType)
				nFootnoteTableSeek = mtiOffBits;
            else
                aSeekTable.push( {type: mtiType, offset: mtiOffBits} );
        }
        if(-1 != nOtherTableSeek)
        {
            res = this.stream.Seek(nOtherTableSeek);
            if(c_oSerConstants.ReadOk != res)
                return res;
			//todo сделать зачитывание в oReadResult, одновременно с кодом презентаций
			if(!this.openParams.bCopyPaste)
			{
				res = (new Binary_OtherTableReader(this.Document, this.oReadResult, this.stream)).Read();
			}
            if(c_oSerConstants.ReadOk != res)
                return res;
        }
		if(-1 != nCommentTableSeek)
        {
            res = this.stream.Seek(nCommentTableSeek);
            if(c_oSerConstants.ReadOk != res)
                return res;
            res = (new Binary_CommentsTableReader(this.Document, this.oReadResult, this.stream, this.oReadResult.oComments)).Read();
            if(c_oSerConstants.ReadOk != res)
                return res;
        }
		if(-1 != nFootnoteTableSeek)
		{
			res = this.stream.Seek(nFootnoteTableSeek);
			if(c_oSerConstants.ReadOk != res)
				return res;
			res = (new Binary_NotesTableReader(this.Document, this.oReadResult, this.openParams, this.stream)).Read();
			if(c_oSerConstants.ReadOk != res)
				return res;
		}
		if(-1 != nSettingTableSeek)
        {
            res = this.stream.Seek(nSettingTableSeek);
            if(c_oSerConstants.ReadOk != res)
                return res;
			//todo сделать зачитывание в oReadResult, одновременно с кодом презентаций
			if(!this.openParams.bCopyPaste)
			{
				res = (new Binary_SettingsTableReader(this.Document, this.oReadResult, this.stream)).Read();
			}
            if(c_oSerConstants.ReadOk != res)
                return res;
        }
		
        //Читаем Numbering, чтобы была возможность заполнить его даже в стилях
        if(-1 != nNumberingTableSeek)
        {
            res = this.stream.Seek(nNumberingTableSeek);
            if(c_oSerConstants.ReadOk != res)
                return res;
            res = (new Binary_NumberingTableReader(this.Document, this.oReadResult, this.stream)).Read();
            if(c_oSerConstants.ReadOk != res)
                return res;
        }
        var oBinary_DocumentTableReader = new Binary_DocumentTableReader(this.Document, this.oReadResult, this.openParams, this.stream, null, this.oReadResult.oCommentsPlaces);
        for(var i = 0, length = aSeekTable.length; i < length; ++i)
        {
            var item = aSeekTable[i];
            var mtiType = item.type;
            var mtiOffBits = item.offset;
            res = this.stream.Seek(mtiOffBits);
            if(c_oSerConstants.ReadOk != res)
                return res;
            switch(mtiType)
            {
                case c_oSerTableTypes.Signature:break;
                case c_oSerTableTypes.Info:break;
                case c_oSerTableTypes.Style:
                    res = (new BinaryStyleTableReader(this.Document, this.oReadResult, this.stream)).Read();
                    break;
                // case c_oSerTableTypes.Document:
                    // res = oBinary_DocumentTableReader.ReadAsTable(this.oReadResult.DocumentContent);
                    // break;
                case c_oSerTableTypes.HdrFtr:
					//todo сделать зачитывание в oReadResult
					if(!this.openParams.bCopyPaste)
					{
						res = (new Binary_HdrFtrTableReader(this.Document, this.oReadResult,  this.openParams, this.stream)).Read();
					}
                    break;
                // case c_oSerTableTypes.Numbering:
                    // res = (new Binary_NumberingTableReader(this.Document, this.stream, oDocxNum)).Read();
                    // break;
                // case c_oSerTableTypes.Other:
                    // res = (new Binary_OtherTableReader(this.Document, this.stream)).Read();
                    // break;
				case c_oSerTableTypes.App:
					res = (new Binary_AppTableReader(this.oReadResult, this.stream)).Read();
					break;
            }
            if(c_oSerConstants.ReadOk != res)
                return res;
        }
		if(-1 != nDocumentTableSeek)
        {
            res = this.stream.Seek(nDocumentTableSeek);
            if(c_oSerConstants.ReadOk != res)
                return res;
            res = oBinary_DocumentTableReader.ReadAsTable(this.oReadResult.DocumentContent);
            if(c_oSerConstants.ReadOk != res)
                return res;
        }
        return res;
    };
	this.PostLoadPrepareCheckStylesRecursion = function(stId, aStylesGrey, styles){
		var stylesGrey = aStylesGrey[stId];
		if(0 != stylesGrey){
			var stObj = styles[stId];
			if(stObj){
				if(1 == stylesGrey)
					stObj.Set_BasedOn(null);
				else{
					if(null != stObj.BasedOn){
						aStylesGrey[stId] = 1;
						this.PostLoadPrepareCheckStylesRecursion(stObj.BasedOn, aStylesGrey, styles);
					}
					aStylesGrey[stId] = 0;
				}
			}
		}
	};
    this.PostLoadPrepare = function(setting)
    {
		//списки
		for(var i in this.oReadResult.numToANumClass) {
			this.Document.Numbering.AddAbstractNum(this.oReadResult.numToANumClass[i]);
		}
		for(var i in this.oReadResult.numToNumClass) {
			this.Document.Numbering.AddNum(this.oReadResult.numToNumClass[i]);
		}

		for(var i = 0, length = this.oReadResult.paraNumPrs.length; i < length; ++i)
		{
			var numPr = this.oReadResult.paraNumPrs[i];
			var oNumClass = this.oReadResult.numToNumClass[numPr.NumId];
			if(null != oNumClass && 0 !== numPr.NumId)
				numPr.NumId = oNumClass.Get_Id();
			else
				numPr.NumId = 0;
		}
		var oDocStyle = this.Document.Styles;
		var styles = this.Document.Styles.Style;
        var stDefault = this.Document.Styles.Default;
		if(AscCommon.CurFileVersion < 2){
			for(var i in this.oReadResult.styles)
				this.oReadResult.styles[i].style.qFormat = true;
		}		
		//запоминаем имена стилей, которые были изначально в нашем документе, чтобы потом подменить их
		var aStartDocStylesNames = {};
		for(var stId in styles)
		{
			var style = styles[stId];
			if(style && style.Name)
				aStartDocStylesNames[style.Name.toLowerCase().replace(/\s/g,"")] = style;
		}
		//запоминаем default стили имена или id которых совпали с стилями открываемого документа и ссылки на них надо подменить
		var oIdRenameMap = {};
		var oIdMap = {};
		//Удаляем стили с тем же именем
		for(var i in this.oReadResult.styles)
		{
			var elem = this.oReadResult.styles[i];
			var oNewStyle = elem.style;
			var sNewStyleId = oNewStyle.Get_Id();
			var oNewId = elem.param;
			oIdMap[oNewId.id] = sNewStyleId;
            //такой код для сранения имен есть в DrawingDocument.js
            // как только меняется DrawingDocument - меняется и код здесь.
            var sNewStyleName = oNewStyle.Name.toLowerCase().replace(/\s/g,"");
			var oStartDocStyle = aStartDocStylesNames[sNewStyleName];
            if(oStartDocStyle)
            {
				var stId = oStartDocStyle.Get_Id();
				oNewStyle.Set_Name(oStartDocStyle.Name);
				oIdRenameMap[stId] = {id: sNewStyleId, def: oNewId.def, type: oNewStyle.Type, newName: sNewStyleName};
				oDocStyle.Remove(stId);
			}
		}
		//меняем BasedOn и Next
		for(var stId in styles)
        {
            var stObj = styles[stId];
			var oNewId;
			if(null != stObj.BasedOn){
				oNewId = oIdRenameMap[stObj.BasedOn];
				if(null != oNewId)
					stObj.Set_BasedOn(oNewId.id);
			}
			if(null != stObj.Next){
				oNewId = oIdRenameMap[stObj.Next];
				if(null != oNewId)
					stObj.Set_Next(oNewId.id);
			}
			if(null != stObj.Link){
				oNewId = oIdRenameMap[stObj.Link];
				if(null != oNewId)
					stObj.Set_Link(oNewId.id);
			}
        }
		//меняем Headings
		for(var i = 0, length = stDefault.Headings.length; i < length; ++i)
        {
            var sHeading = stDefault.Headings[i];
			var oNewId = oIdRenameMap[sHeading];
			if(null != oNewId)
				stDefault.Headings[i] = oNewId.id;
        }
		//TOC
		for(var i = 0, length = stDefault.TOC.length; i < length; ++i)
		{
			var sTOC = stDefault.TOC[i];
			var oNewId = oIdRenameMap[sTOC];
			if(null != oNewId)
				stDefault.TOC[i] = oNewId.id;
		}
		//TOCHeading
		var sTOCHeading = stDefault.TOCHeading;
		var oNewId = oIdRenameMap[sTOCHeading];
		if(null != oNewId)
			stDefault.TOCHeading = oNewId.id;

		//меняем старые id
		for(var sOldId in oIdRenameMap)
		{
			var oNewId = oIdRenameMap[sOldId];
			var sNewStyleName = oNewId.newName;
			var stId = sOldId;
			if(stDefault.Character == stId)
                stDefault.Character = null;
            if(stDefault.Paragraph == stId)
                stDefault.Paragraph = null;
            if(stDefault.Numbering == stId)
                stDefault.Numbering = null;
            if(stDefault.Table == stId)
                stDefault.Table = null;
            if(stDefault.ParaList == stId)
                stDefault.ParaList = oNewId.id;
            if(stDefault.Header == stId || "header" == sNewStyleName)
                stDefault.Header = oNewId.id;
            if(stDefault.Footer == stId || "footer" == sNewStyleName)
                stDefault.Footer = oNewId.id;
			if(stDefault.Hyperlink == stId || "hyperlink" == sNewStyleName)
                stDefault.Hyperlink = oNewId.id;
            if(stDefault.TableGrid == stId || "tablegrid" == sNewStyleName)
                stDefault.TableGrid = oNewId.id;
			if(stDefault.FootnoteText == stId || "footnotetext" == sNewStyleName)
				stDefault.FootnoteText = oNewId.id;
			if(stDefault.FootnoteTextChar == stId || "footnotetextchar" == sNewStyleName)
				stDefault.FootnoteTextChar = oNewId.id;
			if(stDefault.FootnoteReference == stId || "footnotereference" == sNewStyleName)
				stDefault.FootnoteReference = oNewId.id;
			if (stDefault.NoSpacing == stId)
				stDefault.NoSpacing = oNewId.id;
			if (stDefault.Title == stId)
				stDefault.Title = oNewId.id;
			if (stDefault.Subtitle == stId)
				stDefault.Subtitle = oNewId.id;
			if (stDefault.Quote == stId)
				stDefault.Quote = oNewId.id;
			if (stDefault.IntenseQuote == stId)
				stDefault.IntenseQuote = oNewId.id;

            if(true == oNewId.def)
            {
                switch(oNewId.type)
                {
                    case styletype_Character:stDefault.Character = oNewId.id;break;
                    case styletype_Numbering:stDefault.Numbering = oNewId.id;break;
                    case styletype_Paragraph:stDefault.Paragraph = oNewId.id;break;
                    case styletype_Table:stDefault.Table = oNewId.id;break;
                }
            }
		}
		//will be default if there is no def attribute
		var characterNameId, numberingNameId, paragraphNameId, tableNameId;
		//добавляем новые стили
		for(var i in this.oReadResult.styles)
		{
			var elem = this.oReadResult.styles[i];
			var oNewStyle = elem.style;
			var sNewStyleId = oNewStyle.Get_Id();
			if(null != oNewStyle.BasedOn){
				var oStyleBasedOn = this.oReadResult.styles[oNewStyle.BasedOn];
				if(oStyleBasedOn)
					oNewStyle.Set_BasedOn(oStyleBasedOn.style.Get_Id());
				else
					oNewStyle.Set_BasedOn(null);
			}
			if(null != oNewStyle.Next){
				var oStyleNext = this.oReadResult.styles[oNewStyle.Next];
				if(oStyleNext)
					oNewStyle.Set_Next(oStyleNext.style.Get_Id());
				else
					oNewStyle.Set_Next(null);
			}
			if(null != oNewStyle.Link){
				var oStyleNext = this.oReadResult.styles[oNewStyle.Link];
				if(oStyleNext)
					oNewStyle.Set_Link(oStyleNext.style.Get_Id());
				else
					oNewStyle.Set_Link(null);
			}
			var oNewId = elem.param;
			var sNewStyleName = oNewStyle.Name.toLowerCase().replace(/\s/g,"");
			if(true == oNewId.def)
            {
                switch(oNewStyle.Type)
                {
                    case styletype_Character:stDefault.Character = sNewStyleId;break;
                    case styletype_Numbering:stDefault.Numbering = sNewStyleId;break;
                    case styletype_Paragraph:stDefault.Paragraph = sNewStyleId;break;
                    case styletype_Table:stDefault.Table = sNewStyleId;break;
                }
            }
            if("header" == sNewStyleName)
                stDefault.Header = sNewStyleId;
            if("footer" == sNewStyleName)
                stDefault.Footer = sNewStyleId;
            if("hyperlink" == sNewStyleName)
                stDefault.Hyperlink = sNewStyleId;
            if("tablegrid" == sNewStyleName)
                stDefault.TableGrid = sNewStyleId;
			if("footnotetext" == sNewStyleName)
				stDefault.FootnoteText = sNewStyleId;
			if("footnotetextchar" == sNewStyleName)
				stDefault.FootnoteTextChar = sNewStyleId;
			if("footnotereference" == sNewStyleName)
				stDefault.FootnoteReference = sNewStyleId;
			if("defaultparagraphfont" == sNewStyleName)
				characterNameId = sNewStyleId;
			if("normal" == sNewStyleName)
				paragraphNameId = sNewStyleId;
			if("nolist" == sNewStyleName)
				numberingNameId = sNewStyleId;
			if("normaltable" == sNewStyleName)
				tableNameId = sNewStyleId;
			oDocStyle.Add(oNewStyle);
		}
		var oStyleTypes = {par: 1, table: 2, lvl: 3, run: 4, styleLink: 5, numStyleLink: 6};
		var fParseStyle = function(aStyles, oDocumentStyles, nStyleType)
		{
			for(var i = 0, length = aStyles.length; i < length; ++i)
			{
				var elem = aStyles[i];
				var sStyleId = oIdMap[elem.style];
				if(null != sStyleId && null != oDocumentStyles[sStyleId])
				{
					if(oStyleTypes.run == nStyleType)
						elem.pPr.RStyle = sStyleId;
					else if(oStyleTypes.par == nStyleType)
						elem.pPr.PStyle = sStyleId;
					else if(oStyleTypes.table == nStyleType)
						elem.pPr.TableStyle = sStyleId;
					else if(oStyleTypes.styleLink == nStyleType)
						elem.pPr.StyleLink = sStyleId;
					else if(oStyleTypes.numStyleLink == nStyleType)
						elem.pPr.NumStyleLink = sStyleId;
					else
						elem.pPr.PStyle = sStyleId;
				}
			}
		}
		fParseStyle(this.oReadResult.runStyles, styles, oStyleTypes.run);
		fParseStyle(this.oReadResult.paraStyles, styles, oStyleTypes.par);
		fParseStyle(this.oReadResult.tableStyles, styles, oStyleTypes.table);
		fParseStyle(this.oReadResult.lvlStyles, styles, oStyleTypes.lvl);
		fParseStyle(this.oReadResult.styleLinks, styles, oStyleTypes.styleLink);
		fParseStyle(this.oReadResult.numStyleLinks, styles, oStyleTypes.numStyleLink);
		if (null == stDefault.Character) {
			if (!characterNameId) {
				var oNewStyle = new CStyle("Default Paragraph Font", null, null, styletype_Character );
				oNewStyle.CreateDefaultParagraphFont();
				characterNameId = oDocStyle.Add(oNewStyle);
				//remove style with same name
				var oStartDocStyle = aStartDocStylesNames[oNewStyle.Name.toLowerCase().replace(/\s/g,"")];
				if(oStartDocStyle) {
					oDocStyle.Remove(oStartDocStyle.Get_Id());
				}
			}
			stDefault.Character = characterNameId;
		}
		if (null == stDefault.Numbering) {
			if (!numberingNameId) {
				var oNewStyle = new CStyle("No List", null, null, styletype_Numbering);
				oNewStyle.CreateNoList();
				numberingNameId = oDocStyle.Add(oNewStyle);
				//remove style with same name
				var oStartDocStyle = aStartDocStylesNames[oNewStyle.Name.toLowerCase().replace(/\s/g,"")];
				if(oStartDocStyle) {
					oDocStyle.Remove(oStartDocStyle.Get_Id());
				}
			}
			stDefault.Numbering = numberingNameId;
		}
		if (null == stDefault.Paragraph) {
			if (!paragraphNameId) {
				var oNewStyle = new CStyle("Normal", null, null, styletype_Paragraph);
				oNewStyle.CreateNormal();
				paragraphNameId = oDocStyle.Add(oNewStyle);
				//remove style with same name
				var oStartDocStyle = aStartDocStylesNames[oNewStyle.Name.toLowerCase().replace(/\s/g,"")];
				if(oStartDocStyle) {
					oDocStyle.Remove(oStartDocStyle.Get_Id());
				}
			}
			stDefault.Paragraph = paragraphNameId;
		}
		if (null == stDefault.Table) {
			if (!tableNameId) {
				var oNewStyle = new CStyle("Normal Table", null, null, styletype_Table);
				oNewStyle.Create_NormalTable();
				oNewStyle.Set_TablePr(new CTablePr());
				tableNameId = oDocStyle.Add(oNewStyle);
				//remove style with same name
				var oStartDocStyle = aStartDocStylesNames[oNewStyle.Name.toLowerCase().replace(/\s/g,"")];
				if(oStartDocStyle) {
					oDocStyle.Remove(oStartDocStyle.Get_Id());
				}
			}
			stDefault.Table = tableNameId;
		}
		//проверяем циклы в styles по BasedOn
		var aStylesGrey = {};
		for(var stId in styles)
		{
			this.PostLoadPrepareCheckStylesRecursion(stId, aStylesGrey, styles);
		}
		//DefpPr, DefrPr
		//важно чтобы со списками разобрались выше чем этот код
		if(null != this.oReadResult.DefpPr)
			this.Document.Styles.Default.ParaPr.Merge( this.oReadResult.DefpPr );
		if(null != this.oReadResult.DefrPr)
			this.Document.Styles.Default.TextPr.Merge( this.oReadResult.DefrPr );
		//Footnotes strict after style
		if (this.oReadResult.logicDocument) {
			this.oReadResult.logicDocument.Footnotes.ResetSpecialFootnotes();
			for (var i = 0; i < this.oReadResult.footnoteRefs.length; ++i) {
				var footnote = this.oReadResult.footnotes[this.oReadResult.footnoteRefs[i]];
				if (0 == footnote.type) {
					this.oReadResult.logicDocument.Footnotes.SetContinuationNotice(footnote.content);
				} else if (1 == footnote.type) {
					this.oReadResult.logicDocument.Footnotes.SetContinuationSeparator(footnote.content);
				} else if (3 == footnote.type) {
					this.oReadResult.logicDocument.Footnotes.SetSeparator(footnote.content);
				}
			}
		}

		var setting = this.oReadResult.setting;        
		var fInitCommentData = function(comment)
		{
			var oCommentObj = new CCommentData();
			if(null != comment.UserName)
				oCommentObj.m_sUserName = comment.UserName;
			if(null != comment.UserId)
				oCommentObj.m_sUserId = comment.UserId;
			if(null != comment.Date)
				oCommentObj.m_sTime = comment.Date;
			if(null != comment.OODate)
				oCommentObj.m_sOOTime = comment.OODate;
			if(null != comment.Text)
				oCommentObj.m_sText = comment.Text;
			if(null != comment.Solved)
				oCommentObj.m_bSolved = comment.Solved;
			if(null != comment.Replies)
			{
				for(var  i = 0, length = comment.Replies.length; i < length; ++i)
					oCommentObj.Add_Reply(fInitCommentData(comment.Replies[i]));
			}
			return oCommentObj;
		}
		var oCommentsNewId = {};
		for(var i in this.oReadResult.oComments)
		{
			var oOldComment = this.oReadResult.oComments[i];
			var oNewComment = new CComment(this.Document.Comments, fInitCommentData(oOldComment))
			this.Document.Comments.Add(oNewComment);
			oCommentsNewId[oOldComment.Id] = oNewComment;
		}
		for(var commentIndex in this.oReadResult.oCommentsPlaces)
		{
			var item = this.oReadResult.oCommentsPlaces[commentIndex];
			var bToDelete = true;
			if(null != item.Start && null != item.End){
				var oCommentObj = oCommentsNewId[item.Start.Id];
				if(oCommentObj)
				{
					bToDelete = false;
					if(null != item.QuoteText)
						oCommentObj.Data.m_sQuoteText = item.QuoteText;
					item.Start.oParaComment.Set_CommentId(oCommentObj.Get_Id());
					item.End.oParaComment.Set_CommentId(oCommentObj.Get_Id());
				}
			}
			if(bToDelete){
				if(null != item.Start && null != item.Start.oParent)
				{
					var oParent = item.Start.oParent;
					var oParaComment = item.Start.oParaComment;
					for (var i = OpenParStruct.prototype._GetContentLength(oParent) - 1; i >= 0; --i)
					{
					    if (oParaComment == OpenParStruct.prototype._GetFromContent(oParent, i)){
							OpenParStruct.prototype._removeFromContent(oParent, i, 1);
							break;
						}
					}
				}
				if(null != item.End && null != item.End.oParent)
				{
					var oParent = item.End.oParent;
					var oParaComment = item.End.oParaComment;
					for (var i = OpenParStruct.prototype._GetContentLength(oParent) - 1; i >= 0; --i)
					{
					    if (oParaComment == OpenParStruct.prototype._GetFromContent(oParent, i)){
							OpenParStruct.prototype._removeFromContent(oParent, i, 1);
							break;
						}
					}
				}
			}
		}
		//посылаем событие о добавлении комментариев
		for(var i in oCommentsNewId)
		{
			var oNewComment = oCommentsNewId[i];
			this.Document.DrawingDocument.m_oWordControl.m_oApi.sync_AddComment( oNewComment.Id, oNewComment.Data );
		}
		//remove bookmarks without end
		for(var bookmarkIndex in this.oReadResult.bookmarksStarted)
		{
			var elem = this.oReadResult.bookmarksStarted[bookmarkIndex];
			for (var i = 0; i < OpenParStruct.prototype._GetContentLength(elem.parent); ++i)
			{
				if (elem.bookmark === OpenParStruct.prototype._GetFromContent(elem.parent, i)){
					OpenParStruct.prototype._removeFromContent(elem.parent, i, 1);
					break;
				}
			}
		}
		this.Document.Content = this.oReadResult.DocumentContent;
		if(this.Document.Content.length == 0)
        {
            var oNewParagraph = new Paragraph(this.Document.DrawingDocument, this.Document);
            this.Document.Content.push(oNewParagraph);
        }
		// for(var i = 0, length = this.oReadResult.aPostOpenStyleNumCallbacks.length; i < length; ++i)
			// this.oReadResult.aPostOpenStyleNumCallbacks[i].call();
		if (null != this.oReadResult.trackRevisions) {
			this.Document.DrawingDocument.m_oWordControl.m_oApi.asc_SetTrackRevisions(this.oReadResult.trackRevisions);
		}
		for (var i = 0; i < this.oReadResult.drawingToMath.length; ++i) {
			this.oReadResult.drawingToMath[i].Convert_ToMathObject(true);
		}
		for (var i = 0, length = this.oReadResult.aTableCorrect.length; i < length; ++i) {
			var table = this.oReadResult.aTableCorrect[i];
			table.ReIndexing(0);
			table.Correct_BadTable();
		}
		if (null !== this.oReadResult.compatibilityMode) {
			this.Document.Settings.CompatibilityMode = this.oReadResult.compatibilityMode;
		}
        this.Document.On_EndLoad();
		//чтобы удалялся stream с бинарником
		pptx_content_loader.Clear(true);
    };
    this.ReadFromString = function (sBase64, copyPasteObj) {
        //надо сбросить то, что остался после открытия документа
		var isWordCopyPaste = copyPasteObj ? copyPasteObj.wordCopyPaste : null;
		var isExcelCopyPaste = copyPasteObj ? copyPasteObj.excelCopyPaste : null;
		var isCopyPaste = isWordCopyPaste || isExcelCopyPaste;
		var api = isWordCopyPaste ? this.Document.DrawingDocument.m_oWordControl.m_oApi : null;
		var insertDocumentUrlsData = api ? api.insertDocumentUrlsData : null;
        pptx_content_loader.Clear();
        pptx_content_loader.Start_UseFullUrl(insertDocumentUrlsData);
        this.stream = this.getbase64DecodedData(sBase64);
        this.ReadMainTable();
        var oReadResult = this.oReadResult;
        //обрабатываем списки
        for (var i in oReadResult.numToANumClass) {
            var oNumClass = oReadResult.numToANumClass[i];
            var documentANum = this.Document.Numbering.AbstractNum;
            //проверка на уже существующий такой же AbstractNum
            /*var isAlreadyContains = false;
            for (var n in documentANum) {
                var isEqual = documentANum[n].isEqual(oNumClass);
                if (isEqual == true) {
                    isAlreadyContains = true;
                    break;
                }
            }
            if (!isAlreadyContains) {
                this.Document.Numbering.AddAbstractNum(oNumClass);
            }
            else
                oReadResult.numToNumClass[i] = documentANum[n];*/
			
			//убираю проверку на существующий такой же AbstractNum
			//такая проверка может иметь смысл только если numToNumClass содержит 1 элемент
			//если там более 1 одного элемента - это разные списки. будет проверка на существуюший AbstractNum - они могут стать одним списком, если у них одинаковая структура
			//возможно, нужно сравнивать только numid и в пределах одного документа
			//TODO просмотреть все ситуации со списками
			this.Document.Numbering.AddAbstractNum(oNumClass);
        }
		for(var i in this.oReadResult.numToNumClass) {
			this.Document.Numbering.AddNum(this.oReadResult.numToNumClass[i]);
		}
        for (var i = 0, length = oReadResult.paraNumPrs.length; i < length; ++i) {
            var numPr = oReadResult.paraNumPrs[i];
            var oNumClass = oReadResult.numToNumClass[numPr.NumId];
            if (null != oNumClass)
                numPr.NumId = oNumClass.Get_Id();
            else
                numPr.NumId = 0;
        }
        //обрабатываем стили
        var isAlreadyContainsStyle;
        var oStyleTypes = { par: 1, table: 2, lvl: 3, run: 4, styleLink: 5, numStyleLink: 6};
        var addNewStyles = false;
        var fParseStyle = function (aStyles, oDocumentStyles, oReadResult, nStyleType) {
            if (aStyles == undefined)
                return;
            for (var i = 0, length = aStyles.length; i < length; ++i) {
                var elem = aStyles[i];
                var stylePaste = oReadResult.styles[elem.style];
                var isEqualName = null;
                if (null != stylePaste && null != stylePaste.style && oDocumentStyles) {
                    for (var j in oDocumentStyles.Style) {
                        var styleDoc = oDocumentStyles.Style[j];
                        isAlreadyContainsStyle = styleDoc.isEqual(stylePaste.style);
                        if (styleDoc.Name == stylePaste.style.Name)
                            isEqualName = j;
                        if (isAlreadyContainsStyle) 
						{
                            if (oStyleTypes.par == nStyleType)
                                elem.pPr.PStyle = j;
                            else if (oStyleTypes.table == nStyleType)
                                elem.pPr.Set_TableStyle2(j);
							else if (oStyleTypes.run == nStyleType)
							{
								//TODO сделать аналогично для Pstyle
								if(elem.run)
								{
									elem.run.Set_RStyle(j);
								}
								else
								{
									elem.pPr.RStyle = j;
								}
							}	
                            else if(oStyleTypes.styleLink == nStyleType)
                                elem.pPr.StyleLink = j;
                            else if(oStyleTypes.numStyleLink == nStyleType)
                                elem.pPr.NumStyleLink = j;
							else
                                elem.pPr.PStyle = j;
                            break;
                        }
                    }
                    if (!isAlreadyContainsStyle && isEqualName != null)//если нашли имя такого же стиля
                    {
                        if (nStyleType == oStyleTypes.par || nStyleType == oStyleTypes.lvl)
                            elem.pPr.PStyle = isEqualName;
                        else if (nStyleType == oStyleTypes.table)
                            elem.pPr.Set_TableStyle2(isEqualName);
						else if (nStyleType == oStyleTypes.run)
						{
							if(elem.run)
							{
								elem.run.Set_RStyle(isEqualName);
							}
							else
							{
								elem.pPr.RStyle = isEqualName;
							}
						}	
                        else if(nStyleType == oStyleTypes.styleLink)
                            elem.pPr.StyleLink = isEqualName;
                        else if(nStyleType == oStyleTypes.numStyleLink)
                            elem.pPr.NumStyleLink = isEqualName;
                    }
                    else if (!isAlreadyContainsStyle && isEqualName == null)//нужно добавить новый стиль
                    {
                        //todo править и BaseOn
						stylePaste.style.BasedOn = null;
                        var nStyleId = oDocumentStyles.Add(stylePaste.style);
                        if (nStyleType == oStyleTypes.par || nStyleType == oStyleTypes.lvl)
                            elem.pPr.PStyle = nStyleId;
                        else if (nStyleType == oStyleTypes.table)
                            elem.pPr.Set_TableStyle2(nStyleId);
						else if (nStyleType == oStyleTypes.run)
						{
							if(elem.run)
							{
								elem.run.Set_RStyle(nStyleId);
							}
							else
							{
								elem.pPr.RStyle = nStyleId;
							}
						}
                        else if(nStyleType == oStyleTypes.styleLink)
                            elem.pPr.StyleLink = nStyleId;
                        else if(nStyleType == oStyleTypes.numStyleLink)
                            elem.pPr.NumStyleLink = nStyleId;
						
                        addNewStyles = true;
                    }
                }
            }
        };
		
		fParseStyle(this.oReadResult.runStyles, this.Document.Styles, this.oReadResult, oStyleTypes.run);
        fParseStyle(this.oReadResult.paraStyles, this.Document.Styles, this.oReadResult, oStyleTypes.par);
        fParseStyle(this.oReadResult.tableStyles, this.Document.Styles, this.oReadResult, oStyleTypes.table);
        fParseStyle(this.oReadResult.lvlStyles, this.Document.Styles, this.oReadResult, oStyleTypes.lvl);
        fParseStyle(this.oReadResult.styleLinks, this.Document.Styles, this.oReadResult, oStyleTypes.styleLink);
		fParseStyle(this.oReadResult.numStyleLinks, this.Document.Styles, this.oReadResult, oStyleTypes.numStyleLink);
        var aContent = this.oReadResult.DocumentContent;
        for (var i = 0, length = this.oReadResult.aPostOpenStyleNumCallbacks.length; i < length; ++i)
            this.oReadResult.aPostOpenStyleNumCallbacks[i].call();
        var bInBlock;
        if (oReadResult.bLastRun)
            bInBlock = false;
        else
            bInBlock = true;
        //создаем список используемых шрифтов
        var AllFonts = {};
		
		if(this.Document.Numbering)
			this.Document.Numbering.GetAllFontNames(AllFonts);
		if(this.Document.Styles)	
        this.Document.Styles.Document_Get_AllFontNames(AllFonts);
		
        for (var Index = 0, Count = aContent.length; Index < Count; Index++)
            aContent[Index].Document_Get_AllFontNames(AllFonts);
        var aPrepeareFonts = [];
		
		var oDocument = this.Document && this.Document.LogicDocument ? this.Document.LogicDocument : this.Document;
		
		var fontScheme;
		var m_oLogicDocument = editor.WordControl.m_oLogicDocument;
		//для презентаций находим fontScheme
		if(m_oLogicDocument && m_oLogicDocument.slideMasters && m_oLogicDocument.slideMasters[0] && m_oLogicDocument.slideMasters[0].Theme && m_oLogicDocument.slideMasters[0].Theme.themeElements)
			fontScheme = m_oLogicDocument.slideMasters[0].Theme.themeElements.fontScheme;
		else
			fontScheme = m_oLogicDocument.theme.themeElements.fontScheme;

		AscFormat.checkThemeFonts(AllFonts, fontScheme);
		
        for (var i in AllFonts)
            aPrepeareFonts.push(new AscFonts.CFont(i, 0, "", 0));
        //создаем список используемых картинок
        var oPastedImagesUnique = {};
        var aPastedImages = pptx_content_loader.End_UseFullUrl();
        for (var i = 0, length = aPastedImages.length; i < length; ++i) {
            var elem = aPastedImages[i];
            oPastedImagesUnique[elem.Url] = 1;
        }
        var aPrepeareImages = [];
        for (var i in oPastedImagesUnique)
            aPrepeareImages.push(i);
			
		if(!isCopyPaste)
		{
			this.Document.Content = this.oReadResult.DocumentContent;
			
			if(this.Document.Content.length == 0)
			{
				var oNewParagraph = new Paragraph(this.Document.DrawingDocument, this.Document);
				this.Document.Content.push(oNewParagraph);
			}
			
			this.Document.On_EndLoad();
		}
		
		//add comments
		var setting = this.oReadResult.setting;        
		var fInitCommentData = function(comment)
		{
			var oCommentObj = new CCommentData();
			if(null != comment.UserName)
				oCommentObj.m_sUserName = comment.UserName;
			if(null != comment.UserId)
				oCommentObj.m_sUserId = comment.UserId;
			if(null != comment.Date)
				oCommentObj.m_sTime = comment.Date;
			if(null != comment.m_sQuoteText)
				oCommentObj.m_sQuoteText = comment.m_sQuoteText;
			if(null != comment.Text)
				oCommentObj.m_sText = comment.Text;
			if(null != comment.Solved)
				oCommentObj.m_bSolved = comment.Solved;
			if(null != comment.Replies)
			{
				for(var  i = 0, length = comment.Replies.length; i < length; ++i)
					oCommentObj.Add_Reply(fInitCommentData(comment.Replies[i]));
			}
			return oCommentObj;
		};
		
		var oCommentsNewId = {};
		//меняем CDocumentContent на Document для возможности вставки комментариев в колонтитул и таблицу
		var isIntoShape = this.Document && this.Document.Parent && this.Document.Parent instanceof AscFormat.CShape ? true : false;
		var isIntoDocumentContent = this.Document instanceof CDocumentContent ? true : false;
		var document = this.Document && isIntoDocumentContent && !isIntoShape ? this.Document.LogicDocument : this.Document;
		for(var i in this.oReadResult.oComments)
		{
			if(this.oReadResult.oCommentsPlaces && this.oReadResult.oCommentsPlaces[i] && this.oReadResult.oCommentsPlaces[i].Start != null && this.oReadResult.oCommentsPlaces[i].End != null && document && document.Comments && isCopyPaste === true)
			{
				var oOldComment = this.oReadResult.oComments[i];
				
				var m_sQuoteText = this.oReadResult.oCommentsPlaces[i].QuoteText;
				if(m_sQuoteText)
					oOldComment.m_sQuoteText = m_sQuoteText;
				
				var oNewComment = new CComment(document.Comments, fInitCommentData(oOldComment))
				document.Comments.Add(oNewComment);
				oCommentsNewId[oOldComment.Id] = oNewComment;
			}
		}
		for(var commentIndex in this.oReadResult.oCommentsPlaces)
		{
			var item = this.oReadResult.oCommentsPlaces[commentIndex];
			var bToDelete = true;
			if(null != item.Start && null != item.End){
				var oCommentObj = oCommentsNewId[item.Start.Id];
				if(oCommentObj)
				{
					bToDelete = false;
					item.Start.oParaComment.Set_CommentId(oCommentObj.Get_Id());
					item.End.oParaComment.Set_CommentId(oCommentObj.Get_Id());
				}
			}
			if(bToDelete){
				if(null != item.Start && null != item.Start.oParent)
				{
					var oParent = item.Start.oParent;
					var oParaComment = item.Start.oParaComment;
					for (var i = OpenParStruct.prototype._GetContentLength(oParent) - 1; i >= 0; --i)
					{
					    if (oParaComment == OpenParStruct.prototype._GetFromContent(oParent, i)){
							OpenParStruct.prototype._removeFromContent(oParent, i, 1);
							break;
						}
					}
				}
				if(null != item.End && null != item.End.oParent)
				{
					var oParent = item.End.oParent;
					var oParaComment = item.End.oParaComment;
					for (var i = OpenParStruct.prototype._GetContentLength(oParent) - 1; i >= 0; --i)
					{
					    if (oParaComment == OpenParStruct.prototype._GetFromContent(oParent, i)){
							OpenParStruct.prototype._removeFromContent(oParent, i, 1);
							break;
						}
					}
				}
			}
		}
		//посылаем событие о добавлении комментариев
		if(api)
		{
			for(var i in oCommentsNewId)
			{
				var oNewComment = oCommentsNewId[i];
				api.sync_AddComment( oNewComment.Id, oNewComment.Data );
			}
		}
		//remove bookmarks without end
		for(var bookmarkIndex in this.oReadResult.bookmarksStarted)
		{
			var elem = this.oReadResult.bookmarksStarted[bookmarkIndex];
			for (var i = 0; i < OpenParStruct.prototype._GetContentLength(elem.parent); ++i)
			{
				if (elem.bookmark === OpenParStruct.prototype._GetFromContent(elem.parent, i)){
					OpenParStruct.prototype._removeFromContent(elem.parent, i, 1);
					break;
				}
			}
		}
		for (var i = 0, length = this.oReadResult.aTableCorrect.length; i < length; ++i) {
			var table = this.oReadResult.aTableCorrect[i];
			table.ReIndexing(0);
			
			//при вставке вложенных таблиц из документов в презентации и создании cDocumentContent не проставляется CStyles
			if(editor && !editor.isDocumentEditor && !table.Parent.Styles)
			{
				var oldStyles = table.Parent.Styles;
				table.Parent.Styles = this.Document.Styles;
				table.Correct_BadTable();
				table.Parent.Styles = oldStyles;
			}
			else
			{
				table.Correct_BadTable();
			}
		}
		//чтобы удалялся stream с бинарником
		pptx_content_loader.Clear(true);
        return { content: aContent, fonts: aPrepeareFonts, images: aPrepeareImages, bAddNewStyles: addNewStyles, aPastedImages: aPastedImages, bInBlock: bInBlock };
    }
}
function BinaryStyleTableReader(doc, oReadResult, stream)
{
    this.Document = doc;
	this.oReadResult = oReadResult;
    this.stream = stream;
    this.bcr = new Binary_CommonReader(this.stream);
    this.brPrr = new Binary_rPrReader(this.Document, this.oReadResult, this.stream);
    this.bpPrr = new Binary_pPrReader(this.Document, this.oReadResult, this.stream);
	this.btblPrr = new Binary_tblPrReader(this.Document, this.oReadResult, this.stream);
    this.Read = function()
    {
        var oThis = this;
        return this.bcr.ReadTable(function(t, l){
                return oThis.ReadStyleTableContent(t,l);
            });
    };
    this.ReadStyleTableContent = function(type, length)
    {
        var res = c_oSerConstants.ReadOk;
        if(c_oSer_st.Styles == type)
        {
            var oThis = this;
            res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadStyle(t,l);
                });
        }
        else if(c_oSer_st.DefpPr == type)
        {
            var ParaPr = new CParaPr();
            res = this.bpPrr.Read(length, ParaPr);
			this.oReadResult.DefpPr = ParaPr;
        }
        else if(c_oSer_st.DefrPr == type)
        {
            var TextPr = new CTextPr();
            res = this.brPrr.Read(length, TextPr, null);
			this.oReadResult.DefrPr = TextPr;
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.ReadStyle = function(type, length)
    {
        var res = c_oSerConstants.ReadOk;
        if(c_oSer_sts.Style == type)
        {
            var oThis = this;
            var oNewStyle = new CStyle(null, null, null, null);
            var oNewId = {};
            res = this.bcr.Read1(length, function(t, l){
                    return oThis.ReadStyleContent(t, l, oNewStyle, oNewId);
                });
            if(c_oSerConstants.ReadOk != res)
                return res;
            if(null != oNewId.id)
				this.oReadResult.styles[oNewId.id] = {style: oNewStyle, param: oNewId};
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.ReadStyleContent = function(type, length, style, oId)
    {
        var res = c_oSerConstants.ReadOk;
		var oThis = this;
        if(c_oSer_sts.Style_Name == type)
            style.Set_Name(this.stream.GetString2LE(length));
        else if(c_oSer_sts.Style_Id == type)
            oId.id = this.stream.GetString2LE(length);
        else if(c_oSer_sts.Style_Type == type)
		{
			var nStyleType = styletype_Paragraph;
			switch(this.stream.GetUChar())
			{
				case c_oSer_StyleType.Character: nStyleType = styletype_Character;break;
				case c_oSer_StyleType.Numbering: nStyleType = styletype_Numbering;break;
				case c_oSer_StyleType.Paragraph: nStyleType = styletype_Paragraph;break;
				case c_oSer_StyleType.Table: nStyleType = styletype_Table;break;
			}
            style.Set_Type(nStyleType);
		}
        else if(c_oSer_sts.Style_Default == type)
            oId.def = this.stream.GetBool();
        else if(c_oSer_sts.Style_BasedOn == type)
            style.Set_BasedOn(this.stream.GetString2LE(length));
        else if(c_oSer_sts.Style_Next == type)
            style.Set_Next(this.stream.GetString2LE(length));
		else if(c_oSer_sts.Style_Link == type)
			style.Set_Link(this.stream.GetString2LE(length));
        else if(c_oSer_sts.Style_qFormat == type)
            style.Set_QFormat(this.stream.GetBool());
        else if(c_oSer_sts.Style_uiPriority == type)
            style.Set_UiPriority(this.stream.GetULongLE());
        else if(c_oSer_sts.Style_hidden == type)
            style.Set_Hidden(this.stream.GetBool());
        else if(c_oSer_sts.Style_semiHidden == type)
            style.Set_SemiHidden(this.stream.GetBool());
        else if(c_oSer_sts.Style_unhideWhenUsed == type)
            style.Set_UnhideWhenUsed(this.stream.GetBool());
        else if(c_oSer_sts.Style_TextPr == type)
        {
			var oNewTextPr = new CTextPr();
            res = this.brPrr.Read(length, oNewTextPr, null);
			style.Set_TextPr(oNewTextPr);
        }
        else if(c_oSer_sts.Style_ParaPr == type)
        {
			var oNewParaPr = new CParaPr();
            res = this.bpPrr.Read(length, oNewParaPr, null);
			style.ParaPr = oNewParaPr;
			this.oReadResult.aPostOpenStyleNumCallbacks.push(function(){
				style.Set_ParaPr(oNewParaPr);
			});
        }
		else if(c_oSer_sts.Style_TablePr == type)
        {
			var oNewTablePr = new CTablePr();
            res = this.bcr.Read1(length, function(t, l){
                return oThis.btblPrr.Read_tblPr(t,l, oNewTablePr);
            });
			style.Set_TablePr(oNewTablePr);
		}
		else if(c_oSer_sts.Style_RowPr == type)
        {
			var oNewTableRowPr = new CTableRowPr();
            res = this.bcr.Read2(length, function(t, l){
                return oThis.btblPrr.Read_RowPr(t,l, oNewTableRowPr);
            });
			style.Set_TableRowPr(oNewTableRowPr);
		}
		else if(c_oSer_sts.Style_CellPr == type)
        {
			var oNewTableCellPr = new CTableCellPr();
            res = this.bcr.Read2(length, function(t, l){
                return oThis.btblPrr.Read_CellPr(t,l, oNewTableCellPr);
            });
            style.Set_TableCellPr(oNewTableCellPr);
		}
		else if(c_oSer_sts.Style_TblStylePr == type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadTblStylePr(t,l, style);
            });
		}
		else if(c_oSer_sts.Style_CustomStyle == type)
		{
			style.SetCustom(this.stream.GetBool());
		}
		// else if(c_oSer_sts.Style_Aliases == type)
		// {
		// 	style.Aliases = this.stream.GetString2LE(length);
		// }
		// else if(c_oSer_sts.Style_AutoRedefine == type)
		// {
		// 	style.AutoRedefine = this.stream.GetBool();
		// }
		// else if(c_oSer_sts.Style_Locked == type)
		// {
		// 	style.Locked = this.stream.GetBool();
		// }
		// else if(c_oSer_sts.Style_Personal == type)
		// {
		// 	style.Personal = this.stream.GetBool();
		// }
		// else if(c_oSer_sts.Style_PersonalCompose == type)
		// {
		// 	style.PersonalCompose = this.stream.GetBool();
		// }
		// else if(c_oSer_sts.Style_PersonalReply == type)
		// {
		// 	style.PersonalReply = this.stream.GetBool();
		// }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadTblStylePr = function(type, length, style)
    {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
        if(c_oSerProp_tblStylePrType.TblStylePr == type)
        {
			var oRes = {nType: null};
			var oNewTableStylePr = new CTableStylePr();
			res = this.bcr.Read1(length, function(t, l){
					return oThis.ReadTblStyleProperty(t, l, oNewTableStylePr, oRes);
				});
			if(null != oRes.nType)
			{
				switch(oRes.nType)
				{
					case ETblStyleOverrideType.tblstyleoverridetypeBand1Horz: style.TableBand1Horz = oNewTableStylePr;break;
					case ETblStyleOverrideType.tblstyleoverridetypeBand1Vert: style.TableBand1Vert = oNewTableStylePr;break;
					case ETblStyleOverrideType.tblstyleoverridetypeBand2Horz: style.TableBand2Horz = oNewTableStylePr;break;
					case ETblStyleOverrideType.tblstyleoverridetypeBand2Vert: style.TableBand2Vert = oNewTableStylePr;break;
					case ETblStyleOverrideType.tblstyleoverridetypeFirstCol: style.TableFirstCol = oNewTableStylePr;break;
					case ETblStyleOverrideType.tblstyleoverridetypeFirstRow: style.TableFirstRow = oNewTableStylePr;break;
					case ETblStyleOverrideType.tblstyleoverridetypeLastCol: style.TableLastCol = oNewTableStylePr;break;
					case ETblStyleOverrideType.tblstyleoverridetypeLastRow: style.TableLastRow = oNewTableStylePr;break;
					case ETblStyleOverrideType.tblstyleoverridetypeNeCell: style.TableTRCell = oNewTableStylePr;break;
					case ETblStyleOverrideType.tblstyleoverridetypeNwCell: style.TableTLCell = oNewTableStylePr;break;
					case ETblStyleOverrideType.tblstyleoverridetypeSeCell: style.TableBRCell = oNewTableStylePr;break;
					case ETblStyleOverrideType.tblstyleoverridetypeSwCell: style.TableBLCell = oNewTableStylePr;break;
					case ETblStyleOverrideType.tblstyleoverridetypeWholeTable: style.TableWholeTable = oNewTableStylePr;break;
				}
			}
			this.oReadResult.aPostOpenStyleNumCallbacks.push(function(){
				if(null != oRes.nType)
				{
					switch(oRes.nType)
					{
						case ETblStyleOverrideType.tblstyleoverridetypeBand1Horz: style.Set_TableBand1Horz(oNewTableStylePr);break;
						case ETblStyleOverrideType.tblstyleoverridetypeBand1Vert: style.Set_TableBand1Vert(oNewTableStylePr);break;
						case ETblStyleOverrideType.tblstyleoverridetypeBand2Horz: style.Set_TableBand2Horz(oNewTableStylePr);break;
						case ETblStyleOverrideType.tblstyleoverridetypeBand2Vert: style.Set_TableBand2Vert(oNewTableStylePr);break;
						case ETblStyleOverrideType.tblstyleoverridetypeFirstCol: style.Set_TableFirstCol(oNewTableStylePr);break;
						case ETblStyleOverrideType.tblstyleoverridetypeFirstRow: style.Set_TableFirstRow(oNewTableStylePr);break;
						case ETblStyleOverrideType.tblstyleoverridetypeLastCol: style.Set_TableLastCol(oNewTableStylePr);break;
						case ETblStyleOverrideType.tblstyleoverridetypeLastRow: style.Set_TableLastRow(oNewTableStylePr);break;
						case ETblStyleOverrideType.tblstyleoverridetypeNeCell: style.Set_TableTRCell(oNewTableStylePr);break;
						case ETblStyleOverrideType.tblstyleoverridetypeNwCell: style.Set_TableTLCell(oNewTableStylePr);break;
						case ETblStyleOverrideType.tblstyleoverridetypeSeCell: style.Set_TableBRCell(oNewTableStylePr);break;
						case ETblStyleOverrideType.tblstyleoverridetypeSwCell: style.Set_TableBLCell(oNewTableStylePr);break;
						case ETblStyleOverrideType.tblstyleoverridetypeWholeTable: style.Set_TableWholeTable(oNewTableStylePr);break;
					}
				}
			});
			if(c_oSerConstants.ReadOk != res)
				return res;
		}
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
	};
	this.ReadTblStyleProperty = function(type, length, oNewTableStylePr, oRes)
    {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
        if(c_oSerProp_tblStylePrType.Type == type)
			oRes.nType = this.stream.GetUChar();
		else if(c_oSerProp_tblStylePrType.RunPr == type)
		{
            res = this.brPrr.Read(length, oNewTableStylePr.TextPr, null);
		}
		else if(c_oSerProp_tblStylePrType.ParPr == type)
		{
            res = this.bpPrr.Read(length, oNewTableStylePr.ParaPr, null);
		}
		else if(c_oSerProp_tblStylePrType.TblPr == type)
		{
            res = this.bcr.Read1(length, function(t, l){
                return oThis.btblPrr.Read_tblPr(t,l, oNewTableStylePr.TablePr);
            });
		}
		else if(c_oSerProp_tblStylePrType.TrPr == type)
		{
            res = this.bcr.Read2(length, function(t, l){
                return oThis.btblPrr.Read_RowPr(t,l, oNewTableStylePr.TableRowPr);
            });
		}
		else if(c_oSerProp_tblStylePrType.TcPr == type)
		{
            res = this.bcr.Read2(length, function(t, l){
                return oThis.btblPrr.Read_CellPr(t,l, oNewTableStylePr.TableCellPr);
            });
		}
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
	};
};
function Binary_pPrReader(doc, oReadResult, stream)
{
    this.Document = doc;
	this.oReadResult = oReadResult;
    this.stream = stream;
    this.pPr;
    this.paragraph;
    this.bcr = new Binary_CommonReader(this.stream);
    this.brPrr = new Binary_rPrReader(this.Document, this.oReadResult, this.stream);
    this.Read = function(stLen, pPr, par)
    {
        this.pPr = pPr;
        this.paragraph = par;
        var oThis = this;
        return this.bcr.Read2(stLen, function(type, length){
                return oThis.ReadContent(type, length);
            });
    };
    this.ReadContent = function(type, length)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        var pPr = this.pPr;
        switch(type)
        {
            case c_oSerProp_pPrType.contextualSpacing:
				pPr.ContextualSpacing = this.stream.GetBool();
                break;
            case c_oSerProp_pPrType.Ind:
                res = this.bcr.Read2(length, function(t, l){
                        return oThis.ReadInd(t, l, pPr.Ind);
                    });
                break;
            case c_oSerProp_pPrType.Jc:
				pPr.Jc = this.stream.GetUChar();
                break;
            case c_oSerProp_pPrType.KeepLines:
				pPr.KeepLines = this.stream.GetBool();
                break;
            case c_oSerProp_pPrType.KeepNext:
				pPr.KeepNext = this.stream.GetBool();
                break;
            case c_oSerProp_pPrType.PageBreakBefore:
				pPr.PageBreakBefore = this.stream.GetBool();
                break;
            case c_oSerProp_pPrType.Spacing:
                res = this.bcr.Read2(length, function(t, l){
                        return oThis.ReadSpacing(t, l, pPr.Spacing);
                    });
                break;
            case c_oSerProp_pPrType.Shd:
                pPr.Shd = new CDocumentShd();
				var themeColor = {Auto: null, Color: null, Tint: null, Shade: null};
                res = this.bcr.Read2(length, function(t, l){
                        return oThis.bcr.ReadShd(t, l, pPr.Shd, themeColor);
                    });
				if(true == themeColor.Auto && null != pPr.Shd.Color)
					pPr.Shd.Color.Auto = true;//todo менять полностью цвет
				var unifill = CreateThemeUnifill(themeColor.Color, themeColor.Tint, themeColor.Shade);
				if(null != unifill)
					pPr.Shd.Unifill = unifill;
				else if (null != pPr.Shd.Color && !pPr.Shd.Color.Auto)
				    pPr.Shd.Unifill = AscFormat.CreteSolidFillRGB(pPr.Shd.Color.r, pPr.Shd.Color.g, pPr.Shd.Color.b);
                break;
            case c_oSerProp_pPrType.WidowControl:
				pPr.WidowControl = this.stream.GetBool();
                break;
            case c_oSerProp_pPrType.Tab:
                pPr.Tabs = new CParaTabs();
                res = this.bcr.Read2(length, function(t, l){
                        return oThis.ReadTabs(t, l, pPr.Tabs);
                    });
                break;
            case c_oSerProp_pPrType.ParaStyle:
                var ParaStyle = this.stream.GetString2LE(length);
				this.oReadResult.paraStyles.push({pPr: pPr, style: ParaStyle});
                break;
            case c_oSerProp_pPrType.numPr:
                var numPr = new CNumPr();
				numPr.NumId = undefined;
				numPr.Lvl = undefined;
                res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadNumPr(t, l, numPr);
                });
                if(null != numPr.NumId || null != numPr.Lvl)
                {
					if(null != numPr.NumId)
						this.oReadResult.paraNumPrs.push(numPr);
					pPr.NumPr = numPr;
                }
                break;
            case c_oSerProp_pPrType.pBdr:
                res = this.bcr.Read1(length, function(t, l){
                        return oThis.ReadBorders(t, l, pPr.Brd);
                    });
                break;
            case c_oSerProp_pPrType.pPr_rPr:
                if(null != this.paragraph)
				{
                    var EndRun = this.paragraph.Get_ParaEndRun();
                    var rPr = this.paragraph.TextPr.Value;
                    res = this.brPrr.Read(length, rPr, EndRun);
                    var trackRevision = this.brPrr.trackRevision;
                    if (trackRevision) {
                        if(trackRevision.del) {
                            EndRun.Set_ReviewTypeWithInfo(reviewtype_Remove, trackRevision.del);
                        } else if(trackRevision.ins) {
                            EndRun.Set_ReviewTypeWithInfo(reviewtype_Add, trackRevision.ins);
                        } 
                    }
                    this.paragraph.TextPr.Apply_TextPr(rPr);
				}
				else
					res = c_oSerConstants.ReadUnknown;
                break;
			case c_oSerProp_pPrType.FramePr:
				pPr.FramePr = new CFramePr();
                res = this.bcr.Read2(length, function(t, l){
                        return oThis.ReadFramePr(t, l, pPr.FramePr);
                    });
                break;
			case c_oSerProp_pPrType.SectPr:
				if(null != this.paragraph && this.Document instanceof CDocument)
				{
					var oNewSectionPr = new CSectionPr(this.Document);
					var oAdditional = {EvenAndOddHeaders: null};
					res = this.bcr.Read1(length, function(t, l){
							return oThis.Read_SecPr(t, l, oNewSectionPr, oAdditional);
						});
					this.paragraph.Set_SectionPr(oNewSectionPr);
				}
				else
					res = c_oSerConstants.ReadUnknown;
                break;
            case c_oSerProp_pPrType.numPr_Ins:
                res = c_oSerConstants.ReadUnknown;//todo
                break;
            case c_oSerProp_pPrType.pPrChange:
                if(null != this.paragraph && this.Document instanceof CDocument) {
                    var pPrChange = new CParaPr();
                    var reviewInfo = new CReviewInfo();
                    var bpPrr = new Binary_pPrReader(this.Document, this.oReadResult, this.stream);
                    res = this.bcr.Read1(length, function(t, l){
                        return ReadTrackRevision(t, l, oThis.stream, reviewInfo, {bpPrr: bpPrr, pPr: pPrChange});
                    });
                    this.paragraph.Set_PrChange(pPrChange, reviewInfo);
                } else {
                    res = c_oSerConstants.ReadUnknown;
                }
                break;
			case c_oSerProp_pPrType.outlineLvl:
				pPr.OutlineLvl = this.stream.GetLongLE();
				break;
            default:
                res = c_oSerConstants.ReadUnknown;
                break;
        }
        return res;
    };
    this.ReadBorder = function(type, length, Border)
    {
        var res = c_oSerConstants.ReadOk;
		var oThis = this;
        if( c_oSerBorderType.Color === type )
        {
            Border.Color = this.bcr.ReadColor();
        }
        else if( c_oSerBorderType.Space === type )
        {
            Border.Space = this.bcr.ReadDouble();
        }
        else if( c_oSerBorderType.Size === type )
        {
            Border.Size = this.bcr.ReadDouble();
        }
        else if( c_oSerBorderType.Value === type )
        {
            Border.Value = this.stream.GetUChar();
        }
		else if( c_oSerBorderType.ColorTheme === type )
        {
			var themeColor = {Auto: null, Color: null, Tint: null, Shade: null};
			res = this.bcr.Read2(length, function(t, l){
				return oThis.bcr.ReadColorTheme(t, l, themeColor);
			});
			if(true == themeColor.Auto)
				Border.Color = new CDocumentColor(0, 0, 0, true);
			var unifill = CreateThemeUnifill(themeColor.Color, themeColor.Tint, themeColor.Shade);
			if(null != unifill)
				Border.Unifill = unifill;
			else if (null != Border.Color && !Border.Color.Auto)
			    Border.Unifill = AscFormat.CreteSolidFillRGB(Border.Color.r, Border.Color.g, Border.Color.b);
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.NormalizeBorder = function(border)
    {
        if(null == border.Color)
            border.Color = new CDocumentColor(0, 0, 0, true);
        else
            border.Color = new CDocumentColor(border.Color.r, border.Color.g, border.Color.b, border.Color.Auto);
        if(null == border.Space)
            border.Space = 0;
        if(null == border.Size)
            border.Size = 0.5 * g_dKoef_pt_to_mm;
        if(null == border.Value)
            border.Value = border_None;
        return border;
    };
    this.ReadBorders = function(type, length, Borders)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        var oNewBorber = new CDocumentBorder();
        if( c_oSerBordersType.left === type )
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadBorder(t, l, oNewBorber);
            });
            if(null != oNewBorber.Value)
                Borders.Left = this.NormalizeBorder(oNewBorber);
        }
        else if( c_oSerBordersType.top === type )
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadBorder(t, l, oNewBorber);
            });
            if(null != oNewBorber.Value)
                Borders.Top = this.NormalizeBorder(oNewBorber);
        }
        else if( c_oSerBordersType.right === type )
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadBorder(t, l, oNewBorber);
            });
            if(null != oNewBorber.Value)
                Borders.Right = this.NormalizeBorder(oNewBorber);
        }
        else if( c_oSerBordersType.bottom === type )
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadBorder(t, l, oNewBorber);
            });
            if(null != oNewBorber.Value)
                Borders.Bottom = this.NormalizeBorder(oNewBorber);
        }
        else if( c_oSerBordersType.insideV === type )
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadBorder(t, l, oNewBorber);
            });
            if(null != oNewBorber.Value)
                Borders.InsideV = this.NormalizeBorder(oNewBorber);
        }
        else if( c_oSerBordersType.insideH === type )
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadBorder(t, l, oNewBorber);
            });
            if(null != oNewBorber.Value)
                Borders.InsideH = this.NormalizeBorder(oNewBorber);
            
        }
        else if( c_oSerBordersType.between === type )
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadBorder(t, l, oNewBorber);
            });
            if(null != oNewBorber.Value)
                Borders.Between = this.NormalizeBorder(oNewBorber);
            
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.ReadInd = function(type, length, Ind)
    {
        var res = c_oSerConstants.ReadOk;
        switch(type)
        {
            case c_oSerProp_pPrType.Ind_Left: Ind.Left = this.bcr.ReadDouble();break;
            case c_oSerProp_pPrType.Ind_Right: Ind.Right = this.bcr.ReadDouble();break;
            case c_oSerProp_pPrType.Ind_FirstLine: Ind.FirstLine = this.bcr.ReadDouble();break;
            default:
                res = c_oSerConstants.ReadUnknown;
                break;
        }
        return res;
    };
    this.ReadSpacing = function(type, length, Spacing)
    {
        var res = c_oSerConstants.ReadOk;
        switch(type)
        {
            case c_oSerProp_pPrType.Spacing_Line: Spacing.Line = this.bcr.ReadDouble();break;
            case c_oSerProp_pPrType.Spacing_LineRule: Spacing.LineRule = this.stream.GetUChar();break;
            case c_oSerProp_pPrType.Spacing_Before: Spacing.Before = this.bcr.ReadDouble();break;
            case c_oSerProp_pPrType.Spacing_After: Spacing.After = this.bcr.ReadDouble();break;
            case c_oSerProp_pPrType.Spacing_BeforeAuto: Spacing.BeforeAutoSpacing = (this.stream.GetUChar() != 0);break;
            case c_oSerProp_pPrType.Spacing_AfterAuto: Spacing.AfterAutoSpacing = (this.stream.GetUChar() != 0);break;
            default:
                res = c_oSerConstants.ReadUnknown;
                break;
        }
        return res;
    };
    this.ReadTabs = function(type, length, Tabs)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if(c_oSerProp_pPrType.Tab_Item == type)
        {
            var oNewTab = new CParaTab();
            res = this.bcr.Read2(length, function(t, l){
                        return oThis.ReadTabItem(t, l, oNewTab);
                    });
            if(null != oNewTab.Pos && null != oNewTab.Value)
            {
                Tabs.Add(oNewTab);
            }
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.ReadTabItem = function(type, length, tab)
    {
        var res = c_oSerConstants.ReadOk;
        if(c_oSerProp_pPrType.Tab_Item_Val === type)
		{
			switch(this.stream.GetUChar())
			{
				case AscCommon.g_tabtype_right : tab.Value = tab_Right;break;
				case AscCommon.g_tabtype_center : tab.Value = tab_Center;break;
				case AscCommon.g_tabtype_clear : tab.Value = tab_Clear;break;
				default : tab.Value = tab_Left;
			}
		}
        else if(c_oSerProp_pPrType.Tab_Item_Pos === type)
            tab.Pos = this.bcr.ReadDouble();
		else if(c_oSerProp_pPrType.Tab_Item_Leader === type)
			tab.Leader = this.stream.GetUChar();
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.ReadNumPr = function(type, length, numPr)
    {
        var res = c_oSerConstants.ReadOk;
        if(c_oSerProp_pPrType.numPr_lvl == type)
            numPr.Lvl = this.stream.GetULongLE();
        else if(c_oSerProp_pPrType.numPr_id == type)
            numPr.NumId = this.stream.GetULongLE();
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadFramePr = function(type, length, oFramePr)
    {
        var res = c_oSerConstants.ReadOk;
        if(c_oSer_FramePrType.DropCap == type)
            oFramePr.DropCap = this.stream.GetUChar();
		else if(c_oSer_FramePrType.H == type)
            oFramePr.H = g_dKoef_twips_to_mm * this.stream.GetULongLE();
		else if(c_oSer_FramePrType.HAnchor == type)
            oFramePr.HAnchor = this.stream.GetUChar();
		else if(c_oSer_FramePrType.HRule == type)
            oFramePr.HRule = this.stream.GetUChar();
		else if(c_oSer_FramePrType.HSpace == type)
            oFramePr.HSpace = g_dKoef_twips_to_mm * this.stream.GetULongLE();
		else if(c_oSer_FramePrType.Lines == type)
            oFramePr.Lines = this.stream.GetULongLE();
		else if(c_oSer_FramePrType.VAnchor == type)
            oFramePr.VAnchor = this.stream.GetUChar();
		else if(c_oSer_FramePrType.VSpace == type)
            oFramePr.VSpace = g_dKoef_twips_to_mm * this.stream.GetULongLE();
		else if(c_oSer_FramePrType.W == type)
            oFramePr.W = g_dKoef_twips_to_mm * this.stream.GetULongLE();
		else if(c_oSer_FramePrType.Wrap == type){
			var nEditorWrap = wrap_None;
			switch(this.stream.GetUChar()){
				case EWrap.wrapAround: nEditorWrap = wrap_Around;break;
				case EWrap.wrapAuto: nEditorWrap = wrap_Auto;break;
				case EWrap.wrapNone: nEditorWrap = wrap_None;break;
				case EWrap.wrapNotBeside: nEditorWrap = wrap_NotBeside;break;
				case EWrap.wrapThrough: nEditorWrap = wrap_Through;break;
				case EWrap.wrapTight: nEditorWrap = wrap_Tight;break;
			}
			oFramePr.Wrap = nEditorWrap;
		}
		else if(c_oSer_FramePrType.X == type) {
			var xTw = this.stream.GetULongLE();
			if (-4 === xTw) {
				oFramePr.XAlign = c_oAscXAlign.Center;
			} else {
				oFramePr.X = g_dKoef_twips_to_mm * xTw;
			}
		} else if(c_oSer_FramePrType.XAlign == type)
            oFramePr.XAlign = this.stream.GetUChar();
		else if(c_oSer_FramePrType.Y == type) {
			var yTw = this.stream.GetULongLE();
			if (-4 === yTw) {
				oFramePr.YAlign = c_oAscYAlign.Top;
			} else {
				oFramePr.Y = g_dKoef_twips_to_mm * yTw;
			}
		} else if(c_oSer_FramePrType.YAlign == type)
            oFramePr.YAlign = this.stream.GetUChar();
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.Read_SecPr = function(type, length, oSectPr, oAdditional)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerProp_secPrType.pgSz === type )
        {
            var oSize = {W: null, H: null, Orientation: null};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.Read_pgSz(t, l, oSize);
            });
            if(null != oSize.W && null != oSize.H)
            {
                oSectPr.Set_PageSize(oSize.W, oSize.H);
            }
            if(null != oSize.Orientation)
                oSectPr.Set_Orientation(oSize.Orientation, false);
        }
        else if( c_oSerProp_secPrType.pgMar === type )
        {
			var oMar = {L: null, T: null, R: null, B: null};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.Read_pgMar(t, l, oSectPr, oMar, oAdditional);
            });
			if(null != oMar.L && null != oMar.T && null != oMar.R && null != oMar.B)
				oSectPr.Set_PageMargins(oMar.L, oMar.T, oMar.R, oMar.B);
        }
        else if( c_oSerProp_secPrType.setting === type )
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.Read_setting(t, l, oSectPr, oAdditional);
            });
        }
		else if( c_oSerProp_secPrType.headers === type )
        {
			res = this.bcr.Read1(length, function(t, l){
                return oThis.Read_pgHdrFtr(t, l, oSectPr, oThis.oReadResult.headers, true);
            });
        }
		else if( c_oSerProp_secPrType.footers === type )
        {
			res = this.bcr.Read1(length, function(t, l){
                return oThis.Read_pgHdrFtr(t, l, oSectPr, oThis.oReadResult.footers, false);
            });
        }
		else if( c_oSerProp_secPrType.pageNumType === type )
        {
			res = this.bcr.Read1(length, function(t, l){
                return oThis.Read_pageNumType(t, l, oSectPr);
            });
        }
        else if( c_oSerProp_secPrType.sectPrChange === type )
            res = c_oSerConstants.ReadUnknown;//todo
        else if( c_oSerProp_secPrType.cols === type ) {
            //todo clear;
            res = this.bcr.Read1(length, function(t, l){
                return oThis.Read_cols(t, l, oSectPr);
            });
        }
		else if( c_oSerProp_secPrType.pgBorders === type ) {
			res = this.bcr.Read1(length, function(t, l){
				return oThis.Read_pgBorders(t, l, oSectPr.Borders);
			});
		}
		else if( c_oSerProp_secPrType.footnotePr === type ) {
			var props = {fmt: null, restart: null, start: null, pos: null};
			res = this.bcr.Read1(length, function(t, l) {
				return oThis.ReadFootnotePr(t, l, props);
			});
			if (null != props.fmt) {
				oSectPr.SetFootnoteNumFormat(props.fmt);
			}
			if (null != props.restart) {
				oSectPr.SetFootnoteNumRestart(props.restart);
			}
			if (null != props.start) {
				oSectPr.SetFootnoteNumStart(props.start);
			}
			if (null != props.pos) {
				oSectPr.SetFootnotePos(props.pos);
			}
		}
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadFootnotePr = function(type, length, props) {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerNotes.PrFmt === type) {
			res = this.bcr.Read1(length, function(t, l){
				return oThis.ReadNumFmt(t, l, props);
			});
		} else if (c_oSerNotes.PrRestart === type) {
			props.restart = this.stream.GetByte();
		} else if (c_oSerNotes.PrStart === type) {
			props.start = this.stream.GetULongLE();
		} else if (c_oSerNotes.PrFntPos === type) {
			props.pos = this.stream.GetByte();
		} else if (c_oSerNotes.PrRef === type) {
			this.oReadResult.footnoteRefs.push(this.stream.GetULongLE());
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	};
	this.ReadNumFmt = function(type, length, props) {
		var res = c_oSerConstants.ReadOk;
		if (c_oSerNumTypes.NumFmtVal === type) {
			switch (this.stream.GetByte()) {
				case 48: props.fmt = Asc.c_oAscNumberingFormat.None; break;
				case 5: props.fmt = Asc.c_oAscNumberingFormat.Bullet; break;
				case 13: props.fmt = Asc.c_oAscNumberingFormat.Decimal; break;
				case 47: props.fmt = Asc.c_oAscNumberingFormat.LowerRoman; break;
				case 61: props.fmt = Asc.c_oAscNumberingFormat.UpperRoman; break;
				case 46: props.fmt = Asc.c_oAscNumberingFormat.LowerLetter; break;
				case 60: props.fmt = Asc.c_oAscNumberingFormat.UpperLetter; break;
				case 21: props.fmt = Asc.c_oAscNumberingFormat.DecimalZero; break;
				default: props.fmt = Asc.c_oAscNumberingFormat.Decimal; break;
			}
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	};
    this.Read_setting = function(type, length, oSectPr, oAdditional)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerProp_secPrSettingsType.titlePg === type )
        {
            oSectPr.Set_TitlePage(this.stream.GetBool());
        }
        else if( c_oSerProp_secPrSettingsType.EvenAndOddHeaders === type )
        {
            oAdditional.EvenAndOddHeaders = this.stream.GetBool();
        }
		else if( c_oSerProp_secPrSettingsType.SectionType === type && typeof c_oAscSectionBreakType != "undefined" )
        {
			var nEditorType = null;
			switch(this.stream.GetByte())
			{
				case ESectionMark.sectionmarkContinuous: nEditorType = c_oAscSectionBreakType.Continuous;break;
				case ESectionMark.sectionmarkEvenPage: nEditorType = c_oAscSectionBreakType.EvenPage;break;
				case ESectionMark.sectionmarkNextColumn: nEditorType = c_oAscSectionBreakType.Column;break;
				case ESectionMark.sectionmarkNextPage: nEditorType = c_oAscSectionBreakType.NextPage;break;
				case ESectionMark.sectionmarkOddPage: nEditorType = c_oAscSectionBreakType.OddPage;break;
			}
			if(null != nEditorType)
				oSectPr.Set_Type(nEditorType);
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }
    this.Read_pgSz = function(type, length, oSize)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSer_pgSzType.Orientation === type )
        {
            oSize.Orientation = this.stream.GetUChar();
        }
        else if( c_oSer_pgSzType.W === type )
        {
            oSize.W = this.bcr.ReadDouble();
        }
        else if( c_oSer_pgSzType.H === type )
        {
            oSize.H = this.bcr.ReadDouble();
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }
    this.Read_pgMar = function(type, length, oSectPr, oMar, oAdditional)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSer_pgMarType.Left === type )
        {
            oMar.L = this.bcr.ReadDouble();
        }
        else if( c_oSer_pgMarType.Top === type )
        {
            oMar.T = this.bcr.ReadDouble();
        }
        else if( c_oSer_pgMarType.Right === type )
        {
            oMar.R = this.bcr.ReadDouble();
        }
        else if( c_oSer_pgMarType.Bottom === type )
        {
            oMar.B = this.bcr.ReadDouble();
        }
		else if( c_oSer_pgMarType.Header === type )
        {
			oSectPr.Set_PageMargins_Header(this.bcr.ReadDouble());
        }
		else if( c_oSer_pgMarType.Footer === type )
        {
			oSectPr.Set_PageMargins_Footer(this.bcr.ReadDouble());
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }
	this.Read_pgHdrFtr = function(type, length, oSectPr, aHdrFtr, bHeader)
    {
		var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerProp_secPrType.hdrftrelem === type )
        {
			var nIndex = this.stream.GetULongLE();
			if(nIndex >= 0 && nIndex < aHdrFtr.length)
			{
				var item = aHdrFtr[nIndex];
				if(bHeader){
					switch(item.type)
					{
						case c_oSerHdrFtrTypes.HdrFtr_First: oSectPr.Set_Header_First(item.elem);break;
						case c_oSerHdrFtrTypes.HdrFtr_Even: oSectPr.Set_Header_Even(item.elem);break;
						case c_oSerHdrFtrTypes.HdrFtr_Odd: oSectPr.Set_Header_Default(item.elem);break;
					}
				}
				else{
					switch(item.type)
					{
						case c_oSerHdrFtrTypes.HdrFtr_First: oSectPr.Set_Footer_First(item.elem);break;
						case c_oSerHdrFtrTypes.HdrFtr_Even: oSectPr.Set_Footer_Even(item.elem);break;
						case c_oSerHdrFtrTypes.HdrFtr_Odd: oSectPr.Set_Footer_Default(item.elem);break;
					}
				}
			}
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
	}
	this.Read_pageNumType = function(type, length, oSectPr)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerProp_secPrPageNumType.start === type )
        {
            oSectPr.Set_PageNum_Start(this.stream.GetULongLE());
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }
    this.Read_cols = function(type, length, oSectPr)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if (c_oSerProp_Columns.EqualWidth === type) {
            oSectPr.Set_Columns_EqualWidth(this.stream.GetBool());
        } else if (c_oSerProp_Columns.Num === type) {
            oSectPr.Set_Columns_Num(this.stream.GetULongLE());
        } else if (c_oSerProp_Columns.Sep === type) {
            oSectPr.Set_Columns_Sep(this.stream.GetBool());
        } else if (c_oSerProp_Columns.Space === type) {
            oSectPr.Set_Columns_Space(g_dKoef_twips_to_mm * this.stream.GetULongLE());
        } else if (c_oSerProp_Columns.Column === type) {
            var col = new CSectionColumn();
            res = this.bcr.Read1(length, function(t, l){
                return oThis.Read_col(t, l, col);
            });
            oSectPr.Set_Columns_Col(oSectPr.Columns.Cols.length, col.W, col.Space);
        } else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }
    this.Read_col = function(type, length, col)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if (c_oSerProp_Columns.ColumnSpace === type) {
            col.Space = g_dKoef_twips_to_mm * this.stream.GetULongLE();
        } else if (c_oSerProp_Columns.ColumnW === type) {
            col.W = g_dKoef_twips_to_mm * this.stream.GetULongLE();
        } else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }
	this.Read_pgBorders = function(type, length, pgBorders)
	{
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerPageBorders.Display === type) {
			pgBorders.Display = this.stream.GetUChar();
		} else if (c_oSerPageBorders.OffsetFrom === type) {
			pgBorders.OffsetFrom = this.stream.GetUChar();
		} else if (c_oSerPageBorders.ZOrder === type) {
			pgBorders.ZOrder = this.stream.GetUChar();
		} else if (c_oSerPageBorders.Bottom === type) {
			var oNewBorber = new CDocumentBorder();
			res = this.bcr.Read2(length, function(t, l){
				return oThis.Read_pgBorder(t, l, oNewBorber);
			});
			if(null != oNewBorber.Value)
				pgBorders.Bottom = this.NormalizeBorder(oNewBorber);
		} else if (c_oSerPageBorders.Left === type) {
			var oNewBorber = new CDocumentBorder();
			res = this.bcr.Read2(length, function(t, l){
				return oThis.Read_pgBorder(t, l, oNewBorber);
			});
			if(null != oNewBorber.Value)
				pgBorders.Left = this.NormalizeBorder(oNewBorber);
		} else if (c_oSerPageBorders.Right === type) {
			var oNewBorber = new CDocumentBorder();
			res = this.bcr.Read2(length, function(t, l){
				return oThis.Read_pgBorder(t, l, oNewBorber);
			});
			if(null != oNewBorber.Value)
				pgBorders.Right = this.NormalizeBorder(oNewBorber);
		} else if (c_oSerPageBorders.Top === type) {
			var oNewBorber = new CDocumentBorder();
			res = this.bcr.Read2(length, function(t, l){
				return oThis.Read_pgBorder(t, l, oNewBorber);
			});
			if(null != oNewBorber.Value)
				pgBorders.Top = this.NormalizeBorder(oNewBorber);
		} else
			res = c_oSerConstants.ReadUnknown;
		return res;
	}
	this.Read_pgBorder = function(type, length, Border)
	{
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if( c_oSerPageBorders.Color === type )
		{
			Border.Color = this.bcr.ReadColor();
		}
		else if( c_oSerPageBorders.Space === type )
		{
			Border.Space = this.stream.GetLongLE() * g_dKoef_pt_to_mm;
		}
		else if( c_oSerPageBorders.Sz === type )
		{
			Border.Size = this.stream.GetLongLE() * g_dKoef_pt_to_mm / 8;
		}
		else if( c_oSerPageBorders.Val === type )
		{
			var val = this.stream.GetLongLE();
			if (-1 == val || 0 == val) {
				Border.Value = border_None;
			} else {
				Border.Value = border_Single;
			}
		}
		else if( c_oSerPageBorders.ColorTheme === type )
		{
			var themeColor = {Auto: null, Color: null, Tint: null, Shade: null};
			res = this.bcr.Read2(length, function(t, l){
				return oThis.bcr.ReadColorTheme(t, l, themeColor);
			});
			if(true == themeColor.Auto)
				Border.Color = new CDocumentColor(0, 0, 0, true);
			var unifill = CreateThemeUnifill(themeColor.Color, themeColor.Tint, themeColor.Shade);
			if(null != unifill)
				Border.Unifill = unifill;
			else if (null != Border.Color && !Border.Color.Auto)
				Border.Unifill = AscFormat.CreteSolidFillRGB(Border.Color.r, Border.Color.g, Border.Color.b);
		}
		else
			res = c_oSerConstants.ReadUnknown;
		return res;
	};
};
function Binary_rPrReader(doc, oReadResult, stream)
{
    this.Document = doc;
	this.oReadResult = oReadResult;
    this.stream = stream;
    this.rPr;
    this.trackRevision = null;
    this.bcr = new Binary_CommonReader(this.stream);
    this.Read = function(stLen, rPr, run)
    {
        this.rPr = rPr;
        this.trackRevision = null;
        var oThis = this;
        var res = c_oSerConstants.ReadOk;
        res = this.bcr.Read2(stLen, function(type, length){
                return oThis.ReadContent(type, length, run);
            });
        return res;
    };
    this.ReadContent = function(type, length, run)
    {
        var res = c_oSerConstants.ReadOk;
		var oThis = this;
        var rPr = this.rPr;
        switch(type)
        {
            case c_oSerProp_rPrType.Bold:
                rPr.Bold = (this.stream.GetUChar() != 0);
                break;
            case c_oSerProp_rPrType.Italic:
                rPr.Italic = (this.stream.GetUChar() != 0);
                break;
            case c_oSerProp_rPrType.Underline:
                rPr.Underline = (this.stream.GetUChar() != 0);
                break;
            case c_oSerProp_rPrType.Strikeout:
                rPr.Strikeout = (this.stream.GetUChar() != 0);
                break;
            case c_oSerProp_rPrType.FontAscii:
                if ( undefined === rPr.RFonts )
                    rPr.RFonts = {};
                rPr.RFonts.Ascii = { Name : this.stream.GetString2LE(length), Index : -1 };
                break;
            case c_oSerProp_rPrType.FontHAnsi:
                if ( undefined === rPr.RFonts )
                    rPr.RFonts = {};
                rPr.RFonts.HAnsi = { Name : this.stream.GetString2LE(length), Index : -1 };
                break;
            case c_oSerProp_rPrType.FontAE:
                if ( undefined === rPr.RFonts )
                    rPr.RFonts = {};
                rPr.RFonts.EastAsia = { Name : this.stream.GetString2LE(length), Index : -1 };
                break;
            case c_oSerProp_rPrType.FontCS:
                if ( undefined === rPr.RFonts )
                    rPr.RFonts = {};
                rPr.RFonts.CS = { Name : this.stream.GetString2LE(length), Index : -1 };
                break;
            case c_oSerProp_rPrType.FontSize:
                rPr.FontSize = this.stream.GetULongLE() / 2;
                break;
            case c_oSerProp_rPrType.Color:
                rPr.Color = this.bcr.ReadColor();
                break;
            case c_oSerProp_rPrType.VertAlign:
                rPr.VertAlign = this.stream.GetUChar();
                break;
            case c_oSerProp_rPrType.HighLight:
                rPr.HighLight = this.bcr.ReadColor();
                break;
            case c_oSerProp_rPrType.HighLightTyped:
                var nHighLightTyped = this.stream.GetUChar();
                if(nHighLightTyped == AscCommon.c_oSer_ColorType.Auto)
                    rPr.HighLight = highlight_None;
                break;
			case c_oSerProp_rPrType.RStyle:
				var RunStyle = this.stream.GetString2LE(length);
				this.oReadResult.runStyles.push({pPr: rPr, style: RunStyle, run: run});
                break;
			case c_oSerProp_rPrType.Spacing:
				rPr.Spacing = this.bcr.ReadDouble();
                break;
			case c_oSerProp_rPrType.DStrikeout:
				rPr.DStrikeout = (this.stream.GetUChar() != 0);
                break;
			case c_oSerProp_rPrType.Caps:
				rPr.Caps = (this.stream.GetUChar() != 0);
                break;
			case c_oSerProp_rPrType.SmallCaps:
				rPr.SmallCaps = (this.stream.GetUChar() != 0);
                break;
			case c_oSerProp_rPrType.Position:
				rPr.Position = this.bcr.ReadDouble();
                break;
			case c_oSerProp_rPrType.FontHint:
				var nHint;
				switch(this.stream.GetUChar())
				{
					case EHint.hintCs: nHint = fonthint_CS;break;
					case EHint.hintEastAsia: nHint = fonthint_EastAsia;break;
					default : nHint = fonthint_Default;break;
				}
				rPr.RFonts.Hint = nHint;
                break;
			case c_oSerProp_rPrType.BoldCs:
				rPr.BoldCS = this.stream.GetBool();
                break;
			case c_oSerProp_rPrType.ItalicCs:
				rPr.ItalicCS = this.stream.GetBool();
                break;
			case c_oSerProp_rPrType.FontSizeCs:
				rPr.FontSizeCS = this.stream.GetULongLE() / 2;
                break;
			case c_oSerProp_rPrType.Cs:
				rPr.CS = this.stream.GetBool();
                break;
			case c_oSerProp_rPrType.Rtl:
				rPr.RTL = this.stream.GetBool();
                break;
			case c_oSerProp_rPrType.Lang:
				if(null == rPr.Lang)
					rPr.Lang = new CLang();
				var sLang = this.stream.GetString2LE(length);
				var nLcid = g_oLcidNameToIdMap[sLang];
				if(null != nLcid)
					rPr.Lang.Val = nLcid;
                break;
			case c_oSerProp_rPrType.LangBidi:
				if(null == rPr.Lang)
					rPr.Lang = new CLang();
				var sLang = this.stream.GetString2LE(length);
				var nLcid = g_oLcidNameToIdMap[sLang];
				if(null != nLcid)
					rPr.Lang.Bidi = nLcid;
                break;
			case c_oSerProp_rPrType.LangEA:
				if(null == rPr.Lang)
					rPr.Lang = new CLang();
				var sLang = this.stream.GetString2LE(length);
				var nLcid = g_oLcidNameToIdMap[sLang];
				if(null != nLcid)
					rPr.Lang.EastAsia = nLcid;
                break;
			case c_oSerProp_rPrType.ColorTheme:
                var themeColor = {Auto: null, Color: null, Tint: null, Shade: null};
				res = this.bcr.Read2(length, function(t, l){
					return oThis.bcr.ReadColorTheme(t, l, themeColor);
				});
				if(true == themeColor.Auto)
					rPr.Color = new CDocumentColor(0, 0, 0, true);
				var unifill = CreateThemeUnifill(themeColor.Color, themeColor.Tint, themeColor.Shade);
				if(null != unifill)
					rPr.Unifill = unifill;
				else if (null != rPr.Color && !rPr.Color.Auto)
				    rPr.Unifill = AscFormat.CreteSolidFillRGB(rPr.Color.r, rPr.Color.g, rPr.Color.b);
				break;
            case c_oSerProp_rPrType.Shd:
                rPr.Shd = new CDocumentShd();
                var themeColor = { Auto: null, Color: null, Tint: null, Shade: null };
                res = this.bcr.Read2(length, function (t, l) {
                    return oThis.bcr.ReadShd(t, l, rPr.Shd, themeColor);
                });
                if (true == themeColor.Auto && null != rPr.Shd.Color)
                    rPr.Shd.Color.Auto = true;//todo менять полностью цвет
                var unifill = CreateThemeUnifill(themeColor.Color, themeColor.Tint, themeColor.Shade);
                if (null != unifill)
                    rPr.Shd.Unifill = unifill;
                else if (null != rPr.Shd.Color && !rPr.Shd.Color.Auto)
                    rPr.Shd.Unifill = AscFormat.CreteSolidFillRGB(rPr.Shd.Color.r, rPr.Shd.Color.g, rPr.Shd.Color.b);
                break;
			case c_oSerProp_rPrType.Vanish:
                rPr.Vanish = this.stream.GetBool();
                break;
			case c_oSerProp_rPrType.TextOutline:
				if(length > 0){
					var TextOutline = pptx_content_loader.ReadShapeProperty(this.stream, 0);
					if(null != TextOutline)
						rPr.TextOutline = TextOutline;
				}
				else
					res = c_oSerConstants.ReadUnknown;
				break;
			case c_oSerProp_rPrType.TextFill:
				if(length > 0){
					var TextFill = pptx_content_loader.ReadShapeProperty(this.stream, 1);
					if(null != TextFill){
                        rPr.TextFill = TextFill;
                        if(null != TextFill.transparent){
                            TextFill.transparent = 255 - TextFill.transparent;
                        }
                    }
				}
				else
					res = c_oSerConstants.ReadUnknown;
				break;
            case c_oSerProp_rPrType.Del:
                this.trackRevision = {del: new CReviewInfo()};
                res = this.bcr.Read1(length, function(t, l){
                    return ReadTrackRevision(t, l, oThis.stream, oThis.trackRevision.del, null);
                });
				break;
            case c_oSerProp_rPrType.Ins:
                this.trackRevision = {ins: new CReviewInfo()};
                res = this.bcr.Read1(length, function(t, l){
                    return ReadTrackRevision(t, l, oThis.stream, oThis.trackRevision.ins, null);
                });
				break;
			case c_oSerProp_rPrType.MoveFrom:
				this.trackRevision = {del: new CReviewInfo()};
				res = this.bcr.Read1(length, function(t, l){
					return ReadTrackRevision(t, l, oThis.stream, oThis.trackRevision.del, null);
				});
				break;
			case c_oSerProp_rPrType.MoveTo:
				this.trackRevision = {ins: new CReviewInfo()};
				res = this.bcr.Read1(length, function(t, l){
					return ReadTrackRevision(t, l, oThis.stream, oThis.trackRevision.ins, null);
				});
				break;
            case c_oSerProp_rPrType.rPrChange:
                var rPrChange = new CTextPr();
                var reviewInfo = new CReviewInfo();
                var brPrr = new Binary_rPrReader(this.Document, this.oReadResult, this.stream);
                res = this.bcr.Read1(length, function(t, l){
                    return ReadTrackRevision(t, l, oThis.stream, reviewInfo, {brPrr: brPrr, rPr: rPrChange});
                });
                if (run) {
                    run.Set_PrChange(rPrChange, reviewInfo);
                }
				break;
            default:
                res = c_oSerConstants.ReadUnknown;
                break;
        }
        return res;
    }
};
function Binary_tblPrReader(doc, oReadResult, stream)
{
	this.Document = doc;
	this.oReadResult = oReadResult;
    this.stream = stream;
	this.bcr = new Binary_CommonReader(this.stream);
    this.bpPrr = new Binary_pPrReader(this.Document, this.oReadResult, this.stream);
}
Binary_tblPrReader.prototype = 
{
	Read_tblPr: function(type, length, Pr, table)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if ( c_oSerProp_tblPrType.RowBandSize === type ) {
			Pr.TableStyleRowBandSize = this.stream.GetLongLE();
		} else if ( c_oSerProp_tblPrType.ColBandSize === type ) {
			Pr.TableStyleColBandSize = this.stream.GetLongLE();
		} else if ( c_oSerProp_tblPrType.Jc === type )
        {
            Pr.Jc = this.stream.GetUChar();
        }
        else if( c_oSerProp_tblPrType.TableInd === type )
        {
            Pr.TableInd = this.bcr.ReadDouble();
        }
        else if( c_oSerProp_tblPrType.TableW === type )
        {
            var oW = {Type: null, W: null, WDocx: null};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadW(t, l, oW);
            });
			if(null == Pr.TableW)
                Pr.TableW = new CTableMeasurement(tblwidth_Auto, 0);
			this.ParseW(oW, Pr.TableW);
        }
        else if( c_oSerProp_tblPrType.TableCellMar === type )
        {
            if(null == Pr.TableCellMar)
                Pr.TableCellMar = this.GetNewMargin();
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadCellMargins(t, l, Pr.TableCellMar);
            });
        }
        else if( c_oSerProp_tblPrType.TableBorders === type )
        {
            if(null == Pr.TableBorders)
                Pr.TableBorders =
                {
                    Bottom  : undefined,
                    Left    : undefined,
                    Right   : undefined,
                    Top     : undefined,
                    InsideH : undefined,
                    InsideV : undefined
                };
            res = this.bcr.Read1(length, function(t, l){
                return oThis.bpPrr.ReadBorders(t, l, Pr.TableBorders);
            });
        }
        else if( c_oSerProp_tblPrType.Shd === type )
        {
            if(null == Pr.Shd)
                Pr.Shd = new CDocumentShd();
			var themeColor = {Auto: null, Color: null, Tint: null, Shade: null};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.bcr.ReadShd(t, l, Pr.Shd, themeColor);
            });
			if(true == themeColor.Auto && null != Pr.Shd.Color)
				Pr.Shd.Color.Auto = true;//todo менять полностью цвет
			var unifill = CreateThemeUnifill(themeColor.Color, themeColor.Tint, themeColor.Shade);
			if(null != unifill)
				Pr.Shd.Unifill = unifill;
			else if (null != Pr.Shd.Color && !Pr.Shd.Color.Auto)
			    Pr.Shd.Unifill = AscFormat.CreteSolidFillRGB(Pr.Shd.Color.r, Pr.Shd.Color.g, Pr.Shd.Color.b);
        }
		else if( c_oSerProp_tblPrType.Layout === type )
		{
			var nLayout = this.stream.GetUChar();
			switch(nLayout)
			{
				case ETblLayoutType.tbllayouttypeAutofit: Pr.TableLayout = tbllayout_AutoFit;break;
				case ETblLayoutType.tbllayouttypeFixed: Pr.TableLayout = tbllayout_Fixed;break;
			}
		}
		else if( c_oSerProp_tblPrType.TableCellSpacing === type )
		{
			Pr.TableCellSpacing = this.bcr.ReadDouble();
		}
		else if( c_oSerProp_tblPrType.tblCaption === type )
		{
			Pr.TableCaption = this.stream.GetString2LE(length);
		}
		else if( c_oSerProp_tblPrType.tblDescription === type )
		{
			Pr.TableDescription = this.stream.GetString2LE(length);
		} 
		else if(null != table)
		{
			if( c_oSerProp_tblPrType.tblpPr === type )
			{
				table.Set_Inline(false);
				var oAdditionalPr = {PageNum: null, X: null, Y: null, Paddings: null};
				res = this.bcr.Read2(length, function(t, l){
					return oThis.Read_tblpPr(t, l, oAdditionalPr);
				});
				if(null != oAdditionalPr.X)
					table.Set_PositionH(Asc.c_oAscHAnchor.Page, false, oAdditionalPr.X);
				if(null != oAdditionalPr.Y)
					table.Set_PositionV(Asc.c_oAscVAnchor.Page, false, oAdditionalPr.Y);
				if(null != oAdditionalPr.Paddings)
				{
					var Paddings = oAdditionalPr.Paddings;
					table.Set_Distance(Paddings.L, Paddings.T, Paddings.R, Paddings.B);
				}
			}
			else if( c_oSerProp_tblPrType.tblpPr2 === type )
			{
				table.Set_Inline(false);
				var oAdditionalPr = {HRelativeFrom: null, HAlign: null, HValue: null, VRelativeFrom: null, VAlign: null, VValue: null, Distance: null};
				res = this.bcr.Read2(length, function(t, l){
					return oThis.Read_tblpPr2(t, l, oAdditionalPr);
				});
				if(null != oAdditionalPr.HRelativeFrom && null != oAdditionalPr.HAlign && null != oAdditionalPr.HValue)
					table.Set_PositionH(oAdditionalPr.HRelativeFrom, oAdditionalPr.HAlign, oAdditionalPr.HValue);
				if(null != oAdditionalPr.VRelativeFrom && null != oAdditionalPr.VAlign && null != oAdditionalPr.VValue)
					table.Set_PositionV(oAdditionalPr.VRelativeFrom, oAdditionalPr.VAlign, oAdditionalPr.VValue);
				if(null != oAdditionalPr.Distance)
				{
					var Distance = oAdditionalPr.Distance;
					table.Set_Distance(Distance.L, Distance.T, Distance.R, Distance.B);
				}
			}
			else if( c_oSerProp_tblPrType.Look === type )
			{
				var nLook = this.stream.GetULongLE();
				var bFC = 0 != (nLook & 0x0080);
				var bFR = 0 != (nLook & 0x0020);
				var bLC = 0 != (nLook & 0x0100);
				var bLR = 0 != (nLook & 0x0040);
				var bBH = 0 != (nLook & 0x0200);
				var bBV = 0 != (nLook & 0x0400);
				table.Set_TableLook(new CTableLook(bFC, bFR, bLC, bLR, !bBH, !bBV));
			}
			else if( c_oSerProp_tblPrType.Style === type )
				this.oReadResult.tableStyles.push({pPr: table, style: this.stream.GetString2LE(length)});
            else if( c_oSerProp_tblPrType.tblPrChange === type )
				res = c_oSerConstants.ReadUnknown;//todo
			else
				res = c_oSerConstants.ReadUnknown;
		}
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    },
    BordersNull: function(Borders)
    {
        Borders.Left    = new CDocumentBorder();
        Borders.Top     = new CDocumentBorder();
        Borders.Right   = new CDocumentBorder();
        Borders.Bottom  = new CDocumentBorder();
        Borders.InsideV = new CDocumentBorder();
        Borders.InsideH = new CDocumentBorder();
    },
    ReadW: function(type, length, Width)
    {
        var res = c_oSerConstants.ReadOk;
        if( c_oSerWidthType.Type === type )
        {
            Width.Type = this.stream.GetUChar();
        }
        else if( c_oSerWidthType.W === type )
        {
            Width.W = this.bcr.ReadDouble();
        }
		else if( c_oSerWidthType.WDocx === type )
        {
            Width.WDocx = this.stream.GetULongLE();
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    },
	ParseW: function(input, output)
    {
		if(input.Type)
			output.Type = input.Type;
		if(input.W)
			output.W = input.W;
		if(input.WDocx)
		{
			if(tblwidth_Mm == input.Type)
				output.W = g_dKoef_twips_to_mm * input.WDocx;
			else if(tblwidth_Pct == input.Type)
				output.W = 2 * input.WDocx / 100;
			else
				output.W = input.WDocx;
		}
	},
    ReadCellMargins: function(type, length, Margins)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerMarginsType.left === type )
        {
            var oW = {Type: null, W: null, WDocx: null};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadW(t, l, oW);
            });
			if(null == Margins.Left)
                Margins.Left = new CTableMeasurement(tblwidth_Auto, 0);
			this.ParseW(oW, Margins.Left);
        }
        else if( c_oSerMarginsType.top === type )
        {
			var oW = {Type: null, W: null, WDocx: null};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadW(t, l, oW);
            });
			if(null == Margins.Top)
                Margins.Top = new CTableMeasurement(tblwidth_Auto, 0);
			this.ParseW(oW, Margins.Top);
        }
        else if( c_oSerMarginsType.right === type )
        {
			var oW = {Type: null, W: null, WDocx: null};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadW(t, l, oW);
            });
			if(null == Margins.Right)
                Margins.Right = new CTableMeasurement(tblwidth_Auto, 0);
			this.ParseW(oW, Margins.Right);
        }
        else if( c_oSerMarginsType.bottom === type )
        {
			var oW = {Type: null, W: null, WDocx: null};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadW(t, l, oW);
            });
			if(null == Margins.Bottom)
                Margins.Bottom = new CTableMeasurement(tblwidth_Auto, 0);
			this.ParseW(oW, Margins.Bottom);
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    },
    Read_tblpPr: function(type, length, oAdditionalPr)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSer_tblpPrType.Page === type )
            oAdditionalPr.PageNum = this.stream.GetULongLE();
        else if( c_oSer_tblpPrType.X === type )
            oAdditionalPr.X = this.bcr.ReadDouble();
        else if( c_oSer_tblpPrType.Y === type )
            oAdditionalPr.Y = this.bcr.ReadDouble();
        else if( c_oSer_tblpPrType.Paddings === type )
        {
            if(null == oAdditionalPr.Paddings)
                oAdditionalPr.Paddings = {L : 0, T : 0, R : 0, B : 0};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadPaddings2(t, l, oAdditionalPr.Paddings);
            });
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    },
	Read_tblpPr2: function(type, length, oAdditionalPr)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSer_tblpPrType2.HorzAnchor === type )
            oAdditionalPr.HRelativeFrom = this.stream.GetUChar();
		else if( c_oSer_tblpPrType2.TblpX === type )
		{
			oAdditionalPr.HAlign = false;
            oAdditionalPr.HValue = this.bcr.ReadDouble();
		}
		else if( c_oSer_tblpPrType2.TblpXSpec === type )
		{
			oAdditionalPr.HAlign = true;
            oAdditionalPr.HValue = this.stream.GetUChar();
		}
		else if( c_oSer_tblpPrType2.VertAnchor === type )
            oAdditionalPr.VRelativeFrom = this.stream.GetUChar();
		else if( c_oSer_tblpPrType2.TblpY === type )
		{
			oAdditionalPr.VAlign = false;
            oAdditionalPr.VValue = this.bcr.ReadDouble();
		}
		else if( c_oSer_tblpPrType2.TblpYSpec === type )
		{
			oAdditionalPr.VAlign = true;
            oAdditionalPr.VValue = this.stream.GetUChar();
		}
		else if( c_oSer_tblpPrType2.Paddings === type )
		{
			oAdditionalPr.Distance = {L: 0, T: 0, R: 0, B:0};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadPaddings2(t, l, oAdditionalPr.Distance);
            });
		}
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    },
	Read_RowPr: function(type, length, Pr)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerProp_rowPrType.CantSplit === type )
        {
            Pr.CantSplit = (this.stream.GetUChar() != 0);
        }
        else if( c_oSerProp_rowPrType.After === type )
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadAfter(t, l, Pr);
            });
        }
        else if( c_oSerProp_rowPrType.Before === type )
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadBefore(t, l, Pr);
            });
        }
        else if( c_oSerProp_rowPrType.Jc === type )
        {
            Pr.Jc = this.stream.GetUChar();
        }
        else if( c_oSerProp_rowPrType.TableCellSpacing === type )
        {
            Pr.TableCellSpacing = this.bcr.ReadDouble();
        }
        else if( c_oSerProp_rowPrType.Height === type )
        {
            if(null == Pr.Height)
                Pr.Height = new CTableRowHeight(0,Asc.linerule_Auto);
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadHeight(t, l, Pr.Height);
            });
        }
        else if( c_oSerProp_rowPrType.TableHeader === type )
        {
            Pr.TableHeader = (this.stream.GetUChar() != 0);
        }
        else if( c_oSerProp_rowPrType.Del === type ){
            res = c_oSerConstants.ReadUnknown;//todo
        }
        else if( c_oSerProp_rowPrType.Ins === type ){
            res = c_oSerConstants.ReadUnknown;//todo
        }
        else if( c_oSerProp_rowPrType.trPrChange === type ){
            res = c_oSerConstants.ReadUnknown;//todo
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    },
    ReadAfter: function(type, length, After)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerProp_rowPrType.GridAfter === type )
        {
            After.GridAfter = this.stream.GetULongLE();
        }
        else if( c_oSerProp_rowPrType.WAfter === type )
        {
			var oW = {Type: null, W: null, WDocx: null};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadW(t, l, oW);
            });
			if(null == After.WAfter)
                After.WAfter = new CTableMeasurement(tblwidth_Auto, 0);
			this.ParseW(oW, After.WAfter);
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    },
    ReadBefore: function(type, length, Before)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerProp_rowPrType.GridBefore === type )
        {
            Before.GridBefore = this.stream.GetULongLE();
        }
        else if( c_oSerProp_rowPrType.WBefore === type )
        {
			var oW = {Type: null, W: null, WDocx: null};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadW(t, l, oW);
            });
			if(null == Before.WBefore)
                Before.WBefore = new CTableMeasurement(tblwidth_Auto, 0);
			this.ParseW(oW, Before.WBefore);
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    },
    ReadHeight: function(type, length, Height)
    {
        var res = c_oSerConstants.ReadOk;
        if( c_oSerProp_rowPrType.Height_Rule === type )
        {
            Height.HRule = this.stream.GetUChar();
        }
        else if( c_oSerProp_rowPrType.Height_Value === type )
        {
            Height.Value = this.bcr.ReadDouble();
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    },
    Read_CellPr : function(type, length, Pr)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerProp_cellPrType.GridSpan === type )
        {
            Pr.GridSpan = this.stream.GetULongLE();
        }
        else if( c_oSerProp_cellPrType.Shd === type )
        {
            if(null == Pr.Shd)
                Pr.Shd = new CDocumentShd();
            var oNewShd = {Value: undefined, Color: undefined, Unifill: undefined};
			var themeColor = {Auto: null, Color: null, Tint: null, Shade: null};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.bcr.ReadShd(t, l, oNewShd, themeColor);
            });
            var unifill = CreateThemeUnifill(themeColor.Color, themeColor.Tint, themeColor.Shade);
            if (true == themeColor.Auto) {
                if (!oNewShd.Color) {
                    oNewShd.Color = new CDocumentColor(255, 255, 255);
                }
                oNewShd.Color.Auto = true;
            }
			if(null != unifill)
				oNewShd.Unifill = unifill;
			else if (null != oNewShd.Color && !oNewShd.Color.Auto)
			    oNewShd.Unifill = AscFormat.CreteSolidFillRGB(oNewShd.Color.r, oNewShd.Color.g, oNewShd.Color.b);
            //если есть themeColor или Color, то Value по умолчанию ShdClear(Тарифы_на_комплексное_обслуживание_клиен.docx)
            if (undefined == oNewShd.Value && oNewShd.Unifill) {
                oNewShd.Value = Asc.c_oAscShdClear;
            }
            Pr.Shd.Set_FromObject(oNewShd);
        }
        else if( c_oSerProp_cellPrType.TableCellBorders === type )
        {
            if(null == Pr.TableCellBorders)
                Pr.TableCellBorders =
                {
                    Bottom : undefined,
                    Left   : undefined,
                    Right  : undefined,
                    Top    : undefined
                };
            res = this.bcr.Read1(length, function(t, l){
                return oThis.bpPrr.ReadBorders(t, l, Pr.TableCellBorders);
            });
        }
        else if( c_oSerProp_cellPrType.CellMar === type )
        {
			if(null == Pr.TableCellMar)
                Pr.TableCellMar = this.GetNewMargin();
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadCellMargins(t, l, Pr.TableCellMar);
            });
        }
        else if( c_oSerProp_cellPrType.TableCellW === type )
        {
			var oW = {Type: null, W: null, WDocx: null};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadW(t, l, oW);
            });
			if(null == Pr.TableCellW)
                Pr.TableCellW = new CTableMeasurement(tblwidth_Auto, 0);
			this.ParseW(oW, Pr.TableCellW);
        }
        else if( c_oSerProp_cellPrType.VAlign === type )
        {
            Pr.VAlign = this.stream.GetUChar();
        }
        else if( c_oSerProp_cellPrType.VMerge === type )
        {
            Pr.VMerge = this.stream.GetUChar();
        }
		else if( c_oSerProp_cellPrType.HMerge === type )
		{
			Pr.HMerge = this.stream.GetUChar();
		}
        else if( c_oSerProp_cellPrType.CellDel === type ){
            res = c_oSerConstants.ReadUnknown;//todo
        }
        else if( c_oSerProp_cellPrType.CellIns === type ){
            res = c_oSerConstants.ReadUnknown;//todo
        }
        else if( c_oSerProp_cellPrType.CellMerge === type ){
            res = c_oSerConstants.ReadUnknown;//todo
        }
        else if( c_oSerProp_cellPrType.tcPrChange === type ){
            res = c_oSerConstants.ReadUnknown;//todo
        }
        else if( c_oSerProp_cellPrType.textDirection === type ){
            Pr.TextDirection = this.stream.GetUChar();
        }
        else if( c_oSerProp_cellPrType.noWrap === type ){
            Pr.NoWrap = (this.stream.GetUChar() != 0);
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    },
	GetNewMargin: function()
    {
        return { Left : new CTableMeasurement(tblwidth_Auto, 0), Top: new CTableMeasurement(tblwidth_Auto, 0), Right: new CTableMeasurement(tblwidth_Auto, 0), Bottom: new CTableMeasurement(tblwidth_Auto, 0)};
    },
	ReadPaddings: function(type, length, paddings)
    {
        var res = c_oSerConstants.ReadOk;
        if (c_oSerPaddingType.left === type)
            paddings.Left = this.bcr.ReadDouble();
        else if (c_oSerPaddingType.top === type)
            paddings.Top = this.bcr.ReadDouble();
        else if (c_oSerPaddingType.right === type)
            paddings.Right = this.bcr.ReadDouble();
        else if (c_oSerPaddingType.bottom === type)
            paddings.Bottom = this.bcr.ReadDouble();
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    },
	ReadPaddings2: function(type, length, paddings)
    {
        var res = c_oSerConstants.ReadOk;
        if (c_oSerPaddingType.left === type)
            paddings.L = this.bcr.ReadDouble();
        else if (c_oSerPaddingType.top === type)
            paddings.T = this.bcr.ReadDouble();
        else if (c_oSerPaddingType.right === type)
            paddings.R = this.bcr.ReadDouble();
        else if (c_oSerPaddingType.bottom === type)
            paddings.B = this.bcr.ReadDouble();
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }
}
function Binary_NumberingTableReader(doc, oReadResult, stream)
{
    this.Document = doc;
	this.oReadResult = oReadResult;
    this.stream = stream;
	this.m_oANums = {};
    this.bcr = new Binary_CommonReader(this.stream);
    this.brPrr = new Binary_rPrReader(this.Document, this.oReadResult, this.stream);
    this.bpPrr = new Binary_pPrReader(this.Document, this.oReadResult, this.stream);
    this.Read = function()
    {
        var oThis = this;
        var res = this.bcr.ReadTable(function(t, l){
                return oThis.ReadNumberingContent(t,l);
            });
        return res;
    };
    this.ReadNumberingContent = function(type, length)
    {
        var oThis = this;
        var res = c_oSerConstants.ReadOk;
        if ( c_oSerNumTypes.AbstractNums === type )
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadAbstractNums(t, l);
            });
        }
        else if ( c_oSerNumTypes.Nums === type )
        {
			var tmpNum = {NumId: null, Num: null};
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadNums(t, l, tmpNum);
            });
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    },
    this.ReadNums = function(type, length, tmpNum)
    {
        var oThis = this;
        var res = c_oSerConstants.ReadOk;
        if ( c_oSerNumTypes.Num === type )
        {
			tmpNum.NumId = null;
			tmpNum.Num = new CNum(this.oReadResult.logicDocument.GetNumbering());
			res = this.bcr.Read2(length, function(t, l) {
				return oThis.ReadNum(t, l, tmpNum);
			});
			if (null != tmpNum.NumId) {
				this.oReadResult.numToNumClass[tmpNum.NumId] = tmpNum.Num;
			}
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    },
    this.ReadNum = function(type, length, tmpNum)
    {
        var oThis = this;
        var res = c_oSerConstants.ReadOk;
        if ( c_oSerNumTypes.Num_ANumId === type )
        {
			var ANum = this.m_oANums[this.stream.GetULongLE()];
			if (ANum) {
				tmpNum.Num.SetAbstractNumId(ANum.GetId());
				this.oReadResult.numToANumClass[ANum.GetId()] = ANum;
			}
        }
        else if ( c_oSerNumTypes.Num_NumId === type )
        {
			tmpNum.NumId = this.stream.GetULongLE();
        }
		else if ( c_oSerNumTypes.Num_LvlOverride === type )
		{
			var tmpOverride = {nLvl: undefined, StartOverride: undefined, Lvl: undefined};
			res = this.bcr.Read1(length, function(t, l){
				return oThis.ReadLvlOverride(t, l, tmpOverride);
			});
			tmpNum.Num.SetLvlOverride(tmpOverride.Lvl, tmpOverride.nLvl, tmpOverride.StartOverride);
		}
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    },
	this.ReadLvlOverride = function(type, length, lvlOverride) {
		var oThis = this;
		var res = c_oSerConstants.ReadOk;
		if (c_oSerNumTypes.ILvl === type) {
			lvlOverride.nLvl = this.stream.GetULongLE();
		} else if (c_oSerNumTypes.StartOverride === type) {
			lvlOverride.StartOverride = this.stream.GetULongLE();
		} else if (c_oSerNumTypes.Lvl === type) {
			lvlOverride.Lvl = new CNumberingLvl();
			var tmp = {nLevelNum: 0};
			res = this.bcr.Read2(length, function(t, l){
				return oThis.ReadLevel(t, l, lvlOverride.Lvl, tmp);
			});
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	},
    this.ReadAbstractNums = function(type, length)
    {
        var oThis = this;
        var res = c_oSerConstants.ReadOk;
        if ( c_oSerNumTypes.AbstractNum === type )
        {
            var oNewAbstractNum = new CAbstractNum();
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadAbstractNum(t, l, oNewAbstractNum);
            });
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    },
    this.ReadAbstractNum = function(type, length, oNewNum)
    {
        var oThis = this;
        var res = c_oSerConstants.ReadOk;
        if ( c_oSerNumTypes.AbstractNum_Lvls === type )
        {
            var nLevelNum = 0;
            res = this.bcr.Read1(length, function(t, l){
				return oThis.ReadLevels(t, l, nLevelNum++, oNewNum);
            });
        }
		else if ( c_oSerNumTypes.NumStyleLink === type ) {
			this.oReadResult.numStyleLinks.push({pPr: oNewNum, style: this.stream.GetString2LE(length)});
		}
		else if ( c_oSerNumTypes.StyleLink === type ) {
			this.oReadResult.styleLinks.push({pPr: oNewNum, style: this.stream.GetString2LE(length)});
		}
        else if ( c_oSerNumTypes.AbstractNum_Id === type )
        {
			this.m_oANums[this.stream.GetULongLE()] = oNewNum;
            //oNewNum.Id = this.stream.GetULongLE();
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }
    this.ReadLevels = function(type, length, nLevelNum, oNewNum)
    {
        var oThis = this;
        var res = c_oSerConstants.ReadOk;
        if ( c_oSerNumTypes.Lvl === type )
        {
			if(nLevelNum < oNewNum.Lvl.length)
			{
				var oOldLvl = oNewNum.Lvl[nLevelNum];
				var oNewLvl = oOldLvl.Copy();
				//сбрасываем свойства
				oNewLvl.ParaPr = new CParaPr();
				oNewLvl.TextPr = new CTextPr();
				var tmp = {nLevelNum: nLevelNum};
				res = this.bcr.Read2(length, function(t, l){
					return oThis.ReadLevel(t, l, oNewLvl, tmp);
				});
				oNewNum.Lvl[tmp.nLevelNum] = oNewLvl;
				this.oReadResult.aPostOpenStyleNumCallbacks.push(function(){
					oNewNum.SetLvl(tmp.nLevelNum, oNewLvl);
				});
			}
			else
				res = c_oSerConstants.ReadUnknown;
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }
    this.ReadLevel = function(type, length, oNewLvl, tmp)
    {
        var oThis = this;
        var res = c_oSerConstants.ReadOk;
        if ( c_oSerNumTypes.lvl_Format === type )
        {
            oNewLvl.Format = this.stream.GetULongLE();
        }
        else if ( c_oSerNumTypes.lvl_Jc === type )
        {
            oNewLvl.Jc = this.stream.GetUChar();
        }
        else if ( c_oSerNumTypes.lvl_LvlText === type )
        {
            oNewLvl.LvlText = [];
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadLevelText(t, l, oNewLvl.LvlText);
            });
        }
        else if ( c_oSerNumTypes.lvl_Restart === type )
        {
            oNewLvl.Restart = this.stream.GetLongLE();
        }
        else if ( c_oSerNumTypes.lvl_Start === type )
        {
            oNewLvl.Start = this.stream.GetULongLE();
        }
        else if ( c_oSerNumTypes.lvl_Suff === type )
        {
            oNewLvl.Suff = this.stream.GetUChar();
        }
		else if ( c_oSerNumTypes.lvl_PStyle === type )
        {
			this.oReadResult.lvlStyles.push({pPr: oNewLvl, style: this.stream.GetString2LE(length)});
        }
        else if ( c_oSerNumTypes.lvl_ParaPr === type )
        {
            res = this.bpPrr.Read(length, oNewLvl.ParaPr, null);
        }
        else if ( c_oSerNumTypes.lvl_TextPr === type )
        {
            res = this.brPrr.Read(length, oNewLvl.TextPr, null);
        }
		else if ( c_oSerNumTypes.ILvl === type )
		{
			tmp.nLevelNum = this.stream.GetULongLE();
		}
		// else if ( c_oSerNumTypes.Tentative === type )
		// {
		// 	oNewLvl.Tentative = this.stream.GetBool();
		// }
		// else if ( c_oSerNumTypes.Tplc === type )
		// {
		// 	oNewLvl.Tplc = AscFonts.FT_Common.IntToUInt(this.stream.GetULongLE());
		// }
		// else if ( c_oSerNumTypes.IsLgl === type )
		// {
		// 	oNewLvl.IsLgl = this.stream.GetBool();
		// }
		else if ( c_oSerNumTypes.LvlLegacy === type )
		{
			oNewLvl.Legacy = new CNumberingLvlLegacy();
			res = this.bcr.Read1(length, function(t, l){
				return oThis.ReadLvlLegacy(t, l, oNewLvl.Legacy);
			});
		}
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }
	this.ReadLvlLegacy = function(type, length, lvlLegacy) {
		var res = c_oSerConstants.ReadOk;
		if ( c_oSerNumTypes.Legacy === type ) {
			lvlLegacy.Legacy = this.stream.GetBool();
		} else if ( c_oSerNumTypes.LegacyIndent === type ) {
			lvlLegacy.Indent = this.stream.GetULongLE();
		} else if ( c_oSerNumTypes.LegacySpace === type ) {
			lvlLegacy.Space = AscFonts.FT_Common.IntToUInt(this.stream.GetULongLE());
		} else
			res = c_oSerConstants.ReadUnknown;
		return res;
	}
    this.ReadLevelText = function(type, length, aNewText)
    {
        var oThis = this;
        var res = c_oSerConstants.ReadOk;
        if ( c_oSerNumTypes.lvl_LvlTextItem === type )
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadLevelTextItem(t, l, aNewText);
            });
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }
    this.ReadLevelTextItem = function(type, length, aNewText)
    {
        var oThis = this;
        var res = c_oSerConstants.ReadOk;
        if ( c_oSerNumTypes.lvl_LvlTextItemText === type )
        {
            var oNewTextItem = new CNumberingLvlTextString( this.stream.GetString2LE(length) );
            aNewText.push(oNewTextItem);
        }
        else if ( c_oSerNumTypes.lvl_LvlTextItemNum === type )
        {
            var oNewTextItem = new CNumberingLvlTextNum( this.stream.GetUChar() );
            aNewText.push(oNewTextItem);
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }
};
function Binary_HdrFtrTableReader(doc, oReadResult, openParams, stream)
{
    this.Document = doc;
	this.oReadResult = oReadResult;
	this.openParams = openParams;
    this.stream = stream;
    this.bcr = new Binary_CommonReader(this.stream);
    this.bdtr = new Binary_DocumentTableReader(this.Document, this.oReadResult, this.openParams, this.stream, null, this.oReadResult.oCommentsPlaces);
    this.Read = function()
    {
        var oThis = this;
        var res = this.bcr.ReadTable(function(t, l){
                return oThis.ReadHdrFtrContent(t,l);
            });
        return res;
    };
    this.ReadHdrFtrContent = function(type, length)
    {
        var oThis = this;
        var res = c_oSerConstants.ReadOk;
        if ( c_oSerHdrFtrTypes.Header === type || c_oSerHdrFtrTypes.Footer === type )
        {
            var oHdrFtrContainer;
            var nHdrFtrType;
            if(c_oSerHdrFtrTypes.Header === type)
            {
                oHdrFtrContainer = this.oReadResult.headers;
                nHdrFtrType = AscCommon.hdrftr_Header;
            }
            else
            {
                oHdrFtrContainer = this.oReadResult.footers;
                nHdrFtrType = AscCommon.hdrftr_Footer;
            }
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadHdrFtrFEO(t, l, oHdrFtrContainer, nHdrFtrType);
            });
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.ReadHdrFtrFEO = function(type, length, oHdrFtrContainer, nHdrFtrType)
    {
        var oThis = this;
        var res = c_oSerConstants.ReadOk;
        if ( c_oSerHdrFtrTypes.HdrFtr_First === type || c_oSerHdrFtrTypes.HdrFtr_Even === type || c_oSerHdrFtrTypes.HdrFtr_Odd === type )
        {
            var hdrftr;
			if(AscCommon.hdrftr_Header == nHdrFtrType)
				hdrftr = new CHeaderFooter(this.Document.HdrFtr, this.Document, this.Document.DrawingDocument, nHdrFtrType );
			else
				hdrftr = new CHeaderFooter(this.Document.HdrFtr, this.Document, this.Document.DrawingDocument, nHdrFtrType );
            this.bdtr.Document = hdrftr.Content;
            var oNewItem = {Content: null};
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadHdrFtrItem(t, l, oNewItem);
            });
            if(null != oNewItem.Content)
            {
                hdrftr.Content.Content = oNewItem.Content;
				oHdrFtrContainer.push({type: type, elem: hdrftr});
            }
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.ReadHdrFtrItem = function(type, length, oNewItem)
    {
        var oThis = this;
        var res = c_oSerConstants.ReadOk;
        if ( c_oSerHdrFtrTypes.HdrFtr_Content === type )
        {
			oNewItem.Content = [];
			oThis.bdtr.Read(length, oNewItem.Content);
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
};
function Binary_DocumentTableReader(doc, oReadResult, openParams, stream, curFootnote, oComments)
{
    this.Document = doc;
	this.oReadResult = oReadResult;
	this.oReadResult.bdtr = this;
	this.openParams = openParams;
    this.stream = stream;
    this.bcr = new Binary_CommonReader(this.stream);
	this.boMathr = new Binary_oMathReader(this.stream, this.oReadResult, curFootnote);
    this.brPrr = new Binary_rPrReader(this.Document, this.oReadResult, this.stream);
    this.bpPrr = new Binary_pPrReader(this.Document, this.oReadResult, this.stream);
	this.btblPrr = new Binary_tblPrReader(this.Document, this.oReadResult, this.stream);
    this.lastPar = null;
    this.oComments = oComments;
    this.aFields = [];
	this.nCurCommentsCount = 0;
	this.oCurComments = {};//вспомогательный массив  для заполнения QuotedText
	this.curFootnote = curFootnote;
    this.Reset = function()
    {
        this.lastPar = null;
    }
    this.ReadAsTable = function(OpenContent)
    {
        this.Reset();
		
        var oThis = this;
        return this.bcr.ReadTable(function(t, l){
                return oThis.ReadDocumentContent(t, l, OpenContent);
            });
    };
	this.Read = function(length, OpenContent)
    {
        this.Reset();
		
        var oThis = this;
        return this.bcr.Read1(length, function(t, l){
                return oThis.ReadDocumentContent(t, l, OpenContent);
            });
    };
    this.ReadDocumentContent = function(type, length, Content)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if ( c_oSerParType.Par === type )
        {
			if(null != this.openParams && true == this.openParams.checkFileSize)
			{
				this.openParams.parCount += 1;
				if(this.openParams.parCount >= g_nErrorParagraphCount)
					throw new Error(g_sErrorCharCountMessage);
			}
            var oNewParagraph = new Paragraph(this.Document.DrawingDocument, this.Document);
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadParagraph(t,l, oNewParagraph, Content);
            });
            oNewParagraph.Correct_Content();
            //Prev/Next
            if(null != this.lastPar)
            {
                oNewParagraph.Set_DocumentPrev(this.lastPar);
                this.lastPar.Set_DocumentNext(oNewParagraph);
            }
            this.lastPar = oNewParagraph;
            Content.push(oNewParagraph);
        }
        else if ( c_oSerParType.Table === type )
        {
            var doc = this.Document;
			var oNewTable = new CTable(doc.DrawingDocument, doc, true, 0, 0, []);
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadDocTable(t, l, oNewTable);
            });
            if (oNewTable.Content.length > 0) {
				this.oReadResult.aTableCorrect.push(oNewTable);
              if(2 == AscCommon.CurFileVersion && false == oNewTable.Inline)
              {
                  //делаем смещение левой границы
                  if(false == oNewTable.PositionH.Align)
                  {
                      var dx = GetTableOffsetCorrection(oNewTable);
                      oNewTable.PositionH.Value += dx;
                  }
              }
              if(null != this.lastPar)
              {
                  oNewTable.Set_DocumentPrev(this.lastPar);
                  this.lastPar.Set_DocumentNext(oNewTable);
              }
              this.lastPar = oNewTable;
              Content.push(oNewTable);
            }
        }
        else if ( c_oSerParType.sectPr === type && !this.openParams.bCopyPaste)
		{
			var oSectPr = oThis.Document.SectPr;
			var oAdditional = {EvenAndOddHeaders: null};
            res = this.bcr.Read1(length, function(t, l){
                return oThis.bpPrr.Read_SecPr(t, l, oSectPr, oAdditional);
            });
			if(null != oAdditional.EvenAndOddHeaders)
				this.Document.Set_DocumentEvenAndOddHeaders(oAdditional.EvenAndOddHeaders);
			if(AscCommon.CurFileVersion < 5)
			{
				for(var i = 0; i < this.oReadResult.headers.length; ++i)
				{
					var item = this.oReadResult.headers[i];
					switch(item.type)
					{
						case c_oSerHdrFtrTypes.HdrFtr_First: oSectPr.Set_Header_First(item.elem);break;
						case c_oSerHdrFtrTypes.HdrFtr_Even: oSectPr.Set_Header_Even(item.elem);break;
						case c_oSerHdrFtrTypes.HdrFtr_Odd: oSectPr.Set_Header_Default(item.elem);break;
					}
				}
				for(var i = 0; i < this.oReadResult.footers.length; ++i)
				{
					var item = this.oReadResult.footers[i];
					switch(item.type)
					{
						case c_oSerHdrFtrTypes.HdrFtr_First: oSectPr.Set_Footer_First(item.elem);break;
						case c_oSerHdrFtrTypes.HdrFtr_Even: oSectPr.Set_Footer_Even(item.elem);break;
						case c_oSerHdrFtrTypes.HdrFtr_Odd: oSectPr.Set_Footer_Default(item.elem);break;
					}
				}
			}
		} else if ( c_oSerParType.Sdt === type) {
			var oSdt = new AscCommonWord.CBlockLevelSdt(this.oReadResult.logicDocument, this.Document);
			res = this.bcr.Read1(length, function(t, l){
				return oThis.ReadSdt(t,l, oSdt, 0);
			});
			//Prev/Next
			if(null != this.lastPar)
			{
				oSdt.Set_DocumentPrev(this.lastPar);
				this.lastPar.Set_DocumentNext(oSdt);
			}
			this.lastPar = oSdt;
			Content.push(oSdt);
		// } else if ( c_oSerParType.Background === type ) {
			// oThis.Document.Background = {Color: null, Unifill: null, shape: null};
			// res = this.bcr.Read2(length, function(t, l){
				// return oThis.ReadBackground(t,l, oThis.Document.Background);
			// });
		} else if (c_oSerParType.JsaProject === type) {
			this.Document.DrawingDocument.m_oWordControl.m_oApi.macros.SetData(AscCommon.GetStringUtf8(this.stream, length));
		} else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadBackground = function(type, length, oBackground)
	{
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerBackgroundType.Color === type){
			oBackground.Color = this.bcr.ReadColor();
		} else if(c_oSerBackgroundType.ColorTheme === type) {
			var themeColor = {Auto: null, Color: null, Tint: null, Shade: null};
			res = this.bcr.Read2(length, function(t, l){
				return oThis.bcr.ReadColorTheme(t, l, themeColor);
			});
			if(true == themeColor.Auto)
				oBackground.Color = new CDocumentColor(0, 0, 0, true);
			var unifill = CreateThemeUnifill(themeColor.Color, themeColor.Tint, themeColor.Shade);
			if(null != unifill)
				oBackground.Unifill = unifill;
			else if (null != oBackground.Color && !oBackground.Color.Auto)
				oBackground.Unifill = AscFormat.CreteSolidFillRGB(oBackground.Color.r, oBackground.Color.g, oBackground.Color.b);
		} else if(c_oSerBackgroundType.pptxDrawing === type) {
			var oDrawing = {};
			var oParStruct = new OpenParStruct(null, null);
			res = this.ReadDrawing (type, length, oParStruct, oDrawing);
			if(null != oDrawing.content.GraphicObj)
				oBackground.shape = oDrawing.content.GraphicObj;
		} else
			res = c_oSerConstants.ReadUnknown;
		return res;
	}
    this.ReadParagraph = function(type, length, paragraph, Content)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if ( c_oSerParType.pPr === type )
        {
			var oNewParaPr = paragraph.Pr;
            res = this.bpPrr.Read(length, oNewParaPr, paragraph);
			this.oReadResult.aPostOpenStyleNumCallbacks.push(function(){
				paragraph.Set_Pr(oNewParaPr);
			});
        }
        else if ( c_oSerParType.Content === type )
        {
			var oParStruct = new OpenParStruct(paragraph, paragraph);
            //для случая гиперссылок на несколько строк в конце параграфа завершаем начатые, а начале - продолжаем незавершенные
            if (this.aFields.length > 0) {
                for (var i = 0; i < this.aFields.length; ++i) {
					var oField = this.aFields[i];
					if (null != oField && para_Hyperlink == oField.Get_Type()) {
						var oHyperlink = new ParaHyperlink();
						oHyperlink.SetParagraph(paragraph);
						oHyperlink.SetValue(oField.GetValue());
						oHyperlink.SetToolTip(oField.GetToolTip());
						oParStruct.addElem(oHyperlink);
					} else {
                        //зануляем, чтобы когда придет fldend ничего не делать
                        this.aFields[i] = null;
                    }
                }
            }
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadParagraphContent(t, l, oParStruct);
            });
            //завершаем гиперссылки
            oParStruct.commitAll();
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.ReadParagraphContent = function (type, length, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        var oCurContainer = oParStruct.getElem();
        if (c_oSerParType.Run === type)
        {
			oParStruct.addElemToContentStart();
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadRun(t, l, oParStruct);
            });
			oParStruct.addElemToContentFinish();
        }
		else if (c_oSerParType.CommentStart === type)
        {
			var oCommon = {};
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadComment(t,l, oCommon);
			});
			if(null != oCommon.Id && null != oCurContainer)
			{
			    oCommon.oParent = oCurContainer;
				var item = this.oComments[oCommon.Id];
				if(item)
					item.Start = oCommon;
				else
					this.oComments[oCommon.Id] = {Start: oCommon};
				if(null == this.oCurComments[oCommon.Id])
				{
					this.nCurCommentsCount++;
					this.oCurComments[oCommon.Id] = "";
				}
				oCommon.oParaComment = new ParaComment(true, oCommon.Id);
				oParStruct.addToContent(oCommon.oParaComment);
			}
        }
		else if (c_oSerParType.CommentEnd === type)
        {
			var oCommon = {};
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadComment(t,l, oCommon);
            });
			if(null != oCommon.Id && null != oCurContainer)
			{
			    oCommon.oParent = oCurContainer;
				var item = this.oComments[oCommon.Id];
				if(!item)
				{
					item = {};
					this.oComments[oCommon.Id] = item;
				}
				item.End = oCommon;
				var sQuoteText = this.oCurComments[oCommon.Id];
				if(null != sQuoteText)
				{
					item.QuoteText = sQuoteText;
					this.nCurCommentsCount--;
					delete this.oCurComments[oCommon.Id];
				}
				oCommon.oParaComment = new ParaComment(false, oCommon.Id);
				oParStruct.addToContent(oCommon.oParaComment);
			}
        }
		else if ( c_oSerParType.OMathPara == type )
		{
			var props = {};
			res = this.bcr.Read1(length, function(t, l){
                return oThis.boMathr.ReadMathOMathPara(t,l,oParStruct, props);
			});
		}
		else if ( c_oSerParType.OMath == type )
		{	
			var oMath = new ParaMath();
			oParStruct.addToContent(oMath);
			
			res = this.bcr.Read1(length, function(t, l){
                return oThis.boMathr.ReadMathArg(t,l,oMath.Root, oParStruct);
			});

            oMath.Root.Correct_Content(true);
		}
		else if ( c_oSerParType.MRun == type )
		{
			var props = {};
			var oMRun = new ParaRun(oParStruct.paragraph, true);
			res = this.bcr.Read1(length, function(t, l){
				return oThis.boMathr.ReadMathMRun(t,l,oMRun,props,oParStruct,oParStruct);
			});
			oParStruct.addToContent(oMRun);
		}
		else if (c_oSerParType.Hyperlink == type) {
		    var oHyperlinkObj = {Link: null, Anchor: null, Tooltip: null, History: null, DocLocation: null, TgtFrame: null};
		    var oNewHyperlink = new ParaHyperlink();
		    oNewHyperlink.SetParagraph(oParStruct.paragraph);
		    res = this.bcr.Read1(length, function (t, l) {
		        return oThis.ReadHyperlink(t, l, oHyperlinkObj, oNewHyperlink, oParStruct);
		    });
			if (null != oHyperlinkObj.Link)
				oNewHyperlink.SetValue(oHyperlinkObj.Link);
			if (null != oHyperlinkObj.Tooltip)
				 oNewHyperlink.SetToolTip(oHyperlinkObj.Tooltip);
			if (null != oHyperlinkObj.Anchor)
				oNewHyperlink.SetAnchor(oHyperlinkObj.Anchor);
			oParStruct.addToContent(oNewHyperlink);
            oNewHyperlink.Check_Content();
		}
		else if (c_oSerParType.FldSimple == type) {
			var oFldSimpleObj = {ParaField: null};
		    res = this.bcr.Read1(length, function (t, l) {
		        return oThis.ReadFldSimple(t, l, oFldSimpleObj, oParStruct);
		    });
			if(null != oFldSimpleObj.ParaField){
                //чтобы не писать здесь логику для pagenum
                oParStruct.addElem(oFldSimpleObj.ParaField);
                oParStruct.commitElem();
			}
		} else if (c_oSerParType.Del == type) {
            var reviewInfo = new CReviewInfo();
            var startPos = oParStruct.getCurPos();
			res = this.bcr.Read1(length, function(t, l){
                return ReadTrackRevision(t, l, oThis.stream, reviewInfo, {parStruct: oParStruct, bdtr: oThis});
			});
            var endPos = oParStruct.getCurPos();
            for(var i = startPos; i < endPos; ++i) {
                var elem = oParStruct.GetFromContent(i);
                if(elem && elem.Set_ReviewTypeWithInfo) {
                    elem.Set_ReviewTypeWithInfo(reviewtype_Remove, reviewInfo);
                }
            }
        } else if (c_oSerParType.Ins == type) {
            var reviewInfo = new CReviewInfo();
            var startPos = oParStruct.getCurPos();
			res = this.bcr.Read1(length, function(t, l){
                return ReadTrackRevision(t, l, oThis.stream, reviewInfo, {parStruct: oParStruct, bdtr: oThis});
			});
            var endPos = oParStruct.getCurPos();
            for(var i = startPos; i < endPos; ++i) {
                var elem = oParStruct.GetFromContent(i);
                if(elem && elem.Set_ReviewTypeWithInfo) {
                    elem.Set_ReviewTypeWithInfo(reviewtype_Add, reviewInfo);
                }
            }
		} else if (c_oSerParType.MoveFrom == type) {
			var reviewInfo = new CReviewInfo();
			var startPos = oParStruct.getCurPos();
			res = this.bcr.Read1(length, function(t, l){
				return ReadTrackRevision(t, l, oThis.stream, reviewInfo, {parStruct: oParStruct, bdtr: oThis});
			});
			var endPos = oParStruct.getCurPos();
			for(var i = startPos; i < endPos; ++i) {
				var elem = oParStruct.GetFromContent(i);
				if(elem && elem.Set_ReviewTypeWithInfo) {
					elem.Set_ReviewTypeWithInfo(reviewtype_Remove, reviewInfo);
				}
			}
		} else if (c_oSerParType.MoveTo == type) {
			var reviewInfo = new CReviewInfo();
			var startPos = oParStruct.getCurPos();
			res = this.bcr.Read1(length, function(t, l){
				return ReadTrackRevision(t, l, oThis.stream, reviewInfo, {parStruct: oParStruct, bdtr: oThis});
			});
			var endPos = oParStruct.getCurPos();
			for(var i = startPos; i < endPos; ++i) {
				var elem = oParStruct.GetFromContent(i);
				if(elem && elem.Set_ReviewTypeWithInfo) {
					elem.Set_ReviewTypeWithInfo(reviewtype_Add, reviewInfo);
				}
			}
		} else if ( c_oSerParType.Sdt === type) {
			var oSdt = new AscCommonWord.CInlineLevelSdt();
			oSdt.SetParagraph(oParStruct.paragraph);
			var oSdtStruct = new OpenParStruct(oSdt, oParStruct.paragraph);
			res = this.bcr.Read1(length, function(t, l){
				return oThis.ReadSdt(t,l, oSdt, 1, oSdtStruct);
			});
			oSdtStruct.commitAll();
			oParStruct.addToContent(oSdt);
		} else if ( c_oSerParType.BookmarkStart === type) {
			var bookmark = this.oReadResult.bookmarkForRead;
			bookmark.BookmarkId = undefined;
			bookmark.BookmarkName = undefined;
			res = this.bcr.Read1(length, function(t, l){
				return oThis.bcr.ReadBookmark(t,l, bookmark);
			});
			if (undefined !== bookmark.BookmarkId && undefined !== bookmark.BookmarkName) {
				var isCopyPaste = this.openParams && this.openParams.bCopyPaste;
				var bookmarksManager = this.Document.BookmarksManager;
				if(!isCopyPaste || (isCopyPaste && bookmarksManager && null === bookmarksManager.GetBookmarkByName(bookmark.BookmarkName))){
					var newBookmark = new CParagraphBookmark(true, bookmark.BookmarkId, bookmark.BookmarkName);
					this.oReadResult.bookmarksStarted[bookmark.BookmarkId] = {parent: oParStruct.getElem(), bookmark: newBookmark};
					oParStruct.addToContent(newBookmark);
				}
			}
		} else if ( c_oSerParType.BookmarkEnd === type) {
			var bookmark = this.oReadResult.bookmarkForRead;
			bookmark.BookmarkId = undefined;
			res = this.bcr.Read1(length, function(t, l){
				return oThis.bcr.ReadBookmark(t,l, bookmark);
			});
			if (this.oReadResult.bookmarksStarted[bookmark.BookmarkId]) {
				delete this.oReadResult.bookmarksStarted[bookmark.BookmarkId];
				oParStruct.addToContent(new CParagraphBookmark(false, bookmark.BookmarkId));
			}
		} else
		    res = c_oSerConstants.ReadUnknown;
        return res;
    };
	
	this.ReadFldChar = function (type, length, oParStruct) {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSer_FldSimpleType.CharType === type) {
			oParStruct.addElemToContent(new ParaFieldChar(this.stream.GetUChar(), this.oReadResult.logicDocument));
		} else
			res = c_oSerConstants.ReadUnknown;
		return res;
	}
	this.ReadFldSimple = function (type, length, oFldSimpleObj, oParStruct) {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if (c_oSer_FldSimpleType.Instr === type) {
			var Instr = this.stream.GetString2LE(length);
			oFldSimpleObj.ParaField = this.parseField(Instr, oParStruct.paragraph);
		// } else  if (c_oSer_FldSimpleType.FFData === type) {
		// 	var FFData = {};
		// 	res = this.bcr.Read1(length, function (t, l) {
		// 		return oThis.ReadFFData(t, l, FFData);
		// 	});
		// 	oFldSimpleObj.ParaField.FFData = FFData;
		} else if (c_oSer_FldSimpleType.Content === type) {
			if(null != oFldSimpleObj.ParaField) {
				var oFldStruct = new OpenParStruct(oFldSimpleObj.ParaField, oParStruct.paragraph);
				res = this.bcr.Read1(length, function (t, l) {
					return oThis.ReadParagraphContent(t, l, oFldStruct);
				});
				oFldStruct.commitAll();
			} else {
				res = this.bcr.Read1(length, function (t, l) {
					return oThis.ReadParagraphContent(t, l, oParStruct);
				});
			}
		}
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }
	this.ReadFFData = function(type, length, oFFData) {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerFFData.CalcOnExit === type) {
			oFFData.CalcOnExit = this.stream.GetBool();
		} else if (c_oSerFFData.CheckBox === type) {
			oFFData.CheckBox = {};
			res = this.bcr.Read1(length, function(t, l) {
				return oThis.ReadFFCheckBox(t, l, oFFData.CheckBox);
			});
		} else if (c_oSerFFData.DDList === type) {
			oFFData.DDList = {DLListEntry: []};
			res = this.bcr.Read1(length, function(t, l) {
				return oThis.ReadDDList(t, l, oFFData.DDList);
			});
		} else if (c_oSerFFData.Enabled === type) {
			oFFData.Enabled = this.stream.GetBool();
		} else if (c_oSerFFData.EntryMacro === type) {
			oFFData.EntryMacro = this.stream.GetString2LE(length);
		} else if (c_oSerFFData.ExitMacro === type) {
			oFFData.ExitMacro = this.stream.GetString2LE(length);
		} else if (c_oSerFFData.HelpText === type) {
			oFFData.HelpText = {};
			res = this.bcr.Read1(length, function(t, l) {
				return oThis.ReadFFHelpText(t, l, oFFData.HelpText);
			});
		} else if (c_oSerFFData.Label === type) {
			oFFData.Label = this.stream.GetLong();
		} else if (c_oSerFFData.Name === type) {
			oFFData.Name = this.stream.GetString2LE(length);
		} else if (c_oSerFFData.StatusText === type) {
			oFFData.StatusText = {};
			res = this.bcr.Read1(length, function(t, l) {
				return oThis.ReadFFHelpText(t, l, oFFData.StatusText);
			});
		} else if (c_oSerFFData.TabIndex === type) {
			oFFData.TabIndex = this.stream.GetLong();
		} else if (c_oSerFFData.TextInput === type) {
			oFFData.TextInput = {};
			res = this.bcr.Read1(length, function(t, l) {
				return oThis.ReadTextInput(t, l, oFFData.TextInput);
			});
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	};
	this.ReadFFCheckBox = function(type, length, oFFCheckBox) {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerFFData.CBChecked === type) {
			oFFCheckBox.CBChecked = this.stream.GetBool();
		} else if (c_oSerFFData.CBDefault === type) {
			oFFCheckBox.CBDefault = this.stream.GetBool();
		} else if (c_oSerFFData.CBSize === type) {
			oFFCheckBox.CBSize = this.stream.GetULongLE();
		} else if (c_oSerFFData.CBSizeAuto === type) {
			oFFCheckBox.CBSizeAuto = this.stream.GetBool();
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	};
	this.ReadDDList = function(type, length, oDDList) {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerFFData.DLDefault === type) {
			oDDList.DLDefault = this.stream.GetULongLE();
		} else if (c_oSerFFData.DLResult === type) {
			oDDList.DLResult = this.stream.GetULongLE();
		} else if (c_oSerFFData.DLListEntry === type) {
			oDDList.DLListEntry.push(this.stream.GetString2LE(length));
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	};
	this.ReadFFHelpText = function(type, length, oHelpText) {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerFFData.HTType === type) {
			oHelpText.HTType = this.stream.GetUChar();
		} else if (c_oSerFFData.HTVal === type) {
			oHelpText.HTVal = this.stream.GetString2LE(length);
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	};
	this.ReadTextInput = function(type, length, oTextInput) {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerFFData.TIDefault === type) {
			oTextInput.TIDefault = this.stream.GetString2LE(length);
		} else if (c_oSerFFData.TIFormat === type) {
			oTextInput.TIFormat = this.stream.GetString2LE(length);
		} else if (c_oSerFFData.TIMaxLength === type) {
			oTextInput.TIMaxLength = this.stream.GetULongLE();
		} else if (c_oSerFFData.TIType === type) {
			oTextInput.TIType = this.stream.GetUChar();
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	};
    this.ReadHyperlink = function (type, length, oHyperlinkObj, oNewHyperlink, oParStruct) {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if (c_oSer_HyperlinkType.Link === type) {
            oHyperlinkObj.Link = this.stream.GetString2LE(length);
        }
        else if (c_oSer_HyperlinkType.Anchor === type) {
            oHyperlinkObj.Anchor = this.stream.GetString2LE(length);
        }
        else if (c_oSer_HyperlinkType.Tooltip === type) {
            oHyperlinkObj.Tooltip = this.stream.GetString2LE(length);
        }
        else if (c_oSer_HyperlinkType.History === type) {
            oHyperlinkObj.History = this.stream.GetBool();
        }
        else if (c_oSer_HyperlinkType.DocLocation === type) {
            oHyperlinkObj.DocLocation = this.stream.GetString2LE(length);
        }
        else if (c_oSer_HyperlinkType.TgtFrame === type) {
            oHyperlinkObj.TgtFrame = this.stream.GetString2LE(length);
        }
        else if (c_oSer_HyperlinkType.Content === type) {
			var oHypStruct = new OpenParStruct(oNewHyperlink, oParStruct.paragraph);
            res = this.bcr.Read1(length, function (t, l) {
                return oThis.ReadParagraphContent(t, l, oHypStruct);
            });
            oHypStruct.commitAll();
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }
	this.ReadComment = function(type, length, oComments)
	{
		var res = c_oSerConstants.ReadOk;
		if (c_oSer_CommentsType.Id === type)
			oComments.Id = this.stream.GetULongLE();
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
	};
	this.ReadRun = function (type, length, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if (c_oSerRunType.rPr === type)
        {
            var rPr = oParStruct.curRun.Pr;
            res = this.brPrr.Read(length, rPr, oParStruct.curRun);
			oParStruct.curRun.Set_Pr(rPr);
        }
        else if (c_oSerRunType.Content === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadRunContent(t, l, oParStruct);
            });
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadText = function(text, oParStruct, isInstrText){
		for (var i = 0; i < text.length; ++i)
		{
			var nUnicode = null;
			var nCharCode = text.charCodeAt(i);
			if (AscCommon.isLeadingSurrogateChar(nCharCode))
			{
				if(i + 1 < text.length)
				{
					i++;
					var nTrailingChar = text.charCodeAt(i);
					nUnicode = AscCommon.decodeSurrogateChar(nCharCode, nTrailingChar);
				}
			}
			else
				nUnicode = nCharCode;

			if (null !== nUnicode) {
				if (0x20 !== nUnicode || isInstrText)
					oParStruct.addElemToContent(isInstrText ? new ParaInstrText(nUnicode) : new ParaText(nUnicode));
				else
					oParStruct.addElemToContent(new ParaSpace());
			}
		}
	};
	this.ReadRunContent = function (type, length, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        var oNewElem = null;
        if (c_oSerRunType.run === type || c_oSerRunType.delText === type)
        {
            var text = this.stream.GetString2LE(length);
			if(null != this.openParams && true == this.openParams.checkFileSize)
			{
				this.openParams.charCount += length / 2;
				if(this.openParams.charCount >= g_nErrorCharCount)
					throw new Error(g_sErrorCharCountMessage);
			}
			if(this.nCurCommentsCount > 0)
			{
				for(var i in this.oCurComments)
					this.oCurComments[i] += text;
			}

			this.ReadText(text, oParStruct, false);
        }
        else if (c_oSerRunType.tab === type)
        {
            oNewElem = new ParaTab();
        }
        else if (c_oSerRunType.pagenum === type)
        {
            oNewElem = new ParaPageNum();
        }
        else if (c_oSerRunType.pagebreak === type)
        {
            oNewElem = new ParaNewLine( break_Page );
        }
        else if (c_oSerRunType.linebreak === type)
        {
            oNewElem = new ParaNewLine( break_Line );
        }
        else if (c_oSerRunType.columnbreak === type)
        {
            oNewElem = new ParaNewLine( break_Column );
        }
        else if(c_oSerRunType.image === type)
        {
            var oThis = this;
            var image = {page: null, Type: null, MediaId: null, W: null, H: null, X: null, Y: null, Paddings: null};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadImage(t,l, image);
            });
            if((c_oAscWrapStyle.Inline == image.Type && null != image.MediaId && null != image.W && null != image.H) ||
				(c_oAscWrapStyle.Flow == image.Type && null != image.MediaId && null != image.W && null != image.H && null != image.X && null != image.Y))
            {
                var doc = this.Document;
                //todo paragraph
                var drawing = new ParaDrawing(image.W, image.H, null, doc.DrawingDocument, doc,  oParStruct.paragraph);

                var src = this.oReadResult.ImageMap[image.MediaId];
                var Image = editor.WordControl.m_oLogicDocument.DrawingObjects.createImage(src, 0, 0, image.W, image.H);
                drawing.Set_GraphicObject(Image);
                Image.setParent(drawing);
                if(c_oAscWrapStyle.Flow == image.Type)
                {
                    drawing.Set_DrawingType(drawing_Anchor);
                    drawing.Set_PositionH(Asc.c_oAscRelativeFromH.Page, false, image.X, false);
                    drawing.Set_PositionV(Asc.c_oAscRelativeFromV.Page, false, image.Y, false);
                    if(image.Paddings)
                        drawing.Set_Distance(image.Paddings.Left, image.Paddings.Top, image.Paddings.Right, image.Paddings.Bottom);
                }
                if(null != drawing.GraphicObj)
                {
                    pptx_content_loader.ImageMapChecker[src] = true;
                    oNewElem = drawing;
                }
            }
        }
        else if(c_oSerRunType.pptxDrawing === type)
        {
			var oDrawing = new Object();
			this.ReadDrawing (type, length, oParStruct, oDrawing, res);
			if(null != oDrawing.content.GraphicObj)
				oNewElem = oDrawing.content;
        }
		else if(c_oSerRunType.fldstart_deprecated === type)
        {
			var sField = this.stream.GetString2LE(length);
			var oField = this.parseField(sField, oParStruct.paragraph);
			if (null != oField) {
				oParStruct.addElem(oField);
			}
            this.aFields.push(oField);
        }
		else if(c_oSerRunType.fldend_deprecated === type)
        {
			var elem = this.aFields.pop();
			if (elem) {
                oParStruct.commitElem();
            }
        }
		else if(c_oSerRunType.fldChar === type)
		{
			res = this.bcr.Read1(length, function(t, l){
				return oThis.ReadFldChar(t,l,oParStruct);
			});
		}
		else if(c_oSerRunType.instrText === type || c_oSerRunType.delInstrText === type)
		{
			this.ReadText(this.stream.GetString2LE(length), oParStruct, true);
		}
        else if (c_oSerRunType._LastRun === type)
            this.oReadResult.bLastRun = true;
		else if (c_oSerRunType.object === type)
		{	
			var oDrawing = new Object();
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadObject(t,l,oParStruct,oDrawing);
			});
			if (null != oDrawing.content.GraphicObj) {
				oNewElem = oDrawing.content;
				//todo do another check
				if (oDrawing.ParaMath && oNewElem.GraphicObj.getImageUrl && 'image-1.jpg' === oNewElem.GraphicObj.getImageUrl()) {
					//word 95 ole without image
					this.oReadResult.drawingToMath.push(oNewElem);
				}
			}
		}
        else if (c_oSerRunType.cr === type)
        {
            oNewElem = new ParaNewLine( break_Line );
        }
        else if (c_oSerRunType.nonBreakHyphen === type)
        {
            oNewElem = new ParaText(0x002D);
            oNewElem.Set_SpaceAfter(false);
        }
        else if (c_oSerRunType.softHyphen === type)
        {
            //todo
        }
		else if (c_oSerRunType.separator === type)
		{
			oNewElem = new ParaSeparator();
		}
		else if (c_oSerRunType.continuationSeparator === type)
		{
			oNewElem = new ParaContinuationSeparator();
		}
		else if (c_oSerRunType.footnoteRef === type)
		{
			if (this.curFootnote) {
				oNewElem = new ParaFootnoteRef(this.curFootnote);
			}
			else if(this.openParams && this.openParams.bCopyPaste && this.openParams.oDocument){
				oNewElem = new ParaFootnoteRef(this.openParams.oDocument);
			}
		}
		else if (c_oSerRunType.footnoteReference === type)
		{
			var ref = {id: null, customMark: null};
			res = this.bcr.Read1(length, function(t, l) {
				return oThis.ReadFootnoteRef(t, l, ref);
			});
			var footnote = this.oReadResult.footnotes[ref.id];
			if (footnote && this.oReadResult.logicDocument) {
				this.oReadResult.logicDocument.Footnotes.AddFootnote(footnote.content);
				oNewElem = new ParaFootnoteReference(footnote.content, ref.customMark);
			}
		}
        else
            res = c_oSerConstants.ReadUnknown;
        if (null != oNewElem)
        {
			oParStruct.addElemToContent(oNewElem);
        }
        return res;
    };
	this.ReadFootnoteRef = function (type, length, ref)
	{
		var res = c_oSerConstants.ReadOk;
		if(c_oSerNotes.RefCustomMarkFollows === type) {
			ref.customMark = this.stream.GetBool();
		} else if(c_oSerNotes.RefId === type) {
			ref.id = this.stream.GetULongLE();
		} else
			res = c_oSerConstants.ReadUnknown;
		return res;
	};
	this.ReadDrawing = function (type, length, oParStruct, oDrawing, res)
	{
		var oThis = this;
		var doc = this.Document;
		var graphicFramePr = {locks: 0};
        var oParaDrawing = new ParaDrawing(null, null, null, doc.DrawingDocument, doc, oParStruct.paragraph);
        res = this.bcr.Read2(length, function(t, l){
            return oThis.ReadPptxDrawing(t, l, oParaDrawing, graphicFramePr);
        });
        if(null != oParaDrawing.SimplePos)
            oParaDrawing.setSimplePos(oParaDrawing.SimplePos.Use, oParaDrawing.SimplePos.X, oParaDrawing.SimplePos.Y);
        if(null != oParaDrawing.Extent)
            oParaDrawing.setExtent(oParaDrawing.Extent.W, oParaDrawing.Extent.H);
        if(null != oParaDrawing.wrappingPolygon)
            oParaDrawing.addWrapPolygon(oParaDrawing.wrappingPolygon);
		if (oDrawing.ParaMath)
			oParaDrawing.Set_ParaMath(oDrawing.ParaMath);

        if(oParaDrawing.GraphicObj)
        {
			if (oParaDrawing.GraphicObj.setLocks && graphicFramePr.locks > 0) {
				oParaDrawing.GraphicObj.setLocks(graphicFramePr.locks);
			}
            if(oParaDrawing.GraphicObj.getObjectType() !== AscDFH.historyitem_type_ChartSpace)//диаграммы могут быть без spPr
            {
                if(!oParaDrawing.GraphicObj.spPr)
                {
                    oParaDrawing.GraphicObj = null;
                }
            }
            if(AscCommon.isRealObject(oParaDrawing.docPr) && oParaDrawing.docPr.isHidden)
            {
                oParaDrawing.GraphicObj = null;
            }
            if(oParaDrawing.GraphicObj)
            {
                if(oParaDrawing.GraphicObj.bEmptyTransform)
                {
                    var oXfrm = new AscFormat.CXfrm();
                    oXfrm.setOffX(0);
                    oXfrm.setOffY(0);
                    oXfrm.setChOffX(0);
                    oXfrm.setChOffY(0);
                    oXfrm.setExtX(oParaDrawing.Extent.W);
                    oXfrm.setExtY(oParaDrawing.Extent.H);
                    oXfrm.setChExtX(oParaDrawing.Extent.W);
                    oXfrm.setChExtY(oParaDrawing.Extent.H);
                    oXfrm.setParent(oParaDrawing.GraphicObj.spPr);
                    oParaDrawing.GraphicObj.spPr.setXfrm(oXfrm);
                    delete oParaDrawing.GraphicObj.bEmptyTransform;
                }
                if(drawing_Anchor == oParaDrawing.DrawingType && typeof AscCommon.History.RecalcData_Add === "function")//TODO некорректная проверка typeof
                  AscCommon.History.RecalcData_Add( { Type : AscDFH.historyitem_recalctype_Flow, Data : oParaDrawing});
            }
        }
		oDrawing.content = oParaDrawing;
	}
	this.ReadObject = function (type, length, oParStruct, oDrawing)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if (c_oSerParType.OMath === type)
		{
			if ( length > 0 )
			{
				var oMathPara = new ParaMath();
				oDrawing.ParaMath = oMathPara;
				
				res = this.bcr.Read1(length, function(t, l){
					return oThis.boMathr.ReadMathArg(t,l,oMathPara.Root, oParStruct);
				});
				oMathPara.Root.Correct_Content(true);
			}
		}
		else if(c_oSerRunType.pptxDrawing === type)
		{
			this.ReadDrawing (type, length, oParStruct, oDrawing, res);
		}
		else
			res = c_oSerConstants.ReadUnknown;
		return res;
	}
    this.parseField = function(fld, paragraph)
    {
		var sFieldType = "";
		var aArguments = [];
		var aSwitches = [];
		var aParts = this.splitFieldArguments(fld);
		if(aParts.length > 0){
			sFieldType = aParts[0].toUpperCase();
			var bSwitch = false;
			var sCurSwitch = "";
			for(var i = 1; i < aParts.length; ++i){
				var part = aParts[i];
				if(part.length > 1 && '\\' == part[0] && '\"' != part[1] && '\\' != part[1]){
					if(sCurSwitch.length > 0)
						aSwitches.push(sCurSwitch)
					bSwitch = true;
					sCurSwitch = part.substring(1);
				}
				else{
					if(bSwitch)
						sCurSwitch += " " + part;
					else
						aArguments.push(this.parseFieldArgument(part));
				}
			}
			if(sCurSwitch.length > 0)
				aSwitches.push(sCurSwitch)
		}
		//обрабатывает известные field
		return this.initField(sFieldType, aArguments, aSwitches, paragraph);
    };
	this.splitFieldArguments = function(sVal){
		var temp = String.fromCharCode(5);
		//заменяем '\"' , чтобы было проше регулярное выражение,можно написать более быстрый код
		sVal = sVal.replace(/\\"/g, temp);
		var aMatch = sVal.match(/[^\s"]+|"[^"]*"/g);
		if(null != aMatch){
			for(var i = 0; i < aMatch.length; ++i)
				aMatch[i] = aMatch[i].replace(new RegExp(temp, 'g'), "\\\"");
			}
		else
			aMatch = [];
		return aMatch;
	};
	this.parseFieldArgument = function(sVal){
		//trim
		sVal = sVal.replace(/^\s+|\s+$/g,'');
		//remove surrounded quote
		if(sVal.length > 1 && "\"" == sVal[0] && "\"" == sVal[sVal.length - 1])
			sVal = sVal.substring(1, sVal.length - 1);
		//replace '\\' and '\"'
		sVal = sVal.replace(/\\([\\\"])/g, '$1');
		return sVal
	};
	this.initField = function(sFieldType, aArguments, aSwitches, paragraph)
    {
		var oRes = null;
		if("HYPERLINK" == sFieldType){
			var sLink = null;
			var sLocation = null;
			var sTooltip = null;
			if(aArguments.length > 0)
				sLink = aArguments[0];
			for(var i = 0; i < aSwitches.length; ++i){
				var sSwitch = aSwitches[i];
				if(sSwitch.length > 0){
					var cFirstChar = sSwitch[0].toLowerCase();
					var sFieldArgument = this.parseFieldArgument(sSwitch.substring(1));
					if("l" == cFirstChar)
						sLocation = sFieldArgument;
					else if("o" == cFirstChar)
						sTooltip = sFieldArgument;
				}
			}
			if(!(null != sLocation && sLocation.length > 0)){
				oRes = new ParaHyperlink();
				oRes.SetParagraph(paragraph);
				if(null != sLink && sLink.length > 0)
					oRes.SetValue(sLink);
				if(null != sTooltip && sTooltip.length > 0)
					oRes.SetToolTip(sTooltip);
			}
		}
		else if("PAGE" == sFieldType){
            oRes = new ParaField(fieldtype_PAGENUM, aArguments, aSwitches);
		}
		else if("NUMPAGES" == sFieldType){
			oRes = new ParaField(fieldtype_PAGECOUNT, aArguments, aSwitches);
		}
		else if("MERGEFIELD" == sFieldType){
			oRes = new ParaField(fieldtype_MERGEFIELD, aArguments, aSwitches);
            if (editor)
               editor.WordControl.m_oLogicDocument.Register_Field(oRes);
		}
		else if ("FORMTEXT" == sFieldType){
			oRes = new ParaField(fieldtype_FORMTEXT, aArguments, aSwitches);
			if (editor)
				editor.WordControl.m_oLogicDocument.Register_Field(oRes);
		}
		return oRes;
	}
    this.ReadImage = function(type, length, img)
    {
        var res = c_oSerConstants.ReadOk;
        if ( c_oSerImageType.Page === type )
        {
            img.page = this.stream.GetULongLE();
        }
        else if ( c_oSerImageType.MediaId === type )
        {
            img.MediaId = this.stream.GetULongLE();
        }
        else if ( c_oSerImageType.Type === type )
        {
            img.Type = this.stream.GetUChar();
        }
        else if ( c_oSerImageType.Width === type )
        {
            img.W = this.bcr.ReadDouble();
        }
        else if ( c_oSerImageType.Height === type )
        {
            img.H = this.bcr.ReadDouble();
        }
        else if ( c_oSerImageType.X === type )
        {
            img.X = this.bcr.ReadDouble();
        }
        else if ( c_oSerImageType.Y === type )
        {
            img.Y = this.bcr.ReadDouble();
        }
        else if ( c_oSerImageType.Padding === type )
        {
            var oThis = this;
            img.Paddings = {Left:0, Top: 0, Right: 0, Bottom: 0};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.btblPrr.ReadPaddings(t, l, img.Paddings);
            });
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.ReadPptxDrawing = function(type, length, oParaDrawing, graphicFramePr)
	{
		var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerImageType2.Type === type )
        {
			var nDrawingType = null;
			switch(this.stream.GetUChar())
			{
			case c_oAscWrapStyle.Inline: nDrawingType = drawing_Inline;break;
			case c_oAscWrapStyle.Flow: nDrawingType = drawing_Anchor;break;
			}
			if(null != nDrawingType)
				oParaDrawing.Set_DrawingType(nDrawingType);
		}
		else if( c_oSerImageType2.PptxData === type )
        {
			if(length > 0){
				var grObject = pptx_content_loader.ReadDrawing(this, this.stream, this.Document, oParaDrawing);
				if(null != grObject)
					oParaDrawing.Set_GraphicObject(grObject);
			}
			else
				res = c_oSerConstants.ReadUnknown;
		}
		else if( c_oSerImageType2.Chart2 === type )
        {
			res = c_oSerConstants.ReadUnknown;
			var oNewChartSpace = new AscFormat.CChartSpace();
            var oBinaryChartReader = new AscCommon.BinaryChartReader(this.stream);
            res = oBinaryChartReader.ExternalReadCT_ChartSpace(length, oNewChartSpace, this.Document);
            oNewChartSpace.setBDeleted(false);
            oParaDrawing.Set_GraphicObject(oNewChartSpace);
            oNewChartSpace.setParent(oParaDrawing);
		}
		else if( c_oSerImageType2.AllowOverlap === type )
			var AllowOverlap = this.stream.GetBool();
		else if( c_oSerImageType2.BehindDoc === type )
			oParaDrawing.Set_BehindDoc(this.stream.GetBool());
		else if( c_oSerImageType2.DistL === type )
        {
            oParaDrawing.Set_Distance(Math.abs(this.bcr.ReadDouble()), null, null, null);
        }
		else if( c_oSerImageType2.DistT === type )
        {
            oParaDrawing.Set_Distance(null, Math.abs(this.bcr.ReadDouble()), null, null);
        }
		else if( c_oSerImageType2.DistR === type )
        {
            oParaDrawing.Set_Distance(null, null, Math.abs(this.bcr.ReadDouble()), null);
        }
		else if( c_oSerImageType2.DistB === type )
        {
            oParaDrawing.Set_Distance(null, null, null, Math.abs(this.bcr.ReadDouble()));
        }
		else if( c_oSerImageType2.Hidden === type )
        {
            var Hidden = this.stream.GetBool();
        }
        else if( c_oSerImageType2.LayoutInCell === type )
        {
            oParaDrawing.Set_LayoutInCell(this.stream.GetBool());
        }
		else if( c_oSerImageType2.Locked === type )
            oParaDrawing.Set_Locked(this.stream.GetBool());
		else if( c_oSerImageType2.RelativeHeight === type )
			oParaDrawing.Set_RelativeHeight(AscFonts.FT_Common.IntToUInt(this.stream.GetULongLE()));
		else if( c_oSerImageType2.BSimplePos === type )
			oParaDrawing.SimplePos.Use = this.stream.GetBool();
		else if( c_oSerImageType2.EffectExtent === type )
		{
			var oReadEffectExtent = {Left: null, Top: null, Right: null, Bottom: null};
			res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadEffectExtent(t, l, oReadEffectExtent);
                });
            oParaDrawing.setEffectExtent(oReadEffectExtent.L, oReadEffectExtent.T, oReadEffectExtent.R, oReadEffectExtent.B);
		}
		else if( c_oSerImageType2.Extent === type )
		{
			res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadExtent(t, l, oParaDrawing.Extent);
                });
		}
		else if( c_oSerImageType2.PositionH === type )
		{
			var oNewPositionH = {
				RelativeFrom      : Asc.c_oAscRelativeFromH.Column, // Относительно чего вычисляем координаты
				Align             : false,                      // true : В поле Value лежит тип прилегания, false - в поле Value лежит точное значени
				Value             : 0,                          //
                Percent           : false
			};
			res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadPositionHV(t, l, oNewPositionH);
                });
			oParaDrawing.Set_PositionH(oNewPositionH.RelativeFrom , oNewPositionH.Align , oNewPositionH.Value, oNewPositionH.Percent);
		}
		else if( c_oSerImageType2.PositionV === type )
		{
			var oNewPositionV = {
				RelativeFrom      : Asc.c_oAscRelativeFromV.Paragraph, // Относительно чего вычисляем координаты
				Align             : false,                         // true : В поле Value лежит тип прилегания, false - в поле Value лежит точное значени
				Value             : 0,                             //
                Percent           : false
			};
			res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadPositionHV(t, l, oNewPositionV);
                });
			oParaDrawing.Set_PositionV(oNewPositionV.RelativeFrom , oNewPositionV.Align , oNewPositionV.Value, oNewPositionV.Percent);
		}
		else if( c_oSerImageType2.SimplePos === type )
		{
			res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadSimplePos(t, l, oParaDrawing.SimplePos);
                });
		}
		else if( c_oSerImageType2.WrapNone === type )
		{
			oParaDrawing.Set_WrappingType(WRAPPING_TYPE_NONE);
		}
        else if( c_oSerImageType2.SizeRelH === type )
        {
            var oNewSizeRel = {RelativeFrom: null, Percent: null};
            res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadSizeRelHV(t, l, oNewSizeRel);
                });
            oParaDrawing.SetSizeRelH(oNewSizeRel);
        }
        else if( c_oSerImageType2.SizeRelV === type )
        {
            var oNewSizeRel = {RelativeFrom: null, Percent: null};
            res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadSizeRelHV(t, l, oNewSizeRel);
                });
            oParaDrawing.SetSizeRelV(oNewSizeRel);
        }
		else if( c_oSerImageType2.WrapSquare === type )
		{
			oParaDrawing.Set_WrappingType(WRAPPING_TYPE_SQUARE);
			res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadWrapSquare(t, l,  oParaDrawing.wrappingPolygon);
                });
		}
		else if( c_oSerImageType2.WrapThrough === type )
		{
			oParaDrawing.Set_WrappingType(WRAPPING_TYPE_THROUGH);
			res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadWrapThroughTight(t, l,  oParaDrawing.wrappingPolygon);
                });
		}
		else if( c_oSerImageType2.WrapTight === type )
		{
			oParaDrawing.Set_WrappingType(WRAPPING_TYPE_TIGHT);
			res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadWrapThroughTight(t, l,  oParaDrawing.wrappingPolygon);
                });
		}
		else if( c_oSerImageType2.WrapTopAndBottom === type )
		{
			oParaDrawing.Set_WrappingType(WRAPPING_TYPE_TOP_AND_BOTTOM);
			res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadWrapThroughTight(t, l,  oParaDrawing.wrappingPolygon);
                });
		}
		else if( c_oSerImageType2.GraphicFramePr === type )
		{
			res = this.bcr.Read2(length, function(t, l){
					return oThis.ReadNvGraphicFramePr(t, l, graphicFramePr);
				});
		} else if( c_oSerImageType2.DocPr === type ) {
			res = this.bcr.Read1(length, function(t, l){
					return oThis.ReadDocPr(t, l, oParaDrawing.docPr);
				});
		}
		else if( c_oSerImageType2.CachedImage === type )
		{
			if(null != oParaDrawing.GraphicObj)
				oParaDrawing.GraphicObj.cachedImage = this.stream.GetString2LE(length);
			else
				res = c_oSerConstants.ReadUnknown;
		}
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
	}
	this.ReadNvGraphicFramePr = function(type, length, graphicFramePr) {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		var value;
		if (c_oSerGraphicFramePr.NoChangeAspect === type) {
			value = this.stream.GetBool();
			graphicFramePr.locks |= (AscFormat.LOCKS_MASKS.noChangeAspect | (value ? AscFormat.LOCKS_MASKS.noChangeAspect << 1 : 0));
		} else if (c_oSerGraphicFramePr.NoDrilldown === type) {
			value = this.stream.GetBool();
			graphicFramePr.locks |= (AscFormat.LOCKS_MASKS.noDrilldown | (value ? AscFormat.LOCKS_MASKS.noDrilldown << 1 : 0));
		} else if (c_oSerGraphicFramePr.NoGrp === type) {
			value = this.stream.GetBool();
			graphicFramePr.locks |= (AscFormat.LOCKS_MASKS.noGrp | (value ? AscFormat.LOCKS_MASKS.noGrp << 1 : 0));
		} else if (c_oSerGraphicFramePr.NoMove === type) {
			value = this.stream.GetBool();
			graphicFramePr.locks |= (AscFormat.LOCKS_MASKS.noMove | (value ? AscFormat.LOCKS_MASKS.noMove << 1 : 0));
		} else if (c_oSerGraphicFramePr.NoResize === type) {
			value = this.stream.GetBool();
			graphicFramePr.locks |= (AscFormat.LOCKS_MASKS.noResize | (value ? AscFormat.LOCKS_MASKS.noResize << 1 : 0));
		} else if (c_oSerGraphicFramePr.NoSelect === type) {
			value = this.stream.GetBool();
			graphicFramePr.locks |= (AscFormat.LOCKS_MASKS.noSelect | (value ? AscFormat.LOCKS_MASKS.noSelect << 1 : 0));
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	}
	this.ReadDocPr = function(type, length, docPr) {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerDocPr.Id === type) {
			docPr.setId(this.stream.GetLongLE());
		} else if (c_oSerDocPr.Name === type) {
			docPr.setName(this.stream.GetString2LE(length));
		} else if (c_oSerDocPr.Hidden === type) {
			docPr.setIsHidden(this.stream.GetBool());
		} else if (c_oSerDocPr.Title === type) {
			docPr.setTitle(this.stream.GetString2LE(length));
		} else if (c_oSerDocPr.Descr === type) {
			docPr.setDescr(this.stream.GetString2LE(length));
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	}
	this.ReadEffectExtent = function(type, length, oEffectExtent)
	{
		var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerEffectExtent.Left === type )
			oEffectExtent.L = this.bcr.ReadDouble();
		else if( c_oSerEffectExtent.Top === type )
			oEffectExtent.T = this.bcr.ReadDouble();
		else if( c_oSerEffectExtent.Right === type )
			oEffectExtent.R = this.bcr.ReadDouble();
		else if( c_oSerEffectExtent.Bottom === type )
			oEffectExtent.B = this.bcr.ReadDouble();
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
	}
	this.ReadExtent = function(type, length, oExtent)
	{
		var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerExtent.Cx === type )
			oExtent.W = this.bcr.ReadDouble();
		else if( c_oSerExtent.Cy === type )
			oExtent.H = this.bcr.ReadDouble();
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
	}
	this.ReadPositionHV = function(type, length, PositionH)
	{
		var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerPosHV.RelativeFrom === type )
			PositionH.RelativeFrom = this.stream.GetUChar();
		else if( c_oSerPosHV.Align === type )
		{
			PositionH.Align = true;
			PositionH.Value = this.stream.GetUChar();
		}
		else if( c_oSerPosHV.PosOffset === type )
		{
			PositionH.Align = false;
			PositionH.Value = this.bcr.ReadDouble();
		}
		else if( c_oSerPosHV.PctOffset === type )
		{
			PositionH.Percent = true;
			PositionH.Value = this.bcr.ReadDouble();
		}
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
	}
    this.ReadSizeRelHV = function(type, length, SizeRel)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if (c_oSerSizeRelHV.RelativeFrom === type) {
            SizeRel.RelativeFrom = this.stream.GetUChar();
        } else if (c_oSerSizeRelHV.Pct === type) {
            SizeRel.Percent = this.bcr.ReadDouble()/100.0;
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }
	this.ReadSimplePos = function(type, length, oSimplePos)
	{
		var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerSimplePos.X === type )
			oSimplePos.X = this.bcr.ReadDouble();
		else if( c_oSerSimplePos.Y === type )
			oSimplePos.Y = this.bcr.ReadDouble();
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
	}
	this.ReadWrapSquare = function(type, length, wrappingPolygon)
	{
		var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerWrapSquare.DistL === type )
			var DistL = this.bcr.ReadDouble();
		else if( c_oSerWrapSquare.DistT === type )
			var DistT = this.bcr.ReadDouble();
		else if( c_oSerWrapSquare.DistR === type )
			var DistR = this.bcr.ReadDouble();
		else if( c_oSerWrapSquare.DistB === type )
			var DistB = this.bcr.ReadDouble();
		else if( c_oSerWrapSquare.WrapText === type )
			var WrapText = this.stream.GetUChar();
		else if( c_oSerWrapSquare.EffectExtent === type )
		{
			var EffectExtent = {Left: null, Top: null, Right: null, Bottom: null};
			res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadEffectExtent(t, l, EffectExtent);
                });
		}
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
	}
	this.ReadWrapThroughTight = function(type, length, wrappingPolygon)
	{
		var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerWrapThroughTight.DistL === type )
			var DistL = this.bcr.ReadDouble();
		else if( c_oSerWrapThroughTight.DistR === type )
			var DistR = this.bcr.ReadDouble();
		else if( c_oSerWrapThroughTight.WrapText === type )
			var WrapText = this.stream.GetUChar();
		else if( c_oSerWrapThroughTight.WrapPolygon === type && wrappingPolygon !== undefined)
		{
            wrappingPolygon.tempArrPoints = [];
			var oStartRes = {start: null};
			res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadWrapPolygon(t, l, wrappingPolygon, oStartRes);
                });
            if(null != oStartRes.start)
                wrappingPolygon.tempArrPoints.unshift(oStartRes.start);
            wrappingPolygon.setArrRelPoints(wrappingPolygon.tempArrPoints);
            delete wrappingPolygon.tempArrPoints;
		}
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
	}
	this.ReadWrapTopBottom = function(type, length, wrappingPolygon)
	{
		var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerWrapTopBottom.DistT === type )
			var DistT = this.bcr.ReadDouble();
		else if( c_oSerWrapTopBottom.DistB === type )
			var DistB = this.bcr.ReadDouble();
		else if( c_oSerWrapTopBottom.EffectExtent === type )
		{
			var EffectExtent = {L: null, T: null, R: null, B: null};
			res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadEffectExtent(t, l, EffectExtent);
                });
		}
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
	}
	this.ReadWrapPolygon = function(type, length, wrappingPolygon, oStartRes)
	{
		var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerWrapPolygon.Edited === type )
			wrappingPolygon.setEdited(this.stream.GetBool());
		else if( c_oSerWrapPolygon.Start === type )
		{
			oStartRes.start = new CPolygonPoint();
			res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadPolygonPoint(t, l, oStartRes.start);
                });
		}
		else if( c_oSerWrapPolygon.ALineTo === type )
		{
			res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadLineTo(t, l, wrappingPolygon.tempArrPoints);
                });
		}
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
	}
	this.ReadLineTo = function(type, length, arrPoints)
	{
		var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerWrapPolygon.LineTo === type )
		{
			var oPoint = new CPolygonPoint();
			res = this.bcr.Read2(length, function(t, l){
                    return oThis.ReadPolygonPoint(t, l, oPoint);
                });
			arrPoints.push(oPoint);
		}
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
	}
	this.ReadPolygonPoint = function(type, length, oPoint)
	{
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerPoint2D.X === type )
            oPoint.x = (this.bcr.ReadDouble()*36000 >> 0);
        else if( c_oSerPoint2D.Y === type )
            oPoint.y = (this.bcr.ReadDouble()*36000 >> 0);
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
	}
	this.ReadDocTable = function(type, length, table, tableFlow)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerDocTableType.tblPr === type )
        {
			table.Set_TableStyle2(null);
			var oNewTablePr = new CTablePr();
            res = this.bcr.Read1(length, function(t, l){
                return oThis.btblPrr.Read_tblPr(t,l, oNewTablePr, table);
            });
			table.Pr = oNewTablePr;
			this.oReadResult.aPostOpenStyleNumCallbacks.push(function(){
				table.Set_Pr(oNewTablePr);
			});
        }
        else if( c_oSerDocTableType.tblGrid === type )
        {
			var aNewGrid = [];
            res = this.bcr.Read2(length, function(t, l){
                return oThis.Read_tblGrid(t,l, aNewGrid);
            });
			table.SetTableGrid(aNewGrid);
        }
        else if( c_oSerDocTableType.Content === type )
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.Read_TableContent(t, l, table);
            });
			if(table.Content.length > 0)
				table.CurCell = table.Content[0].Get_Cell( 0 );
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.Read_tblGrid = function(type, length, tblGrid)
    {
        var res = c_oSerConstants.ReadOk;
        if( c_oSerDocTableType.tblGrid_Item === type )
        {
            tblGrid.push(this.bcr.ReadDouble());
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.Read_TableContent = function(type, length, table)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        var Content = table.Content;
        if( c_oSerDocTableType.Row === type )
        {
            var row = table.Internal_Add_Row(table.Content.length, 0);
            res = this.bcr.Read1(length, function(t, l){
                return oThis.Read_Row(t, l, row);
            });
		} else if( c_oSerDocTableType.Sdt === type ) {
			res = this.bcr.Read1(length, function(t, l){
				return oThis.ReadSdt(t,l, null, 2, table);
			});
		} else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.Read_Row = function(type, length, Row)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerDocTableType.Row_Pr === type )
        {
			var oNewRowPr = new CTableRowPr();
            res = this.bcr.Read2(length, function(t, l){
                return oThis.btblPrr.Read_RowPr(t, l, oNewRowPr);
            });
			Row.Set_Pr(oNewRowPr);
        }
        else if( c_oSerDocTableType.Row_Content === type )
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadRowContent(t, l, Row);
            });
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.ReadRowContent = function(type, length, row)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        var Content = row.Content;
        if( c_oSerDocTableType.Cell === type )
        {
			var oCell = row.Add_Cell(row.Get_CellsCount(), row, null, false);
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadCell(t, l, oCell);
            });
		} else if( c_oSerDocTableType.Sdt === type ) {
			res = this.bcr.Read1(length, function(t, l){
				return oThis.ReadSdt(t,l, null, 3, row);
			});
		} else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.ReadCell = function(type, length, cell)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if( c_oSerDocTableType.Cell_Pr === type )
        {
			var oNewCellPr = new CTableCellPr();
            res = this.bcr.Read2(length, function(t, l){
                return oThis.btblPrr.Read_CellPr(t, l, oNewCellPr);
            });
			cell.Set_Pr(oNewCellPr);
        }
        else if( c_oSerDocTableType.Cell_Content === type )
        {
			var oCellContent = [];
			var oCellContentReader = new Binary_DocumentTableReader(cell.Content, this.oReadResult, this.openParams, this.stream, this.curFootnote, this.oComments);
			oCellContentReader.aFields = this.aFields;
			oCellContentReader.nCurCommentsCount = this.nCurCommentsCount;
			oCellContentReader.oCurComments = this.oCurComments;
			oCellContentReader.Read(length, oCellContent);
			this.nCurCommentsCount = oCellContentReader.nCurCommentsCount;
			if(oCellContent.length > 0)
			{
				for(var i = 0; i < oCellContent.length; ++i)
				{
					if(i == oCellContent.length - 1)
						cell.Content.Internal_Content_Add(i + 1, oCellContent[i], true);
					else
						cell.Content.Internal_Content_Add(i + 1, oCellContent[i], false);
				}
				cell.Content.Internal_Content_Remove(0, 1);
			}
			//если 0 == oCellContent.length в ячейке остается параграф который был там при создании.
        } else if( c_oSerDocTableType.tblGridChange === type ) {
            res = c_oSerConstants.ReadUnknown;//todo
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadSdt = function(type, length, oSdt, typeContainer, container) {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerSdt.Pr === type) {
			if (oSdt) {
				var sdtPr = new AscCommonWord.CSdtPr();
				res = this.bcr.Read1(length, function(t, l) {
					return oThis.ReadSdtPr(t, l, sdtPr);
				});
				oSdt.SetPr(sdtPr);
			} else {
				res = c_oSerConstants.ReadUnknown;
			}
		} else if (c_oSerSdt.EndPr === type) {
			res = c_oSerConstants.ReadUnknown;
			// if (0 === typeContainer) {
			// 	oSdt.EndPr = new CTextPr();
			// 	res = this.brPrr.Read(length, oSdt.EndPr, null);
			// } else {
			// 	res = c_oSerConstants.ReadUnknown;
			// }
		} else if (c_oSerSdt.Content === type) {
			if (0 === typeContainer) {
				var oSdtContent = [];
				var oSdtContentReader = new Binary_DocumentTableReader(oSdt.Content, this.oReadResult, this.openParams,
					this.stream, this.curFootnote, this.oComments);
				oSdtContentReader.aFields = this.aFields;
				oSdtContentReader.nCurCommentsCount = this.nCurCommentsCount;
				oSdtContentReader.oCurComments = this.oCurComments;
				oSdtContentReader.Read(length, oSdtContent);
				this.nCurCommentsCount = oSdtContentReader.nCurCommentsCount;
				if (oSdtContent.length > 0) {
					for (var i = 0; i < oSdtContent.length; ++i) {
						if (i == oSdtContent.length - 1) {
							oSdt.Content.Internal_Content_Add(i + 1, oSdtContent[i], true);
						} else {
							oSdt.Content.Internal_Content_Add(i + 1, oSdtContent[i], false);
						}
					}
					oSdt.Content.Internal_Content_Remove(0, 1);
				}
			} else if (1 === typeContainer) {
				res = this.bcr.Read1(length, function(t, l) {
					return oThis.ReadParagraphContent(t, l, container);
				});
			} else if (2 === typeContainer) {
				res = this.bcr.Read1(length, function(t, l) {
					return oThis.Read_TableContent(t, l, container);
				});
			} else if (3 === typeContainer) {
				res = this.bcr.Read1(length, function(t, l) {
					return oThis.ReadRowContent(t, l, container);
				});
			}
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	};
	this.ReadSdtPr = function(type, length, oSdtPr) {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		/*if (c_oSerSdt.Type === type) {
			oSdtPr.Type = this.stream.GetByte();
		} else */if (c_oSerSdt.Alias === type) {
			oSdtPr.Alias = this.stream.GetString2LE(length);
		} else if (c_oSerSdt.Appearance === type) {
			var Appearance = this.stream.GetByte();
			if(Appearance == Asc.c_oAscSdtAppearance.Frame || Appearance == Asc.c_oAscSdtAppearance.Hidden){
				oSdtPr.Appearance = Appearance;
			}
		// } else if (c_oSerSdt.ComboBox === type) {
		// 	oSdtPr.ComboBox = {};
		// 	res = this.bcr.Read1(length, function(t, l) {
		// 		return oThis.ReadSdtComboBox(t, l, oSdtPr.ComboBox);
		// 	});
		} else if (c_oSerSdt.Color === type) {
			var textPr = new CTextPr();
			res = this.brPrr.Read(length, textPr, null);
			if(textPr.Color){
				oSdtPr.Color = textPr.Color;
			}
		// } else if (c_oSerSdt.DataBinding === type) {
		// 	oSdtPr.DataBinding = {};
		// 	res = this.bcr.Read1(length, function(t, l) {
		// 		return oThis.ReadSdtPrDataBinding(t, l, oSdtPr.DataBinding);
		// 	});
		// } else if (c_oSerSdt.PrDate === type) {
		// 	oSdtPr.PrDate = {};
		// 	res = this.bcr.Read1(length, function(t, l) {
		// 		return oThis.ReadSdtPrDate(t, l, oSdtPr.PrDate);
		// 	});
		// } else if (c_oSerSdt.DocPartList === type) {
		// 	oSdtPr.DocPartList = {};
		// 	res = this.bcr.Read1(length, function(t, l) {
		// 		return oThis.ReadDocPartList(t, l, oSdtPr.DocPartList);
		// 	});
		} else if (c_oSerSdt.DocPartObj === type) {
			res = this.bcr.Read1(length, function(t, l) {
				return oThis.ReadDocPartList(t, l, oSdtPr.DocPartObj);
			});
		// } else if (c_oSerSdt.DropDownList === type) {
		// 	oSdtPr.DropDownList = {};
		// 	res = this.bcr.Read1(length, function(t, l) {
		// 		return oThis.ReadSdtComboBox(t, l, oSdtPr.DropDownList);
		// 	});
		} else if (c_oSerSdt.Id === type) {
			oSdtPr.Id = this.stream.GetLongLE();
		} else if (c_oSerSdt.Label === type) {
			oSdtPr.Label = this.stream.GetLongLE();
		} else if (c_oSerSdt.Lock === type) {
			oSdtPr.Lock = this.stream.GetByte();
		// } else if (c_oSerSdt.PlaceHolder === type) {
		// 	oSdtPr.PlaceHolder = this.stream.GetString2LE(length);
		// } else if (c_oSerSdt.RPr === type) {
		// 	oSdtPr.RPr = new CTextPr();
		// 	res = this.brPrr.Read(length, oSdtPr.RPr, null);
		// } else if (c_oSerSdt.ShowingPlcHdr === type) {
		// 	oSdtPr.ShowingPlcHdr = (this.stream.GetUChar() != 0);
		// } else if (c_oSerSdt.TabIndex === type) {
		// 	oSdtPr.TabIndex = this.stream.GetLongLE();
		} else if (c_oSerSdt.Tag === type) {
			oSdtPr.Tag = this.stream.GetString2LE(length);
		// } else if (c_oSerSdt.Temporary === type) {
		// 	oSdtPr.Temporary = (this.stream.GetUChar() != 0);
		// } else if (c_oSerSdt.MultiLine === type) {
		// 	oSdtPr.MultiLine = (this.stream.GetUChar() != 0);
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	};
	this.ReadSdtComboBox = function(type, length, val) {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerSdt.LastValue === type) {
			val.LastValue = this.stream.GetString2LE(length);
		} else if (c_oSerSdt.SdtListItem === type) {
			var listItem = {};
			res = this.bcr.Read1(length, function(t, l) {
				return oThis.ReadSdtListItem(t, l, listItem);
			});
			if (!val.List) {
				val.List = [];
			}
			val.List.push(listItem);
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	};
	this.ReadSdtListItem = function(type, length, val) {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerSdt.DisplayText === type) {
			val.DisplayText = this.stream.GetString2LE(length);
		} else if (c_oSerSdt.Value === type) {
			val.Value = this.stream.GetString2LE(length);
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	};
	this.ReadSdtPrDataBinding = function(type, length, val) {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerSdt.PrefixMappings === type) {
			val.PrefixMappings = this.stream.GetString2LE(length);
		} else if (c_oSerSdt.StoreItemID === type) {
			val.StoreItemID = this.stream.GetString2LE(length);
		} else if (c_oSerSdt.XPath === type) {
			val.XPath = this.stream.GetString2LE(length);
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	};
	this.ReadSdtPrDate = function(type, length, val) {
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerSdt.FullDate === type) {
			val.FullDate = this.stream.GetString2LE(length);
		} else if (c_oSerSdt.Calendar === type) {
			val.Calendar = this.stream.GetUChar();
		} else if (c_oSerSdt.DateFormat === type) {
			val.DateFormat = this.stream.GetString2LE(length);
		} else if (c_oSerSdt.Lid === type) {
			val.Lid = this.stream.GetString2LE(length);
		} else if (c_oSerSdt.StoreMappedDataAs === type) {
			val.StoreMappedDataAs = this.stream.GetUChar();
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	};
	this.ReadDocPartList = function(type, length, val) {
		var res = c_oSerConstants.ReadOk;
		if (c_oSerSdt.DocPartCategory === type) {
			val.Category = this.stream.GetString2LE(length);
		} else if (c_oSerSdt.DocPartGallery === type) {
			val.Gallery = this.stream.GetString2LE(length);
		} else if (c_oSerSdt.DocPartUnique === type) {
			val.Unique = (this.stream.GetUChar() != 0);
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	};
};
function Binary_oMathReader(stream, oReadResult, curFootnote)
{	
    this.stream = stream;
	this.oReadResult = oReadResult;
	this.curFootnote = curFootnote;
	this.bcr = new Binary_CommonReader(this.stream);
	this.brPrr = new Binary_rPrReader(null, oReadResult, this.stream);
	
	this.ReadRun = function (type, length, oRunObject, oParStruct, oRes)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        if (c_oSerRunType.rPr === type)
        {
            var rPr = oRunObject.Pr;
            res = this.brPrr.Read(length, rPr, oRunObject);
            oRunObject.Set_Pr(rPr);
        }
        else if (c_oSerRunType.Content === type)
        {
            var oPos = { run: oRunObject , pos: 0};
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadRunContent(t, l, oPos, oParStruct, oRes);
            });
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadRunContent = function (type, length, oPos, oParStruct, oRes)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
        var oNewElem = null;
        if (c_oSerRunType.run === type)
        {
            var text = this.stream.GetString2LE(length);

			for (var i = 0; i < text.length; ++i)
			{
			    var nUnicode = null;
			    var nCharCode = text.charCodeAt(i);
			    if (AscCommon.isLeadingSurrogateChar(nCharCode))
			    {
			        if(i + 1 < text.length)
			        {
			            i++;
			            var nTrailingChar = text.charCodeAt(i);
			            nUnicode = AscCommon.decodeSurrogateChar(nCharCode, nTrailingChar);
			        }
			    }
			    else
			        nUnicode = nCharCode;

			    if (null != nUnicode) {
					if (0x20 !== nUnicode)
						oPos.run.AddToContent(oPos.pos, new ParaText(nUnicode), false);
					else
						oPos.run.AddToContent(oPos.pos, new ParaSpace(), false);
			        oPos.pos++;
			    }
            }
        }
        else if (c_oSerRunType.tab === type)
        {
            oNewElem = new ParaTab();
        }
        else if (c_oSerRunType.pagenum === type)
        {
            oNewElem = new ParaPageNum();
        }
        else if (c_oSerRunType.pagebreak === type)
        {
            oNewElem = new ParaNewLine( break_Page );
        }
        else if (c_oSerRunType.linebreak === type)
        {
            oNewElem = new ParaNewLine( break_Line );
        }
        else if (c_oSerRunType.columnbreak === type)
        {
            oNewElem = new ParaNewLine( break_Column );
        }
        else if (c_oSerRunType.cr === type)
        {
            oNewElem = new ParaNewLine( break_Line );
        }
        else if (c_oSerRunType.nonBreakHyphen === type)
        {
            oNewElem = new ParaText(0x002D);
            oNewElem.Set_SpaceAfter(false);
        }
        else if (c_oSerRunType.softHyphen === type)
        {
            //todo
        }
		else if (c_oSerRunType.separator === type)
		{
			oNewElem = new ParaSeparator();
		}
		else if (c_oSerRunType.continuationSeparator === type)
		{
			oNewElem = new ParaContinuationSeparator();
		}
		else if (c_oSerRunType.footnoteRef === type)
		{
			if (this.curFootnote) {
				oNewElem = new ParaFootnoteRef(this.curFootnote);
			}
		}
		else if (c_oSerRunType.footnoteReference === type)
		{
			var ref = {id: null, customMark: null};
			res = this.bcr.Read1(length, function(t, l) {
				return oThis.ReadFootnoteRef(t, l, ref);
			});
			var footnote = this.oReadResult.footnotes[ref.id];
			if (footnote) {
				this.oReadResult.logicDocument.Footnotes.AddFootnote(footnote.content);
				oNewElem = new ParaFootnoteReference(footnote.content, ref.customMark);
			}
		}
        else if (c_oSerRunType._LastRun === type)
            this.oReadResult.bLastRun = true;
        else
            res = c_oSerConstants.ReadUnknown;
        if (null != oNewElem)
        {
            oPos.run.Add_ToContent(oPos.pos, oNewElem, false);
            oPos.pos++;
        }
        return res;
    };
	
	this.ReadMathAcc = function(type, length, props, oParent, oContent, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.AccPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathAccPr(t,l,props);
            });
			var oMathAcc = new CAccent(props);
            initMathRevisions(oMathAcc, props);
			if (oParent)
				oParent.addElementToContent(oMathAcc);
			if(oParStruct)
			    oMathAcc.Paragraph = oParStruct.paragraph;
			oContent.content = oMathAcc.getBase();
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oContent.content, oParStruct);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathAccPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.Chr === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathChr(t,l,props, c_oSer_OMathChrType.Chr);
            });			
        }
		else if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });	           	
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathAln = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		props.aln = false;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.aln = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathAlnScr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.alnScr = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathArg = function(type, length, oElem, oParStruct)
    {
		var bLast = this.bcr.stream.bLast;
			
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		var props = {};
		if (c_oSer_OMathContentType.Acc === type)
        {
			var oContent = {};
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathAcc(t,l,props,oElem,oContent, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.ArgPr === type)
        {
			//этой обертки пока нет
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArgPr(t,l,oElem);
            });
        }		
		else if (c_oSer_OMathContentType.Bar === type)
        {
			var oContent = {};
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathBar(t,l,props,oElem, oContent, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.BorderBox === type)
        {			
			var oContent = {};
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathBorderBox(t,l,props,oElem, oContent, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.Box === type)
        {
			var oContent = {};
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathBox(t,l,props,oElem,oContent, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.CtrlPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });
			oElem.setCtrPrp(props.ctrlPr);
        }
		else if (c_oSer_OMathContentType.Delimiter === type)
        {
			var arrContent = [];
            res = this.bcr.Read1(length, function(t, l){				
                return oThis.ReadMathDelimiter(t,l,props,oElem,arrContent, oParStruct);
            });			
        }	
		else if (c_oSer_OMathContentType.Del === type)
		{
			var reviewInfo = new CReviewInfo();
			var oSdt = new AscCommonWord.CInlineLevelSdt();
			oSdt.SetParagraph(oParStruct.paragraph);
			var oSdtStruct = new OpenParStruct(oSdt, oParStruct.paragraph);
			res = this.bcr.Read1(length, function(t, l){
				return ReadTrackRevision(t, l, oThis.stream, reviewInfo, {parStruct: oSdtStruct, bdtr: oThis.oReadResult.bdtr});
			});
			if (oElem) {
				for (var i = 0; i < oSdtStruct.GetContentLength(); ++i) {
					var elem = oSdtStruct.GetFromContent(i);
					if (elem && elem.Set_ReviewTypeWithInfo) {
						elem.Set_ReviewTypeWithInfo(reviewtype_Remove, reviewInfo);
					}
					oElem.addElementToContent(elem);
				}
			}
		}
		else if (c_oSer_OMathContentType.EqArr === type)
        {				
			var arrContent = [];
            res = this.bcr.Read1(length, function(t, l){				
                return oThis.ReadMathEqArr(t,l,props,oElem,arrContent, oParStruct);
            });
			if (props.mcJc)
			{
				var oEqArr = oElem.Content[oElem.Content.length-1];
				for(var j=0; j<oEqArr.Content.length; j++)
				{
					var oContentElem = oEqArr.Content[j];
					if (oContentElem.Content.length == 0)
						oContentElem.SetPlaceholder();
				}
				oEqArr.setJustificationForConversion(props.mcJc);
			}		
        }
		else if (c_oSer_OMathContentType.Fraction === type)
        {
			var oElemDen = {};
			var oElemNum = {};
            res = this.bcr.Read1(length, function(t, l){				
                return oThis.ReadMathFraction(t,l,props,oElem,oElemDen,oElemNum, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.Func === type)
        {
			var oContent = {};
			var oName = {};
            res = this.bcr.Read1(length, function(t, l){				
                return oThis.ReadMathFunc(t,l,props,oElem,oContent,oName, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.GroupChr === type)
        {
			var oContent = {};
            res = this.bcr.Read1(length, function(t, l){				
                return oThis.ReadMathGroupChr(t,l,props,oElem,oContent, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.Ins === type)
		{
			var reviewInfo = new CReviewInfo();
			var oSdt = new AscCommonWord.CInlineLevelSdt();
			oSdt.SetParagraph(oParStruct.paragraph);
			var oSdtStruct = new OpenParStruct(oSdt, oParStruct.paragraph);
			res = this.bcr.Read1(length, function(t, l){
				return ReadTrackRevision(t, l, oThis.stream, reviewInfo, {parStruct: oSdtStruct, bdtr: oThis.oReadResult.bdtr});
			});
			if (oElem) {
				for (var i = 0; i < oSdtStruct.GetContentLength(); ++i) {
					var elem = oSdtStruct.GetFromContent(i);
					if (elem && elem.Set_ReviewTypeWithInfo) {
						elem.Set_ReviewTypeWithInfo(reviewtype_Add, reviewInfo);
					}
					oElem.addElementToContent(elem);
				}
			}
		}
		else if (c_oSer_OMathContentType.LimLow === type)
        {
			var oContent = {};
			var oLim = {};
            res = this.bcr.Read1(length, function(t, l){				
                return oThis.ReadMathLimLow(t,l,props,oElem,oContent,oLim, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.LimUpp === type)
        {
			var oContent = {};
			var oLim = {};
            res = this.bcr.Read1(length, function(t, l){				
                return oThis.ReadMathLimUpp(t,l,props,oElem,oContent,oLim, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.Matrix === type)
        {
			var arrContent = [];
			props.mcs = [];
            res = this.bcr.Read1(length, function(t, l){				
				return oThis.ReadMathMatrix(t, l, props, arrContent, oParStruct);
			});
			if (oElem) {
				//create props by content, important  before creation matrix
				var rowMax = arrContent.length;
				var colMax = 0;
				for (var i = 0; i < arrContent.length; ++i) {
					var row = arrContent[i];
					if(colMax < row.length) {
						colMax = row.length;
					}
				}
				props.row = rowMax;
				var colMaxMc = 0;
				for (var i = 0; i < props.mcs.length; ++i) {
					colMaxMc += props.mcs[i].count;
				}
				if (colMaxMc < colMax) {
					props.mcs.push({count: colMax - colMaxMc, mcJc: MCJC_CENTER});
				}
				//create matrix
				var oMatrix = new CMathMatrix(props);
				initMathRevisions(oMatrix, props);
				oElem.addElementToContent(oMatrix);
				//read rows
				var nOldPos = this.stream.GetCurPos();
				for (var i = 0; i < arrContent.length; ++i) {
					var row = arrContent[i];
					for (var j = 0 ; j < row.length; ++j) {
						var cell = row[j];
						this.stream.Seek2(cell.pos);
						res = this.bcr.Read1(cell.length, function(t, l){
							return oThis.ReadMathArg(t, l, oMatrix.getElement(i, j), oParStruct);
						});	
					}
				}
				this.stream.Seek2(nOldPos);
			}
        }			
		else if (c_oSer_OMathContentType.Nary === type)
        {
			var oContent = {};
			var oSub = {};
			var oSup = {};
            res = this.bcr.Read1(length, function(t, l){				
                return oThis.ReadMathNary(t,l,props,oElem,oContent,oSub,oSup, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.OMath === type)
        {		
            res = this.bcr.Read1(length, function(t, l){				
                return oThis.ReadMathArg(t,l,oElem, oParStruct);
            });
        }
		else if (c_oSer_OMathContentType.Phant === type)
        {
			var oContent = {};
            res = this.bcr.Read1(length, function(t, l){				
                return oThis.ReadMathPhant(t,l,props,oElem,oContent, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.MRun === type)
        {
            var oParagraph = oParStruct ? oParStruct.paragraph : null;
			var oMRun = new ParaRun(oParagraph, true);
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathMRun(t,l,oMRun,props,oElem,oParStruct);
            });
			if (oElem)	
				oElem.addElementToContent(oMRun);
        }
		else if (c_oSer_OMathContentType.Rad === type)
        {
			var oContent = {};
			var oDeg = {};
			var oRad = {};
            res = this.bcr.Read1(length, function(t, l){				
                return oThis.ReadMathRad(t,l,props,oElem,oRad,oContent,oDeg, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.SPre === type)
        {
			var oContent = {};
			var oSub = {};
			var oSup = {};
            res = this.bcr.Read1(length, function(t, l){				
                return oThis.ReadMathSPre(t,l,props,oElem,oContent,oSub,oSup, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.SSub === type)
        {
			var oContent = {};
			var oSub = {};
            res = this.bcr.Read1(length, function(t, l){				
                return oThis.ReadMathSSub(t,l,props,oElem,oContent,oSub, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.SSubSup === type)
        {
			var oContent = {};
			var oSub = {};
			var oSup = {};
            res = this.bcr.Read1(length, function(t, l){				
                return oThis.ReadMathSSubSup(t,l,props,oElem,oContent,oSub,oSup, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.SSup === type)
        {
			var oContent = {};
			var oSup = {};
            res = this.bcr.Read1(length, function(t, l){				
                return oThis.ReadMathSSup(t,l,props,oElem,oContent,oSup, oParStruct);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
			
		if (oElem && bLast)
			oElem.Correct_Content(false);

        return res;
    };		
	this.ReadMathArgPr = function(type, length, oElem)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.ArgSz === type)
        {
			var props = {};
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathArgSz(t,l,props);
            });
			oElem.SetArgSize(props.argSz);
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathArgSz = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.argSz = this.stream.GetULongLE();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathBar = function(type, length,props, oParent, oContent, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.BarPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathBarPr(t,l,props,oBar);
            });		
			var oBar = new CBar(props);
            initMathRevisions(oBar, props);
			if (oParent)
				oParent.addElementToContent(oBar);

            if(oParStruct)
                oBar.Paragraph = oParStruct.paragraph;
			oContent.content = oBar.getBase();
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oContent.content, oParStruct);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathBarPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.Pos === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathPos(t,l,props);
            });		
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathBaseJc = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var baseJc = this.stream.GetUChar(length);
			switch (baseJc)
			{
				case c_oAscYAlign.Bottom:	props.baseJc = BASEJC_BOTTOM; break;
				case c_oAscYAlign.Center:	props.baseJc = BASEJC_CENTER; break;
				case c_oAscYAlign.Top:		props.baseJc = BASEJC_TOP; break;
				default: props.baseJc = BASEJC_TOP;
			}
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathBorderBox = function(type, length, props, oParent, oContent, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.BorderBoxPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathBorderBoxPr(t,l,props);
            });	
			var oBorderBox = new CBorderBox(props);
            initMathRevisions(oBorderBox, props);
			if (oParent)
				oParent.addElementToContent(oBorderBox);
            if(oParStruct)
                oBorderBox.Paragraph = oParStruct.paragraph;
			oContent.content = oBorderBox.getBase();
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oContent.content, oParStruct);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathBorderBoxPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.HideBot === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathHideBot(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.HideLeft === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathHideLeft(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.HideRight === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathHideRight(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.HideTop === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathHideTop(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.StrikeBLTR === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathStrikeBLTR(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.StrikeH === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathStrikeH(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.StrikeTLBR === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathStrikeTLBR(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.StrikeV === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathStrikeV(t,l,props);
            });		
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathBox = function(type, length, props, oParent, oContent, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.BoxPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathBoxPr(t,l,props);
            });
			var oBox = new CBox(props);
            initMathRevisions(oBox, props);
			if (oParent)
				oParent.addElementToContent(oBox);
            if(oParStruct)
                oBox.Paragraph = oParStruct.paragraph;
			oContent.content = oBox.getBase();
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oContent.content, oParStruct);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathBoxPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.Aln === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathAln(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.Brk === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathBrk(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.Diff === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathDiff(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.NoBreak === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathNoBreak(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.OpEmu === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathOpEmu(t,l,props);
            });		
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathBrk = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var brk = this.stream.GetBool();
			props.brk = {};
        }
		else if (c_oSer_OMathBottomNodesValType.AlnAt === type)
        {
			var aln = this.stream.GetULongLE();
			props.brk = { alnAt:aln};
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathCGp = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
		
		if(c_oSer_OMathBottomNodesValType.Val == type)
            props.cGp = this.stream.GetULongLE();

        return res;
    };
	this.ReadMathCGpRule = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
		
        if(c_oSer_OMathBottomNodesValType.Val == type)
            props.cGpRule = this.stream.GetULongLE();
			
        return res;
    };
	this.ReadMathCSp = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
		
		if(c_oSer_OMathBottomNodesValType.Val == type)
            props.cSp = this.stream.GetULongLE();

        return res;
    };
	this.ReadMathColumn = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
		props.column = 0;
		
		if(c_oSer_OMathBottomNodesValType.Val == type)
            props.column = this.stream.GetULongLE();

        return res;
    };
	this.ReadMathCount = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
		props.count = 0;
		
		if(c_oSer_OMathBottomNodesValType.Val == type)
            props.count = this.stream.GetULongLE();

        return res;
    };
	this.ReadMathChr = function(type, length, props, typeChr)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var text = this.stream.GetString2LE(length);
            var aUnicode = AscCommon.convertUTF16toUnicode(text);

            var chr = (aUnicode.length <= 0 ? OPERATOR_EMPTY : aUnicode[0]);

            switch (typeChr)
            {
                default:
                case c_oSer_OMathChrType.Chr:    props.chr    = chr; break;
                case c_oSer_OMathChrType.BegChr: props.begChr = chr; break;
                case c_oSer_OMathChrType.EndChr: props.endChr = chr; break;
                case c_oSer_OMathChrType.SepChr: props.sepChr = chr; break;
            }
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathCtrlPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSerRunType.rPr === type) {
			var MathTextRPr = new CTextPr();
			res = this.brPrr.Read(length, MathTextRPr, null);
			props.ctrPrp = MathTextRPr;
		} else if (c_oSerRunType.arPr === type) {
			props.ctrPrp = pptx_content_loader.ReadRunProperties(this.stream);
		} else if (c_oSerRunType.del === type) {
            var rPrChange = new CTextPr();
            var reviewInfo = new CReviewInfo();
            var brPrr = new Binary_rPrReader(this.Document, this.oReadResult, this.stream);
            res = this.bcr.Read1(length, function(t, l){
                return ReadTrackRevision(t, l, oThis.stream, reviewInfo, {brPrr: brPrr, rPr: rPrChange});
            });
            props.del = reviewInfo;
		} else if (c_oSerRunType.ins === type) {
            var rPrChange = new CTextPr();
            var reviewInfo = new CReviewInfo();
            var brPrr = new Binary_rPrReader(this.Document, this.oReadResult, this.stream);
            res = this.bcr.Read1(length, function(t, l){
                return ReadTrackRevision(t, l, oThis.stream, reviewInfo, {brPrr: brPrr, rPr: rPrChange});
            });
            props.ins = reviewInfo;
		}
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };		
	this.ReadMathDelimiter = function(type, length, props, oElem, arrContent, oParStruct)
    {		
        var res = c_oSerConstants.ReadOk;
        var oThis = this;		
		
		if (c_oSer_OMathContentType.DelimiterPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathDelimiterPr(t,l,props);
            });				
			props.counter = 0;
			var oDelimiter = new CDelimiter(props);
            initMathRevisions(oDelimiter, props);
			oElem.addElementToContent(oDelimiter);
            if(oParStruct)
                oDelimiter.Paragraph = oParStruct.paragraph;
			for (var i=0; i<props.column; i++)
				arrContent[i] = oDelimiter.getBase(i);
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
			var lColumn = props.counter;
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,arrContent[lColumn], oParStruct);
            });		
			props.counter++;			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathDelimiterPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.Column === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathColumn(t,l,props);
            });	
        }
		else if (c_oSer_OMathBottomNodesType.BegChr === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathChr(t,l,props, c_oSer_OMathChrType.BegChr);
            });			
        }
		else if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });	           	
        }
		else if (c_oSer_OMathBottomNodesType.EndChr === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathChr(t,l,props, c_oSer_OMathChrType.EndChr);
            });			
        }
		else if (c_oSer_OMathBottomNodesType.Grow === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathGrow(t,l,props);
            });			
        }
		else if (c_oSer_OMathBottomNodesType.SepChr === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathChr(t,l,props, c_oSer_OMathChrType.SepChr);
            });			
        }
		else if (c_oSer_OMathBottomNodesType.Shp === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathShp(t,l,props);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathDegHide = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.degHide = this.stream.GetBool();
        }		
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathDiff = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.diff = this.stream.GetBool();
        }		
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathEqArr = function(type, length, props, oElem, arrContent, oParStruct)
    {		
        var res = c_oSerConstants.ReadOk;
        var oThis = this;		
		
		if (c_oSer_OMathContentType.EqArrPr === type)
        {			
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathEqArrPr(t,l,props);
            });
			
			if (!props.ctrPrp)
				props.ctrPrp = new CTextPr();
			props.counter = 0;
			var oEqArr = new CEqArray(props);
            initMathRevisions(oEqArr, props);
			oElem.addElementToContent(oEqArr);
            if(oParStruct)
                oEqArr.Paragraph = oParStruct.paragraph;
			for (var i=0; i<props.row; i++)
				arrContent[i] = oEqArr.getElement(i);
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
			var lRow = props.counter;
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,arrContent[lRow], oParStruct);
            });		
			props.counter++;
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathEqArrPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.Row === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathRow(t,l,props);
            });	
        }
		else if (c_oSer_OMathBottomNodesType.BaseJc === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathBaseJc(t,l,props);
            });	
        }		
		else if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });	           	
        }
		else if (c_oSer_OMathBottomNodesType.MaxDist === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathMaxDist(t,l,props);
            });			
        }
		else if (c_oSer_OMathBottomNodesType.McJc === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathMcJc(t,l,props);
            });			
        }
		else if (c_oSer_OMathBottomNodesType.ObjDist === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathObjDist(t,l,props);
            });			
        }
		else if (c_oSer_OMathBottomNodesType.RSp === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathRSp(t,l,props);
            });			
        }
		else if (c_oSer_OMathBottomNodesType.RSpRule === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathRSpRule(t,l,props);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathFraction = function(type, length, props, oParent, oElemDen, oElemNum, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.FPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathFPr(t,l,props);
            });	
			var oFraction = new CFraction(props);
            initMathRevisions(oFraction, props);
			if (oParent)
				oParent.addElementToContent(oFraction);
            if(oParStruct)
                oFraction.Paragraph = oParStruct.paragraph;
			oElemDen.content = oFraction.getDenominator();
			oElemNum.content = oFraction.getNumerator();
        }
		else if (c_oSer_OMathContentType.Den === type)
        {
			if (undefined == oElemDen.content)
			{
				var oFraction = new CFraction(props);
				initMathRevisions(oFraction, props);
				if (oParent)
					oParent.addElementToContent(oFraction);

                if(oParStruct)
                    oFraction.Paragraph = oParStruct.paragraph;
				oElemDen.content = oFraction.getDenominator();
				oElemNum.content = oFraction.getNumerator();
			}
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oElemDen.content, oParStruct);
            });
        }
		else if (c_oSer_OMathContentType.Num === type)
        {
			if (undefined == oElemNum.content)
			{
				var oFraction = new CFraction(props);
				initMathRevisions(oFraction, props);
				if (oParent)
					oParent.addElementToContent(oFraction);
                if(oParStruct)
                    oFraction.Paragraph = oParStruct.paragraph;
				oElemDen.content = oFraction.getDenominator();
				oElemNum.content = oFraction.getNumerator();
			}
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oElemNum.content, oParStruct);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathFPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.Type === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathType(t,l,props);
            });		
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathFunc = function(type, length, props, oParent, oContent, oName, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.FuncPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathFuncPr(t,l,props);
            });
			var oFunc = new CMathFunc(props);
            initMathRevisions(oFunc, props);
			if (oParent)
				oParent.addElementToContent(oFunc);
            if(oParStruct)
                oFunc.Paragraph = oParStruct.paragraph;
			oContent.content = oFunc.getArgument();
			oName.content = oFunc.getFName();
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oContent.content, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.FName === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oName.content, oParStruct);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathFuncPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });		
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathHideBot = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.hideBot = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathGroupChr = function(type, length, props, oParent, oContent, oParStruct)
    {		
        var res = c_oSerConstants.ReadOk;
        var oThis = this;	
		if (c_oSer_OMathContentType.GroupChrPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathGroupChrPr(t,l,props);
            });
			var oGroupChr = new CGroupCharacter(props);
            initMathRevisions(oGroupChr, props);
			if (oParent)
				oParent.addElementToContent(oGroupChr);
            if(oParStruct)
                oGroupChr.Paragraph = oParStruct.paragraph;
			oContent.content = oGroupChr.getBase();
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oContent.content, oParStruct);
            });		
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathGroupChrPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.Chr === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathChr(t,l,props, c_oSer_OMathChrType.Chr);
            });	
        }	
		else if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });	           	
        }
		else if (c_oSer_OMathBottomNodesType.Pos === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathPos(t,l,props);
            });			
        }
		else if (c_oSer_OMathBottomNodesType.VertJc === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathVertJc(t,l,props);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathGrow = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.grow = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathHideLeft = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.hideLeft = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathHideRight = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.hideRight = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathHideTop = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.hideTop = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathLimLoc = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var limLoc = this.stream.GetUChar(length);
			switch (limLoc)
			{
				case c_oAscLimLoc.SubSup:	props.limLoc = NARY_SubSup ; break;
				case c_oAscLimLoc.UndOvr:	props.limLoc = NARY_UndOvr; break;
				default: props.limLoc = NARY_SubSup ;
			}
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathLimLow = function(type, length, props, oParent, oContent, oLim, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.LimLowPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathLimLowPr(t,l,props);
            });
			props.type = LIMIT_LOW;
			var oLimLow = new CLimit(props);
            initMathRevisions(oLimLow, props);
			if (oParent)
				oParent.addElementToContent(oLimLow);

            if(oParStruct)
                oLimLow.Paragraph = oParStruct.paragraph;
			oContent.content = oLimLow.getFName();
			oLim.content = oLimLow.getIterator();
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oContent.content, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.Lim === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oLim.content, oParStruct);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathLimLowPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });		
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathLimUpp = function(type, length, props, oParent, oContent, oLim, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.LimUppPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathLimUppPr(t,l,props);
            });
			props.type = LIMIT_UP;
			var oLimUpp = new CLimit(props);
            initMathRevisions(oLimUpp, props);
			if (oParent)			
				oParent.addElementToContent(oLimUpp);
            if(oParStruct)
                oLimUpp.Paragraph = oParStruct.paragraph;
			oContent.content = oLimUpp.getFName();
			oLim.content = oLimUpp.getIterator();
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oContent.content, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.Lim === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oLim.content, oParStruct);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathLimUppPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });		
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathLit = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.lit = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathMatrix = function(type, length, props, arrContent)
    {		
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.MPr === type)
        {			
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathMPr(t,l,props);
            });			
        }
		else if (c_oSer_OMathContentType.Mr === type)
        {
			var row = [];
            res = this.bcr.Read1(length, function(t, l){
				return oThis.ReadMathMr(t, l, row);
            });
			if (row.length > 0) {
				arrContent.push(row);
			}
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathMc = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.McPr === type)
        {
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathMcPr(t,l,props);
            });		
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathMcJc = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var mcJc = this.stream.GetUChar(length);
			switch (mcJc)
			{
				case c_oAscXAlign.Center:	props.mcJc = MCJC_CENTER; break;
				case c_oAscXAlign.Inside:	props.mcJc = MCJC_INSIDE; break;
				case c_oAscXAlign.Left:		props.mcJc = MCJC_LEFT; break;
				case c_oAscXAlign.Outside:	props.mcJc = MCJC_OUTSIDE; break;
				case c_oAscXAlign.Right:	props.mcJc = MCJC_RIGHT; break;
				default: props.mcJc = MCJC_CENTER;
			}
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathMcPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.Count === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathCount(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.McJc === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathMcJc(t,l,props);
            });		
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathMcs = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.Mc === type)
        {
			var mc = {};
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathMc(t,l,mc);
            });	
			props.mcs.push(mc);
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathMJc = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var mJc = this.stream.GetUChar(length);
			switch (mJc)
			{
				case c_oAscMathJc.Center:		props.mJc = JC_CENTER; break;
				case c_oAscMathJc.CenterGroup:	props.mJc = JC_CENTERGROUP; break;
				case c_oAscMathJc.Left:			props.mJc = JC_LEFT; break;
				case c_oAscMathJc.Right:		props.mJc = JC_RIGHT; break;
				default: props.mJc = JC_CENTERGROUP;
			}
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathMPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.Row === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathRow(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.BaseJc === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathBaseJc(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.CGp === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathCGp(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.CGpRule === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathCGpRule(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.CSp === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathCSp(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.Mcs === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathMcs(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.PlcHide === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathPlcHide(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.RSp === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathRSp(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.RSpRule === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathRSpRule(t,l,props);
            });		
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathMr = function(type, length, arrContent)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.Element === type)
        {
			arrContent.push({pos: this.stream.GetCurPos(), length: length});
			res = c_oSerConstants.ReadUnknown;
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathMaxDist = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.maxDist = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathText = function(type, length, oMRun)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var aUnicodes = [];
            if (length > 0)
                aUnicodes = AscCommon.convertUTF16toUnicode(this.stream.GetString2LE(length));

			for (var nPos = 0, nCount = aUnicodes.length; nPos < nCount; ++nPos)
            {
                var nUnicode = aUnicodes[nPos];

                var oText = null;
                if (0x0026 == nUnicode)
                    oText = new CMathAmp();
                else
                {
                    oText = new CMathText(false);
                    oText.add(nUnicode);
                }
                if (oText)
                    oMRun.Add_ToContent(nPos, oText, false, true);
            }
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathMRun = function(type, length, oMRun, props, oParent, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		var oNewElem = null;

		if (c_oSer_OMathContentType.MText === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathText(t,l,oMRun);
            });            
        }
		else if (c_oSer_OMathContentType.MRPr === type)
        {
			//<m:rPr>
			var mrPr = new CMPrp();
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathMRPr(t,l,mrPr);
            });
			oMRun.Set_MathPr(mrPr);
        }
		else if (c_oSer_OMathContentType.ARPr === type)
		{
			var rPr = pptx_content_loader.ReadRunProperties(this.stream);
            oMRun.Set_Pr(rPr);
		}
		else if (c_oSer_OMathContentType.RPr === type)
		{
			//<w:rPr>
			var rPr = oMRun.Pr;
			res = this.brPrr.Read(length, rPr, oMRun);	
			oMRun.Set_Pr(rPr);
		}
		else if (c_oSer_OMathContentType.pagebreak === type)
        {
            oNewElem = new ParaNewLine( break_Page );
        }
        else if (c_oSer_OMathContentType.linebreak === type)
        {
            oNewElem = new ParaNewLine();
        }
        else if (c_oSer_OMathContentType.columnbreak === type)
        {
            oNewElem = new ParaNewLine( break_Column );
        } else if (c_oSer_OMathContentType.Del === type) {
            var reviewInfo = new CReviewInfo();
			res = this.bcr.Read1(length, function(t, l){
                return ReadTrackRevision(t, l, oThis.stream, reviewInfo, {run: oMRun, props: props, oParent: oParent, parStruct: oParStruct, bmr: oThis});
			});
            oMRun.Set_ReviewTypeWithInfo(reviewtype_Remove, reviewInfo);
        } else if (c_oSer_OMathContentType.Ins === type) {
            var reviewInfo = new CReviewInfo();
			res = this.bcr.Read1(length, function(t, l){
                return ReadTrackRevision(t, l, oThis.stream, reviewInfo, {run: oMRun, props: props, oParent: oParent, parStruct: oParStruct, bmr: oThis});
			});
            oMRun.Set_ReviewTypeWithInfo(reviewtype_Add, reviewInfo);
        }
        else
            res = c_oSerConstants.ReadUnknown;
			
		if (null != oNewElem)
        {
			var oNewRun = new ParaRun(oParStruct.paragraph);
			oNewRun.Add_ToContent(0, oNewElem, false);
			oParStruct.addToContent(oNewRun);
        }
		
        return res;
    };
    this.ReadMathMRPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.Aln === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathAln(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.Brk === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathBrk(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.Lit === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathLit(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.Nor === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathNor(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.Scr === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathScr(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.Sty === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathSty(t,l,props);
            });		
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathNary = function(type, length, props, oParent, oContent, oSub, oSup, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.NaryPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathNaryPr(t,l,props);
            });
			if (!props.ctrPrp)
				props.ctrPrp = new CTextPr();
			var oNary = new CNary(props);
            initMathRevisions(oNary, props);
			if (oParent)
				oParent.addElementToContent(oNary);
            if(oParStruct)
                oNary.Paragraph = oParStruct.paragraph;
			oSub.content = oNary.getLowerIterator();
			oSup.content = oNary.getUpperIterator();
			oContent.content = oNary.getBase();
        }
		else if (c_oSer_OMathContentType.Sub === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oSub.content, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.Sup === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oSup.content, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oContent.content, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.CtrlPr)
		{			
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });
			oParent.Content[oParent.Content.length-1].setCtrPrp(props.ctrPrp);
		}
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathNaryPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.Chr === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathChr(t,l,props, c_oSer_OMathChrType.Chr);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });	           	
        }
		else if (c_oSer_OMathBottomNodesType.Grow === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathGrow(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.LimLoc === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathLimLoc(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.SubHide === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathSubHide(t,l,props);
            });		
        }
		else if (c_oSer_OMathBottomNodesType.SupHide === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathSupHide(t,l,props);
            });		
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathNoBreak = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.noBreak = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathNor = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.nor = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathObjDist = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.objDist = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathOMathPara = function(type, length, oParStruct, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		
		if (c_oSer_OMathContentType.OMath === type)
        {
			var oMath = new ParaMath();
            oMath.Set_Align(props.mJc === JC_CENTER ? align_Center : props.mJc === JC_CENTERGROUP ? align_Justify : (props.mJc === JC_LEFT ? align_Left : (props.mJc === JC_RIGHT ? align_Right : props.mJc)));
			oParStruct.addToContent(oMath);
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oMath.Root,oParStruct);
            });

            oMath.Root.Correct_Content(true);
        }
		else if (c_oSer_OMathContentType.OMathParaPr === type)
		{
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathOMathParaPr(t,l,props);
            });
		}
		else if (c_oSer_OMathContentType.Run === type)
		{
			var oNewRun = new ParaRun(oParStruct.paragraph);
            var oRes = { bRes: true };
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadRun(t, l, oNewRun, oParStruct, oRes);
            });
            //if (oRes.bRes && oNewRun.Content.length > 0)
                oParStruct.addToContent(oNewRun);
		}
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathOMathParaPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.MJc === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathMJc(t,l,props);
            });		
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathOpEmu = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.opEmu = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathPhant = function(type, length, props, oParent, oContent, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.PhantPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathPhantPr(t,l,props);
            });
			var oPhant = new CPhantom(props);
            initMathRevisions(oPhant, props);
			if (oParent)
				oParent.addElementToContent(oPhant);
            if(oParStruct)
                oPhant.Paragraph = oParStruct.paragraph;
			oContent.content = oPhant.getBase();
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oContent.content, oParStruct);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathPhantPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });	           	
        }
		else if (c_oSer_OMathBottomNodesType.Show === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathShow(t,l,props);
            });	           	
        }
		else if (c_oSer_OMathBottomNodesType.Transp === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathTransp(t,l,props);
            });	           	
        }
		else if (c_oSer_OMathBottomNodesType.ZeroAsc === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathZeroAsc(t,l,props);
            });	           	
        }
		else if (c_oSer_OMathBottomNodesType.ZeroDesc === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathZeroDesc(t,l,props);
            });	           	
        }
		else if (c_oSer_OMathBottomNodesType.ZeroWid === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathZeroWid(t,l,props);
            });	           	
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathPlcHide = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.plcHide = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathPos = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var pos = this.stream.GetUChar(length);
			switch (pos)
			{
				case c_oAscTopBot.Bot:	props.pos = LOCATION_BOT; break;
				case c_oAscTopBot.Top:	props.pos = LOCATION_TOP; break;
				default: props.pos = LOCATION_BOT;
			}
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathRad = function(type, length, props, oParent, oRad, oContent, oDeg, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.RadPr === type)
        {			
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathRadPr(t,l,props);
            });
			oRad.content = new CRadical(props);
            initMathRevisions(oRad.content, props);
			if (oParent)
				oParent.addElementToContent(oRad.content);
            if(oParStruct)
                oRad.Paragraph = oParStruct.paragraph;
			oDeg.content = oRad.content.getDegree();
			oContent.content = oRad.content.getBase();
        }
		else if (c_oSer_OMathContentType.Deg === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oDeg.content, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oContent.content, oParStruct);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathRadPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });	           	
        }
		else if (c_oSer_OMathBottomNodesType.DegHide === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathDegHide(t,l,props);
            });	           	
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathRow = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
		props.row = 0;
		
		if(c_oSer_OMathBottomNodesValType.Val == type)
            props.row = this.stream.GetULongLE();

        return res;
    };
	this.ReadMathRSp = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
		
		if(c_oSer_OMathBottomNodesValType.Val == type)
            props.rSp = this.stream.GetULongLE();

        return res;
    };
	this.ReadMathRSpRule = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
		
        if(c_oSer_OMathBottomNodesValType.Val == type)
            props.rSpRule = this.stream.GetULongLE();
			
        return res;
    };
	this.ReadMathScr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var scr = this.stream.GetUChar(length);
			switch (scr)
			{
				case c_oAscScript.DoubleStruck:	props.scr = TXT_DOUBLE_STRUCK; break;
				case c_oAscScript.Fraktur:		props.scr = TXT_FRAKTUR; break;
				case c_oAscScript.Monospace:	props.scr = TXT_MONOSPACE; break;
				case c_oAscScript.Roman:		props.scr = TXT_ROMAN; break;
				case c_oAscScript.SansSerif:	props.scr = TXT_SANS_SERIF; break;
				case c_oAscScript.Script:		props.scr = TXT_SCRIPT; break;
				default: props.scr = TXT_ROMAN;
			}
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathShow = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.show = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathShp = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var shp = this.stream.GetUChar(length);
			switch (shp)
			{
				case c_oAscShp.Centered:	props.shp = DELIMITER_SHAPE_CENTERED; break;
				case c_oAscShp.Match:		props.shp = DELIMITER_SHAPE_MATCH; break;
				default: 					props.shp = DELIMITER_SHAPE_CENTERED;
			}
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathSPre = function(type, length, props, oParent, oContent, oSub, oSup, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.SPrePr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathSPrePr(t,l,props);
            });
			props.type = DEGREE_PreSubSup;
			var oSPre = new CDegreeSubSup(props);
            initMathRevisions(oSPre, props);
			if (oParent)
				oParent.addElementToContent(oSPre);

            if(oParStruct)
                oSPre.Paragraph = oParStruct.paragraph;
			oSub.content = oSPre.getLowerIterator();
			oSup.content = oSPre.getUpperIterator();
			oContent.content = oSPre.getBase();
        }
		else if (c_oSer_OMathContentType.Sub === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oSub.content, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.Sup === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oSup.content, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oContent.content, oParStruct);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathSPrePr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });	           	
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathSSub = function(type, length, props, oParent, oContent, oSub, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.SSubPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathSSubPr(t,l,props);
            });
			props.type = DEGREE_SUBSCRIPT;
			var oSSub = new CDegree(props);
            initMathRevisions(oSSub, props);
			if (oParent)
				oParent.addElementToContent(oSSub);
            if(oParStruct)
                oSSub.Paragraph = oParStruct.paragraph;
			oSub.content = oSSub.getLowerIterator();
			oContent.content = oSSub.getBase();
        }
		else if (c_oSer_OMathContentType.Sub === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oSub.content, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oContent.content, oParStruct);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathSSubPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });	           	
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathSSubSup = function(type, length, props, oParent, oContent, oSub, oSup, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.SSubSupPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathSSubSupPr(t,l,props);
            });
			props.type = DEGREE_SubSup;
			var oSSubSup = new CDegreeSubSup(props);
            initMathRevisions(oSSubSup, props);
			if (oParent)
				oParent.addElementToContent(oSSubSup);
            if(oParStruct)
                oSSubSup.Paragraph = oParStruct.paragraph;
			oSub.content = oSSubSup.getLowerIterator();
			oSup.content = oSSubSup.getUpperIterator();
			oContent.content = oSSubSup.getBase();
        }
		else if (c_oSer_OMathContentType.Sub === type)
        {
			if (undefined == oContent.content)
			{
				props.type = DEGREE_SubSup;
				var oSSubSup = new CDegreeSubSup(props);
				if (oParent)
					oParent.addElementToContent(oSSubSup);
				oSub.content = oSSubSup.getLowerIterator();
				oSup.content = oSSubSup.getUpperIterator();
				oContent.content = oSSubSup.getBase();
			}
			
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oSub.content, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.Sup === type)
        {
			if (undefined == oContent.content)
			{
				props.type = DEGREE_SubSup;
				var oSSubSup = new CDegreeSubSup(props);
				if (oParent)
					oParent.addElementToContent(oSSubSup);
				oSub.content = oSSubSup.getLowerIterator();
				oSup.content = oSSubSup.getUpperIterator();
				oContent.content = oSSubSup.getBase();
			}
			
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oSup.content, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
			if (undefined == oContent.content)
			{
				props.type = DEGREE_SubSup;
				var oSSubSup = new CDegreeSubSup(props);
				if (oParent)
					oParent.addElementToContent(oSSubSup);
				oSub.content = oSSubSup.getLowerIterator();
				oSup.content = oSSubSup.getUpperIterator();
				oContent.content = oSSubSup.getBase();
			}
			
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oContent.content, oParStruct);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathSSubSupPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.AlnScr === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathAlnScr(t,l,props);
            });	           	
        }
		else if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });	           	
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathSSup = function(type, length, props, oParent, oContent, oSup, oParStruct)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathContentType.SSupPr === type)
        {
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathSSupPr(t,l,props);
            });
			props.type = DEGREE_SUPERSCRIPT;
			var oSSup = new CDegree(props);
            initMathRevisions(oSSup, props);
			if (oParent)
				oParent.addElementToContent(oSSup);
            if(oParStruct)
                oSSup.Paragraph = oParStruct.paragraph;
			oSup.content = oSSup.getUpperIterator();
			oContent.content = oSSup.getBase();
        }
		else if (c_oSer_OMathContentType.Sup === type)
        {
			if (undefined == oSup.content)
			{
				props.type = DEGREE_SUPERSCRIPT;
				var oSSup = new CDegree(props);
				initMathRevisions(oSSup, props);
				if (oParent)
					oParent.addElementToContent(oSSup);
				oSup.content = oSSup.getUpperIterator();
				oContent.content = oSSup.getBase();
			}

            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oSup.content, oParStruct);
            });			
        }
		else if (c_oSer_OMathContentType.Element === type)
        {
			if (undefined == oContent.content)
			{
				props.type = DEGREE_SUPERSCRIPT;
				var oSSup = new CDegree(props);
				initMathRevisions(oSSup, props);
				if (oParent)
					oParent.addElementToContent(oSSup);
				oSup.content = oSSup.getUpperIterator();
				oContent.content = oSSup.getBase();
			}

            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathArg(t,l,oContent.content, oParStruct);
            });			
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathSSupPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesType.CtrlPr === type)
        {
			res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathCtrlPr(t,l,props);
            });	           	
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathStrikeBLTR = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.strikeBLTR = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathStrikeH = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.strikeH = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathStrikeTLBR = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.strikeTLBR = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathStrikeV = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.strikeV = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathSty = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var sty = this.stream.GetUChar(length);
			switch (sty)
			{
				case c_oAscSty.Bold:		props.sty = STY_BOLD; break;
				case c_oAscSty.BoldItalic:	props.sty = STY_BI; break;
				case c_oAscSty.Italic:		props.sty = STY_ITALIC; break;
				case c_oAscSty.Plain:		props.sty = STY_PLAIN; break;
				default: 					props.sty = STY_ITALIC;
			}
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathSubHide = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.subHide = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathSupHide = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.supHide = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathTransp = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.transp = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathType = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var type = this.stream.GetUChar(length);
			switch (type)
			{
				case c_oAscFType.Bar:	props.type = BAR_FRACTION; break;
				case c_oAscFType.Lin:	props.type = LINEAR_FRACTION; break;
				case c_oAscFType.NoBar:	props.type = NO_BAR_FRACTION; break;
				case c_oAscFType.Skw:	props.type = SKEWED_FRACTION; break;
				default: 				props.type = BAR_FRACTION;
			}
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathVertJc = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var vertJc = this.stream.GetUChar(length);
			switch (vertJc)
			{
				case c_oAscTopBot.Bot:	props.vertJc = VJUST_BOT; break;
				case c_oAscTopBot.Top:	props.vertJc = VJUST_TOP; break;
				default: 				props.vertJc = VJUST_BOT;
			}
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathZeroAsc = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.zeroAsc = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathZeroDesc = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.zeroDesc = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathZeroWid = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.zeroWid = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
};
function Binary_OtherTableReader(doc, oReadResult, stream)
{
    this.Document = doc;
	this.oReadResult = oReadResult;
    this.stream = stream;
    this.bcr = new Binary_CommonReader(this.stream);
    this.ImageMapIndex = 0;
    this.Read = function()
    {
        var oThis = this;
        return this.bcr.ReadTable(function(t, l){
                return oThis.ReadOtherContent(t,l);
            });
    };
    this.ReadOtherContent = function(type, length)
    {
        var res = c_oSerConstants.ReadOk;
        if ( c_oSerOtherTableTypes.ImageMap === type )
        {
            var oThis = this;
            this.ImageMapIndex = 0;
            res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadImageMapContent(t,l);
                });
        }
		else if ( c_oSerOtherTableTypes.DocxTheme === type )
        {
		    this.Document.theme = pptx_content_loader.ReadTheme(this, this.stream);
		    res = c_oSerConstants.ReadUnknown;
		}
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.ReadImageMapContent = function(type, length, oNewImage)
    {
        var res = c_oSerConstants.ReadOk;
        if ( c_oSerOtherTableTypes.ImageMap_Src === type )
        {
            this.oReadResult.ImageMap[this.ImageMapIndex] = this.stream.GetString2LE(length); 
            this.ImageMapIndex++;
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
};
function Binary_CommentsTableReader(doc, oReadResult, stream, oComments)
{
    this.Document = doc;
	this.oReadResult = oReadResult;
    this.stream = stream;
	this.oComments = oComments;
    this.bcr = new Binary_CommonReader(this.stream);
    this.Read = function()
    {
        var oThis = this;
        return this.bcr.ReadTable(function(t, l){
                return oThis.ReadComments(t,l);
            });
    };
    this.ReadComments = function(type, length)
    {
        var res = c_oSerConstants.ReadOk;
		var oThis = this;
        if ( c_oSer_CommentsType.Comment === type )
        {
            var oNewComment = {};
            res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadCommentContent(t,l,oNewComment);
                });
			if(null != oNewComment.Id)
				this.oComments[oNewComment.Id] = oNewComment;
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.ReadCommentContent = function(type, length, oNewImage)
    {
        var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if ( c_oSer_CommentsType.Id === type )
			oNewImage.Id = this.stream.GetULongLE();
        else if ( c_oSer_CommentsType.UserName === type )
            oNewImage.UserName = this.stream.GetString2LE(length);
		else if ( c_oSer_CommentsType.UserId === type )
            oNewImage.UserId = this.stream.GetString2LE(length);
		else if ( c_oSer_CommentsType.Date === type )
		{
			var dateStr = this.stream.GetString2LE(length);
            var dateMs = Date.parse(dateStr);
            if (isNaN(dateMs)) {
                dateMs = new Date().getTime();
            }
			oNewImage.Date = dateMs + "";
		}
		else if ( c_oSer_CommentsType.Text === type )
			oNewImage.Text = this.stream.GetString2LE(length);
		else if ( c_oSer_CommentsType.Solved === type )
			oNewImage.Solved = (this.stream.GetUChar() != 0);
		else if ( c_oSer_CommentsType.Replies === type )
		{
			oNewImage.Replies = [];
			res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadReplies(t,l,oNewImage.Replies);
                });
		}
		else if ( c_oSer_CommentsType.OOData === type )
		{
			ParceAdditionalData(this.stream.GetString2LE(length), oNewImage);
		}
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadReplies = function(type, length, Replies)
    {
        var res = c_oSerConstants.ReadOk;
		var oThis = this;
        if ( c_oSer_CommentsType.Comment === type )
        {
            var oNewComment = {};
            res = this.bcr.Read1(length, function(t,l){
                    return oThis.ReadCommentContent(t,l,oNewComment);
                });
			Replies.push(oNewComment);
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
};
function Binary_SettingsTableReader(doc, oReadResult, stream)
{
    this.Document = doc;
	this.oReadResult = oReadResult;
    this.stream = stream;
	this.trackRevisions = null;
    this.bcr = new Binary_CommonReader(this.stream);
	this.bpPrr = new Binary_pPrReader(this.Document, this.oReadResult, this.stream);
	this.brPrr = new Binary_rPrReader(this.Document, this.oReadResult, this.stream);
    this.Read = function()
    {
        var oThis = this;
        return this.bcr.ReadTable(function(t, l){
                return oThis.ReadSettingsContent(t,l);
            });
    };
    this.ReadSettingsContent = function(type, length)
    {
        var res = c_oSerConstants.ReadOk;
		var oThis = this;
        if ( c_oSer_SettingsType.ClrSchemeMapping === type )
        {
            res = this.bcr.Read2(length, function(t,l){
                    return oThis.ReadColorSchemeMapping(t,l);
                });
        }
		else if ( c_oSer_SettingsType.DefaultTabStop === type )
        {
			var dNewTab_Stop = this.bcr.ReadDouble();
			//word поддерживает 0, но наш редактор к такому не готов.
			if(dNewTab_Stop > 0)
				AscCommonWord.Default_Tab_Stop = dNewTab_Stop;
        }
		else if ( c_oSer_SettingsType.MathPr === type )
        {			
			var props = new CMathPropertiesSettings();
            res = this.bcr.Read1(length, function(t, l){
                return oThis.ReadMathPr(t,l,props);
            });
			editor.WordControl.m_oLogicDocument.Settings.MathSettings.SetPr(props);
        }
		else if ( c_oSer_SettingsType.TrackRevisions === type )
		{
			this.oReadResult.trackRevisions = this.stream.GetBool();
		}
		else if ( c_oSer_SettingsType.FootnotePr === type )
		{
			var props = {fmt: null, restart: null, start: null, pos: null};
			res = this.bcr.Read1(length, function(t, l) {
				return oThis.bpPrr.ReadFootnotePr(t, l, props);
			});
			if (this.oReadResult.logicDocument) {
				var footnotes = this.oReadResult.logicDocument.Footnotes;
				if (null != props.fmt) {
					footnotes.SetFootnotePrNumFormat(props.fmt);
				}
				if (null != props.restart) {
					footnotes.SetFootnotePrNumRestart(props.restart);
				}
				if (null != props.start) {
					footnotes.SetFootnotePrNumStart(props.start);
				}
				if (null != props.pos) {
					footnotes.SetFootnotePrPos(props.pos);
				}
			}
		}
		else if ( c_oSer_SettingsType.SdtGlobalColor === type )
		{
			var textPr = new CTextPr();
			res = this.brPrr.Read(length, textPr, null);
			if (textPr.Color && !textPr.Color.Auto) {
				this.Document.SetSdtGlobalColor(textPr.Color.r, textPr.Color.g, textPr.Color.b);
			}
		}
		else if ( c_oSer_SettingsType.SdtGlobalShowHighlight === type )
		{
			this.Document.SetSdtGlobalShowHighlight(this.stream.GetBool());
		}
		else if ( c_oSer_SettingsType.Compat === type )
		{
			res = this.bcr.Read1(length, function(t, l){
				return oThis.ReadCompat(t,l);
			});
		}
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathPr = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_MathPrType.BrkBin === type)
        {
            res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathBrkBin(t,l,props);
            });			
        }
		else if (c_oSer_MathPrType.BrkBinSub === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathBrkBinSub(t,l,props);
            });	           	
        }
		else if (c_oSer_MathPrType.DefJc === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathDefJc(t,l,props);
            });	           	
        }
		else if (c_oSer_MathPrType.DispDef === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathDispDef(t,l,props);
            });	           	
        }
		else if (c_oSer_MathPrType.InterSp === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathInterSp(t,l,props);
            });	           	
        }
		else if (c_oSer_MathPrType.IntLim === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathIntLim(t,l,props);
            });	           	
        }
		else if (c_oSer_MathPrType.IntraSp === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathIntraSp(t,l,props);
            });	           	
        }
		else if (c_oSer_MathPrType.LMargin === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathLMargin(t,l,props);
            });	           	
        }
		else if (c_oSer_MathPrType.MathFont === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathMathFont(t,l,props);
            });	           	
        }
		else if (c_oSer_MathPrType.NaryLim === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathNaryLim(t,l,props);
            });	           	
        }
		else if (c_oSer_MathPrType.PostSp === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathPostSp(t,l,props);
            });	           	
        }
		else if (c_oSer_MathPrType.PreSp === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathPreSp(t,l,props);
            });	           	
        }
		else if (c_oSer_MathPrType.RMargin === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathRMargin(t,l,props);
            });	           	
        }
		else if (c_oSer_MathPrType.SmallFrac === type)
        {
			props.smallFrac = true;
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathSmallFrac(t,l,props);
            });	           	
        }
		else if (c_oSer_MathPrType.WrapIndent === type)
        {
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathWrapIndent(t,l,props);
            });	           	
        }
		else if (c_oSer_MathPrType.WrapRight === type)
        {
			props.wrapRight = true;
			res = this.bcr.Read2(length, function(t, l){
                return oThis.ReadMathWrapRight(t,l,props);
            });	           	
        }
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };	
	this.ReadMathBrkBin = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var brkBin = this.stream.GetUChar(length);
			switch (brkBin)
			{
				case c_oAscBrkBin.After:	props.brkBin = BREAK_AFTER; break;
				case c_oAscBrkBin.Before:	props.brkBin = BREAK_BEFORE; break;
				case c_oAscBrkBin.Repeat:	props.brkBin = BREAK_REPEAT; break;
				default: 					props.brkBin = BREAK_REPEAT;
			}
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathBrkBinSub = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var brkBinSub = this.stream.GetUChar(length);
			switch (brkBinSub)
			{
				case c_oAscBrkBinSub.PlusMinus:		props.brkBinSub = BREAK_PLUS_MIN; break;
				case c_oAscBrkBinSub.MinusPlus:		props.brkBinSub = BREAK_MIN_PLUS; break;
				case c_oAscBrkBinSub.MinusMinus:	props.brkBinSub = BREAK_MIN_MIN; break;
				default: 							props.brkBinSub = BREAK_MIN_MIN;
			}
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathDefJc = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var defJc = this.stream.GetUChar(length);
			switch (defJc)
			{
				case c_oAscMathJc.Center:		props.defJc = align_Center; break;
				case c_oAscMathJc.CenterGroup:	props.defJc = align_Justify; break;
				case c_oAscMathJc.Left:			props.defJc = align_Left; break;
				case c_oAscMathJc.Right: 		props.defJc = align_Right; break;
				default: 						props.defJc = align_Justify;
			}
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathDispDef = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.dispDef = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }; 
	this.ReadMathInterSp = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.interSp = this.bcr.ReadDouble();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathMathFont = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.mathFont = {Name : this.stream.GetString2LE(length), Index : -1};
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    }; 
	this.ReadMathIntLim = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var intLim = this.stream.GetUChar(length);
			switch (intLim)
			{
				case c_oAscLimLoc.SubSup:	props.intLim = NARY_SubSup; break;
				case c_oAscLimLoc.UndOvr:	props.intLim = NARY_UndOvr; break;
				default: 					props.intLim = NARY_SubSup;
			}
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathIntraSp = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.intraSp = this.bcr.ReadDouble();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathLMargin = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.lMargin = this.bcr.ReadDouble();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathNaryLim = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			var naryLim = this.stream.GetUChar(length);
			switch (naryLim)
			{
				case c_oAscLimLoc.SubSup:	props.naryLim = NARY_SubSup; break;
				case c_oAscLimLoc.UndOvr:	props.naryLim = NARY_UndOvr; break;
				default: 					props.naryLim = NARY_SubSup;
			}
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathPostSp = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.postSp = this.bcr.ReadDouble();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathPreSp = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.preSp = this.bcr.ReadDouble();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathRMargin = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.rMargin = this.bcr.ReadDouble();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathSmallFrac = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.smallFrac = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathWrapIndent = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.wrapIndent = this.bcr.ReadDouble();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ReadMathWrapRight = function(type, length, props)
    {
        var res = c_oSerConstants.ReadOk;
        var oThis = this;
		if (c_oSer_OMathBottomNodesValType.Val === type)
        {
			props.wrapRight = this.stream.GetBool();
        }
		else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
    this.ReadColorSchemeMapping = function(type, length)
    {
        var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if ( c_oSer_ClrSchemeMappingType.Accent1 <= type && type <= c_oSer_ClrSchemeMappingType.T2 )
		{
			var val = this.stream.GetUChar();
			this.ApplyColorSchemeMappingItem(type, val);
		}
        else
            res = c_oSerConstants.ReadUnknown;
        return res;
    };
	this.ApplyColorSchemeMappingItem = function(type, val)
    {
		var nScriptType = 0;
		var nScriptVal = 0;
		switch(type)
		{
			case c_oSer_ClrSchemeMappingType.Accent1: nScriptType = 0; break;
			case c_oSer_ClrSchemeMappingType.Accent2: nScriptType = 1; break;
			case c_oSer_ClrSchemeMappingType.Accent3: nScriptType = 2; break;
			case c_oSer_ClrSchemeMappingType.Accent4: nScriptType = 3; break;
			case c_oSer_ClrSchemeMappingType.Accent5: nScriptType = 4; break;
			case c_oSer_ClrSchemeMappingType.Accent6: nScriptType = 5; break;
			case c_oSer_ClrSchemeMappingType.Bg1: nScriptType = 6; break;
			case c_oSer_ClrSchemeMappingType.Bg2: nScriptType = 7; break;
			case c_oSer_ClrSchemeMappingType.FollowedHyperlink: nScriptType = 10; break;
			case c_oSer_ClrSchemeMappingType.Hyperlink: nScriptType = 11; break;
			case c_oSer_ClrSchemeMappingType.T1: nScriptType = 15; break;
			case c_oSer_ClrSchemeMappingType.T2: nScriptType = 16; break;
		}
		switch(val)
		{
			case EWmlColorSchemeIndex.wmlcolorschemeindexAccent1: nScriptVal = 0; break;
			case EWmlColorSchemeIndex.wmlcolorschemeindexAccent2: nScriptVal = 1; break;
			case EWmlColorSchemeIndex.wmlcolorschemeindexAccent3: nScriptVal = 2; break;
			case EWmlColorSchemeIndex.wmlcolorschemeindexAccent4: nScriptVal = 3; break;
			case EWmlColorSchemeIndex.wmlcolorschemeindexAccent5: nScriptVal = 4; break;
			case EWmlColorSchemeIndex.wmlcolorschemeindexAccent6: nScriptVal = 5; break;
			case EWmlColorSchemeIndex.wmlcolorschemeindexDark1: nScriptVal = 8; break;
			case EWmlColorSchemeIndex.wmlcolorschemeindexDark2: nScriptVal = 9; break;
			case EWmlColorSchemeIndex.wmlcolorschemeindexFollowedHyperlink: nScriptVal = 10; break;
			case EWmlColorSchemeIndex.wmlcolorschemeindexHyperlink: nScriptVal = 11; break;
			case EWmlColorSchemeIndex.wmlcolorschemeindexLight1: nScriptVal = 12; break;
			case EWmlColorSchemeIndex.wmlcolorschemeindexLight2: nScriptVal = 13; break;
		}
		
		this.Document.clrSchemeMap.color_map[nScriptType] = nScriptVal;
	};
	this.ReadCompat = function(type, length)
	{
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerCompat.CompatSetting === type)
		{
			var compat = {name: null, url: null, value: null};
			res = this.bcr.Read1(length, function(t, l){
				return oThis.ReadCompatSetting(t,l,compat);
			});
			if ("compatibilityMode" === compat.name) {
				if ("14" === compat.value) {
					this.oReadResult.compatibilityMode = document_compatibility_mode_Word14;
				} else if ("15" === compat.value) {
					this.oReadResult.compatibilityMode = document_compatibility_mode_Word15;
				}
			}
		}
		else
			res = c_oSerConstants.ReadUnknown;
		return res;
	};
	this.ReadCompatSetting = function(type, length, compat)
	{
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerCompat.CompatName === type) {
			compat.name = this.stream.GetString2LE(length);
		} else if (c_oSerCompat.CompatUri === type) {
			compat.url = this.stream.GetString2LE(length);
		} else if (c_oSerCompat.CompatValue === type) {
			compat.value = this.stream.GetString2LE(length);
		} else
			res = c_oSerConstants.ReadUnknown;
		return res;
	};
};
function Binary_NotesTableReader(doc, oReadResult, openParams, stream)
{
	this.Document = doc;
	this.oReadResult = oReadResult;
	this.openParams = openParams;
	this.stream = stream;
	this.trackRevisions = null;
	this.bcr = new Binary_CommonReader(this.stream);
	this.Read = function()
	{
		var oThis = this;
		return this.bcr.ReadTable(function(t, l){
				return oThis.ReadNotes(t,l);
			});
	};
	this.ReadNotes = function(type, length)
	{
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerNotes.Note === type) {
			var note = {id: null,type:null, content: null};
			res = this.bcr.Read1(length, function(t,l){
					return oThis.ReadNote(t, l, note);
				});
			if (null !== note.id && null !== note.content) {
				this.oReadResult.footnotes[note.id] = note;
			}
		} else
			res = c_oSerConstants.ReadUnknown;
		return res;
	};
	this.ReadNote = function(type, length, note)
	{
		var res = c_oSerConstants.ReadOk;
		var oThis = this;
		if (c_oSerNotes.NoteType === type) {
			note.type = this.stream.GetUChar();
		} else if (c_oSerNotes.NoteId === type) {
			note.id = this.stream.GetULongLE();
		} else if (c_oSerNotes.NoteContent === type) {
			var footnote = new CFootEndnote(this.Document.Footnotes);
			var footnoteContent = [];
			var bdtr = new Binary_DocumentTableReader(footnote, this.oReadResult, this.openParams, this.stream, footnote, this.oReadResult.oCommentsPlaces);
			bdtr.Read(length, footnoteContent);
			if(footnoteContent.length > 0)
			{
				for(var i = 0; i < footnoteContent.length; ++i)
				{
					if(i == length - 1)
						footnote.Internal_Content_Add(i + 1, footnoteContent[i], true);
					else
						footnote.Internal_Content_Add(i + 1, footnoteContent[i], false);
				}
				footnote.Internal_Content_Remove(0, 1);
			}
			//если 0 == footnoteContent.length в ячейке остается параграф который был там при создании.
			note.content = footnote;
		} else
			res = c_oSerConstants.ReadUnknown;
		return res;
	};
};
function Binary_AppTableReader(oReadResult, stream) {
	this.oReadResult = oReadResult;
	this.stream = stream;
	this.bcr = new Binary_CommonReader(this.stream);
	this.Read = function() {
		var oThis = this;
		return this.bcr.ReadTable(function(t, l) {
			return oThis.ReadProperties(t, l);
		});
	};
	this.ReadProperties = function(type, length) {
		var res = c_oSerConstants.ReadOk;
		if (c_oSerApp.Application === type) {
			this.oReadResult.Application = this.stream.GetString2LE(length);
		} else if (c_oSerApp.AppVersion === type) {
			this.oReadResult.AppVersion = this.stream.GetString2LE(length);
		} else {
			res = c_oSerConstants.ReadUnknown;
		}
		return res;
	};
}
function GetTableOffsetCorrection(tbl)
{
    var X = 0;

    var Row = tbl.Content[0];
    var Cell = Row.Get_Cell( 0 );
    var Margins = Cell.GetMargins();

    var CellSpacing = Row.Get_CellSpacing();
    if ( null != CellSpacing )
    {
        var TableBorder_Left = tbl.Get_Borders().Left;
        if ( border_None != TableBorder_Left.Value )
            X += TableBorder_Left.Size / 2;

        X += CellSpacing;

        var CellBorder_Left = Cell.Get_Borders().Left;
        if ( border_None != CellBorder_Left.Value )
            X += CellBorder_Left.Size;

        X += Margins.Left.W;
    }
    else
    {
        var TableBorder_Left = tbl.Get_Borders().Left;
        var CellBorder_Left  = Cell.Get_Borders().Left;
        var Result_Border = tbl.Internal_CompareBorders( TableBorder_Left, CellBorder_Left, true, false );

        if ( border_None != Result_Border.Value )
            X += Math.max( Result_Border.Size / 2, Margins.Left.W );
        else
            X += Margins.Left.W;
    }

    return -X;
};

function CFontCharMap()
{
    this.Name       = "";
    this.Id         = "";
    this.FaceIndex  = -1;
    this.IsEmbedded = false;
    this.CharArray  = {};
}

function CFontsCharMap()
{
    this.CurrentFontName = "";
    this.CurrentFontInfo = null;

    this.map_fonts = {};
}

CFontsCharMap.prototype =
{
    StartWork : function()
    {
    },

    EndWork : function()
    {
        var mem = new AscCommon.CMemory();
        mem.Init();

        for (var i in this.map_fonts)
        {
            var _font = this.map_fonts[i];

            mem.WriteByte(0xF0);

            mem.WriteByte(0xFA);

            mem.WriteByte(0); mem.WriteString2(_font.Name);
            mem.WriteByte(1); mem.WriteString2(_font.Id);
            mem.WriteByte(2); mem.WriteString2(_font.FaceIndex);
            mem.WriteByte(3); mem.WriteBool(_font.IsEmbedded);

            mem.WriteByte(0xFB);

            mem.WriteByte(0);

            var _pos = mem.pos;
            var _len = 0;
            for (var c in _font.CharArray)
            {
                mem.WriteLong(parseInt(c));
                _len++;
            }

            var _new_pos = mem.pos;

            mem.pos = _pos;
            mem.WriteLong(_len);
            mem.pos = _new_pos;

            mem.WriteByte(0xF1);
        }

        return mem.GetBase64Memory();
    },

    StartFont : function(family, bold, italic, size)
    {
        var font_info = g_fontApplication.GetFontInfo(family);

        var bItalic = (true === italic);
        var bBold   = (true === bold);

        var oFontStyle = FontStyle.FontStyleRegular;
        if ( !bItalic && bBold )
            oFontStyle = FontStyle.FontStyleBold;
        else if ( bItalic && !bBold )
            oFontStyle = FontStyle.FontStyleItalic;
        else if ( bItalic && bBold )
            oFontStyle = FontStyle.FontStyleBoldItalic;

        var _id = font_info.GetFontID(AscCommon.g_font_loader, oFontStyle);

        var _find_index = _id.id + "_teamlab_" + _id.faceIndex;
        if (this.CurrentFontName != _find_index)
        {
            var _find = this.map_fonts[_find_index];
            if (_find !== undefined)
            {
                this.CurrentFontInfo = _find;
            }
            else
            {
                _find = new CFontCharMap();
                _find.Name = family;
                _find.Id = _id.id;
                _find.FaceIndex = _id.faceIndex;
                _find.IsEmbedded = (font_info.type == AscFonts.FONT_TYPE_EMBEDDED);

                this.CurrentFontInfo = _find;
                this.map_fonts[_find_index] = _find;
            }
            this.CurrentFontName = _find_index;
        }
    },

    AddChar : function(char1)
    {
        var _find = "" + char1.charCodeAt(0);
        var map_ind = this.CurrentFontInfo.CharArray[_find];
        if (map_ind === undefined)
            this.CurrentFontInfo.CharArray[_find] = true;
    },
    AddChar2 : function(char2)
    {
        var _find = "" + char2.charCodeAt(0);
        var map_ind = this.CurrentFontInfo.CharArray[_find];
        if (map_ind === undefined)
            this.CurrentFontInfo.CharArray[_find] = true;
    }
}
function getStyleFirstRun(oField){
    var res = null;
    //берем первый с непустым Content, потому что в случае fldstart первым будет run fldstart
    for (var i = 0 ; i < oField.Content.length; ++i) {
        var run = oField.Content[i];
        if (run.Content.length > 0) {
            res = run.Get_FirstTextPr();
            break;
        }
    }
    return res;
}
function OpenParStruct(oContainer, paragraph) {
    this.paragraph = paragraph;
    this.cur = { pos: 0, elem: oContainer };
    this.stack = [this.cur];
	this.curRun = null;
}
OpenParStruct.prototype = {
    _addToContent: function (elem, pos, oItem) {
        if (elem.Internal_Content_Add) {
            elem.Internal_Content_Add(pos, oItem, false);
            pos++;
        }
        else if (elem.Add_ToContent) {
            elem.Add_ToContent(pos, oItem, false);
            pos++;
        }
        return pos;
    },
    _GetFromContent: function (elem, nIndex) {
        return elem.Content[nIndex];
    },
    _GetContentLength: function (elem) {
        return elem.Content.length;
    },
	_removeFromContent: function (elem, pos, count) {
        if (elem.Remove_FromContent)
            elem.Remove_FromContent(pos, count);
    },
	addElemToContentStart: function () {
		this.curRun = new ParaRun(this.paragraph);
	},
	addElemToContent: function (elem) {
		if (this.curRun.GetElementsCount() > Asc.c_dMaxParaRunContentLength) {
			this.addToContent(this.curRun);
			var textPr = this.curRun.Get_TextPr();
			this.curRun = new ParaRun(this.paragraph);
			this.curRun.Set_Pr(textPr);
		}
		this.curRun.Add_ToContent(this.curRun.GetElementsCount(), elem, false);
	},
	addElemToContentFinish: function () {
		this.addToContent(this.curRun);
	},
    addToContent: function (oItem) {
		if(null != this.cur.elem)
			this.cur.pos = this._addToContent(this.cur.elem, this.cur.pos, oItem);
    },
    GetFromContent: function (nIndex) {
		if(null != this.cur.elem)
			return this._GetFromContent(this.cur.elem, nIndex);
		return null;
    },
    GetContentLength: function () {
		if(null != this.cur.elem)
			return this._GetContentLength(this.cur.elem);
		return null;
    },
    addElem: function (oElem) {
		if(null != this.cur.elem){
			this.cur = { pos: 0, elem: oElem };
			this.stack.push(this.cur);
		}
    },
	getElem: function () {
        return this.cur.elem;
    },
    commitElem: function () {
        var bRes = false;
        if (this.stack.length > 1) {
            var oPrevElem = this.stack.pop();
            this.cur = this.stack[this.stack.length - 1];
            var elem = oPrevElem.elem;
            if (null != elem && elem.Content) {
                if (para_Field == elem.Get_Type() && (fieldtype_PAGENUM == elem.Get_FieldType() || fieldtype_PAGECOUNT == elem.Get_FieldType())) {
                    var oNewRun = new ParaRun(this.paragraph);
                    var rPr = getStyleFirstRun(elem);
                    if (rPr) {
                        oNewRun.Set_Pr(rPr);
                    }
					if (fieldtype_PAGENUM == elem.Get_FieldType()) {
						oNewRun.Add_ToContent(0, new ParaPageNum());
					} else {
						var pageCount = parseInt(elem.GetSelectedText(true));
						oNewRun.Add_ToContent(0, new ParaPageCount(isNaN(pageCount) ? undefined : pageCount));
					}
                    this.addToContent(oNewRun);
                } else if(elem.Content.length > 0) {
                    this.addToContent(elem);
                }
            }
            bRes = true;
        }
        return bRes;
    },
    commitAll: function () {
        while (this.commitElem())
            ;
    },
    getCurPos: function(){
        return this.cur.pos;
    }
}
function DocSaveParams(bMailMergeDocx, bMailMergeHtml) {
	this.bMailMergeDocx = bMailMergeDocx;
	this.bMailMergeHtml = bMailMergeHtml;
	this.trackRevisionId = 0;
	this.footnotes = {};
	this.footnotesIndex = 0;
	this.docPrId = 1;
};
function DocReadResult(doc) {
	this.logicDocument = doc;
	this.ImageMap = {};
	this.oComments = {};
	this.oCommentsPlaces = {};
	this.setting = {titlePg: false, EvenAndOddHeaders: false};
	this.numToNumClass = {};
	this.numToANumClass = {};
	this.paraNumPrs = [];
	this.styles = [];
	this.runStyles = [];
	this.paraStyles = [];
	this.tableStyles = [];
	this.lvlStyles = [];
	this.styleLinks = [];
	this.numStyleLinks = [];
	this.DefpPr = null;
	this.DefrPr = null;
	this.DocumentContent = [];
	this.bLastRun = null;
	this.aPostOpenStyleNumCallbacks = [];
	this.headers = [];
	this.footers = [];
	this.trackRevisions = null;
	this.drawingToMath = [];
	this.aTableCorrect = [];
	this.footnotes = {};
	this.footnoteRefs = [],
	this.bookmarkForRead = typeof CParagraphBookmark !== "undefined" ? new CParagraphBookmark() : {};
	this.bookmarksStarted = {};
	this.Application;
	this.AppVersion;
	this.compatibilityMode = null;
	this.bdtr = null;
};
//---------------------------------------------------------export---------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window["AscCommonWord"].BinaryFileReader = BinaryFileReader;
window["AscCommonWord"].BinaryFileWriter = BinaryFileWriter;
window["AscCommonWord"].EThemeColor = EThemeColor;
window["AscCommonWord"].DocReadResult = DocReadResult;
window["AscCommonWord"].DocSaveParams = DocSaveParams;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

//----------------------------------------------------------------------------------------------------------------------
// CParagraphSearchElement
//         Найденные элементы в параграфе. Записаны в массиве Paragraph.SearchResults
//----------------------------------------------------------------------------------------------------------------------
function CParagraphSearchElement(StartPos, EndPos, Type, Id)
{
    this.StartPos  = StartPos;
    this.EndPos    = EndPos;
    this.Type      = Type;
    this.ResultStr = "";
    this.Id        = Id;

    this.ClassesS = [];
    this.ClassesE = [];
}

//----------------------------------------------------------------------------------------------------------------------
// CDocumentSearch
//         Механизм поиска. Хранит параграфы с найденной строкой
//----------------------------------------------------------------------------------------------------------------------
function CDocumentSearch()
{
    this.Text          = "";
    this.MatchCase     = false;

    this.Id            = 0;
    this.Count         = 0;
    this.Elements      = [];
    this.CurId         = -1;
    this.Direction     = true; // направление true - вперед, false - назад
    this.ClearOnRecalc = true; // Флаг, говорящий о том, запустился ли пересчет из-за Replace
    this.Selection     = false;
    this.Footnotes     = [];
}

CDocumentSearch.prototype =
{
    Set : function(Text, Props)
    {
        this.Text      = Text;
        this.MatchCase = Props.MatchCase;
    },

    Reset : function()
    {
        this.Text          = "";
        this.MatchCase     = false;
    },

    Compare : function(Text, Props)
    {
        if ( this.Text === Text && this.MatchCase === Props.MatchCase )
            return true;

        return false;
    },

    Clear : function()
    {
        this.Text        = "";
        this.MatchCase   = false;

        // Очищаем предыдущие элементы поиска
        for (var Id in this.Elements)
        {
            var Paragraph = this.Elements[Id];
            Paragraph.Clear_SearchResults();
        }

        this.Id        = 0;
        this.Count     = 0;
        this.Elements  = {};
        this.CurId     = -1;
        this.Direction = true;
    },

    Add : function(Paragraph)
    {
        this.Count++;
        this.Id++;
        this.Elements[this.Id] = Paragraph;
        return this.Id;
    },

    Select : function(Id, bUpdateStates)
    {
        var Paragraph = this.Elements[Id];
        if ( undefined != Paragraph )
        {
            var SearchElement = Paragraph.SearchResults[Id];
            if ( undefined != SearchElement )
            {
                Paragraph.Selection.Use      = true;
                Paragraph.Selection.Start    = false;

                Paragraph.Set_SelectionContentPos(SearchElement.StartPos, SearchElement.EndPos);
                Paragraph.Set_ParaContentPos(SearchElement.StartPos, false, -1, -1);

                Paragraph.Document_SetThisElementCurrent(false !== bUpdateStates ? true : false);
            }

            this.CurId = Id;
        }
    },

    Reset_Current : function()
    {
        this.CurId = -1;
    },

    Replace : function(NewStr, Id, bRestorePos)
    {
        var Para = this.Elements[Id];
        if ( undefined != Para )
        {
            var SearchElement = Para.SearchResults[Id];
            if ( undefined != SearchElement )
            {
                var ContentPos, StartPos, EndPos, bSelection;
                if (true === bRestorePos)
                {
                    // Сохраняем позицию состояние параграфа, чтобы курсор остался в том же месте и после замены.
                    bSelection = Para.IsSelectionUse();
                    ContentPos = Para.Get_ParaContentPos(false, false);
                    StartPos   = Para.Get_ParaContentPos(true, true);
                    EndPos     = Para.Get_ParaContentPos(true, false);

                    Para.Check_NearestPos({ContentPos : ContentPos});
                    Para.Check_NearestPos({ContentPos : StartPos});
                    Para.Check_NearestPos({ContentPos : EndPos});
                }

                // Сначала в начальную позицию поиска добавляем новый текст
                var StartContentPos = SearchElement.StartPos;
                var StartRun = SearchElement.ClassesS[SearchElement.ClassesS.length - 1];

                var RunPos = StartContentPos.Get( SearchElement.ClassesS.length - 1 );
                StartRun.AddText(NewStr, RunPos);

                // Выделяем старый объект поиска и удаляем его
                Para.Selection.Use = true;
                Para.Set_SelectionContentPos( SearchElement.StartPos, SearchElement.EndPos );
                Para.Remove();

                // Перемещаем курсор в конец поиска
                Para.RemoveSelection();
                Para.Set_ParaContentPos( SearchElement.StartPos, true, -1, -1 );

                // Удаляем запись о данном элементе
                this.Count--;

                Para.Remove_SearchResult( Id );
                delete this.Elements[Id];

                if (true === bRestorePos)
                {
                    Para.Set_SelectionContentPos(StartPos, EndPos);
                    Para.Set_ParaContentPos(ContentPos, true, -1, -1 );
                    Para.Selection.Use = bSelection;
                    Para.Clear_NearestPosArray();
                }
            }
        }
    },

    Replace_All : function(NewStr, bUpdateStates)
    {
        for (var Id = this.Id; Id >= 0; --Id)
        {
            if (this.Elements[Id])
                this.Replace(NewStr, Id, true);
        }

        this.Clear();
    },

    Set_Direction : function(bDirection)
    {
        this.Direction = bDirection;
    }
};
CDocumentSearch.prototype.SetFootnotes = function(arrFootnotes)
{
	this.Footnotes = arrFootnotes;
};
CDocumentSearch.prototype.GetFootnotes = function()
{
	return this.Footnotes;
};
CDocumentSearch.prototype.GetDirection = function()
{
	return this.Direction;
};
CDocumentSearch.prototype.SetDirection = function(bDirection)
{
	this.Direction = bDirection;
};
//----------------------------------------------------------------------------------------------------------------------
// CDocument
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.Search = function(Str, Props, bDraw)
{
    //var StartTime = new Date().getTime();

    if ( true === this.SearchEngine.Compare( Str, Props ) )
        return this.SearchEngine;

    this.SearchEngine.Clear();
    this.SearchEngine.Set( Str, Props );

    // Поиск в основном документе
    var Count = this.Content.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        this.Content[Index].Search( Str, Props, this.SearchEngine, search_Common );
    }

    // Поиск в колонтитулах
    this.SectionsInfo.Search( Str, Props, this.SearchEngine );

    // Ищем в сносках
	var arrFootnotes = this.Get_FootnotesList(null, null);
	this.SearchEngine.SetFootnotes(arrFootnotes);
	for (var nIndex = 0, nCount = arrFootnotes.length; nIndex < nCount; ++nIndex)
	{
		var oFootnote = arrFootnotes[nIndex];
		oFootnote.Search(Str, Props, this.SearchEngine, search_Footnote);
	}

    if (false !== bDraw)
    {
        this.DrawingDocument.ClearCachePages();
        this.DrawingDocument.FirePaint();
    }

    //console.log( "Search logic: " + ((new Date().getTime() - StartTime) / 1000) + " s"  );

    return this.SearchEngine;
};
CDocument.prototype.Search_Select = function(Id)
{
    this.RemoveSelection();
    this.SearchEngine.Select(Id, true);
    this.RecalculateCurPos();

    this.Document_UpdateInterfaceState();
    this.Document_UpdateSelectionState();
    this.Document_UpdateRulersState();
};
CDocument.prototype.Search_Replace = function(NewStr, bAll, Id, bInterfaceEvent)
{
    var bResult = false;

    this.RemoveSelection();

    var CheckParagraphs = [];
    if ( true === bAll )
    {
        var CheckParagraphsObj = {};
        for (var Id in this.SearchEngine.Elements)
        {
            CheckParagraphsObj[this.SearchEngine.Elements[Id].Get_Id()] = this.SearchEngine.Elements[Id];
        }

        for (var ParaId in CheckParagraphsObj)
        {
            CheckParagraphs.push(CheckParagraphsObj[ParaId]);
        }
    }
    else
    {
        if ( undefined !== this.SearchEngine.Elements[Id] )
            CheckParagraphs.push( this.SearchEngine.Elements[Id] );
    }

    var AllCount = this.SearchEngine.Count;

    if ( false === this.Document_Is_SelectionLocked( AscCommon.changestype_None, { Type : AscCommon.changestype_2_ElementsArray_and_Type, Elements : CheckParagraphs, CheckType : AscCommon.changestype_Paragraph_Content } ) )
    {
        AscCommon.History.Create_NewPoint(bAll ? AscDFH.historydescription_Document_ReplaceAll : AscDFH.historydescription_Document_ReplaceSingle);

        if (true === bAll)
        {
            this.SearchEngine.Replace_All(NewStr, true);
        }
        else
        {
            this.SearchEngine.Replace(NewStr, Id, false);

            // TODO: В будушем надо будет переделать, чтобы искалось заново только в том параграфе, в котором произошла замена
            //       Тут появляется проблема с вложенным поиском, если то что мы заменяем содержится в том, на что мы заменяем.
            if (true === this.Is_TrackRevisions())
                this.SearchEngine.Reset();
        }

        this.SearchEngine.ClearOnRecalc = false;
        this.Recalculate();
        this.SearchEngine.ClearOnRecalc = true;

        this.RecalculateCurPos();

        bResult = true;

		if (true === bAll && false !== bInterfaceEvent)
			editor.sync_ReplaceAllCallback(AllCount, AllCount);
    }
    else
    {
		if (true === bAll && false !== bInterfaceEvent)
			editor.sync_ReplaceAllCallback(0, AllCount);
    }

    this.Document_UpdateInterfaceState();
    this.Document_UpdateSelectionState();
    this.Document_UpdateRulersState();

    return bResult;
};
CDocument.prototype.Search_GetId = function(bNext)
{
	var Id = null;

	this.SearchEngine.SetDirection(bNext);

	if (docpostype_DrawingObjects === this.CurPos.Type)
	{
		var ParaDrawing = this.DrawingObjects.getMajorParaDrawing();

		Id = ParaDrawing.Search_GetId(bNext, true);
		if (null != Id)
			return Id;

		this.DrawingObjects.resetSelection();
		ParaDrawing.GoTo_Text(true === bNext ? false : true, false);
	}

	if (docpostype_Content === this.CurPos.Type)
	{
		Id = this.private_GetSearchIdInMainDocument(true);

		if (null === Id)
			Id = this.private_GetSearchIdInFootnotes(false);

		if (null === Id)
			Id = this.private_GetSearchIdInHdrFtr(false);

		if (null === Id)
			Id = this.private_GetSearchIdInMainDocument(false);
	}
	else if (docpostype_HdrFtr === this.CurPos.Type)
	{
		Id = this.private_GetSearchIdInHdrFtr(true);

		if (null === Id)
			Id = this.private_GetSearchIdInMainDocument(false);

		if (null === Id)
			Id = this.private_GetSearchIdInFootnotes(false);

		if (null === Id)
			Id = this.private_GetSearchIdInHdrFtr(false);
	}
	else if (docpostype_Footnotes === this.CurPos.Type)
	{
		Id = this.private_GetSearchIdInFootnotes(true);

		if (null === Id)
			Id = this.private_GetSearchIdInHdrFtr(false);

		if (null === Id)
			Id = this.private_GetSearchIdInMainDocument(false);

		if (null === Id)
			Id = this.private_GetSearchIdInFootnotes(false);
	}

	return Id;
};
CDocument.prototype.Search_Set_Selection = function(bSelection)
{
    var OldValue = this.SearchEngine.Selection;
    if ( OldValue === bSelection )
        return;

    this.SearchEngine.Selection = bSelection;
    this.DrawingDocument.ClearCachePages();
    this.DrawingDocument.FirePaint();
};
CDocument.prototype.Search_Get_Selection = function()
{
    return this.SearchEngine.Selection;
};
CDocument.prototype.private_GetSearchIdInMainDocument = function(isCurrent)
{
	var Id    = null;
	var bNext = this.SearchEngine.GetDirection();
	var Pos   = this.CurPos.ContentPos;
	if (true === this.Selection.Use && selectionflag_Common === this.Selection.Flag)
		Pos = bNext ? Math.max(this.Selection.StartPos, this.Selection.EndPos) : Math.min(this.Selection.StartPos, this.Selection.EndPos);

	if (true !== isCurrent)
		Pos = bNext ? 0 : this.Content.length - 1;

	if (true === bNext)
	{
		Id = this.Content[Pos].Search_GetId(true, isCurrent);

		if (null != Id)
			return Id;

		Pos++;

		var Count = this.Content.length;
		while (Pos < Count)
		{
			Id = this.Content[Pos].Search_GetId(true, false);

			if (null != Id)
				return Id;

			Pos++;
		}
	}
	else
	{
		Id = this.Content[Pos].Search_GetId(false, isCurrent);

		if (null != Id)
			return Id;

		Pos--;

		while (Pos >= 0)
		{
			Id = this.Content[Pos].Search_GetId(false, false);

			if (null != Id)
				return Id;

			Pos--;
		}
	}

	return Id;
};
CDocument.prototype.private_GetSearchIdInHdrFtr = function(isCurrent)
{
	return this.SectionsInfo.Search_GetId(this.SearchEngine.GetDirection(), isCurrent ? this.HdrFtr.CurHdrFtr : null);
};
CDocument.prototype.private_GetSearchIdInFootnotes = function(isCurrent)
{
	var bNext        = this.SearchEngine.GetDirection();
	var oCurFootnote = this.Footnotes.CurFootnote;

	var arrFootnotes = this.SearchEngine.GetFootnotes();
	var nCurPos      = -1;
	var nCount       = arrFootnotes.length;

	if (nCount <= 0)
		return null;

	if (isCurrent)
	{
		for (var nIndex = 0; nIndex < nCount; ++nIndex)
		{
			if (arrFootnotes[nIndex] === oCurFootnote)
			{
				nCurPos = nIndex;
				break;
			}
		}
	}

	if (-1 == nCurPos)
	{
		nCurPos      = bNext ? 0 : nCount - 1;
		oCurFootnote = arrFootnotes[nCurPos];
		isCurrent    = false;
	}

	var Id = oCurFootnote.Search_GetId(bNext, isCurrent);
	if (null !== Id)
		return Id;

	if (true === bNext)
	{
		for (var nIndex = nCurPos + 1; nIndex < nCount; ++nIndex)
		{
			Id = arrFootnotes[nIndex].Search_GetId(bNext, false);
			if (null != Id)
				return Id;
		}
	}
	else
	{
		for (var nIndex = nCurPos - 1; nIndex >= 0; --nIndex)
		{
			Id = arrFootnotes[nIndex].Search_GetId(bNext, false);
			if (null != Id)
				return Id;
		}
	}

	return null;
};
//----------------------------------------------------------------------------------------------------------------------
// CDocumentContent
//----------------------------------------------------------------------------------------------------------------------
CDocumentContent.prototype.Search = function(Str, Props, SearchEngine, Type)
{
    // Поиск в основном документе
    var Count = this.Content.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        this.Content[Index].Search( Str, Props, SearchEngine, Type );
    }
};

CDocumentContent.prototype.Search_GetId = function(bNext, bCurrent)
{
    // Получим Id найденного элемента
    var Id = null;

    if ( true === bCurrent )
    {
        if ( docpostype_DrawingObjects === this.CurPos.Type )
        {
            var ParaDrawing = this.DrawingObjects.getMajorParaDrawing();

            Id = ParaDrawing.Search_GetId( bNext, true );
            if ( null != Id )
                return Id;

            ParaDrawing.GoTo_Text( true === bNext ? false : true, false );
        }

        var Pos = this.CurPos.ContentPos;
        if ( true === this.Selection.Use && selectionflag_Common === this.Selection.Flag )
            Pos = ( true === bNext ? Math.max(this.Selection.StartPos, this.Selection.EndPos) : Math.min(this.Selection.StartPos, this.Selection.EndPos) );

        if ( true === bNext )
        {
            Id = this.Content[Pos].Search_GetId(true, true);

            if ( null != Id )
                return Id;

            Pos++;

            var Count = this.Content.length;
            while ( Pos < Count )
            {
                Id = this.Content[Pos].Search_GetId(true, false);
                if ( null != Id )
                    return Id;

                Pos++;
            }
        }
        else
        {
            Id = this.Content[Pos].Search_GetId(false, true);

            if ( null != Id )
                return Id;

            Pos--;

            while ( Pos >= 0 )
            {
                Id = this.Content[Pos].Search_GetId(false, false);
                if ( null != Id )
                    return Id;

                Pos--;
            }
        }
    }
    else
    {
        var Count = this.Content.length;
        if ( true === bNext )
        {
            var Pos = 0;
            while ( Pos < Count )
            {
                Id = this.Content[Pos].Search_GetId(true, false);
                if ( null != Id )
                    return Id;

                Pos++;
            }
        }
        else
        {
            var Pos = Count - 1;
            while ( Pos >= 0 )
            {
                Id = this.Content[Pos].Search_GetId(false, false);
                if ( null != Id )
                    return Id;

                Pos--;
            }
        }
    }

    return null;
};

//----------------------------------------------------------------------------------------------------------------------
// CHeaderFooter
//----------------------------------------------------------------------------------------------------------------------
CHeaderFooter.prototype.Search = function(Str, Props, SearchEngine, Type)
{
    this.Content.Search( Str, Props, SearchEngine, Type );
};

CHeaderFooter.prototype.Search_GetId = function(bNext, bCurrent)
{
    return this.Content.Search_GetId( bNext, bCurrent );
};

//----------------------------------------------------------------------------------------------------------------------
// CDocumentSectionsInfo
//----------------------------------------------------------------------------------------------------------------------
CDocumentSectionsInfo.prototype.Search = function(Str, Props, SearchEngine)
{
    var bEvenOdd = EvenAndOddHeaders;
    var Count = this.Elements.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        var SectPr = this.Elements[Index].SectPr;
        var bFirst = SectPr.Get_TitlePage();
        
        if ( null != SectPr.HeaderFirst && true === bFirst )
            SectPr.HeaderFirst.Search( Str, Props, SearchEngine, search_Header );

        if ( null != SectPr.HeaderEven && true === bEvenOdd )
            SectPr.HeaderEven.Search( Str, Props, SearchEngine, search_Header );

        if ( null != SectPr.HeaderDefault )
            SectPr.HeaderDefault.Search( Str, Props, SearchEngine, search_Header );

        if ( null != SectPr.FooterFirst && true === bFirst )
            SectPr.FooterFirst.Search( Str, Props, SearchEngine, search_Footer );

        if ( null != SectPr.FooterEven && true === bEvenOdd )
            SectPr.FooterEven.Search( Str, Props, SearchEngine, search_Footer );

        if ( null != SectPr.FooterDefault )
            SectPr.FooterDefault.Search( Str, Props, SearchEngine, search_Footer );                
    }            
};

CDocumentSectionsInfo.prototype.Search_GetId = function(bNext, CurHdrFtr)
{
	var HdrFtrs = [];
	var CurPos  = -1;

	var bEvenOdd = EvenAndOddHeaders;
	var Count    = this.Elements.length;
	for (var Index = 0; Index < Count; Index++)
	{
		var SectPr = this.Elements[Index].SectPr;
		var bFirst = SectPr.Get_TitlePage();

		if (null != SectPr.HeaderFirst && true === bFirst)
		{
			HdrFtrs.push(SectPr.HeaderFirst);

			if (CurHdrFtr === SectPr.HeaderFirst)
				CurPos = HdrFtrs.length - 1;
		}

		if (null != SectPr.HeaderEven && true === bEvenOdd)
		{
			HdrFtrs.push(SectPr.HeaderEven);

			if (CurHdrFtr === SectPr.HeaderEven)
				CurPos = HdrFtrs.length - 1;
		}

		if (null != SectPr.HeaderDefault)
		{
			HdrFtrs.push(SectPr.HeaderDefault);

			if (CurHdrFtr === SectPr.HeaderDefault)
				CurPos = HdrFtrs.length - 1;
		}

		if (null != SectPr.FooterFirst && true === bFirst)
		{
			HdrFtrs.push(SectPr.FooterFirst);

			if (CurHdrFtr === SectPr.FooterFirst)
				CurPos = HdrFtrs.length - 1;
		}

		if (null != SectPr.FooterEven && true === bEvenOdd)
		{
			HdrFtrs.push(SectPr.FooterEven);

			if (CurHdrFtr === SectPr.FooterEven)
				CurPos = HdrFtrs.length - 1;
		}

		if (null != SectPr.FooterDefault)
		{
			HdrFtrs.push(SectPr.FooterDefault);

			if (CurHdrFtr === SectPr.FooterDefault)
				CurPos = HdrFtrs.length - 1;
		}
	}

	var Count = HdrFtrs.length;

	var isCurrent = true;
	if (-1 === CurPos)
	{
		isCurrent = false;
		CurPos    = bNext ? 0 : HdrFtrs.length - 1;
		if (HdrFtrs[CurPos])
			CurHdrFtr = HdrFtrs[CurPos];
	}

	if (CurPos >= 0 && CurPos <= HdrFtrs.length - 1)
	{
		var Id = CurHdrFtr.Search_GetId(bNext, isCurrent);
		if (null != Id)
			return Id;

		if (true === bNext)
		{
			for (var Index = CurPos + 1; Index < Count; Index++)
			{
				Id = HdrFtrs[Index].Search_GetId(bNext, false);

				if (null != Id)
					return Id;
			}
		}
		else
		{
			for (var Index = CurPos - 1; Index >= 0; Index--)
			{
				Id = HdrFtrs[Index].Search_GetId(bNext, false);

				if (null != Id)
					return Id;
			}
		}
	}

	return null;
};
//----------------------------------------------------------------------------------------------------------------------
// CTable
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.Search = function(Str, Props, SearchEngine, Type)
{
    for ( var CurRow = 0; CurRow < this.Content.length; CurRow++ )
    {
        var Row = this.Content[CurRow];
        var CellsCount = Row.Get_CellsCount();

        for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
        {
            Row.Get_Cell( CurCell ).Content.Search( Str, Props, SearchEngine, Type );
        }
    }
};

CTable.prototype.Search_GetId = function(bNext, bCurrent)
{
    if ( true === bCurrent )
    {
        var Id = null;
        var CurRow  = 0;
        var CurCell = 0;
        if ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type )
        {
            var Pos = ( true === bNext ? this.Selection.Data[this.Selection.Data.length - 1] : this.Selection.Data[0] );
            CurRow  = Pos.Row;
            CurCell = Pos.CurCell;
        }
        else
        {
            Id = this.CurCell.Content.Search_GetId(bNext, true);
            if ( Id != null )
                return Id;

            CurRow  = this.CurCell.Row.Index;
            CurCell = this.CurCell.Index;
        }

        var Rows_Count = this.Content.length;
        if ( true === bNext )
        {
            for ( var _CurRow = CurRow; _CurRow < Rows_Count; _CurRow++ )
            {
                var Row = this.Content[_CurRow];
                var Cells_Count = Row.Get_CellsCount();
                var StartCell = ( _CurRow === CurRow ? CurCell + 1 : 0 );
                for ( var _CurCell = StartCell; _CurCell < Cells_Count; _CurCell++ )
                {
                    var Cell = Row.Get_Cell(_CurCell);
                    Id = Cell.Content.Search_GetId( true, false );
                    if ( null != Id )
                        return Id;
                }
            }
        }
        else
        {
            for ( var _CurRow = CurRow; _CurRow >= 0; _CurRow-- )
            {
                var Row = this.Content[_CurRow];
                var Cells_Count = Row.Get_CellsCount();
                var StartCell = ( _CurRow === CurRow ? CurCell - 1 : Cells_Count - 1 );
                for ( var _CurCell = StartCell; _CurCell >= 0; _CurCell-- )
                {
                    var Cell = Row.Get_Cell(_CurCell);
                    Id = Cell.Content.Search_GetId( false, false );
                    if ( null != Id )
                        return Id;
                }
            }

        }
    }
    else
    {
        var Rows_Count = this.Content.length;
        if ( true === bNext )
        {
            for ( var _CurRow = 0; _CurRow < Rows_Count; _CurRow++ )
            {
                var Row = this.Content[_CurRow];
                var Cells_Count = Row.Get_CellsCount();
                for ( var _CurCell = 0; _CurCell < Cells_Count; _CurCell++ )
                {
                    var Cell = Row.Get_Cell(_CurCell);
                    Id = Cell.Content.Search_GetId( true, false );
                    if ( null != Id )
                        return Id;
                }
            }
        }
        else
        {
            for ( var _CurRow = Rows_Count - 1; _CurRow >= 0; _CurRow-- )
            {
                var Row = this.Content[_CurRow];
                var Cells_Count = Row.Get_CellsCount();
                for ( var _CurCell = Cells_Count - 1; _CurCell >= 0; _CurCell-- )
                {
                    var Cell = Row.Get_Cell(_CurCell);
                    Id = Cell.Content.Search_GetId( false, false );
                    if ( null != Id )
                        return Id;
                }
            }

        }
    }

    return Id;
};
//----------------------------------------------------------------------------------------------------------------------
// Paragraph
//----------------------------------------------------------------------------------------------------------------------
Paragraph.prototype.Search = function(Str, Props, SearchEngine, Type)
{
    var bMatchCase = Props.MatchCase;
    var ParaSearch = new CParagraphSearch(this, Str, Props, SearchEngine, Type);
    var ContentLen = this.Content.length;
    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        var Element = this.Content[CurPos];

        ParaSearch.ContentPos.Update( CurPos, 0 );

        Element.Search( ParaSearch, 1 );
    }

    var MaxShowValue = 100;
    for ( var FoundId in this.SearchResults )
    {
        var StartPos = this.SearchResults[FoundId].StartPos;
        var EndPos   = this.SearchResults[FoundId].EndPos;
        var ResultStr = new String();

        var _Str = Str;

        // Теперь мы должны сформировать строку
        if ( _Str.length >= MaxShowValue )
        {
            ResultStr = "\<b\>";
            for ( var Index = 0; Index < MaxShowValue - 1; Index++ )
                ResultStr += _Str[Index];

            ResultStr += "\</b\>...";
        }
        else
        {
            ResultStr = "\<b\>" + _Str + "\</b\>";

            var LeaveCount = MaxShowValue - _Str.length;
            var RunElementsAfter  = new CParagraphRunElements(EndPos, LeaveCount, [para_Text, para_Space, para_Tab]);
            var RunElementsBefore = new CParagraphRunElements(StartPos, LeaveCount, [para_Text, para_Space, para_Tab]);

            this.GetNextRunElements(RunElementsAfter);
            this.GetPrevRunElements(RunElementsBefore);

            var LeaveCount_2 = LeaveCount / 2;

            if ( RunElementsAfter.Elements.length >= LeaveCount_2 && RunElementsBefore.Elements.length >= LeaveCount_2 )
            {
                for ( var Index = 0; Index < LeaveCount_2; Index++ )
                {
                    var ItemB = RunElementsBefore.Elements[Index];
                    var ItemA = RunElementsAfter.Elements[Index];

                    ResultStr = (para_Text === ItemB.Type ? ItemB.Value : " ") + ResultStr + (para_Text === ItemA.Type ? ItemA.Value : " ");
                }
            }
            else if ( RunElementsAfter.Elements.length < LeaveCount_2 )
            {
                var TempCount = RunElementsAfter.Elements.length;
                for ( var Index = 0; Index < TempCount; Index++ )
                {
                    var ItemA = RunElementsAfter.Elements[Index];
                    ResultStr = ResultStr + (para_Text === ItemA.Type ? ItemA.Value : " ");
                }

                var TempCount = Math.min( 2 * LeaveCount_2 - RunElementsAfter.Elements.length, RunElementsBefore.Elements.length );
                for ( var Index = 0; Index < TempCount; Index++ )
                {
                    var ItemB = RunElementsBefore.Elements[Index];
                    ResultStr = (para_Text === ItemB.Type ? ItemB.Value : " ") + ResultStr;
                }
            }
            else
            {
                var TempCount = RunElementsAfter.Elements.length;
                for ( var Index = 0; Index < TempCount; Index++ )
                {
                    var ItemA = RunElementsAfter.Elements[Index];
                    ResultStr = ResultStr + (para_Text === ItemA.Type ? ItemA.Value : " ");
                }

                var TempCount = RunElementsBefore.Elements.length;
                for ( var Index = 0; Index < TempCount; Index++ )
                {
                    var ItemB = RunElementsBefore.Elements[Index];
                    ResultStr = (para_Text === ItemB.Type ? ItemB.Value : " ") + ResultStr;
                }
            }
        }

        this.SearchResults[FoundId].ResultStr = ResultStr;
    }
};

Paragraph.prototype.Search_GetId = function(bNext, bCurrent)
{
    // Определим позицию, начиная с которой мы будем искать ближайший найденный элемент
    var ContentPos = null;

    if ( true === bCurrent )
    {
        if ( true === this.Selection.Use )
        {
            var SSelContentPos = this.Get_ParaContentPos( true, true );
            var ESelContentPos = this.Get_ParaContentPos( true, false );

            if ( SSelContentPos.Compare( ESelContentPos ) > 0 )
            {
                var Temp = ESelContentPos;
                ESelContentPos = SSelContentPos;
                SSelContentPos = Temp;
            }

            if ( true === bNext )
                ContentPos = ESelContentPos;
            else
                ContentPos = SSelContentPos;
        }
        else
            ContentPos = this.Get_ParaContentPos( false, false );
    }
    else
    {
        if ( true === bNext )
            ContentPos = this.Get_StartPos();
        else
            ContentPos = this.Get_EndPos( false );
    }

    // Производим поиск ближайшего элемента
    if ( true === bNext )
    {
        var StartPos = ContentPos.Get(0);
        var ContentLen = this.Content.length;

        for ( var CurPos = StartPos; CurPos < ContentLen; CurPos++ )
        {
            var ElementId = this.Content[CurPos].Search_GetId( true, CurPos === StartPos ? true : false, ContentPos, 1 );
            if ( null !== ElementId )
                return ElementId;
        }
    }
    else
    {
        var StartPos = ContentPos.Get(0);
        var ContentLen = this.Content.length;

        for ( var CurPos = StartPos; CurPos >= 0; CurPos-- )
        {
            var ElementId = this.Content[CurPos].Search_GetId( false, CurPos === StartPos ? true : false, ContentPos, 1 );
            if ( null !== ElementId )
                return ElementId;
        }
    }

    return null;
};

Paragraph.prototype.Add_SearchResult = function(Id, StartContentPos, EndContentPos, Type)
{
    var SearchResult = new CParagraphSearchElement( StartContentPos, EndContentPos, Type, Id );

    this.SearchResults[Id] = SearchResult;

    SearchResult.ClassesS.push( this );
    SearchResult.ClassesE.push( this );

    this.Content[StartContentPos.Get(0)].Add_SearchResult( SearchResult, true, StartContentPos, 1 );
    this.Content[EndContentPos.Get(0)].Add_SearchResult( SearchResult, false, EndContentPos, 1 );
};

Paragraph.prototype.Clear_SearchResults = function()
{
    for ( var Id in this.SearchResults )
    {
        var SearchResult = this.SearchResults[Id];

        var ClassesCount = SearchResult.ClassesS.length;
        for ( var Pos = 1; Pos < ClassesCount; Pos++ )
        {
            SearchResult.ClassesS[Pos].Clear_SearchResults();
        }

        var ClassesCount = SearchResult.ClassesE.length;
        for ( var Pos = 1; Pos < ClassesCount; Pos++ )
        {
            SearchResult.ClassesE[Pos].Clear_SearchResults();
        }
    }

    this.SearchResults = {};
};

Paragraph.prototype.Remove_SearchResult = function(Id)
{
    var SearchResult = this.SearchResults[Id];
    if ( undefined !== SearchResult )
    {
        var ClassesCount = SearchResult.ClassesS.length;
        for ( var Pos = 1; Pos < ClassesCount; Pos++ )
        {
            SearchResult.ClassesS[Pos].Remove_SearchResult(SearchResult);
        }

        var ClassesCount = SearchResult.ClassesE.length;
        for ( var Pos = 1; Pos < ClassesCount; Pos++ )
        {
            SearchResult.ClassesE[Pos].Remove_SearchResult(SearchResult);
        }

        delete this.SearchResults[Id];
    }
};

//----------------------------------------------------------------------------------------------------------------------
// ParaRun
//----------------------------------------------------------------------------------------------------------------------
ParaRun.prototype.Search = function(ParaSearch, Depth)
{
    this.SearchMarks = [];

    var Para         = ParaSearch.Paragraph;
    var Str          = ParaSearch.Str;
    var Props        = ParaSearch.Props;
    var SearchEngine = ParaSearch.SearchEngine;
    var Type         = ParaSearch.Type;

    var MatchCase    = Props.MatchCase;

    var ContentLen = this.Content.length;

    for ( var Pos = 0; Pos < ContentLen; Pos++ )
    {
        var Item = this.Content[Pos];

        if ( para_Drawing === Item.Type )
        {
            Item.Search( Str, Props, SearchEngine, Type );
            ParaSearch.Reset();
        }

        if ( (" " === Str[ParaSearch.SearchIndex] && para_Space === Item.Type)|| (para_Math_Text == Item.Type && Item.value === Str.charCodeAt(ParaSearch.SearchIndex)) || ( para_Text === Item.Type && (  ( true != MatchCase && (String.fromCharCode(Item.Value)).toLowerCase() === Str[ParaSearch.SearchIndex].toLowerCase() ) || ( true === MatchCase && Item.Value === Str.charCodeAt(ParaSearch.SearchIndex) ) ) ) )
        {
            if ( 0 === ParaSearch.SearchIndex )
            {
                var StartContentPos = ParaSearch.ContentPos.Copy();
                StartContentPos.Update( Pos, Depth );
                ParaSearch.StartPos = StartContentPos;
            }

            ParaSearch.SearchIndex++;

            if ( ParaSearch.SearchIndex === Str.length )
            {
                var EndContentPos = ParaSearch.ContentPos.Copy();
                EndContentPos.Update( Pos + 1, Depth );

                var Id = SearchEngine.Add( Para );
                Para.Add_SearchResult( Id, ParaSearch.StartPos, EndContentPos, Type );

                // Обнуляем поиск
                ParaSearch.Reset();
            }
        }
        else if ( 0 !== ParaSearch.SearchIndex )
        {
            // Обнуляем поиск
            ParaSearch.Reset();
        }
    }
};

ParaRun.prototype.Add_SearchResult = function(SearchResult, Start, ContentPos, Depth)
{
    if ( true === Start )
        SearchResult.ClassesS.push( this );
    else
        SearchResult.ClassesE.push( this );

    this.SearchMarks.push( new CParagraphSearchMark( SearchResult, Start, Depth ) );
};

ParaRun.prototype.Clear_SearchResults = function()
{
    this.SearchMarks = [];
};

ParaRun.prototype.Remove_SearchResult = function(SearchResult)
{
    var MarksCount = this.SearchMarks.length;
    for ( var Index = 0; Index < MarksCount; Index++ )
    {
        var Mark = this.SearchMarks[Index];
        if ( SearchResult === Mark.SearchResult )
        {
            this.SearchMarks.splice( Index, 1 );
            Index--;
            MarksCount--;
        }
    }
};

ParaRun.prototype.Search_GetId = function(bNext, bUseContentPos, ContentPos, Depth)
{
    var StartPos = 0;

    if ( true === bUseContentPos )
    {
        StartPos = ContentPos.Get( Depth );
    }
    else
    {
        if ( true === bNext )
        {
            StartPos = 0;
        }
        else
        {
            StartPos = this.Content.length;
        }
    }

    var NearElementId = null;

    if ( true === bNext )
    {
        var NearPos = this.Content.length;

        var SearchMarksCount = this.SearchMarks.length;
        for ( var SPos = 0; SPos < SearchMarksCount; SPos++)
        {
            var Mark = this.SearchMarks[SPos];
            var MarkPos = Mark.SearchResult.StartPos.Get(Mark.Depth);

            if (Mark.SearchResult.ClassesS.length > 0 && this === Mark.SearchResult.ClassesS[Mark.SearchResult.ClassesS.length - 1] && MarkPos >= StartPos && MarkPos < NearPos)
            {
                NearElementId = Mark.SearchResult.Id;
                NearPos       = MarkPos;
            }
        }

        for ( var CurPos = StartPos; CurPos < NearPos; CurPos++ )
        {
            var Item = this.Content[CurPos];
            if ( para_Drawing === Item.Type )
            {
                var TempElementId = Item.Search_GetId( true, false );
                if ( null != TempElementId )
                    return TempElementId;
            }
        }
    }
    else
    {
        var NearPos = -1;

        var SearchMarksCount = this.SearchMarks.length;
        for ( var SPos = 0; SPos < SearchMarksCount; SPos++)
        {
            var Mark = this.SearchMarks[SPos];
            var MarkPos = Mark.SearchResult.StartPos.Get(Mark.Depth);

            if (Mark.SearchResult.ClassesS.length > 0 && this === Mark.SearchResult.ClassesS[Mark.SearchResult.ClassesS.length - 1] && MarkPos < StartPos && MarkPos > NearPos)
            {
                NearElementId = Mark.SearchResult.Id;
                NearPos       = MarkPos;
            }
        }

        StartPos = Math.min( this.Content.length - 1, StartPos - 1 );
        for ( var CurPos = StartPos; CurPos > NearPos; CurPos-- )
        {
            var Item = this.Content[CurPos];
            if ( para_Drawing === Item.Type )
            {
                var TempElementId = Item.Search_GetId( false, false );
                if ( null != TempElementId )
                    return TempElementId;
            }
        }

    }

    return NearElementId;
};
//----------------------------------------------------------------------------------------------------------------------
// ParaMath
//----------------------------------------------------------------------------------------------------------------------
ParaMath.prototype.Search = function(ParaSearch, Depth)
{
    // Обнуляем поиск
    //ParaSearch.Reset();

    this.SearchMarks = [];
    this.Root.Search(ParaSearch, Depth);


};

ParaMath.prototype.Add_SearchResult = function(SearchResult, Start, ContentPos, Depth)
{
    this.Root.Add_SearchResult(SearchResult, Start, ContentPos, Depth);
};

ParaMath.prototype.Clear_SearchResults = function()
{
    this.Root.Clear_SearchResults();
};

ParaMath.prototype.Remove_SearchResult = function(SearchResult)
{
    this.Root.Remove_SearchResult(SearchResult);
};

ParaMath.prototype.Search_GetId = function(bNext, bUseContentPos, ContentPos, Depth)
{
    return this.Root.Search_GetId(bNext, bUseContentPos, ContentPos, Depth);
    //return null;
};
//----------------------------------------------------------------------------------------------------------------------
// CBLockLevelSdt
//----------------------------------------------------------------------------------------------------------------------
CBlockLevelSdt.prototype.Search = function(Str, Props, SearchEngine, Type)
{
	this.Content.Search(Str, Props, SearchEngine, Type);
};
CBlockLevelSdt.prototype.Search_GetId = function(bNext, bCurrent)
{
	return this.Content.Search_GetId(bNext, bCurrent);
};

//----------------------------------------------------------------------------------------------------------------------
// Вспомогательные классы для поиска внутри параграфа
//----------------------------------------------------------------------------------------------------------------------
function CParagraphSearch(Paragraph, Str, Props, SearchEngine, Type)
{
    this.Paragraph    = Paragraph;
    this.Str          = Str;
    this.Props        = Props;
    this.SearchEngine = SearchEngine;
    this.Type         = Type;

    this.ContentPos   = new CParagraphContentPos();

    this.StartPos     = null; // Запоминаем здесь стартовую позицию поиска
    this.SearchIndex  = 0;    // Номер символа, с которым мы проверяем совпадение
}

CParagraphSearch.prototype =
{
    Reset : function()
    {
        this.StartPos    = null;
        this.SearchIndex = 0;
    }
};

function CParagraphSearchMark(SearchResult, Start, Depth)
{
    this.SearchResult = SearchResult;
    this.Start        = Start;
    this.Depth        = Depth;
}

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

//----------------------------------------------------------------------------------------------------------------------
// CDocumentSpelling
//         Проверка орфографии в документе. Здесь будут хранится параграфы, которые надо проверить. Параграфы, в
//         которых уже есть неверно набранные слова, а также набор слов, которые игнорируются при проверке.
//----------------------------------------------------------------------------------------------------------------------
  
// Import
var g_oTableId = AscCommon.g_oTableId;

var DOCUMENT_SPELLING_MAX_PARAGRAPHS = 50;  // максимальное количество параграфов, которые мы проверяем в таймере
var DOCUMENT_SPELLING_MAX_ERRORS     = 2000; // максимальное количество ошибок, которые отрисовываются

var DOCUMENT_SPELLING_EXCEPTIONAL_WORDS =
{
    "Teamlab" : true,  "teamlab" : true, "OnlyOffice" : true, "ONLYOFFICE" : true, "API" : true
};


function CDocumentSpelling()
{
    this.Use          = true;
    this.TurnOn       = 1;
    this.ErrorsExceed = false;
    this.Paragraphs  = {}; // Параграфы, в которых есть ошибки в орфографии (объект с ключом - Id параграфа)
    this.Words       = {}; // Слова, которые пользователь решил пропустить(нажал "пропустить все") при проверке орфографии
    this.CheckPara   = {}; // Параграфы, в которых нужно запустить проверку орфографии
    this.CurPara     = {}; // Параграфы, в которых мы не проверили некотырые слова, из-за того что в них стоял курсор
    
    this.WaitingParagraphs      = {}; // Параграфы, которые ждут ответа от сервера
    this.WaitingParagraphsCount = 0; 

    // Заполним начальный список исключений
    this.Words = DOCUMENT_SPELLING_EXCEPTIONAL_WORDS;
}

CDocumentSpelling.prototype =
{
    TurnOff : function()
    {
        this.TurnOn -= 1;
    },

    TurnOn : function()
    {
        this.TurnOn += 1;
    },

    Add_Paragraph : function(Id, Para)
    {
        this.Paragraphs[Id] = Para;
    },

    Remove_Paragraph : function(Id)
    {
        delete this.Paragraphs[Id];
    },
    
    Reset : function() 
    {
        this.Paragraphs = {};
        this.CheckPara  = {};
        this.CurPara    = {};

        this.WaitingParagraphs      = {};
        this.WaitingParagraphsCount = 0;
        
        this.ErrorsExceed = false;
    },    

    Check_Word : function(Word)
    {
        if ( undefined != this.Words[Word] )
            return true;

        return false;
    },

    Add_Word : function(Word)
    {
        this.Words[Word] = true;

        for ( var Id in this.Paragraphs )
        {
            var Para = this.Paragraphs[Id];
            Para.SpellChecker.Ignore( Word );
        }
    },

    Add_ParagraphToCheck : function(Id, Para)
    {
        this.CheckPara[Id] = Para;
    },
    
    GetErrorsCount : function()
    {
        var Count = 0;
        for (var Id in this.Paragraphs)
        {
            var Para = this.Paragraphs[Id];
            Count += Para.SpellChecker.GetErrorsCount();
        }     
        
        return Count;
    },

    ContinueCheckSpelling : function()
    {
        if (0 == this.TurnOn)
            return;

        if (true === this.ErrorsExceed)
            return;
        
        // Пока не обработались предыдущие параграфы, новые не стартуем
        if (this.WaitingParagraphsCount <= 0)
		{
			// Эта функция запускается в таймере, поэтому здесь сразу все параграфы не проверяем, чтобы не было
			// притормоза большого, а запускаем по несколько штук.

			var nCounter = 0;
			for (var sId in this.CheckPara)
			{
				var oParagraph = this.CheckPara[sId];

				if (!oParagraph.ContinueCheckSpelling(false))
					break;

				delete this.CheckPara[sId];
				nCounter++;

				if (nCounter > DOCUMENT_SPELLING_MAX_PARAGRAPHS)
					break;
			}

			// TODO: Послать сообщение
			if (this.GetErrorsCount() > DOCUMENT_SPELLING_MAX_ERRORS)
				this.ErrorsExceed = true;
		}

        for ( var Id in this.CurPara )
        {
            var Para = this.CurPara[Id];
            delete this.CurPara[Id];
            Para.SpellChecker.Reset_ElementsWithCurPos();
            Para.SpellChecker.Check();
        }
    },

    Add_CurPara : function(Id, Para)
    {
        this.CurPara[Id] = Para;
    },

    Check_CurParas : function()
    {
        for ( var Id in this.CheckPara )
        {
            var Para = this.CheckPara[Id];
            Para.ContinueCheckSpelling(true);
            delete this.CheckPara[Id];
        }

        for ( var Id in this.CurPara )
        {
            var Para = this.CurPara[Id];
            delete this.CurPara[Id];
            Para.SpellChecker.Reset_ElementsWithCurPos();
            Para.SpellChecker.Check(undefined, true);
        }
    },
    
    Add_WaitingParagraph : function(Para, RecalcId, Words, Langs)
    {
        var ParaId = Para.Get_Id();
        var WPara = this.WaitingParagraphs[ParaId];
        if (undefined === WPara || RecalcId !== WPara.RecalcId || true !== this.private_CompareWordsAndLangs(WPara.Words, Words, WPara.Langs, Langs))
        {
            this.WaitingParagraphs[ParaId] = {Words : Words, Langs : Langs, RecalcId : RecalcId};
            this.WaitingParagraphsCount++;

            return true;
        }

        return false;
    },

    Check_WaitingParagraph : function(Para)
    {
        var ParaId = Para.Get_Id();
        if (undefined === this.WaitingParagraphs[ParaId])
            return false;

        return true;
    },
    
    Remove_WaitingParagraph : function(Para)
    {
        var ParaId = Para.Get_Id();
        if (undefined !== this.WaitingParagraphs[ParaId])
        {
            delete this.WaitingParagraphs[ParaId];
            this.WaitingParagraphsCount--;
        }
    },

    private_CompareWordsAndLangs : function(Words1, Words2, Langs1, Langs2)
    {
        if (undefined === Words1
            || undefined === Words2
            || undefined === Langs1
            || undefined === Langs2
            || Words1.length !== Words2.length
            || Words1.length !== Langs1.length
            || Words1.length !== Langs2.length)
            return false;

        for (var nIndex = 0, nCount = Words1.length; nIndex < nCount; nIndex++)
        {
            if (Words1[nIndex] !== Words2[nIndex] || Langs1[nIndex] !== Langs2[nIndex])
                return false;
        }

        return true;
    }
};

//----------------------------------------------------------------------------------------------------------------------
// CParaSpellChecker
//         Проверка орфографии внутри одного параграфа. Тут хранится массив всех слов(CParaSpellCheckerElement) в
//         параграфе.
//----------------------------------------------------------------------------------------------------------------------
function CParaSpellChecker(Paragraph)
{
    this.Elements  = [];
    this.RecalcId  = -1;
    this.ParaId    = -1;
    this.Paragraph = Paragraph;
    
    this.Words     = {};

    this.Engine    = null;
}

CParaSpellChecker.prototype =
{
    Clear : function()
    {
        var Count = this.Elements.length;

        for (var Index = 0; Index < Count; Index++)
        {
            var Element = this.Elements[Index];
            
            if (Element.StartRun !== Element.EndRun)
            {
                Element.StartRun.Clear_SpellingMarks();
                Element.EndRun.Clear_SpellingMarks();
            }
            else
            {
                Element.StartRun.Clear_SpellingMarks();
            }

//            var Count2 = Element.ClassesS.length;
//            for ( var Index2 = 1; Index2 < Count2; Index2++ )
//            {
//                Element.ClassesS[Index2].Clear_SpellingMarks();
//            }
//
//            Count2 = Element.ClassesE.length;
//            for ( var Index2 = 1; Index2 < Count2; Index2++ )
//            {
//                Element.ClassesE[Index2].Clear_SpellingMarks();
//            }
        }

        this.Elements = [];
        this.Words    = {};
    },

    Add : function(StartPos, EndPos, Word, Lang)
    {
    	if (Word.length > 0)
		{
			if (Word.charAt(Word.length - 1) == '\'')
				Word = Word.substr(0, Word.length - 1);
			if (Word.charAt(0) == '\'')
				Word = Word.substr(1);
		}

        var SpellCheckerEl = new CParaSpellCheckerElement( StartPos, EndPos, Word, Lang );
        this.Paragraph.Add_SpellCheckerElement( SpellCheckerEl );
        this.Elements.push( SpellCheckerEl );
    },
    
    GetErrorsCount : function()
    {
        var ErrorsCount = 0;
        var ElementsCount = this.Elements.length;
        for (var Index = 0; Index < ElementsCount; Index++)
        {
            var Element = this.Elements[Index];
            if (false === Element.Checked)
                ErrorsCount++;
        }
        
        return ErrorsCount;
    },

    Check : function(ParagraphForceRedraw, _bForceCheckCur)
    {
        var bForceCheckCur = ( true != _bForceCheckCur ? false : true )
        var Paragraph = g_oTableId.Get_ById( this.ParaId );
        var bCurrent = ( true === bForceCheckCur ? false : Paragraph.Is_ThisElementCurrent() );

        var CurPos = -1;

        if ( true === bCurrent && false === Paragraph.Selection.Use )
            CurPos = Paragraph.Get_ParaContentPos( false, false );

        var usrWords = [];
        var usrLang  = [];

        var Count = this.Elements.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            var Element = this.Elements[Index];
            Element.CurPos = false;

            if ( 1 >= Element.Word.length )
                Element.Checked = true;
            else if ( editor.asc_IsSpellCheckCurrentWord() !== true && null === Element.Checked && -1 != CurPos && Element.EndPos.Compare( CurPos ) >= 0 && Element.StartPos.Compare( CurPos ) <= 0 )
            {
                Element.Checked = true;
                Element.CurPos  = true;
                editor.WordControl.m_oLogicDocument.Spelling.Add_CurPara( this.ParaId, g_oTableId.Get_ById( this.ParaId ) );
            }

            if ( null === Element.Checked )
            {
                usrWords.push(this.Elements[Index].Word);
                usrLang.push(this.Elements[Index].Lang);
            }
        }

        if ( 0 < usrWords.length )        
        {
            if (true === editor.WordControl.m_oLogicDocument.Spelling.Add_WaitingParagraph(this.Paragraph, this.RecalcId, usrWords, usrLang))
            {
                editor.spellCheck({"type" : "spell", "ParagraphId" : this.ParaId, "RecalcId" : this.RecalcId, "ElementId" : 0, "usrWords" : usrWords, "usrLang" : usrLang });
            }
            else
            {
                // Значит данный параграф с таким запросом уже обрабатывается
            }
        }
        else if ( undefined != ParagraphForceRedraw )
            ParagraphForceRedraw.ReDraw();
    },

    Check_CallBack : function(RecalcId, UsrCorrect)
    {
        if ( RecalcId == this.RecalcId )
        {
            var DocumentSpelling = editor.WordControl.m_oLogicDocument.Spelling;
            var Count = this.Elements.length;
            var Index2 = 0;
            for ( var Index = 0; Index < Count; Index++ )
            {
                var Element = this.Elements[Index];

                if ( null === Element.Checked && true != Element.Checked )
                {
                    // Если слово есть в локальном словаре, не проверяем его
                    if ( true === DocumentSpelling.Check_Word( Element.Word ) )
                        Element.Checked = true;
                    else
                        Element.Checked = UsrCorrect[Index2];

                    Index2++;
                }
            }
            
            this.Update_WordsList();
            this.Remove_RightWords();
            
            this.Internal_UpdateParagraphState();
        }

        editor.WordControl.m_oLogicDocument.Spelling.Remove_WaitingParagraph(this.Paragraph);
    },

    Internal_UpdateParagraphState : function()
    {
        var DocumentSpelling = editor.WordControl.m_oLogicDocument.Spelling;

        var bMisspeled = false;
        var Count = this.Elements.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            // Если есть хоть одно неправильное слово, запоминаем этот параграф
            if ( false === this.Elements[Index].Checked )
                bMisspeled = true;
        }

        if ( true === bMisspeled )
            DocumentSpelling.Add_Paragraph( this.ParaId, g_oTableId.Get_ById( this.ParaId ) );
        else
            DocumentSpelling.Remove_Paragraph( this.ParaId );
    },

    Check_Spelling : function(Pos)
    {
        var Count = this.Elements.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            var Element = this.Elements[Index];
            if ( Element.StartPos > Pos )
                break;
            else if ( Element.EndPos < Pos )
                continue;
            else
            {
                return (Element.Checked === null ? true : Element.Checked);
            }
        }

        return true;
    },

    Document_UpdateInterfaceState : function(StartPos, EndPos)
	{
		// Надо определить, попадает ли какое-либо неверно набранное слово в заданный промежуток, и одно ли оно
		var Count        = this.Elements.length;
		var FoundElement = null;
		var FoundIndex   = -1;
		for (var Index = 0; Index < Count; Index++)
		{
			var Element = this.Elements[Index];
			if (Element.StartPos.Compare(EndPos) <= 0 && Element.EndPos.Compare(StartPos) >= 0 && false === Element.Checked)
			{
				if (null != FoundElement)
				{
					FoundElement = null;
					break;
				}
				else
				{
					FoundIndex   = Index;
					FoundElement = Element;
				}
			}
		}

		var Word     = "";
		var Variants = null;
		var Checked  = null;

		if (null != FoundElement)
		{
			Word     = FoundElement.Word;
			Variants = FoundElement.Variants;
			Checked  = FoundElement.Checked;

			if (null === Variants && false === editor.WordControl.m_oLogicDocument.Spelling.Check_WaitingParagraph(this.Paragraph))
			{
				editor.spellCheck({
					"type"        : "suggest",
					"ParagraphId" : this.ParaId,
					"RecalcId"    : this.RecalcId,
					"ElementId"   : FoundIndex,
					"usrWords"    : [Word],
					"usrLang"     : [FoundElement.Lang]
				});
			}
		}

		// Неопределенное слово посылаем как хорошее в интерфейс
		if (null === Checked)
			Checked = true;

		editor.sync_SpellCheckCallback(Word, Checked, Variants, this.ParaId, FoundElement);
	},

    Check_CallBack2: function(RecalcId, ElementId, usrVariants)
    {
        if (RecalcId == this.RecalcId && undefined !== this.Elements[ElementId])
        {
            this.Elements[ElementId].Variants = usrVariants[0];
            
            var Count = DOCUMENT_SPELLING_EASTEGGS.length;
            for (var Index = 0; Index < Count; Index++)
            {
                if (DOCUMENT_SPELLING_EASTEGGS[Index] === this.Elements[ElementId].Word)
                {
                    this.Elements[ElementId].Variants = DOCUMENT_SPELLING_EASTEGGS_VARIANTS[Index];
                }
            }

            var Element = this.Elements[ElementId];
            if (undefined !== this.Words[Element.Word] && undefined !== this.Words[Element.Word][Element.LangId])
                this.Words[Element.Word][Element.LangId] = Element.Variants;
        }
    },

    Ignore : function(Word)
    {
        var Count = this.Elements.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            var Element = this.Elements[Index];
            if ( false === Element.Checked && Word === Element.Word )
                Element.Checked = true;
        }

        if (undefined !== this.Words[Word])
            delete this.Words[Word];

        this.Internal_UpdateParagraphState();
    },

    Update_OnAdd : function(Paragraph, Pos, Item)
    {
        var RecalcInfo = ( undefined !== Paragraph.Paragraph ? Paragraph.Paragraph.RecalcInfo : Paragraph.RecalcInfo );
        RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );
    },

    Update_OnRemove : function(Paragraph, Pos, Count)
    {
        var RecalcInfo = ( undefined !== Paragraph.Paragraph ? Paragraph.Paragraph.RecalcInfo : Paragraph.RecalcInfo );
        RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );
    },

    Reset_ElementsWithCurPos : function()
    {
        var Count = this.Elements.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            var Element = this.Elements[Index];
            if ( true === Element.CurPos )
                Element.Checked = null;
        }
    },

    Compare_WithPrevious : function(OldElements)
    {
        var ElementsCount = this.Elements.length;

        for (var Index = 0; Index < ElementsCount; Index++)
        {
            var Element = this.Elements[Index];

            var Word = Element.Word;
            var Lang = Element.Lang;
            
            if (undefined !== this.Words[Word])
            {
                if (true === this.Words[Word][Lang])
                {
                    Element.Checked  = true;
                    Element.Variants = null;
                }
                else if (undefined === this.Words[Word][Lang])
                {
                    Element.Checked  = null;
                    Element.Variants = null;
                }
                else
                {
                    Element.Checked  = false;
                    Element.Variants = this.Words[Word][Lang];
                }
            }
        }
        
        this.Clear_WordsList();
        this.Update_WordsList();
        this.Remove_RightWords();       
    },
    
    Clear_WordsList : function()
    {
        this.Words = {};
    },
    
    Update_WordsList : function()
    {
        var Count = this.Elements.length;
        for (var Index = Count - 1; Index >= 0; Index--)
        {
            var Element = this.Elements[Index];

            if (true === Element.Checked && true !== Element.CurPos)
            {
                if (undefined == this.Words[Element.Word])
                    this.Words[Element.Word] = {};

                if (undefined === this.Words[Element.Word][Element.Lang])
                    this.Words[Element.Word][Element.Lang] = true;
            }
            else if (false === Element.Checked)
            {
                if (undefined == this.Words[Element.Word])
                    this.Words[Element.Word] = {};

                if (undefined === this.Words[Element.Word][Element.Lang])
                    this.Words[Element.Word][Element.Lang] = Element.Variants;
            }
        }        
    },

	Remove_RightWords : function()
	{
		var Count = this.Elements.length;
		for (var Index = Count - 1; Index >= 0; Index--)
		{
			var Element = this.Elements[Index];

			if (true === Element.Checked && true !== Element.CurPos)
			{
				if (Element.StartRun !== Element.EndRun)
				{
					Element.StartRun.Remove_SpellCheckerElement(Element);
					Element.EndRun.Remove_SpellCheckerElement(Element);
				}
				else
					Element.EndRun.Remove_SpellCheckerElement(Element);

				this.Elements.splice(Index, 1);
			}
		}
	}
};
/**
 * Получаем количество элементов проверки орфографии
 * @returns {Number}
 */
CParaSpellChecker.prototype.GetElementsCount = function()
{
	return this.Elements.length;
};
/**
 * Получаем элемент проверки орфографии по номеру
 * @param nIndex
 * @returns {CParaSpellCheckerElement}
 */
CParaSpellChecker.prototype.GetElement = function(nIndex)
{
	return this.Elements[nIndex];
};
/**
 * Приостанавливаем проверку орфографии, если параграф слишком большой
 * @param {CParagraphSpellCheckerEngine} oEngine
 */
CParaSpellChecker.prototype.Pause = function(oEngine)
{
	this.Engine = oEngine;
};
/**
 * Проверяем приостановлена ли проверка в данном параграфе
 * @return {boolean}
 */
CParaSpellChecker.prototype.IsPaused = function()
{
	return !!(this.Engine);
};
/**
 * Получаем класс для проверки орфографии внутри параграфа, на котором была сделана остановка
 * @return {null|CParagraphSpellCheckerEngine}
 */
CParaSpellChecker.prototype.GetPausedEngine = function()
{
	return this.Engine;
};
/**
 * Очищаем остановленное состояние
 */
CParaSpellChecker.prototype.ClearPausedEngine = function()
{
	this.Engine = null;
};

//----------------------------------------------------------------------------------------------------------------------
// CParaSpellCheckerElement
//----------------------------------------------------------------------------------------------------------------------
function CParaSpellCheckerElement(StartPos, EndPos, Word, Lang)
{
    this.StartPos = StartPos;
    this.EndPos   = EndPos;
    this.Word     = Word;
    this.Lang     = Lang;
    this.Checked  = null; // null - неизвестно, true - правильное слово, false - неправильное слово
    this.CurPos   = false;
    this.Variants = null;

    this.StartRun = null;
    this.EndRun   = null;
}

CParaSpellCheckerElement.prototype = {};
CParaSpellCheckerElement.prototype.GetStartPos = function()
{
	return this.StartPos;
};
CParaSpellCheckerElement.prototype.GetEndPos = function()
{
	return this.EndPos;
};

//----------------------------------------------------------------------------------------------------------------------
// CDocument
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.Set_DefaultLanguage = function(NewLangId)
{    
    // Устанавливаем словарь по умолчанию
    var Styles = this.Styles;    
    var OldLangId = Styles.Default.TextPr.Lang.Val;
    this.History.Add(new CChangesDocumentDefaultLanguage(this, OldLangId, NewLangId));
    Styles.Default.TextPr.Lang.Val = NewLangId;

    // Нужно заново запустить проверку орфографии
    this.Restart_CheckSpelling();
    
    this.Document_UpdateInterfaceState();
};

CDocument.prototype.Get_DefaultLanguage = function()
{
    var Styles = this.Styles;
    return Styles.Default.TextPr.Lang.Val;
};

CDocument.prototype.Restart_CheckSpelling = function()
{
    this.Spelling.Reset();
    
    // TODO: добавить обработку в автофигурах
    this.SectionsInfo.Restart_CheckSpelling();

    var Count = this.Content.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        this.Content[Index].Restart_CheckSpelling();
    }
};

CDocument.prototype.Stop_CheckSpelling = function()
{
    this.Spelling.Reset();
};

CDocument.prototype.ContinueCheckSpelling = function()
{
    this.Spelling.ContinueCheckSpelling();
};

CDocument.prototype.TurnOff_CheckSpelling = function()
{
    this.Spelling.TurnOff();
};
CDocument.prototype.TurnOn_CheckSpelling = function()
{
    this.Spelling.TurnOn();
};

//----------------------------------------------------------------------------------------------------------------------
// CDocumentContent
//----------------------------------------------------------------------------------------------------------------------
CDocumentContent.prototype.Restart_CheckSpelling = function()
{
    var Count = this.Content.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        this.Content[Index].Restart_CheckSpelling();
    }
};

//----------------------------------------------------------------------------------------------------------------------
// CHeaderFooter
//----------------------------------------------------------------------------------------------------------------------
CHeaderFooter.prototype.Restart_CheckSpelling = function()
{
    this.Content.Restart_CheckSpelling();
};

//----------------------------------------------------------------------------------------------------------------------
// CDocumentSectionsInfo
//----------------------------------------------------------------------------------------------------------------------
CDocumentSectionsInfo.prototype.Restart_CheckSpelling = function()
{
    var bEvenOdd = EvenAndOddHeaders;
    var Count = this.Elements.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        var SectPr = this.Elements[Index].SectPr;
        var bFirst = SectPr.Get_TitlePage();

        if ( null != SectPr.HeaderFirst && true === bFirst )
            SectPr.HeaderFirst.Restart_CheckSpelling();

        if ( null != SectPr.HeaderEven && true === bEvenOdd )
            SectPr.HeaderEven.Restart_CheckSpelling();

        if ( null != SectPr.HeaderDefault )
            SectPr.HeaderDefault.Restart_CheckSpelling();

        if ( null != SectPr.FooterFirst && true === bFirst )
            SectPr.FooterFirst.Restart_CheckSpelling();

        if ( null != SectPr.FooterEven && true === bEvenOdd )
            SectPr.FooterEven.Restart_CheckSpelling();

        if ( null != SectPr.FooterDefault )
            SectPr.FooterDefault.Restart_CheckSpelling();
    }
};

//----------------------------------------------------------------------------------------------------------------------
// CTable
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.Restart_CheckSpelling = function()
{
    this.Recalc_CompiledPr();

    var RowsCount = this.Content.length;
    for ( var CurRow = 0; CurRow < RowsCount; CurRow++ )
    {
        var Row = this.Content[CurRow];
        Row.Recalc_CompiledPr();
        var CellsCount = Row.Get_CellsCount();

        for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
        {
            var Cell = Row.Get_Cell(CurCell);
            Cell.Recalc_CompiledPr();
            Cell.Content.Restart_CheckSpelling();
        }
    }
};

//----------------------------------------------------------------------------------------------------------------------
// Paragraph
//----------------------------------------------------------------------------------------------------------------------
Paragraph.prototype.Restart_CheckSpelling = function()
{
    this.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );
    
    // Пересчитываем скомпилированный стиль для самого параграфа и для всех ранов в данном параграфе
    this.Recalc_CompiledPr();

    for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; nIndex++)
    {
        this.Content[nIndex].Restart_CheckSpelling();
    }

    this.LogicDocument.Spelling.Add_ParagraphToCheck(this.Get_Id(), this);
};

Paragraph.prototype.Internal_CheckPunctuationBreak = function(_Pos)
{
    // В позиции Pos у нас стоит знак пунктуации, проверяем, идет ли за ним сразу текст

    var Count = this.Content.length;
    for ( var Pos = _Pos + 1; Pos < Count; Pos++ )
    {
        var Item = this.Content[Pos];

        if ( para_Text === Item.Type &&  false === Item.Is_Punctuation() && false === Item.Is_NBSP() && false === Item.Is_Number() && false === Item.Is_SpecialSymbol() )
        {
            return true;
        }
        else if ( para_CollaborativeChangesEnd === Item.Type || para_CollaborativeChangesStart === Item.Type )
            continue;
        else
        {
            return false;
        }
    }

};

Paragraph.prototype.Internal_CheckSpelling = function()
{
    if ( pararecalc_0_Spell_None !== this.RecalcInfo.Recalc_0_Spell.Type )
    {
        if (this === g_oTableId.Get_ById(this.Get_Id()))
            this.LogicDocument && this.LogicDocument.Spelling.Add_ParagraphToCheck(this.Get_Id(), this);
    }
};

/**
 * Производим проверку орфографии.
 * @param isForceFullCheck {boolean} принуждаем параграф проверить целиком, даже если он большой
 * @return {boolean} true - проверка прошла до конца, false - параграф слишком большой и за один раз проверка не выполнилась
 */
Paragraph.prototype.ContinueCheckSpelling = function(isForceFullCheck)
{
    var ParaForceRedraw = undefined;
    var CheckLang = false;
    if ( pararecalc_0_Spell_None === this.RecalcInfo.Recalc_0_Spell.Type )
        return true;
    else
    {
        var OldElements = this.SpellChecker.Elements;

		var oSpellCheckerEngine,
			nStartPos = 0;
        if (this.SpellChecker.IsPaused())
		{
			oSpellCheckerEngine = this.SpellChecker.GetPausedEngine();
			oSpellCheckerEngine.SetFindStart(true);
			oSpellCheckerEngine.ResetCheckedCounter();

			nStartPos = oSpellCheckerEngine.GetPos(0);
		}
		else
		{
			oSpellCheckerEngine = new CParagraphSpellCheckerEngine(this.SpellChecker, isForceFullCheck);

			this.SpellChecker.Elements = [];
		}

		for (var nPos = nStartPos, nCount = this.Content.length; nPos < nCount; ++nPos)
		{
			var oItem = this.Content[nPos];

			oSpellCheckerEngine.UpdatePos(nPos, 0);
			oItem.CheckSpelling(oSpellCheckerEngine, 1);

			if (oSpellCheckerEngine.IsExceedLimit())
				break;
		}

		if (oSpellCheckerEngine.IsExceedLimit())
		{
			this.SpellChecker.Pause(oSpellCheckerEngine);
			return false;
		}

        //if ( true === this.SpellChecker.Compare_WithPrevious( OldElements ) )
        //    ParaForceRedraw = this;

        // TODO: Мы не можем здесь проверить надо ли перерисовывать параграф или нет, потому что возможно у нас в
        //       параграф вставили/удалили элемент, который не повлиял на орфографию, т.е. фактически ни 1 слова не
        //       изменилось, но при этом изменились метки начала и конца подчеркивания орфографии. Если можно это 
        //       отследить, тогда можно будет вернуться к предыдущему варианту.
        this.SpellChecker.Compare_WithPrevious( OldElements );
        ParaForceRedraw = this;

        // Не надо проверять отдельно языки
        CheckLang = false;
    }

    // Специальная проверка на наличие буквицы в предыдущем параграфе. Если она есть, то первое слово мы не проверяем
    var PrevPara = this.Get_DocumentPrev();
    if ( null != PrevPara && type_Paragraph === PrevPara.GetType() && undefined != PrevPara.Get_FramePr() && undefined != PrevPara.Get_FramePr().DropCap )
    {
        if ( this.SpellChecker.Elements.length > 0 )
        {
            var bDontCheckFirstWord = true;
            var Element = this.SpellChecker.Elements[0];
            var StartPos = Element.StartPos;
            for ( var TempPos = 0; TempPos < StartPos; TempPos++  )
            {
                var Item = this.Content[TempPos];
                if ( para_Space === Item.Type )
                {
                    bDontCheckFirstWord = false;
                    break;
                }
            }

            if ( true === bDontCheckFirstWord && true != Element.Checked )
            {
                Element.Checked = true;
                ParaForceRedraw = this;
            }
        }
    }

    if ( true === CheckLang )
    {
        // Пройдемся по всем словам и проверим словарь, в котором должно проверяться слово (если словарь поменялся,
        // тогда слово отправляет на проверку)
        var WordsCount = this.SpellChecker.Elements.length;
        for ( var ElemId = 0; ElemId < WordsCount; ElemId++ )
        {
            var Element = this.SpellChecker.Elements[ElemId];
            var CurLang = Element.Lang;
            var Lang = this.Internal_GetLang( Element.EndPos );
            if ( CurLang != Lang.Val )
            {
                Element.Lang     = Lang.Val;
                Element.Checked  = null;
                Element.Variants = null;
            }
        }
    }

    // Если у нас осталось одно слово в параграфе, состоящее из одной буквы, тогда надо перерисовать данный параграф,
    // чтобы избавиться от подчеркивания.
    if ( 1 === this.SpellChecker.Elements.length && 1 === this.SpellChecker.Elements[0].Word.length )
        ParaForceRedraw = this;

    this.SpellChecker.RecalcId = this.LogicDocument.RecalcId;
    this.SpellChecker.ParaId   = this.Get_Id();
    this.SpellChecker.Check(ParaForceRedraw );

    this.RecalcInfo.Recalc_0_Spell.Type = pararecalc_0_Spell_None;

    return true;
};

Paragraph.prototype.Add_SpellCheckerElement = function(Element)
{   
//    Element.ClassesS.push( this );
//    Element.ClassesE.push( this );
//
    var StartPos = Element.StartPos.Get(0);
    var EndPos   = Element.EndPos.Get(0);

    this.Content[StartPos].Add_SpellCheckerElement( Element, true, 1 );
    this.Content[EndPos].Add_SpellCheckerElement( Element, false, 1 );
};
//----------------------------------------------------------------------------------------------------------------------
// ParaRun
//----------------------------------------------------------------------------------------------------------------------
ParaRun.prototype.Restart_CheckSpelling = function()
{
    this.Recalc_CompiledPr(false);

    for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; nIndex++)
    {
        var Item = this.Content[nIndex];

        if (para_Drawing === Item.Type)
            Item.Restart_CheckSpelling();
    }
};

ParaRun.prototype.CheckSpelling = function(oSpellCheckerEngine, nDepth)
{
	if (oSpellCheckerEngine.IsExceedLimit())
		return;

	var nStartPos = 0;

	var bWord        = oSpellCheckerEngine.bWord;
	var sWord        = oSpellCheckerEngine.sWord;
	var CurLcid      = oSpellCheckerEngine.CurLcid;
	var SpellChecker = oSpellCheckerEngine.SpellChecker;
	var ContentPos   = oSpellCheckerEngine.ContentPos;

	var oCurTextPr = this.Get_CompiledPr(false);

	if (oSpellCheckerEngine.IsFindStart())
	{
		nStartPos = oSpellCheckerEngine.GetPos(nDepth);
		oSpellCheckerEngine.SetFindStart(false);
	}
	else
	{
		this.SpellingMarks = [];

		if (true === this.IsEmpty())
			return;

		if (true === bWord && CurLcid !== oCurTextPr.Lang.Val)
		{
			bWord = false;
			SpellChecker.Add(oSpellCheckerEngine.StartPos, oSpellCheckerEngine.EndPos, sWord, CurLcid);
		}

		CurLcid = oCurTextPr.Lang.Val;
	}

    for (var nPos = nStartPos, nContentLen = this.Content.length; nPos < nContentLen; ++nPos)
	{
		if (oSpellCheckerEngine.IsExceedLimit())
		{
			oSpellCheckerEngine.UpdatePos(nPos, nDepth);
			break;
		}

		var oItem = this.Content[nPos];

		//if ( para_Text === oItem.Type && ( false === oItem.Is_Punctuation() || ( true === bWord && true === this.Internal_CheckPunctuationBreak( nPos ) ) ) && false === oItem.Is_NBSP() && false === oItem.Is_Number() && false === oItem.Is_SpecialSymbol() )
		if (para_Text === oItem.Get_Type() && false === oItem.Is_Punctuation() && false === oItem.Is_NBSP() && false === oItem.Is_Number() && false === oItem.Is_SpecialSymbol())
		{
			if (false === bWord)
			{
				var StartPos = ContentPos.Copy();
				var EndPos   = ContentPos.Copy();

				StartPos.Update(nPos, nDepth);
				EndPos.Update(nPos + 1, nDepth);

				bWord = true;

				sWord = oItem.GetCharForSpellCheck(oCurTextPr.Caps);

				oSpellCheckerEngine.StartPos = StartPos;
				oSpellCheckerEngine.EndPos   = EndPos;
			}
			else
			{
				sWord += oItem.GetCharForSpellCheck(oCurTextPr.Caps);

				var EndPos = ContentPos.Copy();
				EndPos.Update(nPos + 1, nDepth);

				oSpellCheckerEngine.EndPos = EndPos;
			}
		}
		else
		{
			if (true === bWord)
			{
				bWord = false;
				SpellChecker.Add(oSpellCheckerEngine.StartPos, oSpellCheckerEngine.EndPos, sWord, CurLcid);
			}
		}

		oSpellCheckerEngine.IncreaseCheckedCounter();
	}

	oSpellCheckerEngine.bWord   = bWord;
	oSpellCheckerEngine.sWord   = sWord;
	oSpellCheckerEngine.CurLcid = CurLcid;
};

ParaRun.prototype.Add_SpellCheckerElement = function(Element, Start, Depth)
{
//    if ( true === Start )
//        Element.ClassesS.push(this);
//    else
//        Element.ClassesE.push(this);

    if ( true === Start )
        Element.StartRun = this;
    else
        Element.EndRun = this;

    this.SpellingMarks.push( new CParagraphSpellingMark( Element, Start, Depth ) );
};

ParaRun.prototype.Remove_SpellCheckerElement = function(Element)
{
    var Count = this.SpellingMarks.length;
    for (var Pos = Count - 1; Pos >= 0; Pos--)
    {
        var SpellingMark = this.SpellingMarks[Pos];
        if (Element === SpellingMark.Element)
        {
            this.SpellingMarks.splice(Pos, 1);
        }
    }    
};

ParaRun.prototype.Clear_SpellingMarks = function()
{
    this.SpellingMarks = [];
};
//----------------------------------------------------------------------------------------------------------------------
// ParaComment
//----------------------------------------------------------------------------------------------------------------------
ParaComment.prototype.Restart_CheckSpelling = function()
{
};

ParaComment.prototype.Add_SpellCheckerElement = function(Element, Start, Depth)
{
};

ParaComment.prototype.Remove_SpellCheckerElement = function(Element)
{
};

ParaComment.prototype.Clear_SpellingMarks = function()
{
};
//----------------------------------------------------------------------------------------------------------------------
// ParaMath
//----------------------------------------------------------------------------------------------------------------------
ParaMath.prototype.Restart_CheckSpelling = function()
{
};

ParaMath.prototype.CheckSpelling = function(oSpellCheckerEngine, nDepth)
{
	if (oSpellCheckerEngine.IsExceedLimit())
		return;

	if (true === oSpellCheckerEngine.bWord)
	{
		oSpellCheckerEngine.bWord = false;
		oSpellCheckerEngine.SpellChecker.Add(oSpellCheckerEngine.StartPos, oSpellCheckerEngine.EndPos, oSpellCheckerEngine.sWord, oSpellCheckerEngine.CurLcid);
	}
};

ParaMath.prototype.Add_SpellCheckerElement = function(Element, Start, Depth)
{
};

ParaMath.prototype.Remove_SpellCheckerElement = function(Element)
{
};

ParaMath.prototype.Clear_SpellingMarks = function()
{
};
//----------------------------------------------------------------------------------------------------------------------
// ParaField
//----------------------------------------------------------------------------------------------------------------------
ParaField.prototype.Restart_CheckSpelling = function()
{
};

ParaField.prototype.CheckSpelling = function(oSpellCheckerEngine, nDepth)
{
	if (oSpellCheckerEngine.IsExceedLimit())
		return;

	if (true === oSpellCheckerEngine.bWord)
	{
		oSpellCheckerEngine.bWord = false;
		oSpellCheckerEngine.SpellChecker.Add(oSpellCheckerEngine.StartPos, oSpellCheckerEngine.EndPos, oSpellCheckerEngine.sWord, oSpellCheckerEngine.CurLcid);
	}
};

ParaField.prototype.Add_SpellCheckerElement = function(Element, Start, Depth)
{
};

ParaField.prototype.Remove_SpellCheckerElement = function(Element)
{
};

ParaField.prototype.Clear_SpellingMarks = function()
{
};



function CParagraphSpellCheckerEngine(oSpellChecker, isForceFullCheck)
{
    this.ContentPos   = new CParagraphContentPos();
    this.SpellChecker = oSpellChecker;

    this.CurLcid    = -1;
    this.bWord      = false;
    this.sWord      = "";
    this.StartPos   = null; // CParagraphContentPos
    this.EndPos     = null; // CParagraphContentPos


	// Защита от проверки орфографии в большом параграфе
	this.CheckedCounter = 0;
	this.CheckedLimit   = 2000;
	this.FindStart      = false;
	this.ForceFullCheck = !!isForceFullCheck;
}
/**
 * Обновляем текущую позицию на заданной глубине
 * @param nPos {number}
 * @param nDepth {number}
 */
CParagraphSpellCheckerEngine.prototype.UpdatePos = function(nPos, nDepth)
{
	this.ContentPos.Update(nPos, nDepth);
};
/**
 * Получаем текущую позицию на заданном уровне
 * @param nDepth
 * @return {number}
 */
CParagraphSpellCheckerEngine.prototype.GetPos = function(nDepth)
{
	return this.ContentPos.Get(nDepth);
};
/**
 * Проверяем превышен ли лимит возможнных проверок в параграфе за один проход таймера
 * @return {boolean}
 */
CParagraphSpellCheckerEngine.prototype.IsExceedLimit = function()
{
	return (!this.ForceFullCheck && this.CheckedCounter >= this.CheckedLimit);
};
/**
 * Увеличиваем счетчик проверенных элементов
 */
CParagraphSpellCheckerEngine.prototype.IncreaseCheckedCounter = function()
{
	this.CheckedCounter++;
};
/**
 * Перестартовываем счетчик
 */
CParagraphSpellCheckerEngine.prototype.ResetCheckedCounter = function()
{
	this.CheckedCounter = 0;
};
/**
 * Если проверка была приостановлена и сейчас мы ищем начальную позицию
 * @return {boolean}
 */
CParagraphSpellCheckerEngine.prototype.IsFindStart = function()
{
	return this.FindStart;
};
/**
 * Выставляем ищем ли мы место, где закончили проверку прошлый раз
 * @param isFind {boolean}
 */
CParagraphSpellCheckerEngine.prototype.SetFindStart = function(isFind)
{
	this.FindStart = isFind;
};

function CParagraphSpellingMark(SpellCheckerElement, Start, Depth)
{
    this.Element = SpellCheckerElement;
    this.Start   = Start;
    this.Depth   = Depth;
}

var DOCUMENT_SPELLING_EASTEGGS          = [String.fromCharCode(0x4b, 0x69, 0x72, 0x69, 0x6c, 0x6c, 0x6f, 0x76, 0x49, 0x6c, 0x79, 0x61), String.fromCharCode(0x4b, 0x69, 0x72, 0x69, 0x6c, 0x6c, 0x6f, 0x76, 0x53, 0x65, 0x72, 0x67, 0x65, 0x79)];
var DOCUMENT_SPELLING_EASTEGGS_VARIANTS = [[String.fromCharCode(0x4b, 0x69, 0x72, 0x69, 0x6c, 0x6c, 0x6f, 0x76, 0x20, 0x49, 0x6c, 0x79, 0x61), String.fromCharCode(0x47, 0x6f, 0x6f, 0x64, 0x20, 0x6d, 0x61, 0x6e), String.fromCharCode(0x46, 0x6f, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x61, 0x74, 0x68, 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x45, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x21)], [String.fromCharCode(0x4b, 0x69, 0x72, 0x69, 0x6c, 0x6c, 0x6f, 0x76, 0x20, 0x53, 0x65, 0x72, 0x67, 0x65, 0x79, 0x20, 0x41, 0x6c, 0x62, 0x65, 0x72, 0x74, 0x6f, 0x76, 0x69, 0x63, 0x68), String.fromCharCode(0x4f, 0x6c, 0x64, 0x20, 0x77, 0x6f, 0x6c, 0x66), String.fromCharCode(0x46, 0x6f, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x66, 0x61, 0x74, 0x68, 0x65, 0x72, 0x27, 0x73, 0x20, 0x66, 0x61, 0x74, 0x68, 0x65, 0x72)]];

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

/**
 * Класс, работающий со сносками документа.
 * @param {CDocument} LogicDocument - Ссылка на главный документ.
 * @constructor
 * @extends {CDocumentControllerBase}
 */
function CFootnotesController(LogicDocument)
{
	CDocumentControllerBase.call(this, LogicDocument);

	this.Id = LogicDocument.Get_IdCounter().Get_NewId();

	this.FootnotePr = new CFootnotePr(); // Глобальные настройки для сносок
	this.FootnotePr.InitDefault();

	this.Footnote = {}; // Список всех сносок с ключом - Id.
	this.Pages    = [];

	// Специальные сноски
	this.ContinuationNoticeFootnote    = null;
	this.ContinuationSeparatorFootnote = null;
	this.SeparatorFootnote             = null;

	this.Selection = {
		Use       : false,
		Start     : {
			Footnote : null,
			Page     : 0,
			Index    : 0
		},
		End       : {
			Footnote : null,
			Page     : 0,
			Index    : 0
		},
		Footnotes : {},
		Direction : 0
	};

	this.CellLimits = []; // Для рассчета сносок, встречающихся в ячейках с минимальной или фиксированной высотой строки

	this.CurFootnote = null;

	// Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
	LogicDocument.Get_TableId().Add(this, this.Id);
}

CFootnotesController.prototype = Object.create(CDocumentControllerBase.prototype);
CFootnotesController.prototype.constructor = CFootnotesController;

/**
 * Получаем Id данного класса.
 */
CFootnotesController.prototype.Get_Id = function()
{
	return this.Id;
};
/**
 * Начальная инициализация после загрузки всех файлов.
 */
CFootnotesController.prototype.ResetSpecialFootnotes = function()
{
	var oSeparator = new CFootEndnote(this);
	oSeparator.AddToParagraph(new ParaSeparator(), false);
	var oParagraph = oSeparator.GetElement(0);
	oParagraph.Set_Spacing({After : 0, Line : 1, LineRule : Asc.linerule_Auto}, false);
	this.SetSeparator(oSeparator);

	var oContinuationSeparator = new CFootEndnote(this);
	oContinuationSeparator.AddToParagraph(new ParaContinuationSeparator(), false);
	oParagraph = oContinuationSeparator.GetElement(0);
	oParagraph.Set_Spacing({After : 0, Line : 1, LineRule : Asc.linerule_Auto}, false);
	this.SetContinuationSeparator(oContinuationSeparator);

	this.SetContinuationNotice(null);
};
/**
 * Создаем новую сноску.
 * @returns {CFootEndnote}
 */
CFootnotesController.prototype.CreateFootnote = function()
{
	var NewFootnote                     = new CFootEndnote(this);
	this.Footnote[NewFootnote.Get_Id()] = NewFootnote;

	var oHistory = this.LogicDocument.Get_History();
	oHistory.Add(new CChangesFootnotesAddFootnote(this, NewFootnote.Get_Id()));
	return NewFootnote;
};
/**
 * Добавляем сноску (функция для открытия файла)
 * @param oFootnote
 */
CFootnotesController.prototype.AddFootnote = function(oFootnote)
{
	this.Footnote[oFootnote.Get_Id()] = oFootnote;
	var oHistory                      = this.LogicDocument.Get_History();
	oHistory.Add(new CChangesFootnotesAddFootnote(this, oFootnote.Get_Id()));
};
CFootnotesController.prototype.SetSeparator = function(oFootnote)
{
	var oNewValue = oFootnote ? oFootnote : null;
	var oOldValue = this.SeparatorFootnote ? this.SeparatorFootnote : null;

	var oHistory = this.LogicDocument.Get_History();
	oHistory.Add(new CChangesFootnotesSetSeparator(this, oOldValue, oNewValue));
	this.SeparatorFootnote = oNewValue;
};
CFootnotesController.prototype.SetContinuationSeparator = function(oFootnote)
{
	var oNewValue = oFootnote ? oFootnote : null;
	var oOldValue = this.ContinuationSeparatorFootnote ? this.ContinuationSeparatorFootnote : null;

	var oHistory = this.LogicDocument.Get_History();
	oHistory.Add(new CChangesFootnotesSetContinuationSeparator(this, oOldValue, oNewValue));
	this.ContinuationSeparatorFootnote = oNewValue;
};
CFootnotesController.prototype.SetContinuationNotice = function(oFootnote)
{
	var oNewValue = oFootnote ? oFootnote : null;
	var oOldValue = this.ContinuationNoticeFootnote ? this.ContinuationNoticeFootnote : null;

	var oHistory = this.LogicDocument.Get_History();
	oHistory.Add(new CChangesFootnotesSetContinuationNotice(this, oOldValue, oNewValue));
	this.ContinuationNoticeFootnote = oNewValue;
};
CFootnotesController.prototype.SetFootnotePrNumFormat = function(nFormatType)
{
	if (undefined !== nFormatType && this.FootnotePr.NumFormat !== nFormatType)
	{
		var oHistory = this.LogicDocument.Get_History();
		oHistory.Add(new CChangesFootnotesSetFootnotePrNumFormat(this, this.FootnotePr.NumFormat, nFormatType));
		this.FootnotePr.NumFormat = nFormatType;
	}
};
CFootnotesController.prototype.SetFootnotePrPos = function(nPos)
{
	if (undefined !== nPos && this.FootnotePr.Pos !== nPos)
	{
		var oHistory = this.LogicDocument.Get_History();
		oHistory.Add(new CChangesFootnotesSetFootnotePrPos(this, this.FootnotePr.Pos, nPos));
		this.FootnotePr.Pos = nPos;
	}
};
CFootnotesController.prototype.SetFootnotePrNumStart = function(nStart)
{
	if (undefined !== nStart && this.FootnotePr.NumStart !== nStart)
	{
		var oHistory = this.LogicDocument.Get_History();
		oHistory.Add(new CChangesFootnotesSetFootnotePrNumStart(this, this.FootnotePr.NumStart, nStart));
		this.FootnotePr.NumStart = nStart;
	}
};
CFootnotesController.prototype.SetFootnotePrNumRestart = function(nRestartType)
{
	if (undefined !== nRestartType && this.FootnotePr.NumRestart !== nRestartType)
	{
		var oHistory = this.LogicDocument.Get_History();
		oHistory.Add(new CChangesFootnotesSetFootnotePrNumRestart(this, this.FootnotePr.NumRestart, nRestartType));
		this.FootnotePr.NumRestart = nRestartType;
	}
};
/**
 * Сбрасываем рассчетные данный для заданной страницы.
 * @param {number} nPageIndex
 * @param {CSectionPr} oSectPr
 */
CFootnotesController.prototype.Reset = function(nPageIndex, oSectPr)
{
	if (!this.Pages[nPageIndex])
		this.Pages[nPageIndex] = new CFootEndnotePage();

	var oPage = this.Pages[nPageIndex];
	oPage.Reset();

	var X      = oSectPr.Get_PageMargin_Left();
	var XLimit = oSectPr.Get_PageWidth() - oSectPr.Get_PageMargin_Right();

	var nColumnsCount = oSectPr.Get_ColumnsCount();
	for (var nColumnIndex = 0; nColumnIndex < nColumnsCount; ++nColumnIndex)
	{
		var _X = X;
		for (var nTempColumnIndex = 0; nTempColumnIndex < nColumnIndex; ++nTempColumnIndex)
		{
			_X += oSectPr.Get_ColumnWidth(nTempColumnIndex);
			_X += oSectPr.Get_ColumnSpace(nTempColumnIndex);
		}

		var _XLimit = (nColumnsCount - 1 !== nColumnIndex ? _X + oSectPr.Get_ColumnWidth(nColumnIndex) : XLimit);

		var oColumn    = new CFootEndnotePageColumn();
		oColumn.X      = _X;
		oColumn.XLimit = _XLimit;
		oPage.AddColumn(oColumn);
	}

	oPage.X      = X;
	oPage.XLimit = XLimit;
};
/**
 * Рассчитываем сноски, которые перенеслись с предыдущей колонки
 * @param {number} nPageAbs
 * @param {number} nColumnAbs
 * @param {number} Y
 * @param {number} YLimit
 */
CFootnotesController.prototype.ContinueElementsFromPreviousColumn = function(nPageAbs, nColumnAbs, Y, YLimit)
{
	var oColumn = this.private_GetPageColumn(nPageAbs, nColumnAbs);
	if (!oColumn)
		return;

	var nColumnsCount = this.Pages[nPageAbs].Columns.length;

	var X      = oColumn.X;
	var XLimit = oColumn.XLimit;

	var _Y      = 0;
	var _YLimit = YLimit - Y;

	oColumn.Y      = Y;
	oColumn.YLimit = YLimit;

	oColumn.Reset();
	var oPrevColumn = (nColumnAbs > 0 ? this.Pages[nPageAbs].Columns[nColumnAbs - 1] : (nPageAbs > 0 ? this.Pages[nPageAbs - 1].Columns[this.Pages[nPageAbs - 1].Columns.length - 1] : null));
	if (null !== oPrevColumn)
	{
		var arrElements = oPrevColumn.GetContinuesElements();

		if (arrElements.length > 0 && null !== this.ContinuationSeparatorFootnote)
		{
			this.ContinuationSeparatorFootnote.PrepareRecalculateObject();
			this.ContinuationSeparatorFootnote.Reset(X, _Y, XLimit, _YLimit);
			this.ContinuationSeparatorFootnote.Set_StartPage(nPageAbs, nColumnAbs, nColumnsCount);
			this.ContinuationSeparatorFootnote.Recalculate_Page(0, true);
			oColumn.ContinuationSeparatorRecalculateObject = this.ContinuationSeparatorFootnote.SaveRecalculateObject();

			var oBounds = this.ContinuationSeparatorFootnote.Get_PageBounds(0);
			_Y += oBounds.Bottom - oBounds.Top;

			oColumn.Height = _Y;
		}

		for (var nIndex = 0, nCount = arrElements.length; nIndex < nCount; ++nIndex)
		{
			var oFootnote = arrElements[nIndex];
			if (0 !== nIndex)
			{
				oFootnote.Reset(X, _Y, XLimit, _YLimit);
				oFootnote.Set_StartPage(nPageAbs, nColumnAbs, nColumnsCount);
			}

			oColumn.Elements.push(oFootnote);

			var nRelativePage = oFootnote.GetElementPageIndex(nPageAbs, nColumnAbs);
			var nRecalcResult = oFootnote.Recalculate_Page(nRelativePage, true);

			if (recalcresult2_NextPage === nRecalcResult)
			{
				// Начиная с данной сноски мы все оставшиеся сноски заносим в массив ContinuesElements у данной колонки
				var arrContinuesElements = arrElements.slice(nIndex);
				oColumn.SetContinuesElements(arrContinuesElements);
			}
			else if (recalcresult2_CurPage === nRecalcResult)
			{
				// Такого не должно быть при расчете сносок
			}

			var oBounds = oFootnote.Get_PageBounds(nRelativePage);
			_Y += oBounds.Bottom - oBounds.Top;
			oColumn.Height = _Y;

			if (recalcresult2_NextPage === nRecalcResult)
				break;
		}
	}
};
/**
 * Рассчитываем сноски, которые перенеслись с предыдущей колонки
 * @param {number} nPageAbs
 * @param {number} nColumnAbs
 * @param {number} dY
 * @param {Array.CFootEndnote} arrFootnotes
 * @returns {boolean} true - расчиталось нормально, и перенос делать не надо, false - данные сноски перенеслись на
 *     следующую страницу
 */
CFootnotesController.prototype.RecalculateFootnotes = function(nPageAbs, nColumnAbs, dY, arrFootnotes)
{
	if (!arrFootnotes || arrFootnotes.length <= 0)
		return true;

	var oColumn = this.private_GetPageColumn(nPageAbs, nColumnAbs);
	if (!oColumn)
		return true;

	var Y = dY;
	for (var nIndex = 0, nCount = this.CellLimits.length; nIndex < nCount; ++nIndex)
	{
		if (Y < this.CellLimits[nIndex] - 0.001)
			Y = this.CellLimits[nIndex];
	}

	var isLowerY = (Y < oColumn.ReferenceY + 0.001 ? true : false);

	if (oColumn.GetContinuesElements().length > 0)
	{
		// Если уже есть элементы, которые переносятся, тогда данные сноски точно не убирутся
		// Но если пришедший Y выше нашего самого нижнего, тогда мы все пришедшие элементы добавляем в список
		// на следующую страницу. Такое возможно в таблицах, когда сноски расположены в разных ячейках одной строки,
		// причем вторая сноска выше первой.

		if (isLowerY)
		{
			oColumn.AddContinuesElements(arrFootnotes);
			return true;
		}
		else
		{
			return false;
		}
	}

	var nColumnsCount = this.Pages[nPageAbs].Columns.length;

	var X      = oColumn.X;
	var XLimit = oColumn.XLimit;

	var _Y      = oColumn.Height;
	var _YLimit = oColumn.YLimit - Y;

	if (isLowerY)
		_YLimit = oColumn.YLimit - oColumn.ReferenceY;

	if (oColumn.Elements.length <= 0 && null !== this.SeparatorFootnote)
	{
		this.SeparatorFootnote.PrepareRecalculateObject();
		this.SeparatorFootnote.Reset(X, _Y, XLimit, _YLimit);
		this.SeparatorFootnote.Set_StartPage(nPageAbs, nColumnAbs, nColumnsCount);
		this.SeparatorFootnote.Recalculate_Page(0, true);
		oColumn.SeparatorRecalculateObject = this.SeparatorFootnote.SaveRecalculateObject();

		var oBounds    = this.SeparatorFootnote.Get_PageBounds(0);
		_Y += oBounds.Bottom - oBounds.Top;
		oColumn.Height = _Y;
	}

	for (var nIndex = 0, nCount = arrFootnotes.length; nIndex < nCount; ++nIndex)
	{
		var oFootnote = arrFootnotes[nIndex];
		oFootnote.Reset(X, _Y, XLimit, _YLimit);
		oFootnote.Set_StartPage(nPageAbs, nColumnAbs, nColumnsCount);


		var nRelativePage = oFootnote.GetElementPageIndex(nPageAbs, nColumnAbs);
		var nRecalcResult = oFootnote.Recalculate_Page(nRelativePage, true);

		if (recalcresult2_NextPage === nRecalcResult)
		{
			// Если у нас первая сноска не убирается, тогда мы переносим. Есть исключение, когда мы находимся в таблице
			// и у нас уже есть сноски на странице, а ссылка на данную сноску выше чем те, которые мы уже добавили.
			if (0 === nIndex && true !== oFootnote.IsContentOnFirstPage() && (0 === oColumn.Elements.length || !isLowerY))
				return false;

			// Начиная с данной сноски мы все оставшиеся сноски заносим в массив ContinuesElements у данной колонки
			var arrContinuesElements = arrFootnotes.slice(nIndex);
			oColumn.SetContinuesElements(arrContinuesElements);
		}
		else if (recalcresult2_CurPage === nRecalcResult)
		{
			// Такого не должно быть при расчете сносок
		}

		oColumn.Elements.push(oFootnote);

		var oBounds    = oFootnote.Get_PageBounds(nRelativePage);
		_Y += oBounds.Bottom - oBounds.Top;
		oColumn.Height = _Y;

		if (recalcresult2_NextPage === nRecalcResult)
			break;
	}

	oColumn.Height = Math.min(_YLimit, oColumn.Height);

	if (!isLowerY)
		oColumn.ReferenceY = Y;

	return true;
};
/**
 * Получаем суммарную высоту, занимаемую сносками на заданной странице.
 * @param {number} nPageAbs
 * @param {number} nColumnAbs
 * @returns {number}
 */
CFootnotesController.prototype.GetHeight = function(nPageAbs, nColumnAbs)
{
	var oColumn = this.private_GetPageColumn(nPageAbs, nColumnAbs);
	if (!oColumn)
		return 0;

	return oColumn.Height;
};
/**
 * Отрисовываем сноски на заданной странице.
 * @param {number} nPageAbs
 * @param {CGraphics} pGraphics
 */
CFootnotesController.prototype.Draw = function(nPageAbs, pGraphics)
{
	var oPage = this.Pages[nPageAbs];
	if (!oPage)
		return;

	var nColumnsCount = oPage.Columns.length;
	for (var nColumnIndex = 0; nColumnIndex < nColumnsCount; ++nColumnIndex)
	{
		var oColumn = oPage.Columns[nColumnIndex];
		if (!oColumn || oColumn.Elements.length <= 0)
			continue;

		if (null !== this.ContinuationSeparatorFootnote && null !== oColumn.ContinuationSeparatorRecalculateObject)
		{
			this.ContinuationSeparatorFootnote.LoadRecalculateObject(oColumn.ContinuationSeparatorRecalculateObject);
			this.ContinuationSeparatorFootnote.Draw(nPageAbs, pGraphics);
		}
		if (null !== this.SeparatorFootnote && null !== oColumn.SeparatorRecalculateObject)
		{
			this.SeparatorFootnote.LoadRecalculateObject(oColumn.SeparatorRecalculateObject);
			this.SeparatorFootnote.Draw(nPageAbs, pGraphics);
		}

		for (var nIndex = 0, nCount = oColumn.Elements.length; nIndex < nCount; ++nIndex)
		{
			var oFootnote = oColumn.Elements[nIndex];
			var nFootnotePageIndex = oFootnote.GetElementPageIndex(nPageAbs, nColumnIndex);
			oFootnote.Draw(nFootnotePageIndex + oFootnote.StartPage, pGraphics);
		}
	}
};
/**
 * Сдвигаем все рассчитанные позиции на заданной странице.
 * @param {number} nPageAbs
 * @param {number} nColumnAbs
 * @param {number} dX
 * @param {number} dY
 */
CFootnotesController.prototype.Shift = function(nPageAbs, nColumnAbs, dX, dY)
{
	var oColumn = this.private_GetPageColumn(nPageAbs, nColumnAbs);
	if (!oColumn)
		return;

	if (null !== this.ContinuationSeparatorFootnote && null !== oColumn.ContinuationSeparatorRecalculateObject)
	{
		this.ContinuationSeparatorFootnote.LoadRecalculateObject(oColumn.ContinuationSeparatorRecalculateObject);
		this.ContinuationSeparatorFootnote.Shift(0, dX, dY);
		oColumn.ContinuationSeparatorRecalculateObject = this.ContinuationSeparatorFootnote.SaveRecalculateObject();
	}
	if (null !== this.SeparatorFootnote && null !== oColumn.SeparatorRecalculateObject)
	{
		this.SeparatorFootnote.LoadRecalculateObject(oColumn.SeparatorRecalculateObject);
		this.SeparatorFootnote.Shift(0, dX, dY);
		oColumn.SeparatorRecalculateObject = this.SeparatorFootnote.SaveRecalculateObject();
	}

	for (var nIndex = 0, nCount = oColumn.Elements.length; nIndex < nCount; ++nIndex)
	{
		var oFootnote = oColumn.Elements[nIndex];
		var nFootnotePageIndex = oFootnote.GetElementPageIndex(nPageAbs, nColumnAbs);
		oFootnote.Shift(nFootnotePageIndex, dX, dY);
	}
};
CFootnotesController.prototype.PushCellLimit = function(dY)
{
	this.CellLimits.push(dY);
};
CFootnotesController.prototype.PopCellLimit = function()
{
	this.CellLimits.length = Math.max(0, this.CellLimits.length - 1);
};
CFootnotesController.prototype.GetFootnoteNumberOnPage = function(nPageAbs, nColumnAbs, oSectPr)
{
	var nNumRestart = section_footnote_RestartEachPage;
	var nNumStart   = 1;
	if (oSectPr)
	{
		nNumRestart = oSectPr.GetFootnoteNumRestart();
		nNumStart   = oSectPr.GetFootnoteNumStart();
	}

	// NumStart никак не влияет в случаях RestartEachPage и RestartEachSect. Влияет только на случай RestartContinuous:
	// к общему количеству сносок добавляется данное значение, взятое для текущей секции, этоже значение из предыдущих
	// секций не учитывается.

	if (section_footnote_RestartEachPage === nNumRestart)
	{
		// Случай, когда своя отдельная нумерация на каждой странице
		// Мы делаем не совсем как в Word, если у нас происходит ситуация, что ссылка на сноску на одной странице, а сама
		// сноска на следующей, тогда у этих страниц нумерация общая, в Word ставится номер "1" в такой ситуации, и становится
		// непонятно, потому что есть две ссылки с номером 1 на странице, ссылающиеся на разные сноски.

		// В таблицах сами сноски могут переносится на другую колонку, а ссылки будут оставаться на данной, и они пока еще
		// не рассчитаны и никуда не добавлены, поэтому нам также надо учитывать количество переносимы сносок на следующую
		// колонку.
		var nAdditional = 0;

		for (var nColumnIndex = nColumnAbs; nColumnIndex >= 0; --nColumnIndex)
		{
			var oColumn = this.private_GetPageColumn(nPageAbs, nColumnIndex);
			if (nColumnIndex === nColumnAbs)
			{
				var arrContinuesElements = oColumn.GetContinuesElements();
				for (var nTempIndex = 1; nTempIndex < arrContinuesElements.length; ++nTempIndex)
				{
					if (!arrContinuesElements[nTempIndex].IsCustomMarkFollows())
						nAdditional++;
				}
			}

			if (oColumn.Elements.length > 0)
			{
				var oFootnote  = oColumn.Elements[oColumn.Elements.length - 1];
				var nStartPage = oFootnote.Get_StartPage_Absolute();

				if (nStartPage >= nPageAbs || (nStartPage === nPageAbs - 1 && true !== oFootnote.IsContentOnFirstPage()))
					return oFootnote.GetNumber() + 1 + nAdditional;
				else
					return 1 + nAdditional;
			}

		}
	}
	else if (section_footnote_RestartEachSect === nNumRestart)
	{
		var oColumn = this.private_GetPageColumn(nPageAbs, nColumnAbs);
		if (oColumn)
		{
			var arrContinuesElements = oColumn.GetContinuesElements();
			if (arrContinuesElements.length > 0 && oColumn.Elements.length > 0)
			{
				var oFootnote = oColumn.Elements[oColumn.Elements.length - 1];
				if (oFootnote.GetReferenceSectPr() !== oSectPr)
					return 1;

				var nAdditional = 0;
				for (var nTempIndex = 0; nTempIndex < arrContinuesElements.length; ++nTempIndex)
				{
					if (!arrContinuesElements[nTempIndex].IsCustomMarkFollows())
						nAdditional++;
				}

				// Второе условие не нужно, потому что если arrContinuesElements.length > 0, то на такой колонке
				// пусть и пустая но должна быть хоть одна сноска рассчитана

				return oColumn.Elements[oColumn.Elements.length - 1].GetNumber() + 1 + nAdditional;
			}
		}

		// Дальше мы ищем колонку, на которой была последняя сноска. Заметим, что переносы сносок мы не проверяем, т.к.
		// их не может быть вплоть до последней сноски, а что последняя сноска не переносится мы проверили выше.
		for (var nPageIndex = nPageAbs; nPageIndex >= 0; --nPageIndex)
		{
			var nColumnStartIndex = (nPageIndex === nPageAbs ? nColumnAbs : this.Pages[nPageAbs].Columns.length - 1);
			for (var nColumnIndex = nColumnStartIndex; nColumnIndex >= 0; --nColumnIndex)
			{
				oColumn = this.private_GetPageColumn(nPageIndex, nColumnIndex);
				if (oColumn && oColumn.Elements.length > 0)
				{
					var oFootnote = oColumn.Elements[oColumn.Elements.length - 1];
					if (oFootnote.GetReferenceSectPr() !== oSectPr)
						return 1;

					return oColumn.Elements[oColumn.Elements.length - 1].GetNumber() + 1;
				}
			}
		}
	}
	else// if (section_footnote_RestartContinuous === nNumRestart)
	{
		// Здесь нам надо считать, сколько сносок всего в документе до данного момента, отталкиваться от предыдущей мы
		// не можем, потому что Word считает общее количество сносок, а не продолжает нумерацию с предыдущей секции,
		// т.е. после последнего номера 4 в старой секции, в новой секции может идти уже, например, 9.
		var nFootnotesCount = 0;
		for (var nPageIndex = nPageAbs; nPageIndex >= 0; --nPageIndex)
		{
			var nColumnStartIndex = (nPageIndex === nPageAbs ? nColumnAbs : this.Pages[nPageAbs].Columns.length - 1);
			for (var nColumnIndex = nColumnStartIndex; nColumnIndex >= 0; --nColumnIndex)
			{
				oColumn = this.private_GetPageColumn(nPageIndex, nColumnIndex);
				if (oColumn && oColumn.Elements.length > 0)
				{
					for (var nFootnoteIndex = 0, nTempCount = oColumn.Elements.length; nFootnoteIndex < nTempCount; ++nFootnoteIndex)
					{
						var oFootnote = oColumn.Elements[nFootnoteIndex];
						if (oFootnote
							&& true !== oFootnote.IsCustomMarkFollows()
							&& (0 !== nFootnoteIndex
							|| oFootnote.Pages.length <= 1
							|| (0 === nFootnoteIndex && 1 === oColumn.Elements.length && nPageIndex === oFootnote.Get_StartPage_Absolute() && nColumnIndex === oFootnote.Get_StartColumn_Absolute())))
							nFootnotesCount++;
					}
				}
			}
		}

		return nFootnotesCount + nNumStart;
	}

	return 1;
};
CFootnotesController.prototype.SaveRecalculateObject = function(nPageAbs, nColumnAbs)
{
	var oColumn = this.private_GetPageColumn(nPageAbs, nColumnAbs);
	if (!oColumn)
		return null;

	return oColumn.SaveRecalculateObject();
};
CFootnotesController.prototype.LoadRecalculateObject = function(nPageAbs, nColumnAbs, oRObject)
{
	var oColumn = this.private_GetPageColumn(nPageAbs, nColumnAbs);
	if (!oColumn)
		return;

	oColumn.LoadRecalculateObject(oRObject);
};
CFootnotesController.prototype.HaveContinuesFootnotes = function(nPageAbs, nColumnAbs)
{
	var oColumn = this.private_GetPageColumn(nPageAbs, nColumnAbs);
	if (!oColumn)
		return false;

	var arrContinues = oColumn.GetContinuesElements();

	return (arrContinues.length > 0 ? true : false);
};
/**
 * Проверяем, используется заданная сноска в документе.
 * @param {string} sFootnoteId
 * @param {CFootEndnote.array} arrFootnotesList
 * @returns {boolean}
 */
CFootnotesController.prototype.Is_UseInDocument = function(sFootnoteId, arrFootnotesList)
{
	if (!arrFootnotesList)
		arrFootnotesList = this.private_GetFootnotesLogicRange(null, null);

	var oFootnote = null;
	for (var nIndex = 0, nCount = arrFootnotesList.length; nIndex < nCount; ++nIndex)
	{
		var oTempFootnote = arrFootnotesList[nIndex];
		if (oTempFootnote.Get_Id() === sFootnoteId)
		{
			oFootnote = oTempFootnote;
			break;
		}
	}

	if (this.Footnote[sFootnoteId] === oFootnote)
		return true;

	return false;
};
/**
 * Проверяем является ли данная сноска текущей.
 * @param oFootnote
 * return {boolean}
 */
CFootnotesController.prototype.Is_ThisElementCurrent = function(oFootnote)
{
	if (oFootnote === this.CurFootnote && docpostype_Footnotes === this.LogicDocument.Get_DocPosType())
		return true;

	return false;
};
CFootnotesController.prototype.OnContentReDraw = function(StartPageAbs, EndPageAbs)
{
	this.LogicDocument.OnContentReDraw(StartPageAbs, EndPageAbs);
};
/**
 * Проверяем пустая ли страница.
 * @param {number} nPageIndex
 * @returns {boolean}
 */
CFootnotesController.prototype.IsEmptyPage = function(nPageIndex)
{
	var oPage = this.Pages[nPageIndex];
	if (!oPage)
		return true;

	for (var nColumnIndex = 0, nColumnsCount = oPage.Columns.length; nColumnIndex < nColumnsCount; ++nColumnIndex)
	{
		if (true !== this.IsEmptyPageColumn(nPageIndex, nColumnIndex))
			return false;
	}

	return true;
};
CFootnotesController.prototype.IsEmptyPageColumn = function(nPageIndex, nColumnIndex)
{
	var oColumn = this.private_GetPageColumn(nPageIndex, nColumnIndex);
	if (!oColumn || oColumn.Elements.length <= 0)
		return true;

	return false;
};
CFootnotesController.prototype.Refresh_RecalcData = function(Data)
{
};
CFootnotesController.prototype.Refresh_RecalcData2 = function(nRelPageIndex)
{
	var nAbsPageIndex = nRelPageIndex;
	if (this.LogicDocument.Pages[nAbsPageIndex])
	{
		var nIndex = this.LogicDocument.Pages[nAbsPageIndex].Pos;

		if (nIndex >= this.LogicDocument.Content.length)
		{
			History.RecalcData_Add({
				Type    : AscDFH.historyitem_recalctype_NotesEnd,
				PageNum : nAbsPageIndex
			});
		}
		else
		{
			this.LogicDocument.Refresh_RecalcData2(nIndex, nAbsPageIndex);
		}
	}
};
CFootnotesController.prototype.Get_PageContentStartPos = function(nPageAbs, nColumnAbs)
{
	var oColumn = this.private_GetPageColumn(nPageAbs, nColumnAbs);
	if (!oColumn)
		return {X : 0, Y : 0, XLimit : 0, YLimit : 0};

	return {X : oColumn.X, Y : oColumn.Height, XLimit : oColumn.XLimit, YLimit : oColumn.YLimit - oColumn.Y};
};
CFootnotesController.prototype.GetCurFootnote = function()
{
	return this.CurFootnote;
};
CFootnotesController.prototype.IsInDrawing = function(X, Y, PageAbs)
{
	var oResult = this.private_GetFootnoteByXY(X, Y, PageAbs);
	if (oResult)
	{
		var oFootnote = oResult.Footnote;
		return oFootnote.IsInDrawing(X, Y, oResult.FootnotePageIndex);
	}

	return false;
};
CFootnotesController.prototype.IsTableBorder = function(X, Y, PageAbs)
{
	var oResult = this.private_GetFootnoteByXY(X, Y, PageAbs);
	if (oResult)
	{
		var oFootnote = oResult.Footnote;
		return oFootnote.IsTableBorder(X, Y, oResult.FootnotePageIndex);
	}

	return null;
};
CFootnotesController.prototype.IsInText = function(X, Y, PageAbs)
{
	var oResult = this.private_GetFootnoteByXY(X, Y, PageAbs);
	if (oResult)
	{
		var oFootnote = oResult.Footnote;
		return oFootnote.IsInText(X, Y, oResult.FootnotePageIndex);
	}

	return null;
};
CFootnotesController.prototype.GetNearestPos = function(X, Y, PageAbs, bAnchor, Drawing)
{
	var oResult = this.private_GetFootnoteByXY(X, Y, PageAbs);
	if (oResult)
	{
		var oFootnote = oResult.Footnote;
		return oFootnote.Get_NearestPos(oResult.FootnotePageIndex, X, Y, bAnchor, Drawing);
	}

	return null;
};
/**
 * Проверяем попадание в сноски на заданной странице.
 * @param X
 * @param Y
 * @param nPageAbs
 * @returns {boolean}
 */
CFootnotesController.prototype.CheckHitInFootnote = function(X, Y, nPageAbs)
{
	if (true === this.IsEmptyPage(nPageAbs))
		return false;

	var oPage   = this.Pages[nPageAbs];
	var oColumn = null;
	var nFindedColumnIndex = 0, nColumnsCount = oPage.Columns.length;
	for (var nColumnIndex = 0; nColumnIndex < nColumnsCount; ++nColumnIndex)
	{
		if (nColumnIndex < nColumnsCount - 1)
		{
			if (X < (oPage.Columns[nColumnIndex].XLimit + oPage.Columns[nColumnIndex + 1].X) / 2)
			{
				oColumn            = oPage.Columns[nColumnIndex];
				nFindedColumnIndex = nColumnIndex;
				break;
			}
		}
		else
		{
			oColumn            = oPage.Columns[nColumnIndex];
			nFindedColumnIndex = nColumnIndex;
		}
	}

	if (!oColumn || nFindedColumnIndex >= nColumnsCount)
		return false;

	for (var nIndex = 0, nCount = oColumn.Elements.length; nIndex < nCount; ++nIndex)
	{
		var oFootnote          = oColumn.Elements[nIndex];
		var nFootnotePageIndex = oFootnote.GetElementPageIndex(nPageAbs, nFindedColumnIndex);
		var oBounds            = oFootnote.Get_PageBounds(nFootnotePageIndex);

		if (oBounds.Top <= Y)
			return true;
	}

	return false;
};
CFootnotesController.prototype.GetAllParagraphs = function(Props, ParaArray)
{
	for (var sId in  this.Footnote)
	{
		var oFootnote = this.Footnote[sId];
		oFootnote.GetAllParagraphs(Props, ParaArray);
	}
};
CFootnotesController.prototype.StartSelection = function(X, Y, PageAbs, MouseEvent)
{
	if (true === this.Selection.Use)
		this.RemoveSelection();

	var oResult = this.private_GetFootnoteByXY(X, Y, PageAbs);
	if (null === oResult)
	{
		// BAD
		this.Selection.Use = false;
		return;
	}

	this.Selection.Use   = true;
	this.Selection.Start = oResult;
	this.Selection.End   = oResult;

	this.Selection.Start.Footnote.Selection_SetStart(X, Y, this.Selection.Start.FootnotePageIndex, MouseEvent);

	this.CurFootnote = this.Selection.Start.Footnote;

	this.Selection.Footnotes = {};
	this.Selection.Footnotes[this.Selection.Start.Footnote.Get_Id()] = this.Selection.Start.Footnote;
	this.Selection.Direction = 0;
};
CFootnotesController.prototype.EndSelection = function(X, Y, PageAbs, MouseEvent)
{
	if (true === this.IsMovingTableBorder())
	{
		this.CurFootnote.Selection_SetEnd(X, Y, PageAbs, MouseEvent);
		return;
	}

	var oResult = this.private_GetFootnoteByXY(X, Y, PageAbs);
	if (null === oResult)
	{
		// BAD
		this.Selection.Use = false;
		return;
	}

	this.Selection.End = oResult;
	this.CurFootnote = this.Selection.End.Footnote;

	var sStartId = this.Selection.Start.Footnote.Get_Id();
	var sEndId   = this.Selection.End.Footnote.Get_Id();

	// Очищаем старый селект везде кроме начальной сноски
	for (var sFootnoteId in this.Selection.Footnotes)
	{
		if (sFootnoteId !== sStartId)
			this.Selection.Footnotes[sFootnoteId].RemoveSelection();
	}

	// Новый селект
	if (this.Selection.Start.Footnote !== this.Selection.End.Footnote)
	{
		if (this.Selection.Start.Page > this.Selection.End.Page
			|| (this.Selection.Start.Page === this.Selection.End.Page
			&& (this.Selection.Start.Column > this.Selection.End.Column
			|| (this.Selection.Start.Column === this.Selection.End.Column
			&& this.Selection.Start.Index > this.Selection.End.Index))))
		{
			this.Selection.Start.Footnote.Selection_SetEnd(-MEASUREMENT_MAX_MM_VALUE, -MEASUREMENT_MAX_MM_VALUE, 0, MouseEvent);
			this.Selection.End.Footnote.Selection_SetStart(MEASUREMENT_MAX_MM_VALUE, MEASUREMENT_MAX_MM_VALUE, this.Selection.End.Footnote.Pages.length - 1, MouseEvent);
			this.Selection.Direction = -1;
		}
		else
		{
			this.Selection.Start.Footnote.Selection_SetEnd(MEASUREMENT_MAX_MM_VALUE, MEASUREMENT_MAX_MM_VALUE, this.Selection.Start.Footnote.Pages.length - 1, MouseEvent);
			this.Selection.End.Footnote.Selection_SetStart(-MEASUREMENT_MAX_MM_VALUE, -MEASUREMENT_MAX_MM_VALUE, 0, MouseEvent);
			this.Selection.Direction = 1;
		}
		this.Selection.End.Footnote.Selection_SetEnd(X, Y, this.Selection.End.FootnotePageIndex, MouseEvent);

		var oRange = this.private_GetFootnotesRange(this.Selection.Start, this.Selection.End);
		for (var sFootnoteId in oRange)
		{
			if (sFootnoteId !== sStartId && sFootnoteId !== sEndId)
			{
				var oFootnote = oRange[sFootnoteId];
				oFootnote.SelectAll();
			}
		}
		this.Selection.Footnotes = oRange;
	}
	else
	{
		this.Selection.End.Footnote.Selection_SetEnd(X, Y, this.Selection.End.FootnotePageIndex, MouseEvent);
		this.Selection.Footnotes = {};
		this.Selection.Footnotes[this.Selection.Start.Footnote.Get_Id()] = this.Selection.Start.Footnote;
		this.Selection.Direction = 0;
	}
};
CFootnotesController.prototype.Set_CurrentElement = function(bUpdateStates, PageAbs, oFootnote)
{
	if (oFootnote instanceof CFootEndnote)
	{
		if (oFootnote.IsSelectionUse())
		{
			this.CurFootnote              = oFootnote;
			this.Selection.Use            = true;
			this.Selection.Direction      = 0;
			this.Selection.Start.Footnote = oFootnote;
			this.Selection.End.Footnote   = oFootnote;
			this.Selection.Footnotes      = {};

			this.Selection.Footnotes[oFootnote.Get_Id()] = oFootnote;
			this.LogicDocument.Selection.Use   = true;
			this.LogicDocument.Selection.Start = false;
		}
		else
		{
			this.private_SetCurrentFootnoteNoSelection(oFootnote);
			this.LogicDocument.Selection.Use   = false;
			this.LogicDocument.Selection.Start = false;
		}

		var bNeedRedraw = this.LogicDocument.Get_DocPosType() === docpostype_HdrFtr;
		this.LogicDocument.Set_DocPosType(docpostype_Footnotes);

		if (false != bUpdateStates)
		{
			this.LogicDocument.Document_UpdateInterfaceState();
			this.LogicDocument.Document_UpdateRulersState();
			this.LogicDocument.Document_UpdateSelectionState();
		}

		if (bNeedRedraw)
		{
			this.LogicDocument.DrawingDocument.ClearCachePages();
			this.LogicDocument.DrawingDocument.FirePaint();
		}
	}
};
CFootnotesController.prototype.AddFootnoteRef = function()
{
	if (true !== this.private_IsOnFootnoteSelected() || null === this.CurFootnote)
		return;

	var oFootnote  = this.CurFootnote;
	var oParagraph = oFootnote.Get_FirstParagraph();
	if (!oParagraph)
		return;

	var oStyles = this.LogicDocument.Get_Styles();

	var oRun = new ParaRun(oParagraph, false);
	oRun.Add_ToContent(0, new ParaFootnoteRef(oFootnote), false);
	oRun.Set_RStyle(oStyles.GetDefaultFootnoteReference());
	oParagraph.Add_ToContent(0, oRun);
};
CFootnotesController.prototype.GotoPage = function(nPageAbs)
{
	var oColumn = this.private_GetPageColumn(nPageAbs, 0);
	if (!oColumn || oColumn.Elements.length <= 0)
		return;

	var oFootnote = oColumn.Elements[0];
	this.private_SetCurrentFootnoteNoSelection(oFootnote);
	oFootnote.MoveCursorToStartPos(false);
};
CFootnotesController.prototype.CheckTableCoincidence = function(oTable)
{
	return false;
};
CFootnotesController.prototype.GotoNextFootnote = function()
{
	var oNextFootnote = this.private_GetNextFootnote(this.CurFootnote);
	if (oNextFootnote)
	{
		oNextFootnote.MoveCursorToStartPos(false);
		this.private_SetCurrentFootnoteNoSelection(oNextFootnote);
	}
};
CFootnotesController.prototype.GotoPrevFootnote = function()
{
	var oPrevFootnote = this.private_GetPrevFootnote(this.CurFootnote);
	if (oPrevFootnote)
	{
		oPrevFootnote.MoveCursorToStartPos(false);
		this.private_SetCurrentFootnoteNoSelection(oPrevFootnote);
	}
};
CFootnotesController.prototype.GetNumberingInfo = function(oPara, oNumPr, oFootnote)
{
	var arrFootnotes     = this.LogicDocument.Get_FootnotesList(null, oFootnote);
	var oNumberingEngine = new CDocumentNumberingInfoEngine(oPara, oNumPr, this.Get_Numbering());
	for (var nIndex = 0, nCount = arrFootnotes.length; nIndex < nCount; ++nIndex)
	{
		arrFootnotes[nIndex].GetNumberingInfo(oNumberingEngine, oPara, oNumPr);
	}
	return oNumberingEngine.GetNumInfo();
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Private area
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CFootnotesController.prototype.private_GetPageColumn = function(nPageAbs, nColumnAbs)
{
	var oPage = this.Pages[nPageAbs];
	if (!oPage)
		return null;

	var oColumn = oPage.Columns[nColumnAbs];
	if (!oColumn)
		return null;

	return oColumn;
};
CFootnotesController.prototype.private_GetFootnoteOnPageByXY = function(X, Y, nPageAbs)
{
	if (true === this.IsEmptyPage(nPageAbs))
		return null;

	var oPage   = this.Pages[nPageAbs];
	var oColumn = null;
	var nColumnIndex = 0;
	for (var nColumnsCount = oPage.Columns.length; nColumnIndex < nColumnsCount; ++nColumnIndex)
	{
		if (nColumnIndex < nColumnsCount - 1)
		{
			if (X < (oPage.Columns[nColumnIndex].XLimit + oPage.Columns[nColumnIndex + 1].X) / 2)
			{
				oColumn = oPage.Columns[nColumnIndex];
				break;
			}
		}
		else
		{
			oColumn = oPage.Columns[nColumnIndex];
			break;
		}
	}

	if (!oColumn)
		return null;

	if (oColumn.Elements.length <= 0)
	{
		var nCurColumnIndex = nColumnIndex - 1;
		while (nCurColumnIndex >= 0)
		{
			if (oPage.Columns[nCurColumnIndex].Elements.length > 0)
			{
				oColumn      = oPage.Columns[nCurColumnIndex];
				nColumnIndex = nCurColumnIndex;
				break;
			}
			nCurColumnIndex--;
		}

		if (nCurColumnIndex < 0)
		{
			nCurColumnIndex = nColumnIndex + 1;
			while (nCurColumnIndex <= oPage.Columns.length - 1)
			{
				if (oPage.Columns[nCurColumnIndex].Elements.length > 0)
				{
					oColumn      = oPage.Columns[nCurColumnIndex];
					nColumnIndex = nCurColumnIndex;
					break;
				}
				nCurColumnIndex++;
			}
		}
	}

	if (!oColumn)
		return null;

	for (var nIndex = oColumn.Elements.length - 1; nIndex >= 0; --nIndex)
	{
		var oFootnote = oColumn.Elements[nIndex];

		var nElementPageIndex = oFootnote.GetElementPageIndex(nPageAbs, nColumnIndex);
		var oBounds           = oFootnote.Get_PageBounds(nElementPageIndex);

		if (oBounds.Top <= Y || 0 === nIndex)
			return {
				Footnote          : oFootnote,
				Index             : nIndex,
				Page              : nPageAbs,
				Column            : nColumnIndex,
				FootnotePageIndex : nElementPageIndex
			};
	}

	return null;
};
CFootnotesController.prototype.private_GetFootnoteByXY = function(X, Y, PageAbs)
{
	var oResult = this.private_GetFootnoteOnPageByXY(X, Y, PageAbs);
	if (null !== oResult)
		return oResult;

	var nCurPage = PageAbs - 1;
	while (nCurPage >= 0)
	{
		oResult = this.private_GetFootnoteOnPageByXY(MEASUREMENT_MAX_MM_VALUE, MEASUREMENT_MAX_MM_VALUE, nCurPage);
		if (null !== oResult)
			return oResult;

		nCurPage--;
	}

	nCurPage = PageAbs + 1;
	while (nCurPage < this.Pages.length)
	{
		oResult = this.private_GetFootnoteOnPageByXY(-MEASUREMENT_MAX_MM_VALUE, -MEASUREMENT_MAX_MM_VALUE, nCurPage);
		if (null !== oResult)
			return oResult;

		nCurPage++;
	}

	return null;
};
CFootnotesController.prototype.private_GetFootnotesRange = function(Start, End)
{
	var oResult = {};
	if (Start.Page > End.Page || (Start.Page === End.Page && Start.Column > End.Column) || (Start.Page === End.Page && Start.Column === End.Column && Start.Index > End.Index))
	{
		var Temp = Start;
		Start    = End;
		End      = Temp;
	}

	if (Start.Page === End.Page)
	{
		this.private_GetFootnotesOnPage(Start.Page, Start.Column, End.Column, Start.Index, End.Index, oResult);
	}
	else
	{
		this.private_GetFootnotesOnPage(Start.Page, Start.Column, -1, Start.Index, -1, oResult);

		for (var CurPage = Start.Page + 1; CurPage <= End.Page - 1; ++CurPage)
		{
			this.private_GetFootnotesOnPage(CurPage, -1, -1, -1, -1, oResult);
		}

		this.private_GetFootnotesOnPage(End.Page, -1, End.Column, -1, End.Index, oResult);
	}

	return oResult;
};
CFootnotesController.prototype.private_GetFootnotesOnPage = function(nPageAbs, nColumnStart, nColumnEnd, nStartIndex, nEndIndex, oFootnotes)
{
	var oPage = this.Pages[nPageAbs];
	if (!oPage)
		return;

	var _nColumnStart = -1 === nColumnStart ? 0 : nColumnStart;
	var _nColumnEnd   = -1 === nColumnEnd ? oPage.Columns.length - 1 : nColumnEnd;

	var _nStartIndex  = -1 === nColumnStart || -1 === nStartIndex ? 0 : nStartIndex;
	var _nEndIndex    = -1 === nColumnEnd || -1 === nEndIndex ? oPage.Columns[_nColumnEnd].Elements.length - 1 : nEndIndex;

	for (var nColIndex = _nColumnStart; nColIndex <= _nColumnEnd; ++nColIndex)
	{
		var nSIndex = nColIndex === _nColumnStart ? _nStartIndex : 0;
		var nEIndex = nColIndex === _nColumnEnd ? _nEndIndex : oPage.Columns[nColIndex].Elements.length - 1;

		this.private_GetFootnotesOnPageColumn(nPageAbs, nColIndex, nSIndex, nEIndex, oFootnotes);
	}
};
CFootnotesController.prototype.private_GetFootnotesOnPageColumn = function(nPageAbs, nColumnAbs, StartIndex, EndIndex, oFootnotes)
{
	var oColumn = this.private_GetPageColumn(nPageAbs, nColumnAbs);

	var _StartIndex = -1 === StartIndex ? 0 : StartIndex;
	var _EndIndex   = -1 === EndIndex ? oColumn.Elements.length - 1 : EndIndex;

	for (var nIndex = _StartIndex; nIndex <= _EndIndex; ++nIndex)
	{
		var oFootnote = oColumn.Elements[nIndex];
		oFootnotes[oFootnote.Get_Id()] = oFootnote;
	}
};
CFootnotesController.prototype.private_OnNotValidActionForFootnotes = function()
{
	// Пока ничего не делаем, если надо будет выдавать сообщение, то обработать нужно будет здесь.
};
CFootnotesController.prototype.private_IsOnFootnoteSelected = function()
{
	return (0 !== this.Selection.Direction ? false : true);
};
CFootnotesController.prototype.private_CheckFootnotesSelectionBeforeAction = function()
{
	if (true !== this.private_IsOnFootnoteSelected() || null === this.CurFootnote)
	{
		this.private_OnNotValidActionForFootnotes();
		return false;
	}

	return true;
};
CFootnotesController.prototype.private_SetCurrentFootnoteNoSelection = function(oFootnote)
{
	this.Selection.Use            = false;
	this.CurFootnote              = oFootnote;
	this.Selection.Start.Footnote = oFootnote;
	this.Selection.End.Footnote   = oFootnote;
	this.Selection.Direction      = 0;

	this.Selection.Footnotes                     = {};
	this.Selection.Footnotes[oFootnote.Get_Id()] = oFootnote;
};
CFootnotesController.prototype.private_GetPrevFootnote = function(oFootnote)
{
	if (!oFootnote)
		return null;

	var arrList = this.LogicDocument.Get_FootnotesList(null, oFootnote);
	if (!arrList || arrList.length <= 1 || arrList[arrList.length - 1] !== oFootnote)
		return null;

	return arrList[arrList.length - 2];
};
CFootnotesController.prototype.private_GetNextFootnote = function(oFootnote)
{
	if (!oFootnote)
		return null;

	var arrList = this.LogicDocument.Get_FootnotesList(oFootnote, null);
	if (!arrList || arrList.length <= 1 || arrList[0] !== oFootnote)
		return null;

	return arrList[1];
};
CFootnotesController.prototype.private_GetDirection = function(oFootnote1, oFootnote2)
{
	// Предполагается, что эти сноски обязательно есть в документе
	if (oFootnote1 == oFootnote2)
		return 0;

	var arrList = this.LogicDocument.Get_FootnotesList(null, null);

	for (var nPos = 0, nCount = arrList.length; nPos < nCount; ++nPos)
	{
		if (oFootnote1 === arrList[nPos])
			return 1;
		else if (oFootnote2 === arrList[nPos])
			return -1;
	}

	return 0;
};
CFootnotesController.prototype.private_GetFootnotesLogicRange = function(oFootnote1, oFootnote2)
{
	return this.LogicDocument.Get_FootnotesList(oFootnote1, oFootnote2);
};
CFootnotesController.prototype.private_GetSelectionArray = function()
{
	if (true !== this.Selection.Use || 0 === this.Selection.Direction)
		return [this.CurFootnote];

	if (1 === this.Selection.Direction)
		return this.private_GetFootnotesLogicRange(this.Selection.Start.Footnote, this.Selection.End.Footnote);
	else
		return this.private_GetFootnotesLogicRange(this.Selection.End.Footnote, this.Selection.Start.Footnote);
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Controller area
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CFootnotesController.prototype.CanUpdateTarget = function()
{
	return true;
};
CFootnotesController.prototype.RecalculateCurPos = function(bUpdateX, bUpdateY)
{
	if (null !== this.CurFootnote)
		return this.CurFootnote.RecalculateCurPos(bUpdateX, bUpdateY);

	return {X : 0, Y : 0, Height : 0, PageNum : 0, Internal : {Line : 0, Page : 0, Range : 0}, Transform : null};
};
CFootnotesController.prototype.GetCurPage = function()
{
	if (null !== this.CurFootnote)
		return this.CurFootnote.Get_StartPage_Absolute();

	return -1;
};
CFootnotesController.prototype.AddNewParagraph = function(bRecalculate, bForceAdd)
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return false;

	return this.CurFootnote.AddNewParagraph(bRecalculate, bForceAdd);
};
CFootnotesController.prototype.AddInlineImage = function(nW, nH, oImage, oChart, bFlow)
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return false;

	return this.CurFootnote.AddInlineImage(nW, nH, oImage, oChart, bFlow);
};
CFootnotesController.prototype.AddImages = function(aImages)
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return false;

	return this.CurFootnote.AddImages(aImages);
};
CFootnotesController.prototype.AddSignatureLine = function(oSignatureDrawing)
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return false;

	return this.CurFootnote.AddSignatureLine(oSignatureDrawing);
};
CFootnotesController.prototype.AddOleObject = function(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId)
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return false;

	return this.CurFootnote.AddOleObject(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId);
};
CFootnotesController.prototype.EditChart = function(Chart)
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return;

	this.CurFootnote.EditChart(Chart);
};
CFootnotesController.prototype.AddInlineTable = function(Cols, Rows)
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return;

	if (null !== this.CurFootnote)
		this.CurFootnote.AddInlineTable(Cols, Rows);
};
CFootnotesController.prototype.ClearParagraphFormatting = function(isClearParaPr, isClearTextPr)
{
	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		oFootnote.ClearParagraphFormatting(isClearParaPr, isClearTextPr);
	}
};
CFootnotesController.prototype.AddToParagraph = function(oItem, bRecalculate)
{
	if (para_NewLine === oItem.Type && true === oItem.IsPageOrColumnBreak())
		return;

	if (oItem instanceof ParaTextPr)
	{
		for (var sId in this.Selection.Footnotes)
		{
			var oFootnote = this.Selection.Footnotes[sId];
			oFootnote.AddToParagraph(oItem, false);
		}

		if (false !== bRecalculate)
		{
			this.LogicDocument.Recalculate();
		}
	}
	else
	{
		if (false === this.private_CheckFootnotesSelectionBeforeAction())
			return;

		if (null !== this.CurFootnote)
			this.CurFootnote.AddToParagraph(oItem, bRecalculate);
	}
};
CFootnotesController.prototype.Remove = function(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd)
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return;

	this.CurFootnote.Remove(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd);
};
CFootnotesController.prototype.GetCursorPosXY = function()
{
	// Если есть селект, тогда конец селекта совпадает с CurFootnote
	if (null !== this.CurFootnote)
		return this.CurFootnote.GetCursorPosXY();

	return {X : 0, Y : 0}
};
CFootnotesController.prototype.MoveCursorToStartPos = function(AddToSelect)
{
	if (true !== AddToSelect)
	{
		this.LogicDocument.controller_MoveCursorToStartPos(false);
	}
	else
	{
		var oFootnote = this.CurFootnote;
		if (true === this.Selection.Use)
			oFootnote = this.Selection.Start.Footnote;

		var arrRange = this.LogicDocument.Get_FootnotesList(null, oFootnote);
		if (arrRange.length <= 0)
			return;

		if (true !== this.Selection.Use)
			this.LogicDocument.StartSelectionFromCurPos();

		this.Selection.End.Footnote   = arrRange[0];
		this.Selection.Start.Footnote = oFootnote;
		this.Selection.Footnotes      = {};

		oFootnote.MoveCursorToStartPos(true);
		this.Selection.Footnotes = {};
		this.Selection.Footnotes[oFootnote.Get_Id()]  = oFootnote;
		for (var nIndex = 0, nCount = arrRange.length; nIndex < nCount; ++nIndex)
		{
			var oTempFootnote = arrRange[nIndex];
			if (oTempFootnote !== oFootnote)
			{
				oTempFootnote.SelectAll(-1);
				this.Selection.Footnotes[oTempFootnote.Get_Id()] = oTempFootnote;
			}
		}

		if (this.Selection.Start.Footnote !== this.Selection.End.Footnote)
			this.Selection.Direction = -1;
		else
			this.Selection.Direction = 0;
	}
};
CFootnotesController.prototype.MoveCursorToEndPos = function(AddToSelect)
{
	if (true !== AddToSelect)
	{
		this.LogicDocument.controller_MoveCursorToEndPos(false);
	}
	else
	{
		var oFootnote = this.CurFootnote;
		if (true === this.Selection.Use)
			oFootnote = this.Selection.Start.Footnote;

		var arrRange = this.LogicDocument.Get_FootnotesList(oFootnote, null);
		if (arrRange.length <= 0)
			return;

		if (true !== this.Selection.Use)
			this.LogicDocument.StartSelectionFromCurPos();

		this.Selection.End.Footnote   = arrRange[arrRange.length - 1];
		this.Selection.Start.Footnote = oFootnote;
		this.Selection.Footnotes      = {};

		oFootnote.MoveCursorToEndPos(true);
		this.Selection.Footnotes = {};
		this.Selection.Footnotes[oFootnote.Get_Id()]  = oFootnote;
		for (var nIndex = 0, nCount = arrRange.length; nIndex < nCount; ++nIndex)
		{
			var oTempFootnote = arrRange[nIndex];
			if (oTempFootnote !== oFootnote)
			{
				oTempFootnote.SelectAll(1);
				this.Selection.Footnotes[oTempFootnote.Get_Id()] = oTempFootnote;
			}
		}

		if (this.Selection.Start.Footnote !== this.Selection.End.Footnote)
			this.Selection.Direction = 1;
		else
			this.Selection.Direction = 0;
	}
};
CFootnotesController.prototype.MoveCursorLeft = function(AddToSelect, Word)
{
	if (true === this.Selection.Use)
	{
		if (true !== AddToSelect)
		{
			var oFootnote = this.CurFootnote;
			if (0 === this.Selection.Direction)
				oFootnote = this.CurFootnote;
			else if (1 === this.Selection.Direction)
				oFootnote = this.Selection.Start.Footnote;
			else
				oFootnote = this.Selection.End.Footnote;

			for (var sId in this.Selection.Footnotes)
			{
				if (oFootnote !== this.Selection.Footnotes[sId])
					this.Selection.Footnotes[sId].RemoveSelection();
			}

			oFootnote.MoveCursorLeft(false, Word);
			oFootnote.RemoveSelection();
			this.private_SetCurrentFootnoteNoSelection(oFootnote);
		}
		else
		{
			var oFootnote = this.Selection.End.Footnote;
			if (false === oFootnote.MoveCursorLeft(true, Word))
			{
				var oPrevFootnote = this.private_GetPrevFootnote(oFootnote);
				if (null === oPrevFootnote)
					return false;

				if (1 !== this.Selection.Direction)
				{
					this.Selection.End.Footnote = oPrevFootnote;
					this.Selection.Direction    = -1;
					this.CurFootnote            = oPrevFootnote;

					this.Selection.Footnotes[oPrevFootnote.Get_Id()] = oPrevFootnote;

					oPrevFootnote.MoveCursorToEndPos(false, true);
					oPrevFootnote.MoveCursorLeft(true, Word);
				}
				else
				{
					this.Selection.End.Footnote = oPrevFootnote;
					this.CurFootnote            = oPrevFootnote;

					if (oPrevFootnote === this.Selection.Start.Footnote)
						this.Selection.Direction = 0;

					oFootnote.RemoveSelection();
					delete this.Selection.Footnotes[oFootnote.Get_Id()];

					oPrevFootnote.MoveCursorLeft(true, Word);
				}
			}
		}
	}
	else
	{
		if (true === AddToSelect)
		{
			var oFootnote = this.CurFootnote;

			this.Selection.Use            = true;
			this.Selection.Start.Footnote = oFootnote;
			this.Selection.End.Footnote   = oFootnote;
			this.Selection.Footnotes      = {};
			this.Selection.Direction      = 0;

			this.Selection.Footnotes[oFootnote.Get_Id()] = oFootnote;
			if (false === oFootnote.MoveCursorLeft(true, Word))
			{
				var oPrevFootnote = this.private_GetPrevFootnote(oFootnote);
				if (null === oPrevFootnote)
					return false;

				this.Selection.End.Footnote = oPrevFootnote;
				this.Selection.Direction    = -1;
				this.CurFootnote            = oPrevFootnote;

				this.Selection.Footnotes[oPrevFootnote.Get_Id()] = oPrevFootnote;

				oPrevFootnote.MoveCursorToEndPos(false, true);
				oPrevFootnote.MoveCursorLeft(true, Word);
			}
		}
		else
		{
			var oFootnote = this.CurFootnote;
			if (false === oFootnote.MoveCursorLeft(false, Word))
			{
				var oPrevFootnote = this.private_GetPrevFootnote(oFootnote);
				if (null === oPrevFootnote)
					return false;

				this.Selection.Start.Footnote = oPrevFootnote;
				this.Selection.End.Footnote   = oPrevFootnote;
				this.Selection.Direction      = 0;
				this.CurFootnote              = oPrevFootnote;
				this.Selection.Footnotes      = {};

				this.Selection.Footnotes[oPrevFootnote.Get_Id()] = oPrevFootnote;

				oPrevFootnote.MoveCursorToEndPos(false);
			}
		}
	}

	return true;
};
CFootnotesController.prototype.MoveCursorRight = function(AddToSelect, Word, FromPaste)
{
	if (true === this.Selection.Use)
	{
		if (true !== AddToSelect)
		{
			var oFootnote = this.CurFootnote;
			if (0 === this.Selection.Direction)
				oFootnote = this.CurFootnote;
			else if (1 === this.Selection.Direction)
				oFootnote = this.Selection.End.Footnote;
			else
				oFootnote = this.Selection.Start.Footnote;

			for (var sId in this.Selection.Footnotes)
			{
				if (oFootnote !== this.Selection.Footnotes[sId])
					this.Selection.Footnotes[sId].RemoveSelection();
			}

			oFootnote.MoveCursorRight(false, Word, FromPaste);
			oFootnote.RemoveSelection();
			this.private_SetCurrentFootnoteNoSelection(oFootnote);
		}
		else
		{
			var oFootnote = this.Selection.End.Footnote;
			if (false === oFootnote.MoveCursorRight(true, Word, FromPaste))
			{
				var oNextFootnote = this.private_GetNextFootnote(oFootnote);
				if (null === oNextFootnote)
					return false;

				if (-1 !== this.Selection.Direction)
				{
					this.Selection.End.Footnote = oNextFootnote;
					this.Selection.Direction    = 1;
					this.CurFootnote            = oNextFootnote;

					this.Selection.Footnotes[oNextFootnote.Get_Id()] = oNextFootnote;

					oNextFootnote.MoveCursorToStartPos(false);
					oNextFootnote.MoveCursorRight(true, Word, FromPaste);
				}
				else
				{
					this.Selection.End.Footnote = oNextFootnote;
					this.CurFootnote            = oNextFootnote;

					if (oNextFootnote === this.Selection.Start.Footnote)
						this.Selection.Direction = 0;

					oFootnote.RemoveSelection();
					delete this.Selection.Footnotes[oFootnote.Get_Id()];

					oNextFootnote.MoveCursorRight(true, Word, FromPaste);
				}
			}
		}
	}
	else
	{
		if (true === AddToSelect)
		{
			var oFootnote = this.CurFootnote;

			this.Selection.Use            = true;
			this.Selection.Start.Footnote = oFootnote;
			this.Selection.End.Footnote   = oFootnote;
			this.Selection.Footnotes      = {};
			this.Selection.Direction      = 0;

			this.Selection.Footnotes[oFootnote.Get_Id()] = oFootnote;
			if (false === oFootnote.MoveCursorRight(true, Word, FromPaste))
			{
				var oNextFootnote = this.private_GetNextFootnote(oFootnote);
				if (null === oNextFootnote)
					return false;

				this.Selection.End.Footnote = oNextFootnote;
				this.Selection.Direction    = 1;
				this.CurFootnote            = oNextFootnote;

				this.Selection.Footnotes[oNextFootnote.Get_Id()] = oNextFootnote;

				oNextFootnote.MoveCursorToStartPos(false);
				oNextFootnote.MoveCursorRight(true, Word, FromPaste);
			}
		}
		else
		{
			var oFootnote = this.CurFootnote;
			if (false === oFootnote.MoveCursorRight(false, Word ,FromPaste))
			{
				var oNextFootnote = this.private_GetNextFootnote(oFootnote);
				if (null === oNextFootnote)
					return false;

				this.Selection.Start.Footnote = oNextFootnote;
				this.Selection.End.Footnote   = oNextFootnote;
				this.Selection.Direction      = 0;
				this.CurFootnote              = oNextFootnote;
				this.Selection.Footnotes      = {};

				this.Selection.Footnotes[oNextFootnote.Get_Id()] = oNextFootnote;

				oNextFootnote.MoveCursorToStartPos(false);
			}
		}
	}

	return true;
};
CFootnotesController.prototype.MoveCursorUp = function(AddToSelect)
{
	if (true === this.Selection.Use)
	{
		if (true === AddToSelect)
		{
			var oFootnote = this.Selection.End.Footnote;
			var oPos = oFootnote.GetCursorPosXY();

			if (false === oFootnote.MoveCursorUp(true))
			{
				var oPrevFootnote = this.private_GetPrevFootnote(oFootnote);
				if (null === oPrevFootnote)
					return false;

				oFootnote.MoveCursorToStartPos(true);

				if (1 !== this.Selection.Direction)
				{
					this.Selection.End.Footnote = oPrevFootnote;
					this.Selection.Direction    = -1;
					this.CurFootnote            = oPrevFootnote;

					this.Selection.Footnotes[oPrevFootnote.Get_Id()] = oPrevFootnote;

					oPrevFootnote.MoveCursorUpToLastRow(oPos.X, oPos.Y, true);
				}
				else
				{
					this.Selection.End.Footnote = oPrevFootnote;
					this.CurFootnote            = oPrevFootnote;

					if (oPrevFootnote === this.Selection.Start.Footnote)
						this.Selection.Direction = 0;

					oFootnote.RemoveSelection();
					delete this.Selection.Footnotes[oFootnote.Get_Id()];

					oPrevFootnote.MoveCursorUpToLastRow(oPos.X, oPos.Y, true);
				}

			}
		}
		else
		{
			var oFootnote = this.CurFootnote;
			if (0 === this.Selection.Direction)
				oFootnote = this.CurFootnote;
			else if (1 === this.Selection.Direction)
				oFootnote = this.Selection.Start.Footnote;
			else
				oFootnote = this.Selection.End.Footnote;

			for (var sId in this.Selection.Footnotes)
			{
				if (oFootnote !== this.Selection.Footnotes[sId])
					this.Selection.Footnotes[sId].RemoveSelection();
			}

			oFootnote.MoveCursorLeft(false, false);
			oFootnote.RemoveSelection();
			this.private_SetCurrentFootnoteNoSelection(oFootnote);
		}
	}
	else
	{
		if (true === AddToSelect)
		{
			var oFootnote = this.CurFootnote;
			var oPos = oFootnote.GetCursorPosXY();
			
			this.Selection.Use            = true;
			this.Selection.Start.Footnote = oFootnote;
			this.Selection.End.Footnote   = oFootnote;
			this.Selection.Footnotes      = {};
			this.Selection.Direction      = 0;

			this.Selection.Footnotes[oFootnote.Get_Id()] = oFootnote;
			if (false === oFootnote.MoveCursorUp(true))
			{
				var oPrevFootnote = this.private_GetPrevFootnote(oFootnote);
				if (null === oPrevFootnote)
					return false;

				oFootnote.MoveCursorToStartPos(true);

				this.Selection.End.Footnote = oPrevFootnote;
				this.Selection.Direction    = -1;
				this.CurFootnote            = oPrevFootnote;

				this.Selection.Footnotes[oPrevFootnote.Get_Id()] = oPrevFootnote;

				oPrevFootnote.MoveCursorUpToLastRow(oPos.X, oPos.Y, true);
			}
		}
		else
		{
			var oFootnote = this.CurFootnote;
			var oPos = oFootnote.GetCursorPosXY();
			if (false === oFootnote.MoveCursorUp(false))
			{
				var oPrevFootnote = this.private_GetPrevFootnote(oFootnote);
				if (null === oPrevFootnote)
					return false;

				this.Selection.Start.Footnote = oPrevFootnote;
				this.Selection.End.Footnote   = oPrevFootnote;
				this.Selection.Direction      = 0;
				this.CurFootnote              = oPrevFootnote;
				this.Selection.Footnotes      = {};

				this.Selection.Footnotes[oPrevFootnote.Get_Id()] = oPrevFootnote;

				oPrevFootnote.MoveCursorUpToLastRow(oPos.X, oPos.Y, false);
			}
		}
	}

	return true;
};
CFootnotesController.prototype.MoveCursorDown = function(AddToSelect)
{
	if (true === this.Selection.Use)
	{
		if (true === AddToSelect)
		{
			var oFootnote = this.Selection.End.Footnote;
			var oPos = oFootnote.GetCursorPosXY();

			if (false === oFootnote.MoveCursorDown(true))
			{
				var oNextFootnote = this.private_GetNextFootnote(oFootnote);
				if (null === oNextFootnote)
					return false;

				oFootnote.MoveCursorToEndPos(true);

				if (-1 !== this.Selection.Direction)
				{
					this.Selection.End.Footnote = oNextFootnote;
					this.Selection.Direction    = 1;
					this.CurFootnote            = oNextFootnote;

					this.Selection.Footnotes[oNextFootnote.Get_Id()] = oNextFootnote;

					oNextFootnote.MoveCursorDownToFirstRow(oPos.X, oPos.Y, true);
				}
				else
				{
					this.Selection.End.Footnote = oNextFootnote;
					this.CurFootnote            = oNextFootnote;

					if (oNextFootnote === this.Selection.Start.Footnote)
						this.Selection.Direction = 0;

					oFootnote.RemoveSelection();
					delete this.Selection.Footnotes[oFootnote.Get_Id()];

					oNextFootnote.MoveCursorDownToFirstRow(oPos.X, oPos.Y, true);
				}

			}
		}
		else
		{
			var oFootnote = this.CurFootnote;
			if (0 === this.Selection.Direction)
				oFootnote = this.CurFootnote;
			else if (1 === this.Selection.Direction)
				oFootnote = this.Selection.End.Footnote;
			else
				oFootnote = this.Selection.Start.Footnote;

			for (var sId in this.Selection.Footnotes)
			{
				if (oFootnote !== this.Selection.Footnotes[sId])
					this.Selection.Footnotes[sId].RemoveSelection();
			}

			oFootnote.MoveCursorRight(false, false);
			oFootnote.RemoveSelection();
			this.private_SetCurrentFootnoteNoSelection(oFootnote);
		}
	}
	else
	{
		if (true === AddToSelect)
		{
			var oFootnote = this.CurFootnote;
			var oPos = oFootnote.GetCursorPosXY();

			this.Selection.Use            = true;
			this.Selection.Start.Footnote = oFootnote;
			this.Selection.End.Footnote   = oFootnote;
			this.Selection.Footnotes      = {};
			this.Selection.Direction      = 0;

			this.Selection.Footnotes[oFootnote.Get_Id()] = oFootnote;
			if (false === oFootnote.MoveCursorDown(true))
			{
				var oNextFootnote = this.private_GetNextFootnote(oFootnote);
				if (null === oNextFootnote)
					return false;

				oFootnote.MoveCursorToEndPos(true, false);

				this.Selection.End.Footnote = oNextFootnote;
				this.Selection.Direction    = 1;
				this.CurFootnote            = oNextFootnote;

				this.Selection.Footnotes[oNextFootnote.Get_Id()] = oNextFootnote;

				oNextFootnote.MoveCursorDownToFirstRow(oPos.X, oPos.Y, true);
			}
		}
		else
		{
			var oFootnote = this.CurFootnote;
			var oPos = oFootnote.GetCursorPosXY();
			if (false === oFootnote.MoveCursorDown(false))
			{
				var oNextFootnote = this.private_GetNextFootnote(oFootnote);
				if (null === oNextFootnote)
					return false;

				this.Selection.Start.Footnote = oNextFootnote;
				this.Selection.End.Footnote   = oNextFootnote;
				this.Selection.Direction      = 0;
				this.CurFootnote              = oNextFootnote;
				this.Selection.Footnotes      = {};

				this.Selection.Footnotes[oNextFootnote.Get_Id()] = oNextFootnote;

				oNextFootnote.MoveCursorDownToFirstRow(oPos.X, oPos.Y, false);
			}
		}
	}

	return true;
};
CFootnotesController.prototype.MoveCursorToEndOfLine = function(AddToSelect)
{
	if (true === this.Selection.Use)
	{
		if (true === AddToSelect)
		{
			var oFootnote = this.Selection.End.Footnote;
			oFootnote.MoveCursorToEndOfLine(true);
		}
		else
		{
			var oFootonote = null;
			if (0 === this.Selection.Direction)
				oFootnote = this.CurFootnote;
			else if (1 === this.Selection.Direction)
				oFootnote = this.Selection.End.Footnote;
			else
				oFootnote = this.Selection.Start.Footnote;

			for (var sId in this.Selection.Footnotes)
			{
				if (oFootnote !== this.Selection.Footnotes[sId])
					this.Selection.Footnotes[sId].RemoveSelection();
			}

			oFootnote.MoveCursorToEndOfLine(false);
			oFootnote.RemoveSelection();
			this.private_SetCurrentFootnoteNoSelection(oFootnote);
		}
	}
	else
	{
		if (true === AddToSelect)
		{
			var oFootnote = this.CurFootnote;

			this.Selection.Use            = true;
			this.Selection.Start.Footnote = oFootnote;
			this.Selection.End.Footnote   = oFootnote;
			this.Selection.Footnotes      = {};
			this.Selection.Direction      = 0;

			this.Selection.Footnotes[oFootnote.Get_Id()] = oFootnote;
			oFootnote.MoveCursorToEndOfLine(true);
		}
		else
		{
			this.CurFootnote.MoveCursorToEndOfLine(false);
		}
	}

	return true;
};
CFootnotesController.prototype.MoveCursorToStartOfLine = function(AddToSelect)
{
	if (true === this.Selection.Use)
	{
		if (true === AddToSelect)
		{
			var oFootnote = this.Selection.End.Footnote;
			oFootnote.MoveCursorToStartOfLine(true);
		}
		else
		{
			var oFootonote = null;
			if (0 === this.Selection.Direction)
				oFootnote = this.CurFootnote;
			else if (1 === this.Selection.Direction)
				oFootnote = this.Selection.Start.Footnote;
			else
				oFootnote = this.Selection.End.Footnote;

			for (var sId in this.Selection.Footnotes)
			{
				if (oFootnote !== this.Selection.Footnotes[sId])
					this.Selection.Footnotes[sId].RemoveSelection();
			}

			oFootnote.MoveCursorToStartOfLine(false);
			oFootnote.RemoveSelection();
			this.private_SetCurrentFootnoteNoSelection(oFootnote);
		}
	}
	else
	{
		if (true === AddToSelect)
		{
			var oFootnote = this.CurFootnote;

			this.Selection.Use            = true;
			this.Selection.Start.Footnote = oFootnote;
			this.Selection.End.Footnote   = oFootnote;
			this.Selection.Footnotes      = {};
			this.Selection.Direction      = 0;

			this.Selection.Footnotes[oFootnote.Get_Id()] = oFootnote;
			oFootnote.MoveCursorToStartOfLine(true);
		}
		else
		{
			this.CurFootnote.MoveCursorToStartOfLine(false);
		}
	}

	return true;
};
CFootnotesController.prototype.MoveCursorToXY = function(X, Y, PageAbs, AddToSelect)
{
	var oResult = this.private_GetFootnoteByXY(X, Y, PageAbs);
	if (!oResult || !oResult.Footnote)
		return;

	var oFootnote = oResult.Footnote;
	var PageRel   = oResult.FootnotePageIndex;
	if (true === AddToSelect)
	{
		var StartFootnote = null;
		if (true === this.Selection.Use)
		{
			StartFootnote = this.Selection.Start.Footnote;
			for (var sId in this.Selection.Footnotes)
			{
				if (this.Selection.Footnotes[sId] !== StartFootnote)
				{
					this.Selection.Footnotes[sId].RemoveSelection();
				}
			}
		}
		else
		{
			StartFootnote = this.CurFootnote;
		}

		var nDirection = this.private_GetDirection(StartFootnote, oFootnote);
		if (0 === nDirection)
		{
			this.Selection.Use            = true;
			this.Selection.Start.Footnote = oFootnote;
			this.Selection.End.Footnote   = oFootnote;
			this.Selection.Footnotes      = {};
			this.Selection.Direction      = 0;

			this.Selection.Footnotes[oFootnote.Get_Id()] = oFootnote;
			oFootnote.MoveCursorToXY(X, Y, true, true, PageRel);
		}
		else if (nDirection > 0)
		{
			var arrFootnotes = this.private_GetFootnotesLogicRange(StartFootnote, oFootnote);
			if (arrFootnotes.length <= 1)
				return;

			var oStartFootnote = arrFootnotes[0]; // StartFootnote
			var oEndFootnote   = arrFootnotes[arrFootnotes.length - 1]; // oFootnote

			this.Selection.Use            = true;
			this.Selection.Start.Footnote = oStartFootnote;
			this.Selection.End.Footnote   = oEndFootnote;
			this.CurFootnote              = oEndFootnote;
			this.Selection.Footnotes      = {};
			this.Selection.Direction      = 1;

			oStartFootnote.MoveCursorToEndPos(true, false);

			for (var nPos = 0, nCount = arrFootnotes.length; nPos < nCount; ++nPos)
			{
				this.Selection.Footnotes[arrFootnotes[nPos].Get_Id()] = arrFootnotes[nPos];

				if (0 !== nPos && nPos !== nCount - 1)
					arrFootnotes[nPos].SelectAll(1);
			}

			oEndFootnote.MoveCursorToStartPos(false);
			oEndFootnote.MoveCursorToXY(X, Y, true, true, PageRel);
		}
		else if (nDirection < 0)
		{
			var arrFootnotes = this.private_GetFootnotesLogicRange(oFootnote, StartFootnote);
			if (arrFootnotes.length <= 1)
				return;

			var oEndFootnote   = arrFootnotes[0]; // oFootnote
			var oStartFootnote = arrFootnotes[arrFootnotes.length - 1]; // StartFootnote

			this.Selection.Use            = true;
			this.Selection.Start.Footnote = oStartFootnote;
			this.Selection.End.Footnote   = oEndFootnote;
			this.CurFootnote              = oEndFootnote;
			this.Selection.Footnotes      = {};
			this.Selection.Direction      = -1;

			oStartFootnote.MoveCursorToStartPos(true);

			for (var nPos = 0, nCount = arrFootnotes.length; nPos < nCount; ++nPos)
			{
				this.Selection.Footnotes[arrFootnotes[nPos].Get_Id()] = arrFootnotes[nPos];

				if (0 !== nPos && nPos !== nCount - 1)
					arrFootnotes[nPos].SelectAll(-1);
			}

			oEndFootnote.MoveCursorToEndPos(false, true);
			oEndFootnote.MoveCursorToXY(X, Y, true, true, PageRel);
		}
	}
	else
	{
		if (true === this.Selection.Use)
		{
			this.RemoveSelection();
		}

		this.private_SetCurrentFootnoteNoSelection(oFootnote);
		oFootnote.MoveCursorToXY(X, Y, false, true, PageRel);
	}
};
CFootnotesController.prototype.MoveCursorToCell = function(bNext)
{
	if (true !== this.private_IsOnFootnoteSelected() || null === this.CurFootnote)
		return false;

	return this.CurFootnote.MoveCursorToCell(bNext);
};
CFootnotesController.prototype.SetParagraphAlign = function(Align)
{
	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		oFootnote.SetParagraphAlign(Align);
	}
};
CFootnotesController.prototype.SetParagraphSpacing = function(Spacing)
{
	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		oFootnote.SetParagraphSpacing(Spacing);
	}
};
CFootnotesController.prototype.SetParagraphTabs = function(Tabs)
{
	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		oFootnote.SetParagraphTabs(Tabs);
	}
};
CFootnotesController.prototype.SetParagraphIndent = function(Ind)
{
	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		oFootnote.SetParagraphIndent(Ind);
	}
};
CFootnotesController.prototype.SetParagraphShd = function(Shd)
{
	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		oFootnote.SetParagraphShd(Shd);
	}
};
CFootnotesController.prototype.SetParagraphStyle = function(Name)
{
	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		oFootnote.SetParagraphStyle(Name);
	}
};
CFootnotesController.prototype.SetParagraphContextualSpacing = function(Value)
{
	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		oFootnote.SetParagraphContextualSpacing(Value);
	}
};
CFootnotesController.prototype.SetParagraphPageBreakBefore = function(Value)
{
	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		oFootnote.SetParagraphPageBreakBefore(Value);
	}
};
CFootnotesController.prototype.SetParagraphKeepLines = function(Value)
{
	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		oFootnote.SetParagraphKeepLines(Value);
	}
};
CFootnotesController.prototype.SetParagraphKeepNext = function(Value)
{
	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		oFootnote.SetParagraphKeepNext(Value);
	}
};
CFootnotesController.prototype.SetParagraphWidowControl = function(Value)
{
	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		oFootnote.SetParagraphWidowControl(Value);
	}
};
CFootnotesController.prototype.SetParagraphBorders = function(Borders)
{
	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		oFootnote.SetParagraphBorders(Borders);
	}
};
CFootnotesController.prototype.SetParagraphFramePr = function(FramePr, bDelete)
{
	// Не позволяем делать рамки внутри сносок
};
CFootnotesController.prototype.IncreaseDecreaseFontSize = function(bIncrease)
{
	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		oFootnote.IncreaseDecreaseFontSize(bIncrease);
	}
};
CFootnotesController.prototype.IncreaseDecreaseIndent = function(bIncrease)
{
	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		oFootnote.IncreaseDecreaseIndent(bIncrease);
	}
};
CFootnotesController.prototype.SetImageProps = function(Props)
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return;

	return this.CurFootnote.SetImageProps(Props);
};
CFootnotesController.prototype.SetTableProps = function(Props)
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return;

	return this.CurFootnote.SetTableProps(Props);
};
CFootnotesController.prototype.GetCalculatedParaPr = function()
{
	var StartPr = this.CurFootnote.GetCalculatedParaPr();
	var Pr = StartPr.Copy();

	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		var TempPr = oFootnote.GetCalculatedParaPr();
		Pr = Pr.Compare(TempPr);
	}

	if (undefined === Pr.Ind.Left)
		Pr.Ind.Left = StartPr.Ind.Left;

	if (undefined === Pr.Ind.Right)
		Pr.Ind.Right = StartPr.Ind.Right;

	if (undefined === Pr.Ind.FirstLine)
		Pr.Ind.FirstLine = StartPr.Ind.FirstLine;

	if (true !== this.private_IsOnFootnoteSelected())
		Pr.CanAddTable = false;

	return Pr;
};
CFootnotesController.prototype.GetCalculatedTextPr = function()
{
	var StartPr = this.CurFootnote.GetCalculatedTextPr();
	var Pr = StartPr.Copy();

	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		var TempPr = oFootnote.GetCalculatedTextPr();
		Pr = Pr.Compare(TempPr);
	}

	return Pr;
};
CFootnotesController.prototype.GetDirectParaPr = function()
{
	if (null !== this.CurFootnote)
		return this.CurFootnote.GetDirectParaPr();

	return new CParaPr();
};
CFootnotesController.prototype.GetDirectTextPr = function()
{
	if (null !== this.CurFootnote)
		return this.CurFootnote.GetDirectTextPr();

	return new CTextPr();
};
CFootnotesController.prototype.RemoveSelection = function(bNoCheckDrawing)
{
	if (true === this.Selection.Use)
	{
		for (var sId in this.Selection.Footnotes)
		{
			this.Selection.Footnotes[sId].RemoveSelection(bNoCheckDrawing);
		}

		this.Selection.Use = false;
	}

	this.Selection.Footnotes = {};
	if (this.CurFootnote)
		this.Selection.Footnotes[this.CurFootnote.Get_Id()] = this.CurFootnote;
};
CFootnotesController.prototype.IsSelectionEmpty = function(bCheckHidden)
{
	if (true !== this.IsSelectionUse())
		return true;

	var oFootnote = null;
	for (var sId in this.Selection.Footnotes)
	{
		if (null === oFootnote)
			oFootnote = this.Selection.Footnotes[sId];
		else if (oFootnote !== this.Selection.Footnotes[sId])
			return false;
	}

	if (null === oFootnote)
		return true;

	return oFootnote.IsSelectionEmpty(bCheckHidden);
};
CFootnotesController.prototype.DrawSelectionOnPage = function(nPageAbs)
{
	if (true !== this.Selection.Use || true === this.IsEmptyPage(nPageAbs))
		return;

	var oPage = this.Pages[nPageAbs];
	for (var nColumnIndex = 0, nColumnsCount = oPage.Columns.length; nColumnIndex < nColumnsCount; ++nColumnIndex)
	{
		var oColumn = oPage.Columns[nColumnIndex];
		for (var nIndex = 0, nCount = oColumn.Elements.length; nIndex < nCount; ++nIndex)
		{
			var oFootnote = oColumn.Elements[nIndex];
			if (oFootnote === this.Selection.Footnotes[oFootnote.Get_Id()])
			{
				var nFootnotePageIndex = oFootnote.GetElementPageIndex(nPageAbs, nColumnIndex);
				oFootnote.DrawSelectionOnPage(nFootnotePageIndex);
			}
		}
	}
};
CFootnotesController.prototype.GetSelectionBounds = function()
{
	if (true === this.Selection.Use)
	{
		if (0 === this.Selection.Direction)
		{
			return this.CurFootnote.GetSelectionBounds();
		}
		else if (1 === this.Selection.Direction)
		{
			var StartBounds = this.Selection.Start.Footnote.GetSelectionBounds();
			var EndBounds   = this.Selection.End.Footnote.GetSelectionBounds();

			if (!StartBounds && !EndBounds)
				return null;

			var Result       = {};
			Result.Start     = StartBounds ? StartBounds.Start : EndBounds.Start;
			Result.End       = EndBounds ? EndBounds.End : StartBounds.End;
			Result.Direction = 1;
			return Result;
		}
		else
		{
			var StartBounds = this.Selection.End.Footnote.GetSelectionBounds();
			var EndBounds   = this.Selection.Start.Footnote.GetSelectionBounds();

			if (!StartBounds && !EndBounds)
				return null;

			var Result       = {};
			Result.Start     = StartBounds ? StartBounds.Start : EndBounds.Start;
			Result.End       = EndBounds ? EndBounds.End : StartBounds.End;
			Result.Direction = -1;
			return Result;
		}
	}

	return null;
};
CFootnotesController.prototype.IsMovingTableBorder = function()
{
	if (true !== this.private_IsOnFootnoteSelected())
		return false;

	return this.CurFootnote.IsMovingTableBorder();
};
CFootnotesController.prototype.CheckPosInSelection = function(X, Y, PageAbs, NearPos)
{
	var oResult = this.private_GetFootnoteByXY(X, Y, PageAbs);
	if (oResult)
	{
		var oFootnote = oResult.Footnote;
		return oFootnote.CheckPosInSelection(X, Y, oResult.FootnotePageIndex, NearPos);
	}

	return false;
};
CFootnotesController.prototype.SelectAll = function(nDirection)
{
	var arrFootnotes = this.private_GetFootnotesLogicRange(null, null);
	if (!arrFootnotes || arrFootnotes.length <= 0)
		return;

	if (1 === arrFootnotes.length)
	{
		var oFootnote = arrFootnotes[0];

		this.Selection.Use            = true;
		this.Selection.Start.Footnote = oFootnote;
		this.Selection.End.Footnote   = oFootnote;
		this.CurFootnote              = oFootnote;
		this.Selection.Footnotes      = {};
		this.Selection.Direction      = 0;

		this.Selection.Footnotes[oFootnote.Get_Id()] = oFootnote;
		oFootnote.SelectAll(nDirection);
	}
	else
	{
		var StartFootnote, EndFootnote;
		if (nDirection < 0)
		{
			StartFootnote = arrFootnotes[arrFootnotes.length - 1];
			EndFootnote   = arrFootnotes[0];
			this.Selection.Direction = -1;
		}
		else
		{
			StartFootnote = arrFootnotes[0];
			EndFootnote   = arrFootnotes[arrFootnotes.length - 1];
			this.Selection.Direction = -1;
		}

		this.Selection.Use            = true;
		this.Selection.Start.Footnote = StartFootnote;
		this.Selection.End.Footnote   = EndFootnote;
		this.CurFootnote              = EndFootnote;
		this.Selection.Footnotes      = {};

		for (var nPos = 0, nCount = arrFootnotes.length; nPos < nCount; ++nPos)
		{
			var oFootnote = arrFootnotes[nPos];
			oFootnote.SelectAll(nDirection);
			this.Selection.Footnotes[oFootnote.Get_Id()] = oFootnote;
		}
	}
};
CFootnotesController.prototype.GetSelectedContent = function(SelectedContent)
{
	if (true !== this.Selection.Use)
		return;

	if (0 === this.Selection.Direction)
	{
		this.CurFootnote.GetSelectedContent(SelectedContent);
	}
	else
	{
		var arrFootnotes = this.private_GetSelectionArray();
		for (var nPos = 0, nCount = arrFootnotes.length; nPos < nCount; ++nPos)
		{
			arrFootnotes[nPos].GetSelectedContent(SelectedContent);
		}
	}
};
CFootnotesController.prototype.UpdateCursorType = function(X, Y, PageAbs, MouseEvent)
{
	var oResult = this.private_GetFootnoteByXY(X, Y, PageAbs);
	if (oResult)
	{
		var oFootnote = oResult.Footnote;
		oFootnote.UpdateCursorType(X, Y, oResult.FootnotePageIndex, MouseEvent);
	}
};
CFootnotesController.prototype.PasteFormatting = function(TextPr, ParaPr)
{
	for (var sId in this.Selection.Footnotes)
	{
		this.Selection.Footnotes[sId].PasteFormatting(TextPr, ParaPr, true);
	}
};
CFootnotesController.prototype.IsSelectionUse = function()
{
	return this.Selection.Use;
};
CFootnotesController.prototype.IsNumberingSelection = function()
{
	if (this.CurFootnote)
		return this.CurFootnote.IsNumberingSelection();

	return false;
};
CFootnotesController.prototype.IsTextSelectionUse = function()
{
	if (true !== this.Selection.Use)
		return false;

	if (0 === this.Selection.Direction)
		return this.CurFootnote.IsTextSelectionUse();

	return true;
};
CFootnotesController.prototype.GetCurPosXY = function()
{
	if (this.CurFootnote)
		return this.CurFootnote.GetCurPosXY();

	return {X : 0, Y : 0};
};
CFootnotesController.prototype.GetSelectedText = function(bClearText, oPr)
{
	if (true === bClearText)
	{
		if (true !== this.Selection.Use || 0 !== this.Selection.Direction)
			return "";

		return this.CurFootnote.GetSelectedText(true, oPr);
	}
	else
	{
		var sResult = "";
		var arrFootnotes = this.private_GetSelectionArray();
		for (var nPos = 0, nCount = arrFootnotes.length; nPos < nCount; ++nPos)
		{
			var sTempResult = arrFootnotes[nPos].GetSelectedText(false, oPr);
			if (null == sTempResult)
				return null;

			sResult += sTempResult;
		}

		return sResult;
	}
};
CFootnotesController.prototype.GetCurrentParagraph = function(bIgnoreSelection, arrSelectedParagraphs)
{
	return this.CurFootnote.GetCurrentParagraph(bIgnoreSelection, arrSelectedParagraphs);
};
CFootnotesController.prototype.GetSelectedElementsInfo = function(oInfo)
{
	if (true !== this.private_IsOnFootnoteSelected() || null === this.CurFootnote)
		oInfo.Set_MixedSelection();
	else
		this.CurFootnote.GetSelectedElementsInfo(oInfo);
};
CFootnotesController.prototype.AddTableRow = function(bBefore)
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return;

	this.CurFootnote.AddTableRow(bBefore);
};
CFootnotesController.prototype.AddTableColumn = function(bBefore)
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return;

	this.CurFootnote.AddTableColumn(bBefore);
};
CFootnotesController.prototype.RemoveTableRow = function()
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return;

	this.CurFootnote.RemoveTableRow();
};
CFootnotesController.prototype.RemoveTableColumn = function()
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return;

	this.CurFootnote.RemoveTableColumn();
};
CFootnotesController.prototype.MergeTableCells = function()
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return;

	this.CurFootnote.MergeTableCells();
};
CFootnotesController.prototype.SplitTableCells = function(Cols, Rows)
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return;

	this.CurFootnote.SplitTableCells(Cols, Rows);
};
CFootnotesController.prototype.RemoveTable = function()
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return;

	this.CurFootnote.RemoveTable();
};
CFootnotesController.prototype.SelectTable = function(Type)
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return;

	this.RemoveSelection();

	this.CurFootnote.SelectTable(Type);
	if (true === this.CurFootnote.IsSelectionUse())
	{
		this.Selection.Use            = true;
		this.Selection.Start.Footnote = this.CurFootnote;
		this.Selection.End.Footnote   = this.CurFootnote;
		this.Selection.Footnotes      = {};
		this.Selection.Direction      = 0;

		this.Selection.Footnotes[this.CurFootnote.Get_Id()] = this.CurFootnote;
	}
};
CFootnotesController.prototype.CanMergeTableCells = function()
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return false;

	return this.CurFootnote.CanMergeTableCells();
};
CFootnotesController.prototype.CanSplitTableCells = function()
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return false;

	return this.CurFootnote.CanSplitTableCells();
};
CFootnotesController.prototype.DistributeTableCells = function(isHorizontally)
{
	if (false === this.private_CheckFootnotesSelectionBeforeAction())
		return false;

	return this.CurFootnote.DistributeTableCells(isHorizontally);
};
CFootnotesController.prototype.UpdateInterfaceState = function()
{
	if (true === this.private_IsOnFootnoteSelected())
	{
		this.CurFootnote.Document_UpdateInterfaceState();
	}
	else
	{
		var Api = this.LogicDocument.Get_Api();
		if (!Api)
			return;

		var ParaPr = this.GetCalculatedParaPr();

		if (undefined != ParaPr.Tabs)
			Api.Update_ParaTab(AscCommonWord.Default_Tab_Stop, ParaPr.Tabs);

		Api.UpdateParagraphProp(ParaPr);
		Api.UpdateTextPr(this.GetCalculatedTextPr());
	}
};
CFootnotesController.prototype.UpdateRulersState = function()
{
	var PageAbs = this.CurFootnote.Get_StartPage_Absolute();
	if (this.LogicDocument.Pages[PageAbs])
	{
		var Pos    = this.LogicDocument.Pages[PageAbs].Pos;
		var SectPr = this.LogicDocument.SectionsInfo.Get_SectPr(Pos).SectPr;

		var L = SectPr.Get_PageMargin_Left();
		var T = SectPr.Get_PageMargin_Top();
		var R = SectPr.Get_PageWidth() - SectPr.Get_PageMargin_Right();
		var B = SectPr.Get_PageHeight() - SectPr.Get_PageMargin_Bottom();
		this.DrawingDocument.Set_RulerState_Paragraph({L : L, T : T, R : R, B : B}, true);
	}

	if (true === this.private_IsOnFootnoteSelected())
		this.CurFootnote.Document_UpdateRulersState();
};
CFootnotesController.prototype.UpdateSelectionState = function()
{
	if (true === this.Selection.Use)
	{
		if (true === this.IsMovingTableBorder())
		{
			this.DrawingDocument.TargetEnd();
			this.DrawingDocument.SetCurrentPage(this.LogicDocument.CurPage);
		}
		else if (false === this.IsSelectionEmpty())
		{
			if (true !== this.LogicDocument.Selection.Start)
			{
				this.LogicDocument.private_CheckCurPage();
				this.RecalculateCurPos();
			}

			this.LogicDocument.private_UpdateTracks(true, false);

			this.DrawingDocument.TargetEnd();
			this.DrawingDocument.SelectEnabled(true);
			this.DrawingDocument.SelectShow();
		}
		else
		{
			if (true !== this.LogicDocument.Selection.Start)
				this.LogicDocument.RemoveSelection();

			this.LogicDocument.private_CheckCurPage();
			this.RecalculateCurPos();
			this.LogicDocument.private_UpdateTracks(true, true);

			this.DrawingDocument.SelectEnabled(false);
			this.DrawingDocument.TargetStart();
			this.DrawingDocument.TargetShow();
		}
	}
	else
	{
		this.LogicDocument.RemoveSelection();
		this.LogicDocument.private_CheckCurPage();
		this.RecalculateCurPos();
		this.LogicDocument.private_UpdateTracks(false, false);

		this.DrawingDocument.SelectEnabled(false);
		this.DrawingDocument.TargetShow();
	}
};
CFootnotesController.prototype.GetSelectionState = function()
{
	var arrResult = [];

	var oState = {
		Footnotes   : {},
		Use         : this.Selection.Use,
		Start       : this.Selection.Start.Footnote,
		End         : this.Selection.End.Footnote,
		Direction   : this.Selection.Direction,
		CurFootnote : this.CurFootnote
	};

	for (var sId in this.Selection.Footnotes)
	{
		var oFootnote = this.Selection.Footnotes[sId];
		oState.Footnotes[sId] =
		{
			Footnote : oFootnote,
			State    : oFootnote.GetSelectionState()
		};
	}

	arrResult.push(oState);
	return arrResult;
};
CFootnotesController.prototype.SetSelectionState = function(State, StateIndex)
{
	var oState = State[StateIndex];

	this.Selection.Use            = oState.Use;
	this.Selection.Start.Footnote = oState.Start;
	this.Selection.End.Footnote   = oState.End;
	this.Selection.Direction      = oState.Direction;
	this.CurFootnote              = oState.CurFootnote;
	this.Selection.Footnotes      = {};
	
	for (var sId in oState.Footnotes)
	{
		this.Selection.Footnotes[sId] = oState.Footnotes[sId].Footnote;
		this.Selection.Footnotes[sId].SetSelectionState(oState.Footnotes[sId].State, oState.Footnotes[sId].State.length - 1);
	}
};
CFootnotesController.prototype.AddHyperlink = function(Props)
{
	if (true !== this.IsSelectionUse() || true === this.private_IsOnFootnoteSelected())
	{
		this.CurFootnote.AddHyperlink(Props);
	}
};
CFootnotesController.prototype.ModifyHyperlink = function(Props)
{
	if (true !== this.IsSelectionUse() || true === this.private_IsOnFootnoteSelected())
	{
		this.CurFootnote.ModifyHyperlink(Props);
	}
};
CFootnotesController.prototype.RemoveHyperlink = function()
{
	if (true !== this.IsSelectionUse() || true === this.private_IsOnFootnoteSelected())
	{
		this.CurFootnote.RemoveHyperlink();
	}
};
CFootnotesController.prototype.CanAddHyperlink = function(bCheckInHyperlink)
{
	if (true !== this.IsSelectionUse() || true === this.private_IsOnFootnoteSelected())
		return this.CurFootnote.CanAddHyperlink(bCheckInHyperlink);

	return false;
};
CFootnotesController.prototype.IsCursorInHyperlink = function(bCheckEnd)
{
	if (true !== this.IsSelectionUse() || true === this.private_IsOnFootnoteSelected())
		return this.CurFootnote.IsCursorInHyperlink(bCheckEnd);

	return null;
};
CFootnotesController.prototype.AddComment = function(Comment)
{
	if (true !== this.IsSelectionUse() || true === this.private_IsOnFootnoteSelected())
	{
		this.CurFootnote.AddComment(Comment, true, true);
	}
};
CFootnotesController.prototype.CanAddComment = function()
{
	if (true !== this.IsSelectionUse() || true === this.private_IsOnFootnoteSelected())
		return this.CurFootnote.CanAddComment();

	return false;
};
CFootnotesController.prototype.GetSelectionAnchorPos = function()
{
	if (true !== this.Selection.Use || 0 === this.Selection.Direction)
		return this.CurFootnote.GetSelectionAnchorPos();
	else if (1 === this.Selection.Direction)
		return this.Selection.Start.Footnote.GetSelectionAnchorPos();
	else
		return this.Selection.End.Footnote.GetSelectionAnchorPos();
};
CFootnotesController.prototype.StartSelectionFromCurPos = function()
{
	if (true === this.Selection.Use)
		return;

	this.Selection.Use = true;
	this.Selection.Start.Footnote = this.CurFootnote;
	this.Selection.End.Footnote   = this.CurFootnote;
	this.Selection.Footnotes = {};
	this.Selection.Footnotes[this.CurFootnote.Get_Id()] = this.CurFootnote;
	this.CurFootnote.StartSelectionFromCurPos();
};
CFootnotesController.prototype.SaveDocumentStateBeforeLoadChanges   = function(State)
{
	State.FootnotesSelectDirection = this.Selection.Direction;
	State.FootnotesSelectionUse    = this.Selection.Use;

	if (0 === this.Selection.Direction || false === this.Selection.Use)
	{
		var oFootnote               = this.CurFootnote;
		State.CurFootnote           = oFootnote;
		State.CurFootnoteSelection  = oFootnote.Selection.Use;
		State.CurFootnoteDocPosType = oFootnote.Get_DocPosType();

		if (docpostype_Content === oFootnote.Get_DocPosType())
		{
			State.Pos      = oFootnote.GetContentPosition(false, false, undefined);
			State.StartPos = oFootnote.GetContentPosition(true, true, undefined);
			State.EndPos   = oFootnote.GetContentPosition(true, false, undefined);
		}
		else if (docpostype_DrawingObjects === oFootnote.Get_DocPosType())
		{
			this.LogicDocument.DrawingObjects.Save_DocumentStateBeforeLoadChanges(State);
		}
	}
	else
	{
		State.FootnotesList  = this.private_GetSelectionArray();
		var oFootnote        = State.FootnotesList[0];
		State.FootnotesStart = {
			Pos      : oFootnote.GetContentPosition(false, false, undefined),
			StartPos : oFootnote.GetContentPosition(true, true, undefined),
			EndPos   : oFootnote.GetContentPosition(true, false, undefined)
		};

		oFootnote          = State.FootnotesList[State.FootnotesList.length - 1];
		State.FootnotesEnd = {
			Pos      : oFootnote.GetContentPosition(false, false, undefined),
			StartPos : oFootnote.GetContentPosition(true, true, undefined),
			EndPos   : oFootnote.GetContentPosition(true, false, undefined)
		};
	}
};
CFootnotesController.prototype.RestoreDocumentStateAfterLoadChanges = function(State)
{
	this.RemoveSelection();
	if (0 === State.FootnotesSelectDirection)
	{
		var oFootnote = State.CurFootnote;
		if (oFootnote && true === this.Is_UseInDocument(oFootnote.Get_Id()))
		{
			this.Selection.Start.Footnote = oFootnote;
			this.Selection.End.Footnote   = oFootnote;
			this.Selection.Direction      = 0;
			this.CurFootnote              = oFootnote;
			this.Selection.Footnotes      = {};
			this.Selection.Use            = State.FootnotesSelectionUse;

			this.Selection.Footnotes[oFootnote.Get_Id()] = oFootnote;

			if (docpostype_Content === State.CurFootnoteDocPosType)
			{
				oFootnote.Set_DocPosType(docpostype_Content);
				oFootnote.Selection.Use = State.CurFootnoteSelection;
				if (true === oFootnote.Selection.Use)
				{
					oFootnote.SetContentPosition(State.StartPos, 0, 0);
					oFootnote.SetContentSelection(State.StartPos, State.EndPos, 0, 0, 0);
				}
				else
				{
					oFootnote.SetContentPosition(State.Pos, 0, 0);
					this.LogicDocument.NeedUpdateTarget = true;
				}
			}
			else if (docpostype_DrawingObjects === State.CurFootnoteDocPosType)
			{
				oFootnote.Set_DocPosType(docpostype_DrawingObjects);
				if (true !== this.LogicDocument.DrawingObjects.Load_DocumentStateAfterLoadChanges(State))
				{
					oFootnote.Set_DocPosType(docpostype_Content);
					this.LogicDocument.MoveCursorToXY(State.X ? State.X : 0, State.Y ? State.Y : 0, false);
				}
			}
		}
		else
		{
			this.LogicDocument.EndFootnotesEditing();
		}
	}
	else
	{
		var arrFootnotesList = State.FootnotesList;

		var StartFootnote = null;
		var EndFootnote   = null;

		var arrAllFootnotes = this.private_GetFootnotesLogicRange(null, null);

		for (var nIndex = 0, nCount = arrFootnotesList.length; nIndex < nCount; ++nIndex)
		{
			var oFootnote = arrFootnotesList[nIndex];
			if (true === this.Is_UseInDocument(oFootnote.Get_Id(), arrAllFootnotes))
			{
				if (null === StartFootnote)
					StartFootnote = oFootnote;

				EndFootnote = oFootnote;
			}
		}

		if (null === StartFootnote || null === EndFootnote)
		{
			this.LogicDocument.EndFootnotesEditing();
			return;
		}

		var arrNewFootnotesList = this.private_GetFootnotesLogicRange(StartFootnote, EndFootnote);
		if (arrNewFootnotesList.length < 1)
		{
			if (null !== EndFootnote)
			{
				EndFootnote.RemoveSelection();
				this.private_SetCurrentFootnoteNoSelection(EndFootnote);
			}
			else if (null !== StartFootnote)
			{
				StartFootnote.RemoveSelection();
				this.private_SetCurrentFootnoteNoSelection(StartFootnote);
			}
			else
			{
				this.LogicDocument.EndFootnotesEditing();
			}
		}
		else if (arrNewFootnotesList.length === 1)
		{
			this.Selection.Use            = true;
			this.Selection.Direction      = 0;
			this.Selection.Footnotes      = {};
			this.Selection.Start.Footnote = StartFootnote;
			this.Selection.End.Footnote   = StartFootnote;
			this.CurFootnote              = StartFootnote;

			this.Selection.Footnotes[StartFootnote.Get_Id()] = StartFootnote;

			if (arrFootnotesList[0] === StartFootnote)
			{
				StartFootnote.Set_DocPosType(docpostype_Content);
				StartFootnote.Selection.Use = true;
				StartFootnote.SetContentPosition(State.FootnotesStart.Pos, 0, 0);
				StartFootnote.SetContentSelection(State.FootnotesStart.StartPos, State.FootnotesStart.EndPos, 0, 0, 0);
			}
			else if (arrFootnotesList[arrAllFootnotes.length - 1] === StartFootnote)
			{
				StartFootnote.Set_DocPosType(docpostype_Content);
				StartFootnote.Selection.Use = true;
				StartFootnote.SetContentPosition(State.FootnotesEnd.Pos, 0, 0);
				StartFootnote.SetContentSelection(State.FootnotesEnd.StartPos, State.FootnotesEnd.EndPos, 0, 0, 0);
			}
			else
			{
				StartFootnote.Set_DocPosType(docpostype_Content);
				StartFootnote.SelectAll(1);
			}
		}
		else
		{
			this.Selection.Use       = true;
			this.Selection.Direction = State.FootnotesSelectDirection;
			this.Selection.Footnotes = {};

			for (var nIndex = 1, nCount = arrNewFootnotesList.length; nIndex < nCount - 1; ++nIndex)
			{
				var oFootnote = arrNewFootnotesList[nIndex];
				oFootnote.SelectAll(this.Selection.Direction);
				this.Selection.Footnotes[oFootnote.Get_Id()] = oFootnote;
			}

			this.Selection.Footnotes[StartFootnote.Get_Id()] = StartFootnote;
			this.Selection.Footnotes[EndFootnote.Get_Id()]   = EndFootnote;


			if (arrFootnotesList[0] === StartFootnote)
			{
				StartFootnote.Set_DocPosType(docpostype_Content);
				StartFootnote.Selection.Use = true;
				StartFootnote.SetContentPosition(State.FootnotesStart.Pos, 0, 0);
				StartFootnote.SetContentSelection(State.FootnotesStart.StartPos, State.FootnotesStart.EndPos, 0, 0, 0);
			}
			else
			{
				StartFootnote.Set_DocPosType(docpostype_Content);
				StartFootnote.SelectAll(1);
			}

			if (arrFootnotesList[arrFootnotesList.length - 1] === EndFootnote)
			{
				EndFootnote.Set_DocPosType(docpostype_Content);
				EndFootnote.Selection.Use = true;
				EndFootnote.SetContentPosition(State.FootnotesEnd.Pos, 0, 0);
				EndFootnote.SetContentSelection(State.FootnotesEnd.StartPos, State.FootnotesEnd.EndPos, 0, 0, 0);
			}
			else
			{
				EndFootnote.Set_DocPosType(docpostype_Content);
				EndFootnote.SelectAll(1);
			}

			if (1 !== this.Selection.Direction)
			{
				var Temp      = StartFootnote;
				StartFootnote = EndFootnote;
				EndFootnote   = Temp;
			}

			this.Selection.Start.Footnote = StartFootnote;
			this.Selection.End.Footnote   = EndFootnote;
		}
	}
};
CFootnotesController.prototype.GetColumnSize = function()
{
	// TODO: Переделать
	var _w = Math.max(1, AscCommon.Page_Width - (AscCommon.X_Left_Margin + AscCommon.X_Right_Margin));
	var _h = Math.max(1, AscCommon.Page_Height - (AscCommon.Y_Top_Margin + AscCommon.Y_Bottom_Margin));

	return {
		W : AscCommon.Page_Width - (AscCommon.X_Left_Margin + AscCommon.X_Right_Margin),
		H : AscCommon.Page_Height - (AscCommon.Y_Top_Margin + AscCommon.Y_Bottom_Margin)
	};
};
CFootnotesController.prototype.GetCurrentSectionPr = function()
{
	return null;
};
CFootnotesController.prototype.GetColumnFields = function(nPageAbs, nColumnAbs)
{
	var oColumn = this.private_GetPageColumn(nPageAbs, nColumnAbs);
	if (!oColumn)
		return {X : 0, XLimit : 297};

	return {X : oColumn.X, XLimit : oColumn.XLimit};
};
CFootnotesController.prototype.RemoveTextSelection = function()
{
	if (true === this.Selection.Use)
	{
		for (var sId in this.Selection.Footnotes)
		{
			if (this.Selection.Footnotes[sId] !== this.CurFootnote)
				this.Selection.Footnotes[sId].RemoveSelection();
		}

		this.Selection.Use = false;
	}

	this.Selection.Footnotes = {};
	if (this.CurFootnote)
	{
		this.Selection.Footnotes[this.CurFootnote.Get_Id()] = this.CurFootnote;
		this.CurFootnote.RemoveTextSelection();
	}
};
CFootnotesController.prototype.ResetRecalculateCache = function()
{
	for (var Id in this.Footnote)
	{
		this.Footnote[Id].Reset_RecalculateCache();
	}
};
CFootnotesController.prototype.AddContentControl = function(nContentControlType)
{
	if (this.CurFootnote)
		return this.CurFootnote.AddContentControl(nContentControlType);

	return null;
};
CFootnotesController.prototype.GetStyleFromFormatting = function()
{
	if (this.CurFootnote)
		return this.CurFootnote.GetStyleFromFormatting();

	return null;
};
CFootnotesController.prototype.GetSimilarNumbering = function(oEngine)
{
	if (this.CurFootnote)
		this.CurFootnote.GetSimilarNumbering(oEngine);
};


function CFootEndnotePageColumn()
{
	this.X      = 0;
	this.Y      = 0;
	this.XLimit = 0;
	this.YLimit = 0;

	this.ReferenceY        = 0;
	this.Height            = 0;
	this.Elements          = []; // Элементы, которые пересчитаны на данной странице
	this.ContinuesElements = []; // Элементы, которые нужно пересчитывать на следующей колонке

	this.SeparatorRecalculateObject             = null;
	this.ContinuationSeparatorRecalculateObject = null;
	this.ContinuationNoticeRecalculateObject    = null;
}
CFootEndnotePageColumn.prototype.Reset = function()
{
	this.ReferenceY        = 0;
	this.Height            = 0;
	this.Elements          = [];
	this.ContinuesElements = [];

	this.SeparatorRecalculateObject             = null;
	this.ContinuationSeparatorRecalculateObject = null;
	this.ContinuationNoticeRecalculateObject    = null;
};
CFootEndnotePageColumn.prototype.GetContinuesElements = function()
{
	return this.ContinuesElements;
};
CFootEndnotePageColumn.prototype.SetContinuesElements = function(arrContinuesElements)
{
	this.ContinuesElements = arrContinuesElements;
};
CFootEndnotePageColumn.prototype.AddContinuesElements = function(arrElements)
{
	for (var nIndex = 0, nCount = arrElements.length; nIndex < nCount; ++nIndex)
	{
		this.ContinuesElements.push(arrElements[nIndex]);
	}
};
CFootEndnotePageColumn.prototype.SaveRecalculateObject = function()
{
	var oColumn = new CFootEndnotePageColumn();

	oColumn.X      = this.X;
	oColumn.Y      = this.Y;
	oColumn.XLimit = this.XLimit;
	oColumn.YLimit = this.YLimit;

	oColumn.ReferenceY = this.ReferenceY;
	oColumn.Height     = this.Height;

	for (var nIndex = 0, nCount = this.Elements.length; nIndex < nCount; ++nIndex)
	{
		oColumn.Elements[nIndex] = this.Elements[nIndex];
	}

	oColumn.ContinuesElements = this.ContinuesElements;

	oColumn.SeparatorRecalculateObject             = this.SeparatorRecalculateObject;
	oColumn.ContinuationSeparatorRecalculateObject = this.ContinuationSeparatorRecalculateObject;
	oColumn.ContinuationNoticeRecalculateObject    = this.ContinuationNoticeRecalculateObject;
	return oColumn;
};
CFootEndnotePageColumn.prototype.LoadRecalculateObject = function(oObject)
{
	this.X      = oObject.X;
	this.Y      = oObject.Y;
	this.XLimit = oObject.XLimit;
	this.YLimit = oObject.YLimit;

	this.ReferenceY = oObject.ReferenceY;
	this.Height     = oObject.Height;

	this.Elements = [];
	for (var nIndex = 0, nCount = oObject.Elements.length; nIndex < nCount; ++nIndex)
	{
		this.Elements[nIndex] = oObject.Elements[nIndex];
	}

	this.ContinuesElements = oObject.ContinuesElements;

	this.SeparatorRecalculateObject             = oObject.SeparatorRecalculateObject;
	this.ContinuationSeparatorRecalculateObject = oObject.ContinuationSeparatorRecalculateObject;
	this.ContinuationNoticeRecalculateObject    = oObject.ContinuationNoticeRecalculateObject;
};

function CFootEndnotePage()
{
	this.Columns = [];
}
CFootEndnotePage.prototype.Reset = function()
{
	this.Columns = [];
};
CFootEndnotePage.prototype.AddColumn = function(oColumn)
{
	this.Columns.push(oColumn);
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 10.11.2016
 * Time: 19:35
 */

AscDFH.changesFactory[AscDFH.historyitem_Footnotes_AddFootnote]              = CChangesFootnotesAddFootnote;
AscDFH.changesFactory[AscDFH.historyitem_Footnotes_SetSeparator]             = CChangesFootnotesSetSeparator;
AscDFH.changesFactory[AscDFH.historyitem_Footnotes_SetContinuationSeparator] = CChangesFootnotesSetContinuationSeparator;
AscDFH.changesFactory[AscDFH.historyitem_Footnotes_SetContinuationNotice]    = CChangesFootnotesSetContinuationNotice;
AscDFH.changesFactory[AscDFH.historyitem_Footnotes_SetFootnotePrPos]         = CChangesFootnotesSetFootnotePrPos;
AscDFH.changesFactory[AscDFH.historyitem_Footnotes_SetFootnotePrNumStart]    = CChangesFootnotesSetFootnotePrNumStart;
AscDFH.changesFactory[AscDFH.historyitem_Footnotes_SetFootnotePrNumRestart]  = CChangesFootnotesSetFootnotePrNumRestart;
AscDFH.changesFactory[AscDFH.historyitem_Footnotes_SetFootnotePrNumFormat]   = CChangesFootnotesSetFootnotePrNumFormat;

//----------------------------------------------------------------------------------------------------------------------
// Карта зависимости изменений
//----------------------------------------------------------------------------------------------------------------------
AscDFH.changesRelationMap[AscDFH.historyitem_Footnotes_AddFootnote]              = [AscDFH.historyitem_Footnotes_AddFootnote];
AscDFH.changesRelationMap[AscDFH.historyitem_Footnotes_SetSeparator]             = [AscDFH.historyitem_Footnotes_SetSeparator];
AscDFH.changesRelationMap[AscDFH.historyitem_Footnotes_SetContinuationSeparator] = [AscDFH.historyitem_Footnotes_SetContinuationSeparator];
AscDFH.changesRelationMap[AscDFH.historyitem_Footnotes_SetContinuationNotice]    = [AscDFH.historyitem_Footnotes_SetContinuationNotice];
AscDFH.changesRelationMap[AscDFH.historyitem_Footnotes_SetFootnotePrPos]         = [AscDFH.historyitem_Footnotes_SetFootnotePrPos];
AscDFH.changesRelationMap[AscDFH.historyitem_Footnotes_SetFootnotePrNumStart]    = [AscDFH.historyitem_Footnotes_SetFootnotePrNumStart];
AscDFH.changesRelationMap[AscDFH.historyitem_Footnotes_SetFootnotePrNumRestart]  = [AscDFH.historyitem_Footnotes_SetFootnotePrNumRestart];
AscDFH.changesRelationMap[AscDFH.historyitem_Footnotes_SetFootnotePrNumFormat]   = [AscDFH.historyitem_Footnotes_SetFootnotePrNumFormat];
//----------------------------------------------------------------------------------------------------------------------

/**
 * @constructor
 * @extends {AscDFH.CChangesBase}
 */
function CChangesFootnotesAddFootnote(Class, Id)
{
	AscDFH.CChangesBase.call(this, Class);

	this.Id = Id;
}
CChangesFootnotesAddFootnote.prototype = Object.create(AscDFH.CChangesBase.prototype);
CChangesFootnotesAddFootnote.prototype.constructor = CChangesFootnotesAddFootnote;
CChangesFootnotesAddFootnote.prototype.Type = AscDFH.historyitem_Footnotes_AddFootnote;
CChangesFootnotesAddFootnote.prototype.Undo = function()
{
	delete this.Class.Footnote[this.Id];
};
CChangesFootnotesAddFootnote.prototype.Redo = function()
{
	this.Class.Footnote[this.Id] = AscCommon.g_oTableId.Get_ById(this.Id);
};
CChangesFootnotesAddFootnote.prototype.WriteToBinary = function(Writer)
{
	// String : Id
	Writer.WriteString2(this.Id);
};
CChangesFootnotesAddFootnote.prototype.ReadFromBinary = function(Reader)
{
	// String : Id
	this.Id = Reader.GetString2();
};
CChangesFootnotesAddFootnote.prototype.CreateReverseChange = function()
{
	return null;
};
CChangesFootnotesAddFootnote.prototype.Merge = function(oChange)
{
	if (this.Class !== oChange.Class)
		return true;

	if (this.Type === oChange.Type && this.Id === oChange.Id)
		return false;

	return true;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesFootnotesSetSeparator(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesFootnotesSetSeparator.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesFootnotesSetSeparator.prototype.constructor = CChangesFootnotesSetSeparator;
CChangesFootnotesSetSeparator.prototype.Type = AscDFH.historyitem_Footnotes_SetSeparator;
CChangesFootnotesSetSeparator.prototype.private_SetValue = function(Value)
{
	this.Class.SeparatorFootnote = Value;
};
CChangesFootnotesSetSeparator.prototype.WriteToBinary = function(Writer)
{
	// Long : Flags
	// 1bit : is new undefined?
	// 2bit : is old undefined?
	// String : New id (1 bit zero)
	// String : Old id (2 bit zero)

	var nFlags = 0;
	if (!this.New)
		nFlags |= 1;
	if (!this.Old)
		nFlags |= 2;

	Writer.WriteLong(nFlags);

	if (this.New)
		Writer.WriteString2(this.New.Get_Id());

	if (this.Old)
		Writer.WriteString2(this.Old.Get_Id());
};
CChangesFootnotesSetSeparator.prototype.ReadFromBinary = function(Reader)
{
	// Long : Flags
	// 1bit : is new undefined?
	// 2bit : is old undefined?
	// String : New id (1 bit zero)
	// String : Old id (2 bit zero)

	var nFlags = Reader.GetLong();

	if (nFlags & 1)
		this.New = null;
	else
		this.New = AscCommon.g_oTableId.Get_ById(Reader.GetString2());

	if (nFlags & 2)
		this.New = null;
	else
		this.New = AscCommon.g_oTableId.Get_ById(Reader.GetString2());
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesFootnotesSetContinuationSeparator(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesFootnotesSetContinuationSeparator.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesFootnotesSetContinuationSeparator.prototype.constructor = CChangesFootnotesSetContinuationSeparator;
CChangesFootnotesSetContinuationSeparator.prototype.Type = AscDFH.historyitem_Footnotes_SetContinuationSeparator;
CChangesFootnotesSetContinuationSeparator.prototype.private_SetValue = function(Value)
{
	this.Class.ContinuationSeparatorFootnote = Value;
};
CChangesFootnotesSetContinuationSeparator.prototype.WriteToBinary = CChangesFootnotesSetSeparator.prototype.WriteToBinary;
CChangesFootnotesSetContinuationSeparator.prototype.ReadFromBinary = CChangesFootnotesSetSeparator.prototype.ReadFromBinary;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseProperty}
 */
function CChangesFootnotesSetContinuationNotice(Class, Old, New, Color)
{
	AscDFH.CChangesBaseProperty.call(this, Class, Old, New, Color);
}
CChangesFootnotesSetContinuationNotice.prototype = Object.create(AscDFH.CChangesBaseProperty.prototype);
CChangesFootnotesSetContinuationNotice.prototype.constructor = CChangesFootnotesSetContinuationNotice;
CChangesFootnotesSetContinuationNotice.prototype.Type = AscDFH.historyitem_Footnotes_SetContinuationNotice;
CChangesFootnotesSetContinuationNotice.prototype.private_SetValue = function(Value)
{
	this.Class.ContinuationNoticeFootnote = Value;
};
CChangesFootnotesSetContinuationNotice.prototype.WriteToBinary = CChangesFootnotesSetSeparator.prototype.WriteToBinary;
CChangesFootnotesSetContinuationNotice.prototype.ReadFromBinary = CChangesFootnotesSetSeparator.prototype.ReadFromBinary;
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesFootnotesSetFootnotePrPos(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesFootnotesSetFootnotePrPos.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesFootnotesSetFootnotePrPos.prototype.constructor = CChangesFootnotesSetFootnotePrPos;
CChangesFootnotesSetFootnotePrPos.prototype.Type = AscDFH.historyitem_Footnotes_SetFootnotePrPos;
CChangesFootnotesSetFootnotePrPos.prototype.private_SetValue = function(Value)
{
	this.Class.FootnotePr.Pos = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesFootnotesSetFootnotePrNumStart(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesFootnotesSetFootnotePrNumStart.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesFootnotesSetFootnotePrNumStart.prototype.constructor = CChangesFootnotesSetFootnotePrNumStart;
CChangesFootnotesSetFootnotePrNumStart.prototype.Type = AscDFH.historyitem_Footnotes_SetFootnotePrNumStart;
CChangesFootnotesSetFootnotePrNumStart.prototype.private_SetValue = function(Value)
{
	this.Class.FootnotePr.NumStart = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesFootnotesSetFootnotePrNumRestart(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesFootnotesSetFootnotePrNumRestart.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesFootnotesSetFootnotePrNumRestart.prototype.constructor = CChangesFootnotesSetFootnotePrNumRestart;
CChangesFootnotesSetFootnotePrNumRestart.prototype.Type = AscDFH.historyitem_Footnotes_SetFootnotePrNumRestart;
CChangesFootnotesSetFootnotePrNumRestart.prototype.private_SetValue = function(Value)
{
	this.Class.FootnotePr.NumRestart = Value;
};
/**
 * @constructor
 * @extends {AscDFH.CChangesBaseLongProperty}
 */
function CChangesFootnotesSetFootnotePrNumFormat(Class, Old, New, Color)
{
	AscDFH.CChangesBaseLongProperty.call(this, Class, Old, New, Color);
}
CChangesFootnotesSetFootnotePrNumFormat.prototype = Object.create(AscDFH.CChangesBaseLongProperty.prototype);
CChangesFootnotesSetFootnotePrNumFormat.prototype.constructor = CChangesFootnotesSetFootnotePrNumFormat;
CChangesFootnotesSetFootnotePrNumFormat.prototype.Type = AscDFH.historyitem_Footnotes_SetFootnotePrNumFormat;
CChangesFootnotesSetFootnotePrNumFormat.prototype.private_SetValue = function(Value)
{
	this.Class.FootnotePr.NumFormat = Value;
};

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

/**
 * Класс представляющий сноску в документе.
 * @param {CDocumentControllerBase} DocumentController
 * @constructor
 * @extends {CDocumentContent}
 */
function CFootEndnote(DocumentController)
{
	CDocumentContent.call(this, DocumentController, DocumentController ? DocumentController.Get_DrawingDocument() : undefined, 0, 0, 0, 0, true, false, false);

	this.Number            = 1;
	this.SectPr            = null;
	this.CurtomMarkFollows = false;
	this.NeedUpdateHint    = true;
	this.Hint              = "";

	this.PositionInfo     = {
		Paragraph : null,
		Run       : null,
		Line      : 0,
		Range     : 0,
		X         : 0,
		W         : 0
	};
}

CFootEndnote.prototype = Object.create(CDocumentContent.prototype);
CFootEndnote.prototype.constructor = CFootEndnote;

CFootEndnote.prototype.GetElementPageIndex = function(nPageAbs, nColumnAbs)
{
	// Функция аналогична Document.private_GetElementPageIndex
	var nStartPage    = this.StartPage;
	var nStartColumn  = this.StartColumn;
	var nColumnsCount = this.ColumnsCount;

	return Math.max(0, nColumnAbs - nStartColumn + (nPageAbs - nStartPage) * nColumnsCount);
};
CFootEndnote.prototype.Get_PageContentStartPos = function(nCurPage)
{
	var nPageAbs   = this.Get_AbsolutePage(nCurPage);
	var nColumnAbs = this.Get_AbsoluteColumn(nCurPage);
	return this.Parent.Get_PageContentStartPos(nPageAbs, nColumnAbs);
};
CFootEndnote.prototype.Refresh_RecalcData2 = function(nIndex, nCurPage)
{
	this.Parent.Refresh_RecalcData2(this.Get_AbsolutePage(nCurPage));
};
CFootEndnote.prototype.Write_ToBinary2 = function(Writer)
{
	Writer.WriteLong(AscDFH.historyitem_type_FootEndNote);
	CDocumentContent.prototype.Write_ToBinary2.call(this, Writer);
};
CFootEndnote.prototype.Read_FromBinary2 = function(Reader)
{
	Reader.GetLong(); // Должен вернуть historyitem_type_DocumentContent
	CDocumentContent.prototype.Read_FromBinary2.call(this, Reader);
};
CFootEndnote.prototype.SetNumber = function(nNumber, oSectPr, bCustomMarkFollows)
{
	this.Number            = nNumber;
	this.SectPr            = oSectPr;
	this.CurtomMarkFollows = bCustomMarkFollows;
};
CFootEndnote.prototype.GetNumber = function()
{
	return this.Number;
};
CFootEndnote.prototype.GetReferenceSectPr = function()
{
	return this.SectPr;
};
CFootEndnote.prototype.IsCustomMarkFollows = function()
{
	return this.CurtomMarkFollows;
};
CFootEndnote.prototype.AddDefaultFootnoteContent = function(sText)
{
	var oStyles    = this.LogicDocument.Get_Styles();
	var oParagraph = this.GetElement(0);

	oParagraph.Style_Add(oStyles.GetDefaultFootnoteText());
	var oRun = new ParaRun(oParagraph, false);
	oRun.Set_RStyle(oStyles.GetDefaultFootnoteReference());
	if (sText)
		oRun.AddText(sText);
	else
		oRun.Add_ToContent(0, new ParaFootnoteRef(this));

	oParagraph.Add_ToContent(0, oRun);
	oRun = new ParaRun(oParagraph, false);
	oRun.Add_ToContent(0, new ParaSpace());
	oParagraph.Add_ToContent(1, oRun);

	this.MoveCursorToEndPos(false);
};
CFootEndnote.prototype.Recalculate_Page = function(PageIndex, bStart)
{
	this.NeedUpdateHint = true;
	return CDocumentContent.prototype.Recalculate_Page.call(this, PageIndex, bStart);
};
CFootEndnote.prototype.GetHint = function()
{
	if (true === this.NeedUpdateHint)
	{
		var arrParagraphs = this.GetAllParagraphs({All : true});
		this.Hint         = "";
		for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
		{
			this.Hint += arrParagraphs[nIndex].GetText();
		}

		this.NeedUpdateHint = false;
	}

	return this.Hint;
};
CFootEndnote.prototype.UpdatePositionInfo = function(Paragraph, Run, Line, Range, X, W)
{
	this.PositionInfo.Paragraph = Paragraph;
	this.PositionInfo.Run       = Run;
	this.PositionInfo.Line      = Line;
	this.PositionInfo.Range     = Range;
	this.PositionInfo.X         = X;
	this.PositionInfo.W         = W;
};
CFootEndnote.prototype.GetPositionInfo = function()
{
	return this.PositionInfo;
};
CFootEndnote.prototype.OnFastRecalculate = function()
{
	this.NeedUpdateHint = true;
};
CFootEndnote.prototype.Get_ColumnFields = function(ElementIndex, ColumnIndex)
{
	var PageAbs = this.Get_StartPage_Absolute();
	return this.Parent.GetColumnFields(PageAbs, ColumnIndex);
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CFootEndnote = CFootEndnote;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

// Import
var FontStyle = AscFonts.FontStyle;
var g_fontApplication = AscFonts.g_fontApplication;

var locktype_None = AscCommon.locktype_None;
var locktype_Mine = AscCommon.locktype_Mine;
var locktype_Other = AscCommon.locktype_Other;
var locktype_Other2 = AscCommon.locktype_Other2;
var AscBrowser = AscCommon.AscBrowser;
var CMatrixL = AscCommon.CMatrixL;
var global_MatrixTransformer = AscCommon.global_MatrixTransformer;

function CGraphics()
{
    this.m_oContext     = null;
    this.m_dWidthMM     = 0;
    this.m_dHeightMM    = 0;
    this.m_lWidthPix    = 0;
    this.m_lHeightPix   = 0;
    this.m_dDpiX        = 96.0;
    this.m_dDpiY        = 96.0;
    this.m_bIsBreak 	= false;

    this.m_oPen     = new AscCommon.CPen();
    this.m_oBrush   = new AscCommon.CBrush();

    this.m_oFontManager = null;

    this.m_oCoordTransform  = new CMatrixL();
    this.m_oBaseTransform   = new CMatrixL();
    this.m_oTransform       = new CMatrixL();
    this.m_oFullTransform   = new CMatrixL();
    this.m_oInvertFullTransform = new CMatrixL();

    this.ArrayPoints = null;

    this.m_oCurFont =
    {
        Name        : "",
        FontSize    : 10,
        Bold        : false,
        Italic      : false
    };

    // RFonts
    this.m_oTextPr      = null;
    this.m_oGrFonts     = new AscCommon.CGrRFonts();
    this.m_oLastFont    = new AscCommon.CFontSetup();

    this.LastFontOriginInfo = { Name : "", Replace : null };

    this.m_bIntegerGrid = true;

    this.ClipManager = new AscCommon.CClipManager();
    this.ClipManager.BaseObject = this;

    this.TextureFillTransformScaleX = 1;
    this.TextureFillTransformScaleY = 1;
    this.IsThumbnail = false;

    this.IsDemonstrationMode = false;

    this.GrState = new AscCommon.CGrState();
    this.GrState.Parent = this;

    this.globalAlpha = 1;

    this.TextClipRect = null;
    this.IsClipContext = false;

    this.IsUseFonts2        = false;
    this.m_oFontManager2    = null;
    this.m_oLastFont2       = null;

    this.ClearMode          = false;
    this.IsRetina           = false;

    this.dash_no_smart = null;
}

CGraphics.prototype =
{
    init : function(context,width_px,height_px,width_mm,height_mm)
    {
        this.m_oContext     = context;
        this.m_lHeightPix   = height_px >> 0;
        this.m_lWidthPix    = width_px >> 0;
        this.m_dWidthMM     = width_mm;
        this.m_dHeightMM    = height_mm;
        this.m_dDpiX        = 25.4 * this.m_lWidthPix / this.m_dWidthMM;
        this.m_dDpiY        = 25.4 * this.m_lHeightPix / this.m_dHeightMM;

        this.m_oCoordTransform.sx   = this.m_dDpiX / 25.4;
        this.m_oCoordTransform.sy   = this.m_dDpiY / 25.4;

        this.TextureFillTransformScaleX = 1 / this.m_oCoordTransform.sx;
        this.TextureFillTransformScaleY = 1 / this.m_oCoordTransform.sy;

        /*
        if (this.IsThumbnail)
        {
            this.TextureFillTransformScaleX *= (width_px / (width_mm * g_dKoef_mm_to_pix));
            this.TextureFillTransformScaleY *= (height_px / (height_mm * g_dKoef_mm_to_pix))
        }
        */

        /*
		if (true == this.m_oContext.mozImageSmoothingEnabled)
			this.m_oContext.mozImageSmoothingEnabled = false;
        */

        this.m_oLastFont.Clear();
        this.m_oContext.save();
    },
    EndDraw : function()
    {
    },

    put_GlobalAlpha : function(enable, alpha)
    {
        if (false === enable)
        {
            this.globalAlpha = 1;
            this.m_oContext.globalAlpha = 1;
        }
        else
        {
            this.globalAlpha = alpha;
            this.m_oContext.globalAlpha = alpha;
        }
    },
    Start_GlobalAlpha : function()
    {
    },
    End_GlobalAlpha : function()
    {
        if (false === this.m_bIntegerGrid)
        {
            this.m_oContext.setTransform(1,0,0,1,0,0);
        }

        this.b_color1(255, 255, 255, 140);

        this.m_oContext.fillRect(0, 0, this.m_lWidthPix, this.m_lHeightPix);
        this.m_oContext.beginPath();

        if (false === this.m_bIntegerGrid)
        {
            this.m_oContext.setTransform(this.m_oFullTransform.sx,this.m_oFullTransform.shy,this.m_oFullTransform.shx,
                this.m_oFullTransform.sy,this.m_oFullTransform.tx,this.m_oFullTransform.ty);
        }
    },
    // pen methods
    p_color : function(r,g,b,a)
    {
        var _c = this.m_oPen.Color;
        _c.R = r;
        _c.G = g;
        _c.B = b;
        _c.A = a;

        this.m_oContext.strokeStyle = "rgba(" + _c.R + "," + _c.G + "," + _c.B + "," + (_c.A / 255) + ")";
    },
    p_width : function(w)
    {
        this.m_oPen.LineWidth = w / 1000;

        if (!this.m_bIntegerGrid)
        {
            if (0 != this.m_oPen.LineWidth)
            {
                this.m_oContext.lineWidth = this.m_oPen.LineWidth;
            }
            else
            {
                var _x1 = this.m_oFullTransform.TransformPointX(0, 0);
                var _y1 = this.m_oFullTransform.TransformPointY(0, 0);
                var _x2 = this.m_oFullTransform.TransformPointX(1, 1);
                var _y2 = this.m_oFullTransform.TransformPointY(1, 1);

                var _koef = Math.sqrt(((_x2 - _x1)*(_x2 - _x1) + (_y2 - _y1)*(_y2 - _y1)) / 2);
                this.m_oContext.lineWidth = 1 / _koef;
            }
        }
        else
        {
            if (0 != this.m_oPen.LineWidth)
            {
                var _m = this.m_oFullTransform;
                var x = _m.sx + _m.shx;
                var y = _m.sy + _m.shy;

                var koef = Math.sqrt((x * x + y * y) / 2);
                this.m_oContext.lineWidth = this.m_oPen.LineWidth * koef;
            }
            else
            {
                this.m_oContext.lineWidth = 1;
            }
        }
    },

    p_dash : function(params)
    {
        if (!this.m_oContext.setLineDash)
            return;

	    this.dash_no_smart = params ? params.slice() : null;
        this.m_oContext.setLineDash(params ? params : []);
    },

    // brush methods
    b_color1 : function(r,g,b,a)
    {
        var _c = this.m_oBrush.Color1;
        _c.R = r;
        _c.G = g;
        _c.B = b;
        _c.A = a;

        this.m_oContext.fillStyle = "rgba(" + _c.R + "," + _c.G + "," + _c.B + "," + (_c.A / 255) + ")";
    },
    b_color2 : function(r,g,b,a)
    {
        var _c = this.m_oBrush.Color2;
        _c.R = r;
        _c.G = g;
        _c.B = b;
        _c.A = a;
    },

    transform : function(sx,shy,shx,sy,tx,ty)
    {
        var _t = this.m_oTransform;
        _t.sx    = sx;
        _t.shx   = shx;
        _t.shy   = shy;
        _t.sy    = sy;
        _t.tx    = tx;
        _t.ty    = ty;

        this.CalculateFullTransform();
        if (false === this.m_bIntegerGrid)
        {
            var _ft = this.m_oFullTransform;
            this.m_oContext.setTransform(_ft.sx,_ft.shy,_ft.shx,_ft.sy,_ft.tx,_ft.ty);
        }

        if (null != this.m_oFontManager)
        {
            this.m_oFontManager.SetTextMatrix(_t.sx,_t.shy,_t.shx,_t.sy,_t.tx,_t.ty);
        }
    },
    CalculateFullTransform : function(isInvertNeed)
    {
        var _ft = this.m_oFullTransform;
        var _t = this.m_oTransform;
        _ft.sx = _t.sx;
        _ft.shx = _t.shx;
        _ft.shy = _t.shy;
        _ft.sy = _t.sy;
        _ft.tx = _t.tx;
        _ft.ty = _t.ty;
        global_MatrixTransformer.MultiplyAppend(_ft, this.m_oCoordTransform);

        var _it = this.m_oInvertFullTransform;
        _it.sx = _ft.sx;
        _it.shx = _ft.shx;
        _it.shy = _ft.shy;
        _it.sy = _ft.sy;
        _it.tx = _ft.tx;
        _it.ty = _ft.ty;

        if (false !== isInvertNeed)
        {
            global_MatrixTransformer.MultiplyAppendInvert(_it, _t);
        }
    },
    // path commands
    _s : function()
    {
        this.m_oContext.beginPath();
    },
    _e : function()
    {
        this.m_oContext.beginPath();
    },
    _z : function()
    {
        this.m_oContext.closePath();
    },
    _m : function(x,y)
    {
        if (false === this.m_bIntegerGrid)
        {
            this.m_oContext.moveTo(x,y);

            if (this.ArrayPoints != null)
                this.ArrayPoints[this.ArrayPoints.length] = {x: x, y: y};
        }
        else
        {
            var _x = (this.m_oFullTransform.TransformPointX(x,y)) >> 0;
            var _y = (this.m_oFullTransform.TransformPointY(x,y)) >> 0;
            this.m_oContext.moveTo(_x + 0.5,_y + 0.5);
        }
    },
    _l : function(x,y)
    {
        if (false === this.m_bIntegerGrid)
        {
            this.m_oContext.lineTo(x,y);

            if (this.ArrayPoints != null)
                this.ArrayPoints[this.ArrayPoints.length] = {x: x, y: y};
        }
        else
        {
            var _x = (this.m_oFullTransform.TransformPointX(x,y)) >> 0;
            var _y = (this.m_oFullTransform.TransformPointY(x,y)) >> 0;
            this.m_oContext.lineTo(_x + 0.5,_y + 0.5);
        }
    },
    _c : function(x1,y1,x2,y2,x3,y3)
    {
        if (false === this.m_bIntegerGrid)
        {
            this.m_oContext.bezierCurveTo(x1,y1,x2,y2,x3,y3);

            if (this.ArrayPoints != null)
            {
                this.ArrayPoints[this.ArrayPoints.length] = {x: x1, y: y1};
                this.ArrayPoints[this.ArrayPoints.length] = {x: x2, y: y2};
                this.ArrayPoints[this.ArrayPoints.length] = {x: x3, y: y3};
            }
        }
        else
        {
            var _x1 = (this.m_oFullTransform.TransformPointX(x1,y1)) >> 0;
            var _y1 = (this.m_oFullTransform.TransformPointY(x1,y1)) >> 0;

            var _x2 = (this.m_oFullTransform.TransformPointX(x2,y2)) >> 0;
            var _y2 = (this.m_oFullTransform.TransformPointY(x2,y2)) >> 0;

            var _x3 = (this.m_oFullTransform.TransformPointX(x3,y3)) >> 0;
            var _y3 = (this.m_oFullTransform.TransformPointY(x3,y3)) >> 0;
            this.m_oContext.bezierCurveTo(_x1 + 0.5,_y1 + 0.5,_x2 + 0.5,_y2 + 0.5,_x3 + 0.5,_y3 + 0.5);
        }
    },
    _c2 : function(x1,y1,x2,y2)
    {
         if (false === this.m_bIntegerGrid)
         {
             this.m_oContext.quadraticCurveTo(x1,y1,x2,y2);

             if (this.ArrayPoints != null)
             {
                 this.ArrayPoints[this.ArrayPoints.length] = {x: x1, y: y1};
                 this.ArrayPoints[this.ArrayPoints.length] = {x: x2, y: y2};
             }
         }
        else
        {
            var _x1 = (this.m_oFullTransform.TransformPointX(x1,y1)) >> 0;
            var _y1 = (this.m_oFullTransform.TransformPointY(x1,y1)) >> 0;

            var _x2 = (this.m_oFullTransform.TransformPointX(x2,y2)) >> 0;
            var _y2 = (this.m_oFullTransform.TransformPointY(x2,y2)) >> 0;

            this.m_oContext.quadraticCurveTo(_x1 + 0.5,_y1 + 0.5,_x2 + 0.5,_y2 + 0.5);
        }
    },
    ds : function()
    {
        this.m_oContext.stroke();
    },
    df : function()
    {
        this.m_oContext.fill();
    },

    // canvas state
    save : function()
    {
        this.m_oContext.save();
    },
    restore : function()
    {
        this.m_oContext.restore();
    },
    clip : function()
    {
        this.m_oContext.clip();
    },

    reset : function()
    {
        this.m_oTransform.Reset();
        this.CalculateFullTransform(false);

        if (!this.m_bIntegerGrid)
            this.m_oContext.setTransform(this.m_oCoordTransform.sx,0,0,this.m_oCoordTransform.sy,0, 0);
    },

    transform3 : function(m, isNeedInvert)
    {
        var _t = this.m_oTransform;
        _t.sx = m.sx;
        _t.shx = m.shx;
        _t.shy = m.shy;
        _t.sy = m.sy;
        _t.tx = m.tx;
        _t.ty = m.ty;
        this.CalculateFullTransform(isNeedInvert);

        if (!this.m_bIntegerGrid)
        {
            var _ft = this.m_oFullTransform;
            this.m_oContext.setTransform(_ft.sx,_ft.shy,_ft.shx,_ft.sy,_ft.tx,_ft.ty);
        }
        else
        {
            this.SetIntegerGrid(false);
        }

        // теперь трансформ выставляется ТОЛЬКО при загрузке шрифта. Здесь другого быть и не может
        /*
        if (null != this.m_oFontManager && false !== isNeedInvert)
        {
		    this.m_oFontManager.SetTextMatrix(this.m_oTransform.sx,this.m_oTransform.shy,this.m_oTransform.shx,
                this.m_oTransform.sy,this.m_oTransform.tx,this.m_oTransform.ty);
        }
        */
    },

    FreeFont : function()
    {
        // это чтобы не сбросился кэш при отрисовке следующего шейпа
        this.m_oFontManager.m_pFont = null;
    },

    ClearLastFont : function()
    {
        this.m_oLastFont    = new AscCommon.CFontSetup();
        this.m_oLastFont2   = null;
    },

    // images
    drawImage2 : function(img,x,y,w,h,alpha,srcRect)
    {
        var isA = (undefined !== alpha && null != alpha && 255 != alpha);
        var _oldGA = 0;
        if (isA)
        {
            _oldGA = this.m_oContext.globalAlpha;
            this.m_oContext.globalAlpha = alpha / 255;
        }

        if (false === this.m_bIntegerGrid)
        {
            if (!srcRect)
            {
                // тут нужно проверить, можно ли нарисовать точно. т.е. может картинка ровно такая, какая нужна.
                if (!global_MatrixTransformer.IsIdentity2(this.m_oTransform))
                {
                    this.m_oContext.drawImage(img,x,y,w,h);
                }
                else
                {
                    var xx = this.m_oFullTransform.TransformPointX(x, y);
                    var yy = this.m_oFullTransform.TransformPointY(x, y);
                    var rr = this.m_oFullTransform.TransformPointX(x + w, y + h);
                    var bb = this.m_oFullTransform.TransformPointY(x + w, y + h);
                    var ww = rr - xx;
                    var hh = bb - yy;

                    if (Math.abs(img.width - ww) < 2 && Math.abs(img.height - hh) < 2)
                    {
                        // рисуем точно
                        this.m_oContext.setTransform(1, 0, 0, 1, 0, 0);
                        this.m_oContext.drawImage(img, xx >> 0, yy >> 0);

                        var _ft = this.m_oFullTransform;
                        this.m_oContext.setTransform(_ft.sx,_ft.shy,_ft.shx,_ft.sy,_ft.tx,_ft.ty);

                    }
                    else
                    {
                        this.m_oContext.drawImage(img,x,y,w,h);
                    }
                }
            }
            else
            {
                var _w = img.width;
                var _h = img.height;
                if (_w > 0 && _h > 0)
                {
                    var __w = w;
                    var __h = h;
                    var _delW = Math.max(0, -srcRect.l) + Math.max(0, srcRect.r - 100) + 100;
                    var _delH = Math.max(0, -srcRect.t) + Math.max(0, srcRect.b - 100) + 100;

                    var _sx = 0;
                    if (srcRect.l > 0 && srcRect.l < 100)
                        _sx = Math.min((_w * srcRect.l / 100) >> 0, _w - 1);
                    else if (srcRect.l < 0)
                    {
                        var _off = ((-srcRect.l / _delW) * __w);
                        x += _off;
                        w -= _off;
                    }
                    var _sy = 0;
                    if (srcRect.t > 0 && srcRect.t < 100)
                        _sy = Math.min((_h * srcRect.t / 100) >> 0, _h - 1);
                    else if (srcRect.t < 0)
                    {
                        var _off = ((-srcRect.t / _delH) * __h);
                        y += _off;
                        h -= _off;
                    }
                    var _sr = _w;
                    if (srcRect.r > 0 && srcRect.r < 100)
                        _sr = Math.max(Math.min((_w * srcRect.r / 100) >> 0, _w - 1), _sx);
                    else if (srcRect.r > 100)
                    {
                        var _off = ((srcRect.r - 100) / _delW) * __w;
                        w -= _off;
                    }
                    var _sb = _h;
                    if (srcRect.b > 0 && srcRect.b < 100)
                        _sb = Math.max(Math.min((_h * srcRect.b / 100) >> 0, _h - 1), _sy);
                    else if (srcRect.b > 100)
                    {
                        var _off = ((srcRect.b - 100) / _delH) * __h;
                        h -= _off;
                    }

                    if ((_sr-_sx) > 0 && (_sb-_sy) > 0 && w > 0 && h > 0)
                        this.m_oContext.drawImage(img,_sx,_sy,_sr-_sx,_sb-_sy,x,y,w,h);
                }
                else
                {
                    this.m_oContext.drawImage(img,x,y,w,h);
                }
            }
        }
        else
        {
            var _x1 = (this.m_oFullTransform.TransformPointX(x,y)) >> 0;
            var _y1 = (this.m_oFullTransform.TransformPointY(x,y)) >> 0;
            var _x2 = (this.m_oFullTransform.TransformPointX(x+w,y+h)) >> 0;
            var _y2 = (this.m_oFullTransform.TransformPointY(x+w,y+h)) >> 0;

            x = _x1;
            y = _y1;
            w = _x2 - _x1;
            h = _y2 - _y1;

            if (!srcRect)
            {
                // тут нужно проверить, можно ли нарисовать точно. т.е. может картинка ровно такая, какая нужна.
                if (!global_MatrixTransformer.IsIdentity2(this.m_oTransform))
                {
                    this.m_oContext.drawImage(img,_x1,_y1,w,h);
                }
                else
                {
                    if (Math.abs(img.width - w) < 2 && Math.abs(img.height - h) < 2)
                    {
                        // рисуем точно
                        this.m_oContext.drawImage(img, x, y);
                    }
                    else
                    {
                        this.m_oContext.drawImage(img,_x1,_y1,w,h);
                    }
                }
            }
            else
            {
                var _w = img.width;
                var _h = img.height;
                if (_w > 0 && _h > 0)
                {
                    var __w = w;
                    var __h = h;
                    var _delW = Math.max(0, -srcRect.l) + Math.max(0, srcRect.r - 100) + 100;
                    var _delH = Math.max(0, -srcRect.t) + Math.max(0, srcRect.b - 100) + 100;

                    var _sx = 0;
                    if (srcRect.l > 0 && srcRect.l < 100)
                        _sx = Math.min((_w * srcRect.l / 100) >> 0, _w - 1);
                    else if (srcRect.l < 0)
                    {
                        var _off = ((-srcRect.l / _delW) * __w);
                        x += _off;
                        w -= _off;
                    }
                    var _sy = 0;
                    if (srcRect.t > 0 && srcRect.t < 100)
                        _sy = Math.min((_h * srcRect.t / 100) >> 0, _h - 1);
                    else if (srcRect.t < 0)
                    {
                        var _off = ((-srcRect.t / _delH) * __h);
                        y += _off;
                        h -= _off;
                    }
                    var _sr = _w;
                    if (srcRect.r > 0 && srcRect.r < 100)
                        _sr = Math.max(Math.min((_w * srcRect.r / 100) >> 0, _w - 1), _sx);
                    else if (srcRect.r > 100)
                    {
                        var _off = ((srcRect.r - 100) / _delW) * __w;
                        w -= _off;
                    }
                    var _sb = _h;
                    if (srcRect.b > 0 && srcRect.b < 100)
                        _sb = Math.max(Math.min((_h * srcRect.b / 100) >> 0, _h - 1), _sy);
                    else if (srcRect.b > 100)
                    {
                        var _off = ((srcRect.b - 100) / _delH) * __h;
                        h -= _off;
                    }

                    if ((_sr-_sx) > 0 && (_sb-_sy) > 0 && w > 0 && h > 0)
                        this.m_oContext.drawImage(img,_sx,_sy,_sr-_sx,_sb-_sy,x,y,w,h);
                }
                else
                {
                    this.m_oContext.drawImage(img,x,y,w,h);
                }
            }
        }

        if (isA)
        {
            this.m_oContext.globalAlpha = _oldGA;
        }
    },
    drawImage : function(img,x,y,w,h,alpha,srcRect,nativeImage)
    {
        if (nativeImage)
        {
            this.drawImage2(nativeImage,x,y,w,h,alpha,srcRect);
            return;
        }

        var _img = editor.ImageLoader.map_image_index[img];
        if (_img != undefined && _img.Status == AscFonts.ImageLoadStatus.Loading)
        {
            // TODO: IMAGE_LOADING
        }
        else if (_img != undefined && _img.Image != null)
        {
            this.drawImage2(_img.Image,x,y,w,h,alpha,srcRect);
        }
        else
        {
            var _x = x;
            var _y = y;
            var _r = x+w;
            var _b = y+h;

            var ctx = this.m_oContext;
            var old_p = ctx.lineWidth;

            var bIsNoIntGrid = false;

            if (this.m_bIntegerGrid)
            {
                _x = (this.m_oFullTransform.TransformPointX(x,y) >> 0) + 0.5;
                _y = (this.m_oFullTransform.TransformPointY(x,y) >> 0) + 0.5;
                _r = (this.m_oFullTransform.TransformPointX(x+w,y+h) >> 0) + 0.5;
                _b = (this.m_oFullTransform.TransformPointY(x+w,y+h) >> 0) + 0.5;

                ctx.lineWidth = 1;
            }
            else
            {
                if (global_MatrixTransformer.IsIdentity2(this.m_oTransform))
                {
                    bIsNoIntGrid = true;

                    this.SetIntegerGrid(true);
                    _x = (this.m_oFullTransform.TransformPointX(x,y) >> 0) + 0.5;
                    _y = (this.m_oFullTransform.TransformPointY(x,y) >> 0) + 0.5;
                    _r = (this.m_oFullTransform.TransformPointX(x+w,y+h) >> 0) + 0.5;
                    _b = (this.m_oFullTransform.TransformPointY(x+w,y+h) >> 0) + 0.5;

                    ctx.lineWidth = 1;
                }
                else
                {
                    ctx.lineWidth = 1 / this.m_oCoordTransform.sx;
                }
            }

            //ctx.strokeStyle = "#FF0000";
            ctx.strokeStyle = "#F98C76";

            ctx.beginPath();
            ctx.moveTo(_x,_y);
            ctx.lineTo(_r,_b);
            ctx.moveTo(_r,_y);
            ctx.lineTo(_x,_b);
            ctx.stroke();

            ctx.beginPath();
            ctx.moveTo(_x,_y);
            ctx.lineTo(_r,_y);
            ctx.lineTo(_r,_b);
            ctx.lineTo(_x,_b);
            ctx.closePath();

            ctx.stroke();
            ctx.beginPath();

            if (bIsNoIntGrid)
                this.SetIntegerGrid(false);

            ctx.lineWidth = old_p;
            ctx.strokeStyle = "rgba(" + this.m_oPen.Color.R + "," + this.m_oPen.Color.G + "," +
                this.m_oPen.Color.B + "," + (this.m_oPen.Color.A / 255) + ")";
        }
    },

    // text
    GetFont : function()
    {
        return this.m_oCurFont;
    },
    font : function(font_id,font_size)
    {
        AscFonts.g_font_infos[AscFonts.g_map_font_index[font_id]].LoadFont(editor.FontLoader, this.IsUseFonts2 ? this.m_oFontManager2 : this.m_oFontManager,
            Math.max(font_size, 1), 0, this.m_dDpiX, this.m_dDpiY, this.m_oTransform);
    },
    SetFont : function(font)
    {
        if (null == font)
            return;

        this.m_oCurFont.Name        = font.FontFamily.Name;
        this.m_oCurFont.FontSize    = font.FontSize;
        this.m_oCurFont.Bold        = font.Bold;
        this.m_oCurFont.Italic      = font.Italic;

        var bItalic = true === font.Italic;
        var bBold   = true === font.Bold;

        var oFontStyle = FontStyle.FontStyleRegular;
        if ( !bItalic && bBold )
            oFontStyle = FontStyle.FontStyleBold;
        else if ( bItalic && !bBold )
            oFontStyle = FontStyle.FontStyleItalic;
        else if ( bItalic && bBold )
            oFontStyle = FontStyle.FontStyleBoldItalic;

        var _last_font = this.IsUseFonts2 ? this.m_oLastFont2 : this.m_oLastFont;
        var _font_manager = this.IsUseFonts2 ? this.m_oFontManager2 : this.m_oFontManager;

        _last_font.SetUpName = font.FontFamily.Name;
        _last_font.SetUpSize = font.FontSize;
        _last_font.SetUpStyle = oFontStyle;

        g_fontApplication.LoadFont(_last_font.SetUpName, AscCommon.g_font_loader, _font_manager, font.FontSize, oFontStyle, this.m_dDpiX, this.m_dDpiY, this.m_oTransform, this.LastFontOriginInfo);

        var _mD = _last_font.SetUpMatrix;
        var _mS = this.m_oTransform;

        _mD.sx = _mS.sx;
        _mD.sy = _mS.sy;
        _mD.shx = _mS.shx;
        _mD.shy = _mS.shy;
        _mD.tx = _mS.tx;
        _mD.ty = _mS.ty;

        //_font_manager.SetTextMatrix(this.m_oTransform.sx,this.m_oTransform.shy,this.m_oTransform.shx,
        //    this.m_oTransform.sy,this.m_oTransform.tx,this.m_oTransform.ty);
    },

    SetTextPr : function(textPr, theme)
    {
        this.m_oTextPr = textPr;
        if (theme)
            this.m_oGrFonts.checkFromTheme(theme.themeElements.fontScheme, this.m_oTextPr.RFonts);
        else
            this.m_oGrFonts = this.m_oTextPr.RFonts;
    },

    SetFontSlot : function(slot, fontSizeKoef)
    {
        var _rfonts = this.m_oGrFonts;
        var _lastFont = this.IsUseFonts2 ? this.m_oLastFont2 : this.m_oLastFont;

        switch (slot)
        {
            case fontslot_ASCII:
            {
                _lastFont.Name   = _rfonts.Ascii.Name;
                _lastFont.Size = this.m_oTextPr.FontSize;
                _lastFont.Bold = this.m_oTextPr.Bold;
                _lastFont.Italic = this.m_oTextPr.Italic;

                break;
            }
            case fontslot_CS:
            {
                _lastFont.Name   = _rfonts.CS.Name;
                _lastFont.Size = this.m_oTextPr.FontSizeCS;
                _lastFont.Bold = this.m_oTextPr.BoldCS;
                _lastFont.Italic = this.m_oTextPr.ItalicCS;

                break;
            }
            case fontslot_EastAsia:
            {
                _lastFont.Name   = _rfonts.EastAsia.Name;
                _lastFont.Size = this.m_oTextPr.FontSize;
                _lastFont.Bold = this.m_oTextPr.Bold;
                _lastFont.Italic = this.m_oTextPr.Italic;

                break;
            }
            case fontslot_HAnsi:
            default:
            {
                _lastFont.Name   = _rfonts.HAnsi.Name;
                _lastFont.Size = this.m_oTextPr.FontSize;
                _lastFont.Bold = this.m_oTextPr.Bold;
                _lastFont.Italic = this.m_oTextPr.Italic;

                break;
            }
        }

        if (undefined !== fontSizeKoef)
            _lastFont.Size *= fontSizeKoef;

        var _style = 0;
        if (_lastFont.Italic)
            _style += 2;
        if (_lastFont.Bold)
            _style += 1;

        var _font_manager = this.IsUseFonts2 ? this.m_oFontManager2 : this.m_oFontManager;

        if (_lastFont.Name != _lastFont.SetUpName || _lastFont.Size != _lastFont.SetUpSize || _style != _lastFont.SetUpStyle || !_font_manager.m_pFont)
        {
            _lastFont.SetUpName = _lastFont.Name;
            _lastFont.SetUpSize = _lastFont.Size;
            _lastFont.SetUpStyle = _style;

            g_fontApplication.LoadFont(_lastFont.SetUpName, AscCommon.g_font_loader, _font_manager, _lastFont.SetUpSize, _lastFont.SetUpStyle, this.m_dDpiX, this.m_dDpiY, this.m_oTransform, this.LastFontOriginInfo);

            var _mD = _lastFont.SetUpMatrix;
            var _mS = this.m_oTransform;
            _mD.sx = _mS.sx;
            _mD.sy = _mS.sy;
            _mD.shx = _mS.shx;
            _mD.shy = _mS.shy;
            _mD.tx = _mS.tx;
            _mD.ty = _mS.ty;
        }
        else
        {
            var _mD = _lastFont.SetUpMatrix;
            var _mS = this.m_oTransform;

            if (_mD.sx != _mS.sx || _mD.sy != _mS.sy || _mD.shx != _mS.shx || _mD.shy != _mS.shy || _mD.tx != _mS.tx || _mD.ty != _mS.ty)
            {
                _mD.sx = _mS.sx;
                _mD.sy = _mS.sy;
                _mD.shx = _mS.shx;
                _mD.shy = _mS.shy;
                _mD.tx = _mS.tx;
                _mD.ty = _mS.ty;

                _font_manager.SetTextMatrix(_mD.sx,_mD.shy,_mD.shx,_mD.sy,_mD.tx,_mD.ty);
            }
        }

        //_font_manager.SetTextMatrix(this.m_oTransform.sx,this.m_oTransform.shy,this.m_oTransform.shx,
        //    this.m_oTransform.sy,this.m_oTransform.tx,this.m_oTransform.ty);
    },

    GetTextPr : function()
    {
        return this.m_oTextPr;
    },

    FillText : function(x,y,text)
    {
        // убыстеренный вариант. здесь везде заточка на то, что приходит одна буква
        if (this.m_bIsBreak)
            return;

        var _x = this.m_oInvertFullTransform.TransformPointX(x,y);
        var _y = this.m_oInvertFullTransform.TransformPointY(x,y);

        var _font_manager = this.IsUseFonts2 ? this.m_oFontManager2 : this.m_oFontManager;

        try
        {
            var _code = text.charCodeAt(0);

            if (null != this.LastFontOriginInfo.Replace)
                _code = g_fontApplication.GetReplaceGlyph(_code, this.LastFontOriginInfo.Replace);

            _font_manager.LoadString4C(_code,_x,_y);
        }
        catch(err)
        {
        }

        if (false === this.m_bIntegerGrid)
        {
            this.m_oContext.setTransform(1,0,0,1,0,0);
        }
        var pGlyph = _font_manager.m_oGlyphString.m_pGlyphsBuffer[0];
        if (null == pGlyph)
            return;

        if (null != pGlyph.oBitmap)
        {
            this.private_FillGlyph(pGlyph);
        }
        if (false === this.m_bIntegerGrid)
        {
            this.m_oContext.setTransform(this.m_oFullTransform.sx,this.m_oFullTransform.shy,this.m_oFullTransform.shx,
                this.m_oFullTransform.sy,this.m_oFullTransform.tx,this.m_oFullTransform.ty);
        }
    },
    t : function(text,x,y,isBounds)
    {
		if (this.m_bIsBreak)
			return;

		var _x = this.m_oInvertFullTransform.TransformPointX(x,y);
		var _y = this.m_oInvertFullTransform.TransformPointY(x,y);

        var _font_manager = this.IsUseFonts2 ? this.m_oFontManager2 : this.m_oFontManager;

		try
		{
			_font_manager.LoadString2(text,_x,_y);
		}
		catch(err)
		{
		}

	    this.m_oContext.setTransform(1,0,0,1,0,0);
		var _bounds = isBounds ? {x:100000, y:100000, r:-100000, b:-100000} : null;
        while (true)
        {
            var pGlyph = _font_manager.GetNextChar2();
            if (null == pGlyph)
                break;

            if (null != pGlyph.oBitmap)
            {
                this.private_FillGlyph(pGlyph, _bounds);
            }
        }
        if (false === this.m_bIntegerGrid)
        {
            this.m_oContext.setTransform(this.m_oFullTransform.sx,this.m_oFullTransform.shy,this.m_oFullTransform.shx,
                this.m_oFullTransform.sy,this.m_oFullTransform.tx,this.m_oFullTransform.ty);
        }

        return _bounds;
    },
    FillText2 : function(x,y,text,cropX,cropW)
    {
        // убыстеренный вариант. здесь везде заточка на то, что приходит одна буква
        if (this.m_bIsBreak)
            return;

        var _x = this.m_oInvertFullTransform.TransformPointX(x,y);
        var _y = this.m_oInvertFullTransform.TransformPointY(x,y);

        var _font_manager = this.IsUseFonts2 ? this.m_oFontManager2 : this.m_oFontManager;

        try
        {
            var _code = text.charCodeAt(0);

            if (null != this.LastFontOriginInfo.Replace)
                _code = g_fontApplication.GetReplaceGlyph(_code, this.LastFontOriginInfo.Replace);

            _font_manager.LoadString4C(_code,_x,_y);
        }
        catch(err)
        {
        }

        this.m_oContext.setTransform(1,0,0,1,0,0);
        var pGlyph = _font_manager.m_oGlyphString.m_pGlyphsBuffer[0];
        if (null == pGlyph)
            return;

        if (null != pGlyph.oBitmap)
        {
            this.private_FillGlyphC(pGlyph,cropX,cropW);
        }
        if (false === this.m_bIntegerGrid)
        {
            this.m_oContext.setTransform(this.m_oFullTransform.sx,this.m_oFullTransform.shy,this.m_oFullTransform.shx,
                this.m_oFullTransform.sy,this.m_oFullTransform.tx,this.m_oFullTransform.ty);
        }
    },
    t2 : function(text,x,y,cropX,cropW)
    {
        if (this.m_bIsBreak)
            return;

        var _x = this.m_oInvertFullTransform.TransformPointX(x,y);
        var _y = this.m_oInvertFullTransform.TransformPointY(x,y);

        var _font_manager = this.IsUseFonts2 ? this.m_oFontManager2 : this.m_oFontManager;

        try
        {
            _font_manager.LoadString2(text,_x,_y);
        }
        catch(err)
        {
        }

        this.m_oContext.setTransform(1,0,0,1,0,0);
        while (true)
        {
            var pGlyph = _font_manager.GetNextChar2();
            if (null == pGlyph)
                break;

            if (null != pGlyph.oBitmap)
            {
                this.private_FillGlyphC(pGlyph,cropX,cropW);
            }
        }

        if (false === this.m_bIntegerGrid)
        {
            this.m_oContext.setTransform(this.m_oFullTransform.sx,this.m_oFullTransform.shy,this.m_oFullTransform.shx,
                this.m_oFullTransform.sy,this.m_oFullTransform.tx,this.m_oFullTransform.ty);
        }
    },
    FillTextCode : function(x,y,lUnicode)
    {
        // убыстеренный вариант. здесь везде заточка на то, что приходит одна буква
        if (this.m_bIsBreak)
            return;

        var _x = this.m_oInvertFullTransform.TransformPointX(x,y);
        var _y = this.m_oInvertFullTransform.TransformPointY(x,y);

        var _font_manager = this.IsUseFonts2 ? this.m_oFontManager2 : this.m_oFontManager;

        try
        {
            if (null != this.LastFontOriginInfo.Replace)
                lUnicode = g_fontApplication.GetReplaceGlyph(lUnicode, this.LastFontOriginInfo.Replace);

            _font_manager.LoadString4C(lUnicode,_x,_y);
        }
        catch(err)
        {
        }

        if (false === this.m_bIntegerGrid)
        {
            this.m_oContext.setTransform(1,0,0,1,0,0);
        }
        var pGlyph = _font_manager.m_oGlyphString.m_pGlyphsBuffer[0];
        if (null == pGlyph)
            return;

        if (null != pGlyph.oBitmap)
        {
            this.private_FillGlyph(pGlyph);
        }
        if (false === this.m_bIntegerGrid)
        {
            this.m_oContext.setTransform(this.m_oFullTransform.sx,this.m_oFullTransform.shy,this.m_oFullTransform.shx,
                this.m_oFullTransform.sy,this.m_oFullTransform.tx,this.m_oFullTransform.ty);
        }
    },

    tg : function(text,x,y)
    {
        if (this.m_bIsBreak)
            return;

        var _x = this.m_oInvertFullTransform.TransformPointX(x,y);
        var _y = this.m_oInvertFullTransform.TransformPointY(x,y);

        var _font_manager = this.IsUseFonts2 ? this.m_oFontManager2 : this.m_oFontManager;

        try
        {
            _font_manager.LoadString3C(text,_x,_y);
        }
        catch(err)
        {
        }

        if (false === this.m_bIntegerGrid)
        {
            this.m_oContext.setTransform(1,0,0,1,0,0);
        }
        var pGlyph = _font_manager.m_oGlyphString.m_pGlyphsBuffer[0];
        if (null == pGlyph)
            return;

        if (null != pGlyph.oBitmap)
        {
            var _a = this.m_oBrush.Color1.A;
            if (255 != _a)
                this.m_oContext.globalAlpha = _a / 255;
            this.private_FillGlyph(pGlyph);

            if (255 != _a)
                this.m_oContext.globalAlpha = 1.0;
        }
        if (false === this.m_bIntegerGrid)
        {
            this.m_oContext.setTransform(this.m_oFullTransform.sx,this.m_oFullTransform.shy,this.m_oFullTransform.shx,
                this.m_oFullTransform.sy,this.m_oFullTransform.tx,this.m_oFullTransform.ty);
        }
    },
    charspace : function(space)
    {
    },

    // private methods
    private_FillGlyph : function(pGlyph, _bounds)
    {
        // new scheme
        var nW = pGlyph.oBitmap.nWidth;
        var nH = pGlyph.oBitmap.nHeight;

        if (0 == nW || 0 == nH)
            return;

        var _font_manager = this.IsUseFonts2 ? this.m_oFontManager2 : this.m_oFontManager;

		var nX = (_font_manager.m_oGlyphString.m_fX >> 0) + (pGlyph.fX + pGlyph.oBitmap.nX) >> 0;
		var nY = (_font_manager.m_oGlyphString.m_fY >> 0) + (pGlyph.fY - pGlyph.oBitmap.nY) >> 0;

        pGlyph.oBitmap.oGlyphData.checkColor(this.m_oBrush.Color1.R,this.m_oBrush.Color1.G,this.m_oBrush.Color1.B,nW,nH);

        if (null == this.TextClipRect)
            pGlyph.oBitmap.draw(this.m_oContext, nX, nY, this.TextClipRect);
        else
            pGlyph.oBitmap.drawCropInRect(this.m_oContext, nX, nY, this.TextClipRect);

        if (_bounds)
        {
            var _r = nX + pGlyph.oBitmap.nWidth;
            var _b = nY + pGlyph.oBitmap.nHeight;
            if (_bounds.x > nX)
                _bounds.x = nX;
			if (_bounds.y > nY)
				_bounds.y = nY;
			if (_bounds.r < _r)
				_bounds.r = _r;
			if (_bounds.b < _b)
				_bounds.b = _b;
        }
    },
    private_FillGlyphC : function(pGlyph,cropX,cropW)
    {
        // new scheme
        var nW = pGlyph.oBitmap.nWidth;
        var nH = pGlyph.oBitmap.nHeight;

        if (0 == nW || 0 == nH)
            return;

        var _font_manager = this.IsUseFonts2 ? this.m_oFontManager2 : this.m_oFontManager;

        var nX = (_font_manager.m_oGlyphString.m_fX + pGlyph.fX + pGlyph.oBitmap.nX) >> 0;
        var nY = (_font_manager.m_oGlyphString.m_fY + pGlyph.fY - pGlyph.oBitmap.nY) >> 0;

        var d_koef = this.m_dDpiX / 25.4;

        var cX = Math.max((cropX * d_koef) >> 0, 0);
        var cW = Math.min((cropW * d_koef) >> 0, nW);
        if (cW <= 0)
            cW = 1;

        pGlyph.oBitmap.oGlyphData.checkColor(this.m_oBrush.Color1.R,this.m_oBrush.Color1.G,this.m_oBrush.Color1.B,nW,nH);
        pGlyph.oBitmap.drawCrop(this.m_oContext, nX, nY, cW, nH, cX);
    },

    private_FillGlyph2 : function(pGlyph)
    {
        var i = 0;
        var j = 0;

        var nW = pGlyph.oBitmap.nWidth;
        var nH = pGlyph.oBitmap.nHeight;

        if (0 == nW || 0 == nH)
            return;

        var _font_manager = this.IsUseFonts2 ? this.m_oFontManager2 : this.m_oFontManager;

        var nX = (_font_manager.m_oGlyphString.m_fX + pGlyph.fX + pGlyph.oBitmap.nX) >> 0;
        var nY = (_font_manager.m_oGlyphString.m_fY + pGlyph.fY - pGlyph.oBitmap.nY) >> 0;

        var imageData = this.m_oContext.getImageData(nX,nY,nW,nH);
        var pPixels = imageData.data;

        var _r = this.m_oBrush.Color1.R;
        var _g = this.m_oBrush.Color1.G;
        var _b = this.m_oBrush.Color1.B;

        for (; j < nH; ++j)
        {
            var indx = 4 * j * nW;
            for (i = 0; i < nW; ++i)
            {
                var weight  = pGlyph.oBitmap.pData[j * pGlyph.oBitmap.nWidth + i];

                if (255 == weight)
                {
                    pPixels[indx]     = _r;
                    pPixels[indx + 1] = _g;
                    pPixels[indx + 2] = _b;
                    pPixels[indx + 3] = 255;
                }
                else
                {
                    var r = pPixels[indx];
                    var g = pPixels[indx + 1];
                    var b = pPixels[indx + 2];
                    var a = pPixels[indx + 3];

                    pPixels[indx]     = ((_r - r) * weight + (r << 8)) >>> 8;
                    pPixels[indx + 1] = ((_g - g) * weight + (g << 8)) >>> 8;
                    pPixels[indx + 2] = ((_b - b) * weight + (b << 8)) >>> 8;
                    pPixels[indx + 3] = (weight + a) - ((weight * a + 256) >>> 8);
                }

                indx += 4;
            }
        }
        this.m_oContext.putImageData(imageData,nX,nY);
    },

    SetIntegerGrid : function(param)
    {
        if (true == param)
        {
            this.m_bIntegerGrid = true;
            this.m_oContext.setTransform(1,0,0,1,0,0);
        }
        else
        {
            this.m_bIntegerGrid = false;
            this.m_oContext.setTransform(this.m_oFullTransform.sx,this.m_oFullTransform.shy,this.m_oFullTransform.shx,
                this.m_oFullTransform.sy,this.m_oFullTransform.tx,this.m_oFullTransform.ty);
        }
    },
    GetIntegerGrid : function()
    {
        return this.m_bIntegerGrid;
    },

    DrawStringASCII : function(name, size, bold, italic, text, x, y, bIsHeader)
    {
        var _textProp = {
            RFonts : { Ascii : { Name : name, Index : -1 } },
            FontSize : (((size * 2 * 96 / this.m_dDpiY) + 0.5) >> 0) / 2,
            Bold : false,
            Italic : false
        };

        this.m_oTextPr = _textProp;
        this.m_oGrFonts.Ascii.Name = this.m_oTextPr.RFonts.Ascii.Name;
        this.m_oGrFonts.Ascii.Index = -1;

        this.SetFontSlot(fontslot_ASCII, 1);

        this.m_oFontManager.LoadString2(text, 0, 0);
        var measure = this.m_oFontManager.MeasureString2();

        var _ctx = this.m_oContext;
        _ctx.beginPath();
        _ctx.fillStyle = "#E1E1E1";
        _ctx.strokeStyle = GlobalSkin.RulerOutline;

        var _xPxOffset = 10;
        var _yPxOffset = 5;
        if (AscBrowser.isRetina)
        {
            _xPxOffset = (_xPxOffset * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
            _yPxOffset = (_yPxOffset * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
        }

        var __x = this.m_oFullTransform.TransformPointX(x, y) >> 0;
        var __y = this.m_oFullTransform.TransformPointY(x, y) >> 0;
        var __w = (measure.fWidth >> 0) + 2 * _xPxOffset;
        var __h = (Math.abs(measure.fY) >> 0) + 2 * _yPxOffset;

        if (!bIsHeader)
            __y -= __h;

        if (!AscBrowser.isRetina)
            _ctx.rect(__x + 0.5, __y + 0.5, __w, __h);
        else
            _ctx.rect(__x, __y, __w, __h);

        _ctx.fill();
        _ctx.stroke();
        _ctx.beginPath();

        this.b_color1(68, 68, 68, 255);

        var _koef_px_to_mm = 25.4 / this.m_dDpiY;

        if (bIsHeader)
            this.t(text, x + _xPxOffset * _koef_px_to_mm, y + (__h - _yPxOffset) * _koef_px_to_mm);
        else
            this.t(text, x + _xPxOffset * _koef_px_to_mm, y - _yPxOffset * _koef_px_to_mm);
    },

    DrawStringASCII2 : function(name, size, bold, italic, text, x, y, bIsHeader)
    {
        var _textProp = {
            RFonts : { Ascii : { Name : name, Index : -1 } },
            FontSize : (((size * 2 * 96 / this.m_dDpiY) + 0.5) >> 0) / 2,
            Bold : false,
            Italic : false
        };

        this.m_oTextPr = _textProp;
        this.m_oGrFonts.Ascii.Name = this.m_oTextPr.RFonts.Ascii.Name;
        this.m_oGrFonts.Ascii.Index = -1;

        this.SetFontSlot(fontslot_ASCII, 1);

        this.m_oFontManager.LoadString2(text, 0, 0);
        var measure = this.m_oFontManager.MeasureString2();

        var _ctx = this.m_oContext;
        _ctx.beginPath();
        _ctx.fillStyle = "#E1E1E1";
        _ctx.strokeStyle = GlobalSkin.RulerOutline;

        var _xPxOffset = 10;
        var _yPxOffset = 5;
        if (AscBrowser.isRetina)
        {
			_xPxOffset = (_xPxOffset * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
			_yPxOffset = (_yPxOffset * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
        }

        var __x = this.m_oFullTransform.TransformPointX(this.m_dWidthMM - x, y) >> 0;
        var __y = this.m_oFullTransform.TransformPointY(this.m_dWidthMM - x, y) >> 0;
        var __w = (measure.fWidth >> 0) + 2 * _xPxOffset;
        var __h = (Math.abs(measure.fY) >> 0) + 2 * _yPxOffset;
        __x -= __w;

        if (!bIsHeader)
            __y -= __h;

        if (!AscBrowser.isRetina)
            _ctx.rect(__x + 0.5, __y + 0.5, __w, __h);
        else
            _ctx.rect(__x, __y, __w, __h);

        _ctx.fill();
        _ctx.stroke();
        _ctx.beginPath();

        this.b_color1(68, 68, 68, 255);

        var _koef_px_to_mm = 25.4 / this.m_dDpiY;

        var xPos = this.m_dWidthMM - x - (__w - _xPxOffset) * _koef_px_to_mm;

        if (bIsHeader)
            this.t(text, xPos, y + (__h - _yPxOffset) * _koef_px_to_mm);
        else
            this.t(text, xPos, y - _yPxOffset * _koef_px_to_mm);
    },

    DrawHeaderEdit : function(yPos, lock_type, sectionNum, bIsRepeat, type)
    {
        var _y = this.m_oFullTransform.TransformPointY(0,yPos);
        _y = (_y >> 0) + 0.5;
        var _x = 0;
        var _wmax = this.m_lWidthPix;

        var _w1 = 6;
        var _w2 = 3;

        var _lineWidth = 1;
        var _isRetina = AscBrowser.isRetina;
        if (_isRetina && !editor.WordControl.bIsRetinaSupport)
            _isRetina = false;

        if (_isRetina)
        {
            _y >>= 0;
            _lineWidth = 2;
        }


        var ctx = this.m_oContext;

        switch (lock_type)
        {
            case locktype_None:
            case locktype_Mine:
            {
                //this.p_color(155, 187, 277, 255);
                //ctx.lineWidth = 2;
                // GlobalSkin.RulerOutline
                this.p_color(0xBB, 0xBE, 0xC2, 255);
                ctx.lineWidth = _lineWidth;
                break;
            }
            case locktype_Other:
            case locktype_Other2:
            {
                this.p_color(238, 53, 37, 255);
                ctx.lineWidth = _lineWidth;
                _w1 = 2;
                _w2 = 1;
                break;
            }
            default:
            {
                this.p_color(155, 187, 277, 255);
                ctx.lineWidth = _lineWidth;
                _w1 = 2;
                _w2 = 1;
            }
        }

        if (_isRetina)
        {
			_w1 = (_w1 * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
			_w2 = (_w2 * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
        }

        var bIsNoIntGrid = this.m_bIntegerGrid;

        if (false == bIsNoIntGrid)
            this.SetIntegerGrid(true);

        this._s();
        while (true)
        {
            if (_x > _wmax)
                break;
            ctx.moveTo(_x,_y);
            _x+=_w1;
            ctx.lineTo(_x,_y);
            _x+=_w2;
        }
        this.ds();

        var _header_text = AscCommon.translateManager.getValue("Header");
        if (-1 != sectionNum)
            _header_text += (AscCommon.translateManager.getValue(" -Section ") + (sectionNum + 1) + "-");

        if (type)
        {
            if (type.bFirst)
                _header_text = AscCommon.translateManager.getValue("First Page ") + _header_text;
            else if (EvenAndOddHeaders)
            {
                if (type.bEven)
                    _header_text = AscCommon.translateManager.getValue("Even Page ") + _header_text;
                else
                    _header_text = AscCommon.translateManager.getValue("Odd Page ") + _header_text;
            }
        }

        var _fontSize = _isRetina ? ((9 * AscCommon.AscBrowser.retinaPixelRatio) >> 0) : 9;
        this.DrawStringASCII("Courier New", _fontSize, false, false, _header_text, 2, yPos, true);

        if (bIsRepeat)
            this.DrawStringASCII2("Courier New", _fontSize, false, false, AscCommon.translateManager.getValue("Same as Previous"), 2, yPos, true);

        if (false == bIsNoIntGrid)
            this.SetIntegerGrid(false);
    },

    DrawFooterEdit : function(yPos, lock_type, sectionNum, bIsRepeat, type)
    {
        var _y = this.m_oFullTransform.TransformPointY(0,yPos);
        _y = (_y >> 0) + 0.5;
        var _x = 0;
        var _w1 = 6;
        var _w2 = 3;

        var _lineWidth = 1;
        var _isRetina = AscBrowser.isRetina;
        if (_isRetina && !editor.WordControl.bIsRetinaSupport)
            _isRetina = false;

        if (_isRetina)
        {
            _y >>= 0;
            _lineWidth = 2;
        }

        var ctx = this.m_oContext;

        switch (lock_type)
        {
            case locktype_None:
            case locktype_Mine:
            {
                //this.p_color(155, 187, 277, 255);
                //ctx.lineWidth = 2;
                // GlobalSkin.RulerOutline
                this.p_color(0xBB, 0xBE, 0xC2, 255);
                ctx.lineWidth = _lineWidth;
                break;
            }
            case locktype_Other:
            case locktype_Other2:
            {
                this.p_color(238, 53, 37, 255);
                ctx.lineWidth = _lineWidth;
                _w1 = 2;
                _w2 = 1;
                break;
            }
            default:
            {
                this.p_color(155, 187, 277, 255);
                ctx.lineWidth = _lineWidth;
                _w1 = 2;
                _w2 = 1;
            }
        }

        if (_isRetina)
        {
			_w1 = (_w1 * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
			_w2 = (_w2 * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
        }

        var _wmax = this.m_lWidthPix;

        var bIsNoIntGrid = this.m_bIntegerGrid;

        if (false == bIsNoIntGrid)
            this.SetIntegerGrid(true);

        this._s();
        while (true)
        {
            if (_x > _wmax)
                break;
            ctx.moveTo(_x,_y);
            _x+=_w1;
            ctx.lineTo(_x,_y);
            _x+=_w2;
        }
        this.ds();

        var _header_text = AscCommon.translateManager.getValue("Footer");
        if (-1 != sectionNum)
            _header_text += (AscCommon.translateManager.getValue(" -Section ") + (sectionNum + 1) + "-");

        if (type)
        {
            if (type.bFirst)
                _header_text = AscCommon.translateManager.getValue("First Page ") + _header_text;
            else if (EvenAndOddHeaders)
            {
                if (type.bEven)
                    _header_text = AscCommon.translateManager.getValue("Even Page ") + _header_text;
                else
                    _header_text = AscCommon.translateManager.getValue("Odd Page ") + _header_text;
            }
        }

        var _fontSize = _isRetina ? ((9 * AscCommon.AscBrowser.retinaPixelRatio) >> 0) : 9;
        this.DrawStringASCII("Courier New", _fontSize, false, false, _header_text, 2, yPos, false);

        if (bIsRepeat)
            this.DrawStringASCII2("Courier New", _fontSize, false, false, AscCommon.translateManager.getValue("Same as Previous"), 2, yPos, false);

        if (false == bIsNoIntGrid)
            this.SetIntegerGrid(false);
    },

    DrawLockParagraph : function(lock_type, x, y1, y2)
    {
		if (lock_type == locktype_None || editor.WordControl.m_oDrawingDocument.IsLockObjectsEnable === false || editor.isViewMode || (lock_type === locktype_Mine && true === AscCommon.CollaborativeEditing.Is_Fast()))
			return;

		if (lock_type == locktype_Mine)
		{
			this.p_color(22, 156, 0, 255);
			//this.p_color(155, 187, 277, 255);
		}
		else
			this.p_color(238, 53, 37, 255);

		var _x = this.m_oFullTransform.TransformPointX(x, y1) >> 0;
		var _xT = this.m_oFullTransform.TransformPointX(x, y2) >> 0;
		var _y1 = (this.m_oFullTransform.TransformPointY(x, y1) >> 0) + 0.5;
		var _y2 = (this.m_oFullTransform.TransformPointY(x, y2) >> 0) - 1.5;

		var ctx = this.m_oContext;
		if (_x != _xT)
		{
			// значит какой-то трансформ
			var dKoefMMToPx = 1 / Math.max(this.m_oCoordTransform.sx, 0.001);
			this.p_width(1000 * dKoefMMToPx);

			var w_dot = 2 * dKoefMMToPx;
			var w_dist = 1 * dKoefMMToPx;
			var w_len_indent = 3;

			var _interf = editor.WordControl.m_oDrawingDocument.AutoShapesTrack;

			this._s();
			_interf.AddLineDash(ctx, x, y1, x, y2, w_dot, w_dist);
			_interf.AddLineDash(ctx, x, y1, x + w_len_indent, y1, w_dot, w_dist);
			_interf.AddLineDash(ctx, x, y2, x + w_len_indent, y2, w_dot, w_dist);

			this.ds();
			return;
		}

		var bIsInt = this.m_bIntegerGrid;
		if (!bIsInt)
			this.SetIntegerGrid(true);

		ctx.lineWidth = 1;

		var w_dot = 2;
		var w_dist = 1;
		var w_len_indent = (3 * this.m_oCoordTransform.sx) >> 0;

		this._s();

		var y_mem = _y1 - 0.5;
		while (true)
		{
			if ((y_mem + w_dot) > _y2)
				break;
			ctx.moveTo(_x + 0.5,y_mem);
			y_mem+=w_dot;
			ctx.lineTo(_x + 0.5,y_mem);
			y_mem+=w_dist;
		}

		var x_max = _x + w_len_indent;

		var x_mem = _x;
		while (true)
		{
			if (x_mem > x_max)
				break;
			ctx.moveTo(x_mem,_y1);
			x_mem+=w_dot;
			ctx.lineTo(x_mem,_y1);
			x_mem+=w_dist;
		}
		x_mem = _x;
		while (true)
		{
			if (x_mem > x_max)
				break;
			ctx.moveTo(x_mem,_y2);
			x_mem+=w_dot;
			ctx.lineTo(x_mem,_y2);
			x_mem+=w_dist;
		}

		this.ds();

		if (!bIsInt)
			this.SetIntegerGrid(false);
    },

    DrawLockObjectRect : function(lock_type, x, y, w, h)
    {
		if (editor.isViewMode || this.IsThumbnail || lock_type == locktype_None || this.IsDemonstrationMode || (lock_type === locktype_Mine && true === AscCommon.CollaborativeEditing.Is_Fast()))
			return;

		if (editor.WordControl.m_oDrawingDocument.IsLockObjectsEnable === false && lock_type == locktype_Mine)
			return;

		if (lock_type == locktype_Mine)
		{
			this.p_color(22, 156, 0, 255);
			//this.p_color(155, 187, 277, 255);
		}
		else
			this.p_color(238, 53, 37, 255);

		var ctx = this.m_oContext;

		var _m = this.m_oTransform;
		if (_m.sx != 1.0 || _m.shx != 0.0 || _m.shy != 0.0 || _m.sy != 1.0)
		{
			// значит какой-то трансформ
			var dKoefMMToPx = 1 / Math.max(this.m_oCoordTransform.sx, 0.001);
			this.p_width(1000 * dKoefMMToPx);

			var w_dot = 2 * dKoefMMToPx;
			var w_dist = 1 * dKoefMMToPx;

			var _interf = editor.WordControl.m_oDrawingDocument.AutoShapesTrack;

			var eps = 5 * dKoefMMToPx;
			var _x = x - eps;
			var _y = y - eps;
			var _r = x + w + eps;
			var _b = y + h + eps;

			this._s();
			_interf.AddRectDash(ctx, _x, _y, _r, _y, _x, _b, _r, _b, w_dot, w_dist, true);
			this._s();
			return;
		}

		var bIsInt = this.m_bIntegerGrid;
		if (!bIsInt)
			this.SetIntegerGrid(true);

		ctx.lineWidth = 1;

		var w_dot = 2;
		var w_dist = 2;

		var eps = 5;

		var _x = (this.m_oFullTransform.TransformPointX(x, y) >> 0) - eps + 0.5;
		var _y = (this.m_oFullTransform.TransformPointY(x, y) >> 0) - eps + 0.5;

		var _r = (this.m_oFullTransform.TransformPointX(x+w, y+h) >> 0) + eps + 0.5;
		var _b = (this.m_oFullTransform.TransformPointY(x+w, y+h) >> 0) + eps + 0.5;

		this._s();

		for (var i = _x; i < _r; i += w_dist)
		{
			ctx.moveTo(i, _y);
			i += w_dot;

			if (i > _r)
				i = _r;

			ctx.lineTo(i, _y);
		}
		for (var i = _y; i < _b; i += w_dist)
		{
			ctx.moveTo(_r, i);
			i += w_dot;

			if (i > _b)
				i = _b;

			ctx.lineTo(_r, i);
		}
		for (var i = _r; i > _x; i -= w_dist)
		{
			ctx.moveTo(i, _b);
			i -= w_dot;

			if (i < _x)
				i = _x;

			ctx.lineTo(i, _b);
		}
		for (var i = _b; i > _y; i -= w_dist)
		{
			ctx.moveTo(_x, i);
			i -= w_dot;

			if (i < _y)
				i = _y;

			ctx.lineTo(_x, i);
		}

		this.ds();

		if (!bIsInt)
			this.SetIntegerGrid(false);
    },

    DrawEmptyTableLine : function(x1,y1,x2,y2)
    {
        if ((!editor.isShowTableEmptyLine || editor.isViewMode) && (editor.isShowTableEmptyLineAttack === false))
            return;

        var _x1 = this.m_oFullTransform.TransformPointX(x1,y1);
        var _y1 = this.m_oFullTransform.TransformPointY(x1,y1);

        var _x2 = this.m_oFullTransform.TransformPointX(x2,y2);
        var _y2 = this.m_oFullTransform.TransformPointY(x2,y2);

        _x1 = (_x1 >> 0) + 0.5;
        _y1 = (_y1 >> 0) + 0.5;
        _x2 = (_x2 >> 0) + 0.5;
        _y2 = (_y2 >> 0) + 0.5;

        this.p_color(138, 162, 191, 255);
        var ctx = this.m_oContext;

        if (_x1 != _x2 && _y1 != _y2)
        {
            // значит какой-то трансформ
            var dKoefMMToPx = 1 / Math.max(this.m_oCoordTransform.sx, 0.001);

            this.p_width(1000 * dKoefMMToPx);
            this._s();
            editor.WordControl.m_oDrawingDocument.AutoShapesTrack.AddLineDash(ctx, x1, y1, x2, y2, 2 * dKoefMMToPx, 2 * dKoefMMToPx);
            this.ds();
            return;
        }

        ctx.lineWidth = 1;
        var bIsInt = this.m_bIntegerGrid;
        if (!bIsInt)
            this.SetIntegerGrid(true);
        if (_x1 == _x2)
        {
            var _y = Math.min(_y1, _y2) + 0.5;
            var _w1 = 2;
            var _w2 = 2;
            var _wmax = Math.max(_y1, _y2) - 0.5;
            this._s();
            while (true)
            {
                if (_y > _wmax)
                    break;
                ctx.moveTo(_x1,_y);
                _y+=_w1;
                if (_y > _wmax)
                {
                    ctx.lineTo(_x1,_y - _w1 + 1);
                }
                else
                {
                    ctx.lineTo(_x1,_y);
                }
                _y+=_w2;
            }
            this.ds();
        }
        else if (_y1 == _y2)
        {
            var _x = Math.min(_x1, _x2) + 0.5;
            var _w1 = 2;
            var _w2 = 2;
            var _wmax = Math.max(_x1, _x2) - 0.5;
            this._s();
            while (true)
            {
                if (_x > _wmax)
                    break;
                ctx.moveTo(_x,_y1);
                _x+=_w1;

                if (_x > _wmax)
                {
                    ctx.lineTo(_x - _w2 + 1,_y1);
                }
                else
                {
                    ctx.lineTo(_x,_y1);
                }
                _x+=_w2;
            }
            this.ds();
        }
        else
        {
            // значит какой-то трансформ
            this._s();
            editor.WordControl.m_oDrawingDocument.AutoShapesTrack.AddLineDash(ctx, _x1, _y1, _x2, _y2, 2, 2);
            this.ds();
        }
        if (!bIsInt)
            this.SetIntegerGrid(false);
    },

    DrawSpellingLine : function(y0, x0, x1, w)
    {
        if (!editor.isViewMode)
            this.drawHorLine(0, y0, x0, x1, w );
    },

    // smart methods for horizontal / vertical lines
    drawHorLine : function(align, y, x, r, penW)
    {
        var _check_transform = global_MatrixTransformer.IsIdentity2(this.m_oTransform);
        if (!this.m_bIntegerGrid || !_check_transform)
        {
            if (_check_transform)
            {
                this.SetIntegerGrid(true);
                this.drawHorLine(align, y, x, r, penW);
                this.SetIntegerGrid(false);
                return;
            }

            this.p_width(penW * 1000);
            this._s();
            this._m(x, y);
            this._l(r, y);
            this.ds();
            return;
        }

        var pen_w = ((this.m_dDpiX * penW / g_dKoef_in_to_mm) + 0.5) >> 0;
        if (0 == pen_w)
            pen_w = 1;

        var _x = (this.m_oFullTransform.TransformPointX(x,y) >> 0) + 0.5 - 0.5;
        var _r = (this.m_oFullTransform.TransformPointX(r,y) >> 0) + 0.5 + 0.5;

        var ctx = this.m_oContext;

        ctx.setTransform(1,0,0,1,0,0);

        ctx.lineWidth = pen_w;

        switch (align)
        {
            case 0:
            {
                // top
                var _top = (this.m_oFullTransform.TransformPointY(x,y) >> 0) + 0.5;

                ctx.beginPath();
                ctx.moveTo(_x, _top + pen_w / 2 - 0.5);
                ctx.lineTo(_r, _top + pen_w / 2 - 0.5);
                ctx.stroke();

                break;
            }
            case 1:
            {
                // center
                var _center = (this.m_oFullTransform.TransformPointY(x,y) >> 0) + 0.5;

                ctx.beginPath();
                if (0 == (pen_w % 2))
                {
                    ctx.moveTo(_x, _center - 0.5);
                    ctx.lineTo(_r, _center - 0.5);
                }
                else
                {
                    ctx.moveTo(_x, _center);
                    ctx.lineTo(_r, _center);
                }
                ctx.stroke();

                break;
            }
            case 2:
            {
                // bottom
                var _bottom = (this.m_oFullTransform.TransformPointY(x,y) >> 0) + 0.5;

                ctx.beginPath();
                ctx.moveTo(_x, _bottom - pen_w / 2 + 0.5);
                ctx.lineTo(_r, _bottom - pen_w / 2 + 0.5);
                ctx.stroke();

                break;
            }
        }
    },
    drawHorLine2 : function(align, y, x, r, penW)
    {
        var _check_transform = global_MatrixTransformer.IsIdentity2(this.m_oTransform);
        if (!this.m_bIntegerGrid || !_check_transform)
        {
            if (_check_transform)
            {
                this.SetIntegerGrid(true);
                this.drawHorLine2(align, y, x, r, penW);
                this.SetIntegerGrid(false);
                return;
            }

            var _y1 = y - penW / 2;
            var _y2 = _y1 + 2 * penW;

            this.p_width(penW * 1000);
            this._s();
            this._m(x, _y1);
            this._l(r, _y1);
            this.ds();

            this._s();
            this._m(x, _y2);
            this._l(r, _y2);
            this.ds();
            return;
        }

        var pen_w = ((this.m_dDpiX * penW / g_dKoef_in_to_mm) + 0.5) >> 0;
        if (0 == pen_w)
            pen_w = 1;

        var _x = (this.m_oFullTransform.TransformPointX(x,y) >> 0) + 0.5 - 0.5;
        var _r = (this.m_oFullTransform.TransformPointX(r,y) >> 0) + 0.5 + 0.5;

        var ctx = this.m_oContext;
        ctx.lineWidth = pen_w;

        switch (align)
        {
            case 0:
            {
                // top
                var _top = (this.m_oFullTransform.TransformPointY(x,y) >> 0) + 0.5;

                var _pos1 = _top + pen_w / 2 - 0.5 - pen_w;
                var _pos2 = _pos1 + pen_w * 2;

                ctx.beginPath();
                ctx.moveTo(_x, _pos1);
                ctx.lineTo(_r, _pos1);
                ctx.stroke();

                ctx.beginPath();
                ctx.moveTo(_x, _pos2);
                ctx.lineTo(_r, _pos2);
                ctx.stroke();

                break;
            }
            case 1:
            {
                // center
                // TODO:

                break;
            }
            case 2:
            {
                // bottom
                // TODO:

                break;
            }
        }
    },
    drawVerLine : function(align, x, y, b, penW)
    {
        var _check_transform = global_MatrixTransformer.IsIdentity2(this.m_oTransform);
        if (!this.m_bIntegerGrid || !_check_transform)
        {
            if (_check_transform)
            {
                this.SetIntegerGrid(true);
                this.drawVerLine(align, x, y, b, penW);
                this.SetIntegerGrid(false);
                return;
            }

            this.p_width(penW * 1000);
            this._s();
            this._m(x, y);
            this._l(x, b);
            this.ds();
            return;
        }

        var pen_w = ((this.m_dDpiX * penW / g_dKoef_in_to_mm) + 0.5) >> 0;
        if (0 == pen_w)
            pen_w = 1;

        var _y = (this.m_oFullTransform.TransformPointY(x,y) >> 0) + 0.5 - 0.5;
        var _b = (this.m_oFullTransform.TransformPointY(x,b) >> 0) + 0.5 + 0.5;

        var ctx = this.m_oContext;
        ctx.lineWidth = pen_w;

        switch (align)
        {
            case 0:
            {
                // left
                var _left = (this.m_oFullTransform.TransformPointX(x,y) >> 0) + 0.5;

                ctx.beginPath();
                ctx.moveTo(_left + pen_w / 2 - 0.5, _y);
                ctx.lineTo(_left + pen_w / 2 - 0.5, _b);
                ctx.stroke();

                break;
            }
            case 1:
            {
                // center
                var _center = (this.m_oFullTransform.TransformPointX(x,y) >> 0) + 0.5;

                ctx.beginPath();
                if (0 == (pen_w % 2))
                {
                    ctx.moveTo(_center - 0.5, _y);
                    ctx.lineTo(_center - 0.5, _b);
                }
                else
                {
                    ctx.moveTo(_center, _y);
                    ctx.lineTo(_center, _b);
                }
                ctx.stroke();

                break;
            }
            case 2:
            {
                // right
                var _right = (this.m_oFullTransform.TransformPointX(x,y) >> 0) + 0.5;

                ctx.beginPath();
                ctx.moveTo(_right - pen_w / 2 + 0.5, _y);
                ctx.lineTo(_right - pen_w / 2 + 0.5, _b);
                ctx.stroke();

                break;
            }
        }
    },

    // мега крутые функции для таблиц
    drawHorLineExt : function(align, y, x, r, penW, leftMW, rightMW)
    {
        var _check_transform = global_MatrixTransformer.IsIdentity2(this.m_oTransform);
        if (!this.m_bIntegerGrid || !_check_transform)
        {
            if (_check_transform)
            {
                this.SetIntegerGrid(true);
                this.drawHorLineExt(align, y, x, r, penW, leftMW, rightMW);
                this.SetIntegerGrid(false);
                return;
            }

            this.p_width(penW * 1000);
            this._s();
            this._m(x, y);
            this._l(r, y);
            this.ds();
            return;
        }

        var pen_w = Math.max(((this.m_dDpiX * penW / g_dKoef_in_to_mm) + 0.5) >> 0, 1);

        var _x = (this.m_oFullTransform.TransformPointX(x,y) >> 0) + 0.5;
        var _r = (this.m_oFullTransform.TransformPointX(r,y) >> 0) + 0.5;

        if (leftMW != 0)
        {
            var _center = _x;
            var pen_mw = Math.max(((this.m_dDpiX * Math.abs(leftMW) * 2 / g_dKoef_in_to_mm) + 0.5) >> 0, 1);
            if (leftMW < 0)
            {
                if ((pen_mw % 2) == 0)
                {
                    _x = _center - (pen_mw / 2);
                }
                else
                {
                    _x = _center - ((pen_mw / 2) >> 0);
                }
            }
            else
            {
                if ((pen_mw % 2) == 0)
                {
                    _x = _center + ((pen_mw / 2) - 1.0);
                }
                else
                {
                    _x = _center + ((pen_mw / 2) >> 0);
                }
            }
        }
        if (rightMW != 0)
        {
            var _center = _r;
            var pen_mw = Math.max(((this.m_dDpiX * Math.abs(rightMW) * 2 / g_dKoef_in_to_mm) + 0.5) >> 0, 1);
            if (rightMW < 0)
            {
                if ((pen_mw % 2) == 0)
                {
                    _r = _center - (pen_mw / 2);
                }
                else
                {
                    _r = _center - ((pen_mw / 2) >> 0);
                }
            }
            else
            {
                if ((pen_mw % 2) == 0)
                {
                    _r = _center + (pen_mw / 2) - 1.0;
                }
                else
                {
                    _r = _center + ((pen_mw / 2) >> 0);
                }
            }
        }

        var ctx = this.m_oContext;
        ctx.lineWidth = pen_w;

        _x -= 0.5;
        _r += 0.5;

        switch (align)
        {
            case 0:
            {
                // top
                var _top = (this.m_oFullTransform.TransformPointY(x,y) >> 0) + 0.5;

                ctx.beginPath();
                ctx.moveTo(_x, _top + pen_w / 2 - 0.5);
                ctx.lineTo(_r, _top + pen_w / 2 - 0.5);
                ctx.stroke();

                break;
            }
            case 1:
            {
                // center
                var _center = (this.m_oFullTransform.TransformPointY(x,y) >> 0) + 0.5;

                ctx.beginPath();
                if (0 == (pen_w % 2))
                {
                    ctx.moveTo(_x, _center - 0.5);
                    ctx.lineTo(_r, _center - 0.5);
                }
                else
                {
                    ctx.moveTo(_x, _center);
                    ctx.lineTo(_r, _center);
                }
                ctx.stroke();

                break;
            }
            case 2:
            {
                // bottom
                var _bottom = (this.m_oFullTransform.TransformPointY(x,y) >> 0) + 0.5;

                ctx.beginPath();
                ctx.moveTo(_x, _bottom - pen_w / 2 + 0.5);
                ctx.lineTo(_r, _bottom - pen_w / 2 + 0.5);
                ctx.stroke();

                break;
            }
        }
    },

    rect : function(x,y,w,h)
    {
        var ctx = this.m_oContext;
        ctx.beginPath();

        if (this.m_bIntegerGrid)
        {
            var _x = (this.m_oFullTransform.TransformPointX(x,y) + 0.5) >> 0;
            var _y = (this.m_oFullTransform.TransformPointY(x,y) + 0.5) >> 0;
            var _r = (this.m_oFullTransform.TransformPointX(x+w,y) + 0.5) >> 0;
            var _b = (this.m_oFullTransform.TransformPointY(x,y+h) + 0.5) >> 0;

            ctx.rect(_x, _y, _r - _x, _b - _y);
        }
        else
        {
            ctx.rect(x, y, w, h);
        }
    },

    TableRect : function(x,y,w,h)
    {
        var ctx = this.m_oContext;

        if (this.m_bIntegerGrid)
        {
            var _x = (this.m_oFullTransform.TransformPointX(x,y) >> 0) + 0.5;
            var _y = (this.m_oFullTransform.TransformPointY(x,y) >> 0) + 0.5;
            var _r = (this.m_oFullTransform.TransformPointX(x+w,y) >> 0) + 0.5;
            var _b = (this.m_oFullTransform.TransformPointY(x,y+h) >> 0) + 0.5;

            ctx.fillRect(_x - 0.5, _y - 0.5, _r - _x + 1, _b - _y + 1);
        }
        else
        {
            ctx.fillRect(x, y, w, h);
        }
    },

    // функции клиппирования
    AddClipRect : function(x, y, w, h)
    {
        //this.ClipManager.AddRect(x, y, w, h);
        var __rect = new AscCommon._rect();
        __rect.x = x;
        __rect.y = y;
        __rect.w = w;
        __rect.h = h;
        this.GrState.AddClipRect(__rect);
    },
    RemoveClipRect : function()
    {
        //this.ClipManager.RemoveRect();
    },

    SetClip : function(r)
    {
        var ctx = this.m_oContext;
        ctx.save();

        ctx.beginPath();
        if (!global_MatrixTransformer.IsIdentity(this.m_oTransform))
        {
            ctx.rect(r.x, r.y, r.w, r.h);
        }
        else
        {
            var _x = (this.m_oFullTransform.TransformPointX(r.x,r.y) + 1) >> 0;
            var _y = (this.m_oFullTransform.TransformPointY(r.x,r.y) + 1) >> 0;
            var _r = (this.m_oFullTransform.TransformPointX(r.x+r.w,r.y) - 1) >> 0;
            var _b = (this.m_oFullTransform.TransformPointY(r.x,r.y+r.h) - 1) >> 0;

            ctx.rect(_x, _y, _r - _x + 1, _b - _y + 1);
        }

        this.clip();
        ctx.beginPath();
    },

    RemoveClip : function()
    {
        this.m_oContext.restore();
        this.m_oContext.save();

        if (this.m_oContext.globalAlpha != this.globalAlpha)
            this.m_oContext.globalAlpha = this.globalAlpha;
    },

    drawCollaborativeChanges : function(x, y, w, h, Color)
    {
        this.b_color1( Color.r, Color.g, Color.b, 255 );
        this.rect( x, y, w, h );
        this.df();
    },

    drawMailMergeField : function(x, y, w, h)
    {
		this.b_color1(206, 212, 223, 204);
    	//this.b_color1(216, 221, 230, 255);
        this.rect( x, y, w, h );
        this.df();
    },

    drawSearchResult : function(x, y, w, h)
    {
        this.b_color1( 255, 220, 0, 200 );
        this.rect( x, y, w, h );
        this.df();
    },

    drawFlowAnchor : function(x, y)
    {
        if (!AscCommon.g_flow_anchor || !AscCommon.g_flow_anchor.asc_complete || (!editor || !editor.ShowParaMarks))
            return;

        if (false === this.m_bIntegerGrid)
        {
            this.m_oContext.setTransform(1,0,0,1,0,0);
        }

        var _x = this.m_oFullTransform.TransformPointX(x,y) >> 0;
        var _y = this.m_oFullTransform.TransformPointY(x,y) >> 0;

        this.m_oContext.drawImage(AscCommon.g_flow_anchor, _x, _y);

        if (false === this.m_bIntegerGrid)
        {
            this.m_oContext.setTransform(this.m_oFullTransform.sx,this.m_oFullTransform.shy,this.m_oFullTransform.shx,
                this.m_oFullTransform.sy,this.m_oFullTransform.tx,this.m_oFullTransform.ty);
        }
    },

    SavePen : function()
    {
        this.GrState.SavePen();
    },
    RestorePen : function()
    {
        this.GrState.RestorePen();
    },

    SaveBrush : function()
    {
        this.GrState.SaveBrush();
    },
    RestoreBrush : function()
    {
        this.GrState.RestoreBrush();
    },

    SavePenBrush : function()
    {
        this.GrState.SavePenBrush();
    },
    RestorePenBrush : function()
    {
        this.GrState.RestorePenBrush();
    },

    SaveGrState : function()
    {
        this.GrState.SaveGrState();
    },
    RestoreGrState : function()
    {
        this.GrState.RestoreGrState();
    },

    StartClipPath : function()
    {
    },

    EndClipPath : function()
    {
        this.m_oContext.clip();
    },

    StartCheckTableDraw : function()
    {
        if (!this.m_bIntegerGrid && global_MatrixTransformer.IsIdentity2(this.m_oTransform))
        {
            this.SaveGrState();
            this.SetIntegerGrid(true);
            return true;
        }
        return false;
    },

    EndCheckTableDraw : function(bIsRestore)
    {
        if (bIsRestore)
            this.RestoreGrState();
    },

    SetTextClipRect : function(_l, _t, _r, _b)
    {
        this.TextClipRect = {
            l : (_l * this.m_oCoordTransform.sx) >> 0,
            t : (_t * this.m_oCoordTransform.sy) >> 0,
            r : (_r * this.m_oCoordTransform.sx) >> 0,
            b : (_b * this.m_oCoordTransform.sy) >> 0
        };
    },

    AddSmartRect : function(x, y, w, h, pen_w)
    {
        if (!global_MatrixTransformer.IsIdentity2(this.m_oTransform))
        {
            // проверим - может все-таки можно нарисовать как надо?
            var r = x + w;
            var b = y + h;
            var dx1 = this.m_oFullTransform.TransformPointX(x, y);
            var dy1 = this.m_oFullTransform.TransformPointY(x, y);

            var dx2 = this.m_oFullTransform.TransformPointX(r, y);
            var dy2 = this.m_oFullTransform.TransformPointY(r, y);

            var dx3 = this.m_oFullTransform.TransformPointX(x, b);
            var dy3 = this.m_oFullTransform.TransformPointY(x, b);

            var dx4 = this.m_oFullTransform.TransformPointX(r, b);
            var dy4 = this.m_oFullTransform.TransformPointY(r, b);

            var _eps = 0.001;
            var bIsClever = false;
            var _type = 1;
            if (Math.abs(dx1 - dx3) < _eps &&
                Math.abs(dx2 - dx4) < _eps &&
                Math.abs(dy1 - dy2) < _eps &&
                Math.abs(dy3 - dy4) < _eps)
            {
                bIsClever = true;
                _type = 1;
            }
            if (!bIsClever &&
                Math.abs(dx1 - dx2) < _eps &&
                Math.abs(dx3 - dx4) < _eps &&
                Math.abs(dy1 - dy3) < _eps &&
                Math.abs(dy2 - dy4) < _eps)
            {
                _type = 2;
                bIsClever = true;
            }

            if (!bIsClever)
            {
                this.ds();
                return;
            }

            var _xI = (_type == 1) ? Math.min(dx1, dx2) : Math.min(dx1, dx3);
            var _rI = (_type == 1) ? Math.max(dx1, dx2) : Math.max(dx1, dx3);
            var _yI = (_type == 1) ? Math.min(dy1, dy3) : Math.min(dy1, dy2);
            var _bI = (_type == 1) ? Math.max(dy1, dy3) : Math.max(dy1, dy2);

            var bIsSmartAttack = false;
            if (!this.m_bIntegerGrid)
            {
                this.SetIntegerGrid(true);
                bIsSmartAttack = true;

                if (this.dash_no_smart)
                {
                    for (var index = 0; index < this.dash_no_smart.length; index++)
                        this.dash_no_smart[index] = (this.m_oCoordTransform.sx * this.dash_no_smart[index] + 0.5) >> 0;

                    this.m_oContext.setLineDash(this.dash_no_smart);
                    this.dash_no_smart = null;
                }
            }

            var _pen_w = (pen_w * this.m_oCoordTransform.sx + 0.5) >> 0;
            if (0 >= _pen_w)
                _pen_w = 1;

            this._s();

            if ((_pen_w & 0x01) == 0x01)
            {
                var _x = (_xI >> 0) + 0.5;
                var _y = (_yI >> 0) + 0.5;
                var _r = (_rI >> 0) + 0.5;
                var _b = (_bI >> 0) + 0.5;

                this.m_oContext.rect(_x, _y, _r - _x, _b - _y);
            }
            else
            {
                var _x = (_xI + 0.5) >> 0;
                var _y = (_yI + 0.5) >> 0;
                var _r = (_rI + 0.5) >> 0;
                var _b = (_bI + 0.5) >> 0;

                this.m_oContext.rect(_x, _y, _r - _x, _b - _y);
            }

            this.m_oContext.lineWidth = _pen_w;
            this.ds();

            if (bIsSmartAttack)
            {
                this.SetIntegerGrid(false);
            }
            return;
        }

        var bIsSmartAttack = false;
        if (!this.m_bIntegerGrid)
        {
            this.SetIntegerGrid(true);
            bIsSmartAttack = true;

			if (this.dash_no_smart)
			{
				for (var index = 0; index < this.dash_no_smart.length; index++)
					this.dash_no_smart[index] = (this.m_oCoordTransform.sx * this.dash_no_smart[index] + 0.5) >> 0;

				this.m_oContext.setLineDash(this.dash_no_smart);
				this.dash_no_smart = null;
            }
        }

        var _pen_w = (pen_w * this.m_oCoordTransform.sx + 0.5) >> 0;
        if (0 >= _pen_w)
            _pen_w = 1;

        this._s();

        if ((_pen_w & 0x01) == 0x01)
        {
            var _x = (this.m_oFullTransform.TransformPointX(x, y) >> 0) + 0.5;
            var _y = (this.m_oFullTransform.TransformPointY(x, y) >> 0) + 0.5;
            var _r = (this.m_oFullTransform.TransformPointX(x+w, y+h) >> 0) + 0.5;
            var _b = (this.m_oFullTransform.TransformPointY(x+w, y+h) >> 0) + 0.5;

            this.m_oContext.rect(_x, _y, _r - _x, _b - _y);
        }
        else
        {
            var _x = (this.m_oFullTransform.TransformPointX(x, y) + 0.5) >> 0;
            var _y = (this.m_oFullTransform.TransformPointY(x, y) + 0.5) >> 0;
            var _r = (this.m_oFullTransform.TransformPointX(x+w, y+h) + 0.5) >> 0;
            var _b = (this.m_oFullTransform.TransformPointY(x+w, y+h) + 0.5) >> 0;

            this.m_oContext.rect(_x, _y, _r - _x, _b - _y);
        }

        this.m_oContext.lineWidth = _pen_w;
        this.ds();

        if (bIsSmartAttack)
        {
            this.SetIntegerGrid(false);
        }
    },

    CheckUseFonts2 : function(_transform)
    {
        if (!global_MatrixTransformer.IsIdentity2(_transform))
        {
            if (!AscCommon.g_fontManager2)
            {
                AscCommon.g_fontManager2 = new AscFonts.CFontManager();
                AscCommon.g_fontManager2.Initialize(true);
            }

            this.m_oFontManager2 = AscCommon.g_fontManager2;

            if (null == this.m_oLastFont2)
                this.m_oLastFont2 = new AscCommon.CFontSetup();

            this.IsUseFonts2 = true;
        }
    },

    UncheckUseFonts2 : function()
    {
        this.IsUseFonts2 = false;
    },

    Drawing_StartCheckBounds : function(x, y, w, h)
    {

    },

    Drawing_EndCheckBounds : function()
    {

    },

    DrawPresentationComment : function(type, x, y, w, h)
    {
        if (this.IsThumbnail || this.IsDemonstrationMode)
            return;

        if (this.m_bIntegerGrid)
        {
            if (window.g_comment_image && window.g_comment_image.asc_complete === true)
            {
                var _x = (this.m_oFullTransform.TransformPointX(x,y) >> 0);
                var _y = (this.m_oFullTransform.TransformPointY(x,y) >> 0);

                var _index = 0;
                if ((type & 0x02) == 0x02)
                    _index = 2;
                if ((type & 0x01) == 0x01)
                    _index += 1;

                if (this.IsRetina)
                    _index += 4;

                var _offset = g_comment_image_offsets[_index];
                this.m_oContext.drawImage(window.g_comment_image, _offset[0], _offset[1], _offset[2], _offset[3], _x, _y, _offset[2], _offset[3]);
            }
        }
        else
        {
            this.SetIntegerGrid(true);
            this.DrawPresentationComment(type, x, y, w, h);
            this.SetIntegerGrid(false);
        }
    },

    DrawPolygon : function(oPath, lineWidth, shift)
    {
        this.m_oContext.lineWidth = lineWidth;
        this.m_oContext.beginPath();

        var Points    = oPath.Points;

        var nCount = Points.length;
        // берем предпоследнюю точку, т.к. последняя совпадает с первой
        var PrevX = Points[nCount - 2].X, PrevY = Points[nCount - 2].Y;
        var _x = Points[nCount - 2].X,
            _y = Points[nCount - 2].Y;
        var StartX, StartY ;

        for (var nIndex = 0; nIndex < nCount; nIndex++)
        {
            if(PrevX > Points[nIndex].X)
            {
                _y = Points[nIndex].Y - shift;
            }
            else if(PrevX < Points[nIndex].X)
            {
                _y  = Points[nIndex].Y + shift;
            }

            if(PrevY < Points[nIndex].Y)
            {
                _x = Points[nIndex].X - shift;
            }
            else if(PrevY > Points[nIndex].Y)
            {
                _x = Points[nIndex].X + shift;
            }

            PrevX = Points[nIndex].X;
            PrevY = Points[nIndex].Y;

            if(nIndex > 0)
            {
                if (1 == nIndex)
                {
                    StartX = _x;
                    StartY = _y;
                    this._m(_x, _y);
                }
                else
                {
                    this._l(_x, _y);
                }
            }
        }

        this._l(StartX, StartY);
        this.m_oContext.closePath();
        this.m_oContext.stroke();
        this.m_oContext.beginPath();
    },

    DrawFootnoteRect : function(x, y, w, h)
    {
        var _old = this.m_bIntegerGrid;
        if (!_old)
            this.SetIntegerGrid(true);

        this.p_dash([1, 1]);

        this._s();

        var l = x;
        var t = y;
        var r = x + w;
        var b = y + h;

        this.drawHorLineExt(c_oAscLineDrawingRule.Top, t, l, r, 0, 0, 0);
        this.drawVerLine(c_oAscLineDrawingRule.Right, l, t, b, 0);
        this.drawVerLine(c_oAscLineDrawingRule.Left, r, t, b, 0);
        this.drawHorLineExt(c_oAscLineDrawingRule.Top, b, l, r, 0, 0, 0);

        this.ds();
        this._s();

        this.p_dash(null);

        if (!_old)
            this.SetIntegerGrid(false);
    }
};

//------------------------------------------------------------export----------------------------------------------------
window['AscCommon'] = window['AscCommon'] || {};
window['AscCommon'].CGraphics = CGraphics;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined){

// Import
var getFullImageSrc2 = AscCommon.getFullImageSrc2;

var CShapeColor = AscFormat.CShapeColor;

var c_oAscFill = Asc.c_oAscFill;

function DrawLineEnd(xEnd, yEnd, xPrev, yPrev, type, w, len, drawer, trans)
{
    switch (type)
    {
        case AscFormat.LineEndType.None:
            break;
        case AscFormat.LineEndType.Arrow:
        {
            var _ex = xPrev - xEnd;
            var _ey = yPrev - yEnd;
            var _elen = Math.sqrt(_ex*_ex + _ey*_ey);
            _ex /= _elen;
            _ey /= _elen;

            var _vx = _ey;
            var _vy = -_ex;

            var tmpx = xEnd + len * _ex;
            var tmpy = yEnd + len * _ey;

            var x1 = tmpx + _vx * w/2;
            var y1 = tmpy + _vy * w/2;

            var x3 = tmpx - _vx * w/2;
            var y3 = tmpy - _vy * w/2;

            drawer._s();
            drawer._m(trans.TransformPointX(x1, y1), trans.TransformPointY(x1, y1));
            drawer._l(trans.TransformPointX(xEnd, yEnd), trans.TransformPointY(xEnd, yEnd));
            drawer._l(trans.TransformPointX(x3, y3), trans.TransformPointY(x3, y3));
            drawer.ds();
            drawer._e();

            break;
        }
        case AscFormat.LineEndType.Diamond:
        {
            var _ex = xPrev - xEnd;
            var _ey = yPrev - yEnd;
            var _elen = Math.sqrt(_ex*_ex + _ey*_ey);
            _ex /= _elen;
            _ey /= _elen;

            var _vx = _ey;
            var _vy = -_ex;

            var tmpx = xEnd + len/2 * _ex;
            var tmpy = yEnd + len/2 * _ey;

            var x1 = xEnd + _vx * w/2;
            var y1 = yEnd + _vy * w/2;

            var x3 = xEnd - _vx * w/2;
            var y3 = yEnd - _vy * w/2;

            var tmpx2 = xEnd - len/2 * _ex;
            var tmpy2 = yEnd - len/2 * _ey;

            drawer._s();
            drawer._m(trans.TransformPointX(tmpx, tmpy), trans.TransformPointY(tmpx, tmpy));
            drawer._l(trans.TransformPointX(x1, y1), trans.TransformPointY(x1, y1));
            drawer._l(trans.TransformPointX(tmpx2, tmpy2), trans.TransformPointY(tmpx2, tmpy2));
            drawer._l(trans.TransformPointX(x3, y3), trans.TransformPointY(x3, y3));
            drawer._z();
            drawer.drawStrokeFillStyle();
            drawer._e();

            drawer._s();
            drawer._m(trans.TransformPointX(tmpx, tmpy), trans.TransformPointY(tmpx, tmpy));
            drawer._l(trans.TransformPointX(x1, y1), trans.TransformPointY(x1, y1));
            drawer._l(trans.TransformPointX(tmpx2, tmpy2), trans.TransformPointY(tmpx2, tmpy2));
            drawer._l(trans.TransformPointX(x3, y3), trans.TransformPointY(x3, y3));
            drawer._z();
            drawer.ds();
            drawer._e();

            break;
        }
        case AscFormat.LineEndType.Oval:
        {
            var _ex = xPrev - xEnd;
            var _ey = yPrev - yEnd;
            var _elen = Math.sqrt(_ex*_ex + _ey*_ey);
            _ex /= _elen;
            _ey /= _elen;

            var _vx = _ey;
            var _vy = -_ex;

            var tmpx = xEnd + len/2 * _ex;
            var tmpy = yEnd + len/2 * _ey;

            var tmpx2 = xEnd - len/2 * _ex;
            var tmpy2 = yEnd - len/2 * _ey;

            var cx1 = tmpx + _vx * 3*w/4;
            var cy1 = tmpy + _vy * 3*w/4;
            var cx2 = tmpx2 + _vx * 3*w/4;
            var cy2 = tmpy2 + _vy * 3*w/4;

            var cx3 = tmpx - _vx * 3*w/4;
            var cy3 = tmpy - _vy * 3*w/4;
            var cx4 = tmpx2 - _vx * 3*w/4;
            var cy4 = tmpy2 - _vy * 3*w/4;

            drawer._s();
            drawer._m(trans.TransformPointX(tmpx, tmpy), trans.TransformPointY(tmpx, tmpy));
            drawer._c(trans.TransformPointX(cx1, cy1), trans.TransformPointY(cx1, cy1),
                trans.TransformPointX(cx2, cy2), trans.TransformPointY(cx2, cy2),
                trans.TransformPointX(tmpx2, tmpy2), trans.TransformPointY(tmpx2, tmpy2));

            drawer._c(trans.TransformPointX(cx4, cy4), trans.TransformPointY(cx4, cy4),
                trans.TransformPointX(cx3, cy3), trans.TransformPointY(cx3, cy3),
                trans.TransformPointX(tmpx, tmpy), trans.TransformPointY(tmpx, tmpy));

            drawer.drawStrokeFillStyle();
            drawer._e();

            drawer._s();
            drawer._m(trans.TransformPointX(tmpx, tmpy), trans.TransformPointY(tmpx, tmpy));
            drawer._c(trans.TransformPointX(cx1, cy1), trans.TransformPointY(cx1, cy1),
                trans.TransformPointX(cx2, cy2), trans.TransformPointY(cx2, cy2),
                trans.TransformPointX(tmpx2, tmpy2), trans.TransformPointY(tmpx2, tmpy2));

            drawer._c(trans.TransformPointX(cx4, cy4), trans.TransformPointY(cx4, cy4),
                trans.TransformPointX(cx3, cy3), trans.TransformPointY(cx3, cy3),
                trans.TransformPointX(tmpx, tmpy), trans.TransformPointY(tmpx, tmpy));

            drawer.ds();
            drawer._e();
            break;
        }
        case AscFormat.LineEndType.Stealth:
        {
            var _ex = xPrev - xEnd;
            var _ey = yPrev - yEnd;
            var _elen = Math.sqrt(_ex*_ex + _ey*_ey);
            _ex /= _elen;
            _ey /= _elen;

            var _vx = _ey;
            var _vy = -_ex;

            var tmpx = xEnd + len * _ex;
            var tmpy = yEnd + len * _ey;

            var x1 = tmpx + _vx * w/2;
            var y1 = tmpy + _vy * w/2;

            var x3 = tmpx - _vx * w/2;
            var y3 = tmpy - _vy * w/2;

            var x4 = xEnd + (len - w/2) * _ex;
            var y4 = yEnd + (len - w/2) * _ey;

            drawer._s();
            drawer._m(trans.TransformPointX(x1, y1), trans.TransformPointY(x1, y1));
            drawer._l(trans.TransformPointX(xEnd, yEnd), trans.TransformPointY(xEnd, yEnd));
            drawer._l(trans.TransformPointX(x3, y3), trans.TransformPointY(x3, y3));
            drawer._l(trans.TransformPointX(x4, y4), trans.TransformPointY(x4, y4));
            drawer._z();
            drawer.drawStrokeFillStyle();
            drawer._e();

            drawer._s();
            drawer._m(trans.TransformPointX(x1, y1), trans.TransformPointY(x1, y1));
            drawer._l(trans.TransformPointX(xEnd, yEnd), trans.TransformPointY(xEnd, yEnd));
            drawer._l(trans.TransformPointX(x3, y3), trans.TransformPointY(x3, y3));
            drawer._l(trans.TransformPointX(x4, y4), trans.TransformPointY(x4, y4));
            drawer._z();
            drawer.ds();
            drawer._e();

            break;
        }
        case AscFormat.LineEndType.Triangle:
        {
            var _ex = xPrev - xEnd;
            var _ey = yPrev - yEnd;
            var _elen = Math.sqrt(_ex*_ex + _ey*_ey);
            _ex /= _elen;
            _ey /= _elen;

            var _vx = _ey;
            var _vy = -_ex;

            var tmpx = xEnd + len * _ex;
            var tmpy = yEnd + len * _ey;

            var x1 = tmpx + _vx * w/2;
            var y1 = tmpy + _vy * w/2;

            var x3 = tmpx - _vx * w/2;
            var y3 = tmpy - _vy * w/2;

            drawer._s();
            drawer._m(trans.TransformPointX(x1, y1), trans.TransformPointY(x1, y1));
            drawer._l(trans.TransformPointX(xEnd, yEnd), trans.TransformPointY(xEnd, yEnd));
            drawer._l(trans.TransformPointX(x3, y3), trans.TransformPointY(x3, y3));
            drawer._z();
            drawer.drawStrokeFillStyle();
            drawer._e();

            drawer._s();
            drawer._m(trans.TransformPointX(x1, y1), trans.TransformPointY(x1, y1));
            drawer._l(trans.TransformPointX(xEnd, yEnd), trans.TransformPointY(xEnd, yEnd));
            drawer._l(trans.TransformPointX(x3, y3), trans.TransformPointY(x3, y3));
            drawer._z();
            drawer.ds();
            drawer._e();
            break;
        }
    }
}


function CShapeDrawer()
{
    this.Shape = null;
    this.Graphics = null;
    this.UniFill = null;
    this.Ln = null;
    this.Transform = null;

    this.bIsTexture = false;
    this.bIsNoFillAttack = false;
    this.bIsNoStrokeAttack = false;
    this.FillUniColor = null;
    this.StrokeUniColor = null;
    this.StrokeWidth = 0;

    this.min_x = 0xFFFF;
    this.min_y = 0xFFFF;
    this.max_x = -0xFFFF;
    this.max_y = -0xFFFF;

    this.OldLineJoin = null;
    this.IsArrowsDrawing = false;
    this.IsCurrentPathCanArrows = true;

    this.bIsCheckBounds = false;

    this.IsRectShape = false;
}

CShapeDrawer.prototype =
{
    Clear : function()
    {
        //this.Shape = null;
        //this.Graphics = null;
        this.UniFill = null;
        this.Ln = null;
        this.Transform = null;

        this.bIsTexture = false;
        this.bIsNoFillAttack = false;
        this.bIsNoStrokeAttack = false;
        this.FillUniColor = null;
        this.StrokeUniColor = null;
        this.StrokeWidth = 0;

        this.min_x = 0xFFFF;
        this.min_y = 0xFFFF;
        this.max_x = -0xFFFF;
        this.max_y = -0xFFFF;

        this.OldLineJoin = null;
        this.IsArrowsDrawing = false;
        this.IsCurrentPathCanArrows = true;

        this.bIsCheckBounds = false;

        this.IsRectShape = false;
    },

    CheckPoint : function(_x,_y)
    {
        // TODO: !!!
        var x = _x;
        var y = _y;

        if (false && this.Graphics.MaxEpsLine !== undefined)
        {
            x = this.Graphics.Graphics.m_oFullTransform.TransformPointX(_x,_y);
            y = this.Graphics.Graphics.m_oFullTransform.TransformPointY(_x,_y);
        }

        if (x < this.min_x)
            this.min_x = x;
        if (y < this.min_y)
            this.min_y = y;
        if (x > this.max_x)
            this.max_x = x;
        if (y > this.max_y)
            this.max_y = y;
    },

    CheckDash : function()
    {
        if (this.Ln.prstDash != null && AscCommon.DashPatternPresets[this.Ln.prstDash])
        {
            var _arr = AscCommon.DashPatternPresets[this.Ln.prstDash].slice();
            for (var indexD = 0; indexD < _arr.length; indexD++)
                _arr[indexD] *= this.StrokeWidth;
            this.Graphics.p_dash(_arr);
        }
    },

    fromShape2 : function(shape, graphics, geom)
    {
        this.fromShape(shape, graphics);

        if (!geom)
        {
            this.IsRectShape = true;
        }
        else
        {
            if (geom.preset == "rect")
                this.IsRectShape = true;
        }
    },

    fromShape : function(shape, graphics)
    {
        this.IsRectShape = false;
        this.Shape = shape;
        this.Graphics = graphics;
        this.UniFill = shape.brush;
        this.Ln = shape.pen;
        this.Transform = shape.TransformMatrix;

        this.min_x = 0xFFFF;
        this.min_y = 0xFFFF;
        this.max_x = -0xFFFF;
        this.max_y = -0xFFFF;

        var bIsCheckBounds = false;

        if (this.UniFill == null || this.UniFill.fill == null)
            this.bIsNoFillAttack = true;
        else
        {
            var _fill = this.UniFill.fill;
            switch (_fill.type)
            {
                case c_oAscFill.FILL_TYPE_BLIP:
                {
                    this.bIsTexture = true;
                    break;
                }
                case c_oAscFill.FILL_TYPE_SOLID:
                {
                    if(_fill.color)
                    {
                        this.FillUniColor = _fill.color.RGBA;
                    }
                    else
                    {
                        this.FillUniColor = new AscFormat.CUniColor().RGBA;
                    }
                    break;
                }
                case c_oAscFill.FILL_TYPE_GRAD:
                {
                    var _c = _fill.colors;
                    if (_c.length == 0)
                        this.FillUniColor = new AscFormat.CUniColor().RGBA;
                    else
                    {
                        if(_fill.colors[0].color)
                        {
                            this.FillUniColor = _fill.colors[0].color.RGBA;
                        }
                        else
                        {
                            this.FillUniColor = new AscFormat.CUniColor().RGBA;
                        }
                    }

                    bIsCheckBounds = true;

                    break;
                }
                case c_oAscFill.FILL_TYPE_PATT:
                {
                    bIsCheckBounds = true;
                    break;
                }
                case c_oAscFill.FILL_TYPE_NOFILL:
                {
                    this.bIsNoFillAttack = true;
                    break;
                }
                default:
                {
                    this.bIsNoFillAttack = true;
                    break;
                }
            }
        }

        if (this.Ln == null || this.Ln.Fill == null || this.Ln.Fill.fill == null)
            this.bIsNoStrokeAttack = true;
        else
        {
            var _fill = this.Ln.Fill.fill;
            switch (_fill.type)
            {
                case c_oAscFill.FILL_TYPE_BLIP:
                {
                    this.StrokeUniColor = new AscFormat.CUniColor().RGBA;
                    break;
                }
                case c_oAscFill.FILL_TYPE_SOLID:
                {
                    if(_fill.color)
                    {
                        this.StrokeUniColor = _fill.color.RGBA;
                    }
                    else
                    {
                        this.StrokeUniColor = new AscFormat.CUniColor().RGBA;
                    }
                    break;
                }
                case c_oAscFill.FILL_TYPE_GRAD:
                {
                    var _c = _fill.colors;
                    if (_c == 0)
                        this.StrokeUniColor = new AscFormat.CUniColor().RGBA;
                    else
                    {
                        if(_fill.colors[0].color)
                        {
                            this.StrokeUniColor = _fill.colors[0].color.RGBA;
                        }
                        else
                        {
                            this.StrokeUniColor = new AscFormat.CUniColor().RGBA;
                        }
                    }

                    break;
                }
                case c_oAscFill.FILL_TYPE_PATT:
                {
                    if(_fill.fgClr)
                    {
                        this.StrokeUniColor = _fill.fgClr.RGBA;
                    }
                    else
                    {
                        this.StrokeUniColor = new AscFormat.CUniColor().RGBA;
                    }
                    break;
                }
                case c_oAscFill.FILL_TYPE_NOFILL:
                {
                    this.bIsNoStrokeAttack = true;
                    break;
                }
                default:
                {
                    this.bIsNoStrokeAttack = true;
                    break;
                }
            }

            this.StrokeWidth = (this.Ln.w == null) ? 12700 : parseInt(this.Ln.w);
            this.StrokeWidth /= 36000.0;

            this.p_width(1000 * this.StrokeWidth);
            
            this.CheckDash();

            if (graphics.IsSlideBoundsCheckerType && !this.bIsNoStrokeAttack)
                graphics.LineWidth = this.StrokeWidth;

            if ((this.Ln.headEnd != null && this.Ln.headEnd.type != null) || (this.Ln.tailEnd != null && this.Ln.tailEnd.type != null))
            {
                if (true === graphics.IsTrack)
                    graphics.Graphics.ArrayPoints = [];
                else
                    graphics.ArrayPoints = [];
            }

            if (this.Graphics.m_oContext != null && this.Ln.Join != null && this.Ln.Join.type != null)
                this.OldLineJoin = this.Graphics.m_oContext.lineJoin;
        }

        if (this.bIsTexture || bIsCheckBounds)
        {
            // сначала нужно определить границы
            this.bIsCheckBounds = true;
            this.check_bounds();
            this.bIsCheckBounds = false;
        }
    },

    draw : function(geom)
    {
        if (this.bIsNoStrokeAttack && this.bIsNoFillAttack)
            return;

        var bIsPatt = false;
        if (this.UniFill != null && this.UniFill.fill != null &&
            ((this.UniFill.fill.type == c_oAscFill.FILL_TYPE_PATT) || (this.UniFill.fill.type == c_oAscFill.FILL_TYPE_GRAD)))
        {
            bIsPatt = true;
        }

        if (this.Graphics.RENDERER_PDF_FLAG && (this.bIsTexture || bIsPatt))
        {
            this.Graphics.put_TextureBoundsEnabled(true);
            this.Graphics.put_TextureBounds(this.min_x, this.min_y, this.max_x - this.min_x, this.max_y - this.min_y);
        }

        if(geom)
        {
            geom.draw(this);
        }
        else
        {
            this._s();
            this._m(0, 0);
            this._l(this.Shape.extX, 0);
            this._l(this.Shape.extX, this.Shape.extY);
            this._l(0, this.Shape.extY);
            this._z();
            this.drawFillStroke(true, "norm", true && !this.bIsNoStrokeAttack);
            this._e();
        }
        this.Graphics.ArrayPoints = null;

        if (this.Graphics.RENDERER_PDF_FLAG && (this.bIsTexture || bIsPatt))
        {
            this.Graphics.put_TextureBoundsEnabled(false);
        }

        if (this.Graphics.IsSlideBoundsCheckerType && this.Graphics.AutoCheckLineWidth)
        {
            this.Graphics.CorrectBounds2();
        }

        this.Graphics.p_dash(null);
    },

    p_width : function(w)
    {
        this.Graphics.p_width(w);
    },

    _m : function(x, y)
    {
        if (this.bIsCheckBounds)
        {
            this.CheckPoint(x, y);
            return;
        }

        this.Graphics._m(x, y);
    },

    _l : function(x, y)
    {
        if (this.bIsCheckBounds)
        {
            this.CheckPoint(x, y);
            return;
        }

        this.Graphics._l(x, y);
    },

    _c : function(x1, y1, x2, y2, x3, y3)
    {
        if (this.bIsCheckBounds)
        {
            this.CheckPoint(x1, y1);
            this.CheckPoint(x2, y2);
            this.CheckPoint(x3, y3);
            return;
        }

        this.Graphics._c(x1, y1, x2, y2, x3, y3);
    },

    _c2 : function(x1, y1, x2, y2)
    {
        if (this.bIsCheckBounds)
        {
            this.CheckPoint(x1, y1);
            this.CheckPoint(x2, y2);
            return;
        }

        this.Graphics._c2(x1, y1, x2, y2);
    },

    _z : function()
    {
        this.IsCurrentPathCanArrows = false;
        if (this.bIsCheckBounds)
            return;

        this.Graphics._z();
    },

    _s : function()
    {
        this.IsCurrentPathCanArrows = true;
        this.Graphics._s();
        if (this.Graphics.ArrayPoints != null)
            this.Graphics.ArrayPoints = [];
    },
    _e : function()
    {
        this.IsCurrentPathCanArrows = true;
        this.Graphics._e();
        if (this.Graphics.ArrayPoints != null)
            this.Graphics.ArrayPoints = [];
    },

    df : function(mode)
    {
        if (mode == "none" || this.bIsNoFillAttack)
            return;

        if (this.Graphics.IsTrack)
            this.Graphics.m_oOverlay.ClearAll = true;

        if (this.Graphics.IsSlideBoundsCheckerType === true)
            return;

        var bIsIntegerGridTRUE = false;
        if (this.bIsTexture)
        {
            if (this.Graphics.m_bIntegerGrid === true)
            {
                this.Graphics.SetIntegerGrid(false);
                bIsIntegerGridTRUE = true;
            }

            if (this.Graphics.RENDERER_PDF_FLAG)
            {
                if (null == this.UniFill.fill.tile || this.Graphics.m_oContext === undefined)
                {
                    this.Graphics.put_brushTexture(getFullImageSrc2(this.UniFill.fill.RasterImageId), 0);
                }
                else
                {
                    this.Graphics.put_brushTexture(getFullImageSrc2(this.UniFill.fill.RasterImageId), 1);
                }

                if (bIsIntegerGridTRUE)
                {
                    this.Graphics.SetIntegerGrid(true);
                }
                return;
            }

			var bIsUnusePattern = false;
			if (AscCommon.AscBrowser.isIE)
			{
				// ie падает иначе !!!
				if (this.UniFill.fill.RasterImageId)
				{
					if (this.UniFill.fill.RasterImageId.lastIndexOf(".svg") == this.UniFill.fill.RasterImageId.length - 4)
						bIsUnusePattern = true;
				}
			}

            if (bIsUnusePattern || null == this.UniFill.fill.tile || this.Graphics.m_oContext === undefined)
            {
                if (this.IsRectShape)
                {
                    this.Graphics._s();

                    if ((null == this.UniFill.transparent) || (this.UniFill.transparent == 255))
                    {
                        this.Graphics.drawImage(getFullImageSrc2(this.UniFill.fill.RasterImageId), this.min_x, this.min_y, (this.max_x - this.min_x), (this.max_y - this.min_y), undefined, this.UniFill.fill.srcRect, this.UniFill.fill.canvas);
                    }
                    else
                    {
                        var _old_global_alpha = this.Graphics.m_oContext.globalAlpha;
                        this.Graphics.m_oContext.globalAlpha = this.UniFill.transparent / 255;
                        this.Graphics.drawImage(getFullImageSrc2(this.UniFill.fill.RasterImageId), this.min_x, this.min_y, (this.max_x - this.min_x), (this.max_y - this.min_y), undefined, this.UniFill.fill.srcRect, this.UniFill.fill.canvas);
                        this.Graphics.m_oContext.globalAlpha = _old_global_alpha;
                    }
                }
                else
                {
                    this.Graphics.save();
                    this.Graphics.clip();

                    if (this.Graphics.IsNoSupportTextDraw == true || true == this.Graphics.IsTrack || (null == this.UniFill.transparent) || (this.UniFill.transparent == 255))
                    {
                        this.Graphics.drawImage(getFullImageSrc2(this.UniFill.fill.RasterImageId), this.min_x, this.min_y, (this.max_x - this.min_x), (this.max_y - this.min_y), undefined, this.UniFill.fill.srcRect, this.UniFill.fill.canvas);
                    }
                    else
                    {
                        var _old_global_alpha = this.Graphics.m_oContext.globalAlpha;
                        this.Graphics.m_oContext.globalAlpha = this.UniFill.transparent / 255;
                        this.Graphics.drawImage(getFullImageSrc2(this.UniFill.fill.RasterImageId), this.min_x, this.min_y, (this.max_x - this.min_x), (this.max_y - this.min_y), undefined, this.UniFill.fill.srcRect, this.UniFill.fill.canvas);
                        this.Graphics.m_oContext.globalAlpha = _old_global_alpha;
                    }

                    this.Graphics.restore();
                }
            }
            else
            {
                var _img = editor.ImageLoader.map_image_index[getFullImageSrc2(this.UniFill.fill.RasterImageId)];
                var _img_native = this.UniFill.fill.canvas;
                if ((!_img_native) && (_img == undefined || _img.Image == null || _img.Status == AscFonts.ImageLoadStatus.Loading))
                {
                    this.Graphics.save();
                    this.Graphics.clip();

                    if (this.Graphics.IsNoSupportTextDraw === true || true == this.Graphics.IsTrack || (null == this.UniFill.transparent) || (this.UniFill.transparent == 255))
                    {
                        this.Graphics.drawImage(getFullImageSrc2(this.UniFill.fill.RasterImageId), this.min_x, this.min_y, (this.max_x - this.min_x), (this.max_y - this.min_y));
                    }
                    else
                    {
                        var _old_global_alpha = this.Graphics.m_oContext.globalAlpha;
                        this.Graphics.m_oContext.globalAlpha = this.UniFill.transparent / 255;
                        this.Graphics.drawImage(getFullImageSrc2(this.UniFill.fill.RasterImageId), this.min_x, this.min_y, (this.max_x - this.min_x), (this.max_y - this.min_y));
                        this.Graphics.m_oContext.globalAlpha = _old_global_alpha;
                    }

                    this.Graphics.restore();
                }
                else
                {
                    var _is_ctx = false;
                    if (this.Graphics.IsNoSupportTextDraw === true || undefined === this.Graphics.m_oContext || (null == this.UniFill.transparent) || (this.UniFill.transparent == 255))
                    {
                        _is_ctx = false;
                    }
                    else
                    {
                        _is_ctx = true;
                    }

                    var _ctx = (this.Graphics.IsTrack === true) ? this.Graphics.Graphics.m_oContext : this.Graphics.m_oContext;

                    var patt = !_img_native ? _ctx.createPattern(_img.Image, "repeat") : _ctx.createPattern(_img_native, "repeat");

                    _ctx.save();

                    var __graphics = (this.Graphics.MaxEpsLine === undefined) ? this.Graphics : this.Graphics.Graphics;
                    var bIsThumbnail = (__graphics.IsThumbnail === true) ? true : false;

                    var koefX = editor.WordControl.m_nZoomValue / 100;
                    var koefY = editor.WordControl.m_nZoomValue / 100;

                    if (bIsThumbnail)
                    {
                        koefX = __graphics.m_dDpiX / AscCommon.g_dDpiX;
                        koefY = __graphics.m_dDpiY / AscCommon.g_dDpiX;

                        if (editor.WordControl.bIsRetinaSupport)
                        {
                            koefX /= AscCommon.AscBrowser.retinaPixelRatio;
                            koefY /= AscCommon.AscBrowser.retinaPixelRatio;
                        }
                    }

                    // TODO: !!!
                    _ctx.translate(this.min_x, this.min_y);

                    _ctx.scale(koefX * __graphics.TextureFillTransformScaleX, koefY * __graphics.TextureFillTransformScaleY);

                    if (_is_ctx === true)
                    {
                        var _old_global_alpha = _ctx.globalAlpha;
                        _ctx.globalAlpha = this.UniFill.transparent / 255;
                        _ctx.fillStyle = patt;
                        _ctx.fill();
                        _ctx.globalAlpha = _old_global_alpha;
                    }
                    else
                    {
                        _ctx.fillStyle = patt;
                        _ctx.fill();
                    }

                    _ctx.restore();
                }
            }

            if (bIsIntegerGridTRUE)
            {
                this.Graphics.SetIntegerGrid(true);
            }
            return;
        }

        if (this.UniFill != null && this.UniFill.fill != null)
        {
            var _fill = this.UniFill.fill;
            if (_fill.type == c_oAscFill.FILL_TYPE_PATT)
            {
                if (this.Graphics.m_bIntegerGrid === true)
                {
                    this.Graphics.SetIntegerGrid(false);
                    bIsIntegerGridTRUE = true;
                }

                var _is_ctx = false;
                if (this.Graphics.IsNoSupportTextDraw === true || undefined === this.Graphics.m_oContext || (null == this.UniFill.transparent) || (this.UniFill.transparent == 255))
                {
                    _is_ctx = false;
                }
                else
                {
                    _is_ctx = true;
                }

                var _ctx = (this.Graphics.IsTrack === true) ? this.Graphics.Graphics.m_oContext : this.Graphics.m_oContext;

                var _patt_name = AscCommon.global_hatch_names[_fill.ftype];
                if (undefined == _patt_name)
                    _patt_name = "cross";

                var _fc = _fill.fgClr.RGBA;
                var _bc = _fill.bgClr.RGBA;

                var __fa = (null === this.UniFill.transparent) ? _fc.A : 255;
                var __ba = (null === this.UniFill.transparent) ? _bc.A : 255;

                var _test_pattern = AscCommon.GetHatchBrush(_patt_name, _fc.R, _fc.G, _fc.B, __fa, _bc.R, _bc.G, _bc.B, __ba);
                var patt = _ctx.createPattern(_test_pattern.Canvas, "repeat");

                _ctx.save();

                var koefX = editor.WordControl.m_nZoomValue / 100;
                var koefY = editor.WordControl.m_nZoomValue / 100;
                if (this.Graphics.IsThumbnail)
                {
                    koefX = 1;
                    koefY = 1;
                }

                // TODO: !!!
                _ctx.translate(this.min_x, this.min_y);

                if (this.Graphics.MaxEpsLine === undefined)
                {
                    _ctx.scale(koefX * this.Graphics.TextureFillTransformScaleX, koefY * this.Graphics.TextureFillTransformScaleY);
                }
                else
                {
                    _ctx.scale(koefX * this.Graphics.Graphics.TextureFillTransformScaleX, koefY * this.Graphics.Graphics.TextureFillTransformScaleY);
                }

                if (_is_ctx === true)
                {
                    var _old_global_alpha = _ctx.globalAlpha;

                    if (null != this.UniFill.transparent)
                        _ctx.globalAlpha = this.UniFill.transparent / 255;

                    _ctx.fillStyle = patt;
                    _ctx.fill();
                    _ctx.globalAlpha = _old_global_alpha;
                }
                else
                {
                    _ctx.fillStyle = patt;
                    _ctx.fill();
                }

                _ctx.restore();

                if (bIsIntegerGridTRUE)
                {
                    this.Graphics.SetIntegerGrid(true);
                }
                return;
            }
            else if (_fill.type == c_oAscFill.FILL_TYPE_GRAD)
            {
                if (this.Graphics.m_bIntegerGrid === true)
                {
                    this.Graphics.SetIntegerGrid(false);
                    bIsIntegerGridTRUE = true;
                }

                var _is_ctx = false;
                if (this.Graphics.IsNoSupportTextDraw === true || undefined === this.Graphics.m_oContext || (null == this.UniFill.transparent) || (this.UniFill.transparent == 255))
                {
                    _is_ctx = false;
                }
                else
                {
                    _is_ctx = true;
                }

                var _ctx = (this.Graphics.IsTrack === true) ? this.Graphics.Graphics.m_oContext : this.Graphics.m_oContext;

                var gradObj = null;
                if (_fill.lin)
                {
                    var _angle = _fill.lin.angle;
                    if (_fill.rotateWithShape === false)
                    {
                        var matrix_transform = (this.Graphics.IsTrack === true) ? this.Graphics.Graphics.m_oTransform : this.Graphics.m_oTransform;
                        if (matrix_transform)
                        {
                            //_angle -= (60000 * this.Graphics.m_oTransform.GetRotation());
                            _angle = AscCommon.GradientGetAngleNoRotate(_angle, matrix_transform);
                        }
                    }

                    var points = this.getGradientPoints(this.min_x, this.min_y, this.max_x, this.max_y, _angle, _fill.lin.scale);
                    gradObj = _ctx.createLinearGradient(points.x0, points.y0, points.x1, points.y1);
                }
                else if (_fill.path)
                {
                    var _cx = (this.min_x + this.max_x) / 2;
                    var _cy = (this.min_y + this.max_y) / 2;
                    var _r = Math.max(this.max_x - this.min_x, this.max_y - this.min_y) / 2;
                    gradObj = _ctx.createRadialGradient(_cx, _cy, 1, _cx, _cy, _r);
                }
                else
                {
                    //gradObj = _ctx.createLinearGradient(this.min_x, this.min_y, this.max_x, this.min_y);
                    var points = this.getGradientPoints(this.min_x, this.min_y, this.max_x, this.max_y, 0, false);
                    gradObj = _ctx.createLinearGradient(points.x0, points.y0, points.x1, points.y1);
                }

                for (var i = 0; i < _fill.colors.length; i++)
                {
                    gradObj.addColorStop(_fill.colors[i].pos / 100000, _fill.colors[i].color.getCSSColor(this.UniFill.transparent));
                }

                _ctx.fillStyle = gradObj;

                if (null !== this.UniFill.transparent && undefined !== this.UniFill.transparent)
                {
                    var _old_global_alpha = this.Graphics.m_oContext.globalAlpha;
                    _ctx.globalAlpha = this.UniFill.transparent / 255;
                    _ctx.fill();
                    _ctx.globalAlpha = _old_global_alpha;
                }
                else
                {
                    _ctx.fill();
                }

                if (bIsIntegerGridTRUE)
                {
                    this.Graphics.SetIntegerGrid(true);
                }
                return;
            }
        }

        var rgba = this.FillUniColor;
        if (mode == "darken")
        {
            var _color1 = new CShapeColor(rgba.R, rgba.G, rgba.B);
            var rgb = _color1.darken();
            rgba = { R: rgb.r, G: rgb.g, B: rgb.b, A: rgba.A };
        }
        else if (mode == "darkenLess")
        {
            var _color1 = new CShapeColor(rgba.R, rgba.G, rgba.B);
            var rgb = _color1.darkenLess();
            rgba = { R: rgb.r, G: rgb.g, B: rgb.b, A: rgba.A };
        }
        else if (mode == "lighten")
        {
            var _color1 = new CShapeColor(rgba.R, rgba.G, rgba.B);
            var rgb = _color1.lighten();
            rgba = { R: rgb.r, G: rgb.g, B: rgb.b, A: rgba.A };
        }
        else if (mode == "lightenLess")
        {
            var _color1 = new CShapeColor(rgba.R, rgba.G, rgba.B);
            var rgb = _color1.lightenLess();
            rgba = { R: rgb.r, G: rgb.g, B: rgb.b, A: rgba.A };
        }
        if(rgba)
        {
            if (this.UniFill != null && this.UniFill.transparent != null)
                rgba.A = this.UniFill.transparent;
            this.Graphics.b_color1(rgba.R, rgba.G, rgba.B, rgba.A);
        }
        this.Graphics.df();
    },

    ds : function()
    {
        if (this.bIsNoStrokeAttack)
            return;

        if (this.Graphics.IsTrack)
            this.Graphics.m_oOverlay.ClearAll = true;

        if (null != this.OldLineJoin && !this.IsArrowsDrawing)
        {
            switch (this.Ln.Join.type)
            {
                case AscFormat.LineJoinType.Round:
                {
                    this.Graphics.m_oContext.lineJoin = "round";
                    break;
                }
                case AscFormat.LineJoinType.Bevel:
                {
                    this.Graphics.m_oContext.lineJoin = "bevel";
                    break;
                }
                case AscFormat.LineJoinType.Empty:
                {
                    this.Graphics.m_oContext.lineJoin = "miter";
                    break;
                }
                case AscFormat.LineJoinType.Miter:
                {
                    this.Graphics.m_oContext.lineJoin = "miter";
                    break;
                }
            }
        }

        var rgba = this.StrokeUniColor;
        this.Graphics.p_color(rgba.R, rgba.G, rgba.B, rgba.A);

        if (this.IsRectShape && this.Graphics.AddSmartRect !== undefined)
        {
            if (undefined !== this.Shape.extX)
                this.Graphics.AddSmartRect(0, 0, this.Shape.extX, this.Shape.extY, this.StrokeWidth);
            else
                this.Graphics.ds();
        }
        else
        {
            this.Graphics.ds();
        }

        if (null != this.OldLineJoin && !this.IsArrowsDrawing)
        {
            this.Graphics.m_oContext.lineJoin = this.OldLineJoin;
        }

        var arr = (this.Graphics.IsTrack === true) ? this.Graphics.Graphics.ArrayPoints : this.Graphics.ArrayPoints;
        if (arr != null && arr.length > 1 && this.IsCurrentPathCanArrows === true)
        {
            this.IsArrowsDrawing = true;
            this.Graphics.p_dash(null);
            // значит стрелки есть. теперь:
            // определяем толщину линии "как есть"
            // трансформируем точки в окончательные.
            // и отправляем на отрисовку (с матрицей)

			var _graphicsCtx = (this.Graphics.IsTrack === true) ? this.Graphics.Graphics : this.Graphics;

			var trans = _graphicsCtx.m_oFullTransform;
            var trans1 = AscCommon.global_MatrixTransformer.Invert(trans);

            var x1 = trans.TransformPointX(0, 0);
            var y1 = trans.TransformPointY(0, 0);
            var x2 = trans.TransformPointX(1, 1);
            var y2 = trans.TransformPointY(1, 1);
            var dKoef = Math.sqrt(((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))/2);
            var _pen_w = (this.Graphics.IsTrack === true) ? (this.Graphics.Graphics.m_oContext.lineWidth * dKoef) : (this.Graphics.m_oContext.lineWidth * dKoef);
			var _max_w = undefined;
			if (_graphicsCtx.IsThumbnail === true)
			    _max_w = 2;

            var _max_delta_eps2 = 0.001;

            if (this.Ln.headEnd != null)
            {
                var _x1 = trans.TransformPointX(arr[0].x, arr[0].y);
                var _y1 = trans.TransformPointY(arr[0].x, arr[0].y);
                var _x2 = trans.TransformPointX(arr[1].x, arr[1].y);
                var _y2 = trans.TransformPointY(arr[1].x, arr[1].y);

                var _max_delta_eps = Math.max(this.Ln.headEnd.GetLen(_pen_w), 5);

                var _max_delta = Math.max(Math.abs(_x1 - _x2), Math.abs(_y1 - _y2));
                var cur_point = 2;
                while (_max_delta < _max_delta_eps && cur_point < arr.length)
                {
                    _x2 = trans.TransformPointX(arr[cur_point].x, arr[cur_point].y);
                    _y2 = trans.TransformPointY(arr[cur_point].x, arr[cur_point].y);
                    _max_delta = Math.max(Math.abs(_x1 - _x2), Math.abs(_y1 - _y2));
                    cur_point++;
                }

                if (_max_delta > _max_delta_eps2)
                {
					_graphicsCtx.ArrayPoints = null;
					DrawLineEnd(_x1, _y1, _x2, _y2, this.Ln.headEnd.type, this.Ln.headEnd.GetWidth(_pen_w, _max_w), this.Ln.headEnd.GetLen(_pen_w, _max_w), this, trans1);
					_graphicsCtx.ArrayPoints = arr;
                    }
                    }
            if (this.Ln.tailEnd != null)
            {
                var _1 = arr.length-1;
                var _2 = arr.length-2;
                var _x1 = trans.TransformPointX(arr[_1].x, arr[_1].y);
                var _y1 = trans.TransformPointY(arr[_1].x, arr[_1].y);
                var _x2 = trans.TransformPointX(arr[_2].x, arr[_2].y);
                var _y2 = trans.TransformPointY(arr[_2].x, arr[_2].y);

                var _max_delta_eps = Math.max(this.Ln.tailEnd.GetLen(_pen_w), 5);

                var _max_delta = Math.max(Math.abs(_x1 - _x2), Math.abs(_y1 - _y2));
                var cur_point = _2 - 1;
                while (_max_delta < _max_delta_eps && cur_point >= 0)
                {
                    _x2 = trans.TransformPointX(arr[cur_point].x, arr[cur_point].y);
                    _y2 = trans.TransformPointY(arr[cur_point].x, arr[cur_point].y);
                    _max_delta = Math.max(Math.abs(_x1 - _x2), Math.abs(_y1 - _y2));
                    cur_point--;
                }

                if (_max_delta > _max_delta_eps2)
                {
					_graphicsCtx.ArrayPoints = null;
					DrawLineEnd(_x1, _y1, _x2, _y2, this.Ln.tailEnd.type, this.Ln.tailEnd.GetWidth(_pen_w, _max_w), this.Ln.tailEnd.GetLen(_pen_w, _max_w), this, trans1);
					_graphicsCtx.ArrayPoints = arr;
                    }
                    }
            this.IsArrowsDrawing = false;
            this.CheckDash();
        }
    },

    drawFillStroke : function(bIsFill, fill_mode, bIsStroke)
    {
        if (this.Graphics.IsTrack)
            this.Graphics.m_oOverlay.ClearAll = true;

        if(this.Graphics.IsSlideBoundsCheckerType)
            return;
        if (this.Graphics.RENDERER_PDF_FLAG === undefined)
        {
            if (bIsFill)
                this.df(fill_mode);
            if (bIsStroke)
                this.ds();
        }
        else
        {
            if (this.bIsNoStrokeAttack)
                bIsStroke = false;

            if (bIsStroke)
            {
                if (null != this.OldLineJoin && !this.IsArrowsDrawing)
                {
                    this.Graphics.put_PenLineJoin(AscFormat.ConvertJoinAggType(this.Ln.Join.type));
                }

                var rgba = this.StrokeUniColor;
                this.Graphics.p_color(rgba.R, rgba.G, rgba.B, rgba.A);
            }

            if (fill_mode == "none" || this.bIsNoFillAttack)
                bIsFill = false;

            var bIsPattern = false;

            if (bIsFill)
            {
                if (this.bIsTexture)
                {
                    if (null == this.UniFill.fill.tile)
                    {
                        if (null == this.UniFill.fill.srcRect)
                        {
                            if (this.UniFill.fill.RasterImageId && this.UniFill.fill.RasterImageId.indexOf(".svg") != 0)
                            {
                                this.Graphics.put_brushTexture(getFullImageSrc2(this.UniFill.fill.RasterImageId), 0);
                            }
                            else
                            {
                                if (this.UniFill.fill.canvas)
                                {
                                    this.Graphics.put_brushTexture(this.UniFill.fill.canvas.toDataURL("image/png"), 0);
                                }
                                else
                                {
                                    this.Graphics.put_brushTexture(getFullImageSrc2(this.UniFill.fill.RasterImageId), 0);
                                }
                            }
                        }
                        else
                        {
                            this.Graphics.drawImage(getFullImageSrc2(this.UniFill.fill.RasterImageId), this.min_x, this.min_y, (this.max_x - this.min_x), (this.max_y - this.min_y), undefined, this.UniFill.fill.srcRect);
                            bIsFill = false;
                        }
                    }
                    else
                    {
                        if (this.UniFill.fill.canvas)
                        {
                            this.Graphics.put_brushTexture(this.UniFill.fill.canvas.toDataURL("image/png"), 1);
                        }
                        else
                        {
                            this.Graphics.put_brushTexture(getFullImageSrc2(this.UniFill.fill.RasterImageId), 1);
                        }
                    }
                    this.Graphics.put_BrushTextureAlpha(this.UniFill.transparent);
                }
                else
                {
                    var _fill = this.UniFill.fill;
                    if (_fill.type == c_oAscFill.FILL_TYPE_PATT)
                    {
                        var _patt_name = AscCommon.global_hatch_names[_fill.ftype];
                        if (undefined == _patt_name)
                            _patt_name = "cross";

                        var _fc = _fill.fgClr.RGBA;
                        var _bc = _fill.bgClr.RGBA;

                        var __fa = (null === this.UniFill.transparent) ? _fc.A : 255;
                        var __ba = (null === this.UniFill.transparent) ? _bc.A : 255;

                        var _pattern = AscCommon.GetHatchBrush(_patt_name, _fc.R, _fc.G, _fc.B, __fa, _bc.R, _bc.G, _bc.B, __ba);

                        var _url64 = "";
                        try
                        {
                            _url64 = _pattern.toDataURL();
                        }
                        catch (err)
                        {
                            _url64 = "";
                        }

                        this.Graphics.put_brushTexture(_url64, 1);

                        if (null != this.UniFill.transparent)
                            this.Graphics.put_BrushTextureAlpha(this.UniFill.transparent);
                        else
                            this.Graphics.put_BrushTextureAlpha(255);

                        bIsPattern = true;
                    }
                    else if (_fill.type == c_oAscFill.FILL_TYPE_GRAD)
                    {
                        var points = null;
                        if (_fill.lin)
                        {
                            var _angle = _fill.lin.angle;
                            if (_fill.rotateWithShape === false && this.Graphics.m_oTransform)
                            {
                                //_angle -= (60000 * this.Graphics.m_oTransform.GetRotation());
                                _angle = AscCommon.GradientGetAngleNoRotate(_angle, this.Graphics.m_oTransform);
                            }

                            points = this.getGradientPoints(this.min_x, this.min_y, this.max_x, this.max_y, _angle, _fill.lin.scale);
                        }
                        else if (_fill.path)
                        {
                            var _cx = (this.min_x + this.max_x) / 2;
                            var _cy = (this.min_y + this.max_y) / 2;
                            var _r = Math.max(this.max_x - this.min_x, this.max_y - this.min_y) / 2;

                            points = { x0 : _cx, y0 : _cy, x1 : _cx, y1 : _cy, r0 : 1, r1 : _r };
                        }
                        else
                        {
                            points = this.getGradientPoints(this.min_x, this.min_y, this.max_x, this.max_y, 0, false);
                        }

                        this.Graphics.put_BrushGradient(_fill, points, this.UniFill.transparent);
                    }
                    else
                    {
                        var rgba = this.FillUniColor;
                        if (fill_mode == "darken")
                        {
                            var _color1 = new CShapeColor(rgba.R, rgba.G, rgba.B);
                            var rgb = _color1.darken();
                            rgba = { R: rgb.r, G: rgb.g, B: rgb.b, A: rgba.A };
                        }
                        else if (fill_mode == "darkenLess")
                        {
                            var _color1 = new CShapeColor(rgba.R, rgba.G, rgba.B);
                            var rgb = _color1.darkenLess();
                            rgba = { R: rgb.r, G: rgb.g, B: rgb.b, A: rgba.A };
                        }
                        else if (fill_mode == "lighten")
                        {
                            var _color1 = new CShapeColor(rgba.R, rgba.G, rgba.B);
                            var rgb = _color1.lighten();
                            rgba = { R: rgb.r, G: rgb.g, B: rgb.b, A: rgba.A };
                        }
                        else if (fill_mode == "lightenLess")
                        {
                            var _color1 = new CShapeColor(rgba.R, rgba.G, rgba.B);
                            var rgb = _color1.lightenLess();
                            rgba = { R: rgb.r, G: rgb.g, B: rgb.b, A: rgba.A };
                        }
                        if (rgba)
                        {
                            if (this.UniFill != null && this.UniFill.transparent != null)
                                rgba.A = this.UniFill.transparent;
                            this.Graphics.b_color1(rgba.R, rgba.G, rgba.B, rgba.A);
                        }
                    }
                }
            }

            if (bIsFill && bIsStroke)
            {
                if (this.bIsTexture || bIsPattern)
                {
                    this.Graphics.drawpath(256);
                    this.Graphics.drawpath(1);
                }
                else
                {
                    this.Graphics.drawpath(256 + 1);
                }
            }
            else if (bIsFill)
            {
                this.Graphics.drawpath(256);
            }
            else if (bIsStroke)
            {
                this.Graphics.drawpath(1);
            }
            else
            {
                // такого быть не должно по идее
                this.Graphics.b_color1(0, 0, 0, 0);
                this.Graphics.drawpath(256);
            }

            var arr = this.Graphics.ArrayPoints;
            if (arr != null && arr.length > 1 && this.IsCurrentPathCanArrows === true)
            {
                this.IsArrowsDrawing = true;
                this.Graphics.p_dash(null);
                // значит стрелки есть. теперь:
                // определяем толщину линии "как есть"
                // трансформируем точки в окончательные.
                // и отправляем на отрисовку (с матрицей)

                var trans = (this.Graphics.RENDERER_PDF_FLAG === undefined) ? this.Graphics.m_oFullTransform : this.Graphics.GetTransform();
                var trans1 = AscCommon.global_MatrixTransformer.Invert(trans);

                var lineSize = (this.Graphics.RENDERER_PDF_FLAG === undefined) ? this.Graphics.m_oContext.lineWidth : this.Graphics.GetLineWidth();

                var x1 = trans.TransformPointX(0, 0);
                var y1 = trans.TransformPointY(0, 0);
                var x2 = trans.TransformPointX(1, 1);
                var y2 = trans.TransformPointY(1, 1);
                var dKoef = Math.sqrt(((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))/2);
                var _pen_w = lineSize * dKoef;

                if (this.Ln.headEnd != null)
                {
                    var _x1 = trans.TransformPointX(arr[0].x, arr[0].y);
                    var _y1 = trans.TransformPointY(arr[0].x, arr[0].y);
                    var _x2 = trans.TransformPointX(arr[1].x, arr[1].y);
                    var _y2 = trans.TransformPointY(arr[1].x, arr[1].y);

                    var _max_delta = Math.max(Math.abs(_x1 - _x2), Math.abs(_y1 - _y2));
                    var cur_point = 2;
                    while (_max_delta < 0.001 && cur_point < arr.length)
                    {
                        _x2 = trans.TransformPointX(arr[cur_point].x, arr[cur_point].y);
                        _y2 = trans.TransformPointY(arr[cur_point].x, arr[cur_point].y);
                        _max_delta = Math.max(Math.abs(_x1 - _x2), Math.abs(_y1 - _y2));
                        cur_point++;
                    }

                    if (_max_delta > 0.001)
                    {
                        this.Graphics.ArrayPoints = null;
                        DrawLineEnd(_x1, _y1, _x2, _y2, this.Ln.headEnd.type, this.Ln.headEnd.GetWidth(_pen_w, 7 / AscCommon.g_dKoef_mm_to_pix), this.Ln.headEnd.GetLen(_pen_w, 7 / AscCommon.g_dKoef_mm_to_pix), this, trans1);
                        this.Graphics.ArrayPoints = arr;
                    }
                }
                if (this.Ln.tailEnd != null)
                {
                    var _1 = arr.length-1;
                    var _2 = arr.length-2;
                    var _x1 = trans.TransformPointX(arr[_1].x, arr[_1].y);
                    var _y1 = trans.TransformPointY(arr[_1].x, arr[_1].y);
                    var _x2 = trans.TransformPointX(arr[_2].x, arr[_2].y);
                    var _y2 = trans.TransformPointY(arr[_2].x, arr[_2].y);

                    var _max_delta = Math.max(Math.abs(_x1 - _x2), Math.abs(_y1 - _y2));
                    var cur_point = _2 - 1;
                    while (_max_delta < 0.001 && cur_point >= 0)
                    {
                        _x2 = trans.TransformPointX(arr[cur_point].x, arr[cur_point].y);
                        _y2 = trans.TransformPointY(arr[cur_point].x, arr[cur_point].y);
                        _max_delta = Math.max(Math.abs(_x1 - _x2), Math.abs(_y1 - _y2));
                        cur_point--;
                    }

                    if (_max_delta > 0.001)
                    {
                        this.Graphics.ArrayPoints = null;
                        DrawLineEnd(_x1, _y1, _x2, _y2, this.Ln.tailEnd.type, this.Ln.tailEnd.GetWidth(_pen_w, 7 / AscCommon.g_dKoef_mm_to_pix), this.Ln.tailEnd.GetLen(_pen_w, 7 / AscCommon.g_dKoef_mm_to_pix), this, trans1);
                        this.Graphics.ArrayPoints = arr;
                    }
                }
                this.IsArrowsDrawing = false;
                this.CheckDash();
            }
        }
    },

    drawStrokeFillStyle : function()
    {
        if (this.Graphics.RENDERER_PDF_FLAG === undefined)
        {
            var gr = (this.Graphics.IsTrack == true) ? this.Graphics.Graphics : this.Graphics;

            var tmp = gr.m_oBrush.Color1;
            var p_c = gr.m_oPen.Color;
            gr.b_color1(p_c.R, p_c.G, p_c.B, p_c.A);
            gr.df();
            gr.b_color1(tmp.R, tmp.G, tmp.B, tmp.A);
        }
        else
        {
            var tmp = this.Graphics.GetBrush().Color1;
            var p_c = this.Graphics.GetPen().Color;
            this.Graphics.b_color1(p_c.R, p_c.G, p_c.B, p_c.A);
            this.Graphics.df();
            this.Graphics.b_color1(tmp.R, tmp.G, tmp.B, tmp.A);
        }
    },

    check_bounds : function()
    {
        this.Shape.check_bounds(this);
    },

    // common funcs
    getNormalPoint : function(x0, y0, angle, x1, y1)
    {
        // точка - пересечение прямой, проходящей через точку (x0, y0) под углом angle и
        // перпендикуляра к первой прямой, проведенной из точки (x1, y1)
        var ex1 = Math.cos(angle);
        var ey1 = Math.sin(angle);

        var ex2 = -ey1;
        var ey2 = ex1;

        var a = ex1 / ey1;
        var b = ex2 / ey2;

        var x = ((a * b * y1 - a * b * y0) - (a * x1 - b * x0)) / (b - a);
        var y = (x - x0) / a + y0;

        return { X : x, Y : y };
    },

    getGradientPoints : function(min_x, min_y, max_x, max_y, _angle, scale)
    {
        var points = { x0 : 0, y0 : 0, x1 : 0, y1 : 0 };

        var angle = _angle / 60000;
        while (angle < 0)
            angle += 360;
        while (angle >= 360)
            angle -= 360;

        if (Math.abs(angle) < 1)
        {
            points.x0 = min_x;
            points.y0 = min_y;
            points.x1 = max_x;
            points.y1 = min_y;

            return points;
        }
        else if (Math.abs(angle - 90) < 1)
        {
            points.x0 = min_x;
            points.y0 = min_y;
            points.x1 = min_x;
            points.y1 = max_y;

            return points;
        }
        else if (Math.abs(angle - 180) < 1)
        {
            points.x0 = max_x;
            points.y0 = min_y;
            points.x1 = min_x;
            points.y1 = min_y;

            return points;
        }
        else if (Math.abs(angle - 270) < 1)
        {
            points.x0 = min_x;
            points.y0 = max_y;
            points.x1 = min_x;
            points.y1 = min_y;

            return points;
        }

        var grad_a = AscCommon.deg2rad(angle);
        if (!scale)
        {
            if (angle > 0 && angle < 90)
            {
                var p = this.getNormalPoint(min_x, min_y, grad_a, max_x, max_y);

                points.x0 = min_x;
                points.y0 = min_y;
                points.x1 = p.X;
                points.y1 = p.Y;

                return points;
            }
            if (angle > 90 && angle < 180)
            {
                var p = this.getNormalPoint(max_x, min_y, grad_a, min_x, max_y);

                points.x0 = max_x;
                points.y0 = min_y;
                points.x1 = p.X;
                points.y1 = p.Y;

                return points;
            }
            if (angle > 180 && angle < 270)
            {
                var p = this.getNormalPoint(max_x, max_y, grad_a, min_x, min_y);

                points.x0 = max_x;
                points.y0 = max_y;
                points.x1 = p.X;
                points.y1 = p.Y;

                return points;
            }
            if (angle > 270 && angle < 360)
            {
                var p = this.getNormalPoint(min_x, max_y, grad_a, max_x, min_y);

                points.x0 = min_x;
                points.y0 = max_y;
                points.x1 = p.X;
                points.y1 = p.Y;

                return points;
            }
            // никогда сюда не зайдем
            return points;
        }

        // scale == true
        var _grad_45 = (Math.PI / 2) - Math.atan2(max_y - min_y, max_x - min_x);
        var _grad_90_45 = (Math.PI / 2) - _grad_45;
        if (angle > 0 && angle < 90)
        {
            if (angle <= 45)
            {
                grad_a = (_grad_45 * angle / 45);
            }
            else
            {
                grad_a = _grad_45 + _grad_90_45 * (angle - 45) / 45;
            }

            var p = this.getNormalPoint(min_x, min_y, grad_a, max_x, max_y);

            points.x0 = min_x;
            points.y0 = min_y;
            points.x1 = p.X;
            points.y1 = p.Y;

            return points;
        }
        if (angle > 90 && angle < 180)
        {
            if (angle <= 135)
            {
                grad_a = Math.PI / 2 + _grad_90_45 * (angle - 90) / 45;
            }
            else
            {
                grad_a = Math.PI - _grad_45 * (angle - 135) / 45;
            }

            var p = this.getNormalPoint(max_x, min_y, grad_a, min_x, max_y);

            points.x0 = max_x;
            points.y0 = min_y;
            points.x1 = p.X;
            points.y1 = p.Y;

            return points;
        }
        if (angle > 180 && angle < 270)
        {
            if (angle <= 225)
            {
                grad_a = Math.PI + _grad_45 * (angle - 180) / 45;
            }
            else
            {
                grad_a = 3 * Math.PI / 2 - _grad_90_45 * (angle - 225) / 45;
            }

            var p = this.getNormalPoint(max_x, max_y, grad_a, min_x, min_y);

            points.x0 = max_x;
            points.y0 = max_y;
            points.x1 = p.X;
            points.y1 = p.Y;

            return points;
        }
        if (angle > 270 && angle < 360)
        {
            if (angle <= 315)
            {
                grad_a = 3 * Math.PI / 2 + _grad_90_45 * (angle - 270) / 45;
            }
            else
            {
                grad_a = 2 * Math.PI - _grad_45 * (angle - 315) / 45;
            }

            var p = this.getNormalPoint(min_x, max_y, grad_a, max_x, min_y);

            points.x0 = min_x;
            points.y0 = max_y;
            points.x1 = p.X;
            points.y1 = p.Y;

            return points;
        }
        // никогда сюда не зайдем
        return points;
    },

    DrawPresentationComment : function(type, x, y, w, h)
    {
    }
};

function ShapeToImageConverter(shape, pageIndex)
{
    AscCommon.IsShapeToImageConverter = true;
    var _bounds_cheker = new AscFormat.CSlideBoundsChecker();

    var dKoef = AscCommon.g_dKoef_mm_to_pix;
    var w_mm = 210;
    var h_mm = 297;
    var w_px = (w_mm * dKoef) >> 0;
    var h_px = (h_mm * dKoef) >> 0;

    _bounds_cheker.init(w_px, h_px, w_mm, h_mm);
    _bounds_cheker.transform(1,0,0,1,0,0);

    _bounds_cheker.AutoCheckLineWidth = true;
	_bounds_cheker.CheckLineWidth(shape);
    shape.draw(_bounds_cheker, /*pageIndex*/0);
	_bounds_cheker.CorrectBounds2();

    var _need_pix_width     = _bounds_cheker.Bounds.max_x - _bounds_cheker.Bounds.min_x + 1;
    var _need_pix_height    = _bounds_cheker.Bounds.max_y - _bounds_cheker.Bounds.min_y + 1;

    if (_need_pix_width <= 0 || _need_pix_height <= 0)
        return null;

    /*
    if (shape.pen)
    {
        var _w_pen = (shape.pen.w == null) ? 12700 : parseInt(shape.pen.w);
        _w_pen /= 36000.0;
        _w_pen *= g_dKoef_mm_to_pix;

        _need_pix_width += (2 * _w_pen);
        _need_pix_height += (2 * _w_pen);

        _bounds_cheker.Bounds.min_x -= _w_pen;
        _bounds_cheker.Bounds.min_y -= _w_pen;
    }*/

    var _canvas = document.createElement('canvas');
    _canvas.width = _need_pix_width;
    _canvas.height = _need_pix_height;

    var _ctx = _canvas.getContext('2d');

    var g = new AscCommon.CGraphics();
    g.init(_ctx, w_px, h_px, w_mm, h_mm);
    g.m_oFontManager = AscCommon.g_fontManager;

    g.m_oCoordTransform.tx = -_bounds_cheker.Bounds.min_x;
    g.m_oCoordTransform.ty = -_bounds_cheker.Bounds.min_y;
    g.transform(1,0,0,1,0,0);

    shape.draw(g, /*pageIndex*/0);

    AscCommon.IsShapeToImageConverter = false;

    var _ret = { ImageNative : _canvas, ImageUrl : "" };
    try
    {
        _ret.ImageUrl = _canvas.toDataURL("image/png");
    }
    catch (err)
    {
        if (shape.brush != null && shape.brush.fill && shape.brush.fill.RasterImageId)
            _ret.ImageUrl = getFullImageSrc2(shape.brush.fill.RasterImageId);
        else
            _ret.ImageUrl = "";
    }
    return _ret;
}

//------------------------------------------------------------export----------------------------------------------------
window['AscCommon'] = window['AscCommon'] || {};
window['AscCommon'].CShapeDrawer = CShapeDrawer;
window['AscCommon'].ShapeToImageConverter = ShapeToImageConverter;
window['AscCommon'].IsShapeToImageConverter = false;
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var FontStyle = AscFonts.FontStyle;
var g_fontApplication = AscFonts.g_fontApplication;

var CColor = AscCommon.CColor;
var CAscMathCategory = AscCommon.CAscMathCategory;
var g_oTableId = AscCommon.g_oTableId;
var g_oTextMeasurer = AscCommon.g_oTextMeasurer;
var global_mouseEvent = AscCommon.global_mouseEvent;
var History = AscCommon.History;
var global_MatrixTransformer = AscCommon.global_MatrixTransformer;
var g_dKoef_pix_to_mm = AscCommon.g_dKoef_pix_to_mm;
var g_dKoef_mm_to_pix = AscCommon.g_dKoef_mm_to_pix;

var _canvas_tables = null;
var _table_styles = null;

var c_oContentControlTrack = {
	Hover 	: 0,
	In 		: 1
};

function CContentControlButtonIcons()
{
	function CCCBI()
	{
		this.type = 0;
		this.images = [];

		this.load = function(type, url)
		{
			this.type = type;
			this.images[0] = new Image();
			this.images[0].onload = function() { this.asc_complete = true; };
			this.images[0].src = "../../../../sdkjs/common/Images/content_control_" + url + ".png";

			this.images[1] = new Image();
			this.images[1].onload = function() { this.asc_complete = true; };
			this.images[1].src = "../../../../sdkjs/common/Images/content_control_" + url + "_active.png";

			this.images[2] = new Image();
			this.images[2].onload = function() { this.asc_complete = true; };
			this.images[2].src = "../../../../sdkjs/common/Images/content_control_" + url + "_2x.png";

			this.images[3] = new Image();
			this.images[3].onload = function() { this.asc_complete = true; };
			this.images[3].src = "../../../../sdkjs/common/Images/content_control_" + url + "_active_2x.png";
		};

		this.get = function(isActive)
		{
			var index = AscCommon.AscBrowser.isRetina ? 2 : 0;
			if (isActive)
				index++;
			if (this.images[index].asc_complete)
				return this.images[index];
			return null;
		};
	}

	this.images = {};
	this.measures = {};

	this.register = function(type, url)
	{
		var image = new CCCBI();
		image.load(type, url);
		this.images[type] = image;
	};

	this.getFont = function(dKoef)
	{
		if (!dKoef)
			return "11px Helvetica, Arial, sans-serif";
		var size = (1 + 2 * 11 / dKoef) >> 0;
		if (size & 1)
			return (size >> 1) + ".5px Helvetica, Arial, sans-serif";
		return (size >> 1) + "px Helvetica, Arial, sans-serif";
	};

	this.measure = function(text, ctx, not_cache)
	{
		if (!this.measures[text])
			this.measures[text] = [0, 0];

		if (not_cache)
			return ctx.measureText(text).width;

		var arr = this.measures[text];
		var index = AscCommon.AscBrowser.isRetina ? 1 : 0;
		if (0 != arr[index])
			return arr[index];

		arr[index] = ctx.measureText(text).width;
		return arr[index];
	};

	this.getImage = function(type, isActive)
	{
		if (!this.images[type])
			return null;

		return this.images[type].get(isActive);
	};
}

var g_oContentControlButtonIcons = new CContentControlButtonIcons();
g_oContentControlButtonIcons.register(1, "toc");

function CContentControlTrack(_id, _type, _data, _transform, _name, _name_advanced, _button_types, _color)
{
	this.id = (undefined == _id) ? -1 : _id;
	this.type = (undefined == _type) ? -1 : _type;
	this.color = _color;

	this.rects = undefined;
	this.paths = undefined;

	if (undefined === _data[0].Points)
		this.rects = _data;
	else
		this.paths = _data;

	this.transform = (undefined == _transform) ? null : _transform;

	this.X = undefined;
	this.Y = undefined;

	this.Name = _name ? _name : "";
	this.NameButtonAdvanced = _name_advanced ? true : false;
	this.Buttons = _button_types ? _button_types : [];

	this.HoverButtonIndex = -2; // -1 => Text, otherwise index in this.Buttons
	this.ActiveButtonIndex = -2; // -1 => Text, otherwise index in this.Buttons
	this.NameWidth = 0;
}
CContentControlTrack.prototype.getPage = function()
{
	if (this.rects)
		return this.rects[0].Page;
	if (this.paths)
		return this.paths[0].Page;
	return 0;
};
CContentControlTrack.prototype.getXY = function()
{
	if (undefined === this.X && undefined === this.Y)
	{
		if (this.rects)
		{
			this.X = this.rects[0].X;
			this.Y = this.rects[0].Y;
		}
		else if (this.paths)
		{
			var _points = this.paths[0].Points;
			this.Y = _points[0].Y;

			for (var i = 1; i < _points.length; i++)
			{
				if (this.Y > _points[i].Y)
					this.Y = _points[i].Y;
			}

			this.X = 1000000000;
			for (var i = 0; i < _points.length; i++)
			{
				if (Math.abs(this.Y - _points[i].Y) < 0.0001)
				{
					if (this.X > _points[i].X)
						this.X = _points[i].X;
				}
			}
		}
	}

	return { X : this.X, Y : this.Y };
};
CContentControlTrack.prototype.Copy = function()
{
	return new CContentControlTrack(this.id, this.type, this.rects ? this.rects : this.paths, this.transform, this.color);
};
CContentControlTrack.prototype.getColor = function()
{
	return this.color;
};

function CColumnsMarkupColumn()
{
	this.W = 0;
	this.Space = 0;
}

function CColumnsMarkup()
{
	this.CurCol = 0;
	this.X = 0; // левое поле
	this.R = 0; // правое поле

	this.EqualWidth = true;
	this.Num = 1;
	this.Space = 30;
	this.Cols = [];

	this.SectPr = null;
}
CColumnsMarkup.prototype.Update_FromSectPr = function (SectPr)
{
	if (!SectPr)
		return;

	this.SectPr = SectPr;

	var Columns = SectPr.Columns;

	this.X = SectPr.Get_PageMargin_Left();
	this.R = SectPr.Get_PageWidth() - SectPr.Get_PageMargin_Right();
	this.EqualWidth = Columns.EqualWidth;
	this.Num = Columns.Num;
	this.Space = Columns.Space;

	this.Cols = [];
	for (var Index = 0, Count = Columns.Cols.length; Index < Count; ++Index)
	{
		this.Cols[Index] = new CColumnsMarkupColumn();
		this.Cols[Index].W = Columns.Cols[Index].W;
		this.Cols[Index].Space = Columns.Cols[Index].Space;
	}
};
CColumnsMarkup.prototype.Set_CurCol = function (CurCol)
{
	this.CurCol = CurCol;
};
CColumnsMarkup.prototype.CreateDuplicate = function ()
{
	var _ret = new CColumnsMarkup();
	_ret.SectPr = this.SectPr;
	_ret.CurCol = this.CurCol;
	_ret.X = this.X;
	_ret.R = this.R;

	_ret.EqualWidth = this.EqualWidth;
	_ret.Num = this.Num;
	_ret.Space = this.Space;

	_ret.Cols = [];

	for (var i = 0; i < this.Cols.length; i++)
	{
		var _col = new CColumnsMarkupColumn();
		_col.W = this.Cols[i].W;
		_col.Space = this.Cols[i].Space;
		_ret.Cols.push(_col);
	}
	return _ret;
};

function CTableOutlineDr()
{
	this.image = new Image();
	this.image.src = "../../../../sdkjs/common/Images/table_move.png";
	this.image.onload = function() { this.asc_complete = true; };

	this.image2 = new Image();
	this.image2.src = "../../../../sdkjs/common/Images/table_move_2x.png";
	this.image2.onload = function() { this.asc_complete = true; };

	this.TableOutline = null;
	this.Counter = 0;
	this.bIsNoTable = true;
	this.bIsTracked = false;

	this.CurPos = null;
	this.TrackTablePos = 0; // 0 - left_top, 1 - right_top, 2 - right_bottom, 3 - left_bottom
	this.TrackOffsetX = 0;
	this.TrackOffsetY = 0;

	this.InlinePos = null;

	this.IsChangeSmall = true;
	this.ChangeSmallPoint = null;

	this.TableMatrix = null;
	this.CurrentPageIndex = null;

	this.IsResizeTableTrack = false;
	this.AddResizeCurrentW = 0;
	this.AddResizeCurrentH = 0;
	this.AddResizeMinW     = 0;
	this.AddResizeMinH     = 0;

	this.getLastPageBounds = function()
	{
		var _bounds = { Page: 0, X : 0, Y : 0, W : 0, H : 0 };
		if (!this.TableOutline || !this.TableOutline.Table)
			return _bounds;

		var _pagesCount = this.TableOutline.Table.GetPagesCount();
		if (0 >= _pagesCount)
			return _bounds;

		var _boundsTmp = this.TableOutline.Table.Get_PageBounds(_pagesCount - 1);
		_bounds.Page = this.TableOutline.Table.Get_AbsolutePage(_pagesCount - 1);
		_bounds.X = _boundsTmp.Left;
		_bounds.Y = _boundsTmp.Top;
		_bounds.W = (_boundsTmp.Right - _boundsTmp.Left);
		_bounds.H = (_boundsTmp.Bottom - _boundsTmp.Top);
		
		return _bounds;
	}

	this.getFullHeight = function()
	{
		var _height = 0;
		if (!this.TableOutline || !this.TableOutline.Table)
			return _height;

		var _pagesCount = this.TableOutline.Table.GetPagesCount();
		var _boundsTmp;
		for (var i = 0; i < _pagesCount; i++)
		{
			_boundsTmp = this.TableOutline.Table.Get_PageBounds(i);
			_height += (_boundsTmp.Bottom - _boundsTmp.Top);
		}

		return _height;
	}

	this.getFullTopPosition = function(_lastBounds)
	{
		if (_lastBounds.Page == this.TableOutline.PageNum)
		{
			return this.TableOutline.Y;	
		}

		var _height = this.getFullHeight();
		var _top = _lastBounds.Y + _lastBounds.H - _height;
		if (_top < 0)
			_top = 0;

		return _top;
	}

	this.checkMouseDown = function (pos, word_control)
	{
		if (null == this.TableOutline)
			return false;

		var _table_track = this.TableOutline;
		var _d = 13 * g_dKoef_pix_to_mm * 100 / word_control.m_nZoomValue;

		this.IsChangeSmall = true;
		this.ChangeSmallPoint = pos;

		this.CurPos = {X: this.ChangeSmallPoint.X, Y: this.ChangeSmallPoint.Y, Page: this.ChangeSmallPoint.Page};
		this.TrackOffsetX = 0;
		this.TrackOffsetY = 0;

		if (!this.TableMatrix || global_MatrixTransformer.IsIdentity(this.TableMatrix))
		{
			if (word_control.MobileTouchManager)
			{
				var _move_point = word_control.MobileTouchManager.TableMovePoint;

				if (_move_point == null || pos.Page != _table_track.PageNum)
					return false;

				var _pos1 = word_control.m_oDrawingDocument.ConvertCoordsToCursorWR(pos.X, pos.Y, pos.Page);
				var _pos2 = word_control.m_oDrawingDocument.ConvertCoordsToCursorWR(_move_point.X, _move_point.Y, pos.Page);

				var _eps = word_control.MobileTouchManager.TrackTargetEps;

				var _offset1 = word_control.MobileTouchManager.TableRulersRectOffset;
				var _offset2 = _offset1 + word_control.MobileTouchManager.TableRulersRectSize;
				if ((_pos1.X >= (_pos2.X - _offset2 - _eps)) && (_pos1.X <= (_pos2.X - _offset1 + _eps)) &&
					(_pos1.Y >= (_pos2.Y - _offset2 - _eps)) && (_pos1.Y <= (_pos2.Y - _offset1 + _eps)))
				{
					this.TrackTablePos = 0;
					return true;
				}

				return false;
			}

			switch (this.TrackTablePos)
			{
				case 1:
				{
					var _x = _table_track.X + _table_track.W;
					var _b = _table_track.Y;
					var _y = _b - _d;
					var _r = _x + _d;

					if ((pos.X > _x) && (pos.X < _r) && (pos.Y > _y) && (pos.Y < _b))
					{
						this.TrackOffsetX = pos.X - _x;
						this.TrackOffsetY = pos.Y - _b;

						this.CurPos.X -= this.TrackOffsetX;
						this.CurPos.Y -= this.TrackOffsetY;
						return true;
					}
					break;
				}
				case 2:
				{
					var _x = _table_track.X + _table_track.W;
					var _y = _table_track.Y + _table_track.H;
					var _r = _x + _d;
					var _b = _y + _d;

					if ((pos.X > _x) && (pos.X < _r) && (pos.Y > _y) && (pos.Y < _b))
					{
						this.TrackOffsetX = pos.X - _x;
						this.TrackOffsetY = pos.Y - _y;
						return true;
					}
					break;
				}
				case 3:
				{
					var _r = _table_track.X;
					var _x = _r - _d;
					var _y = _table_track.Y + _table_track.H;
					var _b = _y + _d;

					if ((pos.X > _x) && (pos.X < _r) && (pos.Y > _y) && (pos.Y < _b))
					{
						this.TrackOffsetX = pos.X - _r;
						this.TrackOffsetY = pos.Y - _y;

						this.CurPos.X -= this.TrackOffsetX;
						this.CurPos.Y -= this.TrackOffsetY;
						return true;
					}
					break;
				}
				case 0:
				default:
				{
					var _r = _table_track.X;
					var _b = _table_track.Y;
					var _x = _r - _d;
					var _y = _b - _d;

					if ((pos.X > _x) && (pos.X < _r) && (pos.Y > _y) && (pos.Y < _b))
					{
						this.TrackOffsetX = pos.X - _r;
						this.TrackOffsetY = pos.Y - _b;

						this.CurPos.X -= this.TrackOffsetX;
						this.CurPos.Y -= this.TrackOffsetY;
						return true;
					}
					break;
				}
			}

			if (true)
			{
				var _lastBounds = this.getLastPageBounds();
				var _x = _lastBounds.X + _lastBounds.W;
				var _y = _lastBounds.Y + _lastBounds.H;
				_d = 6 * g_dKoef_pix_to_mm * 100 / word_control.m_nZoomValue;

				var _r = _x + _d;
				var _b = _y + _d;

				if ((_lastBounds.Page == pos.Page) && (pos.X > _x) && (pos.X < _r) && (pos.Y > _y) && (pos.Y < _b))
				{
					this.TrackOffsetX = pos.X - _x;
					this.TrackOffsetY = pos.Y - _y;

					this.CurPos.X = global_mouseEvent.X;
					this.CurPos.Y = global_mouseEvent.Y;

					this.AddResizeCurrentW = 0;
					this.AddResizeCurrentH = 0;
					this.IsResizeTableTrack = true;

					var _table = this.TableOutline.Table;

					if (_lastBounds.Page == this.PageNum)
					{
						this.AddResizeMinH = _table.GetMinHeight() - this.TableOutline.H;
						this.AddResizeMinW = _table.GetMinWidth() - this.TableOutline.W;
					}
					else
					{
						var _fullTop = this.getFullTopPosition(_lastBounds);
						if (0 == _fullTop)
							this.AddResizeMinH = _fullTop - (_lastBounds.Y + _lastBounds.H);
						else
							this.AddResizeMinH = _fullTop + _table.GetMinHeight() - (_lastBounds.Y + _lastBounds.H);
						this.AddResizeMinW = _table.GetMinWidth() - _lastBounds.W;
					}

					word_control.m_oDrawingDocument.LockCursorType("se-resize");
					return true;
				}
			}

			return false;
		}
		else
		{
			if (word_control.MobileTouchManager)
			{
				var _invert = global_MatrixTransformer.Invert(this.TableMatrix);
				var _posx = _invert.TransformPointX(pos.X, pos.Y);
				var _posy = _invert.TransformPointY(pos.X, pos.Y);

				var _move_point = word_control.MobileTouchManager.TableMovePoint;

				if (_move_point == null || pos.Page != _table_track.PageNum)
					return false;

				var _koef = g_dKoef_pix_to_mm * 100 / word_control.m_nZoomValue;
				var _eps = word_control.MobileTouchManager.TrackTargetEps * _koef;

				var _offset1 = word_control.MobileTouchManager.TableRulersRectOffset * _koef;
				var _offset2 = _offset1 + word_control.MobileTouchManager.TableRulersRectSize * _koef;
				if ((_posx >= (_move_point.X - _offset2 - _eps)) && (_posx <= (_move_point.X - _offset1 + _eps)) &&
					(_posy >= (_move_point.Y - _offset2 - _eps)) && (_posy <= (_move_point.Y - _offset1 + _eps)))
				{
					this.TrackTablePos = 0;
					return true;
				}

				return false;
			}

			var _invert = global_MatrixTransformer.Invert(this.TableMatrix);
			var _posx = _invert.TransformPointX(pos.X, pos.Y);
			var _posy = _invert.TransformPointY(pos.X, pos.Y);
			switch (this.TrackTablePos)
			{
				case 1:
				{
					var _x = _table_track.X + _table_track.W;
					var _b = _table_track.Y;
					var _y = _b - _d;
					var _r = _x + _d;

					if ((_posx > _x) && (_posx < _r) && (_posy > _y) && (_posy < _b))
					{
						this.TrackOffsetX = _posx - _x;
						this.TrackOffsetY = _posy - _b;

						this.CurPos.X -= this.TrackOffsetX;
						this.CurPos.Y -= this.TrackOffsetY;
						return true;
					}
					break;
				}
				case 2:
				{
					var _x = _table_track.X + _table_track.W;
					var _y = _table_track.Y + _table_track.H;
					var _r = _x + _d;
					var _b = _y + _d;

					if ((_posx > _x) && (_posx < _r) && (_posy > _y) && (_posy < _b))
					{
						this.TrackOffsetX = _posx - _x;
						this.TrackOffsetY = _posy - _y;

						this.CurPos.X -= this.TrackOffsetX;
						this.CurPos.Y -= this.TrackOffsetY;
						return true;
					}
					break;
				}
				case 3:
				{
					var _r = _table_track.X;
					var _x = _r - _d;
					var _y = _table_track.Y + _table_track.H;
					var _b = _y + _d;

					if ((_posx > _x) && (_posx < _r) && (_posy > _y) && (_posy < _b))
					{
						this.TrackOffsetX = _posx - _r;
						this.TrackOffsetY = _posy - _y;

						this.CurPos.X -= this.TrackOffsetX;
						this.CurPos.Y -= this.TrackOffsetY;
						return true;
					}
					break;
				}
				case 0:
				default:
				{
					var _r = _table_track.X;
					var _b = _table_track.Y;
					var _x = _r - _d;
					var _y = _b - _d;

					if ((_posx > _x) && (_posx < _r) && (_posy > _y) && (_posy < _b))
					{
						this.TrackOffsetX = _posx - _r;
						this.TrackOffsetY = _posy - _b;

						this.CurPos.X -= this.TrackOffsetX;
						this.CurPos.Y -= this.TrackOffsetY;
						return true;
					}
					break;
				}
			}

			if (true)
			{
				var _lastBounds = this.getLastPageBounds();
				var _x = _lastBounds.X + _lastBounds.W;
				var _y = _lastBounds.Y + _lastBounds.H;
				_d = 6 * g_dKoef_pix_to_mm * 100 / word_control.m_nZoomValue;

				var _r = _x + _d;
				var _b = _y + _d;

				if ((_posx > _x) && (_posx < _r) && (_posy > _y) && (_posy < _b))
				{
					this.TrackOffsetX = _posx - _x;
					this.TrackOffsetY = _posy - _b;

					this.CurPos.X = global_mouseEvent.X;
					this.CurPos.Y = global_mouseEvent.Y;

					this.AddResizeCurrentW = 0;
					this.AddResizeCurrentH = 0;
					this.IsResizeTableTrack = true;

					word_control.m_oDrawingDocument.LockCursorType("se-resize");
					return true;
				}
			}

			return false;
		}

		return false;
	}

	this.checkMouseMoveTrack = function (pos, word_control)
	{
		if (null == this.TableOutline)
			return false;

		var _table_track = this.TableOutline;
		var _d = 13 * g_dKoef_pix_to_mm * 100 / word_control.m_nZoomValue;

		var _x, _y, _r, _b;
		if (!this.TableMatrix || global_MatrixTransformer.IsIdentity(this.TableMatrix))
		{
			switch (this.TrackTablePos)
			{
				case 1:
				{
					_x = _table_track.X + _table_track.W;
					_b = _table_track.Y;
					_y = _b - _d;
					_r = _x + _d;

					if ((pos.X > _x) && (pos.X < _r) && (pos.Y > _y) && (pos.Y < _b))
						return true;
					break;
				}
				case 2:
				{
					_x = _table_track.X + _table_track.W;
					_y = _table_track.Y + _table_track.H;
					_r = _x + _d;
					_b = _y + _d;

					if ((pos.X > _x) && (pos.X < _r) && (pos.Y > _y) && (pos.Y < _b))
						return true;
					break;
				}
				case 3:
				{
					_r = _table_track.X;
					_x = _r - _d;
					_y = _table_track.Y + _table_track.H;
					_b = _y + _d;

					if ((pos.X > _x) && (pos.X < _r) && (pos.Y > _y) && (pos.Y < _b))
						return true;
					break;
				}
				case 0:
				default:
				{
					_r = _table_track.X;
					_b = _table_track.Y;
					_x = _r - _d;
					_y = _b - _d;

					if ((pos.X > _x) && (pos.X < _r) && (pos.Y > _y) && (pos.Y < _b))
						return true;
					break;
				}
			}
		}
		else
		{
			var _invert = global_MatrixTransformer.Invert(this.TableMatrix);
			var _posx = _invert.TransformPointX(pos.X, pos.Y);
			var _posy = _invert.TransformPointY(pos.X, pos.Y);
			switch (this.TrackTablePos)
			{
				case 1:
				{
					_x = _table_track.X + _table_track.W;
					_b = _table_track.Y;
					_y = _b - _d;
					_r = _x + _d;

					if ((_posx > _x) && (_posx < _r) && (_posy > _y) && (_posy < _b))
						return true;
					break;
				}
				case 2:
				{
					_x = _table_track.X + _table_track.W;
					_y = _table_track.Y + _table_track.H;
					_r = _x + _d;
					_b = _y + _d;

					if ((_posx > _x) && (_posx < _r) && (_posy > _y) && (_posy < _b))
						return true;
					break;
				}
				case 3:
				{
					_r = _table_track.X;
					_x = _r - _d;
					_y = _table_track.Y + _table_track.H;
					_b = _y + _d;

					if ((_posx > _x) && (_posx < _r) && (_posy > _y) && (_posy < _b))
						return true;
					break;
				}
				case 0:
				default:
				{
					_r = _table_track.X;
					_b = _table_track.Y;
					_x = _r - _d;
					_y = _b - _d;

					if ((_posx > _x) && (_posx < _r) && (_posy > _y) && (_posy < _b))
						return true;
					break;
				}
			}
		}

		return false;
	}

	this.checkMouseUp = function (X, Y, word_control)
	{
		this.bIsTracked = false;

		if (null == this.TableOutline || (true === this.IsChangeSmall) || word_control.m_oApi.isViewMode)
			return false;

		var _koef = g_dKoef_pix_to_mm * 100 / word_control.m_nZoomValue;
		var _d = 13 * _koef;

		var _outline = this.TableOutline;
		var _table = _outline.Table;

		_table.MoveCursorToStartPos();
		_table.Document_SetThisElementCurrent(true);

		if (this.IsResizeTableTrack)
		{
			var _addW = (X - this.CurPos.X) * _koef - this.TrackOffsetX;
			var _addH = (Y - this.CurPos.Y) * _koef - this.TrackOffsetY;

			_table.ResizeTableInDocument(this.TableOutline.W + _addW, this.TableOutline.H + _addH);

			this.AddResizeCurrentW = 0;
			this.AddResizeCurrentH = 0;
			this.IsResizeTableTrack = false;
			word_control.m_oDrawingDocument.UnlockCursorType();
			word_control.m_oDrawingDocument.SetCursorType("default");
			return;
		}

		if (!_table.Is_Inline())
		{
			var pos;
			switch (this.TrackTablePos)
			{
				case 1:
				{
					var _w_pix = this.TableOutline.W * g_dKoef_mm_to_pix * word_control.m_nZoomValue / 100;
					pos = word_control.m_oDrawingDocument.ConvertCoordsFromCursor2(X - _w_pix, Y);
					break;
				}
				case 2:
				{
					var _w_pix = this.TableOutline.W * g_dKoef_mm_to_pix * word_control.m_nZoomValue / 100;
					var _h_pix = this.TableOutline.H * g_dKoef_mm_to_pix * word_control.m_nZoomValue / 100;
					pos = word_control.m_oDrawingDocument.ConvertCoordsFromCursor2(X - _w_pix, Y - _h_pix);
					break;
				}
				case 3:
				{
					var _h_pix = this.TableOutline.H * g_dKoef_mm_to_pix * word_control.m_nZoomValue / 100;
					pos = word_control.m_oDrawingDocument.ConvertCoordsFromCursor2(X, Y - _h_pix);
					break;
				}
				case 0:
				default:
				{
					pos = word_control.m_oDrawingDocument.ConvertCoordsFromCursor2(X, Y);
					break;
				}
			}

			var NearestPos = word_control.m_oLogicDocument.Get_NearestPos(pos.Page, pos.X - this.TrackOffsetX, pos.Y - this.TrackOffsetY);
			_table.Move(pos.X - this.TrackOffsetX, pos.Y - this.TrackOffsetY, pos.Page, NearestPos);
			_outline.X = pos.X - this.TrackOffsetX;
			_outline.Y = pos.Y - this.TrackOffsetY;
			_outline.PageNum = pos.Page;
		}
		else
		{
			if (null != this.InlinePos)
			{
				// inline move
				_table.Move(this.InlinePos.X, this.InlinePos.Y, this.InlinePos.Page, this.InlinePos);
			}
		}
	}

	this.checkMouseMove = function (X, Y, word_control)
	{
		if (null == this.TableOutline)
			return false;

		if (true === this.IsChangeSmall)
		{
			var _pos = word_control.m_oDrawingDocument.ConvertCoordsFromCursor2(X, Y);
			var _dist = 15 * g_dKoef_pix_to_mm * 100 / word_control.m_nZoomValue;
			if ((Math.abs(_pos.X - this.ChangeSmallPoint.X) < _dist) && (Math.abs(_pos.Y - this.ChangeSmallPoint.Y) < _dist) && (_pos.Page == this.ChangeSmallPoint.Page))
			{
				if (this.IsResizeTableTrack)
					return;

				this.CurPos = {
					X: this.ChangeSmallPoint.X,
					Y: this.ChangeSmallPoint.Y,
					Page: this.ChangeSmallPoint.Page
				};

				switch (this.TrackTablePos)
				{
					case 1:
					{
						this.CurPos.X -= this.TableOutline.W;
						break;
					}
					case 2:
					{
						this.CurPos.X -= this.TableOutline.W;
						this.CurPos.Y -= this.TableOutline.H;
						break;
					}
					case 3:
					{
						this.CurPos.Y -= this.TableOutline.H;
						break;
					}
					case 0:
					default:
					{
						break;
					}
				}

				this.CurPos.X -= this.TrackOffsetX;
				this.CurPos.Y -= this.TrackOffsetY;
				return;
			}
			this.IsChangeSmall = false;

			this.TableOutline.Table.RemoveSelection();
			this.TableOutline.Table.MoveCursorToStartPos();
			word_control.m_oLogicDocument.Document_UpdateSelectionState();
		}

		if (this.IsResizeTableTrack)
		{
			var _koef = g_dKoef_pix_to_mm * 100 / word_control.m_nZoomValue;
			this.AddResizeCurrentW = Math.max(this.AddResizeMinW, (X - this.CurPos.X) * _koef - this.TrackOffsetX);
			this.AddResizeCurrentH = Math.max(this.AddResizeMinH, (Y - this.CurPos.Y) * _koef - this.TrackOffsetY);

			return true;
		}

		var _d = 13 * g_dKoef_pix_to_mm * 100 / word_control.m_nZoomValue;
		switch (this.TrackTablePos)
		{
			case 1:
			{
				var _w_pix = this.TableOutline.W * g_dKoef_mm_to_pix * word_control.m_nZoomValue / 100;
				this.CurPos = word_control.m_oDrawingDocument.ConvertCoordsFromCursor2(X - _w_pix, Y);
				break;
			}
			case 2:
			{
				var _w_pix = this.TableOutline.W * g_dKoef_mm_to_pix * word_control.m_nZoomValue / 100;
				var _h_pix = this.TableOutline.H * g_dKoef_mm_to_pix * word_control.m_nZoomValue / 100;
				this.CurPos = word_control.m_oDrawingDocument.ConvertCoordsFromCursor2(X - _w_pix, Y - _h_pix);
				break;
			}
			case 3:
			{
				var _h_pix = this.TableOutline.H * g_dKoef_mm_to_pix * word_control.m_nZoomValue / 100;
				this.CurPos = word_control.m_oDrawingDocument.ConvertCoordsFromCursor2(X, Y - _h_pix);
				break;
			}
			case 0:
			default:
			{
				this.CurPos = word_control.m_oDrawingDocument.ConvertCoordsFromCursor2(X, Y);
				break;
			}
		}

		this.CurPos.X -= this.TrackOffsetX;
		this.CurPos.Y -= this.TrackOffsetY;
	}

	this.checkMouseMove2 = function (X, Y, word_control)
	{
		if (null == this.TableOutline)
			return;

		if (word_control.MobileTouchManager)
			return;

		var _table_track = this.TableOutline;

		var pos = null;
		if (word_control.m_oDrawingDocument.AutoShapesTrackLockPageNum == -1)
			pos = word_control.m_oDrawingDocument.ConvertCoordsFromCursor2(global_mouseEvent.X, global_mouseEvent.Y);
		else
			pos = word_control.m_oDrawingDocument.ConvetToPageCoords(global_mouseEvent.X, global_mouseEvent.Y, word_control.m_oDrawingDocument.AutoShapesTrackLockPageNum);

		var _lastBounds = word_control.m_oDrawingDocument.TableOutlineDr.getLastPageBounds();
		if (_lastBounds.Page != pos.Page)
			return false;

		if (!this.TableMatrix || global_MatrixTransformer.IsIdentity(this.TableMatrix))
		{
			var _x = _lastBounds.X + _lastBounds.W;
			var _y = _lastBounds.Y + _lastBounds.H;
			var _d = 6 * g_dKoef_pix_to_mm * 100 / word_control.m_nZoomValue;

			var _r = _x + _d;
			var _b = _y + _d;

			if ((pos.X > _x) && (pos.X < _r) && (pos.Y > _y) && (pos.Y < _b))
			{
				word_control.m_oDrawingDocument.SetCursorType("se-resize");
				return true;
			}
		}
		else
		{
			var _invert = global_MatrixTransformer.Invert(this.TableMatrix);
			var _posx = _invert.TransformPointX(pos.X, pos.Y);
			var _posy = _invert.TransformPointY(pos.X, pos.Y);

			var _x = _lastBounds.X + _lastBounds.W;
			var _y = _lastBounds.Y + _lastBounds.H;
			_d = 6 * g_dKoef_pix_to_mm * 100 / word_control.m_nZoomValue;

			var _r = _x + _d;
			var _b = _y + _d;

			if ((_posx > _x) && (_posx < _r) && (_posy > _y) && (_posy < _b))
			{
				word_control.m_oDrawingDocument.SetCursorType("se-resize");
				return true;
			}
		}
		return false;
	}

	this.CheckStartTrack = function (word_control, transform)
	{
		this.TableMatrix = null;
		if (transform)
			this.TableMatrix = transform.CreateDublicate();

		if (!this.TableMatrix || global_MatrixTransformer.IsIdentity(this.TableMatrix))
		{
			var pos = word_control.m_oDrawingDocument.ConvertCoordsToCursor(this.TableOutline.X, this.TableOutline.Y, this.TableOutline.PageNum, true);

			var _x0 = word_control.m_oEditor.AbsolutePosition.L;
			var _y0 = word_control.m_oEditor.AbsolutePosition.T;

			if (pos.X < _x0 && pos.Y < _y0)
			{
				this.TrackTablePos = 2;
			}
			else if (pos.X < _x0)
			{
				this.TrackTablePos = 1;
			}
			else if (pos.Y < _y0)
			{
				this.TrackTablePos = 3;
			}
			else
			{
				this.TrackTablePos = 0;
			}
		}
		else
		{
			var _x = this.TableOutline.X;
			var _y = this.TableOutline.Y;
			var _r = _x + this.TableOutline.W;
			var _b = _y + this.TableOutline.H;

			var x0 = transform.TransformPointX(_x, _y);
			var y0 = transform.TransformPointY(_x, _y);

			var x1 = transform.TransformPointX(_r, _y);
			var y1 = transform.TransformPointY(_r, _y);

			var x2 = transform.TransformPointX(_r, _b);
			var y2 = transform.TransformPointY(_r, _b);

			var x3 = transform.TransformPointX(_x, _b);
			var y3 = transform.TransformPointY(_x, _b);

			var _x0 = word_control.m_oEditor.AbsolutePosition.L * g_dKoef_mm_to_pix;
			var _y0 = word_control.m_oEditor.AbsolutePosition.T * g_dKoef_mm_to_pix;
			var _x1 = word_control.m_oEditor.AbsolutePosition.R * g_dKoef_mm_to_pix;
			var _y1 = word_control.m_oEditor.AbsolutePosition.B * g_dKoef_mm_to_pix;

			var pos0 = word_control.m_oDrawingDocument.ConvertCoordsToCursor(x0, y0, this.TableOutline.PageNum, true);
			if (pos0.X > _x0 && pos0.X < _x1 && pos0.Y > _y0 && pos0.Y < _y1)
			{
				this.TrackTablePos = 0;
				return;
			}

			pos0 = word_control.m_oDrawingDocument.ConvertCoordsToCursor(x1, y1, this.TableOutline.PageNum, true);
			if (pos0.X > _x0 && pos0.X < _x1 && pos0.Y > _y0 && pos0.Y < _y1)
			{
				this.TrackTablePos = 1;
				return;
			}

			pos0 = word_control.m_oDrawingDocument.ConvertCoordsToCursor(x3, y3, this.TableOutline.PageNum, true);
			if (pos0.X > _x0 && pos0.X < _x1 && pos0.Y > _y0 && pos0.Y < _y1)
			{
				this.TrackTablePos = 3;
				return;
			}

			pos0 = word_control.m_oDrawingDocument.ConvertCoordsToCursor(x2, y2, this.TableOutline.PageNum, true);
			if (pos0.X > _x0 && pos0.X < _x1 && pos0.Y > _y0 && pos0.Y < _y1)
			{
				this.TrackTablePos = 2;
				return;
			}

			this.TrackTablePos = 0;
		}
	}
}

function CCacheImage()
{
	this.image = null;
	this.image_locked = 0;
	this.image_unusedCount = 0;
}

function CCacheManager()
{
	this.arrayImages = [];
	this.arrayCount = 0;
	this.countValidImage = 1;

	this.CheckImagesForNeed = function ()
	{
		for (var i = 0; i < this.arrayCount; ++i)
		{
			if ((this.arrayImages[i].image_locked == 0) && (this.arrayImages[i].image_unusedCount >= this.countValidImage))
			{
				delete this.arrayImages[i].image;
				this.arrayImages.splice(i, 1);
				--i;
				--this.arrayCount;
			}
		}
	}

	this.UnLock = function (_cache_image)
	{
		if (null == _cache_image)
			return;

		_cache_image.image_locked = 0;
		_cache_image.image_unusedCount = 0;
		// затем нужно сбросить ссылку в ноль (_cache_image = null) <- это обязательно !!!!!!!
	}

	this.Lock = function (_w, _h)
	{
		for (var i = 0; i < this.arrayCount; ++i)
		{
			if (this.arrayImages[i].image_locked)
				continue;
			var _wI = this.arrayImages[i].image.width;
			var _hI = this.arrayImages[i].image.height;
			if ((_wI == _w) && (_hI == _h))
			{
				this.arrayImages[i].image_locked = 1;
				this.arrayImages[i].image_unusedCount = 0;

				this.arrayImages[i].image.ctx.globalAlpha = 1.0;
				this.arrayImages[i].image.ctx.setTransform(1, 0, 0, 1, 0, 0);
				this.arrayImages[i].image.ctx.fillStyle = "#ffffff";
				this.arrayImages[i].image.ctx.fillRect(0, 0, _w, _h);
				return this.arrayImages[i];
			}
			this.arrayImages[i].image_unusedCount++;
		}
		this.CheckImagesForNeed();
		var index = this.arrayCount;
		this.arrayCount++;

		this.arrayImages[index] = new CCacheImage();
		this.arrayImages[index].image = document.createElement('canvas');
		this.arrayImages[index].image.width = _w;
		this.arrayImages[index].image.height = _h;
		this.arrayImages[index].image.ctx = this.arrayImages[index].image.getContext('2d');
		this.arrayImages[index].image.ctx.globalAlpha = 1.0;
		this.arrayImages[index].image.ctx.setTransform(1, 0, 0, 1, 0, 0);
		this.arrayImages[index].image.ctx.fillStyle = "#ffffff";
		this.arrayImages[index].image.ctx.fillRect(0, 0, _w, _h);
		this.arrayImages[index].image_locked = 1;
		this.arrayImages[index].image_unusedCount = 0;
		return this.arrayImages[index];
	}
}

function CPolygonPoint(X, Y)
{
	this.X = X;
	this.Y = Y;
}
function CPolygonVectors()
{
	this.Page = -1;
	this.VX = [];
	this.VY = [];
}
function CPolygonPath(precision)
{
	this.Page = -1;
	this.Direction = 1;
	this.precision = precision;
	this.Points = [];
}
CPolygonPath.prototype.PushPoint = function (x, y)
{
	this.Points.push(new CPolygonPoint(x / this.precision, y / this.precision));
};
CPolygonPath.prototype.CorrectExtremePoints = function ()
{
	var Lng = this.Points.length;

	this.Points[0].X = this.Points[Lng - 1].X;
	this.Points[Lng - 1].Y = this.Points[0].Y;
};

function CPolygon()
{
	this.Vectors = [];
	this.precision = 1000;
}
CPolygon.prototype.fill = function (arrBounds)
{
	this.Vectors.length = 0;

	if (arrBounds.length <= 0)
		return;

	var nStartLineIndex = 0, nStartIndex = 0,
		CountLines = arrBounds.length,
		CountBounds;

	while (nStartLineIndex < arrBounds.length)
	{
		CountBounds = arrBounds[nStartLineIndex].length;

		while (nStartIndex < CountBounds)
		{
			if (arrBounds[nStartLineIndex][nStartIndex].W < 0.001)
				nStartIndex++;
			else
				break;
		}

		if (nStartIndex < CountBounds)
			break;

		nStartLineIndex++;
		nStartIndex = 0;
	}

	if (nStartLineIndex >= arrBounds.length)
		return;

	var CurrentPage = arrBounds[nStartLineIndex][nStartIndex].Page,
		CurrentVectors = new CPolygonVectors(),
		VectorsX = CurrentVectors.VX,
		VectorsY = CurrentVectors.VY;

	CurrentVectors.Page = CurrentPage;
	this.Vectors.push(CurrentVectors);

	for (var LineIndex = nStartLineIndex; LineIndex < CountLines; nStartIndex = 0, LineIndex++)
	{
		if (arrBounds[LineIndex][nStartIndex].Page !== CurrentPage)
		{
			CurrentPage = arrBounds[LineIndex][nStartIndex].Page;

			CurrentVectors = new CPolygonVectors();
			VectorsX = CurrentVectors.VX;
			VectorsY = CurrentVectors.VY;
			CurrentVectors.Page = CurrentPage;
			this.Vectors.push(CurrentVectors);

		}

		for (var Index = nStartIndex; Index < arrBounds[LineIndex].length; Index++)
		{
			var oBound = arrBounds[LineIndex][Index];

			if (oBound.W < 0.001)
				continue;

			var x1 = Math.round(oBound.X * this.precision), x2 = Math.round((oBound.X + oBound.W) * this.precision),
				y1 = Math.round(oBound.Y * this.precision), y2 = Math.round((oBound.Y + oBound.H) * this.precision);

			if (VectorsX[y1] == undefined)
			{
				VectorsX[y1] = {};
			}

			this.IntersectionX(VectorsX, x2, x1, y1);

			if (VectorsY[x1] == undefined)
			{
				VectorsY[x1] = {};
			}

			this.IntersectionY(VectorsY, y1, y2, x1);

			if (VectorsX[y2] == undefined)
			{
				VectorsX[y2] = {};
			}

			this.IntersectionX(VectorsX, x1, x2, y2);

			if (VectorsY[x2] == undefined)
			{
				VectorsY[x2] = {};
			}

			this.IntersectionY(VectorsY, y2, y1, x2);
		}
	}
};
CPolygon.prototype.IntersectionX = function (VectorsX, BeginX, EndX, Y)
{
	var CurrentVector = {};
	CurrentVector[BeginX] = EndX;
	var VX = VectorsX[Y];

	if (BeginX > EndX)
	{
		while (true == this.IntersectVectorX(CurrentVector, VX))
		{
		}
	}
	else
	{
		while (true == this.IntersectVectorX(VX, CurrentVector))
		{
		}
	}

	for (var X in CurrentVector)
	{
		var VBeginX = parseInt(X);
		var VEndX = CurrentVector[VBeginX];

		if (VBeginX !== VEndX || VX[VBeginX] === undefined) // добавляем точку, только если она не существует, а ненулевой вектор всегда
		{
			VX[VBeginX] = VEndX;
		}
	}
};
CPolygon.prototype.IntersectVectorX = function (VectorOpp, VectorClW) // vector opposite, vector clockwise
{
	for (var X in VectorOpp)
	{
		var VBeginX = parseInt(X);
		var VEndX = VectorOpp[VBeginX];

		if (VEndX == VBeginX)
			continue;

		for (var ClwX in VectorClW)
		{
			var ClwBeginX = parseInt(ClwX);
			var ClwEndX = VectorClW[ClwBeginX];
			var bIntersection = false;

			if (ClwBeginX == ClwEndX)
				continue;

			if (ClwBeginX <= VEndX && VBeginX <= ClwEndX) // inside vector ClW
			{
				VectorOpp[VBeginX] = VBeginX;

				VectorClW[ClwBeginX] = VEndX;
				VectorClW[VBeginX] = ClwEndX;

				bIntersection = true;
			}
			else if (VEndX <= ClwBeginX && ClwEndX <= VBeginX) // inside vector Opposite clockwise
			{
				VectorClW[ClwBeginX] = ClwBeginX;

				VectorOpp[VBeginX] = ClwEndX;
				VectorOpp[ClwBeginX] = VEndX;

				bIntersection = true;

			}
			else if (ClwBeginX < VEndX && VEndX < ClwEndX) // intersect vector ClW
			{
				VectorClW[ClwBeginX] = VEndX;
				VectorOpp[VBeginX] = ClwEndX;

				bIntersection = true;
			}
			else if (ClwBeginX < VBeginX && VBeginX < ClwEndX) // intersect vector ClW
			{
				VectorOpp[ClwBeginX] = VEndX;
				VectorClW[VBeginX] = ClwEndX;

				delete VectorOpp[VBeginX];
				delete VectorClW[ClwBeginX];

				bIntersection = true;
			}

			if (bIntersection == true)
				return true;
		}
	}

	return false;
};
CPolygon.prototype.IntersectionY = function (VectorsY, BeginY, EndY, X)
{
	var bIntersect = false;

	for (var y in VectorsY[X])
	{
		var CurBeginY = parseInt(y);
		var CurEndY = VectorsY[X][CurBeginY];

		var minY, maxY;

		if (CurBeginY < CurEndY)
		{
			minY = CurBeginY;
			maxY = CurEndY;
		}
		else
		{
			minY = CurEndY;
			maxY = CurBeginY;
		}

		var bInterSection = !((maxY <= BeginY && maxY <= EndY) || (minY >= BeginY && minY >= EndY )), // нач или конечная точка нах-ся внутри данного отрезка
			bDirection = (CurBeginY - CurEndY) * (BeginY - EndY) < 0; // векторы противоположно направленны

		if (bInterSection && bDirection) // если направления векторов совпало, значит один Bounds нах-ся в другом, ничего не делаем, такого быть не должно
		{

			VectorsY[X][CurBeginY] = EndY;
			VectorsY[X][BeginY] = CurEndY;
			bIntersect = true;
		}
	}

	if (bIntersect == false)
	{
		VectorsY[X][BeginY] = EndY;
	}
};
CPolygon.prototype.GetPaths = function (shift)
{
	var Paths = [];

	shift *= this.precision;

	for (var PageIndex = 0; PageIndex < this.Vectors.length; PageIndex++)
	{
		var y, x1, x2,
			x, y1, y2;

		var VectorsX = this.Vectors[PageIndex].VX,
			VectorsY = this.Vectors[PageIndex].VY,
			Page = this.Vectors[PageIndex].Page;


		for (var LineIndex in VectorsX)
		{
			for (var Index in VectorsX[LineIndex])
			{
				var Polygon = new CPolygonPath(this.precision);
				Polygon.Page = Page;

				y = parseInt(LineIndex);
				x1 = parseInt(Index);
				x2 = VectorsX[y][x1];

				VectorsX[y][x1] = -1;

				var Direction = x1 > x2 ? 1 : -1;
				var minY = y;
				var SignRightLeft, SignDownUp;
				var X, Y;

				if (x2 !== -1)
				{
					SignRightLeft = x1 > x2 ? 1 : -1;
					Y = y - SignRightLeft * shift;

					Polygon.PushPoint(x1, Y);

					while (true)
					{
						x = x2;
						y1 = y;
						y2 = VectorsY[x][y1];

						if (y2 == -1)
						{
							break;
						}
						else if (y2 == undefined) // такой ситуации не должно произойти, если произошла, значит есть ошибка в алгоритме => не отрисовываем путь
						{
							return [];
						}

						VectorsY[x][y1] = -1;  // выставляем -1 => чтобы не добавить повторно путь с данными точками + проверка на возвращение в стартовую точку

						SignDownUp = y1 > y2 ? 1 : -1;
						X = x + SignDownUp * shift;

						Polygon.PushPoint(X, Y);

						y = y2;
						x1 = x;
						x2 = VectorsX[y][x1];

						if (x2 == -1)
						{
							break;
						}
						else if (x2 == undefined) // такой ситуации не должно произойти, если произошла, значит есть ошибка в алгоритме => не отрисовываем путь
						{
							return [];
						}

						VectorsX[y][x1] = -1; // выставляем -1 => чтобы не добавить повторно путь с данными точками + проверка на возвращение в стартовую точку

						SignRightLeft = x1 > x2 ? 1 : -1;
						Y = y - SignRightLeft * shift;

						Polygon.PushPoint(X, Y);

						if (y < minY) // направление обхода
						{
							minY = y;
							Direction = x1 > x2 ? 1 : -1;
						}

					}
					Polygon.PushPoint(X, Y);
					Polygon.CorrectExtremePoints();


					Polygon.Direction = Direction;
					Paths.push(Polygon);

				}
			}
		}
	}

	return Paths;
};

function CDrawingPage()
{
	this.left = 0;
	this.top = 0;
	this.right = 0;
	this.bottom = 0;

	this.cachedImage = null;

	this.IsRecalculate = false;
	this.RecalculateTime = -1;
}
CDrawingPage.prototype =
{
	SetRepaint: function (cache_manager)
	{
		if (this.cachedImage != null && this.cachedImage.image != null)
		{
			this.IsRecalculate = true;
			if (-1 == this.RecalculateTime)
				this.RecalculateTime = new Date().getTime();
			return;
		}
		this.UnLock(cache_manager);
	},

	UnLock: function (cache_manager)
	{
		cache_manager.UnLock(this.cachedImage);
		this.cachedImage = null;
		this.IsRecalculate = false;
		this.RecalculateTime = -1;
	}
};

var g_page_outline_inner = false;//AscCommon.AscBrowser.isChrome;
function CPage()
{
	this.width_mm = 210;
	this.height_mm = 297;

	this.margin_left = 0;
	this.margin_top = 0;
	this.margin_right = 0;
	this.margin_bottom = 0;

	this.pageIndex = -1;

	this.searchingArray = [];
	this.selectionArray = [];
	this.drawingPage = new CDrawingPage();

	this.Draw = function (context, xDst, yDst, wDst, hDst, contextW, contextH)
	{
		if (null != this.drawingPage.cachedImage)
		{
			if (!g_page_outline_inner)
			{
				context.strokeStyle = GlobalSkin.PageOutline;
				context.lineWidth = 1;

				// ctx.strokeRect(x - 0.5, y - 0.5, w + 1, h + 1);
				context.beginPath();
				context.moveTo(xDst - 0.5, yDst - 0.5);
				context.lineTo(xDst + wDst + 0.5, yDst - 0.5);
				context.lineTo(xDst + wDst + 0.5, yDst + hDst + 0.5);
				context.lineTo(xDst - 0.5, yDst + hDst + 0.5);
				context.closePath();
				context.stroke();
				context.beginPath();
			}

			// потом посмотреть на кусочную отрисовку
			context.drawImage(this.drawingPage.cachedImage.image, xDst, yDst, wDst, hDst);
		}
		else
		{
			context.fillStyle = "#ffffff";

			if (!g_page_outline_inner)
			{
				context.strokeStyle = GlobalSkin.PageOutline;
				context.lineWidth = 1;

				// ctx.strokeRect(x - 0.5, y - 0.5, w + 1, h + 1);
				context.beginPath();
				context.moveTo(xDst - 0.5, yDst - 0.5);
				context.lineTo(xDst + wDst + 0.5, yDst - 0.5);
				context.lineTo(xDst + wDst + 0.5, yDst + hDst + 0.5);
				context.lineTo(xDst - 0.5, yDst + hDst + 0.5);
				context.closePath();
				context.stroke();
				context.beginPath();
			}

			context.fillRect(xDst, yDst, wDst, hDst);
		}
	};

	this.DrawSelection = function (overlay, xDst, yDst, wDst, hDst, TextMatrix)
	{
		var dKoefX = wDst / this.width_mm;
		var dKoefY = hDst / this.height_mm;

		var selectionArray = this.selectionArray;

		if (null == TextMatrix || global_MatrixTransformer.IsIdentity(TextMatrix))
		{
			for (var i = 0; i < selectionArray.length; i++)
			{
				var r = selectionArray[i];

				var _x = ((xDst + dKoefX * r.x) >> 0) - 0.5;
				var _y = ((yDst + dKoefY * r.y) >> 0) - 0.5;

				var _w = (dKoefX * r.w + 1) >> 0;
				var _h = (dKoefY * r.h + 1) >> 0;

				if (_x < overlay.min_x)
					overlay.min_x = _x;
				if ((_x + _w) > overlay.max_x)
					overlay.max_x = _x + _w;

				if (_y < overlay.min_y)
					overlay.min_y = _y;
				if ((_y + _h) > overlay.max_y)
					overlay.max_y = _y + _h;

				overlay.m_oContext.rect(_x, _y, _w, _h);
			}
		}
		else
		{
			for (var i = 0; i < selectionArray.length; i++)
			{
				var r = selectionArray[i];

				var _x1 = TextMatrix.TransformPointX(r.x, r.y);
				var _y1 = TextMatrix.TransformPointY(r.x, r.y);

				var _x2 = TextMatrix.TransformPointX(r.x + r.w, r.y);
				var _y2 = TextMatrix.TransformPointY(r.x + r.w, r.y);

				var _x3 = TextMatrix.TransformPointX(r.x + r.w, r.y + r.h);
				var _y3 = TextMatrix.TransformPointY(r.x + r.w, r.y + r.h);

				var _x4 = TextMatrix.TransformPointX(r.x, r.y + r.h);
				var _y4 = TextMatrix.TransformPointY(r.x, r.y + r.h);

				var x1 = xDst + dKoefX * _x1;
				var y1 = yDst + dKoefY * _y1;

				var x2 = xDst + dKoefX * _x2;
				var y2 = yDst + dKoefY * _y2;

				var x3 = xDst + dKoefX * _x3;
				var y3 = yDst + dKoefY * _y3;

				var x4 = xDst + dKoefX * _x4;
				var y4 = yDst + dKoefY * _y4;

				overlay.CheckPoint(x1, y1);
				overlay.CheckPoint(x2, y2);
				overlay.CheckPoint(x3, y3);
				overlay.CheckPoint(x4, y4);

				var ctx = overlay.m_oContext;
				ctx.moveTo(x1, y1);
				ctx.lineTo(x2, y2);
				ctx.lineTo(x3, y3);
				ctx.lineTo(x4, y4);
				ctx.closePath();
			}
		}
	}
	this.DrawSearch = function (overlay, xDst, yDst, wDst, hDst, drDoc)
	{
		var dKoefX = wDst / this.width_mm;
		var dKoefY = hDst / this.height_mm;

		// проверяем колонтитулы ------------
		var ret = this.drawInHdrFtr(overlay, xDst, yDst, wDst, hDst, dKoefX, dKoefY, drDoc._search_HdrFtr_All);
		if (!ret && this.pageIndex != 0)
			ret = this.drawInHdrFtr(overlay, xDst, yDst, wDst, hDst, dKoefX, dKoefY, drDoc._search_HdrFtr_All_no_First);
		if (!ret && this.pageIndex == 0)
			ret = this.drawInHdrFtr(overlay, xDst, yDst, wDst, hDst, dKoefX, dKoefY, drDoc._search_HdrFtr_First);
		if (!ret && (this.pageIndex & 1) == 1)
			ret = this.drawInHdrFtr(overlay, xDst, yDst, wDst, hDst, dKoefX, dKoefY, drDoc._search_HdrFtr_Even);
		if (!ret && (this.pageIndex & 1) == 0)
			ret = this.drawInHdrFtr(overlay, xDst, yDst, wDst, hDst, dKoefX, dKoefY, drDoc._search_HdrFtr_Odd);
		if (!ret && (this.pageIndex != 0))
			ret = this.drawInHdrFtr(overlay, xDst, yDst, wDst, hDst, dKoefX, dKoefY, drDoc._search_HdrFtr_Odd_no_First);
		// ----------------------------------

		var ctx = overlay.m_oContext;
		for (var i = 0; i < this.searchingArray.length; i++)
		{
			var place = this.searchingArray[i];

			if (!place.Transform)
			{
				if (undefined === place.Ex)
				{
					var _x = ((xDst + dKoefX * place.X) >> 0) - 0.5;
					var _y = ((yDst + dKoefY * place.Y) >> 0) - 0.5;

					var _w = ((dKoefX * place.W) >> 0) + 1;
					var _h = ((dKoefY * place.H) >> 0) + 1;

					if (_x < overlay.min_x)
						overlay.min_x = _x;
					if ((_x + _w) > overlay.max_x)
						overlay.max_x = _x + _w;

					if (_y < overlay.min_y)
						overlay.min_y = _y;
					if ((_y + _h) > overlay.max_y)
						overlay.max_y = _y + _h;

					ctx.rect(_x, _y, _w, _h);
				}
				else
				{
					var _x1 = (xDst + dKoefX * place.X) >> 0;
					var _y1 = (yDst + dKoefY * place.Y) >> 0;

					var x2 = place.X + place.W * place.Ex;
					var y2 = place.Y + place.W * place.Ey;
					var _x2 = (xDst + dKoefX * x2) >> 0;
					var _y2 = (yDst + dKoefY * y2) >> 0;

					var x3 = x2 - place.H * place.Ey;
					var y3 = y2 + place.H * place.Ex;
					var _x3 = (xDst + dKoefX * x3) >> 0;
					var _y3 = (yDst + dKoefY * y3) >> 0;

					var x4 = place.X - place.H * place.Ey;
					var y4 = place.Y + place.H * place.Ex;
					var _x4 = (xDst + dKoefX * x4) >> 0;
					var _y4 = (yDst + dKoefY * y4) >> 0;

					overlay.CheckPoint(_x1, _y1);
					overlay.CheckPoint(_x2, _y2);
					overlay.CheckPoint(_x3, _y3);
					overlay.CheckPoint(_x4, _y4);

					ctx.moveTo(_x1, _y1);
					ctx.lineTo(_x2, _y2);
					ctx.lineTo(_x3, _y3);
					ctx.lineTo(_x4, _y4);
					ctx.lineTo(_x1, _y1);
				}
			}
			else
			{
				var _tr = place.Transform;
				if (undefined === place.Ex)
				{
					var _x1 = xDst + dKoefX * _tr.TransformPointX(place.X, place.Y);
					var _y1 = yDst + dKoefY * _tr.TransformPointY(place.X, place.Y);

					var _x2 = xDst + dKoefX * _tr.TransformPointX(place.X + place.W, place.Y);
					var _y2 = yDst + dKoefY * _tr.TransformPointY(place.X + place.W, place.Y);

					var _x3 = xDst + dKoefX * _tr.TransformPointX(place.X + place.W, place.Y + place.H);
					var _y3 = yDst + dKoefY * _tr.TransformPointY(place.X + place.W, place.Y + place.H);

					var _x4 = xDst + dKoefX * _tr.TransformPointX(place.X, place.Y + place.H);
					var _y4 = yDst + dKoefY * _tr.TransformPointY(place.X, place.Y + place.H);

					overlay.CheckPoint(_x1, _y1);
					overlay.CheckPoint(_x2, _y2);
					overlay.CheckPoint(_x3, _y3);
					overlay.CheckPoint(_x4, _y4);

					ctx.moveTo(_x1, _y1);
					ctx.lineTo(_x2, _y2);
					ctx.lineTo(_x3, _y3);
					ctx.lineTo(_x4, _y4);
					ctx.lineTo(_x1, _y1);
				}
				else
				{
					var x2 = place.X + place.W * place.Ex;
					var y2 = place.Y + place.W * place.Ey;

					var x3 = x2 - place.H * place.Ey;
					var y3 = y2 + place.H * place.Ex;

					var x4 = place.X - place.H * place.Ey;
					var y4 = place.Y + place.H * place.Ex;

					var _x1 = xDst + dKoefX * _tr.TransformPointX(place.X, place.Y);
					var _y1 = yDst + dKoefY * _tr.TransformPointY(place.X, place.Y);

					var _x2 = xDst + dKoefX * _tr.TransformPointX(x2, y2);
					var _y2 = yDst + dKoefY * _tr.TransformPointY(x2, y2);

					var _x3 = xDst + dKoefX * _tr.TransformPointX(x3, y3);
					var _y3 = yDst + dKoefY * _tr.TransformPointY(x3, y3);

					var _x4 = xDst + dKoefX * _tr.TransformPointX(x4, y4);
					var _y4 = yDst + dKoefY * _tr.TransformPointY(x4, y4);

					overlay.CheckPoint(_x1, _y1);
					overlay.CheckPoint(_x2, _y2);
					overlay.CheckPoint(_x3, _y3);
					overlay.CheckPoint(_x4, _y4);

					ctx.moveTo(_x1, _y1);
					ctx.lineTo(_x2, _y2);
					ctx.lineTo(_x3, _y3);
					ctx.lineTo(_x4, _y4);
					ctx.lineTo(_x1, _y1);
				}
			}
		}
	}

	this.DrawSearch2 = function (overlay, xDst, yDst, wDst, hDst, _searching)
	{
		var dKoefX = wDst / this.width_mm;
		var dKoefY = hDst / this.height_mm;

		var ctx = overlay.m_oContext;
		for (var i = 0; i < _searching.length; i++)
		{
			var _find_count = _searching[i].length;

			for (var j = 0; j < _find_count; j++)
			{
				var place = _searching[i][j];

				if (!place.Transform)
				{
					if (undefined === place.Ex)
					{
						var _x = ((xDst + dKoefX * place.X) >> 0) - 0.5;
						var _y = ((yDst + dKoefY * place.Y) >> 0) - 0.5;

						var _w = ((dKoefX * place.W) >> 0) + 1;
						var _h = ((dKoefY * place.H) >> 0) + 1;

						if (_x < overlay.min_x)
							overlay.min_x = _x;
						if ((_x + _w) > overlay.max_x)
							overlay.max_x = _x + _w;

						if (_y < overlay.min_y)
							overlay.min_y = _y;
						if ((_y + _h) > overlay.max_y)
							overlay.max_y = _y + _h;

						ctx.rect(_x, _y, _w, _h);
					}
					else
					{
						var _x1 = (xDst + dKoefX * place.X) >> 0;
						var _y1 = (yDst + dKoefY * place.Y) >> 0;

						var x2 = place.X + place.W * place.Ex;
						var y2 = place.Y + place.W * place.Ey;
						var _x2 = (xDst + dKoefX * x2) >> 0;
						var _y2 = (yDst + dKoefY * y2) >> 0;

						var x3 = x2 - place.H * place.Ey;
						var y3 = y2 + place.H * place.Ex;
						var _x3 = (xDst + dKoefX * x3) >> 0;
						var _y3 = (yDst + dKoefY * y3) >> 0;

						var x4 = place.X - place.H * place.Ey;
						var y4 = place.Y + place.H * place.Ex;
						var _x4 = (xDst + dKoefX * x4) >> 0;
						var _y4 = (yDst + dKoefY * y4) >> 0;

						overlay.CheckPoint(_x1, _y1);
						overlay.CheckPoint(_x2, _y2);
						overlay.CheckPoint(_x3, _y3);
						overlay.CheckPoint(_x4, _y4);

						ctx.moveTo(_x1, _y1);
						ctx.lineTo(_x2, _y2);
						ctx.lineTo(_x3, _y3);
						ctx.lineTo(_x4, _y4);
						ctx.lineTo(_x1, _y1);
					}
				}
			}
		}
	}

	this.drawInHdrFtr = function (overlay, xDst, yDst, wDst, hDst, dKoefX, dKoefY, arr)
	{
		var _c = arr.length;
		if (0 == _c)
			return false;

		var ctx = overlay.m_oContext;
		for (var i = 0; i < _c; i++)
		{
			var place = arr[i];

			if (!place.Transform)
			{
				if (undefined === place.Ex)
				{
					var _x = ((xDst + dKoefX * place.X) >> 0) - 0.5;
					var _y = ((yDst + dKoefY * place.Y) >> 0) - 0.5;

					var _w = ((dKoefX * place.W) >> 0) + 1;
					var _h = ((dKoefY * place.H) >> 0) + 1;

					if (_x < overlay.min_x)
						overlay.min_x = _x;
					if ((_x + _w) > overlay.max_x)
						overlay.max_x = _x + _w;

					if (_y < overlay.min_y)
						overlay.min_y = _y;
					if ((_y + _h) > overlay.max_y)
						overlay.max_y = _y + _h;

					ctx.rect(_x, _y, _w, _h);
				}
				else
				{
					var _x1 = (xDst + dKoefX * place.X) >> 0;
					var _y1 = (yDst + dKoefY * place.Y) >> 0;

					var x2 = place.X + place.W * place.Ex;
					var y2 = place.Y + place.W * place.Ey;
					var _x2 = (xDst + dKoefX * x2) >> 0;
					var _y2 = (yDst + dKoefY * y2) >> 0;

					var x3 = x2 - place.H * place.Ey;
					var y3 = y2 + place.H * place.Ex;
					var _x3 = (xDst + dKoefX * x3) >> 0;
					var _y3 = (yDst + dKoefY * y3) >> 0;

					var x4 = place.X - place.H * place.Ey;
					var y4 = place.Y + place.H * place.Ex;
					var _x4 = (xDst + dKoefX * x4) >> 0;
					var _y4 = (yDst + dKoefY * y4) >> 0;

					overlay.CheckPoint(_x1, _y1);
					overlay.CheckPoint(_x2, _y2);
					overlay.CheckPoint(_x3, _y3);
					overlay.CheckPoint(_x4, _y4);

					ctx.moveTo(_x1, _y1);
					ctx.lineTo(_x2, _y2);
					ctx.lineTo(_x3, _y3);
					ctx.lineTo(_x4, _y4);
					ctx.lineTo(_x1, _y1);
				}
			}
			else
			{
				var _tr = place.Transform;
				if (undefined === place.Ex)
				{
					var _x1 = xDst + dKoefX * _tr.TransformPointX(place.X, place.Y);
					var _y1 = yDst + dKoefY * _tr.TransformPointY(place.X, place.Y);

					var _x2 = xDst + dKoefX * _tr.TransformPointX(place.X + place.W, place.Y);
					var _y2 = yDst + dKoefY * _tr.TransformPointY(place.X + place.W, place.Y);

					var _x3 = xDst + dKoefX * _tr.TransformPointX(place.X + place.W, place.Y + place.H);
					var _y3 = yDst + dKoefY * _tr.TransformPointY(place.X + place.W, place.Y + place.H);

					var _x4 = xDst + dKoefX * _tr.TransformPointX(place.X, place.Y + place.H);
					var _y4 = yDst + dKoefY * _tr.TransformPointY(place.X, place.Y + place.H);

					overlay.CheckPoint(_x1, _y1);
					overlay.CheckPoint(_x2, _y2);
					overlay.CheckPoint(_x3, _y3);
					overlay.CheckPoint(_x4, _y4);

					ctx.moveTo(_x1, _y1);
					ctx.lineTo(_x2, _y2);
					ctx.lineTo(_x3, _y3);
					ctx.lineTo(_x4, _y4);
					ctx.lineTo(_x1, _y1);
				}
				else
				{
					var x2 = place.X + place.W * place.Ex;
					var y2 = place.Y + place.W * place.Ey;

					var x3 = x2 - place.H * place.Ey;
					var y3 = y2 + place.H * place.Ex;

					var x4 = place.X - place.H * place.Ey;
					var y4 = place.Y + place.H * place.Ex;

					var _x1 = xDst + dKoefX * _tr.TransformPointX(place.X, place.Y);
					var _y1 = yDst + dKoefY * _tr.TransformPointY(place.X, place.Y);

					var _x2 = xDst + dKoefX * _tr.TransformPointX(x2, y2);
					var _y2 = yDst + dKoefY * _tr.TransformPointY(x2, y2);

					var _x3 = xDst + dKoefX * _tr.TransformPointX(x3, y3);
					var _y3 = yDst + dKoefY * _tr.TransformPointY(x3, y3);

					var _x4 = xDst + dKoefX * _tr.TransformPointX(x4, y4);
					var _y4 = yDst + dKoefY * _tr.TransformPointY(x4, y4);

					overlay.CheckPoint(_x1, _y1);
					overlay.CheckPoint(_x2, _y2);
					overlay.CheckPoint(_x3, _y3);
					overlay.CheckPoint(_x4, _y4);

					ctx.moveTo(_x1, _y1);
					ctx.lineTo(_x2, _y2);
					ctx.lineTo(_x3, _y3);
					ctx.lineTo(_x4, _y4);
					ctx.lineTo(_x1, _y1);
				}
			}
		}
		return true;
	}

	this.DrawSearchCur = function (overlay, xDst, yDst, wDst, hDst, places)
	{
		var dKoefX = wDst / this.width_mm;
		var dKoefY = hDst / this.height_mm;

		var len = places.length;

		var ctx = overlay.m_oContext;

		ctx.fillStyle = "rgba(51,102,204,255)";

		for (var i = 0; i < len; i++)
		{
			var place = places[i];
			if (undefined === place.Ex)
			{
				var _x = ((xDst + dKoefX * place.X) >> 0) - 0.5;
				var _y = ((yDst + dKoefY * place.Y) >> 0) - 0.5;

				var _w = ((dKoefX * place.W) >> 0) + 1;
				var _h = ((dKoefY * place.H) >> 0) + 1;

				if (_x < overlay.min_x)
					overlay.min_x = _x;
				if ((_x + _w) > overlay.max_x)
					overlay.max_x = _x + _w;

				if (_y < overlay.min_y)
					overlay.min_y = _y;
				if ((_y + _h) > overlay.max_y)
					overlay.max_y = _y + _h;

				ctx.rect(_x, _y, _w, _h);
			}
			else
			{
				var _x1 = (xDst + dKoefX * place.X) >> 0;
				var _y1 = (yDst + dKoefY * place.Y) >> 0;

				var x2 = place.X + place.W * place.Ex;
				var y2 = place.Y + place.W * place.Ey;
				var _x2 = (xDst + dKoefX * x2) >> 0;
				var _y2 = (yDst + dKoefY * y2) >> 0;

				var x3 = x2 - place.H * place.Ey;
				var y3 = y2 + place.H * place.Ex;
				var _x3 = (xDst + dKoefX * x3) >> 0;
				var _y3 = (yDst + dKoefY * y3) >> 0;

				var x4 = place.X - place.H * place.Ey;
				var y4 = place.Y + place.H * place.Ex;
				var _x4 = (xDst + dKoefX * x4) >> 0;
				var _y4 = (yDst + dKoefY * y4) >> 0;

				overlay.CheckPoint(_x1, _y1);
				overlay.CheckPoint(_x2, _y2);
				overlay.CheckPoint(_x3, _y3);
				overlay.CheckPoint(_x4, _y4);

				ctx.moveTo(_x1, _y1);
				ctx.lineTo(_x2, _y2);
				ctx.lineTo(_x3, _y3);
				ctx.lineTo(_x4, _y4);
				ctx.lineTo(_x1, _y1);
			}
		}

		ctx.fill();
		ctx.beginPath();
	}

	this.DrawTableOutline = function (overlay, xDst, yDst, wDst, hDst, table_outline_dr, lastBounds)
	{
		var transform = table_outline_dr.TableMatrix;
		if (null == transform || transform.IsIdentity2())
		{
			var dKoefX = wDst / this.width_mm;
			var dKoefY = hDst / this.height_mm;

			var _offX = (null == transform) ? 0 : transform.tx;
			var _offY = (null == transform) ? 0 : transform.ty;

			if (!lastBounds)
			{
				var _x = 0;
				var _y = 0;
				switch (table_outline_dr.TrackTablePos)
				{
					case 1:
					{
						_x = (xDst + dKoefX * (table_outline_dr.TableOutline.X + table_outline_dr.TableOutline.W + _offX)) >> 0;
						_y = ((yDst + dKoefY * (table_outline_dr.TableOutline.Y + _offY)) >> 0) - 13;
						break;
					}
					case 2:
					{
						_x = (xDst + dKoefX * (table_outline_dr.TableOutline.X + table_outline_dr.TableOutline.W + _offX)) >> 0;
						_y = (yDst + dKoefY * (table_outline_dr.TableOutline.Y + table_outline_dr.TableOutline.H + _offY)) >> 0;
						break;
					}
					case 3:
					{
						_x = ((xDst + dKoefX * (table_outline_dr.TableOutline.X + _offX)) >> 0) - 13;
						_y = (yDst + dKoefY * (table_outline_dr.TableOutline.Y + table_outline_dr.TableOutline.H + _offY)) >> 0;
						break;
					}
					case 0:
					default:
					{
						_x = ((xDst + dKoefX * (table_outline_dr.TableOutline.X + _offX)) >> 0) - 13;
						_y = ((yDst + dKoefY * (table_outline_dr.TableOutline.Y + _offY)) >> 0) - 13;
						break;
					}
				}

				var _w = 13;
				var _h = 13;

				if (_x < overlay.min_x)
					overlay.min_x = _x;
				if ((_x + _w) > overlay.max_x)
					overlay.max_x = _x + _w;

				if (_y < overlay.min_y)
					overlay.min_y = _y;
				if ((_y + _h) > overlay.max_y)
					overlay.max_y = _y + _h;

				var tmp_image = overlay.IsRetina ? table_outline_dr.image2 : table_outline_dr.image;
				if (tmp_image.asc_complete)
					overlay.m_oContext.drawImage(tmp_image, _x, _y, 13, 13);
			}
			else
			{
				var _xLast = (xDst + dKoefX * (lastBounds.X + lastBounds.W + _offX) + 0.5) >> 0;
				var _yLast = (yDst + dKoefY * (lastBounds.Y + lastBounds.H + _offY) + 0.5) >> 0;

				var ctx = overlay.m_oContext;
				ctx.strokeStyle = "rgb(140, 140, 140)";
				ctx.lineWidth = 1;
				ctx.beginPath();

				overlay.AddRect(_xLast - 0.5, _yLast - 0.5, 6, 6);

				ctx.stroke();
				ctx.beginPath();
			}
		}
		else
		{
			var ctx = overlay.m_oContext;

			var _ft = new AscCommon.CMatrix();
			_ft.sx = transform.sx;
			_ft.shx = transform.shx;
			_ft.shy = transform.shy;
			_ft.sy = transform.sy;
			_ft.tx = transform.tx;
			_ft.ty = transform.ty;

			var coords = new AscCommon.CMatrix();
			coords.sx = wDst / this.width_mm;
			coords.sy = hDst / this.height_mm;
			coords.tx = xDst;
			coords.ty = yDst;

			global_MatrixTransformer.MultiplyAppend(_ft, coords);

			if (!lastBounds)
			{
				ctx.transform(_ft.sx, _ft.shy, _ft.shx, _ft.sy, _ft.tx, _ft.ty);

				var _x = 0;
				var _y = 0;
				var _w = 13 / coords.sx;
				var _h = 13 / coords.sy;
				switch (table_outline_dr.TrackTablePos)
				{
					case 1:
					{
						_x = (table_outline_dr.TableOutline.X + table_outline_dr.TableOutline.W);
						_y = (table_outline_dr.TableOutline.Y - _h);
						break;
					}
					case 2:
					{
						_x = (table_outline_dr.TableOutline.X + table_outline_dr.TableOutline.W);
						_y = (table_outline_dr.TableOutline.Y + table_outline_dr.TableOutline.H);
						break;
					}
					case 3:
					{
						_x = (table_outline_dr.TableOutline.X - _w);
						_y = (table_outline_dr.TableOutline.Y + table_outline_dr.TableOutline.H);
						break;
					}
					case 0:
					default:
					{
						_x = (table_outline_dr.TableOutline.X - _w);
						_y = (table_outline_dr.TableOutline.Y - _h);
						break;
					}
				}

				overlay.CheckPoint(_ft.TransformPointX(_x, _y), _ft.TransformPointY(_x, _y));
				overlay.CheckPoint(_ft.TransformPointX(_x + _w, _y), _ft.TransformPointY(_x + _w, _y));
				overlay.CheckPoint(_ft.TransformPointX(_x + _w, _y + _h), _ft.TransformPointY(_x + _w, _y + _h));
				overlay.CheckPoint(_ft.TransformPointX(_x, _y + _h), _ft.TransformPointY(_x, _y + _h));

				var tmp_image = overlay.IsRetina ? table_outline_dr.image2 : table_outline_dr.image;
				if (tmp_image.asc_complete)
					overlay.m_oContext.drawImage(tmp_image, _x, _y, _w, _h);

				overlay.SetBaseTransform();
			}
			else
			{
				var _xLast = (lastBounds.X + lastBounds.W);
				var _yLast = (lastBounds.Y + lastBounds.H);

				var ctx = overlay.m_oContext;
				ctx.strokeStyle = "rgb(140, 140, 140)";
				ctx.fillStyle = "#FFFFFF";
				ctx.lineWidth = 1;
				ctx.beginPath();

				var _dist = 6 / _ft.GetScaleValue();

				var _arr = [
					_ft.TransformPointX(_xLast, _yLast),
					_ft.TransformPointY(_xLast, _yLast),
					_ft.TransformPointX(_xLast + _dist, _yLast),
					_ft.TransformPointY(_xLast + _dist, _yLast),
					_ft.TransformPointX(_xLast + _dist, _yLast + _dist),
					_ft.TransformPointY(_xLast + _dist, _yLast + _dist),
					_ft.TransformPointX(_xLast, _yLast + _dist),
					_ft.TransformPointY(_xLast, _yLast + _dist)
				];

				overlay.CheckPoint(_arr[0], _arr[1]);
				overlay.CheckPoint(_arr[2], _arr[3]);
				overlay.CheckPoint(_arr[4], _arr[5]);
				overlay.CheckPoint(_arr[6], _arr[7]);

				ctx.moveTo(_arr[0], _arr[1]);
				ctx.lineTo(_arr[2], _arr[3]);
				ctx.lineTo(_arr[4], _arr[5]);
				ctx.lineTo(_arr[6], _arr[7]);
				ctx.closePath();

				ctx.fill();
				ctx.stroke();
				ctx.beginPath();
			}
		}
	}
}

function CDrawingCollaborativeTarget()
{
	this.Id = "";
	this.ShortId = "";

	this.X = 0;
	this.Y = 0;
	this.Size = 0;
	this.Page = -1;

	this.Color = null;
	this.Transform = null;

	this.HtmlElement = null;
	this.HtmlElementX = 0;
	this.HtmlElementY = 0;

	this.Color = null;

	this.Style = "";
	this.IsInsertToDOM = false;
}
CDrawingCollaborativeTarget.prototype =
{
	CheckPosition: function (_drawing_doc, _x, _y, _size, _page, _transform)
	{
		// 1) создаем новый элемент, если еще его не было
		var bIsHtmlElementCreate = false;
		if (this.HtmlElement == null)
		{
			bIsHtmlElementCreate = true;
			this.HtmlElement = document.createElement('canvas');
			this.HtmlElement.style.cssText = "pointer-events: none;position:absolute;padding:0;margin:0;-webkit-user-select:none;width:1px;height:1px;display:block;z-index:3;";
			this.HtmlElement.width = 1;
			this.HtmlElement.height = 1;

			this.Color = AscCommon.getUserColorById(this.ShortId, null, true);
			this.Style = "rgb(" + this.Color.r + "," + this.Color.g + "," + this.Color.b + ")";
		}

		// 2) определяем размер
		this.Transform = _transform;
		this.Size = _size;

		var _old_x = this.X;
		var _old_y = this.Y;
		var _old_page = this.Page;

		this.X = _x;
		this.Y = _y;
		this.Page = _page;

		var _oldW = this.HtmlElement.width;
		var _oldH = this.HtmlElement.height;

		var _newW = 2;
		var _newH = (this.Size * _drawing_doc.m_oWordControl.m_nZoomValue * g_dKoef_mm_to_pix / 100) >> 0;

		if (null != this.Transform && !global_MatrixTransformer.IsIdentity2(this.Transform))
		{
			var _x1 = this.Transform.TransformPointX(_x, _y);
			var _y1 = this.Transform.TransformPointY(_x, _y);

			var _x2 = this.Transform.TransformPointX(_x, _y + this.Size);
			var _y2 = this.Transform.TransformPointY(_x, _y + this.Size);

			var pos1 = _drawing_doc.ConvertCoordsToCursor2(_x1, _y1, this.Page);
			var pos2 = _drawing_doc.ConvertCoordsToCursor2(_x2, _y2, this.Page);

			_newW = (Math.abs(pos1.X - pos2.X) >> 0) + 1;
			_newH = (Math.abs(pos1.Y - pos2.Y) >> 0) + 1;

			if (2 > _newW)
				_newW = 2;
			if (2 > _newH)
				_newH = 2;

			if (_oldW == _newW && _oldH == _newH)
			{
				if (_newW != 2 && _newH != 2)
				{
					// просто очищаем
					this.HtmlElement.width = _newW;
				}
			}
			else
			{
				this.HtmlElement.style.width = _newW + "px";
				this.HtmlElement.style.height = _newH + "px";

				this.HtmlElement.width = _newW;
				this.HtmlElement.height = _newH;
			}
			var ctx = this.HtmlElement.getContext('2d');

			if (_newW == 2 || _newH == 2)
			{
				ctx.fillStyle = this.Style;
				ctx.fillRect(0, 0, _newW, _newH);
			}
			else
			{
				ctx.beginPath();
				ctx.strokeStyle = this.Style;
				ctx.lineWidth = 2;

				if (((pos1.X - pos2.X) * (pos1.Y - pos2.Y)) >= 0)
				{
					ctx.moveTo(0, 0);
					ctx.lineTo(_newW, _newH);
				}
				else
				{
					ctx.moveTo(0, _newH);
					ctx.lineTo(_newW, 0);
				}

				ctx.stroke();
			}

			this.HtmlElementX = Math.min(pos1.X, pos2.X) >> 0;
			this.HtmlElementY = Math.min(pos1.Y, pos2.Y) >> 0;
			if ((!_drawing_doc.m_oWordControl.MobileTouchManager && !AscCommon.AscBrowser.isSafariMacOs) || !AscCommon.AscBrowser.isWebkit)
			{
				this.HtmlElement.style.left = this.HtmlElementX + "px";
				this.HtmlElement.style.top = this.HtmlElementY + "px";
			}
			else
			{
				this.HtmlElement.style.left = "0px";
				this.HtmlElement.style.top = "0px";
				this.HtmlElement.style["webkitTransform"] = "matrix(1, 0, 0, 1, " + this.HtmlElementX + "," + this.HtmlElementY + ")";
			}
		}
		else
		{
			if (_oldW == _newW && _oldH == _newH)
			{
				// просто очищаем
				this.HtmlElement.width = _newW;
			}
			else
			{
				this.HtmlElement.style.width = _newW + "px";
				this.HtmlElement.style.height = _newH + "px";

				this.HtmlElement.width = _newW;
				this.HtmlElement.height = _newH;
			}

			var ctx = this.HtmlElement.getContext('2d');

			ctx.fillStyle = this.Style;
			ctx.fillRect(0, 0, _newW, _newH);

			if (null != this.Transform)
			{
				_x += this.Transform.tx;
				_y += this.Transform.ty;
			}

			var pos = _drawing_doc.ConvertCoordsToCursor2(_x, _y, this.Page);

			this.HtmlElementX = pos.X >> 0;
			this.HtmlElementY = pos.Y >> 0;

			if ((!_drawing_doc.m_oWordControl.MobileTouchManager && !AscCommon.AscBrowser.isSafariMacOs) || !AscCommon.AscBrowser.isWebkit)
			{
				this.HtmlElement.style.left = this.HtmlElementX + "px";
				this.HtmlElement.style.top = this.HtmlElementY + "px";
			}
			else
			{
				this.HtmlElement.style.left = "0px";
				this.HtmlElement.style.top = "0px";
				this.HtmlElement.style["webkitTransform"] = "matrix(1, 0, 0, 1, " + this.HtmlElementX + "," + this.HtmlElementY + ")";
			}
		}

		if (AscCommon.CollaborativeEditing)
			AscCommon.CollaborativeEditing.Update_ForeignCursorLabelPosition(this.Id, this.HtmlElementX, this.HtmlElementY, this.Color);

		// 3) добавить, если нужно
		if (bIsHtmlElementCreate)
		{
			_drawing_doc.m_oWordControl.m_oMainView.HtmlElement.appendChild(this.HtmlElement);
			this.IsInsertToDOM = true;
		}
	},

	Remove: function (_drawing_doc)
	{
		if (this.IsInsertToDOM)
		{
			_drawing_doc.m_oWordControl.m_oMainView.HtmlElement.removeChild(this.HtmlElement);
			this.IsInsertToDOM = false;
		}
	},

	Update: function (_drawing_doc)
	{
		this.CheckPosition(_drawing_doc, this.X, this.Y, this.Size, this.Page, this.Transform);
	}
};

function CDrawingDocument()
{
	this.IsLockObjectsEnable = false;

	AscCommon.g_oHtmlCursor.register("de-markerformat", "marker_format", ["marker_format", 14, 8], "pointer");
	AscCommon.g_oHtmlCursor.register("select-table-row", "select_row", ["select_row", 10, 5], "default");
	AscCommon.g_oHtmlCursor.register("select-table-column", "select_column", ["select_column", 5, 10], "default");
	AscCommon.g_oHtmlCursor.register("select-table-cell", "select_cell", ["select_cell", 9, 0], "default");

	this.m_oWordControl = null;
	this.m_oLogicDocument = null;
	this.m_oDocumentRenderer = null;

	this.m_arrPages = [];
	this.m_lPagesCount = 0;

	this.m_lDrawingFirst = -1;
	this.m_lDrawingEnd = -1;
	this.m_lCurrentPage = -1;

	this.FrameRect = {
		IsActive: false, Rect: {X: 0, Y: 0, R: 0, B: 0}, Frame: null,
		Track: {X: 0, Y: 0, L: 0, T: 0, R: 0, B: 0, PageIndex: 0, Type: -1}, IsTracked: false, PageIndex: 0
	};

	this.MathRect = {IsActive: false, Bounds: [], ContentSelection: null};
	this.MathPolygons = [];
	this.MathSelectPolygons = [];
	this.FieldTrack = {IsActive: false, Rects: []};

	this.m_oCacheManager = new CCacheManager();

	this.m_lCountCalculatePages = 0;

	this.m_bIsDocumentCalculating = true;
	this.m_arPrintingWaitEndRecalculate = null;

	this.m_lTimerTargetId = -1;
	this.m_dTargetX = -1;
	this.m_dTargetY = -1;
	this.m_lTargetPage = -1;
	this.m_dTargetSize = 1;

	this.NeedScrollToTargetFlag = false;

	this.TargetHtmlElement = null;
	this.TargetHtmlElementBlock = false; // true - block, false - visibility
	this.TargetHtmlElementLeft = 0;
	this.TargetHtmlElementTop = 0;

	this.CollaborativeTargets = [];
	this.CollaborativeTargetsUpdateTasks = [];

	this.m_bIsBreakRecalculate = false;

	this.m_bIsSelection = false;
	this.m_bIsSearching = false;
	this.m_lCountRect = 0;

	this.CurrentSearchNavi = null;
	this.SearchTransform = null;

	this.m_lTimerUpdateTargetID = -1;
	this.m_tempX = 0;
	this.m_tempY = 0;
	this.m_tempPageIndex = 0;

	var oThis = this;
	this.m_sLockedCursorType = "";
	this.TableOutlineDr = new CTableOutlineDr();

	this.m_lCurrentRendererPage = -1;
	this.m_oDocRenderer = null;
	this.m_bOldShowMarks = false;

	this.UpdateTargetFromPaint = false;
	this.UpdateTargetCheck = false;
	this.NeedTarget = true;
	this.TextMatrix = null;
	this.TargetShowFlag = false;
	this.TargetShowNeedFlag = false;

	this.SelectionMatrix = null;

	this.CanvasHit = document.createElement('canvas');
	this.CanvasHit.width = 10;
	this.CanvasHit.height = 10;
	this.CanvasHitContext = this.CanvasHit.getContext('2d');

	this.TargetCursorColor = {R: 0, G: 0, B: 0};

	this.GuiControlColorsMap = null;
	this.IsSendStandartColors = false;

	this.GuiCanvasFillTextureParentId = "";
	this.GuiCanvasFillTexture = null;
	this.GuiCanvasFillTextureCtx = null;
	this.LastDrawingUrl = "";

	this.GuiCanvasTextProps = null;
	this.GuiCanvasTextPropsId = "gui_textprops_canvas_id";
	this.GuiLastTextProps = null;

	this.GuiCanvasFillTOCParentId = "";
	this.GuiCanvasFillTOC = null;

	this.TableStylesLastLook = null;
	this.LastParagraphMargins = null;

	this.TableStylesCheckLook = null;
	this.TableStylesCheckLookFlag = false;

	this.InlineTextTrackEnabled = false;
	this.InlineTextTrack = null;
	this.InlineTextTrackPage = -1;

	this.AutoShapesTrack = null;
	this.AutoShapesTrackLockPageNum = -1;

	this.Overlay = null;
	this.IsTextMatrixUse = false;
	this.IsTextSelectionOutline = false;

	this.OverlaySelection2 = {};

	this.HorVerAnchors = [];

	this.MathMenuLoad = false;

	this.UpdateRulerStateFlag = false;
	this.UpdateRulerStateParams = [];

	this.ContentControlObjects = [];
	this.ContentControlObjectsLast = [];
	this.ContentControlObjectState = -1;
	this.ContentControlSmallChangesCheck = { X: 0, Y: 0, Page: 0, Min: 2, IsSmall : true };

	// массивы ректов для поиска
	this._search_HdrFtr_All = []; // Поиск в колонтитуле, который находится на всех страницах
	this._search_HdrFtr_All_no_First = []; // Поиск в колонтитуле, который находится на всех страницах, кроме первой
	this._search_HdrFtr_First = []; // Поиск в колонтитуле, который находится только на первой странице
	this._search_HdrFtr_Even = []; // Поиск в колонтитуле, который находится только на нечетных страницах
	this._search_HdrFtr_Odd = []; // Поиск в колонтитуле, который находится только на четных страницах, включая первую
	this._search_HdrFtr_Odd_no_First = []; // Поиск в колонтитуле, который находится только на нечетных страницах, кроме первой

	this.showTarget = function (isShow)
	{
		if (this.TargetHtmlElementBlock)
			this.TargetHtmlElement.style.display = isShow ? "display" : "none";
		else
			this.TargetHtmlElement.style.visibility = isShow ? "visible" : "hidden";
	};
	this.isShowTarget = function ()
	{
		if (this.TargetHtmlElementBlock)
			return (this.TargetHtmlElement.style.display == "display") ? true : false;
		else
			return (this.TargetHtmlElement.style.visibility == "visible") ? true : false;
	};

	this.Start_CollaborationEditing = function ()
	{
		this.IsLockObjectsEnable = true;
		this.m_oWordControl.OnRePaintAttack();
	}
	this.SetCursorType = function (sType, Data)
	{
		if ("" == this.m_sLockedCursorType)
		{
			if (AscCommon.c_oAscFormatPainterState.kOff !== this.m_oWordControl.m_oApi.isPaintFormat && "text" == sType)
				this.m_oWordControl.m_oMainContent.HtmlElement.style.cursor = AscCommon.g_oHtmlCursor.value(AscCommon.kCurFormatPainterWord);
			else if (this.m_oWordControl.m_oApi.isMarkerFormat && "text" == sType)
				this.m_oWordControl.m_oMainContent.HtmlElement.style.cursor = AscCommon.g_oHtmlCursor.value("de-markerformat");
			else
				this.m_oWordControl.m_oMainContent.HtmlElement.style.cursor = AscCommon.g_oHtmlCursor.value(sType);
		}
		else
			this.m_oWordControl.m_oMainContent.HtmlElement.style.cursor = AscCommon.g_oHtmlCursor.value(this.m_sLockedCursorType);

		if ("undefined" === typeof(Data) || null === Data)
			Data = new AscCommon.CMouseMoveData();

		editor.sync_MouseMoveCallback(Data);
	}
	this.LockCursorType = function (sType)
	{
		this.m_sLockedCursorType = sType;
		this.m_oWordControl.m_oMainContent.HtmlElement.style.cursor = AscCommon.g_oHtmlCursor.value(this.m_sLockedCursorType);
	}
	this.LockCursorTypeCur = function ()
	{
		this.m_sLockedCursorType = this.m_oWordControl.m_oMainContent.HtmlElement.style.cursor;
	}
	this.UnlockCursorType = function ()
	{
		this.m_sLockedCursorType = "";
	}

	this.OnStartRecalculate = function (pageCount)
	{
		if (!this.m_oWordControl.MobileTouchManager)
			this.TableOutlineDr.TableOutline = null;

		if (this.m_oWordControl)
			this.m_oWordControl.m_oApi.checkLastWork();

		this.m_lCountCalculatePages = pageCount;
		//console.log("start " + this.m_lCountCalculatePages);

		if (this.m_oWordControl && this.m_oWordControl.MobileTouchManager)
			this.m_oWordControl.MobileTouchManager.ClearContextMenu();

		this.m_bIsDocumentCalculating = true;
	}

	this.OnRepaintPage = function (index)
	{
		if (this.m_oWordControl)
			this.m_oWordControl.m_oApi.checkLastWork();

		var page = this.m_arrPages[index];
		if (!page)
			return;

		page.drawingPage.SetRepaint(this.m_oCacheManager);

		// перерисовать, если только страница видна на экране
		if (index >= this.m_lDrawingFirst && index <= this.m_lDrawingEnd)
		{
			this.m_oWordControl.OnScroll();
		}
	}

	this.OnRecalculatePage = function (index, pageObject)
	{
		this.m_bIsDocumentCalculating = true;

		editor.sendEvent("asc_onDocumentChanged");
		if (true === this.m_bIsSearching)
		{
			this.SearchClear();
			this.m_oWordControl.OnUpdateOverlay();
		}

		if (this.m_bIsBreakRecalculate)
		{
			this.m_bIsBreakRecalculate = false;
			this.m_lCountCalculatePages = index;
		}

		this.m_lCountCalculatePages = index + 1;
		//console.log("calc " + this.m_lCountCalculatePages);

		/*
		 if (index >= this.m_lPagesCount)
		 {
		 this.m_arrPages[index] = new CPage();
		 }
		 */
		if (undefined === this.m_arrPages[index])
			this.m_arrPages[index] = new CPage();

		var page = this.m_arrPages[index];

		page.width_mm = pageObject.Width;
		page.height_mm = pageObject.Height;

		page.margin_left = pageObject.Margins.Left;
		page.margin_top = pageObject.Margins.Top;
		page.margin_right = pageObject.Margins.Right;
		page.margin_bottom = pageObject.Margins.Bottom;

		page.index = index;

		page.drawingPage.SetRepaint(this.m_oCacheManager);

		// теперь если эта страница на экране - то нужно вызвать отрисовку
		if (index >= this.m_lDrawingFirst && index <= this.m_lDrawingEnd)
		{
			this.m_oWordControl.OnScroll();
		}

		if (this.m_lCountCalculatePages > (this.m_lPagesCount + 50) || (0 == this.m_lPagesCount && 0 != this.m_lCountCalculatePages))
		{
			this.OnEndRecalculate(false);
		}
	}

	this.OnEndRecalculate = function (isFull, isBreak)
	{
		if (this.m_oWordControl)
			this.m_oWordControl.m_oApi.checkLastWork();

		if (undefined != isBreak)
		{
			this.m_lCountCalculatePages = this.m_lPagesCount;
		}

		for (var index = this.m_lCountCalculatePages; index < this.m_lPagesCount; index++)
		{
			var page = this.m_arrPages[index];
			page.drawingPage.SetRepaint(this.m_oCacheManager);
		}

		this.m_bIsBreakRecalculate = (isFull === true) ? false : true;
		if (isFull)
		{
			if (this.m_lPagesCount > this.m_lCountCalculatePages)
			{
				this.m_arrPages.splice(this.m_lCountCalculatePages, this.m_lPagesCount - this.m_lCountCalculatePages);
			}

			this.m_lPagesCount = this.m_lCountCalculatePages;
			this.m_oWordControl.CalculateDocumentSize();
			/*
			 if (true === this.m_bIsUpdateDocSize)
			 {
			 this.m_oWordControl.OnScroll();
			 this.m_oWordControl.OnUpdateSelection();
			 }
			 */
		}
		else if ((this.m_lPagesCount + 50) < this.m_lCountCalculatePages)
		{
			this.m_lPagesCount = this.m_lCountCalculatePages;
			this.m_oWordControl.CalculateDocumentSize();
		}
		else if (0 == this.m_lPagesCount && 0 != this.m_lCountCalculatePages)
		{
			this.m_lPagesCount = this.m_lCountCalculatePages;
			this.m_oWordControl.CalculateDocumentSize();
		}

		//if (this.m_lCurrentPage >= this.m_lPagesCount)
		//    this.m_lCurrentPage = this.m_lPagesCount - 1;
		if (true === isBreak || isFull)
		{
			//this.m_oWordControl.m_oLogicDocument.RecalculateCurPos();
			this.m_lCurrentPage = this.m_oWordControl.m_oLogicDocument.Get_CurPage();
			this.m_oWordControl.m_oApi.sendEvent("asc_onEndCalculate");
			this.m_bIsDocumentCalculating = false;

			window.setTimeout(function() {
                editor.WordControl.onMouseMove(undefined, undefined);
            }, 1);
		}

		if (-1 != this.m_lCurrentPage)
		{
			this.m_oWordControl.m_oApi.sync_currentPageCallback(this.m_lCurrentPage);
			this.m_oWordControl.m_oApi.sync_countPagesCallback(this.m_lPagesCount);

			var bIsSendCurPage = true;
			if (this.m_oWordControl.m_oLogicDocument && this.m_oWordControl.m_oLogicDocument.DrawingObjects)
			{
				var param = this.m_oWordControl.m_oLogicDocument.DrawingObjects.isNeedUpdateRulers();
				if (true === param)
				{
					bIsSendCurPage = false;
					this.m_oWordControl.SetCurrentPage(false);
				}
			}

			if (bIsSendCurPage && this.FrameRect.IsActive)
			{
				bIsSendCurPage = false;
				this.m_oWordControl.SetCurrentPage(false);
			}

			if (bIsSendCurPage)
			{
				this.m_oWordControl.SetCurrentPage(false);
			}
		}

		if (isFull)
		{
			this.m_oWordControl.OnScroll();

			if (this.m_arPrintingWaitEndRecalculate)
				this.m_oWordControl.m_oApi._downloadAs.apply(this.m_oWordControl.m_oApi, this.m_arPrintingWaitEndRecalculate);
		}

		//console.log("end " + this.m_lCountCalculatePages + "," + isFull + "," + isBreak);
	}

	this.ChangePageAttack = function (pageIndex)
	{
		if (pageIndex < this.m_lDrawingFirst || pageIndex > this.m_lDrawingEnd)
			return;

		this.StopRenderingPage(pageIndex);
		this.m_oWordControl.OnScroll();
	}

	this.CheckPagesSizeMaximum = function(_w, _h)
	{
		var w = _w;
		var h = _h;

		// заглушка под мобильную версию (iPad не рисует большие картинки (наверное страховка по памяти))
		if (g_bIsMobile)
		{
			var _mobile_max = 2500;
			if (w > _mobile_max || h > _mobile_max)
			{
				if (w > h)
				{
					h = (h * _mobile_max / w) >> 0;
					w = _mobile_max;
				}
				else
				{
					w = (w * _mobile_max / h) >> 0;
					h = _mobile_max;
				}
			}
		}

		return [w, h];
	}

	this.CheckRecalculatePage = function (width, height, pageIndex)
	{
		var _drawingPage = this.m_arrPages[pageIndex].drawingPage;
		var isUnlock = false;

		if (_drawingPage.cachedImage != null && _drawingPage.cachedImage.image != null)
		{
			var _check = this.CheckPagesSizeMaximum(width, height);
			if (_check[0] != _drawingPage.cachedImage.image.width || _check[1] != _drawingPage.cachedImage.image.height)
				isUnlock = true;
		}

		if (_drawingPage.IsRecalculate)
		{
			if (this.IsFreezePage(pageIndex))
			{
				// убрал выкидывание страницы. лишнее это. пусть всегда рисуется старая, пока не перерисуем
				//if ((Math.abs(_drawingPage.RecalculateTime - (new Date().getTime())) > 500 /*0.5 sec*/))
				//	isUnlock = true;
			}
			else
			{
				isUnlock = true;
			}
		}

		if (isUnlock)
			_drawingPage.UnLock(this.m_oCacheManager);
	}

	this.StartRenderingPage = function (pageIndex)
	{
		if (true === this.IsFreezePage(pageIndex))
		{
			return;
		}

		var page = this.m_arrPages[pageIndex];

		var dKoef = (this.m_oWordControl.m_nZoomValue * g_dKoef_mm_to_pix / 100);

		var w = (page.width_mm * dKoef + 0.5) >> 0;
		var h = (page.height_mm * dKoef + 0.5) >> 0;

		if (this.m_oWordControl.bIsRetinaSupport)
		{
			w = AscCommon.AscBrowser.convertToRetinaValue(w, true);
			h = AscCommon.AscBrowser.convertToRetinaValue(h, true);
		}

		var _check = this.CheckPagesSizeMaximum(w, h);
		w = _check[0];
		h = _check[1];

		page.drawingPage.UnLock(this.m_oCacheManager);
		page.drawingPage.cachedImage = this.m_oCacheManager.Lock(w, h);

		//var StartTime = new Date().getTime();

		// теперь берем графикс
		var g = new AscCommon.CGraphics();
		g.init(page.drawingPage.cachedImage.image.ctx, w, h, page.width_mm, page.height_mm);
		g.m_oFontManager = AscCommon.g_fontManager;

		g.transform(1, 0, 0, 1, 0, 0);

		if (null == this.m_oDocumentRenderer)
			this.m_oLogicDocument.DrawPage(pageIndex, g);
		else
			this.m_oDocumentRenderer.drawPage(pageIndex, g);

		if (g_page_outline_inner)
		{
			var context = page.drawingPage.cachedImage.image.ctx;

			context.strokeStyle = GlobalSkin.PageOutline;
			context.lineWidth = 1;

			context.beginPath();
			context.moveTo(0.5, 0.5);
			context.lineTo(w - 0.5, 0.5);
			context.lineTo(w - 0.5, h - 0.5);
			context.lineTo(0.5, h - 0.5);
			context.closePath();
			context.stroke();
			context.beginPath();
		}

		if (this.m_oWordControl.m_oApi.watermarkDraw)
			this.m_oWordControl.m_oApi.watermarkDraw.Draw(page.drawingPage.cachedImage.image.ctx, w, h);

		//var EndTime = new Date().getTime();

		//alert("" + ((EndTime - StartTime) / 1000));
	}

	this.IsFreezePage = function (pageIndex)
	{
		if (pageIndex >= 0 && (pageIndex < Math.min(this.m_lCountCalculatePages, this.m_lPagesCount)))
		{
			if (this.m_oLogicDocument)
			{
				if (pageIndex >= this.m_oLogicDocument.Pages.length)
					return true;
				else if (!this.m_oLogicDocument.CanDrawPage(pageIndex))
					return true;
			}
			return false;
		}
		return true;
	}

	this.RenderDocument = function (Renderer)
	{
		for (var i = 0; i < this.m_lPagesCount; i++)
		{
			var page = this.m_arrPages[i];
			Renderer.BeginPage(page.width_mm, page.height_mm);
			this.m_oLogicDocument.DrawPage(i, Renderer);
			Renderer.EndPage();
		}
	}

	this.ToRenderer = function ()
	{
		var Renderer = new AscCommon.CDocumentRenderer();
		Renderer.InitPicker(AscCommon.g_oTextMeasurer.m_oManager);
		Renderer.VectorMemoryForPrint = new AscCommon.CMemory();
		var old_marks = this.m_oWordControl.m_oApi.ShowParaMarks;
		this.m_oWordControl.m_oApi.ShowParaMarks = false;
		this.RenderDocument(Renderer);
		this.m_oWordControl.m_oApi.ShowParaMarks = old_marks;
		var ret = Renderer.Memory.GetBase64Memory();
		//console.log(ret);
		return ret;
	}

	this.CheckPrint = function(params)
	{
		if (!this.m_oWordControl.m_oLogicDocument)
			return false;

		if (this.m_arPrintingWaitEndRecalculate)
		{
			this.m_oWordControl.m_oApi.sync_EndAction(Asc.c_oAscAsyncActionType.BlockInteraction, params[2]);
			this.m_arPrintingWaitEndRecalculate = null;
			return false;
		}

		if (!this.m_bIsDocumentCalculating)
			return false;

		this.m_arPrintingWaitEndRecalculate = params;
		this.m_oWordControl.m_oApi.sync_StartAction(Asc.c_oAscAsyncActionType.BlockInteraction, params[2]);
		return true;
	}

	this.ToRenderer2 = function ()
	{
		var Renderer = new AscCommon.CDocumentRenderer();
        Renderer.InitPicker(AscCommon.g_oTextMeasurer.m_oManager);

		var old_marks = this.m_oWordControl.m_oApi.ShowParaMarks;
		this.m_oWordControl.m_oApi.ShowParaMarks = false;

		var ret = "";
		for (var i = 0; i < this.m_lPagesCount; i++)
		{
			var page = this.m_arrPages[i];
			Renderer.BeginPage(page.width_mm, page.height_mm);
			this.m_oLogicDocument.DrawPage(i, Renderer);
			Renderer.EndPage();

			ret += Renderer.Memory.GetBase64Memory();
			Renderer.Memory.Seek(0);
		}

		this.m_oWordControl.m_oApi.ShowParaMarks = old_marks;
		//console.log(ret);
		return ret;
	}
	this.ToRendererPart = function (noBase64)
	{
		var watermark = this.m_oWordControl.m_oApi.watermarkDraw;

		var pagescount = Math.min(this.m_lPagesCount, this.m_lCountCalculatePages);

		if (-1 == this.m_lCurrentRendererPage)
		{
			if (watermark)
				watermark.StartRenderer();

			this.m_oDocRenderer = new AscCommon.CDocumentRenderer();
            this.m_oDocRenderer.InitPicker(AscCommon.g_oTextMeasurer.m_oManager);
			this.m_oDocRenderer.VectorMemoryForPrint = new AscCommon.CMemory();
			this.m_lCurrentRendererPage = 0;
			this.m_bOldShowMarks = this.m_oWordControl.m_oApi.ShowParaMarks;
			this.m_oWordControl.m_oApi.ShowParaMarks = false;
		}

		var start = this.m_lCurrentRendererPage;
		var end = pagescount - 1;

		var renderer = this.m_oDocRenderer;
		renderer.Memory.Seek(0);
		renderer.VectorMemoryForPrint.ClearNoAttack();

		for (var i = start; i <= end; i++)
		{
			var page = this.m_arrPages[i];
			renderer.BeginPage(page.width_mm, page.height_mm);
			this.m_oLogicDocument.DrawPage(i, renderer);

			if (watermark)
				watermark.DrawOnRenderer(renderer, page.width_mm, page.height_mm);

			renderer.EndPage();
		}

		this.m_lCurrentRendererPage = end + 1;

		if (this.m_lCurrentRendererPage >= pagescount)
		{
			if (watermark)
				watermark.EndRenderer();

			this.m_lCurrentRendererPage = -1;
			this.m_oDocRenderer = null;
			this.m_oWordControl.m_oApi.ShowParaMarks = this.m_bOldShowMarks;
		}

		if (noBase64) {
			return renderer.Memory.GetData();
		} else {
			return renderer.Memory.GetBase64Memory();
		}
	}

	this.StopRenderingPage = function (pageIndex)
	{
		if (null != this.m_oDocumentRenderer)
			this.m_oDocumentRenderer.stopRenderingPage(pageIndex);

		this.m_arrPages[pageIndex].drawingPage.UnLock(this.m_oCacheManager);
	}

	this.ClearCachePages = function ()
	{
		for (var i = 0; i < this.m_lPagesCount; i++)
		{
			var page = this.m_arrPages[i];
			if (page)
				page.drawingPage.SetRepaint(this.m_oCacheManager);
		}
	}

	this.CloseFile = function ()
	{
		this.ClearCachePages();
		this.m_arrPages.splice(0, this.m_arrPages.length);
		this.m_lPagesCount = 0;

		this.m_lDrawingFirst = -1;
		this.m_lDrawingEnd = -1;
		this.m_lCurrentPage = -1;
	}

	this.CheckRasterImageOnScreen = function (src)
	{
		if (null == this.m_oWordControl.m_oLogicDocument)
			return;

		if (this.m_lDrawingFirst == -1 || this.m_lDrawingEnd == -1)
			return;

		var bIsRaster = false;
		var _checker = this.m_oWordControl.m_oLogicDocument.DrawingObjects;
		for (var i = this.m_lDrawingFirst; i <= this.m_lDrawingEnd; i++)
		{
			var _imgs = _checker.getAllRasterImagesOnPage(i);

			var _len = _imgs.length;
			for (var j = 0; j < _len; j++)
			{
				if (AscCommon.getFullImageSrc2(_imgs[j]) == src)
				{
					this.StopRenderingPage(i);
					bIsRaster = true;
					break;
				}
			}
		}

		if (bIsRaster)
			this.m_oWordControl.OnScroll();
	}

	this.FirePaint = function ()
	{
		this.m_oWordControl.OnScroll();
	}

	this.ConvertCoordsFromCursor = function (x, y, bIsRul)
	{
		var _x = x;
		var _y = y;

		var dKoef = (100 * g_dKoef_pix_to_mm / this.m_oWordControl.m_nZoomValue);

		if (undefined == bIsRul)
		{
			var _xOffset = this.m_oWordControl.X;
			var _yOffset = this.m_oWordControl.Y;

			/*
			 if (true == this.m_oWordControl.m_bIsRuler)
			 {
			 _xOffset += (5 * g_dKoef_mm_to_pix);
			 _yOffset += (7 * g_dKoef_mm_to_pix);
			 }
			 */

			_x = x - _xOffset;
			_y = y - _yOffset;
		}

		for (var i = this.m_lDrawingFirst; i <= this.m_lDrawingEnd; i++)
		{
			var rect = this.m_arrPages[i].drawingPage;

			if ((rect.left <= _x) && (_x <= rect.right) && (rect.top <= _y) && (_y <= rect.bottom))
			{
				var x_mm = (_x - rect.left) * dKoef;
				var y_mm = (_y - rect.top) * dKoef;

				return {X: x_mm, Y: y_mm, Page: rect.pageIndex, DrawPage: i};
			}
		}

		return {X: 0, Y: 0, Page: -1, DrawPage: -1};
	}

	this.ConvertCoordsFromCursorPage = function (x, y, page, bIsRul)
	{
		var _x = x;
		var _y = y;

		var dKoef = (100 * g_dKoef_pix_to_mm / this.m_oWordControl.m_nZoomValue);

		if (undefined == bIsRul)
		{
			var _xOffset = this.m_oWordControl.X;
			var _yOffset = this.m_oWordControl.Y;

			/*
			 if (true == this.m_oWordControl.m_bIsRuler)
			 {
			 _xOffset += (5 * g_dKoef_mm_to_pix);
			 _yOffset += (7 * g_dKoef_mm_to_pix);
			 }
			 */

			_x = x - _xOffset;
			_y = y - _yOffset;
		}

		if (page < 0 || page >= this.m_lPagesCount)
			return {X: 0, Y: 0, Page: -1, DrawPage: -1};

		var rect = this.m_arrPages[page].drawingPage;
		var x_mm = (_x - rect.left) * dKoef;
		var y_mm = (_y - rect.top) * dKoef;

		return {X: x_mm, Y: y_mm, Page: rect.pageIndex, DrawPage: page};
	}

	this.ConvertCoordsToAnotherPage = function (x, y, pageCoord, pageNeed)
	{
		if (pageCoord < 0 || pageCoord >= this.m_lPagesCount || pageNeed < 0 || pageNeed >= this.m_lPagesCount)
			return {X: 0, Y: 0, Error: true};

		var dKoef1 = this.m_oWordControl.m_nZoomValue * g_dKoef_mm_to_pix / 100;
		var dKoef2 = 100 * g_dKoef_pix_to_mm / this.m_oWordControl.m_nZoomValue;

		var page1 = this.m_arrPages[pageCoord].drawingPage;
		var page2 = this.m_arrPages[pageNeed].drawingPage;

		var xCursor = page1.left + x * dKoef1;
		var yCursor = page1.top + y * dKoef1;

		var _x = (xCursor - page2.left) * dKoef2;
		var _y = (yCursor - page2.top) * dKoef2;

		return {X: _x, Y: _y, Error: false};
	}

	this.ConvertCoordsFromCursor2 = function (x, y, bIsRul, bIsNoNormalize, _zoomVal)
	{
		var _x = x;
		var _y = y;

		var dKoef = (100 * g_dKoef_pix_to_mm / this.m_oWordControl.m_nZoomValue);
		if (undefined !== _zoomVal)
			dKoef = (100 * g_dKoef_pix_to_mm / _zoomVal);

		if (undefined == bIsRul)
		{
			var _xOffset = this.m_oWordControl.X;
			var _yOffset = this.m_oWordControl.Y;

			if (true == this.m_oWordControl.m_bIsRuler)
			{
				_xOffset += (5 * g_dKoef_mm_to_pix);
				_yOffset += (7 * g_dKoef_mm_to_pix);
			}

			_x = x - _xOffset;
			_y = y - _yOffset;
		}

		if (-1 == this.m_lDrawingFirst || -1 == this.m_lDrawingEnd)
			return {X: 0, Y: 0, Page: -1, DrawPage: -1};

		for (var i = this.m_lDrawingFirst; i <= this.m_lDrawingEnd; i++)
		{
			var rect = this.m_arrPages[i].drawingPage;

			if ((rect.left <= _x) && (_x <= rect.right) && (rect.top <= _y) && (_y <= rect.bottom))
			{
				var x_mm = (_x - rect.left) * dKoef;
				var y_mm = (_y - rect.top) * dKoef;

				if (x_mm > (this.m_arrPages[i].width_mm + 10))
					x_mm = this.m_arrPages[i].width_mm + 10;
				if (x_mm < -10)
					x_mm = -10;

				return {X: x_mm, Y: y_mm, Page: rect.pageIndex, DrawPage: i};
			}
		}

		// в страницу не попали. вторая попытка - это попробовать найти страницу по вертикали
		var _start = Math.max(this.m_lDrawingFirst - 1, 0);
		var _end = Math.min(this.m_lDrawingEnd + 1, this.m_lPagesCount - 1);
		for (var i = _start; i <= _end; i++)
		{
			var rect = this.m_arrPages[i].drawingPage;

			var bIsCurrent = false;
			if (i == this.m_lDrawingFirst && rect.top > _y)
			{
				bIsCurrent = true;
			}
			else if ((rect.top <= _y) && (_y <= rect.bottom))
			{
				bIsCurrent = true;
			}
			else if (i != this.m_lPagesCount - 1)
			{
				if (_y > rect.bottom && _y < this.m_arrPages[i + 1].drawingPage.top)
					bIsCurrent = true;
			}
			else if (_y < rect.top)
			{
				// либо вышли раньше, либо это самая первая видимая страница
				bIsCurrent = true;
			}
			else if (i == this.m_lDrawingEnd)
			{
				if (_y > rect.bottom)
					bIsCurrent = true;
			}

			if (bIsCurrent)
			{
				var x_mm = (_x - rect.left) * dKoef;
				var y_mm = (_y - rect.top) * dKoef;

				if (true === bIsNoNormalize)
				{
					if (x_mm > (this.m_arrPages[i].width_mm + 10))
						x_mm = this.m_arrPages[i].width_mm + 10;
					if (x_mm < -10)
						x_mm = -10;
				}

				return {X: x_mm, Y: y_mm, Page: rect.pageIndex, DrawPage: i};
			}
		}

		return {X: 0, Y: 0, Page: -1, DrawPage: -1};
	}

	this.ConvetToPageCoords = function (x, y, pageIndex)
	{
		if (pageIndex < 0 || pageIndex >= this.m_lPagesCount)
		{
			return {X: 0, Y: 0, Page: pageIndex, Error: true};
		}
		var dKoef = (100 * g_dKoef_pix_to_mm / this.m_oWordControl.m_nZoomValue);
		var rect = this.m_arrPages[pageIndex].drawingPage;

		var _x = (x - rect.left) * dKoef;
		var _y = (y - rect.top) * dKoef;

		return {X: _x, Y: _y, Page: pageIndex, Error: false};
	}

	this.IsCursorInTableCur = function (x, y, page)
	{
		var _table = this.TableOutlineDr.TableOutline;
		if (_table == null)
			return false;

		if (page != _table.PageNum)
			return false;

		var _dist = this.TableOutlineDr.image.width * g_dKoef_pix_to_mm;
		_dist *= (100 / this.m_oWordControl.m_nZoomValue);

		var _x = _table.X;
		var _y = _table.Y;
		var _r = _x + _table.W;
		var _b = _y + _table.H;

		if ((x > (_x - _dist)) && (x < _r) && (y > (_y - _dist)) && (y < _b))
		{
			if ((x < _x) || (y < _y))
			{
				this.TableOutlineDr.Counter = 0;
				this.TableOutlineDr.bIsNoTable = false;
				return true;
			}
		}
		return false;
	}

	this.ConvertCoordsToCursorWR = function (x, y, pageIndex, transform, id_ruler_no_use)
	{
		var dKoef = (this.m_oWordControl.m_nZoomValue * g_dKoef_mm_to_pix / 100);

		var _x = 0;
		var _y = 0;
		if (true == this.m_oWordControl.m_bIsRuler && (id_ruler_no_use !== false))
		{
			_x = 5 * g_dKoef_mm_to_pix;
			_y = 7 * g_dKoef_mm_to_pix;
		}

		// теперь крутить всякие циклы нет смысла
		if (pageIndex < 0 || pageIndex >= this.m_lPagesCount)
		{
			return {X: 0, Y: 0, Error: true};
		}

		var __x = x;
		var __y = y;
		if (transform)
		{
			__x = transform.TransformPointX(x, y);
			__y = transform.TransformPointY(x, y);
		}

		var x_pix = (this.m_arrPages[pageIndex].drawingPage.left + __x * dKoef + _x) >> 0;
		var y_pix = (this.m_arrPages[pageIndex].drawingPage.top + __y * dKoef + _y) >> 0;

		return {X: x_pix, Y: y_pix, Error: false};
	}

	this.ConvertCoordsToCursor = function (x, y, pageIndex, bIsRul)
	{
		var dKoef = (this.m_oWordControl.m_nZoomValue * g_dKoef_mm_to_pix / 100);

		var _x = 0;
		var _y = 0;
		if (true == this.m_oWordControl.m_bIsRuler)
		{
			if (undefined == bIsRul)
			{
				//_x = 5 * g_dKoef_mm_to_pix;
				//_y = 7 * g_dKoef_mm_to_pix;
			}
		}

		// теперь крутить всякие циклы нет смысла
		if (pageIndex < 0 || pageIndex >= this.m_lPagesCount)
		{
			return {X: 0, Y: 0, Error: true};
		}

		var x_pix = (this.m_arrPages[pageIndex].drawingPage.left + x * dKoef + _x) >> 0;
		var y_pix = (this.m_arrPages[pageIndex].drawingPage.top + y * dKoef + _y) >> 0;

		return {X: x_pix, Y: y_pix, Error: false};

		// old version
		for (var i = this.m_lDrawingFirst; i <= this.m_lDrawingEnd; i++)
		{
			var rect = this.m_arrPages[i].drawingPage;

			if (this.m_arrPages[i].pageIndex == pageIndex)
			{
				var x_pix = (rect.left + x * dKoef + _x) >> 0;
				var y_pix = (rect.top + y * dKoef + _y) >> 0;

				return {X: x_pix, Y: y_pix, Error: false};
			}
		}

		return {X: 0, Y: 0, Error: true};
	}
	this.ConvertCoordsToCursor2 = function (x, y, pageIndex, bIsRul)
	{
		var dKoef = (this.m_oWordControl.m_nZoomValue * g_dKoef_mm_to_pix / 100);

		var _x = 0;
		var _y = 0;
		if (true == this.m_oWordControl.m_bIsRuler)
		{
			if (undefined == bIsRul)
			{
				//_x = 5 * g_dKoef_mm_to_pix;
				//_y = 7 * g_dKoef_mm_to_pix;
			}
		}

		// теперь крутить всякие циклы нет смысла
		if (pageIndex < 0 || pageIndex >= this.m_lPagesCount)
		{
			return {X: 0, Y: 0, Error: true};
		}

		var x_pix = (this.m_arrPages[pageIndex].drawingPage.left + x * dKoef + _x - 0.5) >> 0;
		var y_pix = (this.m_arrPages[pageIndex].drawingPage.top + y * dKoef + _y - 0.5) >> 0;

		return {X: x_pix, Y: y_pix, Error: false};
	}
	this.ConvertCoordsToCursor3 = function (x, y, pageIndex, isGlobal)
	{
		// теперь крутить всякие циклы нет смысла
		if (pageIndex < 0 || pageIndex >= this.m_lPagesCount)
		{
			return {X: 0, Y: 0, Error: true};
		}

		var dKoef = (this.m_oWordControl.m_nZoomValue * g_dKoef_mm_to_pix / 100);

		var _x = 0;
		var _y = 0;
		if (isGlobal)
		{
			_x = this.m_oWordControl.X;
			_y = this.m_oWordControl.Y;

			if (true == this.m_oWordControl.m_bIsRuler)
			{
				_x += 5 * g_dKoef_mm_to_pix;
				_y += 7 * g_dKoef_mm_to_pix;
			}
		}

		var x_pix = (this.m_arrPages[pageIndex].drawingPage.left + x * dKoef + _x + 0.5) >> 0;
		var y_pix = (this.m_arrPages[pageIndex].drawingPage.top + y * dKoef + _y + 0.5) >> 0;

		return {X: x_pix, Y: y_pix, Error: false};
	}

	this.ConvertCoordsToCursor4 = function (x, y, pageIndex)
	{
		// теперь крутить всякие циклы нет смысла
		if (pageIndex < 0 || pageIndex >= this.m_lPagesCount)
		{
			return {X: 0, Y: 0, Error: true};
		}

		var dKoef = (this.m_oWordControl.m_nZoomValue * g_dKoef_mm_to_pix / 100);

		var x_pix = (this.m_arrPages[pageIndex].drawingPage.left + x * dKoef + 0.5) >> 0;
		var y_pix = (this.m_arrPages[pageIndex].drawingPage.top + y * dKoef + 0.5) >> 0;

		return {X: x_pix, Y: y_pix, Error: false};
	}

	this.InitViewer = function ()
	{
	}

	this.TargetStart = function ()
	{
		if (this.m_lTimerTargetId != -1)
			clearInterval(this.m_lTimerTargetId);
		this.m_lTimerTargetId = setInterval(oThis.DrawTarget, 500);
	}
	this.TargetEnd = function ()
	{
		//if (!this.TargetShowFlag)
		//    return;

		this.TargetShowFlag = false;
		this.TargetShowNeedFlag = false;

		if (this.m_lTimerTargetId != -1)
		{
			clearInterval(this.m_lTimerTargetId);
			this.m_lTimerTargetId = -1;
		}

		this.showTarget(false);
	}
	this.UpdateTargetNoAttack = function ()
	{
		if (null == this.m_oWordControl)
			return;

		this.CheckTargetDraw(this.m_dTargetX, this.m_dTargetY);
	}

	this.GetTargetStyle = function ()
	{
		return "rgb(" + this.TargetCursorColor.R + "," + this.TargetCursorColor.G + "," + this.TargetCursorColor.B + ")";
	}

	this.SetTargetColor = function (r, g, b)
	{
		this.TargetCursorColor.R = r;
		this.TargetCursorColor.G = g;
		this.TargetCursorColor.B = b;
	}

	this.CheckTargetDraw = function (x, y)
	{
		var _oldW = this.TargetHtmlElement.width;
		var _oldH = this.TargetHtmlElement.height;

		var _newW = 2;
		var _newH = (this.m_dTargetSize * this.m_oWordControl.m_nZoomValue * g_dKoef_mm_to_pix / 100) >> 0;

		if (null != this.TextMatrix && !global_MatrixTransformer.IsIdentity2(this.TextMatrix))
		{
			var _x1 = this.TextMatrix.TransformPointX(x, y);
			var _y1 = this.TextMatrix.TransformPointY(x, y);

			var _x2 = this.TextMatrix.TransformPointX(x, y + this.m_dTargetSize);
			var _y2 = this.TextMatrix.TransformPointY(x, y + this.m_dTargetSize);

			var pos1 = this.ConvertCoordsToCursor2(_x1, _y1, this.m_lCurrentPage);
			var pos2 = this.ConvertCoordsToCursor2(_x2, _y2, this.m_lCurrentPage);

			_newW = (Math.abs(pos1.X - pos2.X) >> 0) + 1;
			_newH = (Math.abs(pos1.Y - pos2.Y) >> 0) + 1;

			if (2 > _newW)
				_newW = 2;
			if (2 > _newH)
				_newH = 2;

			if (_oldW == _newW && _oldH == _newH)
			{
				if (_newW != 2 && _newH != 2)
				{
					// просто очищаем
					this.TargetHtmlElement.width = _newW;
				}
			}
			else
			{
				this.TargetHtmlElement.style.width = _newW + "px";
				this.TargetHtmlElement.style.height = _newH + "px";

				this.TargetHtmlElement.width = _newW;
				this.TargetHtmlElement.height = _newH;
			}
			var ctx = this.TargetHtmlElement.getContext('2d');

			if (_newW == 2 || _newH == 2)
			{
				ctx.fillStyle = this.GetTargetStyle();
				ctx.fillRect(0, 0, _newW, _newH);
			}
			else
			{
				ctx.beginPath();
				ctx.strokeStyle = this.GetTargetStyle();
				ctx.lineWidth = 2;

				if (((pos1.X - pos2.X) * (pos1.Y - pos2.Y)) >= 0)
				{
					ctx.moveTo(0, 0);
					ctx.lineTo(_newW, _newH);
				}
				else
				{
					ctx.moveTo(0, _newH);
					ctx.lineTo(_newW, 0);
				}

				ctx.stroke();
			}

			oThis.TargetHtmlElementLeft = Math.min(pos1.X, pos2.X) >> 0;
			oThis.TargetHtmlElementTop = Math.min(pos1.Y, pos2.Y) >> 0;
			if ((!oThis.m_oWordControl.MobileTouchManager && !AscCommon.AscBrowser.isSafariMacOs) || !AscCommon.AscBrowser.isWebkit)
			{
				oThis.TargetHtmlElement.style.left = oThis.TargetHtmlElementLeft + "px";
				oThis.TargetHtmlElement.style.top = oThis.TargetHtmlElementTop + "px";
			}
			else
			{
				oThis.TargetHtmlElement.style.left = "0px";
				oThis.TargetHtmlElement.style.top = "0px";
				oThis.TargetHtmlElement.style["webkitTransform"] = "matrix(1, 0, 0, 1, " + oThis.TargetHtmlElementLeft + "," + oThis.TargetHtmlElementTop + ")";
			}
		}
		else
		{
			if (_oldW == _newW && _oldH == _newH)
			{
				// просто очищаем
				this.TargetHtmlElement.width = _newW;
			}
			else
			{
				this.TargetHtmlElement.style.width = _newW + "px";
				this.TargetHtmlElement.style.height = _newH + "px";

				this.TargetHtmlElement.width = _newW;
				this.TargetHtmlElement.height = _newH;
			}

			var ctx = this.TargetHtmlElement.getContext('2d');

			ctx.fillStyle = this.GetTargetStyle();
			ctx.fillRect(0, 0, _newW, _newH);

			if (null != this.TextMatrix)
			{
				x += this.TextMatrix.tx;
				y += this.TextMatrix.ty;
			}

			var pos = this.ConvertCoordsToCursor2(x, y, this.m_lCurrentPage);

			this.TargetHtmlElementLeft = pos.X >> 0;
			this.TargetHtmlElementTop = pos.Y >> 0;

			if ((!oThis.m_oWordControl.MobileTouchManager && !AscCommon.AscBrowser.isSafariMacOs) || !AscCommon.AscBrowser.isWebkit)
			{
				this.TargetHtmlElement.style.left = this.TargetHtmlElementLeft + "px";
				this.TargetHtmlElement.style.top = this.TargetHtmlElementTop + "px";
			}
			else
			{
				oThis.TargetHtmlElement.style.left = "0px";
				oThis.TargetHtmlElement.style.top = "0px";
				oThis.TargetHtmlElement.style["webkitTransform"] = "matrix(1, 0, 0, 1, " + oThis.TargetHtmlElementLeft + "," + oThis.TargetHtmlElementTop + ")";
			}
		}

		this.MoveTargetInInputContext();
	};

	this.MoveTargetInInputContext = function ()
	{
		if (AscCommon.g_inputContext)
			AscCommon.g_inputContext.move(this.TargetHtmlElementLeft, this.TargetHtmlElementTop);
	}

	this.UpdateTargetTransform = function (matrix)
	{
		this.TextMatrix = matrix;
	}

	this.MultiplyTargetTransform = function (matrix)
	{
		if (!this.TextMatrix)
			this.TextMatrix = matrix;
		else if (matrix)
		{
			this.TextMatrix.Multiply(matrix, AscCommon.MATRIX_ORDER_PREPEND);
		}
	}

	this.UpdateTarget = function (x, y, pageIndex)
	{
		if (this.m_oWordControl)
			this.m_oWordControl.m_oApi.checkLastWork();

		this.m_oWordControl.m_oLogicDocument.Set_TargetPos(x, y, pageIndex);

        if(window["NATIVE_EDITOR_ENJINE"])
        	return;

		if (this.UpdateTargetFromPaint === false && this.m_lCurrentPage != -1)
		{
			this.UpdateTargetCheck = true;
			return;
		}

		var bNeedScrollToTarget = true;
		if (this.m_dTargetX == x && this.m_dTargetY == y && this.m_lTargetPage == pageIndex)
			bNeedScrollToTarget = false;

		if (-1 != this.m_lTimerUpdateTargetID)
		{
			clearTimeout(this.m_lTimerUpdateTargetID);
			this.m_lTimerUpdateTargetID = -1;
		}

		if (pageIndex >= this.m_arrPages.length)
			return;

		var bIsPageChanged = false;
		if (this.m_lCurrentPage != pageIndex)
		{
			this.m_lCurrentPage = pageIndex;
			this.m_oWordControl.SetCurrentPage2();
			this.m_oWordControl.OnScroll();
			bIsPageChanged = true;
		}

		var targetSize = Number(this.m_dTargetSize * this.m_oWordControl.m_nZoomValue * g_dKoef_mm_to_pix / 100);

		var pos = null;
		var __x = x;
		var __y = y;
		if (!this.TextMatrix)
		{
			pos = this.ConvertCoordsToCursor2(x, y, this.m_lCurrentPage);
		}
		else
		{
			__x = this.TextMatrix.TransformPointX(x, y);
			__y = this.TextMatrix.TransformPointY(x, y);

			pos = this.ConvertCoordsToCursor2(__x, __y, this.m_lCurrentPage);
		}

		//pos.Y -= targetSize;

		if (true == pos.Error && (false == bIsPageChanged))
			return;

		// смотрим, виден ли курсор на экране

		var _ww = this.m_oWordControl.m_oEditor.HtmlElement.width;
		var _hh = this.m_oWordControl.m_oEditor.HtmlElement.height;
		if (this.m_oWordControl.bIsRetinaSupport)
		{
			_ww /= AscCommon.AscBrowser.retinaPixelRatio;
			_hh /= AscCommon.AscBrowser.retinaPixelRatio;
		}

		var boxX = 0;
		var boxY = 0;
		var boxR = _ww - 2;
		var boxB = _hh - targetSize;

		/*
		 if (true == this.m_oWordControl.m_bIsRuler)
		 {
		 boxX += Number(5 * g_dKoef_mm_to_pix);
		 boxY += Number(7 * g_dKoef_mm_to_pix);
		 boxR += Number(5 * g_dKoef_mm_to_pix);
		 boxB += Number(7 * g_dKoef_mm_to_pix);
		 }
		 */

		var nValueScrollHor = 0;
		if (pos.X < boxX)
		{
			nValueScrollHor = this.m_oWordControl.GetHorizontalScrollTo(__x - 5, pageIndex);
		}
		if (pos.X > boxR)
		{
			var _mem = __x + 5 - g_dKoef_pix_to_mm * _ww * 100 / this.m_oWordControl.m_nZoomValue;
			nValueScrollHor = this.m_oWordControl.GetHorizontalScrollTo(_mem, pageIndex);
		}

		var nValueScrollVer = 0;
		if (pos.Y < boxY)
		{
			nValueScrollVer = this.m_oWordControl.GetVerticalScrollTo(__y - 5, pageIndex);
		}
		if (pos.Y > boxB)
		{
			var _mem = __y + targetSize + 5 - g_dKoef_pix_to_mm * _hh * 100 / this.m_oWordControl.m_nZoomValue;
			nValueScrollVer = this.m_oWordControl.GetVerticalScrollTo(_mem, pageIndex);
		}

		if (!bNeedScrollToTarget)
		{
			nValueScrollHor = 0;
			nValueScrollVer = 0;
		}

		if (0 != nValueScrollHor || 0 != nValueScrollVer)
		{
			if (this.m_oWordControl.m_bIsMouseUpSend === true && AscCommon.global_keyboardEvent.ClickCount != 1)
			{
				this.m_tempX = x;
				this.m_tempY = y;
				this.m_tempPageIndex = pageIndex;
				var oThis = this;
				this.m_lTimerUpdateTargetID = setTimeout(this.UpdateTargetTimer, 100);
				return;
			}
		}

		this.m_dTargetX = x;
		this.m_dTargetY = y;
		this.m_lTargetPage = pageIndex;
		var isNeedScroll = false;
		if (0 != nValueScrollHor)
		{
			isNeedScroll = true;
			this.m_oWordControl.m_bIsUpdateTargetNoAttack = true;
			var temp = nValueScrollHor * this.m_oWordControl.m_dScrollX_max / (this.m_oWordControl.m_dDocumentWidth - _ww);
			this.m_oWordControl.m_oScrollHorApi.scrollToX(parseInt(temp), false);
		}
		if (0 != nValueScrollVer)
		{
			isNeedScroll = true;
			this.m_oWordControl.m_bIsUpdateTargetNoAttack = true;
			var temp = nValueScrollVer * this.m_oWordControl.m_dScrollY_max / (this.m_oWordControl.m_dDocumentHeight - _hh);
			this.m_oWordControl.m_oScrollVerApi.scrollToY(parseInt(temp), false);
		}

		if (true == isNeedScroll)
		{
			this.m_oWordControl.m_bIsUpdateTargetNoAttack = true;
			this.m_oWordControl.OnScroll();
			return;
		}

		this.CheckTargetDraw(x, y);
	}
	this.UpdateTarget2 = function (x, y, pageIndex)
	{
		if (pageIndex >= this.m_arrPages.length)
			return;

		this.m_oWordControl.m_oLogicDocument.Set_TargetPos(x, y, pageIndex);

		var bIsPageChanged = false;
		if (this.m_lCurrentPage != pageIndex)
		{
			this.m_lCurrentPage = pageIndex;
			this.m_oWordControl.SetCurrentPage2();
			this.m_oWordControl.OnScroll();
			bIsPageChanged = true;
		}

		this.m_dTargetX = x;
		this.m_dTargetY = y;
		this.m_lTargetPage = pageIndex;

		var pos = this.ConvertCoordsToCursor(x, y, this.m_lCurrentPage);

		if (true == pos.Error && (false == bIsPageChanged))
			return;

		var _ww = this.m_oWordControl.m_oEditor.HtmlElement.width;
		var _hh = this.m_oWordControl.m_oEditor.HtmlElement.height;
		if (this.m_oWordControl.bIsRetinaSupport)
		{
			_ww /= AscCommon.AscBrowser.retinaPixelRatio;
			_hh /= AscCommon.AscBrowser.retinaPixelRatio;
		}

		// смотрим, виден ли курсор на экране
		var boxX = 0;
		var boxY = 0;
		var boxR = _ww;
		var boxB = _hh;

		/*
		 if (true == this.m_oWordControl.m_bIsRuler)
		 {
		 boxX += Number(5 * g_dKoef_mm_to_pix);
		 boxY += Number(7 * g_dKoef_mm_to_pix);
		 boxR += Number(5 * g_dKoef_mm_to_pix);
		 boxB += Number(7 * g_dKoef_mm_to_pix);
		 }
		 */

		var nValueScrollHor = 0;
		if (pos.X < boxX)
		{
			nValueScrollHor = this.m_oWordControl.GetHorizontalScrollTo(x - 5, pageIndex);
		}
		if (pos.X > boxR)
		{
			var _mem = x + 5 - g_dKoef_pix_to_mm * _ww * 100 / this.m_oWordControl.m_nZoomValue;
			nValueScrollHor = this.m_oWordControl.GetHorizontalScrollTo(_mem, pageIndex);
		}

		var nValueScrollVer = 0;
		if (pos.Y < boxY)
		{
			nValueScrollVer = this.m_oWordControl.GetVerticalScrollTo(y - 5, pageIndex);
		}
		if (pos.Y > boxB)
		{
			var _mem = y + this.m_dTargetSize + 5 - g_dKoef_pix_to_mm * _hh * 100 / this.m_oWordControl.m_nZoomValue;
			nValueScrollVer = this.m_oWordControl.GetVerticalScrollTo(_mem, pageIndex);
		}

		var isNeedScroll = false;
		if (0 != nValueScrollHor)
		{
			isNeedScroll = true;
			var temp = nValueScrollHor * this.m_oWordControl.m_dScrollX_max / (this.m_oWordControl.m_dDocumentWidth - _ww);
			this.m_oWordControl.m_oScrollHorApi.scrollToX(parseInt(temp), false);
		}
		if (0 != nValueScrollVer)
		{
			isNeedScroll = true;
			var temp = nValueScrollVer * this.m_oWordControl.m_dScrollY_max / (this.m_oWordControl.m_dDocumentHeight - _hh);
			this.m_oWordControl.m_oScrollVerApi.scrollToY(parseInt(temp), false);
		}

		if (true == isNeedScroll)
		{
			this.m_oWordControl.OnScroll();
			return;
		}
	}

	this.UpdateTargetTimer = function ()
	{
		var x = oThis.m_tempX;
		var y = oThis.m_tempY;
		var pageIndex = oThis.m_tempPageIndex;

		oThis.m_lTimerUpdateTargetID = -1;
		if (pageIndex >= oThis.m_arrPages.length)
			return;

		var oWordControl = oThis.m_oWordControl;

		var bIsPageChanged = false;
		if (oThis.m_lCurrentPage != pageIndex)
		{
			oThis.m_lCurrentPage = pageIndex;
			oWordControl.SetCurrentPage2();
			oWordControl.OnScroll();
			bIsPageChanged = true;
		}

		oThis.m_dTargetX = x;
		oThis.m_dTargetY = y;
		oThis.m_lTargetPage = pageIndex;

		var targetSize = Number(oThis.m_dTargetSize * oWordControl.m_nZoomValue * g_dKoef_mm_to_pix / 100);
		var pos = oThis.ConvertCoordsToCursor2(x, y, oThis.m_lCurrentPage);
		//pos.Y -= targetSize;

		if (true === pos.Error && (false === bIsPageChanged))
			return;

		// смотрим, виден ли курсор на экране
		var boxX = 0;
		var boxY = 0;
		var boxR = oWordControl.m_oEditor.HtmlElement.width - 2;
		var boxB = oWordControl.m_oEditor.HtmlElement.height - targetSize;

		/*
		 if (true === oWordControl.m_bIsRuler)
		 {
		 boxX += Number(5 * g_dKoef_mm_to_pix);
		 boxY += Number(7 * g_dKoef_mm_to_pix);
		 boxR += Number(5 * g_dKoef_mm_to_pix);
		 boxB += Number(7 * g_dKoef_mm_to_pix);
		 }
		 */

		var nValueScrollHor = 0;
		if (pos.X < boxX)
		{
			nValueScrollHor = boxX - pos.X;
		}
		if (pos.X > boxR)
		{
			nValueScrollHor = boxR - pos.X;
		}

		var nValueScrollVer = 0;
		if (pos.Y < boxY)
		{
			nValueScrollVer = boxY - pos.Y;
		}
		if (pos.Y > boxB)
		{
			nValueScrollVer = boxB - pos.Y;
		}

		var isNeedScroll = false;
		if (0 != nValueScrollHor)
		{
			isNeedScroll = true;
			oWordControl.m_bIsUpdateTargetNoAttack = true;
			oWordControl.m_oScrollHorApi.scrollByX(-nValueScrollHor, false);
		}
		if (0 != nValueScrollVer)
		{
			isNeedScroll = true;
			oWordControl.m_bIsUpdateTargetNoAttack = true;
			oWordControl.m_oScrollVerApi.scrollByY(-nValueScrollVer, false);
		}

		if (true === isNeedScroll)
		{
			oWordControl.m_bIsUpdateTargetNoAttack = true;
			oWordControl.OnScroll();
			return;
		}

		oThis.TargetHtmlElementLeft = pos.X >> 0;
		oThis.TargetHtmlElementTop = pos.Y >> 0;
		oThis.TargetHtmlElement.style.left = oThis.TargetHtmlElementLeft + "px";
		oThis.TargetHtmlElement.style.top = oThis.TargetHtmlElementTop + "px";
	}

	this.SetTargetSize = function (size)
	{
		this.m_dTargetSize = size;
		//this.TargetHtmlElement.style.height = Number(this.m_dTargetSize * this.m_oWordControl.m_nZoomValue * g_dKoef_mm_to_pix / 100) + "px";
		//this.TargetHtmlElement.style.width = "2px";
	}
	this.DrawTarget = function ()
	{
		if (oThis.NeedTarget && oThis.m_oWordControl.IsFocus)
		{
			oThis.showTarget(!oThis.isShowTarget());
		}
	};

	this.TargetShow = function ()
	{
		this.TargetShowNeedFlag = true;
	}
	this.CheckTargetShow = function ()
	{
		if (this.TargetShowFlag && this.TargetShowNeedFlag)
		{
			this.showTarget(true);
			this.TargetShowNeedFlag = false;
			return;
		}

		if (!this.TargetShowNeedFlag)
			return;

		this.TargetShowNeedFlag = false;

		if (-1 == this.m_lTimerTargetId)
			this.TargetStart();

		if (oThis.NeedTarget)
			this.showTarget(true);

		this.TargetShowFlag = true;
	}
	this.StartTrackImage = function (obj, x, y, w, h, type, pagenum)
	{
	}
	this.StartTrackTable = function (obj, transform)
	{
		if (this.m_oWordControl.MobileTouchManager)
		{
			if (!this.m_oWordControl.MobileTouchManager.TableStartTrack_Check)
				return;
		}

		this.TableOutlineDr.TableOutline = obj;
		this.TableOutlineDr.Counter = 0;
		this.TableOutlineDr.bIsNoTable = false;
		this.TableOutlineDr.CheckStartTrack(this.m_oWordControl, transform);

		if (this.m_oWordControl.MobileTouchManager)
			this.m_oWordControl.OnUpdateOverlay();
	}
	this.EndTrackTable = function (pointer, bIsAttack)
	{
		if (this.TableOutlineDr.TableOutline != null)
		{
			if (pointer == this.TableOutlineDr.TableOutline.Table || bIsAttack)
			{
				this.TableOutlineDr.TableOutline = null;
				this.TableOutlineDr.Counter = 0;
			}
		}
	}
	this.CheckTrackTable = function ()
	{
		if (null == this.TableOutlineDr.TableOutline)
			return;

		if (this.TableOutlineDr.bIsNoTable && this.TableOutlineDr.bIsTracked === false)
		{
			this.TableOutlineDr.Counter++;
			if (this.TableOutlineDr.Counter > 100)
			{
				this.TableOutlineDr.TableOutline = null;
				this.m_oWordControl.OnUpdateOverlay();
			}
		}
	}

	this.DrawFrameTrack = function (overlay)
	{
		if (!this.FrameRect.IsActive)
			return;

		var _page = this.m_arrPages[this.FrameRect.PageIndex];
		var drPage = _page.drawingPage;

		var dKoefX = (drPage.right - drPage.left) / _page.width_mm;
		var dKoefY = (drPage.bottom - drPage.top) / _page.height_mm;

		var _x = (drPage.left + dKoefX * this.FrameRect.Rect.X);
		var _y = (drPage.top + dKoefY * this.FrameRect.Rect.Y);
		var _r = (drPage.left + dKoefX * this.FrameRect.Rect.R);
		var _b = (drPage.top + dKoefY * this.FrameRect.Rect.B);

		if (_x < overlay.min_x)
			overlay.min_x = _x;
		if (_r > overlay.max_x)
			overlay.max_x = _r;

		if (_y < overlay.min_y)
			overlay.min_y = _y;
		if (_b > overlay.max_y)
			overlay.max_y = _b;

		var ctx = overlay.m_oContext;
		ctx.strokeStyle = "#939393";
		ctx.lineWidth = 1;

		ctx.beginPath();
		this.AutoShapesTrack.AddRectDashClever(ctx, _x >> 0, _y >> 0, _r >> 0, _b >> 0, 2, 2, true);
		ctx.beginPath();

		var _w = 4;
		var _wc = 5;

		var _x1 = (_x >> 0) + 1;
		var _y1 = (_y >> 0) + 1;

		var _x2 = (_r >> 0) - _w;
		var _y2 = (_b >> 0) - _w;

		var _xc = ((_x + _r - _wc) / 2) >> 0;
		var _yc = ((_y + _b - _wc) / 2) >> 0;

		ctx.rect(_x1, _y1, _w, _w);
		ctx.rect(_xc, _y1, _wc, _w);
		ctx.rect(_x2, _y1, _w, _w);
		ctx.rect(_x1, _yc, _w, _wc);
		ctx.rect(_x2, _yc, _w, _wc);
		ctx.rect(_x1, _y2, _w, _w);
		ctx.rect(_xc, _y2, _wc, _w);
		ctx.rect(_x2, _y2, _w, _w);

		ctx.fillStyle = "#777777";
		ctx.fill();
		ctx.beginPath();

		// move
		if (this.FrameRect.IsTracked)
		{
			_page = this.m_arrPages[this.FrameRect.Track.PageIndex];
			drPage = _page.drawingPage;

			dKoefX = (drPage.right - drPage.left) / _page.width_mm;
			dKoefY = (drPage.bottom - drPage.top) / _page.height_mm;

			var __x = (drPage.left + dKoefX * this.FrameRect.Track.L) >> 0;
			var __y = (drPage.top + dKoefY * this.FrameRect.Track.T) >> 0;
			var __r = (drPage.left + dKoefX * this.FrameRect.Track.R) >> 0;
			var __b = (drPage.top + dKoefY * this.FrameRect.Track.B) >> 0;

			if (__x < overlay.min_x)
				overlay.min_x = __x;
			if (__r > overlay.max_x)
				overlay.max_x = __r;

			if (__y < overlay.min_y)
				overlay.min_y = __y;
			if (__b > overlay.max_y)
				overlay.max_y = __b;

			ctx.strokeStyle = "#FFFFFF";

			ctx.beginPath();
			ctx.rect(__x + 0.5, __y + 0.5, __r - __x, __b - __y);
			ctx.stroke();

			ctx.strokeStyle = "#000000";
			ctx.beginPath();
			this.AutoShapesTrack.AddRectDashClever(ctx, __x, __y, __r, __b, 3, 3, true);
			ctx.beginPath();
		}
	};

	this.ContentControlsSaveLast = function()
	{
		this.ContentControlObjectsLast = [];
		for (var i = 0; i < this.ContentControlObjects.length; i++)
		{
			this.ContentControlObjectsLast.push(this.ContentControlObjects[i].Copy());
		}
	};

	this.ContentControlsCheckLast = function()
	{
		var _len1 = this.ContentControlObjects.length;
		var _len2 = this.ContentControlObjectsLast.length;

		if (_len1 != _len2)
			return true;

		var count1, count2;
		for (var i = 0; i < _len1; i++)
		{
			var _obj1 = this.ContentControlObjects[i];
			var _obj2 = this.ContentControlObjectsLast[i];

			if (_obj1.id != _obj2.id)
				return true;
			if (_obj1.type != _obj2.type)
				return true;

			if (_obj1.rects && _obj2.rects)
			{
				count1 = _obj1.rects.length;
				count2 = _obj2.rects.length;

				if (count1 != count2)
					return true;

				for (var j = 0; j < count1; j++)
				{
					if (Math.abs(_obj1.rects[j].X - _obj2.rects[j].X) > 0.00001 ||
						Math.abs(_obj1.rects[j].Y - _obj2.rects[j].Y) > 0.00001 ||
						Math.abs(_obj1.rects[j].R - _obj2.rects[j].R) > 0.00001 ||
						Math.abs(_obj1.rects[j].B - _obj2.rects[j].B) > 0.00001 ||
						_obj1.rects[j].Page != _obj2.rects[j].Page)
					{
						return true;
					}
				}
			}
			else if (_obj1.path && _obj2.path)
			{
				count1 = _obj1.paths.length;
				count2 = _obj2.paths.length;

				if (count1 != count2)
					return true;

				var _points1, _points2;
				for (var j = 0; j < count1; j++)
				{
					if (_obj1.paths[j].Page != _obj2.paths[j].Page)
						return true;

					_points1 = _obj1.paths[j].Points;
					_points2 = _obj2.paths[j].Points;

					if (_points1.length != _points2.length)
						return true;

					for (var k = 0; k < _points1.length; k++)
					{
						if (Math.abs(_points1[k].X - _points[k].X) > 0.00001 || Math.abs(_points1[k].Y - _points[k].Y) > 0.00001)
							return true;
					}
				}
			}
			else
			{
				return true;
			}
		}

		return false;
	};

	this.DrawContentControlsTrack = function(overlay)
	{
		var ctx = overlay.m_oContext;
		ctx.strokeStyle = "#ADADAD";
		ctx.lineWidth = 1;

		var _object, _rect, _path;
		var _x, _y, _r, _b;
		var _transform, offset_x, offset_y;
		var _curPage;
		var _color;

		for (var nIndexContentControl = 0; nIndexContentControl < this.ContentControlObjects.length; nIndexContentControl++)
		{
			_object = this.ContentControlObjects[nIndexContentControl];
			_transform = _object.transform;
			_curPage = _object.getPage();
			_color = _object.getColor();

			if (_color)
			{
				ctx.strokeStyle = "rgba(" + _color.r + ", " + _color.g + ", " + _color.b + ", 1)";
				ctx.fillStyle = "rgba(" + _color.r + ", " + _color.g + ", " + _color.b + ", 0.25)";
			}
			else
			{
				ctx.strokeStyle = "#ADADAD";
				ctx.fillStyle = "rgba(205, 205, 205, 0.5)";
			}


			offset_x = 0;
			offset_y = 0;
			if (_transform && global_MatrixTransformer.IsIdentity2(_transform))
			{
				offset_x = _transform.tx;
				offset_y = _transform.ty;
				_transform = null;
			}

			if (!_transform)
			{
				if (_object.rects)
				{
					for (var j = 0; j < _object.rects.length; j++)
					{
						_rect = _object.rects[j];

						if (_rect.Page < this.m_lDrawingFirst || _rect.Page > this.m_lDrawingEnd)
							continue;

						var _page = this.m_arrPages[_rect.Page];
						var drPage = _page.drawingPage;

						var dKoefX = (drPage.right - drPage.left) / _page.width_mm;
						var dKoefY = (drPage.bottom - drPage.top) / _page.height_mm;

						ctx.beginPath();

						_x = (drPage.left + dKoefX * (_rect.X + offset_x));
						_y = (drPage.top + dKoefY * (_rect.Y + offset_y));
						_r = (drPage.left + dKoefX * (_rect.R + offset_x));
						_b = (drPage.top + dKoefY * (_rect.B + offset_y));

						overlay.CheckRect(_x, _y, _r - _x, _b - _y);
						ctx.rect((_x >> 0) + 0.5, (_y >> 0) + 0.5, (_r - _x) >> 0, (_b - _y) >> 0);

						if (_object.type == c_oContentControlTrack.Hover)
						{
							//ctx.fillStyle = "rgba(205, 205, 205, 0.5)";
							ctx.fill();
						}
						ctx.stroke();

						ctx.beginPath();
					}
				}
				else if (_object.paths)
				{
					for (var j = 0; j < _object.paths.length; j++)
					{
						_path = _object.paths[j];
						if (_path.Page < this.m_lDrawingFirst || _path.Page > this.m_lDrawingEnd)
							continue;

						var _page = this.m_arrPages[_path.Page];
						var drPage = _page.drawingPage;

						var dKoefX = (drPage.right - drPage.left) / _page.width_mm;
						var dKoefY = (drPage.bottom - drPage.top) / _page.height_mm;

						ctx.beginPath();

						var Points = _path.Points;

						var nCount = Points.length;
						for (var nIndex = 0; nIndex < nCount; nIndex++)
						{
							_x = (drPage.left + dKoefX * (Points[nIndex].X + offset_x));
							_y = (drPage.top + dKoefY * (Points[nIndex].Y + offset_y));

							overlay.CheckPoint(_x, _y);

							_x = (_x >> 0) + 0.5;
							_y = (_y >> 0) + 0.5;

							if (0 == nIndex)
								ctx.moveTo(_x, _y);
							else
								ctx.lineTo(_x, _y);
						}

						ctx.closePath();

						if (_object.type == c_oContentControlTrack.Hover)
						{
							//ctx.fillStyle = "rgba(205, 205, 205, 0.5)";
							ctx.fill();
						}

						ctx.stroke();
						ctx.beginPath();
					}
				}
			}
			else
			{
				if (_object.rects)
				{
					for (var j = 0; j < _object.rects.length; j++)
					{
						_rect = _object.rects[j];

						if (_rect.Page < this.m_lDrawingFirst || _rect.Page > this.m_lDrawingEnd)
							continue;

						var x1 = _transform.TransformPointX(_rect.X, _rect.Y);
						var y1 = _transform.TransformPointY(_rect.X, _rect.Y);

						var x2 = _transform.TransformPointX(_rect.R, _rect.Y);
						var y2 = _transform.TransformPointY(_rect.R, _rect.Y);

						var x3 = _transform.TransformPointX(_rect.R, _rect.B);
						var y3 = _transform.TransformPointY(_rect.R, _rect.B);

						var x4 = _transform.TransformPointX(_rect.X, _rect.B);
						var y4 = _transform.TransformPointY(_rect.X, _rect.B);

						var _page = this.m_arrPages[_rect.Page];
						var drPage = _page.drawingPage;

						var dKoefX = (drPage.right - drPage.left) / _page.width_mm;
						var dKoefY = (drPage.bottom - drPage.top) / _page.height_mm;

						x1 = drPage.left + dKoefX * x1;
						x2 = drPage.left + dKoefX * x2;
						x3 = drPage.left + dKoefX * x3;
						x4 = drPage.left + dKoefX * x4;

						y1 = drPage.top + dKoefY * y1;
						y2 = drPage.top + dKoefY * y2;
						y3 = drPage.top + dKoefY * y3;
						y4 = drPage.top + dKoefY * y4;

						ctx.beginPath();

						overlay.CheckPoint(x1, y1);
						overlay.CheckPoint(x2, y2);
						overlay.CheckPoint(x3, y3);
						overlay.CheckPoint(x4, y4);

						ctx.moveTo(x1, y1);
						ctx.lineTo(x2, y2);
						ctx.lineTo(x3, y3);
						ctx.lineTo(x4, y4);
						ctx.closePath();

						if (_object.type == c_oContentControlTrack.Hover)
						{
							//ctx.fillStyle = "rgba(205, 205, 205, 0.5)";
							ctx.fill();
						}
						ctx.stroke();

						ctx.beginPath();
					}
				}
				else if (_object.paths)
				{
					for (var j = 0; j < _object.paths.length; j++)
					{
						_path = _object.paths[j];
						if (_path.Page < this.m_lDrawingFirst || _path.Page > this.m_lDrawingEnd)
							continue;

						var _page = this.m_arrPages[_path.Page];
						var drPage = _page.drawingPage;

						var dKoefX = (drPage.right - drPage.left) / _page.width_mm;
						var dKoefY = (drPage.bottom - drPage.top) / _page.height_mm;

						ctx.beginPath();

						var Points = _path.Points;

						var nCount = Points.length;
						for (var nIndex = 0; nIndex < nCount; nIndex++)
						{
							var _x = _transform.TransformPointX(Points[nIndex].X, Points[nIndex].Y);
							var _y = _transform.TransformPointY(Points[nIndex].X, Points[nIndex].Y);

							_x = (drPage.left + dKoefX * _x);
							_y = (drPage.top + dKoefY * _y);

							overlay.CheckPoint(_x, _y);

							if (0 == nIndex)
								ctx.moveTo(_x, _y);
							else
								ctx.lineTo(_x, _y);
						}

						ctx.closePath();

						if (_object.type == c_oContentControlTrack.Hover)
						{
							//ctx.fillStyle = "rgba(205, 205, 205, 0.5)";
							ctx.fill();
						}

						ctx.stroke();
						ctx.beginPath();
					}
				}
			}

			if (_object.type == c_oContentControlTrack.In)
			{
				if (_curPage < this.m_lDrawingFirst || _curPage > this.m_lDrawingEnd)
					continue;

				_rect = _object.getXY();
				var _page = this.m_arrPages[_curPage];
				var drPage = _page.drawingPage;

				var dKoefX = (drPage.right - drPage.left) / _page.width_mm;
				var dKoefY = (drPage.bottom - drPage.top) / _page.height_mm;

				if (!_transform)
				{
					_x = (drPage.left 	+ dKoefX * (_rect.X + offset_x));
					_y = (drPage.top 	+ dKoefY * (_rect.Y + offset_y));

					_x = ((_x >> 0) + 0.5) - 15;
					_y = ((_y >> 0) + 0.5);

					var nAdvancedL = 0;
					var nAdvancedLB = 0;

					if (_object.Name == "" && 0 == _object.Buttons.length)
					{
						ctx.rect(_x, _y, 15, 20);
						overlay.CheckRect(_x, _y, 15, 20);

						ctx.fillStyle = (1 == this.ContentControlObjectState) ? AscCommonWord.GlobalSkin.ContentControlsAnchorActive : AscCommonWord.GlobalSkin.ContentControlsBack;

						ctx.fill();
						ctx.stroke();
					}
					else
					{
						_x += 15;
						_y -= 20;

						var widthControl = 0;

						if (_object.Name != "")
						{
							ctx.font = g_oContentControlButtonIcons.getFont();
							widthControl += g_oContentControlButtonIcons.measure(_object.Name, ctx);
							widthControl += 6; // 3 + 3
							if (_object.NameButtonAdvanced)
							{
								nAdvancedL = _x + 15 + widthControl;
								widthControl += 5;
								widthControl += 3;
							}
							else
								widthControl += 3;
						}

						_object.NameWidth = widthControl;

						nAdvancedLB = _x + 15 + widthControl;
						widthControl += (20 * _object.Buttons.length);

						overlay.CheckRect(_x, _y, 15 + widthControl, 20);

						ctx.beginPath();

						var _fillStyleSetup = (1 == this.ContentControlObjectState) ? AscCommonWord.GlobalSkin.ContentControlsAnchorActive : AscCommonWord.GlobalSkin.ContentControlsBack;
						var _fillStyle = "";
						var _fillX = _x;
						var _fillW = 15;
						if (_object.NameWidth != 0)
						{
							if (_object.ActiveButtonIndex == -1)
								_fillStyle = AscCommonWord.GlobalSkin.ContentControlsActive;
							else if (_object.HoverButtonIndex == -1)
								_fillStyle = AscCommonWord.GlobalSkin.ContentControlsHover;
							else
								_fillStyle = AscCommonWord.GlobalSkin.ContentControlsBack;

							if (_fillStyle != _fillStyleSetup)
							{
								ctx.rect(_fillX, _y, _fillW, 20);
								_fillX = _fillX + _fillW;
								_fillW = 0;

								ctx.fillStyle = _fillStyleSetup;
								ctx.fill();
								ctx.beginPath();
							}
							_fillW += _object.NameWidth;
							_fillStyleSetup = _fillStyle;
						}

						for (var nIndexB = 0; nIndexB < _object.Buttons.length; nIndexB++)
						{
							if (_object.ActiveButtonIndex == nIndexB)
								_fillStyle = AscCommonWord.GlobalSkin.ContentControlsActive;
							else if (_object.HoverButtonIndex == nIndexB)
								_fillStyle = AscCommonWord.GlobalSkin.ContentControlsHover;
							else
								_fillStyle = AscCommonWord.GlobalSkin.ContentControlsBack;

							if (_fillStyle != _fillStyleSetup)
							{
								ctx.rect(_fillX, _y, _fillW, 20);
								_fillX = _fillX + _fillW;
								_fillW = 0;

								ctx.fillStyle = _fillStyleSetup;
								ctx.fill();
								ctx.beginPath();
							}

							_fillW += 20;
							_fillStyleSetup = _fillStyle;
						}

						ctx.rect(_fillX, _y, _fillW, 20);
						ctx.fillStyle = _fillStyleSetup;
						ctx.fill();
						_fillX = _fillX + _fillW;
						_fillW = 0;

						ctx.beginPath();
						ctx.rect(_x, _y, 15 + widthControl, 20);
						ctx.stroke();
					}

					ctx.beginPath();

					if (_object.Name != "")
					{
						ctx.fillStyle = (_object.ActiveButtonIndex == -1) ? AscCommonWord.GlobalSkin.ContentControlsTextActive : AscCommonWord.GlobalSkin.ContentControlsText;

						ctx.fillText(_object.Name, _x + 15 + 3, _y + 20 - 6);

						if (_object.NameButtonAdvanced)
						{
							nAdvancedL = (nAdvancedL + 0.5) >> 0;
							var nY = _y - 0.5;
							nY += 10;
							nY -= 1;

							var plus = AscCommon.AscBrowser.isRetina ? 0.5 : 1;

							for (var i = 0; i <= 2; i+=plus)
								ctx.rect(nAdvancedL + i, nY + i, 1, 1);

							for (var i = 0; i <= 2; i+=plus)
								ctx.rect(nAdvancedL + 4 - i, nY + i, 1, 1);

							ctx.fill();
							ctx.beginPath();
						}
					}

					var _yCell = _y;
					if (!AscCommon.AscBrowser.isRetina)
						_yCell = 1 + (_y >> 0);

					for (var nIndexB = 0; nIndexB < _object.Buttons.length; nIndexB++)
					{
						var image = g_oContentControlButtonIcons.getImage(_object.Buttons[nIndexB], nIndexB == _object.ActiveButtonIndex);
						if (image)
							ctx.drawImage(image, nAdvancedLB >> 0, _yCell, 20, 20);
						nAdvancedLB += 20;
					}

					var cx = _x - 0.5 + 4;
					var cy = _y - 0.5 + 4;

					var _color1 = "#ADADAD";
					var _color2 = "#D4D4D4";

					if (0 == this.ContentControlObjectState || 1 == this.ContentControlObjectState)
					{
						_color1 = "#444444";
						_color2 = "#9D9D9D";
					}

					overlay.AddRect(cx, cy, 3, 3);
					overlay.AddRect(cx + 5, cy, 3, 3);
					overlay.AddRect(cx, cy + 5, 3, 3);
					overlay.AddRect(cx + 5, cy + 5, 3, 3);
					overlay.AddRect(cx, cy + 10, 3, 3);
					overlay.AddRect(cx + 5, cy + 10, 3, 3);

					ctx.fillStyle = _color2;
					ctx.fill();
					ctx.beginPath();

					ctx.moveTo(cx + 1.5, cy);
					ctx.lineTo(cx + 1.5, cy + 3);
					ctx.moveTo(cx + 6.5, cy);
					ctx.lineTo(cx + 6.5, cy + 3);
					ctx.moveTo(cx + 1.5, cy + 5);
					ctx.lineTo(cx + 1.5, cy + 8);
					ctx.moveTo(cx + 6.5, cy + 5);
					ctx.lineTo(cx + 6.5, cy + 8);
					ctx.moveTo(cx + 1.5, cy + 10);
					ctx.lineTo(cx + 1.5, cy + 13);
					ctx.moveTo(cx + 6.5, cy + 10);
					ctx.lineTo(cx + 6.5, cy + 13);

					ctx.moveTo(cx, cy + 1.5);
					ctx.lineTo(cx + 3, cy + 1.5);
					ctx.moveTo(cx + 5, cy + 1.5);
					ctx.lineTo(cx + 8, cy + 1.5);
					ctx.moveTo(cx, cy + 6.5);
					ctx.lineTo(cx + 3, cy + 6.5);
					ctx.moveTo(cx + 5, cy + 6.5);
					ctx.lineTo(cx + 8, cy + 6.5);
					ctx.moveTo(cx, cy + 11.5);
					ctx.lineTo(cx + 3, cy + 11.5);
					ctx.moveTo(cx + 5, cy + 11.5);
					ctx.lineTo(cx + 8, cy + 11.5);

					ctx.strokeStyle = _color1;
					ctx.stroke();
					ctx.beginPath();
				}
				else
				{
					var _x = _rect.X - (15 / dKoefX);
					var _y = _rect.Y;
					var _r = _rect.X;
					var _b = _rect.Y + (20 / dKoefY);

					var nAdvancedL = 0;
					var nAdvancedLB = 0;
					if (_object.Name != "" || 0 != _object.Buttons.length)
					{
						_x = _rect.X;
						_y = _rect.Y - (20 / dKoefY);
						_b = _rect.Y;

						var widthControl = 0;

						if (_object.Name != 0)
						{
							ctx.font = g_oContentControlButtonIcons.getFont();
							widthControl += (g_oContentControlButtonIcons.measure(_object.Name, ctx) + 3);
							widthControl += 6; // 3 + 3
							if (_object.NameButtonAdvanced)
							{
								nAdvancedL = 15 + widthControl;
								widthControl += 5;
								widthControl += 3;
							}
							else
								widthControl += 3;
						}

						_object.NameWidth = widthControl;

						nAdvancedLB = 15 + widthControl;
						widthControl += (20 * _object.Buttons.length);

						_r = _x + ((15 + widthControl) / dKoefX);
					}

					var x1 = _transform.TransformPointX(_x, _y);
					var y1 = _transform.TransformPointY(_x, _y);

					var x2 = _transform.TransformPointX(_r, _y);
					var y2 = _transform.TransformPointY(_r, _y);

					var x3 = _transform.TransformPointX(_r, _b);
					var y3 = _transform.TransformPointY(_r, _b);

					var x4 = _transform.TransformPointX(_x, _b);
					var y4 = _transform.TransformPointY(_x, _b);

					x1 = drPage.left + dKoefX * x1;
					x2 = drPage.left + dKoefX * x2;
					x3 = drPage.left + dKoefX * x3;
					x4 = drPage.left + dKoefX * x4;

					y1 = drPage.top + dKoefY * y1;
					y2 = drPage.top + dKoefY * y2;
					y3 = drPage.top + dKoefY * y3;
					y4 = drPage.top + dKoefY * y4;

					overlay.CheckPoint(x1, y1);
					overlay.CheckPoint(x2, y2);
					overlay.CheckPoint(x3, y3);
					overlay.CheckPoint(x4, y4);

					ctx.beginPath();

					if (_object.Name == "" && 0 == _object.Buttons.length)
					{
						ctx.moveTo(x1, y1);
						ctx.lineTo(x2, y2);
						ctx.lineTo(x3, y3);
						ctx.lineTo(x4, y4);
						ctx.closePath();

						ctx.fillStyle = (1 == this.ContentControlObjectState) ? AscCommonWord.GlobalSkin.ContentControlsAnchorActive : AscCommonWord.GlobalSkin.ContentControlsBack;
						ctx.fill();
						ctx.stroke();
					}
					else
					{
						var _ft = new AscCommon.CMatrix();
						_ft.sx = _transform.sx;
						_ft.shx = _transform.shx;
						_ft.shy = _transform.shy;
						_ft.sy = _transform.sy;
						_ft.tx = _transform.tx;
						_ft.ty = _transform.ty;

						var coords = new AscCommon.CMatrix();
						coords.sx = dKoefX;
						coords.sy = dKoefY;
						coords.tx = drPage.left;
						coords.ty = drPage.top;

						global_MatrixTransformer.MultiplyAppend(_ft, coords);

						ctx.transform(_ft.sx, _ft.shy, _ft.shx, _ft.sy, _ft.tx, _ft.ty);

						var _fillStyleSetup = (1 == this.ContentControlObjectState) ? AscCommonWord.GlobalSkin.ContentControlsAnchorActive : AscCommonWord.GlobalSkin.ContentControlsBack;
						var _fillStyle = "";
						var _fillX = _x;
						var _fillW = 15;
						if (_object.Name != "")
						{
							if (_object.NameWidth != 0)
							{
								if (_object.ActiveButtonIndex == -1)
									_fillStyle = AscCommonWord.GlobalSkin.ContentControlsActive;
								else if (_object.HoverButtonIndex == -1)
									_fillStyle = AscCommonWord.GlobalSkin.ContentControlsHover;
								else
									_fillStyle = AscCommonWord.GlobalSkin.ContentControlsBack;

								if (_fillStyle != _fillStyleSetup)
								{
									ctx.rect(_fillX, _y, _fillW / dKoefX, 20 / dKoefY);
									_fillX = _fillX + _fillW / dKoefX;
									_fillW = 0;

									ctx.fillStyle = _fillStyleSetup;
									ctx.fill();
									ctx.beginPath();
								}

								_fillW += _object.NameWidth;
								_fillStyleSetup = _fillStyle;
							}
						}

						for (var nIndexB = 0; nIndexB < _object.Buttons.length; nIndexB++)
						{
							if (_object.ActiveButtonIndex == nIndexB)
								_fillStyle = AscCommonWord.GlobalSkin.ContentControlsActive;
							else if (_object.HoverButtonIndex == nIndexB)
								_fillStyle = AscCommonWord.GlobalSkin.ContentControlsHover;
							else
								_fillStyle = AscCommonWord.GlobalSkin.ContentControlsBack;

							if (_fillStyle != _fillStyleSetup)
							{
								ctx.rect(_fillX, _y, _fillW / dKoefX, 20 / dKoefY);
								_fillX = _fillX + _fillW / dKoefX;
								_fillW = 0;

								ctx.fillStyle = _fillStyleSetup;
								ctx.fill();
								ctx.beginPath();
							}

							_fillW += 20;
							_fillStyleSetup = _fillStyle;
						}

						ctx.rect(_fillX, _y, _fillW / dKoefX, 20 / dKoefY);
						ctx.fillStyle = _fillStyleSetup;
						ctx.fill();
						_fillX = _fillX + _fillW / dKoefX;
						_fillW = 0;

						ctx.beginPath();

						if (_object.Name != "")
						{
							ctx.fillStyle = (_object.ActiveButtonIndex == -1) ? AscCommonWord.GlobalSkin.ContentControlsTextActive : AscCommonWord.GlobalSkin.ContentControlsText;

							ctx.font = g_oContentControlButtonIcons.getFont(dKoefY);
							ctx.fillText(_object.Name, _x + (15 + 3) / dKoefX, _y + (20 - 6) / dKoefY);

							if (_object.NameButtonAdvanced)
							{
								var nY = _y;
								nY += 9 / dKoefY;

								for (var i = 0; i < 3; i++)
									ctx.rect(_x + (nAdvancedL + i) / dKoefX, nY + i / dKoefY, 1 / dKoefX, 1 / dKoefY);

								for (var i = 0; i < 2; i++)
									ctx.rect(_x + (nAdvancedL + 4 - i) / dKoefX, nY + i / dKoefY, 1 / dKoefX, 1 / dKoefY);

								ctx.fill();
								ctx.beginPath();
							}
						}

						for (var nIndexB = 0; nIndexB < _object.Buttons.length; nIndexB++)
						{
							var image = g_oContentControlButtonIcons.getImage(_object.Buttons[nIndexB], nIndexB == _object.ActiveButtonIndex);
							if (image)
								ctx.drawImage(image, _x + nAdvancedLB / dKoefX, _y, 20 / dKoefX, 20 / dKoefY);
							nAdvancedLB += 20;
						}

						overlay.SetBaseTransform();

						ctx.beginPath();
						ctx.moveTo(x1, y1);
						ctx.lineTo(x2, y2);
						ctx.lineTo(x3, y3);
						ctx.lineTo(x4, y4);
						ctx.closePath();

						ctx.stroke();
					}

					ctx.beginPath();

					var cx1 = _x + 5  / dKoefX;
					var cy1 = _y + 5  / dKoefY;
					var cx2 = _x + 10 / dKoefX;
					var cy2 = _y + 5  / dKoefY;

					var cx3 = _x + 5  / dKoefX;
					var cy3 = _y + 10 / dKoefY;
					var cx4 = _x + 10 / dKoefX;
					var cy4 = _y + 10 / dKoefY;

					var cx5 = _x + 5  / dKoefX;
					var cy5 = _y + 15 / dKoefY;
					var cx6 = _x + 10 / dKoefX;
					var cy6 = _y + 15 / dKoefY;

					overlay.AddEllipse(drPage.left + dKoefX * _transform.TransformPointX(cx1, cy1), drPage.top + dKoefY * _transform.TransformPointY(cx1, cy1), 1.5);
					overlay.AddEllipse(drPage.left + dKoefX * _transform.TransformPointX(cx2, cy2), drPage.top + dKoefY * _transform.TransformPointY(cx2, cy2), 1.5);
					overlay.AddEllipse(drPage.left + dKoefX * _transform.TransformPointX(cx3, cy3), drPage.top + dKoefY * _transform.TransformPointY(cx3, cy3), 1.5);
					overlay.AddEllipse(drPage.left + dKoefX * _transform.TransformPointX(cx4, cy4), drPage.top + dKoefY * _transform.TransformPointY(cx4, cy4), 1.5);
					overlay.AddEllipse(drPage.left + dKoefX * _transform.TransformPointX(cx5, cy5), drPage.top + dKoefY * _transform.TransformPointY(cx5, cy5), 1.5);
					overlay.AddEllipse(drPage.left + dKoefX * _transform.TransformPointX(cx6, cy6), drPage.top + dKoefY * _transform.TransformPointY(cx6, cy6), 1.5);

					var _color1 = "#ADADAD";
					if (0 == this.ContentControlObjectState || 1 == this.ContentControlObjectState)
						_color1 = "#444444";

					ctx.fillStyle = _color1;
					ctx.fill();
					ctx.beginPath();
				}
			}
		}

		this.ContentControlsSaveLast();
	};

	this.OnDrawContentControl = function(id, type, rects, transform, name, name_advanced, button_types, color)
	{
		var isActiveRemove = false;
		// всегда должен быть максимум один hover и in
		for (var i = 0; i < this.ContentControlObjects.length; i++)
		{
			if (type == this.ContentControlObjects[i].type)
			{
				if (-2 != this.ContentControlObjects[i].ActiveButtonIndex)
					isActiveRemove = true;

				this.ContentControlObjects.splice(i, 1);
				i--;
			}
		}

		if (null == id || !rects || rects.length == 0)
		{
			if (isActiveRemove)
				this.m_oWordControl.m_oApi.sendEvent("asc_onHideContentControlsActions");
			return;
		}

		if (type == c_oContentControlTrack.In)
		{
			if (this.ContentControlObjects.length != 0 && this.ContentControlObjects[0].id == id)
			{
				if (-2 != this.ContentControlObjects[0].ActiveButtonIndex)
					isActiveRemove = true;

				this.ContentControlObjects.splice(0, 1);
			}
			if (this.m_oWordControl.m_oApi.isViewMode)
				this.ContentControlObjects.push(new CContentControlTrack(id, type, rects, transform, name, undefined, undefined, color));
			else
				this.ContentControlObjects.push(new CContentControlTrack(id, type, rects, transform, name, name_advanced, button_types, color));
		}
		else
		{
			if (this.ContentControlObjects.length != 0 && this.ContentControlObjects[0].id == id)
				return;

			if (this.m_oWordControl.m_oApi.isViewMode)
				this.ContentControlObjects.push(new CContentControlTrack(id, type, rects, transform, name, undefined, undefined, color));
			else
				this.ContentControlObjects.push(new CContentControlTrack(id, type, rects, transform, name, name_advanced, button_types, color));
		}

		if (isActiveRemove)
			this.m_oWordControl.m_oApi.sendEvent("asc_onHideContentControlsActions");
	};

	this.private_DrawMathTrack = function (overlay, oPath, shift, color, dKoefX, dKoefY, drPage)
	{
		var ctx = overlay.m_oContext;
		ctx.strokeStyle = color;
		ctx.lineWidth = 1;
		ctx.beginPath();

		var Points = oPath.Points;

		var nCount = Points.length;
		// берем предпоследнюю точку, т.к. последняя совпадает с первой
		var PrevX = Points[nCount - 2].X, PrevY = Points[nCount - 2].Y;
		var _x = drPage.left + dKoefX * Points[nCount - 2].X,
			_y = drPage.top + dKoefY * Points[nCount - 2].Y;
		var StartX, StartY;

		for (var nIndex = 0; nIndex < nCount; nIndex++)
		{
			if (PrevX > Points[nIndex].X)
			{
				_y = drPage.top + dKoefY * Points[nIndex].Y - shift;
			}
			else if (PrevX < Points[nIndex].X)
			{
				_y = drPage.top + dKoefY * Points[nIndex].Y + shift;
			}

			if (PrevY < Points[nIndex].Y)
			{
				_x = drPage.left + dKoefX * Points[nIndex].X - shift;
			}
			else if (PrevY > Points[nIndex].Y)
			{
				_x = drPage.left + dKoefX * Points[nIndex].X + shift;
			}

			PrevX = Points[nIndex].X;
			PrevY = Points[nIndex].Y;

			if (nIndex > 0)
			{
				overlay.CheckPoint(_x, _y);

				if (1 == nIndex)
				{
					StartX = _x;
					StartY = _y;
					overlay.m_oContext.moveTo((_x >> 0) + 0.5, (_y >> 0) + 0.5);
				}
				else
				{
					overlay.m_oContext.lineTo((_x >> 0) + 0.5, (_y >> 0) + 0.5);
				}
			}
		}

		overlay.m_oContext.lineTo((StartX >> 0) + 0.5, (StartY >> 0) + 0.5);

		ctx.closePath();
		ctx.stroke();
		ctx.beginPath();
	};
	this.private_DrawMathTrackWithMatrix = function (overlay, oPath, ShiftX, ShiftY, color, dKoefX, dKoefY, drPage, m)
	{
		var ctx = overlay.m_oContext;
		ctx.strokeStyle = color;
		ctx.lineWidth = 1;
		ctx.beginPath();

		var Points = oPath.Points;

		var nCount = Points.length;
		// берем предпоследнюю точку, т.к. последняя совпадает с первой
		var x = Points[nCount - 2].X, y = Points[nCount - 2].Y;
		var _x, _y;

		var PrevX = Points[nCount - 2].X, PrevY = Points[nCount - 2].Y;
		var StartX, StartY;

		for (var nIndex = 0; nIndex < nCount; nIndex++)
		{
			if (PrevX > Points[nIndex].X)
			{
				y = Points[nIndex].Y - ShiftY;
			}
			else if (PrevX < Points[nIndex].X)
			{
				y = Points[nIndex].Y + ShiftY;
			}

			if (PrevY < Points[nIndex].Y)
			{
				x = Points[nIndex].X - ShiftX;
			}
			else if (PrevY > Points[nIndex].Y)
			{
				x = Points[nIndex].X + ShiftX;
			}

			PrevX = Points[nIndex].X;
			PrevY = Points[nIndex].Y;

			if (nIndex > 0)
			{
				_x = (drPage.left + dKoefX * m.TransformPointX(x, y));
				_y = (drPage.top + dKoefY * m.TransformPointY(x, y));

				overlay.CheckPoint(_x, _y);

				if (1 == nIndex)
				{
					StartX = _x;
					StartY = _y;
					overlay.m_oContext.moveTo((_x >> 0) + 0.5, (_y >> 0) + 0.5);
				}
				else
				{
					overlay.m_oContext.lineTo((_x >> 0) + 0.5, (_y >> 0) + 0.5);
				}
			}

		}

		overlay.m_oContext.lineTo((StartX >> 0) + 0.5, (StartY >> 0) + 0.5);

		ctx.closePath();
		ctx.stroke();
		ctx.beginPath();
	};

	this.DrawMathTrack = function (overlay)
	{
		if (!this.MathRect.IsActive)
			return;

		overlay.Show();

		var ctx = overlay.m_oContext;
		var nIndex, nCount;
		var oPath, SelectPaths;
		var _page, drPage, dKoefX, dKoefY;
		var PathLng = this.MathPolygons.length;
		var Points, nPointIndex, _x, _y;

		if (null == this.TextMatrix || global_MatrixTransformer.IsIdentity(this.TextMatrix))
		{
			for (nIndex = 0; nIndex < PathLng; nIndex++)
			{
				oPath = this.MathPolygons[nIndex];

				_page = this.m_arrPages[oPath.Page];
				drPage = _page.drawingPage;

				dKoefX = (drPage.right - drPage.left) / _page.width_mm;
				dKoefY = (drPage.bottom - drPage.top) / _page.height_mm;

				this.private_DrawMathTrack(overlay, oPath, 0, "#939393", dKoefX, dKoefY, drPage);
				this.private_DrawMathTrack(overlay, oPath, 1, "#FFFFFF", dKoefX, dKoefY, drPage);
			}

			SelectPaths = this.MathSelectPolygons;

			for (nIndex = 0, nCount = SelectPaths.length; nIndex < nCount; nIndex++)
			{
				oPath = SelectPaths[nIndex];
				_page = this.m_arrPages[oPath.Page];
				drPage = _page.drawingPage;

				dKoefX = (drPage.right - drPage.left) / _page.width_mm;
				dKoefY = (drPage.bottom - drPage.top) / _page.height_mm;

				ctx.fillStyle = "#375082";
				ctx.beginPath();

				Points = oPath.Points;
				for (nPointIndex = 0; nPointIndex < Points.length - 1; nPointIndex++)
				{
					_x = drPage.left + dKoefX * Points[nPointIndex].X;
					_y = drPage.top + dKoefY * Points[nPointIndex].Y;

					overlay.CheckPoint(_x, _y);

					if (0 == nPointIndex)
						ctx.moveTo((_x >> 0) + 0.5, (_y >> 0) + 0.5);
					else
						ctx.lineTo((_x >> 0) + 0.5, (_y >> 0) + 0.5);
				}

				ctx.globalAlpha = 0.2;
				ctx.fill();
				ctx.globalAlpha = 1;

			}
		}
		else
		{
			for (nIndex = 0; nIndex < PathLng; nIndex++)
			{
				oPath = this.MathPolygons[nIndex];
				_page = this.m_arrPages[oPath.Page];
				drPage = _page.drawingPage;

				dKoefX = (drPage.right - drPage.left) / _page.width_mm;
				dKoefY = (drPage.bottom - drPage.top) / _page.height_mm;

				var _1px_mm_x = 1 / Math.max(dKoefX, 0.001);
				var _1px_mm_y = 1 / Math.max(dKoefY, 0.001);

				this.private_DrawMathTrackWithMatrix(overlay, oPath, 0, 0, "#939393", dKoefX, dKoefY, drPage, this.TextMatrix);
				this.private_DrawMathTrackWithMatrix(overlay, oPath, _1px_mm_x, _1px_mm_y, "#FFFFFF", dKoefX, dKoefY, drPage, this.TextMatrix);
			}

			SelectPaths = this.MathSelectPolygons;

			for (nIndex = 0, nCount = SelectPaths.length; nIndex < nCount; nIndex++)
			{
				oPath = SelectPaths[nIndex];
				_page = this.m_arrPages[oPath.Page];
				drPage = _page.drawingPage;

				dKoefX = (drPage.right - drPage.left) / _page.width_mm;
				dKoefY = (drPage.bottom - drPage.top) / _page.height_mm;

				ctx.fillStyle = "#375082";
				ctx.beginPath();

				Points = oPath.Points;
				for (nPointIndex = 0; nPointIndex < Points.length - 1; nPointIndex++)
				{
					var x = Points[nPointIndex].X, y = Points[nPointIndex].Y;
					_x = drPage.left + dKoefX * this.TextMatrix.TransformPointX(x, y);
					_y = drPage.top + dKoefY * this.TextMatrix.TransformPointY(x, y);

					overlay.CheckPoint(_x, _y);

					if (0 == nPointIndex)
						ctx.moveTo((_x >> 0) + 0.5, (_y >> 0) + 0.5);
					else
						ctx.lineTo((_x >> 0) + 0.5, (_y >> 0) + 0.5);
				}

				ctx.globalAlpha = 0.2;
				ctx.fill();
				ctx.globalAlpha = 1;

			}
		}
	};

	this.DrawFieldTrack = function (overlay)
	{
		if (!this.FieldTrack.IsActive)
			return;

		overlay.Show();

		for (var nIndex = 0, nCount = this.FieldTrack.Rects.length; nIndex < nCount; nIndex++)
		{
			var FieldRect = this.FieldTrack.Rects[nIndex];

			var _page = this.m_arrPages[FieldRect.PageIndex];
			var drPage = _page.drawingPage;

			var dKoefX = (drPage.right - drPage.left) / _page.width_mm;
			var dKoefY = (drPage.bottom - drPage.top) / _page.height_mm;

			if (null == this.TextMatrix || global_MatrixTransformer.IsIdentity(this.TextMatrix))
			{
				var _x = (drPage.left + dKoefX * FieldRect.X0);
				var _y = (drPage.top + dKoefY * FieldRect.Y0);
				var _r = (drPage.left + dKoefX * FieldRect.X1);
				var _b = (drPage.top + dKoefY * FieldRect.Y1);

				if (_x < overlay.min_x)
					overlay.min_x = _x;
				if (_r > overlay.max_x)
					overlay.max_x = _r;

				if (_y < overlay.min_y)
					overlay.min_y = _y;
				if (_b > overlay.max_y)
					overlay.max_y = _b;

				var ctx = overlay.m_oContext;
				ctx.fillStyle = "#375082";

				ctx.beginPath();
				this.AutoShapesTrack.AddRect(ctx, _x >> 0, _y >> 0, _r >> 0, _b >> 0);

				ctx.globalAlpha = 0.2;
				ctx.fill();
				ctx.globalAlpha = 1;
				ctx.beginPath();
			}
			else
			{
				var _arrSelect = TransformRectByMatrix(this.TextMatrix, [FieldRect.X0, FieldRect.Y0, FieldRect.X1, FieldRect.Y1], drPage.left, drPage.top, dKoefX, dKoefY);

				overlay.CheckPoint(_arrSelect[0], _arrSelect[1]);
				overlay.CheckPoint(_arrSelect[2], _arrSelect[3]);
				overlay.CheckPoint(_arrSelect[4], _arrSelect[5]);
				overlay.CheckPoint(_arrSelect[6], _arrSelect[7]);

				var ctx = overlay.m_oContext;
				ctx.fillStyle = "#375082";

				ctx.beginPath();

				ctx.moveTo(_arrSelect[0], _arrSelect[1]);
				ctx.lineTo(_arrSelect[2], _arrSelect[3]);
				ctx.lineTo(_arrSelect[4], _arrSelect[5]);
				ctx.lineTo(_arrSelect[6], _arrSelect[7]);
				ctx.closePath();

				ctx.globalAlpha = 0.2;
				ctx.fill();
				ctx.globalAlpha = 1;
				ctx.beginPath();
			}
		}
	}

	this.DrawTableTrack = function (overlay)
	{
		if (null == this.TableOutlineDr.TableOutline)
			return;

		var _table = this.TableOutlineDr.TableOutline.Table;

		if (!_table.Is_Inline() || this.TableOutlineDr.IsResizeTableTrack)
		{
			if (null == this.TableOutlineDr.CurPos)
				return;

			var _page = this.m_arrPages[this.TableOutlineDr.CurPos.Page];
			var drPage = _page.drawingPage;

			var dKoefX = (drPage.right - drPage.left) / _page.width_mm;
			var dKoefY = (drPage.bottom - drPage.top) / _page.height_mm;

			if (!this.TableOutlineDr.TableMatrix || global_MatrixTransformer.IsIdentity(this.TableOutlineDr.TableMatrix))
			{
				var _x = ((drPage.left + dKoefX * this.TableOutlineDr.CurPos.X) >> 0) + 0.5;
				var _y = ((drPage.top + dKoefY * this.TableOutlineDr.CurPos.Y) >> 0) + 0.5;

				var _r = _x + ((dKoefX * this.TableOutlineDr.TableOutline.W) >> 0);
				var _b = _y + ((dKoefY * this.TableOutlineDr.TableOutline.H) >> 0);

				if (this.TableOutlineDr.IsResizeTableTrack)
				{
					var _lastBounds = this.TableOutlineDr.getLastPageBounds();
					var _lastX = _lastBounds.X;
					var _lastY = this.TableOutlineDr.getFullTopPosition(_lastBounds);
					var _lastYStart = _lastBounds.Y;

					_x = ((drPage.left + dKoefX * _lastX) >> 0) + 0.5;
					_y = ((drPage.top + dKoefY * _lastY) >> 0) + 0.5;
					var _yStart = ((drPage.top + dKoefY * _lastYStart) >> 0) + 0.5;

					_r = _x + ((dKoefX * (_lastBounds.W + this.TableOutlineDr.AddResizeCurrentW)) >> 0);
					_b = _yStart + ((dKoefY * (_lastBounds.H + this.TableOutlineDr.AddResizeCurrentH)) >> 0);
				}

				overlay.CheckPoint(_x, _y);
				overlay.CheckPoint(_x, _b);
				overlay.CheckPoint(_r, _y);
				overlay.CheckPoint(_r, _b);

				var ctx = overlay.m_oContext;
				ctx.strokeStyle = "#FFFFFF";

				ctx.beginPath();
				ctx.rect(_x, _y, _r - _x, _b - _y);
				ctx.stroke();

				ctx.strokeStyle = "#000000";
				ctx.beginPath();

				// набиваем пунктир
				var dot_size = 3;
				for (var i = _x; i < _r; i += dot_size)
				{
					ctx.moveTo(i, _y);
					i += dot_size;

					if (i > _r)
						i = _r;

					ctx.lineTo(i, _y);
				}
				for (var i = _y; i < _b; i += dot_size)
				{
					ctx.moveTo(_r, i);
					i += dot_size;

					if (i > _b)
						i = _b;

					ctx.lineTo(_r, i);
				}
				for (var i = _r; i > _x; i -= dot_size)
				{
					ctx.moveTo(i, _b);
					i -= dot_size;

					if (i < _x)
						i = _x;

					ctx.lineTo(i, _b);
				}
				for (var i = _b; i > _y; i -= dot_size)
				{
					ctx.moveTo(_x, i);
					i -= dot_size;

					if (i < _y)
						i = _y;

					ctx.lineTo(_x, i);
				}

				ctx.stroke();
				ctx.beginPath();
			}
			else
			{
				var _x = this.TableOutlineDr.CurPos.X + _table.GetTableOffsetCorrection();
				var _y = this.TableOutlineDr.CurPos.Y;
				var _r = _x + this.TableOutlineDr.TableOutline.W;
				var _b = _y + this.TableOutlineDr.TableOutline.H;

				if (this.TableOutlineDr.IsResizeTableTrack)
				{
					_x = this.TableOutlineDr.TableOutline.X;
					_y = this.TableOutlineDr.TableOutline.Y;

					_r = _x + (this.TableOutlineDr.TableOutline.W + this.TableOutlineDr.AddResizeCurrentW);
					_b = _y + (this.TableOutlineDr.TableOutline.H + this.TableOutlineDr.AddResizeCurrentH);
				}

				var transform = this.TableOutlineDr.TableMatrix;

				var x1 = transform.TransformPointX(_x, _y);
				var y1 = transform.TransformPointY(_x, _y);

				var x2 = transform.TransformPointX(_r, _y);
				var y2 = transform.TransformPointY(_r, _y);

				var x3 = transform.TransformPointX(_r, _b);
				var y3 = transform.TransformPointY(_r, _b);

				var x4 = transform.TransformPointX(_x, _b);
				var y4 = transform.TransformPointY(_x, _b);

				x1 = drPage.left + dKoefX * x1;
				y1 = drPage.top + dKoefY * y1;

				x2 = drPage.left + dKoefX * x2;
				y2 = drPage.top + dKoefY * y2;

				x3 = drPage.left + dKoefX * x3;
				y3 = drPage.top + dKoefY * y3;

				x4 = drPage.left + dKoefX * x4;
				y4 = drPage.top + dKoefY * y4;

				overlay.CheckPoint(x1, y1);
				overlay.CheckPoint(x2, y2);
				overlay.CheckPoint(x3, y3);
				overlay.CheckPoint(x4, y4);

				var ctx = overlay.m_oContext;
				ctx.strokeStyle = "#FFFFFF";

				ctx.beginPath();
				ctx.moveTo(x1, y1);
				ctx.lineTo(x2, y2);
				ctx.lineTo(x3, y3);
				ctx.lineTo(x4, y4);
				ctx.closePath();
				ctx.stroke();

				ctx.strokeStyle = "#000000";
				ctx.beginPath();
				this.AutoShapesTrack.AddRectDash(ctx, x1, y1, x2, y2, x4, y4, x3, y3, 3, 3, true);
				ctx.beginPath();
			}
		}
		else
		{
			this.LockCursorType("default");

			var _x = global_mouseEvent.X;
			var _y = global_mouseEvent.Y;
			var posMouse = this.ConvertCoordsFromCursor2(_x, _y);

			this.TableOutlineDr.InlinePos = this.m_oWordControl.m_oLogicDocument.Get_NearestPos(posMouse.Page, posMouse.X, posMouse.Y);
			this.TableOutlineDr.InlinePos.Page = posMouse.Page;
			//var posView = this.ConvertCoordsToCursor(this.TableOutlineDr.InlinePos.X, this.TableOutlineDr.InlinePos.Y, posMouse.Page, true);

			var _near = this.TableOutlineDr.InlinePos;
			this.AutoShapesTrack.SetCurrentPage(_near.Page);
			this.AutoShapesTrack.DrawInlineMoveCursor(_near.X, _near.Y, _near.Height, _near.transform);
		}
	}
	this.SetCurrentPage = function (PageIndex)
	{
		if (PageIndex >= this.m_arrPages.length)
			return;
		if (this.m_lCurrentPage == PageIndex)
			return;

		this.m_lCurrentPage = PageIndex;
		this.m_oWordControl.SetCurrentPage();
	}

	this.SelectEnabled = function (bIsEnabled)
	{
		this.m_bIsSelection = bIsEnabled;
		if (false === this.m_bIsSelection)
		{
			this.SelectClear();
			//this.m_oWordControl.CheckUnShowOverlay();
			this.m_oWordControl.OnUpdateOverlay();
			this.m_oWordControl.m_oOverlayApi.m_oContext.globalAlpha = 1.0;
		}
	}
	this.SelectClear = function ()
	{
		if (this.m_oWordControl.MobileTouchManager)
		{
			this.m_oWordControl.MobileTouchManager.RectSelect1 = null;
			this.m_oWordControl.MobileTouchManager.RectSelect2 = null;
		}
	}
	this.SearchClear = function ()
	{
		for (var i = 0; i < this.m_lPagesCount; i++)
		{
			this.m_arrPages[i].searchingArray.splice(0, this.m_arrPages[i].searchingArray.length);
		}

		this._search_HdrFtr_All.splice(0, this._search_HdrFtr_All.length);
		this._search_HdrFtr_All_no_First.splice(0, this._search_HdrFtr_All_no_First.length);
		this._search_HdrFtr_First.splice(0, this._search_HdrFtr_First.length);
		this._search_HdrFtr_Even.splice(0, this._search_HdrFtr_Even.length);
		this._search_HdrFtr_Odd.splice(0, this._search_HdrFtr_Odd.length);
		this._search_HdrFtr_Odd_no_First.splice(0, this._search_HdrFtr_Odd_no_First.length);

		this.m_oWordControl.m_oOverlayApi.Clear();
		this.m_bIsSearching = false;
	}
	this.AddPageSearch = function (findText, rects, type)
	{
		var _len = rects.length;
		if (_len == 0)
			return;

		if (this.m_oWordControl.m_oOverlay.HtmlElement.style.display == "none")
		{
			this.m_oWordControl.ShowOverlay();
			this.m_oWordControl.m_oOverlayApi.m_oContext.globalAlpha = 0.2;
		}

		var navigator = {Page: rects[0].PageNum, Place: rects, Type: type};

		var _find = {text: findText, navigator: navigator};
		this.m_oWordControl.m_oApi.sync_SearchFoundCallback(_find);

		var is_update = false;

		var _type = type & 0x00FF;
		switch (_type)
		{
			case search_Common:
			{
				var _pages = this.m_arrPages;
				for (var i = 0; i < _len; i++)
				{
					var r = rects[i];

					if (this.SearchTransform)
						r.Transform = this.SearchTransform;

					_pages[r.PageNum].searchingArray[_pages[r.PageNum].searchingArray.length] = r;

					if (r.PageNum >= this.m_lDrawingFirst && r.PageNum <= this.m_lDrawingEnd)
						is_update = true;
				}
				break;
			}
			case search_HdrFtr_All:
			{
				for (var i = 0; i < _len; i++)
				{
					if (this.SearchTransform)
						rects[i].Transform = this.SearchTransform;

					this._search_HdrFtr_All[this._search_HdrFtr_All.length] = rects[i];
				}
				is_update = true;

				break;
			}
			case search_HdrFtr_All_no_First:
			{
				for (var i = 0; i < _len; i++)
				{
					if (this.SearchTransform)
						rects[i].Transform = this.SearchTransform;

					this._search_HdrFtr_All_no_First[this._search_HdrFtr_All_no_First.length] = rects[i];
				}
				if (this.m_lDrawingEnd > 0)
					is_update = true;

				break;
			}
			case search_HdrFtr_First:
			{
				for (var i = 0; i < _len; i++)
				{
					if (this.SearchTransform)
						rects[i].Transform = this.SearchTransform;

					this._search_HdrFtr_First[this._search_HdrFtr_First.length] = rects[i];
				}
				if (this.m_lDrawingFirst == 0)
					is_update = true;

				break;
			}
			case search_HdrFtr_Even:
			{
				for (var i = 0; i < _len; i++)
				{
					if (this.SearchTransform)
						rects[i].Transform = this.SearchTransform;

					this._search_HdrFtr_Even[this._search_HdrFtr_Even.length] = rects[i];
				}
				var __c = this.m_lDrawingEnd - this.m_lDrawingFirst;

				if (__c > 1)
					is_update = true;
				else if (__c == 1 && (this.m_lDrawingFirst & 1) == 1)
					is_update = true;

				break;
			}
			case search_HdrFtr_Odd:
			{
				for (var i = 0; i < _len; i++)
				{
					if (this.SearchTransform)
						rects[i].Transform = this.SearchTransform;

					this._search_HdrFtr_Odd[this._search_HdrFtr_Odd.length] = rects[i];
				}
				var __c = this.m_lDrawingEnd - this.m_lDrawingFirst;

				if (__c > 1)
					is_update = true;
				else if (__c == 1 && (this.m_lDrawingFirst & 1) == 0)
					is_update = true;

				break;
			}
			case search_HdrFtr_Odd_no_First:
			{
				for (var i = 0; i < _len; i++)
				{
					if (this.SearchTransform)
						rects[i].Transform = this.SearchTransform;

					this._search_HdrFtr_Odd_no_First[this._search_HdrFtr_Odd_no_First.length] = rects[i];
				}

				if (this.m_lDrawingEnd > 1)
				{
					var __c = this.m_lDrawingEnd - this.m_lDrawingFirst;
					if (__c > 1)
						is_update = true;
					else if (__c == 1 && (this.m_lDrawingFirst & 1) == 0)
						is_update = true;
				}

				break;
			}
			default:
				break;
		}

		if (is_update)
			this.m_oWordControl.OnUpdateOverlay();

	}

	this.StartSearchTransform = function (transform)
	{
		this.SearchTransform = transform.CreateDublicate();
	}

	this.EndSearchTransform = function ()
	{
		this.SearchTransform = null;
	}

	this.StartSearch = function ()
	{
		this.SearchClear();
		if (this.m_bIsSelection)
			this.m_oWordControl.OnUpdateOverlay();
		this.m_bIsSearching = true;
	}
	this.EndSearch = function (bIsChange)
	{
		if (bIsChange)
		{
			this.SearchClear();
			this.m_bIsSearching = false;
			this.m_oWordControl.OnUpdateOverlay();
		}
		else
		{
			this.m_bIsSearching = true;
			this.m_oWordControl.OnUpdateOverlay();
		}
		this.m_oWordControl.m_oApi.sync_SearchEndCallback();
	}

	this.SetTextSelectionOutline = function (isSelectionOutline)
	{
		this.IsTextSelectionOutline = isSelectionOutline;
	}

	this.private_StartDrawSelection = function (overlay, isSelect2)
	{
		this.Overlay = overlay;
		this.IsTextMatrixUse = ((null != this.TextMatrix) && !global_MatrixTransformer.IsIdentity(this.TextMatrix));

		this.Overlay.m_oContext.fillStyle = "rgba(51,102,204,255)";
		this.Overlay.m_oContext.beginPath();

		if (this.m_oWordControl.MobileTouchManager && (true !== isSelect2))
		{
			this.m_oWordControl.MobileTouchManager.RectSelect1 = null;
			this.m_oWordControl.MobileTouchManager.RectSelect2 = null;
		}
	}
	this.private_EndDrawSelection = function ()
	{
		var ctx = this.Overlay.m_oContext;

		ctx.globalAlpha = 0.2;
		ctx.fill();

		if (this.IsTextMatrixUse && this.IsTextSelectionOutline)
		{
			ctx.strokeStyle = "#9ADBFE";
			ctx.lineWidth = 1;
			ctx.globalAlpha = 1.0;
			ctx.stroke();
		}

		ctx.beginPath();
		ctx.globalAlpha = 1.0;

		this.IsTextMatrixUse = false;
		this.Overlay = null;
	}

	this.AddPageSelection = function (pageIndex, x, y, w, h)
	{
		if (null == this.SelectionMatrix)
			this.SelectionMatrix = this.TextMatrix;

		this.IsTextMatrixUse = ((null != this.TextMatrix) && !global_MatrixTransformer.IsIdentity(this.TextMatrix));

		var page = this.m_arrPages[pageIndex];
		var drawPage = page.drawingPage;

		var dKoefX = (drawPage.right - drawPage.left) / page.width_mm;
		var dKoefY = (drawPage.bottom - drawPage.top) / page.height_mm;

		if (!this.IsTextMatrixUse)
		{
			var _x = ((drawPage.left + dKoefX * x) >> 0);
			var _y = ((drawPage.top + dKoefY * y) >> 0);

			var _r = ((drawPage.left + dKoefX * (x + w)) >> 0);
			var _b = ((drawPage.top + dKoefY * (y + h)) >> 0);

			var _w = _r - _x + 1;
			var _h = _b - _y + 1;

			this.Overlay.CheckRect(_x, _y, _w, _h);
			this.Overlay.m_oContext.rect(_x, _y, _w, _h);
		}
		else
		{
			var _x1 = this.TextMatrix.TransformPointX(x, y);
			var _y1 = this.TextMatrix.TransformPointY(x, y);

			var _x2 = this.TextMatrix.TransformPointX(x + w, y);
			var _y2 = this.TextMatrix.TransformPointY(x + w, y);

			var _x3 = this.TextMatrix.TransformPointX(x + w, y + h);
			var _y3 = this.TextMatrix.TransformPointY(x + w, y + h);

			var _x4 = this.TextMatrix.TransformPointX(x, y + h);
			var _y4 = this.TextMatrix.TransformPointY(x, y + h);

			var x1 = drawPage.left + dKoefX * _x1;
			var y1 = drawPage.top + dKoefY * _y1;

			var x2 = drawPage.left + dKoefX * _x2;
			var y2 = drawPage.top + dKoefY * _y2;

			var x3 = drawPage.left + dKoefX * _x3;
			var y3 = drawPage.top + dKoefY * _y3;

			var x4 = drawPage.left + dKoefX * _x4;
			var y4 = drawPage.top + dKoefY * _y4;

			if (global_MatrixTransformer.IsIdentity2(this.TextMatrix))
			{
				x1 = (x1 >> 0) + 0.5;
				y1 = (y1 >> 0) + 0.5;

				x2 = (x2 >> 0) + 0.5;
				y2 = (y2 >> 0) + 0.5;

				x3 = (x3 >> 0) + 0.5;
				y3 = (y3 >> 0) + 0.5;

				x4 = (x4 >> 0) + 0.5;
				y4 = (y4 >> 0) + 0.5;
			}

			this.Overlay.CheckPoint(x1, y1);
			this.Overlay.CheckPoint(x2, y2);
			this.Overlay.CheckPoint(x3, y3);
			this.Overlay.CheckPoint(x4, y4);

			var ctx = this.Overlay.m_oContext;
			ctx.moveTo(x1, y1);
			ctx.lineTo(x2, y2);
			ctx.lineTo(x3, y3);
			ctx.lineTo(x4, y4);
			ctx.closePath();
		}
	}

    this.AddPageSelection2 = function (pageIndex, x, y, w, h)
    {
        if (!this.OverlaySelection2.Data)
            this.OverlaySelection2.Data = [];

        this.OverlaySelection2.Data.push([pageIndex, x, y, w, h]);
    }

    this.DrawPageSelection2 = function(overlay)
	{
		if (this.OverlaySelection2.Data)
		{
			this.private_StartDrawSelection(overlay, true);

			var len = this.OverlaySelection2.Data.length;
			var value;
			for (var i = 0; i < len; i++)
			{
				value = this.OverlaySelection2.Data[i];
				this.AddPageSelection(value[0], value[1], value[2], value[3], value[4]);
			}

            this.private_EndDrawSelection();
		}
        this.OverlaySelection2 = {};
	}

	this.CheckSelectMobile = function (overlay)
	{
		var _select = this.m_oWordControl.m_oLogicDocument.GetSelectionBounds();
		if (!_select)
			return;

		var _rect1 = _select.Start;
		var _rect2 = _select.End;

		if (!_rect1 || !_rect2)
			return;

		var _matrix = this.TextMatrix;

		var ctx = overlay.m_oContext;

		var pos1, pos2, pos3, pos4;

		if (!_matrix || global_MatrixTransformer.IsIdentity(_matrix))
		{
			pos1 = this.ConvertCoordsToCursorWR(_rect1.X, _rect1.Y, _rect1.Page, undefined, false);
			pos2 = this.ConvertCoordsToCursorWR(_rect1.X, _rect1.Y + _rect1.H, _rect1.Page, undefined, false);

			pos3 = this.ConvertCoordsToCursorWR(_rect2.X + _rect2.W, _rect2.Y, _rect2.Page, undefined, false);
			pos4 = this.ConvertCoordsToCursorWR(_rect2.X + _rect2.W, _rect2.Y + _rect2.H, _rect2.Page, undefined, false);

			ctx.strokeStyle = "#1B63BA";

			ctx.moveTo(pos1.X >> 0, pos1.Y >> 0);
			ctx.lineTo(pos2.X >> 0, pos2.Y >> 0);

			ctx.moveTo(pos3.X >> 0, pos3.Y >> 0);
			ctx.lineTo(pos4.X >> 0, pos4.Y >> 0);

			ctx.lineWidth = 2;
			ctx.stroke();

			/*
			 ctx.beginPath();

			 ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
			 overlay.AddEllipse(pos1.X, pos1.Y - 5, 6.5);
			 overlay.AddEllipse(pos4.X, pos4.Y + 5, 6.5);
			 ctx.fill();

			 ctx.beginPath();

			 ctx.fillStyle = "#FFFFFF";
			 overlay.AddEllipse(pos1.X, pos1.Y - 5, 6);
			 overlay.AddEllipse(pos4.X, pos4.Y + 5, 6);
			 ctx.fill();
			 */

			ctx.beginPath();

			ctx.fillStyle = "#1B63BA";
			overlay.AddEllipse(pos1.X, pos1.Y - 5, 5);
			overlay.AddEllipse(pos4.X, pos4.Y + 5, 5);
			ctx.fill();
		}
		else
		{
			var _xx11 = _matrix.TransformPointX(_rect1.X, _rect1.Y);
			var _yy11 = _matrix.TransformPointY(_rect1.X, _rect1.Y);

			var _xx12 = _matrix.TransformPointX(_rect1.X, _rect1.Y + _rect1.H);
			var _yy12 = _matrix.TransformPointY(_rect1.X, _rect1.Y + _rect1.H);

			var _xx21 = _matrix.TransformPointX(_rect2.X + _rect2.W, _rect2.Y);
			var _yy21 = _matrix.TransformPointY(_rect2.X + _rect2.W, _rect2.Y);

			var _xx22 = _matrix.TransformPointX(_rect2.X + _rect2.W, _rect2.Y + _rect2.H);
			var _yy22 = _matrix.TransformPointY(_rect2.X + _rect2.W, _rect2.Y + _rect2.H);

			pos1 = this.ConvertCoordsToCursorWR(_xx11, _yy11, _rect1.Page, undefined, false);
			pos2 = this.ConvertCoordsToCursorWR(_xx12, _yy12, _rect1.Page, undefined, false);

			pos3 = this.ConvertCoordsToCursorWR(_xx21, _yy21, _rect2.Page, undefined, false);
			pos4 = this.ConvertCoordsToCursorWR(_xx22, _yy22, _rect2.Page, undefined, false);

			ctx.strokeStyle = "#1B63BA";

			ctx.moveTo(pos1.X, pos1.Y);
			ctx.lineTo(pos2.X, pos2.Y);

			ctx.moveTo(pos3.X, pos3.Y);
			ctx.lineTo(pos4.X, pos4.Y);

			ctx.lineWidth = 2;
			ctx.stroke();

			/*
			 ctx.beginPath();

			 ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
			 overlay.AddEllipse(pos1.X, pos1.Y - 5, 6.5);
			 overlay.AddEllipse(pos4.X, pos4.Y + 5, 6.5);
			 ctx.fill();

			 ctx.beginPath();

			 ctx.fillStyle = "#FFFFFF";
			 overlay.AddEllipse(pos1.X, pos1.Y - 5, 6);
			 overlay.AddEllipse(pos4.X, pos4.Y + 5, 6);
			 ctx.fill();
			 */

			ctx.beginPath();

			ctx.fillStyle = "#1B63BA";
			overlay.AddEllipse(pos1.X, pos1.Y - 5, 5);
			overlay.AddEllipse(pos4.X, pos4.Y + 5, 5);
			ctx.fill();
		}
	}

	this.SelectShow = function ()
	{
		this.m_oWordControl.OnUpdateOverlay();
	}

	this.Set_RulerState_Start = function ()
	{
		this.UpdateRulerStateFlag = true;
	}
	this.Set_RulerState_End = function ()
	{
		if (this.UpdateRulerStateFlag)
		{
			this.UpdateRulerStateFlag = false;
			if (this.UpdateRulerStateParams.length > 0)
			{
				switch (this.UpdateRulerStateParams[0])
				{
					case 0:
					{
						this.Set_RulerState_Table(this.UpdateRulerStateParams[1],
							this.UpdateRulerStateParams[2]);
						break;
					}
					case 1:
					{
						this.Set_RulerState_Paragraph(this.UpdateRulerStateParams[1],
							this.UpdateRulerStateParams[2]);
						break;
					}
					case 2:
					{
						this.Set_RulerState_HdrFtr(this.UpdateRulerStateParams[1],
							this.UpdateRulerStateParams[2],
							this.UpdateRulerStateParams[3]);
						break;
					}
					case 3:
					{
						this.Set_RulerState_Columns(this.UpdateRulerStateParams[1]);
						break;
					}
					default:
						break;
				}

				this.UpdateRulerStateParams = [];
			}
		}
	}

	this.Set_RulerState_Table = function (markup, transform)
	{
		if (this.UpdateRulerStateFlag)
		{
			this.UpdateRulerStateParams.splice(0, this.UpdateRulerStateParams.length);
			this.UpdateRulerStateParams.push(0);
			this.UpdateRulerStateParams.push(markup);
			this.UpdateRulerStateParams.push(transform);
			return;
		}

		this.FrameRect.IsActive = false;

		var hor_ruler = this.m_oWordControl.m_oHorRuler;
		var ver_ruler = this.m_oWordControl.m_oVerRuler;

		hor_ruler.CurrentObjectType = RULER_OBJECT_TYPE_TABLE;
		hor_ruler.m_oTableMarkup = markup.CreateDublicate();

		ver_ruler.CurrentObjectType = RULER_OBJECT_TYPE_TABLE;
		ver_ruler.m_oTableMarkup = markup.CreateDublicate();

		this.TableOutlineDr.TableMatrix = null;
		this.TableOutlineDr.CurrentPageIndex = this.m_lCurrentPage;
		if (transform)
		{
			hor_ruler.m_oTableMarkup.TransformX = transform.tx;
			hor_ruler.m_oTableMarkup.TransformY = transform.ty;

			ver_ruler.m_oTableMarkup.TransformX = transform.tx;
			ver_ruler.m_oTableMarkup.TransformY = transform.ty;

			hor_ruler.m_oTableMarkup.CorrectFrom();
			ver_ruler.m_oTableMarkup.CorrectFrom();

			this.TableOutlineDr.TableMatrix = transform.CreateDublicate();
		}

		hor_ruler.CalculateMargins();

		if (0 <= this.m_lCurrentPage && this.m_lCurrentPage < this.m_lPagesCount)
		{
			hor_ruler.CreateBackground(this.m_arrPages[this.m_lCurrentPage]);
			ver_ruler.CreateBackground(this.m_arrPages[this.m_lCurrentPage]);
		}

		this.m_oWordControl.UpdateHorRuler();
		this.m_oWordControl.UpdateVerRuler();

		if (this.m_oWordControl.MobileTouchManager)
		{
			this.m_oWordControl.MobileTouchManager.TableStartTrack_Check = true;
			markup.Table.Start_TrackTable();
			this.m_oWordControl.MobileTouchManager.TableStartTrack_Check = false;
		}
	}

	this.Set_RulerState_Paragraph = function (margins, isCanTrackMargins)
	{
		if (this.UpdateRulerStateFlag)
		{
			this.UpdateRulerStateParams.splice(0, this.UpdateRulerStateParams.length);
			this.UpdateRulerStateParams.push(1);
			this.UpdateRulerStateParams.push(margins);
			this.UpdateRulerStateParams.push(isCanTrackMargins);
			return;
		}

		if (margins && margins.Frame !== undefined)
		{
			var bIsUpdate = false;

			if (!this.FrameRect.IsActive)
				bIsUpdate = true;

			if (!bIsUpdate)
			{
				if (this.FrameRect.Rect.X != margins.L ||
					this.FrameRect.Rect.Y != margins.T ||
					this.FrameRect.Rect.R != margins.R ||
					this.FrameRect.Rect.B != margins.B ||
					this.FrameRect.PageIndex != margins.PageIndex)
				{
					bIsUpdate = true;
				}
			}

			this.FrameRect.IsActive = true;
			this.FrameRect.Rect.X = margins.L;
			this.FrameRect.Rect.Y = margins.T;
			this.FrameRect.Rect.R = margins.R;
			this.FrameRect.Rect.B = margins.B;
			this.FrameRect.PageIndex = margins.PageIndex;
			this.FrameRect.Frame = margins.Frame;

			if (bIsUpdate)
			{
				if (this.m_oWordControl.m_oOverlay.HtmlElement.style.display != "block")
					this.m_oWordControl.ShowOverlay();

				this.m_oWordControl.OnUpdateOverlay();
			}
		}
		else
		{
			if (this.FrameRect.IsActive)
			{
				if (this.m_oWordControl.m_oOverlay.HtmlElement.style.display != "block")
					this.m_oWordControl.ShowOverlay();

				this.FrameRect.IsActive = false;
				this.m_oWordControl.OnUpdateOverlay();
			}
			else
				this.FrameRect.IsActive = false;
		}

		var hor_ruler = this.m_oWordControl.m_oHorRuler;
		var ver_ruler = this.m_oWordControl.m_oVerRuler;

		if (hor_ruler.CurrentObjectType == RULER_OBJECT_TYPE_PARAGRAPH && ver_ruler.CurrentObjectType == RULER_OBJECT_TYPE_PARAGRAPH)
		{
			if ((margins && !hor_ruler.IsCanMoveMargins) || (!margins && hor_ruler.IsCanMoveMargins))
			{
				var bIsNeedUpdate = false;
				if (margins && this.LastParagraphMargins)
				{
					if (margins.L != this.LastParagraphMargins.L ||
						margins.T != this.LastParagraphMargins.T ||
						margins.R != this.LastParagraphMargins.R ||
						margins.B != this.LastParagraphMargins.B)
					{
						bIsNeedUpdate = true;
					}
				}

				if (!bIsNeedUpdate)
					return;
			}
		}

		hor_ruler.CurrentObjectType = RULER_OBJECT_TYPE_PARAGRAPH;
		hor_ruler.m_oTableMarkup = null;
		hor_ruler.m_oColumnMarkup = null;

		ver_ruler.CurrentObjectType = RULER_OBJECT_TYPE_PARAGRAPH;
		ver_ruler.m_oTableMarkup = null;

		// вообще надо посмотреть... может и был параграф до этого.
		// тогда вэкграунд перерисовывать не нужно. Только надо знать, на той же странице это было или нет
		if (-1 != this.m_lCurrentPage && this.m_arrPages[this.m_lCurrentPage])
		{
			if (margins)
			{
				var cachedPage = {};
				cachedPage.width_mm = this.m_arrPages[this.m_lCurrentPage].width_mm;
				cachedPage.height_mm = this.m_arrPages[this.m_lCurrentPage].height_mm;

				cachedPage.margin_left = margins.L;
				cachedPage.margin_top = margins.T;
				cachedPage.margin_right = margins.R;
				cachedPage.margin_bottom = margins.B;

				hor_ruler.CreateBackground(cachedPage);
				ver_ruler.CreateBackground(cachedPage);

				// disable margins
				if (true !== isCanTrackMargins)
				{
					hor_ruler.IsCanMoveMargins = false;
					ver_ruler.IsCanMoveMargins = false;
				}
				else
				{
					hor_ruler.IsCanMoveMargins = true;
					ver_ruler.IsCanMoveMargins = true;
				}

				this.LastParagraphMargins = {};
				this.LastParagraphMargins.L = margins.L;
				this.LastParagraphMargins.T = margins.T;
				this.LastParagraphMargins.R = margins.R;
				this.LastParagraphMargins.B = margins.B;
			}
			else
			{
				hor_ruler.CreateBackground(this.m_arrPages[this.m_lCurrentPage]);
				ver_ruler.CreateBackground(this.m_arrPages[this.m_lCurrentPage]);

				// enable margins
				hor_ruler.IsCanMoveMargins = true;
				ver_ruler.IsCanMoveMargins = true;

				this.LastParagraphMargins = null;
			}
		}

		this.m_oWordControl.UpdateHorRuler();
		this.m_oWordControl.UpdateVerRuler();
	}

	this.Set_RulerState_Columns = function (markup)
	{
		if (this.UpdateRulerStateFlag)
		{
			this.UpdateRulerStateParams.splice(0, this.UpdateRulerStateParams.length);
			this.UpdateRulerStateParams.push(3);
			this.UpdateRulerStateParams.push(markup);
			return;
		}

		this.FrameRect.IsActive = false;

		var hor_ruler = this.m_oWordControl.m_oHorRuler;
		var ver_ruler = this.m_oWordControl.m_oVerRuler;

		hor_ruler.CurrentObjectType = RULER_OBJECT_TYPE_COLUMNS;
		hor_ruler.m_oTableMarkup = null;
		hor_ruler.m_oColumnMarkup = markup.CreateDuplicate();

		ver_ruler.CurrentObjectType = RULER_OBJECT_TYPE_PARAGRAPH;
		ver_ruler.m_oTableMarkup = null;

		this.TableOutlineDr.TableMatrix = null;
		this.TableOutlineDr.CurrentPageIndex = this.m_lCurrentPage;

		hor_ruler.CalculateMargins();

		if (0 <= this.m_lCurrentPage && this.m_lCurrentPage < this.m_lPagesCount)
		{
			hor_ruler.CreateBackground(this.m_arrPages[this.m_lCurrentPage]);
			ver_ruler.CreateBackground(this.m_arrPages[this.m_lCurrentPage]);
		}

		this.m_oWordControl.UpdateHorRuler();
		this.m_oWordControl.UpdateVerRuler();
	};

	this.Set_RulerState_HdrFtr = function (bHeader, Y0, Y1)
	{
		if (this.UpdateRulerStateFlag)
		{
			this.UpdateRulerStateParams.splice(0, this.UpdateRulerStateParams.length);
			this.UpdateRulerStateParams.push(2);
			this.UpdateRulerStateParams.push(bHeader);
			this.UpdateRulerStateParams.push(Y0);
			this.UpdateRulerStateParams.push(Y1);
			return;
		}

		this.FrameRect.IsActive = false;

		var hor_ruler = this.m_oWordControl.m_oHorRuler;
		var ver_ruler = this.m_oWordControl.m_oVerRuler;

		hor_ruler.CurrentObjectType = RULER_OBJECT_TYPE_PARAGRAPH;
		hor_ruler.m_oTableMarkup = null;
		hor_ruler.m_oColumnMarkup = null;

		ver_ruler.CurrentObjectType = (true === bHeader) ? RULER_OBJECT_TYPE_HEADER : RULER_OBJECT_TYPE_FOOTER;
		ver_ruler.header_top = Y0;
		ver_ruler.header_bottom = Y1;
		ver_ruler.m_oTableMarkup = null;

		// вообще надо посмотреть... может и бал параграф до этого.
		// тогда вэкграунд перерисовывать не нужно. Только надо знать, на той же странице это было или нет
		if (-1 != this.m_lCurrentPage)
		{
			hor_ruler.CreateBackground(this.m_arrPages[this.m_lCurrentPage]);
			ver_ruler.CreateBackground(this.m_arrPages[this.m_lCurrentPage]);
		}

		this.m_oWordControl.UpdateHorRuler();
		this.m_oWordControl.UpdateVerRuler();
	}

	this.Update_MathTrack = function (IsActive, IsContentActive, oMath)
	{
		this.MathRect.IsActive = IsActive;

		if (true === IsActive && null !== oMath)
		{
			var selectBounds = true === IsContentActive ? oMath.Get_ContentSelection() : null;
			if (selectBounds != null)
			{
				var SelectPolygon = new CPolygon();
				SelectPolygon.fill(selectBounds);
				this.MathSelectPolygons = SelectPolygon.GetPaths(0);
			}
			else
			{
				this.MathSelectPolygons.length = 0;
			}

			var arrBounds = oMath.Get_Bounds();

			if (arrBounds.length <= 0)
				return;

			var MPolygon = new CPolygon();
			MPolygon.fill(arrBounds);

			var PixelError = this.GetMMPerDot(1) * 3;
			this.MathPolygons = MPolygon.GetPaths(PixelError);
		}
	};

	this.Update_FieldTrack = function (IsActive, aRects)
	{
		this.FieldTrack.IsActive = IsActive;

		if (true === IsActive)
			this.FieldTrack.Rects = aRects;
		else
			this.FieldTrack.Rects = [];
	};

	this.Update_ParaTab = function (Default_Tab, ParaTabs)
	{
		var hor_ruler = this.m_oWordControl.m_oHorRuler;

		var __tabs = ParaTabs.Tabs;
		if (undefined === __tabs)
			__tabs = ParaTabs;

		var _len = __tabs.length;
		if ((Default_Tab == hor_ruler.m_dDefaultTab) && (hor_ruler.m_arrTabs.length == _len) && (_len == 0))
		{
			// потом можно и проверить сами табы
			return;
		}

		hor_ruler.m_dDefaultTab = Default_Tab;
		hor_ruler.m_arrTabs = [];
		var _ar = hor_ruler.m_arrTabs;

		for (var i = 0; i < _len; i++)
		{
			if (__tabs[i].Value == tab_Left)
				_ar[i] = new CTab(__tabs[i].Pos, AscCommon.g_tabtype_left, __tabs[i].Leader);
			else if (__tabs[i].Value == tab_Center)
				_ar[i] = new CTab(__tabs[i].Pos, AscCommon.g_tabtype_center, __tabs[i].Leader);
			else if (__tabs[i].Value == tab_Right)
				_ar[i] = new CTab(__tabs[i].Pos, AscCommon.g_tabtype_right, __tabs[i].Leader);
			else
			{
				// не должно такого быть. но приходит
				_ar[i] = new CTab(__tabs[i].Pos, AscCommon.g_tabtype_left, __tabs[i].Leader);
			}
		}

		hor_ruler.CorrectTabs();
		this.m_oWordControl.UpdateHorRuler();
	}

	this.CorrectRulerPosition = function (pos)
	{
		if (AscCommon.global_keyboardEvent.AltKey)
			return pos;

		return ((pos / 2.5 + 0.5) >> 0) * 2.5;
	}

	this.UpdateTableRuler = function (isCols, index, position)
	{
		var dKoef_mm_to_pix = g_dKoef_mm_to_pix * this.m_oWordControl.m_nZoomValue / 100;
		if (false === isCols)
		{
			var markup = this.m_oWordControl.m_oVerRuler.m_oTableMarkup;
			if (markup == null)
				return;

			position += markup.TransformY;
			if (0 == index)
			{
				var delta = position - markup.Rows[0].Y;
				markup.Rows[0].Y = position;
				markup.Rows[0].H -= delta;
			}
			else
			{
				var delta = (markup.Rows[index - 1].Y + markup.Rows[index - 1].H) - position;

				markup.Rows[index - 1].H -= delta;

				if (index != markup.Rows.length)
				{
					markup.Rows[index].Y -= delta;
					markup.Rows[index].H += delta;
				}
			}

			if ("none" == this.m_oWordControl.m_oOverlay.HtmlElement.style.display)
				this.m_oWordControl.ShowOverlay();

			this.m_oWordControl.UpdateVerRulerBack();
			this.m_oWordControl.m_oOverlayApi.HorLine(this.m_arrPages[this.m_lCurrentPage].drawingPage.top + position * dKoef_mm_to_pix);
		}
		else
		{
			var markup = this.m_oWordControl.m_oHorRuler.m_oTableMarkup;
			if (markup == null)
				return;

			position += markup.TransformX;

			if (0 == index)
			{
				var _add = markup.X - position;
				markup.X = position;
				if (markup.Cols.length > 0)
					markup.Cols[0] += _add;
			}
			else
			{
				var _start = markup.X;
				for (var i = 0; i < (index - 1); i++)
				{
					_start += markup.Cols[i];
				}

				var _old = markup.Cols[index - 1];
				markup.Cols[index - 1] = position - _start;

				if (index != markup.Cols.length)
				{
					markup.Cols[index] += (_old - markup.Cols[index - 1]);
				}
			}

			if ("none" == this.m_oWordControl.m_oOverlay.HtmlElement.style.display)
				this.m_oWordControl.ShowOverlay();

			this.m_oWordControl.UpdateHorRulerBack();
			this.m_oWordControl.m_oOverlayApi.VertLine(this.m_arrPages[this.m_lCurrentPage].drawingPage.left + position * dKoef_mm_to_pix);
		}
	}
	this.GetDotsPerMM = function (value)
	{
		return value * this.m_oWordControl.m_nZoomValue * g_dKoef_mm_to_pix / 100;
	}

	this.GetMMPerDot = function (value)
	{
		return value / this.GetDotsPerMM(1);
	}
	this.GetVisibleMMHeight = function ()
	{
		var pixHeigth = this.m_oWordControl.m_oEditor.HtmlElement.height;
		if (this.m_oWordControl.bIsRetinaSupport)
			pixHeigth /= AscCommon.AscBrowser.retinaPixelRatio;
		var pixBetweenPages = 20 * (this.m_lDrawingEnd - this.m_lDrawingFirst);

		return (pixHeigth - pixBetweenPages) * g_dKoef_pix_to_mm * 100 / this.m_oWordControl.m_nZoomValue;
	}

	// вот оооочень важная функция. она выкидывает из кэша неиспользуемые шрифты
	this.CheckFontCache = function ()
	{
		var map_used = this.m_oWordControl.m_oLogicDocument.Document_CreateFontMap();

		var _measure_map = g_oTextMeasurer.m_oManager.m_oFontsCache.Fonts;
		var _drawing_map = AscCommon.g_fontManager.m_oFontsCache.Fonts;

		var map_keys = {};
		var api = this.m_oWordControl.m_oApi;
		for (var i in map_used)
		{
			var key = AscFonts.GenerateMapId(api, g_fontApplication.GetFontInfoName(map_used[i].Name), map_used[i].Style, map_used[i].Size);
			map_keys[key] = true;
		}

		// а теперь просто пробегаем по кэшам и удаляем ненужное
		for (var i in _measure_map)
		{
			if (map_keys[i] == undefined)
			{
				//_measure_map[i] = undefined;
				delete _measure_map[i];
			}
		}
		for (var i in _drawing_map)
		{
			if (map_keys[i] == undefined)
			{
				//_drawing_map[i] = undefined;
				if (null != _drawing_map[i])
					_drawing_map[i].Destroy();
				delete _drawing_map[i];
			}
		}
	}

	// при загрузке документа - нужно понять какие шрифты используются
	this.CheckFontNeeds = function ()
	{
		var map_keys = this.m_oWordControl.m_oLogicDocument.Document_Get_AllFontNames();
		var dstfonts = [];
		for (var i in map_keys)
		{
			dstfonts[dstfonts.length] = new AscFonts.CFont(i, 0, "", 0, null);
		}
        AscFonts.FontPickerByCharacter.extendFonts(dstfonts);
		this.m_oWordControl.m_oLogicDocument.Fonts = dstfonts;
		return;

		/*
		 var map_used = this.m_oWordControl.m_oLogicDocument.Document_CreateFontMap();

		 var map_keys = {};
		 for (var i in map_used)
		 {
		 var search = map_used[i];
		 var found = map_keys[search.Name];

		 var _need_style = 0;
		 switch (search.Style)
		 {
		 case FontStyle.FontStyleRegular:
		 {
		 _need_style = fontstyle_mask_regular;
		 break;
		 }
		 case FontStyle.FontStyleBold:
		 {
		 _need_style = fontstyle_mask_bold;
		 break;
		 }
		 case FontStyle.FontStyleItalic:
		 {
		 _need_style = fontstyle_mask_italic;
		 break;
		 }
		 case FontStyle.FontStyleBoldItalic:
		 {
		 _need_style = fontstyle_mask_bolditalic;
		 break;
		 }
		 default:
		 {
		 _need_style = fontstyle_mask_regular | fontstyle_mask_italic | fontstyle_mask_bold | fontstyle_mask_bolditalic;
		 break;
		 }
		 }

		 if (undefined === found)
		 {
		 map_keys[search.Name] = _need_style;
		 }
		 else
		 {
		 map_keys[search.Name] |= _need_style;
		 }
		 }

		 // теперь просто пробегаем и заполняем все объектами
		 var dstfonts = [];
		 for (var i in map_keys)
		 {
		 dstfonts[dstfonts.length] = new CFont(i, 0, "", 0, map_keys[i]);
		 }
		 this.m_oWordControl.m_oLogicDocument.Fonts = dstfonts;
		 */
	}

	// фукнции для старта работы
	this.OpenDocument = function ()
	{
		//SetHintsProps(false, false);
		this.m_oDocumentRenderer.InitDocument(this);

		this.m_oWordControl.CalculateDocumentSize();
		this.m_oWordControl.OnScroll();
	}

	// вот здесь весь трекинг
	this.DrawTrack = function (type, matrix, left, top, width, height, isLine, canRotate, isNoMove)
	{
		this.AutoShapesTrack.DrawTrack(type, matrix, left, top, width, height, isLine, canRotate, isNoMove);
	}

	this.DrawTrackSelectShapes = function (x, y, w, h)
	{
		this.AutoShapesTrack.DrawTrackSelectShapes(x, y, w, h);
	}

	this.DrawAdjustment = function (matrix, x, y, bTextWarp)
	{
		this.AutoShapesTrack.DrawAdjustment(matrix, x, y, bTextWarp);
	}

	this.LockTrackPageNum = function (nPageNum)
	{
		this.AutoShapesTrackLockPageNum = nPageNum;
	}
	this.UnlockTrackPageNum = function ()
	{
		this.AutoShapesTrackLockPageNum = -1;
	}

	this.CheckGuiControlColors = function ()
	{
		// потом реализовать проверку на то, что нужно ли посылать
		var _theme = this.m_oWordControl.m_oLogicDocument.theme;
		var _clrMap = this.m_oWordControl.m_oLogicDocument.clrSchemeMap.color_map;

		var arr_colors = new Array(10);
		var rgba = {R: 0, G: 0, B: 0, A: 255};
		// bg1,tx1,bg2,tx2,accent1 - accent6
		var array_colors_types = [6, 15, 7, 16, 0, 1, 2, 3, 4, 5];
		var _count = array_colors_types.length;

		var color = new AscFormat.CUniColor();
		color.color = new AscFormat.CSchemeColor();
		for (var i = 0; i < _count; ++i)
		{
			color.color.id = array_colors_types[i];
			color.Calculate(_theme, _clrMap, rgba);

			var _rgba = color.RGBA;
			arr_colors[i] = new CColor(_rgba.R, _rgba.G, _rgba.B);
		}

		// теперь проверим
		var bIsSend = false;
		if (this.GuiControlColorsMap != null)
		{
			for (var i = 0; i < _count; ++i)
			{
				var _color1 = this.GuiControlColorsMap[i];
				var _color2 = arr_colors[i];

				if ((_color1.r != _color2.r) || (_color1.g != _color2.g) || (_color1.b != _color2.b))
				{
					bIsSend = true;
					break;
				}
			}
		}
		else
		{
			this.GuiControlColorsMap = new Array(_count);
			bIsSend = true;
		}

		if (bIsSend)
		{
			for (var i = 0; i < _count; ++i)
			{
				this.GuiControlColorsMap[i] = arr_colors[i];
			}

			this.SendControlColors();
		}
	}

	this.SendControlColors = function ()
	{
		var standart_colors = null;
		if (!this.IsSendStandartColors)
		{
			var standartColors = AscCommon.g_oStandartColors;
			var _c_s = standartColors.length;
			standart_colors = new Array(_c_s);

			for (var i = 0; i < _c_s; ++i)
			{
				standart_colors[i] = new CColor(standartColors[i].R, standartColors[i].G, standartColors[i].B);
			}

			this.IsSendStandartColors = true;
		}

		var _count = this.GuiControlColorsMap.length;

		var _ret_array = new Array(_count * 6);
		var _cur_index = 0;

		for (var i = 0; i < _count; ++i)
		{
			var _color_src = this.GuiControlColorsMap[i];

			_ret_array[_cur_index] = new CColor(_color_src.r, _color_src.g, _color_src.b);
			_cur_index++;

			// теперь с модификаторами
			var _count_mods = 5;
			for (var j = 0; j < _count_mods; ++j)
			{
				var dst_mods = new AscFormat.CColorModifiers();
				dst_mods.Mods = AscCommon.GetDefaultMods(_color_src.r, _color_src.g, _color_src.b, j + 1, 1);

				var _rgba = {R: _color_src.r, G: _color_src.g, B: _color_src.b, A: 255};
				dst_mods.Apply(_rgba);

				_ret_array[_cur_index] = new CColor(_rgba.R, _rgba.G, _rgba.B);
				_cur_index++;
			}
		}

		this.m_oWordControl.m_oApi.sync_SendThemeColors(_ret_array, standart_colors);

		// regenerate styles
		if (null == this.m_oWordControl.m_oApi._gui_styles)
		{
			if (window["NATIVE_EDITOR_ENJINE"] === true)
			{
				if (!this.m_oWordControl.m_oApi.asc_checkNeedCallback("asc_onInitEditorStyles"))
					return;
			}
			var StylesPainter = new CStylesPainter();
			StylesPainter.GenerateStyles(this.m_oWordControl.m_oApi, this.m_oWordControl.m_oLogicDocument.Get_Styles().Style);
		}
	}

	this.DrawImageTextureFillShape = function (url)
	{
		if (this.GuiCanvasFillTexture == null)
		{
			this.InitGuiCanvasShape(this.GuiCanvasFillTextureParentId);
		}

		if (this.GuiCanvasFillTexture == null || this.GuiCanvasFillTextureCtx == null || url == this.LastDrawingUrl)
			return;

		this.LastDrawingUrl = url;
		var _width = this.GuiCanvasFillTexture.width;
		var _height = this.GuiCanvasFillTexture.height;

		this.GuiCanvasFillTextureCtx.clearRect(0, 0, _width, _height);

		if (null == this.LastDrawingUrl)
			return;

		var _img = this.m_oWordControl.m_oApi.ImageLoader.map_image_index[AscCommon.getFullImageSrc2(this.LastDrawingUrl)];
		if (_img != undefined && _img.Image != null && _img.Status != AscFonts.ImageLoadStatus.Loading)
		{
			var _x = 0;
			var _y = 0;
			var _w = Math.max(_img.Image.width, 1);
			var _h = Math.max(_img.Image.height, 1);

			var dAspect1 = _width / _height;
			var dAspect2 = _w / _h;

			_w = _width;
			_h = _height;
			if (dAspect1 >= dAspect2)
			{
				_w = dAspect2 * _height;
				_x = (_width - _w) / 2;
			}
			else
			{
				_h = _w / dAspect2;
				_y = (_height - _h) / 2;
			}

			this.GuiCanvasFillTextureCtx.drawImage(_img.Image, _x, _y, _w, _h);
		}
		else if (!_img || !_img.Image)
		{
			this.GuiCanvasFillTextureCtx.lineWidth = 1;

			this.GuiCanvasFillTextureCtx.beginPath();
			this.GuiCanvasFillTextureCtx.moveTo(0, 0);
			this.GuiCanvasFillTextureCtx.lineTo(_width, _height);
			this.GuiCanvasFillTextureCtx.moveTo(_width, 0);
			this.GuiCanvasFillTextureCtx.lineTo(0, _height);
			this.GuiCanvasFillTextureCtx.strokeStyle = "#FF0000";
			this.GuiCanvasFillTextureCtx.stroke();

			this.GuiCanvasFillTextureCtx.beginPath();
			this.GuiCanvasFillTextureCtx.moveTo(0, 0);
			this.GuiCanvasFillTextureCtx.lineTo(_width, 0);
			this.GuiCanvasFillTextureCtx.lineTo(_width, _height);
			this.GuiCanvasFillTextureCtx.lineTo(0, _height);
			this.GuiCanvasFillTextureCtx.closePath();

			this.GuiCanvasFillTextureCtx.strokeStyle = "#000000";
			this.GuiCanvasFillTextureCtx.stroke();
			this.GuiCanvasFillTextureCtx.beginPath();
		}
	}

	this.InitGuiCanvasShape = function (div_id)
	{
		if (null != this.GuiCanvasFillTexture)
		{
			var _div_elem = document.getElementById(this.GuiCanvasFillTextureParentId);
			if (_div_elem)
				_div_elem.removeChild(this.GuiCanvasFillTexture);

			this.GuiCanvasFillTexture = null;
			this.GuiCanvasFillTextureCtx = null;
		}

		this.GuiCanvasFillTextureParentId = div_id;
		var _div_elem = document.getElementById(this.GuiCanvasFillTextureParentId);
		if (!_div_elem)
			return;

		this.GuiCanvasFillTexture = document.createElement('canvas');
		this.GuiCanvasFillTexture.width = parseInt(_div_elem.style.width);
		this.GuiCanvasFillTexture.height = parseInt(_div_elem.style.height);

		this.LastDrawingUrl = "";
		this.GuiCanvasFillTextureCtx = this.GuiCanvasFillTexture.getContext('2d');

		_div_elem.appendChild(this.GuiCanvasFillTexture);
	}

	this.InitGuiCanvasTextProps = function (div_id)
	{
		var _div_elem = document.getElementById(div_id);
		if (null != this.GuiCanvasTextProps)
		{
			var elem = _div_elem.getElementsByTagName('canvas');
			if (elem.length == 0)
			{
				_div_elem.appendChild(this.GuiCanvasTextProps);
			}
			else
			{
				var _width = parseInt(_div_elem.offsetWidth);
				var _height = parseInt(_div_elem.offsetHeight);
				if (0 == _width)
					_width = 300;
				if (0 == _height)
					_height = 80;

				if (this.GuiCanvasTextProps.width != _width || this.GuiCanvasTextProps.height != _height)
				{
					this.GuiCanvasTextProps.width = _width;
					this.GuiCanvasTextProps.height = _height;
				}
			}
		}
		else
		{
			this.GuiCanvasTextProps = document.createElement('canvas');
			this.GuiCanvasTextProps.style.position = "absolute";
			this.GuiCanvasTextProps.style.left = "0px";
			this.GuiCanvasTextProps.style.top = "0px";

			var _width = parseInt(_div_elem.offsetWidth);
			var _height = parseInt(_div_elem.offsetHeight);
			if (0 == _width)
				_width = 300;
			if (0 == _height)
				_height = 80;

			this.GuiCanvasTextProps.width = _width;
			this.GuiCanvasTextProps.height = _height;

			_div_elem.appendChild(this.GuiCanvasTextProps);
		}
	}

	this.DrawGuiCanvasTextProps = function (props)
	{
		var bIsChange = false;
		if (null == this.GuiLastTextProps)
		{
			bIsChange = true;

			this.GuiLastTextProps = new Asc.asc_CParagraphProperty();

			this.GuiLastTextProps.Subscript = props.Subscript;
			this.GuiLastTextProps.Superscript = props.Superscript;
			this.GuiLastTextProps.SmallCaps = props.SmallCaps;
			this.GuiLastTextProps.AllCaps = props.AllCaps;
			this.GuiLastTextProps.Strikeout = props.Strikeout;
			this.GuiLastTextProps.DStrikeout = props.DStrikeout;

			this.GuiLastTextProps.TextSpacing = props.TextSpacing;
			this.GuiLastTextProps.Position = props.Position;
		}
		else
		{
			if (this.GuiLastTextProps.Subscript != props.Subscript)
			{
				this.GuiLastTextProps.Subscript = props.Subscript;
				bIsChange = true;
			}
			if (this.GuiLastTextProps.Superscript != props.Superscript)
			{
				this.GuiLastTextProps.Superscript = props.Superscript;
				bIsChange = true;
			}
			if (this.GuiLastTextProps.SmallCaps != props.SmallCaps)
			{
				this.GuiLastTextProps.SmallCaps = props.SmallCaps;
				bIsChange = true;
			}
			if (this.GuiLastTextProps.AllCaps != props.AllCaps)
			{
				this.GuiLastTextProps.AllCaps = props.AllCaps;
				bIsChange = true;
			}
			if (this.GuiLastTextProps.Strikeout != props.Strikeout)
			{
				this.GuiLastTextProps.Strikeout = props.Strikeout;
				bIsChange = true;
			}
			if (this.GuiLastTextProps.DStrikeout != props.DStrikeout)
			{
				this.GuiLastTextProps.DStrikeout = props.DStrikeout;
				bIsChange = true;
			}
			if (this.GuiLastTextProps.TextSpacing != props.TextSpacing)
			{
				this.GuiLastTextProps.TextSpacing = props.TextSpacing;
				bIsChange = true;
			}
			if (this.GuiLastTextProps.Position != props.Position)
			{
				this.GuiLastTextProps.Position = props.Position;
				bIsChange = true;
			}
		}

		if (undefined !== this.GuiLastTextProps.Position && isNaN(this.GuiLastTextProps.Position))
			this.GuiLastTextProps.Position = undefined;
		if (undefined !== this.GuiLastTextProps.TextSpacing && isNaN(this.GuiLastTextProps.TextSpacing))
			this.GuiLastTextProps.TextSpacing = undefined;

		if (!bIsChange)
			return;

		History.TurnOff();
		var _oldTurn = editor.isViewMode;
		editor.isViewMode = true;

		var par = new Paragraph(this, this.m_oWordControl.m_oLogicDocument);

		par.MoveCursorToStartPos();

		var _paraPr = new CParaPr();
		par.Pr = _paraPr;
		var _textPr = new CTextPr();
		_textPr.FontFamily = {Name: "Arial", Index: -1};

		_textPr.Strikeout = this.GuiLastTextProps.Strikeout;

		if (true === this.GuiLastTextProps.Subscript)
			_textPr.VertAlign = AscCommon.vertalign_SubScript;
		else if (true === this.GuiLastTextProps.Superscript)
			_textPr.VertAlign = AscCommon.vertalign_SuperScript;
		else
			_textPr.VertAlign = AscCommon.vertalign_Baseline;

		_textPr.DStrikeout = this.GuiLastTextProps.DStrikeout;
		_textPr.Caps = this.GuiLastTextProps.AllCaps;
		_textPr.SmallCaps = this.GuiLastTextProps.SmallCaps;

		_textPr.Spacing = this.GuiLastTextProps.TextSpacing;
		_textPr.Position = this.GuiLastTextProps.Position;

		var parRun = new ParaRun(par);
		parRun.Set_Pr(_textPr);
		parRun.AddText("Hello World");
		par.AddToContent(0, parRun);

		par.Reset(0, 0, 1000, 1000, 0, 0, 1);
		par.Recalculate_Page(0);

		var baseLineOffset = par.Lines[0].Y;
		var _bounds = par.Get_PageBounds(0);

		var ctx = this.GuiCanvasTextProps.getContext('2d');
		var _wPx = this.GuiCanvasTextProps.width;
		var _hPx = this.GuiCanvasTextProps.height;

		var _wMm = _wPx * g_dKoef_pix_to_mm;
		var _hMm = _hPx * g_dKoef_pix_to_mm;

		ctx.fillStyle = "#FFFFFF";
		ctx.fillRect(0, 0, _wPx, _hPx);

		var _pxBoundsW = par.Lines[0].Ranges[0].W * g_dKoef_mm_to_pix;//(_bounds.Right - _bounds.Left) * g_dKoef_mm_to_pix;
		var _pxBoundsH = (_bounds.Bottom - _bounds.Top) * g_dKoef_mm_to_pix;

		if (this.GuiLastTextProps.Position !== undefined && this.GuiLastTextProps.Position != null && this.GuiLastTextProps.Position != 0)
		{
			// TODO: нужна высота без учета Position
			// _pxBoundsH -= (this.GuiLastTextProps.Position * g_dKoef_mm_to_pix);
		}

		if (_pxBoundsH < _hPx && _pxBoundsW < _wPx)
		{
			// рисуем линию
			var _lineY = (((_hPx + _pxBoundsH) / 2) >> 0) + 0.5;
			var _lineW = (((_wPx - _pxBoundsW) / 4) >> 0);

			ctx.strokeStyle = "#000000";
			ctx.lineWidth = 1;

			ctx.beginPath();
			ctx.moveTo(0, _lineY);
			ctx.lineTo(_lineW, _lineY);

			ctx.moveTo(_wPx - _lineW, _lineY);
			ctx.lineTo(_wPx, _lineY);

			ctx.stroke();
			ctx.beginPath();
		}

		var _yOffset = (((_hPx + _pxBoundsH) / 2) - baseLineOffset * g_dKoef_mm_to_pix) >> 0;
		var _xOffset = ((_wPx - _pxBoundsW) / 2) >> 0;

		var graphics = new AscCommon.CGraphics();
		graphics.init(ctx, _wPx, _hPx, _wMm, _hMm);
		graphics.m_oFontManager = AscCommon.g_fontManager;

		graphics.m_oCoordTransform.tx = _xOffset;
		graphics.m_oCoordTransform.ty = _yOffset;

		graphics.transform(1, 0, 0, 1, 0, 0);

		var old_marks = this.m_oWordControl.m_oApi.ShowParaMarks;
		this.m_oWordControl.m_oApi.ShowParaMarks = false;
		par.Draw(0, graphics);
		this.m_oWordControl.m_oApi.ShowParaMarks = old_marks;

		History.TurnOn();
		editor.isViewMode = _oldTurn;
	}

	this.SetDrawImagePlaceContents = function(id, props)
	{
		var _div_elem = null;

		if (null == id || "" == id)
		{
			if ("" != this.GuiCanvasFillTOCParentId)
			{
				_div_elem = document.getElementById(this.GuiCanvasFillTOCParentId);

				if (this.GuiCanvasFillTOC && _div_elem)
					_div_elem.removeChild(this.GuiCanvasFillTOC);

				this.GuiCanvasFillTOCParentId = "";
				this.GuiCanvasFillTOC = null;
			}
			return;
		}

		if (id != this.GuiCanvasFillTOCParentId)
		{
			_div_elem = document.getElementById(this.GuiCanvasFillTOCParentId);

			if (this.GuiCanvasFillTOC && _div_elem)
				_div_elem.removeChild(this.GuiCanvasFillTOC);

			this.GuiCanvasFillTOCParentId = "";
			this.GuiCanvasFillTOC = null;
		}

		this.GuiCanvasFillTOCParentId = id;
		_div_elem =  document.getElementById(this.GuiCanvasFillTOCParentId);
		if (!_div_elem)
			return;

		var widthPx = _div_elem.offsetWidth;
		var heightPx = _div_elem.offsetHeight;

		if (null == this.GuiCanvasFillTOC)
		{
			this.GuiCanvasFillTexture = null;
			this.GuiCanvasFillTextureCtx = null;

			this.GuiCanvasFillTOC = document.createElement('canvas');
			_div_elem.appendChild(this.GuiCanvasFillTOC);
		}

		// draw!
		var wPx = AscBrowser.convertToRetinaValue(widthPx, true);
		var hPx = AscBrowser.convertToRetinaValue(heightPx, true);
		var wMm = wPx * g_dKoef_pix_to_mm / AscCommon.AscBrowser.retinaPixelRatio;
		var hMm = hPx * g_dKoef_pix_to_mm / AscCommon.AscBrowser.retinaPixelRatio;

		var wPxOffset = AscBrowser.convertToRetinaValue(8, true);
		var wMmOffset = wPxOffset * g_dKoef_pix_to_mm / AscCommon.AscBrowser.retinaPixelRatio;

		this.GuiCanvasFillTOC.style.width = widthPx + "px";
		this.GuiCanvasFillTOC.width = wPx;

		History.TurnOff();
		var _oldTurn = editor.isViewMode;
		editor.isViewMode = true;

		var ctx = this.GuiCanvasFillTOC.getContext('2d');

		var old_marks = this.m_oWordControl.m_oApi.ShowParaMarks;
		this.m_oWordControl.m_oApi.ShowParaMarks = false;

		// content
		var oLogicDocument = this.m_oWordControl.m_oLogicDocument;
		var oStyles        = oLogicDocument.GetStyles();

		var oHeader          = new CHeaderFooter(oLogicDocument.HdrFtr, oLogicDocument, this, AscCommon.hdrftr_Header);
		var oDocumentContent = oHeader.GetContent();

		var nOutlineStart = props.get_OutlineStart();
		var nOutlineEnd   = props.get_OutlineEnd();
		var nStylesType   = props.get_StylesType();
		var isShowPageNum = props.get_ShowPageNumbers();
		var isRightTab    = props.get_RightAlignTab();
		var nTabLeader    = props.get_TabLeader();

		if (undefined === nTabLeader || null === nTabLeader)
			nTabLeader = Asc.c_oAscTabLeader.Dot;

		var arrLevels         = [];
		var arrStylesToDelete = [];

		for (var nIndex = 0, nCount = props.get_StylesCount(); nIndex < nCount; ++nIndex)
		{
			var nLvl  = props.get_StyleLevel(nIndex) - 1;
			var sName = props.get_StyleName(nIndex);

			if (!arrLevels[nLvl])
			{
				var sStyleId = null;
				if (Asc.c_oAscTOCStylesType.Current === nStylesType)
				{
					sStyleId = oStyles.GetDefaultTOC(nLvl);
				}
				else
				{
					var oStyle = new CStyle("", null, null, styletype_Paragraph, true);
					oStyle.CreateTOC(nLvl, nStylesType);
					sStyleId = oStyle.GetId();
					oStyles.Add(oStyle);
					arrStylesToDelete.push(oStyle.GetId());
				}

				arrLevels[nLvl] = {
					Styles  : [],
					StyleId : sStyleId
				};
			}

			var isAddStyle = true;
			for (var nIndex = 0, nCount = arrLevels[nLvl].Styles.length; nIndex < nCount; ++nIndex)
			{
				if (arrLevels[nLvl].Styles[nIndex] === sName)
				{
					isAddStyle = false;
					break;
				}
			}

			if (isAddStyle)
				arrLevels[nLvl].Styles.push(sName);
		}

		for (var _nLvl = nOutlineStart; _nLvl <= nOutlineEnd; ++_nLvl)
		{
			var sName = "Heading " + _nLvl;
			var nLvl  = _nLvl - 1;

			if (!arrLevels[nLvl])
			{
				var sStyleId = null;
				if (Asc.c_oAscTOCStylesType.Current === nStylesType)
				{
					sStyleId = oStyles.GetDefaultTOC(nLvl);
				}
				else
				{
					var oStyle = new CStyle("", null, null, styletype_Paragraph, true);
					oStyle.CreateTOC(nLvl, nStylesType);
					sStyleId = oStyle.GetId();
					oStyles.Add(oStyle);
					arrStylesToDelete.push(oStyle.GetId());
				}

				arrLevels[nLvl] = {
					Styles  : [],
					StyleId : sStyleId
				};
			}

			var isAddStyle = true;
			for (var nIndex = 0, nCount = arrLevels[nLvl].Styles.length; nIndex < nCount; ++nIndex)
			{
				if (arrLevels[nLvl].Styles[nIndex] === sName)
				{
					isAddStyle = false;
					break;
				}
			}

			if (isAddStyle)
				arrLevels[nLvl].Styles.push(sName);
		}

		var oParaIndex = 0;
		var nPageIndex = 1;


		for (var nLvl = 0; nLvl <= 8; ++nLvl)
		{
			if (!arrLevels[nLvl])
				continue;

			var sStyleId = arrLevels[nLvl].StyleId;
			for (var nIndex = 0, nCount = arrLevels[nLvl].Styles.length; nIndex < nCount; ++nIndex)
			{
				var sStyleName = AscCommon.translateManager.getValue(arrLevels[nLvl].Styles[nIndex]);

				var oParagraph = new Paragraph(this, oDocumentContent, false);
				oDocumentContent.AddToContent(oParaIndex++, oParagraph);
				oParagraph.SetParagraphStyleById(sStyleId);

				var oRun = new ParaRun(oParagraph, false);
				oParagraph.AddToContent(0, oRun);
				oRun.AddText(sStyleName);

				if (isShowPageNum)
				{
					if (isRightTab)
					{
						var oParaTabs = new CParaTabs();
						oParaTabs.Add(new CParaTab(tab_Right, wMm - 2 - wMmOffset, nTabLeader));
						oParagraph.SetParagraphTabs(oParaTabs);

						oRun.AddToContent(-1, new ParaTab());
					}
					else
					{
						oRun.AddToContent(-1, new ParaSpace());
					}

					oRun.AddText("" + nPageIndex);

					nPageIndex += 2;
				}
			}
		}

		oDocumentContent.Reset(1, 0, 1000, 10000);
		oDocumentContent.Recalculate_Page(0, true);

		for (var nIndex = 0, nCount = arrStylesToDelete.length; nIndex < nCount; ++nIndex)
		{
			oStyles.Remove(arrStylesToDelete[nIndex]);
		}

		var nContentHeight = oDocumentContent.GetSummaryHeight();
		var nContentHeightPx = (AscCommon.AscBrowser.retinaPixelRatio * nContentHeight / g_dKoef_pix_to_mm) >> 0;

		if (nContentHeightPx > hPx)
		{
			hPx = nContentHeightPx;
			hMm = nContentHeight;
		}

		this.GuiCanvasFillTOC.style.height = AscBrowser.convertToRetinaValue(hPx, false) + "px";
		this.GuiCanvasFillTOC.height = hPx;

		var ctx = this.GuiCanvasFillTOC.getContext('2d');

		ctx.fillStyle = "#FFFFFF";
		ctx.fillRect(0, 0, wPx, hPx);

		var graphics = new AscCommon.CGraphics();
		graphics.init(ctx, wPx, hPx, wMm, hMm);
		graphics.m_oFontManager = AscCommon.g_fontManager;
		graphics.m_oCoordTransform.tx = graphics.m_oCoordTransform.ty = wPxOffset;
		graphics.transform(1, 0, 0, 1, 0, 0);
		oDocumentContent.Draw(0, graphics);

		this.m_oWordControl.m_oApi.ShowParaMarks = old_marks;

		History.TurnOn();
		editor.isViewMode = _oldTurn;
	}

	this.StartTableStylesCheck = function ()
	{
		this.TableStylesCheckLookFlag = true;
	}

	this.EndTableStylesCheck = function ()
	{
		this.TableStylesCheckLookFlag = false;
		if (this.TableStylesCheckLook != null)
		{
			this.CheckTableStyles(this.TableStylesCheckLook);
			this.TableStylesCheckLook = null;
		}
	}

	this.CheckTableStyles = function (tableLook)
	{
		if (this.TableStylesCheckLookFlag)
		{
			this.TableStylesCheckLook = tableLook;
			return;
		}

		// сначала проверим, подписан ли кто на этот евент
		// а то во вьюере не стоит ничего посылать
		if (!this.m_oWordControl.m_oApi.asc_checkNeedCallback("asc_onInitTableTemplates"))
			return;

		var bIsChanged = false;
		if (null == this.TableStylesLastLook)
		{
			this.TableStylesLastLook = new Asc.CTablePropLook();

			this.TableStylesLastLook.FirstCol = tableLook.FirstCol;
			this.TableStylesLastLook.FirstRow = tableLook.FirstRow;
			this.TableStylesLastLook.LastCol = tableLook.LastCol;
			this.TableStylesLastLook.LastRow = tableLook.LastRow;
			this.TableStylesLastLook.BandHor = tableLook.BandHor;
			this.TableStylesLastLook.BandVer = tableLook.BandVer;
			bIsChanged = true;
		}
		else
		{
			if (this.TableStylesLastLook.FirstCol != tableLook.FirstCol)
			{
				this.TableStylesLastLook.FirstCol = tableLook.FirstCol;
				bIsChanged = true;
			}
			if (this.TableStylesLastLook.FirstRow != tableLook.FirstRow)
			{
				this.TableStylesLastLook.FirstRow = tableLook.FirstRow;
				bIsChanged = true;
			}
			if (this.TableStylesLastLook.LastCol != tableLook.LastCol)
			{
				this.TableStylesLastLook.LastCol = tableLook.LastCol;
				bIsChanged = true;
			}
			if (this.TableStylesLastLook.LastRow != tableLook.LastRow)
			{
				this.TableStylesLastLook.LastRow = tableLook.LastRow;
				bIsChanged = true;
			}
			if (this.TableStylesLastLook.BandHor != tableLook.BandHor)
			{
				this.TableStylesLastLook.BandHor = tableLook.BandHor;
				bIsChanged = true;
			}
			if (this.TableStylesLastLook.BandVer != tableLook.BandVer)
			{
				this.TableStylesLastLook.BandVer = tableLook.BandVer;
				bIsChanged = true;
			}
		}

		if (!bIsChanged)
			return;

		var logicDoc = this.m_oWordControl.m_oLogicDocument;
		var _dst_styles = [];

		var _styles = logicDoc.Styles.Get_AllTableStyles();
		var _styles_len = _styles.length;

		if (_styles_len == 0)
			return _dst_styles;

		var _x_mar = 10;
		var _y_mar = 10;
		var _r_mar = 10;
		var _b_mar = 10;
		var _pageW = 297;
		var _pageH = 210;

		var W = (_pageW - _x_mar - _r_mar);
		var H = (_pageH - _y_mar - _b_mar);

		if (_canvas_tables == null)
		{
			_canvas_tables = document.createElement('canvas');

			if (!this.m_oWordControl.bIsRetinaSupport)
			{
				_canvas_tables.width = TABLE_STYLE_WIDTH_PIX;
				_canvas_tables.height = TABLE_STYLE_HEIGHT_PIX;
			}
			else
			{
				_canvas_tables.width = (TABLE_STYLE_WIDTH_PIX * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
				_canvas_tables.height = (TABLE_STYLE_HEIGHT_PIX * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
			}
		}

		var _canvas = _canvas_tables;
		var ctx = _canvas.getContext('2d');

		var Rows = 5;

		History.TurnOff();
		g_oTableId.m_bTurnOff = true;
		for (var i1 = 0; i1 < _styles_len; i1++)
		{
			var i = _styles[i1];
			var _style = logicDoc.Styles.Style[i];

			if (!_style || _style.Type != styletype_Table)
				continue;

			if (_table_styles == null)
			{
				var Cols = 5;

				var Grid = [];
				for (var ii = 0; ii < Cols; ii++)
					Grid[ii] = W / Cols;

				_table_styles = new CTable(this, logicDoc, true, Rows, Cols, Grid);
				_table_styles.Reset(_x_mar, _y_mar, 1000, 1000, 0, 0, 1);
				_table_styles.Set_Props({
					TableStyle: i,
					TableLook: tableLook,
					TableLayout: c_oAscTableLayout.Fixed
				});
				_table_styles.Set_Props({
					TableDefaultMargins : {Top : 0, Bottom : 0}
				});

				for (var j = 0; j < Rows; j++)
					_table_styles.Content[j].Set_Height(H / Rows, Asc.linerule_AtLeast);
			}
			else
			{
				_table_styles.Set_Props({
					TableStyle: i,
					TableLook: tableLook,
					TableLayout: c_oAscTableLayout.Fixed,
					CellSelect: false
				});
				_table_styles.Set_Props({
					TableDefaultMargins : {Top : 0, Bottom : 0}
				});
				_table_styles.Recalc_CompiledPr2();

				for (var j = 0; j < Rows; j++)
					_table_styles.Content[j].Set_Height(H / Rows, Asc.linerule_AtLeast);
			}


			ctx.fillStyle = "#FFFFFF";
			ctx.fillRect(0, 0, _canvas.width, _canvas.height);

			var graphics = new AscCommon.CGraphics();
			graphics.init(ctx, _canvas.width, _canvas.height, _pageW, _pageH);
			graphics.m_oFontManager = AscCommon.g_fontManager;
			graphics.transform(1, 0, 0, 1, 0, 0);

			_table_styles.Recalculate_Page(0);

			var _old_mode = editor.isViewMode;
			editor.isViewMode = true;
			editor.isShowTableEmptyLineAttack = true;
			_table_styles.Draw(0, graphics);
			editor.isShowTableEmptyLineAttack = false;
			editor.isViewMode = _old_mode;

			var _styleD = new Asc.CAscTableStyle();
			_styleD.Type = 0;
			_styleD.Image = _canvas.toDataURL("image/png");
			_styleD.Id = i;
			_dst_styles.push(_styleD);
		}
		g_oTableId.m_bTurnOff = false;
		History.TurnOn();

		this.m_oWordControl.m_oApi.sync_InitEditorTableStyles(_dst_styles, this.m_oWordControl.bIsRetinaSupport);
	}

	this.IsMobileVersion = function ()
	{
		if (this.m_oWordControl.MobileTouchManager)
			return true;
		return false;
	}

	this.OnSelectEnd = function ()
	{
		if (this.m_oWordControl && this.m_oWordControl.MobileTouchManager)
			this.m_oWordControl.MobileTouchManager.CheckSelectRects();
	}

	// mouse events
	this.checkMouseDown_Drawing = function (pos)
	{
		var oWordControl = this.m_oWordControl;
		var _ret = this.TableOutlineDr.checkMouseDown(pos, oWordControl);
		if (_ret === true)
		{
			oWordControl.m_oLogicDocument.RemoveSelection(true);
			this.TableOutlineDr.bIsTracked = true;
			if (!this.TableOutlineDr.IsResizeTableTrack)
				this.LockCursorType("move");
			else
				this.LockCursorType("default");

			this.TableOutlineDr.TableOutline.Table.SelectAll();
			this.TableOutlineDr.TableOutline.Table.Document_SetThisElementCurrent(true);

			if (-1 == oWordControl.m_oTimerScrollSelect)
			{
				oWordControl.m_oTimerScrollSelect = setInterval(oWordControl.SelectWheel, 20);
			}
			oWordControl.EndUpdateOverlay();
			return true;
		}

		if (this.FrameRect.IsActive)
		{
			var eps = 10 * g_dKoef_pix_to_mm * 100 / oWordControl.m_nZoomValue;
			var _check = this.checkCursorOnTrackRect(pos.X, pos.Y, eps, this.FrameRect.Rect);

			if (-1 != _check)
			{
				this.FrameRect.IsTracked = true;
				this.FrameRect.Track.X = pos.X;
				this.FrameRect.Track.Y = pos.Y;
				this.FrameRect.Track.Type = _check;

				switch (_check)
				{
					case 0:
					{
						this.LockCursorType("nw-resize");
						break;
					}
					case 1:
					{
						this.LockCursorType("n-resize");
						break;
					}
					case 2:
					{
						this.LockCursorType("ne-resize");
						break;
					}
					case 3:
					{
						this.LockCursorType("e-resize");
						break;
					}
					case 4:
					{
						this.LockCursorType("se-resize");
						break;
					}
					case 5:
					{
						this.LockCursorType("s-resize");
						break;
					}
					case 6:
					{
						this.LockCursorType("sw-resize");
						break;
					}
					case 7:
					{
						this.LockCursorType("w-resize");
						break;
					}
					default:
					{
						this.LockCursorType("move");
						break;
					}
				}

				if (-1 == oWordControl.m_oTimerScrollSelect)
				{
					oWordControl.m_oTimerScrollSelect = setInterval(oWordControl.SelectWheel, 20);
				}
				oWordControl.EndUpdateOverlay();
				return true;
			}
		}

		for (var i = 0; i < this.ContentControlObjects.length; i++)
		{
			var _content_control = this.ContentControlObjects[i];
			if (_content_control.type == c_oContentControlTrack.In)
			{
				var _rect = _content_control.getXY();

				var _page = this.m_arrPages[_content_control.getPage()];
				if (!_page)
					return false;

				var drPage = _page.drawingPage;

				var dKoefX = (drPage.right - drPage.left) / _page.width_mm;
				var dKoefY = (drPage.bottom - drPage.top) / _page.height_mm;

				var _x = _rect.X - (15 / dKoefX);
				var _y = _rect.Y;
				var _r = _rect.X;
				var _b = _rect.Y + (20 / dKoefY);

				if (_content_control.Name != "" || 0 != _content_control.Buttons.length)
				{
					_x = _rect.X;
					_y = _rect.Y - (20 / dKoefY);
					_r = _rect.X + (15 / dKoefX);
					_b = _rect.Y;
				}

				var posX = pos.X;
				var posY = pos.Y;

				var _transform = _content_control.transform;
				if (_transform && global_MatrixTransformer.IsIdentity2(_transform))
				{
					_x += _transform.tx;
					_y += _transform.ty;
					_r += _transform.tx;
					_b += _transform.ty;

					_transform = null;
				}
				if (_transform)
				{
					var _invert = global_MatrixTransformer.Invert(_transform);
					posX = _invert.TransformPointX(pos.X, pos.Y);
					posY = _invert.TransformPointY(pos.X, pos.Y);
				}

				if (posX > _x && posX < _r && posY > _y && posY < _b)
				{
					oWordControl.m_oLogicDocument.SelectContentControl(_content_control.id);
					this.ContentControlObjectState = 1;
					this.ContentControlSmallChangesCheck.X = pos.X;
					this.ContentControlSmallChangesCheck.Y = pos.Y;
					this.ContentControlSmallChangesCheck.Page = pos.Page;
					this.ContentControlSmallChangesCheck.IsSmall = true;

					//this.InlineTextTrackEnabled = true;
					this.InlineTextTrack = null;
					this.InlineTextTrackPage = -1;

					oWordControl.ShowOverlay();
					oWordControl.OnUpdateOverlay();
					oWordControl.EndUpdateOverlay();

					this.LockCursorType("default");
					return true;
				}
				else if (_content_control.NameButtonAdvanced && posX > _r && posX < (_r + _content_control.NameWidth / dKoefX) && posY > _y && posY < _b)
				{
					if (_content_control.ActiveButtonIndex == -1)
					{
						_content_control.ActiveButtonIndex = -2;
						oWordControl.m_oApi.sendEvent("asc_onHideContentControlsActions");
					}
					else
					{
						_content_control.ActiveButtonIndex = -1;

						var xCC = _r;
						var yCC = _b;
						if (_transform)
						{
							xCC = _transform.TransformPointX(_r, _b);
							yCC = _transform.TransformPointY(_r, _b);
						}

						var posOnScreen = this.ConvertCoordsToCursorWR(xCC, yCC, _content_control.getPage());
						oWordControl.m_oApi.sendEvent("asc_onShowContentControlsActions", 0, posOnScreen.X, posOnScreen.Y);
					}

					oWordControl.ShowOverlay();
					oWordControl.OnUpdateOverlay();
					oWordControl.EndUpdateOverlay();

					this.LockCursorType("default");
					return true;
				}
				else
				{
					var _posR = _r + _content_control.NameWidth / dKoefX;
					for (var indexB = 0; indexB < _content_control.Buttons.length; indexB++)
					{
						if (posX > _posR && posX < (_posR + 20 / dKoefX) && posY > _y && posY < _b)
						{
							if (_content_control.ActiveButtonIndex == indexB)
							{
								_content_control.ActiveButtonIndex = -2;
								oWordControl.m_oApi.sendEvent("asc_onHideContentControlsActions");
							}
							else
							{
								_content_control.ActiveButtonIndex = indexB;

								var xCC = _posR;
								var yCC = _b;
								if (_transform)
								{
									xCC = _transform.TransformPointX(_posR, _b);
									yCC = _transform.TransformPointY(_posR, _b);
								}

								var posOnScreen = this.ConvertCoordsToCursorWR(xCC, yCC, _content_control.getPage());
								oWordControl.m_oApi.sendEvent("asc_onShowContentControlsActions", indexB + 1, posOnScreen.X, posOnScreen.Y);
							}

							oWordControl.ShowOverlay();
							oWordControl.OnUpdateOverlay();
							oWordControl.EndUpdateOverlay();

							this.LockCursorType("default");
							return true;
						}
						_posR += (20 / dKoefX);
					}
				}

				break;
			}
		}

		return false;
	};

	this.checkMouseDown_DrawingOnUp = function (pos)
	{
		var oWordControl = this.m_oWordControl;

		for (var i = 0; i < this.ContentControlObjects.length; i++)
		{
			var _content_control = this.ContentControlObjects[i];
			if (_content_control.type == c_oContentControlTrack.In)
			{
				var _rect = _content_control.getXY();

				var _page = this.m_arrPages[_content_control.getPage()];
				if (!_page)
					return false;

				var drPage = _page.drawingPage;

				var dKoefX = (drPage.right - drPage.left) / _page.width_mm;
				var dKoefY = (drPage.bottom - drPage.top) / _page.height_mm;

				var _x = _rect.X - (15 / dKoefX);
				var _y = _rect.Y;
				var _r = _rect.X;
				var _b = _rect.Y + (20 / dKoefY);

				if (_content_control.Name != "" || 0 != _content_control.Buttons.length)
				{
					_x = _rect.X;
					_y = _rect.Y - (20 / dKoefY);
					_r = _rect.X + (15 / dKoefX);
					_b = _rect.Y;
				}

				var posX = pos.X;
				var posY = pos.Y;

				var _transform = _content_control.transform;
				if (_transform && global_MatrixTransformer.IsIdentity2(_transform))
				{
					_x += _transform.tx;
					_y += _transform.ty;
					_r += _transform.tx;
					_b += _transform.ty;

					_transform = null;
				}
				if (_transform)
				{
					var _invert = global_MatrixTransformer.Invert(_transform);
					posX = _invert.TransformPointX(pos.X, pos.Y);
					posY = _invert.TransformPointY(pos.X, pos.Y);
				}

				if (posX > _x && posX < _r && posY > _y && posY < _b)
				{
					return true;
				}
				else if (_content_control.NameButtonAdvanced && posX > _r && posX < (_r + _content_control.NameWidth / dKoefX) && posY > _y && posY < _b)
				{
					return true;
				}
				else
				{
					var _posR = _r + _content_control.NameWidth / dKoefX;
					for (var indexB = 0; indexB < _content_control.Buttons.length; indexB++)
					{
						if (posX > _posR && posX < (_posR + 20 / dKoefX) && posY > _y && posY < _b)
						{
							return true;
						}
						_posR += (20 / dKoefX);
					}
				}

				break;
			}
		}

		return false;
	};

	this.checkMouseMove_Drawing = function (pos)
	{
		var oWordControl = this.m_oWordControl;
		if (this.TableOutlineDr.bIsTracked)
		{
			this.TableOutlineDr.checkMouseMove(global_mouseEvent.X, global_mouseEvent.Y, oWordControl);
			oWordControl.ShowOverlay();
			oWordControl.OnUpdateOverlay();
			oWordControl.EndUpdateOverlay();
			return true;
		}
		if (this.TableOutlineDr.checkMouseMoveTrack)
		{
			if (this.TableOutlineDr.checkMouseMoveTrack(pos, oWordControl))
			{
				this.SetCursorType("default");
				return true;
			}
		}
		if (this.TableOutlineDr.checkMouseMove2)
		{
			if (this.TableOutlineDr.checkMouseMove2(global_mouseEvent.X, global_mouseEvent.Y, oWordControl))
				return true;
		}

		if (this.InlineTextTrackEnabled)
		{
			if (pos.Page != this.ContentControlSmallChangesCheck.Page ||
				Math.abs(pos.X - this.ContentControlSmallChangesCheck.X) > this.ContentControlSmallChangesCheck.Min ||
				Math.abs(pos.Y - this.ContentControlSmallChangesCheck.Y) > this.ContentControlSmallChangesCheck.Min)
			{
				this.ContentControlSmallChangesCheck.IsSmall = false;
			}

			this.InlineTextTrack = oWordControl.m_oLogicDocument.Get_NearestPos(pos.Page, pos.X, pos.Y);
			this.InlineTextTrackPage = pos.Page;

			oWordControl.ShowOverlay();
			oWordControl.OnUpdateOverlay();
			oWordControl.EndUpdateOverlay();
			return true;
		}

		if (this.FrameRect.IsActive)
		{
			if (!this.FrameRect.IsTracked && this.FrameRect.PageIndex == pos.Page)
			{
				var eps = 10 * g_dKoef_pix_to_mm * 100 / oWordControl.m_nZoomValue;
				var _check = this.checkCursorOnTrackRect(pos.X, pos.Y, eps, this.FrameRect.Rect);

				if (_check != -1)
				{
					switch (_check)
					{
						case 0:
						{
							this.SetCursorType("nw-resize");
							break;
						}
						case 1:
						{
							this.SetCursorType("n-resize");
							break;
						}
						case 2:
						{
							this.SetCursorType("ne-resize");
							break;
						}
						case 3:
						{
							this.SetCursorType("e-resize");
							break;
						}
						case 4:
						{
							this.SetCursorType("se-resize");
							break;
						}
						case 5:
						{
							this.SetCursorType("s-resize");
							break;
						}
						case 6:
						{
							this.SetCursorType("sw-resize");
							break;
						}
						case 7:
						{
							this.SetCursorType("w-resize");
							break;
						}
						default:
						{
							this.SetCursorType("move");
							break;
						}
					}
					// оверлей не нужно перерисовывать
					oWordControl.EndUpdateOverlay();
					return true;
				}
			}
			else
			{
				this.checkTrackRect(pos);

				oWordControl.ShowOverlay();
				oWordControl.OnUpdateOverlay();
				oWordControl.EndUpdateOverlay();
				return true;
			}
		}

		var _content_control = null;
		var isChangeHover = false;
		for (var i = 0; i < this.ContentControlObjects.length; i++)
		{
			if (-2 != this.ContentControlObjects[i].HoverButtonIndex)
				isChangeHover = true;
			this.ContentControlObjects[i].HoverButtonIndex = -2;
			if (this.ContentControlObjects[i].type == c_oContentControlTrack.In)
			{
				_content_control = this.ContentControlObjects[i];
				break;
			}
		}

		if (_content_control && pos.Page == _content_control.getPage())
		{
			if (1 == this.ContentControlObjectState)
			{
				if (pos.Page == this.ContentControlSmallChangesCheck.Page &&
					Math.abs(pos.X - this.ContentControlSmallChangesCheck.X) < this.ContentControlSmallChangesCheck.Min &&
					Math.abs(pos.Y - this.ContentControlSmallChangesCheck.Y) < this.ContentControlSmallChangesCheck.Min)
				{
					oWordControl.ShowOverlay();
					oWordControl.OnUpdateOverlay();
					oWordControl.EndUpdateOverlay();
					return true;
				}

				this.InlineTextTrackEnabled = true;
				this.ContentControlSmallChangesCheck.IsSmall = false;

				this.InlineTextTrack = oWordControl.m_oLogicDocument.Get_NearestPos(pos.Page, pos.X, pos.Y);
				this.InlineTextTrackPage = pos.Page;

				oWordControl.ShowOverlay();
				oWordControl.OnUpdateOverlay();
				oWordControl.EndUpdateOverlay();
				return true;
			}

			var _page = this.m_arrPages[pos.Page];
			var drPage = _page.drawingPage;

			var dKoefX = (drPage.right - drPage.left) / _page.width_mm;
			var dKoefY = (drPage.bottom - drPage.top) / _page.height_mm;

			var rect = _content_control.getXY();
			var _x = rect.X - (15 / dKoefX);
			var _y = rect.Y;
			var _r = rect.X;
			var _b = rect.Y + (20 / dKoefY);

			if (_content_control.Name != "" || 0 != _content_control.Buttons.length)
			{
				_x = rect.X;
				_y = rect.Y - (20 / dKoefY);
				_r = rect.X + (15 / dKoefX);
				_b = rect.Y;
			}

			var posX = pos.X;
			var posY = pos.Y;

			var _transform = _content_control.transform;
			if (_transform && global_MatrixTransformer.IsIdentity2(_transform))
			{
				_x += _transform.tx;
				_y += _transform.ty;
				_r += _transform.tx;
				_b += _transform.ty;

				_transform = null;
			}
			if (_transform)
			{
				var _invert = global_MatrixTransformer.Invert(_transform);
				posX = _invert.TransformPointX(pos.X, pos.Y);
				posY = _invert.TransformPointY(pos.X, pos.Y);
			}

			var _old = this.ContentControlObjectState;
			this.ContentControlObjectState = -1;
			if (posX > _x && posX < _r && posY > _y && posY < _b)
			{
				this.ContentControlObjectState = 0;
				oWordControl.ShowOverlay();
				oWordControl.OnUpdateOverlay();
				oWordControl.EndUpdateOverlay();

				this.SetCursorType("default");

				oWordControl.m_oApi.sync_MouseMoveStartCallback();
				oWordControl.m_oApi.sync_MouseMoveEndCallback();
				return true;
			}
			else if (_content_control.NameButtonAdvanced && posX > _r && posX < (_r + _content_control.NameWidth / dKoefX) && posY > _y && posY < _b)
			{
				_content_control.HoverButtonIndex = -1;
				oWordControl.ShowOverlay();
				oWordControl.OnUpdateOverlay();
				oWordControl.EndUpdateOverlay();

				this.SetCursorType("default");

				oWordControl.m_oApi.sync_MouseMoveStartCallback();
				oWordControl.m_oApi.sync_MouseMoveEndCallback();
				return true;
			}
			else
			{
				var _posR = _r + _content_control.NameWidth / dKoefX;
				for (var indexB = 0; indexB < _content_control.Buttons.length; indexB++)
				{
					if (posX > _posR && posX < (_posR + 20 / dKoefX) && posY > _y && posY < _b)
					{
						_content_control.HoverButtonIndex = indexB;
						oWordControl.ShowOverlay();
						oWordControl.OnUpdateOverlay();
						oWordControl.EndUpdateOverlay();

						this.SetCursorType("default");

						oWordControl.m_oApi.sync_MouseMoveStartCallback();
						oWordControl.m_oApi.sync_MouseMoveEndCallback();
						return true;
					}
					_posR += (20 / dKoefX);
				}
			}

			if (_old != this.ContentControlObjectState)
				oWordControl.OnUpdateOverlay();
		}

		if (isChangeHover)
			oWordControl.OnUpdateOverlay();

		return false;
	};

	this.checkMouseUp_Drawing = function (pos)
	{
		var oWordControl = this.m_oWordControl;

		var oldContentControlSmall = this.ContentControlSmallChangesCheck.IsSmall;
		this.ContentControlSmallChangesCheck.IsSmall = true;

		if (this.TableOutlineDr.bIsTracked)
		{
			this.TableOutlineDr.checkMouseUp(global_mouseEvent.X, global_mouseEvent.Y, oWordControl);
			oWordControl.m_oLogicDocument.Document_UpdateInterfaceState();
			oWordControl.m_oLogicDocument.Document_UpdateRulersState();

			if (-1 != oWordControl.m_oTimerScrollSelect)
			{
				clearInterval(oWordControl.m_oTimerScrollSelect);
				oWordControl.m_oTimerScrollSelect = -1;
			}
			oWordControl.OnUpdateOverlay();

			oWordControl.EndUpdateOverlay();
			return true;
		}

		if (this.InlineTextTrackEnabled && (this.ContentControlObjectState != 1))
		{
			this.InlineTextTrack = oWordControl.m_oLogicDocument.Get_NearestPos(pos.Page, pos.X, pos.Y);
			this.InlineTextTrackPage = pos.Page;
			this.EndTrackText();

			oWordControl.ShowOverlay();
			oWordControl.OnUpdateOverlay();
			oWordControl.EndUpdateOverlay();
			return true;
		}

		if (this.FrameRect.IsActive && this.FrameRect.IsTracked)
		{
			this.FrameRect.IsTracked = false;

			this.checkTrackRect(pos);
			var _track = this.FrameRect.Track;
			this.FrameRect.Frame.Change_Frame(_track.L, _track.T, _track.R - _track.L, _track.B - _track.T, _track.PageIndex);

			if (-1 != oWordControl.m_oTimerScrollSelect)
			{
				clearInterval(oWordControl.m_oTimerScrollSelect);
				oWordControl.m_oTimerScrollSelect = -1;
			}
			oWordControl.OnUpdateOverlay();

			oWordControl.EndUpdateOverlay();
			return true;
		}

		if (this.ContentControlObjectState == 1)
		{
			for (var i = 0; i < this.ContentControlObjects.length; i++)
			{
				var _object = this.ContentControlObjects[i];
				if (_object.type == c_oContentControlTrack.In)
				{
					if (this.InlineTextTrackEnabled)
					{
						if (this.InlineTextTrack && !oldContentControlSmall) // значит был MouseMove
						{
							this.InlineTextTrack = oWordControl.m_oLogicDocument.Get_NearestPos(pos.Page, pos.X, pos.Y);
							this.m_oWordControl.m_oLogicDocument.OnContentControlTrackEnd(_object.id, this.InlineTextTrack, AscCommon.global_keyboardEvent.CtrlKey);
							this.InlineTextTrackEnabled = false;
							this.InlineTextTrack = null;
							this.InlineTextTrackPage = -1;
						}
						else
						{
							this.InlineTextTrackEnabled = false;
						}
					}
					break;
				}
			}

			this.ContentControlObjectState = 0;
			oWordControl.ShowOverlay();
			oWordControl.OnUpdateOverlay();
			oWordControl.EndUpdateOverlay();
			return true;
		}

		return false;
	}

	this.checkCursorOnTrackRect = function (X, Y, eps, rect)
	{
		// 0-1-...-7 - точки по часовой стрелке, начиная с left-top,
		// 8-..-11 - стороны по часовой стрелке, начиная с top

		var __x_dist1 = Math.abs(X - rect.X);
		var __x_dist2 = Math.abs(X - ((rect.X + rect.R) / 2));
		var __x_dist3 = Math.abs(X - rect.R);

		var __y_dist1 = Math.abs(Y - rect.Y);
		var __y_dist2 = Math.abs(Y - ((rect.Y + rect.B) / 2));
		var __y_dist3 = Math.abs(Y - rect.B);

		if (__y_dist1 < eps)
		{
			if ((X < (rect.X - eps)) || (X > (rect.R + eps)))
				return -1;

			if (__x_dist1 <= __x_dist2 && __x_dist1 <= __x_dist3)
				return (__x_dist1 < eps) ? 0 : 8;

			if (__x_dist2 <= __x_dist1 && __x_dist2 <= __x_dist3)
				return (__x_dist2 < eps) ? 1 : 8;

			if (__x_dist3 <= __x_dist1 && __x_dist3 <= __x_dist2)
				return (__x_dist3 < eps) ? 2 : 8;

			return 8;
		}

		if (__y_dist3 < eps)
		{
			if ((X < (rect.X - eps)) || (X > (rect.R + eps)))
				return -1;

			if (__x_dist1 <= __x_dist2 && __x_dist1 <= __x_dist3)
				return (__x_dist1 < eps) ? 6 : 10;

			if (__x_dist2 <= __x_dist1 && __x_dist2 <= __x_dist3)
				return (__x_dist2 < eps) ? 5 : 10;

			if (__x_dist3 <= __x_dist1 && __x_dist3 <= __x_dist2)
				return (__x_dist3 < eps) ? 4 : 10;

			return 8;
		}

		if (__x_dist1 < eps)
		{
			if ((Y < (rect.Y - eps)) || (Y > (rect.B + eps)))
				return -1;

			if (__y_dist1 <= __y_dist2 && __y_dist1 <= __y_dist3)
				return (__y_dist1 < eps) ? 0 : 11;

			if (__y_dist2 <= __y_dist1 && __y_dist2 <= __y_dist3)
				return (__y_dist2 < eps) ? 7 : 11;

			if (__y_dist3 <= __y_dist1 && __y_dist3 <= __y_dist2)
				return (__y_dist3 < eps) ? 6 : 11;

			return 11;
		}

		if (__x_dist3 < eps)
		{
			if ((Y < (rect.Y - eps)) || (Y > (rect.B + eps)))
				return -1;

			if (__y_dist1 <= __y_dist2 && __y_dist1 <= __y_dist3)
				return (__y_dist1 < eps) ? 2 : 9;

			if (__y_dist2 <= __y_dist1 && __y_dist2 <= __y_dist3)
				return (__y_dist2 < eps) ? 3 : 9;

			if (__y_dist3 <= __y_dist1 && __y_dist3 <= __y_dist2)
				return (__y_dist3 < eps) ? 4 : 9;

			return 9;
		}

		return -1;
	}

	this.checkTrackRect = function (pos)
	{
		var _min_dist = 3; // mm;

		var _track = this.FrameRect.Track;
		var _rect = this.FrameRect.Rect;
		_track.PageIndex = this.FrameRect.PageIndex;
		switch (_track.Type)
		{
			case 0:
			{
				_track.L = _rect.X + (pos.X - _track.X);
				_track.T = _rect.Y + (pos.Y - _track.Y);
				_track.R = _rect.R;
				_track.B = _rect.B;

				if (_track.L > (_track.R - _min_dist))
					_track.L = _track.R - _min_dist;
				if (_track.T > (_track.B - _min_dist))
					_track.T = _track.B - _min_dist;

				break;
			}
			case 1:
			{
				_track.L = _rect.X;
				_track.T = _rect.Y + (pos.Y - _track.Y);
				_track.R = _rect.R;
				_track.B = _rect.B;

				if (_track.T > (_track.B - _min_dist))
					_track.T = _track.B - _min_dist;

				break;
			}
			case 2:
			{
				_track.L = _rect.X;
				_track.T = _rect.Y + (pos.Y - _track.Y);
				_track.R = _rect.R + (pos.X - _track.X);
				_track.B = _rect.B;

				if (_track.R < (_track.L + _min_dist))
					_track.R = _track.L + _min_dist;
				if (_track.T > (_track.B - _min_dist))
					_track.T = _track.B - _min_dist;

				break;
			}
			case 3:
			{
				_track.L = _rect.X;
				_track.T = _rect.Y;
				_track.R = _rect.R + (pos.X - _track.X);
				_track.B = _rect.B;

				if (_track.R < (_track.L + _min_dist))
					_track.R = _track.L + _min_dist;

				break;
			}
			case 4:
			{
				_track.L = _rect.X;
				_track.T = _rect.Y;
				_track.R = _rect.R + (pos.X - _track.X);
				_track.B = _rect.B + (pos.Y - _track.Y);

				if (_track.R < (_track.L + _min_dist))
					_track.R = _track.L + _min_dist;
				if (_track.B < (_track.T + _min_dist))
					_track.B = _track.T + _min_dist;

				break;
			}
			case 5:
			{
				_track.L = _rect.X;
				_track.T = _rect.Y;
				_track.R = _rect.R;
				_track.B = _rect.B + (pos.Y - _track.Y);

				if (_track.B < (_track.T + _min_dist))
					_track.B = _track.T + _min_dist;

				break;
			}
			case 6:
			{
				_track.L = _rect.X + (pos.X - _track.X);
				_track.T = _rect.Y;
				_track.R = _rect.R;
				_track.B = _rect.B + (pos.Y - _track.Y);

				if (_track.L > (_track.R - _min_dist))
					_track.L = _track.R - _min_dist;
				if (_track.B < (_track.T + _min_dist))
					_track.B = _track.T + _min_dist;

				break;
			}
			case 7:
			{
				_track.L = _rect.X + (pos.X - _track.X);
				_track.T = _rect.Y;
				_track.R = _rect.R;
				_track.B = _rect.B;

				if (_track.L > (_track.R - _min_dist))
					_track.L = _track.R - _min_dist;

				break;
			}
			default:
			{
				_track.L = pos.X - (_track.X - _rect.X);
				_track.T = pos.Y - (_track.Y - _rect.Y);
				_track.R = _track.L + _rect.R - _rect.X;
				_track.B = _track.T + _rect.B - _rect.Y;

				_track.PageIndex = pos.Page;
				break;
			}
		}
	}

	this.DrawVerAnchor = function (pageNum, xPos, bIsFromDrawings)
	{
		if (undefined === bIsFromDrawings)
		{
			if (this.m_oWordControl.m_oApi.ShowSnapLines)
			{
				this.HorVerAnchors.push({Type: 0, Page: pageNum, Pos: xPos});
			}
			return;
		}

		var _pos = this.ConvertCoordsToCursor4(xPos, 0, pageNum);
		if (_pos.Error === false)
		{
			this.m_oWordControl.m_oOverlayApi.DashLineColor = "#C8C8C8";
			this.m_oWordControl.m_oOverlayApi.VertLine2(_pos.X);
			this.m_oWordControl.m_oOverlayApi.DashLineColor = "#000000";
		}
	}

	this.DrawHorAnchor = function (pageNum, yPos, bIsFromDrawings)
	{
		if (undefined === bIsFromDrawings)
		{
			if (this.m_oWordControl.m_oApi.ShowSnapLines)
			{
				this.HorVerAnchors.push({Type: 1, Page: pageNum, Pos: yPos});
			}
			return;
		}

		var _pos = this.ConvertCoordsToCursor4(0, yPos, pageNum);
		if (_pos.Error === false)
		{
			this.m_oWordControl.m_oOverlayApi.DashLineColor = "#C8C8C8";
			this.m_oWordControl.m_oOverlayApi.HorLine2(_pos.Y);
			this.m_oWordControl.m_oOverlayApi.DashLineColor = "#000000";
		}
	}

	this.DrawHorVerAnchor = function ()
	{
		for (var i = 0; i < this.HorVerAnchors.length; i++)
		{
			var _anchor = this.HorVerAnchors[i];
			if (_anchor.Type == 0)
				this.DrawVerAnchor(_anchor.Page, _anchor.Pos, true);
			else
				this.DrawHorAnchor(_anchor.Page, _anchor.Pos, true);
		}
		this.HorVerAnchors.splice(0, this.HorVerAnchors.length);
	}

	// track text (inline)
	this.StartTrackText = function ()
	{
		this.InlineTextTrackEnabled = true;
		this.InlineTextTrack = null;
		this.InlineTextTrackPage = -1;
	}
	this.EndTrackText = function (isOnlyMoveTarget)
	{
		this.InlineTextTrackEnabled = false;

		if (true !== isOnlyMoveTarget)
			this.m_oWordControl.m_oLogicDocument.OnEndTextDrag(this.InlineTextTrack, AscCommon.global_keyboardEvent.CtrlKey);
		else if (this.InlineTextTrack)
		{
            var Paragraph = this.InlineTextTrack.Paragraph;
            Paragraph.Cursor_MoveToNearPos(this.InlineTextTrack);
            Paragraph.Document_SetThisElementCurrent(false);

            this.m_oWordControl.m_oLogicDocument.Document_UpdateSelectionState();
            this.m_oWordControl.m_oLogicDocument.Document_UpdateInterfaceState();
            this.m_oWordControl.m_oLogicDocument.Document_UpdateRulersState();
		}

		this.InlineTextTrack = null;
		this.InlineTextTrackPage = -1;
	}

	this.IsTrackText = function ()
	{
		return this.InlineTextTrackEnabled;
	}

	this.CancelTrackText = function ()
	{
		this.InlineTextTrackEnabled = false;
		this.InlineTextTrack = null;
		this.InlineTextTrackPage = -1;
	}

	this.SendMathToMenu = function ()
	{
		if (this.MathMenuLoad)
			return;

		// GENERATE_IMAGES
		//var _MathPainter = new CMathPainter(this.m_oWordControl.m_oApi);
		//_MathPainter.StartLoad();
		//return;

		var _MathPainter = new AscFormat.CMathPainter(this.m_oWordControl.m_oApi);
		_MathPainter.Generate();
		this.MathMenuLoad = true;
	};

	// collaborative targets
	this.Collaborative_UpdateTarget = function (_id, _shortId, _x, _y, _size, _page, _transform, is_from_paint)
	{
		if (is_from_paint !== true)
		{
			this.CollaborativeTargetsUpdateTasks.push([_id, _shortId, _x, _y, _size, _page, _transform]);
			return;
		}

		for (var i = 0; i < this.CollaborativeTargets.length; i++)
		{
			if (_id == this.CollaborativeTargets[i].Id)
			{
				this.CollaborativeTargets[i].CheckPosition(this, _x, _y, _size, _page, _transform);
				return;
			}
		}
		var _target = new CDrawingCollaborativeTarget();
		_target.Id = _id;
		_target.ShortId = _shortId;
		_target.CheckPosition(this, _x, _y, _size, _page, _transform);
		this.CollaborativeTargets[this.CollaborativeTargets.length] = _target;
	};
	this.Collaborative_RemoveTarget = function (_id)
	{
		var i = 0;
		for (i = 0; i < this.CollaborativeTargets.length; i++)
		{
			if (_id == this.CollaborativeTargets[i].Id)
			{
				this.CollaborativeTargets[i].Remove(this);
				this.CollaborativeTargets.splice(i, 1);
				i--;
			}
		}

		for (i = 0; i < this.CollaborativeTargetsUpdateTasks.length; i++)
		{
			var _tmp = this.CollaborativeTargetsUpdateTasks[i];
			if (_tmp[0] == _id)
			{
				this.CollaborativeTargetsUpdateTasks.splice(i, 1);
				i--;
			}
		}
	};
	this.Collaborative_TargetsUpdate = function (bIsChangePosition)
	{
		var _len_tasks = this.CollaborativeTargetsUpdateTasks.length;
		var i = 0;
		for (i = 0; i < _len_tasks; i++)
		{
			var _tmp = this.CollaborativeTargetsUpdateTasks[i];
			this.Collaborative_UpdateTarget(_tmp[0], _tmp[1], _tmp[2], _tmp[3], _tmp[4], _tmp[5], _tmp[6], true);
		}
		if (_len_tasks != 0)
			this.CollaborativeTargetsUpdateTasks.splice(0, _len_tasks);

		if (bIsChangePosition)
		{
			for (i = 0; i < this.CollaborativeTargets.length; i++)
			{
				this.CollaborativeTargets[i].Update(this);
			}
		}
	};
	this.Collaborative_GetTargetPosition = function (UserId)
	{
		for (var i = 0; i < this.CollaborativeTargets.length; i++)
		{
			if (UserId == this.CollaborativeTargets[i].Id)
				return {X: this.CollaborativeTargets[i].HtmlElementX, Y: this.CollaborativeTargets[i].HtmlElementY};
		}

		return null;
	};
}
function CStylesPainter()
{
	this.defaultStyles = null;
	this.docStyles = null;

	this.mergedStyles = null;

	this.STYLE_THUMBNAIL_WIDTH = GlobalSkin.STYLE_THUMBNAIL_WIDTH;
	this.STYLE_THUMBNAIL_HEIGHT = GlobalSkin.STYLE_THUMBNAIL_HEIGHT;

	this.CurrentTranslate = null;
	this.IsRetinaEnabled = false;
}
CStylesPainter.prototype =
{
	CheckStylesNames : function(_api, ds)
	{
        var DocumentStyles = _api.WordControl.m_oLogicDocument.Get_Styles();
        for (var i in ds)
        {
            var style = ds[i];
            if (style.IsExpressStyle(DocumentStyles) && null === DocumentStyles.GetStyleIdByName(style.Name))
            {
            	AscFonts.FontPickerByCharacter.getFontsByString(style.Name);
            }
        }

        AscFonts.FontPickerByCharacter.getFontsByString("Aa");

        var styles = DocumentStyles.Style;

        if (!styles)
            return;

        for (var i in styles)
        {
            var style = styles[i];
            if (style.IsExpressStyle(DocumentStyles))
            {
                AscFonts.FontPickerByCharacter.getFontsByString(style.Name);
                AscFonts.FontPickerByCharacter.getFontsByString(AscCommon.translateManager.getValue(style.Name));
            }
        }
	},

	GenerateStyles: function (_api, ds)
	{
		var _oldX = this.STYLE_THUMBNAIL_WIDTH;
		var _oldY = this.STYLE_THUMBNAIL_HEIGHT;
		if (_api.WordControl.bIsRetinaSupport)
		{
			this.STYLE_THUMBNAIL_WIDTH 	= AscCommon.AscBrowser.convertToRetinaValue(this.STYLE_THUMBNAIL_WIDTH, true);
			this.STYLE_THUMBNAIL_HEIGHT = AscCommon.AscBrowser.convertToRetinaValue(this.STYLE_THUMBNAIL_HEIGHT, true);
			this.IsRetinaEnabled = true;
		}

		this.CurrentTranslate = _api.CurrentTranslate;

		this.GenerateDefaultStyles(_api, ds);
		this.GenerateDocumentStyles(_api);

		// стили сформированы. осталось просто сформировать единый список
		var _count_default = this.defaultStyles.length;
		var _count_doc = 0;
		if (null != this.docStyles)
			_count_doc = this.docStyles.length;

		var aPriorityStyles = [];
		var fAddToPriorityStyles = function (style)
		{
			var index = style.uiPriority;
			if (null == index)
				index = 0;
			var aSubArray = aPriorityStyles[index];
			if (null == aSubArray)
			{
				aSubArray = [];
				aPriorityStyles[index] = aSubArray;
			}
			aSubArray.push(style);
		};
		var _map_document = {};

		for (var i = 0; i < _count_doc; i++)
		{
			var style = this.docStyles[i];
			_map_document[style.Name] = 1;
			fAddToPriorityStyles(style);
		}

		for (var i = 0; i < _count_default; i++)
		{
			var style = this.defaultStyles[i];
			if (null == _map_document[style.Name])
				fAddToPriorityStyles(style);
		}

		this.mergedStyles = [];
		for (var index in aPriorityStyles)
		{
			var aSubArray = aPriorityStyles[index];
			aSubArray.sort(function (a, b)
			{
				if (a.Name < b.Name)
					return -1;
				else if (a.Name > b.Name)
					return 1;
				else
					return 0;
			});
			for (var i = 0, length = aSubArray.length; i < length; ++i)
			{
				this.mergedStyles.push(aSubArray[i]);
			}
		}

		if (_api.WordControl.bIsRetinaSupport)
		{
			this.STYLE_THUMBNAIL_WIDTH = _oldX;
			this.STYLE_THUMBNAIL_HEIGHT = _oldY;
		}

		// export
		this["STYLE_THUMBNAIL_WIDTH"] = this.STYLE_THUMBNAIL_WIDTH;
		this["STYLE_THUMBNAIL_HEIGHT"] = this.STYLE_THUMBNAIL_HEIGHT;

		// теперь просто отдаем евент наверх
		_api.sync_InitEditorStyles(this);
	},
	GenerateDefaultStyles: function (_api, ds)
	{
		var styles = ds;

		// добавили переводы => нельзя кэшировать
		var _canvas = document.createElement('canvas');
		_canvas.width = this.STYLE_THUMBNAIL_WIDTH;
		_canvas.height = this.STYLE_THUMBNAIL_HEIGHT;
		var ctx = _canvas.getContext('2d');

		ctx.fillStyle = "#FFFFFF";
		ctx.fillRect(0, 0, _canvas.width, _canvas.height);

		var graphics = new AscCommon.CGraphics();
		if (!this.IsRetinaEnabled)
		{
			graphics.init(ctx, _canvas.width, _canvas.height, _canvas.width * g_dKoef_pix_to_mm, _canvas.height * g_dKoef_pix_to_mm);
		}
		else
		{
			graphics.init(ctx, _canvas.width, _canvas.height,
				_canvas.width * g_dKoef_pix_to_mm / AscCommon.AscBrowser.retinaPixelRatio,
				_canvas.height * g_dKoef_pix_to_mm / AscCommon.AscBrowser.retinaPixelRatio);
		}
		graphics.m_oFontManager = AscCommon.g_fontManager;

		var DocumentStyles = _api.WordControl.m_oLogicDocument.Get_Styles();
		this.defaultStyles = [];
		for (var i in styles)
		{
			var style = styles[i];
			if (style.IsExpressStyle(DocumentStyles) && null === DocumentStyles.GetStyleIdByName(style.Name))
			{
				this.drawStyle(graphics, style, AscCommon.translateManager.getValue(style.Name));
				this.defaultStyles.push(new AscCommon.CStyleImage(style.Name, AscCommon.c_oAscStyleImage.Default,
					_canvas.toDataURL("image/png"), style.uiPriority));
			}
		}
	},

	GenerateDocumentStyles: function (_api)
	{
		if (!_api.WordControl.m_oLogicDocument)
		{
			return;
		}

		var __Styles = _api.WordControl.m_oLogicDocument.Get_Styles();
		var styles = __Styles.Style;

		if (!styles)
		{
			return;
		}

		var cur_index = 0;

		var _canvas = document.createElement('canvas');
		_canvas.width = this.STYLE_THUMBNAIL_WIDTH;
		_canvas.height = this.STYLE_THUMBNAIL_HEIGHT;
		var ctx = _canvas.getContext('2d');

		if (window["flat_desine"] !== true)
		{
			ctx.fillStyle = "#FFFFFF";
			ctx.fillRect(0, 0, _canvas.width, _canvas.height);
		}

		var graphics = new AscCommon.CGraphics();
		if (!this.IsRetinaEnabled)
		{
			graphics.init(ctx, _canvas.width, _canvas.height, _canvas.width * g_dKoef_pix_to_mm, _canvas.height * g_dKoef_pix_to_mm);
		}
		else
		{
			graphics.init(ctx, _canvas.width, _canvas.height,
				_canvas.width * g_dKoef_pix_to_mm / AscCommon.AscBrowser.retinaPixelRatio,
				_canvas.height * g_dKoef_pix_to_mm / AscCommon.AscBrowser.retinaPixelRatio);
		}
		graphics.m_oFontManager = AscCommon.g_fontManager;

		this.docStyles = [];
		for (var i in styles)
		{
			var style = styles[i];
			if (style.IsExpressStyle(__Styles))
			{
				// как только меняется сериалайзер - меняется и код здесь. Да, не очень удобно,
				// зато быстро делается
				var formalStyle = i.toLowerCase().replace(/\s/g, "");
				var res = formalStyle.match(/^heading([1-9][0-9]*)$/);
				var index = (res) ? res[1] - 1 : -1;

				var _dr_style = __Styles.Get_Pr(i, styletype_Paragraph);
				_dr_style.Name = style.Name;
				_dr_style.Id = i;

				this.drawStyle(graphics, _dr_style,
					__Styles.Is_StyleDefault(style.Name) ? AscCommon.translateManager.getValue(style.Name) : style.Name);
				this.docStyles[cur_index] = new AscCommon.CStyleImage(style.Name, AscCommon.c_oAscStyleImage.Document,
					_canvas.toDataURL("image/png"), style.uiPriority);

				// алгоритм смены имени
				if (style.Default)
				{
					switch (style.Default)
					{
						case 1:
							break;
						case 2:
							this.docStyles[cur_index].Name = "No List";
							break;
						case 3:
							this.docStyles[cur_index].Name = "Normal";
							break;
						case 4:
							this.docStyles[cur_index].Name = "Normal Table";
							break;
					}
				}
				else if (index != -1)
				{
					this.docStyles[cur_index].Name = "Heading ".concat(index + 1);
				}

				cur_index++;
			}
		}
	},
	drawStyle: function (graphics, style, styleName)
	{
		var ctx = graphics.m_oContext;
		ctx.fillStyle = "#FFFFFF";
		ctx.fillRect(0, 0, this.STYLE_THUMBNAIL_WIDTH, this.STYLE_THUMBNAIL_HEIGHT);

		var font = {
			FontFamily: {Name: "Times New Roman", Index: -1},
			Color: {r: 0, g: 0, b: 0},
			Bold: false,
			Italic: false,
			FontSize: 10
		};

		var textPr = style.TextPr;
		if (textPr.FontFamily != undefined)
		{
			font.FontFamily.Name = textPr.FontFamily.Name;
			font.FontFamily.Index = textPr.FontFamily.Index;
		}

		if (textPr.Bold != undefined)
			font.Bold = textPr.Bold;
		if (textPr.Italic != undefined)
			font.Italic = textPr.Italic;

		if (textPr.FontSize != undefined)
			font.FontSize = textPr.FontSize;

		graphics.SetFont(font);

		if (textPr.Color == undefined)
			graphics.b_color1(0, 0, 0, 255);
		else
			graphics.b_color1(textPr.Color.r, textPr.Color.g, textPr.Color.b, 255);

		var dKoefToMM = g_dKoef_pix_to_mm;
		if (this.IsRetinaEnabled)
			dKoefToMM /= AscCommon.AscBrowser.retinaPixelRatio;

		if (window["flat_desine"] !== true)
		{
			var y = 0;
			var b = dKoefToMM * this.STYLE_THUMBNAIL_HEIGHT;
			var w = dKoefToMM * this.STYLE_THUMBNAIL_WIDTH;

			graphics.transform(1, 0, 0, 1, 0, 0);
			graphics.save();
			graphics._s();
			graphics._m(-0.5, y);
			graphics._l(w, y);
			graphics._l(w, b);
			graphics._l(0, b);
			graphics._z();
			graphics.clip();

			graphics.t(this.CurrentTranslate.StylesText, 0.5, (y + b) / 2);

			ctx.setTransform(1, 0, 0, 1, 0, 0);
			ctx.fillStyle = "#E8E8E8";

			var _b = this.STYLE_THUMBNAIL_HEIGHT - 1.5;
			var _x = 2;
			var _w = this.STYLE_THUMBNAIL_WIDTH - 4;
			var _h = (this.STYLE_THUMBNAIL_HEIGHT / 3) >> 0;
			ctx.beginPath();
			ctx.moveTo(_x, _b - _h);
			ctx.lineTo(_x + _w, _b - _h);
			ctx.lineTo(_x + _w, _b);
			ctx.lineTo(_x, _b);
			ctx.closePath();
			ctx.fill();

			ctx.lineWidth = 1;
			ctx.strokeStyle = "#D8D8D8";
			ctx.beginPath();
			ctx.rect(0.5, 0.5, this.STYLE_THUMBNAIL_WIDTH - 1, this.STYLE_THUMBNAIL_HEIGHT - 1);

			ctx.stroke();

			graphics.restore();
		}
		else
		{
			g_oTableId.m_bTurnOff = true;
			History.TurnOff();

			var oldDefTabStop = AscCommonWord.Default_Tab_Stop;
			AscCommonWord.Default_Tab_Stop = 1;

			var hdr = new CHeaderFooter(editor.WordControl.m_oLogicDocument.HdrFtr, editor.WordControl.m_oLogicDocument, editor.WordControl.m_oDrawingDocument, AscCommon.hdrftr_Header);
			var _dc = hdr.Content;//new CDocumentContent(editor.WordControl.m_oLogicDocument, editor.WordControl.m_oDrawingDocument, 0, 0, 0, 0, false, true, false);

			var par = new Paragraph(editor.WordControl.m_oDrawingDocument, _dc, false);
			var run = new ParaRun(par, false);
			run.AddText(styleName);

			_dc.Internal_Content_Add(0, par, false);
			par.Add_ToContent(0, run);
			par.Style_Add(style.Id, false);
			par.Set_Align(AscCommon.align_Left);
			par.Set_Tabs(new CParaTabs());

			if (!textPr.Color || (255 === textPr.Color.r && 255 === textPr.Color.g && 255 === textPr.Color.b))
				run.Set_Color(new CDocumentColor(0, 0, 0, false));

			var _brdL = style.ParaPr.Brd.Left;
			if (undefined !== _brdL && null !== _brdL)
			{
				var brdL = new CDocumentBorder();
				brdL.Set_FromObject(_brdL);
				brdL.Space = 0;
				par.Set_Border(brdL, AscDFH.historyitem_Paragraph_Borders_Left);
			}

			var _brdT = style.ParaPr.Brd.Top;
			if (undefined !== _brdT && null !== _brdT)
			{
				var brd = new CDocumentBorder();
				brd.Set_FromObject(_brdT);
				brd.Space = 0;
				par.Set_Border(brd, AscDFH.historyitem_Paragraph_Borders_Top);
			}

			var _brdB = style.ParaPr.Brd.Bottom;
			if (undefined !== _brdB && null !== _brdB)
			{
				var brd = new CDocumentBorder();
				brd.Set_FromObject(_brdB);
				brd.Space = 0;
				par.Set_Border(brd, AscDFH.historyitem_Paragraph_Borders_Bottom);
			}

			var _brdR = style.ParaPr.Brd.Right;
			if (undefined !== _brdR && null !== _brdR)
			{
				var brd = new CDocumentBorder();
				brd.Set_FromObject(_brdR);
				brd.Space = 0;
				par.Set_Border(brd, AscDFH.historyitem_Paragraph_Borders_Right);
			}

			var _ind = new CParaInd();
			_ind.FirstLine = 0;
			_ind.Left = 0;
			_ind.Right = 0;
			par.Set_Ind(_ind, false);

			var _sp = new CParaSpacing();
			_sp.Line = 1;
			_sp.LineRule = Asc.linerule_Auto;
			_sp.Before = 0;
			_sp.BeforeAutoSpacing = false;
			_sp.After = 0;
			_sp.AfterAutoSpacing = false;
			par.Set_Spacing(_sp, false);

			_dc.Reset(0, 0, 10000, 10000);
			_dc.Recalculate_Page(0, true);

			_dc.Reset(0, 0, par.Lines[0].Ranges[0].W + 0.001, 10000);
			_dc.Recalculate_Page(0, true);
			//par.Reset(0, 0, 10000, 10000, 0);
			//par.Recalculate_Page(0);

			var y = 0;
			var b = dKoefToMM * this.STYLE_THUMBNAIL_HEIGHT;
			var w = dKoefToMM * this.STYLE_THUMBNAIL_WIDTH;
			var off = 10 * dKoefToMM;
			var off2 = 5 * dKoefToMM;
			var off3 = 1 * dKoefToMM;

			graphics.transform(1, 0, 0, 1, 0, 0);
			graphics.save();
			graphics._s();
			graphics._m(off2, y + off3);
			graphics._l(w - off, y + off3);
			graphics._l(w - off, b - off3);
			graphics._l(off2, b - off3);
			graphics._z();
			graphics.clip();

			//graphics.t(style.Name, off + 0.5, y + 0.75 * (b - y));
			var baseline = par.Lines[0].Y;
			par.Shift(0, off + 0.5, y + 0.75 * (b - y) - baseline);
			par.Draw(0, graphics);

			graphics.restore();

			AscCommonWord.Default_Tab_Stop = oldDefTabStop;

			g_oTableId.m_bTurnOff = false;
			History.TurnOn();
		}
	}
};
CStylesPainter.prototype.get_MergedStyles = function ()
{
	return this.mergedStyles;
};



function TransformRectByMatrix(m, arr, offX, offY, koefX, koefY)
{
	var ret = [];
	ret.push(offX + koefX * m.TransformPointX(arr[0], arr[1]));
	ret.push(offY + koefY * m.TransformPointY(arr[0], arr[1]));

	ret.push(offX + koefX * m.TransformPointX(arr[2], arr[1]));
	ret.push(offY + koefY * m.TransformPointY(arr[2], arr[1]));

	ret.push(offX + koefX * m.TransformPointX(arr[2], arr[3]));
	ret.push(offY + koefY * m.TransformPointY(arr[2], arr[3]));

	ret.push(offX + koefX * m.TransformPointX(arr[0], arr[3]));
	ret.push(offY + koefY * m.TransformPointY(arr[0], arr[3]));
	return ret;
}

//--------------------------------------------------------export----------------------------------------------------
window['AscCommon'] = window['AscCommon'] || {};
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommon'].CPage = CPage;
window['AscCommon'].CDrawingDocument = CDrawingDocument;

window['AscCommonWord'].CStylesPainter = CStylesPainter;
CStylesPainter.prototype['get_MergedStyles'] = CStylesPainter.prototype.get_MergedStyles;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

function scrollUpHover(elem)
{
    elem.style.backgroundPosition = "0px -19px";
}
function scrollUpOut(elem)
{
    elem.style.backgroundPosition = "0px 0px";
}
function scrollUpDown(elem)
{
    elem.style.backgroundPosition = "0px -38px";
}

function scrollDownHover(elem)
{
    elem.style.backgroundPosition = "0px -19px";
}
function scrollDownOut(elem)
{
    elem.style.backgroundPosition = "0px -38px";
}
function scrollDownDown(elem)
{
    elem.style.backgroundPosition = "0px 0px";
}

function scrollLeftHover(elem)
{
    elem.style.backgroundPosition = "-19px 0px";
}
function scrollLeftOut(elem)
{
    elem.style.backgroundPosition = "0px 0px";
}
function scrollLeftDown(elem)
{
    elem.style.backgroundPosition = "-38px 0px";
}

function scrollRightHover(elem)
{
    elem.style.backgroundPosition = "-19px 0px";
}
function scrollRightOut(elem)
{
    elem.style.backgroundPosition = "-38px 0px";
}
function scrollRightDown(elem)
{
    elem.style.backgroundPosition = "0px 0px";
}

function scrollDragHover(elem)
{
    elem.style.backgroundColor = "#DDDDDD";
}
function scrollDragOut(elem)
{
    elem.style.backgroundColor = "#D3D3D3";
}
function scrollDragDown(elem)
{
    elem.style.backgroundColor = "#CCCCCC";
}

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var c_oAscDocumentUnits = Asc.c_oAscDocumentUnits;
var global_mouseEvent = AscCommon.global_mouseEvent;
var g_dKoef_pix_to_mm = AscCommon.g_dKoef_pix_to_mm;
var g_dKoef_mm_to_pix = AscCommon.g_dKoef_mm_to_pix;

function CTab(pos, type, leader)
{
	this.pos    = pos;
	this.type   = type;
	this.leader = leader;
}

var g_array_objects_length = 1;

var RULER_OBJECT_TYPE_PARAGRAPH = 1;
var RULER_OBJECT_TYPE_HEADER    = 2;
var RULER_OBJECT_TYPE_FOOTER    = 4;
var RULER_OBJECT_TYPE_TABLE     = 8;
var RULER_OBJECT_TYPE_COLUMNS   = 16;

function CHorRulerRepaintChecker()
{
    // zoom/section check
    this.Width = 0;
    this.Height = 0;

    // ruler type check
    this.Type = 0;

    // margin check
    this.MarginLeft = 0;
    this.MarginRight = 0;

    // table column check
    this.tableCols = [];
    this.marginsLeft = [];
    this.marginsRight = [];

    this.columns = null; // CColumnsMarkup

    // blit to main params
    this.BlitAttack = false;
    this.BlitLeft = 0;
    this.BlitIndentLeft = 0;
    this.BlitIndentLeftFirst = 0;
    this.BlitIndentRight = 0;
    this.BlitDefaultTab = 0;
    this.BlitTabs = null;

    this.BlitMarginLeftInd = 0;
    this.BlitMarginRightInd = 0;
}

function CVerRulerRepaintChecker()
{
    // zoom/section check
    this.Width = 0;
    this.Height = 0;

    // ruler type check
    this.Type = 0;

    // margin check
    this.MarginTop = 0;
    this.MarginBottom = 0;

    // header/footer check
    this.HeaderTop = 0;
    this.HeaderBottom = 0;

    // table column check
    this.rowsY = [];
    this.rowsH = [];

    // blit params
    this.BlitAttack = false;
    this.BlitTop = 0;
}

function RulerCorrectPosition(_ruler, val, margin)
{
    if (AscCommon.global_keyboardEvent.AltKey)
        return val;

    var mm_1_4 = 10 / 4;

    if (_ruler.Units == c_oAscDocumentUnits.Inch)
        mm_1_4 = 25.4 / 16;
    else if (_ruler.Units == c_oAscDocumentUnits.Point)
        mm_1_4 = 25.4 / 12;

    var mm_1_8 = mm_1_4 / 2;

    if (undefined === margin)
        return (((val + mm_1_8) / mm_1_4) >> 0) * mm_1_4;

    if (val >= margin)
        return margin + (((val - margin + mm_1_8) / mm_1_4) >> 0) * mm_1_4;

    return margin + (((val - margin - mm_1_8) / mm_1_4) >> 0) * mm_1_4;
}

function RulerCheckSimpleChanges()
{
    this.X = -1;
    this.Y = -1;
    this.IsSimple = true;

    this.IsDown   = false;
}
RulerCheckSimpleChanges.prototype =
{
    Clear : function()
    {
        this.X = -1;
        this.Y = -1;
        this.IsSimple = true;
        this.IsDown = false;
    },

    Reinit : function()
    {
        this.X = global_mouseEvent.X;
        this.Y = global_mouseEvent.Y;
        this.IsSimple = true;
        this.IsDown = true;
    },

    CheckMove : function()
    {
        if (!this.IsDown)
            return;
        if (!this.IsSimple)
            return;

        if (Math.abs(global_mouseEvent.X - this.X) > 0 || Math.abs(global_mouseEvent.Y - this.Y) > 0)
            this.IsSimple = false;
    }
};

function CHorRuler()
{
    this.m_oPage        = null;     // текущая страница. Нужна для размеров и маргинов в режиме RULER_OBJECT_TYPE_PARAGRAPH
    
    this.m_nTop         = 0;        // начало прямогулольника линейки
    this.m_nBottom      = 0;        // конец прямоугольника линейки

    // реализация tab'ов
    this.m_dDefaultTab              = 12.5;
    this.m_arrTabs                  = [];
    this.m_lCurrentTab              = -1;
    this.m_dCurrentTabNewPosition   = -1;
    this.m_dMaxTab                  = 0;
    this.IsDrawingCurTab            = true; // это подсказка для пользователя - будет ли оставлен таб после отпускания мышки, или будет выкинут

    this.m_dMarginLeft              = 20;
    this.m_dMarginRight             = 190;

    this.m_dIndentLeft          = 10;
    this.m_dIndentRight         = 20;
    this.m_dIndentLeftFirst     = 20;

    this.m_oCanvas              = null;

    this.m_dZoom                = 1;

    this.DragType = 0;  // 0 - none
                        // 1 - left margin, 2 - right margin
                        // 3 - indent left + indent left first, 4 - indent left // 5 - indent left first, 6 - indent right
                        // 7 - tabs
                        // 8 - table
                        // 9 - column size
                        // 10 - column move

    this.DragTypeMouseDown = 0;

    this.m_dIndentLeft_old      = -10000;
    this.m_dIndentLeftFirst_old = -10000;
    this.m_dIndentRight_old     = -10000;

    // отдельные настройки для текущего объекта линейки
    this.CurrentObjectType  = RULER_OBJECT_TYPE_PARAGRAPH;
    this.m_oTableMarkup     = null;
    this.m_oColumnMarkup    = null;
    this.DragTablePos       = -1;

    this.TableMarginLeft = 0;
    this.TableMarginLeftTrackStart = 0;
    this.TableMarginRight   = 0;

    this.m_oWordControl = null;

    this.RepaintChecker = new CHorRulerRepaintChecker();
    this.m_bIsMouseDown = false;

    // presentations addons
    this.IsCanMoveMargins = true;
    this.IsCanMoveAnyMarkers = true;
    this.IsDrawAnyMarkers = true;

    this.SimpleChanges = new RulerCheckSimpleChanges();

    this.Units = c_oAscDocumentUnits.Millimeter;

    this.InitTablePict = function()
    {
        var _data = g_memory.ctx.createImageData(7, 8);
        var _px = _data.data;
        var is2 = false;

        var black_level = 100;

        for (var j = 0; j < 8; j++)
        {
            var ind = j * 4 * 7;
            if (is2)
            {
                for (i = 0; i < 7; i++)
                {
                    _px[ind++] = black_level;
                    _px[ind++] = black_level;
                    _px[ind++] = black_level;
                    _px[ind++] = 255;
                }
            }
            else
            {
                var is22 = false;
                for (var i = 0; i < 7; i++)
                {
                    if (is22)
                    {
                        _px[ind++] = black_level;
                        _px[ind++] = black_level;
                        _px[ind++] = black_level;
                        _px[ind++] = 255;
                    }
                    else
                    {
                        _px[ind++] = 255;
                        _px[ind++] = 255;
                        _px[ind++] = 255;
                        _px[ind++] = 255;
                    }
                    is22 = !is22;
                }
            }
            is2 = !is2;
        }
        return _data;
    }

    this.InitTablePict2 = function()
    {
        var _data = g_memory.ctx.createImageData(14, 16);
        var _px = _data.data;

        var black_level = 100;

        for (var j = 0; j < 16; j++)
        {
            var ind = j * 4 * 14;
            var is2 = j - ((j >> 2) << 2);

            if (is2 >= 2)
            {
                for (i = 0; i < 14; i++)
                {
                    _px[ind++] = black_level;
                    _px[ind++] = black_level;
                    _px[ind++] = black_level;
                    _px[ind++] = 255;
                }
            }
            else
            {
                var is22 = false;
                for (var i = 0; i < 7; i++)
                {
                    if (is22)
                    {
                        _px[ind++] = black_level;
                        _px[ind++] = black_level;
                        _px[ind++] = black_level;
                        _px[ind++] = 255;
                        _px[ind++] = black_level;
                        _px[ind++] = black_level;
                        _px[ind++] = black_level;
                        _px[ind++] = 255;
                    }
                    else
                    {
                        _px[ind++] = 255;
                        _px[ind++] = 255;
                        _px[ind++] = 255;
                        _px[ind++] = 255;
                        _px[ind++] = 255;
                        _px[ind++] = 255;
                        _px[ind++] = 255;
                        _px[ind++] = 255;
                    }
                    is22 = !is22;
                }
            }
        }
        return _data;
    }

    this.CheckTableSprite = function(is_retina)
    {
        if (null != this.tableSprite)
        {
            if (!is_retina && this.tableSprite.width == 7)
                return;
            if (is_retina && this.tableSprite.width == 14)
                return;
        }
        if (!is_retina)
            this.tableSprite = this.InitTablePict();
        else
            this.tableSprite = this.InitTablePict2();
    }

    this.tableSprite = null;

    this.CheckCanvas = function()
    {
        this.m_dZoom = this.m_oWordControl.m_nZoomValue / 100;
        this.IsRetina = this.m_oWordControl.bIsRetinaSupport;

        this.CheckTableSprite(this.IsRetina);

        var dKoef_mm_to_pix = g_dKoef_mm_to_pix * this.m_dZoom;
        if (this.IsRetina)
            dKoef_mm_to_pix *= 2;

        var widthNew    = dKoef_mm_to_pix * this.m_oPage.width_mm;

        var _width      = 10 + widthNew;
        if (this.IsRetina)
            _width += 10;

        var _height     = 8 * g_dKoef_mm_to_pix;

        if (this.IsRetina)
            _height *= 2;

        var intW = _width >> 0;
        var intH = _height >> 0;
        if (null == this.m_oCanvas)
        {
            this.m_oCanvas = document.createElement('canvas');
            this.m_oCanvas.width    = intW;
            this.m_oCanvas.height   = intH;
        }
        else
        {
            var oldW = this.m_oCanvas.width;
            var oldH = this.m_oCanvas.height;

            if ((oldW != intW) || (oldH != intH))
            {
                delete this.m_oCanvas;
                this.m_oCanvas = document.createElement('canvas');
                this.m_oCanvas.width    = intW;
                this.m_oCanvas.height   = intH;
            }
        }
        return widthNew;
    }

    this.CreateBackground = function(cachedPage, isattack)
    {
        if (window["NATIVE_EDITOR_ENJINE"])
            return;
            
        if (null == cachedPage || undefined == cachedPage)
            return;

        this.m_oPage = cachedPage;
        var width = this.CheckCanvas();

        if (this.IsRetina)
            width >>= 1;

        if (0 == this.DragType)
        {
            this.m_dMarginLeft  = cachedPage.margin_left;
            this.m_dMarginRight = cachedPage.margin_right;
        }

        // check old state
        var checker = this.RepaintChecker;
        var markup = this.m_oTableMarkup;
        if (this.CurrentObjectType == RULER_OBJECT_TYPE_COLUMNS)
            markup = this.m_oColumnMarkup;

        if (isattack !== true && this.CurrentObjectType == checker.Type && width == checker.Width)
        {
            if (this.CurrentObjectType == RULER_OBJECT_TYPE_PARAGRAPH)
            {
                if (this.m_dMarginLeft == checker.MarginLeft && this.m_dMarginRight == checker.MarginRight)
                    return;
            }
            else if (this.CurrentObjectType == RULER_OBJECT_TYPE_TABLE)
            {
                var oldcount = checker.tableCols.length;
                var newcount = 1 + markup.Cols.length;

                if (oldcount == newcount)
                {
                    var arr1 = checker.tableCols;
                    var arr2 = markup.Cols;

                    if (arr1[0] == markup.X)
                    {
                        var _break = false;
                        for (var i = 1; i < newcount; i++)
                        {
                            if (arr1[i] != arr2[i - 1])
                            {
                                _break = true;
                                break;
                            }
                        }

                        if (!_break)
                        {
                            --newcount;
                            var _margs = markup.Margins;

                            for (var i = 0; i < newcount; i++)
                            {
                                if (_margs[i].Left != checker.marginsLeft[i] || _margs[i].Right != checker.marginsRight[i])
                                {
                                    _break = true;
                                    break;
                                }
                            }

                            if (!_break)
                                return;
                        }
                    }
                }
            }
            else if (this.CurrentObjectType == RULER_OBJECT_TYPE_COLUMNS)
            {
                if (this.m_oColumnMarkup.X == checker.columns.X)
                {
                    if (markup.EqualWidth == checker.columns.EqualWidth)
                    {
                        if (markup.EqualWidth)
                        {
                            if (markup.Num == checker.columns.Num && markup.Space == checker.columns.Space && markup.R == checker.columns.R)
                                return;
                        }
                        else
                        {
                            var _arr1 = markup.Cols;
                            var _arr2 = checker.columns.Cols;
                            if (_arr1 && _arr2 && _arr1.length == _arr2.length)
                            {
                                var _len = _arr1.length;
                                var _index = 0;
                                for (_index = 0; _index < _len; _index++)
                                {
                                    if (_arr1[_index].W != _arr2[_index].W || _arr1[_index].Space != _arr2[_index].Space)
                                        break;
                                }

                                if (_index == _len)
                                    return;
                            }
                        }
                    }
                }
            }
        }

        //console.log("horizontal");

        checker.Width = width;
        checker.Type = this.CurrentObjectType;
        checker.BlitAttack = true;

        var dKoef_mm_to_pix = g_dKoef_mm_to_pix * this.m_dZoom;

        // не править !!!
        this.m_nTop     = 6;//(1.8 * g_dKoef_mm_to_pix) >> 0;
        this.m_nBottom  = 19;//(5.2 * g_dKoef_mm_to_pix) >> 0;

        var context = this.m_oCanvas.getContext('2d');
        if (!this.IsRetina)
            context.setTransform(1, 0, 0, 1, 5, 0);
        else
            context.setTransform(2, 0, 0, 2, 10, 0);

        context.fillStyle = GlobalSkin.BackgroundColor;
        context.fillRect(0, 0, this.m_oCanvas.width, this.m_oCanvas.height);

		// промежуток между маргинами
        var left_margin  = 0;
        var right_margin = 0;

        if (this.CurrentObjectType == RULER_OBJECT_TYPE_PARAGRAPH)
        {
            left_margin  = (this.m_dMarginLeft * dKoef_mm_to_pix) >> 0;
            right_margin = (this.m_dMarginRight * dKoef_mm_to_pix) >> 0;

            checker.MarginLeft = this.m_dMarginLeft;
            checker.MarginRight = this.m_dMarginRight;
        }
        else if (this.CurrentObjectType == RULER_OBJECT_TYPE_TABLE && null != markup)
        {
            var _cols = checker.tableCols;
            if (0 != _cols.length)
                _cols.splice(0, _cols.length);

            _cols[0] = markup.X;
            var _ml = checker.marginsLeft;
            if (0 != _ml.length)
                _ml.splice(0, _ml.length);

            var _mr = checker.marginsRight;
            if (0 != _mr.length)
                _mr.splice(0, _mr.length);

            var _count_ = markup.Cols.length;

            for (var i = 0; i < _count_; i++)
            {
                _cols[i + 1] = markup.Cols[i];
                _ml[i] = markup.Margins[i].Left;
                _mr[i] = markup.Margins[i].Right;
            }

            if (0 != _count_)
            {
                var _start = 0;
                for (var i = 0; i < _count_; i++)
                {
                    _start += markup.Cols[i];
                }

                left_margin  = ((markup.X + markup.Margins[0].Left) * dKoef_mm_to_pix) >> 0;
                right_margin = ((markup.X + _start - markup.Margins[markup.Margins.length - 1].Right) * dKoef_mm_to_pix) >> 0;
            }
        }
        else if (this.CurrentObjectType == RULER_OBJECT_TYPE_COLUMNS && null != markup)
        {
            left_margin  = (markup.X * dKoef_mm_to_pix) >> 0;
            right_margin = (markup.R * dKoef_mm_to_pix) >> 0;

            checker.MarginLeft = this.m_dMarginLeft;
            checker.MarginRight = this.m_dMarginRight;

            checker.columns = this.m_oColumnMarkup.CreateDuplicate();
        }

        context.fillStyle = GlobalSkin.RulerLight;
        context.fillRect(left_margin + 0.5, this.m_nTop + 0.5, right_margin - left_margin, this.m_nBottom - this.m_nTop);

        var intW = width >> 0;

        if (window["flat_desine"] === true)
        {
            context.beginPath();
            context.fillStyle = GlobalSkin.RulerDark;

            context.fillRect(0.5, this.m_nTop + 0.5, left_margin, this.m_nBottom - this.m_nTop);
            context.fillRect(right_margin + 0.5, this.m_nTop + 0.5, Math.max(intW - right_margin, 1), this.m_nBottom - this.m_nTop);
            context.beginPath();
        }

		// рамка
        //context.shadowBlur = 0;
        //context.shadowColor = "#81878F";

        context.strokeStyle = GlobalSkin.RulerOutline;

        context.lineWidth = 1;
        context.strokeRect(0.5, this.m_nTop + 0.5, Math.max(intW - 1, 1), this.m_nBottom - this.m_nTop);
        context.beginPath();
        context.moveTo(left_margin + 0.5, this.m_nTop + 0.5);
        context.lineTo(left_margin + 0.5, this.m_nBottom - 0.5);

        context.moveTo(right_margin + 0.5, this.m_nTop + 0.5);
        context.lineTo(right_margin + 0.5, this.m_nBottom - 0.5);

        context.stroke();
        context.beginPath();

        context.strokeStyle = "#585B5E";
        context.fillStyle = "#585B5E";

        var mm_1_4 = 10 * dKoef_mm_to_pix / 4;
        var inch_1_8 = 25.4 * dKoef_mm_to_pix / 8;
        var isDraw1_4 = (mm_1_4 > 7) ? true : false;

        var middleVert = (this.m_nTop + this.m_nBottom) / 2;
        var part1 = 1;
        var part2 = 2.5;

        context.font = "7pt Arial";

        if (this.Units == c_oAscDocumentUnits.Millimeter)
        {
            var lCount1 = ((width - left_margin) / mm_1_4) >> 0;
            var lCount2 = (left_margin / mm_1_4) >> 0;

        var index = 0;
        var num = 0;
        for (var i = 1; i < lCount1; i++)
        {
            var lXPos = ((left_margin + i * mm_1_4) >> 0) + 0.5;
            index++;

            if (index == 4)
                index = 0;

            if (0 == index)
            {
                num++;
                // number
                var strNum = "" + num;
                var lWidthText = context.measureText(strNum).width;
                lXPos -= (lWidthText / 2.0);
                context.fillText(strNum, lXPos, this.m_nBottom - 3);
            }
            else if (1 == index && isDraw1_4)
            {
                // 1/4
                context.beginPath();
                context.moveTo(lXPos, middleVert - part1);
                context.lineTo(lXPos, middleVert + part1);
                context.stroke();
            }
            else if (2 == index)
            {
                // 1/2
                context.beginPath();
                context.moveTo(lXPos, middleVert - part2);
                context.lineTo(lXPos, middleVert + part2);
                context.stroke();
            }
            else if (isDraw1_4)
            {
                // 1/4
                context.beginPath();
                context.moveTo(lXPos, middleVert - part1);
                context.lineTo(lXPos, middleVert + part1);
                context.stroke();
            }
        }

        index = 0;
        num = 0;
        for (var i = 1; i <= lCount2; i++)
        {
            var lXPos = ((left_margin - i * mm_1_4) >> 0) + 0.5;
            index++;

            if (index == 4)
                index = 0;

            if (0 == index)
            {
                num++;
                // number
                var strNum = "" + num;
                var lWidthText = context.measureText(strNum).width;
                lXPos -= (lWidthText / 2.0);
                context.fillText(strNum, lXPos, this.m_nBottom - 3);
            }
            else if (1 == index && isDraw1_4)
            {
                // 1/4
                context.beginPath();
                context.moveTo(lXPos, middleVert - part1);
                context.lineTo(lXPos, middleVert + part1);
                context.stroke();
            }
            else if (2 == index)
            {
                // 1/2
                context.beginPath();
                context.moveTo(lXPos, middleVert - part2);
                context.lineTo(lXPos, middleVert + part2);
                context.stroke();
            }
            else if (isDraw1_4)
            {
                // 1/4
                context.beginPath();
                context.moveTo(lXPos, middleVert - part1);
                context.lineTo(lXPos, middleVert + part1);
                context.stroke();
            }
        }
        }
        else if (this.Units == c_oAscDocumentUnits.Inch)
        {
            var lCount1 = ((width - left_margin) / inch_1_8) >> 0;
            var lCount2 = (left_margin / inch_1_8) >> 0;

            var index = 0;
            var num = 0;
            for (var i = 1; i < lCount1; i++)
            {
                var lXPos = ((left_margin + i * inch_1_8) >> 0) + 0.5;
                index++;

                if (index == 8)
                    index = 0;

                if (0 == index)
                {
                    num++;
                    // number
                    var strNum = "" + num;
                    var lWidthText = context.measureText(strNum).width;
                    lXPos -= (lWidthText / 2.0);
                    context.fillText(strNum, lXPos, this.m_nBottom - 3);
                }
                else if (4 == index)
                {
                    // 1/2
                    context.beginPath();
                    context.moveTo(lXPos, middleVert - part2);
                    context.lineTo(lXPos, middleVert + part2);
                    context.stroke();
                }
                else if (inch_1_8 > 8)
                {
                    // 1/8
                    context.beginPath();
                    context.moveTo(lXPos, middleVert - part1);
                    context.lineTo(lXPos, middleVert + part1);
                    context.stroke();
                }
            }

            index = 0;
            num = 0;
            for (var i = 1; i <= lCount2; i++)
            {
                var lXPos = ((left_margin - i * inch_1_8) >> 0) + 0.5;
                index++;

                if (index == 8)
                    index = 0;

                if (0 == index)
                {
                    num++;
                    // number
                    var strNum = "" + num;
                    var lWidthText = context.measureText(strNum).width;
                    lXPos -= (lWidthText / 2.0);
                    context.fillText(strNum, lXPos, this.m_nBottom - 3);
                }
                else if (4 == index)
                {
                    // 1/2
                    context.beginPath();
                    context.moveTo(lXPos, middleVert - part2);
                    context.lineTo(lXPos, middleVert + part2);
                    context.stroke();
                }
                else if (inch_1_8 > 8)
                {
                    // 1/8
                    context.beginPath();
                    context.moveTo(lXPos, middleVert - part1);
                    context.lineTo(lXPos, middleVert + part1);
                    context.stroke();
                }
            }
        }
        else if (this.Units == c_oAscDocumentUnits.Point)
        {
            var point_1_12 = 25.4 * dKoef_mm_to_pix / 12;

            var lCount1 = ((width - left_margin) / point_1_12) >> 0;
            var lCount2 = (left_margin / point_1_12) >> 0;

            var index = 0;
            var num = 0;
            for (var i = 1; i < lCount1; i++)
            {
                var lXPos = ((left_margin + i * point_1_12) >> 0) + 0.5;
                index++;

                if (index == 12)
                    index = 0;

                if (0 == index || 6 == index)
                {
                    num++;
                    // number
                    var strNum = "" + (num * 36);
                    var lWidthText = context.measureText(strNum).width;
                    lXPos -= (lWidthText / 2.0);
                    context.fillText(strNum, lXPos, this.m_nBottom - 3);
                }
                else if (point_1_12 > 5)
                {
                    // 1/12
                    context.beginPath();
                    context.moveTo(lXPos, middleVert - part1);
                    context.lineTo(lXPos, middleVert + part1);
                    context.stroke();
                }
            }

            index = 0;
            num = 0;
            for (var i = 1; i <= lCount2; i++)
            {
                var lXPos = ((left_margin - i * point_1_12) >> 0) + 0.5;
                index++;

                if (index == 12)
                    index = 0;

                if (0 == index || 6 == index)
                {
                    num++;
                    // number
                    var strNum = "" + (num * 36);
                    var lWidthText = context.measureText(strNum).width;
                    lXPos -= (lWidthText / 2.0);
                    context.fillText(strNum, lXPos, this.m_nBottom - 3);
                }
                else if (point_1_12 > 5)
                {
                    // 1/12
                    context.beginPath();
                    context.moveTo(lXPos, middleVert - part1);
                    context.lineTo(lXPos, middleVert + part1);
                    context.stroke();
                }
            }
        }

        if (null != markup && this.CurrentObjectType == RULER_OBJECT_TYPE_TABLE)
        {
            var _count = markup.Cols.length;
            if (0 != _count)
            {
                context.fillStyle = GlobalSkin.RulerDark;
                context.strokeStyle = GlobalSkin.RulerOutline;

                var _offset = markup.X;
                for (var i = 0; i <= _count; i++)
                {
                    var __xID = 0;
                    if (!this.IsRetina)
                        __xID = (2.5 + _offset * dKoef_mm_to_pix) >> 0;
                    else
                        __xID = ((2.5 + _offset * dKoef_mm_to_pix) * 2) >> 0;

                    var __yID = this.m_nBottom - 10;
                    if (this.IsRetina)
                        __yID <<= 1;

                    if (0 == i)
                    {
                        context.putImageData(this.tableSprite, __xID, __yID);
                        _offset += markup.Cols[i];
                        continue;
                    }
                    if (i == _count)
                    {
                        context.putImageData(this.tableSprite, __xID, __yID);
                        break;
                    }

                    var __x = (((_offset - markup.Margins[i-1].Right) * dKoef_mm_to_pix) >> 0) + 0.5;
                    var __r = (((_offset + markup.Margins[i].Left) * dKoef_mm_to_pix) >> 0) + 0.5;

                    context.fillRect(__x, this.m_nTop + 0.5, __r - __x, this.m_nBottom - this.m_nTop);
                    context.strokeRect(__x, this.m_nTop + 0.5, __r - __x, this.m_nBottom - this.m_nTop);

                    if (!this.IsRetina)
                        context.putImageData(this.tableSprite, __xID, __yID);
                    else
                        context.putImageData(this.tableSprite, __xID, __yID);

                    _offset += markup.Cols[i];
                }
            }
        }

        if (null != markup && this.CurrentObjectType == RULER_OBJECT_TYPE_COLUMNS)
        {
            var _array = markup.EqualWidth ? [] : markup.Cols;
            if (markup.EqualWidth)
            {
                var _w = ((markup.R - markup.X) - markup.Space * (markup.Num - 1)) / markup.Num;

                for (var i = 0; i < markup.Num; i++)
                {
                    var _cur = new CColumnsMarkupColumn();
                    _cur.W = _w;
                    _cur.Space = markup.Space;
                    _array.push(_cur);
                }
            }

            var _count = _array.length;
            if (0 != _count)
            {
                context.fillStyle = GlobalSkin.RulerDark;
                context.strokeStyle = GlobalSkin.RulerOutline;

                var _offsetX = markup.X;
                for (var i = 0; i < _count; i++)
                {
                    var __xTmp = _offsetX + _array[i].W;
                    var __rTmp = __xTmp + _array[i].Space;

                    var _offset = (__xTmp + __rTmp) / 2;

                    if (i == (_count - 1))
                        continue;

                    var __xID = 0;
                    if (!this.IsRetina)
                        __xID = (2.5 + _offset * dKoef_mm_to_pix) >> 0;
                    else
                        __xID = (5 + _offset * dKoef_mm_to_pix * 2) >> 0;

                    var __yID = this.m_nBottom - 10;
                    if (this.IsRetina)
                        __yID <<= 1;

                    var __x = ((__xTmp * dKoef_mm_to_pix) >> 0) + 0.5;
                    var __r = ((__rTmp * dKoef_mm_to_pix) >> 0) + 0.5;

                    context.fillRect(__x, this.m_nTop + 0.5, __r - __x, this.m_nBottom - this.m_nTop);
                    context.strokeRect(__x, this.m_nTop + 0.5, __r - __x, this.m_nBottom - this.m_nTop);

                    if (!markup.EqualWidth)
                        context.putImageData(this.tableSprite, __xID, __yID);

                    if ((__r - __x) > 10)
                    {
                        context.fillStyle = GlobalSkin.RulerLight;
                        context.strokeStyle = "#81878F";
                        context.fillRect(__x + 3, this.m_nTop + 0.5 + 3, 3, this.m_nBottom - this.m_nTop - 6);
                        context.fillRect(__r - 6, this.m_nTop + 0.5 + 3, 3, this.m_nBottom - this.m_nTop - 6);
                        context.strokeRect(__x + 3, this.m_nTop + 0.5 + 3, 3, this.m_nBottom - this.m_nTop - 6);
                        context.strokeRect(__r - 6, this.m_nTop + 0.5 + 3, 3, this.m_nBottom - this.m_nTop - 6);
                        context.fillStyle = GlobalSkin.RulerDark;
                        context.strokeStyle = GlobalSkin.RulerOutline;
                    }

                    _offsetX += (_array[i].W + _array[i].Space);
                }
            }
        }
    }

    this.CorrectTabs = function()
    {
        this.m_dMaxTab = 0;
        var _old_c = this.m_arrTabs.length;
        if (0 == _old_c)
            return;

        var _old = this.m_arrTabs;
        var _new = [];

        for (var i = 0; i < _old_c; i++)
        {
            for (var j = i + 1; j < _old_c; j++)
            {
                if (_old[j].pos < _old[i].pos)
                {
                    var temp = _old[i];
                    _old[i] = _old[j];
                    _old[j] = temp;
                }
            }
        }

        var _new_len = 0;
        _new[_new_len++] = _old[0];
        for (var i = 1; i < _old_c; i++)
        {
            if (_new[_new_len - 1].pos != _old[i].pos)
                _new[_new_len++] = _old[i];
        }
        this.m_arrTabs = null;
        this.m_arrTabs = _new;

        this.m_dMaxTab = this.m_arrTabs[_new_len - 1].pos;
    }

    this.CalculateMargins = function()
    {
        if (this.CurrentObjectType == RULER_OBJECT_TYPE_TABLE)
        {
            this.TableMarginLeft = 0;
            this.TableMarginRight = 0;

            var markup = this.m_oTableMarkup;
            var margin_left = markup.X;

            var _col = markup.CurCol;
            for (var i = 0; i < _col; i++)
                margin_left += markup.Cols[i];

            this.TableMarginLeft = margin_left + markup.Margins[_col].Left;
            this.TableMarginRight = margin_left + markup.Cols[_col] - markup.Margins[_col].Right;
        }
        else if (this.CurrentObjectType == RULER_OBJECT_TYPE_COLUMNS)
        {
            this.TableMarginLeft = 0;
            this.TableMarginRight = 0;

            var markup = this.m_oColumnMarkup;

            if (markup.EqualWidth)
            {
                var _w = ((markup.R - markup.X) - markup.Space * (markup.Num - 1)) / markup.Num;

                this.TableMarginLeft = markup.X + (_w  + markup.Space) * markup.CurCol;
                this.TableMarginRight = this.TableMarginLeft + _w;
            }
            else
            {
                var margin_left = markup.X;
                var _col = markup.CurCol;
                for (var i = 0; i < _col; i++)
                    margin_left += (markup.Cols[i].W + markup.Cols[i].Space);

                this.TableMarginLeft = margin_left;
                this.TableMarginRight = margin_left + markup.Cols[_col].W;

                var _x = markup.X;

                var _len = markup.Cols.length;
                for (var i = 0; i < _len; i++)
                {
                    _x += markup.Cols[i].W;

                    if (i != (_len - 1))
                        _x += markup.Cols[i].Space;
                }

                markup.R = _x;
            }
        }
    }

    this.OnMouseMove = function(left, top, e)
    {
        var word_control = this.m_oWordControl;

        AscCommon.check_MouseMoveEvent(e);

        this.SimpleChanges.CheckMove();

		// теперь определяем позицию относительно самой линейки. Все в миллиметрах
        var hor_ruler = word_control.m_oTopRuler_horRuler;
        var dKoefPxToMM = 100 * g_dKoef_pix_to_mm / word_control.m_nZoomValue;

        var _x = global_mouseEvent.X - 5 * g_dKoef_mm_to_pix - left - word_control.X - word_control.GetMainContentBounds().L * g_dKoef_mm_to_pix;
        _x *= dKoefPxToMM;
        var _y = (global_mouseEvent.Y - word_control.Y) * g_dKoef_pix_to_mm;

        var dKoef_mm_to_pix = g_dKoef_mm_to_pix * this.m_dZoom;
        var mm_1_4 = 10 / 4;
        var mm_1_8 = mm_1_4 / 2;

        var _margin_left = this.m_dMarginLeft;
        var _margin_right = this.m_dMarginRight;
        if (this.CurrentObjectType == RULER_OBJECT_TYPE_TABLE || this.CurrentObjectType == RULER_OBJECT_TYPE_COLUMNS)
        {
            _margin_left = this.TableMarginLeft;
            _margin_right = this.TableMarginRight;
        }

        var _presentations = false;
        if (word_control.EditorType === "presentations")
            _presentations = true;

        switch (this.DragType)
        {
            case 0:
            {
                var position = this.CheckMouseType(_x, _y);
                if ((1 == position) || (2 == position) || (8 == position) || (9 == position) || (10 == position))
                    word_control.m_oDrawingDocument.SetCursorType("w-resize");
                else
                    word_control.m_oDrawingDocument.SetCursorType("default");

                break;
            }
            case 1:
            {
                var newVal = RulerCorrectPosition(this, _x, _margin_left);

                if (newVal < 0)
                    newVal = 0;

                var max = this.m_dMarginRight - 20;
                if (0 < this.m_dIndentRight)
                    max = (this.m_dMarginRight - this.m_dIndentRight - 20);
                if (newVal > max)
                    newVal = max;

                var _max_ind = Math.max(this.m_dIndentLeft, this.m_dIndentLeftFirst);
                if ((newVal + _max_ind) > max)
                    newVal = max - _max_ind;

                this.m_dMarginLeft = newVal;
                word_control.UpdateHorRulerBack();

                var pos = left + this.m_dMarginLeft * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);

                word_control.m_oDrawingDocument.SetCursorType("w-resize");
                break;
            }
            case 2:
            {
                var newVal = RulerCorrectPosition(this, _x, _margin_left);

                var min = this.m_dMarginLeft;
                if ((this.m_dMarginLeft + this.m_dIndentLeft) > min)
                    min = this.m_dMarginLeft + this.m_dIndentLeft;
                if ((this.m_dMarginLeft + this.m_dIndentLeftFirst) > min)
                    min = this.m_dMarginLeft + this.m_dIndentLeftFirst;

                min += 20;
                if (newVal < min)
                    newVal = min;
                if (newVal > this.m_oPage.width_mm)
                    newVal = this.m_oPage.width_mm;

                if ((newVal - this.m_dIndentRight) < min)
                    newVal = min + this.m_dIndentRight;

                this.m_dMarginRight = newVal;
                word_control.UpdateHorRulerBack();

                var pos = left + this.m_dMarginRight * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);

                word_control.m_oDrawingDocument.SetCursorType("w-resize");
                break;
            }
            case 3:
            {
                var newVal = RulerCorrectPosition(this, _x, _margin_left);

                var min = 0;
                if (this.m_dIndentLeftFirst < this.m_dIndentLeft)
                    min = this.m_dIndentLeft - this.m_dIndentLeftFirst;

                if (newVal < min)
                    newVal = min;

                if (_presentations)
                {
                    min = _margin_left;
                    if (this.m_dIndentLeftFirst < this.m_dIndentLeft)
                        min += (this.m_dIndentLeft - this.m_dIndentLeftFirst);
                    if (newVal < min)
                        newVal = min;
                }

                var max = _margin_right;
                if (0 < this.m_dIndentRight)
                    max = _margin_right - this.m_dIndentRight;
                if (this.m_dIndentLeftFirst > this.m_dIndentLeft)
                {
                    max = max + (this.m_dIndentLeft - this.m_dIndentLeftFirst);
                }

                if (newVal > (max - 20))
                    newVal = Math.max(max - 20, (this.m_dIndentLeft_old + _margin_left));

                var newIndent = newVal - _margin_left;
                this.m_dIndentLeftFirst = (this.m_dIndentLeftFirst - this.m_dIndentLeft) + newIndent;
                this.m_dIndentLeft = newIndent;
                word_control.UpdateHorRulerBack();

                var pos = left + (_margin_left + this.m_dIndentLeft) * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);

                break;
            }
            case 4:
            {
                var newVal = RulerCorrectPosition(this, _x, _margin_left);

                if (newVal < 0)
                    newVal = 0;

                var max = _margin_right - 20;
                if (0 < this.m_dIndentRight)
                    max -= this.m_dIndentRight;

                if (_presentations)
                {
                    if (newVal < _margin_left)
                        newVal = _margin_left;
                }

                if (newVal > max)
                    newVal = Math.max(max, _margin_left + this.m_dIndentLeft_old);

                this.m_dIndentLeft = newVal - _margin_left;
                word_control.UpdateHorRulerBack();

                var pos = left + (_margin_left + this.m_dIndentLeft) * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);

                break;
            }
            case 5:
            {
                var newVal = RulerCorrectPosition(this, _x, _margin_left);

                if (newVal < 0)
                    newVal = 0;

                var max = _margin_right - 20;
                if (0 < this.m_dIndentRight)
                    max -= this.m_dIndentRight;

                if (_presentations)
                {
                    if (newVal < _margin_left)
                        newVal = _margin_left;
                }

                if (newVal > max)
                    newVal = Math.max(max, _margin_left + this.m_dIndentLeftFirst_old);

                this.m_dIndentLeftFirst = newVal - _margin_left;
                word_control.UpdateHorRulerBack();

                var pos = left + (_margin_left + this.m_dIndentLeftFirst) * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);

                break;
            }
            case 6:
            {
                var newVal = RulerCorrectPosition(this, _x, _margin_left);

                if (newVal > (this.m_oPage.width_mm))
                    newVal = this.m_oPage.width_mm;

                var min = _margin_left;
                if ((_margin_left + this.m_dIndentLeft) > min)
                    min = _margin_left + this.m_dIndentLeft;
                if ((_margin_left + this.m_dIndentLeftFirst) > min)
                    min = _margin_left + this.m_dIndentLeftFirst;

                min += 20;

                if (newVal < min)
                    newVal = Math.min(min, _margin_right - this.m_dIndentRight_old);

                if (_presentations)
                {
                    if (newVal > _margin_right)
                        newVal = _margin_right;
                }

                this.m_dIndentRight = _margin_right - newVal;
                word_control.UpdateHorRulerBack();

                var pos = left + (_margin_right - this.m_dIndentRight) * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);

                break;
            }
            case 7:
            {
                var newVal = RulerCorrectPosition(this, _x, _margin_left);

                this.m_dCurrentTabNewPosition = newVal - _margin_left;

                var pos = left + (_margin_left + this.m_dCurrentTabNewPosition) * dKoef_mm_to_pix;

                if (_y <= 3 || _y > 5.6)
                {
                    this.IsDrawingCurTab = false;
                    word_control.OnUpdateOverlay();
                }
                else
                {
                    this.IsDrawingCurTab = true;
                }

                word_control.UpdateHorRulerBack();

                if (this.IsDrawingCurTab)
                    word_control.m_oOverlayApi.VertLine(pos);
                break;
            }
            case 8:
            {
                var newVal = RulerCorrectPosition(this, _x, this.TableMarginLeftTrackStart);

                // сначала определим граничные условия
                var _min = 0;
                var _max = this.m_oPage.width_mm;

                var markup = this.m_oTableMarkup;
                var _left = 0;

                if (this.DragTablePos > 0)
                {
                    var start = markup.X;
                    for (var i = 1; i < this.DragTablePos; i++)
                        start += markup.Cols[i - 1];
                    _left = start;

                    start += markup.Margins[this.DragTablePos - 1].Left;
                    start += markup.Margins[this.DragTablePos - 1].Right;

                    _min = start;
                }

                if (newVal < _min)
                    newVal = _min;
                if (newVal > _max)
                    newVal = _max;

                if (0 == this.DragTablePos)
                {
                    markup.X = newVal;
                }
                else
                {
                    markup.Cols[this.DragTablePos - 1] = newVal - _left;
                }

                this.CalculateMargins();
                word_control.UpdateHorRulerBack();

                var pos = left + newVal * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);
                break;
            }
            case 9:
            {
                var newVal = RulerCorrectPosition(this, _x, this.TableMarginLeftTrackStart);

                // сначала определим граничные условия
                var markup = this.m_oColumnMarkup;

                if (markup.EqualWidth)
                {
                    if (0 == this.DragTablePos)
                    {
                        var _min = 0;
                        var _max = markup.R - markup.Num * 10 - (markup.Num - 1) * markup.Space;

                        if (newVal < _min)
                            newVal = _min;
                        if (newVal > _max)
                            newVal = _max;

                        markup.X = newVal;
                    }
                    else if ((2 * markup.Num - 1) == this.DragTablePos)
                    {
                        var _min = markup.X + markup.Num * 10 + (markup.Num - 1) * markup.Space;
                        var _max = this.m_oPage.width_mm;

                        if (newVal < _min)
                            newVal = _min;
                        if (newVal > _max)
                            newVal = _max;

                        markup.R = newVal;
                    }
                    else
                    {
                        var bIsLeftSpace = ((this.DragTablePos & 1) == 1);
                        var _spaceMax = (markup.R - markup.X - 10 * markup.Num) / (markup.Num - 1);

                        var _col = ((this.DragTablePos + 1) >> 1);
                        var _center = _col * (markup.R - markup.X + markup.Space) / markup.Num - markup.Space / 2;

                        newVal -= markup.X;

                        if (bIsLeftSpace)
                        {
                            var _min = _center - _spaceMax / 2;
                            var _max = _center;

                            if (newVal < _min)
                                newVal = _min;
                            if (newVal > _max)
                                newVal = _max;

                            markup.Space = Math.abs((newVal - _center) * 2);
                        }
                        else
                        {
                            var _min = _center;
                            var _max = _center + _spaceMax / 2;

                            if (newVal < _min)
                                newVal = _min;
                            if (newVal > _max)
                                newVal = _max;

                            markup.Space = Math.abs((newVal - _center) * 2);
                        }

                        newVal += markup.X;
                    }
                }
                else
                {
                    var bIsLeftSpace = ((this.DragTablePos & 1) == 1);
                    var nSpaceNumber = ((this.DragTablePos + 1) >> 1);
                    var _min = 0;
                    var _max = this.m_oPage.width_mm;

                    if (0 == nSpaceNumber)
                    {
                        _max = markup.X + markup.Cols[0].W - 10;

                        if (newVal < _min)
                            newVal = _min;
                        if (newVal > _max)
                            newVal = _max;

                        var _delta = markup.X - newVal;
                        markup.X -= _delta;
                        markup.Cols[0].W += _delta;
                    }
                    else
                    {
                        var _offsetX = markup.X;
                        for (var i = 0; i < nSpaceNumber; i++)
                        {
                            _min = _offsetX;

                            _offsetX += markup.Cols[i].W;
                            if (!bIsLeftSpace || i != (nSpaceNumber - 1))
                            {
                                _min = _offsetX;
                                _offsetX += markup.Cols[i].Space;
                            }
                        }

                        if (bIsLeftSpace)
                        {
                            if (nSpaceNumber != markup.Num)
                                _max = _min + markup.Cols[nSpaceNumber - 1].W + markup.Cols[nSpaceNumber - 1].Space;

                            var _natMin = _min + 10;

                            if (newVal < _natMin)
                                newVal = _natMin;
                            if (newVal > _max)
                                newVal = _max;

                            markup.Cols[nSpaceNumber - 1].W = newVal - _min;
                            markup.Cols[nSpaceNumber - 1].Space = _max - newVal;

                            if (nSpaceNumber == markup.Num)
                            {
                                markup.R = newVal;
                            }
                        }
                        else
                        {
                            _max = _min + markup.Cols[nSpaceNumber - 1].Space + markup.Cols[nSpaceNumber].W;
                            var _natMax = _max - 10;

                            if (newVal < _min)
                                newVal = _min;
                            if (newVal > _natMax)
                                newVal = _natMax;

                            markup.Cols[nSpaceNumber - 1].Space = newVal - _min;
                            markup.Cols[nSpaceNumber].W = _max - newVal;
                        }
                    }
                }

                this.CalculateMargins();
                word_control.UpdateHorRulerBack();

                var pos = left + newVal * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);
                break;
            }
            case 10:
            {
                var newVal = RulerCorrectPosition(this, _x, this.TableMarginLeftTrackStart);

                // сначала определим граничные условия
                var markup = this.m_oColumnMarkup;

                var _min = markup.X;
                for (var i = 0; i < this.DragTablePos; i++)
                {
                    _min += (markup.Cols[i].W + markup.Cols[i].Space);
                }

                var _max = _min + markup.Cols[this.DragTablePos].W + markup.Cols[this.DragTablePos].Space;
                _max += markup.Cols[this.DragTablePos + 1].W;

                var _space = markup.Cols[this.DragTablePos].Space;

                var _natMin = _min + _space / 2 + 10;
                var _natMax = _max - _space / 2 - 10;

                if (newVal < _natMin)
                    newVal = _natMin;
                if (newVal > _natMax)
                    newVal = _natMax;

                var _delta = newVal - (_min + markup.Cols[this.DragTablePos].W + markup.Cols[this.DragTablePos].Space / 2);
                markup.Cols[this.DragTablePos].W += _delta;
                markup.Cols[this.DragTablePos + 1].W -= _delta;

                this.CalculateMargins();
                word_control.UpdateHorRulerBack();

                var pos = left + newVal * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);
                break;
            }
        }
    }

    this.CheckMouseType = function(x, y, isMouseDown, isNegative)
    {
		// проверяем где находимся

        var _top = 1.8;
        var _bottom = 5.2;

        var _margin_left = this.m_dMarginLeft;
        var _margin_right = this.m_dMarginRight;
        if (this.CurrentObjectType == RULER_OBJECT_TYPE_TABLE || this.CurrentObjectType == RULER_OBJECT_TYPE_COLUMNS)
        {
            _margin_left = this.TableMarginLeft;
            _margin_right = this.TableMarginRight;
        }

        var posL = _margin_left;
        if ((_margin_left + this.m_dIndentLeft) > posL)
            posL = _margin_left + this.m_dIndentLeft;
        if ((_margin_left + this.m_dIndentLeftFirst) > posL)
            posL = _margin_left + this.m_dIndentLeftFirst;

        var posR = _margin_right;
        if (this.m_dIndentRight > 0)
            posR = _margin_right - this.m_dIndentRight;

        if (this.IsCanMoveAnyMarkers && posL < posR)
        {
            // tabs
            if (y >= 3 && y <= _bottom)
            {
                var _count_tabs = this.m_arrTabs.length;
                for (var i = 0; i < _count_tabs; i++)
                {
                    var _pos = _margin_left + this.m_arrTabs[i].pos;
                    if ((x >= (_pos - 1)) && (x <= (_pos + 1)))
                    {
                        if (true === isMouseDown)
                            this.m_lCurrentTab = i;
                        return 7;
                    }
                }
            }

            // left indent
            var dCenterX = _margin_left +  this.m_dIndentLeft;

            var var1 = dCenterX - 1;
            var var2 = 1.4;
            var var3 = 1.5;
            var var4 = dCenterX + 1;

            if ((x >= var1) && (x <= var4))
            {
                if ((y >= _bottom) && (y < (_bottom + var2)))
                    return 3;
                else if ((y > (_bottom - var3)) && (y < _bottom))
                    return 4;
            }

            // right indent
            dCenterX = _margin_right -  this.m_dIndentRight;

            var1 = dCenterX - 1;
            var4 = dCenterX + 1;

            if ((x >= var1) && (x <= var4))
            {
                if ((y > (_bottom - var3)) && (y < _bottom))
                    return 6;
            }

            // first line indent
            dCenterX = _margin_left +  this.m_dIndentLeftFirst;

            var1 = dCenterX - 1;
            var4 = dCenterX + 1;

            if ((x >= var1) && (x <= var4))
            {
                if ((y > (_top - 1)) && (y < (_top + 1.68)))
                {
                    if (0 == this.m_dIndentLeftFirst && 0 == this.m_dIndentLeft && this.CurrentObjectType == RULER_OBJECT_TYPE_PARAGRAPH && this.IsCanMoveMargins)
                    {
                        if (y > (_top + 1))
                            return 1;
                    }
                    return 5;
                }
            }
        }

        var isColumnsInside = false;
		var isColumnsInside2 = false;
        var isTableInside = false;

        if (this.CurrentObjectType == RULER_OBJECT_TYPE_PARAGRAPH && this.IsCanMoveMargins)
        {
            if (y >= _top && y <= _bottom)
            {
				// внутри линейки
                if (Math.abs(x - this.m_dMarginLeft) < 1)
                {
                    return 1;
                }
                else if (Math.abs(x - this.m_dMarginRight) < 1)
                {
                    return 2;
                }

                if (isNegative)
                {
                    if (x < this.m_dMarginLeft)
                        return -1;
                    if (x > this.m_dMarginRight)
                        return -2;
                }
            }
        }
        else if (this.CurrentObjectType == RULER_OBJECT_TYPE_TABLE)
        {
            var nTI_x = 0;
            var nTI_r = 0;
            if (y >= _top && y <= _bottom)
            {
                var markup = this.m_oTableMarkup;
                var pos = markup.X;
                var _count = markup.Cols.length;
                for (var i = 0; i <= _count; i++)
                {
                    if (Math.abs(x - pos) < 1)
                    {
                        this.DragTablePos = i;
                        return 8;
                    }
                    if (i == _count)
                    {
                        nTI_r = pos;
                        break;
					}
					if (i == 0)
                    {
                        nTI_x = pos;
                    }
                    
                    pos += markup.Cols[i];
                }
            }

            if (x > nTI_x && x < nTI_r)
                isTableInside = true;
        }
        else if (this.CurrentObjectType == RULER_OBJECT_TYPE_COLUMNS)
        {
			if (y >= _top && y <= _bottom)
            {
                var markup = this.m_oColumnMarkup;

				var nCI_x = markup.X;
				var nCI_r = nCI_x;

                if (markup.EqualWidth)
                {
                    var _w = ((markup.R - markup.X) - markup.Space * (markup.Num - 1)) / markup.Num;
                    var _x = markup.X;

                    var _index = 0;
                    for (var i = 0; i < markup.Num; i++)
                    {
                        if (0 == i)
                        {
                            if (Math.abs(x - _x) < 1)
                            {
                                this.DragTablePos = _index;
                                return 9;
                            }
                        }
                        else
                        {
                            if (x < _x + 1 && x > _x - 2)
                            {
                                this.DragTablePos = _index;
                                return 9;
                            }
                        }

                        ++_index;
                        _x += _w;
                        nCI_r = _x;

                        if (i == markup.Num - 1)
                        {
                            if (Math.abs(x - _x) < 1)
                            {
                                this.DragTablePos = _index;
                                return 9;
                            }
                        }
                        else
                        {
                            if (x < _x + 2 && x > _x - 1)
                            {
                                this.DragTablePos = _index;
                                return 9;
                            }

							if (x > _x && x < (_x + markup.Space))
								isColumnsInside = true;
                        }

                        ++_index;
                        _x += markup.Space;
                    }
                }
                else
                {
                    var _x = markup.X;

                    var _index = 0;
                    for (var i = 0; i < markup.Cols.length; i++)
                    {
                        if (0 == i)
                        {
                            if (Math.abs(x - _x) < 1)
                            {
                                this.DragTablePos = _index;
                                return 9;
                            }
                        }
                        else
                        {
                            if (x < _x + 1 && x > _x - 2)
                            {
                                this.DragTablePos = _index;
                                return 9;
                            }
                        }

                        ++_index;
                        _x += markup.Cols[i].W;
						nCI_r = _x;

						if (i == markup.Num - 1)
                        {
                            if (Math.abs(x - _x) < 1)
                            {
                                this.DragTablePos = _index;
                                return 9;
                            }
                        }
                        else
                        {
                            if (x < _x + 2 && x > _x - 1)
                            {
                                this.DragTablePos = _index;
                                return 9;
                            }
                        }

                        if (i != markup.Cols.length - 1)
                        {
                            if (Math.abs(x - (_x + markup.Cols[i].Space / 2)) < 1)
                            {
                                this.DragTablePos = i;
                                return 10;
                            }

							if (x > _x && x < (_x + markup.Cols[i].Space))
								isColumnsInside = true;
                        }

                        ++_index;
                        _x += markup.Cols[i].Space;
                    }
                }

				if (x > nCI_x && x < nCI_r)
					isColumnsInside2 = true;
            }
        }

        if (isNegative)
        {
            if (isColumnsInside)
                return -9;

            // если вникуда - то ВСЕГДА margins
            return -1;

            if (isColumnsInside2)
                return 0;
            if ((y >= _top && y <= _bottom) && !isTableInside)
            {
				if (x < _margin_left)
					return -1;
				if (x > _margin_right)
					return -2;
            }
        }

        return 0;
    }

    this.OnMouseDown = function(left, top, e)
    {
        var word_control = this.m_oWordControl;

        if (true === word_control.m_oApi.isStartAddShape)
        {
			word_control.m_oApi.sync_EndAddShape();
			word_control.m_oApi.sync_StartAddShapeCallback(false);
        }

        AscCommon.check_MouseDownEvent(e, true);
        global_mouseEvent.LockMouse();

        this.SimpleChanges.Reinit();

        var dKoefPxToMM = 100 * g_dKoef_pix_to_mm / word_control.m_nZoomValue;
        var dKoef_mm_to_pix = g_dKoef_mm_to_pix * this.m_dZoom;
        
        var _x = global_mouseEvent.X - 5 * g_dKoef_mm_to_pix - left - word_control.X - word_control.GetMainContentBounds().L * g_dKoef_mm_to_pix;
        _x *= dKoefPxToMM;
        var _y = (global_mouseEvent.Y - word_control.Y) * g_dKoef_pix_to_mm;

        this.DragType = this.CheckMouseType(_x, _y, true, true);
        if (this.DragType < 0)
        {
			this.DragTypeMouseDown = -this.DragType;
			this.DragType = 0;
		}
		else
        {
            this.DragTypeMouseDown = this.DragType;
		}

		if (global_mouseEvent.ClickCount > 1)
        {
            var eventType = "";
            switch (this.DragTypeMouseDown)
            {
                case 1:
                case 2:
                {
					eventType = "margins";
                    break;
                }
                case 3:
                case 4:
                case 5:
                case 6:
                {
					eventType = "indents";
                    break;
                }
                case 7:
                {
					eventType = "tabs";
                    break;
                }
                case 8:
                {
					eventType = "tables";
                    break;
                }
                case 9:
                case 10:
                {
					eventType = "columns";
                    break;
                }
                default:
                    break;
            }

            if (eventType != "")
            {
				word_control.m_oApi.sendEvent("asc_onRulerDblClick", eventType);
                this.DragType = 0;
                this.OnMouseUp(left, top, e);
                return;
            }
        }

        var _margin_left = this.m_dMarginLeft;
        var _margin_right = this.m_dMarginRight;
        if (this.CurrentObjectType == RULER_OBJECT_TYPE_TABLE || this.CurrentObjectType == RULER_OBJECT_TYPE_COLUMNS)
        {
            _margin_left = this.TableMarginLeft;
            _margin_right = this.TableMarginRight;
        }

        this.m_bIsMouseDown = true;

        switch (this.DragType)
        {
            case 1:
            {
                var pos = left + _margin_left * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);
                break;
            }
            case 2:
            {
                var pos = left + _margin_right * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);
                break;
            }
            case 3:
            {
                var pos = left + (_margin_left + this.m_dIndentLeft) * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);

                this.m_dIndentLeft_old      = this.m_dIndentLeft;
                this.m_dIndentLeftFirst_old = this.m_dIndentLeftFirst;
                break;
            }
            case 4:
            {
                var pos = left + (_margin_left + this.m_dIndentLeft) * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);

                this.m_dIndentLeft_old      = this.m_dIndentLeft;
                break;
            }
            case 5:
            {
                var pos = left + (_margin_left + this.m_dIndentLeftFirst) * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);

                this.m_dIndentLeftFirst_old = this.m_dIndentLeftFirst;
                break;
            }
            case 6:
            {
                var pos = left + (_margin_right - this.m_dIndentRight) * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);

                this.m_dIndentRight_old     = this.m_dIndentRight;
                break;
            }
            case 7:
            {
                var pos = left + (_margin_left + this.m_arrTabs[this.m_lCurrentTab].pos) * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);
                break;
            }
            case 8:
            {
                var markup = this.m_oTableMarkup;
                var pos = markup.X;
                var _count = markup.Cols.length;
                for (var i = 0; i < this.DragTablePos; i++)
                {
                    pos += markup.Cols[i];
                }
                pos = left + pos * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);

                this.TableMarginLeftTrackStart = this.TableMarginLeft;
                break;
            }
            case 9:
            {
                var markup = this.m_oColumnMarkup;
                var pos = 0;
                if (markup.EqualWidth)
                {
                    var _w = ((markup.R - markup.X) - markup.Space * (markup.Num - 1)) / markup.Num;
                    var _x = markup.X + (this.DragTablePos >> 1) * (_w + markup.Space);
                    if (this.DragTablePos & 1 == 1)
                        _x += _w;

                    pos = _x;
                }
                else
                {
                    var _x = markup.X;

                    var _index = 0;
                    for (var i = 0; i < markup.Cols.length && _index < this.DragTablePos; i++)
                    {
                        if (_index == this.DragTablePos)
                            break;

                        ++_index;
                        _x += markup.Cols[i].W;

                        if (_index == this.DragTablePos)
                            break;

                        ++_index;
                        _x += markup.Cols[i].Space;
                    }

                    pos = _x;
                }

                pos = left + pos * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);

                this.TableMarginLeftTrackStart = markup.X;
                break;
            }
            case 10:
            {
                var markup = this.m_oColumnMarkup;
                var pos = markup.X;

                var _index = 0;
                for (var i = 0; i < markup.Cols.length && i < this.DragTablePos; i++)
                {
                    if (_index == this.DragTablePos)
                        break;

                    pos += markup.Cols[i].W;
                    pos += markup.Cols[i].Space;
                }

                if (this.DragTablePos < markup.Cols.length)
                {
                    pos += markup.Cols[this.DragTablePos].W;
                    pos += markup.Cols[this.DragTablePos].Space / 2;
                }

                pos = left + pos * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);
                this.TableMarginLeftTrackStart = markup.X;
                break;
            }
        }

        if (0 == this.DragType)
        {
            // посмотрим - может это добавляется таб
            var _top = 1.8;
            var _bottom = 5.2;

            // tabs
            if (_y >= 3 && _y <= _bottom && _x >= (_margin_left + this.m_dIndentLeft) && _x <= (_margin_right - this.m_dIndentRight))
            {
                var mm_1_4 = 10 / 4;
                var mm_1_8 = mm_1_4 / 2;

                var _new_tab_pos = RulerCorrectPosition(this, _x, _margin_left);
                _new_tab_pos -= _margin_left;

                this.m_arrTabs[this.m_arrTabs.length] = new CTab(_new_tab_pos, word_control.m_nTabsType);
                //this.CorrectTabs();
                word_control.UpdateHorRuler();

                this.m_lCurrentTab = this.m_arrTabs.length - 1;
                /*
                var _len = this.m_arrTabs.length;
                for (var i = 0; i < _len; i++)
                {
                    if (this.m_arrTabs[i].pos == _new_tab_pos)
                    {
                        this.m_lCurrentTab = i;
                        break;
                    }
                }
                */

                this.DragType = 7;
                this.m_dCurrentTabNewPosition = _new_tab_pos;

                var pos = left + (_margin_left + _new_tab_pos) * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.VertLine(pos);
            }
        }

        word_control.m_oDrawingDocument.LockCursorTypeCur();
    }
    this.OnMouseUp = function(left, top, e)
    {
        var word_control = this.m_oWordControl;
        this.m_oWordControl.OnUpdateOverlay();
        var lockedElement = AscCommon.check_MouseUpEvent(e);

        this.m_dIndentLeft_old      = -10000;
        this.m_dIndentLeftFirst_old = -10000;
        this.m_dIndentRight_old     = -10000;

        if (7 != this.DragType)
        {
            word_control.UpdateHorRuler();
            //word_control.m_oOverlayApi.UnShow();
        }

        var _margin_left = this.m_dMarginLeft;
        var _margin_right = this.m_dMarginRight;
        if (this.CurrentObjectType == RULER_OBJECT_TYPE_TABLE || this.CurrentObjectType == RULER_OBJECT_TYPE_COLUMNS)
        {
            _margin_left = this.TableMarginLeft;
            _margin_right = this.TableMarginRight;
        }

        switch (this.DragType)
        {
            case 1:
            case 2:
            {
                if (!this.SimpleChanges.IsSimple)
                    this.SetMarginProperties();
                break;
            }
            case 3:
            case 4:
            case 5:
            case 6:
            {
                if (!this.SimpleChanges.IsSimple)
                    this.SetPrProperties();
                else
                    word_control.OnUpdateOverlay();
                break;
            }
            case 7:
            {
                // смотрим, сохраняем ли таб
                var _y = (global_mouseEvent.Y - word_control.Y) * g_dKoef_pix_to_mm;
                if (_y <= 3 || _y > 5.6 || this.m_dCurrentTabNewPosition < this.m_dIndentLeft || (this.m_dCurrentTabNewPosition + _margin_left) > (_margin_right - this.m_dIndentRight))
                {
					if (-1 != this.m_lCurrentTab)
						this.m_arrTabs.splice(this.m_lCurrentTab, 1);
                }
                else
                {
					if (this.m_lCurrentTab < this.m_arrTabs.length)
						this.m_arrTabs[this.m_lCurrentTab].pos = this.m_dCurrentTabNewPosition;
                }

                this.m_lCurrentTab = -1;
                this.CorrectTabs();
                this.m_oWordControl.UpdateHorRuler();
                this.SetTabsProperties();
                break;
            }
            case 8:
            {
                if (!this.SimpleChanges.IsSimple)
                    this.SetTableProperties();
                this.DragTablePos = -1;
                break;
            }
            case 9:
            case 10:
            {
                if (!this.SimpleChanges.IsSimple)
                    this.SetColumnsProperties();
                this.DragTablePos = -1;
                break;
            }
        }

        if (7 == this.DragType)
        {
            word_control.UpdateHorRuler();
            //word_control.m_oOverlayApi.UnShow();
        }

        this.IsDrawingCurTab = true;
        this.DragType = 0;
        this.m_bIsMouseDown = false;

        this.m_oWordControl.m_oDrawingDocument.UnlockCursorType();
        this.SimpleChanges.Clear();
    }

    this.OnMouseUpExternal = function()
    {
        var word_control = this.m_oWordControl;
        this.m_oWordControl.OnUpdateOverlay();

        this.m_dIndentLeft_old      = -10000;
        this.m_dIndentLeftFirst_old = -10000;
        this.m_dIndentRight_old     = -10000;

        if (7 != this.DragType)
        {
            word_control.UpdateHorRuler();
            //word_control.m_oOverlayApi.UnShow();
        }

        var _margin_left = this.m_dMarginLeft;
        var _margin_right = this.m_dMarginRight;
        if (this.CurrentObjectType == RULER_OBJECT_TYPE_TABLE || this.CurrentObjectType == RULER_OBJECT_TYPE_COLUMNS)
        {
            _margin_left = this.TableMarginLeft;
            _margin_right = this.TableMarginRight;
        }

        switch (this.DragType)
        {
            case 1:
            case 2:
            {
                if (!this.SimpleChanges.IsSimple)
                    this.SetMarginProperties();
                break;
            }
            case 3:
            case 4:
            case 5:
            case 6:
            {
                if (!this.SimpleChanges.IsSimple)
                    this.SetPrProperties();
                break;
            }
            case 7:
            {
                // смотрим, сохраняем ли таб
                var _y = (global_mouseEvent.Y - word_control.Y) * g_dKoef_pix_to_mm;
                if (_y <= 3 || _y > 5.6 || this.m_dCurrentTabNewPosition < this.m_dIndentLeft || (this.m_dCurrentTabNewPosition + _margin_left) > (_margin_right - this.m_dIndentRight))
                {
					if (-1 != this.m_lCurrentTab)
						this.m_arrTabs.splice(this.m_lCurrentTab, 1);
                }
                else
                {
					if (this.m_lCurrentTab < this.m_arrTabs.length)
						this.m_arrTabs[this.m_lCurrentTab].pos = this.m_dCurrentTabNewPosition;
                }
                this.m_lCurrentTab = -1;
                this.CorrectTabs();
                this.m_oWordControl.UpdateHorRuler();
                this.SetTabsProperties();
                break;
            }
            case 8:
            {
                if (!this.SimpleChanges.IsSimple)
                    this.SetTableProperties();
                this.DragTablePos = -1;
                break;
            }
            case 9:
            case 10:
            {
                if (!this.SimpleChanges.IsSimple)
                    this.SetColumnsProperties();
                this.DragTablePos = -1;
                break;
            }
        }

        if (7 == this.DragType)
        {
            word_control.UpdateHorRuler();
            //word_control.m_oOverlayApi.UnShow();
        }

        this.IsDrawingCurTab = true;
        this.DragType = 0;
        this.m_bIsMouseDown = false;

        this.m_oWordControl.m_oDrawingDocument.UnlockCursorType();
        this.SimpleChanges.Clear();
    }

    this.SetTabsProperties = function()
	{
		// потом заменить на объекты CTab (когда Илюха реализует не только левые табы)
		var _arr = new CParaTabs();
		var _c   = this.m_arrTabs.length;
		for (var i = 0; i < _c; i++)
		{
			if (this.m_arrTabs[i].type == AscCommon.g_tabtype_left)
				_arr.Add(new CParaTab(tab_Left, this.m_arrTabs[i].pos, this.m_arrTabs[i].leader));
			else if (this.m_arrTabs[i].type == AscCommon.g_tabtype_right)
				_arr.Add(new CParaTab(tab_Right, this.m_arrTabs[i].pos, this.m_arrTabs[i].leader));
			else if (this.m_arrTabs[i].type == AscCommon.g_tabtype_center)
				_arr.Add(new CParaTab(tab_Center, this.m_arrTabs[i].pos, this.m_arrTabs[i].leader));
		}

		if (false === this.m_oWordControl.m_oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_Paragraph_Properties))
		{
			this.m_oWordControl.m_oLogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetParagraphTabs);
			this.m_oWordControl.m_oLogicDocument.SetParagraphTabs(_arr);
		}
	}

    this.SetPrProperties = function()
    {
        if ( false === this.m_oWordControl.m_oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_Paragraph_Properties) )
        {
            this.m_oWordControl.m_oLogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetParagraphIndentFromRulers);
            this.m_oWordControl.m_oLogicDocument.SetParagraphIndent( { Left : this.m_dIndentLeft, Right : this.m_dIndentRight,
                FirstLine: (this.m_dIndentLeftFirst - this.m_dIndentLeft) } );
            this.m_oWordControl.m_oLogicDocument.Document_UpdateInterfaceState();
        }
    }
    this.SetMarginProperties = function()
    {
        if ( false === this.m_oWordControl.m_oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_Document_SectPr) )
        {
            this.m_oWordControl.m_oLogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetDocumentMargin_Hor);
            this.m_oWordControl.m_oLogicDocument.Set_DocumentMargin( { Left : this.m_dMarginLeft, Right : this.m_dMarginRight });
        }
        //oWordControl.m_oLogicDocument.SetParagraphIndent( { Left : this.m_dIndentLeft, Right : this.m_dIndentRight,
        //    FirstLine: (this.m_dIndentLeftFirst - this.m_dIndentLeft) } );
    }

    this.SetTableProperties = function()
    {
        if ( false === this.m_oWordControl.m_oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_Table_Properties) )
        {
            this.m_oWordControl.m_oLogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetTableMarkup_Hor);

            this.m_oTableMarkup.CorrectTo();
            this.m_oTableMarkup.Table.Update_TableMarkupFromRuler(this.m_oTableMarkup, true, this.DragTablePos);
			if (this.m_oTableMarkup)
			    this.m_oTableMarkup.CorrectFrom();

            this.m_oWordControl.m_oLogicDocument.Document_UpdateInterfaceState();
            this.m_oWordControl.m_oLogicDocument.Document_UpdateRulersState();
        }
    }

    this.SetColumnsProperties = function()
    {
        this.m_oWordControl.m_oLogicDocument.Update_ColumnsMarkupFromRuler(this.m_oColumnMarkup);
    }

    this.BlitToMain = function(left, top, htmlElement)
    {
        var _margin_left = this.m_dMarginLeft;
        var _margin_right = this.m_dMarginRight;
        if (this.CurrentObjectType == RULER_OBJECT_TYPE_TABLE || this.CurrentObjectType == RULER_OBJECT_TYPE_COLUMNS)
        {
            _margin_left = this.TableMarginLeft;
            _margin_right = this.TableMarginRight;
        }

        var checker = this.RepaintChecker;
        if (!checker.BlitAttack && left == checker.BlitLeft && !this.m_bIsMouseDown)
        {
            if (checker.BlitIndentLeft == this.m_dIndentLeft && checker.BlitIndentLeftFirst == this.m_dIndentLeftFirst
                && checker.BlitIndentRight == this.m_dIndentRight && checker.BlitDefaultTab == this.m_dDefaultTab &&
                _margin_left == checker.BlitMarginLeftInd && _margin_right == checker.BlitMarginRightInd)
            {
                // осталось проверить только табы кастомные
                var _count1 = 0;
                if (null != checker.BlitTabs)
                    _count1 = checker.BlitTabs.length;

                var _count2 =  this.m_arrTabs.length;
                if (_count1 == _count2)
                {
                    var bIsBreak = false;
                    for (var ii = 0; ii < _count1; ii++)
                    {
                        if ((checker.BlitTabs[ii].type != this.m_arrTabs[ii].type) || (checker.BlitTabs[ii].pos != this.m_arrTabs[ii].pos))
                        {
                            bIsBreak = true;
                            break;
                        }
                    }
                    if (false === bIsBreak)
                        return;
                }
            }
        }

        checker.BlitAttack = false;
        htmlElement.width = htmlElement.width;
        var context = htmlElement.getContext('2d');
        context.setTransform(1, 0, 0, 1, 0, 0);

        if (null != this.m_oCanvas)
        {
            checker.BlitLeft = left;
            checker.BlitIndentLeft = this.m_dIndentLeft;
            checker.BlitIndentLeftFirst = this.m_dIndentLeftFirst;
            checker.BlitIndentRight = this.m_dIndentRight;
            checker.BlitDefaultTab = this.m_dDefaultTab;
            checker.BlitTabs = null;
            if (0 != this.m_arrTabs.length)
            {
                checker.BlitTabs = [];
                var _len = this.m_arrTabs.length;
                for (var ii = 0; ii < _len; ii++)
                {
                    checker.BlitTabs[ii] = { type: this.m_arrTabs[ii].type, pos: this.m_arrTabs[ii].pos };
                }
            }

            //context.drawImage(this.m_oCanvas, left - 5, 0, this.m_oCanvas.width, this.m_oCanvas.height,
            //    0, 0, this.m_oCanvas.width, this.m_oCanvas.height);

            if (!this.IsRetina)
            {
                context.drawImage(this.m_oCanvas, 5, 0, this.m_oCanvas.width - 10, this.m_oCanvas.height,
                    left, 0, this.m_oCanvas.width - 10, this.m_oCanvas.height);
            }
            else
            {
                context.drawImage(this.m_oCanvas, 10, 0, this.m_oCanvas.width - 20, this.m_oCanvas.height,
                    left << 1, 0, this.m_oCanvas.width - 20, this.m_oCanvas.height);
                context.setTransform(2, 0, 0, 2, 0, 0);
            }

            if (!this.IsDrawAnyMarkers)
                return;

            var dKoef_mm_to_pix = g_dKoef_mm_to_pix * this.m_dZoom;

            var dCenterX = 0;
            var var1 = 0;
            var var2 = 0;
            var var3 = 0;
            var var4 = 0;

            var _positon_y = this.m_nBottom - 5;

            context.strokeStyle = "#81878F";
            // не менять!!!
            var2 = 5;//(1.4 * g_dKoef_mm_to_pix) >> 0;
            var3 = 3;//(1 * g_dKoef_mm_to_pix) >> 0;

            checker.BlitMarginLeftInd = _margin_left;
            checker.BlitMarginRightInd = _margin_right;

            // old position --------------------------------------
            context.fillStyle = "#CDD1D6";
            if ((-10000 != this.m_dIndentLeft_old) && (this.m_dIndentLeft_old != this.m_dIndentLeft))
            {
                dCenterX = left + (_margin_left +  this.m_dIndentLeft_old) * dKoef_mm_to_pix;

                var1 = parseInt(dCenterX - 1 * g_dKoef_mm_to_pix) - 0.5;
                var4 = parseInt(dCenterX + 1 * g_dKoef_mm_to_pix) + 0.5;

                context.beginPath();
                context.moveTo(var1, this.m_nBottom + 0.5);
                context.lineTo(var4, this.m_nBottom + 0.5);
                context.lineTo(var4, this.m_nBottom + 0.5 + var2);
                context.lineTo(var1, this.m_nBottom + 0.5 + var2);
                context.lineTo(var1, this.m_nBottom + 0.5);
                context.lineTo(var1, this.m_nBottom + 0.5 - var3);
                context.lineTo((var1 + var4) / 2, this.m_nBottom - var2 * 1.2);
                context.lineTo(var4, this.m_nBottom + 0.5 - var3);
                context.lineTo(var4, this.m_nBottom + 0.5);

                context.fill();
                context.stroke();
            }
            if ((-10000 != this.m_dIndentLeftFirst_old) && (this.m_dIndentLeftFirst_old != this.m_dIndentLeftFirst))
            {
                dCenterX = left + (_margin_left +  this.m_dIndentLeftFirst_old) * dKoef_mm_to_pix;
                var1 = parseInt(dCenterX - 1 * g_dKoef_mm_to_pix) - 0.5;
                var4 = parseInt(dCenterX + 1 * g_dKoef_mm_to_pix) + 0.5;

                // first line indent
                context.beginPath();
                context.moveTo(var1, this.m_nTop + 0.5);
                context.lineTo(var1, this.m_nTop + 0.5 - var3);
                context.lineTo(var4, this.m_nTop + 0.5 - var3);
                context.lineTo(var4, this.m_nTop + 0.5);
                context.lineTo((var1 + var4) / 2, this.m_nTop + var2 * 1.2);
                context.closePath();

                context.fill();
                context.stroke();
            }
            if ((-10000 != this.m_dIndentRight_old) && (this.m_dIndentRight_old != this.m_dIndentRight))
            {
                dCenterX = left + (_margin_right -  this.m_dIndentRight_old) * dKoef_mm_to_pix;
                var1 = parseInt(dCenterX - 1 * g_dKoef_mm_to_pix) - 0.5;
                var4 = parseInt(dCenterX + 1 * g_dKoef_mm_to_pix) + 0.5;

                context.beginPath();
                context.moveTo(var1, this.m_nBottom + 0.5);
                context.lineTo(var4, this.m_nBottom + 0.5);
                context.lineTo(var4, this.m_nBottom + 0.5 - var3);
                context.lineTo((var1 + var4) / 2, this.m_nBottom - var2 * 1.2);
                context.lineTo(var1, this.m_nBottom + 0.5 - var3);
                context.closePath();

                context.fill();
                context.stroke();
            }

            if (-1 != this.m_lCurrentTab && this.m_lCurrentTab < this.m_arrTabs.length)
            {
                var _tab = this.m_arrTabs[this.m_lCurrentTab];
                var _x = parseInt((_margin_left + _tab.pos) * dKoef_mm_to_pix) + left;

                var _old_w = context.lineWidth;
                context.lineWidth = 2;
                switch (_tab.type)
                {
                    case AscCommon.g_tabtype_left:
                    {
                        context.beginPath();
                        context.moveTo(_x, _positon_y);
                        context.lineTo(_x, _positon_y + 5);
                        context.lineTo(_x + 5, _positon_y + 5);
                        context.stroke();
                        break;
                    }
                    case AscCommon.g_tabtype_right:
                    {
                        context.beginPath();
                        context.moveTo(_x, _positon_y);
                        context.lineTo(_x, _positon_y + 5);
                        context.lineTo(_x - 5, _positon_y + 5);
                        context.stroke();
                        break;
                    }
                    case AscCommon.g_tabtype_center:
                    {
                        context.beginPath();
                        context.moveTo(_x, _positon_y);
                        context.lineTo(_x, _positon_y + 5);
                        context.moveTo(_x - 5, _positon_y + 5);
                        context.lineTo(_x + 5, _positon_y + 5);
                        context.stroke();
                        break;
                    }
                    default:
                        break;
                }

                context.lineWidth = _old_w;
            }
            
            // ---------------------------------------------------

            // рисуем инденты, только если они корректны
            var posL = _margin_left;
            if ((_margin_left + this.m_dIndentLeft) > posL)
                posL = _margin_left + this.m_dIndentLeft;
            if ((_margin_left + this.m_dIndentLeftFirst) > posL)
                posL = _margin_left + this.m_dIndentLeftFirst;

            var posR = _margin_right;
            if (this.m_dIndentRight > 0)
                posR = _margin_right - this.m_dIndentRight;

            if (posL < posR)
            {
                context.fillStyle = GlobalSkin.RulerMarkersFillColor;

                // left indent
                dCenterX = left + (_margin_left +  this.m_dIndentLeft) * dKoef_mm_to_pix;

                var _1mm_to_pix = g_dKoef_mm_to_pix;

                var1 = parseInt(dCenterX - _1mm_to_pix) - 0.5;
                var4 = parseInt(dCenterX + _1mm_to_pix) + 0.5;

                context.beginPath();
                context.moveTo(var1, this.m_nBottom + 0.5);
                context.lineTo(var4, this.m_nBottom + 0.5);
                context.lineTo(var4, this.m_nBottom + 0.5 + var2);
                context.lineTo(var1, this.m_nBottom + 0.5 + var2);
                context.lineTo(var1, this.m_nBottom + 0.5);
                context.lineTo(var1, this.m_nBottom + 0.5 - var3);
                context.lineTo((var1 + var4) / 2, this.m_nBottom - var2 * 1.2);
                context.lineTo(var4, this.m_nBottom + 0.5 - var3);
                context.lineTo(var4, this.m_nBottom + 0.5);

                context.fill();
                context.stroke();

                // right indent
                dCenterX = left + (_margin_right - this.m_dIndentRight) * dKoef_mm_to_pix;
                var1 = parseInt(dCenterX - _1mm_to_pix) - 0.5;
                var4 = parseInt(dCenterX + _1mm_to_pix) + 0.5;

                context.beginPath();
                context.moveTo(var1, this.m_nBottom + 0.5);
                context.lineTo(var4, this.m_nBottom + 0.5);
                context.lineTo(var4, this.m_nBottom + 0.5 - var3);
                context.lineTo((var1 + var4) / 2, this.m_nBottom - var2 * 1.2);
                context.lineTo(var1, this.m_nBottom + 0.5 - var3);
                context.closePath();

                context.fill();
                context.stroke();

                // first line indent
                dCenterX = left + (_margin_left +  this.m_dIndentLeftFirst) * dKoef_mm_to_pix;
                var1 = parseInt(dCenterX - _1mm_to_pix) - 0.5;
                var4 = parseInt(dCenterX + _1mm_to_pix) + 0.5;

                context.beginPath();
                context.moveTo(var1, this.m_nTop + 0.5);
                context.lineTo(var1, this.m_nTop + 0.5 - var3);
                context.lineTo(var4, this.m_nTop + 0.5 - var3);
                context.lineTo(var4, this.m_nTop + 0.5);
                context.lineTo((var1 + var4) / 2, this.m_nTop + var2 * 1.2);
                context.closePath();

                context.fill();
                context.stroke();
            }

            // теперь рисуем табы ----------------------------------------
            // default
            var position_default_tab = this.m_dDefaultTab;
            _positon_y = this.m_nBottom + 1.5;

            var _min_default_value = Math.max(0, this.m_dMaxTab);
            if (this.m_dDefaultTab > 0.01)
            {
                while (true)
                {
                    if ((_margin_left + position_default_tab) > this.m_dMarginRight)
                        break;

                    if (position_default_tab < _min_default_value)
                    {
                        position_default_tab += this.m_dDefaultTab;
                        continue;
                    }

                    var _x = parseInt((_margin_left + position_default_tab) * dKoef_mm_to_pix) + left + 0.5;
                    context.beginPath();
                    context.moveTo(_x, _positon_y);
                    context.lineTo(_x, _positon_y + 3);
                    context.stroke();

                    position_default_tab += this.m_dDefaultTab;
                }
            }

            // custom tabs
            var _len_tabs = this.m_arrTabs.length;
            if (0 != _len_tabs)
            {
                context.strokeStyle = "#000000";
                context.lineWidth = 2;

                _positon_y = this.m_nBottom - 5;
                for (var i = 0; i < _len_tabs; i++)
                {
                    var tab = this.m_arrTabs[i];
                    var _x = 0;

                    if (i == this.m_lCurrentTab)
                    {
                        if (!this.IsDrawingCurTab)
                            continue;
                        // рисуем вместо него - позицию нового
                        _x = parseInt((_margin_left + this.m_dCurrentTabNewPosition) * dKoef_mm_to_pix) + left;
                    }
                    else
                    {
                        //if (tab.pos < 0 || tab.pos > this.m_dMarginRight)
                        if (tab.pos < this.m_dIndentLeft || (tab.pos + _margin_left) > (_margin_right - this.m_dIndentRight))
                            continue;

                        _x = parseInt((_margin_left + tab.pos) * dKoef_mm_to_pix) + left;
                    }

                    switch (tab.type)
                    {
                        case AscCommon.g_tabtype_left:
                        {
                            context.beginPath();
                            context.moveTo(_x, _positon_y);
                            context.lineTo(_x, _positon_y + 5);
                            context.lineTo(_x + 5, _positon_y + 5);
                            context.stroke();
                            break;
                        }
                        case AscCommon.g_tabtype_right:
                        {
                            context.beginPath();
                            context.moveTo(_x, _positon_y);
                            context.lineTo(_x, _positon_y + 5);
                            context.lineTo(_x - 5, _positon_y + 5);
                            context.stroke();
                            break;
                        }
                        case AscCommon.g_tabtype_center:
                        {
                            context.beginPath();
                            context.moveTo(_x, _positon_y);
                            context.lineTo(_x, _positon_y + 5);
                            context.moveTo(_x - 5, _positon_y + 5);
                            context.lineTo(_x + 5, _positon_y + 5);
                            context.stroke();
                            break;
                        }
                        default:
                            break;
                    }
                }
            }
            // -----------------------------------------------------------
        }
    }
}

function CVerRuler()
{
    this.m_oPage        = null;

    this.m_nLeft         = 0;        // значения в пикселах - смещение до самой линейки
    this.m_nRight      = 0;          // значения в пикселах - смещение до самой линейки
                                     // (т.е. ширина линейки в пикселах = (this.m_nRight - this.m_nLeft))

    this.m_dMarginTop           = 20;
    this.m_dMarginBottom        = 250;

    this.m_oCanvas              = null;

    this.m_dZoom                = 1;

    this.DragType = 0;          // 0 - none
                                // 1 - top margin, 2 - bottom margin
                                // 3 - header_top, 4 - header_bottom
                                // 5 - table rows

    // отдельные настройки для текущего объекта линейки
    this.CurrentObjectType  = RULER_OBJECT_TYPE_PARAGRAPH;
    this.m_oTableMarkup     = null;
    this.header_top         = 0;
    this.header_bottom      = 0;

    this.DragTablePos       = -1;

    this.RepaintChecker     = new CVerRulerRepaintChecker();

    // presentations addons
    this.IsCanMoveMargins = true;

    this.m_oWordControl = null;
    this.IsRetina = false;

    this.SimpleChanges = new RulerCheckSimpleChanges();

    this.Units = c_oAscDocumentUnits.Millimeter;

    this.CheckCanvas = function()
    {
        this.m_dZoom = this.m_oWordControl.m_nZoomValue / 100;
        this.IsRetina = this.m_oWordControl.bIsRetinaSupport;

        var dKoef_mm_to_pix = g_dKoef_mm_to_pix * this.m_dZoom;
        if (this.IsRetina)
            dKoef_mm_to_pix *= 2;

        var heightNew    = dKoef_mm_to_pix * this.m_oPage.height_mm;

        var _height      = 10 + heightNew;
        if (this.IsRetina)
            _height += 10;

        var _width       = 5 * g_dKoef_mm_to_pix;

        if (this.IsRetina)
            _width *= 2;

        var intW = _width >> 0;
        var intH = _height >> 0;
        if (null == this.m_oCanvas)
        {
            this.m_oCanvas = document.createElement('canvas');
            this.m_oCanvas.width    = intW;
            this.m_oCanvas.height   = intH;
        }
        else
        {
            var oldW = this.m_oCanvas.width;
            var oldH = this.m_oCanvas.height;

            if ((oldW != intW) || (oldH != intH))
            {
                delete this.m_oCanvas;
                this.m_oCanvas = document.createElement('canvas');
                this.m_oCanvas.width    = intW;
                this.m_oCanvas.height   = intH;
            }
        }
        return heightNew;
    }

    this.CreateBackground = function(cachedPage, isattack)
    {
        if (window["NATIVE_EDITOR_ENJINE"])
            return;
            
        if (null == cachedPage || undefined == cachedPage)
            return;
        
        this.m_oPage = cachedPage;
        var height = this.CheckCanvas();

        if (this.IsRetina)
            height >>= 1;

        if (0 == this.DragType)
        {
            this.m_dMarginTop       = cachedPage.margin_top;
            this.m_dMarginBottom    = cachedPage.margin_bottom;
        }

        // check old state
        var checker = this.RepaintChecker;
        var markup = this.m_oTableMarkup;

        if (isattack !== true && this.CurrentObjectType == checker.Type && height == checker.Height)
        {
            if (this.CurrentObjectType == RULER_OBJECT_TYPE_PARAGRAPH)
            {
                if (this.m_dMarginTop == checker.MarginTop && this.m_dMarginBottom == checker.MarginBottom)
                    return;
            }
            else if (this.CurrentObjectType == RULER_OBJECT_TYPE_HEADER || this.CurrentObjectType == RULER_OBJECT_TYPE_FOOTER)
            {
                if (this.header_top == checker.HeaderTop && this.header_bottom == checker.HeaderBottom)
                    return;
            }
            else if (this.CurrentObjectType == RULER_OBJECT_TYPE_TABLE)
            {
                var oldcount = checker.rowsY.length;
                var newcount = markup.Rows.length;

                if (oldcount == newcount)
                {
                    var arr1 = checker.rowsY;
                    var arr2 = checker.rowsH;

                    var rows = markup.Rows;

                    var _break = false;
                    for (var i = 0; i < oldcount; i++)
                    {
                        if ((arr1[i] != rows[i].Y) || (arr2[i] != rows[i].H))
                        {
                            _break = true;
                            break;
                        }
                    }

                    if (!_break)
                        return;
                }
            }
        }

        //console.log("vertical");

        checker.Height = height;
        checker.Type = this.CurrentObjectType;
        checker.BlitAttack = true;

        var dKoef_mm_to_pix = g_dKoef_mm_to_pix * this.m_dZoom;

        // не править !!!
        this.m_nLeft   = 3;//(0.8 * g_dKoef_mm_to_pix) >> 0;
        this.m_nRight  = 15;//(4.2 * g_dKoef_mm_to_pix) >> 0;

        var context = this.m_oCanvas.getContext('2d');
        if (!this.IsRetina)
            context.setTransform(1, 0, 0, 1, 0, 5);
        else
            context.setTransform(2, 0, 0, 2, 0, 10);

        context.fillStyle = GlobalSkin.BackgroundColor;
        context.fillRect(0, 0, this.m_oCanvas.width, this.m_oCanvas.height);

        var top_margin = 0;
        var bottom_margin = 0;

        if (RULER_OBJECT_TYPE_PARAGRAPH == this.CurrentObjectType)
        {
            top_margin = (this.m_dMarginTop * dKoef_mm_to_pix) >> 0;
            bottom_margin = (this.m_dMarginBottom * dKoef_mm_to_pix) >> 0;

            checker.MarginTop = this.m_dMarginTop;
            checker.MarginBottom = this.m_dMarginBottom;
        }
        else if (RULER_OBJECT_TYPE_HEADER == this.CurrentObjectType || RULER_OBJECT_TYPE_FOOTER == this.CurrentObjectType)
        {
            top_margin = (this.header_top * dKoef_mm_to_pix) >> 0;
            bottom_margin = (this.header_bottom * dKoef_mm_to_pix) >> 0;

            checker.HeaderTop = this.header_top;
            checker.HeaderBottom = this.header_bottom;
        }
        else if (RULER_OBJECT_TYPE_TABLE == this.CurrentObjectType)
        {
            var _arr1 = checker.rowsY;
            var _arr2 = checker.rowsH;

            if (0 != _arr1.length)
                _arr1.splice(0, _arr1.length);

            if (0 != _arr2.length)
                _arr2.splice(0, _arr2.length);

            var _count = this.m_oTableMarkup.Rows.length;

            for (var i = 0; i < _count; i++)
            {
                _arr1[i] = markup.Rows[i].Y;
                _arr2[i] = markup.Rows[i].H;
            }

            if (_count != 0)
            {
                top_margin = (markup.Rows[0].Y * dKoef_mm_to_pix) >> 0;
                bottom_margin = ((markup.Rows[_count - 1].Y + markup.Rows[_count - 1].H) * dKoef_mm_to_pix) >> 0;
            }
        }

        if (bottom_margin > top_margin)
        {
            context.fillStyle = GlobalSkin.RulerLight;
            context.fillRect(this.m_nLeft + 0.5, top_margin + 0.5, this.m_nRight - this.m_nLeft, bottom_margin - top_margin);
        }

        var intH = height >> 0;

        if (window["flat_desine"] === true)
        {
            context.beginPath();
            context.fillStyle = GlobalSkin.RulerDark;

            context.fillRect(this.m_nLeft + 0.5, 0.5, this.m_nRight - this.m_nLeft, top_margin);
            context.fillRect(this.m_nLeft + 0.5, bottom_margin + 0.5, this.m_nRight - this.m_nLeft, Math.max(intH - bottom_margin, 1));
            context.beginPath();
        }

		// рамка
        context.strokeStyle = GlobalSkin.RulerOutline;

        context.lineWidth = 1;
        context.strokeRect(this.m_nLeft + 0.5, 0.5, this.m_nRight - this.m_nLeft, Math.max(intH - 1, 1));
        context.beginPath();
        context.moveTo(this.m_nLeft + 0.5, top_margin + 0.5);
        context.lineTo(this.m_nRight - 0.5, top_margin + 0.5);

        context.moveTo(this.m_nLeft + 0.5, bottom_margin + 0.5);
        context.lineTo(this.m_nRight - 0.5, bottom_margin + 0.5);

        context.stroke();
        context.beginPath();

        context.strokeStyle = "#585B5E";
        context.fillStyle = "#585B5E";

        var mm_1_4 = 10 * dKoef_mm_to_pix / 4;
		var isDraw1_4 = (mm_1_4 > 7) ? true : false;
        var inch_1_8 = 25.4 * dKoef_mm_to_pix / 8;

        var middleHor = (this.m_nLeft + this.m_nRight) / 2;
        var part1 = 1;
        var part2 = 2.5;

        context.font = "7pt Arial";

        if (this.Units == c_oAscDocumentUnits.Millimeter)
        {
            var lCount1 = ((height - top_margin) / mm_1_4) >> 0;
            var lCount2 = (top_margin / mm_1_4) >> 0;

        var index = 0;
        var num = 0;
        for (var i = 1; i < lCount1; i++)
        {
            var lYPos = ((top_margin + i * mm_1_4) >> 0) + 0.5;
            index++;

            if (index == 4)
                index = 0;

            if (0 == index)
            {
                num++;
                // number

                var strNum = "" + num;
                var lWidthText = context.measureText(strNum).width;

                context.translate(middleHor, lYPos);
                context.rotate(-Math.PI / 2);
                context.fillText(strNum, -lWidthText / 2.0, 4);

                if (!this.IsRetina)
                    context.setTransform(1, 0, 0, 1, 0, 5);
                else
                    context.setTransform(2, 0, 0, 2, 0, 10);
            }
            else if (1 == index && isDraw1_4)
            {
                // 1/4
                context.beginPath();
                context.moveTo(middleHor - part1, lYPos);
                context.lineTo(middleHor + part1, lYPos);
                context.stroke();
            }
            else if (2 == index)
            {
                // 1/2
                context.beginPath();
                context.moveTo(middleHor - part2, lYPos);
                context.lineTo(middleHor + part2, lYPos);
                context.stroke();
            }
            else if (isDraw1_4)
            {
                // 1/4
                context.beginPath();
                context.moveTo(middleHor - part1, lYPos);
                context.lineTo(middleHor + part1, lYPos);
                context.stroke();
            }
        }

        index = 0;
        num = 0;
        for (var i = 1; i <= lCount2; i++)
        {
            var lYPos = ((top_margin - i * mm_1_4) >> 0) + 0.5;
            index++;

            if (index == 4)
                index = 0;

            if (0 == index)
            {
                num++;
                // number
                var strNum = "" + num;
                var lWidthText = context.measureText(strNum).width;

                context.translate(middleHor, lYPos);
                context.rotate(-Math.PI / 2);
                context.fillText(strNum, -lWidthText / 2.0, 4);

                if (!this.IsRetina)
                    context.setTransform(1, 0, 0, 1, 0, 5);
                else
                    context.setTransform(2, 0, 0, 2, 0, 10);
            }
            else if (1 == index && isDraw1_4)
            {
                // 1/4
                context.beginPath();
                context.moveTo(middleHor - part1, lYPos);
                context.lineTo(middleHor + part1, lYPos);
                context.stroke();
            }
            else if (2 == index)
            {
                // 1/2
                context.beginPath();
                context.moveTo(middleHor - part2, lYPos);
                context.lineTo(middleHor + part2, lYPos);
                context.stroke();
            }
            else if (isDraw1_4)
            {
                // 1/4
                context.beginPath();
                context.moveTo(middleHor - part1, lYPos);
                context.lineTo(middleHor + part1, lYPos);
                context.stroke();
            }
        }
        }
        else if (this.Units == c_oAscDocumentUnits.Inch)
        {
            var lCount1 = ((height - top_margin) / inch_1_8) >> 0;
            var lCount2 = (top_margin / inch_1_8) >> 0;

            var index = 0;
            var num = 0;
            for (var i = 1; i < lCount1; i++)
            {
                var lYPos = ((top_margin + i * inch_1_8) >> 0) + 0.5;
                index++;

                if (index == 8)
                    index = 0;

                if (0 == index)
                {
                    num++;
                    // number

                    var strNum = "" + num;
                    var lWidthText = context.measureText(strNum).width;

                    context.translate(middleHor, lYPos);
                    context.rotate(-Math.PI / 2);
                    context.fillText(strNum, -lWidthText / 2.0, 4);

                    if (!this.IsRetina)
                        context.setTransform(1, 0, 0, 1, 0, 5);
                    else
                        context.setTransform(2, 0, 0, 2, 0, 10);
                }
                else if (4 == index)
                {
                    // 1/2
                    context.beginPath();
                    context.moveTo(middleHor - part2, lYPos);
                    context.lineTo(middleHor + part2, lYPos);
                    context.stroke();
                }
                else if (inch_1_8 > 8)
                {
                    // 1/8
                    context.beginPath();
                    context.moveTo(middleHor - part1, lYPos);
                    context.lineTo(middleHor + part1, lYPos);
                    context.stroke();
                }
            }

            index = 0;
            num = 0;
            for (var i = 1; i <= lCount2; i++)
            {
                var lYPos = ((top_margin - i * inch_1_8) >> 0) + 0.5;
                index++;

                if (index == 8)
                    index = 0;

                if (0 == index)
                {
                    num++;
                    // number
                    var strNum = "" + num;
                    var lWidthText = context.measureText(strNum).width;

                    context.translate(middleHor, lYPos);
                    context.rotate(-Math.PI / 2);
                    context.fillText(strNum, -lWidthText / 2.0, 4);

                    if (!this.IsRetina)
                        context.setTransform(1, 0, 0, 1, 0, 5);
                    else
                        context.setTransform(2, 0, 0, 2, 0, 10);
                }
                else if (4 == index)
                {
                    // 1/2
                    context.beginPath();
                    context.moveTo(middleHor - part2, lYPos);
                    context.lineTo(middleHor + part2, lYPos);
                    context.stroke();
                }
                else if (inch_1_8 > 8)
                {
                    // 1/8
                    context.beginPath();
                    context.moveTo(middleHor - part1, lYPos);
                    context.lineTo(middleHor + part1, lYPos);
                    context.stroke();
                }
            }
        }
        else if (this.Units == c_oAscDocumentUnits.Point)
        {
            var point_1_12 = 25.4 * dKoef_mm_to_pix / 12;

            var lCount1 = ((height - top_margin) / point_1_12) >> 0;
            var lCount2 = (top_margin / point_1_12) >> 0;

            var index = 0;
            var num = 0;
            for (var i = 1; i < lCount1; i++)
            {
                var lYPos = ((top_margin + i * point_1_12) >> 0) + 0.5;
                index++;

                if (index == 12)
                    index = 0;

                if (0 == index || 6 == index)
                {
                    num++;
                    // number

                    var strNum = "" + (num * 36);
                    var lWidthText = context.measureText(strNum).width;

                    context.translate(middleHor, lYPos);
                    context.rotate(-Math.PI / 2);
                    context.fillText(strNum, -lWidthText / 2.0, 4);

                    if (!this.IsRetina)
                        context.setTransform(1, 0, 0, 1, 0, 5);
                    else
                        context.setTransform(2, 0, 0, 2, 0, 10);
                }
                else if (point_1_12 > 5)
                {
                    // 1/8
                    context.beginPath();
                    context.moveTo(middleHor - part1, lYPos);
                    context.lineTo(middleHor + part1, lYPos);
                    context.stroke();
                }
            }

            index = 0;
            num = 0;
            for (var i = 1; i <= lCount2; i++)
            {
                var lYPos = ((top_margin - i * point_1_12) >> 0) + 0.5;
                index++;

                if (index == 12)
                    index = 0;

                if (0 == index || 6 == index)
                {
                    num++;
                    // number
                    var strNum = "" + (num * 36);
                    var lWidthText = context.measureText(strNum).width;

                    context.translate(middleHor, lYPos);
                    context.rotate(-Math.PI / 2);
                    context.fillText(strNum, -lWidthText / 2.0, 4);

                    if (!this.IsRetina)
                        context.setTransform(1, 0, 0, 1, 0, 5);
                    else
                        context.setTransform(2, 0, 0, 2, 0, 10);
                }
                else if (point_1_12 > 5)
                {
                    // 1/8
                    context.beginPath();
                    context.moveTo(middleHor - part1, lYPos);
                    context.lineTo(middleHor + part1, lYPos);
                    context.stroke();
                }
            }
        }

        if ((this.CurrentObjectType == RULER_OBJECT_TYPE_TABLE) && (null != markup))
        {
            var dKoef_mm_to_pix = g_dKoef_mm_to_pix * this.m_dZoom;

            // не будет нулевых таблиц.
            var _count = markup.Rows.length;

            if (0 == _count)
                return;

            var start_dark = (((markup.Rows[0].Y + markup.Rows[0].H) * dKoef_mm_to_pix) >> 0) + 0.5;
            var end_dark = 0;

            context.fillStyle = GlobalSkin.RulerDark;
            context.strokeStyle = GlobalSkin.RulerOutline;

            var _x = this.m_nLeft + 0.5;
            var _w = this.m_nRight - this.m_nLeft;
            for (var i = 1; i < _count; i++)
            {
                end_dark = ((markup.Rows[i].Y * dKoef_mm_to_pix) >> 0) + 0.5;
                context.fillRect(_x, start_dark, _w, Math.max(end_dark - start_dark, 7));
                context.strokeRect(_x, start_dark, _w, Math.max(end_dark - start_dark, 7));

                start_dark = (((markup.Rows[i].Y + markup.Rows[i].H) * dKoef_mm_to_pix) >> 0) + 0.5;
            }
        }
    }

    this.OnMouseMove = function(left, top, e)
    {
        var word_control = this.m_oWordControl;
        AscCommon.check_MouseMoveEvent(e);

        this.SimpleChanges.CheckMove();
        var ver_ruler = word_control.m_oLeftRuler_vertRuler;
        var dKoefPxToMM = 100 * g_dKoef_pix_to_mm / word_control.m_nZoomValue;

		// теперь определяем позицию относительно самой линейки. Все в миллиметрах
        var _y = global_mouseEvent.Y - 7 * g_dKoef_mm_to_pix - top - word_control.Y;
        _y *= dKoefPxToMM;
        var _x = left * g_dKoef_pix_to_mm;

        var dKoef_mm_to_pix = g_dKoef_mm_to_pix * this.m_dZoom;
        var mm_1_4 = 10 / 4;
        var mm_1_8 = mm_1_4 / 2;

        switch (this.DragType)
        {
            case 0:
            {
                if (this.CurrentObjectType == RULER_OBJECT_TYPE_PARAGRAPH)
                {
                    if (this.IsCanMoveMargins && ((Math.abs(_y - this.m_dMarginTop) < 1) || (Math.abs(_y - this.m_dMarginBottom) < 1)))
                        word_control.m_oDrawingDocument.SetCursorType("s-resize");
                    else
                        word_control.m_oDrawingDocument.SetCursorType("default");
                }
                else if (this.CurrentObjectType == RULER_OBJECT_TYPE_HEADER)
                {
                    if ((Math.abs(_y - this.header_top) < 1) || (Math.abs(_y - this.header_bottom) < 1))
                        word_control.m_oDrawingDocument.SetCursorType("s-resize");
                    else
                        word_control.m_oDrawingDocument.SetCursorType("default");
                }
                else if (this.CurrentObjectType == RULER_OBJECT_TYPE_FOOTER)
                {
                    if (Math.abs(_y - this.header_top) < 1)
                        word_control.m_oDrawingDocument.SetCursorType("s-resize");
                    else
                        word_control.m_oDrawingDocument.SetCursorType("default");
                }
                else if (this.CurrentObjectType == RULER_OBJECT_TYPE_TABLE)
                {
                    var type = this.CheckMouseType(2, _y);
                    if (type == 5)
                        word_control.m_oDrawingDocument.SetCursorType("s-resize");
                    else
                        word_control.m_oDrawingDocument.SetCursorType("default");
                }

                break;
            }
            case 1:
            {
                var newVal = RulerCorrectPosition(this, _y, this.m_dMarginTop);

                if (newVal > (this.m_dMarginBottom - 30))
                    newVal = this.m_dMarginBottom - 30;
                if (newVal < 0)
                    newVal = 0;

                this.m_dMarginTop = newVal;
                word_control.UpdateVerRulerBack();

                var pos = top + this.m_dMarginTop * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.HorLine(pos);

                word_control.m_oDrawingDocument.SetCursorType("s-resize");

                break;
            }
            case 2:
            {
                var newVal = RulerCorrectPosition(this, _y, this.m_dMarginTop);

                if (newVal < (this.m_dMarginTop + 30))
                    newVal = this.m_dMarginTop + 30;
                if (newVal > this.m_oPage.height_mm)
                    newVal = this.m_oPage.height_mm;

                this.m_dMarginBottom = newVal;
                word_control.UpdateVerRulerBack();

                var pos = top + this.m_dMarginBottom * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.HorLine(pos);

                word_control.m_oDrawingDocument.SetCursorType("s-resize");

                break;
            }
            case 3:
            {
                var newVal = RulerCorrectPosition(this, _y, this.m_dMarginTop);

                if (newVal > this.header_bottom)
                    newVal = this.header_bottom;
                if (newVal < 0)
                    newVal = 0;

                this.header_top = newVal;
                word_control.UpdateVerRulerBack();

                var pos = top + this.header_top * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.HorLine(pos);

                word_control.m_oDrawingDocument.SetCursorType("s-resize");

                break;
            }
            case 4:
            {
                var newVal = RulerCorrectPosition(this, _y, this.m_dMarginTop);

                if (newVal < 0)
                    newVal = 0;
                if (newVal > this.m_oPage.height_mm)
                    newVal = this.m_oPage.height_mm;

                this.header_bottom = newVal;
                word_control.UpdateVerRulerBack();

                var pos = top + this.header_bottom * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.HorLine(pos);

                word_control.m_oDrawingDocument.SetCursorType("s-resize");

                break;
            }
            case 5:
            {
                // сначала нужно определить минимум и максимум сдвига
                var _min = 0;
                var _max = this.m_oPage.height_mm;

                if (0 < this.DragTablePos)
                {
                    _min = this.m_oTableMarkup.Rows[this.DragTablePos - 1].Y;
                }
                if (this.DragTablePos < this.m_oTableMarkup.Rows.length)
                {
                    _max = this.m_oTableMarkup.Rows[this.DragTablePos].Y + this.m_oTableMarkup.Rows[this.DragTablePos].H;
                }

                var newVal = RulerCorrectPosition(this, _y, this.m_dMarginTop);

                if (newVal < _min)
                    newVal = _min;
                if (newVal > _max)
                    newVal = _max;

                if (0 == this.DragTablePos)
                {
                    var _bottom = this.m_oTableMarkup.Rows[0].Y + this.m_oTableMarkup.Rows[0].H;
                    this.m_oTableMarkup.Rows[0].Y = newVal;
                    this.m_oTableMarkup.Rows[0].H = _bottom - newVal;
                }
                else
                {
                    var oldH = this.m_oTableMarkup.Rows[this.DragTablePos - 1].H;
                    this.m_oTableMarkup.Rows[this.DragTablePos - 1].H = newVal - this.m_oTableMarkup.Rows[this.DragTablePos - 1].Y;

                    var delta = this.m_oTableMarkup.Rows[this.DragTablePos - 1].H - oldH;
                    for (var i = this.DragTablePos; i < this.m_oTableMarkup.Rows.length; i++)
                    {
                        this.m_oTableMarkup.Rows[i].Y += delta;
                    }
                }

                word_control.UpdateVerRulerBack();

                var pos = top + newVal * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.HorLine(pos);

                word_control.m_oDrawingDocument.SetCursorType("s-resize");
            }
        }
    }

    this.CheckMouseType = function(x, y)
    {
		// проверяем где находимся

        if (this.IsCanMoveMargins === false)
            return 0;

        if (x >= 0.8 && x <= 4.2)
        {
			// внутри линейки
            if (this.CurrentObjectType == RULER_OBJECT_TYPE_PARAGRAPH)
            {
                if (Math.abs(y - this.m_dMarginTop) < 1)
                {
                    return 1;
                }
                else if (Math.abs(y - this.m_dMarginBottom) < 1)
                {
                    return 2;
                }
            }
            else if (this.CurrentObjectType == RULER_OBJECT_TYPE_HEADER)
            {
                if (Math.abs(y - this.header_top) < 1)
                {
                    return 3;
                }
                else if (Math.abs(y - this.header_bottom) < 1)
                {
                    return 4;
                }
            }
            else if (this.CurrentObjectType == RULER_OBJECT_TYPE_FOOTER)
            {
                if (Math.abs(y - this.header_top) < 1)
                {
                    return 3;
                }
            }
            else if (this.CurrentObjectType == RULER_OBJECT_TYPE_TABLE && null != this.m_oTableMarkup)
            {
                // не будет нулевых таблиц.
                var markup = this.m_oTableMarkup;
                var _count = markup.Rows.length;

                if (0 == _count)
                    return 0;

                var _start = markup.Rows[0].Y;
                var _end = _start - 2;

                for (var i = 0; i <= _count; i++)
                {
                    if (i == _count)
                    {
                        _end = markup.Rows[i - 1].Y + markup.Rows[i - 1].H;
                        _start = _end + 2;
                    }
                    else if (i != 0)
                    {
                        _end = markup.Rows[i - 1].Y + markup.Rows[i - 1].H;
                        _start = markup.Rows[i].Y;
                    }

                    if ((_end - 1) < y && y < (_start + 1))
                    {
                        this.DragTablePos = i;
                        return 5;
                    }
                }
            }
        }
        return 0;
    }

    this.OnMouseDown = function(left, top, e)
    {
        var word_control = this.m_oWordControl;

		if (true === word_control.m_oApi.isStartAddShape)
		{
			word_control.m_oApi.sync_EndAddShape();
			word_control.m_oApi.sync_StartAddShapeCallback(false);
		}

        AscCommon.check_MouseDownEvent(e, true);

        this.SimpleChanges.Reinit();
        global_mouseEvent.LockMouse();

        var dKoefPxToMM = 100 * g_dKoef_pix_to_mm / word_control.m_nZoomValue;
        var dKoef_mm_to_pix = g_dKoef_mm_to_pix * this.m_dZoom;

        var _y = global_mouseEvent.Y - 7 * g_dKoef_mm_to_pix - top - word_control.Y;
        _y *= dKoefPxToMM;
        var _x = (global_mouseEvent.X - word_control.X) * g_dKoef_pix_to_mm - word_control.GetMainContentBounds().L;

        this.DragType = this.CheckMouseType(_x, _y);
		this.DragTypeMouseDown = this.DragType;

		if (global_mouseEvent.ClickCount > 1)
		{
			var eventType = "";
			switch (this.DragTypeMouseDown)
			{
				case 5:
				    eventType = "tables";
				    break;
				default:
					eventType = "margins";
					break;
			}

			if (eventType != "")
			{
				word_control.m_oApi.sendEvent("asc_onRulerDblClick", eventType);
				this.DragType = 0;
				this.OnMouseUp(left, top, e);
				return;
			}
		}

        switch (this.DragType)
        {
            case 1:
            {
                var pos = top + this.m_dMarginTop * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.HorLine(pos);
                break;
            }
            case 2:
            {
                var pos = top + this.m_dMarginBottom * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.HorLine(pos);
                break;
            }
            case 3:
            {
                var pos = top + this.header_top * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.HorLine(pos);
                break;
            }
            case 4:
            {
                var pos = top + this.header_bottom * dKoef_mm_to_pix;
                word_control.m_oOverlayApi.HorLine(pos);
                break;
            }
            case 5:
            {
                var pos = 0;
                if (0 == this.DragTablePos)
                {
                    pos = top + this.m_oTableMarkup.Rows[0].Y * dKoef_mm_to_pix;
                    word_control.m_oOverlayApi.HorLine(pos);
                }
                else
                {
                    pos = top + (this.m_oTableMarkup.Rows[this.DragTablePos - 1].Y + this.m_oTableMarkup.Rows[this.DragTablePos - 1].H) * dKoef_mm_to_pix;
                    word_control.m_oOverlayApi.HorLine(pos);
                }
            }
        }

        word_control.m_oDrawingDocument.LockCursorTypeCur();
    }

    this.OnMouseUp = function(left, top, e)
    {
        var lockedElement = AscCommon.check_MouseUpEvent(e);

        //this.m_oWordControl.m_oOverlayApi.UnShow();
        this.m_oWordControl.OnUpdateOverlay();

        switch (this.DragType)
        {
            case 1:
            case 2:
            {
                if (!this.SimpleChanges.IsSimple)
                    this.SetMarginProperties();
                break;
            }
            case 3:
            case 4:
            {
                if (!this.SimpleChanges.IsSimple)
                    this.SetHeaderProperties();
                break;
            }
            case 5:
            {
                if (!this.SimpleChanges.IsSimple)
                    this.SetTableProperties();
                this.DragTablePos = -1;
                break;
            }
        }

        this.DragType = 0;
        this.m_oWordControl.m_oDrawingDocument.UnlockCursorType();

        this.SimpleChanges.Clear();
    }

    this.OnMouseUpExternal = function()
    {
        //this.m_oWordControl.m_oOverlayApi.UnShow();
        this.m_oWordControl.OnUpdateOverlay();

        switch (this.DragType)
        {
            case 1:
            case 2:
            {
                if (!this.SimpleChanges.IsSimple)
                    this.SetMarginProperties();
                break;
            }
            case 3:
            case 4:
            {
                if (!this.SimpleChanges.IsSimple)
                    this.SetHeaderProperties();
                break;
            }
            case 5:
            {
                if (!this.SimpleChanges.IsSimple)
                    this.SetTableProperties();
                this.DragTablePos = -1;
                break;
            }
        }

        this.DragType = 0;
        this.m_oWordControl.m_oDrawingDocument.UnlockCursorType();

        this.SimpleChanges.Clear();
    }

    this.BlitToMain = function(left, top, htmlElement)
    {
        if (!this.RepaintChecker.BlitAttack && top == this.RepaintChecker.BlitTop)
            return;
        this.RepaintChecker.BlitTop = top;
        this.RepaintChecker.BlitAttack = false;

        htmlElement.width = htmlElement.width;
        var context = htmlElement.getContext('2d');

        if (null != this.m_oCanvas)
        {
            if (!this.IsRetina)
            {
                context.drawImage(this.m_oCanvas, 0, 5, this.m_oCanvas.width, this.m_oCanvas.height - 10,
                    0, top, this.m_oCanvas.width, this.m_oCanvas.height - 10);
            }
            else
            {
                context.drawImage(this.m_oCanvas, 0, 10, this.m_oCanvas.width, this.m_oCanvas.height - 20,
                    0, top << 1, this.m_oCanvas.width, this.m_oCanvas.height - 20);
            }
        }
    }

    // выставление параметров логическому документу
    this.SetMarginProperties = function()
    {
        if ( false === this.m_oWordControl.m_oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_Document_SectPr) )
        {
            this.m_oWordControl.m_oLogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetDocumentMargin_Ver);
            this.m_oWordControl.m_oLogicDocument.Set_DocumentMargin( { Top : this.m_dMarginTop, Bottom : this.m_dMarginBottom });
        }
    }
    this.SetHeaderProperties = function()
    {
        if ( false === this.m_oWordControl.m_oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_HdrFtr) )
        {
            // TODO: в данной функции при определенных параметрах может меняться верхнее поле. Поэтому, надо
            //       вставить проверку на залоченность с типом changestype_Document_SectPr

            this.m_oWordControl.m_oLogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetHdrFtrBounds);
            this.m_oWordControl.m_oLogicDocument.Document_SetHdrFtrBounds(this.header_top, this.header_bottom);
        }
    }
    this.SetTableProperties = function()
    {
        if ( false === this.m_oWordControl.m_oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_Table_Properties) )
        {
            this.m_oWordControl.m_oLogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_SetTableMarkup_Ver);

            this.m_oTableMarkup.CorrectTo();
            this.m_oTableMarkup.Table.Update_TableMarkupFromRuler(this.m_oTableMarkup, false, this.DragTablePos);
            if (this.m_oTableMarkup)
                this.m_oTableMarkup.CorrectFrom();
        }
    }
}

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var g_fontApplication = AscFonts.g_fontApplication;

var AscBrowser             = AscCommon.AscBrowser;
var g_anchor_left          = AscCommon.g_anchor_left;
var g_anchor_top           = AscCommon.g_anchor_top;
var g_anchor_right         = AscCommon.g_anchor_right;
var g_anchor_bottom        = AscCommon.g_anchor_bottom;
var CreateControlContainer = AscCommon.CreateControlContainer;
var CreateControl          = AscCommon.CreateControl;
var global_keyboardEvent   = AscCommon.global_keyboardEvent;
var global_mouseEvent      = AscCommon.global_mouseEvent;
var History                = AscCommon.History;
var g_dKoef_pix_to_mm      = AscCommon.g_dKoef_pix_to_mm;
var g_dKoef_mm_to_pix      = AscCommon.g_dKoef_mm_to_pix;

var g_bIsMobile = AscBrowser.isMobile;

var Page_Width  = 210;
var Page_Height = 297;

var X_Left_Margin   = 30;  // 3   cm
var X_Right_Margin  = 15;  // 1.5 cm
var Y_Bottom_Margin = 20;  // 2   cm
var Y_Top_Margin    = 20;  // 2   cm

var X_Right_Field  = Page_Width - X_Right_Margin;
var Y_Bottom_Field = Page_Height - Y_Bottom_Margin;

var tableSpacingMinValue = 0.02;//0.02мм

var GlobalSkinTeamlab = {
	Name                   : "classic",
	RulersButton           : true,
	NavigationButtons      : true,
	BackgroundColor        : "#B0B0B0",
	RulerDark              : "#B0B0B0",
	RulerLight             : "EDEDED",
	BackgroundScroll       : "#D3D3D3",
	RulerOutline           : "#929292",
	RulerMarkersFillColor  : "#E7E7E7",
	PageOutline            : "#81878F",
	STYLE_THUMBNAIL_WIDTH  : 80,
	STYLE_THUMBNAIL_HEIGHT : 40,
	ContentControlsBack	   : "#F1F1F1",
	ContentControlsHover   : "#D8DADC",
	ContentControlsActive  : "#7C838A",
	ContentControlsText    : "#444444",
	ContentControlsTextActive   : "#FFFFFF",
	ContentControlsAnchorActive : "#CFCFCF"
};
var GlobalSkinFlat    = {
	Name                   : "flat",
	RulersButton           : false,
	NavigationButtons      : false,
	BackgroundColor        : "#F4F4F4",
	RulerDark              : "#CFCFCF",
	RulerLight             : "#FFFFFF",
	BackgroundScroll       : "#F1F1F1",
	RulerOutline           : "#BBBEC2",
	RulerMarkersFillColor  : "#FFFFFF",
	PageOutline            : "#BBBEC2",
	STYLE_THUMBNAIL_WIDTH  : 104,
	STYLE_THUMBNAIL_HEIGHT : 38,
	isNeedInvertOnActive   : false,
	ContentControlsBack	   : "#F1F1F1",
	ContentControlsHover   : "#D8DADC",
	ContentControlsActive  : "#7C838A",
	ContentControlsText    : "#444444",
	ContentControlsTextActive   : "#FFFFFF",
	ContentControlsAnchorActive : "#CFCFCF"
};
var GlobalSkinFlat2    = {
	Name                   : "flat",
	RulersButton           : false,
	NavigationButtons      : false,
	BackgroundColor        : "#E2E2E2",
	RulerDark              : "#CFCFCF",
	RulerLight             : "#FFFFFF",
	BackgroundScroll       : "#E2E2E2",
	RulerOutline           : "#BBBEC2",
	RulerMarkersFillColor  : "#FFFFFF",
	PageOutline            : "#BBBEC2",
	STYLE_THUMBNAIL_WIDTH  : 104,
	STYLE_THUMBNAIL_HEIGHT : 38,
	isNeedInvertOnActive   : false,
	ContentControlsBack	   : "#F1F1F1",
	ContentControlsHover   : "#D8DADC",
	ContentControlsActive  : "#7C838A",
	ContentControlsText    : "#444444",
	ContentControlsTextActive   : "#FFFFFF",
	ContentControlsAnchorActive : "#CFCFCF"
};

var GlobalSkin = GlobalSkinFlat2;
if (AscCommon.TEMP_STYLE_THUMBNAIL_WIDTH !== undefined && AscCommon.TEMP_STYLE_THUMBNAIL_HEIGHT !== undefined)
{
	// TODO: переделать.
	GlobalSkin.STYLE_THUMBNAIL_WIDTH = AscCommon.TEMP_STYLE_THUMBNAIL_WIDTH;
	GlobalSkin.STYLE_THUMBNAIL_HEIGHT = AscCommon.TEMP_STYLE_THUMBNAIL_HEIGHT;
}

function updateGlobalSkin(newSkin)
{
	GlobalSkin.Name                   = newSkin.Name;
	GlobalSkin.RulersButton           = newSkin.RulersButton;
	GlobalSkin.NavigationButtons      = newSkin.NavigationButtons;
	GlobalSkin.BackgroundColor        = newSkin.BackgroundColor;
	GlobalSkin.RulerDark              = newSkin.RulerDark;
	GlobalSkin.RulerLight             = newSkin.RulerLight;
	GlobalSkin.BackgroundScroll       = newSkin.BackgroundScroll;
	GlobalSkin.RulerOutline           = newSkin.RulerOutline;
	GlobalSkin.RulerMarkersFillColor  = newSkin.RulerMarkersFillColor;
	GlobalSkin.PageOutline            = newSkin.PageOutline;
	GlobalSkin.STYLE_THUMBNAIL_WIDTH  = newSkin.STYLE_THUMBNAIL_WIDTH;
	GlobalSkin.STYLE_THUMBNAIL_HEIGHT = newSkin.STYLE_THUMBNAIL_HEIGHT;
	GlobalSkin.isNeedInvertOnActive   = newSkin.isNeedInvertOnActive;
}

function CEditorPage(api)
{
	this.Name = "";

	this.X      = 0;
	this.Y      = 0;
	this.Width  = 10;
	this.Height = 10;

	this.m_oBody        = null;
	this.m_oMenu        = null;
	this.m_oPanelRight  = null;
	this.m_oScrollHor   = null;
	this.m_oMainContent = null;
	this.m_oLeftRuler   = null;
	this.m_oTopRuler    = null;
	this.m_oMainView    = null;
	this.m_oEditor      = null;
	this.m_oOverlay     = null;

	this.TextBoxBackground = null;

	this.ReaderModeDivWrapper = null;
	this.ReaderModeDiv        = null;

	this.m_oOverlayApi = new AscCommon.COverlay();
	this.m_bIsIE       = (AscBrowser.isIE || window.opera) ? true : false;

	this.m_oPanelRight_buttonRulers   = null;
	this.m_oPanelRight_vertScroll     = null;
	this.m_oPanelRight_buttonPrevPage = null;
	this.m_oPanelRight_buttonNextPage = null;

	this.m_oLeftRuler_buttonsTabs = null;
	this.m_oLeftRuler_vertRuler   = null;

	this.m_oTopRuler_horRuler = null;

	this.m_bIsHorScrollVisible          = false;
	this.m_bIsRuler                     = (api.isMobileVersion === true) ? false : true;
	this.m_bDocumentPlaceChangedEnabled = false;

	this.m_nZoomValue        = 100;
	this.m_oBoundsController = new AscFormat.CBoundsController();
	this.m_nTabsType         = 0;

	this.m_dScrollY           = 0;
	this.m_dScrollX           = 0;
	this.m_dScrollY_max       = 1;
	this.m_dScrollX_max       = 1;
	this.m_bIsRePaintOnScroll = true;

	this.m_dDocumentWidth      = 0;
	this.m_dDocumentHeight     = 0;
	this.m_dDocumentPageWidth  = 0;
	this.m_dDocumentPageHeight = 0;

	this.NoneRepaintPages = false;

	this.m_bIsScroll    = false;
	this.ScrollsWidthPx = 14;

	this.m_oHorRuler = new CHorRuler();
	this.m_oVerRuler = new CVerRuler();

	this.m_oDrawingDocument = new AscCommon.CDrawingDocument();
	this.m_oLogicDocument   = null;

	this.m_oDrawingDocument.m_oWordControl   = this;
	this.m_oDrawingDocument.m_oLogicDocument = this.m_oLogicDocument;

	this.m_bIsUpdateHorRuler       = false;
	this.m_bIsUpdateVerRuler       = false;
	this.m_bIsUpdateTargetNoAttack = false;

	this.m_bIsFullRepaint = false;

	this.m_oScrollHor_ = null;
	this.m_oScrollVer_ = null;

	this.m_oScrollHorApi = null;
	this.m_oScrollVerApi = null;

	this.arrayEventHandlers = [];

	this.m_oTimerScrollSelect = -1;
	this.IsFocus              = true;
	this.m_bIsMouseLock       = false;

	this.DrawingFreeze      = false;

	this.m_oHorRuler.m_oWordControl = this;
	this.m_oVerRuler.m_oWordControl = this;

	this.IsKeyDownButNoPress = false;

	this.MouseDownDocumentCounter = 0;

	this.bIsUseKeyPress = true;
	this.bIsEventPaste  = false;
	this.bIsDoublePx    = true;//поддерживает ли браузер нецелые пикселы
	var oTestSpan       = document.createElement("span");
	oTestSpan.setAttribute("style", "font-size:8pt");
	document.body.appendChild(oTestSpan);
	var defaultView   = oTestSpan.ownerDocument.defaultView;
	var computedStyle = defaultView.getComputedStyle(oTestSpan, null);
	if (null != computedStyle)
	{
		var fontSize = computedStyle.getPropertyValue("font-size");
		if (-1 != fontSize.indexOf("px") && parseFloat(fontSize) == parseInt(fontSize))
			this.bIsDoublePx = false;
	}
	document.body.removeChild(oTestSpan);

	this.m_nPaintTimerId          = -1;
	this.m_nTimerScrollInterval   = 40;
	this.m_nCurrentTimeClearCache = 0;

	this.m_bIsMouseUpSend = false;

	this.zoom_values = [50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200];
	this.m_nZoomType = 0; // 0 - custom, 1 - fitToWodth, 2 - fitToPage

	this.MobileTouchManager = null;
	this.ReaderTouchManager = null;
	this.ReaderModeCurrent  = 0;

	this.ReaderFontSizeCur = 2;
	this.ReaderFontSizes   = [12, 14, 16, 18, 22, 28, 36, 48, 72];

	this.bIsRetinaSupport         = true;
	this.bIsRetinaNoSupportAttack = false;

	this.IsUpdateOverlayOnlyEnd       = false;
	this.IsUpdateOverlayOnlyEndReturn = false;
	this.IsUpdateOverlayOnEndCheck    = false;

	this.m_oApi = api;
	var oThis   = this;

	//this.UseRequestAnimationFrame = false;
	this.UseRequestAnimationFrame = AscCommon.AscBrowser.isChrome;
	this.RequestAnimationFrame    = (function()
	{
		return window.requestAnimationFrame ||
			window.webkitRequestAnimationFrame ||
			window.mozRequestAnimationFrame ||
			window.oRequestAnimationFrame ||
			window.msRequestAnimationFrame || null;
	})();
	this.CancelAnimationFrame     = (function()
	{
		return window.cancelRequestAnimationFrame ||
			window.webkitCancelAnimationFrame ||
			window.webkitCancelRequestAnimationFrame ||
			window.mozCancelRequestAnimationFrame ||
			window.oCancelRequestAnimationFrame ||
			window.msCancelRequestAnimationFrame || null;
	})();

	if (this.UseRequestAnimationFrame)
	{
		if (null == this.RequestAnimationFrame)
			this.UseRequestAnimationFrame = false;
	}
	this.RequestAnimationOldTime = -1;

	this.IsInitControl = false;

	this.checkBodyOffset = function()
	{
		var off = jQuery("#" + this.Name).offset();

		if (off)
		{
			this.X = off.left;
			this.Y = off.top;
		}
	}

	this.checkBodySize = function()
	{
		this.checkBodyOffset();

		var el = document.getElementById(this.Name);

		var _newW = el.offsetWidth;
		var _newH = el.offsetHeight;

		var _left_border_w = 0;
		if (window.getComputedStyle)
		{
			var _computed_style = window.getComputedStyle(el, null);
			if (_computed_style)
			{
				var _value = _computed_style.getPropertyValue("border-left-width");

				if (typeof _value == "string")
				{
					_left_border_w = parseInt(_value);
				}
			}
		}

		_newW -= _left_border_w;
		if (this.Width != _newW || this.Height != _newH)
		{
			this.Width  = _newW;
			this.Height = _newH;
			return true;
		}
		return false;
	};

	this.Init = function()
	{
		this.m_oBody = CreateControlContainer(this.Name);

		var scrollWidthMm = this.ScrollsWidthPx * g_dKoef_pix_to_mm;

		this.m_oScrollHor = CreateControlContainer("id_horscrollpanel");
		this.m_oScrollHor.Bounds.SetParams(0, 0, scrollWidthMm, 0, false, false, true, true, -1, scrollWidthMm);
		this.m_oScrollHor.Anchor = (g_anchor_left | g_anchor_right | g_anchor_bottom);
		this.m_oBody.AddControl(this.m_oScrollHor);

		// panel right --------------------------------------------------------------
		this.m_oPanelRight = CreateControlContainer("id_panel_right");
		this.m_oPanelRight.Bounds.SetParams(0, 0, 1000, 0, false, true, false, true, scrollWidthMm, -1);
		this.m_oPanelRight.Anchor = (g_anchor_top | g_anchor_right | g_anchor_bottom);

		this.m_oBody.AddControl(this.m_oPanelRight);
		if (this.m_oApi.isMobileVersion)
		{
			this.m_oPanelRight.HtmlElement.style.zIndex = -1;

			var hor_scroll          = document.getElementById('id_horscrollpanel');
			hor_scroll.style.zIndex = -1;
		}

		this.m_oPanelRight_buttonRulers = CreateControl("id_buttonRulers");
		this.m_oPanelRight_buttonRulers.Bounds.SetParams(0, 0, 1000, 1000, false, false, false, false, -1, scrollWidthMm);
		this.m_oPanelRight_buttonRulers.Anchor = (g_anchor_left | g_anchor_top | g_anchor_right);
		this.m_oPanelRight.AddControl(this.m_oPanelRight_buttonRulers);

		var _vertScrollTop = scrollWidthMm;
		if (GlobalSkin.RulersButton === false)
		{
			this.m_oPanelRight_buttonRulers.HtmlElement.style.display = "none";
			_vertScrollTop                                            = 0;
		}

		this.m_oPanelRight_buttonNextPage = CreateControl("id_buttonNextPage");
		this.m_oPanelRight_buttonNextPage.Bounds.SetParams(0, 0, 1000, 1000, false, false, false, false, -1, scrollWidthMm);
		this.m_oPanelRight_buttonNextPage.Anchor = (g_anchor_left | g_anchor_bottom | g_anchor_right);
		this.m_oPanelRight.AddControl(this.m_oPanelRight_buttonNextPage);

		this.m_oPanelRight_buttonPrevPage = CreateControl("id_buttonPrevPage");
		this.m_oPanelRight_buttonPrevPage.Bounds.SetParams(0, 0, 1000, scrollWidthMm, false, false, false, true, -1, scrollWidthMm);
		this.m_oPanelRight_buttonPrevPage.Anchor = (g_anchor_left | g_anchor_bottom | g_anchor_right);
		this.m_oPanelRight.AddControl(this.m_oPanelRight_buttonPrevPage);

		var _vertScrollBottom = 2 * scrollWidthMm;
		if (GlobalSkin.NavigationButtons == false)
		{
			this.m_oPanelRight_buttonNextPage.HtmlElement.style.display = "none";
			this.m_oPanelRight_buttonPrevPage.HtmlElement.style.display = "none";
			_vertScrollBottom                                           = 0;
		}

		this.m_oPanelRight_vertScroll = CreateControl("id_vertical_scroll");
		this.m_oPanelRight_vertScroll.Bounds.SetParams(0, _vertScrollTop, 1000, _vertScrollBottom, false, true, false, true, -1, -1);
		this.m_oPanelRight_vertScroll.Anchor = (g_anchor_left | g_anchor_top | g_anchor_right | g_anchor_bottom);
		this.m_oPanelRight.AddControl(this.m_oPanelRight_vertScroll);
		// --------------------------------------------------------------------------

		// main content -------------------------------------------------------------
		this.m_oMainContent = CreateControlContainer("id_main");
		if (!this.m_oApi.isMobileVersion)
			this.m_oMainContent.Bounds.SetParams(0, 0, scrollWidthMm, 0, false, true, true, true, -1, -1);
		else
			this.m_oMainContent.Bounds.SetParams(0, 0, 0, 0, false, true, true, true, -1, -1);
		this.m_oMainContent.Anchor = (g_anchor_left | g_anchor_top | g_anchor_right | g_anchor_bottom);
		this.m_oBody.AddControl(this.m_oMainContent);

		// --- left ---
		this.m_oLeftRuler = CreateControlContainer("id_panel_left");
		this.m_oLeftRuler.Bounds.SetParams(0, 0, 1000, 1000, false, false, false, false, 5, -1);
		this.m_oLeftRuler.Anchor = (g_anchor_left | g_anchor_top | g_anchor_bottom);
		this.m_oMainContent.AddControl(this.m_oLeftRuler);

		this.m_oLeftRuler_buttonsTabs = CreateControl("id_buttonTabs");
		this.m_oLeftRuler_buttonsTabs.Bounds.SetParams(0, 0.8, 1000, 1000, false, true, false, false, -1, 5);
		this.m_oLeftRuler_buttonsTabs.Anchor = (g_anchor_left | g_anchor_top | g_anchor_right);
		this.m_oLeftRuler.AddControl(this.m_oLeftRuler_buttonsTabs);

		this.m_oLeftRuler_vertRuler = CreateControl("id_vert_ruler");
		this.m_oLeftRuler_vertRuler.Bounds.SetParams(0, 7, 1000, 1000, false, true, false, false, -1, -1);
		this.m_oLeftRuler_vertRuler.Anchor = (g_anchor_left | g_anchor_right | g_anchor_top | g_anchor_bottom);
		this.m_oLeftRuler.AddControl(this.m_oLeftRuler_vertRuler);
		// ------------

		// --- top ----
		this.m_oTopRuler = CreateControlContainer("id_panel_top");
		this.m_oTopRuler.Bounds.SetParams(5, 0, 1000, 1000, true, false, false, false, -1, 7);
		this.m_oTopRuler.Anchor = (g_anchor_left | g_anchor_top | g_anchor_right);
		this.m_oMainContent.AddControl(this.m_oTopRuler);

		this.m_oTopRuler_horRuler = CreateControl("id_hor_ruler");
		this.m_oTopRuler_horRuler.Bounds.SetParams(0, 0, 1000, 1000, false, false, false, false, -1, -1);
		this.m_oTopRuler_horRuler.Anchor = (g_anchor_left | g_anchor_right | g_anchor_top | g_anchor_bottom);
		this.m_oTopRuler.AddControl(this.m_oTopRuler_horRuler);
		// ------------

		this.m_oMainView = CreateControlContainer("id_main_view");
		this.m_oMainView.Bounds.SetParams(5, 7, 1000, 1000, true, true, false, false, -1, -1);
		this.m_oMainView.Anchor = (g_anchor_left | g_anchor_right | g_anchor_top | g_anchor_bottom);
		this.m_oMainContent.AddControl(this.m_oMainView);

		this.m_oEditor = CreateControl("id_viewer");
		this.m_oEditor.Bounds.SetParams(0, 0, 1000, 1000, false, false, false, false, -1, -1);
		this.m_oEditor.Anchor = (g_anchor_left | g_anchor_top | g_anchor_right | g_anchor_bottom);
		this.m_oMainView.AddControl(this.m_oEditor);

		this.m_oOverlay = CreateControl("id_viewer_overlay");
		this.m_oOverlay.Bounds.SetParams(0, 0, 1000, 1000, false, false, false, false, -1, -1);
		this.m_oOverlay.Anchor = (g_anchor_left | g_anchor_top | g_anchor_right | g_anchor_bottom);
		this.m_oMainView.AddControl(this.m_oOverlay);
		// --------------------------------------------------------------------------

		this.m_oDrawingDocument.TargetHtmlElement = document.getElementById('id_target_cursor');

		if (this.m_oApi.isMobileVersion)
		{
			this.MobileTouchManager = new AscCommon.CMobileTouchManager( { eventsElement : "word_mobile_element" } );
			this.MobileTouchManager.Init(this.m_oApi);
		}

		this.checkNeedRules();
		this.initEvents2();

		this.m_oOverlayApi.m_oControl  = this.m_oOverlay;
		this.m_oOverlayApi.m_oHtmlPage = this;
		this.m_oOverlayApi.Clear();
		this.ShowOverlay();

		this.m_oDrawingDocument.AutoShapesTrack = new AscCommon.CAutoshapeTrack();
		this.m_oDrawingDocument.AutoShapesTrack.init2(this.m_oOverlayApi);

		this.OnResize(true);
	};

	this.CheckRetinaDisplay = function()
	{
		var old = this.bIsRetinaSupport;
		if (!this.bIsRetinaNoSupportAttack)
		{
			this.bIsRetinaSupport       = AscBrowser.isRetina;
			this.m_oOverlayApi.IsRetina = this.bIsRetinaSupport;
		}
		else
		{
			this.bIsRetinaSupport = false;
			this.m_oOverlayApi.IsRetina = this.bIsRetinaSupport;
		}

		if (old != this.bIsRetinaSupport)
		{
			this.m_oDrawingDocument.ClearCachePages();
			this.onButtonTabsDraw();
		}
	};

	this.ShowOverlay        = function()
	{
		this.m_oOverlay.HtmlElement.style.display = "block";

		if (null == this.m_oOverlayApi.m_oContext)
			this.m_oOverlayApi.m_oContext = this.m_oOverlayApi.m_oControl.HtmlElement.getContext('2d');
	};
	this.UnShowOverlay      = function()
	{
		this.m_oOverlay.HtmlElement.style.display = "none";
	};
	this.CheckUnShowOverlay = function()
	{
		var drDoc = this.m_oDrawingDocument;
		if (!drDoc.m_bIsSearching && !drDoc.m_bIsSelection && !this.MobileTouchManager)
		{
			this.UnShowOverlay();
			return false;
		}
		return true;
	};
	this.CheckShowOverlay   = function()
	{
		var drDoc = this.m_oDrawingDocument;
		if (drDoc.m_bIsSearching || drDoc.m_bIsSelection || this.MobileTouchManager)
			this.ShowOverlay();
	};

	this.initEvents2 = function()
	{
		this.arrayEventHandlers[0] = new AscCommon.button_eventHandlers("", "0px 0px", "0px -16px", "0px -32px", this.m_oPanelRight_buttonRulers, this.onButtonRulersClick);
		this.arrayEventHandlers[1] = new AscCommon.button_eventHandlers("", "0px 0px", "0px -16px", "0px -32px", this.m_oPanelRight_buttonPrevPage, this.onPrevPage);
		this.arrayEventHandlers[2] = new AscCommon.button_eventHandlers("", "0px -48px", "0px -64px", "0px -80px", this.m_oPanelRight_buttonNextPage, this.onNextPage);

		this.m_oLeftRuler_buttonsTabs.HtmlElement.onclick = this.onButtonTabsClick;//new Function("onButtonTabsClick();");

		this.m_oEditor.HtmlElement.onmousedown = this.onMouseDown;//new Function("event", "return Editor_OnMouseDown(event);");
		this.m_oEditor.HtmlElement.onmousemove = this.onMouseMove;//new Function("event", "return Editor_OnMouseMove(event);");
		this.m_oEditor.HtmlElement.onmouseup   = this.onMouseUp;//new Function("event", "return Editor_OnMouseUp(event);");

		this.m_oOverlay.HtmlElement.onmousedown = this.onMouseDown;//new Function("event", "return Editor_OnMouseDown(event);");
		this.m_oOverlay.HtmlElement.onmousemove = this.onMouseMove;//new Function("event", "return Editor_OnMouseMove(event);");
		this.m_oOverlay.HtmlElement.onmouseup   = this.onMouseUp;//new Function("event", "return Editor_OnMouseUp(event);");

		var _cur         = document.getElementById('id_target_cursor');
		_cur.onmousedown = this.onMouseDown;//new Function("event", "return Editor_OnMouseDown(event);");
		_cur.onmousemove = this.onMouseMove;//new Function("event", "return Editor_OnMouseMove(event);");
		_cur.onmouseup   = this.onMouseUp;//new Function("event", "return Editor_OnMouseUp(event);");

		this.m_oMainContent.HtmlElement.onmousewheel = this.onMouseWhell;//new Function("event", "return Editor_OnMouseWhell(event);");
		if (this.m_oMainContent.HtmlElement.addEventListener)
		{
			//this.m_oMainContent.HtmlElement.addEventListener("DOMMouseScroll", new Function("event", "return Editor_OnMouseWhell(event);"), false);
			this.m_oMainContent.HtmlElement.addEventListener("DOMMouseScroll", this.onMouseWhell, false);
		}

		this.m_oTopRuler_horRuler.HtmlElement.onmousedown = this.horRulerMouseDown;//new Function("event", "horRulerMouseDown(event);");
		this.m_oTopRuler_horRuler.HtmlElement.onmouseup   = this.horRulerMouseUp;//new Function("event", "horRulerMouseUp(event);");
		this.m_oTopRuler_horRuler.HtmlElement.onmousemove = this.horRulerMouseMove;//new Function("event", "horRulerMouseMove(event);");

		this.m_oLeftRuler_vertRuler.HtmlElement.onmousedown = this.verRulerMouseDown;//new Function("event", "verRulerMouseDown(event);");
		this.m_oLeftRuler_vertRuler.HtmlElement.onmouseup   = this.verRulerMouseUp;//new Function("event", "verRulerMouseUp(event);");
		this.m_oLeftRuler_vertRuler.HtmlElement.onmousemove = this.verRulerMouseMove;//new Function("event", "verRulerMouseMove(event);");

		/*
		 // теперь все делает AscCommon.InitBrowserSystemContext
		 window.onkeydown = this.onKeyDown;//Editor_OnKeyDown;
		 window.onkeypress = this.onKeyPress;//Editor_OnKeyPress;
		 window.onkeyup = this.onKeyUp;
		 */

		this.m_oBody.HtmlElement.oncontextmenu = function(e)
		{
			if (AscCommon.AscBrowser.isVivaldiLinux)
			{
				AscCommon.Window_OnMouseUp(e);
			}
			AscCommon.stopEvent(e);
			return false;
		};
		//window.oncontextmenu = function() { return false; };

		this.initEvents2MobileAdvances();
	};

	this.initEvents2MobileAdvances = function()
	{
		/*
		 this.m_oEditor.HtmlElement["ontouchstart"] = function (e){
		 if (oThis.TouchManager.StartTouches(e, oThis.m_bIsHorScrollVisible ? oThis.m_dScrollX : undefined, oThis.m_dScrollY) === false)
		 {
		 oThis.onMouseUp(e.touches[0]);
		 return false;
		 }

		 oThis.onMouseDown(e.touches[0]);
		 return false;
		 }
		 this.m_oEditor.HtmlElement["ontouchmove"] = function (e){
		 if (oThis.TouchManager.MoveTouches(e) === false)
		 return false;

		 oThis.onMouseMove(e.touches[0]);
		 return false;
		 }
		 this.m_oEditor.HtmlElement["ontouchend"] = function (e){
		 if (oThis.TouchManager.EndTouches(e) === false)
		 return false;

		 oThis.onMouseUp(e.changedTouches[0]);
		 return false;
		 }

		 this.m_oOverlay.HtmlElement["ontouchstart"] = function (e){
		 if (oThis.TouchManager.StartTouches(e, oThis.m_bIsHorScrollVisible ? oThis.m_dScrollX : undefined, oThis.m_dScrollY) === false)
		 {
		 oThis.onMouseUp(e.touches[0]);
		 return false;
		 }

		 oThis.onMouseDown(e.touches[0]);
		 return false;
		 }
		 this.m_oOverlay.HtmlElement["ontouchmove"] = function (e){
		 if (oThis.TouchManager.MoveTouches(e) === false)
		 return false;

		 oThis.onMouseMove(e.touches[0]);
		 return false;
		 }
		 this.m_oOverlay.HtmlElement["ontouchend"] = function (e){
		 if (oThis.TouchManager.EndTouches(e) === false)
		 return false;

		 oThis.onMouseUp(e.changedTouches[0]);
		 return false;
		 }
		 */

		this.m_oTopRuler_horRuler.HtmlElement["ontouchstart"] = function(e)
		{
			oThis.horRulerMouseDown(e.touches[0]);
			return false;
		};
		this.m_oTopRuler_horRuler.HtmlElement["ontouchmove"]  = function(e)
		{
			oThis.horRulerMouseMove(e.touches[0]);
			return false;
		};
		this.m_oTopRuler_horRuler.HtmlElement["ontouchend"]   = function(e)
		{
			oThis.horRulerMouseUp(e.changedTouches[0]);
			return false;
		};

		this.m_oLeftRuler_vertRuler.HtmlElement["ontouchstart"] = function(e)
		{
			oThis.verRulerMouseDown(e.touches[0]);
			return false;
		};
		this.m_oLeftRuler_vertRuler.HtmlElement["ontouchmove"]  = function(e)
		{
			oThis.verRulerMouseMove(e.touches[0]);
			return false;
		};
		this.m_oLeftRuler_vertRuler.HtmlElement["ontouchend"]   = function(e)
		{
			oThis.verRulerMouseUp(e.changedTouches[0]);
			return false;
		};

		if (!this.m_oApi.isMobileVersion)
		{
			var _check_e = function(e)
			{
				if (e.touches && e.touches[0])
					return e.touches[0];
				if (e.changedTouches && e.changedTouches[0])
					return e.changedTouches[0];
				return e;
			};

			var _cur = document.getElementById('id_target_cursor');

			_cur["ontouchstart"] = this.m_oEditor.HtmlElement["ontouchstart"] = this.m_oOverlay.HtmlElement["ontouchstart"] 	= function(e) {
				//console.log("start: " + AscCommon.isTouch);
				if (AscCommon.isTouch)
					return;

				var _old = global_mouseEvent.KoefPixToMM;
				global_mouseEvent.KoefPixToMM = 5;
				AscCommon.isTouch 			= true;
				AscCommon.isTouchMove 		= false;
				AscCommon.TouchStartTime 	= new Date().getTime();
				AscCommon.stopEvent(e);
				var _ret = this.onmousedown(_check_e(e), true);
				global_mouseEvent.KoefPixToMM = _old;

				if ((document.activeElement !== undefined) &&
					(AscCommon.g_inputContext != null) &&
					(document.activeElement != AscCommon.g_inputContext.HtmlArea))
				{
					AscCommon.g_inputContext.HtmlArea.focus();
				}

				return _ret;
			};
			_cur["ontouchmove"] = this.m_oEditor.HtmlElement["ontouchmove"] = this.m_oOverlay.HtmlElement["ontouchmove"] 		= function(e) {
				//console.log("move: " + AscCommon.isTouch);

				var _old = global_mouseEvent.KoefPixToMM;
				global_mouseEvent.KoefPixToMM = 5;
				AscCommon.isTouch 		= true;
				AscCommon.isTouchMove 	= true;
				AscCommon.stopEvent(e);
				var _ret = this.onmousemove(_check_e(e), true);
				global_mouseEvent.KoefPixToMM = _old;
				return _ret;
			};
			_cur["ontouchend"] = this.m_oEditor.HtmlElement["ontouchend"] = this.m_oOverlay.HtmlElement["ontouchend"] 		= function(e) {
				//console.log("end: " + AscCommon.isTouch);

				if (!AscCommon.isTouch)
					return;

				var _old = global_mouseEvent.KoefPixToMM;
				global_mouseEvent.KoefPixToMM = 5;
				AscCommon.isTouch = false;
				AscCommon.stopEvent(e);
				var _natE = _check_e(e);
				var _ret = this.onmouseup(_natE, undefined, true);
				global_mouseEvent.KoefPixToMM = _old;

				if (!AscCommon.isTouchMove && (-1 != AscCommon.TouchStartTime) && (Math.abs(AscCommon.TouchStartTime - (new Date().getTime())) > 900))
				{
					var _eContextMenu = {
						pageX   : _natE.pageX,
						pageY   : _natE.pageY,
						clientX : _natE.clientX,
						clientY : _natE.clientY,

						altKey   : _natE.altKey,
						shiftKey : _natE.shiftKey,
						ctrlKey  : _natE.ctrlKey,
						metaKey  : _natE.metaKey,

						button : AscCommon.g_mouse_button_right,

						target     : e.target,
						srcElement : e.srcElement
					};

					AscCommon.isTouch = true;
					this.onmousedown(_eContextMenu, true);
					this.onmouseup(_eContextMenu, undefined, true);
					AscCommon.isTouch = false;
				}
				AscCommon.isTouchMove = false;
				AscCommon.TouchStartTime = -1;

				return _ret;
			};
			_cur["ontouchcancel"] = this.m_oEditor.HtmlElement["ontouchcancel"] = this.m_oOverlay.HtmlElement["ontouchcancel"] 	= function(e) {
				//console.log("cancel: " + AscCommon.isTouch);

				if (!AscCommon.isTouch)
					return;

				var _old = global_mouseEvent.KoefPixToMM;
				global_mouseEvent.KoefPixToMM = 5;
				AscCommon.isTouch = false;
				AscCommon.stopEvent(e);
				var _natE = _check_e(e);
				var _ret = this.onmouseup(_natE, undefined, true);
				global_mouseEvent.KoefPixToMM = _old;

				if (!AscCommon.isTouchMove && (-1 != AscCommon.TouchStartTime) && (Math.abs(AscCommon.TouchStartTime - (new Date().getTime())) > 900))
				{
					var _eContextMenu = {
						pageX   : _natE.pageX,
						pageY   : _natE.pageY,
						clientX : _natE.clientX,
						clientY : _natE.clientY,

						altKey   : _natE.altKey,
						shiftKey : _natE.shiftKey,
						ctrlKey  : _natE.ctrlKey,
						metaKey  : _natE.metaKey,

						button : AscCommon.g_mouse_button_right,

						target     : e.target,
						srcElement : e.srcElement
					};

					AscCommon.isTouch = true;
					this.onmousedown(_eContextMenu, true);
					this.onmouseup(_eContextMenu, undefined, true);
					AscCommon.isTouch = false;
				}
				AscCommon.isTouchMove = false;
				AscCommon.TouchStartTime = -1;

				return _ret;
			};
		}
	};

	this.initEventsMobile = function()
	{
        if (this.m_oApi.isMobileVersion)
		{
		    this.TextBoxBackground = CreateControl(AscCommon.g_inputContext.HtmlArea.id);
            this.TextBoxBackground.HtmlElement.parentNode.parentNode.style.zIndex = 10;

            this.MobileTouchManager.initEvents(AscCommon.g_inputContext.HtmlArea.id);

			if (AscBrowser.isAndroid)
			{
				this.TextBoxBackground.HtmlElement["oncontextmenu"] = function(e)
				{
					if (e.preventDefault)
						e.preventDefault();

					e.returnValue = false;
					return false;
				};

				this.TextBoxBackground.HtmlElement["onselectstart"] = function(e)
				{
					oThis.m_oLogicDocument.SelectAll();

					if (e.preventDefault)
						e.preventDefault();

					e.returnValue = false;
					return false;
				};
			}
		}
	};

	this.onButtonRulersClick       = function()
	{
		if (false === oThis.m_oApi.bInit_word_control || true === oThis.m_oApi.isViewMode)
			return;

		oThis.m_bIsRuler = !oThis.m_bIsRuler;
		oThis.checkNeedRules();
		oThis.OnResize(true);
	};

	this.HideRulers = function()
	{
		//if (false === oThis.m_oApi.bInit_word_control)
		//    return;

		if (oThis.m_bIsRuler === false)
			return;

		oThis.m_bIsRuler = !oThis.m_bIsRuler;
		oThis.checkNeedRules();
		oThis.OnResize(true);
	};

	this.calculate_zoom_FitToWidth = function()
	{
		var w = this.m_oEditor.AbsolutePosition.R - this.m_oEditor.AbsolutePosition.L;

		var Zoom = 100;
		if (0 != this.m_dDocumentPageWidth)
		{
			Zoom = 100 * (w - 10) / this.m_dDocumentPageWidth;

			if (Zoom < 5)
				Zoom = 5;

			if (this.m_oApi.isMobileVersion)
			{
				var _w = this.m_oEditor.HtmlElement.width;
				if (this.bIsRetinaSupport)
				{
					_w /= AscCommon.AscBrowser.retinaPixelRatio;
				}
				Zoom = 100 * _w * g_dKoef_pix_to_mm / this.m_dDocumentPageWidth;
			}
		}
		return (Zoom - 0.5) >> 0;
	};

	this.zoom_FitToWidth = function()
	{
		var _new_value = this.calculate_zoom_FitToWidth();

		this.m_nZoomType = 1;
		if (_new_value != this.m_nZoomValue)
		{
			var _old_val      = this.m_nZoomValue;
			this.m_nZoomValue = _new_value;
			this.zoom_Fire(1, _old_val);

			if (this.MobileTouchManager)
				this.MobileTouchManager.CheckZoomCriticalValues(this.m_nZoomValue);

			return true;
		}
		else
		{
			this.m_oApi.sync_zoomChangeCallback(this.m_nZoomValue, 1);
		}
		return false;
	};
	this.zoom_FitToPage  = function()
	{
		var w = parseInt(this.m_oEditor.HtmlElement.width) * g_dKoef_pix_to_mm;
		var h = parseInt(this.m_oEditor.HtmlElement.height) * g_dKoef_pix_to_mm;

		if (this.bIsRetinaSupport)
		{
			w = AscCommon.AscBrowser.convertToRetinaValue(w);
			h = AscCommon.AscBrowser.convertToRetinaValue(h);
		}

		var _hor_Zoom = 100;
		if (0 != this.m_dDocumentPageWidth)
			_hor_Zoom = (100 * (w - 10)) / this.m_dDocumentPageWidth;
		var _ver_Zoom = 100;
		if (0 != this.m_dDocumentPageHeight)
			_ver_Zoom = (100 * (h - 10)) / this.m_dDocumentPageHeight;

		var _new_value = parseInt(Math.min(_hor_Zoom, _ver_Zoom) - 0.5);

		if (_new_value < 5)
			_new_value = 5;

		this.m_nZoomType = 2;
		if (_new_value != this.m_nZoomValue)
		{
			var _old_val      = this.m_nZoomValue;
			this.m_nZoomValue = _new_value;
			this.zoom_Fire(2, _old_val);
			return true;
		}
		else
		{
			this.m_oApi.sync_zoomChangeCallback(this.m_nZoomValue, 2);
		}
		return false;
	};

	this.zoom_Fire = function(type, old_zoom)
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		// нужно проверить режим и сбросить кеш грамотно (ie version)
		AscCommon.g_fontManager.ClearRasterMemory();

		if (AscCommon.g_fontManager2)
			AscCommon.g_fontManager2.ClearRasterMemory();

		var oWordControl = oThis;

		oWordControl.m_bIsRePaintOnScroll = false;

		var xScreen1 = oWordControl.m_oEditor.AbsolutePosition.R - oWordControl.m_oEditor.AbsolutePosition.L;
		var yScreen1 = oWordControl.m_oEditor.AbsolutePosition.B - oWordControl.m_oEditor.AbsolutePosition.T;
		xScreen1 *= g_dKoef_mm_to_pix;
		yScreen1 *= g_dKoef_mm_to_pix;

		xScreen1 >>= 1;
		yScreen1 >>= 1;

		var posDoc = oWordControl.m_oDrawingDocument.ConvertCoordsFromCursor2(xScreen1, yScreen1, true, undefined, old_zoom);

		oWordControl.CheckZoom();
		oWordControl.CalculateDocumentSize();

		var lCurPage = oWordControl.m_oDrawingDocument.m_lCurrentPage;
		if (-1 != lCurPage)
		{
			oWordControl.m_oHorRuler.CreateBackground(oWordControl.m_oDrawingDocument.m_arrPages[lCurPage]);
			oWordControl.m_bIsUpdateHorRuler = true;
			oWordControl.m_oVerRuler.CreateBackground(oWordControl.m_oDrawingDocument.m_arrPages[lCurPage]);
			oWordControl.m_bIsUpdateVerRuler = true;
		}

		oWordControl.OnCalculatePagesPlace();
		var posScreenNew = oWordControl.m_oDrawingDocument.ConvertCoordsToCursor(posDoc.X, posDoc.Y, posDoc.Page);

		var _x_pos = oWordControl.m_oScrollHorApi.getCurScrolledX() + posScreenNew.X - xScreen1;
		var _y_pos = oWordControl.m_oScrollVerApi.getCurScrolledY() + posScreenNew.Y - yScreen1;

		_x_pos = Math.max(0, Math.min(_x_pos, oWordControl.m_dScrollX_max));
		_y_pos = Math.max(0, Math.min(_y_pos, oWordControl.m_dScrollY_max));

		// TODO: заглушка под открытие. мы любим открывать файлы с зумом. И тогда документ не в начале открывается, а с
		// малениким проскролливанием
		if (oWordControl.m_dScrollY == 0)
			_y_pos = 0;

		oWordControl.m_oScrollVerApi.scrollToY(_y_pos);
		oWordControl.m_oScrollHorApi.scrollToX(_x_pos);

		if (this.MobileTouchManager)
			this.MobileTouchManager.Resize();

		oWordControl.m_oApi.sync_zoomChangeCallback(this.m_nZoomValue, type);
		oWordControl.m_bIsUpdateTargetNoAttack = true;
		oWordControl.m_bIsRePaintOnScroll      = true;


		oWordControl.OnScroll();

		if (this.MobileTouchManager)
			this.MobileTouchManager.Resize_After();

		if (this.m_oApi.watermarkDraw)
		{
			this.m_oApi.watermarkDraw.zoom = this.m_nZoomValue / 100;
			this.m_oApi.watermarkDraw.Generate();
		}
	};

	this.zoom_Out = function()
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		oThis.m_nZoomType = 0;

		var _zooms = oThis.zoom_values;
		var _count = _zooms.length;

		var _Zoom = _zooms[0];
		for (var i = (_count - 1); i >= 0; i--)
		{
			if (this.m_nZoomValue > _zooms[i])
			{
				_Zoom = _zooms[i];
				break;
			}
		}

		if (oThis.m_nZoomValue <= _Zoom)
			return;

		var _old_val       = oThis.m_nZoomValue;
		oThis.m_nZoomValue = _Zoom;
		oThis.zoom_Fire(0, _old_val);
	};

	this.zoom_In = function()
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		oThis.m_nZoomType = 0;

		var _zooms = oThis.zoom_values;
		var _count = _zooms.length;

		var _Zoom = _zooms[_count - 1];
		for (var i = 0; i < _count; i++)
		{
			if (this.m_nZoomValue < _zooms[i])
			{
				_Zoom = _zooms[i];
				break;
			}
		}

		if (oThis.m_nZoomValue >= _Zoom)
			return;

		var _old_val       = oThis.m_nZoomValue;
		oThis.m_nZoomValue = _Zoom;
		oThis.zoom_Fire(0, _old_val);
	};

	this.ToSearchResult = function()
	{
		var naviG = this.m_oDrawingDocument.CurrentSearchNavi;

		var navi = naviG[0];
		var x    = navi.X;
		var y    = navi.Y;

		var type    = (naviG.Type & 0xFF);
		var PageNum = navi.PageNum;

		if (navi.Transform)
		{
			var xx = navi.Transform.TransformPointX(x, y);
			var yy = navi.Transform.TransformPointY(x, y);

			x = xx;
			y = yy;
		}

		var rectSize = (navi.H * this.m_nZoomValue * g_dKoef_mm_to_pix / 100);
		var pos      = this.m_oDrawingDocument.ConvertCoordsToCursor2(x, y, PageNum);

		if (true === pos.Error)
			return;

		var boxX = 0;
		var boxY = 0;
		var boxR = this.m_oEditor.HtmlElement.width - 2;
		var boxB = this.m_oEditor.HtmlElement.height - rectSize;

		/*
		 if (true == this.m_bIsRuler)
		 {
		 boxX += Number(5 * g_dKoef_mm_to_pix);
		 boxY += Number(7 * g_dKoef_mm_to_pix);
		 boxR += Number(5 * g_dKoef_mm_to_pix);
		 boxB += Number(7 * g_dKoef_mm_to_pix);
		 }
		 */

		var nValueScrollHor = 0;
		if (pos.X < boxX)
		{
			//nValueScrollHor = boxX - pos.X;
			//nValueScrollHor = pos.X;
			nValueScrollHor = this.GetHorizontalScrollTo(x, PageNum);
		}
		if (pos.X > boxR)
		{
			//nValueScrollHor = boxR - pos.X;
			//nValueScrollHor = pos.X + this.m_oWordControl.m_oEditor.HtmlElement.width;
			var _mem        = x - g_dKoef_pix_to_mm * this.m_oEditor.HtmlElement.width * 100 / this.m_nZoomValue;
			nValueScrollHor = this.GetHorizontalScrollTo(_mem, PageNum);
		}

		var nValueScrollVer = 0;
		if (pos.Y < boxY)
		{
			//nValueScrollVer = boxY - pos.Y;
			//nValueScrollVer = pos.Y;
			nValueScrollVer = this.GetVerticalScrollTo(y, PageNum);
		}
		if (pos.Y > boxB)
		{
			//nValueScrollVer = boxB - pos.Y;
			//nValueScrollHor = pos.Y + this.m_oWordControl.m_oEditor.HtmlElement.height;
			var _mem        = y + navi.H + 10 - g_dKoef_pix_to_mm * this.m_oEditor.HtmlElement.height * 100 / this.m_nZoomValue;
			nValueScrollVer = this.GetVerticalScrollTo(_mem, PageNum);
		}

		var isNeedScroll = false;
		if (0 != nValueScrollHor)
		{
			isNeedScroll                   = true;
			this.m_bIsUpdateTargetNoAttack = true;
			var temp                       = nValueScrollHor * this.m_dScrollX_max / (this.m_dDocumentWidth - this.m_oEditor.HtmlElement.width);
			this.m_oScrollHorApi.scrollToX(parseInt(temp), false);
		}
		if (0 != nValueScrollVer)
		{
			isNeedScroll                   = true;
			this.m_bIsUpdateTargetNoAttack = true;
			var temp                       = nValueScrollVer * this.m_dScrollY_max / (this.m_dDocumentHeight - this.m_oEditor.HtmlElement.height);
			this.m_oScrollVerApi.scrollToY(parseInt(temp), false);
		}

		if (true === isNeedScroll)
		{
			this.OnScroll();
			return;
		}

		// и, в самом конце, перерисовываем оверлей
		this.OnUpdateOverlay();
	};

	this.ScrollToPosition = function(x, y, PageNum)
	{
		if (PageNum < 0 || PageNum >= this.m_oDrawingDocument.m_lCountCalculatePages)
			return;

		var _h       = 5;
		var rectSize = (_h * g_dKoef_mm_to_pix / 100);
		var pos      = this.m_oDrawingDocument.ConvertCoordsToCursor2(x, y, PageNum);

		if (true === pos.Error)
			return;

		var boxX = 0;
		var boxY = 0;
		var boxR = this.m_oEditor.HtmlElement.width - 2;
		var boxB = this.m_oEditor.HtmlElement.height - rectSize;

		var nValueScrollHor = 0;
		if (pos.X < boxX)
		{
			nValueScrollHor = this.GetHorizontalScrollTo(x, PageNum);
		}
		if (pos.X > boxR)
		{
			var _mem        = x - g_dKoef_pix_to_mm * this.m_oEditor.HtmlElement.width * 100 / this.m_nZoomValue;
			nValueScrollHor = this.GetHorizontalScrollTo(_mem, PageNum);
		}

		var nValueScrollVer = 0;
		if (pos.Y < boxY)
		{
			nValueScrollVer = this.GetVerticalScrollTo(y, PageNum);
		}
		if (pos.Y > boxB)
		{
			var _mem        = y + _h + 10 - g_dKoef_pix_to_mm * this.m_oEditor.HtmlElement.height * 100 / this.m_nZoomValue;
			nValueScrollVer = this.GetVerticalScrollTo(_mem, PageNum);
		}

		var isNeedScroll = false;
		if (0 != nValueScrollHor)
		{
			isNeedScroll                   = true;
			this.m_bIsUpdateTargetNoAttack = true;
			var temp                       = nValueScrollHor * this.m_dScrollX_max / (this.m_dDocumentWidth - this.m_oEditor.HtmlElement.width);
			this.m_oScrollHorApi.scrollToX(parseInt(temp), false);
		}
		if (0 != nValueScrollVer)
		{
			isNeedScroll                   = true;
			this.m_bIsUpdateTargetNoAttack = true;
			var temp                       = nValueScrollVer * this.m_dScrollY_max / (this.m_dDocumentHeight - this.m_oEditor.HtmlElement.height);
			this.m_oScrollVerApi.scrollToY(parseInt(temp), false);
		}

		if (true === isNeedScroll)
		{
			this.OnScroll();
			return;
		}
	};

	this.onButtonTabsClick = function()
	{
		var oWordControl = oThis;
		if (oWordControl.m_nTabsType == AscCommon.g_tabtype_left)
		{
			oWordControl.m_nTabsType = AscCommon.g_tabtype_center;
			oWordControl.onButtonTabsDraw();
		}
		else if (oWordControl.m_nTabsType == AscCommon.g_tabtype_center)
		{
			oWordControl.m_nTabsType = AscCommon.g_tabtype_right;
			oWordControl.onButtonTabsDraw();
		}
		else
		{
			oWordControl.m_nTabsType = AscCommon.g_tabtype_left;
			oWordControl
				.onButtonTabsDraw();
		}
	};

	this.onButtonTabsDraw = function()
	{
		var _ctx = this.m_oLeftRuler_buttonsTabs.HtmlElement.getContext('2d');
		if (this.bIsRetinaSupport)
		{
			_ctx.setTransform(AscCommon.AscBrowser.retinaPixelRatio, 0, 0, AscCommon.AscBrowser.retinaPixelRatio, 0, 0);
		}
		else
		{
			_ctx.setTransform(1, 0, 0, 1, 0, 0);
		}

		var _width  = 19;
		var _height = 19;

		_ctx.clearRect(0, 0, 19, 19);

		_ctx.lineWidth   = 1;
		_ctx.strokeStyle = "#BBBEC2";
		_ctx.strokeRect(2.5, 3.5, 14, 14);
		_ctx.beginPath();

		_ctx.strokeStyle = "#3E3E3E";

		_ctx.lineWidth = 2;
		if (this.m_nTabsType == AscCommon.g_tabtype_left)
		{
			_ctx.moveTo(8, 9);
			_ctx.lineTo(8, 14);
			_ctx.lineTo(13, 14);
		}
		else if (this.m_nTabsType == AscCommon.g_tabtype_center)
		{
			_ctx.moveTo(6, 14);
			_ctx.lineTo(14, 14);
			_ctx.moveTo(10, 9);
			_ctx.lineTo(10, 14);
		}
		else
		{
			_ctx.moveTo(12, 9);
			_ctx.lineTo(12, 14);
			_ctx.lineTo(7, 14);
		}

		_ctx.stroke();
		_ctx.beginPath();
	};

	this.onPrevPage = function()
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		var oWordControl = oThis;
		if (0 < oWordControl.m_oDrawingDocument.m_lCurrentPage)
		{
			oWordControl.GoToPage(oWordControl.m_oDrawingDocument.m_lCurrentPage - 1);
		}
		else
		{
			oWordControl.GoToPage(0);
		}
	};
	this.onNextPage = function()
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		var oWordControl = oThis;
		if ((oWordControl.m_oDrawingDocument.m_lPagesCount - 1) > oWordControl.m_oDrawingDocument.m_lCurrentPage)
		{
			oWordControl.GoToPage(oWordControl.m_oDrawingDocument.m_lCurrentPage + 1);
		}
		else if (oWordControl.m_oDrawingDocument.m_lPagesCount > 0)
		{
			oWordControl.GoToPage(oWordControl.m_oDrawingDocument.m_lPagesCount - 1);
		}
	};

	this.horRulerMouseDown = function(e)
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		if (e.preventDefault)
			e.preventDefault();
		else
			e.returnValue = false;

		var oWordControl = oThis;

		var _cur_page = oWordControl.m_oDrawingDocument.m_lCurrentPage;
		if (_cur_page < 0 || _cur_page >= oWordControl.m_oDrawingDocument.m_lPagesCount)
			return;

		oWordControl.m_oHorRuler.OnMouseDown(oWordControl.m_oDrawingDocument.m_arrPages[_cur_page].drawingPage.left, 0, e);
	};
	this.horRulerMouseUp   = function(e)
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		if (e.preventDefault)
			e.preventDefault();
		else
			e.returnValue = false;

		var oWordControl = oThis;

		var _cur_page = oWordControl.m_oDrawingDocument.m_lCurrentPage;
		if (_cur_page < 0 || _cur_page >= oWordControl.m_oDrawingDocument.m_lPagesCount)
			return;

		oWordControl.m_oHorRuler.OnMouseUp(oWordControl.m_oDrawingDocument.m_arrPages[_cur_page].drawingPage.left, 0, e);
	};
	this.horRulerMouseMove = function(e)
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		if (e.preventDefault)
			e.preventDefault();
		else
			e.returnValue = false;

		var oWordControl = oThis;

		var _cur_page = oWordControl.m_oDrawingDocument.m_lCurrentPage;
		if (_cur_page < 0 || _cur_page >= oWordControl.m_oDrawingDocument.m_lPagesCount)
			return;

		oWordControl.m_oHorRuler.OnMouseMove(oWordControl.m_oDrawingDocument.m_arrPages[_cur_page].drawingPage.left, 0, e);
	};

	this.verRulerMouseDown = function(e)
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		if (e.preventDefault)
			e.preventDefault();
		else
			e.returnValue = false;

		var oWordControl = oThis;

		var _cur_page = oWordControl.m_oDrawingDocument.m_lCurrentPage;
		if (_cur_page < 0 || _cur_page >= oWordControl.m_oDrawingDocument.m_lPagesCount)
			return;

		oWordControl.m_oVerRuler.OnMouseDown(0, oWordControl.m_oDrawingDocument.m_arrPages[_cur_page].drawingPage.top, e);
	};
	this.verRulerMouseUp   = function(e)
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		if (e.preventDefault)
			e.preventDefault();
		else
			e.returnValue = false;

		var oWordControl = oThis;

		var _cur_page = oWordControl.m_oDrawingDocument.m_lCurrentPage;
		if (_cur_page < 0 || _cur_page >= oWordControl.m_oDrawingDocument.m_lPagesCount)
			return;

		oWordControl.m_oVerRuler.OnMouseUp(0, oWordControl.m_oDrawingDocument.m_arrPages[_cur_page].drawingPage.top, e);
	};
	this.verRulerMouseMove = function(e)
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		if (e.preventDefault)
			e.preventDefault();
		else
			e.returnValue = false;

		var oWordControl = oThis;

		var _cur_page = oWordControl.m_oDrawingDocument.m_lCurrentPage;
		if (_cur_page < 0 || _cur_page >= oWordControl.m_oDrawingDocument.m_lPagesCount)
			return;

		oWordControl.m_oVerRuler.OnMouseMove(0, oWordControl.m_oDrawingDocument.m_arrPages[_cur_page].drawingPage.top, e);
	};

	this.SelectWheel = function()
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		var oWordControl = oThis;
		var positionMinY = oWordControl.m_oMainContent.AbsolutePosition.T * g_dKoef_mm_to_pix + oWordControl.Y;
		if (oWordControl.m_bIsRuler)
			positionMinY = (oWordControl.m_oMainContent.AbsolutePosition.T + oWordControl.m_oTopRuler_horRuler.AbsolutePosition.B) * g_dKoef_mm_to_pix +
				oWordControl.Y;

		// если находимся в самом верху (без тулбара) - то наверх не будем скроллиться
		// делаем заглушку
		var minPosY = 20;
		if (oThis.bIsRetinaSupport)
			minPosY *= AscCommon.AscBrowser.retinaPixelRatio;
		if (positionMinY < minPosY)
			positionMinY = minPosY;

		var positionMaxY = oWordControl.m_oMainContent.AbsolutePosition.B * g_dKoef_mm_to_pix + oWordControl.Y;

		var scrollYVal = 0;
		if (global_mouseEvent.Y < positionMinY)
		{
			var delta = 30;
			if (20 > (positionMinY - global_mouseEvent.Y))
				delta = 10;

			scrollYVal = -delta;
			//oWordControl.m_oScrollVerApi.scrollByY(-delta, false);
			//oWordControl.onMouseMove2();
			//return;
		}
		else if (global_mouseEvent.Y > positionMaxY)
		{
			var delta = 30;
			if (20 > (global_mouseEvent.Y - positionMaxY))
				delta = 10;

			scrollYVal = delta;
			//oWordControl.m_oScrollVerApi.scrollByY(delta, false);
			//oWordControl.onMouseMove2();
			//return;
		}

		var scrollXVal = 0;
		if (oWordControl.m_bIsHorScrollVisible)
		{
			var positionMinX = oWordControl.m_oMainContent.AbsolutePosition.L * g_dKoef_mm_to_pix + oWordControl.X;
			if (oWordControl.m_bIsRuler)
				positionMinX += oWordControl.m_oLeftRuler.AbsolutePosition.R * g_dKoef_mm_to_pix;

			var positionMaxX = oWordControl.m_oMainContent.AbsolutePosition.R * g_dKoef_mm_to_pix + oWordControl.X;

			if (global_mouseEvent.X < positionMinX)
			{
				var delta = 30;
				if (20 > (positionMinX - global_mouseEvent.X))
					delta = 10;

				scrollXVal = -delta;
				//oWordControl.m_oScrollHorApi.scrollByX(-delta, false);
				//oWordControl.onMouseMove2();
				//return;
			}
			else if (global_mouseEvent.X > positionMaxX)
			{
				var delta = 30;
				if (20 > (global_mouseEvent.X - positionMaxX))
					delta = 10;

				scrollXVal = delta;
				//oWordControl.m_oScrollVerApi.scrollByX(delta, false);
				//oWordControl.onMouseMove2();
				//return;
			}
		}

		if (0 != scrollYVal)
			oWordControl.m_oScrollVerApi.scrollByY(scrollYVal, false);
		if (0 != scrollXVal)
			oWordControl.m_oScrollHorApi.scrollByX(scrollXVal, false);

		if (scrollXVal != 0 || scrollYVal != 0)
			oWordControl.onMouseMove2();
	};

	this.onMouseDown = function(e, isTouch)
	{
		oThis.m_oApi.checkLastWork();

		//console.log("down: " + isTouch + ", " + AscCommon.isTouch);
		if (false === oThis.m_oApi.bInit_word_control || (AscCommon.isTouch && undefined === isTouch) || oThis.m_oApi.isLongAction())
			return;

		if (!oThis.m_bIsIE)
		{
			if (e.preventDefault)
				e.preventDefault();
			else
				e.returnValue = false;
		}

		if (AscCommon.g_inputContext && AscCommon.g_inputContext.externalChangeFocus())
			return;

		var oWordControl = oThis;

		if (this.id == "id_viewer" && oThis.m_oOverlay.HtmlElement.style.display == "block")
			return;

		var _xOffset = oWordControl.X;
		var _yOffset = oWordControl.Y;

		if (true === oWordControl.m_bIsRuler)
		{
			_xOffset += (5 * g_dKoef_mm_to_pix);
			_yOffset += (7 * g_dKoef_mm_to_pix);
		}

		if (window['closeDialogs'] != undefined)
			window['closeDialogs']();

		AscCommon.check_MouseDownEvent(e, true);
		global_mouseEvent.LockMouse();

		// у Илюхи есть проблема при вводе с клавы, пока нажата кнопка мыши
		if ((0 == global_mouseEvent.Button) || (undefined == global_mouseEvent.Button))
		{
			oWordControl.m_bIsMouseLock = true;
		}

		oWordControl.StartUpdateOverlay();
		var bIsSendSelectWhell = false;

		if ((0 == global_mouseEvent.Button) || (undefined == global_mouseEvent.Button))
		{
			var pos = null;
			if (oWordControl.m_oDrawingDocument.AutoShapesTrackLockPageNum == -1)
				pos = oWordControl.m_oDrawingDocument.ConvertCoordsFromCursor2(global_mouseEvent.X, global_mouseEvent.Y);
			else
				pos = oWordControl.m_oDrawingDocument.ConvetToPageCoords(global_mouseEvent.X, global_mouseEvent.Y, oWordControl.m_oDrawingDocument.AutoShapesTrackLockPageNum);

			if (pos.Page == -1)
			{
				oWordControl.EndUpdateOverlay();
				return;
			}

			if (oWordControl.m_oDrawingDocument.IsFreezePage(pos.Page))
			{
				oWordControl.EndUpdateOverlay();
				return;
			}

			if (null == oWordControl.m_oDrawingDocument.m_oDocumentRenderer)
			{
				// теперь проверить трек таблиц
				var ret = oWordControl.m_oDrawingDocument.checkMouseDown_Drawing(pos);
				if (ret === true)
				{
					if (-1 == oWordControl.m_oTimerScrollSelect)
						oWordControl.m_oTimerScrollSelect = setInterval(oWordControl.SelectWheel, 20);

					AscCommon.stopEvent(e);
					return;
				}

				if (-1 == oWordControl.m_oTimerScrollSelect)
				{
					// добавим это и здесь, чтобы можно было отменять во время LogicDocument.OnMouseDown
					oWordControl.m_oTimerScrollSelect = setInterval(oWordControl.SelectWheel, 20);
					bIsSendSelectWhell                = true;
				}

				oWordControl.m_oDrawingDocument.NeedScrollToTargetFlag = true;
				oWordControl.m_oLogicDocument.OnMouseDown(global_mouseEvent, pos.X, pos.Y, pos.Page);
				oWordControl.m_oDrawingDocument.NeedScrollToTargetFlag = false;

				oWordControl.MouseDownDocumentCounter++;
			}
			else
			{
				oWordControl.m_oDrawingDocument.m_oDocumentRenderer.OnMouseDown(pos.Page, pos.X, pos.Y);
				oWordControl.MouseDownDocumentCounter++;
			}
		}
		else if (global_mouseEvent.Button == 2)
			oWordControl.MouseDownDocumentCounter++;

		if (!bIsSendSelectWhell && -1 == oWordControl.m_oTimerScrollSelect)
		{
			oWordControl.m_oTimerScrollSelect = setInterval(oWordControl.SelectWheel, 20);
		}

		oWordControl.EndUpdateOverlay();
	};

	this.onMouseMove  = function(e, isTouch)
	{
		oThis.m_oApi.checkLastWork();

		if (false === oThis.m_oApi.bInit_word_control || (AscCommon.isTouch && undefined === isTouch) || oThis.m_oApi.isLongAction())
			return;

		if (e)
		{
			if (e.preventDefault)
				e.preventDefault();
			else
				e.returnValue = false;

			AscCommon.check_MouseMoveEvent(e);
		}

		var oWordControl = oThis;

		var pos = null;
		if (oWordControl.m_oDrawingDocument.AutoShapesTrackLockPageNum == -1)
			pos = oWordControl.m_oDrawingDocument.ConvertCoordsFromCursor2(global_mouseEvent.X, global_mouseEvent.Y);
		else
			pos = oWordControl.m_oDrawingDocument.ConvetToPageCoords(global_mouseEvent.X, global_mouseEvent.Y, oWordControl.m_oDrawingDocument.AutoShapesTrackLockPageNum);

		if (pos.Page == -1)
			return;

		if (oWordControl.m_oDrawingDocument.IsFreezePage(pos.Page))
			return;

		if (oWordControl.m_oDrawingDocument.m_sLockedCursorType != "")
			oWordControl.m_oDrawingDocument.SetCursorType("default");
		if (oWordControl.m_oDrawingDocument.m_oDocumentRenderer != null)
		{
			oWordControl.m_oDrawingDocument.m_oDocumentRenderer.OnMouseMove(pos.Page, pos.X, pos.Y);
			return;
		}

		oWordControl.StartUpdateOverlay();
		var is_drawing = oWordControl.m_oDrawingDocument.checkMouseMove_Drawing(pos);
		if (is_drawing === true)
			return;

		oWordControl.m_oDrawingDocument.TableOutlineDr.bIsNoTable = true;
		oWordControl.m_oLogicDocument.OnMouseMove(global_mouseEvent, pos.X, pos.Y, pos.Page);

		if (oWordControl.m_oDrawingDocument.TableOutlineDr.bIsNoTable === false)
		{
			// TODO: нужно посмотреть, может в ЭТОМ же месте трек для таблицы уже нарисован
			oWordControl.ShowOverlay();
			oWordControl.OnUpdateOverlay();
		}

		if (!oWordControl.IsUpdateOverlayOnEndCheck)
		{
			if (oWordControl.m_oDrawingDocument.ContentControlsCheckLast())
				oWordControl.OnUpdateOverlay();
		}

		oWordControl.EndUpdateOverlay();
	};
	this.onMouseMove2 = function()
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		var oWordControl = oThis;
		var pos          = null;
		if (oWordControl.m_oDrawingDocument.AutoShapesTrackLockPageNum == -1)
			pos = oWordControl.m_oDrawingDocument.ConvertCoordsFromCursor2(global_mouseEvent.X, global_mouseEvent.Y);
		else
			pos = oWordControl.m_oDrawingDocument.ConvetToPageCoords(global_mouseEvent.X, global_mouseEvent.Y, oWordControl.m_oDrawingDocument.AutoShapesTrackLockPageNum);

		if (pos.Page == -1)
			return;

		if (null != oWordControl.m_oDrawingDocument.m_oDocumentRenderer)
		{
			oWordControl.m_oDrawingDocument.m_oDocumentRenderer.OnMouseMove(pos.Page, pos.X, pos.Y);
			return;
		}

		if (oWordControl.m_oDrawingDocument.IsFreezePage(pos.Page))
			return;

		oWordControl.StartUpdateOverlay();

		var is_drawing = oWordControl.m_oDrawingDocument.checkMouseMove_Drawing(pos);
		if (is_drawing === true)
			return;

		oWordControl.m_oLogicDocument.OnMouseMove(global_mouseEvent, pos.X, pos.Y, pos.Page);
		oWordControl.EndUpdateOverlay();
	};
	this.onMouseUp    = function(e, bIsWindow, isTouch)
	{
		oThis.m_oApi.checkLastWork();

		//console.log("up: " + isTouch + ", " + AscCommon.isTouch);
		if (false === oThis.m_oApi.bInit_word_control || (AscCommon.isTouch && undefined === isTouch) || oThis.m_oApi.isLongAction())
			return;
		//if (true == global_mouseEvent.IsLocked)
		//    return;

		var oWordControl = oThis;
		if (!global_mouseEvent.IsLocked && 0 == oWordControl.MouseDownDocumentCounter)
			return;

		if (this.id == "id_viewer" && oThis.m_oOverlay.HtmlElement.style.display == "block" && undefined == bIsWindow)
			return;

		if ((global_mouseEvent.Sender != oThis.m_oEditor.HtmlElement &&
			global_mouseEvent.Sender != oThis.m_oOverlay.HtmlElement &&
			global_mouseEvent.Sender != oThis.m_oDrawingDocument.TargetHtmlElement) &&
			(oThis.TextBoxBackground && oThis.TextBoxBackground.HtmlElement != global_mouseEvent.Sender))
			return;

		if (-1 != oWordControl.m_oTimerScrollSelect)
		{
			clearInterval(oWordControl.m_oTimerScrollSelect);
			oWordControl.m_oTimerScrollSelect = -1;
		}

		if (oWordControl.m_oHorRuler.m_bIsMouseDown)
			oWordControl.m_oHorRuler.OnMouseUpExternal();

		if (oWordControl.m_oVerRuler.DragType != 0)
			oWordControl.m_oVerRuler.OnMouseUpExternal();

		if (oWordControl.m_oScrollVerApi.getIsLockedMouse())
		{
			oWordControl.m_oScrollVerApi.evt_mouseup(e);
		}
		if (oWordControl.m_oScrollHorApi.getIsLockedMouse())
		{
			oWordControl.m_oScrollHorApi.evt_mouseup(e);
		}

		AscCommon.check_MouseUpEvent(e);
		var pos = null;
		if (oWordControl.m_oDrawingDocument.AutoShapesTrackLockPageNum == -1)
			pos = oWordControl.m_oDrawingDocument.ConvertCoordsFromCursor2(global_mouseEvent.X, global_mouseEvent.Y);
		else
			pos = oWordControl.m_oDrawingDocument.ConvetToPageCoords(global_mouseEvent.X, global_mouseEvent.Y, oWordControl.m_oDrawingDocument.AutoShapesTrackLockPageNum);

		if (pos.Page == -1)
			return;

		if (oWordControl.m_oDrawingDocument.IsFreezePage(pos.Page))
			return;

		oWordControl.m_oDrawingDocument.UnlockCursorType();

		oWordControl.StartUpdateOverlay();

		// восстанавливаем фокус
		oWordControl.m_bIsMouseLock = false;

		var is_drawing = oWordControl.m_oDrawingDocument.checkMouseUp_Drawing(pos);
		if (is_drawing === true)
			return;

		var is_drawing_on_up = oWordControl.m_oDrawingDocument.checkMouseDown_DrawingOnUp(pos);
		if (is_drawing_on_up)
		{
			// не посылаем в документ.
			return;
		}

		if (null != oWordControl.m_oDrawingDocument.m_oDocumentRenderer)
		{
			oWordControl.m_oDrawingDocument.m_oDocumentRenderer.OnMouseUp();

			oWordControl.MouseDownDocumentCounter--;
			if (oWordControl.MouseDownDocumentCounter < 0)
				oWordControl.MouseDownDocumentCounter = 0;

			oWordControl.EndUpdateOverlay();
			return;
		}

		oWordControl.m_bIsMouseUpSend = true;

		if (2 == global_mouseEvent.Button)
		{
			// пошлем сначала моусдаун
			//oWordControl.m_oLogicDocument.OnMouseDown(global_mouseEvent, pos.X, pos.Y, pos.Page);
		}
		oWordControl.m_oDrawingDocument.NeedScrollToTargetFlag = true;
		oWordControl.m_oLogicDocument.OnMouseUp(global_mouseEvent, pos.X, pos.Y, pos.Page);
		oWordControl.m_oDrawingDocument.NeedScrollToTargetFlag = false;

		oWordControl.MouseDownDocumentCounter--;
		if (oWordControl.MouseDownDocumentCounter < 0)
			oWordControl.MouseDownDocumentCounter = 0;

		oWordControl.m_bIsMouseUpSend = false;
		oWordControl.m_oLogicDocument.Document_UpdateInterfaceState();
		oWordControl.m_oLogicDocument.Document_UpdateRulersState();

		oWordControl.EndUpdateOverlay();
	};

	this.onMouseUpMainSimple = function()
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		var oWordControl = oThis;

		global_mouseEvent.Type = AscCommon.g_mouse_event_type_up;

		AscCommon.MouseUpLock.MouseUpLockedSend = true;

		global_mouseEvent.Sender = null;

		global_mouseEvent.UnLockMouse();

		global_mouseEvent.IsPressed = false;

		if (-1 != oWordControl.m_oTimerScrollSelect)
		{
			clearInterval(oWordControl.m_oTimerScrollSelect);
			oWordControl.m_oTimerScrollSelect = -1;
		}
	};

	this.onMouseUpExternal = function(x, y)
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		var oWordControl = oThis;

		//---
		global_mouseEvent.X = x;
		global_mouseEvent.Y = y;

		global_mouseEvent.Type = AscCommon.g_mouse_event_type_up;

		AscCommon.MouseUpLock.MouseUpLockedSend = true;

		if (oWordControl.m_oHorRuler.m_bIsMouseDown)
			oWordControl.m_oHorRuler.OnMouseUpExternal();

		if (oWordControl.m_oVerRuler.DragType != 0)
			oWordControl.m_oVerRuler.OnMouseUpExternal();

		if (oWordControl.m_oScrollVerApi.getIsLockedMouse())
		{
			var __e = {clientX : x, clientY : y};
			oWordControl.m_oScrollVerApi.evt_mouseup(__e);
		}
		if (oWordControl.m_oScrollHorApi.getIsLockedMouse())
		{
			var __e = {clientX : x, clientY : y};
			oWordControl.m_oScrollHorApi.evt_mouseup(__e);
		}

		if (window.g_asc_plugins)
            window.g_asc_plugins.onExternalMouseUp();

		global_mouseEvent.Sender = null;

		global_mouseEvent.UnLockMouse();

		global_mouseEvent.IsPressed = false;

		if (-1 != oWordControl.m_oTimerScrollSelect)
		{
			clearInterval(oWordControl.m_oTimerScrollSelect);
			oWordControl.m_oTimerScrollSelect = -1;
		}

		//---
		var pos = null;
		if (oWordControl.m_oDrawingDocument.AutoShapesTrackLockPageNum == -1)
			pos = oWordControl.m_oDrawingDocument.ConvertCoordsFromCursor2(global_mouseEvent.X, global_mouseEvent.Y);
		else
			pos = oWordControl.m_oDrawingDocument.ConvetToPageCoords(global_mouseEvent.X, global_mouseEvent.Y, oWordControl.m_oDrawingDocument.AutoShapesTrackLockPageNum);

		if (pos.Page == -1)
			return;

		if (oWordControl.m_oDrawingDocument.IsFreezePage(pos.Page))
			return;

		oWordControl.m_oDrawingDocument.UnlockCursorType();

		oWordControl.StartUpdateOverlay();

		// восстанавливаем фокус
		oWordControl.m_bIsMouseLock = false;

		var is_drawing = oWordControl.m_oDrawingDocument.checkMouseUp_Drawing(pos);
		if (is_drawing === true)
			return;

		if (null != oWordControl.m_oDrawingDocument.m_oDocumentRenderer)
		{
			oWordControl.m_oDrawingDocument.m_oDocumentRenderer.OnMouseUp();

			oWordControl.MouseDownDocumentCounter--;
			if (oWordControl.MouseDownDocumentCounter < 0)
				oWordControl.MouseDownDocumentCounter = 0;

			oWordControl.EndUpdateOverlay();
			return;
		}

		oWordControl.m_bIsMouseUpSend = true;

		if (2 == global_mouseEvent.Button)
		{
			// пошлем сначала моусдаун
			//oWordControl.m_oLogicDocument.OnMouseDown(global_mouseEvent, pos.X, pos.Y, pos.Page);
		}
		oWordControl.m_oLogicDocument.OnMouseUp(global_mouseEvent, pos.X, pos.Y, pos.Page);

		oWordControl.MouseDownDocumentCounter--;
		if (oWordControl.MouseDownDocumentCounter < 0)
			oWordControl.MouseDownDocumentCounter = 0;

		oWordControl.m_bIsMouseUpSend = false;
		oWordControl.m_oLogicDocument.Document_UpdateInterfaceState();
		oWordControl.m_oLogicDocument.Document_UpdateRulersState();

		oWordControl.EndUpdateOverlay();
	};

	this.onMouseWhell = function(e)
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		if (undefined !== window["AscDesktopEditor"])
		{
			if (false === window["AscDesktopEditor"]["CheckNeedWheel"]())
				return;
		}

		var _ctrl = false;
		if (e.metaKey !== undefined)
			_ctrl = e.ctrlKey || e.metaKey;
		else
			_ctrl = e.ctrlKey;

		if (true === _ctrl)
		{
			if (e.preventDefault)
				e.preventDefault();
			else
				e.returnValue = false;

			return false;
		}

		var delta  = 0;
		var deltaX = 0;
		var deltaY = 0;

		if (undefined != e.wheelDelta && e.wheelDelta != 0)
		{
			//delta = (e.wheelDelta > 0) ? -45 : 45;
			delta = -45 * e.wheelDelta / 120;
		}
		else if (undefined != e.detail && e.detail != 0)
		{
			//delta = (e.detail > 0) ? 45 : -45;
			delta = 45 * e.detail / 3;
		}

		// New school multidimensional scroll (touchpads) deltas
		deltaY = delta;

		if (oThis.m_bIsHorScrollVisible)
		{
			if (e.axis !== undefined && e.axis === e.HORIZONTAL_AXIS)
			{
				deltaY = 0;
				deltaX = delta;
			}

			// Webkit
			if (undefined !== e.wheelDeltaY && 0 !== e.wheelDeltaY)
			{
				//deltaY = (e.wheelDeltaY > 0) ? -45 : 45;
				deltaY = -45 * e.wheelDeltaY / 120;
			}
			if (undefined !== e.wheelDeltaX && 0 !== e.wheelDeltaX)
			{
				//deltaX = (e.wheelDeltaX > 0) ? -45 : 45;
				deltaX = -45 * e.wheelDeltaX / 120;
			}
		}

		deltaX >>= 0;
		deltaY >>= 0;

		if (0 != deltaX)
			oThis.m_oScrollHorApi.scrollBy(deltaX, 0, false);
		else if (0 != deltaY)
			oThis.m_oScrollVerApi.scrollBy(0, deltaY, false);

		// здесь - имитируем моус мув ---------------------------
		var _e   = {};
		_e.pageX = global_mouseEvent.X;
		_e.pageY = global_mouseEvent.Y;

		_e.clientX = global_mouseEvent.X;
		_e.clientY = global_mouseEvent.Y;

		_e.altKey   = global_mouseEvent.AltKey;
		_e.shiftKey = global_mouseEvent.ShiftKey;
		_e.ctrlKey  = global_mouseEvent.CtrlKey;
		_e.metaKey  = global_mouseEvent.CtrlKey;

		_e.srcElement = global_mouseEvent.Sender;

		oThis.onMouseMove(_e);
		// ------------------------------------------------------

		if (e.preventDefault)
			e.preventDefault();
		else
			e.returnValue = false;

		return false;
	};

	this.checkViewerModeKeys = function(e)
	{
		var isSendEditor = false;
		if (e.KeyCode == 33) // PgUp
		{
			//
		}
		else if (e.KeyCode == 34) // PgDn
		{
			//
		}
		else if (e.KeyCode == 35) // клавиша End
		{
			if (true === e.CtrlKey) // Ctrl + End - переход в конец документа
			{
				oThis.m_oScrollVerApi.scrollTo(0, oThis.m_dScrollY_max);
			}
		}
		else if (e.KeyCode == 36) // клавиша Home
		{
			if (true === e.CtrlKey) // Ctrl + Home - переход в начало документа
			{
				oThis.m_oScrollVerApi.scrollTo(0, 0);
			}
		}
		else if (e.KeyCode == 37) // Left Arrow
		{
			if (oThis.m_bIsHorScrollVisible)
			{
				oThis.m_oScrollHorApi.scrollBy(-30, 0, false);
			}
		}
		else if (e.KeyCode == 38) // Top Arrow
		{
			oThis.m_oScrollVerApi.scrollBy(0, -30, false);
		}
		else if (e.KeyCode == 39) // Right Arrow
		{
			if (oThis.m_bIsHorScrollVisible)
			{
				oThis.m_oScrollHorApi.scrollBy(30, 0, false);
			}
		}
		else if (e.KeyCode == 40) // Bottom Arrow
		{
			oThis.m_oScrollVerApi.scrollBy(0, 30, false);
		}
		else if (e.KeyCode == 65 && true === e.CtrlKey) // Ctrl + A - выделяем все
		{
			isSendEditor = true;
		}
		else if (e.KeyCode == 67 && true === e.CtrlKey) // Ctrl + C + ...
		{
			if (false === e.ShiftKey)
			{
				AscCommon.Editor_Copy(oThis.m_oApi);
				//не возвращаем true чтобы не было preventDefault
			}
		}
		return isSendEditor;
	};

	this.ChangeReaderMode = function()
	{
		if (this.ReaderModeCurrent)
			this.DisableReaderMode();
		else
			this.EnableReaderMode();
	};

	this.IncreaseReaderFontSize = function()
	{
		if (null == this.ReaderModeDiv)
			return;

		if (this.ReaderFontSizeCur >= (this.ReaderFontSizes.length - 1))
		{
			this.ReaderFontSizeCur = this.ReaderFontSizes.length - 1;
			return;
		}
		this.ReaderFontSizeCur++;
		this.ReaderModeDiv.style.fontSize = this.ReaderFontSizes[this.ReaderFontSizeCur] + "pt";

		this.ReaderTouchManager.ChangeFontSize();
	};
	this.DecreaseReaderFontSize = function()
	{
		if (null == this.ReaderModeDiv)
			return;

		if (this.ReaderFontSizeCur <= 0)
		{
			this.ReaderFontSizeCur = 0;
			return;
		}
		this.ReaderFontSizeCur--;
		this.ReaderModeDiv.style.fontSize = this.ReaderFontSizes[this.ReaderFontSizeCur] + "pt";

		this.ReaderTouchManager.ChangeFontSize();
	};

	this.IsReaderMode        = function()
	{
		return (this.ReaderModeCurrent == 1);
	};
	this.UpdateReaderContent = function()
	{
		if (this.ReaderModeCurrent == 1 && this.ReaderModeDivWrapper != null)
		{
			this.ReaderModeDivWrapper.innerHTML = "<div id=\"reader_id\" style=\"width:100%;display:block;z-index:9;font-family:arial;font-size:" +
				this.ReaderFontSizes[this.ReaderFontSizeCur] + "pt;position:absolute;resize:none;-webkit-box-sizing:border-box;box-sizing:border-box;padding-left:5%;padding-right:5%;padding-top:10%;padding-bottom:10%;background-color:#FFFFFF;\">" +
				this.m_oApi.ContentToHTML(true) + "</div>";
		}
	};

	this.EnableReaderMode = function()
	{
		this.ReaderModeCurrent = 1;
		if (this.ReaderTouchManager)
		{
			this.TransformDivUseAnimation(this.ReaderModeDivWrapper, 0);
			return;
		}

		this.ReaderModeDivWrapper = document.createElement('div');
		this.ReaderModeDivWrapper.setAttribute("style", "z-index:11;font-family:arial;font-size:12pt;position:absolute;\
            resize:none;padding:0px;display:block;\
            margin:0px;left:0px;top:0px;background-color:#FFFFFF");

		var _c_h                               = parseInt(oThis.m_oMainView.HtmlElement.style.height);
		this.ReaderModeDivWrapper.style.top    = _c_h + "px";
		this.ReaderModeDivWrapper.style.width  = this.m_oMainView.HtmlElement.style.width;
		this.ReaderModeDivWrapper.style.height = this.m_oMainView.HtmlElement.style.height;

		this.ReaderModeDivWrapper.id        = "wrapper_reader_id";
		this.ReaderModeDivWrapper.innerHTML = "<div id=\"reader_id\" style=\"width:100%;display:block;z-index:9;font-family:arial;font-size:" +
			this.ReaderFontSizes[this.ReaderFontSizeCur] + "pt;position:absolute;resize:none;-webkit-box-sizing:border-box;box-sizing:border-box;padding-left:5%;padding-right:5%;padding-top:10%;padding-bottom:10%;background-color:#FFFFFF;\">" +
			this.m_oApi.ContentToHTML(true) + "</div>";

		this.m_oMainView.HtmlElement.appendChild(this.ReaderModeDivWrapper);

		this.ReaderModeDiv = document.getElementById("reader_id");

		if (this.MobileTouchManager)
		{
			this.MobileTouchManager.Destroy();
			this.MobileTouchManager = null;
		}

		this.ReaderTouchManager = new AscCommon.CReaderTouchManager();
		this.ReaderTouchManager.Init(this.m_oApi);

		this.TransformDivUseAnimation(this.ReaderModeDivWrapper, 0);

		var __hasTouch = 'ontouchstart' in window;

		if (__hasTouch)
		{
			this.ReaderModeDivWrapper["ontouchcancel"] = function(e)
			{
				return oThis.ReaderTouchManager.onTouchEnd(e);
			}

			this.ReaderModeDivWrapper["ontouchstart"] = function(e)
			{
				return oThis.ReaderTouchManager.onTouchStart(e);
			}
			this.ReaderModeDivWrapper["ontouchmove"]  = function(e)
			{
				return oThis.ReaderTouchManager.onTouchMove(e);
			}
			this.ReaderModeDivWrapper["ontouchend"]   = function(e)
			{
				return oThis.ReaderTouchManager.onTouchEnd(e);
			}
		}
		else
		{
			this.ReaderModeDivWrapper["onmousedown"] = function(e)
			{
				return oThis.ReaderTouchManager.onTouchStart(e);
			}
			this.ReaderModeDivWrapper["onmousemove"] = function(e)
			{
				return oThis.ReaderTouchManager.onTouchMove(e);
			}
			this.ReaderModeDivWrapper["onmouseup"]   = function(e)
			{
				return oThis.ReaderTouchManager.onTouchEnd(e);
			}
		}

		//this.m_oEditor.HtmlElement.style.display = "none";
		//this.m_oOverlay.HtmlElement.style.display = "none";
	};

	this.DisableReaderMode = function()
	{
		this.ReaderModeCurrent = 0;
		if (null == this.ReaderModeDivWrapper)
			return;

		this.TransformDivUseAnimation(this.ReaderModeDivWrapper, parseInt(this.ReaderModeDivWrapper.style.height) + 10);
		setTimeout(this.CheckDestroyReader, 500);
		return;
	};

	this.CheckDestroyReader = function()
	{
		if (oThis.ReaderModeDivWrapper != null)
		{
			if (parseInt(oThis.ReaderModeDivWrapper.style.top) > parseInt(oThis.ReaderModeDivWrapper.style.height))
			{
				oThis.m_oMainView.HtmlElement.removeChild(oThis.ReaderModeDivWrapper);

				oThis.ReaderModeDivWrapper = null;
				oThis.ReaderModeDiv        = null;

				oThis.ReaderTouchManager.Destroy();
				oThis.ReaderTouchManager = null;

				oThis.ReaderModeCurrent = 0;

				if (oThis.m_oApi.isMobileVersion)
				{
					oThis.MobileTouchManager = new AscCommon.CMobileTouchManager({ eventsElement : "word_mobile_element" });
					oThis.MobileTouchManager.Init(oThis.m_oApi);

                    if (AscCommon.g_inputContext && AscCommon.g_inputContext.HtmlArea)
                        oThis.MobileTouchManager.initEvents(AscCommon.g_inputContext.HtmlArea.id);

					oThis.MobileTouchManager.Resize();

                    oThis.MobileTouchManager.scrollTo(oThis.m_dScrollX, oThis.m_dScrollY);
				}

				return;
			}

			if (oThis.ReaderModeCurrent == 0)
			{
				setTimeout(oThis.CheckDestroyReader, 200);
			}
		}
	};

	this.TransformDivUseAnimation = function(_div, topPos)
	{
		_div.style[window.asc_sdk_transitionProperty] = "top";
		_div.style[window.asc_sdk_transitionDuration] = "1000ms";
		_div.style.top                                = topPos + "px";
	};

	this.onKeyDown = function(e)
	{
		oThis.m_oApi.checkLastWork();

		if (oThis.m_oApi.isLongAction())
		{
			e.preventDefault();
			return;
		}

		var oWordControl = oThis;
		if (false === oWordControl.m_oApi.bInit_word_control)
		{
			AscCommon.check_KeyboardEvent2(e);
			e.preventDefault();
			return;
		}

		if (oWordControl.m_bIsRuler && oWordControl.m_oHorRuler.m_bIsMouseDown)
		{
			AscCommon.check_KeyboardEvent2(e);
			e.preventDefault();
			return;
		}

		// Esc даем делать с клавы, даже когда мышка зажата, чтобы можно было сбросить drag-n-drop, но если у нас
		// идет работа с автофигурами (любые движения), тогда не пропускаем.
		if (oWordControl.m_bIsMouseLock === true && (27 !== e.keyCode || true === oWordControl.m_oLogicDocument.Is_TrackingDrawingObjects()))
		{
			if (!window.USER_AGENT_MACOS)
			{
				AscCommon.check_KeyboardEvent2(e);
				e.preventDefault();
				return;
			}

			// на масОс есть мега выделение на трекпаде. там моусАп приходит с задержкой.
			// нужно лдибо копить команды клавиатуры, либо насильно заранее сделать моусАп самому.
			// мы выбараем второе

			oWordControl.onMouseUpExternal(global_mouseEvent.X, global_mouseEvent.Y);
		}

		AscCommon.check_KeyboardEvent(e);
		if (oWordControl.IsFocus === false)
		{
			// некоторые команды нужно продолжать обрабатывать
			if (!oWordControl.onKeyDownNoActiveControl(global_keyboardEvent))
				return;
		}

		/*
		 if (oThis.ChangeHintProps())
		 {
		 e.preventDefault();
		 oThis.OnScroll();
		 return;
		 }
		 */
		if (null == oWordControl.m_oLogicDocument)
		{
			var bIsPrev = (oWordControl.m_oDrawingDocument.m_oDocumentRenderer.OnKeyDown(global_keyboardEvent) === true) ? false : true;
			if (false === bIsPrev)
			{
				e.preventDefault();
			}
			return;
		}
		/*
		 if (oWordControl.m_oDrawingDocument.IsFreezePage(oWordControl.m_oDrawingDocument.m_lCurrentPage))
		 {
		 e.preventDefault();
		 return;
		 }
		 */
		/*
		 if (oWordControl.m_oApi.isViewMode)
		 {
		 var isSendToEditor = oWordControl.checkViewerModeKeys(global_keyboardEvent);
		 if (false === isSendToEditor)
		 return;
		 }
		 */

		oWordControl.StartUpdateOverlay();

		oWordControl.IsKeyDownButNoPress = true;
		var _ret_mouseDown               = oWordControl.m_oLogicDocument.OnKeyDown(global_keyboardEvent);
		oWordControl.bIsUseKeyPress      = ((_ret_mouseDown & keydownresult_PreventKeyPress) != 0) ? false : true;

		oWordControl.EndUpdateOverlay();

		if ((_ret_mouseDown & keydownresult_PreventDefault) != 0)// || (true === global_keyboardEvent.AltKey && !AscBrowser.isMacOs))
		{
			// убираем превент с альтом. Уж больно итальянцы недовольны.
			e.preventDefault();
		}

		/*
		 if (false === oWordControl.TextboxUsedForSpecials)
		 {
		 if (false === oWordControl.bIsUseKeyPress || true === global_keyboardEvent.AltKey)
		 {
		 e.preventDefault();
		 }
		 }
		 else
		 {
		 if (true !== global_keyboardEvent.AltKey && true !== global_keyboardEvent.CtrlKey)
		 {
		 if (false === oWordControl.bIsUseKeyPress)
		 e.preventDefault();
		 }
		 }
		 */
	};

	this.onKeyDownNoActiveControl = function(e)
	{
		var bSendToEditor = false;

		if (e.CtrlKey && !e.ShiftKey)
		{
			switch (e.KeyCode)
			{
				case 80: // P
				case 83: // S
					bSendToEditor = true;
					break;
				default:
					break;
			}
		}

		return bSendToEditor;
	};

	this.onKeyUp    = function(e)
	{
		global_keyboardEvent.AltKey   = false;
		global_keyboardEvent.CtrlKey  = false;
		global_keyboardEvent.ShiftKey = false;
		global_keyboardEvent.AltGr    = false;
	};
	this.onKeyPress = function(e)
	{
		if (AscCommon.g_clipboardBase.IsWorking())
			return;

		if (oThis.m_oApi.isLongAction())
		{
			e.preventDefault();
			return;
		}

		var oWordControl = oThis;
		if (false === oWordControl.m_oApi.bInit_word_control || oWordControl.IsFocus === false || oWordControl.m_bIsMouseLock === true)
			return;

		if (window.opera && !oWordControl.IsKeyDownButNoPress)
		{
			oWordControl.StartUpdateOverlay();
			oWordControl.onKeyDown(e);
			oWordControl.EndUpdateOverlay();
		}
		oWordControl.IsKeyDownButNoPress = false;

		if (false === oWordControl.bIsUseKeyPress)
			return;

		if (null == oWordControl.m_oLogicDocument)
			return;

		AscCommon.check_KeyboardEvent(e);

		oWordControl.StartUpdateOverlay();
		var retValue = oWordControl.m_oLogicDocument.OnKeyPress(global_keyboardEvent);
		oWordControl.EndUpdateOverlay();
		if (true === retValue)
			e.preventDefault();
	};

	this.verticalScroll             = function(sender, scrollPositionY, maxY, isAtTop, isAtBottom)
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		var oWordControl                       = oThis;
		oWordControl.m_dScrollY                = Math.max(0, Math.min(scrollPositionY, maxY));
		oWordControl.m_dScrollY_max            = maxY;
		oWordControl.m_bIsUpdateVerRuler       = true;
		oWordControl.m_bIsUpdateTargetNoAttack = true;

		if (oWordControl.m_bIsRePaintOnScroll === true)
			oWordControl.OnScroll();

		if (oWordControl.MobileTouchManager && oWordControl.MobileTouchManager.iScroll)
		{
			oWordControl.MobileTouchManager.iScroll.y = -oWordControl.m_dScrollY;
		}
	};
	this.CorrectSpeedVerticalScroll = function(newScrollPos)
	{
		// без понтов.
		//return pos;

		// понты
		var res = {isChange : false, Pos : newScrollPos};
		if (newScrollPos <= 0 || newScrollPos >= this.m_dScrollY_max)
			return res;

		var _heightPageMM = Page_Height;
		if (this.m_oDrawingDocument.m_arrPages.length > 0)
			_heightPageMM = this.m_oDrawingDocument.m_arrPages[0].height_mm;
		var del = 20 + (g_dKoef_mm_to_pix * _heightPageMM * this.m_nZoomValue / 100 + 0.5) >> 0;

		var delta = Math.abs(newScrollPos - this.m_dScrollY);
		if (this.m_oDrawingDocument.m_lPagesCount <= 10)
			return res;
		else if (this.m_oDrawingDocument.m_lPagesCount <= 100 && (delta < del * 0.3))
			return res;
		else if (delta < del * 0.2)
			return res;

		var canvas = this.m_oEditor.HtmlElement;
		if (null == canvas)
			return;

		var _height      = canvas.height;
		var documentMaxY = this.m_dDocumentHeight - _height;
		if (documentMaxY <= 0)
			return res;

		var lCurrentTopInDoc = parseInt(newScrollPos * documentMaxY / this.m_dScrollY_max);
		var lCount           = parseInt(lCurrentTopInDoc / del);

		res.isChange = true;
		res.Pos      = parseInt((lCount * del) * this.m_dScrollY_max / documentMaxY);

		if (res.Pos < 0)
			res.Pos = 0;
		if (res.Pos > this.m_dScrollY_max)
			res.Pos = this.m_dScrollY_max;

		return res;
	};

	this.horizontalScroll = function(sender, scrollPositionX, maxX, isAtLeft, isAtRight)
	{
		if (false === oThis.m_oApi.bInit_word_control)
			return;

		var oWordControl                       = oThis;
		oWordControl.m_dScrollX                = Math.max(0, Math.min(scrollPositionX, maxX));
		oWordControl.m_dScrollX_max            = maxX;
		oWordControl.m_bIsUpdateHorRuler       = true;
		oWordControl.m_bIsUpdateTargetNoAttack = true;

		if (oWordControl.m_bIsRePaintOnScroll === true)
		{
			oWordControl.OnScroll();
		}

		if (oWordControl.MobileTouchManager && oWordControl.MobileTouchManager.iScroll)
		{
			oWordControl.MobileTouchManager.iScroll.x = -oWordControl.m_dScrollX;
		}
	};

	this.CreateScrollSettings = function()
	{
		var settings = new AscCommon.ScrollSettings();
		settings.screenW = this.m_oEditor.HtmlElement.width;
		settings.screenH = this.m_oEditor.HtmlElement.height;
		settings.vscrollStep = 45;
		settings.hscrollStep = 45;
		settings.isNeedInvertOnActive = GlobalSkin.isNeedInvertOnActive;

		settings.scrollBackgroundColor = GlobalSkin.BackgroundScroll;
		settings.scrollBackgroundColorHover = GlobalSkin.BackgroundScroll;
		settings.scrollBackgroundColorActive = GlobalSkin.BackgroundScroll;

		if (this.bIsRetinaSupport)
		{
			settings.screenW = AscCommon.AscBrowser.convertToRetinaValue(settings.screenW);
			settings.screenH = AscCommon.AscBrowser.convertToRetinaValue(settings.screenH);
		}
		return settings;
	};

	this.UpdateScrolls = function()
	{
		var settings;
		if (window["NATIVE_EDITOR_ENJINE"])
			return;

		settings = this.CreateScrollSettings();
		if (this.m_oScrollHor_)
			this.m_oScrollHor_.Repos(settings, this.m_bIsHorScrollVisible);
		else
		{
			this.m_oScrollHor_ = new AscCommon.ScrollObject("id_horizontal_scroll", settings);

			this.m_oScrollHor_.onLockMouse  = function(evt)
			{
				AscCommon.check_MouseDownEvent(evt, true);
				global_mouseEvent.LockMouse();
			};
			this.m_oScrollHor_.offLockMouse = function(evt)
			{
				AscCommon.check_MouseUpEvent(evt);
			};
			this.m_oScrollHor_.bind("scrollhorizontal", function(evt)
			{
				oThis.horizontalScroll(this, evt.scrollD, evt.maxScrollX);
			});
			this.m_oScrollHorApi = this.m_oScrollHor_;
		}

		settings = this.CreateScrollSettings();
		if (this.m_oScrollVer_)
		{
			this.m_oScrollVer_.Repos(settings, undefined, true);
		}
		else
		{
			this.m_oScrollVer_ = new AscCommon.ScrollObject("id_vertical_scroll", settings);

			this.m_oScrollVer_.onLockMouse  = function(evt)
			{
				AscCommon.check_MouseDownEvent(evt, true);
				global_mouseEvent.LockMouse();
			};
			this.m_oScrollVer_.offLockMouse = function(evt)
			{
				AscCommon.check_MouseUpEvent(evt);
			};
			this.m_oScrollVer_.bind("scrollvertical", function(evt)
			{
				oThis.verticalScroll(this, evt.scrollD, evt.maxScrollY);
			});
			this.m_oScrollVer_.bind("correctVerticalScroll", function(yPos)
			{
				return oThis.CorrectSpeedVerticalScroll(yPos);
			});
			this.m_oScrollVerApi = this.m_oScrollVer_;
		}

		this.m_oApi.sendEvent("asc_onUpdateScrolls", this.m_dDocumentWidth, this.m_dDocumentHeight);

		this.m_dScrollX_max = this.m_oScrollHorApi.getMaxScrolledX();
		this.m_dScrollY_max = this.m_oScrollVerApi.getMaxScrolledY();

		if (this.m_dScrollX >= this.m_dScrollX_max)
			this.m_dScrollX = this.m_dScrollX_max;
		if (this.m_dScrollY >= this.m_dScrollY_max)
			this.m_dScrollY = this.m_dScrollY_max;
	};

	this.OnRePaintAttack = function()
	{
		this.m_bIsFullRepaint = true;
		this.OnScroll();
	};

	this.OnResize = function(isAttack)
	{
		AscBrowser.checkZoom();

		var isNewSize = this.checkBodySize();
		if (!isNewSize && false === isAttack)
			return;

		if (this.MobileTouchManager)
			this.MobileTouchManager.Resize_Before();

		this.CheckRetinaDisplay();
		this.m_oBody.Resize(this.Width * g_dKoef_pix_to_mm, this.Height * g_dKoef_pix_to_mm, this);
		this.onButtonTabsDraw();

		if (AscCommon.g_inputContext)
			AscCommon.g_inputContext.onResize("id_main_view");

		if (this.TextBoxBackground != null)
		{
			// это мега заглушка. чтобы не показывалась клавиатура при тыкании на тулбар
			this.TextBoxBackground.HtmlElement.style.top = "10px";
		}

		if (this.checkNeedHorScroll())
			return;

		// теперь проверим необходимость перезуммирования
		if (1 == this.m_nZoomType)
		{
			if (true === this.zoom_FitToWidth())
			{
				this.m_oBoundsController.ClearNoAttack();
				this.onTimerScroll2_sync();
				return;
			}
		}
		if (2 == this.m_nZoomType)
		{
			if (true === this.zoom_FitToPage())
			{
				this.m_oBoundsController.ClearNoAttack();
				this.onTimerScroll2_sync();
				return;
			}
		}

		this.m_bIsUpdateHorRuler = true;
		this.m_bIsUpdateVerRuler = true;

		if (this.m_bIsRuler)
		{
			this.UpdateHorRulerBack(true);
			this.UpdateVerRulerBack(true);
		}

		this.m_oHorRuler.RepaintChecker.BlitAttack = true;
		this.m_oVerRuler.RepaintChecker.BlitAttack = true;

		this.UpdateScrolls();

		if (this.MobileTouchManager)
			this.MobileTouchManager.Resize();

		if (this.ReaderTouchManager)
			this.ReaderTouchManager.Resize();

		this.m_bIsUpdateTargetNoAttack = true;
		this.m_bIsRePaintOnScroll      = true;

		this.m_oBoundsController.ClearNoAttack();

		this.OnScroll();
		this.onTimerScroll2_sync();

		if (this.MobileTouchManager)
			this.MobileTouchManager.Resize_After();
	};

	this.checkNeedRules     = function()
	{
		if (this.m_bIsRuler)
		{
			this.m_oLeftRuler.HtmlElement.style.display = 'block';
			this.m_oTopRuler.HtmlElement.style.display  = 'block';

			this.m_oMainView.Bounds.L = 5;
			this.m_oMainView.Bounds.T = 7;

			/*
			 this.m_oEditor.Bounds.L = 5;
			 this.m_oEditor.Bounds.T = 7;

			 this.m_oOverlay.Bounds.L = 5;
			 this.m_oOverlay.Bounds.T = 7;
			 */
		}
		else
		{
			this.m_oLeftRuler.HtmlElement.style.display = 'none';
			this.m_oTopRuler.HtmlElement.style.display  = 'none';

			this.m_oMainView.Bounds.L = 0;
			this.m_oMainView.Bounds.T = 0;

			/*
			 this.m_oEditor.Bounds.L = 0;
			 this.m_oEditor.Bounds.T = 0;

			 this.m_oOverlay.Bounds.L = 0;
			 this.m_oOverlay.Bounds.T = 0;
			 */
		}
	};
	this.checkNeedHorScroll = function()
	{
		if (this.m_oApi.isMobileVersion)
		{
			this.m_oPanelRight.Bounds.B  = 0;
			this.m_oMainContent.Bounds.B = 0;

			// этот флаг для того, чтобы не делался лишний зум и т.д.
			this.m_bIsHorScrollVisible = false;

			var hor_scroll         = document.getElementById('panel_hor_scroll');
			hor_scroll.style.width = this.m_dDocumentWidth + "px";

			return false;
		}

		var _editor_width = this.m_oEditor.HtmlElement.width;
		if (this.bIsRetinaSupport)
			_editor_width /= AscCommon.AscBrowser.retinaPixelRatio;

		var oldVisible = this.m_bIsHorScrollVisible;
		if (this.m_dDocumentWidth <= _editor_width)
		{
			this.m_bIsHorScrollVisible = false;
		}
		else
		{
			this.m_bIsHorScrollVisible = true;
		}

		var hor_scroll         = document.getElementById('panel_hor_scroll');
		hor_scroll.style.width = this.m_dDocumentWidth + "px";

		if (this.m_bIsHorScrollVisible)
		{
			this.m_oScrollHor.HtmlElement.style.display = 'block';

			this.m_oPanelRight.Bounds.B  = this.ScrollsWidthPx * g_dKoef_pix_to_mm;
			this.m_oMainContent.Bounds.B = this.ScrollsWidthPx * g_dKoef_pix_to_mm;
		}
		else
		{
			this.m_oPanelRight.Bounds.B                 = 0;
			this.m_oMainContent.Bounds.B                = 0;
			this.m_oScrollHor.HtmlElement.style.display = 'none';
		}

		if (this.m_bIsHorScrollVisible != oldVisible)
		{
			this.m_dScrollX = 0;
			this.OnResize(true);
			return true;
		}
		return false;
	};

	this.getScrollMaxX = function(size)
	{
		if (size >= this.m_dDocumentWidth)
			return 1;
		return this.m_dDocumentWidth - size;
	};
	this.getScrollMaxY = function(size)
	{
		if (size >= this.m_dDocumentHeight)
			return 1;
		return this.m_dDocumentHeight - size;
	};

	this.StartUpdateOverlay = function()
	{
		this.IsUpdateOverlayOnlyEnd = true;
	};
	this.EndUpdateOverlay   = function()
	{
		if (this.IsUpdateOverlayOnlyEndReturn)
			return;

		this.IsUpdateOverlayOnlyEnd = false;
		if (this.IsUpdateOverlayOnEndCheck)
			this.OnUpdateOverlay();
		this.IsUpdateOverlayOnEndCheck = false;
	};

	this.OnUpdateOverlay = function()
	{
		if (this.IsUpdateOverlayOnlyEnd)
		{
			this.IsUpdateOverlayOnEndCheck = true;
			return false;
		}

		this.m_oApi.checkLastWork();

		//console.log("update_overlay");
		var overlay = this.m_oOverlayApi;
		//if (!overlay.m_bIsShow)
		//    return;

		overlay.Clear();
		var ctx = overlay.m_oContext;

		var drDoc = this.m_oDrawingDocument;
		drDoc.SelectionMatrix = null;
		if (drDoc.m_lDrawingFirst < 0 || drDoc.m_lDrawingEnd < 0)
			return true;

		if (drDoc.m_bIsSearching)
		{
			ctx.fillStyle = "rgba(255,200,0,1)";
			ctx.beginPath();

			var drDoc = this.m_oDrawingDocument;
			for (var i = drDoc.m_lDrawingFirst; i <= drDoc.m_lDrawingEnd; i++)
			{
				var drawPage                  = drDoc.m_arrPages[i].drawingPage;
				drDoc.m_arrPages[i].pageIndex = i;
				drDoc.m_arrPages[i].DrawSearch(overlay, drawPage.left, drawPage.top, drawPage.right - drawPage.left, drawPage.bottom - drawPage.top, drDoc);
			}

			ctx.globalAlpha = 0.5;
			ctx.fill();
			ctx.beginPath();
			ctx.globalAlpha = 1.0;
		}

		if (null == drDoc.m_oDocumentRenderer)
		{
			if (drDoc.m_bIsSelection)
			{
				this.CheckShowOverlay();
				drDoc.private_StartDrawSelection(overlay);

				if (!this.MobileTouchManager)
				{
					for (var i = drDoc.m_lDrawingFirst; i <= drDoc.m_lDrawingEnd; i++)
					{
						if (!drDoc.IsFreezePage(i))
							this.m_oLogicDocument.DrawSelectionOnPage(i);
					}
				}
				else
				{
					for (var i = 0; i <= drDoc.m_lPagesCount; i++)
					{
						if (!drDoc.IsFreezePage(i))
							this.m_oLogicDocument.DrawSelectionOnPage(i);
					}
				}

				drDoc.private_EndDrawSelection();

				drDoc.DrawPageSelection2(overlay);

				if (this.MobileTouchManager)
					this.MobileTouchManager.CheckSelect(overlay);
			}

			if (this.MobileTouchManager)
				this.MobileTouchManager.CheckTableRules(overlay);

			ctx.globalAlpha = 1.0;

			var _table_outline = drDoc.TableOutlineDr.TableOutline;
			if (_table_outline != null && !this.MobileTouchManager)
			{
				var _page = _table_outline.PageNum;
				if (_page >= drDoc.m_lDrawingFirst && _page <= drDoc.m_lDrawingEnd)
				{
					var drawPage = drDoc.m_arrPages[_page].drawingPage;
					drDoc.m_arrPages[_page].DrawTableOutline(overlay,
						drawPage.left, drawPage.top, drawPage.right - drawPage.left, drawPage.bottom - drawPage.top, drDoc.TableOutlineDr);
				}
				if (true)
				{
					var _lastBounds = drDoc.TableOutlineDr.getLastPageBounds();
					_page = _lastBounds.Page;
					if (_page >= drDoc.m_lDrawingFirst && _page <= drDoc.m_lDrawingEnd)
					{
						var drawPage = drDoc.m_arrPages[_page].drawingPage;
						drDoc.m_arrPages[_page].DrawTableOutline(overlay,
							drawPage.left, drawPage.top, drawPage.right - drawPage.left, drawPage.bottom - drawPage.top, drDoc.TableOutlineDr, _lastBounds);
					}
				}
			}

			// drawShapes (+ track)
			if (this.m_oLogicDocument.DrawingObjects)
			{
				for (var indP = drDoc.m_lDrawingFirst; indP <= drDoc.m_lDrawingEnd; indP++)
				{
					this.m_oDrawingDocument.AutoShapesTrack.PageIndex = indP;
					this.m_oLogicDocument.DrawingObjects.drawSelect(indP);
				}

				if (this.m_oLogicDocument.DrawingObjects.needUpdateOverlay())
				{
					overlay.Show();
					this.m_oDrawingDocument.AutoShapesTrack.PageIndex = -1;
					this.m_oLogicDocument.DrawingObjects.drawOnOverlay(this.m_oDrawingDocument.AutoShapesTrack);
					this.m_oDrawingDocument.AutoShapesTrack.CorrectOverlayBounds();
				}
			}

			drDoc.DrawContentControlsTrack(overlay);

			if (drDoc.TableOutlineDr.bIsTracked)
			{
				drDoc.DrawTableTrack(overlay);
			}

			if (drDoc.FrameRect.IsActive)
			{
				drDoc.DrawFrameTrack(overlay);
			}

			if (drDoc.MathRect.IsActive)
			{
				drDoc.DrawMathTrack(overlay);
			}

			if (drDoc.FieldTrack.IsActive)
			{
				drDoc.DrawFieldTrack(overlay);
			}

			if (drDoc.InlineTextTrackEnabled && null != drDoc.InlineTextTrack)
			{
				var _oldPage        = drDoc.AutoShapesTrack.PageIndex;
				var _oldCurPageInfo = drDoc.AutoShapesTrack.CurrentPageInfo;

				drDoc.AutoShapesTrack.PageIndex = drDoc.InlineTextTrackPage;
				drDoc.AutoShapesTrack.DrawInlineMoveCursor(drDoc.InlineTextTrack.X, drDoc.InlineTextTrack.Y, drDoc.InlineTextTrack.Height, drDoc.InlineTextTrack.transform);

				drDoc.AutoShapesTrack.PageIndex       = _oldPage;
				drDoc.AutoShapesTrack.CurrentPageInfo = _oldCurPageInfo;
			}

			drDoc.DrawHorVerAnchor();
		}
		else
		{
			ctx.globalAlpha = 0.2;

			if (drDoc.m_oDocumentRenderer.SearchResults.IsSearch)
			{
				this.m_oOverlayApi.Show();

				if (drDoc.m_oDocumentRenderer.SearchResults.Show)
				{
					ctx.globalAlpha = 0.5;
					ctx.fillStyle   = "rgba(255,200,0,1)";
					ctx.beginPath();
					for (var i = drDoc.m_lDrawingFirst; i <= drDoc.m_lDrawingEnd; i++)
					{
						var _searching = drDoc.m_oDocumentRenderer.SearchResults.Pages[i];

						if (0 != _searching.length)
						{
							var drawPage = drDoc.m_arrPages[i].drawingPage;
							drDoc.m_arrPages[i].DrawSearch2(overlay, drawPage.left, drawPage.top, drawPage.right - drawPage.left, drawPage.bottom - drawPage.top, _searching);
						}
					}
					ctx.fill();
					ctx.globalAlpha = 0.2;
				}
				ctx.beginPath();

				if (drDoc.CurrentSearchNavi && drDoc.m_oDocumentRenderer.SearchResults.Show)
				{
					var _pageNum  = drDoc.CurrentSearchNavi[0].PageNum;
					ctx.fillStyle = "rgba(51,102,204,255)";
					if (_pageNum >= drDoc.m_lDrawingFirst && _pageNum <= drDoc.m_lDrawingEnd)
					{
						var drawPage = drDoc.m_arrPages[_pageNum].drawingPage;
						drDoc.m_arrPages[_pageNum].DrawSearchCur(overlay, drawPage.left, drawPage.top, drawPage.right - drawPage.left, drawPage.bottom - drawPage.top, drDoc.CurrentSearchNavi);
					}
				}
			}

			ctx.fillStyle = "rgba(51,102,204,255)";
			ctx.beginPath();

			for (var i = drDoc.m_lDrawingFirst; i <= drDoc.m_lDrawingEnd; i++)
			{
				var drawPage = drDoc.m_arrPages[i].drawingPage;
				drDoc.m_oDocumentRenderer.DrawSelection(i, overlay, drawPage.left, drawPage.top, drawPage.right - drawPage.left, drawPage.bottom - drawPage.top);
			}

			ctx.fill();
			ctx.beginPath();
			ctx.globalAlpha = 1.0;
		}

		return true;
	};

	this.OnUpdateSelection = function()
	{
		if (this.m_oDrawingDocument.m_bIsSelection)
		{
			this.m_oOverlayApi.Clear();
			this.m_oOverlayApi.m_oContext.beginPath();
			this.m_oOverlayApi.m_oContext.fillStyle = "rgba(51,102,204,255)";
		}

		for (var i = 0; i < this.m_oDrawingDocument.m_lPagesCount; i++)
		{
			if (i < this.m_oDrawingDocument.m_lDrawingFirst || i > this.m_oDrawingDocument.m_lDrawingEnd)
			{
				continue;
			}

			var drawPage = this.m_oDrawingDocument.m_arrPages[i].drawingPage;

			if (this.m_oDrawingDocument.m_bIsSelection)
			{
				this.m_oDrawingDocument.m_arrPages[i].DrawSelection(this.m_oOverlayApi, drawPage.left, drawPage.top, drawPage.right - drawPage.left, drawPage.bottom - drawPage.top);
			}
		}

		if (this.m_oDrawingDocument.m_bIsSelection)
		{
			this.m_oOverlayApi.m_oContext.globalAlpha = 0.2;
			this.m_oOverlayApi.m_oContext.fill();
			this.m_oOverlayApi.m_oContext.globalAlpha = 1.0;

			// нужно очистить набивку пата
			this.m_oOverlayApi.m_oContext.beginPath();
		}
	};

	this.OnCalculatePagesPlace = function()
	{
		if (this.MobileTouchManager && !this.MobileTouchManager.IsWorkedPosition())
			this.MobileTouchManager.ClearContextMenu();

		var canvas = this.m_oEditor.HtmlElement;
		if (null == canvas)
			return;

		var _width  = canvas.width;
		var _height = canvas.height;

		if (this.bIsRetinaSupport)
		{
			_width = AscCommon.AscBrowser.convertToRetinaValue(_width);
			_height = AscCommon.AscBrowser.convertToRetinaValue(_height);
		}

		var bIsFoundFirst = false;
		var bIsFoundEnd   = false;

		var hor_pos_median = parseInt(_width / 2);
		if (0 != this.m_dScrollX || (this.m_dDocumentWidth > _width))
		{
			//var part = this.m_dScrollX / Math.max(this.m_dScrollX_max, 1);
			//hor_pos_median = parseInt(this.m_dDocumentWidth / 2 + part * (_width - this.m_dDocumentWidth));
			hor_pos_median = parseInt(this.m_dDocumentWidth / 2 - this.m_dScrollX);
		}

		var lCurrentTopInDoc = parseInt(this.m_dScrollY);

		var dKoef  = (this.m_nZoomValue * g_dKoef_mm_to_pix / 100);
		var lStart = 0;
		for (var i = 0; i < this.m_oDrawingDocument.m_lPagesCount; i++)
		{
			var _pageWidth  = (this.m_oDrawingDocument.m_arrPages[i].width_mm * dKoef + 0.5) >> 0;
			var _pageHeight = (this.m_oDrawingDocument.m_arrPages[i].height_mm * dKoef + 0.5) >> 0;

			if (false === bIsFoundFirst)
			{
				if (lStart + 20 + _pageHeight > lCurrentTopInDoc)
				{
					this.m_oDrawingDocument.m_lDrawingFirst = i;
					bIsFoundFirst                           = true;
				}
			}

			var xDst = hor_pos_median - parseInt(_pageWidth / 2);
			var wDst = _pageWidth;
			var yDst = lStart + 20 - lCurrentTopInDoc;
			var hDst = _pageHeight;

			if (false === bIsFoundEnd)
			{
				if (yDst > _height)
				{
					this.m_oDrawingDocument.m_lDrawingEnd = i - 1;
					bIsFoundEnd                           = true;
				}
			}

			var drawRect = this.m_oDrawingDocument.m_arrPages[i].drawingPage;

			drawRect.left      = xDst;
			drawRect.top       = yDst;
			drawRect.right     = xDst + wDst;
			drawRect.bottom    = yDst + hDst;
			drawRect.pageIndex = i;

			lStart += (20 + _pageHeight);
		}

		if (false === bIsFoundEnd)
		{
			this.m_oDrawingDocument.m_lDrawingEnd = this.m_oDrawingDocument.m_lPagesCount - 1;
		}

		if ((-1 == this.m_oDrawingDocument.m_lPagesCount) && (0 != this.m_oDrawingDocument.m_lPagesCount))
		{
			this.m_oDrawingDocument.m_lCurrentPage = 0;
			this.SetCurrentPage();
		}

		// отправляем евент о текущей странице. только в мобильной версии
		if ((this.m_oApi.isMobileVersion || this.m_oApi.isViewMode) && (!window["NATIVE_EDITOR_ENJINE"]))
		{
			var lPage = this.m_oApi.GetCurrentVisiblePage();
			this.m_oApi.sendEvent("asc_onCurrentVisiblePage", this.m_oApi.GetCurrentVisiblePage());

			if (null != this.m_oDrawingDocument.m_oDocumentRenderer)
			{
				this.m_oDrawingDocument.m_lCurrentPage = lPage;
				this.m_oApi.sendEvent("asc_onCurrentPage", lPage);
			}
		}

		if (this.m_bDocumentPlaceChangedEnabled)
			this.m_oApi.sendEvent("asc_onDocumentPlaceChanged");
	};

	this.OnPaint = function()
	{
		if (this.m_oApi.isLongAction())
			return;

		if (this.DrawingFreeze || true === window["DisableVisibleComponents"])
		{
			this.m_oApi.checkLastWork();
			return;
		}
		//console.log("paint");

		var canvas = this.m_oEditor.HtmlElement;
		if (null == canvas)
		{
			this.m_oApi.checkLastWork();
			return;
		}

		var context       = canvas.getContext("2d");
		context.fillStyle = GlobalSkin.BackgroundColor;

		if (this.m_oDrawingDocument.m_lDrawingFirst < 0 || this.m_oDrawingDocument.m_lDrawingEnd < 0)
			return;

		//this.m_oBoundsController.Clear(context);
		// сначала посморим, изменились ли ректы страниц
		var rectsPages = [];
		for (var i = this.m_oDrawingDocument.m_lDrawingFirst; i <= this.m_oDrawingDocument.m_lDrawingEnd; i++)
		{
			var drawPage = this.m_oDrawingDocument.m_arrPages[i].drawingPage;

			if (!this.bIsRetinaSupport)
			{
				var _cur_page_rect = new AscCommon._rect();
				_cur_page_rect.x   = drawPage.left;
				_cur_page_rect.y   = drawPage.top;
				_cur_page_rect.w   = drawPage.right - drawPage.left;
				_cur_page_rect.h   = drawPage.bottom - drawPage.top;

				rectsPages.push(_cur_page_rect);
			}
			else
			{
				var _cur_page_rect = new AscCommon._rect();
				_cur_page_rect.x   = (drawPage.left * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
				_cur_page_rect.y   = (drawPage.top * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
				_cur_page_rect.w   = ((drawPage.right * AscCommon.AscBrowser.retinaPixelRatio) >> 0) - _cur_page_rect.x;
				_cur_page_rect.h   = ((drawPage.bottom * AscCommon.AscBrowser.retinaPixelRatio) >> 0) - _cur_page_rect.y;

				rectsPages.push(_cur_page_rect);
			}
		}
		this.m_oBoundsController.CheckPageRects(rectsPages, context);

		if (this.m_oDrawingDocument.m_bIsSelection)
		{
			this.m_oOverlayApi.Clear();
			this.m_oOverlayApi.m_oContext.beginPath();
			this.m_oOverlayApi.m_oContext.fillStyle   = "rgba(51,102,204,255)";
			this.m_oOverlayApi.m_oContext.globalAlpha = 0.2;
		}

		if (this.NoneRepaintPages)
		{
			this.m_bIsFullRepaint = false;

			for (var i = this.m_oDrawingDocument.m_lDrawingFirst; i <= this.m_oDrawingDocument.m_lDrawingEnd; i++)
			{
				var drawPage = this.m_oDrawingDocument.m_arrPages[i].drawingPage;

				if (!this.bIsRetinaSupport)
				{
					this.m_oDrawingDocument.m_arrPages[i].Draw(context, drawPage.left, drawPage.top, drawPage.right - drawPage.left, drawPage.bottom - drawPage.top);
					//this.m_oBoundsController.CheckRect(drawPage.left, drawPage.top, drawPage.right - drawPage.left, drawPage.bottom - drawPage.top);
				}
				else
				{
					var __x = (drawPage.left * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
					var __y = (drawPage.top * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
					var __w = ((drawPage.right * AscCommon.AscBrowser.retinaPixelRatio) >> 0) - __x;
					var __h = ((drawPage.bottom * AscCommon.AscBrowser.retinaPixelRatio) >> 0) - __y;
					this.m_oDrawingDocument.m_arrPages[i].Draw(context, __x, __y, __w, __h);
					//this.m_oBoundsController.CheckRect(__x, __y, __w, __h);
				}
			}
		}
		else
		{
			for (var i = 0; i < this.m_oDrawingDocument.m_lDrawingFirst; i++)
				this.m_oDrawingDocument.StopRenderingPage(i);

			for (var i = this.m_oDrawingDocument.m_lDrawingEnd + 1; i < this.m_oDrawingDocument.m_lPagesCount; i++)
				this.m_oDrawingDocument.StopRenderingPage(i);

			for (var i = this.m_oDrawingDocument.m_lDrawingFirst; i <= this.m_oDrawingDocument.m_lDrawingEnd; i++)
			{
				var drawPage = this.m_oDrawingDocument.m_arrPages[i].drawingPage;

				if (this.m_bIsFullRepaint === true)
				{
					this.m_oDrawingDocument.StopRenderingPage(i);
				}

				var __x = drawPage.left;
				var __y = drawPage.top;
				var __w = drawPage.right - __x;
				var __h = drawPage.bottom - __y;
				if (this.bIsRetinaSupport)
				{
					__x = (__x * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
					__y = (__y * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
					__w = (__w * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
					__h = (__h * AscCommon.AscBrowser.retinaPixelRatio) >> 0;
				}

				this.m_oDrawingDocument.CheckRecalculatePage(__w, __h, i);
				if (null == drawPage.cachedImage)
				{
					this.m_oDrawingDocument.StartRenderingPage(i);
				}

				this.m_oDrawingDocument.m_arrPages[i].Draw(context, __x, __y, __w, __h);
				//this.m_oBoundsController.CheckRect(__x, __y, __w, __h);
			}
		}

		this.m_bIsFullRepaint = false;

		this.OnUpdateOverlay();

		if (this.m_bIsUpdateHorRuler)
		{
			this.UpdateHorRuler();
			this.m_bIsUpdateHorRuler = false;
		}
		if (this.m_bIsUpdateVerRuler)
		{
			this.UpdateVerRuler();
			this.m_bIsUpdateVerRuler = false;
		}
		if (this.m_bIsUpdateTargetNoAttack)
		{
			this.m_oDrawingDocument.UpdateTargetNoAttack();
			this.m_bIsUpdateTargetNoAttack = false;
		}
	};

	this.CheckRetinaElement = function(htmlElem)
	{
		if (this.bIsRetinaSupport)
		{
			if (htmlElem.id == "id_viewer" ||
				(htmlElem.id == "id_viewer_overlay" && this.m_oOverlayApi.IsRetina) ||
				htmlElem.id == "id_hor_ruler" ||
				htmlElem.id == "id_vert_ruler" ||
				htmlElem.id == "id_buttonTabs")
				return true;
		}
		return false;
	};

	this.GetDrawingPageInfo = function(nPageIndex)
	{
		return this.m_oDrawingDocument.m_arrPages[nPageIndex];
	};

	this.CheckFontCache = function()
	{
		var _c = oThis;
		_c.m_nCurrentTimeClearCache++;
		if (_c.m_nCurrentTimeClearCache > 750) // 30 секунд. корректировать при смене интервала главного таймера!!!
		{
			_c.m_nCurrentTimeClearCache = 0;
			_c.m_oDrawingDocument.CheckFontCache();
		}

		oThis.m_oLogicDocument.ContinueCheckSpelling();
		oThis.m_oLogicDocument.ContinueTrackRevisions();
	};
	this.OnScroll       = function()
	{
		this.OnCalculatePagesPlace();
		this.m_bIsScroll = true;
	};

	this.CheckZoom = function()
	{
		if (!this.NoneRepaintPages)
			this.m_oDrawingDocument.ClearCachePages();
	};

	this.ChangeHintProps = function()
	{
		var bFlag = false;
		if (global_keyboardEvent.CtrlKey)
		{
			if (null != this.m_oLogicDocument)
			{
				if (49 == global_keyboardEvent.KeyCode)
				{
					AscCommon.SetHintsProps(false, false);
					bFlag = true;
				}
				else if (50 == global_keyboardEvent.KeyCode)
				{
					AscCommon.SetHintsProps(true, false);
					bFlag = true;
				}
				else if (51 == global_keyboardEvent.KeyCode)
				{
					AscCommon.SetHintsProps(true, true);
					bFlag = true;
				}
			}
		}

		if (bFlag)
		{
			this.m_oDrawingDocument.ClearCachePages();
			AscCommon.g_fontManager.ClearFontsRasterCache();

			if (AscCommon.g_fontManager2)
				AscCommon.g_fontManager2.ClearFontsRasterCache();
		}

		return bFlag;
	};

	this.CalculateDocumentSize = function()
	{
		this.m_dDocumentWidth      = 0;
		this.m_dDocumentHeight     = 0;
		this.m_dDocumentPageWidth  = 0;
		this.m_dDocumentPageHeight = 0;

		var dKoef = (this.m_nZoomValue * g_dKoef_mm_to_pix / 100);

		for (var i = 0; i < this.m_oDrawingDocument.m_lPagesCount; i++)
		{
			var mm_w = this.m_oDrawingDocument.m_arrPages[i].width_mm;
			var mm_h = this.m_oDrawingDocument.m_arrPages[i].height_mm;

			if (mm_w > this.m_dDocumentPageWidth)
				this.m_dDocumentPageWidth = mm_w;
			if (mm_h > this.m_dDocumentPageHeight)
				this.m_dDocumentPageHeight = mm_h;

			var _pageWidth  = (mm_w * dKoef) >> 0;
			var _pageHeight = (mm_h * dKoef + 0.5) >> 0;

			if (_pageWidth > this.m_dDocumentWidth)
				this.m_dDocumentWidth = _pageWidth;

			this.m_dDocumentHeight += 20;
			this.m_dDocumentHeight += _pageHeight;
		}

		this.m_dDocumentHeight += 20;

		// теперь увеличим ширину документа, чтобы он не был плотно к краям
		if (!this.m_oApi.isMobileVersion)
			this.m_dDocumentWidth += 40;

		// теперь проверим необходимость перезуммирования
		if (1 == this.m_nZoomType)
		{
			if (true === this.zoom_FitToWidth())
				return;
		}
		if (2 == this.m_nZoomType)
		{
			if (true === this.zoom_FitToPage())
				return;
		}

		// теперь нужно выставить размеры для скроллов
		this.checkNeedHorScroll();

		document.getElementById('panel_right_scroll').style.height = this.m_dDocumentHeight + "px";

		this.UpdateScrolls();

		if (this.MobileTouchManager)
			this.MobileTouchManager.Resize();

		if (this.ReaderTouchManager)
			this.ReaderTouchManager.Resize();

		if (this.m_bIsRePaintOnScroll === true)
			this.OnScroll();
	};

	this.InitDocument = function(bIsEmpty)
	{
		this.m_oDrawingDocument.m_oWordControl   = this;
		this.m_oDrawingDocument.m_oLogicDocument = this.m_oLogicDocument;

		if (false === bIsEmpty)
		{
			this.m_oLogicDocument.LoadTestDocument();
		}

		this.CalculateDocumentSize();
		//setInterval(this.onTimerScroll, this.m_nTimerScrollInterval);
		this.StartMainTimer();

		this.m_oHorRuler.CreateBackground(this.m_oDrawingDocument.m_arrPages[0]);
		this.m_oVerRuler.CreateBackground(this.m_oDrawingDocument.m_arrPages[0]);
		this.UpdateHorRuler();
		this.UpdateVerRuler();
	};

	this.InitControl = function()
	{
		if (this.IsInitControl)
			return;

		this.CalculateDocumentSize();

		if (window["AscDesktopEditor"] && this.m_oDrawingDocument.m_oDocumentRenderer)
		{
			var _new_value = this.calculate_zoom_FitToWidth();
			if (_new_value < this.m_nZoomValue)
			{
				// сначала добавим нужные параметры зума
				var _newValues = [];
				_new_value     = ((_new_value / 10) >> 0) * 10 - 1;
				for (var _test_param = 10; _test_param < this.zoom_values[0]; _test_param += 10)
				{
					if (_new_value < _test_param)
						_newValues.push(_test_param);
				}
				this.zoom_values = [].concat(_newValues, this.zoom_values);

				this.zoom_FitToWidth();
			}
		}

		//setInterval(this.onTimerScroll, this.m_nTimerScrollInterval);

		if (!this.m_oApi.isOnlyReaderMode)
			this.StartMainTimer();

		this.m_oHorRuler.CreateBackground(this.m_oDrawingDocument.m_arrPages[0]);
		this.m_oVerRuler.CreateBackground(this.m_oDrawingDocument.m_arrPages[0]);
		this.UpdateHorRuler();
		this.UpdateVerRuler();

		if (window["AutoTester"] !== undefined)
		{
			window["AutoTester"]["RunTest"]();
		}

        if (true)
        {
            AscCommon.InitBrowserInputContext(this.m_oApi, "id_target_cursor");
            if (AscCommon.g_inputContext)
                AscCommon.g_inputContext.onResize("id_main_view");

            if (this.m_oApi.isMobileVersion)
                this.initEventsMobile();
        }

		//this.m_oDrawingDocument.CheckFontCache();

		this.IsInitControl = true;
	};

	this.AnimationFrame = function()
	{
		var now = Date.now();
		if (-1 == oThis.RequestAnimationOldTime || (now >= (oThis.RequestAnimationOldTime + 40)))
		{
			oThis.RequestAnimationOldTime = now;
			oThis.onTimerScroll2(true);
		}
		oThis.RequestAnimationFrame.call(window, oThis.AnimationFrame);
	};

	this.onTimerScroll = function()
	{
		var oWordControl = oThis;
		if (oWordControl.m_bIsScroll)
		{
			oWordControl.m_bIsScroll = false;
			window.postMessage(_message_update, "*");
			//setTimeout("oWordControl.OnPaint();", 0);
		}
		else if (null != oWordControl.m_oLogicDocument)
		{
			oWordControl.m_oDrawingDocument.UpdateTargetFromPaint = true;
			oWordControl.m_oLogicDocument.CheckTargetUpdate();
			oWordControl.m_oDrawingDocument.UpdateTargetFromPaint = false;
		}
		if (null != oWordControl.m_oLogicDocument)
		{
			oWordControl.CheckFontCache();
			oWordControl.m_oDrawingDocument.CheckTrackTable();
		}
	};

	this.StartMainTimer = function()
	{
		if (this.UseRequestAnimationFrame)
		{
			this.AnimationFrame();
			return;
		}
		if (-1 == this.m_nPaintTimerId)
			this.onTimerScroll2();
	};

	this.onTimerScroll2_internal = function(is_no_timer)
	{
		var oWordControl = oThis;

		if (!oWordControl.m_oApi.bInit_word_control)
			return;

        if (oWordControl.m_oApi.isLongAction())
            return;

		var isRepaint                   = oWordControl.m_bIsScroll;
		if (null != oWordControl.m_oLogicDocument && !oWordControl.m_oApi.isLockTargetUpdate)
		{
			oWordControl.m_oDrawingDocument.UpdateTargetFromPaint = true;
			oWordControl.m_oLogicDocument.CheckTargetUpdate();
			oWordControl.m_oDrawingDocument.CheckTargetShow();
			oWordControl.m_oDrawingDocument.UpdateTargetFromPaint = false;

			oWordControl.CheckFontCache();
			oWordControl.m_oDrawingDocument.CheckTrackTable();
		}
		if (oWordControl.m_bIsScroll)
		{
			oWordControl.m_bIsScroll = false;
			oWordControl.OnPaint();

			if (null != oWordControl.m_oLogicDocument && oWordControl.m_oApi.bInit_word_control)
				oWordControl.m_oLogicDocument.Viewer_OnChangePosition();
		}

		oWordControl.m_oDrawingDocument.Collaborative_TargetsUpdate(isRepaint);

		oWordControl.m_oApi.sendEvent("asc_onPaintTimer");
		//window.requestAnimationFrame(oWordControl.onTimerScroll2);
	};
	this.onTimerScroll2          = function(is_no_timer)
	{
		try
		{
			oThis.onTimerScroll2_internal(is_no_timer);
		}
		catch (err)
		{
		}

		if (true !== is_no_timer)
			this.m_nPaintTimerId = setTimeout(oThis.onTimerScroll2, oThis.m_nTimerScrollInterval);
	};

	this.onTimerScroll2_sync = function()
	{
		var oWordControl = oThis;

		if (!oWordControl.m_oApi.bInit_word_control || oWordControl.m_oApi.isOnlyReaderMode)
			return;

		var isRepaint                   = oWordControl.m_bIsScroll;
		if (oWordControl.m_bIsScroll)
		{
			oWordControl.m_bIsScroll = false;
			oWordControl.OnPaint();

			if (null != oWordControl.m_oLogicDocument && oWordControl.m_oApi.bInit_word_control)
				oWordControl.m_oLogicDocument.Viewer_OnChangePosition();
		}
		if (null != oWordControl.m_oLogicDocument)
		{
			oWordControl.m_oDrawingDocument.UpdateTargetFromPaint = true;
			oWordControl.m_oLogicDocument.CheckTargetUpdate();
			oWordControl.m_oDrawingDocument.CheckTargetShow();
			oWordControl.m_oDrawingDocument.UpdateTargetFromPaint = false;

			oWordControl.CheckFontCache();
			oWordControl.m_oDrawingDocument.CheckTrackTable();
		}
		oWordControl.m_oDrawingDocument.Collaborative_TargetsUpdate(isRepaint);
	};

	this.UpdateHorRuler = function()
	{
		if (!this.m_bIsRuler)
			return;

		var _left = 0;
		var lPage = this.m_oDrawingDocument.m_lCurrentPage;
		if (0 <= lPage && lPage < this.m_oDrawingDocument.m_lPagesCount)
		{
			_left = this.m_oDrawingDocument.m_arrPages[lPage].drawingPage.left;
		}
		else if (this.m_oDrawingDocument.m_lPagesCount != 0)
		{
			_left = this.m_oDrawingDocument.m_arrPages[this.m_oDrawingDocument.m_lPagesCount - 1].drawingPage.left;
		}
		this.m_oHorRuler.BlitToMain(_left, 0, this.m_oTopRuler_horRuler.HtmlElement);
	};
	this.UpdateVerRuler = function()
	{
		if (!this.m_bIsRuler)
			return;

		var _top  = 0;
		var lPage = this.m_oDrawingDocument.m_lCurrentPage;
		if (0 <= lPage && lPage < this.m_oDrawingDocument.m_lPagesCount)
		{
			_top = this.m_oDrawingDocument.m_arrPages[lPage].drawingPage.top;
		}
		else if (this.m_oDrawingDocument.m_lPagesCount != 0)
		{
			_top = this.m_oDrawingDocument.m_arrPages[this.m_oDrawingDocument.m_lPagesCount - 1].drawingPage.top;
		}
		this.m_oVerRuler.BlitToMain(0, _top, this.m_oLeftRuler_vertRuler.HtmlElement);
	};

	this.SetCurrentPage  = function(isNoUpdateRulers)
	{
		var drDoc = this.m_oDrawingDocument;

		if (isNoUpdateRulers === undefined)
		{
			if (0 <= drDoc.m_lCurrentPage && drDoc.m_lCurrentPage < drDoc.m_lPagesCount)
			{
				this.m_oHorRuler.CreateBackground(drDoc.m_arrPages[drDoc.m_lCurrentPage]);
				this.m_oVerRuler.CreateBackground(drDoc.m_arrPages[drDoc.m_lCurrentPage]);

				this.m_oHorRuler.IsCanMoveMargins = true;
				this.m_oVerRuler.IsCanMoveMargins = true;
			}
		}

		this.m_bIsUpdateHorRuler = true;
		this.m_bIsUpdateVerRuler = true;

		this.OnScroll();

		this.m_oApi.sync_currentPageCallback(drDoc.m_lCurrentPage);
	};
	this.SetCurrentPage2 = function()
	{
		var drDoc = this.m_oDrawingDocument;
		if (0 <= drDoc.m_lCurrentPage && drDoc.m_lCurrentPage < drDoc.m_lPagesCount)
		{
			this.m_oHorRuler.CreateBackground(drDoc.m_arrPages[drDoc.m_lCurrentPage]);
			this.m_oVerRuler.CreateBackground(drDoc.m_arrPages[drDoc.m_lCurrentPage]);
		}

		this.m_bIsUpdateHorRuler = true;
		this.m_bIsUpdateVerRuler = true;

		this.m_oApi.sync_currentPageCallback(drDoc.m_lCurrentPage);
	};

	this.UpdateHorRulerBack = function(isattack)
	{
		var drDoc = this.m_oDrawingDocument;
		if (0 <= drDoc.m_lCurrentPage && drDoc.m_lCurrentPage < drDoc.m_lPagesCount)
		{
			this.m_oHorRuler.CreateBackground(drDoc.m_arrPages[drDoc.m_lCurrentPage], isattack);
		}
		this.UpdateHorRuler();
	};
	this.UpdateVerRulerBack = function(isattack)
	{
		var drDoc = this.m_oDrawingDocument;
		if (0 <= drDoc.m_lCurrentPage && drDoc.m_lCurrentPage < drDoc.m_lPagesCount)
		{
			this.m_oVerRuler.CreateBackground(drDoc.m_arrPages[drDoc.m_lCurrentPage], isattack);
		}
		this.UpdateVerRuler();
	};

	this.GoToPage = function(lPageNum)
	{
		var drDoc = this.m_oDrawingDocument;
		if (lPageNum < 0 || lPageNum >= drDoc.m_lPagesCount)
			return;

		// сначала вычислим место для скролла
		var dKoef = g_dKoef_mm_to_pix * this.m_nZoomValue / 100;

		var lYPos = 0;
		for (var i = 0; i < lPageNum; i++)
		{
			lYPos += (20 + parseInt(this.m_oDrawingDocument.m_arrPages[i].height_mm * dKoef));
		}

		drDoc.m_lCurrentPage = lPageNum;
		this.m_oHorRuler.CreateBackground(drDoc.m_arrPages[drDoc.m_lCurrentPage]);
		this.m_oVerRuler.CreateBackground(drDoc.m_arrPages[drDoc.m_lCurrentPage]);

		this.m_bIsUpdateHorRuler = true;
		this.m_bIsUpdateVerRuler = true;

		if (this.m_dDocumentHeight > (this.m_oEditor.HtmlElement.height + 10))
		{
			var y = lYPos * this.m_dScrollY_max / (this.m_dDocumentHeight - this.m_oEditor.HtmlElement.height);
			this.m_oScrollVerApi.scrollTo(0, y + 1);
		}

		if (this.m_oApi.isViewMode === false && null != this.m_oLogicDocument)
		{
			if (false === drDoc.IsFreezePage(drDoc.m_lCurrentPage))
			{
				this.m_oLogicDocument.Set_DocPosType(docpostype_Content);
				this.m_oLogicDocument.Set_CurPage(drDoc.m_lCurrentPage);
				this.m_oLogicDocument.MoveCursorToXY(0, 0, false);
				this.m_oLogicDocument.RecalculateCurPos();
				this.m_oLogicDocument.Document_UpdateSelectionState();

				this.m_oApi.sync_currentPageCallback(drDoc.m_lCurrentPage);
			}
		}
		else
		{
			this.m_oApi.sync_currentPageCallback(drDoc.m_lCurrentPage);
		}
	};

	this.GetVerticalScrollTo = function(y, page)
	{
		var dKoef = g_dKoef_mm_to_pix * this.m_nZoomValue / 100;

		var lYPos = 0;
		for (var i = 0; i < page; i++)
		{
			lYPos += (20 + (this.m_oDrawingDocument.m_arrPages[i].height_mm * dKoef + 0.5) >> 0);
		}

		lYPos += y * dKoef;
		return lYPos;
	};

	this.GetHorizontalScrollTo = function(x, page)
	{
		var dKoef = g_dKoef_mm_to_pix * this.m_nZoomValue / 100;
		return 5 + dKoef * x;
	};

	this.GetMainContentBounds = function()
	{
		return this.m_oMainContent.AbsolutePosition;
	};
}

var _message_update = "zero_delay_update";

//------------------------------------------------------------export----------------------------------------------------
window['AscCommon']                      = window['AscCommon'] || {};
window['AscCommonWord']                  = window['AscCommonWord'] || {};
window['AscCommonWord'].GlobalSkinFlat   = GlobalSkinFlat;
window['AscCommonWord'].GlobalSkinFlat2 = GlobalSkinFlat2;
window['AscCommonWord'].GlobalSkin       = GlobalSkin;
window['AscCommonWord'].updateGlobalSkin = updateGlobalSkin;
window['AscCommonWord'].CEditorPage      = CEditorPage;

window['AscCommon'].Page_Width      = Page_Width;
window['AscCommon'].Page_Height     = Page_Height;
window['AscCommon'].X_Left_Margin   = X_Left_Margin;
window['AscCommon'].X_Right_Margin  = X_Right_Margin;
window['AscCommon'].Y_Bottom_Margin = Y_Bottom_Margin;
window['AscCommon'].Y_Top_Margin    = Y_Top_Margin;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
var g_memory = AscFonts.g_memory;
var DecodeBase64Char = AscFonts.DecodeBase64Char;
var b64_decode = AscFonts.b64_decode;

function CPageMeta()
{
    this.width_mm = 0;
    this.height_mm = 0;
    this.start = 0;
    this.end = 0;
}

function CStream(data, size)
{
    this.obj = null;
    this.data = data;
    this.size = size;
    this.pos = 0;
    this.cur = 0;

    this.Seek = function(_pos)
    {
        if (_pos > this.size)
            return 1;
        this.pos = _pos;
        return 0;
    }
    this.Skip = function(_skip)
    {
        if (_skip < 0)
            return 1;
        return this.Seek(this.pos + _skip);
    }

    // 1 bytes
    this.GetUChar = function()
    {
        if (this.pos >= this.size)
            return 0;
        return this.data[this.pos++];
    }
    this.GetChar = function()
    {
        if (this.pos >= this.size)
            return 0;
        var m = this.data[this.pos++];
        if (m > 0x7F)
            m -= 256;
        return m;
    }
    this.GetString = function(len)
    {
        len *= 2;
        if (this.pos + len > this.size)
            return "";
        var t = "";
        for (var i = 0; i < len; i+=2)
        {
            var _c = this.data[this.pos + i + 1] << 8 | this.data[this.pos + i];
            if (_c == 0)
                break;

            t += String.fromCharCode(_c);
        }
        this.pos += len;
        return t;
    }

    this.GetStringA = function(len)
    {
        if (this.pos + len > this.size)
            return "";
        var t = "";
        for (var i = 0; i < len; i++)
        {
            var _c = this.data[this.pos + i];
            if (_c == 0)
                break;

            t += String.fromCharCode(_c);
        }
        this.pos += len;
        return t;
    }

    // 2 byte
    this.GetUShort = function()
    {
        if (this.pos + 1 >= this.size)
            return 0;
        return (this.data[this.pos++] | this.data[this.pos++] << 8);
    }
    this.GetShort = function()
    {
        if (this.pos + 1 >= this.size)
            return 0;
        var _c = (this.data[this.pos++] | this.data[this.pos++] << 8);

        if (_c > 0x7FFF)
            return _c - 65536;
        return _c;
    }

    // 4 byte
    this.GetULong = function()
    {
        if (this.pos + 3 >= this.size)
            return 0;
        var s = (this.data[this.pos++] | this.data[this.pos++] << 8 | this.data[this.pos++] << 16 | this.data[this.pos++] << 24);
        if (s < 0)
            s += (0xFFFFFFFF + 1);
        return s;
    }
    this.GetLong = function()
    {
        // 32-áèòíûå ÷èñëà - ïî óìîë÷àíèþ çíàêîâûå!!!
        return (this.data[this.pos++] | this.data[this.pos++] << 8 | this.data[this.pos++] << 16 | this.data[this.pos++] << 24);
    }

    // double
    this.GetDouble = function()
    {
        return this.GetLong() / 10000;
    }
    this.GetDouble2 = function()
    {
        return this.GetShort() / 100;
    }

    this.SkipImage = function()
    {
        var _type = this.GetUChar();

        switch (_type)
        {
            case 2:
            {
                this.Skip(4);
                break;
            }
            case 3:
            {
                var _lenA = this.GetULong();
                this.Skip(_lenA);
                break;
            }
            case 10:
            case 11:
            {
                this.Skip(44);
                break;
            }
            default:
            {
                this.Skip(20);
                break;
            }
        }
    }
}

function CreateDocumentData(szSrc)
{
    var isBase64 = false;
	if (typeof(szSrc) == "string" || szSrc instanceof String){
		isBase64 = true;
	}

	var stream = null;
	if (!isBase64)
    {
		stream = new CStream(szSrc, szSrc.length);
		return stream;
    }

    var srcLen = szSrc.length;
    var nWritten = 0;

    var index = 0;
    var dst_len = "";
    while (true)
    {
        var _c = szSrc.charCodeAt(index);
        if (_c == ";".charCodeAt(0))
            break;

        dst_len += String.fromCharCode(_c);
        index++;
    }

    index++;
    var dstLen = parseInt(dst_len);

    if (0 == dstLen)
        return null;

    var pointer = g_memory.Alloc(dstLen);
    stream = new CStream(pointer.data, dstLen);
    stream.obj = pointer.obj;

    var dstPx = stream.data;

    if (window.chrome)
    {
        while (index < srcLen)
        {
            var dwCurr = 0;
            var i;
            var nBits = 0;
            for (i=0; i<4; i++)
            {
                if (index >= srcLen)
                    break;
                var nCh = DecodeBase64Char(szSrc.charCodeAt(index++));
                if (nCh == -1)
                {
                    i--;
                    continue;
                }
                dwCurr <<= 6;
                dwCurr |= nCh;
                nBits += 6;
            }

            dwCurr <<= 24-nBits;
            for (i=0; i<nBits/8; i++)
            {
                dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
                dwCurr <<= 8;
            }
        }
    }
    else
    {
        var p = b64_decode;
        while (index < srcLen)
        {
            var dwCurr = 0;
            var i;
            var nBits = 0;
            for (i=0; i<4; i++)
            {
                if (index >= srcLen)
                    break;
                var nCh = p[szSrc.charCodeAt(index++)];
                if (nCh == undefined)
                {
                    i--;
                    continue;
                }
                dwCurr <<= 6;
                dwCurr |= nCh;
                nBits += 6;
            }

            dwCurr <<= 24-nBits;
            for (i=0; i<nBits/8; i++)
            {
                dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
                dwCurr <<= 8;
            }
        }
    }

    return stream;
}

function CDrawingObject(metaDoc)
{
    this.Page = -1;
    this.StreamPos = -1;

    this.BreakDrawing = 0;
    this.Graphics = null;

    this.fontId = -1;
    this.fontSize = -1;
    this.tm_sx = 0;
    this.tm_sy = 0;
    this.tm_shx = 0;
    this.tm_shy = 0;

    this.LastTimeDrawing = -1;

    this.MetaDoc = metaDoc;
}

CDrawingObject.prototype =
{
    CheckOnScroll : function()
    {
        if (-1 == this.LastTimeDrawing)
        {
            this.LastTimeDrawing = new Date().getTime();
            return false;
        }
        var newTime = new Date().getTime();
        if (newTime - this.LastTimeDrawing > 3000) // 3 сек
        {
            this.LastTimeDrawing = newTime;
            return true;
        }
    }
};

function CDocMetaSelection()
{
    this.Page1 = 0;
    this.Line1 = 0;
    this.Glyph1 = 0;

    this.Page2 = 0;
    this.Line2 = 0;
    this.Glyph2 = 0;

    this.IsSelection = false;
}

function CSpan()
{
    this.fontName = 0;
    this.fontSize = 0;

    this.colorR = 0;
    this.colorG = 0;
    this.colorB = 0;

    this.inner = "";

    this.CreateDublicate = function()
    {
        var ret = new CSpan();

        ret.fontName = this.fontName;
        ret.fontSize = this.fontSize;

        ret.colorR = this.colorR;
        ret.colorG = this.colorG;
        ret.colorB = this.colorB;

        ret.inner = this.inner;

        return ret;
    }
}

function CLineInfo()
{
    this.X = 0;
    this.Y = 0;
    this.W = 0;
    this.H = 0;
    this.Ex = 1;
    this.Ey = 0;

    //this.offsets = [];
    this.text = "";
}

function CDocMeta()
{
    this.Fonts = [];
    this.ImageMap = {};

    this.Pages = null;
    this.PagesCount = 0;

    this.LockObject = null;
    this.stream = null;

    this.CountParagraphs = 0;
    this.CountWords = 0;
    this.CountSymbols = 0;
    this.CountSpaces = 0;

    this.Drawings = [];

    this.Selection = new CDocMetaSelection();
    this.TextMatrix = new AscCommon.CMatrix();

    this.SearchInfo =
    {
        Id   : null,
        Page : 0,
        Text : null
    };

    this.SearchResults = {
        IsSearch    : false,
        Text        : "",
        MachingCase : false,
        Pages       : [],
        CurrentPage : -1,
        Current     : -1,
        Show        : false,
        Count       : 0
    };

    this.pagestreams = [];
    this.waitSelectAll = false;

    this.CachedImagesCount = 5;
    this.CachedImages = [];
}

CDocMeta.prototype =
{
    Init : function()
    {
        if (!window["AscDesktopEditor"] || !window["AscDesktopEditor"]["IsNativeViewer"] || !window["AscDesktopEditor"]["IsNativeViewer"]())
            return;

        CDocMeta.prototype.Load = function(url, doc_bin_base64)
        {
            var stream = CreateDocumentData(doc_bin_base64);

            this.PagesCount = stream.GetLong();
            this.Pages = new Array(this.PagesCount);

            this.CountParagraphs = 0;
            this.CountWords = 0;
            this.CountSymbols = 0;
            this.CountSpaces = 0;

            for (var i = 0; i < this.PagesCount; i++)
            {
                var pageInfo = new CPageMeta();
                pageInfo.width_mm = stream.GetDouble();
                pageInfo.height_mm = stream.GetDouble();
                pageInfo.start = 0;
                pageInfo.end = 0;

                this.Pages[i] = pageInfo;
            }

            if (0 == this.PagesCount)
            {
                this.PagesCount = 1;
                this.Pages = new Array(this.PagesCount);

                var pageInfo = new CPageMeta();
                pageInfo.width_mm = 210;
                pageInfo.height_mm = 297;

                this.Pages[0] = pageInfo;
            }

            if (0 != this.Drawings.length)
            {
                this.Drawings.splice(0, this.Drawings.length);
            }

            AscCommon.g_font_loader.LoadEmbeddedFonts("fonts/", this.Fonts);

            var oThis = this;
            setInterval(function() {oThis.NativeDrawTimer();}, 40);
        };

        CDocMeta.prototype.NativeDrawTimer = function()
        {
            var _ret = window["AscDesktopEditor"]["NativeViewerGetCompleteTasks"]();

            var _drDoc = editor.WordControl.m_oDrawingDocument;

            var _current = 0;

            var _countDrawTasks = _ret[_current++];
            var _countTextTasks = _ret[_current++];

            for (var i = 0; i < _countDrawTasks; ++i)
            {
                var _url    = _ret[_current++];
                var _page   = _ret[_current++];
                var _x      = _ret[_current++];
                var _y      = _ret[_current++];

                if (_page >= _drDoc.m_lDrawingFirst && _page <= _drDoc.m_lDrawingEnd)
                {
                    _drDoc.StopRenderingPage(_page);
                    editor.WordControl.OnScroll();
                }
            }

            for (var i = 0; i < _countTextTasks; ++i)
            {
                var _stream = CreateDocumentData(_ret[_current++]);
                var _page = _ret[_current++];
                this.pagestreams[_page] = _stream;
                this.Pages[_page].end   = this.pagestreams[_page] ? this.pagestreams[_page].size : 0;

                this.CountParagraphs    = _ret[_current++];
                this.CountWords         = _ret[_current++];
                this.CountSpaces        = _ret[_current++];
                this.CountSymbols       = _ret[_current++];

                if (_page == (this.PagesCount - 1))
                {
                    this.selectAllCheckEnd();
                }
            }
        };

        CDocMeta.prototype.getStreamPage = function(pageNum)
        {
            return this.pagestreams[pageNum] ? this.pagestreams[pageNum] : new CStream(null, 0);
        };

        CDocMeta.prototype.OnImageLoad = function(obj)
        {
            if (obj.BreakDrawing == 1)
            {
                return;
            }

            var page = this.Pages[obj.Page];
            var g = obj.Graphics;

            g.SetIntegerGrid(true);

            var _url = window["AscDesktopEditor"]["NativeViewerGetPageUrl"](obj.Page, g.m_lWidthPix, g.m_lHeightPix,
                editor.WordControl.m_oDrawingDocument.m_lDrawingFirst, editor.WordControl.m_oDrawingDocument.m_lDrawingEnd);

            if (_url == "")
            {
                // ждем возврата задачи
                return;
            }

            var img = new Image();
            img.onload = function(){
                if (1 != obj.BreakDrawing)
                {
                    var _ctx = g.m_oContext;
                    _ctx.drawImage(img, 0, 0, img.width, img.height);
                }

                // дорисовали страницу. теперь нужно удалить все объекты, у которых страница такая же
                // по идее удаляем только obj
                obj.MetaDoc.stopRenderingPage(obj.Page);
                editor.WordControl.OnScroll();
            };
            img.onerror = function(){
                obj.MetaDoc.stopRenderingPage(obj.Page);
            };
            img.src = "ascdesktop://fonts/" + _url;
        };

        CDocMeta.prototype.selectAllCheckStart = function()
        {
            if (this.pagestreams[this.PagesCount - 1] !== undefined)
            {
                this.waitSelectAll = false;
                return true;
            }

            this.waitSelectAll = true;
            editor.sync_StartAction(window['Asc'].c_oAscAsyncActionType.BlockInteraction, window['Asc'].c_oAscAsyncAction.SlowOperation);
        };

        CDocMeta.prototype.selectAllCheckEnd = function()
        {
            if (this.waitSelectAll)
            {
                this.waitSelectAll = false;
                editor.sync_EndAction(window['Asc'].c_oAscAsyncActionType.BlockInteraction, window['Asc'].c_oAscAsyncAction.SlowOperation);
                this.selectAll();
            }
        };
    },

    Load : function(url, doc_bin_base64)
    {
        var stream = CreateDocumentData(doc_bin_base64);

        this.PagesCount = stream.GetLong();
        this.Pages = new Array(this.PagesCount);

        this.CountParagraphs = stream.GetLong();
        this.CountWords = stream.GetLong();
        this.CountSymbols = stream.GetLong();
        this.CountSpaces = stream.GetLong();

        var fontsCount = stream.GetLong();
        for (var i = 0; i < fontsCount; i++)
        {
            this.Fonts[i] = new AscFonts.CFont("font" + i, "embedded" + i, AscFonts.FONT_TYPE_EMBEDDED, "", null);
        }

        for (var i = 0; i < this.PagesCount; i++)
        {
            var pageInfo = new CPageMeta();
            pageInfo.width_mm = stream.GetDouble();
            pageInfo.height_mm = stream.GetDouble();
            pageInfo.start = stream.GetLong();
            pageInfo.end = stream.GetLong();

            this.Pages[i] = pageInfo;
        }

        if (0 == this.PagesCount)
        {
            this.PagesCount = 1;
            this.Pages = new Array(this.PagesCount);

            var pageInfo = new CPageMeta();
            pageInfo.width_mm = 210;
            pageInfo.height_mm = 297;
            pageInfo.start = 0;
            pageInfo.end = 0;

            this.Pages[0] = pageInfo;
        }

        this.stream = stream;

        if (0 != this.Drawings.length)
        {
            this.Drawings.splice(0, this.Drawings.length);
        }

        AscCommon.g_font_loader.LoadEmbeddedFonts("fonts/", this.Fonts);
    },

    InitDocument : function(drDoc)
    {
        drDoc.m_arrPages = [];
        drDoc.m_lPagesCount = 0;

        for (var i = 0; i < this.PagesCount; i++)
        {
            var _page = new AscCommon.CPage();
            _page.width_mm = this.Pages[i].width_mm;
            _page.height_mm = this.Pages[i].height_mm;
            _page.pageIndex = i;
            drDoc.m_arrPages[i] = _page;
        }

        drDoc.m_lCurrentPage = 0;
        drDoc.m_lPagesCount = this.PagesCount;
        drDoc.m_lCountCalculatePages = this.PagesCount;

        this.SearchResults.Pages = new Array(this.PagesCount);
        for (var i = 0; i < this.PagesCount; i++)
        {
            this.SearchResults.Pages[i] = [];
        }

        editor.sync_countPagesCallback(this.PagesCount);
        editor.sync_currentPageCallback(0);
    },

    drawPage : function(pageIndex, g)
    {
        // если пришла отрисовка - то точно надо перерисовать (изменился размер)
		this.stopRenderingPage(pageIndex);

        var drObject = new CDrawingObject(this);
        drObject.Page = pageIndex;
        drObject.StreamPos = this.Pages[pageIndex].start;
        drObject.Graphics = g;

        this.Drawings[this.Drawings.length] = drObject;
		this.OnImageLoad(drObject);
    },

    stopRenderingPage : function(pageIndex)
    {
        for (var i = 0; i < this.Drawings.length; i++)
        {
            if (pageIndex == this.Drawings[i].Page)
            {
                this.Drawings[i].BreakDrawing = 1;

                if (this.Drawings[i].Graphics.IsClipContext)
                {
                    this.Drawings[i].Graphics.m_oContext.restore();
                    this.Drawings[i].Graphics.IsClipContext = false;
                }

                this.Drawings.splice(i, 1);
                i--;
            }
        }
    },

    getStreamPage : function(pageNum)
    {
        return this.stream;
    },

    OnImageLoad : function(obj)
    {
        if (obj.BreakDrawing == 1)
        {
            return;
        }

        var page = this.Pages[obj.Page];
        var s = this.getStreamPage(obj.Page);
        s.Seek(obj.StreamPos);
        var g = obj.Graphics;

        g.SetIntegerGrid(false);

        // textline parameters
        var _lineX = 0;
        var _lineY = 0;
        var _lineEx = 0;
        var _lineEy = 0;
        var _lineAscent = 0;
        var _lineDescent = 0;
        var _lineWidth = 0;
        var _lineGidExist = false;
        var _linePrevCharX = 0;
        var _lineCharCount = 0;

        if (obj.fontId != -1)
        {
            // все для того, чтобы не лочить отрисовку страниц. с этим ифом - отрисовка полностью параллельна
            g.font("font" + obj.fontId, obj.fontSize);
        }

        var bIsFromPaint = (this.Pages[obj.Page].start == obj.StreamPos) ? 1 : 0;
        if (bIsFromPaint)
        {
            // default colors: black!!!
            g.b_color1(0, 0, 0, 255);
            g.p_color(0, 0, 0, 255);
        }

        if (obj.CheckOnScroll() && 0 == bIsFromPaint)
            editor.WordControl.OnScroll();

        var _cachedImage = null;

        while (s.pos < page.end)
        {
            var command = s.GetUChar();

            switch (command)
            {
                case 41:
                {
                    var fontId = s.GetLong();
                    var font = "font" + fontId;
                    var style = s.GetLong();
                    var size = s.GetDouble();

                    var m = g.m_oTransform;
                    g.font(font, size);

                    obj.fontId = fontId;
                    obj.fontSize = size;
                    obj.tm_sx = m.sx;
                    obj.tm_sy = m.sy;
                    obj.tm_shx = m.shx;
                    obj.tm_shy = m.shy;

                    break;
                }
                case 22:
                {
                    g.b_color1(s.GetUChar(), s.GetUChar(), s.GetUChar(), s.GetUChar());
                    break;
                }
                case 1:
                {
                    g.p_color(s.GetUChar(), s.GetUChar(), s.GetUChar(), s.GetUChar());
                    break;
                }
                case 3:
                {
                    g.p_width(s.GetDouble() * 1000);
                    break;
                }
                case 131:
                {
                    g.transform(1,0,0,1,0,0);
                    break;
                }
                case 130:
                {
                    g.transform(s.GetDouble(), s.GetDouble(), s.GetDouble(), s.GetDouble(), s.GetDouble(), s.GetDouble());
                    break;
                }
                case 80:
                {
                    /*
                    var gid = s.GetUShort();
                    var _char = s.GetUShort();
					if (0xFFFF == gid)
						g.FillText(s.GetDouble(), s.GetDouble(), String.fromCharCode(_char));
					else
						g.tg(gid, s.GetDouble(), s.GetDouble());
				    */
                    if (0 != _lineCharCount)
                        _linePrevCharX += s.GetDouble2();
                    _lineCharCount++;

                    var _char = s.GetUShort();
                    var _gid = (_lineGidExist === true) ? s.GetUShort() : 0xFFFF;

                    if (_char == 0xFFFF)
                    {
                        s.Skip(2);
                        break;
                    }

                    var __x = 0;
                    var __y = 0;
                    var m1 = g.m_oTransform.sx;
                    var m2 = g.m_oTransform.shx;
                    var m3 = g.m_oTransform.shy;
                    var m4 = g.m_oTransform.sy;

                    var det1 = m1 * m4 - m2 * m3;
                    if (det1 == 0)
                        det1 = 0.01;

                    var xDst = _lineX + _linePrevCharX * _lineEx;
                    var yDst = _lineY + _linePrevCharX * _lineEy;

                    __x = (m4 * xDst - m2 * yDst) / det1;
                    __y = (m1 * yDst - m3 * xDst) / det1;

                    if (0xFFFF == _gid)
                        g.FillText(__x, __y, String.fromCharCode(_char));
                    else
                        g.tg(_gid, __x, __y);

                    s.Skip(2);

                    break;
                }
                case 98:
                case 100:
                {
                    // beginpath
                    g._s();
                    break;
                }
                case 91:
                {
                    // moveto
                    //s.Skip(2 * 4);
                    g._m(s.GetDouble(), s.GetDouble());
                    break;
                }
                case 92:
                {
                    // lineto
                    //s.Skip(2 * 4);
                    g._l(s.GetDouble(), s.GetDouble());
                    break;
                }
                case 94:
                {
                    // curveto
                    //s.Skip(6 * 4);
                    g._c(s.GetDouble(), s.GetDouble(), s.GetDouble(), s.GetDouble(), s.GetDouble(), s.GetDouble());
                    break;
                }
                case 97:
                {
                    g._z();
                    break;
                }
                case 99:
                {
                    // drawpath
                    //s.Skip(4);
                    var type = s.GetLong();
                    if (type > 255)
                        g.df();
                    if ((type & 0xFF) != 0)
                        g.ds();
                    break;
                }
                case 110:
                {
                    // drawImage
                    var _type = s.GetUChar();

                    if (2 == _type)
                    {
                        var _src = AscCommon.g_oDocumentUrls.getImageUrl("image" + s.GetLong() + ".svg");
                        obj.StreamPos = s.pos;

                        _cachedImage = this.GetCachedImage(_src);
                        if (null != _cachedImage)
                        {
							g.drawImage2(_cachedImage, 0, 0, page.width_mm, page.height_mm);
							break;
                        }
                        else
						{
							var img = new Image();
							img.onload = function ()
							{
								obj.MetaDoc.SetCachedImage(_src, img);
								if (1 != obj.BreakDrawing)
								{
									g.drawImage2(img, 0, 0, page.width_mm, page.height_mm);
								}

								obj.MetaDoc.OnImageLoad(obj);
							};
							img.onerror = function ()
							{
								obj.MetaDoc.OnImageLoad(obj);
							};
							img.src = _src;

							return;
						}
                    }
                    else if (3 == _type)
                    {
                        var _lenA = s.GetULong();
                        var _src = "data:image/svg+xml;base64," + s.GetStringA(_lenA);

                        obj.StreamPos = s.pos;

						_cachedImage = this.GetCachedImage(_src);
						if (null != _cachedImage)
						{
							g.drawImage2(_cachedImage, 0, 0, page.width_mm, page.height_mm);
							break;
						}
						else
						{
							var img = new Image();
							img.onload = function ()
							{
								obj.MetaDoc.SetCachedImage(_src, img);
								if (1 != obj.BreakDrawing)
								{
									g.drawImage2(img, 0, 0, page.width_mm, page.height_mm);
								}

								obj.MetaDoc.OnImageLoad(obj);
							};
							img.onerror = function ()
							{
								obj.MetaDoc.OnImageLoad(obj);
							};
							img.src = _src;

							return;
						}
                    }

                    var _src = (0 == _type || 10 == _type) ? AscCommon.g_oDocumentUrls.getImageUrl("image" + s.GetLong() + ".jpg") : AscCommon.g_oDocumentUrls.getImageUrl("image" + s.GetLong() + ".png");

                    var __x = s.GetDouble();
                    var __y = s.GetDouble();
                    var __w = s.GetDouble();
                    var __h = s.GetDouble();

                    var _tr = null;
                    if (10 == _type || 11 == _type)
                    {
                        _tr = new AscCommon.CMatrix();
                        _tr.sx = s.GetDouble();
                        _tr.shy = s.GetDouble();
                        _tr.shx = s.GetDouble();
                        _tr.sy = s.GetDouble();
                        _tr.tx = s.GetDouble();
                        _tr.ty = s.GetDouble();
                    }

                    obj.StreamPos = s.pos;

					_cachedImage = this.GetCachedImage(_src);
					if (null != _cachedImage)
					{
						if (1 != obj.BreakDrawing)
						{
							var _ctx = g.m_oContext;

							if (_tr)
							{
								var _dX = g.m_oCoordTransform.sx;
								var _dY = g.m_oCoordTransform.sy;

								_ctx.save();
								_ctx.setTransform(_tr.sx * _dX, _tr.shy * _dY, _tr.shx * _dX, _tr.sy * _dY, _tr.tx * _dX, _tr.ty * _dY);
							}

							g.drawImage2(_cachedImage,__x,__y,__w,__h);
							//editor.WordControl.OnScroll();

							if (_tr)
							{
								_ctx.restore();
							}
						}
						break;
					}
					else
					{
						var img = new Image();
						img.onload = function ()
						{
							obj.MetaDoc.SetCachedImage(_src, img);
							if (1 != obj.BreakDrawing)
							{
								var _ctx = g.m_oContext;

								if (_tr)
								{
									var _dX = g.m_oCoordTransform.sx;
									var _dY = g.m_oCoordTransform.sy;

									_ctx.save();
									_ctx.setTransform(_tr.sx * _dX, _tr.shy * _dY, _tr.shx * _dX, _tr.sy * _dY, _tr.tx * _dX, _tr.ty * _dY);
								}

								g.drawImage2(img, __x, __y, __w, __h);
								//editor.WordControl.OnScroll();

								if (_tr)
								{
									_ctx.restore();
								}
							}

							obj.MetaDoc.OnImageLoad(obj);
						};
						img.onerror = function ()
						{
							obj.MetaDoc.OnImageLoad(obj);
						};
						img.src = _src;

						return;
					}
					break;
                }
                case 160:
                {
                    // textline
                    _linePrevCharX = 0;
                    _lineCharCount = 0;

                    var mask = s.GetUChar();
                    _lineX = s.GetDouble();
                    _lineY = s.GetDouble();

                    if ((mask & 0x01) != 0)
                    {
                        _lineEx = 1;
                        _lineEy = 0;
                    }
                    else
                    {
                        _lineEx = s.GetDouble();
                        _lineEy = s.GetDouble();
                    }

                    _lineAscent = s.GetDouble();
                    _lineDescent = s.GetDouble();

                    if ((mask & 0x04) != 0)
                        _lineWidth = s.GetDouble();

                    if ((mask & 0x02) != 0)
                        _lineGidExist = true;
                    else
                        _lineGidExist = false;

                    break;
                }
                case 162:
                {
                    // textline end
                    break;
                }
                case 161:
                {
                    // text transform
                    g.transform(s.GetDouble(), s.GetDouble(), s.GetDouble(), s.GetDouble(), 0, 0);
                    break;
                }
                case 163:
                {
                    // text clip rect reset
                    g.TextClipRect = null;
                    break;
                }
                case 164:
                {
                    // text clip rect
                    g.SetTextClipRect(s.GetDouble(), s.GetDouble(), s.GetDouble(), s.GetDouble());
                    break;
                }
                case 121:
                {
                    var _command_type = s.GetLong();
                    if (32 == _command_type)
                    {
                        if (!g.IsClipContext)
                        {
                            g.m_oContext.save();
                        }

                        g.IsClipContext = true;
                    }
                    else if (64 == _command_type && g.IsClipContext)
                    {
                        g.m_oContext.restore();
                        g.IsClipContext = false;
                    }
                    break;
                }
                case 122:
                {
                    var _command_type = s.GetLong();
                    if (32 == _command_type)
                    {
                        // clip
                        g.m_oContext.clip();
                    }
                    break;
                }
                default:
                {
                    s.pos = page.end;
                }
            }
        }

        // дорисовали страницу. теперь нужно удалить все объекты, у которых страница такая же
        // по идее удаляем только obj
        this.stopRenderingPage(obj.Page);

        if (bIsFromPaint == 0)
            editor.WordControl.OnScroll();
    },

    GetNearestPos : function(pageNum, x, y)
    {
        var page = this.Pages[pageNum];
        var s = this.getStreamPage(pageNum);
        s.Seek(page.start);

        // textline parameters
        var _line = -1;
        var _glyph = -1;
        var _minDist = 0xFFFFFF;

        // textline parameters
        var _lineX = 0;
        var _lineY = 0;
        var _lineEx = 0;
        var _lineEy = 0;
        var _lineAscent = 0;
        var _lineDescent = 0;
        var _lineWidth = 0;
        var _lineGidExist = false;
        var _linePrevCharX = 0;
        var _lineCharCount = 0;
        var _lineLastGlyphWidth = 0;
        var _arrayGlyphOffsets = [];

        var _numLine = -1;

        var _lenGls = 0;
        var tmp = 0;

        while (s.pos < page.end)
        {
            var command = s.GetUChar();

            switch (command)
            {
                case 41:
                {
                    s.Skip(12);
                    break;
                }
                case 22:
                {
                    s.Skip(4);
                    break;
                }
                case 1:
                {
                    s.Skip(4);
                    break;
                }
                case 3:
                {
                    s.Skip(4);
                    break;
                }
                case 131:
                {
                    break;
                }
                case 130:
                {
                    s.Skip(24);
                    break;
                }
                case 80:
                {
                    if (0 != _lineCharCount)
                        _linePrevCharX += s.GetDouble2();

                    _arrayGlyphOffsets[_lineCharCount] = _linePrevCharX;

                    _lineCharCount++;

                    if (_lineGidExist)
                        s.Skip(4);
                    else
                        s.Skip(2);

                    if (0 == _lineWidth)
                        _lineLastGlyphWidth = s.GetDouble2();
                    else
                        s.Skip(2);

                    break;
                }
                case 98:
                case 100:
                {
                    break;
                }
                case 91:
                {
                    // moveto
                    s.Skip(8);
                    break;
                }
                case 92:
                {
                    // lineto
                    s.Skip(8);
                    break;
                }
                case 94:
                {
                    // curveto
                    s.Skip(24);break;
                }
                case 97:
                {
                    break;
                }
                case 99:
                {
                    // drawpath
                    s.Skip(4);
                    break;
                }
                case 110:
                {
                    // drawImage
                    s.SkipImage();
                    break;
                }
                case 160:
                {
                    // textline
                    _linePrevCharX = 0;
                    _lineCharCount = 0;
                    _lineWidth = 0;

                    _arrayGlyphOffsets.splice(0, _arrayGlyphOffsets.length);

                    ++_numLine;

                    var mask = s.GetUChar();
                    _lineX = s.GetDouble();
                    _lineY = s.GetDouble();

                    if ((mask & 0x01) != 0)
                    {
                        _lineEx = 1;
                        _lineEy = 0;
                    }
                    else
                    {
                        _lineEx = s.GetDouble();
                        _lineEy = s.GetDouble();
                    }

                    _lineAscent = s.GetDouble();
                    _lineDescent = s.GetDouble();

                    if ((mask & 0x04) != 0)
                        _lineWidth = s.GetDouble();

                    if ((mask & 0x02) != 0)
                        _lineGidExist = true;
                    else
                        _lineGidExist = false;

                    break;
                }
                case 162:
                {
                    // textline end

                    // âñå ïîäñ÷èòàíî
                    if (0 == _lineWidth)
                        _lineWidth = _linePrevCharX + _lineLastGlyphWidth;

                    // â ïðèíöèïå êîä îäèí è òîò æå. Íî ïî÷òè âñåãäà ëèíèè ãîðèçîíòàëüíûå.
                    // à äëÿ ãîðèçîíòàëüíîé ëèíèè âñå ìîæíî ïîîïòèìèçèðîâàòü
                    if (_lineEx == 1 && _lineEy == 0)
                    {
                        var _distX = x - _lineX;
                        if (y >= (_lineY - _lineAscent) && y <= (_lineY + _lineDescent) && _distX >= 0 && _distX <= _lineWidth)
                        {
                            // ïîïàëè âíóòðü ëèíèè. Òåïåðü íóæíî íàéòè ãëèô
                            _line = _numLine;

                            _lenGls = _arrayGlyphOffsets.length;
                            for (_glyph = 0; _glyph < _lenGls; _glyph++)
                            {
                                if (_arrayGlyphOffsets[_glyph] > _distX)
                                    break;
                            }
                            if (_glyph > 0)
                                --_glyph;

                            return { Line : _line, Glyph : _glyph };
                        }

                        if (_distX >= 0 && _distX <= _lineWidth)
                            tmp = Math.abs(y - _lineY);
                        else if (_distX < 0)
                        {
                            tmp = Math.sqrt((x - _lineX) * (x - _lineX) + (y - _lineY) * (y - _lineY));
                        }
                        else
                        {
                            var _xx1 = _lineX + _lineWidth;
                            tmp = Math.sqrt((x - _xx1) * (x - _xx1) + (y - _lineY) * (y - _lineY));
                        }

                        if (tmp < _minDist)
                        {
                            _minDist = tmp;
                            _line = _numLine;

                            if (_distX < 0)
                                _glyph = -2;
                            else if (_distX > _lineWidth)
                            {
                                _glyph = -1;
                            }
                            else
                            {
                                _lenGls = _arrayGlyphOffsets.length;
                                for (_glyph = 0; _glyph < _lenGls; _glyph++)
                                {
                                    if (_arrayGlyphOffsets[_glyph] > _distX)
                                        break;
                                }

                                if (_glyph > 0)
                                    _glyph--;
                            }
                        }

                        // Íè÷åãî íå íàäî äåëàòü, óæå íàéäåíà áîëåå "áëèæíÿÿ" ëèíèÿ
                    }
                    else
                    {
                        // îïðåäåëÿåì òî÷êè descent ëèíèè
                        var ortX = -_lineEy;
                        var ortY = _lineEx;

                        var _dx = _lineX + ortX * _lineDescent;
                        var _dy = _lineY + ortY * _lineDescent;

                        // òåïåðü ïðîåêöèè (ñî çíàêîì) íà ëèíèþ descent
                        var h = -((x - _dx) * ortX + (y - _dy) * ortY);
                        var w = (x - _dx) * _lineEx + (y - _dy) * _lineEy;

                        if (w >= 0 && w <= _lineWidth && h >= 0 && h <= (_lineDescent + _lineAscent))
                        {
                            // ïîïàëè âíóòðü ëèíèè. Òåïåðü íóæíî íàéòè ãëèô
                            _line = _numLine;

                            _lenGls = _arrayGlyphOffsets.length;
                            for (_glyph = 0; _glyph < _lenGls; _glyph++)
                            {
                                if (_arrayGlyphOffsets[_glyph] > w)
                                    break;
                            }

                            if (_glyph > 0)
                                _glyph--;

                            return { Line : _line, Glyph : _glyph };
                        }

                        if (w >= 0 && w <= _lineWidth)
                            tmp = Math.abs(h - _lineDescent);
                        else if (w < 0)
                        {
                            tmp = Math.sqrt((x - _lineX) * (x - _lineX) + (y - _lineY) * (y - _lineY));
                        }
                        else
                        {
                            var _tmpX = _lineX + _lineWidth * _lineEx;
                            var _tmpY = _lineY + _lineWidth * _lineEy;
                            tmp = Math.sqrt((x - _tmpX) * (x - _tmpX) + (y - _tmpY) * (y - _tmpY));
                        }

                        //tmp = Math.abs(h - _lineDescent);
                        if (tmp < _minDist)
                        {
                            _minDist = tmp;
                            _line = _numLine;

                            if (w < 0)
                                _glyph = -2;
                            else if (w > _lineWidth)
                                _glyph = -1;
                            else
                            {
                                _lenGls = _arrayGlyphOffsets.length;
                                for (_glyph = 0; _glyph < _lenGls; _glyph++)
                                {
                                    if (_arrayGlyphOffsets[_glyph] > w)
                                        break;
                                }

                                if (_glyph > 0)
                                    _glyph--;
                            }
                        }

                        // Íè÷åãî íå íàäî äåëàòü, óæå íàéäåíà áîëåå "áëèæíÿÿ" ëèíèÿ
                    }

                    break;
                }
                case 161:
                {
                    // text transform
                    s.Skip(16);
                    break;
                }
                case 163:
                {
                    break;
                }
                case 164:
                {
                    s.Skip(16);
                    break;
                }
                case 121:
                case 122:
                {
                    // begin/end command
                    s.Skip(4);
                    break;
                }
                default:
                {
                    s.pos = page.end;
                }
            }
        }

        return { Line : _line, Glyph : _glyph };
    },

    GetCountLines : function(pageNum)
    {
        var page = this.Pages[pageNum];
        var s = this.getStreamPage(pageNum);
        s.Seek(page.start);

        var _lineGidExist = false;
        var _lineCharCount = 0;
        var _numLine = -1;

        while (s.pos < page.end)
        {
            var command = s.GetUChar();

            switch (command)
            {
                case 41:
                {
                    s.Skip(12);
                    break;
                }
                case 22:
                {
                    s.Skip(4);
                    break;
                }
                case 1:
                {
                    s.Skip(4);
                    break;
                }
                case 3:
                {
                    s.Skip(4);
                    break;
                }
                case 131:
                {
                    break;
                }
                case 130:
                {
                    s.Skip(24);
                    break;
                }
                case 80:
                {
                    if (0 != _lineCharCount)
                        s.Skip(2);

                    _lineCharCount++;

                    if (_lineGidExist)
                        s.Skip(4);
                    else
                        s.Skip(2);

                    s.Skip(2);

                    break;
                }
                case 98:
                case 100:
                {
                    break;
                }
                case 91:
                {
                    // moveto
                    s.Skip(8);
                    break;
                }
                case 92:
                {
                    // lineto
                    s.Skip(8);
                    break;
                }
                case 94:
                {
                    // curveto
                    s.Skip(24);break;
                }
                case 97:
                {
                    break;
                }
                case 99:
                {
                    // drawpath
                    s.Skip(4);
                    break;
                }
                case 110:
                {
                    // drawImage
                    s.SkipImage();
                    break;
                }
                case 160:
                {
                    // textline
                    _lineCharCount = 0;
                    ++_numLine;

                    var mask = s.GetUChar();
                    s.Skip(8);

                    if ((mask & 0x01) == 0)
                        s.Skip(8);

                    s.Skip(8);

                    if ((mask & 0x04) != 0)
                        s.Skip(4);

                    if ((mask & 0x02) != 0)
                        _lineGidExist = true;
                    else
                        _lineGidExist = false;

                    break;
                }
                case 162:
                {
                    break;
                }
                case 161:
                {
                    // text transform
                    s.Skip(16);
                    break;
                }
                case 163:
                {
                    break;
                }
                case 164:
                {
                    s.Skip(16);
                    break;
                }
                case 121:
                case 122:
                {
                    // begin/end command
                    s.Skip(4);
                    break;
                }
                default:
                {
                    s.pos = page.end;
                }
            }
        }

        return _numLine;
    },

    DrawSelection : function(pageNum, overlay, xDst, yDst, width, height)
    {
        var sel = this.Selection;
        var Page1 = 0;
        var Page2 = 0;
        var Line1 = 0;
        var Line2 = 0;
        var Glyph1 = 0;
        var Glyph2 = 0;

        if (sel.Page2 > sel.Page1)
        {
            Page1 = sel.Page1;
            Page2 = sel.Page2;
            Line1 = sel.Line1;
            Line2 = sel.Line2;
            Glyph1 = sel.Glyph1;
            Glyph2 = sel.Glyph2;
        }
        else if (sel.Page2 < sel.Page1)
        {
            Page1 = sel.Page2;
            Page2 = sel.Page1;
            Line1 = sel.Line2;
            Line2 = sel.Line1;
            Glyph1 = sel.Glyph2;
            Glyph2 = sel.Glyph1;
        }
        else if (sel.Page1 == sel.Page2)
        {
            Page1 = sel.Page1;
            Page2 = sel.Page2;

            if (sel.Line1 < sel.Line2)
            {
                Line1 = sel.Line1;
                Line2 = sel.Line2;
                Glyph1 = sel.Glyph1;
                Glyph2 = sel.Glyph2;
            }
            else if (sel.Line2 < sel.Line1)
            {
                Line1 = sel.Line2;
                Line2 = sel.Line1;
                Glyph1 = sel.Glyph2;
                Glyph2 = sel.Glyph1;
            }
            else
            {
                Line1 = sel.Line1;
                Line2 = sel.Line2;

                if (-1 == sel.Glyph1)
                {
                    Glyph1 = sel.Glyph2;
                    Glyph2 = sel.Glyph1;
                }
                else if (-1 == sel.Glyph2)
                {
                    Glyph1 = sel.Glyph1;
                    Glyph2 = sel.Glyph2;
                }
                else if (sel.Glyph1 < sel.Glyph2)
                {
                    Glyph1 = sel.Glyph1;
                    Glyph2 = sel.Glyph2;
                }
                else
                {
                    Glyph1 = sel.Glyph2;
                    Glyph2 = sel.Glyph1;
                }
            }
        }

        if (Page1 > pageNum  || Page2 < pageNum)
            return;

        if (Page1 < pageNum)
        {
            Page1 = pageNum;
            Line1 = 0;
            Glyph1 = -2;
        }
        var bIsFillToEnd = false;
        if (Page2 > pageNum)
            bIsFillToEnd = true;

        var page = this.Pages[pageNum];
        var s = this.getStreamPage(pageNum);
        s.Seek(page.start);

        // textline parameters
        var _lineX = 0;
        var _lineY = 0;
        var _lineEx = 0;
        var _lineEy = 0;
        var _lineAscent = 0;
        var _lineDescent = 0;
        var _lineWidth = 0;
        var _lineGidExist = false;
        var _linePrevCharX = 0;
        var _lineCharCount = 0;
        var _lineLastGlyphWidth = 0;
        var _arrayGlyphOffsets = [];

        var _numLine = -1;

        var dKoefX = width / page.width_mm;
        var dKoefY = height / page.height_mm;

        while (s.pos < page.end)
        {
            var command = s.GetUChar();

            switch (command)
            {
                case 41:
                {
                    s.Skip(12);
                    break;
                }
                case 22:
                {
                    s.Skip(4);
                    break;
                }
                case 1:
                {
                    s.Skip(4);
                    break;
                }
                case 3:
                {
                    s.Skip(4);
                    break;
                }
                case 131:
                {
                    break;
                }
                case 130:
                {
                    s.Skip(24);
                    break;
                }
                case 80:
                {
                    if (0 != _lineCharCount)
                        _linePrevCharX += s.GetDouble2();

                    _arrayGlyphOffsets[_lineCharCount] = _linePrevCharX;

                    _lineCharCount++;

                    if (_lineGidExist)
                        s.Skip(4);
                    else
                        s.Skip(2);

                    if (0 == _lineWidth)
                        _lineLastGlyphWidth = s.GetDouble2();
                    else
                        s.Skip(2);

                    break;
                }
                case 98:
                case 100:
                {
                    break;
                }
                case 91:
                {
                    // moveto
                    s.Skip(8);
                    break;
                }
                case 92:
                {
                    // lineto
                    s.Skip(8);
                    break;
                }
                case 94:
                {
                    // curveto
                    s.Skip(24);break;
                }
                case 97:
                {
                    break;
                }
                case 99:
                {
                    // drawpath
                    s.Skip(4);
                    break;
                }
                case 110:
                {
                    // drawImage
                    s.SkipImage();
                    break;
                }
                case 160:
                {
                    // textline
                    _linePrevCharX = 0;
                    _lineCharCount = 0;
                    _lineWidth = 0;

                    _arrayGlyphOffsets.splice(0, _arrayGlyphOffsets.length);

                    ++_numLine;

                    var mask = s.GetUChar();
                    _lineX = s.GetDouble();
                    _lineY = s.GetDouble();

                    if ((mask & 0x01) != 0)
                    {
                        _lineEx = 1;
                        _lineEy = 0;
                    }
                    else
                    {
                        _lineEx = s.GetDouble();
                        _lineEy = s.GetDouble();
                    }

                    _lineAscent = s.GetDouble();
                    _lineDescent = s.GetDouble();

                    if ((mask & 0x04) != 0)
                        _lineWidth = s.GetDouble();

                    if ((mask & 0x02) != 0)
                        _lineGidExist = true;
                    else
                        _lineGidExist = false;

                    break;
                }
                case 162:
                {
                    // textline end
                    var off1 = 0;
                    var off2 = 0;

                    if (_numLine < Line1)
                        break;
                    if (_numLine > Line2 && !bIsFillToEnd)
                        return;

                    // âñå ïîäñ÷èòàíî
                    if (0 == _lineWidth)
                        _lineWidth = _linePrevCharX + _lineLastGlyphWidth;

                    if (Line1 == _numLine)
                    {
                        if (-2 == Glyph1)
                            off1 = 0;
                        else if (-1 == Glyph1)
                            off1 = _lineWidth;
                        else
                            off1 = _arrayGlyphOffsets[Glyph1];
                    }
                    if (bIsFillToEnd || Line2 != _numLine)
                        off2 = _lineWidth;
                    else
                    {
                        if (Glyph2 == -2)
                            off2 = 0;
                        else if (Glyph2 == -1)
                            off2 = _lineWidth;
                        else
                        {
                            off2 = _arrayGlyphOffsets[Glyph2];
                            /*
                            if (Glyph2 >= (_arrayGlyphOffsets.length - 1))
                                off2 = _lineWidth;
                            else
                                off2 = _arrayGlyphOffsets[Glyph2 + 1];
                            */
                        }
                    }

                    if (off2 <= off1)
                        break;

                    // â ïðèíöèïå êîä îäèí è òîò æå. Íî ïî÷òè âñåãäà ëèíèè ãîðèçîíòàëüíûå.
                    // à äëÿ ãîðèçîíòàëüíîé ëèíèè âñå ìîæíî ïîîïòèìèçèðîâàòü
                    if (_lineEx == 1 && _lineEy == 0)
                    {
                        var _x = parseInt(xDst + dKoefX * (_lineX + off1)) - 0.5;
                        var _y = parseInt(yDst + dKoefY * (_lineY - _lineAscent)) - 0.5;

                        var _w = parseInt(dKoefX * (off2 - off1)) + 1;
                        var _h = parseInt(dKoefY * (_lineAscent + _lineDescent)) + 1;

                        if (_x < overlay.min_x)
                            overlay.min_x = _x;
                        if ((_x + _w) > overlay.max_x)
                            overlay.max_x = _x + _w;

                        if (_y < overlay.min_y)
                            overlay.min_y = _y;
                        if ((_y + _h) > overlay.max_y)
                            overlay.max_y = _y + _h;

                        overlay.m_oContext.rect(_x,_y,_w,_h);
                    }
                    else
                    {
                        // îïðåäåëÿåì òî÷êè descent ëèíèè
                        var ortX = -_lineEy;
                        var ortY = _lineEx;

                        var _dx = _lineX + ortX * _lineDescent;
                        var _dy = _lineY + ortY * _lineDescent;

                        var _x1 = _dx + off1 * _lineEx;
                        var _y1 = _dy + off1 * _lineEy;

                        var _x2 = _x1 - ortX * (_lineAscent + _lineDescent);
                        var _y2 = _y1 - ortY * (_lineAscent + _lineDescent);

                        var _x3 = _x2 + (off2 - off1) * _lineEx;
                        var _y3 = _y2 + (off2 - off1) * _lineEy;

                        var _x4 = _x3 + ortX * (_lineAscent + _lineDescent);
                        var _y4 = _y3 + ortY * (_lineAscent + _lineDescent);

                        _x1 = xDst + dKoefX * _x1;
                        _x2 = xDst + dKoefX * _x2;
                        _x3 = xDst + dKoefX * _x3;
                        _x4 = xDst + dKoefX * _x4;

                        _y1 = yDst + dKoefY * _y1;
                        _y2 = yDst + dKoefY * _y2;
                        _y3 = yDst + dKoefY * _y3;
                        _y4 = yDst + dKoefY * _y4;

                        overlay.CheckPoint(_x1, _y1);
                        overlay.CheckPoint(_x2, _y2);
                        overlay.CheckPoint(_x3, _y3);
                        overlay.CheckPoint(_x4, _y4);

                        var ctx = overlay.m_oContext;
                        ctx.moveTo(_x1, _y1);
                        ctx.lineTo(_x2, _y2);
                        ctx.lineTo(_x3, _y3);
                        ctx.lineTo(_x4, _y4);
                        ctx.closePath();
                    }

                    break;
                }
                case 161:
                {
                    // text transform
                    s.Skip(16);
                    break;
                }
                case 163:
                {
                    break;
                }
                case 164:
                {
                    s.Skip(16);
                    break;
                }
                case 121:
                case 122:
                {
                    // begin/end command
                    s.Skip(4);
                    break;
                }
                default:
                {
                    s.pos = page.end;
                }
            }
        }
    },

    CopySelection : function(pageNum, _text_format)
    {
        var ret = "";

        var sel = this.Selection;
        var Page1 = 0;
        var Page2 = 0;
        var Line1 = 0;
        var Line2 = 0;
        var Glyph1 = 0;
        var Glyph2 = 0;

        if (sel.Page2 > sel.Page1)
        {
            Page1 = sel.Page1;
            Page2 = sel.Page2;
            Line1 = sel.Line1;
            Line2 = sel.Line2;
            Glyph1 = sel.Glyph1;
            Glyph2 = sel.Glyph2;
        }
        else if (sel.Page2 < sel.Page1)
        {
            Page1 = sel.Page2;
            Page2 = sel.Page1;
            Line1 = sel.Line2;
            Line2 = sel.Line1;
            Glyph1 = sel.Glyph2;
            Glyph2 = sel.Glyph1;
        }
        else if (sel.Page1 == sel.Page2)
        {
            Page1 = sel.Page1;
            Page2 = sel.Page2;

            if (sel.Line1 < sel.Line2)
            {
                Line1 = sel.Line1;
                Line2 = sel.Line2;
                Glyph1 = sel.Glyph1;
                Glyph2 = sel.Glyph2;
            }
            else if (sel.Line2 < sel.Line1)
            {
                Line1 = sel.Line2;
                Line2 = sel.Line1;
                Glyph1 = sel.Glyph2;
                Glyph2 = sel.Glyph1;
            }
            else
            {
                Line1 = sel.Line1;
                Line2 = sel.Line2;

                if (((sel.Glyph1 != -1) && (sel.Glyph1 < sel.Glyph2)) || (-1 == sel.Glyph2))
                {
                    Glyph1 = sel.Glyph1;
                    Glyph2 = sel.Glyph2;
                }
                else
                {
                    Glyph1 = sel.Glyph2;
                    Glyph2 = sel.Glyph1;
                }
            }
        }

        if (Page1 > pageNum  || Page2 < pageNum)
            return;

        if (Page1 < pageNum)
        {
            Page1 = pageNum;
            Line1 = 0;
            Glyph1 = -2;
        }
        var bIsFillToEnd = false;
        if (Page2 > pageNum)
            bIsFillToEnd = true;


        var page = this.Pages[pageNum];
        var s = this.getStreamPage(pageNum);
        s.Seek(page.start);

        var lineSpans = [];
        var curSpan = new CSpan();
        var isChangeSpan = false;

        var _lineCharCount = 0;
        var _lineGidExist = false;

        var _numLine = -1;

        while (s.pos < page.end)
        {
            var command = s.GetUChar();

            switch (command)
            {
                case 41:
                {
                    curSpan.fontName = s.GetULong();
                    s.Skip(4);
                    curSpan.fontSize = s.GetDouble();
                    isChangeSpan = true;
                    break;
                }
                case 22:
                {
                    curSpan.colorR = s.GetUChar();
                    curSpan.colorG = s.GetUChar();
                    curSpan.colorB = s.GetUChar();
                    s.Skip(1);
                    isChangeSpan = true;
                    break;
                }
                case 1:
                {
                    s.Skip(4);
                    break;
                }
                case 3:
                {
                    s.Skip(4);
                    break;
                }
                case 131:
                {
                    break;
                }
                case 130:
                {
                    s.Skip(24);
                    break;
                }
                case 80:
                {
                    if (0 != _lineCharCount)
                        s.Skip(2);

                    _lineCharCount++;
                    if (isChangeSpan)
                    {
                        lineSpans[lineSpans.length] = curSpan.CreateDublicate();
                    }
                    var sp = lineSpans[lineSpans.length - 1];

                    var _char = s.GetUShort();
                    if (0xFFFF == _char)
                        sp.inner += " ";
                    else
                        sp.inner += String.fromCharCode(_char);

                    if (_lineGidExist)
                        s.Skip(2);

                    s.Skip(2);

                    isChangeSpan = false;
                    break;
                }
                case 98:
                case 100:
                {
                    break;
                }
                case 91:
                {
                    // moveto
                    s.Skip(8);
                    break;
                }
                case 92:
                {
                    // lineto
                    s.Skip(8);
                    break;
                }
                case 94:
                {
                    // curveto
                    s.Skip(24);break;
                }
                case 97:
                {
                    break;
                }
                case 99:
                {
                    // drawpath
                    s.Skip(4);
                    break;
                }
                case 110:
                {
                    // drawImage
                    s.SkipImage();
                    break;
                }
                case 160:
                {
                    // textline
                    isChangeSpan = true;
                    lineSpans.splice(0, lineSpans.length);
                    _lineCharCount = 0;
                    ++_numLine;

                    var mask = s.GetUChar();
                    s.Skip(8);

                    if ((mask & 0x01) == 0)
                    {
                        s.Skip(8);
                    }

                    s.Skip(8);

                    if ((mask & 0x04) != 0)
                        s.Skip(4);

                    if ((mask & 0x02) != 0)
                        _lineGidExist = true;
                    else
                        _lineGidExist = false;

                    break;
                }
                case 162:
                {
                    // textline end
                    // ñïàíû íàáèòû. òåïåðü íóæíî ñôîðìèðîâàòü ëèíèþ è ñãåíåðèðîâàòü íóæíóþ ñòðîêó.
                    if (Line1 <= _numLine && ((!bIsFillToEnd && Line2 >= _numLine) || bIsFillToEnd))
                    {
                        var _g1 = -2;
                        var _g2 = -1;
                        if (Line1 == _numLine)
                        {
                            _g1 = Glyph1;
                        }
                        if (bIsFillToEnd || Line2 != _numLine)
                        {
                            _g2 = -1;
                        }
                        else
                        {
                            _g2 = Glyph2;
                        }

                        if (_g1 != -1 && _g2 != -2)
                        {
                            var textLine = "<p>";

                            if (-2 == _g1 && -1 == _g2)
                            {
                                var countSpans = lineSpans.length;
                                for (var i = 0; i < countSpans; i++)
                                {
                                    textLine += "<span>";
                                    textLine += lineSpans[i].inner;
                                    textLine += "</span>";

                                    if (_text_format)
                                        _text_format.Text += lineSpans[i].inner;
                                }
                            }
                            else
                            {
                                var curIndex = 0;
                                var countSpans = lineSpans.length;
                                for (var i = 0; i < countSpans; i++)
                                {
                                    var old = curIndex;
                                    var start = curIndex;
                                    var end = start + lineSpans[i].inner.length;
                                    curIndex = end + 1;

                                    if (_g1 > start)
                                        start = _g1;
                                    if (_g2 != -1 && _g2 < end)
                                        end = _g2;

                                    if (start > end)
                                        continue;

                                    start -= old;
                                    end -= old;

                                    textLine += "<span>";
                                    textLine += lineSpans[i].inner.substring(start, end);
                                    textLine += "</span>";

                                    if (_text_format)
                                        _text_format.Text += lineSpans[i].inner.substring(start, end);
                                }
                            }

                            textLine += "</p>";

                            if (_text_format)
                                _text_format.Text += "\n";

                            ret += textLine;
                        }
                    }

                    break;
                }
                case 161:
                {
                    // text transform
                    s.Skip(16);
                    break;
                }
                case 163:
                {
                    break;
                }
                case 164:
                {
                    s.Skip(16);
                    break;
                }
                case 121:
                case 122:
                {
                    // begin/end command
                    s.Skip(4);
                    break;
                }
                default:
                {
                    s.pos = page.end;
                }
            }
        }
        return ret;
    },

    SearchPage : function(pageNum, text)
    {
        var page = this.Pages[pageNum];
        var s = this.getStreamPage(pageNum);
        s.Seek(page.start);

        var glyphsEqualFound = 0;
        var glyphsFindCount = text.length;

        if (0 == glyphsFindCount)
            return;

        var _numLine = -1;
        var _lineGidExist = false;
        var _linePrevCharX = 0;
        var _lineCharCount = 0;
        var _lineLastGlyphWidth = 0;

        var _findLine = 0;
        var _findLineOffsetX = 0;
        var _findLineOffsetR = 0;
        var _findGlyphIndex = 0;

        var _SeekToNextPoint = 0;
        var _SeekLinePrevCharX = 0;

        var arrayLines = [];
        var curLine = null;

        while (s.pos < page.end)
        {
            var command = s.GetUChar();

            switch (command)
            {
                case 41:
                {
                    s.Skip(12);
                    break;
                }
                case 22:
                {
                    s.Skip(4);
                    break;
                }
                case 1:
                {
                    s.Skip(4);
                    break;
                }
                case 3:
                {
                    s.Skip(4);
                    break;
                }
                case 131:
                {
                    break;
                }
                case 130:
                {
                    s.Skip(24);
                    break;
                }
                case 80:
                {
                    if (0 != _lineCharCount)
                        _linePrevCharX += s.GetDouble2();

                    _lineCharCount++;

                    var _char = s.GetUShort();
                    if (_lineGidExist)
                        s.Skip(2);

                    if (0xFFFF == _char)
                        curLine.text += " ";
                    else
                        curLine.text += String.fromCharCode(_char);

                    if (curLine.W != 0)
                        s.Skip(2);
                    else
                        curLine.W = s.GetDouble2();

                    break;
                }
                case 98:
                case 100:
                {
                    break;
                }
                case 91:
                {
                    // moveto
                    s.Skip(8);
                    break;
                }
                case 92:
                {
                    // lineto
                    s.Skip(8);
                    break;
                }
                case 94:
                {
                    // curveto
                    s.Skip(24);break;
                }
                case 97:
                {
                    break;
                }
                case 99:
                {
                    // drawpath
                    s.Skip(4);
                    break;
                }
                case 110:
                {
                    // drawImage
                    s.SkipImage();
                    break;
                }
                case 160:
                {
                    _linePrevCharX = 0;
                    _lineCharCount = 0;

                    arrayLines[arrayLines.length] = new CLineInfo();
                    curLine = arrayLines[arrayLines.length - 1];

                    var mask = s.GetUChar();
                    curLine.X = s.GetDouble();
                    curLine.Y = s.GetDouble();

                    if ((mask & 0x01) == 1)
                    {
                        var dAscent = s.GetDouble();
                        var dDescent = s.GetDouble();

                        curLine.Y -= dAscent;
                        curLine.H = dAscent + dDescent;
                    }
                    else
                    {
                        curLine.Ex = s.GetDouble();
                        curLine.Ey = s.GetDouble();

                        var dAscent = s.GetDouble();
                        var dDescent = s.GetDouble();

                        curLine.X = curLine.X + dAscent * curLine.Ey;
                        curLine.Y = curLine.Y - dAscent * curLine.Ex;

                        curLine.H = dAscent + dDescent;
                    }

                    if ((mask & 0x04) != 0)
                        curLine.W = s.GetDouble();

                    if ((mask & 0x02) != 0)
                        _lineGidExist = true;
                    else
                        _lineGidExist = false;

                    break;
                }
                case 162:
                {
                    break;
                }
                case 161:
                {
                    // text transform
                    s.Skip(16);
                    break;
                }
                case 163:
                {
                    break;
                }
                case 164:
                {
                    s.Skip(16);
                    break;
                }
                case 121:
                case 122:
                {
                    // begin/end command
                    s.Skip(4);
                    break;
                }
                default:
                {
                    s.pos = page.end;
                }
            }
        }

        // òåêñò çàïîëíåí. òåïåðü íóæíî ïðîñòî ïðîáåãàòüñÿ è ñìîòðåòü
        // îòêóäà ñîâïàäåíèå íà÷àëîñü è ãäå çàêîí÷èëîñü
        _linePrevCharX = 0;
        _lineCharCount = 0;
        _numLine = 0;

        s.Seek(page.start);

        while (s.pos < page.end)
        {
            var command = s.GetUChar();

            switch (command)
            {
                case 41:
                {
                    s.Skip(12);
                    break;
                }
                case 22:
                {
                    s.Skip(4);
                    break;
                }
                case 1:
                {
                    s.Skip(4);
                    break;
                }
                case 3:
                {
                    s.Skip(4);
                    break;
                }
                case 131:
                {
                    break;
                }
                case 130:
                {
                    s.Skip(24);
                    break;
                }
                case 80:
                {
                    if (0 != _lineCharCount)
                        _linePrevCharX += s.GetDouble2();

                    _lineCharCount++;

                    var _char = s.GetUShort();
                    if (_lineGidExist)
                        s.Skip(2);

                    if (0xFFFF == _char)
                        _char = " ".charCodeAt(0);

                    _lineLastGlyphWidth = s.GetDouble2();
                    if (_char == text.charCodeAt(glyphsEqualFound))
                    {
                        if (0 == glyphsEqualFound)
                        {
                            _findLine = _numLine;
                            _findLineOffsetX = _linePrevCharX;
                            _findGlyphIndex = _lineCharCount;

                            _SeekToNextPoint = s.pos;
                            _SeekLinePrevCharX = _linePrevCharX;
                        }

                        glyphsEqualFound++;
                        _findLineOffsetR = _linePrevCharX + _lineLastGlyphWidth;
                        if (glyphsFindCount == glyphsEqualFound)
                        {
                            var _text = "";
                            var _rects = [];
                            for (var i = _findLine; i <= _numLine; i++)
                            {
                                var ps = 0;
                                if (_findLine == i)
                                    ps = _findLineOffsetX;
                                var pe = arrayLines[i].W;
                                if (i == _numLine)
                                    pe = _findLineOffsetR;

                                var _l = arrayLines[i];
                                if (i == _findLine && i == _numLine)
                                {
                                    _text = _l.text.substring(0, _findGlyphIndex - 1);
                                    _text += "<b>";
                                    _text += _l.text.substring(_findGlyphIndex - 1, _lineCharCount);
                                    _text += "</b>";
                                    _text += _l.text.substring(_lineCharCount);
                                }
                                else if (i == _findLine)
                                {
                                    _text = _l.text.substring(0, _findGlyphIndex - 1);
                                    _text += "<b>";
                                    _text += _l.text.substring(_findGlyphIndex - 1);
                                }
                                else if (i == _numLine)
                                {
                                    _text += _l.text.substring(0, _lineCharCount);
                                    _text += "</b>";
                                    _text += _l.text.substring(_lineCharCount);
                                }
                                else
                                {
                                    _text += _l.text;
                                }

                                if (_l.Ex == 1 && _l.Ey == 0)
                                {
                                    _rects[_rects.length] = { PageNum : pageNum, X : _l.X + ps, Y : _l.Y, W : pe - ps, H : _l.H };
                                }
                                else
                                {
                                    _rects[_rects.length] = { PageNum : pageNum, X : _l.X + ps * _l.Ex, Y : _l.Y + ps * _l.Ey, W : pe - ps, H : _l.H, Ex : _l.Ex, Ey : _l.Ey };
                                }
                            }

                            //console.log(_text);
                            editor.WordControl.m_oDrawingDocument.AddPageSearch(_text, _rects, search_Common);

                            /*
                            // âñå íàéäåíî. íóæíî äîáàâèòü ðåêòû
                            if (_findLineEx == 1 && _findLineEy == 0)
                            {
                                var navigator = { Page : pageNum, X: _findLineX + _findLineOffsetX, Y: _findLineY - _findAscent,
                                    W : (_findLineOffsetR - _findLineOffsetX) , H : (_findAscent + _findDescent) };

                                var _find = { text: "", navigator : navigator };
                                editor.WordControl.m_oApi.sync_SearchFoundCallback(_find);

                                var _rect = [];
                                _rect[0] = { PageNum : pageNum, X : navigator.X, Y : navigator.Y, W : navigator.W, H : navigator.H };
                                editor.WordControl.m_oDrawingDocument.AddPageSearch("", _rect);
                            }
                            else
                            {
                                var ortX = _findLineEx;
                                var ortY = -_findLineEy;

                                var _x = _lineX + ortX * _findAscent;
                                var _y = _lineY + ortY * _findAscent;

                                var navigator = { Page : pageNum, X: _x, Y: _y,
                                    W : (_findLineOffsetR - _findLineOffsetX) , H : (_findAscent + _findDescent),
                                    Ex: _findLineEx, Ey: _findLineEy };

                                var _find = { text: "", navigator : navigator };
                                editor.WordControl.m_oApi.sync_SearchFoundCallback(_find);
                            }
                            */

                            // íóæíî âåðíóòüñÿ è ïîïðîáîâàòü èñêàòü ñî ñëåä áóêâû.
                            glyphsEqualFound = 0;
                            s.pos = _SeekToNextPoint;
                            _linePrevCharX = _SeekLinePrevCharX;
                            _lineCharCount = _findGlyphIndex;
                            _numLine = _findLine;
                        }
                    }
                    else
                    {
                        if (0 != glyphsEqualFound)
                        {
                            // íóæíî âåðíóòüñÿ è ïîïðîáîâàòü èñêàòü ñî ñëåä áóêâû.
                            glyphsEqualFound = 0;
                            s.pos = _SeekToNextPoint;
                            _linePrevCharX = _SeekLinePrevCharX;
                            _lineCharCount = _findGlyphIndex;
                            _numLine = _findLine;
                        }
                    }

                    break;
                }
                case 98:
                case 100:
                {
                    break;
                }
                case 91:
                {
                    // moveto
                    s.Skip(8);
                    break;
                }
                case 92:
                {
                    // lineto
                    s.Skip(8);
                    break;
                }
                case 94:
                {
                    // curveto
                    s.Skip(24);break;
                }
                case 97:
                {
                    break;
                }
                case 99:
                {
                    // drawpath
                    s.Skip(4);
                    break;
                }
                case 110:
                {
                    // drawImage
                    s.SkipImage();
                    break;
                }
                case 160:
                {
                    // textline
                    _linePrevCharX = 0;
                    _lineCharCount = 0;

                    var mask = s.GetUChar();
                    s.Skip(8);

                    if ((mask & 0x01) == 0)
                        s.Skip(8);

                    s.Skip(8);

                    if ((mask & 0x04) != 0)
                        s.Skip(4);

                    if ((mask & 0x02) != 0)
                        _lineGidExist = true;
                    else
                        _lineGidExist = false;

                    break;
                }
                case 162:
                {
                    ++_numLine;
                    break;
                }
                case 161:
                {
                    // text transform
                    s.Skip(16);
                    break;
                }
                case 163:
                {
                    break;
                }
                case 164:
                {
                    s.Skip(16);
                    break;
                }
                case 121:
                case 122:
                {
                    // begin/end command
                    s.Skip(4);
                    break;
                }
                default:
                {
                    s.pos = page.end;
                }
            }
        }
    },

    SearchPage2 : function(pageNum)
    {
        var page = this.Pages[pageNum];
        var s = this.getStreamPage(pageNum);
        s.Seek(page.start);

        var _searchResults = this.SearchResults;
        var _navRects = _searchResults.Pages[pageNum];

        var glyphsEqualFound = 0;
        var text = _searchResults.Text;
        var glyphsFindCount = text.length;

        if (!_searchResults.MachingCase)
        {
            text = text.toLowerCase();
        }

        if (0 == glyphsFindCount)
            return;

        var _numLine = -1;
        var _lineGidExist = false;
        var _linePrevCharX = 0;
        var _lineCharCount = 0;
        var _lineLastGlyphWidth = 0;

        var _findLine = 0;
        var _findLineOffsetX = 0;
        var _findLineOffsetR = 0;
        var _findGlyphIndex = 0;

        var _SeekToNextPoint = 0;
        var _SeekLinePrevCharX = 0;

        var arrayLines = [];
        var curLine = null;

        while (s.pos < page.end)
        {
            var command = s.GetUChar();

            switch (command)
            {
                case 41:
                {
                    s.Skip(12);
                    break;
                }
                case 22:
                {
                    s.Skip(4);
                    break;
                }
                case 1:
                {
                    s.Skip(4);
                    break;
                }
                case 3:
                {
                    s.Skip(4);
                    break;
                }
                case 131:
                {
                    break;
                }
                case 130:
                {
                    s.Skip(24);
                    break;
                }
                case 80:
                {
                    if (0 != _lineCharCount)
                        _linePrevCharX += s.GetDouble2();

                    _lineCharCount++;

                    var _char = s.GetUShort();
                    if (_lineGidExist)
                        s.Skip(2);

                    if (0xFFFF == _char)
                        curLine.text += " ";
                    else
                        curLine.text += String.fromCharCode(_char);

                    if (curLine.W != 0)
                        s.Skip(2);
                    else
                        curLine.W = s.GetDouble2();

                    break;
                }
                case 98:
                case 100:
                {
                    break;
                }
                case 91:
                {
                    // moveto
                    s.Skip(8);
                    break;
                }
                case 92:
                {
                    // lineto
                    s.Skip(8);
                    break;
                }
                case 94:
                {
                    // curveto
                    s.Skip(24);break;
                }
                case 97:
                {
                    break;
                }
                case 99:
                {
                    // drawpath
                    s.Skip(4);
                    break;
                }
                case 110:
                {
                    // drawImage
                    s.SkipImage();
                    break;
                }
                case 160:
                {
                    _linePrevCharX = 0;
                    _lineCharCount = 0;

                    arrayLines[arrayLines.length] = new CLineInfo();
                    curLine = arrayLines[arrayLines.length - 1];

                    var mask = s.GetUChar();
                    curLine.X = s.GetDouble();
                    curLine.Y = s.GetDouble();

                    if ((mask & 0x01) == 1)
                    {
                        var dAscent = s.GetDouble();
                        var dDescent = s.GetDouble();

                        curLine.Y -= dAscent;
                        curLine.H = dAscent + dDescent;
                    }
                    else
                    {
                        curLine.Ex = s.GetDouble();
                        curLine.Ey = s.GetDouble();

                        var dAscent = s.GetDouble();
                        var dDescent = s.GetDouble();

                        curLine.X = curLine.X + dAscent * curLine.Ey;
                        curLine.Y = curLine.Y - dAscent * curLine.Ex;

                        curLine.H = dAscent + dDescent;
                    }

                    if ((mask & 0x04) != 0)
                        curLine.W = s.GetDouble();

                    if ((mask & 0x02) != 0)
                        _lineGidExist = true;
                    else
                        _lineGidExist = false;

                    break;
                }
                case 162:
                {
                    break;
                }
                case 161:
                {
                    // text transform
                    s.Skip(16);
                    break;
                }
                case 163:
                {
                    break;
                }
                case 164:
                {
                    s.Skip(16);
                    break;
                }
                case 121:
                case 122:
                {
                    // begin/end command
                    s.Skip(4);
                    break;
                }
                default:
                {
                    s.pos = page.end;
                }
            }
        }

        // òåêñò çàïîëíåí. òåïåðü íóæíî ïðîñòî ïðîáåãàòüñÿ è ñìîòðåòü
        // îòêóäà ñîâïàäåíèå íà÷àëîñü è ãäå çàêîí÷èëîñü
        _linePrevCharX = 0;
        _lineCharCount = 0;
        _numLine = 0;

        s.Seek(page.start);

        while (s.pos < page.end)
        {
            var command = s.GetUChar();

            switch (command)
            {
                case 41:
                {
                    s.Skip(12);
                    break;
                }
                case 22:
                {
                    s.Skip(4);
                    break;
                }
                case 1:
                {
                    s.Skip(4);
                    break;
                }
                case 3:
                {
                    s.Skip(4);
                    break;
                }
                case 131:
                {
                    break;
                }
                case 130:
                {
                    s.Skip(24);
                    break;
                }
                case 80:
                {
                    if (0 != _lineCharCount)
                        _linePrevCharX += s.GetDouble2();

                    _lineCharCount++;

                    var _char = s.GetUShort();
                    if (_lineGidExist)
                        s.Skip(2);

                    if (0xFFFF == _char)
                        _char = " ".charCodeAt(0);

                    _lineLastGlyphWidth = s.GetDouble2();

                    var _isFound = false;
                    if (_searchResults.MachingCase)
                    {
                        if (_char == text.charCodeAt(glyphsEqualFound))
                            _isFound = true;
                    }
                    else
                    {
                        var _strMem = String.fromCharCode(_char);
                        _strMem = _strMem.toLowerCase();
                        if (_strMem.charCodeAt(0) == text.charCodeAt(glyphsEqualFound))
                            _isFound = true;
                    }

                    if (_isFound)
                    {
                        if (0 == glyphsEqualFound)
                        {
                            _findLine = _numLine;
                            _findLineOffsetX = _linePrevCharX;
                            _findGlyphIndex = _lineCharCount;

                            _SeekToNextPoint = s.pos;
                            _SeekLinePrevCharX = _linePrevCharX;
                        }

                        glyphsEqualFound++;
                        _findLineOffsetR = _linePrevCharX + _lineLastGlyphWidth;
                        if (glyphsFindCount == glyphsEqualFound)
                        {
                            var _rects = [];
                            for (var i = _findLine; i <= _numLine; i++)
                            {
                                var ps = 0;
                                if (_findLine == i)
                                    ps = _findLineOffsetX;
                                var pe = arrayLines[i].W;
                                if (i == _numLine)
                                    pe = _findLineOffsetR;

                                var _l = arrayLines[i];
                                if (_l.Ex == 1 && _l.Ey == 0)
                                {
                                    _rects[_rects.length] = { PageNum : pageNum, X : _l.X + ps, Y : _l.Y, W : pe - ps, H : _l.H };
                                }
                                else
                                {
                                    _rects[_rects.length] = { PageNum : pageNum, X : _l.X + ps * _l.Ex, Y : _l.Y + ps * _l.Ey, W : pe - ps, H : _l.H, Ex : _l.Ex, Ey : _l.Ey };
                                }
                            }

                            _navRects[_navRects.length] = _rects;

                            // íóæíî âåðíóòüñÿ è ïîïðîáîâàòü èñêàòü ñî ñëåä áóêâû.
                            glyphsEqualFound = 0;
                            s.pos = _SeekToNextPoint;
                            _linePrevCharX = _SeekLinePrevCharX;
                            _lineCharCount = _findGlyphIndex;
                            _numLine = _findLine;
                        }
                    }
                    else
                    {
                        if (0 != glyphsEqualFound)
                        {
                            // íóæíî âåðíóòüñÿ è ïîïðîáîâàòü èñêàòü ñî ñëåä áóêâû.
                            glyphsEqualFound = 0;
                            s.pos = _SeekToNextPoint;
                            _linePrevCharX = _SeekLinePrevCharX;
                            _lineCharCount = _findGlyphIndex;
                            _numLine = _findLine;
                        }
                    }

                    break;
                }
                case 98:
                case 100:
                {
                    break;
                }
                case 91:
                {
                    // moveto
                    s.Skip(8);
                    break;
                }
                case 92:
                {
                    // lineto
                    s.Skip(8);
                    break;
                }
                case 94:
                {
                    // curveto
                    s.Skip(24);break;
                }
                case 97:
                {
                    break;
                }
                case 99:
                {
                    // drawpath
                    s.Skip(4);
                    break;
                }
                case 110:
                {
                    // drawImage
                    s.SkipImage();
                    break;
                }
                case 160:
                {
                    // textline
                    _linePrevCharX = 0;
                    _lineCharCount = 0;

                    var mask = s.GetUChar();
                    s.Skip(8);

                    if ((mask & 0x01) == 0)
                        s.Skip(8);

                    s.Skip(8);

                    if ((mask & 0x04) != 0)
                        s.Skip(4);

                    if ((mask & 0x02) != 0)
                        _lineGidExist = true;
                    else
                        _lineGidExist = false;

                    break;
                }
                case 162:
                {
                    ++_numLine;
                    break;
                }
                case 161:
                {
                    // text transform
                    s.Skip(16);
                    break;
                }
                case 163:
                {
                    break;
                }
                case 164:
                {
                    s.Skip(16);
                    break;
                }
                case 121:
                case 122:
                {
                    // begin/end command
                    s.Skip(4);
                    break;
                }
                default:
                {
                    s.pos = page.end;
                }
            }
        }
    },

    OnMouseDown : function(page, x, y)
    {
        var ret = this.GetNearestPos(page, x, y);

        var sel = this.Selection;
        sel.Page1 = page;
        sel.Line1 = ret.Line;
        sel.Glyph1 = ret.Glyph;

        sel.Page2 = page;
        sel.Line2 = ret.Line;
        sel.Glyph2 = ret.Glyph;

        sel.IsSelection = true;
        this.OnUpdateSelection();
    },

    OnMouseMove : function(page, x, y)
    {
        if (false === this.Selection.IsSelection)
            return;

        var ret = this.GetNearestPos(page, x, y);

        var sel = this.Selection;
        sel.Page2 = page;
        sel.Line2 = ret.Line;
        sel.Glyph2 = ret.Glyph;

        this.OnUpdateSelection();
    },

    OnMouseUp : function()
    {
        if (this.Selection.IsSelection)
            editor.sendEvent("asc_onSelectionEnd");
        this.Selection.IsSelection = false;
    },

    OnUpdateSelection : function()
    {
        editor.WordControl.m_oOverlayApi.Show();
        editor.WordControl.OnUpdateOverlay();
    },

    Copy : function(_text_format)
    {
        var sel = this.Selection;
        var page1 = sel.Page1;
        var page2 = sel.Page2;

        if (page2 < page1)
        {
            page1 = page2;
            page2 = sel.Page1;
        }

        var ret = "<div>";
        for (var i = page1; i <= page2; i++)
        {
            ret += this.CopySelection(i, _text_format);
        }
        ret += "</div>";

        //console.log(ret);
        return ret;
    },

    OnKeyDown : function(e)
    {
        if (!editor.bInit_word_control)
            return false;

        var bRetValue = false;

        if ( e.KeyCode == 33 ) // PgUp
        {
            editor.WordControl.m_oScrollVerApi.scrollByY(-editor.WordControl.m_oEditor.HtmlElement.height, false);
        }
        else if ( e.KeyCode == 34 ) // PgDn
        {
            editor.WordControl.m_oScrollVerApi.scrollByY(editor.WordControl.m_oEditor.HtmlElement.height, false);
        }
        else if ( e.KeyCode == 35 ) // êëàâèøà End
        {
            if ( true === e.CtrlKey ) // Ctrl + End - ïåðåõîä â êîíåö äîêóìåíòà
            {
                editor.WordControl.m_oScrollVerApi.scrollToY(editor.WordControl.m_dScrollY_max, false);
            }

            bRetValue = true;
        }
        else if ( e.KeyCode == 36 ) // êëàâèøà Home
        {
            if ( true === e.CtrlKey ) // Ctrl + Home - ïåðåõîä â íà÷àëî äîêóìåíòà
            {
                editor.WordControl.m_oScrollVerApi.scrollToY(0, false);
            }

            bRetValue = true;
        }
        else if ( e.KeyCode == 37 ) // Left Arrow
        {
            bRetValue = true;
        }
        else if ( e.KeyCode == 38 ) // Top Arrow
        {
            bRetValue = true;
        }
        else if ( e.KeyCode == 39 ) // Right Arrow
        {
            bRetValue = true;
        }
        else if ( e.KeyCode == 40 ) // Bottom Arrow
        {
            bRetValue = true;
        }
        else if ( e.KeyCode == 65 && true === e.CtrlKey ) // Ctrl + A - âûäåëÿåì âñå
        {
            bRetValue = true;

            if (this.selectAllCheckStart())
            {
                this.selectAll();
            }
        }
		else if ( e.KeyCode == 80 && true === e.CtrlKey ) // Ctrl + P + ...
        {
            editor.onPrint();
            bRetValue = true;
        }
        else if ( e.KeyCode == 83 && true === e.CtrlKey ) // Ctrl + S + ...
        {
            // nothing
            bRetValue = true;
        }

        return bRetValue;
    },

    selectAll : function()
    {
        var sel = this.Selection;

        sel.Page1 = 0;
        sel.Line1 = 0;
        sel.Glyph1 = 0;

        sel.Page2 = 0;
        sel.Line2 = 0;
        sel.Glyph2 = 0;

        sel.IsSelection = false;

        if (0 != this.PagesCount)
        {
            var lLinesLastPage = this.GetCountLines(this.PagesCount - 1);
            if (1 != this.PagesCount || 0 != lLinesLastPage)
            {
                sel.Glyph1 = -2;
                sel.Page2 = this.PagesCount - 1;
                sel.Line2 = lLinesLastPage;
                sel.Glyph2 = -1;

                this.OnUpdateSelection();
            }
        }

        editor.sendEvent("asc_onSelectionEnd");
    },

    selectAllCheckStart : function()
    {
        this.waitSelectAll = false;
        return true;
    },

    selectAllCheckEnd : function()
    {
    },

    StartSearch : function(text)
    {
        editor.WordControl.m_oDrawingDocument.StartSearch();

        this.SearchInfo.Text = text;
        this.SearchInfo.Page = 0;

        var oThis = this;
        this.SearchInfo.Id = setTimeout(function(){oThis.OnSearchPage();}, 1);
    },

    OnSearchPage : function()
    {
        this.SearchPage(this.SearchInfo.Page, this.SearchInfo.Text);
        this.SearchInfo.Page++;

        if (this.SearchInfo.Page >= this.PagesCount)
        {
            this.StopSearch();
            return;
        }

        var oThis = this;
        this.SearchInfo.Id = setTimeout(function(){oThis.OnSearchPage();}, 1);
    },

    StopSearch : function()
    {
        if (null != this.SearchInfo.Id)
        {
            clearTimeout(this.SearchInfo.Id);
            this.SearchInfo.Id = null;
        }
        editor.WordControl.m_oDrawingDocument.EndSearch(false);
    },

    findText : function(text, isMachingCase, isNext)
    {
        this.SearchResults.IsSearch = true;
        if (text == this.SearchResults.Text && isMachingCase == this.SearchResults.MachingCase)
        {
            if (this.SearchResults.Count == 0)
            {
                editor.WordControl.m_oDrawingDocument.CurrentSearchNavi = null;
                this.SearchResults.CurrentPage = -1;
                this.SearchResults.Current = -1;
                return;
            }

            // поиск совпал, просто делаем навигацию к нужному месту
            if (isNext)
            {
                if ((this.SearchResults.Current + 1) < this.SearchResults.Pages[this.SearchResults.CurrentPage].length)
                {
                    // результат на этой же странице
                    this.SearchResults.Current++;
                }
                else
                {
                    var _pageFind = this.SearchResults.CurrentPage + 1;
                    var _bIsFound = false;
                    for (var i = _pageFind; i < this.PagesCount; i++)
                    {
                        if (0 < this.SearchResults.Pages[i].length)
                        {
                            this.SearchResults.Current = 0;
                            this.SearchResults.CurrentPage = i;
                            _bIsFound = true;
                            break;
                        }
                    }
                    if (!_bIsFound)
                    {
                        for (var i = 0; i < _pageFind; i++)
                        {
                            if (0 < this.SearchResults.Pages[i].length)
                            {
                                this.SearchResults.Current = 0;
                                this.SearchResults.CurrentPage = i;
                                _bIsFound = true;
                                break;
                            }
                        }
                    }
                }
            }
            else
            {
                if (this.SearchResults.Current > 0)
                {
                    // результат на этой же странице
                    this.SearchResults.Current--;
                }
                else
                {
                    var _pageFind = this.SearchResults.CurrentPage - 1;
                    var _bIsFound = false;
                    for (var i = _pageFind; i >= 0; i--)
                    {
                        if (0 < this.SearchResults.Pages[i].length)
                        {
                            this.SearchResults.Current = this.SearchResults.Pages[i].length - 1;
                            this.SearchResults.CurrentPage = i;
                            _bIsFound = true;
                            break;
                        }
                    }
                    if (!_bIsFound)
                    {
                        for (var i = this.PagesCount - 1; i > _pageFind; i--)
                        {
                            if (0 < this.SearchResults.Pages[i].length)
                            {
                                this.SearchResults.Current = this.SearchResults.Pages[i].length - 1;
                                this.SearchResults.CurrentPage = i;
                                _bIsFound = true;
                                break;
                            }
                        }
                    }
                }
            }

            editor.WordControl.m_oDrawingDocument.CurrentSearchNavi =
                this.SearchResults.Pages[this.SearchResults.CurrentPage][this.SearchResults.Current];

            editor.WordControl.ToSearchResult();
            return;
        }
        // новый поиск
        for (var i = 0; i < this.PagesCount; i++)
        {
            this.SearchResults.Pages[i].splice(0,  this.SearchResults.Pages[i].length);
        }
        this.SearchResults.Count = 0;

        this.SearchResults.CurrentPage = -1;
        this.SearchResults.Current = -1;

        this.SearchResults.Text = text;
        this.SearchResults.MachingCase = isMachingCase;

        for (var i = 0; i < this.PagesCount; i++)
        {
            this.SearchPage2(i);
            this.SearchResults.Count += this.SearchResults.Pages[i].length;
        }

        if (this.SearchResults.Count == 0)
        {
            editor.WordControl.m_oDrawingDocument.CurrentSearchNavi = null;
            editor.WordControl.OnUpdateOverlay();
            return;
        }

        for (var i = 0; i < this.SearchResults.Pages.length; i++)
        {
            if (0 != this.SearchResults.Pages[i].length)
            {
                this.SearchResults.CurrentPage = i;
                this.SearchResults.Current = 0;

                break;
            }
        }

        editor.WordControl.m_oDrawingDocument.CurrentSearchNavi =
            this.SearchResults.Pages[this.SearchResults.CurrentPage][this.SearchResults.Current];

        editor.WordControl.ToSearchResult();
    },

    GetCachedImage : function(_src)
    {
        if (0 == this.CachedImagesCount)
            return null;

        var _len = this.CachedImages.length;
        for (var i = 0; i < _len; i++)
        {
            if (this.CachedImages[i].src == _src)
                return this.CachedImages[i].image;
        }
        return  null;
    },

    SetCachedImage : function(_src, _image)
    {
        if (0 == this.CachedImagesCount)
            return;

        if (this.CachedImages.length == this.CachedImagesCount)
            this.CachedImages.shift();

		this.CachedImages.push({ src: _src, image: _image });
    }
};

//------------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CDocMeta = CDocMeta;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

var g_sEmpty_bin = "DOCY;v4;8985; ";
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

var MATH_FRACTION           	=  0;
var MATH_DEGREE             	=  1;
var MATH_DEGREESubSup       	=  2;
var MATH_RADICAL            	=  3;
var MATH_NARY               	=  4;
var MATH_DELIMITER          	=  5;
var MATH_GROUP_CHARACTER    	=  6;
var MATH_FUNCTION           	=  7;
var MATH_ACCENT             	=  8;
var MATH_BORDER_BOX         	=  9;
var MATH_LIMIT              	= 10;
var MATH_MATRIX             	= 11;
var MATH_BOX                	= 12;
var MATH_EQ_ARRAY               = 13;
var MATH_BAR                    = 14;
var MATH_PHANTOM                = 15;

var MATH_RUN                    = 16;
var MATH_PRIMARY_LIMIT          = 17;

var BAR_FRACTION            	=  0;
var SKEWED_FRACTION         	=  1;
var LINEAR_FRACTION         	=  2;
var NO_BAR_FRACTION         	=  3;

var DEGREE_SUPERSCRIPT      	=  1;
var DEGREE_SUBSCRIPT        	= -1;

var DEGREE_SubSup           	=  1;
var DEGREE_PreSubSup        	= -1;

var SQUARE_RADICAL          	=  0;
var DEGREE_RADICAL          	=  1;

var NARY_INTEGRAL           	=  0;
var NARY_DOUBLE_INTEGRAL    	=  1;
var NARY_TRIPLE_INTEGRAL    	=  2;
var NARY_CONTOUR_INTEGRAL   	=  3;
var NARY_SURFACE_INTEGRAL   	=  4;
var NARY_VOLUME_INTEGRAL    	=  5;
var NARY_SIGMA              	=  6;
var NARY_PRODUCT            	=  7;
var NARY_COPRODUCT          	=  8;
var NARY_UNION              	=  9;
var NARY_INTERSECTION       	= 10;
var NARY_LOGICAL_OR         	= 11;
var NARY_LOGICAL_AND        	= 12;
var NARY_TEXT_OPER              = 13;

var NARY_UndOvr             	=  0;
var NARY_SubSup             	=  1;

////////////////////////////////////////////////////

//  operators:
//  accent, delimiters, group character

var OPERATOR_EMPTY              = -1;
var OPERATOR_TEXT               =  0;
var PARENTHESIS_LEFT        	=  1;
var PARENTHESIS_RIGHT       	=  2;
var BRACKET_CURLY_LEFT      	=  3;
var BRACKET_CURLY_RIGHT     	=  4;
var BRACKET_SQUARE_LEFT     	=  5;
var BRACKET_SQUARE_RIGHT    	=  6;
var BRACKET_ANGLE_LEFT      	=  7;
var BRACKET_ANGLE_RIGHT     	=  8;
var HALF_SQUARE_LEFT    	    =  9;
var HALF_SQUARE_RIGHT   	    = 10;
var HALF_SQUARE_LEFT_UPPER	    = 11;
var HALF_SQUARE_RIGHT_UPPER	    = 12;
var DELIMITER_LINE              = 13;
var DELIMITER_DOUBLE_LINE       = 14;
var WHITE_SQUARE_LEFT           = 15;
var WHITE_SQUARE_RIGHT          = 16;
var BRACKET_CURLY_TOP           = 17;
var BRACKET_CURLY_BOTTOM        = 18;
var ARROW_LEFT                  = 19;
var ARROW_RIGHT                 = 20;
var ARROW_LR                    = 21;
var DOUBLE_LEFT_ARROW           = 22;
var DOUBLE_RIGHT_ARROW          = 23;
var DOUBLE_ARROW_LR             = 24;
var ACCENT_ARROW_LEFT           = 26;
var ACCENT_ARROW_RIGHT          = 27;
var ACCENT_ARROW_LR             = 28;
var ACCENT_HALF_ARROW_LEFT      = 29;
var ACCENT_HALF_ARROW_RIGHT     = 30;
var PARENTHESIS_TOP             = 31;
var PARENTHESIS_BOTTOM          = 32;
var BRACKET_SQUARE_TOP     	    = 33;

var ACCENT_ONE_DOT              = 31;
var ACCENT_TWO_DOTS             = 32;
var ACCENT_THREE_DOTS           = 33;
var ACCENT_GRAVE                = 34;
var ACCENT_ACUTE                = 35;
var ACCENT_CIRCUMFLEX           = 36;
var ACCENT_COMB_CARON           = 37;
var ACCENT_LINE                 = 38;
var ACCENT_DOUBLE_LINE          = 39;
var SINGLE_LINE                 = 40;
var DOUBLE_LINE                 = 41;
var ACCENT_TILDE                = 42;
var ACCENT_BREVE                = 43;
var ACCENT_INVERT_BREVE         = 44;

var ACCENT_SIGN                 = 45;
var ACCENT_TEXT                 = 46;

///////////////////////////////////////////////////


var TXT_ROMAN                   =  0;   // math roman
var TXT_SCRIPT                  =  1;
var TXT_FRAKTUR                 =  2;
var TXT_DOUBLE_STRUCK           =  3;
var TXT_SANS_SERIF              =  4;
var TXT_MONOSPACE               =  5;

var OPER_DELIMITER              =  0;
var OPER_SEPARATOR              =  1;
var OPER_GROUP_CHAR             =  2;
var OPER_ACCENT                 =  3;
var OPER_BAR                    =  4;


var TURN_0                      =  0;
var TURN_180                    =  1;
var TURN_MIRROR_0               =  2;
var TURN_MIRROR_180             =  3;

var DELIMITER_SHAPE_MATCH       =  0;
var DELIMITER_SHAPE_CENTERED    =  1;

var LIMIT_LOW               	=  0;
var LIMIT_UP                	=  1;

/////////////////////////////////////////

var MCJC_CENTER                 =  0;
var MCJC_LEFT                   =  1;
var MCJC_RIGHT                  =  2;
var MCJC_INSIDE                 =  0;
var MCJC_OUTSIDE                =  0;

var BASEJC_CENTER               =  0;
var BASEJC_TOP                  =  1;
var BASEJC_BOTTOM               =  2;
var BASEJC_INLINE               =  0;
var BASEJC_INSIDE               =  0;
var BASEJC_OUTSIDE              =  0;

var JC_CENTER                   =  0;
var JC_CENTERGROUP              =  1;
var JC_LEFT                     =  2;
var JC_RIGHT                    =  3;

var LOCATION_TOP                =  0;
var LOCATION_BOT                =  1;
var LOCATION_LEFT               =  2;
var LOCATION_RIGHT              =  3;
var LOCATION_SEP                =  4;

var VJUST_TOP                   = 0;
var VJUST_BOT                   = 1;


////////////////////////////////////////
var BREAK_BEFORE                =  0;
var BREAK_AFTER                 =  1;
var BREAK_REPEAT                =  2;

var BREAK_MIN_MIN               =  0;
var BREAK_PLUS_MIN              =  1;
var BREAK_MIN_PLUS              =  2;

var STY_BOLD                    =  0;
var STY_BI                      =  1;
var STY_ITALIC                  =  2;
var STY_PLAIN                   =  3;

/////////////////////////////////////////

var ALIGN_MARGIN_WRAP           = 0;
var ALIGN_MARGIN                = 1;
var ALIGN_WRAP                  = 2;
var ALIGN_EMPTY                 = 3;

var MATH_INTERVAL_EMPTY         = 0;
var MATH_INTERVAL_ON_SIDE       = 1;

var MATH_UPDWRAP_NOCHANGES      = 0;
var MATH_UPDWRAP_NEWRANGE       = 1;
var MATH_UPDWRAP_UNDERFLOW      = 2;

var MATH_SIZE                   = 0;
var MATH_BOUNDS_MEASURES        = 1;

var MATH_MATRIX_ROW             = 0;
var MATH_MATRIX_COLUMN          = 1;


var MATH_LINE_START             = 0;
var MATH_LINE_WRAP              = 1;
var MATH_LINE_ALiGN_AT          = 2;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var g_oTextMeasurer = AscCommon.g_oTextMeasurer;

// Таблица соответствия кодов ASCII (десятичные, соответствующие восьмеричные, шестнадцатиричные, двоичные, ASCII коды )
// http://www.dpva.info/Guide/GuideMathematics/GuideMathematicsNumericalSystems/TableCodeEquivalent/

var DIV_CENT = 0.1386;
var StartTextElement = 0x2B1A; // Cambria Math

var MathTextInfo_MathText        = 1;
var MathTextInfo_SpecialOperator = 2;
var MathTextInfo_NormalText      = 3;

function CMathSize()
{
    this.Type   = MATH_SIZE;
    this.width  = 0;
    this.height = 0;
    this.ascent = 0;
}
CMathSize.prototype.SetZero = function()
{
    this.width  = 0;
    this.descent = 0;
    this.ascent = 0;
}
CMathSize.prototype.Set = function(size)
{
    this.width  = size.width;
    this.height = size.height;
    this.ascent = size.ascent;
};

function CMathBaseText()
{
    this.Type           = null;
    this.bJDraw         = false;
    this.value          = null;
    this.bUpdateGaps    = true;

    this.bEmptyGapLeft  = false;
    this.bEmptyGapRight = false;

    this.ParaMath       = null;
    this.Parent         = null;
    this.Flags          = 0;
    this.size           = new CMathSize();
    this.Width          = 0; // special for Run размер буквы без Gaps
                             // в действительности это поле не должно использоваться, нужно использовать функциии Get_Width, Get_Width_2 ,Get_WidthVisible

    this.pos = new CMathPosition();

    this.GapLeft        = 0;
    this.GapRight       = 0;
}
CMathBaseText.prototype.Get_Width = function() // работаем через функцию, т.к. поля  GapLeft и GapRight могут измениться из-за изменения переноса, а пересчет (Measure) в этом случае не прийдет
{
    var Width = this.size.width;

    if(this.bEmptyGapLeft == false)
        Width += this.GapLeft;

    if(this.bEmptyGapRight == false)
        Width += this.GapRight;

    return (Width*TEXTWIDTH_DIVIDER) | 0;
};
CMathBaseText.prototype.Get_Width2 = function() // работаем через функцию, т.к. поля  GapLeft и GapRight могут измениться из-за изменения переноса, а пересчет (Measure) в этом случае не прийдет
{
    return ( (this.size.width + this.GapLeft + this.GapRight)* TEXTWIDTH_DIVIDER ) | 0;
};
CMathBaseText.prototype.Get_WidthVisible = function()
{
    var Width = this.size.width;

    if(this.bEmptyGapLeft == false)
        Width += this.GapLeft;

    if(this.bEmptyGapRight == false)
        Width += this.GapRight;

    return Width;
};
CMathBaseText.prototype.Update_StateGapLeft = function(bState)
{
    this.bEmptyGapLeft = bState;
};
CMathBaseText.prototype.Update_StateGapRight = function(bState)
{
    this.bEmptyGapRight = bState;
};
CMathBaseText.prototype.GetLocationOfLetter = function()
{
    var pos = new CMathPosition();

    pos.x = this.pos.x;
    pos.y = this.pos.y;

    return pos;
};
CMathBaseText.prototype.IsPlaceholder = function()
{
    return this.Type == para_Math_Placeholder;
};
CMathBaseText.prototype.IsJustDraw = function()
{
    return false;
};
// For ParaRun
CMathBaseText.prototype.Is_Punctuation = function()
{
    var bPunc     = 1 === AscCommon.g_aPunctuation[this.value],
        bMathSign = this.value ==  0x2217 || this.value == 0x2212;

    return bPunc || bMathSign;
};
CMathBaseText.prototype.Is_NBSP = function()
{
    return false;
};
CMathBaseText.prototype.Can_AddNumbering = function()
{
    return true;
};
CMathBaseText.prototype.Draw_Elements = function(PDSE)  // эта функция необходима для Draw_Elements основания Nary, когда в основании находится только JustDraw элемент
{
    var PosLine = this.ParaMath.GetLinePosition(PDSE.Line, PDSE.Range);
    this.Draw(PosLine.x, PosLine.y, PDSE.Graphics);
};
CMathBaseText.prototype.SetUpdateGaps = function(bUpd)
{
    this.bUpdateGaps = bUpd;
};
CMathBaseText.prototype.IsNeedUpdateGaps = function()
{
    return this.bUpdateGaps;
};

/**
 *
 * @param bJDraw
 * @constructor
 * @extends {CMathBaseText}
 */
function CMathText(bJDraw)
{
	CMathBaseText.call(this);

    this.Type           = para_Math_Text;
    this.bJDraw         = (undefined === bJDraw ? false : bJDraw);

    this.RecalcInfo =
    {
        StyleCode:        null,
        bAccentIJ:        false,
        bSpaceSpecial:    false,
        bApostrophe:      false,
        bSpecialOperator: false
    };

    this.rasterOffsetX  = 0;
    this.rasterOffsetY  = 0;

    this.FontSlot       = fontslot_ASCII;


    // TO DO
    // убрать

    /*this.transform =
    {
        sx:  1,
        shy: 0,
        shx: 0,
        sy:  1
    };*/

}
CMathText.prototype = Object.create(CMathBaseText.prototype);
CMathText.prototype.constructor = CMathText;
CMathText.prototype.add = function(code)
{
    this.value = code;

	if (AscFonts.IsCheckSymbols)
		AscFonts.FontPickerByCharacter.getFontBySymbol(this.value);

    if( this.private_Is_BreakOperator(code) )
        this.Type = para_Math_BreakOperator;
};
CMathText.prototype.addTxt = function(txt)
{
    var code = txt.charCodeAt(0);
    this.add(code);
};
CMathText.prototype.getCodeChr = function()
{
    return this.value;
};
CMathText.prototype.private_getCode = function()
{
    var code = this.value;

    var bNormal = this.bJDraw ? null : this.Parent.IsNormalText();

    if(this.Type === para_Math_Placeholder || this.bJDraw || bNormal)
        return code;

    var Compiled_MPrp = this.Parent.GetCompiled_ScrStyles();
    var bAccent = this.Parent.IsAccent();

    var bCapitale = (code > 0x0040 && code < 0x005B),
        bSmall = (code > 0x0060 && code < 0x007b),
        bDigit = (code > 0x002F && code < 0x003A);

    var bCapGreek   = (code > 0x0390 && code < 0x03AA),
        bSmallGreek = (code > 0x03B0 && code < 0x03CA);

    var Scr = Compiled_MPrp.scr,
        Sty = Compiled_MPrp.sty;

    // Mathematical Alphanumeric Characters
    // http://www.w3.org/TR/2014/REC-xml-entity-names-20140410/Overview.html#alphabets

    if(code == 0x2A)      // "*"
        code = 0x2217;
    else if(code == 0x2D) // "-"
        code = 0x2212;
    else if(!bNormal && code == 0x27) // " ' "
        code = 0x2032;
    else if(Scr == TXT_ROMAN)
    {
        if(Sty == STY_ITALIC)
        {
            if(code == 0x68)            // h
                code = 0x210E;
            /*else if((code == 0x69 && bAccent) || code == 0x131) // "i" with dot || "i" dotless plain => "i" dotless italic
                code = 0x1D6A4;
            else if((code == 0x6A && bAccent) ||code == 0x237)   // "j" with dot || "j" dotless plain => "j" dotless italic
                code = 0x1D6A5;*/
            else if(code == 0x69 && bAccent)
                code = 2835;
            else if(code == 0x6A && bAccent)
                code = 2836;
            else if(bCapitale)
                code  = code + 0x1D3F3;
            else if(bSmall)
                code  = code + 0x1D3ED;
            else if(code == 0x3F4)      // Capital THETA special
                code = 0x1D6F3;
            else if(code == 0x2207)     // Capital NABLA
                code = 0x1D6FB;
            else if(bCapGreek)
                code = code + 0x1D351;
            else if(bSmallGreek)
                code = code + 0x1D34B;
            else if(code == 0x2202)     //  PARTIAL DIFFERENTIAL
                code = 0x1D715;
            else if(code == 0x3F5)      //  small EPSILON
                code = 0x1D716;
            else if(code == 0x3D1)      //  small THETA
                code = 0x1D717;
            else if(code == 0x3F0)      //  small KAPPA
                code = 0x1D718;
            else if(code == 0x3D5)      //  small PHI
                code = 0x1D719;
            else if(code == 0x3F1)      //  small RHO
                code = 0x1D71A;
            else if(code == 0x3D6)      //  small PI
                code = 0x1D71B;

        }
        else if(Sty == STY_BI)
        {
            if(code == 0x69 && bAccent)
                code = 2841;
            else if(code == 0x6A && bAccent)
                code = 2842;
            else if(bCapitale)
                code = code + 0x1D427;
            else if(bSmall)
                code = code + 0x1D421;
            else if(bDigit)
                code  = code + 0x1D79E;
            else if(code == 0x3F4)      // Capital THETA special
                code = 0x1D72D;
            else if(code == 0x2207)     // Capital NABLA
                code = 0x1D735;
            else if(bCapGreek)
                code = code + 0x1D38B;
            else if(bSmallGreek)
                code = code + 0x1D385;
            else if(code == 0x2202)     //  PARTIAL DIFFERENTIAL
                code = 0x1D74F;
            else if(code == 0x3F5)      //  small EPSILON
                code = 0x1D750;
            else if(code == 0x3D1)      //  small THETA
                code = 0x1D751;
            else if(code == 0x3F0)      //  small KAPPA
                code = 0x1D752;
            else if(code == 0x3D5)      //  small PHI
                code = 0x1D753;
            else if(code == 0x3F1)      //  small RHO
                code = 0x1D754;
            else if(code == 0x3D6)      //  small PI
                code = 0x1D755;
        }
        else if(Sty == STY_BOLD)
        {
            if(code == 0x69 && bAccent)
                code = 2829;
            else if(code == 0x6A && bAccent)
                code = 2830;
            else if(bCapitale)
                code = code + 0x1D3BF;
            else if(bSmall)
                code = code + 0x1D3B9;
            else if(bDigit)
                code  = code + 0x1D79E;
            else if(code == 0x3F4)      // Capital THETA special
                code = 0x1D6B9;
            else if(code == 0x2207)     // Capital NABLA
                code = 0x1D6C1;
            else if(bCapGreek)
                code = code + 0x1D317;
            else if(bSmallGreek)
                code = code + 0x1D311;
            else if(code == 0x2202)     //  PARTIAL DIFFERENTIAL
                code = 0x1D6DB;
            else if(code == 0x3F5)      //  small EPSILON
                code = 0x1D6DC;
            else if(code == 0x3D1)      //  small THETA
                code = 0x1D6DD;
            else if(code == 0x3F0)      //  small KAPPA
                code = 0x1D6DE;
            else if(code == 0x3D5)      //  small PHI
                code = 0x1D6DF;
            else if(code == 0x3F1)      //  small RHO
                code = 0x1D6E0;
            else if(code == 0x3D6)      //  small PI
                code = 0x1D6E1;
            else if(code == 0x3DC)      //  CAPITAL DIGAMMA
                code = 0x1D7CA;
            else if(code == 0x3DD)      //  SMALL DIGAMMA
                code = 0x1D7CB;
        }
        else // PLAIN
        {
            if(bAccent)
            {
                /*if(code == 0x69)    // "i" with dot  => "i" dotless plain
                    code = 0x131;
                else if(code == 0x6A)      //  "j" with dot => "j" dotless plain
                    code = 0x237;*/

                if(code == 0x69 && bAccent)
                    code = 199;
                else if(code == 0x6A && bAccent)
                    code = 2828;

            }
        }
    }
    else if(Scr == TXT_DOUBLE_STRUCK)
    {
        if(code == 0x69 && bAccent)
            code = 2851;
        else if(code == 0x6A && bAccent)
            code = 2852;
        else if(code == 0x43)   // C
            code = 0x2102;
        else if(code == 0x48)   // H
            code = 0x210D;
        else if(code == 0x4E)   // N
            code = 0x2115;
        else if(code == 0x50)   // P
            code = 0x2119;
        else if(code == 0x51)   // Q
            code = 0x211A;
        else if(code == 0x52)   // R
            code = 0x211D;
        else if(code == 0x5A)   // Z
            code = 0x2124;
        else if(bCapitale)
            code  = code + 0x1D4F7;
        else if(bSmall)
            code  = code + 0x1D4F1;

        else if(bDigit)
            code = code + 0x1D7A8;

        // arabic mathematical symbols

        else if(code == 0x628)
            code = 0x1EEA1;
        else if(code == 0x062C)
            code = 0x1EEA2;
        else if(code == 0x062F)
            code = 0x1EEA3;
        else if(code == 0x0648)
            code = 0x1EEA5;
        else if(code == 0x0632)
            code = 0x1EEA6;
        else if(code == 0x062D)
            code = 0x1EEA7;
        else if(code == 0x0637)
            code = 0x1EEA8;
        else if(code == 0x064A)
            code = 0x1EEA9;

        else if(code == 0x0644)
            code = 0x1EEAB;
        else if(code == 0x0645)
            code = 0x1EEAC;
        else if(code == 0x0646)
            code = 0x1EEAD;
        else if(code == 0x0633)
            code = 0x1EEAE;
        else if(code == 0x0639)
            code = 0x1EEAF;
        else if(code == 0x0641)
            code = 0x1EEB0;
        else if(code == 0x0635)
            code = 0x1EEB1;
        else if(code == 0x0642)
            code = 0x1EEB2;
        else if(code == 0x0631)
            code = 0x1EEB3;
        else if(code == 0x0634)
            code = 0x1EEB4;
        else if(code == 0x062A)
            code = 0x1EEB5;
        else if(code == 0x062B)
            code = 0x1EEB6;
        else if(code == 0x062E)
            code = 0x1EEB7;
        else if(code == 0x0630)
            code = 0x1EEB8;
        else if(code == 0x0636)
            code = 0x1EEB9;
        else if(code == 0x0638)
            code = 0x1EEBA;
        else if(code == 0x063A)
            code = 0x1EEBB;

    }
    else if(Scr == TXT_MONOSPACE)
    {
        if(code == 0x69 && bAccent)
            code = 4547;
        else if(code == 0x6A && bAccent)
            code = 4548;
        else if(bCapitale)
            code  = code + 0x1D62F;
        else if(bSmall)
            code  = code + 0x1D629;
        else if(bDigit)
            code  = code + 0x1D7C6;
    }
    else if(Scr == TXT_FRAKTUR)
    {
        if(Sty == STY_BOLD ||Sty == STY_BI)
        {
            if(code == 0x69 && bAccent)
                code = 2849;
            else if(code == 0x6A && bAccent)
                code = 2850;
            else if(bCapitale)
                code = code + 0x1D52B;
            else if(bSmall)
                code = code + 0x1D525;
        }
        else
        {
            if(code == 0x69 && bAccent)
                code = 2847;
            else if(code == 0x6A && bAccent)
                code = 2848;
            else if(code == 0x43)   // C
                code = 0x212D;
            else if(code == 0x48)   // H
                code = 0x210C;
            else if(code == 0x49)   // I
                code = 0x2111;
            else if(code == 0x52)   // R
                code = 0x211C;
            else if(code == 0x5A)   // Z
                code = 0x2128;
            else if(bCapitale)
                code = code + 0x1D4C3;
            else if(bSmall)
                code = code + 0x1D4BD;
        }

    }
    else if(Scr == TXT_SANS_SERIF)
    {
        if(Sty == STY_ITALIC)
        {
            if(code == 0x69 && bAccent)
                code = 2857;
            else if(code == 0x6A && bAccent)
                code = 2858;
            else if(bCapitale)
                code = code + 0x1D5C7;
            else if(bSmall)
                code = code + 0x1D5C1;
            else if(bDigit)
                code = code + 0x1D7B2;
        }
        else if(Sty == STY_BOLD)
        {
            if(code == 0x69 && bAccent)
                code = 2855;
            else if(code == 0x6A && bAccent)
                code = 2856;
            else if(bCapitale)
                code = code + 0x1D593;
            else if(bSmall)
                code = code + 0x1D58D;
            else if(bDigit)
                code = code + 0x1D7BC;
            else if(code == 0x3F4)      // Capital THETA special
                code = 0x1D767;
            else if(code == 0x2207)     // Capital NABLA
                code = 0x1D76F;
            else if(bCapGreek)
                code = code + 0x1D3C5;
            else if(bSmallGreek)
                code = code + 0x1D3BF;
            else if(code == 0x2202)     //  PARTIAL DIFFERENTIAL
                code = 0x1D789;
            else if(code == 0x3F5)      //  small EPSILON
                code = 0x1D78A;
            else if(code == 0x3D1)      //  small THETA
                code = 0x1D78B;
            else if(code == 0x3F0)      //  small KAPPA
                code = 0x1D78C;
            else if(code == 0x3D5)      //  small PHI
                code = 0x1D78D;
            else if(code == 0x3F1)      //  small RHO
                code = 0x1D78E;
            else if(code == 0x3D6)      //  small PI
                code = 0x1D78F;
        }
        else if(Sty == STY_BI)
        {
            if(code == 0x69 && bAccent)
                code = 2859;
            else if(code == 0x6A && bAccent)
                code = 2860;
            else if(bCapitale)
                code = code + 0x1D5FB;
            else if(bSmall)
                code = code + 0x1D5F5;
            else if(bDigit)
                code = code + 0x1D7BC;
            else if(code == 0x3F4)      // Capital THETA special
                code = 0x1D7A1;
            else if(code == 0x2207)     // Capital NABLA
                code = 0x1D7A9;
            else if(bCapGreek)
                code = code + 0x1D3FF;
            else if(bSmallGreek)
                code = code + 0x1D3F9;
            else if(code == 0x2202)     //  PARTIAL DIFFERENTIAL
                code = 0x1D7C3;
            else if(code == 0x3F5)      //  small EPSILON
                code = 0x1D7C4;
            else if(code == 0x3D1)      //  small THETA
                code = 0x11D7C5;
            else if(code == 0x3F0)      //  small KAPPA
                code = 0x1D7C6;
            else if(code == 0x3D5)      //  small PHI
                code = 0x1D7C7;
            else if(code == 0x3F1)      //  small RHO
                code = 0x1D7C8;
            else if(code == 0x3D6)      //  small PI
                code = 0x1D7C9;
        }
        else
        {
            if(code == 0x69 && bAccent)
                code = 2853;
            else if(code == 0x6A && bAccent)
                code = 2854;
            else if(bCapitale)
                code = code + 0x1D55F;
            else if(bSmall)
                code = code + 0x1D559;
            else if(bDigit)
                code = code + 0x1D7B2;
        }

    }
    else if(Scr == TXT_SCRIPT)
    {
        if(Sty == STY_ITALIC || Sty == STY_PLAIN)
        {
            if(code == 0x69 && bAccent)
                code = 2843;
            else if(code == 0x6A && bAccent)
                code = 2844;
            else if(code == 0x42)   // B
                code = 0x212C;
            else if(code == 0x45)   // E
                code = 0x2130;
            else if(code == 0x46)   // F
                code = 0x2131;
            else if(code == 0x48)   // H
                code = 0x210B;
            else if(code == 0x49)   // I
                code = 0x2110;
            else if(code == 0x4C)   // L
                code = 0x2112;
            else if(code == 0x4D)   // M
                code = 0x2133;
            else if(code == 0x52)   // R
                code = 0x211B;
            else if(code == 0x65)   // e
                code = 0x212F;
            else if(code == 0x67)   // g
                code = 0x210A;
            else if(code == 0x6F)   // o
                code = 0x2134;
            else if(bCapitale)
                code  = code + 0x1D45B;
            else if(bSmall)
                code  = code + 0x1D455;
        }
        else
        {
            if(code == 0x69 && bAccent)
                code = 2845;
            else if(code == 0x6A && bAccent)
                code = 2846;
            else if(bCapitale)
                code = code + 0x1D48F;
            else if(bSmall)
                code = code + 0x1D489;

        }
    }

    return code;
};
CMathText.prototype.SetPlaceholder = function()
{
    this.Type = para_Math_Placeholder;
    this.value = StartTextElement;
};
CMathText.prototype.Measure = function(oMeasure, TextPr, InfoMathText)
{
    /*
     var metricsTxt = g_oTextMeasurer.Measure2Code(letter);
     var _width = metricsTxt.Width;
     height = g_oTextMeasurer.GetHeight();
    */

    var metricsTxt;

    // measure
    if(this.bJDraw)
    {
        // Font выставляется на соответствующей функции SetFont в родительском классе (в общем случае в CMathBase)

        this.RecalcInfo.StyleCode = this.value;
        metricsTxt = oMeasure.Measure2Code(this.value);
    }
    else
    {
        var ascent, width, height, descent;

        var letter = this.private_getCode();

        this.FontSlot = InfoMathText.GetFontSlot(letter); // возвращает fontslot_ASCII || fontslot_EastAsia || fontslot_CS || fontslot_HAnsi

        // в не математическом тексте i и j не подменяются на i и j без точек
        var bAccentIJ = !InfoMathText.bNormalText && this.Parent.IsAccent() && (this.value == 0x69 || this.value == 0x6A);

        this.RecalcInfo.StyleCode   = letter;
        this.RecalcInfo.bAccentIJ   = bAccentIJ;

        var bApostrophe = 1 == q_Math_Apostrophe[letter] && this.bJDraw == false;

        if(bAccentIJ)
            oMeasure.SetStringGid(true);

        if( InfoMathText.NeedUpdateFont(letter, this.FontSlot, this.IsPlaceholder(), bApostrophe) )
        {
            g_oTextMeasurer.SetFont(InfoMathText.Font);
            //g_oTextMeasurer.SetTextPr(InfoTextPr.CurrentTextPr, InfoTextPr.Theme);
        }
        else if(InfoMathText.CurrType == MathTextInfo_NormalText)
        {
            var FontKoef = InfoMathText.GetFontKoef(this.FontSlot);

            g_oTextMeasurer.SetFontSlot(this.FontSlot, FontKoef);
        }

        this.RecalcInfo.bApostrophe   = InfoMathText.bApostrophe;
        this.RecalcInfo.bSpaceSpecial = letter == 0x2061;

        metricsTxt = oMeasure.MeasureCode(letter);

        if(bAccentIJ)
            oMeasure.SetStringGid(false);
    }

    if(this.RecalcInfo.bApostrophe)
    {
        width   =  metricsTxt.Width;
        height  = metricsTxt.Height;

        InfoMathText.NeedUpdateFont(0x1D44E, this.FontSlot, false, false);  // a
        g_oTextMeasurer.SetFont(InfoMathText.Font);

        var metricsA = oMeasure.MeasureCode(0x1D44E);   // a
        this.rasterOffsetY = metricsA.Height - metricsTxt.Ascent; // смещение для позиции

        ascent  =  metricsA.Height;
    }
    else if(this.RecalcInfo.bSpaceSpecial)
    {
        width = 0;
        height = 0;
        ascent = 0;
    }
    else
    {
        //  смещения
        this.rasterOffsetX = metricsTxt.rasterOffsetX;
        this.rasterOffsetY = metricsTxt.rasterOffsetY;

        ascent  =  metricsTxt.Ascent;
        descent = (metricsTxt.Height - metricsTxt.Ascent);
        height  =  ascent + descent;


        if(this.bJDraw)
            width = metricsTxt.WidthG;
        else
            width = metricsTxt.Width;
    }

    this.size.width  = width;
    this.size.height = height;
    this.size.ascent = ascent;

    this.Width = (this.size.width * TEXTWIDTH_DIVIDER) | 0;

};
CMathText.prototype.PreRecalc = function(Parent, ParaMath)
{
    this.ParaMath = ParaMath;
    if(!this.bJDraw)
        this.Parent = Parent;
    else
        this.Parent = null;

    this.bUpdateGaps = false;
};
CMathText.prototype.Draw = function(x, y, pGraphics, InfoTextPr)
{
    var X = this.pos.x + x,
        Y = this.pos.y + y;

    if(this.bEmptyGapLeft == false)
        X += this.GapLeft;

    /*var tx = 0;
     var ty = 0;

     var x = (X*sy  - Y*shx - tx*sy)/(sx*sy- shy*shx);
     var y = (Y - x*shy - ty*shx)/sy;*/

    /*var invert = new CMatrix();
    invert.sx = this.transform.sx;
    invert.sy = this.transform.sy;
    invert.shx = this.transform.shx;
    invert.shy = this.transform.shy;
    invert.tx = 0;
    invert.ty = 0;
    invert.Invert();

    var xx = invert.TransformPointX(X, Y);
    var yy = invert.TransformPointY(X, Y);


    var sx = this.transform.sx, shx = this.transform.shx,
        shy = this.transform.shy, sy = this.transform.sy;

    pGraphics.transform(sx, shy, shx, sy, 0, 0);*/

    if(this.bJDraw)
    {
        pGraphics.FillTextCode(X, Y, this.RecalcInfo.StyleCode);    //на отрисовку символа отправляем положение baseLine
    }
    else if(this.RecalcInfo.bSpaceSpecial == false)
    {
        if( InfoTextPr.NeedUpdateFont(this.RecalcInfo.StyleCode, this.FontSlot, this.IsPlaceholder(), this.RecalcInfo.bApostrophe) )
        {
            pGraphics.SetFont(InfoTextPr.Font);
            //pGraphics.SetTextPr(InfoTextPr.CurrentTextPr, InfoTextPr.Theme);
        }
        else if(InfoTextPr.CurrType == MathTextInfo_NormalText)
        {
            var FontKoef = InfoTextPr.GetFontKoef(this.FontSlot);
            pGraphics.SetFontSlot(this.FontSlot, FontKoef);
        }

        if(this.RecalcInfo.bAccentIJ)
            pGraphics.tg(this.RecalcInfo.StyleCode, X, Y);
        else
            pGraphics.FillTextCode(X, Y, this.RecalcInfo.StyleCode);    //на отрисовку символа отправляем положение baseLine
    }
};
CMathText.prototype.setPosition = function(pos)
{
    if(this.RecalcInfo.bApostrophe == true)
    {
        this.pos.x = pos.x;
        this.pos.y = pos.y - this.rasterOffsetY;
    }
    else if (this.bJDraw == false)                      // for text
    {
        this.pos.x = pos.x;
        this.pos.y = pos.y;
    }
    else                                    // for symbol only drawing
    {
        this.pos.x = pos.x - this.rasterOffsetX;
        this.pos.y = pos.y - this.rasterOffsetY + this.size.ascent;
    }
};
CMathText.prototype.GetLocationOfLetter = function()
{
    var pos = new CMathPosition();

    if(this.RecalcInfo.bApostrophe)
    {
        pos.x = this.pos.x;
        pos.y = this.pos.y - this.size.ascent;
    }
    else
    {
        pos.x = this.pos.x;
        pos.y = this.pos.y;
    }

    return pos;
};
CMathText.prototype.Is_InclineLetter = function()
{
    var code = this.value;

    var bCapitale = (code > 0x0040 && code < 0x005B),
        bSmall = (code > 0x0060 && code < 0x007b) || code == 0x131 || code == 0x237;

    var bCapGreek   = (code > 0x0390 && code < 0x03AA),
        bSmallGreek = (code > 0x03B0 && code < 0x03CA);

    var bAlphabet    = bCapitale || bSmall || bCapGreek || bSmallGreek;

    var MPrp = this.Parent.GetCompiled_ScrStyles();

    var bRomanSerif  = (MPrp.sty == STY_BI || MPrp.sty == STY_ITALIC) && (MPrp.scr == TXT_ROMAN || MPrp.scr == TXT_SANS_SERIF),
        bScript      = MPrp.scr == TXT_SCRIPT;

    return bAlphabet && (bRomanSerif || bScript);
};
CMathText.prototype.IsJustDraw = function()
{
    return this.bJDraw;
};
CMathText.prototype.relate = function(Parent)
{
    this.Parent = Parent;
};
CMathText.prototype.IsAlignPoint = function()
{
    return false;
};
CMathText.prototype.IsText = function()
{
    return true;
};
CMathText.prototype.private_Is_BreakOperator = function(val)
{
    var rOper = q_Math_BreakOperators[val];

    return rOper == 1 || rOper == 2;
};
CMathText.prototype.Is_CompareOperator = function()
{
    return q_Math_BreakOperators[this.value] == 2;
};
CMathText.prototype.Is_LeftBracket = function()
{
    return this.value == 0x28 || this.value == 0x7B || this.value == 0x5B || this.value == 0x27E8 || this.value == 0x230A || this.value == 0x2308 || this.value == 0x27E6 || this.value == 0x2329;
};
CMathText.prototype.Is_RightBracket = function()
{
    return this.value == 0x29 || this.value == 0x7D || this.value == 0x5D || this.value == 0x27E9 || this.value == 0x230B || this.value == 0x2309 || this.value == 0x27E7 || this.value == 0x232A;
};
////
CMathText.prototype.setCoeffTransform = function(sx, shx, shy, sy)
{
    this.transform = {sx: sx, shx: shx, shy: shy, sy: sy};

    //здесь надо будет по-другому считать размер, после трансформации размер будет выставляться в g_oTextMeasurer
    //
    //MathControl.pGraph.transform(sx, shy, shx, sy, 0, 0);
    this.applyTransformation();

};
CMathText.prototype.applyTransformation = function()
{
    var sx = this.transform.sx, shx = this.transform.shx,
        shy = this.transform.shy, sy = this.transform.sy;
    sy = (sy < 0) ? -sy : sy;

    this.size.width = this.size.width*sx + (-1)*this.size.width*shx;
    this.size.height = this.size.height*sy + this.size.height*shy;
    this.size.ascent = this.size.ascent*(sy + shy);
    this.size.descent = this.size.descent*(sy + shy);
    this.size.center = this.size.center*(sy + shy);

};
CMathText.prototype.Copy = function()
{
    var NewLetter = new CMathText(this.bJDraw);
    NewLetter.Type  = this.Type;
    NewLetter.value = this.value;
    return NewLetter;
};
CMathText.prototype.Write_ToBinary = function(Writer)
{
    // Пишем тип дла раза, 1 раз для общей функции чтения, второй раз
    // для разделения обычного MathText от PlaceHolder
    Writer.WriteLong(this.Type);

    // Long : Type
    // Long : value
    Writer.WriteLong(this.Type);
    Writer.WriteLong(this.value) ;
};
CMathText.prototype.Read_FromBinary = function(Reader)
{
    this.Type  = Reader.GetLong();
    this.value = Reader.GetLong();

	if (AscFonts.IsCheckSymbols)
		AscFonts.FontPickerByCharacter.getFontBySymbol(this.value);
};
CMathText.prototype.Is_LetterCS = function()
{
    return this.FontSlot == fontslot_CS;
};
/*CMathText.prototype.Recalculate_Reset = function(StartRange, StartLine, PRS)
{
    var bNotUpdate = PRS !== null && PRS!== undefined && PRS.bFastRecalculate == true;
    if(bNotUpdate == false)
    {
        this.StartLine   = StartLine;
        this.StartRange  = StartRange;

        this.protected_ClearLines();
    }
};
CMathText.prototype.Recalculate_Range = function(PRS, ParaPr, Depth)
{
    var CurLine  = PRS.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range );

    var RangeStartPos = this.protected_AddRange(CurLine, CurRange);
    this.protected_FillRange(CurLine, CurRange, RangeStartPos, RangeEndPos);
};*/

/**
 *
 * @constructor
 * @extends {CMathBaseText}
 */
function CMathAmp()
{
	CMathBaseText.call(this);

    this.bAlignPoint = false;
    this.Type = para_Math_Ampersand;

    this.value = 0x26;
	if (AscFonts.IsCheckSymbols)
		AscFonts.FontPickerByCharacter.getFontBySymbol(this.value);

    this.AmpText = new CMathText(false);
    this.AmpText.add(this.value);
}
CMathAmp.prototype = Object.create(CMathBaseText.prototype);
CMathAmp.prototype.constructor = CMathAmp;
CMathAmp.prototype.Measure = function(oMeasure, TextPr, InfoMathText)
{
    this.bAlignPoint = InfoMathText.bEqArray == true && InfoMathText.bNormalText == false;
    this.AmpText.Measure(oMeasure, TextPr, InfoMathText);

    if(this.bAlignPoint)
    {
        this.size.width  = 0;
        this.size.ascent = 0;
        this.size.height = 0;
    }
    else
    {
        this.size.width   = this.AmpText.size.width;
        this.size.height  = this.AmpText.size.height;
        this.size.ascent  = this.AmpText.size.ascent;
    }

    this.Width = (this.size.width * TEXTWIDTH_DIVIDER) | 0;
};
CMathAmp.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI)
{
    this.Parent = Parent;
    this.AmpText.PreRecalc(Parent, ParaMath, ArgSize, RPI);

    this.bUpdateGaps = false;
};
CMathAmp.prototype.getCodeChr = function()
{
    var code = null;
    if(!this.bAlignPoint)
        code = this.AmpText.getCodeChr();

    return code;
};
CMathAmp.prototype.IsText = function()
{
    return !this.bAlignPoint;
};
CMathAmp.prototype.setPosition = function(pos)
{
    this.pos.x = pos.x;
    this.pos.y = pos.y;

    if(this.bAlignPoint == false)
        this.AmpText.setPosition(pos);
};
CMathAmp.prototype.relate = function(Parent)
{
    this.Parent = Parent;
    this.AmpText.relate(Parent);
};
CMathAmp.prototype.Draw = function(x, y, pGraphics, InfoTextPr)
{
    if(this.bAlignPoint == false)
        this.AmpText.Draw(x + this.GapLeft, y, pGraphics, InfoTextPr);
    else if(editor.ShowParaMarks) // показать метки выравнивания, если включена отметка о знаках параграфа
    {
        var X  = x + this.pos.x + this.Get_WidthVisible(),
            Y  = y + this.pos.y,
            Y2 = y + this.pos.y - this.AmpText.size.height;

        pGraphics.drawVerLine(0, X, Y, Y2, 0.1);
    }
};
CMathAmp.prototype.Is_InclineLetter = function()
{
    return false;
};
CMathAmp.prototype.IsAlignPoint = function()
{
    return this.bAlignPoint;
};
CMathAmp.prototype.Copy = function()
{
    return new CMathAmp();
};
CMathAmp.prototype.Write_ToBinary = function(Writer)
{
    // Long : Type
    Writer.WriteLong( this.Type );
};
CMathAmp.prototype.Read_FromBinary = function(Reader)
{
};

function CMathInfoTextPr(InfoTextPr)
{
    this.CurrType         = -1; // в первый раз Font всегда выставляем

    this.TextPr           = InfoTextPr.TextPr;
    this.ArgSize          = InfoTextPr.ArgSize;
    this.bApostrophe      = false;
    this.Font =
    {
        FontFamily:     {Name:  "Cambria Math", Index : -1},
        FontSize:       this.TextPr.FontSize,
        Italic:         false,
        Bold:           false
    };

    this.bNormalText     = InfoTextPr.bNormalText;
    this.bEqArray        = InfoTextPr.bEqArray;

    this.RFontsCompare = [];

    // скопируем эти свойства для SetFontSlot
    // для SpecialOperator нужны уже скомпилированные для мат текста текстовые настройки, поэтому важно эи свойства скопировать именно здесь, а не передавать в MathText обычные текст. настройки

    this.RFontsCompare[fontslot_ASCII]    = undefined !== this.TextPr.RFonts.Ascii && this.TextPr.RFonts.Ascii.Name == "Cambria Math";
    this.RFontsCompare[fontslot_HAnsi]    = undefined !== this.TextPr.RFonts.HAnsi && this.TextPr.RFonts.HAnsi.Name == "Cambria Math";
    this.RFontsCompare[fontslot_CS]       = undefined !== this.TextPr.RFonts.CS && this.TextPr.RFonts.CS.Name == "Cambria Math";
    this.RFontsCompare[fontslot_EastAsia] = undefined !== this.TextPr.RFonts.EastAsia && this.TextPr.RFonts.EastAsia.Name == "Cambria Math";
}
CMathInfoTextPr.prototype.NeedUpdateFont = function(code, fontSlot, IsPlaceholder, IsApostrophe)
{
    var NeedUpdateFont = false;
    var bMathText = this.bNormalText == false || IsPlaceholder === true;
    var Type;

    if(bMathText && (this.RFontsCompare[fontSlot] == true || IsPlaceholder))
        Type = MathTextInfo_MathText;
    else if(bMathText && this.RFontsCompare[fontSlot] == false && true === this.IsSpecilalOperator(code))
        Type = MathTextInfo_SpecialOperator;
    else
        Type = MathTextInfo_NormalText;

    var ArgSize = this.ArgSize;

    // CurrType -1 or MathTextInfo_NormalText
    if(this.CurrType !== MathTextInfo_MathText && this.CurrType !== MathTextInfo_SpecialOperator && Type !== MathTextInfo_NormalText)
    {
        NeedUpdateFont = true;
    }

    this.CurrType = Type;

    if(this.bApostrophe !== IsApostrophe && this.ArgSize < 0 && Type !== MathTextInfo_NormalText)
    {
        ArgSize = IsApostrophe == true ? 1 : this.ArgSize;
        this.bApostrophe = IsApostrophe;

        NeedUpdateFont = true;
    }

    if(NeedUpdateFont == true)
    {
        var FontSize = this.private_GetFontSize(fontSlot);
        var coeff = MatGetKoeffArgSize(FontSize, ArgSize);

        this.Font.FontSize = FontSize*coeff;
    }

    return NeedUpdateFont;
};
CMathInfoTextPr.prototype.private_GetFontSize = function(fontSlot)
{
    return fontSlot == fontslot_CS ? this.TextPr.FontSizeCS : this.TextPr.FontSize;
};
CMathInfoTextPr.prototype.GetFontKoef = function(fontSlot)
{
    var FontSize = this.private_GetFontSize(fontSlot);
    return MatGetKoeffArgSize(FontSize, this.ArgSize);
};
CMathInfoTextPr.prototype.GetFontSlot = function(code)
{
    var Hint = this.TextPr.RFonts.Hint;
    var bCS  = this.TextPr.CS;
    var bRTL = this.TextPr.RTL;
    var lcid = this.TextPr.Lang.EastAsia;

    return g_font_detector.Get_FontClass(code, Hint, lcid, bCS, bRTL);
};
CMathInfoTextPr.prototype.IsSpecilalOperator = function(val)
{
    var bSpecialOperator = false;

    // символы из интервала val >= 0x2E2 && val <= 0x36F есть, как правило, в шрифтах и используют именно их, а не заменяют символами из Cambria Math
    if(val >= 0x2190 && val <= 0x21E9)
    {
        bSpecialOperator = q_Math_Arrows[val] !== 0;
    }
    else if(val >= 0x21F4 && val <= 0x22FF)
    {
        bSpecialOperator = q_Math_SpecialEquals[val] !== 0;
    }
    else if(val >= 0x2701 && val <= 0x299A)
    {
        bSpecialOperator = val !== 0x2981;
    }
    else if(val >= 0x29F4 && val <= 0x2AFF)
    {
        bSpecialOperator = val !== 0x2AE1 && val !== 0x2AF1;
    }
    else
    {
        bSpecialOperator = q_Math_SpecialSymbols[val] == 1;
    }

    return bSpecialOperator;

};

var q_Math_Arrows =
{
    0x21B4: 0, 0x21B5: 0, 0x21B8: 0, 0x21B9: 0
};
var q_Math_SpecialEquals =
{
    0x2205: 0, 0x220E: 0, 0x221F: 0, 0x2220: 0, 0x2221: 0, 0x2222: 0, 0x223F: 0, 0x22BE: 0, 0x22BF: 0, 0x22A4: 0
};
var q_Math_SpecialSymbols =
{
    0x0021: 1, 0x0023: 1, 0x0028: 1, 0x0029: 1, 0x002A: 1, 0x002B: 1, 0x002C: 1, 0x002D: 1, 0x002E: 1, 0x002F: 1,
    0x003A: 1, 0x003B: 1, 0x003C: 1, 0x003D: 1, 0x003E: 1, 0x003F: 1, 0x005B: 1, 0x005C: 1, 0x005D: 1, 0x005E: 1,
    0x005F: 1, 0x007B: 1, 0x007C: 1, 0x007D: 1, 0x007E: 1, 0x00A1: 1, 0x00AC: 1, 0x00B1: 1, 0x00B7: 1, 0X00BF: 1,
    0x00D7: 1, 0x00F7: 1, 0x2010: 1, 0x2012: 1, 0x2013: 1, 0x2014: 1, 0x2016: 1, 0x2020: 1, 0x2021: 1, 0x2022: 1,
    0x2026: 1, 0x2140: 1, 0x2145: 1, 0x2146: 1, 0x2147: 1, 0x2148: 1, 0x2149: 1,
    0x2305: 1, 0x2306: 1, 0x2308: 1, 0x2309: 1, 0x230A: 1, 0x230B: 1, 0x231C: 1, 0x231D: 1, 0x231E: 1, 0x231F: 1,
    0x2322: 1, 0x2323: 1, 0x2329: 1, 0x232A: 1, 0x233D: 1, 0x233F: 1, 0x23B0: 1, 0x23B1: 1,
    0x29B6: 1, 0x29B7: 1, 0x29B8: 1, 0x29B9: 1, 0x29C0: 1, 0x29C1: 1, 0x29C4: 1, 0x29C5: 1, 0x29C6: 1, 0x29C7: 1,
    0x29C8: 1, 0x29CE: 1, 0x29CF: 1, 0x29D0: 1, 0x29D1: 1, 0x29D2: 1, 0x29D3: 1, 0x29D4: 1, 0x29D5: 1, 0x29D6: 1,
    0x29D7: 1, 0x29D8: 1, 0x29D9: 1, 0x29DA: 1, 0x29DB: 1, 0x29DF: 1, 0x29E1: 1, 0x29E2: 1, 0x29E3: 1, 0x29E4: 1,
    0x29E5: 1, 0x29E6: 1, 0x29EB: 1, 0x3014: 1, 0x3015: 1, 0x3016: 1, 0x3017: 1,
    0x1DC0: 1, 0x1DC1: 1, 0x1DC2: 1, 0x1DC3: 1
};
var q_Math_Apostrophe =
{
    0x2032: 1, 0x2033: 1,  0x2034 : 1, 0x2057: 1
};
var q_Math_BreakOperators =
{
    0x002A:	1, 0x002B:	1, 0x002D:	1, 0x002F:	1,0x003C:	2, 0x003D:	2,
    0x003E:	2, 0x005C:	1, 0x00B1:  1, 0x2190:	2, 0x2191:	2, 0x2192:	2,
    0x2193:	2,
    0x2194:	2, 0x2195:	2, 0x2196:	2, 0x2197:	2,0x2198:	2, 0x2199:	2,
    0x219A:	2, 0x219B:	2, 0x219C:	2, 0x219D:	2,0x219E:	2, 0x219F:	2,
    0x21A0:	2, 0x21A1:	2, 0x21A2:	2, 0x21A3:	2, 0x21A4:	2, 0x21A5:	2,
    0x21A6:	2, 0x21A7:	2, 0x21A8:	2, 0x21A9:	2, 0x21AA:	2, 0x21AB:	2,
    0x21AC:	2, 0x21AD:	2, 0x21AE:	2, 0x21AF:	2, 0x21B0:	2, 0x21B1:	2,
    0x21B2:	2, 0x21B3:	2,
    // check
    0x21B6:	2, 0x21B7:	2, 0x21BA:	2, 0x21BB:	2, 0x21BC:	2, 0x21BD:	2,
    0x21BE:	2, 0x21BF:	2, 0x21C0:	2, 0x21C1:	2, 0x21C2:	2, 0x21C3:	2,
    0x21C4:	2, 0x21C5:	2, 0x21C6:	2, 0x21C7:	2, 0x21C8:	2, 0x21C9:	2,
    0x21CA:	2, 0x21CB:	2, 0x21CC:	2, 0x21CD:	2, 0x21CE:	2, 0x21CF:	2,
    0x21D0:	2, 0x21D1:	2, 0x21D2:	2, 0x21D3:	2, 0x21D4:	2, 0x21D5:	2,
    0x21D6:	2, 0x21D7:	2, 0x21D8:	2, 0x21D9:	2, 0x21DA:	2, 0x21DB:	2,
    0x21DC:	2, 0x21DD:	2, 0x21DE:	2, 0x21DF:	2, 0x21E0:	2, 0x21E1:	2,
    0x21E2:	2, 0x21E3:	2, 0x21E4:	2, 0x21E5:	2, 0x21E6:	2, 0x21E7:	2,
    0x21E8:	2, 0x21E9:	2, 0x21F4:	2, 0x21F5:	2, 0x21F6:	2, 0x21F7:	2,
    0x21F8:	2, 0x21F9:	2, 0x21FA:	2, 0x21FB:	2, 0x21FC:	2, 0x21FD:	2,
    0x21FE:	2, 0x21FF:	2, 0x2208:	2, 0x2209:	2, 0x220A:	2, 0x220B:	2,
    0x220C:	2, 0x220D:	2, 0x2212:	1, 0x2213:	1, 0x2214:	1, 0x2215:	1,
    0x2216:	1, 0x2217:	1, 0x2218:	1, 0x2219:	1, 0x221D:	2, 0x2223:	2,
    0x2224:	2, 0x2225:	2, 0x2226:	2, 0x2227:	1, 0x2228:	1, 0x2229:	1,
    0x222A:	1, 0x2234:	2, 0x2235:	2, 0x2236:	2, 0x2237:	2, 0x2238:	1,
    0x2239:	2, 0x223A:	1, 0x223B:	2, 0x223C:	2, 0x223D:	2, 0x223E:	2,
    0x2240:	1, 0x2241:	2, 0x2242:	2, 0x2243:	2, 0x2244:	2, 0x2245:	2,
    0x2246:	2, 0x2247:	2, 0x2248:	2, 0x2249:	2, 0x224A:	2, 0x224B:	2,
    0x224C:	2, 0x224D:	2, 0x224E:	2, 0x224F:	2, 0x2250:	2, 0x2251:	2,
    0x2252:	2, 0x2253:	2, 0x2254:	2, 0x2255:	2, 0x2256:	2, 0x2257:	2,
    0x2258:	2, 0x2259:	2, 0x225A:	2, 0x225B:	2, 0x225C:	2, 0x225D:	2,
    0x225E:	2, 0x225F:	2, 0x2260:	2, 0x2261:	2, 0x2262:	2, 0x2263:	2,
    0x2264:	2, 0x2265:	2, 0x2266:	2, 0x2267:	2, 0x2268:	2, 0x2269:	2,
    0x226A:	2, 0x226B:	2, 0x226C:	2, 0x226D:	2, 0x226E:	2, 0x226F:	2,
    0x2270:	2, 0x2271:	2, 0x2272:	2, 0x2273:	2, 0x2274:	2, 0x2275:	2,
    0x2276:	2, 0x2277:	2, 0x2278:	2, 0x2279:	2, 0x227A:	2, 0x227B:	2,
    0x227C:	2, 0x227D:	2, 0x227E:	2, 0x227F:	2, 0x2280:	2, 0x2281:	2,
    0x2282:	2, 0x2283:	2, 0x2284:	2, 0x2285:	2, 0x2286:	2, 0x2287:	2,
    0x2288:	2, 0x2289:	2, 0x228A:	2, 0x228B:	2, 0x228C:	1, 0x228D:	1,
    0x228E:	1, 0x228F:	2, 0x2290:	2, 0x2291:	2, 0x2292:	2, 0x2293:	1,
    0x2294:	1, 0x2295:  1, 0x2296:  1, 0x2297:  1, 0x2298:  1, 0x2299:  1,
    0x229A: 1, 0x229B:  1, 0x229C:  1, 0x229D:  1, 0x229E:  1, 0x229F:  1,
    0x22A0: 1, 0x22A1:  1, 0x22A2:  2, 0x22A3:  2, 0x22A5:  2, 0x22A6:  2,
    0x22A7: 2, 0x22A8:  2, 0x22A9:  2, 0x22AA:  2, 0x22AB:  2, 0x22AC:  2,
    0x22AD: 2, 0x22AE:  2, 0x22AF:  2, 0x22B0:  2, 0x22B1:  2, 0x22B2:  2,
    0x22B3: 2, 0x22B4:  2, 0x22B5:  2, 0x22B6:  2, 0x22B7:  2, 0x22B8:  2,
    0x22B9: 2, 0x22BA:  1, 0x22BB:  1, 0x22BC:  1, 0x22BD:  1, 0x22C4:  1,
    0x22C5: 1, 0x22C6:  1, 0x22C7:  1, 0x22C8:  2, 0x22C9:  1, 0x22CA:  1,
    0x22CB: 1, 0x22CC:  1, 0x22CD:  2, 0x22CE:  1, 0x22CF:  1, 0x22D0:	2,
    0x22D1:	2, 0x22D2:	1, 0x22D3:	1, 0x22D4:	2,
    0x22D5:	2, 0x22D6:	2, 0x22D7:	2, 0x22D8:	2, 0x22D9:	2, 0x22DA:	2,
    0x22DB:	2, 0x22DC:	2, 0x22DD:	2, 0x22DE:	2, 0x22DF:	2, 0x22E0:	2,
    0x22E1:	2, 0x22E2:	2, 0x22E3:	2, 0x22E4:	2, 0x22E5:	2, 0x22E6:	2,
    0x22E7:	2, 0x22E8:	2, 0x22E9:	2, 0x22EA:	2, 0x22EB:	2, 0x22EC:  2,
    0x22ED: 2, 0x22EE:  2, 0x22EF:  2, 0x22F0:  2, 0x22F1:  2, 0x22F2:  2,
    0x22F3: 2, 0x22F4:  2, 0x22F5:  2, 0x22F6:  2, 0x22F7:  2, 0x22F8:  2,
    0x22F9: 2, 0x22FA:  2, 0x22FB:  2, 0x22FC:  2, 0x22FD:  2, 0x22FE:  2,
    0x22FF: 2, 0x2305:  1, 0x2306:  1, 0x2322:  2, 0x2323:  2, 0x233D:  1,
    0x233F: 2, 0x23B0:  2, 0x23B1:  2, 0x25B3:  1, 0x25CA:  1, 0x25CB:  1,
    0x27D1: 1, 0x27D2:  2, 0x27D3:  2, 0x27D4:  2, 0x27DA:  2, 0x27DB:  2,
    0x27DC:	2, 0x27DD:	2, 0x27DE:	2, 0x27DF:  2, 0x27E0:  1, 0x27E1:  1,
    0x27E2: 1, 0x27E3:  1, 0x27E4:  1, 0x27E5:  1, 0x27F0:  2, 0x27F1:  2,
    0x27F2: 2, 0x27F3:  2, 0x27F4:  2,
    //end check
    0x27F5:	2, 0x27F6:	2, 0x27F7:	2, 0x27F8:	2, 0x27F9:	2, 0x27FA:	2,
    0x27FB:	2, 0x27FC:	2, 0x27FD:	2, 0x27FE:	2, 0x27FF:	2, 0x2900:	2,
    0x2901:	2, 0x2902:	2, 0x2903:	2, 0x2904:	2, 0x2905:	2, 0x2906:	2,
    0x2907:	2, 0x2908:	2, 0x2909:	2, 0x290A:	2, 0x290B:	2, 0x290C:	2,
    0x290D:	2, 0x290E:	2, 0x290F:	2, 0x2910:	2, 0x2911:	2, 0x2912:	2,
    0x2913:	2, 0x2914:	2, 0x2915:	2, 0x2916:	2, 0x2917:	2, 0x2918:	2,
    0x2919:	2, 0x291A:	2, 0x291B:	2, 0x291C:	2, 0x291D:	2, 0x291E:	2,
    0x291F:	2, 0x2920:	2, 0x2921:	2, 0x2922:	2, 0x2923:	2, 0x2924:	2,
    0x2925:	2, 0x2926:	2, 0x2927:	2, 0x2928:	2, 0x2929:	2, 0x292A:	2,
    0x292B:	2, 0x292C:	2, 0x292D:	2, 0x292E:	2, 0x292F:	2, 0x2930:	2,
    0x2931:	2, 0x2932:	2, 0x2933:	2, 0x2934:	2, 0x2935:	2, 0x2936:	2,
    0x2937:	2, 0x2938:	2, 0x2939:	2, 0x293A:	2, 0x293B:	2, 0x293C:	2,
    0x293D:	2, 0x293E:	2, 0x293F:	2, 0x2940:	2, 0x2941:	2, 0x2942:	2,
    0x2943:	2, 0x2944:	2, 0x2945:	2, 0x2946:	2, 0x2947:	2, 0x2948:	2,
    0x2949:	2, 0x294A:	2, 0x294B:	2, 0x294C:	2, 0x294D:	2, 0x294E:	2,
    0x294F:	2, 0x2950:	2, 0x2951:	2, 0x2952:	2, 0x2953:	2, 0x2954:	2,
    0x2955:	2, 0x2956:	2, 0x2957:	2, 0x2958:	2, 0x2959:	2, 0x295A:	2,
    0x295B:	2, 0x295C:	2, 0x295D:	2, 0x295E:	2, 0x295F:	2, 0x2960:	2,
    0x2961:	2, 0x2962:	2, 0x2963:	2, 0x2964:	2, 0x2965:	2, 0x2966:	2,
    0x2967:	2, 0x2968:	2, 0x2969:	2, 0x296A:	2, 0x296B:	2, 0x296C:	2,
    0x296D:	2, 0x296E:	2, 0x296F:	2, 0x2970:	2, 0x2971:	2, 0x2972:	2,
    0x2973:	2, 0x2974:	2, 0x2975:	2, 0x2976:	2, 0x2977:	2, 0x2978:	2,
    0x2979:	2, 0x297A:	2, 0x297B:	2, 0x2A52:	1, 0x2A53:	1, 0x2A54:	1,
    0x2A55:	1, 0x2A56:	1, 0x2A57:	1, 0x2A58:	1, 0x2A59:	1, 0x2A5A:	1,
    0x2A5B:	1, 0x2A5C:	1, 0x2A5D:	1, 0x2A5E:	1, 0x2A5F:	1, 0x2A60:	1,
    0x2A61:	1, 0x2A62:	1, 0x2A63:	1, 0x2A64:	1, 0x2A65:	1, 0x2A66:	2,
    0x2A67:	2, 0x2A68:	2, 0x2A69:	2, 0x2A6A:	2, 0x2A6B:	2, 0x2A6C:	2,
    0x2A6D:	2, 0x2A6E:	2, 0x2A6F:	2, 0x2A70:	2, 0x2A71:	1, 0x2A72:	1,
    0x2A73:	2, 0x2A74:	2, 0x2A75:	2, 0x2A76:	2, 0x2A77:	2, 0x2A78:	2,
    0x2A79:	2, 0x2A7A:	2, 0x2A7B:	2, 0x2A7C:	2, 0x2A7D:	2, 0x2A7E:	2,
    0x2A7F:	2, 0x2A80:	2, 0x2A81:	2, 0x2A82:	2, 0x2A83:	2, 0x2A84:	2,
    0x2A85:	2, 0x2A86:	2, 0x2A87:	2, 0x2A88:	2, 0x2A89:	2, 0x2A8A:	2,
    0x2A8B:	2, 0x2A8C:	2, 0x2A8D:	2, 0x2A8E:	2, 0x2A8F:	2, 0x2A90:	2,
    0x2A91:	2, 0x2A92:	2, 0x2A93:	2, 0x2A94:	2, 0x2A95:	2, 0x2A96:	2,
    0x2A97:	2, 0x2A98:	2, 0x2A99:	2, 0x2A9A:	2, 0x2A9B:	2, 0x2A9C:	2,
    0x2A9D:	2, 0x2A9E:	2, 0x2A9F:	2, 0x2AA0:	2, 0x2AA1:	2, 0x2AA2:	2,
    0x2AA3:	2, 0x2AA4:	2, 0x2AA5:	2, 0x2AA6:	2, 0x2AA7:	2, 0x2AA8:	2,
    0x2AA9:	2, 0x2AAA:	2, 0x2AAB:	2, 0x2AAC:	2, 0x2AAD:	2, 0x2AAE:	2,
    0x2AAF:	2, 0x2AB0:	2, 0x2AB1:	2, 0x2AB2:	2, 0x2AB3:	2, 0x2AB4:	2,
    0x2AB5:	2, 0x2AB6:	2, 0x2AB7:	2, 0x2AB8:	2, 0x2AB9:	2, 0x2ABA:	2,
    0x2ABB:	2, 0x2ABC:	2, 0x2ABD:	2, 0x2ABE:	2, 0x2ABF:	2, 0x2AC0:	2,
    0x2AC1:	2, 0x2AC2:	2, 0x2AC3:	2, 0x2AC4:	2, 0x2AC5:	2, 0x2AC6:	2,
    0x2AC7:	2, 0x2AC8:	2, 0x2AC9:	2, 0x2ACA:	2, 0x2ACB:	2, 0x2ACC:	2,
    0x2ACD:	2, 0x2ACE:	2, 0x2ACF:	2, 0x2AD0:	2, 0x2AD1:	2, 0x2AD2:	2,
    0x2AD3:	2, 0x2AD4:	2, 0x2AD5:	2, 0x2AD6:	2, 0x2AD7:	2, 0x2AD8:	2,
    0x2AD9:	2, 0x2ADA:	2, 0x2ADB:	2, 0x2ADC:	2, 0x2ADD:	2,
    0x00D7: 1, 0x00F7:  1
};



/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var History = AscCommon.History;


/** @enum {number} */
var c_oAscMathType = {
    //----------------------------------------------------------------------------------------------------------------------
    Symbol_pm                               : 0x00000000,
    Symbol_infinity                         : 0x00000001,
    Symbol_equals                           : 0x00000002,
    Symbol_neq                              : 0x00000003,
    Symbol_about                            : 0x00000004,
    Symbol_times                            : 0x00000005,
    Symbol_div                              : 0x00000006,
    Symbol_factorial                        : 0x00000007,
    Symbol_propto                           : 0x00000008,
    Symbol_less                             : 0x00000009,
    Symbol_ll                               : 0x0000000a,
    Symbol_greater                          : 0x0000000b,
    Symbol_gg                               : 0x0000000c,
    Symbol_leq                              : 0x0000000d,
    Symbol_geq                              : 0x0000000e,
    Symbol_mp                               : 0x0000000f,
    Symbol_cong                             : 0x00000010,
    Symbol_approx                           : 0x00000011,
    Symbol_equiv                            : 0x00000012,
    Symbol_forall                           : 0x00000013,
    Symbol_additional                       : 0x00000014,
    Symbol_partial                          : 0x00000015,
    Symbol_sqrt                             : 0x00000016,
    Symbol_cbrt                             : 0x00000017,
    Symbol_qdrt                             : 0x00000018,
    Symbol_cup                              : 0x00000019,
    Symbol_cap                              : 0x0000001a,
    Symbol_emptyset                         : 0x0000001b,
    Symbol_percent                          : 0x0000001c,
    Symbol_degree                           : 0x0000001d,
    Symbol_fahrenheit                       : 0x0000001e,
    Symbol_celsius                          : 0x0000001f,
    Symbol_inc                              : 0x00000020,
    Symbol_nabla                            : 0x00000021,
    Symbol_exists                           : 0x00000022,
    Symbol_notexists                        : 0x00000023,
    Symbol_in                               : 0x00000024,
    Symbol_ni                               : 0x00000025,
    Symbol_leftarrow                        : 0x00000026,
    Symbol_uparrow                          : 0x00000027,
    Symbol_rightarrow                       : 0x00000028,
    Symbol_downarrow                        : 0x00000029,
    Symbol_leftrightarrow                   : 0x0000002a,
    Symbol_therefore                        : 0x0000002b,
    Symbol_plus                             : 0x0000002c,
    Symbol_minus                            : 0x0000002d,
    Symbol_not                              : 0x0000002e,
    Symbol_ast                              : 0x0000002f,
    Symbol_bullet                           : 0x00000030,
    Symbol_vdots                            : 0x00000031,
    Symbol_cdots                            : 0x00000032,
    Symbol_rddots                           : 0x00000033,
    Symbol_ddots                            : 0x00000034,
    Symbol_aleph                            : 0x00000035,
    Symbol_beth                             : 0x00000036,
    Symbol_QED                              : 0x00000037,
    Symbol_alpha                            : 0x00010000,
    Symbol_beta                             : 0x00010001,
    Symbol_gamma                            : 0x00010002,
    Symbol_delta                            : 0x00010003,
    Symbol_varepsilon                       : 0x00010004,
    Symbol_epsilon                          : 0x00010005,
    Symbol_zeta                             : 0x00010006,
    Symbol_eta                              : 0x00010007,
    Symbol_theta                            : 0x00010008,
    Symbol_vartheta                         : 0x00010009,
    Symbol_iota                             : 0x0001000a,
    Symbol_kappa                            : 0x0001000b,
    Symbol_lambda                           : 0x0001000c,
    Symbol_mu                               : 0x0001000d,
    Symbol_nu                               : 0x0001000e,
    Symbol_xsi                              : 0x0001000f,
    Symbol_o                                : 0x00010010,
    Symbol_pi                               : 0x00010011,
    Symbol_varpi                            : 0x00010012,
    Symbol_rho                              : 0x00010013,
    Symbol_varrho                           : 0x00010014,
    Symbol_sigma                            : 0x00010015,
    Symbol_varsigma                         : 0x00010016,
    Symbol_tau                              : 0x00010017,
    Symbol_upsilon                          : 0x00010018,
    Symbol_varphi                           : 0x00010019,
    Symbol_phi                              : 0x0001001a,
    Symbol_chi                              : 0x0001001b,
    Symbol_psi                              : 0x0001001c,
    Symbol_omega                            : 0x0001001d,
    Symbol_Alpha                            : 0x00020000,
    Symbol_Beta                             : 0x00020001,
    Symbol_Gamma                            : 0x00020002,
    Symbol_Delta                            : 0x00020003,
    Symbol_Epsilon                          : 0x00020004,
    Symbol_Zeta                             : 0x00020005,
    Symbol_Eta                              : 0x00020006,
    Symbol_Theta                            : 0x00020007,
    Symbol_Iota                             : 0x00020008,
    Symbol_Kappa                            : 0x00020009,
    Symbol_Lambda                           : 0x0002000a,
    Symbol_Mu                               : 0x0002000b,
    Symbol_Nu                               : 0x0002000c,
    Symbol_Xsi                              : 0x0002000d,
    Symbol_O                                : 0x0002000e,
    Symbol_Pi                               : 0x0002000f,
    Symbol_Rho                              : 0x00020010,
    Symbol_Sigma                            : 0x00020011,
    Symbol_Tau                              : 0x00020012,
    Symbol_Upsilon                          : 0x00020013,
    Symbol_Phi                              : 0x00020014,
    Symbol_Chi                              : 0x00020015,
    Symbol_Psi                              : 0x00020016,
    Symbol_Omega                            : 0x00020017,
    //----------------------------------------------------------------------------------------------------------------------
    FractionVertical                        : 0x01000000,
    FractionDiagonal                        : 0x01000001,
    FractionHorizontal                      : 0x01000002,
    FractionSmall                           : 0x01000003,
    FractionDifferential_1                  : 0x01010000,
    FractionDifferential_2                  : 0x01010001,
    FractionDifferential_3                  : 0x01010002,
    FractionDifferential_4                  : 0x01010003,
    FractionPi_2                            : 0x01010004,
    //----------------------------------------------------------------------------------------------------------------------
    ScriptSup                               : 0x02000000,
    ScriptSub                               : 0x02000001,
    ScriptSubSup                            : 0x02000002,
    ScriptSubSupLeft                        : 0x02000003,
    ScriptCustom_1                          : 0x02010000,
    ScriptCustom_2                          : 0x02010001,
    ScriptCustom_3                          : 0x02010002,
    ScriptCustom_4                          : 0x02010003,
    //----------------------------------------------------------------------------------------------------------------------
    RadicalSqrt                             : 0x03000000,
    RadicalRoot_n                           : 0x03000001,
    RadicalRoot_2                           : 0x03000002,
    RadicalRoot_3                           : 0x03000003,
    RadicalCustom_1                         : 0x03010000,
    RadicalCustom_2                         : 0x03010001,
    //----------------------------------------------------------------------------------------------------------------------
    Integral                                : 0x04000000,
    IntegralSubSup                          : 0x04000001,
    IntegralCenterSubSup                    : 0x04000002,
    IntegralDouble                          : 0x04000003,
    IntegralDoubleSubSup                    : 0x04000004,
    IntegralDoubleCenterSubSup              : 0x04000005,
    IntegralTriple                          : 0x04000006,
    IntegralTripleSubSup                    : 0x04000007,
    IntegralTripleCenterSubSup              : 0x04000008,
    IntegralOriented                        : 0x04010000,
    IntegralOrientedSubSup                  : 0x04010001,
    IntegralOrientedCenterSubSup            : 0x04010002,
    IntegralOrientedDouble                  : 0x04010003,
    IntegralOrientedDoubleSubSup            : 0x04010004,
    IntegralOrientedDoubleCenterSubSup      : 0x04010005,
    IntegralOrientedTriple                  : 0x04010006,
    IntegralOrientedTripleSubSup            : 0x04010007,
    IntegralOrientedTripleCenterSubSup      : 0x04010008,
    Integral_dx                             : 0x04020000,
    Integral_dy                             : 0x04020001,
    Integral_dtheta                         : 0x04020002,
    //----------------------------------------------------------------------------------------------------------------------
    LargeOperator_Sum                       : 0x05000000,
    LargeOperator_Sum_CenterSubSup          : 0x05000001,
    LargeOperator_Sum_SubSup                : 0x05000002,
    LargeOperator_Sum_CenterSub             : 0x05000003,
    LargeOperator_Sum_Sub                   : 0x05000004,
    LargeOperator_Prod                      : 0x05010000,
    LargeOperator_Prod_CenterSubSup         : 0x05010001,
    LargeOperator_Prod_SubSup               : 0x05010002,
    LargeOperator_Prod_CenterSub            : 0x05010003,
    LargeOperator_Prod_Sub                  : 0x05010004,
    LargeOperator_CoProd                    : 0x05010005,
    LargeOperator_CoProd_CenterSubSup       : 0x05010006,
    LargeOperator_CoProd_SubSup             : 0x05010007,
    LargeOperator_CoProd_CenterSub          : 0x05010008,
    LargeOperator_CoProd_Sub                : 0x05010009,
    LargeOperator_Union                     : 0x05020000,
    LargeOperator_Union_CenterSubSup        : 0x05020001,
    LargeOperator_Union_SubSup              : 0x05020002,
    LargeOperator_Union_CenterSub           : 0x05020003,
    LargeOperator_Union_Sub                 : 0x05020004,
    LargeOperator_Intersection              : 0x05020005,
    LargeOperator_Intersection_CenterSubSup : 0x05020006,
    LargeOperator_Intersection_SubSup       : 0x05020007,
    LargeOperator_Intersection_CenterSub    : 0x05020008,
    LargeOperator_Intersection_Sub          : 0x05020009,
    LargeOperator_Disjunction               : 0x05030000,
    LargeOperator_Disjunction_CenterSubSup  : 0x05030001,
    LargeOperator_Disjunction_SubSup        : 0x05030002,
    LargeOperator_Disjunction_CenterSub     : 0x05030003,
    LargeOperator_Disjunction_Sub           : 0x05030004,
    LargeOperator_Conjunction               : 0x05030005,
    LargeOperator_Conjunction_CenterSubSup  : 0x05030006,
    LargeOperator_Conjunction_SubSup        : 0x05030007,
    LargeOperator_Conjunction_CenterSub     : 0x05030008,
    LargeOperator_Conjunction_Sub           : 0x05030009,
    LargeOperator_Custom_1                  : 0x05040000,
    LargeOperator_Custom_2                  : 0x05040001,
    LargeOperator_Custom_3                  : 0x05040002,
    LargeOperator_Custom_4                  : 0x05040003,
    LargeOperator_Custom_5                  : 0x05040004,
    //----------------------------------------------------------------------------------------------------------------------
    Bracket_Round                           : 0x06000000,
    Bracket_Square                          : 0x06000001,
    Bracket_Curve                           : 0x06000002,
    Bracket_Angle                           : 0x06000003,
    Bracket_LowLim                          : 0x06000004,
    Bracket_UppLim                          : 0x06000005,
    Bracket_Line                            : 0x06000006,
    Bracket_LineDouble                      : 0x06000007,
    Bracket_Square_OpenOpen                 : 0x06000008,
    Bracket_Square_CloseClose               : 0x06000009,
    Bracket_Square_CloseOpen                : 0x0600000a,
    Bracket_SquareDouble                    : 0x0600000b,
    Bracket_Round_Delimiter_2               : 0x06010000,
    Bracket_Curve_Delimiter_2               : 0x06010001,
    Bracket_Angle_Delimiter_2               : 0x06010002,
    Bracket_Angle_Delimiter_3               : 0x06010003,
    Bracket_Round_OpenNone                  : 0x06020000,
    Bracket_Round_NoneOpen                  : 0x06020001,
    Bracket_Square_OpenNone                 : 0x06020002,
    Bracket_Square_NoneOpen                 : 0x06020003,
    Bracket_Curve_OpenNone                  : 0x06020004,
    Bracket_Curve_NoneOpen                  : 0x06020005,
    Bracket_Angle_OpenNone                  : 0x06020006,
    Bracket_Angle_NoneOpen                  : 0x06020007,
    Bracket_LowLim_OpenNone                 : 0x06020008,
    Bracket_LowLim_NoneNone                 : 0x06020009,
    Bracket_UppLim_OpenNone                 : 0x0602000a,
    Bracket_UppLim_NoneOpen                 : 0x0602000b,
    Bracket_Line_OpenNone                   : 0x0602000c,
    Bracket_Line_NoneOpen                   : 0x0602000d,
    Bracket_LineDouble_OpenNone             : 0x0602000e,
    Bracket_LineDouble_NoneOpen             : 0x0602000f,
    Bracket_SquareDouble_OpenNone           : 0x06020010,
    Bracket_SquareDouble_NoneOpen           : 0x06020011,
    Bracket_Custom_1                        : 0x06030000,
    Bracket_Custom_2                        : 0x06030001,
    Bracket_Custom_3                        : 0x06030002,
    Bracket_Custom_4                        : 0x06030003,
    Bracket_Custom_5                        : 0x06040000,
    Bracket_Custom_6                        : 0x06040001,
    Bracket_Custom_7                        : 0x06040002,
    //----------------------------------------------------------------------------------------------------------------------
    Function_Sin                            : 0x07000000,
    Function_Cos                            : 0x07000001,
    Function_Tan                            : 0x07000002,
    Function_Csc                            : 0x07000003,
    Function_Sec                            : 0x07000004,
    Function_Cot                            : 0x07000005,
    Function_1_Sin                          : 0x07010000,
    Function_1_Cos                          : 0x07010001,
    Function_1_Tan                          : 0x07010002,
    Function_1_Csc                          : 0x07010003,
    Function_1_Sec                          : 0x07010004,
    Function_1_Cot                          : 0x07010005,
    Function_Sinh                           : 0x07020000,
    Function_Cosh                           : 0x07020001,
    Function_Tanh                           : 0x07020002,
    Function_Csch                           : 0x07020003,
    Function_Sech                           : 0x07020004,
    Function_Coth                           : 0x07020005,
    Function_1_Sinh                         : 0x07030000,
    Function_1_Cosh                         : 0x07030001,
    Function_1_Tanh                         : 0x07030002,
    Function_1_Csch                         : 0x07030003,
    Function_1_Sech                         : 0x07030004,
    Function_1_Coth                         : 0x07030005,
    Function_Custom_1                       : 0x07040000,
    Function_Custom_2                       : 0x07040001,
    Function_Custom_3                       : 0x07040002,
    //----------------------------------------------------------------------------------------------------------------------
    Accent_Dot                              : 0x08000000,
    Accent_DDot                             : 0x08000001,
    Accent_DDDot                            : 0x08000002,
    Accent_Hat                              : 0x08000003,
    Accent_Check                            : 0x08000004,
    Accent_Accent                           : 0x08000005,
    Accent_Grave                            : 0x08000006,
    Accent_Smile                            : 0x08000007,
    Accent_Tilde                            : 0x08000008,
    Accent_Bar                              : 0x08000009,
    Accent_DoubleBar                        : 0x0800000a,
    Accent_CurveBracketTop                  : 0x0800000b,
    Accent_CurveBracketBot                  : 0x0800000c,
    Accent_GroupTop                         : 0x0800000d,
    Accent_GroupBot                         : 0x0800000e,
    Accent_ArrowL                           : 0x0800000f,
    Accent_ArrowR                           : 0x08000010,
    Accent_ArrowD                           : 0x08000011,
    Accent_HarpoonL                         : 0x08000012,
    Accent_HarpoonR                         : 0x08000013,
    Accent_BorderBox                        : 0x08010000,
    Accent_BorderBoxCustom                  : 0x08010001,
    Accent_BarTop                           : 0x08020000,
    Accent_BarBot                           : 0x08020001,
    Accent_Custom_1                         : 0x08030000,
    Accent_Custom_2                         : 0x08030001,
    Accent_Custom_3                         : 0x08030002,
    //----------------------------------------------------------------------------------------------------------------------
    LimitLog_LogBase                        : 0x09000000,
    LimitLog_Log                            : 0x09000001,
    LimitLog_Lim                            : 0x09000002,
    LimitLog_Min                            : 0x09000003,
    LimitLog_Max                            : 0x09000004,
    LimitLog_Ln                             : 0x09000005,
    LimitLog_Custom_1                       : 0x09010000,
    LimitLog_Custom_2                       : 0x09010001,
    //----------------------------------------------------------------------------------------------------------------------
    Operator_ColonEquals                    : 0x0a000000,
    Operator_EqualsEquals                   : 0x0a000001,
    Operator_PlusEquals                     : 0x0a000002,
    Operator_MinusEquals                    : 0x0a000003,
    Operator_Definition                     : 0x0a000004,
    Operator_UnitOfMeasure                  : 0x0a000005,
    Operator_DeltaEquals                    : 0x0a000006,
    Operator_ArrowL_Top                     : 0x0a010000,
    Operator_ArrowR_Top                     : 0x0a010001,
    Operator_ArrowL_Bot                     : 0x0a010002,
    Operator_ArrowR_Bot                     : 0x0a010003,
    Operator_DoubleArrowL_Top               : 0x0a010004,
    Operator_DoubleArrowR_Top               : 0x0a010005,
    Operator_DoubleArrowL_Bot               : 0x0a010006,
    Operator_DoubleArrowR_Bot               : 0x0a010007,
    Operator_ArrowD_Top                     : 0x0a010008,
    Operator_ArrowD_Bot                     : 0x0a010009,
    Operator_DoubleArrowD_Top               : 0x0a01000a,
    Operator_DoubleArrowD_Bot               : 0x0a01000b,
    Operator_Custom_1                       : 0x0a020000,
    Operator_Custom_2                       : 0x0a020001,
    //----------------------------------------------------------------------------------------------------------------------
    Matrix_1_2                              : 0x0b000000,
    Matrix_2_1                              : 0x0b000001,
    Matrix_1_3                              : 0x0b000002,
    Matrix_3_1                              : 0x0b000003,
    Matrix_2_2                              : 0x0b000004,
    Matrix_2_3                              : 0x0b000005,
    Matrix_3_2                              : 0x0b000006,
    Matrix_3_3                              : 0x0b000007,
    Matrix_Dots_Center                      : 0x0b010000,
    Matrix_Dots_Baseline                    : 0x0b010001,
    Matrix_Dots_Vertical                    : 0x0b010002,
    Matrix_Dots_Diagonal                    : 0x0b010003,
    Matrix_Identity_2                       : 0x0b020000,
    Matrix_Identity_2_NoZeros               : 0x0b020001,
    Matrix_Identity_3                       : 0x0b020002,
    Matrix_Identity_3_NoZeros               : 0x0b020003,
    Matrix_2_2_RoundBracket                 : 0x0b030000,
    Matrix_2_2_SquareBracket                : 0x0b030001,
    Matrix_2_2_LineBracket                  : 0x0b030002,
    Matrix_2_2_DLineBracket                 : 0x0b030003,
    Matrix_Flat_Round                       : 0x0b040000,
    Matrix_Flat_Square                      : 0x0b040001,
    //----------------------------------------------------------------------------------------------------------------------
    Default_Text                            : 0x0c000000
};

function CRPI()
{
    this.bDecreasedComp            = false;
    this.bInline                   = false;
    this.bChangeInline             = false;
    this.bNaryInline               = false; /*для CDegreeSupSub внутри N-арного оператора, этот флаг необходим, чтобы итераторы максимально близко друг к другу расположить*/
    this.bEqArray                  = false; /*для амперсанда*/
    this.bMathFunc                 = false;
    this.bRecalcCtrPrp             = false; // пересчет ctrPrp нужен, когда на Undo и тп изменился размер первого Run, а ctrPrp уже для мат объектов пересчитались
    this.bCorrect_ConvertFontSize  = false;
    this.bSmallFraction            = false;
}
CRPI.prototype.MergeMathInfo = function(MathInfo)
{
    this.bInline                   = MathInfo.bInline || (MathInfo.bInternalRanges == true && MathInfo.bStartRanges == false);
    this.bRecalcCtrPrp             = MathInfo.bRecalcCtrPrp;
    this.bChangeInline             = MathInfo.bChangeInline;
    this.bCorrect_ConvertFontSize  = MathInfo.bCorrect_ConvertFontSize;
};

function CMathPointInfo()
{
    this.x    = 0;
    this.y    = 0;

    this.bEven      = true;
    this.CurrPoint  = 0;

    this.InfoPoints = {};
}
CMathPointInfo.prototype.SetInfoPoints = function(InfoPoints)
{
    this.InfoPoints.GWidths       = InfoPoints.GWidths;
    this.InfoPoints.GPoints       = InfoPoints.GPoints;
    this.InfoPoints.ContentPoints = InfoPoints.ContentPoints.Widths;
    this.InfoPoints.GMaxDimWidths = InfoPoints.GMaxDimWidths;
};
CMathPointInfo.prototype.NextAlignRange = function()
{
    if(this.bEven)
        this.bEven = false;
    else
    {
        this.CurrPoint++;
        this.bEven = true;
    }
};
CMathPointInfo.prototype.GetAlign = function()
{
    var align = 0;

    if(this.bEven)
    {
        var alignEven, alignGeneral, alignOdd;

        var Len   = this.InfoPoints.ContentPoints.length,
            Point = this.InfoPoints.ContentPoints[this.CurrPoint];

        var GWidth = this.InfoPoints.GWidths[this.CurrPoint],
            GPoint = this.InfoPoints.GPoints[this.CurrPoint];

        if(this.CurrPoint == Len - 1 && Point.odd == -1) // то есть последняя точка четная, выравнивание по центру
        {
            var GMaxDimWidth = this.InfoPoints.GMaxDimWidths[this.CurrPoint];

            alignGeneral = (GMaxDimWidth - Point.even)/2;
            alignEven = 0;
        }
        else
        {
            alignGeneral = (GWidth - GPoint.even - GPoint.odd)/2;
            alignEven = GPoint.even - Point.even;
        }

        if(this.CurrPoint > 0)
        {
            var PrevGenPoint = this.InfoPoints.GPoints[this.CurrPoint-1],
                PrevGenWidth = this.InfoPoints.GWidths[this.CurrPoint-1],
                PrevPoint    = this.InfoPoints.ContentPoints[this.CurrPoint-1];

            var alignPrevGen = (PrevGenWidth - PrevGenPoint.even - PrevGenPoint.odd)/2;
            alignOdd = alignPrevGen +  PrevGenPoint.odd - PrevPoint.odd;
        }
        else
            alignOdd = 0;

        align = alignGeneral + alignEven + alignOdd;
    }

    return align;
};

function CInfoPoints()
{
    this.GWidths       = null;
    this.GPoints       = null;
    this.GMaxDimWidths = null;
    this.ContentPoints = new AmperWidths();
}
CInfoPoints.prototype.SetDefault = function()
{
    this.GWidths       = null;
    this.GPoints       = null;
    this.GMaxDimWidths = null;
    this.ContentPoints.SetDefault();
};

function CMathPosInfo()
{
    this.CurRange = -1;
    this.CurLine  = -1;

    this.DispositionOpers = null;
}

function CMathPosition()
{
    this.x  = 0;
    this.y  = 0;
}
CMathPosition.prototype.Set = function(Pos)
{
    this.x = Pos.x;
    this.y = Pos.y;
};

function AmperWidths()
{
    this.bEven     = true; // является ли текущая точка нечетной
    this.Widths    = [];
}
AmperWidths.prototype.UpdatePoint = function(value)
{
    var len = this.Widths.length;

    if(len == 0)
    {
        // дефолтное значение bEven true, для случая если первый элемент в контенте будет Ampersand
        var NewPoint = new CMathPoint();
        NewPoint.even = value;
        this.Widths.push(NewPoint);
        this.bEven = true;
    }
    else
    {
        if(this.bEven)
            this.Widths[len-1].even += value;
        else
            this.Widths[len-1].odd += value;
    }

};
AmperWidths.prototype.AddNewAlignRange = function()
{
    var len = this.Widths.length;

    if(!this.bEven || len == 0)
    {
        var NewPoint = new CMathPoint();
        NewPoint.even = 0;
        this.Widths.push(NewPoint);
    }

    if(this.bEven)
    {
        len = this.Widths.length;
        this.Widths[len-1].odd = 0;
    }


    this.bEven = !this.bEven;

};
AmperWidths.prototype.SetDefault = function()
{
    this.bEven         = true;
    this.Widths.length = 0;
};


function CGeneralObjectGaps(Left, Right)
{
    this.left  = Left;
    this.right = Right;
}

function CGaps(oSign, oEqual, oZeroOper, oLett)
{
    this.sign = oSign;
    this.equal = oEqual;
    this.zeroOper = oZeroOper;
    this.letters = oLett;
}

function CCoeffGaps()
{
    var LeftSign  = new CGaps(0.52, 0.26, 0, 0.52),
        RightSign = new CGaps(0.49, 0, 0, 0.49);

    this.Sign = new CGeneralObjectGaps(LeftSign, RightSign);

    var LeftMult  = new CGaps(0, 0, 0, 0.46),
        RightMult = new CGaps(0, 0, 0, 0.49);

    this.Mult = new CGeneralObjectGaps(LeftMult, RightMult);

    var LeftEqual  = new CGaps(0, 0, 0, 0.7),
        RightEqual = new CGaps(0, 0, 0, 0.5);

    this.Equal = new CGeneralObjectGaps(LeftEqual, RightEqual);

    var LeftDefault  = new CGaps(0, 0, 0, 0),
        RightDefault = new CGaps(0, 0, 0, 0);

    this.Default = new CGeneralObjectGaps(LeftDefault, RightDefault);
}
CCoeffGaps.prototype =
{
    getCoeff: function(codeCurr, codeLR , direct) // obj - либо codeChar, либо мат объект
    {
        var operator = null;

        if(this.checkEqualSign(codeCurr))
            operator = this.Equal;
        else if(this.checkOperSign(codeCurr))
            operator = this.Sign;
        else if(codeCurr == 0x2A)
            operator = this.Mult;
        else
            operator = this.Default;

        var part = direct == -1 ? operator.left : operator.right;

        var coeff = 0;
        if(codeLR == -1) // мат объект
            coeff = part.letters;
        else if(this.checkOperSign(codeLR))
            coeff = part.sign;
        else if(this.checkEqualSign(codeLR))
            coeff = part.equal;
        else if(this.checkZeroSign(codeLR, direct))
            coeff = part.zeroOper;
        else
            coeff = part.letters;

        return coeff;
    },
    checkOperSign: function(code) // "+", "-", "±", "∓", "×", "÷"
    {
        var PLUS            = 0x2B,
            MINUS           = 0x2D,
            PLUS_MINUS      = 0xB1,
            MINUS_PLUS      = 0x2213,
            MULTIPLICATION  = 0xD7,
            DIVISION        = 0xF7;

        return code == PLUS || code == MINUS || code == PLUS_MINUS || code == MINUS_PLUS || code == MULTIPLICATION || code == DIVISION;
    },
    checkEqualSign: function(code)
    {
        var COMPARE       = code == 0x3C || code == 0x3E; // LESS, GREATER
        var ARROWS        = (code >= 0x2190 && code <= 0x21B3) || (code == 0x21B6) || (code == 0x21B7) || (code >= 0x21BA && code <= 0x21E9) || (code >=0x21F4 && code <= 0x21FF);
        var INTERSECTION  = code >= 0x2223 && code <= 0x222A;
        var EQUALS        = code == 0x3D || (code >= 0x2234 && code <= 0x22BD) || (code >= 0x22C4 && code <= 0x22FF);
        var ARR_FISHES    = (code >= 0x27DA && code <= 0x27E5) || (code >= 0x27EC && code <= 0x297F);
        var TRIANGLE_SYMB = code >= 0x29CE && code <= 0x29D7;
        var OTH_SYMB      = code == 0x29DF || (code >= 0x29E1 && code <= 0x29E7) || (code >= 0x29F4 && code <= 0x29F8) || (code >= 0x2A22 && code <= 0x2AF0) || (code >= 0x2AF2 && code <= 0x2AFB) || code == 0x2AFD || code == 0x2AFE;


        return COMPARE || ARROWS || INTERSECTION || EQUALS || ARR_FISHES || TRIANGLE_SYMB || OTH_SYMB;
    },
    checkZeroSign: function(code, direct) // "*", "/", "\"
    {
        var MULT     = 0x2A,
            DIVISION = 0x2F,
            B_SLASH  = 0x5C;

        var bOper = code == MULT || code == DIVISION || code == B_SLASH;
        var bLeftBracket = direct == -1 && (code == 0x28 || code == 0x5B || code == 0x7B);
        var bRightBracket = direct == 1 && (code == 0x29 || code == 0x5D || code == 0x7D);


        return bOper || bLeftBracket || bRightBracket;
    }
};

var COEFF_GAPS = new CCoeffGaps();

function CMathArgSize()
{
    this.value       = undefined;
}
CMathArgSize.prototype =
{
    Decrease: function()
    {
        if(this.value == undefined)
            this.value = 0;

        if( this.value > -2 )
            this.value--;

        return this.value;
    },
    Increase: function()
    {
        if(this.value == undefined)
            this.value = 0;

        if(this.value < 2)
            this.value++;

        return this.value;
    },
    Set: function(ArgSize)
    {
        this.value = ArgSize.value;
    },
    GetValue: function()
    {
        return this.value;
    },
    SetValue: function(val)
    {
        if(val === null || val === undefined)
            this.value = undefined;
        else if(val < - 2)
            this.value = -2;
        else if(val > 2)
            this.value = 2;
        else
            this.value = val;
    },
    Copy: function()
    {
        var ArgSize = new CMathArgSize();
        ArgSize.value = this.value;

        return ArgSize;
    },
    Merge: function(ArgSize)
    {
        if(this.value == undefined)
            this.value = 0;

        if(ArgSize.value == undefined)
            ArgSize.value = 0;

        this.SetValue(this.value + ArgSize.value);
    },
    Can_Decrease: function()
    {
        return this.value !== -2;
    },
    Can_Increase: function()
    {
        return this.value == -1 || this.value == -2;
    },
    Can_SimpleIncrease: function()
    {
        return this.value !== 2;
    },
    Write_ToBinary: function(Writer)
    {
        if(this.value == undefined)
        {
            Writer.WriteBool(true);
        }
        else
        {
            Writer.WriteBool(false);
            Writer.WriteLong(this.value);
        }
    },
    Read_FromBinary: function(Reader)
    {
        if(Reader.GetBool() == false)
        {
            this.value = Reader.GetLong();
        }
        else
        {
            this.value = undefined;
        }
    }
};

function CMathGapsInfo(argSize)
{
    this.argSize = argSize; // argSize выставляем один раз для всего контента

    this.Left    = null;    // элемент слева
    this.Current = null;    // текущий элемент

    this.LeftFontSize    = null;
    this.CurrentFontSize = null;
    this.bUpdate         = false;
}
CMathGapsInfo.prototype =
{
    setGaps: function(Current, CurrentFontSize)
    {
        this.updateCurrentObject(Current, CurrentFontSize);
        this.updateGaps();
    },
    updateCurrentObject: function(Current, CurrentFontSize)
    {
        this.Left = this.Current;
        this.LeftFontSize = this.CurrentFontSize;

        this.Current = Current;
        this.CurrentFontSize = CurrentFontSize;
    },
    updateGaps: function()
    {
        if(this.argSize < 0)
        {
            this.Current.GapLeft = 0;

            if(this.Left !== null)
                this.Left.GapRight = 0;
        }
        else
        {
            var leftCoeff = 0,  /// for Current Object
                rightCoeff = 0; /// for Left Object

            var leftCode;


            if(this.Current.IsText())
            {
                var currCode = this.Current.getCodeChr();

                if(this.Left !== null)
                {
                    if(this.Left.Type == para_Math_Composition)
                    {
                        rightCoeff = this.getGapsMComp(this.Left, 1);
                        leftCoeff = COEFF_GAPS.getCoeff(currCode, -1, -1);

                        if(leftCoeff > rightCoeff)
                            leftCoeff -= rightCoeff;
                    }
                    else if(this.Left.IsText())
                    {
                        leftCode = this.Left.getCodeChr();
                        leftCoeff = COEFF_GAPS.getCoeff(currCode, leftCode, -1);
                        rightCoeff = COEFF_GAPS.getCoeff(leftCode, currCode, 1);
                    }

                }
                else
                    this.Current.GapLeft = 0;
            }
            else if(this.Current.Type == para_Math_Composition)
            {
                leftCoeff = this.getGapsMComp(this.Current, -1);

                if(this.Left !== null)
                {
                    if(this.Left.Type == para_Math_Composition)
                    {
                        rightCoeff = this.getGapsMComp(this.Left, 1);

                        if(rightCoeff/2 > leftCoeff)
                            rightCoeff -= leftCoeff;
                        else
                            rightCoeff /= 2;

                        if(leftCoeff < rightCoeff/2)
                            leftCoeff = rightCoeff/2;
                        else
                            leftCoeff -= rightCoeff/2;
                    }
                    else if(this.Left.IsText())
                    {
                        leftCode = this.Left.getCodeChr();
                        rightCoeff = COEFF_GAPS.getCoeff(leftCode, -1, 1);
                        if(rightCoeff > leftCoeff)
                            rightCoeff -= leftCoeff;
                    }
                }
                else
                    leftCoeff = 0;
            }

            var LGapSign = 0.1513*this.CurrentFontSize;
            this.Current.GapLeft = (leftCoeff*LGapSign*100 | 0)/100; // если ни один случай не выполнился, выставляем "нулевые" gaps (default): необходимо, если что-то удалили и объект стал первый или последним в контенте

            if(this.Left !== null)
            {
                var RGapSign = 0.1513*this.LeftFontSize;
                this.Left.GapRight = (rightCoeff*RGapSign*100 | 0)/100;
            }
        }
    },
    getGapsMComp: function(MComp, direct)
    {
        var kind = MComp.kind;
        var checkGap = this.checkGapKind(MComp);

        var bNeedGap = !checkGap.bEmptyGaps && !checkGap.bChildGaps;

        var coeffLeft  = 0.001,
            coeffRight = 0; // for checkGap.bEmptyGaps

        //var bDegree = kind == MATH_DEGREE || kind == MATH_DEGREESubSup;
        var bDegree = kind == MATH_DEGREE;

        if(checkGap.bChildGaps)
        {
            if(bDegree)
            {
                coeffLeft  = 0.03;

                if(MComp.IsPlhIterator())
                    coeffRight = 0.12;
                else
                    coeffRight = 0.16;
            }

            var gapsChild = MComp.getGapsInside(this);

            coeffLeft  = coeffLeft  < gapsChild.left  ? gapsChild.left  : coeffLeft;
            coeffRight = coeffRight < gapsChild.right ? gapsChild.right : coeffRight;
        }
        else if(bNeedGap)
        {
            coeffLeft = 0.4;
            coeffRight = 0.3;
        }


        return direct == -1 ? coeffLeft : coeffRight;
    },
    checkGapKind: function(Comp)
    {
        var kind       = Comp.kind;

        var bEmptyGaps = kind == MATH_MATRIX /*|| (kind == MATH_DELIMITER && Comp.Is_EmptyGaps())*/,
            bChildGaps = kind == MATH_DEGREE || kind == MATH_DEGREESubSup || kind == MATH_ACCENT || kind == MATH_RADICAL || kind == MATH_LIMIT || kind == MATH_BORDER_BOX;


        return  {bEmptyGaps: bEmptyGaps, bChildGaps: bChildGaps};
    }
};

function CMPrp()
{
    this.sty      = undefined;
    this.scr      = undefined;
    this.nor      = undefined;

    this.aln      = undefined;
    this.brk      = undefined;
    this.lit      = undefined;

    // Default
    /*this.sty    = STY_ITALIC;
    this.scr      = TXT_ROMAN;

    this.nor      = false;

    this.aln      = false;
    this.brk      = false;
    this.lit      = false;*/

    // TXT_NORMAL
    // если normal == false, то берем TextPrp отсюда (в wRunPrp bold/italic не учитываем, выставляем отсюда)
    // если normal == true, то их Word не учитывает и берет TextPr из wRunPrp

    // TXT_PLAIN
    // если plain == true
    // буквы берутся обычные, не специальные для Cambria Math : то есть как для TXT_NORMAL
    // отличие от TXT_NORMAL w:rPrp в этом случае не учитываются !

}
CMPrp.prototype =
{
    Set_Pr: function(Pr)
    {
        if(Pr.sty !== undefined)
            this.sty = Pr.sty;

        if(Pr.scr !== undefined)
            this.scr = Pr.scr;

        if(Pr.nor !== undefined)
            this.nor = Pr.nor;

        if(Pr.aln !== undefined)
            this.aln = Pr.aln;

        if(Pr.lit !== undefined)
            this.lit = Pr.lit;

        if(Pr.brk !== undefined)
        {
            this.brk = new CMathBreak();
            this.brk.Set_FromObject(Pr.brk);
        }
    },
    GetTxtPrp: function()
    {
        var textPrp = new CTextPr();

        if(this.sty == undefined)
        {
            textPrp.Italic = true;
            textPrp.Bold   = false;
        }
        else
        {
            textPrp.Italic = this.sty == STY_BI || this.sty == STY_ITALIC;
            textPrp.Bold   = this.sty == STY_BI || this.sty == STY_BOLD;
        }


        return textPrp;
    },
    Copy: function()
    {
        var NewMPrp = new CMPrp();
        
        NewMPrp.aln      = this.aln;
        NewMPrp.lit      = this.lit;
        NewMPrp.nor      = this.nor;
        NewMPrp.sty      = this.sty;
        NewMPrp.scr      = this.scr;

        if(this.brk !== undefined)
            NewMPrp.brk = this.brk.Copy();
        
        return NewMPrp;
    },
    IsBreak: function()
    {
        return this.brk !== undefined;
    },
    Get_AlignBrk: function()
    {
        return this.brk !== undefined ? this.brk.Get_AlignBrk() : null;
    },
    Get_AlnAt: function()
    {
        return this.brk != undefined ? this.brk.Get_AlnAt() : undefined;
    },
    GetCompiled_ScrStyles : function()
    {
        var nor = this.nor == undefined ? false : this.nor;
        var scr = this.scr == undefined ? TXT_ROMAN : this.scr;
        var sty = this.sty == undefined ? STY_ITALIC : this.sty;

        return {nor: nor, scr: scr, sty: sty};
    },
    SetStyle: function(Bold, Italic) /// из ctrPrp получить style для MathPrp
    {
        if(Bold == true && Italic == true)
            this.sty = STY_BI;
        else if(Italic == true)
            this.sty = STY_ITALIC;
        else if(Bold == true)
            this.sty = STY_BOLD;
        else if(Bold == false && Italic == false)
            this.sty = STY_PLAIN;
        else
            this.sty = undefined;
    },
    GetBoldItalic: function()
    {
        var Object =
        {
            Italic: undefined,
            Bold:   undefined
        };

        if(this.sty == STY_BI)
        {
            Object.Bold   = true;

        }
        else if(this.sty == STY_BOLD)
        {
            Object.Bold   = true;
            Object.Italic = false;
        }

        return Object;
    },
    Displace_Break: function(isForward)
    {
        if(this.brk !== undefined)
        {
            this.brk.Displace(isForward);
        }
    },
    Apply_AlnAt: function(alnAt)
    {
        if(this.brk !== undefined)
        {
            this.brk.Apply_AlnAt(alnAt);
        }
    },
    Insert_ForcedBreak: function(AlnAt)
    {
        if(this.brk == undefined)
            this.brk = new CMathBreak();

        this.brk.Apply_AlnAt(AlnAt);
    },
    Delete_ForcedBreak: function()
    {
        this.brk = undefined;
    }
};
CMPrp.prototype.Write_ToBinary = function(Writer)
{
	var StartPos = Writer.GetCurPosition();
	Writer.Skip(4);

	var Flags = 0;
	if (undefined != this.aln)
	{
		Writer.WriteBool(this.aln);
		Flags |= 1;
	}
	if (undefined != this.brk)
	{
		this.brk.Write_ToBinary(Writer);
		Flags |= 2;
	}
	if (undefined != this.lit)
	{
		Writer.WriteBool(this.lit);
		Flags |= 4;
	}
	if (undefined != this.nor)
	{
		Writer.WriteBool(this.nor);
		Flags |= 8;
	}
	if (undefined != this.scr)
	{
		Writer.WriteLong(this.scr);
		Flags |= 16;
	}
	if (undefined != this.sty)
	{
		Writer.WriteLong(this.sty);
		Flags |= 32;
	}

	var EndPos = Writer.GetCurPosition();
	Writer.Seek(StartPos);
	Writer.WriteLong(Flags);
	Writer.Seek(EndPos);
};
CMPrp.prototype.Read_FromBinary = function(Reader)
{
	var Flags = Reader.GetLong();

	if (Flags & 1)
		this.aln = Reader.GetBool();

	if (Flags & 2)
	{
		this.brk = new CMathBreak();
		this.brk.Read_FromBinary(Reader);
	}

	if (Flags & 4)
		this.lit = Reader.GetBool();

	if (Flags & 8)
		this.nor = Reader.GetBool();

	if (Flags & 16)
		this.scr = Reader.GetLong();

	if (Flags & 32)
		this.sty = Reader.GetLong();
};

/**
 *
 * @constructor
 * @extends {CParagraphContentWithParagraphLikeContent}
 */
function CMathContent()
{
	CParagraphContentWithParagraphLikeContent.call(this);

	this.Id = AscCommon.g_oIdCounter.Get_NewId();		

    this.Content = []; // array of mathElem

    this.Type = para_Math_Content;
    this.CurPos = 0;
    this.pos    = new CMathPosition();   // относительная позиция

    //  Properties
    this.ParaMath       = null;
    this.ArgSize        = new CMathArgSize();
    this.Compiled_ArgSz = new CMathArgSize();

    // for EqArray
    this.InfoPoints = new CInfoPoints();
    ///////////////

    this.Bounds = new CMathBounds();

    this.plhHide        = false;
    this.bRoot          = false;
    this.bOneLine  = false;

    //////////////////

    this.Selection =
    {
        StartPos:  0,
        EndPos:    0,
        Use:    false
    };

    this.RecalcInfo =
    {
        TextPr:             true,
        bEqArray:          false,
        bChangeInfoPoints:  false,
        Measure:            true
    };

    this.NearPosArray = [];
    this.ParentElement = null;

    this.size = new CMathSize();

	this.m_oContentChanges = new AscCommon.CContentChanges(); // список изменений(добавление/удаление элементов)
	
	// Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    AscCommon.g_oTableId.Add( this, this.Id );
}
CMathContent.prototype = Object.create(CParagraphContentWithParagraphLikeContent.prototype);
CMathContent.prototype.constructor = CMathContent;
CMathContent.prototype.init = function()
{

};
CMathContent.prototype.addElementToContent = function(obj)
{
    this.Internal_Content_Add(this.Content.length, obj, false);
    this.CurPos = this.Content.length-1;
};
CMathContent.prototype.SetPlaceholder = function()
{
	this.Remove_FromContent(0, this.Content.length);

    var oRun = new ParaRun(null, true);
    oRun.AddMathPlaceholder();

    this.addElementToContent(oRun);

    this.RemoveSelection();
    this.MoveCursorToEndPos();
};
//////////////////////////////////////
CMathContent.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI)
{
    this.ParaMath = ParaMath;
    if(Parent !== null)
    {
        this.bRoot = false;
        this.Parent = Parent;
    }

    if(ArgSize !== null && ArgSize !== undefined)
    {
        this.Compiled_ArgSz.value = this.ArgSize.value;
        this.Compiled_ArgSz.Merge(ArgSize);
    }

    var lng = this.Content.length;

    var GapsInfo = new CMathGapsInfo(this.Compiled_ArgSz.value);

    if(!this.bRoot)
        this.RecalcInfo.bEqArray = this.Parent.IsEqArray();

    for(var pos = 0; pos < lng; pos++)
    {
        if(this.Content[pos].Type == para_Math_Composition)
        {
            this.Content[pos].PreRecalc(this, ParaMath, this.Compiled_ArgSz, RPI, GapsInfo);
        }
        else if(this.Content[pos].Type == para_Math_Run)
            this.Content[pos].Math_PreRecalc(this, ParaMath, this.Compiled_ArgSz, RPI, GapsInfo);
    }

    if(GapsInfo.Current !== null)
        GapsInfo.Current.GapRight = 0;
};
CMathContent.prototype.Math_UpdateGaps = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var GapsInfo = new CMathGapsInfo(this.Compiled_ArgSz.value);

    if(StartPos !== undefined && EndPos !== undefined && CurLine < this.protected_GetLinesCount())
    {
        if(CurLine > 0 && StartPos !== EndPos) // выставим объект, который будет Left для первого элемента в текущей строке
        {
            var EndPosPrev   = this.protected_GetRangeEndPos(CurLine - 1, CurRange);
            this.Content[EndPosPrev].UpdLastElementForGaps(_CurLine - 1, _CurRange, GapsInfo);
        }


        for(var Pos = StartPos; Pos <= EndPos; Pos++)
        {
            this.Content[Pos].Math_UpdateGaps(_CurLine, _CurRange, GapsInfo);
        }
    }
};
CMathContent.prototype.IsEqArray = function()
{
    return this.RecalcInfo.bEqArray;
};
CMathContent.prototype.Get_WidthPoints = function()
{
    return this.InfoPoints.ContentPoints;
};
CMathContent.prototype.ShiftPage = function(Dx)
{
    this.Bounds.ShiftPage(Dx);

    for(var Pos = 0; Pos < this.Content.length; Pos++)
    {
        if(this.Content[Pos].Type === para_Math_Composition)
            this.Content[Pos].ShiftPage(Dx);
    }
};
CMathContent.prototype.Get_CompiledArgSize = function()
{
    return this.Compiled_ArgSz;
};
CMathContent.prototype.getGapsInside = function(GapsInfo) // учитываем gaps внутренних объектов
{
    var gaps = {left: 0, right: 0};
    var bFirstComp = false,
        bLastComp = false;

    var len = this.Content.length;

    if(len > 1)
    {
        var bFRunEmpty = this.Content[0].Is_Empty();
        bFirstComp = bFRunEmpty && this.Content[1].Type == para_Math_Composition; // первый всегда идет Run

        var bLastRunEmpty = this.Content[len - 1].Is_Empty(); // т.к. после мат. объекта стоит пустой Run
        bLastComp = bLastRunEmpty && this.Content[len - 2].Type == para_Math_Composition;
    }

    var checkGap;

    if(bFirstComp)
    {
        checkGap = GapsInfo.checkGapKind(this.Content[1]);

        if(!checkGap.bChildGaps)
        {
            gaps.left = GapsInfo.getGapsMComp(this.Content[1], -1);
        }
    }

    if(bLastComp)
    {
        checkGap = GapsInfo.checkGapKind(this.Content[len - 1]);

        if(!checkGap.bChildGaps)
        {
            gaps.right = GapsInfo.getGapsMComp(this.Content[len - 2], 1);
        }
    }

    return gaps;
};
CMathContent.prototype.draw = function(x, y, pGraphics, PDSE)
{
    var StartPos, EndPos;

    if(this.bRoot)
    {
        var CurLine  = PDSE.Line - this.StartLine;
        var CurRange = ( 0 === CurLine ? PDSE.Range - this.StartRange : PDSE.Range );

        StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
        EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);
    }
    else
    {
        StartPos = 0;
        EndPos   = this.Content.length - 1;
    }

    var bHidePlh = this.plhHide && this.IsPlaceholder();

    if( !bHidePlh )
    {
        for(var i = StartPos; i <= EndPos;i++)
        {
            if(this.Content[i].Type == para_Math_Composition)
            {
                this.Content[i].draw(x, y, pGraphics, PDSE);
            }
            else
                this.Content[i].Draw_Elements(PDSE);
        }
    }
};
CMathContent.prototype.Draw_Elements = function(PDSE)
{
    var StartPos, EndPos;

    if(this.protected_GetLinesCount() > 0)
    {
        var CurLine  = PDSE.Line - this.StartLine;
        var CurRange = ( 0 === CurLine ? PDSE.Range - this.StartRange : PDSE.Range );

        StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
        EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);
    }
    else
    {
        StartPos = 0;
        EndPos   = this.Content.length - 1;
    }

    var bHidePlh = this.plhHide && this.IsPlaceholder();

    if( !bHidePlh )
    {
        for(var CurPos = StartPos; CurPos <= EndPos;CurPos++)
            this.Content[CurPos].Draw_Elements(PDSE);
    }

};
CMathContent.prototype.setCtrPrp = function()
{

};
CMathContent.prototype.Is_InclineLetter = function()
{
    var result = false;

    if(this.Content.length == 1)
        result = this.Content[0].Math_Is_InclineLetter();

    return result;
};
CMathContent.prototype.IsPlaceholder = function()
{
    var bPlh = false;
    if(this.Content.length == 1)
        bPlh  = this.Content[0].IsPlaceholder();

    return bPlh;
};
CMathContent.prototype.Can_GetSelection = function()
{
    var bPlh = false;

    if(this.Content.length == 1)
        bPlh  = this.Content[0].IsPlaceholder();

    return bPlh || this.bRoot == false;
};
CMathContent.prototype.IsJustDraw = function()
{
    return false;
};
CMathContent.prototype.ApplyPoints = function(WidthsPoints, Points, MaxDimWidths)
{
    this.InfoPoints.GWidths       = WidthsPoints;
    this.InfoPoints.GPoints       = Points;
    this.InfoPoints.GMaxDimWidths = MaxDimWidths;
    // точки выравнивания данного контента содержатся в ContentPoints

    var PosInfo = new CMathPointInfo();
    PosInfo.SetInfoPoints(this.InfoPoints);

    this.size.width = 0;

    for(var i = 0 ; i < this.Content.length; i++)
    {
        if(this.Content[i].Type === para_Math_Run)
        {
            this.Content[i].ApplyPoints(PosInfo);
        }

        this.size.width += this.Content[i].size.width;
    }

    this.Bounds.SetWidth(0, 0, this.size.width);
};
CMathContent.prototype.UpdateBoundsPosInfo = function(PRSA, _CurLine, _CurRange, _CurPage)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    this.Bounds.SetGenPos(CurLine, CurRange, PRSA);
    this.Bounds.SetPage(CurLine, CurRange, _CurPage);

    for(var Pos = StartPos; Pos <= EndPos; Pos++)
    {
        if(this.Content[Pos].Type == para_Math_Composition)
            this.Content[Pos].UpdateBoundsPosInfo(PRSA, _CurLine, _CurRange, _CurPage);
    }

};
CMathContent.prototype.setPosition = function(pos, PosInfo)
{
    var Line  = PosInfo.CurLine,
        Range = PosInfo.CurRange;

    var CurLine  = Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? Range - this.StartRange : Range );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    if(this.RecalcInfo.bEqArray)
    {
        var PosInfoEqq = new CMathPointInfo();
        PosInfoEqq.SetInfoPoints(this.InfoPoints);

        pos.x += PosInfoEqq.GetAlign();
    }

    this.pos.x = pos.x;
    this.pos.y = pos.y;

    this.Bounds.SetPos(CurLine, CurRange, this.pos);

    for(var Pos = StartPos; Pos <= EndPos; Pos++)
    {
        if(this.Content[Pos].Type == para_Math_Run)
            this.Content[Pos].Math_SetPosition(pos, PosInfo);
        else
            this.Content[Pos].setPosition(pos, PosInfo);
    }
};
CMathContent.prototype.Shift_Range = function(Dx, Dy, _CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    this.Bounds.ShiftPos(CurLine, CurRange, Dx, Dy);

	CParagraphContentWithParagraphLikeContent.prototype.Shift_Range.call(this, Dx, Dy, _CurLine, _CurRange);
};
CMathContent.prototype.SetParent = function(Parent, ParaMath)
{
    this.Parent   = Parent;
    this.ParaMath = ParaMath;
};
///// properties /////
CMathContent.prototype.hidePlaceholder = function(flag)
{
    this.plhHide = flag;
};
///////// RunPrp, CtrPrp

CMathContent.prototype.Get_FirstTextPr = function()
{
    return this.Content[0].Get_FirstTextPr();
};
CMathContent.prototype.getFirstRPrp  = function()
{
    return this.Content[0].Get_CompiledPr(true);
};
CMathContent.prototype.GetCtrPrp = function()       // for placeholder
{
    var ctrPrp = new CTextPr();
    if(!this.bRoot)
        ctrPrp.Merge( this.Parent.Get_CompiledCtrPrp_2() );

    return ctrPrp;
};
CMathContent.prototype.IsAccent = function()
{
    var result = false;

    if(!this.bRoot)
        result = this.Parent.IsAccent();

    return result;
};
////////////////////////
/// For Para Math
CMathContent.prototype.GetParent = function()
{
    return this.Parent.GetParent();
};
CMathContent.prototype.SetArgSize = function(val)
{
	History.Add(new CChangesMathContentArgSize(this, this.ArgSize.GetValue(), val));
	this.ArgSize.SetValue(val);
};
CMathContent.prototype.GetArgSize = function()
{
    return this.ArgSize.value;
};
/////////   Перемещение     ////////////

// Поиск позиции, селект
CMathContent.prototype.IsSelectedAll = function(Props)
{
    var bFirst = false, bEnd = false;

    if(this.Selection.StartPos == 0 && this.Selection.EndPos == this.Content.length - 1)
    {
        if(this.Content[this.Selection.StartPos].Type == para_Math_Run)
            bFirst = this.Content[this.Selection.StartPos].IsSelectedAll(Props);
        else
            bFirst = true;

        if(this.Content[this.Selection.EndPos].Type == para_Math_Run)
            bEnd = this.Content[this.Selection.EndPos].IsSelectedAll(Props);
        else
            bEnd = true;
    }

    return bFirst && bEnd;
};

///////////////////////

CMathContent.prototype.Get_Id = function()
{
    return this.GetId();
};
CMathContent.prototype.GetId = function()
{
    return this.Id;
};
CMathContent.prototype.private_CorrectContent = function()
{
    var len = this.Content.length;

    var EmptyRun = null;
    var RPr      = null;
    var CurrPos = 0;

    while(CurrPos < len)
    {
        var Current = this.Content[CurrPos];

        var bLeftRun  = CurrPos > 0 ? this.Content[CurrPos-1].Type == para_Math_Run : false,
            bRightRun = CurrPos < len - 1 ? this.Content[CurrPos + 1].Type === para_Math_Run : false;

        var bCurrComp       = Current.Type == para_Math_Composition,
            bCurrEmptyRun   = Current.Type == para_Math_Run && Current.Is_Empty();

        var bDeleteEmptyRun = bCurrEmptyRun && (bLeftRun || bRightRun);

        if(bCurrComp && !bLeftRun)
        {
            EmptyRun = new ParaRun(null, true);
            EmptyRun.Set_RFont_ForMathRun();

            RPr = Current.Get_CtrPrp(false);
            EmptyRun.Apply_Pr(RPr);
            this.Internal_Content_Add(CurrPos, EmptyRun);
            CurrPos += 2;

        }
        else if(bDeleteEmptyRun && false == Current.Is_CheckingNearestPos()) // если NearPosArray не нулевой длины, то это вызов происходит на Insert_Content, не удаляем пустые Run
        {
            this.Remove_FromContent(CurrPos, 1);

            if (this.CurPos === CurrPos)
            {
                if (bLeftRun)
                {
                    this.CurPos = CurrPos - 1;
                    this.Content[this.CurPos].MoveCursorToEndPos(false);
                }
                else
                {
                    this.CurPos = CurrPos;
                    this.Content[this.CurPos].MoveCursorToStartPos();
                }
            }
        }
        else
        {
            CurrPos++;
        }

        len = this.Content.length;
    }

    if(len > 1)
    {
        if(this.Content[len - 1].Type == para_Math_Composition)
        {
            EmptyRun = new ParaRun(null, true);
            EmptyRun.Set_RFont_ForMathRun();

            RPr = this.Content[len - 1].Get_CtrPrp(false);
            EmptyRun.Apply_Pr(RPr);
            this.Internal_Content_Add(CurrPos, EmptyRun);
        }
    }

};
CMathContent.prototype.Correct_Content = function(bInnerCorrection)
{
    if (true === bInnerCorrection)
    {
        for (var nPos = 0, nCount = this.Content.length; nPos < nCount; nPos++)
        {
            if (para_Math_Composition === this.Content[nPos].Type)
                this.Content[nPos].Correct_Content(true);
        }
    }

    this.private_CorrectContent();

    // Если в контенте ничего нет, тогда добавляем пустой ран
    if (this.Content.length < 1)
    {
        var NewMathRun = new ParaRun(null, true);
        NewMathRun.Set_RFont_ForMathRun();
        this.Add_ToContent(0, NewMathRun);
    }

	// Если единственный элемент данного контента ран и он пустой, заполняем его плейсхолдером
	if (1 === this.Content.length && para_Math_Run === this.Content[0].Type && true === this.Content[0].Is_Empty())
	{
		this.Content[0].AddMathPlaceholder();
	}

	// Возможна ситуация, когда у нас остались лишние плейсхолдеры (либо их слишком много, либо они вообще не нужны)
	if (true !== this.IsPlaceholder())
	{
		var isEmptyContent = true;
		for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos)
		{
			if (para_Math_Run === this.Content[nPos].Type)
			{
				this.Content[nPos].RemoveMathPlaceholder();
				if (false === this.Content[nPos].Is_Empty())
					isEmptyContent = false;
			}
			else
			{
				isEmptyContent = false;
			}
		}

		if (isEmptyContent)
			this.SetPlaceholder();
	}

	if (this.CurPos >= this.Content.length)
		this.CurPos = this.Content.length - 1;
    if (this.CurPos < 0)
    	this.CurPos = 0;
};
CMathContent.prototype.Correct_ContentPos = function(nDirection)
{
    var nCurPos = this.CurPos;

    if (nCurPos < 0)
    {
        this.CurPos = 0;
        this.Content[0].MoveCursorToStartPos();
    }
    else if (nCurPos > this.Content.length - 1)
    {
        this.CurPos = this.Content.length - 1;
        this.Content[this.CurPos].MoveCursorToEndPos();
    }
    else if (para_Math_Run !== this.Content[nCurPos].Type)
    {
        if (nDirection > 0)
        {
            this.CurPos = nCurPos + 1;
            this.Content[this.CurPos].MoveCursorToStartPos();
        }
        else
        {
            this.CurPos = nCurPos - 1;
            this.Content[this.CurPos].MoveCursorToEndPos();
        }
    }
};

/// функции для работы с курсором
CMathContent.prototype.Cursor_Is_Start = function()
{
    var result = false;

    if( !this.Is_Empty() )
    {
        if(this.CurPos == 0)
            result = this.Content[0].Cursor_Is_Start();
    }

    return result;
};
CMathContent.prototype.Cursor_Is_End = function()
{
    var result = false;

    if(!this.Is_Empty())
    {
        var len = this.Content.length - 1;
        if(this.CurPos == len)
        {
            result = this.Content[len].Cursor_Is_End();
        }
    }

    return result;
};
//////////////////////////////////////

/////////////////////////
//  Text Properties
///////////////

CMathContent.prototype.Get_TextPr = function(ContentPos, Depth)
{
    var pos = ContentPos.Get(Depth);

    var TextPr;

    if(true !== this.bRoot && this.IsPlaceholder())
        TextPr = this.Parent.Get_CtrPrp(true);
    else
        TextPr = this.Content[pos].Get_TextPr(ContentPos, Depth + 1);

    return TextPr;
};
CMathContent.prototype.Get_ParentCtrRunPr = function(bCopy)
{
    return this.Parent.Get_CtrPrp(bCopy);
};
CMathContent.prototype.Get_CompiledTextPr = function(Copy, bAll)
{
    var TextPr = null;

    if(true !== this.bRoot && this.IsPlaceholder())
    {
        TextPr = this.Parent.Get_CompiledCtrPrp_2();
    }
    else if (this.Selection.Use || bAll == true)
    {
        var StartPos, EndPos;

        if(bAll == true)
        {
            StartPos = 0;
            EndPos = this.Content.length - 1;
        }
        else
        {
            StartPos = this.Selection.StartPos;
            EndPos   = this.Selection.EndPos;

            if ( StartPos > EndPos )
            {
                StartPos = this.Selection.EndPos;
                EndPos   = this.Selection.StartPos;
            }
        }


        // пропускаем пустые рана только для случая, когда есть селект

        while ( null === TextPr && StartPos <= EndPos )
        {
            var bComp = this.Content[StartPos].Type == para_Math_Composition,
                bEmptyRun = this.Content[StartPos].Type == para_Math_Run && true === this.Content[StartPos].IsSelectionEmpty();

            if(bComp || !bEmptyRun || bAll)    //пропускаем пустые Run
                TextPr = this.Content[StartPos].Get_CompiledTextPr(true);

            StartPos++;
        }

        while(this.Content[EndPos].Type == para_Math_Run && true === this.Content[EndPos].IsSelectionEmpty() && StartPos < EndPos + 1 && bAll == false) //пропускаем пустые Run
        {
            EndPos--;
        }


        for ( var CurPos = StartPos; CurPos < EndPos + 1; CurPos++ )
        {
            //var CurTextPr = this.Content[CurPos].Get_CompiledPr(false);
            var CurTextPr = this.Content[CurPos].Get_CompiledTextPr(false);

            if ( null !== CurTextPr )
                TextPr = TextPr.Compare( CurTextPr );
        }
    }
    else
    {
        var CurPos = this.CurPos;

        if ( CurPos >= 0 && CurPos < this.Content.length )
            TextPr = this.Content[CurPos].Get_CompiledTextPr(Copy);
    }

    return TextPr;
};
CMathContent.prototype.GetMathTextPrForMenu = function(ContentPos, Depth)
{
    var pos = ContentPos.Get(Depth);

    return this.Content[pos].GetMathTextPrForMenu(ContentPos, Depth + 1);
};
CMathContent.prototype.Apply_TextPr = function(TextPr, IncFontSize, ApplyToAll, StartPos, EndPos)
{
    if ( true === ApplyToAll )
    {
        for ( var i = 0; i < this.Content.length; i++ )
            this.Content[i].Apply_TextPr( TextPr, IncFontSize, true );
    }
    else
    {
        var StartPos, EndPos, bMenu = false;

        if(StartPos !== undefined && EndPos !== undefined)
        {
            StartPos = StartPos;
            EndPos   = EndPos;

            bMenu = true;
        }
        else
        {
            StartPos = this.Selection.StartPos;
            EndPos   = this.Selection.EndPos;
        }

        var NewRuns;
        var LRun, CRun, RRun;

        var bSelectOneElement = this.Selection.Use && StartPos == EndPos;

        var FirstPos = this.Selection.Use ? Math.min(StartPos, EndPos) : this.CurPos;

        if(FirstPos == 0 && this.bRoot)
            this.ParaMath.SetRecalcCtrPrp(this.Content[0]);

        if( ( !this.Selection.Use && !bMenu ) || (bSelectOneElement && this.Content[StartPos].Type == para_Math_Run) ) // TextPr меняем только в одном Run
        {
            var Pos = !this.Selection.Use ? this.CurPos :  StartPos;

            NewRuns = this.Content[Pos].Apply_TextPr(TextPr, IncFontSize, false);

            LRun = NewRuns[0];
            CRun = NewRuns[1];
            RRun = NewRuns[2];

            var CRunPos = Pos;

            if(LRun !== null)
            {
                this.Internal_Content_Add(Pos+1, CRun);
                CRunPos = Pos + 1;
            }

            if(RRun !== null)
            {
                this.Internal_Content_Add(CRunPos+1, RRun);
            }

            this.CurPos             = CRunPos;
            this.Selection.StartPos = CRunPos;
            this.Selection.EndPos   = CRunPos;

        }
        else if(bSelectOneElement && this.Content[StartPos].Type == para_Math_Composition)  // заселекчен только один мат. объект
        {
            this.Content[StartPos].Apply_TextPr(TextPr, IncFontSize, true);
        }
        else
        {

            if(StartPos > EndPos)
            {
                var temp = StartPos;
                StartPos = EndPos;
                EndPos = temp;
            }


            for(var i = StartPos + 1; i < EndPos; i++)
                this.Content[i].Apply_TextPr(TextPr, IncFontSize, true );


            if(this.Content[EndPos].Type == para_Math_Run)
            {
                NewRuns = this.Content[EndPos].Apply_TextPr(TextPr, IncFontSize, false);

                // LRun - null
                CRun = NewRuns[1];
                RRun = NewRuns[2];

                if(RRun !== null)
                {
                    this.Internal_Content_Add(EndPos+1, RRun);
                }

            }
            else
                this.Content[EndPos].Apply_TextPr(TextPr, IncFontSize, true);


            if(this.Content[StartPos].Type == para_Math_Run)
            {
                NewRuns = this.Content[StartPos].Apply_TextPr(TextPr, IncFontSize, false);

                LRun = NewRuns[0];
                CRun = NewRuns[1];
                // RRun - null


                if(LRun !== null)
                {
                    this.Internal_Content_Add(StartPos+1, CRun);
                }

            }
            else
                this.Content[StartPos].Apply_TextPr(TextPr, IncFontSize, true);


            var bStartComposition = this.Content[StartPos].Type == para_Math_Composition || (this.Content[StartPos].Is_Empty() && this.Content[StartPos + 1].Type == para_Math_Composition);
            var bEndCompostion    = this.Content[EndPos].Type == para_Math_Composition || (this.Content[EndPos].Is_Empty()   && this.Content[EndPos - 1].Type == para_Math_Composition);

            if(!bStartComposition)
            {
                if(this.Selection.StartPos < this.Selection.EndPos && true === this.Content[this.Selection.StartPos].IsSelectionEmpty(true) )
                    this.Selection.StartPos++;
                else if (this.Selection.EndPos < this.Selection.StartPos && true === this.Content[this.Selection.EndPos].IsSelectionEmpty(true) )
                    this.Selection.EndPos++;
            }


            if(!bEndCompostion)
            {
                if(this.Selection.StartPos < this.Selection.EndPos && true === this.Content[this.Selection.EndPos].IsSelectionEmpty(true) )
                    this.Selection.EndPos--;
                else if (this.Selection.EndPos < this.Selection.StartPos && true === this.Content[this.Selection.StartPos].IsSelectionEmpty(true) )
                    this.Selection.StartPos--;
            }

        }
    }

};
CMathContent.prototype.Set_MathTextPr2 = function(TextPr, MathPr, bAll, StartPos, Count)
{
    if(bAll)
    {
        StartPos = 0;
        Count = this.Content.length - 1;
    }

    if(Count < 0 || StartPos + Count > this.Content.length - 1)
        return;

    for(var pos = StartPos; pos <= StartPos + Count; pos++)
        this.Content[pos].Set_MathTextPr2(TextPr, MathPr, true);

};
CMathContent.prototype.IsNormalTextInRuns = function()
{
    var flag = true;

    if(this.Selection.Use)
    {
        var StartPos = this.Selection.StartPos,
            EndPos   = this.Selection.EndPos;

        if ( StartPos > EndPos )
        {
            StartPos = this.Selection.EndPos;
            EndPos   = this.Selection.StartPos;
        }

        for(var i = StartPos; i < EndPos+1; i++)
        {
            var curr = this.Content[i],
                currType = curr.Type;
            if(currType == para_Math_Composition || (currType == para_Math_Run && false == curr.IsNormalText()))
            {
                flag = false;
                break;
            }
        }
    }
    else
        flag = false;

    return flag;
};
CMathContent.prototype.Internal_Content_Add = function(Pos, Item, bUpdatePosition)
{
	Item.Set_ParaMath(this.ParaMath);

	if (Item.SetParagraph)
		Item.SetParagraph(this.Paragraph);

	Item.Parent = this;
	Item.Recalc_RunsCompiledPr();

	History.Add(new CChangesMathContentAddItem(this, Pos, [Item]));
	this.Content.splice(Pos, 0, Item);

	this.private_UpdatePosOnAdd(Pos, bUpdatePosition);
};
CMathContent.prototype.private_UpdatePosOnAdd = function(Pos, bUpdatePosition)
{
    if(bUpdatePosition !== false)
    {
        if ( this.CurPos >= Pos )
            this.CurPos++;

        if ( this.Selection.StartPos >= Pos )
            this.Selection.StartPos++;

        if ( this.Selection.EndPos >= Pos )
            this.Selection.EndPos++;

        this.private_CorrectSelectionPos();
        this.private_CorrectCurPos();
    }

    // Обновляем позиции в NearestPos
    var NearPosLen = this.NearPosArray.length;
    for ( var Index = 0; Index < NearPosLen; Index++ )
    {
        var HyperNearPos = this.NearPosArray[Index];
        var ContentPos = HyperNearPos.NearPos.ContentPos;
        var Depth      = HyperNearPos.Depth;

        if (ContentPos.Data[Depth] >= Pos)
            ContentPos.Data[Depth]++;
    }
};
CMathContent.prototype.private_CorrectSelectionPos = function()
{
    this.Selection.StartPos = Math.max(0, Math.min(this.Content.length - 1, this.Selection.StartPos));
    this.Selection.EndPos   = Math.max(0, Math.min(this.Content.length - 1, this.Selection.EndPos));
};
CMathContent.prototype.private_CorrectCurPos = function()
{
    if (this.Content.length <= 0)
    {
        this.CurPos = 0;
        return;
    }

    if (this.CurPos > this.Content.length - 1)
    {
        this.CurPos = this.Content.length - 1;

        if (para_Math_Run === this.Content[this.CurPos].Type)
            this.Content[this.CurPos].MoveCursorToEndPos(false);
    }

    if (this.CurPos < 0)
    {
        this.CurPos = this.Content.length - 1;

        if (para_Math_Run === this.Content[this.CurPos].Type)
            this.Content[this.CurPos].MoveCursorToStartPos();
    }
};
CMathContent.prototype.Correct_ContentCurPos = function()
{
    this.private_CorrectCurPos();

    for(var Pos = 0; Pos < this.Content.length; Pos++)
    {
        if(this.Content[Pos].Type == para_Math_Composition)
            this.Content[Pos].Correct_ContentCurPos();
    }
};
CMathContent.prototype.SplitContent = function(NewContent, ContentPos, Depth)
{
    var Pos = ContentPos.Get(Depth);

    if(para_Math_Run === this.Content[Pos].Type)
    {
        var NewRun = this.Content[Pos].Split(ContentPos, Depth+1);
        NewContent.Add_ToContent(0, NewRun);

        var len = this.Content.length;
        if(Pos < len - 1)
        {
            NewContent.Concat_ToEnd( this.Content.slice(Pos + 1) );
            this.Remove_FromContent(Pos+1, len - Pos - 1);
        }
    }
    else
	{
		NewContent.Add_ToContent(0, new ParaRun(this.Paragraph, true));
	}
};
CMathContent.prototype.Add_ToContent = function(Pos, Item)
{
    if (Item && para_Run === Item.Type)
    {
        var MathRun = new ParaRun(Item.GetParagraph(), true);
        this.Internal_Content_Add(Pos, MathRun);
    }
    else
    {
        this.Internal_Content_Add(Pos, Item);
    }
};
CMathContent.prototype.Concat_ToEnd = function(NewItems)
{
    this.ConcatToContent(this.Content.length, NewItems);
};
CMathContent.prototype.ConcatToContent = function(Pos, NewItems)
{
	if (NewItems != undefined && NewItems.length > 0)
	{
		var Count = NewItems.length;

		for (var i = 0; i < Count; i++)
		{
			NewItems[i].Set_ParaMath(this.ParaMath);
			NewItems[i].Parent = this;
			NewItems[i].Recalc_RunsCompiledPr();
		}

		History.Add(new CChangesMathContentAddItem(this, Pos, NewItems));

		var Array_start = this.Content.slice(0, Pos);
		var Array_end   = this.Content.slice(Pos);

		this.Content = Array_start.concat(NewItems, Array_end);
	}
};
CMathContent.prototype.Remove_FromContent = function(Pos, Count)
{
	var DeletedItems = this.Content.splice(Pos, Count);
	History.Add(new CChangesMathContentRemoveItem(this, Pos, DeletedItems));

	// Обновим текущую позицию
	if (this.CurPos > Pos + Count)
		this.CurPos -= Count;
	else if (this.CurPos > Pos)
		this.CurPos = Pos;

	this.private_CorrectCurPos();
	this.private_UpdatePosOnRemove(Pos, Count);
};
CMathContent.prototype.private_UpdatePosOnRemove = function(Pos, Count)
{
    // Обновим начало и конец селекта
    if (true === this.Selection.Use)
    {
        if (this.Selection.StartPos <= this.Selection.EndPos)
        {
            if (this.Selection.StartPos > Pos + Count)
                this.Selection.StartPos -= Count;
            else if (this.Selection.StartPos > Pos)
                this.Selection.StartPos = Pos;

            if (this.Selection.EndPos >= Pos + Count)
                this.Selection.EndPos -= Count;
            else if (this.Selection.EndPos >= Pos)
                this.Selection.EndPos = Math.max(0, Pos - 1);
        }
        else
        {
            if (this.Selection.StartPos >= Pos + Count)
                this.Selection.StartPos -= Count;
            else if (this.Selection.StartPos >= Pos)
                this.Selection.StartPos = Math.max(0, Pos - 1);

            if (this.Selection.EndPos > Pos + Count)
                this.Selection.EndPos -= Count;
            else if (this.Selection.EndPos > Pos)
                this.Selection.EndPos = Pos;
        }

        this.Selection.StartPos = Math.min(this.Content.length - 1, Math.max(0, this.Selection.StartPos));
        this.Selection.EndPos   = Math.min(this.Content.length - 1, Math.max(0, this.Selection.EndPos));
    }

    // Обновляем позиции в NearestPos
    var NearPosLen = this.NearPosArray.length;
    for (var Index = 0; Index < NearPosLen; Index++)
    {
        var HyperNearPos = this.NearPosArray[Index];
        var ContentPos = HyperNearPos.NearPos.ContentPos;
        var Depth      = HyperNearPos.Depth;

        if (ContentPos.Data[Depth] > Pos + Count)
            ContentPos.Data[Depth] -= Count;
        else if (ContentPos.Data[Depth] > Pos)
            ContentPos.Data[Depth] = Math.max(0 , Pos);
    }
};
CMathContent.prototype.Get_Default_TPrp = function()
{
    return this.ParaMath.Get_Default_TPrp();
};
/////////////////////////
CMathContent.prototype.Is_Empty = function()
{
    return this.Content.length == 0;
};
CMathContent.prototype.Copy = function(Selected)
{
    var NewContent = new CMathContent();
    this.CopyTo(NewContent, Selected);
    return NewContent;
};
CMathContent.prototype.CopyTo = function(OtherContent, Selected)
{
    var nStartPos, nEndPos;

    if(true === Selected)
    {
        if(this.Selection.StartPos < this.Selection.EndPos)
        {
            nStartPos = this.Selection.StartPos;
            nEndPos   = this.Selection.EndPos;
        }
        else
        {
            nStartPos = this.Selection.EndPos;
            nEndPos   = this.Selection.StartPos;
        }
    }
    else
    {
        nStartPos = 0;
        nEndPos   = this.Content.length - 1;
    }

    OtherContent.plHid = this.plhHide;
    OtherContent.SetArgSize(this.ArgSize.GetValue());

    for(var nPos = nStartPos; nPos <= nEndPos; nPos++)
    {
        var oElement;
        if(this.Content[nPos].Type == para_Math_Run)
            oElement = this.Content[nPos].Copy(Selected);
        else
            oElement = this.Content[nPos].Copy(false);

        OtherContent.Internal_Content_Add(OtherContent.Content.length, oElement);
    }
};
CMathContent.prototype.getElem = function(nNum)
{
    return this.Content[nNum];
};
CMathContent.prototype.GetLastElement = function()
{
    var pos = this.Content.length - 1;

    while(this.Content[pos].Type == para_Math_Run && this.Content[pos].Is_Empty() && pos > 0)
    {
        pos--;
    }

    var last = this.Content[pos].Type == para_Math_Run ? this.Content[pos] : this.Content[pos].GetLastElement();

    return last;
};
CMathContent.prototype.GetFirstElement = function()
{
    var pos = 0;

    while(this.Content[pos].Type == para_Math_Run && this.Content[pos].Is_Empty() && pos < this.Content.length - 1)
    {
        pos++;
    }

    var first = this.Content[pos].Type == para_Math_Run ? this.Content[pos] : this.Content[pos].GetFirstElement();

    return first;
};
////////////////////////////////////////////////////////////////
CMathContent.prototype.Write_ToBinary2 = function(Writer)
{
    Writer.WriteLong(AscDFH.historyitem_type_MathContent);

    // Long : Id
    Writer.WriteString2(this.Id);
};
CMathContent.prototype.Read_FromBinary2 = function(Reader)
{
    // Long : Id
    this.Id = Reader.GetString2();
};
CMathContent.prototype.Refresh_RecalcData = function()
{
    if(this.ParaMath !== null)
        this.ParaMath.Refresh_RecalcData(); // Refresh_RecalcData сообщает родительскому классу, что у него произошли изменения, нужно пересчитать
};
CMathContent.prototype.Insert_MathContent = function(oMathContent, Pos, bSelect)
{
    if (null === this.ParaMath || null === this.ParaMath.Paragraph)
        bSelect = false;

    if (undefined === Pos)
        Pos = this.CurPos;

    var nCount = oMathContent.Content.length;
    for (var nIndex = 0; nIndex < nCount; nIndex++)
    {
        this.Internal_Content_Add(Pos + nIndex, oMathContent.Content[nIndex], false);

        if (true === bSelect)
        {
            oMathContent.Content[nIndex].SelectAll();
        }
    }

    this.CurPos = Pos + nCount;

    if (true === bSelect)
    {
        this.Selection.Use = true;
        this.Selection.StartPos = Pos;
        this.Selection.EndPos   = Pos + nCount - 1;

        if (!this.bRoot)
            this.ParentElement.Select_MathContent(this);
        else
            this.ParaMath.bSelectionUse = true;

        this.ParaMath.Paragraph.Select_Math(this.ParaMath);
    }

    this.Correct_Content(true);
    this.Correct_ContentPos(-1);
};
CMathContent.prototype.Set_ParaMath = function(ParaMath, Parent)
{
    this.Parent   = Parent;
    this.ParaMath = ParaMath;

    for (var Index = 0, Count = this.Content.length; Index < Count; Index++)
    {
        this.Content[Index].Set_ParaMath(ParaMath, this);
    }
};
CMathContent.prototype.Load_FromMenu = function(Type, Paragraph, TextPr)
{
    this.Paragraph = Paragraph;

    var Pr = {
    	ctrPrp : TextPr ? TextPr.Copy() : new CTextPr()
    };

    Pr.ctrPrp.Italic = true;
    Pr.ctrPrp.RFonts.Set_All("Cambria Math", -1);

    var MainType = Type >> 24;

    if (MainType === c_oAscMathMainType.Symbol)
        this.private_LoadFromMenuSymbol(Type, Pr);
    else if (MainType === c_oAscMathMainType.Fraction)
        this.private_LoadFromMenuFraction(Type, Pr);
    else if (MainType === c_oAscMathMainType.Script)
        this.private_LoadFromMenuScript(Type, Pr);
    else if (MainType === c_oAscMathMainType.Radical)
        this.private_LoadFromMenuRadical(Type, Pr);
    else if (MainType === c_oAscMathMainType.Integral)
        this.private_LoadFromMenuIntegral(Type, Pr);
    else if (MainType === c_oAscMathMainType.LargeOperator)
        this.private_LoadFromMenuLargeOperator(Type, Pr);
    else if (MainType === c_oAscMathMainType.Bracket)
        this.private_LoadFromMenuBracket(Type, Pr);
    else if (MainType === c_oAscMathMainType.Function)
        this.private_LoadFromMenuFunction(Type, Pr);
    else if (MainType === c_oAscMathMainType.Accent)
        this.private_LoadFromMenuAccent(Type, Pr);
    else if (MainType === c_oAscMathMainType.LimitLog)
        this.private_LoadFromMenuLimitLog(Type, Pr);
    else if (MainType === c_oAscMathMainType.Operator)
        this.private_LoadFromMenuOperator(Type, Pr);
    else if (MainType === c_oAscMathMainType.Matrix)
        this.private_LoadFromMenuMatrix(Type, Pr);
    else if(MainType == c_oAscMathMainType.Empty_Content)
        this.private_LoadFromMenuDefaultText(Type, Pr);
};
CMathContent.prototype.private_LoadFromMenuSymbol = function(Type, Pr)
{
    var Code = -1;

    switch (Type)
    {
        case c_oAscMathType.Symbol_pm            : Code = 0x00B1; break;
        case c_oAscMathType.Symbol_infinity      : Code = 0x221E; break;
        case c_oAscMathType.Symbol_equals        : Code = 0x003D; break;
        case c_oAscMathType.Symbol_neq           : Code = 0x2260; break;
        case c_oAscMathType.Symbol_about         : Code = 0x007E; break;
        case c_oAscMathType.Symbol_times         : Code = 0x00D7; break;
        case c_oAscMathType.Symbol_div           : Code = 0x00F7; break;
        case c_oAscMathType.Symbol_factorial     : Code = 0x0021; break;
        case c_oAscMathType.Symbol_propto        : Code = 0x221D; break;
        case c_oAscMathType.Symbol_less          : Code = 0x003C; break;
        case c_oAscMathType.Symbol_ll            : Code = 0x226A; break;
        case c_oAscMathType.Symbol_greater       : Code = 0x003E; break;
        case c_oAscMathType.Symbol_gg            : Code = 0x226B; break;
        case c_oAscMathType.Symbol_leq           : Code = 0x2264; break;
        case c_oAscMathType.Symbol_geq           : Code = 0x2265; break;
        case c_oAscMathType.Symbol_mp            : Code = 0x2213; break;
        case c_oAscMathType.Symbol_cong          : Code = 0x2245; break;
        case c_oAscMathType.Symbol_approx        : Code = 0x2248; break;
        case c_oAscMathType.Symbol_equiv         : Code = 0x2261; break;
        case c_oAscMathType.Symbol_forall        : Code = 0x2200; break;
        case c_oAscMathType.Symbol_additional    : Code = 0x2201; break;
        case c_oAscMathType.Symbol_partial       : Code = 0x1D715; break;
        case c_oAscMathType.Symbol_sqrt          : this.Add_Radical(Pr, null, null); break;
        case c_oAscMathType.Symbol_cbrt          : this.Add_Radical({ctrPrp : Pr.ctrPrp, type : DEGREE_RADICAL}, null, "3"); break;
        case c_oAscMathType.Symbol_qdrt          : this.Add_Radical({ctrPrp : Pr.ctrPrp, type : DEGREE_RADICAL}, null, "4"); break;
        case c_oAscMathType.Symbol_cup           : Code = 0x222A; break;
        case c_oAscMathType.Symbol_cap           : Code = 0x2229; break;
        case c_oAscMathType.Symbol_emptyset      : Code = 0x2205; break;
        case c_oAscMathType.Symbol_percent       : Code = 0x0025; break;
        case c_oAscMathType.Symbol_degree        : Code = 0x00B0; break;
        case c_oAscMathType.Symbol_fahrenheit    : Code = 0x2109; break;
        case c_oAscMathType.Symbol_celsius       : Code = 0x2103; break;
        case c_oAscMathType.Symbol_inc           : Code = 0x2206; break;
        case c_oAscMathType.Symbol_nabla         : Code = 0x2207; break;
        case c_oAscMathType.Symbol_exists        : Code = 0x2203; break;
        case c_oAscMathType.Symbol_notexists     : Code = 0x2204; break;
        case c_oAscMathType.Symbol_in            : Code = 0x2208; break;
        case c_oAscMathType.Symbol_ni            : Code = 0x220B; break;
        case c_oAscMathType.Symbol_leftarrow     : Code = 0x2190; break;
        case c_oAscMathType.Symbol_uparrow       : Code = 0x2191; break;
        case c_oAscMathType.Symbol_rightarrow    : Code = 0x2192; break;
        case c_oAscMathType.Symbol_downarrow     : Code = 0x2193; break;
        case c_oAscMathType.Symbol_leftrightarrow: Code = 0x2194; break;
        case c_oAscMathType.Symbol_therefore     : Code = 0x2234; break;
        case c_oAscMathType.Symbol_plus          : Code = 0x002B; break;
        case c_oAscMathType.Symbol_minus         : Code = 0x2212; break;
        case c_oAscMathType.Symbol_not           : Code = 0x00AC; break;
        case c_oAscMathType.Symbol_ast           : Code = 0x2217; break;
        case c_oAscMathType.Symbol_bullet        : Code = 0x2219; break;
        case c_oAscMathType.Symbol_vdots         : Code = 0x22EE; break;
        case c_oAscMathType.Symbol_cdots         : Code = 0x22EF; break;
        case c_oAscMathType.Symbol_rddots        : Code = 0x22F0; break;
        case c_oAscMathType.Symbol_ddots         : Code = 0x22F1; break;
        case c_oAscMathType.Symbol_aleph         : Code = 0x2135; break;
        case c_oAscMathType.Symbol_beth          : Code = 0x2136; break;
        case c_oAscMathType.Symbol_QED           : Code = 0x220E; break;
        case c_oAscMathType.Symbol_alpha         : Code = 0x03B1; break;
        case c_oAscMathType.Symbol_beta          : Code = 0x03B2; break;
        case c_oAscMathType.Symbol_gamma         : Code = 0x03B3; break;
        case c_oAscMathType.Symbol_delta         : Code = 0x03B4; break;
        case c_oAscMathType.Symbol_varepsilon    : Code = 0x03B5; break;
        case c_oAscMathType.Symbol_epsilon       : Code = 0x03F5; break;
        case c_oAscMathType.Symbol_zeta          : Code = 0x03B6; break;
        case c_oAscMathType.Symbol_eta           : Code = 0x03B7; break;
        case c_oAscMathType.Symbol_theta         : Code = 0x03B8; break;
        case c_oAscMathType.Symbol_vartheta      : Code = 0x03D1; break;
        case c_oAscMathType.Symbol_iota          : Code = 0x03B9; break;
        case c_oAscMathType.Symbol_kappa         : Code = 0x03BA; break;
        case c_oAscMathType.Symbol_lambda        : Code = 0x03BB; break;
        case c_oAscMathType.Symbol_mu            : Code = 0x03BC; break;
        case c_oAscMathType.Symbol_nu            : Code = 0x03BD; break;
        case c_oAscMathType.Symbol_xsi           : Code = 0x03BE; break;
        case c_oAscMathType.Symbol_o             : Code = 0x03BF; break;
        case c_oAscMathType.Symbol_pi            : Code = 0x03C0; break;
        case c_oAscMathType.Symbol_varpi         : Code = 0x03D6; break;
        case c_oAscMathType.Symbol_rho           : Code = 0x03C1; break;
        case c_oAscMathType.Symbol_varrho        : Code = 0x03F1; break;
        case c_oAscMathType.Symbol_sigma         : Code = 0x03C3; break;
        case c_oAscMathType.Symbol_varsigma      : Code = 0x03C2; break;
        case c_oAscMathType.Symbol_tau           : Code = 0x03C4; break;
        case c_oAscMathType.Symbol_upsilon       : Code = 0x03C5; break;
        case c_oAscMathType.Symbol_varphi        : Code = 0x03C6; break;
        case c_oAscMathType.Symbol_phi           : Code = 0x03D5; break;
        case c_oAscMathType.Symbol_chi           : Code = 0x03C7; break;
        case c_oAscMathType.Symbol_psi           : Code = 0x03C8; break;
        case c_oAscMathType.Symbol_omega         : Code = 0x03C9; break;
        case c_oAscMathType.Symbol_Alpha         : Code = 0x0391; break;
        case c_oAscMathType.Symbol_Beta          : Code = 0x0392; break;
        case c_oAscMathType.Symbol_Gamma         : Code = 0x0393; break;
        case c_oAscMathType.Symbol_Delta         : Code = 0x0394; break;
        case c_oAscMathType.Symbol_Epsilon       : Code = 0x0395; break;
        case c_oAscMathType.Symbol_Zeta          : Code = 0x0396; break;
        case c_oAscMathType.Symbol_Eta           : Code = 0x0397; break;
        case c_oAscMathType.Symbol_Theta         : Code = 0x0398; break;
        case c_oAscMathType.Symbol_Iota          : Code = 0x0399; break;
        case c_oAscMathType.Symbol_Kappa         : Code = 0x039A; break;
        case c_oAscMathType.Symbol_Lambda        : Code = 0x039B; break;
        case c_oAscMathType.Symbol_Mu            : Code = 0x039C; break;
        case c_oAscMathType.Symbol_Nu            : Code = 0x039D; break;
        case c_oAscMathType.Symbol_Xsi           : Code = 0x039E; break;
        case c_oAscMathType.Symbol_O             : Code = 0x039F; break;
        case c_oAscMathType.Symbol_Pi            : Code = 0x03A0; break;
        case c_oAscMathType.Symbol_Rho           : Code = 0x03A1; break;
        case c_oAscMathType.Symbol_Sigma         : Code = 0x03A3; break;
        case c_oAscMathType.Symbol_Tau           : Code = 0x03A4; break;
        case c_oAscMathType.Symbol_Upsilon       : Code = 0x03A5; break;
        case c_oAscMathType.Symbol_Phi           : Code = 0x03A6; break;
        case c_oAscMathType.Symbol_Chi           : Code = 0x03A7; break;
        case c_oAscMathType.Symbol_Psi           : Code = 0x03A8; break;
        case c_oAscMathType.Symbol_Omega         : Code = 0x03A9; break;
    }

    if (-1 !== Code)
    {
        var TextPr, MathPr;

        if (this.Content.length <= 0)
			this.Correct_Content();

        if(this.Content.length > 0 && this.Content[this.CurPos].Type == para_Math_Run && this.IsSelectionEmpty() == true) // находимся в Run, селект отсутствует
        {
            TextPr = this.Content[this.CurPos].Get_TextPr();
            TextPr.RFonts.Set_All("Cambria Math", -1);          //  на данный момент добавляются символы исключительно из Cambria Math
            MathPr = this.Content[this.CurPos].Get_MathPr();
        }

        this.Add_Symbol(Code, TextPr, MathPr);
    }
};
CMathContent.prototype.private_LoadFromMenuFraction = function(Type, Pr)
{
    switch (Type)
    {
        case c_oAscMathType.FractionVertical   : this.Add_Fraction(Pr, null, null); break;
        case c_oAscMathType.FractionDiagonal   : this.Add_Fraction({ctrPrp : Pr.ctrPrp, type : SKEWED_FRACTION}, null, null); break;
        case c_oAscMathType.FractionHorizontal : this.Add_Fraction({ctrPrp : Pr.ctrPrp, type : LINEAR_FRACTION}, null, null); break;
        case c_oAscMathType.FractionSmall:
            var oBox = new CBox(Pr);
            this.Add_Element(oBox);
            var BoxMathContent = oBox.getBase();
            BoxMathContent.SetArgSize(-1);
            BoxMathContent.Add_Fraction(Pr, null, null);
            break;

        case c_oAscMathType.FractionDifferential_1: this.Add_Fraction(Pr, "dx", "dy"); break;
        case c_oAscMathType.FractionDifferential_2: this.Add_Fraction(Pr, String.fromCharCode(916) + "y", String.fromCharCode(916) + "x"); break;
        case c_oAscMathType.FractionDifferential_3: this.Add_Fraction(Pr, String.fromCharCode(8706) + "y", String.fromCharCode(8706) + "x"); break;
        case c_oAscMathType.FractionDifferential_4: this.Add_Fraction(Pr, String.fromCharCode(948) + "y", String.fromCharCode(948) + "x"); break;
        case c_oAscMathType.FractionPi_2          : this.Add_Fraction(Pr, String.fromCharCode(960), "2"); break;
    }
};
CMathContent.prototype.private_LoadFromMenuScript = function(Type, Pr)
{
    switch (Type)
    {
        case c_oAscMathType.ScriptSup: this.Add_Script(false, {ctrPrp : Pr.ctrPrp, type : DEGREE_SUPERSCRIPT}, null, null, null); break;
        case c_oAscMathType.ScriptSub: this.Add_Script(false, {ctrPrp : Pr.ctrPrp, type : DEGREE_SUBSCRIPT}, null, null, null); break;
        case c_oAscMathType.ScriptSubSup: this.Add_Script(true, {ctrPrp : Pr.ctrPrp, type : DEGREE_SubSup}, null, null, null); break;
        case c_oAscMathType.ScriptSubSupLeft:this.Add_Script(true, {ctrPrp : Pr.ctrPrp, type : DEGREE_PreSubSup}, null, null, null); break;
        case c_oAscMathType.ScriptCustom_1:
            Pr.type = DEGREE_SUBSCRIPT;
            var Script = this.Add_Script(false, Pr, "x", null, null);
            var SubMathContent = Script.getLowerIterator();
            Pr.type = DEGREE_SUPERSCRIPT;
            SubMathContent.Add_Script(false, Pr, "y", "2", null);
            break;

        case c_oAscMathType.ScriptCustom_2: this.Add_Script(false, {ctrPrp : Pr.ctrPrp, type : DEGREE_SUPERSCRIPT}, "e", "-i" + String.fromCharCode(969) + "t", null); break;
        case c_oAscMathType.ScriptCustom_3: this.Add_Script(false, {ctrPrp : Pr.ctrPrp, type : DEGREE_SUPERSCRIPT}, "x", "2", null); break;
        case c_oAscMathType.ScriptCustom_4: this.Add_Script(true, {ctrPrp : Pr.ctrPrp, type : DEGREE_PreSubSup}, "Y", "n", "1"); break;
    }
};
CMathContent.prototype.private_LoadFromMenuRadical = function(Type, Pr)
{
    switch (Type)
    {
        case c_oAscMathType.RadicalSqrt:
            Pr.type    = SQUARE_RADICAL;
            Pr.degHide = true;
            this.Add_Radical(Pr, null, null);
            break;

        case c_oAscMathType.RadicalRoot_n:
            Pr.type = DEGREE_RADICAL;
            this.Add_Radical(Pr, null, null);
            break;

        case c_oAscMathType.RadicalRoot_2:
            Pr.type = DEGREE_RADICAL;
            this.Add_Radical(Pr, null, "2");
            break;

        case c_oAscMathType.RadicalRoot_3:
            Pr.type = DEGREE_RADICAL;
            this.Add_Radical(Pr, null, "3");
            break;

        case c_oAscMathType.RadicalCustom_1:
            var Fraction = this.Add_Fraction(Pr, null, null);
            var NumMathContent = Fraction.getNumeratorMathContent();
            var DenMathContent = Fraction.getDenominatorMathContent();

            NumMathContent.Add_Text("-b" + String.fromCharCode(177), this.Paragraph);
            Pr.type    = SQUARE_RADICAL;
            Pr.degHide = true;
            var Radical = NumMathContent.Add_Radical(Pr, null, null);
            var RadicalBaseMathContent = Radical.getBase();
            RadicalBaseMathContent.Add_Script(false, {ctrPrp : Pr.ctrPrp, type : DEGREE_SUPERSCRIPT}, "b", "2", null);
            RadicalBaseMathContent.Add_Text("-4ac", this.Paragraph);

            DenMathContent.Add_Text("2a", this.Paragraph);

            break;
        case c_oAscMathType.RadicalCustom_2:
            Pr.type    = SQUARE_RADICAL;
            Pr.degHide = true;
            var Radical = this.Add_Radical(Pr, null, null);
            var BaseMathContent = Radical.getBase();

            var ScriptPr = {ctrPrp : Pr.ctrPrp, type : DEGREE_SUPERSCRIPT};
            BaseMathContent.Add_Script(false, ScriptPr, "a", "2", null);
            BaseMathContent.Add_Text("+", this.Paragraph);
            BaseMathContent.Add_Script(false, ScriptPr, "b", "2", null);
            break;
    }
};
CMathContent.prototype.private_LoadFromMenuIntegral = function(Type, Pr)
{
    switch(Type)
    {
        case c_oAscMathType.Integral:                           this.Add_Integral(1, false, NARY_UndOvr,  true,  true, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralSubSup:                     this.Add_Integral(1, false, NARY_SubSup, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralCenterSubSup:               this.Add_Integral(1, false, NARY_UndOvr, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralDouble:                     this.Add_Integral(2, false, NARY_UndOvr,  true,  true, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralDoubleSubSup:               this.Add_Integral(2, false, NARY_SubSup, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralDoubleCenterSubSup:         this.Add_Integral(2, false, NARY_UndOvr, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralTriple:                     this.Add_Integral(3, false, NARY_UndOvr,  true,  true, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralTripleSubSup:               this.Add_Integral(3, false, NARY_SubSup, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralTripleCenterSubSup:         this.Add_Integral(3, false, NARY_UndOvr, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralOriented:                   this.Add_Integral(1,  true, NARY_UndOvr,  true,  true, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralOrientedSubSup:             this.Add_Integral(1,  true, NARY_SubSup, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralOrientedCenterSubSup:       this.Add_Integral(1,  true, NARY_UndOvr, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralOrientedDouble:             this.Add_Integral(2,  true, NARY_UndOvr,  true,  true, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralOrientedDoubleSubSup:       this.Add_Integral(2,  true, NARY_SubSup, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralOrientedDoubleCenterSubSup: this.Add_Integral(2,  true, NARY_UndOvr, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralOrientedTriple:             this.Add_Integral(3,  true, NARY_UndOvr,  true,  true, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralOrientedTripleSubSup:       this.Add_Integral(3,  true, NARY_SubSup, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.IntegralOrientedTripleCenterSubSup: this.Add_Integral(3,  true, NARY_UndOvr, false, false, Pr.ctrPrp, null, null, null); break;

        case c_oAscMathType.Integral_dx:     Pr.diff = 1; this.Add_Box(Pr, "dx"); break;
        case c_oAscMathType.Integral_dy:     Pr.diff = 1; this.Add_Box(Pr, "dy"); break;
        case c_oAscMathType.Integral_dtheta: Pr.diff = 1; this.Add_Box(Pr, "d" + String.fromCharCode(952)); break;
    }
};
CMathContent.prototype.private_LoadFromMenuLargeOperator = function(Type, Pr)
{
    switch(Type)
    {
        case c_oAscMathType.LargeOperator_Sum:              this.Add_LargeOperator(1, NARY_UndOvr,  true,  true, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Sum_CenterSubSup: this.Add_LargeOperator(1, NARY_UndOvr, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Sum_SubSup:       this.Add_LargeOperator(1, NARY_SubSup, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Sum_CenterSub:    this.Add_LargeOperator(1, NARY_UndOvr,  true, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Sum_Sub:          this.Add_LargeOperator(1, NARY_SubSup,  true, false, Pr.ctrPrp, null, null, null); break;

        case c_oAscMathType.LargeOperator_Prod:              this.Add_LargeOperator(2, NARY_UndOvr,  true,  true, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Prod_CenterSubSup: this.Add_LargeOperator(2, NARY_UndOvr, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Prod_SubSup:       this.Add_LargeOperator(2, NARY_SubSup, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Prod_CenterSub:    this.Add_LargeOperator(2, NARY_UndOvr,  true, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Prod_Sub:          this.Add_LargeOperator(2, NARY_SubSup,  true, false, Pr.ctrPrp, null, null, null); break;

        case c_oAscMathType.LargeOperator_CoProd:              this.Add_LargeOperator(3, NARY_UndOvr,  true,  true, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_CoProd_CenterSubSup: this.Add_LargeOperator(3, NARY_UndOvr, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_CoProd_SubSup:       this.Add_LargeOperator(3, NARY_SubSup, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_CoProd_CenterSub:    this.Add_LargeOperator(3, NARY_UndOvr,  true, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_CoProd_Sub:          this.Add_LargeOperator(3, NARY_SubSup,  true, false, Pr.ctrPrp, null, null, null); break;

        case c_oAscMathType.LargeOperator_Union:              this.Add_LargeOperator(4, NARY_UndOvr,  true,  true, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Union_CenterSubSup: this.Add_LargeOperator(4, NARY_UndOvr, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Union_SubSup:       this.Add_LargeOperator(4, NARY_SubSup, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Union_CenterSub:    this.Add_LargeOperator(4, NARY_UndOvr,  true, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Union_Sub:          this.Add_LargeOperator(4, NARY_SubSup,  true, false, Pr.ctrPrp, null, null, null); break;

        case c_oAscMathType.LargeOperator_Intersection:              this.Add_LargeOperator(5, NARY_UndOvr,  true,  true, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Intersection_CenterSubSup: this.Add_LargeOperator(5, NARY_UndOvr, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Intersection_SubSup:       this.Add_LargeOperator(5, NARY_SubSup, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Intersection_CenterSub:    this.Add_LargeOperator(5, NARY_UndOvr,  true, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Intersection_Sub:          this.Add_LargeOperator(5, NARY_SubSup,  true, false, Pr.ctrPrp, null, null, null); break;

        case c_oAscMathType.LargeOperator_Disjunction:              this.Add_LargeOperator(6, NARY_UndOvr,  true,  true, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Disjunction_CenterSubSup: this.Add_LargeOperator(6, NARY_UndOvr, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Disjunction_SubSup:       this.Add_LargeOperator(6, NARY_SubSup, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Disjunction_CenterSub:    this.Add_LargeOperator(6, NARY_UndOvr,  true, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Disjunction_Sub:          this.Add_LargeOperator(6, NARY_SubSup,  true, false, Pr.ctrPrp, null, null, null); break;

        case c_oAscMathType.LargeOperator_Conjunction:              this.Add_LargeOperator(7, NARY_UndOvr,  true,  true, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Conjunction_CenterSubSup: this.Add_LargeOperator(7, NARY_UndOvr, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Conjunction_SubSup:       this.Add_LargeOperator(7, NARY_SubSup, false, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Conjunction_CenterSub:    this.Add_LargeOperator(7, NARY_UndOvr,  true, false, Pr.ctrPrp, null, null, null); break;
        case c_oAscMathType.LargeOperator_Conjunction_Sub:          this.Add_LargeOperator(7, NARY_SubSup,  true, false, Pr.ctrPrp, null, null, null); break;

        case c_oAscMathType.LargeOperator_Custom_1:
            var Sum = this.Add_LargeOperator(1, NARY_UndOvr,  true, false, Pr.ctrPrp, null, null, "k");
            var BaseMathContent = Sum.getBaseMathContent();
            var Delimiter = BaseMathContent.Add_Delimiter({ctrPrp : Pr.ctrPrp, column : 1}, 1, [null]);
            var DelimiterMathContent = Delimiter.getElementMathContent(0);
            DelimiterMathContent.Add_Fraction({ctrPrp: Pr.ctrPrp, type : NO_BAR_FRACTION}, "n", "k");
            break;

        case c_oAscMathType.LargeOperator_Custom_2:
            this.Add_LargeOperator(1, NARY_UndOvr, false, false, Pr.ctrPrp, null, "n", "i=0");
            break;

        case c_oAscMathType.LargeOperator_Custom_3:
            var Sum = this.Add_LargeOperator(1, NARY_UndOvr,  true, false, Pr.ctrPrp, null, null, null);
            var SubMathContent = Sum.getSubMathContent();
            SubMathContent.Add_EqArray({ctrPrp: Pr.ctrPrp, row : 2}, 2, ["0≤ i ≤ m", "0< j < n"]);
            var BaseMathContent = Sum.getBaseMathContent();
            BaseMathContent.Add_Text("P", this.Paragraph);
            BaseMathContent.Add_Delimiter({ctrPrp : Pr.ctrPrp, column : 1}, 1, ["i, j"]);
            break;

        case c_oAscMathType.LargeOperator_Custom_4:
            var Prod = this.Add_LargeOperator(2, NARY_UndOvr, false, false, Pr.ctrPrp, null, "n", "k=1");
            var BaseMathContent = Prod.getBaseMathContent();
            BaseMathContent.Add_Script(false, {ctrPrp: Pr.ctrPrp, type : DEGREE_SUBSCRIPT}, "A", null, "k");
            break;

        case c_oAscMathType.LargeOperator_Custom_5:
            var Union = this.Add_LargeOperator(4, NARY_UndOvr, false, false, Pr.ctrPrp, null, "m", "n=1");
            var BaseMathContent = Union.getBaseMathContent();
            var Delimiter = BaseMathContent.Add_Delimiter({ctrPrp : Pr.ctrPrp, column : 1}, 1, [null]);
            BaseMathContent = Delimiter.getElementMathContent(0);
            BaseMathContent.Add_Script(false, {ctrPrp: Pr.ctrPrp, type : DEGREE_SUBSCRIPT}, "X", null, "n");
            BaseMathContent.Add_Text(String.fromCharCode(8745), this.Paragraph);
            BaseMathContent.Add_Script(false, {ctrPrp: Pr.ctrPrp, type : DEGREE_SUBSCRIPT}, "Y", null, "n");
            break;
    }
};
CMathContent.prototype.private_LoadFromMenuBracket = function(Type, Pr)
{
    switch(Type)
    {
        case c_oAscMathType.Bracket_Round                 : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],  null,  null); break;
        case c_oAscMathType.Bracket_Square                : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],    91,    93); break;
        case c_oAscMathType.Bracket_Curve                 : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],   123,   125); break;
        case c_oAscMathType.Bracket_Angle                 : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null], 10216, 10217); break;
        case c_oAscMathType.Bracket_LowLim                : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null], 0x230A, 0x230B); break;
        case c_oAscMathType.Bracket_UppLim                : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null], 0x2308, 0x2309); break;
        case c_oAscMathType.Bracket_Line                  : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],   124,   124); break;
        case c_oAscMathType.Bracket_LineDouble            : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],  8214,  8214); break;
        case c_oAscMathType.Bracket_Square_OpenOpen       : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],    91,    91); break;
        case c_oAscMathType.Bracket_Square_CloseClose     : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],    93,    93); break;
        case c_oAscMathType.Bracket_Square_CloseOpen      : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],    93,    91); break;
        case c_oAscMathType.Bracket_SquareDouble          : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null], 10214, 10215); break;

        case c_oAscMathType.Bracket_Round_Delimiter_2     : this.Add_DelimiterEx(Pr.ctrPrp, 2, [null, null], null, null); break;
        case c_oAscMathType.Bracket_Curve_Delimiter_2     : this.Add_DelimiterEx(Pr.ctrPrp, 2, [null, null], 123, 125); break;
        case c_oAscMathType.Bracket_Angle_Delimiter_2     : this.Add_DelimiterEx(Pr.ctrPrp, 2, [null, null], 10216, 10217); break;
        case c_oAscMathType.Bracket_Angle_Delimiter_3     : this.Add_DelimiterEx(Pr.ctrPrp, 3, [null, null, null], 10216, 10217); break;

        case c_oAscMathType.Bracket_Round_OpenNone        : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],  null,    -1); break;
        case c_oAscMathType.Bracket_Round_NoneOpen        : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],    -1,  null); break;
        case c_oAscMathType.Bracket_Square_OpenNone       : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],    91,    -1); break;
        case c_oAscMathType.Bracket_Square_NoneOpen       : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],    -1,    93); break;
        case c_oAscMathType.Bracket_Curve_OpenNone        : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],   123,    -1); break;
        case c_oAscMathType.Bracket_Curve_NoneOpen        : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],    -1,   125); break;
        case c_oAscMathType.Bracket_Angle_OpenNone        : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null], 10216,    -1); break;
        case c_oAscMathType.Bracket_Angle_NoneOpen        : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],    -1, 10217); break;
        case c_oAscMathType.Bracket_LowLim_OpenNone       : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null], 0x230A,    -1); break;
        case c_oAscMathType.Bracket_LowLim_NoneNone       : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],    -1,  0x230B); break;
        case c_oAscMathType.Bracket_UppLim_OpenNone       : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null], 0x2308,    -1); break;
        case c_oAscMathType.Bracket_UppLim_NoneOpen       : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],    -1,  0x2309); break;
        case c_oAscMathType.Bracket_Line_OpenNone         : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],   124,    -1); break;
        case c_oAscMathType.Bracket_Line_NoneOpen         : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],    -1,   124); break;
        case c_oAscMathType.Bracket_LineDouble_OpenNone   : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],  8214,    -1); break;
        case c_oAscMathType.Bracket_LineDouble_NoneOpen   : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],    -1,  8214); break;
        case c_oAscMathType.Bracket_SquareDouble_OpenNone : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null], 10214,    -1); break;
        case c_oAscMathType.Bracket_SquareDouble_NoneOpen : this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],    -1, 10215); break;

        case c_oAscMathType.Bracket_Custom_1:
            var Delimiter = this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],   123,    -1);
            var BaseMathContent = Delimiter.getElementMathContent(0);
            BaseMathContent.Add_EqArray({ctrPrp : Pr.ctrPrp, row : 2}, 2, [null, null]);
            break;

        case c_oAscMathType.Bracket_Custom_2:
            var Delimiter = this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],   123,    -1);
            var BaseMathContent = Delimiter.getElementMathContent(0);
            BaseMathContent.Add_EqArray({ctrPrp : Pr.ctrPrp, row : 3}, 3, [null, null, null]);
            break;

        case c_oAscMathType.Bracket_Custom_3:
            this.Add_Fraction({ctrPrp : Pr.ctrPrp, type : NO_BAR_FRACTION}, null, null);
            break;

        case c_oAscMathType.Bracket_Custom_4:
            var Delimiter = this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],  null,  null);
            var BaseMathContent = Delimiter.getElementMathContent(0);
            BaseMathContent.Add_Fraction({ctrPrp : Pr.ctrPrp, type : NO_BAR_FRACTION}, null, null);
            break;

        case c_oAscMathType.Bracket_Custom_5:
            this.Add_Text("f", this.Paragraph);
            this.Add_DelimiterEx(Pr.ctrPrp, 1, ["x"],  null,  null);
            this.Add_Text("=", this.Paragraph);
            var Delimiter = this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],   123,    -1);
            var BaseMathContent = Delimiter.getElementMathContent(0);
            BaseMathContent.Add_EqArray({ctrPrp : Pr.ctrPrp, row : 2}, 2, ["-x,  &x<0", "x,  &x" + String.fromCharCode(8805) + "0"]);
            break;

        case c_oAscMathType.Bracket_Custom_6:
            var Delimiter = this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],  null,  null);
            var BaseMathContent = Delimiter.getElementMathContent(0);
            BaseMathContent.Add_Fraction({ctrPrp : Pr.ctrPrp, type : NO_BAR_FRACTION}, "n", "k");
            break;

        case c_oAscMathType.Bracket_Custom_7:
            var Delimiter = this.Add_DelimiterEx(Pr.ctrPrp, 1, [null],  10216,  10217);
            var BaseMathContent = Delimiter.getElementMathContent(0);
            BaseMathContent.Add_Fraction({ctrPrp : Pr.ctrPrp, type : NO_BAR_FRACTION}, "n", "k");
            break;
    }
};
CMathContent.prototype.private_LoadFromMenuFunction = function(Type, Pr)
{
    switch(Type)
    {
        case c_oAscMathType.Function_Sin : this.Add_Function(Pr, "sin", null); break;
        case c_oAscMathType.Function_Cos : this.Add_Function(Pr, "cos", null); break;
        case c_oAscMathType.Function_Tan : this.Add_Function(Pr, "tan", null); break;
        case c_oAscMathType.Function_Csc : this.Add_Function(Pr, "csc", null); break;
        case c_oAscMathType.Function_Sec : this.Add_Function(Pr, "sec", null); break;
        case c_oAscMathType.Function_Cot : this.Add_Function(Pr, "cot", null); break;

        case c_oAscMathType.Function_1_Sin : this.Add_Function_1(Pr, "sin", null); break;
        case c_oAscMathType.Function_1_Cos : this.Add_Function_1(Pr, "cos", null); break;
        case c_oAscMathType.Function_1_Tan : this.Add_Function_1(Pr, "tan", null); break;
        case c_oAscMathType.Function_1_Csc : this.Add_Function_1(Pr, "csc", null); break;
        case c_oAscMathType.Function_1_Sec : this.Add_Function_1(Pr, "sec", null); break;
        case c_oAscMathType.Function_1_Cot : this.Add_Function_1(Pr, "cot", null); break;

        case c_oAscMathType.Function_Sinh : this.Add_Function(Pr, "sinh", null); break;
        case c_oAscMathType.Function_Cosh : this.Add_Function(Pr, "cosh", null); break;
        case c_oAscMathType.Function_Tanh : this.Add_Function(Pr, "tanh", null); break;
        case c_oAscMathType.Function_Csch : this.Add_Function(Pr, "csch", null); break;
        case c_oAscMathType.Function_Sech : this.Add_Function(Pr, "sech", null); break;
        case c_oAscMathType.Function_Coth : this.Add_Function(Pr, "coth", null); break;

        case c_oAscMathType.Function_1_Sinh : this.Add_Function_1(Pr, "sinh", null); break;
        case c_oAscMathType.Function_1_Cosh : this.Add_Function_1(Pr, "cosh", null); break;
        case c_oAscMathType.Function_1_Tanh : this.Add_Function_1(Pr, "tanh", null); break;
        case c_oAscMathType.Function_1_Csch : this.Add_Function_1(Pr, "csch", null); break;
        case c_oAscMathType.Function_1_Sech : this.Add_Function_1(Pr, "sech", null); break;
        case c_oAscMathType.Function_1_Coth : this.Add_Function_1(Pr, "coth", null); break;

        case c_oAscMathType.Function_Custom_1 : this.Add_Function(Pr, "sin", String.fromCharCode(952)); break;
        case c_oAscMathType.Function_Custom_2 : this.Add_Function(Pr, "cos", "2x"); break;
        case c_oAscMathType.Function_Custom_3 :
            var Theta = String.fromCharCode(952);
            this.Add_Function(Pr, "tan", Theta);
            this.Add_Text("=", this.Paragraph);
            var Fraction = this.Add_Fraction(Pr, null, null);
            var NumMathContent = Fraction.getNumeratorMathContent();
            var DenMathContent = Fraction.getDenominatorMathContent();
            NumMathContent.Add_Function(Pr, "sin", Theta);
            DenMathContent.Add_Function(Pr, "cos", Theta);
            break;
    }
};
CMathContent.prototype.private_LoadFromMenuAccent = function(Type, Pr)
{
    switch(Type)
    {
        case c_oAscMathType.Accent_Dot       : this.Add_Accent(Pr.ctrPrp, 775, null); break;
        case c_oAscMathType.Accent_DDot      : this.Add_Accent(Pr.ctrPrp, 776, null); break;
        case c_oAscMathType.Accent_DDDot     : this.Add_Accent(Pr.ctrPrp, 8411, null); break;
        case c_oAscMathType.Accent_Hat       : this.Add_Accent(Pr.ctrPrp, null, null); break;
        case c_oAscMathType.Accent_Check     : this.Add_Accent(Pr.ctrPrp, 780, null); break;
        case c_oAscMathType.Accent_Accent    : this.Add_Accent(Pr.ctrPrp, 769, null); break;
        case c_oAscMathType.Accent_Grave     : this.Add_Accent(Pr.ctrPrp, 768, null); break;
        case c_oAscMathType.Accent_Smile     : this.Add_Accent(Pr.ctrPrp, 774, null); break;
        case c_oAscMathType.Accent_Tilde     : this.Add_Accent(Pr.ctrPrp, 771, null); break;
        case c_oAscMathType.Accent_Bar       : this.Add_Accent(Pr.ctrPrp, 773, null); break;
        case c_oAscMathType.Accent_DoubleBar : this.Add_Accent(Pr.ctrPrp, 831, null); break;

        case c_oAscMathType.Accent_CurveBracketTop : this.Add_GroupCharacter({ctrPrp : Pr.ctrPrp, chr : 9182, pos : VJUST_TOP, vertJc : VJUST_BOT}, null ); break;
        case c_oAscMathType.Accent_CurveBracketBot : this.Add_GroupCharacter({ctrPrp : Pr.ctrPrp}, null ); break;
        case c_oAscMathType.Accent_GroupTop:
            var Limit = this.Add_Limit({ctrPrp : Pr.ctrPrp, type : LIMIT_UP}, null, null);
            var MathContent = Limit.getFName();
            MathContent.Add_GroupCharacter({ctrPrp : Pr.ctrPrp, chr : 9182, pos : VJUST_TOP, vertJc : VJUST_BOT}, null );
            break;

        case c_oAscMathType.Accent_GroupBot:
            var Limit = this.Add_Limit({ctrPrp : Pr.ctrPrp, type : LIMIT_LOW}, null, null);
            var MathContent = Limit.getFName();
            MathContent.Add_GroupCharacter({ctrPrp : Pr.ctrPrp}, null );
            break;

        case c_oAscMathType.Accent_ArrowL  : this.Add_Accent(Pr.ctrPrp, 8406, null); break;
        case c_oAscMathType.Accent_ArrowR  : this.Add_Accent(Pr.ctrPrp, 8407, null); break;
        case c_oAscMathType.Accent_ArrowD  : this.Add_Accent(Pr.ctrPrp, 8417, null); break;
        case c_oAscMathType.Accent_HarpoonL: this.Add_Accent(Pr.ctrPrp, 8400, null); break;
        case c_oAscMathType.Accent_HarpoonR: this.Add_Accent(Pr.ctrPrp, 8401, null); break;

        case c_oAscMathType.Accent_BorderBox :
            this.Add_BorderBox(Pr, null);
            break;

        case c_oAscMathType.Accent_BorderBoxCustom :
            var BorderBox = this.Add_BorderBox(Pr, null);
            var MathContent = BorderBox.getBase();
            MathContent.Add_Script(false, {ctrPrp : Pr.ctrPrp, type : DEGREE_SUPERSCRIPT}, "a", "2", null);
            MathContent.Add_Text("=", this.Paragraph);
            MathContent.Add_Script(false, {ctrPrp : Pr.ctrPrp, type : DEGREE_SUPERSCRIPT}, "b", "2", null);
            MathContent.Add_Text("+", this.Paragraph);
            MathContent.Add_Script(false, {ctrPrp : Pr.ctrPrp, type : DEGREE_SUPERSCRIPT}, "c", "2", null);
            break;

        case c_oAscMathType.Accent_BarTop : this.Add_Bar({ctrPrp : Pr.ctrPrp, pos : LOCATION_TOP}, null); break;
        case c_oAscMathType.Accent_BarBot : this.Add_Bar({ctrPrp : Pr.ctrPrp, pos : LOCATION_BOT}, null); break;

        case c_oAscMathType.Accent_Custom_1 :
            this.Add_Bar({ctrPrp : Pr.ctrPrp, pos : LOCATION_TOP}, "A");
            break;

        case c_oAscMathType.Accent_Custom_2 :
            this.Add_Bar({ctrPrp : Pr.ctrPrp, pos : LOCATION_TOP}, "ABC");
            break;

        case c_oAscMathType.Accent_Custom_3 :
            this.Add_Bar({ctrPrp : Pr.ctrPrp, pos : LOCATION_TOP}, "x" + String.fromCharCode(8853) + "y");
            break;
    }
};
CMathContent.prototype.private_LoadFromMenuLimitLog = function(Type, Pr)
{
    switch(Type)
    {
        case c_oAscMathType.LimitLog_LogBase:
            var Function = this.Add_Function(Pr, null, null);
            var MathContent = Function.getFName();
            var Script = MathContent.Add_Script(false, {ctrPrp : Pr.ctrPrp, type : DEGREE_SUBSCRIPT}, null, null, null);
            MathContent = Script.getBase();
            MathContent.Add_Text("log", this.Paragraph, STY_PLAIN);
            break;

        case c_oAscMathType.LimitLog_Log: this.Add_Function(Pr, "log", null); break;
        case c_oAscMathType.LimitLog_Lim: this.Add_FunctionWithLimit(Pr, "lim", null, null); break;
        case c_oAscMathType.LimitLog_Min: this.Add_FunctionWithLimit(Pr, "min", null, null); break;
        case c_oAscMathType.LimitLog_Max: this.Add_FunctionWithLimit(Pr, "max", null, null); break;
        case c_oAscMathType.LimitLog_Ln : this.Add_Function(Pr, "ln", null); break;

        case c_oAscMathType.LimitLog_Custom_1:
            var Function = this.Add_FunctionWithLimit(Pr, "lim", "n" + String.fromCharCode(8594,8734), null);
            var MathContent = Function.getArgument();
            var Script = MathContent.Add_Script(false, {ctrPrp : Pr.ctrPrp, type : DEGREE_SUPERSCRIPT}, null, "n", null);
            MathContent = Script.getBase();
            var Delimiter = MathContent.Add_Delimiter({ctrPrp : Pr.ctrPrp, column : 1}, 1, [null]);
            MathContent = Delimiter.getElementMathContent(0);
            MathContent.Add_Text("1+", this.Paragraph);
            MathContent.Add_Fraction({ctrPrp : Pr.ctrPrp}, "1", "n");
            break;

        case c_oAscMathType.LimitLog_Custom_2:
            var Function = this.Add_FunctionWithLimit(Pr, "max", "0" + String.fromCharCode(8804) + "x" + String.fromCharCode(8804) + "1", null);
            var MathContent = Function.getArgument();
            MathContent.Add_Text("x", this.Paragraph);
            var Script = MathContent.Add_Script(false, {ctrPrp : Pr.ctrPrp, type : DEGREE_SUPERSCRIPT}, "e", null, null);
            MathContent = Script.getUpperIterator();
            MathContent.Add_Text("-", this.Paragraph);
            MathContent.Add_Script(false, {ctrPrp : Pr.ctrPrp, type : DEGREE_SUPERSCRIPT}, "x", "2", null);
            break;
    }
};
CMathContent.prototype.private_LoadFromMenuOperator = function(Type, Pr)
{
    switch(Type)
    {
        case c_oAscMathType.Operator_ColonEquals     : this.Add_Box({ctrPrp : Pr.ctrPrp, opEmu : 1}, String.fromCharCode(0x2254)); break;
        case c_oAscMathType.Operator_EqualsEquals    : this.Add_Box({ctrPrp : Pr.ctrPrp, opEmu : 1}, "=="); break;
        case c_oAscMathType.Operator_PlusEquals      : this.Add_Box({ctrPrp : Pr.ctrPrp, opEmu : 1}, "+="); break;
        case c_oAscMathType.Operator_MinusEquals     : this.Add_Box({ctrPrp : Pr.ctrPrp, opEmu : 1}, "-="); break;
        case c_oAscMathType.Operator_Definition      : this.Add_Box({ctrPrp : Pr.ctrPrp, opEmu : 1}, String.fromCharCode(8797)); break;
        case c_oAscMathType.Operator_UnitOfMeasure   : this.Add_Box({ctrPrp : Pr.ctrPrp, opEmu : 1}, String.fromCharCode(8798)); break;
        case c_oAscMathType.Operator_DeltaEquals     : this.Add_Box({ctrPrp : Pr.ctrPrp, opEmu : 1}, String.fromCharCode(8796)); break;
        case c_oAscMathType.Operator_ArrowL_Top      : this.Add_BoxWithGroupChar({ctrPrp : Pr.ctrPrp, opEmu : 1}, VJUST_TOP, 8592, null); break;
        case c_oAscMathType.Operator_ArrowR_Top      : this.Add_BoxWithGroupChar({ctrPrp : Pr.ctrPrp, opEmu : 1}, VJUST_TOP, 8594, null); break;
        case c_oAscMathType.Operator_ArrowL_Bot      : this.Add_BoxWithGroupChar({ctrPrp : Pr.ctrPrp, opEmu : 1}, VJUST_BOT, 8592, null); break;
        case c_oAscMathType.Operator_ArrowR_Bot      : this.Add_BoxWithGroupChar({ctrPrp : Pr.ctrPrp, opEmu : 1}, VJUST_BOT, 8594, null); break;
        case c_oAscMathType.Operator_DoubleArrowL_Top: this.Add_BoxWithGroupChar({ctrPrp : Pr.ctrPrp, opEmu : 1}, VJUST_TOP, 8656, null); break;
        case c_oAscMathType.Operator_DoubleArrowR_Top: this.Add_BoxWithGroupChar({ctrPrp : Pr.ctrPrp, opEmu : 1}, VJUST_TOP, 8658, null); break;
        case c_oAscMathType.Operator_DoubleArrowL_Bot: this.Add_BoxWithGroupChar({ctrPrp : Pr.ctrPrp, opEmu : 1}, VJUST_BOT, 8656, null); break;
        case c_oAscMathType.Operator_DoubleArrowR_Bot: this.Add_BoxWithGroupChar({ctrPrp : Pr.ctrPrp, opEmu : 1}, VJUST_BOT, 8658, null); break;
        case c_oAscMathType.Operator_ArrowD_Top      : this.Add_BoxWithGroupChar({ctrPrp : Pr.ctrPrp, opEmu : 1}, VJUST_TOP, 8596, null); break;
        case c_oAscMathType.Operator_ArrowD_Bot      : this.Add_BoxWithGroupChar({ctrPrp : Pr.ctrPrp, opEmu : 1}, VJUST_BOT, 8596, null); break;
        case c_oAscMathType.Operator_DoubleArrowD_Top: this.Add_BoxWithGroupChar({ctrPrp : Pr.ctrPrp, opEmu : 1}, VJUST_TOP, 8660, null); break;
        case c_oAscMathType.Operator_DoubleArrowD_Bot: this.Add_BoxWithGroupChar({ctrPrp : Pr.ctrPrp, opEmu : 1}, VJUST_BOT, 8660, null); break;
        case c_oAscMathType.Operator_Custom_1        : this.Add_BoxWithGroupChar({ctrPrp : Pr.ctrPrp, opEmu : 1}, VJUST_BOT, 8594, "yields"); break;
        case c_oAscMathType.Operator_Custom_2        : this.Add_BoxWithGroupChar({ctrPrp : Pr.ctrPrp, opEmu : 1}, VJUST_BOT, 8594, String.fromCharCode(8710)); break;
    }
};
CMathContent.prototype.private_LoadFromMenuMatrix = function(Type, Pr)
{
    switch(Type)
    {
        case c_oAscMathType.Matrix_1_2: this.Add_Matrix(Pr.ctrPrp, 1, 2, false, []); break;
        case c_oAscMathType.Matrix_2_1: this.Add_Matrix(Pr.ctrPrp, 2, 1, false, []); break;
        case c_oAscMathType.Matrix_1_3: this.Add_Matrix(Pr.ctrPrp, 1, 3, false, []); break;
        case c_oAscMathType.Matrix_3_1: this.Add_Matrix(Pr.ctrPrp, 3, 1, false, []); break;
        case c_oAscMathType.Matrix_2_2: this.Add_Matrix(Pr.ctrPrp, 2, 2, false, []); break;
        case c_oAscMathType.Matrix_2_3: this.Add_Matrix(Pr.ctrPrp, 2, 3, false, []); break;
        case c_oAscMathType.Matrix_3_2: this.Add_Matrix(Pr.ctrPrp, 3, 2, false, []); break;
        case c_oAscMathType.Matrix_3_3: this.Add_Matrix(Pr.ctrPrp, 3, 3, false, []); break;

        case c_oAscMathType.Matrix_Dots_Center   : this.Add_Text(String.fromCharCode(8943), this.Paragraph); break;
        case c_oAscMathType.Matrix_Dots_Baseline : this.Add_Text(String.fromCharCode(8230), this.Paragraph); break;
        case c_oAscMathType.Matrix_Dots_Vertical : this.Add_Text(String.fromCharCode(8942), this.Paragraph); break;
        case c_oAscMathType.Matrix_Dots_Diagonal : this.Add_Text(String.fromCharCode(8945), this.Paragraph); break;

        case c_oAscMathType.Matrix_Identity_2         : this.Add_Matrix(Pr.ctrPrp, 2, 2, false, ["1", "0", "0", "1"]); break;
        case c_oAscMathType.Matrix_Identity_2_NoZeros : this.Add_Matrix(Pr.ctrPrp, 2, 2, true, ["1", null, null, "1"]); break;
        case c_oAscMathType.Matrix_Identity_3         : this.Add_Matrix(Pr.ctrPrp, 3, 3, false, ["1", "0", "0", "0", "1", "0", "0", "0", "1"]); break;
        case c_oAscMathType.Matrix_Identity_3_NoZeros : this.Add_Matrix(Pr.ctrPrp, 3, 3, true, ["1", null, null, null, "1", null, null, null, "1"]); break;

        case c_oAscMathType.Matrix_2_2_RoundBracket  : this.Add_MatrixWithBrackets(null, null, Pr.ctrPrp, 2, 2, false, []); break;
        case c_oAscMathType.Matrix_2_2_SquareBracket : this.Add_MatrixWithBrackets(  91,   93, Pr.ctrPrp, 2, 2, false, []); break;
        case c_oAscMathType.Matrix_2_2_LineBracket   : this.Add_MatrixWithBrackets( 124,  124, Pr.ctrPrp, 2, 2, false, []); break;
        case c_oAscMathType.Matrix_2_2_DLineBracket  : this.Add_MatrixWithBrackets(8214, 8214, Pr.ctrPrp, 2, 2, false, []); break;

        case c_oAscMathType.Matrix_Flat_Round  : this.Add_MatrixWithBrackets(null, null, Pr.ctrPrp, 3, 3, false, [null, String.fromCharCode(8943), null, String.fromCharCode(8942), String.fromCharCode(8945), String.fromCharCode(8942), null, String.fromCharCode(8943), null]); break;
        case c_oAscMathType.Matrix_Flat_Square : this.Add_MatrixWithBrackets(  91,   93, Pr.ctrPrp, 3, 3, false, [null, String.fromCharCode(8943), null, String.fromCharCode(8942), String.fromCharCode(8945), String.fromCharCode(8942), null, String.fromCharCode(8943), null]); break;
    }
};
CMathContent.prototype.private_LoadFromMenuDefaultText = function(Type, Pr)
{

};
CMathContent.prototype.Add_Element = function(Element)
{
    this.Internal_Content_Add(this.CurPos, Element, false);
    this.CurPos++;
};
CMathContent.prototype.Add_Text = function(sText, Paragraph, MathStyle)
{
    this.Paragraph = Paragraph;

    if (sText)
    {
        var MathRun = new ParaRun(this.Paragraph, true);

        for (var nCharPos = 0, nTextLen = sText.length; nCharPos < nTextLen; nCharPos++)
        {
            var oText = null;
            if (0x0026 == sText.charCodeAt(nCharPos))
                oText = new CMathAmp();
            else
            {
                oText = new CMathText(false);
                oText.addTxt(sText[nCharPos]);
            }
            MathRun.Add(oText, true);
        }

        MathRun.Set_RFont_ForMathRun();

        if (undefined !== MathStyle && null !== MathStyle)
            MathRun.Math_Apply_Style(MathStyle);

        this.Internal_Content_Add(this.CurPos, MathRun, false);
        this.CurPos++;
    }
};
CMathContent.prototype.Add_Symbol = function(Code, TextPr, MathPr)
{
    var MathRun = new ParaRun(this.Paragraph, true);

    var Symbol = new CMathText(false);
    Symbol.add(Code);
    MathRun.Add(Symbol, true);

    if(TextPr !== undefined)
        MathRun.Apply_Pr(TextPr);

    if(MathPr !== undefined)
        MathRun.Set_MathPr(MathPr);

    this.Internal_Content_Add(this.CurPos, MathRun, false);
    this.CurPos++;
};
CMathContent.prototype.Add_Fraction = function(Pr, NumText, DenText)
{
    var Fraction = new CFraction(Pr);
    this.Add_Element(Fraction);

    var DenMathContent = Fraction.getDenominatorMathContent();
    DenMathContent.Add_Text(DenText, this.Paragraph);

    var NumMathContent = Fraction.getNumeratorMathContent();
    NumMathContent.Add_Text(NumText, this.Paragraph);

    return Fraction;
};
CMathContent.prototype.Add_Script = function(bSubSup, Pr, BaseText, SupText, SubText)
{
    var Script = null;

    if (bSubSup)
        Script = new CDegreeSubSup(Pr);
    else
        Script = new CDegree(Pr);

    this.Add_Element(Script);

    var MathContent = Script.getBase();
    MathContent.Add_Text(BaseText, this.Paragraph);

    MathContent = Script.getUpperIterator();
    MathContent.Add_Text(SupText, this.Paragraph);

    MathContent = Script.getLowerIterator();
    MathContent.Add_Text(SubText, this.Paragraph);

    return Script;
};
CMathContent.prototype.Add_Radical = function(Pr, BaseText, DegreeText)
{
    var Radical = new CRadical(Pr);
    this.Add_Element(Radical);

    var MathContent = Radical.getBase();
    MathContent.Add_Text(BaseText, this.Paragraph);

    MathContent = Radical.getDegree();
    MathContent.Add_Text(DegreeText, this.Paragraph);

    return Radical;
};
CMathContent.prototype.Add_NAry = function(Pr, BaseText, SupText, SubText)
{
    var NAry = new CNary(Pr);
    this.Add_Element(NAry);

    var MathContent = NAry.getBase();
    MathContent.Add_Text(BaseText, this.Paragraph);

    MathContent = NAry.getSubMathContent();
    MathContent.Add_Text(SubText, this.Paragraph);

    MathContent = NAry.getSupMathContent();
    MathContent.Add_Text(SupText, this.Paragraph);

    return NAry;
};
CMathContent.prototype.Add_Integral = function(Dim, bOriented, limLoc, supHide, subHide, ctrPr, BaseText, SupText, SubText)
{
    var Pr = {ctrPrp : ctrPr};

    if (null !== limLoc)
        Pr.limLoc = limLoc;

    if (null !== supHide)
        Pr.supHide = supHide;

    if (null !== subHide)
        Pr.subHide = subHide;

    var chr = null;
    switch(Dim)
    {
        case 3: chr = (bOriented ? 8752 : 8749); break;
        case 2: chr = (bOriented ? 8751 : 8748); break;
        default:
        case 1: chr = (bOriented ? 8750 : null); break;
    }

    if (null !== chr)
        Pr.chr = chr;

    return this.Add_NAry(Pr, BaseText, SupText, SubText);
};
CMathContent.prototype.Add_LargeOperator = function(Type, limLoc, supHide, subHide, ctrPr, BaseText, SupText, SubText)
{
    var Pr = {ctrPrp : ctrPr};

    if (null !== limLoc)
        Pr.limLoc = limLoc;

    if (null !== supHide)
        Pr.supHide = supHide;

    if (null !== subHide)
        Pr.subHide = subHide;

    var chr = null;
    switch(Type)
    {
        default:
        case 1: chr = 8721; break;
        case 2: chr = 8719; break;
        case 3: chr = 8720; break;
        case 4: chr = 8899; break;
        case 5: chr = 8898; break;
        case 6: chr = 8897; break;
        case 7: chr = 8896; break;
    }

    if (null !== chr)
        Pr.chr = chr;

    return this.Add_NAry(Pr, BaseText, SupText, SubText);
};
CMathContent.prototype.Add_Delimiter = function(Pr, Count, aText)
{
    var Del = new CDelimiter(Pr);

    this.Add_Element(Del);

    for (var Index = 0; Index < Count; Index++)
    {
        var MathContent = Del.getElementMathContent(Index);
        MathContent.Add_Text(aText[Index], this.Paragraph);
    }

    return Del;
};
CMathContent.prototype.Add_DelimiterEx = function(ctrPr, Count, aText, begChr, endChr)
{
    var Pr =
    {
        ctrPrp : ctrPr,
        column : Count,
        begChr : begChr,
        endChr : endChr
    };

    return this.Add_Delimiter(Pr, Count, aText);
};
CMathContent.prototype.Add_EqArray = function(Pr, Count, aText)
{
    var EqArray = new CEqArray(Pr);

    this.Add_Element(EqArray);

    for (var Index = 0; Index < Count; Index++)
    {
        var MathContent = EqArray.getElementMathContent(Index);
        MathContent.Add_Text(aText[Index], this.Paragraph);
    }

    return EqArray;
};
CMathContent.prototype.Add_Box = function(Pr, BaseText)
{
    var Box = new CBox(Pr);
    this.Add_Element(Box);

    var MathContent = Box.getBase();
    MathContent.Add_Text(BaseText, this.Paragraph);

    return Box;
};
CMathContent.prototype.Add_BoxWithGroupChar = function(BoxPr, GroupPos, GroupChr, BaseText)
{
    var Box = this.Add_Box(BoxPr, null);
    var MathContent = Box.getBase();

    if (GroupPos === VJUST_TOP)
        MathContent.Add_GroupCharacter({ctrPrp : BoxPr.ctrPrp, pos : GroupPos, chr : GroupChr}, BaseText);
    else
        MathContent.Add_GroupCharacter({ctrPrp : BoxPr.ctrPrp, vertJc : GroupPos, chr : GroupChr}, BaseText);

    return Box;
};
CMathContent.prototype.Add_BorderBox = function(Pr, BaseText)
{
    var Box = new CBorderBox(Pr);
    this.Add_Element(Box);

    var MathContent = Box.getBase();
    MathContent.Add_Text(BaseText, this.Paragraph);

    return Box;
};
CMathContent.prototype.Add_Bar = function(Pr, BaseText)
{
    var Bar = new CBar(Pr);
    this.Add_Element(Bar);

    var MathContent = Bar.getBase();
    MathContent.Add_Text(BaseText, this.Paragraph);

    return Bar;
};
CMathContent.prototype.Add_Function = function(Pr, FName, BaseText)
{
    var MathFunc = new CMathFunc(Pr);
    this.Add_Element(MathFunc);

    var MathContent = MathFunc.getFName();
    MathContent.Add_Text(FName, this.Paragraph, STY_PLAIN);

    MathContent = MathFunc.getArgument();
    MathContent.Add_Text(BaseText, this.Paragraph);

    return MathFunc;
};
CMathContent.prototype.Add_Function_1 = function(Pr, FName, BaseText)
{
    var MathFunc = new CMathFunc(Pr);
    this.Add_Element(MathFunc);

    MathFunc.SetParagraph(this.Paragraph);

    var MathContent = MathFunc.getFName();
    var Script = MathContent.Add_Script(false, {ctrPrp : Pr.ctrPrp, type : DEGREE_SUPERSCRIPT}, null, "-1", null);
    MathContent = Script.getBase();
    MathContent.Add_Text(FName, this.Paragraph, STY_PLAIN);

    MathContent = MathFunc.getArgument();
    MathContent.Add_Text(BaseText, this.Paragraph);

    return MathFunc;
};
CMathContent.prototype.Add_FunctionWithLimit = function(Pr, FName, LimitText, BaseText)
{
    var MathFunc = new CMathFunc(Pr);
    this.Add_Element(MathFunc);

    MathFunc.SetParagraph(this.Paragraph);

    var MathContent = MathFunc.getFName();
    var Limit = MathContent.Add_Limit({ctrPrp : Pr.ctrPrp, type : LIMIT_LOW}, null, LimitText);
    MathContent = Limit.getFName();
    MathContent.Add_Text(FName, this.Paragraph, STY_PLAIN);

    MathContent = MathFunc.getArgument();
    MathContent.Add_Text(BaseText, this.Paragraph);

    return MathFunc;
};
CMathContent.prototype.Add_Accent = function(ctrPr, chr, BaseText)
{
    var Pr =
    {
        ctrPrp : ctrPr,
        chr    : chr
    };
    var Accent = new CAccent(Pr);
    this.Add_Element(Accent);

    var MathContent = Accent.getBase();
    MathContent.Add_Text(BaseText, this.Paragraph);

    return Accent;
};
CMathContent.prototype.Add_GroupCharacter = function(Pr, BaseText)
{
    var Group = new CGroupCharacter(Pr);
    this.Add_Element(Group);

    var MathContent = Group.getBase();
    MathContent.Add_Text(BaseText, this.Paragraph);

    return Group;
};
CMathContent.prototype.Add_Limit = function(Pr, BaseText, LimitText)
{
    var Limit = new CLimit(Pr);
    this.Add_Element(Limit);

    var MathContent = Limit.getFName();
    MathContent.Add_Text(BaseText, this.Paragraph);

    MathContent = Limit.getIterator();
    MathContent.Add_Text(LimitText, this.Paragraph);

    return Limit;
};
CMathContent.prototype.Add_Matrix = function(ctrPr, RowsCount, ColsCount, plcHide, aText)
{
    var Pr =
    {
        ctrPrp  : ctrPr,
        row     : RowsCount,
        mcs     : [{count : ColsCount, mcJc : MCJC_CENTER}],
        plcHide : plcHide
    };

    var Matrix = new CMathMatrix(Pr);
    this.Add_Element(Matrix);

    for (var RowIndex = 0; RowIndex < RowsCount; RowIndex++)
    {
        for (var ColIndex = 0; ColIndex < ColsCount; ColIndex++)
        {
            var MathContent = Matrix.getContentElement(RowIndex, ColIndex);
            MathContent.Add_Text(aText[RowIndex * ColsCount + ColIndex], this.Paragraph);
        }
    }

    return Matrix;
};
CMathContent.prototype.Add_MatrixWithBrackets = function(begChr, endChr, ctrPr, RowsCount, ColsCount, plcHide, aText)
{
    var Delimiter = this.Add_DelimiterEx(ctrPr, 1, [null], begChr, endChr);
    var MathContent = Delimiter.getElementMathContent(0);
    return MathContent.Add_Matrix(ctrPr, RowsCount, ColsCount, plcHide, aText);
};
CMathContent.prototype.Recalculate_CurPos = function(_X, _Y, CurrentRun, _CurRange, _CurLine, _CurPage, UpdateCurPos, UpdateTarget, ReturnTarget)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var _EndPos = ( true === CurrentRun ? Math.min( EndPos, this.CurPos ) : EndPos );

    return this.Content[_EndPos].Recalculate_CurPos(_X, _Y, CurrentRun, _CurRange, _CurLine, _CurPage, UpdateCurPos, UpdateTarget, ReturnTarget);
};
CMathContent.prototype.Get_CurrentParaPos = function()
{
    if ( this.CurPos >= 0 && this.CurPos < this.Content.length )
        return this.Content[this.CurPos].Get_CurrentParaPos();

    return new CParaPos( this.StartRange, this.StartLine, 0, 0 );
};
CMathContent.prototype.Get_ParaContentPos = function(bSelection, bStart, ContentPos, bUseCorrection)
{
    if (true === bUseCorrection && true === bSelection)
	{
		var nPos = false !== bStart ? this.Selection.StartPos : this.Selection.EndPos;

		if (para_Math_Run !== this.Content[nPos].Type
			&& (this.Selection.StartPos !== this.Selection.EndPos || true !== this.Content[nPos].Is_InnerSelection())
			&& ((true === bStart && nPos > 0) || (true !== bStart && nPos < this.Content.length - 1)))
		{
			if (true === bStart && nPos > 0)
			{
				ContentPos.Add(nPos - 1);
				this.Content[nPos - 1].Get_EndPos(false, ContentPos, ContentPos.Get_Depth() + 1);
			}
			else
			{
				ContentPos.Add(nPos + 1);
				this.Content[nPos + 1].Get_StartPos(ContentPos, ContentPos.Get_Depth() + 1);
			}
		}
		else
		{
			ContentPos.Add(nPos);

			if (undefined !== this.Content[nPos])
				this.Content[nPos].Get_ParaContentPos(bSelection, bStart, ContentPos, bUseCorrection);
		}
	}
	else
	{
		var nPos = (true !== bSelection ? this.CurPos : (false !== bStart ? this.Selection.StartPos : this.Selection.EndPos));
		nPos = Math.max(0, Math.min(nPos, this.Content.length - 1));

		ContentPos.Add(nPos);

		if (undefined !== this.Content[nPos])
			this.Content[nPos].Get_ParaContentPos(bSelection, bStart, ContentPos, bUseCorrection);
	}
};
CMathContent.prototype.Set_ParaContentPos = function(ContentPos, Depth)
{
    var CurPos = ContentPos.Get(Depth);

    // Делаем такие проверки, потому что после совместного редактирования, позиция может остаться старой, а
    // контент измениться.
    if (undefined === CurPos || CurPos < 0)
    {
        this.CurPos = 0;
        if (this.Content[this.CurPos])
        	this.Content[this.CurPos].MoveCursorToStartPos();
    }
    else if (CurPos > this.Content.length - 1)
    {
        this.CurPos = this.Content.length - 1;
        if (this.Content[this.CurPos])
        	this.Content[this.CurPos].MoveCursorToEndPos(false);
    }
    else
    {
        this.CurPos = CurPos;
        if (this.Content[this.CurPos])
        	this.Content[this.CurPos].Set_ParaContentPos(ContentPos, Depth + 1);
    }
};
CMathContent.prototype.IsSelectionEmpty = function()
{
    if (true !== this.Selection.Use)
        return true;

    if (this.Selection.StartPos === this.Selection.EndPos)
        return this.Content[this.Selection.StartPos].IsSelectionEmpty();

    return false;
};
CMathContent.prototype.GetSelectContent = function()
{
    if (false === this.Selection.Use)
    {
        if (para_Math_Composition === this.Content[this.CurPos].Type)
            return this.Content[this.CurPos].GetSelectContent();
        else
            return {Content : this, Start : this.CurPos, End : this.CurPos};
    }
    else
    {
        var StartPos = this.Selection.StartPos;
        var EndPos   = this.Selection.EndPos;

        if (StartPos > EndPos)
        {
            StartPos = this.Selection.EndPos;
            EndPos   = this.Selection.StartPos;
        }

        if (StartPos === EndPos && para_Math_Composition === this.Content[StartPos].Type && true === this.Content[StartPos].Is_InnerSelection())
            return this.Content[StartPos].GetSelectContent();

        return {Content : this, Start : StartPos, End : EndPos};
    }
};
CMathContent.prototype.Get_LeftPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
    if (true !== this.ParentElement.Is_ContentUse(this))
        return false;

    if (false === UseContentPos && para_Math_Run === this.Content[this.Content.length - 1].Type)
    {
        // При переходе в новый контент встаем в его конец
        var CurPos = this.Content.length - 1;
        this.Content[CurPos].Get_EndPos(false, SearchPos.Pos, Depth + 1);
        SearchPos.Pos.Update(CurPos, Depth);
        SearchPos.Found = true;

        return true;
    }

    var CurPos = UseContentPos ? ContentPos.Get(Depth) : this.Content.length - 1;

    var bStepStart = false;
    if (CurPos > 0 || !this.Content[0].Cursor_Is_Start())
        bStepStart = true;

    this.Content[CurPos].Get_LeftPos(SearchPos, ContentPos, Depth + 1, UseContentPos);
    SearchPos.Pos.Update(CurPos, Depth);

    if (true === SearchPos.Found)
        return true;

    CurPos--;

    if (true === UseContentPos && para_Math_Composition === this.Content[CurPos + 1].Type)
    {
        // При выходе из формулы встаем в конец рана
        this.Content[CurPos].Get_EndPos(false, SearchPos.Pos, Depth + 1);
        SearchPos.Pos.Update(CurPos, Depth);
        SearchPos.Found = true;
        return true;
    }

    while (CurPos >= 0)
    {
        this.Content[CurPos].Get_LeftPos(SearchPos, ContentPos, Depth + 1, false);
        SearchPos.Pos.Update( CurPos, Depth );

        if (true === SearchPos.Found)
            return true;

        CurPos--;
    }

    if (true === bStepStart)
    {
        // Перед выходом из контента встаем в его начало
        this.Content[0].Get_StartPos(SearchPos.Pos, Depth + 1);
        SearchPos.Pos.Update(0, Depth);
        SearchPos.Found = true;

        return true;
    }

    return false;
};
CMathContent.prototype.Get_RightPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
    if (true !== this.ParentElement.Is_ContentUse(this))
        return false;

    if (false === UseContentPos && para_Math_Run === this.Content[0].Type)
    {
        // При переходе в новый контент встаем в его начало
        this.Content[0].Get_StartPos(SearchPos.Pos, Depth + 1);
        SearchPos.Pos.Update(0, Depth);
        SearchPos.Found = true;

        return true;
    }

    var CurPos = true === UseContentPos ? ContentPos.Get(Depth) : 0;

    var Count = this.Content.length;
    var bStepEnd = false;
    if (CurPos < Count - 1 || !this.Content[Count - 1].Cursor_Is_End())
        bStepEnd = true;

    this.Content[CurPos].Get_RightPos(SearchPos, ContentPos, Depth + 1, UseContentPos, StepEnd);
    SearchPos.Pos.Update( CurPos, Depth );

    if (true === SearchPos.Found)
        return true;

    CurPos++;

    if (true === UseContentPos && para_Math_Composition === this.Content[CurPos - 1].Type)
    {
        // При выходе из формулы встаем в начало рана
        this.Content[CurPos].Get_StartPos(SearchPos.Pos, Depth + 1);
        SearchPos.Pos.Update(CurPos, Depth);
        SearchPos.Found = true;
        return true;
    }

    while (CurPos < Count)
    {
        this.Content[CurPos].Get_RightPos(SearchPos, ContentPos, Depth + 1, false, StepEnd);
        SearchPos.Pos.Update(CurPos, Depth);

        if (true === SearchPos.Found)
            return true;

        CurPos++;
    }

    if (true === bStepEnd)
    {
        // Перед выходом из контента встаем в его конец
        this.Content[Count - 1].Get_EndPos(false, SearchPos.Pos, Depth + 1);
        SearchPos.Pos.Update(Count - 1, Depth);
        SearchPos.Found = true;

        return true;
    }

    return false;
};
CMathContent.prototype.Get_WordStartPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
    if (true !== this.ParentElement.Is_ContentUse(this))
        return false;

    if (false === UseContentPos && para_Math_Run === this.Content[this.Content.length - 1].Type)
    {
        // При переходе в новый контент встаем в его конец
        var CurPos = this.Content.length - 1;
        this.Content[CurPos].Get_EndPos(false, SearchPos.Pos, Depth + 1);
        SearchPos.Pos.Update(CurPos, Depth);
        SearchPos.Found     = true;
        SearchPos.UpdatePos = true;
        return true;
    }

    var CurPos = true === UseContentPos ? ContentPos.Get(Depth) : this.Content.length - 1;

    var bStepStart = false;
    if (CurPos > 0 || !this.Content[0].Cursor_Is_Start())
        bStepStart = true;

    this.Content[CurPos].Get_WordStartPos(SearchPos, ContentPos, Depth + 1, UseContentPos);

    if (true === SearchPos.UpdatePos)
        SearchPos.Pos.Update( CurPos, Depth );

    if (true === SearchPos.Found)
        return;

    CurPos--;

    var bStepStartRun = false;
    if (true === UseContentPos && para_Math_Composition === this.Content[CurPos + 1].Type)
    {
        // При выходе из формулы встаем в конец рана
        this.Content[CurPos].Get_EndPos(false, SearchPos.Pos, Depth + 1);
        SearchPos.Pos.Update(CurPos, Depth);
        SearchPos.Found     = true;
        SearchPos.UpdatePos = true;
        return true;
    }
    else if (para_Math_Run === this.Content[CurPos + 1].Type && true === SearchPos.Shift)
        bStepStartRun = true;

    while (CurPos >= 0)
    {
        if (true !== bStepStartRun || para_Math_Run === this.Content[CurPos].Type)
        {
            var OldUpdatePos = SearchPos.UpdatePos;

            this.Content[CurPos].Get_WordStartPos(SearchPos, ContentPos, Depth + 1, false);

            if (true === SearchPos.UpdatePos)
                SearchPos.Pos.Update(CurPos, Depth);
            else
                SearchPos.UpdatePos = OldUpdatePos;

            if (true === SearchPos.Found)
                return;

            if (true === SearchPos.Shift)
                bStepStartRun = true;
        }
        else
        {
            // Встаем в начало рана перед формулой
            this.Content[CurPos + 1].Get_StartPos(SearchPos.Pos, Depth + 1);
            SearchPos.Pos.Update(CurPos + 1, Depth);
            SearchPos.Found     = true;
            SearchPos.UpdatePos = true;
            return true;
        }
        CurPos--;
    }

    if (true === bStepStart)
    {
        // Перед выходом из контента встаем в его начало
        this.Content[0].Get_StartPos(SearchPos.Pos, Depth + 1);
        SearchPos.Pos.Update(0, Depth);
        SearchPos.Found     = true;
        SearchPos.UpdatePos = true;
        return true;
    }
};
CMathContent.prototype.Get_WordEndPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
    if (true !== this.ParentElement.Is_ContentUse(this))
        return false;

    if (false === UseContentPos && para_Math_Run === this.Content[0].Type)
    {
        // При переходе в новый контент встаем в его начало
        this.Content[0].Get_StartPos(SearchPos.Pos, Depth + 1);
        SearchPos.Pos.Update(0, Depth);
        SearchPos.Found     = true;
        SearchPos.UpdatePos = true;
        return true;
    }

    var CurPos = true === UseContentPos ? ContentPos.Get(Depth) : 0;

    var Count = this.Content.length;
    var bStepEnd = false;
    if (CurPos < Count - 1 || !this.Content[Count - 1].Cursor_Is_End())
        bStepEnd = true;

    this.Content[CurPos].Get_WordEndPos(SearchPos, ContentPos, Depth + 1, UseContentPos, StepEnd);

    if (true === SearchPos.UpdatePos)
        SearchPos.Pos.Update( CurPos, Depth);

    if (true === SearchPos.Found)
        return;

    CurPos++;

    var bStepEndRun = false;
    if (true === UseContentPos && para_Math_Composition === this.Content[CurPos - 1].Type)
    {
        // При выходе из формулы встаем в начало рана
        this.Content[CurPos].Get_StartPos(SearchPos.Pos, Depth + 1);
        SearchPos.Pos.Update(CurPos, Depth);
        SearchPos.Found     = true;
        SearchPos.UpdatePos = true;
        return true;
    }
    else if (para_Math_Run === this.Content[CurPos - 1].Type && true === SearchPos.Shift)
        bStepEndRun = true;

    while (CurPos < Count)
    {
        if (true !== bStepEndRun || para_Math_Run === this.Content[CurPos].Type)
        {
            var OldUpdatePos = SearchPos.UpdatePos;

            this.Content[CurPos].Get_WordEndPos(SearchPos, ContentPos, Depth + 1, false, StepEnd);

            if (true === SearchPos.UpdatePos)
                SearchPos.Pos.Update(CurPos, Depth);
            else
                SearchPos.UpdatePos = OldUpdatePos;

            if (true === SearchPos.Found)
                return;

            if (true === SearchPos.Shift)
                bStepEndRun = true;
        }
        else
        {
            // Встаем в конец рана перед формулой
            this.Content[CurPos - 1].Get_EndPos(false, SearchPos.Pos, Depth + 1);
            SearchPos.Pos.Update(CurPos - 1, Depth);
            SearchPos.Found     = true;
            SearchPos.UpdatePos = true;
            return true;
        }

        CurPos++;
    }

    if (true === bStepEnd)
    {
        // Перед выходом из контента встаем в его конец
        this.Content[Count - 1].Get_EndPos(false, SearchPos.Pos, Depth + 1);
        SearchPos.Pos.Update(Count - 1, Depth);
        SearchPos.Found     = true;
        SearchPos.UpdatePos = true;
        return true;
    }
};
CMathContent.prototype.Get_StartPos = function(ContentPos, Depth)
{
    ContentPos.Update(0, Depth);
    this.Content[0].Get_StartPos(ContentPos, Depth + 1);
};
CMathContent.prototype.Get_EndPos = function(BehindEnd, ContentPos, Depth)
{
    var nLastPos = this.Content.length - 1;

    ContentPos.Update(nLastPos, Depth);
    if(undefined !== this.Content[nLastPos])
        this.Content[nLastPos].Get_EndPos(BehindEnd, ContentPos, Depth + 1);
};
CMathContent.prototype.Draw_HighLights = function(PDSH, bAll)
{
	if (!this.bRoot && this.Parent && true !== this.ParentElement.Is_ContentUse(this))
		return;

    var Bound = this.Get_LineBound(PDSH.Line, PDSH.Range);
    PDSH.X    = Bound.X;

    var CurLine  = PDSH.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PDSH.Range - this.StartRange : PDSH.Range );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var Y0 = PDSH.Y0,
        Y1 = PDSH.Y1;

    var FirstRunInRootNotShd = this.bRoot && this.Content.length > 0 && this.Content[StartPos].IsShade() == false;

    if(FirstRunInRootNotShd || this.bRoot == false)
    {
        Y0 = Bound.Y;
        Y1 = Bound.Y + Bound.H;
    }

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        PDSH.Y0 = Y0;
        PDSH.Y1 = Y1;

        if(bAll && this.Content[CurPos].Type == para_Math_Run)
            this.Content[CurPos].SelectAll();

        this.Content[CurPos].Draw_HighLights(PDSH, bAll);
    }
};
CMathContent.prototype.Draw_Lines = function(PDSL)
{
    var CurLine  = PDSL.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PDSL.Range - this.StartRange : PDSL.Range );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var Bound = this.Get_LineBound(PDSL.Line, PDSL.Range);

    var Baseline = Bound.Y + Bound.Asc;

    PDSL.Baseline = Baseline;
    PDSL.X        = Bound.X;

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        this.Content[CurPos].Draw_Lines(PDSL);
        PDSL.Baseline = Baseline;
    }
};
CMathContent.prototype.RemoveSelection = function()
{
    var StartPos = this.Selection.StartPos;
    var EndPos   = this.Selection.EndPos;

    if (StartPos > EndPos)
    {
        StartPos = this.Selection.EndPos;
        EndPos   = this.Selection.StartPos;
    }

    StartPos = Math.max(0, StartPos);
    EndPos   = Math.min(this.Content.length - 1, EndPos);

    for (var nPos = StartPos; nPos <= EndPos; nPos++)
    {
        this.Content[nPos].RemoveSelection();
    }

    this.Selection.Use   = false;
    this.Selection.StartPos = 0;
    this.Selection.EndPos   = 0;
};
CMathContent.prototype.SelectAll = function(Direction)
{
    this.Selection.Use   = true;
    this.Selection.StartPos = 0;
    this.Selection.EndPos   = this.Content.length - 1;

    for (var nPos = 0, nCount = this.Content.length; nPos < nCount; nPos++)
    {
        this.Content[nPos].SelectAll(Direction);
    }
};
CMathContent.prototype.Selection_DrawRange = function(_CurLine, _CurRange, SelectionDraw)
{
    var SelectionStartPos = this.Selection.StartPos;
    var SelectionEndPos   = this.Selection.EndPos;

    if(SelectionStartPos > SelectionEndPos)
    {
        SelectionStartPos = this.Selection.EndPos;
        SelectionEndPos   = this.Selection.StartPos;
    }

    var SelectionUse = this.Selection.Use;

    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    if(this.bRoot == false)
    {
        var Bound = this.Get_LineBound(_CurLine, _CurRange);
        SelectionDraw.StartY   = Bound.Y;
        SelectionDraw.H        = Bound.H;
    }

    for(var CurPos = StartPos; CurPos <= EndPos; CurPos++)
    {
        var Item = this.Content[CurPos];

        var bSelectAll = SelectionUse && SelectionStartPos <= CurPos && CurPos <= SelectionEndPos && SelectionStartPos !== SelectionEndPos;

        if(Item.Type == para_Math_Composition && bSelectAll)
        {
            SelectionDraw.FindStart = false;
            SelectionDraw.W += Item.Get_Width(_CurLine, _CurRange);
        }
        else
        {
            Item.Selection_DrawRange( _CurLine, _CurRange, SelectionDraw );
        }
    }
};
CMathContent.prototype.Select_ElementByPos = function(nPos, bWhole)
{
    this.Selection.Use   = true;
    this.Selection.StartPos = nPos;
    this.Selection.EndPos   = nPos;

    this.Content[nPos].SelectAll();

    if (bWhole)
        this.Correct_Selection();

    if (!this.bRoot)
        this.ParentElement.Select_MathContent(this);
    else
        this.ParaMath.bSelectionUse = true;
};
CMathContent.prototype.Select_Element = function(Element, bWhole)
{
    var nPos = -1;
    for(var nCurPos = 0, nCount = this.Content.length; nCurPos < nCount; nCurPos++)
    {
        if (this.Content[nCurPos] === Element)
        {
            nPos = nCurPos;
            break;
        }
    }

    if (-1 !== nPos)
    {
        this.Selection.Use   = true;
        this.Selection.StartPos = nPos;
        this.Selection.EndPos   = nPos;

        if (bWhole)
            this.Correct_Selection();

        if (!this.bRoot)
            this.ParentElement.Select_MathContent(this);
        else
            this.ParaMath.bSelectionUse = true;
    }
};
CMathContent.prototype.Correct_Selection = function()
{
    if (true !== this.Selection.Use)
        return;

    // Здесь мы делаем так, чтобы селект всегда начинался и заканчивался в ране.
    // Предполагается, что контент скорректирован верно до выполнения данной функции.

    var nContentLen = this.Content.length;
    var nStartPos = Math.max(0, Math.min(this.Selection.StartPos, nContentLen - 1));
    var nEndPos   = Math.max(0, Math.min(this.Selection.EndPos,   nContentLen - 1));

    if (nStartPos > nEndPos)
    {
        var nTemp = nStartPos;
        nStartPos = nEndPos;
        nEndPos   = nTemp;
    }

    var oStartElement = this.Content[nStartPos];
    if (para_Math_Run !== oStartElement.Type)
    {
        // Предыдущий элемент должен быть раном
        this.Selection.StartPos = nStartPos - 1;
        this.Content[this.Selection.StartPos].Set_SelectionAtEndPos();
    }

    var oEndElement = this.Content[nEndPos];
    if (para_Math_Run !== oEndElement.Type)
    {
        // Следующий элемент должен быть раном
        this.Selection.EndPos = nEndPos + 1;
        this.Content[this.Selection.EndPos].Set_SelectionAtStartPos();
    }
};
CMathContent.prototype.Create_FontMap = function(Map)
{
    // ArgSize компилируется только тогда, когда выставлены все ссылки на родительские классы
    for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; nIndex++)
        this.Content[nIndex].Create_FontMap(Map);
};
CMathContent.prototype.Get_AllFontNames = function(AllFonts)
{
    for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; nIndex++)
        this.Content[nIndex].Get_AllFontNames(AllFonts);
};
CMathContent.prototype.Selection_CheckParaContentPos = function(ContentPos, Depth, bStart, bEnd)
{
    var CurPos = ContentPos.Get(Depth);

    var bStartPos = this.Selection.StartPos,
        bEndPos   = this.Selection.EndPos;

    if(bStartPos > bEndPos)
    {
        var temp = bStartPos;
        bStartPos = bEndPos;
        bEndPos = temp;
    }

    if(bStartPos < CurPos)
        bStart = false;

    if(CurPos < bEndPos)
        bEnd = false;


    if(bStart === false && bEnd === false)
        return true;
    else if((bStartPos <= CurPos || bStart === false) && (CurPos <= bEndPos || bEnd === false))
        return this.Content[CurPos].Selection_CheckParaContentPos(ContentPos, Depth + 1, bStart, bEnd);

    return false;
};
CMathContent.prototype.Check_NearestPos = function(ParaNearPos, Depth)
{
    var HyperNearPos = new CParagraphElementNearPos();
    HyperNearPos.NearPos = ParaNearPos.NearPos;
    HyperNearPos.Depth   = Depth;

    this.NearPosArray.push(HyperNearPos);
    ParaNearPos.Classes.push(this);

    var CurPos = ParaNearPos.NearPos.ContentPos.Get(Depth);
    this.Content[CurPos].Check_NearestPos(ParaNearPos, Depth + 1);
};
CMathContent.prototype.Recalculate_Range = function(PRS, ParaPr, Depth)
{
    this.bOneLine = PRS.bMath_OneLine;

    // для неинлайн формул:
    // у операторов, находяхщихся на этом уровне (в Run) приоритет выше, чем у внутренних операторов (внутри мат объектов)
    // возможен только принудительный разрыв
    var bOnlyForcedBreak = PRS.bOnlyForcedBreak;
    var bNoOneBreakOperator = PRS.bNoOneBreakOperator;

    var CurLine  = PRS.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range );

    var ContentLen = this.Content.length;

    var RangeStartPos = this.protected_AddRange(CurLine, CurRange);
    var RangeEndPos   = ContentLen - 1;

    if(this.RecalcInfo.bEqArray)
        this.InfoPoints.SetDefault();

    var ascent = 0, descent = 0;
    this.size.width = 0;
    var bInline = this.ParaMath.Is_Inline();
    var bOperBefore = this.ParaMath.Is_BrkBinBefore(); // true - оператор находится в начале строки, false - оператор находится в конце строки

    // для внутристроковой формулы : начало формулы - начало нового слова
    if(this.bRoot && bInline && true == this.IsStartRange(PRS.Line, PRS.Range) && PRS.Ranges.length == 0)
    {
        PRS.Update_CurPos(0, Depth);
        PRS.Update_CurPos(0, Depth+1); // нулевой элемент всегда Run

        PRS.Set_LineBreakPos(0);

        if(PRS.Word == true)
        {
            PRS.FirstItemOnLine = false;
            PRS.X += PRS.SpaceLen + PRS.WordLen;

			PRS.Word               = false;
			PRS.EmptyLine          = false;
			PRS.EmptyLineWithBreak = false;
			PRS.SpaceLen           = 0;
			PRS.WordLen            = 0;
			PRS.TextOnLine         = true;

            PRS.XRange = PRS.X;
        }
    }

    var bCurInsideOper   = false;

    for(var Pos = RangeStartPos; Pos < ContentLen; Pos++)
    {
        var Item = this.Content[Pos],
            Type = Item.Type;

        PRS.bEndRunToContent = Pos == ContentLen - 1;

        // для однострочных мат объектов обновляем CurLine и CurRange, Run в этом случае не могут разбиваться на несколько строк
        if (this.bOneLine || (0 === Pos && 0 === CurLine && 0 === CurRange ) || Pos !== RangeStartPos)
            Item.Recalculate_Reset( PRS.Range, PRS.Line, PRS );

        PRS.Update_CurPos( Pos, Depth );

        if(this.bOneLine == true) // контент занимает всегда(!) одну строку
        {
            Item.Recalculate_Range_OneLine(PRS, ParaPr, Depth + 1);

            if(this.RecalcInfo.bEqArray && Type == para_Math_Composition)
                this.InfoPoints.ContentPoints.UpdatePoint(this.Content[Pos].size.width);

            this.size.width += Item.size.width;

            if(ascent < Item.size.ascent)
                ascent = Item.size.ascent;

            if(descent < Item.size.height - Item.size.ascent)
                descent = Item.size.height - Item.size.ascent;

            this.size.ascent = ascent;
            this.size.height = ascent + descent;
        }
        else if(bOnlyForcedBreak == true)
        {
            if(Type == para_Math_Run)
            {
                if(true === Item.Is_StartForcedBreakOperator())
                {
                    Item.Recalculate_Range(PRS, ParaPr, Depth + 1);
                }
                else
                {
                    Item.Recalculate_Range_OneLine(PRS, ParaPr, Depth + 1);
                    PRS.WordLen += Item.size.width;
                }
            }
            else
            {
                Item.Recalculate_Range(PRS, ParaPr, Depth + 1);

                if(Item.kind == MATH_BOX && true == Item.IsForcedBreak())
                {
                    this.private_ForceBreakBox(PRS, Item.size.width);
                }
            }

            if(PRS.NewRange == false && PRS.X + PRS.WordLen + PRS.SpaceLen > PRS.XEnd)
            {
                PRS.NewRange = true;
                PRS.MoveToLBP = true;
            }

        }
        else // контент может занимать несколько строк
        {
            // запомним позицию конца Run перед тем как зайдем во внутр мат объект (конечная позиция Run может измениться при пересчете внутр мат объекта)
            var _Depth      = PRS.PosEndRun.Depth;
            var PrevLastPos = PRS.PosEndRun.Get(_Depth-1),
                LastPos     = PRS.PosEndRun.Get(_Depth);

            var PrevWord = PRS.Word,
                MathFirstItem = PRS.MathFirstItem;

            PRS.bInsideOper = false;

            Item.Recalculate_Range(PRS, ParaPr, Depth + 1);

            if(Type == para_Math_Composition)
            {
                // перед мат объектом идет box break_operator и он не является первым элементом в строке
                if(Item.kind == MATH_BOX)
                {
                    PRS.MathFirstItem = MathFirstItem;
                    if(true == Item.IsForcedBreak())
                    {
                        this.private_ForceBreakBox(PRS, Item, _Depth, PrevLastPos, LastPos); // _Depth, PrevLastPos, LastPos запоминаем до пересчета, поэтому передаем эти параметры в функцию
                        PRS.bBreakBox = true;
                    }
                    else if(true == Item.IsOperatorEmulator())
                    {
                        this.private_BoxOperEmulator(PRS, Item, _Depth, PrevLastPos, LastPos); // _Depth, PrevLastPos, LastPos запоминаем до пересчета, поэтому передаем эти параметры в функцию
                        PRS.bBreakBox = true;
                    }
                    else
                    {
                        PRS.WordLen += Item.size.width;
                        PRS.Word = true;

                        if(PRS.X + PRS.SpaceLen + PRS.WordLen > PRS.XEnd)
                        {
                            if (PRS.FirstItemOnLine == false)
                            {
                                PRS.MoveToLBP = true;
                                PRS.NewRange = true;

                                this.ParaMath.UpdateWidthLine(PRS, PRS.X - PRS.XRange);
                            }
                            else
                            {
                                PRS.bMathWordLarge = true;
                            }
                        }
                    }

                    PRS.MathFirstItem = false;
                }
                else
                {
                    // Слово не убирается в отрезке. Переносим слово в следующий отрезок
                    // FirstItemOnLine == false - слово оказалось не единственным элементом в промежутке, делаем перенос
                    if(PRS.X + PRS.SpaceLen + PRS.WordLen > PRS.XEnd)
                    {
                        if (PRS.FirstItemOnLine == false)
                        {
                            PRS.MoveToLBP = true;
                            PRS.NewRange = true;

                            this.ParaMath.UpdateWidthLine(PRS, PRS.X - PRS.XRange);
                        }
                        else
                        {
                            PRS.bMathWordLarge = true;
                        }
                    }


                    // обновляем BreakPos на конец Run, т.к. внутри мат объекта BreakPos  может измениться на  if(true !== Word)
                    // обновляем только в том случае, если Word = false, иначе можем здесь перебить корректный LineBreakPos
                    if(bCurInsideOper == true && PrevWord == false && bOperBefore == false && bNoOneBreakOperator == false && PRS.bInsideOper == false)
                    {
                        // обновим : начало нового слова - конец предыдущего Run

                        PRS.Update_CurPos(PrevLastPos, _Depth-1);
                        PRS.Set_LineBreakPos(LastPos);

                        if(PRS.NewRange == true) // делаем возврат к предыдущему оператору
                            PRS.MoveToLBP = true;
                    }

                    PRS.Word = true;

                }

                if(PRS.NewRange == false && 0 === CurRange && 0 === CurLine)
                {
                    var PrevRecalcInfo = PRS.RunRecalcInfoLast,
                        NumberingAdd;

                    if(null === PrevRecalcInfo)
                        NumberingAdd = true;
                    else
                        NumberingAdd = PrevRecalcInfo.NumberingAdd;

                    if(NumberingAdd)
                    {
                        PRS.X = PRS.Recalculate_Numbering(Item, this, ParaPr, PRS.X);
                        PRS.RunRecalcInfoLast.NumberingAdd = false;
                        PRS.RunRecalcInfoLast.NumberingUse = true;
                        PRS.RunRecalcInfoLast.NumberingItem = PRS.Paragraph.Numbering;
                    }
                }
            }
            else
            {
                if(PRS.MathFirstItem == true && false == Item.Is_EmptyRange(PRS.Line, PRS.Range))
                {
                    PRS.MathFirstItem = false;
                }

                var CheckWrapIndent = PRS.bFirstLine == true ? PRS.X - PRS.XRange > PRS.WrapIndent : true;

                if(PRS.bInsideOper == true && CheckWrapIndent == true)
                {
                    PRS.bOnlyForcedBreak = true;
                }
            }

            bCurInsideOper = bCurInsideOper || PRS.bInsideOper;
        }

        if ( true === PRS.NewRange )
        {
            RangeEndPos = Pos;
            break;
        }
    }

    PRS.bInsideOper = PRS.bInsideOper || bCurInsideOper;
    PRS.bOnlyForcedBreak = bOnlyForcedBreak;

    if ( Pos >= ContentLen )
    {
        RangeEndPos = Pos - 1;
    }

    var bSingleBarFraction = false;

    for(var Pos = 0; Pos < ContentLen; Pos++)
    {

        if(this.Content[Pos].kind == MATH_FRACTION && this.Content[Pos].Pr.type == BAR_FRACTION)
        {
            if(bSingleBarFraction)
            {
                bSingleBarFraction = false;
                break;
            }

            bSingleBarFraction = true;
        }
        else if( !(this.Content[Pos].Type == para_Math_Run && true == this.Content[Pos].Is_Empty()) ) // не пустой Run, другой мат объект
        {
            bSingleBarFraction = false;
            break;
        }
    }

    PRS.bSingleBarFraction = bSingleBarFraction;

    this.protected_FillRange(CurLine, CurRange, RangeStartPos, RangeEndPos);
};
CMathContent.prototype.private_ForceBreakBox = function(PRS, Box, _Depth, PrevLastPos, LastPos)
{
    var BoxLen = Box.size.width;

    if(true == PRS.MathFirstItem)
    {
        PRS.WordLen += BoxLen;
    }
    else
    {
        if(true === this.ParaMath.Is_BrkBinBefore())
        {
            PRS.X += PRS.SpaceLen + PRS.WordLen;
            PRS.Update_CurPos(PrevLastPos, _Depth-1);
            PRS.Set_LineBreakPos(LastPos);

            this.ParaMath.UpdateWidthLine(PRS, PRS.X - PRS.XRange);

            PRS.MoveToLBP = true;
            PRS.NewRange = true;
        }
        else
        {
            PRS.Word         = false;
            PRS.bForcedBreak = true;
            PRS.WordLen     += BoxLen;
        }
    }
};
CMathContent.prototype.private_BoxOperEmulator = function(PRS, Box, _Depth, PrevLastPos, LastPos)
{
    var BoxLen      = Box.size.width,
        BoxGapRight = Box.GapRight;

    var CheckWrapIndent = PRS.bFirstLine == true ? PRS.X - PRS.XRange > PRS.WrapIndent : true;
    var bOperBefore = this.ParaMath.Is_BrkBinBefore() == true;

    var bOnlyForcedBreakBefore = bOperBefore == true && PRS.MathFirstItem == false,
        bOnlyforcedBreakAfter  = bOperBefore == false;

    if(CheckWrapIndent == true && (bOnlyForcedBreakBefore || bOnlyforcedBreakAfter))
    {
        PRS.bOnlyForcedBreak = true;
    }

    var bOverXEnd;

    if(bOperBefore) // оператор находится в начале строки
    {
        bOverXEnd = PRS.X + PRS.WordLen + PRS.SpaceLen > PRS.XEnd;

        if(true == PRS.MathFirstItem)
        {
            PRS.WordLen += PRS.SpaceLen + PRS.WordLen + BoxLen;
        }
        else if(PRS.FirstItemOnLine == false && bOverXEnd)
        {
            PRS.MoveToLBP = true;
            PRS.NewRange = true;

            this.ParaMath.UpdateWidthLine(PRS, PRS.X - PRS.XRange);
        }
        else
        {
            PRS.X += PRS.SpaceLen + PRS.WordLen;
            // обновим : начало нового слова - конец предыдущего Run
            PRS.bInsideOper = true;
            PRS.FirstItemOnLine = false;

            PRS.Update_CurPos(PrevLastPos, _Depth-1);
            PRS.Set_LineBreakPos(LastPos);

            PRS.SpaceLen = BoxLen;

            PRS.WordLen = 0;
            PRS.Word = true;
        }
    }
    else
    {
        bOverXEnd = PRS.X + PRS.SpaceLen + PRS.WordLen + BoxLen - BoxGapRight > PRS.XEnd;

        PRS.OperGapRight = BoxGapRight;

        // Слово не убирается в отрезке. Переносим слово в следующий отрезок
        // FirstItemOnLine == false - слово оказалось не единственным элементом в промежутке, делаем перенос
        if(PRS.FirstItemOnLine == false && bOverXEnd)
        {
            PRS.MoveToLBP = true;
            PRS.NewRange = true;

            this.ParaMath.UpdateWidthLine(PRS, PRS.X - PRS.XRange);
        }
        else
        {
            PRS.bInsideOper = true;
        }

        PRS.X += PRS.SpaceLen + PRS.WordLen + BoxLen;
        PRS.SpaceLen = 0;
        PRS.WordLen = 0;

        PRS.Word = false;
        PRS.FirstItemOnLine = false;
    }
};
CMathContent.prototype.Math_Set_EmptyRange = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var RangeStartPos = this.protected_AddRange(CurLine, CurRange);
    var RangeEndPos   = RangeStartPos;

    this.protected_FillRange(CurLine, CurRange, RangeStartPos, RangeEndPos);

    this.Content[RangeStartPos].Math_Set_EmptyRange(_CurLine, _CurRange);
};
CMathContent.prototype.Recalculate_Reset = function(StartRange, StartLine, PRS)
{
    var bNotUpdate = PRS !== null && PRS!== undefined && PRS.bFastRecalculate == true;
    if(bNotUpdate == false)
    {
        this.StartLine   = StartLine;
        this.StartRange  = StartRange;

        if(this.Content.length > 0)
            this.Content[0].Recalculate_Reset(StartRange, StartLine, PRS);

        this.protected_ClearLines();
    }
};
CMathContent.prototype.IsEmptyRange = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var bEmpty = true;

    if(StartPos == EndPos)
    {
        bEmpty = this.Content[StartPos].IsEmptyRange(_CurLine, _CurRange);
    }
    else
    {
        var Pos = StartPos;

        while(Pos <= EndPos)
        {
            if(false == this.Content[Pos].IsEmptyRange(_CurLine, _CurRange))
            {
                bEmpty = false;
                break;
            }
            Pos++;
        }
    }

    return bEmpty;
};
CMathContent.prototype.Displace_BreakOperator = function(isForward, bBrkBefore, CountOperators)
{
	var Pos = this.CurPos;

	if (this.Content[Pos].Type == para_Math_Run)
	{
		var bApplyBreak = this.Content[Pos].Displace_BreakOperator(isForward, bBrkBefore, CountOperators);
		var NewPos      = bBrkBefore ? Pos + 1 : Pos - 1;

		if (this.Content[NewPos] && bApplyBreak == false && (this.Content[NewPos].Type == para_Math_Run || this.Content[NewPos].kind == MATH_BOX))
		{
			this.Content[NewPos].Displace_BreakOperator(isForward, bBrkBefore, CountOperators);
		}
	}
	else
	{
		this.Content[Pos].Displace_BreakOperator(isForward, bBrkBefore, CountOperators);
	}
};
CMathContent.prototype.Recalculate_Range_Width = function(PRSC, _CurLine, _CurRange)
{
    var RangeW = PRSC.Range.W;
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
    {
        this.Content[CurPos].Recalculate_Range_Width( PRSC, _CurLine, _CurRange );
    }

    this.Bounds.SetWidth(CurLine, CurRange, PRSC.Range.W - RangeW);
};
CMathContent.prototype.RecalculateMinMaxContentWidth = function(MinMax)
{
    if(this.RecalcInfo.bEqArray)
        this.InfoPoints.SetDefault();

    var ascent = 0, descent = 0;
    this.size.width = 0;

    var Lng = this.Content.length;

    for(var Pos = 0; Pos < Lng; Pos++)
    {
        var Item = this.Content[Pos],
            Type = Item.Type;

        if(MinMax.bMath_OneLine)
        {
            if(Type == para_Math_Run)
                Item.Math_RecalculateContent();
            else
                Item.RecalculateMinMaxContentWidth(MinMax);

            if(this.RecalcInfo.bEqArray && Type == para_Math_Composition)
                this.InfoPoints.ContentPoints.UpdatePoint(this.Content[Pos].size.width);

            this.size.width += Item.size.width;

            if(ascent < Item.size.ascent)
                ascent = Item.size.ascent;

            if(descent < Item.size.height - Item.size.ascent)
                descent = Item.size.height - Item.size.ascent;

            this.size.ascent = ascent;
            this.size.height = ascent + descent;
        }
        else
        {
            Item.RecalculateMinMaxContentWidth(MinMax);
        }
    }

};
CMathContent.prototype.Recalculate_LineMetrics = function(PRS, ParaPr, _CurLine, _CurRange, ContentMetrics)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = (0 === CurLine ? _CurRange - this.StartRange : _CurRange);

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    if(PRS.bFastRecalculate === false)
    {
        this.Bounds.Reset(CurLine, CurRange);
    }

    var NewContentMetrics = new CMathBoundsMeasures();

    for(var Pos = StartPos; Pos <= EndPos; Pos++)
    {
        var Item = this.Content[Pos];
        Item.Recalculate_LineMetrics(PRS, ParaPr, _CurLine, _CurRange, NewContentMetrics);
    }

    this.Bounds.UpdateMetrics(CurLine, CurRange, NewContentMetrics);

    ContentMetrics.UpdateMetrics(NewContentMetrics);
};
CMathContent.prototype.Math_UpdateLineMetrics = function(PRS, ParaPr)
{
    this.Content[0].Math_UpdateLineMetrics(PRS, ParaPr); // this.Content[0] - Run
};
CMathContent.prototype.UpdateOperators = function(_CurLine, _CurRange, bEmptyGapLeft, bEmptyGapRight)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for(var Pos = StartPos; Pos <= EndPos; Pos++)
    {
        var _bEmptyGapLeft  = bEmptyGapLeft  && Pos == StartPos,
            _bEmptyGapRight = bEmptyGapRight && Pos == EndPos;

        this.Content[Pos].UpdateOperators(_CurLine, _CurRange, _bEmptyGapLeft, _bEmptyGapRight);
    }
};
CMathContent.prototype.Get_Bounds = function()
{
    return this.Bounds.Get_Bounds();
};
CMathContent.prototype.Get_LineBound = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine,
        CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    return this.Bounds.Get_LineBound(CurLine, CurRange);
};
CMathContent.prototype.GetPos = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine,
        CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    return this.Bounds.GetPos(CurLine, CurRange);
};
CMathContent.prototype.Get_Width = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine,
        CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    return this.Bounds.Get_Width(CurLine, CurRange);
};
CMathContent.prototype.GetAscent = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine,
        CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    return this.Bounds.GetAscent(CurLine, CurRange);
};
CMathContent.prototype.GetDescent = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine,
        CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    return this.Bounds.GetDescent(CurLine, CurRange);
};
CMathContent.prototype.Get_StartRangePos = function(_CurLine, _CurRange, SearchPos, Depth, bStartPos)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var CurPos = this.CurPos;
    var Result;

    var bStart = this.bRoot ? CurRange == 0 : bStartPos;

    if(this.Content[CurPos].Type == para_Math_Composition && bStartPos !== true)
    {
        bStart = bStart && CurPos == StartPos;
        Result = this.Content[CurPos].Get_StartRangePos(_CurLine, _CurRange, SearchPos, Depth + 1, bStart); // пытаемся встать в начало внутреннего контента

        if ( true === Result )
        {
            SearchPos.Pos.Update( CurPos, Depth );
        }
        else if(this.bRoot && CurPos !== StartPos)
        {
            if(this.Content[StartPos].Type == para_Math_Composition)
                Result = this.Content[StartPos].Get_StartRangePos(_CurLine, _CurRange, SearchPos, Depth + 1, true);
            else
                Result = this.Content[StartPos].Math_Get_StartRangePos(_CurLine, _CurRange, SearchPos, Depth + 1, true);

            if ( true === Result )
                SearchPos.Pos.Update(StartPos, Depth);
        }
    }
    else
    {
        if(this.bRoot && CurLine == 0)
        {
            bStart = bStart && StartPos < CurPos;
        }

        if(this.Content[StartPos].Type == para_Math_Composition)
            Result = this.Content[StartPos].Get_StartRangePos(_CurLine, _CurRange, SearchPos, Depth + 1, bStart); // может произойти, если мат объект разбивается на строки
        else
            Result = this.Content[StartPos].Math_Get_StartRangePos(_CurLine, _CurRange, SearchPos, Depth + 1, bStart);

        if ( true === Result )
            SearchPos.Pos.Update(StartPos, Depth );
    }

    return Result;
};
CMathContent.prototype.Get_EndRangePos = function(_CurLine, _CurRange, SearchPos, Depth, bEndPos)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange);
    var CurPos = this.CurPos;
    var Result;

    var bLastRange = CurRange == this.protected_GetRangesCount(CurLine) - 1;

    var bEnd = this.bRoot ? bLastRange : bEndPos;

    if(this.Content[CurPos].Type == para_Math_Composition && bEndPos !== true)
    {
        Result = this.Content[CurPos].Get_EndRangePos(_CurLine, _CurRange, SearchPos, Depth + 1); // пытаемся встать в конец внутреннего контента

        if ( true === Result )
        {
            SearchPos.Pos.Update( CurPos, Depth );
        }
        else if(this.bRoot && CurPos !== EndPos)
        {
            if(this.Content[EndPos].Type == para_Math_Composition)
                Result = this.Content[EndPos].Get_EndRangePos(_CurLine, _CurRange, SearchPos, Depth + 1, true);
            else
                Result = this.Content[EndPos].Math_Get_EndRangePos(_CurLine, _CurRange, SearchPos, Depth + 1, true);

            if ( true === Result )
                SearchPos.Pos.Update(EndPos, Depth );
        }
    }
    else
    {
        bEnd = this.bRoot && bLastRange ? true /*иначе после того как встанем после формулы перед знаком параграфа, на следующем End встанем перед формулой*/ : bEnd || CurPos < EndPos;

        if(this.Content[EndPos].Type == para_Math_Composition)
            Result = this.Content[EndPos].Get_EndRangePos(_CurLine, _CurRange, SearchPos, Depth + 1, bEnd); // может произойти, если мат объект разбивается на строки
        else
            Result = this.Content[EndPos].Math_Get_EndRangePos(_CurLine, _CurRange, SearchPos, Depth + 1, bEnd);

        if ( true === Result )
            SearchPos.Pos.Update(EndPos, Depth );

    }

    return Result;
};
CMathContent.prototype.Math_Is_End = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange);

    var Len = this.Content.length;

    var result = false;

    if(EndPos == Len - 1)
    {
        result = this.Content[Len - 1].Math_Is_End(_CurLine, _CurRange);
    }

    return result;
};
CMathContent.prototype.Get_AlignBrk = function(_CurLine, bBrkBefore)
{
    var AlnAt = null;

    var CurLine  = _CurLine - this.StartLine;
    var RangesCount = this.protected_GetRangesCount(CurLine - 1);
    var EndPos = this.protected_GetRangeEndPos(CurLine - 1, RangesCount - 1);

    if(CurLine !== 0) // получаем смещение до расчета Recalculate_Range
    {
        var bEndRun  = this.Content[EndPos].Type == para_Math_Run && true == this.Content[EndPos].Math_Is_End(_CurLine - 1, RangesCount - 1),
            bNextBox = EndPos < this.Content.length - 1 && this.Content[EndPos + 1].kind == MATH_BOX;

        var bCheckNextBox = bEndRun == true && bNextBox == true && bBrkBefore == true;

        var bRunEmptyRange = this.Content[EndPos].Type == para_Math_Run && this.Content[EndPos].Is_EmptyRange(_CurLine - 1, RangesCount - 1),
            bPrevBox = EndPos > 0 && this.Content[EndPos - 1].kind == MATH_BOX;

        var bCheckPrevNextBox = bRunEmptyRange == true && bPrevBox == true && bBrkBefore == false;

        if(bCheckPrevNextBox)
        {
            AlnAt = this.Content[EndPos - 1].Get_AlignBrk(_CurLine, bBrkBefore);
        }
        else if(bCheckNextBox)
        {
            AlnAt = this.Content[EndPos + 1].Get_AlignBrk(_CurLine, bBrkBefore);
        }
        else
        {
            AlnAt = this.Content[EndPos].Get_AlignBrk(_CurLine, bBrkBefore);
        }
    }

    return AlnAt;
};
CMathContent.prototype.IsStartRange = function(Line, Range)
{
    return Line - this.StartLine == 0 && Range - this.StartRange == 0;
};
CMathContent.prototype.IsStartLine = function(Line)
{
    return Line == this.StartLine;
};
CMathContent.prototype.Get_SelectionDirection = function()
{
    if (true !== this.Selection.Use)
        return 0;

    if (this.Selection.StartPos < this.Selection.EndPos)
        return 1;
    else if (this.Selection.StartPos > this.Selection.EndPos)
        return -1;

    return this.Content[this.Selection.StartPos].Get_SelectionDirection();
};
CMathContent.prototype.MoveCursorToStartPos = function()
{
    this.CurPos = 0;
    this.Content[0].MoveCursorToStartPos();
};
CMathContent.prototype.MoveCursorToEndPos = function(SelectFromEnd)
{
    this.CurPos = this.Content.length - 1;
    this.Content[this.CurPos].MoveCursorToEndPos(SelectFromEnd);
};
CMathContent.prototype.Check_Composition = function()
{
    var Pos = this.private_FindCurrentPosInContent();

    return Pos !== null && this.Content[Pos].Type == para_Math_Composition;
};
CMathContent.prototype.Can_ModifyForcedBreak = function(Pr)
{
    var Pos = this.private_GetPosRunForForcedBreak();

    if(Pos !== null && this.bOneLine == false)
    {
        var bBreakOperator      = this.Content[Pos].Check_ForcedBreak();
        var CurrentRun          = this.Content[Pos];
        var bCanCheckNearsRun   = bBreakOperator == false && false == CurrentRun.IsSelectionUse();
        var bPrevItem           = bCanCheckNearsRun && Pos > 0 && true == CurrentRun.Cursor_Is_Start(),
            bNextItem           = bCanCheckNearsRun && Pos < this.Content.length - 1 && true == CurrentRun.Cursor_Is_End();

        var bPrevRun = bPrevItem &&  this.Content[Pos - 1].Type == para_Math_Run,
            bNextRun = bNextItem &&  this.Content[Pos + 1].Type == para_Math_Run;

        if(bBreakOperator)
        {
            this.Content[Pos].Math_Can_ModidyForcedBreak(Pr);
        }
        else if(bPrevRun)
        {
            this.Content[Pos - 1].Math_Can_ModidyForcedBreak(Pr, true, false);
        }
        else if(bNextRun)
        {
            this.Content[Pos + 1].Math_Can_ModidyForcedBreak(Pr, false, true);
        }
    }
};
CMathContent.prototype.private_GetPosRunForForcedBreak = function()
{
    var Pos = null;

    if(true === this.Selection.Use)
    {
        var StartPos = this.Selection.StartPos,
            EndPos   = this.Selection.EndPos;

        if ( StartPos > EndPos )
        {
            StartPos = this.Selection.EndPos;
            EndPos   = this.Selection.StartPos;
        }


        var bHaveSelectedItem = false;
        for(var CurPos = StartPos; CurPos <= EndPos; CurPos++)
        {
            var Item = this.Content[CurPos];
            var bSelect     = true !== Item.IsSelectionEmpty(),
                bSelectRun  = bSelect == true && Item.Type == para_Math_Run,
                bSelectComp = bSelect == true && Item.Type == para_Math_Composition;
            var bSelectManyRuns = bSelectRun && bHaveSelectedItem;

            if(bSelectComp || bSelectManyRuns)
            {
                Pos = null;
                break;
            }

            if(bSelectRun)
            {
                bHaveSelectedItem = true;
                Pos = CurPos;
            }
        }
    }
    else
    {
        Pos = this.CurPos;
    }

    return Pos;
};
CMathContent.prototype.private_FindCurrentPosInContent = function()
{
    var Pos = null;

    if(true === this.Selection.Use)
    {
        var StartPos = this.Selection.StartPos,
            EndPos   = this.Selection.EndPos;

        if ( StartPos > EndPos )
        {
            StartPos = this.Selection.EndPos;
            EndPos   = this.Selection.StartPos;
        }

        var bComposition = false;

        for(var CurPos = StartPos; CurPos <= EndPos; CurPos++)
        {
            var Item = this.Content[CurPos];

            if(Item.Type == para_Math_Run && true !== Item.IsSelectionEmpty())
            {
                Pos = bComposition == true ? null : CurPos;
                break;
            }
            else if(Item.Type ==  para_Math_Composition)
            {
                if(bComposition == true)
                {
                    Pos = null;
                    break;
                }
                else
                {
                    Pos = CurPos;
                    bComposition = true;
                }
            }
        }
    }
    else
    {
        Pos = this.CurPos;
    }

    return Pos;
};
CMathContent.prototype.Is_CurrentContent = function()
{
    var Pos = this.private_FindCurrentPosInContent();

    return Pos == null || this.Content[Pos].Type == para_Math_Run;
};
CMathContent.prototype.Set_MenuProps = function(Props)
{
    var Pos = this.private_FindCurrentPosInContent();

    if(true == this.Is_CurrentContent())
    {
        this.Apply_MenuProps(Props, Pos);
    }
    else if(false == this.private_IsMenuPropsForContent(Props.Action) &&  true == this.Content[Pos].Can_ApplyMenuPropsToObject())
    {
        // не нужно проходиться по вложенным элементам
        // 1. уже применили изменения, продожать нет необходимости
        // 2. потому что могут совпать типы текущего элемента и вложенного и тогда изменения применятся к обоим элементам
        if(false === this.Delete_ItemToContentThroughInterface(Props, Pos)) // try to delete
        {
            this.Content[Pos].Apply_MenuProps(Props);
        }
    }
    else
    {
        this.Content[Pos].Set_MenuProps(Props);
    }
};
CMathContent.prototype.Apply_MenuProps = function(Props, Pos)
{
	var ArgSize, NewArgSize;

	if (Props.Action & c_oMathMenuAction.IncreaseArgumentSize)
	{
		if (true === this.Parent.Can_ModifyArgSize() && true == this.Compiled_ArgSz.Can_Increase() && true == this.ArgSize.Can_SimpleIncrease())
		{
			ArgSize    = this.ArgSize.GetValue();
			NewArgSize = this.ArgSize.Increase();

			History.Add(new CChangesMathContentArgSize(this, ArgSize, NewArgSize));
			this.Recalc_RunsCompiledPr();
		}
	}
	else if (Props.Action & c_oMathMenuAction.DecreaseArgumentSize)
	{
		if (true === this.Parent.Can_ModifyArgSize() && true == this.Compiled_ArgSz.Can_Decrease() && true == this.ArgSize.Can_Decrease())
		{
			ArgSize    = this.ArgSize.GetValue();
			NewArgSize = this.ArgSize.Decrease();

			History.Add(new CChangesMathContentArgSize(this, ArgSize, NewArgSize));
			this.Recalc_RunsCompiledPr();
		}
	}

	var Run;

	if (Pos !== null && Props.Action & c_oMathMenuAction.InsertForcedBreak)
	{
		Run = this.private_Get_RunForForcedBreak(Pos);
		Run.Set_MathForcedBreak(true);

	}
	else if (Pos !== null && Props.Action & c_oMathMenuAction.DeleteForcedBreak)
	{
		Run = this.private_Get_RunForForcedBreak(Pos);
		Run.Set_MathForcedBreak(false);
	}
};
CMathContent.prototype.private_Get_RunForForcedBreak = function(Pos)
{
    var CurrentRun          = this.Content[Pos];
    var bCurrentForcedBreak = this.Content[Pos].Type == para_Math_Run && true == CurrentRun.Check_ForcedBreak(),
        bPrevForcedBreak    = Pos > 0 && true == CurrentRun.Cursor_Is_Start(),
        bNextForcedBreak    = Pos < this.Content.length && true == CurrentRun.Cursor_Is_End();

    var Run = null;

    if(bCurrentForcedBreak)
    {
        Run = this.Content[Pos];

        var NewRun = Run.Math_SplitRunForcedBreak();

        if(NewRun !== null)
        {
            this.Internal_Content_Add(Pos+1, NewRun, true);
            Run = NewRun;
        }
    }
    else if(bPrevForcedBreak)
    {
        Run = this.Content[Pos - 1];
    }
    else if(bNextForcedBreak)
    {
        Run = this.Content[Pos + 1];
    }

    return Run;
};
CMathContent.prototype.Delete_ItemToContentThroughInterface = function(Props, Pos)
{
    var bDelete = false;
    var Item = this.Content[Pos];

    if(Item.kind == MATH_DEGREESubSup && Item.Pr.type == DEGREE_SubSup && Props.Type == Asc.c_oAscMathInterfaceType.Script)
    {
        if(Props.ScriptType == Asc.c_oAscMathInterfaceScript.Sup)
        {
            this.private_AddModifiedDegree(Pos, DEGREE_SUPERSCRIPT);
            bDelete = true;
        }
        else if(Props.ScriptType == Asc.c_oAscMathInterfaceScript.Sub)
        {
            this.private_AddModifiedDegree(Pos, DEGREE_SUBSCRIPT);
            bDelete = true;
        }
    }

    var RemoveChar      = Props.Action & c_oMathMenuAction.RemoveAccentCharacter && Item.kind == MATH_ACCENT,
        RemoveBar       = Props.Action & c_oMathMenuAction.RemoveBar && Item.kind == MATH_BAR,
        RemoveScript    = Props.Type == Asc.c_oAscMathInterfaceType.Script && Props.ScriptType == Asc.c_oAscMathInterfaceScript.None && (Item.kind == MATH_DEGREESubSup || Item.kind == MATH_DEGREE),
        RemoveLimit     = Props.Type == Asc.c_oAscMathInterfaceType.Limit && Props.Pos == Asc.c_oAscMathInterfaceLimitPos.None && Item.kind === MATH_LIMIT,
        RemoveMatrix    = Props.Type == Asc.c_oAscMathInterfaceType.Matrix && this.Content[Pos].Is_DeletedItem(Props.Action),
        RemoveEqArray   = Props.Type == Asc.c_oAscMathInterfaceType.EqArray && this.Content[Pos].Is_DeletedItem(Props.Action),
        RemoveDelimiter = Props.Action & c_oMathMenuAction.RemoveDelimiter && Item.kind == MATH_DELIMITER,
        RemoveGroupChar = Props.Type == Asc.c_oAscMathInterfaceType.GroupChar && Props.Pos == Asc.c_oAscMathInterfaceGroupCharPos.None && Item.kind == MATH_GROUP_CHARACTER,
        RemoveRadical   = Props.Action & c_oMathMenuAction.RemoveRadical && Item.kind == MATH_RADICAL;


    if(RemoveChar || RemoveBar || RemoveScript || RemoveLimit || RemoveMatrix || RemoveEqArray || RemoveDelimiter || RemoveGroupChar || RemoveRadical)
    {
        var Items = this.Content[Pos].Get_DeletedItemsThroughInterface();

        if(Items == null) // такого не должно произойти
            return;

        this.Remove_FromContent(Pos, 1);

        this.ConcatToContent(Pos, Items);

        this.Correct_Content();

        bDelete = true;
    }

    return bDelete;
};
CMathContent.prototype.private_AddModifiedDegree = function(Pos, Type)
{
    var DegreeSubSup = this.Content[Pos];
    var Base     = DegreeSubSup.getBase();
    var Iterator = Type == DEGREE_SUBSCRIPT ? DegreeSubSup.getLowerIterator() : DegreeSubSup.getUpperIterator();

    var Degree = new CDegree({type: Type}, false);

    this.Remove_FromContent(Pos, 1);
    this.Add_ToContent(Pos, Degree);

    var oBase     = Degree.getBase(),
        oIterator = Degree.getIterator();

    oBase.Concat_ToEnd(Base.Content);
    oIterator.Concat_ToEnd(Iterator.Content);
};
CMathContent.prototype.Get_MenuProps = function()
{
    var Pr = new CMathMenuBase();

    var Pos = this.private_FindCurrentPosInContent();

    if(Pos !== null && this.Content[Pos].Type == para_Math_Composition)
    {
        Pr = this.Content[Pos].Get_MenuProps();
    }
    else
    {
        this.Can_ModifyForcedBreak(Pr);
    }

    return Pr;
};
CMathContent.prototype.private_IsMenuPropsForContent = function(Action)
{
    // данные изменения могут прийти для любого типа изменений
    var bInsertForcedBreak = Action & c_oMathMenuAction.InsertForcedBreak,
        bDeleteForcedBreak = Action & c_oMathMenuAction.DeleteForcedBreak,
        bIncreaseArgSize   = Action & c_oMathMenuAction.IncreaseArgumentSize,
        bDecreaseArgSize   = Action & c_oMathMenuAction.DecreaseArgumentSize;

    return bDecreaseArgSize || bIncreaseArgSize || bInsertForcedBreak || bDeleteForcedBreak;
};
CMathContent.prototype.Process_AutoCorrect = function(ActionElement)
{
    // TODO: Надо проверить как работает весь код с автозаменой, перед тем как влючать его.
    return;

    var bNeedAutoCorrect = this.private_NeedAutoCorrect(ActionElement);

    var AutoCorrectEngine = new CMathAutoCorrectEngine(ActionElement);

    var nCount = this.Content.length;
    for (var nPos = 0; nPos < nCount; nPos++)
    {
        var Element = this.Content[nPos];

        if (para_Math_Run === Element.Type)
            Element.Get_TextForAutoCorrect(AutoCorrectEngine, nPos);
        else
            AutoCorrectEngine.Add_Element(Element, nPos);

        if (false === AutoCorrectEngine.CollectText)
            break;
    }

    if (null == AutoCorrectEngine.TextPr)
        AutoCorrectEngine.TextPr = new CTextPr();
    if (null == AutoCorrectEngine.MathPr)
        AutoCorrectEngine.MathPr = new CMPrp();

    // Создаем новую точку здесь, потому что если автозамену можно будет сделать классы сразу будут создаваться
    History.Create_NewPoint(AscDFH.historydescription_Document_MathAutoCorrect);

    var bCursorStepRight = false;

    var bAutoCorrectFunction       = false;
    var CanMakeAutoCorrectEquation = false;
    var CanMakeAutoCorrectFunc     = false;
    var CanMakeAutoCorrect         = false;

    var oAutoCorrectControl = new AutoCorrectionControl(AutoCorrectEngine, this.ParaMath);
    if (false === bNeedAutoCorrect && ActionElement.Type === para_Math_Text)
    {
        var bFindFunction = oAutoCorrectControl.FindFunction(false);
        if (false === bFindFunction)
            return false;
        if (oAutoCorrectControl.Type === MATH_DELIMITER && oAutoCorrectControl.BrAccount.LBracket === 0x28 && oAutoCorrectControl.BrAccount.RBracket === 0x29)
            oAutoCorrectControl.AutoCorrectDelimiter(AutoCorrectEngine, false);
        else if (oAutoCorrectControl.Type === MATH_MATRIX)
            oAutoCorrectControl.AutoCorrectMatrix(AutoCorrectEngine, false);
        else if (oAutoCorrectControl.Type === MATH_EQ_ARRAY)
            oAutoCorrectControl.AutoCorrectEqArray(AutoCorrectEngine, false);
        else if (oAutoCorrectControl.bDelimiter && (oAutoCorrectControl.Type === MATH_RADICAL || oAutoCorrectControl.Type === MATH_PHANTOM))
            oAutoCorrectControl.AutoCorrectDelimiter(AutoCorrectEngine, false);

    }
    else
    {
        // Смотрим возможно ли выполнить автозамену, если нет, тогда пробуем произвести автозамену пропуская последний символ
        CanMakeAutoCorrect = this.private_CanAutoCorrectText(AutoCorrectEngine, false);

        if (false === CanMakeAutoCorrect)
        {
            // Пробуем произвести автозамену без последнего добавленного символа
            if (0x20 === ActionElement.value)
                CanMakeAutoCorrect = this.private_CanAutoCorrectText(AutoCorrectEngine, true);
            else
            {
                AutoCorrectEngine.Elements.splice(AutoCorrectEngine.Elements.length - 1, 1);
                CanMakeAutoCorrect = this.private_CanAutoCorrectText(AutoCorrectEngine, false);
                bCursorStepRight   = true;
            }
        }

        oAutoCorrectControl.SetReplaceChar(AutoCorrectEngine);

        // Пробуем произвести автозамену без последнего добавленного символа
        if (0x20 === ActionElement.value)
            CanMakeAutoCorrectFunc = this.private_CanAutoCorrectTextFunc(AutoCorrectEngine, true);
        else
            CanMakeAutoCorrectFunc = this.private_CanAutoCorrectTextFunc(AutoCorrectEngine, false);

        // Пробуем сделать формульную автозамену
        if (false === CanMakeAutoCorrectFunc)
        {
            if (CanMakeAutoCorrect || ( 0x28 != ActionElement.value && 0x5C != ActionElement.value))
                CanMakeAutoCorrectEquation = oAutoCorrectControl.private_CanAutoCorrectEquation(AutoCorrectEngine, CanMakeAutoCorrect, bCursorStepRight);
        }
    }

    if (true === bFindFunction || true === CanMakeAutoCorrect || true === CanMakeAutoCorrectEquation || CanMakeAutoCorrectFunc)
    {
        var ElementsCount = AutoCorrectEngine.Elements.length;
        var LastElement   = null;

        var FirstElement    = AutoCorrectEngine.Elements[ElementsCount - 1 - AutoCorrectEngine.Shift];
        var FirstElementPos = FirstElement.ElementPos;
        FirstElement.Pos++;
        var bReplaseShiftContent = false;
        for (var nPos = 0, nCount = AutoCorrectEngine.RemoveCount; nPos < nCount; nPos++)
        {
            /*if (CanMakeAutoCorrectEquation && AutoCorrectEngine.ActionElement.value == 0x20 && bReplaseShiftContent === false)
            {
                bReplaseShiftContent = true;
                nPos++;
                AutoCorrectEngine.RemoveCount--;
                nCount--;
                if (nPos >= nCount)
                    break;
            }*/
            LastElement = AutoCorrectEngine.Elements[ElementsCount - nPos - 1 - AutoCorrectEngine.Shift];

            if (undefined !== LastElement.Run)
            {
                if (FirstElement.Run === LastElement.Run)
                    FirstElement.Pos--;

                LastElement.Run.Remove_FromContent(LastElement.Pos, 1);
            }
            else
            {
                this.Remove_FromContent(LastElement.ElementPos, 1);
                FirstElementPos--;
            }
        }

        if (FirstElement.Type != para_Math_Composition)
        {
            var NewRun = FirstElement.Run.Split2(FirstElement.Pos);
            this.Internal_Content_Add(FirstElementPos + 1, NewRun, false);
        }

        var NewElementsCount = AutoCorrectEngine.ReplaceContent.length;
        for (var nPos = 0; nPos < NewElementsCount; nPos++)
        {
            this.Internal_Content_Add(nPos + FirstElementPos + 1, AutoCorrectEngine.ReplaceContent[nPos], false);
        }

        this.CurPos = FirstElementPos + NewElementsCount;

        if (CanMakeAutoCorrectEquation && AutoCorrectEngine.Type == MATH_NARY)
        {
            var oContentElem = this.Content[this.CurPos];
            this.Correct_Content(true);

            var CurrentContent = new CParagraphContentPos();
            this.ParaMath.Get_ParaContentPos(false, false, CurrentContent);

            var LeftContentPos = new CParagraphSearchPos();
            this.ParaMath.Get_LeftPos(LeftContentPos, CurrentContent, 0, true);
            this.ParaMath.Set_ParaContentPos(LeftContentPos.Pos, 0);

            this.CurPos++;
            oContentElem.CurPos = 2;
            oContentElem.Content[2].MoveCursorToStartPos();
        }
        else
        {
            this.CurPos++;
            if (AutoCorrectEngine.Shift == 0)
                this.Content[this.CurPos].MoveCursorToStartPos();
            else
                this.Content[this.CurPos].MoveCursorToEndPos();

        }

        if (true === bCursorStepRight)
        {
            // TODO: Переделать через функцию в ране
            if (this.Content[this.CurPos].Content.length >= 1)
                this.Content[this.CurPos].State.ContentPos = 1;
        }
    }
    else
    {
        History.Remove_LastPoint();
    }
};
CMathContent.prototype.private_NeedAutoCorrect = function( ActionElement)
{
    var CharCode;
    if (para_Math_Ampersand == ActionElement.Type)
        CharCode = 0x26;
    else
        CharCode = ActionElement.value;

    if (1 === g_aMathAutoCorrectTriggerCharCodes[CharCode])
        return true;

    return false;
};
CMathContent.prototype.private_CanAutoCorrectText = function(AutoCorrectionEngine, bSkipLast)
{
    var IndexAdd = (true === bSkipLast ? 1 : 0);

    var ElementsCount = AutoCorrectionEngine.Elements.length;
    if (ElementsCount < 2 + IndexAdd)
        return false;

    var Result = false;

    var RemoveCount  = 0;
    var ReplaceChars = [0x0020];
    var AutoCorrectCount = g_aAutoCorrectMathSymbols.length;
    for (var nIndex = 0; nIndex < AutoCorrectCount; nIndex++)
    {
        var AutoCorrectElement = g_aAutoCorrectMathSymbols[nIndex];
        var CheckString = AutoCorrectElement[0];
        var CheckStringLen = CheckString.length;

        if (ElementsCount < CheckStringLen)
            continue;

        var Found = true;

        // Начинаем проверять с конца строки
        for (var nStringPos = 0; nStringPos < CheckStringLen; nStringPos++)
        {
            var LastElement = AutoCorrectionEngine.Elements[ElementsCount - nStringPos - 1 - IndexAdd];
            if (undefined === LastElement.Text || LastElement.Text !== CheckString.charAt(CheckStringLen - nStringPos - 1))
            {
                Found = false;
                break;
            }
        }

        if (true === Found)
        {
            RemoveCount   = CheckStringLen + IndexAdd;

            if (undefined === AutoCorrectElement[1].length)
                ReplaceChars[0] = AutoCorrectElement[1];
            else
            {
                for (var Index = 0, Len = AutoCorrectElement[1].length; Index < Len; Index++)
                {
                    ReplaceChars[Index] = AutoCorrectElement[1][Index];
                }
            }

        }
    }

    if (RemoveCount > 0)
    {
        var MathRun = new ParaRun(this.ParaMath.Paragraph, true);
        MathRun.Set_Pr(AutoCorrectionEngine.TextPr.Copy());
        MathRun.Set_MathPr(AutoCorrectionEngine.MathPr.Copy());

        for (var Index = 0, Count = ReplaceChars.length; Index < Count; Index++)
        {
            var ReplaceText = new CMathText();
            ReplaceText.add(ReplaceChars[Index]);
            MathRun.Add(ReplaceText, true);
        }

        AutoCorrectionEngine.RemoveCount = RemoveCount;
        AutoCorrectionEngine.ReplaceContent.push(MathRun);

        Result = true;
    }

    return Result;
};
/*CMathContent.prototype.private_AutoCorrectDelimiter = function( AutoCorrectionEngine, ActionElement)
 {
 var ElementsCount = AutoCorrectionEngine.Elements.length;
 if (ElementsCount < 2)
 return false;

 var oLastElem = AutoCorrectionEngine.Elements[ElementsCount-2];
 if (oLastElem.Type != para_Math_Text && oLastElem.Text != ')')
 return false;

 var bClose = false;
 var bOpen = false;
 var TempElements = [];
 var BrAccount = new CMathBracketAcc();
 for (var i = ElementsCount-1; i >= 0; i--)
 {
 var oCurElem = AutoCorrectionEngine.Elements[i];
 if (oCurElem.Type === para_Math_Text && oCurElem.Text == '(')
 {
 if (!bClose)
 return false;
 BrAccount.CorrectLeft(oCurElem, i, oCurElem.Text.charCodeAt(0));
 }
 else if (oCurElem.Type === para_Math_Text && oCurElem.Text == ')')
 {
 if (bClose)
 return false;
 bClose = true;
 BrAccount.CorrectRight(oCurElem, i, oCurElem.Text.charCodeAt(0));

 }
 else if (oCurElem.Type != para_Math_Composition)
 {
 continue;
 }
 }
 this.AutoCorrectDelimiter(AutoCorrectionEngine, BrAccount, CanMakeAutoCorrect);

 return true;
 };*/
CMathContent.prototype.private_CanAutoCorrectTextFunc = function( AutoCorrectionEngine, bSkipLast)
{
    var IndexAdd = (true === bSkipLast ? 1 : 0);

    var ElementsCount = AutoCorrectionEngine.Elements.length;
    if (ElementsCount < 2 + IndexAdd)
        return false;

    var Result = false;
    var RemoveElem = null;

    var RemoveCount  = 0;
    var ReplaceChars = [0x0020];
    var AutoCorrectCount = g_aAutoCorrectMathFuncSymbols.length;
    for (var nIndex = 0; nIndex < AutoCorrectCount; nIndex++)
    {
        var AutoCorrectElement = g_aAutoCorrectMathFuncSymbols[nIndex];
        var CheckString = AutoCorrectElement;
        var CheckStringLen = CheckString.length;

        if (ElementsCount < CheckStringLen)
            continue;

        var Found = true;

        // Начинаем проверять с конца строки
        for (var nStringPos = 0; nStringPos < CheckStringLen; nStringPos++)
        {
            var LastElement = AutoCorrectionEngine.Elements[ElementsCount - nStringPos - 1 - IndexAdd];
            if (undefined === LastElement.Text || LastElement.Text !== CheckString.charAt(CheckStringLen - nStringPos - 1))
            {
                Found = false;
                break;
            }
        }
        if ( Found === true )
        {
            var nFirstElem = ElementsCount - CheckStringLen - 1 - IndexAdd;
            if (nFirstElem < 0 || (CheckStringLen >= 0 && (AutoCorrectionEngine.Elements[nFirstElem].Type === para_Math_Composition || AutoCorrectionEngine.Elements[nFirstElem].Text.charCodeAt(0) == 0x0020)))
                RemoveElem = AutoCorrectElement;
            else
                break;
        }
    }

    if (RemoveElem)
    {
        var Pr = {ctrPrp: new CTextPr()};
        var MathFunc = new CMathFunc(Pr);
        var MathContent = MathFunc.getFName();

        var MathRun = new ParaRun(this.Paragraph, true);
        for (var nCharPos = 0, nTextLen = RemoveElem.length; nCharPos < nTextLen; nCharPos++)
        {
            var oText = null;
            if (0x0026 == RemoveElem.charCodeAt(nCharPos))
                oText = new CMathAmp();
            else
            {
                oText = new CMathText(false);
                oText.addTxt(RemoveElem[nCharPos]);
            }
            MathRun.Add(oText, true);
        }
        MathRun.Math_Apply_Style(STY_PLAIN);
        MathContent.Internal_Content_Add(0, MathRun);


        AutoCorrectionEngine.RemoveCount = CheckStringLen + IndexAdd;
        AutoCorrectionEngine.ReplaceContent.push(MathFunc);

        Result = true;
    }

    return Result;
};
CMathContent.prototype.Clear_ContentChanges = function()
{
	this.m_oContentChanges.Clear();
};
CMathContent.prototype.Add_ContentChanges = function(Changes)
{
	this.m_oContentChanges.Add(Changes);
};
CMathContent.prototype.Refresh_ContentChanges = function()
{
	this.m_oContentChanges.Refresh();
};

function AutoCorrectionControl (AutoCorrectionEngine, ParaMath)
{
    this.TempElements = [];
    this.TempElements2 = [];
    this.TempElements3 = [];

    this.props = {};
    this.BrAccount = new CMathBracketAcc();

    this.ParaMath = ParaMath;
    this.ActionElement = AutoCorrectionEngine.ActionElement;
    this.ActionElementCode = AutoCorrectionEngine.ActionElement.value;

    this.ReplaceCode = null;

    this.Delimiter = null;
    this.bDelimiter = false;
    this.bOpenBrk = false;
    this.bCloseBrk = false;

    this.RemoveCount = AutoCorrectionEngine.RemoveCount;
    this.Elements = AutoCorrectionEngine.Elements;
    this.ElementsCount = AutoCorrectionEngine.Elements.length;

}
AutoCorrectionControl.prototype.SetReplaceChar = function(AutoCorrectionEngine)
{
    this.Elements = AutoCorrectionEngine.Elements;
    if (AutoCorrectionEngine.ReplaceContent.length > 0)
        this.ReplaceCode = AutoCorrectionEngine.ReplaceContent[0].Content[0].value;
    this.RemoveCount = AutoCorrectionEngine.RemoveCount;
    this.ElementsCount = AutoCorrectionEngine.Elements.length;
};
AutoCorrectionControl.prototype.PackTextToContent = function(Element, TempElements, AutoCorrectionEngine, bReplaceBrackets)
{
    var len = TempElements.length;
    if (len > 1 && TempElements[0].Type != para_Math_Composition && bReplaceBrackets)
        if ( (TempElements[0].Text === '(' && TempElements[len-1].Text === ')') || (TempElements[0].Text.charCodeAt(0) === 0x3016 && TempElements[len-1].Text.charCodeAt(0) === 0x3017))
        {
            TempElements.splice(len-1,1);
            TempElements.splice(0,1);
            len -= 2 ;
        }

    for (var nPos = 0; nPos < len; nPos++)
    {
        if (undefined === TempElements[nPos].Text)
            Element.Internal_Content_Add(nPos, TempElements[nPos].Element);
        else
        {
            var MathRun = new ParaRun(this.ParaMath.Paragraph, true);

            MathRun.Set_Pr(AutoCorrectionEngine.TextPr.Copy());
            MathRun.Set_MathPr(AutoCorrectionEngine.MathPr.Copy());

            var MathText = new CMathText();
            MathText.add(TempElements[nPos].Text.charCodeAt(0));
            MathRun.Add_ToContent(nPos, MathText);
            Element.Internal_Content_Add(nPos, MathRun);
        }
    }
};
AutoCorrectionControl.prototype.AutoCorrectAccent = function(AutoCorrectionEngine, CanMakeAutoCorrect)
{
    var props = new CMathAccentPr();
    props.chr = this.Elements[this.BrAccount.nRRPos+1].Text;
    var oAccent = new CAccent(props);

    var oBase = oAccent.getBase(0);

    var TempElements = [];
    var nRemoveCount = 2;

    if (this.bOpenBrk && this.bCloseBrk)
    {
        for( var i = this.BrAccount.nRPos-1; i>this.BrAccount.nLPos; i--)
            TempElements.splice(0, 0, this.Elements[i]);
        nRemoveCount = this.BrAccount.nRPos - this.BrAccount.nLPos + 2;
    }
    else
        TempElements.splice(0, 0, AutoCorrectionEngine.Elements[this.CurPos-1]);

    this.PackTextToContent(oBase, TempElements, AutoCorrectionEngine);

    if (CanMakeAutoCorrect)
        nRemoveCount += AutoCorrectionEngine.RemoveCount;
    else if (0x20 == this.ActionElementCode)
        nRemoveCount++;
    AutoCorrectionEngine.RemoveCount = nRemoveCount;

    AutoCorrectionEngine.ReplaceContent.unshift(oAccent);
    return true;
};
AutoCorrectionControl.prototype.AutoCorrectDelimiter = function(AutoCorrectionEngine, CanMakeAutoCorrect)
{
    var props = new CMathDelimiterPr();
    props.column = 1;
    props.begChr = this.BrAccount.LBracket;
    props.endChr = this.BrAccount.RBracket;
    var oDelimiter = new CDelimiter(props);

    var oBase = oDelimiter.getBase(0);
    var TempElements = [];
    for( var i = this.BrAccount.nRPos-1; i>this.BrAccount.nLPos; i--)
        TempElements.splice(0, 0, AutoCorrectionEngine.Elements[i]);

    this.PackTextToContent(oBase, TempElements, AutoCorrectionEngine);

    AutoCorrectionEngine.Shift = AutoCorrectionEngine.Elements.length - 1 - this.BrAccount.nRPos;
    if (0x20 == this.ActionElementCode)
        AutoCorrectionEngine.Shift--;

    var nRemoveCount = this.BrAccount.nRPos - this.BrAccount.nLPos + 1;
    if (CanMakeAutoCorrect)
        nRemoveCount += AutoCorrectionEngine.RemoveCount;
    else if (0x20 == this.ActionElementCode)
        nRemoveCount++;
    AutoCorrectionEngine.RemoveCount = nRemoveCount;

    AutoCorrectionEngine.ReplaceContent.unshift(oDelimiter);
};
AutoCorrectionControl.prototype.AutoCorrectPhantom = function(AutoCorrectionEngine, CanMakeAutoCorrect)
{
    var props = new CMathPhantomPr();
    props.Set_FromObject(this.props);
    var oPhantom = new CPhantom(props);

    var oBase = oPhantom.getBase();
    var TempElements = [];

    for( var i = this.BrAccount.nRPos-1; i>this.BrAccount.nLPos; i--)
        TempElements.splice(0, 0, AutoCorrectionEngine.Elements[i]);

    AutoCorrectionEngine.Shift = AutoCorrectionEngine.Elements.length - 1 - this.BrAccount.nRPos;
    if (0x20 == this.ActionElementCode)
        AutoCorrectionEngine.Shift--;

    this.PackTextToContent(oBase, TempElements, AutoCorrectionEngine);

    var nRemoveCount = this.BrAccount.nRPos - this.BrAccount.nLPos + 2;
    if (CanMakeAutoCorrect)
        nRemoveCount += AutoCorrectionEngine.RemoveCount;
    else if (0x20 == this.ActionElementCode)
        nRemoveCount++;
    AutoCorrectionEngine.RemoveCount = nRemoveCount;

    AutoCorrectionEngine.ReplaceContent.unshift(oPhantom);
};
AutoCorrectionControl.prototype.AutoCorrectMatrix = function(AutoCorrectionEngine, CanMakeAutoCorrect)
{
    var arrContent = [];
    var col = 0;
    var row = 0;
    var mcs = [];
    var oCurElem = null;
    arrContent[row] = [];
    arrContent[row][col] = [];
    mcs[0] = {count: 1, mcJc: 0};

    for (var i=this.BrAccount.nLPos+1; i<this.BrAccount.nRPos; i++)
    {
        oCurElem = AutoCorrectionEngine.Elements[i];
        if ( '&' === oCurElem.Text || '@' === oCurElem.Text)
        {
            if ('&' === oCurElem.Text)
            {
                col++;
                if (col+1 > mcs[0].count)
                    mcs[0] = {count: col+1, mcJc: 0};
                arrContent[row][col] = [];
            }
            else if ('@' === oCurElem.Text)
            {
                row++;
                col = 0;
                arrContent[row] = [];
                arrContent[row][col] = [];
            }
        }
        else
        {
            if (para_Math_Text == oCurElem.Type || para_Math_BreakOperator == oCurElem.Type)
            {
                var MathText = new CMathText();
                MathText.add(oCurElem.Text.charCodeAt(0));
                arrContent[row][col].push( MathText );
            }
            else
                arrContent[row][col].push( oCurElem.Element );
        }
    }

    var props = new CMathMatrixPr();
    props.row = row+1;
    props.mcs = mcs;
    props.ctrPrp = AutoCorrectionEngine.TextPr.Copy();
    var Matrix = new CMathMatrix(props);

    for (var i=0; i<arrContent.length; i++)
        for (var j=0; j<arrContent[i].length; j++)
        {
            var Elem = Matrix.getElement(i,j);
            var Content = arrContent[i][j];
            for (var l=0; l<Content.length; l++)
            {
                var CurElem = Content[l];
                if (para_Math_Text == CurElem.Type || para_Math_BreakOperator === CurElem.Type)
                {
                    var MathRun = new ParaRun(this.ParaMath.Paragraph, true);
                    MathRun.Set_Pr(AutoCorrectionEngine.TextPr.Copy());
                    MathRun.Set_MathPr(AutoCorrectionEngine.MathPr.Copy());
                    MathRun.Add_ToContent(0, CurElem);
                    Elem.Internal_Content_Add(Elem.length, MathRun);
                }
                else
                    Elem.Internal_Content_Add(Elem.length, CurElem);

            }
        }

    AutoCorrectionEngine.Shift = AutoCorrectionEngine.Elements.length - 1 - this.BrAccount.nRPos;
    if (0x20 == this.ActionElementCode)
        AutoCorrectionEngine.Shift--;

    var nRemoveCount = this.BrAccount.nRPos - this.BrAccount.nLPos + 2;
    if (CanMakeAutoCorrect)
        nRemoveCount += AutoCorrectionEngine.RemoveCount;
    else if (0x20 == this.ActionElementCode)
        nRemoveCount++;
    AutoCorrectionEngine.RemoveCount = nRemoveCount;

    if (this.Delimiter)
    {
        var oDelElem = this.Delimiter.getBase(0);
        oDelElem.addElementToContent(Matrix);
        AutoCorrectionEngine.ReplaceContent.unshift(this.Delimiter);
    }
    else
        AutoCorrectionEngine.ReplaceContent.unshift(Matrix);
};
AutoCorrectionControl.prototype.AutoCorrectEqArray = function(AutoCorrectionEngine, CanMakeAutoCorrect)
{
    var arrContent = [];
    var col = 0;
    var row = 0;
    var mcs = [];
    var oCurElem = null;
    arrContent[row] = [];

    for (var i=this.BrAccount.nLPos+1; i<this.BrAccount.nRPos; i++)
    {
        oCurElem = AutoCorrectionEngine.Elements[i];
        if ('@' === oCurElem.Text)
        {
            row++;
            arrContent[row] = [];
        }
        else
        {
            if (para_Math_Text == oCurElem.Type || para_Math_BreakOperator == oCurElem.Type)
            {
                var MathText = new CMathText();
                MathText.add(oCurElem.Text.charCodeAt(0));
                arrContent[row].push( MathText );
            }
            else if (para_Math_Ampersand == oCurElem.Type)
            {
                var MathText = new CMathAmp();
                arrContent[row].push( MathText );
            }
            else
                arrContent[row].push( oCurElem.Element );
        }
    }

    var props = new CMathEqArrPr();
    props.row = row+1;
    props.ctrPrp = AutoCorrectionEngine.TextPr.Copy();
    var EqArray = new CEqArray(props);

    for (var i=0; i<arrContent.length; i++)
    {
        var Elem = EqArray.getElement(i);
        var Content = arrContent[i];
        for (var l=0; l<Content.length; l++)
        {
            var CurElem = Content[l];
            if (para_Math_Composition != CurElem.Type)
            {
                var MathRun = new ParaRun(this.ParaMath.Paragraph, true);
                MathRun.Set_Pr(AutoCorrectionEngine.TextPr.Copy());
                MathRun.Set_MathPr(AutoCorrectionEngine.MathPr.Copy());
                MathRun.Add_ToContent(0, CurElem);
                Elem.Internal_Content_Add(Elem.length, MathRun);
            }
            else
                Elem.Internal_Content_Add(Elem.length, CurElem);

        }
    }

    AutoCorrectionEngine.Shift = AutoCorrectionEngine.Elements.length - 1 - this.BrAccount.nRPos;
    if (0x20 == this.ActionElementCode)
        AutoCorrectionEngine.Shift--;

    var nRemoveCount = this.BrAccount.nRPos - this.BrAccount.nLPos + 2;
    if (CanMakeAutoCorrect)
        nRemoveCount += AutoCorrectionEngine.RemoveCount;
    else if (0x20 == this.ActionElementCode)
        nRemoveCount++;
    AutoCorrectionEngine.RemoveCount = nRemoveCount;

    if (this.Delimiter)
    {
        var oDelElem = this.Delimiter.getBase(0);
        oDelElem.addElementToContent(EqArray);
        AutoCorrectionEngine.ReplaceContent.unshift(this.Delimiter);
    }
    else
        AutoCorrectionEngine.ReplaceContent.unshift(EqArray);

};
AutoCorrectionControl.prototype.AutoCorrectRadical = function(AutoCorrectionEngine, CanMakeAutoCorrect)
{
    var oCurElem = null;
    var arrContent = [];
    var col = 0;
    arrContent[col] = [];
    for (var i = this.BrAccount.nLPos + 1; i < this.BrAccount.nRPos; i++)
    {
        oCurElem = AutoCorrectionEngine.Elements[i];
        if ( '&' === oCurElem.Text )
        {
            col++;
            arrContent[col] = [];
        }
        else
        {
            if (oCurElem.Text)
            {
                var MathText = new CMathText();
                MathText.add(oCurElem.Text.charCodeAt(0));
                arrContent[col].push( MathText );
            }
            else
                arrContent[col].push( oCurElem.Element );
        }
    }

    var props = new CMathRadicalPr();
    props.ctrPrp = AutoCorrectionEngine.TextPr.Copy();
    var Radical = new CRadical(props);

    var Base = Radical.getBase();
    var Degree = Radical.getDegree();


    for (var i=0; i<arrContent[1].length; i++)
    {
        var CurElem = arrContent[1][i];
        if (para_Math_Text == CurElem.Type || para_Math_BreakOperator === CurElem.Type)
        {
            var MathRun = new ParaRun(this.ParaMath.Paragraph, true);
            MathRun.Set_Pr(AutoCorrectionEngine.TextPr.Copy());
            MathRun.Set_MathPr(AutoCorrectionEngine.MathPr.Copy());
            MathRun.Add_ToContent(0, CurElem);
            Base.Internal_Content_Add(Base.length, MathRun);
        }
        else
            Base.Internal_Content_Add(Base.length, CurElem);
    }
    for (var i=0; i<arrContent[0].length; i++)
    {
        var CurElem = arrContent[0][i];
        if (para_Math_Text == CurElem.Type || para_Math_BreakOperator === CurElem.Type)
        {
            var MathRun = new ParaRun(this.ParaMath.Paragraph, true);
            MathRun.Set_Pr(AutoCorrectionEngine.TextPr.Copy());
            MathRun.Set_MathPr(AutoCorrectionEngine.MathPr.Copy());
            MathRun.Add_ToContent(0, CurElem);
            Degree.Internal_Content_Add(Degree.length, MathRun);
        }
        else
            Degree.Internal_Content_Add(Degree.length, CurElem);
    }


    AutoCorrectionEngine.RemoveCount = this.BrAccount.nRPos - this.BrAccount.nLPos + 2 + 1;
    AutoCorrectionEngine.ReplaceContent.unshift(Radical);
};
AutoCorrectionControl.prototype.FindFunction = function(CanMakeAutoCorrect)
{
    var oRigthCommandType = null;
    var oLeftCommandType  = null;

    var bOf        = false;
    var bAddAccent = false;

    var nCountElems = this.ElementsCount;
    if (CanMakeAutoCorrect)
        nCountElems = this.ElementsCount - this.RemoveCount;

    if (nCountElems < 2)
        return false;

    var nCurPos = nCountElems - 1;

    var oCurElem = this.Elements[nCurPos];
    if (oCurElem.Type === para_Math_Text && oCurElem.Text == ' ')
    {
        nCurPos--;
        nCountElems--;
        this.ElementsCount--;
        oCurElem = this.Elements[nCurPos];
    }

    // 2 пробела подряд в конце
    if (oCurElem.Type === para_Math_Text && oCurElem.Text == ' ')
        return false;
    //автозамена производится только до оператора остановки ( + - * и тд )
    else if (CanMakeAutoCorrect && oCurElem.Type === para_Math_BreakOperator)
        return false;
    else if (CanMakeAutoCorrect && this.ReplaceCode == 0x8289)
        oRigthCommandType = MATH_RUN;

    //проверка открытых и закрытых скобок
    for (var i = nCurPos; i >= 0; i--)
    {
        oCurElem = this.Elements[i];
        if (para_Math_Composition == oCurElem.Type)
            continue;
        else if (oCurElem.Type === para_Math_Text && oCurElem.Text === '(' && this.bCloseBrk)
        {
            if (this.BrAccount.LBracket == 0x7C)
            {
                this.BrAccount.CorrectLeftSeparate(oCurElem, i, oCurElem.Text.charCodeAt(0));
                this.bOpenBrk    = true;
                oLeftCommandType = MATH_DELIMITER;
                this.bDelimiter  = true;
            }
            else
            {
                this.BrAccount.CorrectLeft(oCurElem, i, oCurElem.Text.charCodeAt(0));
                this.bOpenBrk = true;
                if (this.BrAccount.nCounter < 0)
                    break;

                //для дроби и степени контент в скобках не заменяем на delimiter
                if (0x5E != this.ActionElementCode && 0x5F != this.ActionElementCode && 0x2F != this.ActionElementCode)
                {
                    oLeftCommandType = MATH_DELIMITER;
                    this.bDelimiter  = true;
                }
            }

        }
        else if (oCurElem.Text === ')')
        {
            this.BrAccount.CorrectRight(oCurElem, i, oCurElem.Text.charCodeAt(0));
            this.bCloseBrk = true;
        }
        else if (g_MathLeftBracketAutoCorrectCharCodes[oCurElem.Text.charCodeAt(0)] && this.bCloseBrk)
        {
            if (this.BrAccount.LBracket == 0x7C)
            {
                this.BrAccount.CorrectLeftSeparate(oCurElem, i, oCurElem.Text.charCodeAt(0));
                this.bOpenBrk    = true;
                oLeftCommandType = MATH_DELIMITER;
                this.bDelimiter  = true;
            }
            else
            {
                this.BrAccount.CorrectLeft(oCurElem, i, oCurElem.Text.charCodeAt(0));
                this.bOpenBrk = true;
                if (this.BrAccount.nCounter < 0)
                    break;

                //для дроби и степени контент в скобках не заменяем на delimiter
                if (0x5E != this.ActionElementCode && 0x5F != this.ActionElementCode && 0x2F != this.ActionElementCode)
                {
                    oLeftCommandType = MATH_DELIMITER;
                    this.bDelimiter  = true;
                }
            }
        }
        else if (g_MathRightBracketAutoCorrectCharCodes[oCurElem.Text.charCodeAt(0)])
        {
            this.BrAccount.CorrectRight(oCurElem, i, oCurElem.Text.charCodeAt(0));
            this.bCloseBrk = true;
        }
        else if (oCurElem.Text === '|')
        {
            var code = oCurElem.Text.charCodeAt(0);
            this.BrAccount.Elems.unshift(i, code);

            if (this.bCloseBrk == false)
            {
                this.BrAccount.CorrectRight(oCurElem, i, oCurElem.Text.charCodeAt(0));
                this.bCloseBrk = true;
            }
            else if (this.bCloseBrk == true && this.bOpenBrk == false)
            {
                this.BrAccount.CorrectLeft(oCurElem, i, oCurElem.Text.charCodeAt(0));
                this.bOpenBrk = true;
                if (this.BrAccount.nCounter < 0)
                    break;
                oLeftCommandType = MATH_DELIMITER;
                this.bDelimiter  = true;
            }
            else if (this.bCloseBrk == true && this.bOpenBrk == true)
            {
                if (this.BrAccount.LBracket == 0x7C)
                {
                    this.BrAccount.CorrectLeftSeparate(oCurElem, i, oCurElem.Text.charCodeAt(0));
                    this.bOpenBrk    = true;
                    oLeftCommandType = MATH_DELIMITER;
                    this.bDelimiter  = true;
                }
                else
                {
                    this.BrAccount.CorrectLeft(oCurElem, i, oCurElem.Text.charCodeAt(0));
                    this.bOpenBrk = true;
                    if (this.BrAccount.nCounter < 0)
                        break;
                    oLeftCommandType = MATH_DELIMITER;
                    this.bDelimiter  = true;
                }
            }
        }
        else if (oCurElem.Text === '(' && !this.bCloseBrk)
        {
            if (g_MathRightBracketAutoCorrectCharCodes[this.ActionElementCode] || g_aMathAutoCorrectFracCharCodes[this.ActionElementCode])
                break;
            else
                return;
        }
        else if (oCurElem.Type === para_Math_BreakOperator && oCurElem.Text.charCodeAt(0) == 0x5C)
        {
            if (i < nCurPos)
            {
                var oPrevElem = this.Elements[i + 1];
                if (oPrevElem.Type === para_Math_Text && oPrevElem.Text === '/')
                    break;
            }
            return false;
        }
        else if (oCurElem.Type === para_Math_Text && oCurElem.Text.charCodeAt(0) == 0x2592) // \of
        {
            bOf = true;
            break;
        }
        else if (oCurElem.Type === para_Math_Text && oCurElem.Text == ' ' && this.BrAccount.nCounter < 0)
            break;
        else if (oCurElem.Type === para_Math_Text && oCurElem.Text == ' ' && !this.bCloseBrk)
            break;
        else if (oCurElem.Type === para_Math_Text && oCurElem.Text == ' ' && this.bCloseBrk && this.BrAccount.nCounter == 0)
            break;
        else if ('&' === oCurElem.Text || '@' === oCurElem.Text)
            this.BrAccount.bSeparator = true;
        else if (q_aMathAutoCorrectAccentCharCodes[oCurElem.Text.charCodeAt(0)])
        {
            oRigthCommandType = MATH_ACCENT;
        }
        else if (oCurElem.Type === para_Math_Text)
        {
            var oChar = oCurElem.Text.charCodeAt(0);

            if (q_aMathAutoCorrectControlAggregationCodes[oChar])
                oLeftCommandType = MATH_NARY;
            else
            {
                switch (oChar)
                {
                    case 0x24B8:
                        oLeftCommandType  = MATH_EQ_ARRAY;
                        this.props        = new CMathDelimiterPr();
                        this.props.begChr = 0x007B;
                        this.props.endChr = -1;
                        this.props.column = 1;
                        this.Delimiter    = new CDelimiter(this.props);
                        break;
                    case 0x2588:
                        oLeftCommandType = MATH_EQ_ARRAY;
                        break;
                    case 0x25A0:
                        oLeftCommandType = MATH_MATRIX;
                        break;
                    case 0x24A8:
                        oLeftCommandType  = MATH_MATRIX;
                        this.props        = new CMathDelimiterPr();
                        this.props.column = 1;
                        this.Delimiter    = new CDelimiter(this.props);
                        break;
                    case 0x24A9:
                        oLeftCommandType  = MATH_MATRIX;
                        this.props        = new CMathDelimiterPr();
                        this.props.column = 1;
                        this.props.begChr = 0x2016;
                        this.props.endChr = 0x2016;
                        this.Delimiter    = new CDelimiter(this.props);
                        break;
                    case 0x25AD:
                        oLeftCommandType = MATH_BORDER_BOX;
                        break;
                    case 0x25A1:
                        oLeftCommandType = MATH_BOX;
                        break;
                    case 0x00AF:
                    case 0x033F:
                        oLeftCommandType = MATH_BAR;
                        this.props       = {pos : LOCATION_TOP};
                        break;
                    case 0x2581:
                        oLeftCommandType = MATH_BAR;
                        break;
                    case 0x221A:
                        oLeftCommandType = MATH_RADICAL;
                        break;
                    case 0x221B:
                        //TempElements2.splice(0, 0, {Text : '3'});
                        oLeftCommandType = MATH_RADICAL;
                        break;
                    case 0x221C:
                        //TempElements2.splice(0, 0, {Text : '4'});
                        oLeftCommandType = MATH_RADICAL;
                        break;
                    case 0x23E0:
                    case 0x23DC:
                        oLeftCommandType = MATH_GROUP_CHARACTER;
                        this.props       = {chr : oCurElem.Text.charCodeAt(0), pos : LOCATION_TOP, vertJc : VJUST_BOT};
                        break;
                    case 0x23DD:
                        oLeftCommandType = MATH_GROUP_CHARACTER;
                        this.props       = {chr : oCurElem.Text.charCodeAt(0)};
                        break;
                    case 0x23DF:
                        oLeftCommandType = MATH_GROUP_CHARACTER;
                        break;
                    case 0x23DE:
                        oLeftCommandType = MATH_GROUP_CHARACTER;
                        this.props       = {chr : 0x23DE, pos : LOCATION_TOP, vertJc : VJUST_BOT};
                        break;
                    case 0x24AD:
                        if (bOf)
                            oLeftCommandType = MATH_RADICAL;
                        else
                            return false;
                        break;

                }
            }
            if (oLeftCommandType == MATH_DELIMITER && this.BrAccount.LBracket == 0x7C)
            {
                for (var j = i - 1; j >= 0; j--)
                {
                    oCurElem = this.Elements[j];
                    if (oCurElem.Type === para_Math_Text && oCurElem.Text == ' ' && this.BrAccount.nCounter < 0)
                        break;
                    else if (oCurElem.Type === para_Math_Text && oCurElem.Text == ' ' && !this.bCloseBrk)
                        break;
                    else if (oCurElem.Type === para_Math_Text && oCurElem.Text == ' ' && this.bCloseBrk && this.BrAccount.nCounter == 0)
                        break;
                    else if (oCurElem.Text == '(' && this.BrAccount.nCounter == 0)
                        this.BrAccount.CorrectLeftSeparate(oCurElem, j, oCurElem.Text.charCodeAt(0));
                }
                break;
            }
            else if (oLeftCommandType != null)
                break;
        }
        else if (oCurElem.Type === para_Math_BreakOperator)
        {
            var oChar = oCurElem.Text.charCodeAt(0);
            switch (oChar)
            {
                case 0x27E1:
                    oLeftCommandType = MATH_PHANTOM;
                    this.props       = {show : 0};
                    break;
                case 0x2B04:
                    oLeftCommandType = MATH_PHANTOM;
                    this.props       = {show : 0, zeroAsc : 1, zeroDesc : 1};
                    break;
                case 0x21F3:
                    oLeftCommandType = MATH_PHANTOM;
                    this.props       = {show : 0, zeroWid : 1};
                    break;
            }
            if (oLeftCommandType || !this.bCloseBrk)
                break;
        }
    }
    if (oRigthCommandType)
    {
        this.Type = oRigthCommandType;
    }
    //сюда попадаем, если будет двойная автозамена символ+формула
    else if (CanMakeAutoCorrect)
    {
        if (oLeftCommandType)
        {
            //если это delimiter то ничего не делаем
            if (oLeftCommandType == MATH_DELIMITER)
                return false;
            // для n-арных операторов делается только 1 автозамена
            else if (CanMakeAutoCorrect && (oLeftCommandType == MATH_NARY || oLeftCommandType == MATH_RADICAL))
                return false;
            else
            {
                bAddAccent = true;
                this.Type  = oLeftCommandType;
            }
        }
        //если пришел accent на одну букву то выходим, тк сделается просто автозамена символа
        else if (!this.bOpenBrk && !this.bCloseBrk && q_aMathAutoCorrectAccentCharCodes[this.ReplaceCode])
            return false;
    }
    else
        this.Type = oLeftCommandType;

    this.CurPos = nCurPos;
    return true;
};
AutoCorrectionControl.prototype.private_CanAutoCorrectEquation = function(AutoCorrectionEngine, CanMakeAutoCorrect, bCursorStepRight)
{
    var TempElements = [];
    var TempElementsPos = [];
    var TempElements2 = [];
    var TempElements3 = [];
    var bOf = false;

    this.FindFunction(CanMakeAutoCorrect);

    if ( this.Type == MATH_ACCENT)
    {
        this.AutoCorrectAccent(AutoCorrectionEngine, CanMakeAutoCorrect );
        return true;
    }
    if ( this.Type == MATH_RADICAL && this.bOpenBrk && this.bCloseBrk && this.BrAccount.nCounter == 0 && this.BrAccount.bSeparator)
    {
        this.AutoCorrectRadical(AutoCorrectionEngine, CanMakeAutoCorrect);
        return true;
    }
    if ( this.Type == MATH_MATRIX && this.bOpenBrk && this.bCloseBrk && this.BrAccount.nCounter == 0)
    {
        this.AutoCorrectMatrix(AutoCorrectionEngine, CanMakeAutoCorrect);
        return true;
    }
    if ( this.Type == MATH_EQ_ARRAY && this.bOpenBrk && this.bCloseBrk && this.BrAccount.nCounter == 0)
    {
        this.AutoCorrectEqArray(AutoCorrectionEngine, CanMakeAutoCorrect);
        return true;
    }
    if ( this.Type == MATH_PHANTOM && this.bOpenBrk && this.bCloseBrk && this.BrAccount.nCounter == 0)
    {
        this.AutoCorrectPhantom(AutoCorrectionEngine, CanMakeAutoCorrect);
        return true;
    }
    if ( this.Type == MATH_DELIMITER && this.bOpenBrk && this.bCloseBrk && (this.BrAccount.LBracketlvl2 != null || this.BrAccount.RBracketlvl2 != null))
    {
        if ( (this.BrAccount.LBracket == 0x7C && this.BrAccount.RBracket != 0x7C) || (this.BrAccount.LBracket != 0x7C && this.BrAccount.RBracket == 0x7C))
            return false;
        else if ( this.BrAccount.LBracket == 0x7C && this.BrAccount.RBracket == 0x7C && this.BrAccount.LBracketlvl1 != null)
            return false;

        //this.BrAccount.Counted();
        this.AutoCorrectDelimiter(AutoCorrectionEngine, CanMakeAutoCorrect);
        return true;
    }

    var bOpenBrk = false;
    var bCloseBrk = false;

    var CurPos = this.CurPos;
    while (CurPos >= 0)
    {
        var Element = this.Elements[CurPos];
        if (undefined === Element.Text)
        {
            TempElements.splice(0, 0, Element);
            TempElementsPos.splice(0, 0, CurPos);
        }
        else if ( '|' === Element.Text)
        {
            if (bCloseBrk && !bOpenBrk)
            {
                this.Type = MATH_DELIMITER;
                CurPos--;
                break;
            }
            else
                TempElements2.splice(0, 0, Element);
        }
        else if (Element.Text === ')') // )
        {
            TempElements.splice(0, 0, Element);
            TempElementsPos.splice(0, 0, CurPos);
            bCloseBrk = true;
        }
        else if ( Element.Text === '(' ) // (
        {
            if (!bCloseBrk)
                return false;
            if (bOpenBrk)
            {
                //CurPos--; // a^((a/2))
                break;
            }
            TempElements.splice(0, 0, Element);
            TempElementsPos.splice(0, 0, CurPos);
            bOpenBrk = true;
            if (this.ActionElementCode === 0x20)
            {
                if (CurPos-1 > 0) // ((a/1(a+1)
                {
                    var Elem = this.Elements[CurPos-1];
                    if ( para_Math_Text == Elem.Type  &&  '/' != Elem.Text && '_' != Elem.Text && '^' != Elem.Text && 0x00A6 != Elem.Text.charCodeAt(0) && 0x2592 != Elem.Text.charCodeAt(0)
                        && !q_aMathAutoCorrectControlCharCodes[Elem.Text.charCodeAt(0)] )
                        break;
                }

            }
        }
        else if ('/' === Element.Text)
        {
            //введены символы _ ^ + -
            if (this.ActionElement.Type == para_Math_Text && (this.ActionElementCode == 0x005E || this.ActionElementCode == 0x005F)) // a/a_
                return false;

            this.Type = MATH_FRACTION;
            if (CurPos-1 > 0)
            {
                Element = this.Elements[CurPos-1];
                if ( (para_Math_Text == Element.Type || para_Math_BreakOperator == Element.Type) && 0x005C === Element.Text.charCodeAt(0))
                {
                    this.props = {type: LINEAR_FRACTION};
                    CurPos--;
                }
            }

            CurPos--;
            break;
        }
        else if ( 0x221A ===  Element.Text.charCodeAt(0))
        {
            this.Type = MATH_RADICAL;
            break;
        }
        else if ( 0x25AD === Element.Text.charCodeAt(0))
        {
            this.Type = MATH_BORDER_BOX;
            break;
        }
        else if ( 0x25A1 === Element.Text.charCodeAt(0))
        {
            this.Type = MATH_BOX;
            break;
        }
        else if ( 0x2044 ===  Element.Text.charCodeAt(0))
        {
            this.Type = MATH_FRACTION;
            this.props = {type: SKEWED_FRACTION};
            CurPos--;
            break;
        }
        else if  ('^' === Element.Text)
        {
            //если скобки одинаковые - то степень, разные - delimiter
            if( this.Type == MATH_NARY || !this.Type || ( this && (( this.BrAccount.LBracket == 0x28 && this.BrAccount.RBracket == 0x29) || ( this.BrAccount.LBracket == 0x3016 && this.BrAccount.RBracket == 0x3017))))
            {
                TempElements.Type = DEGREE_SUPERSCRIPT;
                this.Kind = DEGREE_SUPERSCRIPT;
                this.Type = MATH_DEGREE;
            }
            CurPos--;
            break;
        }
        else if  ('_' === Element.Text)
        {
            //если скобки одинаковые - то степень, разные - delimiter
            if( this.Type == MATH_NARY || !this.Type || ( this && (( this.BrAccount.LBracket == 0x28 && this.BrAccount.RBracket == 0x29) || ( this.BrAccount.LBracket == 0x3016 && this.BrAccount.RBracket == 0x3017))))
            {
                TempElements.Type = DEGREE_SUBSCRIPT;
                this.Kind = DEGREE_SUBSCRIPT;
                this.Type = MATH_DEGREE;
            }
            CurPos--;
            break;
        }
        else if ( 0x00A6 === Element.Text.charCodeAt(0) )
        {
            this.Type = MATH_FRACTION;
            this.props = {type: NO_BAR_FRACTION};
            CurPos--;
            break;
        }
        else if ( 0x2592 === Element.Text.charCodeAt(0) )// /of просто пропускаем
        {
            bOf = true;
            CurPos--;
            break;
        }
        else if (q_aMathAutoCorrectControlAggregationCodes[Element.Text.charCodeAt(0)]) //sum
        {
            //введены символы _ ^ + -
            if (this.ActionElement.Type != para_Math_Composition && (this.ActionElementCode == 0x005E || this.ActionElementCode == 0x005F|| this.ActionElementCode == 0x002B || this.ActionElementCode == 0x002D))
                return false;

            this.chr = Element.Text;
            this.Type = MATH_NARY;
            CurPos--;
            break;
        }
        else if ( ' ' === Element.Text && !bCloseBrk)
            break;
        else if (g_aMathAutoCorrectTriggerCharCodes[Element.Text.charCodeAt(0)] && bOpenBrk && bCloseBrk)
            break;
        else if (g_aMathAutoCorrectFracCharCodes[Element.Text.charCodeAt(0)])
        {
            if (CurPos-1 > 0) // \sum_-\infty
            {
                var Elem = this.Elements[CurPos-1];
                if ( para_Math_Text == Elem.Type  &&  ('_' == Elem.Text || '^' == Elem.Text))
                {
                    TempElements.splice(0, 0, Element);
                    TempElementsPos.splice(0, 0, CurPos);
                }
                else if (bCloseBrk) // \sum_(--)
                {
                    TempElements.splice(0, 0, Element);
                    TempElementsPos.splice(0, 0, CurPos);
                }
                else if (!bCloseBrk && !bOf ) // \sum_--
                    break;
            }
            else
                break;
        }
        else if (q_aMathAutoCorrectControlCharCodes[Element.Text.charCodeAt(0)])
            break;
        else
        {
            TempElements.splice(0, 0, Element);
            TempElementsPos.splice(0, 0, CurPos);
        }

        CurPos--;
    }

    bOpenBrk = false;
    bCloseBrk = false;
    while (CurPos >= 0)
    {
        if (this.Type == MATH_NARY && TempElements.length == 0)
            break;

        var Element = this.Elements[CurPos];
        if (undefined === Element.Text)
        {
            if (Element.Element.kind == MATH_GROUP_CHARACTER && this.Type == MATH_DEGREE)
            {
                if ( DEGREE_SUPERSCRIPT == this.Kind )
                    this.props = {type: LIMIT_UP};
                else if ( DEGREE_SUBSCRIPT == this.Kind )
                    this.props = {type: LIMIT_LOW};
                this.Type = MATH_LIMIT;
                TempElements2.splice(0, 0, Element);
                break;
            }
            else
                TempElements2.splice(0, 0, Element);
        }
        else if (Element.Text === ')')
        {
            if (bOpenBrk || TempElements2.length > 0)
                break;
            TempElements2.splice(0, 0, Element);
            bCloseBrk = true;
        }
        else if (Element.Text === '(')
        {
            if (!bCloseBrk)
                break;
            if (bOpenBrk)
                break;
            TempElements2.splice(0, 0, Element);
            bOpenBrk = true;
        }
        else if  ('_' === Element.Text)
        {
            if ( this.Type == MATH_DEGREE && TempElements.Type == DEGREE_SUBSCRIPT)
                break;
            TempElements2.Type = DEGREE_SUBSCRIPT;
            this.Kind = DEGREE_SubSup;
            this.Type = MATH_DEGREESubSup;
            CurPos--;
            break;
        }
        else if  ('^' === Element.Text)
        {
            if ( this.Type == MATH_DEGREE && TempElements.Type == DEGREE_SUPERSCRIPT)
                break;
            TempElements2.Type = DEGREE_SUPERSCRIPT;
            this.Kind = DEGREE_SubSup;
            this.Type = MATH_DEGREESubSup;
            CurPos--;
            break;
        }
        else if ( 0x24AD === Element.Text.charCodeAt(0)) // знак корня
        {
            this.Type = MATH_RADICAL;
            break;
        }
        //если это элемент для Nary
        else if (q_aMathAutoCorrectControlAggregationCodes[Element.Text.charCodeAt(0)]) //sum
        {
            //введены символы _ ^ + -
            if ((this.ActionElement.Type == para_Math_Text && (this.ActionElementCode == 0x005E || this.ActionElementCode == 0x005F))
                || (g_aMathAutoCorrectFracCharCodes[this.ActionElementCode] && TempElements.length == 0)) // \int_-
                return false;

            this.chr = Element.Text;
            this.Type = MATH_NARY;
            //CurPos--;
            break;
        }
        else if (Element.Text === '/')
            break;
        else if  ('@' === Element.Text || '&' === Element.Text )
            break;
        else if (g_aMathAutoCorrectTriggerCharCodes[Element.Text.charCodeAt(0)] && bOpenBrk && bCloseBrk)
            break;
        else if (' ' === Element.Text && !bCloseBrk)
            break;
        else if (g_aMathAutoCorrectFracCharCodes[Element.Text.charCodeAt(0)])
        {
            if (CurPos-1 > 0) // \sum_-\infty
            {
                var Elem = this.Elements[CurPos-1];
                if ( para_Math_Text == Elem.Type  &&  ('_' == Elem.Text || '^' == Elem.Text))
                    TempElements2.splice(0, 0, Element);
                else if (bCloseBrk) // \sum_(--)
                    TempElements2.splice(0, 0, Element);
                else if (!bCloseBrk && !bOf ) // \sum_--
                    break;
                else if (!bCloseBrk && bOf) // \root n+a\of 2
                    TempElements2.splice(0, 0, Element);
            }
            else
                break;
        }
        else if (q_aMathAutoCorrectControlCharCodes[Element.Text.charCodeAt(0)])
            break;
        else
            TempElements2.splice(0, 0, Element);

        CurPos--;
    }

    bOpenBrk = false;
    bCloseBrk = false;
    var TempElements3 = [];
    if (this.Type == MATH_DEGREESubSup)
    {
        var FracCharCodes = false;
        while (CurPos >= 0)
        {
            var Element = this.Elements[CurPos];
            if (Element.Type != para_Math_Composition && q_aMathAutoCorrectControlAggregationCodes[Element.Text.charCodeAt(0)]) //sum
            {
                //введены символы _ ^ + -
                if ((this.ActionElement.Type == para_Math_Text && (this.ActionElementCode == 0x005E || this.ActionElementCode == 0x005F))
                    || (g_aMathAutoCorrectFracCharCodes[this.ActionElementCode] && TempElements.length == 0)) // \int_-
                    return false;

                this.chr = Element.Text;
                this.Type = MATH_NARY;
                //CurPos--;
                break;
            }
            else if (para_Math_Composition === Element.Type)
            {
                TempElements3.splice(0, 0, Element);
            }
            else if (g_MathRightBracketAutoCorrectCharCodes[Element.Text.charCodeAt(0)])
            {
                TempElements3.splice(0, 0, Element);
                bCloseBrk = true;
                FracCharCodes = true;
            }
            else if (g_MathLeftBracketAutoCorrectCharCodes[Element.Text.charCodeAt(0)])
            {
                if (!bCloseBrk)
                    return false;
                if (bOpenBrk)
                    break;
                TempElements3.splice(0, 0, Element);
                bOpenBrk = true;
            }
            else if  ('_' === Element.Text)
            {
                if ( this.Type == MATH_DEGREE && TempElements2.Type == DEGREE_SUBSCRIPT)
                    break;

                TempElements3.Type = DEGREE_SUBSCRIPT;
                //CurPos--;

                if (CurPos >= 1)
                {
                    var Elem = this.Elements[CurPos-1];
                    if (Elem.Type != para_Math_Composition && q_aMathAutoCorrectControlAggregationCodes[Elem.Text.charCodeAt(0)])
                    {
                        this.chr = Elem.Text;
                        this.Type = MATH_NARY;
                        CurPos--;
                        break;
                    }
                    else
                        break;
                }
            }
            else if  ('^' === Element.Text)
            {

                if ( this.Type == MATH_DEGREE && TempElements2.Type == DEGREE_SUPERSCRIPT)
                    break;
                TempElements3.Type = DEGREE_SUPERSCRIPT;
                CurPos--;

                if (CurPos > 0)
                {
                    var Elem = this.Elements[CurPos];
                    if (Elem.Type != para_Math_Composition && q_aMathAutoCorrectControlAggregationCodes[Elem.Text.charCodeAt(0)])
                    {
                        this.chr = Elem.Text;
                        this.Type = MATH_NARY;
                        CurPos--;
                        break;
                    }
                    else
                        break;
                }
            }
            else if ( ' ' == Element.Text)
            {
                if (FracCharCodes)
                    break;
                else
                    return false;
            }
            else if (g_aMathAutoCorrectTriggerCharCodes[Element.Text.charCodeAt(0)])
            {
                TempElements3.splice(0, 0, Element);
                FracCharCodes = true;
            }
            else
            {
                TempElements3.splice(0, 0, Element);
            }
            CurPos--;
        }
    }
    if (this.Type == MATH_FRACTION)
    {
        //todo для нуля вставить плейсхолдер
        if (TempElements2.length > 0)
        {
            var props = new CMathFractionPr();
            props.Set_FromObject(this.props);
            props.ctrPrp = AutoCorrectionEngine.TextPr.Copy();
            var Fraction = new CFraction(props);

            var DenMathContent = Fraction.Content[0];
            var NumMathContent = Fraction.Content[1];

            this.PackTextToContent(DenMathContent, TempElements2, AutoCorrectionEngine, true);
            this.PackTextToContent(NumMathContent, TempElements, AutoCorrectionEngine, true);

            AutoCorrectionEngine.RemoveCount = this.ElementsCount - CurPos - 1;
            if (0x20 == this.ActionElementCode)
                AutoCorrectionEngine.RemoveCount++;
            AutoCorrectionEngine.ReplaceContent.unshift(Fraction);

            return true;
        }
    }
    else if (this.Type == MATH_DEGREE)
    {
        var ReplaceElem = null;
        if (CanMakeAutoCorrect && AutoCorrectionEngine.ReplaceContent.length>0 && AutoCorrectionEngine.ReplaceContent[0].Content.length>0)
            ReplaceElem = AutoCorrectionEngine.ReplaceContent[0].Content[0].value;

        // + - ^ _
        if ( (CanMakeAutoCorrect && !g_aMathAutoCorrectFracCharCodes[ReplaceElem])  // x_i\times
            || !g_aMathAutoCorrectFracCharCodes[this.ActionElementCode])
            return false;
        else
        {

            var props = new CMathDegreePr();
            props.ctrPrp = AutoCorrectionEngine.TextPr.Copy();
            props.type = this.Kind;
            var oDegree = new CDegree(props)

            var BaseContent = oDegree.Content[0];
            var IterContent = oDegree.Content[1];

            this.PackTextToContent(BaseContent, TempElements2, AutoCorrectionEngine, false);
            this.PackTextToContent(IterContent, TempElements, AutoCorrectionEngine, true);

            AutoCorrectionEngine.RemoveCount += this.ElementsCount - CurPos - 1;
            if (0x20 == this.ActionElementCode)
                AutoCorrectionEngine.RemoveCount++;

            AutoCorrectionEngine.ReplaceContent.unshift(oDegree);

            return true;
        }
    }
    else if (this.Type == MATH_DEGREESubSup)
    {
        if ( 0x5E === this.ActionElementCode || 0x5F === this.ActionElementCode)
            return false;
        else if (TempElements2.length > 0 || TempElements3.length > 0)
        {
            if (TempElements3.length === 0)
                return false;
            else
            {
                var props = new CMathDegreePr();
                props.ctrPrp = AutoCorrectionEngine.TextPr.Copy();
                props.type = this.Kind;
                var oDegree = new CDegreeSubSup(props)

                var BaseContent = oDegree.Content[0];
                var IterDnContent = oDegree.Content[1];
                var IterUpContent = oDegree.Content[2];

                if (TempElements.Type == DEGREE_SUPERSCRIPT)
                {
                    this.PackTextToContent(IterUpContent, TempElements2, AutoCorrectionEngine, true);
                    this.PackTextToContent(IterDnContent, TempElements, AutoCorrectionEngine, true);
                }
                else if (TempElements.Type == DEGREE_SUBSCRIPT)
                {
                    this.PackTextToContent(IterUpContent, TempElements, AutoCorrectionEngine, true);
                    this.PackTextToContent(IterDnContent, TempElements2, AutoCorrectionEngine, true);
                }

                var BaseElems = [TempElements3[TempElements3.length-1]];
                this.PackTextToContent(BaseContent, BaseElems, AutoCorrectionEngine, true);

                AutoCorrectionEngine.RemoveCount += this.ElementsCount - CurPos - TempElements3.length;
                if (0x20 == this.ActionElementCode)
                    AutoCorrectionEngine.RemoveCount++;
                AutoCorrectionEngine.ReplaceContent.unshift(oDegree);

                return true;
            }
        }
    }
    else if (this.Type == MATH_RADICAL)
    {
        if (!g_aMathAutoCorrectFracCharCodes[this.ActionElementCode]) // \sqrt(a+b)^
            return false;

        var props = new CMathRadicalPr();
        if (TempElements2.length > 0)
            props.degHide = 0;
        else
            props.degHide = 1;
        props.ctrPrp = AutoCorrectionEngine.TextPr.Copy();
        var Radical = new CRadical(props);

        var Base = Radical.getBase();
        var Degree = Radical.getDegree();

        this.PackTextToContent(Base, TempElements, AutoCorrectionEngine, true);
        if (!props.degHide)
        {
            if (bOf)
                this.PackTextToContent(Degree, TempElements2, AutoCorrectionEngine, false);
            else
                this.PackTextToContent(Degree, TempElements2, AutoCorrectionEngine, true);
        }


        AutoCorrectionEngine.RemoveCount = this.ElementsCount - CurPos;
        if (0x20 == this.ActionElementCode)
            AutoCorrectionEngine.RemoveCount++;
        AutoCorrectionEngine.ReplaceContent.unshift(Radical);
        return true;
    }
    else if (this.Type == MATH_BORDER_BOX)
    {
        var props = {};
        props.ctrPrp = AutoCorrectionEngine.TextPr.Copy();
        var BorderBox = new CBorderBox(props);

        var Base = BorderBox.getBase();

        this.PackTextToContent(Base, TempElements, AutoCorrectionEngine, true);

        AutoCorrectionEngine.RemoveCount = this.ElementsCount - CurPos ;
        if (0x20 == this.ActionElementCode)
            AutoCorrectionEngine.RemoveCount++;
        AutoCorrectionEngine.ReplaceContent.unshift(BorderBox);
        return true;
    }
    else if (this.Type == MATH_BOX)
    {
        var props = {};
        props.ctrPrp = AutoCorrectionEngine.TextPr.Copy();
        var Box = new CBox(props);

        var Base = Box.getBase();

        this.PackTextToContent(Base, TempElements, AutoCorrectionEngine, true);

        AutoCorrectionEngine.RemoveCount += this.ElementsCount - CurPos;
        if (0x20 == this.ActionElementCode)
            AutoCorrectionEngine.RemoveCount++;
        AutoCorrectionEngine.ReplaceContent.unshift(Box);
        return true;
    }
    else if (this.Type == MATH_NARY)
    {
        if ( this.ActionElementCode == 0x005C) //slash
            return false;

        if (bOf && this.CanPackToDelimiter(TempElements))
        {
            this.BrAccount.nLPos = TempElementsPos[0];
            this.BrAccount.nRPos = TempElementsPos[TempElements.length - 1];
            this.AutoCorrectDelimiter (AutoCorrectionEngine, CanMakeAutoCorrect)
            return true;
        }

        var props = {};
        if (TempElements.Type == DEGREE_SUPERSCRIPT)
        {
            if (TempElements2.length == 0)
                props.subHide = true;
            if (TempElements.length == 0)
                props.supHide = true;
        }
        else if (TempElements.Type == DEGREE_SUBSCRIPT)
        {
            if (TempElements.length == 0)
                props.subHide = true;
            if (TempElements2.length == 0)
                props.supHide = true;
        }
        else
        {
            if (TempElements2.Type == DEGREE_SUPERSCRIPT)
            {
                if (TempElements2.length == 0)
                    props.supHide = true;
                if (TempElements3.length == 0)
                    props.subHide = true;
            }
            else
            {
                if (TempElements3.length == 0)
                    props.supHide = true;
                if (TempElements2.length == 0)
                    props.subHide = true;
            }
        }

        props.ctrPrp = AutoCorrectionEngine.TextPr.Copy();
        props.chr = this.chr.charCodeAt(0);
        var oNary = new CNary(props);

        var oSub = oNary.getLowerIterator();
        var oSup = oNary.getUpperIterator();
        var oBase = oNary.getBase();

        if (TempElements.Type == DEGREE_SUPERSCRIPT)
        {
            this.PackTextToContent(oSub, TempElements2, AutoCorrectionEngine, true);
            this.PackTextToContent(oSup, TempElements, AutoCorrectionEngine, true);
        }
        else if (TempElements.Type == DEGREE_SUBSCRIPT)
        {
            this.PackTextToContent(oSub, TempElements, AutoCorrectionEngine, true);
            this.PackTextToContent(oSup, TempElements2, AutoCorrectionEngine, true);
        }
        else
        {
            this.PackTextToContent(oBase, TempElements, AutoCorrectionEngine, true);
            if (TempElements2.Type == DEGREE_SUPERSCRIPT)
            {
                this.PackTextToContent(oSup, TempElements2, AutoCorrectionEngine, true);
                this.PackTextToContent(oSub, TempElements3, AutoCorrectionEngine, true);
            }
            else
            {
                this.PackTextToContent(oSup, TempElements3, AutoCorrectionEngine, true);
                this.PackTextToContent(oSub, TempElements2, AutoCorrectionEngine, true);
            }
        }

        AutoCorrectionEngine.RemoveCount += this.ElementsCount - CurPos ;
        if (0x20 == this.ActionElementCode)
            AutoCorrectionEngine.RemoveCount++;
        AutoCorrectionEngine.ReplaceContent.unshift(oNary);

        return true;
    }
    else if (this.Type == MATH_GROUP_CHARACTER)
    {
        var props = this.props;
        props.ctrPrp = AutoCorrectionEngine.TextPr.Copy();
        var oGroupChr = new CGroupCharacter(props);

        var oBase = oGroupChr.getBase();

        this.PackTextToContent(oBase, TempElements, AutoCorrectionEngine, true);

        AutoCorrectionEngine.RemoveCount += this.ElementsCount - CurPos ;
        if (0x20 == this.ActionElementCode && this.BrAccount.LBracket && this.BrAccount.RBracket && CurPos != 0)
            AutoCorrectionEngine.RemoveCount++;
        AutoCorrectionEngine.ReplaceContent.unshift(oGroupChr);
        return true;
    }
    else if (this.Type == MATH_BAR)
    {
        var props = this.props;
        props.ctrPrp = AutoCorrectionEngine.TextPr.Copy();
        var oBar = new CBar(props);

        var oBase = oBar.getBase();

        this.PackTextToContent(oBase, TempElements, AutoCorrectionEngine, true);

        AutoCorrectionEngine.RemoveCount += this.ElementsCount - CurPos ;
        if (0x20 == this.ActionElementCode)
            AutoCorrectionEngine.RemoveCount++;
        AutoCorrectionEngine.ReplaceContent.unshift(oBar);
        return true;
    }
    else if (this.Type == MATH_LIMIT)
    {
        var props = this.props;
        props.ctrPrp = AutoCorrectionEngine.TextPr.Copy();
        var oLimit = new CLimit(props);

        var oBase = oLimit.getFName();
        var oIter = oLimit.getIterator();

        this.PackTextToContent(oBase, TempElements2, AutoCorrectionEngine, true);
        this.PackTextToContent(oIter, TempElements, AutoCorrectionEngine, true);

        AutoCorrectionEngine.RemoveCount += this.ElementsCount - CurPos ;
        AutoCorrectionEngine.ReplaceContent.unshift(oLimit);
        return true;
    }
    else if (this.Type == MATH_PHANTOM)
    {
        var props = this.props;
        props.ctrPrp = AutoCorrectionEngine.TextPr.Copy();
        var oPhantom = new CPhantom(props);

        var oBase = oPhantom.getBase();

        this.PackTextToContent(oBase, TempElements, AutoCorrectionEngine, true);

        AutoCorrectionEngine.RemoveCount += this.ElementsCount - CurPos ;
        if (0x20 == this.ActionElementCode)
            AutoCorrectionEngine.RemoveCount++;
        AutoCorrectionEngine.ReplaceContent.unshift(oPhantom);
        return true;
    }
    else if (this.Type == MATH_DELIMITER)
    {
        this.AutoCorrectDelimiter(AutoCorrectionEngine, CanMakeAutoCorrect);
        return true;
    }

    return false;
};
AutoCorrectionControl.prototype.CanPackToDelimiter = function(TempElements)
{
    var len = TempElements.length;

    if (len < 2)
        return false;
    if( TempElements[0].Type != para_Math_Composition && TempElements[0].Text === '(' && TempElements[len-1].Type != para_Math_Composition && TempElements[len-1].Text === ')')
        return true;

    return false;
};
CMathContent.prototype.ReplaceAutoCorrect = function(AutoCorrectEngine, bCursorStepRight)
{
    var ElementsCount = AutoCorrectEngine.Elements.length;
    var LastElement = null;

    var FirstElement    = AutoCorrectEngine.Elements[ElementsCount - 1];
    var FirstElementPos = FirstElement.ElementPos;
    FirstElement.Pos++;
    for (var nPos = 0, nCount = AutoCorrectEngine.RemoveCount; nPos < nCount; nPos++)
    {
        LastElement = AutoCorrectEngine.Elements[ElementsCount - nPos - 1];

        if (undefined !== LastElement.Run)
        {
            if (FirstElement.Run === LastElement.Run)
                FirstElement.Pos--;

            LastElement.Run.Remove_FromContent(LastElement.Pos, 1);
        }
        else
        {
            this.Remove_FromContent(LastElement.ElementPos, 1);
            FirstElementPos--;
        }
    }

    var NewRun = FirstElement.Run.Split2(FirstElement.Pos);

    this.Internal_Content_Add(FirstElementPos + 1, NewRun, false);

    var NewElementsCount = AutoCorrectEngine.ReplaceContent.length;
    for (var nPos = 0; nPos < NewElementsCount; nPos++)
    {
        this.Internal_Content_Add(nPos + FirstElementPos + 1, AutoCorrectEngine.ReplaceContent[nPos], false);
    }

    this.CurPos = FirstElementPos + NewElementsCount + 1;
    this.Content[this.CurPos].MoveCursorToStartPos();

    if (true === bCursorStepRight)
    {
        // TODO: Переделать через функцию в ране
        if (this.Content[this.CurPos].Content.length >= 1)
            this.Content[this.CurPos].State.ContentPos = 1;
    }
};

CMathContent.prototype.GetTextContent = function(bSelectedText)
{
	//TODO временная функция. пересмотреть!
	var arr = [], str = "", bIsContainsOperator = false, paraRunArr = [];

	var addText = function(value, bIsAddParenthesis, paraRun)
	{
		if(bIsAddParenthesis && value.length > 1 && value.match())
		{
			arr.push("(");
			str += "(";
			paraRunArr.push("(");
		}

		arr.push(value);
		str += value;
		if(undefined === paraRun)
		{
			paraRunArr.push(value);
		}
		else
		{
			paraRunArr.push(paraRun);
		}


		if(bIsAddParenthesis && value.length > 1)
		{
			arr.push(")");
			str += ")";
			paraRunArr.push(")");
		}

	};

	var getMathSymbol = function(elem)
	{
		var res = [];

		var getVal = function(val, position)
		{
			var newVal = {};
			newVal.prePosition = !!position;
			newVal.value = undefined !== val ? val : "";
			return newVal;
		};

		if(elem instanceof CDegree)
		{
			if(DEGREE_SUPERSCRIPT === elem.Pr.type)
			{
				//res.push(getVal("^"));
				res.push(getVal(String.fromCharCode(94)));
			}
			else
			{
				//res.push(getVal("_"));
				res.push(getVal(String.fromCharCode(95)));
			}
		}
		else if(elem instanceof CDelimiter)
		{
			res.push(getVal("(", true));
			res.push(getVal(")"));
		}
		else if(elem instanceof CNary)
		{
			res.push(getVal(String.fromCharCode(elem.Pr.chr), true));
			if(!elem.Pr.supHide)
			{
				res.push(getVal(String.fromCharCode(95), true));
				//res.push(getVal("_", true));
			}
			else
			{
				res.push(null);
			}
			if(!elem.Pr.subHide)
			{
				res.push(getVal(String.fromCharCode(94), true));
				//res.push(getVal("^", true));//94
			}
			else
			{
				res.push(null);
			}
			res.push(getVal(String.fromCharCode(9618), true));
			//res.push(getVal("▒", true));//9618
		}
		else if(elem instanceof CFraction)
		{
			res.push(getVal("/"));
		}
		else if(elem instanceof CRadical)
		{
			//res.push(getVal("√", true));
			res.push(getVal(String.fromCharCode(8730), true));
			//res.push(getVal("&", true));
			res.push(getVal(String.fromCharCode(38), true));
		}
		else if(elem instanceof CMathMatrix)
		{
			//res[-1] = getVal("■", true);//9632
			res[-1] = getVal(String.fromCharCode(9632), true);

			for(var row = 0; row < elem.nRow; row++)
			{
				for(var col = 1; col < elem.nCol; col++)
				{
					res.push(getVal(String.fromCharCode(38)));
					//res.push(getVal("&"));
				}
				if(row !== elem.nRow - 1)
				{
					res.push(getVal(String.fromCharCode(64)));
					//res.push(getVal("@"));
				}
			}
		}
		else if(elem instanceof CMathFunc)
		{
			//res.push(getVal("#"));//8289
			res.push(getVal(String.fromCharCode(8289)));
		}

		return res;
	};

	var getAndPushTextContent = function(elem)
	{
		var tempStr = elem.GetTextContent(bSelectedText);
		if(tempStr.str)
		{
			addText(tempStr.str, tempStr.bIsContainsOperator, tempStr.paraRunArr);
		}
	};

	var parseMathComposition = function(elem)
	{
		var tempStr;
		var symbol = getMathSymbol(elem);

		if(elem instanceof CDegree)//степень
		{
			//основание
			getAndPushTextContent(elem.Content[0]);

			addText(symbol[0].value);

			//показатель
			getAndPushTextContent(elem.Content[1]);
		}
		else if(elem instanceof CDelimiter)
		{
			getAndPushTextContent(elem.Content[0]);
		}
		else if(elem instanceof CNary)//сумма
		{
			addText(symbol[0].value);

			//нижняя граница суммирования
			if(null !== symbol[1])
			{
				addText(symbol[1].value);

				getAndPushTextContent(elem.Content[0]);
			}

			//верхняя граница суммирования
			if(null !== symbol[2])
			{
				addText(symbol[2].value);

				getAndPushTextContent(elem.Content[1]);
			}

			addText(symbol[3].value);

			getAndPushTextContent(elem.Content[2]);
		}
		else if(elem instanceof CFraction)//дробь
		{
			//числитель
			getAndPushTextContent(elem.Content[0]);

			addText(symbol[0].value);

			//знаменатель
			getAndPushTextContent(elem.Content[1]);
		}
		else if(elem instanceof CRadical)//корень
		{
			addText(symbol[0].value);
			//степень корня
			tempStr = elem.Content[0].GetTextContent(bSelectedText);
			var isAddExp = false;
			if(tempStr.str)
			{
				addText("(");
				addText(tempStr.str, tempStr.bIsContainsOperator, tempStr.paraRunArr);
				isAddExp = true;
			}

			if(tempStr.str)
			{
				addText(symbol[1].value);
			}

			//подкоренное выражение
			getAndPushTextContent(elem.Content[1]);

			if(isAddExp)
			{
				addText(")");
			}
		}
		else if(elem instanceof CMathMatrix)
		{
			addText(symbol[-1].value);
			addText("(");
			for(var j = 0; j < elem.Content.length; j++)
			{
				if(para_Math_Content === elem.Content[j].Type)
				{
					if(symbol[j] && symbol[j].prePosition)
					{
						addText(symbol[j].value);
					}

					getAndPushTextContent(elem.Content[j]);

					if(symbol[j] && !symbol[j].prePosition)
					{
						addText(symbol[j].value);
					}
				}
			}
			addText(")");
		}
		else if(elem instanceof CMathFunc)
		{
			//функция
			getAndPushTextContent(elem.Content[0]);

			addText(symbol[0].value);

			//аргумент
			getAndPushTextContent(elem.Content[1]);
		}
		else if(elem instanceof CLimit)
		{
			//функция
			getAndPushTextContent(elem.Content[0]);
			//аргумент
			getAndPushTextContent(elem.Content[1]);
		}

	};

	var StartPos = 0, EndPos = this.Content.length;
	if(bSelectedText)
	{
		StartPos = ( true == this.Selection.Use ? Math.min(this.Selection.StartPos, this.Selection.EndPos) : this.CurPos.ContentPos );
		EndPos   = ( true == this.Selection.Use ? Math.max(this.Selection.StartPos, this.Selection.EndPos) : this.CurPos.ContentPos );
	}


	for(var i = StartPos; i <= EndPos; i++)
	{
		if(!this.Content[i])
		{
			continue;
		}

		switch(this.Content[i].Type)
		{
			case para_Math_Run:
			{
				if(this.Content[i].Content.length)
				{
					var StartContentPos = 0, EndContentPos = this.Content[i].Content.length;
					if(bSelectedText)
					{
						StartContentPos = ( true == this.Content[i].Selection.Use ? Math.min(this.Content[i].Selection.StartPos, this.Content[i].Selection.EndPos) : this.Content[i].CurPos.ContentPos );
						EndContentPos   = ( true == this.Content[i].Selection.Use ? Math.max(this.Content[i].Selection.StartPos, this.Content[i].Selection.EndPos) : this.Content[i].CurPos.ContentPos );
					}

					var string = "";
					for(var j = StartContentPos; j <= EndContentPos; j++)
					{
						if(!this.Content[i].Content[j])
						{
							continue;
						}

						if(para_Math_Text === this.Content[i].Content[j].Type)
						{
							string += String.fromCharCode(this.Content[i].Content[j].value);
						}
						else if(para_Math_BreakOperator === this.Content[i].Content[j].Type)
						{
							string += String.fromCharCode(this.Content[i].Content[j].value);
							bIsContainsOperator = true;
						}
					}
					addText(string, null, this.Content[i]);
				}
				break;
			}
			case para_Math_Composition:
			{
				parseMathComposition(this.Content[i]);
				break;
			}
		}
	}

	return {str: str, bIsContainsOperator: bIsContainsOperator, paraRunArr: paraRunArr};
};

function CMathBracketAcc()
{
    this.LBracket     = null;
    this.RBracket     = null;
    this.LBracketlvl1 = null;
    this.RBracketlvl1 = null;
    this.LBracketlvl2 = null;
    this.RBracketlvl2 = null;
    this.bSeparator   = false;
    this.nSepPos      = -1;
    this.nCounter     = 0;
    this.nLPos        = -1;
    this.nLLPos       = -1;
    this.nRPos        = -1;
    this.nRRPos       = -1;
    this.Elems        = [];
    this.SepArr       = [];
}
CMathBracketAcc.prototype.Counted             = function()
{
    var len = this.Elems.length;
    for (var i = 0; i < len; i++)
    {
        var oElem = this.Elems[i];

    }
};
CMathBracketAcc.prototype.CorrectLeft         = function(Element, nNum, nCode)
{
    this.nCounter--;
    if (this.nLPos > nNum)
    {
        this.nLLPos = nNum;
        if (this.nRPos < 0)
        {
            this.nLPos    = nNum;
            this.LBracket = nCode;
            if (nCode === 0x0028 || nCode === 0x3016 || nCode === 0x251C)
                this.LBracketlvl1 = nCode;
            else
                this.LBracketlvl2 = nCode;
        }
    }
    else
    {
        this.nLPos    = nNum;
        this.LBracket = nCode;
        if (nCode === 0x0028 || nCode === 0x3016 || nCode === 0x251C)
            this.LBracketlvl1 = nCode;
        else
            this.LBracketlvl2 = nCode;
    }
};
CMathBracketAcc.prototype.CorrectLeftSeparate = function(Element, nNum, nCode)
{
    this.SepArr.unshift(this.nLPos);

    this.nLPos    = nNum;
    this.LBracket = nCode;
    if (nCode === 0x0028 || nCode === 0x3016 || nCode === 0x251C)
        this.LBracketlvl1 = nCode;
    else
        this.LBracketlvl2 = nCode;
};
CMathBracketAcc.prototype.CorrectRight        = function(Element, nNum, nCode)
{
    this.nCounter++;
    if (nNum > this.nRPos)
    {
        this.nRRPos = nNum;
        if (this.nRPos < 0)
        {
            this.nRPos    = nNum;
            this.RBracket = nCode;
            if (nCode === 0x0029 || nCode === 0x2524 || nCode === 0x3017)
                this.LBracketlvl1 = nCode;
            else
                this.LBracketlvl2 = nCode;
        }
    }
    else
    {
        this.nRPos    = nNum;
        this.RBracket = nCode;
        if (nCode === 0x0029 || nCode === 0x2524 || nCode === 0x3017)
            this.LBracketlvl1 = nCode;
        else
            this.LBracketlvl2 = nCode;
    }
};
CMathBracketAcc.prototype.Comparelvl1         = function()
{
    var bRes = false;
    if ((this.LBracket == 0x0028 && this.RBracket == 0x0029) ||
        (this.LBracket == 0x3016 && this.RBracket == 0x3017) ||
        (this.LBracket == 0x251C && this.RBracket == 0x2524))
        bRes = true;
    return bRes;
};
CMathBracketAcc.prototype.Compare             = function()
{
    var bRes = false;
    if ((this.LBracket == 0x0028 && this.RBracket == 0x0029) ||
        (this.LBracket == 0x005B && this.RBracket == 0x005D) ||
        (this.LBracket == 0x007B && this.RBracket == 0x007D) ||
        (this.LBracket == 0x007C && this.RBracket == 0x007C) ||
        (this.LBracket == 0x2016 && this.RBracket == 0x2016) ||
        (this.LBracket == 0x27E8 && this.RBracket == 0x232A) ||
        (this.LBracket == 0x27E8 && this.RBracket == 0x27EB) ||
        (this.LBracket == 0x27E6 && this.RBracket == 0x27E7) ||
        (this.LBracket == 0x2308 && this.RBracket == 0x2309) ||
        (this.LBracket == 0x230A && this.RBracket == 0x230B) ||
        (this.LBracket == 0x3016 && this.RBracket == 0x3017) ||
        (this.LBracket == 0x251C && this.RBracket == 0x2524))
        bRes = true;
    return bRes;
};


function CMathAutoCorrectEngine(Element)
{
    this.ActionElement  = Element; // Элемент на которотом срабатывает автодополнение
    this.Elements       = [];

    this.CollectText    = true;
    this.Type			= null;
    this.Kind			= null;
    this.Delimiter		= null;

    this.RemoveCount    = 0;
    this.ReplaceContent = [];
    this.Shift 			= 0;

    this.TextPr         = null;
    this.MathPr         = null;
}

CMathAutoCorrectEngine.prototype.Add_Element = function(Element, ElementPos)
{
    this.Elements.push({Element : Element, ElementPos : ElementPos, Type:Element.Type});
};

CMathAutoCorrectEngine.prototype.Add_Text = function(Text, Run, Pos, ElementPos, Type)
{
    this.Elements.push({Text : Text, Run : Run, Pos : Pos, ElementPos : ElementPos, Type : Type});
};

CMathAutoCorrectEngine.prototype.Get_ActionElement = function()
{
    return this.ActionElement;
};

CMathAutoCorrectEngine.prototype.Stop_CollectText = function()
{
    this.CollectText = false;
};

var g_aAutoCorrectMathFuncSymbols =
[
    'sin', 'sec', 'asin', 'asec', 'arcsin', 'arcsec',
    'cos', 'csc', 'acos', 'acsc', 'arccos', 'arccsc',
    'tan', 'cot', 'atan', 'acot', 'arctan', 'arccot',
    'sinh', 'sech', 'asinh', 'asech', 'arcsinh', 'arcech',
    'cosh', 'csch', 'acosh', 'acsch', 'arccosh', 'arccsch',
    'tanh', 'coth', 'atanh', 'acoth', 'arctanh', 'arccoth',
    'arg', 'det', 'exp', 'inf', 'lim', 'min',
    'def', 'dim', 'gcd', 'ker', 'log', 'Pr',
    'deg', 'erf', 'hom', 'lg', 'ln', 'max', 'sup'
];
var g_aAutoCorrectMathSymbols =
[
    ['!!', 0x203C],
    ['...', 0x2026],
    ['::', 0x2237],
    [':=', 0x2254],
    ['\\above', 0x2534],
    ['\\acute', 0x0301],
    ['\\aleph', 0x2135],
    ['\\alpha', 0x03B1],
    ['\\Alpha', 0x0391],
    ['\\amalg', 0x2210],
    ['\\angle', 0x2220],
    ['\\aoint', 0x2233],
    ['\\approx', 0x2248],
    ['\\asmash', 0x2B06],
    ['\\ast', 0x2217],
    ['\\asymp', 0x224D],
    ['\\atop', 0x00A6],
    ['\\bar', 0x0305],
    ['\\Bar', 0x033F],
    ['\\because', 0x2235],
    ['\\begin', 0x3016],
    ['\\below', 0x252C],
    ['\\bet', 0x2136],
    ['\\beta', 0x03B2],
    ['\\Beta', 0x0392],
    ['\\beth', 0x2136],
    ['\\bigcap', 0x22C2],
    ['\\bigcup', 0x22C3],
    ['\\bigodot', 0x2A00],
    ['\\bigoplus', 0x2A01],
    ['\\bigotimes', 0x2A02],
    ['\\bigsqcup', 0x2A06],
    ['\\biguplus', 0x2A04],
    ['\\bigvee', 0x22C1],
    ['\\bigwedge', 0x22C0],
    ['\\bot', 0x22A5],
    ['\\bowtie', 0x22C8],
    ['\\box', 0x25A1],
    ['\\bra', 0x27E8],
    ['\\breve', 0x0306],
    ['\\bullet', 0x2219],
    ['\\cap', 0x2229],
    ['\\cbrt', 0x221B],
    ['\\cases', 0x24B8],
    ['\\cdot', 0x22C5],
    ['\\cdots', 0x22EF],
    ['\\check', 0x030C],
    ['\\chi', 0x03C7],
    ['\\Chi', 0x03A7],
    ['\\circ', 0x2218],
    ['\\close', 0x2524],
    ['\\clubsuit', 0x2663],
    ['\\coint', 0x2232],
    ['\\cong', 0x2245],
    ['\\coprod', 0x2210],
    ['\\cup', 0x222A],
    ['\\dalet', 0x2138],
    ['\\daleth', 0x2138],
    ['\\dashv', 0x22A3],
    ['\\dd', 0x2146],
    ['\\Dd', 0x2145],
    ['\\ddddot', 0x20DC],
    ['\\dddot', 0x20DB],
    ['\\ddot', 0x0308],
    ['\\ddots', 0x22F1],
    ['\\degree', 0x00B0],
    ['\\delta', 0x03B4],
    ['\\Delta', 0x0394],
    ['\\diamond', 0x22C4],
    ['\\diamondsuit', 0x2662],
    ['\\div', 0x00F7],
    ['\\dot', 0x0307],
    ['\\doteq', 0x2250],
    ['\\dots', 0x2026],
    ['\\doublea', 0x1D552],
    ['\\doubleA', 0x1D538],
    ['\\doubleb', 0x1D553],
    ['\\doubleB', 0x1D539],
    ['\\doublec', 0x1D554],
    ['\\doubleC', 0x2102],
    ['\\doubled', 0x1D555],
    ['\\doubleD', 0x1D53B],
    ['\\doublee', 0x1D556],
    ['\\doubleE', 0x1D53C],
    ['\\doublef', 0x1D557],
    ['\\doubleF', 0x1D53D],
    ['\\doubleg', 0x1D558],
    ['\\doubleG', 0x1D53E],
    ['\\doubleh', 0x1D559],
    ['\\doubleH', 0x210D],
    ['\\doublei', 0x1D55A],
    ['\\doubleI', 0x1D540],
    ['\\doublej', 0x1D55B],
    ['\\doubleJ', 0x1D541],
    ['\\doublek', 0x1D55C],
    ['\\doubleK', 0x1D542],
    ['\\doublel', 0x1D55D],
    ['\\doubleL', 0x1D543],
    ['\\doublem', 0x1D55E],
    ['\\doubleM', 0x1D544],
    ['\\doublen', 0x1D55F],
    ['\\doubleN', 0x2115],
    ['\\doubleo', 0x1D560],
    ['\\doubleO', 0x1D546],
    ['\\doublep', 0x1D561],
    ['\\doubleP', 0x2119],
    ['\\doubleq', 0x1D562],
    ['\\doubleQ', 0x211A],
    ['\\doubler', 0x1D563],
    ['\\doubleR', 0x211D],
    ['\\doubles', 0x1D564],
    ['\\doubleS', 0x1D54A],
    ['\\doublet', 0x1D565],
    ['\\doubleT', 0x1D54B],
    ['\\doubleu', 0x1D566],
    ['\\doubleU', 0x1D54C],
    ['\\doublev', 0x1D567],
    ['\\doubleV', 0x1D54D],
    ['\\doublew', 0x1D568],
    ['\\doubleW', 0x1D54E],
    ['\\doublex', 0x1D569],
    ['\\doubleX', 0x1D54F],
    ['\\doubley', 0x1D56A],
    ['\\doubleY', 0x1D550],
    ['\\doublez', 0x1D56B],
    ['\\doubleZ', 0x2124],
    ['\\downarrow', 0x2193],
    ['\\Downarrow', 0x21D3],
    ['\\dsmash', 0x2B07],
    ['\\ee', 0x2147],
    ['\\ell', 0x2113],
    ['\\emptyset', 0x2205],
    ['\\end', 0x3017],
    ['\\ensp', 0x2002],
    ['\\epsilon', 0x03F5],
    ['\\Epsilon', 0x0395],
    ['\\eqarray', 0x2588],
    ['\\equiv', 0x2261],
    ['\\eta', 0x03B7],
    ['\\Eta', 0x0397],
    ['\\exists', 0x2203],
    ['\\forall', 0x2200],
    ['\\fraktura', 0x1D51E],
    ['\\frakturA', 0x1D504],
    ['\\frakturb', 0x1D51F],
    ['\\frakturB', 0x1D505],
    ['\\frakturc', 0x1D520],
    ['\\frakturC', 0x212D],
    ['\\frakturd', 0x1D521],
    ['\\frakturD', 0x1D507],
    ['\\frakture', 0x1D522],
    ['\\frakturE', 0x1D508],
    ['\\frakturf', 0x1D523],
    ['\\frakturF', 0x1D509],
    ['\\frakturg', 0x1D524],
    ['\\frakturG', 0x1D50A],
    ['\\frakturh', 0x1D525],
    ['\\frakturH', 0x210C],
    ['\\frakturi', 0x1D526],
    ['\\frakturI', 0x2111],
    ['\\frakturj', 0x1D527],
    ['\\frakturJ', 0x1D50D],
    ['\\frakturk', 0x1D528],
    ['\\frakturK', 0x1D50E],
    ['\\frakturl', 0x1D529],
    ['\\frakturL', 0x1D50F],
    ['\\frakturm', 0x1D52A],
    ['\\frakturM', 0x1D510],
    ['\\frakturn', 0x1D52B],
    ['\\frakturN', 0x1D511],
    ['\\frakturo', 0x1D52C],
    ['\\frakturO', 0x1D512],
    ['\\frakturp', 0x1D52D],
    ['\\frakturP', 0x1D513],
    ['\\frakturq', 0x1D52E],
    ['\\frakturQ', 0x1D514],
    ['\\frakturr', 0x1D52F],
    ['\\frakturR', 0x211C],
    ['\\frakturs', 0x1D530],
    ['\\frakturS', 0x1D516],
    ['\\frakturt', 0x1D531],
    ['\\frakturT', 0x1D517],
    ['\\frakturu', 0x1D532],
    ['\\frakturU', 0x1D518],
    ['\\frakturv', 0x1D533],
    ['\\frakturV', 0x1D519],
    ['\\frakturw', 0x1D534],
    ['\\frakturW', 0x1D51A],
    ['\\frakturx', 0x1D535],
    ['\\frakturX', 0x1D51B],
    ['\\fraktury', 0x1D536],
    ['\\frakturY', 0x1D51C],
    ['\\frakturz', 0x1D537],
    ['\\frakturZ', 0x2128],
    ['\\funcapply', 0x2061],
    ['\\gamma', 0x03B3],
    ['\\Gamma', 0x0393],
    ['\\ge', 0x2265],
    ['\\geq', 0x2265],
    ['\\gets', 0x2190],
    ['\\gg', 0x226B],
    ['\\gimel', 0x2137],
    ['\\grave', 0x0300],
    ['\\hairsp', 0x200A],
    ['\\hat', 0x0302],
    ['\\hbar', 0x210F],
    ['\\heartsuit', 0x2661],
    ['\\hookleftarrow', 0x21A9],
    ['\\hookrightarrow', 0x21AA],
    ['\\hphantom', 0x2B04],
    ['\\hvec', 0x20D1],
    ['\\ii', 0x2148],
    ['\\iiint', 0x222D],
    ['\\iint', 0x222C],
    ['\\iiiint', 0x2A0C],
    ['\\Im', 0x2111],
    ['\\in', 0x2208],
    ['\\inc', 0x2206],
    ['\\infty', 0x221E],
    ['\\int', 0x222B],
    ['\\iota', 0x03B9],
    ['\\Iota', 0x0399],
    ['\\jj', 0x2149],
    ['\\kappa', 0x03BA],
    ['\\Kappa', 0x039A],
    ['\\ket', 0x27E9],
    ['\\lambda', 0x03BB],
    ['\\Lambda', 0x039B],
    ['\\langle', 0x2329],
    ['\\\lbbrack', 0x27E6],
    ['\\lbrace', 0x007B],
    ['\\lbrack', 0x005B],
    ['\\lceil', 0x2308],
    ['\\ldiv', 0x2215],
    ['\\ldivide', 0x2215],
    ['\\ldots', 0x2026],
    ['\\le', 0x2264],
    ['\\left', 0x251C],
    ['\\leftarrow', 0x2190],
    ['\\Leftarrow', 0x21D0],
    ['\\leftharpoondown', 0x21BD],
    ['\\leftharpoonup', 0x21BC],
    ['\\leftrightarrow', 0x2194],
    ['\\Leftrightarrow', 0x21D4],
    ['\\leq', 0x2264],
    ['\\lvec', 0x20D0],
    ['\\lfloor', 0x230A],
    ['\\ll', 0x226A],
    ['\\lvec', 0x20D6],
    ['\\mapsto', 0x21A6],
    ['\\matrix', 0x25A0],
    ['\\medsp', 0x205F],
    ['\\mid', 0x2223],
    ['\\models', 0x22A8],
    ['\\mp', 0x2213],
    ['\\mu', 0x03BC],
    ['\\Mu', 0x039C],
    ['\\nabla', 0x2207],
    ['\\naryand', 0x2592],
    ['\\nbsp', 0x00A0],
    ['\\ne', 0x2260],
    ['\\nearrow', 0x2197],
    ['\\neq', 0x2260],
    ['\\ni', 0x220B],
    ['\\norm', 0x2016],
    ['\\notcontain', 0x220C],
    ['\\notelement', 0x2209],
    ['\\nu', 0x03BD],
    ['\\Nu', 0x039D],
    ['\\nwarrow', 0x2196],
    ['\\o', 0x03BF],
    ['\\O', 0x039F],
    ['\\odot', 0x2299],
    ['\\of', 0x2592],
    ['\\oiiint', 0x2230],
    ['\\oiint', 0x222F],
    ['\\oint', 0x222E],
    ['\\omega', 0x03C9],
    ['\\Omega', 0x03A9],
    ['\\ominus', 0x2296],
    ['\\open', 0x251C],
    ['\\oplus', 0x2295],
    ['\\otimes', 0x2297],
    ['\\over', 0x002F],
    ['\\overbar', 0x00AF],
    ['\\overbrace', 0x23DE],
    ['\\overline', 0x00AF],
    ['\\overparen', 0x23DC],
    ['\\overshell', 0x23E0],
    ['\\parallel', 0x2225],
    ['\\partial', 0x2202],
    ['\\pmatrix', 0x24A8],
    ['\\phantom', 0x27E1],
    ['\\phi', 0x03D5],
    ['\\Phi', 0x03A6],
    ['\\pi', 0x03C0],
    ['\\Pi', 0x03A0],
    ['\\pm', 0x00B1],
    ['\\pppprime', 0x2057],
    ['\\ppprime', 0x2034],
    ['\\pprime', 0x2033],
    ['\\prec', 0x227A],
    ['\\preceq', 0x227C],
    ['\\prime', 0x2032],
    ['\\prod', 0x220F],
    ['\\propto', 0x221D],
    ['\\psi', 0x03C8],
    ['\\Psi', 0x03A8],
    ['\\qdrt', 0x221C],
    ['\\quadratic', [0x0078, 0x003d, 0x0028, 0x002d, 0x0062, 0x00B1, 0x221A, 0x0020, 0x0028, 0x0062, 0x005e, 0x0032, 0x002d, 0x0034, 0x0061, 0x0063, 0x0029, 0x0029, 0x002f, 0x0032, 0x0061]],
    ['\\rangle', 0x232A],
    ['\\Rangle', 0x27EB],
    ['\\ratio', 0x2236],
    ['\\rbrace', 0x007D],
    ['\\rbrack', 0x005D],
    ['\\Rbrack', 0x27E7],
    ['\\rceil', 0x2309],
    ['\\rddots', 0x22F0],
    ['\\Re', 0x211C],
    ['\\rect', 0x25AD],
    ['\\rfloor', 0x230B],
    ['\\rho', 0x03C1],
    ['\\Rho', 0x03A1],
    ['\\rhvec', 0x20D1],
    ['\\right', 0x2524],
    ['\\rightarrow', 0x2192],
    ['\\Rightarrow', 0x21D2],
    ['\\rightharpoondown', 0x21C1],
    ['\\rightharpoonup', 0x21C0],
    ['\\root', 0x24AD],
    ['\\scripta', 0x1D4B6],
    ['\\scriptA', 0x1D49C],
    ['\\scriptb', 0x1D4B7],
    ['\\scriptB', 0x212C],
    ['\\scriptc', 0x1D4B8],
    ['\\scriptC', 0x1D49E],
    ['\\scriptd', 0x1D4B9],
    ['\\scriptD', 0x1D49F],
    ['\\scripte', 0x212F],
    ['\\scriptE', 0x2130],
    ['\\scriptf', 0x1D4BB],
    ['\\scriptF', 0x2131],
    ['\\scriptg', 0x210A],
    ['\\scriptG', 0x1D4A2],
    ['\\scripth', 0x1D4BD],
    ['\\scriptH', 0x210B],
    ['\\scripti', 0x1D4BE],
    ['\\scriptI', 0x2110],
    ['\\scriptj', 0x1D4BF],
    ['\\scriptJ', 0x1D4A5],
    ['\\scriptk', 0x1D4C0],
    ['\\scriptK', 0x1D4A6],
    ['\\scriptl', 0x2113],
    ['\\scriptL', 0x2112],
    ['\\scriptm', 0x1D4C2],
    ['\\scriptM', 0x2133],
    ['\\scriptn', 0x1D4C3],
    ['\\scriptN', 0x1D4A9],
    ['\\scripto', 0x2134],
    ['\\scriptO', 0x1D4AA],
    ['\\scriptp', 0x1D4C5],
    ['\\scriptP', 0x1D4AB],
    ['\\scriptq', 0x1D4C6],
    ['\\scriptQ', 0x1D4AC],
    ['\\scriptr', 0x1D4C7],
    ['\\scriptR', 0x211B],
    ['\\scripts', 0x1D4C8],
    ['\\scriptS', 0x1D4AE],
    ['\\scriptt', 0x1D4C9],
    ['\\scriptT', 0x1D4AF],
    ['\\scriptu', 0x1D4CA],
    ['\\scriptU', 0x1D4B0],
    ['\\scriptv', 0x1D4CB],
    ['\\scriptV', 0x1D4B1],
    ['\\scriptw', 0x1D4CC],
    ['\\scriptW', 0x1D4B2],
    ['\\scriptx', 0x1D4CD],
    ['\\scriptX', 0x1D4B3],
    ['\\scripty', 0x1D4CE],
    ['\\scriptY', 0x1D4B4],
    ['\\scriptz', 0x1D4CF],
    ['\\scriptZ', 0x1D4B5],
    ['\\sdiv', 0x2044],
    ['\\sdivide', 0x2044],
    ['\\searrow', 0x2198],
    ['\\setminus', 0x2216],
    ['\\sigma', 0x03C3],
    ['\\Sigma', 0x03A3],
    ['\\sim', 0x223C],
    ['\\simeq', 0x2243],
    ['\\smash', 0x2B0D],
    ['\\spadesuit', 0x2660],
    ['\\sqcap', 0x2293],
    ['\\sqcup', 0x2294],
    ['\\sqrt', 0x221A],
    ['\\sqsubseteq', 0x2291],
    ['\\sqsuperseteq', 0x2292],
    ['\\star', 0x22C6],
    ['\\subset', 0x2282],
    ['\\subseteq', 0x2286],
    ['\\succ', 0x227B],
    ['\\succeq', 0x227D],
    ['\\sum', 0x2211],
    ['\\superset', 0x2283],
    ['\\superseteq', 0x2287],
    ['\\swarrow', 0x2199],
    ['\\tau', 0x03C4],
    ['\\Tau', 0x03A4],
    ['\\therefore', 0x2234],
    ['\\theta', 0x03B8],
    ['\\Theta', 0x0398],
    ['\\thicksp', 0x2005],
    ['\\thinsp', 0x2006],
    ['\\tilde', 0x0303],
    ['\\times', 0x00D7],
    ['\\to', 0x2192],
    ['\\top', 0x22A4],
    ['\\tvec', 0x20E1],
    ['\\ubar', 0x0332],
    ['\\Ubar', 0x0333],
    ['\\underbar', 0x2581],
    ['\\underbrace', 0x23DF],
    ['\\underparen', 0x23DD],
    ['\\uparrow', 0x2191],
    ['\\Uparrow', 0x21D1],
    ['\\updownarrow', 0x2195],
    ['\\Updownarrow', 0x21D5],
    ['\\uplus', 0x228E],
    ['\\upsilon', 0x03C5],
    ['\\Upsilon', 0x03A5],
    ['\\varepsilon', 0x03B5],
    ['\\varphi', 0x03C6],
    ['\\varpi', 0x03D6],
    ['\\varrho', 0x03F1],
    ['\\varsigma', 0x03C2],
    ['\\vartheta', 0x03D1],
    ['\\vbar', 0x2502],
    ['\\vdash', 0x22A2],
    ['\\vdots', 0x22EE],
    ['\\vec', 0x20D7],
    ['\\vee', 0x2228],
    ['\\vert', 0x007C],
    ['\\Vert', 0x2016],
    ['\\Vmatrix', 0x24A9],
    ['\\vphantom', 0x21F3],
    ['\\vthicksp', 0x2004],
    ['\\wedge', 0x2227],
    ['\\wp', 0x2118],
    ['\\wr', 0x2240],
    ['\\xi', 0x03BE],
    ['\\Xi', 0x039E],
    ['\\zeta', 0x03B6],
    ['\\Zeta', 0x0396],
    ['\\zwnj', 0x200C],
    ['\\zwsp', 0x200B],
    ['~=', 0x2245],
    ['-+', 0x2213],
    ['+-', 0x00B1],
    ['<<', 0x226A],
    ['<=', 0x2264],
    ['->', 0x2192],
    ['>=', 0x2265],
    ['>>', 0x226B]
];
//символы начала формулы (корень, матрица...)
var q_aMathAutoCorrectControlCharCodes =
{
    0x221A : 1, 0x221B : 1, 0x221C : 1, 0x25AD : 1, 0x25A1 : 1, 0x23DC : 1,
    0x23E0 : 1, 0x23DD : 1, 0x00AF : 1, 0x033F : 1, 0x2581 : 1, 0x222E : 1,
    0x23DF : 1, 0x23DE : 1, 0x00D7 : 1, 0x24A9 : 1, 0x25A0 : 1, 0x24A8 : 1,
    0x2588 : 1, 0x27E1 : 1, 0x2B04 : 1, 0x21F3 : 1
};
//символы для mathfunc (интеграл, сумма...)
var q_aMathAutoCorrectControlAggregationCodes =
{
    0x2211 : 1, 0x220F : 1, 0x2210 : 1, 0x22C0 : 1, 0x2233 : 1,
    0x22C1 : 1, 0x22C3 : 1, 0x2A06 : 1, 0x2A04 : 1, 0x2A00 : 1,
    0x2A01 : 1, 0x2A02 : 1, 0x222B : 1, 0x222C : 1, 0x222D : 1,
    0x2A0C : 1, 0x222E : 1, 0x222F : 1, 0x2230 : 1, 0x2232 : 1
};
//символы accent
var q_aMathAutoCorrectAccentCharCodes =
{
    0x0305 : 1, 0x033F : 1, 0x0332 : 1, 0x0333 : 1, 0x0301 : 1,
    0x0300 : 1, 0x20D7 : 1, 0x0306 : 1, 0x0302 : 1, 0x20E1 : 1,
    0x20D1 : 1, 0x030C : 1, 0x0303 : 1, 0x20D6 : 1, 0x20D0 : 1,
    0x0307 : 1, 0x0308 : 1, 0x20DB : 1, 0x20DC : 1, 0x2032 : 1,
    0x2033 : 1, 0x2034 : 1, 0x2057 : 1
};
//симолы которые начинают автозамену groupchar
var g_aMathAutoCorrectTriggerEquationCharCodes =
{
    0x23 : 1, 0x24 : 1, 0x25 : 1, 0x26 : 1, 0x29 : 1,
    0x2A : 1, 0x2B : 1, 0x2C : 1, 0x2D : 1, 0x2E : 1, 0x2F : 1,
    0x3A : 1, 0x3B : 1, 0x3C : 1, 0x3D : 1, 0x3E : 1, 0x3F : 1,
    0x40 : 1, 0x5E : 1, 0x5F : 1,
    0x60 : 1,
    0x7E : 1
};
//left brackets
var g_MathLeftBracketAutoCorrectCharCodes =
{
    /*0x28 : 1,*/ 0x5B : 1, 0x7B : 1, /*0x7C : 1,*/ 0x2016 : 1,
    0x27E8 : 1, 0x2329 : 1, 0x27E6 : 1, 0x2308 : 1, 0x230A : 1,
    0x3016 : 1, 0x251C : 1
};
var g_MathRightBracketAutoCorrectCharCodes =
{
    /*0x29 : 1,*/ 0x5D : 1, 0x7D : 1, /*0x7C : 1,*/ 0x2016 : 1, 0x27E9 : 1,
    0x232A : 1, 0x27EB : 1, 0x27E7 : 1, 0x2309 : 1, 0x230B : 1,
    0x3017 : 1, 0x2524 : 1
};
//знаки (минус, сумма...)
var g_aMathAutoCorrectFracCharCodes =
{
    0x20 : 1, /*0x21 : 1, 0x22 : 1, */0x23 : 1,	/*0x24 : 1,*/ 0x25 : 1, 0x26 : 1,
    /*0x27 : 1, */0x28 : 1, 0x29 : 1, 0x2A : 1, 0x2B : 1, 0x2C : 1, 0x2D : 1,
    0x2E : 1, 0x2F : 1, 0x3A : 1, 0x3B : 1, 0x3C : 1, 0x3D : 1, 0x3E : 1,
    0x3F : 1, 0x40 : 1, 0x5B : 1, /*0x5C : 1,*/ 0x5D : 1, /*0x5E : 1, 0x5F : 1,*/
    0x60 : 1, 0x7B : 1, 0x7C : 1, 0x7D : 1, 0x7E : 1, /*0x2592 : 1*/
    0xD7 : 1
};
var g_aMathAutoCorrectDegreeCharCodes =
{
    /*0x20 : 1, 0x21 : 1, 0x22 : 1, */0x23 : 1, 0x24 : 1, 0x25 : 1, 0x26 : 1,
    /*0x27 : 1, */0x28 : 1, 0x29 : 1, 0x2A : 1, 0x2B : 1, 0x2C : 1, 0x2D : 1,
    0x2E : 1, /*0x2F : 1,*/ 0x3A : 1, 0x3B : 1, 0x3C : 1, 0x3D : 1, 0x3E : 1,
    0x3F : 1, 0x40 : 1, 0x5B : 1, /*0x5C : 1,*/ 0x5D : 1, /*0x5E : 1, 0x5F : 1,*/
    0x60 : 1, 0x7B : 1, 0x7C : 1, 0x7D : 1, 0x7E : 1, /*0x2592 : 1*/
    0xD7 : 1
};
var g_aMathAutoCorrectTriggerCharCodes =
{
    0x20 : 1, 0x21 : 1, 0x22 : 1, 0x23 : 1, 0x24 : 1, 0x25 : 1, 0x26 : 1,
    0x27 : 1, 0x28 : 1, 0x29 : 1, 0x2A : 1, 0x2B : 1, 0x2C : 1, 0x2D : 1,
    0x2E : 1, 0x2F : 1, 0x3A : 1, 0x3B : 1, 0x3C : 1, 0x3D : 1, 0x3E : 1,
    0x3F : 1, 0x40 : 1, 0x5B : 1, 0x5C : 1, 0x5D : 1, 0x5E : 1, 0x5F : 1,
    0x60 : 1, 0x7B : 1, 0x7C : 1, 0x7D : 1, 0x7E : 1, 0x2592 : 1
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CMathContent = CMathContent;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var g_oTextMeasurer = AscCommon.g_oTextMeasurer;
var History = AscCommon.History;

/** @enum {number} */
var c_oAscMathInterfaceMatrixRowRule = {
    Single     : 0x00,
    OneAndHalf : 0x01,
    Double     : 0x02,
    Exactly    : 0x03,
    Multiple   : 0x04

};

/** @enum {number} */
var c_oAscMathInterfaceMatrixColumnRule = {
    Single     : 0x00,
    OneAndHalf : 0x01,
    Double     : 0x02,
    Exactly    : 0x03,
    Multiple   : 0x04
};



/** @enum {number} */
var c_oAscMathInterfaceEqArrayLineRule = {
    Single     : 0x00,
    OneAndHalf : 0x01,
    Double     : 0x02,
    Exactly    : 0x03,
    Multiple   : 0x04
};

/** @enum {number} */
var c_oAscMathInterfaceSettingsBrkBin = {
    BreakRepeat : 0x00,
    BreakBefore : 0x01,
    BreakAfter  : 0x02
};

/** @enum {number} */
var c_oAscMathInterfaceSettingsAlign = {
    Left    : 0,
    Center  : 1,
    Right   : 2,
    Justify : 3
};



/** @enum {number} */
var c_oAscMathMainType = {
    Symbol        : 0x00,
    Fraction      : 0x01,
    Script        : 0x02,
    Radical       : 0x03,
    Integral      : 0x04,
    LargeOperator : 0x05,
    Bracket       : 0x06,
    Function      : 0x07,
    Accent        : 0x08,
    LimitLog      : 0x09,
    Operator      : 0x0a,
    Matrix        : 0x0b,
    Empty_Content : 0x0c
};

/**
 *
 * @param bInside
 * @returns {CMathBase}
 * @constructor
 * @extends {CParagraphContentWithParagraphLikeContent}
 */
function CMathBase(bInside)
{
	CParagraphContentWithParagraphLikeContent.call(this);

    this.Type = para_Math_Composition;

    this.pos  = new CMathPosition();
    this.size = new CMathSize();

    //  Properties
    this.Parent 			 = null;
    this.ParaMath 			 = null; // ссылка на общую формулу

    this.CtrPrp 			 = new CTextPr();
    this.CompiledCtrPrp 	 = new CTextPr(); 
    this.TextPrControlLetter = new CTextPr();

    this.ArgSize             = new CMathArgSize();

    /////////////////
    this.nRow                = 0;
    this.nCol                = 0;

    this.bInside             = bInside === true;

    this.bOneLine            = true;
    this.bCanBreak           = false;
    this.NumBreakContent     = -1;

    this.elements            = [];

    this.Bounds = new CMathBounds();

    this.dW = 0; //column gap, gap width
    this.dH = 0; //row gap, gap height

    this.alignment =
    {
        hgt: null,
        wdt: null
    };

    this.GapLeft = 0;
    this.GapRight = 0;

    this.BrGapLeft  = 0;
    this.BrGapRight = 0;

    this.RecalcInfo =
    {
        bCtrPrp:     true,
        bProps:      true
    };

    this.Content = [];
    this.CurPos  = 0;

    this.Selection =
    {
        StartPos : 0,
        EndPos   : 0,
        Use      : false
    };

    this.NearPosArray = [];

    this.ReviewType = reviewtype_Common;
    this.ReviewInfo = new CReviewInfo();

    var Api = editor;
    if (Api && !Api.isPresentationEditor && Api.WordControl && Api.WordControl.m_oLogicDocument && true === Api.WordControl.m_oLogicDocument.Is_TrackRevisions())
    {
        this.ReviewType = reviewtype_Add;
        this.ReviewInfo.Update();
    }

	this.m_oContentChanges = new AscCommon.CContentChanges(); // список изменений(добавление/удаление элементов)

    return this;
}
CMathBase.prototype = Object.create(CParagraphContentWithParagraphLikeContent.prototype);
CMathBase.prototype.constructor = CMathBase;
CMathBase.prototype.setContent = function()
{
    for(var i=0; i < this.nRow; i++)
    {
        this.elements[i] = [];
        for(var j = 0; j < this.nCol; j++)
            this.elements[i][j] = new CMathContent();
    }
};
CMathBase.prototype.setDimension = function(countRow, countCol)
{
    this.nRow = countRow;
    this.nCol = countCol;

    this.alignment.hgt = [];
    this.alignment.wdt = [];

    for(var i = 0; i < this.nCol ; i++)
    {
        this.alignment.wdt[i] = MCJC_CENTER;
    }

    for(var j=0; j < this.nRow; j++)
    {
        this.elements[j] = [];
        this.alignment.hgt[j] = MCJC_CENTER;
    }

};
CMathBase.prototype.NeedBreakContent = function(Number)
{
    this.bCanBreak       = true;
    this.NumBreakContent = Number;
};
///////// RunPrp, CtrPrp
CMathBase.prototype.setCtrPrp = function(txtPrp) // выставляем ctrPrp на чтение
{
    if(txtPrp !== null && typeof(txtPrp) !== "undefined")
    {
        this.CtrPrp.Merge(txtPrp);
    }
};
CMathBase.prototype.Get_CtrPrp = function(bCopy)
{
    var CtrPrp;
    if(this.bInside === true)
        CtrPrp = this.Parent.Get_CtrPrp(bCopy);
    else
        CtrPrp = bCopy ? this.CtrPrp.Copy() : this.CtrPrp;

    return CtrPrp;
};
CMathBase.prototype.Get_CompiledCtrPrp = function(bAllowInline)
{
    this.Set_CompiledCtrPrp(this.Parent, this.ParaMath);

    var CompiledCtrPrp;

    if(this.bInside === true)
    {
        CompiledCtrPrp = this.Parent.Get_CompiledCtrPrp();
    }
    else
    {
        CompiledCtrPrp = this.Get_CompiledCtrPrp_2();

        if(bAllowInline !== false && this.ParaMath)
            CompiledCtrPrp.FontSize *= MatGetKoeffArgSize(CompiledCtrPrp.FontSize, this.Parent.Get_CompiledArgSize().value);
    }

    if(bAllowInline !== false && this.ParaMath)
        CompiledCtrPrp.FontSize *= MatGetKoeffArgSize(CompiledCtrPrp.FontSize, this.ArgSize.value);// для настроек inline формул

    return CompiledCtrPrp;
};
CMathBase.prototype.Get_CompiledCtrPrp_2 = function() // without arg Size
{
    this.Set_CompiledCtrPrp(this.Parent, this.ParaMath);

    var CompiledCtrPrp;

    if(this.bInside === true)
        CompiledCtrPrp = this.Parent.Get_CompiledCtrPrp_2();
    else
        CompiledCtrPrp = this.CompiledCtrPrp.Copy();

    return CompiledCtrPrp;
};
CMathBase.prototype.Get_CompiledArgSize = function()
{
    return this.Parent.Get_CompiledArgSize();
};
CMathBase.prototype.Get_TxtPrControlLetter = function(RPI) // TextPrControlLetter не копируются !
{
    this.Set_CompiledCtrPrp(this.Parent, this.ParaMath, RPI);

    return this.TextPrControlLetter;
};
CMathBase.prototype.SetPlaceholder = function()
{
	for (var i = 0; i < this.nRow; i++)
	{
		for (var j = 0; j < this.nCol; j++)
		{
			if (!this.elements[i][j].IsJustDraw())
				this.elements[i][j].SetPlaceholder();
		}
	}
};
CMathBase.prototype.addMCToContent = function(elements)
{
    if(elements.length == this.nRow*this.nCol)
    {
        this.elements.length = 0;
        for(var i = 0; i < this.nRow; i++)
        {
            this.elements[i] = [];
            for(var j = 0; j < this.nCol; j++)
                this.elements[i][j] = elements[j + i*this.nCol];
        }
    }
    else
        this.setContent();
};
// эта функция здесь необходима для случая с n-арными операторами : когда передаем n-арный оператор с итераторами и аргумент
CMathBase.prototype.IsJustDraw = function()
{
    return false;
};
CMathBase.prototype.IsAccent = function()
{
    return false;
};
CMathBase.prototype.IsEqArray = function()
{
    return false;
};
CMathBase.prototype.getWidthsHeights = function()
{
    var Widths = [];
    for(var tt = 0; tt < this.nCol; tt++ )
        Widths[tt] = 0;

    var Ascents = [];
    var Descents = [];

    for(tt = 0; tt < this.nRow; tt++ )
    {
        Ascents[tt] = 0;
        Descents[tt] = 0;
    }

    for(var i=0; i < this.nRow; i++)
        for(var j = 0; j < this.nCol ; j++)
        {
            var size = this.elements[i][j].size;
            Widths[j] = ( Widths[j] > size.width ) ? Widths[j] : size.width;
            Ascents[i] = (Ascents[i] > size.ascent ) ? Ascents[i] : size.ascent;
            Descents[i] = (Descents[i] > size.height - size.ascent ) ? Descents[i] : size.height - size.ascent;
        }

    var Heights = [];
    for(tt = 0; tt < this.nRow; tt++ )
    {
        Heights[tt] = Ascents[tt] + Descents[tt];
    }

    return { widths: Widths, heights: Heights };
};
CMathBase.prototype.align = function(pos_x, pos_y)
{
    var PosAlign = new CMathPosition();

    if(this.alignment.hgt[pos_x] == MCJC_CENTER)
    {
        var maxAsc = 0;

        for(var j = 0; j < this.nCol; j++)
        {
            var _ascent = this.elements[pos_x][j].size.ascent;
            maxAsc = ( maxAsc > _ascent ) ? maxAsc : _ascent;
        }
        PosAlign.y = maxAsc - this.elements[pos_x][pos_y].size.ascent;
    }
    else if(this.alignment.hgt[pos_x] == MCJC_LEFT)
    {
        PosAlign.y = 0;
    }
    else // MCJC_RIGHT
    {
        var maxH = 0;

        for(var j = 0; j < this.nCol; j++)
        {
            var _h = this.elements[pos_x][j].size.height;
            maxH = ( maxH > _h ) ? maxH : _h;
        }

        PosAlign.y = maxH - this.elements[pos_x][pos_y].size.height;
    }

    var maxW  = 0;
    for(var i=0; i < this.nRow; i++)
    {
        var _w = this.elements[i][pos_y].size.width;
        maxW = ( maxW > _w ) ? maxW : _w;
    }

    if(this.alignment.wdt[pos_y] == MCJC_CENTER)
        PosAlign.x = (maxW - this.elements[pos_x][pos_y].size.width)*0.5;
    else if(this.alignment.wdt[pos_y] == MCJC_LEFT)
        PosAlign.x = 0;
    else // MCJC_RIGHT
        PosAlign.x = maxW - this.elements[pos_x][pos_y].size.width;

    return PosAlign;
};
CMathBase.prototype.setPosition = function(pos, PosInfo)
{
    this.UpdatePosBound(pos, PosInfo);

    if(this.bOneLine)
    {
        this.pos.x = pos.x;

        if(this.bInside === true)
            this.pos.y = pos.y;
        else
            this.pos.y = pos.y - this.size.ascent; ///!!!!

        var maxWH = this.getWidthsHeights();
        var Widths = maxWH.widths;
        var Heights = maxWH.heights;

        var h = 0, w = 0;

        for(var i=0; i < this.nRow; i++)
        {
            w = 0;
            for(var j = 0; j < this.nCol; j++)
            {
                var NewPos = new CMathPosition();
                var al = this.align(i, j);

                NewPos.x = this.pos.x + this.GapLeft + al.x + this.dW*j + w;
                NewPos.y = this.pos.y + al.y + this.dH*i + h;

                if(this.elements[i][j].Type == para_Math_Content) // прибавим ascent только для контентов, для вложенных мат объектов не добавляем !
                    NewPos.y += this.elements[i][j].size.ascent;

                this.elements[i][j].setPosition(NewPos, PosInfo);
                w += Widths[j];
            }
            h += Heights[i];
        }

        pos.x += this.size.width;
    }
    else
    {
        var Line  = PosInfo.CurLine,
            Range = PosInfo.CurRange;
        var CurLine  = Line - this.StartLine;
        var CurRange = ( 0 === CurLine ? Range - this.StartRange : Range );

        var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
        var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

        if(CurLine == 0 && CurRange == 0)
            pos.x += this.BrGapLeft;

        this.Content[StartPos].setPosition(pos, PosInfo);

        for(var Pos = StartPos + 1; Pos <= EndPos; Pos++)
        {
            pos.x += this.dW;
            this.Content[Pos].setPosition(pos, PosInfo);
        }

        var Len = this.Content.length;

        // Здесь проверяем не на то, что это последний Range (т.к. на данном этапе еще идет вычисление строк) а на конец контента !

        var EndBrContentEnd = this.NumBreakContent == EndPos && this.Content[EndPos].Math_Is_End(Line, Range),
            NotBrContent = this.NumBreakContent !== EndPos;

        var bEnd = EndBrContentEnd || NotBrContent;

        if(EndPos == Len - 1 && true === bEnd)
            pos.x += this.BrGapRight;

    }
};
CMathBase.prototype.ShiftPage = function(Dx)
{
    this.Bounds.ShiftPage(Dx);

    for(var i=0; i < this.nRow; i++)
    {
        for(var j = 0; j < this.nCol; j++)
        {
            var Item = this.elements[i][j];
            if(false == Item.IsJustDraw())
                Item.ShiftPage(Dx);
        }
    }
};
CMathBase.prototype.Shift_Range = function(Dx, Dy, _CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    if(this.bOneLine)
    {
        this.Bounds.ShiftPos(CurLine, CurRange, Dx, Dy);

        for(var i=0; i < this.nRow; i++)
        {
            for(var j = 0; j < this.nCol; j++)
            {
                var Item = this.elements[i][j];
                if(false == Item.IsJustDraw())
                    Item.Shift_Range(Dx, Dy, _CurLine, _CurRange);
            }
        }
    }
    else
    {
        this.Bounds.ShiftPos(CurLine, CurRange, Dx, Dy);

		CParagraphContentWithParagraphLikeContent.prototype.Shift_Range.call(this, Dx, Dy, _CurLine, _CurRange);
    }
};
CMathBase.prototype.IsStartRange = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    return CurLine == 0 && CurRange == 0;
};
CMathBase.prototype.IsLastRange = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var LinesCount = this.protected_GetLinesCount(),
        RangesCount = this.protected_GetRangesCount(CurLine);


    return CurLine == LinesCount - 1 && CurRange == RangesCount - 1;
};
CMathBase.prototype.UpdatePosBound = function(pos, PosInfo)
{
    var CurLine  = PosInfo.CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? PosInfo.CurRange - this.StartRange : PosInfo.CurRange);

    this.Bounds.SetPos(CurLine, CurRange, pos);
};
CMathBase.prototype.UpdateBoundsPosInfo = function(PRSA, _CurLine, _CurRange, _CurPage)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange);

    this.Bounds.SetGenPos(CurLine, CurRange, PRSA);
    this.Bounds.SetPage(CurLine, CurRange, _CurPage);

    if(this.bOneLine == true)
    {
        for(var i=0; i < this.nRow; i++)
        {
            for(var j = 0; j < this.nCol; j++)
            {
                if(false == this.elements[i][j].IsJustDraw())
                    this.elements[i][j].UpdateBoundsPosInfo(PRSA, _CurLine, _CurRange, _CurPage);
            }
        }
    }
    else
    {
        var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
        var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

        for(var Pos = StartPos; Pos <= EndPos; Pos++)
        {
            this.Content[Pos].UpdateBoundsPosInfo(PRSA, _CurLine, _CurRange, _CurPage);
        }
    }

};
CMathBase.prototype.draw = function(x, y, pGraphics, PDSE)
{
    this.Make_ShdColor(PDSE, this.Get_CompiledCtrPrp()); // для Just-Draw элементов

    for(var i=0; i < this.nRow; i++)
        for(var j = 0; j < this.nCol; j++)
        {
            if(this.elements[i][j].IsJustDraw()) // для Just-Draw элементов надо выставить Font
            {
                var ctrPrp = this.Get_TxtPrControlLetter();

                var Font =
                {
                    FontSize:   ctrPrp.FontSize,
                    FontFamily: {Name : ctrPrp.FontFamily.Name, Index : ctrPrp.FontFamily.Index},
                    Italic:     false,
                    Bold:       false //ctrPrp.Bold
                };

                pGraphics.SetFont(Font);
            }

            this.elements[i][j].draw(x, y, pGraphics, PDSE);
        }
};
CMathBase.prototype.Draw_Elements = function(PDSE)
{
    if(this.bOneLine)
    {
        var X = PDSE.X;

        this.Make_ShdColor(PDSE, this.Get_CompiledCtrPrp()); // для Just-Draw элементов

        for(var i=0; i < this.nRow; i++)
        {
            for(var j = 0; j < this.nCol; j++)
            {
                if(this.elements[i][j].IsJustDraw()) // для Just-Draw элементов надо выставить Font
                {
                    var ctrPrp = this.Get_TxtPrControlLetter();

                    var Font =
                    {
                        FontSize:   ctrPrp.FontSize,
                        FontFamily: {Name : ctrPrp.FontFamily.Name, Index : ctrPrp.FontFamily.Index},
                        Italic:     false,
                        Bold:       false //ctrPrp.Bold
                    };

                    PDSE.Graphics.SetFont(Font);
                }

                this.elements[i][j].Draw_Elements(PDSE);
            }
        }

        PDSE.X = X + this.size.width;
    }
    else
    {
        var CurLine  = PDSE.Line - this.StartLine;
        var CurRange = ( 0 === CurLine ? PDSE.Range - this.StartRange : PDSE.Range );

        var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
        var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

        for (var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
        {
			this.Content[CurPos].Draw_Elements(PDSE);
        }
    }
};
CMathBase.prototype.remove = function(order)
{
    return this.Parent.remove(order);
};
CMathBase.prototype.ApplyProperties = function(RPI)
{};
CMathBase.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI, GapsInfo)
{
    this.Parent = Parent;
    this.ParaMath = ParaMath;

    this.Set_CompiledCtrPrp(Parent, ParaMath, RPI);

    this.ApplyProperties(RPI);

    // setGaps обязательно после того как смержили CtrPrp (Set_CompiledCtrPrp)
    if(this.bInside == false)
        GapsInfo.setGaps(this, this.TextPrControlLetter.FontSize);

    for(var i=0; i < this.nRow; i++)
        for(var j = 0; j < this.nCol; j++)
            this.elements[i][j].PreRecalc(this, ParaMath, ArgSize, RPI);

};
CMathBase.prototype.Math_UpdateGaps = function(_CurLine, _CurRange, GapsInfo)
{
    GapsInfo.updateCurrentObject(this, this.TextPrControlLetter.FontSize);

    if(GapsInfo.bUpdate == true)
    {
        GapsInfo.updateGaps();
    }

    if(this.bOneLine == false)
    {
        var BrPos = this.NumBreakContent;
        this.Content[BrPos].Math_UpdateGaps(_CurLine, _CurRange);
    }
};
CMathBase.prototype.UpdLastElementForGaps = function(CurLine, CurRange, GapsInfo)
{
    GapsInfo.updateCurrentObject(this, this.TextPrControlLetter.FontSize);
};
CMathBase.prototype.recalculateSize = function(oMeasure, RPI)
{
    var width = 0;
    var height = 0;

    var maxWH = this.getWidthsHeights();

    this.setDistance();

    var Widths = maxWH.widths;
    var Heights = maxWH.heights;

    for( var j = 0 ; j < this.nRow; j++ )
        height += Heights[j];

    height += this.dH*(this.nRow - 1);

    for(var i=0; i < this.nCol ; i++)
        width += Widths[i];

    width += this.dW*(this.nCol - 1) + this.GapLeft + this.GapRight;

    var ascent = this.getAscent(oMeasure, height);

    this.size.width  = width;
    this.size.height = height;
    this.size.ascent = ascent;
}
CMathBase.prototype.Resize = function(oMeasure, RPI)
{
    for(var i=0; i < this.nRow; i++)
        for(var j = 0; j < this.nCol; j++)
        {
            if(this.elements[i][j].IsJustDraw()) // для Just-Draw элементов надо выставить Font
            {
                var ctrPrp = this.Get_TxtPrControlLetter();

                var Font =
                {
                    FontSize:   ctrPrp.FontSize,
                    FontFamily: {Name : ctrPrp.FontFamily.Name, Index : ctrPrp.FontFamily.Index},
                    Italic:     false,
                    Bold:       false //ctrPrp.Bold
                };

                g_oTextMeasurer.SetFont(Font);
            }

            this.elements[i][j].Resize(oMeasure, RPI);
        }


    this.recalculateSize(oMeasure, RPI);
};
CMathBase.prototype.Resize_2 = function(oMeasure, Parent, ParaMath, RPI, ArgSize)
{
    for(var i=0; i < this.nRow; i++)
        for(var j = 0; j < this.nCol; j++)
            if(!this.elements[i][j].IsJustDraw())
                this.elements[i][j].Resize_2(oMeasure, this, ParaMath, RPI, ArgSize);
};
CMathBase.prototype.Set_CompiledCtrPrp = function(Parent, ParaMath, RPI)
{
    if(this.RecalcInfo.bCtrPrp == true || (RPI !== null && RPI !== undefined && RPI.bRecalcCtrPrp == true))
    {
        if (undefined === ParaMath || null === ParaMath)
        {
            this.CompiledCtrPrp = new CTextPr();
            this.CompiledCtrPrp.Init_Default();
            return;
        }

        // Получим настройки текста, для данного параграфа
        this.CompiledCtrPrp = ParaMath.Paragraph.Get_CompiledPr2(false).TextPr.Copy();

        this.CompiledCtrPrp.Merge(ParaMath.Get_Default_TPrp());

        // Если в прямых настройках задан стиль, тогда смержим настройки стиля
        if ( undefined != this.CtrPrp.RStyle )
        {
            var Styles = ParaMath.Paragraph.Parent.Get_Styles();
            var StyleTextPr = Styles.Get_Pr( this.CtrPrp.RStyle, styletype_Character ).TextPr;
            this.CompiledCtrPrp.Merge( StyleTextPr );
        }

        var defaultTxtPrp = ParaMath.Get_Default_TPrp();

        this.CompiledCtrPrp.FontFamily =
        {
            Name:       defaultTxtPrp.FontFamily.Name,
            Index:      defaultTxtPrp.FontFamily.Index
        };

        this.CompiledCtrPrp.Merge(this.CtrPrp);

        // for Control Letter

        var FontSize = ParaMath.GetFirstRPrp().FontSize;

        if(this.bInside == true)
        {
            var TxtPr = Parent.Get_TxtPrControlLetter(RPI); // чтобы применился ArgSize Parent

            FontSize = TxtPr.FontSize;
            FontSize *= MatGetKoeffArgSize(FontSize, this.ArgSize.value);
        }
        else
        {
            FontSize *= MatGetKoeffArgSize(FontSize, Parent.Get_CompiledArgSize().value);
            FontSize *= MatGetKoeffArgSize(FontSize, this.ArgSize.value);
        }

        this.TextPrControlLetter.FontSize = FontSize;
        this.TextPrControlLetter.FontFamily =
        {
            Name:       defaultTxtPrp.FontFamily.Name,
            Index:      defaultTxtPrp.FontFamily.Index
        }; // Cambria Math


        this.RecalcInfo.bCtrPrp = false;
    }
};
CMathBase.prototype.getAscent = function(oMeasure, _height)
{
    var Ascent = 0;
    if(this.nRow > 1)
    {
        Ascent = _height;
        Ascent /=2;
        var MergedCtrPrp = this.Get_CompiledCtrPrp();
        Ascent += this.ParaMath.GetShiftCenter(oMeasure, MergedCtrPrp);
    }
    else
        for(var i=0; i< this.nCol; i++)
            Ascent = (this.elements[0][i].size.ascent > Ascent) ?  this.elements[0][i].size.ascent : Ascent;

    return Ascent;
};
CMathBase.prototype.alignHor = function(pos, coeff)
{
    if(pos!=-1)
        this.alignment.wdt[pos] = coeff;
    else
        for(var j = 0; j< this.alignment.wdt.length; j++)
            this.alignment.wdt[j] = coeff;

}
CMathBase.prototype.alignVer = function(pos, coeff)
{
    if(pos!=-1)
        this.alignment.hgt[pos] = coeff;
    else
        for(var j = 0; j < this.alignment.hgt.length; j++)
            this.alignment.hgt[j] = coeff;
};
CMathBase.prototype.setDistance = function()
{

};
CMathBase.prototype.hidePlaceholder = function(flag)
{
    for(var i=0; i < this.nRow; i++)
        for(var j = 0; j < this.nCol; j++)
        {
            if( this.elements[i][j].IsJustDraw() == false )
                this.elements[i][j].hidePlaceholder(flag);
        }
};
CMathBase.prototype.getElement = function(x, y)
{
    return this.elements[x][y];
};
CMathBase.prototype.IsOneLineText = function() // for degree
{
    var bOneLineText = true;
    if(this.nRow == 1)
    {
        for(var j = 0; j < this.nCol; j++)
        {
            if(!this.elements[0][j].IsJustDraw() && !this.elements[0][j].IsOneLineText())
            {
                bOneLineText = false;
                break;
            }
        }
    }
    else
        bOneLineText = false;


    return bOneLineText;
};
////    For Edit   /////
CMathBase.prototype.getGapsInside = function(GapsInfo)
{
    var kind = this.kind;
    var gaps = {left: 0, right: 0};
    var checkBase = kind == MATH_DEGREE || kind == MATH_DEGREESubSup || kind == MATH_ACCENT || kind == MATH_RADICAL || kind == MATH_LIMIT || kind == MATH_BORDER_BOX;

    if(checkBase)
    {
        var base = this.getBase();
        gaps = base.getGapsInside(GapsInfo);
    }

    return gaps;
};
CMathBase.prototype.SetGaps = function(GapsInfo)
{
    //this.Parent   = GapsInfo.Parent;
    //this.ParaMath = GapsInfo.ParaMath;

    GapsInfo.Left       = GapsInfo.Current;
    GapsInfo.leftRunPrp = GapsInfo.currRunPrp;


    GapsInfo.Current    = this;
    GapsInfo.currRunPrp = this.Get_CompiledCtrPrp();

    GapsInfo.setGaps();

};
CMathBase.prototype.Is_EmptyGaps = function()
{
    return false;
};
//////////////////////////////////
CMathBase.prototype.IsPlaceholder = function()
{
    return false;
};
CMathBase.prototype.IsText = function()
{
    return false;
};
CMathBase.prototype.GetParent = function()
{
    return (this.Parent.Type !== para_Math_Composition ? this : this.Parent.GetParent());
};
CMathBase.prototype.Get_TextPr = function(ContentPos, Depth)
{
    var pos = ContentPos.Get(Depth);

    return this.Content[pos].Get_TextPr(ContentPos, Depth+1);
};
CMathBase.prototype.Get_CompiledTextPr  = function(Copy)
{
	var TextPr = null;

	var nStartPos = 0;
	var nCount = this.Content.length;
	while (null === TextPr && nStartPos < nCount)
	{
		if (this.Is_ContentUse(this.Content[nStartPos]))
			TextPr = this.Content[nStartPos].Get_CompiledTextPr(true, true);

		nStartPos++;
	}

	for (var nPos = nStartPos; nPos < nCount; ++nPos)
	{
		var CurTextPr = this.Content[nPos].Get_CompiledTextPr(false, true);

		if (null !== CurTextPr)
			TextPr = TextPr.Compare(CurTextPr);
	}

	return TextPr;
};
CMathBase.prototype.Get_CompiledPr = function(Copy)
{
    return this.Get_CompiledTextPr(Copy);
};
CMathBase.prototype.Apply_TextPr = function(TextPr, IncFontSize, ApplyToAll)
{
	this.Apply_TextPrToCtrPr(TextPr, IncFontSize, ApplyToAll);

	for (var nIndex = 0; nIndex < this.Content.length; ++nIndex)
	{
		this.Content[nIndex].Apply_TextPr(TextPr, IncFontSize, ApplyToAll);
	}
};
CMathBase.prototype.Apply_TextPrToCtrPr = function(TextPr, IncFontSize, ApplyToAll)
{
    if(ApplyToAll == true)
        this.RecalcInfo.bCtrPrp = true;

    if(TextPr == undefined)
    {
        var CtrPrp = this.Get_CompiledCtrPrp_2();
        this.Set_FontSizeCtrPrp(FontSize_IncreaseDecreaseValue( IncFontSize, CtrPrp.FontSize ));
    }
    else
    {
    	if (undefined !== TextPr.Bold)
    		this.Set_Bold(TextPr.Bold);

        if(TextPr.AscFill || TextPr.AscLine || TextPr.AscUnifill)
        {
            var oCompiledPr = this.Get_CompiledCtrPrp();
            if(TextPr.AscFill)
            {
                this.Set_TextFill(AscFormat.CorrectUniFill(TextPr.AscFill, oCompiledPr.TextFill, 1));
            }
            if(TextPr.AscUnifill)
            {
                this.Set_Unifill(AscFormat.CorrectUniFill(TextPr.AscUnifill, oCompiledPr.Unifill, 0));
            }
            if(TextPr.AscLine)
            {
                this.Set_TextOutline(AscFormat.CorrectUniStroke(TextPr.AscLine, oCompiledPr.TextOutline, 0));
            }
            return;
        }
        if(TextPr.FontSize !== undefined)
            this.Set_FontSizeCtrPrp(TextPr.FontSize);

        if(TextPr.Shd !== undefined)
            this.Set_Shd(TextPr.Shd);

        if(undefined != TextPr.Unifill)
        {
            this.Set_Unifill(TextPr.Unifill.createDuplicate());
            if(undefined != this.CtrPrp.Color)
            {
                this.Set_Color(undefined);
            }
            if(undefined != this.CtrPrp.TextFill)
            {
                this.Set_TextFill(undefined);
            }
        }
        if(undefined != TextPr.TextOutline)
        {
            this.Set_TextOutline(TextPr.TextOutline);
        }
        if(undefined != TextPr.TextFill)
        {
            this.Set_TextFill(TextPr.TextFill);
            if(undefined != this.CtrPrp.Color)
            {
                this.Set_Color(undefined);
            }
            if(undefined != this.CtrPrp.Unifill)
            {
                this.Set_Unifill(undefined);
            }
        }

        if ( undefined != TextPr.HighLight )
            this.Set_HighLight( null === TextPr.HighLight ? undefined : TextPr.HighLight );

        if(undefined !== TextPr.Underline)
        {
            this.Set_Underline(TextPr.Underline);
        }

        if(undefined !== TextPr.Strikeout)
        {
            this.Set_Strikeout(TextPr.Strikeout);
        }

        if(undefined !== TextPr.DStrikeout)
        {
            this.Set_DoubleStrikeout(TextPr.DStrikeout);
        }

        if ( undefined != TextPr.RFonts )
        {
            var RFonts = new CRFonts();
            RFonts.Set_All("Cambria Math", -1);

            this.raw_SetRFonts(RFonts);
        }
    }
};
CMathBase.prototype.GetMathTextPrForMenu = function(ContentPos, Depth)
{
    var pos = ContentPos.Get(Depth);

    return this.Content[pos].GetMathTextPrForMenu(ContentPos, Depth+1);
};
CMathBase.prototype.Set_MathTextPr2 = function(TextPr, MathPr, bAll)
{
    this.Set_FontSizeCtrPrp(TextPr.FontSize);

    for(var i = 0; i < this.Content.length; i++)
        this.Content[i].Set_MathTextPr2(TextPr, MathPr, bAll);
};
CMathBase.prototype.Set_FontSizeCtrPrp = function(Value)
{
	if (Value !== this.CtrPrp.FontSize)
	{
		History.Add(new CChangesMathBaseFontSize(this, this.CtrPrp.FontSize, Value));
		this.raw_SetFontSize(Value);
	}
};
CMathBase.prototype.Set_Color = function(Value)
{
	if ((undefined === Value && undefined !== this.CtrPrp.Color) || (Value instanceof CDocumentColor && (undefined === this.CtrPrp.Color || false === Value.Compare(this.CtrPrp.Color))))
	{
		History.Add(new CChangesMathBaseColor(this, this.CtrPrp.Color, Value));
		this.raw_SetColor(Value);
	}
};
CMathBase.prototype.Set_Unifill = function(Value)
{
	if (( undefined === Value && undefined !== this.CtrPrp.Unifill ) || ( Value instanceof AscFormat.CUniFill && ( undefined === this.CtrPrp.Unifill || false === AscFormat.CompareUnifillBool(this.CtrPrp.Unifill, Value) ) ))
	{
		History.Add(new CChangesMathBaseUnifill(this, this.CtrPrp.Unifill, Value));
		this.raw_SetUnifill(Value);
	}
};
CMathBase.prototype.Set_TextFill = function(Value)
{
	if (( undefined === Value && undefined !== this.CtrPrp.TextFill ) || ( Value instanceof AscFormat.CUniFill && ( undefined === this.CtrPrp.TextFill || false === AscFormat.CompareUnifillBool(this.CtrPrp.TextFill, Value) ) ))
	{
		History.Add(new CChangesMathBaseTextFill(this, this.CtrPrp.TextFill, Value));
		this.raw_SetTextFill(Value);
	}
};
CMathBase.prototype.Set_TextOutline = function(Value)
{
	if (( undefined === Value && undefined !== this.CtrPrp.TextOutline ) || ( Value instanceof AscFormat.CLn && ( undefined === this.CtrPrp.TextOutline || false === Value.IsIdentical(this.CtrPrp.TextOutline) ) ))
	{
		History.Add(new CChangesMathBaseTextOutline(this, this.CtrPrp.TextOutline, Value));
		this.raw_SetTextOutline(Value);
	}
};
CMathBase.prototype.Set_HighLight = function(Value)
{
	var OldValue = this.CtrPrp.HighLight;
	if ((undefined === Value && undefined !== OldValue) || ( highlight_None === Value && highlight_None !== OldValue ) || ( Value instanceof CDocumentColor && ( undefined === OldValue || highlight_None === OldValue || false === Value.Compare(OldValue) ) ))
	{
		History.Add(new CChangesMathBaseHighLight(this, this.CtrPrp.HighLight, Value));
		this.raw_SetHighLight(Value);
	}
};
CMathBase.prototype.Set_Shd = function(Shd)
{
	if (!(undefined === this.CtrPrp.Shd && undefined === Shd) && !(undefined !== this.CtrPrp.Shd && undefined !== Shd && true === this.CtrPrp.Shd.Compare(Shd)))
	{
		History.Add(new CChangesMathBaseShd(this, this.CtrPrp.Shd, Shd));
		this.raw_SetShd(Shd);
	}
};
CMathBase.prototype.Set_Underline = function(Value)
{
	if (Value !== this.CtrPrp.Underline)
	{
		History.Add(new CChangesMathBaseUnderline(this, this.CtrPrp.Underline, Value));
		this.raw_SetUnderline(Value);
	}
};
CMathBase.prototype.Set_Strikeout = function(Value)
{
	if (Value !== this.CtrPrp.Strikeout)
	{
		History.Add(new CChangesMathBaseStrikeout(this, this.CtrPrp.Strikeout, Value));
		this.raw_SetStrikeout(Value);
	}
};
CMathBase.prototype.Set_DoubleStrikeout = function(Value)
{
	if (Value !== this.CtrPrp.DStrikeout)
	{
		History.Add(new CChangesMathBaseDoubleStrikeout(this, this.CtrPrp.DStrikeout, Value));
		this.raw_Set_DoubleStrikeout(Value);
	}
};
CMathBase.prototype.Set_Bold = function(Value)
{
	if (Value !== this.CtrPrp.Bold)
	{
		History.Add(new CChangesMathBaseBold(this, this.CtrPrp.Bold, Value));
		this.raw_SetBold(Value);
	}
};
CMathBase.prototype.Set_Italic = function(Value)
{
	if (Value !== this.CtrPrp.Italic)
	{
		History.Add(new CChangesMathBaseItalic(this, this.CtrPrp.Italic, Value));
		this.raw_SetItalic(Value);
	}
};
CMathBase.prototype.Set_RFonts_Ascii = function(Value)
{
	if (this.CtrPrp.RFonts.Ascii !== Value)
	{
		History.Add(new CChangesMathBaseRFontsAscii(this, this.CtrPrp.RFonts.Ascii, Value));
		this.raw_SetRFontsAscii(Value);
	}
};
CMathBase.prototype.Set_RFonts_HAnsi = function(Value)
{
	if (this.CtrPrp.RFonts.HAnsi !== Value)
	{
		History.Add(new CChangesMathBaseRFontsHAnsi(this, this.CtrPrp.RFonts.HAnsi, Value));
		this.raw_SetRFontsHAnsi(Value);
	}
};
CMathBase.prototype.Set_RFonts_CS = function(Value)
{
	if (this.CtrPrp.RFonts.CS !== Value)
	{
		History.Add(new CChangesMathBaseRFontsCS(this, this.CtrPrp.RFonts.CS, Value));
		this.raw_SetRFontsCS(Value);
	}
};
CMathBase.prototype.Set_RFonts_EastAsia = function(Value)
{
	if (this.CtrPrp.RFonts.EastAsia !== Value)
	{
		History.Add(new CChangesMathBaseRFontsEastAsia(this, this.CtrPrp.RFonts.EastAsia, Value));
		this.raw_SetRFontsEastAsia(Value);
	}
};
CMathBase.prototype.Set_RFonts_Hint = function(Value)
{
	if (this.CtrPrp.RFonts.Hint !== Value)
	{
		History.Add(new CChangesMathBaseRFontsHint(this, this.CtrPrp.RFonts.Hint, Value));
		this.raw_SetRFontsHint(Value);
	}
};
CMathBase.prototype.raw_SetBold = function(Value)
{
    this.CtrPrp.Bold = Value;
    this.NeedUpdate_CtrPrp();
};
CMathBase.prototype.raw_SetItalic = function(Value)
{
    this.CtrPrp.Italic = Value;
    this.NeedUpdate_CtrPrp();
};
CMathBase.prototype.raw_SetUnderline  = function(Value)
{
    this.CtrPrp.Underline = Value;
    this.NeedUpdate_CtrPrp();

};
CMathBase.prototype.raw_SetStrikeout = function(Value)
{
    this.CtrPrp.Strikeout = Value;
    this.NeedUpdate_CtrPrp();
};
CMathBase.prototype.raw_Set_DoubleStrikeout = function(Value)
{
    this.CtrPrp.DStrikeout = Value;
    this.NeedUpdate_CtrPrp();

};
CMathBase.prototype.raw_SetFontSize  = function(Value)
{
    this.CtrPrp.FontSize    = Value;
    this.NeedUpdate_CtrPrp();
};
CMathBase.prototype.raw_SetShd = function(Shd)
{
    if ( undefined !== Shd )
    {
        this.CtrPrp.Shd = new CDocumentShd();
        this.CtrPrp.Shd.Set_FromObject( Shd );
    }
    else
        this.CtrPrp.Shd = undefined;

    this.NeedUpdate_CtrPrp();
};
CMathBase.prototype.raw_SetColor = function(Value)
{
    this.CtrPrp.Color = Value;
    this.NeedUpdate_CtrPrp();
};
CMathBase.prototype.raw_SetUnifill = function(Value)
{
    this.CtrPrp.Unifill = Value;
    this.NeedUpdate_CtrPrp();
};
CMathBase.prototype.raw_SetTextFill = function(Value)
{
    this.CtrPrp.TextFill = Value;
    this.NeedUpdate_CtrPrp();
};
CMathBase.prototype.raw_SetTextOutline = function(Value)
{
    this.CtrPrp.TextOutline = Value;
    this.NeedUpdate_CtrPrp();
};
CMathBase.prototype.raw_SetHighLight = function(Value)
{
    this.CtrPrp.HighLight = Value;
    this.NeedUpdate_CtrPrp();
};
CMathBase.prototype.raw_SetRFonts = function(RFonts)
{
    if ( undefined != RFonts )
    {
        if ( undefined != RFonts.Ascii )
            this.Set_RFonts_Ascii( RFonts.Ascii );

        if ( undefined != RFonts.HAnsi )
            this.Set_RFonts_HAnsi( RFonts.HAnsi );

        if ( undefined != RFonts.CS )
            this.Set_RFonts_CS( RFonts.CS );

        if ( undefined != RFonts.EastAsia )
            this.Set_RFonts_EastAsia( RFonts.EastAsia );

        if ( undefined != RFonts.Hint )
            this.Set_RFonts_Hint( RFonts.Hint );
    }
    else
    {
        this.Set_RFonts_Ascii( undefined );
        this.Set_RFonts_HAnsi( undefined );
        this.Set_RFonts_CS( undefined );
        this.Set_RFonts_EastAsia( undefined );
        this.Set_RFonts_Hint( undefined );
    }
};
CMathBase.prototype.raw_SetRFontsAscii = function(Value)
{
    this.CtrPrp.RFonts.Ascii = Value;
    this.NeedUpdate_CtrPrp();
};
CMathBase.prototype.raw_SetRFontsHAnsi = function(Value)
{
    this.CtrPrp.RFonts.HAnsi = Value;
    this.NeedUpdate_CtrPrp();
};
CMathBase.prototype.raw_SetRFontsCS = function(Value)
{
    this.CtrPrp.RFonts.CS = Value;
    this.NeedUpdate_CtrPrp();
};
CMathBase.prototype.raw_SetRFontsEastAsia = function(Value)
{
    this.CtrPrp.RFonts.EastAsia = Value;
    this.NeedUpdate_CtrPrp();
};
CMathBase.prototype.raw_SetRFontsHint = function(Value)
{
    this.CtrPrp.RFonts.Hint = Value;
    this.NeedUpdate_CtrPrp();
};
CMathBase.prototype.NeedUpdate_CtrPrp = function()
{
    this.RecalcInfo.bCtrPrp = true;
};
CMathBase.prototype.SelectToParent = function(bCorrect)
{
    this.bSelectionUse = true;
    this.Parent.SelectToParent(bCorrect);
};
CMathBase.prototype.Get_StartRangePos = function(_CurLine, _CurRange, SearchPos, Depth, bStartPos)
{
    var Pos = bStartPos == true ? this.NumBreakContent : this.CurPos;

    var Result = this.Content[Pos].Get_StartRangePos(_CurLine, _CurRange, SearchPos, Depth+1, bStartPos);

    if ( true === Result )
        SearchPos.Pos.Update(Pos, Depth );

    return Result;

};
CMathBase.prototype.Get_EndRangePos = function(_CurLine, _CurRange, SearchPos, Depth, bEndPos)
{
    var Pos = bEndPos == true ? this.NumBreakContent : this.CurPos;

    var Result = this.Content[Pos].Get_EndRangePos(_CurLine, _CurRange, SearchPos, Depth+1, bEndPos);

    if ( true === Result )
        SearchPos.Pos.Update( Pos, Depth );

    return Result;

};
CMathBase.prototype.Recalculate_Range_Spaces = function(PRSA, _CurLine, _CurRange, _CurPage)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var WidthVisible;

    if ( 0 !== PRSA.LettersSkip )
    {
        WidthVisible = this.Bounds.Get_Width(CurLine, CurRange);
        PRSA.LettersSkip--;
    }
    else
    {
        WidthVisible = this.Bounds.Get_Width(CurLine, CurRange) + PRSA.JustifyWord;
    }

    PRSA.X    += WidthVisible;
    PRSA.LastW = WidthVisible;
};
CMathBase.prototype.Get_Width = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine,
        CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    return this.Bounds.Get_Width(CurLine, CurRange);
};
CMathBase.prototype.SaveRecalculateObject = function(Copy)
{
    var RecalcObj;
    if(this.bOneLine)
    {
        RecalcObj = new CEmptyRunRecalculateObject(this.StartLine, this.StartRange);
    }
    else
    {

        var Num = this.NumBreakContent;

        RecalcObj = new CRunRecalculateObject(this.StartLine, this.StartRange);
        RecalcObj.Save_Lines( this, Copy );

        for(var Pos = 0; Pos < this.Content.length; Pos++)
        {
            if(Pos == Num)
            {
                RecalcObj.Content[Pos] = this.Content[Pos].SaveRecalculateObject(Copy);
            }
            else
            {
                RecalcObj.Content[Pos] = new CEmptyRunRecalculateObject(this.StartLine, this.StartRange);
            }
        }
    }

    return RecalcObj;
};
CMathBase.prototype.LoadRecalculateObject = function(RecalcObj)
{
	if (this.bOneLine == false)
		CParagraphContentWithParagraphLikeContent.prototype.LoadRecalculateObject.call(this, RecalcObj);

};
CMathBase.prototype.Fill_LogicalContent = function(nCount)
{
    for (var nIndex = 0; nIndex < nCount; nIndex++)
    {
        this.Content[nIndex] = new CMathContent();
        this.Content[nIndex].ParentElement = this;
        this.Content[nIndex].Parent        = this;
    }
};
CMathBase.prototype.Copy = function()
{
    var oProps = this.Pr.Copy();
    oProps.ctrPrp = this.CtrPrp.Copy();

    var NewElement = new this.constructor(oProps);

    for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; nIndex++)
    {
        this.Content[nIndex].CopyTo(NewElement.Content[nIndex], false);
    }

    return NewElement;
};
CMathBase.prototype.Refresh_RecalcData = function(Data)
{
    if(this.ParaMath !== null)
        this.ParaMath.Refresh_RecalcData(); // Refresh_RecalcData сообщает родительскому классу, что у него произошли изменения, нужно пересчитать
};
CMathBase.prototype.Write_ToBinary2 = function( Writer )
{
    Writer.WriteLong(this.ClassType);

    // String           : Id
    // Long             : Content.length
    // Array of Strings : Content[Index].Id
    // Variable         : Pr
    // Variable(CTextPr): CtrPrp
    // Long             : ReviewType
    // Bool             : undefined == ReviewInfo
    // if false         : ReviewInfo

    Writer.WriteString2(this.Id);

    var nCount = this.Content.length;
    Writer.WriteLong(nCount);
    for (var nIndex = 0; nIndex < nCount; nIndex++)
    {
        Writer.WriteString2(this.Content[nIndex].Id);
    }

    this.Pr.Write_ToBinary(Writer);
    this.CtrPrp.Write_ToBinary(Writer);
    Writer.WriteLong(this.ReviewType);

    if (undefined !== this.ReviewInfo)
    {
        Writer.WriteBool(false);
        this.ReviewInfo.Write_ToBinary(Writer);
    }
    else
    {
        Writer.WriteBool(true);
    }
};
CMathBase.prototype.Read_FromBinary2 = function( Reader )
{
    // String           : Id
    // Long             : Content.length
    // Array of Strings : Content[Index].Id
    // Variable         : Pr
    // Variable(CTextPr): CtrPrp
    // Long             : ReviewType
    // Bool             : undefined == ReviewInfo
    // if false         : ReviewInfo


    this.Id = Reader.GetString2();

    var nCount = Reader.GetLong();
    this.Content = [];
    for (var nIndex = 0; nIndex < nCount; nIndex++)
    {
        this.Content[nIndex] = AscCommon.g_oTableId.Get_ById(Reader.GetString2());
        this.Content[nIndex].ParentElement = this;
        this.Content[nIndex].Parent        = this;
    }

    this.Pr.Read_FromBinary(Reader);
    this.CtrPrp.Read_FromBinary(Reader);

    this.ReviewType = Reader.GetLong();
    if (true === Reader.GetBool())
    {
        this.ReviewInfo = undefined;
    }
    else
    {
        this.ReviewInfo = new CReviewInfo();
        this.ReviewInfo.Read_FromBinary(Reader);
    }

    this.fillContent();
};
CMathBase.prototype.Get_Id = function()
{
    return this.Id;
};
CMathBase.prototype.getPropsForWrite = function()
{
    return this.Pr;
};
CMathBase.prototype.setProperties = function(oProps)
{
    this.Pr.Set_FromObject(oProps);
    this.setCtrPrp(oProps.ctrPrp);

    this.RecalcInfo.bProps = true;
}
CMathBase.prototype.Correct_Content = function(bInnerCorrection)
{
    var nCount = this.Content.length;
    for (var nIndex = 0; nIndex < nCount; nIndex++)
    {
        this.Content[nIndex].Correct_Content(bInnerCorrection);
    }

    if (this.CurPos >= this.Content.length)
    	this.CurPos = this.Content.length - 1;

    if (this.CurPos < 0)
    	this.CurPos = 0;
};
CMathBase.prototype.Undo = function(Data)
{
    Data.Undo(this);
};
CMathBase.prototype.Redo = function(Data)
{
    Data.Redo(this);
};
CMathBase.prototype.Get_AllFontNames = function(AllFonts)
{
    this.CtrPrp.Document_Get_AllFontNames(AllFonts);

    for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; nIndex++)
    {
        this.Content[nIndex].Get_AllFontNames(AllFonts);
    }
};
CMathBase.prototype.Create_FontMap = function(Map)
{
    if (null === this.ParaMath)
        return;

    var CtrPrp = this.Get_CompiledCtrPrp();
    CtrPrp.Document_CreateFontMap(Map, this.ParaMath.Paragraph.Get_Theme().themeElements.fontScheme);

    for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; nIndex++)
        this.Content[nIndex].Create_FontMap(Map);
};
CMathBase.prototype.Recalculate_CurPos = function(_X, Y, CurrentRun, _CurRange, _CurLine, _CurPage, UpdateCurPos, UpdateTarget, ReturnTarget)
{
    return this.Content[this.CurPos].Recalculate_CurPos(_X, Y, CurrentRun, _CurRange, _CurLine, _CurPage, UpdateCurPos, UpdateTarget, ReturnTarget);
};
CMathBase.prototype.Get_ParaContentPosByXY = function(SearchPos, Depth, _CurLine, _CurRange, StepEnd)
{
    var nCount = this.Content.length;
    if (nCount <= 0)
        return false;

    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos, EndPos;

    if(this.bOneLine == false)
    {
        StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
        EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);
    }
    else
    {
        StartPos = 0;
        EndPos = nCount - 1;
    }

    var aBounds = [];

    for (var nIndex = 0; nIndex < nCount; nIndex++)
    {
        if(nIndex < StartPos || nIndex > EndPos)
        {
            aBounds.push(null);
        }
        else
        {
            var oBounds = this.Content[nIndex].Get_LineBound(_CurLine, _CurRange);

            if(oBounds == undefined)
                aBounds.push(null);
            else if (oBounds.W > 0.001 && oBounds.H > 0.001)
                aBounds.push(oBounds);
            else
                aBounds.push(null);
        }
    }

    var X = SearchPos.X;
    var Y = SearchPos.Y;

    var dDiff = null;

    var nCurIndex = 0;
    var nFindIndex = 0;

    while (nCurIndex < nCount)
    {
        var oBounds = aBounds[nCurIndex];

        if (null !== oBounds)
        {
            var _X = oBounds.X,
                _Y = oBounds.Y;

            if (_X <= X && X <= _X + oBounds.W && _Y <= Y && Y <= _Y + oBounds.H)
            {
                nFindIndex = nCurIndex;
                break;
            }
            else
            {
                var dCurDiffX = X - (_X + oBounds.W / 2);
                var dCurDiffY = Y - (_Y + oBounds.H / 2);
                var dCurDiff = dCurDiffX * dCurDiffX + dCurDiffY * dCurDiffY;

                if (null === dDiff || dDiff > dCurDiff)
                {
                    dDiff = dCurDiff;
                    nFindIndex = nCurIndex;
                }
            }
        }

        nCurIndex++;
    }

    if (null === aBounds[nFindIndex])
        return false;

    SearchPos.CurX = aBounds[nFindIndex].X;
    SearchPos.CurY = aBounds[nFindIndex].Y;

    if ( false === SearchPos.InText )
        SearchPos.InTextPos.Update2( nFindIndex, Depth );

    var bResult = false;

    if(true === this.Content[nFindIndex].Get_ParaContentPosByXY(SearchPos, Depth + 1, _CurLine, _CurRange, StepEnd))
    {
        SearchPos.Pos.Update2(nFindIndex, Depth);
        bResult = true;
    }

    return bResult;
};
CMathBase.prototype.Get_ParaContentPos = function(bSelection, bStart, ContentPos, bUseCorrection)
{
    var nPos = (true !== bSelection ? this.CurPos : (false !== bStart ? this.Selection.StartPos : this.Selection.EndPos));
    ContentPos.Add(nPos);

    if (undefined !== this.Content[nPos])
        this.Content[nPos].Get_ParaContentPos(bSelection, bStart, ContentPos, bUseCorrection);
};
CMathBase.prototype.Set_ParaContentPos = function(ContentPos, Depth)
{
    var CurPos = ContentPos.Get(Depth);

    if (undefined === CurPos || this.CurPos < 0)
    {
        this.CurPos = 0;
        this.Content[this.CurPos].MoveCursorToStartPos();
    }
    else if (CurPos > this.Content.length - 1)
    {
        this.CurPos = this.Content.length - 1;
        this.Content[this.CurPos].MoveCursorToEndPos(false);
    }
    else
    {
        this.CurPos = CurPos;
        this.Content[this.CurPos].Set_ParaContentPos(ContentPos, Depth + 1);
    }
};
CMathBase.prototype.Selection_DrawRange = function(_CurLine, _CurRange, SelectionDraw)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var SelectionStartPos = this.Selection.StartPos;
    var SelectionEndPos   = this.Selection.EndPos;

    var SelectionUse = this.Selection.Use;
    // для каждой новой строки в ParaMath FindStart будет true независимо от того нашли или нет начало селекта на предыдущей строке
    // поэтому для контентов разбивающихся на несколько строк сделаем проверку, чтобы не попасть в контенты, которые не относятся к текущей строке

    var ContentSelect = true;

    if(this.bOneLine == false)
    {
        var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
        var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

        ContentSelect = SelectionStartPos >= StartPos && SelectionEndPos <= EndPos;
    }

    if(SelectionUse == true && SelectionStartPos !== SelectionEndPos)
    {
        var Bound = this.Bounds.Get_LineBound(CurLine, CurRange);

        SelectionDraw.FindStart = false;
        SelectionDraw.W += Bound.W;
    }
    else if(SelectionUse == true && ContentSelect == true)
    {
        var Item = this.Content[SelectionStartPos];
        var BoundItem = Item.Get_LineBound(_CurLine, _CurRange);

        SelectionDraw.StartX = BoundItem.X;


        Item.Selection_DrawRange(_CurLine, _CurRange, SelectionDraw);
    }
    else if(SelectionDraw.FindStart == true)
    {
        SelectionDraw.StartX += this.Bounds.Get_Width(CurLine, CurRange);
    }

};
CMathBase.prototype.IsSelectionEmpty = function()
{
    if (true !== this.Selection.Use)
        return true;

    if (this.Selection.StartPos === this.Selection.EndPos)
        return this.Content[this.Selection.StartPos].IsSelectionEmpty();

    return false;
};
CMathBase.prototype.GetSelectContent = function()
{
    var nPos = (true === this.Selection.Use ? this.Selection.StartPos : this.CurPos);
    return this.Content[nPos].GetSelectContent();
};
CMathBase.prototype.Is_InnerSelection = function()
{
    if (true === this.Selection.Use && this.Selection.StartPos === this.Selection.EndPos)
        return true;

    return false;
};
CMathBase.prototype.Select_WholeElement = function()
{
    if (null !== this.Parent)
        this.Parent.Select_Element(this, true);
};
CMathBase.prototype.Select_MathContent = function(MathContent)
{
    for (var nPos = 0, nCount = this.Content.length; nPos < nCount; nPos++)
    {
        if (this.Content[nPos] === MathContent)
        {
            if (null !== this.Parent)
            {
                this.Selection.Use      = true;
                this.Selection.StartPos = nPos;
                this.Selection.EndPos   = nPos;
                this.Parent.Select_Element(this, false);
            }
            break;
        }
    }
};
CMathBase.prototype.Draw_HighLights = function(PDSH, bAll)
{
    var ComplCtrPrp = this.Get_CompiledCtrPrp();
    var oShd = ComplCtrPrp.Shd;
    var bDrawShd  = ( oShd === undefined || Asc.c_oAscShdNil === oShd.Value ? false : true );
    var ShdColor  = ( true === bDrawShd ? oShd.Get_Color( PDSH.Paragraph ) : null );

    var X = PDSH.X,
        Y0 = PDSH.Y0,
        Y1 = PDSH.Y1;

    var CurLine  = PDSH.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PDSH.Range - this.StartRange : PDSH.Range );

    var StartPos, EndPos;
    if(this.bOneLine)
    {
        StartPos = 0;
        EndPos   = this.Content.length - 1;
    }
    else
    {
        StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
        EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);
    }


    var bAllCont = this.Selection.StartPos !== this.Selection.EndPos;

    for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
		this.Content[CurPos].Draw_HighLights(PDSH, bAllCont);

    var Bound = this.Get_LineBound(PDSH.Line, PDSH.Range);

    if (true === bDrawShd)
        PDSH.Shd.Add(Y0, Y1, X, X + Bound.W, 0, ShdColor.r, ShdColor.g, ShdColor.b );

    var HighLight = ComplCtrPrp.HighLight;

    if ( highlight_None != HighLight )
        PDSH.High.Add( Y0, Y1, X, X + Bound.W, 0, HighLight.r, HighLight.g, HighLight.b );


    PDSH.X = Bound.X + Bound.W;
};
CMathBase.prototype.Draw_Lines = function(PDSL)
{
    var CtrPrp = this.Get_CompiledCtrPrp(false);

    var aStrikeout  = PDSL.Strikeout;
    var aDStrikeout = PDSL.DStrikeout;

    var ReviewType = this.Get_ReviewType();
    var bAddReview = reviewtype_Add === ReviewType ? true : false;
    var bRemReview = reviewtype_Remove === ReviewType ? true : false;
    var ReviewColor = null;
    if (bAddReview || bRemReview)
        ReviewColor = this.ReviewInfo.Get_Color();

    var ArgSize     = this.Get_CompiledArgSize();
    var fontCoeff   = MatGetKoeffArgSize(CtrPrp.FontSize, ArgSize.value);

    // вычисляем координату Y и LineW также как в Run
    var X          = PDSL.X;
    var Y          = PDSL.Baseline - CtrPrp.FontSize * fontCoeff * g_dKoef_pt_to_mm * 0.27;

    var LineW      = (CtrPrp.FontSize / 18) * g_dKoef_pt_to_mm;

    var Para       = PDSL.Paragraph;

    var BgColor = PDSL.BgColor;
    if ( undefined !== CtrPrp.Shd && Asc.c_oAscShdNil !== CtrPrp.Shd.Value )
        BgColor = CtrPrp.Shd.Get_Color( Para );
    var AutoColor = ( undefined != BgColor && false === BgColor.Check_BlackAutoColor() ? new CDocumentColor( 255, 255, 255, false ) : new CDocumentColor( 0, 0, 0, false ) );
    var CurColor, RGBA, Theme = this.Paragraph.Get_Theme(), ColorMap = this.Paragraph.Get_ColorMap();

    // Выставляем цвет обводки
    if ( true === PDSL.VisitedHyperlink && ( undefined === this.Pr.Color && undefined === this.Pr.Unifill ) )
        CurColor = new CDocumentColor( 128, 0, 151 );
    else if ( true === CtrPrp.Color.Auto && !CtrPrp.Unifill)
        CurColor = new CDocumentColor( AutoColor.r, AutoColor.g, AutoColor.b );
    else
    {
        if(CtrPrp.Unifill)
        {
            CtrPrp.Unifill.check(Theme, ColorMap);
            RGBA = CtrPrp.Unifill.getRGBAColor();
            CurColor = new CDocumentColor( RGBA.R, RGBA.G, RGBA.B );
        }
        else
        {
            CurColor = new CDocumentColor( CtrPrp.Color.r, CtrPrp.Color.g, CtrPrp.Color.b );
        }
    }

    var CurLine  = PDSL.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PDSL.Range - this.StartRange : PDSL.Range );

    var Bound = this.Bounds.Get_LineBound(CurLine, CurRange);

    if (true === bRemReview)
        aStrikeout.Add(Y, Y, X, X + Bound.W, LineW, ReviewColor.r, ReviewColor.g, ReviewColor.b);
    else if ( true === CtrPrp.DStrikeout )
        aDStrikeout.Add( Y, Y, X, X + Bound.W, LineW, CurColor.r, CurColor.g, CurColor.b );
    else if ( true === CtrPrp.Strikeout )
        aStrikeout.Add( Y, Y, X, X + Bound.W, LineW, CurColor.r, CurColor.g, CurColor.b );

    this.Draw_LinesForContent(PDSL);

    PDSL.X = Bound.X + Bound.W;
};
CMathBase.prototype.Draw_LinesForContent = function(PDSL)
{
    var CurLine  = PDSL.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PDSL.Range - this.StartRange : PDSL.Range );
    
    var StartPos, EndPos;

    if(this.bOneLine)
    {
        StartPos = 0;
        EndPos   = this.Content.length - 1;
    }
    else
    {
        StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
        EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);
    }

    for ( var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
        this.Content[CurPos].Draw_Lines(PDSL);
};
CMathBase.prototype.Make_ShdColor = function(PDSE, CurTextPr)
{
    var Para      = PDSE.Paragraph;
    var pGraphics = PDSE.Graphics;
    var BgColor   = PDSE.BgColor;

    if ( undefined !== CurTextPr.Shd && Asc.c_oAscShdNil !== CurTextPr.Shd.Value )
        BgColor = CurTextPr.Shd.Get_Color( Para );

    var AutoColor = ( undefined != BgColor && false === BgColor.Check_BlackAutoColor() ? new CDocumentColor( 255, 255, 255, false ) : new CDocumentColor( 0, 0, 0, false ) );

    var RGBA;
    if(CurTextPr.Unifill)
    {
        CurTextPr.Unifill.check(PDSE.Theme, PDSE.ColorMap);
        RGBA = CurTextPr.Unifill.getRGBAColor();

        if ( true === PDSE.VisitedHyperlink && ( undefined === this.CtrPrp.Color && undefined === this.CtrPrp.Unifill ) )
        {
            AscFormat.G_O_VISITED_HLINK_COLOR.check(PDSE.Theme, PDSE.ColorMap);
            RGBA = AscFormat.G_O_VISITED_HLINK_COLOR.getRGBAColor();
            pGraphics.p_color( RGBA.R, RGBA.G, RGBA.B, RGBA.A );
            pGraphics.b_color1( RGBA.R, RGBA.G, RGBA.B, RGBA.A );
        }
        else
        {
            pGraphics.p_color( RGBA.R, RGBA.G, RGBA.B, RGBA.A );
            pGraphics.b_color1( RGBA.R, RGBA.G, RGBA.B, RGBA.A);
        }
    }
    else
    {
        if ( true === PDSE.VisitedHyperlink && ( undefined === this.CtrPrp.Color && undefined === this.CtrPrp.Unifill ) )
        {
            AscFormat.G_O_VISITED_HLINK_COLOR.check(PDSE.Theme, PDSE.ColorMap);
            RGBA = AscFormat.G_O_VISITED_HLINK_COLOR.getRGBAColor();
            pGraphics.p_color( RGBA.R, RGBA.G, RGBA.B, RGBA.A );
            pGraphics.b_color1( RGBA.R, RGBA.G, RGBA.B, RGBA.A );
        }
        else if ( true === CurTextPr.Color.Auto )
        {
            pGraphics.p_color( AutoColor.r, AutoColor.g, AutoColor.b, 255);
            pGraphics.b_color1( AutoColor.r, AutoColor.g, AutoColor.b, 255);
        }
        else
        {
            pGraphics.p_color( CurTextPr.Color.r, CurTextPr.Color.g, CurTextPr.Color.b, 255);
            pGraphics.b_color1( CurTextPr.Color.r, CurTextPr.Color.g, CurTextPr.Color.b, 255);
        }
    }

    if (reviewtype_Common !== this.Get_ReviewType())
    {
        var ReviewColor = this.Get_ReviewColor();
        pGraphics.p_color(ReviewColor.r, ReviewColor.g, ReviewColor.b, 255);
        pGraphics.b_color1(ReviewColor.r, ReviewColor.g, ReviewColor.b, 255);
    }

    if(BgColor == undefined)
        BgColor = new CDocumentColor( 255, 255, 255, false );

    return BgColor;
};
CMathBase.prototype.protected_AddToContent = function(Pos, Items, bUpdatePosition)
{
	History.Add(new CChangesMathBaseAddItems(this, Pos, Items));
	this.raw_AddToContent(Pos, Items, bUpdatePosition);
	this.private_UpdatePosOnAdd(Pos, bUpdatePosition);
};
CMathBase.prototype.protected_RemoveItems = function(Pos, Items, bUpdatePosition)
{
	History.Add(new CChangesMathBaseRemoveItems(this, Pos, Items));

	var Count = Items.length;
	this.raw_RemoveFromContent(Pos, Count);

	// Обновим текущую позицию
	if (this.CurPos > Pos + Count)
		this.CurPos -= Count;
	else if (this.CurPos > Pos)
		this.CurPos = Pos;

	this.private_CorrectCurPos();
	this.private_UpdatePosOnRemove(Pos, Count);
};
CMathBase.prototype.raw_AddToContent = function(Pos, Items, bUpdatePosition)
{
	for (var Index = 0, Count = Items.length; Index < Count; Index++)
	{
		var Item = Items[Index];
		this.Content.splice(Pos + Index, 0, Item);

		if (Item.Set_ParaMath)
			Item.Set_ParaMath(this.ParaMath);

		if (Item.SetParagraph)
			Item.SetParagraph(this.Paragraph);

		Item.ParentElement = this;
	}

	this.fillContent();
};
CMathBase.prototype.raw_RemoveFromContent = function(Pos, Count)
{
    this.Content.splice(Pos, Count);

    this.fillContent();
};
CMathBase.prototype.raw_SetColumn = function(Value)
{
    if(Value > 0)
        this.Pr.Set_Column(Value);
};
CMathBase.prototype.Recalc_RunsCompiledPr = function()
{
    this.RecalcInfo.bCtrPrp = true;

    for(var i=0; i < this.nRow; i++)
        for(var j = 0; j < this.nCol; j++)
        {
            var Item = this.elements[i][j];
            if(!Item.IsJustDraw())
                Item.Recalc_RunsCompiledPr();
        }
};
CMathBase.prototype.GetLastElement = function()
{
    return this;
};
CMathBase.prototype.GetFirstElement = function()
{
    return this;
};
CMathBase.prototype.Recalculate_Range = function(PRS, ParaPr, Depth)
{
    var WordLen = PRS.WordLen; // запоминаем, чтобы внутр мат объекты не увеличили WordLen
    var bContainCompareOper = PRS.bContainCompareOper;

    var bOneLine = PRS.bMath_OneLine;

    this.bOneLine = this.bCanBreak == false || PRS.bMath_OneLine == true;

    if(this.kind !== MATH_DELIMITER)
    {
        this.BrGapLeft  = this.GapLeft;
        this.BrGapRight = this.GapRight;
    }

    if(this.bOneLine == true)
    {
        PRS.bMath_OneLine = this.bOneLine;

        for(var i=0; i < this.nRow; i++)
        {
            for(var j = 0; j < this.nCol; j++)
            {
                var Item = this.elements[i][j];

                if(Item.IsJustDraw()) // для Just-Draw элементов надо выставить Font
                {
                    this.MeasureJustDraw(Item);
                }
                else
                {
                    Item.Recalculate_Reset(PRS.Range, PRS.Line, PRS); // обновим StartLine и StartRange
                    Item.Recalculate_Range(PRS, ParaPr, Depth);
                }
            }
        }

        this.recalculateSize(g_oTextMeasurer);

        this.UpdatePRS_OneLine(PRS, WordLen, PRS.MathFirstItem);
        this.Bounds.SetWidth(0, 0, this.size.width);
        this.Bounds.UpdateMetrics(0, 0, this.size);
    }
    else
    {
        var CurLine  = PRS.Line - this.StartLine;
        var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range );

        this.setDistance();

        var Numb = this.NumBreakContent;

        var Len = this.Content.length;
        var RangeStartPos = this.protected_AddRange(CurLine, CurRange),
            RangeEndPos = Len - 1;

        if(CurLine == 0 && CurRange == 0)
        {
            PRS.WordLen += this.BrGapLeft;
        }

        for(var Pos = RangeStartPos; Pos < Len; Pos++)
        {
            var Item = this.Content[Pos];

            var NeedSetReset = CurLine == 0 && CurRange == 0  || Pos !== RangeStartPos;
            if(Item.Type == para_Math_Content && NeedSetReset)
                Item.Recalculate_Reset(PRS.Range, PRS.Line, PRS); // обновим StartLine и StartRange

            if(Pos == Numb)
            {
                PRS.Update_CurPos(Pos, Depth);
                PRS.bMath_OneLine  = false;

                Item.Recalculate_Range(PRS, ParaPr, Depth+1);

                if(true === PRS.NewRange)
                {
                    RangeEndPos = Numb;
                    break;
                }
            }
            else
            {
                PRS.bMath_OneLine = true;

                var WWordLen = PRS.WordLen;

                Item.Recalculate_Range(PRS, ParaPr, Depth+1);

                PRS.WordLen = WWordLen + Item.size.width;
                PRS.Word    = true;

            }

            if(PRS.NewRange == false && Pos < Len - 1)
                PRS.WordLen += this.dW;
        }

        if(PRS.NewRange == false)
        {
            PRS.WordLen += this.BrGapRight;
        }

        this.protected_FillRange(CurLine, CurRange, RangeStartPos, RangeEndPos);
    }

    PRS.bMath_OneLine = bOneLine;
    PRS.bContainCompareOper = bContainCompareOper;
};
/*CMathBase.prototype.Get_WrapToLine = function(_CurLine, _CurRange, WrapIndent)
{
    var Wrap = 0;

    if(this.bOneLine)
    {
        Wrap = WrapIndent;
    }
    else
    {
        var Pos = this.NumBreakContent;
        Wrap = this.Content[Pos].Get_WrapToLine(_CurLine, _CurRange, WrapIndent);
    }

    return Wrap;
};*/
CMathBase.prototype.RecalculateMinMaxContentWidth = function(MinMax)
{
    var bOneLine = MinMax.bMath_OneLine;

    if(this.kind !== MATH_DELIMITER)
    {
        this.BrGapLeft  = this.GapLeft;
        this.BrGapRight = this.GapRight;
    }

    if(this.bCanBreak == false || MinMax.bMath_OneLine == true)
    {
        MinMax.bMath_OneLine = true;

        for(var i=0; i < this.nRow; i++)
        {
            for(var j = 0; j < this.nCol; j++)
            {
                var Item = this.elements[i][j];

                if(Item.IsJustDraw()) // для Just-Draw элементов надо выставить Font
                {
                    this.MeasureJustDraw(Item);
                }
                else
                {
                    Item.RecalculateMinMaxContentWidth(MinMax);
                }
            }
        }

        this.recalculateSize(g_oTextMeasurer);

        var width = this.size.width;

        if(false === MinMax.bWord)
        {
            MinMax.bWord    = true;
            MinMax.nWordLen = width;
        }
        else
        {
            MinMax.nWordLen += width;
        }

        MinMax.nCurMaxWidth += width;
    }
    else
    {
        this.setDistance();

        var Numb = this.NumBreakContent;
        var Len = this.Content.length;

        if(false === MinMax.bWord)
        {
            MinMax.bWord    = true;
            MinMax.nWordLen = this.BrGapLeft;
        }
        else
        {
            MinMax.nWordLen += this.BrGapLeft;
        }

        MinMax.nCurMaxWidth += this.BrGapLeft;


        for(var Pos = 0; Pos < Len; Pos++)
        {
            var Item = this.Content[Pos];

            MinMax.bMath_OneLine = Pos !== Numb;
            Item.RecalculateMinMaxContentWidth(MinMax);

            if(Pos !== Numb)
            {
                MinMax.nWordLen += Item.size.width;
                MinMax.nCurMaxWidth += Item.size.width;
            }

            if(Pos < Len - 1)
            {
                MinMax.nWordLen += this.dW;
                MinMax.nCurMaxWidth += this.dW;
            }
        }

        MinMax.nWordLen += this.BrGapRight;
        MinMax.nCurMaxWidth += this.BrGapRight;

    }

    MinMax.bMath_OneLine = bOneLine;
};
CMathBase.prototype.MeasureJustDraw = function(Item)
{
    var ctrPrp = this.Get_TxtPrControlLetter();

    var Font =
    {
        FontSize:   ctrPrp.FontSize,
        FontFamily: {Name : ctrPrp.FontFamily.Name, Index : ctrPrp.FontFamily.Index},
        Italic:     false,
        Bold:       false //ctrPrp.Bold
    };

    g_oTextMeasurer.SetFont(Font);

    Item.Measure(g_oTextMeasurer);
};
CMathBase.prototype.UpdatePRS_OneLine = function(PRS, WordLen)
{
    if(this.bInside == false)
    {
        PRS.WordLen = WordLen + this.size.width;
        PRS.MathFirstItem = false;
    }
};
CMathBase.prototype.Recalculate_Range_OneLine = function(PRS, ParaPr, Depth)
{
    this.Recalculate_Range(PRS, ParaPr, Depth);
};
CMathBase.prototype.Recalculate_LineMetrics = function(PRS, ParaPr, _CurLine, _CurRange, ContentMetrics)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = (0 === CurLine ? _CurRange - this.StartRange : _CurRange);

    if(PRS.bFastRecalculate === false)
    {
        this.Bounds.Reset(CurLine, CurRange);
    }

    var StartPos, EndPos;

    if(this.bOneLine)
    {
        var NewContentMetrics = new CMathBoundsMeasures();

        for (var CurPos = 0; CurPos < this.Content.length; CurPos++)
        {
            this.Content[CurPos].Recalculate_LineMetrics(PRS, ParaPr, _CurLine, _CurRange, NewContentMetrics);
        }

        //this.Bounds.UpdateMetrics(CurLine, CurRange, this.size);
        this.Bounds.UpdateMetrics(0, 0, this.size);

        // чтобы внутр объекты не перебили метрики (например, у внутр мат объекта Asc может быть больше Asc текущего объекта)

        ContentMetrics.UpdateMetrics(this.size);

        if(this.Parent.bRoot)
        {
            this.UpdatePRS(PRS, this.size);
        }
    }
    else
    {
        StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
        EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

        for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
        {
            var Item = this.Content[CurPos];
            Item.Recalculate_LineMetrics(PRS, ParaPr, _CurLine, _CurRange, ContentMetrics);

            var BoundItem = Item.Get_LineBound(_CurLine, _CurRange);

            this.Bounds.UpdateMetrics(CurLine, CurRange, BoundItem);
            //ContentMetrics.UpdateMetrics(BoundItem);

            this.UpdatePRS(PRS, BoundItem);
        }
    }
};
CMathBase.prototype.IsEmptyRange = function(_CurLine, _CurRange)
{
    var bEmpty = false;
    var Numb = this.NumBreakContent;

    if(this.bOneLine == false)
    {
        bEmpty = this.Content[Numb].IsEmptyRange(_CurLine, _CurRange);
    }

    return bEmpty;
};
CMathBase.prototype.Is_EmptyRange = function(_CurLine, _CurRange)
{
    return this.bOneLine == true ? false : this.Content[this.NumBreakContent].Is_EmptyRange(_CurLine, _CurRange);
};
CMathBase.prototype.Get_LineBound = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    return this.Bounds.Get_LineBound(CurLine, CurRange);
};
CMathBase.prototype.UpdatePRS = function(PRS, Metric)
{
    var MetricAsc  = Metric.Type == MATH_SIZE ? Metric.ascent : Metric.Asc;
    var MetricDesc = Metric.Type == MATH_SIZE ? Metric.height - Metric.ascent : Metric.H - Metric.Asc;

    if(PRS.LineAscent < MetricAsc)
        PRS.LineAscent = MetricAsc;

    if(PRS.LineDescent < MetricDesc)
        PRS.LineDescent = MetricDesc;


};
CMathBase.prototype.UpdateMetrics = function(PRS, Size)
{
    if(PRS.LineAscent < Size.ascent)
        PRS.LineAscent = Size.ascent;

    if(PRS.LineDescent < Size.height - Size.ascent)
        PRS.LineDescent = Size.height - Size.ascent;
};
CMathBase.prototype.Recalculate_Range_Width = function(PRSC, _CurLine, _CurRange)
{
    var RangeW = PRSC.Range.W;

    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    if(this.bOneLine)
    {
        for (var Pos = 0; Pos <= this.Content.length - 1; Pos++)
        {
            this.Content[Pos].Recalculate_Range_Width( PRSC, _CurLine, _CurRange );
        }

        PRSC.Range.W = RangeW + this.size.width;
    }
    else
    {
        var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
        var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

        if(CurLine == 0 && CurRange == 0)
            PRSC.Range.W += this.BrGapLeft;

        for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
        {
            this.Content[CurPos].Recalculate_Range_Width( PRSC, _CurLine, _CurRange );
        }

        PRSC.Range.W += this.dW*(EndPos - StartPos);

        // Здесь проверяем не на то, что это последний Range (т.к. на данном этапе еще идет вычисление строк) а на конец контента !

        var Len = this.Content.length;
        var EndBrContentEnd = this.NumBreakContent == EndPos && this.Content[EndPos].Math_Is_End( _CurLine, _CurRange),
            NotBrContent = this.NumBreakContent !== EndPos;

        var bEnd = EndBrContentEnd || NotBrContent;

        if(EndPos == Len - 1 && true === bEnd)
        {
            PRSC.Range.W += this.BrGapRight;
        }
    }

    this.Bounds.SetWidth(CurLine, CurRange, PRSC.Range.W - RangeW);
};
CMathBase.prototype.UpdateOperators = function(_CurLine, _CurRange, bEmptyGapLeft, bEmptyGapRight)
{
    if(this.bOneLine == false)
    {
         // Content[this.NumBreakContent] должен содержаться в каждой строке многострочного объекта
         this.Content[this.NumBreakContent].UpdateOperators(_CurLine, _CurRange, bEmptyGapLeft, bEmptyGapRight);
    }

};
CMathBase.prototype.IsShade = function()
{
    var oShd = this.Get_CompiledCtrPrp().Shd;
    return !(oShd === undefined || Asc.c_oAscShdNil === oShd.Value);
};
CMathBase.prototype.Get_Range_VisibleWidth = function(RangeW, _CurLine, _CurRange)
{
    if(this.bOneLine)
    {
        RangeW.W += this.size.width;
    }
    else
    {
        var CurLine  = _CurLine - this.StartLine;
        var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

        var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
        var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

        for (var CurPos = StartPos; CurPos <= EndPos; CurPos++ )
        {
            this.Content[CurPos].Get_Range_VisibleWidth(RangeW, _CurLine, _CurRange);
        }
    }
};
CMathBase.prototype.Displace_BreakOperator = function(isForward, bBrkBefore, CountOperators)
{
	if (!this.Content[this.NumBreakContent])
		return;

    this.Content[this.NumBreakContent].Displace_BreakOperator(isForward, bBrkBefore, CountOperators);
};
CMathBase.prototype.Get_AlignBrk = function(_CurLine, bBrkBefore)
{
    return this.Content[this.NumBreakContent].Get_AlignBrk(_CurLine, bBrkBefore);
};
CMathBase.prototype.raw_SetReviewType = function(Type, Info)
{
    this.ReviewType = Type;
    this.ReviewInfo = Info;
    this.private_UpdateTrackRevisions();
};
CMathBase.prototype.Get_ReviewType = function()
{
    if (this.Id)
        return this.ReviewType;
    else if (this.Parent && this.Parent.Get_ReviewType)
        return this.Parent.Get_ReviewType();

    return reviewtype_Common;
};
CMathBase.prototype.Get_ReviewColor = function()
{
    if (this.Id)
    {
        if (this.ReviewInfo)
            return this.ReviewInfo.Get_Color();
        else
            return new CDocumentColor(255, 0, 0);
    }
    else if (this.Parent && this.Parent.Get_ReviewColor)
    {
        return this.Parent.Get_ReviewColor();
    }

    return REVIEW_COLOR;
};
CMathBase.prototype.Set_ReviewType = function(Type, isSetToContent)
{
	if (!this.Id)
		return;

	if (false !== isSetToContent)
		CParagraphContentWithParagraphLikeContent.prototype.Set_ReviewType.apply(this, arguments);

	if (Type !== this.ReviewType)
	{
		var NewInfo = new CReviewInfo();
		NewInfo.Update();

		History.Add(new CChangesMathBaseReviewType(this, {Type : this.ReviewType, Info : this.ReviewInfo}, {Type : Type, Info : NewInfo}));
		this.raw_SetReviewType(Type, NewInfo);
	}
};
CMathBase.prototype.Set_ReviewTypeWithInfo = function(ReviewType, ReviewInfo)
{
	if (!this.Id)
		return;

	CParagraphContentWithParagraphLikeContent.prototype.Set_ReviewTypeWithInfo.apply(this, arguments);

	History.Add(new CChangesMathBaseReviewType(this, {Type : this.ReviewType, Info : this.ReviewInfo}, {Type : ReviewType, Info : ReviewInfo}));
	this.raw_SetReviewType(ReviewType, ReviewInfo);
};
CMathBase.prototype.Check_RevisionsChanges = function(Checker, ContentPos, Depth)
{
    var ReviewType = this.Get_ReviewType();

    if (true !== Checker.Is_CheckOnlyTextPr())
    {
        if (ReviewType !== Checker.Get_AddRemoveType() || (reviewtype_Common !== ReviewType && this.ReviewInfo.Get_UserId() !== Checker.Get_AddRemoveUserId()))
        {
            Checker.Flush_AddRemoveChange();
            ContentPos.Update(0, Depth);

            if (reviewtype_Add === ReviewType || reviewtype_Remove === ReviewType)
            {
                this.Get_StartPos(ContentPos, Depth);
                Checker.Start_AddRemove(ReviewType, ContentPos);
            }
        }

        if (reviewtype_Add === ReviewType || reviewtype_Remove === ReviewType)
        {
            Checker.Add_Math(this);
            Checker.Update_AddRemoveReviewInfo(this.ReviewInfo);
            this.Get_EndPos(false, ContentPos, Depth);
            Checker.Set_AddRemoveEndPos(ContentPos);

            // Нам нужно проставить конечную позицию в начало следующего рана, чтобы выделился данный элемент целиком
            if (this.Paragraph)
            {
                var TempContentPos = this.Paragraph.Get_PosByElement(this);
                if (TempContentPos)
                {
                    var InParentPos = TempContentPos.Get(TempContentPos.Get_Depth());
                    TempContentPos.Decrease_Depth(1);
                    var Parent = this.Paragraph.Get_ElementByPos(TempContentPos);
                    if (Parent && Parent.Content && this === Parent.Content[InParentPos] && Parent.Content[InParentPos + 1] && para_Math_Run === Parent.Content[InParentPos + 1].Type)
                    {
                        ContentPos.Update(InParentPos + 1, Depth - 1);
                        Parent.Content[InParentPos + 1].Get_StartPos(ContentPos, Depth);
                        Checker.Set_AddRemoveEndPos(ContentPos);
                    }
                }
            }
        }
    }

    if (reviewtype_Common !== ReviewType)
        Checker.Begin_CheckOnlyTextPr();

    CParagraphContentWithParagraphLikeContent.prototype.Check_RevisionsChanges.apply(this, arguments);

    if (reviewtype_Common !== ReviewType)
        Checker.End_CheckOnlyTextPr();
};
CMathBase.prototype.AcceptRevisionChanges = function(Type, bAll)
{
    var ReviewType = this.ReviewType;
    if (reviewtype_Add === ReviewType && (undefined === Type || c_oAscRevisionsChangeType.TextAdd === Type))
    {
        this.Set_ReviewType(reviewtype_Common, false);
    }
    else if (reviewtype_Remove === ReviewType && (undefined === Type || c_oAscRevisionsChangeType.TextRem === Type))
    {
        var Parent = this.Get_Parent();
        var PosInParent = this.Get_PosInParent(Parent);

        if (!Parent || -1 === PosInParent)
        {
            this.Set_ReviewType(reviewtype_Common, false);
        }
        else
        {
            Parent.Remove_FromContent(PosInParent, 1);
            return;
        }
    }

    CParagraphContentWithParagraphLikeContent.prototype.AcceptRevisionChanges.apply(this, arguments);
};
CMathBase.prototype.RejectRevisionChanges = function(Type, bAll)
{
    var ReviewType = this.ReviewType;
    if (reviewtype_Remove === ReviewType && (undefined === Type || c_oAscRevisionsChangeType.TextRem === Type))
    {
        this.Set_ReviewType(reviewtype_Common, false);
    }
    else if (reviewtype_Add === ReviewType && (undefined === Type || c_oAscRevisionsChangeType.TextAdd === Type))
    {
        var Parent = this.Get_Parent();
        var PosInParent = this.Get_PosInParent(Parent);

        if (!Parent || -1 === PosInParent)
        {
            this.Set_ReviewType(reviewtype_Common, false);
        }
        else
        {
            Parent.Remove_FromContent(PosInParent, 1);
            return;
        }
    }

    CParagraphContentWithParagraphLikeContent.prototype.RejectRevisionChanges.apply(this, arguments);
};
CMathBase.prototype.Set_MenuProps = function(Props)
{
    this.Apply_ForcedBreak(Props);

    if(this.Selection.Use == false)
    {
        this.Content[this.CurPos].Set_MenuProps(Props);
    }
    else if(this.Selection.Use == true && this.Selection.StartPos == this.Selection.EndPos)
    {
        var Pos = this.Selection.StartPos;
        this.Content[Pos].Set_MenuProps(Props);
    }
};
CMathBase.prototype.Can_ApplyMenuPropsToObject = function()
{
    var bApplyToCurrent = false;

    if(this.Selection.Use == true && this.Selection.StartPos !== this.Selection.EndPos)
    {
        bApplyToCurrent = true;
    }
    else
    {
        var Pos = this.Selection.Use == false ? this.CurPos : this.Selection.StartPos;
        bApplyToCurrent = true === this.Content[Pos].Is_CurrentContent();
    }

    return bApplyToCurrent;
};
CMathBase.prototype.Get_MenuProps = function()
{
    var Pr = {};
    var Pos = null;

    if(this.Selection.Use == false)
    {
        Pos = this.CurPos;
    }
    else if(this.Selection.StartPos == this.Selection.EndPos)
    {
        Pos = this.Selection.StartPos;
    }

    var bOutsideComposition   = Pos !== null && true == this.Content[Pos].Check_Composition(),
        bSelectAllComposition = Pos == null;

    if(bOutsideComposition)
    {
        Pr = this.Content[Pos].Get_MenuProps();
        this.Can_ModifyForcedBreak(Pr);
    }
    else if(bSelectAllComposition == false)
    {
        Pr = this.Get_InterfaceProps();
        this.Content[Pos].Can_ModifyForcedBreak(Pr);
    }
    else
    {
        Pr = this.Get_InterfaceProps();
    }

    return Pr;
};
CMathBase.prototype.Apply_MenuProps = function()
{};
CMathBase.prototype.Can_ModifyForcedBreak = function(Pr)
{
};
CMathBase.prototype.Apply_ForcedBreak = function()
{
};
CMathBase.prototype.Get_DeletedItemsThroughInterface = function()
{
    var baseContent  = this.getBase();
    var DeletedItems =  baseContent !==  null ? baseContent.Content : null;

    return DeletedItems;
};
CMathBase.prototype.Can_DecreaseArgumentSize = function()
{
    var bDecreaseArgSize = false;

    if(true === this.Can_ModifyArgSize())
    {
        var CompiledArgSize = this.Content[this.CurPos].Get_CompiledArgSize();
        bDecreaseArgSize = CompiledArgSize.Can_Decrease();
    }

    return bDecreaseArgSize;
};
CMathBase.prototype.Can_IncreaseArgumentSize = function()
{
    var bIncreaseArgSize = false;

    if(true === this.Can_ModifyArgSize())
    {
        var CompiledArgSize = this.Content[this.CurPos].Get_CompiledArgSize();
        bIncreaseArgSize = CompiledArgSize.Can_Increase();
    }

    return bIncreaseArgSize;
};
CMathBase.prototype.Get_InterfaceProps = function()
{
    return new CMathMenuBase();
};
CMathBase.prototype.Can_ModifyArgSize = function()
{
    return false;
};
CMathBase.prototype.Is_SelectInside = function()
{
    return this.Selection.Use == true && this.Selection.StartPos !== this.Selection.EndPos;
};
CMathBase.prototype.Can_InsertForcedBreak = function()
{
    return false;
};
CMathBase.prototype.Can_DeleteForcedBreak = function()
{
    return false;
};
CMathBase.prototype.Correct_ContentCurPos = function()
{
    for(var Pos = 0; Pos < this.Content.length; Pos++)
    {
        this.Content[Pos].Correct_ContentCurPos();
    }
};
CMathBase.prototype.Math_Set_EmptyRange         = CMathContent.prototype.Math_Set_EmptyRange;
CMathBase.prototype.Set_ParaMath                = CMathContent.prototype.Set_ParaMath;
CMathBase.prototype.Recalculate_Reset           = CMathContent.prototype.Recalculate_Reset;
CMathBase.prototype.Set_ParaContentPos          = CMathContent.prototype.Set_ParaContentPos;
CMathBase.prototype.Get_CurrentParaPos          = CMathContent.prototype.Get_CurrentParaPos;
CMathBase.prototype.private_UpdatePosOnAdd      = CMathContent.prototype.private_UpdatePosOnAdd;
CMathBase.prototype.private_UpdatePosOnRemove   = CMathContent.prototype.private_UpdatePosOnRemove;
CMathBase.prototype.private_CorrectSelectionPos = CMathContent.prototype.private_CorrectSelectionPos;

CMathBase.prototype.private_CorrectCurPos = function()
{
    if (this.CurPos > this.Content.length - 1)
    {
        this.CurPos = this.Content.length - 1;
        this.Content[this.CurPos].MoveCursorToEndPos(false);
    }

    if (this.CurPos < 0)
    {
        this.CurPos = this.Content.length - 1;
        this.Content[this.CurPos].MoveCursorToStartPos();
    }
};
CMathBase.prototype.Selection_CheckParaContentPos = function(ContentPos, Depth, bStart, bEnd)
{
    if (true !== this.Selection.Use)
        return false;

    var CurPos = ContentPos.Get(Depth);

    if (this.Selection.StartPos === this.Selection.EndPos && this.Selection.StartPos === CurPos)
        return this.Content[CurPos].Selection_CheckParaContentPos(ContentPos, Depth + 1, bStart, bEnd);

    if (this.Selection.StartPos !== this.Selection.EndPos)
        return true;

    return false;
};

CMathBase.prototype.Is_ContentUse = function(MathContent)
{
    for (var Pos = 0, Count = this.Content.length; Pos < Count; Pos++)
    {
        if (MathContent === this.Content[Pos])
            return true;
    }

    return false;
};
CMathBase.prototype.Is_FromDocument = function()
{
	return (this.ParaMath && this.ParaMath.Paragraph && this.ParaMath.Paragraph.bFromDocument);
};
CMathBase.prototype.Clear_ContentChanges = function()
{
	this.m_oContentChanges.Clear();
};
CMathBase.prototype.Add_ContentChanges = function(Changes)
{
	this.m_oContentChanges.Add(Changes);
};
CMathBase.prototype.Refresh_ContentChanges = function()
{
	this.m_oContentChanges.Refresh();
};

function CMathBasePr()
{
}
CMathBasePr.prototype.Set_FromObject  = function(Obj){};
CMathBasePr.prototype.Copy            = function(){return new CMathBasePr();};
CMathBasePr.prototype.Write_ToBinary  = function(Writer){};
CMathBasePr.prototype.Read_FromBinary = function(Reader){};

function CMathBounds()
{
    this.Bounds = [];
}
CMathBounds.prototype.Reset = function(CurLine, CurRange)
{
    if(CurRange == 0)
        this.Bounds.length = CurLine;
};
CMathBounds.prototype.CheckLineBound = function(Line, Range)
{
    if(this.Bounds.length <= Line)
    {
        this.Bounds[Line] = [];
    }

    if(this.Bounds[Line].length <= Range)
    {
        this.Bounds[Line][Range] = new CMathBoundsMeasures();
    }
};
CMathBounds.prototype.UpdateMetrics = function(Line, Range, Metric)
{
    this.CheckLineBound(Line, Range);
    this.Bounds[Line][Range].UpdateMetrics(Metric);
};
CMathBounds.prototype.SetWidth = function(Line, Range, Width)
{
    this.CheckLineBound(Line, Range);
    this.Bounds[Line][Range].SetWidth(Width);
};
CMathBounds.prototype.SetPage = function(Line, Range, Page)
{
    this.CheckLineBound(Line);
    this.Bounds[Line][Range].SetPage(Page);
};
CMathBounds.prototype.Get_Width = function(Line, Range)
{
    this.CheckLineBound(Line);
    return this.Bounds[Line][Range].W;
};
CMathBounds.prototype.GetAscent = function(Line, Range)
{
    this.CheckLineBound(Line);
    return this.Bounds[Line][Range].Asc;
};
CMathBounds.prototype.GetDescent = function(Line, Range)
{
    this.CheckLineBound(Line);
    return this.Bounds[Line][Range].H - this.Bounds[Line][Range].Asc;
};
CMathBounds.prototype.ShiftPage = function(Dx)
{
    var CountLines = this.Bounds.length;

    for(var CurLine = 0; CurLine < CountLines; CurLine++)
    {
        var CountRanges = this.Bounds[CurLine].length;

        for(var CurRange = 0; CurRange < CountRanges; CurRange++)
        {
            this.Bounds[CurLine][CurRange].ShiftPage(Dx);
        }
    }
};
CMathBounds.prototype.Get_Bounds = function()
{
    return this.Bounds;
};
CMathBounds.prototype.Get_LineBound = function(CurLine, CurRange)
{
    var Bound;
    if(CurLine < this.Bounds.length && CurRange < this.Bounds[CurLine].length)
    {
        Bound = this.Bounds[CurLine][CurRange];
    }
    else // заглушка, если еще не пересчитали, а запрос Bonds пришел (например, на поиске)
    {
        Bound = new CMathBoundsMeasures();
    }

    return Bound;
};
CMathBounds.prototype.SetPos = function(Line, Range, Pos)
{
    this.CheckLineBound(Line, Range);
    this.Bounds[Line][Range].SetPos(Pos);
};
CMathBounds.prototype.SetGenPos = function(Line, Range, PRSA)
{
    this.CheckLineBound(Line, Range);
    this.Bounds[Line][Range].SetGenPos(PRSA);
};
CMathBounds.prototype.ShiftPos = function(Line, Range, Dx, Dy)
{
    this.CheckLineBound(Line, Range);
    this.Bounds[Line][Range].ShiftPos(Dx, Dy);
};
CMathBounds.prototype.GetPos = function(Line, Range)
{
    this.CheckLineBound(Line);

    var Pos = new CMathPosition();

    Pos.x = this.Bounds[Line][Range].GetX();
    Pos.y = this.Bounds[Line][Range].GetY();

    return Pos;
};
function CMathBoundsMeasures()
{
    this.Type = MATH_BOUNDS_MEASURES;

    // нужны ля расчета выравниваний относительно операторов
    this._X   = 0;
    this._Y   = 0;
    // необходимы для отрисовки рамки, подсветки
    this.X    = 0;
    this.Y    = 0;

    this.W    = 0;
    this.H    = 0;
    this.Asc  = 0;
    this.Page = 0;
}
CMathBoundsMeasures.prototype.UpdateMetrics = function(Metric)
{
    var MetricH   = Metric.Type == MATH_SIZE ? Metric.height : Metric.H;
    var MetricAsc = Metric.Type == MATH_SIZE ? Metric.ascent : Metric.Asc;

    var Descent = this.H - this.Asc;
    var MetricDescent = MetricH - MetricAsc;

    if(this.Asc < MetricAsc)
        this.Asc = MetricAsc;

    if(Descent < MetricDescent)
    {
        this.H = MetricDescent + this.Asc;
    }
    else
    {
        this.H = Descent + this.Asc;
    }
};
CMathBoundsMeasures.prototype.SetWidth = function(Width)
{
    this.W = Width;
};
CMathBoundsMeasures.prototype.SetGenPos = function(PRSA)
{
    this.X = PRSA.X + this._X;
    this.Y = PRSA.Y + this._Y;
};
CMathBoundsMeasures.prototype.SetPos = function(Pos)
{
    this._X = Pos.x;
    this._Y = Pos.y - this.Asc;
};
CMathBoundsMeasures.prototype.ShiftPos = function(Dx, Dy)
{
    this.X += Dx;
    this.Y += Dy;
};
CMathBoundsMeasures.prototype.GetX = function()
{
    return this.X;
};
CMathBoundsMeasures.prototype.GetY = function()
{
    return this.Y + this.Asc;
};
CMathBoundsMeasures.prototype.SetPage = function(Page)
{
    this.Page = Page;
};
CMathBoundsMeasures.prototype.ShiftPage = function(Dx)
{
    this.Page += Dx;
};

function CEmptyRunRecalculateObject(StartLine, StartRange)
{
    this.StartLine   = StartLine;
    this.StartRange  = StartRange;
    this.Lines       = [];
    this.Content     = [];

    this.WrapState   = ALIGN_EMPTY;
}
CEmptyRunRecalculateObject.prototype =
{
    Save_Lines : function(Obj, Copy)
    {

    },

    Save_Content : function(Obj, Copy)
    {

    },

    Save_WrapState: function(Obj, Copy)
    {

    },

    Load_Lines : function(Obj)
    {

    },

    Load_Content : function(Obj)
    {

    },

    Load_WrapState: function(Obj)
    {

    },

    Save_RunContent : function(Run, Copy)
    {

    },

    Load_RunContent : function(Run)
    {

    },

    Get_DrawingFlowPos : function(FlowPos)
    {

    },

    Compare : function(_CurLine, _CurRange, OtherLinesInfo)
    {
        return true;
    }

};

var c_oMathMenuAction = {
    None                    : 0x00000000,
    RemoveAccentCharacter   : 0x00000001,
    RemoveBar               : 0x00000002,
    InsertMatrixRow         : 0x00000004,
    InsertMatrixColumn      : 0x00000008,
    InsertBefore            : 0x00000010,
    DeleteMatrixRow         : 0x00000020,
    DeleteMatrixColumn      : 0x00000040,
    InsertEquation          : 0x00000080,
    DeleteEquation          : 0x00000100,
    InsertDelimiterArgument : 0x00000200,
    DeleteDelimiterArgument : 0x00000400,
    IncreaseArgumentSize    : 0x00000800,
    DecreaseArgumentSize    : 0x00001000,
    InsertForcedBreak       : 0x00002000,
    DeleteForcedBreak       : 0x00004000,
    AlignToCharacter        : 0x00008000,
    RemoveDelimiter         : 0x00010000,
    RemoveRadical           : 0x00020000

};

function CMathMenuBase(oMath)
{
    this.Type   = Asc.c_oAscMathInterfaceType.Common;
    this.Action = c_oMathMenuAction.None;

    if(oMath == undefined)
    {
        this.CanIncreaseArgumentSize = false;
        this.CanDecreaseArgumentSize = false;
        this.CanInsertForcedBreak    = false;
        this.CanDeleteForcedBreak    = false;
        this.CanAlignToCharacter     = false;
    }
    else
    {
        this.CanIncreaseArgumentSize = oMath.Can_IncreaseArgumentSize();
        this.CanDecreaseArgumentSize = oMath.Can_DecreaseArgumentSize();
        this.CanInsertForcedBreak    = oMath.Can_InsertForcedBreak();
        this.CanDeleteForcedBreak    = oMath.Can_DeleteForcedBreak();
        this.CanAlignToCharacter     = false;
    }
}
CMathMenuBase.prototype.get_Type = function()
{
    return this.Type;
};
CMathMenuBase.prototype.remove_AccentCharacter = function()
{
    this.Action |= c_oMathMenuAction.RemoveAccentCharacter;
};
CMathMenuBase.prototype.remove_Bar = function()
{
    this.Action |= c_oMathMenuAction.RemoveBar;
};
CMathMenuBase.prototype.insert_MatrixRow = function(bBefore)
{
    if (bBefore)
        this.Action |= c_oMathMenuAction.InsertBefore;

    this.Action |= c_oMathMenuAction.InsertMatrixRow;
};
CMathMenuBase.prototype.insert_MatrixColumn = function(bBefore)
{
    if (bBefore)
        this.Action |= c_oMathMenuAction.InsertBefore;

    this.Action |= c_oMathMenuAction.InsertMatrixColumn;
};
CMathMenuBase.prototype.delete_MatrixRow = function()
{
    this.Action |= c_oMathMenuAction.DeleteMatrixRow;
};
CMathMenuBase.prototype.delete_MatrixColumn = function()
{
    this.Action |= c_oMathMenuAction.DeleteMatrixColumn;
};
CMathMenuBase.prototype.insert_Equation = function(bBefore)
{
    if (bBefore)
        this.Action |= c_oMathMenuAction.InsertBefore;

    this.Action |= c_oMathMenuAction.InsertEquation;
};
CMathMenuBase.prototype.delete_Equation = function()
{
    this.Action |= c_oMathMenuAction.DeleteEquation;
};
CMathMenuBase.prototype.insert_DelimiterArgument = function(bBefore)
{
    if (bBefore)
        this.Action |= c_oMathMenuAction.InsertBefore;

    this.Action |= c_oMathMenuAction.InsertDelimiterArgument;
};
CMathMenuBase.prototype.delete_DelimiterArgument = function()
{
    this.Action |= c_oMathMenuAction.DeleteDelimiterArgument;
};
CMathMenuBase.prototype.can_IncreaseArgumentSize = function()
{
    return this.CanIncreaseArgumentSize;
};
CMathMenuBase.prototype.can_DecreaseArgumentSize = function()
{
    return this.CanDecreaseArgumentSize;
};
CMathMenuBase.prototype.increase_ArgumentSize = function()
{
    this.Action |= c_oMathMenuAction.IncreaseArgumentSize;
};
CMathMenuBase.prototype.decrease_ArgumentSize = function()
{
    this.Action |= c_oMathMenuAction.DecreaseArgumentSize;
};
CMathMenuBase.prototype.can_InsertManualBreak = function()
{
    return this.CanInsertForcedBreak;
};
CMathMenuBase.prototype.can_DeleteManualBreak = function()
{
    return this.CanDeleteForcedBreak;
};
CMathMenuBase.prototype.can_AlignToCharacter = function()
{
    return this.CanAlignToCharacter;
};
CMathMenuBase.prototype.insert_ManualBreak = function()
{
    this.Action |= c_oMathMenuAction.InsertForcedBreak;
};
CMathMenuBase.prototype.delete_ManualBreak = function()
{
    this.Action |= c_oMathMenuAction.DeleteForcedBreak;
};
CMathMenuBase.prototype.align_ToCharacter = function()
{
    this.Action |= c_oMathMenuAction.AlignToCharacter;
};
CMathMenuBase.prototype.remove_DelimiterCharacters = function()
{
    this.Action |= c_oMathMenuAction.RemoveDelimiter;
};
CMathMenuBase.prototype.remove_Radical = function()
{
    this.Action |= c_oMathMenuAction.RemoveRadical;
};
CMathMenuBase.prototype.Set_InsertForcedBreak = function()
{
    this.CanInsertForcedBreak = true;
    this.CanDeleteForcedBreak = false;
};
CMathMenuBase.prototype.Set_DeleteForcedBreak = function()
{
    this.CanInsertForcedBreak = false;
    this.CanDeleteForcedBreak = true;
};

window["CMathMenuBase"]                                = CMathMenuBase;
CMathMenuBase.prototype["get_Type"]                    = CMathMenuBase.prototype.get_Type;
CMathMenuBase.prototype["remove_AccentCharacter"]      = CMathMenuBase.prototype.remove_AccentCharacter;
CMathMenuBase.prototype["remove_Bar"]                  = CMathMenuBase.prototype.remove_Bar;
CMathMenuBase.prototype["insert_MatrixRow"]            = CMathMenuBase.prototype.insert_MatrixRow;
CMathMenuBase.prototype["insert_MatrixColumn"]         = CMathMenuBase.prototype.insert_MatrixColumn;
CMathMenuBase.prototype["delete_MatrixRow"]            = CMathMenuBase.prototype.delete_MatrixRow;
CMathMenuBase.prototype["delete_MatrixColumn"]         = CMathMenuBase.prototype.delete_MatrixColumn;
CMathMenuBase.prototype["insert_Equation"]             = CMathMenuBase.prototype.insert_Equation;
CMathMenuBase.prototype["delete_Equation"]             = CMathMenuBase.prototype.delete_Equation;
CMathMenuBase.prototype["insert_DelimiterArgument"]    = CMathMenuBase.prototype.insert_DelimiterArgument;
CMathMenuBase.prototype["delete_DelimiterArgument"]    = CMathMenuBase.prototype.delete_DelimiterArgument;
CMathMenuBase.prototype["can_IncreaseArgumentSize"]    = CMathMenuBase.prototype.can_IncreaseArgumentSize;
CMathMenuBase.prototype["can_DecreaseArgumentSize"]    = CMathMenuBase.prototype.can_DecreaseArgumentSize;
CMathMenuBase.prototype["increase_ArgumentSize"]       = CMathMenuBase.prototype.increase_ArgumentSize;
CMathMenuBase.prototype["decrease_ArgumentSize"]       = CMathMenuBase.prototype.decrease_ArgumentSize;
CMathMenuBase.prototype["can_InsertManualBreak"]       = CMathMenuBase.prototype.can_InsertManualBreak;
CMathMenuBase.prototype["insert_ManualBreak"]          = CMathMenuBase.prototype.insert_ManualBreak;
CMathMenuBase.prototype["can_DeleteManualBreak"]       = CMathMenuBase.prototype.can_DeleteManualBreak;
CMathMenuBase.prototype["delete_ManualBreak"]          = CMathMenuBase.prototype.delete_ManualBreak;
CMathMenuBase.prototype["can_AlignToCharacter"]        = CMathMenuBase.prototype.can_AlignToCharacter;
CMathMenuBase.prototype["align_ToCharacter"]           = CMathMenuBase.prototype.align_ToCharacter;
CMathMenuBase.prototype["remove_DelimiterCharacters"]  = CMathMenuBase.prototype.remove_DelimiterCharacters;
CMathMenuBase.prototype["remove_Radical"]              = CMathMenuBase.prototype.remove_Radical;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var g_oTextMeasurer = AscCommon.g_oTextMeasurer;

function CMathFractionPr()
{
    this.type = BAR_FRACTION;
}
CMathFractionPr.prototype.Set_FromObject = function(Obj)
{
    if (undefined !== Obj.type && null !== Obj.type)
        this.type = Obj.type;
};
CMathFractionPr.prototype.Copy = function(Obj)
{
    var NewPr = new CMathFractionPr();
    NewPr.type = this.type;
    return NewPr;
};
CMathFractionPr.prototype.Write_ToBinary = function(Writer)
{
    // Long : type
    Writer.WriteLong(this.type);
};
CMathFractionPr.prototype.Read_FromBinary = function(Reader)
{
    // Long : type
    this.type = Reader.GetLong();
};

/**
 *
 * @param props
 * @constructor
 * @extends {CMathBase}
 */
function CFraction(props)
{
	CMathBase.call(this);

	this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.Numerator   = null;
    this.Denominator = null;

    this.Pr = new CMathFractionPr();

    if(props !== null && typeof(props) !== "undefined")
        this.init(props);

    AscCommon.g_oTableId.Add( this, this.Id );
}
CFraction.prototype = Object.create(CMathBase.prototype);
CFraction.prototype.constructor = CFraction;

CFraction.prototype.ClassType = AscDFH.historyitem_type_frac;
CFraction.prototype.kind      = MATH_FRACTION;

CFraction.prototype.init = function(props)
{
    this.Fill_LogicalContent(2);

    this.setProperties(props);
    this.fillContent();
};
CFraction.prototype.draw = function(x, y, pGraphics, PDSE)
{
    if(this.Pr.type == BAR_FRACTION || this.Pr.type == NO_BAR_FRACTION)
        this.drawBarFraction(x, y, pGraphics, PDSE);
    else if(this.Pr.type == SKEWED_FRACTION)
        this.drawSkewedFraction(x, y, pGraphics, PDSE);
    else if(this.Pr.type == LINEAR_FRACTION)
        this.drawLinearFraction(x, y, pGraphics, PDSE);
};
CFraction.prototype.Draw_Elements = function(PDSE)
{
    var X = PDSE.X;

    if(this.Pr.type == BAR_FRACTION || this.Pr.type == NO_BAR_FRACTION)
        this.drawBarFraction(PDSE);
    else if(this.Pr.type == SKEWED_FRACTION)
        this.drawSkewedFraction(PDSE);
    else if(this.Pr.type == LINEAR_FRACTION)
        this.drawLinearFraction(PDSE);

    PDSE.X = X + this.size.width;
};
CFraction.prototype.drawBarFraction = function(PDSE)
{
    var mgCtrPrp = this.Get_TxtPrControlLetter();

    var penW = mgCtrPrp.FontSize* 25.4/96 * 0.08;

    var numHeight = this.elements[0][0].size.height;

    var PosLine = this.ParaMath.GetLinePosition(PDSE.Line, PDSE.Range);

    var x1 = this.pos.x + PosLine.x + this.GapLeft,
        x2 = this.pos.x + PosLine.x + this.size.width - this.GapRight,
        y1 = this.pos.y + PosLine.y + numHeight - penW;

    if(this.Pr.type == BAR_FRACTION)
    {
        PDSE.Graphics.SetFont(mgCtrPrp);

        this.Make_ShdColor(PDSE, this.Get_CompiledCtrPrp());
        PDSE.Graphics.drawHorLine(0, y1, x1, x2, penW);
    }

    CMathBase.prototype.Draw_Elements.call(this, PDSE);
};
CFraction.prototype.drawSkewedFraction = function(PDSE)
{
    var mgCtrPrp = this.Get_TxtPrControlLetter();

    var gap = this.dW/2 - mgCtrPrp.FontSize*0.0028;
    var plh = 9.877777777777776 * mgCtrPrp.FontSize / 36;

    var minHeight = 2*this.dW,
        middleHeight = plh*4/3,
        maxHeight = (3*this.dW + 5*plh)*2/3;

	var tg;
    var tg1 = -2.22,
        tg2 = -3.7;

    var PosLine = this.ParaMath.GetLinePosition(PDSE.Line, PDSE.Range);

    var X = this.pos.x + PosLine.x + this.GapLeft,
        Y = this.pos.y + PosLine.y;

    var heightSlash = this.size.height*2/3;

    var x1,  y1,  x2,  y2, b,
        xx1, yy1, xx2, yy2;

    if(heightSlash < maxHeight)
    {
        if(heightSlash < minHeight)
        {
            heightSlash = minHeight;
            tg = tg1;
        }
        else
        {
            heightSlash = this.size.height*2/3;
            tg = (heightSlash - maxHeight)*(tg1 - tg2)/(middleHeight - maxHeight) + tg2;
        }

        b = this.elements[0][0].size.height - tg*(this.elements[0][0].size.width + gap);

        y1 =  this.elements[0][0].size.height/3;
        y2 =  this.elements[0][0].size.height/3 + heightSlash;

        x1 =  (y1 - b)/tg;
        x2 =  (y2 - b)/tg;

        xx1 = X + x1;
        xx2 = X + x2;

        yy1 = Y + y1;
        yy2 = Y + y2;
    }
    else
    {
        heightSlash = maxHeight;
        tg = tg2;
        var coeff = this.elements[0][0].size.height/this.size.height;
        var shift = heightSlash*coeff;

        var minVal = plh/2,
            maxVal = heightSlash - minVal;

        if(shift < minVal)
            shift = minVal;
        else if(shift > maxVal)
            shift = maxVal;

        var y0 = this.elements[0][0].size.height - shift;

        b  = this.elements[0][0].size.height - tg*(this.elements[0][0].size.width + gap);

        y1 = y0;
        y2 = y0 + heightSlash;

        x1 = (y1 - b)/tg;
        x2 = (y2 - b)/tg;

        xx1 = X + x1;
        xx2 = X + x2;

        yy1 = Y + y1;
        yy2 = Y + y2;
    }

    this.drawFractionalLine(PDSE, xx1, yy1, xx2, yy2);

    CMathBase.prototype.Draw_Elements.call(this, PDSE);
};
CFraction.prototype.drawLinearFraction = function(PDSE)
{
    var shift = 0.1*this.dW;

    var PosLine = this.ParaMath.GetLinePosition(PDSE.Line, PDSE.Range);

    var X = this.pos.x + PosLine.x + this.GapLeft,
        Y = this.pos.y + PosLine.y;

    var x1 = X + this.elements[0][0].size.width + this.dW - shift,
        y1 = Y,
        x2 = X + this.elements[0][0].size.width + shift,
        y2 = Y + this.size.height;

    this.drawFractionalLine(PDSE, x1, y1, x2, y2);

    CMathBase.prototype.Draw_Elements.call(this, PDSE);
};
CFraction.prototype.drawFractionalLine = function(PDSE, x1, y1, x2, y2)
{
    var mgCtrPrp = this.Get_TxtPrControlLetter();
    var penW = mgCtrPrp.FontSize*0.0211;

    PDSE.Graphics.SetFont(mgCtrPrp);

    PDSE.Graphics.p_width(penW*1000);

    this.Make_ShdColor(PDSE, this.Get_CompiledCtrPrp());
    PDSE.Graphics._s();

    if(PDSE.Graphics.Start_Command)  // textArt
    {
        var sideY = y2 - y1,
            sideX = x1 - x2;

        var hypoth = Math.sqrt(sideY*sideY + sideX*sideX);

        var sin = sideY/hypoth,
            cos = sideX/hypoth;

        var dx = sin*penW/2, dy = cos*penW/2;

        var xx1 = x1 - dx, yy1 = y1 - dy,
            xx2 = x1 + dx, yy2 = y1 + dy,
            xx3 = x2 + dx, yy3 = y2 + dy,
            xx4 = x2 - dx, yy4 = y2 - dy;

        PDSE.Graphics._m(xx1, yy1);
        PDSE.Graphics._l(xx2, yy2);
        PDSE.Graphics._l(xx3, yy3);
        PDSE.Graphics._l(xx4, yy4);
        PDSE.Graphics._l(xx1, yy1);

        PDSE.Graphics.df();
    }
    else  // чтобы линии были четкие как и раньше, рисуем линию заданной толщины (не в textArt)
    {
        var intGrid = PDSE.Graphics.GetIntegerGrid();
        PDSE.Graphics.SetIntegerGrid(true);

        PDSE.Graphics._s();
        PDSE.Graphics._m(x1, y1);
        PDSE.Graphics._l(x2, y2);
        PDSE.Graphics.ds();

        PDSE.Graphics.SetIntegerGrid(intGrid);
    }

    PDSE.Graphics._s();
};
CFraction.prototype.getNumerator = function()
{
    var numerator;

    if(this.Pr.type == BAR_FRACTION || this.Pr.type == NO_BAR_FRACTION)
        numerator = this.elements[0][0].getElement();
    else
        numerator = this.elements[0][0];

    return numerator;
};
CFraction.prototype.getDenominator = function()
{
    var denominator;

    if(this.Pr.type == BAR_FRACTION || this.Pr.type == NO_BAR_FRACTION)
        denominator = this.elements[1][0].getElement();
    else
        denominator = this.elements[0][1];

    return denominator;
};
CFraction.prototype.getNumeratorMathContent = function()
{
    return this.Content[0];
};
CFraction.prototype.getDenominatorMathContent = function()
{
    return this.Content[1];
};
CFraction.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI, GapsInfo)
{
    this.Parent   = Parent;
    this.ParaMath = ParaMath;

    var ArgSzNumDen = ArgSize.Copy();

    var oMathSettings = Get_WordDocumentDefaultMathSettings();

    var bInlineBarFaction = RPI.bInline == true && (this.Pr.type === BAR_FRACTION || this.Pr.type == NO_BAR_FRACTION),
        bReduceSize       = (RPI.bSmallFraction || RPI.bDecreasedComp == true) && true == oMathSettings.Get_SmallFrac();

    if(bInlineBarFaction || bReduceSize) // уменьшае размер числителя и знаменателя
    {
        ArgSzNumDen.Decrease();        // для контентов числителя и знаменателя
        this.ArgSize.SetValue(-1);     // для CtrPrp
    }
    else if(RPI.bDecreasedComp == true)    // уменьшаем  расстояние между числителем и знаменателем (размер FontSize для TxtPr ControlLetter)
                                            // this.ArgSize отвечает за TxtPr ControlLetter
    {
        this.ArgSize.SetValue(-1); // для CtrPrp
    }
    else
    {
        this.ArgSize.SetValue(0);
    }

    this.Set_CompiledCtrPrp(Parent, ParaMath, RPI);

    this.ApplyProperties(RPI);

    var bDecreasedComp = RPI.bDecreasedComp,
        bSmallFraction = RPI.bSmallFraction;

    if(this.Pr.type !== LINEAR_FRACTION)
        RPI.bDecreasedComp = true;

    RPI.bSmallFraction = true;

    // setGaps обязательно после того как смержили CtrPrp (Set_CompiledCtrPrp)

    if(this.bInside == false)
        GapsInfo.setGaps(this, this.TextPrControlLetter.FontSize);

    this.Numerator.PreRecalc(this, ParaMath, ArgSzNumDen, RPI);
    this.Denominator.PreRecalc(this, ParaMath, ArgSzNumDen, RPI);

    RPI.bDecreasedComp = bDecreasedComp;
    RPI.bSmallFraction = bSmallFraction;
};
CFraction.prototype.Recalculate_Range = function(PRS, ParaPr, Depth)
{
    var WordLen = PRS.WordLen; // запоминаем, чтобы внутр мат объекты не увеличили WordLen
    var bContainCompareOper = PRS.bContainCompareOper;

    var bOneLine = PRS.bMath_OneLine;

    this.bOneLine = this.bCanBreak == false || PRS.bMath_OneLine == true;

    this.BrGapLeft  = this.GapLeft;
    this.BrGapRight = this.GapRight;

    PRS.bMath_OneLine = this.bOneLine;

    this.Numerator.Recalculate_Reset(PRS.Range, PRS.Line, PRS); // обновим StartLine и StartRange
    this.Numerator.Recalculate_Range(PRS, ParaPr, Depth);

    var bNumBarFraction = PRS.bSingleBarFraction;

    this.Denominator.Recalculate_Reset(PRS.Range, PRS.Line, PRS);
    this.Denominator.Recalculate_Range(PRS, ParaPr, Depth);

    var bDenBarFraction = PRS.bSingleBarFraction;

    if(this.Pr.type == BAR_FRACTION || this.Pr.type == NO_BAR_FRACTION)
        this.recalculateBarFraction(g_oTextMeasurer, bNumBarFraction, bDenBarFraction);
    else if(this.Pr.type == SKEWED_FRACTION)
        this.recalculateSkewed(g_oTextMeasurer);
    else if(this.Pr.type == LINEAR_FRACTION)
        this.recalculateLinear(g_oTextMeasurer);

    this.UpdatePRS_OneLine(PRS, WordLen, PRS.MathFirstItem);
    this.Bounds.SetWidth(0, 0, this.size.width);
    this.Bounds.UpdateMetrics(0, 0, this.size);

    PRS.bMath_OneLine       = bOneLine;
    PRS.bContainCompareOper = bContainCompareOper;
};
CFraction.prototype.recalculateBarFraction = function(oMeasure, bNumBarFraction, bDenBarFraction)
{
    var Plh = new CMathText(true);
    Plh.add(0x2B1A);
    this.MeasureJustDraw(Plh);

    var num = this.elements[0][0].size,
        den = this.elements[1][0].size;

    var NumWidth = bNumBarFraction ? num.width + 0.25*Plh.size.width : num.width;
    var DenWidth = bDenBarFraction ? den.width + 0.25*Plh.size.width : den.width;

    var mgCtrPrp = this.Get_TxtPrControlLetter();

    var width  = NumWidth > DenWidth ? NumWidth : DenWidth;
    var height = num.height + den.height;
    var ascent = num.height + this.ParaMath.GetShiftCenter(oMeasure, mgCtrPrp);

    width += this.GapLeft + this.GapRight;

    this.size.height = height;
    this.size.width  = width;
    this.size.ascent = ascent;
};
CFraction.prototype.recalculateSkewed = function(oMeasure)
{
    var mgCtrPrp = this.Get_TxtPrControlLetter();

    this.dW = 5.011235894097222 * mgCtrPrp.FontSize/36;
    var width = this.elements[0][0].size.width + this.dW + this.elements[0][1].size.width;
    var height = this.elements[0][0].size.height + this.elements[0][1].size.height;
    var ascent = this.elements[0][0].size.height + this.ParaMath.GetShiftCenter(oMeasure, mgCtrPrp);

    width += this.GapLeft + this.GapRight;

    this.size.height = height;
    this.size.width  = width;
    this.size.ascent = ascent;
};
CFraction.prototype.recalculateLinear = function()
{
    var AscentFirst   = this.elements[0][0].size.ascent,
        DescentFirst  = this.elements[0][0].size.height - this.elements[0][0].size.ascent,
        AscentSecond  = this.elements[0][1].size.ascent,
        DescentSecond = this.elements[0][1].size.height - this.elements[0][1].size.ascent;

    var H = AscentFirst + DescentSecond;

    var mgCtrPrp = this.Get_TxtPrControlLetter();

    var gap = 5.011235894097222*mgCtrPrp.FontSize/36;

    var H3 = gap*4.942252165543792,
        H4 = gap*7.913378248315688,
        H5 = gap*9.884504331087584;

    if( H < H3 )
        this.dW = gap;
    else if( H < H4 )
        this.dW = 2*gap;
    else if( H < H5 )
        this.dW = 2.8*gap;
    else
        this.dW = 3.4*gap;

    var ascent  = AscentFirst > AscentSecond ? AscentFirst : AscentSecond;
    var descent = DescentFirst > DescentSecond ? DescentFirst : DescentSecond;

    var height = ascent + descent;

    var width = this.elements[0][0].size.width + this.dW + this.elements[0][1].size.width;

    width += this.GapLeft + this.GapRight;

    this.size.height = height;
    this.size.width  = width;
    this.size.ascent = ascent;
};
CFraction.prototype.setPosition = function(pos, PosInfo)
{
    if(this.Pr.type == SKEWED_FRACTION)
    {
        this.UpdatePosBound(pos, PosInfo);

        var Numerator   = this.Content[0],
            Denominator = this.Content[1];

        this.pos.x = pos.x;
        this.pos.y = pos.y - this.size.ascent;

        var X = this.pos.x + this.GapLeft,
            Y = this.pos.y;

        var PosNum = new CMathPosition();

        PosNum.x = X;
        PosNum.y = Y + Numerator.size.ascent;

        var PosDen = new CMathPosition();

        PosDen.x = X + Numerator.size.width + this.dW;
        PosDen.y = Y + Numerator.size.height + Denominator.size.ascent;

        Numerator.setPosition(PosNum, PosInfo);
        Denominator.setPosition(PosDen, PosInfo);

        pos.x += this.size.width;
    }
    else
    {
        CMathBase.prototype.setPosition.call(this, pos, PosInfo);
    }
};
CFraction.prototype.align = function(pos_x, pos_y)
{
    var PosAlign = new CMathPosition();

    if(this.Pr.type == BAR_FRACTION || this.Pr.type == NO_BAR_FRACTION)
    {
        var width = this.size.width - this.GapLeft - this.GapRight;

        if(pos_x == 0)
            PosAlign.x = (width - this.Numerator.size.width)*0.5;
        else
            PosAlign.x = (width - this.Denominator.size.width)*0.5;
    }
    else if(this.Pr.type == LINEAR_FRACTION)
    {
        PosAlign.y = this.size.ascent - this.elements[pos_x][pos_y].size.ascent;
    }

    return PosAlign;
};
CFraction.prototype.fillContent = function()
{
    this.Numerator   = new CNumerator(this.Content[0]);
    this.Denominator = new CDenominator(this.Content[1]);

    if(this.Pr.type == BAR_FRACTION || this.Pr.type == NO_BAR_FRACTION)
    {
        this.setDimension(2, 1);

        this.elements[0][0] = this.Numerator;
        this.elements[1][0] = this.Denominator;
    }
    else if(this.Pr.type == SKEWED_FRACTION)
    {
        this.setDimension(1, 2);
        this.elements[0][0] = this.Numerator.getElement();
        this.elements[0][1] = this.Denominator.getElement();
    }
    else if(this.Pr.type == LINEAR_FRACTION)
    {
        this.setDimension(1, 2);
        this.elements[0][0] = this.Numerator.getElement();
        this.elements[0][1] = this.Denominator.getElement();
    }
};
CFraction.prototype.Apply_MenuProps = function(Props)
{
	if (Props.Type == Asc.c_oAscMathInterfaceType.Fraction && Props.FractionType !== undefined)
	{
		var FractionType = this.Pr.type;

		switch (Props.FractionType)
		{
			case Asc.c_oAscMathInterfaceFraction.Bar:
				FractionType = BAR_FRACTION;
				break;
			case Asc.c_oAscMathInterfaceFraction.Skewed:
				FractionType = SKEWED_FRACTION;
				break;
			case Asc.c_oAscMathInterfaceFraction.Linear:
				FractionType = LINEAR_FRACTION;
				break;
			case Asc.c_oAscMathInterfaceFraction.NoBar:
				FractionType = NO_BAR_FRACTION;
				break;
		}

		if (FractionType !== this.Pr.type)
		{
			AscCommon.History.Add(new CChangesMathFractionType(this, this.Pr.type, FractionType));
			this.raw_SetFractionType(FractionType);
		}
	}
};
CFraction.prototype.Get_InterfaceProps = function()
{
    return new CMathMenuFraction(this);
};
CFraction.prototype.raw_SetFractionType = function(FractionType)
{
    this.Pr.type = FractionType;
    this.fillContent();
};

/**
 *
 * @param CMathMenuFraction
 * @constructor
 * @extends {CMathMenuBase}
 */
function CMathMenuFraction(Fraction)
{
	CMathMenuBase.call(this, Fraction);

    this.Type         = Asc.c_oAscMathInterfaceType.Fraction;

    if (undefined !== Fraction)
    {
        this.FractionType = Asc.c_oAscMathInterfaceFraction.Bar;

        switch (Fraction.Pr.type)
        {
            case BAR_FRACTION:
                this.FractionType = Asc.c_oAscMathInterfaceFraction.Bar;
                break;
            case SKEWED_FRACTION:
                this.FractionType = Asc.c_oAscMathInterfaceFraction.Skewed;
                break;
            case LINEAR_FRACTION:
                this.FractionType = Asc.c_oAscMathInterfaceFraction.Linear;
                break;
            case NO_BAR_FRACTION:
                this.FractionType = Asc.c_oAscMathInterfaceFraction.NoBar;
                break;
        }
    }
    else
    {
        this.FractionType = undefined;
    }
}
CMathMenuFraction.prototype = Object.create(CMathMenuBase.prototype);
CMathMenuFraction.prototype.constructor = CMathMenuFraction;

CMathMenuFraction.prototype.get_FractionType = function(){return this.FractionType;};
CMathMenuFraction.prototype.put_FractionType = function(Type){this.FractionType = Type;};

window["CMathMenuFraction"] = CMathMenuFraction;
CMathMenuFraction.prototype["get_FractionType"] = CMathMenuFraction.prototype.get_FractionType;
CMathMenuFraction.prototype["put_FractionType"] = CMathMenuFraction.prototype.put_FractionType;

/**
 *
 * @param bInside
 * @param MathContent
 * @constructor
 * @extends {CMathBase}
 */
function CFractionBase(bInside, MathContent)
{
	CMathBase.call(this, bInside);
    this.gap = 0;
    this.init(MathContent);
}
CFractionBase.prototype = Object.create(CMathBase.prototype);
CFractionBase.prototype.constructor = CFractionBase;
CFractionBase.prototype.init = function(MathContent)
{
    this.setDimension(1, 1);
    this.elements[0][0] = MathContent;
};
CFractionBase.prototype.getElement = function()
{
    return this.elements[0][0];
};
CFractionBase.prototype.setElement = function(Element)
{
    this.elements[0][0] = Element;
};
CFractionBase.prototype.getPropsForWrite = function()
{
    return {};
};
CFractionBase.prototype.Get_Id = function()
{
    return this.elements[0][0].Get_Id();
};

/**
 *
 * @param MathContent
 * @constructor
 * @extends {CFractionBase}
 */
function CNumerator(MathContent)
{
	CFractionBase.call(this, true, MathContent);
}
CNumerator.prototype = Object.create(CFractionBase.prototype);
CNumerator.prototype.constructor = CNumerator;
CNumerator.prototype.recalculateSize = function()
{
    var arg = this.elements[0][0].size;

    var mgCtrPrp = this.Get_TxtPrControlLetter();

    var Descent = arg.height - arg.ascent; // baseLine

    g_oTextMeasurer.SetFont(mgCtrPrp);
    var Height = g_oTextMeasurer.GetHeight();

    var gapNum, minGap;

    if(this.Parent.kind == MATH_LIMIT || this.Parent.kind == MATH_GROUP_CHARACTER)
    {
        //gapNum = Height/2.4;
        //gapNum = Height/2.97;
        //gapNum = Height/2.97 - Height/10.5;
        gapNum = Height/4.14;
        minGap = Height/13.8;

        //var delta = 0.8076354679802956*gapNum - Descent;
        var delta = gapNum - Descent;
        //this.gap = delta > minGap ? delta - 0.95*minGap: minGap;
        this.gap = delta > minGap ? delta: minGap;
    }
    else    // Fraction
    {
        gapNum = Height/3.05;
        minGap = Height/9.77;

        var delta = gapNum - Descent;
        this.gap = delta > minGap ? delta : minGap;
    }


    var width = arg.width;
    var height = arg.height + this.gap;
    var ascent = arg.ascent;

    this.size.height = height;
    this.size.width  = width;
    this.size.ascent = ascent;
};

/**
 *
 * @param MathContent
 * @constructor
 * @extends {CFractionBase}
 */
function CDenominator(MathContent)
{
	CFractionBase.call(this, true, MathContent);
}
CDenominator.prototype = Object.create(CFractionBase.prototype);
CDenominator.prototype.constructor = CDenominator;
CDenominator.prototype.recalculateSize = function()
{
    var arg = this.elements[0][0].size;

    var mgCtrPrp = this.Get_TxtPrControlLetter();

    var Ascent = arg.ascent -  4.939*mgCtrPrp.FontSize/36;

    g_oTextMeasurer.SetFont(mgCtrPrp);
    var Height = g_oTextMeasurer.GetHeight();

    var gapDen, minGap;

    if(this.Parent.kind == MATH_PRIMARY_LIMIT || this.Parent.kind == MATH_GROUP_CHARACTER)
    {
        gapDen = Height/2.6;
        minGap = Height/10;
    }
    else // Fraction
    {
        gapDen = Height/2.03;
        minGap = Height/6.1;
    }

    var delta = gapDen - Ascent;
    this.gap = delta > minGap ? delta : minGap;


    var width = arg.width;
    var height = arg.height + this.gap;
    var ascent = arg.ascent + this.gap;

    this.size.height = height;
    this.size.width  = width;
    this.size.ascent = ascent;
};
CDenominator.prototype.setPosition = function(pos, PosInfo)
{
    pos.y += this.gap;

	CFractionBase.prototype.setPosition.call(this, pos, PosInfo);
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CFraction = CFraction;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var g_oTextMeasurer = AscCommon.g_oTextMeasurer;

function CMathDegreePr()
{
    this.type = DEGREE_SUPERSCRIPT;
}

CMathDegreePr.prototype.Set_FromObject = function(Obj)
{
    if (DEGREE_SUPERSCRIPT === Obj.type || DEGREE_SUBSCRIPT === Obj.type)
        this.type = Obj.type;
    else
        this.type = DEGREE_SUPERSCRIPT;
};

CMathDegreePr.prototype.Copy = function()
{
    var NewPr = new CMathDegreePr();
    NewPr.type = this.type;
    return NewPr;
};

CMathDegreePr.prototype.Write_ToBinary = function(Writer)
{
    // Long : type
    Writer.WriteLong(this.type);
};

CMathDegreePr.prototype.Read_FromBinary = function(Reader)
{
    // Long : type
    this.type = Reader.GetLong(Reader);
};

/**
 *
 * @param props
 * @param bInside
 * @constructor
 * @extends {CMathBase}
 */
function CDegreeBase(props, bInside)
{
	CMathBase.call(this, bInside);

    this.upBase = 0; // отступ сверху для основания
    this.upIter = 0; // отступ сверху для итератора

    this.Pr = new CMathDegreePr();

    this.baseContent = null;
    this.iterContent = null;

    this.bNaryInline = false;

    if(props !== null && typeof(props) !== "undefined")
        this.init(props);
}
CDegreeBase.prototype = Object.create(CMathBase.prototype);
CDegreeBase.prototype.constructor = CDegreeBase;
CDegreeBase.prototype.init = function(props)
{
    this.setProperties(props);
    this.setDimension(1, 2);
};
CDegreeBase.prototype.fillContent = function()
{
    this.setDimension(1, 2);
    this.elements[0][0] = this.baseContent;
    this.elements[0][1] = this.iterContent;
};
CDegreeBase.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI, GapsInfo)
{
    this.Parent = Parent;
    this.ParaMath = ParaMath;

    this.Set_CompiledCtrPrp(Parent, ParaMath, RPI);

    this.ApplyProperties(RPI);

    if(this.bInside == false)
        GapsInfo.setGaps(this, this.TextPrControlLetter.FontSize);

    this.baseContent.PreRecalc(this, ParaMath, ArgSize, RPI);

    var ArgSzDegr = ArgSize.Copy();
    ArgSzDegr.Decrease();

    this.bNaryInline = RPI.bNaryInline;

    var bDecreasedComp = RPI.bDecreasedComp;
    RPI.bDecreasedComp = true;

    this.iterContent.PreRecalc(this, ParaMath, ArgSzDegr, RPI);

    RPI.bDecreasedComp = bDecreasedComp;
};
CDegreeBase.prototype.Resize = function(oMeasure, RPI)
{
    this.baseContent.Resize(oMeasure, RPI);

    this.iterContent.Resize(oMeasure, RPI);

    this.setDistance();

    if(this.Pr.type === DEGREE_SUPERSCRIPT)
        this.GetSizeSup(oMeasure);
    else if(this.Pr.type === DEGREE_SUBSCRIPT)
        this.GetSizeSubScript(oMeasure);
};
CDegreeBase.prototype.recalculateSize = function(oMeasure)
{
    var Metric = new CMathBoundsMeasures();
    Metric.UpdateMetrics(this.baseContent.size);
    Metric.SetWidth(this.baseContent.size.width);

    this.setDistance();

    var ResultSize;

    if(this.Pr.type === DEGREE_SUPERSCRIPT)
    {
        ResultSize = this.GetSizeSup(oMeasure, Metric);
    }
    else if(this.Pr.type === DEGREE_SUBSCRIPT)
    {
        ResultSize = this.GetSizeSubScript(oMeasure, Metric);
    }

    this.size.Set(ResultSize);
};
CDegreeBase.prototype.GetSizeSup = function(oMeasure, Metric)
{
    var iter       = this.iterContent.size,
        baseAsc    = Metric.Asc,
        baseHeight = Metric.H,
        baseWidth  = Metric.W;

    var mgCtrPrp = this.Get_TxtPrControlLetter();

    this.upBase = 0;
    this.upIter = 0;

    var bTextElement = false,
        lastElem;

    if(!this.baseContent.IsJustDraw())
    {
        lastElem = this.baseContent.GetLastElement();

        var bSameFontSize  = lastElem.Type == para_Math_Run && lastElem.Math_CompareFontSize(mgCtrPrp.FontSize, false);
        bTextElement = bSameFontSize || (lastElem.Type !== para_Math_Run && lastElem.IsJustDraw());
    }

    var PlH = 0.64*this.ParaMath.GetPlh(oMeasure, mgCtrPrp);
    var UpBaseline = 0.75*PlH; // расстояние от baseline основания до бейзлайна итератора

    if(bTextElement)
    {
        var last = lastElem.size,
            upBaseLast = 0,
            upBaseIter = 0;

        if( (last.ascent - UpBaseline) + (iter.height - iter.ascent) >  (last.ascent - 2/9*PlH) )
            upBaseLast = iter.height - (last.ascent - 2/9*PlH);
        else if(UpBaseline + iter.ascent > last.ascent)
            upBaseLast = UpBaseline + iter.ascent - last.ascent;
        else
            upBaseIter = last.ascent - UpBaseline - iter.ascent;

        if(upBaseLast + last.ascent > baseAsc)
        {
            this.upBase = upBaseLast - (baseAsc - last.ascent);
            this.upIter = upBaseIter;
        }
        else
        {
            this.upBase = 0;
            this.upIter = (baseAsc - upBaseLast - last.ascent) + upBaseIter;
        }
    }
    else
    {
        var shCenter = this.ParaMath.GetShiftCenter(oMeasure, mgCtrPrp);

        if(iter.height - iter.ascent + shCenter > baseAsc) // для дробей и т.п.
        {
            this.upBase = iter.height - (baseAsc - shCenter);
        }
        else if(iter.ascent > shCenter)
        {
            this.upBase = iter.ascent - shCenter;
        }
        else
        {
            this.upIter = shCenter - iter.ascent;
        }
    }

    var height = this.upBase + baseHeight;
    var ascent = this.upBase + baseAsc;

    this.upIter -= ascent;

    var width = baseWidth + iter.width + this.dW;
    width += this.GapLeft + this.GapRight;

    var ResultSize = new CMathSize();

    ResultSize.height = height;
    ResultSize.width  = width;
    ResultSize.ascent = ascent;

    return ResultSize;
};
CDegreeBase.prototype.GetSizeSubScript = function(oMeasure, Metric)
{
    var iter       = this.iterContent.size,
        baseAsc    = Metric.Asc,
        baseHeight = Metric.H,
        baseWidth  = Metric.W;

    var mgCtrPrp = this.Get_TxtPrControlLetter();
    var shCenter = this.ParaMath.GetShiftCenter(oMeasure, mgCtrPrp);

    var bTextElement = false;

    if(!this.baseContent.IsJustDraw())
    {
        var lastElem = this.baseContent.GetLastElement();

        var bSameFontSize  = lastElem.Type == para_Math_Run && lastElem.Math_CompareFontSize(mgCtrPrp.FontSize, false);
        bTextElement      = bSameFontSize || (lastElem.Type !== para_Math_Run && lastElem.IsJustDraw());
    }

    var height, ascent, descent;

    var PlH = 0.64*this.ParaMath.GetPlh(oMeasure, mgCtrPrp);

    if(bTextElement)
    {
        //var last = lastElem.size;
        var DownBaseline = 0.9*shCenter;

        if(iter.ascent - DownBaseline > 3/4*PlH)
            this.upIter = 1/4*PlH;
        else
            this.upIter = PlH + DownBaseline - iter.ascent;

        if(baseAsc > PlH)
        {
            this.upIter += baseAsc - PlH;
        }

        //this.upIter = base.ascent + DownBaseline - iter.ascent;

        var descentBase = baseHeight - baseAsc,
            descentIter = this.upIter + iter.height - baseAsc;

        descent = descentBase > descentIter ? descentBase : descentIter;
        ascent  = baseAsc;

        height = ascent + descent;
    }
    else
    {
        this.upIter = baseHeight + shCenter - iter.ascent;

        // ограничение для случая, когда аскент итератора >> высоты основания
        if(baseAsc - 1.5*shCenter > this.upIter)
            this.upIter = baseAsc - 1.5*shCenter;

        height = this.upIter + iter.height;
        ascent = baseAsc;
    }

    this.upIter -= ascent;

    var width = baseWidth + iter.width + this.dW;
    width += this.GapLeft + this.GapRight;

    var ResultSize = new CMathSize();

    ResultSize.height = height;
    ResultSize.width  = width;
    ResultSize.ascent = ascent;

    return ResultSize;
};
CDegreeBase.prototype.setDistance = function()
{
    var mgCtrPrp = this.Get_TxtPrControlLetter();
    var PlH = 0.64*this.ParaMath.GetPlh(g_oTextMeasurer, mgCtrPrp);

    if( this.bNaryInline)
        this.dW = 0.17*PlH;
    else
        this.dW = 0.056*PlH;
};
CDegreeBase.prototype.setPosition = function(pos, PosInfo)
{
    this.UpdatePosBound(pos, PosInfo);

    var Line  = PosInfo.CurLine,
        Range = PosInfo.CurRange;
    var CurLine = Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? Range - this.StartRange : Range );

    var X, Y;

    if(this.bOneLine)
    {
        this.pos.x = pos.x;

        if(this.bInside === true)
        {
            this.pos.y = pos.y;
        }
        else
        {
            this.pos.y = pos.y - this.size.ascent;
        }
        X = this.pos.x + this.BrGapLeft;
        Y = this.pos.y;

        var PosBase = new CMathPosition();
        PosBase.y = Y;
        PosBase.x = X;

        PosBase.y += this.size.ascent - this.baseContent.size.ascent;

        if(!this.baseContent.IsJustDraw())
            PosBase.y += this.baseContent.size.ascent;

        this.baseContent.setPosition(PosBase, PosInfo);

        var PosIter = new CMathPosition();
        PosIter.x = X + this.baseContent.size.width + this.dW;
        PosIter.y = Y + this.size.ascent + this.upIter + this.iterContent.size.ascent;

        this.iterContent.setPosition(PosIter, PosInfo);

        pos.x += this.size.width;
    }
    else
    {
        if(CurLine == 0 && CurRange == 0)
            pos.x += this.BrGapLeft;

        Y = pos.y;

        this.baseContent.setPosition(pos, PosInfo);

        var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);
        var Lng = this.Content.length;

        if(EndPos == Lng - 1)
        {
            pos.x += this.dW;

            pos.y += this.upIter + this.iterContent.size.ascent;

            this.iterContent.setPosition(pos, PosInfo);

            pos.x += this.BrGapRight;
        }

        pos.y = Y;
    }
};
CDegreeBase.prototype.getIterator = function()
{
    return this.iterContent;
};
CDegreeBase.prototype.getUpperIterator = function()
{
    return this.iterContent;
};
CDegreeBase.prototype.getLowerIterator = function()
{
    return this.iterContent;
};
CDegreeBase.prototype.getBase = function()
{
    return this.baseContent;
};
CDegreeBase.prototype.IsPlhIterator = function()
{
    return this.iterContent.IsPlaceholder();
};
CDegreeBase.prototype.setBase = function(base)
{
    this.baseContent = base;
};
CDegreeBase.prototype.setIterator = function(iterator)
{
    this.iterContent = iterator;
};

/**
 *
 * @param props
 * @param bInside
 * @constructor
 * @extends {CDegreeBase}
 */
function CDegree(props, bInside)
{
	CDegreeBase.call(this, props, bInside);

    this.Id = AscCommon.g_oIdCounter.Get_NewId();

    if(props !== null && typeof(props) !== "undefined")
        this.init(props);

    AscCommon.g_oTableId.Add( this, this.Id );
}
CDegree.prototype = Object.create(CDegreeBase.prototype);
CDegree.prototype.constructor = CDegree;
CDegree.prototype.ClassType = AscDFH.historyitem_type_deg;
CDegree.prototype.kind      = MATH_DEGREE;
CDegree.prototype.init = function(props)
{
    this.Fill_LogicalContent(2);

    this.setProperties(props);
    this.fillContent();
};
CDegree.prototype.fillContent = function()
{
    this.NeedBreakContent(0);

    this.iterContent = this.Content[1];
    this.baseContent = this.Content[0];

    CDegreeBase.prototype.fillContent.call(this);
};
CDegree.prototype.Recalculate_LineMetrics = function(PRS, ParaPr, _CurLine, _CurRange, ContentMetrics)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = (0 === CurLine ? _CurRange - this.StartRange : _CurRange);

    if(PRS.bFastRecalculate === false)
    {
        this.Bounds.Reset(CurLine, CurRange);
    }

    if(this.bOneLine == false && this.baseContent.Math_Is_End( _CurLine, _CurRange))
    {
        // чтобы при вычислении метрик итератора не были перебили метрики (например, у внутр мат объекта Asc может быть больше Asc текущего объекта)

        var NewContentMetrics = new CMathBoundsMeasures();
        this.iterContent.Recalculate_LineMetrics(PRS, ParaPr, _CurLine, _CurRange, NewContentMetrics);
        this.baseContent.Recalculate_LineMetrics(PRS, ParaPr, _CurLine, _CurRange, NewContentMetrics);

        var BoundBase = this.baseContent.Get_LineBound(_CurLine, _CurRange);
        var Bound;

        if(this.Pr.type === DEGREE_SUPERSCRIPT)
        {
            Bound = this.GetSizeSup(g_oTextMeasurer, BoundBase);
        }
        else
        {
            Bound = this.GetSizeSubScript(g_oTextMeasurer, BoundBase);
        }

        this.Bounds.UpdateMetrics(CurLine, CurRange, Bound);
        ContentMetrics.UpdateMetrics(Bound);

        this.UpdatePRS(PRS, Bound);
    }
    else
    {
        CDegreeBase.prototype.Recalculate_LineMetrics.call(this, PRS, ParaPr, _CurLine, _CurRange, ContentMetrics);
    }

};
CDegree.prototype.setPosition = function(pos, PosInfo)
{
    var Line  = PosInfo.CurLine,
        Range = PosInfo.CurRange;
    var CurLine = Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? Range - this.StartRange : Range );

    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);
    var Len = this.Content.length;

    // у степени всегда итератор идет в конце, поэтому сделать проверку на то, что текущий контент последний (т.е. это и будет итератор)

    if(this.bOneLine || EndPos == Len - 1)
    {
        CDegreeBase.prototype.setPosition.call(this, pos, PosInfo);
    }
    else
    {
        CMathBase.prototype.setPosition.call(this, pos, PosInfo);
    }
};
CDegree.prototype.Get_InterfaceProps = function()
{
    var Type = this.Pr.type == DEGREE_SUBSCRIPT ? Asc.c_oAscMathInterfaceScript.Sub : Asc.c_oAscMathInterfaceScript.Sup;
    return new CMathMenuScript(this, Type);
};
CDegree.prototype.Can_ModifyArgSize = function()
{
    return this.CurPos == 1 && false === this.Is_SelectInside(); // находимся в итераторе
};

/**
 *
 * @param iterUp
 * @param iterDn
 * @constructor
 * @extends {CMathBase}
 */
function CIterators(iterUp, iterDn)
{
	CMathBase.call(this, true);

    this.iterUp = iterUp;
    this.iterDn = iterDn;
}
CIterators.prototype = Object.create(CMathBase.prototype);
CIterators.prototype.constructor = CIterators;
CIterators.prototype.init = function()
{
    this.setDimension(2, 1);
    this.elements[0][0] = this.iterUp;
    this.elements[1][0] = this.iterDn;
};
CIterators.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI, GapsInfo)
{
    this.Parent = Parent;
    this.ParaMath = ParaMath;

    this.ArgSize.SetValue(-1);

    var ArgSzIters = ArgSize.Copy();
    ArgSzIters.Merge(this.ArgSize);

    this.Set_CompiledCtrPrp(Parent, ParaMath, RPI);

    var bDecreasedComp = RPI.bDecreasedComp;
    RPI.bDecreasedComp = true;

    this.iterUp.PreRecalc(this, ParaMath, ArgSzIters, RPI);
    this.iterDn.PreRecalc(this, ParaMath, ArgSzIters, RPI);

    RPI.bDecreasedComp = bDecreasedComp;
};
CIterators.prototype.recalculateSize = function(oMeasure, dH, ascent)
{
    this.dH = dH;

    var iterUp = this.iterUp.size,
        iterDown = this.iterDn.size;

    this.size.ascent = ascent;
    this.size.height = iterUp.height + dH + iterDown.height;
    this.size.width  = iterUp.width > iterDown.width ? iterUp.width : iterDown.width;

};
CIterators.prototype.getUpperIterator = function()
{
    return this.elements[0][0];
};
CIterators.prototype.getLowerIterator = function()
{
    return this.elements[1][0];
};
CIterators.prototype.setUpperIterator = function(iterator)
{
    this.elements[0][0] = iterator;
};
CIterators.prototype.setLowerIterator = function(iterator)
{
    this.elements[1][0] = iterator;
};
CIterators.prototype.alignIterators = function(mcJc)
{
    this.alignment.wdt[0] = mcJc;
};
CIterators.prototype.setPosition = function(pos, PosInfo)
{
     this.pos.x = pos.x;
     this.pos.y = pos.y;

    var UpIterPos = new CMathPosition();
    var al = this.align(0, 0);

    UpIterPos.x = this.pos.x + this.GapLeft + al.x;
    UpIterPos.y = this.pos.y + this.iterUp.size.ascent;

    var DownIterPos = new CMathPosition();
    al = this.align(1, 0);

    DownIterPos.x = this.pos.x + this.GapLeft + al.x;
    DownIterPos.y = this.pos.y + this.dH + this.iterUp.size.height + this.iterDn.size.ascent;

    // сначала выставляем setPosition у верхнего итератора, потом у нижнего
    // такой порядок нужен для выравнивания Box по операторам (так же как в Ворде)

    this.iterDn.setPosition(DownIterPos, PosInfo);
    this.iterUp.setPosition(UpIterPos, PosInfo);

    pos.x += this.size.width;
};

function CMathDegreeSubSupPr()
{
    this.type   = DEGREE_SubSup;
    this.alnScr = false;// не выровнены, итераторы идут в соответствии с наклоном буквы/мат. объекта
}

CMathDegreeSubSupPr.prototype.Set_FromObject = function(Obj)
{
    if (true === Obj.alnScr || 1 === Obj.alnScr)
        this.alnScr = true;
    else
        this.alnScr = false;

    if (DEGREE_SubSup === Obj.type || DEGREE_PreSubSup === Obj.type)
        this.type = Obj.type;
};

CMathDegreeSubSupPr.prototype.Copy = function()
{
    var NewPr = new CMathDegreeSubSupPr();

    NewPr.type   = this.type;
    NewPr.alnScr = this.alnScr;

    return NewPr;
};

CMathDegreeSubSupPr.prototype.Write_ToBinary = function(Writer)
{
    // Long : type
    // Bool : alnScr

    Writer.WriteLong(this.type);
    Writer.WriteBool(this.alnScr);
};

CMathDegreeSubSupPr.prototype.Read_FromBinary = function(Reader)
{
    // Long : type
    // Bool : alnScr

    this.type   = Reader.GetLong();
    this.alnScr = Reader.GetBool();
};

/**
 *
 * @param props
 * @param bInside
 * @constructor
 * @extends {CMathBase}
 */
function CDegreeSubSupBase(props, bInside)
{
	CMathBase.call(this, bInside);

    this.bNaryInline = false;

    this.Pr = new CMathDegreeSubSupPr();

    this.baseContent = null;
    this.iters       = new CIterators(null, null);

    if(props !== null && typeof(props) !== "undefined")
        this.init(props);
}
CDegreeSubSupBase.prototype = Object.create(CMathBase.prototype);
CDegreeSubSupBase.prototype.constructor = CDegreeSubSupBase;
CDegreeSubSupBase.prototype.init = function(props)
{
    this.setProperties(props);
    this.setDimension(1, 2);
};
CDegreeSubSupBase.prototype.fillContent = function()
{
    var oBase  = this.baseContent;
    var oIters = this.iters;

    this.setDimension(1, 2);

    oIters.init();

    if(this.Pr.type == DEGREE_SubSup)
    {
        oIters.alignIterators(MCJC_LEFT);
        this.addMCToContent([oBase, oIters]);
    }
    else if(this.Pr.type == DEGREE_PreSubSup)
    {
        this.addMCToContent([oIters, oBase]);
        oIters.alignIterators(MCJC_RIGHT);
    }
};
CDegreeSubSupBase.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI, GapsInfo)
{
    this.bNaryInline = RPI.bNaryInline;

	CMathBase.prototype.PreRecalc.call(this, Parent, ParaMath, ArgSize, RPI, GapsInfo);
};
CDegreeSubSupBase.prototype.recalculateSize = function(oMeasure)
{
    var Metric = new CMathBoundsMeasures();
    Metric.UpdateMetrics(this.baseContent.size);
    Metric.SetWidth(this.baseContent.size.width);

    var ResultSize = this.GetSize(oMeasure, Metric);

    this.size.Set(ResultSize);
};
CDegreeSubSupBase.prototype.GetSize = function(oMeasure, Metric)
{
    var mgCtrPrp = this.Get_CompiledCtrPrp(); // Get_CompiledCtrPrp -  чтобы итераторы не разъезжались
    // половину ascent брать нельзя, т.к. черта дроби будет разделительной для верхнего и нижнего итератора => соответственно
    // если числитель меньше/больше знаменателя расположение итераторов у степени будет неправильным

    var iterUp   = this.iters.iterUp.size,
        iterDown = this.iters.iterDn.size;

    var baseAsc    = Metric.Asc,
        baseHeight = Metric.H,
        baseWidth  = Metric.W;

    var shCenter = 1.4*this.ParaMath.GetShiftCenter(oMeasure, mgCtrPrp);

    var PlH = 0.26*this.ParaMath.GetPlh(oMeasure, mgCtrPrp);

    var height, width, ascent, descent;

    var dH; // of Iterators
    var minGap;

    var TextElement = false;

    if(!this.baseContent.IsJustDraw())
    {
        var bFirstItem = this.Pr.type == DEGREE_SubSup;
        var BaseItem = bFirstItem ? this.baseContent.GetLastElement() : this.baseContent.GetFirstElement();

        var bSameFontSize  = BaseItem.Type == para_Math_Run && BaseItem.Math_CompareFontSize(mgCtrPrp.FontSize, bFirstItem);
        TextElement  = bSameFontSize || (BaseItem.Type !== para_Math_Run && BaseItem.IsJustDraw());
    }

    if(TextElement)
    {
        minGap =  0.5*PlH;

        var DivBaseline = 3.034*PlH;
        var ascIters, dgrHeight;

        if(DivBaseline > minGap + iterDown.ascent + (iterUp.height - iterUp.ascent))
        {
            dH = DivBaseline - iterDown.ascent - (iterUp.height - iterUp.ascent);
        }
        else
        {
            dH = minGap;
        }

        var GapDown = PlH;

        ascIters = iterUp.height + dH + GapDown;
        dgrHeight = iterDown.height + iterUp.height + dH;

        ascent = ascIters > baseAsc ? ascIters : baseAsc;

        var dscIter = dgrHeight - ascIters,
            dscBase = baseHeight - baseAsc;

        descent = dscIter > dscBase ? dscIter : dscBase;
        height = ascent + descent;

        this.iters.recalculateSize(oMeasure, dH, ascIters /*ascent of Iterators*/);
    }
    else
    {
        minGap =  0.7*PlH;

        var lUpBase    = baseAsc - shCenter; // center of base
        var lDownBase  = baseHeight - lUpBase; // height - center of base


        var DescUpIter  = iterUp.height - iterUp.ascent + PlH;
        var AscDownIter = iterDown.ascent - PlH;

        var UpGap, DownGap;

        if(this.bNaryInline)
        {
            UpGap   = 0;
            DownGap = 0;
        }
        else
        {
            UpGap   = lUpBase > DescUpIter    ? lUpBase   - DescUpIter  : 0;           // расстояние от центра основания до верхнего итератора
            DownGap = lDownBase > AscDownIter ? lDownBase - AscDownIter : 0;           // расстояние от центра основания до нижнего итератора
        }

        if(UpGap + DownGap > minGap)
            dH = UpGap + DownGap;
        else
            dH = minGap;

        height = iterUp.height + dH + iterDown.height;
        ascent = iterUp.height + UpGap + shCenter;

        this.iters.recalculateSize(oMeasure, dH, ascent/*ascent of Iterators*/);
    }

    if( this.bNaryInline)
        this.dW = 0.42*PlH;
    else
        this.dW = 0.14*PlH;

    width  = this.iters.size.width + baseWidth + this.dW;
    width += this.GapLeft + this.GapRight;

    var ResultSize = new CMathSize();

    ResultSize.height = height;
    ResultSize.width  = width;
    ResultSize.ascent = ascent;

    return ResultSize;
};
CDegreeSubSupBase.prototype.getBase = function()
{
    return this.baseContent;
};
CDegreeSubSupBase.prototype.getUpperIterator = function()
{
    return this.iters.iterUp;
};
CDegreeSubSupBase.prototype.getLowerIterator = function()
{
    return this.iters.iterDn;
};
CDegreeSubSupBase.prototype.setBase = function(base)
{
    this.baseContent = base;
};
CDegreeSubSupBase.prototype.setUpperIterator = function(iterator)
{
    this.iters.iterUp = iterator;
};
CDegreeSubSupBase.prototype.setLowerIterator = function(iterator)
{
    this.iters.iterDn = iterator;
};

/**
 *
 * @param props
 * @param bInside
 * @constructor
 * @extends {CDegreeSubSupBase}
 */
function CDegreeSubSup(props, bInside)
{
	CDegreeSubSupBase.call(this, props, bInside);

    this.Id = AscCommon.g_oIdCounter.Get_NewId();

    if(props !== null && typeof(props) !== "undefined")
        this.init(props);

    AscCommon.g_oTableId.Add( this, this.Id );
}
CDegreeSubSup.prototype = Object.create(CDegreeSubSupBase.prototype);
CDegreeSubSup.prototype.constructor = CDegreeSubSup;
CDegreeSubSup.prototype.ClassType = AscDFH.historyitem_type_deg_subsup;
CDegreeSubSup.prototype.kind      = MATH_DEGREESubSup;
CDegreeSubSup.prototype.init = function(props)
{
    this.Fill_LogicalContent(3);

    this.setProperties(props);
    this.fillContent();
};
CDegreeSubSup.prototype.fillContent = function()
{
    if(this.Pr.type == DEGREE_SubSup)
    {
        this.bCanBreak       = true;
        this.NumBreakContent = 0;
    }
    else
    {
        this.bCanBreak       = false;
    }

     this.baseContent = this.Content[0];
     this.iters = new CIterators(this.Content[1], this.Content[2]);

    CDegreeSubSupBase.prototype.fillContent.call(this);
};
CDegreeSubSup.prototype.Recalculate_LineMetrics = function(PRS, ParaPr, _CurLine, _CurRange, ContentMetrics)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = (0 === CurLine ? _CurRange - this.StartRange : _CurRange);

    if(PRS.bFastRecalculate === false)
    {
        this.Bounds.Reset(CurLine, CurRange);
    }

    if(this.bOneLine === false && true === this.Need_Iters(_CurLine, _CurRange))
    {
        // чтобы при вычислении метрик итератора не были перебили метрики (например, у внутр мат объекта Asc может быть больше Asc текущего объекта)

        var NewContentMetrics = new CMathBoundsMeasures();

        this.Content[1].Recalculate_LineMetrics(PRS, ParaPr, _CurLine, _CurRange, NewContentMetrics);
        this.Content[2].Recalculate_LineMetrics(PRS, ParaPr, _CurLine, _CurRange, NewContentMetrics);
        // основание, baseContent
        this.Content[0].Recalculate_LineMetrics(PRS, ParaPr, _CurLine, _CurRange, NewContentMetrics);

        var BoundBase = this.baseContent.Get_LineBound(_CurLine, _CurRange);

        var Bound = this.GetSize(g_oTextMeasurer, BoundBase);
        this.Bounds.UpdateMetrics(CurLine, CurRange, Bound);
        ContentMetrics.UpdateMetrics(Bound);

        this.iters.Recalculate_Reset( PRS.Range, PRS.Line, PRS );
        this.iters.Bounds.Reset(0, 0);
        this.iters.Bounds.UpdateMetrics(0, 0, this.iters.size);

        this.UpdatePRS(PRS, Bound);
    }
    else
    {
        CDegreeSubSupBase.prototype.Recalculate_LineMetrics.call(this, PRS, ParaPr, _CurLine, _CurRange, ContentMetrics);
    }

};
CDegreeSubSup.prototype.Recalculate_Range = function(PRS, ParaPr, Depth)
{
    this.bOneLine = this.bCanBreak == false || PRS.bMath_OneLine == true;

    if(this.bOneLine === true)
    {
        CDegreeSubSupBase.prototype.Recalculate_Range.call(this, PRS, ParaPr, Depth);
    }
    else
    {
        var CurLine  = PRS.Line - this.StartLine;
        var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range );

        var bContainCompareOper = PRS.bContainCompareOper;

        var iterUp = this.iters.iterUp,
            iterDn = this.iters.iterDn;

        this.setDistance();

        var RangeStartPos = this.protected_AddRange(CurLine, CurRange),
            RangeEndPos = 0;

        if(CurLine == 0 && CurRange == 0)
        {
            PRS.WordLen += this.BrGapLeft;
            this.baseContent.Recalculate_Reset(PRS.Range, PRS.Line, PRS);
        }

        PRS.Update_CurPos(0, Depth);
        PRS.bMath_OneLine  = false;


        if(this.Pr.type == DEGREE_SubSup) // baseContent, iters
            this.baseContent.Recalculate_Range(PRS, ParaPr, Depth+1);

        var bNeedUpdateIter = (this.Pr.type == DEGREE_SubSup && PRS.NewRange == false) || (CurLine == 0 && CurRange == 0 && this.Pr.type == DEGREE_PreSubSup);

        if(bNeedUpdateIter)
        {
            var PRS_Pos = PRS.CurPos.Copy();

            PRS.bMath_OneLine = true;

            var WordLen = PRS.WordLen;

            this.iters.Recalculate_Range(PRS, ParaPr, Depth);

            var itersW = iterUp.size.width > iterDn.size.width ? iterUp.size.width : iterDn.size.width;

            PRS.CurPos.Set(PRS_Pos);
            PRS.WordLen = WordLen + itersW + this.dW;
            PRS.Word = true;
        }

        PRS.bMath_OneLine  = false;

        if(this.Pr.type == DEGREE_PreSubSup) // iters, baseContent
            this.baseContent.Recalculate_Range(PRS, ParaPr, Depth+1);

        if(PRS.NewRange == false)
            PRS.WordLen += this.BrGapRight;

        this.protected_FillRange(CurLine, CurRange, RangeStartPos, RangeEndPos);

        PRS.bContainCompareOper = bContainCompareOper;
    }
};
CDegreeSubSup.prototype.Recalculate_Range_Width = function(PRSC, _CurLine, _CurRange)
{
    if(this.bOneLine == true)
    {
        CDegreeSubSupBase.prototype.Recalculate_Range_Width.call(this, PRSC, _CurLine, _CurRange);
    }
    else
    {
        var CurLine = _CurLine - this.StartLine;
        var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

        var RangeW = PRSC.Range.W;

        if(CurLine == 0 && CurRange == 0)
        {
            PRSC.Range.W += this.BrGapLeft;
        }

        if(this.Pr.type == DEGREE_SubSup) // baseContent, iters
            this.baseContent.Recalculate_Range_Width(PRSC, _CurLine, _CurRange);

        if(this.Need_Iters(_CurLine, _CurRange))
        {
            var RangeW2 = PRSC.Range.W;

            this.iters.iterUp.Recalculate_Range_Width(PRSC, _CurLine, _CurRange);
            this.iters.iterDn.Recalculate_Range_Width(PRSC, _CurLine, _CurRange);

            this.iters.Bounds.SetWidth(0, 0, this.iters.size.width);

            PRSC.Range.W = RangeW2 + this.iters.size.width + this.dW;
        }

        if(this.Pr.type == DEGREE_PreSubSup) // iters, baseContent
            this.baseContent.Recalculate_Range_Width(PRSC, _CurLine, _CurRange);

        if(this.baseContent.Math_Is_End(_CurLine, _CurRange))
        {
            PRSC.Range.W += this.BrGapRight;
        }

        this.Bounds.SetWidth(CurLine, CurRange, PRSC.Range.W - RangeW);
    }
};
CDegreeSubSup.prototype.setPosition = function(pos, PosInfo)
{
    if(this.bOneLine)
    {
        CDegreeSubSupBase.prototype.setPosition.call(this, pos, PosInfo);
    }
    else
    {
        var Line  = PosInfo.CurLine,
            Range = PosInfo.CurRange;
        var CurLine  = Line - this.StartLine;
        var CurRange = ( 0 === CurLine ? Range - this.StartRange : Range );

        this.UpdatePosBound(pos, PosInfo);

        if(CurLine == 0 && CurRange == 0)
        {
            pos.x += this.BrGapLeft;
        }

        var PosIters = new CMathPosition();
        if(this.Pr.type == DEGREE_SubSup)
        {
            this.baseContent.setPosition(pos, PosInfo);

            if(this.baseContent.Math_Is_End(Line, Range))
            {
                PosIters.x = pos.x;
                PosIters.y = pos.y - this.iters.size.ascent;

                this.iters.setPosition(PosIters, PosInfo);

                pos.x += this.iters.size.width + this.dW + this.BrGapRight;
            }
        }
        else
        {
            if(CurLine == 0 && CurRange == 0)
            {
                PosIters.x = pos.x;
                PosIters.y = pos.y - this.iters.size.ascent;

                this.iters.setPosition(PosIters, PosInfo);

                pos.x += this.iters.size.width + this.dW;

            }

            this.baseContent.setPosition(pos, PosInfo);

            if(this.baseContent.Math_Is_End(Line, Range))
                pos.x += this.BrGapRight;
        }
    }
};
CDegreeSubSup.prototype.Draw_Elements = function(PDSE)
{
    this.baseContent.Draw_Elements(PDSE);

    if(this.Need_Iters(PDSE.Line, PDSE.Range))
        this.iters.Draw_Elements(PDSE);
};
CDegreeSubSup.prototype.Need_Iters = function(_CurLine, _CurRange)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    return  (this.Pr.type == DEGREE_SubSup && this.baseContent.Math_Is_End(_CurLine, _CurRange)) || (CurLine == 0 && CurRange == 0 && this.Pr.type == DEGREE_PreSubSup);
};
CDegreeSubSup.prototype.protected_GetRangeEndPos = function(CurLine, CurRange)
{
    var _CurLine  = CurLine + this.StartLine;
    var _CurRange = ( 0 === CurLine ? CurRange + this.StartRange : CurRange );

    return this.Need_Iters(_CurLine, _CurRange) ? 2 : 0;
};
CDegreeSubSup.prototype.Apply_MenuProps = function(Props)
{
	if (Props.Type == Asc.c_oAscMathInterfaceType.Script)
	{
		if (Props.ScriptType == Asc.c_oAscMathInterfaceScript.PreSubSup && this.Pr.type == DEGREE_SubSup)
		{
			AscCommon.History.Add(new CChangesMathDegreeSubSupType(this, this.Pr.type, DEGREE_PreSubSup));
			this.raw_SetType(DEGREE_PreSubSup);
		}

		if (Props.ScriptType == Asc.c_oAscMathInterfaceScript.SubSup && this.Pr.type == DEGREE_PreSubSup)
		{
			AscCommon.History.Add(new CChangesMathDegreeSubSupType(this, this.Pr.type, DEGREE_SubSup));
			this.raw_SetType(DEGREE_SubSup);
		}
	}
};
CDegreeSubSup.prototype.raw_SetType = function(type)
{
    this.Pr.type = type;
    this.fillContent();
};
CDegreeSubSup.prototype.Get_InterfaceProps = function()
{
    var Type = this.Pr.type == DEGREE_PreSubSup ? Asc.c_oAscMathInterfaceScript.PreSubSup : Asc.c_oAscMathInterfaceScript.SubSup;
    return new CMathMenuScript(this, Type);
};
CDegreeSubSup.prototype.Can_ModifyArgSize = function()
{
    return this.CurPos !== 0 && false === this.Is_SelectInside(); // находимся в итераторе
};

/**
 *
 * @param CMathMenuScript
 * @constructor
 * @extends {CMathMenuBase}
 */
function CMathMenuScript(Script, Type)
{
	CMathMenuBase.call(this, Script);

    this.Type       = Asc.c_oAscMathInterfaceType.Script;

    if (undefined !== Type)
        this.ScriptType = Type;
    else
        this.ScriptType = undefined;
}
CMathMenuScript.prototype = Object.create(CMathMenuBase.prototype);
CMathMenuScript.prototype.constructor = CMathMenuScript;

CMathMenuScript.prototype.get_ScriptType = function(){return this.ScriptType;};
CMathMenuScript.prototype.put_ScriptType = function(Type){this.ScriptType = Type;};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CDegreeSubSup = CDegreeSubSup;
window['AscCommonWord'].CDegree = CDegree;

window["CMathMenuScript"] = CMathMenuScript;
CMathMenuScript.prototype["get_ScriptType"] = CMathMenuScript.prototype.get_ScriptType;
CMathMenuScript.prototype["put_ScriptType"] = CMathMenuScript.prototype.put_ScriptType;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var History = AscCommon.History;

var MATH_MC_JC = MCJC_CENTER;

function CMathMatrixColumnPr()
{
    this.count = 1;
    this.mcJc  = MCJC_CENTER;
}
CMathMatrixColumnPr.prototype.Set_FromObject = function(Obj)
{
    if (undefined !== Obj.count && null !== Obj.count)
        this.count = Obj.count;
    else
        this.count = 1;

    if (MCJC_LEFT === Obj.mcJc || MCJC_RIGHT === Obj.mcJc || MCJC_CENTER === Obj.mcJc)
        this.mcJc = Obj.mcJc;
    else
        this.mcJc = MCJC_CENTER;
};
CMathMatrixColumnPr.prototype.Copy = function()
{
    var NewPr = new CMathMatrixColumnPr();

    NewPr.count = this.count;
    NewPr.mcJc  = this.mcJc;

    return NewPr;
};
CMathMatrixColumnPr.prototype.Write_ToBinary = function(Writer)
{
    // Long : count
    // Long : mcJc

    Writer.WriteLong(this.count);
    Writer.WriteLong(this.mcJc);
};
CMathMatrixColumnPr.prototype.Read_FromBinary = function(Reader)
{
    // Long : count
    // Long : mcJc

    this.count = Reader.GetLong();
    this.mcJc  = Reader.GetLong();
};

function CMathMatrixPr()
{
    this.row     = 1;

    this.cGp     = 0;
    this.cGpRule = 0;
    this.cSp     = 0;

    this.rSp     = 0;
    this.rSpRule = 0;

    this.mcs     = [];
    this.baseJc  = BASEJC_CENTER;
    this.plcHide = false;
}
CMathMatrixPr.prototype.Set_FromObject = function(Obj)
{
    if (undefined !== Obj.row && null !== Obj.row)
        this.row = Obj.row;

    if (undefined !== Obj.cGp && null !== Obj.cGp)
        this.cGp = Obj.cGp;

    if (undefined !== Obj.cGpRule && null !== Obj.cGpRule)
        this.cGpRule = Obj.cGpRule;

    if (undefined !== Obj.cSp && null !== Obj.cSp)
        this.cSp = Obj.cSp;

    if (undefined !== Obj.rSpRule && null !== Obj.rSpRule)
        this.rSpRule = Obj.rSpRule;

    if (undefined !== Obj.rSp && null !== Obj.rSp)
        this.rSp = Obj.rSp;

    if(true === Obj.plcHide || 1 === Obj.plcHide)
        this.plcHide = true;
    else
        this.plcHide = false;

    if(BASEJC_CENTER === Obj.baseJc || BASEJC_TOP === Obj.baseJc || BASEJC_BOTTOM === Obj.baseJc)
        this.baseJc = Obj.baseJc;

    var nColumnsCount = 0;
    if (undefined !== Obj.mcs.length)
    {
        var nMcsCount = Obj.mcs.length;

        if (0 !== nMcsCount)
        {
            this.mcs.length = nMcsCount;
            for (var nMcsIndex = 0; nMcsIndex < nMcsCount; nMcsIndex++)
            {
                this.mcs[nMcsIndex] = new CMathMatrixColumnPr();
                this.mcs[nMcsIndex].Set_FromObject(Obj.mcs[nMcsIndex]);
                nColumnsCount += this.mcs[nMcsIndex].count;
            }
        }
        else if (undefined !== Obj.column)
            nColumnsCount = Obj.column;
    }

    return nColumnsCount;
};
CMathMatrixPr.prototype.Copy = function()
{
    var NewPr = new CMathMatrixPr();

    NewPr.row     = this.row    ;
    NewPr.cGp     = this.cGp    ;
    NewPr.cGpRule = this.cGpRule;
    NewPr.cSp     = this.cSp    ;
    NewPr.rSp     = this.rSp    ;
    NewPr.rSpRule = this.rSpRule;
    NewPr.baseJc  = this.baseJc ;
    NewPr.plcHide = this.plcHide;

    var nCount = this.mcs.length;
    for (var nMcsIndex = 0; nMcsIndex < nCount; nMcsIndex++)
    {
        NewPr.mcs[nMcsIndex] = this.mcs[nMcsIndex].Copy();
    }

    return NewPr;
};
CMathMatrixPr.prototype.Get_ColumnsCount = function()
{
    var nColumnsCount = 0;
    for (var nMcsIndex = 0, nMcsCount = this.mcs.length; nMcsIndex < nMcsCount; nMcsIndex++)
    {
        nColumnsCount += this.mcs[nMcsIndex].count;
    }
    return nColumnsCount;
};
CMathMatrixPr.prototype.Get_ColumnPrPos = function(PosColumn)
{
    var Count = 0;
    for(var Pos = 0,  nMcsCount = this.mcs.length; Pos < nMcsCount - 1; Pos++)
    {
        if(PosColumn < Count + this.mcs[Pos].count)
            break;

        Count += this.mcs[Pos].count;
    }

    return Pos;
};
CMathMatrixPr.prototype.Modify_ColumnCount = function(PosColumn, DiffCount)
{
    var Pos = this.Get_ColumnPrPos(PosColumn);
    this.mcs[Pos].count += DiffCount;
};
CMathMatrixPr.prototype.Get_ColumnMcJc = function(PosColumn)
{
    var Pos = this.Get_ColumnPrPos(PosColumn);
    return this.mcs[Pos].mcJc;
};
CMathMatrixPr.prototype.Set_Row = function(Value)
{
    this.row = Value;
};
CMathMatrixPr.prototype.Set_BaseJc = function(Value)
{
    this.baseJc = Value;
};
CMathMatrixPr.prototype.Set_ColumnJc = function(Value, PosColumn)
{
    var Count = 0, nMcsCount = this.mcs.length;
    var Pos, MColumnPr;

    for(Pos = 0; Pos < nMcsCount - 1; Pos++)
    {
        if(PosColumn < Count + this.mcs[Pos].count)
            break;

        Count += this.mcs[Pos].count;
    }

    if(this.mcs[Pos].count == 1)
    {
        this.mcs[Pos].mcJc = Value;
    }
    else if(Count < PosColumn  && PosColumn < Count + this.mcs[Pos].count)
    {
        var CountRight = this.mcs[Pos].count + Count - PosColumn - 1,
            CountLeft  = this.mcs[Pos].count - CountRight - 1;

        this.mcs[Pos].count  = CountLeft;
        var MColumnPrRight   = new CMathMatrixColumnPr();
        MColumnPrRight.count = CountRight;
        MColumnPrRight.mcJc  = this.mcs[Pos].mcJc;

        this.mcs.splice(Pos + 1, 0, MColumnPrRight);

        MColumnPr = new CMathMatrixColumnPr();
        MColumnPr.count = 1;
        MColumnPr.mcJc  = Value;
        this.mcs.splice(Pos + 1, 0, MColumnPr);
    }
    else
    {
        this.mcs[Pos].count--;
        var ColumnPos = PosColumn == Count ? Pos : Pos + 1;
        MColumnPr = new CMathMatrixColumnPr();
        MColumnPr.count = 1;
        MColumnPr.mcJc  = Value;
        this.mcs.splice(ColumnPos, 0, MColumnPr);
    }

};
CMathMatrixPr.prototype.Write_ToBinary = function(Writer)
{
    // Long  : row
    // Long  : cGp
    // Long  : cGpRule
    // Long  : rSp
    // Long  : rSpRule
    // Long  : baseJc
    // Bool  : plcHide
    // Long  : count of mcs
    // Array : mcs (CMathMatrixColumnPr)

    Writer.WriteLong(this.row);
    Writer.WriteLong(this.cGp);
    Writer.WriteLong(this.cGpRule);
    Writer.WriteLong(this.rSp);
    Writer.WriteLong(this.rSpRule);
    Writer.WriteLong(this.baseJc);
    Writer.WriteBool(this.plcHide);

    var nMcsCount = this.mcs.length;
    Writer.WriteLong(nMcsCount);
    for (var nIndex = 0; nIndex < nMcsCount; nIndex++)
    {
        this.mcs[nIndex].Write_ToBinary(Writer);
    }
};
CMathMatrixPr.prototype.Read_FromBinary = function(Reader)
{
    // Long  : row
    // Long  : cGp
    // Long  : cGpRule
    // Long  : rSp
    // Long  : rSpRule
    // Long  : baseJc
    // Bool  : plcHide
    // Long  : count of mcs
    // Array : mcs (CMColumnsPr)

    this.row = Reader.GetLong();
    this.cGp = Reader.GetLong();
    this.cGpRule = Reader.GetLong();
    this.rSp     = Reader.GetLong();
    this.rSpRule = Reader.GetLong();
    this.baseJc  = Reader.GetLong();
    this.plcHide = Reader.GetBool();

    var nMcsCount = Reader.GetLong();
    this.mcs.length = nMcsCount;
    for (var nIndex = 0; nIndex < nMcsCount; nIndex++)
    {
        this.mcs[nIndex] = new CMathMatrixColumnPr();
        this.mcs[nIndex].Read_FromBinary(Reader);
    }
};

function CMathMatrixGapPr(Type)
{
    this.Type   = Type;
    this.Rule   = 0;
    this.Gap    = 0;
    this.MinGap = 0;
}
CMathMatrixGapPr.prototype.Set_DefaultSpace = function(Rule, Gap, MinGap)
{
    this.Rule   = Rule;
    this.Gap    = Gap;
    this.MinGap = MinGap;
};


/**
 *
 * @constructor
 * @extends {CMathBase}
 */
function CMatrixBase()
{
	CMathBase.call(this);

    this.SpaceRow       = new CMathMatrixGapPr(MATH_MATRIX_ROW);
    this.SpaceColumn    = new CMathMatrixGapPr(MATH_MATRIX_COLUMN);

    this.gaps =
    {
        row: [],
        column: []
    };

    this.Set_DefaultSpace();
}
CMatrixBase.prototype = Object.create(CMathBase.prototype);
CMatrixBase.prototype.constructor = CMatrixBase;
CMatrixBase.prototype.recalculateSize = function(oMeasure, RPI)
{
    if(this.RecalcInfo.bProps)
    {
        if(this.nRow > 1)
            this.Set_RuleGap(this.SpaceRow, this.Pr.rSpRule, this.Pr.rSp);

        if(this.nCol > 1)
        {
            this.Set_RuleGap(this.SpaceColumn, this.Pr.cGpRule, this.Pr.cGp, this.Pr.cSp);
        }

        if(this.kind == MATH_MATRIX)
        {
            // выставим выравнивание для столбцов
            if(this.Pr.mcs !== undefined)
            {
                var lng = this.Pr.mcs.length;
                var col = 0;

                this.alignment.wdt.length = 0;

                for(var j = 0; j < lng; j++)
                {
                    var mc = this.Pr.mcs[j],
                        count = mc.count;

                    for(var i = 0; i < count; i++)
                    {
                        this.alignment.wdt[col] = mc.mcJc;
                        col++;
                    }
                }
            }


            if(this.Pr.plcHide)
                this.hidePlaceholder(true);
        }

        this.RecalcInfo.bProps = false;
    }

    var FontSize = this.Get_TxtPrControlLetter().FontSize;
    var metrics = this.getMetrics();

    if(this.nCol > 1)
    {
        var gapsCol = this.Get_ColumnGap(this.SpaceColumn, FontSize);

        for(var i = 0; i < this.nCol - 1; i++)
            this.gaps.column[i] = gapsCol;
    }

    this.gaps.column[this.nCol - 1] = 0;

    if(this.nRow > 1)
    {
        var intervalRow = this.Get_RowSpace(this.SpaceRow, FontSize);

        var divCenter = 0;

        var plH = 0.2743827160493827*FontSize;
        var minGp = this.SpaceRow.MinGap*FontSize*g_dKoef_pt_to_mm;
        minGp -= plH;

        for(var j = 0; j < this.nRow - 1; j++)
        {
            divCenter = intervalRow - (metrics.descents[j] + metrics.ascents[j + 1]);
            this.gaps.row[j] = minGp > divCenter ? minGp : divCenter;
        }
    }

    this.gaps.row[this.nRow - 1] = 0;


    var height = 0, width = 0;

    for(var i = 0; i < this.nCol; i++)
        width +=  this.gaps.column[i] + metrics.widths[i];

    for(var j = 0; j < this.nRow; j++)
        height += this.gaps.row[j] + metrics.ascents[j] + metrics.descents[j];

    var ascent = 0;

    if(this.Pr.baseJc == BASEJC_TOP)
    {
        for(var j = 0; j < this.nCol; j++)
            ascent = this.elements[0][j].size.ascent > ascent ? this.elements[0][j].size.ascent : ascent;
    }
    else if(this.Pr.baseJc == BASEJC_BOTTOM)
    {
        var descent = 0,
            currDsc;
        for(var j = 0; j < this.nCol; j++)
        {
            currDsc = this.elements[this.nRow -1][j].size.height - this.elements[this.nRow -1][j].size.ascent;
            descent = currDsc > descent ? currDsc : descent;

            ascent = height - descent;
        }
    }
    else /*this.Pr.baseJc == 0*/
        ascent = this.getAscent(oMeasure, height);


    width += this.GapLeft + this.GapRight;

    this.size.height = height;
    this.size.width  = width;
    this.size.ascent = ascent;
};
CMatrixBase.prototype.Set_DefaultSpace = function()
{
    this.SpaceRow.Set_DefaultSpace(0, 0, 13/12); // MinGap - em
    this.SpaceColumn.Set_DefaultSpace(0, 0, 0);  // MinGap / 20 pt
};
CMatrixBase.prototype.Set_RuleGap = function(oSpace, Rule, Gap, MinGap)
{
    var bInt  =  Rule == Rule - 0 && Rule == Rule^0,
        bRule =  Rule >= 0 && Rule <= 4;

    if(bInt && bRule)
        oSpace.Rule = Rule;

    if(Gap == Gap - 0 && Gap == Gap^0)
        oSpace.Gap = Gap;

    if(MinGap == MinGap - 0 && MinGap == MinGap^0)
        oSpace.MinGap = MinGap;
};
CMatrixBase.prototype.Get_ColumnGap = function(SpaceColumn, FontSize)
{
    var ColumnGap = this.Get_Gap(SpaceColumn, FontSize, 1);

    var wPlh = 0.324*FontSize;
    var MinGap = SpaceColumn.MinGap / 20 * g_dKoef_pt_to_mm - wPlh;

    return ColumnGap > MinGap ? ColumnGap : MinGap;
};
CMatrixBase.prototype.Get_RowSpace = function(SpaceRow, FontSize)
{
    var LineGap = this.Get_Gap(SpaceRow, FontSize, 7/6);

    var MinGap = SpaceRow.MinGap*FontSize*g_dKoef_pt_to_mm;

    return LineGap > MinGap ? LineGap : MinGap;
};
CMatrixBase.prototype.Get_Gap = function(oSpace, FontSize, coeff)
{
    var Space, Gap;

    if(oSpace.Rule == 0)
        Space = coeff;                  //em
    else if(oSpace.Rule == 1)
        Space = coeff*1.5;              //em
    else if(oSpace.Rule == 2)
        Space = coeff*2;                //em
    else if(oSpace.Rule == 3)
        Space = oSpace.Gap/20;          //pt
    else if(oSpace.Rule == 4)
        Space = coeff * oSpace.Gap/2;   //em
    else
        Space = coeff;


    if(oSpace.Rule == 3)
        Gap = Space*g_dKoef_pt_to_mm;          //pt
    else
        Gap = Space*FontSize*g_dKoef_pt_to_mm; //em


    return Gap;
};
CMatrixBase.prototype.getRowsCount = function()
{
    return this.Pr.row;
};
CMatrixBase.prototype.Add_Row = function(Pos)
{
	var Items       = [],
		CountColumn = this.getColsCount();

	for (var CurPos = 0; CurPos < CountColumn; CurPos++)
	{
		var NewContent = new CMathContent();
		NewContent.Correct_Content(true);
		Items.push(NewContent);
	}

	History.Add(new CChangesMathMatrixAddRow(this, Pos, Items));
	this.raw_AddRow(Pos, Items);
};
CMatrixBase.prototype.raw_AddRow = function(Pos, Items)
{
    // изменить кол-во строк в матрицы и добавить элементы новой строки нужно в одной точке истории
    // т.к. при добавлении, удалении элементов учитывается кол-во строк и столбцов для заполнения массива elements

    this.Pr.Set_Row(this.Pr.row + 1);
    this.raw_AddToContent(Pos, Items, true);

    // чтобы корректно обновить NearPos пройдемся циклом еще раз по всем позициям добавленных контентов
    for(var CurPos = Pos; CurPos < Pos + Items.length; CurPos++)
    {
        this.private_UpdatePosOnAdd( CurPos, true);
    }
};
CMatrixBase.prototype.raw_RemoveRow = function(Pos, Count)
{
    this.Pr.Set_Row(this.Pr.row - 1);
    this.raw_RemoveFromContent(Pos, Count);

    // Обновим текущую позицию
    if (this.CurPos > Pos + Count)
        this.CurPos -= Count;
    else if (this.CurPos > Pos )
        this.CurPos = Pos;

    this.private_CorrectCurPos();
    this.private_UpdatePosOnRemove(Pos, Count);
};
CMatrixBase.prototype.Remove_Row = function(RowPos)
{
	if (this.Pr.row > 1)
	{
		var ColumnCount = this.getColsCount();
		var NextPos     = RowPos * ColumnCount;
		var Items       = this.Content.slice(NextPos, NextPos + ColumnCount);

		History.Add(new CChangesMathMatrixRemoveRow(this, NextPos, Items));
		this.raw_RemoveRow(NextPos, Items.length);
	}
};
CMatrixBase.prototype.SetBaseJc = function(Value)
{
	if (this.Pr.baseJc !== Value)
	{
		History.Add(new CChangesMathMatrixBaseJc(this, this.Pr.baseJc, Value));
		this.raw_SetBaseJc(Value);
	}
};
CMatrixBase.prototype.raw_SetBaseJc = function(Value)
{
    this.Pr.Set_BaseJc(Value);
};
CMatrixBase.prototype.Modify_Interval = function(Item, NewRule, NewGap)
{
    var OldRule, OldGap;

    if(Item.Type == MATH_MATRIX_ROW)
    {
        OldRule = this.Pr.rSpRule;
        OldGap  = this.Pr.rSp;
    }
    else
    {
        OldRule = this.Pr.cGpRule;
        OldGap  = this.Pr.cGp;
    }

    if(NewRule !== OldRule || NewGap !== OldGap)
    {
        History.Add(new CChangesMathMatrixInterval(this, Item.Type, OldRule, OldGap, NewRule, NewGap));
        this.raw_SetInterval(Item.Type, NewRule, NewGap);
    }
};
CMatrixBase.prototype.raw_SetInterval = function(Item, Rule, Gap)
{
    if(Item == MATH_MATRIX_ROW)
    {
        this.Pr.rSpRule = Rule;
        this.Pr.rSp     = Gap;
        this.Set_RuleGap(this.SpaceRow, Rule, Gap);
    }
    else if(Item == MATH_MATRIX_COLUMN)
    {
        this.Pr.cGpRule = Rule;
        this.Pr.cGp     = Gap;
        this.Set_RuleGap(this.SpaceColumn, Rule, Gap, this.Pr.cSp);
    }
};

/**
 *
 * @param props
 * @constructor
 * @extends {CMatrixBase}
 */
function CMathMatrix(props)
{
	CMatrixBase.call(this);

	this.Id             = AscCommon.g_oIdCounter.Get_NewId();
    this.Pr             = new CMathMatrixPr();

    this.column         = 0;

    if(props !== null && props !== undefined)
        this.init(props);

    AscCommon.g_oTableId.Add( this, this.Id );
}
CMathMatrix.prototype = Object.create(CMatrixBase.prototype);
CMathMatrix.prototype.constructor = CMathMatrix;

CMathMatrix.prototype.ClassType = AscDFH.historyitem_type_matrix;
CMathMatrix.prototype.kind      = MATH_MATRIX;
CMathMatrix.prototype.init = function(props)
{
    this.setProperties(props);
    this.column = this.Pr.Get_ColumnsCount();

    var nRowsCount = this.getRowsCount();
    var nColsCount = this.getColsCount();

    this.Fill_LogicalContent(nRowsCount * nColsCount);

    this.fillContent();
};
CMathMatrix.prototype.setPosition = function(pos, PosInfo)
{
    this.pos.x = pos.x;

    if(this.bInside === true)
        this.pos.y = pos.y;
    else
        this.pos.y = pos.y - this.size.ascent; ///!!!!

    this.UpdatePosBound(pos, PosInfo);

    var maxWH = this.getWidthsHeights();
    var Widths = maxWH.widths;
    var Heights = maxWH.heights;

    var NewPos = new CMathPosition();

    var h = 0, w = 0;

    for(var i=0; i < this.nRow; i++)
    {
        w = 0;
        for(var j = 0; j < this.nCol; j++)
        {
            var Item = this.elements[i][j];
            var al = this.align(i, j);
            NewPos.x = this.pos.x + this.GapLeft + al.x + w;
            NewPos.y = this.pos.y + al.y + h + Item.size.ascent;

            Item.setPosition(NewPos, PosInfo);
            w += Widths[j] + this.gaps.column[j];
        }
        h += Heights[i] + this.gaps.row[i];
    }

    pos.x += this.size.width;
};
CMathMatrix.prototype.getMetrics = function(RPI)
{
    var Ascents = [];
    var Descents = [];
    var Widths = [];

    for(var i=0; i < this.nRow; i++)
    {
        Ascents[i]  = 0;
        Descents[i] = 0;

        for(var j = 0; j < this.nCol ; j++)
        {
            var size = this.elements[i][j].size;
            Widths[j]   = i > 0  && ( Widths[j] > size.width ) ? Widths[j] : size.width;
            Ascents[i]  = (Ascents[i] > size.ascent ) ? Ascents[i] : size.ascent;
            Descents[i] = (Descents[i] > size.height - size.ascent ) ? Descents[i] : size.height - size.ascent;
        }
    }

    return {ascents: Ascents, descents: Descents, widths: Widths}
};
CMathMatrix.prototype.getContentElement = function(nRowIndex, nColIndex)
{
    return this.Content[nRowIndex * this.getColsCount() + nColIndex];
};
CMathMatrix.prototype.fillContent = function()
{
    this.column = this.Pr.Get_ColumnsCount();

    var nRowsCount = this.getRowsCount();
    var nColsCount = this.getColsCount();

    this.setDimension(nRowsCount, nColsCount);

    for(var nRowIndex = 0; nRowIndex < nRowsCount; nRowIndex++)
    {
        for (var nColIndex = 0; nColIndex < nColsCount; nColIndex++)
        {
            this.elements[nRowIndex][nColIndex] = this.getContentElement(nRowIndex, nColIndex);
        }
    }
};
CMathMatrix.prototype.getColsCount = function()
{
    return this.column;
};
CMathMatrix.prototype.Get_RowPos = function(Pos)
{
    var ColumnCount = this.getColsCount();

    return Pos/ColumnCount >> 0;
};
CMathMatrix.prototype.Get_ColumnPos = function(Pos)
{
    var ColumnCount = this.getColsCount();
    var RowPos      = Pos/ColumnCount >> 0; // номер строки

    return Pos - ColumnCount*RowPos;
};
CMathMatrix.prototype.Apply_MenuProps = function(Props)
{
	if (Props.Type == Asc.c_oAscMathInterfaceType.Matrix)
	{
		var ColumnCount = this.getColsCount(),
			RowPos      = this.Get_RowPos(this.CurPos),
			ColumnPos   = this.Get_ColumnPos(this.CurPos);

		var bGapWholeNumber, bGapNumber;
		var NextPos;

		if (Props.BaseJc !== undefined)
		{
			var BaseJc = this.Pr.baseJc;

			if (Props.BaseJc === Asc.c_oAscMathInterfaceMatrixMatrixAlign.Center)
			{
				BaseJc = BASEJC_CENTER;
			}
			else if (Props.BaseJc === Asc.c_oAscMathInterfaceMatrixMatrixAlign.Bottom)
			{
				BaseJc = BASEJC_BOTTOM;
			}
			else if (Props.BaseJc === Asc.c_oAscMathInterfaceMatrixMatrixAlign.Top)
			{
				BaseJc = BASEJC_TOP;
			}

			this.SetBaseJc(BaseJc);
		}

		if (Props.ColumnJc !== undefined)
		{
			var CurrentMcJc = this.Pr.Get_ColumnMcJc(ColumnPos);
			var McJc        = CurrentMcJc;

			if (Props.ColumnJc === Asc.c_oAscMathInterfaceMatrixColumnAlign.Center)
			{
				McJc = MCJC_CENTER;
			}
			else if (Props.ColumnJc === Asc.c_oAscMathInterfaceMatrixColumnAlign.Left)
			{
				McJc = MCJC_LEFT;
			}
			else if (Props.ColumnJc === Asc.c_oAscMathInterfaceMatrixColumnAlign.Right)
			{
				McJc = MCJC_RIGHT;
			}

			if (CurrentMcJc !== McJc)
			{
				History.Add(new CChangesMathMatrixColumnJc(this, CurrentMcJc, McJc, ColumnPos));
				this.raw_SetColumnJc(McJc, ColumnPos);
			}
		}

		if (Props.RowRule !== undefined)
		{
			switch (Props.RowRule)
			{
				case c_oAscMathInterfaceMatrixRowRule.Single:
				{
					this.Modify_Interval(this.SpaceRow, 0, 0);
					break;
				}
				case c_oAscMathInterfaceMatrixRowRule.OneAndHalf:
				{
					this.Modify_Interval(this.SpaceRow, 1, 0);
					break;
				}
				case c_oAscMathInterfaceMatrixRowRule.Double:
				{
					this.Modify_Interval(this.SpaceRow, 2, 0);
					break;
				}
				case c_oAscMathInterfaceMatrixRowRule.Exactly:
				{
					bGapWholeNumber = Props.Gap !== undefined && Props.Gap + 0 == Props.Gap && Props.Gap >> 0 == Props.Gap;

					if (bGapWholeNumber == true && Props.Gap >= 0 && Props.Gap <= 31680)
					{
						this.Modify_Interval(this.SpaceRow, 3, Props.Gap * 20);
					}

					break;
				}
				case c_oAscMathInterfaceMatrixRowRule.Multiple:
				{
					bGapNumber = Props.Gap !== undefined && Props.Gap + 0 == Props.Gap;

					if (bGapNumber == true && Props.Gap >= 0 && Props.Gap <= 111)
					{
						var Gap = (Props.Gap * 2 + 0.5) >> 0;

						this.Modify_Interval(this.SpaceRow, 4, Gap);
					}

					break;
				}
			}
		}

		if (Props.ColumnRule !== undefined)
		{
			switch (Props.ColumnRule)
			{
				case c_oAscMathInterfaceMatrixColumnRule.Single:
				{
					this.Modify_Interval(this.SpaceColumn, 0, 0);
					break;
				}
				case c_oAscMathInterfaceMatrixColumnRule.OneAndHalf:
				{
					this.Modify_Interval(this.SpaceColumn, 1, 0);
					break;
				}
				case c_oAscMathInterfaceMatrixColumnRule.Double:
				{
					this.Modify_Interval(this.SpaceColumn, 2, 0);
					break;
				}
				case c_oAscMathInterfaceMatrixColumnRule.Exactly:
				{
					bGapWholeNumber = Props.Gap !== undefined && Props.Gap + 0 == Props.Gap && Props.Gap >> 0 == Props.Gap;

					if (bGapWholeNumber == true && Props.Gap >= 0 && Props.Gap <= 31680)
					{
						this.Modify_Interval(this.SpaceColumn, 3, Props.Gap * 20);
					}

					break;
				}
				case c_oAscMathInterfaceMatrixColumnRule.Multiple:
				{
					bGapNumber = Props.Gap !== undefined && Props.Gap + 0 == Props.Gap;

					if (bGapNumber == true && Props.Gap >= 0 && Props.Gap <= 55.87)
					{
						var Gap         = (Props.Gap / 0.21163) >> 0,
							NextMenuGap = (((0.21163 * (Gap + 1)) * 100 + 0.5) >> 0 ) / 100; // учтем округление
																							 // (пример: Props.Gap =
																							 // 2.96)

						if (Props.Gap >= NextMenuGap)
							Gap++;

						this.Modify_Interval(this.SpaceColumn, 4, Gap);
					}

					break;
				}
			}
		}

		if (Props.Action & c_oMathMenuAction.DeleteMatrixRow && this.getRowsCount() > 1)
		{
			this.Remove_Row(RowPos);
		}

		if (Props.Action & c_oMathMenuAction.DeleteMatrixColumn && ColumnCount > 1)
		{
			this.Remove_Column(ColumnPos);
		}

		if (Props.Action & c_oMathMenuAction.InsertMatrixRow)
		{
			if (Props.Action & c_oMathMenuAction.InsertBefore)
			{
				NextPos = RowPos * ColumnCount;
				this.Add_Row(NextPos);
			}
			else
			{
				NextPos = (RowPos + 1) * ColumnCount;     // позиция для вставки массива контентов
				this.Add_Row(NextPos);
			}
		}

		if (Props.Action & c_oMathMenuAction.InsertMatrixColumn)
		{
			if (Props.Action & c_oMathMenuAction.InsertBefore)
			{
				this.Add_Column(ColumnPos);
			}
			else
			{
				this.Add_Column(ColumnPos + 1);
			}
		}

		if (Props.bHidePlh !== undefined)
		{
			if (Props.bHidePlh !== this.Pr.plcHide)
			{
				History.Add(new CChangesMathMatrixPlh(this, this.Pr.plcHide, Props.bHidePlh));
				this.raw_HidePlh(Props.bHidePlh);
			}
		}
	}
};
CMathMatrix.prototype.Get_InterfaceProps = function()
{
    return new CMathMenuMatrix(this);
};
CMathMatrix.prototype.Add_Column = function(ColumnPos)
{
	var Items    = [],
		CountRow = this.getRowsCount();

	for (var CurPos = 0; CurPos < CountRow; CurPos++)
	{
		var NewContent = new CMathContent();
		NewContent.Correct_Content(true);
		Items.push(NewContent);
	}

	History.Add(new CChangesMathMatrixAddColumn(this, ColumnPos, Items));
	this.raw_AddColumn(ColumnPos, Items);
};
CMathMatrix.prototype.raw_AddColumn = function(Pos, Items)
{
    var CountColumn = this.getColsCount();

    var RowPos  = this.CurPos/CountColumn >> 0; // номер строки

    for(var CurPos = 0; CurPos < Items.length; CurPos++)
    {
        this.Content.splice((CountColumn + 1)*CurPos + Pos, 0, Items[CurPos]);
        Items[CurPos].ParentElement = this;

        this.private_UpdatePosOnAdd( (CountColumn + 1)*CurPos + Pos, true);
    }

    this.Modify_ColumnCount(this.CurPos - CountColumn*RowPos, 1);

    this.fillContent();
};
CMathMatrix.prototype.Remove_Column = function(ColumnPos)
{
	var Items       = [],
		CountRow    = this.getRowsCount(),
		CountColumn = this.getColsCount();

	for (var CurPos = 0; CurPos < CountRow; CurPos++)
	{
		Items.push(this.Content[CountColumn * CurPos + ColumnPos]);
	}

	History.Add(new CChangesMathMatrixRemoveColumn(this, ColumnPos, Items));
	this.raw_RemoveColumn(ColumnPos, Items.length);
};
CMathMatrix.prototype.raw_RemoveColumn = function(Pos, CountItems)
{
    var CountColumn = this.getColsCount();
    var RowPos  = this.CurPos/CountColumn >> 0; // номер строки

    for(var CurPos = 0; CurPos < CountItems; CurPos++)
    {
        this.Content.splice((CountColumn-1)*CurPos + Pos, 1);
    }

    this.Modify_ColumnCount(this.CurPos - CountColumn*RowPos, -1);

    this.fillContent();

    // Обновим текущую позицию
    if (this.CurPos > Pos - RowPos)
        this.CurPos -= RowPos;
    else if (this.CurPos > Pos )
        this.CurPos = Pos;

    this.private_CorrectCurPos();
    this.private_UpdatePosOnRemove(Pos, RowPos);
};
CMathMatrix.prototype.Modify_ColumnCount = function(Pos, Count)
{
    this.Pr.Modify_ColumnCount(Pos, Count);
    this.column = this.Pr.Get_ColumnsCount();
};
CMathMatrix.prototype.raw_SetColumnJc = function(Value, ColumnPos)
{
    this.RecalcInfo.bProps = true;
    this.Pr.Set_ColumnJc(Value, ColumnPos);
};
CMathMatrix.prototype.raw_HidePlh = function(Value)
{
    this.Pr.plcHide = Value;
    this.hidePlaceholder(Value);
};
CMathMatrix.prototype.raw_Set_MinColumnWidth = function(Value)
{
    this.Pr.cSp = Value;
    this.Set_RuleGap(this.SpaceColumn, this.Pr.cGpRule, this.Pr.cGp, Value);
};
CMathMatrix.prototype.Is_DeletedItem = function(Action)
{
    var bDeleteMatrix = false;

    if( c_oMathMenuAction.DeleteMatrixRow == Action && 1 == this.getRowsCount())
        bDeleteMatrix = true;
    else if(c_oMathMenuAction.DeleteMatrixColumn == Action && 1 == this.getColsCount())
        bDeleteMatrix = true;

    return bDeleteMatrix;
};
CMathMatrix.prototype.Get_DeletedItemsThroughInterface = function()
{
    return [];
};

/**
 *
 * @param CMathMenuMatrix
 * @constructor
 * @extends {CMathMenuBase}
 */
function CMathMenuMatrix(MathMatrix)
{
	CMathMenuBase.call(this, MathMatrix);

    this.Type           = Asc.c_oAscMathInterfaceType.Matrix;

    if (undefined !== MathMatrix)
    {
        var ColumnPos = MathMatrix.Get_ColumnPos(MathMatrix.CurPos);

        var RowRule, RowGap, ColumnRule, ColumnGap;
        switch (MathMatrix.SpaceRow.Rule)
        {
            default:
            case 0:
            {
                RowRule = c_oAscMathInterfaceMatrixRowRule.Single;
                break;
            }
            case 1:
            {
                RowRule = c_oAscMathInterfaceMatrixRowRule.OneAndHalf;
                break;
            }
            case 2:
            {
                RowRule = c_oAscMathInterfaceMatrixRowRule.Double;
                break;
            }
            case 3:
            {
                RowRule = c_oAscMathInterfaceMatrixRowRule.Exactly;
                RowGap  = MathMatrix.SpaceRow.Gap / 20;
                break;
            }
            case 4:
            {
                RowRule = c_oAscMathInterfaceMatrixRowRule.Multiple;
                RowGap  = MathMatrix.SpaceRow.Gap * 0.5;
                break;
            }
        }

        switch (MathMatrix.SpaceColumn.Rule)
        {
            default:
            case 0:
            {
                ColumnRule = c_oAscMathInterfaceMatrixColumnRule.Single;
                break;
            }
            case 1:
            {
                ColumnRule = c_oAscMathInterfaceMatrixColumnRule.OneAndHalf;
                break;
            }
            case 2:
            {
                ColumnRule = c_oAscMathInterfaceMatrixColumnRule.Double;
                break;
            }
            case 3:
            {
                ColumnRule = c_oAscMathInterfaceMatrixColumnRule.Exactly;
                ColumnGap  = MathMatrix.SpaceColumn.Gap / 20;
                break;
            }
            case 4:
            {
                ColumnRule = c_oAscMathInterfaceMatrixColumnRule.Multiple;
                ColumnGap  = (((0.21163 * MathMatrix.SpaceColumn.Gap) * 100 + 0.5) >> 0 ) / 100;
                break;
            }
        }

        var ColumnJc = MathMatrix.Pr.Get_ColumnMcJc(ColumnPos);

        this.BaseJc         = MathMatrix.Pr.baseJc === BASEJC_CENTER ? Asc.c_oAscMathInterfaceMatrixMatrixAlign.Center : (MathMatrix.Pr.baseJc === BASEJC_BOTTOM ? Asc.c_oAscMathInterfaceMatrixMatrixAlign.Bottom : Asc.c_oAscMathInterfaceMatrixMatrixAlign.Top);
        this.ColumnJc       = ColumnJc === MCJC_CENTER ? Asc.c_oAscMathInterfaceMatrixColumnAlign.Center : (ColumnJc === MCJC_RIGHT ? Asc.c_oAscMathInterfaceMatrixColumnAlign.Right : Asc.c_oAscMathInterfaceMatrixColumnAlign.Left);
        this.RowRule        = RowRule;
        this.RowGap         = RowGap;
        this.ColumnRule     = ColumnRule;
        this.ColumnGap      = ColumnGap;
        this.MinColumnWidth = MathMatrix.Pr.cSp / 20;
        this.bHidePlh       = MathMatrix.Pr.plcHide;
    }
    else
    {
        this.BaseJc         = undefined;
        this.ColumnJc       = undefined;
        this.RowRule        = undefined;
        this.RowGap         = undefined;
        this.ColumnRule     = undefined;
        this.ColumnGap      = undefined;
        this.MinColumnWidth = undefined;
        this.bHidePlh       = undefined;
    }
}
CMathMenuMatrix.prototype = Object.create(CMathMenuBase.prototype);
CMathMenuMatrix.prototype.constructor = CMathMenuMatrix;
CMathMenuMatrix.prototype.get_MatrixAlign     = function(){return this.BaseJc;};
CMathMenuMatrix.prototype.put_MatrixAlign     = function(Align){this.BaseJc = Align;};
CMathMenuMatrix.prototype.get_ColumnAlign     = function(){return this.ColumnJc;};
CMathMenuMatrix.prototype.put_ColumnAlign     = function(Align){this.ColumnJc = Align;};
CMathMenuMatrix.prototype.get_RowRule         = function(){return this.RowRule;};
CMathMenuMatrix.prototype.put_RowRule         = function(RowRule){this.RowRule = RowRule;};
CMathMenuMatrix.prototype.get_RowGap          = function(){return this.RowGap;};
CMathMenuMatrix.prototype.put_RowGap          = function(RowGap){this.RowGap = RowGap;};
CMathMenuMatrix.prototype.get_ColumnRule      = function(){return this.ColumnRule;};
CMathMenuMatrix.prototype.put_ColumnRule      = function(ColumnRule){this.ColumnRule = ColumnRule;};
CMathMenuMatrix.prototype.get_ColumnGap       = function(){return this.ColumnGap;};
CMathMenuMatrix.prototype.put_ColumnGap       = function(ColumnGap){this.ColumnGap = ColumnGap;};
CMathMenuMatrix.prototype.get_MinColumnSpace  = function(){return this.MinColumnWidth;};
CMathMenuMatrix.prototype.put_MinColumnSpace  = function(MinSpace){this.MinColumnWidth = MinSpace;};
CMathMenuMatrix.prototype.get_HidePlaceholder = function(){return this.bHidePlh;};
CMathMenuMatrix.prototype.put_HidePlaceholder = function(Hide){this.bHidePlh = Hide;};

window["CMathMenuMatrix"] = CMathMenuMatrix;
CMathMenuMatrix.prototype["get_MatrixAlign"]     = CMathMenuMatrix.prototype.get_MatrixAlign    ;
CMathMenuMatrix.prototype["put_MatrixAlign"]     = CMathMenuMatrix.prototype.put_MatrixAlign    ;
CMathMenuMatrix.prototype["get_ColumnAlign"]     = CMathMenuMatrix.prototype.get_ColumnAlign    ;
CMathMenuMatrix.prototype["put_ColumnAlign"]     = CMathMenuMatrix.prototype.put_ColumnAlign    ;
CMathMenuMatrix.prototype["get_RowRule"]         = CMathMenuMatrix.prototype.get_RowRule        ;
CMathMenuMatrix.prototype["put_RowRule"]         = CMathMenuMatrix.prototype.put_RowRule        ;
CMathMenuMatrix.prototype["get_RowGap"]          = CMathMenuMatrix.prototype.get_RowGap         ;
CMathMenuMatrix.prototype["put_RowGap"]          = CMathMenuMatrix.prototype.put_RowGap         ;
CMathMenuMatrix.prototype["get_ColumnRule"]      = CMathMenuMatrix.prototype.get_ColumnRule     ;
CMathMenuMatrix.prototype["put_ColumnRule"]      = CMathMenuMatrix.prototype.put_ColumnRule     ;
CMathMenuMatrix.prototype["get_ColumnGap"]       = CMathMenuMatrix.prototype.get_ColumnGap      ;
CMathMenuMatrix.prototype["put_ColumnGap"]       = CMathMenuMatrix.prototype.put_ColumnGap      ;
CMathMenuMatrix.prototype["get_MinColumnSpace"]  = CMathMenuMatrix.prototype.get_MinColumnSpace ;
CMathMenuMatrix.prototype["put_MinColumnSpace"]  = CMathMenuMatrix.prototype.put_MinColumnSpace ;
CMathMenuMatrix.prototype["get_HidePlaceholder"] = CMathMenuMatrix.prototype.get_HidePlaceholder;
CMathMenuMatrix.prototype["put_HidePlaceholder"] = CMathMenuMatrix.prototype.put_HidePlaceholder;

function CMathPoint()
{
    this.even = -1;
    this.odd  = -1;
}

function CMathEqArrPr()
{
    this.maxDist = 0;
    this.objDist = 0;
    this.rSp     = 0;
    this.rSpRule = 0;
    this.baseJc  = BASEJC_CENTER;

    this.row     = 1;
}
CMathEqArrPr.prototype.Set_FromObject = function(Obj)
{
    if(undefined !== Obj.maxDist && null !== Obj.maxDist)
        this.maxDist = Obj.maxDist;

    if(undefined !== Obj.objDist && null !== Obj.objDist)
        this.objDist = Obj.objDist;

    if(undefined !== Obj.rSp && null !== Obj.rSp)
        this.rSp = Obj.rSp;

    if(undefined !== Obj.rSpRule && null !== Obj.rSpRule)
        this.rSpRule = Obj.rSpRule;

    if(undefined !== Obj.baseJc && null !== Obj.baseJc)
        this.baseJc = Obj.baseJc;

    this.row = Obj.row;
};
CMathEqArrPr.prototype.Copy = function()
{
    var NewPr = new CMathEqArrPr();

    NewPr.maxDist = this.maxDist;
    NewPr.objDist = this.objDist;
    NewPr.rSp     = this.rSp    ;
    NewPr.rSpRule = this.rSpRule;
    NewPr.baseJc  = this.baseJc ;
    NewPr.row     = this.row;

    return NewPr;
};
CMathEqArrPr.prototype.Set_Row = function(Value)
{
    this.row = Value;
};
CMathEqArrPr.prototype.Set_BaseJc = function(Value)
{
    this.baseJc = Value;
};
CMathEqArrPr.prototype.Write_ToBinary = function(Writer)
{
    // Long : maxDist
    // Long : objDist
    // Long : rSp
    // Long : rSpRule
    // Long : baseJc
    // Long : row

    Writer.WriteLong(this.maxDist);
    Writer.WriteLong(this.objDist);
    Writer.WriteLong(this.rSp);
    Writer.WriteLong(this.rSpRule);
    Writer.WriteLong(this.baseJc);
    Writer.WriteLong(this.row);
};
CMathEqArrPr.prototype.Read_FromBinary = function(Reader)
{
    // Long : maxDist
    // Long : objDist
    // Long : rSp
    // Long : rSpRule
    // Long : baseJc
    // Long : row

    this.maxDist = Reader.GetLong();
    this.objDist = Reader.GetLong();
    this.rSp     = Reader.GetLong();
    this.rSpRule = Reader.GetLong();
    this.baseJc  = Reader.GetLong();
    this.row     = Reader.GetLong();
};


/**
 *
 * @param props
 * @constructor
 * @extends {CMatrixBase}
 */
function CEqArray(props)
{
	CMatrixBase.call(this);

	this.Id = AscCommon.g_oIdCounter.Get_NewId();
    this.Pr = new CMathEqArrPr();

    // for ampersand in Run
    this.WidthsPoints = [];
    this.Points       = [];
    this.MaxDimWidths = [];
    //

    if(props !== null && props !== undefined)
        this.init(props);

    AscCommon.g_oTableId.Add( this, this.Id );
}
CEqArray.prototype = Object.create(CMatrixBase.prototype);
CEqArray.prototype.constructor = CEqArray;

CEqArray.prototype.ClassType = AscDFH.historyitem_type_eqArr;
CEqArray.prototype.kind      = MATH_EQ_ARRAY;

CEqArray.prototype.init = function(props)
{
    var nRowsCount = props.row;

    this.Fill_LogicalContent(nRowsCount);

    this.setProperties(props);
    this.fillContent();
};
CEqArray.prototype.fillContent = function()
{
    var nRowsCount = this.Content.length;
    this.setDimension(nRowsCount, 1);

    for (var nIndex = 0; nIndex < nRowsCount; nIndex++)
        this.elements[nIndex][0] = this.Content[nIndex];
};
CEqArray.prototype.getColsCount = function()
{
    return 1;
};
CEqArray.prototype.Resize = function(oMeasure, RPI)
{
    var bEqArray = RPI.bEqArray;
    RPI.bEqArray = true;

    for(var i = 0; i < this.nRow; i++)
        this.elements[i][0].Resize(oMeasure, RPI);

    this.recalculateSize(oMeasure);

    RPI.bEqArray = bEqArray;
};
CEqArray.prototype.getMetrics = function()
{
    var AscentsMetrics = [];
    var DescentsMetrics = [];
    var WidthsMetrics = [];

    // нумерация начинается с нуля, поэтому все четные точки идут с нечетными номерами в массиве

    var EndWidths = 0;

    var even, // четная точка
        odd,  // нечетная точка
        last;

    var maxDim, maxDimWidth;

    var Pos = 0;

    this.WidthsPoints.length = 0;
    this.Points.length       = 0;
    this.MaxDimWidths.length = 0;

    WidthsMetrics[0] = 0;

    while(EndWidths < this.nRow)
    {
        even = 0;
        odd  = 0;
        last = 0;

        maxDim = 0;
        maxDimWidth = 0;

        for(var i = 0; i < this.nRow; i++)
        {
            var WidthsRow = this.elements[i][0].Get_WidthPoints().Widths,
                len = WidthsRow.length;

            if(Pos < len)
            {
                if(WidthsRow[Pos].odd !== -1)
                {
                    if(maxDim < WidthsRow[Pos].even || maxDim < WidthsRow[Pos].odd)
                    {
                        maxDim = WidthsRow[Pos].even < WidthsRow[Pos].odd ? WidthsRow[Pos].odd : WidthsRow[Pos].even;
                        maxDimWidth = WidthsRow[Pos].even + WidthsRow[Pos].odd;
                    }
                    even = even > WidthsRow[Pos].even  ? even : WidthsRow[Pos].even;  // before "odd"
                    odd  = odd  > WidthsRow[Pos].odd   ? odd  : WidthsRow[Pos].odd;   // after  "odd"
                }
                else
                {
                    if(maxDim < WidthsRow[Pos].even)
                    {
                        maxDim = WidthsRow[Pos].even;
                        maxDimWidth = maxDim;
                    }
                    last = last > WidthsRow[Pos].even ? last: WidthsRow[Pos].even;
                }

                if(Pos == len - 1)
                    EndWidths++;
            }
        }

        var w = even + odd > last ? even + odd : last;

        var NewPoint = new CMathPoint();
        NewPoint.even   = even;
        NewPoint.odd    = odd;

        this.WidthsPoints.push(w);
        this.MaxDimWidths.push(maxDimWidth);
        this.Points.push(NewPoint);

        WidthsMetrics[0] += w;

        Pos++;
    }

    for(var i = 0; i < this.nRow; i++)
        this.elements[i][0].ApplyPoints(this.WidthsPoints, this.Points, this.MaxDimWidths);


    for(var i = 0; i < this.nRow; i++)
    {
        var size = this.elements[i][0].size;
        AscentsMetrics[i]  = size.ascent;
        DescentsMetrics[i] = size.height - size.ascent;
    }

    return {ascents: AscentsMetrics, descents: DescentsMetrics, widths: WidthsMetrics};
};
CEqArray.prototype.setPosition = function(pos, PosInfo)
{
    this.pos.x = pos.x;

    if(this.bInside === true)
        this.pos.y = pos.y;
    else
        this.pos.y = pos.y - this.size.ascent; ///!!!!

    this.UpdatePosBound(pos, PosInfo);

    var maxWH = this.getWidthsHeights();
    var Heights = maxWH.heights;

    var NewPos = new CMathPosition();

    var h = 0;

    for(var i=0; i < this.nRow; i++)
    {
        var Item = this.elements[i][0];
        NewPos.x = this.pos.x + this.GapLeft;
        NewPos.y = this.pos.y + h + Item.size.ascent;

        Item.setPosition(NewPos, PosInfo);

        h += Heights[i] + this.gaps.row[i];
    }

    pos.x += this.size.width;
};
CEqArray.prototype.setJustificationForConversion = function(js) // эта функция должна вызываться только при конвертации, после того как у всех элементов контенты заполнены
{
    var lng = this.Content.length;
    var NewElement, Run;

    if(js == MCJC_LEFT)
    {
        for(var i = 0; i < lng; i++)
        {
            NewElement = new CMathAmp();
            Run = this.Content[i].Content[0];
            Run.MoveCursorToStartPos();
            Run.Add(NewElement, true);
        }
    }
    else if(js == MCJC_RIGHT)
    {
        for(var i = 0; i < lng; i++)
        {
            NewElement = new CMathAmp();
            var EndPos = this.Content[i].Content.length - 1;
            Run = this.Content[i].Content[EndPos];
            Run.MoveCursorToEndPos();
            Run.Add(NewElement, true);
        }
    }

};
CEqArray.prototype.getElement = function(num)
{
    return this.elements[num][0];
};
CEqArray.prototype.getElementMathContent = function(Index)
{
    return this.Content[Index];
};
CEqArray.prototype.Apply_MenuProps = function(Props)
{
    if(Props.Type == Asc.c_oAscMathInterfaceType.EqArray)
    {
        if(Props.BaseJc !== undefined)
        {
            var BaseJc = this.Pr.baseJc;

            if(Props.BaseJc === Asc.c_oAscMathInterfaceEqArrayAlign.Center)
            {
                BaseJc = BASEJC_CENTER;
            }
            else if(Props.BaseJc === Asc.c_oAscMathInterfaceEqArrayAlign.Bottom)
            {
                BaseJc = BASEJC_BOTTOM;
            }
            else if(Props.BaseJc === Asc.c_oAscMathInterfaceEqArrayAlign.Top)
            {
                BaseJc = BASEJC_TOP;
            }

            this.SetBaseJc(BaseJc);
        }

        if(Props.RowRule !== undefined)
        {
            switch(Props.RowRule)
            {
                case c_oAscMathInterfaceEqArrayLineRule.Single:
                {
                    this.Modify_Interval(this.SpaceRow, 0, 0);
                    break;
                }
                case c_oAscMathInterfaceEqArrayLineRule.OneAndHalf:
                {
                    this.Modify_Interval(this.SpaceRow, 1, 0);
                    break;
                }
                case c_oAscMathInterfaceEqArrayLineRule.Double:
                {
                    this.Modify_Interval(this.SpaceRow, 2, 0);
                    break;
                }
                case c_oAscMathInterfaceEqArrayLineRule.Exactly:
                {
                    var bGapWholeNumber = Props.Gap !== undefined && Props.Gap + 0 == Props.Gap && Props.Gap >> 0 == Props.Gap;

                    if(bGapWholeNumber == true && Props.Gap >= 0 && Props.Gap <= 31680)
                    {
                        this.Modify_Interval(this.SpaceRow, 3, Props.Gap*20);
                    }

                    break;
                }
                case c_oAscMathInterfaceEqArrayLineRule.Multiple:
                {
                    var bGapNumber = Props.Gap !== undefined && Props.Gap + 0 == Props.Gap;

                    if(bGapNumber == true && Props.Gap >= 0 && Props.Gap <= 111)
                    {
                        var Gap = (Props.Gap*2 + 0.5) >> 0;

                        this.Modify_Interval(this.SpaceRow, 4, Gap);
                    }

                    break;
                }
            }
        }

        if(Props.Action & c_oMathMenuAction.DeleteEquation && this.getRowsCount() > 1)
        {
            this.Remove_Row(this.CurPos);
        }

        if(Props.Action & c_oMathMenuAction.InsertEquation)
        {
            if(Props.Action & c_oMathMenuAction.InsertBefore)
            {
                this.Add_Row(this.CurPos);
            }
            else
            {
                this.Add_Row(this.CurPos + 1);
            }
        }
    }

};
CEqArray.prototype.Get_InterfaceProps = function()
{
    return new CMathMenuEqArray(this);
};
CEqArray.prototype.Is_DeletedItem = function(Action)
{
    return Action & c_oMathMenuAction.DeleteEquation && 1 == this.getRowsCount();
};
CEqArray.prototype.Get_DeletedItemsThroughInterface = function()
{
    return [];
};
CEqArray.prototype.IsEqArray = function()
{
    return true;
};

/**
 *
 * @param CMathMenuEqArray
 * @constructor
 * @extends {CMathMenuBase}
 */
function CMathMenuEqArray(EqArray)
{
	CMathMenuBase.call(this, EqArray);

    this.Type    = Asc.c_oAscMathInterfaceType.EqArray;

    if (undefined !== EqArray)
    {
        var RowRule, RowGap;
        switch (EqArray.SpaceRow.Rule)
        {
            default:
            case 0:
            {
                RowRule = c_oAscMathInterfaceEqArrayLineRule.Single;
                break;
            }
            case 1:
            {
                RowRule = c_oAscMathInterfaceEqArrayLineRule.OneAndHalf;
                break;
            }
            case 2:
            {
                RowRule = c_oAscMathInterfaceEqArrayLineRule.Double;
                break;
            }
            case 3:
            {
                RowRule = c_oAscMathInterfaceEqArrayLineRule.Exactly;
                RowGap  = EqArray.SpaceRow.Gap / 20;
                break;
            }
            case 4:
            {
                RowRule = c_oAscMathInterfaceEqArrayLineRule.Multiple;
                RowGap  = EqArray.SpaceRow.Gap * 0.5;
                break;
            }
        }

        this.BaseJc  = EqArray.Pr.baseJc === BASEJC_CENTER ? Asc.c_oAscMathInterfaceEqArrayAlign.Center : (EqArray.Pr.baseJc === BASEJC_BOTTOM ? Asc.c_oAscMathInterfaceEqArrayAlign.Bottom : Asc.c_oAscMathInterfaceEqArrayAlign.Top);
        this.RowRule = RowRule;
        this.RowGap  = RowGap;
    }
    else
    {
        this.BaseJc  = undefined;
        this.RowRule = undefined;
        this.RowGap  = undefined;
    }
}
CMathMenuEqArray.prototype = Object.create(CMathMenuBase.prototype);
CMathMenuEqArray.prototype.constructor = CMathMenuEqArray;
CMathMenuEqArray.prototype.get_Align    = function(){return this.BaseJc;};
CMathMenuEqArray.prototype.put_Align    = function(Align){this.BaseJc = Align;};
CMathMenuEqArray.prototype.get_LineRule = function(){return this.RowRule;};
CMathMenuEqArray.prototype.put_LineRule = function(Rule){this.RowRule = Rule;};
CMathMenuEqArray.prototype.get_LineGap  = function(){return this.RowGap;};
CMathMenuEqArray.prototype.put_LineGap  = function(Gap){this.RowGap = Gap;};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CEqArray = CEqArray;
window['AscCommonWord'].CMathMatrix = CMathMatrix;

window["CMathMenuEqArray"] = CMathMenuEqArray;
CMathMenuEqArray.prototype["get_Align"]    = CMathMenuEqArray.prototype.get_Align;
CMathMenuEqArray.prototype["put_Align"]    = CMathMenuEqArray.prototype.put_Align;
CMathMenuEqArray.prototype["get_LineRule"] = CMathMenuEqArray.prototype.get_LineRule;
CMathMenuEqArray.prototype["put_LineRule"] = CMathMenuEqArray.prototype.put_LineRule;
CMathMenuEqArray.prototype["get_LineGap"]  = CMathMenuEqArray.prototype.get_LineGap ;
CMathMenuEqArray.prototype["put_LineGap"]  = CMathMenuEqArray.prototype.put_LineGap ;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

function CMathLimitPr()
{
    this.type = LIMIT_LOW;
}

CMathLimitPr.prototype.Set_FromObject = function(Obj)
{
    if (undefined !== Obj.type && null !== Obj.type)
        this.type = Obj.type;
};

CMathLimitPr.prototype.Copy = function()
{
    var NewPr = new CMathLimitPr();
    NewPr.type = this.type;
    return NewPr;
};

CMathLimitPr.prototype.Write_ToBinary = function(Writer)
{
    // Long : type
    Writer.WriteLong(this.type);
};

CMathLimitPr.prototype.Read_FromBinary = function(Reader)
{
    // Long : type
    this.type = Reader.GetLong();
};

/**
 *
 * @param bInside
 * @param Type
 * @param FName
 * @param Iterator
 * @constructor
 * @extends {CMathBase}
 */
function CLimitPrimary(bInside, Type, FName, Iterator)
{
	CMathBase.call(this, bInside);

    this.Type = Type;
    this.FName = null;
    this.Iterator = null;

    this.init(FName, Iterator);
}
CLimitPrimary.prototype = Object.create(CMathBase.prototype);
CLimitPrimary.prototype.constructor = CLimitPrimary;
CLimitPrimary.prototype.kind      = MATH_PRIMARY_LIMIT;
CLimitPrimary.prototype.init = function(FName, Iterator)
{
    this.setDimension(2, 1);

    if(this.Type == LIMIT_LOW)
    {
        this.FName  = FName;
        this.Iterator = new CDenominator(Iterator);

        this.elements[0][0] = this.FName;
        this.elements[1][0] = this.Iterator;
    }
    else
    {
        this.Iterator = Iterator;
        this.FName    = FName;

        this.elements[0][0] = this.Iterator;
        this.elements[1][0] = this.FName;
    }
};
CLimitPrimary.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI, GapsInfo)
{
    this.Parent = Parent;
    this.ParaMath = ParaMath;

    this.Set_CompiledCtrPrp(Parent, ParaMath, RPI);

    if(this.bInside == false)
        GapsInfo.setGaps(this, this.TextPrControlLetter.FontSize);

    this.FName.PreRecalc(this, ParaMath, ArgSize, RPI);

    var ArgSzIter = ArgSize.Copy();
    ArgSzIter.Decrease();

    var bDecreasedComp = RPI.bDecreasedComp;
    RPI.bDecreasedComp = true;

    this.Iterator.PreRecalc(this, ParaMath, ArgSzIter, RPI);

    RPI.bDecreasedComp = bDecreasedComp;
};
CLimitPrimary.prototype.Resize = function(oMeasure, RPI)
{
    this.FName.Resize(oMeasure, RPI);

    this.Iterator.Resize(oMeasure, RPI);

    this.recalculateSize(oMeasure);
};
CLimitPrimary.prototype.recalculateSize = function(oMeasure)
{
    if(this.Type == LIMIT_LOW)
        this.dH = 0;
    else
        this.dH = 0.06*this.Get_TxtPrControlLetter().FontSize;

    var SizeFName = this.FName.size,
        SizeIter  = this.Iterator.size;

    var width  = SizeFName.width > SizeIter.width ? SizeFName.width : SizeIter.width,
        height = SizeFName.height + SizeIter.height + this.dH,
        ascent;

    if(this.Type == LIMIT_LOW)
        ascent = SizeFName.ascent;
    else
        ascent = SizeIter.height + this.dH + SizeFName.ascent;


    width += this.GapLeft + this.GapRight;

    this.size.height = height;
    this.size.width  = width;
    this.size.ascent = ascent;
};
CLimitPrimary.prototype.setPosition = function(pos, PosInfo)
{
    this.pos.x = pos.x;
    this.pos.y = pos.y;

    var maxW = this.FName.size.width > this.Iterator.size.width ? this.FName.size.width : this.Iterator.size.width;

    var alignFNameX = (maxW - this.FName.size.width)/2;
    var alignIterX  = (maxW - this.Iterator.size.width)/2;

    var FNamePos = new CMathPosition();
    var IterPos = new CMathPosition();

    if(this.Type == LIMIT_LOW)
    {
        FNamePos.x = this.pos.x + this.GapLeft + alignFNameX;
        FNamePos.y = this.pos.y + this.FName.size.ascent;

        IterPos.x = this.pos.x + this.GapLeft + alignIterX;
        IterPos.y = this.pos.y + this.dH + this.FName.size.height;
    }
    else
    {
        IterPos.x = this.pos.x + this.GapLeft + alignIterX;
        IterPos.y = this.pos.y + this.Iterator.size.ascent;

        FNamePos.x = this.pos.x + this.GapLeft + alignFNameX;
        FNamePos.y = this.pos.y + this.FName.size.ascent + this.dH + this.Iterator.size.height;
    }

    // такой порядок нужен для выравнивания Box по операторам
    this.FName.setPosition(FNamePos, PosInfo);
    this.Iterator.setPosition(IterPos, PosInfo);

    pos.x += this.size.width;
};

/**
 *
 * @param props
 * @constructor
 * @extends {CMathBase}
 */
function CLimit(props)
{
	CMathBase.call(this);

	this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.Pr = new CMathLimitPr();

    if(props !== null && typeof(props) !== "undefined")
        this.init(props);

    AscCommon.g_oTableId.Add( this, this.Id );
}
CLimit.prototype = Object.create(CMathBase.prototype);
CLimit.prototype.constructor = CLimit;

CLimit.prototype.ClassType = AscDFH.historyitem_type_lim;
CLimit.prototype.kind      = MATH_LIMIT;

CLimit.prototype.init = function(props)
{
    this.Fill_LogicalContent(2);

    // посмотреть GetAllFonts
    this.setProperties(props);
    this.fillContent();
};
CLimit.prototype.fillContent = function()
{
};
CLimit.prototype.getFName = function()
{
    return this.Content[0];
};
CLimit.prototype.getIterator = function()
{
    return this.Content[1];
};
CLimit.prototype.getBase = function()
{
    return this.getFName();
};
CLimit.prototype.ApplyProperties = function(RPI)
{
    // реализовано также как и для Word 2010
    // в 2007 реализовано limit для inline формул как степень (закомментированный код)

    /*if(this.RecalcInfo.bProps == true || RPI.bChangeInline == true)
    {
        this.setDimension(1, 1);

        if(RPI.bInline == true && RPI.bMathFunc == true)
        {
            var props;

            if(this.Pr.type == LIMIT_LOW)
                props = {type:   DEGREE_SUBSCRIPT, ctrPrp: this.CtrPrp};
            else
                props = {type:   DEGREE_SUPERSCRIPT, ctrPrp: this.CtrPrp};

            this.elements[0][0] = new CDegreeBase(props, true);
            this.elements[0][0].setBase(this.getFName());
            this.elements[0][0].setIterator(this.getIterator());
            this.elements[0][0].fillContent();
        }
        else
        {
            this.elements[0][0] = new CLimitPrimary(true, this.Pr.type, this.getFName(), this.getIterator());
        }

        this.RecalcInfo.bProps = false;
    }*/

    if(this.RecalcInfo.bProps == true || (RPI != undefined && RPI.bChangeInline == true))
    {
        this.setDimension(1, 1);
        this.elements[0][0] = new CLimitPrimary(true, this.Pr.type, this.getFName(), this.getIterator());
        this.RecalcInfo.bProps = false;
    }

};
CLimit.prototype.Apply_MenuProps = function(Props)
{
	if (Props.Type == Asc.c_oAscMathInterfaceType.Limit && Props.Pos !== undefined)
	{
		var Type = Props.Pos == Asc.c_oAscMathInterfaceLimitPos.Bottom ? LIMIT_LOW : LIMIT_UP;

		if (this.Pr.type !== Type)
		{
			AscCommon.History.Add(new CChangesMathLimitType(this, this.Pr.type, Type));
			this.raw_SetType(Type);
		}
	}
};
CLimit.prototype.Get_InterfaceProps = function()
{
    return new CMathMenuLimit(this);
};
CLimit.prototype.raw_SetType = function(Value)
{
    if(this.Pr.type !== Value)
    {
        this.Pr.type = Value;
        this.RecalcInfo.bProps = true;
        this.ApplyProperties();
    }
};
CLimit.prototype.Can_ModifyArgSize = function()
{
    return this.CurPos == 1 && false === this.Is_SelectInside();
};

/**
 *
 * @param CMathMenuLimit
 * @constructor
 * @extends {CMathMenuBase}
 */
function CMathMenuLimit(Limit)
{
	CMathMenuBase.call(this, Limit);

    this.Type = Asc.c_oAscMathInterfaceType.Limit;

    if (undefined !== Limit)
    {
        this.Pos  = (LIMIT_LOW === Limit.Pr.type) ? Asc.c_oAscMathInterfaceLimitPos.Bottom : Asc.c_oAscMathInterfaceLimitPos.Top;
    }
    else
    {
        this.Pos = undefined;
    }
}
CMathMenuLimit.prototype = Object.create(CMathMenuBase.prototype);
CMathMenuLimit.prototype.constructor = CMathMenuLimit;

CMathMenuLimit.prototype.get_Pos = function(){return this.Pos;};
CMathMenuLimit.prototype.put_Pos = function(Pos){this.Pos = Pos;};

window["CMathMenuLimit"] = CMathMenuLimit;
CMathMenuLimit.prototype["get_Pos"] = CMathMenuLimit.prototype.get_Pos;
CMathMenuLimit.prototype["put_Pos"] = CMathMenuLimit.prototype.put_Pos;

/**
 *
 * @param props
 * @constructor
 * @extends {CMathBase}
 */
function CMathFunc(props)
{
	CMathBase.call(this);

	this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.Pr = new CMathBasePr();

    if(props !== null && typeof(props) !== "undefined")
        this.init(props);

    AscCommon.g_oTableId.Add( this, this.Id );
}
CMathFunc.prototype = Object.create(CMathBase.prototype);
CMathFunc.prototype.constructor = CMathFunc;

CMathFunc.prototype.ClassType = AscDFH.historyitem_type_mathFunc;
CMathFunc.prototype.kind      = MATH_FUNCTION;

CMathFunc.prototype.init = function(props)
{
    this.Fill_LogicalContent(2);

    this.setProperties(props);
    this.fillContent();
};
CMathFunc.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI, GapsInfo)
{
    var bMathFunc = RPI.bMathFunc;
    RPI.bMathFunc = true;

	CMathBase.prototype.PreRecalc.call(this, Parent, ParaMath, ArgSize, RPI, GapsInfo);

    RPI.bMathFunc = bMathFunc;
};
CMathFunc.prototype.GetLastElement = function()
{
    return this.Content[1].GetFirstElement();
};
CMathFunc.prototype.GetFirstElement = function()
{
    return this.Content[0].GetFirstElement();
};
CMathFunc.prototype.setDistance = function()
{
    this.dW = this.Get_TxtPrControlLetter().FontSize*0.044;
};
CMathFunc.prototype.getFName = function()
{
    return this.Content[0];
};
CMathFunc.prototype.getArgument = function()
{
    return this.Content[1];
};
CMathFunc.prototype.fillContent = function()
{
    this.NeedBreakContent(1);

    this.setDimension(1, 2);
    this.elements[0][0] = this.getFName();
    this.elements[0][1] = this.getArgument();
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CMathFunc = CMathFunc;
window['AscCommonWord'].CLimit = CLimit;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

//величина символа "сигма" не меняется в зависимости от аргумента
//если не выставлено в настройках
/////////////////////****//////////////////////////

function CMathNaryPr()
{
    this.chr     = undefined;
    this.chrType = NARY_INTEGRAL;
    this.grow    = false;
    this.limLoc  = undefined;
    this.subHide = false;
    this.supHide = false;
}

CMathNaryPr.prototype.Set_FromObject = function(Obj)
{
    this.chr     = Obj.chr;
    this.chrType = Obj.chrType;

    if(true === Obj.grow === true || 1 === Obj.grow)
        this.grow = true;

    if(NARY_UndOvr === Obj.limLoc || NARY_SubSup === Obj.limLoc)
        this.limLoc = Obj.limLoc;

    if(true === Obj.subHide === true || 1 === Obj.subHide)
        this.subHide = true;

    if(true === Obj.supHide === true || 1 === Obj.supHide)
        this.supHide = true;
};

CMathNaryPr.prototype.Copy = function()
{
    var NewPr = new CMathNaryPr();

    NewPr.chr     = this.chr    ;
    NewPr.chrType = this.chrType;
    NewPr.grow    = this.grow   ;
    NewPr.limLoc  = this.limLoc ;
    NewPr.subHide = this.subHide;
    NewPr.supHide = this.supHide;

    return NewPr;
};

CMathNaryPr.prototype.Write_ToBinary = function(Writer)
{
    // Long : flags

    // Long : chr
    // Long : chrType
    // Long : limLoc

    // Bool : grow
    // Bool : subHide
    // Bool : supHide

    var StartPos = Writer.GetCurPosition();
    Writer.Skip(4);
    var Flags = 0;

    if (undefined !== this.chr)
    {
        Writer.WriteLong(this.chr);
        Flags |= 1;
    }

    if (undefined !== this.chrType)
    {
        Writer.WriteLong(this.chrType);
        Flags |= 2;
    }

    if (undefined !== this.limLoc)
    {
        Writer.WriteLong(this.limLoc);
        Flags |= 4;
    }

    var EndPos = Writer.GetCurPosition();
    Writer.Seek(StartPos);
    Writer.WriteLong(Flags);
    Writer.Seek(EndPos);

    Writer.WriteBool(this.grow);
    Writer.WriteBool(this.subHide);
    Writer.WriteBool(this.supHide);
};

CMathNaryPr.prototype.Read_FromBinary = function(Reader)
{
    // Long : flags

    // Long : chr
    // Long : chrType
    // Long : limLoc

    // Bool : grow
    // Bool : subHide
    // Bool : supHide

    var Flags = Reader.GetLong();

    if (Flags & 1)
        this.chr = Reader.GetLong();
    else
        this.chr = undefined;

    if (Flags & 2)
        this.chrType = Reader.GetLong();
    else
        this.chrType = undefined;

    if (Flags & 4)
        this.limLoc = Reader.GetLong();
    else
        this.limLoc = undefined;

    this.grow    = Reader.GetBool();
    this.subHide = Reader.GetBool();
    this.supHide = Reader.GetBool();
};

/**
 *
 * @param props
 * @constructor
 * @extends {CMathBase}
 */
function CNary(props)
{
	CMathBase.call(this);

	this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.Pr = new CMathNaryPr();

    this.Base = null;
    this.Sign = null;
    this.LowerIterator = null;
    this.UpperIterator = null;
    this.Arg           = null;

    this.CurrentLimLoc = null;

    if(props !== null && props !== undefined)
        this.init(props);

    AscCommon.g_oTableId.Add( this, this.Id );
}
CNary.prototype = Object.create(CMathBase.prototype);
CNary.prototype.constructor = CNary;

CNary.prototype.ClassType = AscDFH.historyitem_type_nary;
CNary.prototype.kind      = MATH_NARY;
  
CNary.prototype.init = function(props)
{
    this.Fill_LogicalContent(3);

    this.setProperties(props);
    this.fillContent();
};
CNary.prototype.fillContent = function()
{
    this.NeedBreakContent(2);
    
    this.LowerIterator = this.Content[0];
    this.UpperIterator = this.Content[1];
    this.Arg           = this.Content[2];
};
CNary.prototype.fillBase = function(PropsInfo)
{
    this.setDimension(1, 2);

    var base;

    var Sign = PropsInfo.sign;
    var ctrPrp = this.CtrPrp.Copy();

    if(PropsInfo.limLoc === NARY_UndOvr)
    {
        if(PropsInfo.supHide && PropsInfo.subHide)
        {
            base = Sign;
        }
        else if( PropsInfo.supHide && !PropsInfo.subHide )
        {
            base = new CNaryOvr(true);
            base.setBase(Sign);
            base.setLowerIterator(this.LowerIterator);
        }
        else if( !PropsInfo.supHide && PropsInfo.subHide )
        {
            base = new CNaryUnd(true);
            base.setBase(Sign);
            base.setUpperIterator(this.UpperIterator);
        }
        else
        {
            base = new CNaryUndOvr(true);
            base.setBase(Sign);
            base.setUpperIterator(this.UpperIterator);
            base.setLowerIterator(this.LowerIterator);
        }
    }
    else
    {
        var prp;

        if( PropsInfo.supHide && !PropsInfo.subHide )
        {
            prp = {type: DEGREE_SUBSCRIPT, ctrPrp:  ctrPrp};
            base = new CDegreeBase(prp, true);
            base.setBase(Sign);
            base.setIterator(this.LowerIterator);
            base.fillContent();
        }
        else if( !PropsInfo.supHide && PropsInfo.subHide )
        {
            prp = {type: DEGREE_SUPERSCRIPT, ctrPrp: ctrPrp};
            base = new CDegreeBase(prp, true);
            base.setBase(Sign);
            base.setIterator(this.UpperIterator);

            base.fillContent();

        }
        else if(PropsInfo.supHide && PropsInfo.subHide)
        {
            base = Sign;
        }
        else
        {
            prp = {type: DEGREE_SubSup, ctrPrp: ctrPrp};
            base = new CDegreeSubSupBase(prp, true);
            base.setBase(Sign);
            base.setLowerIterator(this.LowerIterator);
            base.setUpperIterator(this.UpperIterator);
            
            base.fillContent();
        }
    }

    this.Base = base;

    this.addMCToContent( [base, this.Arg] );

};
CNary.prototype.ApplyProperties = function(RPI)
{
    var bSimpleNarySubSup = RPI.bInline == true || RPI.bDecreasedComp == true;
    var limLoc = bSimpleNarySubSup == true ? NARY_SubSup : this.private_GetLimLoc();

    if(this.RecalcInfo.bProps == true || RPI.bChangeInline == true || limLoc !== this.CurrentLimLoc)
    {
        var oSign = this.getSign(this.Pr.chr, this.Pr.chrType);

        if(bSimpleNarySubSup)
        {
            this.Sign = new CMathText(true);
            this.Sign.add(oSign.chrCode);
        }
        else
        {
            this.Sign = oSign.operator;
        }

        var PropsInfo =
        {
            limLoc :    limLoc,
            sign:       this.Sign,
            supHide:    this.Pr.supHide,
            subHide:    this.Pr.subHide
        };

        // пока оставим так, chrType сейчас нигде не используется
        this.Pr.chrType = oSign.chrType;

        this.fillBase(PropsInfo);

        this.RecalcInfo.bProps = false;
    }

    this.CurrentLimLoc = limLoc;
};
CNary.prototype.private_GetLimLoc = function()
{
    var limLoc         = this.Pr.limLoc;

    if(limLoc === null || limLoc === undefined)
    {
        var bIntegral = (this.Pr.chr > 0x222A && this.Pr.chr < 0x2231) || this.Pr.chr === null || this.Pr.chr === undefined;

        var oMathSettings = Get_WordDocumentDefaultMathSettings();
        if(bIntegral)
            limLoc = oMathSettings.Get_IntLim();
        else
            limLoc = oMathSettings.Get_NaryLim();
    }

    return limLoc;
};
CNary.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI, GapsInfo)
{
    var bNaryInline = RPI.bNaryInline;

    if(RPI.bInline || RPI.bDecreasedComp)
        RPI.bNaryInline = true;

    CMathBase.prototype.PreRecalc.call(this, Parent, ParaMath, ArgSize, RPI, GapsInfo);

    RPI.bNaryInline = bNaryInline;
};
CNary.prototype.getSign = function(chrCode, chrType)
{    
    var result = 
    {
        chrCode:   null,
        chrType:   null,
        operator:  null
    };

    var bChr = chrCode !== null && chrCode == chrCode + 0;

    if(chrCode == 0x222B || chrType == NARY_INTEGRAL)
    {
        result.chrCode = 0x222B;
        result.chrType = NARY_INTEGRAL;
        result.operator = new CIntegral();
    }
    else if(chrCode == 0x222C || chrType == NARY_DOUBLE_INTEGRAL)
    {
        result.chrCode = 0x222C;
        result.chrType = NARY_DOUBLE_INTEGRAL;
        result.operator = new CDoubleIntegral();
    }
    else if(chrCode == 0x222D || chrType == NARY_TRIPLE_INTEGRAL)
    {
        result.chrCode = 0x222D;
        result.chrType = NARY_TRIPLE_INTEGRAL;
        result.operator = new CTripleIntegral();
    }
    else if(chrCode == 0x222E || chrType == NARY_CONTOUR_INTEGRAL )
    {
        result.chrCode = 0x222E;
        result.chrType = NARY_CONTOUR_INTEGRAL;
        result.operator = new CContourIntegral();
    }
    else if(chrCode == 0x222F || chrType == NARY_SURFACE_INTEGRAL )
    {
        result.chrCode = 0x222F;
        result.chrType = NARY_SURFACE_INTEGRAL;
        result.operator = new CSurfaceIntegral();
    }
    else if(chrCode == 0x2230 || chrType == NARY_VOLUME_INTEGRAL)
    {
        result.chrCode = 0x2230;
        result.chrType = NARY_VOLUME_INTEGRAL;
        result.operator = new CVolumeIntegral();
    }
    else if(chrCode == 0x2211 || chrType == NARY_SIGMA)
    {
        result.chrCode = 0x2211;
        result.chrType = NARY_SIGMA;
        result.operator = new CSigma();
    }
    else if(chrCode == 0x220F || chrType == NARY_PRODUCT)
    {
        result.chrCode = 0x220F;
        result.chrType = NARY_PRODUCT;
        result.operator = new CProduct();
    }
    else if(chrCode == 0x2210 || chrType == NARY_COPRODUCT)
    {
        result.chrCode = 0x2210;
        result.chrType = NARY_COPRODUCT;
        result.operator = new CProduct(-1);
    }
    else if(chrCode == 0x22C3 || chrType == NARY_UNION)
    {
        result.chrCode = 0x22C3;
        result.chrType = NARY_UNION;
        result.operator = new CUnion();
    }
    else if(chrCode == 0x22C2 || chrType == NARY_INTERSECTION)
    {
        result.chrCode = 0x22C2;
        result.chrType = NARY_INTERSECTION;
        result.operator = new CUnion(-1);
    }
    else if(chrCode == 0x22C1 || chrType == NARY_LOGICAL_OR)
    {
        result.chrCode = 0x22C1;
        result.chrType = NARY_LOGICAL_OR;
        result.operator  = new CLogicalOr();
    }
    else if(chrCode == 0x22C0 || chrType == NARY_LOGICAL_AND)
    {
        result.chrCode = 0x22C0;
        result.chrType = NARY_LOGICAL_AND;
        result.operator  = new CLogicalOr(-1);
    }
    else if(bChr)
    {
        result.chrCode = chrCode;
        result.chrType = NARY_TEXT_OPER;
        result.operator = new CMathText(true);
        result.operator.add(chrCode);

    }
    else
    {
        result.chrCode = 0x222B;
        result.chrType = NARY_INTEGRAL;
        result.operator = new CIntegral();
    }

    return result;
};
CNary.prototype.setCtrPrp = function(txtPrp)
{
    this.CtrPrp.Merge(txtPrp); // only runPrp for paragraph
    //this.RunPrp.setTxtPrp(txtPrp);

    if(this.elements.length > 0 && !this.elements[0][0].IsJustDraw())
    {
        this.elements[0][0].setCtrPrp(this.CtrPrp);
    }
};
CNary.prototype.setDistance = function()
{
    this.dW = this.Get_TxtPrControlLetter().FontSize/36*2.45;
};
CNary.prototype.getBase = function()
{
    return this.Arg;
};
CNary.prototype.getUpperIterator = function()
{
	if (!this.Pr.supHide)
		return this.UpperIterator;
};
CNary.prototype.getLowerIterator = function()
{
	if (!this.Pr.subHide)
		return this.LowerIterator;
};
CNary.prototype.getBaseMathContent = function()
{
    return this.Arg;
};
CNary.prototype.getSupMathContent = function()
{
    return this.UpperIterator;
};
CNary.prototype.getSubMathContent = function()
{
    return this.LowerIterator;
};
CNary.prototype.Apply_MenuProps = function(Props)
{
	if (Props.Type == Asc.c_oAscMathInterfaceType.LargeOperator)
	{
		if (Props.LimLoc !== undefined && false == this.ParaMath.Is_Inline() && this.Pr.limLoc !== Props.LimLoc)
		{
			var LimLoc = Props.LimLoc == Asc.c_oAscMathInterfaceNaryLimitLocation.SubSup ? NARY_SubSup : NARY_UndOvr;
			AscCommon.History.Add(new CChangesMathNaryLimLoc(this, this.Pr.limLoc, LimLoc));
			this.raw_SetLimLoc(LimLoc);
		}

		if (Props.HideUpper !== undefined && Props.HideUpper !== this.Pr.supHide)
		{
			AscCommon.History.Add(new CChangesMathNaryUpperLimit(this, this.Pr.supHide, !this.Pr.supHide));
			this.raw_HideUpperIterator(!this.Pr.supHide);
		}

		if (Props.HideLower !== undefined && Props.HideLower !== this.Pr.subHide)
		{
			AscCommon.History.Add(new CChangesMathNaryLowerLimit(this, this.Pr.subHide, !this.Pr.subHide));
			this.raw_HideLowerIterator(!this.Pr.subHide);
		}
	}
};
CNary.prototype.Get_InterfaceProps = function()
{
    return new CMathMenuNary(this);
};
CNary.prototype.raw_SetLimLoc = function(Value)
{
    if(this.Pr.limLoc !== Value)
    {
        this.Pr.limLoc = Value;
        this.RecalcInfo.bProps = true;
    }
};
CNary.prototype.raw_HideUpperIterator = function(Value)
{
    if(this.Pr.supHide !== Value)
    {
        this.Pr.supHide = Value;
        this.RecalcInfo.bProps = true;

        this.CurPos = 2;
        this.Arg.MoveCursorToStartPos();
    }
};
CNary.prototype.raw_HideLowerIterator = function(Value)
{
    if(this.Pr.subHide !== Value)
    {
        this.Pr.subHide = Value;
        this.RecalcInfo.bProps = true;

        this.CurPos = 2;
        this.Arg.MoveCursorToStartPos();
    }
};
CNary.prototype.Is_ContentUse = function(MathContent)
{
    if (MathContent === this.getBaseMathContent())
        return true;

    if (true !== this.Pr.subHide && MathContent === this.getSubMathContent())
        return true;

    if (true !== this.Pr.supHide && MathContent === this.getSupMathContent())
        return true;

    return false;
};
CNary.prototype.Recalculate_Range = function(PRS, ParaPr, Depth)
{
    this.bOneLine = PRS.bMath_OneLine;

    if(this.bOneLine === true)
    {
        CMathBase.prototype.Recalculate_Range.call(this, PRS, ParaPr, Depth);
    }
    else
    {
        var CurLine  = PRS.Line - this.StartLine;
        var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range );

        this.setDistance();

        var bContainCompareOper = PRS.bContainCompareOper;

        var RangeStartPos = this.protected_AddRange(CurLine, CurRange),
            RangeEndPos = 2;


        if(CurLine == 0 && CurRange == 0)
        {
            PRS.WordLen += this.BrGapLeft;
            var WordLen = PRS.WordLen;

            if(this.Base.IsJustDraw())
            {
                this.MeasureJustDraw(this.Base);
            }
            else
            {
                PRS.bMath_OneLine = true;
                this.Base.Recalculate_Reset(PRS.Range, PRS.Line, PRS);
                this.LowerIterator.Recalculate_Reset(PRS.Range, PRS.Line, PRS);
                this.UpperIterator.Recalculate_Reset(PRS.Range, PRS.Line, PRS);
                this.Base.Recalculate_Range(PRS, ParaPr, Depth);
            }

            PRS.WordLen = WordLen + this.Base.size.width;

            if(false === PRS.Word && false === PRS.FirstItemOnLine)
            {
                PRS.Word = true;
            }

            PRS.WordLen += this.dW;

            this.Arg.Recalculate_Reset(PRS.Range, PRS.Line, PRS); // обновим StartLine и StartRange
        }

        PRS.Update_CurPos(2, Depth); // this.Arg = this.Content[2]
        PRS.bMath_OneLine  = false;
        this.Arg.Recalculate_Range(PRS, ParaPr, Depth+1);


        if(PRS.NewRange == false)
        {
            PRS.WordLen += this.BrGapRight;
        }

        this.protected_FillRange(CurLine, CurRange, RangeStartPos, RangeEndPos);

        PRS.bMath_OneLine = false;
        PRS.bContainCompareOper = bContainCompareOper;
    }
};
CNary.prototype.Recalculate_Range_Width = function(PRSC, _CurLine, _CurRange)
{
    if(this.bOneLine == true)
    {
        CMathBase.prototype.Recalculate_Range_Width.call(this, PRSC, _CurLine, _CurRange);
    }
    else
    {
        var CurLine = _CurLine - this.StartLine;
        var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

        var RangeW = PRSC.Range.W;

        if(CurLine == 0 && CurRange == 0)
        {
            PRSC.Range.W += this.BrGapLeft;
            var RangeW2 = PRSC.Range.W;

            if(this.Base.IsJustDraw() == false)
            {
                this.LowerIterator.Recalculate_Range_Width(PRSC, _CurLine, _CurRange);
                this.UpperIterator.Recalculate_Range_Width(PRSC, _CurLine, _CurRange);

                this.Base.Bounds.SetWidth(CurLine, CurRange, this.Base.size.width);
            }

            PRSC.Range.W = RangeW2 + this.Base.size.width + this.dW;

        }

        this.Arg.Recalculate_Range_Width( PRSC, _CurLine, _CurRange );

        if(this.Arg.Math_Is_End( _CurLine, _CurRange))
        {
            PRSC.Range.W += this.BrGapRight;
        }

        this.Bounds.SetWidth(CurLine, CurRange, PRSC.Range.W - RangeW);
    }
};
CNary.prototype.Draw_Elements = function(PDSE)
{
    var CurLine  = PDSE.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PDSE.Range - this.StartRange : PDSE.Range );

    if(CurLine == 0 && CurRange == 0)
    {
        if(this.Base.IsJustDraw()) // для Just-Draw элементов надо выставить Font
        {
            var ctrPrp = this.Get_TxtPrControlLetter();

            var Font =
            {
                FontSize:   ctrPrp.FontSize,
                FontFamily: {Name : ctrPrp.FontFamily.Name, Index : ctrPrp.FontFamily.Index},
                Italic:     false,
                Bold:       false //ctrPrp.Bold
            };

            PDSE.Graphics.SetFont(Font);
        }
        this.Base.Draw_Elements(PDSE);
    }

    this.Arg.Draw_Elements(PDSE);
};
CNary.prototype.UpdateBoundsPosInfo = function(PRSA, _CurLine, _CurRange, _CurPage)
{
    if(this.bOneLine == false)
    {
        var CurLine  = _CurLine - this.StartLine;
        var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange);

        this.Bounds.SetGenPos(CurLine, CurRange, PRSA);
        this.Bounds.SetPage(CurLine, CurRange, _CurPage);

        if(false == this.Base.IsJustDraw())
        {
            this.Base.UpdateBoundsPosInfo(PRSA, _CurLine, _CurRange, _CurPage);
        }

        this.Arg.UpdateBoundsPosInfo(PRSA, _CurLine, _CurRange, _CurPage);

    }
    else
    {
        CMathBase.prototype.UpdateBoundsPosInfo.call(this, PRSA, _CurLine, _CurRange, _CurPage);
    }

};
CNary.prototype.Recalculate_LineMetrics = function(PRS, ParaPr, _CurLine, _CurRange, ContentMetrics)
{
    if(this.bOneLine)
    {
        CMathBase.prototype.Recalculate_LineMetrics.call(this, PRS, ParaPr, _CurLine, _CurRange, ContentMetrics);
    }
    else
    {
        var CurLine = _CurLine - this.StartLine;
        var CurRange = (0 === CurLine ? _CurRange - this.StartRange : _CurRange);

        if(PRS.bFastRecalculate === false)
        {
            this.Bounds.Reset(CurLine, CurRange);
        }

        // т.к. ParaNumbering привязывается к первому текстовому элементы, он может находится в аргументе
        // обновляем LineMetrics для Base после того, как обновим метрики для аргумента

        this.Arg.Recalculate_LineMetrics(PRS, ParaPr, _CurLine, _CurRange, ContentMetrics);

        var BoundArg = this.Arg.Get_LineBound(_CurLine, _CurRange);

        this.Bounds.UpdateMetrics(CurLine, CurRange, BoundArg);
        this.UpdatePRS(PRS, BoundArg);

        if(CurLine == 0 && CurRange == 0)
        {
            //this.Bounds.Reset();

            if(this.Base.IsJustDraw())
            {
                this.Bounds.UpdateMetrics(CurLine, CurRange, this.Base.size);
                ContentMetrics.UpdateMetrics(this.Base.size);
                this.UpdatePRS(PRS, this.Base.size);
            }
            else
            {
                // чтобы при вычислении метрик итераторов не были перебили метрики (например, у внутр мат объекта Asc может быть больше Asc текущего объекта)

                var NewContentMetrics = new CMathBoundsMeasures();

                this.LowerIterator.Recalculate_LineMetrics(PRS, ParaPr, _CurLine, _CurRange, NewContentMetrics);
                this.UpperIterator.Recalculate_LineMetrics(PRS, ParaPr, _CurLine, _CurRange, NewContentMetrics);

                this.Base.Recalculate_LineMetrics(PRS, ParaPr, _CurLine, _CurRange, ContentMetrics);

                this.Bounds.UpdateMetrics(CurLine, CurRange, this.Base.size);
                this.UpdatePRS(PRS, this.Base.size);
            }

        }
    }
};
CNary.prototype.setPosition = function(pos, PosInfo)
{
    if(this.bOneLine)
    {
        CMathBase.prototype.setPosition.call(this, pos, PosInfo);
    }
    else
    {
        var Line  = PosInfo.CurLine,
            Range = PosInfo.CurRange;
        var CurLine  = Line - this.StartLine;
        var CurRange = ( 0 === CurLine ? Range - this.StartRange : Range );

        this.UpdatePosBound(pos, PosInfo);

        if(CurLine == 0 && CurRange == 0)
        {
            pos.x += this.BrGapLeft;

            var PosBase = new CMathPosition();
            PosBase.x = pos.x;
            PosBase.y = pos.y - this.Base.size.ascent;

            this.Base.setPosition(PosBase, PosInfo);

            pos.x += this.Base.size.width + this.dW;
        }

        this.Arg.setPosition(pos, PosInfo);

        if(this.Arg.Math_Is_End(Line, Range))
        {
            pos.x += this.BrGapRight;
        }
    }
};
CNary.prototype.Can_ModifyArgSize = function()
{
    return this.CurPos !== 2 && false === this.Is_SelectInside();
};


/**
 *
 * @param CMathMenuNary
 * @constructor
 * @extends {CMathMenuBase}
 */
function CMathMenuNary(Nary)
{
	CMathMenuBase.call(this, Nary);

    this.Type             = Asc.c_oAscMathInterfaceType.LargeOperator;

    if (undefined !== Nary)
    {
        var HideUpper = undefined, HideLower = undefined;
        if (true === Nary.UpperIterator.IsPlaceholder())
            HideUpper = Nary.Pr.supHide == true;

        if (true === Nary.LowerIterator.IsPlaceholder())
            HideLower = Nary.Pr.subHide == true;

        this.bCanChangeLimLoc = false == Nary.ParaMath.Is_Inline();
        this.LimLoc           = Nary.Pr.limLoc === NARY_SubSup ? Asc.c_oAscMathInterfaceNaryLimitLocation.SubSup : Asc.c_oAscMathInterfaceNaryLimitLocation.UndOvr;
        this.HideUpper        = HideUpper;
        this.HideLower        = HideLower;
    }
    else
    {
        this.LimLoc    			= undefined;
        this.HideUpper 			= undefined;
        this.HideLower 			= undefined;
        this.bCanChangeLimLoc 	= false;
    }
}
CMathMenuNary.prototype = Object.create(CMathMenuBase.prototype);
CMathMenuNary.prototype.constructor = CMathMenuNary;
CMathMenuNary.prototype.can_ChangeLimitLocation = function(){ return this.bCanChangeLimLoc;};
CMathMenuNary.prototype.get_LimitLocation       = function(){return this.LimLoc;};
CMathMenuNary.prototype.put_LimitLocation       = function(LimLoc){this.LimLoc = LimLoc;};
CMathMenuNary.prototype.get_HideUpper           = function(){return this.HideUpper;};
CMathMenuNary.prototype.put_HideUpper           = function(Hide){this.HideUpper = Hide;};
CMathMenuNary.prototype.get_HideLower           = function(){return this.HideLower;};
CMathMenuNary.prototype.put_HideLower           = function(Hide){this.HideLower = Hide;};

window["CMathMenuNary"] = CMathMenuNary;
CMathMenuNary.prototype["can_ChangeLimitLocation"] = CMathMenuNary.prototype.can_ChangeLimitLocation;
CMathMenuNary.prototype["get_LimitLocation"]       = CMathMenuNary.prototype.get_LimitLocation;
CMathMenuNary.prototype["put_LimitLocation"]       = CMathMenuNary.prototype.put_LimitLocation;
CMathMenuNary.prototype["get_HideUpper"]           = CMathMenuNary.prototype.get_HideUpper;
CMathMenuNary.prototype["put_HideUpper"]           = CMathMenuNary.prototype.put_HideUpper;
CMathMenuNary.prototype["get_HideLower"]           = CMathMenuNary.prototype.get_HideLower;
CMathMenuNary.prototype["put_HideLower"]           = CMathMenuNary.prototype.put_HideLower;

/**
 *
 * @param bInside
 * @constructor
 * @extends {CMathBase}
 */
function CNaryUnd(bInside)
{
    CMathBase.call(this, bInside);

    this.setDimension(2, 1);
    //this.init();
}
CNaryUnd.prototype = Object.create(CMathBase.prototype);
CNaryUnd.prototype.constructor = CNaryUnd;
CNaryUnd.prototype.setDistance = function()
{
    var zetta = this.Get_TxtPrControlLetter().FontSize*25.4/96;
    this.dH = zetta*0.25;
};
CNaryUnd.prototype.getAscent = function()
{
    return this.elements[0][0].size.height + this.dH + this.elements[1][0].size.ascent;
};
CNaryUnd.prototype.getUpperIterator = function()
{
    return this.elements[0][0];
};
CNaryUnd.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI)
{
    this.Parent = Parent;
    this.ParaMath = ParaMath;

    this.Set_CompiledCtrPrp(Parent, ParaMath, RPI);

    var ArgSzUnd = ArgSize.Copy();
    ArgSzUnd.Decrease();

    this.elements[1][0].PreRecalc(this, ParaMath, ArgSize,  RPI);

    var bDecreasedComp = RPI.bDecreasedComp;
    RPI.bDecreasedComp = true;

    this.elements[0][0].PreRecalc(this, ParaMath, ArgSzUnd, RPI);

    RPI.bDecreasedComp = bDecreasedComp;
};
CNaryUnd.prototype.setBase = function(base)
{
    this.elements[1][0] = base;
};
CNaryUnd.prototype.setUpperIterator = function(iterator)
{
    this.elements[0][0] = iterator;
};

/**
 *
 * @param bInside
 * @constructor
 * @extends {CMathBase}
 */
function CNaryOvr(bInside)
{
    CMathBase.call(this, bInside);

    this.setDimension(2, 1);
}
CNaryOvr.prototype = Object.create(CMathBase.prototype);
CNaryOvr.prototype.constructor = CNaryOvr;
CNaryOvr.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI)
{
    this.Parent = Parent;
    this.ParaMath = ParaMath;

    this.Set_CompiledCtrPrp(Parent, ParaMath, RPI);

    var ArgSzOvr = ArgSize.Copy();
    ArgSzOvr.Decrease();

    this.elements[0][0].PreRecalc(this, ParaMath, ArgSize,  RPI);

    var bDecreasedComp = RPI.bDecreasedComp;
    RPI.bDecreasedComp = true;

    this.elements[1][0].PreRecalc(this, ParaMath, ArgSzOvr, RPI);

    RPI.bDecreasedComp = bDecreasedComp;
};
CNaryOvr.prototype.recalculateSize = function()
{
    var FontSize = this.Get_TxtPrControlLetter().FontSize;
    var zetta = FontSize*25.4/96;

    var minGapBottom = zetta*0.1,
        DownBaseline = FontSize*0.23;

    var nOper = this.elements[0][0].size,
        iter = this.elements[1][0].size;

    this.dH = DownBaseline > iter.ascent + minGapBottom ? DownBaseline - iter.ascent : minGapBottom;

    var ascent = nOper.ascent;
    var width = nOper.width > iter.width ? nOper.width : iter.width;
    width += this.GapLeft + this.GapRight;

    var height = nOper.height + this.dH + iter.height;

    this.size.height = height;
    this.size.width  = width;
    this.size.ascent = ascent;
};
CNaryOvr.prototype.getLowerIterator = function()
{
    return this.elements[1][0];
};
CNaryOvr.prototype.setBase = function(base)
{
    this.elements[0][0] = base;
};
CNaryOvr.prototype.setLowerIterator = function(iterator)
{
    this.elements[1][0] = iterator;
};

/**
 *
 * @param bInside
 * @constructor
 * @extends {CMathBase}
 */
function CNaryUndOvr(bInside)
{
    this.gapTop = 0;
    this.gapBottom = 0;
    CMathBase.call(this, bInside);

    this.setDimension(3,1);
}
CNaryUndOvr.prototype = Object.create(CMathBase.prototype);
CNaryUndOvr.prototype.constructor = CNaryUndOvr;
CNaryUndOvr.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI)
{
    this.Parent = Parent;
    this.ParaMath = ParaMath;

    this.Set_CompiledCtrPrp(Parent, ParaMath, RPI);

    var ArgSzIter = ArgSize.Copy();
    ArgSzIter.Decrease();

    this.elements[1][0].PreRecalc(this, ParaMath, ArgSize,  RPI);

    var bDecreasedComp = RPI.bDecreasedComp;
    RPI.bDecreasedComp = true;

    this.elements[0][0].PreRecalc(this, ParaMath, ArgSzIter, RPI);

    this.elements[2][0].PreRecalc(this, ParaMath, ArgSzIter, RPI);

    RPI.bDecreasedComp = bDecreasedComp;
};
CNaryUndOvr.prototype.recalculateSize = function()
{
    var FontSize = this.Get_TxtPrControlLetter().FontSize;
    var zetta = FontSize*25.4/96;
    this.gapTop = zetta*0.25;

    var minGapBottom = zetta*0.1,
        DownBaseline = FontSize*0.23;

    var ascLIter = this.elements[2][0].size.ascent;
    this.gapBottom = DownBaseline > ascLIter + minGapBottom ? DownBaseline - ascLIter : minGapBottom;

    var ascent = this.elements[0][0].size.height + this.gapTop + this.elements[1][0].size.ascent;

    var width = 0, height = 0;
    for(var i = 0; i < 3; i++)
    {
        width = width > this.elements[i][0].size.width ? width : this.elements[i][0].size.width;
        height += this.elements[i][0].size.height;
    }

    width += this.GapLeft + this.GapRight;
    height += this.gapTop + this.gapBottom;

    this.size.height = height;
    this.size.width  = width;
    this.size.ascent = ascent;
};
CNaryUndOvr.prototype.setPosition = function(pos, PosInfo)
{
    this.pos.x = pos.x;
    this.pos.y = pos.y;

    var UpIter  = this.elements[0][0],
        Sign    = this.elements[1][0],
        LowIter = this.elements[2][0];

    var PosUpIter = new CMathPosition();

    PosUpIter.x = pos.x + this.GapLeft + this.align(0,0).x;
    PosUpIter.y = pos.y + UpIter.size.ascent;


    var PosSign = new CMathPosition();

    PosSign.x = pos.x + this.GapLeft + this.align(1,0).x;
    PosSign.y = pos.y + UpIter.size.height + this.gapTop;


    var PosLowIter = new CMathPosition();

    PosLowIter.x = pos.x + this.GapLeft + this.align(2,0).x;
    PosLowIter.y = PosSign.y + Sign.size.height + this.gapBottom + LowIter.size.ascent;

    // такой порядок нужен для выравнивания Box по операторам
    LowIter.setPosition(PosLowIter, PosInfo);
    Sign.setPosition(PosSign, PosInfo);
    UpIter.setPosition(PosUpIter, PosInfo);
};
CNaryUndOvr.prototype.setBase = function(base)
{
    this.elements[1][0] = base;
};
CNaryUndOvr.prototype.setUpperIterator = function(iterator)
{
    this.elements[0][0] = iterator;
};
CNaryUndOvr.prototype.setLowerIterator = function(iterator)
{
    this.elements[2][0] = iterator;
};
CNaryUndOvr.prototype.getLowerIterator = function()
{
    return this.elements[2][0];
};
CNaryUndOvr.prototype.getUpperIterator = function()
{
    return this.elements[0][0];
};


function CNaryOperator(flip)
{
    this.size = new CMathSize();
    this.pos = new CMathPosition();
    this.bFlip = (flip == -1);
    this.Parent   = null;
    this.ParaMath = null;
    this.sizeGlyph = null;
}
CNaryOperator.prototype.Draw_Elements = function(PDSE)
{
    this.Parent.Make_ShdColor(PDSE, this.Parent.Get_CompiledCtrPrp());

    var PosLine = this.ParaMath.GetLinePosition(PDSE.Line, PDSE.Range);

    if(this.Type == para_Math_Text)
        this.drawTextElem(PosLine.x, PosLine.y, PDSE.Graphics);
    else
        this.drawGlyph(PosLine.x, PosLine.y, PDSE.Graphics, PDSE);
};
CNaryOperator.prototype.drawGlyph = function(x, y, pGraphics, PDSE)
{
    var coord = this.getCoord();

    var X = coord.X,
        Y = coord.Y;

    var XX = [],
        YY = [];

    var textScale = this.Get_TxtPrControlLetter().FontSize/850; // 1000 pt
    var alpha = textScale*25.4/96 /64; // коэффициент; используется для того чтобы перевести координаты в миллиметры
    // g_dKoef_px_to_mm = 25.4/96

    var a, b;
    if(this.bFlip)
    {
        a = -1;
        b = this.sizeGlyph.height;
    }
    else
    {
        a = 1;
        b = 0;
    }

    for(var i = 0 ; i < X.length; i++)
    {
        XX[i] = this.pos.x + x + X[i]*alpha;
        YY[i] = this.pos.y + y + (a*Y[i]*alpha + b);
    }

    var intGrid = pGraphics.GetIntegerGrid();
    pGraphics.SetIntegerGrid(false);

    pGraphics.p_width(0);

    pGraphics._s();

    this.drawPath(pGraphics, XX,YY);

    pGraphics.df();
    pGraphics._s();
    pGraphics.SetIntegerGrid(intGrid);
};
CNaryOperator.prototype.drawTextElem = function(x, y, pGraphics)
{
    //pGraphics.b_color1(0,0,0,255);

    var ctrPrp = this.Get_TxtPrControlLetter();

    var Font =
    {
        FontSize:   ctrPrp.FontSize,
        FontFamily: {Name : ctrPrp.FontFamily.Name, Index : ctrPrp.FontFamily.Index},
        Italic:     false,
        Bold:       false //ctrPrp.Bold
    };

    pGraphics.SetFont(Font);

    // ?????????????????????????????????????????????????????????
    // CNaryOperator.superclass.call.draw(this, x, y, pGraphics);
};
CNaryOperator.prototype.IsJustDraw = function()
{
    return true;
};
CNaryOperator.prototype.setPosition = function(pos)
{
    this.pos.x = pos.x;
    this.pos.y = pos.y;
};
CNaryOperator.prototype.recalculateSize = function()
{
    this.sizeGlyph = this.calculateSizeGlyph();

    var height = this.sizeGlyph.height,
        width =  this.sizeGlyph.width,
        ascent = this.sizeGlyph.height/2 + DIV_CENT*this.Get_TxtPrControlLetter().FontSize;

    this.size.height = height;
    this.size.width  = width;
    this.size.ascent = ascent;
};
CNaryOperator.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI)
{
    this.Parent = Parent;
    this.ParaMath = ParaMath;
};
CNaryOperator.prototype.Measure = function(oMeasure, RPI)
{
    this.recalculateSize(); //обычный пересчет, oMeasure не нужен
};
CNaryOperator.prototype.Get_TxtPrControlLetter = function()
{
    return this.Parent.Get_TxtPrControlLetter();
};

/**
 *
 * @constructor
 * @extends {CNaryOperator}
 */
function CSigma()
{
    CNaryOperator.call(this);
}
CSigma.prototype = Object.create(CNaryOperator.prototype);
CSigma.prototype.constructor = CSigma;
CSigma.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._l(XX[2], YY[2]);
    pGraphics._l(XX[3], YY[3]);
    pGraphics._l(XX[4], YY[4]);
    pGraphics._c(XX[4], YY[4], XX[5], YY[5], XX[6], YY[6] );
    pGraphics._c(XX[6], YY[6], XX[7], YY[7], XX[8], YY[8] );
    pGraphics._c(XX[8], YY[8], XX[9], YY[9], XX[10], YY[10] );
    pGraphics._c(XX[10], YY[10], XX[11], YY[11], XX[12], YY[12] );
    pGraphics._c(XX[12], YY[12], XX[13], YY[13], XX[14], YY[14] );
    pGraphics._l(XX[15], YY[15]);
    pGraphics._l(XX[16], YY[16]);
    pGraphics._l(XX[17], YY[17]);
    pGraphics._l(XX[18], YY[18]);
    pGraphics._l(XX[19], YY[19]);
    pGraphics._l(XX[20], YY[20]);
    pGraphics._l(XX[21], YY[21]);
    pGraphics._l(XX[22], YY[22]);
    pGraphics._l(XX[23], YY[23]);
    pGraphics._l(XX[24], YY[24]);
    pGraphics._c(XX[24], YY[24], XX[25], YY[25], XX[26], YY[26] );
    pGraphics._c(XX[26], YY[26], XX[27], YY[27], XX[28], YY[28] );
    pGraphics._c(XX[28], YY[28], XX[29], YY[29], XX[30], YY[30] );
    pGraphics._c(XX[30], YY[30], XX[31], YY[31], XX[32], YY[32] );
    pGraphics._c(XX[32], YY[32], XX[33], YY[33], XX[34], YY[34] );
    pGraphics._l(XX[35], YY[35]);

};
CSigma.prototype.getCoord = function()
{
    var X = [],
        Y = [];

    /*X[0] = 13560; Y[0] = 4332;
     X[1] = 33847; Y[1] = 35130;
     X[2] = 33847; Y[2] = 38297;
     X[3] = 11103; Y[3] = 69548;
     X[4] = 38512; Y[4] = 69548;
     X[5] = 41095; Y[5] = 69548;
     X[6] = 42407; Y[6] = 69215;
     X[7] = 43719; Y[7] = 68882;
     X[8] = 44656; Y[8] = 68194;
     X[9] = 45594; Y[9] = 67507;
     X[10] = 46364; Y[10] = 66278;
     X[11] = 47135; Y[11] = 65049;
     X[12] = 47843; Y[12] = 62883;
     X[13] = 48552; Y[13] = 60717;
     X[14] = 49176; Y[14] = 57218;
     X[15] = 54028; Y[15] = 57218;
     X[16] = 52820; Y[16] = 77546;
     X[17] = 0; Y[17] = 77546;
     X[18] = 0; Y[18] = 75213;
     X[19] = 25766; Y[19] = 39839;
     X[20] = 1605; Y[20] = 2374;
     X[21] = 1605; Y[21] = 0;
     X[22] = 53050; Y[22] = 0;
     X[23] = 53050; Y[23] = 18543;
     X[24] = 48551; Y[24] = 18543;
     X[25] = 47509; Y[25] = 14584;
     X[26] = 46572; Y[26] = 12084;
     X[27] = 45635; Y[27] = 9583;
     X[28] = 44656; Y[28] = 8125;
     X[29] = 43677; Y[29] = 6666;
     X[30] = 42656; Y[30] = 5895;
     X[31] = 41636; Y[31] = 5124;
     X[32] = 40303; Y[32] = 4728;
     X[33] = 38970; Y[33] = 4332;
     X[34] = 36762; Y[34] = 4332;
     X[35] = 13560; Y[35] = 4332;*/

    X[0] = 16252; Y[0] = 5200;
    X[1] = 40602; Y[1] = 42154;
    X[2] = 40602; Y[2] = 45954;
    X[3] = 13302; Y[3] = 83456;
    X[4] = 46202; Y[4] = 83456;
    X[5] = 49302; Y[5] = 83456;
    X[6] = 50877; Y[6] = 83056;
    X[7] = 52452; Y[7] = 82656;
    X[8] = 53577; Y[8] = 81831;
    X[9] = 54702; Y[9] = 81006;
    X[10] = 55627; Y[10] = 79531;
    X[11] = 56552; Y[11] = 78056;
    X[12] = 57402; Y[12] = 75456;
    X[13] = 58252; Y[13] = 72856;
    X[14] = 59002; Y[14] = 68656;
    X[15] = 64850; Y[15] = 68656;
    X[16] = 63400; Y[16] = 93056;
    X[17] = 0; Y[17] = 93056;
    X[18] = 0; Y[18] = 90256;
    X[19] = 30902; Y[19] = 47804;
    X[20] = 1902; Y[20] = 2850;
    X[21] = 1902; Y[21] = 0;
    X[22] = 63652; Y[22] = 0;
    X[23] = 63652; Y[23] = 22252;
    X[24] = 58252; Y[24] = 22252;
    X[25] = 57002; Y[25] = 17501;
    X[26] = 55877; Y[26] = 14501;
    X[27] = 54752; Y[27] = 11501;
    X[28] = 53577; Y[28] = 9751;
    X[29] = 52402; Y[29] = 8000;
    X[30] = 51177; Y[30] = 7075;
    X[31] = 49952; Y[31] = 6150;
    X[32] = 48352; Y[32] = 5675;
    X[33] = 46752; Y[33] = 5200;
    X[34] = 44102; Y[34] = 5200;
    X[35] = 16252; Y[35] = 5200;


    //var textScale =  this.getTxtPrp().FontSize/850; // 1000 pt
    var textScale =  this.Get_TxtPrControlLetter().FontSize/850; // 1000 pt
    var alpha = textScale*25.4/96 /64;

    var h1 = Y[0] - Y[21],
        h2 = Y[17] - Y[3],
        h3 = Y[2] - Y[1],
        h4 = Y[20] - Y[21],
        h5 = Y[17] - Y[18];

    var H1 = this.sizeGlyph.height/alpha - h1 - h2 - h3;
    //H2 = this.size.height/alpha - h4 - h5;

    var h_middle1 = Y[3] - Y[0] - h3,
        coeff1 = (Y[1] - Y[0])/h_middle1,
        coeff2 = (Y[3] - Y[2])/h_middle1;


    var y3 = Y[3],
        y2 = Y[2];

    Y[1] = Y[0] + H1*coeff1;
    Y[2] = Y[1] + h3;
    Y[3] = Y[2] + H1*coeff2;

    Y[19] = Y[2] + Y[19] - y2;
    Y[18] = Y[3] + Y[18] - y3;

    for(var i = 4; i < 18; i++)
    {
        Y[i] = Y[3] + (Y[i] - y3);
    }

    // Width  -  X[15]

    var W = (this.sizeGlyph.width - this.gap)/alpha;

    var c1 = (X[21] - X[17])/X[15],
        c2 = (X[22] - X[21])/X[15];

    var x22 = X[22];

    X[21] = X[20] = X[17] + c1*W;
    X[22] = X[23] = X[21] + c2*W;

    for(var i = 24; i < 35; i++)
        X[i] = X[22] + X[i] - x22;

    var c3 = (X[4] - X[3])/X[15],
        c4 = (X[15] - X[16])/X[15],
        c5 = (X[15] - X[2])/X[15];

    var x15 = X[15],
        x2 = X[2];

    X[4] = X[3] + c3*W;
    X[15] = W;
    X[16] = X[15] - c4*W;

    X[2] = X[1] = X[15] - c5*W;

    X[19] = X[2] - (x2 - X[19]);

    for(var i = 5; i < 15 ; i++)
        X[i] = X[15] - (x15 - X[i]);

    return {X: X, Y: Y};
};
CSigma.prototype.calculateSizeGlyph = function()
{
    // пока размер не меняем в зависимости от высоты аргумента

    //var betta = this.getTxtPrp().FontSize/36;
    var betta = this.Get_TxtPrControlLetter().FontSize/36;

    var _width = 8.997900390624999*betta,
        _height = 11.994444444444444*betta;

    this.gap = 0.93*betta;

    var width = 1.76*_width + this.gap,
        height = 2*_height;

    return {width : width, height : height};
};

/**
 *
 * @param bFlip
 * @constructor
 * @extends {CNaryOperator}
 */
function CProduct(bFlip)
{
    CNaryOperator.call(this, bFlip);
}
CProduct.prototype = Object.create(CNaryOperator.prototype);
CProduct.prototype.constructor = CProduct;
CProduct.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._c(XX[1], YY[1], XX[2], YY[2], XX[3], YY[3] );
    pGraphics._c(XX[3], YY[3], XX[4], YY[4], XX[5], YY[5] );
    pGraphics._c(XX[5], YY[5], XX[6], YY[6], XX[7], YY[7] );
    pGraphics._c(XX[7], YY[7], XX[8], YY[8], XX[9], YY[9] );
    pGraphics._l(XX[10], YY[10]);
    pGraphics._c(XX[10], YY[10], XX[11], YY[11], XX[12], YY[12] );
    pGraphics._c(XX[12], YY[12], XX[13], YY[13], XX[14], YY[14] );
    pGraphics._c(XX[14], YY[14], XX[15], YY[15], XX[16], YY[16] );
    pGraphics._c(XX[16], YY[16], XX[17], YY[17], XX[18], YY[18] );
    pGraphics._l(XX[19], YY[19]);
    pGraphics._l(XX[20], YY[20]);
    pGraphics._l(XX[21], YY[21]);
    pGraphics._c(XX[21], YY[21], XX[22], YY[22], XX[23], YY[23] );
    pGraphics._c(XX[23], YY[23], XX[24], YY[24], XX[25], YY[25] );
    pGraphics._c(XX[25], YY[25], XX[26], YY[26], XX[27], YY[27] );
    pGraphics._c(XX[27], YY[27], XX[28], YY[28], XX[29], YY[29] );
    pGraphics._l(XX[30], YY[30]);
    pGraphics._l(XX[31], YY[31]);
    pGraphics._l(XX[32], YY[32]);
    pGraphics._c(XX[32], YY[32], XX[33], YY[33], XX[34], YY[34] );
    pGraphics._c(XX[34], YY[34], XX[35], YY[35], XX[36], YY[36] );
    pGraphics._c(XX[36], YY[36], XX[37], YY[37], XX[38], YY[38] );
    pGraphics._c(XX[38], YY[38], XX[39], YY[39], XX[40], YY[40] );
    pGraphics._l(XX[41], YY[41]);
    pGraphics._l(XX[42], YY[42]);
    pGraphics._l(XX[43], YY[43]);
    pGraphics._c(XX[43], YY[43], XX[44], YY[44], XX[45], YY[45] );
    pGraphics._c(XX[45], YY[45], XX[46], YY[46], XX[47], YY[47] );
    pGraphics._c(XX[47], YY[47], XX[48], YY[48], XX[49], YY[49] );
    pGraphics._c(XX[49], YY[49], XX[50], YY[50], XX[51], YY[51] );
    pGraphics._l(XX[52], YY[52]);
    pGraphics._c(XX[52], YY[52], XX[53], YY[53], XX[54], YY[54] );
    pGraphics._c(XX[54], YY[54], XX[55], YY[55], XX[56], YY[56] );
    pGraphics._c(XX[56], YY[56], XX[57], YY[57], XX[58], YY[58] );
    pGraphics._c(XX[58], YY[58], XX[59], YY[59], XX[60], YY[60] );
    pGraphics._l(XX[61], YY[61]);
    pGraphics._l(XX[62], YY[62]);

};
CProduct.prototype.getCoord = function()
{
    var X = [],
        Y = [];

    X[0] = 67894; Y[0] = 0;
    X[1] = 67894; Y[1] = 2245;
    X[2] = 65100; Y[2] = 3024;
    X[3] = 63955; Y[3] = 3666;
    X[4] = 62810; Y[4] = 4307;
    X[5] = 62100; Y[5] = 5338;
    X[6] = 61390; Y[6] = 6368;
    X[7] = 61092; Y[7] = 8338;
    X[8] = 60794; Y[8] = 10308;
    X[9] = 60794; Y[9] = 14706;
    X[10] = 60794; Y[10] = 70551;
    X[11] = 60794; Y[11] = 74674;
    X[12] = 61069; Y[12] = 76666;
    X[13] = 61345; Y[13] = 78659;
    X[14] = 61987; Y[14] = 79736;
    X[15] = 62629; Y[15] = 80813;
    X[16] = 63798; Y[16] = 81523;
    X[17] = 64968; Y[17] = 82233;
    X[18] = 67904; Y[18] = 83012;
    X[19] = 67904; Y[19] = 85257;
    X[20] = 43623; Y[20] = 85257;
    X[21] = 43623; Y[21] = 83012;
    X[22] = 46368; Y[22] = 82279;
    X[23] = 47512; Y[23] = 81614;
    X[24] = 48657; Y[24] = 80950;
    X[25] = 49343; Y[25] = 79896;
    X[26] = 50029; Y[26] = 78843;
    X[27] = 50326; Y[27] = 76850;
    X[28] = 50624; Y[28] = 74857;
    X[29] = 50624; Y[29] = 70551;
    X[30] = 50624; Y[30] = 4856;
    X[31] = 17165; Y[31] = 4856;
    X[32] = 17165; Y[32] = 70551;
    X[33] = 17165; Y[33] = 74994;
    X[34] = 17463; Y[34] = 76918;
    X[35] = 17761; Y[35] = 78843;
    X[36] = 18450; Y[36] = 79873;
    X[37] = 19139; Y[37] = 80904;
    X[38] = 20332; Y[38] = 81591;
    X[39] = 21526; Y[39] = 82279;
    X[40] = 24326; Y[40] = 83012;
    X[41] = 24326; Y[41] = 85257;
    X[42] = 0; Y[42] = 85257;
    X[43] = 0; Y[43] = 83012;
    X[44] = 2743; Y[44] = 82279;
    X[45] = 3931; Y[45] = 81614;
    X[46] = 5120; Y[46] = 80950;
    X[47] = 5783; Y[47] = 79873;
    X[48] = 6446; Y[48] = 78797;
    X[49] = 6743; Y[49] = 76827;
    X[50] = 7040; Y[50] = 74857;
    X[51] = 7040; Y[51] = 70551;
    X[52] = 7040; Y[52] = 14706;
    X[53] = 7040; Y[53] = 10400;
    X[54] = 6743; Y[54] = 8430;
    X[55] = 6446; Y[55] = 6460;
    X[56] = 5806; Y[56] = 5429;
    X[57] = 5166; Y[57] = 4398;
    X[58] = 4000; Y[58] = 3711;
    X[59] = 2834; Y[59] = 3024;
    X[60] = 0; Y[60] = 2245;
    X[61] = 0; Y[61] = 0;
    X[62] = 67894; Y[62] = 0;


    //var textScale = this.getTxtPrp().FontSize/850, // 1000 pt
    var textScale = this.Get_TxtPrControlLetter().FontSize/850, // 1000 pt
        alpha = textScale*25.4/96 /64;

    var h1 = Y[9],
        h2 = Y[19] - Y[10],
        w1 = X[31];

    var Height = this.sizeGlyph.height/alpha - h1 - h2,
        Width = (this.sizeGlyph.width - this.gap)/alpha - 2*w1;

    var hh = Height - (Y[10] - Y[9]),
        ww = Width - (X[30] - X[31]);

    for(var i = 0; i < 20; i++)
    {
        Y[10 + i] += hh;
        Y[32 + i] += hh;
    }

    for(var i = 0; i < 31; i++)
        X[i] += ww;

    X[62] += ww;


    return {X: X, Y: Y};

};
CProduct.prototype.calculateSizeGlyph = function()
{
    //var betta = this.getTxtPrp().FontSize/36;
    var betta = this.Get_TxtPrControlLetter().FontSize/36;

    var _width = 10.312548828125*betta,
        _height = 11.994444444444444*betta;

    this.gap = 0.93*betta;

    var width = 1.76*_width + this.gap,
        height = 2*_height;

    //this.size = {width : width, height : height, center: height/2 };

    return {width : width, height : height};
};

/**
 *
 * @param bFlip
 * @constructor
 * @extends {CNaryOperator}
 */
function CUnion(bFlip)
{
    CNaryOperator.call(this, bFlip);
}
CUnion.prototype = Object.create(CNaryOperator.prototype);
CUnion.prototype.constructor = CUnion;
CUnion.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._c(XX[0], YY[0], XX[1], YY[1], XX[2], YY[2]);
    pGraphics._c(XX[2], YY[2], XX[3], YY[3], XX[4], YY[4]);
    pGraphics._l(XX[5], YY[5]);
    pGraphics._l(XX[6], YY[6]);
    pGraphics._l(XX[7], YY[7]);
    pGraphics._c(XX[7], YY[7], XX[8], YY[8], XX[9], YY[9]);
    pGraphics._c(XX[9], YY[9], XX[10], YY[10], XX[11], YY[11]);
    pGraphics._c(XX[11], YY[11], XX[12], YY[12], XX[13], YY[13]);
    pGraphics._c(XX[13], YY[13], XX[14], YY[14], XX[15], YY[15]);
    pGraphics._l(XX[16], YY[16]);
    pGraphics._l(XX[17], YY[17]);
    pGraphics._l(XX[18], YY[18]);
    pGraphics._c(XX[18], YY[18], XX[19], YY[19], XX[20], YY[20]);
    pGraphics._c(XX[20], YY[20], XX[21], YY[21], XX[22], YY[22]);
};
CUnion.prototype.getCoord = function()
{
    var X = [],
        Y = [];

    X[0] = 49526.184566929136; Y[0] = 127087.84;
    X[1] = 33974.37429971653; Y[1] = 127877.20000000001;
    X[2] = 25226.481024409448; Y[2] = 120034.20000000001;
    X[3] = 15996.016171708661; Y[3] = 113190.09;
    X[4] = 15301.25; Y[4] = 95025.84;
    X[5] = 15301.25; Y[5] = 0;
    X[6] = 7100; Y[6] = 0;
    X[7] = 7100; Y[7] = 94775.84;
    X[8] = 7100; Y[8] = 117815.09;
    X[9] = 21524.90275275591; Y[9] = 127165.84;
    X[10] = 31605.36420585827; Y[10] = 135801.88;
    X[11] = 49526.184566929136; Y[11] = 135775.84;
    X[12] = 67447.00492800001; Y[12] = 135801.88;
    X[13] = 77527.46638110236; Y[13] = 127165.84;
    X[14] = 91952.36913385827; Y[14] = 117815.09;
    X[15] = 91952.36913385827; Y[15] = 94775.84;
    X[16] = 91952.36913385827; Y[16] = 0;
    X[17] = 83751.11913385827; Y[17] = 0;
    X[18] = 83751.11913385827; Y[18] = 95025.84;
    X[19] = 83056.35296214961; Y[19] = 113190.09;
    X[20] = 73825.88810944883; Y[20] = 120034.20000000001;
    X[21] = 65077.99483414174; Y[21] = 127877.20000000001;
    X[22] = 49526.184566929136; Y[22] = 127087.84;

    return {X: X, Y: Y};
};
CUnion.prototype.calculateSizeGlyph = function()
{
    //var betta = this.getTxtPrp().FontSize/36;
    var betta = this.Get_TxtPrControlLetter().FontSize/36;
    this.gap = 0.93*betta;

    var _width = 9.38*betta,
        _height = 11.994444444444444*betta;

    var width = 1.76*_width + this.gap,
        height = 2*_height;

    return {width : width, height : height};
};

/**
 *
 * @param bFlip
 * @constructor
 * @extends {CNaryOperator}
 */
function CLogicalOr(bFlip)
{
    CNaryOperator.call(this, bFlip);
}
CLogicalOr.prototype = Object.create(CNaryOperator.prototype);
CLogicalOr.prototype.constructor = CLogicalOr;
CLogicalOr.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._l(XX[2], YY[2]);
    pGraphics._l(XX[3], YY[3]);
    pGraphics._l(XX[4], YY[4]);
    pGraphics._l(XX[5], YY[5]);
    pGraphics._l(XX[6], YY[6]);
    pGraphics._l(XX[7], YY[7]);

};
CLogicalOr.prototype.getCoord = function()
{
    var X = [],
        Y = [];

    X[0] = 0; Y[0] = 0;
    X[1] = 34812; Y[1] = 89801;
    X[2] = 43792; Y[2] = 89801;
    X[3] = 73240; Y[3] = 0;
    X[4] = 63269; Y[4] = 0;
    X[5] = 38719; Y[5] = 77322;
    X[6] = 10613; Y[6] = 0;
    X[7] = 0; Y[7] = 0;

    //var textScale = this.getTxtPrp().FontSize/850, // 1000 pt
    var textScale = this.Get_TxtPrControlLetter().FontSize/850, // 1000 pt
        alpha = textScale*25.4/96 /64;

    var w1 = X[1],
        w2 = X[2] - X[1],
        w4 = X[5] - X[1],
        w5 = X[3] - X[4];

    var Height = this.sizeGlyph.height/alpha,
        Width = (this.sizeGlyph.width - this.gap)/alpha - w2;

    var _W = X[3] - w2,
        k1 = w1/_W;

    X[1] = k1*Width;
    X[2] = X[1] + w2;
    X[5] = X[1] + w4;

    X[3] = Width + w2;
    X[4] = Width + w2 - w5;

    var hh = Height - Y[2];

    Y[1] += hh;
    Y[2] += hh;
    Y[5] += hh;

    return {X: X, Y: Y};
};
CLogicalOr.prototype.calculateSizeGlyph = function()
{
    //var betta = this.getTxtPrp().FontSize/36;
    var betta = this.Get_TxtPrControlLetter().FontSize/36;

    var _width = 9.6159*betta,
        _height = 11.994444444444444*betta;

    this.gap = 0.55*betta;

    var width = 1.76*_width + this.gap,
        height = 2*_height;

    return {width : width, height : height};
};

/**
 *
 * @constructor
 * @extends {CNaryOperator}
 */
function CIntegral()
{
    CNaryOperator.call(this);
}
CIntegral.prototype = Object.create(CNaryOperator.prototype);
CIntegral.prototype.constructor = CIntegral;
CIntegral.prototype.getCoord = function()
{
    var X = [],
        Y = [];

    //top
    X[0] = 20407; Y[0] = 65723;
    X[1] = 20407; Y[1] = 60840;
    X[2] = 20407; Y[2] = 37013;
    X[3] = 24333; Y[3] = 18507;
    X[4] = 28260; Y[4] = 0;
    X[5] = 40590; Y[5] = 0;
    X[6] = 42142; Y[6] = 0;
    X[7] = 43604; Y[7] = 383;
    X[8] = 45067; Y[8] = 765;
    X[9] = 46215; Y[9] = 1305;
    X[10] = 45180; Y[10] = 9225;
    X[11] = 41760; Y[11] = 9225;
    X[12] = 41512; Y[12] = 7335;
    X[13] = 40724; Y[13] = 6064;
    X[14] = 39937; Y[14] = 4793;
    X[15] = 37935; Y[15] = 4793;
    X[16] = 30465; Y[16] = 4793;
    X[17] = 28406; Y[17] = 23086;
    X[18] = 26347; Y[18] = 41378;
    X[19] = 26347; Y[19] = 60840;
    X[20] = 26347; Y[20] = 65723;

    //botton
    X[22] = 26347; Y[22] = 0;
    X[23] = 26347; Y[23] = 4883;
    X[24] = 26325; Y[24] = 33368;
    X[25] = 21622; Y[25] = 49681;
    X[26] = 16920; Y[26] = 65993;
    X[27] = 5467; Y[27] = 65993;
    X[28] = 4387; Y[28] = 65993;
    X[29] = 2947; Y[29] = 65633;
    X[30] = 1507; Y[30] = 65273;
    X[31] = 0; Y[31] = 64553;
    X[32] = 1147; Y[32] = 55665;
    X[33] = 4770; Y[33] = 55665;
    X[34] = 4927; Y[34] = 58050;
    X[35] = 5782; Y[35] = 59412;
    X[36] = 6637; Y[36] = 60773;
    X[37] = 8775; Y[37] = 60773;
    X[38] = 13365; Y[38] = 60773;
    X[39] = 16886; Y[39] = 50783;
    X[40] = 20407; Y[40] = 40793;
    X[41] = 20407; Y[41] = 4883;
    X[42] = 20407; Y[42] = 0;


    var shX = X[9]*0.025;
    for(var i = 0; i < 21; i++)
    {
        X[i] +=shX;
    }

    var shY = Y[26]*0.3377;
    for(var i = 0; i < 21; i++)
    {
        Y[22+i] += shY + Y[20];
    }


    X[21] = (X[20] + X[22])/2; Y[21] = (Y[20] + Y[22])/2;
    X[44] = X[0]; Y[44] = Y[0];
    X[43] = (X[42] + X[44])/2; Y[43] = (Y[44] + Y[42])/2;

    var W = X[9],
        H = Y[27];

    return {X: X, Y: Y, W : W, H: H};
};
CIntegral.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._c(XX[1], YY[1], XX[2], YY[2], XX[3], YY[3] );
    pGraphics._c(XX[3], YY[3], XX[4], YY[4], XX[5], YY[5] );
    pGraphics._c(XX[5], YY[5], XX[6], YY[6], XX[7], YY[7] );
    pGraphics._c(XX[7], YY[7], XX[8], YY[8], XX[9], YY[9] );
    pGraphics._l(XX[10], YY[10]);
    pGraphics._l(XX[11], YY[11]);
    pGraphics._c(XX[11], YY[11], XX[12], YY[12], XX[13], YY[13] );
    pGraphics._c(XX[13], YY[13], XX[14], YY[14], XX[15], YY[15] );
    pGraphics._c(XX[15], YY[15], XX[16], YY[16], XX[17], YY[17] );
    pGraphics._c(XX[17], YY[17], XX[18], YY[18], XX[19], YY[19] );
    pGraphics._l(XX[20], YY[20]);

    pGraphics._c(XX[20], YY[20], XX[21], YY[21], XX[22], YY[22] );

    pGraphics._l(XX[22], YY[22]);
    pGraphics._l(XX[23], YY[23]);
    pGraphics._c(XX[23], YY[23], XX[24], YY[24], XX[25], YY[25] );
    pGraphics._c(XX[25], YY[25], XX[26], YY[26], XX[27], YY[27] );
    pGraphics._c(XX[27], YY[27], XX[28], YY[28], XX[29], YY[29] );
    pGraphics._c(XX[29], YY[29], XX[30], YY[30], XX[31], YY[31] );
    pGraphics._l(XX[32], YY[32]);
    pGraphics._l(XX[33], YY[33]);
    pGraphics._c(XX[33], YY[33], XX[34], YY[34], XX[35], YY[35] );
    pGraphics._c(XX[35], YY[35], XX[36], YY[36], XX[37], YY[37] );
    pGraphics._c(XX[37], YY[37], XX[38], YY[38], XX[39], YY[39] );
    pGraphics._c(XX[39], YY[39], XX[40], YY[40], XX[41], YY[41] );
    pGraphics._l(XX[42], YY[42]);

    pGraphics._c(XX[42], YY[42], XX[43], YY[43], XX[44], YY[44] );

};
CIntegral.prototype.calculateSizeGlyph = function()
{
    //var betta = this.getTxtPrp().FontSize/36;
    var betta = this.Get_TxtPrControlLetter().FontSize/36;

    var _width =  8.624*betta,
        _height = 13.7*betta;

    this.gap = 0.93*betta;

    var width = _width + this.gap,
        height = 2*_height;

    return {width : width, height : height};
};

/**
 *
 * @constructor
 * @extends {CIntegral}
 */
function CDoubleIntegral()
{
    CIntegral.call(this);
}
CDoubleIntegral.prototype = Object.create(CIntegral.prototype);
CDoubleIntegral.prototype.constructor = CDoubleIntegral;
CDoubleIntegral.prototype.drawPath = function(pGraphics, XX, YY, Width)
{
    var XX2 = [],
        YY2 = [];

    // Width прийдрийдет для TextArt, смещение второго интеграла и для обводки, и для заливки должно быть одинаковым, чтобы корректно отрисовалась обводка
    var w = Width == undefined ? (XX[9] - XX[29])*0.6 : Width*0.36;

    for(var i = 0; i < XX.length; i++)
    {
        XX2[i] = XX[i] + w;
        YY2[i] = YY[i];
    }

	CIntegral.prototype.drawPath.call(this, pGraphics, XX, YY);
    pGraphics.df();

    pGraphics._s();
	CIntegral.prototype.drawPath.call(this, pGraphics, XX2, YY2);
};
CDoubleIntegral.prototype.calculateSizeGlyph = function()
{
    //var betta = this.getTxtPrp().FontSize/36;
    var betta = this.Get_TxtPrControlLetter().FontSize/36;

    var _width = 14.2296*betta,
        _height = 13.7*betta;

    this.gap = 0.93*betta;

    var width = _width + this.gap,
        height = 2*_height;

    return {width : width, height : height};
};

/**
 *
 * @constructor
 * @extends {CIntegral}
 */
function CTripleIntegral()
{
    CIntegral.call(this);
}
CTripleIntegral.prototype = Object.create(CIntegral.prototype);
CTripleIntegral.prototype.constructor = CTripleIntegral;
CTripleIntegral.prototype.drawPath = function(pGraphics, XX, YY, Width)
{
    var XX2 = [],
        YY2 = [];

    // Width прийдрийдет для TextArt, смещения второго и третьего интегралов и для обводки, и для заливки должны быть одинаковыми, чтобы корректно отрисовалась обводка
    var w = Width == undefined ? (XX[9] - XX[29])*0.6 : Width*0.26;

    var XX3 = [],
        YY3 = [];

    for(var i = 0; i < XX.length; i++)
    {
        XX2[i] = XX[i] + w;
        YY2[i] = YY[i];

        XX3[i] = XX[i] + 2*w;
        YY3[i] = YY[i];
    }

	CIntegral.prototype.drawPath.call(this, pGraphics, XX, YY);
    pGraphics.df();

    pGraphics._s();
	CIntegral.prototype.drawPath.call(this, pGraphics, XX2, YY2);
    pGraphics.df();

    pGraphics._s();
	CIntegral.prototype.drawPath.call(this, pGraphics, XX3, YY3);
};
CTripleIntegral.prototype.calculateSizeGlyph = function()
{
    //var betta = this.getTxtPrp().FontSize/36;
    var betta = this.Get_TxtPrControlLetter().FontSize/36;

    var _width = 18.925368*betta,
        _height = 13.7*betta;

    this.gap = 0.93*betta;

    var width = _width + this.gap,
        height = 2*_height;

    return {width : width, height : height};
};


function CCircle()
{

}
CCircle.prototype.getCoord = function()
{
    var X = [],
        Y = [];

    X[0] = 18345.98; Y[0] = 0;
    X[1] = 25288.35; Y[1] = 1008.1;
    X[2] = 27622.45; Y[2] = 2601.85;
    X[3] = 29991.4; Y[3] = 4194.75;
    X[4] = 31723.7; Y[4] = 6460.85;
    X[5] = 33456.85; Y[5] = 8726.95;
    X[6] = 34411.4; Y[6] = 11542.15;
    X[7] = 35366.8; Y[7] = 14357.35;
    X[8] = 35366.8; Y[8] = 17472.6;
    X[9] = 35366.8; Y[9] = 21155.65;
    X[10] = 34180.2; Y[10] = 24201.2;
    X[11] = 32994.45; Y[11] = 27245.9;
    X[12] = 30905.15; Y[12] = 29495;
    X[13] = 28816.7; Y[13] = 31743.25;
    X[14] = 25949.65; Y[14] = 33159.35;
    X[15] = 23294.25; Y[15] = 34469.2;
    X[16] = 17035.7; Y[16] = 34770.53;
    X[17] = 17035.7; Y[17] = 34770.53;
    X[18] = 10029.15; Y[18] = 33832.55;
    X[19] = 7655.1; Y[19] = 32203.1;
    X[20] = 5209.65; Y[20] = 30539.65;
    X[21] = 3525.8; Y[21] = 28309.25;
    X[22] = 1842.8; Y[22] = 26078;
    X[23] = 921.4; Y[23] = 23334.2;
    X[24] = 0; Y[24] = 20589.55;
    X[25] = 0; Y[25] = 17509.15;
    X[26] = 0; Y[26] = 14003.75;
    X[27] = 1133.05; Y[27] = 10959.05;
    X[28] = 2266.1; Y[28] = 7913.5;
    X[29] = 4318.85; Y[29] = 5576.85;
    X[30] = 6372.45; Y[30] = 3240.2;
    X[31] = 9275.2; Y[31] = 1752.7;
    X[32] = 11930.6; Y[32] = 407.15;
    X[33] = 18345.98; Y[33] = 0;

    var W = X[7],
        H = Y[16];

    return {X: X, Y: Y, W: W, H: H};

};
CCircle.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._c(XX[0], YY[0], XX[1], YY[1], XX[2], YY[2]);
    pGraphics._c(XX[2], YY[2], XX[3], YY[3], XX[4], YY[4]);
    pGraphics._c(XX[4], YY[4], XX[5], YY[5], XX[6], YY[6]);
    pGraphics._c(XX[6], YY[6], XX[7], YY[7], XX[8], YY[8]);
    pGraphics._c(XX[8], YY[8], XX[9], YY[9], XX[10], YY[10]);
    pGraphics._c(XX[10], YY[10], XX[11], YY[11], XX[12], YY[12]);
    pGraphics._c(XX[12], YY[12], XX[13], YY[13], XX[14], YY[14]);
    pGraphics._c(XX[14], YY[14], XX[15], YY[15], XX[16], YY[16]);

    pGraphics._c(XX[17], YY[17], XX[18], YY[18], XX[19], YY[19]);
    pGraphics._c(XX[19], YY[19], XX[20], YY[20], XX[21], YY[21]);
    pGraphics._c(XX[21], YY[21], XX[22], YY[22], XX[23], YY[23]);
    pGraphics._c(XX[23], YY[23], XX[24], YY[24], XX[25], YY[25]);
    pGraphics._c(XX[25], YY[25], XX[26], YY[26], XX[27], YY[27]);
    pGraphics._c(XX[27], YY[27], XX[28], YY[28], XX[29], YY[29]);
    pGraphics._c(XX[29], YY[29], XX[30], YY[30], XX[31], YY[31]);
    pGraphics._c(XX[31], YY[31], XX[32], YY[32], XX[33], YY[33]);
};


function CSurface()
{

}
CSurface.prototype.getCoord = function()
{
    var X = [],
        Y = [];

    X[0] = 24855.55; Y[0] = 312.82;
    X[1] = 27995.71; Y[1] = 0;
    X[2] = 31359.09; Y[2] = 0;
    X[3] = 36162.79; Y[3] = 0;
    X[4] = 40559.9; Y[4] = 694.89;
    X[5] = 43954.72; Y[5] = 1285.5;
    X[6] = 47349.55; Y[6] = 1876.11;
    X[7] = 50600.44; Y[7] = 2814.59;
    X[8] = 54054.17; Y[8] = 4639.82;
    X[9] = 57507.91; Y[9] = 6464.21;
    X[10] = 59945.63; Y[10] = 10061.28;
    X[11] = 62383.35; Y[11] = 13658.35;
    X[12] = 62383.35; Y[12] = 18871.27;
    X[13] = 62383.35; Y[13] = 24154.26;
    X[14] = 59945.63; Y[14] = 27752.16;
    X[15] = 57507.91; Y[15] = 31349.23;
    X[16] = 53481.95; Y[16] = 33468.93;
    X[17] = 49936.09; Y[17] = 35345.88;
    X[18] = 45688.68; Y[18] = 36318.56;
    X[19] = 42330.61; Y[19] = 36884.98;
    X[20] = 38972.54; Y[20] = 37451.41;
    X[21] = 34242.37; Y[21] = 37799.27;
    X[22] = 31359.98; Y[22] = 37799.27;
    X[23] = 27369.45; Y[23] = 37799.27;
    X[24] = 22565.76; Y[24] = 37347.13;
    X[25] = 19337.9; Y[25] = 36774.04;
    X[26] = 16110.04; Y[26] = 36200.94;
    X[27] = 11723.56; Y[27] = 35018.88;
    X[28] = 9068.82; Y[28] = 33663.3;
    X[29] = 6377.76; Y[29] = 32273.53;
    X[30] = 4312.96; Y[30] = 30188.03;
    X[31] = 2249.05; Y[31] = 28101.69;
    X[32] = 1124.08; Y[32] = 25286.27;
    X[33] = 0; Y[33] = 22470.84;
    X[34] = 0; Y[34] = 18959.69;
    X[35] = 0; Y[35] = 13745.94;
    X[36] = 2490.87; Y[36] = 10130.52;
    X[37] = 4982.63; Y[37] = 6515.1;
    X[38] = 8967.84; Y[38] = 4394.56;
    X[39] = 12806.01; Y[39] = 2378.3;
    X[40] = 17529.98; Y[40] = 1370.59;
    X[41] = 21192.77; Y[41] = 841.7;
    X[42] = 24855.55; Y[42] = 312.82;

    var W = X[11],
        H = Y[21];



    return {X: X, Y: Y, W: W, H: H};
};
CSurface.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[0], YY[0]);
    pGraphics._c(XX[0], YY[0], XX[1], YY[1], XX[2], YY[2] );
    pGraphics._c(XX[2], YY[2], XX[3], YY[3], XX[4], YY[4] );
    pGraphics._c(XX[4], YY[4], XX[5], YY[5], XX[6], YY[6] );
    pGraphics._c(XX[6], YY[6], XX[7], YY[7], XX[8], YY[8] );
    pGraphics._c(XX[8], YY[8], XX[9], YY[9], XX[10], YY[10] );
    pGraphics._c(XX[10], YY[10], XX[11], YY[11], XX[12], YY[12] );
    pGraphics._c(XX[12], YY[12], XX[13], YY[13], XX[14], YY[14] );
    pGraphics._c(XX[14], YY[14], XX[15], YY[15], XX[16], YY[16] );
    pGraphics._c(XX[16], YY[16], XX[17], YY[17], XX[18], YY[18] );
    pGraphics._c(XX[18], YY[18], XX[19], YY[19], XX[20], YY[20] );
    pGraphics._c(XX[20], YY[20], XX[21], YY[21], XX[22], YY[22] );
    pGraphics._c(XX[22], YY[22], XX[23], YY[23], XX[24], YY[24] );
    pGraphics._c(XX[24], YY[24], XX[25], YY[25], XX[26], YY[26] );
    pGraphics._c(XX[26], YY[26], XX[27], YY[27], XX[28], YY[28] );
    pGraphics._c(XX[28], YY[28], XX[29], YY[29], XX[30], YY[30] );
    pGraphics._c(XX[30], YY[30], XX[31], YY[31], XX[32], YY[32] );
    pGraphics._c(XX[32], YY[32], XX[33], YY[33], XX[34], YY[34] );
    pGraphics._c(XX[34], YY[34], XX[35], YY[35], XX[36], YY[36] );
    pGraphics._c(XX[36], YY[36], XX[37], YY[37], XX[38], YY[38] );
    pGraphics._c(XX[38], YY[38], XX[39], YY[39], XX[40], YY[40] );
    pGraphics._c(XX[40], YY[40], XX[41], YY[41], XX[42], YY[42] );
};

function CVolume()
{

}
CVolume.prototype.getCoord = function()
{
    var X = [],
        Y = [];

    X[0] = 24086.6; Y[0] = 1584.99;
    X[1] = 25878.03; Y[1] = 1268.19;
    X[2] = 30642.29; Y[2] = 669.24;
    X[3] = 35139.13; Y[3] = 104.94;
    X[4] = 43028.74; Y[4] = 0;
    X[5] = 46945.61; Y[5] = 59.9;
    X[6] = 50862.49; Y[6] = 119.79;
    X[7] = 57135.73; Y[7] = 330.66;
    X[8] = 61811.92; Y[8] = 923.67;
    X[9] = 65955.41; Y[9] = 1411.74;
    X[10] = 68883.14; Y[10] = 2040.39;
    X[11] = 72891.84; Y[11] = 3159.09;
    X[12] = 76900.55; Y[12] = 4277.79;
    X[13] = 82700.15; Y[13] = 6485.49;
    X[14] = 86547.22; Y[14] = 10342.53;
    X[15] = 90394.28; Y[15] = 14199.57;
    X[16] = 90394.28; Y[16] = 19211.94;
    X[17] = 90394.28; Y[17] = 24750.99;
    X[18] = 86653.54; Y[18] = 28554.57;
    X[19] = 82913.87; Y[19] = 32358.15;
    X[20] = 79268.72; Y[20] = 33795.63;
    X[21] = 76154.12; Y[21] = 35057.88;
    X[22] = 74484.05; Y[22] = 35583.57;
    X[23] = 70409.29; Y[23] = 36523.08;
    X[24] = 66334.54; Y[24] = 37462.59;
    X[25] = 64662.32; Y[25] = 37742.76;
    X[26] = 60137.56; Y[26] = 38336.76;
    X[27] = 55689.05; Y[27] = 38896.11;
    X[28] = 47782.26; Y[28] = 39001.05;
    X[29] = 44054.41; Y[29] = 38969.37;
    X[30] = 40326.55; Y[30] = 38937.69;
    X[31] = 36744.76; Y[31] = 38832.75;
    X[32] = 32133.01; Y[32] = 38481.3;
    X[33] = 27597.5; Y[33] = 38130.84;
    X[34] = 21918.19; Y[34] = 37007.19;
    X[35] = 17870.29; Y[35] = 35901.36;
    X[36] = 13822.38; Y[36] = 34795.53;
    X[37] = 13593.62; Y[37] = 34726.23;
    X[38] = 13365.93; Y[38] = 34620.3;
    X[39] = 9226.73; Y[39] = 33113.52;
    X[40] = 6246.38; Y[40] = 30888;
    X[41] = 3266.03; Y[41] = 28662.48;
    X[42] = 1632.48; Y[42] = 25789.5;
    X[43] = 0; Y[43] = 22915.53;
    X[44] = 0; Y[44] = 19201.05;
    X[45] = 0; Y[45] = 14329.26;
    X[46] = 3746.11; Y[46] = 10456.38;
    X[47] = 7493.3; Y[47] = 6583.5;
    X[48] = 13503.4; Y[48] = 4341.15;
    X[49] = 18795; Y[49] = 2963.07;
    X[50] = 24086.6; Y[50] = 1584.99;

    var W = X[15],
        H = Y[28];


    return {X: X, Y: Y, W : W, H : H};
};
CVolume.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._c(XX[0], YY[0], XX[1], YY[1], XX[2], YY[2] );
    pGraphics._c(XX[2], YY[2], XX[3], YY[3], XX[4], YY[4] );
    pGraphics._c(XX[4], YY[4], XX[5], YY[5], XX[6], YY[6] );
    pGraphics._c(XX[6], YY[6], XX[7], YY[7], XX[8], YY[8] );
    pGraphics._c(XX[8], YY[8], XX[9], YY[9], XX[10], YY[10] );
    pGraphics._c(XX[10], YY[10], XX[11], YY[11], XX[12], YY[12] );
    pGraphics._c(XX[12], YY[12], XX[13], YY[13], XX[14], YY[14] );
    pGraphics._c(XX[14], YY[14], XX[15], YY[15], XX[16], YY[16] );
    pGraphics._c(XX[16], YY[16], XX[17], YY[17], XX[18], YY[18] );
    pGraphics._c(XX[18], YY[18], XX[19], YY[19], XX[20], YY[20] );
    pGraphics._c(XX[20], YY[20], XX[21], YY[21], XX[22], YY[22] );
    pGraphics._c(XX[22], YY[22], XX[23], YY[23], XX[24], YY[24] );
    pGraphics._c(XX[24], YY[24], XX[25], YY[25], XX[26], YY[26] );
    pGraphics._c(XX[26], YY[26], XX[27], YY[27], XX[28], YY[28] );
    pGraphics._c(XX[28], YY[28], XX[29], YY[29], XX[30], YY[30] );
    pGraphics._c(XX[30], YY[30], XX[31], YY[31], XX[32], YY[32] );
    pGraphics._c(XX[32], YY[32], XX[33], YY[33], XX[34], YY[34] );
    pGraphics._c(XX[34], YY[34], XX[35], YY[35], XX[36], YY[36] );
    pGraphics._c(XX[36], YY[36], XX[37], YY[37], XX[38], YY[38] );
    pGraphics._c(XX[38], YY[38], XX[39], YY[39], XX[40], YY[40] );
    pGraphics._c(XX[40], YY[40], XX[41], YY[41], XX[42], YY[42] );
    pGraphics._c(XX[42], YY[42], XX[43], YY[43], XX[44], YY[44] );
    pGraphics._c(XX[44], YY[44], XX[45], YY[45], XX[46], YY[46] );
    pGraphics._c(XX[46], YY[46], XX[47], YY[47], XX[48], YY[48] );
    pGraphics._c(XX[48], YY[48], XX[49], YY[49], XX[50], YY[50] );
};

/**
 *
 * @constructor
 * @extends {CNaryOperator}
 */
function CClosedPathIntegral()
{
    CNaryOperator.call(this);
}
CClosedPathIntegral.prototype = Object.create(CNaryOperator.prototype);
CClosedPathIntegral.prototype.constructor = CClosedPathIntegral;
CClosedPathIntegral.prototype.drawGlyph = function(parameters)
{
    var x           = parameters.x,
        y           = parameters.y,
        Integral    = parameters.Integral,
        Circle      = parameters.Circle,
        CoeffWidth  = parameters.CoeffWidth,
        PDSE        = parameters.PDSE;

    var pGraphics   = parameters.PDSE.Graphics;


    var oCompiledPr = this.Parent.Get_CompiledCtrPrp();

    if(CoeffWidth == undefined)
        CoeffWidth = 1;

    var CoordCircle     = Circle.getCoord(),
        CoordIntegral   = Integral.getCoord();

    var CircleX = CoordCircle.X,
        CircleY = CoordCircle.Y,
        CircleW = CoordCircle.W,
        CircleH = CoordCircle.H;

    var IntegralX = CoordIntegral.X,
        IntegralY = CoordIntegral.Y,
        IntegralW = CoeffWidth*CoordIntegral.W,
        IntegralH = CoordIntegral.H;

    var FontSize  = this.Get_TxtPrControlLetter().FontSize;
    var textScale = FontSize/850;// 1000 pt
    var alpha     = textScale*0.00413; // 25.4/96 /64;

    var shX = (IntegralW - CircleW)*alpha*0.5,
        shY = (IntegralH - CircleH)*alpha*0.48;

    var ExtX    = [],  ExtY    = [],
        InsideX = [],  InsideY = [];

    for(var j = 0; j < IntegralX.length; j++)
    {
        IntegralX[j] = this.pos.x + x + IntegralX[j]*alpha;
        IntegralY[j] = this.pos.y + y + IntegralY[j]*alpha;
    }

    var CircleLng = CircleX.length;

    var intGrid = pGraphics.GetIntegerGrid();
    pGraphics.SetIntegerGrid(false);

    this.Parent.Make_ShdColor(PDSE, this.Parent.Get_CompiledCtrPrp());

    if(pGraphics.Start_Command)
    {
        for(var i = 0; i < CircleLng; i++)
        {
            ExtX[i]     = this.pos.x + x + shX + CircleX[i]*alpha*1.1 - CircleW*alpha*0.04;
            ExtY[i]     = this.pos.y + y + shY + CircleY[i]*alpha*1.1;

            InsideX[i]  = this.pos.x + x + shX + CircleX[CircleLng - i - 1]*alpha*0.9 + CircleW*alpha*0.06;
            InsideY[i]  = this.pos.y + y + shY + CircleY[CircleLng - i - 1]*alpha*0.9 + CircleH*alpha*0.1;
        }

        var oTextOutline = oCompiledPr.TextOutline;

        var oCompiledPr2 = oCompiledPr.Copy();
        oCompiledPr2.TextFill = AscFormat.CreateNoFillUniFill();
        oCompiledPr2.Unifill  = null;
        oCompiledPr2.Color    = null;
        pGraphics.SetTextPr(oCompiledPr2, PDSE.Theme);
        pGraphics._s();
        Circle.drawPath(pGraphics, ExtX, ExtY);
        pGraphics._z();
        Circle.drawPath(pGraphics, InsideX, InsideY);
        pGraphics._z();
        pGraphics.ds();
        pGraphics.df();
        pGraphics._s();
        Integral.drawPath(pGraphics, IntegralX, IntegralY, IntegralW*alpha);
        pGraphics.ds();
        pGraphics.df();

        // делаем заливку уже обводки

        var WidthLine;
        if(pGraphics.m_oTextPr.TextOutline && AscFormat.isRealNumber(pGraphics.m_oTextPr.TextOutline.w))
        {
            WidthLine = (pGraphics.m_oTextPr.TextOutline.w/36000) *0.6; // сместим заливку на половину толщины линии , чтобы не было зазоров м/ду обводкой и заливкой
        }
        else
        {
            WidthLine = 0;
        }

        // последняя точка совпадает в пути с первой, поэтому берем предпоследнюю

        var PrevX = ExtX[CircleLng - 2],
            PrevY = ExtY[CircleLng - 2];

        for(var i = 1; i < CircleLng; i++)
        {
            if(PrevY > ExtY[i])
            {
                ExtX[i]                     += WidthLine;
                InsideX[CircleLng - i - 1]  -= WidthLine;
            }
            else if(PrevY < ExtY[i])
            {
                ExtX[i]                     -= WidthLine;
                InsideX[CircleLng - i - 1]  += WidthLine;
            }

            if(PrevX > ExtX[i])
            {
                ExtY[i]                     -= WidthLine;
                InsideY[CircleLng - i - 1]  += WidthLine;
            }
            else if(PrevX < ExtX[i])
            {
                ExtY[i]                    += WidthLine;
                InsideY[CircleLng - i - 1] -= WidthLine;
            }

            PrevX = ExtX[i];
            PrevY = ExtY[i];
        }

        ExtX[0] = ExtX[CircleX.length - 1];
        ExtY[0] = ExtY[CircleX.length - 1];

        InsideY[CircleX.length - 1] = InsideY[0];
        InsideY[CircleX.length - 1] = InsideY[0];

        var IntegralLng = IntegralX.length;
        PrevX = IntegralX[IntegralLng - 2];
        PrevY = IntegralY[IntegralLng - 2];

        for(var j = 0; j < IntegralLng; j++)
        {
            var CurrentX = IntegralX[j],
                CurrentY = IntegralY[j];

            if(PrevY > IntegralY[j])
                IntegralX[j] += WidthLine;
            else if(PrevY < IntegralY[j])
                IntegralX[j] -= WidthLine;

            if(PrevX > IntegralX[j])
                IntegralY[j] -= WidthLine;
            else if(PrevX < IntegralX[j])
                IntegralY[j] += WidthLine;


            PrevX = CurrentX;
            PrevY = CurrentY;
        }


        IntegralX[0] = IntegralX[IntegralLng - 1];
        IntegralY[0] = IntegralY[IntegralLng - 1];

        // т.к. при отрисовке textArt сравниаются ссылки текстовых настроек и если они совпали, то текстовые настройки не меняются и отрисовка происходит с теми же текстовые настройками, к-ые выставлены ранее
        oCompiledPr.TextOutline  = null;

        pGraphics.SetTextPr(oCompiledPr, PDSE.Theme);

        pGraphics._s();
        Circle.drawPath(pGraphics, ExtX, ExtY);
        pGraphics._z();
        Circle.drawPath(pGraphics, InsideX, InsideY);
        pGraphics._z();
        pGraphics.ds();
        pGraphics.df();

        pGraphics._s();
        Integral.drawPath(pGraphics, IntegralX, IntegralY, IntegralW*alpha);
        pGraphics.ds();
        pGraphics.df();

        oCompiledPr.TextOutline = oTextOutline; // меняем обратно, чтобы не изменились скомпилированные текстовые настройки
    }
    else
    {
        for(var i = 0; i < CircleLng; i++)
        {
            CircleX[i] = this.pos.x + x + shX + CircleX[i]*alpha;
            CircleY[i] = this.pos.y + y + shY + CircleY[i]*alpha;
        }

        var penCircle = 750*FontSize/32;
        pGraphics.p_width(penCircle);

        pGraphics._s();
        Circle.drawPath(pGraphics, CircleX, CircleY);
        pGraphics.ds();

        pGraphics.p_width(0);

        pGraphics._s();

        Integral.drawPath(pGraphics, IntegralX, IntegralY);
        pGraphics.df();
    }

    pGraphics._s();

    pGraphics.SetIntegerGrid(intGrid);
};


/**
 *
 * @constructor
 * @extends {CClosedPathIntegral}
 */
function CContourIntegral()
{
    CClosedPathIntegral.call(this);
}
CContourIntegral.prototype = Object.create(CClosedPathIntegral.prototype);
CContourIntegral.prototype.constructor = CContourIntegral;
CContourIntegral.prototype.drawGlyph = function(x, y, pGraphics, PDSE)
{
    var parameters =
    {
        x:              x,
        y:              y,
        CoeffWidth:     1.0,
        PDSE:           PDSE,
        Integral:       new CIntegral(),
        Circle:         new CCircle()
    };

	CClosedPathIntegral.prototype.drawGlyph.call(this, parameters);
};
CContourIntegral.prototype.calculateSizeGlyph = function()
{
    var betta = this.Get_TxtPrControlLetter().FontSize/36;

    var _width =  8.624*betta,
        _height = 13.7*betta;

    this.gap = 0.93*betta;

    var width = _width + this.gap,
        height = 2*_height;

    return {width : width, height : height};
};

/**
 *
 * @constructor
 * @extends {CClosedPathIntegral}
 */
function CSurfaceIntegral()
{
    CClosedPathIntegral.call(this);
}
CSurfaceIntegral.prototype = Object.create(CClosedPathIntegral.prototype);
CSurfaceIntegral.prototype.constructor = CSurfaceIntegral;
CSurfaceIntegral.prototype.drawGlyph = function(x, y, pGraphics, PDSE)
{
    var parameters =
    {
        x:              x,
        y:              y,
        CoeffWidth:     1.6,
        PDSE:           PDSE,
        Integral:       new CDoubleIntegral(),
        Circle:         new CSurface()
    };

	CClosedPathIntegral.prototype.drawGlyph.call(this, parameters);
};
CSurfaceIntegral.prototype.calculateSizeGlyph = function()
{
    var betta = this.Get_TxtPrControlLetter().FontSize/36;

    var _width =  14.2296*betta,
        _height = 13.7*betta;

    this.gap = 0.93*betta;

    var width = _width + this.gap,
        height = 2*_height;

    return {width : width, height : height};
};

/**
 *
 * @constructor
 * @extends {CClosedPathIntegral}
 */
function CVolumeIntegral()
{
    CClosedPathIntegral.call(this);
}
CVolumeIntegral.prototype = Object.create(CClosedPathIntegral.prototype);
CVolumeIntegral.prototype.constructor = CVolumeIntegral;
CVolumeIntegral.prototype.drawGlyph = function(x, y, pGraphics, PDSE)
{
    var parameters =
    {
        x:              x,
        y:              y,
        CoeffWidth:     2.1,
        PDSE:           PDSE,
        Integral:       new CTripleIntegral(),
        Circle:         new CVolume()
    };

	CClosedPathIntegral.prototype.drawGlyph.call(this, parameters);
};
CVolumeIntegral.prototype.calculateSizeGlyph = function()
{
    var betta = this.Get_TxtPrControlLetter().FontSize/36;

    var _width =  18.925368*betta,
        _height = 13.7*betta;

    this.gap = 0.93*betta;

    var width = _width + this.gap,
        height = 2*_height;

    return {width : width, height : height};
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CNary = CNary;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var g_oTextMeasurer = AscCommon.g_oTextMeasurer;

function CSignRadical()
{
    this.Parent = null;
    this.pos = null;

    this.size = new CMathSize();
    this.gapArg = 0;
    this.gapSign = 0;   /// расстояние до значка радикала

    this.measure =
    {
        heightTick:     0,
        widthTick:      0,
        widthSlash:     0,
        bHigh:          false
    };

}
CSignRadical.prototype.draw = function(x, y, pGraphics, PDSE)
{
    var txtPrp   = this.Parent.Get_CompiledCtrPrp();
    var FontSize = txtPrp.FontSize;

    var penW =  FontSize*0.01185;

    var penW1 = 1.25*penW,
        penW2 = 5.4*penW,
        penW3 = 1.8*penW;

    y += this.gapSign; // смещаем

    //// Tick for degree ////

    var Height = this.size.height - this.gapSign;
    var sin1 = 0.456, // 0.0242/0.054
        cos1 = 0.89,
        tg1  = 0.512;

    var hTick = this.pos.y + y + Height - this.measure.heightTick;

    var xx1 = this.pos.x + x,         yy1 = hTick + 0.03*FontSize,
        xx2 = xx1 + penW1*sin1,       yy2 = yy1 + penW1*cos1,
        xx3 = xx2 + 0.03*FontSize,    yy3 = tg1*(xx2 - xx3) + yy2;

    var sin2 = 0.876,
        tg =  1.848;


    var yy4 = this.pos.y + y + Height + 0.35;
    var xx4;
    var shift = penW1*0.2336;

    if( !this.measure.bHigh )
    {
        xx4 = xx3 + (yy4-yy3)/tg - shift;
    }
    else
    {
        xx4 = xx1 + this.measure.widthSlash - shift;
    }

    //// Tick for Base ////

    var xx5 = xx4 + shift,                      yy5 = yy4,
        xx6 = xx1 + this.measure.widthSlash,    yy6 = this.pos.y + y + penW3,
        xx7 = this.pos.x + x + this.size.width, yy7 = yy6,
        xx8 = xx7,                              yy8 = yy7 - penW3;

    var tg3     = (yy6 - yy5)/(xx6 - xx5);
    var hypoth3 = Math.sqrt((xx6 - xx5)*(xx6 - xx5) + (yy6 - yy5)*(yy6 - yy5));
    var cos3    = (xx6 - xx5)/hypoth3;
    var sin3    = (yy5 - yy6)/hypoth3;

    var yy9 = yy8, xx9 = xx6 - penW3*sin3;

    var tg2 = (yy4 - yy3)/(xx4 - xx3);

    //  y = tg3*(x - xx9) + yy9
    //
    //
    //  y = tg2*(x - xx4) + yy4 - penW2*sin2
    //  tg2 = (yy4 - yy3)/(xx4 - xx3)
    //  tg3*(x - xx9) + yy9 = tg2*(x - xx4) + yy4 - penW2*sin2
    //  tg3*x - tg3*xx9 + yy9 = tg2*x - tg2*xx4 + yy4 - penW2*sin2
    //  tg3*x - tg2*x = yy4 - penW2*sin2 - tg2*xx4 + tg3*xx9 - yy9
    //
    //

    var xx10, yy10;

    if( !this.measure.bHigh )
    {
        xx10 = (yy4 - tg2*xx4 + tg3*xx9 - yy9 - penW2)/(tg3 - tg2);
        yy10 = tg3*(xx10 - xx9) + yy9;
    }
    else
    {
        xx10 = xx9;
        yy10 = tg2*(xx10 - xx4) + yy4 - penW2*sin2;
    }

    var yy11 =  hTick;
    var xx11 = (yy11 - yy4 + penW2)/tg2 + xx4;

    var mgCtrPrp = this.Parent.Get_TxtPrControlLetter();

    PDSE.Graphics.SetFont(mgCtrPrp);

    this.Parent.Make_ShdColor(PDSE, this.Parent.Get_CompiledCtrPrp());
    PDSE.Graphics._s();

    if(PDSE.Graphics.Start_Command) // textArt
    {
        PDSE.Graphics.p_width(0); // в pGraphics выставится ширина равная 1 px

        PDSE.Graphics._m(xx1,  yy1);
        PDSE.Graphics._l(xx2,  yy2);
        PDSE.Graphics._l(xx3,  yy3);
        PDSE.Graphics._l(xx4,  yy4);
        PDSE.Graphics._l(xx5,  yy5);
        PDSE.Graphics._l(xx6,  yy6);
        PDSE.Graphics._l(xx7,  yy7);
        PDSE.Graphics._l(xx8,  yy8);
        PDSE.Graphics._l(xx9,  yy9);
        PDSE.Graphics._l(xx10, yy10);
        PDSE.Graphics._l(xx11, yy11);
        PDSE.Graphics._l(xx1,  yy1);

        PDSE.Graphics.df();
    }
    else // чтобы линии были четкие не в WordArt, рисуем знак радикала по заданному пути линиями нужной толщины
    {
        var intGrid = PDSE.Graphics.GetIntegerGrid();
        PDSE.Graphics.SetIntegerGrid(true);             // для того чтобы линии были отрисованы четко (неразмыто)

        PDSE.Graphics.p_width(penW3*1000);

        if(PDSE.Graphics.m_oCoordTransform !== undefined)
        {
            var CoordTransform = PDSE.Graphics.m_oCoordTransform;
            var diff = CoordTransform.TransformPointX(xx5, yy5) - CoordTransform.TransformPointX(xx4, yy4);

            // чтобы реже перескакивали точки при незначительном изменении ширины формулы (из-за округления на отрисовке)
            // на небольших размерах приравниваем две нижние точки друг другу
            if( diff < 0.3 )
                xx5 = xx4;
        }

        PDSE.Graphics._m(xx2,  yy2);
        PDSE.Graphics._l(xx3,  yy3);
        PDSE.Graphics._l(xx4,  yy4);
        PDSE.Graphics._l(xx5,  yy5);
        PDSE.Graphics._l(xx6,  yy6);
        PDSE.Graphics._l(xx7,  yy7);

        PDSE.Graphics.ds();

        PDSE.Graphics.SetIntegerGrid(intGrid);
    }

    PDSE.Graphics._s();

};
CSignRadical.prototype.recalculateSize = function(oMeasure, sizeArg, bInline)
{
    var height = 0;
    var CtrPrp = this.Parent.Get_CompiledCtrPrp(),
        FontSize = CtrPrp.FontSize;

    var Symbol5 = new CMathText(true);
    Symbol5.add(0x35);

    // измеряем функцией MeasureJustDraw, чтобы был выставлен Font
    this.Parent.MeasureJustDraw(Symbol5);

    var measureH = Symbol5.size.height;

    // высота символов изменяется непропорционально размерам шрифта
    // поэтому ориентируемся на высоту символа 5

    var H1;

    var H0 =  measureH*1.07,
        H2 = measureH*2.8,
        H3 = measureH*4.08,
        H4 = measureH*5.7,
        H5 = measureH*7.15;

    if(bInline)
    {
        this.gapArg =   measureH*0.015; /// расстояние до аргумента
        this.gapSign =  0; /// расстояние до значка радикала

        H1 = measureH*1.45;
    }
    else
    {
        this.gapArg =  measureH*0.0991; /// расстояние до аргумента
        this.gapSign = measureH*0.1215; /// расстояние до значка радикала

        H1 = measureH*1.6235;
    }

    var heightArg = sizeArg.height + this.gapArg,
        widthArg = sizeArg.width;

    this.measure.bHigh = false;

    var letterG = new CMathText(true);
    letterG.add(0x67);

    // измеряем функцией MeasureJustDraw, чтобы был выставлен Font
    this.Parent.MeasureJustDraw(letterG);

    var Descent = letterG.size.height - letterG.size.ascent;
    var bDescentArg = sizeArg.height - sizeArg.ascent > 0.9*Descent;

    if(heightArg < H0 && !bDescentArg)
        height = H0;
    else if( heightArg < H1)
        height = H1;
    else if( heightArg < H2 )
        height = H2;
    else if( heightArg < H3 )
        height = H3;
    else if( heightArg < H4 )
        height = H4;
    else if( heightArg < H5 )
        height = H5;
    else
    {
        height = heightArg;
        this.measure.bHigh = true;
    }
    ////////////////////////////////////


    //////////  Size of tick  //////////

    var measureTick = 0.27438 * FontSize;

    var minHgtRad = 1.13*measureTick,
        maxHgtRad = 7.03*measureTick;

    var minHgtTick = 0.6*measureTick,
        maxHgtTick = 1.2*measureTick;

    var heightTick, widthSlash,
        gapLeft;

    if ( heightArg > maxHgtRad )
    {
        heightTick = maxHgtTick;
        widthSlash = 0.67*measureTick;

        gapLeft = 0.2*measureTick;
    }
    else
    {
        var zetta;

        if(height < H1)
            zetta = 0.75;
        else if(heightArg < H1)
            zetta = 0.82;
        else
            zetta = 0.868;

        widthSlash = measureTick *zetta;
        var H = heightArg < H1 ? H1 : height;

        var alpha =  (H - minHgtRad)/(2*maxHgtRad);
        heightTick = minHgtTick*(1 + alpha);

        gapLeft = 0.127* measureTick;
    }

    this.measure.widthSlash = widthSlash;

    this.measure.heightTick = heightTick;
    this.measure.widthTick = 0.13*FontSize;

    //////////////////////////////

    //////////   Width, Height  //////////

    this.size.height = height + this.gapSign;
    this.size.width  = widthSlash + gapLeft + widthArg;

    //////////////////////////////
};
CSignRadical.prototype.setPosition = function(pos)
{
    this.pos = pos;
};
CSignRadical.prototype.relate = function(parent)
{
    this.Parent = parent;
};

function CMathRadicalPr()
{
    this.type    = DEGREE_RADICAL;
    this.degHide = false;
}

CMathRadicalPr.prototype.Set_FromObject = function(Obj)
{
    if(SQUARE_RADICAL === Obj.type || DEGREE_RADICAL === Obj.type)
        this.type = Obj.type;

    if(true === Obj.degHide || 1 === Obj.degHide)
    {
        this.degHide = true;
        this.type = SQUARE_RADICAL;
    }
    else if(false === Obj.degHide || 0 === Obj.degHide)
    {
        this.degHide = false;
        this.type = DEGREE_RADICAL;
    }
};
CMathRadicalPr.prototype.ChangeType = function()
{
    if(this.type == DEGREE_RADICAL)
    {
        this.degHide = true;
        this.type = SQUARE_RADICAL;
    }
    else
    {
        this.degHide = false;
        this.type = DEGREE_RADICAL;
    }
};
CMathRadicalPr.prototype.Copy = function()
{
    var NewPr = new CMathRadicalPr();

    NewPr.type    = this.type;
    NewPr.degHide = this.degHide;

    return NewPr;
};

CMathRadicalPr.prototype.Write_ToBinary = function(Writer)
{
    // Long : type
    // Bool : degHide

    Writer.WriteLong(this.type);
    Writer.WriteBool(this.degHide);
};

CMathRadicalPr.prototype.Read_FromBinary = function(Reader)
{
    // Long : type
    // Bool : degHide

    this.type    = Reader.GetLong();
    this.degHide = Reader.GetBool();
};

/**
 *
 * @param props
 * @constructor
 * @extends {CMathBase}
 */
function CRadical(props)
{
	CMathBase.call(this);

	this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.Iterator = null;
    this.Base     = null;

    this.RealBase = null;

    this.signRadical = new CSignRadical();
    this.signRadical.relate(this);

    this.Pr = new CMathRadicalPr();

    this.gapDegree = 0;
    this.gapWidth = 0; //  в случае со степенью, если ширина степени не нулевая, добавляется расстояние для ширины

    if(props !== null && props !== undefined)
        this.init(props);

    AscCommon.g_oTableId.Add( this, this.Id );
}
CRadical.prototype = Object.create(CMathBase.prototype);
CRadical.prototype.constructor = CRadical;

CRadical.prototype.ClassType = AscDFH.historyitem_type_rad;
CRadical.prototype.kind      = MATH_RADICAL;

CRadical.prototype.init = function(props)
{
    this.setProperties(props);
    this.Fill_LogicalContent(2);

    this.fillContent();
};
CRadical.prototype.fillContent = function()
{
    this.Iterator = this.getDegree();
    this.Base     = this.getBase();
};
CRadical.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI, GapsInfo)
{
    this.Parent = Parent;
    this.ParaMath = ParaMath;

    this.Set_CompiledCtrPrp(Parent, ParaMath, RPI);

    this.ApplyProperties(RPI);

    var ArgSzIter = new CMathArgSize();
    ArgSzIter.SetValue(-2);


    this.RealBase.PreRecalc(this, ParaMath, ArgSize, RPI);

    var bDecreasedComp = RPI.bDecreasedComp;
    RPI.bDecreasedComp = true;

    this.Iterator.PreRecalc(this, ParaMath, ArgSzIter, RPI);

    RPI.bDecreasedComp = bDecreasedComp;

    if(this.bInside == false)
        GapsInfo.setGaps(this, this.TextPrControlLetter.FontSize);
};
CRadical.prototype.ApplyProperties = function(RPI)
{
    if(this.RecalcInfo.bProps)
    {
        if(this.Pr.degHide == true)
        {
            this.setDimension(1, 1);

            // TODO: IlyaKirillov: Пока убрал данный вариант, потому что у обычного пользователя он
            //       не встретится с вероятностью 99%, а обработка данного случая в текущей реализации
            //       приводит к багам в совместном редактировании.

//            if(this.Iterator !== null)
//            {
//                var Item = new CMathBase(true);
//                Item.setDimension(1, 2);
//                Item.elements[0][0] = this.Iterator;
//                Item.elements[0][1] = this.Base;
//
//                //Item.addMCToContent(this.Iterator, this.Base);
//
//                this.elements[0][0] = Item;
//            }
//            else
//            {
//                this.elements[0][0] = this.Base;
//            }

            this.elements[0][0] = this.Base;

            //---------------------

            this.RealBase = this.elements[0][0];
        }
        else
        {
            this.setDimension(1, 2);
            this.elements[0][0] = this.Iterator;
            this.elements[0][1] = this.Base;

            this.RealBase       = this.Base;

        }

        this.RecalcInfo.bProps = false;
    }
};
CRadical.prototype.Recalculate_Range = function(PRS, ParaPr, Depth)
{
    var bOneLine = PRS.bMath_OneLine;
    var WordLen = PRS.WordLen; // запоминаем, чтобы внутр мат объекты не увеличили WordLen
    this.BrGapLeft  = this.GapLeft;
    this.BrGapRight = this.GapRight;

    this.Iterator.Recalculate_Reset(PRS.Range, PRS.Line, PRS);
    this.Base.Recalculate_Reset(PRS.Range, PRS.Line, PRS);

    PRS.bMath_OneLine = true;

    this.Iterator.Recalculate_Range(PRS, ParaPr, Depth);
    this.Base.Recalculate_Range(PRS, ParaPr, Depth);

    this.recalculateSize(g_oTextMeasurer);

    this.UpdatePRS_OneLine(PRS, WordLen);
    this.Bounds.SetWidth(0, 0, this.size.width);
    this.Bounds.UpdateMetrics(0, 0, this.size);

    PRS.bMath_OneLine = bOneLine;
};
CRadical.prototype.recalculateSize = function(oMeasure)
{
    var shTop, width, ascent;

    this.signRadical.recalculateSize(oMeasure, this.RealBase.size, this.ParaMath.Is_Inline());

    var txtPrp = this.Get_CompiledCtrPrp();
    var sign = this.signRadical.size,
        gSign = this.signRadical.gapSign,
        // в случае смещения baseline контента тоже смещается, и по высоте артгумент может выйти чуть за пределы (т.о. значок интеграла будет расположен чуть выше, чем следовало бы, и размер аргумента выйде за границы)
        gArg = this.signRadical.gapArg > 2*g_dKoef_pt_to_mm ? this.signRadical.gapArg : 2*g_dKoef_pt_to_mm; // делаем смещение, т.к. для fontSize 11, 14 и меньше высота плейсхолдера не совпадает
                                                                                                            // с высотой отрисовки плейсхолдера и происходит наложение черты значка радикала и плейсхолдера

    var gapBase = gSign + gArg;

    if(this.Pr.type == SQUARE_RADICAL)
    {
        shTop = (sign.height - gSign - this.RealBase.size.height)/2;
        shTop = shTop > 0 ? shTop : 0;

        ascent = gapBase + shTop + this.RealBase.size.ascent;

        this.size.ascent = ascent;
        this.size.height = sign.height > ascent - this.RealBase.size.ascent + this.RealBase.size.height ? sign.height : ascent - this.RealBase.size.ascent + this.RealBase.size.height;
        this.size.width = sign.width + this.GapLeft + this.GapRight;
    }
    else if(this.Pr.type == DEGREE_RADICAL)
    {
        var wTick = this.signRadical.measure.widthTick,
            hTick = this.signRadical.measure.heightTick;

        // общие gaps
        var gapHeight = 0.011*txtPrp.FontSize; // добавляем это расстояние к общей высоте радикала, также как и gapWidth
        this.gapWidth = 0.011*txtPrp.FontSize;

        var wDegree = this.Iterator.size.width > wTick ? this.Iterator.size.width - wTick : 0;
        width = wDegree + sign.width + this.gapWidth;
        this.size.width = width + this.GapLeft + this.GapRight;

        shTop = (sign.height - gSign - this.RealBase.size.height)/2;

        var h1 = this.Iterator.size.height + ((0.65*sign.height + 0.5) >> 0),
            h2 = sign.height;

        if(h1 > h2)
        {
            this.size.height = h1;
            this.size.ascent = h1 - sign.height + gapBase + shTop + this.RealBase.size.ascent;
        }
        else
        {
            this.size.height = h2;
            this.size.ascent = gapBase + shTop + this.RealBase.size.ascent;
        }

        this.gapDegree = this.size.height - h1;
    }
};
CRadical.prototype.Resize = function(oMeasure, RPI)
{
    if(this.Pr.type == SQUARE_RADICAL)
        this.RealBase.Resize(oMeasure, RPI);
    else
    {
        this.Iterator.Resize(oMeasure, RPI);
        this.RealBase.Resize(oMeasure, RPI);
    }

    this.recalculateSize(oMeasure);
};
CRadical.prototype.setPosition = function(pos, PosInfo)
{
    this.pos.x = pos.x;
    this.pos.y = pos.y - this.size.ascent;

    this.UpdatePosBound(pos, PosInfo);

    var PosBase    = new CMathPosition(),
        PosRadical = new CMathPosition();

    if(this.Pr.type == SQUARE_RADICAL)
    {
        var gapLeft = this.size.width - this.RealBase.size.width - this.GapRight;
        var gapTop = this.size.ascent - this.RealBase.size.ascent;

        PosRadical.x = this.pos.x + this.GapLeft;
        PosRadical.y = this.pos.y;

        PosBase.x = this.pos.x + gapLeft;
        PosBase.y = this.pos.y + gapTop + this.RealBase.size.ascent;

        this.signRadical.setPosition(PosRadical);
        this.RealBase.setPosition(PosBase, PosInfo);
    }
    else if(this.Pr.type == DEGREE_RADICAL)
    {
        var wTick = this.signRadical.measure.widthTick;

        var PosDegree = new CMathPosition();

        PosDegree.x = this.pos.x + this.GapLeft + this.gapWidth;
        PosDegree.y = this.pos.y + this.gapDegree + this.Iterator.size.ascent;

        this.Iterator.setPosition(PosDegree, PosInfo);

        var wDegree = this.Iterator.size.width > wTick ? this.Iterator.size.width - wTick : 0;

        PosRadical.x = this.pos.x + this.GapLeft + wDegree;
        PosRadical.y = this.pos.y + this.size.height - this.signRadical.size.height;

        this.signRadical.setPosition(PosRadical);

        PosBase.x = this.pos.x + this.size.width - this.RealBase.size.width - this.GapRight;
        PosBase.y = this.pos.y + this.size.ascent;

        this.RealBase.setPosition(PosBase, PosInfo);
    }

    pos.x += this.size.width;
};
CRadical.prototype.Get_ParaContentPosByXY = function(SearchPos, Depth, _CurLine, _CurRange, StepEnd)
{
    var bResult;

    if(this.Pr.type == DEGREE_RADICAL)
    {
        bResult = CMathBase.prototype.Get_ParaContentPosByXY.call(this, SearchPos, Depth, _CurLine, _CurRange, StepEnd);
    }
    else
    {
        if(true === this.Content[1].Get_ParaContentPosByXY(SearchPos, Depth + 1, _CurLine, _CurRange, StepEnd))
        {
            SearchPos.Pos.Update2(1, Depth);
            bResult = true;
        }
    }

    return bResult;
};
CRadical.prototype.Draw_LinesForContent = function(PDSL)
{
    if(this.Pr.type == SQUARE_RADICAL)
    {
        this.RealBase.Draw_Lines(PDSL);
    }
    else
    {
        this.RealBase.Draw_Lines(PDSL);
        this.Iterator.Draw_Lines(PDSL);
    }
};
CRadical.prototype.Draw_Elements = function(PDSE)
{
    var X = PDSE.X;

    var PosLine = this.ParaMath.GetLinePosition(PDSE.Line, PDSE.Range);

    this.signRadical.draw(PosLine.x, PosLine.y, PDSE.Graphics, PDSE);
    CMathBase.prototype.Draw_Elements.call(this, PDSE);

    PDSE.X = X + this.size.width;
};
CRadical.prototype.getBase = function()
{
    return this.Content[1];
};
CRadical.prototype.getDegree = function()
{
    return this.Content[0];
};
CRadical.prototype.Apply_TextPr = function(TextPr, IncFontSize, ApplyToAll)
{
    this.Apply_TextPrToCtrPr(TextPr, IncFontSize, ApplyToAll);

    this.Iterator.Apply_TextPr(TextPr, IncFontSize, ApplyToAll);
    this.Base.Apply_TextPr(TextPr, IncFontSize, ApplyToAll);
};
CRadical.prototype.Apply_MenuProps = function(Props)
{
	if (Props.Type == Asc.c_oAscMathInterfaceType.Radical && Props.HideDegree !== undefined)
	{
		if (true == this.Iterator.IsPlaceholder() && Props.HideDegree !== this.Pr.degHide)
		{
			AscCommon.History.Add(new CChangesMathRadicalHideDegree(this, this.Pr.degHide, Props.HideDegree));
			this.raw_SetHideDegree(Props.HideDegree);
		}
	}
};
CRadical.prototype.Get_InterfaceProps = function()
{
    return new CMathMenuRadical(this);
};
CRadical.prototype.raw_SetHideDegree = function(Value)
{
    if(this.Pr.degHide !== Value)
    {
        this.Pr.ChangeType();
        this.RecalcInfo.bProps = true;
        this.ApplyProperties();

        if(this.Pr.type === SQUARE_RADICAL && this.CurPos == 0) // находимся в степени
        {
            this.CurPos = 1;
            this.Base.MoveCursorToStartPos();
        }
    }
};
CRadical.prototype.Can_ModifyArgSize = function()
{
    return this.CurPos == 0 && false === this.Is_SelectInside();
};
CRadical.prototype.Is_ContentUse = function(MathContent)
{
    if (MathContent === this.Content[1])
        return true;

    if(DEGREE_RADICAL === this.Pr.type && MathContent === this.Content[0])
        return true;

    return false;
};

/**
 *
 * @param CMathMenuRadical
 * @constructor
 * @extends {CMathMenuBase}
 */
function CMathMenuRadical(Radical)
{
	CMathMenuBase.call(this, Radical);

    if (undefined !== Radical)
    {
        var HideDegree = undefined;
        if (Radical.Iterator.IsPlaceholder())
            HideDegree = Radical.Pr.degHide == true;

        this.Type       = Asc.c_oAscMathInterfaceType.Radical;
        this.HideDegree = HideDegree;
    }
    else
    {
        this.Type       = Asc.c_oAscMathInterfaceType.Radical;
        this.HideDegree = undefined;
    }
}
CMathMenuRadical.prototype = Object.create(CMathMenuBase.prototype);
CMathMenuRadical.prototype.constructor = CMathMenuRadical;
CMathMenuRadical.prototype.get_HideDegree = function(){return this.HideDegree;};
CMathMenuRadical.prototype.put_HideDegree = function(Hide){this.HideDegree = Hide;};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CRadical = CRadical;

window["CMathMenuRadical"] = CMathMenuRadical;
CMathMenuRadical.prototype["get_HideDegree"] = CMathMenuRadical.prototype.get_HideDegree;
CMathMenuRadical.prototype["put_HideDegree"] = CMathMenuRadical.prototype.put_HideDegree;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var g_oTextMeasurer = AscCommon.g_oTextMeasurer;
var History = AscCommon.History;

function CGlyphOperator()
{
    this.loc =  null;
    this.turn = null;

    this.size = new CMathSize();
    this.stretch = 0;
    this.bStretch = true;

    this.penW = 1; // px
}
CGlyphOperator.prototype.init = function(props)
{
    // location

    // 0 - up
    // 1 - down
    // 2 - left
    // 3 - right

    // turn

    // 0 - 0
    // 1 - Pi
    // 2 - Pi/2
    // 3 - 3*Pi/2

    this.loc = props.location;
    this.turn = props.turn;
    this.bStretch = (props.bStretch == true || props.bStretch == false) ? props.bStretch : true;

};
CGlyphOperator.prototype.fixSize = function(stretch)
{
    var sizeGlyph = this.calcSize(stretch);
    var width, height, ascent;

    //var betta = this.getTxtPrp().FontSize/36;
    var bHor = this.loc == LOCATION_TOP || this.loc  == LOCATION_BOT;

    if(bHor)
    {
        width = sizeGlyph.width;
        height = sizeGlyph.height;

        ascent = height/2;
        //
        if(this.bStretch)
            this.stretch = stretch > width ? stretch : width;
        else
            this.stretch = width;

    }
    else
    {
        width = sizeGlyph.height;
        height = sizeGlyph.width;

        // baseLine смещен чуть вверх, чтобы текст при вставке в скобки располагался по центру, относительно высоты скобок
        // плейсхолдер из-за этого располагается чуть выше, как в Ворде
        //center = height/2 - 1.234722222222222*betta;
        ascent = height/2;
        this.stretch = stretch > height ? stretch : height;
    }

    this.size.width  = width;
    this.size.ascent = ascent;
    this.size.height = height;
};
CGlyphOperator.prototype.getCoordinateGlyph = function()
{
    var coord = this.calcCoord(this.stretch);

    var X = coord.XX, Y = coord.YY,
        W =  this.size.width, H =  this.size.height;

    var bHor = this.loc == LOCATION_TOP || this.loc  == LOCATION_BOT;
    var glW = 0, glH = 0;

     if(bHor)
     {
         glW = coord.W;
         glH = coord.H;
     }
     else
     {
         glW = coord.H;
         glH = coord.W;
     }

     /*var shW = (W - glW)/ 2, // выравниваем глиф по длине
         shH = (H - glH)/2; // при повороте на 90 градусовы*/

    // A*x + B*y + C = 0

    var bLine = this.Parent.typeOper == DELIMITER_LINE || this.Parent.typeOper == DELIMITER_DOUBLE_LINE, // если оператор линия, то размещаем оператор по середине
        bArrow = this.Parent.typeOper == ARROW_LEFT || this.Parent.typeOper == ARROW_RIGHT || this.Parent.typeOper == ARROW_LR,
        bDoubleArrow = this.Parent.typeOper == DOUBLE_LEFT_ARROW || this.Parent.typeOper == DOUBLE_RIGHT_ARROW || this.Parent.typeOper == DOUBLE_ARROW_LR;

    var a1, a2, b1, b2, c1, c2;

    if(bLine)
    {
        if(this.loc == LOCATION_TOP)
        {
            a1 = 1; b1 = 0; c1 = 0;
            a2 = 0; b2 = 1; c2 = (H - glH)/2;
        }
        else if(this.loc == LOCATION_BOT)
        {
            a1 = 1; b1 = 0; c1 = 0;
            a2 = 0; b2 = 1; c2 = (H - glH)/2;

        }
        else if(this.loc == LOCATION_LEFT)
        {
            a1 = 0; b1 = 1; c1 = (W - glW)/2;
            a2 = 1; b2 = 0; c2 = 0;
        }
        else if(this.loc == LOCATION_RIGHT)
        {

            a1 = 0; b1 = 1; c1 = (W - glW)/2;
            a2 = 1; b2 = 0; c2 = 0;
        }
        else if(this.loc == LOCATION_SEP)
        {
            a1 = 0; b1 = 1; c1 = (W - glW)/2;
            a2 = 1; b2 = 0; c2 = 0;
        }
    }
    else
    {
        if(this.loc == LOCATION_TOP)
        {
            a1 = 1; b1 = 0; c1 = 0;
            a2 = 0; b2 = 1; c2 = 0;
        }
        else if(this.loc == LOCATION_BOT)
        {
            a1 = 1; b1 = 0; c1 = 0;
            a2 = 0; b2 = 1; c2 = H - glH;

        }
        else if(this.loc == LOCATION_LEFT)
        {
            a1 = 0; b1 = 1; c1 = 0;
            a2 = 1; b2 = 0; c2 = 0;
        }
        else if(this.loc == LOCATION_RIGHT)
        {

            a1 = 0; b1 = 1; c1 = W - glW;
            a2 = 1; b2 = 0; c2 = 0;
        }
        else if(this.loc == LOCATION_SEP)
        {
            a1 = 0; b1 = 1; c1 = 0;
            a2 = 1; b2 = 0; c2 = 0;
        }
    }

    if(this.turn == 1)
    {
        a1 *= -1; b1 *= -1; c1 += glW;
    }
    else if(this.turn == 2)
    {
        a2 *= -1; b2 *= -1; c2 += glH;
    }
    else if(this.turn == 3)
    {
        a1 *= -1; b1 *= -1; c1 += glW;
        a2 *= -1; b2 *= -1; c2 += glH;
    }

    var gpX = 0,
        gpY = 0;

    if(this.loc == 3)
        gpX = - this.penW*25.4/96;

    var XX = [],
        YY = [];

    for(var i = 0; i < X.length; i++)
    {
        XX[i] = X[i]*a1 + Y[i]*b1 + c1 + gpX;
        YY[i] = X[i]*a2 + Y[i]*b2 + c2 + gpY;
    }

    return {XX: XX, YY: YY, Width: glW, Height: glH};
};
CGlyphOperator.prototype.draw = function(pGraphics, XX, YY, PDSE)
{
    this.Parent.Make_ShdColor(PDSE);

    var intGrid = pGraphics.GetIntegerGrid();
    pGraphics.SetIntegerGrid(false);

    pGraphics.p_width(this.penW*1000);
    pGraphics._s();

    this.drawPath(pGraphics, XX, YY, PDSE);

    pGraphics.df();
    pGraphics._s();
    pGraphics.SetIntegerGrid(intGrid);
};
CGlyphOperator.prototype.drawOnlyLines = function(x, y, pGraphics, PDSE)
{
    this.Parent.Make_ShdColor(PDSE);

    this.draw(x, y, pGraphics);
};
CGlyphOperator.prototype.getCtrPrp = function()
{
    return this.Parent.Get_TxtPrControlLetter();
};
CGlyphOperator.prototype.PreRecalc = function(Parent)
{
    this.Parent = Parent;
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function COperatorBracket()
{
    CGlyphOperator.call(this);
}
COperatorBracket.prototype = Object.create(CGlyphOperator.prototype);
COperatorBracket.prototype.constructor = COperatorBracket;
COperatorBracket.prototype.calcSize = function( stretch )
{
    var betta = this.getCtrPrp().FontSize/36;

    var heightBr, widthBr;
    var minBoxH = 4.917529296874999 *betta; //width of 0x28

    if(this.Parent.type == OPER_GROUP_CHAR)
    {
        // перевернутая скобка
        widthBr = 7.347222222222221*betta;
        heightBr = minBoxH;
    }
    else
    {
        // перевернутая скобка
        widthBr = 12.347222222222221*betta;
        var maxBoxH;

        var rx = stretch / widthBr;
        if(rx < 1)
            rx = 1;

        if(rx < 2.1)
            maxBoxH = minBoxH * 1.37;
        else if(rx < 3.22)
            maxBoxH = minBoxH * 1.06;
        else
            maxBoxH =   8.74 *betta;

        var delta = maxBoxH - minBoxH;

        heightBr = delta/4.3 * (rx - 1) + minBoxH;
        heightBr = heightBr >  maxBoxH ? maxBoxH : heightBr;
    }

    return {width: widthBr, height: heightBr};
};
COperatorBracket.prototype.calcCoord = function(stretch)
{
    var X = [],
        Y = [];

    X[0] = 26467; Y[0] = 18871;
    X[1] = 25967; Y[1] = 18871;
    X[2] = 25384; Y[2] = 16830;
    X[3] = 24737; Y[3] = 15476;
    X[4] = 24091; Y[4] = 14122;
    X[5] = 23341; Y[5] = 13309;
    X[6] = 22591; Y[6] = 12497;
    X[7] = 21778; Y[7] = 12164;
    X[8] = 20965; Y[8] = 11831;
    X[9] = 20089; Y[9] = 11831;
    X[10] = 19214; Y[10] = 11831;
    X[11] = 18317; Y[11] = 12083;
    X[12] = 17421; Y[12] = 12336;
    X[13] = 16441; Y[13] = 12652;
    X[14] = 15462; Y[14] = 12969;
    X[15] = 14357; Y[15] = 13243;
    X[16] = 13253; Y[16] = 13518;
    X[17] = 11961; Y[17] = 13518;
    X[18] = 9835; Y[18] = 13518;
    X[19] = 8292; Y[19] = 12621;
    X[20] = 6750; Y[20] = 11724;
    X[21] = 5750; Y[21] = 10055;
    X[22] = 4750; Y[22] = 8386;
    X[23] = 4270; Y[23] = 5987;
    X[24] = 3791; Y[24] = 3589;
    X[25] = 3791; Y[25] = 626;
    X[26] = 3791; Y[26] = 0;
    X[27] = 0; Y[27] = 0;
    X[28] = 0; Y[28] = 1084;
    X[29] = 83; Y[29] = 5963;
    X[30] = 1021; Y[30] = 9612;
    X[31] = 1959; Y[31] = 13261;
    X[32] = 3543; Y[32] = 15700;
    X[33] = 5127; Y[33] = 18139;
    X[34] = 7232; Y[34] = 19369;
    X[35] = 9337; Y[35] = 20599;
    X[36] = 11796; Y[36] = 20599;
    X[37] = 13338; Y[37] = 20599;
    X[38] = 14588; Y[38] = 20283;
    X[39] = 15839; Y[39] = 19968;
    X[40] = 16860; Y[40] = 19610;
    X[41] = 17882; Y[41] = 19252;
    X[42] = 18736; Y[42] = 18936;
    X[43] = 19590; Y[43] = 18621;
    X[44] = 20340; Y[44] = 18621;
    X[45] = 21091; Y[45] = 18621;
    X[46] = 21820; Y[46] = 18995;
    X[47] = 22550; Y[47] = 19370;
    X[48] = 23133; Y[48] = 20266;
    X[49] = 23717; Y[49] = 21162;
    X[50] = 24092; Y[50] = 22703;
    X[51] = 24467; Y[51] = 24245;
    X[52] = 24551; Y[52] = 26578;
    X[53] = 28133; Y[53] = 26578;

    //TODO
    // X[1] > X[52]

    var textScale = this.getCtrPrp().FontSize/1000; // 1000 pt
    var alpha = textScale*25.4/96 /64; // коэффициент используется для того, чтобы перевести координаты в миллиметры

    var augm = stretch/((X[52] + (X[0] - X[1])/2 + X[1] - X[52])*alpha*2);

    if(augm < 1)
        augm = 1;

    var YY = [],
        XX = [];

    var hh1 = [],
        hh2 = [];

    var c1 = [],
        c2 = [];

    var delta = augm < 7 ? augm : 7;

    if(augm < 7)
    {
        var RX = [],
            RX1, RX2;

        if(delta < 5.1)
        {
            hh1[0] = 1.89;
            hh2[0] = 2.58;

            hh1[1] = 1.55;
            hh2[1] = 1.72;

            hh1[2] = 1.5;
            hh2[2] = 1.64;

            hh1[3] = 1.92;
            hh2[3] = 1.97;

            // (!)
            hh1[4] = 1;
            hh2[4] = 1;
            //

            hh1[5] = 2.5;
            hh2[5] = 2.5;

            hh1[6] = 2.1;
            hh2[6] = 2.1;

            hh1[7] = 1;
            hh2[7] = 1;

            RX1 = 0.033*delta + 0.967;
            RX2 = 0.033*delta + 0.967;

        }
        else
        {
            hh1[0] = 1.82;
            hh2[0] = 2.09;

            hh1[1] = 1.64;
            hh2[1] = 1.65;

            hh1[2] = 1.57;
            hh2[2] = 1.92;

            hh1[3] = 1.48;
            hh2[3] = 2.16;

            // (!)
            hh1[4] = 1;
            hh2[4] = 1;
            //

            hh1[5] = 2.5;
            hh2[5] = 2.5;

            hh1[6] = 2.1;
            hh2[6] = 2.1;

            hh1[7] = 1;
            hh2[7] = 1;


            RX1 = 0.22*delta + 0.78;
            RX2 = 0.17*delta + 0.83;

        }

        for(var i = 0; i < 27; i++)
            RX[i] = RX1;

        for(var i = 27; i < 54; i++)
            RX[i] = RX2;

        RX[1] = (Y[52]*RX[52] - (Y[52] - Y[1]) )/Y[1];
        RX[0] = RX[1]*Y[1]/Y[0];

        RX[27] = 1;
        RX[26] = 1;

        for(var i = 0; i < 8; i++ )
            RX[26-i] = 1 + i*((RX2+RX1)/2 - 1)/7;


        for(var i = 0; i < 4; i++)
        {
            c1[i] = X[30 + 2*i] - X[28 + 2*i];
            c2[i] = X[23 - 2*i] - X[25 - 2*i];
        }

        c1[5] = X[48] - X[44];
        c2[5] = X[5] - X[9];


        c1[6] = X[52] - X[48];
        c2[6] = X[1] - X[5];


        c1[7] = (X[0] - X[1])/2 + X[1] - X[52];
        c2[7] = (X[0] - X[1])/2;

        c1[4] = X[44] - X[36];
        c2[4] = X[9] - X[17];

        var rest1 = 0,
            rest2 = 0;

        for(var i = 0; i < 8; i++)
        {
            if(i == 4)
                continue;
            hh1[i] = (hh1[i] - 1)*(delta - 1) + 1;
            hh2[i] = (hh2[i] - 1)*(delta - 1) + 1;

            rest1 += hh1[i]*c1[i];
            rest2 += hh2[i]*c2[i];
        }

        var H1 = delta*(X[52] + c1[7]),
            H2 =  H1 - (X[26] - X[27]) ;

        hh1[4] = (H1 - rest1)/c1[4];
        hh2[4] = (H2 - rest2)/c2[4];

        XX[27] = X[27];
        XX[26] = X[26];

        XX[28] = X[27];
        XX[25] = X[26];

        for(var i = 0; i < 4; i++)
        {
            for(var j = 1; j < 3; j ++)
            {
                var t = j + i*2;
                XX[28 + t] = XX[27 + t] + (X[28+t] - X[27+t])*hh1[i];
                XX[25 - t] = XX[26 - t] + (X[25-t] - X[26-t])*hh2[i];
            }
        }

        //переопределяем 36 и 17
        for(var i = 1; i < 9; i++)
        {
            XX[36 + i] = XX[35+i] + (X[36+i] - X[35+i])*hh1[4];
            XX[17 - i] = XX[18-i] + (X[17-i] - X[18-i])*hh2[4];
        }

        for(var i = 0; i < 4; i++)
        {
            XX[45+i] = XX[44+i] + ( X[45+i] - X[44+i])*hh1[5];
            XX[8-i]  = XX[9-i] + (X[8-i] -X[9-i])*hh2[5];
        }

        for(var i = 0; i < 4; i++)
        {
            XX[49+i] = XX[48+i] + (X[49+i] - X[48+i])*hh1[6];
            XX[4-i]  = XX[5-i]  + (X[4-i] - X[5-i] )*hh2[6];
        }

        XX[53] = XX[52] + 2*c1[7]*hh1[7];
        XX[0]  = XX[1]  + 2*c2[7]*hh2[7];

    }
    else
    {
        hh1[0] = 1.75;
        hh2[0] = 2.55;

        hh1[1] = 1.62;
        hh2[1] = 1.96;

        hh1[2] = 1.97;
        hh2[2] = 1.94;

        hh1[3] = 1.53;
        hh2[3] = 1.0;

        hh1[4] = 2.04;
        hh2[4] = 3.17;

        hh1[5] = 2.0;
        hh2[5] = 2.58;

        hh1[6] = 2.3;
        hh2[6] = 1.9;

        hh1[7] = 2.3;
        hh2[7] = 1.9;

        // (!)
        hh1[8] = 1;
        hh2[8] = 1;
        //

        hh1[9] = 2.5;
        hh2[9] = 2.5;

        hh1[10] = 2.1;
        hh2[10] = 2.1;

        hh1[11] = 1;
        hh2[11] = 1;

        var rest1 = 0,
            rest2 = 0;

        for(var i=0; i<8; i++)
        {
            c1[i] = X[30+i] - X[29+i];
            c2[i] = X[24-i] - X[25-i];
        }

        c1[9] = X[48] - X[44];
        c2[9] = X[5] - X[9];

        c1[10] = X[52] - X[48];
        c2[10] = X[1] - X[5];


        c1[11] = (X[0] - X[1])/2 + X[1] - X[52];
        c2[11] = (X[0] - X[1])/2;

        c1[8] = X[44] - X[36];
        c2[8] = X[9] - X[17];


        for(var i = 0; i < 12; i++)
        {
            if(i == 8)
                continue;
            hh1[i] = (hh1[i] - 1)*(delta - 1) + 1;
            hh2[i] = (hh2[i] - 1)*(delta - 1) + 1;

            rest1 += hh1[i]*c1[i];
            rest2 += hh2[i]*c2[i];
        }

        var H1 = delta*(X[52] + c1[11]),
            H2 =  H1 - (X[26] - X[27]) ;

        hh1[8] = (H1 - rest1)/c1[8];
        hh2[8] = (H2 - rest2)/c2[8];

        XX[27] = X[27];
        XX[26] = X[26];

        XX[28] = X[27];
        XX[25] = X[26];

        for(var i = 0; i < 9; i++)
        {
            XX[28 + i] = XX[27 + i] + (X[28+i] - X[27+i])*hh1[i];
            XX[25 - i] = XX[26 - i] + (X[25-i] - X[26-i])*hh2[i];
        }

        //переопределяем 36 и 17
        for(var i = 1; i < 9; i++)
        {
            XX[36 + i] = XX[35+i] + (X[36+i] - X[35+i])*hh1[8];
            XX[17 - i] = XX[18-i] + (X[17-i] - X[18-i])*hh2[8];
        }

        // TODO
        // переделать
        for(var i = 0; i < 4; i++)
        {
            XX[45+i] = XX[44+i] + ( X[45+i] - X[44+i])*hh1[9];
            XX[8-i]  = XX[9-i] + (X[8-i] -X[9-i])*hh2[9];
        }

        for(var i = 0; i < 4; i++)
        {
            XX[49+i] = XX[48+i] + (X[49+i] - X[48+i])*hh1[10];
            XX[4-i]  = XX[5-i]  + (X[4-i] - X[5-i] )*hh2[10];
        }

        XX[53] = XX[52] + 2*c1[11]*hh1[11];
        XX[0]  = XX[1]  + 2*c2[11]*hh2[11];

        var RX = [];

        for(var i = 0; i < 27; i++)
            RX[i] = 0.182*delta + 0.818;

        for(var i = 27; i < 54; i++)
            RX[i] = 0.145*delta + 0.855;

        RX[1] = (Y[52]*RX[52] - (Y[52] - Y[1]) )/Y[1];
        RX[0] = RX[1]*Y[1]/Y[0];

        RX[27] = 1;
        RX[26] = 1;

        for(var i = 0; i < 7; i++ )
            RX[28-i] = 1 + i*(0.145*delta + 0.855 - 1)/8;

        var w = Y[33]*RX[33],
            w2 = Y[9]*RX[9] + 0.15*(Y[9]*RX[9] - Y[19]*RX[19]);

        for(var i = 0; i < 11; i++)
        {
            RX[34+i] = w/Y[34+i];
            RX[19-i] = w2/Y[19-i];
        }

        var _H1 = augm*(X[52] + c1[11]),
            _H2 =  _H1 - (X[26] - X[27]);

        var w3 = _H1 - (XX[52] + c1[11]),
            w4 = _H2 - (XX[1] - XX[26] + c2[11]);

        for(var i = 0; i < 10; i++)
        {
            XX[53 - i] = XX[53 - i] + w3;
            XX[i] = XX[i] + w4;
        }

    }


    for(var i = 0; i < 54; i++)
    {
        //YY[i] =  (H - Y[i]*RX[i])*alpha;
        if(this.Parent.type == OPER_GROUP_CHAR)
            YY[i] = (Y[53] - Y[i])*alpha;
        else
            YY[i] = (Y[53]*RX[53] - Y[i]*RX[i])*alpha;

        XX[i] =  XX[i]*alpha;
    }


    for(var i = 0; i < 50; i++)
        YY[54 + i] = YY[51 - i];

    for(var i = 0; i < 50; i++)
        XX[54 + i] =  XX[53] + XX[52] - XX[51-i];

    var W = XX[77], // ширина глифа
        H = YY[26]; // высота глифа

    return {XX: XX, YY: YY, W: W, H: H};
};
COperatorBracket.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._c(XX[1], YY[1], XX[2], YY[2], XX[3], YY[3] );
    pGraphics._c(XX[3], YY[3], XX[4], YY[4], XX[5], YY[5] );
    pGraphics._c(XX[5], YY[5], XX[6], YY[6], XX[7], YY[7] );
    pGraphics._c(XX[7], YY[7], XX[8], YY[8], XX[9], YY[9] );
    pGraphics._c(XX[9], YY[9], XX[10], YY[10], XX[11], YY[11] );
    pGraphics._c(XX[11], YY[11], XX[12], YY[12], XX[13], YY[13] );
    pGraphics._c(XX[13], YY[13], XX[14], YY[14], XX[15], YY[15] );
    pGraphics._c(XX[15], YY[15], XX[16], YY[16], XX[17], YY[17] );
    pGraphics._c(XX[17], YY[17], XX[18], YY[18], XX[19], YY[19] );
    pGraphics._c(XX[19], YY[19], XX[20], YY[20], XX[21], YY[21] );
    pGraphics._c(XX[21], YY[21], XX[22], YY[22], XX[23], YY[23] );
    pGraphics._c(XX[23], YY[23], XX[24], YY[24], XX[25], YY[25] );
    pGraphics._l(XX[26], YY[26]);
    pGraphics._l(XX[27], YY[27]);
    pGraphics._l(XX[28], YY[28]);
    pGraphics._c(XX[28], YY[28], XX[29], YY[29], XX[30], YY[30] );
    pGraphics._c(XX[30], YY[30], XX[31], YY[31], XX[32], YY[32] );
    pGraphics._c(XX[32], YY[32], XX[33], YY[33], XX[34], YY[34] );
    pGraphics._c(XX[34], YY[34], XX[35], YY[35], XX[36], YY[36] );
    pGraphics._c(XX[36], YY[36], XX[37], YY[37], XX[38], YY[38] );
    pGraphics._c(XX[38], YY[38], XX[39], YY[39], XX[40], YY[40] );
    pGraphics._c(XX[40], YY[40], XX[41], YY[41], XX[42], YY[42] );
    pGraphics._c(XX[42], YY[42], XX[43], YY[43], XX[44], YY[44] );
    pGraphics._c(XX[44], YY[44], XX[45], YY[45], XX[46], YY[46] );
    pGraphics._c(XX[46], YY[46], XX[47], YY[47], XX[48], YY[48] );
    pGraphics._c(XX[48], YY[48], XX[49], YY[49], XX[50], YY[50] );
    pGraphics._c(XX[50], YY[50], XX[51], YY[51], XX[52], YY[52] );
    pGraphics._l(XX[53], YY[53]);

    pGraphics._c(XX[53], YY[53], XX[54], YY[54], XX[55], YY[55] );
    pGraphics._c(XX[55], YY[55], XX[56], YY[56], XX[57], YY[57] );
    pGraphics._c(XX[57], YY[57], XX[58], YY[58], XX[59], YY[59] );
    pGraphics._c(XX[59], YY[59], XX[60], YY[60], XX[61], YY[61] );
    pGraphics._c(XX[61], YY[61], XX[62], YY[62], XX[63], YY[63] );
    pGraphics._c(XX[63], YY[63], XX[64], YY[64], XX[65], YY[65] );
    pGraphics._c(XX[65], YY[65], XX[66], YY[66], XX[67], YY[67] );
    pGraphics._c(XX[67], YY[67], XX[68], YY[68], XX[69], YY[69] );
    pGraphics._c(XX[69], YY[69], XX[70], YY[70], XX[71], YY[71] );
    pGraphics._c(XX[71], YY[71], XX[72], YY[72], XX[73], YY[73] );
    pGraphics._c(XX[73], YY[73], XX[74], YY[74], XX[75], YY[75] );
    pGraphics._c(XX[75], YY[75], XX[76], YY[76], XX[77], YY[77] );
    pGraphics._l(XX[78], YY[78]);
    pGraphics._l(XX[79], YY[79]);
    pGraphics._l(XX[80], YY[80]);
    pGraphics._c(XX[80], YY[80], XX[81], YY[81], XX[82], YY[82] );
    pGraphics._c(XX[82], YY[82], XX[83], YY[83], XX[84], YY[84] );
    pGraphics._c(XX[84], YY[84], XX[85], YY[85], XX[86], YY[86] );
    pGraphics._c(XX[86], YY[86], XX[87], YY[87], XX[88], YY[88] );
    pGraphics._c(XX[88], YY[88], XX[89], YY[89], XX[90], YY[90] );
    pGraphics._c(XX[90], YY[90], XX[91], YY[91], XX[92], YY[92] );
    pGraphics._c(XX[92], YY[92], XX[93], YY[93], XX[94], YY[94] );
    pGraphics._c(XX[94], YY[94], XX[95], YY[95], XX[96], YY[96] );
    pGraphics._c(XX[96], YY[96], XX[97], YY[97], XX[98], YY[98] );
    pGraphics._c(XX[98], YY[98], XX[99], YY[99], XX[100], YY[100] );
    pGraphics._c(XX[100], YY[100], XX[101], YY[101], XX[102], YY[102]);
    pGraphics._c(XX[102], YY[102], XX[103], YY[103], XX[0], YY[0]);
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function COperatorParenthesis()
{
    CGlyphOperator.call(this);
}
COperatorParenthesis.prototype = Object.create(CGlyphOperator.prototype);
COperatorParenthesis.prototype.constructor = COperatorParenthesis;
COperatorParenthesis.prototype.calcSize = function(stretch)
{
    var betta = this.getCtrPrp().FontSize/36;

    var heightBr, widthBr;
    var minBoxH =   5.27099609375 *betta; //width of 0x28


    if(this.Parent.type == OPER_GROUP_CHAR)
    {
        // перевернутая скобка
        widthBr = 6.99444444444*betta;
        heightBr = minBoxH;
    }
    else
    {
        var maxBoxH =   9.63041992187 *betta; //9.63 width of 0x239D
        widthBr = 11.99444444444 *betta;


        var ry = stretch / widthBr,
            delta = maxBoxH - minBoxH;

        heightBr = delta/4.3 * (ry - 1) + minBoxH;
        heightBr = heightBr >  maxBoxH ? maxBoxH : heightBr;
    }


    return {height: heightBr, width : widthBr};
};
COperatorParenthesis.prototype.calcCoord = function(stretch)
{
    //cкобка перевернутая на 90 градусов

    var X = [],
        Y = [];

    X[0] = 39887; Y[0] = 18995;
    X[1] = 25314; Y[1] = 18995;
    X[2] = 15863; Y[2] = 14309;
    X[3] = 6412; Y[3] = 9623;
    X[4] = 3206; Y[4] = 0;
    X[5] = 0; Y[5] = 1000;
    X[6] = 3206; Y[6] = 13217;
    X[7] = 13802; Y[7] = 19722;
    X[8] = 24398; Y[8] = 26227;
    X[9] = 39470; Y[9] = 26227;

    var textScale = this.getCtrPrp().FontSize/1000; // 1000 pt
    var alpha = textScale*25.4/96 /64; // коэффициент используется для того, чтобы перевести координаты в миллиметры

    var aug = stretch/(X[9]*alpha)/2; //Y[9]*alpha - высота скобки
    var RX, RY;

    var MIN_AUG = this.Parent.type == OPER_GROUP_CHAR ? 0.5 : 1;

    if(aug > 6.53)
    {
        RX = 6.53;
        RY = 2.05;
    }
    else if(aug < MIN_AUG)
    {
        RX = MIN_AUG;
        RY = MIN_AUG;
    }
    else
    {
        RX = aug;
        RY = 1 + (aug - 1)*0.19;
    }

    if(this.Parent.type !== OPER_GROUP_CHAR)
    {
        var DistH = [];
        for(var i= 0; i< 5; i++)
            DistH[i] = Y[9-i] - Y[i];

        for(var i = 5; i < 10; i++)
        {
            Y[i] = Y[i]*RY;               //точки правой дуги
            Y[9-i] = Y[i] - DistH[9-i];   //точки левой дуги
        }
    }

    // X
    var DistW = X[4] - X[5];

    for(var i=5; i<10; i++ )
    {
        X[i] = X[i]*RX;
        X[9-i] = X[i] + DistW;
    }

    var XX = [],
        YY = [];

    var shiftY =  1.1*Y[9]*alpha;

    // YY[0]  - YY[9]  - нижняя часть скобки
    // YY[9]  - YY[10] - отрезок прямой
    // YY[11] - YY[19] - верхняя часть скобки
    // YY[19] - YY[20] - отрезок прямой

    for(var i = 0; i < 10; i++)
    {

        YY[19 - i] = shiftY - Y[i]*alpha;
        YY[i] =  shiftY - Y[i]*alpha;

        XX[19 - i] =  X[i]*alpha;
        XX[i] = stretch - X[i]*alpha;
    }

    YY[20] = YY[0];
    XX[20] = XX[0];

    var W = XX[5],
        H = YY[4];

    return {XX: XX, YY: YY, W: W, H: H };
};
COperatorParenthesis.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]); //mm
    pGraphics._c(XX[0], YY[0], XX[1], YY[1], XX[2], YY[2]);
    pGraphics._c(XX[2], YY[2], XX[3], YY[3], XX[4], YY[4]);
    pGraphics._l(XX[5], YY[5]);
    pGraphics._c(XX[5], YY[5], XX[6], YY[6], XX[7], YY[7]);
    pGraphics._c(XX[7], YY[7], XX[8], YY[8], XX[9], YY[9]);
    pGraphics._l(XX[10], YY[10]);
    pGraphics._c(XX[10], YY[10], XX[11], YY[11], XX[12], YY[12]);
    pGraphics._c(XX[12], YY[12], XX[13], YY[13], XX[14], YY[14]);
    pGraphics._l(XX[15], YY[15]);
    pGraphics._c(XX[15], YY[15], XX[16], YY[16], XX[17], YY[17]);
    pGraphics._c(XX[17], YY[17], XX[18], YY[18], XX[19], YY[19]);
    pGraphics._l(XX[20], YY[20]);
};

// TODO
// установить минимальный размер стрелок
/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function COperatorAngleBracket()
{
    CGlyphOperator.call(this);
}
COperatorAngleBracket.prototype = Object.create(CGlyphOperator.prototype);
COperatorAngleBracket.prototype.constructor = COperatorAngleBracket;
COperatorAngleBracket.prototype.calcSize = function(stretch)
{
    //скобка перевернутая

    var betta = this.getCtrPrp().FontSize/36;
    var widthBr = 11.994444444444444*betta;
    var heightBr;

    if( stretch/widthBr > 3.768 )
        heightBr = 5.3578125*betta;
    else
        heightBr = 4.828645833333333*betta;

    return {width : widthBr, height: heightBr};
};
COperatorAngleBracket.prototype.calcCoord = function(stretch)
{
    var X = [],
        Y = [];

    X[0] = 38990; Y[0] = 7665;
    X[1] = 1583; Y[1] = 21036;
    X[2] = 0; Y[2] = 16621;
    X[3] = 37449; Y[3] = 0;
    X[4] = 40531; Y[4] = 0;
    X[5] = 77938; Y[5] = 16621;
    X[6] = 76439; Y[6] = 21036;
    X[7] = 38990; Y[7] = 7665;

    var textScale = this.getCtrPrp().FontSize/1000; // 1000 pt
    var alpha = textScale*25.4/96 /64; // коэффициент используется для того, чтобы перевести координаты в миллиметры

    var augm = stretch/(X[5]*alpha);

    if(augm < 1)
        augm = 1;
    else if(augm > 4.7)
        augm = 4.7;

    var c1 = 1, c2 = 1;

    var ww1 = Y[0] - Y[3],
        ww2 = Y[1] - Y[2],
        ww3 = Y[1] - Y[0],
        ww4 = Y[2] - Y[3];

    if(augm > 3.768)
    {
        var WW = (Y[1] - Y[3])*1.3;
        c1 = (WW - ww1)/ww3;
        c2 = (WW - ww2)/ww4
    }

    Y[1] = Y[6] = Y[0] + ww3*c1;
    Y[2] = Y[5] = Y[3] + ww4*c2;


    var k1 = 0.01*augm;

    var hh1 = (X[0] - X[3])*k1,
        hh2 = X[1] - X[2],
        hh3 = X[3] - X[2],
        hh4 = X[0] - X[1],
        //HH = augm*(X[0] - X[2]);
        HH = augm*X[5]/2;

    var k2 = (HH -  hh1)/hh3,
        k3 = (HH - hh2)/hh4;

    X[7] = X[0] = X[1] + k3*hh4;
    X[3] = X[2] + k2*hh3;

    for(var i = 0; i < 3; i++)
    {
        X[4 + i] = 2*HH - X[3 - i];
    }

    /*var hh1 = 0.1*augm,
     hh2 = (augm*X[0] - X[])*/

    var XX = [],
        YY = [];

    for(var i = 0; i < X.length; i++)
    {
        XX[i] = X[i]*alpha;
        YY[i] = Y[i]*alpha;
    }

    var W = XX[5],
        H = YY[1];

    return {XX: XX, YY: YY, W: W, H: H};
};
COperatorAngleBracket.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._l(XX[2], YY[2]);
    pGraphics._l(XX[3], YY[3]);
    pGraphics._l(XX[4], YY[4]);
    pGraphics._l(XX[5], YY[5]);
    pGraphics._l(XX[6], YY[6]);
    pGraphics._l(XX[7], YY[7]);
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function CSquareBracket()
{
    CGlyphOperator.call(this);
}
CSquareBracket.prototype = Object.create(CGlyphOperator.prototype);
CSquareBracket.prototype.constructor = CSquareBracket;
CSquareBracket.prototype.calcCoord = function(stretch)
{
    var X = [],
        Y = [];

    X[0] = 3200;  Y[0] = 6912;
    X[1] = 3200;  Y[1] = 18592;
    X[2] = 0;     Y[2] = 18592;
    X[3] = 0;     Y[3] = 0;
    X[4] = 79424; Y[4] = 0;
    X[5] = 79424; Y[5] = 18592;
    X[6] = 76224; Y[6] = 18592;
    X[7] = 76224; Y[7] = 6912;
    X[8] = 3200;  Y[8] = 6912;

    var textScale = this.getCtrPrp().FontSize/1000; // 1000 pt
    var alpha = textScale*25.4/96 /64; // коэффициент используется для того, чтобы перевести координаты в миллиметры

    var lng = stretch/alpha - X[4] - 2*X[0];

    if(lng < 0)
        lng = 0;

    for(var i = 0; i < 4; i++)
        X[4+i] += lng;


    var XX = [],
        YY = [];

    var shY =  Y[0]*alpha;

    for(var i = 0; i < X.length; i++)
    {
        XX[i] = X[i]*alpha;
        YY[i] = Y[i]*alpha + shY;
    }

    var W = XX[4],
        H = YY[1];

    return {XX: XX, YY: YY, W: W, H: H};
};
CSquareBracket.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._l(XX[2], YY[2]);
    pGraphics._l(XX[3], YY[3]);
    pGraphics._l(XX[4], YY[4]);
    pGraphics._l(XX[5], YY[5]);
    pGraphics._l(XX[6], YY[6]);
    pGraphics._l(XX[7], YY[7]);
    pGraphics._l(XX[8], YY[8]);
};
CSquareBracket.prototype.calcSize = function()
{
    var betta = this.getCtrPrp().FontSize/36;

    var height = 4.446240234375*betta;
    //var width = 12.0*this.betta;
    var width = 12.347222222222221*betta;

    return {width: width, height: height};
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function CHalfSquareBracket()
{
    CGlyphOperator.call(this);
}
CHalfSquareBracket.prototype = Object.create(CGlyphOperator.prototype);
CHalfSquareBracket.prototype.constructor = CHalfSquareBracket;
CHalfSquareBracket.prototype.calcCoord = function(stretch)
{
    var X = [],
        Y = [];

    X[0] = 0; Y[0] = 0;
    X[1] = 0; Y[1] = 7000;
    X[2] = 74106; Y[2] = 7000;
    X[3] = 74106; Y[3] = 18578;
    X[4] = 77522; Y[4] = 18578;
    X[5] = 77522; Y[5] = 0;
    X[6] = 0; Y[6] = 0;

    var textScale = this.getCtrPrp().FontSize/1000; // 1000 pt
    var alpha = textScale*25.4/96 /64; // коэффициент используется для того, чтобы перевести координаты в миллиметры

    var w1 = X[4],
        w2 = X[4] - X[3];
    var lng = stretch/alpha - w1 - w2;

    if(lng < 0)
        lng = 0;

    for(var i = 0; i < 4; i++)
        X[2+i] += lng;

    var XX = [],
        YY = [];

    var shY = Y[1]*alpha;

    for(var i = 0; i < X.length; i++)
    {
        XX[i] = X[i]*alpha;
        YY[i] = Y[i]*alpha + shY;
    }

    var W = XX[4],
        H = YY[4];

    return {XX: XX, YY: YY, W: W, H: H};
};
CHalfSquareBracket.prototype.calcSize = function()
{
    var betta = this.getCtrPrp().FontSize/36;

    var height = 4.446240234375*betta;
    var width = 11.99444444444*betta;

    return {width: width, height: height};
};
CHalfSquareBracket.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._l(XX[2], YY[2]);
    pGraphics._l(XX[3], YY[3]);
    pGraphics._l(XX[4], YY[4]);
    pGraphics._l(XX[5], YY[5]);
    pGraphics._l(XX[6], YY[6]);
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function COperatorLine()
{
    CGlyphOperator.call(this);
}
COperatorLine.prototype = Object.create(CGlyphOperator.prototype);
COperatorLine.prototype.constructor = COperatorLine;
COperatorLine.prototype.calcSize = function()
{
    var betta = this.getCtrPrp().FontSize/36;

    var height = 4.018359374999999*betta;
    var width = 11.99444444444*betta;

    return {width: width, height: height};
};
COperatorLine.prototype.calcCoord = function(stretch)
{
    var X = [],
        Y = [];

    X[0] = 0;     Y[0] = 0;
    X[1] = 0;     Y[1] = 5520;
    X[2] = 77504; Y[2] = 5520;
    X[3] = 77504; Y[3] = 0;
    X[4] = 0;     Y[4] = 0;

    var textScale = this.getCtrPrp().FontSize/1000; // 1000 pt
    var alpha = textScale*25.4/96 /64; // коэффициент используется для того, чтобы перевести координаты в миллиметры

    var XX = [],
        YY = [];

    var shY = 0;

    for(var i = 0; i < X.length; i++)
    {
        XX[i] = X[i]*alpha;
        YY[i] = Y[i]*alpha + shY;
    }

    var lng = stretch - X[2]*alpha;

    if(lng < 0)
        lng = 0;

    XX[2] += lng;
    XX[3] += lng;


    var W = XX[2],
        H = YY[2] + shY;

    return {XX: XX, YY: YY, W: W, H: H};

};
COperatorLine.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._l(XX[2], YY[2]);
    pGraphics._l(XX[3], YY[3]);
    pGraphics._l(XX[4], YY[4]);
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function CWhiteSquareBracket()
{
    CGlyphOperator.call(this);
}
CWhiteSquareBracket.prototype = Object.create(CGlyphOperator.prototype);
CWhiteSquareBracket.prototype.constructor = CWhiteSquareBracket;
CWhiteSquareBracket.prototype.calcSize = function()
{
    var betta = this.getCtrPrp().FontSize/36;

    var height = 5.5872558593749995*betta;
    var width = 11.99444444444*betta;

    return {width: width, height: height};
};
CWhiteSquareBracket.prototype.calcCoord = function(stretch)
{
    var X = [],
        Y = [];

    /*X[0] = 77529; Y[0] = 26219;
     X[1] = 77529; Y[1] = 0;
     X[2] = 0; Y[2] = 0;
     X[3] = 0; Y[3] = 26219;
     X[4] = 4249; Y[4] = 26219;
     X[5] = 4249; Y[5] = 17055;
     X[6] = 73280; Y[6] = 17055;
     X[7] = 73280; Y[7] = 26219;
     X[8] = 77529; Y[8] = 26219;
     X[9] = 73280; Y[9] = 12431;
     X[10] = 4249; Y[10] = 12431;
     X[11] = 4249; Y[11] = 4623;
     X[12] = 73280; Y[12] = 4623;
     X[13] = 73280; Y[13] = 12431;*/

    X[0] = 3225;  Y[0] = 17055;
    X[1] = 3225;  Y[1] = 26219;
    X[2] = 0;     Y[2] = 26219;
    X[3] = 0;     Y[3] = 0;
    X[4] = 77529; Y[4] = 0;
    X[5] = 77529; Y[5] = 26219;
    X[6] = 74304; Y[6] = 26219;
    X[7] = 74304; Y[7] = 17055;
    X[8] = 3225;  Y[8] = 17055;

    X[9] = 74304; Y[9] = 12700;
    X[10] = 3225; Y[10] = 12700;
    X[11] = 3225; Y[11] = 4600;
    X[12] = 74304; Y[12] = 4600;
    X[13] = 74304; Y[13] = 12700;

    var textScale = this.getCtrPrp().FontSize/1000; // 1000 pt
    var alpha = textScale*25.4/96 /64; // коэффициент используется для того, чтобы перевести координаты в миллиметры

    var XX = [],
        YY = [];

    var shY = (Y[1] - Y[0])*alpha;

    for(var i = 0; i < X.length; i++)
    {
        XX[i] = X[i]*alpha;
        YY[i] = Y[i]*alpha + shY;
    }

    var lngY = stretch - X[4]*alpha;

    for(var i = 0; i < 4; i++)
        XX[4+i] += lngY;

    XX[12] += lngY;
    XX[13] += lngY;

    var W = XX[4],
        H = YY[3];

    return {XX: XX, YY: YY, W: W, H: H};
};
CWhiteSquareBracket.prototype.drawPath = function(pGraphics, XX, YY, PDSE)
{

    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._l(XX[2], YY[2]);
    pGraphics._l(XX[3], YY[3]);
    pGraphics._l(XX[4], YY[4]);
    pGraphics._l(XX[5], YY[5]);
    pGraphics._l(XX[6], YY[6]);
    pGraphics._l(XX[7], YY[7]);
    pGraphics._l(XX[8], YY[8]);
    pGraphics.df();

    var BgColor = this.Parent.Make_ShdColor(PDSE);
    pGraphics.b_color1(BgColor.r , BgColor.g , BgColor.b , 255);
    pGraphics._s();
    pGraphics._m(XX[9], YY[9]);
    pGraphics._l(XX[10], YY[10]);
    pGraphics._l(XX[11], YY[11]);
    pGraphics._l(XX[12], YY[12]);
    pGraphics._l(XX[13], YY[13]);
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function COperatorDoubleLine()
{
    CGlyphOperator.call(this);
}
COperatorDoubleLine.prototype = Object.create(CGlyphOperator.prototype);
COperatorDoubleLine.prototype.constructor = COperatorDoubleLine;
COperatorDoubleLine.prototype.calcSize = function()
{
    var betta = this.getCtrPrp().FontSize/36;

    var height = 6.715869140624999*betta,
        width = 11.99444444444*betta;

    return {width: width, height: height};
};
COperatorDoubleLine.prototype.calcCoord = function(stretch)
{
    var X = [],
        Y = [];

    //X[0] = 77504; Y[0] = 6400;

    X[0] = 0;     Y[0] = 0;
    X[1] = 0;     Y[1] = 5900;
    X[2] = 77504; Y[2] = 5900;
    X[3] = 77504; Y[3] = 0;
    X[4] = 0;     Y[4] = 0;

    X[5] = 0;     Y[5] = 18112;
    X[6] = 0;     Y[6] = 24012;
    X[7] = 77504; Y[7] = 24012;
    X[8] = 77504; Y[8] = 18112;
    X[9] = 0;     Y[9] = 18112;

    var textScale = this.getCtrPrp().FontSize/1000; // 1000 pt
    var alpha = textScale*25.4/96 /64; // коэффициент используется для того, чтобы перевести координаты в миллиметры

    var XX = [],
        YY = [];

    //var shY = 1.5*Y[1]*alpha;
    var shY = 0;

    for(var i = 0; i < X.length; i++)
    {
        XX[i] = X[i]*alpha;
        YY[i] = Y[i]*alpha + shY;
    }

    for(var i = 0; i < 2; i++)
    {
        XX[2+i] = stretch;
        XX[7+i] = stretch;
    }

    var W = XX[7],
        H = YY[7];

    return {XX: XX, YY: YY, W: W, H: H};
};
COperatorDoubleLine.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._l(XX[2], YY[2]);
    pGraphics._l(XX[3], YY[3]);
    pGraphics._l(XX[4], YY[4]);
    pGraphics.df();

    pGraphics._s();
    pGraphics._m(XX[5], YY[5]);
    pGraphics._l(XX[6], YY[6]);
    pGraphics._l(XX[7], YY[7]);
    pGraphics._l(XX[8], YY[8]);
    pGraphics._l(XX[9], YY[9]);
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function CSingleArrow()
{
    CGlyphOperator.call(this);
}
CSingleArrow.prototype = Object.create(CGlyphOperator.prototype);
CSingleArrow.prototype.constructor = CSingleArrow;
CSingleArrow.prototype.calcSize = function()
{
    var betta = this.getCtrPrp().FontSize/36;
    var height = 5.946923828125*betta;
    var width = 10.641210937499999*betta;

    return {width: width, height: height};
};
CSingleArrow.prototype.calcCoord = function(stretch)
{
    var X = [],
        Y = [];

    X[0] = 56138; Y[0] = 12300;
    X[1] = 8363; Y[1] = 12300;
    X[2] = 16313; Y[2] = 2212;
    X[3] = 13950; Y[3] = 0;
    X[4] = 0; Y[4] = 13650;
    X[5] = 0; Y[5] = 16238;
    X[6] = 13950; Y[6] = 29925;
    X[7] = 16313; Y[7] = 27712;
    X[8] = 8363; Y[8] = 17625;
    X[9] = 56138; Y[9] = 17625;
    X[10] = 56138; Y[10] = 12300;

    var textScale = this.getCtrPrp().FontSize/1000; // 1000 pt
    var alpha = textScale*25.4/96 /64; // коэффициент используется для того, чтобы перевести координаты в миллиметры

    var XX = [],
        YY = [];

    for(var i = 0; i < X.length; i++)
    {
        XX[i] = X[i]*alpha;
        YY[i] = Y[i]*alpha;
    }

    //var lng = stretch - 10000*alpha;
    var lng = stretch;

    if(lng > XX[9])
    {
        XX[0]  = lng;
        XX[9]  = lng;
        XX[10] = lng;
    }

    var W = XX[9],
        H = YY[6];

    return {XX: XX, YY: YY, W: W, H: H};
};
CSingleArrow.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._l(XX[2], YY[2]);
    pGraphics._l(XX[3], YY[3]);
    pGraphics._l(XX[4], YY[4]);
    pGraphics._l(XX[5], YY[5]);
    pGraphics._l(XX[6], YY[6]);
    pGraphics._l(XX[7], YY[7]);
    pGraphics._l(XX[8], YY[8]);
    pGraphics._l(XX[9], YY[9]);
    pGraphics._l(XX[10], YY[10]);
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function CLeftRightArrow()
{
    CGlyphOperator.call(this);
}
CLeftRightArrow.prototype = Object.create(CGlyphOperator.prototype);
CLeftRightArrow.prototype.constructor = CLeftRightArrow;
CLeftRightArrow.prototype.calcSize = function()
{
    var betta = this.getCtrPrp().FontSize/36;

    var height = 5.946923828125*betta;
    var width = 11.695410156249999*betta;

    return {width: width, height: height};
};
CLeftRightArrow.prototype.calcCoord = function(stretch)
{
    var X = [],
        Y = [];

    X[0] = 16950; Y[0] = 28912;
    X[1] = 14738; Y[1] = 30975;
    X[2] = 0; Y[2] = 16687;
    X[3] = 0; Y[3] = 14287;
    X[4] = 14738; Y[4] = 0;
    X[5] = 16950; Y[5] = 2062;
    X[6] = 8363; Y[6] = 12975;
    X[7] = 53738; Y[7] = 12975;
    X[8] = 45150; Y[8] = 2062;
    X[9] = 47363; Y[9] = 0;
    X[10] = 62100; Y[10] = 14287;
    X[11] = 62100; Y[11] = 16687;
    X[12] = 47363; Y[12] = 30975;
    X[13] = 45150; Y[13] = 28912;
    X[14] = 53738; Y[14] = 17962;
    X[15] = 8363; Y[15] = 17962;
    X[16] = 16950; Y[16] = 28912;

    var textScale = this.getCtrPrp().FontSize/1000; // 1000 pt
    var alpha = textScale*25.4/96 /64; // коэффициент используется для того, чтобы перевести координаты в миллиметры

    var XX = [],
        YY = [];

    for(var i = 0; i < X.length; i++)
    {
        XX[i] = X[i]*alpha;
        YY[i] = Y[i]*alpha;
    }

    var w = X[10]*alpha;

    var lng = stretch - w;

    if(lng > 0)
        for(var i = 0; i < 8; i++)
            XX[7+i] += lng;


    var W = XX[10],
        H = YY[1];

    return {XX: XX, YY: YY, W: W, H: H};
};
CLeftRightArrow.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._l(XX[2], YY[2]);
    pGraphics._l(XX[3], YY[3]);
    pGraphics._l(XX[4], YY[4]);
    pGraphics._l(XX[5], YY[5]);
    pGraphics._l(XX[6], YY[6]);
    pGraphics._l(XX[7], YY[7]);
    pGraphics._l(XX[8], YY[8]);
    pGraphics._l(XX[9], YY[9]);
    pGraphics._l(XX[10], YY[10]);
    pGraphics._l(XX[11], YY[11]);
    pGraphics._l(XX[12], YY[12]);
    pGraphics._l(XX[13], YY[13]);
    pGraphics._l(XX[14], YY[14]);
    pGraphics._l(XX[15], YY[15]);
    pGraphics._l(XX[16], YY[16]);

};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function CDoubleArrow()
{
    CGlyphOperator.call(this);
}
CDoubleArrow.prototype = Object.create(CGlyphOperator.prototype);
CDoubleArrow.prototype.constructor = CDoubleArrow;
CDoubleArrow.prototype.calcSize = function()
{
    var betta = this.getCtrPrp().FontSize/36;

    var height = 6.7027777777777775*betta;
    var width = 10.994677734375*betta;

    return {width: width, height: height};
};
CDoubleArrow.prototype.calcCoord = function(stretch)
{
    var X = [],
        Y = [];

    X[0] = 14738;  Y[0] = 29764;
    X[1] = 20775;  Y[1] = 37002;
    X[2] = 18338;  Y[2] = 39064;
    X[3] = 0;      Y[3] = 20731;
    X[4] = 0;      Y[4] = 18334;
    X[5] = 18338;  Y[5] = 0;
    X[6] = 20775;  Y[6] = 2063;
    X[7] = 14775;  Y[7] = 9225;
    X[8] = 57600;  Y[8] = 9225;
    X[9] = 57600;  Y[9] = 14213;
    X[10] = 10950; Y[10] = 14213;
    X[11] = 6638;  Y[11] = 19532;
    X[12] = 10875; Y[12] = 24777;
    X[13] = 57600; Y[13] = 24777;
    X[14] = 57600; Y[14] = 29764;
    X[15] = 14738; Y[15] = 29764;

    X[16] = 58950; Y[16] = 19495;
    X[17] = 58950; Y[17] = 19495;

    var textScale = this.getCtrPrp().FontSize/1000; // 1000 pt
    var alpha = textScale*25.4/96 /64; // коэффициент используется для того, чтобы перевести координаты в миллиметры

    var XX = [],
        YY = [];

    for(var i = 0; i < X.length; i++)
    {
        XX[i] = X[i]*alpha;
        YY[i] = Y[i]*alpha;
    }

    var lng = stretch - 10000*alpha;

    if(lng > XX[16])
    {
        XX[8] = lng;
        XX[9] = lng;

        XX[13] = lng;
        XX[14] = lng;

        XX[16] = lng;
        XX[17] = lng;
    }

    var W = XX[16],
        H = YY[2];

    return {XX: XX, YY: YY, W: W, H: H};
};
CDoubleArrow.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._l(XX[2], YY[2]);
    pGraphics._l(XX[3], YY[3]);
    pGraphics._l(XX[4], YY[4]);
    pGraphics._l(XX[5], YY[5]);
    pGraphics._l(XX[6], YY[6]);
    pGraphics._l(XX[7], YY[7]);
    pGraphics._l(XX[8], YY[8]);
    pGraphics._l(XX[9], YY[9]);
    pGraphics._l(XX[10], YY[10]);
    pGraphics._l(XX[11], YY[11]);
    pGraphics._l(XX[12], YY[12]);
    pGraphics._l(XX[13], YY[13]);
    pGraphics._l(XX[14], YY[14]);
    pGraphics._l(XX[15], YY[15]);
    pGraphics.df();

    pGraphics._s();
    pGraphics._m(XX[16], YY[16]);
    pGraphics._l(XX[17], YY[17]);
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function CLR_DoubleArrow()
{
    CGlyphOperator.call(this);
}
CLR_DoubleArrow.prototype = Object.create(CGlyphOperator.prototype);
CLR_DoubleArrow.prototype.constructor = CLR_DoubleArrow;
CLR_DoubleArrow.prototype.calcSize = function()
{
    var betta = this.getCtrPrp().FontSize/36;

    var height = 6.7027777777777775*betta;
    var width = 13.146484375*betta;

    return {width: width, height: height};
};
CLR_DoubleArrow.prototype.calcCoord = function(stretch)
{
    var X = [],
        Y = [];

    X[0] = 14775; Y[0] = 9225;
    X[1] = 56063; Y[1] = 9225;
    X[2] = 50100; Y[2] = 2063;
    X[3] = 52538; Y[3] = 0;
    X[4] = 70875; Y[4] = 18334;
    X[5] = 70875; Y[5] = 20731;
    X[6] = 52538; Y[6] = 39064;
    X[7] = 50100; Y[7] = 37002;
    X[8] = 56138; Y[8] = 29764;
    X[9] = 14738; Y[9] = 29764;
    X[10] = 20775; Y[10] = 37002;
    X[11] = 18338; Y[11] = 39064;
    X[12] = 0; Y[12] = 20731;
    X[13] = 0; Y[13] = 18334;
    X[14] = 18338; Y[14] = 0;
    X[15] = 20775; Y[15] = 2063;
    X[16] = 14775; Y[16] = 9225;

    X[17] = 10950; Y[17] = 14213;
    X[18] = 6638;  Y[18] = 19532;
    X[19] = 10875; Y[19] = 24777;
    X[20] = 59963; Y[20] = 24777;
    X[21] = 64238; Y[21] = 19532;
    X[22] = 59925; Y[22] = 14213;
    X[23] = 59925; Y[23] = 14213;
    X[24] = 10950; Y[24] = 14213;

    var textScale = this.getCtrPrp().FontSize/1000; // 1000 pt
    var alpha = textScale*25.4/96 /64;

    var XX = [],
        YY = [];

    for(var i = 0; i < X.length; i++)
    {
        XX[i] = X[i]*alpha;
        YY[i] = Y[i]*alpha;
    }

    var w = XX[4];
    var lng = stretch - 10000*alpha - w;

    for(var i = 1; i < 9; i++)
        XX[i] += lng;

    for(var i = 0; i < 3; i++)
    {
        XX[20 + i] += lng;
    }

    var W = XX[4],
        H = YY[11];

    return {XX: XX, YY: YY, W: W, H: H};
};
CLR_DoubleArrow.prototype.drawPath = function(pGraphics, XX, YY, PDSE)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._l(XX[2], YY[2]);
    pGraphics._l(XX[3], YY[3]);
    pGraphics._l(XX[4], YY[4]);
    pGraphics._l(XX[5], YY[5]);
    pGraphics._l(XX[6], YY[6]);
    pGraphics._l(XX[7], YY[7]);
    pGraphics._l(XX[8], YY[8]);
    pGraphics._l(XX[9], YY[9]);
    pGraphics._l(XX[10], YY[10]);
    pGraphics._l(XX[11], YY[11]);
    pGraphics._l(XX[12], YY[12]);
    pGraphics._l(XX[13], YY[13]);
    pGraphics._l(XX[14], YY[14]);
    pGraphics._l(XX[15], YY[15]);
    pGraphics._l(XX[16], YY[16]);
    pGraphics._z();

    pGraphics._m(XX[17], YY[17]);
    pGraphics._l(XX[18], YY[18]);
    pGraphics._l(XX[19], YY[19]);
    pGraphics._l(XX[20], YY[20]);
    pGraphics._l(XX[21], YY[21]);
    pGraphics._l(XX[22], YY[22]);
    pGraphics._l(XX[23], YY[23]);
	pGraphics._l(XX[24], YY[24]);

    pGraphics._z();
    //pGraphics.ds();
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function CCombiningArrow()
{
    CGlyphOperator.call(this);
}
CCombiningArrow.prototype = Object.create(CGlyphOperator.prototype);
CCombiningArrow.prototype.constructor = CCombiningArrow;
CCombiningArrow.prototype.calcSize = function()
{
    var betta = this.getCtrPrp().FontSize/36;

    var height = 3.9*betta;
    var width = 4.938*betta;

    return {width: width, height: height};
};
CCombiningArrow.prototype.calcCoord = function(stretch)
{
    // px                       mm
    // XX[..]                   width
    // YY[..]                   height
    // penW

    var X = [],
        Y = [];

    X[0] = 0; Y[0] = 8137;
    X[1] = 9413; Y[1] = 0;
    X[2] = 11400; Y[2] = 2250;
    X[3] = 5400; Y[3] = 7462;
    X[4] = 28275; Y[4] = 7462;
    X[5] = 28275; Y[5] = 10987;
    X[6] = 5400; Y[6] = 10987;
    X[7] = 11400; Y[7] = 16200;
    X[8] = 9413; Y[8] = 18450;
    X[9] = 0; Y[9] = 10312;
    X[10] = 0; Y[10] = 8137;

    var textScale =  this.getCtrPrp().FontSize/1000; // 1000 pt
    var alpha = textScale*25.4/96 /64; // коэффициент используется для того, чтобы перевести координаты в миллиметры

    var XX = [],
        YY = [];

    for(var i = 0; i < X.length; i++)
    {
        XX[i] = X[i]*alpha;
        YY[i] = Y[i]*alpha;
    }

    XX[4] = XX[5] = stretch;

    var W = XX[4],
        H = YY[8];

    return {XX: XX, YY: YY, W: W, H: H};
};
CCombiningArrow.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._l(XX[2], YY[2]);
    pGraphics._l(XX[3], YY[3]);
    pGraphics._l(XX[4], YY[4]);
    pGraphics._l(XX[5], YY[5]);
    pGraphics._l(XX[6], YY[6]);
    pGraphics._l(XX[7], YY[7]);
    pGraphics._l(XX[8], YY[8]);
    pGraphics._l(XX[9], YY[9]);
    pGraphics._l(XX[10], YY[10]);
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function CCombiningHalfArrow()
{
    CGlyphOperator.call(this);
}
CCombiningHalfArrow.prototype = Object.create(CGlyphOperator.prototype);
CCombiningHalfArrow.prototype.constructor = CCombiningHalfArrow;
CCombiningHalfArrow.prototype.calcSize = function()
{
    var betta = this.getCtrPrp().FontSize/36;

    // 0x21BC half, down

    var height = 3.88*betta;
    var width = 4.938*betta;

    return {width: width, height: height};
};
CCombiningHalfArrow.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._l(XX[2], YY[2]);
    pGraphics._l(XX[3], YY[3]);
    pGraphics._l(XX[4], YY[4]);
    pGraphics._l(XX[5], YY[5]);
    pGraphics._l(XX[6], YY[6]);
    pGraphics._l(XX[7], YY[7]);
};
CCombiningHalfArrow.prototype.calcCoord = function(stretch)
{
    // px                       mm
    // XX[..]                   width
    // YY[..]                   height
    // penW

    var X = [],
        Y = [];

    X[0] = 0; Y[0] = 8137;
    X[1] = 9413; Y[1] = 0;
    X[2] = 11400; Y[2] = 2250;
    X[3] = 5400; Y[3] = 7462;
    X[4] = 28275; Y[4] = 7462;
    X[5] = 28275; Y[5] = 10987;
    X[6] = 0; Y[6] = 10987;
    X[7] = 0; Y[7] = 8137;

    var textScale = this.getCtrPrp().FontSize/1000; // 1000 pt
    var alpha = textScale*25.4/96 /64; // коэффициент используется для того, чтобы перевести координаты в миллиметры

    var XX = [],
        YY = [];

    for(var i = 0; i < X.length; i++)
    {
        XX[i] = X[i]*alpha;
        YY[i] = Y[i]*alpha;
    }

    XX[4] = XX[5] = stretch;

    var W = XX[4],
        H = YY[5];

    return {XX: XX, YY: YY, W: W, H: H};
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function CCombining_LR_Arrow()
{
    CGlyphOperator.call(this);
}
CCombining_LR_Arrow.prototype = Object.create(CGlyphOperator.prototype);
CCombining_LR_Arrow.prototype.constructor = CCombining_LR_Arrow;
CCombining_LR_Arrow.prototype.calcSize = function()
{
    var betta = this.getCtrPrp().FontSize/36;

    var height = 3.88*betta;
    var width = 4.938*betta;

    return {width: width, height: height};
};
CCombining_LR_Arrow.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._l(XX[2], YY[2]);
    pGraphics._l(XX[3], YY[3]);
    pGraphics._l(XX[4], YY[4]);
    pGraphics._l(XX[5], YY[5]);
    pGraphics._l(XX[6], YY[6]);
    pGraphics._l(XX[7], YY[7]);
    pGraphics._l(XX[8], YY[8]);
    pGraphics._l(XX[9], YY[9]);
    pGraphics._l(XX[10], YY[10]);
    pGraphics._l(XX[11], YY[11]);
    pGraphics._l(XX[12], YY[12]);
    pGraphics._l(XX[13], YY[13]);
    pGraphics._l(XX[14], YY[14]);
    pGraphics._l(XX[15], YY[15]);
    pGraphics._l(XX[16], YY[16]);

};
CCombining_LR_Arrow.prototype.calcCoord = function(stretch)
{
    var X = [],
        Y = [];

    X[0] = 0; Y[0] = 8137;
    X[1] = 9413; Y[1] = 0;
    X[2] = 11400; Y[2] = 2250;
    X[3] = 5400; Y[3] = 7462;
    X[4] = 42225; Y[4] = 7462;
    X[5] = 36225; Y[5] = 2250;
    X[6] = 38213; Y[6] = 0;
    X[7] = 47625; Y[7] = 8137;
    X[8] = 47625; Y[8] = 10312;
    X[9] = 38213; Y[9] = 18450;
    X[10] = 36225; Y[10] = 16200;
    X[11] = 42225; Y[11] = 10987;
    X[12] = 5400; Y[12] = 10987;
    X[13] = 11400; Y[13] = 16200;
    X[14] = 9413; Y[14] = 18450;
    X[15] = 0; Y[15] = 10312;
    X[16] = 0; Y[16] = 8137;

    var textScale = this.getCtrPrp().FontSize/1000; // 1000 pt
    var alpha = textScale*25.4/96 /64; // коэффициент используется для того, чтобы перевести координаты в миллиметры

    var XX = [],
        YY = [];

    for(var i = 0; i < X.length; i++)
    {
        XX[i] = X[i]*alpha;
        YY[i] = Y[i]*alpha;
    }

    var lng = stretch - XX[7];

    for(var i = 0; i < 8; i++)
    {
        XX[4+i] += lng;
    }

    var W = XX[7],
        H = YY[9];

    return {XX: XX, YY: YY, W: W, H: H};

};


function COperator(type)
{
    this.ParaMath = null;

    this.type = type; // delimiter, separator, group character, accent
    this.operator = null;

    this.code = null;
    this.typeOper = null;   // тип скобки : круглая и т.п.
    this.defaultType = null;
    this.grow       = true;

    this.pos = new CMathPosition();

    this.coordGlyph = null;

    this.size = new CMathSize();
}
COperator.prototype.mergeProperties = function(properties, defaultProps)   // props (chr, type, location), defaultProps (chr, location)
{
    var props = this.getProps(properties, defaultProps);

    this.grow = properties.grow;

    var operator = null,
        typeOper = null,
        codeChr  = null;

    var type = props.type,
        location = props.loc,
        code = props.code;

    var prp = {};

    //////////    delimiters    //////////

    if( code === 0x28 || type === PARENTHESIS_LEFT)
    {
        codeChr = 0x28;
        typeOper = PARENTHESIS_LEFT;

        operator = new COperatorParenthesis();
        prp =
        {
            location:   location,
            turn:       TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x29 || type === PARENTHESIS_RIGHT)
    {
        codeChr = 0x29;
        typeOper = PARENTHESIS_RIGHT;

        operator = new COperatorParenthesis();
        prp =
        {
            location:   location,
            turn:       TURN_180
        };
        operator.init(prp);
    }
    else if(code == 0x7B || type === BRACKET_CURLY_LEFT)
    {
        codeChr = 0x7B;
        typeOper = BRACKET_CURLY_LEFT;

        operator = new COperatorBracket();
        prp =
        {
            location:   location,
            turn:       TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x7D || type === BRACKET_CURLY_RIGHT)
    {
        codeChr = 0x7D;
        typeOper = BRACKET_CURLY_RIGHT;

        operator = new COperatorBracket();
        prp =
        {
            location:   location,
            turn:       TURN_180
        };
        operator.init(prp);
    }
    else if(code === 0x5B || type === BRACKET_SQUARE_LEFT)
    {
        codeChr = 0x5B;
        typeOper = BRACKET_SQUARE_LEFT;

        operator = new CSquareBracket();
        prp =
        {
            location:   location,
            turn:       TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x5D || type === BRACKET_SQUARE_RIGHT)
    {
        codeChr = 0x5D;
        typeOper = BRACKET_SQUARE_RIGHT;

        operator = new CSquareBracket();
        prp =
        {
            location:   location,
            turn:       TURN_180
        };
        operator.init(prp);
    }
    else if(code === 0x27E8 || type === BRACKET_ANGLE_LEFT) // 0x3C => 0x27E8
    {
        codeChr = 0x27E8;
        typeOper = BRACKET_ANGLE_LEFT;

        operator = new COperatorAngleBracket();
        prp =
        {
            location:   location,
            turn:       TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x27E9 || type === BRACKET_ANGLE_RIGHT) // 0x3E => 0x27E9
    {
        codeChr = 0x27E9;
        typeOper = BRACKET_ANGLE_RIGHT;

        operator = new COperatorAngleBracket();
        prp =
        {
            location:   location,
            turn:       TURN_180
        };
        operator.init(prp);
    }
    else if(code === 0x7C || type === DELIMITER_LINE)
    {
        codeChr = 0x7C;
        typeOper = DELIMITER_LINE;

        operator = new COperatorLine();
        prp =
        {
            location:   location,
            turn:       TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x230A || type === HALF_SQUARE_LEFT)
    {
        codeChr = 0x230A;
        typeOper = HALF_SQUARE_LEFT;

        operator = new CHalfSquareBracket();
        prp =
        {
            location:   location,
            turn:       TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x230B || type == HALF_SQUARE_RIGHT)
    {
        codeChr = 0x230B;
        typeOper = HALF_SQUARE_RIGHT;

        operator = new CHalfSquareBracket();
        prp =
        {
            location:   location,
            turn:       TURN_180
        };
        operator.init(prp);
    }
    else if(code === 0x2308 || type == HALF_SQUARE_LEFT_UPPER)
    {
        codeChr = 0x2308;
        typeOper = HALF_SQUARE_LEFT_UPPER;

        operator = new CHalfSquareBracket();
        prp =
        {
            location:   location,
            turn:       TURN_MIRROR_0
        };
        operator.init(prp);
    }
    else if(code === 0x2309 || type == HALF_SQUARE_RIGHT_UPPER)
    {
        codeChr = 0x2309;
        typeOper = HALF_SQUARE_RIGHT_UPPER;

        operator = new CHalfSquareBracket();
        prp =
        {
            location:   location,
            turn:       TURN_MIRROR_180
        };
        operator.init(prp);
    }
    else if(code === 0x2016 || type == DELIMITER_DOUBLE_LINE)
    {
        codeChr = 0x2016;
        typeOper = DELIMITER_DOUBLE_LINE;

        operator = new COperatorDoubleLine();
        prp =
        {
            location:   location,
            turn:       TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x27E6 || type == WHITE_SQUARE_LEFT)
    {
        codeChr = 0x27E6;
        typeOper = WHITE_SQUARE_LEFT;

        operator = new CWhiteSquareBracket();
        prp =
        {
            location:   location,
            turn:       TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x27E7 || type == WHITE_SQUARE_RIGHT)
    {
        codeChr = 0x27E7;
        typeOper = WHITE_SQUARE_RIGHT;

        operator = new CWhiteSquareBracket();
        prp =
        {
            location:   location,
            turn:       TURN_180
        };
        operator.init(prp);
    }
    else if(type === OPERATOR_EMPTY)
    {
        typeOper = OPERATOR_EMPTY;
        operator = -1;
    }

    //////////////////////////////////////////

    ////////////     accents     /////////////

    /////// only arrows /////

    else if(code === 0x20D6 || type === ACCENT_ARROW_LEFT)
    {
        codeChr = 0x20D6;
        typeOper = ACCENT_ARROW_LEFT;

        operator = new CCombiningArrow();
        prp =
        {
            location:   LOCATION_TOP,
            turn:       TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x20D7 || type === ACCENT_ARROW_RIGHT)
    {
        typeOper = ACCENT_ARROW_RIGHT;
        codeChr = 0x20D7;

        operator = new CCombiningArrow();
        prp =
        {
            location:   LOCATION_TOP,
            turn:       TURN_180
        };
        operator.init(prp);
    }
    else if(code === 0x20E1 || type === ACCENT_ARROW_LR)
    {
        typeOper = ACCENT_ARROW_LR;
        codeChr = 0x20E1;

        operator = new CCombining_LR_Arrow();
        prp =
        {
            location:   LOCATION_TOP,
            turn:       TURN_0
        };

        operator.init(prp);
    }
    else if(code === 0x20D0 || type === ACCENT_HALF_ARROW_LEFT)
    {
        typeOper = ACCENT_HALF_ARROW_LEFT;
        codeChr = 0x20D0;

        operator = new CCombiningHalfArrow();
        prp =
        {
            location:   LOCATION_TOP,
            turn:       TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x20D1 || type ===  ACCENT_HALF_ARROW_RIGHT)
    {
        typeOper = ACCENT_HALF_ARROW_RIGHT;
        codeChr = 0x20D1;

        operator = new CCombiningHalfArrow();
        prp =
        {
            location:   LOCATION_TOP,
            turn:       TURN_180
        };
        operator.init(prp);
    }

    ///////////////////////////////

    else if(code === 0x302 || type === ACCENT_CIRCUMFLEX)
    {
        typeOper = ACCENT_CIRCUMFLEX;
        codeChr = 0x302;

        //operator = new CCircumflex();
        operator = new CAccentCircumflex();

        prp =
        {
            location:   LOCATION_TOP,
            turn:       TURN_MIRROR_0,
            bStretch:   false

        };
        operator.init(prp);

    }
    else if(code === 0x30C || type === ACCENT_COMB_CARON)
    {
        typeOper = ACCENT_COMB_CARON;
        codeChr = 0x30C;

        operator = new CAccentCircumflex();
        prp =
        {
            location:   LOCATION_TOP,
            turn:   TURN_0,
            bStretch:   false
        };
        operator.init(prp);

    }
    else if(code === 0x305 || type === ACCENT_LINE)
    {
        typeOper = ACCENT_LINE;
        codeChr = 0x305;

        operator = new CAccentLine();
        prp =
        {
            location:   LOCATION_TOP,
            turn:   TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x33F || type === ACCENT_DOUBLE_LINE)
    {
        typeOper = ACCENT_DOUBLE_LINE;
        codeChr = 0x33F;

        operator = new CAccentDoubleLine();
        prp =
        {
            location:   LOCATION_TOP,
            turn:   TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x303 || type === ACCENT_TILDE)
    {
        typeOper = ACCENT_TILDE;
        codeChr = 0x303;

        operator = new CAccentTilde();
        prp =
        {
            location:   LOCATION_TOP,
            turn:   TURN_0,
            bStretch:   false
        };
        operator.init(prp);
    }
    else if(code === 0x306 || type === ACCENT_BREVE)
    {
        typeOper = ACCENT_BREVE;
        codeChr = 0x306;

        operator = new CAccentBreve();
        prp =
        {
            location:   LOCATION_TOP,
            turn:   TURN_MIRROR_0,
            bStretch:   false
        };
        operator.init(prp);

    }
    else if(code == 0x311 || type == ACCENT_INVERT_BREVE)
    {
        typeOper = ACCENT_INVERT_BREVE;
        codeChr = 0x311;

        operator = new CAccentBreve();
        prp =
        {
            location:   LOCATION_TOP,
            turn:   TURN_0,
            bStretch:   false
        };
        operator.init(prp);

    }

    //////////////////////////////////////////////////////

    /*else if(code === 0x302 || type === ACCENT_CIRCUMFLEX)
     {
     typeOper = ACCENT_CIRCUMFLEX;
     codeChr = 0x302;

     operator = new CCircumflex();
     var props =
     {
     turn:   TURN_0
     };
     operator.init(props);
     }
     else if(code === 0x30C || type === ACCENT_COMB_CARON)
     {
     typeOper = ACCENT_COMB_CARON;
     codeChr = 0x30C;

     operator = new CCircumflex();
     var props =
     {
     turn:   TURN_MIRROR_0
     };
     operator.init(props);
     }
     else if(code === 0x332 || type === ACCENT_LINE)
     {
     typeOper = ACCENT_LINE;
     codeChr = 0x332;

     operator = new CLine();
     }
     else if(code === 0x333 || type === ACCENT_DOUBLE_LINE)
     {
     typeOper = ACCENT_DOUBLE_LINE;
     codeChr = 0x333;

     operator = new CDoubleLine();

     }
     else if(code === 0x303 || type === ACCENT_TILDE)
     {
     typeOper = ACCENT_TILDE;
     codeChr = 0x303;

     operator = new CTilde();
     }
     else if(code === 0x306 || type === ACCENT_BREVE)
     {
     typeOper = ACCENT_BREVE;
     codeChr = 0x306;

     operator = new CBreve();
     var props =
     {
     turn:   TURN_MIRROR_0
     };
     operator.init(props);
     }
     else if(code == 0x311 || type == ACCENT_INVERT_BREVE)
     {
     typeOper = ACCENT_INVERT_BREVE;
     codeChr = 0x311;

     operator = new CBreve();
     var props =
     {
     turn:   TURN_0
     };
     operator.init(props);
     }
     else if(code === 0x20D6 || type === ACCENT_ARROW_LEFT)
     {
     typeOper = ACCENT_ARROW_LEFT;
     codeChr = 0x20D6;

     operator = new CCombiningArrow();
     var props =
     {
     location:   LOCATION_TOP,
     turn:       TURN_0
     };
     operator.init(props);
     }
     else if(code === 0x20D7 || type === ACCENT_ARROW_RIGHT)
     {
     typeOper = ACCENT_ARROW_RIGHT;
     codeChr = 0x20D7;

     operator = new CCombiningArrow();
     var props =
     {
     location:   LOCATION_TOP,
     turn:       TURN_180
     };
     operator.init(props);
     }
     else if(code === 0x20E1 || type === ACCENT_ARROW_LR)
     {
     typeOper = ACCENT_ARROW_LR;
     codeChr = 0x20E1;

     operator = new CCombining_LR_Arrow();
     var props =
     {
     location:   LOCATION_TOP,
     turn:       TURN_0
     };
     operator.init(props);
     }
     else if(code === 0x20D0 || type === ACCENT_HALF_ARROW_LEFT)
     {
     typeOper = ACCENT_HALF_ARROW_LEFT;
     codeChr = 0x20D0;

     operator = new CCombiningHalfArrow();
     var props =
     {
     location:   LOCATION_TOP,
     turn:       TURN_0
     };
     operator.init(props);
     }
     else if(code === 0x20D1 || type ===  ACCENT_HALF_ARROW_RIGHT)
     {
     typeOper = ACCENT_HALF_ARROW_RIGHT;
     codeChr = 0x20D1;

     operator = new CCombiningHalfArrow();
     var props =
     {
     location:   LOCATION_TOP,
     turn:       TURN_180
     };
     operator.init(props);
     }*/

    //////////////////////////////////////////

    //////////   group characters   //////////

    else if(code === 0x23DE || type == BRACKET_CURLY_TOP)
    {
        codeChr = 0x23DE;
        typeOper = BRACKET_CURLY_TOP;

        operator = new COperatorBracket();
        prp =
        {
            location:   location,
            turn:       TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x23DF || type === BRACKET_CURLY_BOTTOM)
    {
        codeChr =  0x23DF;
        typeOper = BRACKET_CURLY_BOTTOM;

        operator = new COperatorBracket();
        prp =
        {
            location:   location,
            turn:       TURN_MIRROR_0
        };
        operator.init(prp);
    }
    else if(code === 0x23DC || type === PARENTHESIS_TOP)
    {
        codeChr = 0x23DC;
        typeOper = PARENTHESIS_TOP;

        operator = new COperatorParenthesis();
        prp =
        {
            location:   location,
            turn:       TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x23DD || type === PARENTHESIS_BOTTOM)
    {
        codeChr = 0x23DD;
        typeOper = PARENTHESIS_BOTTOM;

        operator = new COperatorParenthesis();
        prp =
        {
            location:   location,
            turn:       TURN_MIRROR_0
        };
        operator.init(prp);
    }
    else if(code === 0x23E0 || type === BRACKET_SQUARE_TOP)
    {
        codeChr = 0x23E0;
        typeOper = BRACKET_SQUARE_TOP;

        operator = new CSquareBracket();
        prp =
        {
            location:   location,
            turn:       TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x2190 || type === ARROW_LEFT)
    {
        codeChr =  0x2190;
        typeOper = ARROW_LEFT;

        operator = new CSingleArrow();

        prp =
        {
            location:   location,
            turn:       TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x2192 || type === ARROW_RIGHT)
    {
        codeChr =  0x2192;
        typeOper = ARROW_RIGHT;

        operator = new CSingleArrow();
        prp =
        {
            location:   location,
            turn:       TURN_180
        };
        operator.init(prp);
    }
    else if(code === 0x2194 || type === ARROW_LR)
    {
        codeChr =  0x2194;
        typeOper = ARROW_LR;

        operator = new CLeftRightArrow();
        prp =
        {
            location:   location,
            turn:       TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x21D0 || type === DOUBLE_LEFT_ARROW)
    {
        codeChr =  0x21D0;
        typeOper = DOUBLE_LEFT_ARROW;

        operator = new CDoubleArrow();
        prp =
        {
            location:   location,
            turn:       TURN_0
        };
        operator.init(prp);
    }
    else if(code === 0x21D2 || type === DOUBLE_RIGHT_ARROW)
    {
        codeChr =  0x21D2;
        typeOper = DOUBLE_RIGHT_ARROW;

        operator = new CDoubleArrow();
        prp =
        {
            location:   location,
            turn:       TURN_180
        };
        operator.init(prp);
    }
    else if(code === 0x21D4 || type === DOUBLE_ARROW_LR)
    {
        codeChr =  0x21D4;
        typeOper = DOUBLE_ARROW_LR;

        operator = new CLR_DoubleArrow();
        prp =
        {
            location:   location,
            turn:       TURN_0
        };
        operator.init(prp);
    }

    //////////////////////////////////////////////////////

    else if(code !== null)
    {
        codeChr  = code;
        typeOper = OPERATOR_TEXT;

        operator = new CMathText(true);
        operator.add(code);
    }
    else
        operator = -1;

    this.operator = operator;
    this.code = codeChr;
    this.typeOper = typeOper;
};
COperator.prototype.getProps = function(props, defaultProps)
{
    var location = props.loc,
        chr = props.chr,
        type = props.type;

    var code = props.chr;

    this.defaultType = defaultProps.type;

    var bDelimiter  = this.type == OPER_DELIMITER || this.type == OPER_SEPARATOR,
        bNotType    = props.type === undefined ||  props.type === null,
        bUnicodeChr = props.chr !== null && props.chr+0 === props.chr;


    if(bDelimiter && props.chr == -1) // empty operator
    {
        type = OPERATOR_EMPTY;
    }
    else if(bNotType && !bUnicodeChr)   // default operator
    {
        type = defaultProps.type;
    }

    var bLoc        = props.loc !== null && props.loc !== undefined;
    var bDefaultLoc = defaultProps.loc !== null && defaultProps.loc !==  undefined;


    if(!bLoc && bDefaultLoc)
        location = defaultProps.loc;

    return  {loc: location, type: type, code: code};
};
COperator.prototype.draw = function(x, y, pGraphics, PDSE)
{
    var XX = this.pos.x + x,
        YY = this.pos.y + y;

    if(this.typeOper === OPERATOR_TEXT)
    {
        this.drawText(x, y, pGraphics, PDSE);
    }
    else if(this.IsLineGlyph())
    {
        this.drawLines(XX, YY, pGraphics, PDSE);
    }
    else
    {
        this.drawOperator(XX, YY, pGraphics, PDSE);
    }
};
COperator.prototype.setPosition = function(_pos)
{
    this.pos.x = _pos.x;
    this.pos.y = _pos.y;

    if(this.typeOper === OPERATOR_TEXT)
    {
        this.operator.setPosition(_pos);
    }
};
COperator.prototype.Make_ShdColor = function(PDSE)
{
    return this.Parent.Make_ShdColor(PDSE, this.Parent.Get_CompiledCtrPrp());
};
COperator.prototype.drawText = function(absX, absY, pGraphics, PDSE)
{
    this.Make_ShdColor(PDSE);

    var ctrPrp =  this.Get_TxtPrControlLetter();

    var Font =
    {
        FontSize:   ctrPrp.FontSize,
        FontFamily: {Name : ctrPrp.FontFamily.Name, Index : ctrPrp.FontFamily.Index},
        Italic:     false,
        Bold:       false
    };

    pGraphics.SetFont(Font);

    ////////////////////////////////////////////////

    this.operator.Draw(absX, absY, pGraphics, PDSE);
};
COperator.prototype.drawOperator = function(absX, absY, pGraphics, PDSE)
{
    if(this.typeOper !== OPERATOR_EMPTY)
    {
        var lng = this.coordGlyph.XX.length;

        var X = [],
            Y = [];

        for(var j = 0; j < lng; j++)
        {
            X.push(absX + this.coordGlyph.XX[j]);
            Y.push(absY + this.coordGlyph.YY[j]);
        }

        this.operator.draw(pGraphics, X, Y, PDSE);
    }
};
COperator.prototype.drawLines = function(absX, absY, pGraphics, PDSE)
{
    if(this.typeOper !== OPERATOR_EMPTY)
    {
        this.operator.drawOnlyLines(absX, absY, pGraphics, PDSE);
    }
};
COperator.prototype.IsLineGlyph = function()
{
    return this.typeOper == ACCENT_LINE || this.typeOper == ACCENT_DOUBLE_LINE;
};
COperator.prototype.fixSize = function(oMeasure, stretch)
{
    if(this.typeOper !== OPERATOR_EMPTY)
    {
        var width, height, ascent;
        var dims;

        var ctrPrp =  this.Get_TxtPrControlLetter();

        var Font =
        {
            FontSize:   ctrPrp.FontSize,
            FontFamily: {Name : ctrPrp.FontFamily.Name, Index : ctrPrp.FontFamily.Index},
            Italic:     false,
            Bold:       false //ctrPrp.Bold
        };

        oMeasure.SetFont(Font);

        var bLine = this.IsLineGlyph();

        var bTopBot = this.operator.loc == LOCATION_TOP || this.operator.loc == LOCATION_BOT;

        // Width
        if(this.typeOper == OPERATOR_TEXT) // отдельный случай для текста в качестве оператора
        {
            this.operator.Measure(oMeasure, ctrPrp);
            width  = this.operator.size.width;
        }
        else
        {
            if(bLine)
            {
                this.operator.fixSize(stretch);
                width = this.operator.size.width;
            }
            else
            {
                var bNotStretchDelim = (this.type == OPER_DELIMITER || this.type == OPER_SEPARATOR) && this.grow == false;

                var StretchLng = bNotStretchDelim ? 0 : stretch;

                this.operator.fixSize(StretchLng);
                dims = this.operator.getCoordinateGlyph();
                this.coordGlyph = {XX: dims.XX, YY: dims.YY};

                width = bTopBot ? dims.Width : this.operator.size.width;
            }
        }

        var mgCtrPrp = this.Parent.Get_TxtPrControlLetter();
        var shCenter = this.ParaMath.GetShiftCenter(oMeasure, mgCtrPrp);

        // Height, Ascent

        if(this.type === OPER_ACCENT)
        {
            var letterOperator = new CMathText(true);
            letterOperator.add(this.code);
            letterOperator.Measure(oMeasure, ctrPrp);

            var letterX = new CMathText(true);
            letterX.add(0x78);
            letterX.Measure(oMeasure, ctrPrp);

            height = letterOperator.size.ascent - letterX.size.ascent;

            ascent = height/2 + shCenter;

        }
        else
        {
            if(this.typeOper == OPERATOR_TEXT)
                height = this.operator.size.height;
            else
            {
                if(bTopBot)
                    height = this.operator.size.height;
                else
                    height = dims.Height;
            }

            if(!bLine && this.operator.loc == LOCATION_TOP)
                ascent = dims.Height;
            else if(!bLine && this.operator.loc == LOCATION_BOT)
                ascent = this.operator.size.height;
            else
                ascent = height/2 + shCenter;
        }



        this.size.width  = width;
        this.size.height = height;
        this.size.ascent = ascent;
    }
};
COperator.prototype.IsJustDraw = function()
{
    return true;
};
COperator.prototype.Resize = function(oMeasure)
{
    if(this.typeOper !== OPERATOR_EMPTY)
    {
        var bHor = this.operator.loc == LOCATION_TOP || this.operator.loc  == LOCATION_BOT;

        if(bHor)
            this.fixSize(oMeasure, this.size.width);
        else
            this.fixSize(oMeasure, this.size.height);
    }
};
COperator.prototype.PreRecalc = function(Parent, ParaMath)
{
    this.Parent   = Parent;
    this.ParaMath = ParaMath;
    if(this.typeOper !== OPERATOR_EMPTY)
        this.operator.PreRecalc(this); // в данном случае mathText нужен только один параметр
};
COperator.prototype.Get_TxtPrControlLetter = function()
{
    return this.Parent.Get_TxtPrControlLetter();
};
COperator.prototype.Is_Empty = function()
{
    return this.typeOper == OPERATOR_EMPTY;
};
COperator.prototype.Get_CodeChr = function()
{
    /*var chr = null; //если operator не определен, то this.code = null

    if(this.code !== null)
        chr = this.typeOper === this.defaultType ? null : String.fromCharCode(this.code);
	if (this.operator == OPERATOR_EMPTY)
		chr = "";*/

    return this.code;
};
COperator.prototype.Get_Type = function()
{
    return this.typeOper;
};
COperator.prototype.IsArrow = function()
{
    //return this.operator.IsArrow();

    var bArrow = this.typeOper == ARROW_LEFT || this.typeOper == ARROW_RIGHT || this.typeOper == ARROW_LR,
        bDoubleArrow = this.typeOper == DOUBLE_LEFT_ARROW || this.typeOper == DOUBLE_RIGHT_ARROW || this.typeOper == DOUBLE_ARROW_LR,
        bAccentArrow = this.typeOper == ACCENT_ARROW_LEFT || this.typeOper == ACCENT_ARROW_RIGHT || this.typeOper == ACCENT_ARROW_LR || this.typeOper == ACCENT_HALF_ARROW_LEFT || this.typeOper == ACCENT_HALF_ARROW_RIGHT;

    return bArrow || bDoubleArrow;
};

function CMathDelimiterPr()
{
    this.begChr     = undefined;
    this.begChrType = undefined;
    this.endChr     = undefined;
    this.endChrType = undefined;
    this.sepChr     = undefined;
    this.sepChrType = undefined;
    this.shp        = DELIMITER_SHAPE_CENTERED;
    this.grow       = true;

    this.column     = 0;
}

CMathDelimiterPr.prototype.Set_Column = function(Value)
{
    this.column = Value;
};

CMathDelimiterPr.prototype.Set_FromObject = function(Obj)
{
    this.begChr     = Obj.begChr;
    this.begChrType = Obj.begChrType;
    this.endChr     = Obj.endChr;
    this.endChrType = Obj.endChrType;
    this.sepChr     = Obj.sepChr;
    this.sepChrType = Obj.sepChrType;

    if(DELIMITER_SHAPE_MATCH === Obj.shp || DELIMITER_SHAPE_CENTERED === Obj.shp)
        this.shp = Obj.shp;

    if(false === Obj.grow || 0 === Obj.grow)
        this.grow = false;

    if(undefined !== Obj.column && null !== Obj.column)
        this.column = Obj.column;
    else
        this.column = 1;
};

CMathDelimiterPr.prototype.Copy = function()
{
    var NewPr = new CMathDelimiterPr();

    NewPr.begChr     = this.begChr    ;
    NewPr.begChrType = this.begChrType;
    NewPr.endChr     = this.endChr    ;
    NewPr.endChrType = this.endChrType;
    NewPr.sepChr     = this.sepChr    ;
    NewPr.sepChrType = this.sepChrType;
    NewPr.shp        = this.shp       ;
    NewPr.grow       = this.grow      ;
    NewPr.column     = this.column    ;

    return NewPr;
};

CMathDelimiterPr.prototype.Write_ToBinary = function(Writer)
{
    // Long : Flag

    // Long : begChr
    // Long : begChrType
    // Long : endChr
    // Long : endChrType
    // Long : sepChr
    // Long : sepChrType

    // Long : shp
    // Bool : grow
    // Long : column

    var StartPos = Writer.GetCurPosition();
    Writer.Skip(4);
    var Flags = 0;

    if (undefined !== this.begChr && this.begChr !== null)
    {
        Writer.WriteLong(this.begChr);
        Flags |= 1;
    }

    if (undefined !== this.begChrType && this.begChrType !== null)
    {
        Writer.WriteLong(this.begChrType);
        Flags |= 2;
    }

    if (undefined !== this.endChr && this.endChr !== null)
    {
        Writer.WriteLong(this.endChr);
        Flags |= 4;
    }

    if (undefined !== this.endChrType && this.endChrType !== null)
    {
        Writer.WriteLong(this.endChrType);
        Flags |= 8;
    }

    if (undefined !== this.sepChr && this.sepChr !== null)
    {
        Writer.WriteLong(this.sepChr);
        Flags |= 16;
    }

    if (undefined !== this.sepChrType && this.sepChrType !== null)
    {
        Writer.WriteLong(this.sepChrType);
        Flags |= 32;
    }

    var EndPos = Writer.GetCurPosition();
    Writer.Seek(StartPos);
    Writer.WriteLong(Flags);
    Writer.Seek(EndPos);

    Writer.WriteLong(this.shp);
    Writer.WriteBool(this.grow);
    Writer.WriteLong(this.column);
};

CMathDelimiterPr.prototype.Read_FromBinary = function(Reader)
{
    // Long : Flags

    // Long : begChr
    // Long : begChrType
    // Long : endChr
    // Long : endChrType
    // Long : sepChr
    // Long : sepChrType

    // Long : shp
    // Bool : grow
    // Long : column

    var Flags = Reader.GetLong();

    if (Flags & 1)
        this.begChr = Reader.GetLong();
    else
        this.begChr = undefined;

    if (Flags & 2)
        this.begChrType = Reader.GetLong();
    else
        this.begChrType = undefined;

    if (Flags & 4)
        this.endChr = Reader.GetLong();
    else
        this.endChr = undefined;

    if (Flags & 8)
        this.endChrType = Reader.GetLong();
    else
        this.endChrType = undefined;

    if (Flags & 16)
        this.sepChr = Reader.GetLong();
    else
        this.sepChr = undefined;

    if (Flags & 32)
        this.sepChrType = Reader.GetLong();
    else
        this.sepChrType = undefined;

    this.shp        = Reader.GetLong();
    this.grow       = Reader.GetBool();
    this.column     = Reader.GetLong();
};

/**
 *
 * @param props
 * @constructor
 * @extends {CMathBase}
 */
function CDelimiter(props)
{
	CMathBase.call(this);

	this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.GeneralMetrics = new CMathSize();

    this.begOper = new COperator (OPER_DELIMITER);
    this.endOper = new COperator (OPER_DELIMITER);
    this.sepOper = new COperator (OPER_SEPARATOR);

    this.Pr = new CMathDelimiterPr();
    this.TextInContent = true;

    if(props !== null && props !== undefined)
        this.init(props);

    AscCommon.g_oTableId.Add( this, this.Id );
}
CDelimiter.prototype = Object.create(CMathBase.prototype);
CDelimiter.prototype.constructor = CDelimiter;

CDelimiter.prototype.ClassType = AscDFH.historyitem_type_delimiter;
CDelimiter.prototype.kind      = MATH_DELIMITER;

CDelimiter.prototype.init = function(props)
{
    this.setProperties(props);

    this.Fill_LogicalContent(this.getColumnsCount());

    this.fillContent();
};
CDelimiter.prototype.getColumnsCount = function()
{
    return this.Pr.column;
};
CDelimiter.prototype.fillContent = function()
{
    this.NeedBreakContent(0);

    var nColumnsCount = this.Content.length;

    this.setDimension(1, nColumnsCount);

    for (var nIndex = 0; nIndex < nColumnsCount; nIndex++)
        this.elements[0][nIndex] = this.Content[nIndex];
};
CDelimiter.prototype.ApplyProperties = function(RPI)
{
    if(this.RecalcInfo.bProps == true)
    {
        var begPrp =
        {
            chr:    this.Pr.begChr,
            type:   this.Pr.begChrType,
            grow:   this.Pr.grow,
            loc:    LOCATION_LEFT
        };
        var begDefaultPrp =
        {
            type:  PARENTHESIS_LEFT,
            chr:   0x28
        };
        this.begOper.mergeProperties(begPrp, begDefaultPrp);

        var endPrp =
        {
            chr:    this.Pr.endChr,
            type:   this.Pr.endChrType,
            grow:   this.Pr.grow,
            loc:    LOCATION_RIGHT
        };
        var endDefaultPrp =
        {
            type:  PARENTHESIS_RIGHT,
            chr:  0x29
        };

        this.endOper.mergeProperties(endPrp, endDefaultPrp);

        var sepPrp =
        {
            chr:    this.Pr.sepChr,
            type:   this.Pr.sepChrType,
            grow:   this.Pr.grow,
            loc:    LOCATION_SEP
        };
        var sepDefaultPrp =
        {
            type:  DELIMITER_LINE,
            chr:  0x7C
        };

        if(this.Pr.column == 1 )
            sepPrp.type = OPERATOR_EMPTY;

        this.sepOper.mergeProperties(sepPrp, sepDefaultPrp);

        this.RecalcInfo.bProps = false;
    }
};
CDelimiter.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI, GapsInfo)
{
    this.ApplyProperties(RPI);

    this.begOper.PreRecalc(this, ParaMath);
    this.endOper.PreRecalc(this, ParaMath);
    this.sepOper.PreRecalc(this, ParaMath);

    CMathBase.prototype.PreRecalc.call(this, Parent, ParaMath, ArgSize, RPI, GapsInfo);
};
CDelimiter.prototype.Recalculate_Range = function(PRS, ParaPr, Depth)
{
    this.bOneLine = PRS.bMath_OneLine == true || this.Content.length > 1; // this.Content.length > 1 - несколько контентов, разделенные сепараторами

    if(this.bOneLine == false)
    {
        var CurLine  = PRS.Line - this.StartLine;
        var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range );
        var bContainCompareOper = PRS.bContainCompareOper;

        this.protected_AddRange(CurLine, CurRange);

        this.NumBreakContent = 0;

        var Content = this.Content[0];

        if(CurLine == 0 && CurRange == 0)
        {
            // посчитаем контент как одностроковый для вычисления размера скобок
            // далее будем считать объект как многостроковый на Recalculate_Range
            PRS.bMath_OneLine = true;

            var WordLen  = PRS.WordLen,
                SpaceLen = PRS.SpaceLen;

            //
            Content.Recalculate_Reset(PRS.Range, PRS.Line, PRS);

            Content.Recalculate_Range(PRS, ParaPr, Depth + 1);
            this.RecalculateGeneralSize(g_oTextMeasurer, Content.size.height, Content.size.ascent);

            // вычисляем до изменения PRS.WordLen
            this.BrGapLeft  = this.GapLeft  + this.begOper.size.width;
            this.BrGapRight = this.GapRight + this.endOper.size.width;

            PRS.WordLen  = WordLen + this.BrGapLeft;
            PRS.SpaceLen = SpaceLen;
        }
        PRS.bMath_OneLine = false;
        PRS.Update_CurPos(0, Depth);
        Content.Recalculate_Range(PRS, ParaPr, Depth + 1);

        if(PRS.NewRange == false)
        {
            PRS.WordLen += this.BrGapRight;
        }

        this.protected_FillRange(CurLine, CurRange, 0, 0);

        PRS.bMath_OneLine = false;
        PRS.bContainCompareOper = bContainCompareOper;
    }
    else
    {
        PRS.bMath_OneLine = true;
        this.NumBreakContent = -1;

        CMathBase.prototype.Recalculate_Range.call(this, PRS, ParaPr, Depth);

        this.BrGapLeft  = this.GapLeft  + this.begOper.size.width;
        this.BrGapRight = this.GapRight + this.endOper.size.width;
    }
};
CDelimiter.prototype.RecalculateMinMaxContentWidth = function(MinMax)
{
    this.BrGapLeft  = this.GapLeft  + this.begOper.size.width;
    this.BrGapRight = this.GapRight + this.endOper.size.width;

    CMathBase.prototype.RecalculateMinMaxContentWidth.call(this, MinMax);
};
CDelimiter.prototype.Is_EmptyGaps = function()
{
    var Height = g_oTextMeasurer.GetHeight();
    var result = this.GeneralMetrics.height < Height;

    return result;
};
CDelimiter.prototype.Recalculate_LineMetrics = function(PRS, ParaPr, _CurLine, _CurRange, ContentMetrics)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = (0 === CurLine ? _CurRange - this.StartRange : _CurRange);

    CMathBase.prototype.Recalculate_LineMetrics.call(this, PRS, ParaPr, _CurLine, _CurRange, ContentMetrics);

    if(CurLine == 0 && CurRange == 0)
    {
        var BegHeight  = this.begOper.size.height;
        var BegAscent  = this.GetAscentOperator(this.begOper),
            BegDescent =  BegHeight - BegAscent;

        if(PRS.LineAscent < BegAscent)
            PRS.LineAscent = BegAscent;

        if ( PRS.LineDescent < BegDescent )
            PRS.LineDescent = BegDescent;

        // метрики скобок не зависят от выравнивания внутренних объектов(например, матриц mbaseJc = top || mbaseJc = bottom )
        var Size_BeggingOper = new CMathSize();
        Size_BeggingOper.ascent = BegAscent;
        Size_BeggingOper.height = BegAscent + BegDescent;

        ContentMetrics.UpdateMetrics(Size_BeggingOper);
    }

    var bEnd = this.Content[0].Math_Is_End(_CurLine, _CurRange);

    if(bEnd)
    {
        var EndHeight  = this.endOper.size.height;
        var EndAscent  = this.GetAscentOperator(this.endOper),
            EndDescent =  EndHeight - EndAscent;

        if(PRS.LineAscent < EndAscent)
            PRS.LineAscent = EndAscent;

        if ( PRS.LineDescent < EndDescent )
            PRS.LineDescent = EndDescent;

        var Size_EndOper = new CMathSize();
        Size_EndOper.ascent = EndAscent;
        Size_EndOper.height = EndAscent + EndDescent;

        ContentMetrics.UpdateMetrics(Size_EndOper);
    }
};
CDelimiter.prototype.RecalculateGeneralSize = function(oMeasure, height, ascent) // здесь пересчитываем скобки, общий максимальный размер delimiters
{
    var descent = height - ascent;
    var mgCtrPrp = this.Get_TxtPrControlLetter();
    var ShCenter = this.ParaMath.GetShiftCenter(oMeasure, mgCtrPrp);
    var maxAD    = ascent - ShCenter  > descent + ShCenter ? ascent - ShCenter: descent + ShCenter;

    var plH = this.ParaMath.GetPlh(oMeasure, mgCtrPrp);
    this.TextInContent = ascent < 1.01*plH && descent < 0.4*plH; // для текста операторы в случае центрирования не увеличиваем

    var bCentered = this.Pr.shp == DELIMITER_SHAPE_CENTERED,
        b2Max = bCentered && (2*maxAD - height > 0.001);

    var heightStretch = b2Max && !this.TextInContent ? 2*maxAD : height;

    this.begOper.fixSize(oMeasure, heightStretch);
    this.endOper.fixSize(oMeasure, heightStretch);
    this.sepOper.fixSize(oMeasure, heightStretch);

    var HeigthMaxOper = Math.max(this.begOper.size.height, this.endOper.size.height, this.sepOper.size.height);
    var AscentMaxOper = HeigthMaxOper/2 + ShCenter;

    g_oTextMeasurer.SetFont(mgCtrPrp);
    var Height = g_oTextMeasurer.GetHeight();

    if(this.Pr.shp == DELIMITER_SHAPE_CENTERED)
    {
        var deltaHeight = height - HeigthMaxOper;
        if(deltaHeight < 0)
            deltaHeight = -deltaHeight;

        /*var deltaMaxAD = maxAD - HeigthMaxOper/2;
        if(deltaMaxAD < 0)
            deltaMaxAD = -deltaMaxAD;

        var deltaMinAD = (height - maxAD) - HeigthMaxOper/2;*/

        var bEqualOper = deltaHeight < 0.001,
            bLText = height < Height;

        var DimHeight, DimAscent;

        if(bEqualOper)
        {
            DimHeight = 2*maxAD;
            DimAscent = maxAD + ShCenter;
        }
        else if(bLText)
        {
            DimAscent = ascent > AscentMaxOper ? ascent : AscentMaxOper;
            DimHeight = HeigthMaxOper;
        }
        else // для случаев когда скобку можно расстянуть не по всей высоте (угловые скобки, аскент >> дескента)
        {
            DimHeight = HeigthMaxOper/2 + maxAD > height ? HeigthMaxOper/2 + maxAD : height;
            DimAscent = ascent > AscentMaxOper? ascent : AscentMaxOper;
        }
    }
    else
    {
        if(height < Height)
        {
            DimAscent = ascent > AscentMaxOper ? ascent : AscentMaxOper;
            DimHeight = HeigthMaxOper;
        }
        else
        {
            DimAscent = ascent;
            DimHeight = height;
        }
    }

    this.GeneralMetrics.ascent = DimAscent;
    this.GeneralMetrics.height = DimHeight;

};
CDelimiter.prototype.recalculateSize = function(oMeasure)
{
    // размеры аргумента
    var widthG = 0,
        ascentG = 0, descentG = 0;

    for(var j = 0; j < this.Pr.column; j++)
    {
        var content = this.elements[0][j].size;
        widthG += content.width;
        ascentG = content.ascent > ascentG ? content.ascent : ascentG;
        descentG = content.height - content.ascent > descentG ? content.height - content.ascent: descentG;
    }

    this.RecalculateGeneralSize(oMeasure, ascentG + descentG, ascentG);

    // Общая ширина
    var width = widthG + this.begOper.size.width + this.endOper.size.width + (this.Pr.column - 1)*this.sepOper.size.width;
    width += this.GapLeft + this.GapRight;


    this.size.ascent = this.GeneralMetrics.ascent;
    this.size.height = this.GeneralMetrics.height;

    this.size.width = width;
};
CDelimiter.prototype.GetAscentOperator = function(operator) // в качестве аргумента передаем высоту оператора
{
    var GeneralAscent = this.GeneralMetrics.ascent,
        GeneralHeight = this.GeneralMetrics.height;

    var OperHeight = operator.size.height,
        OperAscent = operator.size.ascent;

    var Ascent;

    if(this.Pr.shp == DELIMITER_SHAPE_CENTERED)
    {
        Ascent = OperAscent;
    }
    else
    {
        var shCenter = OperAscent - OperHeight/2; // так получаем shCenter, иначе соотношение м/ду ascent и descent будет неверное

        var k = (GeneralAscent - shCenter)/GeneralHeight;

        Ascent = (k*OperHeight + shCenter);
    }

    return Ascent;
};
CDelimiter.prototype.setPosition = function(pos, PosInfo)
{
    this.UpdatePosBound(pos, PosInfo);
    var Line  = PosInfo.CurLine,
        Range = PosInfo.CurRange;

    if(this.bOneLine == false)
    {
        var PosOper = new CMathPosition();

        if(true === this.IsStartRange(Line, Range))
        {
            PosOper.x = pos.x;
            PosOper.y = pos.y - this.begOper.size.ascent;

            this.UpdatePosOperBeg(pos, Line);
        }

        this.Content[0].setPosition(pos, PosInfo);

        // пересчет еще не закончился, поэтому на LastRange не можем проверить
        if(true === this.Content[0].Math_Is_End(Line, Range))
        {
            PosOper.x = pos.x;
            PosOper.y = pos.y - this.endOper.size.ascent;

            this.UpdatePosOperEnd(pos, Line);
        }
    }
    else
    {
        this.pos.x = pos.x;
        this.pos.y = pos.y - this.size.ascent;

        var CurrPos = new CMathPosition();
        CurrPos.x = pos.x;
        CurrPos.y = pos.y;

        this.UpdatePosOperBeg(CurrPos, Line);

        this.Content[0].setPosition(CurrPos, PosInfo); // CMathContent

        var PosSep = new CMathPosition();
        PosSep.x = CurrPos.x;
        //PosSep.y = CurrPos.y + this.alignOperator(this.sepOper, Line);
        PosSep.y = CurrPos.y - this.GetAscentOperator(this.sepOper);

        this.sepOper.setPosition(PosSep);

        for(var j = 1 ; j < this.Pr.column; j++)
        {
            CurrPos.x += this.sepOper.size.width;

            this.Content[j].setPosition(CurrPos, PosInfo);
            pos.x += this.Content[j].size.width;
        }

        this.UpdatePosOperEnd(CurrPos, Line);

        pos.x = CurrPos.x;
    }
};
CDelimiter.prototype.Draw_Elements = function(PDSE)
{
    var PosLine = this.ParaMath.GetLinePosition(PDSE.Line, PDSE.Range);

    if(this.bOneLine == false)
    {
        if(true === this.IsStartRange(PDSE.Line, PDSE.Range))
        {
            this.begOper.draw(PosLine.x, PosLine.y, PDSE.Graphics, PDSE);
            PDSE.X += this.BrGapLeft;
        }

        this.Content[0].Draw_Elements(PDSE);

        if(true === this.IsLastRange(PDSE.Line, PDSE.Range))
        {
            this.endOper.draw(PosLine.x, PosLine.y, PDSE.Graphics, PDSE);
            PDSE.X += this.BrGapRight;
        }
    }
    else
    {
        this.begOper.draw(PosLine.x, PosLine.y, PDSE.Graphics, PDSE);
        PDSE.X += this.BrGapLeft;

        this.Content[0].Draw_Elements(PDSE);

        var X = PosLine.x;

        for(var j = 1; j < this.Pr.column; j++)
        {
            this.sepOper.draw(X, PosLine.y, PDSE.Graphics, PDSE);

            PDSE.X += this.sepOper.size.width;
            this.Content[j].Draw_Elements(PDSE);

            X += this.sepOper.size.width + this.Content[j].size.width;
        }

        this.endOper.draw(PosLine.x, PosLine.y, PDSE.Graphics, PDSE);
        PDSE.X += this.BrGapRight;
    }
};
CDelimiter.prototype.UpdatePosOperBeg = function(pos, Line)
{
    var PosBegOper = new CMathPosition();
    PosBegOper.x = pos.x + this.GapLeft;
    //PosBegOper.y = pos.y + this.alignOperator(this.begOper, Line);
    PosBegOper.y = pos.y - this.GetAscentOperator(this.begOper);

    this.begOper.setPosition(PosBegOper);

    pos.x += this.BrGapLeft; // BrGapLeft = GapLeft + size of beginning Operator
};
CDelimiter.prototype.UpdatePosOperEnd = function(pos, Line)
{
    var PosEndOper = new CMathPosition();
    PosEndOper.x = pos.x;
    //PosEndOper.y = pos.y + this.alignOperator(this.endOper, Line);
    PosEndOper.y = pos.y - this.GetAscentOperator(this.endOper);

    this.endOper.setPosition(PosEndOper);

    pos.x += this.BrGapRight; // BrGapRight = GapRight + size of ending Operator
};
CDelimiter.prototype.getBase = function(numb)
{
    if(numb !== numb - 0)
        numb = 0;

    return this.elements[0][numb];
};
CDelimiter.prototype.getElementMathContent = function(Index)
{
    return this.Content[Index];
};
CDelimiter.prototype.Apply_MenuProps = function(Props)
{
	var NewContent;

	if (Props.Type == Asc.c_oAscMathInterfaceType.Delimiter)
	{
		if (Props.HideBegOper !== undefined && Props.HideBegOper !== this.begOper.Is_Empty())
		{
			var BegOper = this.private_GetLeftOperator(Props.HideBegOper);

			History.Add(new CChangesMathDelimBegOper(this, this.Pr.begChr, BegOper));
			this.raw_HideBegOperator(BegOper);
		}

		if (Props.HideEndOper !== undefined && Props.HideEndOper !== this.endOper.Is_Empty())
		{
			var EndOper = this.private_GetRightOperator(Props.HideEndOper);

			History.Add(new CChangesMathDelimEndOper(this, this.Pr.endChr, EndOper));
			this.raw_HideEndOperator(EndOper);
		}

		if (Props.Grow !== undefined && Props.Grow !== this.Pr.grow)
		{
			History.Add(new CChangesMathDelimiterGrow(this, this.Pr.grow, Props.Grow));
			this.raw_SetGrow(Props.Grow);
		}

		if (Props.MatchBrackets !== undefined && this.Pr.grow == true)
		{
			var Shp = Props.MatchBrackets == true ? DELIMITER_SHAPE_MATCH : DELIMITER_SHAPE_CENTERED;

			if (Shp !== this.Pr.shp)
			{
				History.Add(new CChangesMathDelimiterShape(this, this.Pr.shp, Shp));
				this.raw_SetShape(Shp);
			}
		}

		if (Props.Action & c_oMathMenuAction.DeleteDelimiterArgument)
		{
			if (this.Pr.column > 1)
			{
				History.Add(new CChangesMathDelimiterSetColumn(this, this.Pr.column, this.Pr.column - 1));
				this.raw_SetColumn(this.Pr.column - 1);

				this.protected_RemoveItems(this.CurPos, [this.Content[this.CurPos]], true);
			}
		}

		if (Props.Action & c_oMathMenuAction.InsertDelimiterArgument)
		{
			if (Props.Action & c_oMathMenuAction.InsertBefore)
			{
				History.Add(new CChangesMathDelimiterSetColumn(this, this.Pr.column, this.Pr.column + 1));
				this.raw_SetColumn(this.Pr.column + 1);

				NewContent = new CMathContent();
				NewContent.Correct_Content(true);
				this.protected_AddToContent(this.CurPos, [NewContent], true);
			}
			else
			{
				History.Add(new CChangesMathDelimiterSetColumn(this, this.Pr.column, this.Pr.column + 1));
				this.raw_SetColumn(this.Pr.column + 1);

				NewContent = new CMathContent();
				NewContent.Correct_Content(true);
				this.protected_AddToContent(this.CurPos + 1, [NewContent], true);
			}
		}
	}
};
CDelimiter.prototype.Get_InterfaceProps = function()
{
    return new CMathMenuDelimiter(this);
};
CDelimiter.prototype.raw_SetGrow = function(Value)
{
    this.Pr.grow = Value;
    this.RecalcInfo.bProps = true;
    this.ApplyProperties();
};
CDelimiter.prototype.raw_SetShape = function(Value)
{
    if(this.Pr.grow == true && (Value == DELIMITER_SHAPE_MATCH || Value == DELIMITER_SHAPE_CENTERED))
    {
        this.Pr.shp = Value;
        this.RecalcInfo.bProps = true;
        this.ApplyProperties();
    }
};
CDelimiter.prototype.raw_SetColumn = function(Value)
{
    if((this.Pr.column == 1 && Value > 1) || (Value == 1 && this.Pr.column > 1)) // выставим сепаратор
    {
        this.Pr.Set_Column(Value);
        this.sepOper = new COperator (OPER_SEPARATOR);
        this.RecalcInfo.bProps = true;
        this.ApplyProperties();
    }
    else
    {
        this.Pr.Set_Column(Value);
    }
};
CDelimiter.prototype.raw_HideBegOperator = function(Value)
{
    this.Pr.begChr = Value;
    this.begOper = new COperator (OPER_DELIMITER);
    this.RecalcInfo.bProps = true;
    this.ApplyProperties();
};
CDelimiter.prototype.raw_HideEndOperator = function(Value)
{
    this.Pr.endChr = Value;
    this.endOper = new COperator (OPER_DELIMITER);
    this.RecalcInfo.bProps = true;
    this.ApplyProperties();
};
CDelimiter.prototype.Get_DeletedItemsThroughInterface = function()
{
    var DeletedItems = null;

    if(this.Content.length > 0)
    {
        DeletedItems = this.Content[0].Content;

        for(var Pos = 1; Pos < this.Content.length; Pos++)
        {
            var NewSpace = new CMathText(false);
            NewSpace.add(0x20);

            var CtrPrp = this.Get_CtrPrp();
            var NewRun = new ParaRun(this.ParaMath.Paragraph, true);
            NewRun.Apply_Pr(CtrPrp);
            NewRun.ConcatToContent( [NewSpace] );

            DeletedItems = DeletedItems.concat(NewRun);

            var Items = this.Content[Pos].Content;
            DeletedItems = DeletedItems.concat(Items);
        }
    }

    return DeletedItems;
};
CDelimiter.prototype.GetLastElement = function()
{
    var Result;

    var IsEndOper = this.endOper.typeOper !== OPERATOR_EMPTY;
    var growLast  = IsEndOper && this.Pr.grow == true && this.TextInContent,
        smallLast = IsEndOper && this.Pr.grow == false;

    if(growLast || smallLast || this.endOper.typeOper == OPERATOR_TEXT)
    {
        Result = this.endOper;
    }
    else
        Result = this;

    return Result;
};
CDelimiter.prototype.GetFirstElement = function()
{
    var Result;

    var IsStrartOper = this.begOper.typeOper !== OPERATOR_EMPTY;
    var growLast  = IsStrartOper && this.Pr.grow == true && this.TextInContent,
        smallLast = IsStrartOper && this.Pr.grow == false;

    if(growLast || smallLast || this.begOper.typeOper == OPERATOR_TEXT)
    {
        Result = this.begOper;
    }
    else
        Result = this;

    return Result;
};
CDelimiter.prototype.private_GetLeftOperator = function(bHide)
{
    var NewBegCode = -1;

    if(bHide == true)
    {
        NewBegCode = -1;
    }
    else if(true == this.endOper.Is_Empty())
    {
        NewBegCode = 0x28; // PARENTHESIS_LEFT
    }
    else
    {
        var TypeEndOper = this.endOper.Get_Type();

        var bSymmetricDiffTwo = TypeEndOper == BRACKET_CURLY_RIGHT || TypeEndOper == BRACKET_SQUARE_RIGHT;
        var bSymmetricDiff    = TypeEndOper == PARENTHESIS_RIGHT || TypeEndOper == BRACKET_ANGLE_RIGHT || TypeEndOper == HALF_SQUARE_RIGHT || TypeEndOper == HALF_SQUARE_RIGHT_UPPER || TypeEndOper == WHITE_SQUARE_RIGHT;

        var EndCodeChr = this.endOper.Get_CodeChr();

        if(bSymmetricDiff)
        {
            NewBegCode = EndCodeChr - 1;
        }
        else if(bSymmetricDiffTwo)
        {
            NewBegCode = EndCodeChr - 2;
        }
        else
        {
            NewBegCode = EndCodeChr;
        }
    }

    return NewBegCode;
};
CDelimiter.prototype.private_GetRightOperator = function(bHide)
{
    var NewEndCode = -1;

    if(bHide == true)
    {
        NewEndCode = -1;
    }
    else if(true == this.begOper.Is_Empty())
    {
        NewEndCode = 0x29; // PARENTHESIS_RIGHT
    }
    else
    {
        var TypeBegOper = this.begOper.Get_Type();

        var bSymmetricDiffTwo = TypeBegOper == BRACKET_CURLY_LEFT || TypeBegOper == BRACKET_SQUARE_LEFT;
        var bSymmetricDiff    = TypeBegOper == PARENTHESIS_LEFT || TypeBegOper == BRACKET_ANGLE_LEFT || TypeBegOper == HALF_SQUARE_LEFT || TypeBegOper == HALF_SQUARE_LEFT_UPPER || TypeBegOper == WHITE_SQUARE_LEFT;

        var BegCodeChr = this.begOper.Get_CodeChr();

        if(bSymmetricDiff)
        {
            NewEndCode = BegCodeChr + 1;
        }
        else if(bSymmetricDiffTwo)
        {
            NewEndCode = BegCodeChr + 2;
        }
        else
        {
            NewEndCode = BegCodeChr;
        }
    }

    return NewEndCode;
};

/**
 *
 * @param CMathMenuDelimiter
 * @constructor
 * @extends {CMathMenuBase}
 */
function CMathMenuDelimiter(Delimiter)
{
	CMathMenuBase.call(this, Delimiter);

    this.Type         = Asc.c_oAscMathInterfaceType.Delimiter;

    if (Delimiter)
    {
        this.HideBegOper        = Delimiter.begOper.Is_Empty();
        this.HideEndOper        = Delimiter.endOper.Is_Empty();
        this.Grow               = Delimiter.Pr.grow;
        this.MatchBrackets      = Delimiter.Pr.shp == DELIMITER_SHAPE_MATCH;
        this.bSingleArgument    = Delimiter.Pr.column == 1;
    }
    else
    {
        this.HideBegOper        = undefined;
        this.HideEndOper        = undefined;
        this.Grow               = undefined;
        this.MatchBrackets       = undefined;
        this.bSingleArgument    = true;
    }
}
CMathMenuDelimiter.prototype = Object.create(CMathMenuBase.prototype);
CMathMenuDelimiter.prototype.constructor = CMathMenuDelimiter;
CMathMenuDelimiter.prototype.get_HideOpeningBracket = function(){return this.HideBegOper;};
CMathMenuDelimiter.prototype.put_HideOpeningBracket = function(Hide){this.HideBegOper = Hide;};
CMathMenuDelimiter.prototype.get_HideClosingBracket = function(){return this.HideEndOper;};
CMathMenuDelimiter.prototype.put_HideClosingBracket = function(Hide){this.HideEndOper = Hide;};
CMathMenuDelimiter.prototype.get_StretchBrackets    = function(){return this.Grow;};
CMathMenuDelimiter.prototype.put_StretchBrackets    = function(Stretch){this.Grow = Stretch;};
CMathMenuDelimiter.prototype.get_MatchBrackets      = function(){return this.MatchBrackets;};
CMathMenuDelimiter.prototype.put_MatchBrackets      = function(Match){this.MatchBrackets = Match;};
CMathMenuDelimiter.prototype.can_DeleteArgument     = function(){return this.bSingleArgument == false;};
CMathMenuDelimiter.prototype.has_Separators         = function(){return this.bSingleArgument == false;};

window["CMathMenuDelimiter"]                           = CMathMenuDelimiter;
CMathMenuDelimiter.prototype["get_HideOpeningBracket"] = CMathMenuDelimiter.prototype.get_HideOpeningBracket;
CMathMenuDelimiter.prototype["put_HideOpeningBracket"] = CMathMenuDelimiter.prototype.put_HideOpeningBracket;
CMathMenuDelimiter.prototype["get_HideClosingBracket"] = CMathMenuDelimiter.prototype.get_HideClosingBracket;
CMathMenuDelimiter.prototype["put_HideClosingBracket"] = CMathMenuDelimiter.prototype.put_HideClosingBracket;
CMathMenuDelimiter.prototype["get_StretchBrackets"]    = CMathMenuDelimiter.prototype.get_StretchBrackets;
CMathMenuDelimiter.prototype["put_StretchBrackets"]    = CMathMenuDelimiter.prototype.put_StretchBrackets;
CMathMenuDelimiter.prototype["get_MatchBrackets"]      = CMathMenuDelimiter.prototype.get_MatchBrackets;
CMathMenuDelimiter.prototype["put_MatchBrackets"]      = CMathMenuDelimiter.prototype.put_MatchBrackets;
CMathMenuDelimiter.prototype["can_DeleteArgument"]     = CMathMenuDelimiter.prototype.can_DeleteArgument;
CMathMenuDelimiter.prototype["has_Separators"]         = CMathMenuDelimiter.prototype.has_Separators;

/**
 *
 * @constructor
 * @extends {CMathBase}
 */
function CCharacter()
{
    this.operator = new COperator(OPER_GROUP_CHAR);
    CMathBase.call(this);
}
CCharacter.prototype = Object.create(CMathBase.prototype);
CCharacter.prototype.constructor = CCharacter;
CCharacter.prototype.setCharacter = function(props, defaultProps)
{
    this.operator.mergeProperties(props, defaultProps);
};
CCharacter.prototype.recalculateSize = function(oMeasure)
{
    var Base = this.elements[0][0];

    this.operator.fixSize(oMeasure, Base.size.width);

    var width  = Base.size.width > this.operator.size.width ? Base.size.width : this.operator.size.width,
        height = Base.size.height + this.operator.size.height,
        ascent = this.getAscent(oMeasure);

    width += this.GapLeft + this.GapRight;

    this.size.height = height;
    this.size.width  = width;
    this.size.ascent = ascent;
};
CCharacter.prototype.setPosition = function(pos, PosInfo)
{
    this.pos.x = pos.x;
    this.pos.y = pos.y - this.size.ascent;

    this.UpdatePosBound(pos, PosInfo);

    var width = this.size.width - this.GapLeft - this.GapRight;

    var alignOp  = (width - this.operator.size.width)/2,
        alignCnt = (width - this.elements[0][0].size.width)/2;

    var PosOper = new CMathPosition(),
        PosBase = new CMathPosition();

    var Base = this.elements[0][0];

    if(this.Pr.pos === LOCATION_TOP)
    {
        PosOper.x = this.pos.x + this.GapLeft + alignOp;
        PosOper.y = this.pos.y;

        PosBase.x = this.pos.x + this.GapLeft + alignCnt;
        PosBase.y = this.pos.y + this.operator.size.height;

    }
    else if(this.Pr.pos === LOCATION_BOT)
    {
        PosBase.x = this.pos.x + this.GapLeft + alignCnt;
        PosBase.y = this.pos.y;

        //Base.setPosition(PosBase, PosInfo);

        PosOper.x = this.pos.x + this.GapLeft + alignOp;
        PosOper.y = this.pos.y + Base.size.height;

        //this.operator.setPosition(PosOper);
    }

    this.operator.setPosition(PosOper);

    if(Base.Type == para_Math_Content)
        PosBase.y += Base.size.ascent;

    Base.setPosition(PosBase, PosInfo);

    pos.x += this.size.width;
};
CCharacter.prototype.Draw_Elements = function(PDSE)
{
    var X = PDSE.X;

    this.Content[0].Draw_Elements(PDSE);

    var ctrPrp =  this.Get_TxtPrControlLetter();

    var Font =
    {
        FontSize:   ctrPrp.FontSize,
        FontFamily: {Name : ctrPrp.FontFamily.Name, Index : ctrPrp.FontFamily.Index},
        Italic:     false,
        Bold:       false
    };


    PDSE.Graphics.SetFont(Font);

    var PosLine = this.ParaMath.GetLinePosition(PDSE.Line, PDSE.Range);

    this.operator.draw(PosLine.x, PosLine.y, PDSE.Graphics, PDSE);

    PDSE.X = X + this.size.width;
};
CCharacter.prototype.getBase = function()
{
    return this.elements[0][0];
};

function CMathGroupChrPr()
{
    this.chr     = undefined;
    this.chrType = undefined;
    this.pos     = LOCATION_BOT;
    this.vertJc  = VJUST_TOP;

}
CMathGroupChrPr.prototype.Set = function(Pr)
{
    this.chr     = Pr.chr;
    this.chrType = Pr.chrType;
    this.pos     = Pr.pos;
    this.vertJc  = Pr.vertJc;
};
CMathGroupChrPr.prototype.Set_FromObject = function(Obj)
{
    this.chr     = Obj.chr;
    this.chrType = Obj.chrType;

    if(VJUST_TOP === Obj.vertJc || VJUST_BOT === Obj.vertJc)
        this.vertJc = Obj.vertJc;

    if(LOCATION_TOP === Obj.pos || LOCATION_BOT === Obj.pos)
        this.pos = Obj.pos;
};
CMathGroupChrPr.prototype.Copy = function()
{
    var NewPr = new CMathGroupChrPr();

    NewPr.chr     = this.chr    ;
    NewPr.chrType = this.chrType;
    NewPr.vertJc  = this.vertJc ;
    NewPr.pos     = this.pos    ;

    return NewPr;
};
CMathGroupChrPr.prototype.Write_ToBinary = function(Writer)
{
    // Long : Flag

    // Long : chr
    // Long : chrType

    // Long : vertJc
    // Long : pos

    var StartPos = Writer.GetCurPosition();
    Writer.Skip(4);
    var Flags = 0;

    if (undefined !== this.chr)
    {
        Writer.WriteLong(this.chr);
        Flags |= 1;
    }

    if (undefined !== this.chrType)
    {
        Writer.WriteLong(this.chrType);
        Flags |= 2;
    }

    var EndPos = Writer.GetCurPosition();
    Writer.Seek(StartPos);
    Writer.WriteLong(Flags);
    Writer.Seek(EndPos);

    Writer.WriteLong(this.vertJc);
    Writer.WriteLong(this.pos);
};
CMathGroupChrPr.prototype.Read_FromBinary = function(Reader)
{
    // Long : Flag

    // Long : chr
    // Long : chrType

    // Long : vertJc
    // Long : pos

    var Flags = Reader.GetLong();

    if (Flags & 1)
        this.chr = Reader.GetLong();
    else
        this.chr = undefined;

    if (Flags & 2)
        this.chrType = Reader.GetLong();
    else
        this.chrType = undefined;

    this.vertJc  = Reader.GetLong();
    this.pos     = Reader.GetLong();
};

/**
 *
 * @param props
 * @constructor
 * @extends {CCharacter}
 */
function CGroupCharacter(props)
{
	CCharacter.call(this);

	this.Id   = AscCommon.g_oIdCounter.Get_NewId();

    this.Pr = new CMathGroupChrPr();

    if(props !== null && props !== undefined)
        this.init(props);

    /// вызов этой функции обязательно в конце
    AscCommon.g_oTableId.Add( this, this.Id );
}
CGroupCharacter.prototype = Object.create(CCharacter.prototype);
CGroupCharacter.prototype.constructor = CGroupCharacter;
CGroupCharacter.prototype.ClassType = AscDFH.historyitem_type_groupChr;
CGroupCharacter.prototype.kind      = MATH_GROUP_CHARACTER;
CGroupCharacter.prototype.init = function(props)
{
    this.Fill_LogicalContent(1);

    this.setProperties(props);
    this.fillContent();
};
CGroupCharacter.prototype.ApplyProperties = function(RPI)
{
    if(this.RecalcInfo.bProps == true)
    {
        var operDefaultPrp =
        {
            type:   BRACKET_CURLY_BOTTOM,
            loc:    LOCATION_BOT
        };

        var operProps =
        {
            type:   this.Pr.chrType,
            chr:    this.Pr.chr,
            loc:    this.Pr.pos
        };

        this.setCharacter(operProps, operDefaultPrp);

        this.RecalcInfo.bProps = false;

        if(this.Pr.pos == this.Pr.vertJc)
        {
            var Iterator;

            if(this.Pr.pos == LOCATION_TOP)
                Iterator = new CDenominator(this.getBase());
            else
                Iterator = new CNumerator(this.getBase());

            this.elements[0][0] = Iterator;
        }
        else
            this.elements[0][0] = this.getBase();

    }
};
CGroupCharacter.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI, GapsInfo)
{
    this.ApplyProperties(RPI);

    this.operator.PreRecalc(this, ParaMath);

    var ArgSz = ArgSize.Copy();

    if(this.Pr.pos == this.Pr.vertJc)
        ArgSz.Decrease();

	CCharacter.prototype.PreRecalc.call(this, Parent, ParaMath, ArgSz, RPI, GapsInfo);
};
CGroupCharacter.prototype.getBase = function()
{
    return this.Content[0];
};
CGroupCharacter.prototype.fillContent = function()
{
    this.setDimension(1, 1);
    this.elements[0][0] = this.getBase();
};
CGroupCharacter.prototype.getAscent = function(oMeasure)
{
    var ascent;

    var ctrPrp = this.Get_TxtPrControlLetter();
    var shCent = this.ParaMath.GetShiftCenter(oMeasure, ctrPrp);

    if(this.Pr.vertJc === VJUST_TOP && this.Pr.pos === LOCATION_TOP)
        ascent =  this.operator.size.ascent;
    else if(this.Pr.vertJc === VJUST_BOT && this.Pr.pos === LOCATION_TOP )
        ascent = this.operator.size.height + this.elements[0][0].size.ascent;
    else if(this.Pr.vertJc === VJUST_TOP && this.Pr.pos === LOCATION_BOT )
        ascent = this.elements[0][0].size.ascent;
    else if(this.Pr.vertJc === VJUST_BOT && this.Pr.pos === LOCATION_BOT )
        ascent = this.elements[0][0].size.height + this.operator.size.height;

    return ascent;
};
CGroupCharacter.prototype.Apply_MenuProps = function(Props)
{
    if(Props.Type == Asc.c_oAscMathInterfaceType.GroupChar)
    {
        if(Props.Pos !== undefined && true == this.Can_ChangePos())
        {
            var Pos = Props.Pos == Asc.c_oAscMathInterfaceGroupCharPos.Bottom ? LOCATION_BOT : LOCATION_TOP;

            if(Pos !== this.Pr.pos)
                this.private_InversePr();
        }
    }
};
CGroupCharacter.prototype.private_GetInversePr = function(Pr)
{
    var InversePr = new CMathGroupChrPr();
    if(Pr.pos == LOCATION_TOP)
    {
        InversePr.pos     = LOCATION_BOT;
        InversePr.vertJc  = VJUST_TOP;

        if(Pr.chr == 0x23DC || Pr.chr == 0x23DD)
        {
            InversePr.chr = 0x23DD;
        }
        else if(Pr.chr == 0x23DE || Pr.chr == 0x23DF)
        {
            InversePr.chr = 0x23DF;
        }
        else
        {
            InversePr.chr = Pr.chr;
        }
    }
    else
    {
        InversePr.pos     = LOCATION_TOP;
        InversePr.vertJc  = VJUST_BOT;

        if(Pr.chr == 0x23DC || Pr.chr == 0x23DD)
        {
            InversePr.chr = 0x23DC;
        }
        else if(Pr.chr == 0x23DE || Pr.chr == 0x23DF)
        {
            InversePr.chr = 0x23DE;
        }
        else
        {
            InversePr.chr = Pr.chr;
        }
    }

    return InversePr;
};
CGroupCharacter.prototype.private_InversePr = function()
{
    var NewPr = this.private_GetInversePr(this.Pr);
    var OldPr = this.Pr.Copy();
    History.Add(new CChangesMathGroupCharPr(this, OldPr, NewPr));
    this.raw_SetPr(NewPr);
};
CGroupCharacter.prototype.raw_SetPr = function(Pr)
{
    this.Pr.Set(Pr);

    this.RecalcInfo.bProps = true;
    this.ApplyProperties();
};
CGroupCharacter.prototype.Get_InterfaceProps = function()
{
    return new CMathMenuGroupCharacter(this);
};
CGroupCharacter.prototype.Can_ModifyArgSize = function()
{
    return false === this.Is_SelectInside();
};
CGroupCharacter.prototype.Can_ChangePos = function()
{
    return this.Pr.chr == 0x23DC || this.Pr.chr == 0x23DD || this.Pr.chr == 0x23DE || this.Pr.chr == 0x23DF;
};

/**
 *
 * @param CMathMenuGroupCharacter
 * @constructor
 * @extends {CMathMenuBase}
 */
function CMathMenuGroupCharacter(GroupChr)
{
	CMathMenuBase.call(this, GroupChr);

    this.Type          = Asc.c_oAscMathInterfaceType.GroupChar;

    if (undefined !== GroupChr)
    {
        this.Pos           = GroupChr.Pr.pos == LOCATION_BOT ? Asc.c_oAscMathInterfaceGroupCharPos.Bottom : Asc.c_oAscMathInterfaceGroupCharPos.Top;
        this.bCanChangePos = GroupChr.Can_ChangePos();
    }
    else
    {
        this.Pos           = undefined;
        this.bCanChangePos = undefined;
    }
}
CMathMenuGroupCharacter.prototype = Object.create(CMathMenuBase.prototype);
CMathMenuGroupCharacter.prototype.constructor = CMathMenuGroupCharacter;
CMathMenuGroupCharacter.prototype.get_Pos         = function(){return this.Pos;};
CMathMenuGroupCharacter.prototype.put_Pos         = function(Pos){this.Pos = Pos;};
CMathMenuGroupCharacter.prototype.can_ChangePos   = function(){return this.bCanChangePos;};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CDelimiter = CDelimiter;
window['AscCommonWord'].CGroupCharacter = CGroupCharacter;

window["CMathMenuGroupCharacter"] = CMathMenuGroupCharacter;
CMathMenuGroupCharacter.prototype["get_Pos"]         = CMathMenuGroupCharacter.prototype.get_Pos;
CMathMenuGroupCharacter.prototype["put_Pos"]         = CMathMenuGroupCharacter.prototype.put_Pos;
CMathMenuGroupCharacter.prototype["can_ChangePos"]   = CMathMenuGroupCharacter.prototype.can_ChangePos;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var g_oTextMeasurer = AscCommon.g_oTextMeasurer;

// 0x300  accent grave
// 0x301  accent acute
// 0x307  one dot
// 0x308  two dots
// 0x20DB three dots
// 0x332  single line
// 0x333  double line
// 0x303  tilde
// 0x302  circumflex
// 0x306  breve
// 0x20D6 left arrow
// 0x20D7 right arrow
// 0x20D0 half left arrow (harpoon)
// 0x20D1 half right arrow (harpoon)

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function CAccentCircumflex()
{
    CGlyphOperator.call(this);
}
CAccentCircumflex.prototype = Object.create(CGlyphOperator.prototype);
CAccentCircumflex.prototype.constructor = CAccentCircumflex;
CAccentCircumflex.prototype.calcSize = function(stretch)
{
    var alpha = this.Parent.Get_TxtPrControlLetter().FontSize/36;

    var width = 3.88*alpha;
    var height = 3.175*alpha;

    var augm = 0.8*stretch/width;

    if(augm < 1)
        augm = 1;
    else if (augm > 5)
        augm = 5;

    width *= augm;

    return {width: width, height: height};
};
CAccentCircumflex.prototype.calcCoord = function(stretch)
{
    var fontSize = this.Parent.Get_TxtPrControlLetter().FontSize;
    //var penW = fontSize*g_dKoef_pt_to_mm*this.PEN_W;
    //penW *= 96/25.4;

    // g_dKoef_px_to_mm = 25.4/96


    var textScale = fontSize/1000, // 1000 pt
        alpha = textScale*25.4/96 /64;

    var X = [],
        Y = [];

    X[0] = 0; Y[0] = 2373;
    X[1] = 9331; Y[1] = 15494;
    X[2] = 14913; Y[2] = 15494;
    X[3] = 23869; Y[3] = 2373;
    X[4] = 20953; Y[4] = 0;
    X[5] = 12122; Y[5] = 10118;
    X[6] = 11664; Y[6] = 10118;
    X[7] = 2833; Y[7] = 0;
    X[8] = 0; Y[8] = 2373;


    var XX = [],
        YY = [];

    var W = stretch/alpha;

    var a1 = X[3] - X[0], b1 = W,            c1 = X[2] - X[1],
        a2 = X[4] - X[7], b2 = W - 2*X[7],   c2 = X[5] - X[6] ; //X[8] = 0


    var RX = [];
    for(var i = 0; i < X.length; i++)
        RX[i] = 1;

    RX[0] = RX[2] = (b1 - c1)/(a1-c1);
    RX[4] = RX[6] =  (b2 - c2)/(a2-c2);


    XX[0] = XX[8] = X[0];
    YY[0] = YY[8] = Y[0];

    for(var i = 0; i< 4; i++)
    {
        XX[1 + i] = XX[i] + RX[i]*(X[1+i] - X[i]);
        XX[7-i]   = XX[8 - i] + RX[7-i]*(X[7-i] - X[8-i]);
        YY[1+i] = Y[1+i];
        YY[7-i] = Y[7-i];
    }

    for(var i = 0; i < XX.length; i++)
    {
        XX[i] = XX[i]*alpha ;
        YY[i] = YY[i]*alpha;
    }

    var H = YY[1];
    W = XX[3];

    return {XX: XX, YY: YY, W: W, H: H};
};
CAccentCircumflex.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._l(XX[1], YY[1]);
    pGraphics._l(XX[2], YY[2]);
    pGraphics._l(XX[3], YY[3]);
    pGraphics._l(XX[4], YY[4]);
    pGraphics._l(XX[5], YY[5]);
    pGraphics._l(XX[6], YY[6]);
    pGraphics._l(XX[7], YY[7]);
    pGraphics._l(XX[8], YY[8]);
    pGraphics._l(XX[9], YY[9]);
    pGraphics._l(XX[10], YY[10]);
    pGraphics._l(XX[11], YY[11]);
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function CAccentLine()
{
    CGlyphOperator.call(this);
}
CAccentLine.prototype = Object.create(CGlyphOperator.prototype);
CAccentLine.prototype.constructor = CAccentLine;
CAccentLine.prototype.calcSize = function(stretch)
{
    var alpha = this.Parent.Get_TxtPrControlLetter().FontSize/36;

    var height = 1.68*alpha;
    var width  = 4.938*alpha;

    width = stretch > width ? stretch : width;

    return {width: width, height: height};
};
CAccentLine.prototype.draw = function(x, y, pGraphics)
{
    var fontSize = this.Parent.Get_TxtPrControlLetter().FontSize;

    var penW = fontSize*0.0166;
    var x1 = x + 0.26458,
        x2 = x +  this.stretch - 0.26458;

    pGraphics.drawHorLine(0, y, x1, x2, penW);
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function CAccentDoubleLine()
{
    CGlyphOperator.call(this);
}
CAccentDoubleLine.prototype = Object.create(CGlyphOperator.prototype);
CAccentDoubleLine.prototype.constructor = CAccentDoubleLine;
CAccentDoubleLine.prototype.calcSize = function(stretch)
{
    var alpha = this.Parent.Get_TxtPrControlLetter().FontSize/36;

    var height = 2.843*alpha;
    var width  = 4.938*alpha;

    width = stretch > width ? stretch : width;

    var Line = new CMathText(true);
    Line.add(0x305);
    Line.Measure(g_oTextMeasurer);

    var DoubleLine = new CMathText(true);
    DoubleLine.add(0x33F);
    DoubleLine.Measure(g_oTextMeasurer);

    return {width: width, height: height};
};
CAccentDoubleLine.prototype.draw = function(x, y, pGraphics)
{
    var fontSize = this.Parent.Get_TxtPrControlLetter().FontSize;

    var diff = fontSize*0.05;

    var penW = fontSize*0.0166;

    var x1 = x + 0.26458,
        x2 = x +  this.stretch - 0.26458,
        y1 = y,
        y2 = y + diff;

    pGraphics.drawHorLine(0, y1, x1, x2, penW);

    pGraphics.drawHorLine(0, y2, x1, x2, penW);
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function CAccentTilde()
{
    CGlyphOperator.call(this);
}
CAccentTilde.prototype = Object.create(CGlyphOperator.prototype);
CAccentTilde.prototype.constructor = CAccentTilde;
CAccentTilde.prototype.calcSize = function(stretch)
{
    var betta = this.Parent.Get_TxtPrControlLetter().FontSize/36;

    var width = 9.047509765625*betta; // реальная на отрисовке width 7.495282031249999
    var height = 2.469444444444444*betta;

    var augm = 0.9*stretch/width;

    if(augm < 1)
        augm = 1;
    else if (augm > 2)
        augm = 2;

    width *= augm;

    return {width: width, height: height};
};
CAccentTilde.prototype.calcCoord = function(stretch)
{
    var X = [],
        Y = [];

    X[0] = 0; Y[0] = 3066;
    X[1] = 2125; Y[1] = 7984;
    X[2] = 5624; Y[2] = 11256;
    X[3] = 9123; Y[3] = 14528;
    X[4] = 13913; Y[4] = 14528;
    X[5] = 18912; Y[5] = 14528;
    X[6] = 25827; Y[6] = 10144;
    X[7] = 32742; Y[7] = 5760;
    X[8] = 36324; Y[8] = 5760;
    X[9] = 39865; Y[9] = 5760;
    X[10] = 42239; Y[10] = 7641;
    X[11] = 44614; Y[11] = 9522;
    X[12] = 47030; Y[12] = 13492;
    X[13] = 50362; Y[13] = 11254;
    X[14] = 48571; Y[14] = 7544;
    X[15] = 44697; Y[15] = 3772;
    X[16] = 40823; Y[16] = 0;
    X[17] = 35283; Y[17] = 0;
    X[18] = 29951; Y[18] = 0;
    X[19] = 23098; Y[19] = 4384;
    X[20] = 16246; Y[20] = 8768;
    X[21] = 12622; Y[21] = 8768;
    X[22] = 9581; Y[22] = 8768;
    X[23] = 7290; Y[23] = 6845;
    X[24] = 4999; Y[24] = 4922;
    X[25] = 3249; Y[25] = 1243;
    X[26] = 0; Y[26] = 3066;


    var XX = [],
        YY = [];

    var fontSize = this.Parent.Get_TxtPrControlLetter().FontSize;
    var textScale = fontSize/1000, // 1000 pt
        alpha = textScale*25.4/96 /64 ; // g_dKoef_px_to_mm = 25.4/96

    var Width = stretch/alpha;
    var augm = Width/X[13] * 0.5;


    for(var i = 0; i < X.length; i++)
    {
        XX[i] = X[i]*alpha*augm;
        YY[i] = (Y[5] - Y[i])*alpha*0.65; // сжали !
    }

    var H = YY[5];
    var W = XX[13];


    return {XX: XX, YY: YY, W: W, H: H};
};
CAccentTilde.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._c(XX[0], YY[0], XX[1], YY[1], XX[2], YY[2] );
    pGraphics._c(XX[2], YY[2], XX[3], YY[3], XX[4], YY[4] );
    pGraphics._c(XX[4], YY[4], XX[5], YY[5], XX[6], YY[6] );
    pGraphics._c(XX[6], YY[6], XX[7], YY[7], XX[8], YY[8] );
    pGraphics._c(XX[8], YY[8], XX[9], YY[9], XX[10], YY[10] );
    pGraphics._c(XX[10], YY[10], XX[11], YY[11], XX[12], YY[12] );
    pGraphics._l(XX[13], YY[13]);
    pGraphics._c(XX[13], YY[13], XX[14], YY[14], XX[15], YY[15] );
    pGraphics._c(XX[15], YY[15], XX[16], YY[16], XX[17], YY[17] );
    pGraphics._c(XX[17], YY[17], XX[18], YY[18], XX[19], YY[19] );
    pGraphics._c(XX[19], YY[19], XX[20], YY[20], XX[21], YY[21] );
    pGraphics._c(XX[21], YY[21], XX[22], YY[22], XX[23], YY[23] );
    pGraphics._c(XX[23], YY[23], XX[24], YY[24], XX[25], YY[25] );
    pGraphics._l(XX[26], YY[26]);
};

/**
 *
 * @constructor
 * @extends {CGlyphOperator}
 */
function CAccentBreve()
{
    CGlyphOperator.call(this);
}
CAccentBreve.prototype = Object.create(CGlyphOperator.prototype);
CAccentBreve.prototype.constructor = CAccentBreve;
CAccentBreve.prototype.calcSize = function(stretch)
{
    var betta = this.Parent.Get_TxtPrControlLetter().FontSize/36;

    var width =  4.2333333333333325*betta;
    var height = 2.469444444444445*betta;

    return {width: width, height: height};
};
CAccentBreve.prototype.calcCoord = function(stretch)
{
    var X = [],
        Y = [];

    X[0] = 25161; Y[0] = 11372;
    X[1] = 24077; Y[1] = 5749;
    X[2] = 20932; Y[2] = 2875;
    X[3] = 17787; Y[3] = 0;
    X[4] = 12247; Y[4] = 0;
    X[5] = 7082; Y[5] = 0;
    X[6] = 4083; Y[6] = 2854;
    X[7] = 1083; Y[7] = 5707;
    X[8] = 0; Y[8] = 11372;
    X[9] = 3208; Y[9] = 12371;
    X[10] = 4249; Y[10] = 9623;
    X[11] = 5561; Y[11] = 8083;
    X[12] = 6873; Y[12] = 6542;
    X[13] = 8456; Y[13] = 5959;
    X[14] = 10039; Y[14] = 5376;
    X[15] = 12414; Y[15] = 5376;
    X[16] = 14746; Y[16] = 5376;
    X[17] = 16454; Y[17] = 5980;
    X[18] = 18162; Y[18] = 6583;
    X[19] = 19558; Y[19] = 8124;
    X[20] = 20953; Y[20] = 9665;
    X[21] = 21953; Y[21] = 12371;
    X[22] = 25161; Y[22] = 11372;


    var XX = [],
        YY = [];

    var fontSize = this.Parent.Get_TxtPrControlLetter().FontSize;
    var textScale = fontSize/1000, // 1000 pt
        alpha = textScale*25.4/96 /64 ; // g_dKoef_px_to_mm = 25.4/96

    for(var i = 0; i < X.length; i++)
    {
        XX[i] = X[i]*alpha ;
        YY[i] = Y[i]*alpha ;
    }

    var H = YY[9],
        W = XX[0];

    return {XX: XX, YY: YY, W: W, H: H};
};
CAccentBreve.prototype.drawPath = function(pGraphics, XX, YY)
{
    pGraphics._m(XX[0], YY[0]);
    pGraphics._c(XX[0], YY[0], XX[1], YY[1], XX[2], YY[2] );
    pGraphics._c(XX[2], YY[2], XX[3], YY[3], XX[4], YY[4] );
    pGraphics._c(XX[4], YY[4], XX[5], YY[5], XX[6], YY[6] );
    pGraphics._c(XX[6], YY[6], XX[7], YY[7], XX[8], YY[8] );
    pGraphics._l(XX[9], YY[9]);
    pGraphics._c(XX[9], YY[9], XX[10], YY[10], XX[11], YY[11] );
    pGraphics._c(XX[11], YY[11], XX[12], YY[12], XX[13], YY[13] );
    pGraphics._c(XX[13], YY[13], XX[14], YY[14], XX[15], YY[15] );
    pGraphics._c(XX[15], YY[15], XX[16], YY[16], XX[17], YY[17] );
    pGraphics._c(XX[17], YY[17], XX[18], YY[18], XX[19], YY[19] );
    pGraphics._c(XX[19], YY[19], XX[20], YY[20], XX[21], YY[21] );
    pGraphics._l(XX[22], YY[22]);
};

function CMathAccentPr()
{
    this.chr     = null;
    this.chrType = null;
}
CMathAccentPr.prototype.Set_FromObject = function(Obj)
{
    if (undefined !== Obj.chr && null !== Obj.chr)
        this.chr = Obj.chr;
    else
        this.chr = null;

    if (undefined !== Obj.chrType && null !== Obj.chrType)
        this.chrType = Obj.chrType;
    else
        this.chrType = null;
};
CMathAccentPr.prototype.Copy = function()
{
    var NewPr = new CMathAccentPr();

    NewPr.chr     = this.chr;
    NewPr.chrType = this.chrType;

    return NewPr;
};
CMathAccentPr.prototype.Write_ToBinary = function(Writer)
{
    // Long : chr     (-1 : null)
    // Long : chrType (-1 : null)

    Writer.WriteLong(null === this.chr ? -1 : this.chr);
    Writer.WriteLong(null === this.chrType ? -1 : this.chrType);
};
CMathAccentPr.prototype.Read_FromBinary = function(Reader)
{
    // Long : chr     (-1 : null)
    // Long : chrType (-1 : null)

    var chr     = Reader.GetLong();
    var chrType = Reader.GetLong();

    this.chr     = -1 === chr ? null : chr;
    this.chrType = -1 === chrType ? null : chrType;
};

/**
 *
 * @param props
 * @constructor
 * @extends {CMathBase}
 */
function CAccent(props)
{
	CMathBase.call(this);

    this.Id = AscCommon.g_oIdCounter.Get_NewId();

    //// Properties
    this.Pr = new CMathAccentPr();

    this.gap = 0;

    /////////////////

    this.operator = new COperator(OPER_ACCENT);

    if(props !== null && typeof(props) !== "undefined")
        this.init(props);

    AscCommon.g_oTableId.Add( this, this.Id );	
}
CAccent.prototype = Object.create(CMathBase.prototype);
CAccent.prototype.constructor = CAccent;

CAccent.prototype.ClassType = AscDFH.historyitem_type_acc;
CAccent.prototype.kind      = MATH_ACCENT;

CAccent.prototype.init = function(props)
{
    this.Fill_LogicalContent(1);

    this.setProperties(props);
    this.fillContent();
};
CAccent.prototype.getBase = function()
{
    return this.Content[0];
};
CAccent.prototype.fillContent = function()
{
    this.setDimension(1, 1);
    this.elements[0][0] = this.getBase();
};
CAccent.prototype.IsAccent = function()
{
    return true;
};
CAccent.prototype.setPosition = function(pos, PosInfo)
{
    this.pos.x = pos.x;
    this.pos.y = pos.y - this.size.ascent;

    this.UpdatePosBound(pos, PosInfo);

    var width = this.size.width - this.GapLeft - this.GapRight;
    var oBase = this.Content[0];

    var alignOp  =  (width - this.operator.size.width)/2,
        alignCnt =  (width - oBase.size.width)/2;

    var PosOper = new CMathPosition();

    PosOper.x = this.pos.x + this.GapLeft  + alignOp;
    PosOper.y = this.pos.y;

    this.operator.setPosition(PosOper);

    var PosBase = new CMathPosition();

    PosBase.x = this.pos.x + this.GapLeft + alignCnt;
    PosBase.y = this.pos.y + this.operator.size.height + oBase.size.ascent;

    oBase.setPosition(PosBase, PosInfo);

    pos.x += this.size.width;
};
CAccent.prototype.ApplyProperties = function(RPI)
{
    if(this.RecalcInfo.bProps == true)
    {
        var prp =
        {
            type:   this.Pr.chrType,
            chr:    this.Pr.chr,
            loc:    LOCATION_TOP
        };

        var defaultPrp = {type:   ACCENT_CIRCUMFLEX };

        this.operator.mergeProperties(prp, defaultPrp);

        this.RecalcInfo.bProps = false;
    }
};
CAccent.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI, GapsInfo)
{
    this.ApplyProperties(RPI);
    this.operator.PreRecalc(this, ParaMath);

	CMathBase.prototype.PreRecalc.call(this, Parent, ParaMath, ArgSize, RPI, GapsInfo);
};
CAccent.prototype.Resize = function(oMeasure, RPI)
{
    var base = this.getBase();
    base.Resize(oMeasure, RPI);

    this.operator.fixSize(oMeasure, base.size.width);

    var width  = base.size.width, // (!)
        height = base.size.height + this.operator.size.height,
        ascent = this.operator.size.height + this.elements[0][0].size.ascent;

    width += this.GapLeft + this.GapRight;

    this.size.height = height;
    this.size.width  = width;
    this.size.ascent = ascent;
};
CAccent.prototype.Recalculate_Range = function(PRS, ParaPr, Depth)
{
    var bMath_OneLine = PRS.bMath_OneLine;
    var WordLen = PRS.WordLen; // запоминаем, чтобы внутр мат объекты не увеличили WordLen

    PRS.bMath_OneLine = true;

    var oBase = this.getBase();
    oBase.Recalculate_Reset(PRS.Range, PRS.Line, PRS ); // обновим StartLine и StartRange
    oBase.Recalculate_Range(PRS, ParaPr, Depth);

    this.operator.fixSize(g_oTextMeasurer, oBase.size.width);

    this.size.width  = oBase.size.width + this.GapLeft + this.GapRight; // (!)
    this.size.height = oBase.size.height + this.operator.size.height;
    this.size.ascent = this.operator.size.height + oBase.size.ascent;

    PRS.bMath_OneLine = bMath_OneLine;

    this.UpdatePRS_OneLine(PRS, WordLen);
};
CAccent.prototype.draw = function(x, y, pGraphics, PDSE)
{
    var base = this.elements[0][0];
    base.draw(x, y, pGraphics, PDSE);

    var Info =
    {
        Result:     true,
        sty:        null,
        scr:        null,
        Latin:      false,
        Greek:      false
    };

    base.getInfoLetter(Info);

    if(Info.Result == true)
    {
        var bAlphabet    = Info.Latin || Info.Greek;
        var bRomanSerif  = (Info.sty == STY_BI || Info.sty == STY_ITALIC) && (Info.scr == TXT_ROMAN || Info.scr == TXT_SANS_SERIF),
            bScript      = Info.scr == TXT_SCRIPT;

        if(bAlphabet && (bRomanSerif || bScript))
        {
            if(this.Pr.chr != 0x305 && this.Pr.chr >= 0x300 && this.Pr.chr <= 0x315 || this.Pr.chr == 0x20DB)
            {
                var ascent = this.elements[0][0].size.ascent;
                x += ascent*0.1;
            }
        }
    }

    this.operator.draw(x, y, pGraphics, PDSE);
};
CAccent.prototype.Draw_Elements = function(PDSE)
{
    var X = PDSE.X;

    var oBase = this.Content[0];
    oBase.Draw_Elements(PDSE);

    var PosLine = this.ParaMath.GetLinePosition(PDSE.Line, PDSE.Range);

    var x = PosLine.x,
        y = PosLine.y;

    //var x = PDSE.X,
    //    y = PDSE.Y;

    if(oBase.Is_InclineLetter())
    {
        if(this.Pr.chr != 0x305 && this.Pr.chr >= 0x300 && this.Pr.chr <= 0x315 || this.Pr.chr == 0x20DB)
        {
            var ascent = this.elements[0][0].size.ascent;
            x += ascent*0.1;
        }
    }

    this.operator.draw(x, y, PDSE.Graphics, PDSE);

    PDSE.X = X + this.size.width;
};
CAccent.prototype.GetLastElement = function()
{
    return this.Content[0].GetLastElement();
};
CAccent.prototype.Get_InterfaceProps = function()
{
    return new CMathMenuAccent(this);
};

/**
 *
 * @param CMathMenuAccent
 * @constructor
 * @extends {CMathMenuBase}
 */
function CMathMenuAccent(Accent)
{
	CMathMenuBase.call(this, Accent);

    this.Type   = Asc.c_oAscMathInterfaceType.Accent;
}
CMathMenuAccent.prototype = Object.create(CMathMenuBase.prototype);
CMathMenuAccent.prototype.constructor = CMathMenuAccent;

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CAccent = CAccent;

window["CMathMenuAccent"] = CMathMenuAccent;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var History = AscCommon.History;

function CMathBreak()
{
    this.alnAt = undefined;
}
CMathBreak.prototype.Set_FromObject = function(Obj)
{
    if(Obj.alnAt !== undefined && Obj.alnAt !== null && Obj.alnAt - 0 == Obj.alnAt)
    {
        if(Obj.alnAt >= 1 && Obj.alnAt <= 255)
            this.alnAt = Obj.alnAt;
    }
};
CMathBreak.prototype.Copy = function()
{
    var NewMBreak = new CMathBreak();
    NewMBreak.alnAt = this.alnAt;

    return NewMBreak;
};
CMathBreak.prototype.Get_AlignBrk = function()
{
    // undefined - break отсутствует
    // 0         - break присутствует, alnAt = undefined
    // Number    = break присутствует, alnAt = Number

    return this.alnAt !== undefined ? this.alnAt : 0;
};
CMathBreak.prototype.Get_AlnAt = function()
{
    return this.alnAt;
};
CMathBreak.prototype.Displace = function(isForward)
{
    if(isForward == false)
    {
        if(this.alnAt == 1)
            this.alnAt = undefined;
        else if(this.alnAt !== undefined)
            this.alnAt--;
    }
    else
    {
        if(this.alnAt == undefined)
            this.alnAt = 1;
        else if(this.alnAt < 255)
            this.alnAt++;
    }
};
CMathBreak.prototype.Apply_AlnAt = function(alnAt)
{
    if(alnAt == undefined)
    {
        this.alnAt = undefined;
    }
    else if(alnAt >= 1 && alnAt <= 255)
    {
        this.alnAt = alnAt;
    }
};
CMathBreak.prototype.Write_ToBinary = function(Writer)
{
    if(this.alnAt !== undefined)
    {
        Writer.WriteBool(false);
        Writer.WriteByte(this.alnAt);
    }
    else
    {
        Writer.WriteBool(true);
    }
};
CMathBreak.prototype.Read_FromBinary = function(Reader)
{
    if(Reader.GetBool() == false)
    {
        this.alnAt = Reader.GetByte();
    }
    else
    {
        this.alnAt = undefined;
    }
};


function CMathBorderBoxPr()
{
    this.hideBot    = false;
    this.hideLeft   = false;
    this.hideRight  = false;
    this.hideTop    = false;
    this.strikeBLTR = false;
    this.strikeH    = false;
    this.strikeTLBR = false;
    this.strikeV    = false;
}
CMathBorderBoxPr.prototype.Set_FromObject = function(Obj)
{
    if (undefined !== Obj.hideBot && null !== Obj.hideBot)
        this.hideBot = Obj.hideBot;

    if (undefined !== Obj.hideLeft && null !== Obj.hideLeft)
        this.hideLeft = Obj.hideLeft;

    if (undefined !== Obj.hideRight && null !== Obj.hideRight)
        this.hideRight = Obj.hideRight;

    if (undefined !== Obj.hideTop && null !== Obj.hideTop)
        this.hideTop = Obj.hideTop;

    if (undefined !== Obj.strikeBLTR && null !== Obj.strikeBLTR)
        this.strikeBLTR = Obj.strikeBLTR;

    if (undefined !== Obj.strikeH && null !== Obj.strikeH)
        this.strikeH = Obj.strikeH;

    if (undefined !== Obj.strikeTLBR && null !== Obj.strikeTLBR)
        this.strikeTLBR = Obj.strikeTLBR;

    if (undefined !== Obj.strikeV && null !== Obj.strikeV)
        this.strikeV = Obj.strikeV;
};
CMathBorderBoxPr.prototype.Copy = function()
{
    var NewPr = new CMathBorderBoxPr();

    NewPr.hideLeft   = this.hideLeft;
    NewPr.hideRight  = this.hideRight;
    NewPr.hideTop    = this.hideTop;
    NewPr.strikeBLTR = this.strikeBLTR;
    NewPr.strikeH    = this.strikeH;
    NewPr.strikeTLBR = this.strikeTLBR;
    NewPr.strikeV    = this.strikeV;

    return NewPr;
};
CMathBorderBoxPr.prototype.Write_ToBinary = function(Writer)
{
    // Bool : hideBot
    // Bool : hideLeft
    // Bool : hideRight
    // Bool : hideTop
    // Bool : strikeBLTR
    // Bool : strikeH
    // Bool : strikeTLBR
    // Bool : strikeV

    Writer.WriteBool(this.hideBot);
    Writer.WriteBool(this.hideLeft);
    Writer.WriteBool(this.hideRight);
    Writer.WriteBool(this.hideTop);
    Writer.WriteBool(this.strikeBLTR);
    Writer.WriteBool(this.strikeH);
    Writer.WriteBool(this.strikeTLBR);
    Writer.WriteBool(this.strikeV);
};
CMathBorderBoxPr.prototype.Read_FromBinary = function(Reader)
{
    // Bool : hideBot
    // Bool : hideLeft
    // Bool : hideRight
    // Bool : hideTop
    // Bool : strikeBLTR
    // Bool : strikeH
    // Bool : strikeTLBR
    // Bool : strikeV

    this.hideBot    = Reader.GetBool();
    this.hideLeft   = Reader.GetBool();
    this.hideRight  = Reader.GetBool();
    this.hideTop    = Reader.GetBool();
    this.strikeBLTR = Reader.GetBool();
    this.strikeH    = Reader.GetBool();
    this.strikeTLBR = Reader.GetBool();
    this.strikeV    = Reader.GetBool();
};

/**
 *
 * @param props
 * @constructor
 * @extends {CMathBase}
 */
function CBorderBox(props)
{
	CMathBase.call(this);

	this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.gapBrd = 0;

    this.Pr = new CMathBorderBoxPr();

    if(props !== null && typeof(props) !== "undefined")
        this.init(props);

    AscCommon.g_oTableId.Add(this, this.Id);
}
CBorderBox.prototype = Object.create(CMathBase.prototype);
CBorderBox.prototype.constructor = CBorderBox;
CBorderBox.prototype.ClassType = AscDFH.historyitem_type_borderBox;
CBorderBox.prototype.kind      = MATH_BORDER_BOX;
CBorderBox.prototype.init = function(props)
{
    this.Fill_LogicalContent(1);

    this.setProperties(props);
    this.fillContent();
};
CBorderBox.prototype.getBase = function()
{
    return this.Content[0];
};
CBorderBox.prototype.fillContent = function()
{
    this.setDimension(1, 1);
    this.elements[0][0] = this.getBase();
};
CBorderBox.prototype.recalculateSize = function()
{
    var base = this.elements[0][0].size;

    var width = base.width;
    var height = base.height;
    var ascent = base.ascent;

    this.gapBrd = this.Get_TxtPrControlLetter().FontSize*0.08104587131076388;

    if(this.Pr.hideTop == false)
    {
        height += this.gapBrd;
        ascent += this.gapBrd;
    }

    if(this.Pr.hideBot == false)
        height += this.gapBrd;

    if(this.Pr.hideLeft == false)
        width += this.gapBrd;
    if(this.Pr.hideRight == false)
        width += this.gapBrd;

    width += this.GapLeft + this.GapRight;

    this.size.width  = width;
    this.size.height = height;
    this.size.ascent = ascent;
};
CBorderBox.prototype.Draw_Elements = function(PDSE)
{
    var _X = PDSE.X;

    this.Content[0].Draw_Elements(PDSE);

    var penW = this.Get_TxtPrControlLetter().FontSize*0.02;

    var Width  = this.size.width - this.GapLeft - this.GapRight,
        Height = this.size.height;

    var PosLine = this.ParaMath.GetLinePosition(PDSE.Line, PDSE.Range);

    var X = this.pos.x + PosLine.x + this.GapLeft,
        Y = this.pos.y + PosLine.y;

    var oCompiledPr = this.Get_CompiledCtrPrp();

    this.Make_ShdColor(PDSE, oCompiledPr);

    if(!this.Pr.hideTop)
    {
        var x1 = X,
            x2 = X + Width,
            y1 = Y;

        PDSE.Graphics.drawHorLine(0, y1, x1, x2, penW, true);
    }

    if(!this.Pr.hideBot)
    {
        var x1 = X,
            x2 = X + Width,
            y1 = Y + Height;

        PDSE.Graphics.drawHorLine(2, y1, x1, x2, penW, true);
    }

    if(!this.Pr.hideLeft)
    {
        var x1 = X,
            y1 = Y,
            y2 = Y + Height;

        PDSE.Graphics.drawVerLine(0, x1, y1, y2, penW, true);
    }

    if(!this.Pr.hideRight)
    {
        var x1 = X + Width,
            y1 = Y,
            y2 = Y + Height;

        PDSE.Graphics.drawVerLine(2, x1, y1, y2, penW, true);
    }

    if(this.Pr.strikeTLBR)  // left diagonal
    {
        if(penW < 0.3)
        {
            var x1 = X, y1 = Y,
                x2 = X + Width, y2 = Y + Height;

            PDSE.Graphics.p_width(180);

            PDSE.Graphics._s();
            PDSE.Graphics._m(x1, y1);
            PDSE.Graphics._l(x2, y2);
            PDSE.Graphics.ds();
        }
        else
        {
            var pW = penW*0.8;

            var x1 = X,                 y1 = Y,
                x2 = X + pW,            y2 = Y,
                x3 = X + Width,         y3 = Y + Height - pW,
                x4 = X + Width,         y4 = Y + Height,
                x5 = X + Width - pW,    y5 = Y + Height,
                x6 = X,                 y6 = Y + pW,
                x7 = X,                 y7 = Y;

            PDSE.Graphics.p_width(1000);

            PDSE.Graphics._s();
            PDSE.Graphics._m(x1, y1);
            PDSE.Graphics._l(x2, y2);
            PDSE.Graphics._l(x3, y3);
            PDSE.Graphics._l(x4, y4);
            PDSE.Graphics._l(x5, y5);
            PDSE.Graphics._l(x6, y6);
            PDSE.Graphics._l(x7, y7);
            PDSE.Graphics.df();
        }
    }

    if(this.Pr.strikeBLTR) // right diagonal
    {
        if(penW < 0.3)
        {
            var x1 = X + Width,      y1 = Y,
                x2 = X,              y2 = Y + Height;

            PDSE.Graphics.p_width(180);

            PDSE.Graphics._s();
            PDSE.Graphics._m(x1, y1);
            PDSE.Graphics._l(x2, y2);
            PDSE.Graphics.ds();
        }
        else
        {
            var pW = 0.8*penW;

            var x1 = X + Width,         y1 = Y,
                x2 = X + Width - pW,    y2 = Y,
                x3 = X,                 y3 = Y + Height - pW,
                x4 = X,                 y4 = Y + Height,
                x5 = X + pW,            y5 = Y + Height,
                x6 = X + Width,         y6 = Y + pW,
                x7 = X + Width,         y7 = Y;


            PDSE.Graphics.p_width(1000);

            PDSE.Graphics._s();
            PDSE.Graphics._m(x1, y1);
            PDSE.Graphics._l(x2, y2);
            PDSE.Graphics._l(x3, y3);
            PDSE.Graphics._l(x4, y4);
            PDSE.Graphics._l(x5, y5);
            PDSE.Graphics._l(x6, y6);
            PDSE.Graphics._l(x7, y7);
            PDSE.Graphics.df();
        }
    }

    if(this.Pr.strikeH)
    {
        var x1 = X,
            x2 = X + Width,
            y1 = Y + Height/2 - penW/2;

        PDSE.Graphics.drawHorLine(0, y1, x1, x2, penW);
    }

    if(this.Pr.strikeV)
    {
        var x1 = X + Width/2 - penW/2,
            y1 = Y,
            y2 = Y + Height;

        PDSE.Graphics.drawVerLine(0, x1, y1, y2, penW, true);
    }

    PDSE.X = _X + this.size.width;
};
CBorderBox.prototype.setPosition = function(pos, PosInfo)
{
    this.pos.x = pos.x;
    this.pos.y = pos.y - this.size.ascent;

    this.UpdatePosBound(pos, PosInfo);

    var NewPos = new CMathPosition();

    var Base = this.Content[0];

    if(this.Pr.hideLeft == false)
        NewPos.x = this.pos.x + this.GapLeft + this.gapBrd;
    else
        NewPos.x = this.pos.x + this.GapLeft;


    if(this.Pr.hideTop == false)
        NewPos.y = this.pos.y + this.gapBrd + Base.size.ascent;
    else
        NewPos.y = this.pos.y + Base.size.ascent;

    Base.setPosition(NewPos, PosInfo);

    pos.x += this.size.width;
};
CBorderBox.prototype.Apply_MenuProps = function(Props)
{
	if (Props.Type == Asc.c_oAscMathInterfaceType.BorderBox)
	{
		if (Props.HideTop !== undefined && Props.HideTop !== this.Pr.hideTop)
		{
			History.Add(new CChangesMathBorderBoxTop(this, this.Pr.hideTop, Props.HideTop));
			this.raw_SetTop(Props.HideTop);
		}

		if (Props.HideBottom !== undefined && Props.HideBottom !== this.Pr.hideBot)
		{
			History.Add(new CChangesMathBorderBoxBot(this, this.Pr.hideBot, Props.HideBottom));
			this.raw_SetBot(Props.HideBottom);
		}

		if (Props.HideLeft !== undefined && Props.HideLeft !== this.Pr.hideLeft)
		{
			History.Add(new CChangesMathBorderBoxLeft(this, this.Pr.hideLeft, Props.HideLeft));
			this.raw_SetLeft(Props.HideLeft);
		}

		if (Props.HideRight !== undefined && Props.HideRight !== this.Pr.hideRight)
		{
			History.Add(new CChangesMathBorderBoxRight(this, this.Pr.hideRight, Props.HideRight));
			this.raw_SetRight(Props.HideRight);
		}

		if (Props.HideHor !== undefined && Props.HideHor == this.Pr.strikeH) // strikeH - нарисовать горизонтальную линию
		{
			History.Add(new CChangesMathBorderBoxHor(this, this.Pr.strikeH, !Props.HideHor));
			this.raw_SetHor(!Props.HideHor);
		}

		if (Props.HideVer !== undefined && Props.HideVer == this.Pr.strikeV) // strikeV - нарисовать вертикальную линию
		{
			History.Add(new CChangesMathBorderBoxVer(this, this.Pr.strikeV, !Props.HideVer));
			this.raw_SetVer(!Props.HideVer);
		}

		if (Props.HideTopLTR !== undefined && Props.HideTopLTR == this.Pr.strikeTLBR) // strikeTLBR - нарисовать диагональ из
																			  // верхнего угла слева направо
		{
			History.Add(new CChangesMathBorderBoxTopLTR(this, this.Pr.strikeTLBR, !Props.HideTopLTR));
			this.raw_SetTopLTR(!Props.HideTopLTR);
		}

		if (Props.HideTopRTL !== undefined && Props.HideTopRTL == this.Pr.strikeBLTR)
		{
			History.Add(new CChangesMathBorderBoxTopRTL(this, this.Pr.strikeBLTR, !Props.HideTopRTL)); // strikeBLTR -
																									   // нарисовать
																									   // диагональ из
																									   // нижнего угла
																									   // слева направо
			this.raw_SetTopRTL(!Props.HideTopRTL);
		}
	}
};
CBorderBox.prototype.raw_SetTop = function(Value)
{
    this.Pr.hideTop = Value;
};
CBorderBox.prototype.raw_SetBot = function(Value)
{
    this.Pr.hideBot = Value;
};
CBorderBox.prototype.raw_SetLeft = function(Value)
{
    this.Pr.hideLeft = Value;
};
CBorderBox.prototype.raw_SetRight = function(Value)
{
    this.Pr.hideRight = Value;
};
CBorderBox.prototype.raw_SetHor = function(Value)
{
    this.Pr.strikeH = Value;
};
CBorderBox.prototype.raw_SetVer = function(Value)
{
    this.Pr.strikeV = Value;
};
CBorderBox.prototype.raw_SetTopLTR = function(Value)
{
    this.Pr.strikeTLBR = Value;
};
CBorderBox.prototype.raw_SetTopRTL = function(Value)
{
    this.Pr.strikeBLTR = Value;
};
CBorderBox.prototype.Get_InterfaceProps = function()
{
    return new CMathMenuBorderBox(this);
};

/**
 *
 * @param CMathMenuBorderBox
 * @constructor
 * @extends {CMathMenuBase}
 */
function CMathMenuBorderBox(BorderBox)
{
	CMathMenuBase.call(this, BorderBox);

    this.Type = Asc.c_oAscMathInterfaceType.BorderBox;

    if(undefined !== BorderBox)
    {
        this.HideTop    = BorderBox.Pr.hideTop;
        this.HideBottom = BorderBox.Pr.hideBot;
        this.HideLeft   = BorderBox.Pr.hideLeft;
        this.HideRight  = BorderBox.Pr.hideRight;
        this.HideHor    = BorderBox.Pr.strikeH == false;
        this.HideVer    = BorderBox.Pr.strikeV == false;
        this.HideTopLTR = BorderBox.Pr.strikeTLBR == false;
        this.HideTopRTL = BorderBox.Pr.strikeBLTR == false;
    }
    else
    {
        this.HideTop    = undefined;
        this.HideBottom = undefined;
        this.HideLeft   = undefined;
        this.HideRight  = undefined;
        this.HideHor    = undefined;
        this.HideVer    = undefined;
        this.HideTopLTR = undefined;
        this.HideTopRTL = undefined;
    }
}
CMathMenuBorderBox.prototype = Object.create(CMathMenuBase.prototype);
CMathMenuBorderBox.prototype.constructor = CMathMenuBorderBox;
CMathMenuBorderBox.prototype.get_HideTop = function(){return this.HideTop;};
CMathMenuBorderBox.prototype.put_HideTop = function(bHideTop){this.HideTop = bHideTop;};
CMathMenuBorderBox.prototype.get_HideBottom = function(){return this.HideBottom;};
CMathMenuBorderBox.prototype.put_HideBottom = function(bHideBottom){this.HideBottom = bHideBottom;};
CMathMenuBorderBox.prototype.get_HideLeft = function(){return this.HideLeft;};
CMathMenuBorderBox.prototype.put_HideLeft = function(bHideLeft){this.HideLeft = bHideLeft;};
CMathMenuBorderBox.prototype.get_HideRight = function(){return this.HideRight;};
CMathMenuBorderBox.prototype.put_HideRight = function(bHideRight){this.HideRight = bHideRight;};
CMathMenuBorderBox.prototype.get_HideHor = function(){return this.HideHor;};
CMathMenuBorderBox.prototype.put_HideHor = function(bHideHor){this.HideHor = bHideHor;};
CMathMenuBorderBox.prototype.get_HideVer = function(){return this.HideVer;};
CMathMenuBorderBox.prototype.put_HideVer = function(bHideVer){this.HideVer = bHideVer;};
CMathMenuBorderBox.prototype.get_HideTopLTR = function(){return this.HideTopLTR;};
CMathMenuBorderBox.prototype.put_HideTopLTR = function(bHideTopLTR){this.HideTopLTR = bHideTopLTR;};
CMathMenuBorderBox.prototype.get_HideTopRTL = function(){return this.HideTopRTL;};
CMathMenuBorderBox.prototype.put_HideTopRTL = function(bHideTopRTL){this.HideTopRTL = bHideTopRTL;};

window["CMathMenuBorderBox"]                   = CMathMenuBorderBox;
CMathMenuBorderBox.prototype["get_HideTop"]    = CMathMenuBorderBox.prototype.get_HideTop;
CMathMenuBorderBox.prototype["put_HideTop"]    = CMathMenuBorderBox.prototype.put_HideTop;
CMathMenuBorderBox.prototype["get_HideBottom"] = CMathMenuBorderBox.prototype.get_HideBottom;
CMathMenuBorderBox.prototype["put_HideBottom"] = CMathMenuBorderBox.prototype.put_HideBottom;
CMathMenuBorderBox.prototype["get_HideLeft"]   = CMathMenuBorderBox.prototype.get_HideLeft;
CMathMenuBorderBox.prototype["put_HideLeft"]   = CMathMenuBorderBox.prototype.put_HideLeft;
CMathMenuBorderBox.prototype["get_HideRight"]  = CMathMenuBorderBox.prototype.get_HideRight;
CMathMenuBorderBox.prototype["put_HideRight"]  = CMathMenuBorderBox.prototype.put_HideRight;
CMathMenuBorderBox.prototype["get_HideHor"]    = CMathMenuBorderBox.prototype.get_HideHor;
CMathMenuBorderBox.prototype["put_HideHor"]    = CMathMenuBorderBox.prototype.put_HideHor;
CMathMenuBorderBox.prototype["get_HideVer"]    = CMathMenuBorderBox.prototype.get_HideVer;
CMathMenuBorderBox.prototype["put_HideVer"]    = CMathMenuBorderBox.prototype.put_HideVer;
CMathMenuBorderBox.prototype["get_HideTopLTR"] = CMathMenuBorderBox.prototype.get_HideTopLTR;
CMathMenuBorderBox.prototype["put_HideTopLTR"] = CMathMenuBorderBox.prototype.put_HideTopLTR;
CMathMenuBorderBox.prototype["get_HideTopRTL"] = CMathMenuBorderBox.prototype.get_HideTopRTL;
CMathMenuBorderBox.prototype["put_HideTopRTL"] = CMathMenuBorderBox.prototype.put_HideTopRTL;



function CMathBoxPr()
{
    this.brk     = undefined;
    this.aln     = false;
    this.diff    = false;
    this.noBreak = false;
    this.opEmu   = false;
}
CMathBoxPr.prototype.Set_FromObject = function(Obj)
{
    if(true === Obj.aln || 1 === Obj.aln)
        this.aln = true;
    else
        this.aln = false;

    if(Obj.brk !== null && Obj.brk !== undefined)
    {
        this.brk = new CMathBreak();
        this.brk.Set_FromObject(Obj.brk);
    }

    if(true === Obj.diff || 1 === Obj.diff)
        this.diff = true;
    else
        this.diff = false;

    if(true === Obj.noBreak || 1 === Obj.noBreak)
        this.noBreak = true;
    else
        this.noBreak = false;

    if(true === Obj.opEmu || 1 === Obj.opEmu || Obj.opEmu === null) // null - val attribute is absent
        this.opEmu = true;
    else
        this.opEmu = false;
};
CMathBoxPr.prototype.Get_AlnAt = function()
{
    return this.brk != undefined ? this.brk.Get_AlnAt() : undefined;
};
CMathBoxPr.prototype.Get_AlignBrk = function()
{
    return this.brk == undefined ? null : this.brk.Get_AlignBrk();
};
CMathBoxPr.prototype.Displace_Break = function(isForward)
{
    if(this.brk !== undefined)
    {
        this.brk.Displace(isForward);
    }
};
CMathBoxPr.prototype.Apply_AlnAt = function(alnAt)
{
    if(this.brk !== undefined)
    {
        this.brk.Apply_AlnAt(alnAt);
    }
};
CMathBoxPr.prototype.IsForcedBreak = function()
{
    return this.opEmu == true && this.brk !== undefined;
};
CMathBoxPr.prototype.Insert_ForcedBreak = function()
{
    if(false == this.IsForcedBreak())
    {
        this.brk = new CMathBreak();
    }
};
CMathBoxPr.prototype.Delete_ForcedBreak = function()
{
    if(true == this.IsForcedBreak())
    {
        this.brk = undefined;
    }
};
CMathBoxPr.prototype.Copy = function()
{
    var NewPr = new CMathBoxPr();

    NewPr.aln     = this.aln    ;
    NewPr.diff    = this.diff   ;
    NewPr.noBreak = this.noBreak;
    NewPr.opEmu   = this.opEmu  ;

    if(this.brk !== undefined)
        NewPr.brk = this.brk.Copy();

    return NewPr;
};
CMathBoxPr.prototype.Write_ToBinary = function(Writer)
{
    // Bool : aln
    // Bool : brk
    // Bool : diff
    // Bool : noBreak
    // Bool : opEmu

    Writer.WriteBool(this.aln);
    Writer.WriteBool(this.diff);
    Writer.WriteBool(this.noBreak);
    Writer.WriteBool(this.opEmu);

    if ( undefined !== this.brk )
    {
        Writer.WriteBool(false);
        this.brk.Write_ToBinary(Writer);
    }
    else
    {
        Writer.WriteBool(true);
    }
};
CMathBoxPr.prototype.Read_FromBinary = function(Reader)
{
    // Bool : aln
    // Bool : brk
    // Bool : diff
    // Bool : noBreak
    // Bool : opEmu

    this.aln     = Reader.GetBool();
    this.diff    = Reader.GetBool();
    this.noBreak = Reader.GetBool();
    this.opEmu   = Reader.GetBool();

    if(Reader.GetBool() == false)
    {
        this.brk = new CMathBreak();
        this.brk.Read_FromBinary(Reader);
    }
    else
    {
        this.brk = undefined;
    }
};

/**
 *
 * @param props
 * @constructor
 * @extends {CMathBase}
 */
function CBox(props)
{
	CMathBase.call(this);

	this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.Pr = new CMathBoxPr();

    this.baseContent = new CMathContent();

    if(props !== null && typeof(props) !== "undefined")
        this.init(props);

    AscCommon.g_oTableId.Add( this, this.Id );
}
CBox.prototype = Object.create(CMathBase.prototype);
CBox.prototype.constructor = CBox;
CBox.prototype.ClassType = AscDFH.historyitem_type_box;
CBox.prototype.kind      = MATH_BOX;
CBox.prototype.init = function(props)
{
    this.Fill_LogicalContent(1);

    this.setProperties(props);
    this.fillContent();
};
CBox.prototype.fillContent = function()
{
    if(this.Pr.opEmu == false && this.Pr.noBreak == false)
    {
        this.NeedBreakContent(0);
    }
    else
    {
        this.bCanBreak = false;
    }

    this.setDimension(1, 1);
    this.elements[0][0] = this.getBase();
};
CBox.prototype.getBase = function()
{
    return this.Content[0];
};
CBox.prototype.UpdatePRS_OneLine = function(PRS, WordLen, MathFirstItem)
{
    PRS.WordLen   = WordLen;
    PRS.MathFirstItem = MathFirstItem; // вернем MathFirstItem, который был до расчета Box, т.к . при расчете он мог измениться (при наличии внутри Box др мат объектов)
};
CBox.prototype.IsOperatorEmulator = function()
{
    return this.Pr.opEmu == true;
};
CBox.prototype.private_CanUseForcedBreak = function()
{
    var bInline = this.ParaMath.Is_Inline();

    return bInline == false && true == this.IsOperatorEmulator();
};
CBox.prototype.IsForcedBreak = function()
{
    return true == this.private_CanUseForcedBreak() && true == this.Pr.IsForcedBreak();
};
CBox.prototype.Get_AlignBrk = function()
{
    // null      - break отсутствует
    // 0         - break присутствует, alnAt = undefined
    // Number    = break присутствует, alnAt = Number

    return false == this.private_CanUseForcedBreak() ? null : this.Pr.Get_AlignBrk();
};
CBox.prototype.Displace_BreakOperator = function(isForward, bBrkBefore, CountOperators)
{
	if (this.Pr.brk !== undefined)
	{
		var AlnAt = this.Pr.Get_AlnAt();

		var NotIncrease = AlnAt == CountOperators && isForward == true;

		if (NotIncrease == false)
		{
			this.Pr.Displace_Break(isForward);

			var NewAlnAt = this.Pr.Get_AlnAt();

			if (AlnAt !== NewAlnAt)
			{
				History.Add(new CChangesMathBoxAlnAt(this, AlnAt, NewAlnAt));
			}
		}
	}
};
CBox.prototype.raw_setAlnAt = function(Value)
{
    this.Pr.Apply_AlnAt(Value);
};
CBox.prototype.Can_ModifyArgSize = function()
{
    return false === this.Is_SelectInside();
};
CBox.prototype.Apply_MenuProps = function(Props)
{
    // не проверяем изменения на тип !
    // потому что может прийти свойства из другого (вложенного в Box) мат объекта, но при этом есть возможность вставить/удалить  принудительный перенос для Box

    if(Props.Action & c_oMathMenuAction.InsertForcedBreak && true == this.Can_InsertForcedBreak())
    {
        History.Add(new CChangesMathBoxForcedBreak(this, false, true));
        this.raw_ForcedBreak(true);
    }

    if(Props.Action & c_oMathMenuAction.DeleteForcedBreak && true == this.Can_DeleteForcedBreak())
    {
        History.Add(new CChangesMathBoxForcedBreak(this, true, false));
        this.raw_ForcedBreak(false);
    }
};
CBox.prototype.Get_InterfaceProps = function()
{
    return new CMathMenuBox(this);
};
CBox.prototype.Can_InsertForcedBreak = function()
{
    var bCanModifyForcedBreak = this.private_CanUseForcedBreak();

    return bCanModifyForcedBreak == true && false === this.IsForcedBreak();
};
CBox.prototype.Can_DeleteForcedBreak = function()
{
    var bCanModifyForcedBreak = this.private_CanUseForcedBreak();

    return bCanModifyForcedBreak == true && true == this.IsForcedBreak();
};
CBox.prototype.raw_ForcedBreak = function(InsertBreak, AlnAt)
{
    if(InsertBreak)
    {
        this.Pr.Insert_ForcedBreak();
        this.Pr.Apply_AlnAt(AlnAt);
    }
    else
    {
        this.Pr.Delete_ForcedBreak();
    }
};
CBox.prototype.Can_ModifyForcedBreak = function(Pr)
{
    if(true == this.Can_InsertForcedBreak())
    {
        Pr.Set_InsertForcedBreak();
    }
    else if(true == this.Can_DeleteForcedBreak())
    {
        Pr.Set_DeleteForcedBreak();
    }
};
CBox.prototype.Apply_ForcedBreak = function(Props)
{
    this.Apply_MenuProps(Props);

    // исключаем из Props, чтобы не применить к операторам внути Box
    // иначе при Drag'n'Drop оператора получим неочевидный результат :  принудительный перенос
    if(Props.Action & c_oMathMenuAction.InsertForcedBreak)
        Props.Action ^= c_oMathMenuAction.InsertForcedBreak;

    if(Props.Action & c_oMathMenuAction.DeleteForcedBreak)
        Props.Action ^= c_oMathMenuAction.DeleteForcedBreak;
};

/**
 *
 * @param CMathMenuBox
 * @constructor
 * @extends {CMathMenuBase}
 */
function CMathMenuBox(Box)
{
	CMathMenuBase.call(this, Box);

    this.Type = Asc.c_oAscMathInterfaceType.Box;
}
CMathMenuBox.prototype = Object.create(CMathMenuBase.prototype);
CMathMenuBox.prototype.constructor = CMathMenuBox;
window["CMathMenuBox"] = CMathMenuBox;

function CMathBarPr()
{
    this.pos = LOCATION_BOT;
}
CMathBarPr.prototype.Set_FromObject = function(Obj)
{
    if(LOCATION_TOP === Obj.pos || LOCATION_BOT === Obj.pos)
        this.pos = Obj.pos;
};
CMathBarPr.prototype.Copy = function()
{
    var NewPr = new CMathBarPr();
    NewPr.pos = this.pos;
    return NewPr;
};
CMathBarPr.prototype.Write_ToBinary = function(Writer)
{
    // Long : pos
    Writer.WriteLong(this.pos);
};
CMathBarPr.prototype.Read_FromBinary = function(Reader)
{
    // Long : pos
    this.pos = Reader.GetLong();
};

/**
 *
 * @param props
 * @constructor
 * @extends {CCharacter}
 */
function CBar(props)
{
	CCharacter.call(this);

	this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.Pr = new CMathBarPr();

    this.operator = new COperator(OPER_BAR);

    if(props !== null && typeof(props) !== "undefined")
        this.init(props);

    AscCommon.g_oTableId.Add( this, this.Id );
}
CBar.prototype = Object.create(CCharacter.prototype);
CBar.prototype.constructor = CBar;
CBar.prototype.ClassType = AscDFH.historyitem_type_bar;
CBar.prototype.kind      = MATH_BAR;
CBar.prototype.init = function(props)
{
    this.Fill_LogicalContent(1);

    this.setProperties(props);
    this.fillContent();
};
CBar.prototype.getBase = function()
{
    return this.Content[0];
};
CBar.prototype.fillContent = function()
{
    this.setDimension(1, 1);
    this.elements[0][0] = this.getBase();
};
CBar.prototype.ApplyProperties = function(RPI)
{
    if(this.RecalcInfo.bProps == true)
    {
        var prp = {loc:    this.Pr.pos, type:   DELIMITER_LINE };

        var defaultProps = { loc:   LOCATION_BOT};

        this.setCharacter(prp, defaultProps);
        this.RecalcInfo.bProps = false;
    }
};
CBar.prototype.PreRecalc = function(Parent, ParaMath, ArgSize, RPI, GapsInfo)
{
    this.ApplyProperties(RPI);
    this.operator.PreRecalc(this, ParaMath);

	CCharacter.prototype.PreRecalc.call(this, Parent, ParaMath, ArgSize, RPI, GapsInfo);
};
CBar.prototype.getAscent = function()
{
    var ascent;

    if(this.Pr.pos === LOCATION_TOP )
        ascent = this.operator.size.height + this.elements[0][0].size.ascent;
    else if(this.Pr.pos === LOCATION_BOT )
        ascent = this.elements[0][0].size.ascent;

    return ascent;
};
CBar.prototype.Apply_MenuProps = function(Props)
{
	if (Props.Type == Asc.c_oAscMathInterfaceType.Bar && Props.Pos !== undefined)
	{
		var Pos = Props.Pos == Asc.c_oAscMathInterfaceBarPos.Bottom ? LOCATION_BOT : LOCATION_TOP;

		if (Pos !== this.Pr.pos)
		{
			History.Add(new CChangesMathBarLinePos(this, this.Pr.pos, Pos));
			this.raw_SetLinePos(Pos);
		}
	}
};
CBar.prototype.Get_InterfaceProps = function()
{
    return new CMathMenuBar(this);
};
CBar.prototype.raw_SetLinePos = function(Value)
{
    this.Pr.pos = Value;
    this.RecalcInfo.bProps = true;
    this.ApplyProperties();
};

/**
 *
 * @param CMathMenuBar
 * @constructor
 * @extends {CMathMenuBase}
 */
function CMathMenuBar(Bar)
{
	CMathMenuBase.call(this, Bar);

    this.Type   = Asc.c_oAscMathInterfaceType.Bar;

    if (undefined !== Bar)
    {
        this.Pos = Bar.Pr.pos == LOCATION_BOT ? Asc.c_oAscMathInterfaceBarPos.Bottom : Asc.c_oAscMathInterfaceBarPos.Top;
    }
    else
    {
        this.Pos = undefined;
    }
}
CMathMenuBar.prototype = Object.create(CMathMenuBase.prototype);
CMathMenuBar.prototype.constructor = CMathMenuBar;

CMathMenuBar.prototype.get_Pos = function(){return this.Pos};
CMathMenuBar.prototype.put_Pos = function(Pos){this.Pos = Pos;};

window["CMathMenuBar"] = CMathMenuBar;
CMathMenuBar.prototype["get_Pos"] = CMathMenuBar.prototype.get_Pos;
CMathMenuBar.prototype["put_Pos"] = CMathMenuBar.prototype.put_Pos;

function CMathPhantomPr()
{
    this.show     = true;
    this.transp   = false;
    this.zeroAsc  = false;
    this.zeroDesc = false;
    this.zeroWid  = false;
}
CMathPhantomPr.prototype.Set_FromObject = function(Obj)
{
    if (true === Obj.show || 1 === Obj.show)
        this.show = true;
    else
        this.show = false;

    if (true === Obj.transp || 1 === Obj.transp)
        this.transp = true;
    else
        this.transp = false;

    if (true === Obj.zeroAsc || 1 === Obj.zeroAsc)
        this.zeroAsc = true;
    else
        this.zeroAsc = false;

    if (true === Obj.zeroDesc || 1 === Obj.zeroDesc)
        this.zeroDesc = true;
    else
        this.zeroDesc = false;

    if (true === Obj.zeroWid || 1 === Obj.zeroWid)
        this.zeroWid = true;
    else
        this.zeroWid = false;
};
CMathPhantomPr.prototype.Copy = function()
{
    var NewPr = new CMathPhantomPr();

    NewPr.show     = this.show    ;
    NewPr.transp   = this.transp  ;
    NewPr.zeroAsc  = this.zeroAsc ;
    NewPr.zeroDesc = this.zeroDesc;
    NewPr.zeroWid  = this.zeroWid ;

    return NewPr;
};
CMathPhantomPr.prototype.Write_ToBinary = function(Writer)
{
    // Bool : show
    // Bool : transp
    // Bool : zeroAsc
    // Bool : zeroDesc
    // Bool : zeroWid

    Writer.WriteBool(this.show);
    Writer.WriteBool(this.transp);
    Writer.WriteBool(this.zeroAsc);
    Writer.WriteBool(this.zeroDesc);
    Writer.WriteBool(this.zeroWid);
};
CMathPhantomPr.prototype.Read_FromBinary = function(Reader)
{
    // Bool : show
    // Bool : transp
    // Bool : zeroAsc
    // Bool : zeroDesc
    // Bool : zeroWid

    this.show     = Reader.GetBool();
    this.transp   = Reader.GetBool();
    this.zeroAsc  = Reader.GetBool();
    this.zeroDesc = Reader.GetBool();
    this.zeroWid  = Reader.GetBool();
};

/**
 *
 * @param props
 * @constructor
 * @extends {CMathBase}
 */
function CPhantom(props)
{
	CMathBase.call(this);

	this.Id = AscCommon.g_oIdCounter.Get_NewId();

    this.Pr = new CMathPhantomPr();

    if(props !== null && typeof(props) !== "undefined")
        this.init(props);

    AscCommon.g_oTableId.Add( this, this.Id );
}
CPhantom.prototype = Object.create(CMathBase.prototype);
CPhantom.prototype.constructor = CPhantom;
CPhantom.prototype.ClassType = AscDFH.historyitem_type_phant;
CPhantom.prototype.kind      = MATH_PHANTOM;
CPhantom.prototype.init = function(props)
{
    this.Fill_LogicalContent(1);

    this.setProperties(props);
    this.fillContent();
};
CPhantom.prototype.getBase = function()
{
    return this.Content[0];
};
CPhantom.prototype.fillContent = function()
{
    this.setDimension(1, 1);
    this.elements[0][0] = this.getBase();
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CBar = CBar;
window['AscCommonWord'].CBox = CBox;
window['AscCommonWord'].CBorderBox = CBorderBox;
window['AscCommonWord'].CPhantom = CPhantom;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
(function(window, builder)
{
	/**
	 * Base class
	 * @global
	 * @class
	 * @name Api
	 */
	var Api = window["Asc"]["asc_docs_api"] || window["Asc"]["spreadsheet_api"];

	/**
	 * Class representing a container for paragraphs and tables.
	 * @param Document
	 * @constructor
	 */
	function ApiDocumentContent(Document)
	{
		this.Document = Document;
	}

	/**
	 * Class representing a document.
	 * @constructor
	 * @extends {ApiDocumentContent}
	 */
	function ApiDocument(Document)
	{
		ApiDocumentContent.call(this, Document);
	}
	ApiDocument.prototype = Object.create(ApiDocumentContent.prototype);
	ApiDocument.prototype.constructor = ApiDocument;

	/**
	 * Class representing a paragraph properties.
	 * @constructor
	 */
	function ApiParaPr(Parent, ParaPr)
	{
		this.Parent = Parent;
		this.ParaPr = ParaPr;
	}


	/**
	 * Class representing paragraph bullet
	 * @constructor
	 */
	function ApiBullet(Bullet)
	{
		this.Bullet = Bullet;
	}

	/**
	 * Class representing a paragraph.
	 * @constructor
	 * @extends {ApiParaPr}
	 */
	function ApiParagraph(Paragraph)
	{
		ApiParaPr.call(this, this, Paragraph.Pr.Copy());
		this.Paragraph = Paragraph;
	}
	ApiParagraph.prototype = Object.create(ApiParaPr.prototype);
	ApiParagraph.prototype.constructor = ApiParagraph;

	/**
	 * Class representing a table properties.
	 * @constructor
	 */
	function ApiTablePr(Parent, TablePr)
	{
		this.Parent  = Parent;
		this.TablePr = TablePr;
	}

	/**
	 * Class representing a table.
	 * @constructor
	 * @extends {ApiTablePr}
	 */
	function ApiTable(Table)
	{
		ApiTablePr.call(this, this, Table.Pr.Copy());
		this.Table = Table;
	}
	ApiTable.prototype = Object.create(ApiTablePr.prototype);
	ApiTable.prototype.constructor = ApiTable;

	/**
	 * Class representing a text properties.
	 * @constructor
	 */
	function ApiTextPr(Parent, TextPr)
	{
		this.Parent = Parent;
		this.TextPr = TextPr;
	}

	/**
	 * Class representing a small text block calling 'run'.
	 * @constructor
	 * @extends {ApiTextPr}
	 */
	function ApiRun(Run)
	{
		ApiTextPr.call(this, this, Run.Pr.Copy());
		this.Run = Run;
	}
	ApiRun.prototype = Object.create(ApiTextPr.prototype);
	ApiRun.prototype.constructor = ApiRun;

	/**
	 * Class representing a style.
	 * @constructor
	 */
	function ApiStyle(Style)
	{
		this.Style = Style;
	}

	/**
	 * Class representing a document section.
	 * @constructor
	 */
	function ApiSection(Section)
	{
		this.Section = Section;
	}

	/**
	 * Class representing a table row properties.
	 * @constructor
	 */
	function ApiTableRowPr(Parent, RowPr)
	{
		this.Parent = Parent;
		this.RowPr  = RowPr;
	}

	/**
	 * Class representing a table row.
	 * @constructor
	 * @extends {ApiTableRowPr}
	 */
	function ApiTableRow(Row)
	{
		ApiTableRowPr.call(this, this, Row.Pr.Copy());
		this.Row = Row;
	}
	ApiTableRow.prototype = Object.create(ApiTableRowPr.prototype);
	ApiTableRow.prototype.constructor = ApiTableRow;

	/**
	 * Class representing a table cell proprties.
	 * @constructor
	 */
	function ApiTableCellPr(Parent, CellPr)
	{
		this.Parent = Parent;
		this.CellPr = CellPr;
	}
	/**
	 * Class representing a table cell.
	 * @constructor
	 * @extends {ApiTableCellPr}
	 */
	function ApiTableCell(Cell)
	{
		ApiTableCellPr.call(this, this, Cell.Pr.Copy());
		this.Cell = Cell;
	}
	ApiTableCell.prototype = Object.create(ApiTableCellPr.prototype);
	ApiTableCell.prototype.constructor = ApiTableCell;

	/**
	 * Class representing a numbering properties.
	 * @constructor
	 */
	function ApiNumbering(Num)
	{
		this.Num = Num;
	}

	/**
	 * Class representing a reference to a specified level of the numbering.
	 * @constructor
	 */
	function ApiNumberingLevel(Num, Lvl)
	{
		this.Num = Num;
		this.Lvl = Math.max(0, Math.min(8, Lvl));
	}

	/**
	 * Class representing a set of formatting properties which shall be conditionally applied to the parts of a table
	 * which match the requirement specified on the <code>Type</code>.
	 * @constructor
	 */
	function ApiTableStylePr(Type, Parent, TableStylePr)
	{
		this.Type         = Type;
		this.Parent       = Parent;
		this.TableStylePr = TableStylePr;
	}

	/**
	 * Class representing an unsupported element.
	 * @constructor
	 */
	function ApiUnsupported()
	{
	}

	/**
	 * Class representing a graphical object.
	 * @constructor
	 */
	function ApiDrawing(Drawing)
	{
		this.Drawing = Drawing;
	}

	/**
	 * Class representing a image.
	 * @constructor
	 */
	function ApiImage(Image)
	{
		ApiDrawing.call(this, Image.parent);
		this.Image = Image
	}
	ApiImage.prototype = Object.create(ApiDrawing.prototype);
	ApiImage.prototype.constructor = ApiImage;

	/**
	 * Class representing a shape.
	 * @constructor
	 * */
	function ApiShape(Shape)
	{
		ApiDrawing.call(this, Shape.parent);
		this.Shape = Shape;
	}
	ApiShape.prototype = Object.create(ApiDrawing.prototype);
	ApiShape.prototype.constructor = ApiShape;

	/**
	 * Class representing a Chart.
	 * @constructor
	 *
	 */
	function ApiChart(Chart)
	{
		ApiDrawing.call(this, Chart.parent);
		this.Chart = Chart;
	}
	ApiChart.prototype = Object.create(ApiDrawing.prototype);
	ApiChart.prototype.constructor = ApiChart;

	/**
	 * Class representing a base class for color types
	 * @constructor
	 */
	function ApiUniColor(Unicolor)
	{
		this.Unicolor = Unicolor;
	}
	/**
	 * Class representing RGB color
	 * @constructor
	 */
	function ApiRGBColor(r, g, b)
	{
		ApiUniColor.call(this, AscFormat.CreateUniColorRGB(r, g, b));
	}
	ApiRGBColor.prototype = Object.create(ApiUniColor.prototype);
	ApiRGBColor.prototype.constructor = ApiRGBColor;

	/**
	 * Class representing a Scheme Color
	 * @constructor
	 */
	function ApiSchemeColor(sColorId)
	{
		var oUniColor = new AscFormat.CUniColor();
		oUniColor.setColor(new AscFormat.CSchemeColor());
		switch(sColorId)
		{
			case "accent1": {  oUniColor.color.id  = 0; break;}
			case "accent2": {  oUniColor.color.id  = 1; break;}
			case "accent3": {  oUniColor.color.id  = 2; break;}
			case "accent4": {  oUniColor.color.id  = 3; break;}
			case "accent5": {  oUniColor.color.id  = 4; break;}
			case "accent6": {  oUniColor.color.id  = 5; break;}
			case "bg1": {  oUniColor.color.id      = 6; break;}
			case "bg2": {  oUniColor.color.id      = 7; break;}
			case "dk1": {  oUniColor.color.id      = 8; break;}
			case "dk2": {  oUniColor.color.id      = 9; break;}
			case "lt1": {  oUniColor.color.id      = 12; break;}
			case "lt2": {  oUniColor.color.id      = 13; break;}
			case "tx1": {  oUniColor.color.id      = 15; break;}
			case "tx2": {  oUniColor.color.id      = 16; break;}
			default: {  oUniColor.color.id      = 16; break;}
		}
		ApiUniColor.call(this, oUniColor);
	}
	ApiSchemeColor.prototype = Object.create(ApiUniColor.prototype);
	ApiSchemeColor.prototype.constructor = ApiSchemeColor;

	/**
	 * Class representing a Preset Color
	 * @constructor
	 * */
	function ApiPresetColor(sPresetColor)
	{
		var oUniColor = new AscFormat.CUniColor();
		oUniColor.setColor(new AscFormat.CPrstColor());
		oUniColor.color.id = sPresetColor;
		ApiUniColor.call(this, oUniColor);
	}
	ApiPresetColor.prototype = Object.create(ApiUniColor.prototype);
	ApiPresetColor.prototype.constructor = ApiPresetColor;

	/**
	 * Class represent a base class fill
	 * @constructor
	 * */
	function ApiFill(UniFill)
	{
		this.UniFill = UniFill;
	}


	/**
	 * Class represent a stroke class
	 * @constructor
	 */
	function ApiStroke(oLn)
	{
		this.Ln = oLn;
	}


	/**
	 * Class represent gradient stop
	 * @constructor
	 * */
	function ApiGradientStop(oApiUniColor, pos)
	{
		this.Gs = new AscFormat.CGs();
		this.Gs.pos = pos;
		this.Gs.color = oApiUniColor.Unicolor;
	}

	/**
	 * Class represent a container for the elements of a paragraph
	 * @constructor
	 */
	function ApiInlineLvlSdt(Sdt)
	{
		this.Sdt = Sdt;
	}

	/**
	 * Class represent a container for the content of the document
	 * @constructor
	 */
	function ApiBlockLvlSdt(Sdt)
	{
		this.Sdt = Sdt;
	}

	/**
	 * Twentieths of a point (equivalent to 1/1440th of an inch).
	 * @typedef {number} twips
	 */

	/**
	 * @typedef {(ApiParagraph | ApiTable | ApiBlockLvlSdt)} DocumentElement
	 */

	/**
	 * @typedef {("paragraph" | "table" | "run" | "numbering")} StyleType
	 */

	/**
	 * A 240ths of a line.
	 * @typedef {number} line240
	 */

	/**
	 * Half-points.
	 * @typedef {number} hps
	 */

	/**
	 * A numeric value from 0 to 255.
	 * @typedef {number} byte
	 */

	/**
	 *  A numeric value from 0 to 359.
	 * @typedef {number} PositiveFixedAngle
	 * */

	/**
	 * A border type
	 * @typedef {("none" | "single")} BorderType
	 */

	/**
	 * A shade type
	 * @typedef {("nil" | "clear")} ShdType
	 */

	/**
	 * Types of custom tab
	 * @typedef {("clear" | "left" | "right" | "center")} TabJc
	 */

	/**
	 * Eighths of a point (24 eighths of a point = 3 points)
	 * @typedef {number} pt_8
	 */

	/**
	 * point
	 * @typedef {number} pt
	 */

	/**
	 * Header and footer types
	 * @typedef {("default" | "title" | "even")} HdrFtrType
	 */

	/**
	 * The possible values for the units of the width property being defined by a specific table width property.
	 * @typedef {("auto" | "twips" | "nul" | "percent")} TableWidth
	 */

	/**
	 * This simple type specifies possible values for the sections of the table to which the current conditional
	 * formatting properties shall be applied when this table style is used.
	 * <b>"topLeftCell"</b> - Specifies that the table formatting applies to the top left cell. <br/>
	 * <b>"topRightCell"</b> - Specifies that the table formatting applies to the top right cell. <br/>
	 * <b>"bottomLeftCell"</b> - Specifies that the table formatting applies to the bottom left cell.<br/>
	 * <b>"bottomRightCell"</b> - Specifies that the table formatting applies to the bottom right cell.<br/>
	 * <b>"firstRow"</b> - Specifies that the table formatting applies to the first row. <br/>
	 * <b>"lastRow"</b> - Specifies that the table formatting applies to the last row. <br/>
	 * <b>"firstColumn"</b> - Specifies that the table formatting applies to the first column. Any subsequent row which
	 * is in <i>table header</i>{@link ApiTableRowPr#SetTableHeader} shall also use this conditional format.<br/>
	 * <b>"lastColumn"</b> - Specifies that the table formatting applies to the last column. <br/>
	 * <b>"bandedColumn"</b> - Specifies that the table formatting applies to odd numbered groupings of rows.<br/>
	 * <b>"bandedColumnEven"</b> - Specifies that the table formatting applies to even numbered groupings of rows.<br/>
	 * <b>"bandedRow"</b> - Specifies that the table formatting applies to odd numbered groupings of columns.<br/>
	 * <b>"bandedRowEven"</b> - Specifies that the table formatting applies to even numbered groupings of columns.<br/>
	 * <b>"wholeTable"</b> - Specifies that the conditional formatting applies to the whole table.<br/>
	 * @typedef {("topLeftCell" | "topRightCell" | "bottomLeftCell" | "bottomRightCell" | "firstRow" | "lastRow" |
	 *     "firstColumn" | "lastColumn" | "bandedColumn" | "bandedColumnEven" | "bandedRow" | "bandedRowEven" |
	 *     "wholeTable")} TableStyleOverrideType
	 */

	/**
	 * The types of elements that can be in the paragraph
	 * @typedef {(ApiUnsupported | ApiRun | ApiInlineLvlSdt)} ParagraphContent
	 */

	/**
	 * The possible values for the base from which the relative horizontal positioning of an object shall be calculated.
	 * @typedef {("character" | "column" | "leftMargin" | "rightMargin" | "margin" | "page")} RelFromH
	 */

	/**
	 * The possible values for the base from which the relative vertical positioning of an object shall be calculated.
	 * @typedef {("bottomMargin" | "topMargin" | "margin" | "page" | "line" | "paragraph")} RelFromV
	 */

	/**
	 * English measure unit. 1mm = 36000EMUs, 1inch = 914400EMUs
	 * @typedef {number} EMU
	 */

	/**
	 * This type specifies the preset shape geometry that is to be used for a shape
	 * @typedef {("accentBorderCallout1" | "accentBorderCallout2" | "accentBorderCallout3" | "accentCallout1" |
	 *     "accentCallout2" | "accentCallout3" | "actionButtonBackPrevious" | "actionButtonBeginning" |
	 *     "actionButtonBlank" | "actionButtonDocument" | "actionButtonEnd" | "actionButtonForwardNext" |
	 *     "actionButtonHelp" | "actionButtonHome" | "actionButtonInformation" | "actionButtonMovie" |
	 *     "actionButtonReturn" | "actionButtonSound" | "arc" | "bentArrow" | "bentConnector2" | "bentConnector3" |
	 *     "bentConnector4" | "bentConnector5" | "bentUpArrow" | "bevel" | "blockArc" | "borderCallout1" |
	 *     "borderCallout2" | "borderCallout3" | "bracePair" | "bracketPair" | "callout1" | "callout2" | "callout3" |
	 *     "can" | "chartPlus" | "chartStar" | "chartX" | "chevron" | "chord" | "circularArrow" | "cloud" |
	 *     "cloudCallout" | "corner" | "cornerTabs" | "cube" | "curvedConnector2" | "curvedConnector3" |
	 *     "curvedConnector4" | "curvedConnector5" | "curvedDownArrow" | "curvedLeftArrow" | "curvedRightArrow" |
	 *     "curvedUpArrow" | "decagon" | "diagStripe" | "diamond" | "dodecagon" | "donut" | "doubleWave" | "downArrow" | "downArrowCallout" | "ellipse" | "ellipseRibbon" | "ellipseRibbon2" | "flowChartAlternateProcess" | "flowChartCollate" | "flowChartConnector" | "flowChartDecision" | "flowChartDelay" | "flowChartDisplay" | "flowChartDocument" | "flowChartExtract" | "flowChartInputOutput" | "flowChartInternalStorage" | "flowChartMagneticDisk" | "flowChartMagneticDrum" | "flowChartMagneticTape" | "flowChartManualInput" | "flowChartManualOperation" | "flowChartMerge" | "flowChartMultidocument" | "flowChartOfflineStorage" | "flowChartOffpageConnector" | "flowChartOnlineStorage" | "flowChartOr" | "flowChartPredefinedProcess" | "flowChartPreparation" | "flowChartProcess" | "flowChartPunchedCard" | "flowChartPunchedTape" | "flowChartSort" | "flowChartSummingJunction" | "flowChartTerminator" | "foldedCorner" | "frame" | "funnel" | "gear6" | "gear9" | "halfFrame" | "heart" | "heptagon" | "hexagon" | "homePlate" | "horizontalScroll" | "irregularSeal1" | "irregularSeal2" | "leftArrow" | "leftArrowCallout" | "leftBrace" | "leftBracket" | "leftCircularArrow" | "leftRightArrow" | "leftRightArrowCallout" | "leftRightCircularArrow" | "leftRightRibbon" | "leftRightUpArrow" | "leftUpArrow" | "lightningBolt" | "line" | "lineInv" | "mathDivide" | "mathEqual" | "mathMinus" | "mathMultiply" | "mathNotEqual" | "mathPlus" | "moon" | "nonIsoscelesTrapezoid" | "noSmoking" | "notchedRightArrow" | "octagon" | "parallelogram" | "pentagon" | "pie" | "pieWedge" | "plaque" | "plaqueTabs" | "plus" | "quadArrow" | "quadArrowCallout" | "rect" | "ribbon" | "ribbon2" | "rightArrow" | "rightArrowCallout" | "rightBrace" | "rightBracket" | "round1Rect" | "round2DiagRect" | "round2SameRect" | "roundRect" | "rtTriangle" | "smileyFace" | "snip1Rect" | "snip2DiagRect" | "snip2SameRect" | "snipRoundRect" | "squareTabs" | "star10" | "star12" | "star16" | "star24" | "star32" | "star4" | "star5" | "star6" | "star7" | "star8" | "straightConnector1" | "stripedRightArrow" | "sun" | "swooshArrow" | "teardrop" | "trapezoid" | "triangle" | "upArrowCallout" | "upDownArrow" | "upDownArrow" | "upDownArrowCallout" | "uturnArrow" | "verticalScroll" | "wave" | "wedgeEllipseCallout" | "wedgeRectCallout" | "wedgeRoundRectCallout")} ShapeType
	 */

	/**
	 * This type specifies the types, create charts
	 * @typedef {("bar" | "barStacked" | "barStackedPercent" | "bar3D" | "barStacked3D" | "barStackedPercent3D" |
	 *     "barStackedPercent3DPerspective" | "horizontalBar" | "horizontalBarStacked" | "horizontalBarStackedPercent"
	 *     | "horizontalBar3D" | "horizontalBarStacked3D" | "horizontalBarStackedPercent3D" | "lineNormal" |
	 *     "lineStacked" | "lineStackedPercent" | "line3D" | "pie" | "pie3D" | "doughnut" | "scatter" | "stock" |
	 *     "area" | "areaStacked" | "areaStackedPercent")} ChartType
	 */

	/**
	 * @typedef {("top" | "center" | "bottom")} VerticalTextAlign
	 * */

	/**
	 * @typedef {("accent1" | "accent2" | "accent3" | "accent4" | "accent5" | "accent6" | "bg1" | "bg2" | "dk1" | "dk2"
	 *     | "lt1" | "lt2" | "tx1" | "tx2")} SchemeColorId
	 * */

	/**
	 * @typedef {("aliceBlue" | "antiqueWhite" | "aqua" | "aquamarine" | "azure" | "beige" | "bisque" | "black" |
	 *     "blanchedAlmond" | "blue" | "blueViolet" | "brown" | "burlyWood" | "cadetBlue" | "chartreuse" | "chocolate"
	 *     | "coral" | "cornflowerBlue" | "cornsilk" | "crimson" | "cyan" | "darkBlue" | "darkCyan" | "darkGoldenrod" |
	 *     "darkGray" | "darkGreen" | "darkGrey" | "darkKhaki" | "darkMagenta" | "darkOliveGreen" | "darkOrange" |
	 *     "darkOrchid" | "darkRed" | "darkSalmon" | "darkSeaGreen" | "darkSlateBlue" | "darkSlateGray" |
	 *     "darkSlateGrey" | "darkTurquoise" | "darkViolet" | "deepPink" | "deepSkyBlue" | "dimGray" | "dimGrey" |
	 *     "dkBlue" | "dkCyan" | "dkGoldenrod" | "dkGray" | "dkGreen" | "dkGrey" | "dkKhaki" | "dkMagenta" |
	 *     "dkOliveGreen" | "dkOrange" | "dkOrchid" | "dkRed" | "dkSalmon" | "dkSeaGreen" | "dkSlateBlue" |
	 *     "dkSlateGray" | "dkSlateGrey" | "dkTurquoise" | "dkViolet" | "dodgerBlue" | "firebrick" | "floralWhite" |
	 *     "forestGreen" | "fuchsia" | "gainsboro" | "ghostWhite" | "gold" | "goldenrod" | "gray" | "green" |
	 *     "greenYellow" | "grey" | "honeydew" | "hotPink" | "indianRed" | "indigo" | "ivory" | "khaki" | "lavender" | "lavenderBlush" | "lawnGreen" | "lemonChiffon" | "lightBlue" | "lightCoral" | "lightCyan" | "lightGoldenrodYellow" | "lightGray" | "lightGreen" | "lightGrey" | "lightPink" | "lightSalmon" | "lightSeaGreen" | "lightSkyBlue" | "lightSlateGray" | "lightSlateGrey" | "lightSteelBlue" | "lightYellow" | "lime" | "limeGreen" | "linen" | "ltBlue" | "ltCoral" | "ltCyan" | "ltGoldenrodYellow" | "ltGray" | "ltGreen" | "ltGrey" | "ltPink" | "ltSalmon" | "ltSeaGreen" | "ltSkyBlue" | "ltSlateGray" | "ltSlateGrey" | "ltSteelBlue" | "ltYellow" | "magenta" | "maroon" | "medAquamarine" | "medBlue" | "mediumAquamarine" | "mediumBlue" | "mediumOrchid" | "mediumPurple" | "mediumSeaGreen" | "mediumSlateBlue" | "mediumSpringGreen" | "mediumTurquoise" | "mediumVioletRed" | "medOrchid" | "medPurple" | "medSeaGreen" | "medSlateBlue" | "medSpringGreen" | "medTurquoise" | "medVioletRed" | "midnightBlue" | "mintCream" | "mistyRose" | "moccasin" | "navajoWhite" | "navy" | "oldLace" | "olive" | "oliveDrab" | "orange" | "orangeRed" | "orchid" | "paleGoldenrod" | "paleGreen" | "paleTurquoise" | "paleVioletRed" | "papayaWhip" | "peachPuff" | "peru" | "pink" | "plum" | "powderBlue" | "purple" | "red" | "rosyBrown" | "royalBlue" | "saddleBrown" | "salmon" | "sandyBrown" | "seaGreen" | "seaShell" | "sienna" | "silver" | "skyBlue" | "slateBlue" | "slateGray" | "slateGrey" | "snow" | "springGreen" | "steelBlue" | "tan" | "teal" | "thistle" | "tomato" | "turquoise" | "violet" | "wheat" | "white" | "whiteSmoke" | "yellow" | "yellowGreen")} PresetColor
	 * */


	/**
	 *
	 * @typedef {("none" | "nextTo" | "low" | "high")} TickLabelPosition
	 * **/

	/**
	 * @typedef {"tile" | "stretch"} BlipFillType
	 * */

	/**
	 * @typedef {"cross" | "dashDnDiag" | "dashHorz" | "dashUpDiag" | "dashVert" | "diagBrick" | "diagCross" | "divot"
	 *     | "dkDnDiag" | "dkHorz" | "dkUpDiag" | "dkVert" | "dnDiag" | "dotDmnd" | "dotGrid" | "horz" | "horzBrick" |
	 *     "lgCheck" | "lgConfetti" | "lgGrid" | "ltDnDiag" | "ltHorz" | "ltUpDiag" | "ltVert" | "narHorz" | "narVert"
	 *     | "openDmnd" | "pct10" | "pct20" | "pct25" | "pct30" | "pct40" | "pct5" | "pct50" | "pct60" | "pct70" |
	 *     "pct75" | "pct80" | "pct90" | "plaid" | "shingle" | "smCheck" | "smConfetti" | "smGrid" | "solidDmnd" |
	 *     "sphere" | "trellis" | "upDiag" | "vert" | "wave" | "wdDnDiag" | "wdUpDiag" | "weave" | "zigZag"}
	 *     PatternType
	 * */

	/**
	 *
	 * @typedef {"unlocked" | "contentLocked" | "sdtContentLocked" | "sdtLocked"} SdtLock
	 */
	//------------------------------------------------------------------------------------------------------------------
	//
	// Base Api
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * @typedef {number} PositivePercentage
	 * */

	/**
	 * Get main document
	 * @memberof Api
	 * @typeofeditors ["CDE"]
	 * @returns {ApiDocument}
	 */


	/**
	 * @typedef {("cross" | "in" | "none" | "out")} TickMark
	 * */

	Api.prototype.GetDocument = function()
	{
		return new ApiDocument(this.WordControl.m_oLogicDocument);
	};
	/**
	 * Create a new paragraph.
	 * @memberof Api
	 * @typeofeditors ["CDE", "CSE"]
	 * @returns {ApiParagraph}
	 */
	Api.prototype.CreateParagraph = function()
	{
		return new ApiParagraph(new Paragraph(private_GetDrawingDocument(), private_GetLogicDocument()));
	};
	/**
	 * Create a new table with a specified number of rows and columns.
	 * @memberof Api
	 * @typeofeditors ["CDE"]
	 * @param {number} nCols - Number of columns.
	 * @param {number} nRows - Number of rows.
	 * @returns {ApiTable}
	 */
	Api.prototype.CreateTable = function(nCols, nRows)
	{
		if (!nRows || nRows <= 0 || !nCols || nCols <= 0)
			return null;

		var oTable = new CTable(private_GetDrawingDocument(), private_GetLogicDocument(), true, nRows, nCols, [], false);
		oTable.CorrectBadGrid();
		oTable.Set_TableW(undefined);
		oTable.Set_TableStyle2(undefined);
		return new ApiTable(oTable);
	};
	/**
	 * Create a new smaller text block to be inserted to the current paragraph or table.
	 * @memberof Api
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {ApiRun}
	 */
	Api.prototype.CreateRun = function()
	{
		return new ApiRun(new ParaRun(null, false));
	};

	/**
	 * Create an image with the parameters specified.
	 * @memberof Api
	 * @typeofeditors ["CDE"]
	 * @param {string} sImageSrc - The image source where the image to be inserted should be taken from (currently only internet URL or Base64 encoded images are supported).
	 * @param {EMU} nWidth - The image width in English measure units.
	 * @param {EMU} nHeight - The image height in English measure units.
	 * @returns {ApiImage}
	 */
	Api.prototype.CreateImage = function(sImageSrc, nWidth, nHeight)
	{
		var nW = private_EMU2MM(nWidth);
		var nH = private_EMU2MM(nHeight);

		var oDrawing = new ParaDrawing(nW, nH, null, private_GetDrawingDocument(), private_GetLogicDocument(), null);
		var oImage = private_GetLogicDocument().DrawingObjects.createImage(sImageSrc, 0, 0, nW, nH);
		oImage.setParent(oDrawing);
		oDrawing.Set_GraphicObject(oImage);
		return new ApiImage(oImage);
	};

	/**
	 * Create a shape with the parameters specified.
	 * @memberof Api
	 * @typeofeditors ["CDE"]
	 * @param {ShapeType} [sType="rect"] - The shape type which specifies the preset shape geometry.
	 * @param {EMU} nWidth - The shape width in English measure units.
	 * @param {EMU} nHeight - The shape height in English measure units.
	 * @param {ApiFill} oFill - The color or pattern used to fill the shape.
	 * @param {ApiStroke} oStroke - The stroke used to create the element shadow.
	 * @returns {ApiShape}
	 * */
	Api.prototype.CreateShape = function(sType, nWidth, nHeight, oFill, oStroke)
	{
		var oLogicDocument = private_GetLogicDocument();
		var oDrawingDocuemnt = private_GetDrawingDocument();
		var nW = private_EMU2MM(nWidth);
		var nH = private_EMU2MM(nHeight);
		var oDrawing = new ParaDrawing(nW, nH, null, oDrawingDocuemnt, oLogicDocument, null);
		var oShapeTrack = new AscFormat.NewShapeTrack(sType, 0, 0, oLogicDocument.theme, null, null, null, 0);
		oShapeTrack.track({}, nW, nH);
		var oShape = oShapeTrack.getShape(true, oDrawingDocuemnt, null);
		oShape.setParent(oDrawing);
		oDrawing.Set_GraphicObject(oShape);
		oShape.createTextBoxContent();
		oShape.spPr.setFill(oFill.UniFill);
		oShape.spPr.setLn(oStroke.Ln);
		return new ApiShape(oShape);
	};

	/**
	 * Create a chart with the parameters specified.
	 * @memberof Api
	 * @typeofeditors ["CDE"]
	 * @param {ChartType} [sType="bar"] - The chart type used for the chart display.
	 * @param {Array} aSeries - The array of the data used to build the chart from.
	 * @param {Array} aSeriesNames - The array of the names (the source table column names) used for the data which the chart will be build from.
	 * @param {Array} aCatNames - The array of the names (the source table row names) used for the data which the chart will be build from.
	 * @param {EMU} nWidth - The chart width in English measure units.
	 * @param {EMU} nHeight - The chart height in English measure units.
	 * @param {number} nStyleIndex - The chart color style index (can be 1 - 48, as described in OOXML specification).
	 * @returns {ApiChart}
	 * */
	Api.prototype.CreateChart = function(sType, aSeries, aSeriesNames, aCatNames, nWidth, nHeight, nStyleIndex)
	{
		var oDrawingDocument = private_GetDrawingDocument();
		var oLogicDocument = private_GetLogicDocument();
		var nW = private_EMU2MM(nWidth);
		var nH = private_EMU2MM(nHeight);
		var settings = new Asc.asc_ChartSettings();
		switch (sType)
		{
			case "bar" :
			{
				settings.type = Asc.c_oAscChartTypeSettings.barNormal;
				break;
			}
			case "barStacked":
			{
				settings.type = Asc.c_oAscChartTypeSettings.barStacked;
				break;
			}
			case "barStackedPercent":
			{
				settings.type = Asc.c_oAscChartTypeSettings.barStackedPer;
				break;
			}
			case "bar3D":
			{
				settings.type = Asc.c_oAscChartTypeSettings.barNormal3d;
				break;
			}
			case "barStacked3D":
			{
				settings.type = Asc.c_oAscChartTypeSettings.barStacked3d;
				break;
			}
			case "barStackedPercent3D":
			{
				settings.type = Asc.c_oAscChartTypeSettings.barStackedPer3d;
				break;
			}
			case "barStackedPercent3DPerspective":
			{
				settings.type = Asc.c_oAscChartTypeSettings.barNormal3dPerspective;
				break;
			}
			case "horizontalBar":
			{
				settings.type = Asc.c_oAscChartTypeSettings.hBarNormal;
				break;
			}
			case "horizontalBarStacked":
			{
				settings.type = Asc.c_oAscChartTypeSettings.hBarStacked;
				break;
			}
			case "horizontalBarStackedPercent":
			{
				settings.type = Asc.c_oAscChartTypeSettings.hBarStackedPer;
				break;
			}
			case "horizontalBar3D":
			{
				settings.type = Asc.c_oAscChartTypeSettings.hBarNormal3d;
				break;
			}
			case "horizontalBarStacked3D":
			{
				settings.type = Asc.c_oAscChartTypeSettings.hBarStacked3d;
				break;
			}
			case "horizontalBarStackedPercent3D":
			{
				settings.type = Asc.c_oAscChartTypeSettings.hBarStackedPer3d;
				break;
			}
			case "lineNormal":
			{
				settings.type = Asc.c_oAscChartTypeSettings.lineNormal;
				break;
			}
			case "lineStacked":
			{
				settings.type = Asc.c_oAscChartTypeSettings.lineStacked;
				break;
			}
			case "lineStackedPercent":
			{
				settings.type = Asc.c_oAscChartTypeSettings.lineStackedPer;
				break;
			}
			case "line3D":
			{
				settings.type = Asc.c_oAscChartTypeSettings.line3d;
				break;
			}
			case "pie":
			{
				settings.type = Asc.c_oAscChartTypeSettings.pie;
				break;
			}
			case "pie3D":
			{
				settings.type = Asc.c_oAscChartTypeSettings.pie3d;
				break;
			}
			case "doughnut":
			{
				settings.type = Asc.c_oAscChartTypeSettings.doughnut;
				break;
			}
			case "scatter":
			{
				settings.type = Asc.c_oAscChartTypeSettings.scatter;
				break;
			}
			case "stock":
			{
				settings.type = Asc.c_oAscChartTypeSettings.stock;
				break;
			}
			case "area":
			{
				settings.type = Asc.c_oAscChartTypeSettings.areaNormal;
				break;
			}
			case "areaStacked":
			{
				settings.type = Asc.c_oAscChartTypeSettings.areaStacked;
				break;
			}
			case "areaStackedPercent":
			{
				settings.type = Asc.c_oAscChartTypeSettings.areaStackedPer;
				break;
			}
		}
		var aAscSeries = [];
		var aAlphaBet = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
		var oCat, i;
		if(aCatNames.length > 0)
		{
			var aNumCache = [];
			for(i = 0; i < aCatNames.length; ++i)
			{
				aNumCache.push({val: aCatNames[i] + ""});
			}
			oCat = { Formula: "Sheet1!$B$1:$" + AscFormat.CalcLiterByLength(aAlphaBet, aCatNames.length) + "$1", NumCache: aNumCache };
		}
		for(i = 0; i < aSeries.length; ++i)
		{
			var oAscSeries = new AscFormat.asc_CChartSeria();
			oAscSeries.Val.NumCache = [];
			var aData = aSeries[i];
			var sEndLiter = AscFormat.CalcLiterByLength(aAlphaBet, aData.length);
			oAscSeries.Val.Formula = 'Sheet1!' + '$B$' + (i + 2) + ':$' + sEndLiter + '$' + (i + 2);
			if(aSeriesNames[i])
			{
				oAscSeries.TxCache.Formula =  'Sheet1!' + '$A$' + (i + 2);
				oAscSeries.TxCache.Tx = aSeriesNames[i];
			}
			if(oCat)
			{
				oAscSeries.Cat = oCat;
			}
			for(var j = 0; j < aData.length; ++j)
			{

				oAscSeries.Val.NumCache.push({ numFormatStr: "General", isDateTimeFormat: false, val: aData[j], isHidden: false });
			}
			aAscSeries.push(oAscSeries);
		}
		var chartSeries = {series: aAscSeries, parsedHeaders: {bLeft: true, bTop: true}};
		var oDrawing = new ParaDrawing( nW, nH, null, oDrawingDocument, null, null);
		var oChartSpace = AscFormat.DrawingObjectsController.prototype._getChartSpace(chartSeries, settings, true);
		if(!oChartSpace)
		{
			return null;
		}
		oChartSpace.setParent(oDrawing);
		oDrawing.Set_GraphicObject(oChartSpace);
		oChartSpace.setBDeleted(false);
		oChartSpace.extX = nW;
		oChartSpace.extY = nH;
		if(AscFormat.isRealNumber(nStyleIndex)){
			oChartSpace.setStyle(nStyleIndex);
		}
		AscFormat.CheckSpPrXfrm(oChartSpace);
		oDrawing.setExtent( oChartSpace.spPr.xfrm.extX, oChartSpace.spPr.xfrm.extY );
		return new ApiChart(oChartSpace);
	};

	/**
	 * Create an RGB color setting the appropriate values for the red, green and blue color components.
	 * @memberof Api
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 * @returns {ApiRGBColor}
	 */
	Api.prototype.CreateRGBColor = function(r, g, b)
	{
		return new ApiRGBColor(r, g, b);
	};

	/**
	 * Create a complex color scheme selecting from one of the available schemes.
	 * @memberof Api
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {SchemeColorId} sSchemeColorId - The color scheme identifier.
	 * @returns {ApiSchemeColor}
	 */
	Api.prototype.CreateSchemeColor = function(sSchemeColorId)
	{
		return new ApiSchemeColor(sSchemeColorId);
	};

	/**
	 * Create a color selecting it from one of the available color presets.
	 * @memberof Api
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {PresetColor} sPresetColor - A preset selected from the list of the available color preset names.
	 * @returns {ApiPresetColor};
	 * */
	Api.prototype.CreatePresetColor = function(sPresetColor)
	{
		return new ApiPresetColor(sPresetColor);
	};

	/**
	 * Create a solid fill which allows to fill the object using a selected solid color as the object background.
	 * @memberof Api
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {ApiUniColor} oUniColor - The color used for the element fill.
	 * @returns {ApiFill}
	 * */
	Api.prototype.CreateSolidFill = function(oUniColor)
	{
		return new ApiFill(AscFormat.CreateUniFillByUniColor(oUniColor.Unicolor));
	};

	/**
	 * Create a linear gradient fill which allows to fill the object using a selected linear gradient as the object background.
	 * @memberof Api
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {Array} aGradientStop - The angle measured in 60000th of a degree that will define the gradient direction.
	 * @param {PositiveFixedAngle} Angle - The angle measured in 60000th of a degree that will define the gradient direction.
	 * @returns {ApiFill}
	 */
	Api.prototype.CreateLinearGradientFill = function(aGradientStop, Angle)
	{
		return new ApiFill(AscFormat.builder_CreateLinearGradient(aGradientStop, Angle));
	};


	/**
	 * Create a radial gradient fill which allows to fill the object using a selected radial gradient as the object background.
	 * @memberof Api
	 * @typeofeditors ["CDE", "CPE"]
	 * @param {Array} aGradientStop - The array of gradient color stops measured in 1000th of percent.
	 * @returns {ApiFill}
	 */
	Api.prototype.CreateRadialGradientFill = function(aGradientStop)
	{
		return new ApiFill(AscFormat.builder_CreateRadialGradient(aGradientStop));
	};

	/**
	 * Create a pattern fill which allows to fill the object using a selected pattern as the object background.
	 * @memberof Api
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {PatternType} sPatternType - The pattern type used for the fill selected from one of the available pattern types.
	 * @param {ApiUniColor} BgColor - The background color used for the pattern creation.
	 * @param {ApiUniColor} FgColor - The foreground color used for the pattern creation.
	 * @returns {ApiFill}
	 */
	Api.prototype.CreatePatternFill = function(sPatternType, BgColor, FgColor)
	{
		return new ApiFill(AscFormat.builder_CreatePatternFill(sPatternType, BgColor, FgColor));
	};

	/**
	 * Create a blip fill which allows to fill the object using a selected image as the object background.
	 * @memberof Api
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {string} sImageUrl - The path to the image used for the blip fill (currently only internet URL or Base64 encoded images are supported).
	 * @param {BlipFillType} sBlipFillType - The type of the fill used for the blip fill (tile or stretch).
	 * @returns {ApiFill}
	 * */
	Api.prototype.CreateBlipFill = function(sImageUrl, sBlipFillType)
	{
		return new ApiFill(AscFormat.builder_CreateBlipFill(sImageUrl, sBlipFillType));
	};

	/**
	 * Create no fill and remove the fill from the element.
	 * @memberof Api
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {ApiFill}
	 * */
	Api.prototype.CreateNoFill = function()
	{
		return new ApiFill(AscFormat.CreateNoFillUniFill());
	};

	/**
	 * Create a stroke adding shadows to the element.
	 * @memberof Api
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {EMU} nWidth - The width of the shadow measured in English measure units.
	 * @param {ApiFill} oFill - The fill type used to create the shadow.
	 * @returns {ApiStroke}
	 * */
	Api.prototype.CreateStroke = function(nWidth, oFill)
	{
		return new ApiStroke(AscFormat.builder_CreateLine(nWidth, oFill));
	};

	/**
	 * Create a gradient stop used for different types of gradients.
	 * @memberof Api
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {ApiUniColor} oUniColor - The color used for the gradient stop.
	 * @param {PositivePercentage} nPos - The position of the gradient stop measured in 1000th of percent.
	 * @returns {ApiGradientStop}
	 * */
	Api.prototype.CreateGradientStop = function(oUniColor, nPos)
	{
		return new ApiGradientStop(oUniColor, nPos);
	};

	/**
	 * Create a bullet for a paragraph with the character or symbol specified with the sBullet parameter.
	 * @memberof Api
	 * @typeofeditors ["CSE", "CPE"]
	 * @param {string} sSymbol - The character or symbol which will be used to create the bullet for the paragraph.
	 * @returns {ApiBullet}
	 * */
	Api.prototype.CreateBullet = function(sSymbol){
		var oBullet = new AscFormat.CBullet();
		oBullet.bulletType = new AscFormat.CBulletType();
		if(typeof sSymbol === "string" && sSymbol.length > 0){
			oBullet.bulletType.type = AscFormat.BULLET_TYPE_BULLET_CHAR;
			oBullet.bulletType.Char = sSymbol[0];
		}
		else{
			oBullet.bulletType.type = AscFormat.BULLET_TYPE_BULLET_NONE;
		}
		return new ApiBullet(oBullet);
	};

	/**
	 * Create a bullet for a paragraph with the character or symbol specified with the sType parameter.
	 * @memberof Api
	 * @typeofeditors ["CSE", "CPE"]
	 * @param {BulletType} sType - The numbering type the paragraphs will be numbered with.
	 * @param {number} nStartAt - The number the first numbered paragraph will start with.
	 * @returns {ApiBullet}
	 * */

	Api.prototype.CreateNumbering = function(sType, nStartAt){
		var oBullet = new AscFormat.CBullet();
		oBullet.bulletType = new AscFormat.CBulletType();
		oBullet.bulletType.type = AscFormat.BULLET_TYPE_BULLET_AUTONUM;
		switch(sType){
			case "ArabicPeriod" :{
				oBullet.bulletType.AutoNumType = 12;
				break;
			}
			case "ArabicParenR":{
				oBullet.bulletType.AutoNumType = 11;
				break;
			}
			case "RomanUcPeriod":{
				oBullet.bulletType.AutoNumType = 34;
				break;
			}
			case "RomanLcPeriod":{
				oBullet.bulletType.AutoNumType = 31;
				break;
			}
			case "AlphaLcParenR":{
				oBullet.bulletType.AutoNumType = 1;
				break;
			}
			case "AlphaLcPeriod":{
				oBullet.bulletType.AutoNumType = 2;
				break;
			}
			case "AlphaUcParenR":{
				oBullet.bulletType.AutoNumType = 4;
				break;
			}
			case "AlphaUcPeriod":{
				oBullet.bulletType.AutoNumType = 5;
				break;
			}
			case "None":{
				oBullet.bulletType.type = AscFormat.BULLET_TYPE_BULLET_NONE;
				break;
			}
		}
		if( oBullet.bulletType.type === AscFormat.BULLET_TYPE_BULLET_AUTONUM){
			if(AscFormat.isRealNumber(nStartAt)){
				oBullet.bulletType.startAt = nStartAt;
			}
		}
		return new ApiBullet(oBullet);
	};

	/**
	 * Create a new inline container
	 * @returns {ApiInlineLvlSdt}
	 */
	Api.prototype.CreateInlineLvlSdt = function()
	{
		var oSdt = new CInlineLevelSdt();
		oSdt.Add_ToContent(0, new ParaRun(null, false));
		return new ApiInlineLvlSdt(oSdt);
	};

	/**
	 * Create a new block level container
	 * @returns {ApiBlockLvlSdt}
	 */
	Api.prototype.CreateBlockLvlSdt = function()
	{
		return new ApiBlockLvlSdt(new CBlockLvlSdt());
	};
	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiUnsupported
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE"]
	 * @returns {"unsupported"}
	 */
	ApiUnsupported.prototype.GetClassType = function()
	{
		return "unsupported";
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiDocumentContent
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {"documentContent"}
	 */
	ApiDocumentContent.prototype.GetClassType = function()
	{
		return "documentContent";
	};
	/**
	 * Get the number of elements in the current document.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {number}
	 */
	ApiDocumentContent.prototype.GetElementsCount = function()
	{
		return this.Document.Content.length;
	};
	/**
	 * Get the element by its position in the document.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {?DocumentElement}
	 */
	ApiDocumentContent.prototype.GetElement = function(nPos)
	{
		if (!this.Document.Content[nPos])
			return null;

		var Type = this.Document.Content[nPos].GetType();
		if (type_Paragraph === Type)
			return new ApiParagraph(this.Document.Content[nPos]);
		else if (type_Table === Type)
			return new ApiTable(this.Document.Content[nPos]);
		else if (type_BlockLevelSdt === Type)
			return new ApiBlockLvlSdt(this.Document.Content[nPos]);

		return null;
	};
	/**
	 * Add paragraph or table using its position in the document.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {number} nPos - The position where the current element will be added.
	 * @param {DocumentElement} oElement - The document element which will be added at the current position.
	 */
	ApiDocumentContent.prototype.AddElement = function(nPos, oElement)
	{
		if (oElement instanceof ApiParagraph || oElement instanceof ApiTable || oElement instanceof ApiBlockLvlSdt)
		{
			this.Document.Internal_Content_Add(nPos, oElement.private_GetImpl());
		}
	};
	/**
	 * Push a paragraph or a table to actually add it to the document.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {DocumentElement} oElement - The type of the element which will be pushed to the document.
	 */
	ApiDocumentContent.prototype.Push = function(oElement)
	{
		if (oElement instanceof ApiParagraph || oElement instanceof ApiTable)
		{
			this.Document.Internal_Content_Add(this.Document.Content.length, oElement.private_GetImpl());
			return true;
		}

		return false;
	};
	/**
	 * Remove all elements from the current document or from the current document element.
	 * <note>When all elements are removed, a new empty paragraph is automatically created. If you want to add
	 * content to this paragraph, use the ApiDocumentContent.GetElement method.</note>
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 */
	ApiDocumentContent.prototype.RemoveAllElements = function()
	{
		this.Document.Internal_Content_Remove(0, this.Document.Content.length);
	};
	/**
	 * Remove element using the position specified.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {number} nPos - The element number (position) in the document or inside other element.
	 */
	ApiDocumentContent.prototype.RemoveElement = function(nPos)
	{
		if (nPos < 0 || nPos >= this.GetElementsCount())
			return;

		this.Document.Internal_Content_Remove(nPos, 1);
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiDocument
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE"]
	 * @returns {"document"}
	 */
	ApiDocument.prototype.GetClassType = function()
	{
		return "document";
	};
	/**
	 * Create new history point.
	 */
	ApiDocument.prototype.CreateNewHistoryPoint = function()
	{
		this.Document.Create_NewHistoryPoint(AscDFH.historydescription_Document_ApiBuilder);
	};
	/**
	 * Get a style by the style name.
	 * @typeofeditors ["CDE"]
	 * @param {string} sStyleName - The name using which it is possible to address the style.
	 * @returns {?ApiStyle}
	 */
	ApiDocument.prototype.GetStyle = function(sStyleName)
	{
		var oStyles  = this.Document.Get_Styles();
		var oStyleId = oStyles.GetStyleIdByName(sStyleName, true);
		return new ApiStyle(oStyles.Get(oStyleId));
	};
	/**
	 * Create a new style with the specified type and name. If there is a style with the same name it will be replaced with a new one.
	 * with a new one.
	 * @typeofeditors ["CDE"]
	 * @param {string} sStyleName - The name of the style which will be created.
	 * @param {StyleType} [sType="paragraph"] - The document element which the style will be applied to.
	 * @returns {ApiStyle}
	 */
	ApiDocument.prototype.CreateStyle = function(sStyleName, sType)
	{
		var nStyleType = styletype_Paragraph;
		if ("paragraph" === sType)
			nStyleType = styletype_Paragraph;
		else if ("table" === sType)
			nStyleType = styletype_Table;
		else if ("run" === sType)
			nStyleType = styletype_Character;
		else if ("numbering" === sType)
			nStyleType = styletype_Numbering;

		var oStyle        = new CStyle(sStyleName, null, null, nStyleType, false);
		oStyle.qFormat    = true;
		oStyle.uiPriority = 1;
		var oStyles       = this.Document.Get_Styles();

		// Если у нас есть стиль с данным именем, тогда мы старый стиль удаляем, а новый добавляем со старым Id,
		// чтобы если были ссылки на старый стиль - теперь они стали на новый.
		var sOldId    = oStyles.GetStyleIdByName(sStyleName);
		var oOldStyle = oStyles.Get(sOldId);
		if (null != sOldId && oOldStyle)
		{
			oStyles.Remove(sOldId);
			oStyles.RemapIdReferences(sOldId, oStyle.Get_Id());
		}

		oStyles.Add(oStyle);
		return new ApiStyle(oStyle);
	};
	/**
	 * Get the default style parameters for the specified document element.
	 * @typeofeditors ["CDE"]
	 * @param {StyleType} sStyleType - The document element which we want to get the style for.
	 * @returns {?ApiStyle}
	 */
	ApiDocument.prototype.GetDefaultStyle = function(sStyleType)
	{
		var oStyles = this.Document.Get_Styles();

		if ("paragraph" === sStyleType)
			return new ApiStyle(oStyles.Get(oStyles.Get_Default_Paragraph()));
		else if ("table" === sStyleType)
			return new ApiStyle(oStyles.Get(oStyles.Get_Default_Table()));
		else if ("run" === sStyleType)
			return new ApiStyle(oStyles.Get(oStyles.Get_Default_Character()));
		else if ("numbering" === sStyleType)
			return new ApiStyle(oStyles.Get(oStyles.Get_Default_Numbering()));

		return null;
	};
	/**
	 * Get a set of default properties for the text run in the current document.
	 * @typeofeditors ["CDE"]
	 * @returns {ApiTextPr}
	 */
	ApiDocument.prototype.GetDefaultTextPr = function()
	{
		var oStyles = this.Document.Get_Styles();
		return new ApiTextPr(this, oStyles.Get_DefaultTextPr().Copy());
	};
	/**
	 * Get a set of default paragraph properties in the current document.
	 * @typeofeditors ["CDE"]
	 * @returns {ApiParaPr}
	 */
	ApiDocument.prototype.GetDefaultParaPr = function()
	{
		var oStyles = this.Document.Get_Styles();
		return new ApiParaPr(this, oStyles.Get_DefaultParaPr().Copy());
	};
	/**
	 * Get document final section
	 * @typeofeditors ["CDE"]
	 * @return {ApiSection}
	 */
	ApiDocument.prototype.GetFinalSection = function()
	{
		return new ApiSection(this.Document.SectPr);
	};
	/**
	 * Create a new document section which ends at the specified paragraph. Allows to set local parameters for the current
	 * section - page size, footer, header, columns, etc.
	 * @typeofeditors ["CDE"]
	 * @param {ApiParagraph} oParagraph - The paragraph after which the new document section will be inserted.
	 * @returns {ApiSection}
	 */
	ApiDocument.prototype.CreateSection = function(oParagraph)
	{
		if (!(oParagraph instanceof ApiParagraph))
			return null;

		var oSectPr = new CSectionPr(this.Document);
		oParagraph.private_GetImpl().Set_SectionPr(oSectPr);
		return new ApiSection(oSectPr);
	};

	/**
	 * Specify whether sections in this document will have different headers and footers for even and
	 * odd pages (one header/footer for odd pages and another header/footer for even pages).
	 * @typeofeditors ["CDE"]
	 * @param {boolean} isEvenAndOdd - If true the header/footer will be different for odd and even pages, if false they will be the same.
	 */
	ApiDocument.prototype.SetEvenAndOddHdrFtr = function(isEvenAndOdd)
	{
		this.Document.Set_DocumentEvenAndOddHeaders(isEvenAndOdd);
	};
	/**
	 * Create an abstract multilevel numbering with a specified type.
	 * @typeofeditors ["CDE"]
	 * @param {("bullet" | "numbered")} [sType="bullet"] - The type of the numbering which will be created.
	 * @returns {ApiNumbering}
	 */
	ApiDocument.prototype.CreateNumbering = function(sType)
	{
		var oGlobalNumbering = this.Document.GetNumbering();
		var oNum             = oGlobalNumbering.CreateNum();

		if ("numbered" === sType)
			oNum.CreateDefault(c_oAscMultiLevelNumbering.Numbered);
		else
			oNum.CreateDefault(c_oAscMultiLevelNumbering.Bullet);

		return new ApiNumbering(oNum);
	};

	/**
	 * Insert an array of elements in the current position of the document.
	 * @param {DocumentElement[]} arrContent - An array of elements to insert.
	 * @param {boolean} [isInline=false] - Inline insert on not (works only when the length of arrContent = 1 and it's a paragraph)
	 * @returns {boolean} Success?
	 */
	ApiDocument.prototype.InsertContent = function(arrContent, isInline)
	{
		var oSelectedContent = new CSelectedContent();
		for (var nIndex = 0, nCount = arrContent.length; nIndex < nCount; ++nIndex)
		{
			var oElement = arrContent[nIndex];
			if (oElement instanceof ApiParagraph || oElement instanceof ApiTable)
			{
				if (true === isInline && 1 === nCount && oElement instanceof ApiParagraph)
					oSelectedContent.Add(new CSelectedElement(oElement.private_GetImpl(), false));
				else
					oSelectedContent.Add(new CSelectedElement(oElement.private_GetImpl(), true));
			}
		}
		oSelectedContent.On_EndCollectElements(this.Document, true);

		if (this.Document.IsSelectionUse())
		{
			this.Document.Start_SilentMode();
			this.Document.Remove(1, false, false, false);
			this.Document.End_SilentMode();
			this.Document.RemoveSelection(true);
		}

		var oParagraph = this.Document.GetCurrentParagraph();
		if (!oParagraph)
			return;

		var oNearestPos = {
			Paragraph  : oParagraph,
			ContentPos : oParagraph.Get_ParaContentPos(false, false)
		};

		oParagraph.Check_NearestPos(oNearestPos);

		if (!this.Document.Can_InsertContent(oSelectedContent, oNearestPos))
			return false;

		oParagraph.Parent.Insert_Content(oSelectedContent, oNearestPos);
		oParagraph.Clear_NearestPosArray();
		this.Document.RemoveSelection(true);
		return true;
	};

	/**
	 * Get a report about all the comments added to the document.
	 * @typeofeditors ["CDE"]
	 * @returns {object}
	 */
	ApiDocument.prototype.GetCommentsReport = function()
	{
		var oResult = {};
		var oReport = this.Document.Api.asc_GetCommentsReportByAuthors();
		for (var sUserName in oReport)
		{
			var arrUserComments = oReport[sUserName];
			oResult[sUserName] = [];

			for (var nIndex = 0, nCount = arrUserComments.length; nIndex < nCount; ++nIndex)
			{
				var isAnswer     = oReport[sUserName][nIndex].Top ? false : true;
				var oCommentData = oReport[sUserName][nIndex].Data;

				if (isAnswer)
				{
					oResult[sUserName].push({
						"IsAnswer"       : true,
						"CommentMessage" : oCommentData.GetText(),
						"Date"           : oCommentData.GetDateTime()
					});
				}
				else
				{
					var sQuoteText = oCommentData.GetQuoteText();
					oResult[sUserName].push({
						"IsAnswer"       : false,
						"CommentMessage" : oCommentData.GetText(),
						"Date"           : oCommentData.GetDateTime(),
						"QuoteText"      : sQuoteText,
						"IsSolved"       : oCommentData.IsSolved()
					});
				}
			}
		}

		return oResult;
	};

	/**
	 * Get a report about every change which was made to the document in the review mode.
	 * @typeofeditors ["CDE"]
	 * @returns {object}
	 */
	ApiDocument.prototype.GetReviewReport = function()
	{
		var oResult = {};
		var oReport = this.Document.Api.asc_GetTrackRevisionsReportByAuthors();
		for (var sUserName in oReport)
		{
			var arrUsersChanges = oReport[sUserName];
			oResult[sUserName] = [];

			for (var nIndex = 0, nCount = arrUsersChanges.length; nIndex < nCount; ++nIndex)
			{
				var oChange = oReport[sUserName][nIndex];

				var nType = oChange.get_Type();
				var oElement = {};
				// TODO: Посмотреть почем Value приходит массивом.
				if (c_oAscRevisionsChangeType.TextAdd === nType)
				{
					oElement = {
						"Type" : "TextAdd",
						"Value" : oChange.get_Value().length ? oChange.get_Value()[0] : ""
					};
				}
				else if (c_oAscRevisionsChangeType.TextRem == nType)
				{
					oElement = {
						"Type" : "TextRem",
						"Value" : oChange.get_Value().length ? oChange.get_Value()[0] : ""
					};
				}
				else if (c_oAscRevisionsChangeType.ParaAdd === nType)
				{
					oElement = {
						"Type" : "ParaAdd"
					};
				}
				else if (c_oAscRevisionsChangeType.ParaRem === nType)
				{
					oElement = {
						"Type" : "ParaRem"
					};
				}
				else if (c_oAscRevisionsChangeType.TextPr === nType)
				{
					oElement = {
						"Type" : "TextPr"
					};
				}
				else if (c_oAscRevisionsChangeType.ParaPr === nType)
				{
					oElement = {
						"Type" : "ParaPr"
					};
				}
				else
				{
					oElement = {
						"Type" : "Unknown"
					};
				}
				oElement["Date"] = oChange.get_DateTime();
				oResult[sUserName].push(oElement);
			}
		}
		return oResult;
	};
	/**
	 * Find and replace text.
	 * @param {Object} oProperties The properties for find and replace.
	 * @param {string} oProperties.searchString Search string.
	 * @param {string} oProperties.replaceString Replacement string.
	 * @param {string} [oProperties.matchCase=true]
	 *
	 */
	ApiDocument.prototype.SearchAndReplace = function(oProperties)
	{
		var sSearch     = oProperties["searchString"];
		var sReplace    = oProperties["replaceString"];
		var isMatchCase = undefined !== oProperties["matchCase"] ? oProperties.matchCase : true;

		var oSearchEngine = this.Document.Search(sSearch, {MatchCase : isMatchCase});
		if (!oSearchEngine)
			return;

		this.Document.Search_Replace(sReplace, true, null, false);
	};
	/**
	 * Get the list of all content controls in the document
	 * @returns {ApiBlockLvlSdt[] | ApiInlineLvlSdt[]}
	 */
	ApiDocument.prototype.GetAllContentControls = function()
	{
		var arrResult = [];
		var arrControls = this.Document.GetAllContentControls();
		for (var nIndex = 0, nCount = arrControls.length; nIndex < nCount; ++nIndex)
		{
			var oControl = arrControls[nIndex];

			if (oControl instanceof CBlockLevelSdt)
				arrResult.push(new ApiBlockLvlSdt(oControl));
			else if (oControl instanceof CInlineLevelSdt)
				arrResult.push(new ApiInlineLvlSdt(oControl));
		}

		return arrResult;
	};
	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiParagraph
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Insert watermark on each page of document
	 * @param {?string} [sText="WATERMARK"]
	 * @param {?boolean} [bIsDiagonal=true]
	 */
	ApiDocument.prototype.InsertWatermark = function(sText, bIsDiagonal){
		var oSectPrMap = {};
		if(this.Document.SectPr){
			oSectPrMap[this.Document.SectPr.Get_Id()] = this.Document.SectPr;
		}
		var oElement;
		for(var i = 0; i < this.Document.Content.length; ++i){
			oElement = this.Document.Content[i];
			if(oElement instanceof Paragraph){
				if(oElement.SectPr){
					oSectPrMap[oElement.SectPr.Get_Id()] = oElement.SectPr;
				}
			}
		}
		var oHeadersMap = {};
		var oApiSection, oHeader;
		for(var sId in oSectPrMap){
			if(oSectPrMap.hasOwnProperty(sId)){
				oApiSection = new ApiSection(oSectPrMap[sId]);
				oHeader = oApiSection.GetHeader("title", false);
				if(oHeader){
					oHeadersMap[oHeader.Document.Get_Id()] = oHeader;
				}
				oHeader = oApiSection.GetHeader("even", false);
				if(oHeader){
					oHeadersMap[oHeader.Document.Get_Id()] = oHeader;
				}
				oHeader = oApiSection.GetHeader("default", true);
				if(oHeader){
					oHeadersMap[oHeader.Document.Get_Id()] = oHeader;
				}
			}
		}
		for(var sId in oHeadersMap){
			if(oHeadersMap.hasOwnProperty(sId)){
				privateInsertWatermarkToContent(this.Document.Api, oHeadersMap[sId], sText, bIsDiagonal);
			}
		}
	};
	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {"document"}
	 */
	ApiParagraph.prototype.GetClassType = function()
	{
		return "paragraph";
	};
	/**
	 * Add some text to the element.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {string} [sText=""] - The text that we want to insert into the current document element.
	 * @returns {ApiRun}
	 */
	ApiParagraph.prototype.AddText = function(sText)
	{
		var oRun = new ParaRun(this.Paragraph, false);

		if (!sText || !sText.length)
			return new ApiRun(oRun);

		oRun.AddText(sText);

		private_PushElementToParagraph(this.Paragraph, oRun);
		return new ApiRun(oRun);
	};
	/**
	 * Add page break and start the next element from the next page.
	 * @typeofeditors ["CDE"]
	 * @returns {ApiRun}
	 */
	ApiParagraph.prototype.AddPageBreak = function()
	{
		var oRun = new ParaRun(this.Paragraph, false);
		oRun.Add_ToContent(0, new ParaNewLine(break_Page));
		private_PushElementToParagraph(this.Paragraph, oRun);
		return new ApiRun(oRun);
	};
	/**
	 * Add line break to the current position and start the next element from a new line.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {ApiRun}
	 */
	ApiParagraph.prototype.AddLineBreak = function()
	{
		var oRun = new ParaRun(this.Paragraph, false);
		oRun.Add_ToContent(0, new ParaNewLine(break_Line));
		private_PushElementToParagraph(this.Paragraph, oRun);
		return new ApiRun(oRun);
	};

	/**
	 * Add column break to the current position and start the next element from a new column.
	 * @typeofeditors ["CDE"]
	 * @returns {ApiRun}
	 */
	ApiParagraph.prototype.AddColumnBreak = function()
	{
		var oRun = new ParaRun(this.Paragraph, false);
		oRun.Add_ToContent(0, new ParaNewLine(break_Column));
		private_PushElementToParagraph(this.Paragraph, oRun);
		return new ApiRun(oRun);
	};
	/**
	 * Insert the number of the current document page into the paragraph.
	 * @typeofeditors ["CDE"]
	 * <note>This method works for the paragraphs in the document header/footer only.</note>
	 * @returns {ApiRun}
	 */
	ApiParagraph.prototype.AddPageNumber = function()
	{
		var oRun = new ParaRun(this.Paragraph, false);
		oRun.Add_ToContent(0, new ParaPageNum());
		private_PushElementToParagraph(this.Paragraph, oRun);
		return new ApiRun(oRun);
	};
	/**
	 * Insert the number of pages in the current document into the paragraph.
	 * @typeofeditors ["CDE"]
	 * <note>This method works for the paragraphs in the document header/footer only.</note>
	 * @returns {ApiRun}
	 */
	ApiParagraph.prototype.AddPagesCount = function()
	{
		var oRun = new ParaRun(this.Paragraph, false);
		oRun.Add_ToContent(0, new ParaPageCount());
		private_PushElementToParagraph(this.Paragraph, oRun);
		return new ApiRun(oRun);
	};
	/**
	 * Get the text properties of the paragraph mark which is used to mark the paragraph end. The mark can also acquire
	 * common text properties like bold, italic, underline, etc.
	 * @typeofeditors ["CDE"]
	 * @returns {ApiTextPr}
	 */
	ApiParagraph.prototype.GetParagraphMarkTextPr = function()
	{
		return new ApiTextPr(this, this.Paragraph.TextPr.Value.Copy());
	};
	/**
	 * Get paragraph properties.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {ApiParaPr}
	 */
	ApiParagraph.prototype.GetParaPr = function()
	{
		return new ApiParaPr(this, this.Paragraph.Pr.Copy());
	};
	/**
	 * Get a numbering definition and numbering level for the numbered list.
	 * @typeofeditors ["CDE"]
	 * @returns {?ApiNumberingLevel}
	 */
	ApiParagraph.prototype.GetNumbering = function()
	{
		var oNumPr = this.Paragraph.GetNumPr();
		if (!oNumPr)
			return null;

		var oLogicDocument   = private_GetLogicDocument();
		var oGlobalNumbering = oLogicDocument.GetNumbering();
		var oNum             = oGlobalNumbering.GetNum(oNumPr.NumId);
		if (!oNum)
			return null;

		return new ApiNumberingLevel(oNumbering, oNumPr.Lvl);
	};
	/**
	 * Specifies that the current paragraph references a numbering definition instance in the current document.
	 * @typeofeditors ["CDE"]
	 * @see Same as {@link ApiParagraph#SetNumPr}
	 * @param {ApiNumberingLevel} oNumberingLevel
	 */
	ApiParagraph.prototype.SetNumbering = function(oNumberingLevel)
	{
		if (!(oNumberingLevel instanceof ApiNumberingLevel))
			return;

		this.SetNumPr(oNumberingLevel.GetNumbering(), oNumberingLevel.GetLevelIndex());
	};
	/**
	 * Get the number of elements in the current paragraph.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {number}
	 */
	ApiParagraph.prototype.GetElementsCount = function()
	{
		// TODO: ParaEnd
		return this.Paragraph.Content.length - 1;
	};
	/**
	 * Get the element of the paragraph using the position specified.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {number} nPos - The position where the element which content we want to get must be located.
	 * @returns {?ParagraphContent}
	 */
	ApiParagraph.prototype.GetElement = function(nPos)
	{
		// TODO: ParaEnd
		if (nPos < 0 || nPos >= this.Paragraph.Content.length - 1)
			return null;

		return private_GetSupportedParaElement(this.Paragraph.Content[nPos]);
	};
	/**
	 * Remove the element using the position specified.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {number} nPos - The position of the element which we want to remove in the paragraph.
	 */
	ApiParagraph.prototype.RemoveElement = function(nPos)
	{
		if (nPos < 0 || nPos >= this.Paragraph.Content.length - 1)
			return;

		this.Paragraph.Remove_FromContent(nPos, 1);
	};
	/**
	 * Remove all elements from the current paragraph.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 */
	ApiParagraph.prototype.RemoveAllElements = function()
	{
		if (this.Paragraph.Content.length > 1)
			this.Paragraph.Remove_FromContent(0, this.Paragraph.Content.length - 1);
	};
	/**
	 * Add an element to the current paragraph.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {ParagraphContent} oElement - The document element which will be added at the current position. Returns false if the
	 * type of oElement is not supported by a paragraph.
	 * @param {number} [nPos] The number of the paragraph where the current element will be added. If this value is not
	 * specified then the element will be added at the end of the current paragraph.
	 * @returns {boolean} Returns <code>false</code> if the type of <code>oElement</code> is not supported by paragraph
	 * content.
	 */
	ApiParagraph.prototype.AddElement = function(oElement, nPos)
	{
		// TODO: ParaEnd
		if (!private_IsSupportedParaElement(oElement) || nPos < 0 || nPos > this.Paragraph.Content.length - 1)
			return false;

		var oParaElement = oElement.private_GetImpl();
		if (undefined !== nPos)
		{
			this.Paragraph.Add_ToContent(nPos, oParaElement);
		}
		else
		{
			private_PushElementToParagraph(this.Paragraph, oParaElement);
		}

		return true;
	};
	/**
	 * Add a tab stop to the current paragraph.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {ApiRun}
	 */
	ApiParagraph.prototype.AddTabStop = function()
	{
		var oRun = new ParaRun(this.Paragraph, false);
		oRun.Add_ToContent(0, new ParaTab());
		private_PushElementToParagraph(this.Paragraph, oRun);
		return new ApiRun(oRun);
	};
	/**
	 * Add an object (image, shape or chart) to the current paragraph.
	 * @typeofeditors ["CDE"]
	 * @param {ApiDrawing} oDrawing - The object which will be added to the current paragraph.
	 * @returns {ApiRun}
	 */
	ApiParagraph.prototype.AddDrawing = function(oDrawing)
	{
		var oRun = new ParaRun(this.Paragraph, false);

		if (!(oDrawing instanceof ApiDrawing))
			return new ApiRun(oRun);

		oRun.Add_ToContent(0, oDrawing.Drawing);
		private_PushElementToParagraph(this.Paragraph, oRun);
		return new ApiRun(oRun);
	};

	/**
	 * Add a inline container
	 * @param {ApiInlineLvlSdt?} oSdt - if undefined or null, then new class ApiInlineLvlSdt will be created and added to paragraph.
	 * @returns {ApiInlineLvlSdt}
	 */
	ApiParagraph.prototype.AddInlineLvlSdt = function(oSdt)
	{
		if (!oSdt || !(oSdt instanceof ApiInlineLvlSdt))
		{
			var _oSdt = new CInlineLevelSdt();
			_oSdt.Add_ToContent(0, new ParaRun(null, false));
			oSdt = new ApiInlineLvlSdt(_oSdt);
		}

		private_PushElementToParagraph(this.Paragraph, oSdt.Sdt);
		return oSdt;
	};
	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiRun
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE", "CPE"]
	 * @returns {"run"}
	 */
	ApiRun.prototype.GetClassType = function()
	{
		return "run";
	};
	/**
	 * Get the text properties of the current run.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {ApiTextPr}
	 */
	ApiRun.prototype.GetTextPr = function()
	{
		return new ApiTextPr(this, this.Run.Pr.Copy());
	};
	/**
	 * Remove all content from the current run.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 */
	ApiRun.prototype.ClearContent = function()
	{
		this.Run.Remove_FromContent(0, this.Run.Content.length);
	};
	/**
	 * Add some text to this run.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {string} sText - The text which will be added to the current run.
	 */
	ApiRun.prototype.AddText = function(sText)
	{
		if (!sText || !sText.length)
			return;

		this.Run.AddText(sText);
	};
	/**
	 * Add a page break and start the next element from a new page.
	 * @typeofeditors ["CDE"]
	 */
	ApiRun.prototype.AddPageBreak = function()
	{
		this.Run.Add_ToContent(this.Run.Content.length, new ParaNewLine(break_Page));
	};
	/**
	 * Add a line break to the current run position and start the next element from a new line.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 */
	ApiRun.prototype.AddLineBreak = function()
	{
		this.Run.Add_ToContent(this.Run.Content.length, new ParaNewLine(break_Line));
	};
	/**
	 * Add a column break to the current run position and start the next element from a new column.
	 * @typeofeditors ["CDE"]
	 */
	ApiRun.prototype.AddColumnBreak = function()
	{
		this.Run.Add_ToContent(this.Run.Content.length, new ParaNewLine(break_Column));
	};
	/**
	 * Add a tab stop to the current run.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 */
	ApiRun.prototype.AddTabStop = function()
	{
		this.Run.Add_ToContent(this.Run.Content.length, new ParaTab());
	};
	/**
	 * Add an object (image, shape or chart) to the current text run.
	 * @param {ApiDrawing} oDrawing - The object which will be added to the current run.
	 * @typeofeditors ["CDE"]
	 */
	ApiRun.prototype.AddDrawing = function(oDrawing)
	{
		if (!(oDrawing instanceof ApiDrawing))
			return;

		this.Run.Add_ToContent(this.Run.Content.length, oDrawing.Drawing);
	};


	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiSection
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE"]
	 * @returns {"section"}
	 */
	ApiSection.prototype.GetClassType = function()
	{
		return "section";
	};
	/**
	 * Specify the section type of the current section. The section type specifies how the contents of the current
	 * section shall be placed relative to the previous section.<br/>
	 * WordprocessingML supports five distinct types of section breaks:<br/>
	 *   * <b>Next page</b> section breaks (the default if type is not specified), which begin the new section on the
	 *   following page.<br/>
	 *   * <b>Odd</b> page section breaks, which begin the new section on the next odd-numbered page.<br/>
	 *   * <b>Even</b> page section breaks, which begin the new section on the next even-numbered page.<br/>
	 *   * <b>Continuous</b> section breaks, which begin the new section on the following paragraph. This means that
	 *   continuous section breaks might not specify certain page-level section properties, since they shall be
	 *   inherited from the following section. These breaks, however, can specify other section properties, such
	 *   as line numbering and footnote/endnote settings.<br/>
	 *   * <b>Column</b> section breaks, which begin the new section on the next column on the page.
	 *   @typeofeditors ["CDE"]
	 * @param {("nextPage" | "oddPage" | "evenPage" | "continuous" | "nextColumn")} sType - Type of the section break
	 */
	ApiSection.prototype.SetType = function(sType)
	{
		if ("oddPage" === sType)
			this.Section.Set_Type(c_oAscSectionBreakType.OddPage);
		else if ("evenPage" === sType)
			this.Section.Set_Type(c_oAscSectionBreakType.EvenPage);
		else if ("continuous" === sType)
			this.Section.Set_Type(c_oAscSectionBreakType.Continuous);
		else if ("nextColumn" === sType)
			this.Section.Set_Type(c_oAscSectionBreakType.Column);
		else if ("nextPage" === sType)
			this.Section.Set_Type(c_oAscSectionBreakType.NextPage);
	};
	/**
	 * Specify that all text columns in the current section are of equal width.
	 * @typeofeditors ["CDE"]
	 * @param {number} nCount - Number of columns.
	 * @param {twips} nSpace - Distance between columns measured in twentieths of a point (1/1440 of an inch).
	 */
	ApiSection.prototype.SetEqualColumns = function(nCount, nSpace)
	{
		this.Section.Set_Columns_EqualWidth(true);
		this.Section.Set_Columns_Num(nCount);
		this.Section.Set_Columns_Space(private_Twips2MM(nSpace));
	};
	/**
	 * Set all columns of this section are of different widths. Count of columns are equal length of
	 * <code>aWidth</code> array. The length of <code>aSpaces</code> array <b>MUST BE</b> (<code>aWidth.length -
	 * 1</code>).
	 * @typeofeditors ["CDE"]
	 * @param {twips[]} aWidths - An array of column width values measured in twentieths of a point (1/1440 of an inch).
	 * @param {twips[]} aSpaces - An array of distances values between the columns measured in twentieths of a point (1/1440 of an inch).
	 */
	ApiSection.prototype.SetNotEqualColumns = function(aWidths, aSpaces)
	{
		if (!aWidths || !aWidths.length || aWidths.length <= 1 || aSpaces.length !== aWidths.length - 1)
			return;

		this.Section.Set_Columns_EqualWidth(false);
		var aCols = [];
		for (var nPos = 0, nCount = aWidths.length; nPos < nCount; ++nPos)
		{
			var SectionColumn   = new CSectionColumn();
			SectionColumn.W     = private_Twips2MM(aWidths[nPos]);
			SectionColumn.Space = private_Twips2MM(nPos !== nCount - 1 ? aSpaces[nPos] : 0);
			aCols.push(SectionColumn);
		}

		this.Section.Set_Columns_Cols(aCols);
		this.Section.Set_Columns_Num(aCols.length);
	};
	/**
	 * Specify the properties (size and orientation) for all pages in the current section.
	 * @typeofeditors ["CDE"]
	 * @param {twips} nWidth - The page width measured in twentieths of a point (1/1440 of an inch).
	 * @param {twips} nHeight - The page height measured in twentieths of a point (1/1440 of an inch).
	 * @param {boolean} [isPortrait=false] - Specifies the orientation of all pages in this section (if set to true then the portrait orientation is chosen).
	 */
	ApiSection.prototype.SetPageSize = function(nWidth, nHeight, isPortrait)
	{
		this.Section.Set_PageSize(private_Twips2MM(nWidth), private_Twips2MM(nHeight));
		this.Section.Set_Orientation(false === isPortrait ? Asc.c_oAscPageOrientation.PageLandscape : Asc.c_oAscPageOrientation.PagePortrait, false);
	};
	/**
	 * Specify the page margins for all pages in this section.
	 * @typeofeditors ["CDE"]
	 * @param {twips} nLeft - The left margin width measured in twentieths of a point (1/1440 of an inch).
	 * @param {twips} nTop - The top margin height measured in twentieths of a point (1/1440 of an inch).
	 * @param {twips} nRight - The right margin width measured in twentieths of a point (1/1440 of an inch).
	 * @param {twips} nBottom - The bottom margin height measured in twentieths of a point (1/1440 of an inch).
	 */
	ApiSection.prototype.SetPageMargins = function(nLeft, nTop, nRight, nBottom)
	{
		this.Section.Set_PageMargins(private_Twips2MM(nLeft), private_Twips2MM(nTop), private_Twips2MM(nRight), private_Twips2MM(nBottom));
	};
	/**
	 * Specify the distance from the top edge of the page to the top edge of the header.
	 * @typeofeditors ["CDE"]
	 * @param {twips} nDistance - The distance from the top edge of the page to the top edge of the header measured in twentieths of a point (1/1440 of an inch).
	 */
	ApiSection.prototype.SetHeaderDistance = function(nDistance)
	{
		this.Section.Set_PageMargins_Header(private_Twips2MM(nDistance));
	};
	/**
	 * Specify the distance from the bottom edge of the page to the bottom edge of the footer.
	 * footer.
	 * @typeofeditors ["CDE"]
	 * @param {twips} nDistance - The distance from the bottom edge of the page to the bottom edge of the footer measured
	 * in twentieths of a point (1/1440 of an inch).
	 */
	ApiSection.prototype.SetFooterDistance = function(nDistance)
	{
		this.Section.Set_PageMargins_Footer(private_Twips2MM(nDistance));
	};
	/**
	 * Get the content for the specified header type.
	 * @typeofeditors ["CDE"]
	 * @param {HdrFtrType} sType - Type of header to get the content from.
	 * @param {boolean} [isCreate=false] - Whether to create a new header or not with the specified header type in case
	 * no header with such a type could be found in the current section.
	 * @returns {?ApiDocumentContent}
	 */
	ApiSection.prototype.GetHeader = function(sType, isCreate)
	{
		var oHeader = null;

		if ("title" === sType)
			oHeader = this.Section.Get_Header_First();
		else if ("even" === sType)
			oHeader = this.Section.Get_Header_Even();
		else if ("default" === sType)
			oHeader = this.Section.Get_Header_Default();
		else
			return null;

		if (null === oHeader && true === isCreate)
		{
			var oLogicDocument = private_GetLogicDocument();
			oHeader            = new CHeaderFooter(oLogicDocument.Get_HdrFtr(), oLogicDocument, oLogicDocument.Get_DrawingDocument(), hdrftr_Header);
			if ("title" === sType)
				this.Section.Set_Header_First(oHeader);
			else if ("even" === sType)
				this.Section.Set_Header_Even(oHeader);
			else if ("default" === sType)
				this.Section.Set_Header_Default(oHeader);
		}
		if(!oHeader){
			return null;
		}
		return new ApiDocumentContent(oHeader.Get_DocumentContent());
	};
	/**
	 * Remove the header of the specified type from the current section. After removal the header will be inherited from
	 * the previous section or, if this is the first section in the document, no header of the specified type will be present.
	 * @typeofeditors ["CDE"]
	 * @param {HdrFtrType} sType - Type of header to be removed.
	 */
	ApiSection.prototype.RemoveHeader = function(sType)
	{
		if ("title" === sType)
			this.Section.Set_Header_First(null);
		else if ("even" === sType)
			this.Section.Set_Header_Even(null);
		else if ("default" === sType)
			this.Section.Set_Header_Default(null);
	};
	/**
	 * Get the content for the specified footer type.
	 * @typeofeditors ["CDE"]
	 * @param {HdrFtrType} sType - Type of footer to get the content from.
	 * @param {boolean} [isCreate=false] - Whether to create a new footer or not with the specified footer type in case
	 * no footer with such a type could be found in the current section.
	 * @returns {?ApiDocumentContent}
	 */
	ApiSection.prototype.GetFooter = function(sType, isCreate)
	{
		var oFooter = null;

		if ("title" === sType)
			oFooter = this.Section.Get_Footer_First();
		else if ("even" === sType)
			oFooter = this.Section.Get_Footer_Even();
		else if ("default" === sType)
			oFooter = this.Section.Get_Footer_Default();
		else
			return null;

		if (null === oFooter && true === isCreate)
		{
			var oLogicDocument = private_GetLogicDocument();
			oFooter            = new CHeaderFooter(oLogicDocument.Get_HdrFtr(), oLogicDocument, oLogicDocument.Get_DrawingDocument(), hdrftr_Footer);
			if ("title" === sType)
				this.Section.Set_Footer_First(oFooter);
			else if ("even" === sType)
				this.Section.Set_Footer_Even(oFooter);
			else if ("default" === sType)
				this.Section.Set_Footer_Default(oFooter);
		}

		return new ApiDocumentContent(oFooter.Get_DocumentContent());
	};
	/**
	 * Remove a footer of the specified type from the current section. After removing the footer will be inherited from
	 * the previous section or, if this is the first section in the document, there won't be no footer of the specified
	 * type.
	 * @typeofeditors ["CDE"]
	 * @param {HdrFtrType} sType - Type of footer.
	 */
	ApiSection.prototype.RemoveFooter = function(sType)
	{
		if ("title" === sType)
			this.Section.Set_Footer_First(null);
		else if ("even" === sType)
			this.Section.Set_Footer_Even(null);
		else if ("default" === sType)
			this.Section.Set_Footer_Default(null);
	};
	/**
	 * Specify whether the current section in this document have different header and footer for the section first page.
	 * @typeofeditors ["CDE"]
	 * @param {boolean} isTitlePage - If true the first page of the section will have header and footer that will differ from the other pages of the same section.
	 */
	ApiSection.prototype.SetTitlePage = function(isTitlePage)
	{
		this.Section.Set_TitlePage(private_GetBoolean(isTitlePage));
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiTable
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE"]
	 * @returns {"table"}
	 */
	ApiTable.prototype.GetClassType = function()
	{
		return "table";
	};
	/**
	 * Get the number of rows in the current table.
	 * @typeofeditors ["CDE"]
	 */
	ApiTable.prototype.GetRowsCount = function()
	{
		return this.Table.Content.length;
	};
	/**
	 * Get the table row by its position in the table.
	 * @param {number} nPos - The row position within the tabl
	 * @returns {ApiTableRow}
	 */
	ApiTable.prototype.GetRow = function(nPos)
	{
		if (nPos < 0 || nPos >= this.Table.Content.length)
			return null;

		return new ApiTableRow(this.Table.Content[nPos]);
	};
	/**
	 * Merge array of cells. If merge was done successfully it will return merged cell, otherwise "null".
	 * <note><b>Please note</b>: the number of cells in any row and the number of rows in the current table may be changed.</note>
	 * @typeofeditors ["CDE"]
	 * @param {ApiTableCell[]} aCells
	 * @returns {?ApiTableCell}
	 */
	ApiTable.prototype.MergeCells = function(aCells)
	{
		private_StartSilentMode();
		this.private_PrepareTableForActions();

		var oTable            = this.Table;
		oTable.Selection.Use  = true;
		oTable.Selection.Type = table_Selection_Cell;
		oTable.Selection.Data = [];

		for (var nPos = 0, nCount = aCells.length; nPos < nCount; ++nPos)
		{
			var oCell = aCells[nPos].Cell;
			var oPos  = {Cell : oCell.Index, Row : oCell.Row.Index};

			var nResultPos    = 0;
			var nResultLength = oTable.Selection.Data.length;
			for (nResultPos = 0; nResultPos < nResultLength; ++nResultPos)
			{
				var oCurPos = oTable.Selection.Data[nResultPos];
				if (oCurPos.Row < oPos.Row)
				{
					continue;
				}
				else if (oCurPos.Row > oPos.Row)
				{
					break;
				}
				else
				{
					if (oCurPos.Cell < oPos.Cell)
						continue;
					else
						break;
				}
			}

			oTable.Selection.Data.splice(nResultPos, 0, oPos);
		}

		var isMerged = this.Table.MergeTableCells(true);
		var oMergedCell = this.Table.CurCell;
		oTable.RemoveSelection();

		private_EndSilentMode();

		if (true === isMerged)
			return new ApiTableCell(oMergedCell);

		return null;
	};
	/**
	 * Set table style.
	 * @typeofeditors ["CDE"]
	 * @param {ApiStyle} oStyle
	 */
	ApiTable.prototype.SetStyle = function(oStyle)
	{
		if (!oStyle || !(oStyle instanceof ApiStyle) || styletype_Table !== oStyle.Style.Get_Type())
			return;

		this.Table.Set_TableStyle(oStyle.Style.Get_Id(), true);
	};
	/**
	 * Specify the components of the conditional formatting of the referenced table style (if one exists)
	 * which shall be applied to the set of table rows with the current table-level property exceptions. A table style
	 * can specify up to six different optional conditional formats [Example: Different formatting for first column.
	 * end example], which then can be applied or omitted from individual table rows in the parent table.
	 *
	 * The default setting is to apply the row and column banding formatting, but not the first row, last row, first
	 * column, or last column formatting.
	 * @typeofeditors ["CDE"]
	 * @param {boolean} isFirstColumn - Specifies that the first column conditional formatting will be applied to the table.
	 * @param {boolean} isFirstRow - Specifies that the first row conditional formatting will be applied to the table.
	 * @param {boolean} isLastColumn - Specifies that the last column conditional formatting will be applied to the table.
	 * @param {boolean} isLastRow - Specifies that the last row conditional formatting will be applied to the table.
	 * @param {boolean} isHorBand - Specifies that the horizontal banding conditional formatting will not be applied to the table.
	 * @param {boolean} isVerBand - Specifies that the vertical banding conditional formatting will not be applied to the table.
	 */
	ApiTable.prototype.SetTableLook = function(isFirstColumn, isFirstRow, isLastColumn, isLastRow, isHorBand, isVerBand)
	{
		var oTableLook = new CTableLook(private_GetBoolean(isFirstColumn),
			private_GetBoolean(isFirstRow),
			private_GetBoolean(isLastColumn),
			private_GetBoolean(isLastRow),
			private_GetBoolean(isHorBand),
			private_GetBoolean(isVerBand));
		this.Table.Set_TableLook(oTableLook);
	};
	/**
	 * Add a new row to the current table.
	 * @typeofeditors ["CDE"]
	 * @param {ApiTableCell} [oCell] - The cell after which the new row will be added. If not specified the new row will
	 * be added at the end of the table.
	 * @param {boolean} [isBefore=false] - Add a new row before or after the specified cell. If no cell is specified then
	 * this parameter will be ignored.
	 * @returns {ApiTableRow}
	 */
	ApiTable.prototype.AddRow = function(oCell, isBefore)
	{
		private_StartSilentMode();
		this.private_PrepareTableForActions();

		var _isBefore = private_GetBoolean(isBefore, false);
		var _oCell = (oCell instanceof ApiTableCell ? oCell.Cell : undefined);
		if (_oCell && this.Table !== _oCell.Row.Table)
			_oCell = undefined;

		if (!_oCell)
		{
			_oCell = this.Table.Content[this.Table.Content.length - 1].Get_Cell(0);
			_isBefore = false;
		}

		var nRowIndex = true === _isBefore ? _oCell.Row.Index : _oCell.Row.Index + 1;

		this.Table.RemoveSelection();
		this.Table.CurCell = _oCell;
		this.Table.AddTableRow(_isBefore);

		private_EndSilentMode();
		return new ApiTableRow(this.Table.Content[nRowIndex]);
	};
	/**
	 * Add a new column to the current table.
	 * @typeofeditors ["CDE"]
	 * @param {ApiTableCell} [oCell] - The cell after which the new column will be added. If not specified the new column will be added at the end of the table.
	 * @param {boolean} [isBefore=false] - Add a new column before or after the specified cell. If no cell is specified
	 * then this parameter will be ignored.
	 */
	ApiTable.prototype.AddColumn = function(oCell, isBefore)
	{
		private_StartSilentMode();
		this.private_PrepareTableForActions();

		var _isBefore = private_GetBoolean(isBefore, false);
		var _oCell = (oCell instanceof ApiTableCell ? oCell.Cell : undefined);
		if (_oCell && this.Table !== _oCell.Row.Table)
			_oCell = undefined;

		if (!_oCell)
		{
			_oCell = this.Table.Content[0].Get_Cell(this.Table.Content[0].Get_CellsCount() - 1);
			_isBefore = false;
		}

		this.Table.RemoveSelection();
		this.Table.CurCell = _oCell;
		this.Table.AddTableColumn(_isBefore);

		private_EndSilentMode();
	};
	/**
	 * Remove the table row with a specified cell.
	 * @typeofeditors ["CDE"]
	 * @param {ApiTableCell} oCell - The cell which is present in the row that will be removed.
	 * @returns {boolean} Is the table empty after removing.
	 */
	ApiTable.prototype.RemoveRow = function(oCell)
	{
		if (!(oCell instanceof ApiTableCell) || this.Table !== oCell.Cell.Row.Table)
			return false;

		private_StartSilentMode();
		this.private_PrepareTableForActions();

		this.Table.RemoveSelection();
		this.Table.CurCell = oCell.Cell;
		var isEmpty = !(this.Table.RemoveTableRow());

		private_EndSilentMode();
		return isEmpty;
	};
	/**
	 * Remove the table column with a specified cell.
	 * @typeofeditors ["CDE"]
	 * @param {ApiTableCell} oCell - The cell which is present in the column that will be removed.
	 * @returns {boolean} Is the table empty after removing.
	 */
	ApiTable.prototype.RemoveColumn = function(oCell)
	{
		if (!(oCell instanceof ApiTableCell) || this.Table !== oCell.Cell.Row.Table)
			return false;

		private_StartSilentMode();
		this.private_PrepareTableForActions();

		this.Table.RemoveSelection();
		this.Table.CurCell = oCell.Cell;
		var isEmpty = !(this.Table.RemoveTableColumn());

		private_EndSilentMode();
		return isEmpty;
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiTableRow
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE"]
	 * @returns {"tableRow"}
	 */
	ApiTableRow.prototype.GetClassType = function()
	{
		return "tableRow";
	};
	/**
	 * Get the number of cells in the current row.
	 * @typeofeditors ["CDE"]
	 * @returns {number}
	 */
	ApiTableRow.prototype.GetCellsCount = function()
	{
		return this.Row.Content.length;
	};
	/**
	 * Get the cell by its position.
	 * @typeofeditors ["CDE"]
	 * @param {number} nPos - The cell position in the current table.
	 * @returns {ApiTableCell}
	 */
	ApiTableRow.prototype.GetCell = function(nPos)
	{
		if (nPos < 0 || nPos >= this.Row.Content.length)
			return null;

		return new ApiTableCell(this.Row.Content[nPos]);
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiTableCell
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE"]
	 * @returns {"tableCell"}
	 */
	ApiTableCell.prototype.GetClassType = function()
	{
		return "tableCell";
	};
	/**
	 * Get cell content.
	 * @typeofeditors ["CDE"]
	 * @returns {ApiDocumentContent}
	 */
	ApiTableCell.prototype.GetContent = function()
	{
		return new ApiDocumentContent(this.Cell.Content);
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiStyle
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE"]
	 * @returns {"style"}
	 */
	ApiStyle.prototype.GetClassType = function()
	{
		return "style";
	};
	/**
	 * Get the name of the current style.
	 * @typeofeditors ["CDE"]
	 * @returns {string}
	 */
	ApiStyle.prototype.GetName = function()
	{
		return this.Style.Get_Name();
	};
	/**
	 * Set the name of the current style.
	 * @typeofeditors ["CDE"]
	 * @param {string} sStyleName - The name which will be used for the current style.
	 */
	ApiStyle.prototype.SetName = function(sStyleName)
	{
		this.Style.Set_Name(sStyleName);
	};
	/**
	 * Get the type of the current style.
	 * @typeofeditors ["CDE"]
	 * @returns {StyleType}
	 */
	ApiStyle.prototype.GetType = function()
	{
		var nStyleType = this.Style.Get_Type();

		if (styletype_Paragraph === nStyleType)
			return "paragraph";
		else if (styletype_Table === nStyleType)
			return "table";
		else if (styletype_Character === nStyleType)
			return "run";
		else if (styletype_Numbering === nStyleType)
			return "numbering";

		return "paragraph";
	};
	/**
	 * Get the text properties of the current style.
	 * @typeofeditors ["CDE"]
	 * @returns {ApiTextPr}
	 */
	ApiStyle.prototype.GetTextPr = function()
	{
		return new ApiTextPr(this, this.Style.TextPr.Copy());
	};
	/**
	 * Get the paragraph properties of the current style.
	 * @typeofeditors ["CDE"]
	 * @returns {ApiParaPr}
	 */
	ApiStyle.prototype.GetParaPr = function()
	{
		return new ApiParaPr(this, this.Style.ParaPr.Copy());
	};
	/**
	 * Get the table properties of the current style.
	 * @typeofeditors ["CDE"]
	 * @returns {?ApiTablePr} If the type of this style is not a <code>"table"</code> then it will return
	 *     <code>null</code>.
	 */
	ApiStyle.prototype.GetTablePr = function()
	{
		if (styletype_Table !== this.Style.Get_Type())
			return null;

		return new ApiTablePr(this, this.Style.TablePr.Copy());
	};
	/**
	 * Get the table row properties of the current style.
	 * @typeofeditors ["CDE"]
	 * @returns {?ApiTableRowPr} If the type of this style is not a <code>"table"</code> then it will return
	 *     <code>null</code>.
	 */
	ApiStyle.prototype.GetTableRowPr = function()
	{
		if (styletype_Table !== this.Style.Get_Type())
			return null;

		return new ApiTableRowPr(this, this.Style.TableRowPr.Copy());
	};
	/**
	 * Get the table cell properties of the current style.
	 * @typeofeditors ["CDE"]
	 * @returns {?ApiTableCellPr}
	 */
	ApiStyle.prototype.GetTableCellPr = function()
	{
		if (styletype_Table !== this.Style.Get_Type())
			return null;

		return new ApiTableCellPr(this, this.Style.TableCellPr.Copy());
	};
	/**
	 * Specify the reference to the parent style which this style inherits from in the style hierarchy.
	 * @typeofeditors ["CDE"]
	 * @param {ApiStyle} oStyle - The parent style which the style inherits properties from.
	 */
	ApiStyle.prototype.SetBasedOn = function(oStyle)
	{
		if (!(oStyle instanceof ApiStyle) || this.Style.Get_Type() !== oStyle.Style.Get_Type())
			return;

		this.Style.Set_BasedOn(oStyle.Style.Get_Id());
	};
	/**
	 * Get a set of formatting properties which shall be conditionally applied to the parts of a table which match the
	 * requirement specified on the <code>sType</code> parameter.
	 * @typeofeditors ["CDE"]
	 * @param {TableStyleOverrideType} [sType="wholeTable"] - The part of the table which the formatting properties must be applied to.
	 * @returns {ApiTableStylePr}
	 */
	ApiStyle.prototype.GetConditionalTableStyle = function(sType)
	{
		if ("topLeftCell" === sType)
			return new ApiTableStylePr(sType, this, this.Style.TableTLCell.Copy());
		else if ("topRightCell" === sType)
			return new ApiTableStylePr(sType, this, this.Style.TableTRCell.Copy());
		else if ("bottomLeftCell" === sType)
			return new ApiTableStylePr(sType, this, this.Style.TableBLCell.Copy());
		else if ("bottomRightCell" === sType)
			return new ApiTableStylePr(sType, this, this.Style.TableBRCell.Copy());
		else if ("firstRow" === sType)
			return new ApiTableStylePr(sType, this, this.Style.TableFirstRow.Copy());
		else if ("lastRow" === sType)
			return new ApiTableStylePr(sType, this, this.Style.TableLastRow.Copy());
		else if ("firstColumn" === sType)
			return new ApiTableStylePr(sType, this, this.Style.TableFirstCol.Copy());
		else if ("lastColumn" === sType)
			return new ApiTableStylePr(sType, this, this.Style.TableLastCol.Copy());
		else if ("bandedColumn" === sType)
			return new ApiTableStylePr(sType, this, this.Style.TableBand1Vert.Copy());
		else if("bandedColumnEven" === sType)
			return new ApiTableStylePr(sType, this, this.Style.TableBand2Vert.Copy());
		else if ("bandedRow" === sType)
			return new ApiTableStylePr(sType, this, this.Style.TableBand1Horz.Copy());
		else if ("bandedRowEven" === sType)
			return new ApiTableStylePr(sType, this, this.Style.TableBand2Horz.Copy());
		else if ("wholeTable" === sType)
			return new ApiTableStylePr(sType, this, this.Style.TableWholeTable.Copy());

		return new ApiTableStylePr(sType, this, this.Style.TableWholeTable.Copy());
	};


	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiTextPr
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {"textPr"}
	 */
	ApiTextPr.prototype.GetClassType = function()
	{
		return "textPr";
	};
	/**
	 * The text style base method.
	 * <note>This method is not used by itself, as it only forms the basis for the ApiRun.SetStyle method which sets
	 * the selected or created style for the text.</note>
	 * @typeofeditors ["CDE"]
	 * @param {ApiStyle} oStyle - The style which must be applied to the text character.
	 */
	ApiTextPr.prototype.SetStyle = function(oStyle)
	{
		if (!(oStyle instanceof ApiStyle))
			return;

		this.TextPr.RStyle = oStyle.Style.Get_Id();
		this.private_OnChange();
	};
	/**
	 * Set the bold property to the text character.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {boolean} isBold - Specifies that the contents of this run are displayed bold.
	 */
	ApiTextPr.prototype.SetBold = function(isBold)
	{
		this.TextPr.Bold = isBold;
		this.private_OnChange();
	};
	/**
	 * Set the italic property to the text character.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {boolean} isItalic - Specifies that the contents of the current run are displayed italicized.
	 */
	ApiTextPr.prototype.SetItalic = function(isItalic)
	{
		this.TextPr.Italic = isItalic;
		this.private_OnChange();
	};
	/**
	 * Specify that the contents of this run are displayed with a single horizontal line through the center of the line.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {boolean} isStrikeout - Specifies that the contents of the current run are displayed struck through.
	 */
	ApiTextPr.prototype.SetStrikeout = function(isStrikeout)
	{
		this.TextPr.Strikeout = isStrikeout;
		this.private_OnChange();
	};
	/**
	 * Specify that the contents of this run are displayed along with a line appearing directly below the character
	 * (less than all the spacing above and below the characters on the line).
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {boolean} isUnderline - Specifies that the contents of the current run are displayed underlined.
	 */
	ApiTextPr.prototype.SetUnderline = function(isUnderline)
	{
		this.TextPr.Underline = isUnderline;
		this.private_OnChange();
	};
	/**
	 * Set all 4 font slots with the specified font family.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {string} sFontFamily - The font family or families used for the current text run.
	 */
	ApiTextPr.prototype.SetFontFamily = function(sFontFamily)
	{
		this.TextPr.RFonts.Set_All(sFontFamily, -1);
		this.private_OnChange();
	};
	/**
	 * Set the font size for the characters of the current text run.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {hps} nSize - The text size value measured in half-points (1/144 of an inch).
	 */
	ApiTextPr.prototype.SetFontSize = function(nSize)
	{
		this.TextPr.FontSize = private_GetHps(nSize);
		this.private_OnChange();
	};
	/**
	 * Set the text color for the current text run in the RGB format.
	 * @typeofeditors ["CDE"]
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 * @param {boolean} [isAuto=false] - If this parameter is set to "true", then r,g,b parameters will be ignored.
	 */
	ApiTextPr.prototype.SetColor = function(r, g, b, isAuto)
	{
		this.TextPr.Color = private_GetColor(r, g, b, isAuto);
		this.private_OnChange();
	};
	/**
	 * Specify the alignment which will be applied to the contents of this run in relation to the default appearance of the run text:
	 * * <b>"baseline"</b> - the characters in the current text run will be aligned by the default text baseline.
	 * * <b>"subscript"</b> - the characters in the current text run will be aligned below the default text baseline.
	 * * <b>"superscript"</b> - the characters in the current text run will be aligned above the default text baseline.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {("baseline" | "subscript" | "superscript")} sType - The vertical alignment type applied to the text contents.
	 */
	ApiTextPr.prototype.SetVertAlign = function(sType)
	{
		if ("baseline" === sType)
			this.TextPr.VertAlign = AscCommon.vertalign_Baseline;
		else if ("subscript" === sType)
			this.TextPr.VertAlign = AscCommon.vertalign_SubScript;
		else if ("superscript" === sType)
			this.TextPr.VertAlign = AscCommon.vertalign_SuperScript;

		this.private_OnChange();
	};
	/**
	 * Specify a highlighting color in the RGB format which is applied as a background for the contents of the current run.
	 * @typeofeditors ["CDE"]
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 * @param {boolean} [isNone=false] If this parameter is set to "true", then r,g,b parameters will be ignored.
	 */
	ApiTextPr.prototype.SetHighlight = function(r, g, b, isNone)
	{
		if (undefined === isNone)
			isNone = false;

		if (true === isNone)
			this.TextPr.HighLight = AscCommonWord.highlight_None;
		else
			this.TextPr.HighLight = new AscCommonWord.CDocumentColor(r, g, b, false);

		this.private_OnChange();
	};
	/**
	 * Set text spacing measured in twentieths of a point.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {twips} nSpacing - The value of the text spacing measured in twentieths of a point (1/1440 of an inch).
	 */
	ApiTextPr.prototype.SetSpacing = function(nSpacing)
	{
		this.TextPr.Spacing = private_Twips2MM(nSpacing);
		this.private_OnChange();
	};
	/**
	 * Specify that the contents of this run is displayed with two horizontal lines through each character displayed on the line.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {boolean} isDoubleStrikeout - Specifies that the contents of the current run are displayed double struck through.
	 */
	ApiTextPr.prototype.SetDoubleStrikeout = function(isDoubleStrikeout)
	{
		this.TextPr.DStrikeout = isDoubleStrikeout;
		this.private_OnChange();
	};
	/**
	 * Specify that any lowercase characters in this text run are formatted for display only as their capital letter character equivalents.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {boolean} isCaps - Specifies that the contents of the current run are displayed capitalized.
	 */
	ApiTextPr.prototype.SetCaps = function(isCaps)
	{
		this.TextPr.Caps = isCaps;
		this.private_OnChange();
	};
	/**
	 * Specify that all small letter characters in this text run are formatted for display only as their capital
	 * letter character equivalents in a font size two points smaller than the actual font size specified for this text.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {boolean} isSmallCaps - Specifies that the contents of the current run are displayed capitalized two points smaller.
	 */
	ApiTextPr.prototype.SetSmallCaps = function(isSmallCaps)
	{
		this.TextPr.SmallCaps = isSmallCaps;
		this.private_OnChange();
	};
	/**
	 * Specify the amount by which text is raised or lowered for this run in relation to the default
	 * baseline of the surrounding non-positioned text.
	 * @typeofeditors ["CDE"]
	 * @param {hps} nPosition - Specifies a positive (raised text) or negative (lowered text)
	 * measurement in half-points (1/144 of an inch).
	 */
	ApiTextPr.prototype.SetPosition = function(nPosition)
	{
		this.TextPr.Position = private_PtToMM(private_GetHps(nPosition));
		this.private_OnChange();
	};
	/**
	 * Specify the languages which will be used to check spelling and grammar (if requested) when processing
	 * the contents of this text run.
	 * @typeofeditors ["CDE"]
	 * @param {string} sLangId - The possible value for this parameter is a language identifier as defined by
	 * RFC 4646/BCP 47. Example: "en-CA".
	 */
	ApiTextPr.prototype.SetLanguage = function(sLangId)
	{
		var nLcid = g_oLcidNameToIdMap[sLangId];
		if (undefined !== nLcid)
		{
			this.TextPr.Lang.Val = nLcid;
			this.private_OnChange();
		}
	};
	/**
	 * Specify the shading applied to the contents of the current text run.
	 * @typeofeditors ["CDE"]
	 * @param {ShdType} sType - The shading type applied to the contents of the current text run.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 */
	ApiTextPr.prototype.SetShd = function(sType, r, g, b)
	{
		this.TextPr.Shd = private_GetShd(sType, r, g, b, false);
		this.private_OnChange();
	};


	/**
	 * Set the text color for the current text run.
	 * @typeofeditors ["CSE", "CPE"]
	 * @param {ApiFill} oApiFill - The color or pattern used to fill the text color.
	 */
	ApiTextPr.prototype.SetFill = function(oApiFill)
	{
		this.TextPr.Unifill = oApiFill.UniFill;
		this.private_OnChange();
	};


	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiParaPr
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {"paraPr"}
	 */
	ApiParaPr.prototype.GetClassType = function()
	{
		return "paraPr";
	};
	/**
	 * The paragraph style base method.
	 * <note>This method is not used by itself, as it only forms the basis for the {@link ApiParagraph#SetStyle} method which sets the selected or created style for the paragraph.</note>
	 * @typeofeditors ["CDE"]
	 * @param {ApiStyle} oStyle - The style of the paragraph to be set.
	 */
	ApiParaPr.prototype.SetStyle = function(oStyle)
	{
		if (!oStyle || !(oStyle instanceof ApiStyle))
			return;

		this.ParaPr.PStyle = oStyle.Style.Get_Id();
		this.private_OnChange();
	};
	/**
	 * Specifies that any space specified before or after this paragraph, specified using the spacing element
	 * {@link ApiParaPr#SetSpacingBefore}{@link ApiParaPr#SetSpacingAfter}, should not be applied when the preceding and
	 * following paragraphs are of the same paragraph style, affecting the top and bottom spacing respectively.
	 * @typeofeditors ["CDE"]
	 * @param {boolean} isContextualSpacing - The true value will enable the paragraph contextual spacing.
	 */
	ApiParaPr.prototype.SetContextualSpacing = function(isContextualSpacing)
	{
		this.ParaPr.ContextualSpacing = private_GetBoolean(isContextualSpacing);
		this.private_OnChange();
	};
	/**
	 * Set the paragraph left side indentation.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {twips} nValue - The paragraph left side indentation value measured in twentieths of a point (1/1440 of an inch).
	 */
	ApiParaPr.prototype.SetIndLeft = function(nValue)
	{
		this.ParaPr.Ind.Left = private_Twips2MM(nValue);
		this.private_OnChange();
	};
	/**
	 * Set the paragraph right side indentation.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {twips} nValue - The paragraph right side indentation value measured in twentieths of a point (1/1440 of an inch).
	 */
	ApiParaPr.prototype.SetIndRight = function(nValue)
	{
		this.ParaPr.Ind.Right = private_Twips2MM(nValue);
		this.private_OnChange();
	};
	/**
	 * Set the paragraph first line indentation.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {twips} nValue - The paragraph first line indentation value measured in twentieths of a point (1/1440 of an inch).
	 */
	ApiParaPr.prototype.SetIndFirstLine = function(nValue)
	{
		this.ParaPr.Ind.FirstLine = private_Twips2MM(nValue);
		this.private_OnChange();
	};
	/**
	 * Set paragraph contents justification.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {("left" | "right" | "both" | "center")} sJc - The parameters will define the justification type that
	 * will be applied to the paragraph contents.
	 */
	ApiParaPr.prototype.SetJc = function(sJc)
	{
		this.ParaPr.Jc = private_GetParaAlign(sJc);
		this.private_OnChange();
	};
	/**
	 * Specify that when rendering this document using a page view, all lines of this paragraph are maintained on a single page whenever possible.
	 * @typeofeditors ["CDE"]
	 * @param {boolean} isKeepLines - The true value will enable the option to keep lines of the paragraph on a single page.
	 */
	ApiParaPr.prototype.SetKeepLines = function(isKeepLines)
	{
		this.ParaPr.KeepLines = isKeepLines;
		this.private_OnChange();
	};
	/**
	 * Specify that when rendering this document using a paginated view, the contents of this paragraph are at least
	 * partly rendered on the same page as the following paragraph whenever possible.
	 * @typeofeditors ["CDE"]
	 * @param {boolean} isKeepNext - The true value will enable the option to keep lines of the paragraph on the same
	 * page as the following paragraph.
	 */
	ApiParaPr.prototype.SetKeepNext = function(isKeepNext)
	{
		this.ParaPr.KeepNext = isKeepNext;
		this.private_OnChange();
	};
	/**
	 * Specify that when rendering this document using a paginated view, the contents of this paragraph are rendered at
	 * the beginning of a new page in the document.
	 * @typeofeditors ["CDE"]
	 * @param {boolean} isPageBreakBefore - The true value will enable the option to render the contents of the paragraph
	 * at the beginning of the a new page in the document.
	 */
	ApiParaPr.prototype.SetPageBreakBefore = function(isPageBreakBefore)
	{
		this.ParaPr.PageBreakBefore = isPageBreakBefore;
		this.private_OnChange();
	};
	/**
	 * Set paragraph line spacing. If the value of the <code>sLineRule</code> parameter is either
	 * <code>"atLeast"</code>
	 * or <code>"exact"</code>, then the value of <code>nLine</code> shall be interpreted as twentieths of a point. If
	 * the value of the <code>sLineRule</code> parameter is <code>"auto"</code>, then the value of the
	 * <code>nLine</code> attribute shall be interpreted as 240ths of a line.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {(twips | line240)} nLine - The line spacing value measured either in twentieths of a point (1/1440 of an inch) or in 240ths of a line.
	 * @param {("auto" | "atLeast" | "exact")} sLineRule - The rule that determines the measuring units of the nLine parameter.
	 */
	ApiParaPr.prototype.SetSpacingLine = function(nLine, sLineRule)
	{
		if (undefined !== nLine && undefined !== sLineRule)
		{
			if ("auto" === sLineRule)
			{
				this.ParaPr.Spacing.LineRule = Asc.linerule_Auto;
				this.ParaPr.Spacing.Line     = nLine / 240.0;
			}
			else if ("atLeast" === sLineRule)
			{
				this.ParaPr.Spacing.LineRule = Asc.linerule_AtLeast;
				this.ParaPr.Spacing.Line     = private_Twips2MM(nLine);

			}
			else if ("exact" === sLineRule)
			{
				this.ParaPr.Spacing.LineRule = Asc.linerule_Exact;
				this.ParaPr.Spacing.Line     = private_Twips2MM(nLine);
			}
		}

		this.private_OnChange();
	};
	/**
	 * Set paragraph spacing before. If the value of the <code>isBeforeAuto</code> parameter is <code>true</code>, then
	 * any value of the <code>nBefore</code> is ignored. If <code>isBeforeAuto</code> parameter is not specified, then
	 * it will be interpreted as <code>false</code>.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {twips} nBefore - The value of the spacing before the current paragraph measured in twentieths of a point (1/1440 of an inch).
	 * @param {boolean} [isBeforeAuto=false] - The true value will disable the nBefore parameter.
	 */
	ApiParaPr.prototype.SetSpacingBefore = function(nBefore, isBeforeAuto)
	{
		if (undefined !== nBefore)
			this.ParaPr.Spacing.Before = private_Twips2MM(nBefore);

		if (undefined !== isBeforeAuto)
			this.ParaPr.Spacing.BeforeAutoSpacing = isBeforeAuto;

		this.private_OnChange();
	};
	/**
	 * Set paragraph spacing after. If the value of the <code>isAfterAuto</code> parameter is <code>true</code>, then
	 * any value of the <code>nAfter</code> is ignored. If <code>isAfterAuto</code> parameter is not specified, then it
	 * will be interpreted as <code>false</code>.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {twips} nAfter - The value of the spacing after the current paragraph measured in twentieths of a point (1/1440 of an inch).
	 * @param {boolean} [isAfterAuto=false] - The true value will disable the nAfter parameter.
	 */
	ApiParaPr.prototype.SetSpacingAfter = function(nAfter, isAfterAuto)
	{
		if (undefined !== nAfter)
			this.ParaPr.Spacing.After = private_Twips2MM(nAfter);

		if (undefined !== isAfterAuto)
			this.ParaPr.Spacing.AfterAutoSpacing = isAfterAuto;

		this.private_OnChange();
	};
	/**
	 * Specify the shading applied to the contents of the paragraph.
	 * @typeofeditors ["CDE"]
	 * @param {ShdType} sType - The shading type which will be applied to the contents of the current paragraph.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 * @param {boolean} [isAuto=false] - The true value will disable paragraph contents shading.
	 */
	ApiParaPr.prototype.SetShd = function(sType, r, g, b, isAuto)
	{
		this.ParaPr.Shd = private_GetShd(sType, r, g, b, isAuto);
		this.private_OnChange();
	};
	/**
	 * Specify the border which will be displayed below a set of paragraphs which have the same paragraph border settings.
	 * <note>The paragraphs of the same style going one by one are considered as a single block, so the border is added
	 * to the whole block rather than to every paragraph in this block.</note>
	 * @typeofeditors ["CDE"]
	 * @param {BorderType} sType - The border style.
	 * @param {pt_8} nSize - The width of the current bottom border measured in eighths of a point.
	 * @param {pt} nSpace - The spacing offset below the paragraph measured in points used to place this border.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 */
	ApiParaPr.prototype.SetBottomBorder = function(sType, nSize, nSpace, r, g, b)
	{
		this.ParaPr.Brd.Bottom = private_GetTableBorder(sType, nSize, nSpace, r, g, b);
		this.private_OnChange();
	};
	/**
	 * Specify the border which will be displayed at the left side of the page around the specified paragraph.
	 * @typeofeditors ["CDE"]
	 * @param {BorderType} sType - The style of border.
	 * @param {pt_8} nSize - The width of the current left border measured in eighths of a point.
	 * @param {pt} nSpace - The spacing offset to the left of the paragraph measured in points used to place this border.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 */
	ApiParaPr.prototype.SetLeftBorder = function(sType, nSize, nSpace, r, g, b)
	{
		this.ParaPr.Brd.Left = private_GetTableBorder(sType, nSize, nSpace, r, g, b);
		this.private_OnChange();
	};
	/**
	 * Specify the border which will be displayed at the right side of the page around the specified paragraph.
	 * @typeofeditors ["CDE"]
	 * @param {BorderType} sType - The border style.
	 * @param {pt_8} nSize - The width of the current right border measured in eighths of a point.
	 * @param {pt} nSpace - The spacing offset to the right of the paragraph measured in points used to place this border.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 */
	ApiParaPr.prototype.SetRightBorder = function(sType, nSize, nSpace, r, g, b)
	{
		this.ParaPr.Brd.Right = private_GetTableBorder(sType, nSize, nSpace, r, g, b);
		this.private_OnChange();
	};
	/**
	 * Specify the border which will be displayed above a set of paragraphs which have the same set of paragraph border settings.
	 * <note>The paragraphs of the same style going one by one are considered as a single block, so the border is added to the whole block rather than to every paragraph in this block.</note>
	 * @typeofeditors ["CDE"]
	 * @param {BorderType} sType - The border style.
	 * @param {pt_8} nSize - The width of the current top border measured in eighths of a point.
	 * @param {pt} nSpace - The spacing offset above the paragraph measured in points used to place this border.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 */
	ApiParaPr.prototype.SetTopBorder = function(sType, nSize, nSpace, r, g, b)
	{
		this.ParaPr.Brd.Top = private_GetTableBorder(sType, nSize, nSpace, r, g, b);
		this.private_OnChange();
	};
	/**
	 * Specify the border which will be displayed between each paragraph in a set of paragraphs which have the same set of paragraph border settings.
	 * @typeofeditors ["CDE"]
	 * @param {BorderType} sType - The border style.
	 * @param {pt_8} nSize - The width of the current border measured in eighths of a point.
	 * @param {pt} nSpace - The spacing offset between the paragraphs measured in points used to place this border.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 */
	ApiParaPr.prototype.SetBetweenBorder = function(sType, nSize, nSpace, r, g, b)
	{
		this.ParaPr.Brd.Between = private_GetTableBorder(sType, nSize, nSpace, r, g, b);
		this.private_OnChange();
	};
	/**
	 * Specify whether a single line of this paragraph will be prevented from being displayed on a separate page from the remaining content at display time by moving the line onto the following page.
	 * @typeofeditors ["CDE"]
	 * @param {boolean} isWidowControl - The true value will enable the SetWidowControl method use.
	 */
	ApiParaPr.prototype.SetWidowControl = function(isWidowControl)
	{
		this.ParaPr.WidowControl = isWidowControl;
		this.private_OnChange();
	};
	/**
	 * Specifies a sequence of custom tab stops which shall be used for any tab characters in the current paragraph.
	 * <b>Warning</b>: The lengths of aPos array and aVal array <b>MUST BE</b> equal.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @param {twips[]} aPos - An array of the positions of custom tab stops with respect to the current page margins
	 * measured in twentieths of a point (1/1440 of an inch).
	 * @param {TabJc[]} aVal - An array of the styles of custom tab stops, which determines the behavior of the tab
	 * stop and the alignment which will be applied to text entered at the current custom tab stop.
	 */
	ApiParaPr.prototype.SetTabs = function(aPos, aVal)
	{
		if (!(aPos instanceof Array) || !(aVal instanceof Array) || aPos.length !== aVal.length)
			return;

		var oTabs = new CParaTabs();
		for (var nIndex = 0, nCount = aPos.length; nIndex < nCount; ++nIndex)
		{
			oTabs.Add(private_GetTabStop(aPos[nIndex], aVal[nIndex]));
		}
		this.ParaPr.Tabs = oTabs;
		this.private_OnChange();
	};
	/**
	 * Specify that the current paragraph references a numbering definition instance in the current document.
	 * @typeofeditors ["CDE"]
	 * @param {ApiNumbering} oNumPr - Specifies a numbering definition.
	 * @param {number} [nLvl=0] - Specifies a numbering level reference. If the current instance of the ApiParaPr class is direct
	 * formatting of a paragraph, then this parameter MUST BE specified. Otherwise if the current instance of the ApiParaPr class
	 * is the part of ApiStyle properties, this parameter will be ignored.
	 */
	ApiParaPr.prototype.SetNumPr = function(oNumPr, nLvl)
	{
		if (!(oNumPr instanceof ApiNumbering))
			return;

		this.ParaPr.NumPr       = new CNumPr();
		this.ParaPr.NumPr.NumId = oNumPr.Num.GetId();
		this.ParaPr.NumPr.Lvl   = undefined;

		if (this.Parent instanceof ApiParagraph)
		{
			this.ParaPr.NumPr.Lvl = Math.min(8, Math.max(0, (nLvl ? nLvl : 0)));
		}
		this.private_OnChange();
	};


	/**
	 * Set the bullet or numbering to the current paragraph.
	 * @typeofeditors ["CSE", "CPE"]
	 * @param {?ApiBullet} oBullet - The bullet object created using either the {@link Api#CreateBullet} or {@link Api#CreateNumbering} method.
	 */
	ApiParaPr.prototype.SetBullet = function(oBullet){
		if(oBullet){
			this.ParaPr.Bullet = oBullet.Bullet;
		}
		else{
			this.ParaPr.Bullet = null;
		}
		this.private_OnChange();
	};


	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiNumbering
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE"]
	 * @returns {"numbering"}
	 */
	ApiNumbering.prototype.GetClassType = function()
	{
		return "numbering";
	};
	/**
	 * Get the specified level of the current numbering.
	 * @typeofeditors ["CDE"]
	 * @param {number} nLevel - The numbering level index. This value MUST BE from 0 to 8.
	 * @returns {ApiNumberingLevel}
	 */
	ApiNumbering.prototype.GetLevel = function(nLevel)
	{
		return new ApiNumberingLevel(this.Num, nLevel);
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiNumberingLevel
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE"]
	 * @returns {"numberingLevel"}
	 */
	ApiNumberingLevel.prototype.GetClassType = function()
	{
		return "numberingLevel";
	};
	/**
	 * Get the numbering definition.
	 * @typeofeditors ["CDE"]
	 * @returns {ApiNumbering}
	 */
	ApiNumberingLevel.prototype.GetNumbering = function()
	{
		return new ApiNumbering(this.Num);
	};
	/**
	 * Get level index.
	 * @typeofeditors ["CDE"]
	 * @returns {number}
	 */
	ApiNumberingLevel.prototype.GetLevelIndex = function()
	{
		return this.Lvl;
	};
	/**
	 * Specify the text properties which will be applied to the text in the current numbering level itself, not to the text in the subsequent paragraph.
	 * <note>To change the text style for the paragraph, a style must be applied to it using the ApiRun.SetStyle method.</note>
	 * @typeofeditors ["CDE"]
	 * @returns {ApiTextPr}
	 */
	ApiNumberingLevel.prototype.GetTextPr = function()
	{
		return new ApiTextPr(this, this.Num.GetLvl(this.Lvl).TextPr.Copy());
	};
	/**
	 * The paragraph properties which are applied to any numbered paragraph that references the given numbering definition and numbering level.
	 * @typeofeditors ["CDE"]
	 * @returns {ApiParaPr}
	 */
	ApiNumberingLevel.prototype.GetParaPr = function()
	{
		return new ApiParaPr(this, this.Num.GetLvl(this.Lvl).ParaPr.Copy());
	};
	/**
	 * Set one of the existing predefined numbering templates.
	 * @typeofeditors ["CDE"]
	 * @param {("none" | "bullet" | "1)" | "1." | "I." | "A." | "a)" | "a." | "i." )} sType - Set one of the existing predefined numbering templates.
	 * @param {string} [sSymbol=""] - The symbol used for the list numbering. This parameter have a meaning only if the sType="bullet" property is selected.
	 */
	ApiNumberingLevel.prototype.SetTemplateType = function(sType, sSymbol)
	{
		switch (sType)
		{
			case "none"  :
				this.Num.SetLvlByType(this.Lvl, c_oAscNumberingLevel.None);
				break;
			case "bullet":
				this.Num.SetLvlByType(this.Lvl, c_oAscNumberingLevel.Bullet, sSymbol, new CTextPr());
				break;
			case "1)"    :
				this.Num.SetLvlByType(this.Lvl, c_oAscNumberingLevel.DecimalBracket_Right);
				break;
			case "1."    :
				this.Num.SetLvlByType(this.Lvl, c_oAscNumberingLevel.DecimalDot_Right);
				break;
			case "I."    :
				this.Num.SetLvlByType(this.Lvl, c_oAscNumberingLevel.UpperRomanDot_Right);
				break;
			case "A."    :
				this.Num.SetLvlByType(this.Lvl, c_oAscNumberingLevel.UpperLetterDot_Left);
				break;
			case "a)"    :
				this.Num.SetLvlByType(this.Lvl, c_oAscNumberingLevel.LowerLetterBracket_Left);
				break;
			case "a."    :
				this.Num.SetLvlByType(this.Lvl, c_oAscNumberingLevel.LowerLetterDot_Left);
				break;
			case "i."    :
				this.Num.SetLvlByType(this.Lvl, c_oAscNumberingLevel.LowerRomanDot_Right);
				break;
		}
	};
	/**
	 * Set your own customized numbering type.
	 * @typeofeditors ["CDE"]
	 * @param {("none" | "bullet" | "decimal" | "lowerRoman" | "upperRoman" | "lowerLetter" | "upperLetter" |
	 *     "decimalZero")} sType - The custom numbering type used for the current numbering definition.
	 * @param {string} sTextFormatString - Any text in this parameter will be taken as literal text to be repeated in each instance of this numbering level, except for any use of the percent symbol (%) followed by a number, which will be used to indicate the one-based index of the number to be used at this level. Any number of a level higher than this level will be ignored.
	 * higher than this level shall be ignored.
	 * @param {("left" | "right" | "center")} sAlign - Type of justification applied to the text run in the current numbering level.
	 */
	ApiNumberingLevel.prototype.SetCustomType = function(sType, sTextFormatString, sAlign)
	{
		var nType = Asc.c_oAscNumberingFormat.None;
		if ("none" === sType)
			nType = Asc.c_oAscNumberingFormat.None;
		else if ("bullet" === sType)
			nType = Asc.c_oAscNumberingFormat.Bullet;
		else if ("decimal" === sType)
			nType = Asc.c_oAscNumberingFormat.Decimal;
		else if ("lowerRoman" === sType)
			nType = Asc.c_oAscNumberingFormat.LowerRoman;
		else if ("upperRoman" === sType)
			nType = Asc.c_oAscNumberingFormat.UpperRoman;
		else if ("lowerLetter" === sType)
			nType = Asc.c_oAscNumberingFormat.LowerLetter;
		else if ("upperLetter" === sType)
			nType = Asc.c_oAscNumberingFormat.UpperLetter;
		else if ("decimalZero" === sType)
			nType = Asc.c_oAscNumberingFormat.DecimalZero;

		var nAlign = align_Left;
		if ("left" === sAlign)
			nAlign = align_Left;
		else if ("right" === sAlign)
			nAlign = align_Right;
		else if ("center" === sAlign)
			nAlign = align_Center;

		this.Num.SetLvlByFormat(this.Lvl, nType, sTextFormatString, nAlign);
	};
	/**
	 * Specify a one-based index which determines when a numbering level should restart to its starting value. A numbering level restarts when an instance of the specified numbering level, which will be higher (earlier than the this level) is used in the given document contents. By default this value is true.
	 * @typeofeditors ["CDE"]
	 * @param {boolean} isRestart - The true value will enable the SetRestart method use.
	 */
	ApiNumberingLevel.prototype.SetRestart = function(isRestart)
	{
		this.Num.SetLvlRestart(this.Lvl, private_GetBoolean(isRestart, true));
	};
	/**
	 * Specify the starting value for the numbering used by the parent numbering level within a given numbering level definition. By default this value is 1.
	 * @typeofeditors ["CDE"]
	 * @param {number} nStart -
	 */
	ApiNumberingLevel.prototype.SetStart = function(nStart)
	{
		this.Num.SetLvlStart(this.Lvl, private_GetInt(nStart));
	};
	/**
	 * Specify the content which will be added between a given numbering level text and the text of every numbered paragraph which references that numbering level. By default this value is "tab".
	 * @typeofeditors ["CDE"]
	 * @param {("space" | "tab" | "none")} sType - The content added between the numbering level text and the text in the numbered paragraph.
	 */
	ApiNumberingLevel.prototype.SetSuff = function(sType)
	{
		if ("space" === sType)
			this.Num.SetLvlSuff(this.Lvl, Asc.c_oAscNumberingSuff.Space);
		else if ("tab" === sType)
			this.Num.SetLvlSuff(this.Lvl, Asc.c_oAscNumberingSuff.Tab);
		else if ("none" === sType)
			this.Num.SetLvlSuff(this.Lvl, Asc.c_oAscNumberingSuff.None);
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiTablePr
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE"]
	 * @returns {"tablePr"}
	 */
	ApiTablePr.prototype.GetClassType = function()
	{
		return "tablePr";
	};
	/**
	 * Specify the number of columns which will comprise each table column band for this table style.
	 * @typeofeditors ["CDE"]
	 * @param {number} nCount - The number of columns measured in positive integers.
	 */
	ApiTablePr.prototype.SetStyleColBandSize = function(nCount)
	{
		this.TablePr.TableStyleColBandSize = private_GetInt(nCount, 1, null);
		this.private_OnChange();
	};
	/**
	 * Specify the number of rows which will comprise each table row band for this table style.
	 * @typeofeditors ["CDE"]
	 * @param {number} nCount - The number of rows measured in positive integers.
	 */
	ApiTablePr.prototype.SetStyleRowBandSize = function(nCount)
	{
		this.TablePr.TableStyleRowBandSize = private_GetInt(nCount, 1, null);
		this.private_OnChange();
	};
	/**
	 * Specify the alignment of the current table with respect to the text margins in the current section.
	 * @typeofeditors ["CDE"]
	 * @param {("left" | "right" | "center")} sJcType - The alignment type used for the current table placement.
	 */
	ApiTablePr.prototype.SetJc = function(sJcType)
	{
		if ("left" === sJcType)
			this.TablePr.Jc = align_Left;
		else if ("right" === sJcType)
			this.TablePr.Jc = align_Right;
		else if ("center" === sJcType)
			this.TablePr.Jc = align_Center;
		this.private_OnChange();
	};
	/**
	 * Specify the shading which is applied to the extents of the current table.
	 * @typeofeditors ["CDE"]
	 * @param {ShdType} sType - The shading type applied to the extents of the current table.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 * @param {boolean} [isAuto=false] - The true value will disable the SetShd method use.
	 */
	ApiTablePr.prototype.SetShd = function(sType, r, g, b, isAuto)
	{
		this.TablePr.Shd = private_GetShd(sType, r, g, b, isAuto);
		this.private_OnChange();
	};
	/**
	 * Set the border which will be displayed at the top of the current table.
	 * @typeofeditors ["CDE"]
	 * @param {BorderType} sType - The top border style.
	 * @param {pt_8} nSize - The width of the current top border measured in eighths of a point.
	 * @param {pt} nSpace - The spacing offset in the top part of the table measured in points used to place this border.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 */
	ApiTablePr.prototype.SetTableBorderTop = function(sType, nSize, nSpace, r, g, b)
	{
		this.TablePr.TableBorders.Top = private_GetTableBorder(sType, nSize, nSpace, r, g, b);
		this.private_OnChange();
	};
	/**
	 * Set the border which will be displayed at the bottom of the current table.
	 * @typeofeditors ["CDE"]
	 * @param {BorderType} sType - The bottom border style.
	 * @param {pt_8} nSize - The width of the current bottom border measured in eighths of a point.
	 * @param {pt} nSpace - The spacing offset in the bottom part of the table measured in points used to place this border.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 */
	ApiTablePr.prototype.SetTableBorderBottom = function(sType, nSize, nSpace, r, g, b)
	{
		this.TablePr.TableBorders.Bottom = private_GetTableBorder(sType, nSize, nSpace, r, g, b);
		this.private_OnChange();
	};
	/**
	 * Set the border which will be displayed on the left of the current table.
	 * @typeofeditors ["CDE"]
	 * @param {BorderType} sType - The left border style.
	 * @param {pt_8} nSize - The width of the current left border measured in eighths of a point.
	 * @param {pt} nSpace - The spacing offset in the left part of the table measured in points used to place this border.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 */
	ApiTablePr.prototype.SetTableBorderLeft = function(sType, nSize, nSpace, r, g, b)
	{
		this.TablePr.TableBorders.Left = private_GetTableBorder(sType, nSize, nSpace, r, g, b);
		this.private_OnChange();
	};
	/**
	 * Set the border which will be displayed on the right of the current table.
	 * @typeofeditors ["CDE"]
	 * @param {BorderType} sType - The right border style.
	 * @param {pt_8} nSize - The width of the current right border measured in eighths of a point.
	 * @param {pt} nSpace - The spacing offset in the right part of the table measured in points used to place this border.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 */
	ApiTablePr.prototype.SetTableBorderRight = function(sType, nSize, nSpace, r, g, b)
	{
		this.TablePr.TableBorders.Right = private_GetTableBorder(sType, nSize, nSpace, r, g, b);
		this.private_OnChange();
	};
	/**
	 * Specify the border which will be displayed on all horizontal table cell borders which are not on an outmost edge
	 * of the parent table (all horizontal borders which are not the topmost or bottommost border).
	 * @typeofeditors ["CDE"]
	 * @param {BorderType} sType - The horizontal table cell border style.
	 * @param {pt_8} nSize - The width of the current border measured in eighths of a point.
	 * @param {pt} nSpace - The spacing offset in the horizontal table cells of the table measured in points used to place this border.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 */
	ApiTablePr.prototype.SetTableBorderInsideH = function(sType, nSize, nSpace, r, g, b)
	{
		this.TablePr.TableBorders.InsideH = private_GetTableBorder(sType, nSize, nSpace, r, g, b);
		this.private_OnChange();
	};
	/**
	 * Specify the border which will be displayed on all vertical table cell borders which are not on an outmost edge
	 * of the parent table (all vertical borders which are not the leftmost or rightmost border).
	 * @typeofeditors ["CDE"]
	 * @param {BorderType} sType - The vertical table cell border style.
	 * @param {pt_8} nSize - The width of the current border measured in eighths of a point.
	 * @param {pt} nSpace - The spacing offset in the vertical table cells of the table measured in points used to place this border.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 */
	ApiTablePr.prototype.SetTableBorderInsideV = function(sType, nSize, nSpace, r, g, b)
	{
		this.TablePr.TableBorders.InsideV = private_GetTableBorder(sType, nSize, nSpace, r, g, b);
		this.private_OnChange();
	};

	/**
	 * Specify the amount of space which will be left between the bottom extent of the cell contents and the border
	 * of all table cells within the parent table (or table row).
	 * @typeofeditors ["CDE"]
	 * @param {twips} nValue - The value for the amount of space below the bottom extent of the cell measured in
	 * twentieths of a point (1/1440 of an inch).
	 */
	ApiTablePr.prototype.SetTableCellMarginBottom = function(nValue)
	{
		this.TablePr.TableCellMar.Bottom = private_GetTableMeasure("twips", nValue);
		this.private_OnChange();
	};
	/**
	 * Specify the amount of space which will be present between the left extent of the cell contents and the left
	 * border of all table cells within the parent table (or table row).
	 * @typeofeditors ["CDE"]
	 * @param {twips} nValue - The value for the amount of space to the left extent of the cell measured in twentieths of a point (1/1440 of an inch).
	 */
	ApiTablePr.prototype.SetTableCellMarginLeft = function(nValue)
	{
		this.TablePr.TableCellMar.Left = private_GetTableMeasure("twips", nValue);
		this.private_OnChange();
	};
	/**
	 * Specify the amount of space which will be present between the right extent of the cell contents and the right
	 * border of all table cells within the parent table (or table row).
	 * @typeofeditors ["CDE"]
	 * @param {twips} nValue - The value for the amount of space to the right extent of the cell measured in twentieths of a point (1/1440 of an inch).
	 */
	ApiTablePr.prototype.SetTableCellMarginRight = function(nValue)
	{
		this.TablePr.TableCellMar.Right = private_GetTableMeasure("twips", nValue);
		this.private_OnChange();
	};
	/**
	 * Specify the amount of space which will be present between the top extent of the cell contents and the top border
	 * of all table cells within the parent table (or table row).
	 * @typeofeditors ["CDE"]
	 * @param {twips} nValue - The value for the amount of space above the top extent of the cell measured in twentieths of a point (1/1440 of an inch).
	 */
	ApiTablePr.prototype.SetTableCellMarginTop = function(nValue)
	{
		this.TablePr.TableCellMar.Top = private_GetTableMeasure("twips", nValue);
		this.private_OnChange();
	};
	/**
	 * Specify the default table cell spacing (the spacing between adjacent cells and the edges of the table).
	 * @typeofeditors ["CDE"]
	 * @param {?twips} nValue - Spacing value measured in twentieths of a point (1/1440 of an inch). <code>"Null"</code> means no spacing will be applied.
	 */
	ApiTablePr.prototype.SetCellSpacing = function(nValue)
	{
		if (null === nValue)
			this.TablePr.TableCellSpacing = null;
		else
			this.TablePr.TableCellSpacing = private_Twips2MM(nValue);
		this.private_OnChange();
	};
	/**
	 * Specify the indentation which will be added before the leading edge of the current table in the document
	 * (the left edge in a left-to-right table, and the right edge in a right-to-left table).
	 * @typeofeditors ["CDE"]
	 * @param {twips} nValue - The indentation value measured in twentieths of a point (1/1440 of an inch).
	 */
	ApiTablePr.prototype.SetTableInd = function(nValue)
	{
		this.TablePr.TableInd = private_Twips2MM(nValue);
		this.private_OnChange();
	};
	/**
	 * Set the preferred width for this table.
	 * <note>Tables are created with the ApiTable.SetWidth method properties set by default, which always override the {@link ApiTablePr#SetWidth} method properties. That is why there is no use to try and apply ApiTablePr.SetWidth, we recommend that you use the  {@link ApiTablePr#SetWidth}  method instead.</node>
	 * @typeofeditors ["CDE"]
	 * @param {TableWidth} sType - Type of the width value from one of the available width values types.
	 * @param {number} [nValue] - The table width value measured in positive integers.
	 */
	ApiTablePr.prototype.SetWidth = function(sType, nValue)
	{
		this.TablePr.TableW = private_GetTableMeasure(sType, nValue);
		this.private_OnChange();
	};
	/**
	 * Specify the algorithm which will be used to lay out the contents of this table within the document.
	 * @typeofeditors ["CDE"]
	 * @param {("autofit" | "fixed")} sType - The type of the table layout in the document.
	 */
	ApiTablePr.prototype.SetTableLayout = function(sType)
	{
		if ("autofit" === sType)
			this.TablePr.TableLayout = tbllayout_AutoFit;
		else if ("fixed" === sType)
			this.TablePr.TableLayout = tbllayout_Fixed;

		this.private_OnChange();
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiTableRowPr
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE"]
	 * @returns {"tableRowPr"}
	 */
	ApiTableRowPr.prototype.GetClassType = function()
	{
		return "tableRowPr";
	};
	/**
	 * @typeofeditors ["CDE"]
	 * @param {("auto" | "atLeast")} sHRule - The rule to either apply or ignore the height value to the current table row. Use the <code>"atLeast"</code> value to enable the <code>SetHeight</code> method use.
	 * @param {twips} [nValue] - The height for the current table row measured in twentieths of a point (1/1440 of an inch). This value will be ignored if <code>sHRule="auto"<code>.
	 */
	ApiTableRowPr.prototype.SetHeight = function(sHRule, nValue)
	{
		if ("auto" === sHRule)
			this.RowPr.Height = new CTableRowHeight(0, Asc.linerule_Auto);
		else if ("atLeast" === sHRule)
			this.RowPr.Height = new CTableRowHeight(private_Twips2MM(nValue), Asc.linerule_AtLeast);

		this.private_OnChange();
	};
	/**
	 * Specify that all the current table rows will be styled as its header row.
	 * @typeofeditors ["CDE"]
	 * @param {boolean} isHeader - The true value will enable the SetTableHeader method use.
	 */
	ApiTableRowPr.prototype.SetTableHeader = function(isHeader)
	{
		this.RowPr.TableHeader = private_GetBoolean(isHeader);
		this.private_OnChange();
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiTableCellPr
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE"]
	 * @returns {"tableCellPr"}
	 */
	ApiTableCellPr.prototype.GetClassType = function()
	{
		return "tableCellPr";
	};
	/**
	 * Specify the shading applied to the contents of the table cell.
	 * @typeofeditors ["CDE"]
	 * @param {ShdType} sType - The shading type which will be applied to the contents of the current table cell.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 * @param {boolean} [isAuto=false] - The true value will disable table cell contents shading.
	 */
	ApiTableCellPr.prototype.SetShd = function(sType, r, g, b, isAuto)
	{
		this.CellPr.Shd = private_GetShd(sType, r, g, b, isAuto);
		this.private_OnChange();
	};
	/**
	 * Specify the amount of space which will be left between the bottom extent of the cell contents and the border
	 * of a specific table cell within a table.
	 * @typeofeditors ["CDE"]
	 * @param {?twips} nValue - The value for the amount of space below the bottom extent of the cell measured in twentieths
	 * of a point (1/1440 of an inch). If this value is <code>null</code>, then default table cell bottom margin will be used, otherwise
	 * the table cell bottom margin will be overridden with the specified value for the current cell.
	 */
	ApiTableCellPr.prototype.SetCellMarginBottom = function(nValue)
	{
		if (!this.CellPr.TableCellMar)
		{
			this.CellPr.TableCellMar =
			{
				Bottom : undefined,
				Left   : undefined,
				Right  : undefined,
				Top    : undefined
			};
		}

		if (null === nValue)
			this.CellPr.TableCellMar.Bottom = undefined;
		else
			this.CellPr.TableCellMar.Bottom = private_GetTableMeasure("twips", nValue);
		this.private_OnChange();
	};
	/**
	 * Specifies the amount of space which shall be left between the right extent of the current cell contents and the
	 * right edge border of a specific individual table cell within a table.
	 * @typeofeditors ["CDE"]
	 * @param {?twips} nValue - The value for the amount of space to the left extent of the cell measured in twentieths
	 * of a point (1/1440 of an inch). If this value is <code>null<c/ode>, then default table cell left margin will be used, otherwise
	 * the table cell left margin will be overridden with the specified value for the current cell.
	 */
	ApiTableCellPr.prototype.SetCellMarginLeft = function(nValue)
	{
		if (!this.CellPr.TableCellMar)
		{
			this.CellPr.TableCellMar =
			{
				Bottom : undefined,
				Left   : undefined,
				Right  : undefined,
				Top    : undefined
			};
		}

		if (null === nValue)
			this.CellPr.TableCellMar.Left = undefined;
		else
			this.CellPr.TableCellMar.Left = private_GetTableMeasure("twips", nValue);
		this.private_OnChange();
	};
	/**
	 * Specify the amount of space which will be left between the right extent of the cell contents and the border of a specific table cell within a table.
	 * @typeofeditors ["CDE"]
	 * @param {?twips} nValue - The value for the amount of space to the right extent of the cell measured in twentieths
	 * of a point (1/1440 of an inch). If this value is <code>null</code>, then default table cell right margin will be used, otherwise
	 * the table cell right margin will be overridden with the specified value for the current cell.
	 */
	ApiTableCellPr.prototype.SetCellMarginRight = function(nValue)
	{
		if (!this.CellPr.TableCellMar)
		{
			this.CellPr.TableCellMar =
			{
				Bottom : undefined,
				Left   : undefined,
				Right  : undefined,
				Top    : undefined
			};
		}

		if (null === nValue)
			this.CellPr.TableCellMar.Right = undefined;
		else
			this.CellPr.TableCellMar.Right = private_GetTableMeasure("twips", nValue);
		this.private_OnChange();
	};
	/**
	 * Specify the amount of space which will be left between the upper extent of the cell contents
	 * and the border of a specific table cell within a table.
	 * @typeofeditors ["CDE"]
	 * @param {?twips} nValue - The value for the amount of space above the upper extent of the cell measured in twentieths
	 * of a point (1/1440 of an inch). If this value is <code>null</code>, then default table cell top margin will be used, otherwise
	 * the table cell top margin will be overridden with the specified value for the current cell.
	 */
	ApiTableCellPr.prototype.SetCellMarginTop = function(nValue)
	{
		if (!this.CellPr.TableCellMar)
		{
			this.CellPr.TableCellMar =
			{
				Bottom : undefined,
				Left   : undefined,
				Right  : undefined,
				Top    : undefined
			};
		}

		if (null === nValue)
			this.CellPr.TableCellMar.Top = undefined;
		else
			this.CellPr.TableCellMar.Top = private_GetTableMeasure("twips", nValue);
		this.private_OnChange();
	};
	/**
	 * Set the border which will be displayed at the bottom of the current table cell.
	 * @typeofeditors ["CDE"]
	 * @param {BorderType} sType - The cell bottom border style.
	 * @param {pt_8} nSize - The width of the current cell bottom border measured in eighths of a point.
	 * @param {pt} nSpace - The spacing offset in the bottom part of the table cell measured in points used to place this border.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 */
	ApiTableCellPr.prototype.SetCellBorderBottom = function(sType, nSize, nSpace, r, g, b)
	{
		this.CellPr.TableCellBorders.Bottom = private_GetTableBorder(sType, nSize, nSpace, r, g, b);
		this.private_OnChange();
	};
	/**
	 * Set the border which will be displayed to the left of the current table cell.
	 * @typeofeditors ["CDE"]
	 * @param {BorderType} sType - The cell left border style.
	 * @param {pt_8} nSize - The width of the current cell left border measured in eighths of a point.
	 * @param {pt} nSpace - The spacing offset in the left part of the table cell measured in points used to place this border.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 */
	ApiTableCellPr.prototype.SetCellBorderLeft = function(sType, nSize, nSpace, r, g, b)
	{
		this.CellPr.TableCellBorders.Left = private_GetTableBorder(sType, nSize, nSpace, r, g, b);
		this.private_OnChange();
	};
	/**
	 * Set the border which will be displayed to the right of the current table cell.
	 * @typeofeditors ["CDE"]
	 * @param {BorderType} sType - The cell right border style.
	 * @param {pt_8} nSize - The width of the current cell right border measured in eighths of a point.
	 * @param {pt} nSpace - The spacing offset in the right part of the table cell measured in points used to place this border.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 */
	ApiTableCellPr.prototype.SetCellBorderRight = function(sType, nSize, nSpace, r, g, b)
	{
		this.CellPr.TableCellBorders.Right = private_GetTableBorder(sType, nSize, nSpace, r, g, b);
		this.private_OnChange();
	};
	/**
	 * Set the border which will be displayed at the top of the current table cell.
	 * @typeofeditors ["CDE"]
	 * @param {BorderType} sType - The cell top border style.
	 * @param {pt_8} nSize - The width of the current cell top border measured in eighths of a point.
	 * @param {pt} nSpace - The spacing offset in the top part of the table cell measured in points used to place this border.
	 * @param {byte} r - Red color component value.
	 * @param {byte} g - Green color component value.
	 * @param {byte} b - Blue color component value.
	 */
	ApiTableCellPr.prototype.SetCellBorderTop = function(sType, nSize, nSpace, r, g, b)
	{
		this.CellPr.TableCellBorders.Top = private_GetTableBorder(sType, nSize, nSpace, r, g, b);
		this.private_OnChange();
	};
	/**
	 * Set the preferred width for the current table cell.
	 * @typeofeditors ["CDE"]
	 * @param {TableWidth} sType - Type of the width value from one of the available width values types.
	 * @param {number} [nValue] - The table cell width value measured in positive integers.
	 */
	ApiTableCellPr.prototype.SetWidth = function(sType, nValue)
	{
		this.CellPr.TableCellW = private_GetTableMeasure(sType, nValue);
		this.private_OnChange();
	};
	/**
	 * Specify the vertical alignment for text contents within the current table cell.
	 * @typeofeditors ["CDE"]
	 * @param {("top" | "center" | "bottom")} sType - The available types of the vertical alignment for the text contents of the current table cell.
	 */
	ApiTableCellPr.prototype.SetVerticalAlign = function(sType)
	{
		if ("top" === sType)
			this.CellPr.VAlign = vertalignjc_Top;
		else if ("bottom" === sType)
			this.CellPr.VAlign = vertalignjc_Bottom;
		else if ("center" === sType)
			this.CellPr.VAlign = vertalignjc_Center;

		this.private_OnChange();
	};
	/**
	 * Specify the direction of the text flow for this table cell.
	 * @typeofeditors ["CDE"]
	 * @param {("lrtb" | "tbrl" | "btlr")} sType - The available types of the text direction in the table cell: <code>"lrtb"</code>
	 * - text direction left-to-right moving from top to bottom, <code>"tbrl"</code> - text direction top-to-bottom moving from right
	 * to left, <code>"btlr"</code> - text direction bottom-to-top moving from left to right.
	 */
	ApiTableCellPr.prototype.SetTextDirection = function(sType)
	{
		if ("lrtb" === sType)
			this.CellPr.TextDirection = textdirection_LRTB;
		else if ("tbrl" === sType)
			this.CellPr.TextDirection = textdirection_TBRL;
		else if ("btlr" === sType)
			this.CellPr.TextDirection = textdirection_BTLR;

		this.private_OnChange();
	};
	/**
	 * Specify how this table cell is laid out when the parent table is displayed in a document. This setting
	 * only affects the behavior of the cell when the {@link ApiTablePr#SetTableLayout} table layout for this table is set to use the <code>"autofit"</code> algorithm.
	 * @typeofeditors ["CDE"]
	 * @param {boolean} isNoWrap - The true value will enable the <code>SetNoWrap</code> method use.
	 */
	ApiTableCellPr.prototype.SetNoWrap = function(isNoWrap)
	{
		this.CellPr.NoWrap = private_GetBoolean(isNoWrap);
		this.private_OnChange();
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiTableStylePr
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE"]
	 * @returns {"tableStylePr"}
	 */
	ApiTableStylePr.prototype.GetClassType = function()
	{
		return "tableStylePr";
	};
	/**
	 * Get the type of the current table conditional style.
	 * @typeofeditors ["CDE"]
	 * @returns {TableStyleOverrideType}
	 */
	ApiTableStylePr.prototype.GetType = function()
	{
		return this.Type;
	};
	/**
	 * Get the set of the text run properties which will be applied to all the text runs within the table which match the conditional formatting type.
	 * @typeofeditors ["CDE"]
	 * @returns {ApiTextPr}
	 */
	ApiTableStylePr.prototype.GetTextPr = function()
	{
		return new ApiTextPr(this, this.TableStylePr.TextPr);
	};
	/**
	 * Get the set of the paragraph properties which will be applied to all the paragraphs within a table which match the conditional formatting type.
	 * @typeofeditors ["CDE"]
	 * @returns {ApiParaPr}
	 */
	ApiTableStylePr.prototype.GetParaPr = function()
	{
		return new ApiParaPr(this, this.TableStylePr.ParaPr);
	};
	/**
	 * Get the set of the table properties which will be applied to all the regions within a table which match the conditional formatting type.
	 * @typeofeditors ["CDE"]
	 * @returns {ApiTablePr}
	 */
	ApiTableStylePr.prototype.GetTablePr = function()
	{
		return new ApiTablePr(this, this.TableStylePr.TablePr);
	};
	/**
	 * Get the set of the table row properties which will be applied to all the rows within a table which match the conditional formatting type.
	 * @typeofeditors ["CDE"]
	 * @returns {ApiTableRowPr}
	 */
	ApiTableStylePr.prototype.GetTableRowPr = function()
	{
		return new ApiTableRowPr(this, this.TableStylePr.TableRowPr);
	};
	/**
	 * Get the set of the table cell properties which will be applied to all the cells within a table which match the conditional formatting type.
	 * @typeofeditors ["CDE"]
	 * @returns {ApiTableCellPr}
	 */
	ApiTableStylePr.prototype.GetTableCellPr = function()
	{
		return new ApiTableCellPr(this, this.TableStylePr.TableCellPr);
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiDrawing
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of the class based on this base class.
	 * @typeofeditors ["CDE", "CPE"]
	 * @returns {"drawing"}
	 */
	ApiDrawing.prototype.GetClassType = function()
	{
		return "drawing";
	};
	/**
	 * Set the size of the object (image, shape, chart) bounding box.
	 * @typeofeditors ["CDE"]
	 * @param {EMU} nWidth - The object width measured in English measure units.
	 * @param {EMU} nHeight - The object height measured in English measure units.
	 */
	ApiDrawing.prototype.SetSize = function(nWidth, nHeight)
	{
		var fWidth = private_EMU2MM(nWidth);
		var fHeight = private_EMU2MM(nHeight);
		this.Drawing.setExtent(fWidth, fHeight);
		if(this.Drawing.GraphicObj && this.Drawing.GraphicObj.spPr && this.Drawing.GraphicObj.spPr.xfrm)
		{
			this.Drawing.GraphicObj.spPr.xfrm.setExtX(fWidth);
			this.Drawing.GraphicObj.spPr.xfrm.setExtY(fHeight);
		}
	};
	/**
	 * Set the wrapping type of this object (image, shape, chart). One of the following wrapping style types can be set:
	 * * <b>"inline"</b> - the object is considered to be a part of the text, like a character, so when the text moves, the object moves as well. In this case the positioning options are inaccessible.
	 * If one of the following styles is selected, the object can be moved independently of the text and positioned on the page exactly:
	 * * <b>"square"</b> - the text wraps the rectangular box that bounds the object.
	 * * <b>"tight"</b> - the text wraps the actual object edges.
	 * * <b>"through"</b> - the text wraps around the object edges and fills in the open white space within the object.
	 * * <b>"topAndBottom"</b> - the text is only above and below the object.
	 * * <b>"behind"</b> - the text overlaps the object.
	 * * <b>"inFront"</b> - the object overlaps the text.
	 * @typeofeditors ["CDE"]
	 * @param {"inline" | "square" | "tight" | "through" | "topAndBottom" | "behind" | "inFront"} sType
	 */
	ApiDrawing.prototype.SetWrappingStyle = function(sType)
	{
		if(this.Drawing)
		{
			if ("inline" === sType)
			{
				this.Drawing.Set_DrawingType(drawing_Inline);
				this.Drawing.Set_WrappingType(WRAPPING_TYPE_NONE);
				this.Drawing.Set_BehindDoc(false);
			}
			else if ("square" === sType)
			{
				this.Drawing.Set_DrawingType(drawing_Anchor);
				this.Drawing.Set_WrappingType(WRAPPING_TYPE_SQUARE);
				this.Drawing.Set_BehindDoc(false);
			}
			else if ("tight" === sType)
			{
				this.Drawing.Set_DrawingType(drawing_Anchor);
				this.Drawing.Set_WrappingType(WRAPPING_TYPE_TIGHT);
				this.Drawing.Set_BehindDoc(true);
			}
			else if ("through" === sType)
			{
				this.Drawing.Set_DrawingType(drawing_Anchor);
				this.Drawing.Set_WrappingType(WRAPPING_TYPE_THROUGH);
				this.Drawing.Set_BehindDoc(true);
			}
			else if ("topAndBottom" === sType)
			{
				this.Drawing.Set_DrawingType(drawing_Anchor);
				this.Drawing.Set_WrappingType(WRAPPING_TYPE_TOP_AND_BOTTOM);
				this.Drawing.Set_BehindDoc(false);
			}
			else if ("behind" === sType)
			{
				this.Drawing.Set_DrawingType(drawing_Anchor);
				this.Drawing.Set_WrappingType(WRAPPING_TYPE_NONE);
				this.Drawing.Set_BehindDoc(true);
			}
			else if ("inFront" === sType)
			{
				this.Drawing.Set_DrawingType(drawing_Anchor);
				this.Drawing.Set_WrappingType(WRAPPING_TYPE_NONE);
				this.Drawing.Set_BehindDoc(false);
			}
			this.Drawing.Check_WrapPolygon();
			if(this.Drawing.GraphicObj && this.Drawing.GraphicObj.setRecalculateInfo)
			{
				this.Drawing.GraphicObj.setRecalculateInfo();
			}
		}
	};

	/**
	 * Specify how the floating object will be horizontally aligned.
	 * @typeofeditors ["CDE"]
	 * @param {RelFromH} [sRelativeFrom="page"] - The document element which will be taken as a countdown point for the object horizontal alignment.
	 * @param {("left" | "right" | "center")} [sAlign="left"] - The alingment type which will be used for the object horizontal alignment.
	 */
	ApiDrawing.prototype.SetHorAlign = function(sRelativeFrom, sAlign)
	{
		var nAlign        = private_GetAlignH(sAlign);
		var nRelativeFrom = private_GetRelativeFromH(sRelativeFrom);
		this.Drawing.Set_PositionH(nRelativeFrom, true, nAlign, false);
	};
	/**
	 * Specify how the floating object will be vertically aligned.
	 * @typeofeditors ["CDE"]
	 * @param {RelFromV} [sRelativeFrom="page"] - The document element which will be taken as a countdown point for the object vertical alignment.
	 * @param {("top" | "bottom" | "center")} [sAlign="top"] - The alingment type which will be used for the object vertical alignment.
	 */
	ApiDrawing.prototype.SetVerAlign = function(sRelativeFrom, sAlign)
	{
		var nAlign        = private_GetAlignV(sAlign);
		var nRelativeFrom = private_GetRelativeFromV(sRelativeFrom);
		this.Drawing.Set_PositionV(nRelativeFrom, true, nAlign, false);
	};
	/**
	 * Set an absolute measurement for the horizontal positioning of the floating object.
	 * @typeofeditors ["CDE"]
	 * @param {RelFromH} sRelativeFrom - The document element which will be taken as a countdown point for the object horizontal alignment.
	 * @param {EMU} nDistance - The distance from the right side of the document element to the floating object measured in English measure units.
	 */
	ApiDrawing.prototype.SetHorPosition = function(sRelativeFrom, nDistance)
	{
		var nValue        = private_EMU2MM(nDistance);
		var nRelativeFrom = private_GetRelativeFromH(sRelativeFrom);
		this.Drawing.Set_PositionH(nRelativeFrom, false, nValue, false);
	};
	/**
	 * Set an absolute measurement for the vertical positioning of the floating object.
	 * @typeofeditors ["CDE"]
	 * @param {RelFromH} sRelativeFrom - The document element which will be taken as a countdown point for the object vertical alignment.
	 * @param {EMU} nDistance - The distance from the bottom part of the document element to the floating object measured in English measure units.
	 */
	ApiDrawing.prototype.SetVerPosition = function(sRelativeFrom, nDistance)
	{
		var nValue        = private_EMU2MM(nDistance);
		var nRelativeFrom = private_GetRelativeFromV(sRelativeFrom);
		this.Drawing.Set_PositionV(nRelativeFrom, false, nValue, false);
	};
	/**
	 * Specify the minimum distance which will be maintained between the edges of this drawing object and any
	 * subsequent text.
	 * @typeofeditors ["CDE"]
	 * @param {EMU} nLeft - The distance from the left side of the current object and the subsequent text run measured in English measure units.
	 * @param {EMU} nTop - The distance from the top side of the current object and the preceding text run measured in English measure units.
	 * @param {EMU} nRight - The distance from the right side of the current object and the subsequent text run measured in English measure units.
	 * @param {EMU} nBottom - The distance from the bottom side of the current object and the subsequent text run measured in English measure units.
	 */
	ApiDrawing.prototype.SetDistances = function(nLeft, nTop, nRight, nBottom)
	{
		this.Drawing.Set_Distance(private_EMU2MM(nLeft), private_EMU2MM(nTop), private_EMU2MM(nRight), private_EMU2MM(nBottom));
	};


	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiImage
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE", "CPE"]
	 * @returns {"image"}
	 */
	ApiImage.prototype.GetClassType = function()
	{
		return "image";
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiShape
	//
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE", "CSE"]
	 * @returns {"shape"}
	 */
	ApiShape.prototype.GetClassType = function()
	{
		return "shape";
	};


	/**
	 * Get the shape inner contents where a paragraph or text runs can be inserted.
	 * @typeofeditors ["CDE", "CSE"]
	 * @returns {?ApiDocumentContent}
	 */
	ApiShape.prototype.GetDocContent = function()
	{
		if(this.Shape && this.Shape.textBoxContent)
		{
			return new ApiDocumentContent(this.Shape.textBoxContent);
		}
		return null;
	};

	/**
	 * Set the vertical alignment for the shape content where a paragraph or text runs can be inserted.
	 * @typeofeditors ["CDE", "CSE"]
	 * @param {VerticalTextAlign} VerticalAlign - The type of the vertical alignment for the shape inner contents.
	 */
	ApiShape.prototype.SetVerticalTextAlign = function(VerticalAlign)
	{
		if(this.Shape)
		{
			switch(VerticalAlign)
			{
				case "top":
				{
					this.Shape.setVerticalAlign(4);
					break;
				}
				case "center":
				{
					this.Shape.setVerticalAlign(1);
					break;
				}
				case "bottom":
				{
					this.Shape.setVerticalAlign(0);
					break;
				}
			}
		}
	};




	/**
	 * Set text paddings
	 * @param {?EMU} nLeft
	 * @param {?EMU} nTop
	 * @param {?EMU} nRight
	 * @param {?EMU} nBottom
	 */
	ApiShape.prototype.SetPaddings = function(nLeft, nTop, nRight, nBottom)
	{
		if(this.Shape)
		{
			this.Shape.setPaddings({
				Left: AscFormat.isRealNumber(nLeft) ? private_EMU2MM(nLeft) : null,
				Top: AscFormat.isRealNumber(nTop) ? private_EMU2MM(nTop) : null,
				Right: AscFormat.isRealNumber(nRight) ? private_EMU2MM(nRight) : null,
				Bottom: AscFormat.isRealNumber(nBottom) ? private_EMU2MM(nBottom) : null
			});
		}
	};



	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiChart
	//
	//------------------------------------------------------------------------------------------------------------------
	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE"]
	 * @returns {"chart"}
	 */
	ApiChart.prototype.GetClassType = function()
	{
		return "chart";
	};


	ApiChart.prototype.CreateTitle = function(sTitle, nFontSize){
		if(!this.Chart)
		{
			return null;
		}
		if(typeof sTitle === "string" && sTitle.length > 0){
			var oTitle = new AscFormat.CTitle();
			oTitle.setOverlay(false);
			oTitle.setTx(new AscFormat.CChartText());
			var oTextBody = AscFormat.CreateTextBodyFromString(sTitle, this.Chart.getDrawingDocument(), oTitle.tx);
			if(AscFormat.isRealNumber(nFontSize)){
				oTextBody.content.Set_ApplyToAll(true);
				oTextBody.content.AddToParagraph(new ParaTextPr({ FontSize : nFontSize}));
				oTextBody.content.Set_ApplyToAll(false);
			}
			oTitle.tx.setRich(oTextBody);
			return oTitle;
		}
		return null;
	};


	/**
	 *  Specifies a chart title
	 *  @typeofeditors ["CDE"]
	 *  @param {string} sTitle - The title which will be displayed for the current chart.
	 *  @param {hps} nFontSize - The text size value measured in points.
	 *  @param {?bool} bIsBold
	 */
	ApiChart.prototype.SetTitle = function (sTitle, nFontSize, bIsBold)
	{
		AscFormat.builder_SetChartTitle(this.Chart, sTitle, nFontSize, bIsBold);
	};

	/**
	 *  Specifies a horizontal axis title
	 *  @typeofeditors ["CDE"]
	 *  @param {string} sTitle - The title which will be displayed for the horizontal axis of the current chart.
	 *  @param {hps} nFontSize - The text size value measured in points.
	 *  @param {?bool} bIsBold
	 * */
	ApiChart.prototype.SetHorAxisTitle = function (sTitle, nFontSize, bIsBold)
	{
		AscFormat.builder_SetChartHorAxisTitle(this.Chart, sTitle, nFontSize, bIsBold);
	};

	/**
	 *  Specifies a vertical axis title
	 *  @typeofeditors ["CDE"]
	 *  @param {string} sTitle - The title which will be displayed for the vertical axis of the current chart.
	 *  @param {hps} nFontSize - The text size value measured in points.
	 *  @param {?bool} bIsBold
	 * */
	ApiChart.prototype.SetVerAxisTitle = function (sTitle, nFontSize, bIsBold)
	{
		AscFormat.builder_SetChartVertAxisTitle(this.Chart, sTitle, nFontSize, bIsBold);
	};

	/**
	 * Specifies a  vertical axis orientation
	 * @param {bool} bIsMinMax
	 * */
	ApiChart.prototype.SetVerAxisOrientation = function(bIsMinMax){
		AscFormat.builder_SetChartVertAxisOrientation(this.Chart, bIsMinMax);
	};

	/**
	 * Specifies a  horizontal axis orientation
	 * @param {bool} bIsMinMax
	 * */
	ApiChart.prototype.SetHorAxisOrientation = function(bIsMinMax){
		AscFormat.builder_SetChartHorAxisOrientation(this.Chart, bIsMinMax);
	};

	/**
	 * Specifies a legend position
	 * @typeofeditors ["CDE"]
	 * @param {"left" | "top" | "right" | "bottom" | "none"} sLegendPos - The position of the chart legend inside the chart window.
	 * */
	ApiChart.prototype.SetLegendPos = function(sLegendPos)
	{
		if(this.Chart && this.Chart.chart)
		{
			if(sLegendPos === "none")
			{
				if(this.Chart.chart.legend)
				{
					this.Chart.chart.setLegend(null);
				}
			}
			else
			{
				var nLegendPos = null;
				switch(sLegendPos)
				{
					case "left":
					{
						nLegendPos = Asc.c_oAscChartLegendShowSettings.left;
						break;
					}
					case "top":
					{
						nLegendPos = Asc.c_oAscChartLegendShowSettings.top;
						break;
					}
					case "right":
					{
						nLegendPos = Asc.c_oAscChartLegendShowSettings.right;
						break;
					}
					case "bottom":
					{
						nLegendPos = Asc.c_oAscChartLegendShowSettings.bottom;
						break;
					}
				}
				if(null !== nLegendPos)
				{
					if(!this.Chart.chart.legend)
					{
						this.Chart.chart.setLegend(new AscFormat.CLegend());
					}
					if(this.Chart.chart.legend.legendPos !== nLegendPos)
						this.Chart.chart.legend.setLegendPos(nLegendPos);
					if(this.Chart.chart.legend.overlay !== false)
					{
						this.Chart.chart.legend.setOverlay(false);
					}
				}
			}
		}
	};

	/**
	 * Specifies a legend position
	 * @number nFontSize
	 * */
	ApiChart.prototype.SetLegendFontSize = function(nFontSize)
	{
		AscFormat.builder_SetLegendFontSize(this.Chart, nFontSize);
	};

	/**
	 * Specifies which chart data labels are shown for the chart.
	 * @typeofeditors ["CDE"]
	 * @param {boolean} bShowSerName - Whether to show or hide the source table column names used for the data which the chart will be build from.
	 * @param {boolean} bShowCatName - Whether to show or hide the source table row names used for the data which the chart will be build from.
	 * @param {boolean} bShowVal - Whether to show or hide the chart data values.
	 * @param {boolean} bShowPercent - Whether to show or hide the percent for the data values (works with stacked chart types).
	 * */
	ApiChart.prototype.SetShowDataLabels = function(bShowSerName, bShowCatName, bShowVal, bShowPercent)
	{
		AscFormat.builder_SetShowDataLabels(this.Chart, bShowSerName, bShowCatName, bShowVal, bShowPercent);
	};


	/**
	 * Spicifies a show options for data labels
	 * @param {number} nSeriesIndex
	 * @param {number} nPointIndex
	 * @param {boolean} bShowSerName
	 * @param {boolean} bShowCatName
	 * @param {boolean} bShowVal
	 * @param {boolean} bShowPercent
	 * */
	ApiChart.prototype.SetShowPointDataLabel = function(nSeriesIndex, nPointIndex, bShowSerName, bShowCatName, bShowVal, bShowPercent)
	{
		AscFormat.builder_SetShowPointDataLabel(this.Chart, nSeriesIndex, nPointIndex, bShowSerName, bShowCatName, bShowVal, bShowPercent);
	};

	/**
	 * Spicifies tick labels position vertical axis
	 * @param {TickLabelPosition} sTickLabelPosition
	 * */
	ApiChart.prototype.SetVertAxisTickLabelPosition = function(sTickLabelPosition)
	{
		AscFormat.builder_SetChartVertAxisTickLablePosition(this.Chart, sTickLabelPosition);
	};
	/**
	 * Spicifies tick labels position horizontal axis
	 * @param {TickLabelPosition} sTickLabelPosition
	 * */
	ApiChart.prototype.SetHorAxisTickLabelPosition = function(sTickLabelPosition)
	{
		AscFormat.builder_SetChartHorAxisTickLablePosition(this.Chart, sTickLabelPosition);
	};


	/**
	 * Specifies major tick mark for horizontal axis
	 * @param {TickMark} sTickMark
	 * */

	ApiChart.prototype.SetHorAxisMajorTickMark = function(sTickMark){
		AscFormat.builder_SetChartHorAxisMajorTickMark(this.Chart, sTickMark);
	};
	/**
	 * Specifies minor tick mark for horizontal axis
	 * @param {TickMark} sTickMark
	 * */

	ApiChart.prototype.SetHorAxisMinorTickMark = function(sTickMark){
		AscFormat.builder_SetChartHorAxisMinorTickMark(this.Chart, sTickMark);
	};

	/**
	 * Specifies major tick mark for vertical axis
	 * @param {TickMark} sTickMark
	 * */

	ApiChart.prototype.SetVertAxisMajorTickMark = function(sTickMark){
		AscFormat.builder_SetChartVerAxisMajorTickMark(this.Chart, sTickMark);
	};

	/**
	 * Specifies minor tick mark for vertical axis
	 * @param {TickMark} sTickMark
	 * */
	ApiChart.prototype.SetVertAxisMinorTickMark = function(sTickMark){
		AscFormat.builder_SetChartVerAxisMinorTickMark(this.Chart, sTickMark);
	};



	/**
	 * Specifies major vertical gridline's visual properties
	 * @param {?ApiStroke} oStroke
	 * */
	ApiChart.prototype.SetMajorVerticalGridlines = function(oStroke)
	{
		AscFormat.builder_SetVerAxisMajorGridlines(this.Chart, oStroke ?  oStroke.Ln : null);
	};

	/**
	 * Specifies minor vertical gridline's visual properties
	 * @param {?ApiStroke} oStroke
	 * */
	ApiChart.prototype.SetMinorVerticalGridlines = function(oStroke)
	{
		AscFormat.builder_SetVerAxisMinorGridlines(this.Chart, oStroke ?  oStroke.Ln : null);
	};


	/**
	 * Specifies major horizontal gridline's visual properties
	 * @param {?ApiStroke} oStroke
	 * */
	ApiChart.prototype.SetMajorHorizontalGridlines = function(oStroke)
	{
		AscFormat.builder_SetHorAxisMajorGridlines(this.Chart, oStroke ?  oStroke.Ln : null);
	};

	/**
	 * Specifies minor vertical gridline's visual properties
	 * @param {?ApiStroke} oStroke
	 * */
	ApiChart.prototype.SetMinorHorizontalGridlines = function(oStroke)
	{
		AscFormat.builder_SetHorAxisMinorGridlines(this.Chart, oStroke ?  oStroke.Ln : null);
	};


	/**
	 * Specifies font size for labels of horizontal axis
	 * @param {number} nFontSize
	 */
	ApiChart.prototype.SetHorAxisLablesFontSize = function(nFontSize){
		AscFormat.builder_SetHorAxisFontSize(this.Chart, nFontSize);
	};

	/**
	 * Specifies font size for labels of vertical axis
	 * @param {number} nFontSize
	 */
	ApiChart.prototype.SetVertAxisLablesFontSize = function(nFontSize){
		AscFormat.builder_SetVerAxisFontSize(this.Chart, nFontSize);
	};


	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiFill
	//
	//------------------------------------------------------------------------------------------------------------------
	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {"fill"}
	 */
	ApiFill.prototype.GetClassType = function()
	{
		return "fill";
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiStroke
	//
	//------------------------------------------------------------------------------------------------------------------
	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {"stroke"}
	 */
	ApiStroke.prototype.GetClassType = function()
	{
		return "stroke";
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiGradientStop
	//
	//------------------------------------------------------------------------------------------------------------------
	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {"gradientStop"}
	 */
	ApiGradientStop.prototype.GetClassType = function ()
	{
		return "gradientStop"
	};
	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiUniColor
	//
	//------------------------------------------------------------------------------------------------------------------
	/**
	 * Get the type of the class based on this base class.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {"uniColor"}
	 */
	ApiUniColor.prototype.GetClassType = function ()
	{
		return "uniColor"
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiRGBColor
	//
	//------------------------------------------------------------------------------------------------------------------
	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {"rgbColor"}
	 */
	ApiRGBColor.prototype.GetClassType = function ()
	{
		return "rgbColor"
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiSchemeColor
	//
	//------------------------------------------------------------------------------------------------------------------
	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE", "CSE", "CPE"]
	 * @returns {"schemeColor"}
	 */
	ApiSchemeColor.prototype.GetClassType = function ()
	{
		return "schemeColor"
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiPresetColor
	//
	//------------------------------------------------------------------------------------------------------------------
	/**
	 * Get the type of this class.
	 * @typeofeditors ["CDE", "CPE"]
	 * @returns {"presetColor"}
	 */
	ApiPresetColor.prototype.GetClassType = function ()
	{
		return "presetColor"
	};

	/**
	 * Get the type of this class.
	 * @typeofeditors ["CSE", "CPE"]
	 * @returns {"bullet"}
	 */
	ApiBullet.prototype.GetClassType = function()
	{
		return "bullet";
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiInlineLvlSdt
	//
	//------------------------------------------------------------------------------------------------------------------
	/**
	 * Get the type of this class.
	 * @returns {"inlineLvlSdt"}
	 */
	ApiInlineLvlSdt.prototype.GetClassType = function()
	{
		return "inlineLvlSdt";
	};
	/**
	 * Set the lock type of this container
	 * @param {SdtLock} sLockType
	 */
	ApiInlineLvlSdt.prototype.SetLock = function(sLockType)
	{
		var nLock = sdtlock_Unlocked;
		if ("contentLocked" === sLockType)
			nLock = sdtlock_ContentLocked;
		else if ("sdtContentLocked" === sLockType)
			nLock = sdtlock_SdtContentLocked;
		else if ("sdtLocked" === sLockType)
			nLock = sdtlock_SdtLocked;

		this.Sdt.SetContentControlLock(nLock);
	};
	/**
	 * Get the lock type of this container
	 * @returns {SdtLock}
	 */
	ApiInlineLvlSdt.prototype.GetLock = function()
	{
		var nLock = this.Sdt.GetContentControlLock();

		var sResult = "unlocked";

		if (sdtlock_ContentLocked === nLock)
			sResult = "contentLocked";
		else if (sdtlock_SdtContentLocked === nLock)
			sResult = "sdtContentLocked";
		else if (sdtlock_SdtLocked === nLock)
			sResult = "sdtLocked";

		return sResult;
	};
	/**
	 * Set the tag attribute for this container
	 * @param {string} sTag
	 */
	ApiInlineLvlSdt.prototype.SetTag = function(sTag)
	{
		this.Sdt.SetTag(sTag);
	};
	/**
	 * Get the tag attribute for this container
	 * @returns {string}
	 */
	ApiInlineLvlSdt.prototype.GetTag = function()
	{
		return this.Sdt.GetTag();
	};
	/**
	 * Set the label attribute for this container
	 * @param {string} sLabel
	 */
	ApiInlineLvlSdt.prototype.SetLabel = function(sLabel)
	{
		this.Sdt.SetLabel(sLabel);
	};
	/**
	 * Get the label attribute for this container
	 * @returns {string}
	 */
	ApiInlineLvlSdt.prototype.GetLabel = function()
	{
		return this.Sdt.GetLabel();
	};
	/**
	 * Set the alias attribute for this container
	 * @param {string} sAlias
	 */
	ApiInlineLvlSdt.prototype.SetAlias = function(sAlias)
	{
		this.Sdt.SetAlias(sAlias);
	};
	/**
	 * Get the alias attribute for this container
	 * @returns {string}
	 */
	ApiInlineLvlSdt.prototype.GetAlias = function()
	{
		return this.Sdt.GetAlias();
	};
	/**
	 * Get the number of elements in the current container.
	 * @returns {number}
	 */
	ApiInlineLvlSdt.prototype.GetElementsCount = function()
	{
		return this.Sdt.Content.length;
	};
	/**
	 * Get the element of the container content by specified position.
	 * @param {number} nPos
	 * @returns {?ParagraphContent}
	 */
	ApiInlineLvlSdt.prototype.GetElement = function(nPos)
	{
		if (nPos < 0 || nPos >= this.Sdt.Content.length)
			return null;

		return private_GetSupportedParaElement(this.Sdt.Content[nPos]);
	};
	/**
	 * Remove element by specified position.
	 * @param {number} nPos
	 */
	ApiInlineLvlSdt.prototype.RemoveElement = function(nPos)
	{
		if (nPos < 0 || nPos >= this.Sdt.Content.length)
			return;

		this.Sdt.Remove_FromContent(nPos, 1);
	};
	/**
	 * Remove all elements.
	 */
	ApiInlineLvlSdt.prototype.RemoveAllElements = function()
	{
		if (this.Sdt.Content.length > 0)
			this.Sdt.Remove_FromContent(0, this.Sdt.Content.length);
	};
	/**
	 * Add an element to inline container.
	 * @param {ParagraphContent} oElement
	 * @param {number} [nPos] If this value is not specified then element will be added to the end of this container.
	 * @returns {boolean} Returns <code>false</code> if the type of <code>oElement</code> is not supported.
	 * content.
	 */
	ApiInlineLvlSdt.prototype.AddElement = function(oElement, nPos)
	{
		if (!private_IsSupportedParaElement(oElement) || nPos < 0 || nPos > this.Sdt.Content.length)
			return false;

		var oParaElement = oElement.private_GetImpl();
		if (undefined !== nPos)
		{
			this.Sdt.Add_ToContent(nPos, oParaElement);
		}
		else
		{
			private_PushElementToParagraph(this.Sdt, oParaElement);
		}

		return true;
	};

	//------------------------------------------------------------------------------------------------------------------
	//
	// ApiBlockLvlSdt
	//
	//------------------------------------------------------------------------------------------------------------------
	/**
	 * Get the type of this class.
	 * @returns {"blockLvlSdt"}
	 */
	ApiBlockLvlSdt.prototype.GetClassType = function()
	{
		return "blockLvlSdt";
	};
	/**
	 * Set the lock type of this container
	 * @param {SdtLock} sLockType
	 */
	ApiBlockLvlSdt.prototype.SetLock = function(sLockType)
	{
		var nLock = sdtlock_Unlocked;
		if ("contentLocked" === sLockType)
			nLock = sdtlock_ContentLocked;
		else if ("sdtContentLocked" === sLockType)
			nLock = sdtlock_SdtContentLocked;
		else if ("sdtLocked" === sLockType)
			nLock = sdtlock_SdtLocked;

		this.Sdt.SetContentControlLock(nLock);
	};
	/**
	 * Get the lock type of this container
	 * @returns {SdtLock}
	 */
	ApiBlockLvlSdt.prototype.GetLock = function()
	{
		var nLock = this.Sdt.GetContentControlLock();

		var sResult = "unlocked";

		if (sdtlock_ContentLocked === nLock)
			sResult = "contentLocked";
		else if (sdtlock_SdtContentLocked === nLock)
			sResult = "sdtContentLocked";
		else if (sdtlock_SdtLocked === nLock)
			sResult = "sdtLocked";

		return sResult;
	};
	/**
	 * Set the tag attribute for this container
	 * @param {string} sTag
	 */
	ApiBlockLvlSdt.prototype.SetTag = function(sTag)
	{
		this.Sdt.SetTag(sTag);
	};
	/**
	 * Get the tag attribute for this container
	 * @returns {string}
	 */
	ApiBlockLvlSdt.prototype.GetTag = function()
	{
		return this.Sdt.GetTag();
	};
	/**
	 * Set the label attribute for this container
	 * @param {string} sLabel
	 */
	ApiBlockLvlSdt.prototype.SetLabel = function(sLabel)
	{
		this.Sdt.SetLabel(sLabel);
	};
	/**
	 * Get the label attribute for this container
	 * @returns {string}
	 */
	ApiBlockLvlSdt.prototype.GetLabel = function()
	{
		return this.Sdt.GetLabel();
	};
	/**
	 * Set the alias attribute for this container
	 * @param {string} sAlias
	 */
	ApiBlockLvlSdt.prototype.SetAlias = function(sAlias)
	{
		this.Sdt.SetAlias(sAlias);
	};
	/**
	 * Get the alias attribute for this container
	 * @returns {string}
	 */
	ApiBlockLvlSdt.prototype.GetAlias = function()
	{
		return this.Sdt.GetAlias();
	};
	/**
	 * Get the content of this container
	 * @returns {ApiDocumentContent}
	 */
	ApiBlockLvlSdt.prototype.GetContent = function()
	{
		return new ApiDocumentContent(this.Sdt.GetContent());
	};
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Export
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	Api.prototype["GetDocument"]                     = Api.prototype.GetDocument;
	Api.prototype["CreateParagraph"]                 = Api.prototype.CreateParagraph;
	Api.prototype["CreateTable"]                     = Api.prototype.CreateTable;
	Api.prototype["CreateRun"]                       = Api.prototype.CreateRun;
	Api.prototype["CreateImage"]                     = Api.prototype.CreateImage;
	Api.prototype["CreateShape"]                     = Api.prototype.CreateShape;
	Api.prototype["CreateChart"]                     = Api.prototype.CreateChart;
	Api.prototype["CreateRGBColor"]                  = Api.prototype.CreateRGBColor;
	Api.prototype["CreateSchemeColor"]               = Api.prototype.CreateSchemeColor;
	Api.prototype["CreatePresetColor"]               = Api.prototype.CreatePresetColor;
	Api.prototype["CreateSolidFill"]                 = Api.prototype.CreateSolidFill;
	Api.prototype["CreateLinearGradientFill"]        = Api.prototype.CreateLinearGradientFill;
	Api.prototype["CreateRadialGradientFill"]        = Api.prototype.CreateRadialGradientFill;
	Api.prototype["CreatePatternFill"]               = Api.prototype.CreatePatternFill;
	Api.prototype["CreateBlipFill"]                  = Api.prototype.CreateBlipFill;
	Api.prototype["CreateNoFill"]                    = Api.prototype.CreateNoFill;
	Api.prototype["CreateStroke"]                    = Api.prototype.CreateStroke;
	Api.prototype["CreateGradientStop"]              = Api.prototype.CreateGradientStop;
	Api.prototype["CreateBullet"]                    = Api.prototype.CreateBullet;
	Api.prototype["CreateNumbering"]                 = Api.prototype.CreateNumbering;
	Api.prototype["CreateInlineLvlSdt"]              = Api.prototype.CreateInlineLvlSdt;
	Api.prototype["CreateBlockLvlSdt"]               = Api.prototype.CreateBlockLvlSdt;

	ApiUnsupported.prototype["GetClassType"]         = ApiUnsupported.prototype.GetClassType;

	ApiDocumentContent.prototype["GetClassType"]     = ApiDocumentContent.prototype.GetClassType;
	ApiDocumentContent.prototype["GetElementsCount"] = ApiDocumentContent.prototype.GetElementsCount;
	ApiDocumentContent.prototype["GetElement"]       = ApiDocumentContent.prototype.GetElement;
	ApiDocumentContent.prototype["AddElement"]       = ApiDocumentContent.prototype.AddElement;
	ApiDocumentContent.prototype["Push"]             = ApiDocumentContent.prototype.Push;
	ApiDocumentContent.prototype["RemoveAllElements"]= ApiDocumentContent.prototype.RemoveAllElements;
	ApiDocumentContent.prototype["RemoveElement"]    = ApiDocumentContent.prototype.RemoveElement;

	ApiDocument.prototype["GetClassType"]            = ApiDocument.prototype.GetClassType;
	ApiDocument.prototype["CreateNewHistoryPoint"]   = ApiDocument.prototype.CreateNewHistoryPoint;
	ApiDocument.prototype["GetDefaultTextPr"]        = ApiDocument.prototype.GetDefaultTextPr;
	ApiDocument.prototype["GetDefaultParaPr"]        = ApiDocument.prototype.GetDefaultParaPr;
	ApiDocument.prototype["GetStyle"]                = ApiDocument.prototype.GetStyle;
	ApiDocument.prototype["CreateStyle"]             = ApiDocument.prototype.CreateStyle;
	ApiDocument.prototype["GetDefaultStyle"]         = ApiDocument.prototype.GetDefaultStyle;
	ApiDocument.prototype["GetFinalSection"]         = ApiDocument.prototype.GetFinalSection;
	ApiDocument.prototype["CreateSection"]           = ApiDocument.prototype.CreateSection;
	ApiDocument.prototype["SetEvenAndOddHdrFtr"]     = ApiDocument.prototype.SetEvenAndOddHdrFtr;
	ApiDocument.prototype["CreateNumbering"]         = ApiDocument.prototype.CreateNumbering;
	ApiDocument.prototype["InsertContent"]           = ApiDocument.prototype.InsertContent;
	ApiDocument.prototype["GetCommentsReport"]       = ApiDocument.prototype.GetCommentsReport;
	ApiDocument.prototype["GetReviewReport"]         = ApiDocument.prototype.GetReviewReport;
	ApiDocument.prototype["InsertWatermark"]         = ApiDocument.prototype.InsertWatermark;
	ApiDocument.prototype["SearchAndReplace"]        = ApiDocument.prototype.SearchAndReplace;
	ApiDocument.prototype["GetAllContentControls"]   = ApiDocument.prototype.GetAllContentControls;

	ApiParagraph.prototype["GetClassType"]           = ApiParagraph.prototype.GetClassType;
	ApiParagraph.prototype["AddText"]                = ApiParagraph.prototype.AddText;
	ApiParagraph.prototype["AddPageBreak"]           = ApiParagraph.prototype.AddPageBreak;
	ApiParagraph.prototype["AddLineBreak"]           = ApiParagraph.prototype.AddLineBreak;
	ApiParagraph.prototype["AddColumnBreak"]         = ApiParagraph.prototype.AddColumnBreak;
	ApiParagraph.prototype["AddPageNumber"]          = ApiParagraph.prototype.AddPageNumber;
	ApiParagraph.prototype["AddPagesCount"]          = ApiParagraph.prototype.AddPagesCount;
	ApiParagraph.prototype["GetParagraphMarkTextPr"] = ApiParagraph.prototype.GetParagraphMarkTextPr;
	ApiParagraph.prototype["GetParaPr"]              = ApiParagraph.prototype.GetParaPr;
	ApiParagraph.prototype["GetNumbering"]           = ApiParagraph.prototype.GetNumbering;
	ApiParagraph.prototype["SetNumbering"]           = ApiParagraph.prototype.SetNumbering;
	ApiParagraph.prototype["GetElementsCount"]       = ApiParagraph.prototype.GetElementsCount;
	ApiParagraph.prototype["GetElement"]             = ApiParagraph.prototype.GetElement;
	ApiParagraph.prototype["RemoveElement"]          = ApiParagraph.prototype.RemoveElement;
	ApiParagraph.prototype["RemoveAllElements"]      = ApiParagraph.prototype.RemoveAllElements;
	ApiParagraph.prototype["AddElement"]             = ApiParagraph.prototype.AddElement;
	ApiParagraph.prototype["AddTabStop"]             = ApiParagraph.prototype.AddTabStop;
	ApiParagraph.prototype["AddDrawing"]             = ApiParagraph.prototype.AddDrawing;
	ApiParagraph.prototype["AddInlineLvlSdt"]        = ApiParagraph.prototype.AddInlineLvlSdt;

	ApiRun.prototype["GetClassType"]                 = ApiRun.prototype.GetClassType;
	ApiRun.prototype["GetTextPr"]                    = ApiRun.prototype.GetTextPr;
	ApiRun.prototype["ClearContent"]                 = ApiRun.prototype.ClearContent;
	ApiRun.prototype["AddText"]                      = ApiRun.prototype.AddText;
	ApiRun.prototype["AddPageBreak"]                 = ApiRun.prototype.AddPageBreak;
	ApiRun.prototype["AddLineBreak"]                 = ApiRun.prototype.AddLineBreak;
	ApiRun.prototype["AddColumnBreak"]               = ApiRun.prototype.AddColumnBreak;
	ApiRun.prototype["AddTabStop"]                   = ApiRun.prototype.AddTabStop;
	ApiRun.prototype["AddDrawing"]                   = ApiRun.prototype.AddDrawing;

	ApiSection.prototype["GetClassType"]             = ApiSection.prototype.GetClassType;
	ApiSection.prototype["SetType"]                  = ApiSection.prototype.SetType;
	ApiSection.prototype["SetEqualColumns"]          = ApiSection.prototype.SetEqualColumns;
	ApiSection.prototype["SetNotEqualColumns"]       = ApiSection.prototype.SetNotEqualColumns;
	ApiSection.prototype["SetPageSize"]              = ApiSection.prototype.SetPageSize;
	ApiSection.prototype["SetPageMargins"]           = ApiSection.prototype.SetPageMargins;
	ApiSection.prototype["SetHeaderDistance"]        = ApiSection.prototype.SetHeaderDistance;
	ApiSection.prototype["SetFooterDistance"]        = ApiSection.prototype.SetFooterDistance;
	ApiSection.prototype["GetHeader"]                = ApiSection.prototype.GetHeader;
	ApiSection.prototype["RemoveHeader"]             = ApiSection.prototype.RemoveHeader;
	ApiSection.prototype["GetFooter"]                = ApiSection.prototype.GetFooter;
	ApiSection.prototype["RemoveFooter"]             = ApiSection.prototype.RemoveFooter;
	ApiSection.prototype["SetTitlePage"]             = ApiSection.prototype.SetTitlePage;

	ApiTable.prototype["GetClassType"]               = ApiTable.prototype.GetClassType;
	ApiTable.prototype["SetJc"]                      = ApiTable.prototype.SetJc;
	ApiTable.prototype["GetRowsCount"]               = ApiTable.prototype.GetRowsCount;
	ApiTable.prototype["GetRow"]                     = ApiTable.prototype.GetRow;
	ApiTable.prototype["MergeCells"]                 = ApiTable.prototype.MergeCells;
	ApiTable.prototype["SetStyle"]                   = ApiTable.prototype.SetStyle;
	ApiTable.prototype["SetTableLook"]               = ApiTable.prototype.SetTableLook;
	ApiTable.prototype["AddRow"]                     = ApiTable.prototype.AddRow;
	ApiTable.prototype["AddColumn"]                  = ApiTable.prototype.AddColumn;
	ApiTable.prototype["RemoveRow"]                  = ApiTable.prototype.RemoveRow;
	ApiTable.prototype["RemoveColumn"]               = ApiTable.prototype.RemoveColumn;

	ApiTableRow.prototype["GetClassType"]            = ApiTableRow.prototype.GetClassType;
	ApiTableRow.prototype["GetCellsCount"]           = ApiTableRow.prototype.GetCellsCount;
	ApiTableRow.prototype["GetCell"]                 = ApiTableRow.prototype.GetCell;

	ApiTableCell.prototype["GetClassType"]           = ApiTableCell.prototype.GetClassType;
	ApiTableCell.prototype["GetContent"]             = ApiTableCell.prototype.GetContent;

	ApiStyle.prototype["GetClassType"]               = ApiStyle.prototype.GetClassType;
	ApiStyle.prototype["GetName"]                    = ApiStyle.prototype.GetName;
	ApiStyle.prototype["SetName"]                    = ApiStyle.prototype.SetName;
	ApiStyle.prototype["GetType"]                    = ApiStyle.prototype.GetType;
	ApiStyle.prototype["GetTextPr"]                  = ApiStyle.prototype.GetTextPr;
	ApiStyle.prototype["GetParaPr"]                  = ApiStyle.prototype.GetParaPr;
	ApiStyle.prototype["GetTablePr"]                 = ApiStyle.prototype.GetTablePr;
	ApiStyle.prototype["GetTableRowPr"]              = ApiStyle.prototype.GetTableRowPr;
	ApiStyle.prototype["GetTableCellPr"]             = ApiStyle.prototype.GetTableCellPr;
	ApiStyle.prototype["SetBasedOn"]                 = ApiStyle.prototype.SetBasedOn;
	ApiStyle.prototype["GetConditionalTableStyle"]   = ApiStyle.prototype.GetConditionalTableStyle;

	ApiNumbering.prototype["GetClassType"]           = ApiNumbering.prototype.GetClassType;
	ApiNumbering.prototype["GetLevel"]               = ApiNumbering.prototype.GetLevel;

	ApiNumberingLevel.prototype["GetClassType"]      = ApiNumberingLevel.prototype.GetClassType;
	ApiNumberingLevel.prototype["GetNumbering"]      = ApiNumberingLevel.prototype.GetNumbering;
	ApiNumberingLevel.prototype["GetLevelIndex"]     = ApiNumberingLevel.prototype.GetLevelIndex;
	ApiNumberingLevel.prototype["GetTextPr"]         = ApiNumberingLevel.prototype.GetTextPr;
	ApiNumberingLevel.prototype["GetParaPr"]         = ApiNumberingLevel.prototype.GetParaPr;
	ApiNumberingLevel.prototype["SetTemplateType"]   = ApiNumberingLevel.prototype.SetTemplateType;
	ApiNumberingLevel.prototype["SetCustomType"]     = ApiNumberingLevel.prototype.SetCustomType;
	ApiNumberingLevel.prototype["SetRestart"]        = ApiNumberingLevel.prototype.SetRestart;
	ApiNumberingLevel.prototype["SetStart"]          = ApiNumberingLevel.prototype.SetStart;
	ApiNumberingLevel.prototype["SetSuff"]           = ApiNumberingLevel.prototype.SetSuff;

	ApiTextPr.prototype["GetClassType"]              = ApiTextPr.prototype.GetClassType;
	ApiTextPr.prototype["SetStyle"]                  = ApiTextPr.prototype.SetStyle;
	ApiTextPr.prototype["SetBold"]                   = ApiTextPr.prototype.SetBold;
	ApiTextPr.prototype["SetItalic"]                 = ApiTextPr.prototype.SetItalic;
	ApiTextPr.prototype["SetStrikeout"]              = ApiTextPr.prototype.SetStrikeout;
	ApiTextPr.prototype["SetUnderline"]              = ApiTextPr.prototype.SetUnderline;
	ApiTextPr.prototype["SetFontFamily"]             = ApiTextPr.prototype.SetFontFamily;
	ApiTextPr.prototype["SetFontSize"]               = ApiTextPr.prototype.SetFontSize;
	ApiTextPr.prototype["SetColor"]                  = ApiTextPr.prototype.SetColor;
	ApiTextPr.prototype["SetVertAlign"]              = ApiTextPr.prototype.SetVertAlign;
	ApiTextPr.prototype["SetHighlight"]              = ApiTextPr.prototype.SetHighlight;
	ApiTextPr.prototype["SetSpacing"]                = ApiTextPr.prototype.SetSpacing;
	ApiTextPr.prototype["SetDoubleStrikeout"]        = ApiTextPr.prototype.SetDoubleStrikeout;
	ApiTextPr.prototype["SetCaps"]                   = ApiTextPr.prototype.SetCaps;
	ApiTextPr.prototype["SetSmallCaps"]              = ApiTextPr.prototype.SetSmallCaps;
	ApiTextPr.prototype["SetPosition"]               = ApiTextPr.prototype.SetPosition;
	ApiTextPr.prototype["SetLanguage"]               = ApiTextPr.prototype.SetLanguage;
	ApiTextPr.prototype["SetShd"]                    = ApiTextPr.prototype.SetShd;
	ApiTextPr.prototype["SetFill"]                   = ApiTextPr.prototype.SetFill;

	ApiParaPr.prototype["GetClassType"]              = ApiParaPr.prototype.GetClassType;
	ApiParaPr.prototype["SetStyle"]                  = ApiParaPr.prototype.SetStyle;
	ApiParaPr.prototype["SetContextualSpacing"]      = ApiParaPr.prototype.SetContextualSpacing;
	ApiParaPr.prototype["SetIndLeft"]                = ApiParaPr.prototype.SetIndLeft;
	ApiParaPr.prototype["SetIndRight"]               = ApiParaPr.prototype.SetIndRight;
	ApiParaPr.prototype["SetIndFirstLine"]           = ApiParaPr.prototype.SetIndFirstLine;
	ApiParaPr.prototype["SetJc"]                     = ApiParaPr.prototype.SetJc;
	ApiParaPr.prototype["SetKeepLines"]              = ApiParaPr.prototype.SetKeepLines;
	ApiParaPr.prototype["SetKeepNext"]               = ApiParaPr.prototype.SetKeepNext;
	ApiParaPr.prototype["SetPageBreakBefore"]        = ApiParaPr.prototype.SetPageBreakBefore;
	ApiParaPr.prototype["SetSpacingLine"]            = ApiParaPr.prototype.SetSpacingLine;
	ApiParaPr.prototype["SetSpacingBefore"]          = ApiParaPr.prototype.SetSpacingBefore;
	ApiParaPr.prototype["SetSpacingAfter"]           = ApiParaPr.prototype.SetSpacingAfter;
	ApiParaPr.prototype["SetShd"]                    = ApiParaPr.prototype.SetShd;
	ApiParaPr.prototype["SetBottomBorder"]           = ApiParaPr.prototype.SetBottomBorder;
	ApiParaPr.prototype["SetLeftBorder"]             = ApiParaPr.prototype.SetLeftBorder;
	ApiParaPr.prototype["SetRightBorder"]            = ApiParaPr.prototype.SetRightBorder;
	ApiParaPr.prototype["SetTopBorder"]              = ApiParaPr.prototype.SetTopBorder;
	ApiParaPr.prototype["SetBetweenBorder"]          = ApiParaPr.prototype.SetBetweenBorder;
	ApiParaPr.prototype["SetWidowControl"]           = ApiParaPr.prototype.SetWidowControl;
	ApiParaPr.prototype["SetTabs"]                   = ApiParaPr.prototype.SetTabs;
	ApiParaPr.prototype["SetNumPr"]                  = ApiParaPr.prototype.SetNumPr;
	ApiParaPr.prototype["SetBullet"]                 = ApiParaPr.prototype.SetBullet;

	ApiTablePr.prototype["GetClassType"]             = ApiTablePr.prototype.GetClassType;
	ApiTablePr.prototype["SetStyleColBandSize"]      = ApiTablePr.prototype.SetStyleColBandSize;
	ApiTablePr.prototype["SetStyleRowBandSize"]      = ApiTablePr.prototype.SetStyleRowBandSize;
	ApiTablePr.prototype["SetJc"]                    = ApiTablePr.prototype.SetJc;
	ApiTablePr.prototype["SetShd"]                   = ApiTablePr.prototype.SetShd;
	ApiTablePr.prototype["SetTableBorderTop"]        = ApiTablePr.prototype.SetTableBorderTop;
	ApiTablePr.prototype["SetTableBorderBottom"]     = ApiTablePr.prototype.SetTableBorderBottom;
	ApiTablePr.prototype["SetTableBorderLeft"]       = ApiTablePr.prototype.SetTableBorderLeft;
	ApiTablePr.prototype["SetTableBorderRight"]      = ApiTablePr.prototype.SetTableBorderRight;
	ApiTablePr.prototype["SetTableBorderInsideH"]    = ApiTablePr.prototype.SetTableBorderInsideH;
	ApiTablePr.prototype["SetTableBorderInsideV"]    = ApiTablePr.prototype.SetTableBorderInsideV;
	ApiTablePr.prototype["SetTableCellMarginBottom"] = ApiTablePr.prototype.SetTableCellMarginBottom;
	ApiTablePr.prototype["SetTableCellMarginLeft"]   = ApiTablePr.prototype.SetTableCellMarginLeft;
	ApiTablePr.prototype["SetTableCellMarginRight"]  = ApiTablePr.prototype.SetTableCellMarginRight;
	ApiTablePr.prototype["SetTableCellMarginTop"]    = ApiTablePr.prototype.SetTableCellMarginTop;
	ApiTablePr.prototype["SetCellSpacing"]           = ApiTablePr.prototype.SetCellSpacing;
	ApiTablePr.prototype["SetTableInd"]              = ApiTablePr.prototype.SetTableInd;
	ApiTablePr.prototype["SetWidth"]                 = ApiTablePr.prototype.SetWidth;
	ApiTablePr.prototype["SetTableLayout"]           = ApiTablePr.prototype.SetTableLayout;

	ApiTableRowPr.prototype["GetClassType"]          = ApiTableRowPr.prototype.GetClassType;
	ApiTableRowPr.prototype["SetHeight"]             = ApiTableRowPr.prototype.SetHeight;
	ApiTableRowPr.prototype["SetTableHeader"]        = ApiTableRowPr.prototype.SetTableHeader;

	ApiTableCellPr.prototype["GetClassType"]         = ApiTableCellPr.prototype.GetClassType;
	ApiTableCellPr.prototype["SetShd"]               = ApiTableCellPr.prototype.SetShd;
	ApiTableCellPr.prototype["SetCellMarginBottom"]  = ApiTableCellPr.prototype.SetCellMarginBottom;
	ApiTableCellPr.prototype["SetCellMarginLeft"]    = ApiTableCellPr.prototype.SetCellMarginLeft;
	ApiTableCellPr.prototype["SetCellMarginRight"]   = ApiTableCellPr.prototype.SetCellMarginRight;
	ApiTableCellPr.prototype["SetCellMarginTop"]     = ApiTableCellPr.prototype.SetCellMarginTop;
	ApiTableCellPr.prototype["SetCellBorderBottom"]  = ApiTableCellPr.prototype.SetCellBorderBottom;
	ApiTableCellPr.prototype["SetCellBorderLeft"]    = ApiTableCellPr.prototype.SetCellBorderLeft;
	ApiTableCellPr.prototype["SetCellBorderRight"]   = ApiTableCellPr.prototype.SetCellBorderRight;
	ApiTableCellPr.prototype["SetCellBorderTop"]     = ApiTableCellPr.prototype.SetCellBorderTop;
	ApiTableCellPr.prototype["SetWidth"]             = ApiTableCellPr.prototype.SetWidth;
	ApiTableCellPr.prototype["SetVerticalAlign"]     = ApiTableCellPr.prototype.SetVerticalAlign;
	ApiTableCellPr.prototype["SetTextDirection"]     = ApiTableCellPr.prototype.SetTextDirection;
	ApiTableCellPr.prototype["SetNoWrap"]            = ApiTableCellPr.prototype.SetNoWrap;

	ApiTableStylePr.prototype["GetClassType"]        = ApiTableStylePr.prototype.GetClassType;
	ApiTableStylePr.prototype["GetType"]             = ApiTableStylePr.prototype.GetType;
	ApiTableStylePr.prototype["GetTextPr"]           = ApiTableStylePr.prototype.GetTextPr;
	ApiTableStylePr.prototype["GetParaPr"]           = ApiTableStylePr.prototype.GetParaPr;
	ApiTableStylePr.prototype["GetTablePr"]          = ApiTableStylePr.prototype.GetTablePr;
	ApiTableStylePr.prototype["GetTableRowPr"]       = ApiTableStylePr.prototype.GetTableRowPr;
	ApiTableStylePr.prototype["GetTableCellPr"]      = ApiTableStylePr.prototype.GetTableCellPr;

	ApiDrawing.prototype["GetClassType"]             = ApiDrawing.prototype.GetClassType;
	ApiDrawing.prototype["SetSize"]                  = ApiDrawing.prototype.SetSize;
	ApiDrawing.prototype["SetWrappingStyle"]         = ApiDrawing.prototype.SetWrappingStyle;
	ApiDrawing.prototype["SetHorAlign"]              = ApiDrawing.prototype.SetHorAlign;
	ApiDrawing.prototype["SetVerAlign"]              = ApiDrawing.prototype.SetVerAlign;
	ApiDrawing.prototype["SetHorPosition"]           = ApiDrawing.prototype.SetHorPosition;
	ApiDrawing.prototype["SetVerPosition"]           = ApiDrawing.prototype.SetVerPosition;
	ApiDrawing.prototype["SetDistances"]             = ApiDrawing.prototype.SetDistances;

	ApiImage.prototype["GetClassType"]               = ApiImage.prototype.GetClassType;

	ApiShape.prototype["GetClassType"]               = ApiShape.prototype.GetClassType;
	ApiShape.prototype["GetDocContent"]              = ApiShape.prototype.GetDocContent;
	ApiShape.prototype["SetVerticalTextAlign"]       = ApiShape.prototype.SetVerticalTextAlign;
	ApiShape.prototype["SetPaddings"]                = ApiShape.prototype.SetPaddings;

	ApiChart.prototype["GetClassType"]                 = ApiChart.prototype.GetClassType;
	ApiChart.prototype["SetTitle"]                     = ApiChart.prototype.SetTitle;
	ApiChart.prototype["SetHorAxisTitle"]              = ApiChart.prototype.SetHorAxisTitle;
	ApiChart.prototype["SetVerAxisTitle"]              = ApiChart.prototype.SetVerAxisTitle;
	ApiChart.prototype["SetVerAxisOrientation"]        = ApiChart.prototype.SetVerAxisOrientation;
	ApiChart.prototype["SetHorAxisOrientation"]        = ApiChart.prototype.SetHorAxisOrientation;
	ApiChart.prototype["SetLegendPos"]                 = ApiChart.prototype.SetLegendPos;
	ApiChart.prototype["SetLegendFontSize"]            = ApiChart.prototype.SetLegendFontSize;
	ApiChart.prototype["SetShowDataLabels"]            = ApiChart.prototype.SetShowDataLabels;
	ApiChart.prototype["SetShowPointDataLabel"]        = ApiChart.prototype.SetShowPointDataLabel;
	ApiChart.prototype["SetVertAxisTickLabelPosition"] = ApiChart.prototype.SetVertAxisTickLabelPosition;
	ApiChart.prototype["SetHorAxisTickLabelPosition"]  = ApiChart.prototype.SetHorAxisTickLabelPosition;

	ApiChart.prototype["SetHorAxisMajorTickMark"]  =  ApiChart.prototype.SetHorAxisMajorTickMark;
	ApiChart.prototype["SetHorAxisMinorTickMark"]  =  ApiChart.prototype.SetHorAxisMinorTickMark;
	ApiChart.prototype["SetVertAxisMajorTickMark"]  =  ApiChart.prototype.SetVertAxisMajorTickMark;
	ApiChart.prototype["SetVertAxisMinorTickMark"]  =  ApiChart.prototype.SetVertAxisMinorTickMark;
	ApiChart.prototype["SetMajorVerticalGridlines"]  =  ApiChart.prototype.SetMajorVerticalGridlines;
	ApiChart.prototype["SetMinorVerticalGridlines"]  =  ApiChart.prototype.SetMinorVerticalGridlines;
	ApiChart.prototype["SetMajorHorizontalGridlines"]  =  ApiChart.prototype.SetMajorHorizontalGridlines;
	ApiChart.prototype["SetMinorHorizontalGridlines"]  =  ApiChart.prototype.SetMinorHorizontalGridlines;
	ApiChart.prototype["SetHorAxisLablesFontSize"]  =  ApiChart.prototype.SetHorAxisLablesFontSize;
	ApiChart.prototype["SetVertAxisLablesFontSize"]  =  ApiChart.prototype.SetVertAxisLablesFontSize;

	ApiFill.prototype["GetClassType"]                = ApiFill.prototype.GetClassType;

	ApiStroke.prototype["GetClassType"]              = ApiStroke.prototype.GetClassType;

	ApiGradientStop.prototype["GetClassType"]        = ApiGradientStop.prototype.GetClassType;

	ApiUniColor.prototype["GetClassType"]            = ApiUniColor.prototype.GetClassType;

	ApiRGBColor.prototype["GetClassType"]            = ApiRGBColor.prototype.GetClassType;

	ApiSchemeColor.prototype["GetClassType"]         = ApiSchemeColor.prototype.GetClassType;

	ApiPresetColor.prototype["GetClassType"]         = ApiPresetColor.prototype.GetClassType;

	ApiBullet.prototype["GetClassType"]              = ApiBullet.prototype.GetClassType;

	ApiInlineLvlSdt.prototype["GetClassType"]      = ApiInlineLvlSdt.prototype.GetClassType;
	ApiInlineLvlSdt.prototype["SetLock"]           = ApiInlineLvlSdt.prototype.SetLock;
	ApiInlineLvlSdt.prototype["GetLock"]           = ApiInlineLvlSdt.prototype.GetLock;
	ApiInlineLvlSdt.prototype["SetTag"]            = ApiInlineLvlSdt.prototype.SetTag;
	ApiInlineLvlSdt.prototype["GetTag"]            = ApiInlineLvlSdt.prototype.GetTag;
	ApiInlineLvlSdt.prototype["SetLabel"]          = ApiInlineLvlSdt.prototype.SetLabel;
	ApiInlineLvlSdt.prototype["GetLabel"]          = ApiInlineLvlSdt.prototype.GetLabel;
	ApiInlineLvlSdt.prototype["SetAlias"]          = ApiInlineLvlSdt.prototype.SetAlias;
	ApiInlineLvlSdt.prototype["GetAlias"]          = ApiInlineLvlSdt.prototype.GetAlias;
	ApiInlineLvlSdt.prototype["GetElementsCount"]  = ApiInlineLvlSdt.prototype.GetElementsCount;
	ApiInlineLvlSdt.prototype["GetElement"]        = ApiInlineLvlSdt.prototype.GetElement;
	ApiInlineLvlSdt.prototype["RemoveElement"]     = ApiInlineLvlSdt.prototype.RemoveElement;
	ApiInlineLvlSdt.prototype["RemoveAllElements"] = ApiInlineLvlSdt.prototype.RemoveAllElements;
	ApiInlineLvlSdt.prototype["AddElement"]        = ApiInlineLvlSdt.prototype.AddElement;


	ApiBlockLvlSdt.prototype["GetClassType"] = ApiBlockLvlSdt.prototype.GetClassType;
	ApiBlockLvlSdt.prototype["SetLock"]      = ApiBlockLvlSdt.prototype.SetLock;
	ApiBlockLvlSdt.prototype["GetLock"]      = ApiBlockLvlSdt.prototype.GetLock;
	ApiBlockLvlSdt.prototype["SetTag"]       = ApiBlockLvlSdt.prototype.SetTag;
	ApiBlockLvlSdt.prototype["GetTag"]       = ApiBlockLvlSdt.prototype.GetTag;
	ApiBlockLvlSdt.prototype["SetLabel"]     = ApiBlockLvlSdt.prototype.SetLabel;
	ApiBlockLvlSdt.prototype["GetLabel"]     = ApiBlockLvlSdt.prototype.GetLabel;
	ApiBlockLvlSdt.prototype["SetAlias"]     = ApiBlockLvlSdt.prototype.SetAlias;
	ApiBlockLvlSdt.prototype["GetAlias"]     = ApiBlockLvlSdt.prototype.GetAlias;
	ApiBlockLvlSdt.prototype["GetContent"]   = ApiBlockLvlSdt.prototype.GetContent;

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Private area
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	function private_GetDrawingDocument()
	{
		return editor.WordControl.m_oLogicDocument.DrawingDocument;
	}

	function private_PushElementToParagraph(oPara, oElement)
	{
		// Добавляем не в конец из-за рана с символом конца параграфа TODO: ParaEnd
		oPara.Add_ToContent(oPara.Content.length - 1, oElement);
	}

	function private_IsSupportedParaElement(oElement)
	{
		if (oElement instanceof ApiRun
			|| oElement instanceof ApiInlineLvlSdt)
			return true;

		return false;
	}

	function private_GetSupportedParaElement(oElement)
	{
		if (oElement instanceof ParaRun)
			return new ApiRun(oElement);
		else if (oElement instanceof CInlineLevelSdt)
			return new ApiInlineLvlSdt(oElement);
		else
			return new ApiUnsupported();
	}

	function private_GetLogicDocument()
	{
		return editor.WordControl.m_oLogicDocument;
	}

	function private_Twips2MM(twips)
	{
		return 25.4 / 72.0 / 20 * twips;
	}

	function private_EMU2MM(EMU)
	{
		return EMU / 36000.0;
	}

	function private_GetHps(hps)
	{
		return Math.ceil(hps) / 2.0;
	}

	function private_GetColor(r, g, b, Auto)
	{
		return new AscCommonWord.CDocumentColor(r, g, b, Auto ? Auto : false);
	}

	function private_GetTabStop(nPos, sValue)
	{
		var nType = tab_Left;
		if ("left" === sValue)
			nType = tab_Left;
		else if ("right" === sValue)
			nType = tab_Right;
		else if ("clear" === sValue)
			nType = tab_Clear;
		else if ("center" === sValue)
			nType = tab_Center;

		return new CParaTab(nType, private_Twips2MM(nPos));
	}

	function private_GetParaAlign(sJc)
	{
		if ("left" === sJc)
			return align_Left;
		else if ("right" === sJc)
			return align_Right;
		else if ("both" === sJc)
			return align_Justify;
		else if ("center" === sJc)
			return align_Center;

		return undefined;
	}

	function private_GetTableBorder(sType, nSize, nSpace, r, g, b)
	{
		var oBorder = new CDocumentBorder();

		if ("none" === sType)
		{
			oBorder.Value = border_None;
			oBorder.Size  = 0;
			oBorder.Space = 0;
			oBorder.Color.Set(0, 0, 0, true);
		}
		else
		{
			if ("single" === sType)
				oBorder.Value = border_Single;

			oBorder.Size  = private_Pt_8ToMM(nSize);
			oBorder.Space = private_PtToMM(nSpace);
			oBorder.Color.Set(r, g, b);
		}

		return oBorder;
	}

	function private_GetTableMeasure(sType, nValue)
	{
		var nType = tblwidth_Auto;
		var nW    = 0;
		if ("auto" === sType)
		{
			nType = tblwidth_Auto;
			nW    = 0;
		}
		else if ("nil" === sType)
		{
			nType = tblwidth_Nil;
			nW    = 0;
		}
		else if ("percent" === sType)
		{
			nType = tblwidth_Pct;
			nW    = private_GetInt(nValue, null, null);
		}
		else if ("twips" === sType)
		{
			nType = tblwidth_Mm;
			nW    = private_Twips2MM(nValue);
		}

		return new CTableMeasurement(nType, nW);
	}

	function private_GetShd(sType, r, g, b, isAuto)
	{
		var oShd = new CDocumentShd();

		if ("nil" === sType)
			oShd.Value = Asc.c_oAscShdNil;
		else if ("clear" === sType)
			oShd.Value = Asc.c_oAscShdClear;

		oShd.Color.Set(r, g, b, isAuto);
		return oShd;
	}

	function private_GetBoolean(bValue, bDefValue)
	{
		if (true === bValue)
			return true;
		else if (false === bValue)
			return false;
		else
			return (undefined !== bDefValue ? bDefValue : false);
	}

	function private_GetInt(nValue, nMin, nMax)
	{
		var nResult = nValue | 0;

		if (undefined !== nMin && null !== nMin)
			nResult = Math.max(nMin, nResult);

		if (undefined !== nMax && null !== nMax)
			nResult = Math.min(nMax, nResult);

		return nResult;
	}

	function private_PtToMM(pt)
	{
		return 25.4 / 72.0 * pt;
	}

	function private_Pt_8ToMM(pt)
	{
		return 25.4 / 72.0 / 8 * pt;
	}

	function private_StartSilentMode()
	{
		private_GetLogicDocument().Start_SilentMode();
	}
	function private_EndSilentMode()
	{
		private_GetLogicDocument().End_SilentMode(false);
	}
	function private_GetAlignH(sAlign)
	{
		if ("left" === sAlign)
			return c_oAscAlignH.Left;
		else if ("right" === sAlign)
			return c_oAscAlignH.Right;
		else if ("center" === sAlign)
			return c_oAscAlignH.Center;

		return c_oAscAlignH.Left;
	}

	function private_GetAlignV(sAlign)
	{
		if ("top" === sAlign)
			return c_oAscAlignV.Top;
		else if ("bottom" === sAlign)
			return c_oAscAlignV.Bottom;
		else if ("center" === sAlign)
			return c_oAscAlignV.Center;

		return c_oAscAlignV.Center;
	}
	function private_GetRelativeFromH(sRel)
	{
		if ("character" === sRel)
			return Asc.c_oAscRelativeFromH.Character;
		else if ("column" === sRel)
			return Asc.c_oAscRelativeFromH.Column;
		else if ("leftMargin" === sRel)
			return Asc.c_oAscRelativeFromH.LeftMargin;
		else if ("rightMargin" === sRel)
			return Asc.c_oAscRelativeFromH.RightMargin;
		else if ("margin" === sRel)
			return Asc.c_oAscRelativeFromH.Margin;
		else if ("page" === sRel)
			return Asc.c_oAscRelativeFromH.Page;

		return Asc.c_oAscRelativeFromH.Page;
	}

	function private_GetRelativeFromV(sRel)
	{
		if ("bottomMargin" === sRel)
			return Asc.c_oAscRelativeFromV.BottomMargin;
		else if ("topMargin" === sRel)
			return Asc.c_oAscRelativeFromV.TopMargin;
		else if ("margin" === sRel)
			return Asc.c_oAscRelativeFromV.Margin;
		else if ("page" === sRel)
			return Asc.c_oAscRelativeFromV.Page;
		else if ("line" === sRel)
			return Asc.c_oAscRelativeFromV.Line;
		else if ("paragraph" === sRel)
			return Asc.c_oAscRelativeFromV.Paragraph;

		return Asc.c_oAscRelativeFromV.Page;
	}

	function private_CreateWatermark(sText, bDiagonal){
		var sText2 = ((typeof (sText) === "string") && (sText.length > 0)) ? sText : "WATERMARK";
		var sFontName2 = undefined;
		var nFontSize2 = 2;
		var oTextFill2 = AscFormat.CreateUnfilFromRGB(127, 127, 127);
		oTextFill2.transparent = 127;

		var MainLogicDocument = (editor && editor.WordControl && editor.WordControl.m_oLogicDocument ? editor && editor.WordControl && editor.WordControl.m_oLogicDocument : null);
		var TrackRevisions = (MainLogicDocument ? MainLogicDocument.Is_TrackRevisions() : false);

		if (MainLogicDocument && true === TrackRevisions)
			MainLogicDocument.Set_TrackRevisions(false);

		var oShape = new AscFormat.CShape();
		oShape.setWordShape(true);
		oShape.setBDeleted(false);
		oShape.createTextBoxContent();
		var oSpPr = new AscFormat.CSpPr();
		var oXfrm = new AscFormat.CXfrm();
		oXfrm.setOffX(0);
		oXfrm.setOffY(0);


		var fHeight = 45;
		var fWidth;
		if(bDiagonal !== false){
			fWidth = 175;
			oXfrm.setRot(7*Math.PI/4);
		}
		else{
			fWidth = 165;
		}

		oXfrm.setExtX(fWidth);
		oXfrm.setExtY(fHeight);
		oSpPr.setXfrm(oXfrm);
		oXfrm.setParent(oSpPr);
		oSpPr.setFill(AscFormat.CreateNoFillUniFill());
		oSpPr.setLn(AscFormat.CreateNoFillLine());
		oSpPr.setGeometry(AscFormat.CreateGeometry("rect"));
		oShape.setSpPr(oSpPr);
		oSpPr.setParent(oShape);
		var oContent = oShape.getDocContent();
		AscFormat.AddToContentFromString(oContent, sText2);
		var oTextPr = new CTextPr();
		oTextPr.FontSize = nFontSize2;
		oTextPr.RFonts.Ascii = sFontName2;
		oTextPr.TextFill = oTextFill2;
		oContent.Set_ApplyToAll(true);
		oContent.AddToParagraph(new ParaTextPr(oTextPr));
		oContent.SetParagraphAlign(AscCommon.align_Center);
		oContent.Set_ApplyToAll(false);
		var oBodyPr = oShape.getBodyPr().createDuplicate();
		oBodyPr.rot = 0;
		oBodyPr.spcFirstLastPara = false;
		oBodyPr.vertOverflow = AscFormat.nOTOwerflow;
		oBodyPr.horzOverflow = AscFormat.nOTOwerflow;
		oBodyPr.vert = AscFormat.nVertTThorz;
		oBodyPr.lIns = 2.54;
		oBodyPr.tIns = 1.27;
		oBodyPr.rIns = 2.54;
		oBodyPr.bIns = 1.27;
		oBodyPr.numCol = 1;
		oBodyPr.spcCol = 0;
		oBodyPr.rtlCol = 0;
		oBodyPr.fromWordArt = false;
		oBodyPr.anchor = 4;
		oBodyPr.anchorCtr = false;
		oBodyPr.forceAA = false;
		oBodyPr.compatLnSpc = true;
		oBodyPr.prstTxWarp = AscFormat.ExecuteNoHistory(function(){return AscFormat.CreatePrstTxWarpGeometry("textPlain");}, this, []);
		oShape.setBodyPr(oBodyPr);

		var oLogicDocument = private_GetLogicDocument();
		var oDrawingDocuemnt = private_GetDrawingDocument();
		var oDrawing = new ParaDrawing(fWidth, fHeight, null, oDrawingDocuemnt, oLogicDocument, null);
		oShape.setParent(oDrawing);
		oDrawing.Set_GraphicObject(oShape);
		var oApiShape = new ApiShape(oShape);
		oApiShape.SetWrappingStyle("inFront");
		oApiShape.SetHorAlign("margin", "center");
		oApiShape.SetVerAlign("margin", "center");
		return oApiShape;
	}


	function privateInsertWatermarkToContent(oApi, oContent, sText, bIsDiagonal){
		if(oContent){
			var nElementsCount = oContent.GetElementsCount();
			for(var i = 0; i < nElementsCount; ++i){
				var oElement = oContent.GetElement(i);
				if(oElement.GetClassType() === "paragraph"){
					oElement.AddDrawing(private_CreateWatermark(sText, bIsDiagonal));
					break;
				}
			}
			if(i === nElementsCount){
				oElement = oApi.CreateParagraph();
				oElement.AddDrawing(private_CreateWatermark(sText, bIsDiagonal));
				oContent.Push(oElement);
			}
		}
	}

	ApiDocument.prototype.OnChangeParaPr = function(oApiParaPr)
	{
		var oStyles = this.Document.Get_Styles();
		oStyles.Set_DefaultParaPr(oApiParaPr.ParaPr);
		oApiParaPr.ParaPr = oStyles.Get_DefaultParaPr().Copy();
	};
	ApiDocument.prototype.OnChangeTextPr = function(oApiTextPr)
	{
		var oStyles = this.Document.Get_Styles();
		oStyles.Set_DefaultTextPr(oApiTextPr.TextPr);
		oApiTextPr.TextPr = oStyles.Get_DefaultTextPr().Copy();
	};
	ApiParagraph.prototype.private_GetImpl = function()
	{
		return this.Paragraph;
	};
	ApiParagraph.prototype.OnChangeParaPr = function(oApiParaPr)
	{
		this.Paragraph.Set_Pr(oApiParaPr.ParaPr);
		oApiParaPr.ParaPr = this.Paragraph.Pr.Copy();
	};
	ApiParagraph.prototype.OnChangeTextPr = function(oApiTextPr)
	{
		this.Paragraph.TextPr.Set_Value(oApiTextPr.TextPr);
		oApiTextPr.TextPr = this.Paragraph.TextPr.Value.Copy();
	};
	ApiRun.prototype.private_GetImpl = function()
	{
		return this.Run;
	};
	ApiRun.prototype.OnChangeTextPr = function(oApiTextPr)
	{
		this.Run.Set_Pr(oApiTextPr.TextPr);
		oApiTextPr.TextPr = this.Run.Pr.Copy();
	};
	ApiTable.prototype.private_GetImpl = function()
	{
		return this.Table;
	};
	ApiTable.prototype.OnChangeTablePr = function(oApiTablePr)
	{
		this.Table.Set_Pr(oApiTablePr.TablePr);
		oApiTablePr.TablePr = this.Table.Pr.Copy();
	};
	ApiTable.prototype.private_PrepareTableForActions = function()
	{
		this.Table.private_RecalculateGrid();
		this.Table.private_UpdateCellsGrid();
	};
	ApiStyle.prototype.OnChangeTextPr = function(oApiTextPr)
	{
		this.Style.Set_TextPr(oApiTextPr.TextPr);
		oApiTextPr.TextPr = this.Style.TextPr.Copy();
	};
	ApiStyle.prototype.OnChangeParaPr = function(oApiParaPr)
	{
		this.Style.Set_ParaPr(oApiParaPr.ParaPr);
		oApiParaPr.ParaPr = this.Style.ParaPr.Copy();
	};
	ApiStyle.prototype.OnChangeTablePr = function(oApiTablePr)
	{
		this.Style.Set_TablePr(oApiTablePr.TablePr);
		oApiTablePr.TablePr = this.Style.TablePr.Copy();
	};
	ApiStyle.prototype.OnChangeTableRowPr = function(oApiTableRowPr)
	{
		this.Style.Set_TableRowPr(oApiTableRowPr.RowPr);
		oApiTableRowPr.RowPr = this.Style.TableRowPr.Copy();
	};
	ApiStyle.prototype.OnChangeTableCellPr = function(oApiTableCellPr)
	{
		this.Style.Set_TableCellPr(oApiTableCellPr.CellPr);
		oApiTableCellPr.CellPr = this.Style.TableCellPr.Copy();
	};
	ApiStyle.prototype.OnChangeTableStylePr = function(oApiTableStylePr)
	{
		var sType = oApiTableStylePr.GetType();
		switch(sType)
		{
			case "topLeftCell":
			{
				this.Style.Set_TableTLCell(oApiTableStylePr.TableStylePr);
				oApiTableStylePr.TableStylePr = this.Style.TableTLCell.Copy();
				break;
			}
			case "topRightCell":
			{
				this.Style.Set_TableTRCell(oApiTableStylePr.TableStylePr);
				oApiTableStylePr.TableStylePr = this.Style.TableTRCell.Copy();
				break;
			}
			case "bottomLeftCell":
			{
				this.Style.Set_TableBLCell(oApiTableStylePr.TableStylePr);
				oApiTableStylePr.TableStylePr = this.Style.TableBLCell.Copy();
				break;
			}
			case "bottomRightCell":
			{
				this.Style.Set_TableBRCell(oApiTableStylePr.TableStylePr);
				oApiTableStylePr.TableStylePr = this.Style.TableBRCell.Copy();
				break;
			}
			case "firstRow":
			{
				this.Style.Set_TableFirstRow(oApiTableStylePr.TableStylePr);
				oApiTableStylePr.TableStylePr = this.Style.TableFirstRow.Copy();
				break;
			}
			case "lastRow":
			{
				this.Style.Set_TableLastRow(oApiTableStylePr.TableStylePr);
				oApiTableStylePr.TableStylePr = this.Style.TableLastRow.Copy();
				break;
			}
			case "firstColumn":
			{
				this.Style.Set_TableFirstCol(oApiTableStylePr.TableStylePr);
				oApiTableStylePr.TableStylePr = this.Style.TableFirstCol.Copy();
				break;
			}
			case "lastColumn":
			{
				this.Style.Set_TableLastCol(oApiTableStylePr.TableStylePr);
				oApiTableStylePr.TableStylePr = this.Style.TableLastCol.Copy();
				break;
			}
			case "bandedColumn":
			{
				this.Style.Set_TableBand1Vert(oApiTableStylePr.TableStylePr);
				oApiTableStylePr.TableStylePr = this.Style.TableBand1Vert.Copy();
				break;
			}
			case "bandedColumnEven":
			{
				this.Style.Set_TableBand2Vert(oApiTableStylePr.TableStylePr);
				oApiTableStylePr.TableStylePr = this.Style.TableBand2Vert.Copy();
				break;
			}
			case "bandedRow":
			{
				this.Style.Set_TableBand1Horz(oApiTableStylePr.TableStylePr);
				oApiTableStylePr.TableStylePr = this.Style.TableBand1Horz.Copy();
				break;
			}
			case "bandedRowEven":
			{
				this.Style.Set_TableBand2Horz(oApiTableStylePr.TableStylePr);
				oApiTableStylePr.TableStylePr = this.Style.TableBand2Horz.Copy();
				break;
			}
			case "wholeTable":
			{
				this.Style.Set_TableWholeTable(oApiTableStylePr.TableStylePr);
				oApiTableStylePr.TableStylePr = this.Style.TableWholeTable.Copy();
				break;
			}
		}
	};
	ApiNumberingLevel.prototype.OnChangeTextPr = function(oApiTextPr)
	{
		this.Num.SetTextPr(this.Lvl, oApiTextPr.TextPr);
		oApiTextPr.TextPr = this.Num.GetLvl(this.Lvl).GetTextPr().Copy();
	};
	ApiNumberingLevel.prototype.OnChangeParaPr = function(oApiParaPr)
	{
		this.Num.SetParaPr(this.Lvl, oApiParaPr.ParaPr);
		oApiParaPr.ParaPr = this.Num.GetLvl(this.Lvl).GetParaPr().Copy();
	};
	ApiTableRow.prototype.OnChangeTableRowPr = function(oApiTableRowPr)
	{
		this.Row.Set_Pr(oApiTableRowPr.RowPr);
		oApiTableRowPr.RowPr = this.Row.Pr.Copy();
	};
	ApiTableCell.prototype.OnChangeTableCellPr = function(oApiTableCellPr)
	{
		this.Cell.Set_Pr(oApiTableCellPr.CellPr);
		oApiTableCellPr.CellPr = this.Cell.Pr.Copy();
	};
	ApiTextPr.prototype.private_OnChange = function()
	{
		this.Parent.OnChangeTextPr(this);
	};
	ApiParaPr.prototype.private_OnChange = function()
	{
		this.Parent.OnChangeParaPr(this);
	};
	ApiTablePr.prototype.private_OnChange = function()
	{
		this.Parent.OnChangeTablePr(this);
	};
	ApiTableRowPr.prototype.private_OnChange = function()
	{
		this.Parent.OnChangeTableRowPr(this);
	};
	ApiTableCellPr.prototype.private_OnChange = function()
	{
		this.Parent.OnChangeTableCellPr(this);
	};
	ApiTableStylePr.prototype.private_OnChange = function()
	{
		this.Parent.OnChangeTableStylePr(this);
	};
	ApiTableStylePr.prototype.OnChangeTextPr = function()
	{
		this.private_OnChange();
	};
	ApiTableStylePr.prototype.OnChangeParaPr = function()
	{
		this.private_OnChange();
	};
	ApiTableStylePr.prototype.OnChangeTablePr = function()
	{
		this.private_OnChange();
	};
	ApiTableStylePr.prototype.OnChangeTableRowPr = function()
	{
		this.private_OnChange();
	};
	ApiTableStylePr.prototype.OnChangeTableCellPr = function()
	{
		this.private_OnChange();
	};
	ApiInlineLvlSdt.prototype.private_GetImpl = function()
	{
		return this.Sdt;
	};
	ApiBlockLvlSdt.prototype.private_GetImpl = function()
	{
		return this.Sdt;
	};

	Api.prototype.private_CreateApiParagraph = function(oParagraph){
		return new ApiParagraph(oParagraph);
	};

	Api.prototype.private_CreateApiDocContent = function(oDocContent){
		return new ApiDocumentContent(oDocContent);
	};
}(window, null));
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined)
{
	///
	// api редактора должен иметь методы
	// 1) asc_IsFocus(true /* bIsNaturalFocus */) - это принимаем ли мы сейчас клавиатуру.
	// bIsNaturalFocus - это параметр, говорящий о том, что нам нужен фокус наш, исключая поля для ввода (иероглифы например)
	// 2) asc_CheckCopy(_clipboard /* CClipboardData */, _formats) - для наполнения буфера обмена.
	// В нем вызывать _clipboard.pushData(_format, _data); _formats - какие форматы нужны
	// 3) asc_PasteData(_format, ...)
	// 4) incrementCounterLongAction / decrementCounterLongAction - для залочивания вставки
	// 5) asc_SelectionCut();
	///

	// Для инициализации вызвать g_clipboardBase.Init(api); в любой момент времени

	// Import
	var AscBrowser = AscCommon.AscBrowser;

	var c_oAscClipboardDataFormat       = {
		Text        : 1,
		Html        : 2,
		Internal    : 4,
		HtmlElement : 8
	};
	AscCommon.c_oAscClipboardDataFormat = c_oAscClipboardDataFormat;

	function CClipboardBase()
	{
		this.PasteFlag = false;
		this.CopyFlag  = false;

		this.Api = null;

		this.IsNeedDivOnCopy  = AscBrowser.isIE;
		this.IsNeedDivOnPaste = AscBrowser.isIE/* || AscBrowser.isMozilla*/;

		this.IsCopyCutOnlyInEditable = AscBrowser.isIE || AscBrowser.isMozilla;
		this.IsPasteOnlyInEditable   = AscBrowser.isIE || AscBrowser.isMozilla || AscBrowser.isSafari;

		this.CommonDivClassName = "sdk-element";

		this.CommonDivIdParent = "";

		this.CommonDivId = "asc_pasteBin";
		this.CommonDiv   = null;

		this.CommonIframeId = "asc_pasteFrame";
		this.CommonIframe   = null;

		this.ClosureParams = {};

		this.CopyPasteFocus = false;
		this.CopyPasteFocusTimer = -1;

		this.inputContext = null;
		this.LastCopyBinary = null; // для вставки по кнопке, когда браузер не позволяет

		// images counter
		this.PasteImagesCount = 0;
		this.PasteImagesCounter = 0;
		this.PasteImagesBody = "";

		this.DivOnCopyHtmlPresent = false;
		this.DivOnCopyText = "";

		this.bSaveFormat = false; //для вставки, допустим, из плагина необходимо чтобы при добавлении текста в шейп сохранялось форматирование
	}

	CClipboardBase.prototype =
	{
		_console_log : function(_obj)
		{
			//console.log(_obj);
		},

		_private_oncopy : function(e)
		{
			this._console_log("oncopy");

			if (!this.Api.asc_IsFocus(true))
				return;

			this.ClosureParams._e = e;
			if (this.IsNeedDivOnCopy)
			{
				this.CommonDiv_Copy();
			}
			else
			{
				this.LastCopyBinary = null;
				this.Api.asc_CheckCopy(this, AscCommon.c_oAscClipboardDataFormat.Text | AscCommon.c_oAscClipboardDataFormat.Html | AscCommon.c_oAscClipboardDataFormat.Internal);

				setTimeout(function(){
					//вызываю CommonDiv_End, поскольку на _private_onbeforecopy всегда делается CommonDiv_Start
					//TODO перепроверить!
					g_clipboardBase.CommonDiv_End();
				}, 0);

				e.preventDefault();
				return false;
			}
		},

		_private_oncut : function(e)
		{
			this._console_log("oncut");

			if (!this.Api.asc_IsFocus(true))
				return;

			this.ClosureParams._e = e;
			if (this.IsNeedDivOnCopy)
			{
				this.CommonDiv_Copy();
			}
			else
			{
				this.LastCopyBinary = null;
				this.Api.asc_CheckCopy(this, AscCommon.c_oAscClipboardDataFormat.Text | AscCommon.c_oAscClipboardDataFormat.Html | AscCommon.c_oAscClipboardDataFormat.Internal);
			}

			this.Api.asc_SelectionCut();

			if (!this.IsNeedDivOnCopy)
			{
				setTimeout(function(){
					//вызываю CommonDiv_End, поскольку на _private_onbeforecopy всегда делается CommonDiv_Start
					//TODO перепроверить!
					g_clipboardBase.CommonDiv_End();
				}, 0);

				e.preventDefault();
				return false;
			}
		},

		_private_onpaste : function(e)
		{
			this._console_log("onpaste");

			if (!this.Api.asc_IsFocus(true))
				return;

			if (!this.IsNeedDivOnPaste)
				e.preventDefault();

			this.ClosureParams._e = e;
			if (this.Api.isLongAction())
				return false;

			this.PasteFlag = true;
			this.Api.incrementCounterLongAction();

			if (this.IsNeedDivOnPaste)
			{
				window.setTimeout(function()
				{

					g_clipboardBase.Api.asc_PasteData(AscCommon.c_oAscClipboardDataFormat.HtmlElement, g_clipboardBase.CommonDiv);
					g_clipboardBase.CommonDiv_End();
					g_clipboardBase.Paste_End();

				}, 0);
				return;
			}
			else
			{
				var _clipboard = (e && e.clipboardData) ? e.clipboardData : window.clipboardData;
				if (!_clipboard || !_clipboard.getData)
					return false;

				var _text_format = this.ClosureParams.getData("text/plain");
				var _internal = this.ClosureParams.getData("text/x-custom");
				if (_internal && _internal != "" && _internal.indexOf("asc_internalData2;") == 0)
				{
					this.Api.asc_PasteData(AscCommon.c_oAscClipboardDataFormat.Internal, _internal.substr("asc_internalData2;".length), null, _text_format);
					g_clipboardBase.Paste_End();
					return false;
				}

				var _html_format = this.ClosureParams.getData("text/html");
				if (_html_format && _html_format != "")
				{
					var nIndex = _html_format.indexOf("</html>");
					if (-1 != nIndex)
						_html_format = _html_format.substring(0, nIndex + "</html>".length);

					this.CommonIframe_PasteStart(_html_format, _text_format);
					return false;
				}

				if (_text_format && _text_format != "")
				{
					this.Api.asc_PasteData(AscCommon.c_oAscClipboardDataFormat.Text, _text_format);
					g_clipboardBase.Paste_End();
					return false;
				}

				var items = _clipboard.items;
                if (null != items && 0 != items.length)
                {
                    g_clipboardBase.PasteImagesBody = "";
                    g_clipboardBase.PasteImagesCount = items.length;
                    g_clipboardBase.PasteImagesCounter = 0;
                    for (var i = 0; i < items.length; ++i)
                    {
                        if (items[i].kind == 'file' && items[i].type.indexOf('image/') !== -1)
                        {
                            var blob = items[i].getAsFile();
                            var reader = new FileReader();

                            reader.onload = function(e) {
                                g_clipboardBase.PasteImagesCounter++;
                                g_clipboardBase.PasteImagesBody += ("<img src=\"" + e.target.result + "\"/>");

                                if (g_clipboardBase.PasteImagesCounter == g_clipboardBase.PasteImagesCount)
                                {
                                    g_clipboardBase.CommonIframe_PasteStart("<html><body>" + g_clipboardBase.PasteImagesBody + "</body></html>");

                                    g_clipboardBase.PasteImagesBody = "";
                                    g_clipboardBase.PasteImagesCounter = 0;
                                    g_clipboardBase.PasteImagesCount = 0;
                                }
                            };

                            reader.onabort = reader.onerror = function(e) {
                                g_clipboardBase.PasteImagesCounter++;

                                if (g_clipboardBase.PasteImagesCounter == g_clipboardBase.PasteImagesCount)
                                {
                                    g_clipboardBase.CommonIframe_PasteStart("<html><body>" + g_clipboardBase.PasteImagesBody + "</body></html>");

                                    g_clipboardBase.PasteImagesBody = "";
                                    g_clipboardBase.PasteImagesCounter = 0;
                                    g_clipboardBase.PasteImagesCount = 0;
                                }
                            };

                            try
							{
                                reader.readAsDataURL(blob);
                            }
                            catch(err)
							{
                                g_clipboardBase.PasteImagesCounter++;
							}
                        }
                        else
                        {
                            g_clipboardBase.PasteImagesCounter++;
                        }
                    }

                    if (g_clipboardBase.PasteImagesCounter == g_clipboardBase.PasteImagesCount)
                        g_clipboardBase.Paste_End();

                    return false;
                }
			}

            g_clipboardBase.Paste_End();
			return false;
		},

		_private_onbeforepaste : function(e, isAttackEmulate)
		{
			this._console_log("onbeforepaste");
			
			//TODO условие добавил, чтобы не терялся фокус со строки формул при copy/paste. проверить!
			if (!this.Api.asc_IsFocus(true))
				return;
			
			//if (isAttackEmulate === true)
			{
				this.CommonDiv = this.CommonDiv_Check();
				this.CommonDiv_Start();

				this.CommonDiv.focus();
				this.StartFocus();
				this.CommonDiv_Select();
				return;
			}

			return false;
		},

		_private_onbeforecopy_select : function()
		{
			if (AscBrowser.isIE)
			{
				this._console_log("onbeforecopy_select");

				this.CommonDiv = this.CommonDiv_Check();
				this.CommonDiv_Start();
				this.CommonDiv.innerHTML = "<span> </span>";

				this.CommonDiv.focus();
				this.StartFocus();
				this.CommonDiv_Select();
			}
		},

		_private_onbeforecopy : function(e, isAttackEmulate)
		{
			this._console_log("onbeforecopy");
			
			//TODO условие добавил, чтобы не терялся фокус со строки формул при copy/paste. проверить!
			if (!this.Api.asc_IsFocus(true))
				return;
			
			//if (isAttackEmulate === true)
			{
				this.CommonDiv = this.CommonDiv_Check();
				this.CommonDiv_Start();
				this.CommonDiv.innerHTML = "<span> </span>";

				this.CommonDiv.focus();
				this.StartFocus();
				this.CommonDiv_Select();
			}

			return false;
		},

		Init : function(_api)
		{
			this.Api = _api;

			window['AscCommon'].g_specialPasteHelper.Init(_api);

			this.ClosureParams.getData = function(type)
			{
				var _clipboard = (this._e && this._e.clipboardData) ? this._e.clipboardData : window.clipboardData;
				if (!_clipboard || !_clipboard.getData)
					return null;

				var _type = type;
				if (AscBrowser.isIE && (type == 'text' || type == 'text/plain'))
					_type = "Text";

				try
				{
					return _clipboard.getData(_type);
				}
				catch (e)
				{
				}
				return null;
			};

			this.ClosureParams.setData = function(type, _data)
			{
				var _clipboard = (this._e && this._e.clipboardData) ? this._e.clipboardData : window.clipboardData;
				if (!_clipboard || !_clipboard.setData)
					return null;

				var _type = type;
				if (AscBrowser.isIE && (type == 'text' || type == 'text/plain'))
					_type = "Text";

				try
				{
					_clipboard.setData(_type, _data);
				}
				catch (e)
				{
				}
			};

			if (!AscBrowser.isIE)
			{
				document.oncopy           = function(e)
				{
					return g_clipboardBase._private_oncopy(e)
				};
				document.oncut            = function(e)
				{
					return g_clipboardBase._private_oncut(e)
				};
				document.onpaste          = function(e)
				{
					return g_clipboardBase._private_onpaste(e);
				};
				document["onbeforecopy"]  = function(e)
				{
					return g_clipboardBase._private_onbeforecopy(e);
				};
				document["onbeforecut"]   = function(e)
				{
					return g_clipboardBase._private_onbeforecopy(e);
				};
				document["onbeforepaste"] = function(e)
				{
					return g_clipboardBase._private_onbeforepaste(e);
				};
			}
			else
			{
				document.addEventListener("copy", function(e)
				{
					return g_clipboardBase._private_oncopy(e);
				});
				document.addEventListener("cut", function(e)
				{
					return g_clipboardBase._private_oncut(e);
				});
				document.addEventListener("paste", function(e)
				{
					return g_clipboardBase._private_onpaste(e);
				});
				document.addEventListener("beforepaste", function(e)
				{
					return g_clipboardBase._private_onbeforepaste(e);
				});
				document.addEventListener("beforecopy", function(e)
				{
					return g_clipboardBase._private_onbeforecopy(e);
				});
				document.addEventListener("beforecut", function(e)
				{
					return g_clipboardBase._private_onbeforecopy(e);
				});
			}

			if (this.IsCopyCutOnlyInEditable || this.IsPasteOnlyInEditable)
			{
				document.onkeydown = function(e)
				{
					if (!g_clipboardBase.Api.asc_IsFocus(true) || g_clipboardBase.Api.isLongAction())
						return;

					var isAltGr = AscCommon.getAltGr(e);
					if (isAltGr)
						return;

					var isCtrl  = (e.ctrlKey === true || e.metaKey === true);
					var isShift = e.shiftKey;
					var keyCode = e.keyCode;

					if (g_clipboardBase.IsCopyCutOnlyInEditable)
					{
						var bIsBeforeCopyCutEmulate = false;
						var _cut                    = false;
						if (isCtrl && !isShift && (keyCode == 67 || keyCode == 88)) // copy
							bIsBeforeCopyCutEmulate = true;
						if (!isCtrl && isShift && keyCode == 45) // cut
						{
							bIsBeforeCopyCutEmulate = true;
							_cut                    = true;
						}

						if (bIsBeforeCopyCutEmulate)
						{
							//g_clipboardBase._private_onbeforecopy_select();

							g_clipboardBase._console_log("emulate_beforecopycut");
							var isEmulate = false;
							try
							{
								isEmulate = _cut ? document.execCommand("beforecut") : document.execCommand("beforecopy");
							}
							catch (err)
							{
							}

							g_clipboardBase._private_onbeforecopy(undefined, !isEmulate);
						}
					}

					if (g_clipboardBase.IsPasteOnlyInEditable)
					{
						var bIsBeforePasteEmulate = false;
						if (isCtrl && !isShift && keyCode == 86)
							bIsBeforePasteEmulate = true;
						if (!isCtrl && isShift && keyCode == 45)
							bIsBeforePasteEmulate = true;

						if (bIsBeforePasteEmulate)
						{
							g_clipboardBase._console_log("emulate_beforepaste");
							var isEmulate = false;
							try
							{
								isEmulate = document.execCommand("beforepaste");
							}
							catch (err)
							{
							}

							g_clipboardBase._private_onbeforepaste(undefined, !isEmulate);
						}
					}
				};
			}

			if (AscBrowser.isSafari && false)
			{
				this.CommonDiv = this.CommonDiv_Check();

				setInterval(function()
				{
					if (g_clipboardBase.Api.asc_IsFocus(true))
						g_clipboardBase.CommonDiv.focus();

				}, 100);
			}
		},

		IsWorking : function()
		{
			return (this.CopyFlag || this.PasteFlag) ? true : false;
		},

		StartFocus : function()
		{
			// не плодим таймеры
			this.EndFocus(false);

			this.CopyPasteFocus = true;

			// этот метод используется на beforeCopy/Cut/Paste
			// нужно не отдать фокус текстовому полю (до настоящих Copy/Cut/Paste)
			// время ставим с запасом, так как обрубим на конец Copy/Cut/Paste
			this.CopyPasteFocusTimer = setTimeout(function(){
				g_clipboardBase.EndFocus();
			}, 1000);

		},

		EndFocus : function(isFocusToEditor)
		{
			this.CopyPasteFocus = false;
			if (-1 != this.CopyPasteFocusTimer)
			{
				clearTimeout(this.CopyPasteFocusTimer);
				this.CopyPasteFocusTimer = -1;


				if (false !== isFocusToEditor && null != this.inputContext)
				{
					if (this.inputContext.HtmlArea)
						this.inputContext.HtmlArea.focus();
				}
			}
		},

		IsFocus : function()
		{
			return this.CopyPasteFocus;
		},

		CommonDiv_Check : function()
		{
			var ElemToSelect = document.getElementById(this.CommonDivId);
			if (!ElemToSelect)
			{
				ElemToSelect                              = document.createElement("div");
				ElemToSelect.id                           = this.CommonDivId;
				ElemToSelect.className                    = this.CommonDivClassName;
				ElemToSelect.style.position               = "fixed";
				ElemToSelect.style.left                   = '0px';
				ElemToSelect.style.top                    = '-100px';
				ElemToSelect.style.width                  = '10000px';
				ElemToSelect.style.height                 = '100px';
				ElemToSelect.style.overflow               = 'hidden';
				ElemToSelect.style.zIndex                 = -1000;
				ElemToSelect.style.MozUserSelect          = "text";
				ElemToSelect.style.fontFamily             = "onlyofficeDefaultFont";//дефолтовый шрифт
				ElemToSelect.style.fontSize               = "11pt";//дефолтовый размер. значения 0 и тп не подходят - изменяются такие параметры, как line-height
				ElemToSelect.style.color                  = "black";
				ElemToSelect.style["-khtml-user-select"]  = "text";
				ElemToSelect.style["-o-user-select"]      = "text";
				ElemToSelect.style["user-select"]         = "text";
				ElemToSelect.style["-webkit-user-select"] = "text";
				ElemToSelect.setAttribute("contentEditable", this.isCopyOutEnabled());

				var _parent = ("" == this.CommonDivIdParent) ? document.body : document.getElementById(this.CommonDivIdParent);
				_parent.appendChild(ElemToSelect);
			}
			else
			{
				ElemToSelect.setAttribute("contentEditable", this.isCopyOutEnabled());
			}
			return ElemToSelect;
		},

		CommonDiv_Select : function()
		{
			var ElemToSelect = this.CommonDiv;
			if (window.getSelection) // all browsers, except IE before version 9
			{
				var selection     = window.getSelection();
				var rangeToSelect = document.createRange();

				var is_gecko = AscBrowser.isGecko;
				if (is_gecko)
				{
					ElemToSelect.appendChild(document.createTextNode('\xa0'));
					ElemToSelect.insertBefore(document.createTextNode('\xa0'), ElemToSelect.firstChild);
					rangeToSelect.setStartAfter(ElemToSelect.firstChild);
					rangeToSelect.setEndBefore(ElemToSelect.lastChild);
				}
				else
				{
					var aChildNodes = ElemToSelect.childNodes;
					if (aChildNodes.length == 1)
					{
						var elem = aChildNodes[0];
						var wrap = document.createElement("b");
						wrap.setAttribute("style", "font-weight:normal; background-color: transparent; color: transparent;");
						elem = ElemToSelect.removeChild(elem);
						wrap.appendChild(elem);
						ElemToSelect.appendChild(wrap);
					}
					rangeToSelect.selectNodeContents(ElemToSelect);
				}

				selection.removeAllRanges();
				selection.addRange(rangeToSelect);
			}
			else
			{
				if (document.body.createTextRange) // Internet Explorer
				{
					var rangeToSelect = document.body.createTextRange();
					rangeToSelect.moveToElementText(ElemToSelect);
					rangeToSelect.select();
				}
			}
		},

		CommonDiv_Start : function()
		{
			this.ClosureParams.overflowBody = document.body.style.overflow;
			document.body.style.overflow    = 'hidden';

			this.ClosureParams.backgroundcolorBody  = document.body.style["background-color"];
			document.body.style["background-color"] = "transparent";

			var ElemToSelect           = this.CommonDiv;
			ElemToSelect.style.display = "block";

			while (ElemToSelect.hasChildNodes())
				ElemToSelect.removeChild(ElemToSelect.lastChild);

			document.body.style.MozUserSelect = "text";
			delete document.body.style["-khtml-user-select"];
			delete document.body.style["-o-user-select"];
			delete document.body.style["user-select"];
			document.body.style["-webkit-user-select"] = "text";

			ElemToSelect.style.MozUserSelect = "all";
		},

		CommonDiv_End : function()
		{
			var ElemToSelect = this.CommonDiv;

			ElemToSelect.style.display                 = AscBrowser.isSafari ? "block" : "none";
			document.body.style.MozUserSelect          = "none";
			document.body.style["-khtml-user-select"]  = "none";
			document.body.style["-o-user-select"]      = "none";
			document.body.style["user-select"]         = "none";
			document.body.style["-webkit-user-select"] = "none";

			document.body.style["background-color"] = this.ClosureParams.backgroundcolorBody;

			ElemToSelect.style.MozUserSelect = "none";
			document.body.style.overflow     = this.ClosureParams.overflowBody;

			this.CopyFlag = false;
			this.EndFocus();
		},

		CommonDiv_Copy : function()
		{
			this.CopyFlag  = true;
			this.CommonDiv = this.CommonDiv_Check();

			this.CommonDiv_Start();

			this.ClosureParams.isDivCopy = true;
			this.DivOnCopyHtmlPresent = false;
			this.DivOnCopyText = "";
			this.LastCopyBinary = null;
			this.Api.asc_CheckCopy(this, AscCommon.c_oAscClipboardDataFormat.Text | AscCommon.c_oAscClipboardDataFormat.Html | AscCommon.c_oAscClipboardDataFormat.Internal);
			this.ClosureParams.isDivCopy = false;

			if (!this.DivOnCopyHtmlPresent && this.DivOnCopyText != "")
			{
				this.CommonDiv.innerHTML = this.DivOnCopyText;
			}

			this.DivOnCopyHtmlPresent = false;
			this.DivOnCopyText = "";

			this.CommonDiv_Select();

			window.setTimeout(function()
			{

				g_clipboardBase.CommonDiv_End();

			}, 0);
		},

		CommonDiv_Execute_CopyCut : function()
		{
			if (this.IsCopyCutOnlyInEditable)
			{
				this._private_onbeforecopy(undefined, true);
			}
		},

		CommonIframe_PasteStart : function(_html_data, text_data)
		{
			var ifr = document.getElementById(this.CommonIframeId);
			if (!ifr)
			{
				ifr                = document.createElement("iframe");
				ifr.name           = this.CommonIframeId;
				ifr.id             = this.CommonIframeId;
				ifr.style.position = 'absolute';
				ifr.style.top      = '-100px';
				ifr.style.left     = '0px';
				ifr.style.width    = '10000px';
				ifr.style.height   = '100px';
				ifr.style.overflow = 'hidden';
				ifr.style.zIndex   = -1000;
				ifr.setAttribute("sandbox", "allow-same-origin");
				document.body.appendChild(ifr);

				this.CommonIframe = ifr;
			}
			else
				ifr.style.width = '10000px';

			var frameWindow = window.frames[this.CommonIframeId];
			if (frameWindow)
			{
				frameWindow.document.open();
				frameWindow.document.write(_html_data);
				frameWindow.document.close();
				if (null != frameWindow.document && null != frameWindow.document.body)
				{
					ifr.style.display = "block";

					this.Api.asc_PasteData(AscCommon.c_oAscClipboardDataFormat.HtmlElement, frameWindow.document.body, ifr, text_data);
				}
			}

			ifr.style.width = '100px';

			g_clipboardBase.Paste_End();
		},

		CommonIframe_PasteEnd : function()
		{
			if (this.CommonIframe && this.CommonIframe.style.display != "none")
			{
				this.CommonIframe.blur();
				this.CommonIframe.style.display = "none";
			}
		},

		Paste_End : function()
		{
			this.CommonIframe_PasteEnd();
			this.Api.decrementCounterLongAction();
			this.PasteFlag = false;
			this.EndFocus();
		},

		pushData : function(_format, _data)
		{
			if (null == this.LastCopyBinary)
				this.LastCopyBinary = [];
			this.LastCopyBinary.push({ type: _format, data : _data });

			if (this.ClosureParams.isDivCopy === true)
			{
				if (_format == AscCommon.c_oAscClipboardDataFormat.Html)
				{
					this.CommonDiv.innerHTML = _data;
					this.DivOnCopyHtmlPresent = true;
				}

				if (_format == AscCommon.c_oAscClipboardDataFormat.Text)
					this.DivOnCopyText = _data;

				return;
			}

			var _data_format = "";
			switch (_format)
			{
				case AscCommon.c_oAscClipboardDataFormat.Html:
					_data_format = "text/html";
					break;
				case AscCommon.c_oAscClipboardDataFormat.Text:
					_data_format = "text/plain";
					break;
				case AscCommon.c_oAscClipboardDataFormat.Internal:
					_data_format = "text/x-custom";
					break;
				default:
					break;
			}

			if (_data_format != "" && _data !== null && this.isCopyOutEnabled())
			{
				if (_data_format == "text/x-custom")
					this.ClosureParams.setData(_data_format, "asc_internalData2;" + _data);
				else
					this.ClosureParams.setData(_data_format, _data);
			}
		},

		Button_Copy : function()
		{
			if (this.inputContext)
				this.inputContext.HtmlArea.focus();
			this.Api.asc_enableKeyEvents(true, true);

			this.CommonDiv_Execute_CopyCut();
			var _ret = false;
			try
			{
				_ret = document.execCommand("copy");
			}
			catch (err)
			{
				_ret = false;
			}
			if (!_ret)
			{
				//　копирования не было
				this.LastCopyBinary = null;
				this.Api.asc_CheckCopy(this, AscCommon.c_oAscClipboardDataFormat.Text | AscCommon.c_oAscClipboardDataFormat.Html | AscCommon.c_oAscClipboardDataFormat.Internal);
			}
			return  _ret;
		},

		Button_Cut : function()
		{
			if (this.inputContext)
				this.inputContext.HtmlArea.focus();
			this.Api.asc_enableKeyEvents(true, true);

			this.CommonDiv_Execute_CopyCut();
			var _ret = false;
			try
			{
				_ret = document.execCommand("cut");
			}
			catch (err)
			{
				_ret = false;
			}
			if (!_ret)
			{
				//　копирования не было
				this.LastCopyBinary = null;
				this.Api.asc_CheckCopy(this, AscCommon.c_oAscClipboardDataFormat.Text | AscCommon.c_oAscClipboardDataFormat.Html | AscCommon.c_oAscClipboardDataFormat.Internal);

				this.Api.asc_SelectionCut();
			}
			return _ret;
		},

		Button_Paste : function()
		{
			if (this.inputContext)
				this.inputContext.HtmlArea.focus();
			this.Api.asc_enableKeyEvents(true, true);

			var _ret = false;
			try
			{
				_ret = document.execCommand("paste");
			}
			catch (err)
			{
				_ret = false;
			}

			if (!_ret && null != this.LastCopyBinary)
			{
				var _data = null;
				var _isInternal = false;
				for (var i = 0; i < this.LastCopyBinary.length; i++)
				{
					if (c_oAscClipboardDataFormat.Internal == this.LastCopyBinary[i].type)
					{
						this.Api.asc_PasteData(AscCommon.c_oAscClipboardDataFormat.Internal, this.LastCopyBinary[i].data);
						_isInternal = true;
					}
				}

				if (!_isInternal && this.LastCopyBinary.length > 0)
					this.Api.asc_PasteData(this.LastCopyBinary[0].type, this.LastCopyBinary[0].data);
			}
			return _ret;
		},

		isCopyOutEnabled : function()
		{
			if (this.Api && this.Api.isCopyOutEnabled)
				return this.Api.isCopyOutEnabled();
			return true;
		}
	};

	function CSpecialPasteHelper()
	{
		this.Api = null;

		//special paste
		this.specialPasteData = {};//данные последней вставки перед специальной вставкой

		//параметры специальной вставки из меню.используется класс для EXCEL СSpecialPasteProps. чтобы не протаскивать через все вызываемые функции, добавил это свойство
		this.specialPasteProps = null;

		this.showSpecialPasteButton = false;//нужно показывать или нет кнопку специальной вставки
		this.buttonInfo = new Asc.SpecialPasteShowOptions();//параметры кнопки специальной вставки - позиция. нужно при прокрутке документа, изменения масштаба и тп

		this.specialPasteStart = false;//если true, то в данный момент выполняется специальная вставка
		this.pasteStart = false;//идет процесс вставки, выставится в false только после полного ее окончания(загрузка картинок и шрифтов)

		this.bIsEndTransaction = false;//временный флаг для excel. TODO пересмотреть!

		this.showButtonIdParagraph = null;
		this.endRecalcDocument = false;//для документов, закончен ли пересчет документа. нужно, чтобы грамотно рассчитать позицию иконки с/в
		this.doNotShowButton = false;
	}

	CSpecialPasteHelper.prototype = {
		Init : function(_api) {
			this.Api = _api;
		},

		Special_Paste : function(props)
		{
			this.Api.asc_SpecialPasteData(props);
			return true;
		},
		
		Clean_SpecialPasteObj : function()
		{
			this.specialPasteData = {};
		},
		
		Special_Paste_Start : function()
		{
			this.specialPasteStart = true;
		},
		
		Special_Paste_End : function()
		{
			this.specialPasteStart = false;
		},
		
		Paste_Process_Start : function(doNotShowButton)
		{
			if(doNotShowButton)
			{
				this.Special_Paste_Hide_Button();
			}
			this.pasteStart = true;

			AscFonts.IsCheckSymbols = true;
		},

		Special_Paste_Hide_Button: function()
		{
			this.doNotShowButton = true;
		},

		Paste_Process_End : function()
		{
			AscFonts.IsCheckSymbols             = false;
			//todo возможно стоит добавить проверку
			/*if(!this.pasteStart)
			{
				return;
			}*/
			this.pasteStart = false;
			this.specialPasteProps = null;
			this.bSaveFormat = false;
			//процесс специальной вставки заканчивается вместе с общей вставкой
			if(this.specialPasteStart)
			{
				this.Special_Paste_End();
				//TODO только для презентаций! проверить на остальных редакторах!
				if(!this.buttonInfo.isClean()){
					this.buttonInfo.asc_setOptions(null);
					this.Api.asc_ShowSpecialPasteButton(this.buttonInfo);
				}
			}
			else//если не было специальной вставки, необходимо показать кнопку специальной вставки
			{
				this.SpecialPasteButton_Show();
			}

			this.doNotShowButton = false;

			//TODO для excel заглушка. пересмотреть!
			if(this.bIsEndTransaction)
			{
				this.bIsEndTransaction = false;
				History.EndTransaction();
			}
		},
		
		SpecialPasteButton_Show : function()
		{
			if (!this.Api || this.doNotShowButton)
				return;

			//при быстром совместном редактировании отключаем возможность специальной вставки
			if(this.CheckFastCoEditing())
			{
				return;
			}

			var props = this.buttonInfo;
			if(props && props.options)
			{
				if((window["Asc"] && window["Asc"]["editor"]) || props.cellCoord)
				{
					this.showSpecialPasteButton = true;
					this.Api.asc_ShowSpecialPasteButton(props);
				}
			}
		},


		SpecialPasteButtonById_Show: function()
		{
			if(!this.Api || !this.Api.asc_specialPasteShowButton || this.doNotShowButton)
			{
				if(this.doNotShowButton) {
					this.showButtonIdParagraph = null;
				}
				return;
			}

			if(this.Api.asc_specialPasteShowButton())
			{
				this.showSpecialPasteButton = true;
			}
		},

		SpecialPasteButton_Hide : function()
		{
			if (!this.Api)
				return;

			if(this.showSpecialPasteButton)
			{
				this.showSpecialPasteButton = false;
				this.CleanButtonInfo();
				this.Api.asc_HideSpecialPasteButton();
			}
		},
		
		SpecialPasteButton_Update_Position : function()
		{
			if (!this.Api || !this.buttonInfo || this.buttonInfo.isClean())
				return;
			
			if(this.showSpecialPasteButton && !this.pasteStart)
			{
				this.Api.asc_UpdateSpecialPasteButton();
			}
		},

		CheckFastCoEditing: function()
		{
			if (!this.Api)
				return false;

			var res = false;

			var bFast = false;
			var bIsSingleUser = false;
			if(this.Api.collaborativeEditing)
			{
				bFast = this.Api.collaborativeEditing.m_bFast;
				bIsSingleUser = !this.Api.collaborativeEditing.getCollaborativeEditing();
			}
			else
			{
				bFast = AscCommon.CollaborativeEditing.m_bFast;
				bIsSingleUser = AscCommon.CollaborativeEditing.Is_SingleUser();
			}

			if(bFast && !bIsSingleUser)
			{
				res = true;
			}

			return res;
		},

		CleanButtonInfo: function()
		{
			this.buttonInfo.clean();
		}
	};

	var g_clipboardBase = new CClipboardBase();
	window['AscCommon'] = window['AscCommon'] || {};
	window['AscCommon'].g_clipboardBase = g_clipboardBase;

	var g_specialPasteHelper = new CSpecialPasteHelper();
	window['AscCommon'].g_specialPasteHelper = g_specialPasteHelper;
})(window);

// copy/paste focus error!!!
window["asc_desktop_copypaste"] = function(_api, _method)
{
	var bIsFocus = _api.asc_IsFocus();
	if (!bIsFocus)
		_api.asc_enableKeyEvents(true);
	window["AscDesktopEditor"][_method]();
	if (!bIsFocus)
		_api.asc_enableKeyEvents(false);
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(function(window, undefined)
{
	window["AscInputMethod"] = window["AscInputMethod"] || {};
	///
	// такие методы нужны в апи
	// baseEditorsApi.prototype.Begin_CompositeInput = function()
	// baseEditorsApi.prototype.Replace_CompositeText = function(arrCharCodes)
	// baseEditorsApi.prototype.Set_CursorPosInCompositeText = function(nPos)
	// baseEditorsApi.prototype.Get_CursorPosInCompositeText = function()
	// baseEditorsApi.prototype.End_CompositeInput = function()
	// baseEditorsApi.prototype.Get_MaxCursorPosInCompositeText = function()

	// baseEditorsApi.prototype.onKeyDown = function(e)
	// baseEditorsApi.prototype.onKeyPress = function(e)
	// baseEditorsApi.prototype.onKeyUp = function(e)
	///

	function CKeyboardEventWrapper(e)
	{
		// emulate
		this.altKey 	= e.altKey;
		this.ctrlKey 	= e.ctrlKey;
		this.metaKey 	= e.metaKey;
		this.shiftKey 	= e.shiftKey;

		this.charCode 	= e.charCode;
		this.keyCode 	= e.keyCode;
		this.which 		= e.which;

		this.code 		= e.code;
		this.key 		= e.key;

		this.srcElement = e.srcElement;
		this.target		= e.target;

		// work
		this._isDefaultPrevented = false;
	}
	CKeyboardEventWrapper.prototype =
	{
		preventDefault : function()
		{
			this._isDefaultPrevented = true;
		},
		stopPropagation : function()
		{
			// nothing
		}
	};

	function CTextInput(api)
	{
		this.Api = api;

		this.TargetId = null;			// id caret
		this.HtmlDiv  = null;			// для незаметной реализации одной textarea недостаточно

		this.TextArea_Not_ContentEditableDiv = true;
		this.HtmlArea = null;

		this.HtmlAreaOffset = 50; // height in pix
		this.HtmlAreaWidth = 200;

		this.LockerTargetTimer = -1;

		this.KeyDownFlag               = false;
		this.KeyPressFlag 			   = false;

		this.IsLockTargetMode = false;

		this.nativeFocusElement = null;
		this.nativeFocusElementNoRemoveOnElementFocus = false;
		this.InterfaceEnableKeyEvents = true;

		this.debugTexBoxMaxW = 100;
		this.debugTexBoxMaxH = 20;
		this.isDebug 	= false;
		this.isSystem 	= false;
		this.isShow		= false;

		// chrome element for left/top
		this.FixedPosCheckElementX = 0;
		this.FixedPosCheckElementY = 0;

		this.virtualKeyboardClickTimeout = -1;
		this.virtualKeyboardClickPrevent = false;

		// current text info
		this.TextBeforeComposition = "";
		this.Text = "";
		this.Target = 0;
		this.CompositionStart = 0;
		this.CompositionEnd = 0;

		this.IsComposition = false;
		this.ApiIsComposition = false;

		// Notes offset for slides
		this.TargetOffsetY = 0;

		// editor_sdk div sizes (for visible textarea)
		this.editorSdkW = 0;
		this.editorSdkH = 0;

		this.ReadOnlyCounter = 0;

		this.LastReplaceText = [];
		this.IsLastReplaceFlag = false;
	}

	CTextInput.prototype =
	{
		log : function(_val)
		{
			//console.log(_val);
		},

		init : function(target_id, parent_id)
		{
			this.TargetId   = target_id;

			var oHtmlParent = null;

			var oHtmlTarget = document.getElementById(this.TargetId);
			if (undefined == parent_id)
				oHtmlParent = oHtmlTarget.parentNode;
			else
				oHtmlParent = document.getElementById(parent_id);

			this.HtmlDiv                  = document.createElement("div");
			this.HtmlDiv.id               = "area_id_parent";
			this.HtmlDiv.style.background = "transparent";
			this.HtmlDiv.style.border     = "none";

			// в хроме скроллируется редактор, когда курсор текстового поля выходит за пределы окна
			if (AscCommon.AscBrowser.isChrome)
				this.HtmlDiv.style.position = "fixed";
			else
				this.HtmlDiv.style.position   = "absolute";
			this.HtmlDiv.style.zIndex     = 10;
			this.HtmlDiv.style.width      = "20px";
			this.HtmlDiv.style.height     = "50px";
			this.HtmlDiv.style.overflow   = "hidden";

			this.HtmlDiv.style.boxSizing 		= "content-box";
			this.HtmlDiv.style.webkitBoxSizing 	= "content-box";
			this.HtmlDiv.style.MozBoxSizing 	= "content-box";

			if (this.TextArea_Not_ContentEditableDiv)
			{
				this.HtmlArea               	= document.createElement("textarea");
			}
			else
			{
				this.HtmlArea					= document.createElement("div");
				this.HtmlArea.setAttribute("contentEditable", true);
			}
			this.HtmlArea.id                   	= "area_id";

			var _style = ("left:-" + (this.HtmlAreaWidth >> 1) + "px;top:" + (-this.HtmlAreaOffset) + "px;");
			_style += ("background:transparent;border:none;position:absolute;text-shadow:0 0 0 #000;outline:none;color:transparent;width:" + this.HtmlAreaWidth + "px;height:50px;");
			_style += "overflow:hidden;padding:0px;margin:0px;font-family:arial;font-size:10pt;resize:none;font-weight:normal;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;";
			this.HtmlArea.setAttribute("style", _style);
			this.HtmlArea.setAttribute("spellcheck", false);

			this.HtmlArea.setAttribute("autocapitalize", "none");
            this.HtmlArea.setAttribute("autocomplete", "off");
            this.HtmlArea.setAttribute("autocorrect", "off");

			this.HtmlDiv.appendChild(this.HtmlArea);

			if (true)
			{
				// нужен еще один родитель. чтобы скроллился он, а не oHtmlParent
				var oHtmlDivScrollable              = document.createElement("div");
				oHtmlDivScrollable.id 				= "area_id_main";
				oHtmlDivScrollable.setAttribute("style", "background:transparent;border:none;position:absolute;padding:0px;margin:0px;z-index:0;pointer-events:none;");

				var parentStyle                   = getComputedStyle(oHtmlParent);
				oHtmlDivScrollable.style.left     = parentStyle.left;
				oHtmlDivScrollable.style.top      = parentStyle.top;
				oHtmlDivScrollable.style.width    = parentStyle.width;
				oHtmlDivScrollable.style.height   = parentStyle.height;
				oHtmlDivScrollable.style.overflow = "hidden";

				oHtmlDivScrollable.appendChild(this.HtmlDiv);
				oHtmlParent.parentNode.appendChild(oHtmlDivScrollable);
			}
			else
			{
				oHtmlParent.appendChild(this.HtmlDiv);
			}

			// events:
			var oThis                   = this;
			this.HtmlArea["onkeydown"]  = function(e)
			{
			    if (AscCommon.AscBrowser.isSafariMacOs)
                {
                    var cmdButton = (e.ctrlKey || e.metaKey) ? true : false;
                    var buttonCode = ((e.keyCode == 67) || (e.keyCode == 88) || (e.keyCode == 86));
                    if (cmdButton && buttonCode)
                        oThis.IsDisableKeyPress = true;
                    else
                        oThis.IsDisableKeyPress = false;
                }
				return oThis.onKeyDown(e);
			};
			this.HtmlArea["onkeypress"] = function(e)
			{
			    if (oThis.IsDisableKeyPress == true)
			    {
			        // macOS Sierra send keypress before copy event
			        oThis.IsDisableKeyPress = false;
			        var cmdButton = (e.ctrlKey || e.metaKey) ? true : false;
			        if (cmdButton)
                        return;
			    }
				return oThis.onKeyPress(e);
			};
			this.HtmlArea["onkeyup"]    = function(e)
			{
			    oThis.IsDisableKeyPress = false;
				return oThis.onKeyUp(e);
			};

			this.HtmlArea.addEventListener("input", function(e)
			{
				return oThis.onInput(e);
			}, false);

			this.HtmlArea.addEventListener("compositionstart", function(e)
			{
				return oThis.onCompositionStart(e);
			}, false);
			this.HtmlArea.addEventListener("compositionupdate", function(e)
			{
				return oThis.onCompositionUpdate(e);
			}, false);
			this.HtmlArea.addEventListener("compositionend", function(e)
			{
				return oThis.onCompositionEnd(e);
			}, false);

			this.show();

			this.Api.Input_UpdatePos();

			if (AscCommon.AscBrowser.isAndroid)
			{
				this.HtmlArea.onclick = function (e)
				{
					var _this = AscCommon.g_inputContext;

					if (-1 != _this.virtualKeyboardClickTimeout)
					{
						clearTimeout(_this.virtualKeyboardClickTimeout);
						_this.virtualKeyboardClickTimeout = -1;
					}

					_this.apiCompositeEnd();

					if (!_this.virtualKeyboardClickPrevent)
						return;

					_this.HtmlArea.readOnly = true;
					_this.virtualKeyboardClickPrevent = false;
					AscCommon.stopEvent(e);
					_this.virtualKeyboardClickTimeout = setTimeout(function ()
					{
						_this.HtmlArea.readOnly = false;
						_this.virtualKeyboardClickTimeout = -1;
					}, 1);
					return false;
				};
			}
		},

		onResize : function(_editorContainerId)
		{
			var _elem          = document.getElementById("area_id_main");
			var _elemSrc       = document.getElementById(_editorContainerId);

			if (AscCommon.AscBrowser.isChrome)
			{
				var rectObject = _elemSrc.getBoundingClientRect();
				this.FixedPosCheckElementX = rectObject.left;
				this.FixedPosCheckElementY = rectObject.top;
			}

			var _width = _elemSrc.style.width;
			if ((null == _width || "" == _width) && window.getComputedStyle)
			{
				var _s = window.getComputedStyle(_elemSrc);
				_elem.style.left   = _s.left;
				_elem.style.top    = _s.top;
				_elem.style.width  = _s.width;
				_elem.style.height = _s.height;
			}
			else
			{
				_elem.style.left   = _elemSrc.style.left;
				_elem.style.top    = _elemSrc.style.top;
				_elem.style.width  = _width;
				_elem.style.height = _elemSrc.style.height;
			}

			if (this.Api.isMobileVersion)
			{
			    var _elem1 = document.getElementById("area_id_parent");
			    var _elem2 = document.getElementById("area_id");

			    _elem1.parentNode.style.pointerEvents = "";


                _elem1.style.left = "-100px";
			    _elem1.style.top = "-100px";
			    _elem1.style.right = "-100px";
			    _elem1.style.bottom = "-100px";
			    _elem1.style.width = "auto";
                _elem1.style.height = "auto";

			    _elem2.style.left = "0px";
                _elem2.style.top = "0px";
                _elem2.style.right = "0px";
                _elem2.style.bottom = "0px";
                _elem2.style.width = "100%";
                _elem2.style.height = "100%";

                if (AscCommon.AscBrowser.isIE)
				{
					document.body.style["msTouchAction"] = "none";
					document.body.style["touchAction"] = "none";
				}
			}

			var _editorSdk = document.getElementById("editor_sdk");
			this.editorSdkW = _editorSdk.clientWidth;
			this.editorSdkH = _editorSdk.clientHeight;
		},

		checkFocus : function()
		{
			if (this.Api.asc_IsFocus() && !AscCommon.g_clipboardBase.IsFocus() && !AscCommon.g_clipboardBase.IsWorking())
			{
				if (document.activeElement != this.HtmlArea)
					this.HtmlArea.focus();
			}
		},

		move : function(x, y)
		{
		    if (this.Api.isMobileVersion)
		        return;

			var oTarget = document.getElementById(this.TargetId);
			var xPos    = x ? x : parseInt(oTarget.style.left);
			var yPos    = (y ? y : parseInt(oTarget.style.top)) + parseInt(oTarget.style.height);

            if (AscCommon.AscBrowser.isSafari && AscCommon.AscBrowser.isMobile)
                xPos = -100;

			if (!this.isDebug && !this.isSystem)
			{
				this.HtmlDiv.style.left = xPos + this.FixedPosCheckElementX + "px";
				this.HtmlDiv.style.top  = yPos + this.FixedPosCheckElementY + this.TargetOffsetY + this.HtmlAreaOffset + "px";

				this.HtmlArea.scrollTop = this.HtmlArea.scrollHeight;
				//this.log("" + this.HtmlArea.scrollTop + ", " + this.HtmlArea.scrollHeight);
			}
			else
			{
				// this.HtmlAreaOffset - не сдвигаем, курсор должен быть виден
				this.debugCalculatePlace(xPos + this.FixedPosCheckElementX, yPos + this.FixedPosCheckElementY + this.TargetOffsetY);
			}

            if (window.g_asc_plugins)
                window.g_asc_plugins.onPluginEvent("onTargetPositionChanged");
		},

		emulateKeyDownApi : function(code)
		{
			var _e = {
				altKey : false,
				ctrlKey : false,
				shiftKey : false,
				target : null,
				charCode : 0,
				which : 0,
				keyCode : code,
				code : "",

				preventDefault : function() {},
				stopPropagation : function() {}
			};

			this.Api.onKeyDown(_e);
			this.Api.onKeyUp(_e);
		},

		clear : function(isFromFocus)
		{
			if (!this.TextArea_Not_ContentEditableDiv)
			{
				this.HtmlArea.innerHTML = "";
			}
			else
			{
				this.HtmlArea.value = "";
			}

			if (isFromFocus !== true)
				this.HtmlArea.focus();

			this.TextBeforeComposition = "";
			this.Text = "";
			this.Target = 0;
			this.CompositionStart = 0;
			this.CompositionEnd = 0;
			this.IsComposition = false;
		},

		getAreaValue : function()
		{
			return this.TextArea_Not_ContentEditableDiv ? this.HtmlArea.value : this.HtmlArea.innerText;
		},

		setReadOnly : function(isLock)
		{
			if (isLock)
				this.ReadOnlyCounter++;
			else
				this.ReadOnlyCounter--;

			// при синхронной загрузке шрифтов (десктоп)
			// может вызываться и в обратном порядке (setReadOnly(false), setReadOnly(true))
			// поэтому сравнение с нулем неверно. отрицательные значение могут быть.

			this.HtmlArea.readOnly = (0 >= this.ReadOnlyCounter) ? false : true;
		},

		show : function()
		{
			if (this.isDebug || this.isSystem)
			{
				this.log("ti: show");

				document.getElementById("area_id_main").style.zIndex = 10;

				this.HtmlArea.style.top   	= "0px";
				this.HtmlArea.style.width 	= "100%";
				this.HtmlArea.style.height 	= "100%";

				this.HtmlArea.style.background = "#FFFFFF";
				this.HtmlArea.style.color = "black";
				this.HtmlDiv.style.zIndex = 90;

				this.HtmlDiv.style.border = "2px solid #4363A4";

				this.isShow = true;
			}
		},

		unshow : function(isAttack)
		{
			if (this.isDebug || this.isSystem || (true == isAttack))
			{
				this.log("ti: unshow");

				document.getElementById("area_id_main").style.zIndex = 0;

				this.HtmlArea.style.top   	= ((-this.HtmlAreaOffset) + "px");
				this.HtmlArea.style.width 	= "1000px";
				this.HtmlArea.style.height 	= "50px";

				this.HtmlArea.style.background = "transparent";
				this.HtmlArea.style.color = "transparent";
				this.HtmlDiv.style.zIndex = 0;

				this.HtmlDiv.style.border = "none";

				this.isShow = false;
			}
		},

		debugCalculatePlace : function(x, y)
		{
			var _left = x;
			var _top = y;

			if (undefined == _left)
				_left = parseInt(this.HtmlDiv.style.left);
			if (undefined == _top)
				_top = parseInt(this.HtmlDiv.style.top);

			var _r_max = this.editorSdkW;
			var _b_max = this.editorSdkH;

			_r_max -= 60;
			if ((_r_max - _left) > 50)
			{
				this.debugTexBoxMaxW = _r_max - _left;
			}
			else
			{
				_left                = _r_max - 50;
				this.debugTexBoxMaxW	 = 50;
			}
			_b_max -= 40;
			if ((_b_max - _top) > 50)
			{
				this.debugTexBoxMaxH = _b_max - _top;
			}
			else
			{
				_top				= _b_max - 50;
				this.debugTexBoxMaxH = 50;
			}

			if (AscCommon.AscBrowser.isSafari && AscCommon.AscBrowser.isMobile)
			    _left = -100;

			this.HtmlDiv.style.left = _left + "px";
			this.HtmlDiv.style.top  = _top + "px";

			var _height = 22;
			var _t = this.getAreaValue();

			if (0 != _t.length)
			{
				var _editorSdk = document.getElementById("editor_sdk");

				// теперь нужно расчитать ширину/высоту текстбокса
				var _p = document.createElement('p');
				_p.style.zIndex = "-1";
				_p.style.position = "absolute";
				_p.style.fontFamily = "arial";
				_p.style.fontSize = "12pt";
				_p.style.left = "0px";
				_p.style.width = this.debugTexBoxMaxW + "px";

				_editorSdk.appendChild(_p);

				_t = _t.replace(/ /g, "&nbsp;");
				_p.innerHTML = "<span>" + _t + "</span>";
				var _width = _p.firstChild.offsetWidth;
				_width = Math.min(_width + 20, this.debugTexBoxMaxW);

				if (AscCommon.AscBrowser.isIE)
					_width += 10;

				var area = document.createElement('textarea');
				area.style.zIndex = "-1";
				area.id = "area2_id";
				area.rows = 1;
				area.setAttribute("style", "font-family:arial;font-size:12pt;position:absolute;resize:none;padding:0px;margin:0px;font-weight:normal;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;");
				area.style.overflow = "hidden";
				area.style.width = _width + "px";
				_editorSdk.appendChild(area);

				area.value = this.getAreaValue();

				_height = area.clientHeight;
				if (area.scrollHeight > _height)
					_height = area.scrollHeight;

				_editorSdk.removeChild(_p);
				_editorSdk.removeChild(area);
			}

			if (_height > this.debugTexBoxMaxH)
				_height = this.debugTexBoxMaxH;

			this.HtmlDiv.style.width  = _width + "px";
			this.HtmlDiv.style.height = _height + "px";

			// вот такая заглушка под firefox если этого не делать, то будет плохо перерисовываться border)
			var oldZindex                  = parseInt(this.HtmlDiv.style.zIndex);
			var newZindex                  = (oldZindex == 90) ? "89" : "90";
			this.HtmlDiv.style.zIndex = newZindex;
		},

		onInput : function(e, isFromCompositionUpdate)
		{
			if (this.Api.isLongAction() || this.Api.isViewMode)
			{
				AscCommon.stopEvent(e);
				return false;
			}

			if (this.isSystem)
			{
				if (!this.isShow)
					this.show();

				this.debugCalculatePlace(undefined, undefined);
				return;
			}

			this.log("ti: onInput");

			// current text value
			this.Text = this.getAreaValue();
			this.Text = this.Text.split("&nbsp;").join(" ");

			var codes = [];
			if (this.IsComposition || this.ApiIsComposition)
			{
				var ieStart = -1;
				var ieEnd = -1;

				if (true)
				{
					var target = e.target;
					if (target["msGetInputContext"])
					{
						var ctx = target["msGetInputContext"]();

						if (ctx)
						{
							ieStart = ctx["compositionStartOffset"];
							ieEnd = ctx["compositionEndOffset"];
						}
					}
				}

				this.CompositionEnd = this.Text.length;
				this.CompositionStart = this.TextBeforeComposition.length;

				var textReplace = this.Text.substr(this.CompositionStart);
				var iter;
				for (iter = textReplace.getUnicodeIterator(); iter.check(); iter.next())
				{
					codes.push(iter.value());
				}

				var isAsync = AscFonts.FontPickerByCharacter.checkTextLight(codes, true);

				if (!isAsync)
				{
					// ie/edge могут не присылать onCompositeEnd. И тогда ориентир - дополнительный селект
					if (ieStart > this.CompositionStart)
					{
						textReplace = textReplace.substr(0, ieStart - this.CompositionStart);

						codes = [];
						for (iter = textReplace.getUnicodeIterator(); iter.check(); iter.next())
						{
							codes.push(iter.value());
						}

						this.apiCompositeReplace(codes);
						this.apiCompositeEnd();

						this.TextBeforeComposition = this.Text.substr(0, ieStart);

						this.apiCompositeStart();
						this.CompositionStart = ieStart;

						codes = [];
						textReplace = this.Text.substr(this.CompositionStart);
						for (iter = textReplace.getUnicodeIterator(); iter.check(); iter.next())
						{
							codes.push(iter.value());
						}

						this.apiCompositeReplace(codes);
					}
					else
					{
						this.apiCompositeReplace(codes);
					}

					if (!this.IsComposition)
					{
						this.apiCompositeEnd();
						this.TextBeforeComposition = this.Text;
					}
				}
				else
				{
					AscFonts.FontPickerByCharacter.loadFonts(this, function ()
					{

						this.apiCompositeReplace(codes);
						this.apiCompositeEnd();

						this.clear();
						this.setReadOnly(false);

					});

					AscCommon.stopEvent(e);
					this.setReadOnly(true);
					return false;
				}
			}
			else
			{
				var textToApi = this.Text.substr(this.TextBeforeComposition.length);
				for (var iter = textToApi.getUnicodeIterator(); iter.check(); iter.next())
				{
					codes.push(iter.value());
				}

				this.apiInputText(codes);
				this.TextBeforeComposition = this.Text;
			}

			if (!this.IsComposition)
			{
				if (this.Text.length > 0)
				{
					var _lastCode = this.Text.charCodeAt(this.Text.length - 1);
					if (_lastCode == 12290 || _lastCode == 46)
					{
						// китайская точка
						AscCommon.stopEvent(e);

						if (AscCommon.AscBrowser.isIE && !AscCommon.AscBrowser.isIeEdge)
						{
							// ie тепряет фокус
							setTimeout(function(){
                                window['AscCommon'].g_inputContext.clear();
                                window['AscCommon'].g_inputContext.HtmlArea.focus();
							}, 0);
						}
						else
						{
							this.clear();
						}

						return false;
					}
				}
			}
		},

		emulateNativeKeyDown : function(e)
		{
			var oEvent = document.createEvent('KeyboardEvent');

			/*
			 var _event = new KeyboardEvent("keydown", {
			 bubbles : true,
			 cancelable : true,
			 char : e.charCode,
			 shiftKey : e.shiftKey,
			 ctrlKey : e.ctrlKey,
			 metaKey : e.metaKey,
			 altKey : e.altKey,
			 keyCode : e.keyCode,
			 which : e.which,
			 key : e.key
			 });
			 */

			// Chromium Hack
			Object.defineProperty(oEvent, 'keyCode', {
				get : function()
				{
					return this.keyCodeVal;
				}
			});
			Object.defineProperty(oEvent, 'which', {
				get : function()
				{
					return this.keyCodeVal;
				}
			});
			Object.defineProperty(oEvent, 'shiftKey', {
				get : function()
				{
					return this.shiftKeyVal;
				}
			});
			Object.defineProperty(oEvent, 'altKey', {
				get : function()
				{
					return this.altKeyVal;
				}
			});
			Object.defineProperty(oEvent, 'metaKey', {
				get : function()
				{
					return this.metaKeyVal;
				}
			});
			Object.defineProperty(oEvent, 'ctrlKey', {
				get : function()
				{
					return this.ctrlKeyVal;
				}
			});

			if (AscCommon.AscBrowser.isIE)
			{
				oEvent.preventDefault = function ()
				{
					try
					{
						Object.defineProperty(this, "defaultPrevented", {
							get: function ()
							{
								return true;
							}
						});
					}
					catch(err)
					{
					}
				};
			}

			var k = e.keyCode;
			if (oEvent.initKeyboardEvent)
			{
				oEvent.initKeyboardEvent("keydown", true, true, window, false, false, false, false, k, k);
			}
			else
			{
				oEvent.initKeyEvent("keydown", true, true, window, false, false, false, false, k, 0);
			}

			oEvent.keyCodeVal = k;
			oEvent.shiftKeyVal = e.shiftKey;
			oEvent.altKeyVal = e.altKey;
			oEvent.metaKeyVal = e.metaKey;
			oEvent.ctrlKeyVal = e.ctrlKey;

			var _elem = _getElementKeyboardDown(this.nativeFocusElement, 3);
			_elem.dispatchEvent(oEvent);

			return oEvent.defaultPrevented;
		},

		isSpaceSymbol : function(e)
		{
			if (e.keyCode == 32)
				return true;

			if ((e.keyCode == 229) && ((e.code == "space") || (e.code == "Space") || (e.key == "Spacebar")))
				return true;

			return false;
		},

		systemInputEnable : function(isEnabled)
		{
			if (this.isSystem == isEnabled)
				return;

			this.isSystem = isEnabled;

			this.HtmlArea.style.left = this.isSystem ? "0px" : ("-" + (this.HtmlAreaWidth >> 1) + "px");

			this.clear();
			if (this.isShow)
				this.unshow(true);

			if (this.Api.WordControl && this.Api.WordControl.m_oLogicDocument && this.Api.WordControl.m_oLogicDocument.Document_UpdateSelectionState)
				this.Api.WordControl.m_oLogicDocument.Document_UpdateSelectionState();
		},

		debugInputEnable : function(isEnabled)
		{
			if (this.isDebug == isEnabled)
				return;

			this.isDebug = isEnabled;
			this.HtmlArea.style.left = this.isDebug ? "0px" : ("-" + (this.HtmlAreaWidth >> 1) + "px");
		},

		apiInputText : function(codes)
		{
			var isAsync = AscFonts.FontPickerByCharacter.checkTextLight(codes, true);

			if (!isAsync)
			{
				this.apiCompositeStart();
				this.apiCompositeReplace(codes);
				this.apiCompositeEnd();
			}
			else
			{
				AscFonts.FontPickerByCharacter.loadFonts(this, function ()
				{

					this.apiCompositeStart();
					this.apiCompositeReplace(codes);
					this.apiCompositeEnd();

					this.setReadOnly(false);

				});

				this.setReadOnly(true);
				return false;
			}
		},

		onKeyDown : function(e)
		{
			if (this.Api.isLongAction())
			{
				AscCommon.stopEvent(e);
				return false;
			}

			if (this.isSystem && this.isShow)
			{
				// нужно проверить на enter
				// вся остальная обработка - в текстбоксе

				if (e.keyCode == 13)
				{
					var text = this.getAreaValue();
					var codes = [];
					for (var iter = text.getUnicodeIterator(); iter.check(); iter.next())
					{
						codes.push(iter.value());
					}

					this.apiInputText(codes);

					this.clear();
					this.unshow();

					AscCommon.stopEvent(e);
					return false;
				}
				else if (e.keyCode == 27)
				{
					this.clear();
					this.unshow();

					AscCommon.stopEvent(e);
					return false;
				}

				// вся обработка - в текстбоксе
				return;
			}

			if (null != this.nativeFocusElement)
			{
				if (this.emulateNativeKeyDown(e))
				{
					e.preventDefault();
					return false;
				}
			}

			// некоторые рукописные вводы не присылают keyUp
			var _code = e.keyCode;
			if (_code != 8 && _code != 46)
				this.KeyDownFlag = true;

			AscCommon.check_KeyboardEvent(e);
			var arrCodes = this.Api.getAddedTextOnKeyDown(AscCommon.global_keyboardEvent);

			var isAsync = AscFonts.FontPickerByCharacter.checkTextLight(arrCodes, true);

			if (isAsync)
			{
				AscFonts.FontPickerByCharacter.loadFonts(this, function ()
				{

					this.onKeyDown(e);
					this.onKeyUp(e);

					this.setReadOnly(false);

				});

				AscCommon.stopEvent(e);
				this.setReadOnly(true);
				return false;
			}

			var ret = this.Api.onKeyDown(e);

			switch (e.keyCode)
			{
				case 8:		// backspace
				case 9:		// tab
				case 13:	// enter
				case 37:	// left
				case 38:	// top
				case 39:	// right
				case 40:	// bottom
				case 33: 	// pageup
				case 34: 	// pagedown
				case 35: 	// end
				case 36: 	// home
				{
					this.clear();
					return false;
				}
				case 46:	// delete
				case 45:	// insert
				{
					if (!AscCommon.global_keyboardEvent.CtrlKey && !AscCommon.global_keyboardEvent.ShiftKey) // copy/cut/paste
					{
						// заканчиваем "непрерывный" ввод => очищаем текстбокс
						this.clear();
						return false;
					}
				}
				default:
					break;
			}

			return ret;
		},

		onKeyPress : function(e)
		{
			if (this.Api.isLongAction() || !this.Api.asc_IsFocus() || this.Api.isViewMode)
			{
				AscCommon.stopEvent(e);
				return false;
			}

			if (this.isSystem)
				return;

			if (this.KeyDownFlag)
				this.KeyPressFlag = true;

			if (this.IsComposition)
				return;

			if ((e.which == 13 && e.keyCode == 13) || (e.which == 10 && e.keyCode == 10))
			{
				AscCommon.stopEvent(e);
				return false;
			}

            var c = e.which || e.keyCode;

			var isAsync = AscFonts.FontPickerByCharacter.checkTextLight([c], true);

			if (isAsync)
			{
				AscFonts.FontPickerByCharacter.loadFonts(this, function ()
				{

					this.apiCompositeStart();
					this.apiCompositeReplace([c]);
					this.apiCompositeEnd();

					this.setReadOnly(false);

				});

				AscCommon.stopEvent(e);
				this.setReadOnly(true);
				return false;
			}

			var ret = this.Api.onKeyPress(e);

			switch (e.which)
			{
				case 46:
				{
					AscCommon.stopEvent(e);
					this.clear();
					return false;
				}
				default:
					break;
			}

			AscCommon.stopEvent(e);
			return ret;
		},

		onKeyUp : function(e)
		{
			if (this.Api.isLongAction())
			{
				AscCommon.stopEvent(e);
				return false;
			}

			if (this.isSystem && this.isShow)
				return;

			this.KeyDownFlag = false;
			this.KeyPressFlag = false;

			AscCommon.global_keyboardEvent.Up();
		},

		getAreaPos : function()
		{
			var _offset = 0;
			if (this.TextArea_Not_ContentEditableDiv)
			{
				_offset = this.HtmlArea.selectionEnd;
			}
			else
			{
				var sel = window.getSelection();
				if (sel.rangeCount > 0)
				{
					var range = sel.getRangeAt(0);
					_offset = range.endOffset;
				}
			}
			return _offset;
		},

		checkTargetPosition : function(isCorrect)
		{
			var _offset = this.getAreaPos();

			if (false !== isCorrect)
			{
				var _value = this.getAreaValue();
				_offset -= (_value.length - this.compositionValue.length);
			}

			if (!this.IsLockTargetMode)
			{
				// никакого смысла прыгать курсором туда-сюда
				if (_offset == 0 && this.compositionValue.length == 1)
					_offset = 1;
			}

			this.Api.Set_CursorPosInCompositeText(_offset);

			this.unlockTarget();
		},

		lockTarget : function()
		{
			if (!this.IsLockTargetMode)
				return;

			if (-1 != this.LockerTargetTimer)
				clearTimeout(this.LockerTargetTimer);

			this.Api.asc_LockTargetUpdate(true);

			var oThis              = this;
			this.LockerTargetTimer = setTimeout(function()
			{
				oThis.unlockTarget();
			}, 1000);
		},

		unlockTarget : function()
		{
			if (!this.IsLockTargetMode)
				return;

			if (-1 != this.LockerTargetTimer)
				clearTimeout(this.LockerTargetTimer);
			this.LockerTargetTimer = -1;

			this.Api.asc_LockTargetUpdate(false);
		},

		clearLastCompositeText : function()
		{
			this.LastReplaceText = [];
			this.IsLastReplaceFlag = false;
		},

		apiCompositeStart : function()
		{
		},

		apiCompositeReplace : function(_value)
		{
			if (this.Api.isLongAction())
			{
				AscCommon.stopEvent(e);
				return false;
			}

			if (!this.ApiIsComposition)
			{
				this.Api.Begin_CompositeInput();
				this.clearLastCompositeText();
			}

            this.ApiIsComposition = true;

			if (this.IsLastReplaceFlag)
			{
				// check _value == this.LastReplaceText
				if (_value.length == this.LastReplaceText.length)
				{
					var isEqual = true;
					for (var nC = 0; nC < _value.length; nC++)
					{
						if (_value[nC] != this.LastReplaceText[nC])
						{
							isEqual = false;
							break;
						}
					}

					if (isEqual)
						return; // не посылаем одинаковые замены!
				}
			}

            this.Api.Replace_CompositeText(_value);

			this.LastReplaceText = _value.slice();
			this.IsLastReplaceFlag = true;
		},

		apiCompositeEnd : function()
		{
			if (!this.ApiIsComposition)
				return;

			this.ApiIsComposition = false;
			this.Api.End_CompositeInput();
			this.clearLastCompositeText();
		},

		onCompositionStart : function(e)
		{
			if (this.isSystem)
				return;

			this.IsComposition = true;
		},

		onCompositionUpdate : function(e)
		{
			if (this.isSystem)
				return;

			this.IsComposition = true;
			this.onInput(e, true);
		},

		onCompositionEnd : function(e)
		{
			if (this.isSystem)
				return;

			this.IsComposition = false;

			this.onInput(e, true);
		},

		setInterfaceEnableKeyEvents : function(value)
		{
			this.InterfaceEnableKeyEvents = value;
			if (true == this.InterfaceEnableKeyEvents)
			{
			    if (document.activeElement)
			    {
			        var _id = document.activeElement.id;
			        if (_id == "area_id" || (window.g_asc_plugins && window.g_asc_plugins.checkRunnedFrameId(_id)))
			            return;
			    }

				this.HtmlArea.focus();
			}
		},

		externalEndCompositeInput : function()
		{
			this.clear();
		},

		externalChangeFocus : function()
		{
			if (!this.IsComposition)
				return false;

			setTimeout(function() {
				window['AscCommon'].g_inputContext.clear();
			}, 10);

			return true;
		},

		isCompositionProcess : function()
		{
			return this.IsComposition;
		},

		preventVirtualKeyboard : function(e)
		{
			//AscCommon.stopEvent(e);

			if (AscCommon.AscBrowser.isAndroid)
			{
				this.virtualKeyboardClickPrevent = true;
			}
		},

		enableVirtualKeyboard : function()
		{
			if (AscCommon.AscBrowser.isAndroid)
			{
				if (-1 != this.virtualKeyboardClickTimeout)
				{
					clearTimeout(this.virtualKeyboardClickTimeout);
					this.virtualKeyboardClickTimeout = -1;
				}

				this.virtualKeyboardClickPrevent = false;
			}
		}
	};

	function _getAttirbute(_elem, _attr, _depth)
	{
		var _elemTest = _elem;
		for (var _level = 0; _elemTest && (_level < _depth); ++_level, _elemTest = _elemTest.parentNode)
		{
			var _res = _elemTest.getAttribute ? _elemTest.getAttribute(_attr) : null;
			if (null != _res)
				return _res;
		}
		return null;
	}
	function _getElementKeyboardDown(_elem, _depth)
	{
		var _elemTest = _elem;
		for (var _level = 0; _elemTest && (_level < _depth); ++_level, _elemTest = _elemTest.parentNode)
		{
			var _res = _elemTest.getAttribute ? _elemTest.getAttribute("oo_editor_keyboard") : null;
			if (null != _res)
				return _elemTest;
		}
		return null;
	}
	function _getDefaultKeyboardInput(_elem, _depth)
	{
		var _elemTest = _elem;
		for (var _level = 0; _elemTest && (_level < _depth); ++_level, _elemTest = _elemTest.parentNode)
		{
			var _name = " " + _elemTest.className + " ";
			if (_name.indexOf(" dropdown-menu" ) > -1 ||
				_name.indexOf(" dropdown-toggle ") > -1 ||
				_name.indexOf(" dropdown-submenu ") > -1 ||
				_name.indexOf(" canfocused ") > -1)
			{
				return "true";
			}
		}
		return null;
	}

	window['AscCommon']            = window['AscCommon'] || {};
	window['AscCommon'].CTextInput = CTextInput;

	window['AscCommon'].InitBrowserInputContext = function(api, target_id, parent_id)
	{
		if (window['AscCommon'].g_inputContext)
			return;

		window['AscCommon'].g_inputContext = new CTextInput(api);
		window['AscCommon'].g_inputContext.init(target_id, parent_id);
		window['AscCommon'].g_clipboardBase.Init(api);
		window['AscCommon'].g_clipboardBase.inputContext = window['AscCommon'].g_inputContext;

		if (window['AscCommon'].TextBoxInputMode === true)
		{
			window['AscCommon'].g_inputContext.systemInputEnable(true);
		}

		//window["SetInputDebugMode"]();

		document.addEventListener("focus", function(e)
		{
			var t                = window['AscCommon'].g_inputContext;
			var _oldNativeFE	 = t.nativeFocusElement;
			t.nativeFocusElement = e.target;

			if (t.IsComposition)
			{
				t.apiCompositeEnd();
				t.externalEndCompositeInput();
			}

			if (!t.isSystem)
				t.clear(true);

			var _nativeFocusElementNoRemoveOnElementFocus = t.nativeFocusElementNoRemoveOnElementFocus;
			t.nativeFocusElementNoRemoveOnElementFocus = false;

			if (t.InterfaceEnableKeyEvents == false)
			{
				t.nativeFocusElement = null;
				return;
			}

			if (t.nativeFocusElement && (t.nativeFocusElement.id == t.HtmlArea.id))
			{
				t.Api.asc_enableKeyEvents(true, true);

				if (_nativeFocusElementNoRemoveOnElementFocus)
					t.nativeFocusElement = _oldNativeFE;
				else
					t.nativeFocusElement = null;

				return;
			}
			if (t.nativeFocusElement && (t.nativeFocusElement.id == window['AscCommon'].g_clipboardBase.CommonDivId))
			{
				t.nativeFocusElement = null;
				return;
			}

			t.nativeFocusElementNoRemoveOnElementFocus = false;

			var _isElementEditable = false;
			if (t.nativeFocusElement)
			{
				// detect _isElementEditable
				var _name = t.nativeFocusElement.nodeName;
				if (_name)
					_name = _name.toUpperCase();

				if ("INPUT" == _name || "TEXTAREA" == _name)
					_isElementEditable = true;
				else if ("DIV" == _name)
				{
					if (t.nativeFocusElement.getAttribute("contenteditable") == "true")
						_isElementEditable = true;
				}
			}
			if ("IFRAME" == _name)
			{
				// перехват клавиатуры
				t.Api.asc_enableKeyEvents(false, true);
				t.nativeFocusElement = null;
				return;
			}

			// перехватывает ли элемент ввод
			var _oo_editor_input    = _getAttirbute(t.nativeFocusElement, "oo_editor_input", 3);
			// нужно ли прокидывать нажатие клавиш элементу (ТОЛЬКО keyDown)
			var _oo_editor_keyboard = _getAttirbute(t.nativeFocusElement, "oo_editor_keyboard", 3);

			if (!_oo_editor_input && !_oo_editor_keyboard)
				_oo_editor_input = _getDefaultKeyboardInput(t.nativeFocusElement, 3);

			if (_oo_editor_keyboard == "true")
				_oo_editor_input = undefined;

			if (_oo_editor_input == "true")
			{
				// перехват клавиатуры
				t.Api.asc_enableKeyEvents(false, true);
				t.nativeFocusElement = null;
				return;
			}

			if (_isElementEditable && (_oo_editor_input != "false"))
			{
				// перехват клавиатуры
				t.Api.asc_enableKeyEvents(false, true);
				t.nativeFocusElement = null;
				return;
			}

			// итак, ввод у нас. теперь определяем, нужна ли клавиатура элементу
			if (_oo_editor_keyboard != "true")
				t.nativeFocusElement = null;

			var _elem = t.nativeFocusElement;
			t.nativeFocusElementNoRemoveOnElementFocus = true; // ie focus async
			t.HtmlArea.focus();
			t.nativeFocusElement = _elem;
			t.Api.asc_enableKeyEvents(true, true);
		}, true);

		// send focus
		window['AscCommon'].g_inputContext.HtmlArea.focus();
	};

	window["SetInputDebugMode"] = function()
	{
		if (!window['AscCommon'].g_inputContext)
			return;

		window['AscCommon'].g_inputContext.debugInputEnable(true);
		window['AscCommon'].g_inputContext.show();
	};
})(window);

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

(
    /**
     * @param {Window} window
     * @param {undefined} undefined
     */
function (window, undefined) {


        function COleSize(w, h){
            this.w = w;
            this.h = h;
        }
        COleSize.prototype.Write_ToBinary = function(Writer){
            Writer.WriteLong(this.w);
            Writer.WriteLong(this.h);
        };
        COleSize.prototype.Read_FromBinary = function(Reader){
            this.w = Reader.GetLong();
            this.h = Reader.GetLong();
        };

        AscDFH.changesFactory[AscDFH.historyitem_ImageShapeSetData] = AscDFH.CChangesDrawingsString;
        AscDFH.changesFactory[AscDFH.historyitem_ImageShapeSetApplicationId] = AscDFH.CChangesDrawingsString;
        AscDFH.changesFactory[AscDFH.historyitem_ImageShapeSetPixSizes] = AscDFH.CChangesDrawingsObjectNoId;
		AscDFH.changesFactory[AscDFH.historyitem_ImageShapeSetObjectFile] = AscDFH.CChangesDrawingsString;


        AscDFH.drawingsChangesMap[AscDFH.historyitem_ImageShapeSetData] = function(oClass, value){oClass.m_sData = value;};
        AscDFH.drawingsChangesMap[AscDFH.historyitem_ImageShapeSetApplicationId] = function(oClass, value){oClass.m_sApplicationId = value;};
        AscDFH.drawingsChangesMap[AscDFH.historyitem_ImageShapeSetPixSizes] = function(oClass, value){
            if(value){
                oClass.m_nPixWidth = value.w;
                oClass.m_nPixHeight = value.h;
            }
        };
        AscDFH.drawingsConstructorsMap[AscDFH.historyitem_ImageShapeSetPixSizes] = COleSize;
		AscDFH.drawingsChangesMap[AscDFH.historyitem_ImageShapeSetObjectFile] = function(oClass, value){oClass.m_sObjectFile = value;};

    function COleObject()
    {
		AscFormat.CImageShape.call(this);
        this.m_sData = null;
        this.m_sApplicationId = null;
        this.m_nPixWidth = null;
        this.m_nPixHeight = null;
        this.m_fDefaultSizeX = null;
        this.m_fDefaultSizeY = null;
        this.m_sObjectFile = null;//ole object name in OOX
    }

		COleObject.prototype = Object.create(AscFormat.CImageShape.prototype);
		COleObject.prototype.constructor = COleObject;

    COleObject.prototype.getObjectType = function()
    {
        return AscDFH.historyitem_type_OleObject;
    };
    COleObject.prototype.setData = function(sData)
    {
        AscCommon.History.Add(new AscDFH.CChangesDrawingsString(this, AscDFH.historyitem_ImageShapeSetData, this.m_sData, sData));
        this.m_sData = sData;
    };
    COleObject.prototype.setApplicationId = function(sApplicationId)
    {
        AscCommon.History.Add(new AscDFH.CChangesDrawingsString(this, AscDFH.historyitem_ImageShapeSetApplicationId, this.m_sApplicationId, sApplicationId));
        this.m_sApplicationId = sApplicationId;
    };
    COleObject.prototype.setPixSizes = function(nPixWidth, nPixHeight)
    {
        AscCommon.History.Add(new AscDFH.CChangesDrawingsObjectNoId(this, AscDFH.historyitem_ImageShapeSetPixSizes, new COleSize(this.m_nPixWidth, this.m_nPixHeight), new COleSize(nPixWidth, nPixHeight)));
        this.m_nPixWidth = nPixWidth;
        this.m_nPixHeight = nPixHeight;
    };
    COleObject.prototype.setObjectFile = function(sObjectFile)
    {
        AscCommon.History.Add(new AscDFH.CChangesDrawingsString(this, AscDFH.historyitem_ImageShapeSetObjectFile, this.m_sObjectFile, sObjectFile));
        this.m_sObjectFile = sObjectFile;
    };

    COleObject.prototype.canRotate = function () {
        return false;
    };

    COleObject.prototype.copy = function()
    {
        var copy = new COleObject();
        if(this.nvPicPr)
        {
            copy.setNvPicPr(this.nvPicPr.createDuplicate());
        }
        if(this.spPr)
        {
            copy.setSpPr(this.spPr.createDuplicate());
            copy.spPr.setParent(copy);
        }
        if(this.blipFill)
        {
            copy.setBlipFill(this.blipFill.createDuplicate());
        }
        if(this.style)
        {
            copy.setStyle(this.style.createDuplicate());
        }
        copy.setBDeleted(this.bDeleted);
        if(this.fromSerialize)
        {
            copy.setBFromSerialize(true);
        }
        copy.setData(this.m_sData);
        copy.setApplicationId(this.m_sApplicationId);
        copy.setPixSizes(this.m_nPixWidth, this.m_nPixHeight);
        copy.setObjectFile(this.m_sObjectFile);
        copy.cachedImage = this.getBase64Img();
        copy.cachedPixH = this.cachedPixH;
        copy.cachedPixW = this.cachedPixW;
        return copy;
    };


    COleObject.prototype.handleUpdateExtents = function(){
        if(!AscFormat.isRealNumber(this.m_fDefaultSizeX) || !AscFormat.isRealNumber(this.m_fDefaultSizeY)){
            if(this.spPr && this.spPr.xfrm && AscFormat.isRealNumber(this.spPr.xfrm.extX) && AscFormat.isRealNumber(this.spPr.xfrm.extY)){
                this.m_fDefaultSizeX = this.spPr.xfrm.extX;
                this.m_fDefaultSizeY = this.spPr.xfrm.extY;
            }
        }
        if(AscFormat.CImageShape.prototype.handleUpdateExtents){
            AscFormat.CImageShape.prototype.handleUpdateExtents.call(this, []);
        }
    };
    COleObject.prototype.checkTypeCorrect = function(){
        if(!this.m_sData){
            return false;
        }
        if(!this.m_sApplicationId){
            return false;
        }
        if(this.m_nPixHeight === null || this.m_nPixHeight === null){
            return false;
        }
        return true;
    };
        window['AscFormat'] = window['AscFormat'] || {};
        window['AscFormat'].COleObject = COleObject;
})(window);
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */
"use strict";
(function (window, undefined){


    /**
     * CDrawingDocContent
     * @constructor
     * @extends {CDocumentContent}
     */
    function CDrawingDocContent(Parent, DrawingDocument, X, Y, XLimit, YLimit) {
		CDocumentContent.call(this, Parent, DrawingDocument, X, Y, XLimit, YLimit, false, false, true);
        this.FullRecalc = new CDocumentRecalculateState();
    }

	CDrawingDocContent.prototype = Object.create(CDocumentContent.prototype);
	CDrawingDocContent.prototype.constructor = CDrawingDocContent;

    CDrawingDocContent.prototype.GetSummaryHeight = function(){
        var fSummHeight = 0;
        var nColumnsCount = this.Get_ColumnsCount();
        for(var i = 0; i < this.Pages.length; ++i){
            var oPage = this.Pages[i];
            var fPageHeight = 0;
            if(oPage.Sections.length > 0){
                var aColumns = oPage.Sections[0].Columns;
                for(var j = 0; j < aColumns.length; ++j){
                    var oColumn = aColumns[j];
                    for(var k = oColumn.Pos; k <= oColumn.EndPos; ++k){
                        var nElementPageIndex = this.private_GetElementPageIndex(k, i, j, nColumnsCount);
                        var fParagraphPageBottom = this.Content[k].Get_PageBounds(nElementPageIndex).Bottom;
                        if(fPageHeight < fParagraphPageBottom){
                            fPageHeight = fParagraphPageBottom;
                        }
                    }
                }
            }
            else{
                var Bounds = this.Get_PageBounds(i);
                fPageHeight = Bounds.Bottom - Bounds.Top;
            }
            fSummHeight += fPageHeight;
        }
        return fSummHeight;
    };

    CDrawingDocContent.prototype.GetSummaryHeight_ =function () {
        var dHeight = 0.0;
        for(var i = 0; i < this.Content.length; ++i){
            var oElement = this.Content[i];
            if(oElement.GetType() === type_Paragraph){
                for(var j = 0; j < oElement.Lines.length; ++j){
                    var oLine = oElement.Lines[j];
                    dHeight += (oLine.Bottom - oLine.Top - oLine.Metrics.Descent);
                }
            }
        }
        return dHeight;
    };

    CDrawingDocContent.prototype.Get_ColumnsCount = function(){
        var nColumnCount = 1;
        if(this.Parent.getBodyPr){
            var oBodyPr = this.Parent.getBodyPr();
            nColumnCount = AscFormat.isRealNumber(oBodyPr.numCol) ? oBodyPr.numCol : 1;
        }
        return nColumnCount;
    };

    CDrawingDocContent.prototype.Get_PageContentStartPos2 = function(StartPageIndex, StartColumnIndex, ElementPageIndex, ElementIndex){
        var ColumnsCount = this.Get_ColumnsCount();
        var nColumnIndex    = (StartColumnIndex + ElementPageIndex) - ((StartColumnIndex + ElementPageIndex) / ColumnsCount | 0) * ColumnsCount;
        return this.Get_PageContentStartPos3(nColumnIndex);
    };


    CDrawingDocContent.prototype.Get_PageContentStartPos3 = function(nColumnIndex){

        var X = this.X;
        var Y = this.Y;
        var XLimit = this.XLimit;
        var YLimit = this.YLimit;
        var ColumnSpaceBefore = 0;
        var ColumnSpaceAfter = 0;
        var nNumCol = this.Get_ColumnsCount();
        var oBodyPr = this.Parent.getBodyPr && this.Parent.getBodyPr();
        if(nNumCol > 1 && oBodyPr)
        {
            var fSpace = AscFormat.isRealNumber(oBodyPr.spcCol) ? oBodyPr.spcCol : 0;
            fSpace = Math.min(fSpace, this.XLimit/(nNumCol - 1));
            var fColumnWidth = Math.max((this.XLimit - this.X - (nNumCol - 1)*fSpace)/nNumCol, 0);
            X += nColumnIndex*(fColumnWidth + fSpace);
            XLimit = X + fColumnWidth;
            if(nColumnIndex > 0)
            {
                ColumnSpaceBefore = fSpace;
            }
            if(nColumnIndex < nNumCol - 1)
            {
                ColumnSpaceAfter = fSpace;
            }
        }
        return {
            X                 : X,
            Y                 : Y,
            XLimit            : XLimit,
            YLimit            : YLimit,
            ColumnSpaceBefore : ColumnSpaceBefore,
            ColumnSpaceAfter  : ColumnSpaceAfter
        };
    };


    CDrawingDocContent.prototype.RecalculateContent = function(fWidth, fHeight, nStartPage){
        if(this.Get_ColumnsCount() === 1){
            CDocumentContent.prototype.RecalculateContent.call(this, fWidth, fHeight, nStartPage);
        }
        else{
            this.Start_Recalculate(fWidth, fHeight);
            if(this.Pages.length > 1){
                var fSummaryHeight = this.GetSummaryHeight();

                var fLow = fHeight, fHigh = fSummaryHeight;
                this.Start_Recalculate(fWidth, fHigh);
                var nItCount = 0;
                while(this.Pages.length > 1 && nItCount < 5){
                    fHigh += fSummaryHeight;
                    this.Start_Recalculate(fWidth, fHigh);
                    ++nItCount;
                }
                var fNeedHeight = fHigh;
                if(this.Get_ColumnsCount() > 1){
                    while((fHigh - fLow) > 0.1){
                        var fCheckHeight = fLow +  (fHigh - fLow)/2;
                        this.Start_Recalculate(fWidth, fCheckHeight);
                        if(this.Pages.length > 1){
                            fLow = fCheckHeight;
                        }
                        else{
                            fHigh = fCheckHeight;
                            fNeedHeight = fCheckHeight;
                        }
                    }
                }
                this.Start_Recalculate(fWidth, fNeedHeight + 0.01);
            }
        }
    };

    CDrawingDocContent.prototype.Start_Recalculate = function(fWidth, fHeight){
        this.FullRecalc.PageIndex         = 0;
        this.FullRecalc.SectionIndex      = 0;
        this.FullRecalc.ColumnIndex       = 0;
        this.FullRecalc.StartIndex        = 0;
        this.FullRecalc.Start             = true;
        this.FullRecalc.StartPage         = 0;
        this.Reset(0, 0, fWidth, fHeight);
        this.Recalculate_PageDrawing();
    };

    CDrawingDocContent.prototype.Recalculate_PageDrawing   = function()
    {
        var nColumnsCount = this.Get_ColumnsCount();
        var nPageIndex = this.FullRecalc.PageIndex;
        this.Pages.length = nPageIndex + 1;
        if(0 === this.FullRecalc.ColumnIndex && true === this.FullRecalc.Start)
        {
            var oPage      = new CDocumentPage();
            oPage.Pos = this.FullRecalc.StartIndex;
            oPage.Sections[0] = new CDocumentPageSection();
            for (var i = 0; i < nColumnsCount; ++i)
            {
                oPage.Sections[0].Columns[i] = new CDocumentPageColumn();
            }
            this.Pages[nPageIndex] = oPage;
        }
        this.Recalculate_PageColumn();
    };

    CDrawingDocContent.prototype.Recalculate_PageColumn = function()
    {
        var nPageIndex          = this.FullRecalc.PageIndex;
        var nColumnIndex        = this.FullRecalc.ColumnIndex;
        var nStartIndex         = this.FullRecalc.StartIndex;

        var oStartPos = this.Get_PageContentStartPos3(nColumnIndex);
        var X = oStartPos.X;
        var Y = oStartPos.Y;
        var XLimit = oStartPos.XLimit;
        var YLimit = oStartPos.YLimit;

        var nColumnsCount = this.Get_ColumnsCount();

        var aContent = this.Content;
        var nCount = aContent.length;
        var nRecalcResult = recalcresult_NextPage;
        var oParagraph;
        var bContinue = false;

        var oPage = this.Pages[nPageIndex];
        var oSection = oPage.Sections[0];
        var oColumn = oSection.Columns[nColumnIndex];
        oColumn.X           = X;
        oColumn.XLimit      = XLimit;
        oColumn.Y           = Y;
        oColumn.YLimit      = YLimit;
        oColumn.Pos         = nStartIndex;
        oColumn.Empty       = false;
        oColumn.SpaceBefore = oStartPos.ColumnSpaceBefore;
        oColumn.SpaceAfter  = oStartPos.ColumnSpaceAfter;
        for(var i = nStartIndex; i < nCount; ++i)
        {
            oParagraph = this.Content[i];

            if((0 === i && 0 === nPageIndex && 0 === nColumnIndex) || i != nStartIndex || (i === nStartIndex && true === this.FullRecalc.ResetStartElement))
            {
                oParagraph.Set_DocumentIndex(i);
                oParagraph.Reset(X, Y, XLimit, YLimit, nPageIndex, nColumnIndex, nColumnsCount);
            }
            var nElementPageIndex = this.private_GetElementPageIndex(i, nPageIndex, nColumnIndex, nColumnsCount);
            nRecalcResult = oParagraph.Recalculate_Page(nElementPageIndex);
            if(nRecalcResult & recalcresult_NextElement)
            {
                Y = oParagraph.Get_PageBounds(nElementPageIndex).Bottom;
            }
            oColumn.Bounds.Bottom = Y;
            if (nRecalcResult & recalcresult_CurPage)
            {
                if (nRecalcResult & recalcresultflags_Column)
                {
                    this.FullRecalc.ColumnIndex = nColumnIndex;
                }
                else
                {
                    this.FullRecalc.ColumnIndex = 0;
                }
                bContinue = true;
                break;
            }
            else if(nRecalcResult & recalcresult_NextPage)
            {
                if (nRecalcResult & recalcresultflags_LastFromNewColumn)
                {
                    oColumn.EndPos  = i - 1;
                    oSection.EndPos = i - 1;
                    oPage.EndPos    = i - 1;
                    bContinue       = true;
                    this.FullRecalc.ColumnIndex = nColumnIndex + 1;
                    this.FullRecalc.PageIndex   = nPageIndex;
                    this.FullRecalc.StartIndex  = i;
                    this.FullRecalc.Start       = true;
                    if (this.FullRecalc.ColumnIndex >= nColumnsCount)
                    {
                        this.FullRecalc.ColumnIndex = 0;
                        this.FullRecalc.PageIndex   = nPageIndex + 1;
                    }
                    break;
                }
                else if (nRecalcResult & recalcresultflags_LastFromNewPage)
                {
                    oColumn.EndPos  = i - 1;
                    oSection.EndPos = i - 1;
                    oPage.EndPos    = i - 1;
                    bContinue = true;
                    this.FullRecalc.SectionIndex = 0;
                    this.FullRecalc.ColumnIndex  = 0;
                    this.FullRecalc.PageIndex    = nPageIndex + 1;
                    this.FullRecalc.StartIndex   = i;
                    this.FullRecalc.Start        = true;
                    if (oColumn.EndPos === oColumn.Pos)
                    {
                        var Element          = this.Content[oColumn.Pos];
                        var ElementPageIndex = this.private_GetElementPageIndex(i, nPageIndex, nColumnIndex, nColumnsCount);
                        if (true === Element.IsEmptyPage(ElementPageIndex))
                            oColumn.Empty = true;
                    }
                    for (var TempColumnIndex = nColumnIndex + 1; TempColumnIndex < nColumnsCount; ++TempColumnIndex)
                    {
                        oSection.Columns[TempColumnIndex].Empty  = true;
                        oSection.Columns[TempColumnIndex].Pos    = i;
                        oSection.Columns[TempColumnIndex].EndPos = i - 1;
                    }
                    break;
                }
                else if (nRecalcResult & recalcresultflags_Page)
                {
                    oColumn.EndPos  = i;
                    oSection.EndPos = i;
                    oPage.EndPos    = i;

                    bContinue = true;

                    this.FullRecalc.SectionIndex = 0;
                    this.FullRecalc.ColumnIndex  = 0;
                    this.FullRecalc.PageIndex    = nPageIndex + 1;
                    this.FullRecalc.StartIndex   = i;
                    this.FullRecalc.Start       = true;

                    if (oColumn.EndPos === oColumn.Pos)
                    {
                        var Element          = this.Content[oColumn.Pos];
                        var ElementPageIndex = this.private_GetElementPageIndex(i, nPageIndex, nColumnIndex, nColumnsCount);
                        if (true === Element.IsEmptyPage(nElementPageIndex))
                            oColumn.Empty = true;
                    }
                    for (var TempColumnIndex = nColumnIndex + 1; TempColumnIndex < nColumnsCount; ++TempColumnIndex)
                    {
                        var ElementPageIndex = this.private_GetElementPageIndex(i, nPageIndex, TempColumnIndex, nColumnsCount);
                        this.Content[i].Recalculate_SkipPage(ElementPageIndex);
                        oSection.Columns[TempColumnIndex].Empty  = true;
                        oSection.Columns[TempColumnIndex].Pos    = i;
                        oSection.Columns[TempColumnIndex].EndPos = i - 1;
                    }
                    break;
                }
                else
                {
                    oColumn.EndPos  = i;
                    oSection.EndPos = i;
                    oPage.EndPos    = i;

                    bContinue = true;

                    this.FullRecalc.ColumnIndex = nColumnIndex + 1;
                    if (this.FullRecalc.ColumnIndex >= nColumnsCount)
                    {
                        this.FullRecalc.SectionIndex = 0;
                        this.FullRecalc.ColumnIndex  = 0;
                        this.FullRecalc.PageIndex    = nPageIndex + 1;
                    }

                    this.FullRecalc.StartIndex = i;
                    this.FullRecalc.Start     = true;

                    if (oColumn.EndPos === oColumn.Pos)
                    {
                        var Element          = this.Content[oColumn.Pos];
                        var ElementPageIndex = this.private_GetElementPageIndex(i, nPageIndex, nColumnIndex, nColumnsCount);
                        if (true === Element.IsEmptyPage(ElementPageIndex))
                            oColumn.Empty = true;
                    }

                    break;
                }
            }
        }
        if (i === nCount)
        {
            oPage.EndPos    = nCount - 1;
            oSection.EndPos = nCount - 1;
            oColumn.EndPos  = nCount  - 1;
        }
        if(bContinue)
        {
            this.Recalculate_PageDrawing();
        }
    };

    CDrawingDocContent.prototype.Draw = function(nPageIndex, pGraphics){
        if(this.Pages.length > 0){

            var oSection = this.Pages[0].Sections[0];
            if(oSection){

                if (pGraphics.Start_Command)
                {
                    pGraphics.Start_Command(AscFormat.DRAW_COMMAND_CONTENT);
                }

                for (var ColumnIndex = 0, ColumnsCount = oSection.Columns.length; ColumnIndex < ColumnsCount; ++ColumnIndex)
                {
                    var Column         = oSection.Columns[ColumnIndex];
                    var ColumnStartPos = Column.Pos;
                    var ColumnEndPos   = Column.EndPos;

                    // Плавающие объекты не должны попадать в клип колонок
                    var FlowElements = [];

                    if (ColumnsCount > 1)
                    {
                        //    pGraphics.SaveGrState();

                        var X    = ColumnIndex === 0 ? 0 : Column.X - Column.SpaceBefore / 2;
                        // var XEnd = (ColumnIndex >= ColumnsCount - 1 ? Page.Width : Column.XLimit + Column.SpaceAfter / 2);
                        //  pGraphics.AddClipRect(X, 0, XEnd - X, Page.Height);
                    }

                    for (var ContentPos = ColumnStartPos; ContentPos <= ColumnEndPos; ++ContentPos)
                    {
                        var ElementPageIndex = this.private_GetElementPageIndex(ContentPos, 0, ColumnIndex, ColumnsCount);
                        this.Content[ContentPos].Draw(ElementPageIndex, pGraphics);
                    }

                    /*if (ColumnsCount > 1)
                     {
                     pGraphics.RestoreGrState();
                     }*/
                }

                if (pGraphics.End_Command)
                {
                    pGraphics.End_Command();
                }
            }

            else{
                CDocumentContent.prototype.Draw.call(this, nPageIndex, pGraphics);
            }
        }
    };

    CDrawingDocContent.prototype.Write_ToBinary2 = function(oWriter){
        oWriter.WriteLong(AscDFH.historyitem_type_DrawingContent);
        CDocumentContent.prototype.Write_ToBinary2.call(this, oWriter);
    };
    CDrawingDocContent.prototype.Read_FromBinary2 = function(oReader){
        oReader.GetLong();//type of DocumentContent
        CDocumentContent.prototype.Read_FromBinary2.call(this, oReader);
    };
    CDrawingDocContent.prototype.IsTableCellContent = function(isReturnCell){

    	if (true === isReturnCell)
    		return null;

        return false;
    };

    CDrawingDocContent.prototype.Is_ChartTitleContent = function(){
        if(this.Parent instanceof AscFormat.CTextBody &&
        this.Parent.parent instanceof AscFormat.CTitle){
            return true;
        }
        return false;
    };

    CDrawingDocContent.prototype.DrawSelectionOnPage = function(PageIndex){
        var CurPage = PageIndex;
        if (CurPage < 0 || CurPage >= this.Pages.length)
            return;
        var Pos_start = this.Pages[CurPage].Pos;
        var Pos_end   = this.Pages[CurPage].EndPos;

        if (true === this.Selection.Use)
        {
            if(this.Selection.Flag === selectionflag_Common)
            {
                var Start = this.Selection.StartPos;
                var End   = this.Selection.EndPos;

                if (Start > End)
                {
                    Start = this.Selection.EndPos;
                    End   = this.Selection.StartPos;
                }

                var Start = Math.max(Start, Pos_start);
                var End   = Math.min(End, Pos_end);

                var Page = this.Pages[PageIndex];
                if(this.Pages[PageIndex].Sections.length === 0){
                    for (var Index = Start; Index <= End; Index++)
                    {
                        var ElementPageIndex = this.private_GetElementPageIndex(Index, CurPage, 0, 1);
                        this.Content[Index].DrawSelectionOnPage(ElementPageIndex);
                    }
                }
                else{
                    var PageSection = Page.Sections[0];
                    for (var ColumnIndex = 0, ColumnsCount = PageSection.Columns.length; ColumnIndex < ColumnsCount; ++ColumnIndex)
                    {
                        var Pos_start = Page.Pos;
                        var Pos_end   = Page.EndPos;

                        var Start = this.Selection.StartPos;
                        var End   = this.Selection.EndPos;

                        if (Start > End)
                        {
                            Start = this.Selection.EndPos;
                            End   = this.Selection.StartPos;
                        }

                        var Start = Math.max(Start, Pos_start);
                        var End   = Math.min(End, Pos_end);

                        for (var Index = Start; Index <= End; ++Index)
                        {
                            var ElementPage = this.private_GetElementPageIndex(Index, 0, ColumnIndex, ColumnsCount);
                            this.Content[Index].DrawSelectionOnPage(ElementPage);
                        }

                    }
                }

            }
        }
    };

    CDrawingDocContent.prototype.Internal_GetContentPosByXY = function(X, Y, PageNum, ColumnsInfo)
    {
        if (!ColumnsInfo)
            ColumnsInfo = {Column : 0, ColumnsCount : 1};

        if (undefined === PageNum || null === PageNum)
            PageNum = this.CurPage;
        // Теперь проверим пустые параграфы с окончанием секций
        var SectCount = this.Pages[PageNum].EndSectionParas.length;
        if(this.Pages[PageNum].Sections.length === 0){
            return CDocumentContent.prototype.Internal_GetContentPosByXY.call(this, X, Y, PageNum, ColumnsInfo);
        }
        for (var Index = 0; Index < SectCount; ++Index)
        {
            var Item   = this.Pages[PageNum].EndSectionParas[Index];
            var Bounds = Item.Pages[0].Bounds;

            if (Y < Bounds.Bottom && Y > Bounds.Top && X > Bounds.Left && X < Bounds.Right)
            {
                var Element              = this.Content[Item.Index];
                ColumnsInfo.Column       = Element.Get_StartColumn();
                ColumnsInfo.ColumnsCount = Element.Get_ColumnsCount();
                return Item.Index;
            }
        }

        // Сначала мы определим секцию и колонку, в которую попали
        var Page = this.Pages[PageNum];

        var SectionIndex = 0;
        for (var SectionsCount = Page.Sections.length; SectionIndex < SectionsCount - 1; ++SectionIndex)
        {
            if (Y < Page.Sections[SectionIndex + 1].Y)
                break;
        }

        var PageSection  = this.Pages[PageNum].Sections[SectionIndex];
        var ColumnsCount = PageSection.Columns.length;
        var ColumnIndex  = 0;
        for (; ColumnIndex < ColumnsCount - 1; ++ColumnIndex)
        {
            if (X < (PageSection.Columns[ColumnIndex].XLimit + PageSection.Columns[ColumnIndex + 1].X) / 2)
                break;
        }

        // TODO: Разобраться с ситуацией, когда пустые колонки стоят не только в конце
        while (ColumnIndex > 0 && true === PageSection.Columns[ColumnIndex].Empty)
            ColumnIndex--;

        ColumnsInfo.Column       = ColumnIndex;
        ColumnsInfo.ColumnsCount = ColumnsCount;

        var Column   = PageSection.Columns[ColumnIndex];
        var StartPos = Column.Pos;
        var EndPos   = Column.EndPos;

        for (var Pos = StartPos; Pos < EndPos; ++Pos)
        {
            var Item = this.Content[Pos + 1];
            var PageBounds = Item.Get_PageBounds(0);
            if (Y < PageBounds.Top)
                return Pos;
        }

        if (Pos === EndPos)
        {
            return EndPos;
        }
        return 0;
    };

    CDrawingDocContent.prototype.private_GetElementPageIndexByXY = function(ElementPos, X, Y, PageIndex){
        if(this.Pages.length > 0){
            if(this.Pages[0].Sections.length > 0){
                return CDocument_prototype_private_GetElementPageIndexByXY.call(this, ElementPos, X, Y, PageIndex);
            }
        }
        return CDocumentContent.prototype.private_GetElementPageIndexByXY.call(this, ElementPos, X, Y, PageIndex);
    };
    CDrawingDocContent.prototype.Copy            = function(Parent, DrawingDocument)
    {
        var DC = new CDrawingDocContent(Parent, DrawingDocument ? DrawingDocument : this.DrawingDocument, 0, 0, 0, 0, this.Split, this.TurnOffInnerWrap, this.bPresentation);

        // Копируем содержимое
        DC.Internal_Content_RemoveAll();

        var Count = this.Content.length;
        for (var Index = 0; Index < Count; Index++)
        {
            DC.Internal_Content_Add(Index, this.Content[Index].Copy(DC, DrawingDocument, {}), false);
        }

        return DC;
    };
    CDrawingDocContent.prototype.Copy3           = function(Parent)//для заголовков диаграмм
    {
        var DC = new CDrawingDocContent(Parent, this.DrawingDocument, 0, 0, 0, 0, this.Split, this.TurnOffInnerWrap, true);

        // Копируем содержимое
        DC.Internal_Content_RemoveAll();

        var Count = this.Content.length;
        for (var Index = 0; Index < Count; Index++)
        {
            DC.Internal_Content_Add(Index, this.Content[Index].Copy2(DC), false);
        }
        return DC;
    };

    CDrawingDocContent.prototype.Recalculate = function()
    {

        if(typeof editor !== "undefined" && editor &&
            (editor.isPresentationEditor || editor.isDocumentEditor)){
               if(editor.WordControl && editor.WordControl.m_oLogicDocument){
                   editor.WordControl.m_oLogicDocument.Recalculate();
               }
        }
        else{
            if(this.Parent){
                if(this.Parent instanceof AscFormat.CShape){
                    this.Parent.recalculateContent();
                    return;
                }
                else if(this.Parent && this.Parent.parent){
                    if(this.Parent.parent instanceof AscFormat.CShape){
                        this.Parent.parent.recalculateContent();
                        return;
                    }
                }
            }
            if(this.XLimit > 0){
                this.Recalculate_PageDrawing();
            }
        }
    };


    CDrawingDocContent.prototype.ClearParagraphFormatting = function(isClearParaPr, isClearTextPr)
    {
        if (true === this.ApplyToAll)
        {
            for (var Index = 0; Index < this.Content.length; Index++)
            {
                var Item = this.Content[Index];
                Item.Set_ApplyToAll(true);
                Item.ClearParagraphFormatting(isClearParaPr, isClearTextPr);
                Item.Set_ApplyToAll(false);
            }

            return;
        }

        if (docpostype_DrawingObjects == this.CurPos.Type)
        {
            return this.LogicDocument.DrawingObjects.paragraphClearFormatting(isClearParaPr, isClearTextPr);
        }
        else //if ( docpostype_Content === this.CurPos.Type )
        {
            if (true === this.Selection.Use)
            {
                if (selectionflag_Common === this.Selection.Flag)
                {
                    var StartPos = this.Selection.StartPos;
                    var EndPos   = this.Selection.EndPos;
                    if (StartPos > EndPos)
                    {
                        var Temp = StartPos;
                        StartPos = EndPos;
                        EndPos   = Temp;
                    }

                    for (var Index = StartPos; Index <= EndPos; Index++)
                    {
                        var Item = this.Content[Index];
                        Item.ClearParagraphFormatting(isClearParaPr, isClearTextPr);
                    }
                }
            }
            else
            {
                var Item = this.Content[this.CurPos.ContentPos];
                Item.ClearParagraphFormatting(isClearParaPr, isClearTextPr);
            }
        }
    };
    // TODO: сделать по-нормальному!!!
    function CDocument_prototype_private_GetElementPageIndexByXY(ElementPos, X, Y, PageIndex)
    {
        var Element = this.Content[ElementPos];
    	if (!Element)
    		return 0;

    	var Page = this.Pages[PageIndex];
    	if (!Page)
    		return 0;

    	var PageSection = null;
    	for (var SectionIndex = 0, SectionsCount = Page.Sections.length; SectionIndex < SectionsCount; ++SectionIndex)
    	{
    		if (Page.Sections[SectionIndex].Pos <= ElementPos && ElementPos <= Page.Sections[SectionIndex].EndPos)
    		{
    			PageSection = Page.Sections[SectionIndex];
    			break;
    		}
    	}

    	if (!PageSection)
    		return 0;

    	var ElementStartPage   = Element.Get_StartPage_Relative();
    	var ElementStartColumn = Element.Get_StartColumn();
    	var ElementPagesCount  = Element.Get_PagesCount();

    	var ColumnsCount = PageSection.Columns.length;
    	var StartColumn  = 0;
    	var EndColumn    = ColumnsCount - 1;

    	if (PageIndex === ElementStartPage)
    	{
    		StartColumn = Element.Get_StartColumn();
    		EndColumn   = Math.min(ElementStartColumn + ElementPagesCount - 1, ColumnsCount - 1);
    	}
    	else
    	{
    		StartColumn = 0;
    		EndColumn   = Math.min(ElementPagesCount - ElementStartColumn + (PageIndex - ElementStartPage) * ColumnsCount, ColumnsCount - 1);
    	}

    	// TODO: Разобраться с ситуацией, когда пустые колонки стоят не только в конце
    	while (true === PageSection.Columns[EndColumn].Empty && EndColumn > StartColumn)
    		EndColumn--;

    	var ResultColumn = EndColumn;
    	for (var ColumnIndex = StartColumn; ColumnIndex < EndColumn; ++ColumnIndex)
    	{
    		if (X < (PageSection.Columns[ColumnIndex].XLimit + PageSection.Columns[ColumnIndex + 1].X) / 2)
    		{
    			ResultColumn = ColumnIndex;
    			break;
    		}
    	}

    	return this.private_GetElementPageIndex(ElementPos, PageIndex, ResultColumn, ColumnsCount);
    }

    AscFormat.CDrawingDocContent = CDrawingDocContent;
})(window);
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

(function(window, undefined)
{

	function CPluginData()
	{
		this.privateData = {};
	}

	CPluginData.prototype =
	{
		setAttribute : function(name, value)
		{
			this.privateData[name] = value;
		},

		getAttribute : function(name)
		{
			return this.privateData[name];
		},

		serialize : function()
		{
			var _data = "";
			try
			{
				_data = JSON.stringify(this.privateData);
			}
			catch (err)
			{
				_data = "{ \"data\" : \"\" }";
			}
			return _data;
		},

		deserialize : function(_data)
		{
			try
			{
				this.privateData = JSON.parse(_data);
			}
			catch (err)
			{
				this.privateData = {"data" : ""};
			}
		}
	};

	function CPluginsManager(api)
	{
		this.plugins          = [];
		this.systemPlugins	  = [];

		this.runnedPluginsMap = {}; // guid => { iframeId: "", currentVariation: 0, currentInit: false, isSystem: false, startData: {}, closeAttackTimer: -1, methodReturnAsync: false }
		this.pluginsMap = {};		// guid => { isSystem: false }

		this.path             = "../../../../sdkjs-plugins/";
		this.systemPath 	  = "";
		this.api              = api;
		this["api"]			  = this.api;

		this.runAndCloseData = null;

		this.isNoSystemPluginsOnlyOne = true;

		this.guidAsyncMethod = "";

		this.sendsToInterface = {};

		this.sendEncryptionDataCounter = 0;

		if (this.api.isCheckCryptoReporter)
			this.checkCryptoReporter();
	}

	CPluginsManager.prototype =
	{
		unregisterAll : function()
		{
			// удаляем все, кроме запущенного
			var i = 0;
			for (i = 0; i < this.plugins.length; i++)
			{
				if (!this.runnedPluginsMap[this.plugins[i].guid])
				{
					delete this.pluginsMap[this.plugins[i].guid];
					this.plugins.splice(i, 1);
					i--;
				}
			}
		},

		register : function(basePath, plugins)
		{
			this.path = basePath;

			for (var i = 0; i < plugins.length; i++)
			{
				var guid = plugins[i].guid;
				if (this.runnedPluginsMap[guid])
				{
					// не меняем запущенный
					continue;
				}
				else if (this.pluginsMap[guid])
				{
					// заменяем новым
					for (var j = 0; j < this.plugins.length; j++)
					{
						if (this.plugins[j].guid == guid)
						{
							this.plugins[j] = plugins[i];
							break;
						}
					}
				}
				else
				{
					this.plugins.push(plugins[i]);
					this.pluginsMap[guid] = { isSystem : false };
				}
			}
		},
		registerSystem : function(basePath, plugins)
		{
			this.systemPath = basePath;

			for (var i = 0; i < plugins.length; i++)
			{
				var guid = plugins[i].guid;

				// системные не обновляем
				if (this.pluginsMap[guid])
				{
					continue;
				}

				this.systemPlugins.push(plugins[i]);
				this.pluginsMap[guid] = { isSystem : true };
			}
		},
		runAllSystem : function()
		{
			for (var i = 0; i < this.systemPlugins.length; i++)
			{
				this.run(this.systemPlugins[i].guid, 0, "");
			}
		},
		// pointer events methods -------------------
		enablePointerEvents : function()
		{
			for (var guid in this.runnedPluginsMap)
			{
				var _frame = document.getElementById(this.runnedPluginsMap[guid].frameId);
				if (_frame)
					_frame.style.pointerEvents = "";
			}
		},
		disablePointerEvents : function()
		{
			for (var guid in this.runnedPluginsMap)
			{
				var _frame = document.getElementById(this.runnedPluginsMap[guid].frameId);
				if (_frame)
					_frame.style.pointerEvents = "none";
			}
		},
		// ------------------------------------------
		checkRunnedFrameId : function(id)
		{
			for (var guid in this.runnedPluginsMap)
			{
				if (this.runnedPluginsMap[guid].frameId == id)
					return true;
			}
			return false;
		},
		sendToAllPlugins : function(data)
		{
			for (var guid in this.runnedPluginsMap)
			{
				var _frame = document.getElementById(this.runnedPluginsMap[guid].frameId);
				if (_frame)
					_frame.contentWindow.postMessage(data, "*");
			}
		},
		getPluginByGuid : function(guid)
		{
			if (undefined === this.pluginsMap[guid])
				return null;

			var _array = (this.pluginsMap[guid].isSystem) ? this.systemPlugins : this.plugins;
			for (var i = _array.length - 1; i >= 0; i--)
			{
				if (_array[i].guid == guid)
					return _array[i];
			}
			return null;
		},
		isWorked : function()
		{
			for (var i in this.runnedPluginsMap)
			{
				if (this.pluginsMap[i] && !this.pluginsMap[i].isSystem)
				{
					return true;
				}
			}
			return false;
		},
		stopWorked : function()
		{
		   for (var i in this.runnedPluginsMap)
		   {
			   if (this.pluginsMap[i] && !this.pluginsMap[i].isSystem)
			   {
					this.close(i);
			   }
		   }
		},
		isRunned : function(guid)
		{
			return (undefined !== this.runnedPluginsMap[guid]);
		},
		run : function(guid, variation, data, isNoUse_isNoSystemPluginsOnlyOne)
		{
			if (this.runAndCloseData) // run only on close!!!
				return;

			if (this.pluginsMap[guid] === undefined)
				return;

			var plugin = this.getPluginByGuid(guid);
			if (!plugin)
				return;

			var isSystem = this.pluginsMap[guid].isSystem;
			var isRunned = (this.runnedPluginsMap[guid] !== undefined) ? true : false;

			if (isRunned && ((variation == null) || variation == this.runnedPluginsMap[guid].currentVariation))
			{
				// запуск запущенного => закрытие
				this.close(guid);
				return false;
			}

			if ((isNoUse_isNoSystemPluginsOnlyOne !== true) && !isSystem && this.isNoSystemPluginsOnlyOne)
			{
				// смотрим, есть ли запущенный несистемный плагин
				var guidOther = "";
				for (var i in this.runnedPluginsMap)
				{
					if (this.pluginsMap[i] && !this.pluginsMap[i].isSystem)
					{
						guidOther = i;
						break;
					}
				}

				if (guidOther != "")
				{
					// стопим текущий, а после закрытия - стартуем новый.
					this.runAndCloseData = {};
					this.runAndCloseData.guid = guid;
					this.runAndCloseData.variation = variation;
					this.runAndCloseData.data = data;

					this.close(guidOther);
					return;
				}
			}

			var _startData = (data == null || data == "") ? new CPluginData() : data;
			_startData.setAttribute("guid", guid);
			this.correctData(_startData);

			this.runnedPluginsMap[guid] = {
				frameId: "iframe_" + guid,
				currentVariation: Math.min(variation, plugin.variations.length - 1),
				currentInit: false,
				isSystem: isSystem,
				startData: _startData,
				closeAttackTimer: -1,
				methodReturnAsync: false
			};

			this.show(guid);
		},
		runResize : function(data)
		{
			var guid = data.getAttribute("guid");
			var plugin = this.getPluginByGuid(guid);

			if (!plugin)
				return;

			if (true !== plugin.variations[0].isUpdateOleOnResize)
				return;

			data.setAttribute("resize", true);
			return this.run(guid, 0, data, true);
		},
		close : function(guid)
		{
			var plugin = this.getPluginByGuid(guid);
			var runObject = this.runnedPluginsMap[guid];
			if (!plugin || !runObject)
				return;

			if (runObject.startData && runObject.startData.getAttribute("resize") === true)
				this.endLongAction();

			runObject.startData = null;

			if (true)
			{
				if (this.sendsToInterface[plugin.guid])
				{
					this.api.sendEvent("asc_onPluginClose", plugin, runObject.currentVariation);
					delete this.sendsToInterface[plugin.guid];
				}
				var _div = document.getElementById(runObject.frameId);
				if (_div)
					_div.parentNode.removeChild(_div);
			}

			delete this.runnedPluginsMap[guid];

			if (this.runAndCloseData)
			{
				var _tmp = this.runAndCloseData;
				this.runAndCloseData = null;
				this.run(_tmp.guid, _tmp.variation, _tmp.data);
			}
		},

		show : function(guid)
		{
			var plugin = this.getPluginByGuid(guid);
			var runObject = this.runnedPluginsMap[guid];

			if (!plugin || !runObject)
				return;

			if (runObject.startData.getAttribute("resize") === true)
				this.startLongAction();

		    if (this.api.WordControl && this.api.WordControl.m_oTimerScrollSelect != -1)
		    {
		        clearInterval(this.api.WordControl.m_oTimerScrollSelect);
                this.api.WordControl.m_oTimerScrollSelect = -1;
		    }

			if (plugin.variations[runObject.currentVariation].isVisual && runObject.startData.getAttribute("resize") !== true)
			{
				this.api.sendEvent("asc_onPluginShow", plugin, runObject.currentVariation, runObject.frameId);
				this.sendsToInterface[plugin.guid] = true;
			}
			else
			{
				var ifr            = document.createElement("iframe");
				ifr.name           = runObject.frameId;
				ifr.id             = runObject.frameId;
				var _add           = plugin.baseUrl == "" ? this.path : plugin.baseUrl;
				ifr.src            = _add + plugin.variations[runObject.currentVariation].url;
				ifr.style.position = AscCommon.AscBrowser.isIE ? 'fixed' : "absolute";
				ifr.style.top      = '-100px';
				ifr.style.left     = '0px';
				ifr.style.width    = '10000px';
				ifr.style.height   = '100px';
				ifr.style.overflow = 'hidden';
				ifr.style.zIndex   = -1000;
				document.body.appendChild(ifr);

				if (runObject.startData.getAttribute("resize") !== true)
				{
					this.api.sendEvent("asc_onPluginShow", plugin, runObject.currentVariation);
					this.sendsToInterface[plugin.guid] = true;
				}
			}

			runObject.currentInit = false;
		},

		buttonClick : function(id, guid)
		{
			if (guid === undefined)
			{
				// old version support
				for (var i in this.runnedPluginsMap)
				{
					if (this.runnedPluginsMap[i].isSystem)
						continue;
					
					if (this.pluginsMap[i])
					{
						guid = i;
						break;
					}
				}
			}

			if (undefined === guid)
				return;

			var plugin = this.getPluginByGuid(guid);
			var runObject = this.runnedPluginsMap[guid];

			if (!plugin || !runObject)
				return;

			if (runObject.closeAttackTimer != -1)
			{
				clearTimeout(runObject.closeAttackTimer);
				runObject.closeAttackTimer = -1;
			}

			if (-1 == id)
			{
				if (!runObject.currentInit)
				{
					this.close(guid);
				}

				// защита от плохого плагина
				runObject.closeAttackTimer = setTimeout(function()
				{
					window.g_asc_plugins.close();
				}, 5000);
			}
			var _iframe = document.getElementById(runObject.frameId);
			if (_iframe)
			{
				var pluginData = new CPluginData();
				pluginData.setAttribute("guid", plugin.guid);
				pluginData.setAttribute("type", "button");
				pluginData.setAttribute("button", "" + id);
				_iframe.contentWindow.postMessage(pluginData.serialize(), "*");
			}
		},

		init : function(guid, raw_data)
		{
			var plugin = this.getPluginByGuid(guid);
			var runObject = this.runnedPluginsMap[guid];

			if (!plugin || !runObject || !runObject.startData)
				return;

			if (undefined === raw_data)
			{
				switch (plugin.variations[runObject.currentVariation].initDataType)
				{
					case Asc.EPluginDataType.text:
					{
						var text_data = {
							data:     "",
							pushData: function (format, value)
									  {
										  this.data = value;
									  }
						};

						this.api.asc_CheckCopy(text_data, 1);
						if (text_data.data == null)
							text_data.data = "";
						runObject.startData.setAttribute("data", text_data.data);
						break;
					}
					case Asc.EPluginDataType.html:
					{
						var text_data = {
							data:     "",
							pushData: function (format, value)
									  {
										  this.data = value;
									  }
						};

						this.api.asc_CheckCopy(text_data, 2);
						if (text_data.data == null)
							text_data.data = "";
						runObject.startData.setAttribute("data", text_data.data);
						break;
					}
					case Asc.EPluginDataType.ole:
					{
						// теперь выше задается
						break;
					}
					case Asc.EPluginDataType.desktop:
					{
						if (plugin.variations[runObject.currentVariation].initData == "encryption")
						{
							if (this.api.isReporterMode)
							{
                                this.sendEncryptionDataCounter++;
                                if (2 <= this.sendEncryptionDataCounter)
                                {
                                    runObject.startData.setAttribute("data", {
                                        "type": "setPassword",
                                        "password": this.api.currentPassword,
                                        "hash": this.api.currentDocumentHash,
                                        "docinfo": this.api.currentDocumentInfo
                                    });
                                }
                            }

                            // for crypt mode (end waiting all system plugins)
                            if (this.api.asc_initAdvancedOptions_params)
                            {
                            	window["asc_initAdvancedOptions"].apply(window, this.api.asc_initAdvancedOptions_params);
                                delete this.api.asc_initAdvancedOptions_params;
                                // already sended in asc_initAdvancedOptions
                                return;
                            }
						}
						break;
					}
				}
			}
			else
			{
				runObject.startData.setAttribute("data", raw_data);
			}

			var _iframe = document.getElementById(runObject.frameId);
			if (_iframe)
			{
				runObject.startData.setAttribute("type", "init");
				_iframe.contentWindow.postMessage(runObject.startData.serialize(), "*");
			}

			runObject.currentInit = true;
		},
		correctData : function(pluginData)
		{
			pluginData.setAttribute("editorType", this.api._editorNameById());

			var _mmToPx = AscCommon.g_dKoef_mm_to_pix;
			if (this.api.WordControl && this.api.WordControl.m_nZoomValue)
				_mmToPx *= this.api.WordControl.m_nZoomValue / 100;

			pluginData.setAttribute("mmToPx", _mmToPx);

			if (undefined == pluginData.getAttribute("data"))
				pluginData.setAttribute("data", "");
		},
		loadExtensionPlugins : function(_plugins)
		{
			if (!_plugins || _plugins.length < 1)
				return;

			var _map = {};
			for (var i = 0; i < this.plugins.length; i++)
				_map[this.plugins[i].guid] = true;

			var _new = [];
			for (var i = 0; i < _plugins.length; i++)
			{
				var _p = new Asc.CPlugin();
				_p["deserialize"](_plugins[i]);

				if (_map[_p.guid] === true)
					continue;

				_new.push(_p);
			}

			this.register(this.path, _new);

			var _pluginsInstall = {"url" : this.path, "pluginsData" : []};
			for (var i = 0; i < this.plugins.length; i++)
			{
				_pluginsInstall["pluginsData"].push(this.plugins[i].serialize());
			}

			this.api.sendEvent("asc_onPluginsInit", _pluginsInstall);
		},

		startLongAction : function()
		{
			//console.log("startLongAction");
			this.api.sync_StartAction(Asc.c_oAscAsyncActionType.BlockInteraction, Asc.c_oAscAsyncAction.SlowOperation);
		},
		endLongAction   : function()
		{
			//console.log("endLongAction");
			this.api.sync_EndAction(Asc.c_oAscAsyncActionType.BlockInteraction, Asc.c_oAscAsyncAction.SlowOperation);
		},

		onChangedSelectionData : function()
		{
			for (var guid in this.runnedPluginsMap)
			{
				var plugin = this.getPluginByGuid(guid);
				var runObject = this.runnedPluginsMap[guid];

				if (plugin && plugin.variations[runObject.currentVariation].initOnSelectionChanged === true)
				{
					// re-init
					this.init(guid);
				}
			}
		},

        onPluginEvent : function(name, data)
        {
            for (var guid in this.runnedPluginsMap)
            {
                var plugin = this.getPluginByGuid(guid);
                var runObject = this.runnedPluginsMap[guid];

                if (plugin && plugin.variations[runObject.currentVariation].eventsMap[name])
                {
                    var pluginData = new CPluginData();
                    pluginData.setAttribute("guid", plugin.guid);
                    pluginData.setAttribute("type", "onEvent");
                    pluginData.setAttribute("eventName", name);
                    pluginData.setAttribute("eventData", data);
                    var _iframe = document.getElementById(runObject.frameId);
                    if (_iframe)
                        _iframe.contentWindow.postMessage(pluginData.serialize(), "*");
                }
            }
        },

		onExternalMouseUp : function()
		{
			for (var guid in this.runnedPluginsMap)
			{
				var runObject = this.runnedPluginsMap[guid];
				runObject.startData.setAttribute("type", "onExternalMouseUp");
				this.correctData(runObject.startData);

				var _iframe = document.getElementById(runObject.frameId);
				if (_iframe)
				{
					runObject.startData.setAttribute("guid", guid);
					_iframe.contentWindow.postMessage(runObject.startData.serialize(), "*");
				}
			}
		},

		onEnableMouseEvents : function(isEnable)
		{
			for (var guid in this.runnedPluginsMap)
			{
				var runObject = this.runnedPluginsMap[guid];

				var _pluginData = new Asc.CPluginData();
				_pluginData.setAttribute("type", "enableMouseEvent");
				_pluginData.setAttribute("isEnabled", isEnable);
				this.correctData(_pluginData);

				var _iframe = document.getElementById(runObject.frameId);
				if (_iframe)
				{
					_pluginData.setAttribute("guid", guid);
					_iframe.contentWindow.postMessage(_pluginData.serialize(), "*");
				}
			}
		},

		onPluginMethodReturn : function(guid, _return)
		{
			var plugin = this.getPluginByGuid(guid);
			var runObject = this.runnedPluginsMap[guid];

			if (!plugin || !runObject)
				return;

			var pluginData = new CPluginData();
			pluginData.setAttribute("guid", plugin.guid);
			pluginData.setAttribute("type", "onMethodReturn");
			pluginData.setAttribute("methodReturnData", _return);
			var _iframe = document.getElementById(runObject.frameId);
			if (_iframe)
				_iframe.contentWindow.postMessage(pluginData.serialize(), "*");
		},

		setPluginMethodReturnAsync : function()
		{
			if (this.runnedPluginsMap[this.guidAsyncMethod])
				this.runnedPluginsMap[this.guidAsyncMethod].methodReturnAsync = true;
			return this.guidAsyncMethod;
		},

        /* encryption methods ------------- */
        getEncryption : function()
        {
            var _count = this.plugins.length;
            var i = 0;
            for (i = 0; i < _count; i++)
            {
                var _variation = this.plugins[i].variations[0];
                if (_variation)
                {
                    if ("desktop" == _variation.initDataType && "encryption" == _variation.initData)
                        return this.plugins[i];
                }
            }

            _count = this.systemPlugins.length;
            for (i = 0; i < _count; i++)
            {
                var _variation = this.systemPlugins[i].variations[0];
                if (_variation)
                {
                    if ("desktop" == _variation.initDataType && "encryption" == _variation.initData)
                        return this.systemPlugins[i];
                }
            }

            return null;
        },
        isRunnedEncryption : function()
        {
            var _plugin = this.getEncryption();
            if (!_plugin)
            	return false;
            return this.isRunned(_plugin.guid);
        },
        sendToEncryption : function(data)
        {
            var _plugin = this.getEncryption();
            if (!_plugin)
            	return;
            this.init(_plugin.guid, data);
        },
        checkCryptoReporter : function()
        {
            this.sendEncryptionDataCounter++;
            if (2 <= this.sendEncryptionDataCounter)
            {
                this.sendToEncryption({
                    "type" : "setPassword",
                    "password" : this.api.currentPassword,
                    "hash" : this.api.currentDocumentHash,
                    "docinfo" : this.api.currentDocumentInfo
                });
            }
        }
        /* -------------------------------- */
	};

	// export
	CPluginsManager.prototype["buttonClick"] = CPluginsManager.prototype.buttonClick;

	function onMessage(event)
	{
		if (!window.g_asc_plugins)
			return;

		if (typeof(event.data) != "string")
			return;

		var pluginData = new CPluginData();
		pluginData.deserialize(event.data);

		var guid = pluginData.getAttribute("guid");
		var runObject = window.g_asc_plugins.runnedPluginsMap[guid];

		if (!runObject)
			return;

		var name  = pluginData.getAttribute("type");
		var value = pluginData.getAttribute("data");

		if ("initialize_internal" == name)
		{
			window.g_asc_plugins.init(guid);
		}
		else if ("initialize" == name)
		{
			var pluginData = new CPluginData();
			pluginData.setAttribute("guid", guid);
			pluginData.setAttribute("type", "plugin_init");
			pluginData.setAttribute("data", "!function(l,o){var c=!1;l.plugin_sendMessage=function(e){l.parent.postMessage(e,\"*\")},l.plugin_onMessage=function(e){if(l.Asc.plugin&&\"string\"==typeof e.data){var n={};try{n=JSON.parse(e.data)}catch(e){n={}}if(n.guid!=l.Asc.plugin.guid)return;var t=n.type;switch(\"init\"==t&&(l.Asc.plugin.info=n),t){case\"init\":l.Asc.plugin.executeCommand=function(e,n){l.Asc.plugin.info.type=e,l.Asc.plugin.info.data=n;var t=\"\";try{t=JSON.stringify(l.Asc.plugin.info)}catch(e){t=JSON.stringify({type:n})}l.plugin_sendMessage(t)},l.Asc.plugin.executeMethod=function(e,n,t){if(!0===l.Asc.plugin.isWaitMethod)return o===this.executeMethodStack&&(this.executeMethodStack=[]),this.executeMethodStack.push({name:e,params:n,callback:t}),!1;l.Asc.plugin.isWaitMethod=!0,l.Asc.plugin.methodCallback=t,l.Asc.plugin.info.type=\"method\",l.Asc.plugin.info.methodName=e,l.Asc.plugin.info.data=n;var i=\"\";try{i=JSON.stringify(l.Asc.plugin.info)}catch(e){i=JSON.stringify({type:data})}return l.plugin_sendMessage(i),!0},l.Asc.plugin.resizeWindow=function(e,n,t,i,a,s){o==t&&(t=0),o==i&&(i=0),o==a&&(a=0),o==s&&(s=0);var c=JSON.stringify({width:e,height:n,minw:t,minh:i,maxw:a,maxh:s});l.Asc.plugin.info.type=\"resize\",l.Asc.plugin.info.data=c;var u=\"\";try{u=JSON.stringify(l.Asc.plugin.info)}catch(e){u=JSON.stringify({type:c})}l.plugin_sendMessage(u)},l.Asc.plugin.callCommand=function(e,n,t){var i=\"var Asc = {}; Asc.scope = \"+JSON.stringify(l.Asc.scope)+\"; var scope = Asc.scope; (\"+e.toString()+\")();\",a=!0===n?\"close\":\"command\";l.Asc.plugin.info.recalculate=!1!==t,l.Asc.plugin.executeCommand(a,i)},l.Asc.plugin.callModule=function(e,n,t){var i=t,a=new XMLHttpRequest;a.open(\"GET\",e),a.onreadystatechange=function(){if(4==a.readyState&&(200==a.status||0==location.href.indexOf(\"file:\"))){var e=!0===i?\"close\":\"command\";l.Asc.plugin.info.recalculate=!0,l.Asc.plugin.executeCommand(e,a.responseText),n&&n(a.responseText)}},a.send()},l.Asc.plugin.loadModule=function(e,n){var t=new XMLHttpRequest;t.open(\"GET\",e),t.onreadystatechange=function(){4!=t.readyState||200!=t.status&&0!=location.href.indexOf(\"file:\")||n&&n(t.responseText)},t.send()},l.Asc.plugin.init(l.Asc.plugin.info.data);break;case\"button\":var i=parseInt(n.button);l.Asc.plugin.button||-1!=i?l.Asc.plugin.button(i):l.Asc.plugin.executeCommand(\"close\",\"\");break;case\"enableMouseEvent\":c=n.isEnabled,l.Asc.plugin.onEnableMouseEvent&&l.Asc.plugin.onEnableMouseEvent(c);break;case\"onExternalMouseUp\":l.Asc.plugin.onExternalMouseUp&&l.Asc.plugin.onExternalMouseUp();break;case\"onMethodReturn\":if(l.Asc.plugin.isWaitMethod=!1,l.Asc.plugin.methodCallback){var a=l.Asc.plugin.methodCallback;l.Asc.plugin.methodCallback=null,a(n.methodReturnData),a=null}else l.Asc.plugin.onMethodReturn&&l.Asc.plugin.onMethodReturn(n.methodReturnData);if(l.Asc.plugin.executeMethodStack&&0<l.Asc.plugin.executeMethodStack.length){var s=l.Asc.plugin.executeMethodStack.shift();l.Asc.plugin.executeMethod(s.name,s.params,s.callback)}break;case\"onCommandCallback\":l.Asc.plugin.onCommandCallback&&l.Asc.plugin.onCommandCallback();break;case\"onExternalPluginMessage\":l.Asc.plugin.onExternalPluginMessage&&n.data&&n.data.type&&l.Asc.plugin.onExternalPluginMessage(n.data);case\"onEvent\":l.Asc.plugin[\"event_\"+n.eventName]&&l.Asc.plugin[\"event_\"+n.eventName](n.eventData)}}},l.onmousemove=function(e){if(c&&l.Asc.plugin&&l.Asc.plugin.executeCommand){var n=o===e.clientX?e.pageX:e.clientX,t=o===e.clientY?e.pageY:e.clientY;l.Asc.plugin.executeCommand(\"onmousemove\",JSON.stringify({x:n,y:t}))}},l.onmouseup=function(e){if(c&&l.Asc.plugin&&l.Asc.plugin.executeCommand){var n=o===e.clientX?e.pageX:e.clientX,t=o===e.clientY?e.pageY:e.clientY;l.Asc.plugin.executeCommand(\"onmouseup\",JSON.stringify({x:n,y:t}))}},l.plugin_sendMessage(JSON.stringify({guid:l.Asc.plugin.guid,type:\"initialize_internal\"}))}(window,void 0);");
			var _iframe = document.getElementById(runObject.frameId);
			if (_iframe)
				_iframe.contentWindow.postMessage(pluginData.serialize(), "*");
			return;
		}
		else if ("reload" == name)
		{
			if (true === pluginData.getAttribute("ctrl"))
			{				
				if (AscCommon.c_oEditorId.Presentation === window.g_asc_plugins.api.getEditorId())
				{
					window.g_asc_plugins.api.sendEvent("asc_onStartDemonstration");
				}
			}
			return;
		}
		else if ("close" == name || "command" == name)
		{
			if (runObject.closeAttackTimer != -1)
			{
				clearTimeout(runObject.closeAttackTimer);
				runObject.closeAttackTimer = -1;
			}

			if (value && value != "")
			{
				var _command_callback_send = ("command" == name);
				try
				{
					if (pluginData.getAttribute("interface"))
					{
						var _script = "(function(){ var Api = window.g_asc_plugins.api;\n" + value + "\n})();";
						eval(_script);
					}
					else if (pluginData.getAttribute("resize") || window.g_asc_plugins.api.asc_canPaste())
					{
						var oLogicDocument, i;
						var editorId = window.g_asc_plugins.api.getEditorId();
						if (AscCommon.c_oEditorId.Word === editorId ||
							AscCommon.c_oEditorId.Presentation === editorId)
						{
							oLogicDocument = window.g_asc_plugins.api.WordControl ?
								window.g_asc_plugins.api.WordControl.m_oLogicDocument : null;
							if(AscCommon.c_oEditorId.Word === editorId){
								oLogicDocument.LockPanelStyles();
							}
						}

                        AscFonts.IsCheckSymbols = true;
						var _script = "(function(){ var Api = window.g_asc_plugins.api;\n" + value + "\n})();";
						eval(_script);
                        AscFonts.IsCheckSymbols = false;

						if (pluginData.getAttribute("recalculate") == true)
						{
							_command_callback_send = false;
							if (AscCommon.c_oEditorId.Word === editorId ||
								AscCommon.c_oEditorId.Presentation === editorId)
							{
								oLogicDocument = window.g_asc_plugins.api.WordControl ?
									window.g_asc_plugins.api.WordControl.m_oLogicDocument : null;
								var _fonts         = oLogicDocument.Document_Get_AllFontNames();
								var _imagesArray   = oLogicDocument.Get_AllImageUrls();
								var _images        = {};
								for (i = 0; i < _imagesArray.length; i++)
								{
									_images[_imagesArray[i]] = _imagesArray[i];
								}

								window.g_asc_plugins.images_rename = _images;
								AscCommon.Check_LoadingDataBeforePrepaste(window.g_asc_plugins.api, _fonts, _images,
									function()
									{
										if (window.g_asc_plugins.api.WordControl &&
											window.g_asc_plugins.api.WordControl.m_oLogicDocument &&
											window.g_asc_plugins.api.WordControl.m_oLogicDocument.Reassign_ImageUrls)
										{
											window.g_asc_plugins.api.WordControl.m_oLogicDocument.Reassign_ImageUrls(
												window.g_asc_plugins.images_rename);
										}
										delete window.g_asc_plugins.images_rename;

										if(AscCommon.c_oEditorId.Word === editorId) {
											oLogicDocument.UnlockPanelStyles(true);
											oLogicDocument.OnEndLoadScript();
										}

										window.g_asc_plugins.api.asc_Recalculate();

										var pluginData = new CPluginData();
										pluginData.setAttribute("guid", guid);
										pluginData.setAttribute("type", "onCommandCallback");

										var _iframe = document.getElementById(runObject.frameId);
										if (_iframe)
											_iframe.contentWindow.postMessage(pluginData.serialize(), "*");
									});
							}
							else if (AscCommon.c_oEditorId.Spreadsheet === editorId)
							{
								var oApi    = window.g_asc_plugins.api;
								var oFonts  = oApi.wbModel._generateFontMap();
								var aImages = oApi.wbModel.getAllImageUrls();
								var oImages = {};
								for (i = 0; i < aImages.length; i++)
								{
									oImages[aImages[i]] = aImages[i];
								}
								window.g_asc_plugins.images_rename = oImages;
								AscCommon.Check_LoadingDataBeforePrepaste(window.g_asc_plugins.api, oFonts, oImages,
									function(){
										oApi.wbModel.reassignImageUrls(window.g_asc_plugins.images_rename);
										delete window.g_asc_plugins.images_rename;
										window.g_asc_plugins.api.asc_Recalculate();
										var wsView = oApi.wb && oApi.wb.getWorksheet();
										if (wsView && wsView.objectRender && wsView.objectRender.controller) {
											wsView.objectRender.controller.recalculate2(undefined);
										}
										var pluginData = new CPluginData();
										pluginData.setAttribute("guid", guid);
										pluginData.setAttribute("type", "onCommandCallback");

										var _iframe = document.getElementById(runObject.frameId);
										if (_iframe)
											_iframe.contentWindow.postMessage(pluginData.serialize(), "*");
									});
							}
						} else {
							if (AscCommon.c_oEditorId.Spreadsheet === editorId) {
								// На asc_canPaste создается точка в истории и startTransaction. Поэтому нужно ее закрыть без пересчета.
								window.g_asc_plugins.api.asc_endPaste();
							}
						}
					}
				} catch (err)
				{
				}

				if (_command_callback_send)
				{
					var pluginData = new CPluginData();
					pluginData.setAttribute("guid", guid);
					pluginData.setAttribute("type", "onCommandCallback");
					var _iframe = document.getElementById(runObject.frameId);
					if (_iframe)
						_iframe.contentWindow.postMessage(pluginData.serialize(), "*");
				}
			}

			if ("close" == name)
			{
				window.g_asc_plugins.close(guid);
			}
		}
		else if ("resize" == name)
		{
			var _sizes = JSON.parse(value);

			window.g_asc_plugins.api.sendEvent("asc_onPluginResize",
				[_sizes["width"], _sizes["height"]],
				[_sizes["minw"], _sizes["minh"]],
				[_sizes["maxw"], _sizes["maxh"]], function() {
				// TODO: send resize end event
			});
		}
		else if ("onmousemove" == name)
		{
			var _pos = JSON.parse(value);
			window.g_asc_plugins.api.sendEvent("asc_onPluginMouseMove", _pos["x"], _pos["y"]);
		}
		else if ("onmouseup" == name)
		{
			var _pos = JSON.parse(value);
			window.g_asc_plugins.api.sendEvent("asc_onPluginMouseUp", _pos["x"], _pos["y"]);
		}
		else if ("method" == name)
		{
			var _apiMethodName = "pluginMethod_" + pluginData.getAttribute("methodName");
			var _return = undefined;

			window.g_asc_plugins.guidAsyncMethod = guid;

			if (window.g_asc_plugins.api[_apiMethodName])
				_return = window.g_asc_plugins.api[_apiMethodName].apply(window.g_asc_plugins.api, value);

			if (!runObject.methodReturnAsync)
			{
				var pluginData = new CPluginData();
				pluginData.setAttribute("guid", guid);
				pluginData.setAttribute("type", "onMethodReturn");
				pluginData.setAttribute("methodReturnData", _return);
				var _iframe = document.getElementById(runObject.frameId);
				if (_iframe)
					_iframe.contentWindow.postMessage(pluginData.serialize(), "*");
			}
			runObject.methodReturnAsync = false;
			window.g_asc_plugins.guidAsyncMethod = "";
			return;
		}
	}

	if (window.addEventListener)
	{
		window.addEventListener("message", onMessage, false);
	}
	else if (window.attachEvent)
	{
		window.attachEvent("onmessage", onMessage);
	}

	window["Asc"]                      = window["Asc"] ? window["Asc"] : {};
	window["Asc"].createPluginsManager = function(api)
	{
		if (window.g_asc_plugins)
			return window.g_asc_plugins;

		window.g_asc_plugins        = new CPluginsManager(api);
		window["g_asc_plugins"]     = window.g_asc_plugins;
		window.g_asc_plugins.api    = api;
		window.g_asc_plugins["api"] = window.g_asc_plugins.api;

		api.asc_registerCallback('asc_onSelectionEnd', function(){
			window.g_asc_plugins.onChangedSelectionData();
		});

		window.g_asc_plugins.api.asc_registerCallback('asc_onDocumentContentReady', function()
		{

			setTimeout(function()
			{
				window.g_asc_plugins.loadExtensionPlugins(window["Asc"]["extensionPlugins"]);
			}, 10);

		});

		if (window["AscDesktopEditor"] && window["UpdateSystemPlugins"])
			window["UpdateSystemPlugins"]();

		return window.g_asc_plugins;
	};

	window["Asc"].CPluginData      = CPluginData;
	window["Asc"].CPluginData_wrap = function(obj)
	{
		if (!obj.getAttribute)
			obj.getAttribute = function(name)
			{
				return this[name];
			};
		if (!obj.setAttribute)
			obj.setAttribute = function(name, value)
			{
				return this[name] = value;
			};
	};
})(window, undefined);
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";
(/**
 * @param {Window} window
 * @param {undefined} undefined
 */
  function(window, undefined) {
  /** @constructor */
  function asc_CVersionHistory(newObj) {
    this.docId = null;
    this.url = null;
    this.urlChanges = null;
    this.currentChangeId = -1;
    this.newChangeId = -1;
    this.colors = null;
    this.changes = null;
	this.token = null;
	this.isRequested = null;
	this.serverVersion = null;

    if (newObj) {
      this.update(newObj);
    }
  }

  asc_CVersionHistory.prototype.update = function(newObj) {
    var bUpdate = (this.docId !== newObj.docId || this.url !== newObj.url || this.urlChanges !== newObj.urlChanges || this.currentChangeId > newObj.currentChangeId);
    if (bUpdate) {
      this.docId = newObj.docId;
      this.url = newObj.url;
      this.urlChanges = newObj.urlChanges;
      this.currentChangeId = -1;
      this.changes = null;
	  this.token = newObj.token;
    }
    this.colors = newObj.colors;
    this.newChangeId = newObj.currentChangeId;
	this.isRequested = newObj.isRequested;
	this.serverVersion = newObj.serverVersion;
    return bUpdate;
  };
  asc_CVersionHistory.prototype.applyChanges = function(editor) {
    var color;
    this.newChangeId = (null == this.newChangeId) ? (this.changes.length - 1) : this.newChangeId;
    for (var i = this.currentChangeId + 1; i <= this.newChangeId && i < this.changes.length; ++i) {
      color = this.colors[i];
      editor._coAuthoringSetChanges(this.changes[i], i !== this.newChangeId ? null : (color ? new CDocumentColor((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF) : new CDocumentColor(191, 255, 199)));
    }
    this.currentChangeId = this.newChangeId;
  };
  asc_CVersionHistory.prototype.asc_setDocId = function(val) {
    this.docId = val;
  };
  asc_CVersionHistory.prototype.asc_setUrl = function(val) {
    this.url = val;
  };
  asc_CVersionHistory.prototype.asc_setUrlChanges = function(val) {
    this.urlChanges = val;
  };
  asc_CVersionHistory.prototype.asc_setCurrentChangeId = function(val) {
    this.currentChangeId = val;
  };
  asc_CVersionHistory.prototype.asc_setArrColors = function(val) {
    this.colors = val;
  };
  asc_CVersionHistory.prototype.asc_setToken = function(val) {
    this.token = val;
  };
  asc_CVersionHistory.prototype.asc_setIsRequested = function(val) {
    this.isRequested = val;
  };
  asc_CVersionHistory.prototype.asc_setServerVersion = function(val) {
    this.serverVersion = val;
  };

  window["Asc"].asc_CVersionHistory = window["Asc"]["asc_CVersionHistory"] = asc_CVersionHistory;
  prot = asc_CVersionHistory.prototype;
  prot["asc_setDocId"] = prot.asc_setDocId;
  prot["asc_setUrl"] = prot.asc_setUrl;
  prot["asc_setUrlChanges"] = prot.asc_setUrlChanges;
  prot["asc_setCurrentChangeId"] = prot.asc_setCurrentChangeId;
  prot["asc_setArrColors"] = prot.asc_setArrColors;
  prot["asc_setToken"] = prot.asc_setToken;
  prot["asc_setIsRequested"] = prot.asc_setIsRequested;
  prot["asc_setServerVersion"] = prot.asc_setServerVersion;
})(window);

AscCommon.baseEditorsApi.prototype.asc_showRevision = function(newObj) {
  if (!newObj.docId) {
    return;
  }
  if (this.isCoAuthoringEnable) {
    this.asc_coAuthoringDisconnect();
  }

  var bUpdate = true;
  if (null === this.VersionHistory) {
    this.VersionHistory = new window["Asc"].asc_CVersionHistory(newObj);
  } else {
    bUpdate = this.VersionHistory.update(newObj);
  }
  // ToDo должно быть все общее
  if (bUpdate) {
    this.asc_CloseFile();

    this.DocInfo.put_Id(this.VersionHistory.docId);
    this.DocInfo.put_Url(this.VersionHistory.url);
    this.documentUrlChanges = this.VersionHistory.urlChanges;
    this.asc_setDocInfo(this.DocInfo);
    this.asc_LoadDocument(this.VersionHistory);
  } else if (this.VersionHistory.currentChangeId < newObj.currentChangeId) {
    // Нужно только добавить некоторые изменения
    AscCommon.CollaborativeEditing.Clear_CollaborativeMarks();
    editor.VersionHistory.applyChanges(editor);
    AscCommon.CollaborativeEditing.Apply_Changes();
  }
};
AscCommon.baseEditorsApi.prototype['asc_showRevision'] = AscCommon.baseEditorsApi.prototype.asc_showRevision;
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

Asc['asc_docs_api'].prototype.asc_addComment = function(AscCommentData)
{
	if (true === AscCommon.CollaborativeEditing.Get_GlobalLock())
		return;

	var oLogicDocument = this.WordControl.m_oLogicDocument;

	if (!oLogicDocument)
		return;

	// Комментарий без цитаты позволяем добавить всегда
	if (true !== this.can_AddQuotedComment() || false === oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_Paragraph_Content, null, true, oLogicDocument.IsEditCommentsMode()))
	{
		var CommentData = new CCommentData();
		CommentData.Read_FromAscCommentData(AscCommentData);

		this.WordControl.m_oLogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddComment);
		var Comment = this.WordControl.m_oLogicDocument.AddComment(CommentData, AscCommentData.asc_getDocumentFlag());
		if (null != Comment)
		{
			this.sync_AddComment(Comment.Get_Id(), CommentData);
		}

		return Comment.Get_Id();
	}
};
Asc['asc_docs_api'].prototype.asc_GetCommentsReportByAuthors = function()
{
	var oReport = {};

	function privateProcessCommentData(isTopComment, oCommentData)
	{
		var sUserName = oCommentData.GetUserName();
		var nDateTime = oCommentData.GetDateTime();

		if (!oReport[sUserName])
			oReport[sUserName] = [];

		var arrUserComments = oReport[sUserName];

		var nPos = 0;
		var nLen = arrUserComments.length;
		while (nPos < nLen)
		{
			if (nDateTime < arrUserComments[nPos].Data.GetDateTime())
				break;

			nPos++;
		}

		arrUserComments.splice(nPos, 0, {Top : isTopComment, Data : oCommentData});

		for (var nIndex = 0, nCount = oCommentData.GetRepliesCount(); nIndex < nCount; ++nIndex)
		{
			privateProcessCommentData(false, oCommentData.GetReply(nIndex))
		}
	}

	var oLogicDocument = this.WordControl.m_oLogicDocument;
	if (!oLogicDocument)
		return oReport;

	var oAllComments = oLogicDocument.Comments.GetAllComments();
	for (var sId in oAllComments)
	{
		var oComment = oAllComments[sId];
		privateProcessCommentData(true, oComment.GetData());
	}

	return oReport;
};

Asc['asc_docs_api'].prototype['asc_addComment']                 = Asc['asc_docs_api'].prototype.asc_addComment;
Asc['asc_docs_api'].prototype['asc_GetCommentsReportByAuthors'] = Asc['asc_docs_api'].prototype.asc_GetCommentsReportByAuthors;

/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

//----------------------------------------------------------------------------------------------------------------------
//  asc_docs_api (Обращение из апи)
//----------------------------------------------------------------------------------------------------------------------
Asc['asc_docs_api'].prototype.asc_GetStyleFromFormatting = function()
{
    return this.WordControl.m_oLogicDocument.GetStyleFromFormatting();
};
Asc['asc_docs_api'].prototype.asc_AddNewStyle = function(oStyle)
{
    this.WordControl.m_oLogicDocument.Add_NewStyle(oStyle);
};
Asc['asc_docs_api'].prototype.asc_RemoveStyle = function(sName)
{
    this.WordControl.m_oLogicDocument.Remove_Style(sName);
};
Asc['asc_docs_api'].prototype.asc_RemoveAllCustomStyles = function()
{
    this.WordControl.m_oLogicDocument.Remove_AllCustomStyles();
};
Asc['asc_docs_api'].prototype.asc_IsStyleDefault = function(sName)
{
    return this.WordControl.m_oLogicDocument.Is_StyleDefault(sName);
};
Asc['asc_docs_api'].prototype.asc_IsDefaultStyleChanged = function(sName)
{
    return this.WordControl.m_oLogicDocument.Is_DefaultStyleChanged(sName);
};

Asc['asc_docs_api'].prototype['asc_GetStyleFromFormatting'] = Asc['asc_docs_api'].prototype.asc_GetStyleFromFormatting;
Asc['asc_docs_api'].prototype['asc_AddNewStyle']            = Asc['asc_docs_api'].prototype.asc_AddNewStyle;
Asc['asc_docs_api'].prototype['asc_RemoveStyle']            = Asc['asc_docs_api'].prototype.asc_RemoveStyle;
Asc['asc_docs_api'].prototype['asc_RemoveAllCustomStyles']  = Asc['asc_docs_api'].prototype.asc_RemoveAllCustomStyles;
Asc['asc_docs_api'].prototype['asc_IsStyleDefault']         = Asc['asc_docs_api'].prototype.asc_IsStyleDefault;
Asc['asc_docs_api'].prototype['asc_IsDefaultStyleChanged']  = Asc['asc_docs_api'].prototype.asc_IsDefaultStyleChanged;
//----------------------------------------------------------------------------------------------------------------------
//  CDocument
//----------------------------------------------------------------------------------------------------------------------
/**
 * Получаем стиль по выделенному фрагменту
 */
CDocument.prototype.GetStyleFromFormatting = function()
{
	return this.Controller.GetStyleFromFormatting();
};
/**
 * Добавляем новый стиль (или заменяем старый с таким же названием).
 * И сразу применяем его к выделенному фрагменту.
 */
CDocument.prototype.Add_NewStyle = function(oStyle)
{
    if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Document_Styles, {Type : AscCommon.changestype_2_AdditionalTypes, Types : [AscCommon.changestype_Paragraph_Properties]}))
    {
        AscCommon.History.Create_NewPoint(AscDFH.historydescription_Document_AddNewStyle);
        var NewStyle = this.Styles.Create_StyleFromInterface(oStyle);
        this.SetParagraphStyle(NewStyle.Get_Name());
        this.Recalculate();
        this.Document_UpdateInterfaceState();
    }
};
/**
 * Удаляем заданный стиль по имени.
 */
CDocument.prototype.Remove_Style = function(sStyleName)
{
    var StyleId = this.Styles.GetStyleIdByName(sStyleName);
    // Сначала проверим есть ли стиль с таким именем
    if (null == StyleId)
        return;

    if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Document_Styles))
    {
        AscCommon.History.Create_NewPoint(AscDFH.historydescription_Document_RemoveStyle);
        this.Styles.Remove_StyleFromInterface(StyleId);
        this.Recalculate();
        this.Document_UpdateInterfaceState();
    }
};
/**
 * Удаляем все недефолтовые стили в документе.
 */
CDocument.prototype.Remove_AllCustomStyles = function()
{
    if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Document_Styles))
    {
        AscCommon.History.Create_NewPoint(AscDFH.historydescription_Document_RemoveAllCustomStyles);
        this.Styles.Remove_AllCustomStylesFromInterface();
        this.Recalculate();
        this.Document_UpdateInterfaceState();
    }
};
/**
 * Проверяем является ли заданный стиль дефолтовым.
 */
CDocument.prototype.Is_StyleDefault = function(sName)
{
    return this.Styles.Is_StyleDefault(sName);
};
/**
 * Проверяем изменен ли дефолтовый стиль.
 */
CDocument.prototype.Is_DefaultStyleChanged = function(sName)
{
    return this.Styles.Is_DefaultStyleChanged(sName);
};
//----------------------------------------------------------------------------------------------------------------------
//  CStyles
//----------------------------------------------------------------------------------------------------------------------
CStyles.prototype.Create_StyleFromInterface = function(oAscStyle, bCheckLink)
{
	var sStyleName = oAscStyle.get_Name();
	var sStyleId   = this.GetStyleIdByName(sStyleName);
	if (null !== sStyleId)
	{
		var oStyle = this.Style[sStyleId];

		var NewStyleParaPr = oAscStyle.get_ParaPr();
		var NewStyleTextPr = oAscStyle.get_TextPr();

		var BasedOnId = this.GetStyleIdByName(oAscStyle.get_BasedOn());
		var NextId    = this.GetStyleIdByName(oAscStyle.get_Next());

		oStyle.Set_Type(oAscStyle.get_Type());

		if (BasedOnId === sStyleId || sStyleId === this.Default.Paragraph)
		{
			if (sStyleId !== this.Default.Paragraph)
			{
				var oBaseStyle      = this.Get(BasedOnId);
				var oBasedBasesOnId = this.Get_Default_Paragraph();
				if (oBaseStyle)
				{
					oBasedBasesOnId = oBaseStyle.Get_BasedOn();
					if (oBaseStyle.Get_BasedOn() !== sStyleId)
						oBasedBasesOnId = oBaseStyle.Get_BasedOn();
				}

				oStyle.Set_BasedOn(oBasedBasesOnId);
			}
			else
			{
				oStyle.Set_BasedOn(null);
			}

			var OldStyleParaPr = oStyle.ParaPr.Copy();
			var OldStyleTextPr = oStyle.TextPr.Copy();
			OldStyleParaPr.Merge(NewStyleParaPr);
			OldStyleTextPr.Merge(NewStyleTextPr);
			NewStyleParaPr = OldStyleParaPr;
			NewStyleTextPr = OldStyleTextPr;
		}
		else
		{
			oStyle.Set_BasedOn(BasedOnId);
		}

		if (null === oStyle.Get_Next() || (null !== NextId && NextId !== sStyleId))
		{
			if (NextId === sStyleId)
				oStyle.Set_Next(null);
			else
				oStyle.Set_Next(NextId);
		}

		var oAscLink   = oAscStyle.get_Link();
		var sOldLinkId = oStyle.Get_Link();
		if (sOldLinkId && this.Style[sOldLinkId])
			oAscLink.put_Name(this.Style[sOldLinkId].GetName());
		else
			bCheckLink = false;

		if (false != bCheckLink && null != oAscLink && undefined !== oAscLink)
		{
			var oLinkedStyle = this.Create_StyleFromInterface(oAscLink, false);
			oStyle.Set_Link(oLinkedStyle.Get_Id());
			oLinkedStyle.Set_Link(oStyle.Get_Id());
		}

		oStyle.Set_TextPr(NewStyleTextPr);
		oStyle.Set_ParaPr(NewStyleParaPr);

		return oStyle;
	}
	else
	{
		var oStyle = new CStyle();

		var BasedOnId = this.GetStyleIdByName(oAscStyle.get_BasedOn());
		oStyle.Set_BasedOn(BasedOnId);
		oStyle.Set_Next(this.GetStyleIdByName(oAscStyle.get_Next()));
		oStyle.Set_Type(oAscStyle.get_Type());
		oStyle.Set_TextPr(oAscStyle.get_TextPr());
		oStyle.Set_ParaPr(oAscStyle.get_ParaPr());
		oStyle.Set_Name(sStyleName);
		oStyle.SetCustom(true);

		if (styletype_Paragraph === oStyle.Get_Type())
			oStyle.Set_QFormat(true);

		var oAscLink = oAscStyle.get_Link();
		if (false != bCheckLink && null != oAscLink && undefined !== oAscLink)
		{
			var oLinkedStyle = this.Create_StyleFromInterface(oAscLink, false);
			oStyle.Set_Link(oLinkedStyle.Get_Id());
			oLinkedStyle.Set_Link(oStyle.Get_Id());
		}

		this.Add(oStyle);
		return oStyle;
	}
};
CStyles.prototype.Remove_StyleFromInterface = function(StyleId)
{
    // Если этот стиль не один из стилей по умолчанию, тогда мы просто удаляем этот стиль
    // и очищаем все параграфы с сылкой на этот стиль.

    var Style = this.Style[StyleId];
    if (StyleId == this.Default.Paragraph)
    {
        Style.Clear("Normal", null, null, styletype_Paragraph);
        Style.CreateNormal();
    }
    else if (StyleId == this.Default.Character)
    {
        Style.Clear("Default Paragraph Font", null, null, styletype_Character);
        Style.CreateDefaultParagraphFont();
    }
    else if (StyleId == this.Default.Numbering)
    {
        Style.Clear("No List", null, null, styletype_Numbering);
        Style.CreateNoList();
    }
    else if (StyleId == this.Default.Table)
    {
        Style.Clear("Normal Table", null, null, styletype_Table);
        Style.Create_NormalTable();
    }
    else if (StyleId == this.Default.TableGrid)
    {
        Style.Clear("Table Grid", this.Default.Table, null, styletype_Table);
        Style.Create_TableGrid();
    }
    else if (StyleId == this.Default.Headings[0])
    {
        Style.Clear("Heading 1", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(0);
    }
    else if (StyleId == this.Default.Headings[1])
    {
        Style.Clear("Heading 2", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(1);
    }
    else if (StyleId == this.Default.Headings[2])
    {
        Style.Clear("Heading 3", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(2);
    }
    else if (StyleId == this.Default.Headings[3])
    {
        Style.Clear("Heading 4", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(3);
    }
    else if (StyleId == this.Default.Headings[4])
    {
        Style.Clear("Heading 5", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(4);
    }
    else if (StyleId == this.Default.Headings[5])
    {
        Style.Clear("Heading 6", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(5);
    }
    else if (StyleId == this.Default.Headings[6])
    {
        Style.Clear("Heading 7", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(6);
    }
    else if (StyleId == this.Default.Headings[7])
    {
        Style.Clear("Heading 8", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(7);
    }
    else if (StyleId == this.Default.Headings[8])
    {
        Style.Clear("Heading 9", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(8);
    }
    else if (StyleId == this.Default.ParaList)
    {
        Style.Clear("List Paragraph", this.Default.Paragraph, null, styletype_Paragraph);
        Style.CreateListParagraph();
    }
    else if (StyleId == this.Default.Header)
    {
        Style.Clear("Header", this.Default.Paragraph, null, styletype_Paragraph);
        Style.CreateHeader();
    }
    else if (StyleId == this.Default.Footer)
    {
        Style.Clear("Footer", this.Default.Paragraph, null, styletype_Paragraph);
        Style.CreateFooter();
    }
    else if (StyleId == this.Default.Hyperlink)
    {
        Style.Clear("Hyperlink", null, null, styletype_Character);
        Style.CreateHyperlink();
    }
	else if (StyleId == this.Default.NoSpacing)
	{
		Style.Clear("No Spacing", this.Default.Paragraph, null, styletype_Paragraph);
		Style.CreateNoSpacing();
	}
	else if (StyleId === this.Default.Title)
	{
		Style.Clear("Title", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
		Style.CreateTitle();
	}
	else if (StyleId === this.Default.Subtitle)
	{
		Style.Clear("Subtitle", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
		Style.CreateSubtitle();
	}
	else if (StyleId === this.Default.Quote)
	{
		Style.Clear("Quote", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
		Style.CreateQuote();
	}
	else if (StyleId === this.Default.IntenseQuote)
	{
		Style.Clear("Intense Quote", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
		Style.CreateIntenseQuote();
	}
    else
    {
        this.Remove(StyleId);

        if (this.LogicDocument)
        {
            var AllParagraphs = this.LogicDocument.GetAllParagraphsByStyle([StyleId]);
            var Count = AllParagraphs.length;
            for (var Index = 0; Index < Count; Index++)
            {
                var Para = AllParagraphs[Index];
                Para.Style_Remove();
            }
        }
    }
    this.Update_Interface(StyleId);
};
CStyles.prototype.Remove_AllCustomStylesFromInterface = function()
{
    for (var StyleId in this.Style)
    {
        var Style = this.Style[StyleId];
        if ((styletype_Paragraph === Style.GetType() || styletype_Character === Style.GetType()) && true === Style.GetQFormat())
        {
            this.Remove_StyleFromInterface(StyleId);
        }
    }
};
CStyles.prototype.Is_StyleDefault = function(sStyleName)
{
    var StyleId = this.GetStyleIdByName(sStyleName);
    if (null === StyleId)
        return false;

    if (StyleId == this.Default.Paragraph
        || StyleId == this.Default.Character
        || StyleId == this.Default.Numbering
        || StyleId == this.Default.Table
        || StyleId == this.Default.TableGrid
        || StyleId == this.Default.Headings[0]
        || StyleId == this.Default.Headings[1]
        || StyleId == this.Default.Headings[2]
        || StyleId == this.Default.Headings[3]
        || StyleId == this.Default.Headings[4]
        || StyleId == this.Default.Headings[5]
        || StyleId == this.Default.Headings[6]
        || StyleId == this.Default.Headings[7]
        || StyleId == this.Default.Headings[8]
        || StyleId == this.Default.ParaList
        || StyleId == this.Default.Header
        || StyleId == this.Default.Footer
        || StyleId == this.Default.Hyperlink
		|| StyleId == this.Default.FootnoteText
		|| StyleId == this.Default.FootnoteTextChar
		|| StyleId == this.Default.FootnoteReference
		|| StyleId == this.Default.NoSpacing
		|| StyleId == this.Default.Title
		|| StyleId == this.Default.Subtitle
		|| StyleId == this.Default.Quote
		|| StyleId == this.Default.IntenseQuote)
    {
        return true;
    }

    return false;
};
CStyles.prototype.Is_DefaultStyleChanged = function(sStyleName)
{
    if (true != this.Is_StyleDefault(sStyleName))
        return false;

    var StyleId = this.GetStyleIdByName(sStyleName);
    if (null === StyleId)
        return false;

    var CurrentStyle = this.Style[StyleId];
    this.LogicDocument.TurnOffHistory();

    var Style = new CStyle();
    if (StyleId == this.Default.Paragraph)
    {
        Style.Clear("Normal", null, null, styletype_Paragraph);
        Style.CreateNormal();
    }
    else if (StyleId == this.Default.Character)
    {
        Style.Clear("Default Paragraph Font", null, null, styletype_Character);
        Style.CreateDefaultParagraphFont();
    }
    else if (StyleId == this.Default.Numbering)
    {
        Style.Clear("No List", null, null, styletype_Numbering);
        Style.CreateNoList();
    }
    else if (StyleId == this.Default.Table)
    {
        Style.Clear("Normal Table", null, null, styletype_Table);
        Style.Create_NormalTable();
    }
    else if (StyleId == this.Default.TableGrid)
    {
        Style.Clear("Table Grid", this.Default.Table, null, styletype_Table);
        Style.Create_TableGrid();
    }
    else if (StyleId == this.Default.Headings[0])
    {
        Style.Clear("Heading 1", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(0);
    }
    else if (StyleId == this.Default.Headings[1])
    {
        Style.Clear("Heading 2", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(1);
    }
    else if (StyleId == this.Default.Headings[2])
    {
        Style.Clear("Heading 3", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(2);
    }
    else if (StyleId == this.Default.Headings[3])
    {
        Style.Clear("Heading 4", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(3);
    }
    else if (StyleId == this.Default.Headings[4])
    {
        Style.Clear("Heading 5", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(4);
    }
    else if (StyleId == this.Default.Headings[5])
    {
        Style.Clear("Heading 6", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(5);
    }
    else if (StyleId == this.Default.Headings[6])
    {
        Style.Clear("Heading 7", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(6);
    }
    else if (StyleId == this.Default.Headings[7])
    {
        Style.Clear("Heading 8", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(7);
    }
    else if (StyleId == this.Default.Headings[8])
    {
        Style.Clear("Heading 9", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
        Style.CreateHeading(8);
    }
    else if (StyleId == this.Default.ParaList)
    {
        Style.Clear("List Paragraph", this.Default.Paragraph, null, styletype_Paragraph);
        Style.CreateListParagraph();
    }
    else if (StyleId == this.Default.Header)
    {
        Style.Clear("Header", this.Default.Paragraph, null, styletype_Paragraph);
        Style.CreateHeader();
    }
    else if (StyleId == this.Default.Footer)
    {
        Style.Clear("Footer", this.Default.Paragraph, null, styletype_Paragraph);
        Style.CreateFooter();
    }
    else if (StyleId == this.Default.Hyperlink)
    {
        Style.Clear("Hyperlink", null, null, styletype_Character);
        Style.CreateHyperlink();
    }
    else if (StyleId == this.Default.NoSpacing)
	{
		Style.Clear("No Spacing", this.Default.Paragraph, null, styletype_Paragraph);
		Style.CreateNoSpacing();
	}
	else if (StyleId === this.Default.Title)
	{
		Style.Clear("Title", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
		Style.CreateTitle();
	}
	else if (StyleId === this.Default.Subtitle)
	{
		Style.Clear("Subtitle", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
		Style.CreateSubtitle();
	}
	else if (StyleId === this.Default.Quote)
	{
		Style.Clear("Quote", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
		Style.CreateQuote();
	}
	else if (StyleId === this.Default.IntenseQuote)
	{
		Style.Clear("Intense Quote", this.Default.Paragraph, this.Default.Paragraph, styletype_Paragraph);
		Style.CreateIntenseQuote();
	}

    this.LogicDocument.TurnOnHistory();

    return (true === Style.Is_Equal(CurrentStyle) ? false : true);
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var c_oAscError = Asc.c_oAscError;

//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с MailMerge
//----------------------------------------------------------------------------------------------------------------------
Asc['asc_docs_api'].prototype.asc_StartMailMerge = function(oData)
{
    this.mailMergeFileData = oData;
    this.asc_DownloadAs(Asc.c_oAscFileType.JSON);
};
Asc['asc_docs_api'].prototype.asc_StartMailMergeByList = function(aList)
{
    if (!aList || !aList.length || aList.length <= 0)
        aList = [[]];

    var aFields = aList[0];
    if (!aFields || !aFields.length || aFields.length <= 0)
        aFields = [];

    // Пробегаемся по названиям полей и делаем следующее:
    // Если название пустой, тогда задем ему имя "F<номер столбца>"
    // Если название совпадает, тогда добавляем ему число, чтобы имя стало уникальным.

    var UsedNames = {};
    for (var Pos = 0, Count = aFields.length; Pos < Count; Pos++)
    {
        if ("" === aFields[Pos])
            aFields[Pos] = "F" + (Pos + 1);

        if (undefined !== UsedNames[aFields[Pos]])
        {
            var Add = 1;
            var NewName = aFields[Pos] + Add;
            while (undefined !== UsedNames[NewName])
            {
                Add++;
                NewName = aFields[Pos] + Add;
            }
            aFields[Pos] = NewName;
        }

        UsedNames[aFields[Pos]] = 1;
    }

    var DstList = [];
    var FieldsCount = aFields.length;
    for (var Index = 1, Count = aList.length; Index < Count; Index++)
    {
        var oSrcElement = aList[Index];
        var oDstElement = {};
        for (var FieldIndex = 0; FieldIndex < FieldsCount; FieldIndex++)
        {
            var sFieldName = aFields[FieldIndex];
            oDstElement[sFieldName] = oSrcElement[FieldIndex];
        }

        DstList.push(oDstElement);
    }

    this.WordControl.m_oLogicDocument.Start_MailMerge(DstList, aFields);
};
Asc['asc_docs_api'].prototype.asc_GetReceptionsCount = function()
{
    return this.WordControl.m_oLogicDocument.Get_MailMergeReceptionsCount();
};
Asc['asc_docs_api'].prototype.asc_GetMailMergeFieldsNameList = function()
{
    return this.WordControl.m_oLogicDocument.Get_MailMergeFieldsNameList();
};
Asc['asc_docs_api'].prototype.asc_AddMailMergeField = function(Name)
{
    this.WordControl.m_oLogicDocument.Add_MailMergeField(Name);
};
Asc['asc_docs_api'].prototype.asc_SetHighlightMailMergeFields = function(Value)
{
    this.WordControl.m_oLogicDocument.Set_HightlighMailMergeFields(Value);
};
Asc['asc_docs_api'].prototype.asc_PreviewMailMergeResult = function(Index)
{
    this.WordControl.m_oLogicDocument.Preview_MailMergeResult(Index);
};
Asc['asc_docs_api'].prototype.asc_EndPreviewMailMergeResult = function()
{
    this.WordControl.m_oLogicDocument.EndPreview_MailMergeResult();
};
Asc['asc_docs_api'].prototype.sync_StartMailMerge = function()
{
    this.sendEvent("asc_onStartMailMerge");
};
Asc['asc_docs_api'].prototype.sync_PreviewMailMergeResult = function(Index)
{
    this.sendEvent("asc_onPreviewMailMergeResult", Index);
};
Asc['asc_docs_api'].prototype.sync_EndPreviewMailMergeResult = function()
{
    this.sendEvent("asc_onEndPreviewMailMergeResult");
};
Asc['asc_docs_api'].prototype.sync_HighlightMailMergeFields = function(Value)
{
    this.sendEvent("asc_onHighlightMailMergeFields", Value);
};
Asc['asc_docs_api'].prototype.asc_getMailMergeData = function()
{
    return this.WordControl.m_oLogicDocument.Get_MailMergeReceptionsList();
};
Asc['asc_docs_api'].prototype.asc_setMailMergeData = function(aList)
{
    this.asc_StartMailMergeByList(aList);
};
Asc['asc_docs_api'].prototype.asc_sendMailMergeData = function(oData)
{
    var actionType = Asc.c_oAscAsyncAction.SendMailMerge;
    oData.put_UserId(this.documentUserId);
    oData.put_RecordCount(oData.get_RecordTo() - oData.get_RecordFrom() + 1);
    var options = {oMailMergeSendData: oData, isNoCallback: true};
    var t = this;
    this._downloadAs("sendmm", Asc.c_oAscFileType.TXT, actionType, options, function(input) {
        if (null != input && "sendmm" == input["type"])
        {
            if ("ok" != input["status"])
            {
                t.sendEvent("asc_onError", AscCommon.mapAscServerErrorToAscError(parseInt(input["data"])),
                    c_oAscError.Level.NoCritical);
            }
        }
        else
        {
            t.sendEvent("asc_onError", c_oAscError.ID.Unknown, c_oAscError.Level.NoCritical);
        }
        t.sync_EndAction(Asc.c_oAscAsyncActionType.BlockInteraction, actionType);
    });
};
Asc['asc_docs_api'].prototype.asc_GetMailMergeFiledValue = function(nIndex, sName)
{
    return this.WordControl.m_oLogicDocument.Get_MailMergeFileldValue(nIndex, sName);
};
Asc['asc_docs_api'].prototype.asc_DownloadAsMailMerge = function(typeFile, StartIndex, EndIndex, bIsDownload)
{
    var oDocumentMailMerge = this.WordControl.m_oLogicDocument.Get_MailMergedDocument(StartIndex, EndIndex);
    if (null != oDocumentMailMerge)
    {
        var actionType = null;
        var options = {oDocumentMailMerge: oDocumentMailMerge, downloadType: AscCommon.DownloadType.MailMerge, errorDirect: c_oAscError.ID.MailMergeSaveFile};
        if (bIsDownload) {
            actionType = Asc.c_oAscAsyncAction.DownloadMerge;
            options.downloadType = AscCommon.DownloadType.None;
        }
        this._downloadAs("save", typeFile, actionType, options, null);
    }
    return null != oDocumentMailMerge ? true : false;
};

Asc['asc_docs_api'].prototype['asc_StartMailMerge']              = Asc['asc_docs_api'].prototype.asc_StartMailMerge;
Asc['asc_docs_api'].prototype['asc_StartMailMergeByList']        = Asc['asc_docs_api'].prototype.asc_StartMailMergeByList;
Asc['asc_docs_api'].prototype['asc_GetReceptionsCount']          = Asc['asc_docs_api'].prototype.asc_GetReceptionsCount;
Asc['asc_docs_api'].prototype['asc_GetMailMergeFieldsNameList']  = Asc['asc_docs_api'].prototype.asc_GetMailMergeFieldsNameList;
Asc['asc_docs_api'].prototype['asc_AddMailMergeField']           = Asc['asc_docs_api'].prototype.asc_AddMailMergeField;
Asc['asc_docs_api'].prototype['asc_SetHighlightMailMergeFields'] = Asc['asc_docs_api'].prototype.asc_SetHighlightMailMergeFields;
Asc['asc_docs_api'].prototype['asc_PreviewMailMergeResult']      = Asc['asc_docs_api'].prototype.asc_PreviewMailMergeResult;
Asc['asc_docs_api'].prototype['asc_EndPreviewMailMergeResult']   = Asc['asc_docs_api'].prototype.asc_EndPreviewMailMergeResult;
Asc['asc_docs_api'].prototype['sync_StartMailMerge']             = Asc['asc_docs_api'].prototype.sync_StartMailMerge;
Asc['asc_docs_api'].prototype['sync_PreviewMailMergeResult']     = Asc['asc_docs_api'].prototype.sync_PreviewMailMergeResult;
Asc['asc_docs_api'].prototype['sync_EndPreviewMailMergeResult']  = Asc['asc_docs_api'].prototype.sync_EndPreviewMailMergeResult;
Asc['asc_docs_api'].prototype['sync_HighlightMailMergeFields']   = Asc['asc_docs_api'].prototype.sync_HighlightMailMergeFields;
Asc['asc_docs_api'].prototype['asc_getMailMergeData']            = Asc['asc_docs_api'].prototype.asc_getMailMergeData;
Asc['asc_docs_api'].prototype['asc_setMailMergeData']            = Asc['asc_docs_api'].prototype.asc_setMailMergeData;
Asc['asc_docs_api'].prototype['asc_sendMailMergeData']           = Asc['asc_docs_api'].prototype.asc_sendMailMergeData;
Asc['asc_docs_api'].prototype['asc_GetMailMergeFiledValue']      = Asc['asc_docs_api'].prototype.asc_GetMailMergeFiledValue;
Asc['asc_docs_api'].prototype['asc_DownloadAsMailMerge']         = Asc['asc_docs_api'].prototype.asc_DownloadAsMailMerge;
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с MailMerge
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.Start_MailMerge = function(MailMergeMap, arrFields)
{
	this.EndPreview_MailMergeResult();

	this.MailMergeMap    = MailMergeMap;
	this.MailMergeFields = arrFields;
	editor.sync_HighlightMailMergeFields(this.MailMergeFieldsHighlight);
	editor.sync_StartMailMerge();
};
CDocument.prototype.Get_MailMergeReceptionsCount = function()
{
    if (null === this.MailMergeMap || !this.MailMergeMap)
        return 0;

    return this.MailMergeMap.length;
};
CDocument.prototype.Get_MailMergeFieldsNameList = function()
{
    if (this.Get_MailMergeReceptionsCount() <= 0)
        return this.MailMergeFields;

    // Предполагаем, что в первом элементе перечислены все поля
    var Element = this.MailMergeMap[0];
    var aList = [];
    for (var sId in Element)
    {
        aList.push(sId);
    }

    return aList;
};
CDocument.prototype.Add_MailMergeField = function(Name)
{
    if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_Paragraph_Content))
    {
        this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AddMailMergeField);

        var oField = new ParaField(fieldtype_MERGEFIELD, [Name], []);
        var oRun = new ParaRun();
        oRun.AddText("«" + Name + "»");
        oField.Add_ToContent(0, oRun);

        this.Register_Field(oField);
        this.AddToParagraph(oField);
        this.Document_UpdateInterfaceState();
    }
};
CDocument.prototype.Set_HightlighMailMergeFields = function(Value)
{
    if (Value !== this.MailMergeFieldsHighlight)
    {
        this.MailMergeFieldsHighlight = Value;
        this.DrawingDocument.ClearCachePages();
        this.DrawingDocument.FirePaint();
        this.DrawingDocument.Update_FieldTrack(false);
        editor.sync_HighlightMailMergeFields(this.MailMergeFieldsHighlight);
    }
};
CDocument.prototype.Preview_MailMergeResult = function(Index)
{
    if (null === this.MailMergeMap)
        return;

    if (true !== this.MailMergePreview)
    {
        this.MailMergePreview = true;
        this.RemoveSelection();
        AscCommon.CollaborativeEditing.Set_GlobalLock(true);
    }

    this.FieldsManager.Update_MailMergeFields(this.MailMergeMap[Index]);
    this.Recalculate_FromStart(true);

    editor.sync_PreviewMailMergeResult(Index);
};
CDocument.prototype.EndPreview_MailMergeResult = function()
{
    if (null === this.MailMergeMap || true !== this.MailMergePreview)
        return;

    this.MailMergePreview = false;
    AscCommon.CollaborativeEditing.Set_GlobalLock(false);

    this.FieldsManager.Restore_MailMergeTemplate();
    this.Recalculate_FromStart(true);

    editor.sync_EndPreviewMailMergeResult();
};
CDocument.prototype.Get_MailMergeReceptionsList = function()
{
    var aList = [];

    var aHeaders = [];
    var nCount = this.MailMergeMap.length;
    if (nCount <= 0)
        return [this.MailMergeFields];

    for (var sId in this.MailMergeMap[0])
        aHeaders.push(sId);

    var nHeadersCount = aHeaders.length;

    aList.push(aHeaders);
    for (var nIndex = 0; nIndex < nCount; nIndex++)
    {
        var aReception = [];
        var oReception = this.MailMergeMap[nIndex];
        for (var nHeaderIndex = 0; nHeaderIndex < nHeadersCount; nHeaderIndex++)
        {
            var sValue = oReception[aHeaders[nHeaderIndex]];
            aReception.push(sValue ? sValue : "");
        }

        aList.push(aReception);
    }

    return aList;
};
CDocument.prototype.Get_MailMergeFileldValue = function(nIndex, sName)
{
    if (null === this.MailMergeMap)
        return null;

    return this.MailMergeMap[nIndex][sName];
};
CDocument.prototype.Get_MailMergedDocument = function(_nStartIndex, _nEndIndex)
{
    var nStartIndex = (undefined !== _nStartIndex ? Math.max(0, _nStartIndex) : 0);
    var nEndIndex   = (undefined !== _nEndIndex   ? Math.min(_nEndIndex, this.MailMergeMap.length - 1) : this.MailMergeMap.length - 1);

    if (null === this.MailMergeMap || nStartIndex > nEndIndex || nStartIndex >= this.MailMergeMap.length)
        return null;

    AscCommon.History.TurnOff();
    AscCommon.g_oTableId.TurnOff();

    var LogicDocument = new CDocument(undefined, false);
    AscCommon.History.Document = this;

    // Копируем стили, они все одинаковые для всех документов
    LogicDocument.Styles = this.Styles.Copy();

    // Нумерацию придется повторить для каждого отдельного файла
    LogicDocument.Numbering.Clear();

    LogicDocument.DrawingDocument = this.DrawingDocument;

    LogicDocument.theme = this.theme.createDuplicate();
    LogicDocument.clrSchemeMap   = this.clrSchemeMap.createDuplicate();

    var FieldsManager = this.FieldsManager;

    var ContentCount = this.Content.length;
    var OverallIndex = 0;
    this.ForceCopySectPr = true;

    for (var Index = nStartIndex; Index <= nEndIndex; Index++)
    {
        // Подменяем ссылку на менеджер полей, чтобы скопированные поля регистрировались в новом классе
        this.FieldsManager = LogicDocument.FieldsManager;
        var NewNumbering = this.Numbering.CopyAllNums(LogicDocument.Numbering);

        LogicDocument.Numbering.AppendAbstractNums(NewNumbering.AbstractNum);
        LogicDocument.Numbering.AppendNums(NewNumbering.Num);

        this.CopyNumberingMap = NewNumbering.NumMap;

        for (var ContentIndex = 0; ContentIndex < ContentCount; ContentIndex++)
        {
            LogicDocument.Content[OverallIndex++] = this.Content[ContentIndex].Copy(LogicDocument, this.DrawingDocument);

            if (type_Paragraph === this.Content[ContentIndex].Get_Type())
            {
                var ParaSectPr = this.Content[ContentIndex].Get_SectionPr();
                if (ParaSectPr)
                {
                    var NewParaSectPr = new CSectionPr();
                    NewParaSectPr.Copy(ParaSectPr, true);
                    LogicDocument.Content[OverallIndex - 1].Set_SectionPr(NewParaSectPr, false);
                }
            }
        }

        // Добавляем дополнительный параграф с окончанием секции
        var SectionPara = new Paragraph(this.DrawingDocument, this);
        var SectPr = new CSectionPr();
        SectPr.Copy(this.SectPr, true);
        SectPr.Set_Type(c_oAscSectionBreakType.NextPage);
        SectionPara.Set_SectionPr(SectPr, false);
        LogicDocument.Content[OverallIndex++] = SectionPara;

        LogicDocument.FieldsManager.Replace_MailMergeFields(this.MailMergeMap[Index]);
    }

    this.CopyNumberingMap = null;
    this.ForceCopySectPr  = false;

    // Добавляем дополнительный параграф в самом конце для последней секции документа
    var SectPara = new Paragraph(this.DrawingDocument, this);
    LogicDocument.Content[OverallIndex++] = SectPara;
    LogicDocument.SectPr.Copy(this.SectPr);
    LogicDocument.SectPr.Set_Type(c_oAscSectionBreakType.Continuous);

    for (var Index = 0, Count = LogicDocument.Content.length; Index < Count; Index++)
    {
        if (0 === Index)
            LogicDocument.Content[Index].Prev = null;
        else
            LogicDocument.Content[Index].Prev = LogicDocument.Content[Index - 1];

        if (Count - 1 === Index)
            LogicDocument.Content[Index].Next = null;
        else
            LogicDocument.Content[Index].Next = LogicDocument.Content[Index + 1];

        LogicDocument.Content[Index].Parent = LogicDocument;
    }

    this.FieldsManager = FieldsManager;
    AscCommon.g_oTableId.TurnOn();
    AscCommon.History.TurnOn();

    return LogicDocument;
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// Import
var changestype_2_ElementsArray_and_Type = AscCommon.changestype_2_ElementsArray_and_Type;
var History = AscCommon.History;

//----------------------------------------------------------------------------------------------------------------------
// Работаем с рецензированием
//----------------------------------------------------------------------------------------------------------------------
Asc['asc_docs_api'].prototype.asc_SetTrackRevisions = function(bTrack)
{
	var oLogicDocument = this.WordControl.m_oLogicDocument;
	if (!oLogicDocument)
		return;

	return oLogicDocument.Set_TrackRevisions(bTrack);
};
Asc['asc_docs_api'].prototype.asc_IsTrackRevisions = function()
{
	var oLogicDocument = this.WordControl.m_oLogicDocument;
	if (!oLogicDocument)
		return false;

    return oLogicDocument.Is_TrackRevisions();
};
Asc['asc_docs_api'].prototype.sync_BeginCatchRevisionsChanges = function()
{
    this.RevisionChangesStack = [];
};
Asc['asc_docs_api'].prototype.sync_EndCatchRevisionsChanges = function()
{
    this.sendEvent("asc_onShowRevisionsChange", this.RevisionChangesStack);
};
Asc['asc_docs_api'].prototype.asc_GetRevisionsChangesStack = function()
{
	return this.RevisionChangesStack;
};
Asc['asc_docs_api'].prototype.sync_AddRevisionsChange = function(Change)
{
    this.RevisionChangesStack.push(Change);
};
Asc['asc_docs_api'].prototype.asc_AcceptChanges = function(Change)
{
    if (undefined !== Change)
        this.WordControl.m_oLogicDocument.Accept_RevisionChange(Change);
    else
        this.WordControl.m_oLogicDocument.AcceptRevisionChangesBySelection();
};
Asc['asc_docs_api'].prototype.asc_RejectChanges = function(Change)
{
    if (undefined !== Change)
        this.WordControl.m_oLogicDocument.Reject_RevisionChange(Change);
    else
        this.WordControl.m_oLogicDocument.RejectRevisionChangesBySelection();
};
Asc['asc_docs_api'].prototype.asc_HaveRevisionsChanges = function()
{
    return this.WordControl.m_oLogicDocument.Have_RevisionChanges();
};
Asc['asc_docs_api'].prototype.asc_HaveNewRevisionsChanges = function()
{
    return this.asc_HaveRevisionsChanges();
};
Asc['asc_docs_api'].prototype.asc_GetNextRevisionsChange = function()
{
    return this.WordControl.m_oLogicDocument.Get_NextRevisionChange();
};
Asc['asc_docs_api'].prototype.asc_GetPrevRevisionsChange = function()
{
    return this.WordControl.m_oLogicDocument.Get_PrevRevisionChange();
};
Asc['asc_docs_api'].prototype.sync_UpdateRevisionsChangesPosition = function(X, Y)
{
    this.sendEvent("asc_onUpdateRevisionsChangesPosition", X, Y);
};
Asc['asc_docs_api'].prototype.asc_AcceptAllChanges = function()
{
    this.WordControl.m_oLogicDocument.Accept_AllRevisionChanges();
};
Asc['asc_docs_api'].prototype.asc_RejectAllChanges = function()
{
    this.WordControl.m_oLogicDocument.Reject_AllRevisionChanges();
};
Asc['asc_docs_api'].prototype.asc_GetTrackRevisionsReportByAuthors = function()
{
	var oResult = {};
	var oAllChanges = this.WordControl.m_oLogicDocument.TrackRevisionsManager.Get_AllChanges();
	for (var ParaId in oAllChanges)
	{
		var arrChanges = oAllChanges[ParaId];
		for (var nIndex = 0, nCount = arrChanges.length; nIndex < nCount; ++nIndex)
		{
			var oChange   = arrChanges[nIndex];
			var sUserName = oChange.get_UserName();
			var nDateTime = oChange.get_DateTime();

			if (!oResult[sUserName])
				oResult[sUserName] = [];

			var arrUserChanges = oResult[sUserName];

			var nPos = 0;
			var nLen = arrUserChanges.length;
			while (nPos < nLen)
			{
				if (nDateTime < arrUserChanges[nPos].get_DateTime())
					break;

				nPos++;
			}

			arrUserChanges.splice(nPos, 0, oChange);
		}
	}

	return oResult;
};

Asc['asc_docs_api'].prototype['asc_SetTrackRevisions']                = Asc['asc_docs_api'].prototype.asc_SetTrackRevisions;
Asc['asc_docs_api'].prototype['asc_IsTrackRevisions']                 = Asc['asc_docs_api'].prototype.asc_IsTrackRevisions;
Asc['asc_docs_api'].prototype['sync_BeginCatchRevisionsChanges']      = Asc['asc_docs_api'].prototype.sync_BeginCatchRevisionsChanges;
Asc['asc_docs_api'].prototype['sync_EndCatchRevisionsChanges']        = Asc['asc_docs_api'].prototype.sync_EndCatchRevisionsChanges;
Asc['asc_docs_api'].prototype['sync_AddRevisionsChange']              = Asc['asc_docs_api'].prototype.sync_AddRevisionsChange;
Asc['asc_docs_api'].prototype['asc_AcceptChanges']                    = Asc['asc_docs_api'].prototype.asc_AcceptChanges;
Asc['asc_docs_api'].prototype['asc_RejectChanges']                    = Asc['asc_docs_api'].prototype.asc_RejectChanges;
Asc['asc_docs_api'].prototype['asc_HaveRevisionsChanges']             = Asc['asc_docs_api'].prototype.asc_HaveRevisionsChanges;
Asc['asc_docs_api'].prototype['asc_HaveNewRevisionsChanges']          = Asc['asc_docs_api'].prototype.asc_HaveNewRevisionsChanges;
Asc['asc_docs_api'].prototype['asc_GetNextRevisionsChange']           = Asc['asc_docs_api'].prototype.asc_GetNextRevisionsChange;
Asc['asc_docs_api'].prototype['asc_GetPrevRevisionsChange']           = Asc['asc_docs_api'].prototype.asc_GetPrevRevisionsChange;
Asc['asc_docs_api'].prototype['sync_UpdateRevisionsChangesPosition']  = Asc['asc_docs_api'].prototype.sync_UpdateRevisionsChangesPosition;
Asc['asc_docs_api'].prototype['asc_AcceptAllChanges']                 = Asc['asc_docs_api'].prototype.asc_AcceptAllChanges;
Asc['asc_docs_api'].prototype['asc_RejectAllChanges']                 = Asc['asc_docs_api'].prototype.asc_RejectAllChanges;
Asc['asc_docs_api'].prototype['asc_GetTrackRevisionsReportByAuthors'] = Asc['asc_docs_api'].prototype.asc_GetTrackRevisionsReportByAuthors;
//----------------------------------------------------------------------------------------------------------------------
// CDocument
//----------------------------------------------------------------------------------------------------------------------
CDocument.prototype.Set_TrackRevisions = function(bTrack)
{
    this.TrackRevisions = bTrack;
};
CDocument.prototype.ContinueTrackRevisions = function()
{
    this.TrackRevisionsManager.ContinueTrackRevisions();
};
CDocument.prototype.Get_NextRevisionChange = function()
{
	this.TrackRevisionsManager.ContinueTrackRevisions();
	var oChange = this.TrackRevisionsManager.Get_NextChange();
	if (oChange)
	{
		this.RemoveSelection();
		this.private_SelectRevisionChange(oChange);
		this.Document_UpdateSelectionState();
		this.Document_UpdateInterfaceState(true);
	}
};
CDocument.prototype.Get_PrevRevisionChange = function()
{
	this.TrackRevisionsManager.ContinueTrackRevisions();
	var oChange = this.TrackRevisionsManager.Get_PrevChange();
	if (oChange)
	{
		this.RemoveSelection();
		this.private_SelectRevisionChange(oChange);
		this.Document_UpdateSelectionState();
		this.Document_UpdateInterfaceState(true);
	}
};
CDocument.prototype.GetRevisionsChangeParagraph = function(Direction, CurrentPara)
{
    return this.private_GetRevisionsChangeParagraph(Direction, CurrentPara).Get_FoundedParagraph();
};
CDocument.prototype.private_GetRevisionsChangeParagraph = function(Direction, CurrentPara)
{
    var SearchEngine = new CRevisionsChangeParagraphSearchEngine(Direction, CurrentPara, this.TrackRevisionsManager);
    if (null === CurrentPara)
    {
        CurrentPara = this.GetCurrentParagraph();
        if (null === CurrentPara)
            return SearchEngine;

        SearchEngine.Set_CurrentParagraph(CurrentPara);
        SearchEngine.Set_FoundedParagraph(CurrentPara);
        if (true === SearchEngine.Is_Found())
            return SearchEngine;
    }

    var oFootnote = CurrentPara.Parent ? CurrentPara.Parent.GetTopDocumentContent() : null;
    if (!(oFootnote instanceof CFootEndnote))
    	oFootnote = null;

    var HdrFtr = CurrentPara.Get_HdrFtr();
    if (null !== HdrFtr)
    {
        this.private_GetRevisionsChangeParagraphInHdrFtr(SearchEngine, HdrFtr);

        if (Direction > 0)
		{
			if (true !== SearchEngine.Is_Found())
				this.private_GetRevisionsChangeParagraphInDocument(SearchEngine, 0);

			if (true !== SearchEngine.Is_Found())
				this.private_GetRevisionsChangeParagraphInFooters(SearchEngine, null);
		}
		else
		{
			if (true !== SearchEngine.Is_Found())
				this.private_GetRevisionsChangeParagraphInFooters(SearchEngine, null);

			if (true !== SearchEngine.Is_Found())
				this.private_GetRevisionsChangeParagraphInDocument(SearchEngine, this.Content.length - 1);
		}


        if (true !== SearchEngine.Is_Found())
            this.private_GetRevisionsChangeParagraphInHdrFtr(SearchEngine, null);
    }
    else if (oFootnote)
	{
		this.private_GetRevisionsChangeParagraphInFooters(SearchEngine, oFootnote);

		if (Direction > 0)
		{
			if (true !== SearchEngine.Is_Found())
				this.private_GetRevisionsChangeParagraphInHdrFtr(SearchEngine, null);

			if (true !== SearchEngine.Is_Found())
				this.private_GetRevisionsChangeParagraphInDocument(SearchEngine, 0);
		}
		else
		{
			if (true !== SearchEngine.Is_Found())
				this.private_GetRevisionsChangeParagraphInDocument(SearchEngine, this.Content.length - 1);

			if (true !== SearchEngine.Is_Found())
				this.private_GetRevisionsChangeParagraphInHdrFtr(SearchEngine, null);
		}

		if (true !== SearchEngine.Is_Found())
			this.private_GetRevisionsChangeParagraphInFooters(SearchEngine, null);
	}
    else
    {
        var Pos = (true === this.Selection.Use && docpostype_DrawingObjects !== this.Get_DocPosType() ? (this.Selection.StartPos <= this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos) : this.CurPos.ContentPos);
        this.private_GetRevisionsChangeParagraphInDocument(SearchEngine, Pos);

        if (Direction > 0)
		{
			if (true !== SearchEngine.Is_Found())
				this.private_GetRevisionsChangeParagraphInFooters(SearchEngine, null);

			if (true !== SearchEngine.Is_Found())
				this.private_GetRevisionsChangeParagraphInHdrFtr(SearchEngine, null);
		}
		else
		{
			if (true !== SearchEngine.Is_Found())
				this.private_GetRevisionsChangeParagraphInHdrFtr(SearchEngine, null);

			if (true !== SearchEngine.Is_Found())
				this.private_GetRevisionsChangeParagraphInFooters(SearchEngine, null);
		}

        if (true !== SearchEngine.Is_Found())
            this.private_GetRevisionsChangeParagraphInDocument(SearchEngine, Direction > 0 ? 0 : this.Content.length - 1);
    }

    return SearchEngine;
};
CDocument.prototype.private_GetRevisionsChangeParagraphInDocument = function(SearchEngine, Pos)
{
    var Direction = SearchEngine.Get_Direction();
    this.Content[Pos].GetRevisionsChangeParagraph(SearchEngine);
    while (true !== SearchEngine.Is_Found())
    {
        Pos = (Direction > 0 ? Pos + 1 : Pos - 1);
        if (Pos >= this.Content.length || Pos < 0)
            break;

        this.Content[Pos].GetRevisionsChangeParagraph(SearchEngine);
    }
};
CDocument.prototype.private_GetRevisionsChangeParagraphInHdrFtr = function(SearchEngine, HdrFtr)
{
    var AllHdrFtrs = this.SectionsInfo.Get_AllHdrFtrs();
    var Count = AllHdrFtrs.length;

    if (Count <= 0)
        return;

    var Pos = -1;
    if (null !== HdrFtr)
    {
        for (var Index = 0; Index < Count; ++Index)
        {
            if (HdrFtr === AllHdrFtrs[Index])
            {
                Pos = Index;
                break;
            }
        }
    }

    var Direction = SearchEngine.Get_Direction();
    if (Pos < 0 || Pos >= Count)
    {
        if (Direction > 0)
            Pos = 0;
        else
            Pos = Count - 1;
    }

    AllHdrFtrs[Pos].GetRevisionsChangeParagraph(SearchEngine);
    while (true !== SearchEngine.Is_Found())
    {
        Pos = (Direction > 0 ? Pos + 1 : Pos - 1);
        if (Pos >= Count || Pos < 0)
            break;

        AllHdrFtrs[Pos].GetRevisionsChangeParagraph(SearchEngine);
    }
};
CDocument.prototype.private_GetRevisionsChangeParagraphInFooters = function(SearchEngine, oFootnote)
{
	var arrFootnotes = this.Get_FootnotesList(null, null);
	var nCount = arrFootnotes.length;
	if (nCount <= 0)
		return;

	var nPos = -1;
	if (oFootnote)
	{
		for (var nIndex = 0; nIndex < nCount; ++nIndex)
		{
			if (arrFootnotes[nPos] === oFootnote)
			{
				nPos = nIndex;
				break;
			}
		}
	}

	var nDirection = SearchEngine.Get_Direction();
	if (nPos < 0 || nPos >= nCount)
	{
		if (nDirection > 0)
			nPos = 0;
		else
			nPos = nCount - 1;
	}

	arrFootnotes[nPos].GetRevisionsChangeParagraph(SearchEngine);
	while (true !== SearchEngine.Is_Found())
	{
		nPos = (nDirection > 0 ? nPos + 1 : nPos - 1);
		if (nPos >= nCount || nPos < 0)
			break;

		arrFootnotes[nPos].GetRevisionsChangeParagraph(SearchEngine);
	}
};
CDocument.prototype.private_SelectRevisionChange = function(oChange)
{
	if (oChange && oChange.get_Paragraph())
	{
		this.RemoveSelection();
		var oParagraph = oChange.get_Paragraph();

		if (this.TrackRevisionsManager.CompleteTrackChangesForElements([oParagraph]))
			return;

		oParagraph.Selection.Use = true;
		oParagraph.Set_SelectionContentPos(oChange.get_StartPos(), oChange.get_EndPos());
		oParagraph.Set_ParaContentPos(oChange.get_StartPos(), false, -1, -1);
		oParagraph.Document_SetThisElementCurrent(false);
	}
};
CDocument.prototype.Accept_RevisionChange = function(oChange)
{
	if (oChange)
	{
		var arrRelatedParas = this.TrackRevisionsManager.GetChangeRelatedParagraphs(oChange, true);

		if (this.TrackRevisionsManager.CompleteTrackChangesForElements(arrRelatedParas))
		{
			this.Document_UpdateInterfaceState();
			this.Document_UpdateSelectionState();
			return;
		}

		if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_None, {
				Type      : changestype_2_ElementsArray_and_Type,
				Elements  : arrRelatedParas,
				CheckType : AscCommon.changestype_Paragraph_Content
			}))
		{
			this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AcceptRevisionChange);
			this.private_SelectRevisionChange(oChange);
			this.AcceptRevisionChanges(oChange.get_Type(), false);
		}
	}
};
CDocument.prototype.Reject_RevisionChange = function(oChange)
{
	if (oChange)
	{
		var arrRelatedParas = this.TrackRevisionsManager.GetChangeRelatedParagraphs(oChange, false);

		if (this.TrackRevisionsManager.CompleteTrackChangesForElements(arrRelatedParas))
		{
			this.Document_UpdateInterfaceState();
			this.Document_UpdateSelectionState();
			return;
		}

		if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_None, {
				Type      : changestype_2_ElementsArray_and_Type,
				Elements  : arrRelatedParas,
				CheckType : AscCommon.changestype_Paragraph_Content
			}))
		{
			this.Create_NewHistoryPoint(AscDFH.historydescription_Document_RejectRevisionChange);
			this.private_SelectRevisionChange(oChange);
			this.RejectRevisionChanges(oChange.get_Type(), false);
		}
	}
};
CDocument.prototype.AcceptRevisionChangesBySelection = function()
{
    var CurrentChange = this.TrackRevisionsManager.Get_CurrentChange();
    if (null !== CurrentChange)
	{
		this.Accept_RevisionChange(CurrentChange);
	}
    else
    {
        var SelectedParagraphs = this.GetAllParagraphs({Selected : true});
        var RelatedParas = this.TrackRevisionsManager.Get_AllChangesRelatedParagraphsBySelectedParagraphs(SelectedParagraphs, true);
        if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_None, { Type : changestype_2_ElementsArray_and_Type, Elements : RelatedParas, CheckType : AscCommon.changestype_Paragraph_Content}))
        {
            this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AcceptRevisionChangesBySelection);
            this.AcceptRevisionChanges(undefined, false);

            if (true === this.History.Is_LastPointEmpty())
                this.History.Remove_LastPoint();
        }
    }

    this.TrackRevisionsManager.Clear_CurrentChange();
    this.Get_NextRevisionChange();
};
CDocument.prototype.RejectRevisionChangesBySelection = function()
{
    var CurrentChange = this.TrackRevisionsManager.Get_CurrentChange();
    if (null !== CurrentChange)
	{
		this.Reject_RevisionChange(CurrentChange);
	}
    else
    {
        var SelectedParagraphs = this.GetAllParagraphs({Selected : true});
        var RelatedParas = this.TrackRevisionsManager.Get_AllChangesRelatedParagraphsBySelectedParagraphs(SelectedParagraphs, false);
        if (false === this.Document_Is_SelectionLocked(AscCommon.changestype_None, { Type : changestype_2_ElementsArray_and_Type, Elements : RelatedParas, CheckType : AscCommon.changestype_Paragraph_Content}))
        {
            this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AcceptRevisionChangesBySelection);
            this.RejectRevisionChanges(undefined, false);

            if (true === this.History.Is_LastPointEmpty())
                this.History.Remove_LastPoint();
        }
    }

	this.TrackRevisionsManager.Clear_CurrentChange();
    this.Get_NextRevisionChange();
};
CDocument.prototype.Accept_AllRevisionChanges = function(isSkipCheckLock)
{
    var RelatedParas = this.TrackRevisionsManager.Get_AllChangesRelatedParagraphs(true);
    if (true === isSkipCheckLock || false === this.Document_Is_SelectionLocked(AscCommon.changestype_None, { Type : changestype_2_ElementsArray_and_Type, Elements : RelatedParas, CheckType : AscCommon.changestype_Paragraph_Content}))
    {
        this.Create_NewHistoryPoint(AscDFH.historydescription_Document_AcceptAllRevisionChanges);
        var LogicDocuments = this.TrackRevisionsManager.Get_AllChangesLogicDocuments();
        for (var LogicDocId in LogicDocuments)
        {
            var LogicDoc = AscCommon.g_oTableId.Get_ById(LogicDocId);
            if (LogicDoc)
            {
                LogicDoc.AcceptRevisionChanges(undefined, true);
            }
        }

        if (true !== isSkipCheckLock && true === this.History.Is_LastPointEmpty())
        {
            this.History.Remove_LastPoint();
            return;
        }

        this.RemoveSelection();
        this.private_CorrectDocumentPosition();
        this.Recalculate();
        this.Document_UpdateSelectionState();
        this.Document_UpdateInterfaceState();
    }
};
CDocument.prototype.Reject_AllRevisionChanges = function(isSkipCheckLock)
{
    var RelatedParas = this.TrackRevisionsManager.Get_AllChangesRelatedParagraphs(false);
    if (true === isSkipCheckLock || false === this.Document_Is_SelectionLocked(AscCommon.changestype_None, { Type : changestype_2_ElementsArray_and_Type, Elements : RelatedParas, CheckType : AscCommon.changestype_Paragraph_Content}))
    {
        this.Create_NewHistoryPoint(AscDFH.historydescription_Document_RejectAllRevisionChanges);

        this.private_RejectAllRevisionChanges();

        if (true !== isSkipCheckLock && true === this.History.Is_LastPointEmpty())
        {
            this.History.Remove_LastPoint();
            return;
        }

        this.RemoveSelection();
        this.private_CorrectDocumentPosition();
        this.Recalculate();
        this.Document_UpdateSelectionState();
        this.Document_UpdateInterfaceState();
    }
};
CDocument.prototype.private_RejectAllRevisionChanges = function()
{
	var LogicDocuments = this.TrackRevisionsManager.Get_AllChangesLogicDocuments();
	for (var LogicDocId in LogicDocuments)
	{
		var LogicDoc = this.TableId.Get_ById(LogicDocId);
		if (LogicDoc)
		{
			LogicDoc.RejectRevisionChanges(undefined, true);
		}
	}
};
CDocument.prototype.AcceptRevisionChanges = function(Type, bAll)
{
    // Принимаем все изменения, которые попали в селект.
    // Принимаем изменения в следующей последовательности:
    // 1. Изменение настроек параграфа
    // 2. Изменение настроек текста
    // 3. Добавление/удаление текста
    // 4. Добавление/удаление параграфа
    if (docpostype_Content === this.CurPos.Type || true === bAll)
    {
        if (true === this.Selection.Use || true === bAll)
        {
            var StartPos = this.Selection.StartPos;
            var EndPos = this.Selection.EndPos;
            if (StartPos > EndPos)
            {
                StartPos = this.Selection.EndPos;
                EndPos = this.Selection.StartPos;
            }

            var LastElement = this.Content[EndPos];
            var LastParaEnd = (type_Paragraph === LastElement.Get_Type() && true === LastElement.Selection_CheckParaEnd() ? true : false);

            if (true === bAll)
            {
                StartPos = 0;
                EndPos = this.Content.length - 1;
                LastParaEnd = true;
            }

            if (undefined === Type || c_oAscRevisionsChangeType.ParaPr === Type)
            {
                for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
                {
                    var Element = this.Content[CurPos];
                    if (type_Paragraph === Element.Get_Type() && (true === Element.IsSelectedAll() || true == bAll) && true === Element.Have_PrChange())
                    {
                        Element.Accept_PrChange();
                    }
                }
            }

            for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
            {
                var Element = this.Content[CurPos];
                Element.AcceptRevisionChanges(Type, bAll);
            }

            if (undefined === Type || c_oAscRevisionsChangeType.ParaAdd === Type || c_oAscRevisionsChangeType.ParaRem === Type)
            {
                EndPos = (true === LastParaEnd ? EndPos : EndPos - 1);
                for (var CurPos = EndPos; CurPos >= StartPos; CurPos--)
                {
                    var Element = this.Content[CurPos];
                    if (type_Paragraph === Element.Get_Type())
                    {
                        var ReviewType = Element.Get_ReviewType();
                        if (reviewtype_Add === ReviewType && (undefined === Type || c_oAscRevisionsChangeType.ParaAdd === Type))
                        {
                            Element.Set_ReviewType(reviewtype_Common);
                        }
                        else if (reviewtype_Remove === ReviewType && (undefined === Type || c_oAscRevisionsChangeType.ParaRem === Type))
                        {
                            Element.Set_ReviewType(reviewtype_Common);
                            this.Concat_Paragraphs(CurPos);
                        }
                    }
                }
            }
        }
    }
    else if (docpostype_HdrFtr === this.CurPos.Type)
    {
        this.HdrFtr.AcceptRevisionChanges(Type, bAll);
    }
    else if (docpostype_DrawingObjects === this.CurPos.Type)
    {
        this.DrawingObjects.AcceptRevisionChanges(Type, bAll);
    }
    else if (docpostype_Footnotes === this.CurPos.Type)
	{
		this.Footnotes.AcceptRevisionChanges(Type, bAll);
	}

    if (true !== bAll)
    {
        this.Recalculate();
        this.Document_UpdateInterfaceState();
        this.Document_UpdateSelectionState();
    }
};
CDocument.prototype.RejectRevisionChanges = function(Type, bAll)
{
    // Отменяем все изменения, которые попали в селект.
    // Отменяем изменения в следующей последовательности:
    // 1. Изменение настроек параграфа
    // 2. Изменение настроек текста
    // 3. Добавление/удаление текста
    // 4. Добавление/удаление параграфа

    if (docpostype_Content === this.CurPos.Type || true === bAll)
    {
        if (true === this.Selection.Use || true === bAll)
        {
            var StartPos = this.Selection.StartPos;
            var EndPos = this.Selection.EndPos;
            if (StartPos > EndPos)
            {
                StartPos = this.Selection.EndPos;
                EndPos = this.Selection.StartPos;
            }

            var LastElement = this.Content[EndPos];
            var LastParaEnd = (type_Paragraph === LastElement.Get_Type() && true === LastElement.Selection_CheckParaEnd() ? true : false);

            if (true === bAll)
            {
                StartPos = 0;
                EndPos = this.Content.length - 1;
                LastParaEnd = true;
            }

            if (undefined === Type || c_oAscRevisionsChangeType.ParaPr === Type)
            {
                for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
                {
                    var Element = this.Content[CurPos];
                    if (type_Paragraph === Element.Get_Type() && (true === Element.IsSelectedAll() || true === bAll) && true === Element.Have_PrChange())
                    {
                        Element.Reject_PrChange();
                    }
                }
            }

            for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
            {
                var Element = this.Content[CurPos];
                Element.RejectRevisionChanges(Type, bAll);
            }

            if (undefined === Type || c_oAscRevisionsChangeType.ParaAdd === Type || c_oAscRevisionsChangeType.ParaRem === Type)
            {
                EndPos = (true === LastParaEnd ? EndPos : EndPos - 1);
                for (var CurPos = EndPos; CurPos >= StartPos; CurPos--)
                {
                    var Element = this.Content[CurPos];
                    if (type_Paragraph === Element.Get_Type())
                    {
                        var ReviewType = Element.Get_ReviewType();
                        if (reviewtype_Add === ReviewType && (undefined === Type || c_oAscRevisionsChangeType.ParaAdd === Type))
                        {
                            Element.Set_ReviewType(reviewtype_Common);
                            this.Concat_Paragraphs(CurPos);
                        }
                        else if (reviewtype_Remove === ReviewType && (undefined === Type || c_oAscRevisionsChangeType.ParaRem === Type))
                        {
                            Element.Set_ReviewType(reviewtype_Common);
                        }
                    }
                }
            }
        }
    }
    else if (docpostype_HdrFtr === this.CurPos.Type)
    {
        this.HdrFtr.RejectRevisionChanges(Type, bAll);
    }
    else if (docpostype_DrawingObjects === this.CurPos.Type)
    {
        this.DrawingObjects.RejectRevisionChanges(Type, bAll);
    }
    else if (docpostype_Footnotes === this.CurPos.Type)
	{
		this.Footnotes.RejectRevisionChanges(Type, bAll);
	}

    if (true !== bAll)
    {
        this.Recalculate();
        this.Document_UpdateInterfaceState();
        this.Document_UpdateSelectionState();
    }
};
CDocument.prototype.Have_RevisionChanges = function()
{
    this.TrackRevisionsManager.ContinueTrackRevisions();
    return this.TrackRevisionsManager.HaveOtherUsersChanges();
};
//----------------------------------------------------------------------------------------------------------------------
// CHeaderFooterController
//----------------------------------------------------------------------------------------------------------------------
CHeaderFooterController.prototype.AcceptRevisionChanges = function(Type, bAll)
{
    if (null !== this.CurHdrFtr)
        this.CurHdrFtr.Content.AcceptRevisionChanges(Type, bAll);
};
CHeaderFooterController.prototype.RejectRevisionChanges = function(Type, bAll)
{
    if (null !== this.CurHdrFtr)
        this.CurHdrFtr.Content.RejectRevisionChanges(Type, bAll);
};
//----------------------------------------------------------------------------------------------------------------------
// CDocumentContent
//----------------------------------------------------------------------------------------------------------------------
CDocumentContent.prototype.AcceptRevisionChanges = function(Type, bAll)
{
    if (docpostype_Content === this.CurPos.Type || true === bAll)
    {
        if (true === this.Selection.Use || true === bAll)
        {
            var StartPos = this.Selection.StartPos;
            var EndPos   = this.Selection.EndPos;
            if (StartPos > EndPos)
            {
                StartPos = this.Selection.EndPos;
                EndPos   = this.Selection.StartPos;
            }
            var LastElement = this.Content[EndPos];
            var LastParaEnd = (type_Paragraph === LastElement.Get_Type() && true === LastElement.Selection_CheckParaEnd() ? true : false);

            if (true === bAll)
            {
                StartPos    = 0;
                EndPos      = this.Content.length - 1;
                LastParaEnd = true;
            }

            if (undefined === Type || c_oAscRevisionsChangeType.ParaPr === Type)
            {
                for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
                {
                    var Element = this.Content[CurPos];
                    if (type_Paragraph === Element.Get_Type() && (true === Element.IsSelectedAll() || true === bAll) && true === Element.Have_PrChange())
                    {
                        Element.Accept_PrChange();
                    }
                }
            }

            for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
            {
                var Element = this.Content[CurPos];
                Element.AcceptRevisionChanges(Type, bAll);
            }

            if (undefined === Type || c_oAscRevisionsChangeType.ParaAdd === Type || c_oAscRevisionsChangeType.ParaRem === Type)
            {
                EndPos = (true === LastParaEnd ? EndPos : EndPos - 1);
                for (var CurPos = EndPos; CurPos >= StartPos; CurPos--)
                {
                    var Element = this.Content[CurPos];
                    if (type_Paragraph === Element.Get_Type())
                    {
                        var ReviewType = Element.Get_ReviewType();
                        if (reviewtype_Add === ReviewType && (undefined === Type || c_oAscRevisionsChangeType.ParaAdd === Type))
                        {
                            Element.Set_ReviewType(reviewtype_Common);
                        }
                        else if (reviewtype_Remove === ReviewType && (undefined === Type || c_oAscRevisionsChangeType.ParaRem === Type))
                        {
                            Element.Set_ReviewType(reviewtype_Common);
                            this.Concat_Paragraphs(CurPos);
                        }
                    }
                }
            }
        }
    }
    else if (docpostype_DrawingObjects === this.CurPos.Type)
    {
        this.DrawingObjects.AcceptRevisionChanges(Type, bAll);
    }
};
CDocumentContent.prototype.RejectRevisionChanges = function(Type, bAll)
{
    if (docpostype_Content === this.CurPos.Type || true === bAll)
    {
        if (true === this.Selection.Use || true === bAll)
        {
            var StartPos = this.Selection.StartPos;
            var EndPos = this.Selection.EndPos;
            if (StartPos > EndPos)
            {
                StartPos = this.Selection.EndPos;
                EndPos = this.Selection.StartPos;
            }
            var LastElement = this.Content[EndPos];
            var LastParaEnd = (type_Paragraph === LastElement.Get_Type() && true === LastElement.Selection_CheckParaEnd() ? true : false);

            if (true === bAll)
            {
                StartPos = 0;
                EndPos = this.Content.length - 1;
                LastParaEnd = true;
            }

            if (undefined === Type || c_oAscRevisionsChangeType.ParaPr === Type)
            {
                for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
                {
                    var Element = this.Content[CurPos];
                    if (type_Paragraph === Element.Get_Type() && (true === Element.IsSelectedAll() || true === bAll) && true === Element.Have_PrChange())
                    {
                        Element.Reject_PrChange();
                    }
                }
            }

            for (var CurPos = StartPos; CurPos <= EndPos; CurPos++)
            {
                var Element = this.Content[CurPos];
                Element.RejectRevisionChanges(Type, bAll);
            }

            if (undefined === Type || c_oAscRevisionsChangeType.ParaAdd === Type || c_oAscRevisionsChangeType.ParaRem === Type)
            {
                EndPos = (true === LastParaEnd ? EndPos : EndPos - 1);
                for (var CurPos = EndPos; CurPos >= StartPos; CurPos--)
                {
                    var Element = this.Content[CurPos];
                    if (type_Paragraph === Element.Get_Type())
                    {
                        var ReviewType = Element.Get_ReviewType();
                        if (reviewtype_Add === ReviewType && (undefined === Type || c_oAscRevisionsChangeType.ParaAdd === Type))
                        {
                            Element.Set_ReviewType(reviewtype_Common);
                            this.Concat_Paragraphs(CurPos);
                        }
                        else if (reviewtype_Remove === ReviewType && (undefined === Type || c_oAscRevisionsChangeType.ParaRem === Type))
                        {
                            Element.Set_ReviewType(reviewtype_Common);
                        }
                    }
                }
            }
        }
    }
    else if (docpostype_DrawingObjects === this.CurPos.Type)
    {
        this.DrawingObjects.RejectRevisionChanges(Type, bAll);
    }
};
CDocumentContent.prototype.GetRevisionsChangeParagraph = function(SearchEngine)
{
    if (true === SearchEngine.Is_Found())
        return;

    var Direction = SearchEngine.Get_Direction();
    var Pos = 0;
    if (true !== SearchEngine.Is_CurrentFound())
    {
        Pos = (true === this.Selection.Use ? (this.Selection.StartPos <= this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos) : this.CurPos.ContentPos);
    }
    else
    {
        if (Direction > 0)
        {
            Pos = 0;
        }
        else
        {
            Pos = this.Content.length - 1;
        }
    }

    this.Content[Pos].GetRevisionsChangeParagraph(SearchEngine);
    while (true !== SearchEngine.Is_Found())
    {
        Pos = (Direction > 0 ? Pos + 1 : Pos - 1);
        if (Pos >= this.Content.length || Pos < 0)
            break;

        this.Content[Pos].GetRevisionsChangeParagraph(SearchEngine);
    }
};
//----------------------------------------------------------------------------------------------------------------------
// CFootnotesController
//----------------------------------------------------------------------------------------------------------------------
CFootnotesController.prototype.AcceptRevisionChanges = function(Type, bAll)
{
	if (null !== this.CurFootnote)
		this.CurFootnote.AcceptRevisionChanges(Type, bAll);
};
CFootnotesController.prototype.RejectRevisionChanges = function(Type, bAll)
{
	if (null !== this.CurFootnote)
		this.CurFootnote.RejectRevisionChanges(Type, bAll);
};
/*
 * (c) Copyright Ascensio System SIA 2010-2018
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

// Import
var locktype_None = AscCommon.locktype_None;
var locktype_Mine = AscCommon.locktype_Mine;

if(typeof CDocument !== "undefined")
{
	CDocument.prototype.Document_Is_SelectionLocked = function(CheckType, AdditionalData, DontLockInFastMode, isIgnoreCanEditFlag)
	{
		if (!this.CanEdit() && true !== isIgnoreCanEditFlag)
			return true;

		if (true === AscCommon.CollaborativeEditing.Get_GlobalLock())
			return true;

		AscCommon.CollaborativeEditing.OnStart_CheckLock();

		this.private_DocumentIsSelectionLocked(CheckType);

		if ("undefined" != typeof(AdditionalData) && null != AdditionalData)
		{
			if (AscCommon.changestype_2_InlineObjectMove === AdditionalData.Type)
			{
				var PageNum = AdditionalData.PageNum;
				var X       = AdditionalData.X;
				var Y       = AdditionalData.Y;

				var NearestPara = this.Get_NearestPos(PageNum, X, Y).Paragraph;
				NearestPara.Document_Is_SelectionLocked(AscCommon.changestype_Document_Content);
			}
			else if (AscCommon.changestype_2_HdrFtr === AdditionalData.Type)
			{
				this.HdrFtr.Document_Is_SelectionLocked(AscCommon.changestype_HdrFtr);
			}
			else if (AscCommon.changestype_2_Comment === AdditionalData.Type)
			{
				this.Comments.Document_Is_SelectionLocked(AdditionalData.Id);
			}
			else if (AscCommon.changestype_2_Element_and_Type === AdditionalData.Type)
			{
				AdditionalData.Element.Document_Is_SelectionLocked(AdditionalData.CheckType, false);
			}
			else if (AscCommon.changestype_2_ElementsArray_and_Type === AdditionalData.Type)
			{
				var Count = AdditionalData.Elements.length;
				for (var Index = 0; Index < Count; Index++)
				{
					AdditionalData.Elements[Index].Document_Is_SelectionLocked(AdditionalData.CheckType, false);
				}
			}
			else if (AscCommon.changestype_2_Element_and_Type_Array === AdditionalData.Type)
			{
				var nCount = Math.min(AdditionalData.Elements.length, AdditionalData.CheckTypes.length);
				for (var nIndex = 0; nIndex < nCount; ++nIndex)
				{
					AdditionalData.Elements[nIndex].Document_Is_SelectionLocked(AdditionalData.CheckTypes[nIndex], false);
				}
			}
			else if (AscCommon.changestype_2_AdditionalTypes === AdditionalData.Type)
			{
				var Count = AdditionalData.Types.length;
				for (var Index = 0; Index < Count; ++Index)
				{
					this.private_DocumentIsSelectionLocked(AdditionalData.Types[Index]);
				}
			}
		}

		var bResult = AscCommon.CollaborativeEditing.OnEnd_CheckLock(DontLockInFastMode);

		if (true === bResult)
		{
			this.Document_UpdateSelectionState();
			this.Document_UpdateInterfaceState();
			//this.Document_UpdateRulersState();
		}

		return bResult;
	};
	CDocument.prototype.private_DocumentIsSelectionLocked = function(CheckType)
	{
		if (AscCommon.changestype_None != CheckType)
		{
			if (AscCommon.changestype_Document_SectPr === CheckType)
			{
				this.Lock.Check(this.Get_Id());
			}
			else if (AscCommon.changestype_Document_Styles === CheckType)
			{
				this.Styles.Lock.Check(this.Styles.Get_Id());
			}
			else if (AscCommon.changestype_ColorScheme === CheckType)
			{
				this.DrawingObjects.Lock.Check(this.DrawingObjects.Get_Id());
			}
			else
			{
				this.Controller.IsSelectionLocked(CheckType);
			}
		}
	};
	CDocumentControllerBase.prototype.IsSelectionLocked  = function(CheckType)
	{
	};
	CLogicDocumentController.prototype.IsSelectionLocked = function(CheckType)
	{
		this.LogicDocument.controller_IsSelectionLocked(CheckType);
	};
	CDocument.prototype.controller_IsSelectionLocked = function(CheckType)
	{
		switch (this.Selection.Flag)
		{
			case selectionflag_Common :
			{
				if (true === this.Selection.Use)
				{
					var StartPos = ( this.Selection.StartPos > this.Selection.EndPos ? this.Selection.EndPos : this.Selection.StartPos );
					var EndPos   = ( this.Selection.StartPos > this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos );

					if (StartPos != EndPos && AscCommon.changestype_Delete === CheckType)
						CheckType = AscCommon.changestype_Remove;

					for (var Index = StartPos; Index <= EndPos; Index++)
						this.Content[Index].Document_Is_SelectionLocked(CheckType);
				}
				else
				{
					var CurElement = this.Content[this.CurPos.ContentPos];

					if (AscCommon.changestype_Document_Content_Add === CheckType && type_Paragraph === CurElement.GetType() && true === CurElement.IsCursorAtEnd())
						AscCommon.CollaborativeEditing.Add_CheckLock(false);
					else
						this.Content[this.CurPos.ContentPos].Document_Is_SelectionLocked(CheckType);
				}

				break;
			}
			case selectionflag_Numbering:
			{
				var oNumPr = this.Selection.Data.CurPara.GetNumPr();
				if (oNumPr)
				{
					var oNum = this.GetNumbering().GetNum(oNumPr.NumId);
					oNum.IsSelectionLocked(CheckType);
				}

				this.Content[this.CurPos.ContentPos].Document_Is_SelectionLocked(CheckType);

				break;
			}
		}
	};
	CHdrFtrController.prototype.IsSelectionLocked = function(CheckType)
	{
		this.HdrFtr.Document_Is_SelectionLocked(CheckType);
	};
	CDrawingsController.prototype.IsSelectionLocked = function(CheckType)
	{
		this.DrawingObjects.documentIsSelectionLocked(CheckType);
	};
	CFootnotesController.prototype.IsSelectionLocked = function(CheckType)
	{
		for (var sId in this.Selection.Footnotes)
		{
			var oFootnote = this.Selection.Footnotes[sId];
			oFootnote.Document_Is_SelectionLocked(CheckType);
		}
	};
}

if(typeof CHeaderFooterController !== "undefined")
{
    CHeaderFooterController.prototype.Document_Is_SelectionLocked = function(CheckType)
    {
        // Любое действие внутри колонтитула лочит его
        this.Lock.Check(this.Get_Id());
    };
}

CNum.prototype.Document_Is_SelectionLocked = function(nCheckType)
{
	return this.IsSelectionLocked(nCheckType);
};
CNum.prototype.IsSelectionLocked = function(nCheckType)
{
	switch (nCheckType)
	{
		case AscCommon.changestype_Paragraph_Content:
		case AscCommon.changestype_Paragraph_Properties:
		case AscCommon.changestype_Paragraph_AddText:
		case AscCommon.changestype_ContentControl_Add:
		{
			this.Lock.Check(this.Get_Id());
			break;
		}
		case AscCommon.changestype_Document_Content:
		case AscCommon.changestype_Document_Content_Add:
		case AscCommon.changestype_Image_Properties:
		{
			AscCommon.CollaborativeEditing.Add_CheckLock(true);
			break;
		}
	}

	var oAbstractNum = this.Numbering.GetAbstractNum(this.AbstractNumId);
	if (oAbstractNum)
		oAbstractNum.IsSelectionLocked(nCheckType);
};
CAbstractNum.prototype.Document_Is_SelectionLocked = function(nCheckType)
{
	return this.IsSelectionLocked(nCheckType);
};
CAbstractNum.prototype.IsSelectionLocked = function(nCheckType)
{
	switch (nCheckType)
	{
		case AscCommon.changestype_Paragraph_Content:
		case AscCommon.changestype_Paragraph_Properties:
		case AscCommon.changestype_Paragraph_AddText:
		case AscCommon.changestype_ContentControl_Add:
		{
			this.Lock.Check(this.Get_Id());
			break;
		}
		case AscCommon.changestype_Document_Content:
		case AscCommon.changestype_Document_Content_Add:
		case AscCommon.changestype_Image_Properties:
		{
			AscCommon.CollaborativeEditing.Add_CheckLock(true);
			break;
		}
	}
};

if(typeof CGraphicObjects !== "undefined")
{
    CGraphicObjects.prototype.Document_Is_SelectionLocked = function(CheckType)
    {
        if(CheckType === AscCommon.changestype_ColorScheme)
        {
            this.Lock.Check(this.Get_Id());
        }
    };


    CGraphicObjects.prototype.documentIsSelectionLocked = function(CheckType)
    {
        var oDrawing, i;
        var bDelete = (AscCommon.changestype_Delete === CheckType || AscCommon.changestype_Remove === CheckType);
        if(AscCommon.changestype_Drawing_Props === CheckType
            || AscCommon.changestype_Image_Properties === CheckType
            || AscCommon.changestype_Delete === CheckType
            || AscCommon.changestype_Remove === CheckType
            || AscCommon.changestype_Paragraph_Content === CheckType
			|| AscCommon.changestype_Paragraph_AddText === CheckType
			|| AscCommon.changestype_ContentControl_Add === CheckType
            || AscCommon.changestype_Paragraph_Properties === CheckType
            || AscCommon.changestype_Document_Content_Add === CheckType)
        {
            for(i = 0; i < this.selectedObjects.length; ++i)
            {
                oDrawing = this.selectedObjects[i].parent;
                if(bDelete)
                {
                    oDrawing.CheckContentControlDeletingLock();
                }
                oDrawing.Lock.Check(oDrawing.Get_Id());
            }
        }
    };
}

ParaDrawing.prototype.Document_Is_SelectionLocked = function(CheckType)
{
    if(CheckType === AscCommon.changestype_Drawing_Props)
    {
        this.Lock.Check(this.Get_Id());
    }
};
CStyle.prototype.Document_Is_SelectionLocked = function(CheckType)
{
    switch ( CheckType )
    {
        case AscCommon.changestype_Paragraph_Content:
        case AscCommon.changestype_Paragraph_Properties:
		case AscCommon.changestype_Paragraph_AddText:
		case AscCommon.changestype_ContentControl_Add:
        case AscCommon.changestype_Document_Content:
        case AscCommon.changestype_Document_Content_Add:
        case AscCommon.changestype_Image_Properties:
        case AscCommon.changestype_Remove:
        case AscCommon.changestype_Delete:
        case AscCommon.changestype_Document_SectPr:
        case AscCommon.changestype_Table_Properties:
        case AscCommon.changestype_Table_RemoveCells:
        case AscCommon.changestype_HdrFtr:
        {
            AscCommon.CollaborativeEditing.Add_CheckLock(true);
            break;
        }
    }
};
CStyles.prototype.Document_Is_SelectionLocked = function(CheckType)
{
    switch ( CheckType )
    {
        case AscCommon.changestype_Paragraph_Content:
        case AscCommon.changestype_Paragraph_Properties:
		case AscCommon.changestype_Paragraph_AddText:
		case AscCommon.changestype_ContentControl_Add:
        case AscCommon.changestype_Document_Content:
        case AscCommon.changestype_Document_Content_Add:
        case AscCommon.changestype_Image_Properties:
        case AscCommon.changestype_Remove:
        case AscCommon.changestype_Delete:
        case AscCommon.changestype_Document_SectPr:
        case AscCommon.changestype_Table_Properties:
        case AscCommon.changestype_Table_RemoveCells:
        case AscCommon.changestype_HdrFtr:
        {
            AscCommon.CollaborativeEditing.Add_CheckLock(true);
            break;
        }
    }
};
CDocumentContent.prototype.Document_Is_SelectionLocked = function(CheckType)
{
    if ( true === this.ApplyToAll )
    {
        var Count = this.Content.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            this.Content[Index].Set_ApplyToAll( true );
            this.Content[Index].Document_Is_SelectionLocked(CheckType);
            this.Content[Index].Set_ApplyToAll( false );
        }
        return;
    }
    else
    {
        if ( docpostype_DrawingObjects === this.CurPos.Type )
        {
            this.LogicDocument.DrawingObjects.documentIsSelectionLocked(CheckType);
        }
        else if ( docpostype_Content == this.CurPos.Type )
        {
            switch ( this.Selection.Flag )
            {
                case selectionflag_Common :
                {
                    if ( true === this.Selection.Use )
                    {
                        var StartPos = ( this.Selection.StartPos > this.Selection.EndPos ? this.Selection.EndPos : this.Selection.StartPos );
                        var EndPos   = ( this.Selection.StartPos > this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos );

                        if ( StartPos != EndPos && AscCommon.changestype_Delete === CheckType )
                            CheckType = AscCommon.changestype_Remove;

                        for ( var Index = StartPos; Index <= EndPos; Index++ )
                            this.Content[Index].Document_Is_SelectionLocked(CheckType);
                    }
                    else
                    {
                        var CurElement = this.Content[this.CurPos.ContentPos];

                        if ( AscCommon.changestype_Document_Content_Add === CheckType && type_Paragraph === CurElement.GetType() && true === CurElement.IsCursorAtEnd() )
                            AscCommon.CollaborativeEditing.Add_CheckLock(false);
                        else
                            this.Content[this.CurPos.ContentPos].Document_Is_SelectionLocked(CheckType);
                    }

                    break;
                }
                case selectionflag_Numbering:
                {
                    var oNumPr = this.Selection.Data.CurPara.GetNumPr();
                    if (oNumPr)
                    {
                    	var oNum = this.GetNumbering().GetNum(oNumPr.NumId);
						oNum.IsSelectionLocked(CheckType);
                    }

                    this.Content[this.CurPos.ContentPos].Document_Is_SelectionLocked(CheckType);

                    break;
                }
            }
        }
    }
};
CDocumentContent.prototype.CheckContentControlEditingLock = function()
{
	if (this.Parent && this.Parent.CheckContentControlEditingLock)
		this.Parent.CheckContentControlEditingLock();
};
CDocumentContent.prototype.CheckContentControlDeletingLock = function()
{
	for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex)
	{
		this.Content[nIndex].CheckContentControlDeletingLock();
	}
};
Paragraph.prototype.Document_Is_SelectionLocked = function(CheckType)
{
	var isSelectionUse = this.IsSelectionUse();
	var arrContentControls = this.GetSelectedContentControls();
	for (var nIndex = 0, nCount = arrContentControls.length; nIndex < nCount; ++nIndex)
	{
		if (arrContentControls[nIndex].IsSelectionUse() === isSelectionUse)
			arrContentControls[nIndex].Document_Is_SelectionLocked(CheckType);
	}

	// Проверка для специального случая, когда мы переносим текст из параграфа в него самого. В такой ситуации надо
	// проверять не только выделенную часть, но и место куда происходит вставка/перенос.
	if (this.NearPosArray.length > 0)
	{
		var ParaState = this.GetSelectionState();
		this.RemoveSelection();
		this.Set_ParaContentPos(this.NearPosArray[0].NearPos.ContentPos, true, -1, -1);
		arrContentControls = this.GetSelectedContentControls();

		for (var nIndex = 0, nCount = arrContentControls.length; nIndex < nCount; ++nIndex)
		{
			if (false === arrContentControls[nIndex].IsSelectionUse())
				arrContentControls[nIndex].Document_Is_SelectionLocked(CheckType);
		}

		this.SetSelectionState(ParaState, 0);
	}

	var bCheckContentControl = false;
    switch ( CheckType )
    {
        case AscCommon.changestype_Paragraph_Content:
		case AscCommon.changestype_Paragraph_Properties:
		case AscCommon.changestype_Paragraph_AddText:
		case AscCommon.changestype_ContentControl_Add:
        case AscCommon.changestype_Document_Content:
        case AscCommon.changestype_Document_Content_Add:
        case AscCommon.changestype_Image_Properties:
		{
			this.Lock.Check( this.Get_Id() );
			bCheckContentControl = true;
			break;
		}
        case AscCommon.changestype_Remove:
        {
            // Если у нас нет выделения, и курсор стоит в начале, мы должны проверить в том же порядке, в каком
            // идут проверки при удалении в команде Internal_Remove_Backward.
            if ( true != this.Selection.Use && true == this.IsCursorAtBegin() )
            {
                var Pr = this.Get_CompiledPr2(false).ParaPr;
                if ( undefined != this.GetNumPr() || Math.abs(Pr.Ind.FirstLine) > 0.001 || Math.abs(Pr.Ind.Left) > 0.001 )
                {
                    // Надо проверить только текущий параграф, а это будет сделано далее
                }
                else
                {
                    var Prev = this.Get_DocumentPrev();
                    if ( null != Prev && type_Paragraph === Prev.GetType() )
                        Prev.Lock.Check( Prev.Get_Id() );
                }
            }
            // Если есть выделение, и знак параграфа попал в выделение ( и параграф выделен не целиком )
            else if ( true === this.Selection.Use )
            {
                var StartPos = this.Selection.StartPos;
                var EndPos   = this.Selection.EndPos;

                if ( StartPos > EndPos )
                {
                    var Temp = EndPos;
                    EndPos   = StartPos;
                    StartPos = Temp;
                }

                if ( EndPos >= this.Content.length - 1 && StartPos > this.Internal_GetStartPos() )
                {
                    var Next = this.Get_DocumentNext();
                    if ( null != Next && type_Paragraph === Next.GetType() )
                        Next.Lock.Check( Next.Get_Id() );
                }
            }

            this.Lock.Check( this.Get_Id() );
            bCheckContentControl = true;
            break;
        }
        case AscCommon.changestype_Delete:
        {
            // Если у нас нет выделения, и курсор стоит в конце, мы должны проверить следующий элемент
            if ( true != this.Selection.Use && true === this.IsCursorAtEnd() )
            {
                var Next = this.Get_DocumentNext();
                if ( null != Next && type_Paragraph === Next.GetType() )
                    Next.Lock.Check( Next.Get_Id() );
            }
            // Если есть выделение, и знак параграфа попал в выделение и параграф выделен не целиком
            else if ( true === this.Selection.Use )
            {
                var StartPos = this.Selection.StartPos;
                var EndPos   = this.Selection.EndPos;

                if ( StartPos > EndPos )
                {
                    var Temp = EndPos;
                    EndPos   = StartPos;
                    StartPos = Temp;
                }

                if ( EndPos >= this.Content.length - 1 && StartPos > this.Internal_GetStartPos() )
                {
                    var Next = this.Get_DocumentNext();
                    if ( null != Next && type_Paragraph === Next.GetType() )
                        Next.Lock.Check( Next.Get_Id() );
                }
            }

            this.Lock.Check( this.Get_Id() );
			bCheckContentControl = true;
            break;
        }
        case AscCommon.changestype_Document_SectPr:
        case AscCommon.changestype_Table_Properties:
        case AscCommon.changestype_Table_RemoveCells:
        case AscCommon.changestype_HdrFtr:
        {
            AscCommon.CollaborativeEditing.Add_CheckLock(true);
            break;
        }
    }

    if (bCheckContentControl && this.Parent && this.Parent.CheckContentControlEditingLock)
		this.Parent.CheckContentControlEditingLock();
};
Paragraph.prototype.CheckContentControlDeletingLock = function()
{
};
CTable.prototype.Document_Is_SelectionLocked = function(CheckType, bCheckInner)
{
	var bCheckContentControl = false;
    switch (CheckType)
    {
        case AscCommon.changestype_Paragraph_Content:
        case AscCommon.changestype_Paragraph_Properties:
		case AscCommon.changestype_Paragraph_AddText:
		case AscCommon.changestype_ContentControl_Add:
        case AscCommon.changestype_Document_Content:
        case AscCommon.changestype_Document_Content_Add:
        case AscCommon.changestype_Delete:
        case AscCommon.changestype_Image_Properties:
        {
            if ( true === this.ApplyToAll || (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type) )
            {
                var Cells_array = this.Internal_Get_SelectionArray();

                var Count = Cells_array.length;
                for ( var Index = 0; Index < Count; Index++ )
                {
                    var Pos  = Cells_array[Index];
                    var Cell = this.Content[Pos.Row].Get_Cell( Pos.Cell );

                    Cell.Content.Set_ApplyToAll( true );
                    Cell.Content.Document_Is_SelectionLocked( CheckType );
                    Cell.Content.Set_ApplyToAll( false );
                }
            }
            else
                this.CurCell.Content.Document_Is_SelectionLocked( CheckType );

            bCheckContentControl = true;
            break;
        }
        case AscCommon.changestype_Remove:
        {
			if (true === this.ApplyToAll || (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type))
			{
				this.Lock.Check(this.Get_Id());

				var arrCells = this.Internal_Get_SelectionArray();
				for (var nIndex = 0, nCellsCount = arrCells.length; nIndex < nCellsCount; ++nIndex)
				{
					var Pos  = arrCells[nIndex];
					var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
					Cell.Content.CheckContentControlDeletingLock();
				}
			}
			else
			{
				this.CurCell.Content.Document_Is_SelectionLocked(CheckType);
			}

			bCheckContentControl = true;
            break;
        }
        case AscCommon.changestype_Table_Properties:
        {
            if ( false != bCheckInner && true === this.IsInnerTable() )
                this.CurCell.Content.Document_Is_SelectionLocked( CheckType );
            else
                this.Lock.Check( this.Get_Id() );

			bCheckContentControl = true;
            break;
        }
        case AscCommon.changestype_Table_RemoveCells:
        {
            /*
             // Проверяем все ячейки
             if ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type )
             {
             var Count = this.Selection.Data.length;
             for ( var Index = 0; Index < Count; Index++ )
             {
             var Pos = this.Selection.Data[Index];
             var Cell = this.Content[Pos.Row].Get_Cell( Pos.Cell );
             Cell.Content.Document_Is_SelectionLocked( CheckType );
             }
             }
             else
             this.CurCell.Content.Document_Is_SelectionLocked( CheckType );
             */

            // Проверяем саму таблицу

            if ( false != bCheckInner && true === this.IsInnerTable() )
                this.CurCell.Content.Document_Is_SelectionLocked( CheckType );
            else
                this.Lock.Check( this.Get_Id() );

			bCheckContentControl = true;
            break;
        }
        case AscCommon.changestype_Document_SectPr:
        case AscCommon.changestype_HdrFtr:
        {
            AscCommon.CollaborativeEditing.Add_CheckLock(true);
            break;
        }
    }

	if (bCheckContentControl && this.Parent && this.Parent.CheckContentControlEditingLock)
		this.Parent.CheckContentControlEditingLock();
};
CTable.prototype.CheckContentControlDeletingLock = function()
{
	for (var nCurRow = 0, nRowsCount = this.Content.length; nCurRow < nRowsCount; ++nCurRow)
	{
		var oRow = this.Content[nCurRow];
		for (var nCurCell = 0, nCellsCount = oRow.Get_CellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			oRow.Get_Cell(nCurCell).Content.CheckContentControlDeletingLock();
		}
	}
};
CBlockLevelSdt.prototype.Document_Is_SelectionLocked = function(CheckType, bCheckInner)
{
	if (AscCommon.changestype_Document_Content_Add === CheckType && this.Content.IsCursorAtBegin())
		return AscCommon.CollaborativeEditing.Add_CheckLock(false);

	var isCheckContentControlLock = this.LogicDocument ? this.LogicDocument.IsCheckContentControlsLock() : true;

	var nContentControlLock = this.GetContentControlLock();

	if (AscCommon.changestype_ContentControl_Properties === CheckType)
		return this.Lock.Check(this.GetId());

	if (AscCommon.changestype_ContentControl_Remove === CheckType)
		this.Lock.Check(this.GetId());

	if (isCheckContentControlLock
		&& (AscCommon.changestype_Paragraph_Content === CheckType
		|| AscCommon.changestype_Paragraph_AddText === CheckType
		|| AscCommon.changestype_ContentControl_Add === CheckType
		|| AscCommon.changestype_Remove === CheckType
		|| AscCommon.changestype_Delete === CheckType
		|| AscCommon.changestype_Document_Content === CheckType
		|| AscCommon.changestype_Document_Content_Add === CheckType
		|| AscCommon.changestype_ContentControl_Remove === CheckType)
		&& this.IsSelectionUse()
		&& this.IsSelectedAll())
	{
		var bSelectedOnlyThis = false;
		// Если это происходит на добавлении текста, тогда проверяем, что выделен только данный элемент
		if ((AscCommon.changestype_Paragraph_AddText === CheckType || AscCommon.changestype_ContentControl_Add === CheckType) && this.LogicDocument)
		{
			var oInfo = this.LogicDocument.GetSelectedElementsInfo();
			bSelectedOnlyThis = oInfo.GetBlockLevelSdt() === this ? true : false;
		}

		if (c_oAscSdtLockType.SdtContentLocked === nContentControlLock
			|| (c_oAscSdtLockType.SdtLocked === nContentControlLock && true !== bSelectedOnlyThis)
			|| (c_oAscSdtLockType.ContentLocked === nContentControlLock && true === bSelectedOnlyThis))
		{
			return AscCommon.CollaborativeEditing.Add_CheckLock(true);
		}
		else
		{
			AscCommon.CollaborativeEditing.AddContentControlForSkippingOnCheckEditingLock(this);
			this.Content.Document_Is_SelectionLocked(CheckType, bCheckInner);
			AscCommon.CollaborativeEditing.RemoveContentControlForSkippingOnCheckEditingLock(this);
			return;
		}
	}
	else if (isCheckContentControlLock
		&& (c_oAscSdtLockType.SdtContentLocked === nContentControlLock
		|| c_oAscSdtLockType.ContentLocked === nContentControlLock))
	{
		return AscCommon.CollaborativeEditing.Add_CheckLock(true);
	}
	else
	{
		return this.Content.Document_Is_SelectionLocked(CheckType, bCheckInner);
	}
};
CBlockLevelSdt.prototype.CheckContentControlEditingLock = function()
{
	var isCheckContentControlLock = this.LogicDocument ? this.LogicDocument.IsCheckContentControlsLock() : true;
	if (!isCheckContentControlLock)
		return;

	var nContentControlLock = this.GetContentControlLock();

	if (false === AscCommon.CollaborativeEditing.IsNeedToSkipContentControlOnCheckEditingLock(this)
		&& (c_oAscSdtLockType.SdtContentLocked === nContentControlLock || c_oAscSdtLockType.ContentLocked === nContentControlLock))
		return AscCommon.CollaborativeEditing.Add_CheckLock(true);

	if (this.Parent && this.Parent.CheckContentControlEditingLock)
		this.Parent.CheckContentControlEditingLock();
};
CBlockLevelSdt.prototype.CheckContentControlDeletingLock = function()
{
	var isCheckContentControlLock = this.LogicDocument ? this.LogicDocument.IsCheckContentControlsLock() : true;
	if (!isCheckContentControlLock)
		return;

	var nContentControlLock = this.GetContentControlLock();

	if (c_oAscSdtLockType.SdtContentLocked === nContentControlLock || c_oAscSdtLockType.SdtLocked === nContentControlLock)
		return AscCommon.CollaborativeEditing.Add_CheckLock(true);

	this.Content.CheckContentControlEditingLock();
};
CInlineLevelSdt.prototype.Document_Is_SelectionLocked = function(CheckType)
{
	var isCheckContentControlLock = this.Paragraph && this.Paragraph.LogicDocument ? this.Paragraph.LogicDocument.IsCheckContentControlsLock() : true;
	if (!isCheckContentControlLock)
		return;

	var nContentControlLock = this.GetContentControlLock();

	if ((AscCommon.changestype_Paragraph_Content === CheckType
		|| AscCommon.changestype_Paragraph_AddText === CheckType
		|| AscCommon.changestype_ContentControl_Add === CheckType
		|| AscCommon.changestype_Remove === CheckType
		|| AscCommon.changestype_Delete === CheckType
		|| AscCommon.changestype_Document_Content === CheckType
		|| AscCommon.changestype_Document_Content_Add === CheckType)
		&& this.IsSelectionUse()
		&& this.IsSelectedAll())
	{
		var bSelectedOnlyThis = false;
		// Если это происходит на добавлении текста, тогда проверяем, что выделен только данный элемент
		if ((AscCommon.changestype_Paragraph_AddText === CheckType ||  AscCommon.changestype_ContentControl_Add === CheckType) && this.Paragraph && this.Paragraph.LogicDocument)
		{
			var oInfo = this.Paragraph.LogicDocument.GetSelectedElementsInfo();
			bSelectedOnlyThis = oInfo.GetInlineLevelSdt() === this ? true : false;
		}

		if (c_oAscSdtLockType.SdtContentLocked === nContentControlLock
			|| (c_oAscSdtLockType.SdtLocked === nContentControlLock && true !== bSelectedOnlyThis)
			|| (c_oAscSdtLockType.ContentLocked === nContentControlLock && true === bSelectedOnlyThis))
		{
			return AscCommon.CollaborativeEditing.Add_CheckLock(true);
		}
	}
	else if ((AscCommon.changestype_Paragraph_Content === CheckType
		|| AscCommon.changestype_Paragraph_AddText === CheckType
		|| AscCommon.changestype_ContentControl_Add === CheckType
		|| AscCommon.changestype_Remove === CheckType
		|| AscCommon.changestype_Delete === CheckType
		|| AscCommon.changestype_Document_Content === CheckType
		|| AscCommon.changestype_Document_Content_Add === CheckType
		|| AscCommon.changestype_Image_Properties === CheckType)
		&& (c_oAscSdtLockType.SdtContentLocked === nContentControlLock
		|| c_oAscSdtLockType.ContentLocked === nContentControlLock))
	{
		return AscCommon.CollaborativeEditing.Add_CheckLock(true);
	}
};
CTableCell.prototype.CheckContentControlEditingLock = function()
{
	if (this.Row && this.Row.Table && this.Row.Table.Parent && this.Row.Table.Parent.CheckContentControlEditingLock)
		this.Row.Table.Parent.CheckContentControlEditingLock();
};

if(typeof CComments !== "undefined")
{
    CComments.prototype.Document_Is_SelectionLocked = function(Id)
    {
        var Comment = this.Get_ById( Id );
        if ( null != Comment )
            Comment.Lock.Check( Comment.Get_Id() );
    };
}

if(typeof CPresentation !== "undefined")
{
    CPresentation.prototype.Document_Is_SelectionLocked =  function(CheckType, AdditionalData, isIgnoreCanEditFlag, aAdditionaObjects)
    {
        if (!this.CanEdit() && true !== isIgnoreCanEditFlag)
            return true;

        if ( true === AscCommon.CollaborativeEditing.Get_GlobalLock() )
            return true;
        if(this.Slides.length === 0)
            return false;
        if(AscCommon.changestype_Document_SectPr === CheckType)
        {
            return true;
        }

        if(CheckType === AscCommon.changestype_None && AscCommon.isRealObject(AdditionalData) && AdditionalData.CheckType === AscCommon.changestype_Table_Properties)
        {
            CheckType = AscCommon.changestype_Drawing_Props;
        }


        var cur_slide = this.Slides[this.CurPage];
        var slide_id;
        if(this.FocusOnNotes && cur_slide.notes){
            slide_id = cur_slide.notes.Get_Id();
        }
        else{
            slide_id = cur_slide.deleteLock.Get_Id();
        }

        AscCommon.CollaborativeEditing.OnStart_CheckLock();

        var oController = this.GetCurrentController();
        if(!oController){
            return false;
        }

        if(CheckType === AscCommon.changestype_Paragraph_Content)
        {
            var oTargetTextObject = oController.getTargetDocContent(false, true);
            if(oTargetTextObject)
            {
                CheckType = AscCommon.changestype_Drawing_Props;
            }
            else
            {
                return false;
            }
        }

        if(CheckType === AscCommon.changestype_Drawing_Props)
        {
            if(cur_slide.deleteLock.Lock.Type !== locktype_Mine && cur_slide.deleteLock.Lock.Type !== locktype_None)
                return true;
            var selected_objects = oController.selectedObjects;
            for(var i = 0; i < selected_objects.length; ++i)
            {
                var check_obj =
                {
                    "type": c_oAscLockTypeElemPresentation.Object,
                    "slideId": slide_id,
                    "objId": selected_objects[i].Get_Id(),
                    "guid": selected_objects[i].Get_Id()
                };
                selected_objects[i].Lock.Check(check_obj);
            }
            if(Array.isArray(aAdditionaObjects)){
                for(var i = 0; i < aAdditionaObjects.length; ++i)
                {
                    var check_obj =
                        {
                            "type": c_oAscLockTypeElemPresentation.Object,
                            "slideId": slide_id,
                            "objId": aAdditionaObjects[i].Get_Id(),
                            "guid": aAdditionaObjects[i].Get_Id()
                        };
                    aAdditionaObjects[i].Lock.Check(check_obj);
                }
            }
        }

        if(CheckType === AscCommon.changestype_AddShape || CheckType === AscCommon.changestype_AddComment)
        {

            if(CheckType === AscCommon.changestype_AddComment && AdditionalData && AdditionalData.Parent === this.comments)
            {
                var check_obj =
                {
                    "type": c_oAscLockTypeElemPresentation.Slide,
                    "val": this.commentsLock.Get_Id(),
                    "guid": this.commentsLock.Get_Id()
                };
                this.commentsLock.Lock.Check(check_obj);
            }
            else
            {
                if(cur_slide.deleteLock.Lock.Type !== locktype_Mine && cur_slide.deleteLock.Lock.Type !== locktype_None)
                    return true;
                var check_obj =
                {
                    "type": c_oAscLockTypeElemPresentation.Object,
                    "slideId": slide_id,
                    "objId": AdditionalData.Get_Id(),
                    "guid": AdditionalData.Get_Id()
                };
                AdditionalData.Lock.Check(check_obj);
            }
        }
        if(CheckType === AscCommon.changestype_AddShapes)
        {
            if(cur_slide.deleteLock.Lock.Type !== locktype_Mine && cur_slide.deleteLock.Lock.Type !== locktype_None)
                return true;
            for(var i = 0; i < AdditionalData.length; ++i)
            {
                var check_obj =
                {
                    "type": c_oAscLockTypeElemPresentation.Object,
                    "slideId": slide_id,
                    "objId": AdditionalData[i].Get_Id(),
                    "guid": AdditionalData[i].Get_Id()
                };
                AdditionalData[i].Lock.Check(check_obj);
            }
        }

        if(CheckType === AscCommon.changestype_MoveComment)
        {
            var comment = AscCommon.g_oTableId.Get_ById(AdditionalData);
            if(AscCommon.isRealObject(comment))
            {
                var slides = this.Slides;
                var check_slide = null;
                for(var i = 0; i < slides.length; ++i)
                {
                    if(slides[i].slideComments)
                    {
                        var comments = slides[i].slideComments.comments;
                        for(var j = 0; j < comments.length; ++j)
                        {
                            if(comments[j] === comment)
                            {
                                check_slide = slides[i];
                                break;
                            }
                        }
                        if(j < comments.length)
                        {
                            break;
                        }
                    }
                }
                if(AscCommon.isRealObject(check_slide))
                {
                    if(check_slide.deleteLock.Lock.Type !== locktype_Mine && check_slide.deleteLock.Lock.Type !== locktype_None)
                        return true;
                    var check_obj =
                    {
                        "type": c_oAscLockTypeElemPresentation.Object,
                        "slideId": slide_id,
                        "objId": comment.Get_Id(),
                        "guid": comment.Get_Id()
                    };
                    comment.Lock.Check(check_obj);
                }
                else
                {
                    return true;
                }
            }
            else
            {
                return true;
            }


        }

        if(CheckType === AscCommon.changestype_SlideBg)
        {
            var selected_slides = this.GetSelectedSlides();
            for(var i = 0; i < selected_slides.length; ++i)
            {
                var check_obj =
                {
                    "type": c_oAscLockTypeElemPresentation.Slide,
                    "val": this.Slides[selected_slides[i]].backgroundLock.Get_Id(),
                    "guid": this.Slides[selected_slides[i]].backgroundLock.Get_Id()
                };
                this.Slides[selected_slides[i]].backgroundLock.Lock.Check(check_obj);
            }
        }
        if(CheckType === AscCommon.changestype_SlideHide)
        {
            var selected_slides = AdditionalData;
            for(var i = 0; i < selected_slides.length; ++i)
            {
                var check_obj =
                {
                    "type": c_oAscLockTypeElemPresentation.Slide,
                    "val": this.Slides[selected_slides[i]].showLock.Get_Id(),
                    "guid": this.Slides[selected_slides[i]].showLock.Get_Id()
                };
                this.Slides[selected_slides[i]].showLock.Lock.Check(check_obj);
            }
        }

        if(CheckType === AscCommon.changestype_SlideTiming)
        {
            if(!AdditionalData || !AdditionalData.All)
            {
                var aSelectedSlides = this.GetSelectedSlides();
                for(var i = 0; i < aSelectedSlides.length; ++i){
                    var check_obj =
                        {
                            "type": c_oAscLockTypeElemPresentation.Slide,
                            "val": this.Slides[this.CurPage].timingLock.Get_Id(),
                            "guid": this.Slides[this.CurPage].timingLock.Get_Id()
                        };
                    this.Slides[aSelectedSlides[i]].timingLock.Lock.Check(check_obj);
                }
            }
            else{
                for(var i = 0; i < this.Slides.length; ++i)
                {
                    var check_obj =
                    {
                        "type": c_oAscLockTypeElemPresentation.Slide,
                        "val": this.Slides[i].timingLock.Get_Id(),
                        "guid": this.Slides[i].timingLock.Get_Id()
                    };
                    this.Slides[i].timingLock.Lock.Check(check_obj);
                }
            }

        }

        if(CheckType === AscCommon.changestype_Text_Props)
        {
            if(cur_slide.deleteLock.Lock.Type !== locktype_Mine && cur_slide.deleteLock.Lock.Type !== locktype_None)
                return true;
            var selected_objects = oController.selectedObjects;
            for(var i = 0; i < selected_objects.length; ++i)
            {
                var check_obj =
                {
                    "type": c_oAscLockTypeElemPresentation.Object,
                    "slideId": slide_id,
                    "objId": selected_objects[i].Get_Id(),
                    "guid":selected_objects[i].Get_Id()
                };
                selected_objects[i].Lock.Check(check_obj);
            }
        }

        if(CheckType === AscCommon.changestype_RemoveSlide)
        {
            var selected_slides = AdditionalData;
            for(var i = 0; i < selected_slides.length; ++i)
            {
                if(this.Slides[selected_slides[i]].isLockedObject())
                    return true;
            }
            for(var i = 0; i < selected_slides.length; ++i)
            {
                var check_obj =
                {
                    "type": c_oAscLockTypeElemPresentation.Slide,
                    "val": this.Slides[selected_slides[i]].deleteLock.Get_Id(),
                    "guid": this.Slides[selected_slides[i]].deleteLock.Get_Id()
                };
                this.Slides[selected_slides[i]].deleteLock.Lock.Check(check_obj);
            }
        }

        if(CheckType === AscCommon.changestype_Theme)
        {
            var check_obj =
            {
                "type": c_oAscLockTypeElemPresentation.Slide,
                "val": this.themeLock.Get_Id(),
                "guid": this.themeLock.Get_Id()
            };
            this.themeLock.Lock.Check(check_obj);
        }

        if(CheckType === AscCommon.changestype_Layout)
        {
            var selected_slides = this.GetSelectedSlides();
            for(var i = 0; i < selected_slides.length; ++i)
            {
                var check_obj =
                {
                    "type": c_oAscLockTypeElemPresentation.Slide,
                    "val": this.Slides[selected_slides[i]].layoutLock.Get_Id(),
                    "guid": this.Slides[selected_slides[i]].layoutLock.Get_Id()
                };
                this.Slides[selected_slides[i]].layoutLock.Lock.Check(check_obj);
            }
        }
        if(CheckType === AscCommon.changestype_ColorScheme)
        {
            var check_obj =
            {
                "type": c_oAscLockTypeElemPresentation.Slide,
                "val": this.schemeLock.Get_Id(),
                "guid": this.schemeLock.Get_Id()
            };
            this.schemeLock.Lock.Check(check_obj);
        }

        if(CheckType === AscCommon.changestype_SlideSize)
        {
            var check_obj =
            {
                "type": c_oAscLockTypeElemPresentation.Slide,
                "val": this.slideSizeLock.Get_Id(),
                "guid": this.slideSizeLock.Get_Id()
            };
            this.slideSizeLock.Lock.Check(check_obj);
        }

        if(CheckType === AscCommon.changestype_PresDefaultLang )
        {
            var check_obj =
                {
                    "type": c_oAscLockTypeElemPresentation.Slide,
                    "val": this.defaultTextStyleLock.Get_Id(),
                    "guid": this.defaultTextStyleLock.Get_Id()
                };

            this.defaultTextStyleLock.Lock.Check(check_obj);
        }

        var bResult = AscCommon.CollaborativeEditing.OnEnd_CheckLock();

        if ( true === bResult )
        {
            this.Document_UpdateSelectionState();
            this.Document_UpdateInterfaceState();
        }

        return bResult;
    };
}
